smsc: Move the SMC (SMSC) drivers
authorJeff Kirsher <jeffrey.t.kirsher@intel.com>
Fri, 13 May 2011 03:21:07 +0000 (20:21 -0700)
committerJeff Kirsher <jeffrey.t.kirsher@intel.com>
Thu, 11 Aug 2011 03:04:03 +0000 (20:04 -0700)
Moves the SMC (SMSC) drivers into drivers/net/ethernet/smsc/ and the
necessary Kconfig and Makefile changes.  Also did some cleanup
of NET_VENDOR_SMC Kconfig tag for the 8390 based drivers.

CC: Nicolas Pitre <nico@fluxnic.net>
CC: Donald Becker <becker@scyld.com>
CC: Erik Stahlman <erik@vt.edu>
CC: Dustin McIntire <dustin@sensoria.com>
CC: Steve Glendinning <steve.glendinning@smsc.com>
CC: David Hinds <dahinds@users.sourceforge.net>
Signed-off-by: Jeff Kirsher <jeffrey.t.kirsher@intel.com>
34 files changed:
MAINTAINERS
drivers/net/Kconfig
drivers/net/Makefile
drivers/net/epic100.c [deleted file]
drivers/net/ethernet/8390/Kconfig
drivers/net/ethernet/Kconfig
drivers/net/ethernet/Makefile
drivers/net/ethernet/smsc/Kconfig [new file with mode: 0644]
drivers/net/ethernet/smsc/Makefile [new file with mode: 0644]
drivers/net/ethernet/smsc/epic100.c [new file with mode: 0644]
drivers/net/ethernet/smsc/smc911x.c [new file with mode: 0644]
drivers/net/ethernet/smsc/smc911x.h [new file with mode: 0644]
drivers/net/ethernet/smsc/smc9194.c [new file with mode: 0644]
drivers/net/ethernet/smsc/smc9194.h [new file with mode: 0644]
drivers/net/ethernet/smsc/smc91c92_cs.c [new file with mode: 0644]
drivers/net/ethernet/smsc/smc91x.c [new file with mode: 0644]
drivers/net/ethernet/smsc/smc91x.h [new file with mode: 0644]
drivers/net/ethernet/smsc/smsc911x.c [new file with mode: 0644]
drivers/net/ethernet/smsc/smsc911x.h [new file with mode: 0644]
drivers/net/ethernet/smsc/smsc9420.c [new file with mode: 0644]
drivers/net/ethernet/smsc/smsc9420.h [new file with mode: 0644]
drivers/net/pcmcia/Kconfig
drivers/net/pcmcia/Makefile
drivers/net/pcmcia/smc91c92_cs.c [deleted file]
drivers/net/smc911x.c [deleted file]
drivers/net/smc911x.h [deleted file]
drivers/net/smc9194.c [deleted file]
drivers/net/smc9194.h [deleted file]
drivers/net/smc91x.c [deleted file]
drivers/net/smc91x.h [deleted file]
drivers/net/smsc911x.c [deleted file]
drivers/net/smsc911x.h [deleted file]
drivers/net/smsc9420.c [deleted file]
drivers/net/smsc9420.h [deleted file]

index 8f2821c30821ad21efdc15798cd98d4c6c9be914..7c0294cdf9f1e1f5ec4b493293d0b849ebf3c871 100644 (file)
@@ -5869,7 +5869,7 @@ F:        mm/sl?b.c
 SMC91x ETHERNET DRIVER
 M:     Nicolas Pitre <nico@fluxnic.net>
 S:     Odd Fixes
-F:     drivers/net/smc91x.*
+F:     drivers/net/ethernet/smsc/smc91x.*
 
 SMM665 HARDWARE MONITOR DRIVER
 M:     Guenter Roeck <linux@roeck-us.net>
@@ -5904,13 +5904,13 @@ M:      Steve Glendinning <steve.glendinning@smsc.com>
 L:     netdev@vger.kernel.org
 S:     Supported
 F:     include/linux/smsc911x.h
-F:     drivers/net/smsc911x.*
+F:     drivers/net/ethernet/smsc/smsc911x.*
 
 SMSC9420 PCI ETHERNET DRIVER
 M:     Steve Glendinning <steve.glendinning@smsc.com>
 L:     netdev@vger.kernel.org
 S:     Supported
-F:     drivers/net/smsc9420.*
+F:     drivers/net/ethernet/smsc/smsc9420.*
 
 SN-IA64 (Itanium) SUB-PLATFORM
 M:     Jes Sorensen <jes@sgi.com>
index de2293d23d550aba5b66135ccef101e9ec4a3d30..649918609cb64fd9da583e737abfd50cf585ce21 100644 (file)
@@ -565,39 +565,6 @@ config BFIN_MAC_USE_HWSTAMP
        help
          To support the IEEE 1588 Precision Time Protocol (PTP), select y here
 
-config SMC9194
-       tristate "SMC 9194 support"
-       depends on NET_VENDOR_SMC && (ISA || MAC && BROKEN)
-       select CRC32
-       ---help---
-         This is support for the SMC9xxx based Ethernet cards. Choose this
-         option if you have a DELL laptop with the docking station, or
-         another SMC9192/9194 based chipset.  Say Y if you want it compiled
-         into the kernel, and read the file
-         <file:Documentation/networking/smc9.txt> and the Ethernet-HOWTO,
-         available from <http://www.tldp.org/docs.html#howto>.
-
-         To compile this driver as a module, choose M here. The module
-         will be called smc9194.
-
-config SMC91X
-       tristate "SMC 91C9x/91C1xxx support"
-       select CRC32
-       select MII
-       depends on ARM || M32R || SUPERH || \
-               MIPS || BLACKFIN || MN10300 || COLDFIRE
-       help
-         This is a driver for SMC's 91x series of Ethernet chipsets,
-         including the SMC91C94 and the SMC91C111. Say Y if you want it
-         compiled into the kernel, and read the file
-         <file:Documentation/networking/smc9.txt>  and the Ethernet-HOWTO,
-         available from  <http://www.tldp.org/docs.html#howto>.
-
-         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 smc91x.  If you want to compile it as a
-         module, say M here and read <file:Documentation/kbuild/modules.txt>.
-
 config PXA168_ETH
        tristate "Marvell pxa168 ethernet support"
        depends on CPU_PXA168
@@ -712,44 +679,6 @@ config GRETH
        help
          Say Y here if you want to use the Aeroflex Gaisler GRETH Ethernet MAC.
 
-config SMC911X
-       tristate "SMSC LAN911[5678] support"
-       select CRC32
-       select MII
-       depends on ARM || SUPERH || MN10300
-       help
-         This is a driver for SMSC's LAN911x series of Ethernet chipsets
-         including the new LAN9115, LAN9116, LAN9117, and LAN9118.
-         Say Y if you want it compiled into the kernel, 
-         and read the Ethernet-HOWTO, available from
-         <http://www.tldp.org/docs.html#howto>.
-
-         This driver is also available as a module. The module will be 
-         called smc911x.  If you want to compile it as a module, say M 
-         here and read <file:Documentation/kbuild/modules.txt>
-
-config SMSC911X
-       tristate "SMSC LAN911x/LAN921x families embedded ethernet support"
-       depends on ARM || SUPERH || BLACKFIN || MIPS || MN10300
-       select CRC32
-       select MII
-       select PHYLIB
-       ---help---
-         Say Y here if you want support for SMSC LAN911x and LAN921x families
-         of ethernet controllers.
-
-         To compile this driver as a module, choose M here and read
-         <file:Documentation/networking/net-modules.txt>. The module
-         will be called smsc911x.
-
-config SMSC911X_ARCH_HOOKS
-       def_bool n
-       depends on SMSC911X
-       help
-         If the arch enables this, it allows the arch to implement various
-         hooks for more comprehensive interrupt control and also to override
-         the source of the MAC address.
-
 config NET_VENDOR_RACAL
        bool "Racal-Interlan (Micom) NI cards"
        depends on ISA
@@ -1148,33 +1077,6 @@ config SIS900
          To compile this driver as a module, choose M here: the module
          will be called sis900.  This is recommended.
 
-config EPIC100
-       tristate "SMC EtherPower II"
-       depends on NET_PCI && PCI
-       select CRC32
-       select MII
-       help
-         This driver is for the SMC EtherPower II 9432 PCI Ethernet NIC,
-         which is based on the SMC83c17x (EPIC/100).
-         More specific information and updates are available from
-         <http://www.scyld.com/network/epic100.html>.
-
-config SMSC9420
-       tristate "SMSC LAN9420 PCI ethernet adapter support"
-       depends on NET_PCI && PCI
-       select CRC32
-       select PHYLIB
-       select SMSC_PHY
-       help
-         This is a driver for SMSC's LAN9420 PCI ethernet adapter.
-         Say Y if you want it compiled into the kernel,
-         and read the Ethernet-HOWTO, available from
-         <http://www.tldp.org/docs.html#howto>.
-
-         This driver is also available as a module. The module will be
-         called smsc9420.  If you want to compile it as a module, say M
-         here and read <file:Documentation/kbuild/modules.txt>
-
 config SUNDANCE
        tristate "Sundance Alta support"
        depends on NET_PCI && PCI
@@ -1891,13 +1793,6 @@ config MYRI10GE_DCA
          driver.  DCA is a method for warming the CPU cache before data
          is used, with the intent of lessening the impact of cache misses.
 
-config NETXEN_NIC
-       tristate "NetXen Multi port (1/10) Gigabit Ethernet NIC"
-       depends on PCI
-       select FW_LOADER
-       help
-         This enables the support for NetXen's Gigabit Ethernet card.
-
 config NIU
        tristate "Sun Neptune 10Gbit Ethernet support"
        depends on PCI
index a58a9f0b7999e33dfb75a0d17efbcf95a9e9bfee..e74b4244ee7f2bf60a6e5d5c27e97cc31968a137 100644 (file)
@@ -55,8 +55,6 @@ obj-$(CONFIG_MACE) += mace.o
 obj-$(CONFIG_BMAC) += bmac.o
 
 obj-$(CONFIG_TLAN) += tlan.o
-obj-$(CONFIG_EPIC100) += epic100.o
-obj-$(CONFIG_SMSC9420) += smsc9420.o
 obj-$(CONFIG_SIS190) += sis190.o
 obj-$(CONFIG_SIS900) += sis900.o
 obj-$(CONFIG_R6040) += r6040.o
@@ -95,7 +93,6 @@ obj-$(CONFIG_NET) += Space.o loopback.o
 obj-$(CONFIG_SEEQ8005) += seeq8005.o
 obj-$(CONFIG_NET_SB1000) += sb1000.o
 obj-$(CONFIG_HP100) += hp100.o
-obj-$(CONFIG_SMC9194) += smc9194.o
 obj-$(CONFIG_FEC) += fec.o
 obj-$(CONFIG_FEC_MPC52xx) += fec_mpc52xx.o
 ifeq ($(CONFIG_FEC_MPC52xx_MDIO),y)
@@ -182,9 +179,6 @@ obj-$(CONFIG_IBMVETH) += ibmveth.o
 obj-$(CONFIG_S2IO) += s2io.o
 obj-$(CONFIG_VXGE) += vxge/
 obj-$(CONFIG_MYRI10GE) += myri10ge/
-obj-$(CONFIG_SMC91X) += smc91x.o
-obj-$(CONFIG_SMC911X) += smc911x.o
-obj-$(CONFIG_SMSC911X) += smsc911x.o
 obj-$(CONFIG_PXA168_ETH) += pxa168_eth.o
 obj-$(CONFIG_BFIN_MAC) += bfin_mac.o
 obj-$(CONFIG_DM9000) += dm9000.o
@@ -231,7 +225,6 @@ obj-$(CONFIG_NETCONSOLE) += netconsole.o
 
 obj-$(CONFIG_FS_ENET) += fs_enet/
 
-obj-$(CONFIG_NETXEN_NIC) += netxen/
 obj-$(CONFIG_NIU) += niu.o
 obj-$(CONFIG_VIRTIO_NET) += virtio_net.o
 obj-$(CONFIG_SFC) += sfc/
diff --git a/drivers/net/epic100.c b/drivers/net/epic100.c
deleted file mode 100644 (file)
index 814c187..0000000
+++ /dev/null
@@ -1,1609 +0,0 @@
-/* epic100.c: A SMC 83c170 EPIC/100 Fast Ethernet driver for Linux. */
-/*
-       Written/copyright 1997-2001 by Donald Becker.
-
-       This software may be used and distributed according to the terms of
-       the GNU General Public License (GPL), incorporated herein by reference.
-       Drivers based on or derived from this code fall under the GPL and must
-       retain the authorship, copyright and license notice.  This file is not
-       a complete program and may only be used when the entire operating
-       system is licensed under the GPL.
-
-       This driver is for the SMC83c170/175 "EPIC" series, as used on the
-       SMC EtherPower II 9432 PCI adapter, and several CardBus cards.
-
-       The author may be reached as becker@scyld.com, or C/O
-       Scyld Computing Corporation
-       410 Severn Ave., Suite 210
-       Annapolis MD 21403
-
-       Information and updates available at
-       http://www.scyld.com/network/epic100.html
-       [this link no longer provides anything useful -jgarzik]
-
-       ---------------------------------------------------------------------
-
-*/
-
-#define DRV_NAME        "epic100"
-#define DRV_VERSION     "2.1"
-#define DRV_RELDATE     "Sept 11, 2006"
-
-/* The user-configurable values.
-   These may be modified when a driver module is loaded.*/
-
-static int debug = 1;                  /* 1 normal messages, 0 quiet .. 7 verbose. */
-
-/* Used to pass the full-duplex flag, etc. */
-#define MAX_UNITS 8            /* More are supported, limit only on options */
-static int options[MAX_UNITS] = {-1, -1, -1, -1, -1, -1, -1, -1};
-static int full_duplex[MAX_UNITS] = {-1, -1, -1, -1, -1, -1, -1, -1};
-
-/* Set the copy breakpoint for the copy-only-tiny-frames scheme.
-   Setting to > 1518 effectively disables this feature. */
-static int rx_copybreak;
-
-/* Operational parameters that are set at compile time. */
-
-/* Keep the ring sizes a power of two for operational efficiency.
-   The compiler will convert <unsigned>'%'<2^N> into a bit mask.
-   Making the Tx ring too large decreases the effectiveness of channel
-   bonding and packet priority.
-   There are no ill effects from too-large receive rings. */
-#define TX_RING_SIZE   256
-#define TX_QUEUE_LEN   240             /* Limit ring entries actually used.  */
-#define RX_RING_SIZE   256
-#define TX_TOTAL_SIZE  TX_RING_SIZE*sizeof(struct epic_tx_desc)
-#define RX_TOTAL_SIZE  RX_RING_SIZE*sizeof(struct epic_rx_desc)
-
-/* Operational parameters that usually are not changed. */
-/* Time in jiffies before concluding the transmitter is hung. */
-#define TX_TIMEOUT  (2*HZ)
-
-#define PKT_BUF_SZ             1536                    /* Size of each temporary Rx buffer.*/
-
-/* Bytes transferred to chip before transmission starts. */
-/* Initial threshold, increased on underflow, rounded down to 4 byte units. */
-#define TX_FIFO_THRESH 256
-#define RX_FIFO_THRESH 1               /* 0-3, 0==32, 64,96, or 3==128 bytes  */
-
-#include <linux/module.h>
-#include <linux/kernel.h>
-#include <linux/string.h>
-#include <linux/timer.h>
-#include <linux/errno.h>
-#include <linux/ioport.h>
-#include <linux/interrupt.h>
-#include <linux/pci.h>
-#include <linux/delay.h>
-#include <linux/netdevice.h>
-#include <linux/etherdevice.h>
-#include <linux/skbuff.h>
-#include <linux/init.h>
-#include <linux/spinlock.h>
-#include <linux/ethtool.h>
-#include <linux/mii.h>
-#include <linux/crc32.h>
-#include <linux/bitops.h>
-#include <asm/io.h>
-#include <asm/uaccess.h>
-#include <asm/byteorder.h>
-
-/* These identify the driver base version and may not be removed. */
-static char version[] __devinitdata =
-DRV_NAME ".c:v1.11 1/7/2001 Written by Donald Becker <becker@scyld.com>\n";
-static char version2[] __devinitdata =
-"  (unofficial 2.4.x kernel port, version " DRV_VERSION ", " DRV_RELDATE ")\n";
-
-MODULE_AUTHOR("Donald Becker <becker@scyld.com>");
-MODULE_DESCRIPTION("SMC 83c170 EPIC series Ethernet driver");
-MODULE_LICENSE("GPL");
-
-module_param(debug, int, 0);
-module_param(rx_copybreak, int, 0);
-module_param_array(options, int, NULL, 0);
-module_param_array(full_duplex, int, NULL, 0);
-MODULE_PARM_DESC(debug, "EPIC/100 debug level (0-5)");
-MODULE_PARM_DESC(options, "EPIC/100: Bits 0-3: media type, bit 4: full duplex");
-MODULE_PARM_DESC(rx_copybreak, "EPIC/100 copy breakpoint for copy-only-tiny-frames");
-MODULE_PARM_DESC(full_duplex, "EPIC/100 full duplex setting(s) (1)");
-
-/*
-                               Theory of Operation
-
-I. Board Compatibility
-
-This device driver is designed for the SMC "EPIC/100", the SMC
-single-chip Ethernet controllers for PCI.  This chip is used on
-the SMC EtherPower II boards.
-
-II. Board-specific settings
-
-PCI bus devices are configured by the system at boot time, so no jumpers
-need to be set on the board.  The system BIOS will assign the
-PCI INTA signal to a (preferably otherwise unused) system IRQ line.
-Note: Kernel versions earlier than 1.3.73 do not support shared PCI
-interrupt lines.
-
-III. Driver operation
-
-IIIa. Ring buffers
-
-IVb. References
-
-http://www.smsc.com/media/Downloads_Public/discontinued/83c171.pdf
-http://www.smsc.com/media/Downloads_Public/discontinued/83c175.pdf
-http://scyld.com/expert/NWay.html
-http://www.national.com/pf/DP/DP83840A.html
-
-IVc. Errata
-
-*/
-
-
-enum chip_capability_flags { MII_PWRDWN=1, TYPE2_INTR=2, NO_MII=4 };
-
-#define EPIC_TOTAL_SIZE 0x100
-#define USE_IO_OPS 1
-
-typedef enum {
-       SMSC_83C170_0,
-       SMSC_83C170,
-       SMSC_83C175,
-} chip_t;
-
-
-struct epic_chip_info {
-       const char *name;
-        int drv_flags;                          /* Driver use, intended as capability flags. */
-};
-
-
-/* indexed by chip_t */
-static const struct epic_chip_info pci_id_tbl[] = {
-       { "SMSC EPIC/100 83c170",       TYPE2_INTR | NO_MII | MII_PWRDWN },
-       { "SMSC EPIC/100 83c170",       TYPE2_INTR },
-       { "SMSC EPIC/C 83c175",         TYPE2_INTR | MII_PWRDWN },
-};
-
-
-static DEFINE_PCI_DEVICE_TABLE(epic_pci_tbl) = {
-       { 0x10B8, 0x0005, 0x1092, 0x0AB4, 0, 0, SMSC_83C170_0 },
-       { 0x10B8, 0x0005, PCI_ANY_ID, PCI_ANY_ID, 0, 0, SMSC_83C170 },
-       { 0x10B8, 0x0006, PCI_ANY_ID, PCI_ANY_ID,
-         PCI_CLASS_NETWORK_ETHERNET << 8, 0xffff00, SMSC_83C175 },
-       { 0,}
-};
-MODULE_DEVICE_TABLE (pci, epic_pci_tbl);
-
-
-#ifndef USE_IO_OPS
-#undef inb
-#undef inw
-#undef inl
-#undef outb
-#undef outw
-#undef outl
-#define inb readb
-#define inw readw
-#define inl readl
-#define outb writeb
-#define outw writew
-#define outl writel
-#endif
-
-/* Offsets to registers, using the (ugh) SMC names. */
-enum epic_registers {
-  COMMAND=0, INTSTAT=4, INTMASK=8, GENCTL=0x0C, NVCTL=0x10, EECTL=0x14,
-  PCIBurstCnt=0x18,
-  TEST1=0x1C, CRCCNT=0x20, ALICNT=0x24, MPCNT=0x28,    /* Rx error counters. */
-  MIICtrl=0x30, MIIData=0x34, MIICfg=0x38,
-  LAN0=64,                                             /* MAC address. */
-  MC0=80,                                              /* Multicast filter table. */
-  RxCtrl=96, TxCtrl=112, TxSTAT=0x74,
-  PRxCDAR=0x84, RxSTAT=0xA4, EarlyRx=0xB0, PTxCDAR=0xC4, TxThresh=0xDC,
-};
-
-/* Interrupt register bits, using my own meaningful names. */
-enum IntrStatus {
-       TxIdle=0x40000, RxIdle=0x20000, IntrSummary=0x010000,
-       PCIBusErr170=0x7000, PCIBusErr175=0x1000, PhyEvent175=0x8000,
-       RxStarted=0x0800, RxEarlyWarn=0x0400, CntFull=0x0200, TxUnderrun=0x0100,
-       TxEmpty=0x0080, TxDone=0x0020, RxError=0x0010,
-       RxOverflow=0x0008, RxFull=0x0004, RxHeader=0x0002, RxDone=0x0001,
-};
-enum CommandBits {
-       StopRx=1, StartRx=2, TxQueued=4, RxQueued=8,
-       StopTxDMA=0x20, StopRxDMA=0x40, RestartTx=0x80,
-};
-
-#define EpicRemoved    0xffffffff      /* Chip failed or removed (CardBus) */
-
-#define EpicNapiEvent  (TxEmpty | TxDone | \
-                        RxDone | RxStarted | RxEarlyWarn | RxOverflow | RxFull)
-#define EpicNormalEvent        (0x0000ffff & ~EpicNapiEvent)
-
-static const u16 media2miictl[16] = {
-       0, 0x0C00, 0x0C00, 0x2000,  0x0100, 0x2100, 0, 0,
-       0, 0, 0, 0,  0, 0, 0, 0 };
-
-/*
- * The EPIC100 Rx and Tx buffer descriptors.  Note that these
- * really ARE host-endian; it's not a misannotation.  We tell
- * the card to byteswap them internally on big-endian hosts -
- * look for #ifdef __BIG_ENDIAN in epic_open().
- */
-
-struct epic_tx_desc {
-       u32 txstatus;
-       u32 bufaddr;
-       u32 buflength;
-       u32 next;
-};
-
-struct epic_rx_desc {
-       u32 rxstatus;
-       u32 bufaddr;
-       u32 buflength;
-       u32 next;
-};
-
-enum desc_status_bits {
-       DescOwn=0x8000,
-};
-
-#define PRIV_ALIGN     15      /* Required alignment mask */
-struct epic_private {
-       struct epic_rx_desc *rx_ring;
-       struct epic_tx_desc *tx_ring;
-       /* The saved address of a sent-in-place packet/buffer, for skfree(). */
-       struct sk_buff* tx_skbuff[TX_RING_SIZE];
-       /* The addresses of receive-in-place skbuffs. */
-       struct sk_buff* rx_skbuff[RX_RING_SIZE];
-
-       dma_addr_t tx_ring_dma;
-       dma_addr_t rx_ring_dma;
-
-       /* Ring pointers. */
-       spinlock_t lock;                                /* Group with Tx control cache line. */
-       spinlock_t napi_lock;
-       struct napi_struct napi;
-       unsigned int reschedule_in_poll;
-       unsigned int cur_tx, dirty_tx;
-
-       unsigned int cur_rx, dirty_rx;
-       u32 irq_mask;
-       unsigned int rx_buf_sz;                         /* Based on MTU+slack. */
-
-       struct pci_dev *pci_dev;                        /* PCI bus location. */
-       int chip_id, chip_flags;
-
-       struct timer_list timer;                        /* Media selection timer. */
-       int tx_threshold;
-       unsigned char mc_filter[8];
-       signed char phys[4];                            /* MII device addresses. */
-       u16 advertising;                                        /* NWay media advertisement */
-       int mii_phy_cnt;
-       struct mii_if_info mii;
-       unsigned int tx_full:1;                         /* The Tx queue is full. */
-       unsigned int default_port:4;            /* Last dev->if_port value. */
-};
-
-static int epic_open(struct net_device *dev);
-static int read_eeprom(long ioaddr, int location);
-static int mdio_read(struct net_device *dev, int phy_id, int location);
-static void mdio_write(struct net_device *dev, int phy_id, int loc, int val);
-static void epic_restart(struct net_device *dev);
-static void epic_timer(unsigned long data);
-static void epic_tx_timeout(struct net_device *dev);
-static void epic_init_ring(struct net_device *dev);
-static netdev_tx_t epic_start_xmit(struct sk_buff *skb,
-                                  struct net_device *dev);
-static int epic_rx(struct net_device *dev, int budget);
-static int epic_poll(struct napi_struct *napi, int budget);
-static irqreturn_t epic_interrupt(int irq, void *dev_instance);
-static int netdev_ioctl(struct net_device *dev, struct ifreq *rq, int cmd);
-static const struct ethtool_ops netdev_ethtool_ops;
-static int epic_close(struct net_device *dev);
-static struct net_device_stats *epic_get_stats(struct net_device *dev);
-static void set_rx_mode(struct net_device *dev);
-
-static const struct net_device_ops epic_netdev_ops = {
-       .ndo_open               = epic_open,
-       .ndo_stop               = epic_close,
-       .ndo_start_xmit         = epic_start_xmit,
-       .ndo_tx_timeout         = epic_tx_timeout,
-       .ndo_get_stats          = epic_get_stats,
-       .ndo_set_multicast_list = set_rx_mode,
-       .ndo_do_ioctl           = netdev_ioctl,
-       .ndo_change_mtu         = eth_change_mtu,
-       .ndo_set_mac_address    = eth_mac_addr,
-       .ndo_validate_addr      = eth_validate_addr,
-};
-
-static int __devinit epic_init_one (struct pci_dev *pdev,
-                                   const struct pci_device_id *ent)
-{
-       static int card_idx = -1;
-       long ioaddr;
-       int chip_idx = (int) ent->driver_data;
-       int irq;
-       struct net_device *dev;
-       struct epic_private *ep;
-       int i, ret, option = 0, duplex = 0;
-       void *ring_space;
-       dma_addr_t ring_dma;
-
-/* when built into the kernel, we only print version if device is found */
-#ifndef MODULE
-       static int printed_version;
-       if (!printed_version++)
-               printk(KERN_INFO "%s%s", version, version2);
-#endif
-
-       card_idx++;
-
-       ret = pci_enable_device(pdev);
-       if (ret)
-               goto out;
-       irq = pdev->irq;
-
-       if (pci_resource_len(pdev, 0) < EPIC_TOTAL_SIZE) {
-               dev_err(&pdev->dev, "no PCI region space\n");
-               ret = -ENODEV;
-               goto err_out_disable;
-       }
-
-       pci_set_master(pdev);
-
-       ret = pci_request_regions(pdev, DRV_NAME);
-       if (ret < 0)
-               goto err_out_disable;
-
-       ret = -ENOMEM;
-
-       dev = alloc_etherdev(sizeof (*ep));
-       if (!dev) {
-               dev_err(&pdev->dev, "no memory for eth device\n");
-               goto err_out_free_res;
-       }
-       SET_NETDEV_DEV(dev, &pdev->dev);
-
-#ifdef USE_IO_OPS
-       ioaddr = pci_resource_start (pdev, 0);
-#else
-       ioaddr = pci_resource_start (pdev, 1);
-       ioaddr = (long) pci_ioremap_bar(pdev, 1);
-       if (!ioaddr) {
-               dev_err(&pdev->dev, "ioremap failed\n");
-               goto err_out_free_netdev;
-       }
-#endif
-
-       pci_set_drvdata(pdev, dev);
-       ep = netdev_priv(dev);
-       ep->mii.dev = dev;
-       ep->mii.mdio_read = mdio_read;
-       ep->mii.mdio_write = mdio_write;
-       ep->mii.phy_id_mask = 0x1f;
-       ep->mii.reg_num_mask = 0x1f;
-
-       ring_space = pci_alloc_consistent(pdev, TX_TOTAL_SIZE, &ring_dma);
-       if (!ring_space)
-               goto err_out_iounmap;
-       ep->tx_ring = ring_space;
-       ep->tx_ring_dma = ring_dma;
-
-       ring_space = pci_alloc_consistent(pdev, RX_TOTAL_SIZE, &ring_dma);
-       if (!ring_space)
-               goto err_out_unmap_tx;
-       ep->rx_ring = ring_space;
-       ep->rx_ring_dma = ring_dma;
-
-       if (dev->mem_start) {
-               option = dev->mem_start;
-               duplex = (dev->mem_start & 16) ? 1 : 0;
-       } else if (card_idx >= 0  &&  card_idx < MAX_UNITS) {
-               if (options[card_idx] >= 0)
-                       option = options[card_idx];
-               if (full_duplex[card_idx] >= 0)
-                       duplex = full_duplex[card_idx];
-       }
-
-       dev->base_addr = ioaddr;
-       dev->irq = irq;
-
-       spin_lock_init(&ep->lock);
-       spin_lock_init(&ep->napi_lock);
-       ep->reschedule_in_poll = 0;
-
-       /* Bring the chip out of low-power mode. */
-       outl(0x4200, ioaddr + GENCTL);
-       /* Magic?!  If we don't set this bit the MII interface won't work. */
-       /* This magic is documented in SMSC app note 7.15 */
-       for (i = 16; i > 0; i--)
-               outl(0x0008, ioaddr + TEST1);
-
-       /* Turn on the MII transceiver. */
-       outl(0x12, ioaddr + MIICfg);
-       if (chip_idx == 1)
-               outl((inl(ioaddr + NVCTL) & ~0x003C) | 0x4800, ioaddr + NVCTL);
-       outl(0x0200, ioaddr + GENCTL);
-
-       /* Note: the '175 does not have a serial EEPROM. */
-       for (i = 0; i < 3; i++)
-               ((__le16 *)dev->dev_addr)[i] = cpu_to_le16(inw(ioaddr + LAN0 + i*4));
-
-       if (debug > 2) {
-               dev_printk(KERN_DEBUG, &pdev->dev, "EEPROM contents:\n");
-               for (i = 0; i < 64; i++)
-                       printk(" %4.4x%s", read_eeprom(ioaddr, i),
-                                  i % 16 == 15 ? "\n" : "");
-       }
-
-       ep->pci_dev = pdev;
-       ep->chip_id = chip_idx;
-       ep->chip_flags = pci_id_tbl[chip_idx].drv_flags;
-       ep->irq_mask =
-               (ep->chip_flags & TYPE2_INTR ?  PCIBusErr175 : PCIBusErr170)
-                | CntFull | TxUnderrun | EpicNapiEvent;
-
-       /* Find the connected MII xcvrs.
-          Doing this in open() would allow detecting external xcvrs later, but
-          takes much time and no cards have external MII. */
-       {
-               int phy, phy_idx = 0;
-               for (phy = 1; phy < 32 && phy_idx < sizeof(ep->phys); phy++) {
-                       int mii_status = mdio_read(dev, phy, MII_BMSR);
-                       if (mii_status != 0xffff  &&  mii_status != 0x0000) {
-                               ep->phys[phy_idx++] = phy;
-                               dev_info(&pdev->dev,
-                                       "MII transceiver #%d control "
-                                       "%4.4x status %4.4x.\n",
-                                       phy, mdio_read(dev, phy, 0), mii_status);
-                       }
-               }
-               ep->mii_phy_cnt = phy_idx;
-               if (phy_idx != 0) {
-                       phy = ep->phys[0];
-                       ep->mii.advertising = mdio_read(dev, phy, MII_ADVERTISE);
-                       dev_info(&pdev->dev,
-                               "Autonegotiation advertising %4.4x link "
-                                  "partner %4.4x.\n",
-                                  ep->mii.advertising, mdio_read(dev, phy, 5));
-               } else if ( ! (ep->chip_flags & NO_MII)) {
-                       dev_warn(&pdev->dev,
-                               "***WARNING***: No MII transceiver found!\n");
-                       /* Use the known PHY address of the EPII. */
-                       ep->phys[0] = 3;
-               }
-               ep->mii.phy_id = ep->phys[0];
-       }
-
-       /* Turn off the MII xcvr (175 only!), leave the chip in low-power mode. */
-       if (ep->chip_flags & MII_PWRDWN)
-               outl(inl(ioaddr + NVCTL) & ~0x483C, ioaddr + NVCTL);
-       outl(0x0008, ioaddr + GENCTL);
-
-       /* The lower four bits are the media type. */
-       if (duplex) {
-               ep->mii.force_media = ep->mii.full_duplex = 1;
-               dev_info(&pdev->dev, "Forced full duplex requested.\n");
-       }
-       dev->if_port = ep->default_port = option;
-
-       /* The Epic-specific entries in the device structure. */
-       dev->netdev_ops = &epic_netdev_ops;
-       dev->ethtool_ops = &netdev_ethtool_ops;
-       dev->watchdog_timeo = TX_TIMEOUT;
-       netif_napi_add(dev, &ep->napi, epic_poll, 64);
-
-       ret = register_netdev(dev);
-       if (ret < 0)
-               goto err_out_unmap_rx;
-
-       printk(KERN_INFO "%s: %s at %#lx, IRQ %d, %pM\n",
-              dev->name, pci_id_tbl[chip_idx].name, ioaddr, dev->irq,
-              dev->dev_addr);
-
-out:
-       return ret;
-
-err_out_unmap_rx:
-       pci_free_consistent(pdev, RX_TOTAL_SIZE, ep->rx_ring, ep->rx_ring_dma);
-err_out_unmap_tx:
-       pci_free_consistent(pdev, TX_TOTAL_SIZE, ep->tx_ring, ep->tx_ring_dma);
-err_out_iounmap:
-#ifndef USE_IO_OPS
-       iounmap(ioaddr);
-err_out_free_netdev:
-#endif
-       free_netdev(dev);
-err_out_free_res:
-       pci_release_regions(pdev);
-err_out_disable:
-       pci_disable_device(pdev);
-       goto out;
-}
-
-/* Serial EEPROM section. */
-
-/*  EEPROM_Ctrl bits. */
-#define EE_SHIFT_CLK   0x04    /* EEPROM shift clock. */
-#define EE_CS                  0x02    /* EEPROM chip select. */
-#define EE_DATA_WRITE  0x08    /* EEPROM chip data in. */
-#define EE_WRITE_0             0x01
-#define EE_WRITE_1             0x09
-#define EE_DATA_READ   0x10    /* EEPROM chip data out. */
-#define EE_ENB                 (0x0001 | EE_CS)
-
-/* Delay between EEPROM clock transitions.
-   This serves to flush the operation to the PCI bus.
- */
-
-#define eeprom_delay() inl(ee_addr)
-
-/* The EEPROM commands include the alway-set leading bit. */
-#define EE_WRITE_CMD   (5 << 6)
-#define EE_READ64_CMD  (6 << 6)
-#define EE_READ256_CMD (6 << 8)
-#define EE_ERASE_CMD   (7 << 6)
-
-static void epic_disable_int(struct net_device *dev, struct epic_private *ep)
-{
-       long ioaddr = dev->base_addr;
-
-       outl(0x00000000, ioaddr + INTMASK);
-}
-
-static inline void __epic_pci_commit(long ioaddr)
-{
-#ifndef USE_IO_OPS
-       inl(ioaddr + INTMASK);
-#endif
-}
-
-static inline void epic_napi_irq_off(struct net_device *dev,
-                                    struct epic_private *ep)
-{
-       long ioaddr = dev->base_addr;
-
-       outl(ep->irq_mask & ~EpicNapiEvent, ioaddr + INTMASK);
-       __epic_pci_commit(ioaddr);
-}
-
-static inline void epic_napi_irq_on(struct net_device *dev,
-                                   struct epic_private *ep)
-{
-       long ioaddr = dev->base_addr;
-
-       /* No need to commit possible posted write */
-       outl(ep->irq_mask | EpicNapiEvent, ioaddr + INTMASK);
-}
-
-static int __devinit read_eeprom(long ioaddr, int location)
-{
-       int i;
-       int retval = 0;
-       long ee_addr = ioaddr + EECTL;
-       int read_cmd = location |
-               (inl(ee_addr) & 0x40 ? EE_READ64_CMD : EE_READ256_CMD);
-
-       outl(EE_ENB & ~EE_CS, ee_addr);
-       outl(EE_ENB, ee_addr);
-
-       /* Shift the read command bits out. */
-       for (i = 12; i >= 0; i--) {
-               short dataval = (read_cmd & (1 << i)) ? EE_WRITE_1 : EE_WRITE_0;
-               outl(EE_ENB | dataval, ee_addr);
-               eeprom_delay();
-               outl(EE_ENB | dataval | EE_SHIFT_CLK, ee_addr);
-               eeprom_delay();
-       }
-       outl(EE_ENB, ee_addr);
-
-       for (i = 16; i > 0; i--) {
-               outl(EE_ENB | EE_SHIFT_CLK, ee_addr);
-               eeprom_delay();
-               retval = (retval << 1) | ((inl(ee_addr) & EE_DATA_READ) ? 1 : 0);
-               outl(EE_ENB, ee_addr);
-               eeprom_delay();
-       }
-
-       /* Terminate the EEPROM access. */
-       outl(EE_ENB & ~EE_CS, ee_addr);
-       return retval;
-}
-
-#define MII_READOP             1
-#define MII_WRITEOP            2
-static int mdio_read(struct net_device *dev, int phy_id, int location)
-{
-       long ioaddr = dev->base_addr;
-       int read_cmd = (phy_id << 9) | (location << 4) | MII_READOP;
-       int i;
-
-       outl(read_cmd, ioaddr + MIICtrl);
-       /* Typical operation takes 25 loops. */
-       for (i = 400; i > 0; i--) {
-               barrier();
-               if ((inl(ioaddr + MIICtrl) & MII_READOP) == 0) {
-                       /* Work around read failure bug. */
-                       if (phy_id == 1 && location < 6 &&
-                           inw(ioaddr + MIIData) == 0xffff) {
-                               outl(read_cmd, ioaddr + MIICtrl);
-                               continue;
-                       }
-                       return inw(ioaddr + MIIData);
-               }
-       }
-       return 0xffff;
-}
-
-static void mdio_write(struct net_device *dev, int phy_id, int loc, int value)
-{
-       long ioaddr = dev->base_addr;
-       int i;
-
-       outw(value, ioaddr + MIIData);
-       outl((phy_id << 9) | (loc << 4) | MII_WRITEOP, ioaddr + MIICtrl);
-       for (i = 10000; i > 0; i--) {
-               barrier();
-               if ((inl(ioaddr + MIICtrl) & MII_WRITEOP) == 0)
-                       break;
-       }
-}
-
-
-static int epic_open(struct net_device *dev)
-{
-       struct epic_private *ep = netdev_priv(dev);
-       long ioaddr = dev->base_addr;
-       int i;
-       int retval;
-
-       /* Soft reset the chip. */
-       outl(0x4001, ioaddr + GENCTL);
-
-       napi_enable(&ep->napi);
-       if ((retval = request_irq(dev->irq, epic_interrupt, IRQF_SHARED, dev->name, dev))) {
-               napi_disable(&ep->napi);
-               return retval;
-       }
-
-       epic_init_ring(dev);
-
-       outl(0x4000, ioaddr + GENCTL);
-       /* This magic is documented in SMSC app note 7.15 */
-       for (i = 16; i > 0; i--)
-               outl(0x0008, ioaddr + TEST1);
-
-       /* Pull the chip out of low-power mode, enable interrupts, and set for
-          PCI read multiple.  The MIIcfg setting and strange write order are
-          required by the details of which bits are reset and the transceiver
-          wiring on the Ositech CardBus card.
-       */
-#if 0
-       outl(dev->if_port == 1 ? 0x13 : 0x12, ioaddr + MIICfg);
-#endif
-       if (ep->chip_flags & MII_PWRDWN)
-               outl((inl(ioaddr + NVCTL) & ~0x003C) | 0x4800, ioaddr + NVCTL);
-
-       /* Tell the chip to byteswap descriptors on big-endian hosts */
-#ifdef __BIG_ENDIAN
-       outl(0x4432 | (RX_FIFO_THRESH<<8), ioaddr + GENCTL);
-       inl(ioaddr + GENCTL);
-       outl(0x0432 | (RX_FIFO_THRESH<<8), ioaddr + GENCTL);
-#else
-       outl(0x4412 | (RX_FIFO_THRESH<<8), ioaddr + GENCTL);
-       inl(ioaddr + GENCTL);
-       outl(0x0412 | (RX_FIFO_THRESH<<8), ioaddr + GENCTL);
-#endif
-
-       udelay(20); /* Looks like EPII needs that if you want reliable RX init. FIXME: pci posting bug? */
-
-       for (i = 0; i < 3; i++)
-               outl(le16_to_cpu(((__le16*)dev->dev_addr)[i]), ioaddr + LAN0 + i*4);
-
-       ep->tx_threshold = TX_FIFO_THRESH;
-       outl(ep->tx_threshold, ioaddr + TxThresh);
-
-       if (media2miictl[dev->if_port & 15]) {
-               if (ep->mii_phy_cnt)
-                       mdio_write(dev, ep->phys[0], MII_BMCR, media2miictl[dev->if_port&15]);
-               if (dev->if_port == 1) {
-                       if (debug > 1)
-                               printk(KERN_INFO "%s: Using the 10base2 transceiver, MII "
-                                          "status %4.4x.\n",
-                                          dev->name, mdio_read(dev, ep->phys[0], MII_BMSR));
-               }
-       } else {
-               int mii_lpa = mdio_read(dev, ep->phys[0], MII_LPA);
-               if (mii_lpa != 0xffff) {
-                       if ((mii_lpa & LPA_100FULL) || (mii_lpa & 0x01C0) == LPA_10FULL)
-                               ep->mii.full_duplex = 1;
-                       else if (! (mii_lpa & LPA_LPACK))
-                               mdio_write(dev, ep->phys[0], MII_BMCR, BMCR_ANENABLE|BMCR_ANRESTART);
-                       if (debug > 1)
-                               printk(KERN_INFO "%s: Setting %s-duplex based on MII xcvr %d"
-                                          " register read of %4.4x.\n", dev->name,
-                                          ep->mii.full_duplex ? "full" : "half",
-                                          ep->phys[0], mii_lpa);
-               }
-       }
-
-       outl(ep->mii.full_duplex ? 0x7F : 0x79, ioaddr + TxCtrl);
-       outl(ep->rx_ring_dma, ioaddr + PRxCDAR);
-       outl(ep->tx_ring_dma, ioaddr + PTxCDAR);
-
-       /* Start the chip's Rx process. */
-       set_rx_mode(dev);
-       outl(StartRx | RxQueued, ioaddr + COMMAND);
-
-       netif_start_queue(dev);
-
-       /* Enable interrupts by setting the interrupt mask. */
-       outl((ep->chip_flags & TYPE2_INTR ? PCIBusErr175 : PCIBusErr170)
-                | CntFull | TxUnderrun
-                | RxError | RxHeader | EpicNapiEvent, ioaddr + INTMASK);
-
-       if (debug > 1)
-               printk(KERN_DEBUG "%s: epic_open() ioaddr %lx IRQ %d status %4.4x "
-                          "%s-duplex.\n",
-                          dev->name, ioaddr, dev->irq, (int)inl(ioaddr + GENCTL),
-                          ep->mii.full_duplex ? "full" : "half");
-
-       /* Set the timer to switch to check for link beat and perhaps switch
-          to an alternate media type. */
-       init_timer(&ep->timer);
-       ep->timer.expires = jiffies + 3*HZ;
-       ep->timer.data = (unsigned long)dev;
-       ep->timer.function = epic_timer;                                /* timer handler */
-       add_timer(&ep->timer);
-
-       return 0;
-}
-
-/* Reset the chip to recover from a PCI transaction error.
-   This may occur at interrupt time. */
-static void epic_pause(struct net_device *dev)
-{
-       long ioaddr = dev->base_addr;
-
-       netif_stop_queue (dev);
-
-       /* Disable interrupts by clearing the interrupt mask. */
-       outl(0x00000000, ioaddr + INTMASK);
-       /* Stop the chip's Tx and Rx DMA processes. */
-       outw(StopRx | StopTxDMA | StopRxDMA, ioaddr + COMMAND);
-
-       /* Update the error counts. */
-       if (inw(ioaddr + COMMAND) != 0xffff) {
-               dev->stats.rx_missed_errors += inb(ioaddr + MPCNT);
-               dev->stats.rx_frame_errors += inb(ioaddr + ALICNT);
-               dev->stats.rx_crc_errors += inb(ioaddr + CRCCNT);
-       }
-
-       /* Remove the packets on the Rx queue. */
-       epic_rx(dev, RX_RING_SIZE);
-}
-
-static void epic_restart(struct net_device *dev)
-{
-       long ioaddr = dev->base_addr;
-       struct epic_private *ep = netdev_priv(dev);
-       int i;
-
-       /* Soft reset the chip. */
-       outl(0x4001, ioaddr + GENCTL);
-
-       printk(KERN_DEBUG "%s: Restarting the EPIC chip, Rx %d/%d Tx %d/%d.\n",
-                  dev->name, ep->cur_rx, ep->dirty_rx, ep->dirty_tx, ep->cur_tx);
-       udelay(1);
-
-       /* This magic is documented in SMSC app note 7.15 */
-       for (i = 16; i > 0; i--)
-               outl(0x0008, ioaddr + TEST1);
-
-#ifdef __BIG_ENDIAN
-       outl(0x0432 | (RX_FIFO_THRESH<<8), ioaddr + GENCTL);
-#else
-       outl(0x0412 | (RX_FIFO_THRESH<<8), ioaddr + GENCTL);
-#endif
-       outl(dev->if_port == 1 ? 0x13 : 0x12, ioaddr + MIICfg);
-       if (ep->chip_flags & MII_PWRDWN)
-               outl((inl(ioaddr + NVCTL) & ~0x003C) | 0x4800, ioaddr + NVCTL);
-
-       for (i = 0; i < 3; i++)
-               outl(le16_to_cpu(((__le16*)dev->dev_addr)[i]), ioaddr + LAN0 + i*4);
-
-       ep->tx_threshold = TX_FIFO_THRESH;
-       outl(ep->tx_threshold, ioaddr + TxThresh);
-       outl(ep->mii.full_duplex ? 0x7F : 0x79, ioaddr + TxCtrl);
-       outl(ep->rx_ring_dma + (ep->cur_rx%RX_RING_SIZE)*
-               sizeof(struct epic_rx_desc), ioaddr + PRxCDAR);
-       outl(ep->tx_ring_dma + (ep->dirty_tx%TX_RING_SIZE)*
-                sizeof(struct epic_tx_desc), ioaddr + PTxCDAR);
-
-       /* Start the chip's Rx process. */
-       set_rx_mode(dev);
-       outl(StartRx | RxQueued, ioaddr + COMMAND);
-
-       /* Enable interrupts by setting the interrupt mask. */
-       outl((ep->chip_flags & TYPE2_INTR ? PCIBusErr175 : PCIBusErr170)
-                | CntFull | TxUnderrun
-                | RxError | RxHeader | EpicNapiEvent, ioaddr + INTMASK);
-
-       printk(KERN_DEBUG "%s: epic_restart() done, cmd status %4.4x, ctl %4.4x"
-                  " interrupt %4.4x.\n",
-                  dev->name, (int)inl(ioaddr + COMMAND), (int)inl(ioaddr + GENCTL),
-                  (int)inl(ioaddr + INTSTAT));
-}
-
-static void check_media(struct net_device *dev)
-{
-       struct epic_private *ep = netdev_priv(dev);
-       long ioaddr = dev->base_addr;
-       int mii_lpa = ep->mii_phy_cnt ? mdio_read(dev, ep->phys[0], MII_LPA) : 0;
-       int negotiated = mii_lpa & ep->mii.advertising;
-       int duplex = (negotiated & 0x0100) || (negotiated & 0x01C0) == 0x0040;
-
-       if (ep->mii.force_media)
-               return;
-       if (mii_lpa == 0xffff)          /* Bogus read */
-               return;
-       if (ep->mii.full_duplex != duplex) {
-               ep->mii.full_duplex = duplex;
-               printk(KERN_INFO "%s: Setting %s-duplex based on MII #%d link"
-                          " partner capability of %4.4x.\n", dev->name,
-                          ep->mii.full_duplex ? "full" : "half", ep->phys[0], mii_lpa);
-               outl(ep->mii.full_duplex ? 0x7F : 0x79, ioaddr + TxCtrl);
-       }
-}
-
-static void epic_timer(unsigned long data)
-{
-       struct net_device *dev = (struct net_device *)data;
-       struct epic_private *ep = netdev_priv(dev);
-       long ioaddr = dev->base_addr;
-       int next_tick = 5*HZ;
-
-       if (debug > 3) {
-               printk(KERN_DEBUG "%s: Media monitor tick, Tx status %8.8x.\n",
-                          dev->name, (int)inl(ioaddr + TxSTAT));
-               printk(KERN_DEBUG "%s: Other registers are IntMask %4.4x "
-                          "IntStatus %4.4x RxStatus %4.4x.\n",
-                          dev->name, (int)inl(ioaddr + INTMASK),
-                          (int)inl(ioaddr + INTSTAT), (int)inl(ioaddr + RxSTAT));
-       }
-
-       check_media(dev);
-
-       ep->timer.expires = jiffies + next_tick;
-       add_timer(&ep->timer);
-}
-
-static void epic_tx_timeout(struct net_device *dev)
-{
-       struct epic_private *ep = netdev_priv(dev);
-       long ioaddr = dev->base_addr;
-
-       if (debug > 0) {
-               printk(KERN_WARNING "%s: Transmit timeout using MII device, "
-                          "Tx status %4.4x.\n",
-                          dev->name, (int)inw(ioaddr + TxSTAT));
-               if (debug > 1) {
-                       printk(KERN_DEBUG "%s: Tx indices: dirty_tx %d, cur_tx %d.\n",
-                                  dev->name, ep->dirty_tx, ep->cur_tx);
-               }
-       }
-       if (inw(ioaddr + TxSTAT) & 0x10) {              /* Tx FIFO underflow. */
-               dev->stats.tx_fifo_errors++;
-               outl(RestartTx, ioaddr + COMMAND);
-       } else {
-               epic_restart(dev);
-               outl(TxQueued, dev->base_addr + COMMAND);
-       }
-
-       dev->trans_start = jiffies; /* prevent tx timeout */
-       dev->stats.tx_errors++;
-       if (!ep->tx_full)
-               netif_wake_queue(dev);
-}
-
-/* Initialize the Rx and Tx rings, along with various 'dev' bits. */
-static void epic_init_ring(struct net_device *dev)
-{
-       struct epic_private *ep = netdev_priv(dev);
-       int i;
-
-       ep->tx_full = 0;
-       ep->dirty_tx = ep->cur_tx = 0;
-       ep->cur_rx = ep->dirty_rx = 0;
-       ep->rx_buf_sz = (dev->mtu <= 1500 ? PKT_BUF_SZ : dev->mtu + 32);
-
-       /* Initialize all Rx descriptors. */
-       for (i = 0; i < RX_RING_SIZE; i++) {
-               ep->rx_ring[i].rxstatus = 0;
-               ep->rx_ring[i].buflength = ep->rx_buf_sz;
-               ep->rx_ring[i].next = ep->rx_ring_dma +
-                                     (i+1)*sizeof(struct epic_rx_desc);
-               ep->rx_skbuff[i] = NULL;
-       }
-       /* Mark the last entry as wrapping the ring. */
-       ep->rx_ring[i-1].next = ep->rx_ring_dma;
-
-       /* Fill in the Rx buffers.  Handle allocation failure gracefully. */
-       for (i = 0; i < RX_RING_SIZE; i++) {
-               struct sk_buff *skb = dev_alloc_skb(ep->rx_buf_sz + 2);
-               ep->rx_skbuff[i] = skb;
-               if (skb == NULL)
-                       break;
-               skb_reserve(skb, 2);    /* 16 byte align the IP header. */
-               ep->rx_ring[i].bufaddr = pci_map_single(ep->pci_dev,
-                       skb->data, ep->rx_buf_sz, PCI_DMA_FROMDEVICE);
-               ep->rx_ring[i].rxstatus = DescOwn;
-       }
-       ep->dirty_rx = (unsigned int)(i - RX_RING_SIZE);
-
-       /* The Tx buffer descriptor is filled in as needed, but we
-          do need to clear the ownership bit. */
-       for (i = 0; i < TX_RING_SIZE; i++) {
-               ep->tx_skbuff[i] = NULL;
-               ep->tx_ring[i].txstatus = 0x0000;
-               ep->tx_ring[i].next = ep->tx_ring_dma +
-                       (i+1)*sizeof(struct epic_tx_desc);
-       }
-       ep->tx_ring[i-1].next = ep->tx_ring_dma;
-}
-
-static netdev_tx_t epic_start_xmit(struct sk_buff *skb, struct net_device *dev)
-{
-       struct epic_private *ep = netdev_priv(dev);
-       int entry, free_count;
-       u32 ctrl_word;
-       unsigned long flags;
-
-       if (skb_padto(skb, ETH_ZLEN))
-               return NETDEV_TX_OK;
-
-       /* Caution: the write order is important here, set the field with the
-          "ownership" bit last. */
-
-       /* Calculate the next Tx descriptor entry. */
-       spin_lock_irqsave(&ep->lock, flags);
-       free_count = ep->cur_tx - ep->dirty_tx;
-       entry = ep->cur_tx % TX_RING_SIZE;
-
-       ep->tx_skbuff[entry] = skb;
-       ep->tx_ring[entry].bufaddr = pci_map_single(ep->pci_dev, skb->data,
-                                                   skb->len, PCI_DMA_TODEVICE);
-       if (free_count < TX_QUEUE_LEN/2) {/* Typical path */
-               ctrl_word = 0x100000; /* No interrupt */
-       } else if (free_count == TX_QUEUE_LEN/2) {
-               ctrl_word = 0x140000; /* Tx-done intr. */
-       } else if (free_count < TX_QUEUE_LEN - 1) {
-               ctrl_word = 0x100000; /* No Tx-done intr. */
-       } else {
-               /* Leave room for an additional entry. */
-               ctrl_word = 0x140000; /* Tx-done intr. */
-               ep->tx_full = 1;
-       }
-       ep->tx_ring[entry].buflength = ctrl_word | skb->len;
-       ep->tx_ring[entry].txstatus =
-               ((skb->len >= ETH_ZLEN ? skb->len : ETH_ZLEN) << 16)
-                           | DescOwn;
-
-       ep->cur_tx++;
-       if (ep->tx_full)
-               netif_stop_queue(dev);
-
-       spin_unlock_irqrestore(&ep->lock, flags);
-       /* Trigger an immediate transmit demand. */
-       outl(TxQueued, dev->base_addr + COMMAND);
-
-       if (debug > 4)
-               printk(KERN_DEBUG "%s: Queued Tx packet size %d to slot %d, "
-                          "flag %2.2x Tx status %8.8x.\n",
-                          dev->name, (int)skb->len, entry, ctrl_word,
-                          (int)inl(dev->base_addr + TxSTAT));
-
-       return NETDEV_TX_OK;
-}
-
-static void epic_tx_error(struct net_device *dev, struct epic_private *ep,
-                         int status)
-{
-       struct net_device_stats *stats = &dev->stats;
-
-#ifndef final_version
-       /* There was an major error, log it. */
-       if (debug > 1)
-               printk(KERN_DEBUG "%s: Transmit error, Tx status %8.8x.\n",
-                      dev->name, status);
-#endif
-       stats->tx_errors++;
-       if (status & 0x1050)
-               stats->tx_aborted_errors++;
-       if (status & 0x0008)
-               stats->tx_carrier_errors++;
-       if (status & 0x0040)
-               stats->tx_window_errors++;
-       if (status & 0x0010)
-               stats->tx_fifo_errors++;
-}
-
-static void epic_tx(struct net_device *dev, struct epic_private *ep)
-{
-       unsigned int dirty_tx, cur_tx;
-
-       /*
-        * Note: if this lock becomes a problem we can narrow the locked
-        * region at the cost of occasionally grabbing the lock more times.
-        */
-       cur_tx = ep->cur_tx;
-       for (dirty_tx = ep->dirty_tx; cur_tx - dirty_tx > 0; dirty_tx++) {
-               struct sk_buff *skb;
-               int entry = dirty_tx % TX_RING_SIZE;
-               int txstatus = ep->tx_ring[entry].txstatus;
-
-               if (txstatus & DescOwn)
-                       break;  /* It still hasn't been Txed */
-
-               if (likely(txstatus & 0x0001)) {
-                       dev->stats.collisions += (txstatus >> 8) & 15;
-                       dev->stats.tx_packets++;
-                       dev->stats.tx_bytes += ep->tx_skbuff[entry]->len;
-               } else
-                       epic_tx_error(dev, ep, txstatus);
-
-               /* Free the original skb. */
-               skb = ep->tx_skbuff[entry];
-               pci_unmap_single(ep->pci_dev, ep->tx_ring[entry].bufaddr,
-                                skb->len, PCI_DMA_TODEVICE);
-               dev_kfree_skb_irq(skb);
-               ep->tx_skbuff[entry] = NULL;
-       }
-
-#ifndef final_version
-       if (cur_tx - dirty_tx > TX_RING_SIZE) {
-               printk(KERN_WARNING
-                      "%s: Out-of-sync dirty pointer, %d vs. %d, full=%d.\n",
-                      dev->name, dirty_tx, cur_tx, ep->tx_full);
-               dirty_tx += TX_RING_SIZE;
-       }
-#endif
-       ep->dirty_tx = dirty_tx;
-       if (ep->tx_full && cur_tx - dirty_tx < TX_QUEUE_LEN - 4) {
-               /* The ring is no longer full, allow new TX entries. */
-               ep->tx_full = 0;
-               netif_wake_queue(dev);
-       }
-}
-
-/* The interrupt handler does all of the Rx thread work and cleans up
-   after the Tx thread. */
-static irqreturn_t epic_interrupt(int irq, void *dev_instance)
-{
-       struct net_device *dev = dev_instance;
-       struct epic_private *ep = netdev_priv(dev);
-       long ioaddr = dev->base_addr;
-       unsigned int handled = 0;
-       int status;
-
-       status = inl(ioaddr + INTSTAT);
-       /* Acknowledge all of the current interrupt sources ASAP. */
-       outl(status & EpicNormalEvent, ioaddr + INTSTAT);
-
-       if (debug > 4) {
-               printk(KERN_DEBUG "%s: Interrupt, status=%#8.8x new "
-                                  "intstat=%#8.8x.\n", dev->name, status,
-                                  (int)inl(ioaddr + INTSTAT));
-       }
-
-       if ((status & IntrSummary) == 0)
-               goto out;
-
-       handled = 1;
-
-       if ((status & EpicNapiEvent) && !ep->reschedule_in_poll) {
-               spin_lock(&ep->napi_lock);
-               if (napi_schedule_prep(&ep->napi)) {
-                       epic_napi_irq_off(dev, ep);
-                       __napi_schedule(&ep->napi);
-               } else
-                       ep->reschedule_in_poll++;
-               spin_unlock(&ep->napi_lock);
-       }
-       status &= ~EpicNapiEvent;
-
-       /* Check uncommon events all at once. */
-       if (status & (CntFull | TxUnderrun | PCIBusErr170 | PCIBusErr175)) {
-               if (status == EpicRemoved)
-                       goto out;
-
-               /* Always update the error counts to avoid overhead later. */
-               dev->stats.rx_missed_errors += inb(ioaddr + MPCNT);
-               dev->stats.rx_frame_errors += inb(ioaddr + ALICNT);
-               dev->stats.rx_crc_errors += inb(ioaddr + CRCCNT);
-
-               if (status & TxUnderrun) { /* Tx FIFO underflow. */
-                       dev->stats.tx_fifo_errors++;
-                       outl(ep->tx_threshold += 128, ioaddr + TxThresh);
-                       /* Restart the transmit process. */
-                       outl(RestartTx, ioaddr + COMMAND);
-               }
-               if (status & PCIBusErr170) {
-                       printk(KERN_ERR "%s: PCI Bus Error! status %4.4x.\n",
-                                        dev->name, status);
-                       epic_pause(dev);
-                       epic_restart(dev);
-               }
-               /* Clear all error sources. */
-               outl(status & 0x7f18, ioaddr + INTSTAT);
-       }
-
-out:
-       if (debug > 3) {
-               printk(KERN_DEBUG "%s: exit interrupt, intr_status=%#4.4x.\n",
-                                  dev->name, status);
-       }
-
-       return IRQ_RETVAL(handled);
-}
-
-static int epic_rx(struct net_device *dev, int budget)
-{
-       struct epic_private *ep = netdev_priv(dev);
-       int entry = ep->cur_rx % RX_RING_SIZE;
-       int rx_work_limit = ep->dirty_rx + RX_RING_SIZE - ep->cur_rx;
-       int work_done = 0;
-
-       if (debug > 4)
-               printk(KERN_DEBUG " In epic_rx(), entry %d %8.8x.\n", entry,
-                          ep->rx_ring[entry].rxstatus);
-
-       if (rx_work_limit > budget)
-               rx_work_limit = budget;
-
-       /* If we own the next entry, it's a new packet. Send it up. */
-       while ((ep->rx_ring[entry].rxstatus & DescOwn) == 0) {
-               int status = ep->rx_ring[entry].rxstatus;
-
-               if (debug > 4)
-                       printk(KERN_DEBUG "  epic_rx() status was %8.8x.\n", status);
-               if (--rx_work_limit < 0)
-                       break;
-               if (status & 0x2006) {
-                       if (debug > 2)
-                               printk(KERN_DEBUG "%s: epic_rx() error status was %8.8x.\n",
-                                          dev->name, status);
-                       if (status & 0x2000) {
-                               printk(KERN_WARNING "%s: Oversized Ethernet frame spanned "
-                                          "multiple buffers, status %4.4x!\n", dev->name, status);
-                               dev->stats.rx_length_errors++;
-                       } else if (status & 0x0006)
-                               /* Rx Frame errors are counted in hardware. */
-                               dev->stats.rx_errors++;
-               } else {
-                       /* Malloc up new buffer, compatible with net-2e. */
-                       /* Omit the four octet CRC from the length. */
-                       short pkt_len = (status >> 16) - 4;
-                       struct sk_buff *skb;
-
-                       if (pkt_len > PKT_BUF_SZ - 4) {
-                               printk(KERN_ERR "%s: Oversized Ethernet frame, status %x "
-                                          "%d bytes.\n",
-                                          dev->name, status, pkt_len);
-                               pkt_len = 1514;
-                       }
-                       /* Check if the packet is long enough to accept without copying
-                          to a minimally-sized skbuff. */
-                       if (pkt_len < rx_copybreak &&
-                           (skb = dev_alloc_skb(pkt_len + 2)) != NULL) {
-                               skb_reserve(skb, 2);    /* 16 byte align the IP header */
-                               pci_dma_sync_single_for_cpu(ep->pci_dev,
-                                                           ep->rx_ring[entry].bufaddr,
-                                                           ep->rx_buf_sz,
-                                                           PCI_DMA_FROMDEVICE);
-                               skb_copy_to_linear_data(skb, ep->rx_skbuff[entry]->data, pkt_len);
-                               skb_put(skb, pkt_len);
-                               pci_dma_sync_single_for_device(ep->pci_dev,
-                                                              ep->rx_ring[entry].bufaddr,
-                                                              ep->rx_buf_sz,
-                                                              PCI_DMA_FROMDEVICE);
-                       } else {
-                               pci_unmap_single(ep->pci_dev,
-                                       ep->rx_ring[entry].bufaddr,
-                                       ep->rx_buf_sz, PCI_DMA_FROMDEVICE);
-                               skb_put(skb = ep->rx_skbuff[entry], pkt_len);
-                               ep->rx_skbuff[entry] = NULL;
-                       }
-                       skb->protocol = eth_type_trans(skb, dev);
-                       netif_receive_skb(skb);
-                       dev->stats.rx_packets++;
-                       dev->stats.rx_bytes += pkt_len;
-               }
-               work_done++;
-               entry = (++ep->cur_rx) % RX_RING_SIZE;
-       }
-
-       /* Refill the Rx ring buffers. */
-       for (; ep->cur_rx - ep->dirty_rx > 0; ep->dirty_rx++) {
-               entry = ep->dirty_rx % RX_RING_SIZE;
-               if (ep->rx_skbuff[entry] == NULL) {
-                       struct sk_buff *skb;
-                       skb = ep->rx_skbuff[entry] = dev_alloc_skb(ep->rx_buf_sz + 2);
-                       if (skb == NULL)
-                               break;
-                       skb_reserve(skb, 2);    /* Align IP on 16 byte boundaries */
-                       ep->rx_ring[entry].bufaddr = pci_map_single(ep->pci_dev,
-                               skb->data, ep->rx_buf_sz, PCI_DMA_FROMDEVICE);
-                       work_done++;
-               }
-               /* AV: shouldn't we add a barrier here? */
-               ep->rx_ring[entry].rxstatus = DescOwn;
-       }
-       return work_done;
-}
-
-static void epic_rx_err(struct net_device *dev, struct epic_private *ep)
-{
-       long ioaddr = dev->base_addr;
-       int status;
-
-       status = inl(ioaddr + INTSTAT);
-
-       if (status == EpicRemoved)
-               return;
-       if (status & RxOverflow)        /* Missed a Rx frame. */
-               dev->stats.rx_errors++;
-       if (status & (RxOverflow | RxFull))
-               outw(RxQueued, ioaddr + COMMAND);
-}
-
-static int epic_poll(struct napi_struct *napi, int budget)
-{
-       struct epic_private *ep = container_of(napi, struct epic_private, napi);
-       struct net_device *dev = ep->mii.dev;
-       int work_done = 0;
-       long ioaddr = dev->base_addr;
-
-rx_action:
-
-       epic_tx(dev, ep);
-
-       work_done += epic_rx(dev, budget);
-
-       epic_rx_err(dev, ep);
-
-       if (work_done < budget) {
-               unsigned long flags;
-               int more;
-
-               /* A bit baroque but it avoids a (space hungry) spin_unlock */
-
-               spin_lock_irqsave(&ep->napi_lock, flags);
-
-               more = ep->reschedule_in_poll;
-               if (!more) {
-                       __napi_complete(napi);
-                       outl(EpicNapiEvent, ioaddr + INTSTAT);
-                       epic_napi_irq_on(dev, ep);
-               } else
-                       ep->reschedule_in_poll--;
-
-               spin_unlock_irqrestore(&ep->napi_lock, flags);
-
-               if (more)
-                       goto rx_action;
-       }
-
-       return work_done;
-}
-
-static int epic_close(struct net_device *dev)
-{
-       long ioaddr = dev->base_addr;
-       struct epic_private *ep = netdev_priv(dev);
-       struct sk_buff *skb;
-       int i;
-
-       netif_stop_queue(dev);
-       napi_disable(&ep->napi);
-
-       if (debug > 1)
-               printk(KERN_DEBUG "%s: Shutting down ethercard, status was %2.2x.\n",
-                          dev->name, (int)inl(ioaddr + INTSTAT));
-
-       del_timer_sync(&ep->timer);
-
-       epic_disable_int(dev, ep);
-
-       free_irq(dev->irq, dev);
-
-       epic_pause(dev);
-
-       /* Free all the skbuffs in the Rx queue. */
-       for (i = 0; i < RX_RING_SIZE; i++) {
-               skb = ep->rx_skbuff[i];
-               ep->rx_skbuff[i] = NULL;
-               ep->rx_ring[i].rxstatus = 0;            /* Not owned by Epic chip. */
-               ep->rx_ring[i].buflength = 0;
-               if (skb) {
-                       pci_unmap_single(ep->pci_dev, ep->rx_ring[i].bufaddr,
-                                        ep->rx_buf_sz, PCI_DMA_FROMDEVICE);
-                       dev_kfree_skb(skb);
-               }
-               ep->rx_ring[i].bufaddr = 0xBADF00D0; /* An invalid address. */
-       }
-       for (i = 0; i < TX_RING_SIZE; i++) {
-               skb = ep->tx_skbuff[i];
-               ep->tx_skbuff[i] = NULL;
-               if (!skb)
-                       continue;
-               pci_unmap_single(ep->pci_dev, ep->tx_ring[i].bufaddr,
-                                skb->len, PCI_DMA_TODEVICE);
-               dev_kfree_skb(skb);
-       }
-
-       /* Green! Leave the chip in low-power mode. */
-       outl(0x0008, ioaddr + GENCTL);
-
-       return 0;
-}
-
-static struct net_device_stats *epic_get_stats(struct net_device *dev)
-{
-       long ioaddr = dev->base_addr;
-
-       if (netif_running(dev)) {
-               /* Update the error counts. */
-               dev->stats.rx_missed_errors += inb(ioaddr + MPCNT);
-               dev->stats.rx_frame_errors += inb(ioaddr + ALICNT);
-               dev->stats.rx_crc_errors += inb(ioaddr + CRCCNT);
-       }
-
-       return &dev->stats;
-}
-
-/* Set or clear the multicast filter for this adaptor.
-   Note that we only use exclusion around actually queueing the
-   new frame, not around filling ep->setup_frame.  This is non-deterministic
-   when re-entered but still correct. */
-
-static void set_rx_mode(struct net_device *dev)
-{
-       long ioaddr = dev->base_addr;
-       struct epic_private *ep = netdev_priv(dev);
-       unsigned char mc_filter[8];              /* Multicast hash filter */
-       int i;
-
-       if (dev->flags & IFF_PROMISC) {                 /* Set promiscuous. */
-               outl(0x002C, ioaddr + RxCtrl);
-               /* Unconditionally log net taps. */
-               memset(mc_filter, 0xff, sizeof(mc_filter));
-       } else if ((!netdev_mc_empty(dev)) || (dev->flags & IFF_ALLMULTI)) {
-               /* There is apparently a chip bug, so the multicast filter
-                  is never enabled. */
-               /* Too many to filter perfectly -- accept all multicasts. */
-               memset(mc_filter, 0xff, sizeof(mc_filter));
-               outl(0x000C, ioaddr + RxCtrl);
-       } else if (netdev_mc_empty(dev)) {
-               outl(0x0004, ioaddr + RxCtrl);
-               return;
-       } else {                                        /* Never executed, for now. */
-               struct netdev_hw_addr *ha;
-
-               memset(mc_filter, 0, sizeof(mc_filter));
-               netdev_for_each_mc_addr(ha, dev) {
-                       unsigned int bit_nr =
-                               ether_crc_le(ETH_ALEN, ha->addr) & 0x3f;
-                       mc_filter[bit_nr >> 3] |= (1 << bit_nr);
-               }
-       }
-       /* ToDo: perhaps we need to stop the Tx and Rx process here? */
-       if (memcmp(mc_filter, ep->mc_filter, sizeof(mc_filter))) {
-               for (i = 0; i < 4; i++)
-                       outw(((u16 *)mc_filter)[i], ioaddr + MC0 + i*4);
-               memcpy(ep->mc_filter, mc_filter, sizeof(mc_filter));
-       }
-}
-
-static void netdev_get_drvinfo (struct net_device *dev, struct ethtool_drvinfo *info)
-{
-       struct epic_private *np = netdev_priv(dev);
-
-       strcpy (info->driver, DRV_NAME);
-       strcpy (info->version, DRV_VERSION);
-       strcpy (info->bus_info, pci_name(np->pci_dev));
-}
-
-static int netdev_get_settings(struct net_device *dev, struct ethtool_cmd *cmd)
-{
-       struct epic_private *np = netdev_priv(dev);
-       int rc;
-
-       spin_lock_irq(&np->lock);
-       rc = mii_ethtool_gset(&np->mii, cmd);
-       spin_unlock_irq(&np->lock);
-
-       return rc;
-}
-
-static int netdev_set_settings(struct net_device *dev, struct ethtool_cmd *cmd)
-{
-       struct epic_private *np = netdev_priv(dev);
-       int rc;
-
-       spin_lock_irq(&np->lock);
-       rc = mii_ethtool_sset(&np->mii, cmd);
-       spin_unlock_irq(&np->lock);
-
-       return rc;
-}
-
-static int netdev_nway_reset(struct net_device *dev)
-{
-       struct epic_private *np = netdev_priv(dev);
-       return mii_nway_restart(&np->mii);
-}
-
-static u32 netdev_get_link(struct net_device *dev)
-{
-       struct epic_private *np = netdev_priv(dev);
-       return mii_link_ok(&np->mii);
-}
-
-static u32 netdev_get_msglevel(struct net_device *dev)
-{
-       return debug;
-}
-
-static void netdev_set_msglevel(struct net_device *dev, u32 value)
-{
-       debug = value;
-}
-
-static int ethtool_begin(struct net_device *dev)
-{
-       unsigned long ioaddr = dev->base_addr;
-       /* power-up, if interface is down */
-       if (! netif_running(dev)) {
-               outl(0x0200, ioaddr + GENCTL);
-               outl((inl(ioaddr + NVCTL) & ~0x003C) | 0x4800, ioaddr + NVCTL);
-       }
-       return 0;
-}
-
-static void ethtool_complete(struct net_device *dev)
-{
-       unsigned long ioaddr = dev->base_addr;
-       /* power-down, if interface is down */
-       if (! netif_running(dev)) {
-               outl(0x0008, ioaddr + GENCTL);
-               outl((inl(ioaddr + NVCTL) & ~0x483C) | 0x0000, ioaddr + NVCTL);
-       }
-}
-
-static const struct ethtool_ops netdev_ethtool_ops = {
-       .get_drvinfo            = netdev_get_drvinfo,
-       .get_settings           = netdev_get_settings,
-       .set_settings           = netdev_set_settings,
-       .nway_reset             = netdev_nway_reset,
-       .get_link               = netdev_get_link,
-       .get_msglevel           = netdev_get_msglevel,
-       .set_msglevel           = netdev_set_msglevel,
-       .begin                  = ethtool_begin,
-       .complete               = ethtool_complete
-};
-
-static int netdev_ioctl(struct net_device *dev, struct ifreq *rq, int cmd)
-{
-       struct epic_private *np = netdev_priv(dev);
-       long ioaddr = dev->base_addr;
-       struct mii_ioctl_data *data = if_mii(rq);
-       int rc;
-
-       /* power-up, if interface is down */
-       if (! netif_running(dev)) {
-               outl(0x0200, ioaddr + GENCTL);
-               outl((inl(ioaddr + NVCTL) & ~0x003C) | 0x4800, ioaddr + NVCTL);
-       }
-
-       /* all non-ethtool ioctls (the SIOC[GS]MIIxxx ioctls) */
-       spin_lock_irq(&np->lock);
-       rc = generic_mii_ioctl(&np->mii, data, cmd, NULL);
-       spin_unlock_irq(&np->lock);
-
-       /* power-down, if interface is down */
-       if (! netif_running(dev)) {
-               outl(0x0008, ioaddr + GENCTL);
-               outl((inl(ioaddr + NVCTL) & ~0x483C) | 0x0000, ioaddr + NVCTL);
-       }
-       return rc;
-}
-
-
-static void __devexit epic_remove_one (struct pci_dev *pdev)
-{
-       struct net_device *dev = pci_get_drvdata(pdev);
-       struct epic_private *ep = netdev_priv(dev);
-
-       pci_free_consistent(pdev, TX_TOTAL_SIZE, ep->tx_ring, ep->tx_ring_dma);
-       pci_free_consistent(pdev, RX_TOTAL_SIZE, ep->rx_ring, ep->rx_ring_dma);
-       unregister_netdev(dev);
-#ifndef USE_IO_OPS
-       iounmap((void*) dev->base_addr);
-#endif
-       pci_release_regions(pdev);
-       free_netdev(dev);
-       pci_disable_device(pdev);
-       pci_set_drvdata(pdev, NULL);
-       /* pci_power_off(pdev, -1); */
-}
-
-
-#ifdef CONFIG_PM
-
-static int epic_suspend (struct pci_dev *pdev, pm_message_t state)
-{
-       struct net_device *dev = pci_get_drvdata(pdev);
-       long ioaddr = dev->base_addr;
-
-       if (!netif_running(dev))
-               return 0;
-       epic_pause(dev);
-       /* Put the chip into low-power mode. */
-       outl(0x0008, ioaddr + GENCTL);
-       /* pci_power_off(pdev, -1); */
-       return 0;
-}
-
-
-static int epic_resume (struct pci_dev *pdev)
-{
-       struct net_device *dev = pci_get_drvdata(pdev);
-
-       if (!netif_running(dev))
-               return 0;
-       epic_restart(dev);
-       /* pci_power_on(pdev); */
-       return 0;
-}
-
-#endif /* CONFIG_PM */
-
-
-static struct pci_driver epic_driver = {
-       .name           = DRV_NAME,
-       .id_table       = epic_pci_tbl,
-       .probe          = epic_init_one,
-       .remove         = __devexit_p(epic_remove_one),
-#ifdef CONFIG_PM
-       .suspend        = epic_suspend,
-       .resume         = epic_resume,
-#endif /* CONFIG_PM */
-};
-
-
-static int __init epic_init (void)
-{
-/* when a module, this is printed whether or not devices are found in probe */
-#ifdef MODULE
-       printk (KERN_INFO "%s%s",
-               version, version2);
-#endif
-
-       return pci_register_driver(&epic_driver);
-}
-
-
-static void __exit epic_cleanup (void)
-{
-       pci_unregister_driver (&epic_driver);
-}
-
-
-module_init(epic_init);
-module_exit(epic_cleanup);
index 5cd53f1b84d350f1c1d1a80c3024b7443667aac9..f1b9bddc155068e1fce5ed3ef9c4674d6547c035 100644 (file)
@@ -264,22 +264,9 @@ config STNIC
 
          If unsure, say N.
 
-config NET_VENDOR_SMC
-       bool "Western Digital/SMC cards"
-       depends on (ISA || MCA || EISA || MAC)
-       ---help---
-         If you have a network (Ethernet) card belonging to this class, say Y
-         and read the Ethernet-HOWTO, available from
-         <http://www.tldp.org/docs.html#howto>.
-
-         Note that the answer to this question doesn't directly affect the
-         kernel: saying N will just cause the configurator to skip all
-         the questions about Western Digital cards. If you say Y, you will be
-         asked for your specific card in the following questions.
-
 config ULTRAMCA
        tristate "SMC Ultra MCA support"
-       depends on NET_VENDOR_SMC && MCA
+       depends on MCA
        select CRC32
        ---help---
          If you have a network (Ethernet) card of this type and are running
@@ -291,7 +278,7 @@ config ULTRAMCA
 
 config ULTRA
        tristate "SMC Ultra support"
-       depends on NET_VENDOR_SMC && ISA
+       depends on ISA
        select CRC32
        ---help---
          If you have a network (Ethernet) card of this type, say Y and read
@@ -310,7 +297,7 @@ config ULTRA
 
 config ULTRA32
        tristate "SMC Ultra32 EISA support"
-       depends on NET_VENDOR_SMC && EISA
+       depends on EISA
        select CRC32
        ---help---
          If you have a network (Ethernet) card of this type, say Y and read
@@ -322,7 +309,7 @@ config ULTRA32
 
 config WD80x3
        tristate "WD80*3 support"
-       depends on NET_VENDOR_SMC && ISA
+       depends on ISA
        select CRC32
        ---help---
          If you have a network (Ethernet) card of this type, say Y and read
index ab591bb96702e4daffd10b4f77c30f686046bb77..ed5836ccb8d67d1edec5572ea053cdab3485131b 100644 (file)
@@ -18,5 +18,6 @@ source "drivers/net/ethernet/broadcom/Kconfig"
 source "drivers/net/ethernet/chelsio/Kconfig"
 source "drivers/net/ethernet/intel/Kconfig"
 source "drivers/net/ethernet/qlogic/Kconfig"
+source "drivers/net/ethernet/smsc/Kconfig"
 
 endif # ETHERNET
index d8cf120e33223cfd37b943fc2a035096b8ceeb5d..983fd275215138b375a1ad990d0e0eecbe402b30 100644 (file)
@@ -9,3 +9,4 @@ obj-$(CONFIG_NET_VENDOR_BROADCOM) += broadcom/
 obj-$(CONFIG_NET_VENDOR_CHELSIO) += chelsio/
 obj-$(CONFIG_NET_VENDOR_INTEL) += intel/
 obj-$(CONFIG_NET_VENDOR_QLOGIC) += qlogic/
+obj-$(CONFIG_NET_VENDOR_SMSC) += smsc/
diff --git a/drivers/net/ethernet/smsc/Kconfig b/drivers/net/ethernet/smsc/Kconfig
new file mode 100644 (file)
index 0000000..702efe6
--- /dev/null
@@ -0,0 +1,131 @@
+#
+# Western Digital/SMC network device configuration
+#
+
+config NET_VENDOR_SMSC
+       bool "SMC (SMSC)/Western Digital devices"
+       depends on ARM || ISA || MAC || ARM || MIPS || M32R || SUPERH || \
+               BLACKFIN || MN10300 || COLDFIRE || PCI || PCMCIA
+       ---help---
+         If you have a network (Ethernet) card belonging to this class, say Y
+         and read the Ethernet-HOWTO, available from
+         <http://www.tldp.org/docs.html#howto>.
+
+         Note that the answer to this question doesn't directly affect the
+         kernel: saying N will just cause the configurator to skip all
+         the questions about SMC/Western Digital cards. If you say Y, you will
+         be asked for your specific card in the following questions.
+
+if NET_VENDOR_SMSC
+
+config SMC9194
+       tristate "SMC 9194 support"
+       depends on (ISA || MAC && BROKEN)
+       select CRC32
+       ---help---
+         This is support for the SMC9xxx based Ethernet cards. Choose this
+         option if you have a DELL laptop with the docking station, or
+         another SMC9192/9194 based chipset.  Say Y if you want it compiled
+         into the kernel, and read the file
+         <file:Documentation/networking/smc9.txt> and the Ethernet-HOWTO,
+         available from <http://www.tldp.org/docs.html#howto>.
+
+         To compile this driver as a module, choose M here. The module
+         will be called smc9194.
+
+config SMC91X
+       tristate "SMC 91C9x/91C1xxx support"
+       select CRC32
+       select MII
+       depends on (ARM || M32R || SUPERH || MIPS || BLACKFIN || \
+                   MN10300 || COLDFIRE)
+       ---help---
+         This is a driver for SMC's 91x series of Ethernet chipsets,
+         including the SMC91C94 and the SMC91C111. Say Y if you want it
+         compiled into the kernel, and read the file
+         <file:Documentation/networking/smc9.txt>  and the Ethernet-HOWTO,
+         available from  <http://www.tldp.org/docs.html#howto>.
+
+         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 smc91x.  If you want to compile it as a
+         module, say M here and read <file:Documentation/kbuild/modules.txt>.
+
+config PCMCIA_SMC91C92
+       tristate "SMC 91Cxx PCMCIA support"
+       depends on PCMCIA
+       select CRC32
+       select MII
+       ---help---
+         Say Y here if you intend to attach an SMC 91Cxx compatible PCMCIA
+         (PC-card) Ethernet or Fast Ethernet card to your computer.
+
+         To compile this driver as a module, choose M here: the module will be
+         called smc91c92_cs.  If unsure, say N.
+
+config EPIC100
+       tristate "SMC EtherPower II"
+       depends on PCI
+       select CRC32
+       select MII
+       ---help---
+         This driver is for the SMC EtherPower II 9432 PCI Ethernet NIC,
+         which is based on the SMC83c17x (EPIC/100).
+         More specific information and updates are available from
+         <http://www.scyld.com/network/epic100.html>.
+
+config SMC911X
+       tristate "SMSC LAN911[5678] support"
+       select CRC32
+       select MII
+       depends on (ARM || SUPERH || MN10300)
+       ---help---
+         This is a driver for SMSC's LAN911x series of Ethernet chipsets
+         including the new LAN9115, LAN9116, LAN9117, and LAN9118.
+         Say Y if you want it compiled into the kernel,
+         and read the Ethernet-HOWTO, available from
+         <http://www.tldp.org/docs.html#howto>.
+
+         This driver is also available as a module. The module will be
+         called smc911x.  If you want to compile it as a module, say M
+         here and read <file:Documentation/kbuild/modules.txt>
+
+config SMSC911X
+       tristate "SMSC LAN911x/LAN921x families embedded ethernet support"
+       depends on (ARM || SUPERH || BLACKFIN || MIPS || MN10300)
+       select CRC32
+       select MII
+       select PHYLIB
+       ---help---
+         Say Y here if you want support for SMSC LAN911x and LAN921x families
+         of ethernet controllers.
+
+         To compile this driver as a module, choose M here and read
+         <file:Documentation/networking/net-modules.txt>. The module
+         will be called smsc911x.
+
+config SMSC911X_ARCH_HOOKS
+       def_bool n
+       depends on SMSC911X
+       ---help---
+         If the arch enables this, it allows the arch to implement various
+         hooks for more comprehensive interrupt control and also to override
+         the source of the MAC address.
+
+config SMSC9420
+       tristate "SMSC LAN9420 PCI ethernet adapter support"
+       depends on PCI
+       select CRC32
+       select PHYLIB
+       select SMSC_PHY
+       ---help---
+         This is a driver for SMSC's LAN9420 PCI ethernet adapter.
+         Say Y if you want it compiled into the kernel,
+         and read the Ethernet-HOWTO, available from
+         <http://www.tldp.org/docs.html#howto>.
+
+         This driver is also available as a module. The module will be
+         called smsc9420.  If you want to compile it as a module, say M
+         here and read <file:Documentation/kbuild/modules.txt>
+
+endif # NET_VENDOR_SMSC
diff --git a/drivers/net/ethernet/smsc/Makefile b/drivers/net/ethernet/smsc/Makefile
new file mode 100644 (file)
index 0000000..f3438de
--- /dev/null
@@ -0,0 +1,11 @@
+#
+# Makefile for the SMSC network device drivers.
+#
+
+obj-$(CONFIG_SMC9194) += smc9194.o
+obj-$(CONFIG_SMC91X) += smc91x.o
+obj-$(CONFIG_PCMCIA_SMC91C92) += smc91c92_cs.o
+obj-$(CONFIG_EPIC100) += epic100.o
+obj-$(CONFIG_SMSC9420) += smsc9420.o
+obj-$(CONFIG_SMC911X) += smc911x.o
+obj-$(CONFIG_SMSC911X) += smsc911x.o
diff --git a/drivers/net/ethernet/smsc/epic100.c b/drivers/net/ethernet/smsc/epic100.c
new file mode 100644 (file)
index 0000000..814c187
--- /dev/null
@@ -0,0 +1,1609 @@
+/* epic100.c: A SMC 83c170 EPIC/100 Fast Ethernet driver for Linux. */
+/*
+       Written/copyright 1997-2001 by Donald Becker.
+
+       This software may be used and distributed according to the terms of
+       the GNU General Public License (GPL), incorporated herein by reference.
+       Drivers based on or derived from this code fall under the GPL and must
+       retain the authorship, copyright and license notice.  This file is not
+       a complete program and may only be used when the entire operating
+       system is licensed under the GPL.
+
+       This driver is for the SMC83c170/175 "EPIC" series, as used on the
+       SMC EtherPower II 9432 PCI adapter, and several CardBus cards.
+
+       The author may be reached as becker@scyld.com, or C/O
+       Scyld Computing Corporation
+       410 Severn Ave., Suite 210
+       Annapolis MD 21403
+
+       Information and updates available at
+       http://www.scyld.com/network/epic100.html
+       [this link no longer provides anything useful -jgarzik]
+
+       ---------------------------------------------------------------------
+
+*/
+
+#define DRV_NAME        "epic100"
+#define DRV_VERSION     "2.1"
+#define DRV_RELDATE     "Sept 11, 2006"
+
+/* The user-configurable values.
+   These may be modified when a driver module is loaded.*/
+
+static int debug = 1;                  /* 1 normal messages, 0 quiet .. 7 verbose. */
+
+/* Used to pass the full-duplex flag, etc. */
+#define MAX_UNITS 8            /* More are supported, limit only on options */
+static int options[MAX_UNITS] = {-1, -1, -1, -1, -1, -1, -1, -1};
+static int full_duplex[MAX_UNITS] = {-1, -1, -1, -1, -1, -1, -1, -1};
+
+/* Set the copy breakpoint for the copy-only-tiny-frames scheme.
+   Setting to > 1518 effectively disables this feature. */
+static int rx_copybreak;
+
+/* Operational parameters that are set at compile time. */
+
+/* Keep the ring sizes a power of two for operational efficiency.
+   The compiler will convert <unsigned>'%'<2^N> into a bit mask.
+   Making the Tx ring too large decreases the effectiveness of channel
+   bonding and packet priority.
+   There are no ill effects from too-large receive rings. */
+#define TX_RING_SIZE   256
+#define TX_QUEUE_LEN   240             /* Limit ring entries actually used.  */
+#define RX_RING_SIZE   256
+#define TX_TOTAL_SIZE  TX_RING_SIZE*sizeof(struct epic_tx_desc)
+#define RX_TOTAL_SIZE  RX_RING_SIZE*sizeof(struct epic_rx_desc)
+
+/* Operational parameters that usually are not changed. */
+/* Time in jiffies before concluding the transmitter is hung. */
+#define TX_TIMEOUT  (2*HZ)
+
+#define PKT_BUF_SZ             1536                    /* Size of each temporary Rx buffer.*/
+
+/* Bytes transferred to chip before transmission starts. */
+/* Initial threshold, increased on underflow, rounded down to 4 byte units. */
+#define TX_FIFO_THRESH 256
+#define RX_FIFO_THRESH 1               /* 0-3, 0==32, 64,96, or 3==128 bytes  */
+
+#include <linux/module.h>
+#include <linux/kernel.h>
+#include <linux/string.h>
+#include <linux/timer.h>
+#include <linux/errno.h>
+#include <linux/ioport.h>
+#include <linux/interrupt.h>
+#include <linux/pci.h>
+#include <linux/delay.h>
+#include <linux/netdevice.h>
+#include <linux/etherdevice.h>
+#include <linux/skbuff.h>
+#include <linux/init.h>
+#include <linux/spinlock.h>
+#include <linux/ethtool.h>
+#include <linux/mii.h>
+#include <linux/crc32.h>
+#include <linux/bitops.h>
+#include <asm/io.h>
+#include <asm/uaccess.h>
+#include <asm/byteorder.h>
+
+/* These identify the driver base version and may not be removed. */
+static char version[] __devinitdata =
+DRV_NAME ".c:v1.11 1/7/2001 Written by Donald Becker <becker@scyld.com>\n";
+static char version2[] __devinitdata =
+"  (unofficial 2.4.x kernel port, version " DRV_VERSION ", " DRV_RELDATE ")\n";
+
+MODULE_AUTHOR("Donald Becker <becker@scyld.com>");
+MODULE_DESCRIPTION("SMC 83c170 EPIC series Ethernet driver");
+MODULE_LICENSE("GPL");
+
+module_param(debug, int, 0);
+module_param(rx_copybreak, int, 0);
+module_param_array(options, int, NULL, 0);
+module_param_array(full_duplex, int, NULL, 0);
+MODULE_PARM_DESC(debug, "EPIC/100 debug level (0-5)");
+MODULE_PARM_DESC(options, "EPIC/100: Bits 0-3: media type, bit 4: full duplex");
+MODULE_PARM_DESC(rx_copybreak, "EPIC/100 copy breakpoint for copy-only-tiny-frames");
+MODULE_PARM_DESC(full_duplex, "EPIC/100 full duplex setting(s) (1)");
+
+/*
+                               Theory of Operation
+
+I. Board Compatibility
+
+This device driver is designed for the SMC "EPIC/100", the SMC
+single-chip Ethernet controllers for PCI.  This chip is used on
+the SMC EtherPower II boards.
+
+II. Board-specific settings
+
+PCI bus devices are configured by the system at boot time, so no jumpers
+need to be set on the board.  The system BIOS will assign the
+PCI INTA signal to a (preferably otherwise unused) system IRQ line.
+Note: Kernel versions earlier than 1.3.73 do not support shared PCI
+interrupt lines.
+
+III. Driver operation
+
+IIIa. Ring buffers
+
+IVb. References
+
+http://www.smsc.com/media/Downloads_Public/discontinued/83c171.pdf
+http://www.smsc.com/media/Downloads_Public/discontinued/83c175.pdf
+http://scyld.com/expert/NWay.html
+http://www.national.com/pf/DP/DP83840A.html
+
+IVc. Errata
+
+*/
+
+
+enum chip_capability_flags { MII_PWRDWN=1, TYPE2_INTR=2, NO_MII=4 };
+
+#define EPIC_TOTAL_SIZE 0x100
+#define USE_IO_OPS 1
+
+typedef enum {
+       SMSC_83C170_0,
+       SMSC_83C170,
+       SMSC_83C175,
+} chip_t;
+
+
+struct epic_chip_info {
+       const char *name;
+        int drv_flags;                          /* Driver use, intended as capability flags. */
+};
+
+
+/* indexed by chip_t */
+static const struct epic_chip_info pci_id_tbl[] = {
+       { "SMSC EPIC/100 83c170",       TYPE2_INTR | NO_MII | MII_PWRDWN },
+       { "SMSC EPIC/100 83c170",       TYPE2_INTR },
+       { "SMSC EPIC/C 83c175",         TYPE2_INTR | MII_PWRDWN },
+};
+
+
+static DEFINE_PCI_DEVICE_TABLE(epic_pci_tbl) = {
+       { 0x10B8, 0x0005, 0x1092, 0x0AB4, 0, 0, SMSC_83C170_0 },
+       { 0x10B8, 0x0005, PCI_ANY_ID, PCI_ANY_ID, 0, 0, SMSC_83C170 },
+       { 0x10B8, 0x0006, PCI_ANY_ID, PCI_ANY_ID,
+         PCI_CLASS_NETWORK_ETHERNET << 8, 0xffff00, SMSC_83C175 },
+       { 0,}
+};
+MODULE_DEVICE_TABLE (pci, epic_pci_tbl);
+
+
+#ifndef USE_IO_OPS
+#undef inb
+#undef inw
+#undef inl
+#undef outb
+#undef outw
+#undef outl
+#define inb readb
+#define inw readw
+#define inl readl
+#define outb writeb
+#define outw writew
+#define outl writel
+#endif
+
+/* Offsets to registers, using the (ugh) SMC names. */
+enum epic_registers {
+  COMMAND=0, INTSTAT=4, INTMASK=8, GENCTL=0x0C, NVCTL=0x10, EECTL=0x14,
+  PCIBurstCnt=0x18,
+  TEST1=0x1C, CRCCNT=0x20, ALICNT=0x24, MPCNT=0x28,    /* Rx error counters. */
+  MIICtrl=0x30, MIIData=0x34, MIICfg=0x38,
+  LAN0=64,                                             /* MAC address. */
+  MC0=80,                                              /* Multicast filter table. */
+  RxCtrl=96, TxCtrl=112, TxSTAT=0x74,
+  PRxCDAR=0x84, RxSTAT=0xA4, EarlyRx=0xB0, PTxCDAR=0xC4, TxThresh=0xDC,
+};
+
+/* Interrupt register bits, using my own meaningful names. */
+enum IntrStatus {
+       TxIdle=0x40000, RxIdle=0x20000, IntrSummary=0x010000,
+       PCIBusErr170=0x7000, PCIBusErr175=0x1000, PhyEvent175=0x8000,
+       RxStarted=0x0800, RxEarlyWarn=0x0400, CntFull=0x0200, TxUnderrun=0x0100,
+       TxEmpty=0x0080, TxDone=0x0020, RxError=0x0010,
+       RxOverflow=0x0008, RxFull=0x0004, RxHeader=0x0002, RxDone=0x0001,
+};
+enum CommandBits {
+       StopRx=1, StartRx=2, TxQueued=4, RxQueued=8,
+       StopTxDMA=0x20, StopRxDMA=0x40, RestartTx=0x80,
+};
+
+#define EpicRemoved    0xffffffff      /* Chip failed or removed (CardBus) */
+
+#define EpicNapiEvent  (TxEmpty | TxDone | \
+                        RxDone | RxStarted | RxEarlyWarn | RxOverflow | RxFull)
+#define EpicNormalEvent        (0x0000ffff & ~EpicNapiEvent)
+
+static const u16 media2miictl[16] = {
+       0, 0x0C00, 0x0C00, 0x2000,  0x0100, 0x2100, 0, 0,
+       0, 0, 0, 0,  0, 0, 0, 0 };
+
+/*
+ * The EPIC100 Rx and Tx buffer descriptors.  Note that these
+ * really ARE host-endian; it's not a misannotation.  We tell
+ * the card to byteswap them internally on big-endian hosts -
+ * look for #ifdef __BIG_ENDIAN in epic_open().
+ */
+
+struct epic_tx_desc {
+       u32 txstatus;
+       u32 bufaddr;
+       u32 buflength;
+       u32 next;
+};
+
+struct epic_rx_desc {
+       u32 rxstatus;
+       u32 bufaddr;
+       u32 buflength;
+       u32 next;
+};
+
+enum desc_status_bits {
+       DescOwn=0x8000,
+};
+
+#define PRIV_ALIGN     15      /* Required alignment mask */
+struct epic_private {
+       struct epic_rx_desc *rx_ring;
+       struct epic_tx_desc *tx_ring;
+       /* The saved address of a sent-in-place packet/buffer, for skfree(). */
+       struct sk_buff* tx_skbuff[TX_RING_SIZE];
+       /* The addresses of receive-in-place skbuffs. */
+       struct sk_buff* rx_skbuff[RX_RING_SIZE];
+
+       dma_addr_t tx_ring_dma;
+       dma_addr_t rx_ring_dma;
+
+       /* Ring pointers. */
+       spinlock_t lock;                                /* Group with Tx control cache line. */
+       spinlock_t napi_lock;
+       struct napi_struct napi;
+       unsigned int reschedule_in_poll;
+       unsigned int cur_tx, dirty_tx;
+
+       unsigned int cur_rx, dirty_rx;
+       u32 irq_mask;
+       unsigned int rx_buf_sz;                         /* Based on MTU+slack. */
+
+       struct pci_dev *pci_dev;                        /* PCI bus location. */
+       int chip_id, chip_flags;
+
+       struct timer_list timer;                        /* Media selection timer. */
+       int tx_threshold;
+       unsigned char mc_filter[8];
+       signed char phys[4];                            /* MII device addresses. */
+       u16 advertising;                                        /* NWay media advertisement */
+       int mii_phy_cnt;
+       struct mii_if_info mii;
+       unsigned int tx_full:1;                         /* The Tx queue is full. */
+       unsigned int default_port:4;            /* Last dev->if_port value. */
+};
+
+static int epic_open(struct net_device *dev);
+static int read_eeprom(long ioaddr, int location);
+static int mdio_read(struct net_device *dev, int phy_id, int location);
+static void mdio_write(struct net_device *dev, int phy_id, int loc, int val);
+static void epic_restart(struct net_device *dev);
+static void epic_timer(unsigned long data);
+static void epic_tx_timeout(struct net_device *dev);
+static void epic_init_ring(struct net_device *dev);
+static netdev_tx_t epic_start_xmit(struct sk_buff *skb,
+                                  struct net_device *dev);
+static int epic_rx(struct net_device *dev, int budget);
+static int epic_poll(struct napi_struct *napi, int budget);
+static irqreturn_t epic_interrupt(int irq, void *dev_instance);
+static int netdev_ioctl(struct net_device *dev, struct ifreq *rq, int cmd);
+static const struct ethtool_ops netdev_ethtool_ops;
+static int epic_close(struct net_device *dev);
+static struct net_device_stats *epic_get_stats(struct net_device *dev);
+static void set_rx_mode(struct net_device *dev);
+
+static const struct net_device_ops epic_netdev_ops = {
+       .ndo_open               = epic_open,
+       .ndo_stop               = epic_close,
+       .ndo_start_xmit         = epic_start_xmit,
+       .ndo_tx_timeout         = epic_tx_timeout,
+       .ndo_get_stats          = epic_get_stats,
+       .ndo_set_multicast_list = set_rx_mode,
+       .ndo_do_ioctl           = netdev_ioctl,
+       .ndo_change_mtu         = eth_change_mtu,
+       .ndo_set_mac_address    = eth_mac_addr,
+       .ndo_validate_addr      = eth_validate_addr,
+};
+
+static int __devinit epic_init_one (struct pci_dev *pdev,
+                                   const struct pci_device_id *ent)
+{
+       static int card_idx = -1;
+       long ioaddr;
+       int chip_idx = (int) ent->driver_data;
+       int irq;
+       struct net_device *dev;
+       struct epic_private *ep;
+       int i, ret, option = 0, duplex = 0;
+       void *ring_space;
+       dma_addr_t ring_dma;
+
+/* when built into the kernel, we only print version if device is found */
+#ifndef MODULE
+       static int printed_version;
+       if (!printed_version++)
+               printk(KERN_INFO "%s%s", version, version2);
+#endif
+
+       card_idx++;
+
+       ret = pci_enable_device(pdev);
+       if (ret)
+               goto out;
+       irq = pdev->irq;
+
+       if (pci_resource_len(pdev, 0) < EPIC_TOTAL_SIZE) {
+               dev_err(&pdev->dev, "no PCI region space\n");
+               ret = -ENODEV;
+               goto err_out_disable;
+       }
+
+       pci_set_master(pdev);
+
+       ret = pci_request_regions(pdev, DRV_NAME);
+       if (ret < 0)
+               goto err_out_disable;
+
+       ret = -ENOMEM;
+
+       dev = alloc_etherdev(sizeof (*ep));
+       if (!dev) {
+               dev_err(&pdev->dev, "no memory for eth device\n");
+               goto err_out_free_res;
+       }
+       SET_NETDEV_DEV(dev, &pdev->dev);
+
+#ifdef USE_IO_OPS
+       ioaddr = pci_resource_start (pdev, 0);
+#else
+       ioaddr = pci_resource_start (pdev, 1);
+       ioaddr = (long) pci_ioremap_bar(pdev, 1);
+       if (!ioaddr) {
+               dev_err(&pdev->dev, "ioremap failed\n");
+               goto err_out_free_netdev;
+       }
+#endif
+
+       pci_set_drvdata(pdev, dev);
+       ep = netdev_priv(dev);
+       ep->mii.dev = dev;
+       ep->mii.mdio_read = mdio_read;
+       ep->mii.mdio_write = mdio_write;
+       ep->mii.phy_id_mask = 0x1f;
+       ep->mii.reg_num_mask = 0x1f;
+
+       ring_space = pci_alloc_consistent(pdev, TX_TOTAL_SIZE, &ring_dma);
+       if (!ring_space)
+               goto err_out_iounmap;
+       ep->tx_ring = ring_space;
+       ep->tx_ring_dma = ring_dma;
+
+       ring_space = pci_alloc_consistent(pdev, RX_TOTAL_SIZE, &ring_dma);
+       if (!ring_space)
+               goto err_out_unmap_tx;
+       ep->rx_ring = ring_space;
+       ep->rx_ring_dma = ring_dma;
+
+       if (dev->mem_start) {
+               option = dev->mem_start;
+               duplex = (dev->mem_start & 16) ? 1 : 0;
+       } else if (card_idx >= 0  &&  card_idx < MAX_UNITS) {
+               if (options[card_idx] >= 0)
+                       option = options[card_idx];
+               if (full_duplex[card_idx] >= 0)
+                       duplex = full_duplex[card_idx];
+       }
+
+       dev->base_addr = ioaddr;
+       dev->irq = irq;
+
+       spin_lock_init(&ep->lock);
+       spin_lock_init(&ep->napi_lock);
+       ep->reschedule_in_poll = 0;
+
+       /* Bring the chip out of low-power mode. */
+       outl(0x4200, ioaddr + GENCTL);
+       /* Magic?!  If we don't set this bit the MII interface won't work. */
+       /* This magic is documented in SMSC app note 7.15 */
+       for (i = 16; i > 0; i--)
+               outl(0x0008, ioaddr + TEST1);
+
+       /* Turn on the MII transceiver. */
+       outl(0x12, ioaddr + MIICfg);
+       if (chip_idx == 1)
+               outl((inl(ioaddr + NVCTL) & ~0x003C) | 0x4800, ioaddr + NVCTL);
+       outl(0x0200, ioaddr + GENCTL);
+
+       /* Note: the '175 does not have a serial EEPROM. */
+       for (i = 0; i < 3; i++)
+               ((__le16 *)dev->dev_addr)[i] = cpu_to_le16(inw(ioaddr + LAN0 + i*4));
+
+       if (debug > 2) {
+               dev_printk(KERN_DEBUG, &pdev->dev, "EEPROM contents:\n");
+               for (i = 0; i < 64; i++)
+                       printk(" %4.4x%s", read_eeprom(ioaddr, i),
+                                  i % 16 == 15 ? "\n" : "");
+       }
+
+       ep->pci_dev = pdev;
+       ep->chip_id = chip_idx;
+       ep->chip_flags = pci_id_tbl[chip_idx].drv_flags;
+       ep->irq_mask =
+               (ep->chip_flags & TYPE2_INTR ?  PCIBusErr175 : PCIBusErr170)
+                | CntFull | TxUnderrun | EpicNapiEvent;
+
+       /* Find the connected MII xcvrs.
+          Doing this in open() would allow detecting external xcvrs later, but
+          takes much time and no cards have external MII. */
+       {
+               int phy, phy_idx = 0;
+               for (phy = 1; phy < 32 && phy_idx < sizeof(ep->phys); phy++) {
+                       int mii_status = mdio_read(dev, phy, MII_BMSR);
+                       if (mii_status != 0xffff  &&  mii_status != 0x0000) {
+                               ep->phys[phy_idx++] = phy;
+                               dev_info(&pdev->dev,
+                                       "MII transceiver #%d control "
+                                       "%4.4x status %4.4x.\n",
+                                       phy, mdio_read(dev, phy, 0), mii_status);
+                       }
+               }
+               ep->mii_phy_cnt = phy_idx;
+               if (phy_idx != 0) {
+                       phy = ep->phys[0];
+                       ep->mii.advertising = mdio_read(dev, phy, MII_ADVERTISE);
+                       dev_info(&pdev->dev,
+                               "Autonegotiation advertising %4.4x link "
+                                  "partner %4.4x.\n",
+                                  ep->mii.advertising, mdio_read(dev, phy, 5));
+               } else if ( ! (ep->chip_flags & NO_MII)) {
+                       dev_warn(&pdev->dev,
+                               "***WARNING***: No MII transceiver found!\n");
+                       /* Use the known PHY address of the EPII. */
+                       ep->phys[0] = 3;
+               }
+               ep->mii.phy_id = ep->phys[0];
+       }
+
+       /* Turn off the MII xcvr (175 only!), leave the chip in low-power mode. */
+       if (ep->chip_flags & MII_PWRDWN)
+               outl(inl(ioaddr + NVCTL) & ~0x483C, ioaddr + NVCTL);
+       outl(0x0008, ioaddr + GENCTL);
+
+       /* The lower four bits are the media type. */
+       if (duplex) {
+               ep->mii.force_media = ep->mii.full_duplex = 1;
+               dev_info(&pdev->dev, "Forced full duplex requested.\n");
+       }
+       dev->if_port = ep->default_port = option;
+
+       /* The Epic-specific entries in the device structure. */
+       dev->netdev_ops = &epic_netdev_ops;
+       dev->ethtool_ops = &netdev_ethtool_ops;
+       dev->watchdog_timeo = TX_TIMEOUT;
+       netif_napi_add(dev, &ep->napi, epic_poll, 64);
+
+       ret = register_netdev(dev);
+       if (ret < 0)
+               goto err_out_unmap_rx;
+
+       printk(KERN_INFO "%s: %s at %#lx, IRQ %d, %pM\n",
+              dev->name, pci_id_tbl[chip_idx].name, ioaddr, dev->irq,
+              dev->dev_addr);
+
+out:
+       return ret;
+
+err_out_unmap_rx:
+       pci_free_consistent(pdev, RX_TOTAL_SIZE, ep->rx_ring, ep->rx_ring_dma);
+err_out_unmap_tx:
+       pci_free_consistent(pdev, TX_TOTAL_SIZE, ep->tx_ring, ep->tx_ring_dma);
+err_out_iounmap:
+#ifndef USE_IO_OPS
+       iounmap(ioaddr);
+err_out_free_netdev:
+#endif
+       free_netdev(dev);
+err_out_free_res:
+       pci_release_regions(pdev);
+err_out_disable:
+       pci_disable_device(pdev);
+       goto out;
+}
+
+/* Serial EEPROM section. */
+
+/*  EEPROM_Ctrl bits. */
+#define EE_SHIFT_CLK   0x04    /* EEPROM shift clock. */
+#define EE_CS                  0x02    /* EEPROM chip select. */
+#define EE_DATA_WRITE  0x08    /* EEPROM chip data in. */
+#define EE_WRITE_0             0x01
+#define EE_WRITE_1             0x09
+#define EE_DATA_READ   0x10    /* EEPROM chip data out. */
+#define EE_ENB                 (0x0001 | EE_CS)
+
+/* Delay between EEPROM clock transitions.
+   This serves to flush the operation to the PCI bus.
+ */
+
+#define eeprom_delay() inl(ee_addr)
+
+/* The EEPROM commands include the alway-set leading bit. */
+#define EE_WRITE_CMD   (5 << 6)
+#define EE_READ64_CMD  (6 << 6)
+#define EE_READ256_CMD (6 << 8)
+#define EE_ERASE_CMD   (7 << 6)
+
+static void epic_disable_int(struct net_device *dev, struct epic_private *ep)
+{
+       long ioaddr = dev->base_addr;
+
+       outl(0x00000000, ioaddr + INTMASK);
+}
+
+static inline void __epic_pci_commit(long ioaddr)
+{
+#ifndef USE_IO_OPS
+       inl(ioaddr + INTMASK);
+#endif
+}
+
+static inline void epic_napi_irq_off(struct net_device *dev,
+                                    struct epic_private *ep)
+{
+       long ioaddr = dev->base_addr;
+
+       outl(ep->irq_mask & ~EpicNapiEvent, ioaddr + INTMASK);
+       __epic_pci_commit(ioaddr);
+}
+
+static inline void epic_napi_irq_on(struct net_device *dev,
+                                   struct epic_private *ep)
+{
+       long ioaddr = dev->base_addr;
+
+       /* No need to commit possible posted write */
+       outl(ep->irq_mask | EpicNapiEvent, ioaddr + INTMASK);
+}
+
+static int __devinit read_eeprom(long ioaddr, int location)
+{
+       int i;
+       int retval = 0;
+       long ee_addr = ioaddr + EECTL;
+       int read_cmd = location |
+               (inl(ee_addr) & 0x40 ? EE_READ64_CMD : EE_READ256_CMD);
+
+       outl(EE_ENB & ~EE_CS, ee_addr);
+       outl(EE_ENB, ee_addr);
+
+       /* Shift the read command bits out. */
+       for (i = 12; i >= 0; i--) {
+               short dataval = (read_cmd & (1 << i)) ? EE_WRITE_1 : EE_WRITE_0;
+               outl(EE_ENB | dataval, ee_addr);
+               eeprom_delay();
+               outl(EE_ENB | dataval | EE_SHIFT_CLK, ee_addr);
+               eeprom_delay();
+       }
+       outl(EE_ENB, ee_addr);
+
+       for (i = 16; i > 0; i--) {
+               outl(EE_ENB | EE_SHIFT_CLK, ee_addr);
+               eeprom_delay();
+               retval = (retval << 1) | ((inl(ee_addr) & EE_DATA_READ) ? 1 : 0);
+               outl(EE_ENB, ee_addr);
+               eeprom_delay();
+       }
+
+       /* Terminate the EEPROM access. */
+       outl(EE_ENB & ~EE_CS, ee_addr);
+       return retval;
+}
+
+#define MII_READOP             1
+#define MII_WRITEOP            2
+static int mdio_read(struct net_device *dev, int phy_id, int location)
+{
+       long ioaddr = dev->base_addr;
+       int read_cmd = (phy_id << 9) | (location << 4) | MII_READOP;
+       int i;
+
+       outl(read_cmd, ioaddr + MIICtrl);
+       /* Typical operation takes 25 loops. */
+       for (i = 400; i > 0; i--) {
+               barrier();
+               if ((inl(ioaddr + MIICtrl) & MII_READOP) == 0) {
+                       /* Work around read failure bug. */
+                       if (phy_id == 1 && location < 6 &&
+                           inw(ioaddr + MIIData) == 0xffff) {
+                               outl(read_cmd, ioaddr + MIICtrl);
+                               continue;
+                       }
+                       return inw(ioaddr + MIIData);
+               }
+       }
+       return 0xffff;
+}
+
+static void mdio_write(struct net_device *dev, int phy_id, int loc, int value)
+{
+       long ioaddr = dev->base_addr;
+       int i;
+
+       outw(value, ioaddr + MIIData);
+       outl((phy_id << 9) | (loc << 4) | MII_WRITEOP, ioaddr + MIICtrl);
+       for (i = 10000; i > 0; i--) {
+               barrier();
+               if ((inl(ioaddr + MIICtrl) & MII_WRITEOP) == 0)
+                       break;
+       }
+}
+
+
+static int epic_open(struct net_device *dev)
+{
+       struct epic_private *ep = netdev_priv(dev);
+       long ioaddr = dev->base_addr;
+       int i;
+       int retval;
+
+       /* Soft reset the chip. */
+       outl(0x4001, ioaddr + GENCTL);
+
+       napi_enable(&ep->napi);
+       if ((retval = request_irq(dev->irq, epic_interrupt, IRQF_SHARED, dev->name, dev))) {
+               napi_disable(&ep->napi);
+               return retval;
+       }
+
+       epic_init_ring(dev);
+
+       outl(0x4000, ioaddr + GENCTL);
+       /* This magic is documented in SMSC app note 7.15 */
+       for (i = 16; i > 0; i--)
+               outl(0x0008, ioaddr + TEST1);
+
+       /* Pull the chip out of low-power mode, enable interrupts, and set for
+          PCI read multiple.  The MIIcfg setting and strange write order are
+          required by the details of which bits are reset and the transceiver
+          wiring on the Ositech CardBus card.
+       */
+#if 0
+       outl(dev->if_port == 1 ? 0x13 : 0x12, ioaddr + MIICfg);
+#endif
+       if (ep->chip_flags & MII_PWRDWN)
+               outl((inl(ioaddr + NVCTL) & ~0x003C) | 0x4800, ioaddr + NVCTL);
+
+       /* Tell the chip to byteswap descriptors on big-endian hosts */
+#ifdef __BIG_ENDIAN
+       outl(0x4432 | (RX_FIFO_THRESH<<8), ioaddr + GENCTL);
+       inl(ioaddr + GENCTL);
+       outl(0x0432 | (RX_FIFO_THRESH<<8), ioaddr + GENCTL);
+#else
+       outl(0x4412 | (RX_FIFO_THRESH<<8), ioaddr + GENCTL);
+       inl(ioaddr + GENCTL);
+       outl(0x0412 | (RX_FIFO_THRESH<<8), ioaddr + GENCTL);
+#endif
+
+       udelay(20); /* Looks like EPII needs that if you want reliable RX init. FIXME: pci posting bug? */
+
+       for (i = 0; i < 3; i++)
+               outl(le16_to_cpu(((__le16*)dev->dev_addr)[i]), ioaddr + LAN0 + i*4);
+
+       ep->tx_threshold = TX_FIFO_THRESH;
+       outl(ep->tx_threshold, ioaddr + TxThresh);
+
+       if (media2miictl[dev->if_port & 15]) {
+               if (ep->mii_phy_cnt)
+                       mdio_write(dev, ep->phys[0], MII_BMCR, media2miictl[dev->if_port&15]);
+               if (dev->if_port == 1) {
+                       if (debug > 1)
+                               printk(KERN_INFO "%s: Using the 10base2 transceiver, MII "
+                                          "status %4.4x.\n",
+                                          dev->name, mdio_read(dev, ep->phys[0], MII_BMSR));
+               }
+       } else {
+               int mii_lpa = mdio_read(dev, ep->phys[0], MII_LPA);
+               if (mii_lpa != 0xffff) {
+                       if ((mii_lpa & LPA_100FULL) || (mii_lpa & 0x01C0) == LPA_10FULL)
+                               ep->mii.full_duplex = 1;
+                       else if (! (mii_lpa & LPA_LPACK))
+                               mdio_write(dev, ep->phys[0], MII_BMCR, BMCR_ANENABLE|BMCR_ANRESTART);
+                       if (debug > 1)
+                               printk(KERN_INFO "%s: Setting %s-duplex based on MII xcvr %d"
+                                          " register read of %4.4x.\n", dev->name,
+                                          ep->mii.full_duplex ? "full" : "half",
+                                          ep->phys[0], mii_lpa);
+               }
+       }
+
+       outl(ep->mii.full_duplex ? 0x7F : 0x79, ioaddr + TxCtrl);
+       outl(ep->rx_ring_dma, ioaddr + PRxCDAR);
+       outl(ep->tx_ring_dma, ioaddr + PTxCDAR);
+
+       /* Start the chip's Rx process. */
+       set_rx_mode(dev);
+       outl(StartRx | RxQueued, ioaddr + COMMAND);
+
+       netif_start_queue(dev);
+
+       /* Enable interrupts by setting the interrupt mask. */
+       outl((ep->chip_flags & TYPE2_INTR ? PCIBusErr175 : PCIBusErr170)
+                | CntFull | TxUnderrun
+                | RxError | RxHeader | EpicNapiEvent, ioaddr + INTMASK);
+
+       if (debug > 1)
+               printk(KERN_DEBUG "%s: epic_open() ioaddr %lx IRQ %d status %4.4x "
+                          "%s-duplex.\n",
+                          dev->name, ioaddr, dev->irq, (int)inl(ioaddr + GENCTL),
+                          ep->mii.full_duplex ? "full" : "half");
+
+       /* Set the timer to switch to check for link beat and perhaps switch
+          to an alternate media type. */
+       init_timer(&ep->timer);
+       ep->timer.expires = jiffies + 3*HZ;
+       ep->timer.data = (unsigned long)dev;
+       ep->timer.function = epic_timer;                                /* timer handler */
+       add_timer(&ep->timer);
+
+       return 0;
+}
+
+/* Reset the chip to recover from a PCI transaction error.
+   This may occur at interrupt time. */
+static void epic_pause(struct net_device *dev)
+{
+       long ioaddr = dev->base_addr;
+
+       netif_stop_queue (dev);
+
+       /* Disable interrupts by clearing the interrupt mask. */
+       outl(0x00000000, ioaddr + INTMASK);
+       /* Stop the chip's Tx and Rx DMA processes. */
+       outw(StopRx | StopTxDMA | StopRxDMA, ioaddr + COMMAND);
+
+       /* Update the error counts. */
+       if (inw(ioaddr + COMMAND) != 0xffff) {
+               dev->stats.rx_missed_errors += inb(ioaddr + MPCNT);
+               dev->stats.rx_frame_errors += inb(ioaddr + ALICNT);
+               dev->stats.rx_crc_errors += inb(ioaddr + CRCCNT);
+       }
+
+       /* Remove the packets on the Rx queue. */
+       epic_rx(dev, RX_RING_SIZE);
+}
+
+static void epic_restart(struct net_device *dev)
+{
+       long ioaddr = dev->base_addr;
+       struct epic_private *ep = netdev_priv(dev);
+       int i;
+
+       /* Soft reset the chip. */
+       outl(0x4001, ioaddr + GENCTL);
+
+       printk(KERN_DEBUG "%s: Restarting the EPIC chip, Rx %d/%d Tx %d/%d.\n",
+                  dev->name, ep->cur_rx, ep->dirty_rx, ep->dirty_tx, ep->cur_tx);
+       udelay(1);
+
+       /* This magic is documented in SMSC app note 7.15 */
+       for (i = 16; i > 0; i--)
+               outl(0x0008, ioaddr + TEST1);
+
+#ifdef __BIG_ENDIAN
+       outl(0x0432 | (RX_FIFO_THRESH<<8), ioaddr + GENCTL);
+#else
+       outl(0x0412 | (RX_FIFO_THRESH<<8), ioaddr + GENCTL);
+#endif
+       outl(dev->if_port == 1 ? 0x13 : 0x12, ioaddr + MIICfg);
+       if (ep->chip_flags & MII_PWRDWN)
+               outl((inl(ioaddr + NVCTL) & ~0x003C) | 0x4800, ioaddr + NVCTL);
+
+       for (i = 0; i < 3; i++)
+               outl(le16_to_cpu(((__le16*)dev->dev_addr)[i]), ioaddr + LAN0 + i*4);
+
+       ep->tx_threshold = TX_FIFO_THRESH;
+       outl(ep->tx_threshold, ioaddr + TxThresh);
+       outl(ep->mii.full_duplex ? 0x7F : 0x79, ioaddr + TxCtrl);
+       outl(ep->rx_ring_dma + (ep->cur_rx%RX_RING_SIZE)*
+               sizeof(struct epic_rx_desc), ioaddr + PRxCDAR);
+       outl(ep->tx_ring_dma + (ep->dirty_tx%TX_RING_SIZE)*
+                sizeof(struct epic_tx_desc), ioaddr + PTxCDAR);
+
+       /* Start the chip's Rx process. */
+       set_rx_mode(dev);
+       outl(StartRx | RxQueued, ioaddr + COMMAND);
+
+       /* Enable interrupts by setting the interrupt mask. */
+       outl((ep->chip_flags & TYPE2_INTR ? PCIBusErr175 : PCIBusErr170)
+                | CntFull | TxUnderrun
+                | RxError | RxHeader | EpicNapiEvent, ioaddr + INTMASK);
+
+       printk(KERN_DEBUG "%s: epic_restart() done, cmd status %4.4x, ctl %4.4x"
+                  " interrupt %4.4x.\n",
+                  dev->name, (int)inl(ioaddr + COMMAND), (int)inl(ioaddr + GENCTL),
+                  (int)inl(ioaddr + INTSTAT));
+}
+
+static void check_media(struct net_device *dev)
+{
+       struct epic_private *ep = netdev_priv(dev);
+       long ioaddr = dev->base_addr;
+       int mii_lpa = ep->mii_phy_cnt ? mdio_read(dev, ep->phys[0], MII_LPA) : 0;
+       int negotiated = mii_lpa & ep->mii.advertising;
+       int duplex = (negotiated & 0x0100) || (negotiated & 0x01C0) == 0x0040;
+
+       if (ep->mii.force_media)
+               return;
+       if (mii_lpa == 0xffff)          /* Bogus read */
+               return;
+       if (ep->mii.full_duplex != duplex) {
+               ep->mii.full_duplex = duplex;
+               printk(KERN_INFO "%s: Setting %s-duplex based on MII #%d link"
+                          " partner capability of %4.4x.\n", dev->name,
+                          ep->mii.full_duplex ? "full" : "half", ep->phys[0], mii_lpa);
+               outl(ep->mii.full_duplex ? 0x7F : 0x79, ioaddr + TxCtrl);
+       }
+}
+
+static void epic_timer(unsigned long data)
+{
+       struct net_device *dev = (struct net_device *)data;
+       struct epic_private *ep = netdev_priv(dev);
+       long ioaddr = dev->base_addr;
+       int next_tick = 5*HZ;
+
+       if (debug > 3) {
+               printk(KERN_DEBUG "%s: Media monitor tick, Tx status %8.8x.\n",
+                          dev->name, (int)inl(ioaddr + TxSTAT));
+               printk(KERN_DEBUG "%s: Other registers are IntMask %4.4x "
+                          "IntStatus %4.4x RxStatus %4.4x.\n",
+                          dev->name, (int)inl(ioaddr + INTMASK),
+                          (int)inl(ioaddr + INTSTAT), (int)inl(ioaddr + RxSTAT));
+       }
+
+       check_media(dev);
+
+       ep->timer.expires = jiffies + next_tick;
+       add_timer(&ep->timer);
+}
+
+static void epic_tx_timeout(struct net_device *dev)
+{
+       struct epic_private *ep = netdev_priv(dev);
+       long ioaddr = dev->base_addr;
+
+       if (debug > 0) {
+               printk(KERN_WARNING "%s: Transmit timeout using MII device, "
+                          "Tx status %4.4x.\n",
+                          dev->name, (int)inw(ioaddr + TxSTAT));
+               if (debug > 1) {
+                       printk(KERN_DEBUG "%s: Tx indices: dirty_tx %d, cur_tx %d.\n",
+                                  dev->name, ep->dirty_tx, ep->cur_tx);
+               }
+       }
+       if (inw(ioaddr + TxSTAT) & 0x10) {              /* Tx FIFO underflow. */
+               dev->stats.tx_fifo_errors++;
+               outl(RestartTx, ioaddr + COMMAND);
+       } else {
+               epic_restart(dev);
+               outl(TxQueued, dev->base_addr + COMMAND);
+       }
+
+       dev->trans_start = jiffies; /* prevent tx timeout */
+       dev->stats.tx_errors++;
+       if (!ep->tx_full)
+               netif_wake_queue(dev);
+}
+
+/* Initialize the Rx and Tx rings, along with various 'dev' bits. */
+static void epic_init_ring(struct net_device *dev)
+{
+       struct epic_private *ep = netdev_priv(dev);
+       int i;
+
+       ep->tx_full = 0;
+       ep->dirty_tx = ep->cur_tx = 0;
+       ep->cur_rx = ep->dirty_rx = 0;
+       ep->rx_buf_sz = (dev->mtu <= 1500 ? PKT_BUF_SZ : dev->mtu + 32);
+
+       /* Initialize all Rx descriptors. */
+       for (i = 0; i < RX_RING_SIZE; i++) {
+               ep->rx_ring[i].rxstatus = 0;
+               ep->rx_ring[i].buflength = ep->rx_buf_sz;
+               ep->rx_ring[i].next = ep->rx_ring_dma +
+                                     (i+1)*sizeof(struct epic_rx_desc);
+               ep->rx_skbuff[i] = NULL;
+       }
+       /* Mark the last entry as wrapping the ring. */
+       ep->rx_ring[i-1].next = ep->rx_ring_dma;
+
+       /* Fill in the Rx buffers.  Handle allocation failure gracefully. */
+       for (i = 0; i < RX_RING_SIZE; i++) {
+               struct sk_buff *skb = dev_alloc_skb(ep->rx_buf_sz + 2);
+               ep->rx_skbuff[i] = skb;
+               if (skb == NULL)
+                       break;
+               skb_reserve(skb, 2);    /* 16 byte align the IP header. */
+               ep->rx_ring[i].bufaddr = pci_map_single(ep->pci_dev,
+                       skb->data, ep->rx_buf_sz, PCI_DMA_FROMDEVICE);
+               ep->rx_ring[i].rxstatus = DescOwn;
+       }
+       ep->dirty_rx = (unsigned int)(i - RX_RING_SIZE);
+
+       /* The Tx buffer descriptor is filled in as needed, but we
+          do need to clear the ownership bit. */
+       for (i = 0; i < TX_RING_SIZE; i++) {
+               ep->tx_skbuff[i] = NULL;
+               ep->tx_ring[i].txstatus = 0x0000;
+               ep->tx_ring[i].next = ep->tx_ring_dma +
+                       (i+1)*sizeof(struct epic_tx_desc);
+       }
+       ep->tx_ring[i-1].next = ep->tx_ring_dma;
+}
+
+static netdev_tx_t epic_start_xmit(struct sk_buff *skb, struct net_device *dev)
+{
+       struct epic_private *ep = netdev_priv(dev);
+       int entry, free_count;
+       u32 ctrl_word;
+       unsigned long flags;
+
+       if (skb_padto(skb, ETH_ZLEN))
+               return NETDEV_TX_OK;
+
+       /* Caution: the write order is important here, set the field with the
+          "ownership" bit last. */
+
+       /* Calculate the next Tx descriptor entry. */
+       spin_lock_irqsave(&ep->lock, flags);
+       free_count = ep->cur_tx - ep->dirty_tx;
+       entry = ep->cur_tx % TX_RING_SIZE;
+
+       ep->tx_skbuff[entry] = skb;
+       ep->tx_ring[entry].bufaddr = pci_map_single(ep->pci_dev, skb->data,
+                                                   skb->len, PCI_DMA_TODEVICE);
+       if (free_count < TX_QUEUE_LEN/2) {/* Typical path */
+               ctrl_word = 0x100000; /* No interrupt */
+       } else if (free_count == TX_QUEUE_LEN/2) {
+               ctrl_word = 0x140000; /* Tx-done intr. */
+       } else if (free_count < TX_QUEUE_LEN - 1) {
+               ctrl_word = 0x100000; /* No Tx-done intr. */
+       } else {
+               /* Leave room for an additional entry. */
+               ctrl_word = 0x140000; /* Tx-done intr. */
+               ep->tx_full = 1;
+       }
+       ep->tx_ring[entry].buflength = ctrl_word | skb->len;
+       ep->tx_ring[entry].txstatus =
+               ((skb->len >= ETH_ZLEN ? skb->len : ETH_ZLEN) << 16)
+                           | DescOwn;
+
+       ep->cur_tx++;
+       if (ep->tx_full)
+               netif_stop_queue(dev);
+
+       spin_unlock_irqrestore(&ep->lock, flags);
+       /* Trigger an immediate transmit demand. */
+       outl(TxQueued, dev->base_addr + COMMAND);
+
+       if (debug > 4)
+               printk(KERN_DEBUG "%s: Queued Tx packet size %d to slot %d, "
+                          "flag %2.2x Tx status %8.8x.\n",
+                          dev->name, (int)skb->len, entry, ctrl_word,
+                          (int)inl(dev->base_addr + TxSTAT));
+
+       return NETDEV_TX_OK;
+}
+
+static void epic_tx_error(struct net_device *dev, struct epic_private *ep,
+                         int status)
+{
+       struct net_device_stats *stats = &dev->stats;
+
+#ifndef final_version
+       /* There was an major error, log it. */
+       if (debug > 1)
+               printk(KERN_DEBUG "%s: Transmit error, Tx status %8.8x.\n",
+                      dev->name, status);
+#endif
+       stats->tx_errors++;
+       if (status & 0x1050)
+               stats->tx_aborted_errors++;
+       if (status & 0x0008)
+               stats->tx_carrier_errors++;
+       if (status & 0x0040)
+               stats->tx_window_errors++;
+       if (status & 0x0010)
+               stats->tx_fifo_errors++;
+}
+
+static void epic_tx(struct net_device *dev, struct epic_private *ep)
+{
+       unsigned int dirty_tx, cur_tx;
+
+       /*
+        * Note: if this lock becomes a problem we can narrow the locked
+        * region at the cost of occasionally grabbing the lock more times.
+        */
+       cur_tx = ep->cur_tx;
+       for (dirty_tx = ep->dirty_tx; cur_tx - dirty_tx > 0; dirty_tx++) {
+               struct sk_buff *skb;
+               int entry = dirty_tx % TX_RING_SIZE;
+               int txstatus = ep->tx_ring[entry].txstatus;
+
+               if (txstatus & DescOwn)
+                       break;  /* It still hasn't been Txed */
+
+               if (likely(txstatus & 0x0001)) {
+                       dev->stats.collisions += (txstatus >> 8) & 15;
+                       dev->stats.tx_packets++;
+                       dev->stats.tx_bytes += ep->tx_skbuff[entry]->len;
+               } else
+                       epic_tx_error(dev, ep, txstatus);
+
+               /* Free the original skb. */
+               skb = ep->tx_skbuff[entry];
+               pci_unmap_single(ep->pci_dev, ep->tx_ring[entry].bufaddr,
+                                skb->len, PCI_DMA_TODEVICE);
+               dev_kfree_skb_irq(skb);
+               ep->tx_skbuff[entry] = NULL;
+       }
+
+#ifndef final_version
+       if (cur_tx - dirty_tx > TX_RING_SIZE) {
+               printk(KERN_WARNING
+                      "%s: Out-of-sync dirty pointer, %d vs. %d, full=%d.\n",
+                      dev->name, dirty_tx, cur_tx, ep->tx_full);
+               dirty_tx += TX_RING_SIZE;
+       }
+#endif
+       ep->dirty_tx = dirty_tx;
+       if (ep->tx_full && cur_tx - dirty_tx < TX_QUEUE_LEN - 4) {
+               /* The ring is no longer full, allow new TX entries. */
+               ep->tx_full = 0;
+               netif_wake_queue(dev);
+       }
+}
+
+/* The interrupt handler does all of the Rx thread work and cleans up
+   after the Tx thread. */
+static irqreturn_t epic_interrupt(int irq, void *dev_instance)
+{
+       struct net_device *dev = dev_instance;
+       struct epic_private *ep = netdev_priv(dev);
+       long ioaddr = dev->base_addr;
+       unsigned int handled = 0;
+       int status;
+
+       status = inl(ioaddr + INTSTAT);
+       /* Acknowledge all of the current interrupt sources ASAP. */
+       outl(status & EpicNormalEvent, ioaddr + INTSTAT);
+
+       if (debug > 4) {
+               printk(KERN_DEBUG "%s: Interrupt, status=%#8.8x new "
+                                  "intstat=%#8.8x.\n", dev->name, status,
+                                  (int)inl(ioaddr + INTSTAT));
+       }
+
+       if ((status & IntrSummary) == 0)
+               goto out;
+
+       handled = 1;
+
+       if ((status & EpicNapiEvent) && !ep->reschedule_in_poll) {
+               spin_lock(&ep->napi_lock);
+               if (napi_schedule_prep(&ep->napi)) {
+                       epic_napi_irq_off(dev, ep);
+                       __napi_schedule(&ep->napi);
+               } else
+                       ep->reschedule_in_poll++;
+               spin_unlock(&ep->napi_lock);
+       }
+       status &= ~EpicNapiEvent;
+
+       /* Check uncommon events all at once. */
+       if (status & (CntFull | TxUnderrun | PCIBusErr170 | PCIBusErr175)) {
+               if (status == EpicRemoved)
+                       goto out;
+
+               /* Always update the error counts to avoid overhead later. */
+               dev->stats.rx_missed_errors += inb(ioaddr + MPCNT);
+               dev->stats.rx_frame_errors += inb(ioaddr + ALICNT);
+               dev->stats.rx_crc_errors += inb(ioaddr + CRCCNT);
+
+               if (status & TxUnderrun) { /* Tx FIFO underflow. */
+                       dev->stats.tx_fifo_errors++;
+                       outl(ep->tx_threshold += 128, ioaddr + TxThresh);
+                       /* Restart the transmit process. */
+                       outl(RestartTx, ioaddr + COMMAND);
+               }
+               if (status & PCIBusErr170) {
+                       printk(KERN_ERR "%s: PCI Bus Error! status %4.4x.\n",
+                                        dev->name, status);
+                       epic_pause(dev);
+                       epic_restart(dev);
+               }
+               /* Clear all error sources. */
+               outl(status & 0x7f18, ioaddr + INTSTAT);
+       }
+
+out:
+       if (debug > 3) {
+               printk(KERN_DEBUG "%s: exit interrupt, intr_status=%#4.4x.\n",
+                                  dev->name, status);
+       }
+
+       return IRQ_RETVAL(handled);
+}
+
+static int epic_rx(struct net_device *dev, int budget)
+{
+       struct epic_private *ep = netdev_priv(dev);
+       int entry = ep->cur_rx % RX_RING_SIZE;
+       int rx_work_limit = ep->dirty_rx + RX_RING_SIZE - ep->cur_rx;
+       int work_done = 0;
+
+       if (debug > 4)
+               printk(KERN_DEBUG " In epic_rx(), entry %d %8.8x.\n", entry,
+                          ep->rx_ring[entry].rxstatus);
+
+       if (rx_work_limit > budget)
+               rx_work_limit = budget;
+
+       /* If we own the next entry, it's a new packet. Send it up. */
+       while ((ep->rx_ring[entry].rxstatus & DescOwn) == 0) {
+               int status = ep->rx_ring[entry].rxstatus;
+
+               if (debug > 4)
+                       printk(KERN_DEBUG "  epic_rx() status was %8.8x.\n", status);
+               if (--rx_work_limit < 0)
+                       break;
+               if (status & 0x2006) {
+                       if (debug > 2)
+                               printk(KERN_DEBUG "%s: epic_rx() error status was %8.8x.\n",
+                                          dev->name, status);
+                       if (status & 0x2000) {
+                               printk(KERN_WARNING "%s: Oversized Ethernet frame spanned "
+                                          "multiple buffers, status %4.4x!\n", dev->name, status);
+                               dev->stats.rx_length_errors++;
+                       } else if (status & 0x0006)
+                               /* Rx Frame errors are counted in hardware. */
+                               dev->stats.rx_errors++;
+               } else {
+                       /* Malloc up new buffer, compatible with net-2e. */
+                       /* Omit the four octet CRC from the length. */
+                       short pkt_len = (status >> 16) - 4;
+                       struct sk_buff *skb;
+
+                       if (pkt_len > PKT_BUF_SZ - 4) {
+                               printk(KERN_ERR "%s: Oversized Ethernet frame, status %x "
+                                          "%d bytes.\n",
+                                          dev->name, status, pkt_len);
+                               pkt_len = 1514;
+                       }
+                       /* Check if the packet is long enough to accept without copying
+                          to a minimally-sized skbuff. */
+                       if (pkt_len < rx_copybreak &&
+                           (skb = dev_alloc_skb(pkt_len + 2)) != NULL) {
+                               skb_reserve(skb, 2);    /* 16 byte align the IP header */
+                               pci_dma_sync_single_for_cpu(ep->pci_dev,
+                                                           ep->rx_ring[entry].bufaddr,
+                                                           ep->rx_buf_sz,
+                                                           PCI_DMA_FROMDEVICE);
+                               skb_copy_to_linear_data(skb, ep->rx_skbuff[entry]->data, pkt_len);
+                               skb_put(skb, pkt_len);
+                               pci_dma_sync_single_for_device(ep->pci_dev,
+                                                              ep->rx_ring[entry].bufaddr,
+                                                              ep->rx_buf_sz,
+                                                              PCI_DMA_FROMDEVICE);
+                       } else {
+                               pci_unmap_single(ep->pci_dev,
+                                       ep->rx_ring[entry].bufaddr,
+                                       ep->rx_buf_sz, PCI_DMA_FROMDEVICE);
+                               skb_put(skb = ep->rx_skbuff[entry], pkt_len);
+                               ep->rx_skbuff[entry] = NULL;
+                       }
+                       skb->protocol = eth_type_trans(skb, dev);
+                       netif_receive_skb(skb);
+                       dev->stats.rx_packets++;
+                       dev->stats.rx_bytes += pkt_len;
+               }
+               work_done++;
+               entry = (++ep->cur_rx) % RX_RING_SIZE;
+       }
+
+       /* Refill the Rx ring buffers. */
+       for (; ep->cur_rx - ep->dirty_rx > 0; ep->dirty_rx++) {
+               entry = ep->dirty_rx % RX_RING_SIZE;
+               if (ep->rx_skbuff[entry] == NULL) {
+                       struct sk_buff *skb;
+                       skb = ep->rx_skbuff[entry] = dev_alloc_skb(ep->rx_buf_sz + 2);
+                       if (skb == NULL)
+                               break;
+                       skb_reserve(skb, 2);    /* Align IP on 16 byte boundaries */
+                       ep->rx_ring[entry].bufaddr = pci_map_single(ep->pci_dev,
+                               skb->data, ep->rx_buf_sz, PCI_DMA_FROMDEVICE);
+                       work_done++;
+               }
+               /* AV: shouldn't we add a barrier here? */
+               ep->rx_ring[entry].rxstatus = DescOwn;
+       }
+       return work_done;
+}
+
+static void epic_rx_err(struct net_device *dev, struct epic_private *ep)
+{
+       long ioaddr = dev->base_addr;
+       int status;
+
+       status = inl(ioaddr + INTSTAT);
+
+       if (status == EpicRemoved)
+               return;
+       if (status & RxOverflow)        /* Missed a Rx frame. */
+               dev->stats.rx_errors++;
+       if (status & (RxOverflow | RxFull))
+               outw(RxQueued, ioaddr + COMMAND);
+}
+
+static int epic_poll(struct napi_struct *napi, int budget)
+{
+       struct epic_private *ep = container_of(napi, struct epic_private, napi);
+       struct net_device *dev = ep->mii.dev;
+       int work_done = 0;
+       long ioaddr = dev->base_addr;
+
+rx_action:
+
+       epic_tx(dev, ep);
+
+       work_done += epic_rx(dev, budget);
+
+       epic_rx_err(dev, ep);
+
+       if (work_done < budget) {
+               unsigned long flags;
+               int more;
+
+               /* A bit baroque but it avoids a (space hungry) spin_unlock */
+
+               spin_lock_irqsave(&ep->napi_lock, flags);
+
+               more = ep->reschedule_in_poll;
+               if (!more) {
+                       __napi_complete(napi);
+                       outl(EpicNapiEvent, ioaddr + INTSTAT);
+                       epic_napi_irq_on(dev, ep);
+               } else
+                       ep->reschedule_in_poll--;
+
+               spin_unlock_irqrestore(&ep->napi_lock, flags);
+
+               if (more)
+                       goto rx_action;
+       }
+
+       return work_done;
+}
+
+static int epic_close(struct net_device *dev)
+{
+       long ioaddr = dev->base_addr;
+       struct epic_private *ep = netdev_priv(dev);
+       struct sk_buff *skb;
+       int i;
+
+       netif_stop_queue(dev);
+       napi_disable(&ep->napi);
+
+       if (debug > 1)
+               printk(KERN_DEBUG "%s: Shutting down ethercard, status was %2.2x.\n",
+                          dev->name, (int)inl(ioaddr + INTSTAT));
+
+       del_timer_sync(&ep->timer);
+
+       epic_disable_int(dev, ep);
+
+       free_irq(dev->irq, dev);
+
+       epic_pause(dev);
+
+       /* Free all the skbuffs in the Rx queue. */
+       for (i = 0; i < RX_RING_SIZE; i++) {
+               skb = ep->rx_skbuff[i];
+               ep->rx_skbuff[i] = NULL;
+               ep->rx_ring[i].rxstatus = 0;            /* Not owned by Epic chip. */
+               ep->rx_ring[i].buflength = 0;
+               if (skb) {
+                       pci_unmap_single(ep->pci_dev, ep->rx_ring[i].bufaddr,
+                                        ep->rx_buf_sz, PCI_DMA_FROMDEVICE);
+                       dev_kfree_skb(skb);
+               }
+               ep->rx_ring[i].bufaddr = 0xBADF00D0; /* An invalid address. */
+       }
+       for (i = 0; i < TX_RING_SIZE; i++) {
+               skb = ep->tx_skbuff[i];
+               ep->tx_skbuff[i] = NULL;
+               if (!skb)
+                       continue;
+               pci_unmap_single(ep->pci_dev, ep->tx_ring[i].bufaddr,
+                                skb->len, PCI_DMA_TODEVICE);
+               dev_kfree_skb(skb);
+       }
+
+       /* Green! Leave the chip in low-power mode. */
+       outl(0x0008, ioaddr + GENCTL);
+
+       return 0;
+}
+
+static struct net_device_stats *epic_get_stats(struct net_device *dev)
+{
+       long ioaddr = dev->base_addr;
+
+       if (netif_running(dev)) {
+               /* Update the error counts. */
+               dev->stats.rx_missed_errors += inb(ioaddr + MPCNT);
+               dev->stats.rx_frame_errors += inb(ioaddr + ALICNT);
+               dev->stats.rx_crc_errors += inb(ioaddr + CRCCNT);
+       }
+
+       return &dev->stats;
+}
+
+/* Set or clear the multicast filter for this adaptor.
+   Note that we only use exclusion around actually queueing the
+   new frame, not around filling ep->setup_frame.  This is non-deterministic
+   when re-entered but still correct. */
+
+static void set_rx_mode(struct net_device *dev)
+{
+       long ioaddr = dev->base_addr;
+       struct epic_private *ep = netdev_priv(dev);
+       unsigned char mc_filter[8];              /* Multicast hash filter */
+       int i;
+
+       if (dev->flags & IFF_PROMISC) {                 /* Set promiscuous. */
+               outl(0x002C, ioaddr + RxCtrl);
+               /* Unconditionally log net taps. */
+               memset(mc_filter, 0xff, sizeof(mc_filter));
+       } else if ((!netdev_mc_empty(dev)) || (dev->flags & IFF_ALLMULTI)) {
+               /* There is apparently a chip bug, so the multicast filter
+                  is never enabled. */
+               /* Too many to filter perfectly -- accept all multicasts. */
+               memset(mc_filter, 0xff, sizeof(mc_filter));
+               outl(0x000C, ioaddr + RxCtrl);
+       } else if (netdev_mc_empty(dev)) {
+               outl(0x0004, ioaddr + RxCtrl);
+               return;
+       } else {                                        /* Never executed, for now. */
+               struct netdev_hw_addr *ha;
+
+               memset(mc_filter, 0, sizeof(mc_filter));
+               netdev_for_each_mc_addr(ha, dev) {
+                       unsigned int bit_nr =
+                               ether_crc_le(ETH_ALEN, ha->addr) & 0x3f;
+                       mc_filter[bit_nr >> 3] |= (1 << bit_nr);
+               }
+       }
+       /* ToDo: perhaps we need to stop the Tx and Rx process here? */
+       if (memcmp(mc_filter, ep->mc_filter, sizeof(mc_filter))) {
+               for (i = 0; i < 4; i++)
+                       outw(((u16 *)mc_filter)[i], ioaddr + MC0 + i*4);
+               memcpy(ep->mc_filter, mc_filter, sizeof(mc_filter));
+       }
+}
+
+static void netdev_get_drvinfo (struct net_device *dev, struct ethtool_drvinfo *info)
+{
+       struct epic_private *np = netdev_priv(dev);
+
+       strcpy (info->driver, DRV_NAME);
+       strcpy (info->version, DRV_VERSION);
+       strcpy (info->bus_info, pci_name(np->pci_dev));
+}
+
+static int netdev_get_settings(struct net_device *dev, struct ethtool_cmd *cmd)
+{
+       struct epic_private *np = netdev_priv(dev);
+       int rc;
+
+       spin_lock_irq(&np->lock);
+       rc = mii_ethtool_gset(&np->mii, cmd);
+       spin_unlock_irq(&np->lock);
+
+       return rc;
+}
+
+static int netdev_set_settings(struct net_device *dev, struct ethtool_cmd *cmd)
+{
+       struct epic_private *np = netdev_priv(dev);
+       int rc;
+
+       spin_lock_irq(&np->lock);
+       rc = mii_ethtool_sset(&np->mii, cmd);
+       spin_unlock_irq(&np->lock);
+
+       return rc;
+}
+
+static int netdev_nway_reset(struct net_device *dev)
+{
+       struct epic_private *np = netdev_priv(dev);
+       return mii_nway_restart(&np->mii);
+}
+
+static u32 netdev_get_link(struct net_device *dev)
+{
+       struct epic_private *np = netdev_priv(dev);
+       return mii_link_ok(&np->mii);
+}
+
+static u32 netdev_get_msglevel(struct net_device *dev)
+{
+       return debug;
+}
+
+static void netdev_set_msglevel(struct net_device *dev, u32 value)
+{
+       debug = value;
+}
+
+static int ethtool_begin(struct net_device *dev)
+{
+       unsigned long ioaddr = dev->base_addr;
+       /* power-up, if interface is down */
+       if (! netif_running(dev)) {
+               outl(0x0200, ioaddr + GENCTL);
+               outl((inl(ioaddr + NVCTL) & ~0x003C) | 0x4800, ioaddr + NVCTL);
+       }
+       return 0;
+}
+
+static void ethtool_complete(struct net_device *dev)
+{
+       unsigned long ioaddr = dev->base_addr;
+       /* power-down, if interface is down */
+       if (! netif_running(dev)) {
+               outl(0x0008, ioaddr + GENCTL);
+               outl((inl(ioaddr + NVCTL) & ~0x483C) | 0x0000, ioaddr + NVCTL);
+       }
+}
+
+static const struct ethtool_ops netdev_ethtool_ops = {
+       .get_drvinfo            = netdev_get_drvinfo,
+       .get_settings           = netdev_get_settings,
+       .set_settings           = netdev_set_settings,
+       .nway_reset             = netdev_nway_reset,
+       .get_link               = netdev_get_link,
+       .get_msglevel           = netdev_get_msglevel,
+       .set_msglevel           = netdev_set_msglevel,
+       .begin                  = ethtool_begin,
+       .complete               = ethtool_complete
+};
+
+static int netdev_ioctl(struct net_device *dev, struct ifreq *rq, int cmd)
+{
+       struct epic_private *np = netdev_priv(dev);
+       long ioaddr = dev->base_addr;
+       struct mii_ioctl_data *data = if_mii(rq);
+       int rc;
+
+       /* power-up, if interface is down */
+       if (! netif_running(dev)) {
+               outl(0x0200, ioaddr + GENCTL);
+               outl((inl(ioaddr + NVCTL) & ~0x003C) | 0x4800, ioaddr + NVCTL);
+       }
+
+       /* all non-ethtool ioctls (the SIOC[GS]MIIxxx ioctls) */
+       spin_lock_irq(&np->lock);
+       rc = generic_mii_ioctl(&np->mii, data, cmd, NULL);
+       spin_unlock_irq(&np->lock);
+
+       /* power-down, if interface is down */
+       if (! netif_running(dev)) {
+               outl(0x0008, ioaddr + GENCTL);
+               outl((inl(ioaddr + NVCTL) & ~0x483C) | 0x0000, ioaddr + NVCTL);
+       }
+       return rc;
+}
+
+
+static void __devexit epic_remove_one (struct pci_dev *pdev)
+{
+       struct net_device *dev = pci_get_drvdata(pdev);
+       struct epic_private *ep = netdev_priv(dev);
+
+       pci_free_consistent(pdev, TX_TOTAL_SIZE, ep->tx_ring, ep->tx_ring_dma);
+       pci_free_consistent(pdev, RX_TOTAL_SIZE, ep->rx_ring, ep->rx_ring_dma);
+       unregister_netdev(dev);
+#ifndef USE_IO_OPS
+       iounmap((void*) dev->base_addr);
+#endif
+       pci_release_regions(pdev);
+       free_netdev(dev);
+       pci_disable_device(pdev);
+       pci_set_drvdata(pdev, NULL);
+       /* pci_power_off(pdev, -1); */
+}
+
+
+#ifdef CONFIG_PM
+
+static int epic_suspend (struct pci_dev *pdev, pm_message_t state)
+{
+       struct net_device *dev = pci_get_drvdata(pdev);
+       long ioaddr = dev->base_addr;
+
+       if (!netif_running(dev))
+               return 0;
+       epic_pause(dev);
+       /* Put the chip into low-power mode. */
+       outl(0x0008, ioaddr + GENCTL);
+       /* pci_power_off(pdev, -1); */
+       return 0;
+}
+
+
+static int epic_resume (struct pci_dev *pdev)
+{
+       struct net_device *dev = pci_get_drvdata(pdev);
+
+       if (!netif_running(dev))
+               return 0;
+       epic_restart(dev);
+       /* pci_power_on(pdev); */
+       return 0;
+}
+
+#endif /* CONFIG_PM */
+
+
+static struct pci_driver epic_driver = {
+       .name           = DRV_NAME,
+       .id_table       = epic_pci_tbl,
+       .probe          = epic_init_one,
+       .remove         = __devexit_p(epic_remove_one),
+#ifdef CONFIG_PM
+       .suspend        = epic_suspend,
+       .resume         = epic_resume,
+#endif /* CONFIG_PM */
+};
+
+
+static int __init epic_init (void)
+{
+/* when a module, this is printed whether or not devices are found in probe */
+#ifdef MODULE
+       printk (KERN_INFO "%s%s",
+               version, version2);
+#endif
+
+       return pci_register_driver(&epic_driver);
+}
+
+
+static void __exit epic_cleanup (void)
+{
+       pci_unregister_driver (&epic_driver);
+}
+
+
+module_init(epic_init);
+module_exit(epic_cleanup);
diff --git a/drivers/net/ethernet/smsc/smc911x.c b/drivers/net/ethernet/smsc/smc911x.c
new file mode 100644 (file)
index 0000000..a91fe17
--- /dev/null
@@ -0,0 +1,2210 @@
+/*
+ * smc911x.c
+ * This is a driver for SMSC's LAN911{5,6,7,8} single-chip Ethernet devices.
+ *
+ * Copyright (C) 2005 Sensoria Corp
+ *        Derived from the unified SMC91x driver by Nicolas Pitre
+ *        and the smsc911x.c reference driver by SMSC
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ *
+ * Arguments:
+ *      watchdog  = TX watchdog timeout
+ *      tx_fifo_kb = Size of TX FIFO in KB
+ *
+ * History:
+ *       04/16/05      Dustin McIntire          Initial version
+ */
+static const char version[] =
+        "smc911x.c: v1.0 04-16-2005 by Dustin McIntire <dustin@sensoria.com>\n";
+
+/* Debugging options */
+#define ENABLE_SMC_DEBUG_RX            0
+#define ENABLE_SMC_DEBUG_TX            0
+#define ENABLE_SMC_DEBUG_DMA           0
+#define ENABLE_SMC_DEBUG_PKTS          0
+#define ENABLE_SMC_DEBUG_MISC          0
+#define ENABLE_SMC_DEBUG_FUNC          0
+
+#define SMC_DEBUG_RX           ((ENABLE_SMC_DEBUG_RX   ? 1 : 0) << 0)
+#define SMC_DEBUG_TX           ((ENABLE_SMC_DEBUG_TX   ? 1 : 0) << 1)
+#define SMC_DEBUG_DMA          ((ENABLE_SMC_DEBUG_DMA  ? 1 : 0) << 2)
+#define SMC_DEBUG_PKTS         ((ENABLE_SMC_DEBUG_PKTS ? 1 : 0) << 3)
+#define SMC_DEBUG_MISC         ((ENABLE_SMC_DEBUG_MISC ? 1 : 0) << 4)
+#define SMC_DEBUG_FUNC         ((ENABLE_SMC_DEBUG_FUNC ? 1 : 0) << 5)
+
+#ifndef SMC_DEBUG
+#define SMC_DEBUG       ( SMC_DEBUG_RX   | \
+                          SMC_DEBUG_TX   | \
+                          SMC_DEBUG_DMA  | \
+                          SMC_DEBUG_PKTS | \
+                          SMC_DEBUG_MISC | \
+                          SMC_DEBUG_FUNC   \
+                        )
+#endif
+
+#include <linux/init.h>
+#include <linux/module.h>
+#include <linux/kernel.h>
+#include <linux/sched.h>
+#include <linux/delay.h>
+#include <linux/interrupt.h>
+#include <linux/errno.h>
+#include <linux/ioport.h>
+#include <linux/crc32.h>
+#include <linux/device.h>
+#include <linux/platform_device.h>
+#include <linux/spinlock.h>
+#include <linux/ethtool.h>
+#include <linux/mii.h>
+#include <linux/workqueue.h>
+
+#include <linux/netdevice.h>
+#include <linux/etherdevice.h>
+#include <linux/skbuff.h>
+
+#include <asm/io.h>
+
+#include "smc911x.h"
+
+/*
+ * Transmit timeout, default 5 seconds.
+ */
+static int watchdog = 5000;
+module_param(watchdog, int, 0400);
+MODULE_PARM_DESC(watchdog, "transmit timeout in milliseconds");
+
+static int tx_fifo_kb=8;
+module_param(tx_fifo_kb, int, 0400);
+MODULE_PARM_DESC(tx_fifo_kb,"transmit FIFO size in KB (1<x<15)(default=8)");
+
+MODULE_LICENSE("GPL");
+MODULE_ALIAS("platform:smc911x");
+
+/*
+ * The internal workings of the driver.  If you are changing anything
+ * here with the SMC stuff, you should have the datasheet and know
+ * what you are doing.
+ */
+#define CARDNAME "smc911x"
+
+/*
+ * Use power-down feature of the chip
+ */
+#define POWER_DOWN              1
+
+#if SMC_DEBUG > 0
+#define DBG(n, args...)                                 \
+       do {                                     \
+               if (SMC_DEBUG & (n))             \
+                       printk(args);            \
+       } while (0)
+
+#define PRINTK(args...)   printk(args)
+#else
+#define DBG(n, args...)   do { } while (0)
+#define PRINTK(args...)   printk(KERN_DEBUG args)
+#endif
+
+#if SMC_DEBUG_PKTS > 0
+static void PRINT_PKT(u_char *buf, int length)
+{
+       int i;
+       int remainder;
+       int lines;
+
+       lines = length / 16;
+       remainder = length % 16;
+
+       for (i = 0; i < lines ; i ++) {
+               int cur;
+               for (cur = 0; cur < 8; cur++) {
+                       u_char a, b;
+                       a = *buf++;
+                       b = *buf++;
+                       printk("%02x%02x ", a, b);
+               }
+               printk("\n");
+       }
+       for (i = 0; i < remainder/2 ; i++) {
+               u_char a, b;
+               a = *buf++;
+               b = *buf++;
+               printk("%02x%02x ", a, b);
+       }
+       printk("\n");
+}
+#else
+#define PRINT_PKT(x...)  do { } while (0)
+#endif
+
+
+/* this enables an interrupt in the interrupt mask register */
+#define SMC_ENABLE_INT(lp, x) do {                     \
+       unsigned int  __mask;                           \
+       __mask = SMC_GET_INT_EN((lp));                  \
+       __mask |= (x);                                  \
+       SMC_SET_INT_EN((lp), __mask);                   \
+} while (0)
+
+/* this disables an interrupt from the interrupt mask register */
+#define SMC_DISABLE_INT(lp, x) do {                    \
+       unsigned int  __mask;                           \
+       __mask = SMC_GET_INT_EN((lp));                  \
+       __mask &= ~(x);                                 \
+       SMC_SET_INT_EN((lp), __mask);                   \
+} while (0)
+
+/*
+ * this does a soft reset on the device
+ */
+static void smc911x_reset(struct net_device *dev)
+{
+       struct smc911x_local *lp = netdev_priv(dev);
+       unsigned int reg, timeout=0, resets=1, irq_cfg;
+       unsigned long flags;
+
+       DBG(SMC_DEBUG_FUNC, "%s: --> %s\n", dev->name, __func__);
+
+       /*       Take out of PM setting first */
+       if ((SMC_GET_PMT_CTRL(lp) & PMT_CTRL_READY_) == 0) {
+               /* Write to the bytetest will take out of powerdown */
+               SMC_SET_BYTE_TEST(lp, 0);
+               timeout=10;
+               do {
+                       udelay(10);
+                       reg = SMC_GET_PMT_CTRL(lp) & PMT_CTRL_READY_;
+               } while (--timeout && !reg);
+               if (timeout == 0) {
+                       PRINTK("%s: smc911x_reset timeout waiting for PM restore\n", dev->name);
+                       return;
+               }
+       }
+
+       /* Disable all interrupts */
+       spin_lock_irqsave(&lp->lock, flags);
+       SMC_SET_INT_EN(lp, 0);
+       spin_unlock_irqrestore(&lp->lock, flags);
+
+       while (resets--) {
+               SMC_SET_HW_CFG(lp, HW_CFG_SRST_);
+               timeout=10;
+               do {
+                       udelay(10);
+                       reg = SMC_GET_HW_CFG(lp);
+                       /* If chip indicates reset timeout then try again */
+                       if (reg & HW_CFG_SRST_TO_) {
+                               PRINTK("%s: chip reset timeout, retrying...\n", dev->name);
+                               resets++;
+                               break;
+                       }
+               } while (--timeout && (reg & HW_CFG_SRST_));
+       }
+       if (timeout == 0) {
+               PRINTK("%s: smc911x_reset timeout waiting for reset\n", dev->name);
+               return;
+       }
+
+       /* make sure EEPROM has finished loading before setting GPIO_CFG */
+       timeout=1000;
+       while (--timeout && (SMC_GET_E2P_CMD(lp) & E2P_CMD_EPC_BUSY_))
+               udelay(10);
+
+       if (timeout == 0){
+               PRINTK("%s: smc911x_reset timeout waiting for EEPROM busy\n", dev->name);
+               return;
+       }
+
+       /* Initialize interrupts */
+       SMC_SET_INT_EN(lp, 0);
+       SMC_ACK_INT(lp, -1);
+
+       /* Reset the FIFO level and flow control settings */
+       SMC_SET_HW_CFG(lp, (lp->tx_fifo_kb & 0xF) << 16);
+//TODO: Figure out what appropriate pause time is
+       SMC_SET_FLOW(lp, FLOW_FCPT_ | FLOW_FCEN_);
+       SMC_SET_AFC_CFG(lp, lp->afc_cfg);
+
+
+       /* Set to LED outputs */
+       SMC_SET_GPIO_CFG(lp, 0x70070000);
+
+       /*
+        * Deassert IRQ for 1*10us for edge type interrupts
+        * and drive IRQ pin push-pull
+        */
+       irq_cfg = (1 << 24) | INT_CFG_IRQ_EN_ | INT_CFG_IRQ_TYPE_;
+#ifdef SMC_DYNAMIC_BUS_CONFIG
+       if (lp->cfg.irq_polarity)
+               irq_cfg |= INT_CFG_IRQ_POL_;
+#endif
+       SMC_SET_IRQ_CFG(lp, irq_cfg);
+
+       /* clear anything saved */
+       if (lp->pending_tx_skb != NULL) {
+               dev_kfree_skb (lp->pending_tx_skb);
+               lp->pending_tx_skb = NULL;
+               dev->stats.tx_errors++;
+               dev->stats.tx_aborted_errors++;
+       }
+}
+
+/*
+ * Enable Interrupts, Receive, and Transmit
+ */
+static void smc911x_enable(struct net_device *dev)
+{
+       struct smc911x_local *lp = netdev_priv(dev);
+       unsigned mask, cfg, cr;
+       unsigned long flags;
+
+       DBG(SMC_DEBUG_FUNC, "%s: --> %s\n", dev->name, __func__);
+
+       spin_lock_irqsave(&lp->lock, flags);
+
+       SMC_SET_MAC_ADDR(lp, dev->dev_addr);
+
+       /* Enable TX */
+       cfg = SMC_GET_HW_CFG(lp);
+       cfg &= HW_CFG_TX_FIF_SZ_ | 0xFFF;
+       cfg |= HW_CFG_SF_;
+       SMC_SET_HW_CFG(lp, cfg);
+       SMC_SET_FIFO_TDA(lp, 0xFF);
+       /* Update TX stats on every 64 packets received or every 1 sec */
+       SMC_SET_FIFO_TSL(lp, 64);
+       SMC_SET_GPT_CFG(lp, GPT_CFG_TIMER_EN_ | 10000);
+
+       SMC_GET_MAC_CR(lp, cr);
+       cr |= MAC_CR_TXEN_ | MAC_CR_HBDIS_;
+       SMC_SET_MAC_CR(lp, cr);
+       SMC_SET_TX_CFG(lp, TX_CFG_TX_ON_);
+
+       /* Add 2 byte padding to start of packets */
+       SMC_SET_RX_CFG(lp, (2<<8) & RX_CFG_RXDOFF_);
+
+       /* Turn on receiver and enable RX */
+       if (cr & MAC_CR_RXEN_)
+               DBG(SMC_DEBUG_RX, "%s: Receiver already enabled\n", dev->name);
+
+       SMC_SET_MAC_CR(lp, cr | MAC_CR_RXEN_);
+
+       /* Interrupt on every received packet */
+       SMC_SET_FIFO_RSA(lp, 0x01);
+       SMC_SET_FIFO_RSL(lp, 0x00);
+
+       /* now, enable interrupts */
+       mask = INT_EN_TDFA_EN_ | INT_EN_TSFL_EN_ | INT_EN_RSFL_EN_ |
+               INT_EN_GPT_INT_EN_ | INT_EN_RXDFH_INT_EN_ | INT_EN_RXE_EN_ |
+               INT_EN_PHY_INT_EN_;
+       if (IS_REV_A(lp->revision))
+               mask|=INT_EN_RDFL_EN_;
+       else {
+               mask|=INT_EN_RDFO_EN_;
+       }
+       SMC_ENABLE_INT(lp, mask);
+
+       spin_unlock_irqrestore(&lp->lock, flags);
+}
+
+/*
+ * this puts the device in an inactive state
+ */
+static void smc911x_shutdown(struct net_device *dev)
+{
+       struct smc911x_local *lp = netdev_priv(dev);
+       unsigned cr;
+       unsigned long flags;
+
+       DBG(SMC_DEBUG_FUNC, "%s: --> %s\n", CARDNAME, __func__);
+
+       /* Disable IRQ's */
+       SMC_SET_INT_EN(lp, 0);
+
+       /* Turn of Rx and TX */
+       spin_lock_irqsave(&lp->lock, flags);
+       SMC_GET_MAC_CR(lp, cr);
+       cr &= ~(MAC_CR_TXEN_ | MAC_CR_RXEN_ | MAC_CR_HBDIS_);
+       SMC_SET_MAC_CR(lp, cr);
+       SMC_SET_TX_CFG(lp, TX_CFG_STOP_TX_);
+       spin_unlock_irqrestore(&lp->lock, flags);
+}
+
+static inline void smc911x_drop_pkt(struct net_device *dev)
+{
+       struct smc911x_local *lp = netdev_priv(dev);
+       unsigned int fifo_count, timeout, reg;
+
+       DBG(SMC_DEBUG_FUNC | SMC_DEBUG_RX, "%s: --> %s\n", CARDNAME, __func__);
+       fifo_count = SMC_GET_RX_FIFO_INF(lp) & 0xFFFF;
+       if (fifo_count <= 4) {
+               /* Manually dump the packet data */
+               while (fifo_count--)
+                       SMC_GET_RX_FIFO(lp);
+       } else   {
+               /* Fast forward through the bad packet */
+               SMC_SET_RX_DP_CTRL(lp, RX_DP_CTRL_FFWD_BUSY_);
+               timeout=50;
+               do {
+                       udelay(10);
+                       reg = SMC_GET_RX_DP_CTRL(lp) & RX_DP_CTRL_FFWD_BUSY_;
+               } while (--timeout && reg);
+               if (timeout == 0) {
+                       PRINTK("%s: timeout waiting for RX fast forward\n", dev->name);
+               }
+       }
+}
+
+/*
+ * This is the procedure to handle the receipt of a packet.
+ * It should be called after checking for packet presence in
+ * the RX status FIFO.  It must be called with the spin lock
+ * already held.
+ */
+static inline void      smc911x_rcv(struct net_device *dev)
+{
+       struct smc911x_local *lp = netdev_priv(dev);
+       unsigned int pkt_len, status;
+       struct sk_buff *skb;
+       unsigned char *data;
+
+       DBG(SMC_DEBUG_FUNC | SMC_DEBUG_RX, "%s: --> %s\n",
+               dev->name, __func__);
+       status = SMC_GET_RX_STS_FIFO(lp);
+       DBG(SMC_DEBUG_RX, "%s: Rx pkt len %d status 0x%08x\n",
+               dev->name, (status & 0x3fff0000) >> 16, status & 0xc000ffff);
+       pkt_len = (status & RX_STS_PKT_LEN_) >> 16;
+       if (status & RX_STS_ES_) {
+               /* Deal with a bad packet */
+               dev->stats.rx_errors++;
+               if (status & RX_STS_CRC_ERR_)
+                       dev->stats.rx_crc_errors++;
+               else {
+                       if (status & RX_STS_LEN_ERR_)
+                               dev->stats.rx_length_errors++;
+                       if (status & RX_STS_MCAST_)
+                               dev->stats.multicast++;
+               }
+               /* Remove the bad packet data from the RX FIFO */
+               smc911x_drop_pkt(dev);
+       } else {
+               /* Receive a valid packet */
+               /* Alloc a buffer with extra room for DMA alignment */
+               skb=dev_alloc_skb(pkt_len+32);
+               if (unlikely(skb == NULL)) {
+                       PRINTK( "%s: Low memory, rcvd packet dropped.\n",
+                               dev->name);
+                       dev->stats.rx_dropped++;
+                       smc911x_drop_pkt(dev);
+                       return;
+               }
+               /* Align IP header to 32 bits
+                * Note that the device is configured to add a 2
+                * byte padding to the packet start, so we really
+                * want to write to the orignal data pointer */
+               data = skb->data;
+               skb_reserve(skb, 2);
+               skb_put(skb,pkt_len-4);
+#ifdef SMC_USE_DMA
+               {
+               unsigned int fifo;
+               /* Lower the FIFO threshold if possible */
+               fifo = SMC_GET_FIFO_INT(lp);
+               if (fifo & 0xFF) fifo--;
+               DBG(SMC_DEBUG_RX, "%s: Setting RX stat FIFO threshold to %d\n",
+                       dev->name, fifo & 0xff);
+               SMC_SET_FIFO_INT(lp, fifo);
+               /* Setup RX DMA */
+               SMC_SET_RX_CFG(lp, RX_CFG_RX_END_ALGN16_ | ((2<<8) & RX_CFG_RXDOFF_));
+               lp->rxdma_active = 1;
+               lp->current_rx_skb = skb;
+               SMC_PULL_DATA(lp, data, (pkt_len+2+15) & ~15);
+               /* Packet processing deferred to DMA RX interrupt */
+               }
+#else
+               SMC_SET_RX_CFG(lp, RX_CFG_RX_END_ALGN4_ | ((2<<8) & RX_CFG_RXDOFF_));
+               SMC_PULL_DATA(lp, data, pkt_len+2+3);
+
+               DBG(SMC_DEBUG_PKTS, "%s: Received packet\n", dev->name);
+               PRINT_PKT(data, ((pkt_len - 4) <= 64) ? pkt_len - 4 : 64);
+               skb->protocol = eth_type_trans(skb, dev);
+               netif_rx(skb);
+               dev->stats.rx_packets++;
+               dev->stats.rx_bytes += pkt_len-4;
+#endif
+       }
+}
+
+/*
+ * This is called to actually send a packet to the chip.
+ */
+static void smc911x_hardware_send_pkt(struct net_device *dev)
+{
+       struct smc911x_local *lp = netdev_priv(dev);
+       struct sk_buff *skb;
+       unsigned int cmdA, cmdB, len;
+       unsigned char *buf;
+
+       DBG(SMC_DEBUG_FUNC | SMC_DEBUG_TX, "%s: --> %s\n", dev->name, __func__);
+       BUG_ON(lp->pending_tx_skb == NULL);
+
+       skb = lp->pending_tx_skb;
+       lp->pending_tx_skb = NULL;
+
+       /* cmdA {25:24] data alignment [20:16] start offset [10:0] buffer length */
+       /* cmdB {31:16] pkt tag [10:0] length */
+#ifdef SMC_USE_DMA
+       /* 16 byte buffer alignment mode */
+       buf = (char*)((u32)(skb->data) & ~0xF);
+       len = (skb->len + 0xF + ((u32)skb->data & 0xF)) & ~0xF;
+       cmdA = (1<<24) | (((u32)skb->data & 0xF)<<16) |
+                       TX_CMD_A_INT_FIRST_SEG_ | TX_CMD_A_INT_LAST_SEG_ |
+                       skb->len;
+#else
+       buf = (char*)((u32)skb->data & ~0x3);
+       len = (skb->len + 3 + ((u32)skb->data & 3)) & ~0x3;
+       cmdA = (((u32)skb->data & 0x3) << 16) |
+                       TX_CMD_A_INT_FIRST_SEG_ | TX_CMD_A_INT_LAST_SEG_ |
+                       skb->len;
+#endif
+       /* tag is packet length so we can use this in stats update later */
+       cmdB = (skb->len  << 16) | (skb->len & 0x7FF);
+
+       DBG(SMC_DEBUG_TX, "%s: TX PKT LENGTH 0x%04x (%d) BUF 0x%p CMDA 0x%08x CMDB 0x%08x\n",
+                dev->name, len, len, buf, cmdA, cmdB);
+       SMC_SET_TX_FIFO(lp, cmdA);
+       SMC_SET_TX_FIFO(lp, cmdB);
+
+       DBG(SMC_DEBUG_PKTS, "%s: Transmitted packet\n", dev->name);
+       PRINT_PKT(buf, len <= 64 ? len : 64);
+
+       /* Send pkt via PIO or DMA */
+#ifdef SMC_USE_DMA
+       lp->current_tx_skb = skb;
+       SMC_PUSH_DATA(lp, buf, len);
+       /* DMA complete IRQ will free buffer and set jiffies */
+#else
+       SMC_PUSH_DATA(lp, buf, len);
+       dev->trans_start = jiffies;
+       dev_kfree_skb_irq(skb);
+#endif
+       if (!lp->tx_throttle) {
+               netif_wake_queue(dev);
+       }
+       SMC_ENABLE_INT(lp, INT_EN_TDFA_EN_ | INT_EN_TSFL_EN_);
+}
+
+/*
+ * Since I am not sure if I will have enough room in the chip's ram
+ * to store the packet, I call this routine which either sends it
+ * now, or set the card to generates an interrupt when ready
+ * for the packet.
+ */
+static int smc911x_hard_start_xmit(struct sk_buff *skb, struct net_device *dev)
+{
+       struct smc911x_local *lp = netdev_priv(dev);
+       unsigned int free;
+       unsigned long flags;
+
+       DBG(SMC_DEBUG_FUNC | SMC_DEBUG_TX, "%s: --> %s\n",
+               dev->name, __func__);
+
+       spin_lock_irqsave(&lp->lock, flags);
+
+       BUG_ON(lp->pending_tx_skb != NULL);
+
+       free = SMC_GET_TX_FIFO_INF(lp) & TX_FIFO_INF_TDFREE_;
+       DBG(SMC_DEBUG_TX, "%s: TX free space %d\n", dev->name, free);
+
+       /* Turn off the flow when running out of space in FIFO */
+       if (free <= SMC911X_TX_FIFO_LOW_THRESHOLD) {
+               DBG(SMC_DEBUG_TX, "%s: Disabling data flow due to low FIFO space (%d)\n",
+                       dev->name, free);
+               /* Reenable when at least 1 packet of size MTU present */
+               SMC_SET_FIFO_TDA(lp, (SMC911X_TX_FIFO_LOW_THRESHOLD)/64);
+               lp->tx_throttle = 1;
+               netif_stop_queue(dev);
+       }
+
+       /* Drop packets when we run out of space in TX FIFO
+        * Account for overhead required for:
+        *
+        *        Tx command words                       8 bytes
+        *        Start offset                           15 bytes
+        *        End padding                            15 bytes
+        */
+       if (unlikely(free < (skb->len + 8 + 15 + 15))) {
+               printk("%s: No Tx free space %d < %d\n",
+                       dev->name, free, skb->len);
+               lp->pending_tx_skb = NULL;
+               dev->stats.tx_errors++;
+               dev->stats.tx_dropped++;
+               spin_unlock_irqrestore(&lp->lock, flags);
+               dev_kfree_skb(skb);
+               return NETDEV_TX_OK;
+       }
+
+#ifdef SMC_USE_DMA
+       {
+               /* If the DMA is already running then defer this packet Tx until
+                * the DMA IRQ starts it
+                */
+               if (lp->txdma_active) {
+                       DBG(SMC_DEBUG_TX | SMC_DEBUG_DMA, "%s: Tx DMA running, deferring packet\n", dev->name);
+                       lp->pending_tx_skb = skb;
+                       netif_stop_queue(dev);
+                       spin_unlock_irqrestore(&lp->lock, flags);
+                       return NETDEV_TX_OK;
+               } else {
+                       DBG(SMC_DEBUG_TX | SMC_DEBUG_DMA, "%s: Activating Tx DMA\n", dev->name);
+                       lp->txdma_active = 1;
+               }
+       }
+#endif
+       lp->pending_tx_skb = skb;
+       smc911x_hardware_send_pkt(dev);
+       spin_unlock_irqrestore(&lp->lock, flags);
+
+       return NETDEV_TX_OK;
+}
+
+/*
+ * This handles a TX status interrupt, which is only called when:
+ * - a TX error occurred, or
+ * - TX of a packet completed.
+ */
+static void smc911x_tx(struct net_device *dev)
+{
+       struct smc911x_local *lp = netdev_priv(dev);
+       unsigned int tx_status;
+
+       DBG(SMC_DEBUG_FUNC | SMC_DEBUG_TX, "%s: --> %s\n",
+               dev->name, __func__);
+
+       /* Collect the TX status */
+       while (((SMC_GET_TX_FIFO_INF(lp) & TX_FIFO_INF_TSUSED_) >> 16) != 0) {
+               DBG(SMC_DEBUG_TX, "%s: Tx stat FIFO used 0x%04x\n",
+                       dev->name,
+                       (SMC_GET_TX_FIFO_INF(lp) & TX_FIFO_INF_TSUSED_) >> 16);
+               tx_status = SMC_GET_TX_STS_FIFO(lp);
+               dev->stats.tx_packets++;
+               dev->stats.tx_bytes+=tx_status>>16;
+               DBG(SMC_DEBUG_TX, "%s: Tx FIFO tag 0x%04x status 0x%04x\n",
+                       dev->name, (tx_status & 0xffff0000) >> 16,
+                       tx_status & 0x0000ffff);
+               /* count Tx errors, but ignore lost carrier errors when in
+                * full-duplex mode */
+               if ((tx_status & TX_STS_ES_) && !(lp->ctl_rfduplx &&
+                   !(tx_status & 0x00000306))) {
+                       dev->stats.tx_errors++;
+               }
+               if (tx_status & TX_STS_MANY_COLL_) {
+                       dev->stats.collisions+=16;
+                       dev->stats.tx_aborted_errors++;
+               } else {
+                       dev->stats.collisions+=(tx_status & TX_STS_COLL_CNT_) >> 3;
+               }
+               /* carrier error only has meaning for half-duplex communication */
+               if ((tx_status & (TX_STS_LOC_ | TX_STS_NO_CARR_)) &&
+                   !lp->ctl_rfduplx) {
+                       dev->stats.tx_carrier_errors++;
+               }
+               if (tx_status & TX_STS_LATE_COLL_) {
+                       dev->stats.collisions++;
+                       dev->stats.tx_aborted_errors++;
+               }
+       }
+}
+
+
+/*---PHY CONTROL AND CONFIGURATION-----------------------------------------*/
+/*
+ * Reads a register from the MII Management serial interface
+ */
+
+static int smc911x_phy_read(struct net_device *dev, int phyaddr, int phyreg)
+{
+       struct smc911x_local *lp = netdev_priv(dev);
+       unsigned int phydata;
+
+       SMC_GET_MII(lp, phyreg, phyaddr, phydata);
+
+       DBG(SMC_DEBUG_MISC, "%s: phyaddr=0x%x, phyreg=0x%02x, phydata=0x%04x\n",
+               __func__, phyaddr, phyreg, phydata);
+       return phydata;
+}
+
+
+/*
+ * Writes a register to the MII Management serial interface
+ */
+static void smc911x_phy_write(struct net_device *dev, int phyaddr, int phyreg,
+                       int phydata)
+{
+       struct smc911x_local *lp = netdev_priv(dev);
+
+       DBG(SMC_DEBUG_MISC, "%s: phyaddr=0x%x, phyreg=0x%x, phydata=0x%x\n",
+               __func__, phyaddr, phyreg, phydata);
+
+       SMC_SET_MII(lp, phyreg, phyaddr, phydata);
+}
+
+/*
+ * Finds and reports the PHY address (115 and 117 have external
+ * PHY interface 118 has internal only
+ */
+static void smc911x_phy_detect(struct net_device *dev)
+{
+       struct smc911x_local *lp = netdev_priv(dev);
+       int phyaddr;
+       unsigned int cfg, id1, id2;
+
+       DBG(SMC_DEBUG_FUNC, "%s: --> %s\n", dev->name, __func__);
+
+       lp->phy_type = 0;
+
+       /*
+        * Scan all 32 PHY addresses if necessary, starting at
+        * PHY#1 to PHY#31, and then PHY#0 last.
+        */
+       switch(lp->version) {
+               case CHIP_9115:
+               case CHIP_9117:
+               case CHIP_9215:
+               case CHIP_9217:
+                       cfg = SMC_GET_HW_CFG(lp);
+                       if (cfg & HW_CFG_EXT_PHY_DET_) {
+                               cfg &= ~HW_CFG_PHY_CLK_SEL_;
+                               cfg |= HW_CFG_PHY_CLK_SEL_CLK_DIS_;
+                               SMC_SET_HW_CFG(lp, cfg);
+                               udelay(10); /* Wait for clocks to stop */
+
+                               cfg |= HW_CFG_EXT_PHY_EN_;
+                               SMC_SET_HW_CFG(lp, cfg);
+                               udelay(10); /* Wait for clocks to stop */
+
+                               cfg &= ~HW_CFG_PHY_CLK_SEL_;
+                               cfg |= HW_CFG_PHY_CLK_SEL_EXT_PHY_;
+                               SMC_SET_HW_CFG(lp, cfg);
+                               udelay(10); /* Wait for clocks to stop */
+
+                               cfg |= HW_CFG_SMI_SEL_;
+                               SMC_SET_HW_CFG(lp, cfg);
+
+                               for (phyaddr = 1; phyaddr < 32; ++phyaddr) {
+
+                                       /* Read the PHY identifiers */
+                                       SMC_GET_PHY_ID1(lp, phyaddr & 31, id1);
+                                       SMC_GET_PHY_ID2(lp, phyaddr & 31, id2);
+
+                                       /* Make sure it is a valid identifier */
+                                       if (id1 != 0x0000 && id1 != 0xffff &&
+                                           id1 != 0x8000 && id2 != 0x0000 &&
+                                           id2 != 0xffff && id2 != 0x8000) {
+                                               /* Save the PHY's address */
+                                               lp->mii.phy_id = phyaddr & 31;
+                                               lp->phy_type = id1 << 16 | id2;
+                                               break;
+                                       }
+                               }
+                               if (phyaddr < 32)
+                                       /* Found an external PHY */
+                                       break;
+                       }
+               default:
+                       /* Internal media only */
+                       SMC_GET_PHY_ID1(lp, 1, id1);
+                       SMC_GET_PHY_ID2(lp, 1, id2);
+                       /* Save the PHY's address */
+                       lp->mii.phy_id = 1;
+                       lp->phy_type = id1 << 16 | id2;
+       }
+
+       DBG(SMC_DEBUG_MISC, "%s: phy_id1=0x%x, phy_id2=0x%x phyaddr=0x%d\n",
+               dev->name, id1, id2, lp->mii.phy_id);
+}
+
+/*
+ * Sets the PHY to a configuration as determined by the user.
+ * Called with spin_lock held.
+ */
+static int smc911x_phy_fixed(struct net_device *dev)
+{
+       struct smc911x_local *lp = netdev_priv(dev);
+       int phyaddr = lp->mii.phy_id;
+       int bmcr;
+
+       DBG(SMC_DEBUG_FUNC, "%s: --> %s\n", dev->name, __func__);
+
+       /* Enter Link Disable state */
+       SMC_GET_PHY_BMCR(lp, phyaddr, bmcr);
+       bmcr |= BMCR_PDOWN;
+       SMC_SET_PHY_BMCR(lp, phyaddr, bmcr);
+
+       /*
+        * Set our fixed capabilities
+        * Disable auto-negotiation
+        */
+       bmcr &= ~BMCR_ANENABLE;
+       if (lp->ctl_rfduplx)
+               bmcr |= BMCR_FULLDPLX;
+
+       if (lp->ctl_rspeed == 100)
+               bmcr |= BMCR_SPEED100;
+
+       /* Write our capabilities to the phy control register */
+       SMC_SET_PHY_BMCR(lp, phyaddr, bmcr);
+
+       /* Re-Configure the Receive/Phy Control register */
+       bmcr &= ~BMCR_PDOWN;
+       SMC_SET_PHY_BMCR(lp, phyaddr, bmcr);
+
+       return 1;
+}
+
+/*
+ * smc911x_phy_reset - reset the phy
+ * @dev: net device
+ * @phy: phy address
+ *
+ * Issue a software reset for the specified PHY and
+ * wait up to 100ms for the reset to complete.  We should
+ * not access the PHY for 50ms after issuing the reset.
+ *
+ * The time to wait appears to be dependent on the PHY.
+ *
+ */
+static int smc911x_phy_reset(struct net_device *dev, int phy)
+{
+       struct smc911x_local *lp = netdev_priv(dev);
+       int timeout;
+       unsigned long flags;
+       unsigned int reg;
+
+       DBG(SMC_DEBUG_FUNC, "%s: --> %s()\n", dev->name, __func__);
+
+       spin_lock_irqsave(&lp->lock, flags);
+       reg = SMC_GET_PMT_CTRL(lp);
+       reg &= ~0xfffff030;
+       reg |= PMT_CTRL_PHY_RST_;
+       SMC_SET_PMT_CTRL(lp, reg);
+       spin_unlock_irqrestore(&lp->lock, flags);
+       for (timeout = 2; timeout; timeout--) {
+               msleep(50);
+               spin_lock_irqsave(&lp->lock, flags);
+               reg = SMC_GET_PMT_CTRL(lp);
+               spin_unlock_irqrestore(&lp->lock, flags);
+               if (!(reg & PMT_CTRL_PHY_RST_)) {
+                       /* extra delay required because the phy may
+                        * not be completed with its reset
+                        * when PHY_BCR_RESET_ is cleared. 256us
+                        * should suffice, but use 500us to be safe
+                        */
+                       udelay(500);
+               break;
+               }
+       }
+
+       return reg & PMT_CTRL_PHY_RST_;
+}
+
+/*
+ * smc911x_phy_powerdown - powerdown phy
+ * @dev: net device
+ * @phy: phy address
+ *
+ * Power down the specified PHY
+ */
+static void smc911x_phy_powerdown(struct net_device *dev, int phy)
+{
+       struct smc911x_local *lp = netdev_priv(dev);
+       unsigned int bmcr;
+
+       /* Enter Link Disable state */
+       SMC_GET_PHY_BMCR(lp, phy, bmcr);
+       bmcr |= BMCR_PDOWN;
+       SMC_SET_PHY_BMCR(lp, phy, bmcr);
+}
+
+/*
+ * smc911x_phy_check_media - check the media status and adjust BMCR
+ * @dev: net device
+ * @init: set true for initialisation
+ *
+ * Select duplex mode depending on negotiation state.  This
+ * also updates our carrier state.
+ */
+static void smc911x_phy_check_media(struct net_device *dev, int init)
+{
+       struct smc911x_local *lp = netdev_priv(dev);
+       int phyaddr = lp->mii.phy_id;
+       unsigned int bmcr, cr;
+
+       DBG(SMC_DEBUG_FUNC, "%s: --> %s\n", dev->name, __func__);
+
+       if (mii_check_media(&lp->mii, netif_msg_link(lp), init)) {
+               /* duplex state has changed */
+               SMC_GET_PHY_BMCR(lp, phyaddr, bmcr);
+               SMC_GET_MAC_CR(lp, cr);
+               if (lp->mii.full_duplex) {
+                       DBG(SMC_DEBUG_MISC, "%s: Configuring for full-duplex mode\n", dev->name);
+                       bmcr |= BMCR_FULLDPLX;
+                       cr |= MAC_CR_RCVOWN_;
+               } else {
+                       DBG(SMC_DEBUG_MISC, "%s: Configuring for half-duplex mode\n", dev->name);
+                       bmcr &= ~BMCR_FULLDPLX;
+                       cr &= ~MAC_CR_RCVOWN_;
+               }
+               SMC_SET_PHY_BMCR(lp, phyaddr, bmcr);
+               SMC_SET_MAC_CR(lp, cr);
+       }
+}
+
+/*
+ * Configures the specified PHY through the MII management interface
+ * using Autonegotiation.
+ * Calls smc911x_phy_fixed() if the user has requested a certain config.
+ * If RPC ANEG bit is set, the media selection is dependent purely on
+ * the selection by the MII (either in the MII BMCR reg or the result
+ * of autonegotiation.)  If the RPC ANEG bit is cleared, the selection
+ * is controlled by the RPC SPEED and RPC DPLX bits.
+ */
+static void smc911x_phy_configure(struct work_struct *work)
+{
+       struct smc911x_local *lp = container_of(work, struct smc911x_local,
+                                               phy_configure);
+       struct net_device *dev = lp->netdev;
+       int phyaddr = lp->mii.phy_id;
+       int my_phy_caps; /* My PHY capabilities */
+       int my_ad_caps; /* My Advertised capabilities */
+       int status;
+       unsigned long flags;
+
+       DBG(SMC_DEBUG_FUNC, "%s: --> %s()\n", dev->name, __func__);
+
+       /*
+        * We should not be called if phy_type is zero.
+        */
+       if (lp->phy_type == 0)
+               return;
+
+       if (smc911x_phy_reset(dev, phyaddr)) {
+               printk("%s: PHY reset timed out\n", dev->name);
+               return;
+       }
+       spin_lock_irqsave(&lp->lock, flags);
+
+       /*
+        * Enable PHY Interrupts (for register 18)
+        * Interrupts listed here are enabled
+        */
+       SMC_SET_PHY_INT_MASK(lp, phyaddr, PHY_INT_MASK_ENERGY_ON_ |
+                PHY_INT_MASK_ANEG_COMP_ | PHY_INT_MASK_REMOTE_FAULT_ |
+                PHY_INT_MASK_LINK_DOWN_);
+
+       /* If the user requested no auto neg, then go set his request */
+       if (lp->mii.force_media) {
+               smc911x_phy_fixed(dev);
+               goto smc911x_phy_configure_exit;
+       }
+
+       /* Copy our capabilities from MII_BMSR to MII_ADVERTISE */
+       SMC_GET_PHY_BMSR(lp, phyaddr, my_phy_caps);
+       if (!(my_phy_caps & BMSR_ANEGCAPABLE)) {
+               printk(KERN_INFO "Auto negotiation NOT supported\n");
+               smc911x_phy_fixed(dev);
+               goto smc911x_phy_configure_exit;
+       }
+
+       /* CSMA capable w/ both pauses */
+       my_ad_caps = ADVERTISE_CSMA | ADVERTISE_PAUSE_CAP | ADVERTISE_PAUSE_ASYM;
+
+       if (my_phy_caps & BMSR_100BASE4)
+               my_ad_caps |= ADVERTISE_100BASE4;
+       if (my_phy_caps & BMSR_100FULL)
+               my_ad_caps |= ADVERTISE_100FULL;
+       if (my_phy_caps & BMSR_100HALF)
+               my_ad_caps |= ADVERTISE_100HALF;
+       if (my_phy_caps & BMSR_10FULL)
+               my_ad_caps |= ADVERTISE_10FULL;
+       if (my_phy_caps & BMSR_10HALF)
+               my_ad_caps |= ADVERTISE_10HALF;
+
+       /* Disable capabilities not selected by our user */
+       if (lp->ctl_rspeed != 100)
+               my_ad_caps &= ~(ADVERTISE_100BASE4|ADVERTISE_100FULL|ADVERTISE_100HALF);
+
+        if (!lp->ctl_rfduplx)
+               my_ad_caps &= ~(ADVERTISE_100FULL|ADVERTISE_10FULL);
+
+       /* Update our Auto-Neg Advertisement Register */
+       SMC_SET_PHY_MII_ADV(lp, phyaddr, my_ad_caps);
+       lp->mii.advertising = my_ad_caps;
+
+       /*
+        * Read the register back.       Without this, it appears that when
+        * auto-negotiation is restarted, sometimes it isn't ready and
+        * the link does not come up.
+        */
+       udelay(10);
+       SMC_GET_PHY_MII_ADV(lp, phyaddr, status);
+
+       DBG(SMC_DEBUG_MISC, "%s: phy caps=0x%04x\n", dev->name, my_phy_caps);
+       DBG(SMC_DEBUG_MISC, "%s: phy advertised caps=0x%04x\n", dev->name, my_ad_caps);
+
+       /* Restart auto-negotiation process in order to advertise my caps */
+       SMC_SET_PHY_BMCR(lp, phyaddr, BMCR_ANENABLE | BMCR_ANRESTART);
+
+       smc911x_phy_check_media(dev, 1);
+
+smc911x_phy_configure_exit:
+       spin_unlock_irqrestore(&lp->lock, flags);
+}
+
+/*
+ * smc911x_phy_interrupt
+ *
+ * Purpose:  Handle interrupts relating to PHY register 18. This is
+ *      called from the "hard" interrupt handler under our private spinlock.
+ */
+static void smc911x_phy_interrupt(struct net_device *dev)
+{
+       struct smc911x_local *lp = netdev_priv(dev);
+       int phyaddr = lp->mii.phy_id;
+       int status;
+
+       DBG(SMC_DEBUG_FUNC, "%s: --> %s\n", dev->name, __func__);
+
+       if (lp->phy_type == 0)
+               return;
+
+       smc911x_phy_check_media(dev, 0);
+       /* read to clear status bits */
+       SMC_GET_PHY_INT_SRC(lp, phyaddr,status);
+       DBG(SMC_DEBUG_MISC, "%s: PHY interrupt status 0x%04x\n",
+               dev->name, status & 0xffff);
+       DBG(SMC_DEBUG_MISC, "%s: AFC_CFG 0x%08x\n",
+               dev->name, SMC_GET_AFC_CFG(lp));
+}
+
+/*--- END PHY CONTROL AND CONFIGURATION-------------------------------------*/
+
+/*
+ * This is the main routine of the driver, to handle the device when
+ * it needs some attention.
+ */
+static irqreturn_t smc911x_interrupt(int irq, void *dev_id)
+{
+       struct net_device *dev = dev_id;
+       struct smc911x_local *lp = netdev_priv(dev);
+       unsigned int status, mask, timeout;
+       unsigned int rx_overrun=0, cr, pkts;
+       unsigned long flags;
+
+       DBG(SMC_DEBUG_FUNC, "%s: --> %s\n", dev->name, __func__);
+
+       spin_lock_irqsave(&lp->lock, flags);
+
+       /* Spurious interrupt check */
+       if ((SMC_GET_IRQ_CFG(lp) & (INT_CFG_IRQ_INT_ | INT_CFG_IRQ_EN_)) !=
+               (INT_CFG_IRQ_INT_ | INT_CFG_IRQ_EN_)) {
+               spin_unlock_irqrestore(&lp->lock, flags);
+               return IRQ_NONE;
+       }
+
+       mask = SMC_GET_INT_EN(lp);
+       SMC_SET_INT_EN(lp, 0);
+
+       /* set a timeout value, so I don't stay here forever */
+       timeout = 8;
+
+
+       do {
+               status = SMC_GET_INT(lp);
+
+               DBG(SMC_DEBUG_MISC, "%s: INT 0x%08x MASK 0x%08x OUTSIDE MASK 0x%08x\n",
+                       dev->name, status, mask, status & ~mask);
+
+               status &= mask;
+               if (!status)
+                       break;
+
+               /* Handle SW interrupt condition */
+               if (status & INT_STS_SW_INT_) {
+                       SMC_ACK_INT(lp, INT_STS_SW_INT_);
+                       mask &= ~INT_EN_SW_INT_EN_;
+               }
+               /* Handle various error conditions */
+               if (status & INT_STS_RXE_) {
+                       SMC_ACK_INT(lp, INT_STS_RXE_);
+                       dev->stats.rx_errors++;
+               }
+               if (status & INT_STS_RXDFH_INT_) {
+                       SMC_ACK_INT(lp, INT_STS_RXDFH_INT_);
+                       dev->stats.rx_dropped+=SMC_GET_RX_DROP(lp);
+                }
+               /* Undocumented interrupt-what is the right thing to do here? */
+               if (status & INT_STS_RXDF_INT_) {
+                       SMC_ACK_INT(lp, INT_STS_RXDF_INT_);
+               }
+
+               /* Rx Data FIFO exceeds set level */
+               if (status & INT_STS_RDFL_) {
+                       if (IS_REV_A(lp->revision)) {
+                               rx_overrun=1;
+                               SMC_GET_MAC_CR(lp, cr);
+                               cr &= ~MAC_CR_RXEN_;
+                               SMC_SET_MAC_CR(lp, cr);
+                               DBG(SMC_DEBUG_RX, "%s: RX overrun\n", dev->name);
+                               dev->stats.rx_errors++;
+                               dev->stats.rx_fifo_errors++;
+                       }
+                       SMC_ACK_INT(lp, INT_STS_RDFL_);
+               }
+               if (status & INT_STS_RDFO_) {
+                       if (!IS_REV_A(lp->revision)) {
+                               SMC_GET_MAC_CR(lp, cr);
+                               cr &= ~MAC_CR_RXEN_;
+                               SMC_SET_MAC_CR(lp, cr);
+                               rx_overrun=1;
+                               DBG(SMC_DEBUG_RX, "%s: RX overrun\n", dev->name);
+                               dev->stats.rx_errors++;
+                               dev->stats.rx_fifo_errors++;
+                       }
+                       SMC_ACK_INT(lp, INT_STS_RDFO_);
+               }
+               /* Handle receive condition */
+               if ((status & INT_STS_RSFL_) || rx_overrun) {
+                       unsigned int fifo;
+                       DBG(SMC_DEBUG_RX, "%s: RX irq\n", dev->name);
+                       fifo = SMC_GET_RX_FIFO_INF(lp);
+                       pkts = (fifo & RX_FIFO_INF_RXSUSED_) >> 16;
+                       DBG(SMC_DEBUG_RX, "%s: Rx FIFO pkts %d, bytes %d\n",
+                               dev->name, pkts, fifo & 0xFFFF );
+                       if (pkts != 0) {
+#ifdef SMC_USE_DMA
+                               unsigned int fifo;
+                               if (lp->rxdma_active){
+                                       DBG(SMC_DEBUG_RX | SMC_DEBUG_DMA,
+                                               "%s: RX DMA active\n", dev->name);
+                                       /* The DMA is already running so up the IRQ threshold */
+                                       fifo = SMC_GET_FIFO_INT(lp) & ~0xFF;
+                                       fifo |= pkts & 0xFF;
+                                       DBG(SMC_DEBUG_RX,
+                                               "%s: Setting RX stat FIFO threshold to %d\n",
+                                               dev->name, fifo & 0xff);
+                                       SMC_SET_FIFO_INT(lp, fifo);
+                               } else
+#endif
+                               smc911x_rcv(dev);
+                       }
+                       SMC_ACK_INT(lp, INT_STS_RSFL_);
+               }
+               /* Handle transmit FIFO available */
+               if (status & INT_STS_TDFA_) {
+                       DBG(SMC_DEBUG_TX, "%s: TX data FIFO space available irq\n", dev->name);
+                       SMC_SET_FIFO_TDA(lp, 0xFF);
+                       lp->tx_throttle = 0;
+#ifdef SMC_USE_DMA
+                       if (!lp->txdma_active)
+#endif
+                               netif_wake_queue(dev);
+                       SMC_ACK_INT(lp, INT_STS_TDFA_);
+               }
+               /* Handle transmit done condition */
+#if 1
+               if (status & (INT_STS_TSFL_ | INT_STS_GPT_INT_)) {
+                       DBG(SMC_DEBUG_TX | SMC_DEBUG_MISC,
+                               "%s: Tx stat FIFO limit (%d) /GPT irq\n",
+                               dev->name, (SMC_GET_FIFO_INT(lp) & 0x00ff0000) >> 16);
+                       smc911x_tx(dev);
+                       SMC_SET_GPT_CFG(lp, GPT_CFG_TIMER_EN_ | 10000);
+                       SMC_ACK_INT(lp, INT_STS_TSFL_);
+                       SMC_ACK_INT(lp, INT_STS_TSFL_ | INT_STS_GPT_INT_);
+               }
+#else
+               if (status & INT_STS_TSFL_) {
+                       DBG(SMC_DEBUG_TX, "%s: TX status FIFO limit (%d) irq\n", dev->name, );
+                       smc911x_tx(dev);
+                       SMC_ACK_INT(lp, INT_STS_TSFL_);
+               }
+
+               if (status & INT_STS_GPT_INT_) {
+                       DBG(SMC_DEBUG_RX, "%s: IRQ_CFG 0x%08x FIFO_INT 0x%08x RX_CFG 0x%08x\n",
+                               dev->name,
+                               SMC_GET_IRQ_CFG(lp),
+                               SMC_GET_FIFO_INT(lp),
+                               SMC_GET_RX_CFG(lp));
+                       DBG(SMC_DEBUG_RX, "%s: Rx Stat FIFO Used 0x%02x "
+                               "Data FIFO Used 0x%04x Stat FIFO 0x%08x\n",
+                               dev->name,
+                               (SMC_GET_RX_FIFO_INF(lp) & 0x00ff0000) >> 16,
+                               SMC_GET_RX_FIFO_INF(lp) & 0xffff,
+                               SMC_GET_RX_STS_FIFO_PEEK(lp));
+                       SMC_SET_GPT_CFG(lp, GPT_CFG_TIMER_EN_ | 10000);
+                       SMC_ACK_INT(lp, INT_STS_GPT_INT_);
+               }
+#endif
+
+               /* Handle PHY interrupt condition */
+               if (status & INT_STS_PHY_INT_) {
+                       DBG(SMC_DEBUG_MISC, "%s: PHY irq\n", dev->name);
+                       smc911x_phy_interrupt(dev);
+                       SMC_ACK_INT(lp, INT_STS_PHY_INT_);
+               }
+       } while (--timeout);
+
+       /* restore mask state */
+       SMC_SET_INT_EN(lp, mask);
+
+       DBG(SMC_DEBUG_MISC, "%s: Interrupt done (%d loops)\n",
+               dev->name, 8-timeout);
+
+       spin_unlock_irqrestore(&lp->lock, flags);
+
+       return IRQ_HANDLED;
+}
+
+#ifdef SMC_USE_DMA
+static void
+smc911x_tx_dma_irq(int dma, void *data)
+{
+       struct net_device *dev = (struct net_device *)data;
+       struct smc911x_local *lp = netdev_priv(dev);
+       struct sk_buff *skb = lp->current_tx_skb;
+       unsigned long flags;
+
+       DBG(SMC_DEBUG_FUNC, "%s: --> %s\n", dev->name, __func__);
+
+       DBG(SMC_DEBUG_TX | SMC_DEBUG_DMA, "%s: TX DMA irq handler\n", dev->name);
+       /* Clear the DMA interrupt sources */
+       SMC_DMA_ACK_IRQ(dev, dma);
+       BUG_ON(skb == NULL);
+       dma_unmap_single(NULL, tx_dmabuf, tx_dmalen, DMA_TO_DEVICE);
+       dev->trans_start = jiffies;
+       dev_kfree_skb_irq(skb);
+       lp->current_tx_skb = NULL;
+       if (lp->pending_tx_skb != NULL)
+               smc911x_hardware_send_pkt(dev);
+       else {
+               DBG(SMC_DEBUG_TX | SMC_DEBUG_DMA,
+                       "%s: No pending Tx packets. DMA disabled\n", dev->name);
+               spin_lock_irqsave(&lp->lock, flags);
+               lp->txdma_active = 0;
+               if (!lp->tx_throttle) {
+                       netif_wake_queue(dev);
+               }
+               spin_unlock_irqrestore(&lp->lock, flags);
+       }
+
+       DBG(SMC_DEBUG_TX | SMC_DEBUG_DMA,
+               "%s: TX DMA irq completed\n", dev->name);
+}
+static void
+smc911x_rx_dma_irq(int dma, void *data)
+{
+       struct net_device *dev = (struct net_device *)data;
+       unsigned long ioaddr = dev->base_addr;
+       struct smc911x_local *lp = netdev_priv(dev);
+       struct sk_buff *skb = lp->current_rx_skb;
+       unsigned long flags;
+       unsigned int pkts;
+
+       DBG(SMC_DEBUG_FUNC, "%s: --> %s\n", dev->name, __func__);
+       DBG(SMC_DEBUG_RX | SMC_DEBUG_DMA, "%s: RX DMA irq handler\n", dev->name);
+       /* Clear the DMA interrupt sources */
+       SMC_DMA_ACK_IRQ(dev, dma);
+       dma_unmap_single(NULL, rx_dmabuf, rx_dmalen, DMA_FROM_DEVICE);
+       BUG_ON(skb == NULL);
+       lp->current_rx_skb = NULL;
+       PRINT_PKT(skb->data, skb->len);
+       skb->protocol = eth_type_trans(skb, dev);
+       dev->stats.rx_packets++;
+       dev->stats.rx_bytes += skb->len;
+       netif_rx(skb);
+
+       spin_lock_irqsave(&lp->lock, flags);
+       pkts = (SMC_GET_RX_FIFO_INF(lp) & RX_FIFO_INF_RXSUSED_) >> 16;
+       if (pkts != 0) {
+               smc911x_rcv(dev);
+       }else {
+               lp->rxdma_active = 0;
+       }
+       spin_unlock_irqrestore(&lp->lock, flags);
+       DBG(SMC_DEBUG_RX | SMC_DEBUG_DMA,
+               "%s: RX DMA irq completed. DMA RX FIFO PKTS %d\n",
+               dev->name, pkts);
+}
+#endif  /* SMC_USE_DMA */
+
+#ifdef CONFIG_NET_POLL_CONTROLLER
+/*
+ * Polling receive - used by netconsole and other diagnostic tools
+ * to allow network i/o with interrupts disabled.
+ */
+static void smc911x_poll_controller(struct net_device *dev)
+{
+       disable_irq(dev->irq);
+       smc911x_interrupt(dev->irq, dev);
+       enable_irq(dev->irq);
+}
+#endif
+
+/* Our watchdog timed out. Called by the networking layer */
+static void smc911x_timeout(struct net_device *dev)
+{
+       struct smc911x_local *lp = netdev_priv(dev);
+       int status, mask;
+       unsigned long flags;
+
+       DBG(SMC_DEBUG_FUNC, "%s: --> %s\n", dev->name, __func__);
+
+       spin_lock_irqsave(&lp->lock, flags);
+       status = SMC_GET_INT(lp);
+       mask = SMC_GET_INT_EN(lp);
+       spin_unlock_irqrestore(&lp->lock, flags);
+       DBG(SMC_DEBUG_MISC, "%s: INT 0x%02x MASK 0x%02x\n",
+               dev->name, status, mask);
+
+       /* Dump the current TX FIFO contents and restart */
+       mask = SMC_GET_TX_CFG(lp);
+       SMC_SET_TX_CFG(lp, mask | TX_CFG_TXS_DUMP_ | TX_CFG_TXD_DUMP_);
+       /*
+        * Reconfiguring the PHY doesn't seem like a bad idea here, but
+        * smc911x_phy_configure() calls msleep() which calls schedule_timeout()
+        * which calls schedule().       Hence we use a work queue.
+        */
+       if (lp->phy_type != 0)
+               schedule_work(&lp->phy_configure);
+
+       /* We can accept TX packets again */
+       dev->trans_start = jiffies; /* prevent tx timeout */
+       netif_wake_queue(dev);
+}
+
+/*
+ * This routine will, depending on the values passed to it,
+ * either make it accept multicast packets, go into
+ * promiscuous mode (for TCPDUMP and cousins) or accept
+ * a select set of multicast packets
+ */
+static void smc911x_set_multicast_list(struct net_device *dev)
+{
+       struct smc911x_local *lp = netdev_priv(dev);
+       unsigned int multicast_table[2];
+       unsigned int mcr, update_multicast = 0;
+       unsigned long flags;
+
+       DBG(SMC_DEBUG_FUNC, "%s: --> %s\n", dev->name, __func__);
+
+       spin_lock_irqsave(&lp->lock, flags);
+       SMC_GET_MAC_CR(lp, mcr);
+       spin_unlock_irqrestore(&lp->lock, flags);
+
+       if (dev->flags & IFF_PROMISC) {
+
+               DBG(SMC_DEBUG_MISC, "%s: RCR_PRMS\n", dev->name);
+               mcr |= MAC_CR_PRMS_;
+       }
+       /*
+        * Here, I am setting this to accept all multicast packets.
+        * I don't need to zero the multicast table, because the flag is
+        * checked before the table is
+        */
+       else if (dev->flags & IFF_ALLMULTI || netdev_mc_count(dev) > 16) {
+               DBG(SMC_DEBUG_MISC, "%s: RCR_ALMUL\n", dev->name);
+               mcr |= MAC_CR_MCPAS_;
+       }
+
+       /*
+        * This sets the internal hardware table to filter out unwanted
+        * multicast packets before they take up memory.
+        *
+        * The SMC chip uses a hash table where the high 6 bits of the CRC of
+        * address are the offset into the table.       If that bit is 1, then the
+        * multicast packet is accepted.  Otherwise, it's dropped silently.
+        *
+        * To use the 6 bits as an offset into the table, the high 1 bit is
+        * the number of the 32 bit register, while the low 5 bits are the bit
+        * within that register.
+        */
+       else if (!netdev_mc_empty(dev)) {
+               struct netdev_hw_addr *ha;
+
+               /* Set the Hash perfec mode */
+               mcr |= MAC_CR_HPFILT_;
+
+               /* start with a table of all zeros: reject all */
+               memset(multicast_table, 0, sizeof(multicast_table));
+
+               netdev_for_each_mc_addr(ha, dev) {
+                       u32 position;
+
+                       /* upper 6 bits are used as hash index */
+                       position = ether_crc(ETH_ALEN, ha->addr)>>26;
+
+                       multicast_table[position>>5] |= 1 << (position&0x1f);
+               }
+
+               /* be sure I get rid of flags I might have set */
+               mcr &= ~(MAC_CR_PRMS_ | MAC_CR_MCPAS_);
+
+               /* now, the table can be loaded into the chipset */
+               update_multicast = 1;
+       } else   {
+               DBG(SMC_DEBUG_MISC, "%s: ~(MAC_CR_PRMS_|MAC_CR_MCPAS_)\n",
+                       dev->name);
+               mcr &= ~(MAC_CR_PRMS_ | MAC_CR_MCPAS_);
+
+               /*
+                * since I'm disabling all multicast entirely, I need to
+                * clear the multicast list
+                */
+               memset(multicast_table, 0, sizeof(multicast_table));
+               update_multicast = 1;
+       }
+
+       spin_lock_irqsave(&lp->lock, flags);
+       SMC_SET_MAC_CR(lp, mcr);
+       if (update_multicast) {
+               DBG(SMC_DEBUG_MISC,
+                       "%s: update mcast hash table 0x%08x 0x%08x\n",
+                       dev->name, multicast_table[0], multicast_table[1]);
+               SMC_SET_HASHL(lp, multicast_table[0]);
+               SMC_SET_HASHH(lp, multicast_table[1]);
+       }
+       spin_unlock_irqrestore(&lp->lock, flags);
+}
+
+
+/*
+ * Open and Initialize the board
+ *
+ * Set up everything, reset the card, etc..
+ */
+static int
+smc911x_open(struct net_device *dev)
+{
+       struct smc911x_local *lp = netdev_priv(dev);
+
+       DBG(SMC_DEBUG_FUNC, "%s: --> %s\n", dev->name, __func__);
+
+       /*
+        * Check that the address is valid.  If its not, refuse
+        * to bring the device up.       The user must specify an
+        * address using ifconfig eth0 hw ether xx:xx:xx:xx:xx:xx
+        */
+       if (!is_valid_ether_addr(dev->dev_addr)) {
+               PRINTK("%s: no valid ethernet hw addr\n", __func__);
+               return -EINVAL;
+       }
+
+       /* reset the hardware */
+       smc911x_reset(dev);
+
+       /* Configure the PHY, initialize the link state */
+       smc911x_phy_configure(&lp->phy_configure);
+
+       /* Turn on Tx + Rx */
+       smc911x_enable(dev);
+
+       netif_start_queue(dev);
+
+       return 0;
+}
+
+/*
+ * smc911x_close
+ *
+ * this makes the board clean up everything that it can
+ * and not talk to the outside world.   Caused by
+ * an 'ifconfig ethX down'
+ */
+static int smc911x_close(struct net_device *dev)
+{
+       struct smc911x_local *lp = netdev_priv(dev);
+
+       DBG(SMC_DEBUG_FUNC, "%s: --> %s\n", dev->name, __func__);
+
+       netif_stop_queue(dev);
+       netif_carrier_off(dev);
+
+       /* clear everything */
+       smc911x_shutdown(dev);
+
+       if (lp->phy_type != 0) {
+               /* We need to ensure that no calls to
+                * smc911x_phy_configure are pending.
+                */
+               cancel_work_sync(&lp->phy_configure);
+               smc911x_phy_powerdown(dev, lp->mii.phy_id);
+       }
+
+       if (lp->pending_tx_skb) {
+               dev_kfree_skb(lp->pending_tx_skb);
+               lp->pending_tx_skb = NULL;
+       }
+
+       return 0;
+}
+
+/*
+ * Ethtool support
+ */
+static int
+smc911x_ethtool_getsettings(struct net_device *dev, struct ethtool_cmd *cmd)
+{
+       struct smc911x_local *lp = netdev_priv(dev);
+       int ret, status;
+       unsigned long flags;
+
+       DBG(SMC_DEBUG_FUNC, "%s: --> %s\n", dev->name, __func__);
+       cmd->maxtxpkt = 1;
+       cmd->maxrxpkt = 1;
+
+       if (lp->phy_type != 0) {
+               spin_lock_irqsave(&lp->lock, flags);
+               ret = mii_ethtool_gset(&lp->mii, cmd);
+               spin_unlock_irqrestore(&lp->lock, flags);
+       } else {
+               cmd->supported = SUPPORTED_10baseT_Half |
+                               SUPPORTED_10baseT_Full |
+                               SUPPORTED_TP | SUPPORTED_AUI;
+
+               if (lp->ctl_rspeed == 10)
+                       ethtool_cmd_speed_set(cmd, SPEED_10);
+               else if (lp->ctl_rspeed == 100)
+                       ethtool_cmd_speed_set(cmd, SPEED_100);
+
+               cmd->autoneg = AUTONEG_DISABLE;
+               if (lp->mii.phy_id==1)
+                       cmd->transceiver = XCVR_INTERNAL;
+               else
+                       cmd->transceiver = XCVR_EXTERNAL;
+               cmd->port = 0;
+               SMC_GET_PHY_SPECIAL(lp, lp->mii.phy_id, status);
+               cmd->duplex =
+                       (status & (PHY_SPECIAL_SPD_10FULL_ | PHY_SPECIAL_SPD_100FULL_)) ?
+                               DUPLEX_FULL : DUPLEX_HALF;
+               ret = 0;
+       }
+
+       return ret;
+}
+
+static int
+smc911x_ethtool_setsettings(struct net_device *dev, struct ethtool_cmd *cmd)
+{
+       struct smc911x_local *lp = netdev_priv(dev);
+       int ret;
+       unsigned long flags;
+
+       if (lp->phy_type != 0) {
+               spin_lock_irqsave(&lp->lock, flags);
+               ret = mii_ethtool_sset(&lp->mii, cmd);
+               spin_unlock_irqrestore(&lp->lock, flags);
+       } else {
+               if (cmd->autoneg != AUTONEG_DISABLE ||
+                       cmd->speed != SPEED_10 ||
+                       (cmd->duplex != DUPLEX_HALF && cmd->duplex != DUPLEX_FULL) ||
+                       (cmd->port != PORT_TP && cmd->port != PORT_AUI))
+                       return -EINVAL;
+
+               lp->ctl_rfduplx = cmd->duplex == DUPLEX_FULL;
+
+               ret = 0;
+       }
+
+       return ret;
+}
+
+static void
+smc911x_ethtool_getdrvinfo(struct net_device *dev, struct ethtool_drvinfo *info)
+{
+       strncpy(info->driver, CARDNAME, sizeof(info->driver));
+       strncpy(info->version, version, sizeof(info->version));
+       strncpy(info->bus_info, dev_name(dev->dev.parent), sizeof(info->bus_info));
+}
+
+static int smc911x_ethtool_nwayreset(struct net_device *dev)
+{
+       struct smc911x_local *lp = netdev_priv(dev);
+       int ret = -EINVAL;
+       unsigned long flags;
+
+       if (lp->phy_type != 0) {
+               spin_lock_irqsave(&lp->lock, flags);
+               ret = mii_nway_restart(&lp->mii);
+               spin_unlock_irqrestore(&lp->lock, flags);
+       }
+
+       return ret;
+}
+
+static u32 smc911x_ethtool_getmsglevel(struct net_device *dev)
+{
+       struct smc911x_local *lp = netdev_priv(dev);
+       return lp->msg_enable;
+}
+
+static void smc911x_ethtool_setmsglevel(struct net_device *dev, u32 level)
+{
+       struct smc911x_local *lp = netdev_priv(dev);
+       lp->msg_enable = level;
+}
+
+static int smc911x_ethtool_getregslen(struct net_device *dev)
+{
+       /* System regs + MAC regs + PHY regs */
+       return (((E2P_CMD - ID_REV)/4 + 1) +
+                       (WUCSR - MAC_CR)+1 + 32) * sizeof(u32);
+}
+
+static void smc911x_ethtool_getregs(struct net_device *dev,
+                                                                                struct ethtool_regs* regs, void *buf)
+{
+       struct smc911x_local *lp = netdev_priv(dev);
+       unsigned long flags;
+       u32 reg,i,j=0;
+       u32 *data = (u32*)buf;
+
+       regs->version = lp->version;
+       for(i=ID_REV;i<=E2P_CMD;i+=4) {
+               data[j++] = SMC_inl(lp, i);
+       }
+       for(i=MAC_CR;i<=WUCSR;i++) {
+               spin_lock_irqsave(&lp->lock, flags);
+               SMC_GET_MAC_CSR(lp, i, reg);
+               spin_unlock_irqrestore(&lp->lock, flags);
+               data[j++] = reg;
+       }
+       for(i=0;i<=31;i++) {
+               spin_lock_irqsave(&lp->lock, flags);
+               SMC_GET_MII(lp, i, lp->mii.phy_id, reg);
+               spin_unlock_irqrestore(&lp->lock, flags);
+               data[j++] = reg & 0xFFFF;
+       }
+}
+
+static int smc911x_ethtool_wait_eeprom_ready(struct net_device *dev)
+{
+       struct smc911x_local *lp = netdev_priv(dev);
+       unsigned int timeout;
+       int e2p_cmd;
+
+       e2p_cmd = SMC_GET_E2P_CMD(lp);
+       for(timeout=10;(e2p_cmd & E2P_CMD_EPC_BUSY_) && timeout; timeout--) {
+               if (e2p_cmd & E2P_CMD_EPC_TIMEOUT_) {
+                       PRINTK("%s: %s timeout waiting for EEPROM to respond\n",
+                               dev->name, __func__);
+                       return -EFAULT;
+               }
+               mdelay(1);
+               e2p_cmd = SMC_GET_E2P_CMD(lp);
+       }
+       if (timeout == 0) {
+               PRINTK("%s: %s timeout waiting for EEPROM CMD not busy\n",
+                       dev->name, __func__);
+               return -ETIMEDOUT;
+       }
+       return 0;
+}
+
+static inline int smc911x_ethtool_write_eeprom_cmd(struct net_device *dev,
+                                                                                                       int cmd, int addr)
+{
+       struct smc911x_local *lp = netdev_priv(dev);
+       int ret;
+
+       if ((ret = smc911x_ethtool_wait_eeprom_ready(dev))!=0)
+               return ret;
+       SMC_SET_E2P_CMD(lp, E2P_CMD_EPC_BUSY_ |
+               ((cmd) & (0x7<<28)) |
+               ((addr) & 0xFF));
+       return 0;
+}
+
+static inline int smc911x_ethtool_read_eeprom_byte(struct net_device *dev,
+                                                                                                       u8 *data)
+{
+       struct smc911x_local *lp = netdev_priv(dev);
+       int ret;
+
+       if ((ret = smc911x_ethtool_wait_eeprom_ready(dev))!=0)
+               return ret;
+       *data = SMC_GET_E2P_DATA(lp);
+       return 0;
+}
+
+static inline int smc911x_ethtool_write_eeprom_byte(struct net_device *dev,
+                                                                                                        u8 data)
+{
+       struct smc911x_local *lp = netdev_priv(dev);
+       int ret;
+
+       if ((ret = smc911x_ethtool_wait_eeprom_ready(dev))!=0)
+               return ret;
+       SMC_SET_E2P_DATA(lp, data);
+       return 0;
+}
+
+static int smc911x_ethtool_geteeprom(struct net_device *dev,
+                                                                         struct ethtool_eeprom *eeprom, u8 *data)
+{
+       u8 eebuf[SMC911X_EEPROM_LEN];
+       int i, ret;
+
+       for(i=0;i<SMC911X_EEPROM_LEN;i++) {
+               if ((ret=smc911x_ethtool_write_eeprom_cmd(dev, E2P_CMD_EPC_CMD_READ_, i ))!=0)
+                       return ret;
+               if ((ret=smc911x_ethtool_read_eeprom_byte(dev, &eebuf[i]))!=0)
+                       return ret;
+               }
+       memcpy(data, eebuf+eeprom->offset, eeprom->len);
+       return 0;
+}
+
+static int smc911x_ethtool_seteeprom(struct net_device *dev,
+                                                                          struct ethtool_eeprom *eeprom, u8 *data)
+{
+       int i, ret;
+
+       /* Enable erase */
+       if ((ret=smc911x_ethtool_write_eeprom_cmd(dev, E2P_CMD_EPC_CMD_EWEN_, 0 ))!=0)
+               return ret;
+       for(i=eeprom->offset;i<(eeprom->offset+eeprom->len);i++) {
+               /* erase byte */
+               if ((ret=smc911x_ethtool_write_eeprom_cmd(dev, E2P_CMD_EPC_CMD_ERASE_, i ))!=0)
+                       return ret;
+               /* write byte */
+               if ((ret=smc911x_ethtool_write_eeprom_byte(dev, *data))!=0)
+                        return ret;
+               if ((ret=smc911x_ethtool_write_eeprom_cmd(dev, E2P_CMD_EPC_CMD_WRITE_, i ))!=0)
+                       return ret;
+               }
+        return 0;
+}
+
+static int smc911x_ethtool_geteeprom_len(struct net_device *dev)
+{
+        return SMC911X_EEPROM_LEN;
+}
+
+static const struct ethtool_ops smc911x_ethtool_ops = {
+       .get_settings    = smc911x_ethtool_getsettings,
+       .set_settings    = smc911x_ethtool_setsettings,
+       .get_drvinfo     = smc911x_ethtool_getdrvinfo,
+       .get_msglevel    = smc911x_ethtool_getmsglevel,
+       .set_msglevel    = smc911x_ethtool_setmsglevel,
+       .nway_reset = smc911x_ethtool_nwayreset,
+       .get_link        = ethtool_op_get_link,
+       .get_regs_len    = smc911x_ethtool_getregslen,
+       .get_regs        = smc911x_ethtool_getregs,
+       .get_eeprom_len = smc911x_ethtool_geteeprom_len,
+       .get_eeprom = smc911x_ethtool_geteeprom,
+       .set_eeprom = smc911x_ethtool_seteeprom,
+};
+
+/*
+ * smc911x_findirq
+ *
+ * This routine has a simple purpose -- make the SMC chip generate an
+ * interrupt, so an auto-detect routine can detect it, and find the IRQ,
+ */
+static int __devinit smc911x_findirq(struct net_device *dev)
+{
+       struct smc911x_local *lp = netdev_priv(dev);
+       int timeout = 20;
+       unsigned long cookie;
+
+       DBG(SMC_DEBUG_FUNC, "--> %s\n", __func__);
+
+       cookie = probe_irq_on();
+
+       /*
+        * Force a SW interrupt
+        */
+
+       SMC_SET_INT_EN(lp, INT_EN_SW_INT_EN_);
+
+       /*
+        * Wait until positive that the interrupt has been generated
+        */
+       do {
+               int int_status;
+               udelay(10);
+               int_status = SMC_GET_INT_EN(lp);
+               if (int_status & INT_EN_SW_INT_EN_)
+                        break;         /* got the interrupt */
+       } while (--timeout);
+
+       /*
+        * there is really nothing that I can do here if timeout fails,
+        * as autoirq_report will return a 0 anyway, which is what I
+        * want in this case.    Plus, the clean up is needed in both
+        * cases.
+        */
+
+       /* and disable all interrupts again */
+       SMC_SET_INT_EN(lp, 0);
+
+       /* and return what I found */
+       return probe_irq_off(cookie);
+}
+
+static const struct net_device_ops smc911x_netdev_ops = {
+       .ndo_open               = smc911x_open,
+       .ndo_stop               = smc911x_close,
+       .ndo_start_xmit         = smc911x_hard_start_xmit,
+       .ndo_tx_timeout         = smc911x_timeout,
+       .ndo_set_multicast_list = smc911x_set_multicast_list,
+       .ndo_change_mtu         = eth_change_mtu,
+       .ndo_validate_addr      = eth_validate_addr,
+       .ndo_set_mac_address    = eth_mac_addr,
+#ifdef CONFIG_NET_POLL_CONTROLLER
+       .ndo_poll_controller    = smc911x_poll_controller,
+#endif
+};
+
+/*
+ * Function: smc911x_probe(unsigned long ioaddr)
+ *
+ * Purpose:
+ *      Tests to see if a given ioaddr points to an SMC911x chip.
+ *      Returns a 0 on success
+ *
+ * Algorithm:
+ *      (1) see if the endian word is OK
+ *      (1) see if I recognize the chip ID in the appropriate register
+ *
+ * Here I do typical initialization tasks.
+ *
+ * o  Initialize the structure if needed
+ * o  print out my vanity message if not done so already
+ * o  print out what type of hardware is detected
+ * o  print out the ethernet address
+ * o  find the IRQ
+ * o  set up my private data
+ * o  configure the dev structure with my subroutines
+ * o  actually GRAB the irq.
+ * o  GRAB the region
+ */
+static int __devinit smc911x_probe(struct net_device *dev)
+{
+       struct smc911x_local *lp = netdev_priv(dev);
+       int i, retval;
+       unsigned int val, chip_id, revision;
+       const char *version_string;
+       unsigned long irq_flags;
+
+       DBG(SMC_DEBUG_FUNC, "%s: --> %s\n", dev->name, __func__);
+
+       /* First, see if the endian word is recognized */
+       val = SMC_GET_BYTE_TEST(lp);
+       DBG(SMC_DEBUG_MISC, "%s: endian probe returned 0x%04x\n", CARDNAME, val);
+       if (val != 0x87654321) {
+               printk(KERN_ERR "Invalid chip endian 0x%08x\n",val);
+               retval = -ENODEV;
+               goto err_out;
+       }
+
+       /*
+        * check if the revision register is something that I
+        * recognize.   These might need to be added to later,
+        * as future revisions could be added.
+        */
+       chip_id = SMC_GET_PN(lp);
+       DBG(SMC_DEBUG_MISC, "%s: id probe returned 0x%04x\n", CARDNAME, chip_id);
+       for(i=0;chip_ids[i].id != 0; i++) {
+               if (chip_ids[i].id == chip_id) break;
+       }
+       if (!chip_ids[i].id) {
+               printk(KERN_ERR "Unknown chip ID %04x\n", chip_id);
+               retval = -ENODEV;
+               goto err_out;
+       }
+       version_string = chip_ids[i].name;
+
+       revision = SMC_GET_REV(lp);
+       DBG(SMC_DEBUG_MISC, "%s: revision = 0x%04x\n", CARDNAME, revision);
+
+       /* At this point I'll assume that the chip is an SMC911x. */
+       DBG(SMC_DEBUG_MISC, "%s: Found a %s\n", CARDNAME, chip_ids[i].name);
+
+       /* Validate the TX FIFO size requested */
+       if ((tx_fifo_kb < 2) || (tx_fifo_kb > 14)) {
+               printk(KERN_ERR "Invalid TX FIFO size requested %d\n", tx_fifo_kb);
+               retval = -EINVAL;
+               goto err_out;
+       }
+
+       /* fill in some of the fields */
+       lp->version = chip_ids[i].id;
+       lp->revision = revision;
+       lp->tx_fifo_kb = tx_fifo_kb;
+       /* Reverse calculate the RX FIFO size from the TX */
+       lp->tx_fifo_size=(lp->tx_fifo_kb<<10) - 512;
+       lp->rx_fifo_size= ((0x4000 - 512 - lp->tx_fifo_size) / 16) * 15;
+
+       /* Set the automatic flow control values */
+       switch(lp->tx_fifo_kb) {
+               /*
+                *       AFC_HI is about ((Rx Data Fifo Size)*2/3)/64
+                *       AFC_LO is AFC_HI/2
+                *       BACK_DUR is about 5uS*(AFC_LO) rounded down
+                */
+               case 2:/* 13440 Rx Data Fifo Size */
+                       lp->afc_cfg=0x008C46AF;break;
+               case 3:/* 12480 Rx Data Fifo Size */
+                       lp->afc_cfg=0x0082419F;break;
+               case 4:/* 11520 Rx Data Fifo Size */
+                       lp->afc_cfg=0x00783C9F;break;
+               case 5:/* 10560 Rx Data Fifo Size */
+                       lp->afc_cfg=0x006E374F;break;
+               case 6:/* 9600 Rx Data Fifo Size */
+                       lp->afc_cfg=0x0064328F;break;
+               case 7:/* 8640 Rx Data Fifo Size */
+                       lp->afc_cfg=0x005A2D7F;break;
+               case 8:/* 7680 Rx Data Fifo Size */
+                       lp->afc_cfg=0x0050287F;break;
+               case 9:/* 6720 Rx Data Fifo Size */
+                       lp->afc_cfg=0x0046236F;break;
+               case 10:/* 5760 Rx Data Fifo Size */
+                       lp->afc_cfg=0x003C1E6F;break;
+               case 11:/* 4800 Rx Data Fifo Size */
+                       lp->afc_cfg=0x0032195F;break;
+               /*
+                *       AFC_HI is ~1520 bytes less than RX Data Fifo Size
+                *       AFC_LO is AFC_HI/2
+                *       BACK_DUR is about 5uS*(AFC_LO) rounded down
+                */
+               case 12:/* 3840 Rx Data Fifo Size */
+                       lp->afc_cfg=0x0024124F;break;
+               case 13:/* 2880 Rx Data Fifo Size */
+                       lp->afc_cfg=0x0015073F;break;
+               case 14:/* 1920 Rx Data Fifo Size */
+                       lp->afc_cfg=0x0006032F;break;
+                default:
+                        PRINTK("%s: ERROR -- no AFC_CFG setting found",
+                               dev->name);
+                        break;
+       }
+
+       DBG(SMC_DEBUG_MISC | SMC_DEBUG_TX | SMC_DEBUG_RX,
+               "%s: tx_fifo %d rx_fifo %d afc_cfg 0x%08x\n", CARDNAME,
+               lp->tx_fifo_size, lp->rx_fifo_size, lp->afc_cfg);
+
+       spin_lock_init(&lp->lock);
+
+       /* Get the MAC address */
+       SMC_GET_MAC_ADDR(lp, dev->dev_addr);
+
+       /* now, reset the chip, and put it into a known state */
+       smc911x_reset(dev);
+
+       /*
+        * If dev->irq is 0, then the device has to be banged on to see
+        * what the IRQ is.
+        *
+        * Specifying an IRQ is done with the assumption that the user knows
+        * what (s)he is doing.  No checking is done!!!!
+        */
+       if (dev->irq < 1) {
+               int trials;
+
+               trials = 3;
+               while (trials--) {
+                       dev->irq = smc911x_findirq(dev);
+                       if (dev->irq)
+                               break;
+                       /* kick the card and try again */
+                       smc911x_reset(dev);
+               }
+       }
+       if (dev->irq == 0) {
+               printk("%s: Couldn't autodetect your IRQ. Use irq=xx.\n",
+                       dev->name);
+               retval = -ENODEV;
+               goto err_out;
+       }
+       dev->irq = irq_canonicalize(dev->irq);
+
+       /* Fill in the fields of the device structure with ethernet values. */
+       ether_setup(dev);
+
+       dev->netdev_ops = &smc911x_netdev_ops;
+       dev->watchdog_timeo = msecs_to_jiffies(watchdog);
+       dev->ethtool_ops = &smc911x_ethtool_ops;
+
+       INIT_WORK(&lp->phy_configure, smc911x_phy_configure);
+       lp->mii.phy_id_mask = 0x1f;
+       lp->mii.reg_num_mask = 0x1f;
+       lp->mii.force_media = 0;
+       lp->mii.full_duplex = 0;
+       lp->mii.dev = dev;
+       lp->mii.mdio_read = smc911x_phy_read;
+       lp->mii.mdio_write = smc911x_phy_write;
+
+       /*
+        * Locate the phy, if any.
+        */
+       smc911x_phy_detect(dev);
+
+       /* Set default parameters */
+       lp->msg_enable = NETIF_MSG_LINK;
+       lp->ctl_rfduplx = 1;
+       lp->ctl_rspeed = 100;
+
+#ifdef SMC_DYNAMIC_BUS_CONFIG
+       irq_flags = lp->cfg.irq_flags;
+#else
+       irq_flags = IRQF_SHARED | SMC_IRQ_SENSE;
+#endif
+
+       /* Grab the IRQ */
+       retval = request_irq(dev->irq, smc911x_interrupt,
+                            irq_flags, dev->name, dev);
+       if (retval)
+               goto err_out;
+
+#ifdef SMC_USE_DMA
+       lp->rxdma = SMC_DMA_REQUEST(dev, smc911x_rx_dma_irq);
+       lp->txdma = SMC_DMA_REQUEST(dev, smc911x_tx_dma_irq);
+       lp->rxdma_active = 0;
+       lp->txdma_active = 0;
+       dev->dma = lp->rxdma;
+#endif
+
+       retval = register_netdev(dev);
+       if (retval == 0) {
+               /* now, print out the card info, in a short format.. */
+               printk("%s: %s (rev %d) at %#lx IRQ %d",
+                       dev->name, version_string, lp->revision,
+                       dev->base_addr, dev->irq);
+
+#ifdef SMC_USE_DMA
+               if (lp->rxdma != -1)
+                       printk(" RXDMA %d ", lp->rxdma);
+
+               if (lp->txdma != -1)
+                       printk("TXDMA %d", lp->txdma);
+#endif
+               printk("\n");
+               if (!is_valid_ether_addr(dev->dev_addr)) {
+                       printk("%s: Invalid ethernet MAC address. Please "
+                                       "set using ifconfig\n", dev->name);
+               } else {
+                       /* Print the Ethernet address */
+                       printk("%s: Ethernet addr: %pM\n",
+                               dev->name, dev->dev_addr);
+               }
+
+               if (lp->phy_type == 0) {
+                       PRINTK("%s: No PHY found\n", dev->name);
+               } else if ((lp->phy_type & ~0xff) == LAN911X_INTERNAL_PHY_ID) {
+                       PRINTK("%s: LAN911x Internal PHY\n", dev->name);
+               } else {
+                       PRINTK("%s: External PHY 0x%08x\n", dev->name, lp->phy_type);
+               }
+       }
+
+err_out:
+#ifdef SMC_USE_DMA
+       if (retval) {
+               if (lp->rxdma != -1) {
+                       SMC_DMA_FREE(dev, lp->rxdma);
+               }
+               if (lp->txdma != -1) {
+                       SMC_DMA_FREE(dev, lp->txdma);
+               }
+       }
+#endif
+       return retval;
+}
+
+/*
+ * smc911x_init(void)
+ *
+ *       Output:
+ *      0 --> there is a device
+ *      anything else, error
+ */
+static int __devinit smc911x_drv_probe(struct platform_device *pdev)
+{
+       struct net_device *ndev;
+       struct resource *res;
+       struct smc911x_local *lp;
+       unsigned int *addr;
+       int ret;
+
+       DBG(SMC_DEBUG_FUNC, "--> %s\n",  __func__);
+       res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+       if (!res) {
+               ret = -ENODEV;
+               goto out;
+       }
+
+       /*
+        * Request the regions.
+        */
+       if (!request_mem_region(res->start, SMC911X_IO_EXTENT, CARDNAME)) {
+                ret = -EBUSY;
+                goto out;
+       }
+
+       ndev = alloc_etherdev(sizeof(struct smc911x_local));
+       if (!ndev) {
+               printk("%s: could not allocate device.\n", CARDNAME);
+               ret = -ENOMEM;
+               goto release_1;
+       }
+       SET_NETDEV_DEV(ndev, &pdev->dev);
+
+       ndev->dma = (unsigned char)-1;
+       ndev->irq = platform_get_irq(pdev, 0);
+       lp = netdev_priv(ndev);
+       lp->netdev = ndev;
+#ifdef SMC_DYNAMIC_BUS_CONFIG
+       {
+               struct smc911x_platdata *pd = pdev->dev.platform_data;
+               if (!pd) {
+                       ret = -EINVAL;
+                       goto release_both;
+               }
+               memcpy(&lp->cfg, pd, sizeof(lp->cfg));
+       }
+#endif
+
+       addr = ioremap(res->start, SMC911X_IO_EXTENT);
+       if (!addr) {
+               ret = -ENOMEM;
+               goto release_both;
+       }
+
+       platform_set_drvdata(pdev, ndev);
+       lp->base = addr;
+       ndev->base_addr = res->start;
+       ret = smc911x_probe(ndev);
+       if (ret != 0) {
+               platform_set_drvdata(pdev, NULL);
+               iounmap(addr);
+release_both:
+               free_netdev(ndev);
+release_1:
+               release_mem_region(res->start, SMC911X_IO_EXTENT);
+out:
+               printk("%s: not found (%d).\n", CARDNAME, ret);
+       }
+#ifdef SMC_USE_DMA
+       else {
+               lp->physaddr = res->start;
+               lp->dev = &pdev->dev;
+       }
+#endif
+
+       return ret;
+}
+
+static int __devexit smc911x_drv_remove(struct platform_device *pdev)
+{
+       struct net_device *ndev = platform_get_drvdata(pdev);
+       struct smc911x_local *lp = netdev_priv(ndev);
+       struct resource *res;
+
+       DBG(SMC_DEBUG_FUNC, "--> %s\n", __func__);
+       platform_set_drvdata(pdev, NULL);
+
+       unregister_netdev(ndev);
+
+       free_irq(ndev->irq, ndev);
+
+#ifdef SMC_USE_DMA
+       {
+               if (lp->rxdma != -1) {
+                       SMC_DMA_FREE(dev, lp->rxdma);
+               }
+               if (lp->txdma != -1) {
+                       SMC_DMA_FREE(dev, lp->txdma);
+               }
+       }
+#endif
+       iounmap(lp->base);
+       res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+       release_mem_region(res->start, SMC911X_IO_EXTENT);
+
+       free_netdev(ndev);
+       return 0;
+}
+
+static int smc911x_drv_suspend(struct platform_device *dev, pm_message_t state)
+{
+       struct net_device *ndev = platform_get_drvdata(dev);
+       struct smc911x_local *lp = netdev_priv(ndev);
+
+       DBG(SMC_DEBUG_FUNC, "--> %s\n", __func__);
+       if (ndev) {
+               if (netif_running(ndev)) {
+                       netif_device_detach(ndev);
+                       smc911x_shutdown(ndev);
+#if POWER_DOWN
+                       /* Set D2 - Energy detect only setting */
+                       SMC_SET_PMT_CTRL(lp, 2<<12);
+#endif
+               }
+       }
+       return 0;
+}
+
+static int smc911x_drv_resume(struct platform_device *dev)
+{
+       struct net_device *ndev = platform_get_drvdata(dev);
+
+       DBG(SMC_DEBUG_FUNC, "--> %s\n", __func__);
+       if (ndev) {
+               struct smc911x_local *lp = netdev_priv(ndev);
+
+               if (netif_running(ndev)) {
+                       smc911x_reset(ndev);
+                       if (lp->phy_type != 0)
+                               smc911x_phy_configure(&lp->phy_configure);
+                       smc911x_enable(ndev);
+                       netif_device_attach(ndev);
+               }
+       }
+       return 0;
+}
+
+static struct platform_driver smc911x_driver = {
+       .probe           = smc911x_drv_probe,
+       .remove  = __devexit_p(smc911x_drv_remove),
+       .suspend         = smc911x_drv_suspend,
+       .resume  = smc911x_drv_resume,
+       .driver  = {
+               .name    = CARDNAME,
+               .owner  = THIS_MODULE,
+       },
+};
+
+static int __init smc911x_init(void)
+{
+       return platform_driver_register(&smc911x_driver);
+}
+
+static void __exit smc911x_cleanup(void)
+{
+       platform_driver_unregister(&smc911x_driver);
+}
+
+module_init(smc911x_init);
+module_exit(smc911x_cleanup);
diff --git a/drivers/net/ethernet/smsc/smc911x.h b/drivers/net/ethernet/smsc/smc911x.h
new file mode 100644 (file)
index 0000000..3269292
--- /dev/null
@@ -0,0 +1,924 @@
+/*------------------------------------------------------------------------
+ . smc911x.h - macros for SMSC's LAN911{5,6,7,8} single-chip Ethernet device.
+ .
+ . Copyright (C) 2005 Sensoria Corp.
+ . Derived from the unified SMC91x driver by Nicolas Pitre
+ .
+ . This program is free software; you can redistribute it and/or modify
+ . it under the terms of the GNU General Public License as published by
+ . the Free Software Foundation; either version 2 of the License, or
+ . (at your option) any later version.
+ .
+ . This program is distributed in the hope that it will be useful,
+ . but WITHOUT ANY WARRANTY; without even the implied warranty of
+ . MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ . GNU General Public License for more details.
+ .
+ . You should have received a copy of the GNU General Public License
+ . along with this program; if not, write to the Free Software
+ . Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ .
+ . Information contained in this file was obtained from the LAN9118
+ . manual from SMC.  To get a copy, if you really want one, you can find
+ . information under www.smsc.com.
+ .
+ . Authors
+ .      Dustin McIntire                 <dustin@sensoria.com>
+ .
+ ---------------------------------------------------------------------------*/
+#ifndef _SMC911X_H_
+#define _SMC911X_H_
+
+#include <linux/smc911x.h>
+/*
+ * Use the DMA feature on PXA chips
+ */
+#ifdef CONFIG_ARCH_PXA
+  #define SMC_USE_PXA_DMA      1
+  #define SMC_USE_16BIT                0
+  #define SMC_USE_32BIT                1
+  #define SMC_IRQ_SENSE                IRQF_TRIGGER_FALLING
+#elif defined(CONFIG_SH_MAGIC_PANEL_R2)
+  #define SMC_USE_16BIT                0
+  #define SMC_USE_32BIT                1
+  #define SMC_IRQ_SENSE                IRQF_TRIGGER_LOW
+#elif defined(CONFIG_ARCH_OMAP3)
+  #define SMC_USE_16BIT                0
+  #define SMC_USE_32BIT                1
+  #define SMC_IRQ_SENSE                IRQF_TRIGGER_LOW
+  #define SMC_MEM_RESERVED     1
+#elif defined(CONFIG_ARCH_OMAP2)
+  #define SMC_USE_16BIT                0
+  #define SMC_USE_32BIT                1
+  #define SMC_IRQ_SENSE                IRQF_TRIGGER_LOW
+  #define SMC_MEM_RESERVED     1
+#else
+/*
+ * Default configuration
+ */
+
+#define SMC_DYNAMIC_BUS_CONFIG
+#endif
+
+#ifdef SMC_USE_PXA_DMA
+#define SMC_USE_DMA
+#endif
+
+/* store this information for the driver.. */
+struct smc911x_local {
+       /*
+        * If I have to wait until the DMA is finished and ready to reload a
+        * packet, I will store the skbuff here. Then, the DMA will send it
+        * out and free it.
+        */
+       struct sk_buff *pending_tx_skb;
+
+       /* version/revision of the SMC911x chip */
+       u16 version;
+       u16 revision;
+
+       /* FIFO sizes */
+       int tx_fifo_kb;
+       int tx_fifo_size;
+       int rx_fifo_size;
+       int afc_cfg;
+
+       /* Contains the current active receive/phy mode */
+       int ctl_rfduplx;
+       int ctl_rspeed;
+
+       u32 msg_enable;
+       u32 phy_type;
+       struct mii_if_info mii;
+
+       /* work queue */
+       struct work_struct phy_configure;
+
+       int tx_throttle;
+       spinlock_t lock;
+
+       struct net_device *netdev;
+
+#ifdef SMC_USE_DMA
+       /* DMA needs the physical address of the chip */
+       u_long physaddr;
+       int rxdma;
+       int txdma;
+       int rxdma_active;
+       int txdma_active;
+       struct sk_buff *current_rx_skb;
+       struct sk_buff *current_tx_skb;
+       struct device *dev;
+#endif
+       void __iomem *base;
+#ifdef SMC_DYNAMIC_BUS_CONFIG
+       struct smc911x_platdata cfg;
+#endif
+};
+
+/*
+ * Define the bus width specific IO macros
+ */
+
+#ifdef SMC_DYNAMIC_BUS_CONFIG
+static inline unsigned int SMC_inl(struct smc911x_local *lp, int reg)
+{
+       void __iomem *ioaddr = lp->base + reg;
+
+       if (lp->cfg.flags & SMC911X_USE_32BIT)
+               return readl(ioaddr);
+
+       if (lp->cfg.flags & SMC911X_USE_16BIT)
+               return readw(ioaddr) | (readw(ioaddr + 2) << 16);
+
+       BUG();
+}
+
+static inline void SMC_outl(unsigned int value, struct smc911x_local *lp,
+                           int reg)
+{
+       void __iomem *ioaddr = lp->base + reg;
+
+       if (lp->cfg.flags & SMC911X_USE_32BIT) {
+               writel(value, ioaddr);
+               return;
+       }
+
+       if (lp->cfg.flags & SMC911X_USE_16BIT) {
+               writew(value & 0xffff, ioaddr);
+               writew(value >> 16, ioaddr + 2);
+               return;
+       }
+
+       BUG();
+}
+
+static inline void SMC_insl(struct smc911x_local *lp, int reg,
+                             void *addr, unsigned int count)
+{
+       void __iomem *ioaddr = lp->base + reg;
+
+       if (lp->cfg.flags & SMC911X_USE_32BIT) {
+               readsl(ioaddr, addr, count);
+               return;
+       }
+
+       if (lp->cfg.flags & SMC911X_USE_16BIT) {
+               readsw(ioaddr, addr, count * 2);
+               return;
+       }
+
+       BUG();
+}
+
+static inline void SMC_outsl(struct smc911x_local *lp, int reg,
+                            void *addr, unsigned int count)
+{
+       void __iomem *ioaddr = lp->base + reg;
+
+       if (lp->cfg.flags & SMC911X_USE_32BIT) {
+               writesl(ioaddr, addr, count);
+               return;
+       }
+
+       if (lp->cfg.flags & SMC911X_USE_16BIT) {
+               writesw(ioaddr, addr, count * 2);
+               return;
+       }
+
+       BUG();
+}
+#else
+#if    SMC_USE_16BIT
+#define SMC_inl(lp, r)          ((readw((lp)->base + (r)) & 0xFFFF) + (readw((lp)->base + (r) + 2) << 16))
+#define SMC_outl(v, lp, r)                      \
+       do{                                      \
+                writew(v & 0xFFFF, (lp)->base + (r));   \
+                writew(v >> 16, (lp)->base + (r) + 2); \
+        } while (0)
+#define SMC_insl(lp, r, p, l)   readsw((short*)((lp)->base + (r)), p, l*2)
+#define SMC_outsl(lp, r, p, l)  writesw((short*)((lp)->base + (r)), p, l*2)
+
+#elif  SMC_USE_32BIT
+#define SMC_inl(lp, r)          readl((lp)->base + (r))
+#define SMC_outl(v, lp, r)      writel(v, (lp)->base + (r))
+#define SMC_insl(lp, r, p, l)   readsl((int*)((lp)->base + (r)), p, l)
+#define SMC_outsl(lp, r, p, l)  writesl((int*)((lp)->base + (r)), p, l)
+
+#endif /* SMC_USE_16BIT */
+#endif /* SMC_DYNAMIC_BUS_CONFIG */
+
+
+#ifdef SMC_USE_PXA_DMA
+
+#include <mach/dma.h>
+
+/*
+ * Define the request and free functions
+ * These are unfortunately architecture specific as no generic allocation
+ * mechanism exits
+ */
+#define SMC_DMA_REQUEST(dev, handler) \
+        pxa_request_dma(dev->name, DMA_PRIO_LOW, handler, dev)
+
+#define SMC_DMA_FREE(dev, dma) \
+        pxa_free_dma(dma)
+
+#define SMC_DMA_ACK_IRQ(dev, dma)                                      \
+{                                                                      \
+       if (DCSR(dma) & DCSR_BUSERR) {                                  \
+               printk("%s: DMA %d bus error!\n", dev->name, dma);      \
+       }                                                               \
+       DCSR(dma) = DCSR_STARTINTR|DCSR_ENDINTR|DCSR_BUSERR;            \
+}
+
+/*
+ * Use a DMA for RX and TX packets.
+ */
+#include <linux/dma-mapping.h>
+
+static dma_addr_t rx_dmabuf, tx_dmabuf;
+static int rx_dmalen, tx_dmalen;
+
+#ifdef SMC_insl
+#undef SMC_insl
+#define SMC_insl(lp, r, p, l) \
+       smc_pxa_dma_insl(lp, lp->physaddr, r, lp->rxdma, p, l)
+
+static inline void
+smc_pxa_dma_insl(struct smc911x_local *lp, u_long physaddr,
+               int reg, int dma, u_char *buf, int len)
+{
+       /* 64 bit alignment is required for memory to memory DMA */
+       if ((long)buf & 4) {
+               *((u32 *)buf) = SMC_inl(lp, reg);
+               buf += 4;
+               len--;
+       }
+
+       len *= 4;
+       rx_dmabuf = dma_map_single(lp->dev, buf, len, DMA_FROM_DEVICE);
+       rx_dmalen = len;
+       DCSR(dma) = DCSR_NODESC;
+       DTADR(dma) = rx_dmabuf;
+       DSADR(dma) = physaddr + reg;
+       DCMD(dma) = (DCMD_INCTRGADDR | DCMD_BURST32 |
+               DCMD_WIDTH4 | DCMD_ENDIRQEN | (DCMD_LENGTH & rx_dmalen));
+       DCSR(dma) = DCSR_NODESC | DCSR_RUN;
+}
+#endif
+
+#ifdef SMC_outsl
+#undef SMC_outsl
+#define SMC_outsl(lp, r, p, l) \
+        smc_pxa_dma_outsl(lp, lp->physaddr, r, lp->txdma, p, l)
+
+static inline void
+smc_pxa_dma_outsl(struct smc911x_local *lp, u_long physaddr,
+               int reg, int dma, u_char *buf, int len)
+{
+       /* 64 bit alignment is required for memory to memory DMA */
+       if ((long)buf & 4) {
+               SMC_outl(*((u32 *)buf), lp, reg);
+               buf += 4;
+               len--;
+       }
+
+       len *= 4;
+       tx_dmabuf = dma_map_single(lp->dev, buf, len, DMA_TO_DEVICE);
+       tx_dmalen = len;
+       DCSR(dma) = DCSR_NODESC;
+       DSADR(dma) = tx_dmabuf;
+       DTADR(dma) = physaddr + reg;
+       DCMD(dma) = (DCMD_INCSRCADDR | DCMD_BURST32 |
+               DCMD_WIDTH4 | DCMD_ENDIRQEN | (DCMD_LENGTH & tx_dmalen));
+       DCSR(dma) = DCSR_NODESC | DCSR_RUN;
+}
+#endif
+#endif  /* SMC_USE_PXA_DMA */
+
+
+/* Chip Parameters and Register Definitions */
+
+#define SMC911X_TX_FIFO_LOW_THRESHOLD  (1536*2)
+
+#define SMC911X_IO_EXTENT       0x100
+
+#define SMC911X_EEPROM_LEN      7
+
+/* Below are the register offsets and bit definitions
+ * of the Lan911x memory space
+ */
+#define RX_DATA_FIFO            (0x00)
+
+#define TX_DATA_FIFO            (0x20)
+#define        TX_CMD_A_INT_ON_COMP_           (0x80000000)
+#define        TX_CMD_A_INT_BUF_END_ALGN_      (0x03000000)
+#define        TX_CMD_A_INT_4_BYTE_ALGN_       (0x00000000)
+#define        TX_CMD_A_INT_16_BYTE_ALGN_      (0x01000000)
+#define        TX_CMD_A_INT_32_BYTE_ALGN_      (0x02000000)
+#define        TX_CMD_A_INT_DATA_OFFSET_       (0x001F0000)
+#define        TX_CMD_A_INT_FIRST_SEG_         (0x00002000)
+#define        TX_CMD_A_INT_LAST_SEG_          (0x00001000)
+#define        TX_CMD_A_BUF_SIZE_              (0x000007FF)
+#define        TX_CMD_B_PKT_TAG_               (0xFFFF0000)
+#define        TX_CMD_B_ADD_CRC_DISABLE_       (0x00002000)
+#define        TX_CMD_B_DISABLE_PADDING_       (0x00001000)
+#define        TX_CMD_B_PKT_BYTE_LENGTH_       (0x000007FF)
+
+#define RX_STATUS_FIFO         (0x40)
+#define        RX_STS_PKT_LEN_                 (0x3FFF0000)
+#define        RX_STS_ES_                      (0x00008000)
+#define        RX_STS_BCST_                    (0x00002000)
+#define        RX_STS_LEN_ERR_                 (0x00001000)
+#define        RX_STS_RUNT_ERR_                (0x00000800)
+#define        RX_STS_MCAST_                   (0x00000400)
+#define        RX_STS_TOO_LONG_                (0x00000080)
+#define        RX_STS_COLL_                    (0x00000040)
+#define        RX_STS_ETH_TYPE_                (0x00000020)
+#define        RX_STS_WDOG_TMT_                (0x00000010)
+#define        RX_STS_MII_ERR_                 (0x00000008)
+#define        RX_STS_DRIBBLING_               (0x00000004)
+#define        RX_STS_CRC_ERR_                 (0x00000002)
+#define RX_STATUS_FIFO_PEEK    (0x44)
+#define TX_STATUS_FIFO         (0x48)
+#define        TX_STS_TAG_                     (0xFFFF0000)
+#define        TX_STS_ES_                      (0x00008000)
+#define        TX_STS_LOC_                     (0x00000800)
+#define        TX_STS_NO_CARR_                 (0x00000400)
+#define        TX_STS_LATE_COLL_               (0x00000200)
+#define        TX_STS_MANY_COLL_               (0x00000100)
+#define        TX_STS_COLL_CNT_                (0x00000078)
+#define        TX_STS_MANY_DEFER_              (0x00000004)
+#define        TX_STS_UNDERRUN_                (0x00000002)
+#define        TX_STS_DEFERRED_                (0x00000001)
+#define TX_STATUS_FIFO_PEEK    (0x4C)
+#define ID_REV                 (0x50)
+#define        ID_REV_CHIP_ID_                 (0xFFFF0000)  /* RO */
+#define        ID_REV_REV_ID_                  (0x0000FFFF)  /* RO */
+
+#define INT_CFG                        (0x54)
+#define        INT_CFG_INT_DEAS_               (0xFF000000)  /* R/W */
+#define        INT_CFG_INT_DEAS_CLR_           (0x00004000)
+#define        INT_CFG_INT_DEAS_STS_           (0x00002000)
+#define        INT_CFG_IRQ_INT_                (0x00001000)  /* RO */
+#define        INT_CFG_IRQ_EN_                 (0x00000100)  /* R/W */
+#define        INT_CFG_IRQ_POL_                (0x00000010)  /* R/W Not Affected by SW Reset */
+#define        INT_CFG_IRQ_TYPE_               (0x00000001)  /* R/W Not Affected by SW Reset */
+
+#define INT_STS                        (0x58)
+#define        INT_STS_SW_INT_                 (0x80000000)  /* R/WC */
+#define        INT_STS_TXSTOP_INT_             (0x02000000)  /* R/WC */
+#define        INT_STS_RXSTOP_INT_             (0x01000000)  /* R/WC */
+#define        INT_STS_RXDFH_INT_              (0x00800000)  /* R/WC */
+#define        INT_STS_RXDF_INT_               (0x00400000)  /* R/WC */
+#define        INT_STS_TX_IOC_                 (0x00200000)  /* R/WC */
+#define        INT_STS_RXD_INT_                (0x00100000)  /* R/WC */
+#define        INT_STS_GPT_INT_                (0x00080000)  /* R/WC */
+#define        INT_STS_PHY_INT_                (0x00040000)  /* RO */
+#define        INT_STS_PME_INT_                (0x00020000)  /* R/WC */
+#define        INT_STS_TXSO_                   (0x00010000)  /* R/WC */
+#define        INT_STS_RWT_                    (0x00008000)  /* R/WC */
+#define        INT_STS_RXE_                    (0x00004000)  /* R/WC */
+#define        INT_STS_TXE_                    (0x00002000)  /* R/WC */
+//#define      INT_STS_ERX_            (0x00001000)  /* R/WC */
+#define        INT_STS_TDFU_                   (0x00000800)  /* R/WC */
+#define        INT_STS_TDFO_                   (0x00000400)  /* R/WC */
+#define        INT_STS_TDFA_                   (0x00000200)  /* R/WC */
+#define        INT_STS_TSFF_                   (0x00000100)  /* R/WC */
+#define        INT_STS_TSFL_                   (0x00000080)  /* R/WC */
+//#define      INT_STS_RXDF_           (0x00000040)  /* R/WC */
+#define        INT_STS_RDFO_                   (0x00000040)  /* R/WC */
+#define        INT_STS_RDFL_                   (0x00000020)  /* R/WC */
+#define        INT_STS_RSFF_                   (0x00000010)  /* R/WC */
+#define        INT_STS_RSFL_                   (0x00000008)  /* R/WC */
+#define        INT_STS_GPIO2_INT_              (0x00000004)  /* R/WC */
+#define        INT_STS_GPIO1_INT_              (0x00000002)  /* R/WC */
+#define        INT_STS_GPIO0_INT_              (0x00000001)  /* R/WC */
+
+#define INT_EN                 (0x5C)
+#define        INT_EN_SW_INT_EN_               (0x80000000)  /* R/W */
+#define        INT_EN_TXSTOP_INT_EN_           (0x02000000)  /* R/W */
+#define        INT_EN_RXSTOP_INT_EN_           (0x01000000)  /* R/W */
+#define        INT_EN_RXDFH_INT_EN_            (0x00800000)  /* R/W */
+//#define      INT_EN_RXDF_INT_EN_             (0x00400000)  /* R/W */
+#define        INT_EN_TIOC_INT_EN_             (0x00200000)  /* R/W */
+#define        INT_EN_RXD_INT_EN_              (0x00100000)  /* R/W */
+#define        INT_EN_GPT_INT_EN_              (0x00080000)  /* R/W */
+#define        INT_EN_PHY_INT_EN_              (0x00040000)  /* R/W */
+#define        INT_EN_PME_INT_EN_              (0x00020000)  /* R/W */
+#define        INT_EN_TXSO_EN_                 (0x00010000)  /* R/W */
+#define        INT_EN_RWT_EN_                  (0x00008000)  /* R/W */
+#define        INT_EN_RXE_EN_                  (0x00004000)  /* R/W */
+#define        INT_EN_TXE_EN_                  (0x00002000)  /* R/W */
+//#define      INT_EN_ERX_EN_                  (0x00001000)  /* R/W */
+#define        INT_EN_TDFU_EN_                 (0x00000800)  /* R/W */
+#define        INT_EN_TDFO_EN_                 (0x00000400)  /* R/W */
+#define        INT_EN_TDFA_EN_                 (0x00000200)  /* R/W */
+#define        INT_EN_TSFF_EN_                 (0x00000100)  /* R/W */
+#define        INT_EN_TSFL_EN_                 (0x00000080)  /* R/W */
+//#define      INT_EN_RXDF_EN_                 (0x00000040)  /* R/W */
+#define        INT_EN_RDFO_EN_                 (0x00000040)  /* R/W */
+#define        INT_EN_RDFL_EN_                 (0x00000020)  /* R/W */
+#define        INT_EN_RSFF_EN_                 (0x00000010)  /* R/W */
+#define        INT_EN_RSFL_EN_                 (0x00000008)  /* R/W */
+#define        INT_EN_GPIO2_INT_               (0x00000004)  /* R/W */
+#define        INT_EN_GPIO1_INT_               (0x00000002)  /* R/W */
+#define        INT_EN_GPIO0_INT_               (0x00000001)  /* R/W */
+
+#define BYTE_TEST              (0x64)
+#define FIFO_INT               (0x68)
+#define        FIFO_INT_TX_AVAIL_LEVEL_        (0xFF000000)  /* R/W */
+#define        FIFO_INT_TX_STS_LEVEL_          (0x00FF0000)  /* R/W */
+#define        FIFO_INT_RX_AVAIL_LEVEL_        (0x0000FF00)  /* R/W */
+#define        FIFO_INT_RX_STS_LEVEL_          (0x000000FF)  /* R/W */
+
+#define RX_CFG                 (0x6C)
+#define        RX_CFG_RX_END_ALGN_             (0xC0000000)  /* R/W */
+#define                RX_CFG_RX_END_ALGN4_            (0x00000000)  /* R/W */
+#define                RX_CFG_RX_END_ALGN16_           (0x40000000)  /* R/W */
+#define                RX_CFG_RX_END_ALGN32_           (0x80000000)  /* R/W */
+#define        RX_CFG_RX_DMA_CNT_              (0x0FFF0000)  /* R/W */
+#define        RX_CFG_RX_DUMP_                 (0x00008000)  /* R/W */
+#define        RX_CFG_RXDOFF_                  (0x00001F00)  /* R/W */
+//#define      RX_CFG_RXBAD_                   (0x00000001)  /* R/W */
+
+#define TX_CFG                 (0x70)
+//#define      TX_CFG_TX_DMA_LVL_              (0xE0000000)     /* R/W */
+//#define      TX_CFG_TX_DMA_CNT_              (0x0FFF0000)     /* R/W Self Clearing */
+#define        TX_CFG_TXS_DUMP_                (0x00008000)  /* Self Clearing */
+#define        TX_CFG_TXD_DUMP_                (0x00004000)  /* Self Clearing */
+#define        TX_CFG_TXSAO_                   (0x00000004)  /* R/W */
+#define        TX_CFG_TX_ON_                   (0x00000002)  /* R/W */
+#define        TX_CFG_STOP_TX_                 (0x00000001)  /* Self Clearing */
+
+#define HW_CFG                 (0x74)
+#define        HW_CFG_TTM_                     (0x00200000)  /* R/W */
+#define        HW_CFG_SF_                      (0x00100000)  /* R/W */
+#define        HW_CFG_TX_FIF_SZ_               (0x000F0000)  /* R/W */
+#define        HW_CFG_TR_                      (0x00003000)  /* R/W */
+#define        HW_CFG_PHY_CLK_SEL_             (0x00000060)  /* R/W */
+#define                 HW_CFG_PHY_CLK_SEL_INT_PHY_    (0x00000000) /* R/W */
+#define                 HW_CFG_PHY_CLK_SEL_EXT_PHY_    (0x00000020) /* R/W */
+#define                 HW_CFG_PHY_CLK_SEL_CLK_DIS_    (0x00000040) /* R/W */
+#define        HW_CFG_SMI_SEL_                 (0x00000010)  /* R/W */
+#define        HW_CFG_EXT_PHY_DET_             (0x00000008)  /* RO */
+#define        HW_CFG_EXT_PHY_EN_              (0x00000004)  /* R/W */
+#define        HW_CFG_32_16_BIT_MODE_          (0x00000004)  /* RO */
+#define        HW_CFG_SRST_TO_                 (0x00000002)  /* RO */
+#define        HW_CFG_SRST_                    (0x00000001)  /* Self Clearing */
+
+#define RX_DP_CTRL             (0x78)
+#define        RX_DP_CTRL_RX_FFWD_             (0x80000000)  /* R/W */
+#define        RX_DP_CTRL_FFWD_BUSY_           (0x80000000)  /* RO */
+
+#define RX_FIFO_INF            (0x7C)
+#define         RX_FIFO_INF_RXSUSED_           (0x00FF0000)  /* RO */
+#define         RX_FIFO_INF_RXDUSED_           (0x0000FFFF)  /* RO */
+
+#define TX_FIFO_INF            (0x80)
+#define        TX_FIFO_INF_TSUSED_             (0x00FF0000)  /* RO */
+#define        TX_FIFO_INF_TDFREE_             (0x0000FFFF)  /* RO */
+
+#define PMT_CTRL               (0x84)
+#define        PMT_CTRL_PM_MODE_               (0x00003000)  /* Self Clearing */
+#define        PMT_CTRL_PHY_RST_               (0x00000400)  /* Self Clearing */
+#define        PMT_CTRL_WOL_EN_                (0x00000200)  /* R/W */
+#define        PMT_CTRL_ED_EN_                 (0x00000100)  /* R/W */
+#define        PMT_CTRL_PME_TYPE_              (0x00000040)  /* R/W Not Affected by SW Reset */
+#define        PMT_CTRL_WUPS_                  (0x00000030)  /* R/WC */
+#define                PMT_CTRL_WUPS_NOWAKE_           (0x00000000)  /* R/WC */
+#define                PMT_CTRL_WUPS_ED_               (0x00000010)  /* R/WC */
+#define                PMT_CTRL_WUPS_WOL_              (0x00000020)  /* R/WC */
+#define                PMT_CTRL_WUPS_MULTI_            (0x00000030)  /* R/WC */
+#define        PMT_CTRL_PME_IND_               (0x00000008)  /* R/W */
+#define        PMT_CTRL_PME_POL_               (0x00000004)  /* R/W */
+#define        PMT_CTRL_PME_EN_                (0x00000002)  /* R/W Not Affected by SW Reset */
+#define        PMT_CTRL_READY_                 (0x00000001)  /* RO */
+
+#define GPIO_CFG               (0x88)
+#define        GPIO_CFG_LED3_EN_               (0x40000000)  /* R/W */
+#define        GPIO_CFG_LED2_EN_               (0x20000000)  /* R/W */
+#define        GPIO_CFG_LED1_EN_               (0x10000000)  /* R/W */
+#define        GPIO_CFG_GPIO2_INT_POL_         (0x04000000)  /* R/W */
+#define        GPIO_CFG_GPIO1_INT_POL_         (0x02000000)  /* R/W */
+#define        GPIO_CFG_GPIO0_INT_POL_         (0x01000000)  /* R/W */
+#define        GPIO_CFG_EEPR_EN_               (0x00700000)  /* R/W */
+#define        GPIO_CFG_GPIOBUF2_              (0x00040000)  /* R/W */
+#define        GPIO_CFG_GPIOBUF1_              (0x00020000)  /* R/W */
+#define        GPIO_CFG_GPIOBUF0_              (0x00010000)  /* R/W */
+#define        GPIO_CFG_GPIODIR2_              (0x00000400)  /* R/W */
+#define        GPIO_CFG_GPIODIR1_              (0x00000200)  /* R/W */
+#define        GPIO_CFG_GPIODIR0_              (0x00000100)  /* R/W */
+#define        GPIO_CFG_GPIOD4_                (0x00000010)  /* R/W */
+#define        GPIO_CFG_GPIOD3_                (0x00000008)  /* R/W */
+#define        GPIO_CFG_GPIOD2_                (0x00000004)  /* R/W */
+#define        GPIO_CFG_GPIOD1_                (0x00000002)  /* R/W */
+#define        GPIO_CFG_GPIOD0_                (0x00000001)  /* R/W */
+
+#define GPT_CFG                        (0x8C)
+#define        GPT_CFG_TIMER_EN_               (0x20000000)  /* R/W */
+#define        GPT_CFG_GPT_LOAD_               (0x0000FFFF)  /* R/W */
+
+#define GPT_CNT                        (0x90)
+#define        GPT_CNT_GPT_CNT_                (0x0000FFFF)  /* RO */
+
+#define ENDIAN                 (0x98)
+#define FREE_RUN               (0x9C)
+#define RX_DROP                        (0xA0)
+#define MAC_CSR_CMD            (0xA4)
+#define         MAC_CSR_CMD_CSR_BUSY_          (0x80000000)  /* Self Clearing */
+#define         MAC_CSR_CMD_R_NOT_W_           (0x40000000)  /* R/W */
+#define         MAC_CSR_CMD_CSR_ADDR_          (0x000000FF)  /* R/W */
+
+#define MAC_CSR_DATA           (0xA8)
+#define AFC_CFG                        (0xAC)
+#define                AFC_CFG_AFC_HI_                 (0x00FF0000)  /* R/W */
+#define                AFC_CFG_AFC_LO_                 (0x0000FF00)  /* R/W */
+#define                AFC_CFG_BACK_DUR_               (0x000000F0)  /* R/W */
+#define                AFC_CFG_FCMULT_                 (0x00000008)  /* R/W */
+#define                AFC_CFG_FCBRD_                  (0x00000004)  /* R/W */
+#define                AFC_CFG_FCADD_                  (0x00000002)  /* R/W */
+#define                AFC_CFG_FCANY_                  (0x00000001)  /* R/W */
+
+#define E2P_CMD                        (0xB0)
+#define        E2P_CMD_EPC_BUSY_               (0x80000000)  /* Self Clearing */
+#define        E2P_CMD_EPC_CMD_                        (0x70000000)  /* R/W */
+#define                E2P_CMD_EPC_CMD_READ_           (0x00000000)  /* R/W */
+#define                E2P_CMD_EPC_CMD_EWDS_           (0x10000000)  /* R/W */
+#define                E2P_CMD_EPC_CMD_EWEN_           (0x20000000)  /* R/W */
+#define                E2P_CMD_EPC_CMD_WRITE_          (0x30000000)  /* R/W */
+#define                E2P_CMD_EPC_CMD_WRAL_           (0x40000000)  /* R/W */
+#define                E2P_CMD_EPC_CMD_ERASE_          (0x50000000)  /* R/W */
+#define                E2P_CMD_EPC_CMD_ERAL_           (0x60000000)  /* R/W */
+#define                E2P_CMD_EPC_CMD_RELOAD_         (0x70000000)  /* R/W */
+#define        E2P_CMD_EPC_TIMEOUT_            (0x00000200)  /* RO */
+#define        E2P_CMD_MAC_ADDR_LOADED_        (0x00000100)  /* RO */
+#define        E2P_CMD_EPC_ADDR_               (0x000000FF)  /* R/W */
+
+#define E2P_DATA               (0xB4)
+#define        E2P_DATA_EEPROM_DATA_           (0x000000FF)  /* R/W */
+/* end of LAN register offsets and bit definitions */
+
+/*
+ ****************************************************************************
+ ****************************************************************************
+ * MAC Control and Status Register (Indirect Address)
+ * Offset (through the MAC_CSR CMD and DATA port)
+ ****************************************************************************
+ ****************************************************************************
+ *
+ */
+#define MAC_CR                 (0x01)  /* R/W */
+
+/* MAC_CR - MAC Control Register */
+#define MAC_CR_RXALL_                  (0x80000000)
+// TODO: delete this bit? It is not described in the data sheet.
+#define MAC_CR_HBDIS_                  (0x10000000)
+#define MAC_CR_RCVOWN_                 (0x00800000)
+#define MAC_CR_LOOPBK_                 (0x00200000)
+#define MAC_CR_FDPX_                   (0x00100000)
+#define MAC_CR_MCPAS_                  (0x00080000)
+#define MAC_CR_PRMS_                   (0x00040000)
+#define MAC_CR_INVFILT_                        (0x00020000)
+#define MAC_CR_PASSBAD_                        (0x00010000)
+#define MAC_CR_HFILT_                  (0x00008000)
+#define MAC_CR_HPFILT_                 (0x00002000)
+#define MAC_CR_LCOLL_                  (0x00001000)
+#define MAC_CR_BCAST_                  (0x00000800)
+#define MAC_CR_DISRTY_                 (0x00000400)
+#define MAC_CR_PADSTR_                 (0x00000100)
+#define MAC_CR_BOLMT_MASK_             (0x000000C0)
+#define MAC_CR_DFCHK_                  (0x00000020)
+#define MAC_CR_TXEN_                   (0x00000008)
+#define MAC_CR_RXEN_                   (0x00000004)
+
+#define ADDRH                  (0x02)    /* R/W mask 0x0000FFFFUL */
+#define ADDRL                  (0x03)    /* R/W mask 0xFFFFFFFFUL */
+#define HASHH                  (0x04)    /* R/W */
+#define HASHL                  (0x05)    /* R/W */
+
+#define MII_ACC                        (0x06)    /* R/W */
+#define MII_ACC_PHY_ADDR_              (0x0000F800)
+#define MII_ACC_MIIRINDA_              (0x000007C0)
+#define MII_ACC_MII_WRITE_             (0x00000002)
+#define MII_ACC_MII_BUSY_              (0x00000001)
+
+#define MII_DATA               (0x07)    /* R/W mask 0x0000FFFFUL */
+
+#define FLOW                   (0x08)    /* R/W */
+#define FLOW_FCPT_                     (0xFFFF0000)
+#define FLOW_FCPASS_                   (0x00000004)
+#define FLOW_FCEN_                     (0x00000002)
+#define FLOW_FCBSY_                    (0x00000001)
+
+#define VLAN1                  (0x09)    /* R/W mask 0x0000FFFFUL */
+#define VLAN1_VTI1_                    (0x0000ffff)
+
+#define VLAN2                  (0x0A)    /* R/W mask 0x0000FFFFUL */
+#define VLAN2_VTI2_                    (0x0000ffff)
+
+#define WUFF                   (0x0B)    /* WO */
+
+#define WUCSR                  (0x0C)    /* R/W */
+#define WUCSR_GUE_                     (0x00000200)
+#define WUCSR_WUFR_                    (0x00000040)
+#define WUCSR_MPR_                     (0x00000020)
+#define WUCSR_WAKE_EN_                 (0x00000004)
+#define WUCSR_MPEN_                    (0x00000002)
+
+/*
+ ****************************************************************************
+ * Chip Specific MII Defines
+ ****************************************************************************
+ *
+ * Phy register offsets and bit definitions
+ *
+ */
+
+#define PHY_MODE_CTRL_STS      ((u32)17)       /* Mode Control/Status Register */
+//#define MODE_CTRL_STS_FASTRIP_         ((u16)0x4000)
+#define MODE_CTRL_STS_EDPWRDOWN_        ((u16)0x2000)
+//#define MODE_CTRL_STS_LOWSQEN_          ((u16)0x0800)
+//#define MODE_CTRL_STS_MDPREBP_          ((u16)0x0400)
+//#define MODE_CTRL_STS_FARLOOPBACK_  ((u16)0x0200)
+//#define MODE_CTRL_STS_FASTEST_          ((u16)0x0100)
+//#define MODE_CTRL_STS_REFCLKEN_         ((u16)0x0010)
+//#define MODE_CTRL_STS_PHYADBP_          ((u16)0x0008)
+//#define MODE_CTRL_STS_FORCE_G_LINK_ ((u16)0x0004)
+#define MODE_CTRL_STS_ENERGYON_                ((u16)0x0002)
+
+#define PHY_INT_SRC                    ((u32)29)
+#define PHY_INT_SRC_ENERGY_ON_                 ((u16)0x0080)
+#define PHY_INT_SRC_ANEG_COMP_                 ((u16)0x0040)
+#define PHY_INT_SRC_REMOTE_FAULT_              ((u16)0x0020)
+#define PHY_INT_SRC_LINK_DOWN_                 ((u16)0x0010)
+#define PHY_INT_SRC_ANEG_LP_ACK_               ((u16)0x0008)
+#define PHY_INT_SRC_PAR_DET_FAULT_             ((u16)0x0004)
+#define PHY_INT_SRC_ANEG_PGRX_                 ((u16)0x0002)
+
+#define PHY_INT_MASK                   ((u32)30)
+#define PHY_INT_MASK_ENERGY_ON_                        ((u16)0x0080)
+#define PHY_INT_MASK_ANEG_COMP_                        ((u16)0x0040)
+#define PHY_INT_MASK_REMOTE_FAULT_             ((u16)0x0020)
+#define PHY_INT_MASK_LINK_DOWN_                        ((u16)0x0010)
+#define PHY_INT_MASK_ANEG_LP_ACK_              ((u16)0x0008)
+#define PHY_INT_MASK_PAR_DET_FAULT_            ((u16)0x0004)
+#define PHY_INT_MASK_ANEG_PGRX_                        ((u16)0x0002)
+
+#define PHY_SPECIAL                    ((u32)31)
+#define PHY_SPECIAL_ANEG_DONE_                 ((u16)0x1000)
+#define PHY_SPECIAL_RES_                       ((u16)0x0040)
+#define PHY_SPECIAL_RES_MASK_                  ((u16)0x0FE1)
+#define PHY_SPECIAL_SPD_                       ((u16)0x001C)
+#define PHY_SPECIAL_SPD_10HALF_                        ((u16)0x0004)
+#define PHY_SPECIAL_SPD_10FULL_                        ((u16)0x0014)
+#define PHY_SPECIAL_SPD_100HALF_               ((u16)0x0008)
+#define PHY_SPECIAL_SPD_100FULL_               ((u16)0x0018)
+
+#define LAN911X_INTERNAL_PHY_ID                (0x0007C000)
+
+/* Chip ID values */
+#define CHIP_9115      0x0115
+#define CHIP_9116      0x0116
+#define CHIP_9117      0x0117
+#define CHIP_9118      0x0118
+#define CHIP_9211      0x9211
+#define CHIP_9215      0x115A
+#define CHIP_9217      0x117A
+#define CHIP_9218      0x118A
+
+struct chip_id {
+       u16 id;
+       char *name;
+};
+
+static const struct chip_id chip_ids[] =  {
+       { CHIP_9115, "LAN9115" },
+       { CHIP_9116, "LAN9116" },
+       { CHIP_9117, "LAN9117" },
+       { CHIP_9118, "LAN9118" },
+       { CHIP_9211, "LAN9211" },
+       { CHIP_9215, "LAN9215" },
+       { CHIP_9217, "LAN9217" },
+       { CHIP_9218, "LAN9218" },
+       { 0, NULL },
+};
+
+#define IS_REV_A(x)    ((x & 0xFFFF)==0)
+
+/*
+ * Macros to abstract register access according to the data bus
+ * capabilities.  Please use those and not the in/out primitives.
+ */
+/* FIFO read/write macros */
+#define SMC_PUSH_DATA(lp, p, l)        SMC_outsl( lp, TX_DATA_FIFO, p, (l) >> 2 )
+#define SMC_PULL_DATA(lp, p, l)        SMC_insl ( lp, RX_DATA_FIFO, p, (l) >> 2 )
+#define SMC_SET_TX_FIFO(lp, x)         SMC_outl( x, lp, TX_DATA_FIFO )
+#define SMC_GET_RX_FIFO(lp)    SMC_inl( lp, RX_DATA_FIFO )
+
+
+/* I/O mapped register read/write macros */
+#define SMC_GET_TX_STS_FIFO(lp)                SMC_inl( lp, TX_STATUS_FIFO )
+#define SMC_GET_RX_STS_FIFO(lp)                SMC_inl( lp, RX_STATUS_FIFO )
+#define SMC_GET_RX_STS_FIFO_PEEK(lp)   SMC_inl( lp, RX_STATUS_FIFO_PEEK )
+#define SMC_GET_PN(lp)                 (SMC_inl( lp, ID_REV ) >> 16)
+#define SMC_GET_REV(lp)                        (SMC_inl( lp, ID_REV ) & 0xFFFF)
+#define SMC_GET_IRQ_CFG(lp)            SMC_inl( lp, INT_CFG )
+#define SMC_SET_IRQ_CFG(lp, x)         SMC_outl( x, lp, INT_CFG )
+#define SMC_GET_INT(lp)                        SMC_inl( lp, INT_STS )
+#define SMC_ACK_INT(lp, x)                     SMC_outl( x, lp, INT_STS )
+#define SMC_GET_INT_EN(lp)             SMC_inl( lp, INT_EN )
+#define SMC_SET_INT_EN(lp, x)          SMC_outl( x, lp, INT_EN )
+#define SMC_GET_BYTE_TEST(lp)          SMC_inl( lp, BYTE_TEST )
+#define SMC_SET_BYTE_TEST(lp, x)               SMC_outl( x, lp, BYTE_TEST )
+#define SMC_GET_FIFO_INT(lp)           SMC_inl( lp, FIFO_INT )
+#define SMC_SET_FIFO_INT(lp, x)                SMC_outl( x, lp, FIFO_INT )
+#define SMC_SET_FIFO_TDA(lp, x)                                        \
+       do {                                                    \
+               unsigned long __flags;                          \
+               int __mask;                                     \
+               local_irq_save(__flags);                        \
+               __mask = SMC_GET_FIFO_INT((lp)) & ~(0xFF<<24);  \
+               SMC_SET_FIFO_INT( (lp), __mask | (x)<<24 );     \
+               local_irq_restore(__flags);                     \
+       } while (0)
+#define SMC_SET_FIFO_TSL(lp, x)                                        \
+       do {                                                    \
+               unsigned long __flags;                          \
+               int __mask;                                     \
+               local_irq_save(__flags);                        \
+               __mask = SMC_GET_FIFO_INT((lp)) & ~(0xFF<<16);  \
+               SMC_SET_FIFO_INT( (lp), __mask | (((x) & 0xFF)<<16));   \
+               local_irq_restore(__flags);                     \
+       } while (0)
+#define SMC_SET_FIFO_RSA(lp, x)                                        \
+       do {                                                    \
+               unsigned long __flags;                          \
+               int __mask;                                     \
+               local_irq_save(__flags);                        \
+               __mask = SMC_GET_FIFO_INT((lp)) & ~(0xFF<<8);   \
+               SMC_SET_FIFO_INT( (lp), __mask | (((x) & 0xFF)<<8));    \
+               local_irq_restore(__flags);                     \
+       } while (0)
+#define SMC_SET_FIFO_RSL(lp, x)                                        \
+       do {                                                    \
+               unsigned long __flags;                          \
+               int __mask;                                     \
+               local_irq_save(__flags);                        \
+               __mask = SMC_GET_FIFO_INT((lp)) & ~0xFF;        \
+               SMC_SET_FIFO_INT( (lp),__mask | ((x) & 0xFF));  \
+               local_irq_restore(__flags);                     \
+       } while (0)
+#define SMC_GET_RX_CFG(lp)             SMC_inl( lp, RX_CFG )
+#define SMC_SET_RX_CFG(lp, x)          SMC_outl( x, lp, RX_CFG )
+#define SMC_GET_TX_CFG(lp)             SMC_inl( lp, TX_CFG )
+#define SMC_SET_TX_CFG(lp, x)          SMC_outl( x, lp, TX_CFG )
+#define SMC_GET_HW_CFG(lp)             SMC_inl( lp, HW_CFG )
+#define SMC_SET_HW_CFG(lp, x)          SMC_outl( x, lp, HW_CFG )
+#define SMC_GET_RX_DP_CTRL(lp)         SMC_inl( lp, RX_DP_CTRL )
+#define SMC_SET_RX_DP_CTRL(lp, x)              SMC_outl( x, lp, RX_DP_CTRL )
+#define SMC_GET_PMT_CTRL(lp)           SMC_inl( lp, PMT_CTRL )
+#define SMC_SET_PMT_CTRL(lp, x)                SMC_outl( x, lp, PMT_CTRL )
+#define SMC_GET_GPIO_CFG(lp)           SMC_inl( lp, GPIO_CFG )
+#define SMC_SET_GPIO_CFG(lp, x)                SMC_outl( x, lp, GPIO_CFG )
+#define SMC_GET_RX_FIFO_INF(lp)                SMC_inl( lp, RX_FIFO_INF )
+#define SMC_SET_RX_FIFO_INF(lp, x)             SMC_outl( x, lp, RX_FIFO_INF )
+#define SMC_GET_TX_FIFO_INF(lp)                SMC_inl( lp, TX_FIFO_INF )
+#define SMC_SET_TX_FIFO_INF(lp, x)             SMC_outl( x, lp, TX_FIFO_INF )
+#define SMC_GET_GPT_CFG(lp)            SMC_inl( lp, GPT_CFG )
+#define SMC_SET_GPT_CFG(lp, x)         SMC_outl( x, lp, GPT_CFG )
+#define SMC_GET_RX_DROP(lp)            SMC_inl( lp, RX_DROP )
+#define SMC_SET_RX_DROP(lp, x)         SMC_outl( x, lp, RX_DROP )
+#define SMC_GET_MAC_CMD(lp)            SMC_inl( lp, MAC_CSR_CMD )
+#define SMC_SET_MAC_CMD(lp, x)         SMC_outl( x, lp, MAC_CSR_CMD )
+#define SMC_GET_MAC_DATA(lp)           SMC_inl( lp, MAC_CSR_DATA )
+#define SMC_SET_MAC_DATA(lp, x)                SMC_outl( x, lp, MAC_CSR_DATA )
+#define SMC_GET_AFC_CFG(lp)            SMC_inl( lp, AFC_CFG )
+#define SMC_SET_AFC_CFG(lp, x)         SMC_outl( x, lp, AFC_CFG )
+#define SMC_GET_E2P_CMD(lp)            SMC_inl( lp, E2P_CMD )
+#define SMC_SET_E2P_CMD(lp, x)         SMC_outl( x, lp, E2P_CMD )
+#define SMC_GET_E2P_DATA(lp)           SMC_inl( lp, E2P_DATA )
+#define SMC_SET_E2P_DATA(lp, x)                SMC_outl( x, lp, E2P_DATA )
+
+/* MAC register read/write macros */
+#define SMC_GET_MAC_CSR(lp,a,v)                                                \
+       do {                                                            \
+               while (SMC_GET_MAC_CMD((lp)) & MAC_CSR_CMD_CSR_BUSY_);  \
+               SMC_SET_MAC_CMD((lp),MAC_CSR_CMD_CSR_BUSY_ |            \
+                       MAC_CSR_CMD_R_NOT_W_ | (a) );                   \
+               while (SMC_GET_MAC_CMD((lp)) & MAC_CSR_CMD_CSR_BUSY_);  \
+               v = SMC_GET_MAC_DATA((lp));                             \
+       } while (0)
+#define SMC_SET_MAC_CSR(lp,a,v)                                                \
+       do {                                                            \
+               while (SMC_GET_MAC_CMD((lp)) & MAC_CSR_CMD_CSR_BUSY_);  \
+               SMC_SET_MAC_DATA((lp), v);                              \
+               SMC_SET_MAC_CMD((lp), MAC_CSR_CMD_CSR_BUSY_ | (a) );    \
+               while (SMC_GET_MAC_CMD((lp)) & MAC_CSR_CMD_CSR_BUSY_);  \
+       } while (0)
+#define SMC_GET_MAC_CR(lp, x)  SMC_GET_MAC_CSR( (lp), MAC_CR, x )
+#define SMC_SET_MAC_CR(lp, x)  SMC_SET_MAC_CSR( (lp), MAC_CR, x )
+#define SMC_GET_ADDRH(lp, x)   SMC_GET_MAC_CSR( (lp), ADDRH, x )
+#define SMC_SET_ADDRH(lp, x)   SMC_SET_MAC_CSR( (lp), ADDRH, x )
+#define SMC_GET_ADDRL(lp, x)   SMC_GET_MAC_CSR( (lp), ADDRL, x )
+#define SMC_SET_ADDRL(lp, x)   SMC_SET_MAC_CSR( (lp), ADDRL, x )
+#define SMC_GET_HASHH(lp, x)   SMC_GET_MAC_CSR( (lp), HASHH, x )
+#define SMC_SET_HASHH(lp, x)   SMC_SET_MAC_CSR( (lp), HASHH, x )
+#define SMC_GET_HASHL(lp, x)   SMC_GET_MAC_CSR( (lp), HASHL, x )
+#define SMC_SET_HASHL(lp, x)   SMC_SET_MAC_CSR( (lp), HASHL, x )
+#define SMC_GET_MII_ACC(lp, x) SMC_GET_MAC_CSR( (lp), MII_ACC, x )
+#define SMC_SET_MII_ACC(lp, x) SMC_SET_MAC_CSR( (lp), MII_ACC, x )
+#define SMC_GET_MII_DATA(lp, x)        SMC_GET_MAC_CSR( (lp), MII_DATA, x )
+#define SMC_SET_MII_DATA(lp, x)        SMC_SET_MAC_CSR( (lp), MII_DATA, x )
+#define SMC_GET_FLOW(lp, x)            SMC_GET_MAC_CSR( (lp), FLOW, x )
+#define SMC_SET_FLOW(lp, x)            SMC_SET_MAC_CSR( (lp), FLOW, x )
+#define SMC_GET_VLAN1(lp, x)   SMC_GET_MAC_CSR( (lp), VLAN1, x )
+#define SMC_SET_VLAN1(lp, x)   SMC_SET_MAC_CSR( (lp), VLAN1, x )
+#define SMC_GET_VLAN2(lp, x)   SMC_GET_MAC_CSR( (lp), VLAN2, x )
+#define SMC_SET_VLAN2(lp, x)   SMC_SET_MAC_CSR( (lp), VLAN2, x )
+#define SMC_SET_WUFF(lp, x)            SMC_SET_MAC_CSR( (lp), WUFF, x )
+#define SMC_GET_WUCSR(lp, x)   SMC_GET_MAC_CSR( (lp), WUCSR, x )
+#define SMC_SET_WUCSR(lp, x)   SMC_SET_MAC_CSR( (lp), WUCSR, x )
+
+/* PHY register read/write macros */
+#define SMC_GET_MII(lp,a,phy,v)                                        \
+       do {                                                    \
+               u32 __v;                                        \
+               do {                                            \
+                       SMC_GET_MII_ACC((lp), __v);                     \
+               } while ( __v & MII_ACC_MII_BUSY_ );            \
+               SMC_SET_MII_ACC( (lp), ((phy)<<11) | ((a)<<6) | \
+                       MII_ACC_MII_BUSY_);                     \
+               do {                                            \
+                       SMC_GET_MII_ACC( (lp), __v);                    \
+               } while ( __v & MII_ACC_MII_BUSY_ );            \
+               SMC_GET_MII_DATA((lp), v);                              \
+       } while (0)
+#define SMC_SET_MII(lp,a,phy,v)                                        \
+       do {                                                    \
+               u32 __v;                                        \
+               do {                                            \
+                       SMC_GET_MII_ACC((lp), __v);                     \
+               } while ( __v & MII_ACC_MII_BUSY_ );            \
+               SMC_SET_MII_DATA((lp), v);                              \
+               SMC_SET_MII_ACC( (lp), ((phy)<<11) | ((a)<<6) | \
+                       MII_ACC_MII_BUSY_        |              \
+                       MII_ACC_MII_WRITE_  );                  \
+               do {                                            \
+                       SMC_GET_MII_ACC((lp), __v);                     \
+               } while ( __v & MII_ACC_MII_BUSY_ );            \
+       } while (0)
+#define SMC_GET_PHY_BMCR(lp,phy,x)             SMC_GET_MII( (lp), MII_BMCR, phy, x )
+#define SMC_SET_PHY_BMCR(lp,phy,x)             SMC_SET_MII( (lp), MII_BMCR, phy, x )
+#define SMC_GET_PHY_BMSR(lp,phy,x)             SMC_GET_MII( (lp), MII_BMSR, phy, x )
+#define SMC_GET_PHY_ID1(lp,phy,x)              SMC_GET_MII( (lp), MII_PHYSID1, phy, x )
+#define SMC_GET_PHY_ID2(lp,phy,x)              SMC_GET_MII( (lp), MII_PHYSID2, phy, x )
+#define SMC_GET_PHY_MII_ADV(lp,phy,x)  SMC_GET_MII( (lp), MII_ADVERTISE, phy, x )
+#define SMC_SET_PHY_MII_ADV(lp,phy,x)  SMC_SET_MII( (lp), MII_ADVERTISE, phy, x )
+#define SMC_GET_PHY_MII_LPA(lp,phy,x)  SMC_GET_MII( (lp), MII_LPA, phy, x )
+#define SMC_SET_PHY_MII_LPA(lp,phy,x)  SMC_SET_MII( (lp), MII_LPA, phy, x )
+#define SMC_GET_PHY_CTRL_STS(lp,phy,x) SMC_GET_MII( (lp), PHY_MODE_CTRL_STS, phy, x )
+#define SMC_SET_PHY_CTRL_STS(lp,phy,x) SMC_SET_MII( (lp), PHY_MODE_CTRL_STS, phy, x )
+#define SMC_GET_PHY_INT_SRC(lp,phy,x)  SMC_GET_MII( (lp), PHY_INT_SRC, phy, x )
+#define SMC_SET_PHY_INT_SRC(lp,phy,x)  SMC_SET_MII( (lp), PHY_INT_SRC, phy, x )
+#define SMC_GET_PHY_INT_MASK(lp,phy,x) SMC_GET_MII( (lp), PHY_INT_MASK, phy, x )
+#define SMC_SET_PHY_INT_MASK(lp,phy,x) SMC_SET_MII( (lp), PHY_INT_MASK, phy, x )
+#define SMC_GET_PHY_SPECIAL(lp,phy,x)  SMC_GET_MII( (lp), PHY_SPECIAL, phy, x )
+
+
+
+/* Misc read/write macros */
+
+#ifndef SMC_GET_MAC_ADDR
+#define SMC_GET_MAC_ADDR(lp, addr)                             \
+       do {                                                    \
+               unsigned int __v;                               \
+                                                               \
+               SMC_GET_MAC_CSR((lp), ADDRL, __v);                      \
+               addr[0] = __v; addr[1] = __v >> 8;              \
+               addr[2] = __v >> 16; addr[3] = __v >> 24;       \
+               SMC_GET_MAC_CSR((lp), ADDRH, __v);                      \
+               addr[4] = __v; addr[5] = __v >> 8;              \
+       } while (0)
+#endif
+
+#define SMC_SET_MAC_ADDR(lp, addr)                             \
+       do {                                                    \
+                SMC_SET_MAC_CSR((lp), ADDRL,                           \
+                                addr[0] |                      \
+                               (addr[1] << 8) |                \
+                               (addr[2] << 16) |               \
+                               (addr[3] << 24));               \
+                SMC_SET_MAC_CSR((lp), ADDRH, addr[4]|(addr[5] << 8));\
+       } while (0)
+
+
+#define SMC_WRITE_EEPROM_CMD(lp, cmd, addr)                            \
+       do {                                                            \
+               while (SMC_GET_E2P_CMD((lp)) & MAC_CSR_CMD_CSR_BUSY_);  \
+               SMC_SET_MAC_CMD((lp), MAC_CSR_CMD_R_NOT_W_ | a );               \
+               while (SMC_GET_MAC_CMD((lp)) & MAC_CSR_CMD_CSR_BUSY_);  \
+       } while (0)
+
+#endif  /* _SMC911X_H_ */
diff --git a/drivers/net/ethernet/smsc/smc9194.c b/drivers/net/ethernet/smsc/smc9194.c
new file mode 100644 (file)
index 0000000..5b65ac4
--- /dev/null
@@ -0,0 +1,1589 @@
+/*------------------------------------------------------------------------
+ . smc9194.c
+ . This is a driver for SMC's 9000 series of Ethernet cards.
+ .
+ . Copyright (C) 1996 by Erik Stahlman
+ . This software may be used and distributed according to the terms
+ . of the GNU General Public License, incorporated herein by reference.
+ .
+ . "Features" of the SMC chip:
+ .   4608 byte packet memory. ( for the 91C92.  Others have more )
+ .   EEPROM for configuration
+ .   AUI/TP selection  ( mine has 10Base2/10BaseT select )
+ .
+ . Arguments:
+ .     io               = for the base address
+ .     irq      = for the IRQ
+ .     ifport = 0 for autodetect, 1 for TP, 2 for AUI ( or 10base2 )
+ .
+ . author:
+ .     Erik Stahlman                           ( erik@vt.edu )
+ . contributors:
+ .      Arnaldo Carvalho de Melo <acme@conectiva.com.br>
+ .
+ . Hardware multicast code from Peter Cammaert ( pc@denkart.be )
+ .
+ . Sources:
+ .    o   SMC databook
+ .    o   skeleton.c by Donald Becker ( becker@scyld.com )
+ .    o   ( a LOT of advice from Becker as well )
+ .
+ . History:
+ .     12/07/95  Erik Stahlman  written, got receive/xmit handled
+ .     01/03/96  Erik Stahlman  worked out some bugs, actually usable!!! :-)
+ .     01/06/96  Erik Stahlman  cleaned up some, better testing, etc
+ .     01/29/96  Erik Stahlman  fixed autoirq, added multicast
+ .     02/01/96  Erik Stahlman  1. disabled all interrupts in smc_reset
+ .                              2. got rid of post-decrementing bug -- UGH.
+ .     02/13/96  Erik Stahlman  Tried to fix autoirq failure.  Added more
+ .                              descriptive error messages.
+ .     02/15/96  Erik Stahlman  Fixed typo that caused detection failure
+ .     02/23/96  Erik Stahlman  Modified it to fit into kernel tree
+ .                              Added support to change hardware address
+ .                              Cleared stats on opens
+ .     02/26/96  Erik Stahlman  Trial support for Kernel 1.2.13
+ .                              Kludge for automatic IRQ detection
+ .     03/04/96  Erik Stahlman  Fixed kernel 1.3.70 +
+ .                              Fixed bug reported by Gardner Buchanan in
+ .                                smc_enable, with outw instead of outb
+ .     03/06/96  Erik Stahlman  Added hardware multicast from Peter Cammaert
+ .     04/14/00  Heiko Pruessing (SMA Regelsysteme)  Fixed bug in chip memory
+ .                              allocation
+ .      08/20/00  Arnaldo Melo   fix kfree(skb) in smc_hardware_send_packet
+ .      12/15/00  Christian Jullien fix "Warning: kfree_skb on hard IRQ"
+ .      11/08/01 Matt Domsch     Use common crc32 function
+ ----------------------------------------------------------------------------*/
+
+static const char version[] =
+       "smc9194.c:v0.14 12/15/00 by Erik Stahlman (erik@vt.edu)\n";
+
+#include <linux/module.h>
+#include <linux/kernel.h>
+#include <linux/types.h>
+#include <linux/fcntl.h>
+#include <linux/interrupt.h>
+#include <linux/ioport.h>
+#include <linux/in.h>
+#include <linux/string.h>
+#include <linux/init.h>
+#include <linux/crc32.h>
+#include <linux/errno.h>
+#include <linux/netdevice.h>
+#include <linux/etherdevice.h>
+#include <linux/skbuff.h>
+#include <linux/bitops.h>
+
+#include <asm/io.h>
+
+#include "smc9194.h"
+
+#define DRV_NAME "smc9194"
+
+/*------------------------------------------------------------------------
+ .
+ . Configuration options, for the experienced user to change.
+ .
+ -------------------------------------------------------------------------*/
+
+/*
+ . Do you want to use 32 bit xfers?  This should work on all chips, as
+ . the chipset is designed to accommodate them.
+*/
+#ifdef __sh__
+#undef USE_32_BIT
+#else
+#define USE_32_BIT 1
+#endif
+
+#if defined(__H8300H__) || defined(__H8300S__)
+#define NO_AUTOPROBE
+#undef insl
+#undef outsl
+#define insl(a,b,l)  io_insl_noswap(a,b,l)
+#define outsl(a,b,l) io_outsl_noswap(a,b,l)
+#endif
+
+/*
+ .the SMC9194 can be at any of the following port addresses.  To change,
+ .for a slightly different card, you can add it to the array.  Keep in
+ .mind that the array must end in zero.
+*/
+
+struct devlist {
+       unsigned int port;
+       unsigned int irq;
+};
+
+#if defined(CONFIG_H8S_EDOSK2674)
+static struct devlist smc_devlist[] __initdata = {
+       {.port = 0xf80000, .irq = 16},
+       {.port = 0,        .irq = 0 },
+};
+#else
+static struct devlist smc_devlist[] __initdata = {
+       {.port = 0x200, .irq = 0},
+       {.port = 0x220, .irq = 0},
+       {.port = 0x240, .irq = 0},
+       {.port = 0x260, .irq = 0},
+       {.port = 0x280, .irq = 0},
+       {.port = 0x2A0, .irq = 0},
+       {.port = 0x2C0, .irq = 0},
+       {.port = 0x2E0, .irq = 0},
+       {.port = 0x300, .irq = 0},
+       {.port = 0x320, .irq = 0},
+       {.port = 0x340, .irq = 0},
+       {.port = 0x360, .irq = 0},
+       {.port = 0x380, .irq = 0},
+       {.port = 0x3A0, .irq = 0},
+       {.port = 0x3C0, .irq = 0},
+       {.port = 0x3E0, .irq = 0},
+       {.port = 0,     .irq = 0},
+};
+#endif
+/*
+ . Wait time for memory to be free.  This probably shouldn't be
+ . tuned that much, as waiting for this means nothing else happens
+ . in the system
+*/
+#define MEMORY_WAIT_TIME 16
+
+/*
+ . DEBUGGING LEVELS
+ .
+ . 0 for normal operation
+ . 1 for slightly more details
+ . >2 for various levels of increasingly useless information
+ .    2 for interrupt tracking, status flags
+ .    3 for packet dumps, etc.
+*/
+#define SMC_DEBUG 0
+
+#if (SMC_DEBUG > 2 )
+#define PRINTK3(x) printk x
+#else
+#define PRINTK3(x)
+#endif
+
+#if SMC_DEBUG > 1
+#define PRINTK2(x) printk x
+#else
+#define PRINTK2(x)
+#endif
+
+#ifdef SMC_DEBUG
+#define PRINTK(x) printk x
+#else
+#define PRINTK(x)
+#endif
+
+
+/*------------------------------------------------------------------------
+ .
+ . The internal workings of the driver.  If you are changing anything
+ . here with the SMC stuff, you should have the datasheet and known
+ . what you are doing.
+ .
+ -------------------------------------------------------------------------*/
+#define CARDNAME "SMC9194"
+
+
+/* store this information for the driver.. */
+struct smc_local {
+       /*
+          If I have to wait until memory is available to send
+          a packet, I will store the skbuff here, until I get the
+          desired memory.  Then, I'll send it out and free it.
+       */
+       struct sk_buff * saved_skb;
+
+       /*
+        . This keeps track of how many packets that I have
+        . sent out.  When an TX_EMPTY interrupt comes, I know
+        . that all of these have been sent.
+       */
+       int     packets_waiting;
+};
+
+
+/*-----------------------------------------------------------------
+ .
+ .  The driver can be entered at any of the following entry points.
+ .
+ .------------------------------------------------------------------  */
+
+/*
+ . This is called by  register_netdev().  It is responsible for
+ . checking the portlist for the SMC9000 series chipset.  If it finds
+ . one, then it will initialize the device, find the hardware information,
+ . and sets up the appropriate device parameters.
+ . NOTE: Interrupts are *OFF* when this procedure is called.
+ .
+ . NB:This shouldn't be static since it is referred to externally.
+*/
+struct net_device *smc_init(int unit);
+
+/*
+ . The kernel calls this function when someone wants to use the device,
+ . typically 'ifconfig ethX up'.
+*/
+static int smc_open(struct net_device *dev);
+
+/*
+ . Our watchdog timed out. Called by the networking layer
+*/
+static void smc_timeout(struct net_device *dev);
+
+/*
+ . This is called by the kernel in response to 'ifconfig ethX down'.  It
+ . is responsible for cleaning up everything that the open routine
+ . does, and maybe putting the card into a powerdown state.
+*/
+static int smc_close(struct net_device *dev);
+
+/*
+ . Finally, a call to set promiscuous mode ( for TCPDUMP and related
+ . programs ) and multicast modes.
+*/
+static void smc_set_multicast_list(struct net_device *dev);
+
+
+/*---------------------------------------------------------------
+ .
+ . Interrupt level calls..
+ .
+ ----------------------------------------------------------------*/
+
+/*
+ . Handles the actual interrupt
+*/
+static irqreturn_t smc_interrupt(int irq, void *);
+/*
+ . This is a separate procedure to handle the receipt of a packet, to
+ . leave the interrupt code looking slightly cleaner
+*/
+static inline void smc_rcv( struct net_device *dev );
+/*
+ . This handles a TX interrupt, which is only called when an error
+ . relating to a packet is sent.
+*/
+static inline void smc_tx( struct net_device * dev );
+
+/*
+ ------------------------------------------------------------
+ .
+ . Internal routines
+ .
+ ------------------------------------------------------------
+*/
+
+/*
+ . Test if a given location contains a chip, trying to cause as
+ . little damage as possible if it's not a SMC chip.
+*/
+static int smc_probe(struct net_device *dev, int ioaddr);
+
+/*
+ . A rather simple routine to print out a packet for debugging purposes.
+*/
+#if SMC_DEBUG > 2
+static void print_packet( byte *, int );
+#endif
+
+#define tx_done(dev) 1
+
+/* this is called to actually send the packet to the chip */
+static void smc_hardware_send_packet( struct net_device * dev );
+
+/* Since I am not sure if I will have enough room in the chip's ram
+ . to store the packet, I call this routine, which either sends it
+ . now, or generates an interrupt when the card is ready for the
+ . packet */
+static netdev_tx_t  smc_wait_to_send_packet( struct sk_buff * skb,
+                                            struct net_device *dev );
+
+/* this does a soft reset on the device */
+static void smc_reset( int ioaddr );
+
+/* Enable Interrupts, Receive, and Transmit */
+static void smc_enable( int ioaddr );
+
+/* this puts the device in an inactive state */
+static void smc_shutdown( int ioaddr );
+
+/* This routine will find the IRQ of the driver if one is not
+ . specified in the input to the device.  */
+static int smc_findirq( int ioaddr );
+
+/*
+ . Function: smc_reset( int ioaddr )
+ . Purpose:
+ .     This sets the SMC91xx chip to its normal state, hopefully from whatever
+ .     mess that any other DOS driver has put it in.
+ .
+ . Maybe I should reset more registers to defaults in here?  SOFTRESET  should
+ . do that for me.
+ .
+ . Method:
+ .     1.  send a SOFT RESET
+ .     2.  wait for it to finish
+ .     3.  enable autorelease mode
+ .     4.  reset the memory management unit
+ .     5.  clear all interrupts
+ .
+*/
+static void smc_reset( int ioaddr )
+{
+       /* This resets the registers mostly to defaults, but doesn't
+          affect EEPROM.  That seems unnecessary */
+       SMC_SELECT_BANK( 0 );
+       outw( RCR_SOFTRESET, ioaddr + RCR );
+
+       /* this should pause enough for the chip to be happy */
+       SMC_DELAY( );
+
+       /* Set the transmit and receive configuration registers to
+          default values */
+       outw( RCR_CLEAR, ioaddr + RCR );
+       outw( TCR_CLEAR, ioaddr + TCR );
+
+       /* set the control register to automatically
+          release successfully transmitted packets, to make the best
+          use out of our limited memory */
+       SMC_SELECT_BANK( 1 );
+       outw( inw( ioaddr + CONTROL ) | CTL_AUTO_RELEASE , ioaddr + CONTROL );
+
+       /* Reset the MMU */
+       SMC_SELECT_BANK( 2 );
+       outw( MC_RESET, ioaddr + MMU_CMD );
+
+       /* Note:  It doesn't seem that waiting for the MMU busy is needed here,
+          but this is a place where future chipsets _COULD_ break.  Be wary
+          of issuing another MMU command right after this */
+
+       outb( 0, ioaddr + INT_MASK );
+}
+
+/*
+ . Function: smc_enable
+ . Purpose: let the chip talk to the outside work
+ . Method:
+ .     1.  Enable the transmitter
+ .     2.  Enable the receiver
+ .     3.  Enable interrupts
+*/
+static void smc_enable( int ioaddr )
+{
+       SMC_SELECT_BANK( 0 );
+       /* see the header file for options in TCR/RCR NORMAL*/
+       outw( TCR_NORMAL, ioaddr + TCR );
+       outw( RCR_NORMAL, ioaddr + RCR );
+
+       /* now, enable interrupts */
+       SMC_SELECT_BANK( 2 );
+       outb( SMC_INTERRUPT_MASK, ioaddr + INT_MASK );
+}
+
+/*
+ . Function: smc_shutdown
+ . Purpose:  closes down the SMC91xxx chip.
+ . Method:
+ .     1. zero the interrupt mask
+ .     2. clear the enable receive flag
+ .     3. clear the enable xmit flags
+ .
+ . TODO:
+ .   (1) maybe utilize power down mode.
+ .     Why not yet?  Because while the chip will go into power down mode,
+ .     the manual says that it will wake up in response to any I/O requests
+ .     in the register space.   Empirical results do not show this working.
+*/
+static void smc_shutdown( int ioaddr )
+{
+       /* no more interrupts for me */
+       SMC_SELECT_BANK( 2 );
+       outb( 0, ioaddr + INT_MASK );
+
+       /* and tell the card to stay away from that nasty outside world */
+       SMC_SELECT_BANK( 0 );
+       outb( RCR_CLEAR, ioaddr + RCR );
+       outb( TCR_CLEAR, ioaddr + TCR );
+#if 0
+       /* finally, shut the chip down */
+       SMC_SELECT_BANK( 1 );
+       outw( inw( ioaddr + CONTROL ), CTL_POWERDOWN, ioaddr + CONTROL  );
+#endif
+}
+
+
+/*
+ . Function: smc_setmulticast( int ioaddr, struct net_device *dev )
+ . Purpose:
+ .    This sets the internal hardware table to filter out unwanted multicast
+ .    packets before they take up memory.
+ .
+ .    The SMC chip uses a hash table where the high 6 bits of the CRC of
+ .    address are the offset into the table.  If that bit is 1, then the
+ .    multicast packet is accepted.  Otherwise, it's dropped silently.
+ .
+ .    To use the 6 bits as an offset into the table, the high 3 bits are the
+ .    number of the 8 bit register, while the low 3 bits are the bit within
+ .    that register.
+ .
+ . This routine is based very heavily on the one provided by Peter Cammaert.
+*/
+
+
+static void smc_setmulticast(int ioaddr, struct net_device *dev)
+{
+       int                     i;
+       unsigned char           multicast_table[ 8 ];
+       struct netdev_hw_addr *ha;
+       /* table for flipping the order of 3 bits */
+       unsigned char invert3[] = { 0, 4, 2, 6, 1, 5, 3, 7 };
+
+       /* start with a table of all zeros: reject all */
+       memset( multicast_table, 0, sizeof( multicast_table ) );
+
+       netdev_for_each_mc_addr(ha, dev) {
+               int position;
+
+               /* only use the low order bits */
+               position = ether_crc_le(6, ha->addr) & 0x3f;
+
+               /* do some messy swapping to put the bit in the right spot */
+               multicast_table[invert3[position&7]] |=
+                                       (1<<invert3[(position>>3)&7]);
+
+       }
+       /* now, the table can be loaded into the chipset */
+       SMC_SELECT_BANK( 3 );
+
+       for ( i = 0; i < 8 ; i++ ) {
+               outb( multicast_table[i], ioaddr + MULTICAST1 + i );
+       }
+}
+
+/*
+ . Function: smc_wait_to_send_packet( struct sk_buff * skb, struct net_device * )
+ . Purpose:
+ .    Attempt to allocate memory for a packet, if chip-memory is not
+ .    available, then tell the card to generate an interrupt when it
+ .    is available.
+ .
+ . Algorithm:
+ .
+ . o   if the saved_skb is not currently null, then drop this packet
+ .     on the floor.  This should never happen, because of TBUSY.
+ . o   if the saved_skb is null, then replace it with the current packet,
+ . o   See if I can sending it now.
+ . o   (NO): Enable interrupts and let the interrupt handler deal with it.
+ . o   (YES):Send it now.
+*/
+static netdev_tx_t smc_wait_to_send_packet(struct sk_buff *skb,
+                                          struct net_device *dev)
+{
+       struct smc_local *lp = netdev_priv(dev);
+       unsigned int ioaddr     = dev->base_addr;
+       word                    length;
+       unsigned short          numPages;
+       word                    time_out;
+
+       netif_stop_queue(dev);
+       /* Well, I want to send the packet.. but I don't know
+          if I can send it right now...  */
+
+       if ( lp->saved_skb) {
+               /* THIS SHOULD NEVER HAPPEN. */
+               dev->stats.tx_aborted_errors++;
+               printk(CARDNAME": Bad Craziness - sent packet while busy.\n" );
+               return NETDEV_TX_BUSY;
+       }
+       lp->saved_skb = skb;
+
+       length = skb->len;
+
+       if (length < ETH_ZLEN) {
+               if (skb_padto(skb, ETH_ZLEN)) {
+                       netif_wake_queue(dev);
+                       return NETDEV_TX_OK;
+               }
+               length = ETH_ZLEN;
+       }
+
+       /*
+       ** The MMU wants the number of pages to be the number of 256 bytes
+       ** 'pages', minus 1 ( since a packet can't ever have 0 pages :) )
+       **
+       ** Pkt size for allocating is data length +6 (for additional status words,
+       ** length and ctl!) If odd size last byte is included in this header.
+       */
+       numPages =  ((length & 0xfffe) + 6) / 256;
+
+       if (numPages > 7 ) {
+               printk(CARDNAME": Far too big packet error.\n");
+               /* freeing the packet is a good thing here... but should
+                . any packets of this size get down here?   */
+               dev_kfree_skb (skb);
+               lp->saved_skb = NULL;
+               /* this IS an error, but, i don't want the skb saved */
+               netif_wake_queue(dev);
+               return NETDEV_TX_OK;
+       }
+       /* either way, a packet is waiting now */
+       lp->packets_waiting++;
+
+       /* now, try to allocate the memory */
+       SMC_SELECT_BANK( 2 );
+       outw( MC_ALLOC | numPages, ioaddr + MMU_CMD );
+       /*
+       . Performance Hack
+       .
+       . wait a short amount of time.. if I can send a packet now, I send
+       . it now.  Otherwise, I enable an interrupt and wait for one to be
+       . available.
+       .
+       . I could have handled this a slightly different way, by checking to
+       . see if any memory was available in the FREE MEMORY register.  However,
+       . either way, I need to generate an allocation, and the allocation works
+       . no matter what, so I saw no point in checking free memory.
+       */
+       time_out = MEMORY_WAIT_TIME;
+       do {
+               word    status;
+
+               status = inb( ioaddr + INTERRUPT );
+               if ( status & IM_ALLOC_INT ) {
+                       /* acknowledge the interrupt */
+                       outb( IM_ALLOC_INT, ioaddr + INTERRUPT );
+                       break;
+               }
+       } while ( -- time_out );
+
+       if ( !time_out ) {
+               /* oh well, wait until the chip finds memory later */
+               SMC_ENABLE_INT( IM_ALLOC_INT );
+               PRINTK2((CARDNAME": memory allocation deferred.\n"));
+               /* it's deferred, but I'll handle it later */
+               return NETDEV_TX_OK;
+       }
+       /* or YES! I can send the packet now.. */
+       smc_hardware_send_packet(dev);
+       netif_wake_queue(dev);
+       return NETDEV_TX_OK;
+}
+
+/*
+ . Function:  smc_hardware_send_packet(struct net_device * )
+ . Purpose:
+ .     This sends the actual packet to the SMC9xxx chip.
+ .
+ . Algorithm:
+ .     First, see if a saved_skb is available.
+ .             ( this should NOT be called if there is no 'saved_skb'
+ .     Now, find the packet number that the chip allocated
+ .     Point the data pointers at it in memory
+ .     Set the length word in the chip's memory
+ .     Dump the packet to chip memory
+ .     Check if a last byte is needed ( odd length packet )
+ .             if so, set the control flag right
+ .     Tell the card to send it
+ .     Enable the transmit interrupt, so I know if it failed
+ .     Free the kernel data if I actually sent it.
+*/
+static void smc_hardware_send_packet( struct net_device * dev )
+{
+       struct smc_local *lp = netdev_priv(dev);
+       byte                    packet_no;
+       struct sk_buff *        skb = lp->saved_skb;
+       word                    length;
+       unsigned int            ioaddr;
+       byte                    * buf;
+
+       ioaddr = dev->base_addr;
+
+       if ( !skb ) {
+               PRINTK((CARDNAME": In XMIT with no packet to send\n"));
+               return;
+       }
+       length = ETH_ZLEN < skb->len ? skb->len : ETH_ZLEN;
+       buf = skb->data;
+
+       /* If I get here, I _know_ there is a packet slot waiting for me */
+       packet_no = inb( ioaddr + PNR_ARR + 1 );
+       if ( packet_no & 0x80 ) {
+               /* or isn't there?  BAD CHIP! */
+               printk(KERN_DEBUG CARDNAME": Memory allocation failed.\n");
+               dev_kfree_skb_any(skb);
+               lp->saved_skb = NULL;
+               netif_wake_queue(dev);
+               return;
+       }
+
+       /* we have a packet address, so tell the card to use it */
+       outb( packet_no, ioaddr + PNR_ARR );
+
+       /* point to the beginning of the packet */
+       outw( PTR_AUTOINC , ioaddr + POINTER );
+
+       PRINTK3((CARDNAME": Trying to xmit packet of length %x\n", length ));
+#if SMC_DEBUG > 2
+       print_packet( buf, length );
+#endif
+
+       /* send the packet length ( +6 for status, length and ctl byte )
+          and the status word ( set to zeros ) */
+#ifdef USE_32_BIT
+       outl(  (length +6 ) << 16 , ioaddr + DATA_1 );
+#else
+       outw( 0, ioaddr + DATA_1 );
+       /* send the packet length ( +6 for status words, length, and ctl*/
+       outb( (length+6) & 0xFF,ioaddr + DATA_1 );
+       outb( (length+6) >> 8 , ioaddr + DATA_1 );
+#endif
+
+       /* send the actual data
+        . I _think_ it's faster to send the longs first, and then
+        . mop up by sending the last word.  It depends heavily
+        . on alignment, at least on the 486.  Maybe it would be
+        . a good idea to check which is optimal?  But that could take
+        . almost as much time as is saved?
+       */
+#ifdef USE_32_BIT
+       if ( length & 0x2  ) {
+               outsl(ioaddr + DATA_1, buf,  length >> 2 );
+#if !defined(__H8300H__) && !defined(__H8300S__)
+               outw( *((word *)(buf + (length & 0xFFFFFFFC))),ioaddr +DATA_1);
+#else
+               ctrl_outw( *((word *)(buf + (length & 0xFFFFFFFC))),ioaddr +DATA_1);
+#endif
+       }
+       else
+               outsl(ioaddr + DATA_1, buf,  length >> 2 );
+#else
+       outsw(ioaddr + DATA_1 , buf, (length ) >> 1);
+#endif
+       /* Send the last byte, if there is one.   */
+
+       if ( (length & 1) == 0 ) {
+               outw( 0, ioaddr + DATA_1 );
+       } else {
+               outb( buf[length -1 ], ioaddr + DATA_1 );
+               outb( 0x20, ioaddr + DATA_1);
+       }
+
+       /* enable the interrupts */
+       SMC_ENABLE_INT( (IM_TX_INT | IM_TX_EMPTY_INT) );
+
+       /* and let the chipset deal with it */
+       outw( MC_ENQUEUE , ioaddr + MMU_CMD );
+
+       PRINTK2((CARDNAME": Sent packet of length %d\n", length));
+
+       lp->saved_skb = NULL;
+       dev_kfree_skb_any (skb);
+
+       dev->trans_start = jiffies;
+
+       /* we can send another packet */
+       netif_wake_queue(dev);
+}
+
+/*-------------------------------------------------------------------------
+ |
+ | smc_init(int unit)
+ |   Input parameters:
+ |     dev->base_addr == 0, try to find all possible locations
+ |     dev->base_addr == 1, return failure code
+ |     dev->base_addr == 2, always allocate space,  and return success
+ |     dev->base_addr == <anything else>   this is the address to check
+ |
+ |   Output:
+ |     pointer to net_device or ERR_PTR(error)
+ |
+ ---------------------------------------------------------------------------
+*/
+static int io;
+static int irq;
+static int ifport;
+
+struct net_device * __init smc_init(int unit)
+{
+       struct net_device *dev = alloc_etherdev(sizeof(struct smc_local));
+       struct devlist *smcdev = smc_devlist;
+       int err = 0;
+
+       if (!dev)
+               return ERR_PTR(-ENODEV);
+
+       if (unit >= 0) {
+               sprintf(dev->name, "eth%d", unit);
+               netdev_boot_setup_check(dev);
+               io = dev->base_addr;
+               irq = dev->irq;
+       }
+
+       if (io > 0x1ff) {       /* Check a single specified location. */
+               err = smc_probe(dev, io);
+       } else if (io != 0) {   /* Don't probe at all. */
+               err = -ENXIO;
+       } else {
+               for (;smcdev->port; smcdev++) {
+                       if (smc_probe(dev, smcdev->port) == 0)
+                               break;
+               }
+               if (!smcdev->port)
+                       err = -ENODEV;
+       }
+       if (err)
+               goto out;
+       err = register_netdev(dev);
+       if (err)
+               goto out1;
+       return dev;
+out1:
+       free_irq(dev->irq, dev);
+       release_region(dev->base_addr, SMC_IO_EXTENT);
+out:
+       free_netdev(dev);
+       return ERR_PTR(err);
+}
+
+/*----------------------------------------------------------------------
+ . smc_findirq
+ .
+ . This routine has a simple purpose -- make the SMC chip generate an
+ . interrupt, so an auto-detect routine can detect it, and find the IRQ,
+ ------------------------------------------------------------------------
+*/
+static int __init smc_findirq(int ioaddr)
+{
+#ifndef NO_AUTOPROBE
+       int     timeout = 20;
+       unsigned long cookie;
+
+
+       cookie = probe_irq_on();
+
+       /*
+        * What I try to do here is trigger an ALLOC_INT. This is done
+        * by allocating a small chunk of memory, which will give an interrupt
+        * when done.
+        */
+
+
+       SMC_SELECT_BANK(2);
+       /* enable ALLOCation interrupts ONLY */
+       outb( IM_ALLOC_INT, ioaddr + INT_MASK );
+
+       /*
+        . Allocate 512 bytes of memory.  Note that the chip was just
+        . reset so all the memory is available
+       */
+       outw( MC_ALLOC | 1, ioaddr + MMU_CMD );
+
+       /*
+        . Wait until positive that the interrupt has been generated
+       */
+       while ( timeout ) {
+               byte    int_status;
+
+               int_status = inb( ioaddr + INTERRUPT );
+
+               if ( int_status & IM_ALLOC_INT )
+                       break;          /* got the interrupt */
+               timeout--;
+       }
+       /* there is really nothing that I can do here if timeout fails,
+          as probe_irq_off will return a 0 anyway, which is what I
+          want in this case.   Plus, the clean up is needed in both
+          cases.  */
+
+       /* DELAY HERE!
+          On a fast machine, the status might change before the interrupt
+          is given to the processor.  This means that the interrupt was
+          never detected, and probe_irq_off fails to report anything.
+          This should fix probe_irq_* problems.
+       */
+       SMC_DELAY();
+       SMC_DELAY();
+
+       /* and disable all interrupts again */
+       outb( 0, ioaddr + INT_MASK );
+
+       /* and return what I found */
+       return probe_irq_off(cookie);
+#else /* NO_AUTOPROBE */
+       struct devlist *smcdev;
+       for (smcdev = smc_devlist; smcdev->port; smcdev++) {
+               if (smcdev->port == ioaddr)
+                       return smcdev->irq;
+       }
+       return 0;
+#endif
+}
+
+static const struct net_device_ops smc_netdev_ops = {
+       .ndo_open                = smc_open,
+       .ndo_stop               = smc_close,
+       .ndo_start_xmit         = smc_wait_to_send_packet,
+       .ndo_tx_timeout         = smc_timeout,
+       .ndo_set_multicast_list = smc_set_multicast_list,
+       .ndo_change_mtu         = eth_change_mtu,
+       .ndo_set_mac_address    = eth_mac_addr,
+       .ndo_validate_addr      = eth_validate_addr,
+};
+
+/*----------------------------------------------------------------------
+ . Function: smc_probe( int ioaddr )
+ .
+ . Purpose:
+ .     Tests to see if a given ioaddr points to an SMC9xxx chip.
+ .     Returns a 0 on success
+ .
+ . Algorithm:
+ .     (1) see if the high byte of BANK_SELECT is 0x33
+ .     (2) compare the ioaddr with the base register's address
+ .     (3) see if I recognize the chip ID in the appropriate register
+ .
+ .---------------------------------------------------------------------
+ */
+
+/*---------------------------------------------------------------
+ . Here I do typical initialization tasks.
+ .
+ . o  Initialize the structure if needed
+ . o  print out my vanity message if not done so already
+ . o  print out what type of hardware is detected
+ . o  print out the ethernet address
+ . o  find the IRQ
+ . o  set up my private data
+ . o  configure the dev structure with my subroutines
+ . o  actually GRAB the irq.
+ . o  GRAB the region
+ .-----------------------------------------------------------------
+*/
+static int __init smc_probe(struct net_device *dev, int ioaddr)
+{
+       int i, memory, retval;
+       static unsigned version_printed;
+       unsigned int bank;
+
+       const char *version_string;
+       const char *if_string;
+
+       /* registers */
+       word revision_register;
+       word base_address_register;
+       word configuration_register;
+       word memory_info_register;
+       word memory_cfg_register;
+
+       /* Grab the region so that no one else tries to probe our ioports. */
+       if (!request_region(ioaddr, SMC_IO_EXTENT, DRV_NAME))
+               return -EBUSY;
+
+       dev->irq = irq;
+       dev->if_port = ifport;
+
+       /* First, see if the high byte is 0x33 */
+       bank = inw( ioaddr + BANK_SELECT );
+       if ( (bank & 0xFF00) != 0x3300 ) {
+               retval = -ENODEV;
+               goto err_out;
+       }
+       /* The above MIGHT indicate a device, but I need to write to further
+               test this.  */
+       outw( 0x0, ioaddr + BANK_SELECT );
+       bank = inw( ioaddr + BANK_SELECT );
+       if ( (bank & 0xFF00 ) != 0x3300 ) {
+               retval = -ENODEV;
+               goto err_out;
+       }
+#if !defined(CONFIG_H8S_EDOSK2674)
+       /* well, we've already written once, so hopefully another time won't
+          hurt.  This time, I need to switch the bank register to bank 1,
+          so I can access the base address register */
+       SMC_SELECT_BANK(1);
+       base_address_register = inw( ioaddr + BASE );
+       if ( ioaddr != ( base_address_register >> 3 & 0x3E0 ) )  {
+               printk(CARDNAME ": IOADDR %x doesn't match configuration (%x). "
+                       "Probably not a SMC chip\n",
+                       ioaddr, base_address_register >> 3 & 0x3E0 );
+               /* well, the base address register didn't match.  Must not have
+                  been a SMC chip after all. */
+               retval = -ENODEV;
+               goto err_out;
+       }
+#else
+       (void)base_address_register; /* Warning suppression */
+#endif
+
+
+       /*  check if the revision register is something that I recognize.
+           These might need to be added to later, as future revisions
+           could be added.  */
+       SMC_SELECT_BANK(3);
+       revision_register  = inw( ioaddr + REVISION );
+       if ( !chip_ids[ ( revision_register  >> 4 ) & 0xF  ] ) {
+               /* I don't recognize this chip, so... */
+               printk(CARDNAME ": IO %x: Unrecognized revision register:"
+                       " %x, Contact author.\n", ioaddr, revision_register);
+
+               retval = -ENODEV;
+               goto err_out;
+       }
+
+       /* at this point I'll assume that the chip is an SMC9xxx.
+          It might be prudent to check a listing of MAC addresses
+          against the hardware address, or do some other tests. */
+
+       if (version_printed++ == 0)
+               printk("%s", version);
+
+       /* fill in some of the fields */
+       dev->base_addr = ioaddr;
+
+       /*
+        . Get the MAC address ( bank 1, regs 4 - 9 )
+       */
+       SMC_SELECT_BANK( 1 );
+       for ( i = 0; i < 6; i += 2 ) {
+               word    address;
+
+               address = inw( ioaddr + ADDR0 + i  );
+               dev->dev_addr[ i + 1] = address >> 8;
+               dev->dev_addr[ i ] = address & 0xFF;
+       }
+
+       /* get the memory information */
+
+       SMC_SELECT_BANK( 0 );
+       memory_info_register = inw( ioaddr + MIR );
+       memory_cfg_register  = inw( ioaddr + MCR );
+       memory = ( memory_cfg_register >> 9 )  & 0x7;  /* multiplier */
+       memory *= 256 * ( memory_info_register & 0xFF );
+
+       /*
+        Now, I want to find out more about the chip.  This is sort of
+        redundant, but it's cleaner to have it in both, rather than having
+        one VERY long probe procedure.
+       */
+       SMC_SELECT_BANK(3);
+       revision_register  = inw( ioaddr + REVISION );
+       version_string = chip_ids[ ( revision_register  >> 4 ) & 0xF  ];
+       if ( !version_string ) {
+               /* I shouldn't get here because this call was done before.... */
+               retval = -ENODEV;
+               goto err_out;
+       }
+
+       /* is it using AUI or 10BaseT ? */
+       if ( dev->if_port == 0 ) {
+               SMC_SELECT_BANK(1);
+               configuration_register = inw( ioaddr + CONFIG );
+               if ( configuration_register & CFG_AUI_SELECT )
+                       dev->if_port = 2;
+               else
+                       dev->if_port = 1;
+       }
+       if_string = interfaces[ dev->if_port - 1 ];
+
+       /* now, reset the chip, and put it into a known state */
+       smc_reset( ioaddr );
+
+       /*
+        . If dev->irq is 0, then the device has to be banged on to see
+        . what the IRQ is.
+        .
+        . This banging doesn't always detect the IRQ, for unknown reasons.
+        . a workaround is to reset the chip and try again.
+        .
+        . Interestingly, the DOS packet driver *SETS* the IRQ on the card to
+        . be what is requested on the command line.   I don't do that, mostly
+        . because the card that I have uses a non-standard method of accessing
+        . the IRQs, and because this _should_ work in most configurations.
+        .
+        . Specifying an IRQ is done with the assumption that the user knows
+        . what (s)he is doing.  No checking is done!!!!
+        .
+       */
+       if ( dev->irq < 2 ) {
+               int     trials;
+
+               trials = 3;
+               while ( trials-- ) {
+                       dev->irq = smc_findirq( ioaddr );
+                       if ( dev->irq )
+                               break;
+                       /* kick the card and try again */
+                       smc_reset( ioaddr );
+               }
+       }
+       if (dev->irq == 0 ) {
+               printk(CARDNAME": Couldn't autodetect your IRQ. Use irq=xx.\n");
+               retval = -ENODEV;
+               goto err_out;
+       }
+
+       /* now, print out the card info, in a short format.. */
+
+       printk("%s: %s(r:%d) at %#3x IRQ:%d INTF:%s MEM:%db ", dev->name,
+               version_string, revision_register & 0xF, ioaddr, dev->irq,
+               if_string, memory );
+       /*
+        . Print the Ethernet address
+       */
+       printk("ADDR: %pM\n", dev->dev_addr);
+
+       /* Grab the IRQ */
+       retval = request_irq(dev->irq, smc_interrupt, 0, DRV_NAME, dev);
+       if (retval) {
+               printk("%s: unable to get IRQ %d (irqval=%d).\n", DRV_NAME,
+                       dev->irq, retval);
+               goto err_out;
+       }
+
+       dev->netdev_ops                 = &smc_netdev_ops;
+       dev->watchdog_timeo             = HZ/20;
+
+       return 0;
+
+err_out:
+       release_region(ioaddr, SMC_IO_EXTENT);
+       return retval;
+}
+
+#if SMC_DEBUG > 2
+static void print_packet( byte * buf, int length )
+{
+#if 0
+       int i;
+       int remainder;
+       int lines;
+
+       printk("Packet of length %d\n", length);
+       lines = length / 16;
+       remainder = length % 16;
+
+       for ( i = 0; i < lines ; i ++ ) {
+               int cur;
+
+               for ( cur = 0; cur < 8; cur ++ ) {
+                       byte a, b;
+
+                       a = *(buf ++ );
+                       b = *(buf ++ );
+                       printk("%02x%02x ", a, b );
+               }
+               printk("\n");
+       }
+       for ( i = 0; i < remainder/2 ; i++ ) {
+               byte a, b;
+
+               a = *(buf ++ );
+               b = *(buf ++ );
+               printk("%02x%02x ", a, b );
+       }
+       printk("\n");
+#endif
+}
+#endif
+
+
+/*
+ * Open and Initialize the board
+ *
+ * Set up everything, reset the card, etc ..
+ *
+ */
+static int smc_open(struct net_device *dev)
+{
+       int     ioaddr = dev->base_addr;
+
+       int     i;      /* used to set hw ethernet address */
+
+       /* clear out all the junk that was put here before... */
+       memset(netdev_priv(dev), 0, sizeof(struct smc_local));
+
+       /* reset the hardware */
+
+       smc_reset( ioaddr );
+       smc_enable( ioaddr );
+
+       /* Select which interface to use */
+
+       SMC_SELECT_BANK( 1 );
+       if ( dev->if_port == 1 ) {
+               outw( inw( ioaddr + CONFIG ) & ~CFG_AUI_SELECT,
+                       ioaddr + CONFIG );
+       }
+       else if ( dev->if_port == 2 ) {
+               outw( inw( ioaddr + CONFIG ) | CFG_AUI_SELECT,
+                       ioaddr + CONFIG );
+       }
+
+       /*
+               According to Becker, I have to set the hardware address
+               at this point, because the (l)user can set it with an
+               ioctl.  Easily done...
+       */
+       SMC_SELECT_BANK( 1 );
+       for ( i = 0; i < 6; i += 2 ) {
+               word    address;
+
+               address = dev->dev_addr[ i + 1 ] << 8 ;
+               address  |= dev->dev_addr[ i ];
+               outw( address, ioaddr + ADDR0 + i );
+       }
+
+       netif_start_queue(dev);
+       return 0;
+}
+
+/*--------------------------------------------------------
+ . Called by the kernel to send a packet out into the void
+ . of the net.  This routine is largely based on
+ . skeleton.c, from Becker.
+ .--------------------------------------------------------
+*/
+
+static void smc_timeout(struct net_device *dev)
+{
+       /* If we get here, some higher level has decided we are broken.
+          There should really be a "kick me" function call instead. */
+       printk(KERN_WARNING CARDNAME": transmit timed out, %s?\n",
+               tx_done(dev) ? "IRQ conflict" :
+               "network cable problem");
+       /* "kick" the adaptor */
+       smc_reset( dev->base_addr );
+       smc_enable( dev->base_addr );
+       dev->trans_start = jiffies; /* prevent tx timeout */
+       /* clear anything saved */
+       ((struct smc_local *)netdev_priv(dev))->saved_skb = NULL;
+       netif_wake_queue(dev);
+}
+
+/*-------------------------------------------------------------
+ .
+ . smc_rcv -  receive a packet from the card
+ .
+ . There is ( at least ) a packet waiting to be read from
+ . chip-memory.
+ .
+ . o Read the status
+ . o If an error, record it
+ . o otherwise, read in the packet
+ --------------------------------------------------------------
+*/
+static void smc_rcv(struct net_device *dev)
+{
+       int     ioaddr = dev->base_addr;
+       int     packet_number;
+       word    status;
+       word    packet_length;
+
+       /* assume bank 2 */
+
+       packet_number = inw( ioaddr + FIFO_PORTS );
+
+       if ( packet_number & FP_RXEMPTY ) {
+               /* we got called , but nothing was on the FIFO */
+               PRINTK((CARDNAME ": WARNING: smc_rcv with nothing on FIFO.\n"));
+               /* don't need to restore anything */
+               return;
+       }
+
+       /*  start reading from the start of the packet */
+       outw( PTR_READ | PTR_RCV | PTR_AUTOINC, ioaddr + POINTER );
+
+       /* First two words are status and packet_length */
+       status          = inw( ioaddr + DATA_1 );
+       packet_length   = inw( ioaddr + DATA_1 );
+
+       packet_length &= 0x07ff;  /* mask off top bits */
+
+       PRINTK2(("RCV: STATUS %4x LENGTH %4x\n", status, packet_length ));
+       /*
+        . the packet length contains 3 extra words :
+        . status, length, and an extra word with an odd byte .
+       */
+       packet_length -= 6;
+
+       if ( !(status & RS_ERRORS ) ){
+               /* do stuff to make a new packet */
+               struct sk_buff  * skb;
+               byte            * data;
+
+               /* read one extra byte */
+               if ( status & RS_ODDFRAME )
+                       packet_length++;
+
+               /* set multicast stats */
+               if ( status & RS_MULTICAST )
+                       dev->stats.multicast++;
+
+               skb = dev_alloc_skb( packet_length + 5);
+
+               if ( skb == NULL ) {
+                       printk(KERN_NOTICE CARDNAME ": Low memory, packet dropped.\n");
+                       dev->stats.rx_dropped++;
+                       goto done;
+               }
+
+               /*
+                ! This should work without alignment, but it could be
+                ! in the worse case
+               */
+
+               skb_reserve( skb, 2 );   /* 16 bit alignment */
+
+               data = skb_put( skb, packet_length);
+
+#ifdef USE_32_BIT
+               /* QUESTION:  Like in the TX routine, do I want
+                  to send the DWORDs or the bytes first, or some
+                  mixture.  A mixture might improve already slow PIO
+                  performance  */
+               PRINTK3((" Reading %d dwords (and %d bytes)\n",
+                       packet_length >> 2, packet_length & 3 ));
+               insl(ioaddr + DATA_1 , data, packet_length >> 2 );
+               /* read the left over bytes */
+               insb( ioaddr + DATA_1, data + (packet_length & 0xFFFFFC),
+                       packet_length & 0x3  );
+#else
+               PRINTK3((" Reading %d words and %d byte(s)\n",
+                       (packet_length >> 1 ), packet_length & 1 ));
+               insw(ioaddr + DATA_1 , data, packet_length >> 1);
+               if ( packet_length & 1 ) {
+                       data += packet_length & ~1;
+                       *(data++) = inb( ioaddr + DATA_1 );
+               }
+#endif
+#if    SMC_DEBUG > 2
+                       print_packet( data, packet_length );
+#endif
+
+               skb->protocol = eth_type_trans(skb, dev );
+               netif_rx(skb);
+               dev->stats.rx_packets++;
+               dev->stats.rx_bytes += packet_length;
+       } else {
+               /* error ... */
+               dev->stats.rx_errors++;
+
+               if ( status & RS_ALGNERR )  dev->stats.rx_frame_errors++;
+               if ( status & (RS_TOOSHORT | RS_TOOLONG ) )
+                       dev->stats.rx_length_errors++;
+               if ( status & RS_BADCRC)        dev->stats.rx_crc_errors++;
+       }
+
+done:
+       /*  error or good, tell the card to get rid of this packet */
+       outw( MC_RELEASE, ioaddr + MMU_CMD );
+}
+
+
+/*************************************************************************
+ . smc_tx
+ .
+ . Purpose:  Handle a transmit error message.   This will only be called
+ .   when an error, because of the AUTO_RELEASE mode.
+ .
+ . Algorithm:
+ .     Save pointer and packet no
+ .     Get the packet no from the top of the queue
+ .     check if it's valid ( if not, is this an error??? )
+ .     read the status word
+ .     record the error
+ .     ( resend?  Not really, since we don't want old packets around )
+ .     Restore saved values
+ ************************************************************************/
+static void smc_tx( struct net_device * dev )
+{
+       int     ioaddr = dev->base_addr;
+       struct smc_local *lp = netdev_priv(dev);
+       byte saved_packet;
+       byte packet_no;
+       word tx_status;
+
+
+       /* assume bank 2  */
+
+       saved_packet = inb( ioaddr + PNR_ARR );
+       packet_no = inw( ioaddr + FIFO_PORTS );
+       packet_no &= 0x7F;
+
+       /* select this as the packet to read from */
+       outb( packet_no, ioaddr + PNR_ARR );
+
+       /* read the first word from this packet */
+       outw( PTR_AUTOINC | PTR_READ, ioaddr + POINTER );
+
+       tx_status = inw( ioaddr + DATA_1 );
+       PRINTK3((CARDNAME": TX DONE STATUS: %4x\n", tx_status));
+
+       dev->stats.tx_errors++;
+       if ( tx_status & TS_LOSTCAR ) dev->stats.tx_carrier_errors++;
+       if ( tx_status & TS_LATCOL  ) {
+               printk(KERN_DEBUG CARDNAME
+                       ": Late collision occurred on last xmit.\n");
+               dev->stats.tx_window_errors++;
+       }
+#if 0
+               if ( tx_status & TS_16COL ) { ... }
+#endif
+
+       if ( tx_status & TS_SUCCESS ) {
+               printk(CARDNAME": Successful packet caused interrupt\n");
+       }
+       /* re-enable transmit */
+       SMC_SELECT_BANK( 0 );
+       outw( inw( ioaddr + TCR ) | TCR_ENABLE, ioaddr + TCR );
+
+       /* kill the packet */
+       SMC_SELECT_BANK( 2 );
+       outw( MC_FREEPKT, ioaddr + MMU_CMD );
+
+       /* one less packet waiting for me */
+       lp->packets_waiting--;
+
+       outb( saved_packet, ioaddr + PNR_ARR );
+}
+
+/*--------------------------------------------------------------------
+ .
+ . This is the main routine of the driver, to handle the device when
+ . it needs some attention.
+ .
+ . So:
+ .   first, save state of the chipset
+ .   branch off into routines to handle each case, and acknowledge
+ .         each to the interrupt register
+ .   and finally restore state.
+ .
+ ---------------------------------------------------------------------*/
+
+static irqreturn_t smc_interrupt(int irq, void * dev_id)
+{
+       struct net_device *dev  = dev_id;
+       int ioaddr              = dev->base_addr;
+       struct smc_local *lp = netdev_priv(dev);
+
+       byte    status;
+       word    card_stats;
+       byte    mask;
+       int     timeout;
+       /* state registers */
+       word    saved_bank;
+       word    saved_pointer;
+       int handled = 0;
+
+
+       PRINTK3((CARDNAME": SMC interrupt started\n"));
+
+       saved_bank = inw( ioaddr + BANK_SELECT );
+
+       SMC_SELECT_BANK(2);
+       saved_pointer = inw( ioaddr + POINTER );
+
+       mask = inb( ioaddr + INT_MASK );
+       /* clear all interrupts */
+       outb( 0, ioaddr + INT_MASK );
+
+
+       /* set a timeout value, so I don't stay here forever */
+       timeout = 4;
+
+       PRINTK2((KERN_WARNING CARDNAME ": MASK IS %x\n", mask));
+       do {
+               /* read the status flag, and mask it */
+               status = inb( ioaddr + INTERRUPT ) & mask;
+               if (!status )
+                       break;
+
+               handled = 1;
+
+               PRINTK3((KERN_WARNING CARDNAME
+                       ": Handling interrupt status %x\n", status));
+
+               if (status & IM_RCV_INT) {
+                       /* Got a packet(s). */
+                       PRINTK2((KERN_WARNING CARDNAME
+                               ": Receive Interrupt\n"));
+                       smc_rcv(dev);
+               } else if (status & IM_TX_INT ) {
+                       PRINTK2((KERN_WARNING CARDNAME
+                               ": TX ERROR handled\n"));
+                       smc_tx(dev);
+                       outb(IM_TX_INT, ioaddr + INTERRUPT );
+               } else if (status & IM_TX_EMPTY_INT ) {
+                       /* update stats */
+                       SMC_SELECT_BANK( 0 );
+                       card_stats = inw( ioaddr + COUNTER );
+                       /* single collisions */
+                       dev->stats.collisions += card_stats & 0xF;
+                       card_stats >>= 4;
+                       /* multiple collisions */
+                       dev->stats.collisions += card_stats & 0xF;
+
+                       /* these are for when linux supports these statistics */
+
+                       SMC_SELECT_BANK( 2 );
+                       PRINTK2((KERN_WARNING CARDNAME
+                               ": TX_BUFFER_EMPTY handled\n"));
+                       outb( IM_TX_EMPTY_INT, ioaddr + INTERRUPT );
+                       mask &= ~IM_TX_EMPTY_INT;
+                       dev->stats.tx_packets += lp->packets_waiting;
+                       lp->packets_waiting = 0;
+
+               } else if (status & IM_ALLOC_INT ) {
+                       PRINTK2((KERN_DEBUG CARDNAME
+                               ": Allocation interrupt\n"));
+                       /* clear this interrupt so it doesn't happen again */
+                       mask &= ~IM_ALLOC_INT;
+
+                       smc_hardware_send_packet( dev );
+
+                       /* enable xmit interrupts based on this */
+                       mask |= ( IM_TX_EMPTY_INT | IM_TX_INT );
+
+                       /* and let the card send more packets to me */
+                       netif_wake_queue(dev);
+
+                       PRINTK2((CARDNAME": Handoff done successfully.\n"));
+               } else if (status & IM_RX_OVRN_INT ) {
+                       dev->stats.rx_errors++;
+                       dev->stats.rx_fifo_errors++;
+                       outb( IM_RX_OVRN_INT, ioaddr + INTERRUPT );
+               } else if (status & IM_EPH_INT ) {
+                       PRINTK((CARDNAME ": UNSUPPORTED: EPH INTERRUPT\n"));
+               } else if (status & IM_ERCV_INT ) {
+                       PRINTK((CARDNAME ": UNSUPPORTED: ERCV INTERRUPT\n"));
+                       outb( IM_ERCV_INT, ioaddr + INTERRUPT );
+               }
+       } while ( timeout -- );
+
+
+       /* restore state register */
+       SMC_SELECT_BANK( 2 );
+       outb( mask, ioaddr + INT_MASK );
+
+       PRINTK3((KERN_WARNING CARDNAME ": MASK is now %x\n", mask));
+       outw( saved_pointer, ioaddr + POINTER );
+
+       SMC_SELECT_BANK( saved_bank );
+
+       PRINTK3((CARDNAME ": Interrupt done\n"));
+       return IRQ_RETVAL(handled);
+}
+
+
+/*----------------------------------------------------
+ . smc_close
+ .
+ . this makes the board clean up everything that it can
+ . and not talk to the outside world.   Caused by
+ . an 'ifconfig ethX down'
+ .
+ -----------------------------------------------------*/
+static int smc_close(struct net_device *dev)
+{
+       netif_stop_queue(dev);
+       /* clear everything */
+       smc_shutdown( dev->base_addr );
+
+       /* Update the statistics here. */
+       return 0;
+}
+
+/*-----------------------------------------------------------
+ . smc_set_multicast_list
+ .
+ . This routine will, depending on the values passed to it,
+ . either make it accept multicast packets, go into
+ . promiscuous mode ( for TCPDUMP and cousins ) or accept
+ . a select set of multicast packets
+*/
+static void smc_set_multicast_list(struct net_device *dev)
+{
+       short ioaddr = dev->base_addr;
+
+       SMC_SELECT_BANK(0);
+       if ( dev->flags & IFF_PROMISC )
+               outw( inw(ioaddr + RCR ) | RCR_PROMISC, ioaddr + RCR );
+
+/* BUG?  I never disable promiscuous mode if multicasting was turned on.
+   Now, I turn off promiscuous mode, but I don't do anything to multicasting
+   when promiscuous mode is turned on.
+*/
+
+       /* Here, I am setting this to accept all multicast packets.
+          I don't need to zero the multicast table, because the flag is
+          checked before the table is
+       */
+       else if (dev->flags & IFF_ALLMULTI)
+               outw( inw(ioaddr + RCR ) | RCR_ALMUL, ioaddr + RCR );
+
+       /* We just get all multicast packets even if we only want them
+        . from one source.  This will be changed at some future
+        . point. */
+       else if (!netdev_mc_empty(dev)) {
+               /* support hardware multicasting */
+
+               /* be sure I get rid of flags I might have set */
+               outw( inw( ioaddr + RCR ) & ~(RCR_PROMISC | RCR_ALMUL),
+                       ioaddr + RCR );
+               /* NOTE: this has to set the bank, so make sure it is the
+                  last thing called.  The bank is set to zero at the top */
+               smc_setmulticast(ioaddr, dev);
+       }
+       else  {
+               outw( inw( ioaddr + RCR ) & ~(RCR_PROMISC | RCR_ALMUL),
+                       ioaddr + RCR );
+
+               /*
+                 since I'm disabling all multicast entirely, I need to
+                 clear the multicast list
+               */
+               SMC_SELECT_BANK( 3 );
+               outw( 0, ioaddr + MULTICAST1 );
+               outw( 0, ioaddr + MULTICAST2 );
+               outw( 0, ioaddr + MULTICAST3 );
+               outw( 0, ioaddr + MULTICAST4 );
+       }
+}
+
+#ifdef MODULE
+
+static struct net_device *devSMC9194;
+MODULE_LICENSE("GPL");
+
+module_param(io, int, 0);
+module_param(irq, int, 0);
+module_param(ifport, int, 0);
+MODULE_PARM_DESC(io, "SMC 99194 I/O base address");
+MODULE_PARM_DESC(irq, "SMC 99194 IRQ number");
+MODULE_PARM_DESC(ifport, "SMC 99194 interface port (0-default, 1-TP, 2-AUI)");
+
+int __init init_module(void)
+{
+       if (io == 0)
+               printk(KERN_WARNING
+               CARDNAME": You shouldn't use auto-probing with insmod!\n" );
+
+       /* copy the parameters from insmod into the device structure */
+       devSMC9194 = smc_init(-1);
+       if (IS_ERR(devSMC9194))
+               return PTR_ERR(devSMC9194);
+       return 0;
+}
+
+void __exit cleanup_module(void)
+{
+       unregister_netdev(devSMC9194);
+       free_irq(devSMC9194->irq, devSMC9194);
+       release_region(devSMC9194->base_addr, SMC_IO_EXTENT);
+       free_netdev(devSMC9194);
+}
+
+#endif /* MODULE */
diff --git a/drivers/net/ethernet/smsc/smc9194.h b/drivers/net/ethernet/smsc/smc9194.h
new file mode 100644 (file)
index 0000000..cf69d0a
--- /dev/null
@@ -0,0 +1,241 @@
+/*------------------------------------------------------------------------
+ . smc9194.h
+ . Copyright (C) 1996 by Erik Stahlman
+ .
+ . This software may be used and distributed according to the terms
+ . of the GNU General Public License, incorporated herein by reference.
+ .
+ . This file contains register information and access macros for
+ . the SMC91xxx chipset.
+ .
+ . Information contained in this file was obtained from the SMC91C94
+ . manual from SMC.  To get a copy, if you really want one, you can find
+ . information under www.smc.com in the components division.
+ . ( this thanks to advice from Donald Becker ).
+ .
+ . Authors
+ .     Erik Stahlman                           ( erik@vt.edu )
+ .
+ . History
+ . 01/06/96             Erik Stahlman   moved definitions here from main .c file
+ . 01/19/96             Erik Stahlman    polished this up some, and added better
+ .                                                                               error handling
+ .
+ ---------------------------------------------------------------------------*/
+#ifndef _SMC9194_H_
+#define _SMC9194_H_
+
+/* I want some simple types */
+
+typedef unsigned char                  byte;
+typedef unsigned short                 word;
+typedef unsigned long int              dword;
+
+
+/* Because of bank switching, the SMC91xxx uses only 16 I/O ports */
+
+#define SMC_IO_EXTENT  16
+
+
+/*---------------------------------------------------------------
+ .
+ . A description of the SMC registers is probably in order here,
+ . although for details, the SMC datasheet is invaluable.
+ .
+ . Basically, the chip has 4 banks of registers ( 0 to 3 ), which
+ . are accessed by writing a number into the BANK_SELECT register
+ . ( I also use a SMC_SELECT_BANK macro for this ).
+ .
+ . The banks are configured so that for most purposes, bank 2 is all
+ . that is needed for simple run time tasks.
+ -----------------------------------------------------------------------*/
+
+/*
+ . Bank Select Register:
+ .
+ .             yyyy yyyy 0000 00xx
+ .             xx              = bank number
+ .             yyyy yyyy       = 0x33, for identification purposes.
+*/
+#define        BANK_SELECT             14
+
+/* BANK 0  */
+
+#define        TCR             0       /* transmit control register */
+#define TCR_ENABLE     0x0001  /* if this is 1, we can transmit */
+#define TCR_FDUPLX     0x0800  /* receive packets sent out */
+#define TCR_STP_SQET   0x1000  /* stop transmitting if Signal quality error */
+#define        TCR_MON_CNS     0x0400  /* monitors the carrier status */
+#define        TCR_PAD_ENABLE  0x0080  /* pads short packets to 64 bytes */
+
+#define        TCR_CLEAR       0       /* do NOTHING */
+/* the normal settings for the TCR register : */
+/* QUESTION: do I want to enable padding of short packets ? */
+#define        TCR_NORMAL      TCR_ENABLE
+
+
+#define EPH_STATUS     2
+#define ES_LINK_OK     0x4000  /* is the link integrity ok ? */
+
+#define        RCR             4
+#define RCR_SOFTRESET  0x8000  /* resets the chip */
+#define        RCR_STRIP_CRC   0x200   /* strips CRC */
+#define RCR_ENABLE     0x100   /* IFF this is set, we can receive packets */
+#define RCR_ALMUL      0x4     /* receive all multicast packets */
+#define        RCR_PROMISC     0x2     /* enable promiscuous mode */
+
+/* the normal settings for the RCR register : */
+#define        RCR_NORMAL      (RCR_STRIP_CRC | RCR_ENABLE)
+#define RCR_CLEAR      0x0             /* set it to a base state */
+
+#define        COUNTER         6
+#define        MIR             8
+#define        MCR             10
+/* 12 is reserved */
+
+/* BANK 1 */
+#define CONFIG                 0
+#define CFG_AUI_SELECT         0x100
+#define        BASE                    2
+#define        ADDR0                   4
+#define        ADDR1                   6
+#define        ADDR2                   8
+#define        GENERAL                 10
+#define        CONTROL                 12
+#define        CTL_POWERDOWN           0x2000
+#define        CTL_LE_ENABLE           0x80
+#define        CTL_CR_ENABLE           0x40
+#define        CTL_TE_ENABLE           0x0020
+#define CTL_AUTO_RELEASE       0x0800
+#define        CTL_EPROM_ACCESS        0x0003 /* high if Eprom is being read */
+
+/* BANK 2 */
+#define MMU_CMD                0
+#define MC_BUSY                1       /* only readable bit in the register */
+#define MC_NOP         0
+#define        MC_ALLOC        0x20    /* or with number of 256 byte packets */
+#define        MC_RESET        0x40
+#define        MC_REMOVE       0x60    /* remove the current rx packet */
+#define MC_RELEASE     0x80    /* remove and release the current rx packet */
+#define MC_FREEPKT     0xA0    /* Release packet in PNR register */
+#define MC_ENQUEUE     0xC0    /* Enqueue the packet for transmit */
+
+#define        PNR_ARR         2
+#define FIFO_PORTS     4
+
+#define FP_RXEMPTY  0x8000
+#define FP_TXEMPTY  0x80
+
+#define        POINTER         6
+#define PTR_READ       0x2000
+#define        PTR_RCV         0x8000
+#define        PTR_AUTOINC     0x4000
+#define PTR_AUTO_INC   0x0040
+
+#define        DATA_1          8
+#define        DATA_2          10
+#define        INTERRUPT       12
+
+#define INT_MASK       13
+#define IM_RCV_INT     0x1
+#define        IM_TX_INT       0x2
+#define        IM_TX_EMPTY_INT 0x4
+#define        IM_ALLOC_INT    0x8
+#define        IM_RX_OVRN_INT  0x10
+#define        IM_EPH_INT      0x20
+#define        IM_ERCV_INT     0x40 /* not on SMC9192 */
+
+/* BANK 3 */
+#define        MULTICAST1      0
+#define        MULTICAST2      2
+#define        MULTICAST3      4
+#define        MULTICAST4      6
+#define        MGMT            8
+#define        REVISION        10 /* ( hi: chip id   low: rev # ) */
+
+
+/* this is NOT on SMC9192 */
+#define        ERCV            12
+
+#define CHIP_9190      3
+#define CHIP_9194      4
+#define CHIP_9195      5
+#define CHIP_91100     7
+
+static const char * chip_ids[ 15 ] =  {
+       NULL, NULL, NULL,
+       /* 3 */ "SMC91C90/91C92",
+       /* 4 */ "SMC91C94",
+       /* 5 */ "SMC91C95",
+       NULL,
+       /* 7 */ "SMC91C100",
+       /* 8 */ "SMC91C100FD",
+       NULL, NULL, NULL,
+       NULL, NULL, NULL};
+
+/*
+ . Transmit status bits
+*/
+#define TS_SUCCESS 0x0001
+#define TS_LOSTCAR 0x0400
+#define TS_LATCOL  0x0200
+#define TS_16COL   0x0010
+
+/*
+ . Receive status bits
+*/
+#define RS_ALGNERR     0x8000
+#define RS_BADCRC      0x2000
+#define RS_ODDFRAME    0x1000
+#define RS_TOOLONG     0x0800
+#define RS_TOOSHORT    0x0400
+#define RS_MULTICAST   0x0001
+#define RS_ERRORS      (RS_ALGNERR | RS_BADCRC | RS_TOOLONG | RS_TOOSHORT)
+
+static const char * interfaces[ 2 ] = { "TP", "AUI" };
+
+/*-------------------------------------------------------------------------
+ .  I define some macros to make it easier to do somewhat common
+ . or slightly complicated, repeated tasks.
+ --------------------------------------------------------------------------*/
+
+/* select a register bank, 0 to 3  */
+
+#define SMC_SELECT_BANK(x)  { outw( x, ioaddr + BANK_SELECT ); }
+
+/* define a small delay for the reset */
+#define SMC_DELAY() { inw( ioaddr + RCR );\
+                       inw( ioaddr + RCR );\
+                       inw( ioaddr + RCR );  }
+
+/* this enables an interrupt in the interrupt mask register */
+#define SMC_ENABLE_INT(x) {\
+               unsigned char mask;\
+               SMC_SELECT_BANK(2);\
+               mask = inb( ioaddr + INT_MASK );\
+               mask |= (x);\
+               outb( mask, ioaddr + INT_MASK ); \
+}
+
+/* this disables an interrupt from the interrupt mask register */
+
+#define SMC_DISABLE_INT(x) {\
+               unsigned char mask;\
+               SMC_SELECT_BANK(2);\
+               mask = inb( ioaddr + INT_MASK );\
+               mask &= ~(x);\
+               outb( mask, ioaddr + INT_MASK ); \
+}
+
+/*----------------------------------------------------------------------
+ . Define the interrupts that I want to receive from the card
+ .
+ . I want:
+ .  IM_EPH_INT, for nasty errors
+ .  IM_RCV_INT, for happy received packets
+ .  IM_RX_OVRN_INT, because I have to kick the receiver
+ --------------------------------------------------------------------------*/
+#define SMC_INTERRUPT_MASK   (IM_EPH_INT | IM_RX_OVRN_INT | IM_RCV_INT)
+
+#endif  /* _SMC_9194_H_ */
+
diff --git a/drivers/net/ethernet/smsc/smc91c92_cs.c b/drivers/net/ethernet/smsc/smc91c92_cs.c
new file mode 100644 (file)
index 0000000..cffbc03
--- /dev/null
@@ -0,0 +1,2070 @@
+/*======================================================================
+
+    A PCMCIA ethernet driver for SMC91c92-based cards.
+
+    This driver supports Megahertz PCMCIA ethernet cards; and
+    Megahertz, Motorola, Ositech, and Psion Dacom ethernet/modem
+    multifunction cards.
+
+    Copyright (C) 1999 David A. Hinds -- dahinds@users.sourceforge.net
+
+    smc91c92_cs.c 1.122 2002/10/25 06:26:39
+
+    This driver contains code written by Donald Becker
+    (becker@scyld.com), Rowan Hughes (x-csrdh@jcu.edu.au),
+    David Hinds (dahinds@users.sourceforge.net), and Erik Stahlman
+    (erik@vt.edu).  Donald wrote the SMC 91c92 code using parts of
+    Erik's SMC 91c94 driver.  Rowan wrote a similar driver, and I've
+    incorporated some parts of his driver here.  I (Dave) wrote most
+    of the PCMCIA glue code, and the Ositech support code.  Kelly
+    Stephens (kstephen@holli.com) added support for the Motorola
+    Mariner, with help from Allen Brost.
+
+    This software may be used and distributed according to the terms of
+    the GNU General Public License, incorporated herein by reference.
+
+======================================================================*/
+
+#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
+
+#include <linux/module.h>
+#include <linux/kernel.h>
+#include <linux/init.h>
+#include <linux/slab.h>
+#include <linux/string.h>
+#include <linux/timer.h>
+#include <linux/interrupt.h>
+#include <linux/delay.h>
+#include <linux/crc32.h>
+#include <linux/netdevice.h>
+#include <linux/etherdevice.h>
+#include <linux/skbuff.h>
+#include <linux/if_arp.h>
+#include <linux/ioport.h>
+#include <linux/ethtool.h>
+#include <linux/mii.h>
+#include <linux/jiffies.h>
+#include <linux/firmware.h>
+
+#include <pcmcia/cistpl.h>
+#include <pcmcia/cisreg.h>
+#include <pcmcia/ciscode.h>
+#include <pcmcia/ds.h>
+#include <pcmcia/ss.h>
+
+#include <asm/io.h>
+#include <asm/system.h>
+#include <asm/uaccess.h>
+
+/*====================================================================*/
+
+static const char *if_names[] = { "auto", "10baseT", "10base2"};
+
+/* Firmware name */
+#define FIRMWARE_NAME          "ositech/Xilinx7OD.bin"
+
+/* Module parameters */
+
+MODULE_DESCRIPTION("SMC 91c92 series PCMCIA ethernet driver");
+MODULE_LICENSE("GPL");
+MODULE_FIRMWARE(FIRMWARE_NAME);
+
+#define INT_MODULE_PARM(n, v) static int n = v; module_param(n, int, 0)
+
+/*
+  Transceiver/media type.
+   0 = auto
+   1 = 10baseT (and autoselect if #define AUTOSELECT),
+   2 = AUI/10base2,
+*/
+INT_MODULE_PARM(if_port, 0);
+
+
+#define DRV_NAME       "smc91c92_cs"
+#define DRV_VERSION    "1.123"
+
+/*====================================================================*/
+
+/* Operational parameter that usually are not changed. */
+
+/* Time in jiffies before concluding Tx hung */
+#define TX_TIMEOUT             ((400*HZ)/1000)
+
+/* Maximum events (Rx packets, etc.) to handle at each interrupt. */
+#define INTR_WORK              4
+
+/* Times to check the check the chip before concluding that it doesn't
+   currently have room for another Tx packet. */
+#define MEMORY_WAIT_TIME               8
+
+struct smc_private {
+       struct pcmcia_device    *p_dev;
+    spinlock_t                 lock;
+    u_short                    manfid;
+    u_short                    cardid;
+
+    struct sk_buff             *saved_skb;
+    int                                packets_waiting;
+    void                       __iomem *base;
+    u_short                    cfg;
+    struct timer_list          media;
+    int                                watchdog, tx_err;
+    u_short                    media_status;
+    u_short                    fast_poll;
+    u_short                    link_status;
+    struct mii_if_info         mii_if;
+    int                                duplex;
+    int                                rx_ovrn;
+};
+
+/* Special definitions for Megahertz multifunction cards */
+#define MEGAHERTZ_ISR          0x0380
+
+/* Special function registers for Motorola Mariner */
+#define MOT_LAN                        0x0000
+#define MOT_UART               0x0020
+#define MOT_EEPROM             0x20
+
+#define MOT_NORMAL \
+(COR_LEVEL_REQ | COR_FUNC_ENA | COR_ADDR_DECODE | COR_IREQ_ENA)
+
+/* Special function registers for Ositech cards */
+#define OSITECH_AUI_CTL                0x0c
+#define OSITECH_PWRDOWN                0x0d
+#define OSITECH_RESET          0x0e
+#define OSITECH_ISR            0x0f
+#define OSITECH_AUI_PWR                0x0c
+#define OSITECH_RESET_ISR      0x0e
+
+#define OSI_AUI_PWR            0x40
+#define OSI_LAN_PWRDOWN                0x02
+#define OSI_MODEM_PWRDOWN      0x01
+#define OSI_LAN_RESET          0x02
+#define OSI_MODEM_RESET                0x01
+
+/* Symbolic constants for the SMC91c9* series chips, from Erik Stahlman. */
+#define        BANK_SELECT             14              /* Window select register. */
+#define SMC_SELECT_BANK(x)  { outw(x, ioaddr + BANK_SELECT); }
+
+/* Bank 0 registers. */
+#define        TCR             0       /* transmit control register */
+#define         TCR_CLEAR      0       /* do NOTHING */
+#define  TCR_ENABLE    0x0001  /* if this is 1, we can transmit */
+#define         TCR_PAD_EN     0x0080  /* pads short packets to 64 bytes */
+#define  TCR_MONCSN    0x0400  /* Monitor Carrier. */
+#define  TCR_FDUPLX    0x0800  /* Full duplex mode. */
+#define         TCR_NORMAL TCR_ENABLE | TCR_PAD_EN
+
+#define EPH            2       /* Ethernet Protocol Handler report. */
+#define  EPH_TX_SUC    0x0001
+#define  EPH_SNGLCOL   0x0002
+#define  EPH_MULCOL    0x0004
+#define  EPH_LTX_MULT  0x0008
+#define  EPH_16COL     0x0010
+#define  EPH_SQET      0x0020
+#define  EPH_LTX_BRD   0x0040
+#define  EPH_TX_DEFR   0x0080
+#define  EPH_LAT_COL   0x0200
+#define  EPH_LOST_CAR  0x0400
+#define  EPH_EXC_DEF   0x0800
+#define  EPH_CTR_ROL   0x1000
+#define  EPH_RX_OVRN   0x2000
+#define  EPH_LINK_OK   0x4000
+#define  EPH_TX_UNRN   0x8000
+#define MEMINFO                8       /* Memory Information Register */
+#define MEMCFG         10      /* Memory Configuration Register */
+
+/* Bank 1 registers. */
+#define CONFIG                 0
+#define  CFG_MII_SELECT                0x8000  /* 91C100 only */
+#define  CFG_NO_WAIT           0x1000
+#define  CFG_FULL_STEP         0x0400
+#define  CFG_SET_SQLCH         0x0200
+#define  CFG_AUI_SELECT                0x0100
+#define  CFG_16BIT             0x0080
+#define  CFG_DIS_LINK          0x0040
+#define  CFG_STATIC            0x0030
+#define  CFG_IRQ_SEL_1         0x0004
+#define  CFG_IRQ_SEL_0         0x0002
+#define BASE_ADDR              2
+#define        ADDR0                   4
+#define        GENERAL                 10
+#define        CONTROL                 12
+#define  CTL_STORE             0x0001
+#define  CTL_RELOAD            0x0002
+#define  CTL_EE_SELECT         0x0004
+#define  CTL_TE_ENABLE         0x0020
+#define  CTL_CR_ENABLE         0x0040
+#define  CTL_LE_ENABLE         0x0080
+#define  CTL_AUTO_RELEASE      0x0800
+#define         CTL_POWERDOWN          0x2000
+
+/* Bank 2 registers. */
+#define MMU_CMD                0
+#define         MC_ALLOC       0x20    /* or with number of 256 byte packets */
+#define         MC_RESET       0x40
+#define  MC_RELEASE    0x80    /* remove and release the current rx packet */
+#define  MC_FREEPKT    0xA0    /* Release packet in PNR register */
+#define  MC_ENQUEUE    0xC0    /* Enqueue the packet for transmit */
+#define        PNR_ARR         2
+#define FIFO_PORTS     4
+#define  FP_RXEMPTY    0x8000
+#define        POINTER         6
+#define  PTR_AUTO_INC  0x0040
+#define  PTR_READ      0x2000
+#define         PTR_AUTOINC    0x4000
+#define         PTR_RCV        0x8000
+#define        DATA_1          8
+#define        INTERRUPT       12
+#define  IM_RCV_INT            0x1
+#define         IM_TX_INT              0x2
+#define         IM_TX_EMPTY_INT        0x4
+#define         IM_ALLOC_INT           0x8
+#define         IM_RX_OVRN_INT         0x10
+#define         IM_EPH_INT             0x20
+
+#define        RCR             4
+enum RxCfg { RxAllMulti = 0x0004, RxPromisc = 0x0002,
+            RxEnable = 0x0100, RxStripCRC = 0x0200};
+#define  RCR_SOFTRESET 0x8000  /* resets the chip */
+#define         RCR_STRIP_CRC  0x200   /* strips CRC */
+#define  RCR_ENABLE    0x100   /* IFF this is set, we can receive packets */
+#define  RCR_ALMUL     0x4     /* receive all multicast packets */
+#define         RCR_PROMISC    0x2     /* enable promiscuous mode */
+
+/* the normal settings for the RCR register : */
+#define         RCR_NORMAL     (RCR_STRIP_CRC | RCR_ENABLE)
+#define  RCR_CLEAR     0x0             /* set it to a base state */
+#define        COUNTER         6
+
+/* BANK 3 -- not the same values as in smc9194! */
+#define        MULTICAST0      0
+#define        MULTICAST2      2
+#define        MULTICAST4      4
+#define        MULTICAST6      6
+#define MGMT           8
+#define REVISION       0x0a
+
+/* Transmit status bits. */
+#define TS_SUCCESS 0x0001
+#define TS_16COL   0x0010
+#define TS_LATCOL  0x0200
+#define TS_LOSTCAR 0x0400
+
+/* Receive status bits. */
+#define RS_ALGNERR     0x8000
+#define RS_BADCRC      0x2000
+#define RS_ODDFRAME    0x1000
+#define RS_TOOLONG     0x0800
+#define RS_TOOSHORT    0x0400
+#define RS_MULTICAST   0x0001
+#define RS_ERRORS      (RS_ALGNERR | RS_BADCRC | RS_TOOLONG | RS_TOOSHORT)
+
+#define set_bits(v, p) outw(inw(p)|(v), (p))
+#define mask_bits(v, p) outw(inw(p)&(v), (p))
+
+/*====================================================================*/
+
+static void smc91c92_detach(struct pcmcia_device *p_dev);
+static int smc91c92_config(struct pcmcia_device *link);
+static void smc91c92_release(struct pcmcia_device *link);
+
+static int smc_open(struct net_device *dev);
+static int smc_close(struct net_device *dev);
+static int smc_ioctl(struct net_device *dev, struct ifreq *rq, int cmd);
+static void smc_tx_timeout(struct net_device *dev);
+static netdev_tx_t smc_start_xmit(struct sk_buff *skb,
+                                       struct net_device *dev);
+static irqreturn_t smc_interrupt(int irq, void *dev_id);
+static void smc_rx(struct net_device *dev);
+static void set_rx_mode(struct net_device *dev);
+static int s9k_config(struct net_device *dev, struct ifmap *map);
+static void smc_set_xcvr(struct net_device *dev, int if_port);
+static void smc_reset(struct net_device *dev);
+static void media_check(u_long arg);
+static void mdio_sync(unsigned int addr);
+static int mdio_read(struct net_device *dev, int phy_id, int loc);
+static void mdio_write(struct net_device *dev, int phy_id, int loc, int value);
+static int smc_link_ok(struct net_device *dev);
+static const struct ethtool_ops ethtool_ops;
+
+static const struct net_device_ops smc_netdev_ops = {
+       .ndo_open               = smc_open,
+       .ndo_stop               = smc_close,
+       .ndo_start_xmit         = smc_start_xmit,
+       .ndo_tx_timeout         = smc_tx_timeout,
+       .ndo_set_config         = s9k_config,
+       .ndo_set_multicast_list = set_rx_mode,
+       .ndo_do_ioctl           = smc_ioctl,
+       .ndo_change_mtu         = eth_change_mtu,
+       .ndo_set_mac_address    = eth_mac_addr,
+       .ndo_validate_addr      = eth_validate_addr,
+};
+
+static int smc91c92_probe(struct pcmcia_device *link)
+{
+    struct smc_private *smc;
+    struct net_device *dev;
+
+    dev_dbg(&link->dev, "smc91c92_attach()\n");
+
+    /* Create new ethernet device */
+    dev = alloc_etherdev(sizeof(struct smc_private));
+    if (!dev)
+       return -ENOMEM;
+    smc = netdev_priv(dev);
+    smc->p_dev = link;
+    link->priv = dev;
+
+    spin_lock_init(&smc->lock);
+
+    /* The SMC91c92-specific entries in the device structure. */
+    dev->netdev_ops = &smc_netdev_ops;
+    SET_ETHTOOL_OPS(dev, &ethtool_ops);
+    dev->watchdog_timeo = TX_TIMEOUT;
+
+    smc->mii_if.dev = dev;
+    smc->mii_if.mdio_read = mdio_read;
+    smc->mii_if.mdio_write = mdio_write;
+    smc->mii_if.phy_id_mask = 0x1f;
+    smc->mii_if.reg_num_mask = 0x1f;
+
+    return smc91c92_config(link);
+} /* smc91c92_attach */
+
+static void smc91c92_detach(struct pcmcia_device *link)
+{
+    struct net_device *dev = link->priv;
+
+    dev_dbg(&link->dev, "smc91c92_detach\n");
+
+    unregister_netdev(dev);
+
+    smc91c92_release(link);
+
+    free_netdev(dev);
+} /* smc91c92_detach */
+
+/*====================================================================*/
+
+static int cvt_ascii_address(struct net_device *dev, char *s)
+{
+    int i, j, da, c;
+
+    if (strlen(s) != 12)
+       return -1;
+    for (i = 0; i < 6; i++) {
+       da = 0;
+       for (j = 0; j < 2; j++) {
+           c = *s++;
+           da <<= 4;
+           da += ((c >= '0') && (c <= '9')) ?
+               (c - '0') : ((c & 0x0f) + 9);
+       }
+       dev->dev_addr[i] = da;
+    }
+    return 0;
+}
+
+/*====================================================================
+
+    Configuration stuff for Megahertz cards
+
+    mhz_3288_power() is used to power up a 3288's ethernet chip.
+    mhz_mfc_config() handles socket setup for multifunction (1144
+    and 3288) cards.  mhz_setup() gets a card's hardware ethernet
+    address.
+
+======================================================================*/
+
+static int mhz_3288_power(struct pcmcia_device *link)
+{
+    struct net_device *dev = link->priv;
+    struct smc_private *smc = netdev_priv(dev);
+    u_char tmp;
+
+    /* Read the ISR twice... */
+    readb(smc->base+MEGAHERTZ_ISR);
+    udelay(5);
+    readb(smc->base+MEGAHERTZ_ISR);
+
+    /* Pause 200ms... */
+    mdelay(200);
+
+    /* Now read and write the COR... */
+    tmp = readb(smc->base + link->config_base + CISREG_COR);
+    udelay(5);
+    writeb(tmp, smc->base + link->config_base + CISREG_COR);
+
+    return 0;
+}
+
+static int mhz_mfc_config_check(struct pcmcia_device *p_dev, void *priv_data)
+{
+       int k;
+       p_dev->io_lines = 16;
+       p_dev->resource[1]->start = p_dev->resource[0]->start;
+       p_dev->resource[1]->end = 8;
+       p_dev->resource[1]->flags &= ~IO_DATA_PATH_WIDTH;
+       p_dev->resource[1]->flags |= IO_DATA_PATH_WIDTH_8;
+       p_dev->resource[0]->end = 16;
+       p_dev->resource[0]->flags &= ~IO_DATA_PATH_WIDTH;
+       p_dev->resource[0]->flags |= IO_DATA_PATH_WIDTH_AUTO;
+       for (k = 0; k < 0x400; k += 0x10) {
+               if (k & 0x80)
+                       continue;
+               p_dev->resource[0]->start = k ^ 0x300;
+               if (!pcmcia_request_io(p_dev))
+                       return 0;
+       }
+       return -ENODEV;
+}
+
+static int mhz_mfc_config(struct pcmcia_device *link)
+{
+    struct net_device *dev = link->priv;
+    struct smc_private *smc = netdev_priv(dev);
+    unsigned int offset;
+    int i;
+
+    link->config_flags |= CONF_ENABLE_SPKR | CONF_ENABLE_IRQ |
+           CONF_AUTO_SET_IO;
+
+    /* The Megahertz combo cards have modem-like CIS entries, so
+       we have to explicitly try a bunch of port combinations. */
+    if (pcmcia_loop_config(link, mhz_mfc_config_check, NULL))
+           return -ENODEV;
+
+    dev->base_addr = link->resource[0]->start;
+
+    /* Allocate a memory window, for accessing the ISR */
+    link->resource[2]->flags = WIN_DATA_WIDTH_8|WIN_MEMORY_TYPE_AM|WIN_ENABLE;
+    link->resource[2]->start = link->resource[2]->end = 0;
+    i = pcmcia_request_window(link, link->resource[2], 0);
+    if (i != 0)
+           return -ENODEV;
+
+    smc->base = ioremap(link->resource[2]->start,
+                   resource_size(link->resource[2]));
+    offset = (smc->manfid == MANFID_MOTOROLA) ? link->config_base : 0;
+    i = pcmcia_map_mem_page(link, link->resource[2], offset);
+    if ((i == 0) &&
+       (smc->manfid == MANFID_MEGAHERTZ) &&
+       (smc->cardid == PRODID_MEGAHERTZ_EM3288))
+           mhz_3288_power(link);
+
+    return 0;
+}
+
+static int pcmcia_get_versmac(struct pcmcia_device *p_dev,
+                             tuple_t *tuple,
+                             void *priv)
+{
+       struct net_device *dev = priv;
+       cisparse_t parse;
+       u8 *buf;
+
+       if (pcmcia_parse_tuple(tuple, &parse))
+               return -EINVAL;
+
+       buf = parse.version_1.str + parse.version_1.ofs[3];
+
+       if ((parse.version_1.ns > 3) && (cvt_ascii_address(dev, buf) == 0))
+               return 0;
+
+       return -EINVAL;
+};
+
+static int mhz_setup(struct pcmcia_device *link)
+{
+    struct net_device *dev = link->priv;
+    size_t len;
+    u8 *buf;
+    int rc;
+
+    /* Read the station address from the CIS.  It is stored as the last
+       (fourth) string in the Version 1 Version/ID tuple. */
+    if ((link->prod_id[3]) &&
+       (cvt_ascii_address(dev, link->prod_id[3]) == 0))
+           return 0;
+
+    /* Workarounds for broken cards start here. */
+    /* Ugh -- the EM1144 card has two VERS_1 tuples!?! */
+    if (!pcmcia_loop_tuple(link, CISTPL_VERS_1, pcmcia_get_versmac, dev))
+           return 0;
+
+    /* Another possibility: for the EM3288, in a special tuple */
+    rc = -1;
+    len = pcmcia_get_tuple(link, 0x81, &buf);
+    if (buf && len >= 13) {
+           buf[12] = '\0';
+           if (cvt_ascii_address(dev, buf) == 0)
+                   rc = 0;
+    }
+    kfree(buf);
+
+    return rc;
+};
+
+/*======================================================================
+
+    Configuration stuff for the Motorola Mariner
+
+    mot_config() writes directly to the Mariner configuration
+    registers because the CIS is just bogus.
+
+======================================================================*/
+
+static void mot_config(struct pcmcia_device *link)
+{
+    struct net_device *dev = link->priv;
+    struct smc_private *smc = netdev_priv(dev);
+    unsigned int ioaddr = dev->base_addr;
+    unsigned int iouart = link->resource[1]->start;
+
+    /* Set UART base address and force map with COR bit 1 */
+    writeb(iouart & 0xff,        smc->base + MOT_UART + CISREG_IOBASE_0);
+    writeb((iouart >> 8) & 0xff, smc->base + MOT_UART + CISREG_IOBASE_1);
+    writeb(MOT_NORMAL,           smc->base + MOT_UART + CISREG_COR);
+
+    /* Set SMC base address and force map with COR bit 1 */
+    writeb(ioaddr & 0xff,        smc->base + MOT_LAN + CISREG_IOBASE_0);
+    writeb((ioaddr >> 8) & 0xff, smc->base + MOT_LAN + CISREG_IOBASE_1);
+    writeb(MOT_NORMAL,           smc->base + MOT_LAN + CISREG_COR);
+
+    /* Wait for things to settle down */
+    mdelay(100);
+}
+
+static int mot_setup(struct pcmcia_device *link)
+{
+    struct net_device *dev = link->priv;
+    unsigned int ioaddr = dev->base_addr;
+    int i, wait, loop;
+    u_int addr;
+
+    /* Read Ethernet address from Serial EEPROM */
+
+    for (i = 0; i < 3; i++) {
+       SMC_SELECT_BANK(2);
+       outw(MOT_EEPROM + i, ioaddr + POINTER);
+       SMC_SELECT_BANK(1);
+       outw((CTL_RELOAD | CTL_EE_SELECT), ioaddr + CONTROL);
+
+       for (loop = wait = 0; loop < 200; loop++) {
+           udelay(10);
+           wait = ((CTL_RELOAD | CTL_STORE) & inw(ioaddr + CONTROL));
+           if (wait == 0) break;
+       }
+       
+       if (wait)
+           return -1;
+       
+       addr = inw(ioaddr + GENERAL);
+       dev->dev_addr[2*i]   = addr & 0xff;
+       dev->dev_addr[2*i+1] = (addr >> 8) & 0xff;
+    }
+
+    return 0;
+}
+
+/*====================================================================*/
+
+static int smc_configcheck(struct pcmcia_device *p_dev, void *priv_data)
+{
+       p_dev->resource[0]->end = 16;
+       p_dev->resource[0]->flags &= ~IO_DATA_PATH_WIDTH;
+       p_dev->resource[0]->flags |= IO_DATA_PATH_WIDTH_AUTO;
+
+       return pcmcia_request_io(p_dev);
+}
+
+static int smc_config(struct pcmcia_device *link)
+{
+    struct net_device *dev = link->priv;
+    int i;
+
+    link->config_flags |= CONF_ENABLE_IRQ | CONF_AUTO_SET_IO;
+
+    i = pcmcia_loop_config(link, smc_configcheck, NULL);
+    if (!i)
+           dev->base_addr = link->resource[0]->start;
+
+    return i;
+}
+
+
+static int smc_setup(struct pcmcia_device *link)
+{
+    struct net_device *dev = link->priv;
+
+    /* Check for a LAN function extension tuple */
+    if (!pcmcia_get_mac_from_cis(link, dev))
+           return 0;
+
+    /* Try the third string in the Version 1 Version/ID tuple. */
+    if (link->prod_id[2]) {
+           if (cvt_ascii_address(dev, link->prod_id[2]) == 0)
+                   return 0;
+    }
+    return -1;
+}
+
+/*====================================================================*/
+
+static int osi_config(struct pcmcia_device *link)
+{
+    struct net_device *dev = link->priv;
+    static const unsigned int com[4] = { 0x3f8, 0x2f8, 0x3e8, 0x2e8 };
+    int i, j;
+
+    link->config_flags |= CONF_ENABLE_SPKR | CONF_ENABLE_IRQ;
+    link->resource[0]->end = 64;
+    link->resource[1]->flags |= IO_DATA_PATH_WIDTH_8;
+    link->resource[1]->end = 8;
+
+    /* Enable Hard Decode, LAN, Modem */
+    link->io_lines = 16;
+    link->config_index = 0x23;
+
+    for (i = j = 0; j < 4; j++) {
+       link->resource[1]->start = com[j];
+       i = pcmcia_request_io(link);
+       if (i == 0)
+               break;
+    }
+    if (i != 0) {
+       /* Fallback: turn off hard decode */
+       link->config_index = 0x03;
+       link->resource[1]->end = 0;
+       i = pcmcia_request_io(link);
+    }
+    dev->base_addr = link->resource[0]->start + 0x10;
+    return i;
+}
+
+static int osi_load_firmware(struct pcmcia_device *link)
+{
+       const struct firmware *fw;
+       int i, err;
+
+       err = request_firmware(&fw, FIRMWARE_NAME, &link->dev);
+       if (err) {
+               pr_err("Failed to load firmware \"%s\"\n", FIRMWARE_NAME);
+               return err;
+       }
+
+       /* Download the Seven of Diamonds firmware */
+       for (i = 0; i < fw->size; i++) {
+           outb(fw->data[i], link->resource[0]->start + 2);
+           udelay(50);
+       }
+       release_firmware(fw);
+       return err;
+}
+
+static int pcmcia_osi_mac(struct pcmcia_device *p_dev,
+                         tuple_t *tuple,
+                         void *priv)
+{
+       struct net_device *dev = priv;
+       int i;
+
+       if (tuple->TupleDataLen < 8)
+               return -EINVAL;
+       if (tuple->TupleData[0] != 0x04)
+               return -EINVAL;
+       for (i = 0; i < 6; i++)
+               dev->dev_addr[i] = tuple->TupleData[i+2];
+       return 0;
+};
+
+
+static int osi_setup(struct pcmcia_device *link, u_short manfid, u_short cardid)
+{
+    struct net_device *dev = link->priv;
+    int rc;
+
+    /* Read the station address from tuple 0x90, subtuple 0x04 */
+    if (pcmcia_loop_tuple(link, 0x90, pcmcia_osi_mac, dev))
+           return -1;
+
+    if (((manfid == MANFID_OSITECH) &&
+        (cardid == PRODID_OSITECH_SEVEN)) ||
+       ((manfid == MANFID_PSION) &&
+        (cardid == PRODID_PSION_NET100))) {
+       rc = osi_load_firmware(link);
+       if (rc)
+               return rc;
+    } else if (manfid == MANFID_OSITECH) {
+       /* Make sure both functions are powered up */
+       set_bits(0x300, link->resource[0]->start + OSITECH_AUI_PWR);
+       /* Now, turn on the interrupt for both card functions */
+       set_bits(0x300, link->resource[0]->start + OSITECH_RESET_ISR);
+       dev_dbg(&link->dev, "AUI/PWR: %4.4x RESET/ISR: %4.4x\n",
+             inw(link->resource[0]->start + OSITECH_AUI_PWR),
+             inw(link->resource[0]->start + OSITECH_RESET_ISR));
+    }
+    return 0;
+}
+
+static int smc91c92_suspend(struct pcmcia_device *link)
+{
+       struct net_device *dev = link->priv;
+
+       if (link->open)
+               netif_device_detach(dev);
+
+       return 0;
+}
+
+static int smc91c92_resume(struct pcmcia_device *link)
+{
+       struct net_device *dev = link->priv;
+       struct smc_private *smc = netdev_priv(dev);
+       int i;
+
+       if ((smc->manfid == MANFID_MEGAHERTZ) &&
+           (smc->cardid == PRODID_MEGAHERTZ_EM3288))
+               mhz_3288_power(link);
+       if (smc->manfid == MANFID_MOTOROLA)
+               mot_config(link);
+       if ((smc->manfid == MANFID_OSITECH) &&
+           (smc->cardid != PRODID_OSITECH_SEVEN)) {
+               /* Power up the card and enable interrupts */
+               set_bits(0x0300, dev->base_addr-0x10+OSITECH_AUI_PWR);
+               set_bits(0x0300, dev->base_addr-0x10+OSITECH_RESET_ISR);
+       }
+       if (((smc->manfid == MANFID_OSITECH) &&
+            (smc->cardid == PRODID_OSITECH_SEVEN)) ||
+           ((smc->manfid == MANFID_PSION) &&
+            (smc->cardid == PRODID_PSION_NET100))) {
+               i = osi_load_firmware(link);
+               if (i) {
+                       pr_err("smc91c92_cs: Failed to load firmware\n");
+                       return i;
+               }
+       }
+       if (link->open) {
+               smc_reset(dev);
+               netif_device_attach(dev);
+       }
+
+       return 0;
+}
+
+
+/*======================================================================
+
+    This verifies that the chip is some SMC91cXX variant, and returns
+    the revision code if successful.  Otherwise, it returns -ENODEV.
+
+======================================================================*/
+
+static int check_sig(struct pcmcia_device *link)
+{
+    struct net_device *dev = link->priv;
+    unsigned int ioaddr = dev->base_addr;
+    int width;
+    u_short s;
+
+    SMC_SELECT_BANK(1);
+    if (inw(ioaddr + BANK_SELECT) >> 8 != 0x33) {
+       /* Try powering up the chip */
+       outw(0, ioaddr + CONTROL);
+       mdelay(55);
+    }
+
+    /* Try setting bus width */
+    width = (link->resource[0]->flags == IO_DATA_PATH_WIDTH_AUTO);
+    s = inb(ioaddr + CONFIG);
+    if (width)
+       s |= CFG_16BIT;
+    else
+       s &= ~CFG_16BIT;
+    outb(s, ioaddr + CONFIG);
+
+    /* Check Base Address Register to make sure bus width is OK */
+    s = inw(ioaddr + BASE_ADDR);
+    if ((inw(ioaddr + BANK_SELECT) >> 8 == 0x33) &&
+       ((s >> 8) != (s & 0xff))) {
+       SMC_SELECT_BANK(3);
+       s = inw(ioaddr + REVISION);
+       return s & 0xff;
+    }
+
+    if (width) {
+           pr_info("using 8-bit IO window\n");
+
+           smc91c92_suspend(link);
+           pcmcia_fixup_iowidth(link);
+           smc91c92_resume(link);
+           return check_sig(link);
+    }
+    return -ENODEV;
+}
+
+static int smc91c92_config(struct pcmcia_device *link)
+{
+    struct net_device *dev = link->priv;
+    struct smc_private *smc = netdev_priv(dev);
+    char *name;
+    int i, rev, j = 0;
+    unsigned int ioaddr;
+    u_long mir;
+
+    dev_dbg(&link->dev, "smc91c92_config\n");
+
+    smc->manfid = link->manf_id;
+    smc->cardid = link->card_id;
+
+    if ((smc->manfid == MANFID_OSITECH) &&
+       (smc->cardid != PRODID_OSITECH_SEVEN)) {
+       i = osi_config(link);
+    } else if ((smc->manfid == MANFID_MOTOROLA) ||
+              ((smc->manfid == MANFID_MEGAHERTZ) &&
+               ((smc->cardid == PRODID_MEGAHERTZ_VARIOUS) ||
+                (smc->cardid == PRODID_MEGAHERTZ_EM3288)))) {
+       i = mhz_mfc_config(link);
+    } else {
+       i = smc_config(link);
+    }
+    if (i)
+           goto config_failed;
+
+    i = pcmcia_request_irq(link, smc_interrupt);
+    if (i)
+           goto config_failed;
+    i = pcmcia_enable_device(link);
+    if (i)
+           goto config_failed;
+
+    if (smc->manfid == MANFID_MOTOROLA)
+       mot_config(link);
+
+    dev->irq = link->irq;
+
+    if ((if_port >= 0) && (if_port <= 2))
+       dev->if_port = if_port;
+    else
+       dev_notice(&link->dev, "invalid if_port requested\n");
+
+    switch (smc->manfid) {
+    case MANFID_OSITECH:
+    case MANFID_PSION:
+       i = osi_setup(link, smc->manfid, smc->cardid); break;
+    case MANFID_SMC:
+    case MANFID_NEW_MEDIA:
+       i = smc_setup(link); break;
+    case 0x128: /* For broken Megahertz cards */
+    case MANFID_MEGAHERTZ:
+       i = mhz_setup(link); break;
+    case MANFID_MOTOROLA:
+    default: /* get the hw address from EEPROM */
+       i = mot_setup(link); break;
+    }
+
+    if (i != 0) {
+       dev_notice(&link->dev, "Unable to find hardware address.\n");
+       goto config_failed;
+    }
+
+    smc->duplex = 0;
+    smc->rx_ovrn = 0;
+
+    rev = check_sig(link);
+    name = "???";
+    if (rev > 0)
+       switch (rev >> 4) {
+       case 3: name = "92"; break;
+       case 4: name = ((rev & 15) >= 6) ? "96" : "94"; break;
+       case 5: name = "95"; break;
+       case 7: name = "100"; break;
+       case 8: name = "100-FD"; break;
+       case 9: name = "110"; break;
+       }
+
+    ioaddr = dev->base_addr;
+    if (rev > 0) {
+       u_long mcr;
+       SMC_SELECT_BANK(0);
+       mir = inw(ioaddr + MEMINFO) & 0xff;
+       if (mir == 0xff) mir++;
+       /* Get scale factor for memory size */
+       mcr = ((rev >> 4) > 3) ? inw(ioaddr + MEMCFG) : 0x0200;
+       mir *= 128 * (1<<((mcr >> 9) & 7));
+       SMC_SELECT_BANK(1);
+       smc->cfg = inw(ioaddr + CONFIG) & ~CFG_AUI_SELECT;
+       smc->cfg |= CFG_NO_WAIT | CFG_16BIT | CFG_STATIC;
+       if (smc->manfid == MANFID_OSITECH)
+           smc->cfg |= CFG_IRQ_SEL_1 | CFG_IRQ_SEL_0;
+       if ((rev >> 4) >= 7)
+           smc->cfg |= CFG_MII_SELECT;
+    } else
+       mir = 0;
+
+    if (smc->cfg & CFG_MII_SELECT) {
+       SMC_SELECT_BANK(3);
+
+       for (i = 0; i < 32; i++) {
+           j = mdio_read(dev, i, 1);
+           if ((j != 0) && (j != 0xffff)) break;
+       }
+       smc->mii_if.phy_id = (i < 32) ? i : -1;
+
+       SMC_SELECT_BANK(0);
+    }
+
+    SET_NETDEV_DEV(dev, &link->dev);
+
+    if (register_netdev(dev) != 0) {
+       dev_err(&link->dev, "register_netdev() failed\n");
+       goto config_undo;
+    }
+
+    netdev_info(dev, "smc91c%s rev %d: io %#3lx, irq %d, hw_addr %pM\n",
+               name, (rev & 0x0f), dev->base_addr, dev->irq, dev->dev_addr);
+
+    if (rev > 0) {
+       if (mir & 0x3ff)
+           netdev_info(dev, "  %lu byte", mir);
+       else
+           netdev_info(dev, "  %lu kb", mir>>10);
+       pr_cont(" buffer, %s xcvr\n",
+               (smc->cfg & CFG_MII_SELECT) ? "MII" : if_names[dev->if_port]);
+    }
+
+    if (smc->cfg & CFG_MII_SELECT) {
+       if (smc->mii_if.phy_id != -1) {
+           netdev_dbg(dev, "  MII transceiver at index %d, status %x\n",
+                      smc->mii_if.phy_id, j);
+       } else {
+           netdev_notice(dev, "  No MII transceivers found!\n");
+       }
+    }
+    return 0;
+
+config_undo:
+    unregister_netdev(dev);
+config_failed:
+    smc91c92_release(link);
+    free_netdev(dev);
+    return -ENODEV;
+} /* smc91c92_config */
+
+static void smc91c92_release(struct pcmcia_device *link)
+{
+       dev_dbg(&link->dev, "smc91c92_release\n");
+       if (link->resource[2]->end) {
+               struct net_device *dev = link->priv;
+               struct smc_private *smc = netdev_priv(dev);
+               iounmap(smc->base);
+       }
+       pcmcia_disable_device(link);
+}
+
+/*======================================================================
+
+    MII interface support for SMC91cXX based cards
+======================================================================*/
+
+#define MDIO_SHIFT_CLK         0x04
+#define MDIO_DATA_OUT          0x01
+#define MDIO_DIR_WRITE         0x08
+#define MDIO_DATA_WRITE0       (MDIO_DIR_WRITE)
+#define MDIO_DATA_WRITE1       (MDIO_DIR_WRITE | MDIO_DATA_OUT)
+#define MDIO_DATA_READ         0x02
+
+static void mdio_sync(unsigned int addr)
+{
+    int bits;
+    for (bits = 0; bits < 32; bits++) {
+       outb(MDIO_DATA_WRITE1, addr);
+       outb(MDIO_DATA_WRITE1 | MDIO_SHIFT_CLK, addr);
+    }
+}
+
+static int mdio_read(struct net_device *dev, int phy_id, int loc)
+{
+    unsigned int addr = dev->base_addr + MGMT;
+    u_int cmd = (0x06<<10)|(phy_id<<5)|loc;
+    int i, retval = 0;
+
+    mdio_sync(addr);
+    for (i = 13; i >= 0; i--) {
+       int dat = (cmd&(1<<i)) ? MDIO_DATA_WRITE1 : MDIO_DATA_WRITE0;
+       outb(dat, addr);
+       outb(dat | MDIO_SHIFT_CLK, addr);
+    }
+    for (i = 19; i > 0; i--) {
+       outb(0, addr);
+       retval = (retval << 1) | ((inb(addr) & MDIO_DATA_READ) != 0);
+       outb(MDIO_SHIFT_CLK, addr);
+    }
+    return (retval>>1) & 0xffff;
+}
+
+static void mdio_write(struct net_device *dev, int phy_id, int loc, int value)
+{
+    unsigned int addr = dev->base_addr + MGMT;
+    u_int cmd = (0x05<<28)|(phy_id<<23)|(loc<<18)|(1<<17)|value;
+    int i;
+
+    mdio_sync(addr);
+    for (i = 31; i >= 0; i--) {
+       int dat = (cmd&(1<<i)) ? MDIO_DATA_WRITE1 : MDIO_DATA_WRITE0;
+       outb(dat, addr);
+       outb(dat | MDIO_SHIFT_CLK, addr);
+    }
+    for (i = 1; i >= 0; i--) {
+       outb(0, addr);
+       outb(MDIO_SHIFT_CLK, addr);
+    }
+}
+
+/*======================================================================
+
+    The driver core code, most of which should be common with a
+    non-PCMCIA implementation.
+
+======================================================================*/
+
+#ifdef PCMCIA_DEBUG
+static void smc_dump(struct net_device *dev)
+{
+    unsigned int ioaddr = dev->base_addr;
+    u_short i, w, save;
+    save = inw(ioaddr + BANK_SELECT);
+    for (w = 0; w < 4; w++) {
+       SMC_SELECT_BANK(w);
+       netdev_printk(KERN_DEBUG, dev, "bank %d: ", w);
+       for (i = 0; i < 14; i += 2)
+           pr_cont(" %04x", inw(ioaddr + i));
+       pr_cont("\n");
+    }
+    outw(save, ioaddr + BANK_SELECT);
+}
+#endif
+
+static int smc_open(struct net_device *dev)
+{
+    struct smc_private *smc = netdev_priv(dev);
+    struct pcmcia_device *link = smc->p_dev;
+
+    dev_dbg(&link->dev, "%s: smc_open(%p), ID/Window %4.4x.\n",
+         dev->name, dev, inw(dev->base_addr + BANK_SELECT));
+#ifdef PCMCIA_DEBUG
+    smc_dump(dev);
+#endif
+
+    /* Check that the PCMCIA card is still here. */
+    if (!pcmcia_dev_present(link))
+       return -ENODEV;
+    /* Physical device present signature. */
+    if (check_sig(link) < 0) {
+       netdev_info(dev, "Yikes!  Bad chip signature!\n");
+       return -ENODEV;
+    }
+    link->open++;
+
+    netif_start_queue(dev);
+    smc->saved_skb = NULL;
+    smc->packets_waiting = 0;
+
+    smc_reset(dev);
+    init_timer(&smc->media);
+    smc->media.function = media_check;
+    smc->media.data = (u_long) dev;
+    smc->media.expires = jiffies + HZ;
+    add_timer(&smc->media);
+
+    return 0;
+} /* smc_open */
+
+/*====================================================================*/
+
+static int smc_close(struct net_device *dev)
+{
+    struct smc_private *smc = netdev_priv(dev);
+    struct pcmcia_device *link = smc->p_dev;
+    unsigned int ioaddr = dev->base_addr;
+
+    dev_dbg(&link->dev, "%s: smc_close(), status %4.4x.\n",
+         dev->name, inw(ioaddr + BANK_SELECT));
+
+    netif_stop_queue(dev);
+
+    /* Shut off all interrupts, and turn off the Tx and Rx sections.
+       Don't bother to check for chip present. */
+    SMC_SELECT_BANK(2);        /* Nominally paranoia, but do no assume... */
+    outw(0, ioaddr + INTERRUPT);
+    SMC_SELECT_BANK(0);
+    mask_bits(0xff00, ioaddr + RCR);
+    mask_bits(0xff00, ioaddr + TCR);
+
+    /* Put the chip into power-down mode. */
+    SMC_SELECT_BANK(1);
+    outw(CTL_POWERDOWN, ioaddr + CONTROL );
+
+    link->open--;
+    del_timer_sync(&smc->media);
+
+    return 0;
+} /* smc_close */
+
+/*======================================================================
+
+   Transfer a packet to the hardware and trigger the packet send.
+   This may be called at either from either the Tx queue code
+   or the interrupt handler.
+
+======================================================================*/
+
+static void smc_hardware_send_packet(struct net_device * dev)
+{
+    struct smc_private *smc = netdev_priv(dev);
+    struct sk_buff *skb = smc->saved_skb;
+    unsigned int ioaddr = dev->base_addr;
+    u_char packet_no;
+
+    if (!skb) {
+       netdev_err(dev, "In XMIT with no packet to send\n");
+       return;
+    }
+
+    /* There should be a packet slot waiting. */
+    packet_no = inw(ioaddr + PNR_ARR) >> 8;
+    if (packet_no & 0x80) {
+       /* If not, there is a hardware problem!  Likely an ejected card. */
+       netdev_warn(dev, "hardware Tx buffer allocation failed, status %#2.2x\n",
+                   packet_no);
+       dev_kfree_skb_irq(skb);
+       smc->saved_skb = NULL;
+       netif_start_queue(dev);
+       return;
+    }
+
+    dev->stats.tx_bytes += skb->len;
+    /* The card should use the just-allocated buffer. */
+    outw(packet_no, ioaddr + PNR_ARR);
+    /* point to the beginning of the packet */
+    outw(PTR_AUTOINC , ioaddr + POINTER);
+
+    /* Send the packet length (+6 for status, length and ctl byte)
+       and the status word (set to zeros). */
+    {
+       u_char *buf = skb->data;
+       u_int length = skb->len; /* The chip will pad to ethernet min. */
+
+       netdev_dbg(dev, "Trying to xmit packet of length %d\n", length);
+       
+       /* send the packet length: +6 for status word, length, and ctl */
+       outw(0, ioaddr + DATA_1);
+       outw(length + 6, ioaddr + DATA_1);
+       outsw(ioaddr + DATA_1, buf, length >> 1);
+       
+       /* The odd last byte, if there is one, goes in the control word. */
+       outw((length & 1) ? 0x2000 | buf[length-1] : 0, ioaddr + DATA_1);
+    }
+
+    /* Enable the Tx interrupts, both Tx (TxErr) and TxEmpty. */
+    outw(((IM_TX_INT|IM_TX_EMPTY_INT)<<8) |
+        (inw(ioaddr + INTERRUPT) & 0xff00),
+        ioaddr + INTERRUPT);
+
+    /* The chip does the rest of the work. */
+    outw(MC_ENQUEUE , ioaddr + MMU_CMD);
+
+    smc->saved_skb = NULL;
+    dev_kfree_skb_irq(skb);
+    dev->trans_start = jiffies;
+    netif_start_queue(dev);
+}
+
+/*====================================================================*/
+
+static void smc_tx_timeout(struct net_device *dev)
+{
+    struct smc_private *smc = netdev_priv(dev);
+    unsigned int ioaddr = dev->base_addr;
+
+    netdev_notice(dev, "transmit timed out, Tx_status %2.2x status %4.4x.\n",
+                 inw(ioaddr)&0xff, inw(ioaddr + 2));
+    dev->stats.tx_errors++;
+    smc_reset(dev);
+    dev->trans_start = jiffies; /* prevent tx timeout */
+    smc->saved_skb = NULL;
+    netif_wake_queue(dev);
+}
+
+static netdev_tx_t smc_start_xmit(struct sk_buff *skb,
+                                       struct net_device *dev)
+{
+    struct smc_private *smc = netdev_priv(dev);
+    unsigned int ioaddr = dev->base_addr;
+    u_short num_pages;
+    short time_out, ir;
+    unsigned long flags;
+
+    netif_stop_queue(dev);
+
+    netdev_dbg(dev, "smc_start_xmit(length = %d) called, status %04x\n",
+              skb->len, inw(ioaddr + 2));
+
+    if (smc->saved_skb) {
+       /* THIS SHOULD NEVER HAPPEN. */
+       dev->stats.tx_aborted_errors++;
+       netdev_printk(KERN_DEBUG, dev,
+                     "Internal error -- sent packet while busy\n");
+       return NETDEV_TX_BUSY;
+    }
+    smc->saved_skb = skb;
+
+    num_pages = skb->len >> 8;
+
+    if (num_pages > 7) {
+       netdev_err(dev, "Far too big packet error: %d pages\n", num_pages);
+       dev_kfree_skb (skb);
+       smc->saved_skb = NULL;
+       dev->stats.tx_dropped++;
+       return NETDEV_TX_OK;            /* Do not re-queue this packet. */
+    }
+    /* A packet is now waiting. */
+    smc->packets_waiting++;
+
+    spin_lock_irqsave(&smc->lock, flags);
+    SMC_SELECT_BANK(2);        /* Paranoia, we should always be in window 2 */
+
+    /* need MC_RESET to keep the memory consistent. errata? */
+    if (smc->rx_ovrn) {
+       outw(MC_RESET, ioaddr + MMU_CMD);
+       smc->rx_ovrn = 0;
+    }
+
+    /* Allocate the memory; send the packet now if we win. */
+    outw(MC_ALLOC | num_pages, ioaddr + MMU_CMD);
+    for (time_out = MEMORY_WAIT_TIME; time_out >= 0; time_out--) {
+       ir = inw(ioaddr+INTERRUPT);
+       if (ir & IM_ALLOC_INT) {
+           /* Acknowledge the interrupt, send the packet. */
+           outw((ir&0xff00) | IM_ALLOC_INT, ioaddr + INTERRUPT);
+           smc_hardware_send_packet(dev);      /* Send the packet now.. */
+           spin_unlock_irqrestore(&smc->lock, flags);
+           return NETDEV_TX_OK;
+       }
+    }
+
+    /* Otherwise defer until the Tx-space-allocated interrupt. */
+    pr_debug("%s: memory allocation deferred.\n", dev->name);
+    outw((IM_ALLOC_INT << 8) | (ir & 0xff00), ioaddr + INTERRUPT);
+    spin_unlock_irqrestore(&smc->lock, flags);
+
+    return NETDEV_TX_OK;
+}
+
+/*======================================================================
+
+    Handle a Tx anomalous event.  Entered while in Window 2.
+
+======================================================================*/
+
+static void smc_tx_err(struct net_device * dev)
+{
+    struct smc_private *smc = netdev_priv(dev);
+    unsigned int ioaddr = dev->base_addr;
+    int saved_packet = inw(ioaddr + PNR_ARR) & 0xff;
+    int packet_no = inw(ioaddr + FIFO_PORTS) & 0x7f;
+    int tx_status;
+
+    /* select this as the packet to read from */
+    outw(packet_no, ioaddr + PNR_ARR);
+
+    /* read the first word from this packet */
+    outw(PTR_AUTOINC | PTR_READ | 0, ioaddr + POINTER);
+
+    tx_status = inw(ioaddr + DATA_1);
+
+    dev->stats.tx_errors++;
+    if (tx_status & TS_LOSTCAR) dev->stats.tx_carrier_errors++;
+    if (tx_status & TS_LATCOL)  dev->stats.tx_window_errors++;
+    if (tx_status & TS_16COL) {
+       dev->stats.tx_aborted_errors++;
+       smc->tx_err++;
+    }
+
+    if (tx_status & TS_SUCCESS) {
+       netdev_notice(dev, "Successful packet caused error interrupt?\n");
+    }
+    /* re-enable transmit */
+    SMC_SELECT_BANK(0);
+    outw(inw(ioaddr + TCR) | TCR_ENABLE | smc->duplex, ioaddr + TCR);
+    SMC_SELECT_BANK(2);
+
+    outw(MC_FREEPKT, ioaddr + MMU_CMD);        /* Free the packet memory. */
+
+    /* one less packet waiting for me */
+    smc->packets_waiting--;
+
+    outw(saved_packet, ioaddr + PNR_ARR);
+}
+
+/*====================================================================*/
+
+static void smc_eph_irq(struct net_device *dev)
+{
+    struct smc_private *smc = netdev_priv(dev);
+    unsigned int ioaddr = dev->base_addr;
+    u_short card_stats, ephs;
+
+    SMC_SELECT_BANK(0);
+    ephs = inw(ioaddr + EPH);
+    pr_debug("%s: Ethernet protocol handler interrupt, status"
+         " %4.4x.\n", dev->name, ephs);
+    /* Could be a counter roll-over warning: update stats. */
+    card_stats = inw(ioaddr + COUNTER);
+    /* single collisions */
+    dev->stats.collisions += card_stats & 0xF;
+    card_stats >>= 4;
+    /* multiple collisions */
+    dev->stats.collisions += card_stats & 0xF;
+#if 0          /* These are for when linux supports these statistics */
+    card_stats >>= 4;                  /* deferred */
+    card_stats >>= 4;                  /* excess deferred */
+#endif
+    /* If we had a transmit error we must re-enable the transmitter. */
+    outw(inw(ioaddr + TCR) | TCR_ENABLE | smc->duplex, ioaddr + TCR);
+
+    /* Clear a link error interrupt. */
+    SMC_SELECT_BANK(1);
+    outw(CTL_AUTO_RELEASE | 0x0000, ioaddr + CONTROL);
+    outw(CTL_AUTO_RELEASE | CTL_TE_ENABLE | CTL_CR_ENABLE,
+        ioaddr + CONTROL);
+    SMC_SELECT_BANK(2);
+}
+
+/*====================================================================*/
+
+static irqreturn_t smc_interrupt(int irq, void *dev_id)
+{
+    struct net_device *dev = dev_id;
+    struct smc_private *smc = netdev_priv(dev);
+    unsigned int ioaddr;
+    u_short saved_bank, saved_pointer, mask, status;
+    unsigned int handled = 1;
+    char bogus_cnt = INTR_WORK;                /* Work we are willing to do. */
+
+    if (!netif_device_present(dev))
+       return IRQ_NONE;
+
+    ioaddr = dev->base_addr;
+
+    pr_debug("%s: SMC91c92 interrupt %d at %#x.\n", dev->name,
+         irq, ioaddr);
+
+    spin_lock(&smc->lock);
+    smc->watchdog = 0;
+    saved_bank = inw(ioaddr + BANK_SELECT);
+    if ((saved_bank & 0xff00) != 0x3300) {
+       /* The device does not exist -- the card could be off-line, or
+          maybe it has been ejected. */
+       pr_debug("%s: SMC91c92 interrupt %d for non-existent"
+             "/ejected device.\n", dev->name, irq);
+       handled = 0;
+       goto irq_done;
+    }
+
+    SMC_SELECT_BANK(2);
+    saved_pointer = inw(ioaddr + POINTER);
+    mask = inw(ioaddr + INTERRUPT) >> 8;
+    /* clear all interrupts */
+    outw(0, ioaddr + INTERRUPT);
+
+    do { /* read the status flag, and mask it */
+       status = inw(ioaddr + INTERRUPT) & 0xff;
+       pr_debug("%s: Status is %#2.2x (mask %#2.2x).\n", dev->name,
+             status, mask);
+       if ((status & mask) == 0) {
+           if (bogus_cnt == INTR_WORK)
+               handled = 0;
+           break;
+       }
+       if (status & IM_RCV_INT) {
+           /* Got a packet(s). */
+           smc_rx(dev);
+       }
+       if (status & IM_TX_INT) {
+           smc_tx_err(dev);
+           outw(IM_TX_INT, ioaddr + INTERRUPT);
+       }
+       status &= mask;
+       if (status & IM_TX_EMPTY_INT) {
+           outw(IM_TX_EMPTY_INT, ioaddr + INTERRUPT);
+           mask &= ~IM_TX_EMPTY_INT;
+           dev->stats.tx_packets += smc->packets_waiting;
+           smc->packets_waiting = 0;
+       }
+       if (status & IM_ALLOC_INT) {
+           /* Clear this interrupt so it doesn't happen again */
+           mask &= ~IM_ALLOC_INT;
+       
+           smc_hardware_send_packet(dev);
+       
+           /* enable xmit interrupts based on this */
+           mask |= (IM_TX_EMPTY_INT | IM_TX_INT);
+       
+           /* and let the card send more packets to me */
+           netif_wake_queue(dev);
+       }
+       if (status & IM_RX_OVRN_INT) {
+           dev->stats.rx_errors++;
+           dev->stats.rx_fifo_errors++;
+           if (smc->duplex)
+               smc->rx_ovrn = 1; /* need MC_RESET outside smc_interrupt */
+           outw(IM_RX_OVRN_INT, ioaddr + INTERRUPT);
+       }
+       if (status & IM_EPH_INT)
+           smc_eph_irq(dev);
+    } while (--bogus_cnt);
+
+    pr_debug("  Restoring saved registers mask %2.2x bank %4.4x"
+         " pointer %4.4x.\n", mask, saved_bank, saved_pointer);
+
+    /* restore state register */
+    outw((mask<<8), ioaddr + INTERRUPT);
+    outw(saved_pointer, ioaddr + POINTER);
+    SMC_SELECT_BANK(saved_bank);
+
+    pr_debug("%s: Exiting interrupt IRQ%d.\n", dev->name, irq);
+
+irq_done:
+
+    if ((smc->manfid == MANFID_OSITECH) &&
+       (smc->cardid != PRODID_OSITECH_SEVEN)) {
+       /* Retrigger interrupt if needed */
+       mask_bits(0x00ff, ioaddr-0x10+OSITECH_RESET_ISR);
+       set_bits(0x0300, ioaddr-0x10+OSITECH_RESET_ISR);
+    }
+    if (smc->manfid == MANFID_MOTOROLA) {
+       u_char cor;
+       cor = readb(smc->base + MOT_UART + CISREG_COR);
+       writeb(cor & ~COR_IREQ_ENA, smc->base + MOT_UART + CISREG_COR);
+       writeb(cor, smc->base + MOT_UART + CISREG_COR);
+       cor = readb(smc->base + MOT_LAN + CISREG_COR);
+       writeb(cor & ~COR_IREQ_ENA, smc->base + MOT_LAN + CISREG_COR);
+       writeb(cor, smc->base + MOT_LAN + CISREG_COR);
+    }
+
+    if ((smc->base != NULL) &&  /* Megahertz MFC's */
+       (smc->manfid == MANFID_MEGAHERTZ) &&
+       (smc->cardid == PRODID_MEGAHERTZ_EM3288)) {
+
+       u_char tmp;
+       tmp = readb(smc->base+MEGAHERTZ_ISR);
+       tmp = readb(smc->base+MEGAHERTZ_ISR);
+
+       /* Retrigger interrupt if needed */
+       writeb(tmp, smc->base + MEGAHERTZ_ISR);
+       writeb(tmp, smc->base + MEGAHERTZ_ISR);
+    }
+
+    spin_unlock(&smc->lock);
+    return IRQ_RETVAL(handled);
+}
+
+/*====================================================================*/
+
+static void smc_rx(struct net_device *dev)
+{
+    unsigned int ioaddr = dev->base_addr;
+    int rx_status;
+    int packet_length; /* Caution: not frame length, rather words
+                          to transfer from the chip. */
+
+    /* Assertion: we are in Window 2. */
+
+    if (inw(ioaddr + FIFO_PORTS) & FP_RXEMPTY) {
+       netdev_err(dev, "smc_rx() with nothing on Rx FIFO\n");
+       return;
+    }
+
+    /*  Reset the read pointer, and read the status and packet length. */
+    outw(PTR_READ | PTR_RCV | PTR_AUTOINC, ioaddr + POINTER);
+    rx_status = inw(ioaddr + DATA_1);
+    packet_length = inw(ioaddr + DATA_1) & 0x07ff;
+
+    pr_debug("%s: Receive status %4.4x length %d.\n",
+         dev->name, rx_status, packet_length);
+
+    if (!(rx_status & RS_ERRORS)) {            
+       /* do stuff to make a new packet */
+       struct sk_buff *skb;
+       
+       /* Note: packet_length adds 5 or 6 extra bytes here! */
+       skb = dev_alloc_skb(packet_length+2);
+       
+       if (skb == NULL) {
+           pr_debug("%s: Low memory, packet dropped.\n", dev->name);
+           dev->stats.rx_dropped++;
+           outw(MC_RELEASE, ioaddr + MMU_CMD);
+           return;
+       }
+       
+       packet_length -= (rx_status & RS_ODDFRAME ? 5 : 6);
+       skb_reserve(skb, 2);
+       insw(ioaddr+DATA_1, skb_put(skb, packet_length),
+            (packet_length+1)>>1);
+       skb->protocol = eth_type_trans(skb, dev);
+       
+       netif_rx(skb);
+       dev->last_rx = jiffies;
+       dev->stats.rx_packets++;
+       dev->stats.rx_bytes += packet_length;
+       if (rx_status & RS_MULTICAST)
+           dev->stats.multicast++;
+    } else {
+       /* error ... */
+       dev->stats.rx_errors++;
+       
+       if (rx_status & RS_ALGNERR)  dev->stats.rx_frame_errors++;
+       if (rx_status & (RS_TOOSHORT | RS_TOOLONG))
+           dev->stats.rx_length_errors++;
+       if (rx_status & RS_BADCRC)      dev->stats.rx_crc_errors++;
+    }
+    /* Let the MMU free the memory of this packet. */
+    outw(MC_RELEASE, ioaddr + MMU_CMD);
+}
+
+/*======================================================================
+
+    Set the receive mode.
+
+    This routine is used by both the protocol level to notify us of
+    promiscuous/multicast mode changes, and by the open/reset code to
+    initialize the Rx registers.  We always set the multicast list and
+    leave the receiver running.
+
+======================================================================*/
+
+static void set_rx_mode(struct net_device *dev)
+{
+    unsigned int ioaddr = dev->base_addr;
+    struct smc_private *smc = netdev_priv(dev);
+    unsigned char multicast_table[8];
+    unsigned long flags;
+    u_short rx_cfg_setting;
+    int i;
+
+    memset(multicast_table, 0, sizeof(multicast_table));
+
+    if (dev->flags & IFF_PROMISC) {
+       rx_cfg_setting = RxStripCRC | RxEnable | RxPromisc | RxAllMulti;
+    } else if (dev->flags & IFF_ALLMULTI)
+       rx_cfg_setting = RxStripCRC | RxEnable | RxAllMulti;
+    else {
+       if (!netdev_mc_empty(dev)) {
+           struct netdev_hw_addr *ha;
+
+           netdev_for_each_mc_addr(ha, dev) {
+               u_int position = ether_crc(6, ha->addr);
+               multicast_table[position >> 29] |= 1 << ((position >> 26) & 7);
+           }
+       }
+       rx_cfg_setting = RxStripCRC | RxEnable;
+    }
+
+    /* Load MC table and Rx setting into the chip without interrupts. */
+    spin_lock_irqsave(&smc->lock, flags);
+    SMC_SELECT_BANK(3);
+    for (i = 0; i < 8; i++)
+       outb(multicast_table[i], ioaddr + MULTICAST0 + i);
+    SMC_SELECT_BANK(0);
+    outw(rx_cfg_setting, ioaddr + RCR);
+    SMC_SELECT_BANK(2);
+    spin_unlock_irqrestore(&smc->lock, flags);
+}
+
+/*======================================================================
+
+    Senses when a card's config changes. Here, it's coax or TP.
+
+======================================================================*/
+
+static int s9k_config(struct net_device *dev, struct ifmap *map)
+{
+    struct smc_private *smc = netdev_priv(dev);
+    if ((map->port != (u_char)(-1)) && (map->port != dev->if_port)) {
+       if (smc->cfg & CFG_MII_SELECT)
+           return -EOPNOTSUPP;
+       else if (map->port > 2)
+           return -EINVAL;
+       dev->if_port = map->port;
+       netdev_info(dev, "switched to %s port\n", if_names[dev->if_port]);
+       smc_reset(dev);
+    }
+    return 0;
+}
+
+/*======================================================================
+
+    Reset the chip, reloading every register that might be corrupted.
+
+======================================================================*/
+
+/*
+  Set transceiver type, perhaps to something other than what the user
+  specified in dev->if_port.
+*/
+static void smc_set_xcvr(struct net_device *dev, int if_port)
+{
+    struct smc_private *smc = netdev_priv(dev);
+    unsigned int ioaddr = dev->base_addr;
+    u_short saved_bank;
+
+    saved_bank = inw(ioaddr + BANK_SELECT);
+    SMC_SELECT_BANK(1);
+    if (if_port == 2) {
+       outw(smc->cfg | CFG_AUI_SELECT, ioaddr + CONFIG);
+       if ((smc->manfid == MANFID_OSITECH) &&
+           (smc->cardid != PRODID_OSITECH_SEVEN))
+           set_bits(OSI_AUI_PWR, ioaddr - 0x10 + OSITECH_AUI_PWR);
+       smc->media_status = ((dev->if_port == 0) ? 0x0001 : 0x0002);
+    } else {
+       outw(smc->cfg, ioaddr + CONFIG);
+       if ((smc->manfid == MANFID_OSITECH) &&
+           (smc->cardid != PRODID_OSITECH_SEVEN))
+           mask_bits(~OSI_AUI_PWR, ioaddr - 0x10 + OSITECH_AUI_PWR);
+       smc->media_status = ((dev->if_port == 0) ? 0x0012 : 0x4001);
+    }
+    SMC_SELECT_BANK(saved_bank);
+}
+
+static void smc_reset(struct net_device *dev)
+{
+    unsigned int ioaddr = dev->base_addr;
+    struct smc_private *smc = netdev_priv(dev);
+    int i;
+
+    pr_debug("%s: smc91c92 reset called.\n", dev->name);
+
+    /* The first interaction must be a write to bring the chip out
+       of sleep mode. */
+    SMC_SELECT_BANK(0);
+    /* Reset the chip. */
+    outw(RCR_SOFTRESET, ioaddr + RCR);
+    udelay(10);
+
+    /* Clear the transmit and receive configuration registers. */
+    outw(RCR_CLEAR, ioaddr + RCR);
+    outw(TCR_CLEAR, ioaddr + TCR);
+
+    /* Set the Window 1 control, configuration and station addr registers.
+       No point in writing the I/O base register ;-> */
+    SMC_SELECT_BANK(1);
+    /* Automatically release successfully transmitted packets,
+       Accept link errors, counter and Tx error interrupts. */
+    outw(CTL_AUTO_RELEASE | CTL_TE_ENABLE | CTL_CR_ENABLE,
+        ioaddr + CONTROL);
+    smc_set_xcvr(dev, dev->if_port);
+    if ((smc->manfid == MANFID_OSITECH) &&
+       (smc->cardid != PRODID_OSITECH_SEVEN))
+       outw((dev->if_port == 2 ? OSI_AUI_PWR : 0) |
+            (inw(ioaddr-0x10+OSITECH_AUI_PWR) & 0xff00),
+            ioaddr - 0x10 + OSITECH_AUI_PWR);
+
+    /* Fill in the physical address.  The databook is wrong about the order! */
+    for (i = 0; i < 6; i += 2)
+       outw((dev->dev_addr[i+1]<<8)+dev->dev_addr[i],
+            ioaddr + ADDR0 + i);
+
+    /* Reset the MMU */
+    SMC_SELECT_BANK(2);
+    outw(MC_RESET, ioaddr + MMU_CMD);
+    outw(0, ioaddr + INTERRUPT);
+
+    /* Re-enable the chip. */
+    SMC_SELECT_BANK(0);
+    outw(((smc->cfg & CFG_MII_SELECT) ? 0 : TCR_MONCSN) |
+        TCR_ENABLE | TCR_PAD_EN | smc->duplex, ioaddr + TCR);
+    set_rx_mode(dev);
+
+    if (smc->cfg & CFG_MII_SELECT) {
+       SMC_SELECT_BANK(3);
+
+       /* Reset MII */
+       mdio_write(dev, smc->mii_if.phy_id, 0, 0x8000);
+
+       /* Advertise 100F, 100H, 10F, 10H */
+       mdio_write(dev, smc->mii_if.phy_id, 4, 0x01e1);
+
+       /* Restart MII autonegotiation */
+       mdio_write(dev, smc->mii_if.phy_id, 0, 0x0000);
+       mdio_write(dev, smc->mii_if.phy_id, 0, 0x1200);
+    }
+
+    /* Enable interrupts. */
+    SMC_SELECT_BANK(2);
+    outw((IM_EPH_INT | IM_RX_OVRN_INT | IM_RCV_INT) << 8,
+        ioaddr + INTERRUPT);
+}
+
+/*======================================================================
+
+    Media selection timer routine
+
+======================================================================*/
+
+static void media_check(u_long arg)
+{
+    struct net_device *dev = (struct net_device *) arg;
+    struct smc_private *smc = netdev_priv(dev);
+    unsigned int ioaddr = dev->base_addr;
+    u_short i, media, saved_bank;
+    u_short link;
+    unsigned long flags;
+
+    spin_lock_irqsave(&smc->lock, flags);
+
+    saved_bank = inw(ioaddr + BANK_SELECT);
+
+    if (!netif_device_present(dev))
+       goto reschedule;
+
+    SMC_SELECT_BANK(2);
+
+    /* need MC_RESET to keep the memory consistent. errata? */
+    if (smc->rx_ovrn) {
+       outw(MC_RESET, ioaddr + MMU_CMD);
+       smc->rx_ovrn = 0;
+    }
+    i = inw(ioaddr + INTERRUPT);
+    SMC_SELECT_BANK(0);
+    media = inw(ioaddr + EPH) & EPH_LINK_OK;
+    SMC_SELECT_BANK(1);
+    media |= (inw(ioaddr + CONFIG) & CFG_AUI_SELECT) ? 2 : 1;
+
+    SMC_SELECT_BANK(saved_bank);
+    spin_unlock_irqrestore(&smc->lock, flags);
+
+    /* Check for pending interrupt with watchdog flag set: with
+       this, we can limp along even if the interrupt is blocked */
+    if (smc->watchdog++ && ((i>>8) & i)) {
+       if (!smc->fast_poll)
+           netdev_info(dev, "interrupt(s) dropped!\n");
+       local_irq_save(flags);
+       smc_interrupt(dev->irq, dev);
+       local_irq_restore(flags);
+       smc->fast_poll = HZ;
+    }
+    if (smc->fast_poll) {
+       smc->fast_poll--;
+       smc->media.expires = jiffies + HZ/100;
+       add_timer(&smc->media);
+       return;
+    }
+
+    spin_lock_irqsave(&smc->lock, flags);
+
+    saved_bank = inw(ioaddr + BANK_SELECT);
+
+    if (smc->cfg & CFG_MII_SELECT) {
+       if (smc->mii_if.phy_id < 0)
+           goto reschedule;
+
+       SMC_SELECT_BANK(3);
+       link = mdio_read(dev, smc->mii_if.phy_id, 1);
+       if (!link || (link == 0xffff)) {
+           netdev_info(dev, "MII is missing!\n");
+           smc->mii_if.phy_id = -1;
+           goto reschedule;
+       }
+
+       link &= 0x0004;
+       if (link != smc->link_status) {
+           u_short p = mdio_read(dev, smc->mii_if.phy_id, 5);
+           netdev_info(dev, "%s link beat\n", link ? "found" : "lost");
+           smc->duplex = (((p & 0x0100) || ((p & 0x1c0) == 0x40))
+                          ? TCR_FDUPLX : 0);
+           if (link) {
+               netdev_info(dev, "autonegotiation complete: "
+                           "%dbaseT-%cD selected\n",
+                           (p & 0x0180) ? 100 : 10, smc->duplex ? 'F' : 'H');
+           }
+           SMC_SELECT_BANK(0);
+           outw(inw(ioaddr + TCR) | smc->duplex, ioaddr + TCR);
+           smc->link_status = link;
+       }
+       goto reschedule;
+    }
+
+    /* Ignore collisions unless we've had no rx's recently */
+    if (time_after(jiffies, dev->last_rx + HZ)) {
+       if (smc->tx_err || (smc->media_status & EPH_16COL))
+           media |= EPH_16COL;
+    }
+    smc->tx_err = 0;
+
+    if (media != smc->media_status) {
+       if ((media & smc->media_status & 1) &&
+           ((smc->media_status ^ media) & EPH_LINK_OK))
+           netdev_info(dev, "%s link beat\n",
+                       smc->media_status & EPH_LINK_OK ? "lost" : "found");
+       else if ((media & smc->media_status & 2) &&
+                ((smc->media_status ^ media) & EPH_16COL))
+           netdev_info(dev, "coax cable %s\n",
+                       media & EPH_16COL ? "problem" : "ok");
+       if (dev->if_port == 0) {
+           if (media & 1) {
+               if (media & EPH_LINK_OK)
+                   netdev_info(dev, "flipped to 10baseT\n");
+               else
+                   smc_set_xcvr(dev, 2);
+           } else {
+               if (media & EPH_16COL)
+                   smc_set_xcvr(dev, 1);
+               else
+                   netdev_info(dev, "flipped to 10base2\n");
+           }
+       }
+       smc->media_status = media;
+    }
+
+reschedule:
+    smc->media.expires = jiffies + HZ;
+    add_timer(&smc->media);
+    SMC_SELECT_BANK(saved_bank);
+    spin_unlock_irqrestore(&smc->lock, flags);
+}
+
+static int smc_link_ok(struct net_device *dev)
+{
+    unsigned int ioaddr = dev->base_addr;
+    struct smc_private *smc = netdev_priv(dev);
+
+    if (smc->cfg & CFG_MII_SELECT) {
+       return mii_link_ok(&smc->mii_if);
+    } else {
+        SMC_SELECT_BANK(0);
+       return inw(ioaddr + EPH) & EPH_LINK_OK;
+    }
+}
+
+static int smc_netdev_get_ecmd(struct net_device *dev, struct ethtool_cmd *ecmd)
+{
+    u16 tmp;
+    unsigned int ioaddr = dev->base_addr;
+
+    ecmd->supported = (SUPPORTED_TP | SUPPORTED_AUI |
+       SUPPORTED_10baseT_Half | SUPPORTED_10baseT_Full);
+               
+    SMC_SELECT_BANK(1);
+    tmp = inw(ioaddr + CONFIG);
+    ecmd->port = (tmp & CFG_AUI_SELECT) ? PORT_AUI : PORT_TP;
+    ecmd->transceiver = XCVR_INTERNAL;
+    ethtool_cmd_speed_set(ecmd, SPEED_10);
+    ecmd->phy_address = ioaddr + MGMT;
+
+    SMC_SELECT_BANK(0);
+    tmp = inw(ioaddr + TCR);
+    ecmd->duplex = (tmp & TCR_FDUPLX) ? DUPLEX_FULL : DUPLEX_HALF;
+
+    return 0;
+}
+
+static int smc_netdev_set_ecmd(struct net_device *dev, struct ethtool_cmd *ecmd)
+{
+    u16 tmp;
+    unsigned int ioaddr = dev->base_addr;
+
+    if (ethtool_cmd_speed(ecmd) != SPEED_10)
+       return -EINVAL;
+    if (ecmd->duplex != DUPLEX_HALF && ecmd->duplex != DUPLEX_FULL)
+       return -EINVAL;
+    if (ecmd->port != PORT_TP && ecmd->port != PORT_AUI)
+       return -EINVAL;
+    if (ecmd->transceiver != XCVR_INTERNAL)
+       return -EINVAL;
+
+    if (ecmd->port == PORT_AUI)
+       smc_set_xcvr(dev, 1);
+    else
+       smc_set_xcvr(dev, 0);
+
+    SMC_SELECT_BANK(0);
+    tmp = inw(ioaddr + TCR);
+    if (ecmd->duplex == DUPLEX_FULL)
+       tmp |= TCR_FDUPLX;
+    else
+       tmp &= ~TCR_FDUPLX;
+    outw(tmp, ioaddr + TCR);
+       
+    return 0;
+}
+
+static int check_if_running(struct net_device *dev)
+{
+       if (!netif_running(dev))
+               return -EINVAL;
+       return 0;
+}
+
+static void smc_get_drvinfo(struct net_device *dev, struct ethtool_drvinfo *info)
+{
+       strcpy(info->driver, DRV_NAME);
+       strcpy(info->version, DRV_VERSION);
+}
+
+static int smc_get_settings(struct net_device *dev, struct ethtool_cmd *ecmd)
+{
+       struct smc_private *smc = netdev_priv(dev);
+       unsigned int ioaddr = dev->base_addr;
+       u16 saved_bank = inw(ioaddr + BANK_SELECT);
+       int ret;
+       unsigned long flags;
+
+       spin_lock_irqsave(&smc->lock, flags);
+       SMC_SELECT_BANK(3);
+       if (smc->cfg & CFG_MII_SELECT)
+               ret = mii_ethtool_gset(&smc->mii_if, ecmd);
+       else
+               ret = smc_netdev_get_ecmd(dev, ecmd);
+       SMC_SELECT_BANK(saved_bank);
+       spin_unlock_irqrestore(&smc->lock, flags);
+       return ret;
+}
+
+static int smc_set_settings(struct net_device *dev, struct ethtool_cmd *ecmd)
+{
+       struct smc_private *smc = netdev_priv(dev);
+       unsigned int ioaddr = dev->base_addr;
+       u16 saved_bank = inw(ioaddr + BANK_SELECT);
+       int ret;
+       unsigned long flags;
+
+       spin_lock_irqsave(&smc->lock, flags);
+       SMC_SELECT_BANK(3);
+       if (smc->cfg & CFG_MII_SELECT)
+               ret = mii_ethtool_sset(&smc->mii_if, ecmd);
+       else
+               ret = smc_netdev_set_ecmd(dev, ecmd);
+       SMC_SELECT_BANK(saved_bank);
+       spin_unlock_irqrestore(&smc->lock, flags);
+       return ret;
+}
+
+static u32 smc_get_link(struct net_device *dev)
+{
+       struct smc_private *smc = netdev_priv(dev);
+       unsigned int ioaddr = dev->base_addr;
+       u16 saved_bank = inw(ioaddr + BANK_SELECT);
+       u32 ret;
+       unsigned long flags;
+
+       spin_lock_irqsave(&smc->lock, flags);
+       SMC_SELECT_BANK(3);
+       ret = smc_link_ok(dev);
+       SMC_SELECT_BANK(saved_bank);
+       spin_unlock_irqrestore(&smc->lock, flags);
+       return ret;
+}
+
+static int smc_nway_reset(struct net_device *dev)
+{
+       struct smc_private *smc = netdev_priv(dev);
+       if (smc->cfg & CFG_MII_SELECT) {
+               unsigned int ioaddr = dev->base_addr;
+               u16 saved_bank = inw(ioaddr + BANK_SELECT);
+               int res;
+
+               SMC_SELECT_BANK(3);
+               res = mii_nway_restart(&smc->mii_if);
+               SMC_SELECT_BANK(saved_bank);
+
+               return res;
+       } else
+               return -EOPNOTSUPP;
+}
+
+static const struct ethtool_ops ethtool_ops = {
+       .begin = check_if_running,
+       .get_drvinfo = smc_get_drvinfo,
+       .get_settings = smc_get_settings,
+       .set_settings = smc_set_settings,
+       .get_link = smc_get_link,
+       .nway_reset = smc_nway_reset,
+};
+
+static int smc_ioctl (struct net_device *dev, struct ifreq *rq, int cmd)
+{
+       struct smc_private *smc = netdev_priv(dev);
+       struct mii_ioctl_data *mii = if_mii(rq);
+       int rc = 0;
+       u16 saved_bank;
+       unsigned int ioaddr = dev->base_addr;
+       unsigned long flags;
+
+       if (!netif_running(dev))
+               return -EINVAL;
+
+       spin_lock_irqsave(&smc->lock, flags);
+       saved_bank = inw(ioaddr + BANK_SELECT);
+       SMC_SELECT_BANK(3);
+       rc = generic_mii_ioctl(&smc->mii_if, mii, cmd, NULL);
+       SMC_SELECT_BANK(saved_bank);
+       spin_unlock_irqrestore(&smc->lock, flags);
+       return rc;
+}
+
+static const struct pcmcia_device_id smc91c92_ids[] = {
+       PCMCIA_PFC_DEVICE_MANF_CARD(0, 0x0109, 0x0501),
+       PCMCIA_PFC_DEVICE_MANF_CARD(0, 0x0140, 0x000a),
+       PCMCIA_PFC_DEVICE_PROD_ID123(0, "MEGAHERTZ", "CC/XJEM3288", "DATA/FAX/CELL ETHERNET MODEM", 0xf510db04, 0x04cd2988, 0x46a52d63),
+       PCMCIA_PFC_DEVICE_PROD_ID123(0, "MEGAHERTZ", "CC/XJEM3336", "DATA/FAX/CELL ETHERNET MODEM", 0xf510db04, 0x0143b773, 0x46a52d63),
+       PCMCIA_PFC_DEVICE_PROD_ID123(0, "MEGAHERTZ", "EM1144T", "PCMCIA MODEM", 0xf510db04, 0x856d66c8, 0xbd6c43ef),
+       PCMCIA_PFC_DEVICE_PROD_ID123(0, "MEGAHERTZ", "XJEM1144/CCEM1144", "PCMCIA MODEM", 0xf510db04, 0x52d21e1e, 0xbd6c43ef),
+       PCMCIA_PFC_DEVICE_PROD_ID12(0, "Gateway 2000", "XJEM3336", 0xdd9989be, 0x662c394c),
+       PCMCIA_PFC_DEVICE_PROD_ID12(0, "MEGAHERTZ", "XJEM1144/CCEM1144", 0xf510db04, 0x52d21e1e),
+       PCMCIA_PFC_DEVICE_PROD_ID12(0, "Ositech", "Trumpcard:Jack of Diamonds Modem+Ethernet", 0xc2f80cd, 0x656947b9),
+       PCMCIA_PFC_DEVICE_PROD_ID12(0, "Ositech", "Trumpcard:Jack of Hearts Modem+Ethernet", 0xc2f80cd, 0xdc9ba5ed),
+       PCMCIA_MFC_DEVICE_MANF_CARD(0, 0x016c, 0x0020),
+       PCMCIA_DEVICE_MANF_CARD(0x016c, 0x0023),
+       PCMCIA_DEVICE_PROD_ID123("BASICS by New Media Corporation", "Ethernet", "SMC91C94", 0x23c78a9d, 0x00b2e941, 0xcef397fb),
+       PCMCIA_DEVICE_PROD_ID12("ARGOSY", "Fast Ethernet PCCard", 0x78f308dc, 0xdcea68bc),
+       PCMCIA_DEVICE_PROD_ID12("dit Co., Ltd.", "PC Card-10/100BTX", 0xe59365c8, 0x6a2161d1),
+       PCMCIA_DEVICE_PROD_ID12("DYNALINK", "L100C", 0x6a26d1cf, 0xc16ce9c5),
+       PCMCIA_DEVICE_PROD_ID12("Farallon", "Farallon Enet", 0x58d93fc4, 0x244734e9),
+       PCMCIA_DEVICE_PROD_ID12("Megahertz", "CC10BT/2", 0x33234748, 0x3c95b953),
+       PCMCIA_DEVICE_PROD_ID12("MELCO/SMC", "LPC-TX", 0xa2cd8e6d, 0x42da662a),
+       PCMCIA_DEVICE_PROD_ID12("Ositech", "Trumpcard:Four of Diamonds Ethernet", 0xc2f80cd, 0xb3466314),
+       PCMCIA_DEVICE_PROD_ID12("Ositech", "Trumpcard:Seven of Diamonds Ethernet", 0xc2f80cd, 0x194b650a),
+       PCMCIA_DEVICE_PROD_ID12("PCMCIA", "Fast Ethernet PCCard", 0x281f1c5d, 0xdcea68bc),
+       PCMCIA_DEVICE_PROD_ID12("Psion", "10Mb Ethernet", 0x4ef00b21, 0x844be9e9),
+       PCMCIA_DEVICE_PROD_ID12("SMC", "EtherEZ Ethernet 8020", 0xc4f8b18b, 0x4a0eeb2d),
+       /* These conflict with other cards! */
+       /* PCMCIA_DEVICE_MANF_CARD(0x0186, 0x0100), */
+       /* PCMCIA_DEVICE_MANF_CARD(0x8a01, 0xc1ab), */
+       PCMCIA_DEVICE_NULL,
+};
+MODULE_DEVICE_TABLE(pcmcia, smc91c92_ids);
+
+static struct pcmcia_driver smc91c92_cs_driver = {
+       .owner          = THIS_MODULE,
+       .name           = "smc91c92_cs",
+       .probe          = smc91c92_probe,
+       .remove         = smc91c92_detach,
+       .id_table       = smc91c92_ids,
+       .suspend        = smc91c92_suspend,
+       .resume         = smc91c92_resume,
+};
+
+static int __init init_smc91c92_cs(void)
+{
+       return pcmcia_register_driver(&smc91c92_cs_driver);
+}
+
+static void __exit exit_smc91c92_cs(void)
+{
+       pcmcia_unregister_driver(&smc91c92_cs_driver);
+}
+
+module_init(init_smc91c92_cs);
+module_exit(exit_smc91c92_cs);
diff --git a/drivers/net/ethernet/smsc/smc91x.c b/drivers/net/ethernet/smsc/smc91x.c
new file mode 100644 (file)
index 0000000..2b1d254
--- /dev/null
@@ -0,0 +1,2431 @@
+/*
+ * smc91x.c
+ * This is a driver for SMSC's 91C9x/91C1xx single-chip Ethernet devices.
+ *
+ * Copyright (C) 1996 by Erik Stahlman
+ * Copyright (C) 2001 Standard Microsystems Corporation
+ *     Developed by Simple Network Magic Corporation
+ * Copyright (C) 2003 Monta Vista Software, Inc.
+ *     Unified SMC91x driver by Nicolas Pitre
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ *
+ * Arguments:
+ *     io      = for the base address
+ *     irq     = for the IRQ
+ *     nowait  = 0 for normal wait states, 1 eliminates additional wait states
+ *
+ * original author:
+ *     Erik Stahlman <erik@vt.edu>
+ *
+ * hardware multicast code:
+ *    Peter Cammaert <pc@denkart.be>
+ *
+ * contributors:
+ *     Daris A Nevil <dnevil@snmc.com>
+ *      Nicolas Pitre <nico@fluxnic.net>
+ *     Russell King <rmk@arm.linux.org.uk>
+ *
+ * History:
+ *   08/20/00  Arnaldo Melo       fix kfree(skb) in smc_hardware_send_packet
+ *   12/15/00  Christian Jullien  fix "Warning: kfree_skb on hard IRQ"
+ *   03/16/01  Daris A Nevil      modified smc9194.c for use with LAN91C111
+ *   08/22/01  Scott Anderson     merge changes from smc9194 to smc91111
+ *   08/21/01  Pramod B Bhardwaj  added support for RevB of LAN91C111
+ *   12/20/01  Jeff Sutherland    initial port to Xscale PXA with DMA support
+ *   04/07/03  Nicolas Pitre      unified SMC91x driver, killed irq races,
+ *                                more bus abstraction, big cleanup, etc.
+ *   29/09/03  Russell King       - add driver model support
+ *                                - ethtool support
+ *                                - convert to use generic MII interface
+ *                                - add link up/down notification
+ *                                - don't try to handle full negotiation in
+ *                                  smc_phy_configure
+ *                                - clean up (and fix stack overrun) in PHY
+ *                                  MII read/write functions
+ *   22/09/04  Nicolas Pitre      big update (see commit log for details)
+ */
+static const char version[] =
+       "smc91x.c: v1.1, sep 22 2004 by Nicolas Pitre <nico@fluxnic.net>\n";
+
+/* Debugging level */
+#ifndef SMC_DEBUG
+#define SMC_DEBUG              0
+#endif
+
+
+#include <linux/init.h>
+#include <linux/module.h>
+#include <linux/kernel.h>
+#include <linux/sched.h>
+#include <linux/delay.h>
+#include <linux/interrupt.h>
+#include <linux/irq.h>
+#include <linux/errno.h>
+#include <linux/ioport.h>
+#include <linux/crc32.h>
+#include <linux/platform_device.h>
+#include <linux/spinlock.h>
+#include <linux/ethtool.h>
+#include <linux/mii.h>
+#include <linux/workqueue.h>
+#include <linux/of.h>
+
+#include <linux/netdevice.h>
+#include <linux/etherdevice.h>
+#include <linux/skbuff.h>
+
+#include <asm/io.h>
+
+#include "smc91x.h"
+
+#ifndef SMC_NOWAIT
+# define SMC_NOWAIT            0
+#endif
+static int nowait = SMC_NOWAIT;
+module_param(nowait, int, 0400);
+MODULE_PARM_DESC(nowait, "set to 1 for no wait state");
+
+/*
+ * Transmit timeout, default 5 seconds.
+ */
+static int watchdog = 1000;
+module_param(watchdog, int, 0400);
+MODULE_PARM_DESC(watchdog, "transmit timeout in milliseconds");
+
+MODULE_LICENSE("GPL");
+MODULE_ALIAS("platform:smc91x");
+
+/*
+ * The internal workings of the driver.  If you are changing anything
+ * here with the SMC stuff, you should have the datasheet and know
+ * what you are doing.
+ */
+#define CARDNAME "smc91x"
+
+/*
+ * Use power-down feature of the chip
+ */
+#define POWER_DOWN             1
+
+/*
+ * Wait time for memory to be free.  This probably shouldn't be
+ * tuned that much, as waiting for this means nothing else happens
+ * in the system
+ */
+#define MEMORY_WAIT_TIME       16
+
+/*
+ * The maximum number of processing loops allowed for each call to the
+ * IRQ handler.
+ */
+#define MAX_IRQ_LOOPS          8
+
+/*
+ * This selects whether TX packets are sent one by one to the SMC91x internal
+ * memory and throttled until transmission completes.  This may prevent
+ * RX overruns a litle by keeping much of the memory free for RX packets
+ * but to the expense of reduced TX throughput and increased IRQ overhead.
+ * Note this is not a cure for a too slow data bus or too high IRQ latency.
+ */
+#define THROTTLE_TX_PKTS       0
+
+/*
+ * The MII clock high/low times.  2x this number gives the MII clock period
+ * in microseconds. (was 50, but this gives 6.4ms for each MII transaction!)
+ */
+#define MII_DELAY              1
+
+#if SMC_DEBUG > 0
+#define DBG(n, args...)                                        \
+       do {                                            \
+               if (SMC_DEBUG >= (n))                   \
+                       printk(args);   \
+       } while (0)
+
+#define PRINTK(args...)   printk(args)
+#else
+#define DBG(n, args...)   do { } while(0)
+#define PRINTK(args...)   printk(KERN_DEBUG args)
+#endif
+
+#if SMC_DEBUG > 3
+static void PRINT_PKT(u_char *buf, int length)
+{
+       int i;
+       int remainder;
+       int lines;
+
+       lines = length / 16;
+       remainder = length % 16;
+
+       for (i = 0; i < lines ; i ++) {
+               int cur;
+               for (cur = 0; cur < 8; cur++) {
+                       u_char a, b;
+                       a = *buf++;
+                       b = *buf++;
+                       printk("%02x%02x ", a, b);
+               }
+               printk("\n");
+       }
+       for (i = 0; i < remainder/2 ; i++) {
+               u_char a, b;
+               a = *buf++;
+               b = *buf++;
+               printk("%02x%02x ", a, b);
+       }
+       printk("\n");
+}
+#else
+#define PRINT_PKT(x...)  do { } while(0)
+#endif
+
+
+/* this enables an interrupt in the interrupt mask register */
+#define SMC_ENABLE_INT(lp, x) do {                                     \
+       unsigned char mask;                                             \
+       unsigned long smc_enable_flags;                                 \
+       spin_lock_irqsave(&lp->lock, smc_enable_flags);                 \
+       mask = SMC_GET_INT_MASK(lp);                                    \
+       mask |= (x);                                                    \
+       SMC_SET_INT_MASK(lp, mask);                                     \
+       spin_unlock_irqrestore(&lp->lock, smc_enable_flags);            \
+} while (0)
+
+/* this disables an interrupt from the interrupt mask register */
+#define SMC_DISABLE_INT(lp, x) do {                                    \
+       unsigned char mask;                                             \
+       unsigned long smc_disable_flags;                                \
+       spin_lock_irqsave(&lp->lock, smc_disable_flags);                \
+       mask = SMC_GET_INT_MASK(lp);                                    \
+       mask &= ~(x);                                                   \
+       SMC_SET_INT_MASK(lp, mask);                                     \
+       spin_unlock_irqrestore(&lp->lock, smc_disable_flags);           \
+} while (0)
+
+/*
+ * Wait while MMU is busy.  This is usually in the order of a few nanosecs
+ * if at all, but let's avoid deadlocking the system if the hardware
+ * decides to go south.
+ */
+#define SMC_WAIT_MMU_BUSY(lp) do {                                     \
+       if (unlikely(SMC_GET_MMU_CMD(lp) & MC_BUSY)) {          \
+               unsigned long timeout = jiffies + 2;                    \
+               while (SMC_GET_MMU_CMD(lp) & MC_BUSY) {         \
+                       if (time_after(jiffies, timeout)) {             \
+                               printk("%s: timeout %s line %d\n",      \
+                                       dev->name, __FILE__, __LINE__); \
+                               break;                                  \
+                       }                                               \
+                       cpu_relax();                                    \
+               }                                                       \
+       }                                                               \
+} while (0)
+
+
+/*
+ * this does a soft reset on the device
+ */
+static void smc_reset(struct net_device *dev)
+{
+       struct smc_local *lp = netdev_priv(dev);
+       void __iomem *ioaddr = lp->base;
+       unsigned int ctl, cfg;
+       struct sk_buff *pending_skb;
+
+       DBG(2, "%s: %s\n", dev->name, __func__);
+
+       /* Disable all interrupts, block TX tasklet */
+       spin_lock_irq(&lp->lock);
+       SMC_SELECT_BANK(lp, 2);
+       SMC_SET_INT_MASK(lp, 0);
+       pending_skb = lp->pending_tx_skb;
+       lp->pending_tx_skb = NULL;
+       spin_unlock_irq(&lp->lock);
+
+       /* free any pending tx skb */
+       if (pending_skb) {
+               dev_kfree_skb(pending_skb);
+               dev->stats.tx_errors++;
+               dev->stats.tx_aborted_errors++;
+       }
+
+       /*
+        * This resets the registers mostly to defaults, but doesn't
+        * affect EEPROM.  That seems unnecessary
+        */
+       SMC_SELECT_BANK(lp, 0);
+       SMC_SET_RCR(lp, RCR_SOFTRST);
+
+       /*
+        * Setup the Configuration Register
+        * This is necessary because the CONFIG_REG is not affected
+        * by a soft reset
+        */
+       SMC_SELECT_BANK(lp, 1);
+
+       cfg = CONFIG_DEFAULT;
+
+       /*
+        * Setup for fast accesses if requested.  If the card/system
+        * can't handle it then there will be no recovery except for
+        * a hard reset or power cycle
+        */
+       if (lp->cfg.flags & SMC91X_NOWAIT)
+               cfg |= CONFIG_NO_WAIT;
+
+       /*
+        * Release from possible power-down state
+        * Configuration register is not affected by Soft Reset
+        */
+       cfg |= CONFIG_EPH_POWER_EN;
+
+       SMC_SET_CONFIG(lp, cfg);
+
+       /* this should pause enough for the chip to be happy */
+       /*
+        * elaborate?  What does the chip _need_? --jgarzik
+        *
+        * This seems to be undocumented, but something the original
+        * driver(s) have always done.  Suspect undocumented timing
+        * info/determined empirically. --rmk
+        */
+       udelay(1);
+
+       /* Disable transmit and receive functionality */
+       SMC_SELECT_BANK(lp, 0);
+       SMC_SET_RCR(lp, RCR_CLEAR);
+       SMC_SET_TCR(lp, TCR_CLEAR);
+
+       SMC_SELECT_BANK(lp, 1);
+       ctl = SMC_GET_CTL(lp) | CTL_LE_ENABLE;
+
+       /*
+        * Set the control register to automatically release successfully
+        * transmitted packets, to make the best use out of our limited
+        * memory
+        */
+       if(!THROTTLE_TX_PKTS)
+               ctl |= CTL_AUTO_RELEASE;
+       else
+               ctl &= ~CTL_AUTO_RELEASE;
+       SMC_SET_CTL(lp, ctl);
+
+       /* Reset the MMU */
+       SMC_SELECT_BANK(lp, 2);
+       SMC_SET_MMU_CMD(lp, MC_RESET);
+       SMC_WAIT_MMU_BUSY(lp);
+}
+
+/*
+ * Enable Interrupts, Receive, and Transmit
+ */
+static void smc_enable(struct net_device *dev)
+{
+       struct smc_local *lp = netdev_priv(dev);
+       void __iomem *ioaddr = lp->base;
+       int mask;
+
+       DBG(2, "%s: %s\n", dev->name, __func__);
+
+       /* see the header file for options in TCR/RCR DEFAULT */
+       SMC_SELECT_BANK(lp, 0);
+       SMC_SET_TCR(lp, lp->tcr_cur_mode);
+       SMC_SET_RCR(lp, lp->rcr_cur_mode);
+
+       SMC_SELECT_BANK(lp, 1);
+       SMC_SET_MAC_ADDR(lp, dev->dev_addr);
+
+       /* now, enable interrupts */
+       mask = IM_EPH_INT|IM_RX_OVRN_INT|IM_RCV_INT;
+       if (lp->version >= (CHIP_91100 << 4))
+               mask |= IM_MDINT;
+       SMC_SELECT_BANK(lp, 2);
+       SMC_SET_INT_MASK(lp, mask);
+
+       /*
+        * From this point the register bank must _NOT_ be switched away
+        * to something else than bank 2 without proper locking against
+        * races with any tasklet or interrupt handlers until smc_shutdown()
+        * or smc_reset() is called.
+        */
+}
+
+/*
+ * this puts the device in an inactive state
+ */
+static void smc_shutdown(struct net_device *dev)
+{
+       struct smc_local *lp = netdev_priv(dev);
+       void __iomem *ioaddr = lp->base;
+       struct sk_buff *pending_skb;
+
+       DBG(2, "%s: %s\n", CARDNAME, __func__);
+
+       /* no more interrupts for me */
+       spin_lock_irq(&lp->lock);
+       SMC_SELECT_BANK(lp, 2);
+       SMC_SET_INT_MASK(lp, 0);
+       pending_skb = lp->pending_tx_skb;
+       lp->pending_tx_skb = NULL;
+       spin_unlock_irq(&lp->lock);
+       if (pending_skb)
+               dev_kfree_skb(pending_skb);
+
+       /* and tell the card to stay away from that nasty outside world */
+       SMC_SELECT_BANK(lp, 0);
+       SMC_SET_RCR(lp, RCR_CLEAR);
+       SMC_SET_TCR(lp, TCR_CLEAR);
+
+#ifdef POWER_DOWN
+       /* finally, shut the chip down */
+       SMC_SELECT_BANK(lp, 1);
+       SMC_SET_CONFIG(lp, SMC_GET_CONFIG(lp) & ~CONFIG_EPH_POWER_EN);
+#endif
+}
+
+/*
+ * This is the procedure to handle the receipt of a packet.
+ */
+static inline void  smc_rcv(struct net_device *dev)
+{
+       struct smc_local *lp = netdev_priv(dev);
+       void __iomem *ioaddr = lp->base;
+       unsigned int packet_number, status, packet_len;
+
+       DBG(3, "%s: %s\n", dev->name, __func__);
+
+       packet_number = SMC_GET_RXFIFO(lp);
+       if (unlikely(packet_number & RXFIFO_REMPTY)) {
+               PRINTK("%s: smc_rcv with nothing on FIFO.\n", dev->name);
+               return;
+       }
+
+       /* read from start of packet */
+       SMC_SET_PTR(lp, PTR_READ | PTR_RCV | PTR_AUTOINC);
+
+       /* First two words are status and packet length */
+       SMC_GET_PKT_HDR(lp, status, packet_len);
+       packet_len &= 0x07ff;  /* mask off top bits */
+       DBG(2, "%s: RX PNR 0x%x STATUS 0x%04x LENGTH 0x%04x (%d)\n",
+               dev->name, packet_number, status,
+               packet_len, packet_len);
+
+       back:
+       if (unlikely(packet_len < 6 || status & RS_ERRORS)) {
+               if (status & RS_TOOLONG && packet_len <= (1514 + 4 + 6)) {
+                       /* accept VLAN packets */
+                       status &= ~RS_TOOLONG;
+                       goto back;
+               }
+               if (packet_len < 6) {
+                       /* bloody hardware */
+                       printk(KERN_ERR "%s: fubar (rxlen %u status %x\n",
+                                       dev->name, packet_len, status);
+                       status |= RS_TOOSHORT;
+               }
+               SMC_WAIT_MMU_BUSY(lp);
+               SMC_SET_MMU_CMD(lp, MC_RELEASE);
+               dev->stats.rx_errors++;
+               if (status & RS_ALGNERR)
+                       dev->stats.rx_frame_errors++;
+               if (status & (RS_TOOSHORT | RS_TOOLONG))
+                       dev->stats.rx_length_errors++;
+               if (status & RS_BADCRC)
+                       dev->stats.rx_crc_errors++;
+       } else {
+               struct sk_buff *skb;
+               unsigned char *data;
+               unsigned int data_len;
+
+               /* set multicast stats */
+               if (status & RS_MULTICAST)
+                       dev->stats.multicast++;
+
+               /*
+                * Actual payload is packet_len - 6 (or 5 if odd byte).
+                * We want skb_reserve(2) and the final ctrl word
+                * (2 bytes, possibly containing the payload odd byte).
+                * Furthermore, we add 2 bytes to allow rounding up to
+                * multiple of 4 bytes on 32 bit buses.
+                * Hence packet_len - 6 + 2 + 2 + 2.
+                */
+               skb = dev_alloc_skb(packet_len);
+               if (unlikely(skb == NULL)) {
+                       printk(KERN_NOTICE "%s: Low memory, packet dropped.\n",
+                               dev->name);
+                       SMC_WAIT_MMU_BUSY(lp);
+                       SMC_SET_MMU_CMD(lp, MC_RELEASE);
+                       dev->stats.rx_dropped++;
+                       return;
+               }
+
+               /* Align IP header to 32 bits */
+               skb_reserve(skb, 2);
+
+               /* BUG: the LAN91C111 rev A never sets this bit. Force it. */
+               if (lp->version == 0x90)
+                       status |= RS_ODDFRAME;
+
+               /*
+                * If odd length: packet_len - 5,
+                * otherwise packet_len - 6.
+                * With the trailing ctrl byte it's packet_len - 4.
+                */
+               data_len = packet_len - ((status & RS_ODDFRAME) ? 5 : 6);
+               data = skb_put(skb, data_len);
+               SMC_PULL_DATA(lp, data, packet_len - 4);
+
+               SMC_WAIT_MMU_BUSY(lp);
+               SMC_SET_MMU_CMD(lp, MC_RELEASE);
+
+               PRINT_PKT(data, packet_len - 4);
+
+               skb->protocol = eth_type_trans(skb, dev);
+               netif_rx(skb);
+               dev->stats.rx_packets++;
+               dev->stats.rx_bytes += data_len;
+       }
+}
+
+#ifdef CONFIG_SMP
+/*
+ * On SMP we have the following problem:
+ *
+ *     A = smc_hardware_send_pkt()
+ *     B = smc_hard_start_xmit()
+ *     C = smc_interrupt()
+ *
+ * A and B can never be executed simultaneously.  However, at least on UP,
+ * it is possible (and even desirable) for C to interrupt execution of
+ * A or B in order to have better RX reliability and avoid overruns.
+ * C, just like A and B, must have exclusive access to the chip and
+ * each of them must lock against any other concurrent access.
+ * Unfortunately this is not possible to have C suspend execution of A or
+ * B taking place on another CPU. On UP this is no an issue since A and B
+ * are run from softirq context and C from hard IRQ context, and there is
+ * no other CPU where concurrent access can happen.
+ * If ever there is a way to force at least B and C to always be executed
+ * on the same CPU then we could use read/write locks to protect against
+ * any other concurrent access and C would always interrupt B. But life
+ * isn't that easy in a SMP world...
+ */
+#define smc_special_trylock(lock, flags)                               \
+({                                                                     \
+       int __ret;                                                      \
+       local_irq_save(flags);                                          \
+       __ret = spin_trylock(lock);                                     \
+       if (!__ret)                                                     \
+               local_irq_restore(flags);                               \
+       __ret;                                                          \
+})
+#define smc_special_lock(lock, flags)          spin_lock_irqsave(lock, flags)
+#define smc_special_unlock(lock, flags)        spin_unlock_irqrestore(lock, flags)
+#else
+#define smc_special_trylock(lock, flags)       (flags == flags)
+#define smc_special_lock(lock, flags)          do { flags = 0; } while (0)
+#define smc_special_unlock(lock, flags)        do { flags = 0; } while (0)
+#endif
+
+/*
+ * This is called to actually send a packet to the chip.
+ */
+static void smc_hardware_send_pkt(unsigned long data)
+{
+       struct net_device *dev = (struct net_device *)data;
+       struct smc_local *lp = netdev_priv(dev);
+       void __iomem *ioaddr = lp->base;
+       struct sk_buff *skb;
+       unsigned int packet_no, len;
+       unsigned char *buf;
+       unsigned long flags;
+
+       DBG(3, "%s: %s\n", dev->name, __func__);
+
+       if (!smc_special_trylock(&lp->lock, flags)) {
+               netif_stop_queue(dev);
+               tasklet_schedule(&lp->tx_task);
+               return;
+       }
+
+       skb = lp->pending_tx_skb;
+       if (unlikely(!skb)) {
+               smc_special_unlock(&lp->lock, flags);
+               return;
+       }
+       lp->pending_tx_skb = NULL;
+
+       packet_no = SMC_GET_AR(lp);
+       if (unlikely(packet_no & AR_FAILED)) {
+               printk("%s: Memory allocation failed.\n", dev->name);
+               dev->stats.tx_errors++;
+               dev->stats.tx_fifo_errors++;
+               smc_special_unlock(&lp->lock, flags);
+               goto done;
+       }
+
+       /* point to the beginning of the packet */
+       SMC_SET_PN(lp, packet_no);
+       SMC_SET_PTR(lp, PTR_AUTOINC);
+
+       buf = skb->data;
+       len = skb->len;
+       DBG(2, "%s: TX PNR 0x%x LENGTH 0x%04x (%d) BUF 0x%p\n",
+               dev->name, packet_no, len, len, buf);
+       PRINT_PKT(buf, len);
+
+       /*
+        * Send the packet length (+6 for status words, length, and ctl.
+        * The card will pad to 64 bytes with zeroes if packet is too small.
+        */
+       SMC_PUT_PKT_HDR(lp, 0, len + 6);
+
+       /* send the actual data */
+       SMC_PUSH_DATA(lp, buf, len & ~1);
+
+       /* Send final ctl word with the last byte if there is one */
+       SMC_outw(((len & 1) ? (0x2000 | buf[len-1]) : 0), ioaddr, DATA_REG(lp));
+
+       /*
+        * If THROTTLE_TX_PKTS is set, we stop the queue here. This will
+        * have the effect of having at most one packet queued for TX
+        * in the chip's memory at all time.
+        *
+        * If THROTTLE_TX_PKTS is not set then the queue is stopped only
+        * when memory allocation (MC_ALLOC) does not succeed right away.
+        */
+       if (THROTTLE_TX_PKTS)
+               netif_stop_queue(dev);
+
+       /* queue the packet for TX */
+       SMC_SET_MMU_CMD(lp, MC_ENQUEUE);
+       smc_special_unlock(&lp->lock, flags);
+
+       dev->trans_start = jiffies;
+       dev->stats.tx_packets++;
+       dev->stats.tx_bytes += len;
+
+       SMC_ENABLE_INT(lp, IM_TX_INT | IM_TX_EMPTY_INT);
+
+done:  if (!THROTTLE_TX_PKTS)
+               netif_wake_queue(dev);
+
+       dev_kfree_skb(skb);
+}
+
+/*
+ * Since I am not sure if I will have enough room in the chip's ram
+ * to store the packet, I call this routine which either sends it
+ * now, or set the card to generates an interrupt when ready
+ * for the packet.
+ */
+static int smc_hard_start_xmit(struct sk_buff *skb, struct net_device *dev)
+{
+       struct smc_local *lp = netdev_priv(dev);
+       void __iomem *ioaddr = lp->base;
+       unsigned int numPages, poll_count, status;
+       unsigned long flags;
+
+       DBG(3, "%s: %s\n", dev->name, __func__);
+
+       BUG_ON(lp->pending_tx_skb != NULL);
+
+       /*
+        * The MMU wants the number of pages to be the number of 256 bytes
+        * 'pages', minus 1 (since a packet can't ever have 0 pages :))
+        *
+        * The 91C111 ignores the size bits, but earlier models don't.
+        *
+        * Pkt size for allocating is data length +6 (for additional status
+        * words, length and ctl)
+        *
+        * If odd size then last byte is included in ctl word.
+        */
+       numPages = ((skb->len & ~1) + (6 - 1)) >> 8;
+       if (unlikely(numPages > 7)) {
+               printk("%s: Far too big packet error.\n", dev->name);
+               dev->stats.tx_errors++;
+               dev->stats.tx_dropped++;
+               dev_kfree_skb(skb);
+               return NETDEV_TX_OK;
+       }
+
+       smc_special_lock(&lp->lock, flags);
+
+       /* now, try to allocate the memory */
+       SMC_SET_MMU_CMD(lp, MC_ALLOC | numPages);
+
+       /*
+        * Poll the chip for a short amount of time in case the
+        * allocation succeeds quickly.
+        */
+       poll_count = MEMORY_WAIT_TIME;
+       do {
+               status = SMC_GET_INT(lp);
+               if (status & IM_ALLOC_INT) {
+                       SMC_ACK_INT(lp, IM_ALLOC_INT);
+                       break;
+               }
+       } while (--poll_count);
+
+       smc_special_unlock(&lp->lock, flags);
+
+       lp->pending_tx_skb = skb;
+       if (!poll_count) {
+               /* oh well, wait until the chip finds memory later */
+               netif_stop_queue(dev);
+               DBG(2, "%s: TX memory allocation deferred.\n", dev->name);
+               SMC_ENABLE_INT(lp, IM_ALLOC_INT);
+       } else {
+               /*
+                * Allocation succeeded: push packet to the chip's own memory
+                * immediately.
+                */
+               smc_hardware_send_pkt((unsigned long)dev);
+       }
+
+       return NETDEV_TX_OK;
+}
+
+/*
+ * This handles a TX interrupt, which is only called when:
+ * - a TX error occurred, or
+ * - CTL_AUTO_RELEASE is not set and TX of a packet completed.
+ */
+static void smc_tx(struct net_device *dev)
+{
+       struct smc_local *lp = netdev_priv(dev);
+       void __iomem *ioaddr = lp->base;
+       unsigned int saved_packet, packet_no, tx_status, pkt_len;
+
+       DBG(3, "%s: %s\n", dev->name, __func__);
+
+       /* If the TX FIFO is empty then nothing to do */
+       packet_no = SMC_GET_TXFIFO(lp);
+       if (unlikely(packet_no & TXFIFO_TEMPTY)) {
+               PRINTK("%s: smc_tx with nothing on FIFO.\n", dev->name);
+               return;
+       }
+
+       /* select packet to read from */
+       saved_packet = SMC_GET_PN(lp);
+       SMC_SET_PN(lp, packet_no);
+
+       /* read the first word (status word) from this packet */
+       SMC_SET_PTR(lp, PTR_AUTOINC | PTR_READ);
+       SMC_GET_PKT_HDR(lp, tx_status, pkt_len);
+       DBG(2, "%s: TX STATUS 0x%04x PNR 0x%02x\n",
+               dev->name, tx_status, packet_no);
+
+       if (!(tx_status & ES_TX_SUC))
+               dev->stats.tx_errors++;
+
+       if (tx_status & ES_LOSTCARR)
+               dev->stats.tx_carrier_errors++;
+
+       if (tx_status & (ES_LATCOL | ES_16COL)) {
+               PRINTK("%s: %s occurred on last xmit\n", dev->name,
+                      (tx_status & ES_LATCOL) ?
+                       "late collision" : "too many collisions");
+               dev->stats.tx_window_errors++;
+               if (!(dev->stats.tx_window_errors & 63) && net_ratelimit()) {
+                       printk(KERN_INFO "%s: unexpectedly large number of "
+                              "bad collisions. Please check duplex "
+                              "setting.\n", dev->name);
+               }
+       }
+
+       /* kill the packet */
+       SMC_WAIT_MMU_BUSY(lp);
+       SMC_SET_MMU_CMD(lp, MC_FREEPKT);
+
+       /* Don't restore Packet Number Reg until busy bit is cleared */
+       SMC_WAIT_MMU_BUSY(lp);
+       SMC_SET_PN(lp, saved_packet);
+
+       /* re-enable transmit */
+       SMC_SELECT_BANK(lp, 0);
+       SMC_SET_TCR(lp, lp->tcr_cur_mode);
+       SMC_SELECT_BANK(lp, 2);
+}
+
+
+/*---PHY CONTROL AND CONFIGURATION-----------------------------------------*/
+
+static void smc_mii_out(struct net_device *dev, unsigned int val, int bits)
+{
+       struct smc_local *lp = netdev_priv(dev);
+       void __iomem *ioaddr = lp->base;
+       unsigned int mii_reg, mask;
+
+       mii_reg = SMC_GET_MII(lp) & ~(MII_MCLK | MII_MDOE | MII_MDO);
+       mii_reg |= MII_MDOE;
+
+       for (mask = 1 << (bits - 1); mask; mask >>= 1) {
+               if (val & mask)
+                       mii_reg |= MII_MDO;
+               else
+                       mii_reg &= ~MII_MDO;
+
+               SMC_SET_MII(lp, mii_reg);
+               udelay(MII_DELAY);
+               SMC_SET_MII(lp, mii_reg | MII_MCLK);
+               udelay(MII_DELAY);
+       }
+}
+
+static unsigned int smc_mii_in(struct net_device *dev, int bits)
+{
+       struct smc_local *lp = netdev_priv(dev);
+       void __iomem *ioaddr = lp->base;
+       unsigned int mii_reg, mask, val;
+
+       mii_reg = SMC_GET_MII(lp) & ~(MII_MCLK | MII_MDOE | MII_MDO);
+       SMC_SET_MII(lp, mii_reg);
+
+       for (mask = 1 << (bits - 1), val = 0; mask; mask >>= 1) {
+               if (SMC_GET_MII(lp) & MII_MDI)
+                       val |= mask;
+
+               SMC_SET_MII(lp, mii_reg);
+               udelay(MII_DELAY);
+               SMC_SET_MII(lp, mii_reg | MII_MCLK);
+               udelay(MII_DELAY);
+       }
+
+       return val;
+}
+
+/*
+ * Reads a register from the MII Management serial interface
+ */
+static int smc_phy_read(struct net_device *dev, int phyaddr, int phyreg)
+{
+       struct smc_local *lp = netdev_priv(dev);
+       void __iomem *ioaddr = lp->base;
+       unsigned int phydata;
+
+       SMC_SELECT_BANK(lp, 3);
+
+       /* Idle - 32 ones */
+       smc_mii_out(dev, 0xffffffff, 32);
+
+       /* Start code (01) + read (10) + phyaddr + phyreg */
+       smc_mii_out(dev, 6 << 10 | phyaddr << 5 | phyreg, 14);
+
+       /* Turnaround (2bits) + phydata */
+       phydata = smc_mii_in(dev, 18);
+
+       /* Return to idle state */
+       SMC_SET_MII(lp, SMC_GET_MII(lp) & ~(MII_MCLK|MII_MDOE|MII_MDO));
+
+       DBG(3, "%s: phyaddr=0x%x, phyreg=0x%x, phydata=0x%x\n",
+               __func__, phyaddr, phyreg, phydata);
+
+       SMC_SELECT_BANK(lp, 2);
+       return phydata;
+}
+
+/*
+ * Writes a register to the MII Management serial interface
+ */
+static void smc_phy_write(struct net_device *dev, int phyaddr, int phyreg,
+                         int phydata)
+{
+       struct smc_local *lp = netdev_priv(dev);
+       void __iomem *ioaddr = lp->base;
+
+       SMC_SELECT_BANK(lp, 3);
+
+       /* Idle - 32 ones */
+       smc_mii_out(dev, 0xffffffff, 32);
+
+       /* Start code (01) + write (01) + phyaddr + phyreg + turnaround + phydata */
+       smc_mii_out(dev, 5 << 28 | phyaddr << 23 | phyreg << 18 | 2 << 16 | phydata, 32);
+
+       /* Return to idle state */
+       SMC_SET_MII(lp, SMC_GET_MII(lp) & ~(MII_MCLK|MII_MDOE|MII_MDO));
+
+       DBG(3, "%s: phyaddr=0x%x, phyreg=0x%x, phydata=0x%x\n",
+               __func__, phyaddr, phyreg, phydata);
+
+       SMC_SELECT_BANK(lp, 2);
+}
+
+/*
+ * Finds and reports the PHY address
+ */
+static void smc_phy_detect(struct net_device *dev)
+{
+       struct smc_local *lp = netdev_priv(dev);
+       int phyaddr;
+
+       DBG(2, "%s: %s\n", dev->name, __func__);
+
+       lp->phy_type = 0;
+
+       /*
+        * Scan all 32 PHY addresses if necessary, starting at
+        * PHY#1 to PHY#31, and then PHY#0 last.
+        */
+       for (phyaddr = 1; phyaddr < 33; ++phyaddr) {
+               unsigned int id1, id2;
+
+               /* Read the PHY identifiers */
+               id1 = smc_phy_read(dev, phyaddr & 31, MII_PHYSID1);
+               id2 = smc_phy_read(dev, phyaddr & 31, MII_PHYSID2);
+
+               DBG(3, "%s: phy_id1=0x%x, phy_id2=0x%x\n",
+                       dev->name, id1, id2);
+
+               /* Make sure it is a valid identifier */
+               if (id1 != 0x0000 && id1 != 0xffff && id1 != 0x8000 &&
+                   id2 != 0x0000 && id2 != 0xffff && id2 != 0x8000) {
+                       /* Save the PHY's address */
+                       lp->mii.phy_id = phyaddr & 31;
+                       lp->phy_type = id1 << 16 | id2;
+                       break;
+               }
+       }
+}
+
+/*
+ * Sets the PHY to a configuration as determined by the user
+ */
+static int smc_phy_fixed(struct net_device *dev)
+{
+       struct smc_local *lp = netdev_priv(dev);
+       void __iomem *ioaddr = lp->base;
+       int phyaddr = lp->mii.phy_id;
+       int bmcr, cfg1;
+
+       DBG(3, "%s: %s\n", dev->name, __func__);
+
+       /* Enter Link Disable state */
+       cfg1 = smc_phy_read(dev, phyaddr, PHY_CFG1_REG);
+       cfg1 |= PHY_CFG1_LNKDIS;
+       smc_phy_write(dev, phyaddr, PHY_CFG1_REG, cfg1);
+
+       /*
+        * Set our fixed capabilities
+        * Disable auto-negotiation
+        */
+       bmcr = 0;
+
+       if (lp->ctl_rfduplx)
+               bmcr |= BMCR_FULLDPLX;
+
+       if (lp->ctl_rspeed == 100)
+               bmcr |= BMCR_SPEED100;
+
+       /* Write our capabilities to the phy control register */
+       smc_phy_write(dev, phyaddr, MII_BMCR, bmcr);
+
+       /* Re-Configure the Receive/Phy Control register */
+       SMC_SELECT_BANK(lp, 0);
+       SMC_SET_RPC(lp, lp->rpc_cur_mode);
+       SMC_SELECT_BANK(lp, 2);
+
+       return 1;
+}
+
+/*
+ * smc_phy_reset - reset the phy
+ * @dev: net device
+ * @phy: phy address
+ *
+ * Issue a software reset for the specified PHY and
+ * wait up to 100ms for the reset to complete.  We should
+ * not access the PHY for 50ms after issuing the reset.
+ *
+ * The time to wait appears to be dependent on the PHY.
+ *
+ * Must be called with lp->lock locked.
+ */
+static int smc_phy_reset(struct net_device *dev, int phy)
+{
+       struct smc_local *lp = netdev_priv(dev);
+       unsigned int bmcr;
+       int timeout;
+
+       smc_phy_write(dev, phy, MII_BMCR, BMCR_RESET);
+
+       for (timeout = 2; timeout; timeout--) {
+               spin_unlock_irq(&lp->lock);
+               msleep(50);
+               spin_lock_irq(&lp->lock);
+
+               bmcr = smc_phy_read(dev, phy, MII_BMCR);
+               if (!(bmcr & BMCR_RESET))
+                       break;
+       }
+
+       return bmcr & BMCR_RESET;
+}
+
+/*
+ * smc_phy_powerdown - powerdown phy
+ * @dev: net device
+ *
+ * Power down the specified PHY
+ */
+static void smc_phy_powerdown(struct net_device *dev)
+{
+       struct smc_local *lp = netdev_priv(dev);
+       unsigned int bmcr;
+       int phy = lp->mii.phy_id;
+
+       if (lp->phy_type == 0)
+               return;
+
+       /* We need to ensure that no calls to smc_phy_configure are
+          pending.
+       */
+       cancel_work_sync(&lp->phy_configure);
+
+       bmcr = smc_phy_read(dev, phy, MII_BMCR);
+       smc_phy_write(dev, phy, MII_BMCR, bmcr | BMCR_PDOWN);
+}
+
+/*
+ * smc_phy_check_media - check the media status and adjust TCR
+ * @dev: net device
+ * @init: set true for initialisation
+ *
+ * Select duplex mode depending on negotiation state.  This
+ * also updates our carrier state.
+ */
+static void smc_phy_check_media(struct net_device *dev, int init)
+{
+       struct smc_local *lp = netdev_priv(dev);
+       void __iomem *ioaddr = lp->base;
+
+       if (mii_check_media(&lp->mii, netif_msg_link(lp), init)) {
+               /* duplex state has changed */
+               if (lp->mii.full_duplex) {
+                       lp->tcr_cur_mode |= TCR_SWFDUP;
+               } else {
+                       lp->tcr_cur_mode &= ~TCR_SWFDUP;
+               }
+
+               SMC_SELECT_BANK(lp, 0);
+               SMC_SET_TCR(lp, lp->tcr_cur_mode);
+       }
+}
+
+/*
+ * Configures the specified PHY through the MII management interface
+ * using Autonegotiation.
+ * Calls smc_phy_fixed() if the user has requested a certain config.
+ * If RPC ANEG bit is set, the media selection is dependent purely on
+ * the selection by the MII (either in the MII BMCR reg or the result
+ * of autonegotiation.)  If the RPC ANEG bit is cleared, the selection
+ * is controlled by the RPC SPEED and RPC DPLX bits.
+ */
+static void smc_phy_configure(struct work_struct *work)
+{
+       struct smc_local *lp =
+               container_of(work, struct smc_local, phy_configure);
+       struct net_device *dev = lp->dev;
+       void __iomem *ioaddr = lp->base;
+       int phyaddr = lp->mii.phy_id;
+       int my_phy_caps; /* My PHY capabilities */
+       int my_ad_caps; /* My Advertised capabilities */
+       int status;
+
+       DBG(3, "%s:smc_program_phy()\n", dev->name);
+
+       spin_lock_irq(&lp->lock);
+
+       /*
+        * We should not be called if phy_type is zero.
+        */
+       if (lp->phy_type == 0)
+               goto smc_phy_configure_exit;
+
+       if (smc_phy_reset(dev, phyaddr)) {
+               printk("%s: PHY reset timed out\n", dev->name);
+               goto smc_phy_configure_exit;
+       }
+
+       /*
+        * Enable PHY Interrupts (for register 18)
+        * Interrupts listed here are disabled
+        */
+       smc_phy_write(dev, phyaddr, PHY_MASK_REG,
+               PHY_INT_LOSSSYNC | PHY_INT_CWRD | PHY_INT_SSD |
+               PHY_INT_ESD | PHY_INT_RPOL | PHY_INT_JAB |
+               PHY_INT_SPDDET | PHY_INT_DPLXDET);
+
+       /* Configure the Receive/Phy Control register */
+       SMC_SELECT_BANK(lp, 0);
+       SMC_SET_RPC(lp, lp->rpc_cur_mode);
+
+       /* If the user requested no auto neg, then go set his request */
+       if (lp->mii.force_media) {
+               smc_phy_fixed(dev);
+               goto smc_phy_configure_exit;
+       }
+
+       /* Copy our capabilities from MII_BMSR to MII_ADVERTISE */
+       my_phy_caps = smc_phy_read(dev, phyaddr, MII_BMSR);
+
+       if (!(my_phy_caps & BMSR_ANEGCAPABLE)) {
+               printk(KERN_INFO "Auto negotiation NOT supported\n");
+               smc_phy_fixed(dev);
+               goto smc_phy_configure_exit;
+       }
+
+       my_ad_caps = ADVERTISE_CSMA; /* I am CSMA capable */
+
+       if (my_phy_caps & BMSR_100BASE4)
+               my_ad_caps |= ADVERTISE_100BASE4;
+       if (my_phy_caps & BMSR_100FULL)
+               my_ad_caps |= ADVERTISE_100FULL;
+       if (my_phy_caps & BMSR_100HALF)
+               my_ad_caps |= ADVERTISE_100HALF;
+       if (my_phy_caps & BMSR_10FULL)
+               my_ad_caps |= ADVERTISE_10FULL;
+       if (my_phy_caps & BMSR_10HALF)
+               my_ad_caps |= ADVERTISE_10HALF;
+
+       /* Disable capabilities not selected by our user */
+       if (lp->ctl_rspeed != 100)
+               my_ad_caps &= ~(ADVERTISE_100BASE4|ADVERTISE_100FULL|ADVERTISE_100HALF);
+
+       if (!lp->ctl_rfduplx)
+               my_ad_caps &= ~(ADVERTISE_100FULL|ADVERTISE_10FULL);
+
+       /* Update our Auto-Neg Advertisement Register */
+       smc_phy_write(dev, phyaddr, MII_ADVERTISE, my_ad_caps);
+       lp->mii.advertising = my_ad_caps;
+
+       /*
+        * Read the register back.  Without this, it appears that when
+        * auto-negotiation is restarted, sometimes it isn't ready and
+        * the link does not come up.
+        */
+       status = smc_phy_read(dev, phyaddr, MII_ADVERTISE);
+
+       DBG(2, "%s: phy caps=%x\n", dev->name, my_phy_caps);
+       DBG(2, "%s: phy advertised caps=%x\n", dev->name, my_ad_caps);
+
+       /* Restart auto-negotiation process in order to advertise my caps */
+       smc_phy_write(dev, phyaddr, MII_BMCR, BMCR_ANENABLE | BMCR_ANRESTART);
+
+       smc_phy_check_media(dev, 1);
+
+smc_phy_configure_exit:
+       SMC_SELECT_BANK(lp, 2);
+       spin_unlock_irq(&lp->lock);
+}
+
+/*
+ * smc_phy_interrupt
+ *
+ * Purpose:  Handle interrupts relating to PHY register 18. This is
+ *  called from the "hard" interrupt handler under our private spinlock.
+ */
+static void smc_phy_interrupt(struct net_device *dev)
+{
+       struct smc_local *lp = netdev_priv(dev);
+       int phyaddr = lp->mii.phy_id;
+       int phy18;
+
+       DBG(2, "%s: %s\n", dev->name, __func__);
+
+       if (lp->phy_type == 0)
+               return;
+
+       for(;;) {
+               smc_phy_check_media(dev, 0);
+
+               /* Read PHY Register 18, Status Output */
+               phy18 = smc_phy_read(dev, phyaddr, PHY_INT_REG);
+               if ((phy18 & PHY_INT_INT) == 0)
+                       break;
+       }
+}
+
+/*--- END PHY CONTROL AND CONFIGURATION-------------------------------------*/
+
+static void smc_10bt_check_media(struct net_device *dev, int init)
+{
+       struct smc_local *lp = netdev_priv(dev);
+       void __iomem *ioaddr = lp->base;
+       unsigned int old_carrier, new_carrier;
+
+       old_carrier = netif_carrier_ok(dev) ? 1 : 0;
+
+       SMC_SELECT_BANK(lp, 0);
+       new_carrier = (SMC_GET_EPH_STATUS(lp) & ES_LINK_OK) ? 1 : 0;
+       SMC_SELECT_BANK(lp, 2);
+
+       if (init || (old_carrier != new_carrier)) {
+               if (!new_carrier) {
+                       netif_carrier_off(dev);
+               } else {
+                       netif_carrier_on(dev);
+               }
+               if (netif_msg_link(lp))
+                       printk(KERN_INFO "%s: link %s\n", dev->name,
+                              new_carrier ? "up" : "down");
+       }
+}
+
+static void smc_eph_interrupt(struct net_device *dev)
+{
+       struct smc_local *lp = netdev_priv(dev);
+       void __iomem *ioaddr = lp->base;
+       unsigned int ctl;
+
+       smc_10bt_check_media(dev, 0);
+
+       SMC_SELECT_BANK(lp, 1);
+       ctl = SMC_GET_CTL(lp);
+       SMC_SET_CTL(lp, ctl & ~CTL_LE_ENABLE);
+       SMC_SET_CTL(lp, ctl);
+       SMC_SELECT_BANK(lp, 2);
+}
+
+/*
+ * This is the main routine of the driver, to handle the device when
+ * it needs some attention.
+ */
+static irqreturn_t smc_interrupt(int irq, void *dev_id)
+{
+       struct net_device *dev = dev_id;
+       struct smc_local *lp = netdev_priv(dev);
+       void __iomem *ioaddr = lp->base;
+       int status, mask, timeout, card_stats;
+       int saved_pointer;
+
+       DBG(3, "%s: %s\n", dev->name, __func__);
+
+       spin_lock(&lp->lock);
+
+       /* A preamble may be used when there is a potential race
+        * between the interruptible transmit functions and this
+        * ISR. */
+       SMC_INTERRUPT_PREAMBLE;
+
+       saved_pointer = SMC_GET_PTR(lp);
+       mask = SMC_GET_INT_MASK(lp);
+       SMC_SET_INT_MASK(lp, 0);
+
+       /* set a timeout value, so I don't stay here forever */
+       timeout = MAX_IRQ_LOOPS;
+
+       do {
+               status = SMC_GET_INT(lp);
+
+               DBG(2, "%s: INT 0x%02x MASK 0x%02x MEM 0x%04x FIFO 0x%04x\n",
+                       dev->name, status, mask,
+                       ({ int meminfo; SMC_SELECT_BANK(lp, 0);
+                          meminfo = SMC_GET_MIR(lp);
+                          SMC_SELECT_BANK(lp, 2); meminfo; }),
+                       SMC_GET_FIFO(lp));
+
+               status &= mask;
+               if (!status)
+                       break;
+
+               if (status & IM_TX_INT) {
+                       /* do this before RX as it will free memory quickly */
+                       DBG(3, "%s: TX int\n", dev->name);
+                       smc_tx(dev);
+                       SMC_ACK_INT(lp, IM_TX_INT);
+                       if (THROTTLE_TX_PKTS)
+                               netif_wake_queue(dev);
+               } else if (status & IM_RCV_INT) {
+                       DBG(3, "%s: RX irq\n", dev->name);
+                       smc_rcv(dev);
+               } else if (status & IM_ALLOC_INT) {
+                       DBG(3, "%s: Allocation irq\n", dev->name);
+                       tasklet_hi_schedule(&lp->tx_task);
+                       mask &= ~IM_ALLOC_INT;
+               } else if (status & IM_TX_EMPTY_INT) {
+                       DBG(3, "%s: TX empty\n", dev->name);
+                       mask &= ~IM_TX_EMPTY_INT;
+
+                       /* update stats */
+                       SMC_SELECT_BANK(lp, 0);
+                       card_stats = SMC_GET_COUNTER(lp);
+                       SMC_SELECT_BANK(lp, 2);
+
+                       /* single collisions */
+                       dev->stats.collisions += card_stats & 0xF;
+                       card_stats >>= 4;
+
+                       /* multiple collisions */
+                       dev->stats.collisions += card_stats & 0xF;
+               } else if (status & IM_RX_OVRN_INT) {
+                       DBG(1, "%s: RX overrun (EPH_ST 0x%04x)\n", dev->name,
+                              ({ int eph_st; SMC_SELECT_BANK(lp, 0);
+                                 eph_st = SMC_GET_EPH_STATUS(lp);
+                                 SMC_SELECT_BANK(lp, 2); eph_st; }));
+                       SMC_ACK_INT(lp, IM_RX_OVRN_INT);
+                       dev->stats.rx_errors++;
+                       dev->stats.rx_fifo_errors++;
+               } else if (status & IM_EPH_INT) {
+                       smc_eph_interrupt(dev);
+               } else if (status & IM_MDINT) {
+                       SMC_ACK_INT(lp, IM_MDINT);
+                       smc_phy_interrupt(dev);
+               } else if (status & IM_ERCV_INT) {
+                       SMC_ACK_INT(lp, IM_ERCV_INT);
+                       PRINTK("%s: UNSUPPORTED: ERCV INTERRUPT\n", dev->name);
+               }
+       } while (--timeout);
+
+       /* restore register states */
+       SMC_SET_PTR(lp, saved_pointer);
+       SMC_SET_INT_MASK(lp, mask);
+       spin_unlock(&lp->lock);
+
+#ifndef CONFIG_NET_POLL_CONTROLLER
+       if (timeout == MAX_IRQ_LOOPS)
+               PRINTK("%s: spurious interrupt (mask = 0x%02x)\n",
+                      dev->name, mask);
+#endif
+       DBG(3, "%s: Interrupt done (%d loops)\n",
+              dev->name, MAX_IRQ_LOOPS - timeout);
+
+       /*
+        * We return IRQ_HANDLED unconditionally here even if there was
+        * nothing to do.  There is a possibility that a packet might
+        * get enqueued into the chip right after TX_EMPTY_INT is raised
+        * but just before the CPU acknowledges the IRQ.
+        * Better take an unneeded IRQ in some occasions than complexifying
+        * the code for all cases.
+        */
+       return IRQ_HANDLED;
+}
+
+#ifdef CONFIG_NET_POLL_CONTROLLER
+/*
+ * Polling receive - used by netconsole and other diagnostic tools
+ * to allow network i/o with interrupts disabled.
+ */
+static void smc_poll_controller(struct net_device *dev)
+{
+       disable_irq(dev->irq);
+       smc_interrupt(dev->irq, dev);
+       enable_irq(dev->irq);
+}
+#endif
+
+/* Our watchdog timed out. Called by the networking layer */
+static void smc_timeout(struct net_device *dev)
+{
+       struct smc_local *lp = netdev_priv(dev);
+       void __iomem *ioaddr = lp->base;
+       int status, mask, eph_st, meminfo, fifo;
+
+       DBG(2, "%s: %s\n", dev->name, __func__);
+
+       spin_lock_irq(&lp->lock);
+       status = SMC_GET_INT(lp);
+       mask = SMC_GET_INT_MASK(lp);
+       fifo = SMC_GET_FIFO(lp);
+       SMC_SELECT_BANK(lp, 0);
+       eph_st = SMC_GET_EPH_STATUS(lp);
+       meminfo = SMC_GET_MIR(lp);
+       SMC_SELECT_BANK(lp, 2);
+       spin_unlock_irq(&lp->lock);
+       PRINTK( "%s: TX timeout (INT 0x%02x INTMASK 0x%02x "
+               "MEM 0x%04x FIFO 0x%04x EPH_ST 0x%04x)\n",
+               dev->name, status, mask, meminfo, fifo, eph_st );
+
+       smc_reset(dev);
+       smc_enable(dev);
+
+       /*
+        * Reconfiguring the PHY doesn't seem like a bad idea here, but
+        * smc_phy_configure() calls msleep() which calls schedule_timeout()
+        * which calls schedule().  Hence we use a work queue.
+        */
+       if (lp->phy_type != 0)
+               schedule_work(&lp->phy_configure);
+
+       /* We can accept TX packets again */
+       dev->trans_start = jiffies; /* prevent tx timeout */
+       netif_wake_queue(dev);
+}
+
+/*
+ * This routine will, depending on the values passed to it,
+ * either make it accept multicast packets, go into
+ * promiscuous mode (for TCPDUMP and cousins) or accept
+ * a select set of multicast packets
+ */
+static void smc_set_multicast_list(struct net_device *dev)
+{
+       struct smc_local *lp = netdev_priv(dev);
+       void __iomem *ioaddr = lp->base;
+       unsigned char multicast_table[8];
+       int update_multicast = 0;
+
+       DBG(2, "%s: %s\n", dev->name, __func__);
+
+       if (dev->flags & IFF_PROMISC) {
+               DBG(2, "%s: RCR_PRMS\n", dev->name);
+               lp->rcr_cur_mode |= RCR_PRMS;
+       }
+
+/* BUG?  I never disable promiscuous mode if multicasting was turned on.
+   Now, I turn off promiscuous mode, but I don't do anything to multicasting
+   when promiscuous mode is turned on.
+*/
+
+       /*
+        * Here, I am setting this to accept all multicast packets.
+        * I don't need to zero the multicast table, because the flag is
+        * checked before the table is
+        */
+       else if (dev->flags & IFF_ALLMULTI || netdev_mc_count(dev) > 16) {
+               DBG(2, "%s: RCR_ALMUL\n", dev->name);
+               lp->rcr_cur_mode |= RCR_ALMUL;
+       }
+
+       /*
+        * This sets the internal hardware table to filter out unwanted
+        * multicast packets before they take up memory.
+        *
+        * The SMC chip uses a hash table where the high 6 bits of the CRC of
+        * address are the offset into the table.  If that bit is 1, then the
+        * multicast packet is accepted.  Otherwise, it's dropped silently.
+        *
+        * To use the 6 bits as an offset into the table, the high 3 bits are
+        * the number of the 8 bit register, while the low 3 bits are the bit
+        * within that register.
+        */
+       else if (!netdev_mc_empty(dev)) {
+               struct netdev_hw_addr *ha;
+
+               /* table for flipping the order of 3 bits */
+               static const unsigned char invert3[] = {0, 4, 2, 6, 1, 5, 3, 7};
+
+               /* start with a table of all zeros: reject all */
+               memset(multicast_table, 0, sizeof(multicast_table));
+
+               netdev_for_each_mc_addr(ha, dev) {
+                       int position;
+
+                       /* only use the low order bits */
+                       position = crc32_le(~0, ha->addr, 6) & 0x3f;
+
+                       /* do some messy swapping to put the bit in the right spot */
+                       multicast_table[invert3[position&7]] |=
+                               (1<<invert3[(position>>3)&7]);
+               }
+
+               /* be sure I get rid of flags I might have set */
+               lp->rcr_cur_mode &= ~(RCR_PRMS | RCR_ALMUL);
+
+               /* now, the table can be loaded into the chipset */
+               update_multicast = 1;
+       } else  {
+               DBG(2, "%s: ~(RCR_PRMS|RCR_ALMUL)\n", dev->name);
+               lp->rcr_cur_mode &= ~(RCR_PRMS | RCR_ALMUL);
+
+               /*
+                * since I'm disabling all multicast entirely, I need to
+                * clear the multicast list
+                */
+               memset(multicast_table, 0, sizeof(multicast_table));
+               update_multicast = 1;
+       }
+
+       spin_lock_irq(&lp->lock);
+       SMC_SELECT_BANK(lp, 0);
+       SMC_SET_RCR(lp, lp->rcr_cur_mode);
+       if (update_multicast) {
+               SMC_SELECT_BANK(lp, 3);
+               SMC_SET_MCAST(lp, multicast_table);
+       }
+       SMC_SELECT_BANK(lp, 2);
+       spin_unlock_irq(&lp->lock);
+}
+
+
+/*
+ * Open and Initialize the board
+ *
+ * Set up everything, reset the card, etc..
+ */
+static int
+smc_open(struct net_device *dev)
+{
+       struct smc_local *lp = netdev_priv(dev);
+
+       DBG(2, "%s: %s\n", dev->name, __func__);
+
+       /*
+        * Check that the address is valid.  If its not, refuse
+        * to bring the device up.  The user must specify an
+        * address using ifconfig eth0 hw ether xx:xx:xx:xx:xx:xx
+        */
+       if (!is_valid_ether_addr(dev->dev_addr)) {
+               PRINTK("%s: no valid ethernet hw addr\n", __func__);
+               return -EINVAL;
+       }
+
+       /* Setup the default Register Modes */
+       lp->tcr_cur_mode = TCR_DEFAULT;
+       lp->rcr_cur_mode = RCR_DEFAULT;
+       lp->rpc_cur_mode = RPC_DEFAULT |
+                               lp->cfg.leda << RPC_LSXA_SHFT |
+                               lp->cfg.ledb << RPC_LSXB_SHFT;
+
+       /*
+        * If we are not using a MII interface, we need to
+        * monitor our own carrier signal to detect faults.
+        */
+       if (lp->phy_type == 0)
+               lp->tcr_cur_mode |= TCR_MON_CSN;
+
+       /* reset the hardware */
+       smc_reset(dev);
+       smc_enable(dev);
+
+       /* Configure the PHY, initialize the link state */
+       if (lp->phy_type != 0)
+               smc_phy_configure(&lp->phy_configure);
+       else {
+               spin_lock_irq(&lp->lock);
+               smc_10bt_check_media(dev, 1);
+               spin_unlock_irq(&lp->lock);
+       }
+
+       netif_start_queue(dev);
+       return 0;
+}
+
+/*
+ * smc_close
+ *
+ * this makes the board clean up everything that it can
+ * and not talk to the outside world.   Caused by
+ * an 'ifconfig ethX down'
+ */
+static int smc_close(struct net_device *dev)
+{
+       struct smc_local *lp = netdev_priv(dev);
+
+       DBG(2, "%s: %s\n", dev->name, __func__);
+
+       netif_stop_queue(dev);
+       netif_carrier_off(dev);
+
+       /* clear everything */
+       smc_shutdown(dev);
+       tasklet_kill(&lp->tx_task);
+       smc_phy_powerdown(dev);
+       return 0;
+}
+
+/*
+ * Ethtool support
+ */
+static int
+smc_ethtool_getsettings(struct net_device *dev, struct ethtool_cmd *cmd)
+{
+       struct smc_local *lp = netdev_priv(dev);
+       int ret;
+
+       cmd->maxtxpkt = 1;
+       cmd->maxrxpkt = 1;
+
+       if (lp->phy_type != 0) {
+               spin_lock_irq(&lp->lock);
+               ret = mii_ethtool_gset(&lp->mii, cmd);
+               spin_unlock_irq(&lp->lock);
+       } else {
+               cmd->supported = SUPPORTED_10baseT_Half |
+                                SUPPORTED_10baseT_Full |
+                                SUPPORTED_TP | SUPPORTED_AUI;
+
+               if (lp->ctl_rspeed == 10)
+                       ethtool_cmd_speed_set(cmd, SPEED_10);
+               else if (lp->ctl_rspeed == 100)
+                       ethtool_cmd_speed_set(cmd, SPEED_100);
+
+               cmd->autoneg = AUTONEG_DISABLE;
+               cmd->transceiver = XCVR_INTERNAL;
+               cmd->port = 0;
+               cmd->duplex = lp->tcr_cur_mode & TCR_SWFDUP ? DUPLEX_FULL : DUPLEX_HALF;
+
+               ret = 0;
+       }
+
+       return ret;
+}
+
+static int
+smc_ethtool_setsettings(struct net_device *dev, struct ethtool_cmd *cmd)
+{
+       struct smc_local *lp = netdev_priv(dev);
+       int ret;
+
+       if (lp->phy_type != 0) {
+               spin_lock_irq(&lp->lock);
+               ret = mii_ethtool_sset(&lp->mii, cmd);
+               spin_unlock_irq(&lp->lock);
+       } else {
+               if (cmd->autoneg != AUTONEG_DISABLE ||
+                   cmd->speed != SPEED_10 ||
+                   (cmd->duplex != DUPLEX_HALF && cmd->duplex != DUPLEX_FULL) ||
+                   (cmd->port != PORT_TP && cmd->port != PORT_AUI))
+                       return -EINVAL;
+
+//             lp->port = cmd->port;
+               lp->ctl_rfduplx = cmd->duplex == DUPLEX_FULL;
+
+//             if (netif_running(dev))
+//                     smc_set_port(dev);
+
+               ret = 0;
+       }
+
+       return ret;
+}
+
+static void
+smc_ethtool_getdrvinfo(struct net_device *dev, struct ethtool_drvinfo *info)
+{
+       strncpy(info->driver, CARDNAME, sizeof(info->driver));
+       strncpy(info->version, version, sizeof(info->version));
+       strncpy(info->bus_info, dev_name(dev->dev.parent), sizeof(info->bus_info));
+}
+
+static int smc_ethtool_nwayreset(struct net_device *dev)
+{
+       struct smc_local *lp = netdev_priv(dev);
+       int ret = -EINVAL;
+
+       if (lp->phy_type != 0) {
+               spin_lock_irq(&lp->lock);
+               ret = mii_nway_restart(&lp->mii);
+               spin_unlock_irq(&lp->lock);
+       }
+
+       return ret;
+}
+
+static u32 smc_ethtool_getmsglevel(struct net_device *dev)
+{
+       struct smc_local *lp = netdev_priv(dev);
+       return lp->msg_enable;
+}
+
+static void smc_ethtool_setmsglevel(struct net_device *dev, u32 level)
+{
+       struct smc_local *lp = netdev_priv(dev);
+       lp->msg_enable = level;
+}
+
+static int smc_write_eeprom_word(struct net_device *dev, u16 addr, u16 word)
+{
+       u16 ctl;
+       struct smc_local *lp = netdev_priv(dev);
+       void __iomem *ioaddr = lp->base;
+
+       spin_lock_irq(&lp->lock);
+       /* load word into GP register */
+       SMC_SELECT_BANK(lp, 1);
+       SMC_SET_GP(lp, word);
+       /* set the address to put the data in EEPROM */
+       SMC_SELECT_BANK(lp, 2);
+       SMC_SET_PTR(lp, addr);
+       /* tell it to write */
+       SMC_SELECT_BANK(lp, 1);
+       ctl = SMC_GET_CTL(lp);
+       SMC_SET_CTL(lp, ctl | (CTL_EEPROM_SELECT | CTL_STORE));
+       /* wait for it to finish */
+       do {
+               udelay(1);
+       } while (SMC_GET_CTL(lp) & CTL_STORE);
+       /* clean up */
+       SMC_SET_CTL(lp, ctl);
+       SMC_SELECT_BANK(lp, 2);
+       spin_unlock_irq(&lp->lock);
+       return 0;
+}
+
+static int smc_read_eeprom_word(struct net_device *dev, u16 addr, u16 *word)
+{
+       u16 ctl;
+       struct smc_local *lp = netdev_priv(dev);
+       void __iomem *ioaddr = lp->base;
+
+       spin_lock_irq(&lp->lock);
+       /* set the EEPROM address to get the data from */
+       SMC_SELECT_BANK(lp, 2);
+       SMC_SET_PTR(lp, addr | PTR_READ);
+       /* tell it to load */
+       SMC_SELECT_BANK(lp, 1);
+       SMC_SET_GP(lp, 0xffff); /* init to known */
+       ctl = SMC_GET_CTL(lp);
+       SMC_SET_CTL(lp, ctl | (CTL_EEPROM_SELECT | CTL_RELOAD));
+       /* wait for it to finish */
+       do {
+               udelay(1);
+       } while (SMC_GET_CTL(lp) & CTL_RELOAD);
+       /* read word from GP register */
+       *word = SMC_GET_GP(lp);
+       /* clean up */
+       SMC_SET_CTL(lp, ctl);
+       SMC_SELECT_BANK(lp, 2);
+       spin_unlock_irq(&lp->lock);
+       return 0;
+}
+
+static int smc_ethtool_geteeprom_len(struct net_device *dev)
+{
+       return 0x23 * 2;
+}
+
+static int smc_ethtool_geteeprom(struct net_device *dev,
+               struct ethtool_eeprom *eeprom, u8 *data)
+{
+       int i;
+       int imax;
+
+       DBG(1, "Reading %d bytes at %d(0x%x)\n",
+               eeprom->len, eeprom->offset, eeprom->offset);
+       imax = smc_ethtool_geteeprom_len(dev);
+       for (i = 0; i < eeprom->len; i += 2) {
+               int ret;
+               u16 wbuf;
+               int offset = i + eeprom->offset;
+               if (offset > imax)
+                       break;
+               ret = smc_read_eeprom_word(dev, offset >> 1, &wbuf);
+               if (ret != 0)
+                       return ret;
+               DBG(2, "Read 0x%x from 0x%x\n", wbuf, offset >> 1);
+               data[i] = (wbuf >> 8) & 0xff;
+               data[i+1] = wbuf & 0xff;
+       }
+       return 0;
+}
+
+static int smc_ethtool_seteeprom(struct net_device *dev,
+               struct ethtool_eeprom *eeprom, u8 *data)
+{
+       int i;
+       int imax;
+
+       DBG(1, "Writing %d bytes to %d(0x%x)\n",
+                       eeprom->len, eeprom->offset, eeprom->offset);
+       imax = smc_ethtool_geteeprom_len(dev);
+       for (i = 0; i < eeprom->len; i += 2) {
+               int ret;
+               u16 wbuf;
+               int offset = i + eeprom->offset;
+               if (offset > imax)
+                       break;
+               wbuf = (data[i] << 8) | data[i + 1];
+               DBG(2, "Writing 0x%x to 0x%x\n", wbuf, offset >> 1);
+               ret = smc_write_eeprom_word(dev, offset >> 1, wbuf);
+               if (ret != 0)
+                       return ret;
+       }
+       return 0;
+}
+
+
+static const struct ethtool_ops smc_ethtool_ops = {
+       .get_settings   = smc_ethtool_getsettings,
+       .set_settings   = smc_ethtool_setsettings,
+       .get_drvinfo    = smc_ethtool_getdrvinfo,
+
+       .get_msglevel   = smc_ethtool_getmsglevel,
+       .set_msglevel   = smc_ethtool_setmsglevel,
+       .nway_reset     = smc_ethtool_nwayreset,
+       .get_link       = ethtool_op_get_link,
+       .get_eeprom_len = smc_ethtool_geteeprom_len,
+       .get_eeprom     = smc_ethtool_geteeprom,
+       .set_eeprom     = smc_ethtool_seteeprom,
+};
+
+static const struct net_device_ops smc_netdev_ops = {
+       .ndo_open               = smc_open,
+       .ndo_stop               = smc_close,
+       .ndo_start_xmit         = smc_hard_start_xmit,
+       .ndo_tx_timeout         = smc_timeout,
+       .ndo_set_multicast_list = smc_set_multicast_list,
+       .ndo_change_mtu         = eth_change_mtu,
+       .ndo_validate_addr      = eth_validate_addr,
+       .ndo_set_mac_address    = eth_mac_addr,
+#ifdef CONFIG_NET_POLL_CONTROLLER
+       .ndo_poll_controller    = smc_poll_controller,
+#endif
+};
+
+/*
+ * smc_findirq
+ *
+ * This routine has a simple purpose -- make the SMC chip generate an
+ * interrupt, so an auto-detect routine can detect it, and find the IRQ,
+ */
+/*
+ * does this still work?
+ *
+ * I just deleted auto_irq.c, since it was never built...
+ *   --jgarzik
+ */
+static int __devinit smc_findirq(struct smc_local *lp)
+{
+       void __iomem *ioaddr = lp->base;
+       int timeout = 20;
+       unsigned long cookie;
+
+       DBG(2, "%s: %s\n", CARDNAME, __func__);
+
+       cookie = probe_irq_on();
+
+       /*
+        * What I try to do here is trigger an ALLOC_INT. This is done
+        * by allocating a small chunk of memory, which will give an interrupt
+        * when done.
+        */
+       /* enable ALLOCation interrupts ONLY */
+       SMC_SELECT_BANK(lp, 2);
+       SMC_SET_INT_MASK(lp, IM_ALLOC_INT);
+
+       /*
+        * Allocate 512 bytes of memory.  Note that the chip was just
+        * reset so all the memory is available
+        */
+       SMC_SET_MMU_CMD(lp, MC_ALLOC | 1);
+
+       /*
+        * Wait until positive that the interrupt has been generated
+        */
+       do {
+               int int_status;
+               udelay(10);
+               int_status = SMC_GET_INT(lp);
+               if (int_status & IM_ALLOC_INT)
+                       break;          /* got the interrupt */
+       } while (--timeout);
+
+       /*
+        * there is really nothing that I can do here if timeout fails,
+        * as autoirq_report will return a 0 anyway, which is what I
+        * want in this case.   Plus, the clean up is needed in both
+        * cases.
+        */
+
+       /* and disable all interrupts again */
+       SMC_SET_INT_MASK(lp, 0);
+
+       /* and return what I found */
+       return probe_irq_off(cookie);
+}
+
+/*
+ * Function: smc_probe(unsigned long ioaddr)
+ *
+ * Purpose:
+ *     Tests to see if a given ioaddr points to an SMC91x chip.
+ *     Returns a 0 on success
+ *
+ * Algorithm:
+ *     (1) see if the high byte of BANK_SELECT is 0x33
+ *     (2) compare the ioaddr with the base register's address
+ *     (3) see if I recognize the chip ID in the appropriate register
+ *
+ * Here I do typical initialization tasks.
+ *
+ * o  Initialize the structure if needed
+ * o  print out my vanity message if not done so already
+ * o  print out what type of hardware is detected
+ * o  print out the ethernet address
+ * o  find the IRQ
+ * o  set up my private data
+ * o  configure the dev structure with my subroutines
+ * o  actually GRAB the irq.
+ * o  GRAB the region
+ */
+static int __devinit smc_probe(struct net_device *dev, void __iomem *ioaddr,
+                           unsigned long irq_flags)
+{
+       struct smc_local *lp = netdev_priv(dev);
+       static int version_printed = 0;
+       int retval;
+       unsigned int val, revision_register;
+       const char *version_string;
+
+       DBG(2, "%s: %s\n", CARDNAME, __func__);
+
+       /* First, see if the high byte is 0x33 */
+       val = SMC_CURRENT_BANK(lp);
+       DBG(2, "%s: bank signature probe returned 0x%04x\n", CARDNAME, val);
+       if ((val & 0xFF00) != 0x3300) {
+               if ((val & 0xFF) == 0x33) {
+                       printk(KERN_WARNING
+                               "%s: Detected possible byte-swapped interface"
+                               " at IOADDR %p\n", CARDNAME, ioaddr);
+               }
+               retval = -ENODEV;
+               goto err_out;
+       }
+
+       /*
+        * The above MIGHT indicate a device, but I need to write to
+        * further test this.
+        */
+       SMC_SELECT_BANK(lp, 0);
+       val = SMC_CURRENT_BANK(lp);
+       if ((val & 0xFF00) != 0x3300) {
+               retval = -ENODEV;
+               goto err_out;
+       }
+
+       /*
+        * well, we've already written once, so hopefully another
+        * time won't hurt.  This time, I need to switch the bank
+        * register to bank 1, so I can access the base address
+        * register
+        */
+       SMC_SELECT_BANK(lp, 1);
+       val = SMC_GET_BASE(lp);
+       val = ((val & 0x1F00) >> 3) << SMC_IO_SHIFT;
+       if (((unsigned int)ioaddr & (0x3e0 << SMC_IO_SHIFT)) != val) {
+               printk("%s: IOADDR %p doesn't match configuration (%x).\n",
+                       CARDNAME, ioaddr, val);
+       }
+
+       /*
+        * check if the revision register is something that I
+        * recognize.  These might need to be added to later,
+        * as future revisions could be added.
+        */
+       SMC_SELECT_BANK(lp, 3);
+       revision_register = SMC_GET_REV(lp);
+       DBG(2, "%s: revision = 0x%04x\n", CARDNAME, revision_register);
+       version_string = chip_ids[ (revision_register >> 4) & 0xF];
+       if (!version_string || (revision_register & 0xff00) != 0x3300) {
+               /* I don't recognize this chip, so... */
+               printk("%s: IO %p: Unrecognized revision register 0x%04x"
+                       ", Contact author.\n", CARDNAME,
+                       ioaddr, revision_register);
+
+               retval = -ENODEV;
+               goto err_out;
+       }
+
+       /* At this point I'll assume that the chip is an SMC91x. */
+       if (version_printed++ == 0)
+               printk("%s", version);
+
+       /* fill in some of the fields */
+       dev->base_addr = (unsigned long)ioaddr;
+       lp->base = ioaddr;
+       lp->version = revision_register & 0xff;
+       spin_lock_init(&lp->lock);
+
+       /* Get the MAC address */
+       SMC_SELECT_BANK(lp, 1);
+       SMC_GET_MAC_ADDR(lp, dev->dev_addr);
+
+       /* now, reset the chip, and put it into a known state */
+       smc_reset(dev);
+
+       /*
+        * If dev->irq is 0, then the device has to be banged on to see
+        * what the IRQ is.
+        *
+        * This banging doesn't always detect the IRQ, for unknown reasons.
+        * a workaround is to reset the chip and try again.
+        *
+        * Interestingly, the DOS packet driver *SETS* the IRQ on the card to
+        * be what is requested on the command line.   I don't do that, mostly
+        * because the card that I have uses a non-standard method of accessing
+        * the IRQs, and because this _should_ work in most configurations.
+        *
+        * Specifying an IRQ is done with the assumption that the user knows
+        * what (s)he is doing.  No checking is done!!!!
+        */
+       if (dev->irq < 1) {
+               int trials;
+
+               trials = 3;
+               while (trials--) {
+                       dev->irq = smc_findirq(lp);
+                       if (dev->irq)
+                               break;
+                       /* kick the card and try again */
+                       smc_reset(dev);
+               }
+       }
+       if (dev->irq == 0) {
+               printk("%s: Couldn't autodetect your IRQ. Use irq=xx.\n",
+                       dev->name);
+               retval = -ENODEV;
+               goto err_out;
+       }
+       dev->irq = irq_canonicalize(dev->irq);
+
+       /* Fill in the fields of the device structure with ethernet values. */
+       ether_setup(dev);
+
+       dev->watchdog_timeo = msecs_to_jiffies(watchdog);
+       dev->netdev_ops = &smc_netdev_ops;
+       dev->ethtool_ops = &smc_ethtool_ops;
+
+       tasklet_init(&lp->tx_task, smc_hardware_send_pkt, (unsigned long)dev);
+       INIT_WORK(&lp->phy_configure, smc_phy_configure);
+       lp->dev = dev;
+       lp->mii.phy_id_mask = 0x1f;
+       lp->mii.reg_num_mask = 0x1f;
+       lp->mii.force_media = 0;
+       lp->mii.full_duplex = 0;
+       lp->mii.dev = dev;
+       lp->mii.mdio_read = smc_phy_read;
+       lp->mii.mdio_write = smc_phy_write;
+
+       /*
+        * Locate the phy, if any.
+        */
+       if (lp->version >= (CHIP_91100 << 4))
+               smc_phy_detect(dev);
+
+       /* then shut everything down to save power */
+       smc_shutdown(dev);
+       smc_phy_powerdown(dev);
+
+       /* Set default parameters */
+       lp->msg_enable = NETIF_MSG_LINK;
+       lp->ctl_rfduplx = 0;
+       lp->ctl_rspeed = 10;
+
+       if (lp->version >= (CHIP_91100 << 4)) {
+               lp->ctl_rfduplx = 1;
+               lp->ctl_rspeed = 100;
+       }
+
+       /* Grab the IRQ */
+       retval = request_irq(dev->irq, smc_interrupt, irq_flags, dev->name, dev);
+       if (retval)
+               goto err_out;
+
+#ifdef CONFIG_ARCH_PXA
+#  ifdef SMC_USE_PXA_DMA
+       lp->cfg.flags |= SMC91X_USE_DMA;
+#  endif
+       if (lp->cfg.flags & SMC91X_USE_DMA) {
+               int dma = pxa_request_dma(dev->name, DMA_PRIO_LOW,
+                                         smc_pxa_dma_irq, NULL);
+               if (dma >= 0)
+                       dev->dma = dma;
+       }
+#endif
+
+       retval = register_netdev(dev);
+       if (retval == 0) {
+               /* now, print out the card info, in a short format.. */
+               printk("%s: %s (rev %d) at %p IRQ %d",
+                       dev->name, version_string, revision_register & 0x0f,
+                       lp->base, dev->irq);
+
+               if (dev->dma != (unsigned char)-1)
+                       printk(" DMA %d", dev->dma);
+
+               printk("%s%s\n",
+                       lp->cfg.flags & SMC91X_NOWAIT ? " [nowait]" : "",
+                       THROTTLE_TX_PKTS ? " [throttle_tx]" : "");
+
+               if (!is_valid_ether_addr(dev->dev_addr)) {
+                       printk("%s: Invalid ethernet MAC address.  Please "
+                              "set using ifconfig\n", dev->name);
+               } else {
+                       /* Print the Ethernet address */
+                       printk("%s: Ethernet addr: %pM\n",
+                              dev->name, dev->dev_addr);
+               }
+
+               if (lp->phy_type == 0) {
+                       PRINTK("%s: No PHY found\n", dev->name);
+               } else if ((lp->phy_type & 0xfffffff0) == 0x0016f840) {
+                       PRINTK("%s: PHY LAN83C183 (LAN91C111 Internal)\n", dev->name);
+               } else if ((lp->phy_type & 0xfffffff0) == 0x02821c50) {
+                       PRINTK("%s: PHY LAN83C180\n", dev->name);
+               }
+       }
+
+err_out:
+#ifdef CONFIG_ARCH_PXA
+       if (retval && dev->dma != (unsigned char)-1)
+               pxa_free_dma(dev->dma);
+#endif
+       return retval;
+}
+
+static int smc_enable_device(struct platform_device *pdev)
+{
+       struct net_device *ndev = platform_get_drvdata(pdev);
+       struct smc_local *lp = netdev_priv(ndev);
+       unsigned long flags;
+       unsigned char ecor, ecsr;
+       void __iomem *addr;
+       struct resource * res;
+
+       res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "smc91x-attrib");
+       if (!res)
+               return 0;
+
+       /*
+        * Map the attribute space.  This is overkill, but clean.
+        */
+       addr = ioremap(res->start, ATTRIB_SIZE);
+       if (!addr)
+               return -ENOMEM;
+
+       /*
+        * Reset the device.  We must disable IRQs around this
+        * since a reset causes the IRQ line become active.
+        */
+       local_irq_save(flags);
+       ecor = readb(addr + (ECOR << SMC_IO_SHIFT)) & ~ECOR_RESET;
+       writeb(ecor | ECOR_RESET, addr + (ECOR << SMC_IO_SHIFT));
+       readb(addr + (ECOR << SMC_IO_SHIFT));
+
+       /*
+        * Wait 100us for the chip to reset.
+        */
+       udelay(100);
+
+       /*
+        * The device will ignore all writes to the enable bit while
+        * reset is asserted, even if the reset bit is cleared in the
+        * same write.  Must clear reset first, then enable the device.
+        */
+       writeb(ecor, addr + (ECOR << SMC_IO_SHIFT));
+       writeb(ecor | ECOR_ENABLE, addr + (ECOR << SMC_IO_SHIFT));
+
+       /*
+        * Set the appropriate byte/word mode.
+        */
+       ecsr = readb(addr + (ECSR << SMC_IO_SHIFT)) & ~ECSR_IOIS8;
+       if (!SMC_16BIT(lp))
+               ecsr |= ECSR_IOIS8;
+       writeb(ecsr, addr + (ECSR << SMC_IO_SHIFT));
+       local_irq_restore(flags);
+
+       iounmap(addr);
+
+       /*
+        * Wait for the chip to wake up.  We could poll the control
+        * register in the main register space, but that isn't mapped
+        * yet.  We know this is going to take 750us.
+        */
+       msleep(1);
+
+       return 0;
+}
+
+static int smc_request_attrib(struct platform_device *pdev,
+                             struct net_device *ndev)
+{
+       struct resource * res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "smc91x-attrib");
+       struct smc_local *lp __maybe_unused = netdev_priv(ndev);
+
+       if (!res)
+               return 0;
+
+       if (!request_mem_region(res->start, ATTRIB_SIZE, CARDNAME))
+               return -EBUSY;
+
+       return 0;
+}
+
+static void smc_release_attrib(struct platform_device *pdev,
+                              struct net_device *ndev)
+{
+       struct resource * res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "smc91x-attrib");
+       struct smc_local *lp __maybe_unused = netdev_priv(ndev);
+
+       if (res)
+               release_mem_region(res->start, ATTRIB_SIZE);
+}
+
+static inline void smc_request_datacs(struct platform_device *pdev, struct net_device *ndev)
+{
+       if (SMC_CAN_USE_DATACS) {
+               struct resource * res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "smc91x-data32");
+               struct smc_local *lp = netdev_priv(ndev);
+
+               if (!res)
+                       return;
+
+               if(!request_mem_region(res->start, SMC_DATA_EXTENT, CARDNAME)) {
+                       printk(KERN_INFO "%s: failed to request datacs memory region.\n", CARDNAME);
+                       return;
+               }
+
+               lp->datacs = ioremap(res->start, SMC_DATA_EXTENT);
+       }
+}
+
+static void smc_release_datacs(struct platform_device *pdev, struct net_device *ndev)
+{
+       if (SMC_CAN_USE_DATACS) {
+               struct smc_local *lp = netdev_priv(ndev);
+               struct resource * res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "smc91x-data32");
+
+               if (lp->datacs)
+                       iounmap(lp->datacs);
+
+               lp->datacs = NULL;
+
+               if (res)
+                       release_mem_region(res->start, SMC_DATA_EXTENT);
+       }
+}
+
+/*
+ * smc_init(void)
+ *   Input parameters:
+ *     dev->base_addr == 0, try to find all possible locations
+ *     dev->base_addr > 0x1ff, this is the address to check
+ *     dev->base_addr == <anything else>, return failure code
+ *
+ *   Output:
+ *     0 --> there is a device
+ *     anything else, error
+ */
+static int __devinit smc_drv_probe(struct platform_device *pdev)
+{
+       struct smc91x_platdata *pd = pdev->dev.platform_data;
+       struct smc_local *lp;
+       struct net_device *ndev;
+       struct resource *res, *ires;
+       unsigned int __iomem *addr;
+       unsigned long irq_flags = SMC_IRQ_FLAGS;
+       int ret;
+
+       ndev = alloc_etherdev(sizeof(struct smc_local));
+       if (!ndev) {
+               printk("%s: could not allocate device.\n", CARDNAME);
+               ret = -ENOMEM;
+               goto out;
+       }
+       SET_NETDEV_DEV(ndev, &pdev->dev);
+
+       /* get configuration from platform data, only allow use of
+        * bus width if both SMC_CAN_USE_xxx and SMC91X_USE_xxx are set.
+        */
+
+       lp = netdev_priv(ndev);
+
+       if (pd) {
+               memcpy(&lp->cfg, pd, sizeof(lp->cfg));
+               lp->io_shift = SMC91X_IO_SHIFT(lp->cfg.flags);
+       } else {
+               lp->cfg.flags |= (SMC_CAN_USE_8BIT)  ? SMC91X_USE_8BIT  : 0;
+               lp->cfg.flags |= (SMC_CAN_USE_16BIT) ? SMC91X_USE_16BIT : 0;
+               lp->cfg.flags |= (SMC_CAN_USE_32BIT) ? SMC91X_USE_32BIT : 0;
+               lp->cfg.flags |= (nowait) ? SMC91X_NOWAIT : 0;
+       }
+
+       if (!lp->cfg.leda && !lp->cfg.ledb) {
+               lp->cfg.leda = RPC_LSA_DEFAULT;
+               lp->cfg.ledb = RPC_LSB_DEFAULT;
+       }
+
+       ndev->dma = (unsigned char)-1;
+
+       res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "smc91x-regs");
+       if (!res)
+               res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+       if (!res) {
+               ret = -ENODEV;
+               goto out_free_netdev;
+       }
+
+
+       if (!request_mem_region(res->start, SMC_IO_EXTENT, CARDNAME)) {
+               ret = -EBUSY;
+               goto out_free_netdev;
+       }
+
+       ires = platform_get_resource(pdev, IORESOURCE_IRQ, 0);
+       if (!ires) {
+               ret = -ENODEV;
+               goto out_release_io;
+       }
+
+       ndev->irq = ires->start;
+
+       if (irq_flags == -1 || ires->flags & IRQF_TRIGGER_MASK)
+               irq_flags = ires->flags & IRQF_TRIGGER_MASK;
+
+       ret = smc_request_attrib(pdev, ndev);
+       if (ret)
+               goto out_release_io;
+#if defined(CONFIG_SA1100_ASSABET)
+       NCR_0 |= NCR_ENET_OSC_EN;
+#endif
+       platform_set_drvdata(pdev, ndev);
+       ret = smc_enable_device(pdev);
+       if (ret)
+               goto out_release_attrib;
+
+       addr = ioremap(res->start, SMC_IO_EXTENT);
+       if (!addr) {
+               ret = -ENOMEM;
+               goto out_release_attrib;
+       }
+
+#ifdef CONFIG_ARCH_PXA
+       {
+               struct smc_local *lp = netdev_priv(ndev);
+               lp->device = &pdev->dev;
+               lp->physaddr = res->start;
+       }
+#endif
+
+       ret = smc_probe(ndev, addr, irq_flags);
+       if (ret != 0)
+               goto out_iounmap;
+
+       smc_request_datacs(pdev, ndev);
+
+       return 0;
+
+ out_iounmap:
+       platform_set_drvdata(pdev, NULL);
+       iounmap(addr);
+ out_release_attrib:
+       smc_release_attrib(pdev, ndev);
+ out_release_io:
+       release_mem_region(res->start, SMC_IO_EXTENT);
+ out_free_netdev:
+       free_netdev(ndev);
+ out:
+       printk("%s: not found (%d).\n", CARDNAME, ret);
+
+       return ret;
+}
+
+static int __devexit smc_drv_remove(struct platform_device *pdev)
+{
+       struct net_device *ndev = platform_get_drvdata(pdev);
+       struct smc_local *lp = netdev_priv(ndev);
+       struct resource *res;
+
+       platform_set_drvdata(pdev, NULL);
+
+       unregister_netdev(ndev);
+
+       free_irq(ndev->irq, ndev);
+
+#ifdef CONFIG_ARCH_PXA
+       if (ndev->dma != (unsigned char)-1)
+               pxa_free_dma(ndev->dma);
+#endif
+       iounmap(lp->base);
+
+       smc_release_datacs(pdev,ndev);
+       smc_release_attrib(pdev,ndev);
+
+       res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "smc91x-regs");
+       if (!res)
+               res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+       release_mem_region(res->start, SMC_IO_EXTENT);
+
+       free_netdev(ndev);
+
+       return 0;
+}
+
+static int smc_drv_suspend(struct device *dev)
+{
+       struct platform_device *pdev = to_platform_device(dev);
+       struct net_device *ndev = platform_get_drvdata(pdev);
+
+       if (ndev) {
+               if (netif_running(ndev)) {
+                       netif_device_detach(ndev);
+                       smc_shutdown(ndev);
+                       smc_phy_powerdown(ndev);
+               }
+       }
+       return 0;
+}
+
+static int smc_drv_resume(struct device *dev)
+{
+       struct platform_device *pdev = to_platform_device(dev);
+       struct net_device *ndev = platform_get_drvdata(pdev);
+
+       if (ndev) {
+               struct smc_local *lp = netdev_priv(ndev);
+               smc_enable_device(pdev);
+               if (netif_running(ndev)) {
+                       smc_reset(ndev);
+                       smc_enable(ndev);
+                       if (lp->phy_type != 0)
+                               smc_phy_configure(&lp->phy_configure);
+                       netif_device_attach(ndev);
+               }
+       }
+       return 0;
+}
+
+#ifdef CONFIG_OF
+static const struct of_device_id smc91x_match[] = {
+       { .compatible = "smsc,lan91c94", },
+       { .compatible = "smsc,lan91c111", },
+       {},
+};
+MODULE_DEVICE_TABLE(of, smc91x_match);
+#else
+#define smc91x_match NULL
+#endif
+
+static struct dev_pm_ops smc_drv_pm_ops = {
+       .suspend        = smc_drv_suspend,
+       .resume         = smc_drv_resume,
+};
+
+static struct platform_driver smc_driver = {
+       .probe          = smc_drv_probe,
+       .remove         = __devexit_p(smc_drv_remove),
+       .driver         = {
+               .name   = CARDNAME,
+               .owner  = THIS_MODULE,
+               .pm     = &smc_drv_pm_ops,
+               .of_match_table = smc91x_match,
+       },
+};
+
+static int __init smc_init(void)
+{
+       return platform_driver_register(&smc_driver);
+}
+
+static void __exit smc_cleanup(void)
+{
+       platform_driver_unregister(&smc_driver);
+}
+
+module_init(smc_init);
+module_exit(smc_cleanup);
diff --git a/drivers/net/ethernet/smsc/smc91x.h b/drivers/net/ethernet/smsc/smc91x.h
new file mode 100644 (file)
index 0000000..5f53fbb
--- /dev/null
@@ -0,0 +1,1180 @@
+/*------------------------------------------------------------------------
+ . smc91x.h - macros for SMSC's 91C9x/91C1xx single-chip Ethernet device.
+ .
+ . Copyright (C) 1996 by Erik Stahlman
+ . Copyright (C) 2001 Standard Microsystems Corporation
+ .     Developed by Simple Network Magic Corporation
+ . Copyright (C) 2003 Monta Vista Software, Inc.
+ .     Unified SMC91x driver by Nicolas Pitre
+ .
+ . This program is free software; you can redistribute it and/or modify
+ . it under the terms of the GNU General Public License as published by
+ . the Free Software Foundation; either version 2 of the License, or
+ . (at your option) any later version.
+ .
+ . This program is distributed in the hope that it will be useful,
+ . but WITHOUT ANY WARRANTY; without even the implied warranty of
+ . MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ . GNU General Public License for more details.
+ .
+ . You should have received a copy of the GNU General Public License
+ . along with this program; if not, write to the Free Software
+ . Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ .
+ . Information contained in this file was obtained from the LAN91C111
+ . manual from SMC.  To get a copy, if you really want one, you can find
+ . information under www.smsc.com.
+ .
+ . Authors
+ .     Erik Stahlman           <erik@vt.edu>
+ .     Daris A Nevil           <dnevil@snmc.com>
+ .     Nicolas Pitre           <nico@fluxnic.net>
+ .
+ ---------------------------------------------------------------------------*/
+#ifndef _SMC91X_H_
+#define _SMC91X_H_
+
+#include <linux/smc91x.h>
+
+/*
+ * Define your architecture specific bus configuration parameters here.
+ */
+
+#if defined(CONFIG_ARCH_LUBBOCK) ||\
+    defined(CONFIG_MACH_MAINSTONE) ||\
+    defined(CONFIG_MACH_ZYLONITE) ||\
+    defined(CONFIG_MACH_LITTLETON) ||\
+    defined(CONFIG_MACH_ZYLONITE2) ||\
+    defined(CONFIG_ARCH_VIPER) ||\
+    defined(CONFIG_MACH_STARGATE2)
+
+#include <asm/mach-types.h>
+
+/* Now the bus width is specified in the platform data
+ * pretend here to support all I/O access types
+ */
+#define SMC_CAN_USE_8BIT       1
+#define SMC_CAN_USE_16BIT      1
+#define SMC_CAN_USE_32BIT      1
+#define SMC_NOWAIT             1
+
+#define SMC_IO_SHIFT           (lp->io_shift)
+
+#define SMC_inb(a, r)          readb((a) + (r))
+#define SMC_inw(a, r)          readw((a) + (r))
+#define SMC_inl(a, r)          readl((a) + (r))
+#define SMC_outb(v, a, r)      writeb(v, (a) + (r))
+#define SMC_outl(v, a, r)      writel(v, (a) + (r))
+#define SMC_insw(a, r, p, l)   readsw((a) + (r), p, l)
+#define SMC_outsw(a, r, p, l)  writesw((a) + (r), p, l)
+#define SMC_insl(a, r, p, l)   readsl((a) + (r), p, l)
+#define SMC_outsl(a, r, p, l)  writesl((a) + (r), p, l)
+#define SMC_IRQ_FLAGS          (-1)    /* from resource */
+
+/* We actually can't write halfwords properly if not word aligned */
+static inline void SMC_outw(u16 val, void __iomem *ioaddr, int reg)
+{
+       if ((machine_is_mainstone() || machine_is_stargate2()) && reg & 2) {
+               unsigned int v = val << 16;
+               v |= readl(ioaddr + (reg & ~2)) & 0xffff;
+               writel(v, ioaddr + (reg & ~2));
+       } else {
+               writew(val, ioaddr + reg);
+       }
+}
+
+#elif defined(CONFIG_SA1100_PLEB)
+/* We can only do 16-bit reads and writes in the static memory space. */
+#define SMC_CAN_USE_8BIT       1
+#define SMC_CAN_USE_16BIT      1
+#define SMC_CAN_USE_32BIT      0
+#define SMC_IO_SHIFT           0
+#define SMC_NOWAIT             1
+
+#define SMC_inb(a, r)          readb((a) + (r))
+#define SMC_insb(a, r, p, l)   readsb((a) + (r), p, (l))
+#define SMC_inw(a, r)          readw((a) + (r))
+#define SMC_insw(a, r, p, l)   readsw((a) + (r), p, l)
+#define SMC_outb(v, a, r)      writeb(v, (a) + (r))
+#define SMC_outsb(a, r, p, l)  writesb((a) + (r), p, (l))
+#define SMC_outw(v, a, r)      writew(v, (a) + (r))
+#define SMC_outsw(a, r, p, l)  writesw((a) + (r), p, l)
+
+#define SMC_IRQ_FLAGS          (-1)
+
+#elif defined(CONFIG_SA1100_ASSABET)
+
+#include <mach/neponset.h>
+
+/* We can only do 8-bit reads and writes in the static memory space. */
+#define SMC_CAN_USE_8BIT       1
+#define SMC_CAN_USE_16BIT      0
+#define SMC_CAN_USE_32BIT      0
+#define SMC_NOWAIT             1
+
+/* The first two address lines aren't connected... */
+#define SMC_IO_SHIFT           2
+
+#define SMC_inb(a, r)          readb((a) + (r))
+#define SMC_outb(v, a, r)      writeb(v, (a) + (r))
+#define SMC_insb(a, r, p, l)   readsb((a) + (r), p, (l))
+#define SMC_outsb(a, r, p, l)  writesb((a) + (r), p, (l))
+#define SMC_IRQ_FLAGS          (-1)    /* from resource */
+
+#elif  defined(CONFIG_MACH_LOGICPD_PXA270) ||  \
+       defined(CONFIG_MACH_NOMADIK_8815NHK)
+
+#define SMC_CAN_USE_8BIT       0
+#define SMC_CAN_USE_16BIT      1
+#define SMC_CAN_USE_32BIT      0
+#define SMC_IO_SHIFT           0
+#define SMC_NOWAIT             1
+
+#define SMC_inw(a, r)          readw((a) + (r))
+#define SMC_outw(v, a, r)      writew(v, (a) + (r))
+#define SMC_insw(a, r, p, l)   readsw((a) + (r), p, l)
+#define SMC_outsw(a, r, p, l)  writesw((a) + (r), p, l)
+
+#elif  defined(CONFIG_ARCH_INNOKOM) || \
+       defined(CONFIG_ARCH_PXA_IDP) || \
+       defined(CONFIG_ARCH_RAMSES) || \
+       defined(CONFIG_ARCH_PCM027)
+
+#define SMC_CAN_USE_8BIT       1
+#define SMC_CAN_USE_16BIT      1
+#define SMC_CAN_USE_32BIT      1
+#define SMC_IO_SHIFT           0
+#define SMC_NOWAIT             1
+#define SMC_USE_PXA_DMA                1
+
+#define SMC_inb(a, r)          readb((a) + (r))
+#define SMC_inw(a, r)          readw((a) + (r))
+#define SMC_inl(a, r)          readl((a) + (r))
+#define SMC_outb(v, a, r)      writeb(v, (a) + (r))
+#define SMC_outl(v, a, r)      writel(v, (a) + (r))
+#define SMC_insl(a, r, p, l)   readsl((a) + (r), p, l)
+#define SMC_outsl(a, r, p, l)  writesl((a) + (r), p, l)
+#define SMC_IRQ_FLAGS          (-1)    /* from resource */
+
+/* We actually can't write halfwords properly if not word aligned */
+static inline void
+SMC_outw(u16 val, void __iomem *ioaddr, int reg)
+{
+       if (reg & 2) {
+               unsigned int v = val << 16;
+               v |= readl(ioaddr + (reg & ~2)) & 0xffff;
+               writel(v, ioaddr + (reg & ~2));
+       } else {
+               writew(val, ioaddr + reg);
+       }
+}
+
+#elif  defined(CONFIG_SH_SH4202_MICRODEV)
+
+#define SMC_CAN_USE_8BIT       0
+#define SMC_CAN_USE_16BIT      1
+#define SMC_CAN_USE_32BIT      0
+
+#define SMC_inb(a, r)          inb((a) + (r) - 0xa0000000)
+#define SMC_inw(a, r)          inw((a) + (r) - 0xa0000000)
+#define SMC_inl(a, r)          inl((a) + (r) - 0xa0000000)
+#define SMC_outb(v, a, r)      outb(v, (a) + (r) - 0xa0000000)
+#define SMC_outw(v, a, r)      outw(v, (a) + (r) - 0xa0000000)
+#define SMC_outl(v, a, r)      outl(v, (a) + (r) - 0xa0000000)
+#define SMC_insl(a, r, p, l)   insl((a) + (r) - 0xa0000000, p, l)
+#define SMC_outsl(a, r, p, l)  outsl((a) + (r) - 0xa0000000, p, l)
+#define SMC_insw(a, r, p, l)   insw((a) + (r) - 0xa0000000, p, l)
+#define SMC_outsw(a, r, p, l)  outsw((a) + (r) - 0xa0000000, p, l)
+
+#define SMC_IRQ_FLAGS          (0)
+
+#elif   defined(CONFIG_M32R)
+
+#define SMC_CAN_USE_8BIT       0
+#define SMC_CAN_USE_16BIT      1
+#define SMC_CAN_USE_32BIT      0
+
+#define SMC_inb(a, r)          inb(((u32)a) + (r))
+#define SMC_inw(a, r)          inw(((u32)a) + (r))
+#define SMC_outb(v, a, r)      outb(v, ((u32)a) + (r))
+#define SMC_outw(v, a, r)      outw(v, ((u32)a) + (r))
+#define SMC_insw(a, r, p, l)   insw(((u32)a) + (r), p, l)
+#define SMC_outsw(a, r, p, l)  outsw(((u32)a) + (r), p, l)
+
+#define SMC_IRQ_FLAGS          (0)
+
+#define RPC_LSA_DEFAULT                RPC_LED_TX_RX
+#define RPC_LSB_DEFAULT                RPC_LED_100_10
+
+#elif  defined(CONFIG_ARCH_VERSATILE)
+
+#define SMC_CAN_USE_8BIT       1
+#define SMC_CAN_USE_16BIT      1
+#define SMC_CAN_USE_32BIT      1
+#define SMC_NOWAIT             1
+
+#define SMC_inb(a, r)          readb((a) + (r))
+#define SMC_inw(a, r)          readw((a) + (r))
+#define SMC_inl(a, r)          readl((a) + (r))
+#define SMC_outb(v, a, r)      writeb(v, (a) + (r))
+#define SMC_outw(v, a, r)      writew(v, (a) + (r))
+#define SMC_outl(v, a, r)      writel(v, (a) + (r))
+#define SMC_insl(a, r, p, l)   readsl((a) + (r), p, l)
+#define SMC_outsl(a, r, p, l)  writesl((a) + (r), p, l)
+#define SMC_IRQ_FLAGS          (-1)    /* from resource */
+
+#elif defined(CONFIG_MN10300)
+
+/*
+ * MN10300/AM33 configuration
+ */
+
+#include <unit/smc91111.h>
+
+#elif defined(CONFIG_ARCH_MSM)
+
+#define SMC_CAN_USE_8BIT       0
+#define SMC_CAN_USE_16BIT      1
+#define SMC_CAN_USE_32BIT      0
+#define SMC_NOWAIT             1
+
+#define SMC_inw(a, r)          readw((a) + (r))
+#define SMC_outw(v, a, r)      writew(v, (a) + (r))
+#define SMC_insw(a, r, p, l)   readsw((a) + (r), p, l)
+#define SMC_outsw(a, r, p, l)  writesw((a) + (r), p, l)
+
+#define SMC_IRQ_FLAGS          IRQF_TRIGGER_HIGH
+
+#elif defined(CONFIG_COLDFIRE)
+
+#define SMC_CAN_USE_8BIT       0
+#define SMC_CAN_USE_16BIT      1
+#define SMC_CAN_USE_32BIT      0
+#define SMC_NOWAIT             1
+
+static inline void mcf_insw(void *a, unsigned char *p, int l)
+{
+       u16 *wp = (u16 *) p;
+       while (l-- > 0)
+               *wp++ = readw(a);
+}
+
+static inline void mcf_outsw(void *a, unsigned char *p, int l)
+{
+       u16 *wp = (u16 *) p;
+       while (l-- > 0)
+               writew(*wp++, a);
+}
+
+#define SMC_inw(a, r)          _swapw(readw((a) + (r)))
+#define SMC_outw(v, a, r)      writew(_swapw(v), (a) + (r))
+#define SMC_insw(a, r, p, l)   mcf_insw(a + r, p, l)
+#define SMC_outsw(a, r, p, l)  mcf_outsw(a + r, p, l)
+
+#define SMC_IRQ_FLAGS          (IRQF_DISABLED)
+
+#else
+
+/*
+ * Default configuration
+ */
+
+#define SMC_CAN_USE_8BIT       1
+#define SMC_CAN_USE_16BIT      1
+#define SMC_CAN_USE_32BIT      1
+#define SMC_NOWAIT             1
+
+#define SMC_IO_SHIFT           (lp->io_shift)
+
+#define SMC_inb(a, r)          readb((a) + (r))
+#define SMC_inw(a, r)          readw((a) + (r))
+#define SMC_inl(a, r)          readl((a) + (r))
+#define SMC_outb(v, a, r)      writeb(v, (a) + (r))
+#define SMC_outw(v, a, r)      writew(v, (a) + (r))
+#define SMC_outl(v, a, r)      writel(v, (a) + (r))
+#define SMC_insw(a, r, p, l)   readsw((a) + (r), p, l)
+#define SMC_outsw(a, r, p, l)  writesw((a) + (r), p, l)
+#define SMC_insl(a, r, p, l)   readsl((a) + (r), p, l)
+#define SMC_outsl(a, r, p, l)  writesl((a) + (r), p, l)
+
+#define RPC_LSA_DEFAULT                RPC_LED_100_10
+#define RPC_LSB_DEFAULT                RPC_LED_TX_RX
+
+#endif
+
+
+/* store this information for the driver.. */
+struct smc_local {
+       /*
+        * If I have to wait until memory is available to send a
+        * packet, I will store the skbuff here, until I get the
+        * desired memory.  Then, I'll send it out and free it.
+        */
+       struct sk_buff *pending_tx_skb;
+       struct tasklet_struct tx_task;
+
+       /* version/revision of the SMC91x chip */
+       int     version;
+
+       /* Contains the current active transmission mode */
+       int     tcr_cur_mode;
+
+       /* Contains the current active receive mode */
+       int     rcr_cur_mode;
+
+       /* Contains the current active receive/phy mode */
+       int     rpc_cur_mode;
+       int     ctl_rfduplx;
+       int     ctl_rspeed;
+
+       u32     msg_enable;
+       u32     phy_type;
+       struct mii_if_info mii;
+
+       /* work queue */
+       struct work_struct phy_configure;
+       struct net_device *dev;
+       int     work_pending;
+
+       spinlock_t lock;
+
+#ifdef CONFIG_ARCH_PXA
+       /* DMA needs the physical address of the chip */
+       u_long physaddr;
+       struct device *device;
+#endif
+       void __iomem *base;
+       void __iomem *datacs;
+
+       /* the low address lines on some platforms aren't connected... */
+       int     io_shift;
+
+       struct smc91x_platdata cfg;
+};
+
+#define SMC_8BIT(p)    ((p)->cfg.flags & SMC91X_USE_8BIT)
+#define SMC_16BIT(p)   ((p)->cfg.flags & SMC91X_USE_16BIT)
+#define SMC_32BIT(p)   ((p)->cfg.flags & SMC91X_USE_32BIT)
+
+#ifdef CONFIG_ARCH_PXA
+/*
+ * Let's use the DMA engine on the XScale PXA2xx for RX packets. This is
+ * always happening in irq context so no need to worry about races.  TX is
+ * different and probably not worth it for that reason, and not as critical
+ * as RX which can overrun memory and lose packets.
+ */
+#include <linux/dma-mapping.h>
+#include <mach/dma.h>
+
+#ifdef SMC_insl
+#undef SMC_insl
+#define SMC_insl(a, r, p, l) \
+       smc_pxa_dma_insl(a, lp, r, dev->dma, p, l)
+static inline void
+smc_pxa_dma_insl(void __iomem *ioaddr, struct smc_local *lp, int reg, int dma,
+                u_char *buf, int len)
+{
+       u_long physaddr = lp->physaddr;
+       dma_addr_t dmabuf;
+
+       /* fallback if no DMA available */
+       if (dma == (unsigned char)-1) {
+               readsl(ioaddr + reg, buf, len);
+               return;
+       }
+
+       /* 64 bit alignment is required for memory to memory DMA */
+       if ((long)buf & 4) {
+               *((u32 *)buf) = SMC_inl(ioaddr, reg);
+               buf += 4;
+               len--;
+       }
+
+       len *= 4;
+       dmabuf = dma_map_single(lp->device, buf, len, DMA_FROM_DEVICE);
+       DCSR(dma) = DCSR_NODESC;
+       DTADR(dma) = dmabuf;
+       DSADR(dma) = physaddr + reg;
+       DCMD(dma) = (DCMD_INCTRGADDR | DCMD_BURST32 |
+                    DCMD_WIDTH4 | (DCMD_LENGTH & len));
+       DCSR(dma) = DCSR_NODESC | DCSR_RUN;
+       while (!(DCSR(dma) & DCSR_STOPSTATE))
+               cpu_relax();
+       DCSR(dma) = 0;
+       dma_unmap_single(lp->device, dmabuf, len, DMA_FROM_DEVICE);
+}
+#endif
+
+#ifdef SMC_insw
+#undef SMC_insw
+#define SMC_insw(a, r, p, l) \
+       smc_pxa_dma_insw(a, lp, r, dev->dma, p, l)
+static inline void
+smc_pxa_dma_insw(void __iomem *ioaddr, struct smc_local *lp, int reg, int dma,
+                u_char *buf, int len)
+{
+       u_long physaddr = lp->physaddr;
+       dma_addr_t dmabuf;
+
+       /* fallback if no DMA available */
+       if (dma == (unsigned char)-1) {
+               readsw(ioaddr + reg, buf, len);
+               return;
+       }
+
+       /* 64 bit alignment is required for memory to memory DMA */
+       while ((long)buf & 6) {
+               *((u16 *)buf) = SMC_inw(ioaddr, reg);
+               buf += 2;
+               len--;
+       }
+
+       len *= 2;
+       dmabuf = dma_map_single(lp->device, buf, len, DMA_FROM_DEVICE);
+       DCSR(dma) = DCSR_NODESC;
+       DTADR(dma) = dmabuf;
+       DSADR(dma) = physaddr + reg;
+       DCMD(dma) = (DCMD_INCTRGADDR | DCMD_BURST32 |
+                    DCMD_WIDTH2 | (DCMD_LENGTH & len));
+       DCSR(dma) = DCSR_NODESC | DCSR_RUN;
+       while (!(DCSR(dma) & DCSR_STOPSTATE))
+               cpu_relax();
+       DCSR(dma) = 0;
+       dma_unmap_single(lp->device, dmabuf, len, DMA_FROM_DEVICE);
+}
+#endif
+
+static void
+smc_pxa_dma_irq(int dma, void *dummy)
+{
+       DCSR(dma) = 0;
+}
+#endif  /* CONFIG_ARCH_PXA */
+
+
+/*
+ * Everything a particular hardware setup needs should have been defined
+ * at this point.  Add stubs for the undefined cases, mainly to avoid
+ * compilation warnings since they'll be optimized away, or to prevent buggy
+ * use of them.
+ */
+
+#if ! SMC_CAN_USE_32BIT
+#define SMC_inl(ioaddr, reg)           ({ BUG(); 0; })
+#define SMC_outl(x, ioaddr, reg)       BUG()
+#define SMC_insl(a, r, p, l)           BUG()
+#define SMC_outsl(a, r, p, l)          BUG()
+#endif
+
+#if !defined(SMC_insl) || !defined(SMC_outsl)
+#define SMC_insl(a, r, p, l)           BUG()
+#define SMC_outsl(a, r, p, l)          BUG()
+#endif
+
+#if ! SMC_CAN_USE_16BIT
+
+/*
+ * Any 16-bit access is performed with two 8-bit accesses if the hardware
+ * can't do it directly. Most registers are 16-bit so those are mandatory.
+ */
+#define SMC_outw(x, ioaddr, reg)                                       \
+       do {                                                            \
+               unsigned int __val16 = (x);                             \
+               SMC_outb( __val16, ioaddr, reg );                       \
+               SMC_outb( __val16 >> 8, ioaddr, reg + (1 << SMC_IO_SHIFT));\
+       } while (0)
+#define SMC_inw(ioaddr, reg)                                           \
+       ({                                                              \
+               unsigned int __val16;                                   \
+               __val16 =  SMC_inb( ioaddr, reg );                      \
+               __val16 |= SMC_inb( ioaddr, reg + (1 << SMC_IO_SHIFT)) << 8; \
+               __val16;                                                \
+       })
+
+#define SMC_insw(a, r, p, l)           BUG()
+#define SMC_outsw(a, r, p, l)          BUG()
+
+#endif
+
+#if !defined(SMC_insw) || !defined(SMC_outsw)
+#define SMC_insw(a, r, p, l)           BUG()
+#define SMC_outsw(a, r, p, l)          BUG()
+#endif
+
+#if ! SMC_CAN_USE_8BIT
+#define SMC_inb(ioaddr, reg)           ({ BUG(); 0; })
+#define SMC_outb(x, ioaddr, reg)       BUG()
+#define SMC_insb(a, r, p, l)           BUG()
+#define SMC_outsb(a, r, p, l)          BUG()
+#endif
+
+#if !defined(SMC_insb) || !defined(SMC_outsb)
+#define SMC_insb(a, r, p, l)           BUG()
+#define SMC_outsb(a, r, p, l)          BUG()
+#endif
+
+#ifndef SMC_CAN_USE_DATACS
+#define SMC_CAN_USE_DATACS     0
+#endif
+
+#ifndef SMC_IO_SHIFT
+#define SMC_IO_SHIFT   0
+#endif
+
+#ifndef        SMC_IRQ_FLAGS
+#define        SMC_IRQ_FLAGS           IRQF_TRIGGER_RISING
+#endif
+
+#ifndef SMC_INTERRUPT_PREAMBLE
+#define SMC_INTERRUPT_PREAMBLE
+#endif
+
+
+/* Because of bank switching, the LAN91x uses only 16 I/O ports */
+#define SMC_IO_EXTENT  (16 << SMC_IO_SHIFT)
+#define SMC_DATA_EXTENT (4)
+
+/*
+ . Bank Select Register:
+ .
+ .             yyyy yyyy 0000 00xx
+ .             xx              = bank number
+ .             yyyy yyyy       = 0x33, for identification purposes.
+*/
+#define BANK_SELECT            (14 << SMC_IO_SHIFT)
+
+
+// Transmit Control Register
+/* BANK 0  */
+#define TCR_REG(lp)    SMC_REG(lp, 0x0000, 0)
+#define TCR_ENABLE     0x0001  // When 1 we can transmit
+#define TCR_LOOP       0x0002  // Controls output pin LBK
+#define TCR_FORCOL     0x0004  // When 1 will force a collision
+#define TCR_PAD_EN     0x0080  // When 1 will pad tx frames < 64 bytes w/0
+#define TCR_NOCRC      0x0100  // When 1 will not append CRC to tx frames
+#define TCR_MON_CSN    0x0400  // When 1 tx monitors carrier
+#define TCR_FDUPLX     0x0800  // When 1 enables full duplex operation
+#define TCR_STP_SQET   0x1000  // When 1 stops tx if Signal Quality Error
+#define TCR_EPH_LOOP   0x2000  // When 1 enables EPH block loopback
+#define TCR_SWFDUP     0x8000  // When 1 enables Switched Full Duplex mode
+
+#define TCR_CLEAR      0       /* do NOTHING */
+/* the default settings for the TCR register : */
+#define TCR_DEFAULT    (TCR_ENABLE | TCR_PAD_EN)
+
+
+// EPH Status Register
+/* BANK 0  */
+#define EPH_STATUS_REG(lp)     SMC_REG(lp, 0x0002, 0)
+#define ES_TX_SUC      0x0001  // Last TX was successful
+#define ES_SNGL_COL    0x0002  // Single collision detected for last tx
+#define ES_MUL_COL     0x0004  // Multiple collisions detected for last tx
+#define ES_LTX_MULT    0x0008  // Last tx was a multicast
+#define ES_16COL       0x0010  // 16 Collisions Reached
+#define ES_SQET                0x0020  // Signal Quality Error Test
+#define ES_LTXBRD      0x0040  // Last tx was a broadcast
+#define ES_TXDEFR      0x0080  // Transmit Deferred
+#define ES_LATCOL      0x0200  // Late collision detected on last tx
+#define ES_LOSTCARR    0x0400  // Lost Carrier Sense
+#define ES_EXC_DEF     0x0800  // Excessive Deferral
+#define ES_CTR_ROL     0x1000  // Counter Roll Over indication
+#define ES_LINK_OK     0x4000  // Driven by inverted value of nLNK pin
+#define ES_TXUNRN      0x8000  // Tx Underrun
+
+
+// Receive Control Register
+/* BANK 0  */
+#define RCR_REG(lp)            SMC_REG(lp, 0x0004, 0)
+#define RCR_RX_ABORT   0x0001  // Set if a rx frame was aborted
+#define RCR_PRMS       0x0002  // Enable promiscuous mode
+#define RCR_ALMUL      0x0004  // When set accepts all multicast frames
+#define RCR_RXEN       0x0100  // IFF this is set, we can receive packets
+#define RCR_STRIP_CRC  0x0200  // When set strips CRC from rx packets
+#define RCR_ABORT_ENB  0x0200  // When set will abort rx on collision
+#define RCR_FILT_CAR   0x0400  // When set filters leading 12 bit s of carrier
+#define RCR_SOFTRST    0x8000  // resets the chip
+
+/* the normal settings for the RCR register : */
+#define RCR_DEFAULT    (RCR_STRIP_CRC | RCR_RXEN)
+#define RCR_CLEAR      0x0     // set it to a base state
+
+
+// Counter Register
+/* BANK 0  */
+#define COUNTER_REG(lp)        SMC_REG(lp, 0x0006, 0)
+
+
+// Memory Information Register
+/* BANK 0  */
+#define MIR_REG(lp)            SMC_REG(lp, 0x0008, 0)
+
+
+// Receive/Phy Control Register
+/* BANK 0  */
+#define RPC_REG(lp)            SMC_REG(lp, 0x000A, 0)
+#define RPC_SPEED      0x2000  // When 1 PHY is in 100Mbps mode.
+#define RPC_DPLX       0x1000  // When 1 PHY is in Full-Duplex Mode
+#define RPC_ANEG       0x0800  // When 1 PHY is in Auto-Negotiate Mode
+#define RPC_LSXA_SHFT  5       // Bits to shift LS2A,LS1A,LS0A to lsb
+#define RPC_LSXB_SHFT  2       // Bits to get LS2B,LS1B,LS0B to lsb
+
+#ifndef RPC_LSA_DEFAULT
+#define RPC_LSA_DEFAULT        RPC_LED_100
+#endif
+#ifndef RPC_LSB_DEFAULT
+#define RPC_LSB_DEFAULT RPC_LED_FD
+#endif
+
+#define RPC_DEFAULT (RPC_ANEG | RPC_SPEED | RPC_DPLX)
+
+
+/* Bank 0 0x0C is reserved */
+
+// Bank Select Register
+/* All Banks */
+#define BSR_REG                0x000E
+
+
+// Configuration Reg
+/* BANK 1 */
+#define CONFIG_REG(lp) SMC_REG(lp, 0x0000,     1)
+#define CONFIG_EXT_PHY 0x0200  // 1=external MII, 0=internal Phy
+#define CONFIG_GPCNTRL 0x0400  // Inverse value drives pin nCNTRL
+#define CONFIG_NO_WAIT 0x1000  // When 1 no extra wait states on ISA bus
+#define CONFIG_EPH_POWER_EN 0x8000 // When 0 EPH is placed into low power mode.
+
+// Default is powered-up, Internal Phy, Wait States, and pin nCNTRL=low
+#define CONFIG_DEFAULT (CONFIG_EPH_POWER_EN)
+
+
+// Base Address Register
+/* BANK 1 */
+#define BASE_REG(lp)   SMC_REG(lp, 0x0002, 1)
+
+
+// Individual Address Registers
+/* BANK 1 */
+#define ADDR0_REG(lp)  SMC_REG(lp, 0x0004, 1)
+#define ADDR1_REG(lp)  SMC_REG(lp, 0x0006, 1)
+#define ADDR2_REG(lp)  SMC_REG(lp, 0x0008, 1)
+
+
+// General Purpose Register
+/* BANK 1 */
+#define GP_REG(lp)             SMC_REG(lp, 0x000A, 1)
+
+
+// Control Register
+/* BANK 1 */
+#define CTL_REG(lp)            SMC_REG(lp, 0x000C, 1)
+#define CTL_RCV_BAD    0x4000 // When 1 bad CRC packets are received
+#define CTL_AUTO_RELEASE 0x0800 // When 1 tx pages are released automatically
+#define CTL_LE_ENABLE  0x0080 // When 1 enables Link Error interrupt
+#define CTL_CR_ENABLE  0x0040 // When 1 enables Counter Rollover interrupt
+#define CTL_TE_ENABLE  0x0020 // When 1 enables Transmit Error interrupt
+#define CTL_EEPROM_SELECT 0x0004 // Controls EEPROM reload & store
+#define CTL_RELOAD     0x0002 // When set reads EEPROM into registers
+#define CTL_STORE      0x0001 // When set stores registers into EEPROM
+
+
+// MMU Command Register
+/* BANK 2 */
+#define MMU_CMD_REG(lp)        SMC_REG(lp, 0x0000, 2)
+#define MC_BUSY                1       // When 1 the last release has not completed
+#define MC_NOP         (0<<5)  // No Op
+#define MC_ALLOC       (1<<5)  // OR with number of 256 byte packets
+#define MC_RESET       (2<<5)  // Reset MMU to initial state
+#define MC_REMOVE      (3<<5)  // Remove the current rx packet
+#define MC_RELEASE     (4<<5)  // Remove and release the current rx packet
+#define MC_FREEPKT     (5<<5)  // Release packet in PNR register
+#define MC_ENQUEUE     (6<<5)  // Enqueue the packet for transmit
+#define MC_RSTTXFIFO   (7<<5)  // Reset the TX FIFOs
+
+
+// Packet Number Register
+/* BANK 2 */
+#define PN_REG(lp)             SMC_REG(lp, 0x0002, 2)
+
+
+// Allocation Result Register
+/* BANK 2 */
+#define AR_REG(lp)             SMC_REG(lp, 0x0003, 2)
+#define AR_FAILED      0x80    // Alocation Failed
+
+
+// TX FIFO Ports Register
+/* BANK 2 */
+#define TXFIFO_REG(lp) SMC_REG(lp, 0x0004, 2)
+#define TXFIFO_TEMPTY  0x80    // TX FIFO Empty
+
+// RX FIFO Ports Register
+/* BANK 2 */
+#define RXFIFO_REG(lp) SMC_REG(lp, 0x0005, 2)
+#define RXFIFO_REMPTY  0x80    // RX FIFO Empty
+
+#define FIFO_REG(lp)   SMC_REG(lp, 0x0004, 2)
+
+// Pointer Register
+/* BANK 2 */
+#define PTR_REG(lp)            SMC_REG(lp, 0x0006, 2)
+#define PTR_RCV                0x8000 // 1=Receive area, 0=Transmit area
+#define PTR_AUTOINC    0x4000 // Auto increment the pointer on each access
+#define PTR_READ       0x2000 // When 1 the operation is a read
+
+
+// Data Register
+/* BANK 2 */
+#define DATA_REG(lp)   SMC_REG(lp, 0x0008, 2)
+
+
+// Interrupt Status/Acknowledge Register
+/* BANK 2 */
+#define INT_REG(lp)            SMC_REG(lp, 0x000C, 2)
+
+
+// Interrupt Mask Register
+/* BANK 2 */
+#define IM_REG(lp)             SMC_REG(lp, 0x000D, 2)
+#define IM_MDINT       0x80 // PHY MI Register 18 Interrupt
+#define IM_ERCV_INT    0x40 // Early Receive Interrupt
+#define IM_EPH_INT     0x20 // Set by Ethernet Protocol Handler section
+#define IM_RX_OVRN_INT 0x10 // Set by Receiver Overruns
+#define IM_ALLOC_INT   0x08 // Set when allocation request is completed
+#define IM_TX_EMPTY_INT        0x04 // Set if the TX FIFO goes empty
+#define IM_TX_INT      0x02 // Transmit Interrupt
+#define IM_RCV_INT     0x01 // Receive Interrupt
+
+
+// Multicast Table Registers
+/* BANK 3 */
+#define MCAST_REG1(lp) SMC_REG(lp, 0x0000, 3)
+#define MCAST_REG2(lp) SMC_REG(lp, 0x0002, 3)
+#define MCAST_REG3(lp) SMC_REG(lp, 0x0004, 3)
+#define MCAST_REG4(lp) SMC_REG(lp, 0x0006, 3)
+
+
+// Management Interface Register (MII)
+/* BANK 3 */
+#define MII_REG(lp)            SMC_REG(lp, 0x0008, 3)
+#define MII_MSK_CRS100 0x4000 // Disables CRS100 detection during tx half dup
+#define MII_MDOE       0x0008 // MII Output Enable
+#define MII_MCLK       0x0004 // MII Clock, pin MDCLK
+#define MII_MDI                0x0002 // MII Input, pin MDI
+#define MII_MDO                0x0001 // MII Output, pin MDO
+
+
+// Revision Register
+/* BANK 3 */
+/* ( hi: chip id   low: rev # ) */
+#define REV_REG(lp)            SMC_REG(lp, 0x000A, 3)
+
+
+// Early RCV Register
+/* BANK 3 */
+/* this is NOT on SMC9192 */
+#define ERCV_REG(lp)   SMC_REG(lp, 0x000C, 3)
+#define ERCV_RCV_DISCRD        0x0080 // When 1 discards a packet being received
+#define ERCV_THRESHOLD 0x001F // ERCV Threshold Mask
+
+
+// External Register
+/* BANK 7 */
+#define EXT_REG(lp)            SMC_REG(lp, 0x0000, 7)
+
+
+#define CHIP_9192      3
+#define CHIP_9194      4
+#define CHIP_9195      5
+#define CHIP_9196      6
+#define CHIP_91100     7
+#define CHIP_91100FD   8
+#define CHIP_91111FD   9
+
+static const char * chip_ids[ 16 ] =  {
+       NULL, NULL, NULL,
+       /* 3 */ "SMC91C90/91C92",
+       /* 4 */ "SMC91C94",
+       /* 5 */ "SMC91C95",
+       /* 6 */ "SMC91C96",
+       /* 7 */ "SMC91C100",
+       /* 8 */ "SMC91C100FD",
+       /* 9 */ "SMC91C11xFD",
+       NULL, NULL, NULL,
+       NULL, NULL, NULL};
+
+
+/*
+ . Receive status bits
+*/
+#define RS_ALGNERR     0x8000
+#define RS_BRODCAST    0x4000
+#define RS_BADCRC      0x2000
+#define RS_ODDFRAME    0x1000
+#define RS_TOOLONG     0x0800
+#define RS_TOOSHORT    0x0400
+#define RS_MULTICAST   0x0001
+#define RS_ERRORS      (RS_ALGNERR | RS_BADCRC | RS_TOOLONG | RS_TOOSHORT)
+
+
+/*
+ * PHY IDs
+ *  LAN83C183 == LAN91C111 Internal PHY
+ */
+#define PHY_LAN83C183  0x0016f840
+#define PHY_LAN83C180  0x02821c50
+
+/*
+ * PHY Register Addresses (LAN91C111 Internal PHY)
+ *
+ * Generic PHY registers can be found in <linux/mii.h>
+ *
+ * These phy registers are specific to our on-board phy.
+ */
+
+// PHY Configuration Register 1
+#define PHY_CFG1_REG           0x10
+#define PHY_CFG1_LNKDIS                0x8000  // 1=Rx Link Detect Function disabled
+#define PHY_CFG1_XMTDIS                0x4000  // 1=TP Transmitter Disabled
+#define PHY_CFG1_XMTPDN                0x2000  // 1=TP Transmitter Powered Down
+#define PHY_CFG1_BYPSCR                0x0400  // 1=Bypass scrambler/descrambler
+#define PHY_CFG1_UNSCDS                0x0200  // 1=Unscramble Idle Reception Disable
+#define PHY_CFG1_EQLZR         0x0100  // 1=Rx Equalizer Disabled
+#define PHY_CFG1_CABLE         0x0080  // 1=STP(150ohm), 0=UTP(100ohm)
+#define PHY_CFG1_RLVL0         0x0040  // 1=Rx Squelch level reduced by 4.5db
+#define PHY_CFG1_TLVL_SHIFT    2       // Transmit Output Level Adjust
+#define PHY_CFG1_TLVL_MASK     0x003C
+#define PHY_CFG1_TRF_MASK      0x0003  // Transmitter Rise/Fall time
+
+
+// PHY Configuration Register 2
+#define PHY_CFG2_REG           0x11
+#define PHY_CFG2_APOLDIS       0x0020  // 1=Auto Polarity Correction disabled
+#define PHY_CFG2_JABDIS                0x0010  // 1=Jabber disabled
+#define PHY_CFG2_MREG          0x0008  // 1=Multiple register access (MII mgt)
+#define PHY_CFG2_INTMDIO       0x0004  // 1=Interrupt signaled with MDIO pulseo
+
+// PHY Status Output (and Interrupt status) Register
+#define PHY_INT_REG            0x12    // Status Output (Interrupt Status)
+#define PHY_INT_INT            0x8000  // 1=bits have changed since last read
+#define PHY_INT_LNKFAIL                0x4000  // 1=Link Not detected
+#define PHY_INT_LOSSSYNC       0x2000  // 1=Descrambler has lost sync
+#define PHY_INT_CWRD           0x1000  // 1=Invalid 4B5B code detected on rx
+#define PHY_INT_SSD            0x0800  // 1=No Start Of Stream detected on rx
+#define PHY_INT_ESD            0x0400  // 1=No End Of Stream detected on rx
+#define PHY_INT_RPOL           0x0200  // 1=Reverse Polarity detected
+#define PHY_INT_JAB            0x0100  // 1=Jabber detected
+#define PHY_INT_SPDDET         0x0080  // 1=100Base-TX mode, 0=10Base-T mode
+#define PHY_INT_DPLXDET                0x0040  // 1=Device in Full Duplex
+
+// PHY Interrupt/Status Mask Register
+#define PHY_MASK_REG           0x13    // Interrupt Mask
+// Uses the same bit definitions as PHY_INT_REG
+
+
+/*
+ * SMC91C96 ethernet config and status registers.
+ * These are in the "attribute" space.
+ */
+#define ECOR                   0x8000
+#define ECOR_RESET             0x80
+#define ECOR_LEVEL_IRQ         0x40
+#define ECOR_WR_ATTRIB         0x04
+#define ECOR_ENABLE            0x01
+
+#define ECSR                   0x8002
+#define ECSR_IOIS8             0x20
+#define ECSR_PWRDWN            0x04
+#define ECSR_INT               0x02
+
+#define ATTRIB_SIZE            ((64*1024) << SMC_IO_SHIFT)
+
+
+/*
+ * Macros to abstract register access according to the data bus
+ * capabilities.  Please use those and not the in/out primitives.
+ * Note: the following macros do *not* select the bank -- this must
+ * be done separately as needed in the main code.  The SMC_REG() macro
+ * only uses the bank argument for debugging purposes (when enabled).
+ *
+ * Note: despite inline functions being safer, everything leading to this
+ * should preferably be macros to let BUG() display the line number in
+ * the core source code since we're interested in the top call site
+ * not in any inline function location.
+ */
+
+#if SMC_DEBUG > 0
+#define SMC_REG(lp, reg, bank)                                 \
+       ({                                                              \
+               int __b = SMC_CURRENT_BANK(lp);                 \
+               if (unlikely((__b & ~0xf0) != (0x3300 | bank))) {       \
+                       printk( "%s: bank reg screwed (0x%04x)\n",      \
+                               CARDNAME, __b );                        \
+                       BUG();                                          \
+               }                                                       \
+               reg<<SMC_IO_SHIFT;                                      \
+       })
+#else
+#define SMC_REG(lp, reg, bank) (reg<<SMC_IO_SHIFT)
+#endif
+
+/*
+ * Hack Alert: Some setups just can't write 8 or 16 bits reliably when not
+ * aligned to a 32 bit boundary.  I tell you that does exist!
+ * Fortunately the affected register accesses can be easily worked around
+ * since we can write zeroes to the preceding 16 bits without adverse
+ * effects and use a 32-bit access.
+ *
+ * Enforce it on any 32-bit capable setup for now.
+ */
+#define SMC_MUST_ALIGN_WRITE(lp)       SMC_32BIT(lp)
+
+#define SMC_GET_PN(lp)                                         \
+       (SMC_8BIT(lp)   ? (SMC_inb(ioaddr, PN_REG(lp))) \
+                               : (SMC_inw(ioaddr, PN_REG(lp)) & 0xFF))
+
+#define SMC_SET_PN(lp, x)                                              \
+       do {                                                            \
+               if (SMC_MUST_ALIGN_WRITE(lp))                           \
+                       SMC_outl((x)<<16, ioaddr, SMC_REG(lp, 0, 2));   \
+               else if (SMC_8BIT(lp))                          \
+                       SMC_outb(x, ioaddr, PN_REG(lp));                \
+               else                                                    \
+                       SMC_outw(x, ioaddr, PN_REG(lp));                \
+       } while (0)
+
+#define SMC_GET_AR(lp)                                         \
+       (SMC_8BIT(lp)   ? (SMC_inb(ioaddr, AR_REG(lp))) \
+                               : (SMC_inw(ioaddr, PN_REG(lp)) >> 8))
+
+#define SMC_GET_TXFIFO(lp)                                             \
+       (SMC_8BIT(lp)   ? (SMC_inb(ioaddr, TXFIFO_REG(lp)))     \
+                               : (SMC_inw(ioaddr, TXFIFO_REG(lp)) & 0xFF))
+
+#define SMC_GET_RXFIFO(lp)                                             \
+       (SMC_8BIT(lp)   ? (SMC_inb(ioaddr, RXFIFO_REG(lp)))     \
+                               : (SMC_inw(ioaddr, TXFIFO_REG(lp)) >> 8))
+
+#define SMC_GET_INT(lp)                                                \
+       (SMC_8BIT(lp)   ? (SMC_inb(ioaddr, INT_REG(lp)))        \
+                               : (SMC_inw(ioaddr, INT_REG(lp)) & 0xFF))
+
+#define SMC_ACK_INT(lp, x)                                             \
+       do {                                                            \
+               if (SMC_8BIT(lp))                                       \
+                       SMC_outb(x, ioaddr, INT_REG(lp));               \
+               else {                                                  \
+                       unsigned long __flags;                          \
+                       int __mask;                                     \
+                       local_irq_save(__flags);                        \
+                       __mask = SMC_inw(ioaddr, INT_REG(lp)) & ~0xff; \
+                       SMC_outw(__mask | (x), ioaddr, INT_REG(lp));    \
+                       local_irq_restore(__flags);                     \
+               }                                                       \
+       } while (0)
+
+#define SMC_GET_INT_MASK(lp)                                           \
+       (SMC_8BIT(lp)   ? (SMC_inb(ioaddr, IM_REG(lp))) \
+                               : (SMC_inw(ioaddr, INT_REG(lp)) >> 8))
+
+#define SMC_SET_INT_MASK(lp, x)                                        \
+       do {                                                            \
+               if (SMC_8BIT(lp))                                       \
+                       SMC_outb(x, ioaddr, IM_REG(lp));                \
+               else                                                    \
+                       SMC_outw((x) << 8, ioaddr, INT_REG(lp));        \
+       } while (0)
+
+#define SMC_CURRENT_BANK(lp)   SMC_inw(ioaddr, BANK_SELECT)
+
+#define SMC_SELECT_BANK(lp, x)                                 \
+       do {                                                            \
+               if (SMC_MUST_ALIGN_WRITE(lp))                           \
+                       SMC_outl((x)<<16, ioaddr, 12<<SMC_IO_SHIFT);    \
+               else                                                    \
+                       SMC_outw(x, ioaddr, BANK_SELECT);               \
+       } while (0)
+
+#define SMC_GET_BASE(lp)               SMC_inw(ioaddr, BASE_REG(lp))
+
+#define SMC_SET_BASE(lp, x)            SMC_outw(x, ioaddr, BASE_REG(lp))
+
+#define SMC_GET_CONFIG(lp)     SMC_inw(ioaddr, CONFIG_REG(lp))
+
+#define SMC_SET_CONFIG(lp, x)  SMC_outw(x, ioaddr, CONFIG_REG(lp))
+
+#define SMC_GET_COUNTER(lp)    SMC_inw(ioaddr, COUNTER_REG(lp))
+
+#define SMC_GET_CTL(lp)                SMC_inw(ioaddr, CTL_REG(lp))
+
+#define SMC_SET_CTL(lp, x)             SMC_outw(x, ioaddr, CTL_REG(lp))
+
+#define SMC_GET_MII(lp)                SMC_inw(ioaddr, MII_REG(lp))
+
+#define SMC_GET_GP(lp)         SMC_inw(ioaddr, GP_REG(lp))
+
+#define SMC_SET_GP(lp, x)                                              \
+       do {                                                            \
+               if (SMC_MUST_ALIGN_WRITE(lp))                           \
+                       SMC_outl((x)<<16, ioaddr, SMC_REG(lp, 8, 1));   \
+               else                                                    \
+                       SMC_outw(x, ioaddr, GP_REG(lp));                \
+       } while (0)
+
+#define SMC_SET_MII(lp, x)             SMC_outw(x, ioaddr, MII_REG(lp))
+
+#define SMC_GET_MIR(lp)                SMC_inw(ioaddr, MIR_REG(lp))
+
+#define SMC_SET_MIR(lp, x)             SMC_outw(x, ioaddr, MIR_REG(lp))
+
+#define SMC_GET_MMU_CMD(lp)    SMC_inw(ioaddr, MMU_CMD_REG(lp))
+
+#define SMC_SET_MMU_CMD(lp, x) SMC_outw(x, ioaddr, MMU_CMD_REG(lp))
+
+#define SMC_GET_FIFO(lp)               SMC_inw(ioaddr, FIFO_REG(lp))
+
+#define SMC_GET_PTR(lp)                SMC_inw(ioaddr, PTR_REG(lp))
+
+#define SMC_SET_PTR(lp, x)                                             \
+       do {                                                            \
+               if (SMC_MUST_ALIGN_WRITE(lp))                           \
+                       SMC_outl((x)<<16, ioaddr, SMC_REG(lp, 4, 2));   \
+               else                                                    \
+                       SMC_outw(x, ioaddr, PTR_REG(lp));               \
+       } while (0)
+
+#define SMC_GET_EPH_STATUS(lp) SMC_inw(ioaddr, EPH_STATUS_REG(lp))
+
+#define SMC_GET_RCR(lp)                SMC_inw(ioaddr, RCR_REG(lp))
+
+#define SMC_SET_RCR(lp, x)             SMC_outw(x, ioaddr, RCR_REG(lp))
+
+#define SMC_GET_REV(lp)                SMC_inw(ioaddr, REV_REG(lp))
+
+#define SMC_GET_RPC(lp)                SMC_inw(ioaddr, RPC_REG(lp))
+
+#define SMC_SET_RPC(lp, x)                                             \
+       do {                                                            \
+               if (SMC_MUST_ALIGN_WRITE(lp))                           \
+                       SMC_outl((x)<<16, ioaddr, SMC_REG(lp, 8, 0));   \
+               else                                                    \
+                       SMC_outw(x, ioaddr, RPC_REG(lp));               \
+       } while (0)
+
+#define SMC_GET_TCR(lp)                SMC_inw(ioaddr, TCR_REG(lp))
+
+#define SMC_SET_TCR(lp, x)             SMC_outw(x, ioaddr, TCR_REG(lp))
+
+#ifndef SMC_GET_MAC_ADDR
+#define SMC_GET_MAC_ADDR(lp, addr)                                     \
+       do {                                                            \
+               unsigned int __v;                                       \
+               __v = SMC_inw(ioaddr, ADDR0_REG(lp));                   \
+               addr[0] = __v; addr[1] = __v >> 8;                      \
+               __v = SMC_inw(ioaddr, ADDR1_REG(lp));                   \
+               addr[2] = __v; addr[3] = __v >> 8;                      \
+               __v = SMC_inw(ioaddr, ADDR2_REG(lp));                   \
+               addr[4] = __v; addr[5] = __v >> 8;                      \
+       } while (0)
+#endif
+
+#define SMC_SET_MAC_ADDR(lp, addr)                                     \
+       do {                                                            \
+               SMC_outw(addr[0]|(addr[1] << 8), ioaddr, ADDR0_REG(lp)); \
+               SMC_outw(addr[2]|(addr[3] << 8), ioaddr, ADDR1_REG(lp)); \
+               SMC_outw(addr[4]|(addr[5] << 8), ioaddr, ADDR2_REG(lp)); \
+       } while (0)
+
+#define SMC_SET_MCAST(lp, x)                                           \
+       do {                                                            \
+               const unsigned char *mt = (x);                          \
+               SMC_outw(mt[0] | (mt[1] << 8), ioaddr, MCAST_REG1(lp)); \
+               SMC_outw(mt[2] | (mt[3] << 8), ioaddr, MCAST_REG2(lp)); \
+               SMC_outw(mt[4] | (mt[5] << 8), ioaddr, MCAST_REG3(lp)); \
+               SMC_outw(mt[6] | (mt[7] << 8), ioaddr, MCAST_REG4(lp)); \
+       } while (0)
+
+#define SMC_PUT_PKT_HDR(lp, status, length)                            \
+       do {                                                            \
+               if (SMC_32BIT(lp))                                      \
+                       SMC_outl((status) | (length)<<16, ioaddr,       \
+                                DATA_REG(lp));                 \
+               else {                                                  \
+                       SMC_outw(status, ioaddr, DATA_REG(lp)); \
+                       SMC_outw(length, ioaddr, DATA_REG(lp)); \
+               }                                                       \
+       } while (0)
+
+#define SMC_GET_PKT_HDR(lp, status, length)                            \
+       do {                                                            \
+               if (SMC_32BIT(lp)) {                            \
+                       unsigned int __val = SMC_inl(ioaddr, DATA_REG(lp)); \
+                       (status) = __val & 0xffff;                      \
+                       (length) = __val >> 16;                         \
+               } else {                                                \
+                       (status) = SMC_inw(ioaddr, DATA_REG(lp));       \
+                       (length) = SMC_inw(ioaddr, DATA_REG(lp));       \
+               }                                                       \
+       } while (0)
+
+#define SMC_PUSH_DATA(lp, p, l)                                        \
+       do {                                                            \
+               if (SMC_32BIT(lp)) {                            \
+                       void *__ptr = (p);                              \
+                       int __len = (l);                                \
+                       void __iomem *__ioaddr = ioaddr;                \
+                       if (__len >= 2 && (unsigned long)__ptr & 2) {   \
+                               __len -= 2;                             \
+                               SMC_outw(*(u16 *)__ptr, ioaddr,         \
+                                       DATA_REG(lp));          \
+                               __ptr += 2;                             \
+                       }                                               \
+                       if (SMC_CAN_USE_DATACS && lp->datacs)           \
+                               __ioaddr = lp->datacs;                  \
+                       SMC_outsl(__ioaddr, DATA_REG(lp), __ptr, __len>>2); \
+                       if (__len & 2) {                                \
+                               __ptr += (__len & ~3);                  \
+                               SMC_outw(*((u16 *)__ptr), ioaddr,       \
+                                        DATA_REG(lp));         \
+                       }                                               \
+               } else if (SMC_16BIT(lp))                               \
+                       SMC_outsw(ioaddr, DATA_REG(lp), p, (l) >> 1);   \
+               else if (SMC_8BIT(lp))                          \
+                       SMC_outsb(ioaddr, DATA_REG(lp), p, l);  \
+       } while (0)
+
+#define SMC_PULL_DATA(lp, p, l)                                        \
+       do {                                                            \
+               if (SMC_32BIT(lp)) {                            \
+                       void *__ptr = (p);                              \
+                       int __len = (l);                                \
+                       void __iomem *__ioaddr = ioaddr;                \
+                       if ((unsigned long)__ptr & 2) {                 \
+                               /*                                      \
+                                * We want 32bit alignment here.        \
+                                * Since some buses perform a full      \
+                                * 32bit fetch even for 16bit data      \
+                                * we can't use SMC_inw() here.         \
+                                * Back both source (on-chip) and       \
+                                * destination pointers of 2 bytes.     \
+                                * This is possible since the call to   \
+                                * SMC_GET_PKT_HDR() already advanced   \
+                                * the source pointer of 4 bytes, and   \
+                                * the skb_reserve(skb, 2) advanced     \
+                                * the destination pointer of 2 bytes.  \
+                                */                                     \
+                               __ptr -= 2;                             \
+                               __len += 2;                             \
+                               SMC_SET_PTR(lp,                 \
+                                       2|PTR_READ|PTR_RCV|PTR_AUTOINC); \
+                       }                                               \
+                       if (SMC_CAN_USE_DATACS && lp->datacs)           \
+                               __ioaddr = lp->datacs;                  \
+                       __len += 2;                                     \
+                       SMC_insl(__ioaddr, DATA_REG(lp), __ptr, __len>>2); \
+               } else if (SMC_16BIT(lp))                               \
+                       SMC_insw(ioaddr, DATA_REG(lp), p, (l) >> 1);    \
+               else if (SMC_8BIT(lp))                          \
+                       SMC_insb(ioaddr, DATA_REG(lp), p, l);           \
+       } while (0)
+
+#endif  /* _SMC91X_H_ */
diff --git a/drivers/net/ethernet/smsc/smsc911x.c b/drivers/net/ethernet/smsc/smsc911x.c
new file mode 100644 (file)
index 0000000..75c08a5
--- /dev/null
@@ -0,0 +1,2404 @@
+/***************************************************************************
+ *
+ * Copyright (C) 2004-2008 SMSC
+ * Copyright (C) 2005-2008 ARM
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
+ *
+ ***************************************************************************
+ * Rewritten, heavily based on smsc911x simple driver by SMSC.
+ * Partly uses io macros from smc91x.c by Nicolas Pitre
+ *
+ * Supported devices:
+ *   LAN9115, LAN9116, LAN9117, LAN9118
+ *   LAN9215, LAN9216, LAN9217, LAN9218
+ *   LAN9210, LAN9211
+ *   LAN9220, LAN9221
+ *
+ */
+
+#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
+
+#include <linux/crc32.h>
+#include <linux/delay.h>
+#include <linux/errno.h>
+#include <linux/etherdevice.h>
+#include <linux/ethtool.h>
+#include <linux/init.h>
+#include <linux/interrupt.h>
+#include <linux/ioport.h>
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/netdevice.h>
+#include <linux/platform_device.h>
+#include <linux/sched.h>
+#include <linux/timer.h>
+#include <linux/bug.h>
+#include <linux/bitops.h>
+#include <linux/irq.h>
+#include <linux/io.h>
+#include <linux/swab.h>
+#include <linux/phy.h>
+#include <linux/smsc911x.h>
+#include <linux/device.h>
+#include <linux/of.h>
+#include <linux/of_device.h>
+#include <linux/of_gpio.h>
+#include <linux/of_net.h>
+#include "smsc911x.h"
+
+#define SMSC_CHIPNAME          "smsc911x"
+#define SMSC_MDIONAME          "smsc911x-mdio"
+#define SMSC_DRV_VERSION       "2008-10-21"
+
+MODULE_LICENSE("GPL");
+MODULE_VERSION(SMSC_DRV_VERSION);
+MODULE_ALIAS("platform:smsc911x");
+
+#if USE_DEBUG > 0
+static int debug = 16;
+#else
+static int debug = 3;
+#endif
+
+module_param(debug, int, 0);
+MODULE_PARM_DESC(debug, "Debug level (0=none,...,16=all)");
+
+struct smsc911x_data;
+
+struct smsc911x_ops {
+       u32 (*reg_read)(struct smsc911x_data *pdata, u32 reg);
+       void (*reg_write)(struct smsc911x_data *pdata, u32 reg, u32 val);
+       void (*rx_readfifo)(struct smsc911x_data *pdata,
+                               unsigned int *buf, unsigned int wordcount);
+       void (*tx_writefifo)(struct smsc911x_data *pdata,
+                               unsigned int *buf, unsigned int wordcount);
+};
+
+struct smsc911x_data {
+       void __iomem *ioaddr;
+
+       unsigned int idrev;
+
+       /* used to decide which workarounds apply */
+       unsigned int generation;
+
+       /* device configuration (copied from platform_data during probe) */
+       struct smsc911x_platform_config config;
+
+       /* This needs to be acquired before calling any of below:
+        * smsc911x_mac_read(), smsc911x_mac_write()
+        */
+       spinlock_t mac_lock;
+
+       /* spinlock to ensure register accesses are serialised */
+       spinlock_t dev_lock;
+
+       struct phy_device *phy_dev;
+       struct mii_bus *mii_bus;
+       int phy_irq[PHY_MAX_ADDR];
+       unsigned int using_extphy;
+       int last_duplex;
+       int last_carrier;
+
+       u32 msg_enable;
+       unsigned int gpio_setting;
+       unsigned int gpio_orig_setting;
+       struct net_device *dev;
+       struct napi_struct napi;
+
+       unsigned int software_irq_signal;
+
+#ifdef USE_PHY_WORK_AROUND
+#define MIN_PACKET_SIZE (64)
+       char loopback_tx_pkt[MIN_PACKET_SIZE];
+       char loopback_rx_pkt[MIN_PACKET_SIZE];
+       unsigned int resetcount;
+#endif
+
+       /* Members for Multicast filter workaround */
+       unsigned int multicast_update_pending;
+       unsigned int set_bits_mask;
+       unsigned int clear_bits_mask;
+       unsigned int hashhi;
+       unsigned int hashlo;
+
+       /* register access functions */
+       const struct smsc911x_ops *ops;
+};
+
+/* Easy access to information */
+#define __smsc_shift(pdata, reg) ((reg) << ((pdata)->config.shift))
+
+static inline u32 __smsc911x_reg_read(struct smsc911x_data *pdata, u32 reg)
+{
+       if (pdata->config.flags & SMSC911X_USE_32BIT)
+               return readl(pdata->ioaddr + reg);
+
+       if (pdata->config.flags & SMSC911X_USE_16BIT)
+               return ((readw(pdata->ioaddr + reg) & 0xFFFF) |
+                       ((readw(pdata->ioaddr + reg + 2) & 0xFFFF) << 16));
+
+       BUG();
+       return 0;
+}
+
+static inline u32
+__smsc911x_reg_read_shift(struct smsc911x_data *pdata, u32 reg)
+{
+       if (pdata->config.flags & SMSC911X_USE_32BIT)
+               return readl(pdata->ioaddr + __smsc_shift(pdata, reg));
+
+       if (pdata->config.flags & SMSC911X_USE_16BIT)
+               return (readw(pdata->ioaddr +
+                               __smsc_shift(pdata, reg)) & 0xFFFF) |
+                       ((readw(pdata->ioaddr +
+                       __smsc_shift(pdata, reg + 2)) & 0xFFFF) << 16);
+
+       BUG();
+       return 0;
+}
+
+static inline u32 smsc911x_reg_read(struct smsc911x_data *pdata, u32 reg)
+{
+       u32 data;
+       unsigned long flags;
+
+       spin_lock_irqsave(&pdata->dev_lock, flags);
+       data = pdata->ops->reg_read(pdata, reg);
+       spin_unlock_irqrestore(&pdata->dev_lock, flags);
+
+       return data;
+}
+
+static inline void __smsc911x_reg_write(struct smsc911x_data *pdata, u32 reg,
+                                       u32 val)
+{
+       if (pdata->config.flags & SMSC911X_USE_32BIT) {
+               writel(val, pdata->ioaddr + reg);
+               return;
+       }
+
+       if (pdata->config.flags & SMSC911X_USE_16BIT) {
+               writew(val & 0xFFFF, pdata->ioaddr + reg);
+               writew((val >> 16) & 0xFFFF, pdata->ioaddr + reg + 2);
+               return;
+       }
+
+       BUG();
+}
+
+static inline void
+__smsc911x_reg_write_shift(struct smsc911x_data *pdata, u32 reg, u32 val)
+{
+       if (pdata->config.flags & SMSC911X_USE_32BIT) {
+               writel(val, pdata->ioaddr + __smsc_shift(pdata, reg));
+               return;
+       }
+
+       if (pdata->config.flags & SMSC911X_USE_16BIT) {
+               writew(val & 0xFFFF,
+                       pdata->ioaddr + __smsc_shift(pdata, reg));
+               writew((val >> 16) & 0xFFFF,
+                       pdata->ioaddr + __smsc_shift(pdata, reg + 2));
+               return;
+       }
+
+       BUG();
+}
+
+static inline void smsc911x_reg_write(struct smsc911x_data *pdata, u32 reg,
+                                     u32 val)
+{
+       unsigned long flags;
+
+       spin_lock_irqsave(&pdata->dev_lock, flags);
+       pdata->ops->reg_write(pdata, reg, val);
+       spin_unlock_irqrestore(&pdata->dev_lock, flags);
+}
+
+/* Writes a packet to the TX_DATA_FIFO */
+static inline void
+smsc911x_tx_writefifo(struct smsc911x_data *pdata, unsigned int *buf,
+                     unsigned int wordcount)
+{
+       unsigned long flags;
+
+       spin_lock_irqsave(&pdata->dev_lock, flags);
+
+       if (pdata->config.flags & SMSC911X_SWAP_FIFO) {
+               while (wordcount--)
+                       __smsc911x_reg_write(pdata, TX_DATA_FIFO,
+                                            swab32(*buf++));
+               goto out;
+       }
+
+       if (pdata->config.flags & SMSC911X_USE_32BIT) {
+               writesl(pdata->ioaddr + TX_DATA_FIFO, buf, wordcount);
+               goto out;
+       }
+
+       if (pdata->config.flags & SMSC911X_USE_16BIT) {
+               while (wordcount--)
+                       __smsc911x_reg_write(pdata, TX_DATA_FIFO, *buf++);
+               goto out;
+       }
+
+       BUG();
+out:
+       spin_unlock_irqrestore(&pdata->dev_lock, flags);
+}
+
+/* Writes a packet to the TX_DATA_FIFO - shifted version */
+static inline void
+smsc911x_tx_writefifo_shift(struct smsc911x_data *pdata, unsigned int *buf,
+                     unsigned int wordcount)
+{
+       unsigned long flags;
+
+       spin_lock_irqsave(&pdata->dev_lock, flags);
+
+       if (pdata->config.flags & SMSC911X_SWAP_FIFO) {
+               while (wordcount--)
+                       __smsc911x_reg_write_shift(pdata, TX_DATA_FIFO,
+                                            swab32(*buf++));
+               goto out;
+       }
+
+       if (pdata->config.flags & SMSC911X_USE_32BIT) {
+               writesl(pdata->ioaddr + __smsc_shift(pdata,
+                                               TX_DATA_FIFO), buf, wordcount);
+               goto out;
+       }
+
+       if (pdata->config.flags & SMSC911X_USE_16BIT) {
+               while (wordcount--)
+                       __smsc911x_reg_write_shift(pdata,
+                                                TX_DATA_FIFO, *buf++);
+               goto out;
+       }
+
+       BUG();
+out:
+       spin_unlock_irqrestore(&pdata->dev_lock, flags);
+}
+
+/* Reads a packet out of the RX_DATA_FIFO */
+static inline void
+smsc911x_rx_readfifo(struct smsc911x_data *pdata, unsigned int *buf,
+                    unsigned int wordcount)
+{
+       unsigned long flags;
+
+       spin_lock_irqsave(&pdata->dev_lock, flags);
+
+       if (pdata->config.flags & SMSC911X_SWAP_FIFO) {
+               while (wordcount--)
+                       *buf++ = swab32(__smsc911x_reg_read(pdata,
+                                                           RX_DATA_FIFO));
+               goto out;
+       }
+
+       if (pdata->config.flags & SMSC911X_USE_32BIT) {
+               readsl(pdata->ioaddr + RX_DATA_FIFO, buf, wordcount);
+               goto out;
+       }
+
+       if (pdata->config.flags & SMSC911X_USE_16BIT) {
+               while (wordcount--)
+                       *buf++ = __smsc911x_reg_read(pdata, RX_DATA_FIFO);
+               goto out;
+       }
+
+       BUG();
+out:
+       spin_unlock_irqrestore(&pdata->dev_lock, flags);
+}
+
+/* Reads a packet out of the RX_DATA_FIFO - shifted version */
+static inline void
+smsc911x_rx_readfifo_shift(struct smsc911x_data *pdata, unsigned int *buf,
+                    unsigned int wordcount)
+{
+       unsigned long flags;
+
+       spin_lock_irqsave(&pdata->dev_lock, flags);
+
+       if (pdata->config.flags & SMSC911X_SWAP_FIFO) {
+               while (wordcount--)
+                       *buf++ = swab32(__smsc911x_reg_read_shift(pdata,
+                                                           RX_DATA_FIFO));
+               goto out;
+       }
+
+       if (pdata->config.flags & SMSC911X_USE_32BIT) {
+               readsl(pdata->ioaddr + __smsc_shift(pdata,
+                                               RX_DATA_FIFO), buf, wordcount);
+               goto out;
+       }
+
+       if (pdata->config.flags & SMSC911X_USE_16BIT) {
+               while (wordcount--)
+                       *buf++ = __smsc911x_reg_read_shift(pdata,
+                                                               RX_DATA_FIFO);
+               goto out;
+       }
+
+       BUG();
+out:
+       spin_unlock_irqrestore(&pdata->dev_lock, flags);
+}
+
+/* waits for MAC not busy, with timeout.  Only called by smsc911x_mac_read
+ * and smsc911x_mac_write, so assumes mac_lock is held */
+static int smsc911x_mac_complete(struct smsc911x_data *pdata)
+{
+       int i;
+       u32 val;
+
+       SMSC_ASSERT_MAC_LOCK(pdata);
+
+       for (i = 0; i < 40; i++) {
+               val = smsc911x_reg_read(pdata, MAC_CSR_CMD);
+               if (!(val & MAC_CSR_CMD_CSR_BUSY_))
+                       return 0;
+       }
+       SMSC_WARN(pdata, hw, "Timed out waiting for MAC not BUSY. "
+                 "MAC_CSR_CMD: 0x%08X", val);
+       return -EIO;
+}
+
+/* Fetches a MAC register value. Assumes mac_lock is acquired */
+static u32 smsc911x_mac_read(struct smsc911x_data *pdata, unsigned int offset)
+{
+       unsigned int temp;
+
+       SMSC_ASSERT_MAC_LOCK(pdata);
+
+       temp = smsc911x_reg_read(pdata, MAC_CSR_CMD);
+       if (unlikely(temp & MAC_CSR_CMD_CSR_BUSY_)) {
+               SMSC_WARN(pdata, hw, "MAC busy at entry");
+               return 0xFFFFFFFF;
+       }
+
+       /* Send the MAC cmd */
+       smsc911x_reg_write(pdata, MAC_CSR_CMD, ((offset & 0xFF) |
+               MAC_CSR_CMD_CSR_BUSY_ | MAC_CSR_CMD_R_NOT_W_));
+
+       /* Workaround for hardware read-after-write restriction */
+       temp = smsc911x_reg_read(pdata, BYTE_TEST);
+
+       /* Wait for the read to complete */
+       if (likely(smsc911x_mac_complete(pdata) == 0))
+               return smsc911x_reg_read(pdata, MAC_CSR_DATA);
+
+       SMSC_WARN(pdata, hw, "MAC busy after read");
+       return 0xFFFFFFFF;
+}
+
+/* Set a mac register, mac_lock must be acquired before calling */
+static void smsc911x_mac_write(struct smsc911x_data *pdata,
+                              unsigned int offset, u32 val)
+{
+       unsigned int temp;
+
+       SMSC_ASSERT_MAC_LOCK(pdata);
+
+       temp = smsc911x_reg_read(pdata, MAC_CSR_CMD);
+       if (unlikely(temp & MAC_CSR_CMD_CSR_BUSY_)) {
+               SMSC_WARN(pdata, hw,
+                         "smsc911x_mac_write failed, MAC busy at entry");
+               return;
+       }
+
+       /* Send data to write */
+       smsc911x_reg_write(pdata, MAC_CSR_DATA, val);
+
+       /* Write the actual data */
+       smsc911x_reg_write(pdata, MAC_CSR_CMD, ((offset & 0xFF) |
+               MAC_CSR_CMD_CSR_BUSY_));
+
+       /* Workaround for hardware read-after-write restriction */
+       temp = smsc911x_reg_read(pdata, BYTE_TEST);
+
+       /* Wait for the write to complete */
+       if (likely(smsc911x_mac_complete(pdata) == 0))
+               return;
+
+       SMSC_WARN(pdata, hw, "smsc911x_mac_write failed, MAC busy after write");
+}
+
+/* Get a phy register */
+static int smsc911x_mii_read(struct mii_bus *bus, int phyaddr, int regidx)
+{
+       struct smsc911x_data *pdata = (struct smsc911x_data *)bus->priv;
+       unsigned long flags;
+       unsigned int addr;
+       int i, reg;
+
+       spin_lock_irqsave(&pdata->mac_lock, flags);
+
+       /* Confirm MII not busy */
+       if (unlikely(smsc911x_mac_read(pdata, MII_ACC) & MII_ACC_MII_BUSY_)) {
+               SMSC_WARN(pdata, hw, "MII is busy in smsc911x_mii_read???");
+               reg = -EIO;
+               goto out;
+       }
+
+       /* Set the address, index & direction (read from PHY) */
+       addr = ((phyaddr & 0x1F) << 11) | ((regidx & 0x1F) << 6);
+       smsc911x_mac_write(pdata, MII_ACC, addr);
+
+       /* Wait for read to complete w/ timeout */
+       for (i = 0; i < 100; i++)
+               if (!(smsc911x_mac_read(pdata, MII_ACC) & MII_ACC_MII_BUSY_)) {
+                       reg = smsc911x_mac_read(pdata, MII_DATA);
+                       goto out;
+               }
+
+       SMSC_WARN(pdata, hw, "Timed out waiting for MII read to finish");
+       reg = -EIO;
+
+out:
+       spin_unlock_irqrestore(&pdata->mac_lock, flags);
+       return reg;
+}
+
+/* Set a phy register */
+static int smsc911x_mii_write(struct mii_bus *bus, int phyaddr, int regidx,
+                          u16 val)
+{
+       struct smsc911x_data *pdata = (struct smsc911x_data *)bus->priv;
+       unsigned long flags;
+       unsigned int addr;
+       int i, reg;
+
+       spin_lock_irqsave(&pdata->mac_lock, flags);
+
+       /* Confirm MII not busy */
+       if (unlikely(smsc911x_mac_read(pdata, MII_ACC) & MII_ACC_MII_BUSY_)) {
+               SMSC_WARN(pdata, hw, "MII is busy in smsc911x_mii_write???");
+               reg = -EIO;
+               goto out;
+       }
+
+       /* Put the data to write in the MAC */
+       smsc911x_mac_write(pdata, MII_DATA, val);
+
+       /* Set the address, index & direction (write to PHY) */
+       addr = ((phyaddr & 0x1F) << 11) | ((regidx & 0x1F) << 6) |
+               MII_ACC_MII_WRITE_;
+       smsc911x_mac_write(pdata, MII_ACC, addr);
+
+       /* Wait for write to complete w/ timeout */
+       for (i = 0; i < 100; i++)
+               if (!(smsc911x_mac_read(pdata, MII_ACC) & MII_ACC_MII_BUSY_)) {
+                       reg = 0;
+                       goto out;
+               }
+
+       SMSC_WARN(pdata, hw, "Timed out waiting for MII write to finish");
+       reg = -EIO;
+
+out:
+       spin_unlock_irqrestore(&pdata->mac_lock, flags);
+       return reg;
+}
+
+/* Switch to external phy. Assumes tx and rx are stopped. */
+static void smsc911x_phy_enable_external(struct smsc911x_data *pdata)
+{
+       unsigned int hwcfg = smsc911x_reg_read(pdata, HW_CFG);
+
+       /* Disable phy clocks to the MAC */
+       hwcfg &= (~HW_CFG_PHY_CLK_SEL_);
+       hwcfg |= HW_CFG_PHY_CLK_SEL_CLK_DIS_;
+       smsc911x_reg_write(pdata, HW_CFG, hwcfg);
+       udelay(10);     /* Enough time for clocks to stop */
+
+       /* Switch to external phy */
+       hwcfg |= HW_CFG_EXT_PHY_EN_;
+       smsc911x_reg_write(pdata, HW_CFG, hwcfg);
+
+       /* Enable phy clocks to the MAC */
+       hwcfg &= (~HW_CFG_PHY_CLK_SEL_);
+       hwcfg |= HW_CFG_PHY_CLK_SEL_EXT_PHY_;
+       smsc911x_reg_write(pdata, HW_CFG, hwcfg);
+       udelay(10);     /* Enough time for clocks to restart */
+
+       hwcfg |= HW_CFG_SMI_SEL_;
+       smsc911x_reg_write(pdata, HW_CFG, hwcfg);
+}
+
+/* Autodetects and enables external phy if present on supported chips.
+ * autodetection can be overridden by specifying SMSC911X_FORCE_INTERNAL_PHY
+ * or SMSC911X_FORCE_EXTERNAL_PHY in the platform_data flags. */
+static void smsc911x_phy_initialise_external(struct smsc911x_data *pdata)
+{
+       unsigned int hwcfg = smsc911x_reg_read(pdata, HW_CFG);
+
+       if (pdata->config.flags & SMSC911X_FORCE_INTERNAL_PHY) {
+               SMSC_TRACE(pdata, hw, "Forcing internal PHY");
+               pdata->using_extphy = 0;
+       } else if (pdata->config.flags & SMSC911X_FORCE_EXTERNAL_PHY) {
+               SMSC_TRACE(pdata, hw, "Forcing external PHY");
+               smsc911x_phy_enable_external(pdata);
+               pdata->using_extphy = 1;
+       } else if (hwcfg & HW_CFG_EXT_PHY_DET_) {
+               SMSC_TRACE(pdata, hw,
+                          "HW_CFG EXT_PHY_DET set, using external PHY");
+               smsc911x_phy_enable_external(pdata);
+               pdata->using_extphy = 1;
+       } else {
+               SMSC_TRACE(pdata, hw,
+                          "HW_CFG EXT_PHY_DET clear, using internal PHY");
+               pdata->using_extphy = 0;
+       }
+}
+
+/* Fetches a tx status out of the status fifo */
+static unsigned int smsc911x_tx_get_txstatus(struct smsc911x_data *pdata)
+{
+       unsigned int result =
+           smsc911x_reg_read(pdata, TX_FIFO_INF) & TX_FIFO_INF_TSUSED_;
+
+       if (result != 0)
+               result = smsc911x_reg_read(pdata, TX_STATUS_FIFO);
+
+       return result;
+}
+
+/* Fetches the next rx status */
+static unsigned int smsc911x_rx_get_rxstatus(struct smsc911x_data *pdata)
+{
+       unsigned int result =
+           smsc911x_reg_read(pdata, RX_FIFO_INF) & RX_FIFO_INF_RXSUSED_;
+
+       if (result != 0)
+               result = smsc911x_reg_read(pdata, RX_STATUS_FIFO);
+
+       return result;
+}
+
+#ifdef USE_PHY_WORK_AROUND
+static int smsc911x_phy_check_loopbackpkt(struct smsc911x_data *pdata)
+{
+       unsigned int tries;
+       u32 wrsz;
+       u32 rdsz;
+       ulong bufp;
+
+       for (tries = 0; tries < 10; tries++) {
+               unsigned int txcmd_a;
+               unsigned int txcmd_b;
+               unsigned int status;
+               unsigned int pktlength;
+               unsigned int i;
+
+               /* Zero-out rx packet memory */
+               memset(pdata->loopback_rx_pkt, 0, MIN_PACKET_SIZE);
+
+               /* Write tx packet to 118 */
+               txcmd_a = (u32)((ulong)pdata->loopback_tx_pkt & 0x03) << 16;
+               txcmd_a |= TX_CMD_A_FIRST_SEG_ | TX_CMD_A_LAST_SEG_;
+               txcmd_a |= MIN_PACKET_SIZE;
+
+               txcmd_b = MIN_PACKET_SIZE << 16 | MIN_PACKET_SIZE;
+
+               smsc911x_reg_write(pdata, TX_DATA_FIFO, txcmd_a);
+               smsc911x_reg_write(pdata, TX_DATA_FIFO, txcmd_b);
+
+               bufp = (ulong)pdata->loopback_tx_pkt & (~0x3);
+               wrsz = MIN_PACKET_SIZE + 3;
+               wrsz += (u32)((ulong)pdata->loopback_tx_pkt & 0x3);
+               wrsz >>= 2;
+
+               pdata->ops->tx_writefifo(pdata, (unsigned int *)bufp, wrsz);
+
+               /* Wait till transmit is done */
+               i = 60;
+               do {
+                       udelay(5);
+                       status = smsc911x_tx_get_txstatus(pdata);
+               } while ((i--) && (!status));
+
+               if (!status) {
+                       SMSC_WARN(pdata, hw,
+                                 "Failed to transmit during loopback test");
+                       continue;
+               }
+               if (status & TX_STS_ES_) {
+                       SMSC_WARN(pdata, hw,
+                                 "Transmit encountered errors during loopback test");
+                       continue;
+               }
+
+               /* Wait till receive is done */
+               i = 60;
+               do {
+                       udelay(5);
+                       status = smsc911x_rx_get_rxstatus(pdata);
+               } while ((i--) && (!status));
+
+               if (!status) {
+                       SMSC_WARN(pdata, hw,
+                                 "Failed to receive during loopback test");
+                       continue;
+               }
+               if (status & RX_STS_ES_) {
+                       SMSC_WARN(pdata, hw,
+                                 "Receive encountered errors during loopback test");
+                       continue;
+               }
+
+               pktlength = ((status & 0x3FFF0000UL) >> 16);
+               bufp = (ulong)pdata->loopback_rx_pkt;
+               rdsz = pktlength + 3;
+               rdsz += (u32)((ulong)pdata->loopback_rx_pkt & 0x3);
+               rdsz >>= 2;
+
+               pdata->ops->rx_readfifo(pdata, (unsigned int *)bufp, rdsz);
+
+               if (pktlength != (MIN_PACKET_SIZE + 4)) {
+                       SMSC_WARN(pdata, hw, "Unexpected packet size "
+                                 "during loop back test, size=%d, will retry",
+                                 pktlength);
+               } else {
+                       unsigned int j;
+                       int mismatch = 0;
+                       for (j = 0; j < MIN_PACKET_SIZE; j++) {
+                               if (pdata->loopback_tx_pkt[j]
+                                   != pdata->loopback_rx_pkt[j]) {
+                                       mismatch = 1;
+                                       break;
+                               }
+                       }
+                       if (!mismatch) {
+                               SMSC_TRACE(pdata, hw, "Successfully verified "
+                                          "loopback packet");
+                               return 0;
+                       } else {
+                               SMSC_WARN(pdata, hw, "Data mismatch "
+                                         "during loop back test, will retry");
+                       }
+               }
+       }
+
+       return -EIO;
+}
+
+static int smsc911x_phy_reset(struct smsc911x_data *pdata)
+{
+       struct phy_device *phy_dev = pdata->phy_dev;
+       unsigned int temp;
+       unsigned int i = 100000;
+
+       BUG_ON(!phy_dev);
+       BUG_ON(!phy_dev->bus);
+
+       SMSC_TRACE(pdata, hw, "Performing PHY BCR Reset");
+       smsc911x_mii_write(phy_dev->bus, phy_dev->addr, MII_BMCR, BMCR_RESET);
+       do {
+               msleep(1);
+               temp = smsc911x_mii_read(phy_dev->bus, phy_dev->addr,
+                       MII_BMCR);
+       } while ((i--) && (temp & BMCR_RESET));
+
+       if (temp & BMCR_RESET) {
+               SMSC_WARN(pdata, hw, "PHY reset failed to complete");
+               return -EIO;
+       }
+       /* Extra delay required because the phy may not be completed with
+       * its reset when BMCR_RESET is cleared. Specs say 256 uS is
+       * enough delay but using 1ms here to be safe */
+       msleep(1);
+
+       return 0;
+}
+
+static int smsc911x_phy_loopbacktest(struct net_device *dev)
+{
+       struct smsc911x_data *pdata = netdev_priv(dev);
+       struct phy_device *phy_dev = pdata->phy_dev;
+       int result = -EIO;
+       unsigned int i, val;
+       unsigned long flags;
+
+       /* Initialise tx packet using broadcast destination address */
+       memset(pdata->loopback_tx_pkt, 0xff, ETH_ALEN);
+
+       /* Use incrementing source address */
+       for (i = 6; i < 12; i++)
+               pdata->loopback_tx_pkt[i] = (char)i;
+
+       /* Set length type field */
+       pdata->loopback_tx_pkt[12] = 0x00;
+       pdata->loopback_tx_pkt[13] = 0x00;
+
+       for (i = 14; i < MIN_PACKET_SIZE; i++)
+               pdata->loopback_tx_pkt[i] = (char)i;
+
+       val = smsc911x_reg_read(pdata, HW_CFG);
+       val &= HW_CFG_TX_FIF_SZ_;
+       val |= HW_CFG_SF_;
+       smsc911x_reg_write(pdata, HW_CFG, val);
+
+       smsc911x_reg_write(pdata, TX_CFG, TX_CFG_TX_ON_);
+       smsc911x_reg_write(pdata, RX_CFG,
+               (u32)((ulong)pdata->loopback_rx_pkt & 0x03) << 8);
+
+       for (i = 0; i < 10; i++) {
+               /* Set PHY to 10/FD, no ANEG, and loopback mode */
+               smsc911x_mii_write(phy_dev->bus, phy_dev->addr, MII_BMCR,
+                       BMCR_LOOPBACK | BMCR_FULLDPLX);
+
+               /* Enable MAC tx/rx, FD */
+               spin_lock_irqsave(&pdata->mac_lock, flags);
+               smsc911x_mac_write(pdata, MAC_CR, MAC_CR_FDPX_
+                                  | MAC_CR_TXEN_ | MAC_CR_RXEN_);
+               spin_unlock_irqrestore(&pdata->mac_lock, flags);
+
+               if (smsc911x_phy_check_loopbackpkt(pdata) == 0) {
+                       result = 0;
+                       break;
+               }
+               pdata->resetcount++;
+
+               /* Disable MAC rx */
+               spin_lock_irqsave(&pdata->mac_lock, flags);
+               smsc911x_mac_write(pdata, MAC_CR, 0);
+               spin_unlock_irqrestore(&pdata->mac_lock, flags);
+
+               smsc911x_phy_reset(pdata);
+       }
+
+       /* Disable MAC */
+       spin_lock_irqsave(&pdata->mac_lock, flags);
+       smsc911x_mac_write(pdata, MAC_CR, 0);
+       spin_unlock_irqrestore(&pdata->mac_lock, flags);
+
+       /* Cancel PHY loopback mode */
+       smsc911x_mii_write(phy_dev->bus, phy_dev->addr, MII_BMCR, 0);
+
+       smsc911x_reg_write(pdata, TX_CFG, 0);
+       smsc911x_reg_write(pdata, RX_CFG, 0);
+
+       return result;
+}
+#endif                         /* USE_PHY_WORK_AROUND */
+
+static void smsc911x_phy_update_flowcontrol(struct smsc911x_data *pdata)
+{
+       struct phy_device *phy_dev = pdata->phy_dev;
+       u32 afc = smsc911x_reg_read(pdata, AFC_CFG);
+       u32 flow;
+       unsigned long flags;
+
+       if (phy_dev->duplex == DUPLEX_FULL) {
+               u16 lcladv = phy_read(phy_dev, MII_ADVERTISE);
+               u16 rmtadv = phy_read(phy_dev, MII_LPA);
+               u8 cap = mii_resolve_flowctrl_fdx(lcladv, rmtadv);
+
+               if (cap & FLOW_CTRL_RX)
+                       flow = 0xFFFF0002;
+               else
+                       flow = 0;
+
+               if (cap & FLOW_CTRL_TX)
+                       afc |= 0xF;
+               else
+                       afc &= ~0xF;
+
+               SMSC_TRACE(pdata, hw, "rx pause %s, tx pause %s",
+                          (cap & FLOW_CTRL_RX ? "enabled" : "disabled"),
+                          (cap & FLOW_CTRL_TX ? "enabled" : "disabled"));
+       } else {
+               SMSC_TRACE(pdata, hw, "half duplex");
+               flow = 0;
+               afc |= 0xF;
+       }
+
+       spin_lock_irqsave(&pdata->mac_lock, flags);
+       smsc911x_mac_write(pdata, FLOW, flow);
+       spin_unlock_irqrestore(&pdata->mac_lock, flags);
+
+       smsc911x_reg_write(pdata, AFC_CFG, afc);
+}
+
+/* Update link mode if anything has changed.  Called periodically when the
+ * PHY is in polling mode, even if nothing has changed. */
+static void smsc911x_phy_adjust_link(struct net_device *dev)
+{
+       struct smsc911x_data *pdata = netdev_priv(dev);
+       struct phy_device *phy_dev = pdata->phy_dev;
+       unsigned long flags;
+       int carrier;
+
+       if (phy_dev->duplex != pdata->last_duplex) {
+               unsigned int mac_cr;
+               SMSC_TRACE(pdata, hw, "duplex state has changed");
+
+               spin_lock_irqsave(&pdata->mac_lock, flags);
+               mac_cr = smsc911x_mac_read(pdata, MAC_CR);
+               if (phy_dev->duplex) {
+                       SMSC_TRACE(pdata, hw,
+                                  "configuring for full duplex mode");
+                       mac_cr |= MAC_CR_FDPX_;
+               } else {
+                       SMSC_TRACE(pdata, hw,
+                                  "configuring for half duplex mode");
+                       mac_cr &= ~MAC_CR_FDPX_;
+               }
+               smsc911x_mac_write(pdata, MAC_CR, mac_cr);
+               spin_unlock_irqrestore(&pdata->mac_lock, flags);
+
+               smsc911x_phy_update_flowcontrol(pdata);
+               pdata->last_duplex = phy_dev->duplex;
+       }
+
+       carrier = netif_carrier_ok(dev);
+       if (carrier != pdata->last_carrier) {
+               SMSC_TRACE(pdata, hw, "carrier state has changed");
+               if (carrier) {
+                       SMSC_TRACE(pdata, hw, "configuring for carrier OK");
+                       if ((pdata->gpio_orig_setting & GPIO_CFG_LED1_EN_) &&
+                           (!pdata->using_extphy)) {
+                               /* Restore original GPIO configuration */
+                               pdata->gpio_setting = pdata->gpio_orig_setting;
+                               smsc911x_reg_write(pdata, GPIO_CFG,
+                                       pdata->gpio_setting);
+                       }
+               } else {
+                       SMSC_TRACE(pdata, hw, "configuring for no carrier");
+                       /* Check global setting that LED1
+                        * usage is 10/100 indicator */
+                       pdata->gpio_setting = smsc911x_reg_read(pdata,
+                               GPIO_CFG);
+                       if ((pdata->gpio_setting & GPIO_CFG_LED1_EN_) &&
+                           (!pdata->using_extphy)) {
+                               /* Force 10/100 LED off, after saving
+                                * original GPIO configuration */
+                               pdata->gpio_orig_setting = pdata->gpio_setting;
+
+                               pdata->gpio_setting &= ~GPIO_CFG_LED1_EN_;
+                               pdata->gpio_setting |= (GPIO_CFG_GPIOBUF0_
+                                                       | GPIO_CFG_GPIODIR0_
+                                                       | GPIO_CFG_GPIOD0_);
+                               smsc911x_reg_write(pdata, GPIO_CFG,
+                                       pdata->gpio_setting);
+                       }
+               }
+               pdata->last_carrier = carrier;
+       }
+}
+
+static int smsc911x_mii_probe(struct net_device *dev)
+{
+       struct smsc911x_data *pdata = netdev_priv(dev);
+       struct phy_device *phydev = NULL;
+       int ret;
+
+       /* find the first phy */
+       phydev = phy_find_first(pdata->mii_bus);
+       if (!phydev) {
+               netdev_err(dev, "no PHY found\n");
+               return -ENODEV;
+       }
+
+       SMSC_TRACE(pdata, probe, "PHY: addr %d, phy_id 0x%08X",
+                  phydev->addr, phydev->phy_id);
+
+       ret = phy_connect_direct(dev, phydev,
+                       &smsc911x_phy_adjust_link, 0,
+                       pdata->config.phy_interface);
+
+       if (ret) {
+               netdev_err(dev, "Could not attach to PHY\n");
+               return ret;
+       }
+
+       netdev_info(dev,
+                   "attached PHY driver [%s] (mii_bus:phy_addr=%s, irq=%d)\n",
+                   phydev->drv->name, dev_name(&phydev->dev), phydev->irq);
+
+       /* mask with MAC supported features */
+       phydev->supported &= (PHY_BASIC_FEATURES | SUPPORTED_Pause |
+                             SUPPORTED_Asym_Pause);
+       phydev->advertising = phydev->supported;
+
+       pdata->phy_dev = phydev;
+       pdata->last_duplex = -1;
+       pdata->last_carrier = -1;
+
+#ifdef USE_PHY_WORK_AROUND
+       if (smsc911x_phy_loopbacktest(dev) < 0) {
+               SMSC_WARN(pdata, hw, "Failed Loop Back Test");
+               return -ENODEV;
+       }
+       SMSC_TRACE(pdata, hw, "Passed Loop Back Test");
+#endif                         /* USE_PHY_WORK_AROUND */
+
+       SMSC_TRACE(pdata, hw, "phy initialised successfully");
+       return 0;
+}
+
+static int __devinit smsc911x_mii_init(struct platform_device *pdev,
+                                      struct net_device *dev)
+{
+       struct smsc911x_data *pdata = netdev_priv(dev);
+       int err = -ENXIO, i;
+
+       pdata->mii_bus = mdiobus_alloc();
+       if (!pdata->mii_bus) {
+               err = -ENOMEM;
+               goto err_out_1;
+       }
+
+       pdata->mii_bus->name = SMSC_MDIONAME;
+       snprintf(pdata->mii_bus->id, MII_BUS_ID_SIZE, "%x", pdev->id);
+       pdata->mii_bus->priv = pdata;
+       pdata->mii_bus->read = smsc911x_mii_read;
+       pdata->mii_bus->write = smsc911x_mii_write;
+       pdata->mii_bus->irq = pdata->phy_irq;
+       for (i = 0; i < PHY_MAX_ADDR; ++i)
+               pdata->mii_bus->irq[i] = PHY_POLL;
+
+       pdata->mii_bus->parent = &pdev->dev;
+
+       switch (pdata->idrev & 0xFFFF0000) {
+       case 0x01170000:
+       case 0x01150000:
+       case 0x117A0000:
+       case 0x115A0000:
+               /* External PHY supported, try to autodetect */
+               smsc911x_phy_initialise_external(pdata);
+               break;
+       default:
+               SMSC_TRACE(pdata, hw, "External PHY is not supported, "
+                          "using internal PHY");
+               pdata->using_extphy = 0;
+               break;
+       }
+
+       if (!pdata->using_extphy) {
+               /* Mask all PHYs except ID 1 (internal) */
+               pdata->mii_bus->phy_mask = ~(1 << 1);
+       }
+
+       if (mdiobus_register(pdata->mii_bus)) {
+               SMSC_WARN(pdata, probe, "Error registering mii bus");
+               goto err_out_free_bus_2;
+       }
+
+       if (smsc911x_mii_probe(dev) < 0) {
+               SMSC_WARN(pdata, probe, "Error registering mii bus");
+               goto err_out_unregister_bus_3;
+       }
+
+       return 0;
+
+err_out_unregister_bus_3:
+       mdiobus_unregister(pdata->mii_bus);
+err_out_free_bus_2:
+       mdiobus_free(pdata->mii_bus);
+err_out_1:
+       return err;
+}
+
+/* Gets the number of tx statuses in the fifo */
+static unsigned int smsc911x_tx_get_txstatcount(struct smsc911x_data *pdata)
+{
+       return (smsc911x_reg_read(pdata, TX_FIFO_INF)
+               & TX_FIFO_INF_TSUSED_) >> 16;
+}
+
+/* Reads tx statuses and increments counters where necessary */
+static void smsc911x_tx_update_txcounters(struct net_device *dev)
+{
+       struct smsc911x_data *pdata = netdev_priv(dev);
+       unsigned int tx_stat;
+
+       while ((tx_stat = smsc911x_tx_get_txstatus(pdata)) != 0) {
+               if (unlikely(tx_stat & 0x80000000)) {
+                       /* In this driver the packet tag is used as the packet
+                        * length. Since a packet length can never reach the
+                        * size of 0x8000, this bit is reserved. It is worth
+                        * noting that the "reserved bit" in the warning above
+                        * does not reference a hardware defined reserved bit
+                        * but rather a driver defined one.
+                        */
+                       SMSC_WARN(pdata, hw, "Packet tag reserved bit is high");
+               } else {
+                       if (unlikely(tx_stat & TX_STS_ES_)) {
+                               dev->stats.tx_errors++;
+                       } else {
+                               dev->stats.tx_packets++;
+                               dev->stats.tx_bytes += (tx_stat >> 16);
+                       }
+                       if (unlikely(tx_stat & TX_STS_EXCESS_COL_)) {
+                               dev->stats.collisions += 16;
+                               dev->stats.tx_aborted_errors += 1;
+                       } else {
+                               dev->stats.collisions +=
+                                   ((tx_stat >> 3) & 0xF);
+                       }
+                       if (unlikely(tx_stat & TX_STS_LOST_CARRIER_))
+                               dev->stats.tx_carrier_errors += 1;
+                       if (unlikely(tx_stat & TX_STS_LATE_COL_)) {
+                               dev->stats.collisions++;
+                               dev->stats.tx_aborted_errors++;
+                       }
+               }
+       }
+}
+
+/* Increments the Rx error counters */
+static void
+smsc911x_rx_counterrors(struct net_device *dev, unsigned int rxstat)
+{
+       int crc_err = 0;
+
+       if (unlikely(rxstat & RX_STS_ES_)) {
+               dev->stats.rx_errors++;
+               if (unlikely(rxstat & RX_STS_CRC_ERR_)) {
+                       dev->stats.rx_crc_errors++;
+                       crc_err = 1;
+               }
+       }
+       if (likely(!crc_err)) {
+               if (unlikely((rxstat & RX_STS_FRAME_TYPE_) &&
+                            (rxstat & RX_STS_LENGTH_ERR_)))
+                       dev->stats.rx_length_errors++;
+               if (rxstat & RX_STS_MCAST_)
+                       dev->stats.multicast++;
+       }
+}
+
+/* Quickly dumps bad packets */
+static void
+smsc911x_rx_fastforward(struct smsc911x_data *pdata, unsigned int pktbytes)
+{
+       unsigned int pktwords = (pktbytes + NET_IP_ALIGN + 3) >> 2;
+
+       if (likely(pktwords >= 4)) {
+               unsigned int timeout = 500;
+               unsigned int val;
+               smsc911x_reg_write(pdata, RX_DP_CTRL, RX_DP_CTRL_RX_FFWD_);
+               do {
+                       udelay(1);
+                       val = smsc911x_reg_read(pdata, RX_DP_CTRL);
+               } while ((val & RX_DP_CTRL_RX_FFWD_) && --timeout);
+
+               if (unlikely(timeout == 0))
+                       SMSC_WARN(pdata, hw, "Timed out waiting for "
+                                 "RX FFWD to finish, RX_DP_CTRL: 0x%08X", val);
+       } else {
+               unsigned int temp;
+               while (pktwords--)
+                       temp = smsc911x_reg_read(pdata, RX_DATA_FIFO);
+       }
+}
+
+/* NAPI poll function */
+static int smsc911x_poll(struct napi_struct *napi, int budget)
+{
+       struct smsc911x_data *pdata =
+               container_of(napi, struct smsc911x_data, napi);
+       struct net_device *dev = pdata->dev;
+       int npackets = 0;
+
+       while (npackets < budget) {
+               unsigned int pktlength;
+               unsigned int pktwords;
+               struct sk_buff *skb;
+               unsigned int rxstat = smsc911x_rx_get_rxstatus(pdata);
+
+               if (!rxstat) {
+                       unsigned int temp;
+                       /* We processed all packets available.  Tell NAPI it can
+                        * stop polling then re-enable rx interrupts */
+                       smsc911x_reg_write(pdata, INT_STS, INT_STS_RSFL_);
+                       napi_complete(napi);
+                       temp = smsc911x_reg_read(pdata, INT_EN);
+                       temp |= INT_EN_RSFL_EN_;
+                       smsc911x_reg_write(pdata, INT_EN, temp);
+                       break;
+               }
+
+               /* Count packet for NAPI scheduling, even if it has an error.
+                * Error packets still require cycles to discard */
+               npackets++;
+
+               pktlength = ((rxstat & 0x3FFF0000) >> 16);
+               pktwords = (pktlength + NET_IP_ALIGN + 3) >> 2;
+               smsc911x_rx_counterrors(dev, rxstat);
+
+               if (unlikely(rxstat & RX_STS_ES_)) {
+                       SMSC_WARN(pdata, rx_err,
+                                 "Discarding packet with error bit set");
+                       /* Packet has an error, discard it and continue with
+                        * the next */
+                       smsc911x_rx_fastforward(pdata, pktwords);
+                       dev->stats.rx_dropped++;
+                       continue;
+               }
+
+               skb = netdev_alloc_skb(dev, pktlength + NET_IP_ALIGN);
+               if (unlikely(!skb)) {
+                       SMSC_WARN(pdata, rx_err,
+                                 "Unable to allocate skb for rx packet");
+                       /* Drop the packet and stop this polling iteration */
+                       smsc911x_rx_fastforward(pdata, pktwords);
+                       dev->stats.rx_dropped++;
+                       break;
+               }
+
+               skb->data = skb->head;
+               skb_reset_tail_pointer(skb);
+
+               /* Align IP on 16B boundary */
+               skb_reserve(skb, NET_IP_ALIGN);
+               skb_put(skb, pktlength - 4);
+               pdata->ops->rx_readfifo(pdata,
+                                (unsigned int *)skb->head, pktwords);
+               skb->protocol = eth_type_trans(skb, dev);
+               skb_checksum_none_assert(skb);
+               netif_receive_skb(skb);
+
+               /* Update counters */
+               dev->stats.rx_packets++;
+               dev->stats.rx_bytes += (pktlength - 4);
+       }
+
+       /* Return total received packets */
+       return npackets;
+}
+
+/* Returns hash bit number for given MAC address
+ * Example:
+ * 01 00 5E 00 00 01 -> returns bit number 31 */
+static unsigned int smsc911x_hash(char addr[ETH_ALEN])
+{
+       return (ether_crc(ETH_ALEN, addr) >> 26) & 0x3f;
+}
+
+static void smsc911x_rx_multicast_update(struct smsc911x_data *pdata)
+{
+       /* Performs the multicast & mac_cr update.  This is called when
+        * safe on the current hardware, and with the mac_lock held */
+       unsigned int mac_cr;
+
+       SMSC_ASSERT_MAC_LOCK(pdata);
+
+       mac_cr = smsc911x_mac_read(pdata, MAC_CR);
+       mac_cr |= pdata->set_bits_mask;
+       mac_cr &= ~(pdata->clear_bits_mask);
+       smsc911x_mac_write(pdata, MAC_CR, mac_cr);
+       smsc911x_mac_write(pdata, HASHH, pdata->hashhi);
+       smsc911x_mac_write(pdata, HASHL, pdata->hashlo);
+       SMSC_TRACE(pdata, hw, "maccr 0x%08X, HASHH 0x%08X, HASHL 0x%08X",
+                  mac_cr, pdata->hashhi, pdata->hashlo);
+}
+
+static void smsc911x_rx_multicast_update_workaround(struct smsc911x_data *pdata)
+{
+       unsigned int mac_cr;
+
+       /* This function is only called for older LAN911x devices
+        * (revA or revB), where MAC_CR, HASHH and HASHL should not
+        * be modified during Rx - newer devices immediately update the
+        * registers.
+        *
+        * This is called from interrupt context */
+
+       spin_lock(&pdata->mac_lock);
+
+       /* Check Rx has stopped */
+       if (smsc911x_mac_read(pdata, MAC_CR) & MAC_CR_RXEN_)
+               SMSC_WARN(pdata, drv, "Rx not stopped");
+
+       /* Perform the update - safe to do now Rx has stopped */
+       smsc911x_rx_multicast_update(pdata);
+
+       /* Re-enable Rx */
+       mac_cr = smsc911x_mac_read(pdata, MAC_CR);
+       mac_cr |= MAC_CR_RXEN_;
+       smsc911x_mac_write(pdata, MAC_CR, mac_cr);
+
+       pdata->multicast_update_pending = 0;
+
+       spin_unlock(&pdata->mac_lock);
+}
+
+static int smsc911x_soft_reset(struct smsc911x_data *pdata)
+{
+       unsigned int timeout;
+       unsigned int temp;
+
+       /* Reset the LAN911x */
+       smsc911x_reg_write(pdata, HW_CFG, HW_CFG_SRST_);
+       timeout = 10;
+       do {
+               udelay(10);
+               temp = smsc911x_reg_read(pdata, HW_CFG);
+       } while ((--timeout) && (temp & HW_CFG_SRST_));
+
+       if (unlikely(temp & HW_CFG_SRST_)) {
+               SMSC_WARN(pdata, drv, "Failed to complete reset");
+               return -EIO;
+       }
+       return 0;
+}
+
+/* Sets the device MAC address to dev_addr, called with mac_lock held */
+static void
+smsc911x_set_hw_mac_address(struct smsc911x_data *pdata, u8 dev_addr[6])
+{
+       u32 mac_high16 = (dev_addr[5] << 8) | dev_addr[4];
+       u32 mac_low32 = (dev_addr[3] << 24) | (dev_addr[2] << 16) |
+           (dev_addr[1] << 8) | dev_addr[0];
+
+       SMSC_ASSERT_MAC_LOCK(pdata);
+
+       smsc911x_mac_write(pdata, ADDRH, mac_high16);
+       smsc911x_mac_write(pdata, ADDRL, mac_low32);
+}
+
+static int smsc911x_open(struct net_device *dev)
+{
+       struct smsc911x_data *pdata = netdev_priv(dev);
+       unsigned int timeout;
+       unsigned int temp;
+       unsigned int intcfg;
+
+       /* if the phy is not yet registered, retry later*/
+       if (!pdata->phy_dev) {
+               SMSC_WARN(pdata, hw, "phy_dev is NULL");
+               return -EAGAIN;
+       }
+
+       if (!is_valid_ether_addr(dev->dev_addr)) {
+               SMSC_WARN(pdata, hw, "dev_addr is not a valid MAC address");
+               return -EADDRNOTAVAIL;
+       }
+
+       /* Reset the LAN911x */
+       if (smsc911x_soft_reset(pdata)) {
+               SMSC_WARN(pdata, hw, "soft reset failed");
+               return -EIO;
+       }
+
+       smsc911x_reg_write(pdata, HW_CFG, 0x00050000);
+       smsc911x_reg_write(pdata, AFC_CFG, 0x006E3740);
+
+       /* Increase the legal frame size of VLAN tagged frames to 1522 bytes */
+       spin_lock_irq(&pdata->mac_lock);
+       smsc911x_mac_write(pdata, VLAN1, ETH_P_8021Q);
+       spin_unlock_irq(&pdata->mac_lock);
+
+       /* Make sure EEPROM has finished loading before setting GPIO_CFG */
+       timeout = 50;
+       while ((smsc911x_reg_read(pdata, E2P_CMD) & E2P_CMD_EPC_BUSY_) &&
+              --timeout) {
+               udelay(10);
+       }
+
+       if (unlikely(timeout == 0))
+               SMSC_WARN(pdata, ifup,
+                         "Timed out waiting for EEPROM busy bit to clear");
+
+       smsc911x_reg_write(pdata, GPIO_CFG, 0x70070000);
+
+       /* The soft reset above cleared the device's MAC address,
+        * restore it from local copy (set in probe) */
+       spin_lock_irq(&pdata->mac_lock);
+       smsc911x_set_hw_mac_address(pdata, dev->dev_addr);
+       spin_unlock_irq(&pdata->mac_lock);
+
+       /* Initialise irqs, but leave all sources disabled */
+       smsc911x_reg_write(pdata, INT_EN, 0);
+       smsc911x_reg_write(pdata, INT_STS, 0xFFFFFFFF);
+
+       /* Set interrupt deassertion to 100uS */
+       intcfg = ((10 << 24) | INT_CFG_IRQ_EN_);
+
+       if (pdata->config.irq_polarity) {
+               SMSC_TRACE(pdata, ifup, "irq polarity: active high");
+               intcfg |= INT_CFG_IRQ_POL_;
+       } else {
+               SMSC_TRACE(pdata, ifup, "irq polarity: active low");
+       }
+
+       if (pdata->config.irq_type) {
+               SMSC_TRACE(pdata, ifup, "irq type: push-pull");
+               intcfg |= INT_CFG_IRQ_TYPE_;
+       } else {
+               SMSC_TRACE(pdata, ifup, "irq type: open drain");
+       }
+
+       smsc911x_reg_write(pdata, INT_CFG, intcfg);
+
+       SMSC_TRACE(pdata, ifup, "Testing irq handler using IRQ %d", dev->irq);
+       pdata->software_irq_signal = 0;
+       smp_wmb();
+
+       temp = smsc911x_reg_read(pdata, INT_EN);
+       temp |= INT_EN_SW_INT_EN_;
+       smsc911x_reg_write(pdata, INT_EN, temp);
+
+       timeout = 1000;
+       while (timeout--) {
+               if (pdata->software_irq_signal)
+                       break;
+               msleep(1);
+       }
+
+       if (!pdata->software_irq_signal) {
+               netdev_warn(dev, "ISR failed signaling test (IRQ %d)\n",
+                           dev->irq);
+               return -ENODEV;
+       }
+       SMSC_TRACE(pdata, ifup, "IRQ handler passed test using IRQ %d",
+                  dev->irq);
+
+       netdev_info(dev, "SMSC911x/921x identified at %#08lx, IRQ: %d\n",
+                   (unsigned long)pdata->ioaddr, dev->irq);
+
+       /* Reset the last known duplex and carrier */
+       pdata->last_duplex = -1;
+       pdata->last_carrier = -1;
+
+       /* Bring the PHY up */
+       phy_start(pdata->phy_dev);
+
+       temp = smsc911x_reg_read(pdata, HW_CFG);
+       /* Preserve TX FIFO size and external PHY configuration */
+       temp &= (HW_CFG_TX_FIF_SZ_|0x00000FFF);
+       temp |= HW_CFG_SF_;
+       smsc911x_reg_write(pdata, HW_CFG, temp);
+
+       temp = smsc911x_reg_read(pdata, FIFO_INT);
+       temp |= FIFO_INT_TX_AVAIL_LEVEL_;
+       temp &= ~(FIFO_INT_RX_STS_LEVEL_);
+       smsc911x_reg_write(pdata, FIFO_INT, temp);
+
+       /* set RX Data offset to 2 bytes for alignment */
+       smsc911x_reg_write(pdata, RX_CFG, (2 << 8));
+
+       /* enable NAPI polling before enabling RX interrupts */
+       napi_enable(&pdata->napi);
+
+       temp = smsc911x_reg_read(pdata, INT_EN);
+       temp |= (INT_EN_TDFA_EN_ | INT_EN_RSFL_EN_ | INT_EN_RXSTOP_INT_EN_);
+       smsc911x_reg_write(pdata, INT_EN, temp);
+
+       spin_lock_irq(&pdata->mac_lock);
+       temp = smsc911x_mac_read(pdata, MAC_CR);
+       temp |= (MAC_CR_TXEN_ | MAC_CR_RXEN_ | MAC_CR_HBDIS_);
+       smsc911x_mac_write(pdata, MAC_CR, temp);
+       spin_unlock_irq(&pdata->mac_lock);
+
+       smsc911x_reg_write(pdata, TX_CFG, TX_CFG_TX_ON_);
+
+       netif_start_queue(dev);
+       return 0;
+}
+
+/* Entry point for stopping the interface */
+static int smsc911x_stop(struct net_device *dev)
+{
+       struct smsc911x_data *pdata = netdev_priv(dev);
+       unsigned int temp;
+
+       /* Disable all device interrupts */
+       temp = smsc911x_reg_read(pdata, INT_CFG);
+       temp &= ~INT_CFG_IRQ_EN_;
+       smsc911x_reg_write(pdata, INT_CFG, temp);
+
+       /* Stop Tx and Rx polling */
+       netif_stop_queue(dev);
+       napi_disable(&pdata->napi);
+
+       /* At this point all Rx and Tx activity is stopped */
+       dev->stats.rx_dropped += smsc911x_reg_read(pdata, RX_DROP);
+       smsc911x_tx_update_txcounters(dev);
+
+       /* Bring the PHY down */
+       if (pdata->phy_dev)
+               phy_stop(pdata->phy_dev);
+
+       SMSC_TRACE(pdata, ifdown, "Interface stopped");
+       return 0;
+}
+
+/* Entry point for transmitting a packet */
+static int smsc911x_hard_start_xmit(struct sk_buff *skb, struct net_device *dev)
+{
+       struct smsc911x_data *pdata = netdev_priv(dev);
+       unsigned int freespace;
+       unsigned int tx_cmd_a;
+       unsigned int tx_cmd_b;
+       unsigned int temp;
+       u32 wrsz;
+       ulong bufp;
+
+       freespace = smsc911x_reg_read(pdata, TX_FIFO_INF) & TX_FIFO_INF_TDFREE_;
+
+       if (unlikely(freespace < TX_FIFO_LOW_THRESHOLD))
+               SMSC_WARN(pdata, tx_err,
+                         "Tx data fifo low, space available: %d", freespace);
+
+       /* Word alignment adjustment */
+       tx_cmd_a = (u32)((ulong)skb->data & 0x03) << 16;
+       tx_cmd_a |= TX_CMD_A_FIRST_SEG_ | TX_CMD_A_LAST_SEG_;
+       tx_cmd_a |= (unsigned int)skb->len;
+
+       tx_cmd_b = ((unsigned int)skb->len) << 16;
+       tx_cmd_b |= (unsigned int)skb->len;
+
+       smsc911x_reg_write(pdata, TX_DATA_FIFO, tx_cmd_a);
+       smsc911x_reg_write(pdata, TX_DATA_FIFO, tx_cmd_b);
+
+       bufp = (ulong)skb->data & (~0x3);
+       wrsz = (u32)skb->len + 3;
+       wrsz += (u32)((ulong)skb->data & 0x3);
+       wrsz >>= 2;
+
+       pdata->ops->tx_writefifo(pdata, (unsigned int *)bufp, wrsz);
+       freespace -= (skb->len + 32);
+       skb_tx_timestamp(skb);
+       dev_kfree_skb(skb);
+
+       if (unlikely(smsc911x_tx_get_txstatcount(pdata) >= 30))
+               smsc911x_tx_update_txcounters(dev);
+
+       if (freespace < TX_FIFO_LOW_THRESHOLD) {
+               netif_stop_queue(dev);
+               temp = smsc911x_reg_read(pdata, FIFO_INT);
+               temp &= 0x00FFFFFF;
+               temp |= 0x32000000;
+               smsc911x_reg_write(pdata, FIFO_INT, temp);
+       }
+
+       return NETDEV_TX_OK;
+}
+
+/* Entry point for getting status counters */
+static struct net_device_stats *smsc911x_get_stats(struct net_device *dev)
+{
+       struct smsc911x_data *pdata = netdev_priv(dev);
+       smsc911x_tx_update_txcounters(dev);
+       dev->stats.rx_dropped += smsc911x_reg_read(pdata, RX_DROP);
+       return &dev->stats;
+}
+
+/* Entry point for setting addressing modes */
+static void smsc911x_set_multicast_list(struct net_device *dev)
+{
+       struct smsc911x_data *pdata = netdev_priv(dev);
+       unsigned long flags;
+
+       if (dev->flags & IFF_PROMISC) {
+               /* Enabling promiscuous mode */
+               pdata->set_bits_mask = MAC_CR_PRMS_;
+               pdata->clear_bits_mask = (MAC_CR_MCPAS_ | MAC_CR_HPFILT_);
+               pdata->hashhi = 0;
+               pdata->hashlo = 0;
+       } else if (dev->flags & IFF_ALLMULTI) {
+               /* Enabling all multicast mode */
+               pdata->set_bits_mask = MAC_CR_MCPAS_;
+               pdata->clear_bits_mask = (MAC_CR_PRMS_ | MAC_CR_HPFILT_);
+               pdata->hashhi = 0;
+               pdata->hashlo = 0;
+       } else if (!netdev_mc_empty(dev)) {
+               /* Enabling specific multicast addresses */
+               unsigned int hash_high = 0;
+               unsigned int hash_low = 0;
+               struct netdev_hw_addr *ha;
+
+               pdata->set_bits_mask = MAC_CR_HPFILT_;
+               pdata->clear_bits_mask = (MAC_CR_PRMS_ | MAC_CR_MCPAS_);
+
+               netdev_for_each_mc_addr(ha, dev) {
+                       unsigned int bitnum = smsc911x_hash(ha->addr);
+                       unsigned int mask = 0x01 << (bitnum & 0x1F);
+
+                       if (bitnum & 0x20)
+                               hash_high |= mask;
+                       else
+                               hash_low |= mask;
+               }
+
+               pdata->hashhi = hash_high;
+               pdata->hashlo = hash_low;
+       } else {
+               /* Enabling local MAC address only */
+               pdata->set_bits_mask = 0;
+               pdata->clear_bits_mask =
+                   (MAC_CR_PRMS_ | MAC_CR_MCPAS_ | MAC_CR_HPFILT_);
+               pdata->hashhi = 0;
+               pdata->hashlo = 0;
+       }
+
+       spin_lock_irqsave(&pdata->mac_lock, flags);
+
+       if (pdata->generation <= 1) {
+               /* Older hardware revision - cannot change these flags while
+                * receiving data */
+               if (!pdata->multicast_update_pending) {
+                       unsigned int temp;
+                       SMSC_TRACE(pdata, hw, "scheduling mcast update");
+                       pdata->multicast_update_pending = 1;
+
+                       /* Request the hardware to stop, then perform the
+                        * update when we get an RX_STOP interrupt */
+                       temp = smsc911x_mac_read(pdata, MAC_CR);
+                       temp &= ~(MAC_CR_RXEN_);
+                       smsc911x_mac_write(pdata, MAC_CR, temp);
+               } else {
+                       /* There is another update pending, this should now
+                        * use the newer values */
+               }
+       } else {
+               /* Newer hardware revision - can write immediately */
+               smsc911x_rx_multicast_update(pdata);
+       }
+
+       spin_unlock_irqrestore(&pdata->mac_lock, flags);
+}
+
+static irqreturn_t smsc911x_irqhandler(int irq, void *dev_id)
+{
+       struct net_device *dev = dev_id;
+       struct smsc911x_data *pdata = netdev_priv(dev);
+       u32 intsts = smsc911x_reg_read(pdata, INT_STS);
+       u32 inten = smsc911x_reg_read(pdata, INT_EN);
+       int serviced = IRQ_NONE;
+       u32 temp;
+
+       if (unlikely(intsts & inten & INT_STS_SW_INT_)) {
+               temp = smsc911x_reg_read(pdata, INT_EN);
+               temp &= (~INT_EN_SW_INT_EN_);
+               smsc911x_reg_write(pdata, INT_EN, temp);
+               smsc911x_reg_write(pdata, INT_STS, INT_STS_SW_INT_);
+               pdata->software_irq_signal = 1;
+               smp_wmb();
+               serviced = IRQ_HANDLED;
+       }
+
+       if (unlikely(intsts & inten & INT_STS_RXSTOP_INT_)) {
+               /* Called when there is a multicast update scheduled and
+                * it is now safe to complete the update */
+               SMSC_TRACE(pdata, intr, "RX Stop interrupt");
+               smsc911x_reg_write(pdata, INT_STS, INT_STS_RXSTOP_INT_);
+               if (pdata->multicast_update_pending)
+                       smsc911x_rx_multicast_update_workaround(pdata);
+               serviced = IRQ_HANDLED;
+       }
+
+       if (intsts & inten & INT_STS_TDFA_) {
+               temp = smsc911x_reg_read(pdata, FIFO_INT);
+               temp |= FIFO_INT_TX_AVAIL_LEVEL_;
+               smsc911x_reg_write(pdata, FIFO_INT, temp);
+               smsc911x_reg_write(pdata, INT_STS, INT_STS_TDFA_);
+               netif_wake_queue(dev);
+               serviced = IRQ_HANDLED;
+       }
+
+       if (unlikely(intsts & inten & INT_STS_RXE_)) {
+               SMSC_TRACE(pdata, intr, "RX Error interrupt");
+               smsc911x_reg_write(pdata, INT_STS, INT_STS_RXE_);
+               serviced = IRQ_HANDLED;
+       }
+
+       if (likely(intsts & inten & INT_STS_RSFL_)) {
+               if (likely(napi_schedule_prep(&pdata->napi))) {
+                       /* Disable Rx interrupts */
+                       temp = smsc911x_reg_read(pdata, INT_EN);
+                       temp &= (~INT_EN_RSFL_EN_);
+                       smsc911x_reg_write(pdata, INT_EN, temp);
+                       /* Schedule a NAPI poll */
+                       __napi_schedule(&pdata->napi);
+               } else {
+                       SMSC_WARN(pdata, rx_err, "napi_schedule_prep failed");
+               }
+               serviced = IRQ_HANDLED;
+       }
+
+       return serviced;
+}
+
+#ifdef CONFIG_NET_POLL_CONTROLLER
+static void smsc911x_poll_controller(struct net_device *dev)
+{
+       disable_irq(dev->irq);
+       smsc911x_irqhandler(0, dev);
+       enable_irq(dev->irq);
+}
+#endif                         /* CONFIG_NET_POLL_CONTROLLER */
+
+static int smsc911x_set_mac_address(struct net_device *dev, void *p)
+{
+       struct smsc911x_data *pdata = netdev_priv(dev);
+       struct sockaddr *addr = p;
+
+       /* On older hardware revisions we cannot change the mac address
+        * registers while receiving data.  Newer devices can safely change
+        * this at any time. */
+       if (pdata->generation <= 1 && netif_running(dev))
+               return -EBUSY;
+
+       if (!is_valid_ether_addr(addr->sa_data))
+               return -EADDRNOTAVAIL;
+
+       memcpy(dev->dev_addr, addr->sa_data, ETH_ALEN);
+
+       spin_lock_irq(&pdata->mac_lock);
+       smsc911x_set_hw_mac_address(pdata, dev->dev_addr);
+       spin_unlock_irq(&pdata->mac_lock);
+
+       netdev_info(dev, "MAC Address: %pM\n", dev->dev_addr);
+
+       return 0;
+}
+
+/* Standard ioctls for mii-tool */
+static int smsc911x_do_ioctl(struct net_device *dev, struct ifreq *ifr, int cmd)
+{
+       struct smsc911x_data *pdata = netdev_priv(dev);
+
+       if (!netif_running(dev) || !pdata->phy_dev)
+               return -EINVAL;
+
+       return phy_mii_ioctl(pdata->phy_dev, ifr, cmd);
+}
+
+static int
+smsc911x_ethtool_getsettings(struct net_device *dev, struct ethtool_cmd *cmd)
+{
+       struct smsc911x_data *pdata = netdev_priv(dev);
+
+       cmd->maxtxpkt = 1;
+       cmd->maxrxpkt = 1;
+       return phy_ethtool_gset(pdata->phy_dev, cmd);
+}
+
+static int
+smsc911x_ethtool_setsettings(struct net_device *dev, struct ethtool_cmd *cmd)
+{
+       struct smsc911x_data *pdata = netdev_priv(dev);
+
+       return phy_ethtool_sset(pdata->phy_dev, cmd);
+}
+
+static void smsc911x_ethtool_getdrvinfo(struct net_device *dev,
+                                       struct ethtool_drvinfo *info)
+{
+       strlcpy(info->driver, SMSC_CHIPNAME, sizeof(info->driver));
+       strlcpy(info->version, SMSC_DRV_VERSION, sizeof(info->version));
+       strlcpy(info->bus_info, dev_name(dev->dev.parent),
+               sizeof(info->bus_info));
+}
+
+static int smsc911x_ethtool_nwayreset(struct net_device *dev)
+{
+       struct smsc911x_data *pdata = netdev_priv(dev);
+
+       return phy_start_aneg(pdata->phy_dev);
+}
+
+static u32 smsc911x_ethtool_getmsglevel(struct net_device *dev)
+{
+       struct smsc911x_data *pdata = netdev_priv(dev);
+       return pdata->msg_enable;
+}
+
+static void smsc911x_ethtool_setmsglevel(struct net_device *dev, u32 level)
+{
+       struct smsc911x_data *pdata = netdev_priv(dev);
+       pdata->msg_enable = level;
+}
+
+static int smsc911x_ethtool_getregslen(struct net_device *dev)
+{
+       return (((E2P_DATA - ID_REV) / 4 + 1) + (WUCSR - MAC_CR) + 1 + 32) *
+           sizeof(u32);
+}
+
+static void
+smsc911x_ethtool_getregs(struct net_device *dev, struct ethtool_regs *regs,
+                        void *buf)
+{
+       struct smsc911x_data *pdata = netdev_priv(dev);
+       struct phy_device *phy_dev = pdata->phy_dev;
+       unsigned long flags;
+       unsigned int i;
+       unsigned int j = 0;
+       u32 *data = buf;
+
+       regs->version = pdata->idrev;
+       for (i = ID_REV; i <= E2P_DATA; i += (sizeof(u32)))
+               data[j++] = smsc911x_reg_read(pdata, i);
+
+       for (i = MAC_CR; i <= WUCSR; i++) {
+               spin_lock_irqsave(&pdata->mac_lock, flags);
+               data[j++] = smsc911x_mac_read(pdata, i);
+               spin_unlock_irqrestore(&pdata->mac_lock, flags);
+       }
+
+       for (i = 0; i <= 31; i++)
+               data[j++] = smsc911x_mii_read(phy_dev->bus, phy_dev->addr, i);
+}
+
+static void smsc911x_eeprom_enable_access(struct smsc911x_data *pdata)
+{
+       unsigned int temp = smsc911x_reg_read(pdata, GPIO_CFG);
+       temp &= ~GPIO_CFG_EEPR_EN_;
+       smsc911x_reg_write(pdata, GPIO_CFG, temp);
+       msleep(1);
+}
+
+static int smsc911x_eeprom_send_cmd(struct smsc911x_data *pdata, u32 op)
+{
+       int timeout = 100;
+       u32 e2cmd;
+
+       SMSC_TRACE(pdata, drv, "op 0x%08x", op);
+       if (smsc911x_reg_read(pdata, E2P_CMD) & E2P_CMD_EPC_BUSY_) {
+               SMSC_WARN(pdata, drv, "Busy at start");
+               return -EBUSY;
+       }
+
+       e2cmd = op | E2P_CMD_EPC_BUSY_;
+       smsc911x_reg_write(pdata, E2P_CMD, e2cmd);
+
+       do {
+               msleep(1);
+               e2cmd = smsc911x_reg_read(pdata, E2P_CMD);
+       } while ((e2cmd & E2P_CMD_EPC_BUSY_) && (--timeout));
+
+       if (!timeout) {
+               SMSC_TRACE(pdata, drv, "TIMED OUT");
+               return -EAGAIN;
+       }
+
+       if (e2cmd & E2P_CMD_EPC_TIMEOUT_) {
+               SMSC_TRACE(pdata, drv, "Error occurred during eeprom operation");
+               return -EINVAL;
+       }
+
+       return 0;
+}
+
+static int smsc911x_eeprom_read_location(struct smsc911x_data *pdata,
+                                        u8 address, u8 *data)
+{
+       u32 op = E2P_CMD_EPC_CMD_READ_ | address;
+       int ret;
+
+       SMSC_TRACE(pdata, drv, "address 0x%x", address);
+       ret = smsc911x_eeprom_send_cmd(pdata, op);
+
+       if (!ret)
+               data[address] = smsc911x_reg_read(pdata, E2P_DATA);
+
+       return ret;
+}
+
+static int smsc911x_eeprom_write_location(struct smsc911x_data *pdata,
+                                         u8 address, u8 data)
+{
+       u32 op = E2P_CMD_EPC_CMD_ERASE_ | address;
+       u32 temp;
+       int ret;
+
+       SMSC_TRACE(pdata, drv, "address 0x%x, data 0x%x", address, data);
+       ret = smsc911x_eeprom_send_cmd(pdata, op);
+
+       if (!ret) {
+               op = E2P_CMD_EPC_CMD_WRITE_ | address;
+               smsc911x_reg_write(pdata, E2P_DATA, (u32)data);
+
+               /* Workaround for hardware read-after-write restriction */
+               temp = smsc911x_reg_read(pdata, BYTE_TEST);
+
+               ret = smsc911x_eeprom_send_cmd(pdata, op);
+       }
+
+       return ret;
+}
+
+static int smsc911x_ethtool_get_eeprom_len(struct net_device *dev)
+{
+       return SMSC911X_EEPROM_SIZE;
+}
+
+static int smsc911x_ethtool_get_eeprom(struct net_device *dev,
+                                      struct ethtool_eeprom *eeprom, u8 *data)
+{
+       struct smsc911x_data *pdata = netdev_priv(dev);
+       u8 eeprom_data[SMSC911X_EEPROM_SIZE];
+       int len;
+       int i;
+
+       smsc911x_eeprom_enable_access(pdata);
+
+       len = min(eeprom->len, SMSC911X_EEPROM_SIZE);
+       for (i = 0; i < len; i++) {
+               int ret = smsc911x_eeprom_read_location(pdata, i, eeprom_data);
+               if (ret < 0) {
+                       eeprom->len = 0;
+                       return ret;
+               }
+       }
+
+       memcpy(data, &eeprom_data[eeprom->offset], len);
+       eeprom->len = len;
+       return 0;
+}
+
+static int smsc911x_ethtool_set_eeprom(struct net_device *dev,
+                                      struct ethtool_eeprom *eeprom, u8 *data)
+{
+       int ret;
+       struct smsc911x_data *pdata = netdev_priv(dev);
+
+       smsc911x_eeprom_enable_access(pdata);
+       smsc911x_eeprom_send_cmd(pdata, E2P_CMD_EPC_CMD_EWEN_);
+       ret = smsc911x_eeprom_write_location(pdata, eeprom->offset, *data);
+       smsc911x_eeprom_send_cmd(pdata, E2P_CMD_EPC_CMD_EWDS_);
+
+       /* Single byte write, according to man page */
+       eeprom->len = 1;
+
+       return ret;
+}
+
+static const struct ethtool_ops smsc911x_ethtool_ops = {
+       .get_settings = smsc911x_ethtool_getsettings,
+       .set_settings = smsc911x_ethtool_setsettings,
+       .get_link = ethtool_op_get_link,
+       .get_drvinfo = smsc911x_ethtool_getdrvinfo,
+       .nway_reset = smsc911x_ethtool_nwayreset,
+       .get_msglevel = smsc911x_ethtool_getmsglevel,
+       .set_msglevel = smsc911x_ethtool_setmsglevel,
+       .get_regs_len = smsc911x_ethtool_getregslen,
+       .get_regs = smsc911x_ethtool_getregs,
+       .get_eeprom_len = smsc911x_ethtool_get_eeprom_len,
+       .get_eeprom = smsc911x_ethtool_get_eeprom,
+       .set_eeprom = smsc911x_ethtool_set_eeprom,
+};
+
+static const struct net_device_ops smsc911x_netdev_ops = {
+       .ndo_open               = smsc911x_open,
+       .ndo_stop               = smsc911x_stop,
+       .ndo_start_xmit         = smsc911x_hard_start_xmit,
+       .ndo_get_stats          = smsc911x_get_stats,
+       .ndo_set_multicast_list = smsc911x_set_multicast_list,
+       .ndo_do_ioctl           = smsc911x_do_ioctl,
+       .ndo_change_mtu         = eth_change_mtu,
+       .ndo_validate_addr      = eth_validate_addr,
+       .ndo_set_mac_address    = smsc911x_set_mac_address,
+#ifdef CONFIG_NET_POLL_CONTROLLER
+       .ndo_poll_controller    = smsc911x_poll_controller,
+#endif
+};
+
+/* copies the current mac address from hardware to dev->dev_addr */
+static void __devinit smsc911x_read_mac_address(struct net_device *dev)
+{
+       struct smsc911x_data *pdata = netdev_priv(dev);
+       u32 mac_high16 = smsc911x_mac_read(pdata, ADDRH);
+       u32 mac_low32 = smsc911x_mac_read(pdata, ADDRL);
+
+       dev->dev_addr[0] = (u8)(mac_low32);
+       dev->dev_addr[1] = (u8)(mac_low32 >> 8);
+       dev->dev_addr[2] = (u8)(mac_low32 >> 16);
+       dev->dev_addr[3] = (u8)(mac_low32 >> 24);
+       dev->dev_addr[4] = (u8)(mac_high16);
+       dev->dev_addr[5] = (u8)(mac_high16 >> 8);
+}
+
+/* Initializing private device structures, only called from probe */
+static int __devinit smsc911x_init(struct net_device *dev)
+{
+       struct smsc911x_data *pdata = netdev_priv(dev);
+       unsigned int byte_test;
+
+       SMSC_TRACE(pdata, probe, "Driver Parameters:");
+       SMSC_TRACE(pdata, probe, "LAN base: 0x%08lX",
+                  (unsigned long)pdata->ioaddr);
+       SMSC_TRACE(pdata, probe, "IRQ: %d", dev->irq);
+       SMSC_TRACE(pdata, probe, "PHY will be autodetected.");
+
+       spin_lock_init(&pdata->dev_lock);
+       spin_lock_init(&pdata->mac_lock);
+
+       if (pdata->ioaddr == 0) {
+               SMSC_WARN(pdata, probe, "pdata->ioaddr: 0x00000000");
+               return -ENODEV;
+       }
+
+       /* Check byte ordering */
+       byte_test = smsc911x_reg_read(pdata, BYTE_TEST);
+       SMSC_TRACE(pdata, probe, "BYTE_TEST: 0x%08X", byte_test);
+       if (byte_test == 0x43218765) {
+               SMSC_TRACE(pdata, probe, "BYTE_TEST looks swapped, "
+                          "applying WORD_SWAP");
+               smsc911x_reg_write(pdata, WORD_SWAP, 0xffffffff);
+
+               /* 1 dummy read of BYTE_TEST is needed after a write to
+                * WORD_SWAP before its contents are valid */
+               byte_test = smsc911x_reg_read(pdata, BYTE_TEST);
+
+               byte_test = smsc911x_reg_read(pdata, BYTE_TEST);
+       }
+
+       if (byte_test != 0x87654321) {
+               SMSC_WARN(pdata, drv, "BYTE_TEST: 0x%08X", byte_test);
+               if (((byte_test >> 16) & 0xFFFF) == (byte_test & 0xFFFF)) {
+                       SMSC_WARN(pdata, probe,
+                                 "top 16 bits equal to bottom 16 bits");
+                       SMSC_TRACE(pdata, probe,
+                                  "This may mean the chip is set "
+                                  "for 32 bit while the bus is reading 16 bit");
+               }
+               return -ENODEV;
+       }
+
+       /* Default generation to zero (all workarounds apply) */
+       pdata->generation = 0;
+
+       pdata->idrev = smsc911x_reg_read(pdata, ID_REV);
+       switch (pdata->idrev & 0xFFFF0000) {
+       case 0x01180000:
+       case 0x01170000:
+       case 0x01160000:
+       case 0x01150000:
+               /* LAN911[5678] family */
+               pdata->generation = pdata->idrev & 0x0000FFFF;
+               break;
+
+       case 0x118A0000:
+       case 0x117A0000:
+       case 0x116A0000:
+       case 0x115A0000:
+               /* LAN921[5678] family */
+               pdata->generation = 3;
+               break;
+
+       case 0x92100000:
+       case 0x92110000:
+       case 0x92200000:
+       case 0x92210000:
+               /* LAN9210/LAN9211/LAN9220/LAN9221 */
+               pdata->generation = 4;
+               break;
+
+       default:
+               SMSC_WARN(pdata, probe, "LAN911x not identified, idrev: 0x%08X",
+                         pdata->idrev);
+               return -ENODEV;
+       }
+
+       SMSC_TRACE(pdata, probe,
+                  "LAN911x identified, idrev: 0x%08X, generation: %d",
+                  pdata->idrev, pdata->generation);
+
+       if (pdata->generation == 0)
+               SMSC_WARN(pdata, probe,
+                         "This driver is not intended for this chip revision");
+
+       /* workaround for platforms without an eeprom, where the mac address
+        * is stored elsewhere and set by the bootloader.  This saves the
+        * mac address before resetting the device */
+       if (pdata->config.flags & SMSC911X_SAVE_MAC_ADDRESS) {
+               spin_lock_irq(&pdata->mac_lock);
+               smsc911x_read_mac_address(dev);
+               spin_unlock_irq(&pdata->mac_lock);
+       }
+
+       /* Reset the LAN911x */
+       if (smsc911x_soft_reset(pdata))
+               return -ENODEV;
+
+       /* Disable all interrupt sources until we bring the device up */
+       smsc911x_reg_write(pdata, INT_EN, 0);
+
+       ether_setup(dev);
+       dev->flags |= IFF_MULTICAST;
+       netif_napi_add(dev, &pdata->napi, smsc911x_poll, SMSC_NAPI_WEIGHT);
+       dev->netdev_ops = &smsc911x_netdev_ops;
+       dev->ethtool_ops = &smsc911x_ethtool_ops;
+
+       return 0;
+}
+
+static int __devexit smsc911x_drv_remove(struct platform_device *pdev)
+{
+       struct net_device *dev;
+       struct smsc911x_data *pdata;
+       struct resource *res;
+
+       dev = platform_get_drvdata(pdev);
+       BUG_ON(!dev);
+       pdata = netdev_priv(dev);
+       BUG_ON(!pdata);
+       BUG_ON(!pdata->ioaddr);
+       BUG_ON(!pdata->phy_dev);
+
+       SMSC_TRACE(pdata, ifdown, "Stopping driver");
+
+       phy_disconnect(pdata->phy_dev);
+       pdata->phy_dev = NULL;
+       mdiobus_unregister(pdata->mii_bus);
+       mdiobus_free(pdata->mii_bus);
+
+       platform_set_drvdata(pdev, NULL);
+       unregister_netdev(dev);
+       free_irq(dev->irq, dev);
+       res = platform_get_resource_byname(pdev, IORESOURCE_MEM,
+                                          "smsc911x-memory");
+       if (!res)
+               res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+
+       release_mem_region(res->start, resource_size(res));
+
+       iounmap(pdata->ioaddr);
+
+       free_netdev(dev);
+
+       return 0;
+}
+
+/* standard register acces */
+static const struct smsc911x_ops standard_smsc911x_ops = {
+       .reg_read = __smsc911x_reg_read,
+       .reg_write = __smsc911x_reg_write,
+       .rx_readfifo = smsc911x_rx_readfifo,
+       .tx_writefifo = smsc911x_tx_writefifo,
+};
+
+/* shifted register access */
+static const struct smsc911x_ops shifted_smsc911x_ops = {
+       .reg_read = __smsc911x_reg_read_shift,
+       .reg_write = __smsc911x_reg_write_shift,
+       .rx_readfifo = smsc911x_rx_readfifo_shift,
+       .tx_writefifo = smsc911x_tx_writefifo_shift,
+};
+
+#ifdef CONFIG_OF
+static int __devinit smsc911x_probe_config_dt(
+                               struct smsc911x_platform_config *config,
+                               struct device_node *np)
+{
+       const char *mac;
+       u32 width = 0;
+
+       if (!np)
+               return -ENODEV;
+
+       config->phy_interface = of_get_phy_mode(np);
+
+       mac = of_get_mac_address(np);
+       if (mac)
+               memcpy(config->mac, mac, ETH_ALEN);
+
+       of_property_read_u32(np, "reg-shift", &config->shift);
+
+       of_property_read_u32(np, "reg-io-width", &width);
+       if (width == 4)
+               config->flags |= SMSC911X_USE_32BIT;
+
+       if (of_get_property(np, "smsc,irq-active-high", NULL))
+               config->irq_polarity = SMSC911X_IRQ_POLARITY_ACTIVE_HIGH;
+
+       if (of_get_property(np, "smsc,irq-push-pull", NULL))
+               config->irq_type = SMSC911X_IRQ_TYPE_PUSH_PULL;
+
+       if (of_get_property(np, "smsc,force-internal-phy", NULL))
+               config->flags |= SMSC911X_FORCE_INTERNAL_PHY;
+
+       if (of_get_property(np, "smsc,force-external-phy", NULL))
+               config->flags |= SMSC911X_FORCE_EXTERNAL_PHY;
+
+       if (of_get_property(np, "smsc,save-mac-address", NULL))
+               config->flags |= SMSC911X_SAVE_MAC_ADDRESS;
+
+       return 0;
+}
+#else
+static inline int smsc911x_probe_config_dt(
+                               struct smsc911x_platform_config *config,
+                               struct device_node *np)
+{
+       return -ENODEV;
+}
+#endif /* CONFIG_OF */
+
+static int __devinit smsc911x_drv_probe(struct platform_device *pdev)
+{
+       struct device_node *np = pdev->dev.of_node;
+       struct net_device *dev;
+       struct smsc911x_data *pdata;
+       struct smsc911x_platform_config *config = pdev->dev.platform_data;
+       struct resource *res, *irq_res;
+       unsigned int intcfg = 0;
+       int res_size, irq_flags;
+       int retval;
+
+       pr_info("Driver version %s\n", SMSC_DRV_VERSION);
+
+       res = platform_get_resource_byname(pdev, IORESOURCE_MEM,
+                                          "smsc911x-memory");
+       if (!res)
+               res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+       if (!res) {
+               pr_warn("Could not allocate resource\n");
+               retval = -ENODEV;
+               goto out_0;
+       }
+       res_size = resource_size(res);
+
+       irq_res = platform_get_resource(pdev, IORESOURCE_IRQ, 0);
+       if (!irq_res) {
+               pr_warn("Could not allocate irq resource\n");
+               retval = -ENODEV;
+               goto out_0;
+       }
+
+       if (!request_mem_region(res->start, res_size, SMSC_CHIPNAME)) {
+               retval = -EBUSY;
+               goto out_0;
+       }
+
+       dev = alloc_etherdev(sizeof(struct smsc911x_data));
+       if (!dev) {
+               pr_warn("Could not allocate device\n");
+               retval = -ENOMEM;
+               goto out_release_io_1;
+       }
+
+       SET_NETDEV_DEV(dev, &pdev->dev);
+
+       pdata = netdev_priv(dev);
+
+       dev->irq = irq_res->start;
+       irq_flags = irq_res->flags & IRQF_TRIGGER_MASK;
+       pdata->ioaddr = ioremap_nocache(res->start, res_size);
+
+       pdata->dev = dev;
+       pdata->msg_enable = ((1 << debug) - 1);
+
+       if (pdata->ioaddr == NULL) {
+               SMSC_WARN(pdata, probe, "Error smsc911x base address invalid");
+               retval = -ENOMEM;
+               goto out_free_netdev_2;
+       }
+
+       retval = smsc911x_probe_config_dt(&pdata->config, np);
+       if (retval && config) {
+               /* copy config parameters across to pdata */
+               memcpy(&pdata->config, config, sizeof(pdata->config));
+               retval = 0;
+       }
+
+       if (retval) {
+               SMSC_WARN(pdata, probe, "Error smsc911x config not found");
+               goto out_unmap_io_3;
+       }
+
+       /* assume standard, non-shifted, access to HW registers */
+       pdata->ops = &standard_smsc911x_ops;
+       /* apply the right access if shifting is needed */
+       if (pdata->config.shift)
+               pdata->ops = &shifted_smsc911x_ops;
+
+       retval = smsc911x_init(dev);
+       if (retval < 0)
+               goto out_unmap_io_3;
+
+       /* configure irq polarity and type before connecting isr */
+       if (pdata->config.irq_polarity == SMSC911X_IRQ_POLARITY_ACTIVE_HIGH)
+               intcfg |= INT_CFG_IRQ_POL_;
+
+       if (pdata->config.irq_type == SMSC911X_IRQ_TYPE_PUSH_PULL)
+               intcfg |= INT_CFG_IRQ_TYPE_;
+
+       smsc911x_reg_write(pdata, INT_CFG, intcfg);
+
+       /* Ensure interrupts are globally disabled before connecting ISR */
+       smsc911x_reg_write(pdata, INT_EN, 0);
+       smsc911x_reg_write(pdata, INT_STS, 0xFFFFFFFF);
+
+       retval = request_irq(dev->irq, smsc911x_irqhandler,
+                            irq_flags | IRQF_SHARED, dev->name, dev);
+       if (retval) {
+               SMSC_WARN(pdata, probe,
+                         "Unable to claim requested irq: %d", dev->irq);
+               goto out_unmap_io_3;
+       }
+
+       platform_set_drvdata(pdev, dev);
+
+       retval = register_netdev(dev);
+       if (retval) {
+               SMSC_WARN(pdata, probe, "Error %i registering device", retval);
+               goto out_unset_drvdata_4;
+       } else {
+               SMSC_TRACE(pdata, probe,
+                          "Network interface: \"%s\"", dev->name);
+       }
+
+       retval = smsc911x_mii_init(pdev, dev);
+       if (retval) {
+               SMSC_WARN(pdata, probe, "Error %i initialising mii", retval);
+               goto out_unregister_netdev_5;
+       }
+
+       spin_lock_irq(&pdata->mac_lock);
+
+       /* Check if mac address has been specified when bringing interface up */
+       if (is_valid_ether_addr(dev->dev_addr)) {
+               smsc911x_set_hw_mac_address(pdata, dev->dev_addr);
+               SMSC_TRACE(pdata, probe,
+                          "MAC Address is specified by configuration");
+       } else if (is_valid_ether_addr(pdata->config.mac)) {
+               memcpy(dev->dev_addr, pdata->config.mac, 6);
+               SMSC_TRACE(pdata, probe,
+                          "MAC Address specified by platform data");
+       } else {
+               /* Try reading mac address from device. if EEPROM is present
+                * it will already have been set */
+               smsc_get_mac(dev);
+
+               if (is_valid_ether_addr(dev->dev_addr)) {
+                       /* eeprom values are valid  so use them */
+                       SMSC_TRACE(pdata, probe,
+                                  "Mac Address is read from LAN911x EEPROM");
+               } else {
+                       /* eeprom values are invalid, generate random MAC */
+                       random_ether_addr(dev->dev_addr);
+                       smsc911x_set_hw_mac_address(pdata, dev->dev_addr);
+                       SMSC_TRACE(pdata, probe,
+                                  "MAC Address is set to random_ether_addr");
+               }
+       }
+
+       spin_unlock_irq(&pdata->mac_lock);
+
+       netdev_info(dev, "MAC Address: %pM\n", dev->dev_addr);
+
+       return 0;
+
+out_unregister_netdev_5:
+       unregister_netdev(dev);
+out_unset_drvdata_4:
+       platform_set_drvdata(pdev, NULL);
+       free_irq(dev->irq, dev);
+out_unmap_io_3:
+       iounmap(pdata->ioaddr);
+out_free_netdev_2:
+       free_netdev(dev);
+out_release_io_1:
+       release_mem_region(res->start, resource_size(res));
+out_0:
+       return retval;
+}
+
+#ifdef CONFIG_PM
+/* This implementation assumes the devices remains powered on its VDDVARIO
+ * pins during suspend. */
+
+/* TODO: implement freeze/thaw callbacks for hibernation.*/
+
+static int smsc911x_suspend(struct device *dev)
+{
+       struct net_device *ndev = dev_get_drvdata(dev);
+       struct smsc911x_data *pdata = netdev_priv(ndev);
+
+       /* enable wake on LAN, energy detection and the external PME
+        * signal. */
+       smsc911x_reg_write(pdata, PMT_CTRL,
+               PMT_CTRL_PM_MODE_D1_ | PMT_CTRL_WOL_EN_ |
+               PMT_CTRL_ED_EN_ | PMT_CTRL_PME_EN_);
+
+       return 0;
+}
+
+static int smsc911x_resume(struct device *dev)
+{
+       struct net_device *ndev = dev_get_drvdata(dev);
+       struct smsc911x_data *pdata = netdev_priv(ndev);
+       unsigned int to = 100;
+
+       /* Note 3.11 from the datasheet:
+        *      "When the LAN9220 is in a power saving state, a write of any
+        *       data to the BYTE_TEST register will wake-up the device."
+        */
+       smsc911x_reg_write(pdata, BYTE_TEST, 0);
+
+       /* poll the READY bit in PMT_CTRL. Any other access to the device is
+        * forbidden while this bit isn't set. Try for 100ms and return -EIO
+        * if it failed. */
+       while (!(smsc911x_reg_read(pdata, PMT_CTRL) & PMT_CTRL_READY_) && --to)
+               udelay(1000);
+
+       return (to == 0) ? -EIO : 0;
+}
+
+static const struct dev_pm_ops smsc911x_pm_ops = {
+       .suspend        = smsc911x_suspend,
+       .resume         = smsc911x_resume,
+};
+
+#define SMSC911X_PM_OPS (&smsc911x_pm_ops)
+
+#else
+#define SMSC911X_PM_OPS NULL
+#endif
+
+static const struct of_device_id smsc911x_dt_ids[] = {
+       { .compatible = "smsc,lan9115", },
+       { /* sentinel */ }
+};
+MODULE_DEVICE_TABLE(of, smsc911x_dt_ids);
+
+static struct platform_driver smsc911x_driver = {
+       .probe = smsc911x_drv_probe,
+       .remove = __devexit_p(smsc911x_drv_remove),
+       .driver = {
+               .name   = SMSC_CHIPNAME,
+               .owner  = THIS_MODULE,
+               .pm     = SMSC911X_PM_OPS,
+               .of_match_table = smsc911x_dt_ids,
+       },
+};
+
+/* Entry point for loading the module */
+static int __init smsc911x_init_module(void)
+{
+       SMSC_INITIALIZE();
+       return platform_driver_register(&smsc911x_driver);
+}
+
+/* entry point for unloading the module */
+static void __exit smsc911x_cleanup_module(void)
+{
+       platform_driver_unregister(&smsc911x_driver);
+}
+
+module_init(smsc911x_init_module);
+module_exit(smsc911x_cleanup_module);
diff --git a/drivers/net/ethernet/smsc/smsc911x.h b/drivers/net/ethernet/smsc/smsc911x.h
new file mode 100644 (file)
index 0000000..8d67aac
--- /dev/null
@@ -0,0 +1,404 @@
+/***************************************************************************
+ *
+ * Copyright (C) 2004-2008 SMSC
+ * Copyright (C) 2005-2008 ARM
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
+ *
+ ***************************************************************************/
+#ifndef __SMSC911X_H__
+#define __SMSC911X_H__
+
+#define TX_FIFO_LOW_THRESHOLD  ((u32)1600)
+#define SMSC911X_EEPROM_SIZE   ((u32)128)
+#define USE_DEBUG              0
+
+/* This is the maximum number of packets to be received every
+ * NAPI poll */
+#define SMSC_NAPI_WEIGHT       16
+
+/* implements a PHY loopback test at initialisation time, to ensure a packet
+ * can be successfully looped back */
+#define USE_PHY_WORK_AROUND
+
+#if USE_DEBUG >= 1
+#define SMSC_WARN(pdata, nlevel, fmt, args...)                 \
+       netif_warn(pdata, nlevel, (pdata)->dev,                 \
+                  "%s: " fmt "\n", __func__, ##args)
+#else
+#define SMSC_WARN(pdata, nlevel, fmt, args...)                 \
+       no_printk(fmt "\n", ##args)
+#endif
+
+#if USE_DEBUG >= 2
+#define SMSC_TRACE(pdata, nlevel, fmt, args...)                        \
+       netif_info(pdata, nlevel, pdata->dev, fmt "\n", ##args)
+#else
+#define SMSC_TRACE(pdata, nlevel, fmt, args...)                        \
+       no_printk(fmt "\n", ##args)
+#endif
+
+#ifdef CONFIG_DEBUG_SPINLOCK
+#define SMSC_ASSERT_MAC_LOCK(pdata) \
+               WARN_ON(!spin_is_locked(&pdata->mac_lock))
+#else
+#define SMSC_ASSERT_MAC_LOCK(pdata) do {} while (0)
+#endif                         /* CONFIG_DEBUG_SPINLOCK */
+
+/* SMSC911x registers and bitfields */
+#define RX_DATA_FIFO                   0x00
+
+#define TX_DATA_FIFO                   0x20
+#define TX_CMD_A_ON_COMP_              0x80000000
+#define TX_CMD_A_BUF_END_ALGN_         0x03000000
+#define TX_CMD_A_4_BYTE_ALGN_          0x00000000
+#define TX_CMD_A_16_BYTE_ALGN_         0x01000000
+#define TX_CMD_A_32_BYTE_ALGN_         0x02000000
+#define TX_CMD_A_DATA_OFFSET_          0x001F0000
+#define TX_CMD_A_FIRST_SEG_            0x00002000
+#define TX_CMD_A_LAST_SEG_             0x00001000
+#define TX_CMD_A_BUF_SIZE_             0x000007FF
+#define TX_CMD_B_PKT_TAG_              0xFFFF0000
+#define TX_CMD_B_ADD_CRC_DISABLE_      0x00002000
+#define TX_CMD_B_DISABLE_PADDING_      0x00001000
+#define TX_CMD_B_PKT_BYTE_LENGTH_      0x000007FF
+
+#define RX_STATUS_FIFO                 0x40
+#define RX_STS_ES_                     0x00008000
+#define RX_STS_LENGTH_ERR_             0x00001000
+#define RX_STS_MCAST_                  0x00000400
+#define RX_STS_FRAME_TYPE_             0x00000020
+#define RX_STS_CRC_ERR_                        0x00000002
+
+#define RX_STATUS_FIFO_PEEK            0x44
+
+#define TX_STATUS_FIFO                 0x48
+#define TX_STS_ES_                     0x00008000
+#define TX_STS_LOST_CARRIER_           0x00000800
+#define TX_STS_NO_CARRIER_             0x00000400
+#define TX_STS_LATE_COL_               0x00000200
+#define TX_STS_EXCESS_COL_             0x00000100
+
+#define TX_STATUS_FIFO_PEEK            0x4C
+
+#define ID_REV                         0x50
+#define ID_REV_CHIP_ID_                        0xFFFF0000
+#define ID_REV_REV_ID_                 0x0000FFFF
+
+#define INT_CFG                                0x54
+#define INT_CFG_INT_DEAS_              0xFF000000
+#define INT_CFG_INT_DEAS_CLR_          0x00004000
+#define INT_CFG_INT_DEAS_STS_          0x00002000
+#define INT_CFG_IRQ_INT_               0x00001000
+#define INT_CFG_IRQ_EN_                        0x00000100
+#define INT_CFG_IRQ_POL_               0x00000010
+#define INT_CFG_IRQ_TYPE_              0x00000001
+
+#define INT_STS                                0x58
+#define INT_STS_SW_INT_                        0x80000000
+#define INT_STS_TXSTOP_INT_            0x02000000
+#define INT_STS_RXSTOP_INT_            0x01000000
+#define INT_STS_RXDFH_INT_             0x00800000
+#define INT_STS_RXDF_INT_              0x00400000
+#define INT_STS_TX_IOC_                        0x00200000
+#define INT_STS_RXD_INT_               0x00100000
+#define INT_STS_GPT_INT_               0x00080000
+#define INT_STS_PHY_INT_               0x00040000
+#define INT_STS_PME_INT_               0x00020000
+#define INT_STS_TXSO_                  0x00010000
+#define INT_STS_RWT_                   0x00008000
+#define INT_STS_RXE_                   0x00004000
+#define INT_STS_TXE_                   0x00002000
+#define INT_STS_TDFU_                  0x00000800
+#define INT_STS_TDFO_                  0x00000400
+#define INT_STS_TDFA_                  0x00000200
+#define INT_STS_TSFF_                  0x00000100
+#define INT_STS_TSFL_                  0x00000080
+#define INT_STS_RXDF_                  0x00000040
+#define INT_STS_RDFL_                  0x00000020
+#define INT_STS_RSFF_                  0x00000010
+#define INT_STS_RSFL_                  0x00000008
+#define INT_STS_GPIO2_INT_             0x00000004
+#define INT_STS_GPIO1_INT_             0x00000002
+#define INT_STS_GPIO0_INT_             0x00000001
+
+#define INT_EN                         0x5C
+#define INT_EN_SW_INT_EN_              0x80000000
+#define INT_EN_TXSTOP_INT_EN_          0x02000000
+#define INT_EN_RXSTOP_INT_EN_          0x01000000
+#define INT_EN_RXDFH_INT_EN_           0x00800000
+#define INT_EN_TIOC_INT_EN_            0x00200000
+#define INT_EN_RXD_INT_EN_             0x00100000
+#define INT_EN_GPT_INT_EN_             0x00080000
+#define INT_EN_PHY_INT_EN_             0x00040000
+#define INT_EN_PME_INT_EN_             0x00020000
+#define INT_EN_TXSO_EN_                        0x00010000
+#define INT_EN_RWT_EN_                 0x00008000
+#define INT_EN_RXE_EN_                 0x00004000
+#define INT_EN_TXE_EN_                 0x00002000
+#define INT_EN_TDFU_EN_                        0x00000800
+#define INT_EN_TDFO_EN_                        0x00000400
+#define INT_EN_TDFA_EN_                        0x00000200
+#define INT_EN_TSFF_EN_                        0x00000100
+#define INT_EN_TSFL_EN_                        0x00000080
+#define INT_EN_RXDF_EN_                        0x00000040
+#define INT_EN_RDFL_EN_                        0x00000020
+#define INT_EN_RSFF_EN_                        0x00000010
+#define INT_EN_RSFL_EN_                        0x00000008
+#define INT_EN_GPIO2_INT_              0x00000004
+#define INT_EN_GPIO1_INT_              0x00000002
+#define INT_EN_GPIO0_INT_              0x00000001
+
+#define BYTE_TEST                      0x64
+
+#define FIFO_INT                       0x68
+#define FIFO_INT_TX_AVAIL_LEVEL_       0xFF000000
+#define FIFO_INT_TX_STS_LEVEL_         0x00FF0000
+#define FIFO_INT_RX_AVAIL_LEVEL_       0x0000FF00
+#define FIFO_INT_RX_STS_LEVEL_         0x000000FF
+
+#define RX_CFG                         0x6C
+#define RX_CFG_RX_END_ALGN_            0xC0000000
+#define RX_CFG_RX_END_ALGN4_           0x00000000
+#define RX_CFG_RX_END_ALGN16_          0x40000000
+#define RX_CFG_RX_END_ALGN32_          0x80000000
+#define RX_CFG_RX_DMA_CNT_             0x0FFF0000
+#define RX_CFG_RX_DUMP_                        0x00008000
+#define RX_CFG_RXDOFF_                 0x00001F00
+
+#define TX_CFG                         0x70
+#define TX_CFG_TXS_DUMP_               0x00008000
+#define TX_CFG_TXD_DUMP_               0x00004000
+#define TX_CFG_TXSAO_                  0x00000004
+#define TX_CFG_TX_ON_                  0x00000002
+#define TX_CFG_STOP_TX_                        0x00000001
+
+#define HW_CFG                         0x74
+#define HW_CFG_TTM_                    0x00200000
+#define HW_CFG_SF_                     0x00100000
+#define HW_CFG_TX_FIF_SZ_              0x000F0000
+#define HW_CFG_TR_                     0x00003000
+#define HW_CFG_SRST_                   0x00000001
+
+/* only available on 115/117 */
+#define HW_CFG_PHY_CLK_SEL_            0x00000060
+#define HW_CFG_PHY_CLK_SEL_INT_PHY_    0x00000000
+#define HW_CFG_PHY_CLK_SEL_EXT_PHY_    0x00000020
+#define HW_CFG_PHY_CLK_SEL_CLK_DIS_    0x00000040
+#define HW_CFG_SMI_SEL_                        0x00000010
+#define HW_CFG_EXT_PHY_DET_            0x00000008
+#define HW_CFG_EXT_PHY_EN_             0x00000004
+#define HW_CFG_SRST_TO_                        0x00000002
+
+/* only available  on 116/118 */
+#define HW_CFG_32_16_BIT_MODE_         0x00000004
+
+#define RX_DP_CTRL                     0x78
+#define RX_DP_CTRL_RX_FFWD_            0x80000000
+
+#define RX_FIFO_INF                    0x7C
+#define RX_FIFO_INF_RXSUSED_           0x00FF0000
+#define RX_FIFO_INF_RXDUSED_           0x0000FFFF
+
+#define TX_FIFO_INF                    0x80
+#define TX_FIFO_INF_TSUSED_            0x00FF0000
+#define TX_FIFO_INF_TDFREE_            0x0000FFFF
+
+#define PMT_CTRL                       0x84
+#define PMT_CTRL_PM_MODE_              0x00003000
+#define PMT_CTRL_PM_MODE_D0_           0x00000000
+#define PMT_CTRL_PM_MODE_D1_           0x00001000
+#define PMT_CTRL_PM_MODE_D2_           0x00002000
+#define PMT_CTRL_PM_MODE_D3_           0x00003000
+#define PMT_CTRL_PHY_RST_              0x00000400
+#define PMT_CTRL_WOL_EN_               0x00000200
+#define PMT_CTRL_ED_EN_                        0x00000100
+#define PMT_CTRL_PME_TYPE_             0x00000040
+#define PMT_CTRL_WUPS_                 0x00000030
+#define PMT_CTRL_WUPS_NOWAKE_          0x00000000
+#define PMT_CTRL_WUPS_ED_              0x00000010
+#define PMT_CTRL_WUPS_WOL_             0x00000020
+#define PMT_CTRL_WUPS_MULTI_           0x00000030
+#define PMT_CTRL_PME_IND_              0x00000008
+#define PMT_CTRL_PME_POL_              0x00000004
+#define PMT_CTRL_PME_EN_               0x00000002
+#define PMT_CTRL_READY_                        0x00000001
+
+#define GPIO_CFG                       0x88
+#define GPIO_CFG_LED3_EN_              0x40000000
+#define GPIO_CFG_LED2_EN_              0x20000000
+#define GPIO_CFG_LED1_EN_              0x10000000
+#define GPIO_CFG_GPIO2_INT_POL_                0x04000000
+#define GPIO_CFG_GPIO1_INT_POL_                0x02000000
+#define GPIO_CFG_GPIO0_INT_POL_                0x01000000
+#define GPIO_CFG_EEPR_EN_              0x00700000
+#define GPIO_CFG_GPIOBUF2_             0x00040000
+#define GPIO_CFG_GPIOBUF1_             0x00020000
+#define GPIO_CFG_GPIOBUF0_             0x00010000
+#define GPIO_CFG_GPIODIR2_             0x00000400
+#define GPIO_CFG_GPIODIR1_             0x00000200
+#define GPIO_CFG_GPIODIR0_             0x00000100
+#define GPIO_CFG_GPIOD4_               0x00000020
+#define GPIO_CFG_GPIOD3_               0x00000010
+#define GPIO_CFG_GPIOD2_               0x00000004
+#define GPIO_CFG_GPIOD1_               0x00000002
+#define GPIO_CFG_GPIOD0_               0x00000001
+
+#define GPT_CFG                                0x8C
+#define GPT_CFG_TIMER_EN_              0x20000000
+#define GPT_CFG_GPT_LOAD_              0x0000FFFF
+
+#define GPT_CNT                                0x90
+#define GPT_CNT_GPT_CNT_               0x0000FFFF
+
+#define WORD_SWAP                      0x98
+
+#define FREE_RUN                       0x9C
+
+#define RX_DROP                                0xA0
+
+#define MAC_CSR_CMD                    0xA4
+#define MAC_CSR_CMD_CSR_BUSY_          0x80000000
+#define MAC_CSR_CMD_R_NOT_W_           0x40000000
+#define MAC_CSR_CMD_CSR_ADDR_          0x000000FF
+
+#define MAC_CSR_DATA                   0xA8
+
+#define AFC_CFG                                0xAC
+#define AFC_CFG_AFC_HI_                        0x00FF0000
+#define AFC_CFG_AFC_LO_                        0x0000FF00
+#define AFC_CFG_BACK_DUR_              0x000000F0
+#define AFC_CFG_FCMULT_                        0x00000008
+#define AFC_CFG_FCBRD_                 0x00000004
+#define AFC_CFG_FCADD_                 0x00000002
+#define AFC_CFG_FCANY_                 0x00000001
+
+#define E2P_CMD                                0xB0
+#define E2P_CMD_EPC_BUSY_              0x80000000
+#define E2P_CMD_EPC_CMD_               0x70000000
+#define E2P_CMD_EPC_CMD_READ_          0x00000000
+#define E2P_CMD_EPC_CMD_EWDS_          0x10000000
+#define E2P_CMD_EPC_CMD_EWEN_          0x20000000
+#define E2P_CMD_EPC_CMD_WRITE_         0x30000000
+#define E2P_CMD_EPC_CMD_WRAL_          0x40000000
+#define E2P_CMD_EPC_CMD_ERASE_         0x50000000
+#define E2P_CMD_EPC_CMD_ERAL_          0x60000000
+#define E2P_CMD_EPC_CMD_RELOAD_                0x70000000
+#define E2P_CMD_EPC_TIMEOUT_           0x00000200
+#define E2P_CMD_MAC_ADDR_LOADED_       0x00000100
+#define E2P_CMD_EPC_ADDR_              0x000000FF
+
+#define E2P_DATA                       0xB4
+#define E2P_DATA_EEPROM_DATA_          0x000000FF
+#define LAN_REGISTER_EXTENT            0x00000100
+
+/*
+ * MAC Control and Status Register (Indirect Address)
+ * Offset (through the MAC_CSR CMD and DATA port)
+ */
+#define MAC_CR                         0x01
+#define MAC_CR_RXALL_                  0x80000000
+#define MAC_CR_HBDIS_                  0x10000000
+#define MAC_CR_RCVOWN_                 0x00800000
+#define MAC_CR_LOOPBK_                 0x00200000
+#define MAC_CR_FDPX_                   0x00100000
+#define MAC_CR_MCPAS_                  0x00080000
+#define MAC_CR_PRMS_                   0x00040000
+#define MAC_CR_INVFILT_                        0x00020000
+#define MAC_CR_PASSBAD_                        0x00010000
+#define MAC_CR_HFILT_                  0x00008000
+#define MAC_CR_HPFILT_                 0x00002000
+#define MAC_CR_LCOLL_                  0x00001000
+#define MAC_CR_BCAST_                  0x00000800
+#define MAC_CR_DISRTY_                 0x00000400
+#define MAC_CR_PADSTR_                 0x00000100
+#define MAC_CR_BOLMT_MASK_             0x000000C0
+#define MAC_CR_DFCHK_                  0x00000020
+#define MAC_CR_TXEN_                   0x00000008
+#define MAC_CR_RXEN_                   0x00000004
+
+#define ADDRH                          0x02
+
+#define ADDRL                          0x03
+
+#define HASHH                          0x04
+
+#define HASHL                          0x05
+
+#define MII_ACC                                0x06
+#define MII_ACC_PHY_ADDR_              0x0000F800
+#define MII_ACC_MIIRINDA_              0x000007C0
+#define MII_ACC_MII_WRITE_             0x00000002
+#define MII_ACC_MII_BUSY_              0x00000001
+
+#define MII_DATA                       0x07
+
+#define FLOW                           0x08
+#define FLOW_FCPT_                     0xFFFF0000
+#define FLOW_FCPASS_                   0x00000004
+#define FLOW_FCEN_                     0x00000002
+#define FLOW_FCBSY_                    0x00000001
+
+#define VLAN1                          0x09
+
+#define VLAN2                          0x0A
+
+#define WUFF                           0x0B
+
+#define WUCSR                          0x0C
+#define WUCSR_GUE_                     0x00000200
+#define WUCSR_WUFR_                    0x00000040
+#define WUCSR_MPR_                     0x00000020
+#define WUCSR_WAKE_EN_                 0x00000004
+#define WUCSR_MPEN_                    0x00000002
+
+/*
+ * Phy definitions (vendor-specific)
+ */
+#define LAN9118_PHY_ID                 0x00C0001C
+
+#define MII_INTSTS                     0x1D
+
+#define MII_INTMSK                     0x1E
+#define PHY_INTMSK_AN_RCV_             (1 << 1)
+#define PHY_INTMSK_PDFAULT_            (1 << 2)
+#define PHY_INTMSK_AN_ACK_             (1 << 3)
+#define PHY_INTMSK_LNKDOWN_            (1 << 4)
+#define PHY_INTMSK_RFAULT_             (1 << 5)
+#define PHY_INTMSK_AN_COMP_            (1 << 6)
+#define PHY_INTMSK_ENERGYON_           (1 << 7)
+#define PHY_INTMSK_DEFAULT_            (PHY_INTMSK_ENERGYON_ | \
+                                        PHY_INTMSK_AN_COMP_ | \
+                                        PHY_INTMSK_RFAULT_ | \
+                                        PHY_INTMSK_LNKDOWN_)
+
+#define ADVERTISE_PAUSE_ALL            (ADVERTISE_PAUSE_CAP | \
+                                        ADVERTISE_PAUSE_ASYM)
+
+#define LPA_PAUSE_ALL                  (LPA_PAUSE_CAP | \
+                                        LPA_PAUSE_ASYM)
+
+/*
+ * Provide hooks to let the arch add to the initialisation procedure
+ * and to override the source of the MAC address.
+ */
+#define SMSC_INITIALIZE()              do {} while (0)
+#define smsc_get_mac(dev)              smsc911x_read_mac_address((dev))
+
+#ifdef CONFIG_SMSC911X_ARCH_HOOKS
+#include <asm/smsc911x.h>
+#endif
+
+#endif                         /* __SMSC911X_H__ */
diff --git a/drivers/net/ethernet/smsc/smsc9420.c b/drivers/net/ethernet/smsc/smsc9420.c
new file mode 100644 (file)
index 0000000..459726f
--- /dev/null
@@ -0,0 +1,1763 @@
+ /***************************************************************************
+ *
+ * Copyright (C) 2007,2008  SMSC
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
+ *
+ ***************************************************************************
+ */
+
+#include <linux/interrupt.h>
+#include <linux/kernel.h>
+#include <linux/netdevice.h>
+#include <linux/phy.h>
+#include <linux/pci.h>
+#include <linux/if_vlan.h>
+#include <linux/dma-mapping.h>
+#include <linux/crc32.h>
+#include <linux/slab.h>
+#include <asm/unaligned.h>
+#include "smsc9420.h"
+
+#define DRV_NAME               "smsc9420"
+#define PFX                    DRV_NAME ": "
+#define DRV_MDIONAME           "smsc9420-mdio"
+#define DRV_DESCRIPTION                "SMSC LAN9420 driver"
+#define DRV_VERSION            "1.01"
+
+MODULE_LICENSE("GPL");
+MODULE_VERSION(DRV_VERSION);
+
+struct smsc9420_dma_desc {
+       u32 status;
+       u32 length;
+       u32 buffer1;
+       u32 buffer2;
+};
+
+struct smsc9420_ring_info {
+       struct sk_buff *skb;
+       dma_addr_t mapping;
+};
+
+struct smsc9420_pdata {
+       void __iomem *base_addr;
+       struct pci_dev *pdev;
+       struct net_device *dev;
+
+       struct smsc9420_dma_desc *rx_ring;
+       struct smsc9420_dma_desc *tx_ring;
+       struct smsc9420_ring_info *tx_buffers;
+       struct smsc9420_ring_info *rx_buffers;
+       dma_addr_t rx_dma_addr;
+       dma_addr_t tx_dma_addr;
+       int tx_ring_head, tx_ring_tail;
+       int rx_ring_head, rx_ring_tail;
+
+       spinlock_t int_lock;
+       spinlock_t phy_lock;
+
+       struct napi_struct napi;
+
+       bool software_irq_signal;
+       bool rx_csum;
+       u32 msg_enable;
+
+       struct phy_device *phy_dev;
+       struct mii_bus *mii_bus;
+       int phy_irq[PHY_MAX_ADDR];
+       int last_duplex;
+       int last_carrier;
+};
+
+static DEFINE_PCI_DEVICE_TABLE(smsc9420_id_table) = {
+       { PCI_VENDOR_ID_9420, PCI_DEVICE_ID_9420, PCI_ANY_ID, PCI_ANY_ID, },
+       { 0, }
+};
+
+MODULE_DEVICE_TABLE(pci, smsc9420_id_table);
+
+#define SMSC_MSG_DEFAULT (NETIF_MSG_DRV | NETIF_MSG_PROBE | NETIF_MSG_LINK)
+
+static uint smsc_debug;
+static uint debug = -1;
+module_param(debug, uint, 0);
+MODULE_PARM_DESC(debug, "debug level");
+
+#define smsc_dbg(TYPE, f, a...) \
+do {   if ((pd)->msg_enable & NETIF_MSG_##TYPE) \
+               printk(KERN_DEBUG PFX f "\n", ## a); \
+} while (0)
+
+#define smsc_info(TYPE, f, a...) \
+do {   if ((pd)->msg_enable & NETIF_MSG_##TYPE) \
+               printk(KERN_INFO PFX f "\n", ## a); \
+} while (0)
+
+#define smsc_warn(TYPE, f, a...) \
+do {   if ((pd)->msg_enable & NETIF_MSG_##TYPE) \
+               printk(KERN_WARNING PFX f "\n", ## a); \
+} while (0)
+
+static inline u32 smsc9420_reg_read(struct smsc9420_pdata *pd, u32 offset)
+{
+       return ioread32(pd->base_addr + offset);
+}
+
+static inline void
+smsc9420_reg_write(struct smsc9420_pdata *pd, u32 offset, u32 value)
+{
+       iowrite32(value, pd->base_addr + offset);
+}
+
+static inline void smsc9420_pci_flush_write(struct smsc9420_pdata *pd)
+{
+       /* to ensure PCI write completion, we must perform a PCI read */
+       smsc9420_reg_read(pd, ID_REV);
+}
+
+static int smsc9420_mii_read(struct mii_bus *bus, int phyaddr, int regidx)
+{
+       struct smsc9420_pdata *pd = (struct smsc9420_pdata *)bus->priv;
+       unsigned long flags;
+       u32 addr;
+       int i, reg = -EIO;
+
+       spin_lock_irqsave(&pd->phy_lock, flags);
+
+       /*  confirm MII not busy */
+       if ((smsc9420_reg_read(pd, MII_ACCESS) & MII_ACCESS_MII_BUSY_)) {
+               smsc_warn(DRV, "MII is busy???");
+               goto out;
+       }
+
+       /* set the address, index & direction (read from PHY) */
+       addr = ((phyaddr & 0x1F) << 11) | ((regidx & 0x1F) << 6) |
+               MII_ACCESS_MII_READ_;
+       smsc9420_reg_write(pd, MII_ACCESS, addr);
+
+       /* wait for read to complete with 50us timeout */
+       for (i = 0; i < 5; i++) {
+               if (!(smsc9420_reg_read(pd, MII_ACCESS) &
+                       MII_ACCESS_MII_BUSY_)) {
+                       reg = (u16)smsc9420_reg_read(pd, MII_DATA);
+                       goto out;
+               }
+               udelay(10);
+       }
+
+       smsc_warn(DRV, "MII busy timeout!");
+
+out:
+       spin_unlock_irqrestore(&pd->phy_lock, flags);
+       return reg;
+}
+
+static int smsc9420_mii_write(struct mii_bus *bus, int phyaddr, int regidx,
+                          u16 val)
+{
+       struct smsc9420_pdata *pd = (struct smsc9420_pdata *)bus->priv;
+       unsigned long flags;
+       u32 addr;
+       int i, reg = -EIO;
+
+       spin_lock_irqsave(&pd->phy_lock, flags);
+
+       /* confirm MII not busy */
+       if ((smsc9420_reg_read(pd, MII_ACCESS) & MII_ACCESS_MII_BUSY_)) {
+               smsc_warn(DRV, "MII is busy???");
+               goto out;
+       }
+
+       /* put the data to write in the MAC */
+       smsc9420_reg_write(pd, MII_DATA, (u32)val);
+
+       /* set the address, index & direction (write to PHY) */
+       addr = ((phyaddr & 0x1F) << 11) | ((regidx & 0x1F) << 6) |
+               MII_ACCESS_MII_WRITE_;
+       smsc9420_reg_write(pd, MII_ACCESS, addr);
+
+       /* wait for write to complete with 50us timeout */
+       for (i = 0; i < 5; i++) {
+               if (!(smsc9420_reg_read(pd, MII_ACCESS) &
+                       MII_ACCESS_MII_BUSY_)) {
+                       reg = 0;
+                       goto out;
+               }
+               udelay(10);
+       }
+
+       smsc_warn(DRV, "MII busy timeout!");
+
+out:
+       spin_unlock_irqrestore(&pd->phy_lock, flags);
+       return reg;
+}
+
+/* Returns hash bit number for given MAC address
+ * Example:
+ * 01 00 5E 00 00 01 -> returns bit number 31 */
+static u32 smsc9420_hash(u8 addr[ETH_ALEN])
+{
+       return (ether_crc(ETH_ALEN, addr) >> 26) & 0x3f;
+}
+
+static int smsc9420_eeprom_reload(struct smsc9420_pdata *pd)
+{
+       int timeout = 100000;
+
+       BUG_ON(!pd);
+
+       if (smsc9420_reg_read(pd, E2P_CMD) & E2P_CMD_EPC_BUSY_) {
+               smsc_dbg(DRV, "smsc9420_eeprom_reload: Eeprom busy");
+               return -EIO;
+       }
+
+       smsc9420_reg_write(pd, E2P_CMD,
+               (E2P_CMD_EPC_BUSY_ | E2P_CMD_EPC_CMD_RELOAD_));
+
+       do {
+               udelay(10);
+               if (!(smsc9420_reg_read(pd, E2P_CMD) & E2P_CMD_EPC_BUSY_))
+                       return 0;
+       } while (timeout--);
+
+       smsc_warn(DRV, "smsc9420_eeprom_reload: Eeprom timed out");
+       return -EIO;
+}
+
+/* Standard ioctls for mii-tool */
+static int smsc9420_do_ioctl(struct net_device *dev, struct ifreq *ifr, int cmd)
+{
+       struct smsc9420_pdata *pd = netdev_priv(dev);
+
+       if (!netif_running(dev) || !pd->phy_dev)
+               return -EINVAL;
+
+       return phy_mii_ioctl(pd->phy_dev, ifr, cmd);
+}
+
+static int smsc9420_ethtool_get_settings(struct net_device *dev,
+                                        struct ethtool_cmd *cmd)
+{
+       struct smsc9420_pdata *pd = netdev_priv(dev);
+
+       if (!pd->phy_dev)
+               return -ENODEV;
+
+       cmd->maxtxpkt = 1;
+       cmd->maxrxpkt = 1;
+       return phy_ethtool_gset(pd->phy_dev, cmd);
+}
+
+static int smsc9420_ethtool_set_settings(struct net_device *dev,
+                                        struct ethtool_cmd *cmd)
+{
+       struct smsc9420_pdata *pd = netdev_priv(dev);
+
+       if (!pd->phy_dev)
+               return -ENODEV;
+
+       return phy_ethtool_sset(pd->phy_dev, cmd);
+}
+
+static void smsc9420_ethtool_get_drvinfo(struct net_device *netdev,
+                                        struct ethtool_drvinfo *drvinfo)
+{
+       struct smsc9420_pdata *pd = netdev_priv(netdev);
+
+       strcpy(drvinfo->driver, DRV_NAME);
+       strcpy(drvinfo->bus_info, pci_name(pd->pdev));
+       strcpy(drvinfo->version, DRV_VERSION);
+}
+
+static u32 smsc9420_ethtool_get_msglevel(struct net_device *netdev)
+{
+       struct smsc9420_pdata *pd = netdev_priv(netdev);
+       return pd->msg_enable;
+}
+
+static void smsc9420_ethtool_set_msglevel(struct net_device *netdev, u32 data)
+{
+       struct smsc9420_pdata *pd = netdev_priv(netdev);
+       pd->msg_enable = data;
+}
+
+static int smsc9420_ethtool_nway_reset(struct net_device *netdev)
+{
+       struct smsc9420_pdata *pd = netdev_priv(netdev);
+
+       if (!pd->phy_dev)
+               return -ENODEV;
+
+       return phy_start_aneg(pd->phy_dev);
+}
+
+static int smsc9420_ethtool_getregslen(struct net_device *dev)
+{
+       /* all smsc9420 registers plus all phy registers */
+       return 0x100 + (32 * sizeof(u32));
+}
+
+static void
+smsc9420_ethtool_getregs(struct net_device *dev, struct ethtool_regs *regs,
+                        void *buf)
+{
+       struct smsc9420_pdata *pd = netdev_priv(dev);
+       struct phy_device *phy_dev = pd->phy_dev;
+       unsigned int i, j = 0;
+       u32 *data = buf;
+
+       regs->version = smsc9420_reg_read(pd, ID_REV);
+       for (i = 0; i < 0x100; i += (sizeof(u32)))
+               data[j++] = smsc9420_reg_read(pd, i);
+
+       // cannot read phy registers if the net device is down
+       if (!phy_dev)
+               return;
+
+       for (i = 0; i <= 31; i++)
+               data[j++] = smsc9420_mii_read(phy_dev->bus, phy_dev->addr, i);
+}
+
+static void smsc9420_eeprom_enable_access(struct smsc9420_pdata *pd)
+{
+       unsigned int temp = smsc9420_reg_read(pd, GPIO_CFG);
+       temp &= ~GPIO_CFG_EEPR_EN_;
+       smsc9420_reg_write(pd, GPIO_CFG, temp);
+       msleep(1);
+}
+
+static int smsc9420_eeprom_send_cmd(struct smsc9420_pdata *pd, u32 op)
+{
+       int timeout = 100;
+       u32 e2cmd;
+
+       smsc_dbg(HW, "op 0x%08x", op);
+       if (smsc9420_reg_read(pd, E2P_CMD) & E2P_CMD_EPC_BUSY_) {
+               smsc_warn(HW, "Busy at start");
+               return -EBUSY;
+       }
+
+       e2cmd = op | E2P_CMD_EPC_BUSY_;
+       smsc9420_reg_write(pd, E2P_CMD, e2cmd);
+
+       do {
+               msleep(1);
+               e2cmd = smsc9420_reg_read(pd, E2P_CMD);
+       } while ((e2cmd & E2P_CMD_EPC_BUSY_) && (--timeout));
+
+       if (!timeout) {
+               smsc_info(HW, "TIMED OUT");
+               return -EAGAIN;
+       }
+
+       if (e2cmd & E2P_CMD_EPC_TIMEOUT_) {
+               smsc_info(HW, "Error occurred during eeprom operation");
+               return -EINVAL;
+       }
+
+       return 0;
+}
+
+static int smsc9420_eeprom_read_location(struct smsc9420_pdata *pd,
+                                        u8 address, u8 *data)
+{
+       u32 op = E2P_CMD_EPC_CMD_READ_ | address;
+       int ret;
+
+       smsc_dbg(HW, "address 0x%x", address);
+       ret = smsc9420_eeprom_send_cmd(pd, op);
+
+       if (!ret)
+               data[address] = smsc9420_reg_read(pd, E2P_DATA);
+
+       return ret;
+}
+
+static int smsc9420_eeprom_write_location(struct smsc9420_pdata *pd,
+                                         u8 address, u8 data)
+{
+       u32 op = E2P_CMD_EPC_CMD_ERASE_ | address;
+       int ret;
+
+       smsc_dbg(HW, "address 0x%x, data 0x%x", address, data);
+       ret = smsc9420_eeprom_send_cmd(pd, op);
+
+       if (!ret) {
+               op = E2P_CMD_EPC_CMD_WRITE_ | address;
+               smsc9420_reg_write(pd, E2P_DATA, (u32)data);
+               ret = smsc9420_eeprom_send_cmd(pd, op);
+       }
+
+       return ret;
+}
+
+static int smsc9420_ethtool_get_eeprom_len(struct net_device *dev)
+{
+       return SMSC9420_EEPROM_SIZE;
+}
+
+static int smsc9420_ethtool_get_eeprom(struct net_device *dev,
+                                      struct ethtool_eeprom *eeprom, u8 *data)
+{
+       struct smsc9420_pdata *pd = netdev_priv(dev);
+       u8 eeprom_data[SMSC9420_EEPROM_SIZE];
+       int len, i;
+
+       smsc9420_eeprom_enable_access(pd);
+
+       len = min(eeprom->len, SMSC9420_EEPROM_SIZE);
+       for (i = 0; i < len; i++) {
+               int ret = smsc9420_eeprom_read_location(pd, i, eeprom_data);
+               if (ret < 0) {
+                       eeprom->len = 0;
+                       return ret;
+               }
+       }
+
+       memcpy(data, &eeprom_data[eeprom->offset], len);
+       eeprom->magic = SMSC9420_EEPROM_MAGIC;
+       eeprom->len = len;
+       return 0;
+}
+
+static int smsc9420_ethtool_set_eeprom(struct net_device *dev,
+                                      struct ethtool_eeprom *eeprom, u8 *data)
+{
+       struct smsc9420_pdata *pd = netdev_priv(dev);
+       int ret;
+
+       if (eeprom->magic != SMSC9420_EEPROM_MAGIC)
+               return -EINVAL;
+
+       smsc9420_eeprom_enable_access(pd);
+       smsc9420_eeprom_send_cmd(pd, E2P_CMD_EPC_CMD_EWEN_);
+       ret = smsc9420_eeprom_write_location(pd, eeprom->offset, *data);
+       smsc9420_eeprom_send_cmd(pd, E2P_CMD_EPC_CMD_EWDS_);
+
+       /* Single byte write, according to man page */
+       eeprom->len = 1;
+
+       return ret;
+}
+
+static const struct ethtool_ops smsc9420_ethtool_ops = {
+       .get_settings = smsc9420_ethtool_get_settings,
+       .set_settings = smsc9420_ethtool_set_settings,
+       .get_drvinfo = smsc9420_ethtool_get_drvinfo,
+       .get_msglevel = smsc9420_ethtool_get_msglevel,
+       .set_msglevel = smsc9420_ethtool_set_msglevel,
+       .nway_reset = smsc9420_ethtool_nway_reset,
+       .get_link = ethtool_op_get_link,
+       .get_eeprom_len = smsc9420_ethtool_get_eeprom_len,
+       .get_eeprom = smsc9420_ethtool_get_eeprom,
+       .set_eeprom = smsc9420_ethtool_set_eeprom,
+       .get_regs_len = smsc9420_ethtool_getregslen,
+       .get_regs = smsc9420_ethtool_getregs,
+};
+
+/* Sets the device MAC address to dev_addr */
+static void smsc9420_set_mac_address(struct net_device *dev)
+{
+       struct smsc9420_pdata *pd = netdev_priv(dev);
+       u8 *dev_addr = dev->dev_addr;
+       u32 mac_high16 = (dev_addr[5] << 8) | dev_addr[4];
+       u32 mac_low32 = (dev_addr[3] << 24) | (dev_addr[2] << 16) |
+           (dev_addr[1] << 8) | dev_addr[0];
+
+       smsc9420_reg_write(pd, ADDRH, mac_high16);
+       smsc9420_reg_write(pd, ADDRL, mac_low32);
+}
+
+static void smsc9420_check_mac_address(struct net_device *dev)
+{
+       struct smsc9420_pdata *pd = netdev_priv(dev);
+
+       /* Check if mac address has been specified when bringing interface up */
+       if (is_valid_ether_addr(dev->dev_addr)) {
+               smsc9420_set_mac_address(dev);
+               smsc_dbg(PROBE, "MAC Address is specified by configuration");
+       } else {
+               /* Try reading mac address from device. if EEPROM is present
+                * it will already have been set */
+               u32 mac_high16 = smsc9420_reg_read(pd, ADDRH);
+               u32 mac_low32 = smsc9420_reg_read(pd, ADDRL);
+               dev->dev_addr[0] = (u8)(mac_low32);
+               dev->dev_addr[1] = (u8)(mac_low32 >> 8);
+               dev->dev_addr[2] = (u8)(mac_low32 >> 16);
+               dev->dev_addr[3] = (u8)(mac_low32 >> 24);
+               dev->dev_addr[4] = (u8)(mac_high16);
+               dev->dev_addr[5] = (u8)(mac_high16 >> 8);
+
+               if (is_valid_ether_addr(dev->dev_addr)) {
+                       /* eeprom values are valid  so use them */
+                       smsc_dbg(PROBE, "Mac Address is read from EEPROM");
+               } else {
+                       /* eeprom values are invalid, generate random MAC */
+                       random_ether_addr(dev->dev_addr);
+                       smsc9420_set_mac_address(dev);
+                       smsc_dbg(PROBE,
+                               "MAC Address is set to random_ether_addr");
+               }
+       }
+}
+
+static void smsc9420_stop_tx(struct smsc9420_pdata *pd)
+{
+       u32 dmac_control, mac_cr, dma_intr_ena;
+       int timeout = 1000;
+
+       /* disable TX DMAC */
+       dmac_control = smsc9420_reg_read(pd, DMAC_CONTROL);
+       dmac_control &= (~DMAC_CONTROL_ST_);
+       smsc9420_reg_write(pd, DMAC_CONTROL, dmac_control);
+
+       /* Wait max 10ms for transmit process to stop */
+       while (--timeout) {
+               if (smsc9420_reg_read(pd, DMAC_STATUS) & DMAC_STS_TS_)
+                       break;
+               udelay(10);
+       }
+
+       if (!timeout)
+               smsc_warn(IFDOWN, "TX DMAC failed to stop");
+
+       /* ACK Tx DMAC stop bit */
+       smsc9420_reg_write(pd, DMAC_STATUS, DMAC_STS_TXPS_);
+
+       /* mask TX DMAC interrupts */
+       dma_intr_ena = smsc9420_reg_read(pd, DMAC_INTR_ENA);
+       dma_intr_ena &= ~(DMAC_INTR_ENA_TX_);
+       smsc9420_reg_write(pd, DMAC_INTR_ENA, dma_intr_ena);
+       smsc9420_pci_flush_write(pd);
+
+       /* stop MAC TX */
+       mac_cr = smsc9420_reg_read(pd, MAC_CR) & (~MAC_CR_TXEN_);
+       smsc9420_reg_write(pd, MAC_CR, mac_cr);
+       smsc9420_pci_flush_write(pd);
+}
+
+static void smsc9420_free_tx_ring(struct smsc9420_pdata *pd)
+{
+       int i;
+
+       BUG_ON(!pd->tx_ring);
+
+       if (!pd->tx_buffers)
+               return;
+
+       for (i = 0; i < TX_RING_SIZE; i++) {
+               struct sk_buff *skb = pd->tx_buffers[i].skb;
+
+               if (skb) {
+                       BUG_ON(!pd->tx_buffers[i].mapping);
+                       pci_unmap_single(pd->pdev, pd->tx_buffers[i].mapping,
+                                        skb->len, PCI_DMA_TODEVICE);
+                       dev_kfree_skb_any(skb);
+               }
+
+               pd->tx_ring[i].status = 0;
+               pd->tx_ring[i].length = 0;
+               pd->tx_ring[i].buffer1 = 0;
+               pd->tx_ring[i].buffer2 = 0;
+       }
+       wmb();
+
+       kfree(pd->tx_buffers);
+       pd->tx_buffers = NULL;
+
+       pd->tx_ring_head = 0;
+       pd->tx_ring_tail = 0;
+}
+
+static void smsc9420_free_rx_ring(struct smsc9420_pdata *pd)
+{
+       int i;
+
+       BUG_ON(!pd->rx_ring);
+
+       if (!pd->rx_buffers)
+               return;
+
+       for (i = 0; i < RX_RING_SIZE; i++) {
+               if (pd->rx_buffers[i].skb)
+                       dev_kfree_skb_any(pd->rx_buffers[i].skb);
+
+               if (pd->rx_buffers[i].mapping)
+                       pci_unmap_single(pd->pdev, pd->rx_buffers[i].mapping,
+                               PKT_BUF_SZ, PCI_DMA_FROMDEVICE);
+
+               pd->rx_ring[i].status = 0;
+               pd->rx_ring[i].length = 0;
+               pd->rx_ring[i].buffer1 = 0;
+               pd->rx_ring[i].buffer2 = 0;
+       }
+       wmb();
+
+       kfree(pd->rx_buffers);
+       pd->rx_buffers = NULL;
+
+       pd->rx_ring_head = 0;
+       pd->rx_ring_tail = 0;
+}
+
+static void smsc9420_stop_rx(struct smsc9420_pdata *pd)
+{
+       int timeout = 1000;
+       u32 mac_cr, dmac_control, dma_intr_ena;
+
+       /* mask RX DMAC interrupts */
+       dma_intr_ena = smsc9420_reg_read(pd, DMAC_INTR_ENA);
+       dma_intr_ena &= (~DMAC_INTR_ENA_RX_);
+       smsc9420_reg_write(pd, DMAC_INTR_ENA, dma_intr_ena);
+       smsc9420_pci_flush_write(pd);
+
+       /* stop RX MAC prior to stoping DMA */
+       mac_cr = smsc9420_reg_read(pd, MAC_CR) & (~MAC_CR_RXEN_);
+       smsc9420_reg_write(pd, MAC_CR, mac_cr);
+       smsc9420_pci_flush_write(pd);
+
+       /* stop RX DMAC */
+       dmac_control = smsc9420_reg_read(pd, DMAC_CONTROL);
+       dmac_control &= (~DMAC_CONTROL_SR_);
+       smsc9420_reg_write(pd, DMAC_CONTROL, dmac_control);
+       smsc9420_pci_flush_write(pd);
+
+       /* wait up to 10ms for receive to stop */
+       while (--timeout) {
+               if (smsc9420_reg_read(pd, DMAC_STATUS) & DMAC_STS_RS_)
+                       break;
+               udelay(10);
+       }
+
+       if (!timeout)
+               smsc_warn(IFDOWN, "RX DMAC did not stop! timeout.");
+
+       /* ACK the Rx DMAC stop bit */
+       smsc9420_reg_write(pd, DMAC_STATUS, DMAC_STS_RXPS_);
+}
+
+static irqreturn_t smsc9420_isr(int irq, void *dev_id)
+{
+       struct smsc9420_pdata *pd = dev_id;
+       u32 int_cfg, int_sts, int_ctl;
+       irqreturn_t ret = IRQ_NONE;
+       ulong flags;
+
+       BUG_ON(!pd);
+       BUG_ON(!pd->base_addr);
+
+       int_cfg = smsc9420_reg_read(pd, INT_CFG);
+
+       /* check if it's our interrupt */
+       if ((int_cfg & (INT_CFG_IRQ_EN_ | INT_CFG_IRQ_INT_)) !=
+           (INT_CFG_IRQ_EN_ | INT_CFG_IRQ_INT_))
+               return IRQ_NONE;
+
+       int_sts = smsc9420_reg_read(pd, INT_STAT);
+
+       if (likely(INT_STAT_DMAC_INT_ & int_sts)) {
+               u32 status = smsc9420_reg_read(pd, DMAC_STATUS);
+               u32 ints_to_clear = 0;
+
+               if (status & DMAC_STS_TX_) {
+                       ints_to_clear |= (DMAC_STS_TX_ | DMAC_STS_NIS_);
+                       netif_wake_queue(pd->dev);
+               }
+
+               if (status & DMAC_STS_RX_) {
+                       /* mask RX DMAC interrupts */
+                       u32 dma_intr_ena = smsc9420_reg_read(pd, DMAC_INTR_ENA);
+                       dma_intr_ena &= (~DMAC_INTR_ENA_RX_);
+                       smsc9420_reg_write(pd, DMAC_INTR_ENA, dma_intr_ena);
+                       smsc9420_pci_flush_write(pd);
+
+                       ints_to_clear |= (DMAC_STS_RX_ | DMAC_STS_NIS_);
+                       napi_schedule(&pd->napi);
+               }
+
+               if (ints_to_clear)
+                       smsc9420_reg_write(pd, DMAC_STATUS, ints_to_clear);
+
+               ret = IRQ_HANDLED;
+       }
+
+       if (unlikely(INT_STAT_SW_INT_ & int_sts)) {
+               /* mask software interrupt */
+               spin_lock_irqsave(&pd->int_lock, flags);
+               int_ctl = smsc9420_reg_read(pd, INT_CTL);
+               int_ctl &= (~INT_CTL_SW_INT_EN_);
+               smsc9420_reg_write(pd, INT_CTL, int_ctl);
+               spin_unlock_irqrestore(&pd->int_lock, flags);
+
+               smsc9420_reg_write(pd, INT_STAT, INT_STAT_SW_INT_);
+               pd->software_irq_signal = true;
+               smp_wmb();
+
+               ret = IRQ_HANDLED;
+       }
+
+       /* to ensure PCI write completion, we must perform a PCI read */
+       smsc9420_pci_flush_write(pd);
+
+       return ret;
+}
+
+#ifdef CONFIG_NET_POLL_CONTROLLER
+static void smsc9420_poll_controller(struct net_device *dev)
+{
+       disable_irq(dev->irq);
+       smsc9420_isr(0, dev);
+       enable_irq(dev->irq);
+}
+#endif /* CONFIG_NET_POLL_CONTROLLER */
+
+static void smsc9420_dmac_soft_reset(struct smsc9420_pdata *pd)
+{
+       smsc9420_reg_write(pd, BUS_MODE, BUS_MODE_SWR_);
+       smsc9420_reg_read(pd, BUS_MODE);
+       udelay(2);
+       if (smsc9420_reg_read(pd, BUS_MODE) & BUS_MODE_SWR_)
+               smsc_warn(DRV, "Software reset not cleared");
+}
+
+static int smsc9420_stop(struct net_device *dev)
+{
+       struct smsc9420_pdata *pd = netdev_priv(dev);
+       u32 int_cfg;
+       ulong flags;
+
+       BUG_ON(!pd);
+       BUG_ON(!pd->phy_dev);
+
+       /* disable master interrupt */
+       spin_lock_irqsave(&pd->int_lock, flags);
+       int_cfg = smsc9420_reg_read(pd, INT_CFG) & (~INT_CFG_IRQ_EN_);
+       smsc9420_reg_write(pd, INT_CFG, int_cfg);
+       spin_unlock_irqrestore(&pd->int_lock, flags);
+
+       netif_tx_disable(dev);
+       napi_disable(&pd->napi);
+
+       smsc9420_stop_tx(pd);
+       smsc9420_free_tx_ring(pd);
+
+       smsc9420_stop_rx(pd);
+       smsc9420_free_rx_ring(pd);
+
+       free_irq(dev->irq, pd);
+
+       smsc9420_dmac_soft_reset(pd);
+
+       phy_stop(pd->phy_dev);
+
+       phy_disconnect(pd->phy_dev);
+       pd->phy_dev = NULL;
+       mdiobus_unregister(pd->mii_bus);
+       mdiobus_free(pd->mii_bus);
+
+       return 0;
+}
+
+static void smsc9420_rx_count_stats(struct net_device *dev, u32 desc_status)
+{
+       if (unlikely(desc_status & RDES0_ERROR_SUMMARY_)) {
+               dev->stats.rx_errors++;
+               if (desc_status & RDES0_DESCRIPTOR_ERROR_)
+                       dev->stats.rx_over_errors++;
+               else if (desc_status & (RDES0_FRAME_TOO_LONG_ |
+                       RDES0_RUNT_FRAME_ | RDES0_COLLISION_SEEN_))
+                       dev->stats.rx_frame_errors++;
+               else if (desc_status & RDES0_CRC_ERROR_)
+                       dev->stats.rx_crc_errors++;
+       }
+
+       if (unlikely(desc_status & RDES0_LENGTH_ERROR_))
+               dev->stats.rx_length_errors++;
+
+       if (unlikely(!((desc_status & RDES0_LAST_DESCRIPTOR_) &&
+               (desc_status & RDES0_FIRST_DESCRIPTOR_))))
+               dev->stats.rx_length_errors++;
+
+       if (desc_status & RDES0_MULTICAST_FRAME_)
+               dev->stats.multicast++;
+}
+
+static void smsc9420_rx_handoff(struct smsc9420_pdata *pd, const int index,
+                               const u32 status)
+{
+       struct net_device *dev = pd->dev;
+       struct sk_buff *skb;
+       u16 packet_length = (status & RDES0_FRAME_LENGTH_MASK_)
+               >> RDES0_FRAME_LENGTH_SHFT_;
+
+       /* remove crc from packet lendth */
+       packet_length -= 4;
+
+       if (pd->rx_csum)
+               packet_length -= 2;
+
+       dev->stats.rx_packets++;
+       dev->stats.rx_bytes += packet_length;
+
+       pci_unmap_single(pd->pdev, pd->rx_buffers[index].mapping,
+               PKT_BUF_SZ, PCI_DMA_FROMDEVICE);
+       pd->rx_buffers[index].mapping = 0;
+
+       skb = pd->rx_buffers[index].skb;
+       pd->rx_buffers[index].skb = NULL;
+
+       if (pd->rx_csum) {
+               u16 hw_csum = get_unaligned_le16(skb_tail_pointer(skb) +
+                       NET_IP_ALIGN + packet_length + 4);
+               put_unaligned_le16(hw_csum, &skb->csum);
+               skb->ip_summed = CHECKSUM_COMPLETE;
+       }
+
+       skb_reserve(skb, NET_IP_ALIGN);
+       skb_put(skb, packet_length);
+
+       skb->protocol = eth_type_trans(skb, dev);
+
+       netif_receive_skb(skb);
+}
+
+static int smsc9420_alloc_rx_buffer(struct smsc9420_pdata *pd, int index)
+{
+       struct sk_buff *skb = netdev_alloc_skb(pd->dev, PKT_BUF_SZ);
+       dma_addr_t mapping;
+
+       BUG_ON(pd->rx_buffers[index].skb);
+       BUG_ON(pd->rx_buffers[index].mapping);
+
+       if (unlikely(!skb)) {
+               smsc_warn(RX_ERR, "Failed to allocate new skb!");
+               return -ENOMEM;
+       }
+
+       skb->dev = pd->dev;
+
+       mapping = pci_map_single(pd->pdev, skb_tail_pointer(skb),
+                                PKT_BUF_SZ, PCI_DMA_FROMDEVICE);
+       if (pci_dma_mapping_error(pd->pdev, mapping)) {
+               dev_kfree_skb_any(skb);
+               smsc_warn(RX_ERR, "pci_map_single failed!");
+               return -ENOMEM;
+       }
+
+       pd->rx_buffers[index].skb = skb;
+       pd->rx_buffers[index].mapping = mapping;
+       pd->rx_ring[index].buffer1 = mapping + NET_IP_ALIGN;
+       pd->rx_ring[index].status = RDES0_OWN_;
+       wmb();
+
+       return 0;
+}
+
+static void smsc9420_alloc_new_rx_buffers(struct smsc9420_pdata *pd)
+{
+       while (pd->rx_ring_tail != pd->rx_ring_head) {
+               if (smsc9420_alloc_rx_buffer(pd, pd->rx_ring_tail))
+                       break;
+
+               pd->rx_ring_tail = (pd->rx_ring_tail + 1) % RX_RING_SIZE;
+       }
+}
+
+static int smsc9420_rx_poll(struct napi_struct *napi, int budget)
+{
+       struct smsc9420_pdata *pd =
+               container_of(napi, struct smsc9420_pdata, napi);
+       struct net_device *dev = pd->dev;
+       u32 drop_frame_cnt, dma_intr_ena, status;
+       int work_done;
+
+       for (work_done = 0; work_done < budget; work_done++) {
+               rmb();
+               status = pd->rx_ring[pd->rx_ring_head].status;
+
+               /* stop if DMAC owns this dma descriptor */
+               if (status & RDES0_OWN_)
+                       break;
+
+               smsc9420_rx_count_stats(dev, status);
+               smsc9420_rx_handoff(pd, pd->rx_ring_head, status);
+               pd->rx_ring_head = (pd->rx_ring_head + 1) % RX_RING_SIZE;
+               smsc9420_alloc_new_rx_buffers(pd);
+       }
+
+       drop_frame_cnt = smsc9420_reg_read(pd, MISS_FRAME_CNTR);
+       dev->stats.rx_dropped +=
+           (drop_frame_cnt & 0xFFFF) + ((drop_frame_cnt >> 17) & 0x3FF);
+
+       /* Kick RXDMA */
+       smsc9420_reg_write(pd, RX_POLL_DEMAND, 1);
+       smsc9420_pci_flush_write(pd);
+
+       if (work_done < budget) {
+               napi_complete(&pd->napi);
+
+               /* re-enable RX DMA interrupts */
+               dma_intr_ena = smsc9420_reg_read(pd, DMAC_INTR_ENA);
+               dma_intr_ena |= (DMAC_INTR_ENA_RX_ | DMAC_INTR_ENA_NIS_);
+               smsc9420_reg_write(pd, DMAC_INTR_ENA, dma_intr_ena);
+               smsc9420_pci_flush_write(pd);
+       }
+       return work_done;
+}
+
+static void
+smsc9420_tx_update_stats(struct net_device *dev, u32 status, u32 length)
+{
+       if (unlikely(status & TDES0_ERROR_SUMMARY_)) {
+               dev->stats.tx_errors++;
+               if (status & (TDES0_EXCESSIVE_DEFERRAL_ |
+                       TDES0_EXCESSIVE_COLLISIONS_))
+                       dev->stats.tx_aborted_errors++;
+
+               if (status & (TDES0_LOSS_OF_CARRIER_ | TDES0_NO_CARRIER_))
+                       dev->stats.tx_carrier_errors++;
+       } else {
+               dev->stats.tx_packets++;
+               dev->stats.tx_bytes += (length & 0x7FF);
+       }
+
+       if (unlikely(status & TDES0_EXCESSIVE_COLLISIONS_)) {
+               dev->stats.collisions += 16;
+       } else {
+               dev->stats.collisions +=
+                       (status & TDES0_COLLISION_COUNT_MASK_) >>
+                       TDES0_COLLISION_COUNT_SHFT_;
+       }
+
+       if (unlikely(status & TDES0_HEARTBEAT_FAIL_))
+               dev->stats.tx_heartbeat_errors++;
+}
+
+/* Check for completed dma transfers, update stats and free skbs */
+static void smsc9420_complete_tx(struct net_device *dev)
+{
+       struct smsc9420_pdata *pd = netdev_priv(dev);
+
+       while (pd->tx_ring_tail != pd->tx_ring_head) {
+               int index = pd->tx_ring_tail;
+               u32 status, length;
+
+               rmb();
+               status = pd->tx_ring[index].status;
+               length = pd->tx_ring[index].length;
+
+               /* Check if DMA still owns this descriptor */
+               if (unlikely(TDES0_OWN_ & status))
+                       break;
+
+               smsc9420_tx_update_stats(dev, status, length);
+
+               BUG_ON(!pd->tx_buffers[index].skb);
+               BUG_ON(!pd->tx_buffers[index].mapping);
+
+               pci_unmap_single(pd->pdev, pd->tx_buffers[index].mapping,
+                       pd->tx_buffers[index].skb->len, PCI_DMA_TODEVICE);
+               pd->tx_buffers[index].mapping = 0;
+
+               dev_kfree_skb_any(pd->tx_buffers[index].skb);
+               pd->tx_buffers[index].skb = NULL;
+
+               pd->tx_ring[index].buffer1 = 0;
+               wmb();
+
+               pd->tx_ring_tail = (pd->tx_ring_tail + 1) % TX_RING_SIZE;
+       }
+}
+
+static netdev_tx_t smsc9420_hard_start_xmit(struct sk_buff *skb,
+                                           struct net_device *dev)
+{
+       struct smsc9420_pdata *pd = netdev_priv(dev);
+       dma_addr_t mapping;
+       int index = pd->tx_ring_head;
+       u32 tmp_desc1;
+       bool about_to_take_last_desc =
+               (((pd->tx_ring_head + 2) % TX_RING_SIZE) == pd->tx_ring_tail);
+
+       smsc9420_complete_tx(dev);
+
+       rmb();
+       BUG_ON(pd->tx_ring[index].status & TDES0_OWN_);
+       BUG_ON(pd->tx_buffers[index].skb);
+       BUG_ON(pd->tx_buffers[index].mapping);
+
+       mapping = pci_map_single(pd->pdev, skb->data,
+                                skb->len, PCI_DMA_TODEVICE);
+       if (pci_dma_mapping_error(pd->pdev, mapping)) {
+               smsc_warn(TX_ERR, "pci_map_single failed, dropping packet");
+               return NETDEV_TX_BUSY;
+       }
+
+       pd->tx_buffers[index].skb = skb;
+       pd->tx_buffers[index].mapping = mapping;
+
+       tmp_desc1 = (TDES1_LS_ | ((u32)skb->len & 0x7FF));
+       if (unlikely(about_to_take_last_desc)) {
+               tmp_desc1 |= TDES1_IC_;
+               netif_stop_queue(pd->dev);
+       }
+
+       /* check if we are at the last descriptor and need to set EOR */
+       if (unlikely(index == (TX_RING_SIZE - 1)))
+               tmp_desc1 |= TDES1_TER_;
+
+       pd->tx_ring[index].buffer1 = mapping;
+       pd->tx_ring[index].length = tmp_desc1;
+       wmb();
+
+       /* increment head */
+       pd->tx_ring_head = (pd->tx_ring_head + 1) % TX_RING_SIZE;
+
+       /* assign ownership to DMAC */
+       pd->tx_ring[index].status = TDES0_OWN_;
+       wmb();
+
+       skb_tx_timestamp(skb);
+
+       /* kick the DMA */
+       smsc9420_reg_write(pd, TX_POLL_DEMAND, 1);
+       smsc9420_pci_flush_write(pd);
+
+       return NETDEV_TX_OK;
+}
+
+static struct net_device_stats *smsc9420_get_stats(struct net_device *dev)
+{
+       struct smsc9420_pdata *pd = netdev_priv(dev);
+       u32 counter = smsc9420_reg_read(pd, MISS_FRAME_CNTR);
+       dev->stats.rx_dropped +=
+           (counter & 0x0000FFFF) + ((counter >> 17) & 0x000003FF);
+       return &dev->stats;
+}
+
+static void smsc9420_set_multicast_list(struct net_device *dev)
+{
+       struct smsc9420_pdata *pd = netdev_priv(dev);
+       u32 mac_cr = smsc9420_reg_read(pd, MAC_CR);
+
+       if (dev->flags & IFF_PROMISC) {
+               smsc_dbg(HW, "Promiscuous Mode Enabled");
+               mac_cr |= MAC_CR_PRMS_;
+               mac_cr &= (~MAC_CR_MCPAS_);
+               mac_cr &= (~MAC_CR_HPFILT_);
+       } else if (dev->flags & IFF_ALLMULTI) {
+               smsc_dbg(HW, "Receive all Multicast Enabled");
+               mac_cr &= (~MAC_CR_PRMS_);
+               mac_cr |= MAC_CR_MCPAS_;
+               mac_cr &= (~MAC_CR_HPFILT_);
+       } else if (!netdev_mc_empty(dev)) {
+               struct netdev_hw_addr *ha;
+               u32 hash_lo = 0, hash_hi = 0;
+
+               smsc_dbg(HW, "Multicast filter enabled");
+               netdev_for_each_mc_addr(ha, dev) {
+                       u32 bit_num = smsc9420_hash(ha->addr);
+                       u32 mask = 1 << (bit_num & 0x1F);
+
+                       if (bit_num & 0x20)
+                               hash_hi |= mask;
+                       else
+                               hash_lo |= mask;
+
+               }
+               smsc9420_reg_write(pd, HASHH, hash_hi);
+               smsc9420_reg_write(pd, HASHL, hash_lo);
+
+               mac_cr &= (~MAC_CR_PRMS_);
+               mac_cr &= (~MAC_CR_MCPAS_);
+               mac_cr |= MAC_CR_HPFILT_;
+       } else {
+               smsc_dbg(HW, "Receive own packets only.");
+               smsc9420_reg_write(pd, HASHH, 0);
+               smsc9420_reg_write(pd, HASHL, 0);
+
+               mac_cr &= (~MAC_CR_PRMS_);
+               mac_cr &= (~MAC_CR_MCPAS_);
+               mac_cr &= (~MAC_CR_HPFILT_);
+       }
+
+       smsc9420_reg_write(pd, MAC_CR, mac_cr);
+       smsc9420_pci_flush_write(pd);
+}
+
+static void smsc9420_phy_update_flowcontrol(struct smsc9420_pdata *pd)
+{
+       struct phy_device *phy_dev = pd->phy_dev;
+       u32 flow;
+
+       if (phy_dev->duplex == DUPLEX_FULL) {
+               u16 lcladv = phy_read(phy_dev, MII_ADVERTISE);
+               u16 rmtadv = phy_read(phy_dev, MII_LPA);
+               u8 cap = mii_resolve_flowctrl_fdx(lcladv, rmtadv);
+
+               if (cap & FLOW_CTRL_RX)
+                       flow = 0xFFFF0002;
+               else
+                       flow = 0;
+
+               smsc_info(LINK, "rx pause %s, tx pause %s",
+                       (cap & FLOW_CTRL_RX ? "enabled" : "disabled"),
+                       (cap & FLOW_CTRL_TX ? "enabled" : "disabled"));
+       } else {
+               smsc_info(LINK, "half duplex");
+               flow = 0;
+       }
+
+       smsc9420_reg_write(pd, FLOW, flow);
+}
+
+/* Update link mode if anything has changed.  Called periodically when the
+ * PHY is in polling mode, even if nothing has changed. */
+static void smsc9420_phy_adjust_link(struct net_device *dev)
+{
+       struct smsc9420_pdata *pd = netdev_priv(dev);
+       struct phy_device *phy_dev = pd->phy_dev;
+       int carrier;
+
+       if (phy_dev->duplex != pd->last_duplex) {
+               u32 mac_cr = smsc9420_reg_read(pd, MAC_CR);
+               if (phy_dev->duplex) {
+                       smsc_dbg(LINK, "full duplex mode");
+                       mac_cr |= MAC_CR_FDPX_;
+               } else {
+                       smsc_dbg(LINK, "half duplex mode");
+                       mac_cr &= ~MAC_CR_FDPX_;
+               }
+               smsc9420_reg_write(pd, MAC_CR, mac_cr);
+
+               smsc9420_phy_update_flowcontrol(pd);
+               pd->last_duplex = phy_dev->duplex;
+       }
+
+       carrier = netif_carrier_ok(dev);
+       if (carrier != pd->last_carrier) {
+               if (carrier)
+                       smsc_dbg(LINK, "carrier OK");
+               else
+                       smsc_dbg(LINK, "no carrier");
+               pd->last_carrier = carrier;
+       }
+}
+
+static int smsc9420_mii_probe(struct net_device *dev)
+{
+       struct smsc9420_pdata *pd = netdev_priv(dev);
+       struct phy_device *phydev = NULL;
+
+       BUG_ON(pd->phy_dev);
+
+       /* Device only supports internal PHY at address 1 */
+       if (!pd->mii_bus->phy_map[1]) {
+               pr_err("%s: no PHY found at address 1\n", dev->name);
+               return -ENODEV;
+       }
+
+       phydev = pd->mii_bus->phy_map[1];
+       smsc_info(PROBE, "PHY addr %d, phy_id 0x%08X", phydev->addr,
+               phydev->phy_id);
+
+       phydev = phy_connect(dev, dev_name(&phydev->dev),
+               smsc9420_phy_adjust_link, 0, PHY_INTERFACE_MODE_MII);
+
+       if (IS_ERR(phydev)) {
+               pr_err("%s: Could not attach to PHY\n", dev->name);
+               return PTR_ERR(phydev);
+       }
+
+       pr_info("%s: attached PHY driver [%s] (mii_bus:phy_addr=%s, irq=%d)\n",
+               dev->name, phydev->drv->name, dev_name(&phydev->dev), phydev->irq);
+
+       /* mask with MAC supported features */
+       phydev->supported &= (PHY_BASIC_FEATURES | SUPPORTED_Pause |
+                             SUPPORTED_Asym_Pause);
+       phydev->advertising = phydev->supported;
+
+       pd->phy_dev = phydev;
+       pd->last_duplex = -1;
+       pd->last_carrier = -1;
+
+       return 0;
+}
+
+static int smsc9420_mii_init(struct net_device *dev)
+{
+       struct smsc9420_pdata *pd = netdev_priv(dev);
+       int err = -ENXIO, i;
+
+       pd->mii_bus = mdiobus_alloc();
+       if (!pd->mii_bus) {
+               err = -ENOMEM;
+               goto err_out_1;
+       }
+       pd->mii_bus->name = DRV_MDIONAME;
+       snprintf(pd->mii_bus->id, MII_BUS_ID_SIZE, "%x",
+               (pd->pdev->bus->number << 8) | pd->pdev->devfn);
+       pd->mii_bus->priv = pd;
+       pd->mii_bus->read = smsc9420_mii_read;
+       pd->mii_bus->write = smsc9420_mii_write;
+       pd->mii_bus->irq = pd->phy_irq;
+       for (i = 0; i < PHY_MAX_ADDR; ++i)
+               pd->mii_bus->irq[i] = PHY_POLL;
+
+       /* Mask all PHYs except ID 1 (internal) */
+       pd->mii_bus->phy_mask = ~(1 << 1);
+
+       if (mdiobus_register(pd->mii_bus)) {
+               smsc_warn(PROBE, "Error registering mii bus");
+               goto err_out_free_bus_2;
+       }
+
+       if (smsc9420_mii_probe(dev) < 0) {
+               smsc_warn(PROBE, "Error probing mii bus");
+               goto err_out_unregister_bus_3;
+       }
+
+       return 0;
+
+err_out_unregister_bus_3:
+       mdiobus_unregister(pd->mii_bus);
+err_out_free_bus_2:
+       mdiobus_free(pd->mii_bus);
+err_out_1:
+       return err;
+}
+
+static int smsc9420_alloc_tx_ring(struct smsc9420_pdata *pd)
+{
+       int i;
+
+       BUG_ON(!pd->tx_ring);
+
+       pd->tx_buffers = kmalloc((sizeof(struct smsc9420_ring_info) *
+               TX_RING_SIZE), GFP_KERNEL);
+       if (!pd->tx_buffers) {
+               smsc_warn(IFUP, "Failed to allocated tx_buffers");
+               return -ENOMEM;
+       }
+
+       /* Initialize the TX Ring */
+       for (i = 0; i < TX_RING_SIZE; i++) {
+               pd->tx_buffers[i].skb = NULL;
+               pd->tx_buffers[i].mapping = 0;
+               pd->tx_ring[i].status = 0;
+               pd->tx_ring[i].length = 0;
+               pd->tx_ring[i].buffer1 = 0;
+               pd->tx_ring[i].buffer2 = 0;
+       }
+       pd->tx_ring[TX_RING_SIZE - 1].length = TDES1_TER_;
+       wmb();
+
+       pd->tx_ring_head = 0;
+       pd->tx_ring_tail = 0;
+
+       smsc9420_reg_write(pd, TX_BASE_ADDR, pd->tx_dma_addr);
+       smsc9420_pci_flush_write(pd);
+
+       return 0;
+}
+
+static int smsc9420_alloc_rx_ring(struct smsc9420_pdata *pd)
+{
+       int i;
+
+       BUG_ON(!pd->rx_ring);
+
+       pd->rx_buffers = kmalloc((sizeof(struct smsc9420_ring_info) *
+               RX_RING_SIZE), GFP_KERNEL);
+       if (pd->rx_buffers == NULL) {
+               smsc_warn(IFUP, "Failed to allocated rx_buffers");
+               goto out;
+       }
+
+       /* initialize the rx ring */
+       for (i = 0; i < RX_RING_SIZE; i++) {
+               pd->rx_ring[i].status = 0;
+               pd->rx_ring[i].length = PKT_BUF_SZ;
+               pd->rx_ring[i].buffer2 = 0;
+               pd->rx_buffers[i].skb = NULL;
+               pd->rx_buffers[i].mapping = 0;
+       }
+       pd->rx_ring[RX_RING_SIZE - 1].length = (PKT_BUF_SZ | RDES1_RER_);
+
+       /* now allocate the entire ring of skbs */
+       for (i = 0; i < RX_RING_SIZE; i++) {
+               if (smsc9420_alloc_rx_buffer(pd, i)) {
+                       smsc_warn(IFUP, "failed to allocate rx skb %d", i);
+                       goto out_free_rx_skbs;
+               }
+       }
+
+       pd->rx_ring_head = 0;
+       pd->rx_ring_tail = 0;
+
+       smsc9420_reg_write(pd, VLAN1, ETH_P_8021Q);
+       smsc_dbg(IFUP, "VLAN1 = 0x%08x", smsc9420_reg_read(pd, VLAN1));
+
+       if (pd->rx_csum) {
+               /* Enable RX COE */
+               u32 coe = smsc9420_reg_read(pd, COE_CR) | RX_COE_EN;
+               smsc9420_reg_write(pd, COE_CR, coe);
+               smsc_dbg(IFUP, "COE_CR = 0x%08x", coe);
+       }
+
+       smsc9420_reg_write(pd, RX_BASE_ADDR, pd->rx_dma_addr);
+       smsc9420_pci_flush_write(pd);
+
+       return 0;
+
+out_free_rx_skbs:
+       smsc9420_free_rx_ring(pd);
+out:
+       return -ENOMEM;
+}
+
+static int smsc9420_open(struct net_device *dev)
+{
+       struct smsc9420_pdata *pd;
+       u32 bus_mode, mac_cr, dmac_control, int_cfg, dma_intr_ena, int_ctl;
+       unsigned long flags;
+       int result = 0, timeout;
+
+       BUG_ON(!dev);
+       pd = netdev_priv(dev);
+       BUG_ON(!pd);
+
+       if (!is_valid_ether_addr(dev->dev_addr)) {
+               smsc_warn(IFUP, "dev_addr is not a valid MAC address");
+               result = -EADDRNOTAVAIL;
+               goto out_0;
+       }
+
+       netif_carrier_off(dev);
+
+       /* disable, mask and acknowledge all interrupts */
+       spin_lock_irqsave(&pd->int_lock, flags);
+       int_cfg = smsc9420_reg_read(pd, INT_CFG) & (~INT_CFG_IRQ_EN_);
+       smsc9420_reg_write(pd, INT_CFG, int_cfg);
+       smsc9420_reg_write(pd, INT_CTL, 0);
+       spin_unlock_irqrestore(&pd->int_lock, flags);
+       smsc9420_reg_write(pd, DMAC_INTR_ENA, 0);
+       smsc9420_reg_write(pd, INT_STAT, 0xFFFFFFFF);
+       smsc9420_pci_flush_write(pd);
+
+       if (request_irq(dev->irq, smsc9420_isr, IRQF_SHARED | IRQF_DISABLED,
+                       DRV_NAME, pd)) {
+               smsc_warn(IFUP, "Unable to use IRQ = %d", dev->irq);
+               result = -ENODEV;
+               goto out_0;
+       }
+
+       smsc9420_dmac_soft_reset(pd);
+
+       /* make sure MAC_CR is sane */
+       smsc9420_reg_write(pd, MAC_CR, 0);
+
+       smsc9420_set_mac_address(dev);
+
+       /* Configure GPIO pins to drive LEDs */
+       smsc9420_reg_write(pd, GPIO_CFG,
+               (GPIO_CFG_LED_3_ | GPIO_CFG_LED_2_ | GPIO_CFG_LED_1_));
+
+       bus_mode = BUS_MODE_DMA_BURST_LENGTH_16;
+
+#ifdef __BIG_ENDIAN
+       bus_mode |= BUS_MODE_DBO_;
+#endif
+
+       smsc9420_reg_write(pd, BUS_MODE, bus_mode);
+
+       smsc9420_pci_flush_write(pd);
+
+       /* set bus master bridge arbitration priority for Rx and TX DMA */
+       smsc9420_reg_write(pd, BUS_CFG, BUS_CFG_RXTXWEIGHT_4_1);
+
+       smsc9420_reg_write(pd, DMAC_CONTROL,
+               (DMAC_CONTROL_SF_ | DMAC_CONTROL_OSF_));
+
+       smsc9420_pci_flush_write(pd);
+
+       /* test the IRQ connection to the ISR */
+       smsc_dbg(IFUP, "Testing ISR using IRQ %d", dev->irq);
+       pd->software_irq_signal = false;
+
+       spin_lock_irqsave(&pd->int_lock, flags);
+       /* configure interrupt deassertion timer and enable interrupts */
+       int_cfg = smsc9420_reg_read(pd, INT_CFG) | INT_CFG_IRQ_EN_;
+       int_cfg &= ~(INT_CFG_INT_DEAS_MASK);
+       int_cfg |= (INT_DEAS_TIME & INT_CFG_INT_DEAS_MASK);
+       smsc9420_reg_write(pd, INT_CFG, int_cfg);
+
+       /* unmask software interrupt */
+       int_ctl = smsc9420_reg_read(pd, INT_CTL) | INT_CTL_SW_INT_EN_;
+       smsc9420_reg_write(pd, INT_CTL, int_ctl);
+       spin_unlock_irqrestore(&pd->int_lock, flags);
+       smsc9420_pci_flush_write(pd);
+
+       timeout = 1000;
+       while (timeout--) {
+               if (pd->software_irq_signal)
+                       break;
+               msleep(1);
+       }
+
+       /* disable interrupts */
+       spin_lock_irqsave(&pd->int_lock, flags);
+       int_cfg = smsc9420_reg_read(pd, INT_CFG) & (~INT_CFG_IRQ_EN_);
+       smsc9420_reg_write(pd, INT_CFG, int_cfg);
+       spin_unlock_irqrestore(&pd->int_lock, flags);
+
+       if (!pd->software_irq_signal) {
+               smsc_warn(IFUP, "ISR failed signaling test");
+               result = -ENODEV;
+               goto out_free_irq_1;
+       }
+
+       smsc_dbg(IFUP, "ISR passed test using IRQ %d", dev->irq);
+
+       result = smsc9420_alloc_tx_ring(pd);
+       if (result) {
+               smsc_warn(IFUP, "Failed to Initialize tx dma ring");
+               result = -ENOMEM;
+               goto out_free_irq_1;
+       }
+
+       result = smsc9420_alloc_rx_ring(pd);
+       if (result) {
+               smsc_warn(IFUP, "Failed to Initialize rx dma ring");
+               result = -ENOMEM;
+               goto out_free_tx_ring_2;
+       }
+
+       result = smsc9420_mii_init(dev);
+       if (result) {
+               smsc_warn(IFUP, "Failed to initialize Phy");
+               result = -ENODEV;
+               goto out_free_rx_ring_3;
+       }
+
+       /* Bring the PHY up */
+       phy_start(pd->phy_dev);
+
+       napi_enable(&pd->napi);
+
+       /* start tx and rx */
+       mac_cr = smsc9420_reg_read(pd, MAC_CR) | MAC_CR_TXEN_ | MAC_CR_RXEN_;
+       smsc9420_reg_write(pd, MAC_CR, mac_cr);
+
+       dmac_control = smsc9420_reg_read(pd, DMAC_CONTROL);
+       dmac_control |= DMAC_CONTROL_ST_ | DMAC_CONTROL_SR_;
+       smsc9420_reg_write(pd, DMAC_CONTROL, dmac_control);
+       smsc9420_pci_flush_write(pd);
+
+       dma_intr_ena = smsc9420_reg_read(pd, DMAC_INTR_ENA);
+       dma_intr_ena |=
+               (DMAC_INTR_ENA_TX_ | DMAC_INTR_ENA_RX_ | DMAC_INTR_ENA_NIS_);
+       smsc9420_reg_write(pd, DMAC_INTR_ENA, dma_intr_ena);
+       smsc9420_pci_flush_write(pd);
+
+       netif_wake_queue(dev);
+
+       smsc9420_reg_write(pd, RX_POLL_DEMAND, 1);
+
+       /* enable interrupts */
+       spin_lock_irqsave(&pd->int_lock, flags);
+       int_cfg = smsc9420_reg_read(pd, INT_CFG) | INT_CFG_IRQ_EN_;
+       smsc9420_reg_write(pd, INT_CFG, int_cfg);
+       spin_unlock_irqrestore(&pd->int_lock, flags);
+
+       return 0;
+
+out_free_rx_ring_3:
+       smsc9420_free_rx_ring(pd);
+out_free_tx_ring_2:
+       smsc9420_free_tx_ring(pd);
+out_free_irq_1:
+       free_irq(dev->irq, pd);
+out_0:
+       return result;
+}
+
+#ifdef CONFIG_PM
+
+static int smsc9420_suspend(struct pci_dev *pdev, pm_message_t state)
+{
+       struct net_device *dev = pci_get_drvdata(pdev);
+       struct smsc9420_pdata *pd = netdev_priv(dev);
+       u32 int_cfg;
+       ulong flags;
+
+       /* disable interrupts */
+       spin_lock_irqsave(&pd->int_lock, flags);
+       int_cfg = smsc9420_reg_read(pd, INT_CFG) & (~INT_CFG_IRQ_EN_);
+       smsc9420_reg_write(pd, INT_CFG, int_cfg);
+       spin_unlock_irqrestore(&pd->int_lock, flags);
+
+       if (netif_running(dev)) {
+               netif_tx_disable(dev);
+               smsc9420_stop_tx(pd);
+               smsc9420_free_tx_ring(pd);
+
+               napi_disable(&pd->napi);
+               smsc9420_stop_rx(pd);
+               smsc9420_free_rx_ring(pd);
+
+               free_irq(dev->irq, pd);
+
+               netif_device_detach(dev);
+       }
+
+       pci_save_state(pdev);
+       pci_enable_wake(pdev, pci_choose_state(pdev, state), 0);
+       pci_disable_device(pdev);
+       pci_set_power_state(pdev, pci_choose_state(pdev, state));
+
+       return 0;
+}
+
+static int smsc9420_resume(struct pci_dev *pdev)
+{
+       struct net_device *dev = pci_get_drvdata(pdev);
+       struct smsc9420_pdata *pd = netdev_priv(dev);
+       int err;
+
+       pci_set_power_state(pdev, PCI_D0);
+       pci_restore_state(pdev);
+
+       err = pci_enable_device(pdev);
+       if (err)
+               return err;
+
+       pci_set_master(pdev);
+
+       err = pci_enable_wake(pdev, 0, 0);
+       if (err)
+               smsc_warn(IFUP, "pci_enable_wake failed: %d", err);
+
+       if (netif_running(dev)) {
+               err = smsc9420_open(dev);
+               netif_device_attach(dev);
+       }
+       return err;
+}
+
+#endif /* CONFIG_PM */
+
+static const struct net_device_ops smsc9420_netdev_ops = {
+       .ndo_open               = smsc9420_open,
+       .ndo_stop               = smsc9420_stop,
+       .ndo_start_xmit         = smsc9420_hard_start_xmit,
+       .ndo_get_stats          = smsc9420_get_stats,
+       .ndo_set_multicast_list = smsc9420_set_multicast_list,
+       .ndo_do_ioctl           = smsc9420_do_ioctl,
+       .ndo_validate_addr      = eth_validate_addr,
+       .ndo_set_mac_address    = eth_mac_addr,
+#ifdef CONFIG_NET_POLL_CONTROLLER
+       .ndo_poll_controller    = smsc9420_poll_controller,
+#endif /* CONFIG_NET_POLL_CONTROLLER */
+};
+
+static int __devinit
+smsc9420_probe(struct pci_dev *pdev, const struct pci_device_id *id)
+{
+       struct net_device *dev;
+       struct smsc9420_pdata *pd;
+       void __iomem *virt_addr;
+       int result = 0;
+       u32 id_rev;
+
+       printk(KERN_INFO DRV_DESCRIPTION " version " DRV_VERSION "\n");
+
+       /* First do the PCI initialisation */
+       result = pci_enable_device(pdev);
+       if (unlikely(result)) {
+               printk(KERN_ERR "Cannot enable smsc9420\n");
+               goto out_0;
+       }
+
+       pci_set_master(pdev);
+
+       dev = alloc_etherdev(sizeof(*pd));
+       if (!dev) {
+               printk(KERN_ERR "ether device alloc failed\n");
+               goto out_disable_pci_device_1;
+       }
+
+       SET_NETDEV_DEV(dev, &pdev->dev);
+
+       if (!(pci_resource_flags(pdev, SMSC_BAR) & IORESOURCE_MEM)) {
+               printk(KERN_ERR "Cannot find PCI device base address\n");
+               goto out_free_netdev_2;
+       }
+
+       if ((pci_request_regions(pdev, DRV_NAME))) {
+               printk(KERN_ERR "Cannot obtain PCI resources, aborting.\n");
+               goto out_free_netdev_2;
+       }
+
+       if (pci_set_dma_mask(pdev, DMA_BIT_MASK(32))) {
+               printk(KERN_ERR "No usable DMA configuration, aborting.\n");
+               goto out_free_regions_3;
+       }
+
+       virt_addr = ioremap(pci_resource_start(pdev, SMSC_BAR),
+               pci_resource_len(pdev, SMSC_BAR));
+       if (!virt_addr) {
+               printk(KERN_ERR "Cannot map device registers, aborting.\n");
+               goto out_free_regions_3;
+       }
+
+       /* registers are double mapped with 0 offset for LE and 0x200 for BE */
+       virt_addr += LAN9420_CPSR_ENDIAN_OFFSET;
+
+       dev->base_addr = (ulong)virt_addr;
+
+       pd = netdev_priv(dev);
+
+       /* pci descriptors are created in the PCI consistent area */
+       pd->rx_ring = pci_alloc_consistent(pdev,
+               sizeof(struct smsc9420_dma_desc) * RX_RING_SIZE +
+               sizeof(struct smsc9420_dma_desc) * TX_RING_SIZE,
+               &pd->rx_dma_addr);
+
+       if (!pd->rx_ring)
+               goto out_free_io_4;
+
+       /* descriptors are aligned due to the nature of pci_alloc_consistent */
+       pd->tx_ring = (struct smsc9420_dma_desc *)
+           (pd->rx_ring + RX_RING_SIZE);
+       pd->tx_dma_addr = pd->rx_dma_addr +
+           sizeof(struct smsc9420_dma_desc) * RX_RING_SIZE;
+
+       pd->pdev = pdev;
+       pd->dev = dev;
+       pd->base_addr = virt_addr;
+       pd->msg_enable = smsc_debug;
+       pd->rx_csum = true;
+
+       smsc_dbg(PROBE, "lan_base=0x%08lx", (ulong)virt_addr);
+
+       id_rev = smsc9420_reg_read(pd, ID_REV);
+       switch (id_rev & 0xFFFF0000) {
+       case 0x94200000:
+               smsc_info(PROBE, "LAN9420 identified, ID_REV=0x%08X", id_rev);
+               break;
+       default:
+               smsc_warn(PROBE, "LAN9420 NOT identified");
+               smsc_warn(PROBE, "ID_REV=0x%08X", id_rev);
+               goto out_free_dmadesc_5;
+       }
+
+       smsc9420_dmac_soft_reset(pd);
+       smsc9420_eeprom_reload(pd);
+       smsc9420_check_mac_address(dev);
+
+       dev->netdev_ops = &smsc9420_netdev_ops;
+       dev->ethtool_ops = &smsc9420_ethtool_ops;
+       dev->irq = pdev->irq;
+
+       netif_napi_add(dev, &pd->napi, smsc9420_rx_poll, NAPI_WEIGHT);
+
+       result = register_netdev(dev);
+       if (result) {
+               smsc_warn(PROBE, "error %i registering device", result);
+               goto out_free_dmadesc_5;
+       }
+
+       pci_set_drvdata(pdev, dev);
+
+       spin_lock_init(&pd->int_lock);
+       spin_lock_init(&pd->phy_lock);
+
+       dev_info(&dev->dev, "MAC Address: %pM\n", dev->dev_addr);
+
+       return 0;
+
+out_free_dmadesc_5:
+       pci_free_consistent(pdev, sizeof(struct smsc9420_dma_desc) *
+               (RX_RING_SIZE + TX_RING_SIZE), pd->rx_ring, pd->rx_dma_addr);
+out_free_io_4:
+       iounmap(virt_addr - LAN9420_CPSR_ENDIAN_OFFSET);
+out_free_regions_3:
+       pci_release_regions(pdev);
+out_free_netdev_2:
+       free_netdev(dev);
+out_disable_pci_device_1:
+       pci_disable_device(pdev);
+out_0:
+       return -ENODEV;
+}
+
+static void __devexit smsc9420_remove(struct pci_dev *pdev)
+{
+       struct net_device *dev;
+       struct smsc9420_pdata *pd;
+
+       dev = pci_get_drvdata(pdev);
+       if (!dev)
+               return;
+
+       pci_set_drvdata(pdev, NULL);
+
+       pd = netdev_priv(dev);
+       unregister_netdev(dev);
+
+       /* tx_buffers and rx_buffers are freed in stop */
+       BUG_ON(pd->tx_buffers);
+       BUG_ON(pd->rx_buffers);
+
+       BUG_ON(!pd->tx_ring);
+       BUG_ON(!pd->rx_ring);
+
+       pci_free_consistent(pdev, sizeof(struct smsc9420_dma_desc) *
+               (RX_RING_SIZE + TX_RING_SIZE), pd->rx_ring, pd->rx_dma_addr);
+
+       iounmap(pd->base_addr - LAN9420_CPSR_ENDIAN_OFFSET);
+       pci_release_regions(pdev);
+       free_netdev(dev);
+       pci_disable_device(pdev);
+}
+
+static struct pci_driver smsc9420_driver = {
+       .name = DRV_NAME,
+       .id_table = smsc9420_id_table,
+       .probe = smsc9420_probe,
+       .remove = __devexit_p(smsc9420_remove),
+#ifdef CONFIG_PM
+       .suspend = smsc9420_suspend,
+       .resume = smsc9420_resume,
+#endif /* CONFIG_PM */
+};
+
+static int __init smsc9420_init_module(void)
+{
+       smsc_debug = netif_msg_init(debug, SMSC_MSG_DEFAULT);
+
+       return pci_register_driver(&smsc9420_driver);
+}
+
+static void __exit smsc9420_exit_module(void)
+{
+       pci_unregister_driver(&smsc9420_driver);
+}
+
+module_init(smsc9420_init_module);
+module_exit(smsc9420_exit_module);
diff --git a/drivers/net/ethernet/smsc/smsc9420.h b/drivers/net/ethernet/smsc/smsc9420.h
new file mode 100644 (file)
index 0000000..e441402
--- /dev/null
@@ -0,0 +1,276 @@
+ /***************************************************************************
+ *
+ * Copyright (C) 2007,2008  SMSC
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
+ *
+ ***************************************************************************
+ */
+
+#ifndef _SMSC9420_H
+#define _SMSC9420_H
+
+#define TX_RING_SIZE                   (32)
+#define RX_RING_SIZE                   (128)
+
+/* interrupt deassertion in multiples of 10us */
+#define INT_DEAS_TIME                  (50)
+
+#define NAPI_WEIGHT                    (64)
+#define SMSC_BAR                       (3)
+
+#ifdef __BIG_ENDIAN
+/* Register set is duplicated for BE at an offset of 0x200 */
+#define LAN9420_CPSR_ENDIAN_OFFSET     (0x200)
+#else
+#define LAN9420_CPSR_ENDIAN_OFFSET     (0)
+#endif
+
+#define PCI_VENDOR_ID_9420             (0x1055)
+#define PCI_DEVICE_ID_9420             (0xE420)
+
+#define LAN_REGISTER_EXTENT            (0x400)
+
+#define SMSC9420_EEPROM_SIZE           ((u32)11)
+#define SMSC9420_EEPROM_MAGIC          (0x9420)
+
+#define PKT_BUF_SZ                     (VLAN_ETH_FRAME_LEN + NET_IP_ALIGN + 4)
+
+/***********************************************/
+/* DMA Controller Control and Status Registers */
+/***********************************************/
+#define BUS_MODE                       (0x00)
+#define BUS_MODE_SWR_                  (BIT(0))
+#define BUS_MODE_DMA_BURST_LENGTH_1    (BIT(8))
+#define BUS_MODE_DMA_BURST_LENGTH_2    (BIT(9))
+#define BUS_MODE_DMA_BURST_LENGTH_4    (BIT(10))
+#define BUS_MODE_DMA_BURST_LENGTH_8    (BIT(11))
+#define BUS_MODE_DMA_BURST_LENGTH_16   (BIT(12))
+#define BUS_MODE_DMA_BURST_LENGTH_32   (BIT(13))
+#define BUS_MODE_DBO_                  (BIT(20))
+
+#define TX_POLL_DEMAND                 (0x04)
+
+#define RX_POLL_DEMAND                 (0x08)
+
+#define RX_BASE_ADDR                   (0x0C)
+
+#define TX_BASE_ADDR                   (0x10)
+
+#define DMAC_STATUS                    (0x14)
+#define DMAC_STS_TS_                   (7 << 20)
+#define DMAC_STS_RS_                   (7 << 17)
+#define DMAC_STS_NIS_                  (BIT(16))
+#define DMAC_STS_AIS_                  (BIT(15))
+#define DMAC_STS_RWT_                  (BIT(9))
+#define DMAC_STS_RXPS_                 (BIT(8))
+#define DMAC_STS_RXBU_                 (BIT(7))
+#define DMAC_STS_RX_                   (BIT(6))
+#define DMAC_STS_TXUNF_                        (BIT(5))
+#define DMAC_STS_TXBU_                 (BIT(2))
+#define DMAC_STS_TXPS_                 (BIT(1))
+#define DMAC_STS_TX_                   (BIT(0))
+
+#define DMAC_CONTROL                   (0x18)
+#define DMAC_CONTROL_TTM_              (BIT(22))
+#define DMAC_CONTROL_SF_               (BIT(21))
+#define DMAC_CONTROL_ST_               (BIT(13))
+#define DMAC_CONTROL_OSF_              (BIT(2))
+#define DMAC_CONTROL_SR_               (BIT(1))
+
+#define DMAC_INTR_ENA                  (0x1C)
+#define DMAC_INTR_ENA_NIS_             (BIT(16))
+#define DMAC_INTR_ENA_AIS_             (BIT(15))
+#define DMAC_INTR_ENA_RWT_             (BIT(9))
+#define DMAC_INTR_ENA_RXPS_            (BIT(8))
+#define DMAC_INTR_ENA_RXBU_            (BIT(7))
+#define DMAC_INTR_ENA_RX_              (BIT(6))
+#define DMAC_INTR_ENA_TXBU_            (BIT(2))
+#define DMAC_INTR_ENA_TXPS_            (BIT(1))
+#define DMAC_INTR_ENA_TX_              (BIT(0))
+
+#define MISS_FRAME_CNTR                        (0x20)
+
+#define TX_BUFF_ADDR                   (0x50)
+
+#define RX_BUFF_ADDR                   (0x54)
+
+/* Transmit Descriptor Bit Defs */
+#define TDES0_OWN_                     (0x80000000)
+#define TDES0_ERROR_SUMMARY_           (0x00008000)
+#define TDES0_LOSS_OF_CARRIER_         (0x00000800)
+#define TDES0_NO_CARRIER_              (0x00000400)
+#define TDES0_LATE_COLLISION_          (0x00000200)
+#define TDES0_EXCESSIVE_COLLISIONS_    (0x00000100)
+#define TDES0_HEARTBEAT_FAIL_          (0x00000080)
+#define TDES0_COLLISION_COUNT_MASK_    (0x00000078)
+#define TDES0_COLLISION_COUNT_SHFT_    (3)
+#define TDES0_EXCESSIVE_DEFERRAL_      (0x00000004)
+#define TDES0_DEFERRED_                        (0x00000001)
+
+#define TDES1_IC_                      0x80000000
+#define TDES1_LS_                      0x40000000
+#define TDES1_FS_                      0x20000000
+#define TDES1_TXCSEN_                  0x08000000
+#define TDES1_TER_                     (BIT(25))
+#define TDES1_TCH_                     0x01000000
+
+/* Receive Descriptor 0 Bit Defs */
+#define RDES0_OWN_                     (0x80000000)
+#define RDES0_FRAME_LENGTH_MASK_       (0x07FF0000)
+#define RDES0_FRAME_LENGTH_SHFT_       (16)
+#define RDES0_ERROR_SUMMARY_           (0x00008000)
+#define RDES0_DESCRIPTOR_ERROR_                (0x00004000)
+#define RDES0_LENGTH_ERROR_            (0x00001000)
+#define RDES0_RUNT_FRAME_              (0x00000800)
+#define RDES0_MULTICAST_FRAME_         (0x00000400)
+#define RDES0_FIRST_DESCRIPTOR_                (0x00000200)
+#define RDES0_LAST_DESCRIPTOR_         (0x00000100)
+#define RDES0_FRAME_TOO_LONG_          (0x00000080)
+#define RDES0_COLLISION_SEEN_          (0x00000040)
+#define RDES0_FRAME_TYPE_              (0x00000020)
+#define RDES0_WATCHDOG_TIMEOUT_                (0x00000010)
+#define RDES0_MII_ERROR_               (0x00000008)
+#define RDES0_DRIBBLING_BIT_           (0x00000004)
+#define RDES0_CRC_ERROR_               (0x00000002)
+
+/* Receive Descriptor 1 Bit Defs */
+#define RDES1_RER_                     (0x02000000)
+
+/***********************************************/
+/*       MAC Control and Status Registers      */
+/***********************************************/
+#define MAC_CR                         (0x80)
+#define MAC_CR_RXALL_                  (0x80000000)
+#define MAC_CR_DIS_RXOWN_              (0x00800000)
+#define MAC_CR_LOOPBK_                 (0x00200000)
+#define MAC_CR_FDPX_                   (0x00100000)
+#define MAC_CR_MCPAS_                  (0x00080000)
+#define MAC_CR_PRMS_                   (0x00040000)
+#define MAC_CR_INVFILT_                        (0x00020000)
+#define MAC_CR_PASSBAD_                        (0x00010000)
+#define MAC_CR_HFILT_                  (0x00008000)
+#define MAC_CR_HPFILT_                 (0x00002000)
+#define MAC_CR_LCOLL_                  (0x00001000)
+#define MAC_CR_DIS_BCAST_              (0x00000800)
+#define MAC_CR_DIS_RTRY_               (0x00000400)
+#define MAC_CR_PADSTR_                 (0x00000100)
+#define MAC_CR_BOLMT_MSK               (0x000000C0)
+#define MAC_CR_MFCHK_                  (0x00000020)
+#define MAC_CR_TXEN_                   (0x00000008)
+#define MAC_CR_RXEN_                   (0x00000004)
+
+#define ADDRH                          (0x84)
+
+#define ADDRL                          (0x88)
+
+#define HASHH                          (0x8C)
+
+#define HASHL                          (0x90)
+
+#define MII_ACCESS                     (0x94)
+#define MII_ACCESS_MII_BUSY_           (0x00000001)
+#define MII_ACCESS_MII_WRITE_          (0x00000002)
+#define MII_ACCESS_MII_READ_           (0x00000000)
+#define MII_ACCESS_INDX_MSK_           (0x000007C0)
+#define MII_ACCESS_PHYADDR_MSK_                (0x0000F8C0)
+#define MII_ACCESS_INDX_SHFT_CNT       (6)
+#define MII_ACCESS_PHYADDR_SHFT_CNT    (11)
+
+#define MII_DATA                       (0x98)
+
+#define FLOW                           (0x9C)
+
+#define VLAN1                          (0xA0)
+
+#define VLAN2                          (0xA4)
+
+#define WUFF                           (0xA8)
+
+#define WUCSR                          (0xAC)
+
+#define COE_CR                         (0xB0)
+#define TX_COE_EN                      (0x00010000)
+#define RX_COE_MODE                    (0x00000002)
+#define RX_COE_EN                      (0x00000001)
+
+/***********************************************/
+/*     System Control and Status Registers     */
+/***********************************************/
+#define ID_REV                         (0xC0)
+
+#define INT_CTL                                (0xC4)
+#define INT_CTL_SW_INT_EN_             (0x00008000)
+#define INT_CTL_SBERR_INT_EN_          (1 << 12)
+#define INT_CTL_MBERR_INT_EN_          (1 << 13)
+#define INT_CTL_GPT_INT_EN_            (0x00000008)
+#define INT_CTL_PHY_INT_EN_            (0x00000004)
+#define INT_CTL_WAKE_INT_EN_           (0x00000002)
+
+#define INT_STAT                       (0xC8)
+#define INT_STAT_SW_INT_               (1 << 15)
+#define INT_STAT_MBERR_INT_            (1 << 13)
+#define INT_STAT_SBERR_INT_            (1 << 12)
+#define INT_STAT_GPT_INT_              (1 << 3)
+#define INT_STAT_PHY_INT_              (0x00000004)
+#define INT_STAT_WAKE_INT_             (0x00000002)
+#define INT_STAT_DMAC_INT_             (0x00000001)
+
+#define INT_CFG                                (0xCC)
+#define INT_CFG_IRQ_INT_               (0x00080000)
+#define INT_CFG_IRQ_EN_                        (0x00040000)
+#define INT_CFG_INT_DEAS_CLR_          (0x00000200)
+#define INT_CFG_INT_DEAS_MASK          (0x000000FF)
+
+#define GPIO_CFG                       (0xD0)
+#define GPIO_CFG_LED_3_                        (0x40000000)
+#define GPIO_CFG_LED_2_                        (0x20000000)
+#define GPIO_CFG_LED_1_                        (0x10000000)
+#define GPIO_CFG_EEPR_EN_              (0x00700000)
+
+#define GPT_CFG                                (0xD4)
+#define GPT_CFG_TIMER_EN_              (0x20000000)
+
+#define GPT_CNT                                (0xD8)
+
+#define BUS_CFG                                (0xDC)
+#define BUS_CFG_RXTXWEIGHT_1_1         (0 << 25)
+#define BUS_CFG_RXTXWEIGHT_2_1         (1 << 25)
+#define BUS_CFG_RXTXWEIGHT_3_1         (2 << 25)
+#define BUS_CFG_RXTXWEIGHT_4_1         (3 << 25)
+
+#define PMT_CTRL                       (0xE0)
+
+#define FREE_RUN                       (0xF4)
+
+#define E2P_CMD                                (0xF8)
+#define E2P_CMD_EPC_BUSY_              (0x80000000)
+#define E2P_CMD_EPC_CMD_               (0x70000000)
+#define E2P_CMD_EPC_CMD_READ_          (0x00000000)
+#define E2P_CMD_EPC_CMD_EWDS_          (0x10000000)
+#define E2P_CMD_EPC_CMD_EWEN_          (0x20000000)
+#define E2P_CMD_EPC_CMD_WRITE_         (0x30000000)
+#define E2P_CMD_EPC_CMD_WRAL_          (0x40000000)
+#define E2P_CMD_EPC_CMD_ERASE_         (0x50000000)
+#define E2P_CMD_EPC_CMD_ERAL_          (0x60000000)
+#define E2P_CMD_EPC_CMD_RELOAD_                (0x70000000)
+#define E2P_CMD_EPC_TIMEOUT_           (0x00000200)
+#define E2P_CMD_MAC_ADDR_LOADED_       (0x00000100)
+#define E2P_CMD_EPC_ADDR_              (0x000000FF)
+
+#define E2P_DATA                       (0xFC)
+#define E2P_DATA_EEPROM_DATA_          (0x000000FF)
+
+#endif /* _SMSC9420_H */
index 72aa25786a95a4a9e83e67e72f53de60919ac0b0..f5a738ff59f57b22ab821e1dfa274d3e0685f7ff 100644 (file)
@@ -31,17 +31,6 @@ config PCMCIA_FMVJ18X
          To compile this driver as a module, choose M here: the module will be
          called fmvj18x_cs.  If unsure, say N.
 
-config PCMCIA_SMC91C92
-       tristate "SMC 91Cxx PCMCIA support"
-       select CRC32
-       select MII
-       help
-         Say Y here if you intend to attach an SMC 91Cxx compatible PCMCIA
-         (PC-card) Ethernet or Fast Ethernet card to your computer.
-
-         To compile this driver as a module, choose M here: the module will be
-         called smc91c92_cs.  If unsure, say N.
-
 config PCMCIA_XIRC2PS
        tristate "Xircom 16-bit PCMCIA support"
        help
index c2b8b44c7bb114f6ef599d7e9119bfa562c55836..f9c98836d75b5c734999f84ee9377b8eedfa8209 100644 (file)
@@ -4,7 +4,6 @@
 
 # 16-bit client drivers
 obj-$(CONFIG_PCMCIA_FMVJ18X)   += fmvj18x_cs.o
-obj-$(CONFIG_PCMCIA_SMC91C92)  += smc91c92_cs.o
 obj-$(CONFIG_PCMCIA_XIRC2PS)   += xirc2ps_cs.o
 obj-$(CONFIG_ARCNET_COM20020_CS)+= com20020_cs.o
 
diff --git a/drivers/net/pcmcia/smc91c92_cs.c b/drivers/net/pcmcia/smc91c92_cs.c
deleted file mode 100644 (file)
index cffbc03..0000000
+++ /dev/null
@@ -1,2070 +0,0 @@
-/*======================================================================
-
-    A PCMCIA ethernet driver for SMC91c92-based cards.
-
-    This driver supports Megahertz PCMCIA ethernet cards; and
-    Megahertz, Motorola, Ositech, and Psion Dacom ethernet/modem
-    multifunction cards.
-
-    Copyright (C) 1999 David A. Hinds -- dahinds@users.sourceforge.net
-
-    smc91c92_cs.c 1.122 2002/10/25 06:26:39
-
-    This driver contains code written by Donald Becker
-    (becker@scyld.com), Rowan Hughes (x-csrdh@jcu.edu.au),
-    David Hinds (dahinds@users.sourceforge.net), and Erik Stahlman
-    (erik@vt.edu).  Donald wrote the SMC 91c92 code using parts of
-    Erik's SMC 91c94 driver.  Rowan wrote a similar driver, and I've
-    incorporated some parts of his driver here.  I (Dave) wrote most
-    of the PCMCIA glue code, and the Ositech support code.  Kelly
-    Stephens (kstephen@holli.com) added support for the Motorola
-    Mariner, with help from Allen Brost.
-
-    This software may be used and distributed according to the terms of
-    the GNU General Public License, incorporated herein by reference.
-
-======================================================================*/
-
-#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
-
-#include <linux/module.h>
-#include <linux/kernel.h>
-#include <linux/init.h>
-#include <linux/slab.h>
-#include <linux/string.h>
-#include <linux/timer.h>
-#include <linux/interrupt.h>
-#include <linux/delay.h>
-#include <linux/crc32.h>
-#include <linux/netdevice.h>
-#include <linux/etherdevice.h>
-#include <linux/skbuff.h>
-#include <linux/if_arp.h>
-#include <linux/ioport.h>
-#include <linux/ethtool.h>
-#include <linux/mii.h>
-#include <linux/jiffies.h>
-#include <linux/firmware.h>
-
-#include <pcmcia/cistpl.h>
-#include <pcmcia/cisreg.h>
-#include <pcmcia/ciscode.h>
-#include <pcmcia/ds.h>
-#include <pcmcia/ss.h>
-
-#include <asm/io.h>
-#include <asm/system.h>
-#include <asm/uaccess.h>
-
-/*====================================================================*/
-
-static const char *if_names[] = { "auto", "10baseT", "10base2"};
-
-/* Firmware name */
-#define FIRMWARE_NAME          "ositech/Xilinx7OD.bin"
-
-/* Module parameters */
-
-MODULE_DESCRIPTION("SMC 91c92 series PCMCIA ethernet driver");
-MODULE_LICENSE("GPL");
-MODULE_FIRMWARE(FIRMWARE_NAME);
-
-#define INT_MODULE_PARM(n, v) static int n = v; module_param(n, int, 0)
-
-/*
-  Transceiver/media type.
-   0 = auto
-   1 = 10baseT (and autoselect if #define AUTOSELECT),
-   2 = AUI/10base2,
-*/
-INT_MODULE_PARM(if_port, 0);
-
-
-#define DRV_NAME       "smc91c92_cs"
-#define DRV_VERSION    "1.123"
-
-/*====================================================================*/
-
-/* Operational parameter that usually are not changed. */
-
-/* Time in jiffies before concluding Tx hung */
-#define TX_TIMEOUT             ((400*HZ)/1000)
-
-/* Maximum events (Rx packets, etc.) to handle at each interrupt. */
-#define INTR_WORK              4
-
-/* Times to check the check the chip before concluding that it doesn't
-   currently have room for another Tx packet. */
-#define MEMORY_WAIT_TIME               8
-
-struct smc_private {
-       struct pcmcia_device    *p_dev;
-    spinlock_t                 lock;
-    u_short                    manfid;
-    u_short                    cardid;
-
-    struct sk_buff             *saved_skb;
-    int                                packets_waiting;
-    void                       __iomem *base;
-    u_short                    cfg;
-    struct timer_list          media;
-    int                                watchdog, tx_err;
-    u_short                    media_status;
-    u_short                    fast_poll;
-    u_short                    link_status;
-    struct mii_if_info         mii_if;
-    int                                duplex;
-    int                                rx_ovrn;
-};
-
-/* Special definitions for Megahertz multifunction cards */
-#define MEGAHERTZ_ISR          0x0380
-
-/* Special function registers for Motorola Mariner */
-#define MOT_LAN                        0x0000
-#define MOT_UART               0x0020
-#define MOT_EEPROM             0x20
-
-#define MOT_NORMAL \
-(COR_LEVEL_REQ | COR_FUNC_ENA | COR_ADDR_DECODE | COR_IREQ_ENA)
-
-/* Special function registers for Ositech cards */
-#define OSITECH_AUI_CTL                0x0c
-#define OSITECH_PWRDOWN                0x0d
-#define OSITECH_RESET          0x0e
-#define OSITECH_ISR            0x0f
-#define OSITECH_AUI_PWR                0x0c
-#define OSITECH_RESET_ISR      0x0e
-
-#define OSI_AUI_PWR            0x40
-#define OSI_LAN_PWRDOWN                0x02
-#define OSI_MODEM_PWRDOWN      0x01
-#define OSI_LAN_RESET          0x02
-#define OSI_MODEM_RESET                0x01
-
-/* Symbolic constants for the SMC91c9* series chips, from Erik Stahlman. */
-#define        BANK_SELECT             14              /* Window select register. */
-#define SMC_SELECT_BANK(x)  { outw(x, ioaddr + BANK_SELECT); }
-
-/* Bank 0 registers. */
-#define        TCR             0       /* transmit control register */
-#define         TCR_CLEAR      0       /* do NOTHING */
-#define  TCR_ENABLE    0x0001  /* if this is 1, we can transmit */
-#define         TCR_PAD_EN     0x0080  /* pads short packets to 64 bytes */
-#define  TCR_MONCSN    0x0400  /* Monitor Carrier. */
-#define  TCR_FDUPLX    0x0800  /* Full duplex mode. */
-#define         TCR_NORMAL TCR_ENABLE | TCR_PAD_EN
-
-#define EPH            2       /* Ethernet Protocol Handler report. */
-#define  EPH_TX_SUC    0x0001
-#define  EPH_SNGLCOL   0x0002
-#define  EPH_MULCOL    0x0004
-#define  EPH_LTX_MULT  0x0008
-#define  EPH_16COL     0x0010
-#define  EPH_SQET      0x0020
-#define  EPH_LTX_BRD   0x0040
-#define  EPH_TX_DEFR   0x0080
-#define  EPH_LAT_COL   0x0200
-#define  EPH_LOST_CAR  0x0400
-#define  EPH_EXC_DEF   0x0800
-#define  EPH_CTR_ROL   0x1000
-#define  EPH_RX_OVRN   0x2000
-#define  EPH_LINK_OK   0x4000
-#define  EPH_TX_UNRN   0x8000
-#define MEMINFO                8       /* Memory Information Register */
-#define MEMCFG         10      /* Memory Configuration Register */
-
-/* Bank 1 registers. */
-#define CONFIG                 0
-#define  CFG_MII_SELECT                0x8000  /* 91C100 only */
-#define  CFG_NO_WAIT           0x1000
-#define  CFG_FULL_STEP         0x0400
-#define  CFG_SET_SQLCH         0x0200
-#define  CFG_AUI_SELECT                0x0100
-#define  CFG_16BIT             0x0080
-#define  CFG_DIS_LINK          0x0040
-#define  CFG_STATIC            0x0030
-#define  CFG_IRQ_SEL_1         0x0004
-#define  CFG_IRQ_SEL_0         0x0002
-#define BASE_ADDR              2
-#define        ADDR0                   4
-#define        GENERAL                 10
-#define        CONTROL                 12
-#define  CTL_STORE             0x0001
-#define  CTL_RELOAD            0x0002
-#define  CTL_EE_SELECT         0x0004
-#define  CTL_TE_ENABLE         0x0020
-#define  CTL_CR_ENABLE         0x0040
-#define  CTL_LE_ENABLE         0x0080
-#define  CTL_AUTO_RELEASE      0x0800
-#define         CTL_POWERDOWN          0x2000
-
-/* Bank 2 registers. */
-#define MMU_CMD                0
-#define         MC_ALLOC       0x20    /* or with number of 256 byte packets */
-#define         MC_RESET       0x40
-#define  MC_RELEASE    0x80    /* remove and release the current rx packet */
-#define  MC_FREEPKT    0xA0    /* Release packet in PNR register */
-#define  MC_ENQUEUE    0xC0    /* Enqueue the packet for transmit */
-#define        PNR_ARR         2
-#define FIFO_PORTS     4
-#define  FP_RXEMPTY    0x8000
-#define        POINTER         6
-#define  PTR_AUTO_INC  0x0040
-#define  PTR_READ      0x2000
-#define         PTR_AUTOINC    0x4000
-#define         PTR_RCV        0x8000
-#define        DATA_1          8
-#define        INTERRUPT       12
-#define  IM_RCV_INT            0x1
-#define         IM_TX_INT              0x2
-#define         IM_TX_EMPTY_INT        0x4
-#define         IM_ALLOC_INT           0x8
-#define         IM_RX_OVRN_INT         0x10
-#define         IM_EPH_INT             0x20
-
-#define        RCR             4
-enum RxCfg { RxAllMulti = 0x0004, RxPromisc = 0x0002,
-            RxEnable = 0x0100, RxStripCRC = 0x0200};
-#define  RCR_SOFTRESET 0x8000  /* resets the chip */
-#define         RCR_STRIP_CRC  0x200   /* strips CRC */
-#define  RCR_ENABLE    0x100   /* IFF this is set, we can receive packets */
-#define  RCR_ALMUL     0x4     /* receive all multicast packets */
-#define         RCR_PROMISC    0x2     /* enable promiscuous mode */
-
-/* the normal settings for the RCR register : */
-#define         RCR_NORMAL     (RCR_STRIP_CRC | RCR_ENABLE)
-#define  RCR_CLEAR     0x0             /* set it to a base state */
-#define        COUNTER         6
-
-/* BANK 3 -- not the same values as in smc9194! */
-#define        MULTICAST0      0
-#define        MULTICAST2      2
-#define        MULTICAST4      4
-#define        MULTICAST6      6
-#define MGMT           8
-#define REVISION       0x0a
-
-/* Transmit status bits. */
-#define TS_SUCCESS 0x0001
-#define TS_16COL   0x0010
-#define TS_LATCOL  0x0200
-#define TS_LOSTCAR 0x0400
-
-/* Receive status bits. */
-#define RS_ALGNERR     0x8000
-#define RS_BADCRC      0x2000
-#define RS_ODDFRAME    0x1000
-#define RS_TOOLONG     0x0800
-#define RS_TOOSHORT    0x0400
-#define RS_MULTICAST   0x0001
-#define RS_ERRORS      (RS_ALGNERR | RS_BADCRC | RS_TOOLONG | RS_TOOSHORT)
-
-#define set_bits(v, p) outw(inw(p)|(v), (p))
-#define mask_bits(v, p) outw(inw(p)&(v), (p))
-
-/*====================================================================*/
-
-static void smc91c92_detach(struct pcmcia_device *p_dev);
-static int smc91c92_config(struct pcmcia_device *link);
-static void smc91c92_release(struct pcmcia_device *link);
-
-static int smc_open(struct net_device *dev);
-static int smc_close(struct net_device *dev);
-static int smc_ioctl(struct net_device *dev, struct ifreq *rq, int cmd);
-static void smc_tx_timeout(struct net_device *dev);
-static netdev_tx_t smc_start_xmit(struct sk_buff *skb,
-                                       struct net_device *dev);
-static irqreturn_t smc_interrupt(int irq, void *dev_id);
-static void smc_rx(struct net_device *dev);
-static void set_rx_mode(struct net_device *dev);
-static int s9k_config(struct net_device *dev, struct ifmap *map);
-static void smc_set_xcvr(struct net_device *dev, int if_port);
-static void smc_reset(struct net_device *dev);
-static void media_check(u_long arg);
-static void mdio_sync(unsigned int addr);
-static int mdio_read(struct net_device *dev, int phy_id, int loc);
-static void mdio_write(struct net_device *dev, int phy_id, int loc, int value);
-static int smc_link_ok(struct net_device *dev);
-static const struct ethtool_ops ethtool_ops;
-
-static const struct net_device_ops smc_netdev_ops = {
-       .ndo_open               = smc_open,
-       .ndo_stop               = smc_close,
-       .ndo_start_xmit         = smc_start_xmit,
-       .ndo_tx_timeout         = smc_tx_timeout,
-       .ndo_set_config         = s9k_config,
-       .ndo_set_multicast_list = set_rx_mode,
-       .ndo_do_ioctl           = smc_ioctl,
-       .ndo_change_mtu         = eth_change_mtu,
-       .ndo_set_mac_address    = eth_mac_addr,
-       .ndo_validate_addr      = eth_validate_addr,
-};
-
-static int smc91c92_probe(struct pcmcia_device *link)
-{
-    struct smc_private *smc;
-    struct net_device *dev;
-
-    dev_dbg(&link->dev, "smc91c92_attach()\n");
-
-    /* Create new ethernet device */
-    dev = alloc_etherdev(sizeof(struct smc_private));
-    if (!dev)
-       return -ENOMEM;
-    smc = netdev_priv(dev);
-    smc->p_dev = link;
-    link->priv = dev;
-
-    spin_lock_init(&smc->lock);
-
-    /* The SMC91c92-specific entries in the device structure. */
-    dev->netdev_ops = &smc_netdev_ops;
-    SET_ETHTOOL_OPS(dev, &ethtool_ops);
-    dev->watchdog_timeo = TX_TIMEOUT;
-
-    smc->mii_if.dev = dev;
-    smc->mii_if.mdio_read = mdio_read;
-    smc->mii_if.mdio_write = mdio_write;
-    smc->mii_if.phy_id_mask = 0x1f;
-    smc->mii_if.reg_num_mask = 0x1f;
-
-    return smc91c92_config(link);
-} /* smc91c92_attach */
-
-static void smc91c92_detach(struct pcmcia_device *link)
-{
-    struct net_device *dev = link->priv;
-
-    dev_dbg(&link->dev, "smc91c92_detach\n");
-
-    unregister_netdev(dev);
-
-    smc91c92_release(link);
-
-    free_netdev(dev);
-} /* smc91c92_detach */
-
-/*====================================================================*/
-
-static int cvt_ascii_address(struct net_device *dev, char *s)
-{
-    int i, j, da, c;
-
-    if (strlen(s) != 12)
-       return -1;
-    for (i = 0; i < 6; i++) {
-       da = 0;
-       for (j = 0; j < 2; j++) {
-           c = *s++;
-           da <<= 4;
-           da += ((c >= '0') && (c <= '9')) ?
-               (c - '0') : ((c & 0x0f) + 9);
-       }
-       dev->dev_addr[i] = da;
-    }
-    return 0;
-}
-
-/*====================================================================
-
-    Configuration stuff for Megahertz cards
-
-    mhz_3288_power() is used to power up a 3288's ethernet chip.
-    mhz_mfc_config() handles socket setup for multifunction (1144
-    and 3288) cards.  mhz_setup() gets a card's hardware ethernet
-    address.
-
-======================================================================*/
-
-static int mhz_3288_power(struct pcmcia_device *link)
-{
-    struct net_device *dev = link->priv;
-    struct smc_private *smc = netdev_priv(dev);
-    u_char tmp;
-
-    /* Read the ISR twice... */
-    readb(smc->base+MEGAHERTZ_ISR);
-    udelay(5);
-    readb(smc->base+MEGAHERTZ_ISR);
-
-    /* Pause 200ms... */
-    mdelay(200);
-
-    /* Now read and write the COR... */
-    tmp = readb(smc->base + link->config_base + CISREG_COR);
-    udelay(5);
-    writeb(tmp, smc->base + link->config_base + CISREG_COR);
-
-    return 0;
-}
-
-static int mhz_mfc_config_check(struct pcmcia_device *p_dev, void *priv_data)
-{
-       int k;
-       p_dev->io_lines = 16;
-       p_dev->resource[1]->start = p_dev->resource[0]->start;
-       p_dev->resource[1]->end = 8;
-       p_dev->resource[1]->flags &= ~IO_DATA_PATH_WIDTH;
-       p_dev->resource[1]->flags |= IO_DATA_PATH_WIDTH_8;
-       p_dev->resource[0]->end = 16;
-       p_dev->resource[0]->flags &= ~IO_DATA_PATH_WIDTH;
-       p_dev->resource[0]->flags |= IO_DATA_PATH_WIDTH_AUTO;
-       for (k = 0; k < 0x400; k += 0x10) {
-               if (k & 0x80)
-                       continue;
-               p_dev->resource[0]->start = k ^ 0x300;
-               if (!pcmcia_request_io(p_dev))
-                       return 0;
-       }
-       return -ENODEV;
-}
-
-static int mhz_mfc_config(struct pcmcia_device *link)
-{
-    struct net_device *dev = link->priv;
-    struct smc_private *smc = netdev_priv(dev);
-    unsigned int offset;
-    int i;
-
-    link->config_flags |= CONF_ENABLE_SPKR | CONF_ENABLE_IRQ |
-           CONF_AUTO_SET_IO;
-
-    /* The Megahertz combo cards have modem-like CIS entries, so
-       we have to explicitly try a bunch of port combinations. */
-    if (pcmcia_loop_config(link, mhz_mfc_config_check, NULL))
-           return -ENODEV;
-
-    dev->base_addr = link->resource[0]->start;
-
-    /* Allocate a memory window, for accessing the ISR */
-    link->resource[2]->flags = WIN_DATA_WIDTH_8|WIN_MEMORY_TYPE_AM|WIN_ENABLE;
-    link->resource[2]->start = link->resource[2]->end = 0;
-    i = pcmcia_request_window(link, link->resource[2], 0);
-    if (i != 0)
-           return -ENODEV;
-
-    smc->base = ioremap(link->resource[2]->start,
-                   resource_size(link->resource[2]));
-    offset = (smc->manfid == MANFID_MOTOROLA) ? link->config_base : 0;
-    i = pcmcia_map_mem_page(link, link->resource[2], offset);
-    if ((i == 0) &&
-       (smc->manfid == MANFID_MEGAHERTZ) &&
-       (smc->cardid == PRODID_MEGAHERTZ_EM3288))
-           mhz_3288_power(link);
-
-    return 0;
-}
-
-static int pcmcia_get_versmac(struct pcmcia_device *p_dev,
-                             tuple_t *tuple,
-                             void *priv)
-{
-       struct net_device *dev = priv;
-       cisparse_t parse;
-       u8 *buf;
-
-       if (pcmcia_parse_tuple(tuple, &parse))
-               return -EINVAL;
-
-       buf = parse.version_1.str + parse.version_1.ofs[3];
-
-       if ((parse.version_1.ns > 3) && (cvt_ascii_address(dev, buf) == 0))
-               return 0;
-
-       return -EINVAL;
-};
-
-static int mhz_setup(struct pcmcia_device *link)
-{
-    struct net_device *dev = link->priv;
-    size_t len;
-    u8 *buf;
-    int rc;
-
-    /* Read the station address from the CIS.  It is stored as the last
-       (fourth) string in the Version 1 Version/ID tuple. */
-    if ((link->prod_id[3]) &&
-       (cvt_ascii_address(dev, link->prod_id[3]) == 0))
-           return 0;
-
-    /* Workarounds for broken cards start here. */
-    /* Ugh -- the EM1144 card has two VERS_1 tuples!?! */
-    if (!pcmcia_loop_tuple(link, CISTPL_VERS_1, pcmcia_get_versmac, dev))
-           return 0;
-
-    /* Another possibility: for the EM3288, in a special tuple */
-    rc = -1;
-    len = pcmcia_get_tuple(link, 0x81, &buf);
-    if (buf && len >= 13) {
-           buf[12] = '\0';
-           if (cvt_ascii_address(dev, buf) == 0)
-                   rc = 0;
-    }
-    kfree(buf);
-
-    return rc;
-};
-
-/*======================================================================
-
-    Configuration stuff for the Motorola Mariner
-
-    mot_config() writes directly to the Mariner configuration
-    registers because the CIS is just bogus.
-
-======================================================================*/
-
-static void mot_config(struct pcmcia_device *link)
-{
-    struct net_device *dev = link->priv;
-    struct smc_private *smc = netdev_priv(dev);
-    unsigned int ioaddr = dev->base_addr;
-    unsigned int iouart = link->resource[1]->start;
-
-    /* Set UART base address and force map with COR bit 1 */
-    writeb(iouart & 0xff,        smc->base + MOT_UART + CISREG_IOBASE_0);
-    writeb((iouart >> 8) & 0xff, smc->base + MOT_UART + CISREG_IOBASE_1);
-    writeb(MOT_NORMAL,           smc->base + MOT_UART + CISREG_COR);
-
-    /* Set SMC base address and force map with COR bit 1 */
-    writeb(ioaddr & 0xff,        smc->base + MOT_LAN + CISREG_IOBASE_0);
-    writeb((ioaddr >> 8) & 0xff, smc->base + MOT_LAN + CISREG_IOBASE_1);
-    writeb(MOT_NORMAL,           smc->base + MOT_LAN + CISREG_COR);
-
-    /* Wait for things to settle down */
-    mdelay(100);
-}
-
-static int mot_setup(struct pcmcia_device *link)
-{
-    struct net_device *dev = link->priv;
-    unsigned int ioaddr = dev->base_addr;
-    int i, wait, loop;
-    u_int addr;
-
-    /* Read Ethernet address from Serial EEPROM */
-
-    for (i = 0; i < 3; i++) {
-       SMC_SELECT_BANK(2);
-       outw(MOT_EEPROM + i, ioaddr + POINTER);
-       SMC_SELECT_BANK(1);
-       outw((CTL_RELOAD | CTL_EE_SELECT), ioaddr + CONTROL);
-
-       for (loop = wait = 0; loop < 200; loop++) {
-           udelay(10);
-           wait = ((CTL_RELOAD | CTL_STORE) & inw(ioaddr + CONTROL));
-           if (wait == 0) break;
-       }
-       
-       if (wait)
-           return -1;
-       
-       addr = inw(ioaddr + GENERAL);
-       dev->dev_addr[2*i]   = addr & 0xff;
-       dev->dev_addr[2*i+1] = (addr >> 8) & 0xff;
-    }
-
-    return 0;
-}
-
-/*====================================================================*/
-
-static int smc_configcheck(struct pcmcia_device *p_dev, void *priv_data)
-{
-       p_dev->resource[0]->end = 16;
-       p_dev->resource[0]->flags &= ~IO_DATA_PATH_WIDTH;
-       p_dev->resource[0]->flags |= IO_DATA_PATH_WIDTH_AUTO;
-
-       return pcmcia_request_io(p_dev);
-}
-
-static int smc_config(struct pcmcia_device *link)
-{
-    struct net_device *dev = link->priv;
-    int i;
-
-    link->config_flags |= CONF_ENABLE_IRQ | CONF_AUTO_SET_IO;
-
-    i = pcmcia_loop_config(link, smc_configcheck, NULL);
-    if (!i)
-           dev->base_addr = link->resource[0]->start;
-
-    return i;
-}
-
-
-static int smc_setup(struct pcmcia_device *link)
-{
-    struct net_device *dev = link->priv;
-
-    /* Check for a LAN function extension tuple */
-    if (!pcmcia_get_mac_from_cis(link, dev))
-           return 0;
-
-    /* Try the third string in the Version 1 Version/ID tuple. */
-    if (link->prod_id[2]) {
-           if (cvt_ascii_address(dev, link->prod_id[2]) == 0)
-                   return 0;
-    }
-    return -1;
-}
-
-/*====================================================================*/
-
-static int osi_config(struct pcmcia_device *link)
-{
-    struct net_device *dev = link->priv;
-    static const unsigned int com[4] = { 0x3f8, 0x2f8, 0x3e8, 0x2e8 };
-    int i, j;
-
-    link->config_flags |= CONF_ENABLE_SPKR | CONF_ENABLE_IRQ;
-    link->resource[0]->end = 64;
-    link->resource[1]->flags |= IO_DATA_PATH_WIDTH_8;
-    link->resource[1]->end = 8;
-
-    /* Enable Hard Decode, LAN, Modem */
-    link->io_lines = 16;
-    link->config_index = 0x23;
-
-    for (i = j = 0; j < 4; j++) {
-       link->resource[1]->start = com[j];
-       i = pcmcia_request_io(link);
-       if (i == 0)
-               break;
-    }
-    if (i != 0) {
-       /* Fallback: turn off hard decode */
-       link->config_index = 0x03;
-       link->resource[1]->end = 0;
-       i = pcmcia_request_io(link);
-    }
-    dev->base_addr = link->resource[0]->start + 0x10;
-    return i;
-}
-
-static int osi_load_firmware(struct pcmcia_device *link)
-{
-       const struct firmware *fw;
-       int i, err;
-
-       err = request_firmware(&fw, FIRMWARE_NAME, &link->dev);
-       if (err) {
-               pr_err("Failed to load firmware \"%s\"\n", FIRMWARE_NAME);
-               return err;
-       }
-
-       /* Download the Seven of Diamonds firmware */
-       for (i = 0; i < fw->size; i++) {
-           outb(fw->data[i], link->resource[0]->start + 2);
-           udelay(50);
-       }
-       release_firmware(fw);
-       return err;
-}
-
-static int pcmcia_osi_mac(struct pcmcia_device *p_dev,
-                         tuple_t *tuple,
-                         void *priv)
-{
-       struct net_device *dev = priv;
-       int i;
-
-       if (tuple->TupleDataLen < 8)
-               return -EINVAL;
-       if (tuple->TupleData[0] != 0x04)
-               return -EINVAL;
-       for (i = 0; i < 6; i++)
-               dev->dev_addr[i] = tuple->TupleData[i+2];
-       return 0;
-};
-
-
-static int osi_setup(struct pcmcia_device *link, u_short manfid, u_short cardid)
-{
-    struct net_device *dev = link->priv;
-    int rc;
-
-    /* Read the station address from tuple 0x90, subtuple 0x04 */
-    if (pcmcia_loop_tuple(link, 0x90, pcmcia_osi_mac, dev))
-           return -1;
-
-    if (((manfid == MANFID_OSITECH) &&
-        (cardid == PRODID_OSITECH_SEVEN)) ||
-       ((manfid == MANFID_PSION) &&
-        (cardid == PRODID_PSION_NET100))) {
-       rc = osi_load_firmware(link);
-       if (rc)
-               return rc;
-    } else if (manfid == MANFID_OSITECH) {
-       /* Make sure both functions are powered up */
-       set_bits(0x300, link->resource[0]->start + OSITECH_AUI_PWR);
-       /* Now, turn on the interrupt for both card functions */
-       set_bits(0x300, link->resource[0]->start + OSITECH_RESET_ISR);
-       dev_dbg(&link->dev, "AUI/PWR: %4.4x RESET/ISR: %4.4x\n",
-             inw(link->resource[0]->start + OSITECH_AUI_PWR),
-             inw(link->resource[0]->start + OSITECH_RESET_ISR));
-    }
-    return 0;
-}
-
-static int smc91c92_suspend(struct pcmcia_device *link)
-{
-       struct net_device *dev = link->priv;
-
-       if (link->open)
-               netif_device_detach(dev);
-
-       return 0;
-}
-
-static int smc91c92_resume(struct pcmcia_device *link)
-{
-       struct net_device *dev = link->priv;
-       struct smc_private *smc = netdev_priv(dev);
-       int i;
-
-       if ((smc->manfid == MANFID_MEGAHERTZ) &&
-           (smc->cardid == PRODID_MEGAHERTZ_EM3288))
-               mhz_3288_power(link);
-       if (smc->manfid == MANFID_MOTOROLA)
-               mot_config(link);
-       if ((smc->manfid == MANFID_OSITECH) &&
-           (smc->cardid != PRODID_OSITECH_SEVEN)) {
-               /* Power up the card and enable interrupts */
-               set_bits(0x0300, dev->base_addr-0x10+OSITECH_AUI_PWR);
-               set_bits(0x0300, dev->base_addr-0x10+OSITECH_RESET_ISR);
-       }
-       if (((smc->manfid == MANFID_OSITECH) &&
-            (smc->cardid == PRODID_OSITECH_SEVEN)) ||
-           ((smc->manfid == MANFID_PSION) &&
-            (smc->cardid == PRODID_PSION_NET100))) {
-               i = osi_load_firmware(link);
-               if (i) {
-                       pr_err("smc91c92_cs: Failed to load firmware\n");
-                       return i;
-               }
-       }
-       if (link->open) {
-               smc_reset(dev);
-               netif_device_attach(dev);
-       }
-
-       return 0;
-}
-
-
-/*======================================================================
-
-    This verifies that the chip is some SMC91cXX variant, and returns
-    the revision code if successful.  Otherwise, it returns -ENODEV.
-
-======================================================================*/
-
-static int check_sig(struct pcmcia_device *link)
-{
-    struct net_device *dev = link->priv;
-    unsigned int ioaddr = dev->base_addr;
-    int width;
-    u_short s;
-
-    SMC_SELECT_BANK(1);
-    if (inw(ioaddr + BANK_SELECT) >> 8 != 0x33) {
-       /* Try powering up the chip */
-       outw(0, ioaddr + CONTROL);
-       mdelay(55);
-    }
-
-    /* Try setting bus width */
-    width = (link->resource[0]->flags == IO_DATA_PATH_WIDTH_AUTO);
-    s = inb(ioaddr + CONFIG);
-    if (width)
-       s |= CFG_16BIT;
-    else
-       s &= ~CFG_16BIT;
-    outb(s, ioaddr + CONFIG);
-
-    /* Check Base Address Register to make sure bus width is OK */
-    s = inw(ioaddr + BASE_ADDR);
-    if ((inw(ioaddr + BANK_SELECT) >> 8 == 0x33) &&
-       ((s >> 8) != (s & 0xff))) {
-       SMC_SELECT_BANK(3);
-       s = inw(ioaddr + REVISION);
-       return s & 0xff;
-    }
-
-    if (width) {
-           pr_info("using 8-bit IO window\n");
-
-           smc91c92_suspend(link);
-           pcmcia_fixup_iowidth(link);
-           smc91c92_resume(link);
-           return check_sig(link);
-    }
-    return -ENODEV;
-}
-
-static int smc91c92_config(struct pcmcia_device *link)
-{
-    struct net_device *dev = link->priv;
-    struct smc_private *smc = netdev_priv(dev);
-    char *name;
-    int i, rev, j = 0;
-    unsigned int ioaddr;
-    u_long mir;
-
-    dev_dbg(&link->dev, "smc91c92_config\n");
-
-    smc->manfid = link->manf_id;
-    smc->cardid = link->card_id;
-
-    if ((smc->manfid == MANFID_OSITECH) &&
-       (smc->cardid != PRODID_OSITECH_SEVEN)) {
-       i = osi_config(link);
-    } else if ((smc->manfid == MANFID_MOTOROLA) ||
-              ((smc->manfid == MANFID_MEGAHERTZ) &&
-               ((smc->cardid == PRODID_MEGAHERTZ_VARIOUS) ||
-                (smc->cardid == PRODID_MEGAHERTZ_EM3288)))) {
-       i = mhz_mfc_config(link);
-    } else {
-       i = smc_config(link);
-    }
-    if (i)
-           goto config_failed;
-
-    i = pcmcia_request_irq(link, smc_interrupt);
-    if (i)
-           goto config_failed;
-    i = pcmcia_enable_device(link);
-    if (i)
-           goto config_failed;
-
-    if (smc->manfid == MANFID_MOTOROLA)
-       mot_config(link);
-
-    dev->irq = link->irq;
-
-    if ((if_port >= 0) && (if_port <= 2))
-       dev->if_port = if_port;
-    else
-       dev_notice(&link->dev, "invalid if_port requested\n");
-
-    switch (smc->manfid) {
-    case MANFID_OSITECH:
-    case MANFID_PSION:
-       i = osi_setup(link, smc->manfid, smc->cardid); break;
-    case MANFID_SMC:
-    case MANFID_NEW_MEDIA:
-       i = smc_setup(link); break;
-    case 0x128: /* For broken Megahertz cards */
-    case MANFID_MEGAHERTZ:
-       i = mhz_setup(link); break;
-    case MANFID_MOTOROLA:
-    default: /* get the hw address from EEPROM */
-       i = mot_setup(link); break;
-    }
-
-    if (i != 0) {
-       dev_notice(&link->dev, "Unable to find hardware address.\n");
-       goto config_failed;
-    }
-
-    smc->duplex = 0;
-    smc->rx_ovrn = 0;
-
-    rev = check_sig(link);
-    name = "???";
-    if (rev > 0)
-       switch (rev >> 4) {
-       case 3: name = "92"; break;
-       case 4: name = ((rev & 15) >= 6) ? "96" : "94"; break;
-       case 5: name = "95"; break;
-       case 7: name = "100"; break;
-       case 8: name = "100-FD"; break;
-       case 9: name = "110"; break;
-       }
-
-    ioaddr = dev->base_addr;
-    if (rev > 0) {
-       u_long mcr;
-       SMC_SELECT_BANK(0);
-       mir = inw(ioaddr + MEMINFO) & 0xff;
-       if (mir == 0xff) mir++;
-       /* Get scale factor for memory size */
-       mcr = ((rev >> 4) > 3) ? inw(ioaddr + MEMCFG) : 0x0200;
-       mir *= 128 * (1<<((mcr >> 9) & 7));
-       SMC_SELECT_BANK(1);
-       smc->cfg = inw(ioaddr + CONFIG) & ~CFG_AUI_SELECT;
-       smc->cfg |= CFG_NO_WAIT | CFG_16BIT | CFG_STATIC;
-       if (smc->manfid == MANFID_OSITECH)
-           smc->cfg |= CFG_IRQ_SEL_1 | CFG_IRQ_SEL_0;
-       if ((rev >> 4) >= 7)
-           smc->cfg |= CFG_MII_SELECT;
-    } else
-       mir = 0;
-
-    if (smc->cfg & CFG_MII_SELECT) {
-       SMC_SELECT_BANK(3);
-
-       for (i = 0; i < 32; i++) {
-           j = mdio_read(dev, i, 1);
-           if ((j != 0) && (j != 0xffff)) break;
-       }
-       smc->mii_if.phy_id = (i < 32) ? i : -1;
-
-       SMC_SELECT_BANK(0);
-    }
-
-    SET_NETDEV_DEV(dev, &link->dev);
-
-    if (register_netdev(dev) != 0) {
-       dev_err(&link->dev, "register_netdev() failed\n");
-       goto config_undo;
-    }
-
-    netdev_info(dev, "smc91c%s rev %d: io %#3lx, irq %d, hw_addr %pM\n",
-               name, (rev & 0x0f), dev->base_addr, dev->irq, dev->dev_addr);
-
-    if (rev > 0) {
-       if (mir & 0x3ff)
-           netdev_info(dev, "  %lu byte", mir);
-       else
-           netdev_info(dev, "  %lu kb", mir>>10);
-       pr_cont(" buffer, %s xcvr\n",
-               (smc->cfg & CFG_MII_SELECT) ? "MII" : if_names[dev->if_port]);
-    }
-
-    if (smc->cfg & CFG_MII_SELECT) {
-       if (smc->mii_if.phy_id != -1) {
-           netdev_dbg(dev, "  MII transceiver at index %d, status %x\n",
-                      smc->mii_if.phy_id, j);
-       } else {
-           netdev_notice(dev, "  No MII transceivers found!\n");
-       }
-    }
-    return 0;
-
-config_undo:
-    unregister_netdev(dev);
-config_failed:
-    smc91c92_release(link);
-    free_netdev(dev);
-    return -ENODEV;
-} /* smc91c92_config */
-
-static void smc91c92_release(struct pcmcia_device *link)
-{
-       dev_dbg(&link->dev, "smc91c92_release\n");
-       if (link->resource[2]->end) {
-               struct net_device *dev = link->priv;
-               struct smc_private *smc = netdev_priv(dev);
-               iounmap(smc->base);
-       }
-       pcmcia_disable_device(link);
-}
-
-/*======================================================================
-
-    MII interface support for SMC91cXX based cards
-======================================================================*/
-
-#define MDIO_SHIFT_CLK         0x04
-#define MDIO_DATA_OUT          0x01
-#define MDIO_DIR_WRITE         0x08
-#define MDIO_DATA_WRITE0       (MDIO_DIR_WRITE)
-#define MDIO_DATA_WRITE1       (MDIO_DIR_WRITE | MDIO_DATA_OUT)
-#define MDIO_DATA_READ         0x02
-
-static void mdio_sync(unsigned int addr)
-{
-    int bits;
-    for (bits = 0; bits < 32; bits++) {
-       outb(MDIO_DATA_WRITE1, addr);
-       outb(MDIO_DATA_WRITE1 | MDIO_SHIFT_CLK, addr);
-    }
-}
-
-static int mdio_read(struct net_device *dev, int phy_id, int loc)
-{
-    unsigned int addr = dev->base_addr + MGMT;
-    u_int cmd = (0x06<<10)|(phy_id<<5)|loc;
-    int i, retval = 0;
-
-    mdio_sync(addr);
-    for (i = 13; i >= 0; i--) {
-       int dat = (cmd&(1<<i)) ? MDIO_DATA_WRITE1 : MDIO_DATA_WRITE0;
-       outb(dat, addr);
-       outb(dat | MDIO_SHIFT_CLK, addr);
-    }
-    for (i = 19; i > 0; i--) {
-       outb(0, addr);
-       retval = (retval << 1) | ((inb(addr) & MDIO_DATA_READ) != 0);
-       outb(MDIO_SHIFT_CLK, addr);
-    }
-    return (retval>>1) & 0xffff;
-}
-
-static void mdio_write(struct net_device *dev, int phy_id, int loc, int value)
-{
-    unsigned int addr = dev->base_addr + MGMT;
-    u_int cmd = (0x05<<28)|(phy_id<<23)|(loc<<18)|(1<<17)|value;
-    int i;
-
-    mdio_sync(addr);
-    for (i = 31; i >= 0; i--) {
-       int dat = (cmd&(1<<i)) ? MDIO_DATA_WRITE1 : MDIO_DATA_WRITE0;
-       outb(dat, addr);
-       outb(dat | MDIO_SHIFT_CLK, addr);
-    }
-    for (i = 1; i >= 0; i--) {
-       outb(0, addr);
-       outb(MDIO_SHIFT_CLK, addr);
-    }
-}
-
-/*======================================================================
-
-    The driver core code, most of which should be common with a
-    non-PCMCIA implementation.
-
-======================================================================*/
-
-#ifdef PCMCIA_DEBUG
-static void smc_dump(struct net_device *dev)
-{
-    unsigned int ioaddr = dev->base_addr;
-    u_short i, w, save;
-    save = inw(ioaddr + BANK_SELECT);
-    for (w = 0; w < 4; w++) {
-       SMC_SELECT_BANK(w);
-       netdev_printk(KERN_DEBUG, dev, "bank %d: ", w);
-       for (i = 0; i < 14; i += 2)
-           pr_cont(" %04x", inw(ioaddr + i));
-       pr_cont("\n");
-    }
-    outw(save, ioaddr + BANK_SELECT);
-}
-#endif
-
-static int smc_open(struct net_device *dev)
-{
-    struct smc_private *smc = netdev_priv(dev);
-    struct pcmcia_device *link = smc->p_dev;
-
-    dev_dbg(&link->dev, "%s: smc_open(%p), ID/Window %4.4x.\n",
-         dev->name, dev, inw(dev->base_addr + BANK_SELECT));
-#ifdef PCMCIA_DEBUG
-    smc_dump(dev);
-#endif
-
-    /* Check that the PCMCIA card is still here. */
-    if (!pcmcia_dev_present(link))
-       return -ENODEV;
-    /* Physical device present signature. */
-    if (check_sig(link) < 0) {
-       netdev_info(dev, "Yikes!  Bad chip signature!\n");
-       return -ENODEV;
-    }
-    link->open++;
-
-    netif_start_queue(dev);
-    smc->saved_skb = NULL;
-    smc->packets_waiting = 0;
-
-    smc_reset(dev);
-    init_timer(&smc->media);
-    smc->media.function = media_check;
-    smc->media.data = (u_long) dev;
-    smc->media.expires = jiffies + HZ;
-    add_timer(&smc->media);
-
-    return 0;
-} /* smc_open */
-
-/*====================================================================*/
-
-static int smc_close(struct net_device *dev)
-{
-    struct smc_private *smc = netdev_priv(dev);
-    struct pcmcia_device *link = smc->p_dev;
-    unsigned int ioaddr = dev->base_addr;
-
-    dev_dbg(&link->dev, "%s: smc_close(), status %4.4x.\n",
-         dev->name, inw(ioaddr + BANK_SELECT));
-
-    netif_stop_queue(dev);
-
-    /* Shut off all interrupts, and turn off the Tx and Rx sections.
-       Don't bother to check for chip present. */
-    SMC_SELECT_BANK(2);        /* Nominally paranoia, but do no assume... */
-    outw(0, ioaddr + INTERRUPT);
-    SMC_SELECT_BANK(0);
-    mask_bits(0xff00, ioaddr + RCR);
-    mask_bits(0xff00, ioaddr + TCR);
-
-    /* Put the chip into power-down mode. */
-    SMC_SELECT_BANK(1);
-    outw(CTL_POWERDOWN, ioaddr + CONTROL );
-
-    link->open--;
-    del_timer_sync(&smc->media);
-
-    return 0;
-} /* smc_close */
-
-/*======================================================================
-
-   Transfer a packet to the hardware and trigger the packet send.
-   This may be called at either from either the Tx queue code
-   or the interrupt handler.
-
-======================================================================*/
-
-static void smc_hardware_send_packet(struct net_device * dev)
-{
-    struct smc_private *smc = netdev_priv(dev);
-    struct sk_buff *skb = smc->saved_skb;
-    unsigned int ioaddr = dev->base_addr;
-    u_char packet_no;
-
-    if (!skb) {
-       netdev_err(dev, "In XMIT with no packet to send\n");
-       return;
-    }
-
-    /* There should be a packet slot waiting. */
-    packet_no = inw(ioaddr + PNR_ARR) >> 8;
-    if (packet_no & 0x80) {
-       /* If not, there is a hardware problem!  Likely an ejected card. */
-       netdev_warn(dev, "hardware Tx buffer allocation failed, status %#2.2x\n",
-                   packet_no);
-       dev_kfree_skb_irq(skb);
-       smc->saved_skb = NULL;
-       netif_start_queue(dev);
-       return;
-    }
-
-    dev->stats.tx_bytes += skb->len;
-    /* The card should use the just-allocated buffer. */
-    outw(packet_no, ioaddr + PNR_ARR);
-    /* point to the beginning of the packet */
-    outw(PTR_AUTOINC , ioaddr + POINTER);
-
-    /* Send the packet length (+6 for status, length and ctl byte)
-       and the status word (set to zeros). */
-    {
-       u_char *buf = skb->data;
-       u_int length = skb->len; /* The chip will pad to ethernet min. */
-
-       netdev_dbg(dev, "Trying to xmit packet of length %d\n", length);
-       
-       /* send the packet length: +6 for status word, length, and ctl */
-       outw(0, ioaddr + DATA_1);
-       outw(length + 6, ioaddr + DATA_1);
-       outsw(ioaddr + DATA_1, buf, length >> 1);
-       
-       /* The odd last byte, if there is one, goes in the control word. */
-       outw((length & 1) ? 0x2000 | buf[length-1] : 0, ioaddr + DATA_1);
-    }
-
-    /* Enable the Tx interrupts, both Tx (TxErr) and TxEmpty. */
-    outw(((IM_TX_INT|IM_TX_EMPTY_INT)<<8) |
-        (inw(ioaddr + INTERRUPT) & 0xff00),
-        ioaddr + INTERRUPT);
-
-    /* The chip does the rest of the work. */
-    outw(MC_ENQUEUE , ioaddr + MMU_CMD);
-
-    smc->saved_skb = NULL;
-    dev_kfree_skb_irq(skb);
-    dev->trans_start = jiffies;
-    netif_start_queue(dev);
-}
-
-/*====================================================================*/
-
-static void smc_tx_timeout(struct net_device *dev)
-{
-    struct smc_private *smc = netdev_priv(dev);
-    unsigned int ioaddr = dev->base_addr;
-
-    netdev_notice(dev, "transmit timed out, Tx_status %2.2x status %4.4x.\n",
-                 inw(ioaddr)&0xff, inw(ioaddr + 2));
-    dev->stats.tx_errors++;
-    smc_reset(dev);
-    dev->trans_start = jiffies; /* prevent tx timeout */
-    smc->saved_skb = NULL;
-    netif_wake_queue(dev);
-}
-
-static netdev_tx_t smc_start_xmit(struct sk_buff *skb,
-                                       struct net_device *dev)
-{
-    struct smc_private *smc = netdev_priv(dev);
-    unsigned int ioaddr = dev->base_addr;
-    u_short num_pages;
-    short time_out, ir;
-    unsigned long flags;
-
-    netif_stop_queue(dev);
-
-    netdev_dbg(dev, "smc_start_xmit(length = %d) called, status %04x\n",
-              skb->len, inw(ioaddr + 2));
-
-    if (smc->saved_skb) {
-       /* THIS SHOULD NEVER HAPPEN. */
-       dev->stats.tx_aborted_errors++;
-       netdev_printk(KERN_DEBUG, dev,
-                     "Internal error -- sent packet while busy\n");
-       return NETDEV_TX_BUSY;
-    }
-    smc->saved_skb = skb;
-
-    num_pages = skb->len >> 8;
-
-    if (num_pages > 7) {
-       netdev_err(dev, "Far too big packet error: %d pages\n", num_pages);
-       dev_kfree_skb (skb);
-       smc->saved_skb = NULL;
-       dev->stats.tx_dropped++;
-       return NETDEV_TX_OK;            /* Do not re-queue this packet. */
-    }
-    /* A packet is now waiting. */
-    smc->packets_waiting++;
-
-    spin_lock_irqsave(&smc->lock, flags);
-    SMC_SELECT_BANK(2);        /* Paranoia, we should always be in window 2 */
-
-    /* need MC_RESET to keep the memory consistent. errata? */
-    if (smc->rx_ovrn) {
-       outw(MC_RESET, ioaddr + MMU_CMD);
-       smc->rx_ovrn = 0;
-    }
-
-    /* Allocate the memory; send the packet now if we win. */
-    outw(MC_ALLOC | num_pages, ioaddr + MMU_CMD);
-    for (time_out = MEMORY_WAIT_TIME; time_out >= 0; time_out--) {
-       ir = inw(ioaddr+INTERRUPT);
-       if (ir & IM_ALLOC_INT) {
-           /* Acknowledge the interrupt, send the packet. */
-           outw((ir&0xff00) | IM_ALLOC_INT, ioaddr + INTERRUPT);
-           smc_hardware_send_packet(dev);      /* Send the packet now.. */
-           spin_unlock_irqrestore(&smc->lock, flags);
-           return NETDEV_TX_OK;
-       }
-    }
-
-    /* Otherwise defer until the Tx-space-allocated interrupt. */
-    pr_debug("%s: memory allocation deferred.\n", dev->name);
-    outw((IM_ALLOC_INT << 8) | (ir & 0xff00), ioaddr + INTERRUPT);
-    spin_unlock_irqrestore(&smc->lock, flags);
-
-    return NETDEV_TX_OK;
-}
-
-/*======================================================================
-
-    Handle a Tx anomalous event.  Entered while in Window 2.
-
-======================================================================*/
-
-static void smc_tx_err(struct net_device * dev)
-{
-    struct smc_private *smc = netdev_priv(dev);
-    unsigned int ioaddr = dev->base_addr;
-    int saved_packet = inw(ioaddr + PNR_ARR) & 0xff;
-    int packet_no = inw(ioaddr + FIFO_PORTS) & 0x7f;
-    int tx_status;
-
-    /* select this as the packet to read from */
-    outw(packet_no, ioaddr + PNR_ARR);
-
-    /* read the first word from this packet */
-    outw(PTR_AUTOINC | PTR_READ | 0, ioaddr + POINTER);
-
-    tx_status = inw(ioaddr + DATA_1);
-
-    dev->stats.tx_errors++;
-    if (tx_status & TS_LOSTCAR) dev->stats.tx_carrier_errors++;
-    if (tx_status & TS_LATCOL)  dev->stats.tx_window_errors++;
-    if (tx_status & TS_16COL) {
-       dev->stats.tx_aborted_errors++;
-       smc->tx_err++;
-    }
-
-    if (tx_status & TS_SUCCESS) {
-       netdev_notice(dev, "Successful packet caused error interrupt?\n");
-    }
-    /* re-enable transmit */
-    SMC_SELECT_BANK(0);
-    outw(inw(ioaddr + TCR) | TCR_ENABLE | smc->duplex, ioaddr + TCR);
-    SMC_SELECT_BANK(2);
-
-    outw(MC_FREEPKT, ioaddr + MMU_CMD);        /* Free the packet memory. */
-
-    /* one less packet waiting for me */
-    smc->packets_waiting--;
-
-    outw(saved_packet, ioaddr + PNR_ARR);
-}
-
-/*====================================================================*/
-
-static void smc_eph_irq(struct net_device *dev)
-{
-    struct smc_private *smc = netdev_priv(dev);
-    unsigned int ioaddr = dev->base_addr;
-    u_short card_stats, ephs;
-
-    SMC_SELECT_BANK(0);
-    ephs = inw(ioaddr + EPH);
-    pr_debug("%s: Ethernet protocol handler interrupt, status"
-         " %4.4x.\n", dev->name, ephs);
-    /* Could be a counter roll-over warning: update stats. */
-    card_stats = inw(ioaddr + COUNTER);
-    /* single collisions */
-    dev->stats.collisions += card_stats & 0xF;
-    card_stats >>= 4;
-    /* multiple collisions */
-    dev->stats.collisions += card_stats & 0xF;
-#if 0          /* These are for when linux supports these statistics */
-    card_stats >>= 4;                  /* deferred */
-    card_stats >>= 4;                  /* excess deferred */
-#endif
-    /* If we had a transmit error we must re-enable the transmitter. */
-    outw(inw(ioaddr + TCR) | TCR_ENABLE | smc->duplex, ioaddr + TCR);
-
-    /* Clear a link error interrupt. */
-    SMC_SELECT_BANK(1);
-    outw(CTL_AUTO_RELEASE | 0x0000, ioaddr + CONTROL);
-    outw(CTL_AUTO_RELEASE | CTL_TE_ENABLE | CTL_CR_ENABLE,
-        ioaddr + CONTROL);
-    SMC_SELECT_BANK(2);
-}
-
-/*====================================================================*/
-
-static irqreturn_t smc_interrupt(int irq, void *dev_id)
-{
-    struct net_device *dev = dev_id;
-    struct smc_private *smc = netdev_priv(dev);
-    unsigned int ioaddr;
-    u_short saved_bank, saved_pointer, mask, status;
-    unsigned int handled = 1;
-    char bogus_cnt = INTR_WORK;                /* Work we are willing to do. */
-
-    if (!netif_device_present(dev))
-       return IRQ_NONE;
-
-    ioaddr = dev->base_addr;
-
-    pr_debug("%s: SMC91c92 interrupt %d at %#x.\n", dev->name,
-         irq, ioaddr);
-
-    spin_lock(&smc->lock);
-    smc->watchdog = 0;
-    saved_bank = inw(ioaddr + BANK_SELECT);
-    if ((saved_bank & 0xff00) != 0x3300) {
-       /* The device does not exist -- the card could be off-line, or
-          maybe it has been ejected. */
-       pr_debug("%s: SMC91c92 interrupt %d for non-existent"
-             "/ejected device.\n", dev->name, irq);
-       handled = 0;
-       goto irq_done;
-    }
-
-    SMC_SELECT_BANK(2);
-    saved_pointer = inw(ioaddr + POINTER);
-    mask = inw(ioaddr + INTERRUPT) >> 8;
-    /* clear all interrupts */
-    outw(0, ioaddr + INTERRUPT);
-
-    do { /* read the status flag, and mask it */
-       status = inw(ioaddr + INTERRUPT) & 0xff;
-       pr_debug("%s: Status is %#2.2x (mask %#2.2x).\n", dev->name,
-             status, mask);
-       if ((status & mask) == 0) {
-           if (bogus_cnt == INTR_WORK)
-               handled = 0;
-           break;
-       }
-       if (status & IM_RCV_INT) {
-           /* Got a packet(s). */
-           smc_rx(dev);
-       }
-       if (status & IM_TX_INT) {
-           smc_tx_err(dev);
-           outw(IM_TX_INT, ioaddr + INTERRUPT);
-       }
-       status &= mask;
-       if (status & IM_TX_EMPTY_INT) {
-           outw(IM_TX_EMPTY_INT, ioaddr + INTERRUPT);
-           mask &= ~IM_TX_EMPTY_INT;
-           dev->stats.tx_packets += smc->packets_waiting;
-           smc->packets_waiting = 0;
-       }
-       if (status & IM_ALLOC_INT) {
-           /* Clear this interrupt so it doesn't happen again */
-           mask &= ~IM_ALLOC_INT;
-       
-           smc_hardware_send_packet(dev);
-       
-           /* enable xmit interrupts based on this */
-           mask |= (IM_TX_EMPTY_INT | IM_TX_INT);
-       
-           /* and let the card send more packets to me */
-           netif_wake_queue(dev);
-       }
-       if (status & IM_RX_OVRN_INT) {
-           dev->stats.rx_errors++;
-           dev->stats.rx_fifo_errors++;
-           if (smc->duplex)
-               smc->rx_ovrn = 1; /* need MC_RESET outside smc_interrupt */
-           outw(IM_RX_OVRN_INT, ioaddr + INTERRUPT);
-       }
-       if (status & IM_EPH_INT)
-           smc_eph_irq(dev);
-    } while (--bogus_cnt);
-
-    pr_debug("  Restoring saved registers mask %2.2x bank %4.4x"
-         " pointer %4.4x.\n", mask, saved_bank, saved_pointer);
-
-    /* restore state register */
-    outw((mask<<8), ioaddr + INTERRUPT);
-    outw(saved_pointer, ioaddr + POINTER);
-    SMC_SELECT_BANK(saved_bank);
-
-    pr_debug("%s: Exiting interrupt IRQ%d.\n", dev->name, irq);
-
-irq_done:
-
-    if ((smc->manfid == MANFID_OSITECH) &&
-       (smc->cardid != PRODID_OSITECH_SEVEN)) {
-       /* Retrigger interrupt if needed */
-       mask_bits(0x00ff, ioaddr-0x10+OSITECH_RESET_ISR);
-       set_bits(0x0300, ioaddr-0x10+OSITECH_RESET_ISR);
-    }
-    if (smc->manfid == MANFID_MOTOROLA) {
-       u_char cor;
-       cor = readb(smc->base + MOT_UART + CISREG_COR);
-       writeb(cor & ~COR_IREQ_ENA, smc->base + MOT_UART + CISREG_COR);
-       writeb(cor, smc->base + MOT_UART + CISREG_COR);
-       cor = readb(smc->base + MOT_LAN + CISREG_COR);
-       writeb(cor & ~COR_IREQ_ENA, smc->base + MOT_LAN + CISREG_COR);
-       writeb(cor, smc->base + MOT_LAN + CISREG_COR);
-    }
-
-    if ((smc->base != NULL) &&  /* Megahertz MFC's */
-       (smc->manfid == MANFID_MEGAHERTZ) &&
-       (smc->cardid == PRODID_MEGAHERTZ_EM3288)) {
-
-       u_char tmp;
-       tmp = readb(smc->base+MEGAHERTZ_ISR);
-       tmp = readb(smc->base+MEGAHERTZ_ISR);
-
-       /* Retrigger interrupt if needed */
-       writeb(tmp, smc->base + MEGAHERTZ_ISR);
-       writeb(tmp, smc->base + MEGAHERTZ_ISR);
-    }
-
-    spin_unlock(&smc->lock);
-    return IRQ_RETVAL(handled);
-}
-
-/*====================================================================*/
-
-static void smc_rx(struct net_device *dev)
-{
-    unsigned int ioaddr = dev->base_addr;
-    int rx_status;
-    int packet_length; /* Caution: not frame length, rather words
-                          to transfer from the chip. */
-
-    /* Assertion: we are in Window 2. */
-
-    if (inw(ioaddr + FIFO_PORTS) & FP_RXEMPTY) {
-       netdev_err(dev, "smc_rx() with nothing on Rx FIFO\n");
-       return;
-    }
-
-    /*  Reset the read pointer, and read the status and packet length. */
-    outw(PTR_READ | PTR_RCV | PTR_AUTOINC, ioaddr + POINTER);
-    rx_status = inw(ioaddr + DATA_1);
-    packet_length = inw(ioaddr + DATA_1) & 0x07ff;
-
-    pr_debug("%s: Receive status %4.4x length %d.\n",
-         dev->name, rx_status, packet_length);
-
-    if (!(rx_status & RS_ERRORS)) {            
-       /* do stuff to make a new packet */
-       struct sk_buff *skb;
-       
-       /* Note: packet_length adds 5 or 6 extra bytes here! */
-       skb = dev_alloc_skb(packet_length+2);
-       
-       if (skb == NULL) {
-           pr_debug("%s: Low memory, packet dropped.\n", dev->name);
-           dev->stats.rx_dropped++;
-           outw(MC_RELEASE, ioaddr + MMU_CMD);
-           return;
-       }
-       
-       packet_length -= (rx_status & RS_ODDFRAME ? 5 : 6);
-       skb_reserve(skb, 2);
-       insw(ioaddr+DATA_1, skb_put(skb, packet_length),
-            (packet_length+1)>>1);
-       skb->protocol = eth_type_trans(skb, dev);
-       
-       netif_rx(skb);
-       dev->last_rx = jiffies;
-       dev->stats.rx_packets++;
-       dev->stats.rx_bytes += packet_length;
-       if (rx_status & RS_MULTICAST)
-           dev->stats.multicast++;
-    } else {
-       /* error ... */
-       dev->stats.rx_errors++;
-       
-       if (rx_status & RS_ALGNERR)  dev->stats.rx_frame_errors++;
-       if (rx_status & (RS_TOOSHORT | RS_TOOLONG))
-           dev->stats.rx_length_errors++;
-       if (rx_status & RS_BADCRC)      dev->stats.rx_crc_errors++;
-    }
-    /* Let the MMU free the memory of this packet. */
-    outw(MC_RELEASE, ioaddr + MMU_CMD);
-}
-
-/*======================================================================
-
-    Set the receive mode.
-
-    This routine is used by both the protocol level to notify us of
-    promiscuous/multicast mode changes, and by the open/reset code to
-    initialize the Rx registers.  We always set the multicast list and
-    leave the receiver running.
-
-======================================================================*/
-
-static void set_rx_mode(struct net_device *dev)
-{
-    unsigned int ioaddr = dev->base_addr;
-    struct smc_private *smc = netdev_priv(dev);
-    unsigned char multicast_table[8];
-    unsigned long flags;
-    u_short rx_cfg_setting;
-    int i;
-
-    memset(multicast_table, 0, sizeof(multicast_table));
-
-    if (dev->flags & IFF_PROMISC) {
-       rx_cfg_setting = RxStripCRC | RxEnable | RxPromisc | RxAllMulti;
-    } else if (dev->flags & IFF_ALLMULTI)
-       rx_cfg_setting = RxStripCRC | RxEnable | RxAllMulti;
-    else {
-       if (!netdev_mc_empty(dev)) {
-           struct netdev_hw_addr *ha;
-
-           netdev_for_each_mc_addr(ha, dev) {
-               u_int position = ether_crc(6, ha->addr);
-               multicast_table[position >> 29] |= 1 << ((position >> 26) & 7);
-           }
-       }
-       rx_cfg_setting = RxStripCRC | RxEnable;
-    }
-
-    /* Load MC table and Rx setting into the chip without interrupts. */
-    spin_lock_irqsave(&smc->lock, flags);
-    SMC_SELECT_BANK(3);
-    for (i = 0; i < 8; i++)
-       outb(multicast_table[i], ioaddr + MULTICAST0 + i);
-    SMC_SELECT_BANK(0);
-    outw(rx_cfg_setting, ioaddr + RCR);
-    SMC_SELECT_BANK(2);
-    spin_unlock_irqrestore(&smc->lock, flags);
-}
-
-/*======================================================================
-
-    Senses when a card's config changes. Here, it's coax or TP.
-
-======================================================================*/
-
-static int s9k_config(struct net_device *dev, struct ifmap *map)
-{
-    struct smc_private *smc = netdev_priv(dev);
-    if ((map->port != (u_char)(-1)) && (map->port != dev->if_port)) {
-       if (smc->cfg & CFG_MII_SELECT)
-           return -EOPNOTSUPP;
-       else if (map->port > 2)
-           return -EINVAL;
-       dev->if_port = map->port;
-       netdev_info(dev, "switched to %s port\n", if_names[dev->if_port]);
-       smc_reset(dev);
-    }
-    return 0;
-}
-
-/*======================================================================
-
-    Reset the chip, reloading every register that might be corrupted.
-
-======================================================================*/
-
-/*
-  Set transceiver type, perhaps to something other than what the user
-  specified in dev->if_port.
-*/
-static void smc_set_xcvr(struct net_device *dev, int if_port)
-{
-    struct smc_private *smc = netdev_priv(dev);
-    unsigned int ioaddr = dev->base_addr;
-    u_short saved_bank;
-
-    saved_bank = inw(ioaddr + BANK_SELECT);
-    SMC_SELECT_BANK(1);
-    if (if_port == 2) {
-       outw(smc->cfg | CFG_AUI_SELECT, ioaddr + CONFIG);
-       if ((smc->manfid == MANFID_OSITECH) &&
-           (smc->cardid != PRODID_OSITECH_SEVEN))
-           set_bits(OSI_AUI_PWR, ioaddr - 0x10 + OSITECH_AUI_PWR);
-       smc->media_status = ((dev->if_port == 0) ? 0x0001 : 0x0002);
-    } else {
-       outw(smc->cfg, ioaddr + CONFIG);
-       if ((smc->manfid == MANFID_OSITECH) &&
-           (smc->cardid != PRODID_OSITECH_SEVEN))
-           mask_bits(~OSI_AUI_PWR, ioaddr - 0x10 + OSITECH_AUI_PWR);
-       smc->media_status = ((dev->if_port == 0) ? 0x0012 : 0x4001);
-    }
-    SMC_SELECT_BANK(saved_bank);
-}
-
-static void smc_reset(struct net_device *dev)
-{
-    unsigned int ioaddr = dev->base_addr;
-    struct smc_private *smc = netdev_priv(dev);
-    int i;
-
-    pr_debug("%s: smc91c92 reset called.\n", dev->name);
-
-    /* The first interaction must be a write to bring the chip out
-       of sleep mode. */
-    SMC_SELECT_BANK(0);
-    /* Reset the chip. */
-    outw(RCR_SOFTRESET, ioaddr + RCR);
-    udelay(10);
-
-    /* Clear the transmit and receive configuration registers. */
-    outw(RCR_CLEAR, ioaddr + RCR);
-    outw(TCR_CLEAR, ioaddr + TCR);
-
-    /* Set the Window 1 control, configuration and station addr registers.
-       No point in writing the I/O base register ;-> */
-    SMC_SELECT_BANK(1);
-    /* Automatically release successfully transmitted packets,
-       Accept link errors, counter and Tx error interrupts. */
-    outw(CTL_AUTO_RELEASE | CTL_TE_ENABLE | CTL_CR_ENABLE,
-        ioaddr + CONTROL);
-    smc_set_xcvr(dev, dev->if_port);
-    if ((smc->manfid == MANFID_OSITECH) &&
-       (smc->cardid != PRODID_OSITECH_SEVEN))
-       outw((dev->if_port == 2 ? OSI_AUI_PWR : 0) |
-            (inw(ioaddr-0x10+OSITECH_AUI_PWR) & 0xff00),
-            ioaddr - 0x10 + OSITECH_AUI_PWR);
-
-    /* Fill in the physical address.  The databook is wrong about the order! */
-    for (i = 0; i < 6; i += 2)
-       outw((dev->dev_addr[i+1]<<8)+dev->dev_addr[i],
-            ioaddr + ADDR0 + i);
-
-    /* Reset the MMU */
-    SMC_SELECT_BANK(2);
-    outw(MC_RESET, ioaddr + MMU_CMD);
-    outw(0, ioaddr + INTERRUPT);
-
-    /* Re-enable the chip. */
-    SMC_SELECT_BANK(0);
-    outw(((smc->cfg & CFG_MII_SELECT) ? 0 : TCR_MONCSN) |
-        TCR_ENABLE | TCR_PAD_EN | smc->duplex, ioaddr + TCR);
-    set_rx_mode(dev);
-
-    if (smc->cfg & CFG_MII_SELECT) {
-       SMC_SELECT_BANK(3);
-
-       /* Reset MII */
-       mdio_write(dev, smc->mii_if.phy_id, 0, 0x8000);
-
-       /* Advertise 100F, 100H, 10F, 10H */
-       mdio_write(dev, smc->mii_if.phy_id, 4, 0x01e1);
-
-       /* Restart MII autonegotiation */
-       mdio_write(dev, smc->mii_if.phy_id, 0, 0x0000);
-       mdio_write(dev, smc->mii_if.phy_id, 0, 0x1200);
-    }
-
-    /* Enable interrupts. */
-    SMC_SELECT_BANK(2);
-    outw((IM_EPH_INT | IM_RX_OVRN_INT | IM_RCV_INT) << 8,
-        ioaddr + INTERRUPT);
-}
-
-/*======================================================================
-
-    Media selection timer routine
-
-======================================================================*/
-
-static void media_check(u_long arg)
-{
-    struct net_device *dev = (struct net_device *) arg;
-    struct smc_private *smc = netdev_priv(dev);
-    unsigned int ioaddr = dev->base_addr;
-    u_short i, media, saved_bank;
-    u_short link;
-    unsigned long flags;
-
-    spin_lock_irqsave(&smc->lock, flags);
-
-    saved_bank = inw(ioaddr + BANK_SELECT);
-
-    if (!netif_device_present(dev))
-       goto reschedule;
-
-    SMC_SELECT_BANK(2);
-
-    /* need MC_RESET to keep the memory consistent. errata? */
-    if (smc->rx_ovrn) {
-       outw(MC_RESET, ioaddr + MMU_CMD);
-       smc->rx_ovrn = 0;
-    }
-    i = inw(ioaddr + INTERRUPT);
-    SMC_SELECT_BANK(0);
-    media = inw(ioaddr + EPH) & EPH_LINK_OK;
-    SMC_SELECT_BANK(1);
-    media |= (inw(ioaddr + CONFIG) & CFG_AUI_SELECT) ? 2 : 1;
-
-    SMC_SELECT_BANK(saved_bank);
-    spin_unlock_irqrestore(&smc->lock, flags);
-
-    /* Check for pending interrupt with watchdog flag set: with
-       this, we can limp along even if the interrupt is blocked */
-    if (smc->watchdog++ && ((i>>8) & i)) {
-       if (!smc->fast_poll)
-           netdev_info(dev, "interrupt(s) dropped!\n");
-       local_irq_save(flags);
-       smc_interrupt(dev->irq, dev);
-       local_irq_restore(flags);
-       smc->fast_poll = HZ;
-    }
-    if (smc->fast_poll) {
-       smc->fast_poll--;
-       smc->media.expires = jiffies + HZ/100;
-       add_timer(&smc->media);
-       return;
-    }
-
-    spin_lock_irqsave(&smc->lock, flags);
-
-    saved_bank = inw(ioaddr + BANK_SELECT);
-
-    if (smc->cfg & CFG_MII_SELECT) {
-       if (smc->mii_if.phy_id < 0)
-           goto reschedule;
-
-       SMC_SELECT_BANK(3);
-       link = mdio_read(dev, smc->mii_if.phy_id, 1);
-       if (!link || (link == 0xffff)) {
-           netdev_info(dev, "MII is missing!\n");
-           smc->mii_if.phy_id = -1;
-           goto reschedule;
-       }
-
-       link &= 0x0004;
-       if (link != smc->link_status) {
-           u_short p = mdio_read(dev, smc->mii_if.phy_id, 5);
-           netdev_info(dev, "%s link beat\n", link ? "found" : "lost");
-           smc->duplex = (((p & 0x0100) || ((p & 0x1c0) == 0x40))
-                          ? TCR_FDUPLX : 0);
-           if (link) {
-               netdev_info(dev, "autonegotiation complete: "
-                           "%dbaseT-%cD selected\n",
-                           (p & 0x0180) ? 100 : 10, smc->duplex ? 'F' : 'H');
-           }
-           SMC_SELECT_BANK(0);
-           outw(inw(ioaddr + TCR) | smc->duplex, ioaddr + TCR);
-           smc->link_status = link;
-       }
-       goto reschedule;
-    }
-
-    /* Ignore collisions unless we've had no rx's recently */
-    if (time_after(jiffies, dev->last_rx + HZ)) {
-       if (smc->tx_err || (smc->media_status & EPH_16COL))
-           media |= EPH_16COL;
-    }
-    smc->tx_err = 0;
-
-    if (media != smc->media_status) {
-       if ((media & smc->media_status & 1) &&
-           ((smc->media_status ^ media) & EPH_LINK_OK))
-           netdev_info(dev, "%s link beat\n",
-                       smc->media_status & EPH_LINK_OK ? "lost" : "found");
-       else if ((media & smc->media_status & 2) &&
-                ((smc->media_status ^ media) & EPH_16COL))
-           netdev_info(dev, "coax cable %s\n",
-                       media & EPH_16COL ? "problem" : "ok");
-       if (dev->if_port == 0) {
-           if (media & 1) {
-               if (media & EPH_LINK_OK)
-                   netdev_info(dev, "flipped to 10baseT\n");
-               else
-                   smc_set_xcvr(dev, 2);
-           } else {
-               if (media & EPH_16COL)
-                   smc_set_xcvr(dev, 1);
-               else
-                   netdev_info(dev, "flipped to 10base2\n");
-           }
-       }
-       smc->media_status = media;
-    }
-
-reschedule:
-    smc->media.expires = jiffies + HZ;
-    add_timer(&smc->media);
-    SMC_SELECT_BANK(saved_bank);
-    spin_unlock_irqrestore(&smc->lock, flags);
-}
-
-static int smc_link_ok(struct net_device *dev)
-{
-    unsigned int ioaddr = dev->base_addr;
-    struct smc_private *smc = netdev_priv(dev);
-
-    if (smc->cfg & CFG_MII_SELECT) {
-       return mii_link_ok(&smc->mii_if);
-    } else {
-        SMC_SELECT_BANK(0);
-       return inw(ioaddr + EPH) & EPH_LINK_OK;
-    }
-}
-
-static int smc_netdev_get_ecmd(struct net_device *dev, struct ethtool_cmd *ecmd)
-{
-    u16 tmp;
-    unsigned int ioaddr = dev->base_addr;
-
-    ecmd->supported = (SUPPORTED_TP | SUPPORTED_AUI |
-       SUPPORTED_10baseT_Half | SUPPORTED_10baseT_Full);
-               
-    SMC_SELECT_BANK(1);
-    tmp = inw(ioaddr + CONFIG);
-    ecmd->port = (tmp & CFG_AUI_SELECT) ? PORT_AUI : PORT_TP;
-    ecmd->transceiver = XCVR_INTERNAL;
-    ethtool_cmd_speed_set(ecmd, SPEED_10);
-    ecmd->phy_address = ioaddr + MGMT;
-
-    SMC_SELECT_BANK(0);
-    tmp = inw(ioaddr + TCR);
-    ecmd->duplex = (tmp & TCR_FDUPLX) ? DUPLEX_FULL : DUPLEX_HALF;
-
-    return 0;
-}
-
-static int smc_netdev_set_ecmd(struct net_device *dev, struct ethtool_cmd *ecmd)
-{
-    u16 tmp;
-    unsigned int ioaddr = dev->base_addr;
-
-    if (ethtool_cmd_speed(ecmd) != SPEED_10)
-       return -EINVAL;
-    if (ecmd->duplex != DUPLEX_HALF && ecmd->duplex != DUPLEX_FULL)
-       return -EINVAL;
-    if (ecmd->port != PORT_TP && ecmd->port != PORT_AUI)
-       return -EINVAL;
-    if (ecmd->transceiver != XCVR_INTERNAL)
-       return -EINVAL;
-
-    if (ecmd->port == PORT_AUI)
-       smc_set_xcvr(dev, 1);
-    else
-       smc_set_xcvr(dev, 0);
-
-    SMC_SELECT_BANK(0);
-    tmp = inw(ioaddr + TCR);
-    if (ecmd->duplex == DUPLEX_FULL)
-       tmp |= TCR_FDUPLX;
-    else
-       tmp &= ~TCR_FDUPLX;
-    outw(tmp, ioaddr + TCR);
-       
-    return 0;
-}
-
-static int check_if_running(struct net_device *dev)
-{
-       if (!netif_running(dev))
-               return -EINVAL;
-       return 0;
-}
-
-static void smc_get_drvinfo(struct net_device *dev, struct ethtool_drvinfo *info)
-{
-       strcpy(info->driver, DRV_NAME);
-       strcpy(info->version, DRV_VERSION);
-}
-
-static int smc_get_settings(struct net_device *dev, struct ethtool_cmd *ecmd)
-{
-       struct smc_private *smc = netdev_priv(dev);
-       unsigned int ioaddr = dev->base_addr;
-       u16 saved_bank = inw(ioaddr + BANK_SELECT);
-       int ret;
-       unsigned long flags;
-
-       spin_lock_irqsave(&smc->lock, flags);
-       SMC_SELECT_BANK(3);
-       if (smc->cfg & CFG_MII_SELECT)
-               ret = mii_ethtool_gset(&smc->mii_if, ecmd);
-       else
-               ret = smc_netdev_get_ecmd(dev, ecmd);
-       SMC_SELECT_BANK(saved_bank);
-       spin_unlock_irqrestore(&smc->lock, flags);
-       return ret;
-}
-
-static int smc_set_settings(struct net_device *dev, struct ethtool_cmd *ecmd)
-{
-       struct smc_private *smc = netdev_priv(dev);
-       unsigned int ioaddr = dev->base_addr;
-       u16 saved_bank = inw(ioaddr + BANK_SELECT);
-       int ret;
-       unsigned long flags;
-
-       spin_lock_irqsave(&smc->lock, flags);
-       SMC_SELECT_BANK(3);
-       if (smc->cfg & CFG_MII_SELECT)
-               ret = mii_ethtool_sset(&smc->mii_if, ecmd);
-       else
-               ret = smc_netdev_set_ecmd(dev, ecmd);
-       SMC_SELECT_BANK(saved_bank);
-       spin_unlock_irqrestore(&smc->lock, flags);
-       return ret;
-}
-
-static u32 smc_get_link(struct net_device *dev)
-{
-       struct smc_private *smc = netdev_priv(dev);
-       unsigned int ioaddr = dev->base_addr;
-       u16 saved_bank = inw(ioaddr + BANK_SELECT);
-       u32 ret;
-       unsigned long flags;
-
-       spin_lock_irqsave(&smc->lock, flags);
-       SMC_SELECT_BANK(3);
-       ret = smc_link_ok(dev);
-       SMC_SELECT_BANK(saved_bank);
-       spin_unlock_irqrestore(&smc->lock, flags);
-       return ret;
-}
-
-static int smc_nway_reset(struct net_device *dev)
-{
-       struct smc_private *smc = netdev_priv(dev);
-       if (smc->cfg & CFG_MII_SELECT) {
-               unsigned int ioaddr = dev->base_addr;
-               u16 saved_bank = inw(ioaddr + BANK_SELECT);
-               int res;
-
-               SMC_SELECT_BANK(3);
-               res = mii_nway_restart(&smc->mii_if);
-               SMC_SELECT_BANK(saved_bank);
-
-               return res;
-       } else
-               return -EOPNOTSUPP;
-}
-
-static const struct ethtool_ops ethtool_ops = {
-       .begin = check_if_running,
-       .get_drvinfo = smc_get_drvinfo,
-       .get_settings = smc_get_settings,
-       .set_settings = smc_set_settings,
-       .get_link = smc_get_link,
-       .nway_reset = smc_nway_reset,
-};
-
-static int smc_ioctl (struct net_device *dev, struct ifreq *rq, int cmd)
-{
-       struct smc_private *smc = netdev_priv(dev);
-       struct mii_ioctl_data *mii = if_mii(rq);
-       int rc = 0;
-       u16 saved_bank;
-       unsigned int ioaddr = dev->base_addr;
-       unsigned long flags;
-
-       if (!netif_running(dev))
-               return -EINVAL;
-
-       spin_lock_irqsave(&smc->lock, flags);
-       saved_bank = inw(ioaddr + BANK_SELECT);
-       SMC_SELECT_BANK(3);
-       rc = generic_mii_ioctl(&smc->mii_if, mii, cmd, NULL);
-       SMC_SELECT_BANK(saved_bank);
-       spin_unlock_irqrestore(&smc->lock, flags);
-       return rc;
-}
-
-static const struct pcmcia_device_id smc91c92_ids[] = {
-       PCMCIA_PFC_DEVICE_MANF_CARD(0, 0x0109, 0x0501),
-       PCMCIA_PFC_DEVICE_MANF_CARD(0, 0x0140, 0x000a),
-       PCMCIA_PFC_DEVICE_PROD_ID123(0, "MEGAHERTZ", "CC/XJEM3288", "DATA/FAX/CELL ETHERNET MODEM", 0xf510db04, 0x04cd2988, 0x46a52d63),
-       PCMCIA_PFC_DEVICE_PROD_ID123(0, "MEGAHERTZ", "CC/XJEM3336", "DATA/FAX/CELL ETHERNET MODEM", 0xf510db04, 0x0143b773, 0x46a52d63),
-       PCMCIA_PFC_DEVICE_PROD_ID123(0, "MEGAHERTZ", "EM1144T", "PCMCIA MODEM", 0xf510db04, 0x856d66c8, 0xbd6c43ef),
-       PCMCIA_PFC_DEVICE_PROD_ID123(0, "MEGAHERTZ", "XJEM1144/CCEM1144", "PCMCIA MODEM", 0xf510db04, 0x52d21e1e, 0xbd6c43ef),
-       PCMCIA_PFC_DEVICE_PROD_ID12(0, "Gateway 2000", "XJEM3336", 0xdd9989be, 0x662c394c),
-       PCMCIA_PFC_DEVICE_PROD_ID12(0, "MEGAHERTZ", "XJEM1144/CCEM1144", 0xf510db04, 0x52d21e1e),
-       PCMCIA_PFC_DEVICE_PROD_ID12(0, "Ositech", "Trumpcard:Jack of Diamonds Modem+Ethernet", 0xc2f80cd, 0x656947b9),
-       PCMCIA_PFC_DEVICE_PROD_ID12(0, "Ositech", "Trumpcard:Jack of Hearts Modem+Ethernet", 0xc2f80cd, 0xdc9ba5ed),
-       PCMCIA_MFC_DEVICE_MANF_CARD(0, 0x016c, 0x0020),
-       PCMCIA_DEVICE_MANF_CARD(0x016c, 0x0023),
-       PCMCIA_DEVICE_PROD_ID123("BASICS by New Media Corporation", "Ethernet", "SMC91C94", 0x23c78a9d, 0x00b2e941, 0xcef397fb),
-       PCMCIA_DEVICE_PROD_ID12("ARGOSY", "Fast Ethernet PCCard", 0x78f308dc, 0xdcea68bc),
-       PCMCIA_DEVICE_PROD_ID12("dit Co., Ltd.", "PC Card-10/100BTX", 0xe59365c8, 0x6a2161d1),
-       PCMCIA_DEVICE_PROD_ID12("DYNALINK", "L100C", 0x6a26d1cf, 0xc16ce9c5),
-       PCMCIA_DEVICE_PROD_ID12("Farallon", "Farallon Enet", 0x58d93fc4, 0x244734e9),
-       PCMCIA_DEVICE_PROD_ID12("Megahertz", "CC10BT/2", 0x33234748, 0x3c95b953),
-       PCMCIA_DEVICE_PROD_ID12("MELCO/SMC", "LPC-TX", 0xa2cd8e6d, 0x42da662a),
-       PCMCIA_DEVICE_PROD_ID12("Ositech", "Trumpcard:Four of Diamonds Ethernet", 0xc2f80cd, 0xb3466314),
-       PCMCIA_DEVICE_PROD_ID12("Ositech", "Trumpcard:Seven of Diamonds Ethernet", 0xc2f80cd, 0x194b650a),
-       PCMCIA_DEVICE_PROD_ID12("PCMCIA", "Fast Ethernet PCCard", 0x281f1c5d, 0xdcea68bc),
-       PCMCIA_DEVICE_PROD_ID12("Psion", "10Mb Ethernet", 0x4ef00b21, 0x844be9e9),
-       PCMCIA_DEVICE_PROD_ID12("SMC", "EtherEZ Ethernet 8020", 0xc4f8b18b, 0x4a0eeb2d),
-       /* These conflict with other cards! */
-       /* PCMCIA_DEVICE_MANF_CARD(0x0186, 0x0100), */
-       /* PCMCIA_DEVICE_MANF_CARD(0x8a01, 0xc1ab), */
-       PCMCIA_DEVICE_NULL,
-};
-MODULE_DEVICE_TABLE(pcmcia, smc91c92_ids);
-
-static struct pcmcia_driver smc91c92_cs_driver = {
-       .owner          = THIS_MODULE,
-       .name           = "smc91c92_cs",
-       .probe          = smc91c92_probe,
-       .remove         = smc91c92_detach,
-       .id_table       = smc91c92_ids,
-       .suspend        = smc91c92_suspend,
-       .resume         = smc91c92_resume,
-};
-
-static int __init init_smc91c92_cs(void)
-{
-       return pcmcia_register_driver(&smc91c92_cs_driver);
-}
-
-static void __exit exit_smc91c92_cs(void)
-{
-       pcmcia_unregister_driver(&smc91c92_cs_driver);
-}
-
-module_init(init_smc91c92_cs);
-module_exit(exit_smc91c92_cs);
diff --git a/drivers/net/smc911x.c b/drivers/net/smc911x.c
deleted file mode 100644 (file)
index a91fe17..0000000
+++ /dev/null
@@ -1,2210 +0,0 @@
-/*
- * smc911x.c
- * This is a driver for SMSC's LAN911{5,6,7,8} single-chip Ethernet devices.
- *
- * Copyright (C) 2005 Sensoria Corp
- *        Derived from the unified SMC91x driver by Nicolas Pitre
- *        and the smsc911x.c reference driver by SMSC
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
- *
- * Arguments:
- *      watchdog  = TX watchdog timeout
- *      tx_fifo_kb = Size of TX FIFO in KB
- *
- * History:
- *       04/16/05      Dustin McIntire          Initial version
- */
-static const char version[] =
-        "smc911x.c: v1.0 04-16-2005 by Dustin McIntire <dustin@sensoria.com>\n";
-
-/* Debugging options */
-#define ENABLE_SMC_DEBUG_RX            0
-#define ENABLE_SMC_DEBUG_TX            0
-#define ENABLE_SMC_DEBUG_DMA           0
-#define ENABLE_SMC_DEBUG_PKTS          0
-#define ENABLE_SMC_DEBUG_MISC          0
-#define ENABLE_SMC_DEBUG_FUNC          0
-
-#define SMC_DEBUG_RX           ((ENABLE_SMC_DEBUG_RX   ? 1 : 0) << 0)
-#define SMC_DEBUG_TX           ((ENABLE_SMC_DEBUG_TX   ? 1 : 0) << 1)
-#define SMC_DEBUG_DMA          ((ENABLE_SMC_DEBUG_DMA  ? 1 : 0) << 2)
-#define SMC_DEBUG_PKTS         ((ENABLE_SMC_DEBUG_PKTS ? 1 : 0) << 3)
-#define SMC_DEBUG_MISC         ((ENABLE_SMC_DEBUG_MISC ? 1 : 0) << 4)
-#define SMC_DEBUG_FUNC         ((ENABLE_SMC_DEBUG_FUNC ? 1 : 0) << 5)
-
-#ifndef SMC_DEBUG
-#define SMC_DEBUG       ( SMC_DEBUG_RX   | \
-                          SMC_DEBUG_TX   | \
-                          SMC_DEBUG_DMA  | \
-                          SMC_DEBUG_PKTS | \
-                          SMC_DEBUG_MISC | \
-                          SMC_DEBUG_FUNC   \
-                        )
-#endif
-
-#include <linux/init.h>
-#include <linux/module.h>
-#include <linux/kernel.h>
-#include <linux/sched.h>
-#include <linux/delay.h>
-#include <linux/interrupt.h>
-#include <linux/errno.h>
-#include <linux/ioport.h>
-#include <linux/crc32.h>
-#include <linux/device.h>
-#include <linux/platform_device.h>
-#include <linux/spinlock.h>
-#include <linux/ethtool.h>
-#include <linux/mii.h>
-#include <linux/workqueue.h>
-
-#include <linux/netdevice.h>
-#include <linux/etherdevice.h>
-#include <linux/skbuff.h>
-
-#include <asm/io.h>
-
-#include "smc911x.h"
-
-/*
- * Transmit timeout, default 5 seconds.
- */
-static int watchdog = 5000;
-module_param(watchdog, int, 0400);
-MODULE_PARM_DESC(watchdog, "transmit timeout in milliseconds");
-
-static int tx_fifo_kb=8;
-module_param(tx_fifo_kb, int, 0400);
-MODULE_PARM_DESC(tx_fifo_kb,"transmit FIFO size in KB (1<x<15)(default=8)");
-
-MODULE_LICENSE("GPL");
-MODULE_ALIAS("platform:smc911x");
-
-/*
- * The internal workings of the driver.  If you are changing anything
- * here with the SMC stuff, you should have the datasheet and know
- * what you are doing.
- */
-#define CARDNAME "smc911x"
-
-/*
- * Use power-down feature of the chip
- */
-#define POWER_DOWN              1
-
-#if SMC_DEBUG > 0
-#define DBG(n, args...)                                 \
-       do {                                     \
-               if (SMC_DEBUG & (n))             \
-                       printk(args);            \
-       } while (0)
-
-#define PRINTK(args...)   printk(args)
-#else
-#define DBG(n, args...)   do { } while (0)
-#define PRINTK(args...)   printk(KERN_DEBUG args)
-#endif
-
-#if SMC_DEBUG_PKTS > 0
-static void PRINT_PKT(u_char *buf, int length)
-{
-       int i;
-       int remainder;
-       int lines;
-
-       lines = length / 16;
-       remainder = length % 16;
-
-       for (i = 0; i < lines ; i ++) {
-               int cur;
-               for (cur = 0; cur < 8; cur++) {
-                       u_char a, b;
-                       a = *buf++;
-                       b = *buf++;
-                       printk("%02x%02x ", a, b);
-               }
-               printk("\n");
-       }
-       for (i = 0; i < remainder/2 ; i++) {
-               u_char a, b;
-               a = *buf++;
-               b = *buf++;
-               printk("%02x%02x ", a, b);
-       }
-       printk("\n");
-}
-#else
-#define PRINT_PKT(x...)  do { } while (0)
-#endif
-
-
-/* this enables an interrupt in the interrupt mask register */
-#define SMC_ENABLE_INT(lp, x) do {                     \
-       unsigned int  __mask;                           \
-       __mask = SMC_GET_INT_EN((lp));                  \
-       __mask |= (x);                                  \
-       SMC_SET_INT_EN((lp), __mask);                   \
-} while (0)
-
-/* this disables an interrupt from the interrupt mask register */
-#define SMC_DISABLE_INT(lp, x) do {                    \
-       unsigned int  __mask;                           \
-       __mask = SMC_GET_INT_EN((lp));                  \
-       __mask &= ~(x);                                 \
-       SMC_SET_INT_EN((lp), __mask);                   \
-} while (0)
-
-/*
- * this does a soft reset on the device
- */
-static void smc911x_reset(struct net_device *dev)
-{
-       struct smc911x_local *lp = netdev_priv(dev);
-       unsigned int reg, timeout=0, resets=1, irq_cfg;
-       unsigned long flags;
-
-       DBG(SMC_DEBUG_FUNC, "%s: --> %s\n", dev->name, __func__);
-
-       /*       Take out of PM setting first */
-       if ((SMC_GET_PMT_CTRL(lp) & PMT_CTRL_READY_) == 0) {
-               /* Write to the bytetest will take out of powerdown */
-               SMC_SET_BYTE_TEST(lp, 0);
-               timeout=10;
-               do {
-                       udelay(10);
-                       reg = SMC_GET_PMT_CTRL(lp) & PMT_CTRL_READY_;
-               } while (--timeout && !reg);
-               if (timeout == 0) {
-                       PRINTK("%s: smc911x_reset timeout waiting for PM restore\n", dev->name);
-                       return;
-               }
-       }
-
-       /* Disable all interrupts */
-       spin_lock_irqsave(&lp->lock, flags);
-       SMC_SET_INT_EN(lp, 0);
-       spin_unlock_irqrestore(&lp->lock, flags);
-
-       while (resets--) {
-               SMC_SET_HW_CFG(lp, HW_CFG_SRST_);
-               timeout=10;
-               do {
-                       udelay(10);
-                       reg = SMC_GET_HW_CFG(lp);
-                       /* If chip indicates reset timeout then try again */
-                       if (reg & HW_CFG_SRST_TO_) {
-                               PRINTK("%s: chip reset timeout, retrying...\n", dev->name);
-                               resets++;
-                               break;
-                       }
-               } while (--timeout && (reg & HW_CFG_SRST_));
-       }
-       if (timeout == 0) {
-               PRINTK("%s: smc911x_reset timeout waiting for reset\n", dev->name);
-               return;
-       }
-
-       /* make sure EEPROM has finished loading before setting GPIO_CFG */
-       timeout=1000;
-       while (--timeout && (SMC_GET_E2P_CMD(lp) & E2P_CMD_EPC_BUSY_))
-               udelay(10);
-
-       if (timeout == 0){
-               PRINTK("%s: smc911x_reset timeout waiting for EEPROM busy\n", dev->name);
-               return;
-       }
-
-       /* Initialize interrupts */
-       SMC_SET_INT_EN(lp, 0);
-       SMC_ACK_INT(lp, -1);
-
-       /* Reset the FIFO level and flow control settings */
-       SMC_SET_HW_CFG(lp, (lp->tx_fifo_kb & 0xF) << 16);
-//TODO: Figure out what appropriate pause time is
-       SMC_SET_FLOW(lp, FLOW_FCPT_ | FLOW_FCEN_);
-       SMC_SET_AFC_CFG(lp, lp->afc_cfg);
-
-
-       /* Set to LED outputs */
-       SMC_SET_GPIO_CFG(lp, 0x70070000);
-
-       /*
-        * Deassert IRQ for 1*10us for edge type interrupts
-        * and drive IRQ pin push-pull
-        */
-       irq_cfg = (1 << 24) | INT_CFG_IRQ_EN_ | INT_CFG_IRQ_TYPE_;
-#ifdef SMC_DYNAMIC_BUS_CONFIG
-       if (lp->cfg.irq_polarity)
-               irq_cfg |= INT_CFG_IRQ_POL_;
-#endif
-       SMC_SET_IRQ_CFG(lp, irq_cfg);
-
-       /* clear anything saved */
-       if (lp->pending_tx_skb != NULL) {
-               dev_kfree_skb (lp->pending_tx_skb);
-               lp->pending_tx_skb = NULL;
-               dev->stats.tx_errors++;
-               dev->stats.tx_aborted_errors++;
-       }
-}
-
-/*
- * Enable Interrupts, Receive, and Transmit
- */
-static void smc911x_enable(struct net_device *dev)
-{
-       struct smc911x_local *lp = netdev_priv(dev);
-       unsigned mask, cfg, cr;
-       unsigned long flags;
-
-       DBG(SMC_DEBUG_FUNC, "%s: --> %s\n", dev->name, __func__);
-
-       spin_lock_irqsave(&lp->lock, flags);
-
-       SMC_SET_MAC_ADDR(lp, dev->dev_addr);
-
-       /* Enable TX */
-       cfg = SMC_GET_HW_CFG(lp);
-       cfg &= HW_CFG_TX_FIF_SZ_ | 0xFFF;
-       cfg |= HW_CFG_SF_;
-       SMC_SET_HW_CFG(lp, cfg);
-       SMC_SET_FIFO_TDA(lp, 0xFF);
-       /* Update TX stats on every 64 packets received or every 1 sec */
-       SMC_SET_FIFO_TSL(lp, 64);
-       SMC_SET_GPT_CFG(lp, GPT_CFG_TIMER_EN_ | 10000);
-
-       SMC_GET_MAC_CR(lp, cr);
-       cr |= MAC_CR_TXEN_ | MAC_CR_HBDIS_;
-       SMC_SET_MAC_CR(lp, cr);
-       SMC_SET_TX_CFG(lp, TX_CFG_TX_ON_);
-
-       /* Add 2 byte padding to start of packets */
-       SMC_SET_RX_CFG(lp, (2<<8) & RX_CFG_RXDOFF_);
-
-       /* Turn on receiver and enable RX */
-       if (cr & MAC_CR_RXEN_)
-               DBG(SMC_DEBUG_RX, "%s: Receiver already enabled\n", dev->name);
-
-       SMC_SET_MAC_CR(lp, cr | MAC_CR_RXEN_);
-
-       /* Interrupt on every received packet */
-       SMC_SET_FIFO_RSA(lp, 0x01);
-       SMC_SET_FIFO_RSL(lp, 0x00);
-
-       /* now, enable interrupts */
-       mask = INT_EN_TDFA_EN_ | INT_EN_TSFL_EN_ | INT_EN_RSFL_EN_ |
-               INT_EN_GPT_INT_EN_ | INT_EN_RXDFH_INT_EN_ | INT_EN_RXE_EN_ |
-               INT_EN_PHY_INT_EN_;
-       if (IS_REV_A(lp->revision))
-               mask|=INT_EN_RDFL_EN_;
-       else {
-               mask|=INT_EN_RDFO_EN_;
-       }
-       SMC_ENABLE_INT(lp, mask);
-
-       spin_unlock_irqrestore(&lp->lock, flags);
-}
-
-/*
- * this puts the device in an inactive state
- */
-static void smc911x_shutdown(struct net_device *dev)
-{
-       struct smc911x_local *lp = netdev_priv(dev);
-       unsigned cr;
-       unsigned long flags;
-
-       DBG(SMC_DEBUG_FUNC, "%s: --> %s\n", CARDNAME, __func__);
-
-       /* Disable IRQ's */
-       SMC_SET_INT_EN(lp, 0);
-
-       /* Turn of Rx and TX */
-       spin_lock_irqsave(&lp->lock, flags);
-       SMC_GET_MAC_CR(lp, cr);
-       cr &= ~(MAC_CR_TXEN_ | MAC_CR_RXEN_ | MAC_CR_HBDIS_);
-       SMC_SET_MAC_CR(lp, cr);
-       SMC_SET_TX_CFG(lp, TX_CFG_STOP_TX_);
-       spin_unlock_irqrestore(&lp->lock, flags);
-}
-
-static inline void smc911x_drop_pkt(struct net_device *dev)
-{
-       struct smc911x_local *lp = netdev_priv(dev);
-       unsigned int fifo_count, timeout, reg;
-
-       DBG(SMC_DEBUG_FUNC | SMC_DEBUG_RX, "%s: --> %s\n", CARDNAME, __func__);
-       fifo_count = SMC_GET_RX_FIFO_INF(lp) & 0xFFFF;
-       if (fifo_count <= 4) {
-               /* Manually dump the packet data */
-               while (fifo_count--)
-                       SMC_GET_RX_FIFO(lp);
-       } else   {
-               /* Fast forward through the bad packet */
-               SMC_SET_RX_DP_CTRL(lp, RX_DP_CTRL_FFWD_BUSY_);
-               timeout=50;
-               do {
-                       udelay(10);
-                       reg = SMC_GET_RX_DP_CTRL(lp) & RX_DP_CTRL_FFWD_BUSY_;
-               } while (--timeout && reg);
-               if (timeout == 0) {
-                       PRINTK("%s: timeout waiting for RX fast forward\n", dev->name);
-               }
-       }
-}
-
-/*
- * This is the procedure to handle the receipt of a packet.
- * It should be called after checking for packet presence in
- * the RX status FIFO.  It must be called with the spin lock
- * already held.
- */
-static inline void      smc911x_rcv(struct net_device *dev)
-{
-       struct smc911x_local *lp = netdev_priv(dev);
-       unsigned int pkt_len, status;
-       struct sk_buff *skb;
-       unsigned char *data;
-
-       DBG(SMC_DEBUG_FUNC | SMC_DEBUG_RX, "%s: --> %s\n",
-               dev->name, __func__);
-       status = SMC_GET_RX_STS_FIFO(lp);
-       DBG(SMC_DEBUG_RX, "%s: Rx pkt len %d status 0x%08x\n",
-               dev->name, (status & 0x3fff0000) >> 16, status & 0xc000ffff);
-       pkt_len = (status & RX_STS_PKT_LEN_) >> 16;
-       if (status & RX_STS_ES_) {
-               /* Deal with a bad packet */
-               dev->stats.rx_errors++;
-               if (status & RX_STS_CRC_ERR_)
-                       dev->stats.rx_crc_errors++;
-               else {
-                       if (status & RX_STS_LEN_ERR_)
-                               dev->stats.rx_length_errors++;
-                       if (status & RX_STS_MCAST_)
-                               dev->stats.multicast++;
-               }
-               /* Remove the bad packet data from the RX FIFO */
-               smc911x_drop_pkt(dev);
-       } else {
-               /* Receive a valid packet */
-               /* Alloc a buffer with extra room for DMA alignment */
-               skb=dev_alloc_skb(pkt_len+32);
-               if (unlikely(skb == NULL)) {
-                       PRINTK( "%s: Low memory, rcvd packet dropped.\n",
-                               dev->name);
-                       dev->stats.rx_dropped++;
-                       smc911x_drop_pkt(dev);
-                       return;
-               }
-               /* Align IP header to 32 bits
-                * Note that the device is configured to add a 2
-                * byte padding to the packet start, so we really
-                * want to write to the orignal data pointer */
-               data = skb->data;
-               skb_reserve(skb, 2);
-               skb_put(skb,pkt_len-4);
-#ifdef SMC_USE_DMA
-               {
-               unsigned int fifo;
-               /* Lower the FIFO threshold if possible */
-               fifo = SMC_GET_FIFO_INT(lp);
-               if (fifo & 0xFF) fifo--;
-               DBG(SMC_DEBUG_RX, "%s: Setting RX stat FIFO threshold to %d\n",
-                       dev->name, fifo & 0xff);
-               SMC_SET_FIFO_INT(lp, fifo);
-               /* Setup RX DMA */
-               SMC_SET_RX_CFG(lp, RX_CFG_RX_END_ALGN16_ | ((2<<8) & RX_CFG_RXDOFF_));
-               lp->rxdma_active = 1;
-               lp->current_rx_skb = skb;
-               SMC_PULL_DATA(lp, data, (pkt_len+2+15) & ~15);
-               /* Packet processing deferred to DMA RX interrupt */
-               }
-#else
-               SMC_SET_RX_CFG(lp, RX_CFG_RX_END_ALGN4_ | ((2<<8) & RX_CFG_RXDOFF_));
-               SMC_PULL_DATA(lp, data, pkt_len+2+3);
-
-               DBG(SMC_DEBUG_PKTS, "%s: Received packet\n", dev->name);
-               PRINT_PKT(data, ((pkt_len - 4) <= 64) ? pkt_len - 4 : 64);
-               skb->protocol = eth_type_trans(skb, dev);
-               netif_rx(skb);
-               dev->stats.rx_packets++;
-               dev->stats.rx_bytes += pkt_len-4;
-#endif
-       }
-}
-
-/*
- * This is called to actually send a packet to the chip.
- */
-static void smc911x_hardware_send_pkt(struct net_device *dev)
-{
-       struct smc911x_local *lp = netdev_priv(dev);
-       struct sk_buff *skb;
-       unsigned int cmdA, cmdB, len;
-       unsigned char *buf;
-
-       DBG(SMC_DEBUG_FUNC | SMC_DEBUG_TX, "%s: --> %s\n", dev->name, __func__);
-       BUG_ON(lp->pending_tx_skb == NULL);
-
-       skb = lp->pending_tx_skb;
-       lp->pending_tx_skb = NULL;
-
-       /* cmdA {25:24] data alignment [20:16] start offset [10:0] buffer length */
-       /* cmdB {31:16] pkt tag [10:0] length */
-#ifdef SMC_USE_DMA
-       /* 16 byte buffer alignment mode */
-       buf = (char*)((u32)(skb->data) & ~0xF);
-       len = (skb->len + 0xF + ((u32)skb->data & 0xF)) & ~0xF;
-       cmdA = (1<<24) | (((u32)skb->data & 0xF)<<16) |
-                       TX_CMD_A_INT_FIRST_SEG_ | TX_CMD_A_INT_LAST_SEG_ |
-                       skb->len;
-#else
-       buf = (char*)((u32)skb->data & ~0x3);
-       len = (skb->len + 3 + ((u32)skb->data & 3)) & ~0x3;
-       cmdA = (((u32)skb->data & 0x3) << 16) |
-                       TX_CMD_A_INT_FIRST_SEG_ | TX_CMD_A_INT_LAST_SEG_ |
-                       skb->len;
-#endif
-       /* tag is packet length so we can use this in stats update later */
-       cmdB = (skb->len  << 16) | (skb->len & 0x7FF);
-
-       DBG(SMC_DEBUG_TX, "%s: TX PKT LENGTH 0x%04x (%d) BUF 0x%p CMDA 0x%08x CMDB 0x%08x\n",
-                dev->name, len, len, buf, cmdA, cmdB);
-       SMC_SET_TX_FIFO(lp, cmdA);
-       SMC_SET_TX_FIFO(lp, cmdB);
-
-       DBG(SMC_DEBUG_PKTS, "%s: Transmitted packet\n", dev->name);
-       PRINT_PKT(buf, len <= 64 ? len : 64);
-
-       /* Send pkt via PIO or DMA */
-#ifdef SMC_USE_DMA
-       lp->current_tx_skb = skb;
-       SMC_PUSH_DATA(lp, buf, len);
-       /* DMA complete IRQ will free buffer and set jiffies */
-#else
-       SMC_PUSH_DATA(lp, buf, len);
-       dev->trans_start = jiffies;
-       dev_kfree_skb_irq(skb);
-#endif
-       if (!lp->tx_throttle) {
-               netif_wake_queue(dev);
-       }
-       SMC_ENABLE_INT(lp, INT_EN_TDFA_EN_ | INT_EN_TSFL_EN_);
-}
-
-/*
- * Since I am not sure if I will have enough room in the chip's ram
- * to store the packet, I call this routine which either sends it
- * now, or set the card to generates an interrupt when ready
- * for the packet.
- */
-static int smc911x_hard_start_xmit(struct sk_buff *skb, struct net_device *dev)
-{
-       struct smc911x_local *lp = netdev_priv(dev);
-       unsigned int free;
-       unsigned long flags;
-
-       DBG(SMC_DEBUG_FUNC | SMC_DEBUG_TX, "%s: --> %s\n",
-               dev->name, __func__);
-
-       spin_lock_irqsave(&lp->lock, flags);
-
-       BUG_ON(lp->pending_tx_skb != NULL);
-
-       free = SMC_GET_TX_FIFO_INF(lp) & TX_FIFO_INF_TDFREE_;
-       DBG(SMC_DEBUG_TX, "%s: TX free space %d\n", dev->name, free);
-
-       /* Turn off the flow when running out of space in FIFO */
-       if (free <= SMC911X_TX_FIFO_LOW_THRESHOLD) {
-               DBG(SMC_DEBUG_TX, "%s: Disabling data flow due to low FIFO space (%d)\n",
-                       dev->name, free);
-               /* Reenable when at least 1 packet of size MTU present */
-               SMC_SET_FIFO_TDA(lp, (SMC911X_TX_FIFO_LOW_THRESHOLD)/64);
-               lp->tx_throttle = 1;
-               netif_stop_queue(dev);
-       }
-
-       /* Drop packets when we run out of space in TX FIFO
-        * Account for overhead required for:
-        *
-        *        Tx command words                       8 bytes
-        *        Start offset                           15 bytes
-        *        End padding                            15 bytes
-        */
-       if (unlikely(free < (skb->len + 8 + 15 + 15))) {
-               printk("%s: No Tx free space %d < %d\n",
-                       dev->name, free, skb->len);
-               lp->pending_tx_skb = NULL;
-               dev->stats.tx_errors++;
-               dev->stats.tx_dropped++;
-               spin_unlock_irqrestore(&lp->lock, flags);
-               dev_kfree_skb(skb);
-               return NETDEV_TX_OK;
-       }
-
-#ifdef SMC_USE_DMA
-       {
-               /* If the DMA is already running then defer this packet Tx until
-                * the DMA IRQ starts it
-                */
-               if (lp->txdma_active) {
-                       DBG(SMC_DEBUG_TX | SMC_DEBUG_DMA, "%s: Tx DMA running, deferring packet\n", dev->name);
-                       lp->pending_tx_skb = skb;
-                       netif_stop_queue(dev);
-                       spin_unlock_irqrestore(&lp->lock, flags);
-                       return NETDEV_TX_OK;
-               } else {
-                       DBG(SMC_DEBUG_TX | SMC_DEBUG_DMA, "%s: Activating Tx DMA\n", dev->name);
-                       lp->txdma_active = 1;
-               }
-       }
-#endif
-       lp->pending_tx_skb = skb;
-       smc911x_hardware_send_pkt(dev);
-       spin_unlock_irqrestore(&lp->lock, flags);
-
-       return NETDEV_TX_OK;
-}
-
-/*
- * This handles a TX status interrupt, which is only called when:
- * - a TX error occurred, or
- * - TX of a packet completed.
- */
-static void smc911x_tx(struct net_device *dev)
-{
-       struct smc911x_local *lp = netdev_priv(dev);
-       unsigned int tx_status;
-
-       DBG(SMC_DEBUG_FUNC | SMC_DEBUG_TX, "%s: --> %s\n",
-               dev->name, __func__);
-
-       /* Collect the TX status */
-       while (((SMC_GET_TX_FIFO_INF(lp) & TX_FIFO_INF_TSUSED_) >> 16) != 0) {
-               DBG(SMC_DEBUG_TX, "%s: Tx stat FIFO used 0x%04x\n",
-                       dev->name,
-                       (SMC_GET_TX_FIFO_INF(lp) & TX_FIFO_INF_TSUSED_) >> 16);
-               tx_status = SMC_GET_TX_STS_FIFO(lp);
-               dev->stats.tx_packets++;
-               dev->stats.tx_bytes+=tx_status>>16;
-               DBG(SMC_DEBUG_TX, "%s: Tx FIFO tag 0x%04x status 0x%04x\n",
-                       dev->name, (tx_status & 0xffff0000) >> 16,
-                       tx_status & 0x0000ffff);
-               /* count Tx errors, but ignore lost carrier errors when in
-                * full-duplex mode */
-               if ((tx_status & TX_STS_ES_) && !(lp->ctl_rfduplx &&
-                   !(tx_status & 0x00000306))) {
-                       dev->stats.tx_errors++;
-               }
-               if (tx_status & TX_STS_MANY_COLL_) {
-                       dev->stats.collisions+=16;
-                       dev->stats.tx_aborted_errors++;
-               } else {
-                       dev->stats.collisions+=(tx_status & TX_STS_COLL_CNT_) >> 3;
-               }
-               /* carrier error only has meaning for half-duplex communication */
-               if ((tx_status & (TX_STS_LOC_ | TX_STS_NO_CARR_)) &&
-                   !lp->ctl_rfduplx) {
-                       dev->stats.tx_carrier_errors++;
-               }
-               if (tx_status & TX_STS_LATE_COLL_) {
-                       dev->stats.collisions++;
-                       dev->stats.tx_aborted_errors++;
-               }
-       }
-}
-
-
-/*---PHY CONTROL AND CONFIGURATION-----------------------------------------*/
-/*
- * Reads a register from the MII Management serial interface
- */
-
-static int smc911x_phy_read(struct net_device *dev, int phyaddr, int phyreg)
-{
-       struct smc911x_local *lp = netdev_priv(dev);
-       unsigned int phydata;
-
-       SMC_GET_MII(lp, phyreg, phyaddr, phydata);
-
-       DBG(SMC_DEBUG_MISC, "%s: phyaddr=0x%x, phyreg=0x%02x, phydata=0x%04x\n",
-               __func__, phyaddr, phyreg, phydata);
-       return phydata;
-}
-
-
-/*
- * Writes a register to the MII Management serial interface
- */
-static void smc911x_phy_write(struct net_device *dev, int phyaddr, int phyreg,
-                       int phydata)
-{
-       struct smc911x_local *lp = netdev_priv(dev);
-
-       DBG(SMC_DEBUG_MISC, "%s: phyaddr=0x%x, phyreg=0x%x, phydata=0x%x\n",
-               __func__, phyaddr, phyreg, phydata);
-
-       SMC_SET_MII(lp, phyreg, phyaddr, phydata);
-}
-
-/*
- * Finds and reports the PHY address (115 and 117 have external
- * PHY interface 118 has internal only
- */
-static void smc911x_phy_detect(struct net_device *dev)
-{
-       struct smc911x_local *lp = netdev_priv(dev);
-       int phyaddr;
-       unsigned int cfg, id1, id2;
-
-       DBG(SMC_DEBUG_FUNC, "%s: --> %s\n", dev->name, __func__);
-
-       lp->phy_type = 0;
-
-       /*
-        * Scan all 32 PHY addresses if necessary, starting at
-        * PHY#1 to PHY#31, and then PHY#0 last.
-        */
-       switch(lp->version) {
-               case CHIP_9115:
-               case CHIP_9117:
-               case CHIP_9215:
-               case CHIP_9217:
-                       cfg = SMC_GET_HW_CFG(lp);
-                       if (cfg & HW_CFG_EXT_PHY_DET_) {
-                               cfg &= ~HW_CFG_PHY_CLK_SEL_;
-                               cfg |= HW_CFG_PHY_CLK_SEL_CLK_DIS_;
-                               SMC_SET_HW_CFG(lp, cfg);
-                               udelay(10); /* Wait for clocks to stop */
-
-                               cfg |= HW_CFG_EXT_PHY_EN_;
-                               SMC_SET_HW_CFG(lp, cfg);
-                               udelay(10); /* Wait for clocks to stop */
-
-                               cfg &= ~HW_CFG_PHY_CLK_SEL_;
-                               cfg |= HW_CFG_PHY_CLK_SEL_EXT_PHY_;
-                               SMC_SET_HW_CFG(lp, cfg);
-                               udelay(10); /* Wait for clocks to stop */
-
-                               cfg |= HW_CFG_SMI_SEL_;
-                               SMC_SET_HW_CFG(lp, cfg);
-
-                               for (phyaddr = 1; phyaddr < 32; ++phyaddr) {
-
-                                       /* Read the PHY identifiers */
-                                       SMC_GET_PHY_ID1(lp, phyaddr & 31, id1);
-                                       SMC_GET_PHY_ID2(lp, phyaddr & 31, id2);
-
-                                       /* Make sure it is a valid identifier */
-                                       if (id1 != 0x0000 && id1 != 0xffff &&
-                                           id1 != 0x8000 && id2 != 0x0000 &&
-                                           id2 != 0xffff && id2 != 0x8000) {
-                                               /* Save the PHY's address */
-                                               lp->mii.phy_id = phyaddr & 31;
-                                               lp->phy_type = id1 << 16 | id2;
-                                               break;
-                                       }
-                               }
-                               if (phyaddr < 32)
-                                       /* Found an external PHY */
-                                       break;
-                       }
-               default:
-                       /* Internal media only */
-                       SMC_GET_PHY_ID1(lp, 1, id1);
-                       SMC_GET_PHY_ID2(lp, 1, id2);
-                       /* Save the PHY's address */
-                       lp->mii.phy_id = 1;
-                       lp->phy_type = id1 << 16 | id2;
-       }
-
-       DBG(SMC_DEBUG_MISC, "%s: phy_id1=0x%x, phy_id2=0x%x phyaddr=0x%d\n",
-               dev->name, id1, id2, lp->mii.phy_id);
-}
-
-/*
- * Sets the PHY to a configuration as determined by the user.
- * Called with spin_lock held.
- */
-static int smc911x_phy_fixed(struct net_device *dev)
-{
-       struct smc911x_local *lp = netdev_priv(dev);
-       int phyaddr = lp->mii.phy_id;
-       int bmcr;
-
-       DBG(SMC_DEBUG_FUNC, "%s: --> %s\n", dev->name, __func__);
-
-       /* Enter Link Disable state */
-       SMC_GET_PHY_BMCR(lp, phyaddr, bmcr);
-       bmcr |= BMCR_PDOWN;
-       SMC_SET_PHY_BMCR(lp, phyaddr, bmcr);
-
-       /*
-        * Set our fixed capabilities
-        * Disable auto-negotiation
-        */
-       bmcr &= ~BMCR_ANENABLE;
-       if (lp->ctl_rfduplx)
-               bmcr |= BMCR_FULLDPLX;
-
-       if (lp->ctl_rspeed == 100)
-               bmcr |= BMCR_SPEED100;
-
-       /* Write our capabilities to the phy control register */
-       SMC_SET_PHY_BMCR(lp, phyaddr, bmcr);
-
-       /* Re-Configure the Receive/Phy Control register */
-       bmcr &= ~BMCR_PDOWN;
-       SMC_SET_PHY_BMCR(lp, phyaddr, bmcr);
-
-       return 1;
-}
-
-/*
- * smc911x_phy_reset - reset the phy
- * @dev: net device
- * @phy: phy address
- *
- * Issue a software reset for the specified PHY and
- * wait up to 100ms for the reset to complete.  We should
- * not access the PHY for 50ms after issuing the reset.
- *
- * The time to wait appears to be dependent on the PHY.
- *
- */
-static int smc911x_phy_reset(struct net_device *dev, int phy)
-{
-       struct smc911x_local *lp = netdev_priv(dev);
-       int timeout;
-       unsigned long flags;
-       unsigned int reg;
-
-       DBG(SMC_DEBUG_FUNC, "%s: --> %s()\n", dev->name, __func__);
-
-       spin_lock_irqsave(&lp->lock, flags);
-       reg = SMC_GET_PMT_CTRL(lp);
-       reg &= ~0xfffff030;
-       reg |= PMT_CTRL_PHY_RST_;
-       SMC_SET_PMT_CTRL(lp, reg);
-       spin_unlock_irqrestore(&lp->lock, flags);
-       for (timeout = 2; timeout; timeout--) {
-               msleep(50);
-               spin_lock_irqsave(&lp->lock, flags);
-               reg = SMC_GET_PMT_CTRL(lp);
-               spin_unlock_irqrestore(&lp->lock, flags);
-               if (!(reg & PMT_CTRL_PHY_RST_)) {
-                       /* extra delay required because the phy may
-                        * not be completed with its reset
-                        * when PHY_BCR_RESET_ is cleared. 256us
-                        * should suffice, but use 500us to be safe
-                        */
-                       udelay(500);
-               break;
-               }
-       }
-
-       return reg & PMT_CTRL_PHY_RST_;
-}
-
-/*
- * smc911x_phy_powerdown - powerdown phy
- * @dev: net device
- * @phy: phy address
- *
- * Power down the specified PHY
- */
-static void smc911x_phy_powerdown(struct net_device *dev, int phy)
-{
-       struct smc911x_local *lp = netdev_priv(dev);
-       unsigned int bmcr;
-
-       /* Enter Link Disable state */
-       SMC_GET_PHY_BMCR(lp, phy, bmcr);
-       bmcr |= BMCR_PDOWN;
-       SMC_SET_PHY_BMCR(lp, phy, bmcr);
-}
-
-/*
- * smc911x_phy_check_media - check the media status and adjust BMCR
- * @dev: net device
- * @init: set true for initialisation
- *
- * Select duplex mode depending on negotiation state.  This
- * also updates our carrier state.
- */
-static void smc911x_phy_check_media(struct net_device *dev, int init)
-{
-       struct smc911x_local *lp = netdev_priv(dev);
-       int phyaddr = lp->mii.phy_id;
-       unsigned int bmcr, cr;
-
-       DBG(SMC_DEBUG_FUNC, "%s: --> %s\n", dev->name, __func__);
-
-       if (mii_check_media(&lp->mii, netif_msg_link(lp), init)) {
-               /* duplex state has changed */
-               SMC_GET_PHY_BMCR(lp, phyaddr, bmcr);
-               SMC_GET_MAC_CR(lp, cr);
-               if (lp->mii.full_duplex) {
-                       DBG(SMC_DEBUG_MISC, "%s: Configuring for full-duplex mode\n", dev->name);
-                       bmcr |= BMCR_FULLDPLX;
-                       cr |= MAC_CR_RCVOWN_;
-               } else {
-                       DBG(SMC_DEBUG_MISC, "%s: Configuring for half-duplex mode\n", dev->name);
-                       bmcr &= ~BMCR_FULLDPLX;
-                       cr &= ~MAC_CR_RCVOWN_;
-               }
-               SMC_SET_PHY_BMCR(lp, phyaddr, bmcr);
-               SMC_SET_MAC_CR(lp, cr);
-       }
-}
-
-/*
- * Configures the specified PHY through the MII management interface
- * using Autonegotiation.
- * Calls smc911x_phy_fixed() if the user has requested a certain config.
- * If RPC ANEG bit is set, the media selection is dependent purely on
- * the selection by the MII (either in the MII BMCR reg or the result
- * of autonegotiation.)  If the RPC ANEG bit is cleared, the selection
- * is controlled by the RPC SPEED and RPC DPLX bits.
- */
-static void smc911x_phy_configure(struct work_struct *work)
-{
-       struct smc911x_local *lp = container_of(work, struct smc911x_local,
-                                               phy_configure);
-       struct net_device *dev = lp->netdev;
-       int phyaddr = lp->mii.phy_id;
-       int my_phy_caps; /* My PHY capabilities */
-       int my_ad_caps; /* My Advertised capabilities */
-       int status;
-       unsigned long flags;
-
-       DBG(SMC_DEBUG_FUNC, "%s: --> %s()\n", dev->name, __func__);
-
-       /*
-        * We should not be called if phy_type is zero.
-        */
-       if (lp->phy_type == 0)
-               return;
-
-       if (smc911x_phy_reset(dev, phyaddr)) {
-               printk("%s: PHY reset timed out\n", dev->name);
-               return;
-       }
-       spin_lock_irqsave(&lp->lock, flags);
-
-       /*
-        * Enable PHY Interrupts (for register 18)
-        * Interrupts listed here are enabled
-        */
-       SMC_SET_PHY_INT_MASK(lp, phyaddr, PHY_INT_MASK_ENERGY_ON_ |
-                PHY_INT_MASK_ANEG_COMP_ | PHY_INT_MASK_REMOTE_FAULT_ |
-                PHY_INT_MASK_LINK_DOWN_);
-
-       /* If the user requested no auto neg, then go set his request */
-       if (lp->mii.force_media) {
-               smc911x_phy_fixed(dev);
-               goto smc911x_phy_configure_exit;
-       }
-
-       /* Copy our capabilities from MII_BMSR to MII_ADVERTISE */
-       SMC_GET_PHY_BMSR(lp, phyaddr, my_phy_caps);
-       if (!(my_phy_caps & BMSR_ANEGCAPABLE)) {
-               printk(KERN_INFO "Auto negotiation NOT supported\n");
-               smc911x_phy_fixed(dev);
-               goto smc911x_phy_configure_exit;
-       }
-
-       /* CSMA capable w/ both pauses */
-       my_ad_caps = ADVERTISE_CSMA | ADVERTISE_PAUSE_CAP | ADVERTISE_PAUSE_ASYM;
-
-       if (my_phy_caps & BMSR_100BASE4)
-               my_ad_caps |= ADVERTISE_100BASE4;
-       if (my_phy_caps & BMSR_100FULL)
-               my_ad_caps |= ADVERTISE_100FULL;
-       if (my_phy_caps & BMSR_100HALF)
-               my_ad_caps |= ADVERTISE_100HALF;
-       if (my_phy_caps & BMSR_10FULL)
-               my_ad_caps |= ADVERTISE_10FULL;
-       if (my_phy_caps & BMSR_10HALF)
-               my_ad_caps |= ADVERTISE_10HALF;
-
-       /* Disable capabilities not selected by our user */
-       if (lp->ctl_rspeed != 100)
-               my_ad_caps &= ~(ADVERTISE_100BASE4|ADVERTISE_100FULL|ADVERTISE_100HALF);
-
-        if (!lp->ctl_rfduplx)
-               my_ad_caps &= ~(ADVERTISE_100FULL|ADVERTISE_10FULL);
-
-       /* Update our Auto-Neg Advertisement Register */
-       SMC_SET_PHY_MII_ADV(lp, phyaddr, my_ad_caps);
-       lp->mii.advertising = my_ad_caps;
-
-       /*
-        * Read the register back.       Without this, it appears that when
-        * auto-negotiation is restarted, sometimes it isn't ready and
-        * the link does not come up.
-        */
-       udelay(10);
-       SMC_GET_PHY_MII_ADV(lp, phyaddr, status);
-
-       DBG(SMC_DEBUG_MISC, "%s: phy caps=0x%04x\n", dev->name, my_phy_caps);
-       DBG(SMC_DEBUG_MISC, "%s: phy advertised caps=0x%04x\n", dev->name, my_ad_caps);
-
-       /* Restart auto-negotiation process in order to advertise my caps */
-       SMC_SET_PHY_BMCR(lp, phyaddr, BMCR_ANENABLE | BMCR_ANRESTART);
-
-       smc911x_phy_check_media(dev, 1);
-
-smc911x_phy_configure_exit:
-       spin_unlock_irqrestore(&lp->lock, flags);
-}
-
-/*
- * smc911x_phy_interrupt
- *
- * Purpose:  Handle interrupts relating to PHY register 18. This is
- *      called from the "hard" interrupt handler under our private spinlock.
- */
-static void smc911x_phy_interrupt(struct net_device *dev)
-{
-       struct smc911x_local *lp = netdev_priv(dev);
-       int phyaddr = lp->mii.phy_id;
-       int status;
-
-       DBG(SMC_DEBUG_FUNC, "%s: --> %s\n", dev->name, __func__);
-
-       if (lp->phy_type == 0)
-               return;
-
-       smc911x_phy_check_media(dev, 0);
-       /* read to clear status bits */
-       SMC_GET_PHY_INT_SRC(lp, phyaddr,status);
-       DBG(SMC_DEBUG_MISC, "%s: PHY interrupt status 0x%04x\n",
-               dev->name, status & 0xffff);
-       DBG(SMC_DEBUG_MISC, "%s: AFC_CFG 0x%08x\n",
-               dev->name, SMC_GET_AFC_CFG(lp));
-}
-
-/*--- END PHY CONTROL AND CONFIGURATION-------------------------------------*/
-
-/*
- * This is the main routine of the driver, to handle the device when
- * it needs some attention.
- */
-static irqreturn_t smc911x_interrupt(int irq, void *dev_id)
-{
-       struct net_device *dev = dev_id;
-       struct smc911x_local *lp = netdev_priv(dev);
-       unsigned int status, mask, timeout;
-       unsigned int rx_overrun=0, cr, pkts;
-       unsigned long flags;
-
-       DBG(SMC_DEBUG_FUNC, "%s: --> %s\n", dev->name, __func__);
-
-       spin_lock_irqsave(&lp->lock, flags);
-
-       /* Spurious interrupt check */
-       if ((SMC_GET_IRQ_CFG(lp) & (INT_CFG_IRQ_INT_ | INT_CFG_IRQ_EN_)) !=
-               (INT_CFG_IRQ_INT_ | INT_CFG_IRQ_EN_)) {
-               spin_unlock_irqrestore(&lp->lock, flags);
-               return IRQ_NONE;
-       }
-
-       mask = SMC_GET_INT_EN(lp);
-       SMC_SET_INT_EN(lp, 0);
-
-       /* set a timeout value, so I don't stay here forever */
-       timeout = 8;
-
-
-       do {
-               status = SMC_GET_INT(lp);
-
-               DBG(SMC_DEBUG_MISC, "%s: INT 0x%08x MASK 0x%08x OUTSIDE MASK 0x%08x\n",
-                       dev->name, status, mask, status & ~mask);
-
-               status &= mask;
-               if (!status)
-                       break;
-
-               /* Handle SW interrupt condition */
-               if (status & INT_STS_SW_INT_) {
-                       SMC_ACK_INT(lp, INT_STS_SW_INT_);
-                       mask &= ~INT_EN_SW_INT_EN_;
-               }
-               /* Handle various error conditions */
-               if (status & INT_STS_RXE_) {
-                       SMC_ACK_INT(lp, INT_STS_RXE_);
-                       dev->stats.rx_errors++;
-               }
-               if (status & INT_STS_RXDFH_INT_) {
-                       SMC_ACK_INT(lp, INT_STS_RXDFH_INT_);
-                       dev->stats.rx_dropped+=SMC_GET_RX_DROP(lp);
-                }
-               /* Undocumented interrupt-what is the right thing to do here? */
-               if (status & INT_STS_RXDF_INT_) {
-                       SMC_ACK_INT(lp, INT_STS_RXDF_INT_);
-               }
-
-               /* Rx Data FIFO exceeds set level */
-               if (status & INT_STS_RDFL_) {
-                       if (IS_REV_A(lp->revision)) {
-                               rx_overrun=1;
-                               SMC_GET_MAC_CR(lp, cr);
-                               cr &= ~MAC_CR_RXEN_;
-                               SMC_SET_MAC_CR(lp, cr);
-                               DBG(SMC_DEBUG_RX, "%s: RX overrun\n", dev->name);
-                               dev->stats.rx_errors++;
-                               dev->stats.rx_fifo_errors++;
-                       }
-                       SMC_ACK_INT(lp, INT_STS_RDFL_);
-               }
-               if (status & INT_STS_RDFO_) {
-                       if (!IS_REV_A(lp->revision)) {
-                               SMC_GET_MAC_CR(lp, cr);
-                               cr &= ~MAC_CR_RXEN_;
-                               SMC_SET_MAC_CR(lp, cr);
-                               rx_overrun=1;
-                               DBG(SMC_DEBUG_RX, "%s: RX overrun\n", dev->name);
-                               dev->stats.rx_errors++;
-                               dev->stats.rx_fifo_errors++;
-                       }
-                       SMC_ACK_INT(lp, INT_STS_RDFO_);
-               }
-               /* Handle receive condition */
-               if ((status & INT_STS_RSFL_) || rx_overrun) {
-                       unsigned int fifo;
-                       DBG(SMC_DEBUG_RX, "%s: RX irq\n", dev->name);
-                       fifo = SMC_GET_RX_FIFO_INF(lp);
-                       pkts = (fifo & RX_FIFO_INF_RXSUSED_) >> 16;
-                       DBG(SMC_DEBUG_RX, "%s: Rx FIFO pkts %d, bytes %d\n",
-                               dev->name, pkts, fifo & 0xFFFF );
-                       if (pkts != 0) {
-#ifdef SMC_USE_DMA
-                               unsigned int fifo;
-                               if (lp->rxdma_active){
-                                       DBG(SMC_DEBUG_RX | SMC_DEBUG_DMA,
-                                               "%s: RX DMA active\n", dev->name);
-                                       /* The DMA is already running so up the IRQ threshold */
-                                       fifo = SMC_GET_FIFO_INT(lp) & ~0xFF;
-                                       fifo |= pkts & 0xFF;
-                                       DBG(SMC_DEBUG_RX,
-                                               "%s: Setting RX stat FIFO threshold to %d\n",
-                                               dev->name, fifo & 0xff);
-                                       SMC_SET_FIFO_INT(lp, fifo);
-                               } else
-#endif
-                               smc911x_rcv(dev);
-                       }
-                       SMC_ACK_INT(lp, INT_STS_RSFL_);
-               }
-               /* Handle transmit FIFO available */
-               if (status & INT_STS_TDFA_) {
-                       DBG(SMC_DEBUG_TX, "%s: TX data FIFO space available irq\n", dev->name);
-                       SMC_SET_FIFO_TDA(lp, 0xFF);
-                       lp->tx_throttle = 0;
-#ifdef SMC_USE_DMA
-                       if (!lp->txdma_active)
-#endif
-                               netif_wake_queue(dev);
-                       SMC_ACK_INT(lp, INT_STS_TDFA_);
-               }
-               /* Handle transmit done condition */
-#if 1
-               if (status & (INT_STS_TSFL_ | INT_STS_GPT_INT_)) {
-                       DBG(SMC_DEBUG_TX | SMC_DEBUG_MISC,
-                               "%s: Tx stat FIFO limit (%d) /GPT irq\n",
-                               dev->name, (SMC_GET_FIFO_INT(lp) & 0x00ff0000) >> 16);
-                       smc911x_tx(dev);
-                       SMC_SET_GPT_CFG(lp, GPT_CFG_TIMER_EN_ | 10000);
-                       SMC_ACK_INT(lp, INT_STS_TSFL_);
-                       SMC_ACK_INT(lp, INT_STS_TSFL_ | INT_STS_GPT_INT_);
-               }
-#else
-               if (status & INT_STS_TSFL_) {
-                       DBG(SMC_DEBUG_TX, "%s: TX status FIFO limit (%d) irq\n", dev->name, );
-                       smc911x_tx(dev);
-                       SMC_ACK_INT(lp, INT_STS_TSFL_);
-               }
-
-               if (status & INT_STS_GPT_INT_) {
-                       DBG(SMC_DEBUG_RX, "%s: IRQ_CFG 0x%08x FIFO_INT 0x%08x RX_CFG 0x%08x\n",
-                               dev->name,
-                               SMC_GET_IRQ_CFG(lp),
-                               SMC_GET_FIFO_INT(lp),
-                               SMC_GET_RX_CFG(lp));
-                       DBG(SMC_DEBUG_RX, "%s: Rx Stat FIFO Used 0x%02x "
-                               "Data FIFO Used 0x%04x Stat FIFO 0x%08x\n",
-                               dev->name,
-                               (SMC_GET_RX_FIFO_INF(lp) & 0x00ff0000) >> 16,
-                               SMC_GET_RX_FIFO_INF(lp) & 0xffff,
-                               SMC_GET_RX_STS_FIFO_PEEK(lp));
-                       SMC_SET_GPT_CFG(lp, GPT_CFG_TIMER_EN_ | 10000);
-                       SMC_ACK_INT(lp, INT_STS_GPT_INT_);
-               }
-#endif
-
-               /* Handle PHY interrupt condition */
-               if (status & INT_STS_PHY_INT_) {
-                       DBG(SMC_DEBUG_MISC, "%s: PHY irq\n", dev->name);
-                       smc911x_phy_interrupt(dev);
-                       SMC_ACK_INT(lp, INT_STS_PHY_INT_);
-               }
-       } while (--timeout);
-
-       /* restore mask state */
-       SMC_SET_INT_EN(lp, mask);
-
-       DBG(SMC_DEBUG_MISC, "%s: Interrupt done (%d loops)\n",
-               dev->name, 8-timeout);
-
-       spin_unlock_irqrestore(&lp->lock, flags);
-
-       return IRQ_HANDLED;
-}
-
-#ifdef SMC_USE_DMA
-static void
-smc911x_tx_dma_irq(int dma, void *data)
-{
-       struct net_device *dev = (struct net_device *)data;
-       struct smc911x_local *lp = netdev_priv(dev);
-       struct sk_buff *skb = lp->current_tx_skb;
-       unsigned long flags;
-
-       DBG(SMC_DEBUG_FUNC, "%s: --> %s\n", dev->name, __func__);
-
-       DBG(SMC_DEBUG_TX | SMC_DEBUG_DMA, "%s: TX DMA irq handler\n", dev->name);
-       /* Clear the DMA interrupt sources */
-       SMC_DMA_ACK_IRQ(dev, dma);
-       BUG_ON(skb == NULL);
-       dma_unmap_single(NULL, tx_dmabuf, tx_dmalen, DMA_TO_DEVICE);
-       dev->trans_start = jiffies;
-       dev_kfree_skb_irq(skb);
-       lp->current_tx_skb = NULL;
-       if (lp->pending_tx_skb != NULL)
-               smc911x_hardware_send_pkt(dev);
-       else {
-               DBG(SMC_DEBUG_TX | SMC_DEBUG_DMA,
-                       "%s: No pending Tx packets. DMA disabled\n", dev->name);
-               spin_lock_irqsave(&lp->lock, flags);
-               lp->txdma_active = 0;
-               if (!lp->tx_throttle) {
-                       netif_wake_queue(dev);
-               }
-               spin_unlock_irqrestore(&lp->lock, flags);
-       }
-
-       DBG(SMC_DEBUG_TX | SMC_DEBUG_DMA,
-               "%s: TX DMA irq completed\n", dev->name);
-}
-static void
-smc911x_rx_dma_irq(int dma, void *data)
-{
-       struct net_device *dev = (struct net_device *)data;
-       unsigned long ioaddr = dev->base_addr;
-       struct smc911x_local *lp = netdev_priv(dev);
-       struct sk_buff *skb = lp->current_rx_skb;
-       unsigned long flags;
-       unsigned int pkts;
-
-       DBG(SMC_DEBUG_FUNC, "%s: --> %s\n", dev->name, __func__);
-       DBG(SMC_DEBUG_RX | SMC_DEBUG_DMA, "%s: RX DMA irq handler\n", dev->name);
-       /* Clear the DMA interrupt sources */
-       SMC_DMA_ACK_IRQ(dev, dma);
-       dma_unmap_single(NULL, rx_dmabuf, rx_dmalen, DMA_FROM_DEVICE);
-       BUG_ON(skb == NULL);
-       lp->current_rx_skb = NULL;
-       PRINT_PKT(skb->data, skb->len);
-       skb->protocol = eth_type_trans(skb, dev);
-       dev->stats.rx_packets++;
-       dev->stats.rx_bytes += skb->len;
-       netif_rx(skb);
-
-       spin_lock_irqsave(&lp->lock, flags);
-       pkts = (SMC_GET_RX_FIFO_INF(lp) & RX_FIFO_INF_RXSUSED_) >> 16;
-       if (pkts != 0) {
-               smc911x_rcv(dev);
-       }else {
-               lp->rxdma_active = 0;
-       }
-       spin_unlock_irqrestore(&lp->lock, flags);
-       DBG(SMC_DEBUG_RX | SMC_DEBUG_DMA,
-               "%s: RX DMA irq completed. DMA RX FIFO PKTS %d\n",
-               dev->name, pkts);
-}
-#endif  /* SMC_USE_DMA */
-
-#ifdef CONFIG_NET_POLL_CONTROLLER
-/*
- * Polling receive - used by netconsole and other diagnostic tools
- * to allow network i/o with interrupts disabled.
- */
-static void smc911x_poll_controller(struct net_device *dev)
-{
-       disable_irq(dev->irq);
-       smc911x_interrupt(dev->irq, dev);
-       enable_irq(dev->irq);
-}
-#endif
-
-/* Our watchdog timed out. Called by the networking layer */
-static void smc911x_timeout(struct net_device *dev)
-{
-       struct smc911x_local *lp = netdev_priv(dev);
-       int status, mask;
-       unsigned long flags;
-
-       DBG(SMC_DEBUG_FUNC, "%s: --> %s\n", dev->name, __func__);
-
-       spin_lock_irqsave(&lp->lock, flags);
-       status = SMC_GET_INT(lp);
-       mask = SMC_GET_INT_EN(lp);
-       spin_unlock_irqrestore(&lp->lock, flags);
-       DBG(SMC_DEBUG_MISC, "%s: INT 0x%02x MASK 0x%02x\n",
-               dev->name, status, mask);
-
-       /* Dump the current TX FIFO contents and restart */
-       mask = SMC_GET_TX_CFG(lp);
-       SMC_SET_TX_CFG(lp, mask | TX_CFG_TXS_DUMP_ | TX_CFG_TXD_DUMP_);
-       /*
-        * Reconfiguring the PHY doesn't seem like a bad idea here, but
-        * smc911x_phy_configure() calls msleep() which calls schedule_timeout()
-        * which calls schedule().       Hence we use a work queue.
-        */
-       if (lp->phy_type != 0)
-               schedule_work(&lp->phy_configure);
-
-       /* We can accept TX packets again */
-       dev->trans_start = jiffies; /* prevent tx timeout */
-       netif_wake_queue(dev);
-}
-
-/*
- * This routine will, depending on the values passed to it,
- * either make it accept multicast packets, go into
- * promiscuous mode (for TCPDUMP and cousins) or accept
- * a select set of multicast packets
- */
-static void smc911x_set_multicast_list(struct net_device *dev)
-{
-       struct smc911x_local *lp = netdev_priv(dev);
-       unsigned int multicast_table[2];
-       unsigned int mcr, update_multicast = 0;
-       unsigned long flags;
-
-       DBG(SMC_DEBUG_FUNC, "%s: --> %s\n", dev->name, __func__);
-
-       spin_lock_irqsave(&lp->lock, flags);
-       SMC_GET_MAC_CR(lp, mcr);
-       spin_unlock_irqrestore(&lp->lock, flags);
-
-       if (dev->flags & IFF_PROMISC) {
-
-               DBG(SMC_DEBUG_MISC, "%s: RCR_PRMS\n", dev->name);
-               mcr |= MAC_CR_PRMS_;
-       }
-       /*
-        * Here, I am setting this to accept all multicast packets.
-        * I don't need to zero the multicast table, because the flag is
-        * checked before the table is
-        */
-       else if (dev->flags & IFF_ALLMULTI || netdev_mc_count(dev) > 16) {
-               DBG(SMC_DEBUG_MISC, "%s: RCR_ALMUL\n", dev->name);
-               mcr |= MAC_CR_MCPAS_;
-       }
-
-       /*
-        * This sets the internal hardware table to filter out unwanted
-        * multicast packets before they take up memory.
-        *
-        * The SMC chip uses a hash table where the high 6 bits of the CRC of
-        * address are the offset into the table.       If that bit is 1, then the
-        * multicast packet is accepted.  Otherwise, it's dropped silently.
-        *
-        * To use the 6 bits as an offset into the table, the high 1 bit is
-        * the number of the 32 bit register, while the low 5 bits are the bit
-        * within that register.
-        */
-       else if (!netdev_mc_empty(dev)) {
-               struct netdev_hw_addr *ha;
-
-               /* Set the Hash perfec mode */
-               mcr |= MAC_CR_HPFILT_;
-
-               /* start with a table of all zeros: reject all */
-               memset(multicast_table, 0, sizeof(multicast_table));
-
-               netdev_for_each_mc_addr(ha, dev) {
-                       u32 position;
-
-                       /* upper 6 bits are used as hash index */
-                       position = ether_crc(ETH_ALEN, ha->addr)>>26;
-
-                       multicast_table[position>>5] |= 1 << (position&0x1f);
-               }
-
-               /* be sure I get rid of flags I might have set */
-               mcr &= ~(MAC_CR_PRMS_ | MAC_CR_MCPAS_);
-
-               /* now, the table can be loaded into the chipset */
-               update_multicast = 1;
-       } else   {
-               DBG(SMC_DEBUG_MISC, "%s: ~(MAC_CR_PRMS_|MAC_CR_MCPAS_)\n",
-                       dev->name);
-               mcr &= ~(MAC_CR_PRMS_ | MAC_CR_MCPAS_);
-
-               /*
-                * since I'm disabling all multicast entirely, I need to
-                * clear the multicast list
-                */
-               memset(multicast_table, 0, sizeof(multicast_table));
-               update_multicast = 1;
-       }
-
-       spin_lock_irqsave(&lp->lock, flags);
-       SMC_SET_MAC_CR(lp, mcr);
-       if (update_multicast) {
-               DBG(SMC_DEBUG_MISC,
-                       "%s: update mcast hash table 0x%08x 0x%08x\n",
-                       dev->name, multicast_table[0], multicast_table[1]);
-               SMC_SET_HASHL(lp, multicast_table[0]);
-               SMC_SET_HASHH(lp, multicast_table[1]);
-       }
-       spin_unlock_irqrestore(&lp->lock, flags);
-}
-
-
-/*
- * Open and Initialize the board
- *
- * Set up everything, reset the card, etc..
- */
-static int
-smc911x_open(struct net_device *dev)
-{
-       struct smc911x_local *lp = netdev_priv(dev);
-
-       DBG(SMC_DEBUG_FUNC, "%s: --> %s\n", dev->name, __func__);
-
-       /*
-        * Check that the address is valid.  If its not, refuse
-        * to bring the device up.       The user must specify an
-        * address using ifconfig eth0 hw ether xx:xx:xx:xx:xx:xx
-        */
-       if (!is_valid_ether_addr(dev->dev_addr)) {
-               PRINTK("%s: no valid ethernet hw addr\n", __func__);
-               return -EINVAL;
-       }
-
-       /* reset the hardware */
-       smc911x_reset(dev);
-
-       /* Configure the PHY, initialize the link state */
-       smc911x_phy_configure(&lp->phy_configure);
-
-       /* Turn on Tx + Rx */
-       smc911x_enable(dev);
-
-       netif_start_queue(dev);
-
-       return 0;
-}
-
-/*
- * smc911x_close
- *
- * this makes the board clean up everything that it can
- * and not talk to the outside world.   Caused by
- * an 'ifconfig ethX down'
- */
-static int smc911x_close(struct net_device *dev)
-{
-       struct smc911x_local *lp = netdev_priv(dev);
-
-       DBG(SMC_DEBUG_FUNC, "%s: --> %s\n", dev->name, __func__);
-
-       netif_stop_queue(dev);
-       netif_carrier_off(dev);
-
-       /* clear everything */
-       smc911x_shutdown(dev);
-
-       if (lp->phy_type != 0) {
-               /* We need to ensure that no calls to
-                * smc911x_phy_configure are pending.
-                */
-               cancel_work_sync(&lp->phy_configure);
-               smc911x_phy_powerdown(dev, lp->mii.phy_id);
-       }
-
-       if (lp->pending_tx_skb) {
-               dev_kfree_skb(lp->pending_tx_skb);
-               lp->pending_tx_skb = NULL;
-       }
-
-       return 0;
-}
-
-/*
- * Ethtool support
- */
-static int
-smc911x_ethtool_getsettings(struct net_device *dev, struct ethtool_cmd *cmd)
-{
-       struct smc911x_local *lp = netdev_priv(dev);
-       int ret, status;
-       unsigned long flags;
-
-       DBG(SMC_DEBUG_FUNC, "%s: --> %s\n", dev->name, __func__);
-       cmd->maxtxpkt = 1;
-       cmd->maxrxpkt = 1;
-
-       if (lp->phy_type != 0) {
-               spin_lock_irqsave(&lp->lock, flags);
-               ret = mii_ethtool_gset(&lp->mii, cmd);
-               spin_unlock_irqrestore(&lp->lock, flags);
-       } else {
-               cmd->supported = SUPPORTED_10baseT_Half |
-                               SUPPORTED_10baseT_Full |
-                               SUPPORTED_TP | SUPPORTED_AUI;
-
-               if (lp->ctl_rspeed == 10)
-                       ethtool_cmd_speed_set(cmd, SPEED_10);
-               else if (lp->ctl_rspeed == 100)
-                       ethtool_cmd_speed_set(cmd, SPEED_100);
-
-               cmd->autoneg = AUTONEG_DISABLE;
-               if (lp->mii.phy_id==1)
-                       cmd->transceiver = XCVR_INTERNAL;
-               else
-                       cmd->transceiver = XCVR_EXTERNAL;
-               cmd->port = 0;
-               SMC_GET_PHY_SPECIAL(lp, lp->mii.phy_id, status);
-               cmd->duplex =
-                       (status & (PHY_SPECIAL_SPD_10FULL_ | PHY_SPECIAL_SPD_100FULL_)) ?
-                               DUPLEX_FULL : DUPLEX_HALF;
-               ret = 0;
-       }
-
-       return ret;
-}
-
-static int
-smc911x_ethtool_setsettings(struct net_device *dev, struct ethtool_cmd *cmd)
-{
-       struct smc911x_local *lp = netdev_priv(dev);
-       int ret;
-       unsigned long flags;
-
-       if (lp->phy_type != 0) {
-               spin_lock_irqsave(&lp->lock, flags);
-               ret = mii_ethtool_sset(&lp->mii, cmd);
-               spin_unlock_irqrestore(&lp->lock, flags);
-       } else {
-               if (cmd->autoneg != AUTONEG_DISABLE ||
-                       cmd->speed != SPEED_10 ||
-                       (cmd->duplex != DUPLEX_HALF && cmd->duplex != DUPLEX_FULL) ||
-                       (cmd->port != PORT_TP && cmd->port != PORT_AUI))
-                       return -EINVAL;
-
-               lp->ctl_rfduplx = cmd->duplex == DUPLEX_FULL;
-
-               ret = 0;
-       }
-
-       return ret;
-}
-
-static void
-smc911x_ethtool_getdrvinfo(struct net_device *dev, struct ethtool_drvinfo *info)
-{
-       strncpy(info->driver, CARDNAME, sizeof(info->driver));
-       strncpy(info->version, version, sizeof(info->version));
-       strncpy(info->bus_info, dev_name(dev->dev.parent), sizeof(info->bus_info));
-}
-
-static int smc911x_ethtool_nwayreset(struct net_device *dev)
-{
-       struct smc911x_local *lp = netdev_priv(dev);
-       int ret = -EINVAL;
-       unsigned long flags;
-
-       if (lp->phy_type != 0) {
-               spin_lock_irqsave(&lp->lock, flags);
-               ret = mii_nway_restart(&lp->mii);
-               spin_unlock_irqrestore(&lp->lock, flags);
-       }
-
-       return ret;
-}
-
-static u32 smc911x_ethtool_getmsglevel(struct net_device *dev)
-{
-       struct smc911x_local *lp = netdev_priv(dev);
-       return lp->msg_enable;
-}
-
-static void smc911x_ethtool_setmsglevel(struct net_device *dev, u32 level)
-{
-       struct smc911x_local *lp = netdev_priv(dev);
-       lp->msg_enable = level;
-}
-
-static int smc911x_ethtool_getregslen(struct net_device *dev)
-{
-       /* System regs + MAC regs + PHY regs */
-       return (((E2P_CMD - ID_REV)/4 + 1) +
-                       (WUCSR - MAC_CR)+1 + 32) * sizeof(u32);
-}
-
-static void smc911x_ethtool_getregs(struct net_device *dev,
-                                                                                struct ethtool_regs* regs, void *buf)
-{
-       struct smc911x_local *lp = netdev_priv(dev);
-       unsigned long flags;
-       u32 reg,i,j=0;
-       u32 *data = (u32*)buf;
-
-       regs->version = lp->version;
-       for(i=ID_REV;i<=E2P_CMD;i+=4) {
-               data[j++] = SMC_inl(lp, i);
-       }
-       for(i=MAC_CR;i<=WUCSR;i++) {
-               spin_lock_irqsave(&lp->lock, flags);
-               SMC_GET_MAC_CSR(lp, i, reg);
-               spin_unlock_irqrestore(&lp->lock, flags);
-               data[j++] = reg;
-       }
-       for(i=0;i<=31;i++) {
-               spin_lock_irqsave(&lp->lock, flags);
-               SMC_GET_MII(lp, i, lp->mii.phy_id, reg);
-               spin_unlock_irqrestore(&lp->lock, flags);
-               data[j++] = reg & 0xFFFF;
-       }
-}
-
-static int smc911x_ethtool_wait_eeprom_ready(struct net_device *dev)
-{
-       struct smc911x_local *lp = netdev_priv(dev);
-       unsigned int timeout;
-       int e2p_cmd;
-
-       e2p_cmd = SMC_GET_E2P_CMD(lp);
-       for(timeout=10;(e2p_cmd & E2P_CMD_EPC_BUSY_) && timeout; timeout--) {
-               if (e2p_cmd & E2P_CMD_EPC_TIMEOUT_) {
-                       PRINTK("%s: %s timeout waiting for EEPROM to respond\n",
-                               dev->name, __func__);
-                       return -EFAULT;
-               }
-               mdelay(1);
-               e2p_cmd = SMC_GET_E2P_CMD(lp);
-       }
-       if (timeout == 0) {
-               PRINTK("%s: %s timeout waiting for EEPROM CMD not busy\n",
-                       dev->name, __func__);
-               return -ETIMEDOUT;
-       }
-       return 0;
-}
-
-static inline int smc911x_ethtool_write_eeprom_cmd(struct net_device *dev,
-                                                                                                       int cmd, int addr)
-{
-       struct smc911x_local *lp = netdev_priv(dev);
-       int ret;
-
-       if ((ret = smc911x_ethtool_wait_eeprom_ready(dev))!=0)
-               return ret;
-       SMC_SET_E2P_CMD(lp, E2P_CMD_EPC_BUSY_ |
-               ((cmd) & (0x7<<28)) |
-               ((addr) & 0xFF));
-       return 0;
-}
-
-static inline int smc911x_ethtool_read_eeprom_byte(struct net_device *dev,
-                                                                                                       u8 *data)
-{
-       struct smc911x_local *lp = netdev_priv(dev);
-       int ret;
-
-       if ((ret = smc911x_ethtool_wait_eeprom_ready(dev))!=0)
-               return ret;
-       *data = SMC_GET_E2P_DATA(lp);
-       return 0;
-}
-
-static inline int smc911x_ethtool_write_eeprom_byte(struct net_device *dev,
-                                                                                                        u8 data)
-{
-       struct smc911x_local *lp = netdev_priv(dev);
-       int ret;
-
-       if ((ret = smc911x_ethtool_wait_eeprom_ready(dev))!=0)
-               return ret;
-       SMC_SET_E2P_DATA(lp, data);
-       return 0;
-}
-
-static int smc911x_ethtool_geteeprom(struct net_device *dev,
-                                                                         struct ethtool_eeprom *eeprom, u8 *data)
-{
-       u8 eebuf[SMC911X_EEPROM_LEN];
-       int i, ret;
-
-       for(i=0;i<SMC911X_EEPROM_LEN;i++) {
-               if ((ret=smc911x_ethtool_write_eeprom_cmd(dev, E2P_CMD_EPC_CMD_READ_, i ))!=0)
-                       return ret;
-               if ((ret=smc911x_ethtool_read_eeprom_byte(dev, &eebuf[i]))!=0)
-                       return ret;
-               }
-       memcpy(data, eebuf+eeprom->offset, eeprom->len);
-       return 0;
-}
-
-static int smc911x_ethtool_seteeprom(struct net_device *dev,
-                                                                          struct ethtool_eeprom *eeprom, u8 *data)
-{
-       int i, ret;
-
-       /* Enable erase */
-       if ((ret=smc911x_ethtool_write_eeprom_cmd(dev, E2P_CMD_EPC_CMD_EWEN_, 0 ))!=0)
-               return ret;
-       for(i=eeprom->offset;i<(eeprom->offset+eeprom->len);i++) {
-               /* erase byte */
-               if ((ret=smc911x_ethtool_write_eeprom_cmd(dev, E2P_CMD_EPC_CMD_ERASE_, i ))!=0)
-                       return ret;
-               /* write byte */
-               if ((ret=smc911x_ethtool_write_eeprom_byte(dev, *data))!=0)
-                        return ret;
-               if ((ret=smc911x_ethtool_write_eeprom_cmd(dev, E2P_CMD_EPC_CMD_WRITE_, i ))!=0)
-                       return ret;
-               }
-        return 0;
-}
-
-static int smc911x_ethtool_geteeprom_len(struct net_device *dev)
-{
-        return SMC911X_EEPROM_LEN;
-}
-
-static const struct ethtool_ops smc911x_ethtool_ops = {
-       .get_settings    = smc911x_ethtool_getsettings,
-       .set_settings    = smc911x_ethtool_setsettings,
-       .get_drvinfo     = smc911x_ethtool_getdrvinfo,
-       .get_msglevel    = smc911x_ethtool_getmsglevel,
-       .set_msglevel    = smc911x_ethtool_setmsglevel,
-       .nway_reset = smc911x_ethtool_nwayreset,
-       .get_link        = ethtool_op_get_link,
-       .get_regs_len    = smc911x_ethtool_getregslen,
-       .get_regs        = smc911x_ethtool_getregs,
-       .get_eeprom_len = smc911x_ethtool_geteeprom_len,
-       .get_eeprom = smc911x_ethtool_geteeprom,
-       .set_eeprom = smc911x_ethtool_seteeprom,
-};
-
-/*
- * smc911x_findirq
- *
- * This routine has a simple purpose -- make the SMC chip generate an
- * interrupt, so an auto-detect routine can detect it, and find the IRQ,
- */
-static int __devinit smc911x_findirq(struct net_device *dev)
-{
-       struct smc911x_local *lp = netdev_priv(dev);
-       int timeout = 20;
-       unsigned long cookie;
-
-       DBG(SMC_DEBUG_FUNC, "--> %s\n", __func__);
-
-       cookie = probe_irq_on();
-
-       /*
-        * Force a SW interrupt
-        */
-
-       SMC_SET_INT_EN(lp, INT_EN_SW_INT_EN_);
-
-       /*
-        * Wait until positive that the interrupt has been generated
-        */
-       do {
-               int int_status;
-               udelay(10);
-               int_status = SMC_GET_INT_EN(lp);
-               if (int_status & INT_EN_SW_INT_EN_)
-                        break;         /* got the interrupt */
-       } while (--timeout);
-
-       /*
-        * there is really nothing that I can do here if timeout fails,
-        * as autoirq_report will return a 0 anyway, which is what I
-        * want in this case.    Plus, the clean up is needed in both
-        * cases.
-        */
-
-       /* and disable all interrupts again */
-       SMC_SET_INT_EN(lp, 0);
-
-       /* and return what I found */
-       return probe_irq_off(cookie);
-}
-
-static const struct net_device_ops smc911x_netdev_ops = {
-       .ndo_open               = smc911x_open,
-       .ndo_stop               = smc911x_close,
-       .ndo_start_xmit         = smc911x_hard_start_xmit,
-       .ndo_tx_timeout         = smc911x_timeout,
-       .ndo_set_multicast_list = smc911x_set_multicast_list,
-       .ndo_change_mtu         = eth_change_mtu,
-       .ndo_validate_addr      = eth_validate_addr,
-       .ndo_set_mac_address    = eth_mac_addr,
-#ifdef CONFIG_NET_POLL_CONTROLLER
-       .ndo_poll_controller    = smc911x_poll_controller,
-#endif
-};
-
-/*
- * Function: smc911x_probe(unsigned long ioaddr)
- *
- * Purpose:
- *      Tests to see if a given ioaddr points to an SMC911x chip.
- *      Returns a 0 on success
- *
- * Algorithm:
- *      (1) see if the endian word is OK
- *      (1) see if I recognize the chip ID in the appropriate register
- *
- * Here I do typical initialization tasks.
- *
- * o  Initialize the structure if needed
- * o  print out my vanity message if not done so already
- * o  print out what type of hardware is detected
- * o  print out the ethernet address
- * o  find the IRQ
- * o  set up my private data
- * o  configure the dev structure with my subroutines
- * o  actually GRAB the irq.
- * o  GRAB the region
- */
-static int __devinit smc911x_probe(struct net_device *dev)
-{
-       struct smc911x_local *lp = netdev_priv(dev);
-       int i, retval;
-       unsigned int val, chip_id, revision;
-       const char *version_string;
-       unsigned long irq_flags;
-
-       DBG(SMC_DEBUG_FUNC, "%s: --> %s\n", dev->name, __func__);
-
-       /* First, see if the endian word is recognized */
-       val = SMC_GET_BYTE_TEST(lp);
-       DBG(SMC_DEBUG_MISC, "%s: endian probe returned 0x%04x\n", CARDNAME, val);
-       if (val != 0x87654321) {
-               printk(KERN_ERR "Invalid chip endian 0x%08x\n",val);
-               retval = -ENODEV;
-               goto err_out;
-       }
-
-       /*
-        * check if the revision register is something that I
-        * recognize.   These might need to be added to later,
-        * as future revisions could be added.
-        */
-       chip_id = SMC_GET_PN(lp);
-       DBG(SMC_DEBUG_MISC, "%s: id probe returned 0x%04x\n", CARDNAME, chip_id);
-       for(i=0;chip_ids[i].id != 0; i++) {
-               if (chip_ids[i].id == chip_id) break;
-       }
-       if (!chip_ids[i].id) {
-               printk(KERN_ERR "Unknown chip ID %04x\n", chip_id);
-               retval = -ENODEV;
-               goto err_out;
-       }
-       version_string = chip_ids[i].name;
-
-       revision = SMC_GET_REV(lp);
-       DBG(SMC_DEBUG_MISC, "%s: revision = 0x%04x\n", CARDNAME, revision);
-
-       /* At this point I'll assume that the chip is an SMC911x. */
-       DBG(SMC_DEBUG_MISC, "%s: Found a %s\n", CARDNAME, chip_ids[i].name);
-
-       /* Validate the TX FIFO size requested */
-       if ((tx_fifo_kb < 2) || (tx_fifo_kb > 14)) {
-               printk(KERN_ERR "Invalid TX FIFO size requested %d\n", tx_fifo_kb);
-               retval = -EINVAL;
-               goto err_out;
-       }
-
-       /* fill in some of the fields */
-       lp->version = chip_ids[i].id;
-       lp->revision = revision;
-       lp->tx_fifo_kb = tx_fifo_kb;
-       /* Reverse calculate the RX FIFO size from the TX */
-       lp->tx_fifo_size=(lp->tx_fifo_kb<<10) - 512;
-       lp->rx_fifo_size= ((0x4000 - 512 - lp->tx_fifo_size) / 16) * 15;
-
-       /* Set the automatic flow control values */
-       switch(lp->tx_fifo_kb) {
-               /*
-                *       AFC_HI is about ((Rx Data Fifo Size)*2/3)/64
-                *       AFC_LO is AFC_HI/2
-                *       BACK_DUR is about 5uS*(AFC_LO) rounded down
-                */
-               case 2:/* 13440 Rx Data Fifo Size */
-                       lp->afc_cfg=0x008C46AF;break;
-               case 3:/* 12480 Rx Data Fifo Size */
-                       lp->afc_cfg=0x0082419F;break;
-               case 4:/* 11520 Rx Data Fifo Size */
-                       lp->afc_cfg=0x00783C9F;break;
-               case 5:/* 10560 Rx Data Fifo Size */
-                       lp->afc_cfg=0x006E374F;break;
-               case 6:/* 9600 Rx Data Fifo Size */
-                       lp->afc_cfg=0x0064328F;break;
-               case 7:/* 8640 Rx Data Fifo Size */
-                       lp->afc_cfg=0x005A2D7F;break;
-               case 8:/* 7680 Rx Data Fifo Size */
-                       lp->afc_cfg=0x0050287F;break;
-               case 9:/* 6720 Rx Data Fifo Size */
-                       lp->afc_cfg=0x0046236F;break;
-               case 10:/* 5760 Rx Data Fifo Size */
-                       lp->afc_cfg=0x003C1E6F;break;
-               case 11:/* 4800 Rx Data Fifo Size */
-                       lp->afc_cfg=0x0032195F;break;
-               /*
-                *       AFC_HI is ~1520 bytes less than RX Data Fifo Size
-                *       AFC_LO is AFC_HI/2
-                *       BACK_DUR is about 5uS*(AFC_LO) rounded down
-                */
-               case 12:/* 3840 Rx Data Fifo Size */
-                       lp->afc_cfg=0x0024124F;break;
-               case 13:/* 2880 Rx Data Fifo Size */
-                       lp->afc_cfg=0x0015073F;break;
-               case 14:/* 1920 Rx Data Fifo Size */
-                       lp->afc_cfg=0x0006032F;break;
-                default:
-                        PRINTK("%s: ERROR -- no AFC_CFG setting found",
-                               dev->name);
-                        break;
-       }
-
-       DBG(SMC_DEBUG_MISC | SMC_DEBUG_TX | SMC_DEBUG_RX,
-               "%s: tx_fifo %d rx_fifo %d afc_cfg 0x%08x\n", CARDNAME,
-               lp->tx_fifo_size, lp->rx_fifo_size, lp->afc_cfg);
-
-       spin_lock_init(&lp->lock);
-
-       /* Get the MAC address */
-       SMC_GET_MAC_ADDR(lp, dev->dev_addr);
-
-       /* now, reset the chip, and put it into a known state */
-       smc911x_reset(dev);
-
-       /*
-        * If dev->irq is 0, then the device has to be banged on to see
-        * what the IRQ is.
-        *
-        * Specifying an IRQ is done with the assumption that the user knows
-        * what (s)he is doing.  No checking is done!!!!
-        */
-       if (dev->irq < 1) {
-               int trials;
-
-               trials = 3;
-               while (trials--) {
-                       dev->irq = smc911x_findirq(dev);
-                       if (dev->irq)
-                               break;
-                       /* kick the card and try again */
-                       smc911x_reset(dev);
-               }
-       }
-       if (dev->irq == 0) {
-               printk("%s: Couldn't autodetect your IRQ. Use irq=xx.\n",
-                       dev->name);
-               retval = -ENODEV;
-               goto err_out;
-       }
-       dev->irq = irq_canonicalize(dev->irq);
-
-       /* Fill in the fields of the device structure with ethernet values. */
-       ether_setup(dev);
-
-       dev->netdev_ops = &smc911x_netdev_ops;
-       dev->watchdog_timeo = msecs_to_jiffies(watchdog);
-       dev->ethtool_ops = &smc911x_ethtool_ops;
-
-       INIT_WORK(&lp->phy_configure, smc911x_phy_configure);
-       lp->mii.phy_id_mask = 0x1f;
-       lp->mii.reg_num_mask = 0x1f;
-       lp->mii.force_media = 0;
-       lp->mii.full_duplex = 0;
-       lp->mii.dev = dev;
-       lp->mii.mdio_read = smc911x_phy_read;
-       lp->mii.mdio_write = smc911x_phy_write;
-
-       /*
-        * Locate the phy, if any.
-        */
-       smc911x_phy_detect(dev);
-
-       /* Set default parameters */
-       lp->msg_enable = NETIF_MSG_LINK;
-       lp->ctl_rfduplx = 1;
-       lp->ctl_rspeed = 100;
-
-#ifdef SMC_DYNAMIC_BUS_CONFIG
-       irq_flags = lp->cfg.irq_flags;
-#else
-       irq_flags = IRQF_SHARED | SMC_IRQ_SENSE;
-#endif
-
-       /* Grab the IRQ */
-       retval = request_irq(dev->irq, smc911x_interrupt,
-                            irq_flags, dev->name, dev);
-       if (retval)
-               goto err_out;
-
-#ifdef SMC_USE_DMA
-       lp->rxdma = SMC_DMA_REQUEST(dev, smc911x_rx_dma_irq);
-       lp->txdma = SMC_DMA_REQUEST(dev, smc911x_tx_dma_irq);
-       lp->rxdma_active = 0;
-       lp->txdma_active = 0;
-       dev->dma = lp->rxdma;
-#endif
-
-       retval = register_netdev(dev);
-       if (retval == 0) {
-               /* now, print out the card info, in a short format.. */
-               printk("%s: %s (rev %d) at %#lx IRQ %d",
-                       dev->name, version_string, lp->revision,
-                       dev->base_addr, dev->irq);
-
-#ifdef SMC_USE_DMA
-               if (lp->rxdma != -1)
-                       printk(" RXDMA %d ", lp->rxdma);
-
-               if (lp->txdma != -1)
-                       printk("TXDMA %d", lp->txdma);
-#endif
-               printk("\n");
-               if (!is_valid_ether_addr(dev->dev_addr)) {
-                       printk("%s: Invalid ethernet MAC address. Please "
-                                       "set using ifconfig\n", dev->name);
-               } else {
-                       /* Print the Ethernet address */
-                       printk("%s: Ethernet addr: %pM\n",
-                               dev->name, dev->dev_addr);
-               }
-
-               if (lp->phy_type == 0) {
-                       PRINTK("%s: No PHY found\n", dev->name);
-               } else if ((lp->phy_type & ~0xff) == LAN911X_INTERNAL_PHY_ID) {
-                       PRINTK("%s: LAN911x Internal PHY\n", dev->name);
-               } else {
-                       PRINTK("%s: External PHY 0x%08x\n", dev->name, lp->phy_type);
-               }
-       }
-
-err_out:
-#ifdef SMC_USE_DMA
-       if (retval) {
-               if (lp->rxdma != -1) {
-                       SMC_DMA_FREE(dev, lp->rxdma);
-               }
-               if (lp->txdma != -1) {
-                       SMC_DMA_FREE(dev, lp->txdma);
-               }
-       }
-#endif
-       return retval;
-}
-
-/*
- * smc911x_init(void)
- *
- *       Output:
- *      0 --> there is a device
- *      anything else, error
- */
-static int __devinit smc911x_drv_probe(struct platform_device *pdev)
-{
-       struct net_device *ndev;
-       struct resource *res;
-       struct smc911x_local *lp;
-       unsigned int *addr;
-       int ret;
-
-       DBG(SMC_DEBUG_FUNC, "--> %s\n",  __func__);
-       res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
-       if (!res) {
-               ret = -ENODEV;
-               goto out;
-       }
-
-       /*
-        * Request the regions.
-        */
-       if (!request_mem_region(res->start, SMC911X_IO_EXTENT, CARDNAME)) {
-                ret = -EBUSY;
-                goto out;
-       }
-
-       ndev = alloc_etherdev(sizeof(struct smc911x_local));
-       if (!ndev) {
-               printk("%s: could not allocate device.\n", CARDNAME);
-               ret = -ENOMEM;
-               goto release_1;
-       }
-       SET_NETDEV_DEV(ndev, &pdev->dev);
-
-       ndev->dma = (unsigned char)-1;
-       ndev->irq = platform_get_irq(pdev, 0);
-       lp = netdev_priv(ndev);
-       lp->netdev = ndev;
-#ifdef SMC_DYNAMIC_BUS_CONFIG
-       {
-               struct smc911x_platdata *pd = pdev->dev.platform_data;
-               if (!pd) {
-                       ret = -EINVAL;
-                       goto release_both;
-               }
-               memcpy(&lp->cfg, pd, sizeof(lp->cfg));
-       }
-#endif
-
-       addr = ioremap(res->start, SMC911X_IO_EXTENT);
-       if (!addr) {
-               ret = -ENOMEM;
-               goto release_both;
-       }
-
-       platform_set_drvdata(pdev, ndev);
-       lp->base = addr;
-       ndev->base_addr = res->start;
-       ret = smc911x_probe(ndev);
-       if (ret != 0) {
-               platform_set_drvdata(pdev, NULL);
-               iounmap(addr);
-release_both:
-               free_netdev(ndev);
-release_1:
-               release_mem_region(res->start, SMC911X_IO_EXTENT);
-out:
-               printk("%s: not found (%d).\n", CARDNAME, ret);
-       }
-#ifdef SMC_USE_DMA
-       else {
-               lp->physaddr = res->start;
-               lp->dev = &pdev->dev;
-       }
-#endif
-
-       return ret;
-}
-
-static int __devexit smc911x_drv_remove(struct platform_device *pdev)
-{
-       struct net_device *ndev = platform_get_drvdata(pdev);
-       struct smc911x_local *lp = netdev_priv(ndev);
-       struct resource *res;
-
-       DBG(SMC_DEBUG_FUNC, "--> %s\n", __func__);
-       platform_set_drvdata(pdev, NULL);
-
-       unregister_netdev(ndev);
-
-       free_irq(ndev->irq, ndev);
-
-#ifdef SMC_USE_DMA
-       {
-               if (lp->rxdma != -1) {
-                       SMC_DMA_FREE(dev, lp->rxdma);
-               }
-               if (lp->txdma != -1) {
-                       SMC_DMA_FREE(dev, lp->txdma);
-               }
-       }
-#endif
-       iounmap(lp->base);
-       res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
-       release_mem_region(res->start, SMC911X_IO_EXTENT);
-
-       free_netdev(ndev);
-       return 0;
-}
-
-static int smc911x_drv_suspend(struct platform_device *dev, pm_message_t state)
-{
-       struct net_device *ndev = platform_get_drvdata(dev);
-       struct smc911x_local *lp = netdev_priv(ndev);
-
-       DBG(SMC_DEBUG_FUNC, "--> %s\n", __func__);
-       if (ndev) {
-               if (netif_running(ndev)) {
-                       netif_device_detach(ndev);
-                       smc911x_shutdown(ndev);
-#if POWER_DOWN
-                       /* Set D2 - Energy detect only setting */
-                       SMC_SET_PMT_CTRL(lp, 2<<12);
-#endif
-               }
-       }
-       return 0;
-}
-
-static int smc911x_drv_resume(struct platform_device *dev)
-{
-       struct net_device *ndev = platform_get_drvdata(dev);
-
-       DBG(SMC_DEBUG_FUNC, "--> %s\n", __func__);
-       if (ndev) {
-               struct smc911x_local *lp = netdev_priv(ndev);
-
-               if (netif_running(ndev)) {
-                       smc911x_reset(ndev);
-                       if (lp->phy_type != 0)
-                               smc911x_phy_configure(&lp->phy_configure);
-                       smc911x_enable(ndev);
-                       netif_device_attach(ndev);
-               }
-       }
-       return 0;
-}
-
-static struct platform_driver smc911x_driver = {
-       .probe           = smc911x_drv_probe,
-       .remove  = __devexit_p(smc911x_drv_remove),
-       .suspend         = smc911x_drv_suspend,
-       .resume  = smc911x_drv_resume,
-       .driver  = {
-               .name    = CARDNAME,
-               .owner  = THIS_MODULE,
-       },
-};
-
-static int __init smc911x_init(void)
-{
-       return platform_driver_register(&smc911x_driver);
-}
-
-static void __exit smc911x_cleanup(void)
-{
-       platform_driver_unregister(&smc911x_driver);
-}
-
-module_init(smc911x_init);
-module_exit(smc911x_cleanup);
diff --git a/drivers/net/smc911x.h b/drivers/net/smc911x.h
deleted file mode 100644 (file)
index 3269292..0000000
+++ /dev/null
@@ -1,924 +0,0 @@
-/*------------------------------------------------------------------------
- . smc911x.h - macros for SMSC's LAN911{5,6,7,8} single-chip Ethernet device.
- .
- . Copyright (C) 2005 Sensoria Corp.
- . Derived from the unified SMC91x driver by Nicolas Pitre
- .
- . This program is free software; you can redistribute it and/or modify
- . it under the terms of the GNU General Public License as published by
- . the Free Software Foundation; either version 2 of the License, or
- . (at your option) any later version.
- .
- . This program is distributed in the hope that it will be useful,
- . but WITHOUT ANY WARRANTY; without even the implied warranty of
- . MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
- . GNU General Public License for more details.
- .
- . You should have received a copy of the GNU General Public License
- . along with this program; if not, write to the Free Software
- . Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
- .
- . Information contained in this file was obtained from the LAN9118
- . manual from SMC.  To get a copy, if you really want one, you can find
- . information under www.smsc.com.
- .
- . Authors
- .      Dustin McIntire                 <dustin@sensoria.com>
- .
- ---------------------------------------------------------------------------*/
-#ifndef _SMC911X_H_
-#define _SMC911X_H_
-
-#include <linux/smc911x.h>
-/*
- * Use the DMA feature on PXA chips
- */
-#ifdef CONFIG_ARCH_PXA
-  #define SMC_USE_PXA_DMA      1
-  #define SMC_USE_16BIT                0
-  #define SMC_USE_32BIT                1
-  #define SMC_IRQ_SENSE                IRQF_TRIGGER_FALLING
-#elif defined(CONFIG_SH_MAGIC_PANEL_R2)
-  #define SMC_USE_16BIT                0
-  #define SMC_USE_32BIT                1
-  #define SMC_IRQ_SENSE                IRQF_TRIGGER_LOW
-#elif defined(CONFIG_ARCH_OMAP3)
-  #define SMC_USE_16BIT                0
-  #define SMC_USE_32BIT                1
-  #define SMC_IRQ_SENSE                IRQF_TRIGGER_LOW
-  #define SMC_MEM_RESERVED     1
-#elif defined(CONFIG_ARCH_OMAP2)
-  #define SMC_USE_16BIT                0
-  #define SMC_USE_32BIT                1
-  #define SMC_IRQ_SENSE                IRQF_TRIGGER_LOW
-  #define SMC_MEM_RESERVED     1
-#else
-/*
- * Default configuration
- */
-
-#define SMC_DYNAMIC_BUS_CONFIG
-#endif
-
-#ifdef SMC_USE_PXA_DMA
-#define SMC_USE_DMA
-#endif
-
-/* store this information for the driver.. */
-struct smc911x_local {
-       /*
-        * If I have to wait until the DMA is finished and ready to reload a
-        * packet, I will store the skbuff here. Then, the DMA will send it
-        * out and free it.
-        */
-       struct sk_buff *pending_tx_skb;
-
-       /* version/revision of the SMC911x chip */
-       u16 version;
-       u16 revision;
-
-       /* FIFO sizes */
-       int tx_fifo_kb;
-       int tx_fifo_size;
-       int rx_fifo_size;
-       int afc_cfg;
-
-       /* Contains the current active receive/phy mode */
-       int ctl_rfduplx;
-       int ctl_rspeed;
-
-       u32 msg_enable;
-       u32 phy_type;
-       struct mii_if_info mii;
-
-       /* work queue */
-       struct work_struct phy_configure;
-
-       int tx_throttle;
-       spinlock_t lock;
-
-       struct net_device *netdev;
-
-#ifdef SMC_USE_DMA
-       /* DMA needs the physical address of the chip */
-       u_long physaddr;
-       int rxdma;
-       int txdma;
-       int rxdma_active;
-       int txdma_active;
-       struct sk_buff *current_rx_skb;
-       struct sk_buff *current_tx_skb;
-       struct device *dev;
-#endif
-       void __iomem *base;
-#ifdef SMC_DYNAMIC_BUS_CONFIG
-       struct smc911x_platdata cfg;
-#endif
-};
-
-/*
- * Define the bus width specific IO macros
- */
-
-#ifdef SMC_DYNAMIC_BUS_CONFIG
-static inline unsigned int SMC_inl(struct smc911x_local *lp, int reg)
-{
-       void __iomem *ioaddr = lp->base + reg;
-
-       if (lp->cfg.flags & SMC911X_USE_32BIT)
-               return readl(ioaddr);
-
-       if (lp->cfg.flags & SMC911X_USE_16BIT)
-               return readw(ioaddr) | (readw(ioaddr + 2) << 16);
-
-       BUG();
-}
-
-static inline void SMC_outl(unsigned int value, struct smc911x_local *lp,
-                           int reg)
-{
-       void __iomem *ioaddr = lp->base + reg;
-
-       if (lp->cfg.flags & SMC911X_USE_32BIT) {
-               writel(value, ioaddr);
-               return;
-       }
-
-       if (lp->cfg.flags & SMC911X_USE_16BIT) {
-               writew(value & 0xffff, ioaddr);
-               writew(value >> 16, ioaddr + 2);
-               return;
-       }
-
-       BUG();
-}
-
-static inline void SMC_insl(struct smc911x_local *lp, int reg,
-                             void *addr, unsigned int count)
-{
-       void __iomem *ioaddr = lp->base + reg;
-
-       if (lp->cfg.flags & SMC911X_USE_32BIT) {
-               readsl(ioaddr, addr, count);
-               return;
-       }
-
-       if (lp->cfg.flags & SMC911X_USE_16BIT) {
-               readsw(ioaddr, addr, count * 2);
-               return;
-       }
-
-       BUG();
-}
-
-static inline void SMC_outsl(struct smc911x_local *lp, int reg,
-                            void *addr, unsigned int count)
-{
-       void __iomem *ioaddr = lp->base + reg;
-
-       if (lp->cfg.flags & SMC911X_USE_32BIT) {
-               writesl(ioaddr, addr, count);
-               return;
-       }
-
-       if (lp->cfg.flags & SMC911X_USE_16BIT) {
-               writesw(ioaddr, addr, count * 2);
-               return;
-       }
-
-       BUG();
-}
-#else
-#if    SMC_USE_16BIT
-#define SMC_inl(lp, r)          ((readw((lp)->base + (r)) & 0xFFFF) + (readw((lp)->base + (r) + 2) << 16))
-#define SMC_outl(v, lp, r)                      \
-       do{                                      \
-                writew(v & 0xFFFF, (lp)->base + (r));   \
-                writew(v >> 16, (lp)->base + (r) + 2); \
-        } while (0)
-#define SMC_insl(lp, r, p, l)   readsw((short*)((lp)->base + (r)), p, l*2)
-#define SMC_outsl(lp, r, p, l)  writesw((short*)((lp)->base + (r)), p, l*2)
-
-#elif  SMC_USE_32BIT
-#define SMC_inl(lp, r)          readl((lp)->base + (r))
-#define SMC_outl(v, lp, r)      writel(v, (lp)->base + (r))
-#define SMC_insl(lp, r, p, l)   readsl((int*)((lp)->base + (r)), p, l)
-#define SMC_outsl(lp, r, p, l)  writesl((int*)((lp)->base + (r)), p, l)
-
-#endif /* SMC_USE_16BIT */
-#endif /* SMC_DYNAMIC_BUS_CONFIG */
-
-
-#ifdef SMC_USE_PXA_DMA
-
-#include <mach/dma.h>
-
-/*
- * Define the request and free functions
- * These are unfortunately architecture specific as no generic allocation
- * mechanism exits
- */
-#define SMC_DMA_REQUEST(dev, handler) \
-        pxa_request_dma(dev->name, DMA_PRIO_LOW, handler, dev)
-
-#define SMC_DMA_FREE(dev, dma) \
-        pxa_free_dma(dma)
-
-#define SMC_DMA_ACK_IRQ(dev, dma)                                      \
-{                                                                      \
-       if (DCSR(dma) & DCSR_BUSERR) {                                  \
-               printk("%s: DMA %d bus error!\n", dev->name, dma);      \
-       }                                                               \
-       DCSR(dma) = DCSR_STARTINTR|DCSR_ENDINTR|DCSR_BUSERR;            \
-}
-
-/*
- * Use a DMA for RX and TX packets.
- */
-#include <linux/dma-mapping.h>
-
-static dma_addr_t rx_dmabuf, tx_dmabuf;
-static int rx_dmalen, tx_dmalen;
-
-#ifdef SMC_insl
-#undef SMC_insl
-#define SMC_insl(lp, r, p, l) \
-       smc_pxa_dma_insl(lp, lp->physaddr, r, lp->rxdma, p, l)
-
-static inline void
-smc_pxa_dma_insl(struct smc911x_local *lp, u_long physaddr,
-               int reg, int dma, u_char *buf, int len)
-{
-       /* 64 bit alignment is required for memory to memory DMA */
-       if ((long)buf & 4) {
-               *((u32 *)buf) = SMC_inl(lp, reg);
-               buf += 4;
-               len--;
-       }
-
-       len *= 4;
-       rx_dmabuf = dma_map_single(lp->dev, buf, len, DMA_FROM_DEVICE);
-       rx_dmalen = len;
-       DCSR(dma) = DCSR_NODESC;
-       DTADR(dma) = rx_dmabuf;
-       DSADR(dma) = physaddr + reg;
-       DCMD(dma) = (DCMD_INCTRGADDR | DCMD_BURST32 |
-               DCMD_WIDTH4 | DCMD_ENDIRQEN | (DCMD_LENGTH & rx_dmalen));
-       DCSR(dma) = DCSR_NODESC | DCSR_RUN;
-}
-#endif
-
-#ifdef SMC_outsl
-#undef SMC_outsl
-#define SMC_outsl(lp, r, p, l) \
-        smc_pxa_dma_outsl(lp, lp->physaddr, r, lp->txdma, p, l)
-
-static inline void
-smc_pxa_dma_outsl(struct smc911x_local *lp, u_long physaddr,
-               int reg, int dma, u_char *buf, int len)
-{
-       /* 64 bit alignment is required for memory to memory DMA */
-       if ((long)buf & 4) {
-               SMC_outl(*((u32 *)buf), lp, reg);
-               buf += 4;
-               len--;
-       }
-
-       len *= 4;
-       tx_dmabuf = dma_map_single(lp->dev, buf, len, DMA_TO_DEVICE);
-       tx_dmalen = len;
-       DCSR(dma) = DCSR_NODESC;
-       DSADR(dma) = tx_dmabuf;
-       DTADR(dma) = physaddr + reg;
-       DCMD(dma) = (DCMD_INCSRCADDR | DCMD_BURST32 |
-               DCMD_WIDTH4 | DCMD_ENDIRQEN | (DCMD_LENGTH & tx_dmalen));
-       DCSR(dma) = DCSR_NODESC | DCSR_RUN;
-}
-#endif
-#endif  /* SMC_USE_PXA_DMA */
-
-
-/* Chip Parameters and Register Definitions */
-
-#define SMC911X_TX_FIFO_LOW_THRESHOLD  (1536*2)
-
-#define SMC911X_IO_EXTENT       0x100
-
-#define SMC911X_EEPROM_LEN      7
-
-/* Below are the register offsets and bit definitions
- * of the Lan911x memory space
- */
-#define RX_DATA_FIFO            (0x00)
-
-#define TX_DATA_FIFO            (0x20)
-#define        TX_CMD_A_INT_ON_COMP_           (0x80000000)
-#define        TX_CMD_A_INT_BUF_END_ALGN_      (0x03000000)
-#define        TX_CMD_A_INT_4_BYTE_ALGN_       (0x00000000)
-#define        TX_CMD_A_INT_16_BYTE_ALGN_      (0x01000000)
-#define        TX_CMD_A_INT_32_BYTE_ALGN_      (0x02000000)
-#define        TX_CMD_A_INT_DATA_OFFSET_       (0x001F0000)
-#define        TX_CMD_A_INT_FIRST_SEG_         (0x00002000)
-#define        TX_CMD_A_INT_LAST_SEG_          (0x00001000)
-#define        TX_CMD_A_BUF_SIZE_              (0x000007FF)
-#define        TX_CMD_B_PKT_TAG_               (0xFFFF0000)
-#define        TX_CMD_B_ADD_CRC_DISABLE_       (0x00002000)
-#define        TX_CMD_B_DISABLE_PADDING_       (0x00001000)
-#define        TX_CMD_B_PKT_BYTE_LENGTH_       (0x000007FF)
-
-#define RX_STATUS_FIFO         (0x40)
-#define        RX_STS_PKT_LEN_                 (0x3FFF0000)
-#define        RX_STS_ES_                      (0x00008000)
-#define        RX_STS_BCST_                    (0x00002000)
-#define        RX_STS_LEN_ERR_                 (0x00001000)
-#define        RX_STS_RUNT_ERR_                (0x00000800)
-#define        RX_STS_MCAST_                   (0x00000400)
-#define        RX_STS_TOO_LONG_                (0x00000080)
-#define        RX_STS_COLL_                    (0x00000040)
-#define        RX_STS_ETH_TYPE_                (0x00000020)
-#define        RX_STS_WDOG_TMT_                (0x00000010)
-#define        RX_STS_MII_ERR_                 (0x00000008)
-#define        RX_STS_DRIBBLING_               (0x00000004)
-#define        RX_STS_CRC_ERR_                 (0x00000002)
-#define RX_STATUS_FIFO_PEEK    (0x44)
-#define TX_STATUS_FIFO         (0x48)
-#define        TX_STS_TAG_                     (0xFFFF0000)
-#define        TX_STS_ES_                      (0x00008000)
-#define        TX_STS_LOC_                     (0x00000800)
-#define        TX_STS_NO_CARR_                 (0x00000400)
-#define        TX_STS_LATE_COLL_               (0x00000200)
-#define        TX_STS_MANY_COLL_               (0x00000100)
-#define        TX_STS_COLL_CNT_                (0x00000078)
-#define        TX_STS_MANY_DEFER_              (0x00000004)
-#define        TX_STS_UNDERRUN_                (0x00000002)
-#define        TX_STS_DEFERRED_                (0x00000001)
-#define TX_STATUS_FIFO_PEEK    (0x4C)
-#define ID_REV                 (0x50)
-#define        ID_REV_CHIP_ID_                 (0xFFFF0000)  /* RO */
-#define        ID_REV_REV_ID_                  (0x0000FFFF)  /* RO */
-
-#define INT_CFG                        (0x54)
-#define        INT_CFG_INT_DEAS_               (0xFF000000)  /* R/W */
-#define        INT_CFG_INT_DEAS_CLR_           (0x00004000)
-#define        INT_CFG_INT_DEAS_STS_           (0x00002000)
-#define        INT_CFG_IRQ_INT_                (0x00001000)  /* RO */
-#define        INT_CFG_IRQ_EN_                 (0x00000100)  /* R/W */
-#define        INT_CFG_IRQ_POL_                (0x00000010)  /* R/W Not Affected by SW Reset */
-#define        INT_CFG_IRQ_TYPE_               (0x00000001)  /* R/W Not Affected by SW Reset */
-
-#define INT_STS                        (0x58)
-#define        INT_STS_SW_INT_                 (0x80000000)  /* R/WC */
-#define        INT_STS_TXSTOP_INT_             (0x02000000)  /* R/WC */
-#define        INT_STS_RXSTOP_INT_             (0x01000000)  /* R/WC */
-#define        INT_STS_RXDFH_INT_              (0x00800000)  /* R/WC */
-#define        INT_STS_RXDF_INT_               (0x00400000)  /* R/WC */
-#define        INT_STS_TX_IOC_                 (0x00200000)  /* R/WC */
-#define        INT_STS_RXD_INT_                (0x00100000)  /* R/WC */
-#define        INT_STS_GPT_INT_                (0x00080000)  /* R/WC */
-#define        INT_STS_PHY_INT_                (0x00040000)  /* RO */
-#define        INT_STS_PME_INT_                (0x00020000)  /* R/WC */
-#define        INT_STS_TXSO_                   (0x00010000)  /* R/WC */
-#define        INT_STS_RWT_                    (0x00008000)  /* R/WC */
-#define        INT_STS_RXE_                    (0x00004000)  /* R/WC */
-#define        INT_STS_TXE_                    (0x00002000)  /* R/WC */
-//#define      INT_STS_ERX_            (0x00001000)  /* R/WC */
-#define        INT_STS_TDFU_                   (0x00000800)  /* R/WC */
-#define        INT_STS_TDFO_                   (0x00000400)  /* R/WC */
-#define        INT_STS_TDFA_                   (0x00000200)  /* R/WC */
-#define        INT_STS_TSFF_                   (0x00000100)  /* R/WC */
-#define        INT_STS_TSFL_                   (0x00000080)  /* R/WC */
-//#define      INT_STS_RXDF_           (0x00000040)  /* R/WC */
-#define        INT_STS_RDFO_                   (0x00000040)  /* R/WC */
-#define        INT_STS_RDFL_                   (0x00000020)  /* R/WC */
-#define        INT_STS_RSFF_                   (0x00000010)  /* R/WC */
-#define        INT_STS_RSFL_                   (0x00000008)  /* R/WC */
-#define        INT_STS_GPIO2_INT_              (0x00000004)  /* R/WC */
-#define        INT_STS_GPIO1_INT_              (0x00000002)  /* R/WC */
-#define        INT_STS_GPIO0_INT_              (0x00000001)  /* R/WC */
-
-#define INT_EN                 (0x5C)
-#define        INT_EN_SW_INT_EN_               (0x80000000)  /* R/W */
-#define        INT_EN_TXSTOP_INT_EN_           (0x02000000)  /* R/W */
-#define        INT_EN_RXSTOP_INT_EN_           (0x01000000)  /* R/W */
-#define        INT_EN_RXDFH_INT_EN_            (0x00800000)  /* R/W */
-//#define      INT_EN_RXDF_INT_EN_             (0x00400000)  /* R/W */
-#define        INT_EN_TIOC_INT_EN_             (0x00200000)  /* R/W */
-#define        INT_EN_RXD_INT_EN_              (0x00100000)  /* R/W */
-#define        INT_EN_GPT_INT_EN_              (0x00080000)  /* R/W */
-#define        INT_EN_PHY_INT_EN_              (0x00040000)  /* R/W */
-#define        INT_EN_PME_INT_EN_              (0x00020000)  /* R/W */
-#define        INT_EN_TXSO_EN_                 (0x00010000)  /* R/W */
-#define        INT_EN_RWT_EN_                  (0x00008000)  /* R/W */
-#define        INT_EN_RXE_EN_                  (0x00004000)  /* R/W */
-#define        INT_EN_TXE_EN_                  (0x00002000)  /* R/W */
-//#define      INT_EN_ERX_EN_                  (0x00001000)  /* R/W */
-#define        INT_EN_TDFU_EN_                 (0x00000800)  /* R/W */
-#define        INT_EN_TDFO_EN_                 (0x00000400)  /* R/W */
-#define        INT_EN_TDFA_EN_                 (0x00000200)  /* R/W */
-#define        INT_EN_TSFF_EN_                 (0x00000100)  /* R/W */
-#define        INT_EN_TSFL_EN_                 (0x00000080)  /* R/W */
-//#define      INT_EN_RXDF_EN_                 (0x00000040)  /* R/W */
-#define        INT_EN_RDFO_EN_                 (0x00000040)  /* R/W */
-#define        INT_EN_RDFL_EN_                 (0x00000020)  /* R/W */
-#define        INT_EN_RSFF_EN_                 (0x00000010)  /* R/W */
-#define        INT_EN_RSFL_EN_                 (0x00000008)  /* R/W */
-#define        INT_EN_GPIO2_INT_               (0x00000004)  /* R/W */
-#define        INT_EN_GPIO1_INT_               (0x00000002)  /* R/W */
-#define        INT_EN_GPIO0_INT_               (0x00000001)  /* R/W */
-
-#define BYTE_TEST              (0x64)
-#define FIFO_INT               (0x68)
-#define        FIFO_INT_TX_AVAIL_LEVEL_        (0xFF000000)  /* R/W */
-#define        FIFO_INT_TX_STS_LEVEL_          (0x00FF0000)  /* R/W */
-#define        FIFO_INT_RX_AVAIL_LEVEL_        (0x0000FF00)  /* R/W */
-#define        FIFO_INT_RX_STS_LEVEL_          (0x000000FF)  /* R/W */
-
-#define RX_CFG                 (0x6C)
-#define        RX_CFG_RX_END_ALGN_             (0xC0000000)  /* R/W */
-#define                RX_CFG_RX_END_ALGN4_            (0x00000000)  /* R/W */
-#define                RX_CFG_RX_END_ALGN16_           (0x40000000)  /* R/W */
-#define                RX_CFG_RX_END_ALGN32_           (0x80000000)  /* R/W */
-#define        RX_CFG_RX_DMA_CNT_              (0x0FFF0000)  /* R/W */
-#define        RX_CFG_RX_DUMP_                 (0x00008000)  /* R/W */
-#define        RX_CFG_RXDOFF_                  (0x00001F00)  /* R/W */
-//#define      RX_CFG_RXBAD_                   (0x00000001)  /* R/W */
-
-#define TX_CFG                 (0x70)
-//#define      TX_CFG_TX_DMA_LVL_              (0xE0000000)     /* R/W */
-//#define      TX_CFG_TX_DMA_CNT_              (0x0FFF0000)     /* R/W Self Clearing */
-#define        TX_CFG_TXS_DUMP_                (0x00008000)  /* Self Clearing */
-#define        TX_CFG_TXD_DUMP_                (0x00004000)  /* Self Clearing */
-#define        TX_CFG_TXSAO_                   (0x00000004)  /* R/W */
-#define        TX_CFG_TX_ON_                   (0x00000002)  /* R/W */
-#define        TX_CFG_STOP_TX_                 (0x00000001)  /* Self Clearing */
-
-#define HW_CFG                 (0x74)
-#define        HW_CFG_TTM_                     (0x00200000)  /* R/W */
-#define        HW_CFG_SF_                      (0x00100000)  /* R/W */
-#define        HW_CFG_TX_FIF_SZ_               (0x000F0000)  /* R/W */
-#define        HW_CFG_TR_                      (0x00003000)  /* R/W */
-#define        HW_CFG_PHY_CLK_SEL_             (0x00000060)  /* R/W */
-#define                 HW_CFG_PHY_CLK_SEL_INT_PHY_    (0x00000000) /* R/W */
-#define                 HW_CFG_PHY_CLK_SEL_EXT_PHY_    (0x00000020) /* R/W */
-#define                 HW_CFG_PHY_CLK_SEL_CLK_DIS_    (0x00000040) /* R/W */
-#define        HW_CFG_SMI_SEL_                 (0x00000010)  /* R/W */
-#define        HW_CFG_EXT_PHY_DET_             (0x00000008)  /* RO */
-#define        HW_CFG_EXT_PHY_EN_              (0x00000004)  /* R/W */
-#define        HW_CFG_32_16_BIT_MODE_          (0x00000004)  /* RO */
-#define        HW_CFG_SRST_TO_                 (0x00000002)  /* RO */
-#define        HW_CFG_SRST_                    (0x00000001)  /* Self Clearing */
-
-#define RX_DP_CTRL             (0x78)
-#define        RX_DP_CTRL_RX_FFWD_             (0x80000000)  /* R/W */
-#define        RX_DP_CTRL_FFWD_BUSY_           (0x80000000)  /* RO */
-
-#define RX_FIFO_INF            (0x7C)
-#define         RX_FIFO_INF_RXSUSED_           (0x00FF0000)  /* RO */
-#define         RX_FIFO_INF_RXDUSED_           (0x0000FFFF)  /* RO */
-
-#define TX_FIFO_INF            (0x80)
-#define        TX_FIFO_INF_TSUSED_             (0x00FF0000)  /* RO */
-#define        TX_FIFO_INF_TDFREE_             (0x0000FFFF)  /* RO */
-
-#define PMT_CTRL               (0x84)
-#define        PMT_CTRL_PM_MODE_               (0x00003000)  /* Self Clearing */
-#define        PMT_CTRL_PHY_RST_               (0x00000400)  /* Self Clearing */
-#define        PMT_CTRL_WOL_EN_                (0x00000200)  /* R/W */
-#define        PMT_CTRL_ED_EN_                 (0x00000100)  /* R/W */
-#define        PMT_CTRL_PME_TYPE_              (0x00000040)  /* R/W Not Affected by SW Reset */
-#define        PMT_CTRL_WUPS_                  (0x00000030)  /* R/WC */
-#define                PMT_CTRL_WUPS_NOWAKE_           (0x00000000)  /* R/WC */
-#define                PMT_CTRL_WUPS_ED_               (0x00000010)  /* R/WC */
-#define                PMT_CTRL_WUPS_WOL_              (0x00000020)  /* R/WC */
-#define                PMT_CTRL_WUPS_MULTI_            (0x00000030)  /* R/WC */
-#define        PMT_CTRL_PME_IND_               (0x00000008)  /* R/W */
-#define        PMT_CTRL_PME_POL_               (0x00000004)  /* R/W */
-#define        PMT_CTRL_PME_EN_                (0x00000002)  /* R/W Not Affected by SW Reset */
-#define        PMT_CTRL_READY_                 (0x00000001)  /* RO */
-
-#define GPIO_CFG               (0x88)
-#define        GPIO_CFG_LED3_EN_               (0x40000000)  /* R/W */
-#define        GPIO_CFG_LED2_EN_               (0x20000000)  /* R/W */
-#define        GPIO_CFG_LED1_EN_               (0x10000000)  /* R/W */
-#define        GPIO_CFG_GPIO2_INT_POL_         (0x04000000)  /* R/W */
-#define        GPIO_CFG_GPIO1_INT_POL_         (0x02000000)  /* R/W */
-#define        GPIO_CFG_GPIO0_INT_POL_         (0x01000000)  /* R/W */
-#define        GPIO_CFG_EEPR_EN_               (0x00700000)  /* R/W */
-#define        GPIO_CFG_GPIOBUF2_              (0x00040000)  /* R/W */
-#define        GPIO_CFG_GPIOBUF1_              (0x00020000)  /* R/W */
-#define        GPIO_CFG_GPIOBUF0_              (0x00010000)  /* R/W */
-#define        GPIO_CFG_GPIODIR2_              (0x00000400)  /* R/W */
-#define        GPIO_CFG_GPIODIR1_              (0x00000200)  /* R/W */
-#define        GPIO_CFG_GPIODIR0_              (0x00000100)  /* R/W */
-#define        GPIO_CFG_GPIOD4_                (0x00000010)  /* R/W */
-#define        GPIO_CFG_GPIOD3_                (0x00000008)  /* R/W */
-#define        GPIO_CFG_GPIOD2_                (0x00000004)  /* R/W */
-#define        GPIO_CFG_GPIOD1_                (0x00000002)  /* R/W */
-#define        GPIO_CFG_GPIOD0_                (0x00000001)  /* R/W */
-
-#define GPT_CFG                        (0x8C)
-#define        GPT_CFG_TIMER_EN_               (0x20000000)  /* R/W */
-#define        GPT_CFG_GPT_LOAD_               (0x0000FFFF)  /* R/W */
-
-#define GPT_CNT                        (0x90)
-#define        GPT_CNT_GPT_CNT_                (0x0000FFFF)  /* RO */
-
-#define ENDIAN                 (0x98)
-#define FREE_RUN               (0x9C)
-#define RX_DROP                        (0xA0)
-#define MAC_CSR_CMD            (0xA4)
-#define         MAC_CSR_CMD_CSR_BUSY_          (0x80000000)  /* Self Clearing */
-#define         MAC_CSR_CMD_R_NOT_W_           (0x40000000)  /* R/W */
-#define         MAC_CSR_CMD_CSR_ADDR_          (0x000000FF)  /* R/W */
-
-#define MAC_CSR_DATA           (0xA8)
-#define AFC_CFG                        (0xAC)
-#define                AFC_CFG_AFC_HI_                 (0x00FF0000)  /* R/W */
-#define                AFC_CFG_AFC_LO_                 (0x0000FF00)  /* R/W */
-#define                AFC_CFG_BACK_DUR_               (0x000000F0)  /* R/W */
-#define                AFC_CFG_FCMULT_                 (0x00000008)  /* R/W */
-#define                AFC_CFG_FCBRD_                  (0x00000004)  /* R/W */
-#define                AFC_CFG_FCADD_                  (0x00000002)  /* R/W */
-#define                AFC_CFG_FCANY_                  (0x00000001)  /* R/W */
-
-#define E2P_CMD                        (0xB0)
-#define        E2P_CMD_EPC_BUSY_               (0x80000000)  /* Self Clearing */
-#define        E2P_CMD_EPC_CMD_                        (0x70000000)  /* R/W */
-#define                E2P_CMD_EPC_CMD_READ_           (0x00000000)  /* R/W */
-#define                E2P_CMD_EPC_CMD_EWDS_           (0x10000000)  /* R/W */
-#define                E2P_CMD_EPC_CMD_EWEN_           (0x20000000)  /* R/W */
-#define                E2P_CMD_EPC_CMD_WRITE_          (0x30000000)  /* R/W */
-#define                E2P_CMD_EPC_CMD_WRAL_           (0x40000000)  /* R/W */
-#define                E2P_CMD_EPC_CMD_ERASE_          (0x50000000)  /* R/W */
-#define                E2P_CMD_EPC_CMD_ERAL_           (0x60000000)  /* R/W */
-#define                E2P_CMD_EPC_CMD_RELOAD_         (0x70000000)  /* R/W */
-#define        E2P_CMD_EPC_TIMEOUT_            (0x00000200)  /* RO */
-#define        E2P_CMD_MAC_ADDR_LOADED_        (0x00000100)  /* RO */
-#define        E2P_CMD_EPC_ADDR_               (0x000000FF)  /* R/W */
-
-#define E2P_DATA               (0xB4)
-#define        E2P_DATA_EEPROM_DATA_           (0x000000FF)  /* R/W */
-/* end of LAN register offsets and bit definitions */
-
-/*
- ****************************************************************************
- ****************************************************************************
- * MAC Control and Status Register (Indirect Address)
- * Offset (through the MAC_CSR CMD and DATA port)
- ****************************************************************************
- ****************************************************************************
- *
- */
-#define MAC_CR                 (0x01)  /* R/W */
-
-/* MAC_CR - MAC Control Register */
-#define MAC_CR_RXALL_                  (0x80000000)
-// TODO: delete this bit? It is not described in the data sheet.
-#define MAC_CR_HBDIS_                  (0x10000000)
-#define MAC_CR_RCVOWN_                 (0x00800000)
-#define MAC_CR_LOOPBK_                 (0x00200000)
-#define MAC_CR_FDPX_                   (0x00100000)
-#define MAC_CR_MCPAS_                  (0x00080000)
-#define MAC_CR_PRMS_                   (0x00040000)
-#define MAC_CR_INVFILT_                        (0x00020000)
-#define MAC_CR_PASSBAD_                        (0x00010000)
-#define MAC_CR_HFILT_                  (0x00008000)
-#define MAC_CR_HPFILT_                 (0x00002000)
-#define MAC_CR_LCOLL_                  (0x00001000)
-#define MAC_CR_BCAST_                  (0x00000800)
-#define MAC_CR_DISRTY_                 (0x00000400)
-#define MAC_CR_PADSTR_                 (0x00000100)
-#define MAC_CR_BOLMT_MASK_             (0x000000C0)
-#define MAC_CR_DFCHK_                  (0x00000020)
-#define MAC_CR_TXEN_                   (0x00000008)
-#define MAC_CR_RXEN_                   (0x00000004)
-
-#define ADDRH                  (0x02)    /* R/W mask 0x0000FFFFUL */
-#define ADDRL                  (0x03)    /* R/W mask 0xFFFFFFFFUL */
-#define HASHH                  (0x04)    /* R/W */
-#define HASHL                  (0x05)    /* R/W */
-
-#define MII_ACC                        (0x06)    /* R/W */
-#define MII_ACC_PHY_ADDR_              (0x0000F800)
-#define MII_ACC_MIIRINDA_              (0x000007C0)
-#define MII_ACC_MII_WRITE_             (0x00000002)
-#define MII_ACC_MII_BUSY_              (0x00000001)
-
-#define MII_DATA               (0x07)    /* R/W mask 0x0000FFFFUL */
-
-#define FLOW                   (0x08)    /* R/W */
-#define FLOW_FCPT_                     (0xFFFF0000)
-#define FLOW_FCPASS_                   (0x00000004)
-#define FLOW_FCEN_                     (0x00000002)
-#define FLOW_FCBSY_                    (0x00000001)
-
-#define VLAN1                  (0x09)    /* R/W mask 0x0000FFFFUL */
-#define VLAN1_VTI1_                    (0x0000ffff)
-
-#define VLAN2                  (0x0A)    /* R/W mask 0x0000FFFFUL */
-#define VLAN2_VTI2_                    (0x0000ffff)
-
-#define WUFF                   (0x0B)    /* WO */
-
-#define WUCSR                  (0x0C)    /* R/W */
-#define WUCSR_GUE_                     (0x00000200)
-#define WUCSR_WUFR_                    (0x00000040)
-#define WUCSR_MPR_                     (0x00000020)
-#define WUCSR_WAKE_EN_                 (0x00000004)
-#define WUCSR_MPEN_                    (0x00000002)
-
-/*
- ****************************************************************************
- * Chip Specific MII Defines
- ****************************************************************************
- *
- * Phy register offsets and bit definitions
- *
- */
-
-#define PHY_MODE_CTRL_STS      ((u32)17)       /* Mode Control/Status Register */
-//#define MODE_CTRL_STS_FASTRIP_         ((u16)0x4000)
-#define MODE_CTRL_STS_EDPWRDOWN_        ((u16)0x2000)
-//#define MODE_CTRL_STS_LOWSQEN_          ((u16)0x0800)
-//#define MODE_CTRL_STS_MDPREBP_          ((u16)0x0400)
-//#define MODE_CTRL_STS_FARLOOPBACK_  ((u16)0x0200)
-//#define MODE_CTRL_STS_FASTEST_          ((u16)0x0100)
-//#define MODE_CTRL_STS_REFCLKEN_         ((u16)0x0010)
-//#define MODE_CTRL_STS_PHYADBP_          ((u16)0x0008)
-//#define MODE_CTRL_STS_FORCE_G_LINK_ ((u16)0x0004)
-#define MODE_CTRL_STS_ENERGYON_                ((u16)0x0002)
-
-#define PHY_INT_SRC                    ((u32)29)
-#define PHY_INT_SRC_ENERGY_ON_                 ((u16)0x0080)
-#define PHY_INT_SRC_ANEG_COMP_                 ((u16)0x0040)
-#define PHY_INT_SRC_REMOTE_FAULT_              ((u16)0x0020)
-#define PHY_INT_SRC_LINK_DOWN_                 ((u16)0x0010)
-#define PHY_INT_SRC_ANEG_LP_ACK_               ((u16)0x0008)
-#define PHY_INT_SRC_PAR_DET_FAULT_             ((u16)0x0004)
-#define PHY_INT_SRC_ANEG_PGRX_                 ((u16)0x0002)
-
-#define PHY_INT_MASK                   ((u32)30)
-#define PHY_INT_MASK_ENERGY_ON_                        ((u16)0x0080)
-#define PHY_INT_MASK_ANEG_COMP_                        ((u16)0x0040)
-#define PHY_INT_MASK_REMOTE_FAULT_             ((u16)0x0020)
-#define PHY_INT_MASK_LINK_DOWN_                        ((u16)0x0010)
-#define PHY_INT_MASK_ANEG_LP_ACK_              ((u16)0x0008)
-#define PHY_INT_MASK_PAR_DET_FAULT_            ((u16)0x0004)
-#define PHY_INT_MASK_ANEG_PGRX_                        ((u16)0x0002)
-
-#define PHY_SPECIAL                    ((u32)31)
-#define PHY_SPECIAL_ANEG_DONE_                 ((u16)0x1000)
-#define PHY_SPECIAL_RES_                       ((u16)0x0040)
-#define PHY_SPECIAL_RES_MASK_                  ((u16)0x0FE1)
-#define PHY_SPECIAL_SPD_                       ((u16)0x001C)
-#define PHY_SPECIAL_SPD_10HALF_                        ((u16)0x0004)
-#define PHY_SPECIAL_SPD_10FULL_                        ((u16)0x0014)
-#define PHY_SPECIAL_SPD_100HALF_               ((u16)0x0008)
-#define PHY_SPECIAL_SPD_100FULL_               ((u16)0x0018)
-
-#define LAN911X_INTERNAL_PHY_ID                (0x0007C000)
-
-/* Chip ID values */
-#define CHIP_9115      0x0115
-#define CHIP_9116      0x0116
-#define CHIP_9117      0x0117
-#define CHIP_9118      0x0118
-#define CHIP_9211      0x9211
-#define CHIP_9215      0x115A
-#define CHIP_9217      0x117A
-#define CHIP_9218      0x118A
-
-struct chip_id {
-       u16 id;
-       char *name;
-};
-
-static const struct chip_id chip_ids[] =  {
-       { CHIP_9115, "LAN9115" },
-       { CHIP_9116, "LAN9116" },
-       { CHIP_9117, "LAN9117" },
-       { CHIP_9118, "LAN9118" },
-       { CHIP_9211, "LAN9211" },
-       { CHIP_9215, "LAN9215" },
-       { CHIP_9217, "LAN9217" },
-       { CHIP_9218, "LAN9218" },
-       { 0, NULL },
-};
-
-#define IS_REV_A(x)    ((x & 0xFFFF)==0)
-
-/*
- * Macros to abstract register access according to the data bus
- * capabilities.  Please use those and not the in/out primitives.
- */
-/* FIFO read/write macros */
-#define SMC_PUSH_DATA(lp, p, l)        SMC_outsl( lp, TX_DATA_FIFO, p, (l) >> 2 )
-#define SMC_PULL_DATA(lp, p, l)        SMC_insl ( lp, RX_DATA_FIFO, p, (l) >> 2 )
-#define SMC_SET_TX_FIFO(lp, x)         SMC_outl( x, lp, TX_DATA_FIFO )
-#define SMC_GET_RX_FIFO(lp)    SMC_inl( lp, RX_DATA_FIFO )
-
-
-/* I/O mapped register read/write macros */
-#define SMC_GET_TX_STS_FIFO(lp)                SMC_inl( lp, TX_STATUS_FIFO )
-#define SMC_GET_RX_STS_FIFO(lp)                SMC_inl( lp, RX_STATUS_FIFO )
-#define SMC_GET_RX_STS_FIFO_PEEK(lp)   SMC_inl( lp, RX_STATUS_FIFO_PEEK )
-#define SMC_GET_PN(lp)                 (SMC_inl( lp, ID_REV ) >> 16)
-#define SMC_GET_REV(lp)                        (SMC_inl( lp, ID_REV ) & 0xFFFF)
-#define SMC_GET_IRQ_CFG(lp)            SMC_inl( lp, INT_CFG )
-#define SMC_SET_IRQ_CFG(lp, x)         SMC_outl( x, lp, INT_CFG )
-#define SMC_GET_INT(lp)                        SMC_inl( lp, INT_STS )
-#define SMC_ACK_INT(lp, x)                     SMC_outl( x, lp, INT_STS )
-#define SMC_GET_INT_EN(lp)             SMC_inl( lp, INT_EN )
-#define SMC_SET_INT_EN(lp, x)          SMC_outl( x, lp, INT_EN )
-#define SMC_GET_BYTE_TEST(lp)          SMC_inl( lp, BYTE_TEST )
-#define SMC_SET_BYTE_TEST(lp, x)               SMC_outl( x, lp, BYTE_TEST )
-#define SMC_GET_FIFO_INT(lp)           SMC_inl( lp, FIFO_INT )
-#define SMC_SET_FIFO_INT(lp, x)                SMC_outl( x, lp, FIFO_INT )
-#define SMC_SET_FIFO_TDA(lp, x)                                        \
-       do {                                                    \
-               unsigned long __flags;                          \
-               int __mask;                                     \
-               local_irq_save(__flags);                        \
-               __mask = SMC_GET_FIFO_INT((lp)) & ~(0xFF<<24);  \
-               SMC_SET_FIFO_INT( (lp), __mask | (x)<<24 );     \
-               local_irq_restore(__flags);                     \
-       } while (0)
-#define SMC_SET_FIFO_TSL(lp, x)                                        \
-       do {                                                    \
-               unsigned long __flags;                          \
-               int __mask;                                     \
-               local_irq_save(__flags);                        \
-               __mask = SMC_GET_FIFO_INT((lp)) & ~(0xFF<<16);  \
-               SMC_SET_FIFO_INT( (lp), __mask | (((x) & 0xFF)<<16));   \
-               local_irq_restore(__flags);                     \
-       } while (0)
-#define SMC_SET_FIFO_RSA(lp, x)                                        \
-       do {                                                    \
-               unsigned long __flags;                          \
-               int __mask;                                     \
-               local_irq_save(__flags);                        \
-               __mask = SMC_GET_FIFO_INT((lp)) & ~(0xFF<<8);   \
-               SMC_SET_FIFO_INT( (lp), __mask | (((x) & 0xFF)<<8));    \
-               local_irq_restore(__flags);                     \
-       } while (0)
-#define SMC_SET_FIFO_RSL(lp, x)                                        \
-       do {                                                    \
-               unsigned long __flags;                          \
-               int __mask;                                     \
-               local_irq_save(__flags);                        \
-               __mask = SMC_GET_FIFO_INT((lp)) & ~0xFF;        \
-               SMC_SET_FIFO_INT( (lp),__mask | ((x) & 0xFF));  \
-               local_irq_restore(__flags);                     \
-       } while (0)
-#define SMC_GET_RX_CFG(lp)             SMC_inl( lp, RX_CFG )
-#define SMC_SET_RX_CFG(lp, x)          SMC_outl( x, lp, RX_CFG )
-#define SMC_GET_TX_CFG(lp)             SMC_inl( lp, TX_CFG )
-#define SMC_SET_TX_CFG(lp, x)          SMC_outl( x, lp, TX_CFG )
-#define SMC_GET_HW_CFG(lp)             SMC_inl( lp, HW_CFG )
-#define SMC_SET_HW_CFG(lp, x)          SMC_outl( x, lp, HW_CFG )
-#define SMC_GET_RX_DP_CTRL(lp)         SMC_inl( lp, RX_DP_CTRL )
-#define SMC_SET_RX_DP_CTRL(lp, x)              SMC_outl( x, lp, RX_DP_CTRL )
-#define SMC_GET_PMT_CTRL(lp)           SMC_inl( lp, PMT_CTRL )
-#define SMC_SET_PMT_CTRL(lp, x)                SMC_outl( x, lp, PMT_CTRL )
-#define SMC_GET_GPIO_CFG(lp)           SMC_inl( lp, GPIO_CFG )
-#define SMC_SET_GPIO_CFG(lp, x)                SMC_outl( x, lp, GPIO_CFG )
-#define SMC_GET_RX_FIFO_INF(lp)                SMC_inl( lp, RX_FIFO_INF )
-#define SMC_SET_RX_FIFO_INF(lp, x)             SMC_outl( x, lp, RX_FIFO_INF )
-#define SMC_GET_TX_FIFO_INF(lp)                SMC_inl( lp, TX_FIFO_INF )
-#define SMC_SET_TX_FIFO_INF(lp, x)             SMC_outl( x, lp, TX_FIFO_INF )
-#define SMC_GET_GPT_CFG(lp)            SMC_inl( lp, GPT_CFG )
-#define SMC_SET_GPT_CFG(lp, x)         SMC_outl( x, lp, GPT_CFG )
-#define SMC_GET_RX_DROP(lp)            SMC_inl( lp, RX_DROP )
-#define SMC_SET_RX_DROP(lp, x)         SMC_outl( x, lp, RX_DROP )
-#define SMC_GET_MAC_CMD(lp)            SMC_inl( lp, MAC_CSR_CMD )
-#define SMC_SET_MAC_CMD(lp, x)         SMC_outl( x, lp, MAC_CSR_CMD )
-#define SMC_GET_MAC_DATA(lp)           SMC_inl( lp, MAC_CSR_DATA )
-#define SMC_SET_MAC_DATA(lp, x)                SMC_outl( x, lp, MAC_CSR_DATA )
-#define SMC_GET_AFC_CFG(lp)            SMC_inl( lp, AFC_CFG )
-#define SMC_SET_AFC_CFG(lp, x)         SMC_outl( x, lp, AFC_CFG )
-#define SMC_GET_E2P_CMD(lp)            SMC_inl( lp, E2P_CMD )
-#define SMC_SET_E2P_CMD(lp, x)         SMC_outl( x, lp, E2P_CMD )
-#define SMC_GET_E2P_DATA(lp)           SMC_inl( lp, E2P_DATA )
-#define SMC_SET_E2P_DATA(lp, x)                SMC_outl( x, lp, E2P_DATA )
-
-/* MAC register read/write macros */
-#define SMC_GET_MAC_CSR(lp,a,v)                                                \
-       do {                                                            \
-               while (SMC_GET_MAC_CMD((lp)) & MAC_CSR_CMD_CSR_BUSY_);  \
-               SMC_SET_MAC_CMD((lp),MAC_CSR_CMD_CSR_BUSY_ |            \
-                       MAC_CSR_CMD_R_NOT_W_ | (a) );                   \
-               while (SMC_GET_MAC_CMD((lp)) & MAC_CSR_CMD_CSR_BUSY_);  \
-               v = SMC_GET_MAC_DATA((lp));                             \
-       } while (0)
-#define SMC_SET_MAC_CSR(lp,a,v)                                                \
-       do {                                                            \
-               while (SMC_GET_MAC_CMD((lp)) & MAC_CSR_CMD_CSR_BUSY_);  \
-               SMC_SET_MAC_DATA((lp), v);                              \
-               SMC_SET_MAC_CMD((lp), MAC_CSR_CMD_CSR_BUSY_ | (a) );    \
-               while (SMC_GET_MAC_CMD((lp)) & MAC_CSR_CMD_CSR_BUSY_);  \
-       } while (0)
-#define SMC_GET_MAC_CR(lp, x)  SMC_GET_MAC_CSR( (lp), MAC_CR, x )
-#define SMC_SET_MAC_CR(lp, x)  SMC_SET_MAC_CSR( (lp), MAC_CR, x )
-#define SMC_GET_ADDRH(lp, x)   SMC_GET_MAC_CSR( (lp), ADDRH, x )
-#define SMC_SET_ADDRH(lp, x)   SMC_SET_MAC_CSR( (lp), ADDRH, x )
-#define SMC_GET_ADDRL(lp, x)   SMC_GET_MAC_CSR( (lp), ADDRL, x )
-#define SMC_SET_ADDRL(lp, x)   SMC_SET_MAC_CSR( (lp), ADDRL, x )
-#define SMC_GET_HASHH(lp, x)   SMC_GET_MAC_CSR( (lp), HASHH, x )
-#define SMC_SET_HASHH(lp, x)   SMC_SET_MAC_CSR( (lp), HASHH, x )
-#define SMC_GET_HASHL(lp, x)   SMC_GET_MAC_CSR( (lp), HASHL, x )
-#define SMC_SET_HASHL(lp, x)   SMC_SET_MAC_CSR( (lp), HASHL, x )
-#define SMC_GET_MII_ACC(lp, x) SMC_GET_MAC_CSR( (lp), MII_ACC, x )
-#define SMC_SET_MII_ACC(lp, x) SMC_SET_MAC_CSR( (lp), MII_ACC, x )
-#define SMC_GET_MII_DATA(lp, x)        SMC_GET_MAC_CSR( (lp), MII_DATA, x )
-#define SMC_SET_MII_DATA(lp, x)        SMC_SET_MAC_CSR( (lp), MII_DATA, x )
-#define SMC_GET_FLOW(lp, x)            SMC_GET_MAC_CSR( (lp), FLOW, x )
-#define SMC_SET_FLOW(lp, x)            SMC_SET_MAC_CSR( (lp), FLOW, x )
-#define SMC_GET_VLAN1(lp, x)   SMC_GET_MAC_CSR( (lp), VLAN1, x )
-#define SMC_SET_VLAN1(lp, x)   SMC_SET_MAC_CSR( (lp), VLAN1, x )
-#define SMC_GET_VLAN2(lp, x)   SMC_GET_MAC_CSR( (lp), VLAN2, x )
-#define SMC_SET_VLAN2(lp, x)   SMC_SET_MAC_CSR( (lp), VLAN2, x )
-#define SMC_SET_WUFF(lp, x)            SMC_SET_MAC_CSR( (lp), WUFF, x )
-#define SMC_GET_WUCSR(lp, x)   SMC_GET_MAC_CSR( (lp), WUCSR, x )
-#define SMC_SET_WUCSR(lp, x)   SMC_SET_MAC_CSR( (lp), WUCSR, x )
-
-/* PHY register read/write macros */
-#define SMC_GET_MII(lp,a,phy,v)                                        \
-       do {                                                    \
-               u32 __v;                                        \
-               do {                                            \
-                       SMC_GET_MII_ACC((lp), __v);                     \
-               } while ( __v & MII_ACC_MII_BUSY_ );            \
-               SMC_SET_MII_ACC( (lp), ((phy)<<11) | ((a)<<6) | \
-                       MII_ACC_MII_BUSY_);                     \
-               do {                                            \
-                       SMC_GET_MII_ACC( (lp), __v);                    \
-               } while ( __v & MII_ACC_MII_BUSY_ );            \
-               SMC_GET_MII_DATA((lp), v);                              \
-       } while (0)
-#define SMC_SET_MII(lp,a,phy,v)                                        \
-       do {                                                    \
-               u32 __v;                                        \
-               do {                                            \
-                       SMC_GET_MII_ACC((lp), __v);                     \
-               } while ( __v & MII_ACC_MII_BUSY_ );            \
-               SMC_SET_MII_DATA((lp), v);                              \
-               SMC_SET_MII_ACC( (lp), ((phy)<<11) | ((a)<<6) | \
-                       MII_ACC_MII_BUSY_        |              \
-                       MII_ACC_MII_WRITE_  );                  \
-               do {                                            \
-                       SMC_GET_MII_ACC((lp), __v);                     \
-               } while ( __v & MII_ACC_MII_BUSY_ );            \
-       } while (0)
-#define SMC_GET_PHY_BMCR(lp,phy,x)             SMC_GET_MII( (lp), MII_BMCR, phy, x )
-#define SMC_SET_PHY_BMCR(lp,phy,x)             SMC_SET_MII( (lp), MII_BMCR, phy, x )
-#define SMC_GET_PHY_BMSR(lp,phy,x)             SMC_GET_MII( (lp), MII_BMSR, phy, x )
-#define SMC_GET_PHY_ID1(lp,phy,x)              SMC_GET_MII( (lp), MII_PHYSID1, phy, x )
-#define SMC_GET_PHY_ID2(lp,phy,x)              SMC_GET_MII( (lp), MII_PHYSID2, phy, x )
-#define SMC_GET_PHY_MII_ADV(lp,phy,x)  SMC_GET_MII( (lp), MII_ADVERTISE, phy, x )
-#define SMC_SET_PHY_MII_ADV(lp,phy,x)  SMC_SET_MII( (lp), MII_ADVERTISE, phy, x )
-#define SMC_GET_PHY_MII_LPA(lp,phy,x)  SMC_GET_MII( (lp), MII_LPA, phy, x )
-#define SMC_SET_PHY_MII_LPA(lp,phy,x)  SMC_SET_MII( (lp), MII_LPA, phy, x )
-#define SMC_GET_PHY_CTRL_STS(lp,phy,x) SMC_GET_MII( (lp), PHY_MODE_CTRL_STS, phy, x )
-#define SMC_SET_PHY_CTRL_STS(lp,phy,x) SMC_SET_MII( (lp), PHY_MODE_CTRL_STS, phy, x )
-#define SMC_GET_PHY_INT_SRC(lp,phy,x)  SMC_GET_MII( (lp), PHY_INT_SRC, phy, x )
-#define SMC_SET_PHY_INT_SRC(lp,phy,x)  SMC_SET_MII( (lp), PHY_INT_SRC, phy, x )
-#define SMC_GET_PHY_INT_MASK(lp,phy,x) SMC_GET_MII( (lp), PHY_INT_MASK, phy, x )
-#define SMC_SET_PHY_INT_MASK(lp,phy,x) SMC_SET_MII( (lp), PHY_INT_MASK, phy, x )
-#define SMC_GET_PHY_SPECIAL(lp,phy,x)  SMC_GET_MII( (lp), PHY_SPECIAL, phy, x )
-
-
-
-/* Misc read/write macros */
-
-#ifndef SMC_GET_MAC_ADDR
-#define SMC_GET_MAC_ADDR(lp, addr)                             \
-       do {                                                    \
-               unsigned int __v;                               \
-                                                               \
-               SMC_GET_MAC_CSR((lp), ADDRL, __v);                      \
-               addr[0] = __v; addr[1] = __v >> 8;              \
-               addr[2] = __v >> 16; addr[3] = __v >> 24;       \
-               SMC_GET_MAC_CSR((lp), ADDRH, __v);                      \
-               addr[4] = __v; addr[5] = __v >> 8;              \
-       } while (0)
-#endif
-
-#define SMC_SET_MAC_ADDR(lp, addr)                             \
-       do {                                                    \
-                SMC_SET_MAC_CSR((lp), ADDRL,                           \
-                                addr[0] |                      \
-                               (addr[1] << 8) |                \
-                               (addr[2] << 16) |               \
-                               (addr[3] << 24));               \
-                SMC_SET_MAC_CSR((lp), ADDRH, addr[4]|(addr[5] << 8));\
-       } while (0)
-
-
-#define SMC_WRITE_EEPROM_CMD(lp, cmd, addr)                            \
-       do {                                                            \
-               while (SMC_GET_E2P_CMD((lp)) & MAC_CSR_CMD_CSR_BUSY_);  \
-               SMC_SET_MAC_CMD((lp), MAC_CSR_CMD_R_NOT_W_ | a );               \
-               while (SMC_GET_MAC_CMD((lp)) & MAC_CSR_CMD_CSR_BUSY_);  \
-       } while (0)
-
-#endif  /* _SMC911X_H_ */
diff --git a/drivers/net/smc9194.c b/drivers/net/smc9194.c
deleted file mode 100644 (file)
index 5b65ac4..0000000
+++ /dev/null
@@ -1,1589 +0,0 @@
-/*------------------------------------------------------------------------
- . smc9194.c
- . This is a driver for SMC's 9000 series of Ethernet cards.
- .
- . Copyright (C) 1996 by Erik Stahlman
- . This software may be used and distributed according to the terms
- . of the GNU General Public License, incorporated herein by reference.
- .
- . "Features" of the SMC chip:
- .   4608 byte packet memory. ( for the 91C92.  Others have more )
- .   EEPROM for configuration
- .   AUI/TP selection  ( mine has 10Base2/10BaseT select )
- .
- . Arguments:
- .     io               = for the base address
- .     irq      = for the IRQ
- .     ifport = 0 for autodetect, 1 for TP, 2 for AUI ( or 10base2 )
- .
- . author:
- .     Erik Stahlman                           ( erik@vt.edu )
- . contributors:
- .      Arnaldo Carvalho de Melo <acme@conectiva.com.br>
- .
- . Hardware multicast code from Peter Cammaert ( pc@denkart.be )
- .
- . Sources:
- .    o   SMC databook
- .    o   skeleton.c by Donald Becker ( becker@scyld.com )
- .    o   ( a LOT of advice from Becker as well )
- .
- . History:
- .     12/07/95  Erik Stahlman  written, got receive/xmit handled
- .     01/03/96  Erik Stahlman  worked out some bugs, actually usable!!! :-)
- .     01/06/96  Erik Stahlman  cleaned up some, better testing, etc
- .     01/29/96  Erik Stahlman  fixed autoirq, added multicast
- .     02/01/96  Erik Stahlman  1. disabled all interrupts in smc_reset
- .                              2. got rid of post-decrementing bug -- UGH.
- .     02/13/96  Erik Stahlman  Tried to fix autoirq failure.  Added more
- .                              descriptive error messages.
- .     02/15/96  Erik Stahlman  Fixed typo that caused detection failure
- .     02/23/96  Erik Stahlman  Modified it to fit into kernel tree
- .                              Added support to change hardware address
- .                              Cleared stats on opens
- .     02/26/96  Erik Stahlman  Trial support for Kernel 1.2.13
- .                              Kludge for automatic IRQ detection
- .     03/04/96  Erik Stahlman  Fixed kernel 1.3.70 +
- .                              Fixed bug reported by Gardner Buchanan in
- .                                smc_enable, with outw instead of outb
- .     03/06/96  Erik Stahlman  Added hardware multicast from Peter Cammaert
- .     04/14/00  Heiko Pruessing (SMA Regelsysteme)  Fixed bug in chip memory
- .                              allocation
- .      08/20/00  Arnaldo Melo   fix kfree(skb) in smc_hardware_send_packet
- .      12/15/00  Christian Jullien fix "Warning: kfree_skb on hard IRQ"
- .      11/08/01 Matt Domsch     Use common crc32 function
- ----------------------------------------------------------------------------*/
-
-static const char version[] =
-       "smc9194.c:v0.14 12/15/00 by Erik Stahlman (erik@vt.edu)\n";
-
-#include <linux/module.h>
-#include <linux/kernel.h>
-#include <linux/types.h>
-#include <linux/fcntl.h>
-#include <linux/interrupt.h>
-#include <linux/ioport.h>
-#include <linux/in.h>
-#include <linux/string.h>
-#include <linux/init.h>
-#include <linux/crc32.h>
-#include <linux/errno.h>
-#include <linux/netdevice.h>
-#include <linux/etherdevice.h>
-#include <linux/skbuff.h>
-#include <linux/bitops.h>
-
-#include <asm/io.h>
-
-#include "smc9194.h"
-
-#define DRV_NAME "smc9194"
-
-/*------------------------------------------------------------------------
- .
- . Configuration options, for the experienced user to change.
- .
- -------------------------------------------------------------------------*/
-
-/*
- . Do you want to use 32 bit xfers?  This should work on all chips, as
- . the chipset is designed to accommodate them.
-*/
-#ifdef __sh__
-#undef USE_32_BIT
-#else
-#define USE_32_BIT 1
-#endif
-
-#if defined(__H8300H__) || defined(__H8300S__)
-#define NO_AUTOPROBE
-#undef insl
-#undef outsl
-#define insl(a,b,l)  io_insl_noswap(a,b,l)
-#define outsl(a,b,l) io_outsl_noswap(a,b,l)
-#endif
-
-/*
- .the SMC9194 can be at any of the following port addresses.  To change,
- .for a slightly different card, you can add it to the array.  Keep in
- .mind that the array must end in zero.
-*/
-
-struct devlist {
-       unsigned int port;
-       unsigned int irq;
-};
-
-#if defined(CONFIG_H8S_EDOSK2674)
-static struct devlist smc_devlist[] __initdata = {
-       {.port = 0xf80000, .irq = 16},
-       {.port = 0,        .irq = 0 },
-};
-#else
-static struct devlist smc_devlist[] __initdata = {
-       {.port = 0x200, .irq = 0},
-       {.port = 0x220, .irq = 0},
-       {.port = 0x240, .irq = 0},
-       {.port = 0x260, .irq = 0},
-       {.port = 0x280, .irq = 0},
-       {.port = 0x2A0, .irq = 0},
-       {.port = 0x2C0, .irq = 0},
-       {.port = 0x2E0, .irq = 0},
-       {.port = 0x300, .irq = 0},
-       {.port = 0x320, .irq = 0},
-       {.port = 0x340, .irq = 0},
-       {.port = 0x360, .irq = 0},
-       {.port = 0x380, .irq = 0},
-       {.port = 0x3A0, .irq = 0},
-       {.port = 0x3C0, .irq = 0},
-       {.port = 0x3E0, .irq = 0},
-       {.port = 0,     .irq = 0},
-};
-#endif
-/*
- . Wait time for memory to be free.  This probably shouldn't be
- . tuned that much, as waiting for this means nothing else happens
- . in the system
-*/
-#define MEMORY_WAIT_TIME 16
-
-/*
- . DEBUGGING LEVELS
- .
- . 0 for normal operation
- . 1 for slightly more details
- . >2 for various levels of increasingly useless information
- .    2 for interrupt tracking, status flags
- .    3 for packet dumps, etc.
-*/
-#define SMC_DEBUG 0
-
-#if (SMC_DEBUG > 2 )
-#define PRINTK3(x) printk x
-#else
-#define PRINTK3(x)
-#endif
-
-#if SMC_DEBUG > 1
-#define PRINTK2(x) printk x
-#else
-#define PRINTK2(x)
-#endif
-
-#ifdef SMC_DEBUG
-#define PRINTK(x) printk x
-#else
-#define PRINTK(x)
-#endif
-
-
-/*------------------------------------------------------------------------
- .
- . The internal workings of the driver.  If you are changing anything
- . here with the SMC stuff, you should have the datasheet and known
- . what you are doing.
- .
- -------------------------------------------------------------------------*/
-#define CARDNAME "SMC9194"
-
-
-/* store this information for the driver.. */
-struct smc_local {
-       /*
-          If I have to wait until memory is available to send
-          a packet, I will store the skbuff here, until I get the
-          desired memory.  Then, I'll send it out and free it.
-       */
-       struct sk_buff * saved_skb;
-
-       /*
-        . This keeps track of how many packets that I have
-        . sent out.  When an TX_EMPTY interrupt comes, I know
-        . that all of these have been sent.
-       */
-       int     packets_waiting;
-};
-
-
-/*-----------------------------------------------------------------
- .
- .  The driver can be entered at any of the following entry points.
- .
- .------------------------------------------------------------------  */
-
-/*
- . This is called by  register_netdev().  It is responsible for
- . checking the portlist for the SMC9000 series chipset.  If it finds
- . one, then it will initialize the device, find the hardware information,
- . and sets up the appropriate device parameters.
- . NOTE: Interrupts are *OFF* when this procedure is called.
- .
- . NB:This shouldn't be static since it is referred to externally.
-*/
-struct net_device *smc_init(int unit);
-
-/*
- . The kernel calls this function when someone wants to use the device,
- . typically 'ifconfig ethX up'.
-*/
-static int smc_open(struct net_device *dev);
-
-/*
- . Our watchdog timed out. Called by the networking layer
-*/
-static void smc_timeout(struct net_device *dev);
-
-/*
- . This is called by the kernel in response to 'ifconfig ethX down'.  It
- . is responsible for cleaning up everything that the open routine
- . does, and maybe putting the card into a powerdown state.
-*/
-static int smc_close(struct net_device *dev);
-
-/*
- . Finally, a call to set promiscuous mode ( for TCPDUMP and related
- . programs ) and multicast modes.
-*/
-static void smc_set_multicast_list(struct net_device *dev);
-
-
-/*---------------------------------------------------------------
- .
- . Interrupt level calls..
- .
- ----------------------------------------------------------------*/
-
-/*
- . Handles the actual interrupt
-*/
-static irqreturn_t smc_interrupt(int irq, void *);
-/*
- . This is a separate procedure to handle the receipt of a packet, to
- . leave the interrupt code looking slightly cleaner
-*/
-static inline void smc_rcv( struct net_device *dev );
-/*
- . This handles a TX interrupt, which is only called when an error
- . relating to a packet is sent.
-*/
-static inline void smc_tx( struct net_device * dev );
-
-/*
- ------------------------------------------------------------
- .
- . Internal routines
- .
- ------------------------------------------------------------
-*/
-
-/*
- . Test if a given location contains a chip, trying to cause as
- . little damage as possible if it's not a SMC chip.
-*/
-static int smc_probe(struct net_device *dev, int ioaddr);
-
-/*
- . A rather simple routine to print out a packet for debugging purposes.
-*/
-#if SMC_DEBUG > 2
-static void print_packet( byte *, int );
-#endif
-
-#define tx_done(dev) 1
-
-/* this is called to actually send the packet to the chip */
-static void smc_hardware_send_packet( struct net_device * dev );
-
-/* Since I am not sure if I will have enough room in the chip's ram
- . to store the packet, I call this routine, which either sends it
- . now, or generates an interrupt when the card is ready for the
- . packet */
-static netdev_tx_t  smc_wait_to_send_packet( struct sk_buff * skb,
-                                            struct net_device *dev );
-
-/* this does a soft reset on the device */
-static void smc_reset( int ioaddr );
-
-/* Enable Interrupts, Receive, and Transmit */
-static void smc_enable( int ioaddr );
-
-/* this puts the device in an inactive state */
-static void smc_shutdown( int ioaddr );
-
-/* This routine will find the IRQ of the driver if one is not
- . specified in the input to the device.  */
-static int smc_findirq( int ioaddr );
-
-/*
- . Function: smc_reset( int ioaddr )
- . Purpose:
- .     This sets the SMC91xx chip to its normal state, hopefully from whatever
- .     mess that any other DOS driver has put it in.
- .
- . Maybe I should reset more registers to defaults in here?  SOFTRESET  should
- . do that for me.
- .
- . Method:
- .     1.  send a SOFT RESET
- .     2.  wait for it to finish
- .     3.  enable autorelease mode
- .     4.  reset the memory management unit
- .     5.  clear all interrupts
- .
-*/
-static void smc_reset( int ioaddr )
-{
-       /* This resets the registers mostly to defaults, but doesn't
-          affect EEPROM.  That seems unnecessary */
-       SMC_SELECT_BANK( 0 );
-       outw( RCR_SOFTRESET, ioaddr + RCR );
-
-       /* this should pause enough for the chip to be happy */
-       SMC_DELAY( );
-
-       /* Set the transmit and receive configuration registers to
-          default values */
-       outw( RCR_CLEAR, ioaddr + RCR );
-       outw( TCR_CLEAR, ioaddr + TCR );
-
-       /* set the control register to automatically
-          release successfully transmitted packets, to make the best
-          use out of our limited memory */
-       SMC_SELECT_BANK( 1 );
-       outw( inw( ioaddr + CONTROL ) | CTL_AUTO_RELEASE , ioaddr + CONTROL );
-
-       /* Reset the MMU */
-       SMC_SELECT_BANK( 2 );
-       outw( MC_RESET, ioaddr + MMU_CMD );
-
-       /* Note:  It doesn't seem that waiting for the MMU busy is needed here,
-          but this is a place where future chipsets _COULD_ break.  Be wary
-          of issuing another MMU command right after this */
-
-       outb( 0, ioaddr + INT_MASK );
-}
-
-/*
- . Function: smc_enable
- . Purpose: let the chip talk to the outside work
- . Method:
- .     1.  Enable the transmitter
- .     2.  Enable the receiver
- .     3.  Enable interrupts
-*/
-static void smc_enable( int ioaddr )
-{
-       SMC_SELECT_BANK( 0 );
-       /* see the header file for options in TCR/RCR NORMAL*/
-       outw( TCR_NORMAL, ioaddr + TCR );
-       outw( RCR_NORMAL, ioaddr + RCR );
-
-       /* now, enable interrupts */
-       SMC_SELECT_BANK( 2 );
-       outb( SMC_INTERRUPT_MASK, ioaddr + INT_MASK );
-}
-
-/*
- . Function: smc_shutdown
- . Purpose:  closes down the SMC91xxx chip.
- . Method:
- .     1. zero the interrupt mask
- .     2. clear the enable receive flag
- .     3. clear the enable xmit flags
- .
- . TODO:
- .   (1) maybe utilize power down mode.
- .     Why not yet?  Because while the chip will go into power down mode,
- .     the manual says that it will wake up in response to any I/O requests
- .     in the register space.   Empirical results do not show this working.
-*/
-static void smc_shutdown( int ioaddr )
-{
-       /* no more interrupts for me */
-       SMC_SELECT_BANK( 2 );
-       outb( 0, ioaddr + INT_MASK );
-
-       /* and tell the card to stay away from that nasty outside world */
-       SMC_SELECT_BANK( 0 );
-       outb( RCR_CLEAR, ioaddr + RCR );
-       outb( TCR_CLEAR, ioaddr + TCR );
-#if 0
-       /* finally, shut the chip down */
-       SMC_SELECT_BANK( 1 );
-       outw( inw( ioaddr + CONTROL ), CTL_POWERDOWN, ioaddr + CONTROL  );
-#endif
-}
-
-
-/*
- . Function: smc_setmulticast( int ioaddr, struct net_device *dev )
- . Purpose:
- .    This sets the internal hardware table to filter out unwanted multicast
- .    packets before they take up memory.
- .
- .    The SMC chip uses a hash table where the high 6 bits of the CRC of
- .    address are the offset into the table.  If that bit is 1, then the
- .    multicast packet is accepted.  Otherwise, it's dropped silently.
- .
- .    To use the 6 bits as an offset into the table, the high 3 bits are the
- .    number of the 8 bit register, while the low 3 bits are the bit within
- .    that register.
- .
- . This routine is based very heavily on the one provided by Peter Cammaert.
-*/
-
-
-static void smc_setmulticast(int ioaddr, struct net_device *dev)
-{
-       int                     i;
-       unsigned char           multicast_table[ 8 ];
-       struct netdev_hw_addr *ha;
-       /* table for flipping the order of 3 bits */
-       unsigned char invert3[] = { 0, 4, 2, 6, 1, 5, 3, 7 };
-
-       /* start with a table of all zeros: reject all */
-       memset( multicast_table, 0, sizeof( multicast_table ) );
-
-       netdev_for_each_mc_addr(ha, dev) {
-               int position;
-
-               /* only use the low order bits */
-               position = ether_crc_le(6, ha->addr) & 0x3f;
-
-               /* do some messy swapping to put the bit in the right spot */
-               multicast_table[invert3[position&7]] |=
-                                       (1<<invert3[(position>>3)&7]);
-
-       }
-       /* now, the table can be loaded into the chipset */
-       SMC_SELECT_BANK( 3 );
-
-       for ( i = 0; i < 8 ; i++ ) {
-               outb( multicast_table[i], ioaddr + MULTICAST1 + i );
-       }
-}
-
-/*
- . Function: smc_wait_to_send_packet( struct sk_buff * skb, struct net_device * )
- . Purpose:
- .    Attempt to allocate memory for a packet, if chip-memory is not
- .    available, then tell the card to generate an interrupt when it
- .    is available.
- .
- . Algorithm:
- .
- . o   if the saved_skb is not currently null, then drop this packet
- .     on the floor.  This should never happen, because of TBUSY.
- . o   if the saved_skb is null, then replace it with the current packet,
- . o   See if I can sending it now.
- . o   (NO): Enable interrupts and let the interrupt handler deal with it.
- . o   (YES):Send it now.
-*/
-static netdev_tx_t smc_wait_to_send_packet(struct sk_buff *skb,
-                                          struct net_device *dev)
-{
-       struct smc_local *lp = netdev_priv(dev);
-       unsigned int ioaddr     = dev->base_addr;
-       word                    length;
-       unsigned short          numPages;
-       word                    time_out;
-
-       netif_stop_queue(dev);
-       /* Well, I want to send the packet.. but I don't know
-          if I can send it right now...  */
-
-       if ( lp->saved_skb) {
-               /* THIS SHOULD NEVER HAPPEN. */
-               dev->stats.tx_aborted_errors++;
-               printk(CARDNAME": Bad Craziness - sent packet while busy.\n" );
-               return NETDEV_TX_BUSY;
-       }
-       lp->saved_skb = skb;
-
-       length = skb->len;
-
-       if (length < ETH_ZLEN) {
-               if (skb_padto(skb, ETH_ZLEN)) {
-                       netif_wake_queue(dev);
-                       return NETDEV_TX_OK;
-               }
-               length = ETH_ZLEN;
-       }
-
-       /*
-       ** The MMU wants the number of pages to be the number of 256 bytes
-       ** 'pages', minus 1 ( since a packet can't ever have 0 pages :) )
-       **
-       ** Pkt size for allocating is data length +6 (for additional status words,
-       ** length and ctl!) If odd size last byte is included in this header.
-       */
-       numPages =  ((length & 0xfffe) + 6) / 256;
-
-       if (numPages > 7 ) {
-               printk(CARDNAME": Far too big packet error.\n");
-               /* freeing the packet is a good thing here... but should
-                . any packets of this size get down here?   */
-               dev_kfree_skb (skb);
-               lp->saved_skb = NULL;
-               /* this IS an error, but, i don't want the skb saved */
-               netif_wake_queue(dev);
-               return NETDEV_TX_OK;
-       }
-       /* either way, a packet is waiting now */
-       lp->packets_waiting++;
-
-       /* now, try to allocate the memory */
-       SMC_SELECT_BANK( 2 );
-       outw( MC_ALLOC | numPages, ioaddr + MMU_CMD );
-       /*
-       . Performance Hack
-       .
-       . wait a short amount of time.. if I can send a packet now, I send
-       . it now.  Otherwise, I enable an interrupt and wait for one to be
-       . available.
-       .
-       . I could have handled this a slightly different way, by checking to
-       . see if any memory was available in the FREE MEMORY register.  However,
-       . either way, I need to generate an allocation, and the allocation works
-       . no matter what, so I saw no point in checking free memory.
-       */
-       time_out = MEMORY_WAIT_TIME;
-       do {
-               word    status;
-
-               status = inb( ioaddr + INTERRUPT );
-               if ( status & IM_ALLOC_INT ) {
-                       /* acknowledge the interrupt */
-                       outb( IM_ALLOC_INT, ioaddr + INTERRUPT );
-                       break;
-               }
-       } while ( -- time_out );
-
-       if ( !time_out ) {
-               /* oh well, wait until the chip finds memory later */
-               SMC_ENABLE_INT( IM_ALLOC_INT );
-               PRINTK2((CARDNAME": memory allocation deferred.\n"));
-               /* it's deferred, but I'll handle it later */
-               return NETDEV_TX_OK;
-       }
-       /* or YES! I can send the packet now.. */
-       smc_hardware_send_packet(dev);
-       netif_wake_queue(dev);
-       return NETDEV_TX_OK;
-}
-
-/*
- . Function:  smc_hardware_send_packet(struct net_device * )
- . Purpose:
- .     This sends the actual packet to the SMC9xxx chip.
- .
- . Algorithm:
- .     First, see if a saved_skb is available.
- .             ( this should NOT be called if there is no 'saved_skb'
- .     Now, find the packet number that the chip allocated
- .     Point the data pointers at it in memory
- .     Set the length word in the chip's memory
- .     Dump the packet to chip memory
- .     Check if a last byte is needed ( odd length packet )
- .             if so, set the control flag right
- .     Tell the card to send it
- .     Enable the transmit interrupt, so I know if it failed
- .     Free the kernel data if I actually sent it.
-*/
-static void smc_hardware_send_packet( struct net_device * dev )
-{
-       struct smc_local *lp = netdev_priv(dev);
-       byte                    packet_no;
-       struct sk_buff *        skb = lp->saved_skb;
-       word                    length;
-       unsigned int            ioaddr;
-       byte                    * buf;
-
-       ioaddr = dev->base_addr;
-
-       if ( !skb ) {
-               PRINTK((CARDNAME": In XMIT with no packet to send\n"));
-               return;
-       }
-       length = ETH_ZLEN < skb->len ? skb->len : ETH_ZLEN;
-       buf = skb->data;
-
-       /* If I get here, I _know_ there is a packet slot waiting for me */
-       packet_no = inb( ioaddr + PNR_ARR + 1 );
-       if ( packet_no & 0x80 ) {
-               /* or isn't there?  BAD CHIP! */
-               printk(KERN_DEBUG CARDNAME": Memory allocation failed.\n");
-               dev_kfree_skb_any(skb);
-               lp->saved_skb = NULL;
-               netif_wake_queue(dev);
-               return;
-       }
-
-       /* we have a packet address, so tell the card to use it */
-       outb( packet_no, ioaddr + PNR_ARR );
-
-       /* point to the beginning of the packet */
-       outw( PTR_AUTOINC , ioaddr + POINTER );
-
-       PRINTK3((CARDNAME": Trying to xmit packet of length %x\n", length ));
-#if SMC_DEBUG > 2
-       print_packet( buf, length );
-#endif
-
-       /* send the packet length ( +6 for status, length and ctl byte )
-          and the status word ( set to zeros ) */
-#ifdef USE_32_BIT
-       outl(  (length +6 ) << 16 , ioaddr + DATA_1 );
-#else
-       outw( 0, ioaddr + DATA_1 );
-       /* send the packet length ( +6 for status words, length, and ctl*/
-       outb( (length+6) & 0xFF,ioaddr + DATA_1 );
-       outb( (length+6) >> 8 , ioaddr + DATA_1 );
-#endif
-
-       /* send the actual data
-        . I _think_ it's faster to send the longs first, and then
-        . mop up by sending the last word.  It depends heavily
-        . on alignment, at least on the 486.  Maybe it would be
-        . a good idea to check which is optimal?  But that could take
-        . almost as much time as is saved?
-       */
-#ifdef USE_32_BIT
-       if ( length & 0x2  ) {
-               outsl(ioaddr + DATA_1, buf,  length >> 2 );
-#if !defined(__H8300H__) && !defined(__H8300S__)
-               outw( *((word *)(buf + (length & 0xFFFFFFFC))),ioaddr +DATA_1);
-#else
-               ctrl_outw( *((word *)(buf + (length & 0xFFFFFFFC))),ioaddr +DATA_1);
-#endif
-       }
-       else
-               outsl(ioaddr + DATA_1, buf,  length >> 2 );
-#else
-       outsw(ioaddr + DATA_1 , buf, (length ) >> 1);
-#endif
-       /* Send the last byte, if there is one.   */
-
-       if ( (length & 1) == 0 ) {
-               outw( 0, ioaddr + DATA_1 );
-       } else {
-               outb( buf[length -1 ], ioaddr + DATA_1 );
-               outb( 0x20, ioaddr + DATA_1);
-       }
-
-       /* enable the interrupts */
-       SMC_ENABLE_INT( (IM_TX_INT | IM_TX_EMPTY_INT) );
-
-       /* and let the chipset deal with it */
-       outw( MC_ENQUEUE , ioaddr + MMU_CMD );
-
-       PRINTK2((CARDNAME": Sent packet of length %d\n", length));
-
-       lp->saved_skb = NULL;
-       dev_kfree_skb_any (skb);
-
-       dev->trans_start = jiffies;
-
-       /* we can send another packet */
-       netif_wake_queue(dev);
-}
-
-/*-------------------------------------------------------------------------
- |
- | smc_init(int unit)
- |   Input parameters:
- |     dev->base_addr == 0, try to find all possible locations
- |     dev->base_addr == 1, return failure code
- |     dev->base_addr == 2, always allocate space,  and return success
- |     dev->base_addr == <anything else>   this is the address to check
- |
- |   Output:
- |     pointer to net_device or ERR_PTR(error)
- |
- ---------------------------------------------------------------------------
-*/
-static int io;
-static int irq;
-static int ifport;
-
-struct net_device * __init smc_init(int unit)
-{
-       struct net_device *dev = alloc_etherdev(sizeof(struct smc_local));
-       struct devlist *smcdev = smc_devlist;
-       int err = 0;
-
-       if (!dev)
-               return ERR_PTR(-ENODEV);
-
-       if (unit >= 0) {
-               sprintf(dev->name, "eth%d", unit);
-               netdev_boot_setup_check(dev);
-               io = dev->base_addr;
-               irq = dev->irq;
-       }
-
-       if (io > 0x1ff) {       /* Check a single specified location. */
-               err = smc_probe(dev, io);
-       } else if (io != 0) {   /* Don't probe at all. */
-               err = -ENXIO;
-       } else {
-               for (;smcdev->port; smcdev++) {
-                       if (smc_probe(dev, smcdev->port) == 0)
-                               break;
-               }
-               if (!smcdev->port)
-                       err = -ENODEV;
-       }
-       if (err)
-               goto out;
-       err = register_netdev(dev);
-       if (err)
-               goto out1;
-       return dev;
-out1:
-       free_irq(dev->irq, dev);
-       release_region(dev->base_addr, SMC_IO_EXTENT);
-out:
-       free_netdev(dev);
-       return ERR_PTR(err);
-}
-
-/*----------------------------------------------------------------------
- . smc_findirq
- .
- . This routine has a simple purpose -- make the SMC chip generate an
- . interrupt, so an auto-detect routine can detect it, and find the IRQ,
- ------------------------------------------------------------------------
-*/
-static int __init smc_findirq(int ioaddr)
-{
-#ifndef NO_AUTOPROBE
-       int     timeout = 20;
-       unsigned long cookie;
-
-
-       cookie = probe_irq_on();
-
-       /*
-        * What I try to do here is trigger an ALLOC_INT. This is done
-        * by allocating a small chunk of memory, which will give an interrupt
-        * when done.
-        */
-
-
-       SMC_SELECT_BANK(2);
-       /* enable ALLOCation interrupts ONLY */
-       outb( IM_ALLOC_INT, ioaddr + INT_MASK );
-
-       /*
-        . Allocate 512 bytes of memory.  Note that the chip was just
-        . reset so all the memory is available
-       */
-       outw( MC_ALLOC | 1, ioaddr + MMU_CMD );
-
-       /*
-        . Wait until positive that the interrupt has been generated
-       */
-       while ( timeout ) {
-               byte    int_status;
-
-               int_status = inb( ioaddr + INTERRUPT );
-
-               if ( int_status & IM_ALLOC_INT )
-                       break;          /* got the interrupt */
-               timeout--;
-       }
-       /* there is really nothing that I can do here if timeout fails,
-          as probe_irq_off will return a 0 anyway, which is what I
-          want in this case.   Plus, the clean up is needed in both
-          cases.  */
-
-       /* DELAY HERE!
-          On a fast machine, the status might change before the interrupt
-          is given to the processor.  This means that the interrupt was
-          never detected, and probe_irq_off fails to report anything.
-          This should fix probe_irq_* problems.
-       */
-       SMC_DELAY();
-       SMC_DELAY();
-
-       /* and disable all interrupts again */
-       outb( 0, ioaddr + INT_MASK );
-
-       /* and return what I found */
-       return probe_irq_off(cookie);
-#else /* NO_AUTOPROBE */
-       struct devlist *smcdev;
-       for (smcdev = smc_devlist; smcdev->port; smcdev++) {
-               if (smcdev->port == ioaddr)
-                       return smcdev->irq;
-       }
-       return 0;
-#endif
-}
-
-static const struct net_device_ops smc_netdev_ops = {
-       .ndo_open                = smc_open,
-       .ndo_stop               = smc_close,
-       .ndo_start_xmit         = smc_wait_to_send_packet,
-       .ndo_tx_timeout         = smc_timeout,
-       .ndo_set_multicast_list = smc_set_multicast_list,
-       .ndo_change_mtu         = eth_change_mtu,
-       .ndo_set_mac_address    = eth_mac_addr,
-       .ndo_validate_addr      = eth_validate_addr,
-};
-
-/*----------------------------------------------------------------------
- . Function: smc_probe( int ioaddr )
- .
- . Purpose:
- .     Tests to see if a given ioaddr points to an SMC9xxx chip.
- .     Returns a 0 on success
- .
- . Algorithm:
- .     (1) see if the high byte of BANK_SELECT is 0x33
- .     (2) compare the ioaddr with the base register's address
- .     (3) see if I recognize the chip ID in the appropriate register
- .
- .---------------------------------------------------------------------
- */
-
-/*---------------------------------------------------------------
- . Here I do typical initialization tasks.
- .
- . o  Initialize the structure if needed
- . o  print out my vanity message if not done so already
- . o  print out what type of hardware is detected
- . o  print out the ethernet address
- . o  find the IRQ
- . o  set up my private data
- . o  configure the dev structure with my subroutines
- . o  actually GRAB the irq.
- . o  GRAB the region
- .-----------------------------------------------------------------
-*/
-static int __init smc_probe(struct net_device *dev, int ioaddr)
-{
-       int i, memory, retval;
-       static unsigned version_printed;
-       unsigned int bank;
-
-       const char *version_string;
-       const char *if_string;
-
-       /* registers */
-       word revision_register;
-       word base_address_register;
-       word configuration_register;
-       word memory_info_register;
-       word memory_cfg_register;
-
-       /* Grab the region so that no one else tries to probe our ioports. */
-       if (!request_region(ioaddr, SMC_IO_EXTENT, DRV_NAME))
-               return -EBUSY;
-
-       dev->irq = irq;
-       dev->if_port = ifport;
-
-       /* First, see if the high byte is 0x33 */
-       bank = inw( ioaddr + BANK_SELECT );
-       if ( (bank & 0xFF00) != 0x3300 ) {
-               retval = -ENODEV;
-               goto err_out;
-       }
-       /* The above MIGHT indicate a device, but I need to write to further
-               test this.  */
-       outw( 0x0, ioaddr + BANK_SELECT );
-       bank = inw( ioaddr + BANK_SELECT );
-       if ( (bank & 0xFF00 ) != 0x3300 ) {
-               retval = -ENODEV;
-               goto err_out;
-       }
-#if !defined(CONFIG_H8S_EDOSK2674)
-       /* well, we've already written once, so hopefully another time won't
-          hurt.  This time, I need to switch the bank register to bank 1,
-          so I can access the base address register */
-       SMC_SELECT_BANK(1);
-       base_address_register = inw( ioaddr + BASE );
-       if ( ioaddr != ( base_address_register >> 3 & 0x3E0 ) )  {
-               printk(CARDNAME ": IOADDR %x doesn't match configuration (%x). "
-                       "Probably not a SMC chip\n",
-                       ioaddr, base_address_register >> 3 & 0x3E0 );
-               /* well, the base address register didn't match.  Must not have
-                  been a SMC chip after all. */
-               retval = -ENODEV;
-               goto err_out;
-       }
-#else
-       (void)base_address_register; /* Warning suppression */
-#endif
-
-
-       /*  check if the revision register is something that I recognize.
-           These might need to be added to later, as future revisions
-           could be added.  */
-       SMC_SELECT_BANK(3);
-       revision_register  = inw( ioaddr + REVISION );
-       if ( !chip_ids[ ( revision_register  >> 4 ) & 0xF  ] ) {
-               /* I don't recognize this chip, so... */
-               printk(CARDNAME ": IO %x: Unrecognized revision register:"
-                       " %x, Contact author.\n", ioaddr, revision_register);
-
-               retval = -ENODEV;
-               goto err_out;
-       }
-
-       /* at this point I'll assume that the chip is an SMC9xxx.
-          It might be prudent to check a listing of MAC addresses
-          against the hardware address, or do some other tests. */
-
-       if (version_printed++ == 0)
-               printk("%s", version);
-
-       /* fill in some of the fields */
-       dev->base_addr = ioaddr;
-
-       /*
-        . Get the MAC address ( bank 1, regs 4 - 9 )
-       */
-       SMC_SELECT_BANK( 1 );
-       for ( i = 0; i < 6; i += 2 ) {
-               word    address;
-
-               address = inw( ioaddr + ADDR0 + i  );
-               dev->dev_addr[ i + 1] = address >> 8;
-               dev->dev_addr[ i ] = address & 0xFF;
-       }
-
-       /* get the memory information */
-
-       SMC_SELECT_BANK( 0 );
-       memory_info_register = inw( ioaddr + MIR );
-       memory_cfg_register  = inw( ioaddr + MCR );
-       memory = ( memory_cfg_register >> 9 )  & 0x7;  /* multiplier */
-       memory *= 256 * ( memory_info_register & 0xFF );
-
-       /*
-        Now, I want to find out more about the chip.  This is sort of
-        redundant, but it's cleaner to have it in both, rather than having
-        one VERY long probe procedure.
-       */
-       SMC_SELECT_BANK(3);
-       revision_register  = inw( ioaddr + REVISION );
-       version_string = chip_ids[ ( revision_register  >> 4 ) & 0xF  ];
-       if ( !version_string ) {
-               /* I shouldn't get here because this call was done before.... */
-               retval = -ENODEV;
-               goto err_out;
-       }
-
-       /* is it using AUI or 10BaseT ? */
-       if ( dev->if_port == 0 ) {
-               SMC_SELECT_BANK(1);
-               configuration_register = inw( ioaddr + CONFIG );
-               if ( configuration_register & CFG_AUI_SELECT )
-                       dev->if_port = 2;
-               else
-                       dev->if_port = 1;
-       }
-       if_string = interfaces[ dev->if_port - 1 ];
-
-       /* now, reset the chip, and put it into a known state */
-       smc_reset( ioaddr );
-
-       /*
-        . If dev->irq is 0, then the device has to be banged on to see
-        . what the IRQ is.
-        .
-        . This banging doesn't always detect the IRQ, for unknown reasons.
-        . a workaround is to reset the chip and try again.
-        .
-        . Interestingly, the DOS packet driver *SETS* the IRQ on the card to
-        . be what is requested on the command line.   I don't do that, mostly
-        . because the card that I have uses a non-standard method of accessing
-        . the IRQs, and because this _should_ work in most configurations.
-        .
-        . Specifying an IRQ is done with the assumption that the user knows
-        . what (s)he is doing.  No checking is done!!!!
-        .
-       */
-       if ( dev->irq < 2 ) {
-               int     trials;
-
-               trials = 3;
-               while ( trials-- ) {
-                       dev->irq = smc_findirq( ioaddr );
-                       if ( dev->irq )
-                               break;
-                       /* kick the card and try again */
-                       smc_reset( ioaddr );
-               }
-       }
-       if (dev->irq == 0 ) {
-               printk(CARDNAME": Couldn't autodetect your IRQ. Use irq=xx.\n");
-               retval = -ENODEV;
-               goto err_out;
-       }
-
-       /* now, print out the card info, in a short format.. */
-
-       printk("%s: %s(r:%d) at %#3x IRQ:%d INTF:%s MEM:%db ", dev->name,
-               version_string, revision_register & 0xF, ioaddr, dev->irq,
-               if_string, memory );
-       /*
-        . Print the Ethernet address
-       */
-       printk("ADDR: %pM\n", dev->dev_addr);
-
-       /* Grab the IRQ */
-       retval = request_irq(dev->irq, smc_interrupt, 0, DRV_NAME, dev);
-       if (retval) {
-               printk("%s: unable to get IRQ %d (irqval=%d).\n", DRV_NAME,
-                       dev->irq, retval);
-               goto err_out;
-       }
-
-       dev->netdev_ops                 = &smc_netdev_ops;
-       dev->watchdog_timeo             = HZ/20;
-
-       return 0;
-
-err_out:
-       release_region(ioaddr, SMC_IO_EXTENT);
-       return retval;
-}
-
-#if SMC_DEBUG > 2
-static void print_packet( byte * buf, int length )
-{
-#if 0
-       int i;
-       int remainder;
-       int lines;
-
-       printk("Packet of length %d\n", length);
-       lines = length / 16;
-       remainder = length % 16;
-
-       for ( i = 0; i < lines ; i ++ ) {
-               int cur;
-
-               for ( cur = 0; cur < 8; cur ++ ) {
-                       byte a, b;
-
-                       a = *(buf ++ );
-                       b = *(buf ++ );
-                       printk("%02x%02x ", a, b );
-               }
-               printk("\n");
-       }
-       for ( i = 0; i < remainder/2 ; i++ ) {
-               byte a, b;
-
-               a = *(buf ++ );
-               b = *(buf ++ );
-               printk("%02x%02x ", a, b );
-       }
-       printk("\n");
-#endif
-}
-#endif
-
-
-/*
- * Open and Initialize the board
- *
- * Set up everything, reset the card, etc ..
- *
- */
-static int smc_open(struct net_device *dev)
-{
-       int     ioaddr = dev->base_addr;
-
-       int     i;      /* used to set hw ethernet address */
-
-       /* clear out all the junk that was put here before... */
-       memset(netdev_priv(dev), 0, sizeof(struct smc_local));
-
-       /* reset the hardware */
-
-       smc_reset( ioaddr );
-       smc_enable( ioaddr );
-
-       /* Select which interface to use */
-
-       SMC_SELECT_BANK( 1 );
-       if ( dev->if_port == 1 ) {
-               outw( inw( ioaddr + CONFIG ) & ~CFG_AUI_SELECT,
-                       ioaddr + CONFIG );
-       }
-       else if ( dev->if_port == 2 ) {
-               outw( inw( ioaddr + CONFIG ) | CFG_AUI_SELECT,
-                       ioaddr + CONFIG );
-       }
-
-       /*
-               According to Becker, I have to set the hardware address
-               at this point, because the (l)user can set it with an
-               ioctl.  Easily done...
-       */
-       SMC_SELECT_BANK( 1 );
-       for ( i = 0; i < 6; i += 2 ) {
-               word    address;
-
-               address = dev->dev_addr[ i + 1 ] << 8 ;
-               address  |= dev->dev_addr[ i ];
-               outw( address, ioaddr + ADDR0 + i );
-       }
-
-       netif_start_queue(dev);
-       return 0;
-}
-
-/*--------------------------------------------------------
- . Called by the kernel to send a packet out into the void
- . of the net.  This routine is largely based on
- . skeleton.c, from Becker.
- .--------------------------------------------------------
-*/
-
-static void smc_timeout(struct net_device *dev)
-{
-       /* If we get here, some higher level has decided we are broken.
-          There should really be a "kick me" function call instead. */
-       printk(KERN_WARNING CARDNAME": transmit timed out, %s?\n",
-               tx_done(dev) ? "IRQ conflict" :
-               "network cable problem");
-       /* "kick" the adaptor */
-       smc_reset( dev->base_addr );
-       smc_enable( dev->base_addr );
-       dev->trans_start = jiffies; /* prevent tx timeout */
-       /* clear anything saved */
-       ((struct smc_local *)netdev_priv(dev))->saved_skb = NULL;
-       netif_wake_queue(dev);
-}
-
-/*-------------------------------------------------------------
- .
- . smc_rcv -  receive a packet from the card
- .
- . There is ( at least ) a packet waiting to be read from
- . chip-memory.
- .
- . o Read the status
- . o If an error, record it
- . o otherwise, read in the packet
- --------------------------------------------------------------
-*/
-static void smc_rcv(struct net_device *dev)
-{
-       int     ioaddr = dev->base_addr;
-       int     packet_number;
-       word    status;
-       word    packet_length;
-
-       /* assume bank 2 */
-
-       packet_number = inw( ioaddr + FIFO_PORTS );
-
-       if ( packet_number & FP_RXEMPTY ) {
-               /* we got called , but nothing was on the FIFO */
-               PRINTK((CARDNAME ": WARNING: smc_rcv with nothing on FIFO.\n"));
-               /* don't need to restore anything */
-               return;
-       }
-
-       /*  start reading from the start of the packet */
-       outw( PTR_READ | PTR_RCV | PTR_AUTOINC, ioaddr + POINTER );
-
-       /* First two words are status and packet_length */
-       status          = inw( ioaddr + DATA_1 );
-       packet_length   = inw( ioaddr + DATA_1 );
-
-       packet_length &= 0x07ff;  /* mask off top bits */
-
-       PRINTK2(("RCV: STATUS %4x LENGTH %4x\n", status, packet_length ));
-       /*
-        . the packet length contains 3 extra words :
-        . status, length, and an extra word with an odd byte .
-       */
-       packet_length -= 6;
-
-       if ( !(status & RS_ERRORS ) ){
-               /* do stuff to make a new packet */
-               struct sk_buff  * skb;
-               byte            * data;
-
-               /* read one extra byte */
-               if ( status & RS_ODDFRAME )
-                       packet_length++;
-
-               /* set multicast stats */
-               if ( status & RS_MULTICAST )
-                       dev->stats.multicast++;
-
-               skb = dev_alloc_skb( packet_length + 5);
-
-               if ( skb == NULL ) {
-                       printk(KERN_NOTICE CARDNAME ": Low memory, packet dropped.\n");
-                       dev->stats.rx_dropped++;
-                       goto done;
-               }
-
-               /*
-                ! This should work without alignment, but it could be
-                ! in the worse case
-               */
-
-               skb_reserve( skb, 2 );   /* 16 bit alignment */
-
-               data = skb_put( skb, packet_length);
-
-#ifdef USE_32_BIT
-               /* QUESTION:  Like in the TX routine, do I want
-                  to send the DWORDs or the bytes first, or some
-                  mixture.  A mixture might improve already slow PIO
-                  performance  */
-               PRINTK3((" Reading %d dwords (and %d bytes)\n",
-                       packet_length >> 2, packet_length & 3 ));
-               insl(ioaddr + DATA_1 , data, packet_length >> 2 );
-               /* read the left over bytes */
-               insb( ioaddr + DATA_1, data + (packet_length & 0xFFFFFC),
-                       packet_length & 0x3  );
-#else
-               PRINTK3((" Reading %d words and %d byte(s)\n",
-                       (packet_length >> 1 ), packet_length & 1 ));
-               insw(ioaddr + DATA_1 , data, packet_length >> 1);
-               if ( packet_length & 1 ) {
-                       data += packet_length & ~1;
-                       *(data++) = inb( ioaddr + DATA_1 );
-               }
-#endif
-#if    SMC_DEBUG > 2
-                       print_packet( data, packet_length );
-#endif
-
-               skb->protocol = eth_type_trans(skb, dev );
-               netif_rx(skb);
-               dev->stats.rx_packets++;
-               dev->stats.rx_bytes += packet_length;
-       } else {
-               /* error ... */
-               dev->stats.rx_errors++;
-
-               if ( status & RS_ALGNERR )  dev->stats.rx_frame_errors++;
-               if ( status & (RS_TOOSHORT | RS_TOOLONG ) )
-                       dev->stats.rx_length_errors++;
-               if ( status & RS_BADCRC)        dev->stats.rx_crc_errors++;
-       }
-
-done:
-       /*  error or good, tell the card to get rid of this packet */
-       outw( MC_RELEASE, ioaddr + MMU_CMD );
-}
-
-
-/*************************************************************************
- . smc_tx
- .
- . Purpose:  Handle a transmit error message.   This will only be called
- .   when an error, because of the AUTO_RELEASE mode.
- .
- . Algorithm:
- .     Save pointer and packet no
- .     Get the packet no from the top of the queue
- .     check if it's valid ( if not, is this an error??? )
- .     read the status word
- .     record the error
- .     ( resend?  Not really, since we don't want old packets around )
- .     Restore saved values
- ************************************************************************/
-static void smc_tx( struct net_device * dev )
-{
-       int     ioaddr = dev->base_addr;
-       struct smc_local *lp = netdev_priv(dev);
-       byte saved_packet;
-       byte packet_no;
-       word tx_status;
-
-
-       /* assume bank 2  */
-
-       saved_packet = inb( ioaddr + PNR_ARR );
-       packet_no = inw( ioaddr + FIFO_PORTS );
-       packet_no &= 0x7F;
-
-       /* select this as the packet to read from */
-       outb( packet_no, ioaddr + PNR_ARR );
-
-       /* read the first word from this packet */
-       outw( PTR_AUTOINC | PTR_READ, ioaddr + POINTER );
-
-       tx_status = inw( ioaddr + DATA_1 );
-       PRINTK3((CARDNAME": TX DONE STATUS: %4x\n", tx_status));
-
-       dev->stats.tx_errors++;
-       if ( tx_status & TS_LOSTCAR ) dev->stats.tx_carrier_errors++;
-       if ( tx_status & TS_LATCOL  ) {
-               printk(KERN_DEBUG CARDNAME
-                       ": Late collision occurred on last xmit.\n");
-               dev->stats.tx_window_errors++;
-       }
-#if 0
-               if ( tx_status & TS_16COL ) { ... }
-#endif
-
-       if ( tx_status & TS_SUCCESS ) {
-               printk(CARDNAME": Successful packet caused interrupt\n");
-       }
-       /* re-enable transmit */
-       SMC_SELECT_BANK( 0 );
-       outw( inw( ioaddr + TCR ) | TCR_ENABLE, ioaddr + TCR );
-
-       /* kill the packet */
-       SMC_SELECT_BANK( 2 );
-       outw( MC_FREEPKT, ioaddr + MMU_CMD );
-
-       /* one less packet waiting for me */
-       lp->packets_waiting--;
-
-       outb( saved_packet, ioaddr + PNR_ARR );
-}
-
-/*--------------------------------------------------------------------
- .
- . This is the main routine of the driver, to handle the device when
- . it needs some attention.
- .
- . So:
- .   first, save state of the chipset
- .   branch off into routines to handle each case, and acknowledge
- .         each to the interrupt register
- .   and finally restore state.
- .
- ---------------------------------------------------------------------*/
-
-static irqreturn_t smc_interrupt(int irq, void * dev_id)
-{
-       struct net_device *dev  = dev_id;
-       int ioaddr              = dev->base_addr;
-       struct smc_local *lp = netdev_priv(dev);
-
-       byte    status;
-       word    card_stats;
-       byte    mask;
-       int     timeout;
-       /* state registers */
-       word    saved_bank;
-       word    saved_pointer;
-       int handled = 0;
-
-
-       PRINTK3((CARDNAME": SMC interrupt started\n"));
-
-       saved_bank = inw( ioaddr + BANK_SELECT );
-
-       SMC_SELECT_BANK(2);
-       saved_pointer = inw( ioaddr + POINTER );
-
-       mask = inb( ioaddr + INT_MASK );
-       /* clear all interrupts */
-       outb( 0, ioaddr + INT_MASK );
-
-
-       /* set a timeout value, so I don't stay here forever */
-       timeout = 4;
-
-       PRINTK2((KERN_WARNING CARDNAME ": MASK IS %x\n", mask));
-       do {
-               /* read the status flag, and mask it */
-               status = inb( ioaddr + INTERRUPT ) & mask;
-               if (!status )
-                       break;
-
-               handled = 1;
-
-               PRINTK3((KERN_WARNING CARDNAME
-                       ": Handling interrupt status %x\n", status));
-
-               if (status & IM_RCV_INT) {
-                       /* Got a packet(s). */
-                       PRINTK2((KERN_WARNING CARDNAME
-                               ": Receive Interrupt\n"));
-                       smc_rcv(dev);
-               } else if (status & IM_TX_INT ) {
-                       PRINTK2((KERN_WARNING CARDNAME
-                               ": TX ERROR handled\n"));
-                       smc_tx(dev);
-                       outb(IM_TX_INT, ioaddr + INTERRUPT );
-               } else if (status & IM_TX_EMPTY_INT ) {
-                       /* update stats */
-                       SMC_SELECT_BANK( 0 );
-                       card_stats = inw( ioaddr + COUNTER );
-                       /* single collisions */
-                       dev->stats.collisions += card_stats & 0xF;
-                       card_stats >>= 4;
-                       /* multiple collisions */
-                       dev->stats.collisions += card_stats & 0xF;
-
-                       /* these are for when linux supports these statistics */
-
-                       SMC_SELECT_BANK( 2 );
-                       PRINTK2((KERN_WARNING CARDNAME
-                               ": TX_BUFFER_EMPTY handled\n"));
-                       outb( IM_TX_EMPTY_INT, ioaddr + INTERRUPT );
-                       mask &= ~IM_TX_EMPTY_INT;
-                       dev->stats.tx_packets += lp->packets_waiting;
-                       lp->packets_waiting = 0;
-
-               } else if (status & IM_ALLOC_INT ) {
-                       PRINTK2((KERN_DEBUG CARDNAME
-                               ": Allocation interrupt\n"));
-                       /* clear this interrupt so it doesn't happen again */
-                       mask &= ~IM_ALLOC_INT;
-
-                       smc_hardware_send_packet( dev );
-
-                       /* enable xmit interrupts based on this */
-                       mask |= ( IM_TX_EMPTY_INT | IM_TX_INT );
-
-                       /* and let the card send more packets to me */
-                       netif_wake_queue(dev);
-
-                       PRINTK2((CARDNAME": Handoff done successfully.\n"));
-               } else if (status & IM_RX_OVRN_INT ) {
-                       dev->stats.rx_errors++;
-                       dev->stats.rx_fifo_errors++;
-                       outb( IM_RX_OVRN_INT, ioaddr + INTERRUPT );
-               } else if (status & IM_EPH_INT ) {
-                       PRINTK((CARDNAME ": UNSUPPORTED: EPH INTERRUPT\n"));
-               } else if (status & IM_ERCV_INT ) {
-                       PRINTK((CARDNAME ": UNSUPPORTED: ERCV INTERRUPT\n"));
-                       outb( IM_ERCV_INT, ioaddr + INTERRUPT );
-               }
-       } while ( timeout -- );
-
-
-       /* restore state register */
-       SMC_SELECT_BANK( 2 );
-       outb( mask, ioaddr + INT_MASK );
-
-       PRINTK3((KERN_WARNING CARDNAME ": MASK is now %x\n", mask));
-       outw( saved_pointer, ioaddr + POINTER );
-
-       SMC_SELECT_BANK( saved_bank );
-
-       PRINTK3((CARDNAME ": Interrupt done\n"));
-       return IRQ_RETVAL(handled);
-}
-
-
-/*----------------------------------------------------
- . smc_close
- .
- . this makes the board clean up everything that it can
- . and not talk to the outside world.   Caused by
- . an 'ifconfig ethX down'
- .
- -----------------------------------------------------*/
-static int smc_close(struct net_device *dev)
-{
-       netif_stop_queue(dev);
-       /* clear everything */
-       smc_shutdown( dev->base_addr );
-
-       /* Update the statistics here. */
-       return 0;
-}
-
-/*-----------------------------------------------------------
- . smc_set_multicast_list
- .
- . This routine will, depending on the values passed to it,
- . either make it accept multicast packets, go into
- . promiscuous mode ( for TCPDUMP and cousins ) or accept
- . a select set of multicast packets
-*/
-static void smc_set_multicast_list(struct net_device *dev)
-{
-       short ioaddr = dev->base_addr;
-
-       SMC_SELECT_BANK(0);
-       if ( dev->flags & IFF_PROMISC )
-               outw( inw(ioaddr + RCR ) | RCR_PROMISC, ioaddr + RCR );
-
-/* BUG?  I never disable promiscuous mode if multicasting was turned on.
-   Now, I turn off promiscuous mode, but I don't do anything to multicasting
-   when promiscuous mode is turned on.
-*/
-
-       /* Here, I am setting this to accept all multicast packets.
-          I don't need to zero the multicast table, because the flag is
-          checked before the table is
-       */
-       else if (dev->flags & IFF_ALLMULTI)
-               outw( inw(ioaddr + RCR ) | RCR_ALMUL, ioaddr + RCR );
-
-       /* We just get all multicast packets even if we only want them
-        . from one source.  This will be changed at some future
-        . point. */
-       else if (!netdev_mc_empty(dev)) {
-               /* support hardware multicasting */
-
-               /* be sure I get rid of flags I might have set */
-               outw( inw( ioaddr + RCR ) & ~(RCR_PROMISC | RCR_ALMUL),
-                       ioaddr + RCR );
-               /* NOTE: this has to set the bank, so make sure it is the
-                  last thing called.  The bank is set to zero at the top */
-               smc_setmulticast(ioaddr, dev);
-       }
-       else  {
-               outw( inw( ioaddr + RCR ) & ~(RCR_PROMISC | RCR_ALMUL),
-                       ioaddr + RCR );
-
-               /*
-                 since I'm disabling all multicast entirely, I need to
-                 clear the multicast list
-               */
-               SMC_SELECT_BANK( 3 );
-               outw( 0, ioaddr + MULTICAST1 );
-               outw( 0, ioaddr + MULTICAST2 );
-               outw( 0, ioaddr + MULTICAST3 );
-               outw( 0, ioaddr + MULTICAST4 );
-       }
-}
-
-#ifdef MODULE
-
-static struct net_device *devSMC9194;
-MODULE_LICENSE("GPL");
-
-module_param(io, int, 0);
-module_param(irq, int, 0);
-module_param(ifport, int, 0);
-MODULE_PARM_DESC(io, "SMC 99194 I/O base address");
-MODULE_PARM_DESC(irq, "SMC 99194 IRQ number");
-MODULE_PARM_DESC(ifport, "SMC 99194 interface port (0-default, 1-TP, 2-AUI)");
-
-int __init init_module(void)
-{
-       if (io == 0)
-               printk(KERN_WARNING
-               CARDNAME": You shouldn't use auto-probing with insmod!\n" );
-
-       /* copy the parameters from insmod into the device structure */
-       devSMC9194 = smc_init(-1);
-       if (IS_ERR(devSMC9194))
-               return PTR_ERR(devSMC9194);
-       return 0;
-}
-
-void __exit cleanup_module(void)
-{
-       unregister_netdev(devSMC9194);
-       free_irq(devSMC9194->irq, devSMC9194);
-       release_region(devSMC9194->base_addr, SMC_IO_EXTENT);
-       free_netdev(devSMC9194);
-}
-
-#endif /* MODULE */
diff --git a/drivers/net/smc9194.h b/drivers/net/smc9194.h
deleted file mode 100644 (file)
index cf69d0a..0000000
+++ /dev/null
@@ -1,241 +0,0 @@
-/*------------------------------------------------------------------------
- . smc9194.h
- . Copyright (C) 1996 by Erik Stahlman
- .
- . This software may be used and distributed according to the terms
- . of the GNU General Public License, incorporated herein by reference.
- .
- . This file contains register information and access macros for
- . the SMC91xxx chipset.
- .
- . Information contained in this file was obtained from the SMC91C94
- . manual from SMC.  To get a copy, if you really want one, you can find
- . information under www.smc.com in the components division.
- . ( this thanks to advice from Donald Becker ).
- .
- . Authors
- .     Erik Stahlman                           ( erik@vt.edu )
- .
- . History
- . 01/06/96             Erik Stahlman   moved definitions here from main .c file
- . 01/19/96             Erik Stahlman    polished this up some, and added better
- .                                                                               error handling
- .
- ---------------------------------------------------------------------------*/
-#ifndef _SMC9194_H_
-#define _SMC9194_H_
-
-/* I want some simple types */
-
-typedef unsigned char                  byte;
-typedef unsigned short                 word;
-typedef unsigned long int              dword;
-
-
-/* Because of bank switching, the SMC91xxx uses only 16 I/O ports */
-
-#define SMC_IO_EXTENT  16
-
-
-/*---------------------------------------------------------------
- .
- . A description of the SMC registers is probably in order here,
- . although for details, the SMC datasheet is invaluable.
- .
- . Basically, the chip has 4 banks of registers ( 0 to 3 ), which
- . are accessed by writing a number into the BANK_SELECT register
- . ( I also use a SMC_SELECT_BANK macro for this ).
- .
- . The banks are configured so that for most purposes, bank 2 is all
- . that is needed for simple run time tasks.
- -----------------------------------------------------------------------*/
-
-/*
- . Bank Select Register:
- .
- .             yyyy yyyy 0000 00xx
- .             xx              = bank number
- .             yyyy yyyy       = 0x33, for identification purposes.
-*/
-#define        BANK_SELECT             14
-
-/* BANK 0  */
-
-#define        TCR             0       /* transmit control register */
-#define TCR_ENABLE     0x0001  /* if this is 1, we can transmit */
-#define TCR_FDUPLX     0x0800  /* receive packets sent out */
-#define TCR_STP_SQET   0x1000  /* stop transmitting if Signal quality error */
-#define        TCR_MON_CNS     0x0400  /* monitors the carrier status */
-#define        TCR_PAD_ENABLE  0x0080  /* pads short packets to 64 bytes */
-
-#define        TCR_CLEAR       0       /* do NOTHING */
-/* the normal settings for the TCR register : */
-/* QUESTION: do I want to enable padding of short packets ? */
-#define        TCR_NORMAL      TCR_ENABLE
-
-
-#define EPH_STATUS     2
-#define ES_LINK_OK     0x4000  /* is the link integrity ok ? */
-
-#define        RCR             4
-#define RCR_SOFTRESET  0x8000  /* resets the chip */
-#define        RCR_STRIP_CRC   0x200   /* strips CRC */
-#define RCR_ENABLE     0x100   /* IFF this is set, we can receive packets */
-#define RCR_ALMUL      0x4     /* receive all multicast packets */
-#define        RCR_PROMISC     0x2     /* enable promiscuous mode */
-
-/* the normal settings for the RCR register : */
-#define        RCR_NORMAL      (RCR_STRIP_CRC | RCR_ENABLE)
-#define RCR_CLEAR      0x0             /* set it to a base state */
-
-#define        COUNTER         6
-#define        MIR             8
-#define        MCR             10
-/* 12 is reserved */
-
-/* BANK 1 */
-#define CONFIG                 0
-#define CFG_AUI_SELECT         0x100
-#define        BASE                    2
-#define        ADDR0                   4
-#define        ADDR1                   6
-#define        ADDR2                   8
-#define        GENERAL                 10
-#define        CONTROL                 12
-#define        CTL_POWERDOWN           0x2000
-#define        CTL_LE_ENABLE           0x80
-#define        CTL_CR_ENABLE           0x40
-#define        CTL_TE_ENABLE           0x0020
-#define CTL_AUTO_RELEASE       0x0800
-#define        CTL_EPROM_ACCESS        0x0003 /* high if Eprom is being read */
-
-/* BANK 2 */
-#define MMU_CMD                0
-#define MC_BUSY                1       /* only readable bit in the register */
-#define MC_NOP         0
-#define        MC_ALLOC        0x20    /* or with number of 256 byte packets */
-#define        MC_RESET        0x40
-#define        MC_REMOVE       0x60    /* remove the current rx packet */
-#define MC_RELEASE     0x80    /* remove and release the current rx packet */
-#define MC_FREEPKT     0xA0    /* Release packet in PNR register */
-#define MC_ENQUEUE     0xC0    /* Enqueue the packet for transmit */
-
-#define        PNR_ARR         2
-#define FIFO_PORTS     4
-
-#define FP_RXEMPTY  0x8000
-#define FP_TXEMPTY  0x80
-
-#define        POINTER         6
-#define PTR_READ       0x2000
-#define        PTR_RCV         0x8000
-#define        PTR_AUTOINC     0x4000
-#define PTR_AUTO_INC   0x0040
-
-#define        DATA_1          8
-#define        DATA_2          10
-#define        INTERRUPT       12
-
-#define INT_MASK       13
-#define IM_RCV_INT     0x1
-#define        IM_TX_INT       0x2
-#define        IM_TX_EMPTY_INT 0x4
-#define        IM_ALLOC_INT    0x8
-#define        IM_RX_OVRN_INT  0x10
-#define        IM_EPH_INT      0x20
-#define        IM_ERCV_INT     0x40 /* not on SMC9192 */
-
-/* BANK 3 */
-#define        MULTICAST1      0
-#define        MULTICAST2      2
-#define        MULTICAST3      4
-#define        MULTICAST4      6
-#define        MGMT            8
-#define        REVISION        10 /* ( hi: chip id   low: rev # ) */
-
-
-/* this is NOT on SMC9192 */
-#define        ERCV            12
-
-#define CHIP_9190      3
-#define CHIP_9194      4
-#define CHIP_9195      5
-#define CHIP_91100     7
-
-static const char * chip_ids[ 15 ] =  {
-       NULL, NULL, NULL,
-       /* 3 */ "SMC91C90/91C92",
-       /* 4 */ "SMC91C94",
-       /* 5 */ "SMC91C95",
-       NULL,
-       /* 7 */ "SMC91C100",
-       /* 8 */ "SMC91C100FD",
-       NULL, NULL, NULL,
-       NULL, NULL, NULL};
-
-/*
- . Transmit status bits
-*/
-#define TS_SUCCESS 0x0001
-#define TS_LOSTCAR 0x0400
-#define TS_LATCOL  0x0200
-#define TS_16COL   0x0010
-
-/*
- . Receive status bits
-*/
-#define RS_ALGNERR     0x8000
-#define RS_BADCRC      0x2000
-#define RS_ODDFRAME    0x1000
-#define RS_TOOLONG     0x0800
-#define RS_TOOSHORT    0x0400
-#define RS_MULTICAST   0x0001
-#define RS_ERRORS      (RS_ALGNERR | RS_BADCRC | RS_TOOLONG | RS_TOOSHORT)
-
-static const char * interfaces[ 2 ] = { "TP", "AUI" };
-
-/*-------------------------------------------------------------------------
- .  I define some macros to make it easier to do somewhat common
- . or slightly complicated, repeated tasks.
- --------------------------------------------------------------------------*/
-
-/* select a register bank, 0 to 3  */
-
-#define SMC_SELECT_BANK(x)  { outw( x, ioaddr + BANK_SELECT ); }
-
-/* define a small delay for the reset */
-#define SMC_DELAY() { inw( ioaddr + RCR );\
-                       inw( ioaddr + RCR );\
-                       inw( ioaddr + RCR );  }
-
-/* this enables an interrupt in the interrupt mask register */
-#define SMC_ENABLE_INT(x) {\
-               unsigned char mask;\
-               SMC_SELECT_BANK(2);\
-               mask = inb( ioaddr + INT_MASK );\
-               mask |= (x);\
-               outb( mask, ioaddr + INT_MASK ); \
-}
-
-/* this disables an interrupt from the interrupt mask register */
-
-#define SMC_DISABLE_INT(x) {\
-               unsigned char mask;\
-               SMC_SELECT_BANK(2);\
-               mask = inb( ioaddr + INT_MASK );\
-               mask &= ~(x);\
-               outb( mask, ioaddr + INT_MASK ); \
-}
-
-/*----------------------------------------------------------------------
- . Define the interrupts that I want to receive from the card
- .
- . I want:
- .  IM_EPH_INT, for nasty errors
- .  IM_RCV_INT, for happy received packets
- .  IM_RX_OVRN_INT, because I have to kick the receiver
- --------------------------------------------------------------------------*/
-#define SMC_INTERRUPT_MASK   (IM_EPH_INT | IM_RX_OVRN_INT | IM_RCV_INT)
-
-#endif  /* _SMC_9194_H_ */
-
diff --git a/drivers/net/smc91x.c b/drivers/net/smc91x.c
deleted file mode 100644 (file)
index 2b1d254..0000000
+++ /dev/null
@@ -1,2431 +0,0 @@
-/*
- * smc91x.c
- * This is a driver for SMSC's 91C9x/91C1xx single-chip Ethernet devices.
- *
- * Copyright (C) 1996 by Erik Stahlman
- * Copyright (C) 2001 Standard Microsystems Corporation
- *     Developed by Simple Network Magic Corporation
- * Copyright (C) 2003 Monta Vista Software, Inc.
- *     Unified SMC91x driver by Nicolas Pitre
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
- *
- * Arguments:
- *     io      = for the base address
- *     irq     = for the IRQ
- *     nowait  = 0 for normal wait states, 1 eliminates additional wait states
- *
- * original author:
- *     Erik Stahlman <erik@vt.edu>
- *
- * hardware multicast code:
- *    Peter Cammaert <pc@denkart.be>
- *
- * contributors:
- *     Daris A Nevil <dnevil@snmc.com>
- *      Nicolas Pitre <nico@fluxnic.net>
- *     Russell King <rmk@arm.linux.org.uk>
- *
- * History:
- *   08/20/00  Arnaldo Melo       fix kfree(skb) in smc_hardware_send_packet
- *   12/15/00  Christian Jullien  fix "Warning: kfree_skb on hard IRQ"
- *   03/16/01  Daris A Nevil      modified smc9194.c for use with LAN91C111
- *   08/22/01  Scott Anderson     merge changes from smc9194 to smc91111
- *   08/21/01  Pramod B Bhardwaj  added support for RevB of LAN91C111
- *   12/20/01  Jeff Sutherland    initial port to Xscale PXA with DMA support
- *   04/07/03  Nicolas Pitre      unified SMC91x driver, killed irq races,
- *                                more bus abstraction, big cleanup, etc.
- *   29/09/03  Russell King       - add driver model support
- *                                - ethtool support
- *                                - convert to use generic MII interface
- *                                - add link up/down notification
- *                                - don't try to handle full negotiation in
- *                                  smc_phy_configure
- *                                - clean up (and fix stack overrun) in PHY
- *                                  MII read/write functions
- *   22/09/04  Nicolas Pitre      big update (see commit log for details)
- */
-static const char version[] =
-       "smc91x.c: v1.1, sep 22 2004 by Nicolas Pitre <nico@fluxnic.net>\n";
-
-/* Debugging level */
-#ifndef SMC_DEBUG
-#define SMC_DEBUG              0
-#endif
-
-
-#include <linux/init.h>
-#include <linux/module.h>
-#include <linux/kernel.h>
-#include <linux/sched.h>
-#include <linux/delay.h>
-#include <linux/interrupt.h>
-#include <linux/irq.h>
-#include <linux/errno.h>
-#include <linux/ioport.h>
-#include <linux/crc32.h>
-#include <linux/platform_device.h>
-#include <linux/spinlock.h>
-#include <linux/ethtool.h>
-#include <linux/mii.h>
-#include <linux/workqueue.h>
-#include <linux/of.h>
-
-#include <linux/netdevice.h>
-#include <linux/etherdevice.h>
-#include <linux/skbuff.h>
-
-#include <asm/io.h>
-
-#include "smc91x.h"
-
-#ifndef SMC_NOWAIT
-# define SMC_NOWAIT            0
-#endif
-static int nowait = SMC_NOWAIT;
-module_param(nowait, int, 0400);
-MODULE_PARM_DESC(nowait, "set to 1 for no wait state");
-
-/*
- * Transmit timeout, default 5 seconds.
- */
-static int watchdog = 1000;
-module_param(watchdog, int, 0400);
-MODULE_PARM_DESC(watchdog, "transmit timeout in milliseconds");
-
-MODULE_LICENSE("GPL");
-MODULE_ALIAS("platform:smc91x");
-
-/*
- * The internal workings of the driver.  If you are changing anything
- * here with the SMC stuff, you should have the datasheet and know
- * what you are doing.
- */
-#define CARDNAME "smc91x"
-
-/*
- * Use power-down feature of the chip
- */
-#define POWER_DOWN             1
-
-/*
- * Wait time for memory to be free.  This probably shouldn't be
- * tuned that much, as waiting for this means nothing else happens
- * in the system
- */
-#define MEMORY_WAIT_TIME       16
-
-/*
- * The maximum number of processing loops allowed for each call to the
- * IRQ handler.
- */
-#define MAX_IRQ_LOOPS          8
-
-/*
- * This selects whether TX packets are sent one by one to the SMC91x internal
- * memory and throttled until transmission completes.  This may prevent
- * RX overruns a litle by keeping much of the memory free for RX packets
- * but to the expense of reduced TX throughput and increased IRQ overhead.
- * Note this is not a cure for a too slow data bus or too high IRQ latency.
- */
-#define THROTTLE_TX_PKTS       0
-
-/*
- * The MII clock high/low times.  2x this number gives the MII clock period
- * in microseconds. (was 50, but this gives 6.4ms for each MII transaction!)
- */
-#define MII_DELAY              1
-
-#if SMC_DEBUG > 0
-#define DBG(n, args...)                                        \
-       do {                                            \
-               if (SMC_DEBUG >= (n))                   \
-                       printk(args);   \
-       } while (0)
-
-#define PRINTK(args...)   printk(args)
-#else
-#define DBG(n, args...)   do { } while(0)
-#define PRINTK(args...)   printk(KERN_DEBUG args)
-#endif
-
-#if SMC_DEBUG > 3
-static void PRINT_PKT(u_char *buf, int length)
-{
-       int i;
-       int remainder;
-       int lines;
-
-       lines = length / 16;
-       remainder = length % 16;
-
-       for (i = 0; i < lines ; i ++) {
-               int cur;
-               for (cur = 0; cur < 8; cur++) {
-                       u_char a, b;
-                       a = *buf++;
-                       b = *buf++;
-                       printk("%02x%02x ", a, b);
-               }
-               printk("\n");
-       }
-       for (i = 0; i < remainder/2 ; i++) {
-               u_char a, b;
-               a = *buf++;
-               b = *buf++;
-               printk("%02x%02x ", a, b);
-       }
-       printk("\n");
-}
-#else
-#define PRINT_PKT(x...)  do { } while(0)
-#endif
-
-
-/* this enables an interrupt in the interrupt mask register */
-#define SMC_ENABLE_INT(lp, x) do {                                     \
-       unsigned char mask;                                             \
-       unsigned long smc_enable_flags;                                 \
-       spin_lock_irqsave(&lp->lock, smc_enable_flags);                 \
-       mask = SMC_GET_INT_MASK(lp);                                    \
-       mask |= (x);                                                    \
-       SMC_SET_INT_MASK(lp, mask);                                     \
-       spin_unlock_irqrestore(&lp->lock, smc_enable_flags);            \
-} while (0)
-
-/* this disables an interrupt from the interrupt mask register */
-#define SMC_DISABLE_INT(lp, x) do {                                    \
-       unsigned char mask;                                             \
-       unsigned long smc_disable_flags;                                \
-       spin_lock_irqsave(&lp->lock, smc_disable_flags);                \
-       mask = SMC_GET_INT_MASK(lp);                                    \
-       mask &= ~(x);                                                   \
-       SMC_SET_INT_MASK(lp, mask);                                     \
-       spin_unlock_irqrestore(&lp->lock, smc_disable_flags);           \
-} while (0)
-
-/*
- * Wait while MMU is busy.  This is usually in the order of a few nanosecs
- * if at all, but let's avoid deadlocking the system if the hardware
- * decides to go south.
- */
-#define SMC_WAIT_MMU_BUSY(lp) do {                                     \
-       if (unlikely(SMC_GET_MMU_CMD(lp) & MC_BUSY)) {          \
-               unsigned long timeout = jiffies + 2;                    \
-               while (SMC_GET_MMU_CMD(lp) & MC_BUSY) {         \
-                       if (time_after(jiffies, timeout)) {             \
-                               printk("%s: timeout %s line %d\n",      \
-                                       dev->name, __FILE__, __LINE__); \
-                               break;                                  \
-                       }                                               \
-                       cpu_relax();                                    \
-               }                                                       \
-       }                                                               \
-} while (0)
-
-
-/*
- * this does a soft reset on the device
- */
-static void smc_reset(struct net_device *dev)
-{
-       struct smc_local *lp = netdev_priv(dev);
-       void __iomem *ioaddr = lp->base;
-       unsigned int ctl, cfg;
-       struct sk_buff *pending_skb;
-
-       DBG(2, "%s: %s\n", dev->name, __func__);
-
-       /* Disable all interrupts, block TX tasklet */
-       spin_lock_irq(&lp->lock);
-       SMC_SELECT_BANK(lp, 2);
-       SMC_SET_INT_MASK(lp, 0);
-       pending_skb = lp->pending_tx_skb;
-       lp->pending_tx_skb = NULL;
-       spin_unlock_irq(&lp->lock);
-
-       /* free any pending tx skb */
-       if (pending_skb) {
-               dev_kfree_skb(pending_skb);
-               dev->stats.tx_errors++;
-               dev->stats.tx_aborted_errors++;
-       }
-
-       /*
-        * This resets the registers mostly to defaults, but doesn't
-        * affect EEPROM.  That seems unnecessary
-        */
-       SMC_SELECT_BANK(lp, 0);
-       SMC_SET_RCR(lp, RCR_SOFTRST);
-
-       /*
-        * Setup the Configuration Register
-        * This is necessary because the CONFIG_REG is not affected
-        * by a soft reset
-        */
-       SMC_SELECT_BANK(lp, 1);
-
-       cfg = CONFIG_DEFAULT;
-
-       /*
-        * Setup for fast accesses if requested.  If the card/system
-        * can't handle it then there will be no recovery except for
-        * a hard reset or power cycle
-        */
-       if (lp->cfg.flags & SMC91X_NOWAIT)
-               cfg |= CONFIG_NO_WAIT;
-
-       /*
-        * Release from possible power-down state
-        * Configuration register is not affected by Soft Reset
-        */
-       cfg |= CONFIG_EPH_POWER_EN;
-
-       SMC_SET_CONFIG(lp, cfg);
-
-       /* this should pause enough for the chip to be happy */
-       /*
-        * elaborate?  What does the chip _need_? --jgarzik
-        *
-        * This seems to be undocumented, but something the original
-        * driver(s) have always done.  Suspect undocumented timing
-        * info/determined empirically. --rmk
-        */
-       udelay(1);
-
-       /* Disable transmit and receive functionality */
-       SMC_SELECT_BANK(lp, 0);
-       SMC_SET_RCR(lp, RCR_CLEAR);
-       SMC_SET_TCR(lp, TCR_CLEAR);
-
-       SMC_SELECT_BANK(lp, 1);
-       ctl = SMC_GET_CTL(lp) | CTL_LE_ENABLE;
-
-       /*
-        * Set the control register to automatically release successfully
-        * transmitted packets, to make the best use out of our limited
-        * memory
-        */
-       if(!THROTTLE_TX_PKTS)
-               ctl |= CTL_AUTO_RELEASE;
-       else
-               ctl &= ~CTL_AUTO_RELEASE;
-       SMC_SET_CTL(lp, ctl);
-
-       /* Reset the MMU */
-       SMC_SELECT_BANK(lp, 2);
-       SMC_SET_MMU_CMD(lp, MC_RESET);
-       SMC_WAIT_MMU_BUSY(lp);
-}
-
-/*
- * Enable Interrupts, Receive, and Transmit
- */
-static void smc_enable(struct net_device *dev)
-{
-       struct smc_local *lp = netdev_priv(dev);
-       void __iomem *ioaddr = lp->base;
-       int mask;
-
-       DBG(2, "%s: %s\n", dev->name, __func__);
-
-       /* see the header file for options in TCR/RCR DEFAULT */
-       SMC_SELECT_BANK(lp, 0);
-       SMC_SET_TCR(lp, lp->tcr_cur_mode);
-       SMC_SET_RCR(lp, lp->rcr_cur_mode);
-
-       SMC_SELECT_BANK(lp, 1);
-       SMC_SET_MAC_ADDR(lp, dev->dev_addr);
-
-       /* now, enable interrupts */
-       mask = IM_EPH_INT|IM_RX_OVRN_INT|IM_RCV_INT;
-       if (lp->version >= (CHIP_91100 << 4))
-               mask |= IM_MDINT;
-       SMC_SELECT_BANK(lp, 2);
-       SMC_SET_INT_MASK(lp, mask);
-
-       /*
-        * From this point the register bank must _NOT_ be switched away
-        * to something else than bank 2 without proper locking against
-        * races with any tasklet or interrupt handlers until smc_shutdown()
-        * or smc_reset() is called.
-        */
-}
-
-/*
- * this puts the device in an inactive state
- */
-static void smc_shutdown(struct net_device *dev)
-{
-       struct smc_local *lp = netdev_priv(dev);
-       void __iomem *ioaddr = lp->base;
-       struct sk_buff *pending_skb;
-
-       DBG(2, "%s: %s\n", CARDNAME, __func__);
-
-       /* no more interrupts for me */
-       spin_lock_irq(&lp->lock);
-       SMC_SELECT_BANK(lp, 2);
-       SMC_SET_INT_MASK(lp, 0);
-       pending_skb = lp->pending_tx_skb;
-       lp->pending_tx_skb = NULL;
-       spin_unlock_irq(&lp->lock);
-       if (pending_skb)
-               dev_kfree_skb(pending_skb);
-
-       /* and tell the card to stay away from that nasty outside world */
-       SMC_SELECT_BANK(lp, 0);
-       SMC_SET_RCR(lp, RCR_CLEAR);
-       SMC_SET_TCR(lp, TCR_CLEAR);
-
-#ifdef POWER_DOWN
-       /* finally, shut the chip down */
-       SMC_SELECT_BANK(lp, 1);
-       SMC_SET_CONFIG(lp, SMC_GET_CONFIG(lp) & ~CONFIG_EPH_POWER_EN);
-#endif
-}
-
-/*
- * This is the procedure to handle the receipt of a packet.
- */
-static inline void  smc_rcv(struct net_device *dev)
-{
-       struct smc_local *lp = netdev_priv(dev);
-       void __iomem *ioaddr = lp->base;
-       unsigned int packet_number, status, packet_len;
-
-       DBG(3, "%s: %s\n", dev->name, __func__);
-
-       packet_number = SMC_GET_RXFIFO(lp);
-       if (unlikely(packet_number & RXFIFO_REMPTY)) {
-               PRINTK("%s: smc_rcv with nothing on FIFO.\n", dev->name);
-               return;
-       }
-
-       /* read from start of packet */
-       SMC_SET_PTR(lp, PTR_READ | PTR_RCV | PTR_AUTOINC);
-
-       /* First two words are status and packet length */
-       SMC_GET_PKT_HDR(lp, status, packet_len);
-       packet_len &= 0x07ff;  /* mask off top bits */
-       DBG(2, "%s: RX PNR 0x%x STATUS 0x%04x LENGTH 0x%04x (%d)\n",
-               dev->name, packet_number, status,
-               packet_len, packet_len);
-
-       back:
-       if (unlikely(packet_len < 6 || status & RS_ERRORS)) {
-               if (status & RS_TOOLONG && packet_len <= (1514 + 4 + 6)) {
-                       /* accept VLAN packets */
-                       status &= ~RS_TOOLONG;
-                       goto back;
-               }
-               if (packet_len < 6) {
-                       /* bloody hardware */
-                       printk(KERN_ERR "%s: fubar (rxlen %u status %x\n",
-                                       dev->name, packet_len, status);
-                       status |= RS_TOOSHORT;
-               }
-               SMC_WAIT_MMU_BUSY(lp);
-               SMC_SET_MMU_CMD(lp, MC_RELEASE);
-               dev->stats.rx_errors++;
-               if (status & RS_ALGNERR)
-                       dev->stats.rx_frame_errors++;
-               if (status & (RS_TOOSHORT | RS_TOOLONG))
-                       dev->stats.rx_length_errors++;
-               if (status & RS_BADCRC)
-                       dev->stats.rx_crc_errors++;
-       } else {
-               struct sk_buff *skb;
-               unsigned char *data;
-               unsigned int data_len;
-
-               /* set multicast stats */
-               if (status & RS_MULTICAST)
-                       dev->stats.multicast++;
-
-               /*
-                * Actual payload is packet_len - 6 (or 5 if odd byte).
-                * We want skb_reserve(2) and the final ctrl word
-                * (2 bytes, possibly containing the payload odd byte).
-                * Furthermore, we add 2 bytes to allow rounding up to
-                * multiple of 4 bytes on 32 bit buses.
-                * Hence packet_len - 6 + 2 + 2 + 2.
-                */
-               skb = dev_alloc_skb(packet_len);
-               if (unlikely(skb == NULL)) {
-                       printk(KERN_NOTICE "%s: Low memory, packet dropped.\n",
-                               dev->name);
-                       SMC_WAIT_MMU_BUSY(lp);
-                       SMC_SET_MMU_CMD(lp, MC_RELEASE);
-                       dev->stats.rx_dropped++;
-                       return;
-               }
-
-               /* Align IP header to 32 bits */
-               skb_reserve(skb, 2);
-
-               /* BUG: the LAN91C111 rev A never sets this bit. Force it. */
-               if (lp->version == 0x90)
-                       status |= RS_ODDFRAME;
-
-               /*
-                * If odd length: packet_len - 5,
-                * otherwise packet_len - 6.
-                * With the trailing ctrl byte it's packet_len - 4.
-                */
-               data_len = packet_len - ((status & RS_ODDFRAME) ? 5 : 6);
-               data = skb_put(skb, data_len);
-               SMC_PULL_DATA(lp, data, packet_len - 4);
-
-               SMC_WAIT_MMU_BUSY(lp);
-               SMC_SET_MMU_CMD(lp, MC_RELEASE);
-
-               PRINT_PKT(data, packet_len - 4);
-
-               skb->protocol = eth_type_trans(skb, dev);
-               netif_rx(skb);
-               dev->stats.rx_packets++;
-               dev->stats.rx_bytes += data_len;
-       }
-}
-
-#ifdef CONFIG_SMP
-/*
- * On SMP we have the following problem:
- *
- *     A = smc_hardware_send_pkt()
- *     B = smc_hard_start_xmit()
- *     C = smc_interrupt()
- *
- * A and B can never be executed simultaneously.  However, at least on UP,
- * it is possible (and even desirable) for C to interrupt execution of
- * A or B in order to have better RX reliability and avoid overruns.
- * C, just like A and B, must have exclusive access to the chip and
- * each of them must lock against any other concurrent access.
- * Unfortunately this is not possible to have C suspend execution of A or
- * B taking place on another CPU. On UP this is no an issue since A and B
- * are run from softirq context and C from hard IRQ context, and there is
- * no other CPU where concurrent access can happen.
- * If ever there is a way to force at least B and C to always be executed
- * on the same CPU then we could use read/write locks to protect against
- * any other concurrent access and C would always interrupt B. But life
- * isn't that easy in a SMP world...
- */
-#define smc_special_trylock(lock, flags)                               \
-({                                                                     \
-       int __ret;                                                      \
-       local_irq_save(flags);                                          \
-       __ret = spin_trylock(lock);                                     \
-       if (!__ret)                                                     \
-               local_irq_restore(flags);                               \
-       __ret;                                                          \
-})
-#define smc_special_lock(lock, flags)          spin_lock_irqsave(lock, flags)
-#define smc_special_unlock(lock, flags)        spin_unlock_irqrestore(lock, flags)
-#else
-#define smc_special_trylock(lock, flags)       (flags == flags)
-#define smc_special_lock(lock, flags)          do { flags = 0; } while (0)
-#define smc_special_unlock(lock, flags)        do { flags = 0; } while (0)
-#endif
-
-/*
- * This is called to actually send a packet to the chip.
- */
-static void smc_hardware_send_pkt(unsigned long data)
-{
-       struct net_device *dev = (struct net_device *)data;
-       struct smc_local *lp = netdev_priv(dev);
-       void __iomem *ioaddr = lp->base;
-       struct sk_buff *skb;
-       unsigned int packet_no, len;
-       unsigned char *buf;
-       unsigned long flags;
-
-       DBG(3, "%s: %s\n", dev->name, __func__);
-
-       if (!smc_special_trylock(&lp->lock, flags)) {
-               netif_stop_queue(dev);
-               tasklet_schedule(&lp->tx_task);
-               return;
-       }
-
-       skb = lp->pending_tx_skb;
-       if (unlikely(!skb)) {
-               smc_special_unlock(&lp->lock, flags);
-               return;
-       }
-       lp->pending_tx_skb = NULL;
-
-       packet_no = SMC_GET_AR(lp);
-       if (unlikely(packet_no & AR_FAILED)) {
-               printk("%s: Memory allocation failed.\n", dev->name);
-               dev->stats.tx_errors++;
-               dev->stats.tx_fifo_errors++;
-               smc_special_unlock(&lp->lock, flags);
-               goto done;
-       }
-
-       /* point to the beginning of the packet */
-       SMC_SET_PN(lp, packet_no);
-       SMC_SET_PTR(lp, PTR_AUTOINC);
-
-       buf = skb->data;
-       len = skb->len;
-       DBG(2, "%s: TX PNR 0x%x LENGTH 0x%04x (%d) BUF 0x%p\n",
-               dev->name, packet_no, len, len, buf);
-       PRINT_PKT(buf, len);
-
-       /*
-        * Send the packet length (+6 for status words, length, and ctl.
-        * The card will pad to 64 bytes with zeroes if packet is too small.
-        */
-       SMC_PUT_PKT_HDR(lp, 0, len + 6);
-
-       /* send the actual data */
-       SMC_PUSH_DATA(lp, buf, len & ~1);
-
-       /* Send final ctl word with the last byte if there is one */
-       SMC_outw(((len & 1) ? (0x2000 | buf[len-1]) : 0), ioaddr, DATA_REG(lp));
-
-       /*
-        * If THROTTLE_TX_PKTS is set, we stop the queue here. This will
-        * have the effect of having at most one packet queued for TX
-        * in the chip's memory at all time.
-        *
-        * If THROTTLE_TX_PKTS is not set then the queue is stopped only
-        * when memory allocation (MC_ALLOC) does not succeed right away.
-        */
-       if (THROTTLE_TX_PKTS)
-               netif_stop_queue(dev);
-
-       /* queue the packet for TX */
-       SMC_SET_MMU_CMD(lp, MC_ENQUEUE);
-       smc_special_unlock(&lp->lock, flags);
-
-       dev->trans_start = jiffies;
-       dev->stats.tx_packets++;
-       dev->stats.tx_bytes += len;
-
-       SMC_ENABLE_INT(lp, IM_TX_INT | IM_TX_EMPTY_INT);
-
-done:  if (!THROTTLE_TX_PKTS)
-               netif_wake_queue(dev);
-
-       dev_kfree_skb(skb);
-}
-
-/*
- * Since I am not sure if I will have enough room in the chip's ram
- * to store the packet, I call this routine which either sends it
- * now, or set the card to generates an interrupt when ready
- * for the packet.
- */
-static int smc_hard_start_xmit(struct sk_buff *skb, struct net_device *dev)
-{
-       struct smc_local *lp = netdev_priv(dev);
-       void __iomem *ioaddr = lp->base;
-       unsigned int numPages, poll_count, status;
-       unsigned long flags;
-
-       DBG(3, "%s: %s\n", dev->name, __func__);
-
-       BUG_ON(lp->pending_tx_skb != NULL);
-
-       /*
-        * The MMU wants the number of pages to be the number of 256 bytes
-        * 'pages', minus 1 (since a packet can't ever have 0 pages :))
-        *
-        * The 91C111 ignores the size bits, but earlier models don't.
-        *
-        * Pkt size for allocating is data length +6 (for additional status
-        * words, length and ctl)
-        *
-        * If odd size then last byte is included in ctl word.
-        */
-       numPages = ((skb->len & ~1) + (6 - 1)) >> 8;
-       if (unlikely(numPages > 7)) {
-               printk("%s: Far too big packet error.\n", dev->name);
-               dev->stats.tx_errors++;
-               dev->stats.tx_dropped++;
-               dev_kfree_skb(skb);
-               return NETDEV_TX_OK;
-       }
-
-       smc_special_lock(&lp->lock, flags);
-
-       /* now, try to allocate the memory */
-       SMC_SET_MMU_CMD(lp, MC_ALLOC | numPages);
-
-       /*
-        * Poll the chip for a short amount of time in case the
-        * allocation succeeds quickly.
-        */
-       poll_count = MEMORY_WAIT_TIME;
-       do {
-               status = SMC_GET_INT(lp);
-               if (status & IM_ALLOC_INT) {
-                       SMC_ACK_INT(lp, IM_ALLOC_INT);
-                       break;
-               }
-       } while (--poll_count);
-
-       smc_special_unlock(&lp->lock, flags);
-
-       lp->pending_tx_skb = skb;
-       if (!poll_count) {
-               /* oh well, wait until the chip finds memory later */
-               netif_stop_queue(dev);
-               DBG(2, "%s: TX memory allocation deferred.\n", dev->name);
-               SMC_ENABLE_INT(lp, IM_ALLOC_INT);
-       } else {
-               /*
-                * Allocation succeeded: push packet to the chip's own memory
-                * immediately.
-                */
-               smc_hardware_send_pkt((unsigned long)dev);
-       }
-
-       return NETDEV_TX_OK;
-}
-
-/*
- * This handles a TX interrupt, which is only called when:
- * - a TX error occurred, or
- * - CTL_AUTO_RELEASE is not set and TX of a packet completed.
- */
-static void smc_tx(struct net_device *dev)
-{
-       struct smc_local *lp = netdev_priv(dev);
-       void __iomem *ioaddr = lp->base;
-       unsigned int saved_packet, packet_no, tx_status, pkt_len;
-
-       DBG(3, "%s: %s\n", dev->name, __func__);
-
-       /* If the TX FIFO is empty then nothing to do */
-       packet_no = SMC_GET_TXFIFO(lp);
-       if (unlikely(packet_no & TXFIFO_TEMPTY)) {
-               PRINTK("%s: smc_tx with nothing on FIFO.\n", dev->name);
-               return;
-       }
-
-       /* select packet to read from */
-       saved_packet = SMC_GET_PN(lp);
-       SMC_SET_PN(lp, packet_no);
-
-       /* read the first word (status word) from this packet */
-       SMC_SET_PTR(lp, PTR_AUTOINC | PTR_READ);
-       SMC_GET_PKT_HDR(lp, tx_status, pkt_len);
-       DBG(2, "%s: TX STATUS 0x%04x PNR 0x%02x\n",
-               dev->name, tx_status, packet_no);
-
-       if (!(tx_status & ES_TX_SUC))
-               dev->stats.tx_errors++;
-
-       if (tx_status & ES_LOSTCARR)
-               dev->stats.tx_carrier_errors++;
-
-       if (tx_status & (ES_LATCOL | ES_16COL)) {
-               PRINTK("%s: %s occurred on last xmit\n", dev->name,
-                      (tx_status & ES_LATCOL) ?
-                       "late collision" : "too many collisions");
-               dev->stats.tx_window_errors++;
-               if (!(dev->stats.tx_window_errors & 63) && net_ratelimit()) {
-                       printk(KERN_INFO "%s: unexpectedly large number of "
-                              "bad collisions. Please check duplex "
-                              "setting.\n", dev->name);
-               }
-       }
-
-       /* kill the packet */
-       SMC_WAIT_MMU_BUSY(lp);
-       SMC_SET_MMU_CMD(lp, MC_FREEPKT);
-
-       /* Don't restore Packet Number Reg until busy bit is cleared */
-       SMC_WAIT_MMU_BUSY(lp);
-       SMC_SET_PN(lp, saved_packet);
-
-       /* re-enable transmit */
-       SMC_SELECT_BANK(lp, 0);
-       SMC_SET_TCR(lp, lp->tcr_cur_mode);
-       SMC_SELECT_BANK(lp, 2);
-}
-
-
-/*---PHY CONTROL AND CONFIGURATION-----------------------------------------*/
-
-static void smc_mii_out(struct net_device *dev, unsigned int val, int bits)
-{
-       struct smc_local *lp = netdev_priv(dev);
-       void __iomem *ioaddr = lp->base;
-       unsigned int mii_reg, mask;
-
-       mii_reg = SMC_GET_MII(lp) & ~(MII_MCLK | MII_MDOE | MII_MDO);
-       mii_reg |= MII_MDOE;
-
-       for (mask = 1 << (bits - 1); mask; mask >>= 1) {
-               if (val & mask)
-                       mii_reg |= MII_MDO;
-               else
-                       mii_reg &= ~MII_MDO;
-
-               SMC_SET_MII(lp, mii_reg);
-               udelay(MII_DELAY);
-               SMC_SET_MII(lp, mii_reg | MII_MCLK);
-               udelay(MII_DELAY);
-       }
-}
-
-static unsigned int smc_mii_in(struct net_device *dev, int bits)
-{
-       struct smc_local *lp = netdev_priv(dev);
-       void __iomem *ioaddr = lp->base;
-       unsigned int mii_reg, mask, val;
-
-       mii_reg = SMC_GET_MII(lp) & ~(MII_MCLK | MII_MDOE | MII_MDO);
-       SMC_SET_MII(lp, mii_reg);
-
-       for (mask = 1 << (bits - 1), val = 0; mask; mask >>= 1) {
-               if (SMC_GET_MII(lp) & MII_MDI)
-                       val |= mask;
-
-               SMC_SET_MII(lp, mii_reg);
-               udelay(MII_DELAY);
-               SMC_SET_MII(lp, mii_reg | MII_MCLK);
-               udelay(MII_DELAY);
-       }
-
-       return val;
-}
-
-/*
- * Reads a register from the MII Management serial interface
- */
-static int smc_phy_read(struct net_device *dev, int phyaddr, int phyreg)
-{
-       struct smc_local *lp = netdev_priv(dev);
-       void __iomem *ioaddr = lp->base;
-       unsigned int phydata;
-
-       SMC_SELECT_BANK(lp, 3);
-
-       /* Idle - 32 ones */
-       smc_mii_out(dev, 0xffffffff, 32);
-
-       /* Start code (01) + read (10) + phyaddr + phyreg */
-       smc_mii_out(dev, 6 << 10 | phyaddr << 5 | phyreg, 14);
-
-       /* Turnaround (2bits) + phydata */
-       phydata = smc_mii_in(dev, 18);
-
-       /* Return to idle state */
-       SMC_SET_MII(lp, SMC_GET_MII(lp) & ~(MII_MCLK|MII_MDOE|MII_MDO));
-
-       DBG(3, "%s: phyaddr=0x%x, phyreg=0x%x, phydata=0x%x\n",
-               __func__, phyaddr, phyreg, phydata);
-
-       SMC_SELECT_BANK(lp, 2);
-       return phydata;
-}
-
-/*
- * Writes a register to the MII Management serial interface
- */
-static void smc_phy_write(struct net_device *dev, int phyaddr, int phyreg,
-                         int phydata)
-{
-       struct smc_local *lp = netdev_priv(dev);
-       void __iomem *ioaddr = lp->base;
-
-       SMC_SELECT_BANK(lp, 3);
-
-       /* Idle - 32 ones */
-       smc_mii_out(dev, 0xffffffff, 32);
-
-       /* Start code (01) + write (01) + phyaddr + phyreg + turnaround + phydata */
-       smc_mii_out(dev, 5 << 28 | phyaddr << 23 | phyreg << 18 | 2 << 16 | phydata, 32);
-
-       /* Return to idle state */
-       SMC_SET_MII(lp, SMC_GET_MII(lp) & ~(MII_MCLK|MII_MDOE|MII_MDO));
-
-       DBG(3, "%s: phyaddr=0x%x, phyreg=0x%x, phydata=0x%x\n",
-               __func__, phyaddr, phyreg, phydata);
-
-       SMC_SELECT_BANK(lp, 2);
-}
-
-/*
- * Finds and reports the PHY address
- */
-static void smc_phy_detect(struct net_device *dev)
-{
-       struct smc_local *lp = netdev_priv(dev);
-       int phyaddr;
-
-       DBG(2, "%s: %s\n", dev->name, __func__);
-
-       lp->phy_type = 0;
-
-       /*
-        * Scan all 32 PHY addresses if necessary, starting at
-        * PHY#1 to PHY#31, and then PHY#0 last.
-        */
-       for (phyaddr = 1; phyaddr < 33; ++phyaddr) {
-               unsigned int id1, id2;
-
-               /* Read the PHY identifiers */
-               id1 = smc_phy_read(dev, phyaddr & 31, MII_PHYSID1);
-               id2 = smc_phy_read(dev, phyaddr & 31, MII_PHYSID2);
-
-               DBG(3, "%s: phy_id1=0x%x, phy_id2=0x%x\n",
-                       dev->name, id1, id2);
-
-               /* Make sure it is a valid identifier */
-               if (id1 != 0x0000 && id1 != 0xffff && id1 != 0x8000 &&
-                   id2 != 0x0000 && id2 != 0xffff && id2 != 0x8000) {
-                       /* Save the PHY's address */
-                       lp->mii.phy_id = phyaddr & 31;
-                       lp->phy_type = id1 << 16 | id2;
-                       break;
-               }
-       }
-}
-
-/*
- * Sets the PHY to a configuration as determined by the user
- */
-static int smc_phy_fixed(struct net_device *dev)
-{
-       struct smc_local *lp = netdev_priv(dev);
-       void __iomem *ioaddr = lp->base;
-       int phyaddr = lp->mii.phy_id;
-       int bmcr, cfg1;
-
-       DBG(3, "%s: %s\n", dev->name, __func__);
-
-       /* Enter Link Disable state */
-       cfg1 = smc_phy_read(dev, phyaddr, PHY_CFG1_REG);
-       cfg1 |= PHY_CFG1_LNKDIS;
-       smc_phy_write(dev, phyaddr, PHY_CFG1_REG, cfg1);
-
-       /*
-        * Set our fixed capabilities
-        * Disable auto-negotiation
-        */
-       bmcr = 0;
-
-       if (lp->ctl_rfduplx)
-               bmcr |= BMCR_FULLDPLX;
-
-       if (lp->ctl_rspeed == 100)
-               bmcr |= BMCR_SPEED100;
-
-       /* Write our capabilities to the phy control register */
-       smc_phy_write(dev, phyaddr, MII_BMCR, bmcr);
-
-       /* Re-Configure the Receive/Phy Control register */
-       SMC_SELECT_BANK(lp, 0);
-       SMC_SET_RPC(lp, lp->rpc_cur_mode);
-       SMC_SELECT_BANK(lp, 2);
-
-       return 1;
-}
-
-/*
- * smc_phy_reset - reset the phy
- * @dev: net device
- * @phy: phy address
- *
- * Issue a software reset for the specified PHY and
- * wait up to 100ms for the reset to complete.  We should
- * not access the PHY for 50ms after issuing the reset.
- *
- * The time to wait appears to be dependent on the PHY.
- *
- * Must be called with lp->lock locked.
- */
-static int smc_phy_reset(struct net_device *dev, int phy)
-{
-       struct smc_local *lp = netdev_priv(dev);
-       unsigned int bmcr;
-       int timeout;
-
-       smc_phy_write(dev, phy, MII_BMCR, BMCR_RESET);
-
-       for (timeout = 2; timeout; timeout--) {
-               spin_unlock_irq(&lp->lock);
-               msleep(50);
-               spin_lock_irq(&lp->lock);
-
-               bmcr = smc_phy_read(dev, phy, MII_BMCR);
-               if (!(bmcr & BMCR_RESET))
-                       break;
-       }
-
-       return bmcr & BMCR_RESET;
-}
-
-/*
- * smc_phy_powerdown - powerdown phy
- * @dev: net device
- *
- * Power down the specified PHY
- */
-static void smc_phy_powerdown(struct net_device *dev)
-{
-       struct smc_local *lp = netdev_priv(dev);
-       unsigned int bmcr;
-       int phy = lp->mii.phy_id;
-
-       if (lp->phy_type == 0)
-               return;
-
-       /* We need to ensure that no calls to smc_phy_configure are
-          pending.
-       */
-       cancel_work_sync(&lp->phy_configure);
-
-       bmcr = smc_phy_read(dev, phy, MII_BMCR);
-       smc_phy_write(dev, phy, MII_BMCR, bmcr | BMCR_PDOWN);
-}
-
-/*
- * smc_phy_check_media - check the media status and adjust TCR
- * @dev: net device
- * @init: set true for initialisation
- *
- * Select duplex mode depending on negotiation state.  This
- * also updates our carrier state.
- */
-static void smc_phy_check_media(struct net_device *dev, int init)
-{
-       struct smc_local *lp = netdev_priv(dev);
-       void __iomem *ioaddr = lp->base;
-
-       if (mii_check_media(&lp->mii, netif_msg_link(lp), init)) {
-               /* duplex state has changed */
-               if (lp->mii.full_duplex) {
-                       lp->tcr_cur_mode |= TCR_SWFDUP;
-               } else {
-                       lp->tcr_cur_mode &= ~TCR_SWFDUP;
-               }
-
-               SMC_SELECT_BANK(lp, 0);
-               SMC_SET_TCR(lp, lp->tcr_cur_mode);
-       }
-}
-
-/*
- * Configures the specified PHY through the MII management interface
- * using Autonegotiation.
- * Calls smc_phy_fixed() if the user has requested a certain config.
- * If RPC ANEG bit is set, the media selection is dependent purely on
- * the selection by the MII (either in the MII BMCR reg or the result
- * of autonegotiation.)  If the RPC ANEG bit is cleared, the selection
- * is controlled by the RPC SPEED and RPC DPLX bits.
- */
-static void smc_phy_configure(struct work_struct *work)
-{
-       struct smc_local *lp =
-               container_of(work, struct smc_local, phy_configure);
-       struct net_device *dev = lp->dev;
-       void __iomem *ioaddr = lp->base;
-       int phyaddr = lp->mii.phy_id;
-       int my_phy_caps; /* My PHY capabilities */
-       int my_ad_caps; /* My Advertised capabilities */
-       int status;
-
-       DBG(3, "%s:smc_program_phy()\n", dev->name);
-
-       spin_lock_irq(&lp->lock);
-
-       /*
-        * We should not be called if phy_type is zero.
-        */
-       if (lp->phy_type == 0)
-               goto smc_phy_configure_exit;
-
-       if (smc_phy_reset(dev, phyaddr)) {
-               printk("%s: PHY reset timed out\n", dev->name);
-               goto smc_phy_configure_exit;
-       }
-
-       /*
-        * Enable PHY Interrupts (for register 18)
-        * Interrupts listed here are disabled
-        */
-       smc_phy_write(dev, phyaddr, PHY_MASK_REG,
-               PHY_INT_LOSSSYNC | PHY_INT_CWRD | PHY_INT_SSD |
-               PHY_INT_ESD | PHY_INT_RPOL | PHY_INT_JAB |
-               PHY_INT_SPDDET | PHY_INT_DPLXDET);
-
-       /* Configure the Receive/Phy Control register */
-       SMC_SELECT_BANK(lp, 0);
-       SMC_SET_RPC(lp, lp->rpc_cur_mode);
-
-       /* If the user requested no auto neg, then go set his request */
-       if (lp->mii.force_media) {
-               smc_phy_fixed(dev);
-               goto smc_phy_configure_exit;
-       }
-
-       /* Copy our capabilities from MII_BMSR to MII_ADVERTISE */
-       my_phy_caps = smc_phy_read(dev, phyaddr, MII_BMSR);
-
-       if (!(my_phy_caps & BMSR_ANEGCAPABLE)) {
-               printk(KERN_INFO "Auto negotiation NOT supported\n");
-               smc_phy_fixed(dev);
-               goto smc_phy_configure_exit;
-       }
-
-       my_ad_caps = ADVERTISE_CSMA; /* I am CSMA capable */
-
-       if (my_phy_caps & BMSR_100BASE4)
-               my_ad_caps |= ADVERTISE_100BASE4;
-       if (my_phy_caps & BMSR_100FULL)
-               my_ad_caps |= ADVERTISE_100FULL;
-       if (my_phy_caps & BMSR_100HALF)
-               my_ad_caps |= ADVERTISE_100HALF;
-       if (my_phy_caps & BMSR_10FULL)
-               my_ad_caps |= ADVERTISE_10FULL;
-       if (my_phy_caps & BMSR_10HALF)
-               my_ad_caps |= ADVERTISE_10HALF;
-
-       /* Disable capabilities not selected by our user */
-       if (lp->ctl_rspeed != 100)
-               my_ad_caps &= ~(ADVERTISE_100BASE4|ADVERTISE_100FULL|ADVERTISE_100HALF);
-
-       if (!lp->ctl_rfduplx)
-               my_ad_caps &= ~(ADVERTISE_100FULL|ADVERTISE_10FULL);
-
-       /* Update our Auto-Neg Advertisement Register */
-       smc_phy_write(dev, phyaddr, MII_ADVERTISE, my_ad_caps);
-       lp->mii.advertising = my_ad_caps;
-
-       /*
-        * Read the register back.  Without this, it appears that when
-        * auto-negotiation is restarted, sometimes it isn't ready and
-        * the link does not come up.
-        */
-       status = smc_phy_read(dev, phyaddr, MII_ADVERTISE);
-
-       DBG(2, "%s: phy caps=%x\n", dev->name, my_phy_caps);
-       DBG(2, "%s: phy advertised caps=%x\n", dev->name, my_ad_caps);
-
-       /* Restart auto-negotiation process in order to advertise my caps */
-       smc_phy_write(dev, phyaddr, MII_BMCR, BMCR_ANENABLE | BMCR_ANRESTART);
-
-       smc_phy_check_media(dev, 1);
-
-smc_phy_configure_exit:
-       SMC_SELECT_BANK(lp, 2);
-       spin_unlock_irq(&lp->lock);
-}
-
-/*
- * smc_phy_interrupt
- *
- * Purpose:  Handle interrupts relating to PHY register 18. This is
- *  called from the "hard" interrupt handler under our private spinlock.
- */
-static void smc_phy_interrupt(struct net_device *dev)
-{
-       struct smc_local *lp = netdev_priv(dev);
-       int phyaddr = lp->mii.phy_id;
-       int phy18;
-
-       DBG(2, "%s: %s\n", dev->name, __func__);
-
-       if (lp->phy_type == 0)
-               return;
-
-       for(;;) {
-               smc_phy_check_media(dev, 0);
-
-               /* Read PHY Register 18, Status Output */
-               phy18 = smc_phy_read(dev, phyaddr, PHY_INT_REG);
-               if ((phy18 & PHY_INT_INT) == 0)
-                       break;
-       }
-}
-
-/*--- END PHY CONTROL AND CONFIGURATION-------------------------------------*/
-
-static void smc_10bt_check_media(struct net_device *dev, int init)
-{
-       struct smc_local *lp = netdev_priv(dev);
-       void __iomem *ioaddr = lp->base;
-       unsigned int old_carrier, new_carrier;
-
-       old_carrier = netif_carrier_ok(dev) ? 1 : 0;
-
-       SMC_SELECT_BANK(lp, 0);
-       new_carrier = (SMC_GET_EPH_STATUS(lp) & ES_LINK_OK) ? 1 : 0;
-       SMC_SELECT_BANK(lp, 2);
-
-       if (init || (old_carrier != new_carrier)) {
-               if (!new_carrier) {
-                       netif_carrier_off(dev);
-               } else {
-                       netif_carrier_on(dev);
-               }
-               if (netif_msg_link(lp))
-                       printk(KERN_INFO "%s: link %s\n", dev->name,
-                              new_carrier ? "up" : "down");
-       }
-}
-
-static void smc_eph_interrupt(struct net_device *dev)
-{
-       struct smc_local *lp = netdev_priv(dev);
-       void __iomem *ioaddr = lp->base;
-       unsigned int ctl;
-
-       smc_10bt_check_media(dev, 0);
-
-       SMC_SELECT_BANK(lp, 1);
-       ctl = SMC_GET_CTL(lp);
-       SMC_SET_CTL(lp, ctl & ~CTL_LE_ENABLE);
-       SMC_SET_CTL(lp, ctl);
-       SMC_SELECT_BANK(lp, 2);
-}
-
-/*
- * This is the main routine of the driver, to handle the device when
- * it needs some attention.
- */
-static irqreturn_t smc_interrupt(int irq, void *dev_id)
-{
-       struct net_device *dev = dev_id;
-       struct smc_local *lp = netdev_priv(dev);
-       void __iomem *ioaddr = lp->base;
-       int status, mask, timeout, card_stats;
-       int saved_pointer;
-
-       DBG(3, "%s: %s\n", dev->name, __func__);
-
-       spin_lock(&lp->lock);
-
-       /* A preamble may be used when there is a potential race
-        * between the interruptible transmit functions and this
-        * ISR. */
-       SMC_INTERRUPT_PREAMBLE;
-
-       saved_pointer = SMC_GET_PTR(lp);
-       mask = SMC_GET_INT_MASK(lp);
-       SMC_SET_INT_MASK(lp, 0);
-
-       /* set a timeout value, so I don't stay here forever */
-       timeout = MAX_IRQ_LOOPS;
-
-       do {
-               status = SMC_GET_INT(lp);
-
-               DBG(2, "%s: INT 0x%02x MASK 0x%02x MEM 0x%04x FIFO 0x%04x\n",
-                       dev->name, status, mask,
-                       ({ int meminfo; SMC_SELECT_BANK(lp, 0);
-                          meminfo = SMC_GET_MIR(lp);
-                          SMC_SELECT_BANK(lp, 2); meminfo; }),
-                       SMC_GET_FIFO(lp));
-
-               status &= mask;
-               if (!status)
-                       break;
-
-               if (status & IM_TX_INT) {
-                       /* do this before RX as it will free memory quickly */
-                       DBG(3, "%s: TX int\n", dev->name);
-                       smc_tx(dev);
-                       SMC_ACK_INT(lp, IM_TX_INT);
-                       if (THROTTLE_TX_PKTS)
-                               netif_wake_queue(dev);
-               } else if (status & IM_RCV_INT) {
-                       DBG(3, "%s: RX irq\n", dev->name);
-                       smc_rcv(dev);
-               } else if (status & IM_ALLOC_INT) {
-                       DBG(3, "%s: Allocation irq\n", dev->name);
-                       tasklet_hi_schedule(&lp->tx_task);
-                       mask &= ~IM_ALLOC_INT;
-               } else if (status & IM_TX_EMPTY_INT) {
-                       DBG(3, "%s: TX empty\n", dev->name);
-                       mask &= ~IM_TX_EMPTY_INT;
-
-                       /* update stats */
-                       SMC_SELECT_BANK(lp, 0);
-                       card_stats = SMC_GET_COUNTER(lp);
-                       SMC_SELECT_BANK(lp, 2);
-
-                       /* single collisions */
-                       dev->stats.collisions += card_stats & 0xF;
-                       card_stats >>= 4;
-
-                       /* multiple collisions */
-                       dev->stats.collisions += card_stats & 0xF;
-               } else if (status & IM_RX_OVRN_INT) {
-                       DBG(1, "%s: RX overrun (EPH_ST 0x%04x)\n", dev->name,
-                              ({ int eph_st; SMC_SELECT_BANK(lp, 0);
-                                 eph_st = SMC_GET_EPH_STATUS(lp);
-                                 SMC_SELECT_BANK(lp, 2); eph_st; }));
-                       SMC_ACK_INT(lp, IM_RX_OVRN_INT);
-                       dev->stats.rx_errors++;
-                       dev->stats.rx_fifo_errors++;
-               } else if (status & IM_EPH_INT) {
-                       smc_eph_interrupt(dev);
-               } else if (status & IM_MDINT) {
-                       SMC_ACK_INT(lp, IM_MDINT);
-                       smc_phy_interrupt(dev);
-               } else if (status & IM_ERCV_INT) {
-                       SMC_ACK_INT(lp, IM_ERCV_INT);
-                       PRINTK("%s: UNSUPPORTED: ERCV INTERRUPT\n", dev->name);
-               }
-       } while (--timeout);
-
-       /* restore register states */
-       SMC_SET_PTR(lp, saved_pointer);
-       SMC_SET_INT_MASK(lp, mask);
-       spin_unlock(&lp->lock);
-
-#ifndef CONFIG_NET_POLL_CONTROLLER
-       if (timeout == MAX_IRQ_LOOPS)
-               PRINTK("%s: spurious interrupt (mask = 0x%02x)\n",
-                      dev->name, mask);
-#endif
-       DBG(3, "%s: Interrupt done (%d loops)\n",
-              dev->name, MAX_IRQ_LOOPS - timeout);
-
-       /*
-        * We return IRQ_HANDLED unconditionally here even if there was
-        * nothing to do.  There is a possibility that a packet might
-        * get enqueued into the chip right after TX_EMPTY_INT is raised
-        * but just before the CPU acknowledges the IRQ.
-        * Better take an unneeded IRQ in some occasions than complexifying
-        * the code for all cases.
-        */
-       return IRQ_HANDLED;
-}
-
-#ifdef CONFIG_NET_POLL_CONTROLLER
-/*
- * Polling receive - used by netconsole and other diagnostic tools
- * to allow network i/o with interrupts disabled.
- */
-static void smc_poll_controller(struct net_device *dev)
-{
-       disable_irq(dev->irq);
-       smc_interrupt(dev->irq, dev);
-       enable_irq(dev->irq);
-}
-#endif
-
-/* Our watchdog timed out. Called by the networking layer */
-static void smc_timeout(struct net_device *dev)
-{
-       struct smc_local *lp = netdev_priv(dev);
-       void __iomem *ioaddr = lp->base;
-       int status, mask, eph_st, meminfo, fifo;
-
-       DBG(2, "%s: %s\n", dev->name, __func__);
-
-       spin_lock_irq(&lp->lock);
-       status = SMC_GET_INT(lp);
-       mask = SMC_GET_INT_MASK(lp);
-       fifo = SMC_GET_FIFO(lp);
-       SMC_SELECT_BANK(lp, 0);
-       eph_st = SMC_GET_EPH_STATUS(lp);
-       meminfo = SMC_GET_MIR(lp);
-       SMC_SELECT_BANK(lp, 2);
-       spin_unlock_irq(&lp->lock);
-       PRINTK( "%s: TX timeout (INT 0x%02x INTMASK 0x%02x "
-               "MEM 0x%04x FIFO 0x%04x EPH_ST 0x%04x)\n",
-               dev->name, status, mask, meminfo, fifo, eph_st );
-
-       smc_reset(dev);
-       smc_enable(dev);
-
-       /*
-        * Reconfiguring the PHY doesn't seem like a bad idea here, but
-        * smc_phy_configure() calls msleep() which calls schedule_timeout()
-        * which calls schedule().  Hence we use a work queue.
-        */
-       if (lp->phy_type != 0)
-               schedule_work(&lp->phy_configure);
-
-       /* We can accept TX packets again */
-       dev->trans_start = jiffies; /* prevent tx timeout */
-       netif_wake_queue(dev);
-}
-
-/*
- * This routine will, depending on the values passed to it,
- * either make it accept multicast packets, go into
- * promiscuous mode (for TCPDUMP and cousins) or accept
- * a select set of multicast packets
- */
-static void smc_set_multicast_list(struct net_device *dev)
-{
-       struct smc_local *lp = netdev_priv(dev);
-       void __iomem *ioaddr = lp->base;
-       unsigned char multicast_table[8];
-       int update_multicast = 0;
-
-       DBG(2, "%s: %s\n", dev->name, __func__);
-
-       if (dev->flags & IFF_PROMISC) {
-               DBG(2, "%s: RCR_PRMS\n", dev->name);
-               lp->rcr_cur_mode |= RCR_PRMS;
-       }
-
-/* BUG?  I never disable promiscuous mode if multicasting was turned on.
-   Now, I turn off promiscuous mode, but I don't do anything to multicasting
-   when promiscuous mode is turned on.
-*/
-
-       /*
-        * Here, I am setting this to accept all multicast packets.
-        * I don't need to zero the multicast table, because the flag is
-        * checked before the table is
-        */
-       else if (dev->flags & IFF_ALLMULTI || netdev_mc_count(dev) > 16) {
-               DBG(2, "%s: RCR_ALMUL\n", dev->name);
-               lp->rcr_cur_mode |= RCR_ALMUL;
-       }
-
-       /*
-        * This sets the internal hardware table to filter out unwanted
-        * multicast packets before they take up memory.
-        *
-        * The SMC chip uses a hash table where the high 6 bits of the CRC of
-        * address are the offset into the table.  If that bit is 1, then the
-        * multicast packet is accepted.  Otherwise, it's dropped silently.
-        *
-        * To use the 6 bits as an offset into the table, the high 3 bits are
-        * the number of the 8 bit register, while the low 3 bits are the bit
-        * within that register.
-        */
-       else if (!netdev_mc_empty(dev)) {
-               struct netdev_hw_addr *ha;
-
-               /* table for flipping the order of 3 bits */
-               static const unsigned char invert3[] = {0, 4, 2, 6, 1, 5, 3, 7};
-
-               /* start with a table of all zeros: reject all */
-               memset(multicast_table, 0, sizeof(multicast_table));
-
-               netdev_for_each_mc_addr(ha, dev) {
-                       int position;
-
-                       /* only use the low order bits */
-                       position = crc32_le(~0, ha->addr, 6) & 0x3f;
-
-                       /* do some messy swapping to put the bit in the right spot */
-                       multicast_table[invert3[position&7]] |=
-                               (1<<invert3[(position>>3)&7]);
-               }
-
-               /* be sure I get rid of flags I might have set */
-               lp->rcr_cur_mode &= ~(RCR_PRMS | RCR_ALMUL);
-
-               /* now, the table can be loaded into the chipset */
-               update_multicast = 1;
-       } else  {
-               DBG(2, "%s: ~(RCR_PRMS|RCR_ALMUL)\n", dev->name);
-               lp->rcr_cur_mode &= ~(RCR_PRMS | RCR_ALMUL);
-
-               /*
-                * since I'm disabling all multicast entirely, I need to
-                * clear the multicast list
-                */
-               memset(multicast_table, 0, sizeof(multicast_table));
-               update_multicast = 1;
-       }
-
-       spin_lock_irq(&lp->lock);
-       SMC_SELECT_BANK(lp, 0);
-       SMC_SET_RCR(lp, lp->rcr_cur_mode);
-       if (update_multicast) {
-               SMC_SELECT_BANK(lp, 3);
-               SMC_SET_MCAST(lp, multicast_table);
-       }
-       SMC_SELECT_BANK(lp, 2);
-       spin_unlock_irq(&lp->lock);
-}
-
-
-/*
- * Open and Initialize the board
- *
- * Set up everything, reset the card, etc..
- */
-static int
-smc_open(struct net_device *dev)
-{
-       struct smc_local *lp = netdev_priv(dev);
-
-       DBG(2, "%s: %s\n", dev->name, __func__);
-
-       /*
-        * Check that the address is valid.  If its not, refuse
-        * to bring the device up.  The user must specify an
-        * address using ifconfig eth0 hw ether xx:xx:xx:xx:xx:xx
-        */
-       if (!is_valid_ether_addr(dev->dev_addr)) {
-               PRINTK("%s: no valid ethernet hw addr\n", __func__);
-               return -EINVAL;
-       }
-
-       /* Setup the default Register Modes */
-       lp->tcr_cur_mode = TCR_DEFAULT;
-       lp->rcr_cur_mode = RCR_DEFAULT;
-       lp->rpc_cur_mode = RPC_DEFAULT |
-                               lp->cfg.leda << RPC_LSXA_SHFT |
-                               lp->cfg.ledb << RPC_LSXB_SHFT;
-
-       /*
-        * If we are not using a MII interface, we need to
-        * monitor our own carrier signal to detect faults.
-        */
-       if (lp->phy_type == 0)
-               lp->tcr_cur_mode |= TCR_MON_CSN;
-
-       /* reset the hardware */
-       smc_reset(dev);
-       smc_enable(dev);
-
-       /* Configure the PHY, initialize the link state */
-       if (lp->phy_type != 0)
-               smc_phy_configure(&lp->phy_configure);
-       else {
-               spin_lock_irq(&lp->lock);
-               smc_10bt_check_media(dev, 1);
-               spin_unlock_irq(&lp->lock);
-       }
-
-       netif_start_queue(dev);
-       return 0;
-}
-
-/*
- * smc_close
- *
- * this makes the board clean up everything that it can
- * and not talk to the outside world.   Caused by
- * an 'ifconfig ethX down'
- */
-static int smc_close(struct net_device *dev)
-{
-       struct smc_local *lp = netdev_priv(dev);
-
-       DBG(2, "%s: %s\n", dev->name, __func__);
-
-       netif_stop_queue(dev);
-       netif_carrier_off(dev);
-
-       /* clear everything */
-       smc_shutdown(dev);
-       tasklet_kill(&lp->tx_task);
-       smc_phy_powerdown(dev);
-       return 0;
-}
-
-/*
- * Ethtool support
- */
-static int
-smc_ethtool_getsettings(struct net_device *dev, struct ethtool_cmd *cmd)
-{
-       struct smc_local *lp = netdev_priv(dev);
-       int ret;
-
-       cmd->maxtxpkt = 1;
-       cmd->maxrxpkt = 1;
-
-       if (lp->phy_type != 0) {
-               spin_lock_irq(&lp->lock);
-               ret = mii_ethtool_gset(&lp->mii, cmd);
-               spin_unlock_irq(&lp->lock);
-       } else {
-               cmd->supported = SUPPORTED_10baseT_Half |
-                                SUPPORTED_10baseT_Full |
-                                SUPPORTED_TP | SUPPORTED_AUI;
-
-               if (lp->ctl_rspeed == 10)
-                       ethtool_cmd_speed_set(cmd, SPEED_10);
-               else if (lp->ctl_rspeed == 100)
-                       ethtool_cmd_speed_set(cmd, SPEED_100);
-
-               cmd->autoneg = AUTONEG_DISABLE;
-               cmd->transceiver = XCVR_INTERNAL;
-               cmd->port = 0;
-               cmd->duplex = lp->tcr_cur_mode & TCR_SWFDUP ? DUPLEX_FULL : DUPLEX_HALF;
-
-               ret = 0;
-       }
-
-       return ret;
-}
-
-static int
-smc_ethtool_setsettings(struct net_device *dev, struct ethtool_cmd *cmd)
-{
-       struct smc_local *lp = netdev_priv(dev);
-       int ret;
-
-       if (lp->phy_type != 0) {
-               spin_lock_irq(&lp->lock);
-               ret = mii_ethtool_sset(&lp->mii, cmd);
-               spin_unlock_irq(&lp->lock);
-       } else {
-               if (cmd->autoneg != AUTONEG_DISABLE ||
-                   cmd->speed != SPEED_10 ||
-                   (cmd->duplex != DUPLEX_HALF && cmd->duplex != DUPLEX_FULL) ||
-                   (cmd->port != PORT_TP && cmd->port != PORT_AUI))
-                       return -EINVAL;
-
-//             lp->port = cmd->port;
-               lp->ctl_rfduplx = cmd->duplex == DUPLEX_FULL;
-
-//             if (netif_running(dev))
-//                     smc_set_port(dev);
-
-               ret = 0;
-       }
-
-       return ret;
-}
-
-static void
-smc_ethtool_getdrvinfo(struct net_device *dev, struct ethtool_drvinfo *info)
-{
-       strncpy(info->driver, CARDNAME, sizeof(info->driver));
-       strncpy(info->version, version, sizeof(info->version));
-       strncpy(info->bus_info, dev_name(dev->dev.parent), sizeof(info->bus_info));
-}
-
-static int smc_ethtool_nwayreset(struct net_device *dev)
-{
-       struct smc_local *lp = netdev_priv(dev);
-       int ret = -EINVAL;
-
-       if (lp->phy_type != 0) {
-               spin_lock_irq(&lp->lock);
-               ret = mii_nway_restart(&lp->mii);
-               spin_unlock_irq(&lp->lock);
-       }
-
-       return ret;
-}
-
-static u32 smc_ethtool_getmsglevel(struct net_device *dev)
-{
-       struct smc_local *lp = netdev_priv(dev);
-       return lp->msg_enable;
-}
-
-static void smc_ethtool_setmsglevel(struct net_device *dev, u32 level)
-{
-       struct smc_local *lp = netdev_priv(dev);
-       lp->msg_enable = level;
-}
-
-static int smc_write_eeprom_word(struct net_device *dev, u16 addr, u16 word)
-{
-       u16 ctl;
-       struct smc_local *lp = netdev_priv(dev);
-       void __iomem *ioaddr = lp->base;
-
-       spin_lock_irq(&lp->lock);
-       /* load word into GP register */
-       SMC_SELECT_BANK(lp, 1);
-       SMC_SET_GP(lp, word);
-       /* set the address to put the data in EEPROM */
-       SMC_SELECT_BANK(lp, 2);
-       SMC_SET_PTR(lp, addr);
-       /* tell it to write */
-       SMC_SELECT_BANK(lp, 1);
-       ctl = SMC_GET_CTL(lp);
-       SMC_SET_CTL(lp, ctl | (CTL_EEPROM_SELECT | CTL_STORE));
-       /* wait for it to finish */
-       do {
-               udelay(1);
-       } while (SMC_GET_CTL(lp) & CTL_STORE);
-       /* clean up */
-       SMC_SET_CTL(lp, ctl);
-       SMC_SELECT_BANK(lp, 2);
-       spin_unlock_irq(&lp->lock);
-       return 0;
-}
-
-static int smc_read_eeprom_word(struct net_device *dev, u16 addr, u16 *word)
-{
-       u16 ctl;
-       struct smc_local *lp = netdev_priv(dev);
-       void __iomem *ioaddr = lp->base;
-
-       spin_lock_irq(&lp->lock);
-       /* set the EEPROM address to get the data from */
-       SMC_SELECT_BANK(lp, 2);
-       SMC_SET_PTR(lp, addr | PTR_READ);
-       /* tell it to load */
-       SMC_SELECT_BANK(lp, 1);
-       SMC_SET_GP(lp, 0xffff); /* init to known */
-       ctl = SMC_GET_CTL(lp);
-       SMC_SET_CTL(lp, ctl | (CTL_EEPROM_SELECT | CTL_RELOAD));
-       /* wait for it to finish */
-       do {
-               udelay(1);
-       } while (SMC_GET_CTL(lp) & CTL_RELOAD);
-       /* read word from GP register */
-       *word = SMC_GET_GP(lp);
-       /* clean up */
-       SMC_SET_CTL(lp, ctl);
-       SMC_SELECT_BANK(lp, 2);
-       spin_unlock_irq(&lp->lock);
-       return 0;
-}
-
-static int smc_ethtool_geteeprom_len(struct net_device *dev)
-{
-       return 0x23 * 2;
-}
-
-static int smc_ethtool_geteeprom(struct net_device *dev,
-               struct ethtool_eeprom *eeprom, u8 *data)
-{
-       int i;
-       int imax;
-
-       DBG(1, "Reading %d bytes at %d(0x%x)\n",
-               eeprom->len, eeprom->offset, eeprom->offset);
-       imax = smc_ethtool_geteeprom_len(dev);
-       for (i = 0; i < eeprom->len; i += 2) {
-               int ret;
-               u16 wbuf;
-               int offset = i + eeprom->offset;
-               if (offset > imax)
-                       break;
-               ret = smc_read_eeprom_word(dev, offset >> 1, &wbuf);
-               if (ret != 0)
-                       return ret;
-               DBG(2, "Read 0x%x from 0x%x\n", wbuf, offset >> 1);
-               data[i] = (wbuf >> 8) & 0xff;
-               data[i+1] = wbuf & 0xff;
-       }
-       return 0;
-}
-
-static int smc_ethtool_seteeprom(struct net_device *dev,
-               struct ethtool_eeprom *eeprom, u8 *data)
-{
-       int i;
-       int imax;
-
-       DBG(1, "Writing %d bytes to %d(0x%x)\n",
-                       eeprom->len, eeprom->offset, eeprom->offset);
-       imax = smc_ethtool_geteeprom_len(dev);
-       for (i = 0; i < eeprom->len; i += 2) {
-               int ret;
-               u16 wbuf;
-               int offset = i + eeprom->offset;
-               if (offset > imax)
-                       break;
-               wbuf = (data[i] << 8) | data[i + 1];
-               DBG(2, "Writing 0x%x to 0x%x\n", wbuf, offset >> 1);
-               ret = smc_write_eeprom_word(dev, offset >> 1, wbuf);
-               if (ret != 0)
-                       return ret;
-       }
-       return 0;
-}
-
-
-static const struct ethtool_ops smc_ethtool_ops = {
-       .get_settings   = smc_ethtool_getsettings,
-       .set_settings   = smc_ethtool_setsettings,
-       .get_drvinfo    = smc_ethtool_getdrvinfo,
-
-       .get_msglevel   = smc_ethtool_getmsglevel,
-       .set_msglevel   = smc_ethtool_setmsglevel,
-       .nway_reset     = smc_ethtool_nwayreset,
-       .get_link       = ethtool_op_get_link,
-       .get_eeprom_len = smc_ethtool_geteeprom_len,
-       .get_eeprom     = smc_ethtool_geteeprom,
-       .set_eeprom     = smc_ethtool_seteeprom,
-};
-
-static const struct net_device_ops smc_netdev_ops = {
-       .ndo_open               = smc_open,
-       .ndo_stop               = smc_close,
-       .ndo_start_xmit         = smc_hard_start_xmit,
-       .ndo_tx_timeout         = smc_timeout,
-       .ndo_set_multicast_list = smc_set_multicast_list,
-       .ndo_change_mtu         = eth_change_mtu,
-       .ndo_validate_addr      = eth_validate_addr,
-       .ndo_set_mac_address    = eth_mac_addr,
-#ifdef CONFIG_NET_POLL_CONTROLLER
-       .ndo_poll_controller    = smc_poll_controller,
-#endif
-};
-
-/*
- * smc_findirq
- *
- * This routine has a simple purpose -- make the SMC chip generate an
- * interrupt, so an auto-detect routine can detect it, and find the IRQ,
- */
-/*
- * does this still work?
- *
- * I just deleted auto_irq.c, since it was never built...
- *   --jgarzik
- */
-static int __devinit smc_findirq(struct smc_local *lp)
-{
-       void __iomem *ioaddr = lp->base;
-       int timeout = 20;
-       unsigned long cookie;
-
-       DBG(2, "%s: %s\n", CARDNAME, __func__);
-
-       cookie = probe_irq_on();
-
-       /*
-        * What I try to do here is trigger an ALLOC_INT. This is done
-        * by allocating a small chunk of memory, which will give an interrupt
-        * when done.
-        */
-       /* enable ALLOCation interrupts ONLY */
-       SMC_SELECT_BANK(lp, 2);
-       SMC_SET_INT_MASK(lp, IM_ALLOC_INT);
-
-       /*
-        * Allocate 512 bytes of memory.  Note that the chip was just
-        * reset so all the memory is available
-        */
-       SMC_SET_MMU_CMD(lp, MC_ALLOC | 1);
-
-       /*
-        * Wait until positive that the interrupt has been generated
-        */
-       do {
-               int int_status;
-               udelay(10);
-               int_status = SMC_GET_INT(lp);
-               if (int_status & IM_ALLOC_INT)
-                       break;          /* got the interrupt */
-       } while (--timeout);
-
-       /*
-        * there is really nothing that I can do here if timeout fails,
-        * as autoirq_report will return a 0 anyway, which is what I
-        * want in this case.   Plus, the clean up is needed in both
-        * cases.
-        */
-
-       /* and disable all interrupts again */
-       SMC_SET_INT_MASK(lp, 0);
-
-       /* and return what I found */
-       return probe_irq_off(cookie);
-}
-
-/*
- * Function: smc_probe(unsigned long ioaddr)
- *
- * Purpose:
- *     Tests to see if a given ioaddr points to an SMC91x chip.
- *     Returns a 0 on success
- *
- * Algorithm:
- *     (1) see if the high byte of BANK_SELECT is 0x33
- *     (2) compare the ioaddr with the base register's address
- *     (3) see if I recognize the chip ID in the appropriate register
- *
- * Here I do typical initialization tasks.
- *
- * o  Initialize the structure if needed
- * o  print out my vanity message if not done so already
- * o  print out what type of hardware is detected
- * o  print out the ethernet address
- * o  find the IRQ
- * o  set up my private data
- * o  configure the dev structure with my subroutines
- * o  actually GRAB the irq.
- * o  GRAB the region
- */
-static int __devinit smc_probe(struct net_device *dev, void __iomem *ioaddr,
-                           unsigned long irq_flags)
-{
-       struct smc_local *lp = netdev_priv(dev);
-       static int version_printed = 0;
-       int retval;
-       unsigned int val, revision_register;
-       const char *version_string;
-
-       DBG(2, "%s: %s\n", CARDNAME, __func__);
-
-       /* First, see if the high byte is 0x33 */
-       val = SMC_CURRENT_BANK(lp);
-       DBG(2, "%s: bank signature probe returned 0x%04x\n", CARDNAME, val);
-       if ((val & 0xFF00) != 0x3300) {
-               if ((val & 0xFF) == 0x33) {
-                       printk(KERN_WARNING
-                               "%s: Detected possible byte-swapped interface"
-                               " at IOADDR %p\n", CARDNAME, ioaddr);
-               }
-               retval = -ENODEV;
-               goto err_out;
-       }
-
-       /*
-        * The above MIGHT indicate a device, but I need to write to
-        * further test this.
-        */
-       SMC_SELECT_BANK(lp, 0);
-       val = SMC_CURRENT_BANK(lp);
-       if ((val & 0xFF00) != 0x3300) {
-               retval = -ENODEV;
-               goto err_out;
-       }
-
-       /*
-        * well, we've already written once, so hopefully another
-        * time won't hurt.  This time, I need to switch the bank
-        * register to bank 1, so I can access the base address
-        * register
-        */
-       SMC_SELECT_BANK(lp, 1);
-       val = SMC_GET_BASE(lp);
-       val = ((val & 0x1F00) >> 3) << SMC_IO_SHIFT;
-       if (((unsigned int)ioaddr & (0x3e0 << SMC_IO_SHIFT)) != val) {
-               printk("%s: IOADDR %p doesn't match configuration (%x).\n",
-                       CARDNAME, ioaddr, val);
-       }
-
-       /*
-        * check if the revision register is something that I
-        * recognize.  These might need to be added to later,
-        * as future revisions could be added.
-        */
-       SMC_SELECT_BANK(lp, 3);
-       revision_register = SMC_GET_REV(lp);
-       DBG(2, "%s: revision = 0x%04x\n", CARDNAME, revision_register);
-       version_string = chip_ids[ (revision_register >> 4) & 0xF];
-       if (!version_string || (revision_register & 0xff00) != 0x3300) {
-               /* I don't recognize this chip, so... */
-               printk("%s: IO %p: Unrecognized revision register 0x%04x"
-                       ", Contact author.\n", CARDNAME,
-                       ioaddr, revision_register);
-
-               retval = -ENODEV;
-               goto err_out;
-       }
-
-       /* At this point I'll assume that the chip is an SMC91x. */
-       if (version_printed++ == 0)
-               printk("%s", version);
-
-       /* fill in some of the fields */
-       dev->base_addr = (unsigned long)ioaddr;
-       lp->base = ioaddr;
-       lp->version = revision_register & 0xff;
-       spin_lock_init(&lp->lock);
-
-       /* Get the MAC address */
-       SMC_SELECT_BANK(lp, 1);
-       SMC_GET_MAC_ADDR(lp, dev->dev_addr);
-
-       /* now, reset the chip, and put it into a known state */
-       smc_reset(dev);
-
-       /*
-        * If dev->irq is 0, then the device has to be banged on to see
-        * what the IRQ is.
-        *
-        * This banging doesn't always detect the IRQ, for unknown reasons.
-        * a workaround is to reset the chip and try again.
-        *
-        * Interestingly, the DOS packet driver *SETS* the IRQ on the card to
-        * be what is requested on the command line.   I don't do that, mostly
-        * because the card that I have uses a non-standard method of accessing
-        * the IRQs, and because this _should_ work in most configurations.
-        *
-        * Specifying an IRQ is done with the assumption that the user knows
-        * what (s)he is doing.  No checking is done!!!!
-        */
-       if (dev->irq < 1) {
-               int trials;
-
-               trials = 3;
-               while (trials--) {
-                       dev->irq = smc_findirq(lp);
-                       if (dev->irq)
-                               break;
-                       /* kick the card and try again */
-                       smc_reset(dev);
-               }
-       }
-       if (dev->irq == 0) {
-               printk("%s: Couldn't autodetect your IRQ. Use irq=xx.\n",
-                       dev->name);
-               retval = -ENODEV;
-               goto err_out;
-       }
-       dev->irq = irq_canonicalize(dev->irq);
-
-       /* Fill in the fields of the device structure with ethernet values. */
-       ether_setup(dev);
-
-       dev->watchdog_timeo = msecs_to_jiffies(watchdog);
-       dev->netdev_ops = &smc_netdev_ops;
-       dev->ethtool_ops = &smc_ethtool_ops;
-
-       tasklet_init(&lp->tx_task, smc_hardware_send_pkt, (unsigned long)dev);
-       INIT_WORK(&lp->phy_configure, smc_phy_configure);
-       lp->dev = dev;
-       lp->mii.phy_id_mask = 0x1f;
-       lp->mii.reg_num_mask = 0x1f;
-       lp->mii.force_media = 0;
-       lp->mii.full_duplex = 0;
-       lp->mii.dev = dev;
-       lp->mii.mdio_read = smc_phy_read;
-       lp->mii.mdio_write = smc_phy_write;
-
-       /*
-        * Locate the phy, if any.
-        */
-       if (lp->version >= (CHIP_91100 << 4))
-               smc_phy_detect(dev);
-
-       /* then shut everything down to save power */
-       smc_shutdown(dev);
-       smc_phy_powerdown(dev);
-
-       /* Set default parameters */
-       lp->msg_enable = NETIF_MSG_LINK;
-       lp->ctl_rfduplx = 0;
-       lp->ctl_rspeed = 10;
-
-       if (lp->version >= (CHIP_91100 << 4)) {
-               lp->ctl_rfduplx = 1;
-               lp->ctl_rspeed = 100;
-       }
-
-       /* Grab the IRQ */
-       retval = request_irq(dev->irq, smc_interrupt, irq_flags, dev->name, dev);
-       if (retval)
-               goto err_out;
-
-#ifdef CONFIG_ARCH_PXA
-#  ifdef SMC_USE_PXA_DMA
-       lp->cfg.flags |= SMC91X_USE_DMA;
-#  endif
-       if (lp->cfg.flags & SMC91X_USE_DMA) {
-               int dma = pxa_request_dma(dev->name, DMA_PRIO_LOW,
-                                         smc_pxa_dma_irq, NULL);
-               if (dma >= 0)
-                       dev->dma = dma;
-       }
-#endif
-
-       retval = register_netdev(dev);
-       if (retval == 0) {
-               /* now, print out the card info, in a short format.. */
-               printk("%s: %s (rev %d) at %p IRQ %d",
-                       dev->name, version_string, revision_register & 0x0f,
-                       lp->base, dev->irq);
-
-               if (dev->dma != (unsigned char)-1)
-                       printk(" DMA %d", dev->dma);
-
-               printk("%s%s\n",
-                       lp->cfg.flags & SMC91X_NOWAIT ? " [nowait]" : "",
-                       THROTTLE_TX_PKTS ? " [throttle_tx]" : "");
-
-               if (!is_valid_ether_addr(dev->dev_addr)) {
-                       printk("%s: Invalid ethernet MAC address.  Please "
-                              "set using ifconfig\n", dev->name);
-               } else {
-                       /* Print the Ethernet address */
-                       printk("%s: Ethernet addr: %pM\n",
-                              dev->name, dev->dev_addr);
-               }
-
-               if (lp->phy_type == 0) {
-                       PRINTK("%s: No PHY found\n", dev->name);
-               } else if ((lp->phy_type & 0xfffffff0) == 0x0016f840) {
-                       PRINTK("%s: PHY LAN83C183 (LAN91C111 Internal)\n", dev->name);
-               } else if ((lp->phy_type & 0xfffffff0) == 0x02821c50) {
-                       PRINTK("%s: PHY LAN83C180\n", dev->name);
-               }
-       }
-
-err_out:
-#ifdef CONFIG_ARCH_PXA
-       if (retval && dev->dma != (unsigned char)-1)
-               pxa_free_dma(dev->dma);
-#endif
-       return retval;
-}
-
-static int smc_enable_device(struct platform_device *pdev)
-{
-       struct net_device *ndev = platform_get_drvdata(pdev);
-       struct smc_local *lp = netdev_priv(ndev);
-       unsigned long flags;
-       unsigned char ecor, ecsr;
-       void __iomem *addr;
-       struct resource * res;
-
-       res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "smc91x-attrib");
-       if (!res)
-               return 0;
-
-       /*
-        * Map the attribute space.  This is overkill, but clean.
-        */
-       addr = ioremap(res->start, ATTRIB_SIZE);
-       if (!addr)
-               return -ENOMEM;
-
-       /*
-        * Reset the device.  We must disable IRQs around this
-        * since a reset causes the IRQ line become active.
-        */
-       local_irq_save(flags);
-       ecor = readb(addr + (ECOR << SMC_IO_SHIFT)) & ~ECOR_RESET;
-       writeb(ecor | ECOR_RESET, addr + (ECOR << SMC_IO_SHIFT));
-       readb(addr + (ECOR << SMC_IO_SHIFT));
-
-       /*
-        * Wait 100us for the chip to reset.
-        */
-       udelay(100);
-
-       /*
-        * The device will ignore all writes to the enable bit while
-        * reset is asserted, even if the reset bit is cleared in the
-        * same write.  Must clear reset first, then enable the device.
-        */
-       writeb(ecor, addr + (ECOR << SMC_IO_SHIFT));
-       writeb(ecor | ECOR_ENABLE, addr + (ECOR << SMC_IO_SHIFT));
-
-       /*
-        * Set the appropriate byte/word mode.
-        */
-       ecsr = readb(addr + (ECSR << SMC_IO_SHIFT)) & ~ECSR_IOIS8;
-       if (!SMC_16BIT(lp))
-               ecsr |= ECSR_IOIS8;
-       writeb(ecsr, addr + (ECSR << SMC_IO_SHIFT));
-       local_irq_restore(flags);
-
-       iounmap(addr);
-
-       /*
-        * Wait for the chip to wake up.  We could poll the control
-        * register in the main register space, but that isn't mapped
-        * yet.  We know this is going to take 750us.
-        */
-       msleep(1);
-
-       return 0;
-}
-
-static int smc_request_attrib(struct platform_device *pdev,
-                             struct net_device *ndev)
-{
-       struct resource * res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "smc91x-attrib");
-       struct smc_local *lp __maybe_unused = netdev_priv(ndev);
-
-       if (!res)
-               return 0;
-
-       if (!request_mem_region(res->start, ATTRIB_SIZE, CARDNAME))
-               return -EBUSY;
-
-       return 0;
-}
-
-static void smc_release_attrib(struct platform_device *pdev,
-                              struct net_device *ndev)
-{
-       struct resource * res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "smc91x-attrib");
-       struct smc_local *lp __maybe_unused = netdev_priv(ndev);
-
-       if (res)
-               release_mem_region(res->start, ATTRIB_SIZE);
-}
-
-static inline void smc_request_datacs(struct platform_device *pdev, struct net_device *ndev)
-{
-       if (SMC_CAN_USE_DATACS) {
-               struct resource * res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "smc91x-data32");
-               struct smc_local *lp = netdev_priv(ndev);
-
-               if (!res)
-                       return;
-
-               if(!request_mem_region(res->start, SMC_DATA_EXTENT, CARDNAME)) {
-                       printk(KERN_INFO "%s: failed to request datacs memory region.\n", CARDNAME);
-                       return;
-               }
-
-               lp->datacs = ioremap(res->start, SMC_DATA_EXTENT);
-       }
-}
-
-static void smc_release_datacs(struct platform_device *pdev, struct net_device *ndev)
-{
-       if (SMC_CAN_USE_DATACS) {
-               struct smc_local *lp = netdev_priv(ndev);
-               struct resource * res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "smc91x-data32");
-
-               if (lp->datacs)
-                       iounmap(lp->datacs);
-
-               lp->datacs = NULL;
-
-               if (res)
-                       release_mem_region(res->start, SMC_DATA_EXTENT);
-       }
-}
-
-/*
- * smc_init(void)
- *   Input parameters:
- *     dev->base_addr == 0, try to find all possible locations
- *     dev->base_addr > 0x1ff, this is the address to check
- *     dev->base_addr == <anything else>, return failure code
- *
- *   Output:
- *     0 --> there is a device
- *     anything else, error
- */
-static int __devinit smc_drv_probe(struct platform_device *pdev)
-{
-       struct smc91x_platdata *pd = pdev->dev.platform_data;
-       struct smc_local *lp;
-       struct net_device *ndev;
-       struct resource *res, *ires;
-       unsigned int __iomem *addr;
-       unsigned long irq_flags = SMC_IRQ_FLAGS;
-       int ret;
-
-       ndev = alloc_etherdev(sizeof(struct smc_local));
-       if (!ndev) {
-               printk("%s: could not allocate device.\n", CARDNAME);
-               ret = -ENOMEM;
-               goto out;
-       }
-       SET_NETDEV_DEV(ndev, &pdev->dev);
-
-       /* get configuration from platform data, only allow use of
-        * bus width if both SMC_CAN_USE_xxx and SMC91X_USE_xxx are set.
-        */
-
-       lp = netdev_priv(ndev);
-
-       if (pd) {
-               memcpy(&lp->cfg, pd, sizeof(lp->cfg));
-               lp->io_shift = SMC91X_IO_SHIFT(lp->cfg.flags);
-       } else {
-               lp->cfg.flags |= (SMC_CAN_USE_8BIT)  ? SMC91X_USE_8BIT  : 0;
-               lp->cfg.flags |= (SMC_CAN_USE_16BIT) ? SMC91X_USE_16BIT : 0;
-               lp->cfg.flags |= (SMC_CAN_USE_32BIT) ? SMC91X_USE_32BIT : 0;
-               lp->cfg.flags |= (nowait) ? SMC91X_NOWAIT : 0;
-       }
-
-       if (!lp->cfg.leda && !lp->cfg.ledb) {
-               lp->cfg.leda = RPC_LSA_DEFAULT;
-               lp->cfg.ledb = RPC_LSB_DEFAULT;
-       }
-
-       ndev->dma = (unsigned char)-1;
-
-       res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "smc91x-regs");
-       if (!res)
-               res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
-       if (!res) {
-               ret = -ENODEV;
-               goto out_free_netdev;
-       }
-
-
-       if (!request_mem_region(res->start, SMC_IO_EXTENT, CARDNAME)) {
-               ret = -EBUSY;
-               goto out_free_netdev;
-       }
-
-       ires = platform_get_resource(pdev, IORESOURCE_IRQ, 0);
-       if (!ires) {
-               ret = -ENODEV;
-               goto out_release_io;
-       }
-
-       ndev->irq = ires->start;
-
-       if (irq_flags == -1 || ires->flags & IRQF_TRIGGER_MASK)
-               irq_flags = ires->flags & IRQF_TRIGGER_MASK;
-
-       ret = smc_request_attrib(pdev, ndev);
-       if (ret)
-               goto out_release_io;
-#if defined(CONFIG_SA1100_ASSABET)
-       NCR_0 |= NCR_ENET_OSC_EN;
-#endif
-       platform_set_drvdata(pdev, ndev);
-       ret = smc_enable_device(pdev);
-       if (ret)
-               goto out_release_attrib;
-
-       addr = ioremap(res->start, SMC_IO_EXTENT);
-       if (!addr) {
-               ret = -ENOMEM;
-               goto out_release_attrib;
-       }
-
-#ifdef CONFIG_ARCH_PXA
-       {
-               struct smc_local *lp = netdev_priv(ndev);
-               lp->device = &pdev->dev;
-               lp->physaddr = res->start;
-       }
-#endif
-
-       ret = smc_probe(ndev, addr, irq_flags);
-       if (ret != 0)
-               goto out_iounmap;
-
-       smc_request_datacs(pdev, ndev);
-
-       return 0;
-
- out_iounmap:
-       platform_set_drvdata(pdev, NULL);
-       iounmap(addr);
- out_release_attrib:
-       smc_release_attrib(pdev, ndev);
- out_release_io:
-       release_mem_region(res->start, SMC_IO_EXTENT);
- out_free_netdev:
-       free_netdev(ndev);
- out:
-       printk("%s: not found (%d).\n", CARDNAME, ret);
-
-       return ret;
-}
-
-static int __devexit smc_drv_remove(struct platform_device *pdev)
-{
-       struct net_device *ndev = platform_get_drvdata(pdev);
-       struct smc_local *lp = netdev_priv(ndev);
-       struct resource *res;
-
-       platform_set_drvdata(pdev, NULL);
-
-       unregister_netdev(ndev);
-
-       free_irq(ndev->irq, ndev);
-
-#ifdef CONFIG_ARCH_PXA
-       if (ndev->dma != (unsigned char)-1)
-               pxa_free_dma(ndev->dma);
-#endif
-       iounmap(lp->base);
-
-       smc_release_datacs(pdev,ndev);
-       smc_release_attrib(pdev,ndev);
-
-       res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "smc91x-regs");
-       if (!res)
-               res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
-       release_mem_region(res->start, SMC_IO_EXTENT);
-
-       free_netdev(ndev);
-
-       return 0;
-}
-
-static int smc_drv_suspend(struct device *dev)
-{
-       struct platform_device *pdev = to_platform_device(dev);
-       struct net_device *ndev = platform_get_drvdata(pdev);
-
-       if (ndev) {
-               if (netif_running(ndev)) {
-                       netif_device_detach(ndev);
-                       smc_shutdown(ndev);
-                       smc_phy_powerdown(ndev);
-               }
-       }
-       return 0;
-}
-
-static int smc_drv_resume(struct device *dev)
-{
-       struct platform_device *pdev = to_platform_device(dev);
-       struct net_device *ndev = platform_get_drvdata(pdev);
-
-       if (ndev) {
-               struct smc_local *lp = netdev_priv(ndev);
-               smc_enable_device(pdev);
-               if (netif_running(ndev)) {
-                       smc_reset(ndev);
-                       smc_enable(ndev);
-                       if (lp->phy_type != 0)
-                               smc_phy_configure(&lp->phy_configure);
-                       netif_device_attach(ndev);
-               }
-       }
-       return 0;
-}
-
-#ifdef CONFIG_OF
-static const struct of_device_id smc91x_match[] = {
-       { .compatible = "smsc,lan91c94", },
-       { .compatible = "smsc,lan91c111", },
-       {},
-};
-MODULE_DEVICE_TABLE(of, smc91x_match);
-#else
-#define smc91x_match NULL
-#endif
-
-static struct dev_pm_ops smc_drv_pm_ops = {
-       .suspend        = smc_drv_suspend,
-       .resume         = smc_drv_resume,
-};
-
-static struct platform_driver smc_driver = {
-       .probe          = smc_drv_probe,
-       .remove         = __devexit_p(smc_drv_remove),
-       .driver         = {
-               .name   = CARDNAME,
-               .owner  = THIS_MODULE,
-               .pm     = &smc_drv_pm_ops,
-               .of_match_table = smc91x_match,
-       },
-};
-
-static int __init smc_init(void)
-{
-       return platform_driver_register(&smc_driver);
-}
-
-static void __exit smc_cleanup(void)
-{
-       platform_driver_unregister(&smc_driver);
-}
-
-module_init(smc_init);
-module_exit(smc_cleanup);
diff --git a/drivers/net/smc91x.h b/drivers/net/smc91x.h
deleted file mode 100644 (file)
index 5f53fbb..0000000
+++ /dev/null
@@ -1,1180 +0,0 @@
-/*------------------------------------------------------------------------
- . smc91x.h - macros for SMSC's 91C9x/91C1xx single-chip Ethernet device.
- .
- . Copyright (C) 1996 by Erik Stahlman
- . Copyright (C) 2001 Standard Microsystems Corporation
- .     Developed by Simple Network Magic Corporation
- . Copyright (C) 2003 Monta Vista Software, Inc.
- .     Unified SMC91x driver by Nicolas Pitre
- .
- . This program is free software; you can redistribute it and/or modify
- . it under the terms of the GNU General Public License as published by
- . the Free Software Foundation; either version 2 of the License, or
- . (at your option) any later version.
- .
- . This program is distributed in the hope that it will be useful,
- . but WITHOUT ANY WARRANTY; without even the implied warranty of
- . MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
- . GNU General Public License for more details.
- .
- . You should have received a copy of the GNU General Public License
- . along with this program; if not, write to the Free Software
- . Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
- .
- . Information contained in this file was obtained from the LAN91C111
- . manual from SMC.  To get a copy, if you really want one, you can find
- . information under www.smsc.com.
- .
- . Authors
- .     Erik Stahlman           <erik@vt.edu>
- .     Daris A Nevil           <dnevil@snmc.com>
- .     Nicolas Pitre           <nico@fluxnic.net>
- .
- ---------------------------------------------------------------------------*/
-#ifndef _SMC91X_H_
-#define _SMC91X_H_
-
-#include <linux/smc91x.h>
-
-/*
- * Define your architecture specific bus configuration parameters here.
- */
-
-#if defined(CONFIG_ARCH_LUBBOCK) ||\
-    defined(CONFIG_MACH_MAINSTONE) ||\
-    defined(CONFIG_MACH_ZYLONITE) ||\
-    defined(CONFIG_MACH_LITTLETON) ||\
-    defined(CONFIG_MACH_ZYLONITE2) ||\
-    defined(CONFIG_ARCH_VIPER) ||\
-    defined(CONFIG_MACH_STARGATE2)
-
-#include <asm/mach-types.h>
-
-/* Now the bus width is specified in the platform data
- * pretend here to support all I/O access types
- */
-#define SMC_CAN_USE_8BIT       1
-#define SMC_CAN_USE_16BIT      1
-#define SMC_CAN_USE_32BIT      1
-#define SMC_NOWAIT             1
-
-#define SMC_IO_SHIFT           (lp->io_shift)
-
-#define SMC_inb(a, r)          readb((a) + (r))
-#define SMC_inw(a, r)          readw((a) + (r))
-#define SMC_inl(a, r)          readl((a) + (r))
-#define SMC_outb(v, a, r)      writeb(v, (a) + (r))
-#define SMC_outl(v, a, r)      writel(v, (a) + (r))
-#define SMC_insw(a, r, p, l)   readsw((a) + (r), p, l)
-#define SMC_outsw(a, r, p, l)  writesw((a) + (r), p, l)
-#define SMC_insl(a, r, p, l)   readsl((a) + (r), p, l)
-#define SMC_outsl(a, r, p, l)  writesl((a) + (r), p, l)
-#define SMC_IRQ_FLAGS          (-1)    /* from resource */
-
-/* We actually can't write halfwords properly if not word aligned */
-static inline void SMC_outw(u16 val, void __iomem *ioaddr, int reg)
-{
-       if ((machine_is_mainstone() || machine_is_stargate2()) && reg & 2) {
-               unsigned int v = val << 16;
-               v |= readl(ioaddr + (reg & ~2)) & 0xffff;
-               writel(v, ioaddr + (reg & ~2));
-       } else {
-               writew(val, ioaddr + reg);
-       }
-}
-
-#elif defined(CONFIG_SA1100_PLEB)
-/* We can only do 16-bit reads and writes in the static memory space. */
-#define SMC_CAN_USE_8BIT       1
-#define SMC_CAN_USE_16BIT      1
-#define SMC_CAN_USE_32BIT      0
-#define SMC_IO_SHIFT           0
-#define SMC_NOWAIT             1
-
-#define SMC_inb(a, r)          readb((a) + (r))
-#define SMC_insb(a, r, p, l)   readsb((a) + (r), p, (l))
-#define SMC_inw(a, r)          readw((a) + (r))
-#define SMC_insw(a, r, p, l)   readsw((a) + (r), p, l)
-#define SMC_outb(v, a, r)      writeb(v, (a) + (r))
-#define SMC_outsb(a, r, p, l)  writesb((a) + (r), p, (l))
-#define SMC_outw(v, a, r)      writew(v, (a) + (r))
-#define SMC_outsw(a, r, p, l)  writesw((a) + (r), p, l)
-
-#define SMC_IRQ_FLAGS          (-1)
-
-#elif defined(CONFIG_SA1100_ASSABET)
-
-#include <mach/neponset.h>
-
-/* We can only do 8-bit reads and writes in the static memory space. */
-#define SMC_CAN_USE_8BIT       1
-#define SMC_CAN_USE_16BIT      0
-#define SMC_CAN_USE_32BIT      0
-#define SMC_NOWAIT             1
-
-/* The first two address lines aren't connected... */
-#define SMC_IO_SHIFT           2
-
-#define SMC_inb(a, r)          readb((a) + (r))
-#define SMC_outb(v, a, r)      writeb(v, (a) + (r))
-#define SMC_insb(a, r, p, l)   readsb((a) + (r), p, (l))
-#define SMC_outsb(a, r, p, l)  writesb((a) + (r), p, (l))
-#define SMC_IRQ_FLAGS          (-1)    /* from resource */
-
-#elif  defined(CONFIG_MACH_LOGICPD_PXA270) ||  \
-       defined(CONFIG_MACH_NOMADIK_8815NHK)
-
-#define SMC_CAN_USE_8BIT       0
-#define SMC_CAN_USE_16BIT      1
-#define SMC_CAN_USE_32BIT      0
-#define SMC_IO_SHIFT           0
-#define SMC_NOWAIT             1
-
-#define SMC_inw(a, r)          readw((a) + (r))
-#define SMC_outw(v, a, r)      writew(v, (a) + (r))
-#define SMC_insw(a, r, p, l)   readsw((a) + (r), p, l)
-#define SMC_outsw(a, r, p, l)  writesw((a) + (r), p, l)
-
-#elif  defined(CONFIG_ARCH_INNOKOM) || \
-       defined(CONFIG_ARCH_PXA_IDP) || \
-       defined(CONFIG_ARCH_RAMSES) || \
-       defined(CONFIG_ARCH_PCM027)
-
-#define SMC_CAN_USE_8BIT       1
-#define SMC_CAN_USE_16BIT      1
-#define SMC_CAN_USE_32BIT      1
-#define SMC_IO_SHIFT           0
-#define SMC_NOWAIT             1
-#define SMC_USE_PXA_DMA                1
-
-#define SMC_inb(a, r)          readb((a) + (r))
-#define SMC_inw(a, r)          readw((a) + (r))
-#define SMC_inl(a, r)          readl((a) + (r))
-#define SMC_outb(v, a, r)      writeb(v, (a) + (r))
-#define SMC_outl(v, a, r)      writel(v, (a) + (r))
-#define SMC_insl(a, r, p, l)   readsl((a) + (r), p, l)
-#define SMC_outsl(a, r, p, l)  writesl((a) + (r), p, l)
-#define SMC_IRQ_FLAGS          (-1)    /* from resource */
-
-/* We actually can't write halfwords properly if not word aligned */
-static inline void
-SMC_outw(u16 val, void __iomem *ioaddr, int reg)
-{
-       if (reg & 2) {
-               unsigned int v = val << 16;
-               v |= readl(ioaddr + (reg & ~2)) & 0xffff;
-               writel(v, ioaddr + (reg & ~2));
-       } else {
-               writew(val, ioaddr + reg);
-       }
-}
-
-#elif  defined(CONFIG_SH_SH4202_MICRODEV)
-
-#define SMC_CAN_USE_8BIT       0
-#define SMC_CAN_USE_16BIT      1
-#define SMC_CAN_USE_32BIT      0
-
-#define SMC_inb(a, r)          inb((a) + (r) - 0xa0000000)
-#define SMC_inw(a, r)          inw((a) + (r) - 0xa0000000)
-#define SMC_inl(a, r)          inl((a) + (r) - 0xa0000000)
-#define SMC_outb(v, a, r)      outb(v, (a) + (r) - 0xa0000000)
-#define SMC_outw(v, a, r)      outw(v, (a) + (r) - 0xa0000000)
-#define SMC_outl(v, a, r)      outl(v, (a) + (r) - 0xa0000000)
-#define SMC_insl(a, r, p, l)   insl((a) + (r) - 0xa0000000, p, l)
-#define SMC_outsl(a, r, p, l)  outsl((a) + (r) - 0xa0000000, p, l)
-#define SMC_insw(a, r, p, l)   insw((a) + (r) - 0xa0000000, p, l)
-#define SMC_outsw(a, r, p, l)  outsw((a) + (r) - 0xa0000000, p, l)
-
-#define SMC_IRQ_FLAGS          (0)
-
-#elif   defined(CONFIG_M32R)
-
-#define SMC_CAN_USE_8BIT       0
-#define SMC_CAN_USE_16BIT      1
-#define SMC_CAN_USE_32BIT      0
-
-#define SMC_inb(a, r)          inb(((u32)a) + (r))
-#define SMC_inw(a, r)          inw(((u32)a) + (r))
-#define SMC_outb(v, a, r)      outb(v, ((u32)a) + (r))
-#define SMC_outw(v, a, r)      outw(v, ((u32)a) + (r))
-#define SMC_insw(a, r, p, l)   insw(((u32)a) + (r), p, l)
-#define SMC_outsw(a, r, p, l)  outsw(((u32)a) + (r), p, l)
-
-#define SMC_IRQ_FLAGS          (0)
-
-#define RPC_LSA_DEFAULT                RPC_LED_TX_RX
-#define RPC_LSB_DEFAULT                RPC_LED_100_10
-
-#elif  defined(CONFIG_ARCH_VERSATILE)
-
-#define SMC_CAN_USE_8BIT       1
-#define SMC_CAN_USE_16BIT      1
-#define SMC_CAN_USE_32BIT      1
-#define SMC_NOWAIT             1
-
-#define SMC_inb(a, r)          readb((a) + (r))
-#define SMC_inw(a, r)          readw((a) + (r))
-#define SMC_inl(a, r)          readl((a) + (r))
-#define SMC_outb(v, a, r)      writeb(v, (a) + (r))
-#define SMC_outw(v, a, r)      writew(v, (a) + (r))
-#define SMC_outl(v, a, r)      writel(v, (a) + (r))
-#define SMC_insl(a, r, p, l)   readsl((a) + (r), p, l)
-#define SMC_outsl(a, r, p, l)  writesl((a) + (r), p, l)
-#define SMC_IRQ_FLAGS          (-1)    /* from resource */
-
-#elif defined(CONFIG_MN10300)
-
-/*
- * MN10300/AM33 configuration
- */
-
-#include <unit/smc91111.h>
-
-#elif defined(CONFIG_ARCH_MSM)
-
-#define SMC_CAN_USE_8BIT       0
-#define SMC_CAN_USE_16BIT      1
-#define SMC_CAN_USE_32BIT      0
-#define SMC_NOWAIT             1
-
-#define SMC_inw(a, r)          readw((a) + (r))
-#define SMC_outw(v, a, r)      writew(v, (a) + (r))
-#define SMC_insw(a, r, p, l)   readsw((a) + (r), p, l)
-#define SMC_outsw(a, r, p, l)  writesw((a) + (r), p, l)
-
-#define SMC_IRQ_FLAGS          IRQF_TRIGGER_HIGH
-
-#elif defined(CONFIG_COLDFIRE)
-
-#define SMC_CAN_USE_8BIT       0
-#define SMC_CAN_USE_16BIT      1
-#define SMC_CAN_USE_32BIT      0
-#define SMC_NOWAIT             1
-
-static inline void mcf_insw(void *a, unsigned char *p, int l)
-{
-       u16 *wp = (u16 *) p;
-       while (l-- > 0)
-               *wp++ = readw(a);
-}
-
-static inline void mcf_outsw(void *a, unsigned char *p, int l)
-{
-       u16 *wp = (u16 *) p;
-       while (l-- > 0)
-               writew(*wp++, a);
-}
-
-#define SMC_inw(a, r)          _swapw(readw((a) + (r)))
-#define SMC_outw(v, a, r)      writew(_swapw(v), (a) + (r))
-#define SMC_insw(a, r, p, l)   mcf_insw(a + r, p, l)
-#define SMC_outsw(a, r, p, l)  mcf_outsw(a + r, p, l)
-
-#define SMC_IRQ_FLAGS          (IRQF_DISABLED)
-
-#else
-
-/*
- * Default configuration
- */
-
-#define SMC_CAN_USE_8BIT       1
-#define SMC_CAN_USE_16BIT      1
-#define SMC_CAN_USE_32BIT      1
-#define SMC_NOWAIT             1
-
-#define SMC_IO_SHIFT           (lp->io_shift)
-
-#define SMC_inb(a, r)          readb((a) + (r))
-#define SMC_inw(a, r)          readw((a) + (r))
-#define SMC_inl(a, r)          readl((a) + (r))
-#define SMC_outb(v, a, r)      writeb(v, (a) + (r))
-#define SMC_outw(v, a, r)      writew(v, (a) + (r))
-#define SMC_outl(v, a, r)      writel(v, (a) + (r))
-#define SMC_insw(a, r, p, l)   readsw((a) + (r), p, l)
-#define SMC_outsw(a, r, p, l)  writesw((a) + (r), p, l)
-#define SMC_insl(a, r, p, l)   readsl((a) + (r), p, l)
-#define SMC_outsl(a, r, p, l)  writesl((a) + (r), p, l)
-
-#define RPC_LSA_DEFAULT                RPC_LED_100_10
-#define RPC_LSB_DEFAULT                RPC_LED_TX_RX
-
-#endif
-
-
-/* store this information for the driver.. */
-struct smc_local {
-       /*
-        * If I have to wait until memory is available to send a
-        * packet, I will store the skbuff here, until I get the
-        * desired memory.  Then, I'll send it out and free it.
-        */
-       struct sk_buff *pending_tx_skb;
-       struct tasklet_struct tx_task;
-
-       /* version/revision of the SMC91x chip */
-       int     version;
-
-       /* Contains the current active transmission mode */
-       int     tcr_cur_mode;
-
-       /* Contains the current active receive mode */
-       int     rcr_cur_mode;
-
-       /* Contains the current active receive/phy mode */
-       int     rpc_cur_mode;
-       int     ctl_rfduplx;
-       int     ctl_rspeed;
-
-       u32     msg_enable;
-       u32     phy_type;
-       struct mii_if_info mii;
-
-       /* work queue */
-       struct work_struct phy_configure;
-       struct net_device *dev;
-       int     work_pending;
-
-       spinlock_t lock;
-
-#ifdef CONFIG_ARCH_PXA
-       /* DMA needs the physical address of the chip */
-       u_long physaddr;
-       struct device *device;
-#endif
-       void __iomem *base;
-       void __iomem *datacs;
-
-       /* the low address lines on some platforms aren't connected... */
-       int     io_shift;
-
-       struct smc91x_platdata cfg;
-};
-
-#define SMC_8BIT(p)    ((p)->cfg.flags & SMC91X_USE_8BIT)
-#define SMC_16BIT(p)   ((p)->cfg.flags & SMC91X_USE_16BIT)
-#define SMC_32BIT(p)   ((p)->cfg.flags & SMC91X_USE_32BIT)
-
-#ifdef CONFIG_ARCH_PXA
-/*
- * Let's use the DMA engine on the XScale PXA2xx for RX packets. This is
- * always happening in irq context so no need to worry about races.  TX is
- * different and probably not worth it for that reason, and not as critical
- * as RX which can overrun memory and lose packets.
- */
-#include <linux/dma-mapping.h>
-#include <mach/dma.h>
-
-#ifdef SMC_insl
-#undef SMC_insl
-#define SMC_insl(a, r, p, l) \
-       smc_pxa_dma_insl(a, lp, r, dev->dma, p, l)
-static inline void
-smc_pxa_dma_insl(void __iomem *ioaddr, struct smc_local *lp, int reg, int dma,
-                u_char *buf, int len)
-{
-       u_long physaddr = lp->physaddr;
-       dma_addr_t dmabuf;
-
-       /* fallback if no DMA available */
-       if (dma == (unsigned char)-1) {
-               readsl(ioaddr + reg, buf, len);
-               return;
-       }
-
-       /* 64 bit alignment is required for memory to memory DMA */
-       if ((long)buf & 4) {
-               *((u32 *)buf) = SMC_inl(ioaddr, reg);
-               buf += 4;
-               len--;
-       }
-
-       len *= 4;
-       dmabuf = dma_map_single(lp->device, buf, len, DMA_FROM_DEVICE);
-       DCSR(dma) = DCSR_NODESC;
-       DTADR(dma) = dmabuf;
-       DSADR(dma) = physaddr + reg;
-       DCMD(dma) = (DCMD_INCTRGADDR | DCMD_BURST32 |
-                    DCMD_WIDTH4 | (DCMD_LENGTH & len));
-       DCSR(dma) = DCSR_NODESC | DCSR_RUN;
-       while (!(DCSR(dma) & DCSR_STOPSTATE))
-               cpu_relax();
-       DCSR(dma) = 0;
-       dma_unmap_single(lp->device, dmabuf, len, DMA_FROM_DEVICE);
-}
-#endif
-
-#ifdef SMC_insw
-#undef SMC_insw
-#define SMC_insw(a, r, p, l) \
-       smc_pxa_dma_insw(a, lp, r, dev->dma, p, l)
-static inline void
-smc_pxa_dma_insw(void __iomem *ioaddr, struct smc_local *lp, int reg, int dma,
-                u_char *buf, int len)
-{
-       u_long physaddr = lp->physaddr;
-       dma_addr_t dmabuf;
-
-       /* fallback if no DMA available */
-       if (dma == (unsigned char)-1) {
-               readsw(ioaddr + reg, buf, len);
-               return;
-       }
-
-       /* 64 bit alignment is required for memory to memory DMA */
-       while ((long)buf & 6) {
-               *((u16 *)buf) = SMC_inw(ioaddr, reg);
-               buf += 2;
-               len--;
-       }
-
-       len *= 2;
-       dmabuf = dma_map_single(lp->device, buf, len, DMA_FROM_DEVICE);
-       DCSR(dma) = DCSR_NODESC;
-       DTADR(dma) = dmabuf;
-       DSADR(dma) = physaddr + reg;
-       DCMD(dma) = (DCMD_INCTRGADDR | DCMD_BURST32 |
-                    DCMD_WIDTH2 | (DCMD_LENGTH & len));
-       DCSR(dma) = DCSR_NODESC | DCSR_RUN;
-       while (!(DCSR(dma) & DCSR_STOPSTATE))
-               cpu_relax();
-       DCSR(dma) = 0;
-       dma_unmap_single(lp->device, dmabuf, len, DMA_FROM_DEVICE);
-}
-#endif
-
-static void
-smc_pxa_dma_irq(int dma, void *dummy)
-{
-       DCSR(dma) = 0;
-}
-#endif  /* CONFIG_ARCH_PXA */
-
-
-/*
- * Everything a particular hardware setup needs should have been defined
- * at this point.  Add stubs for the undefined cases, mainly to avoid
- * compilation warnings since they'll be optimized away, or to prevent buggy
- * use of them.
- */
-
-#if ! SMC_CAN_USE_32BIT
-#define SMC_inl(ioaddr, reg)           ({ BUG(); 0; })
-#define SMC_outl(x, ioaddr, reg)       BUG()
-#define SMC_insl(a, r, p, l)           BUG()
-#define SMC_outsl(a, r, p, l)          BUG()
-#endif
-
-#if !defined(SMC_insl) || !defined(SMC_outsl)
-#define SMC_insl(a, r, p, l)           BUG()
-#define SMC_outsl(a, r, p, l)          BUG()
-#endif
-
-#if ! SMC_CAN_USE_16BIT
-
-/*
- * Any 16-bit access is performed with two 8-bit accesses if the hardware
- * can't do it directly. Most registers are 16-bit so those are mandatory.
- */
-#define SMC_outw(x, ioaddr, reg)                                       \
-       do {                                                            \
-               unsigned int __val16 = (x);                             \
-               SMC_outb( __val16, ioaddr, reg );                       \
-               SMC_outb( __val16 >> 8, ioaddr, reg + (1 << SMC_IO_SHIFT));\
-       } while (0)
-#define SMC_inw(ioaddr, reg)                                           \
-       ({                                                              \
-               unsigned int __val16;                                   \
-               __val16 =  SMC_inb( ioaddr, reg );                      \
-               __val16 |= SMC_inb( ioaddr, reg + (1 << SMC_IO_SHIFT)) << 8; \
-               __val16;                                                \
-       })
-
-#define SMC_insw(a, r, p, l)           BUG()
-#define SMC_outsw(a, r, p, l)          BUG()
-
-#endif
-
-#if !defined(SMC_insw) || !defined(SMC_outsw)
-#define SMC_insw(a, r, p, l)           BUG()
-#define SMC_outsw(a, r, p, l)          BUG()
-#endif
-
-#if ! SMC_CAN_USE_8BIT
-#define SMC_inb(ioaddr, reg)           ({ BUG(); 0; })
-#define SMC_outb(x, ioaddr, reg)       BUG()
-#define SMC_insb(a, r, p, l)           BUG()
-#define SMC_outsb(a, r, p, l)          BUG()
-#endif
-
-#if !defined(SMC_insb) || !defined(SMC_outsb)
-#define SMC_insb(a, r, p, l)           BUG()
-#define SMC_outsb(a, r, p, l)          BUG()
-#endif
-
-#ifndef SMC_CAN_USE_DATACS
-#define SMC_CAN_USE_DATACS     0
-#endif
-
-#ifndef SMC_IO_SHIFT
-#define SMC_IO_SHIFT   0
-#endif
-
-#ifndef        SMC_IRQ_FLAGS
-#define        SMC_IRQ_FLAGS           IRQF_TRIGGER_RISING
-#endif
-
-#ifndef SMC_INTERRUPT_PREAMBLE
-#define SMC_INTERRUPT_PREAMBLE
-#endif
-
-
-/* Because of bank switching, the LAN91x uses only 16 I/O ports */
-#define SMC_IO_EXTENT  (16 << SMC_IO_SHIFT)
-#define SMC_DATA_EXTENT (4)
-
-/*
- . Bank Select Register:
- .
- .             yyyy yyyy 0000 00xx
- .             xx              = bank number
- .             yyyy yyyy       = 0x33, for identification purposes.
-*/
-#define BANK_SELECT            (14 << SMC_IO_SHIFT)
-
-
-// Transmit Control Register
-/* BANK 0  */
-#define TCR_REG(lp)    SMC_REG(lp, 0x0000, 0)
-#define TCR_ENABLE     0x0001  // When 1 we can transmit
-#define TCR_LOOP       0x0002  // Controls output pin LBK
-#define TCR_FORCOL     0x0004  // When 1 will force a collision
-#define TCR_PAD_EN     0x0080  // When 1 will pad tx frames < 64 bytes w/0
-#define TCR_NOCRC      0x0100  // When 1 will not append CRC to tx frames
-#define TCR_MON_CSN    0x0400  // When 1 tx monitors carrier
-#define TCR_FDUPLX     0x0800  // When 1 enables full duplex operation
-#define TCR_STP_SQET   0x1000  // When 1 stops tx if Signal Quality Error
-#define TCR_EPH_LOOP   0x2000  // When 1 enables EPH block loopback
-#define TCR_SWFDUP     0x8000  // When 1 enables Switched Full Duplex mode
-
-#define TCR_CLEAR      0       /* do NOTHING */
-/* the default settings for the TCR register : */
-#define TCR_DEFAULT    (TCR_ENABLE | TCR_PAD_EN)
-
-
-// EPH Status Register
-/* BANK 0  */
-#define EPH_STATUS_REG(lp)     SMC_REG(lp, 0x0002, 0)
-#define ES_TX_SUC      0x0001  // Last TX was successful
-#define ES_SNGL_COL    0x0002  // Single collision detected for last tx
-#define ES_MUL_COL     0x0004  // Multiple collisions detected for last tx
-#define ES_LTX_MULT    0x0008  // Last tx was a multicast
-#define ES_16COL       0x0010  // 16 Collisions Reached
-#define ES_SQET                0x0020  // Signal Quality Error Test
-#define ES_LTXBRD      0x0040  // Last tx was a broadcast
-#define ES_TXDEFR      0x0080  // Transmit Deferred
-#define ES_LATCOL      0x0200  // Late collision detected on last tx
-#define ES_LOSTCARR    0x0400  // Lost Carrier Sense
-#define ES_EXC_DEF     0x0800  // Excessive Deferral
-#define ES_CTR_ROL     0x1000  // Counter Roll Over indication
-#define ES_LINK_OK     0x4000  // Driven by inverted value of nLNK pin
-#define ES_TXUNRN      0x8000  // Tx Underrun
-
-
-// Receive Control Register
-/* BANK 0  */
-#define RCR_REG(lp)            SMC_REG(lp, 0x0004, 0)
-#define RCR_RX_ABORT   0x0001  // Set if a rx frame was aborted
-#define RCR_PRMS       0x0002  // Enable promiscuous mode
-#define RCR_ALMUL      0x0004  // When set accepts all multicast frames
-#define RCR_RXEN       0x0100  // IFF this is set, we can receive packets
-#define RCR_STRIP_CRC  0x0200  // When set strips CRC from rx packets
-#define RCR_ABORT_ENB  0x0200  // When set will abort rx on collision
-#define RCR_FILT_CAR   0x0400  // When set filters leading 12 bit s of carrier
-#define RCR_SOFTRST    0x8000  // resets the chip
-
-/* the normal settings for the RCR register : */
-#define RCR_DEFAULT    (RCR_STRIP_CRC | RCR_RXEN)
-#define RCR_CLEAR      0x0     // set it to a base state
-
-
-// Counter Register
-/* BANK 0  */
-#define COUNTER_REG(lp)        SMC_REG(lp, 0x0006, 0)
-
-
-// Memory Information Register
-/* BANK 0  */
-#define MIR_REG(lp)            SMC_REG(lp, 0x0008, 0)
-
-
-// Receive/Phy Control Register
-/* BANK 0  */
-#define RPC_REG(lp)            SMC_REG(lp, 0x000A, 0)
-#define RPC_SPEED      0x2000  // When 1 PHY is in 100Mbps mode.
-#define RPC_DPLX       0x1000  // When 1 PHY is in Full-Duplex Mode
-#define RPC_ANEG       0x0800  // When 1 PHY is in Auto-Negotiate Mode
-#define RPC_LSXA_SHFT  5       // Bits to shift LS2A,LS1A,LS0A to lsb
-#define RPC_LSXB_SHFT  2       // Bits to get LS2B,LS1B,LS0B to lsb
-
-#ifndef RPC_LSA_DEFAULT
-#define RPC_LSA_DEFAULT        RPC_LED_100
-#endif
-#ifndef RPC_LSB_DEFAULT
-#define RPC_LSB_DEFAULT RPC_LED_FD
-#endif
-
-#define RPC_DEFAULT (RPC_ANEG | RPC_SPEED | RPC_DPLX)
-
-
-/* Bank 0 0x0C is reserved */
-
-// Bank Select Register
-/* All Banks */
-#define BSR_REG                0x000E
-
-
-// Configuration Reg
-/* BANK 1 */
-#define CONFIG_REG(lp) SMC_REG(lp, 0x0000,     1)
-#define CONFIG_EXT_PHY 0x0200  // 1=external MII, 0=internal Phy
-#define CONFIG_GPCNTRL 0x0400  // Inverse value drives pin nCNTRL
-#define CONFIG_NO_WAIT 0x1000  // When 1 no extra wait states on ISA bus
-#define CONFIG_EPH_POWER_EN 0x8000 // When 0 EPH is placed into low power mode.
-
-// Default is powered-up, Internal Phy, Wait States, and pin nCNTRL=low
-#define CONFIG_DEFAULT (CONFIG_EPH_POWER_EN)
-
-
-// Base Address Register
-/* BANK 1 */
-#define BASE_REG(lp)   SMC_REG(lp, 0x0002, 1)
-
-
-// Individual Address Registers
-/* BANK 1 */
-#define ADDR0_REG(lp)  SMC_REG(lp, 0x0004, 1)
-#define ADDR1_REG(lp)  SMC_REG(lp, 0x0006, 1)
-#define ADDR2_REG(lp)  SMC_REG(lp, 0x0008, 1)
-
-
-// General Purpose Register
-/* BANK 1 */
-#define GP_REG(lp)             SMC_REG(lp, 0x000A, 1)
-
-
-// Control Register
-/* BANK 1 */
-#define CTL_REG(lp)            SMC_REG(lp, 0x000C, 1)
-#define CTL_RCV_BAD    0x4000 // When 1 bad CRC packets are received
-#define CTL_AUTO_RELEASE 0x0800 // When 1 tx pages are released automatically
-#define CTL_LE_ENABLE  0x0080 // When 1 enables Link Error interrupt
-#define CTL_CR_ENABLE  0x0040 // When 1 enables Counter Rollover interrupt
-#define CTL_TE_ENABLE  0x0020 // When 1 enables Transmit Error interrupt
-#define CTL_EEPROM_SELECT 0x0004 // Controls EEPROM reload & store
-#define CTL_RELOAD     0x0002 // When set reads EEPROM into registers
-#define CTL_STORE      0x0001 // When set stores registers into EEPROM
-
-
-// MMU Command Register
-/* BANK 2 */
-#define MMU_CMD_REG(lp)        SMC_REG(lp, 0x0000, 2)
-#define MC_BUSY                1       // When 1 the last release has not completed
-#define MC_NOP         (0<<5)  // No Op
-#define MC_ALLOC       (1<<5)  // OR with number of 256 byte packets
-#define MC_RESET       (2<<5)  // Reset MMU to initial state
-#define MC_REMOVE      (3<<5)  // Remove the current rx packet
-#define MC_RELEASE     (4<<5)  // Remove and release the current rx packet
-#define MC_FREEPKT     (5<<5)  // Release packet in PNR register
-#define MC_ENQUEUE     (6<<5)  // Enqueue the packet for transmit
-#define MC_RSTTXFIFO   (7<<5)  // Reset the TX FIFOs
-
-
-// Packet Number Register
-/* BANK 2 */
-#define PN_REG(lp)             SMC_REG(lp, 0x0002, 2)
-
-
-// Allocation Result Register
-/* BANK 2 */
-#define AR_REG(lp)             SMC_REG(lp, 0x0003, 2)
-#define AR_FAILED      0x80    // Alocation Failed
-
-
-// TX FIFO Ports Register
-/* BANK 2 */
-#define TXFIFO_REG(lp) SMC_REG(lp, 0x0004, 2)
-#define TXFIFO_TEMPTY  0x80    // TX FIFO Empty
-
-// RX FIFO Ports Register
-/* BANK 2 */
-#define RXFIFO_REG(lp) SMC_REG(lp, 0x0005, 2)
-#define RXFIFO_REMPTY  0x80    // RX FIFO Empty
-
-#define FIFO_REG(lp)   SMC_REG(lp, 0x0004, 2)
-
-// Pointer Register
-/* BANK 2 */
-#define PTR_REG(lp)            SMC_REG(lp, 0x0006, 2)
-#define PTR_RCV                0x8000 // 1=Receive area, 0=Transmit area
-#define PTR_AUTOINC    0x4000 // Auto increment the pointer on each access
-#define PTR_READ       0x2000 // When 1 the operation is a read
-
-
-// Data Register
-/* BANK 2 */
-#define DATA_REG(lp)   SMC_REG(lp, 0x0008, 2)
-
-
-// Interrupt Status/Acknowledge Register
-/* BANK 2 */
-#define INT_REG(lp)            SMC_REG(lp, 0x000C, 2)
-
-
-// Interrupt Mask Register
-/* BANK 2 */
-#define IM_REG(lp)             SMC_REG(lp, 0x000D, 2)
-#define IM_MDINT       0x80 // PHY MI Register 18 Interrupt
-#define IM_ERCV_INT    0x40 // Early Receive Interrupt
-#define IM_EPH_INT     0x20 // Set by Ethernet Protocol Handler section
-#define IM_RX_OVRN_INT 0x10 // Set by Receiver Overruns
-#define IM_ALLOC_INT   0x08 // Set when allocation request is completed
-#define IM_TX_EMPTY_INT        0x04 // Set if the TX FIFO goes empty
-#define IM_TX_INT      0x02 // Transmit Interrupt
-#define IM_RCV_INT     0x01 // Receive Interrupt
-
-
-// Multicast Table Registers
-/* BANK 3 */
-#define MCAST_REG1(lp) SMC_REG(lp, 0x0000, 3)
-#define MCAST_REG2(lp) SMC_REG(lp, 0x0002, 3)
-#define MCAST_REG3(lp) SMC_REG(lp, 0x0004, 3)
-#define MCAST_REG4(lp) SMC_REG(lp, 0x0006, 3)
-
-
-// Management Interface Register (MII)
-/* BANK 3 */
-#define MII_REG(lp)            SMC_REG(lp, 0x0008, 3)
-#define MII_MSK_CRS100 0x4000 // Disables CRS100 detection during tx half dup
-#define MII_MDOE       0x0008 // MII Output Enable
-#define MII_MCLK       0x0004 // MII Clock, pin MDCLK
-#define MII_MDI                0x0002 // MII Input, pin MDI
-#define MII_MDO                0x0001 // MII Output, pin MDO
-
-
-// Revision Register
-/* BANK 3 */
-/* ( hi: chip id   low: rev # ) */
-#define REV_REG(lp)            SMC_REG(lp, 0x000A, 3)
-
-
-// Early RCV Register
-/* BANK 3 */
-/* this is NOT on SMC9192 */
-#define ERCV_REG(lp)   SMC_REG(lp, 0x000C, 3)
-#define ERCV_RCV_DISCRD        0x0080 // When 1 discards a packet being received
-#define ERCV_THRESHOLD 0x001F // ERCV Threshold Mask
-
-
-// External Register
-/* BANK 7 */
-#define EXT_REG(lp)            SMC_REG(lp, 0x0000, 7)
-
-
-#define CHIP_9192      3
-#define CHIP_9194      4
-#define CHIP_9195      5
-#define CHIP_9196      6
-#define CHIP_91100     7
-#define CHIP_91100FD   8
-#define CHIP_91111FD   9
-
-static const char * chip_ids[ 16 ] =  {
-       NULL, NULL, NULL,
-       /* 3 */ "SMC91C90/91C92",
-       /* 4 */ "SMC91C94",
-       /* 5 */ "SMC91C95",
-       /* 6 */ "SMC91C96",
-       /* 7 */ "SMC91C100",
-       /* 8 */ "SMC91C100FD",
-       /* 9 */ "SMC91C11xFD",
-       NULL, NULL, NULL,
-       NULL, NULL, NULL};
-
-
-/*
- . Receive status bits
-*/
-#define RS_ALGNERR     0x8000
-#define RS_BRODCAST    0x4000
-#define RS_BADCRC      0x2000
-#define RS_ODDFRAME    0x1000
-#define RS_TOOLONG     0x0800
-#define RS_TOOSHORT    0x0400
-#define RS_MULTICAST   0x0001
-#define RS_ERRORS      (RS_ALGNERR | RS_BADCRC | RS_TOOLONG | RS_TOOSHORT)
-
-
-/*
- * PHY IDs
- *  LAN83C183 == LAN91C111 Internal PHY
- */
-#define PHY_LAN83C183  0x0016f840
-#define PHY_LAN83C180  0x02821c50
-
-/*
- * PHY Register Addresses (LAN91C111 Internal PHY)
- *
- * Generic PHY registers can be found in <linux/mii.h>
- *
- * These phy registers are specific to our on-board phy.
- */
-
-// PHY Configuration Register 1
-#define PHY_CFG1_REG           0x10
-#define PHY_CFG1_LNKDIS                0x8000  // 1=Rx Link Detect Function disabled
-#define PHY_CFG1_XMTDIS                0x4000  // 1=TP Transmitter Disabled
-#define PHY_CFG1_XMTPDN                0x2000  // 1=TP Transmitter Powered Down
-#define PHY_CFG1_BYPSCR                0x0400  // 1=Bypass scrambler/descrambler
-#define PHY_CFG1_UNSCDS                0x0200  // 1=Unscramble Idle Reception Disable
-#define PHY_CFG1_EQLZR         0x0100  // 1=Rx Equalizer Disabled
-#define PHY_CFG1_CABLE         0x0080  // 1=STP(150ohm), 0=UTP(100ohm)
-#define PHY_CFG1_RLVL0         0x0040  // 1=Rx Squelch level reduced by 4.5db
-#define PHY_CFG1_TLVL_SHIFT    2       // Transmit Output Level Adjust
-#define PHY_CFG1_TLVL_MASK     0x003C
-#define PHY_CFG1_TRF_MASK      0x0003  // Transmitter Rise/Fall time
-
-
-// PHY Configuration Register 2
-#define PHY_CFG2_REG           0x11
-#define PHY_CFG2_APOLDIS       0x0020  // 1=Auto Polarity Correction disabled
-#define PHY_CFG2_JABDIS                0x0010  // 1=Jabber disabled
-#define PHY_CFG2_MREG          0x0008  // 1=Multiple register access (MII mgt)
-#define PHY_CFG2_INTMDIO       0x0004  // 1=Interrupt signaled with MDIO pulseo
-
-// PHY Status Output (and Interrupt status) Register
-#define PHY_INT_REG            0x12    // Status Output (Interrupt Status)
-#define PHY_INT_INT            0x8000  // 1=bits have changed since last read
-#define PHY_INT_LNKFAIL                0x4000  // 1=Link Not detected
-#define PHY_INT_LOSSSYNC       0x2000  // 1=Descrambler has lost sync
-#define PHY_INT_CWRD           0x1000  // 1=Invalid 4B5B code detected on rx
-#define PHY_INT_SSD            0x0800  // 1=No Start Of Stream detected on rx
-#define PHY_INT_ESD            0x0400  // 1=No End Of Stream detected on rx
-#define PHY_INT_RPOL           0x0200  // 1=Reverse Polarity detected
-#define PHY_INT_JAB            0x0100  // 1=Jabber detected
-#define PHY_INT_SPDDET         0x0080  // 1=100Base-TX mode, 0=10Base-T mode
-#define PHY_INT_DPLXDET                0x0040  // 1=Device in Full Duplex
-
-// PHY Interrupt/Status Mask Register
-#define PHY_MASK_REG           0x13    // Interrupt Mask
-// Uses the same bit definitions as PHY_INT_REG
-
-
-/*
- * SMC91C96 ethernet config and status registers.
- * These are in the "attribute" space.
- */
-#define ECOR                   0x8000
-#define ECOR_RESET             0x80
-#define ECOR_LEVEL_IRQ         0x40
-#define ECOR_WR_ATTRIB         0x04
-#define ECOR_ENABLE            0x01
-
-#define ECSR                   0x8002
-#define ECSR_IOIS8             0x20
-#define ECSR_PWRDWN            0x04
-#define ECSR_INT               0x02
-
-#define ATTRIB_SIZE            ((64*1024) << SMC_IO_SHIFT)
-
-
-/*
- * Macros to abstract register access according to the data bus
- * capabilities.  Please use those and not the in/out primitives.
- * Note: the following macros do *not* select the bank -- this must
- * be done separately as needed in the main code.  The SMC_REG() macro
- * only uses the bank argument for debugging purposes (when enabled).
- *
- * Note: despite inline functions being safer, everything leading to this
- * should preferably be macros to let BUG() display the line number in
- * the core source code since we're interested in the top call site
- * not in any inline function location.
- */
-
-#if SMC_DEBUG > 0
-#define SMC_REG(lp, reg, bank)                                 \
-       ({                                                              \
-               int __b = SMC_CURRENT_BANK(lp);                 \
-               if (unlikely((__b & ~0xf0) != (0x3300 | bank))) {       \
-                       printk( "%s: bank reg screwed (0x%04x)\n",      \
-                               CARDNAME, __b );                        \
-                       BUG();                                          \
-               }                                                       \
-               reg<<SMC_IO_SHIFT;                                      \
-       })
-#else
-#define SMC_REG(lp, reg, bank) (reg<<SMC_IO_SHIFT)
-#endif
-
-/*
- * Hack Alert: Some setups just can't write 8 or 16 bits reliably when not
- * aligned to a 32 bit boundary.  I tell you that does exist!
- * Fortunately the affected register accesses can be easily worked around
- * since we can write zeroes to the preceding 16 bits without adverse
- * effects and use a 32-bit access.
- *
- * Enforce it on any 32-bit capable setup for now.
- */
-#define SMC_MUST_ALIGN_WRITE(lp)       SMC_32BIT(lp)
-
-#define SMC_GET_PN(lp)                                         \
-       (SMC_8BIT(lp)   ? (SMC_inb(ioaddr, PN_REG(lp))) \
-                               : (SMC_inw(ioaddr, PN_REG(lp)) & 0xFF))
-
-#define SMC_SET_PN(lp, x)                                              \
-       do {                                                            \
-               if (SMC_MUST_ALIGN_WRITE(lp))                           \
-                       SMC_outl((x)<<16, ioaddr, SMC_REG(lp, 0, 2));   \
-               else if (SMC_8BIT(lp))                          \
-                       SMC_outb(x, ioaddr, PN_REG(lp));                \
-               else                                                    \
-                       SMC_outw(x, ioaddr, PN_REG(lp));                \
-       } while (0)
-
-#define SMC_GET_AR(lp)                                         \
-       (SMC_8BIT(lp)   ? (SMC_inb(ioaddr, AR_REG(lp))) \
-                               : (SMC_inw(ioaddr, PN_REG(lp)) >> 8))
-
-#define SMC_GET_TXFIFO(lp)                                             \
-       (SMC_8BIT(lp)   ? (SMC_inb(ioaddr, TXFIFO_REG(lp)))     \
-                               : (SMC_inw(ioaddr, TXFIFO_REG(lp)) & 0xFF))
-
-#define SMC_GET_RXFIFO(lp)                                             \
-       (SMC_8BIT(lp)   ? (SMC_inb(ioaddr, RXFIFO_REG(lp)))     \
-                               : (SMC_inw(ioaddr, TXFIFO_REG(lp)) >> 8))
-
-#define SMC_GET_INT(lp)                                                \
-       (SMC_8BIT(lp)   ? (SMC_inb(ioaddr, INT_REG(lp)))        \
-                               : (SMC_inw(ioaddr, INT_REG(lp)) & 0xFF))
-
-#define SMC_ACK_INT(lp, x)                                             \
-       do {                                                            \
-               if (SMC_8BIT(lp))                                       \
-                       SMC_outb(x, ioaddr, INT_REG(lp));               \
-               else {                                                  \
-                       unsigned long __flags;                          \
-                       int __mask;                                     \
-                       local_irq_save(__flags);                        \
-                       __mask = SMC_inw(ioaddr, INT_REG(lp)) & ~0xff; \
-                       SMC_outw(__mask | (x), ioaddr, INT_REG(lp));    \
-                       local_irq_restore(__flags);                     \
-               }                                                       \
-       } while (0)
-
-#define SMC_GET_INT_MASK(lp)                                           \
-       (SMC_8BIT(lp)   ? (SMC_inb(ioaddr, IM_REG(lp))) \
-                               : (SMC_inw(ioaddr, INT_REG(lp)) >> 8))
-
-#define SMC_SET_INT_MASK(lp, x)                                        \
-       do {                                                            \
-               if (SMC_8BIT(lp))                                       \
-                       SMC_outb(x, ioaddr, IM_REG(lp));                \
-               else                                                    \
-                       SMC_outw((x) << 8, ioaddr, INT_REG(lp));        \
-       } while (0)
-
-#define SMC_CURRENT_BANK(lp)   SMC_inw(ioaddr, BANK_SELECT)
-
-#define SMC_SELECT_BANK(lp, x)                                 \
-       do {                                                            \
-               if (SMC_MUST_ALIGN_WRITE(lp))                           \
-                       SMC_outl((x)<<16, ioaddr, 12<<SMC_IO_SHIFT);    \
-               else                                                    \
-                       SMC_outw(x, ioaddr, BANK_SELECT);               \
-       } while (0)
-
-#define SMC_GET_BASE(lp)               SMC_inw(ioaddr, BASE_REG(lp))
-
-#define SMC_SET_BASE(lp, x)            SMC_outw(x, ioaddr, BASE_REG(lp))
-
-#define SMC_GET_CONFIG(lp)     SMC_inw(ioaddr, CONFIG_REG(lp))
-
-#define SMC_SET_CONFIG(lp, x)  SMC_outw(x, ioaddr, CONFIG_REG(lp))
-
-#define SMC_GET_COUNTER(lp)    SMC_inw(ioaddr, COUNTER_REG(lp))
-
-#define SMC_GET_CTL(lp)                SMC_inw(ioaddr, CTL_REG(lp))
-
-#define SMC_SET_CTL(lp, x)             SMC_outw(x, ioaddr, CTL_REG(lp))
-
-#define SMC_GET_MII(lp)                SMC_inw(ioaddr, MII_REG(lp))
-
-#define SMC_GET_GP(lp)         SMC_inw(ioaddr, GP_REG(lp))
-
-#define SMC_SET_GP(lp, x)                                              \
-       do {                                                            \
-               if (SMC_MUST_ALIGN_WRITE(lp))                           \
-                       SMC_outl((x)<<16, ioaddr, SMC_REG(lp, 8, 1));   \
-               else                                                    \
-                       SMC_outw(x, ioaddr, GP_REG(lp));                \
-       } while (0)
-
-#define SMC_SET_MII(lp, x)             SMC_outw(x, ioaddr, MII_REG(lp))
-
-#define SMC_GET_MIR(lp)                SMC_inw(ioaddr, MIR_REG(lp))
-
-#define SMC_SET_MIR(lp, x)             SMC_outw(x, ioaddr, MIR_REG(lp))
-
-#define SMC_GET_MMU_CMD(lp)    SMC_inw(ioaddr, MMU_CMD_REG(lp))
-
-#define SMC_SET_MMU_CMD(lp, x) SMC_outw(x, ioaddr, MMU_CMD_REG(lp))
-
-#define SMC_GET_FIFO(lp)               SMC_inw(ioaddr, FIFO_REG(lp))
-
-#define SMC_GET_PTR(lp)                SMC_inw(ioaddr, PTR_REG(lp))
-
-#define SMC_SET_PTR(lp, x)                                             \
-       do {                                                            \
-               if (SMC_MUST_ALIGN_WRITE(lp))                           \
-                       SMC_outl((x)<<16, ioaddr, SMC_REG(lp, 4, 2));   \
-               else                                                    \
-                       SMC_outw(x, ioaddr, PTR_REG(lp));               \
-       } while (0)
-
-#define SMC_GET_EPH_STATUS(lp) SMC_inw(ioaddr, EPH_STATUS_REG(lp))
-
-#define SMC_GET_RCR(lp)                SMC_inw(ioaddr, RCR_REG(lp))
-
-#define SMC_SET_RCR(lp, x)             SMC_outw(x, ioaddr, RCR_REG(lp))
-
-#define SMC_GET_REV(lp)                SMC_inw(ioaddr, REV_REG(lp))
-
-#define SMC_GET_RPC(lp)                SMC_inw(ioaddr, RPC_REG(lp))
-
-#define SMC_SET_RPC(lp, x)                                             \
-       do {                                                            \
-               if (SMC_MUST_ALIGN_WRITE(lp))                           \
-                       SMC_outl((x)<<16, ioaddr, SMC_REG(lp, 8, 0));   \
-               else                                                    \
-                       SMC_outw(x, ioaddr, RPC_REG(lp));               \
-       } while (0)
-
-#define SMC_GET_TCR(lp)                SMC_inw(ioaddr, TCR_REG(lp))
-
-#define SMC_SET_TCR(lp, x)             SMC_outw(x, ioaddr, TCR_REG(lp))
-
-#ifndef SMC_GET_MAC_ADDR
-#define SMC_GET_MAC_ADDR(lp, addr)                                     \
-       do {                                                            \
-               unsigned int __v;                                       \
-               __v = SMC_inw(ioaddr, ADDR0_REG(lp));                   \
-               addr[0] = __v; addr[1] = __v >> 8;                      \
-               __v = SMC_inw(ioaddr, ADDR1_REG(lp));                   \
-               addr[2] = __v; addr[3] = __v >> 8;                      \
-               __v = SMC_inw(ioaddr, ADDR2_REG(lp));                   \
-               addr[4] = __v; addr[5] = __v >> 8;                      \
-       } while (0)
-#endif
-
-#define SMC_SET_MAC_ADDR(lp, addr)                                     \
-       do {                                                            \
-               SMC_outw(addr[0]|(addr[1] << 8), ioaddr, ADDR0_REG(lp)); \
-               SMC_outw(addr[2]|(addr[3] << 8), ioaddr, ADDR1_REG(lp)); \
-               SMC_outw(addr[4]|(addr[5] << 8), ioaddr, ADDR2_REG(lp)); \
-       } while (0)
-
-#define SMC_SET_MCAST(lp, x)                                           \
-       do {                                                            \
-               const unsigned char *mt = (x);                          \
-               SMC_outw(mt[0] | (mt[1] << 8), ioaddr, MCAST_REG1(lp)); \
-               SMC_outw(mt[2] | (mt[3] << 8), ioaddr, MCAST_REG2(lp)); \
-               SMC_outw(mt[4] | (mt[5] << 8), ioaddr, MCAST_REG3(lp)); \
-               SMC_outw(mt[6] | (mt[7] << 8), ioaddr, MCAST_REG4(lp)); \
-       } while (0)
-
-#define SMC_PUT_PKT_HDR(lp, status, length)                            \
-       do {                                                            \
-               if (SMC_32BIT(lp))                                      \
-                       SMC_outl((status) | (length)<<16, ioaddr,       \
-                                DATA_REG(lp));                 \
-               else {                                                  \
-                       SMC_outw(status, ioaddr, DATA_REG(lp)); \
-                       SMC_outw(length, ioaddr, DATA_REG(lp)); \
-               }                                                       \
-       } while (0)
-
-#define SMC_GET_PKT_HDR(lp, status, length)                            \
-       do {                                                            \
-               if (SMC_32BIT(lp)) {                            \
-                       unsigned int __val = SMC_inl(ioaddr, DATA_REG(lp)); \
-                       (status) = __val & 0xffff;                      \
-                       (length) = __val >> 16;                         \
-               } else {                                                \
-                       (status) = SMC_inw(ioaddr, DATA_REG(lp));       \
-                       (length) = SMC_inw(ioaddr, DATA_REG(lp));       \
-               }                                                       \
-       } while (0)
-
-#define SMC_PUSH_DATA(lp, p, l)                                        \
-       do {                                                            \
-               if (SMC_32BIT(lp)) {                            \
-                       void *__ptr = (p);                              \
-                       int __len = (l);                                \
-                       void __iomem *__ioaddr = ioaddr;                \
-                       if (__len >= 2 && (unsigned long)__ptr & 2) {   \
-                               __len -= 2;                             \
-                               SMC_outw(*(u16 *)__ptr, ioaddr,         \
-                                       DATA_REG(lp));          \
-                               __ptr += 2;                             \
-                       }                                               \
-                       if (SMC_CAN_USE_DATACS && lp->datacs)           \
-                               __ioaddr = lp->datacs;                  \
-                       SMC_outsl(__ioaddr, DATA_REG(lp), __ptr, __len>>2); \
-                       if (__len & 2) {                                \
-                               __ptr += (__len & ~3);                  \
-                               SMC_outw(*((u16 *)__ptr), ioaddr,       \
-                                        DATA_REG(lp));         \
-                       }                                               \
-               } else if (SMC_16BIT(lp))                               \
-                       SMC_outsw(ioaddr, DATA_REG(lp), p, (l) >> 1);   \
-               else if (SMC_8BIT(lp))                          \
-                       SMC_outsb(ioaddr, DATA_REG(lp), p, l);  \
-       } while (0)
-
-#define SMC_PULL_DATA(lp, p, l)                                        \
-       do {                                                            \
-               if (SMC_32BIT(lp)) {                            \
-                       void *__ptr = (p);                              \
-                       int __len = (l);                                \
-                       void __iomem *__ioaddr = ioaddr;                \
-                       if ((unsigned long)__ptr & 2) {                 \
-                               /*                                      \
-                                * We want 32bit alignment here.        \
-                                * Since some buses perform a full      \
-                                * 32bit fetch even for 16bit data      \
-                                * we can't use SMC_inw() here.         \
-                                * Back both source (on-chip) and       \
-                                * destination pointers of 2 bytes.     \
-                                * This is possible since the call to   \
-                                * SMC_GET_PKT_HDR() already advanced   \
-                                * the source pointer of 4 bytes, and   \
-                                * the skb_reserve(skb, 2) advanced     \
-                                * the destination pointer of 2 bytes.  \
-                                */                                     \
-                               __ptr -= 2;                             \
-                               __len += 2;                             \
-                               SMC_SET_PTR(lp,                 \
-                                       2|PTR_READ|PTR_RCV|PTR_AUTOINC); \
-                       }                                               \
-                       if (SMC_CAN_USE_DATACS && lp->datacs)           \
-                               __ioaddr = lp->datacs;                  \
-                       __len += 2;                                     \
-                       SMC_insl(__ioaddr, DATA_REG(lp), __ptr, __len>>2); \
-               } else if (SMC_16BIT(lp))                               \
-                       SMC_insw(ioaddr, DATA_REG(lp), p, (l) >> 1);    \
-               else if (SMC_8BIT(lp))                          \
-                       SMC_insb(ioaddr, DATA_REG(lp), p, l);           \
-       } while (0)
-
-#endif  /* _SMC91X_H_ */
diff --git a/drivers/net/smsc911x.c b/drivers/net/smsc911x.c
deleted file mode 100644 (file)
index 75c08a5..0000000
+++ /dev/null
@@ -1,2404 +0,0 @@
-/***************************************************************************
- *
- * Copyright (C) 2004-2008 SMSC
- * Copyright (C) 2005-2008 ARM
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU General Public License
- * as published by the Free Software Foundation; either version 2
- * of the License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
- *
- ***************************************************************************
- * Rewritten, heavily based on smsc911x simple driver by SMSC.
- * Partly uses io macros from smc91x.c by Nicolas Pitre
- *
- * Supported devices:
- *   LAN9115, LAN9116, LAN9117, LAN9118
- *   LAN9215, LAN9216, LAN9217, LAN9218
- *   LAN9210, LAN9211
- *   LAN9220, LAN9221
- *
- */
-
-#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
-
-#include <linux/crc32.h>
-#include <linux/delay.h>
-#include <linux/errno.h>
-#include <linux/etherdevice.h>
-#include <linux/ethtool.h>
-#include <linux/init.h>
-#include <linux/interrupt.h>
-#include <linux/ioport.h>
-#include <linux/kernel.h>
-#include <linux/module.h>
-#include <linux/netdevice.h>
-#include <linux/platform_device.h>
-#include <linux/sched.h>
-#include <linux/timer.h>
-#include <linux/bug.h>
-#include <linux/bitops.h>
-#include <linux/irq.h>
-#include <linux/io.h>
-#include <linux/swab.h>
-#include <linux/phy.h>
-#include <linux/smsc911x.h>
-#include <linux/device.h>
-#include <linux/of.h>
-#include <linux/of_device.h>
-#include <linux/of_gpio.h>
-#include <linux/of_net.h>
-#include "smsc911x.h"
-
-#define SMSC_CHIPNAME          "smsc911x"
-#define SMSC_MDIONAME          "smsc911x-mdio"
-#define SMSC_DRV_VERSION       "2008-10-21"
-
-MODULE_LICENSE("GPL");
-MODULE_VERSION(SMSC_DRV_VERSION);
-MODULE_ALIAS("platform:smsc911x");
-
-#if USE_DEBUG > 0
-static int debug = 16;
-#else
-static int debug = 3;
-#endif
-
-module_param(debug, int, 0);
-MODULE_PARM_DESC(debug, "Debug level (0=none,...,16=all)");
-
-struct smsc911x_data;
-
-struct smsc911x_ops {
-       u32 (*reg_read)(struct smsc911x_data *pdata, u32 reg);
-       void (*reg_write)(struct smsc911x_data *pdata, u32 reg, u32 val);
-       void (*rx_readfifo)(struct smsc911x_data *pdata,
-                               unsigned int *buf, unsigned int wordcount);
-       void (*tx_writefifo)(struct smsc911x_data *pdata,
-                               unsigned int *buf, unsigned int wordcount);
-};
-
-struct smsc911x_data {
-       void __iomem *ioaddr;
-
-       unsigned int idrev;
-
-       /* used to decide which workarounds apply */
-       unsigned int generation;
-
-       /* device configuration (copied from platform_data during probe) */
-       struct smsc911x_platform_config config;
-
-       /* This needs to be acquired before calling any of below:
-        * smsc911x_mac_read(), smsc911x_mac_write()
-        */
-       spinlock_t mac_lock;
-
-       /* spinlock to ensure register accesses are serialised */
-       spinlock_t dev_lock;
-
-       struct phy_device *phy_dev;
-       struct mii_bus *mii_bus;
-       int phy_irq[PHY_MAX_ADDR];
-       unsigned int using_extphy;
-       int last_duplex;
-       int last_carrier;
-
-       u32 msg_enable;
-       unsigned int gpio_setting;
-       unsigned int gpio_orig_setting;
-       struct net_device *dev;
-       struct napi_struct napi;
-
-       unsigned int software_irq_signal;
-
-#ifdef USE_PHY_WORK_AROUND
-#define MIN_PACKET_SIZE (64)
-       char loopback_tx_pkt[MIN_PACKET_SIZE];
-       char loopback_rx_pkt[MIN_PACKET_SIZE];
-       unsigned int resetcount;
-#endif
-
-       /* Members for Multicast filter workaround */
-       unsigned int multicast_update_pending;
-       unsigned int set_bits_mask;
-       unsigned int clear_bits_mask;
-       unsigned int hashhi;
-       unsigned int hashlo;
-
-       /* register access functions */
-       const struct smsc911x_ops *ops;
-};
-
-/* Easy access to information */
-#define __smsc_shift(pdata, reg) ((reg) << ((pdata)->config.shift))
-
-static inline u32 __smsc911x_reg_read(struct smsc911x_data *pdata, u32 reg)
-{
-       if (pdata->config.flags & SMSC911X_USE_32BIT)
-               return readl(pdata->ioaddr + reg);
-
-       if (pdata->config.flags & SMSC911X_USE_16BIT)
-               return ((readw(pdata->ioaddr + reg) & 0xFFFF) |
-                       ((readw(pdata->ioaddr + reg + 2) & 0xFFFF) << 16));
-
-       BUG();
-       return 0;
-}
-
-static inline u32
-__smsc911x_reg_read_shift(struct smsc911x_data *pdata, u32 reg)
-{
-       if (pdata->config.flags & SMSC911X_USE_32BIT)
-               return readl(pdata->ioaddr + __smsc_shift(pdata, reg));
-
-       if (pdata->config.flags & SMSC911X_USE_16BIT)
-               return (readw(pdata->ioaddr +
-                               __smsc_shift(pdata, reg)) & 0xFFFF) |
-                       ((readw(pdata->ioaddr +
-                       __smsc_shift(pdata, reg + 2)) & 0xFFFF) << 16);
-
-       BUG();
-       return 0;
-}
-
-static inline u32 smsc911x_reg_read(struct smsc911x_data *pdata, u32 reg)
-{
-       u32 data;
-       unsigned long flags;
-
-       spin_lock_irqsave(&pdata->dev_lock, flags);
-       data = pdata->ops->reg_read(pdata, reg);
-       spin_unlock_irqrestore(&pdata->dev_lock, flags);
-
-       return data;
-}
-
-static inline void __smsc911x_reg_write(struct smsc911x_data *pdata, u32 reg,
-                                       u32 val)
-{
-       if (pdata->config.flags & SMSC911X_USE_32BIT) {
-               writel(val, pdata->ioaddr + reg);
-               return;
-       }
-
-       if (pdata->config.flags & SMSC911X_USE_16BIT) {
-               writew(val & 0xFFFF, pdata->ioaddr + reg);
-               writew((val >> 16) & 0xFFFF, pdata->ioaddr + reg + 2);
-               return;
-       }
-
-       BUG();
-}
-
-static inline void
-__smsc911x_reg_write_shift(struct smsc911x_data *pdata, u32 reg, u32 val)
-{
-       if (pdata->config.flags & SMSC911X_USE_32BIT) {
-               writel(val, pdata->ioaddr + __smsc_shift(pdata, reg));
-               return;
-       }
-
-       if (pdata->config.flags & SMSC911X_USE_16BIT) {
-               writew(val & 0xFFFF,
-                       pdata->ioaddr + __smsc_shift(pdata, reg));
-               writew((val >> 16) & 0xFFFF,
-                       pdata->ioaddr + __smsc_shift(pdata, reg + 2));
-               return;
-       }
-
-       BUG();
-}
-
-static inline void smsc911x_reg_write(struct smsc911x_data *pdata, u32 reg,
-                                     u32 val)
-{
-       unsigned long flags;
-
-       spin_lock_irqsave(&pdata->dev_lock, flags);
-       pdata->ops->reg_write(pdata, reg, val);
-       spin_unlock_irqrestore(&pdata->dev_lock, flags);
-}
-
-/* Writes a packet to the TX_DATA_FIFO */
-static inline void
-smsc911x_tx_writefifo(struct smsc911x_data *pdata, unsigned int *buf,
-                     unsigned int wordcount)
-{
-       unsigned long flags;
-
-       spin_lock_irqsave(&pdata->dev_lock, flags);
-
-       if (pdata->config.flags & SMSC911X_SWAP_FIFO) {
-               while (wordcount--)
-                       __smsc911x_reg_write(pdata, TX_DATA_FIFO,
-                                            swab32(*buf++));
-               goto out;
-       }
-
-       if (pdata->config.flags & SMSC911X_USE_32BIT) {
-               writesl(pdata->ioaddr + TX_DATA_FIFO, buf, wordcount);
-               goto out;
-       }
-
-       if (pdata->config.flags & SMSC911X_USE_16BIT) {
-               while (wordcount--)
-                       __smsc911x_reg_write(pdata, TX_DATA_FIFO, *buf++);
-               goto out;
-       }
-
-       BUG();
-out:
-       spin_unlock_irqrestore(&pdata->dev_lock, flags);
-}
-
-/* Writes a packet to the TX_DATA_FIFO - shifted version */
-static inline void
-smsc911x_tx_writefifo_shift(struct smsc911x_data *pdata, unsigned int *buf,
-                     unsigned int wordcount)
-{
-       unsigned long flags;
-
-       spin_lock_irqsave(&pdata->dev_lock, flags);
-
-       if (pdata->config.flags & SMSC911X_SWAP_FIFO) {
-               while (wordcount--)
-                       __smsc911x_reg_write_shift(pdata, TX_DATA_FIFO,
-                                            swab32(*buf++));
-               goto out;
-       }
-
-       if (pdata->config.flags & SMSC911X_USE_32BIT) {
-               writesl(pdata->ioaddr + __smsc_shift(pdata,
-                                               TX_DATA_FIFO), buf, wordcount);
-               goto out;
-       }
-
-       if (pdata->config.flags & SMSC911X_USE_16BIT) {
-               while (wordcount--)
-                       __smsc911x_reg_write_shift(pdata,
-                                                TX_DATA_FIFO, *buf++);
-               goto out;
-       }
-
-       BUG();
-out:
-       spin_unlock_irqrestore(&pdata->dev_lock, flags);
-}
-
-/* Reads a packet out of the RX_DATA_FIFO */
-static inline void
-smsc911x_rx_readfifo(struct smsc911x_data *pdata, unsigned int *buf,
-                    unsigned int wordcount)
-{
-       unsigned long flags;
-
-       spin_lock_irqsave(&pdata->dev_lock, flags);
-
-       if (pdata->config.flags & SMSC911X_SWAP_FIFO) {
-               while (wordcount--)
-                       *buf++ = swab32(__smsc911x_reg_read(pdata,
-                                                           RX_DATA_FIFO));
-               goto out;
-       }
-
-       if (pdata->config.flags & SMSC911X_USE_32BIT) {
-               readsl(pdata->ioaddr + RX_DATA_FIFO, buf, wordcount);
-               goto out;
-       }
-
-       if (pdata->config.flags & SMSC911X_USE_16BIT) {
-               while (wordcount--)
-                       *buf++ = __smsc911x_reg_read(pdata, RX_DATA_FIFO);
-               goto out;
-       }
-
-       BUG();
-out:
-       spin_unlock_irqrestore(&pdata->dev_lock, flags);
-}
-
-/* Reads a packet out of the RX_DATA_FIFO - shifted version */
-static inline void
-smsc911x_rx_readfifo_shift(struct smsc911x_data *pdata, unsigned int *buf,
-                    unsigned int wordcount)
-{
-       unsigned long flags;
-
-       spin_lock_irqsave(&pdata->dev_lock, flags);
-
-       if (pdata->config.flags & SMSC911X_SWAP_FIFO) {
-               while (wordcount--)
-                       *buf++ = swab32(__smsc911x_reg_read_shift(pdata,
-                                                           RX_DATA_FIFO));
-               goto out;
-       }
-
-       if (pdata->config.flags & SMSC911X_USE_32BIT) {
-               readsl(pdata->ioaddr + __smsc_shift(pdata,
-                                               RX_DATA_FIFO), buf, wordcount);
-               goto out;
-       }
-
-       if (pdata->config.flags & SMSC911X_USE_16BIT) {
-               while (wordcount--)
-                       *buf++ = __smsc911x_reg_read_shift(pdata,
-                                                               RX_DATA_FIFO);
-               goto out;
-       }
-
-       BUG();
-out:
-       spin_unlock_irqrestore(&pdata->dev_lock, flags);
-}
-
-/* waits for MAC not busy, with timeout.  Only called by smsc911x_mac_read
- * and smsc911x_mac_write, so assumes mac_lock is held */
-static int smsc911x_mac_complete(struct smsc911x_data *pdata)
-{
-       int i;
-       u32 val;
-
-       SMSC_ASSERT_MAC_LOCK(pdata);
-
-       for (i = 0; i < 40; i++) {
-               val = smsc911x_reg_read(pdata, MAC_CSR_CMD);
-               if (!(val & MAC_CSR_CMD_CSR_BUSY_))
-                       return 0;
-       }
-       SMSC_WARN(pdata, hw, "Timed out waiting for MAC not BUSY. "
-                 "MAC_CSR_CMD: 0x%08X", val);
-       return -EIO;
-}
-
-/* Fetches a MAC register value. Assumes mac_lock is acquired */
-static u32 smsc911x_mac_read(struct smsc911x_data *pdata, unsigned int offset)
-{
-       unsigned int temp;
-
-       SMSC_ASSERT_MAC_LOCK(pdata);
-
-       temp = smsc911x_reg_read(pdata, MAC_CSR_CMD);
-       if (unlikely(temp & MAC_CSR_CMD_CSR_BUSY_)) {
-               SMSC_WARN(pdata, hw, "MAC busy at entry");
-               return 0xFFFFFFFF;
-       }
-
-       /* Send the MAC cmd */
-       smsc911x_reg_write(pdata, MAC_CSR_CMD, ((offset & 0xFF) |
-               MAC_CSR_CMD_CSR_BUSY_ | MAC_CSR_CMD_R_NOT_W_));
-
-       /* Workaround for hardware read-after-write restriction */
-       temp = smsc911x_reg_read(pdata, BYTE_TEST);
-
-       /* Wait for the read to complete */
-       if (likely(smsc911x_mac_complete(pdata) == 0))
-               return smsc911x_reg_read(pdata, MAC_CSR_DATA);
-
-       SMSC_WARN(pdata, hw, "MAC busy after read");
-       return 0xFFFFFFFF;
-}
-
-/* Set a mac register, mac_lock must be acquired before calling */
-static void smsc911x_mac_write(struct smsc911x_data *pdata,
-                              unsigned int offset, u32 val)
-{
-       unsigned int temp;
-
-       SMSC_ASSERT_MAC_LOCK(pdata);
-
-       temp = smsc911x_reg_read(pdata, MAC_CSR_CMD);
-       if (unlikely(temp & MAC_CSR_CMD_CSR_BUSY_)) {
-               SMSC_WARN(pdata, hw,
-                         "smsc911x_mac_write failed, MAC busy at entry");
-               return;
-       }
-
-       /* Send data to write */
-       smsc911x_reg_write(pdata, MAC_CSR_DATA, val);
-
-       /* Write the actual data */
-       smsc911x_reg_write(pdata, MAC_CSR_CMD, ((offset & 0xFF) |
-               MAC_CSR_CMD_CSR_BUSY_));
-
-       /* Workaround for hardware read-after-write restriction */
-       temp = smsc911x_reg_read(pdata, BYTE_TEST);
-
-       /* Wait for the write to complete */
-       if (likely(smsc911x_mac_complete(pdata) == 0))
-               return;
-
-       SMSC_WARN(pdata, hw, "smsc911x_mac_write failed, MAC busy after write");
-}
-
-/* Get a phy register */
-static int smsc911x_mii_read(struct mii_bus *bus, int phyaddr, int regidx)
-{
-       struct smsc911x_data *pdata = (struct smsc911x_data *)bus->priv;
-       unsigned long flags;
-       unsigned int addr;
-       int i, reg;
-
-       spin_lock_irqsave(&pdata->mac_lock, flags);
-
-       /* Confirm MII not busy */
-       if (unlikely(smsc911x_mac_read(pdata, MII_ACC) & MII_ACC_MII_BUSY_)) {
-               SMSC_WARN(pdata, hw, "MII is busy in smsc911x_mii_read???");
-               reg = -EIO;
-               goto out;
-       }
-
-       /* Set the address, index & direction (read from PHY) */
-       addr = ((phyaddr & 0x1F) << 11) | ((regidx & 0x1F) << 6);
-       smsc911x_mac_write(pdata, MII_ACC, addr);
-
-       /* Wait for read to complete w/ timeout */
-       for (i = 0; i < 100; i++)
-               if (!(smsc911x_mac_read(pdata, MII_ACC) & MII_ACC_MII_BUSY_)) {
-                       reg = smsc911x_mac_read(pdata, MII_DATA);
-                       goto out;
-               }
-
-       SMSC_WARN(pdata, hw, "Timed out waiting for MII read to finish");
-       reg = -EIO;
-
-out:
-       spin_unlock_irqrestore(&pdata->mac_lock, flags);
-       return reg;
-}
-
-/* Set a phy register */
-static int smsc911x_mii_write(struct mii_bus *bus, int phyaddr, int regidx,
-                          u16 val)
-{
-       struct smsc911x_data *pdata = (struct smsc911x_data *)bus->priv;
-       unsigned long flags;
-       unsigned int addr;
-       int i, reg;
-
-       spin_lock_irqsave(&pdata->mac_lock, flags);
-
-       /* Confirm MII not busy */
-       if (unlikely(smsc911x_mac_read(pdata, MII_ACC) & MII_ACC_MII_BUSY_)) {
-               SMSC_WARN(pdata, hw, "MII is busy in smsc911x_mii_write???");
-               reg = -EIO;
-               goto out;
-       }
-
-       /* Put the data to write in the MAC */
-       smsc911x_mac_write(pdata, MII_DATA, val);
-
-       /* Set the address, index & direction (write to PHY) */
-       addr = ((phyaddr & 0x1F) << 11) | ((regidx & 0x1F) << 6) |
-               MII_ACC_MII_WRITE_;
-       smsc911x_mac_write(pdata, MII_ACC, addr);
-
-       /* Wait for write to complete w/ timeout */
-       for (i = 0; i < 100; i++)
-               if (!(smsc911x_mac_read(pdata, MII_ACC) & MII_ACC_MII_BUSY_)) {
-                       reg = 0;
-                       goto out;
-               }
-
-       SMSC_WARN(pdata, hw, "Timed out waiting for MII write to finish");
-       reg = -EIO;
-
-out:
-       spin_unlock_irqrestore(&pdata->mac_lock, flags);
-       return reg;
-}
-
-/* Switch to external phy. Assumes tx and rx are stopped. */
-static void smsc911x_phy_enable_external(struct smsc911x_data *pdata)
-{
-       unsigned int hwcfg = smsc911x_reg_read(pdata, HW_CFG);
-
-       /* Disable phy clocks to the MAC */
-       hwcfg &= (~HW_CFG_PHY_CLK_SEL_);
-       hwcfg |= HW_CFG_PHY_CLK_SEL_CLK_DIS_;
-       smsc911x_reg_write(pdata, HW_CFG, hwcfg);
-       udelay(10);     /* Enough time for clocks to stop */
-
-       /* Switch to external phy */
-       hwcfg |= HW_CFG_EXT_PHY_EN_;
-       smsc911x_reg_write(pdata, HW_CFG, hwcfg);
-
-       /* Enable phy clocks to the MAC */
-       hwcfg &= (~HW_CFG_PHY_CLK_SEL_);
-       hwcfg |= HW_CFG_PHY_CLK_SEL_EXT_PHY_;
-       smsc911x_reg_write(pdata, HW_CFG, hwcfg);
-       udelay(10);     /* Enough time for clocks to restart */
-
-       hwcfg |= HW_CFG_SMI_SEL_;
-       smsc911x_reg_write(pdata, HW_CFG, hwcfg);
-}
-
-/* Autodetects and enables external phy if present on supported chips.
- * autodetection can be overridden by specifying SMSC911X_FORCE_INTERNAL_PHY
- * or SMSC911X_FORCE_EXTERNAL_PHY in the platform_data flags. */
-static void smsc911x_phy_initialise_external(struct smsc911x_data *pdata)
-{
-       unsigned int hwcfg = smsc911x_reg_read(pdata, HW_CFG);
-
-       if (pdata->config.flags & SMSC911X_FORCE_INTERNAL_PHY) {
-               SMSC_TRACE(pdata, hw, "Forcing internal PHY");
-               pdata->using_extphy = 0;
-       } else if (pdata->config.flags & SMSC911X_FORCE_EXTERNAL_PHY) {
-               SMSC_TRACE(pdata, hw, "Forcing external PHY");
-               smsc911x_phy_enable_external(pdata);
-               pdata->using_extphy = 1;
-       } else if (hwcfg & HW_CFG_EXT_PHY_DET_) {
-               SMSC_TRACE(pdata, hw,
-                          "HW_CFG EXT_PHY_DET set, using external PHY");
-               smsc911x_phy_enable_external(pdata);
-               pdata->using_extphy = 1;
-       } else {
-               SMSC_TRACE(pdata, hw,
-                          "HW_CFG EXT_PHY_DET clear, using internal PHY");
-               pdata->using_extphy = 0;
-       }
-}
-
-/* Fetches a tx status out of the status fifo */
-static unsigned int smsc911x_tx_get_txstatus(struct smsc911x_data *pdata)
-{
-       unsigned int result =
-           smsc911x_reg_read(pdata, TX_FIFO_INF) & TX_FIFO_INF_TSUSED_;
-
-       if (result != 0)
-               result = smsc911x_reg_read(pdata, TX_STATUS_FIFO);
-
-       return result;
-}
-
-/* Fetches the next rx status */
-static unsigned int smsc911x_rx_get_rxstatus(struct smsc911x_data *pdata)
-{
-       unsigned int result =
-           smsc911x_reg_read(pdata, RX_FIFO_INF) & RX_FIFO_INF_RXSUSED_;
-
-       if (result != 0)
-               result = smsc911x_reg_read(pdata, RX_STATUS_FIFO);
-
-       return result;
-}
-
-#ifdef USE_PHY_WORK_AROUND
-static int smsc911x_phy_check_loopbackpkt(struct smsc911x_data *pdata)
-{
-       unsigned int tries;
-       u32 wrsz;
-       u32 rdsz;
-       ulong bufp;
-
-       for (tries = 0; tries < 10; tries++) {
-               unsigned int txcmd_a;
-               unsigned int txcmd_b;
-               unsigned int status;
-               unsigned int pktlength;
-               unsigned int i;
-
-               /* Zero-out rx packet memory */
-               memset(pdata->loopback_rx_pkt, 0, MIN_PACKET_SIZE);
-
-               /* Write tx packet to 118 */
-               txcmd_a = (u32)((ulong)pdata->loopback_tx_pkt & 0x03) << 16;
-               txcmd_a |= TX_CMD_A_FIRST_SEG_ | TX_CMD_A_LAST_SEG_;
-               txcmd_a |= MIN_PACKET_SIZE;
-
-               txcmd_b = MIN_PACKET_SIZE << 16 | MIN_PACKET_SIZE;
-
-               smsc911x_reg_write(pdata, TX_DATA_FIFO, txcmd_a);
-               smsc911x_reg_write(pdata, TX_DATA_FIFO, txcmd_b);
-
-               bufp = (ulong)pdata->loopback_tx_pkt & (~0x3);
-               wrsz = MIN_PACKET_SIZE + 3;
-               wrsz += (u32)((ulong)pdata->loopback_tx_pkt & 0x3);
-               wrsz >>= 2;
-
-               pdata->ops->tx_writefifo(pdata, (unsigned int *)bufp, wrsz);
-
-               /* Wait till transmit is done */
-               i = 60;
-               do {
-                       udelay(5);
-                       status = smsc911x_tx_get_txstatus(pdata);
-               } while ((i--) && (!status));
-
-               if (!status) {
-                       SMSC_WARN(pdata, hw,
-                                 "Failed to transmit during loopback test");
-                       continue;
-               }
-               if (status & TX_STS_ES_) {
-                       SMSC_WARN(pdata, hw,
-                                 "Transmit encountered errors during loopback test");
-                       continue;
-               }
-
-               /* Wait till receive is done */
-               i = 60;
-               do {
-                       udelay(5);
-                       status = smsc911x_rx_get_rxstatus(pdata);
-               } while ((i--) && (!status));
-
-               if (!status) {
-                       SMSC_WARN(pdata, hw,
-                                 "Failed to receive during loopback test");
-                       continue;
-               }
-               if (status & RX_STS_ES_) {
-                       SMSC_WARN(pdata, hw,
-                                 "Receive encountered errors during loopback test");
-                       continue;
-               }
-
-               pktlength = ((status & 0x3FFF0000UL) >> 16);
-               bufp = (ulong)pdata->loopback_rx_pkt;
-               rdsz = pktlength + 3;
-               rdsz += (u32)((ulong)pdata->loopback_rx_pkt & 0x3);
-               rdsz >>= 2;
-
-               pdata->ops->rx_readfifo(pdata, (unsigned int *)bufp, rdsz);
-
-               if (pktlength != (MIN_PACKET_SIZE + 4)) {
-                       SMSC_WARN(pdata, hw, "Unexpected packet size "
-                                 "during loop back test, size=%d, will retry",
-                                 pktlength);
-               } else {
-                       unsigned int j;
-                       int mismatch = 0;
-                       for (j = 0; j < MIN_PACKET_SIZE; j++) {
-                               if (pdata->loopback_tx_pkt[j]
-                                   != pdata->loopback_rx_pkt[j]) {
-                                       mismatch = 1;
-                                       break;
-                               }
-                       }
-                       if (!mismatch) {
-                               SMSC_TRACE(pdata, hw, "Successfully verified "
-                                          "loopback packet");
-                               return 0;
-                       } else {
-                               SMSC_WARN(pdata, hw, "Data mismatch "
-                                         "during loop back test, will retry");
-                       }
-               }
-       }
-
-       return -EIO;
-}
-
-static int smsc911x_phy_reset(struct smsc911x_data *pdata)
-{
-       struct phy_device *phy_dev = pdata->phy_dev;
-       unsigned int temp;
-       unsigned int i = 100000;
-
-       BUG_ON(!phy_dev);
-       BUG_ON(!phy_dev->bus);
-
-       SMSC_TRACE(pdata, hw, "Performing PHY BCR Reset");
-       smsc911x_mii_write(phy_dev->bus, phy_dev->addr, MII_BMCR, BMCR_RESET);
-       do {
-               msleep(1);
-               temp = smsc911x_mii_read(phy_dev->bus, phy_dev->addr,
-                       MII_BMCR);
-       } while ((i--) && (temp & BMCR_RESET));
-
-       if (temp & BMCR_RESET) {
-               SMSC_WARN(pdata, hw, "PHY reset failed to complete");
-               return -EIO;
-       }
-       /* Extra delay required because the phy may not be completed with
-       * its reset when BMCR_RESET is cleared. Specs say 256 uS is
-       * enough delay but using 1ms here to be safe */
-       msleep(1);
-
-       return 0;
-}
-
-static int smsc911x_phy_loopbacktest(struct net_device *dev)
-{
-       struct smsc911x_data *pdata = netdev_priv(dev);
-       struct phy_device *phy_dev = pdata->phy_dev;
-       int result = -EIO;
-       unsigned int i, val;
-       unsigned long flags;
-
-       /* Initialise tx packet using broadcast destination address */
-       memset(pdata->loopback_tx_pkt, 0xff, ETH_ALEN);
-
-       /* Use incrementing source address */
-       for (i = 6; i < 12; i++)
-               pdata->loopback_tx_pkt[i] = (char)i;
-
-       /* Set length type field */
-       pdata->loopback_tx_pkt[12] = 0x00;
-       pdata->loopback_tx_pkt[13] = 0x00;
-
-       for (i = 14; i < MIN_PACKET_SIZE; i++)
-               pdata->loopback_tx_pkt[i] = (char)i;
-
-       val = smsc911x_reg_read(pdata, HW_CFG);
-       val &= HW_CFG_TX_FIF_SZ_;
-       val |= HW_CFG_SF_;
-       smsc911x_reg_write(pdata, HW_CFG, val);
-
-       smsc911x_reg_write(pdata, TX_CFG, TX_CFG_TX_ON_);
-       smsc911x_reg_write(pdata, RX_CFG,
-               (u32)((ulong)pdata->loopback_rx_pkt & 0x03) << 8);
-
-       for (i = 0; i < 10; i++) {
-               /* Set PHY to 10/FD, no ANEG, and loopback mode */
-               smsc911x_mii_write(phy_dev->bus, phy_dev->addr, MII_BMCR,
-                       BMCR_LOOPBACK | BMCR_FULLDPLX);
-
-               /* Enable MAC tx/rx, FD */
-               spin_lock_irqsave(&pdata->mac_lock, flags);
-               smsc911x_mac_write(pdata, MAC_CR, MAC_CR_FDPX_
-                                  | MAC_CR_TXEN_ | MAC_CR_RXEN_);
-               spin_unlock_irqrestore(&pdata->mac_lock, flags);
-
-               if (smsc911x_phy_check_loopbackpkt(pdata) == 0) {
-                       result = 0;
-                       break;
-               }
-               pdata->resetcount++;
-
-               /* Disable MAC rx */
-               spin_lock_irqsave(&pdata->mac_lock, flags);
-               smsc911x_mac_write(pdata, MAC_CR, 0);
-               spin_unlock_irqrestore(&pdata->mac_lock, flags);
-
-               smsc911x_phy_reset(pdata);
-       }
-
-       /* Disable MAC */
-       spin_lock_irqsave(&pdata->mac_lock, flags);
-       smsc911x_mac_write(pdata, MAC_CR, 0);
-       spin_unlock_irqrestore(&pdata->mac_lock, flags);
-
-       /* Cancel PHY loopback mode */
-       smsc911x_mii_write(phy_dev->bus, phy_dev->addr, MII_BMCR, 0);
-
-       smsc911x_reg_write(pdata, TX_CFG, 0);
-       smsc911x_reg_write(pdata, RX_CFG, 0);
-
-       return result;
-}
-#endif                         /* USE_PHY_WORK_AROUND */
-
-static void smsc911x_phy_update_flowcontrol(struct smsc911x_data *pdata)
-{
-       struct phy_device *phy_dev = pdata->phy_dev;
-       u32 afc = smsc911x_reg_read(pdata, AFC_CFG);
-       u32 flow;
-       unsigned long flags;
-
-       if (phy_dev->duplex == DUPLEX_FULL) {
-               u16 lcladv = phy_read(phy_dev, MII_ADVERTISE);
-               u16 rmtadv = phy_read(phy_dev, MII_LPA);
-               u8 cap = mii_resolve_flowctrl_fdx(lcladv, rmtadv);
-
-               if (cap & FLOW_CTRL_RX)
-                       flow = 0xFFFF0002;
-               else
-                       flow = 0;
-
-               if (cap & FLOW_CTRL_TX)
-                       afc |= 0xF;
-               else
-                       afc &= ~0xF;
-
-               SMSC_TRACE(pdata, hw, "rx pause %s, tx pause %s",
-                          (cap & FLOW_CTRL_RX ? "enabled" : "disabled"),
-                          (cap & FLOW_CTRL_TX ? "enabled" : "disabled"));
-       } else {
-               SMSC_TRACE(pdata, hw, "half duplex");
-               flow = 0;
-               afc |= 0xF;
-       }
-
-       spin_lock_irqsave(&pdata->mac_lock, flags);
-       smsc911x_mac_write(pdata, FLOW, flow);
-       spin_unlock_irqrestore(&pdata->mac_lock, flags);
-
-       smsc911x_reg_write(pdata, AFC_CFG, afc);
-}
-
-/* Update link mode if anything has changed.  Called periodically when the
- * PHY is in polling mode, even if nothing has changed. */
-static void smsc911x_phy_adjust_link(struct net_device *dev)
-{
-       struct smsc911x_data *pdata = netdev_priv(dev);
-       struct phy_device *phy_dev = pdata->phy_dev;
-       unsigned long flags;
-       int carrier;
-
-       if (phy_dev->duplex != pdata->last_duplex) {
-               unsigned int mac_cr;
-               SMSC_TRACE(pdata, hw, "duplex state has changed");
-
-               spin_lock_irqsave(&pdata->mac_lock, flags);
-               mac_cr = smsc911x_mac_read(pdata, MAC_CR);
-               if (phy_dev->duplex) {
-                       SMSC_TRACE(pdata, hw,
-                                  "configuring for full duplex mode");
-                       mac_cr |= MAC_CR_FDPX_;
-               } else {
-                       SMSC_TRACE(pdata, hw,
-                                  "configuring for half duplex mode");
-                       mac_cr &= ~MAC_CR_FDPX_;
-               }
-               smsc911x_mac_write(pdata, MAC_CR, mac_cr);
-               spin_unlock_irqrestore(&pdata->mac_lock, flags);
-
-               smsc911x_phy_update_flowcontrol(pdata);
-               pdata->last_duplex = phy_dev->duplex;
-       }
-
-       carrier = netif_carrier_ok(dev);
-       if (carrier != pdata->last_carrier) {
-               SMSC_TRACE(pdata, hw, "carrier state has changed");
-               if (carrier) {
-                       SMSC_TRACE(pdata, hw, "configuring for carrier OK");
-                       if ((pdata->gpio_orig_setting & GPIO_CFG_LED1_EN_) &&
-                           (!pdata->using_extphy)) {
-                               /* Restore original GPIO configuration */
-                               pdata->gpio_setting = pdata->gpio_orig_setting;
-                               smsc911x_reg_write(pdata, GPIO_CFG,
-                                       pdata->gpio_setting);
-                       }
-               } else {
-                       SMSC_TRACE(pdata, hw, "configuring for no carrier");
-                       /* Check global setting that LED1
-                        * usage is 10/100 indicator */
-                       pdata->gpio_setting = smsc911x_reg_read(pdata,
-                               GPIO_CFG);
-                       if ((pdata->gpio_setting & GPIO_CFG_LED1_EN_) &&
-                           (!pdata->using_extphy)) {
-                               /* Force 10/100 LED off, after saving
-                                * original GPIO configuration */
-                               pdata->gpio_orig_setting = pdata->gpio_setting;
-
-                               pdata->gpio_setting &= ~GPIO_CFG_LED1_EN_;
-                               pdata->gpio_setting |= (GPIO_CFG_GPIOBUF0_
-                                                       | GPIO_CFG_GPIODIR0_
-                                                       | GPIO_CFG_GPIOD0_);
-                               smsc911x_reg_write(pdata, GPIO_CFG,
-                                       pdata->gpio_setting);
-                       }
-               }
-               pdata->last_carrier = carrier;
-       }
-}
-
-static int smsc911x_mii_probe(struct net_device *dev)
-{
-       struct smsc911x_data *pdata = netdev_priv(dev);
-       struct phy_device *phydev = NULL;
-       int ret;
-
-       /* find the first phy */
-       phydev = phy_find_first(pdata->mii_bus);
-       if (!phydev) {
-               netdev_err(dev, "no PHY found\n");
-               return -ENODEV;
-       }
-
-       SMSC_TRACE(pdata, probe, "PHY: addr %d, phy_id 0x%08X",
-                  phydev->addr, phydev->phy_id);
-
-       ret = phy_connect_direct(dev, phydev,
-                       &smsc911x_phy_adjust_link, 0,
-                       pdata->config.phy_interface);
-
-       if (ret) {
-               netdev_err(dev, "Could not attach to PHY\n");
-               return ret;
-       }
-
-       netdev_info(dev,
-                   "attached PHY driver [%s] (mii_bus:phy_addr=%s, irq=%d)\n",
-                   phydev->drv->name, dev_name(&phydev->dev), phydev->irq);
-
-       /* mask with MAC supported features */
-       phydev->supported &= (PHY_BASIC_FEATURES | SUPPORTED_Pause |
-                             SUPPORTED_Asym_Pause);
-       phydev->advertising = phydev->supported;
-
-       pdata->phy_dev = phydev;
-       pdata->last_duplex = -1;
-       pdata->last_carrier = -1;
-
-#ifdef USE_PHY_WORK_AROUND
-       if (smsc911x_phy_loopbacktest(dev) < 0) {
-               SMSC_WARN(pdata, hw, "Failed Loop Back Test");
-               return -ENODEV;
-       }
-       SMSC_TRACE(pdata, hw, "Passed Loop Back Test");
-#endif                         /* USE_PHY_WORK_AROUND */
-
-       SMSC_TRACE(pdata, hw, "phy initialised successfully");
-       return 0;
-}
-
-static int __devinit smsc911x_mii_init(struct platform_device *pdev,
-                                      struct net_device *dev)
-{
-       struct smsc911x_data *pdata = netdev_priv(dev);
-       int err = -ENXIO, i;
-
-       pdata->mii_bus = mdiobus_alloc();
-       if (!pdata->mii_bus) {
-               err = -ENOMEM;
-               goto err_out_1;
-       }
-
-       pdata->mii_bus->name = SMSC_MDIONAME;
-       snprintf(pdata->mii_bus->id, MII_BUS_ID_SIZE, "%x", pdev->id);
-       pdata->mii_bus->priv = pdata;
-       pdata->mii_bus->read = smsc911x_mii_read;
-       pdata->mii_bus->write = smsc911x_mii_write;
-       pdata->mii_bus->irq = pdata->phy_irq;
-       for (i = 0; i < PHY_MAX_ADDR; ++i)
-               pdata->mii_bus->irq[i] = PHY_POLL;
-
-       pdata->mii_bus->parent = &pdev->dev;
-
-       switch (pdata->idrev & 0xFFFF0000) {
-       case 0x01170000:
-       case 0x01150000:
-       case 0x117A0000:
-       case 0x115A0000:
-               /* External PHY supported, try to autodetect */
-               smsc911x_phy_initialise_external(pdata);
-               break;
-       default:
-               SMSC_TRACE(pdata, hw, "External PHY is not supported, "
-                          "using internal PHY");
-               pdata->using_extphy = 0;
-               break;
-       }
-
-       if (!pdata->using_extphy) {
-               /* Mask all PHYs except ID 1 (internal) */
-               pdata->mii_bus->phy_mask = ~(1 << 1);
-       }
-
-       if (mdiobus_register(pdata->mii_bus)) {
-               SMSC_WARN(pdata, probe, "Error registering mii bus");
-               goto err_out_free_bus_2;
-       }
-
-       if (smsc911x_mii_probe(dev) < 0) {
-               SMSC_WARN(pdata, probe, "Error registering mii bus");
-               goto err_out_unregister_bus_3;
-       }
-
-       return 0;
-
-err_out_unregister_bus_3:
-       mdiobus_unregister(pdata->mii_bus);
-err_out_free_bus_2:
-       mdiobus_free(pdata->mii_bus);
-err_out_1:
-       return err;
-}
-
-/* Gets the number of tx statuses in the fifo */
-static unsigned int smsc911x_tx_get_txstatcount(struct smsc911x_data *pdata)
-{
-       return (smsc911x_reg_read(pdata, TX_FIFO_INF)
-               & TX_FIFO_INF_TSUSED_) >> 16;
-}
-
-/* Reads tx statuses and increments counters where necessary */
-static void smsc911x_tx_update_txcounters(struct net_device *dev)
-{
-       struct smsc911x_data *pdata = netdev_priv(dev);
-       unsigned int tx_stat;
-
-       while ((tx_stat = smsc911x_tx_get_txstatus(pdata)) != 0) {
-               if (unlikely(tx_stat & 0x80000000)) {
-                       /* In this driver the packet tag is used as the packet
-                        * length. Since a packet length can never reach the
-                        * size of 0x8000, this bit is reserved. It is worth
-                        * noting that the "reserved bit" in the warning above
-                        * does not reference a hardware defined reserved bit
-                        * but rather a driver defined one.
-                        */
-                       SMSC_WARN(pdata, hw, "Packet tag reserved bit is high");
-               } else {
-                       if (unlikely(tx_stat & TX_STS_ES_)) {
-                               dev->stats.tx_errors++;
-                       } else {
-                               dev->stats.tx_packets++;
-                               dev->stats.tx_bytes += (tx_stat >> 16);
-                       }
-                       if (unlikely(tx_stat & TX_STS_EXCESS_COL_)) {
-                               dev->stats.collisions += 16;
-                               dev->stats.tx_aborted_errors += 1;
-                       } else {
-                               dev->stats.collisions +=
-                                   ((tx_stat >> 3) & 0xF);
-                       }
-                       if (unlikely(tx_stat & TX_STS_LOST_CARRIER_))
-                               dev->stats.tx_carrier_errors += 1;
-                       if (unlikely(tx_stat & TX_STS_LATE_COL_)) {
-                               dev->stats.collisions++;
-                               dev->stats.tx_aborted_errors++;
-                       }
-               }
-       }
-}
-
-/* Increments the Rx error counters */
-static void
-smsc911x_rx_counterrors(struct net_device *dev, unsigned int rxstat)
-{
-       int crc_err = 0;
-
-       if (unlikely(rxstat & RX_STS_ES_)) {
-               dev->stats.rx_errors++;
-               if (unlikely(rxstat & RX_STS_CRC_ERR_)) {
-                       dev->stats.rx_crc_errors++;
-                       crc_err = 1;
-               }
-       }
-       if (likely(!crc_err)) {
-               if (unlikely((rxstat & RX_STS_FRAME_TYPE_) &&
-                            (rxstat & RX_STS_LENGTH_ERR_)))
-                       dev->stats.rx_length_errors++;
-               if (rxstat & RX_STS_MCAST_)
-                       dev->stats.multicast++;
-       }
-}
-
-/* Quickly dumps bad packets */
-static void
-smsc911x_rx_fastforward(struct smsc911x_data *pdata, unsigned int pktbytes)
-{
-       unsigned int pktwords = (pktbytes + NET_IP_ALIGN + 3) >> 2;
-
-       if (likely(pktwords >= 4)) {
-               unsigned int timeout = 500;
-               unsigned int val;
-               smsc911x_reg_write(pdata, RX_DP_CTRL, RX_DP_CTRL_RX_FFWD_);
-               do {
-                       udelay(1);
-                       val = smsc911x_reg_read(pdata, RX_DP_CTRL);
-               } while ((val & RX_DP_CTRL_RX_FFWD_) && --timeout);
-
-               if (unlikely(timeout == 0))
-                       SMSC_WARN(pdata, hw, "Timed out waiting for "
-                                 "RX FFWD to finish, RX_DP_CTRL: 0x%08X", val);
-       } else {
-               unsigned int temp;
-               while (pktwords--)
-                       temp = smsc911x_reg_read(pdata, RX_DATA_FIFO);
-       }
-}
-
-/* NAPI poll function */
-static int smsc911x_poll(struct napi_struct *napi, int budget)
-{
-       struct smsc911x_data *pdata =
-               container_of(napi, struct smsc911x_data, napi);
-       struct net_device *dev = pdata->dev;
-       int npackets = 0;
-
-       while (npackets < budget) {
-               unsigned int pktlength;
-               unsigned int pktwords;
-               struct sk_buff *skb;
-               unsigned int rxstat = smsc911x_rx_get_rxstatus(pdata);
-
-               if (!rxstat) {
-                       unsigned int temp;
-                       /* We processed all packets available.  Tell NAPI it can
-                        * stop polling then re-enable rx interrupts */
-                       smsc911x_reg_write(pdata, INT_STS, INT_STS_RSFL_);
-                       napi_complete(napi);
-                       temp = smsc911x_reg_read(pdata, INT_EN);
-                       temp |= INT_EN_RSFL_EN_;
-                       smsc911x_reg_write(pdata, INT_EN, temp);
-                       break;
-               }
-
-               /* Count packet for NAPI scheduling, even if it has an error.
-                * Error packets still require cycles to discard */
-               npackets++;
-
-               pktlength = ((rxstat & 0x3FFF0000) >> 16);
-               pktwords = (pktlength + NET_IP_ALIGN + 3) >> 2;
-               smsc911x_rx_counterrors(dev, rxstat);
-
-               if (unlikely(rxstat & RX_STS_ES_)) {
-                       SMSC_WARN(pdata, rx_err,
-                                 "Discarding packet with error bit set");
-                       /* Packet has an error, discard it and continue with
-                        * the next */
-                       smsc911x_rx_fastforward(pdata, pktwords);
-                       dev->stats.rx_dropped++;
-                       continue;
-               }
-
-               skb = netdev_alloc_skb(dev, pktlength + NET_IP_ALIGN);
-               if (unlikely(!skb)) {
-                       SMSC_WARN(pdata, rx_err,
-                                 "Unable to allocate skb for rx packet");
-                       /* Drop the packet and stop this polling iteration */
-                       smsc911x_rx_fastforward(pdata, pktwords);
-                       dev->stats.rx_dropped++;
-                       break;
-               }
-
-               skb->data = skb->head;
-               skb_reset_tail_pointer(skb);
-
-               /* Align IP on 16B boundary */
-               skb_reserve(skb, NET_IP_ALIGN);
-               skb_put(skb, pktlength - 4);
-               pdata->ops->rx_readfifo(pdata,
-                                (unsigned int *)skb->head, pktwords);
-               skb->protocol = eth_type_trans(skb, dev);
-               skb_checksum_none_assert(skb);
-               netif_receive_skb(skb);
-
-               /* Update counters */
-               dev->stats.rx_packets++;
-               dev->stats.rx_bytes += (pktlength - 4);
-       }
-
-       /* Return total received packets */
-       return npackets;
-}
-
-/* Returns hash bit number for given MAC address
- * Example:
- * 01 00 5E 00 00 01 -> returns bit number 31 */
-static unsigned int smsc911x_hash(char addr[ETH_ALEN])
-{
-       return (ether_crc(ETH_ALEN, addr) >> 26) & 0x3f;
-}
-
-static void smsc911x_rx_multicast_update(struct smsc911x_data *pdata)
-{
-       /* Performs the multicast & mac_cr update.  This is called when
-        * safe on the current hardware, and with the mac_lock held */
-       unsigned int mac_cr;
-
-       SMSC_ASSERT_MAC_LOCK(pdata);
-
-       mac_cr = smsc911x_mac_read(pdata, MAC_CR);
-       mac_cr |= pdata->set_bits_mask;
-       mac_cr &= ~(pdata->clear_bits_mask);
-       smsc911x_mac_write(pdata, MAC_CR, mac_cr);
-       smsc911x_mac_write(pdata, HASHH, pdata->hashhi);
-       smsc911x_mac_write(pdata, HASHL, pdata->hashlo);
-       SMSC_TRACE(pdata, hw, "maccr 0x%08X, HASHH 0x%08X, HASHL 0x%08X",
-                  mac_cr, pdata->hashhi, pdata->hashlo);
-}
-
-static void smsc911x_rx_multicast_update_workaround(struct smsc911x_data *pdata)
-{
-       unsigned int mac_cr;
-
-       /* This function is only called for older LAN911x devices
-        * (revA or revB), where MAC_CR, HASHH and HASHL should not
-        * be modified during Rx - newer devices immediately update the
-        * registers.
-        *
-        * This is called from interrupt context */
-
-       spin_lock(&pdata->mac_lock);
-
-       /* Check Rx has stopped */
-       if (smsc911x_mac_read(pdata, MAC_CR) & MAC_CR_RXEN_)
-               SMSC_WARN(pdata, drv, "Rx not stopped");
-
-       /* Perform the update - safe to do now Rx has stopped */
-       smsc911x_rx_multicast_update(pdata);
-
-       /* Re-enable Rx */
-       mac_cr = smsc911x_mac_read(pdata, MAC_CR);
-       mac_cr |= MAC_CR_RXEN_;
-       smsc911x_mac_write(pdata, MAC_CR, mac_cr);
-
-       pdata->multicast_update_pending = 0;
-
-       spin_unlock(&pdata->mac_lock);
-}
-
-static int smsc911x_soft_reset(struct smsc911x_data *pdata)
-{
-       unsigned int timeout;
-       unsigned int temp;
-
-       /* Reset the LAN911x */
-       smsc911x_reg_write(pdata, HW_CFG, HW_CFG_SRST_);
-       timeout = 10;
-       do {
-               udelay(10);
-               temp = smsc911x_reg_read(pdata, HW_CFG);
-       } while ((--timeout) && (temp & HW_CFG_SRST_));
-
-       if (unlikely(temp & HW_CFG_SRST_)) {
-               SMSC_WARN(pdata, drv, "Failed to complete reset");
-               return -EIO;
-       }
-       return 0;
-}
-
-/* Sets the device MAC address to dev_addr, called with mac_lock held */
-static void
-smsc911x_set_hw_mac_address(struct smsc911x_data *pdata, u8 dev_addr[6])
-{
-       u32 mac_high16 = (dev_addr[5] << 8) | dev_addr[4];
-       u32 mac_low32 = (dev_addr[3] << 24) | (dev_addr[2] << 16) |
-           (dev_addr[1] << 8) | dev_addr[0];
-
-       SMSC_ASSERT_MAC_LOCK(pdata);
-
-       smsc911x_mac_write(pdata, ADDRH, mac_high16);
-       smsc911x_mac_write(pdata, ADDRL, mac_low32);
-}
-
-static int smsc911x_open(struct net_device *dev)
-{
-       struct smsc911x_data *pdata = netdev_priv(dev);
-       unsigned int timeout;
-       unsigned int temp;
-       unsigned int intcfg;
-
-       /* if the phy is not yet registered, retry later*/
-       if (!pdata->phy_dev) {
-               SMSC_WARN(pdata, hw, "phy_dev is NULL");
-               return -EAGAIN;
-       }
-
-       if (!is_valid_ether_addr(dev->dev_addr)) {
-               SMSC_WARN(pdata, hw, "dev_addr is not a valid MAC address");
-               return -EADDRNOTAVAIL;
-       }
-
-       /* Reset the LAN911x */
-       if (smsc911x_soft_reset(pdata)) {
-               SMSC_WARN(pdata, hw, "soft reset failed");
-               return -EIO;
-       }
-
-       smsc911x_reg_write(pdata, HW_CFG, 0x00050000);
-       smsc911x_reg_write(pdata, AFC_CFG, 0x006E3740);
-
-       /* Increase the legal frame size of VLAN tagged frames to 1522 bytes */
-       spin_lock_irq(&pdata->mac_lock);
-       smsc911x_mac_write(pdata, VLAN1, ETH_P_8021Q);
-       spin_unlock_irq(&pdata->mac_lock);
-
-       /* Make sure EEPROM has finished loading before setting GPIO_CFG */
-       timeout = 50;
-       while ((smsc911x_reg_read(pdata, E2P_CMD) & E2P_CMD_EPC_BUSY_) &&
-              --timeout) {
-               udelay(10);
-       }
-
-       if (unlikely(timeout == 0))
-               SMSC_WARN(pdata, ifup,
-                         "Timed out waiting for EEPROM busy bit to clear");
-
-       smsc911x_reg_write(pdata, GPIO_CFG, 0x70070000);
-
-       /* The soft reset above cleared the device's MAC address,
-        * restore it from local copy (set in probe) */
-       spin_lock_irq(&pdata->mac_lock);
-       smsc911x_set_hw_mac_address(pdata, dev->dev_addr);
-       spin_unlock_irq(&pdata->mac_lock);
-
-       /* Initialise irqs, but leave all sources disabled */
-       smsc911x_reg_write(pdata, INT_EN, 0);
-       smsc911x_reg_write(pdata, INT_STS, 0xFFFFFFFF);
-
-       /* Set interrupt deassertion to 100uS */
-       intcfg = ((10 << 24) | INT_CFG_IRQ_EN_);
-
-       if (pdata->config.irq_polarity) {
-               SMSC_TRACE(pdata, ifup, "irq polarity: active high");
-               intcfg |= INT_CFG_IRQ_POL_;
-       } else {
-               SMSC_TRACE(pdata, ifup, "irq polarity: active low");
-       }
-
-       if (pdata->config.irq_type) {
-               SMSC_TRACE(pdata, ifup, "irq type: push-pull");
-               intcfg |= INT_CFG_IRQ_TYPE_;
-       } else {
-               SMSC_TRACE(pdata, ifup, "irq type: open drain");
-       }
-
-       smsc911x_reg_write(pdata, INT_CFG, intcfg);
-
-       SMSC_TRACE(pdata, ifup, "Testing irq handler using IRQ %d", dev->irq);
-       pdata->software_irq_signal = 0;
-       smp_wmb();
-
-       temp = smsc911x_reg_read(pdata, INT_EN);
-       temp |= INT_EN_SW_INT_EN_;
-       smsc911x_reg_write(pdata, INT_EN, temp);
-
-       timeout = 1000;
-       while (timeout--) {
-               if (pdata->software_irq_signal)
-                       break;
-               msleep(1);
-       }
-
-       if (!pdata->software_irq_signal) {
-               netdev_warn(dev, "ISR failed signaling test (IRQ %d)\n",
-                           dev->irq);
-               return -ENODEV;
-       }
-       SMSC_TRACE(pdata, ifup, "IRQ handler passed test using IRQ %d",
-                  dev->irq);
-
-       netdev_info(dev, "SMSC911x/921x identified at %#08lx, IRQ: %d\n",
-                   (unsigned long)pdata->ioaddr, dev->irq);
-
-       /* Reset the last known duplex and carrier */
-       pdata->last_duplex = -1;
-       pdata->last_carrier = -1;
-
-       /* Bring the PHY up */
-       phy_start(pdata->phy_dev);
-
-       temp = smsc911x_reg_read(pdata, HW_CFG);
-       /* Preserve TX FIFO size and external PHY configuration */
-       temp &= (HW_CFG_TX_FIF_SZ_|0x00000FFF);
-       temp |= HW_CFG_SF_;
-       smsc911x_reg_write(pdata, HW_CFG, temp);
-
-       temp = smsc911x_reg_read(pdata, FIFO_INT);
-       temp |= FIFO_INT_TX_AVAIL_LEVEL_;
-       temp &= ~(FIFO_INT_RX_STS_LEVEL_);
-       smsc911x_reg_write(pdata, FIFO_INT, temp);
-
-       /* set RX Data offset to 2 bytes for alignment */
-       smsc911x_reg_write(pdata, RX_CFG, (2 << 8));
-
-       /* enable NAPI polling before enabling RX interrupts */
-       napi_enable(&pdata->napi);
-
-       temp = smsc911x_reg_read(pdata, INT_EN);
-       temp |= (INT_EN_TDFA_EN_ | INT_EN_RSFL_EN_ | INT_EN_RXSTOP_INT_EN_);
-       smsc911x_reg_write(pdata, INT_EN, temp);
-
-       spin_lock_irq(&pdata->mac_lock);
-       temp = smsc911x_mac_read(pdata, MAC_CR);
-       temp |= (MAC_CR_TXEN_ | MAC_CR_RXEN_ | MAC_CR_HBDIS_);
-       smsc911x_mac_write(pdata, MAC_CR, temp);
-       spin_unlock_irq(&pdata->mac_lock);
-
-       smsc911x_reg_write(pdata, TX_CFG, TX_CFG_TX_ON_);
-
-       netif_start_queue(dev);
-       return 0;
-}
-
-/* Entry point for stopping the interface */
-static int smsc911x_stop(struct net_device *dev)
-{
-       struct smsc911x_data *pdata = netdev_priv(dev);
-       unsigned int temp;
-
-       /* Disable all device interrupts */
-       temp = smsc911x_reg_read(pdata, INT_CFG);
-       temp &= ~INT_CFG_IRQ_EN_;
-       smsc911x_reg_write(pdata, INT_CFG, temp);
-
-       /* Stop Tx and Rx polling */
-       netif_stop_queue(dev);
-       napi_disable(&pdata->napi);
-
-       /* At this point all Rx and Tx activity is stopped */
-       dev->stats.rx_dropped += smsc911x_reg_read(pdata, RX_DROP);
-       smsc911x_tx_update_txcounters(dev);
-
-       /* Bring the PHY down */
-       if (pdata->phy_dev)
-               phy_stop(pdata->phy_dev);
-
-       SMSC_TRACE(pdata, ifdown, "Interface stopped");
-       return 0;
-}
-
-/* Entry point for transmitting a packet */
-static int smsc911x_hard_start_xmit(struct sk_buff *skb, struct net_device *dev)
-{
-       struct smsc911x_data *pdata = netdev_priv(dev);
-       unsigned int freespace;
-       unsigned int tx_cmd_a;
-       unsigned int tx_cmd_b;
-       unsigned int temp;
-       u32 wrsz;
-       ulong bufp;
-
-       freespace = smsc911x_reg_read(pdata, TX_FIFO_INF) & TX_FIFO_INF_TDFREE_;
-
-       if (unlikely(freespace < TX_FIFO_LOW_THRESHOLD))
-               SMSC_WARN(pdata, tx_err,
-                         "Tx data fifo low, space available: %d", freespace);
-
-       /* Word alignment adjustment */
-       tx_cmd_a = (u32)((ulong)skb->data & 0x03) << 16;
-       tx_cmd_a |= TX_CMD_A_FIRST_SEG_ | TX_CMD_A_LAST_SEG_;
-       tx_cmd_a |= (unsigned int)skb->len;
-
-       tx_cmd_b = ((unsigned int)skb->len) << 16;
-       tx_cmd_b |= (unsigned int)skb->len;
-
-       smsc911x_reg_write(pdata, TX_DATA_FIFO, tx_cmd_a);
-       smsc911x_reg_write(pdata, TX_DATA_FIFO, tx_cmd_b);
-
-       bufp = (ulong)skb->data & (~0x3);
-       wrsz = (u32)skb->len + 3;
-       wrsz += (u32)((ulong)skb->data & 0x3);
-       wrsz >>= 2;
-
-       pdata->ops->tx_writefifo(pdata, (unsigned int *)bufp, wrsz);
-       freespace -= (skb->len + 32);
-       skb_tx_timestamp(skb);
-       dev_kfree_skb(skb);
-
-       if (unlikely(smsc911x_tx_get_txstatcount(pdata) >= 30))
-               smsc911x_tx_update_txcounters(dev);
-
-       if (freespace < TX_FIFO_LOW_THRESHOLD) {
-               netif_stop_queue(dev);
-               temp = smsc911x_reg_read(pdata, FIFO_INT);
-               temp &= 0x00FFFFFF;
-               temp |= 0x32000000;
-               smsc911x_reg_write(pdata, FIFO_INT, temp);
-       }
-
-       return NETDEV_TX_OK;
-}
-
-/* Entry point for getting status counters */
-static struct net_device_stats *smsc911x_get_stats(struct net_device *dev)
-{
-       struct smsc911x_data *pdata = netdev_priv(dev);
-       smsc911x_tx_update_txcounters(dev);
-       dev->stats.rx_dropped += smsc911x_reg_read(pdata, RX_DROP);
-       return &dev->stats;
-}
-
-/* Entry point for setting addressing modes */
-static void smsc911x_set_multicast_list(struct net_device *dev)
-{
-       struct smsc911x_data *pdata = netdev_priv(dev);
-       unsigned long flags;
-
-       if (dev->flags & IFF_PROMISC) {
-               /* Enabling promiscuous mode */
-               pdata->set_bits_mask = MAC_CR_PRMS_;
-               pdata->clear_bits_mask = (MAC_CR_MCPAS_ | MAC_CR_HPFILT_);
-               pdata->hashhi = 0;
-               pdata->hashlo = 0;
-       } else if (dev->flags & IFF_ALLMULTI) {
-               /* Enabling all multicast mode */
-               pdata->set_bits_mask = MAC_CR_MCPAS_;
-               pdata->clear_bits_mask = (MAC_CR_PRMS_ | MAC_CR_HPFILT_);
-               pdata->hashhi = 0;
-               pdata->hashlo = 0;
-       } else if (!netdev_mc_empty(dev)) {
-               /* Enabling specific multicast addresses */
-               unsigned int hash_high = 0;
-               unsigned int hash_low = 0;
-               struct netdev_hw_addr *ha;
-
-               pdata->set_bits_mask = MAC_CR_HPFILT_;
-               pdata->clear_bits_mask = (MAC_CR_PRMS_ | MAC_CR_MCPAS_);
-
-               netdev_for_each_mc_addr(ha, dev) {
-                       unsigned int bitnum = smsc911x_hash(ha->addr);
-                       unsigned int mask = 0x01 << (bitnum & 0x1F);
-
-                       if (bitnum & 0x20)
-                               hash_high |= mask;
-                       else
-                               hash_low |= mask;
-               }
-
-               pdata->hashhi = hash_high;
-               pdata->hashlo = hash_low;
-       } else {
-               /* Enabling local MAC address only */
-               pdata->set_bits_mask = 0;
-               pdata->clear_bits_mask =
-                   (MAC_CR_PRMS_ | MAC_CR_MCPAS_ | MAC_CR_HPFILT_);
-               pdata->hashhi = 0;
-               pdata->hashlo = 0;
-       }
-
-       spin_lock_irqsave(&pdata->mac_lock, flags);
-
-       if (pdata->generation <= 1) {
-               /* Older hardware revision - cannot change these flags while
-                * receiving data */
-               if (!pdata->multicast_update_pending) {
-                       unsigned int temp;
-                       SMSC_TRACE(pdata, hw, "scheduling mcast update");
-                       pdata->multicast_update_pending = 1;
-
-                       /* Request the hardware to stop, then perform the
-                        * update when we get an RX_STOP interrupt */
-                       temp = smsc911x_mac_read(pdata, MAC_CR);
-                       temp &= ~(MAC_CR_RXEN_);
-                       smsc911x_mac_write(pdata, MAC_CR, temp);
-               } else {
-                       /* There is another update pending, this should now
-                        * use the newer values */
-               }
-       } else {
-               /* Newer hardware revision - can write immediately */
-               smsc911x_rx_multicast_update(pdata);
-       }
-
-       spin_unlock_irqrestore(&pdata->mac_lock, flags);
-}
-
-static irqreturn_t smsc911x_irqhandler(int irq, void *dev_id)
-{
-       struct net_device *dev = dev_id;
-       struct smsc911x_data *pdata = netdev_priv(dev);
-       u32 intsts = smsc911x_reg_read(pdata, INT_STS);
-       u32 inten = smsc911x_reg_read(pdata, INT_EN);
-       int serviced = IRQ_NONE;
-       u32 temp;
-
-       if (unlikely(intsts & inten & INT_STS_SW_INT_)) {
-               temp = smsc911x_reg_read(pdata, INT_EN);
-               temp &= (~INT_EN_SW_INT_EN_);
-               smsc911x_reg_write(pdata, INT_EN, temp);
-               smsc911x_reg_write(pdata, INT_STS, INT_STS_SW_INT_);
-               pdata->software_irq_signal = 1;
-               smp_wmb();
-               serviced = IRQ_HANDLED;
-       }
-
-       if (unlikely(intsts & inten & INT_STS_RXSTOP_INT_)) {
-               /* Called when there is a multicast update scheduled and
-                * it is now safe to complete the update */
-               SMSC_TRACE(pdata, intr, "RX Stop interrupt");
-               smsc911x_reg_write(pdata, INT_STS, INT_STS_RXSTOP_INT_);
-               if (pdata->multicast_update_pending)
-                       smsc911x_rx_multicast_update_workaround(pdata);
-               serviced = IRQ_HANDLED;
-       }
-
-       if (intsts & inten & INT_STS_TDFA_) {
-               temp = smsc911x_reg_read(pdata, FIFO_INT);
-               temp |= FIFO_INT_TX_AVAIL_LEVEL_;
-               smsc911x_reg_write(pdata, FIFO_INT, temp);
-               smsc911x_reg_write(pdata, INT_STS, INT_STS_TDFA_);
-               netif_wake_queue(dev);
-               serviced = IRQ_HANDLED;
-       }
-
-       if (unlikely(intsts & inten & INT_STS_RXE_)) {
-               SMSC_TRACE(pdata, intr, "RX Error interrupt");
-               smsc911x_reg_write(pdata, INT_STS, INT_STS_RXE_);
-               serviced = IRQ_HANDLED;
-       }
-
-       if (likely(intsts & inten & INT_STS_RSFL_)) {
-               if (likely(napi_schedule_prep(&pdata->napi))) {
-                       /* Disable Rx interrupts */
-                       temp = smsc911x_reg_read(pdata, INT_EN);
-                       temp &= (~INT_EN_RSFL_EN_);
-                       smsc911x_reg_write(pdata, INT_EN, temp);
-                       /* Schedule a NAPI poll */
-                       __napi_schedule(&pdata->napi);
-               } else {
-                       SMSC_WARN(pdata, rx_err, "napi_schedule_prep failed");
-               }
-               serviced = IRQ_HANDLED;
-       }
-
-       return serviced;
-}
-
-#ifdef CONFIG_NET_POLL_CONTROLLER
-static void smsc911x_poll_controller(struct net_device *dev)
-{
-       disable_irq(dev->irq);
-       smsc911x_irqhandler(0, dev);
-       enable_irq(dev->irq);
-}
-#endif                         /* CONFIG_NET_POLL_CONTROLLER */
-
-static int smsc911x_set_mac_address(struct net_device *dev, void *p)
-{
-       struct smsc911x_data *pdata = netdev_priv(dev);
-       struct sockaddr *addr = p;
-
-       /* On older hardware revisions we cannot change the mac address
-        * registers while receiving data.  Newer devices can safely change
-        * this at any time. */
-       if (pdata->generation <= 1 && netif_running(dev))
-               return -EBUSY;
-
-       if (!is_valid_ether_addr(addr->sa_data))
-               return -EADDRNOTAVAIL;
-
-       memcpy(dev->dev_addr, addr->sa_data, ETH_ALEN);
-
-       spin_lock_irq(&pdata->mac_lock);
-       smsc911x_set_hw_mac_address(pdata, dev->dev_addr);
-       spin_unlock_irq(&pdata->mac_lock);
-
-       netdev_info(dev, "MAC Address: %pM\n", dev->dev_addr);
-
-       return 0;
-}
-
-/* Standard ioctls for mii-tool */
-static int smsc911x_do_ioctl(struct net_device *dev, struct ifreq *ifr, int cmd)
-{
-       struct smsc911x_data *pdata = netdev_priv(dev);
-
-       if (!netif_running(dev) || !pdata->phy_dev)
-               return -EINVAL;
-
-       return phy_mii_ioctl(pdata->phy_dev, ifr, cmd);
-}
-
-static int
-smsc911x_ethtool_getsettings(struct net_device *dev, struct ethtool_cmd *cmd)
-{
-       struct smsc911x_data *pdata = netdev_priv(dev);
-
-       cmd->maxtxpkt = 1;
-       cmd->maxrxpkt = 1;
-       return phy_ethtool_gset(pdata->phy_dev, cmd);
-}
-
-static int
-smsc911x_ethtool_setsettings(struct net_device *dev, struct ethtool_cmd *cmd)
-{
-       struct smsc911x_data *pdata = netdev_priv(dev);
-
-       return phy_ethtool_sset(pdata->phy_dev, cmd);
-}
-
-static void smsc911x_ethtool_getdrvinfo(struct net_device *dev,
-                                       struct ethtool_drvinfo *info)
-{
-       strlcpy(info->driver, SMSC_CHIPNAME, sizeof(info->driver));
-       strlcpy(info->version, SMSC_DRV_VERSION, sizeof(info->version));
-       strlcpy(info->bus_info, dev_name(dev->dev.parent),
-               sizeof(info->bus_info));
-}
-
-static int smsc911x_ethtool_nwayreset(struct net_device *dev)
-{
-       struct smsc911x_data *pdata = netdev_priv(dev);
-
-       return phy_start_aneg(pdata->phy_dev);
-}
-
-static u32 smsc911x_ethtool_getmsglevel(struct net_device *dev)
-{
-       struct smsc911x_data *pdata = netdev_priv(dev);
-       return pdata->msg_enable;
-}
-
-static void smsc911x_ethtool_setmsglevel(struct net_device *dev, u32 level)
-{
-       struct smsc911x_data *pdata = netdev_priv(dev);
-       pdata->msg_enable = level;
-}
-
-static int smsc911x_ethtool_getregslen(struct net_device *dev)
-{
-       return (((E2P_DATA - ID_REV) / 4 + 1) + (WUCSR - MAC_CR) + 1 + 32) *
-           sizeof(u32);
-}
-
-static void
-smsc911x_ethtool_getregs(struct net_device *dev, struct ethtool_regs *regs,
-                        void *buf)
-{
-       struct smsc911x_data *pdata = netdev_priv(dev);
-       struct phy_device *phy_dev = pdata->phy_dev;
-       unsigned long flags;
-       unsigned int i;
-       unsigned int j = 0;
-       u32 *data = buf;
-
-       regs->version = pdata->idrev;
-       for (i = ID_REV; i <= E2P_DATA; i += (sizeof(u32)))
-               data[j++] = smsc911x_reg_read(pdata, i);
-
-       for (i = MAC_CR; i <= WUCSR; i++) {
-               spin_lock_irqsave(&pdata->mac_lock, flags);
-               data[j++] = smsc911x_mac_read(pdata, i);
-               spin_unlock_irqrestore(&pdata->mac_lock, flags);
-       }
-
-       for (i = 0; i <= 31; i++)
-               data[j++] = smsc911x_mii_read(phy_dev->bus, phy_dev->addr, i);
-}
-
-static void smsc911x_eeprom_enable_access(struct smsc911x_data *pdata)
-{
-       unsigned int temp = smsc911x_reg_read(pdata, GPIO_CFG);
-       temp &= ~GPIO_CFG_EEPR_EN_;
-       smsc911x_reg_write(pdata, GPIO_CFG, temp);
-       msleep(1);
-}
-
-static int smsc911x_eeprom_send_cmd(struct smsc911x_data *pdata, u32 op)
-{
-       int timeout = 100;
-       u32 e2cmd;
-
-       SMSC_TRACE(pdata, drv, "op 0x%08x", op);
-       if (smsc911x_reg_read(pdata, E2P_CMD) & E2P_CMD_EPC_BUSY_) {
-               SMSC_WARN(pdata, drv, "Busy at start");
-               return -EBUSY;
-       }
-
-       e2cmd = op | E2P_CMD_EPC_BUSY_;
-       smsc911x_reg_write(pdata, E2P_CMD, e2cmd);
-
-       do {
-               msleep(1);
-               e2cmd = smsc911x_reg_read(pdata, E2P_CMD);
-       } while ((e2cmd & E2P_CMD_EPC_BUSY_) && (--timeout));
-
-       if (!timeout) {
-               SMSC_TRACE(pdata, drv, "TIMED OUT");
-               return -EAGAIN;
-       }
-
-       if (e2cmd & E2P_CMD_EPC_TIMEOUT_) {
-               SMSC_TRACE(pdata, drv, "Error occurred during eeprom operation");
-               return -EINVAL;
-       }
-
-       return 0;
-}
-
-static int smsc911x_eeprom_read_location(struct smsc911x_data *pdata,
-                                        u8 address, u8 *data)
-{
-       u32 op = E2P_CMD_EPC_CMD_READ_ | address;
-       int ret;
-
-       SMSC_TRACE(pdata, drv, "address 0x%x", address);
-       ret = smsc911x_eeprom_send_cmd(pdata, op);
-
-       if (!ret)
-               data[address] = smsc911x_reg_read(pdata, E2P_DATA);
-
-       return ret;
-}
-
-static int smsc911x_eeprom_write_location(struct smsc911x_data *pdata,
-                                         u8 address, u8 data)
-{
-       u32 op = E2P_CMD_EPC_CMD_ERASE_ | address;
-       u32 temp;
-       int ret;
-
-       SMSC_TRACE(pdata, drv, "address 0x%x, data 0x%x", address, data);
-       ret = smsc911x_eeprom_send_cmd(pdata, op);
-
-       if (!ret) {
-               op = E2P_CMD_EPC_CMD_WRITE_ | address;
-               smsc911x_reg_write(pdata, E2P_DATA, (u32)data);
-
-               /* Workaround for hardware read-after-write restriction */
-               temp = smsc911x_reg_read(pdata, BYTE_TEST);
-
-               ret = smsc911x_eeprom_send_cmd(pdata, op);
-       }
-
-       return ret;
-}
-
-static int smsc911x_ethtool_get_eeprom_len(struct net_device *dev)
-{
-       return SMSC911X_EEPROM_SIZE;
-}
-
-static int smsc911x_ethtool_get_eeprom(struct net_device *dev,
-                                      struct ethtool_eeprom *eeprom, u8 *data)
-{
-       struct smsc911x_data *pdata = netdev_priv(dev);
-       u8 eeprom_data[SMSC911X_EEPROM_SIZE];
-       int len;
-       int i;
-
-       smsc911x_eeprom_enable_access(pdata);
-
-       len = min(eeprom->len, SMSC911X_EEPROM_SIZE);
-       for (i = 0; i < len; i++) {
-               int ret = smsc911x_eeprom_read_location(pdata, i, eeprom_data);
-               if (ret < 0) {
-                       eeprom->len = 0;
-                       return ret;
-               }
-       }
-
-       memcpy(data, &eeprom_data[eeprom->offset], len);
-       eeprom->len = len;
-       return 0;
-}
-
-static int smsc911x_ethtool_set_eeprom(struct net_device *dev,
-                                      struct ethtool_eeprom *eeprom, u8 *data)
-{
-       int ret;
-       struct smsc911x_data *pdata = netdev_priv(dev);
-
-       smsc911x_eeprom_enable_access(pdata);
-       smsc911x_eeprom_send_cmd(pdata, E2P_CMD_EPC_CMD_EWEN_);
-       ret = smsc911x_eeprom_write_location(pdata, eeprom->offset, *data);
-       smsc911x_eeprom_send_cmd(pdata, E2P_CMD_EPC_CMD_EWDS_);
-
-       /* Single byte write, according to man page */
-       eeprom->len = 1;
-
-       return ret;
-}
-
-static const struct ethtool_ops smsc911x_ethtool_ops = {
-       .get_settings = smsc911x_ethtool_getsettings,
-       .set_settings = smsc911x_ethtool_setsettings,
-       .get_link = ethtool_op_get_link,
-       .get_drvinfo = smsc911x_ethtool_getdrvinfo,
-       .nway_reset = smsc911x_ethtool_nwayreset,
-       .get_msglevel = smsc911x_ethtool_getmsglevel,
-       .set_msglevel = smsc911x_ethtool_setmsglevel,
-       .get_regs_len = smsc911x_ethtool_getregslen,
-       .get_regs = smsc911x_ethtool_getregs,
-       .get_eeprom_len = smsc911x_ethtool_get_eeprom_len,
-       .get_eeprom = smsc911x_ethtool_get_eeprom,
-       .set_eeprom = smsc911x_ethtool_set_eeprom,
-};
-
-static const struct net_device_ops smsc911x_netdev_ops = {
-       .ndo_open               = smsc911x_open,
-       .ndo_stop               = smsc911x_stop,
-       .ndo_start_xmit         = smsc911x_hard_start_xmit,
-       .ndo_get_stats          = smsc911x_get_stats,
-       .ndo_set_multicast_list = smsc911x_set_multicast_list,
-       .ndo_do_ioctl           = smsc911x_do_ioctl,
-       .ndo_change_mtu         = eth_change_mtu,
-       .ndo_validate_addr      = eth_validate_addr,
-       .ndo_set_mac_address    = smsc911x_set_mac_address,
-#ifdef CONFIG_NET_POLL_CONTROLLER
-       .ndo_poll_controller    = smsc911x_poll_controller,
-#endif
-};
-
-/* copies the current mac address from hardware to dev->dev_addr */
-static void __devinit smsc911x_read_mac_address(struct net_device *dev)
-{
-       struct smsc911x_data *pdata = netdev_priv(dev);
-       u32 mac_high16 = smsc911x_mac_read(pdata, ADDRH);
-       u32 mac_low32 = smsc911x_mac_read(pdata, ADDRL);
-
-       dev->dev_addr[0] = (u8)(mac_low32);
-       dev->dev_addr[1] = (u8)(mac_low32 >> 8);
-       dev->dev_addr[2] = (u8)(mac_low32 >> 16);
-       dev->dev_addr[3] = (u8)(mac_low32 >> 24);
-       dev->dev_addr[4] = (u8)(mac_high16);
-       dev->dev_addr[5] = (u8)(mac_high16 >> 8);
-}
-
-/* Initializing private device structures, only called from probe */
-static int __devinit smsc911x_init(struct net_device *dev)
-{
-       struct smsc911x_data *pdata = netdev_priv(dev);
-       unsigned int byte_test;
-
-       SMSC_TRACE(pdata, probe, "Driver Parameters:");
-       SMSC_TRACE(pdata, probe, "LAN base: 0x%08lX",
-                  (unsigned long)pdata->ioaddr);
-       SMSC_TRACE(pdata, probe, "IRQ: %d", dev->irq);
-       SMSC_TRACE(pdata, probe, "PHY will be autodetected.");
-
-       spin_lock_init(&pdata->dev_lock);
-       spin_lock_init(&pdata->mac_lock);
-
-       if (pdata->ioaddr == 0) {
-               SMSC_WARN(pdata, probe, "pdata->ioaddr: 0x00000000");
-               return -ENODEV;
-       }
-
-       /* Check byte ordering */
-       byte_test = smsc911x_reg_read(pdata, BYTE_TEST);
-       SMSC_TRACE(pdata, probe, "BYTE_TEST: 0x%08X", byte_test);
-       if (byte_test == 0x43218765) {
-               SMSC_TRACE(pdata, probe, "BYTE_TEST looks swapped, "
-                          "applying WORD_SWAP");
-               smsc911x_reg_write(pdata, WORD_SWAP, 0xffffffff);
-
-               /* 1 dummy read of BYTE_TEST is needed after a write to
-                * WORD_SWAP before its contents are valid */
-               byte_test = smsc911x_reg_read(pdata, BYTE_TEST);
-
-               byte_test = smsc911x_reg_read(pdata, BYTE_TEST);
-       }
-
-       if (byte_test != 0x87654321) {
-               SMSC_WARN(pdata, drv, "BYTE_TEST: 0x%08X", byte_test);
-               if (((byte_test >> 16) & 0xFFFF) == (byte_test & 0xFFFF)) {
-                       SMSC_WARN(pdata, probe,
-                                 "top 16 bits equal to bottom 16 bits");
-                       SMSC_TRACE(pdata, probe,
-                                  "This may mean the chip is set "
-                                  "for 32 bit while the bus is reading 16 bit");
-               }
-               return -ENODEV;
-       }
-
-       /* Default generation to zero (all workarounds apply) */
-       pdata->generation = 0;
-
-       pdata->idrev = smsc911x_reg_read(pdata, ID_REV);
-       switch (pdata->idrev & 0xFFFF0000) {
-       case 0x01180000:
-       case 0x01170000:
-       case 0x01160000:
-       case 0x01150000:
-               /* LAN911[5678] family */
-               pdata->generation = pdata->idrev & 0x0000FFFF;
-               break;
-
-       case 0x118A0000:
-       case 0x117A0000:
-       case 0x116A0000:
-       case 0x115A0000:
-               /* LAN921[5678] family */
-               pdata->generation = 3;
-               break;
-
-       case 0x92100000:
-       case 0x92110000:
-       case 0x92200000:
-       case 0x92210000:
-               /* LAN9210/LAN9211/LAN9220/LAN9221 */
-               pdata->generation = 4;
-               break;
-
-       default:
-               SMSC_WARN(pdata, probe, "LAN911x not identified, idrev: 0x%08X",
-                         pdata->idrev);
-               return -ENODEV;
-       }
-
-       SMSC_TRACE(pdata, probe,
-                  "LAN911x identified, idrev: 0x%08X, generation: %d",
-                  pdata->idrev, pdata->generation);
-
-       if (pdata->generation == 0)
-               SMSC_WARN(pdata, probe,
-                         "This driver is not intended for this chip revision");
-
-       /* workaround for platforms without an eeprom, where the mac address
-        * is stored elsewhere and set by the bootloader.  This saves the
-        * mac address before resetting the device */
-       if (pdata->config.flags & SMSC911X_SAVE_MAC_ADDRESS) {
-               spin_lock_irq(&pdata->mac_lock);
-               smsc911x_read_mac_address(dev);
-               spin_unlock_irq(&pdata->mac_lock);
-       }
-
-       /* Reset the LAN911x */
-       if (smsc911x_soft_reset(pdata))
-               return -ENODEV;
-
-       /* Disable all interrupt sources until we bring the device up */
-       smsc911x_reg_write(pdata, INT_EN, 0);
-
-       ether_setup(dev);
-       dev->flags |= IFF_MULTICAST;
-       netif_napi_add(dev, &pdata->napi, smsc911x_poll, SMSC_NAPI_WEIGHT);
-       dev->netdev_ops = &smsc911x_netdev_ops;
-       dev->ethtool_ops = &smsc911x_ethtool_ops;
-
-       return 0;
-}
-
-static int __devexit smsc911x_drv_remove(struct platform_device *pdev)
-{
-       struct net_device *dev;
-       struct smsc911x_data *pdata;
-       struct resource *res;
-
-       dev = platform_get_drvdata(pdev);
-       BUG_ON(!dev);
-       pdata = netdev_priv(dev);
-       BUG_ON(!pdata);
-       BUG_ON(!pdata->ioaddr);
-       BUG_ON(!pdata->phy_dev);
-
-       SMSC_TRACE(pdata, ifdown, "Stopping driver");
-
-       phy_disconnect(pdata->phy_dev);
-       pdata->phy_dev = NULL;
-       mdiobus_unregister(pdata->mii_bus);
-       mdiobus_free(pdata->mii_bus);
-
-       platform_set_drvdata(pdev, NULL);
-       unregister_netdev(dev);
-       free_irq(dev->irq, dev);
-       res = platform_get_resource_byname(pdev, IORESOURCE_MEM,
-                                          "smsc911x-memory");
-       if (!res)
-               res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
-
-       release_mem_region(res->start, resource_size(res));
-
-       iounmap(pdata->ioaddr);
-
-       free_netdev(dev);
-
-       return 0;
-}
-
-/* standard register acces */
-static const struct smsc911x_ops standard_smsc911x_ops = {
-       .reg_read = __smsc911x_reg_read,
-       .reg_write = __smsc911x_reg_write,
-       .rx_readfifo = smsc911x_rx_readfifo,
-       .tx_writefifo = smsc911x_tx_writefifo,
-};
-
-/* shifted register access */
-static const struct smsc911x_ops shifted_smsc911x_ops = {
-       .reg_read = __smsc911x_reg_read_shift,
-       .reg_write = __smsc911x_reg_write_shift,
-       .rx_readfifo = smsc911x_rx_readfifo_shift,
-       .tx_writefifo = smsc911x_tx_writefifo_shift,
-};
-
-#ifdef CONFIG_OF
-static int __devinit smsc911x_probe_config_dt(
-                               struct smsc911x_platform_config *config,
-                               struct device_node *np)
-{
-       const char *mac;
-       u32 width = 0;
-
-       if (!np)
-               return -ENODEV;
-
-       config->phy_interface = of_get_phy_mode(np);
-
-       mac = of_get_mac_address(np);
-       if (mac)
-               memcpy(config->mac, mac, ETH_ALEN);
-
-       of_property_read_u32(np, "reg-shift", &config->shift);
-
-       of_property_read_u32(np, "reg-io-width", &width);
-       if (width == 4)
-               config->flags |= SMSC911X_USE_32BIT;
-
-       if (of_get_property(np, "smsc,irq-active-high", NULL))
-               config->irq_polarity = SMSC911X_IRQ_POLARITY_ACTIVE_HIGH;
-
-       if (of_get_property(np, "smsc,irq-push-pull", NULL))
-               config->irq_type = SMSC911X_IRQ_TYPE_PUSH_PULL;
-
-       if (of_get_property(np, "smsc,force-internal-phy", NULL))
-               config->flags |= SMSC911X_FORCE_INTERNAL_PHY;
-
-       if (of_get_property(np, "smsc,force-external-phy", NULL))
-               config->flags |= SMSC911X_FORCE_EXTERNAL_PHY;
-
-       if (of_get_property(np, "smsc,save-mac-address", NULL))
-               config->flags |= SMSC911X_SAVE_MAC_ADDRESS;
-
-       return 0;
-}
-#else
-static inline int smsc911x_probe_config_dt(
-                               struct smsc911x_platform_config *config,
-                               struct device_node *np)
-{
-       return -ENODEV;
-}
-#endif /* CONFIG_OF */
-
-static int __devinit smsc911x_drv_probe(struct platform_device *pdev)
-{
-       struct device_node *np = pdev->dev.of_node;
-       struct net_device *dev;
-       struct smsc911x_data *pdata;
-       struct smsc911x_platform_config *config = pdev->dev.platform_data;
-       struct resource *res, *irq_res;
-       unsigned int intcfg = 0;
-       int res_size, irq_flags;
-       int retval;
-
-       pr_info("Driver version %s\n", SMSC_DRV_VERSION);
-
-       res = platform_get_resource_byname(pdev, IORESOURCE_MEM,
-                                          "smsc911x-memory");
-       if (!res)
-               res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
-       if (!res) {
-               pr_warn("Could not allocate resource\n");
-               retval = -ENODEV;
-               goto out_0;
-       }
-       res_size = resource_size(res);
-
-       irq_res = platform_get_resource(pdev, IORESOURCE_IRQ, 0);
-       if (!irq_res) {
-               pr_warn("Could not allocate irq resource\n");
-               retval = -ENODEV;
-               goto out_0;
-       }
-
-       if (!request_mem_region(res->start, res_size, SMSC_CHIPNAME)) {
-               retval = -EBUSY;
-               goto out_0;
-       }
-
-       dev = alloc_etherdev(sizeof(struct smsc911x_data));
-       if (!dev) {
-               pr_warn("Could not allocate device\n");
-               retval = -ENOMEM;
-               goto out_release_io_1;
-       }
-
-       SET_NETDEV_DEV(dev, &pdev->dev);
-
-       pdata = netdev_priv(dev);
-
-       dev->irq = irq_res->start;
-       irq_flags = irq_res->flags & IRQF_TRIGGER_MASK;
-       pdata->ioaddr = ioremap_nocache(res->start, res_size);
-
-       pdata->dev = dev;
-       pdata->msg_enable = ((1 << debug) - 1);
-
-       if (pdata->ioaddr == NULL) {
-               SMSC_WARN(pdata, probe, "Error smsc911x base address invalid");
-               retval = -ENOMEM;
-               goto out_free_netdev_2;
-       }
-
-       retval = smsc911x_probe_config_dt(&pdata->config, np);
-       if (retval && config) {
-               /* copy config parameters across to pdata */
-               memcpy(&pdata->config, config, sizeof(pdata->config));
-               retval = 0;
-       }
-
-       if (retval) {
-               SMSC_WARN(pdata, probe, "Error smsc911x config not found");
-               goto out_unmap_io_3;
-       }
-
-       /* assume standard, non-shifted, access to HW registers */
-       pdata->ops = &standard_smsc911x_ops;
-       /* apply the right access if shifting is needed */
-       if (pdata->config.shift)
-               pdata->ops = &shifted_smsc911x_ops;
-
-       retval = smsc911x_init(dev);
-       if (retval < 0)
-               goto out_unmap_io_3;
-
-       /* configure irq polarity and type before connecting isr */
-       if (pdata->config.irq_polarity == SMSC911X_IRQ_POLARITY_ACTIVE_HIGH)
-               intcfg |= INT_CFG_IRQ_POL_;
-
-       if (pdata->config.irq_type == SMSC911X_IRQ_TYPE_PUSH_PULL)
-               intcfg |= INT_CFG_IRQ_TYPE_;
-
-       smsc911x_reg_write(pdata, INT_CFG, intcfg);
-
-       /* Ensure interrupts are globally disabled before connecting ISR */
-       smsc911x_reg_write(pdata, INT_EN, 0);
-       smsc911x_reg_write(pdata, INT_STS, 0xFFFFFFFF);
-
-       retval = request_irq(dev->irq, smsc911x_irqhandler,
-                            irq_flags | IRQF_SHARED, dev->name, dev);
-       if (retval) {
-               SMSC_WARN(pdata, probe,
-                         "Unable to claim requested irq: %d", dev->irq);
-               goto out_unmap_io_3;
-       }
-
-       platform_set_drvdata(pdev, dev);
-
-       retval = register_netdev(dev);
-       if (retval) {
-               SMSC_WARN(pdata, probe, "Error %i registering device", retval);
-               goto out_unset_drvdata_4;
-       } else {
-               SMSC_TRACE(pdata, probe,
-                          "Network interface: \"%s\"", dev->name);
-       }
-
-       retval = smsc911x_mii_init(pdev, dev);
-       if (retval) {
-               SMSC_WARN(pdata, probe, "Error %i initialising mii", retval);
-               goto out_unregister_netdev_5;
-       }
-
-       spin_lock_irq(&pdata->mac_lock);
-
-       /* Check if mac address has been specified when bringing interface up */
-       if (is_valid_ether_addr(dev->dev_addr)) {
-               smsc911x_set_hw_mac_address(pdata, dev->dev_addr);
-               SMSC_TRACE(pdata, probe,
-                          "MAC Address is specified by configuration");
-       } else if (is_valid_ether_addr(pdata->config.mac)) {
-               memcpy(dev->dev_addr, pdata->config.mac, 6);
-               SMSC_TRACE(pdata, probe,
-                          "MAC Address specified by platform data");
-       } else {
-               /* Try reading mac address from device. if EEPROM is present
-                * it will already have been set */
-               smsc_get_mac(dev);
-
-               if (is_valid_ether_addr(dev->dev_addr)) {
-                       /* eeprom values are valid  so use them */
-                       SMSC_TRACE(pdata, probe,
-                                  "Mac Address is read from LAN911x EEPROM");
-               } else {
-                       /* eeprom values are invalid, generate random MAC */
-                       random_ether_addr(dev->dev_addr);
-                       smsc911x_set_hw_mac_address(pdata, dev->dev_addr);
-                       SMSC_TRACE(pdata, probe,
-                                  "MAC Address is set to random_ether_addr");
-               }
-       }
-
-       spin_unlock_irq(&pdata->mac_lock);
-
-       netdev_info(dev, "MAC Address: %pM\n", dev->dev_addr);
-
-       return 0;
-
-out_unregister_netdev_5:
-       unregister_netdev(dev);
-out_unset_drvdata_4:
-       platform_set_drvdata(pdev, NULL);
-       free_irq(dev->irq, dev);
-out_unmap_io_3:
-       iounmap(pdata->ioaddr);
-out_free_netdev_2:
-       free_netdev(dev);
-out_release_io_1:
-       release_mem_region(res->start, resource_size(res));
-out_0:
-       return retval;
-}
-
-#ifdef CONFIG_PM
-/* This implementation assumes the devices remains powered on its VDDVARIO
- * pins during suspend. */
-
-/* TODO: implement freeze/thaw callbacks for hibernation.*/
-
-static int smsc911x_suspend(struct device *dev)
-{
-       struct net_device *ndev = dev_get_drvdata(dev);
-       struct smsc911x_data *pdata = netdev_priv(ndev);
-
-       /* enable wake on LAN, energy detection and the external PME
-        * signal. */
-       smsc911x_reg_write(pdata, PMT_CTRL,
-               PMT_CTRL_PM_MODE_D1_ | PMT_CTRL_WOL_EN_ |
-               PMT_CTRL_ED_EN_ | PMT_CTRL_PME_EN_);
-
-       return 0;
-}
-
-static int smsc911x_resume(struct device *dev)
-{
-       struct net_device *ndev = dev_get_drvdata(dev);
-       struct smsc911x_data *pdata = netdev_priv(ndev);
-       unsigned int to = 100;
-
-       /* Note 3.11 from the datasheet:
-        *      "When the LAN9220 is in a power saving state, a write of any
-        *       data to the BYTE_TEST register will wake-up the device."
-        */
-       smsc911x_reg_write(pdata, BYTE_TEST, 0);
-
-       /* poll the READY bit in PMT_CTRL. Any other access to the device is
-        * forbidden while this bit isn't set. Try for 100ms and return -EIO
-        * if it failed. */
-       while (!(smsc911x_reg_read(pdata, PMT_CTRL) & PMT_CTRL_READY_) && --to)
-               udelay(1000);
-
-       return (to == 0) ? -EIO : 0;
-}
-
-static const struct dev_pm_ops smsc911x_pm_ops = {
-       .suspend        = smsc911x_suspend,
-       .resume         = smsc911x_resume,
-};
-
-#define SMSC911X_PM_OPS (&smsc911x_pm_ops)
-
-#else
-#define SMSC911X_PM_OPS NULL
-#endif
-
-static const struct of_device_id smsc911x_dt_ids[] = {
-       { .compatible = "smsc,lan9115", },
-       { /* sentinel */ }
-};
-MODULE_DEVICE_TABLE(of, smsc911x_dt_ids);
-
-static struct platform_driver smsc911x_driver = {
-       .probe = smsc911x_drv_probe,
-       .remove = __devexit_p(smsc911x_drv_remove),
-       .driver = {
-               .name   = SMSC_CHIPNAME,
-               .owner  = THIS_MODULE,
-               .pm     = SMSC911X_PM_OPS,
-               .of_match_table = smsc911x_dt_ids,
-       },
-};
-
-/* Entry point for loading the module */
-static int __init smsc911x_init_module(void)
-{
-       SMSC_INITIALIZE();
-       return platform_driver_register(&smsc911x_driver);
-}
-
-/* entry point for unloading the module */
-static void __exit smsc911x_cleanup_module(void)
-{
-       platform_driver_unregister(&smsc911x_driver);
-}
-
-module_init(smsc911x_init_module);
-module_exit(smsc911x_cleanup_module);
diff --git a/drivers/net/smsc911x.h b/drivers/net/smsc911x.h
deleted file mode 100644 (file)
index 8d67aac..0000000
+++ /dev/null
@@ -1,404 +0,0 @@
-/***************************************************************************
- *
- * Copyright (C) 2004-2008 SMSC
- * Copyright (C) 2005-2008 ARM
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU General Public License
- * as published by the Free Software Foundation; either version 2
- * of the License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
- *
- ***************************************************************************/
-#ifndef __SMSC911X_H__
-#define __SMSC911X_H__
-
-#define TX_FIFO_LOW_THRESHOLD  ((u32)1600)
-#define SMSC911X_EEPROM_SIZE   ((u32)128)
-#define USE_DEBUG              0
-
-/* This is the maximum number of packets to be received every
- * NAPI poll */
-#define SMSC_NAPI_WEIGHT       16
-
-/* implements a PHY loopback test at initialisation time, to ensure a packet
- * can be successfully looped back */
-#define USE_PHY_WORK_AROUND
-
-#if USE_DEBUG >= 1
-#define SMSC_WARN(pdata, nlevel, fmt, args...)                 \
-       netif_warn(pdata, nlevel, (pdata)->dev,                 \
-                  "%s: " fmt "\n", __func__, ##args)
-#else
-#define SMSC_WARN(pdata, nlevel, fmt, args...)                 \
-       no_printk(fmt "\n", ##args)
-#endif
-
-#if USE_DEBUG >= 2
-#define SMSC_TRACE(pdata, nlevel, fmt, args...)                        \
-       netif_info(pdata, nlevel, pdata->dev, fmt "\n", ##args)
-#else
-#define SMSC_TRACE(pdata, nlevel, fmt, args...)                        \
-       no_printk(fmt "\n", ##args)
-#endif
-
-#ifdef CONFIG_DEBUG_SPINLOCK
-#define SMSC_ASSERT_MAC_LOCK(pdata) \
-               WARN_ON(!spin_is_locked(&pdata->mac_lock))
-#else
-#define SMSC_ASSERT_MAC_LOCK(pdata) do {} while (0)
-#endif                         /* CONFIG_DEBUG_SPINLOCK */
-
-/* SMSC911x registers and bitfields */
-#define RX_DATA_FIFO                   0x00
-
-#define TX_DATA_FIFO                   0x20
-#define TX_CMD_A_ON_COMP_              0x80000000
-#define TX_CMD_A_BUF_END_ALGN_         0x03000000
-#define TX_CMD_A_4_BYTE_ALGN_          0x00000000
-#define TX_CMD_A_16_BYTE_ALGN_         0x01000000
-#define TX_CMD_A_32_BYTE_ALGN_         0x02000000
-#define TX_CMD_A_DATA_OFFSET_          0x001F0000
-#define TX_CMD_A_FIRST_SEG_            0x00002000
-#define TX_CMD_A_LAST_SEG_             0x00001000
-#define TX_CMD_A_BUF_SIZE_             0x000007FF
-#define TX_CMD_B_PKT_TAG_              0xFFFF0000
-#define TX_CMD_B_ADD_CRC_DISABLE_      0x00002000
-#define TX_CMD_B_DISABLE_PADDING_      0x00001000
-#define TX_CMD_B_PKT_BYTE_LENGTH_      0x000007FF
-
-#define RX_STATUS_FIFO                 0x40
-#define RX_STS_ES_                     0x00008000
-#define RX_STS_LENGTH_ERR_             0x00001000
-#define RX_STS_MCAST_                  0x00000400
-#define RX_STS_FRAME_TYPE_             0x00000020
-#define RX_STS_CRC_ERR_                        0x00000002
-
-#define RX_STATUS_FIFO_PEEK            0x44
-
-#define TX_STATUS_FIFO                 0x48
-#define TX_STS_ES_                     0x00008000
-#define TX_STS_LOST_CARRIER_           0x00000800
-#define TX_STS_NO_CARRIER_             0x00000400
-#define TX_STS_LATE_COL_               0x00000200
-#define TX_STS_EXCESS_COL_             0x00000100
-
-#define TX_STATUS_FIFO_PEEK            0x4C
-
-#define ID_REV                         0x50
-#define ID_REV_CHIP_ID_                        0xFFFF0000
-#define ID_REV_REV_ID_                 0x0000FFFF
-
-#define INT_CFG                                0x54
-#define INT_CFG_INT_DEAS_              0xFF000000
-#define INT_CFG_INT_DEAS_CLR_          0x00004000
-#define INT_CFG_INT_DEAS_STS_          0x00002000
-#define INT_CFG_IRQ_INT_               0x00001000
-#define INT_CFG_IRQ_EN_                        0x00000100
-#define INT_CFG_IRQ_POL_               0x00000010
-#define INT_CFG_IRQ_TYPE_              0x00000001
-
-#define INT_STS                                0x58
-#define INT_STS_SW_INT_                        0x80000000
-#define INT_STS_TXSTOP_INT_            0x02000000
-#define INT_STS_RXSTOP_INT_            0x01000000
-#define INT_STS_RXDFH_INT_             0x00800000
-#define INT_STS_RXDF_INT_              0x00400000
-#define INT_STS_TX_IOC_                        0x00200000
-#define INT_STS_RXD_INT_               0x00100000
-#define INT_STS_GPT_INT_               0x00080000
-#define INT_STS_PHY_INT_               0x00040000
-#define INT_STS_PME_INT_               0x00020000
-#define INT_STS_TXSO_                  0x00010000
-#define INT_STS_RWT_                   0x00008000
-#define INT_STS_RXE_                   0x00004000
-#define INT_STS_TXE_                   0x00002000
-#define INT_STS_TDFU_                  0x00000800
-#define INT_STS_TDFO_                  0x00000400
-#define INT_STS_TDFA_                  0x00000200
-#define INT_STS_TSFF_                  0x00000100
-#define INT_STS_TSFL_                  0x00000080
-#define INT_STS_RXDF_                  0x00000040
-#define INT_STS_RDFL_                  0x00000020
-#define INT_STS_RSFF_                  0x00000010
-#define INT_STS_RSFL_                  0x00000008
-#define INT_STS_GPIO2_INT_             0x00000004
-#define INT_STS_GPIO1_INT_             0x00000002
-#define INT_STS_GPIO0_INT_             0x00000001
-
-#define INT_EN                         0x5C
-#define INT_EN_SW_INT_EN_              0x80000000
-#define INT_EN_TXSTOP_INT_EN_          0x02000000
-#define INT_EN_RXSTOP_INT_EN_          0x01000000
-#define INT_EN_RXDFH_INT_EN_           0x00800000
-#define INT_EN_TIOC_INT_EN_            0x00200000
-#define INT_EN_RXD_INT_EN_             0x00100000
-#define INT_EN_GPT_INT_EN_             0x00080000
-#define INT_EN_PHY_INT_EN_             0x00040000
-#define INT_EN_PME_INT_EN_             0x00020000
-#define INT_EN_TXSO_EN_                        0x00010000
-#define INT_EN_RWT_EN_                 0x00008000
-#define INT_EN_RXE_EN_                 0x00004000
-#define INT_EN_TXE_EN_                 0x00002000
-#define INT_EN_TDFU_EN_                        0x00000800
-#define INT_EN_TDFO_EN_                        0x00000400
-#define INT_EN_TDFA_EN_                        0x00000200
-#define INT_EN_TSFF_EN_                        0x00000100
-#define INT_EN_TSFL_EN_                        0x00000080
-#define INT_EN_RXDF_EN_                        0x00000040
-#define INT_EN_RDFL_EN_                        0x00000020
-#define INT_EN_RSFF_EN_                        0x00000010
-#define INT_EN_RSFL_EN_                        0x00000008
-#define INT_EN_GPIO2_INT_              0x00000004
-#define INT_EN_GPIO1_INT_              0x00000002
-#define INT_EN_GPIO0_INT_              0x00000001
-
-#define BYTE_TEST                      0x64
-
-#define FIFO_INT                       0x68
-#define FIFO_INT_TX_AVAIL_LEVEL_       0xFF000000
-#define FIFO_INT_TX_STS_LEVEL_         0x00FF0000
-#define FIFO_INT_RX_AVAIL_LEVEL_       0x0000FF00
-#define FIFO_INT_RX_STS_LEVEL_         0x000000FF
-
-#define RX_CFG                         0x6C
-#define RX_CFG_RX_END_ALGN_            0xC0000000
-#define RX_CFG_RX_END_ALGN4_           0x00000000
-#define RX_CFG_RX_END_ALGN16_          0x40000000
-#define RX_CFG_RX_END_ALGN32_          0x80000000
-#define RX_CFG_RX_DMA_CNT_             0x0FFF0000
-#define RX_CFG_RX_DUMP_                        0x00008000
-#define RX_CFG_RXDOFF_                 0x00001F00
-
-#define TX_CFG                         0x70
-#define TX_CFG_TXS_DUMP_               0x00008000
-#define TX_CFG_TXD_DUMP_               0x00004000
-#define TX_CFG_TXSAO_                  0x00000004
-#define TX_CFG_TX_ON_                  0x00000002
-#define TX_CFG_STOP_TX_                        0x00000001
-
-#define HW_CFG                         0x74
-#define HW_CFG_TTM_                    0x00200000
-#define HW_CFG_SF_                     0x00100000
-#define HW_CFG_TX_FIF_SZ_              0x000F0000
-#define HW_CFG_TR_                     0x00003000
-#define HW_CFG_SRST_                   0x00000001
-
-/* only available on 115/117 */
-#define HW_CFG_PHY_CLK_SEL_            0x00000060
-#define HW_CFG_PHY_CLK_SEL_INT_PHY_    0x00000000
-#define HW_CFG_PHY_CLK_SEL_EXT_PHY_    0x00000020
-#define HW_CFG_PHY_CLK_SEL_CLK_DIS_    0x00000040
-#define HW_CFG_SMI_SEL_                        0x00000010
-#define HW_CFG_EXT_PHY_DET_            0x00000008
-#define HW_CFG_EXT_PHY_EN_             0x00000004
-#define HW_CFG_SRST_TO_                        0x00000002
-
-/* only available  on 116/118 */
-#define HW_CFG_32_16_BIT_MODE_         0x00000004
-
-#define RX_DP_CTRL                     0x78
-#define RX_DP_CTRL_RX_FFWD_            0x80000000
-
-#define RX_FIFO_INF                    0x7C
-#define RX_FIFO_INF_RXSUSED_           0x00FF0000
-#define RX_FIFO_INF_RXDUSED_           0x0000FFFF
-
-#define TX_FIFO_INF                    0x80
-#define TX_FIFO_INF_TSUSED_            0x00FF0000
-#define TX_FIFO_INF_TDFREE_            0x0000FFFF
-
-#define PMT_CTRL                       0x84
-#define PMT_CTRL_PM_MODE_              0x00003000
-#define PMT_CTRL_PM_MODE_D0_           0x00000000
-#define PMT_CTRL_PM_MODE_D1_           0x00001000
-#define PMT_CTRL_PM_MODE_D2_           0x00002000
-#define PMT_CTRL_PM_MODE_D3_           0x00003000
-#define PMT_CTRL_PHY_RST_              0x00000400
-#define PMT_CTRL_WOL_EN_               0x00000200
-#define PMT_CTRL_ED_EN_                        0x00000100
-#define PMT_CTRL_PME_TYPE_             0x00000040
-#define PMT_CTRL_WUPS_                 0x00000030
-#define PMT_CTRL_WUPS_NOWAKE_          0x00000000
-#define PMT_CTRL_WUPS_ED_              0x00000010
-#define PMT_CTRL_WUPS_WOL_             0x00000020
-#define PMT_CTRL_WUPS_MULTI_           0x00000030
-#define PMT_CTRL_PME_IND_              0x00000008
-#define PMT_CTRL_PME_POL_              0x00000004
-#define PMT_CTRL_PME_EN_               0x00000002
-#define PMT_CTRL_READY_                        0x00000001
-
-#define GPIO_CFG                       0x88
-#define GPIO_CFG_LED3_EN_              0x40000000
-#define GPIO_CFG_LED2_EN_              0x20000000
-#define GPIO_CFG_LED1_EN_              0x10000000
-#define GPIO_CFG_GPIO2_INT_POL_                0x04000000
-#define GPIO_CFG_GPIO1_INT_POL_                0x02000000
-#define GPIO_CFG_GPIO0_INT_POL_                0x01000000
-#define GPIO_CFG_EEPR_EN_              0x00700000
-#define GPIO_CFG_GPIOBUF2_             0x00040000
-#define GPIO_CFG_GPIOBUF1_             0x00020000
-#define GPIO_CFG_GPIOBUF0_             0x00010000
-#define GPIO_CFG_GPIODIR2_             0x00000400
-#define GPIO_CFG_GPIODIR1_             0x00000200
-#define GPIO_CFG_GPIODIR0_             0x00000100
-#define GPIO_CFG_GPIOD4_               0x00000020
-#define GPIO_CFG_GPIOD3_               0x00000010
-#define GPIO_CFG_GPIOD2_               0x00000004
-#define GPIO_CFG_GPIOD1_               0x00000002
-#define GPIO_CFG_GPIOD0_               0x00000001
-
-#define GPT_CFG                                0x8C
-#define GPT_CFG_TIMER_EN_              0x20000000
-#define GPT_CFG_GPT_LOAD_              0x0000FFFF
-
-#define GPT_CNT                                0x90
-#define GPT_CNT_GPT_CNT_               0x0000FFFF
-
-#define WORD_SWAP                      0x98
-
-#define FREE_RUN                       0x9C
-
-#define RX_DROP                                0xA0
-
-#define MAC_CSR_CMD                    0xA4
-#define MAC_CSR_CMD_CSR_BUSY_          0x80000000
-#define MAC_CSR_CMD_R_NOT_W_           0x40000000
-#define MAC_CSR_CMD_CSR_ADDR_          0x000000FF
-
-#define MAC_CSR_DATA                   0xA8
-
-#define AFC_CFG                                0xAC
-#define AFC_CFG_AFC_HI_                        0x00FF0000
-#define AFC_CFG_AFC_LO_                        0x0000FF00
-#define AFC_CFG_BACK_DUR_              0x000000F0
-#define AFC_CFG_FCMULT_                        0x00000008
-#define AFC_CFG_FCBRD_                 0x00000004
-#define AFC_CFG_FCADD_                 0x00000002
-#define AFC_CFG_FCANY_                 0x00000001
-
-#define E2P_CMD                                0xB0
-#define E2P_CMD_EPC_BUSY_              0x80000000
-#define E2P_CMD_EPC_CMD_               0x70000000
-#define E2P_CMD_EPC_CMD_READ_          0x00000000
-#define E2P_CMD_EPC_CMD_EWDS_          0x10000000
-#define E2P_CMD_EPC_CMD_EWEN_          0x20000000
-#define E2P_CMD_EPC_CMD_WRITE_         0x30000000
-#define E2P_CMD_EPC_CMD_WRAL_          0x40000000
-#define E2P_CMD_EPC_CMD_ERASE_         0x50000000
-#define E2P_CMD_EPC_CMD_ERAL_          0x60000000
-#define E2P_CMD_EPC_CMD_RELOAD_                0x70000000
-#define E2P_CMD_EPC_TIMEOUT_           0x00000200
-#define E2P_CMD_MAC_ADDR_LOADED_       0x00000100
-#define E2P_CMD_EPC_ADDR_              0x000000FF
-
-#define E2P_DATA                       0xB4
-#define E2P_DATA_EEPROM_DATA_          0x000000FF
-#define LAN_REGISTER_EXTENT            0x00000100
-
-/*
- * MAC Control and Status Register (Indirect Address)
- * Offset (through the MAC_CSR CMD and DATA port)
- */
-#define MAC_CR                         0x01
-#define MAC_CR_RXALL_                  0x80000000
-#define MAC_CR_HBDIS_                  0x10000000
-#define MAC_CR_RCVOWN_                 0x00800000
-#define MAC_CR_LOOPBK_                 0x00200000
-#define MAC_CR_FDPX_                   0x00100000
-#define MAC_CR_MCPAS_                  0x00080000
-#define MAC_CR_PRMS_                   0x00040000
-#define MAC_CR_INVFILT_                        0x00020000
-#define MAC_CR_PASSBAD_                        0x00010000
-#define MAC_CR_HFILT_                  0x00008000
-#define MAC_CR_HPFILT_                 0x00002000
-#define MAC_CR_LCOLL_                  0x00001000
-#define MAC_CR_BCAST_                  0x00000800
-#define MAC_CR_DISRTY_                 0x00000400
-#define MAC_CR_PADSTR_                 0x00000100
-#define MAC_CR_BOLMT_MASK_             0x000000C0
-#define MAC_CR_DFCHK_                  0x00000020
-#define MAC_CR_TXEN_                   0x00000008
-#define MAC_CR_RXEN_                   0x00000004
-
-#define ADDRH                          0x02
-
-#define ADDRL                          0x03
-
-#define HASHH                          0x04
-
-#define HASHL                          0x05
-
-#define MII_ACC                                0x06
-#define MII_ACC_PHY_ADDR_              0x0000F800
-#define MII_ACC_MIIRINDA_              0x000007C0
-#define MII_ACC_MII_WRITE_             0x00000002
-#define MII_ACC_MII_BUSY_              0x00000001
-
-#define MII_DATA                       0x07
-
-#define FLOW                           0x08
-#define FLOW_FCPT_                     0xFFFF0000
-#define FLOW_FCPASS_                   0x00000004
-#define FLOW_FCEN_                     0x00000002
-#define FLOW_FCBSY_                    0x00000001
-
-#define VLAN1                          0x09
-
-#define VLAN2                          0x0A
-
-#define WUFF                           0x0B
-
-#define WUCSR                          0x0C
-#define WUCSR_GUE_                     0x00000200
-#define WUCSR_WUFR_                    0x00000040
-#define WUCSR_MPR_                     0x00000020
-#define WUCSR_WAKE_EN_                 0x00000004
-#define WUCSR_MPEN_                    0x00000002
-
-/*
- * Phy definitions (vendor-specific)
- */
-#define LAN9118_PHY_ID                 0x00C0001C
-
-#define MII_INTSTS                     0x1D
-
-#define MII_INTMSK                     0x1E
-#define PHY_INTMSK_AN_RCV_             (1 << 1)
-#define PHY_INTMSK_PDFAULT_            (1 << 2)
-#define PHY_INTMSK_AN_ACK_             (1 << 3)
-#define PHY_INTMSK_LNKDOWN_            (1 << 4)
-#define PHY_INTMSK_RFAULT_             (1 << 5)
-#define PHY_INTMSK_AN_COMP_            (1 << 6)
-#define PHY_INTMSK_ENERGYON_           (1 << 7)
-#define PHY_INTMSK_DEFAULT_            (PHY_INTMSK_ENERGYON_ | \
-                                        PHY_INTMSK_AN_COMP_ | \
-                                        PHY_INTMSK_RFAULT_ | \
-                                        PHY_INTMSK_LNKDOWN_)
-
-#define ADVERTISE_PAUSE_ALL            (ADVERTISE_PAUSE_CAP | \
-                                        ADVERTISE_PAUSE_ASYM)
-
-#define LPA_PAUSE_ALL                  (LPA_PAUSE_CAP | \
-                                        LPA_PAUSE_ASYM)
-
-/*
- * Provide hooks to let the arch add to the initialisation procedure
- * and to override the source of the MAC address.
- */
-#define SMSC_INITIALIZE()              do {} while (0)
-#define smsc_get_mac(dev)              smsc911x_read_mac_address((dev))
-
-#ifdef CONFIG_SMSC911X_ARCH_HOOKS
-#include <asm/smsc911x.h>
-#endif
-
-#endif                         /* __SMSC911X_H__ */
diff --git a/drivers/net/smsc9420.c b/drivers/net/smsc9420.c
deleted file mode 100644 (file)
index 459726f..0000000
+++ /dev/null
@@ -1,1763 +0,0 @@
- /***************************************************************************
- *
- * Copyright (C) 2007,2008  SMSC
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU General Public License
- * as published by the Free Software Foundation; either version 2
- * of the License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
- *
- ***************************************************************************
- */
-
-#include <linux/interrupt.h>
-#include <linux/kernel.h>
-#include <linux/netdevice.h>
-#include <linux/phy.h>
-#include <linux/pci.h>
-#include <linux/if_vlan.h>
-#include <linux/dma-mapping.h>
-#include <linux/crc32.h>
-#include <linux/slab.h>
-#include <asm/unaligned.h>
-#include "smsc9420.h"
-
-#define DRV_NAME               "smsc9420"
-#define PFX                    DRV_NAME ": "
-#define DRV_MDIONAME           "smsc9420-mdio"
-#define DRV_DESCRIPTION                "SMSC LAN9420 driver"
-#define DRV_VERSION            "1.01"
-
-MODULE_LICENSE("GPL");
-MODULE_VERSION(DRV_VERSION);
-
-struct smsc9420_dma_desc {
-       u32 status;
-       u32 length;
-       u32 buffer1;
-       u32 buffer2;
-};
-
-struct smsc9420_ring_info {
-       struct sk_buff *skb;
-       dma_addr_t mapping;
-};
-
-struct smsc9420_pdata {
-       void __iomem *base_addr;
-       struct pci_dev *pdev;
-       struct net_device *dev;
-
-       struct smsc9420_dma_desc *rx_ring;
-       struct smsc9420_dma_desc *tx_ring;
-       struct smsc9420_ring_info *tx_buffers;
-       struct smsc9420_ring_info *rx_buffers;
-       dma_addr_t rx_dma_addr;
-       dma_addr_t tx_dma_addr;
-       int tx_ring_head, tx_ring_tail;
-       int rx_ring_head, rx_ring_tail;
-
-       spinlock_t int_lock;
-       spinlock_t phy_lock;
-
-       struct napi_struct napi;
-
-       bool software_irq_signal;
-       bool rx_csum;
-       u32 msg_enable;
-
-       struct phy_device *phy_dev;
-       struct mii_bus *mii_bus;
-       int phy_irq[PHY_MAX_ADDR];
-       int last_duplex;
-       int last_carrier;
-};
-
-static DEFINE_PCI_DEVICE_TABLE(smsc9420_id_table) = {
-       { PCI_VENDOR_ID_9420, PCI_DEVICE_ID_9420, PCI_ANY_ID, PCI_ANY_ID, },
-       { 0, }
-};
-
-MODULE_DEVICE_TABLE(pci, smsc9420_id_table);
-
-#define SMSC_MSG_DEFAULT (NETIF_MSG_DRV | NETIF_MSG_PROBE | NETIF_MSG_LINK)
-
-static uint smsc_debug;
-static uint debug = -1;
-module_param(debug, uint, 0);
-MODULE_PARM_DESC(debug, "debug level");
-
-#define smsc_dbg(TYPE, f, a...) \
-do {   if ((pd)->msg_enable & NETIF_MSG_##TYPE) \
-               printk(KERN_DEBUG PFX f "\n", ## a); \
-} while (0)
-
-#define smsc_info(TYPE, f, a...) \
-do {   if ((pd)->msg_enable & NETIF_MSG_##TYPE) \
-               printk(KERN_INFO PFX f "\n", ## a); \
-} while (0)
-
-#define smsc_warn(TYPE, f, a...) \
-do {   if ((pd)->msg_enable & NETIF_MSG_##TYPE) \
-               printk(KERN_WARNING PFX f "\n", ## a); \
-} while (0)
-
-static inline u32 smsc9420_reg_read(struct smsc9420_pdata *pd, u32 offset)
-{
-       return ioread32(pd->base_addr + offset);
-}
-
-static inline void
-smsc9420_reg_write(struct smsc9420_pdata *pd, u32 offset, u32 value)
-{
-       iowrite32(value, pd->base_addr + offset);
-}
-
-static inline void smsc9420_pci_flush_write(struct smsc9420_pdata *pd)
-{
-       /* to ensure PCI write completion, we must perform a PCI read */
-       smsc9420_reg_read(pd, ID_REV);
-}
-
-static int smsc9420_mii_read(struct mii_bus *bus, int phyaddr, int regidx)
-{
-       struct smsc9420_pdata *pd = (struct smsc9420_pdata *)bus->priv;
-       unsigned long flags;
-       u32 addr;
-       int i, reg = -EIO;
-
-       spin_lock_irqsave(&pd->phy_lock, flags);
-
-       /*  confirm MII not busy */
-       if ((smsc9420_reg_read(pd, MII_ACCESS) & MII_ACCESS_MII_BUSY_)) {
-               smsc_warn(DRV, "MII is busy???");
-               goto out;
-       }
-
-       /* set the address, index & direction (read from PHY) */
-       addr = ((phyaddr & 0x1F) << 11) | ((regidx & 0x1F) << 6) |
-               MII_ACCESS_MII_READ_;
-       smsc9420_reg_write(pd, MII_ACCESS, addr);
-
-       /* wait for read to complete with 50us timeout */
-       for (i = 0; i < 5; i++) {
-               if (!(smsc9420_reg_read(pd, MII_ACCESS) &
-                       MII_ACCESS_MII_BUSY_)) {
-                       reg = (u16)smsc9420_reg_read(pd, MII_DATA);
-                       goto out;
-               }
-               udelay(10);
-       }
-
-       smsc_warn(DRV, "MII busy timeout!");
-
-out:
-       spin_unlock_irqrestore(&pd->phy_lock, flags);
-       return reg;
-}
-
-static int smsc9420_mii_write(struct mii_bus *bus, int phyaddr, int regidx,
-                          u16 val)
-{
-       struct smsc9420_pdata *pd = (struct smsc9420_pdata *)bus->priv;
-       unsigned long flags;
-       u32 addr;
-       int i, reg = -EIO;
-
-       spin_lock_irqsave(&pd->phy_lock, flags);
-
-       /* confirm MII not busy */
-       if ((smsc9420_reg_read(pd, MII_ACCESS) & MII_ACCESS_MII_BUSY_)) {
-               smsc_warn(DRV, "MII is busy???");
-               goto out;
-       }
-
-       /* put the data to write in the MAC */
-       smsc9420_reg_write(pd, MII_DATA, (u32)val);
-
-       /* set the address, index & direction (write to PHY) */
-       addr = ((phyaddr & 0x1F) << 11) | ((regidx & 0x1F) << 6) |
-               MII_ACCESS_MII_WRITE_;
-       smsc9420_reg_write(pd, MII_ACCESS, addr);
-
-       /* wait for write to complete with 50us timeout */
-       for (i = 0; i < 5; i++) {
-               if (!(smsc9420_reg_read(pd, MII_ACCESS) &
-                       MII_ACCESS_MII_BUSY_)) {
-                       reg = 0;
-                       goto out;
-               }
-               udelay(10);
-       }
-
-       smsc_warn(DRV, "MII busy timeout!");
-
-out:
-       spin_unlock_irqrestore(&pd->phy_lock, flags);
-       return reg;
-}
-
-/* Returns hash bit number for given MAC address
- * Example:
- * 01 00 5E 00 00 01 -> returns bit number 31 */
-static u32 smsc9420_hash(u8 addr[ETH_ALEN])
-{
-       return (ether_crc(ETH_ALEN, addr) >> 26) & 0x3f;
-}
-
-static int smsc9420_eeprom_reload(struct smsc9420_pdata *pd)
-{
-       int timeout = 100000;
-
-       BUG_ON(!pd);
-
-       if (smsc9420_reg_read(pd, E2P_CMD) & E2P_CMD_EPC_BUSY_) {
-               smsc_dbg(DRV, "smsc9420_eeprom_reload: Eeprom busy");
-               return -EIO;
-       }
-
-       smsc9420_reg_write(pd, E2P_CMD,
-               (E2P_CMD_EPC_BUSY_ | E2P_CMD_EPC_CMD_RELOAD_));
-
-       do {
-               udelay(10);
-               if (!(smsc9420_reg_read(pd, E2P_CMD) & E2P_CMD_EPC_BUSY_))
-                       return 0;
-       } while (timeout--);
-
-       smsc_warn(DRV, "smsc9420_eeprom_reload: Eeprom timed out");
-       return -EIO;
-}
-
-/* Standard ioctls for mii-tool */
-static int smsc9420_do_ioctl(struct net_device *dev, struct ifreq *ifr, int cmd)
-{
-       struct smsc9420_pdata *pd = netdev_priv(dev);
-
-       if (!netif_running(dev) || !pd->phy_dev)
-               return -EINVAL;
-
-       return phy_mii_ioctl(pd->phy_dev, ifr, cmd);
-}
-
-static int smsc9420_ethtool_get_settings(struct net_device *dev,
-                                        struct ethtool_cmd *cmd)
-{
-       struct smsc9420_pdata *pd = netdev_priv(dev);
-
-       if (!pd->phy_dev)
-               return -ENODEV;
-
-       cmd->maxtxpkt = 1;
-       cmd->maxrxpkt = 1;
-       return phy_ethtool_gset(pd->phy_dev, cmd);
-}
-
-static int smsc9420_ethtool_set_settings(struct net_device *dev,
-                                        struct ethtool_cmd *cmd)
-{
-       struct smsc9420_pdata *pd = netdev_priv(dev);
-
-       if (!pd->phy_dev)
-               return -ENODEV;
-
-       return phy_ethtool_sset(pd->phy_dev, cmd);
-}
-
-static void smsc9420_ethtool_get_drvinfo(struct net_device *netdev,
-                                        struct ethtool_drvinfo *drvinfo)
-{
-       struct smsc9420_pdata *pd = netdev_priv(netdev);
-
-       strcpy(drvinfo->driver, DRV_NAME);
-       strcpy(drvinfo->bus_info, pci_name(pd->pdev));
-       strcpy(drvinfo->version, DRV_VERSION);
-}
-
-static u32 smsc9420_ethtool_get_msglevel(struct net_device *netdev)
-{
-       struct smsc9420_pdata *pd = netdev_priv(netdev);
-       return pd->msg_enable;
-}
-
-static void smsc9420_ethtool_set_msglevel(struct net_device *netdev, u32 data)
-{
-       struct smsc9420_pdata *pd = netdev_priv(netdev);
-       pd->msg_enable = data;
-}
-
-static int smsc9420_ethtool_nway_reset(struct net_device *netdev)
-{
-       struct smsc9420_pdata *pd = netdev_priv(netdev);
-
-       if (!pd->phy_dev)
-               return -ENODEV;
-
-       return phy_start_aneg(pd->phy_dev);
-}
-
-static int smsc9420_ethtool_getregslen(struct net_device *dev)
-{
-       /* all smsc9420 registers plus all phy registers */
-       return 0x100 + (32 * sizeof(u32));
-}
-
-static void
-smsc9420_ethtool_getregs(struct net_device *dev, struct ethtool_regs *regs,
-                        void *buf)
-{
-       struct smsc9420_pdata *pd = netdev_priv(dev);
-       struct phy_device *phy_dev = pd->phy_dev;
-       unsigned int i, j = 0;
-       u32 *data = buf;
-
-       regs->version = smsc9420_reg_read(pd, ID_REV);
-       for (i = 0; i < 0x100; i += (sizeof(u32)))
-               data[j++] = smsc9420_reg_read(pd, i);
-
-       // cannot read phy registers if the net device is down
-       if (!phy_dev)
-               return;
-
-       for (i = 0; i <= 31; i++)
-               data[j++] = smsc9420_mii_read(phy_dev->bus, phy_dev->addr, i);
-}
-
-static void smsc9420_eeprom_enable_access(struct smsc9420_pdata *pd)
-{
-       unsigned int temp = smsc9420_reg_read(pd, GPIO_CFG);
-       temp &= ~GPIO_CFG_EEPR_EN_;
-       smsc9420_reg_write(pd, GPIO_CFG, temp);
-       msleep(1);
-}
-
-static int smsc9420_eeprom_send_cmd(struct smsc9420_pdata *pd, u32 op)
-{
-       int timeout = 100;
-       u32 e2cmd;
-
-       smsc_dbg(HW, "op 0x%08x", op);
-       if (smsc9420_reg_read(pd, E2P_CMD) & E2P_CMD_EPC_BUSY_) {
-               smsc_warn(HW, "Busy at start");
-               return -EBUSY;
-       }
-
-       e2cmd = op | E2P_CMD_EPC_BUSY_;
-       smsc9420_reg_write(pd, E2P_CMD, e2cmd);
-
-       do {
-               msleep(1);
-               e2cmd = smsc9420_reg_read(pd, E2P_CMD);
-       } while ((e2cmd & E2P_CMD_EPC_BUSY_) && (--timeout));
-
-       if (!timeout) {
-               smsc_info(HW, "TIMED OUT");
-               return -EAGAIN;
-       }
-
-       if (e2cmd & E2P_CMD_EPC_TIMEOUT_) {
-               smsc_info(HW, "Error occurred during eeprom operation");
-               return -EINVAL;
-       }
-
-       return 0;
-}
-
-static int smsc9420_eeprom_read_location(struct smsc9420_pdata *pd,
-                                        u8 address, u8 *data)
-{
-       u32 op = E2P_CMD_EPC_CMD_READ_ | address;
-       int ret;
-
-       smsc_dbg(HW, "address 0x%x", address);
-       ret = smsc9420_eeprom_send_cmd(pd, op);
-
-       if (!ret)
-               data[address] = smsc9420_reg_read(pd, E2P_DATA);
-
-       return ret;
-}
-
-static int smsc9420_eeprom_write_location(struct smsc9420_pdata *pd,
-                                         u8 address, u8 data)
-{
-       u32 op = E2P_CMD_EPC_CMD_ERASE_ | address;
-       int ret;
-
-       smsc_dbg(HW, "address 0x%x, data 0x%x", address, data);
-       ret = smsc9420_eeprom_send_cmd(pd, op);
-
-       if (!ret) {
-               op = E2P_CMD_EPC_CMD_WRITE_ | address;
-               smsc9420_reg_write(pd, E2P_DATA, (u32)data);
-               ret = smsc9420_eeprom_send_cmd(pd, op);
-       }
-
-       return ret;
-}
-
-static int smsc9420_ethtool_get_eeprom_len(struct net_device *dev)
-{
-       return SMSC9420_EEPROM_SIZE;
-}
-
-static int smsc9420_ethtool_get_eeprom(struct net_device *dev,
-                                      struct ethtool_eeprom *eeprom, u8 *data)
-{
-       struct smsc9420_pdata *pd = netdev_priv(dev);
-       u8 eeprom_data[SMSC9420_EEPROM_SIZE];
-       int len, i;
-
-       smsc9420_eeprom_enable_access(pd);
-
-       len = min(eeprom->len, SMSC9420_EEPROM_SIZE);
-       for (i = 0; i < len; i++) {
-               int ret = smsc9420_eeprom_read_location(pd, i, eeprom_data);
-               if (ret < 0) {
-                       eeprom->len = 0;
-                       return ret;
-               }
-       }
-
-       memcpy(data, &eeprom_data[eeprom->offset], len);
-       eeprom->magic = SMSC9420_EEPROM_MAGIC;
-       eeprom->len = len;
-       return 0;
-}
-
-static int smsc9420_ethtool_set_eeprom(struct net_device *dev,
-                                      struct ethtool_eeprom *eeprom, u8 *data)
-{
-       struct smsc9420_pdata *pd = netdev_priv(dev);
-       int ret;
-
-       if (eeprom->magic != SMSC9420_EEPROM_MAGIC)
-               return -EINVAL;
-
-       smsc9420_eeprom_enable_access(pd);
-       smsc9420_eeprom_send_cmd(pd, E2P_CMD_EPC_CMD_EWEN_);
-       ret = smsc9420_eeprom_write_location(pd, eeprom->offset, *data);
-       smsc9420_eeprom_send_cmd(pd, E2P_CMD_EPC_CMD_EWDS_);
-
-       /* Single byte write, according to man page */
-       eeprom->len = 1;
-
-       return ret;
-}
-
-static const struct ethtool_ops smsc9420_ethtool_ops = {
-       .get_settings = smsc9420_ethtool_get_settings,
-       .set_settings = smsc9420_ethtool_set_settings,
-       .get_drvinfo = smsc9420_ethtool_get_drvinfo,
-       .get_msglevel = smsc9420_ethtool_get_msglevel,
-       .set_msglevel = smsc9420_ethtool_set_msglevel,
-       .nway_reset = smsc9420_ethtool_nway_reset,
-       .get_link = ethtool_op_get_link,
-       .get_eeprom_len = smsc9420_ethtool_get_eeprom_len,
-       .get_eeprom = smsc9420_ethtool_get_eeprom,
-       .set_eeprom = smsc9420_ethtool_set_eeprom,
-       .get_regs_len = smsc9420_ethtool_getregslen,
-       .get_regs = smsc9420_ethtool_getregs,
-};
-
-/* Sets the device MAC address to dev_addr */
-static void smsc9420_set_mac_address(struct net_device *dev)
-{
-       struct smsc9420_pdata *pd = netdev_priv(dev);
-       u8 *dev_addr = dev->dev_addr;
-       u32 mac_high16 = (dev_addr[5] << 8) | dev_addr[4];
-       u32 mac_low32 = (dev_addr[3] << 24) | (dev_addr[2] << 16) |
-           (dev_addr[1] << 8) | dev_addr[0];
-
-       smsc9420_reg_write(pd, ADDRH, mac_high16);
-       smsc9420_reg_write(pd, ADDRL, mac_low32);
-}
-
-static void smsc9420_check_mac_address(struct net_device *dev)
-{
-       struct smsc9420_pdata *pd = netdev_priv(dev);
-
-       /* Check if mac address has been specified when bringing interface up */
-       if (is_valid_ether_addr(dev->dev_addr)) {
-               smsc9420_set_mac_address(dev);
-               smsc_dbg(PROBE, "MAC Address is specified by configuration");
-       } else {
-               /* Try reading mac address from device. if EEPROM is present
-                * it will already have been set */
-               u32 mac_high16 = smsc9420_reg_read(pd, ADDRH);
-               u32 mac_low32 = smsc9420_reg_read(pd, ADDRL);
-               dev->dev_addr[0] = (u8)(mac_low32);
-               dev->dev_addr[1] = (u8)(mac_low32 >> 8);
-               dev->dev_addr[2] = (u8)(mac_low32 >> 16);
-               dev->dev_addr[3] = (u8)(mac_low32 >> 24);
-               dev->dev_addr[4] = (u8)(mac_high16);
-               dev->dev_addr[5] = (u8)(mac_high16 >> 8);
-
-               if (is_valid_ether_addr(dev->dev_addr)) {
-                       /* eeprom values are valid  so use them */
-                       smsc_dbg(PROBE, "Mac Address is read from EEPROM");
-               } else {
-                       /* eeprom values are invalid, generate random MAC */
-                       random_ether_addr(dev->dev_addr);
-                       smsc9420_set_mac_address(dev);
-                       smsc_dbg(PROBE,
-                               "MAC Address is set to random_ether_addr");
-               }
-       }
-}
-
-static void smsc9420_stop_tx(struct smsc9420_pdata *pd)
-{
-       u32 dmac_control, mac_cr, dma_intr_ena;
-       int timeout = 1000;
-
-       /* disable TX DMAC */
-       dmac_control = smsc9420_reg_read(pd, DMAC_CONTROL);
-       dmac_control &= (~DMAC_CONTROL_ST_);
-       smsc9420_reg_write(pd, DMAC_CONTROL, dmac_control);
-
-       /* Wait max 10ms for transmit process to stop */
-       while (--timeout) {
-               if (smsc9420_reg_read(pd, DMAC_STATUS) & DMAC_STS_TS_)
-                       break;
-               udelay(10);
-       }
-
-       if (!timeout)
-               smsc_warn(IFDOWN, "TX DMAC failed to stop");
-
-       /* ACK Tx DMAC stop bit */
-       smsc9420_reg_write(pd, DMAC_STATUS, DMAC_STS_TXPS_);
-
-       /* mask TX DMAC interrupts */
-       dma_intr_ena = smsc9420_reg_read(pd, DMAC_INTR_ENA);
-       dma_intr_ena &= ~(DMAC_INTR_ENA_TX_);
-       smsc9420_reg_write(pd, DMAC_INTR_ENA, dma_intr_ena);
-       smsc9420_pci_flush_write(pd);
-
-       /* stop MAC TX */
-       mac_cr = smsc9420_reg_read(pd, MAC_CR) & (~MAC_CR_TXEN_);
-       smsc9420_reg_write(pd, MAC_CR, mac_cr);
-       smsc9420_pci_flush_write(pd);
-}
-
-static void smsc9420_free_tx_ring(struct smsc9420_pdata *pd)
-{
-       int i;
-
-       BUG_ON(!pd->tx_ring);
-
-       if (!pd->tx_buffers)
-               return;
-
-       for (i = 0; i < TX_RING_SIZE; i++) {
-               struct sk_buff *skb = pd->tx_buffers[i].skb;
-
-               if (skb) {
-                       BUG_ON(!pd->tx_buffers[i].mapping);
-                       pci_unmap_single(pd->pdev, pd->tx_buffers[i].mapping,
-                                        skb->len, PCI_DMA_TODEVICE);
-                       dev_kfree_skb_any(skb);
-               }
-
-               pd->tx_ring[i].status = 0;
-               pd->tx_ring[i].length = 0;
-               pd->tx_ring[i].buffer1 = 0;
-               pd->tx_ring[i].buffer2 = 0;
-       }
-       wmb();
-
-       kfree(pd->tx_buffers);
-       pd->tx_buffers = NULL;
-
-       pd->tx_ring_head = 0;
-       pd->tx_ring_tail = 0;
-}
-
-static void smsc9420_free_rx_ring(struct smsc9420_pdata *pd)
-{
-       int i;
-
-       BUG_ON(!pd->rx_ring);
-
-       if (!pd->rx_buffers)
-               return;
-
-       for (i = 0; i < RX_RING_SIZE; i++) {
-               if (pd->rx_buffers[i].skb)
-                       dev_kfree_skb_any(pd->rx_buffers[i].skb);
-
-               if (pd->rx_buffers[i].mapping)
-                       pci_unmap_single(pd->pdev, pd->rx_buffers[i].mapping,
-                               PKT_BUF_SZ, PCI_DMA_FROMDEVICE);
-
-               pd->rx_ring[i].status = 0;
-               pd->rx_ring[i].length = 0;
-               pd->rx_ring[i].buffer1 = 0;
-               pd->rx_ring[i].buffer2 = 0;
-       }
-       wmb();
-
-       kfree(pd->rx_buffers);
-       pd->rx_buffers = NULL;
-
-       pd->rx_ring_head = 0;
-       pd->rx_ring_tail = 0;
-}
-
-static void smsc9420_stop_rx(struct smsc9420_pdata *pd)
-{
-       int timeout = 1000;
-       u32 mac_cr, dmac_control, dma_intr_ena;
-
-       /* mask RX DMAC interrupts */
-       dma_intr_ena = smsc9420_reg_read(pd, DMAC_INTR_ENA);
-       dma_intr_ena &= (~DMAC_INTR_ENA_RX_);
-       smsc9420_reg_write(pd, DMAC_INTR_ENA, dma_intr_ena);
-       smsc9420_pci_flush_write(pd);
-
-       /* stop RX MAC prior to stoping DMA */
-       mac_cr = smsc9420_reg_read(pd, MAC_CR) & (~MAC_CR_RXEN_);
-       smsc9420_reg_write(pd, MAC_CR, mac_cr);
-       smsc9420_pci_flush_write(pd);
-
-       /* stop RX DMAC */
-       dmac_control = smsc9420_reg_read(pd, DMAC_CONTROL);
-       dmac_control &= (~DMAC_CONTROL_SR_);
-       smsc9420_reg_write(pd, DMAC_CONTROL, dmac_control);
-       smsc9420_pci_flush_write(pd);
-
-       /* wait up to 10ms for receive to stop */
-       while (--timeout) {
-               if (smsc9420_reg_read(pd, DMAC_STATUS) & DMAC_STS_RS_)
-                       break;
-               udelay(10);
-       }
-
-       if (!timeout)
-               smsc_warn(IFDOWN, "RX DMAC did not stop! timeout.");
-
-       /* ACK the Rx DMAC stop bit */
-       smsc9420_reg_write(pd, DMAC_STATUS, DMAC_STS_RXPS_);
-}
-
-static irqreturn_t smsc9420_isr(int irq, void *dev_id)
-{
-       struct smsc9420_pdata *pd = dev_id;
-       u32 int_cfg, int_sts, int_ctl;
-       irqreturn_t ret = IRQ_NONE;
-       ulong flags;
-
-       BUG_ON(!pd);
-       BUG_ON(!pd->base_addr);
-
-       int_cfg = smsc9420_reg_read(pd, INT_CFG);
-
-       /* check if it's our interrupt */
-       if ((int_cfg & (INT_CFG_IRQ_EN_ | INT_CFG_IRQ_INT_)) !=
-           (INT_CFG_IRQ_EN_ | INT_CFG_IRQ_INT_))
-               return IRQ_NONE;
-
-       int_sts = smsc9420_reg_read(pd, INT_STAT);
-
-       if (likely(INT_STAT_DMAC_INT_ & int_sts)) {
-               u32 status = smsc9420_reg_read(pd, DMAC_STATUS);
-               u32 ints_to_clear = 0;
-
-               if (status & DMAC_STS_TX_) {
-                       ints_to_clear |= (DMAC_STS_TX_ | DMAC_STS_NIS_);
-                       netif_wake_queue(pd->dev);
-               }
-
-               if (status & DMAC_STS_RX_) {
-                       /* mask RX DMAC interrupts */
-                       u32 dma_intr_ena = smsc9420_reg_read(pd, DMAC_INTR_ENA);
-                       dma_intr_ena &= (~DMAC_INTR_ENA_RX_);
-                       smsc9420_reg_write(pd, DMAC_INTR_ENA, dma_intr_ena);
-                       smsc9420_pci_flush_write(pd);
-
-                       ints_to_clear |= (DMAC_STS_RX_ | DMAC_STS_NIS_);
-                       napi_schedule(&pd->napi);
-               }
-
-               if (ints_to_clear)
-                       smsc9420_reg_write(pd, DMAC_STATUS, ints_to_clear);
-
-               ret = IRQ_HANDLED;
-       }
-
-       if (unlikely(INT_STAT_SW_INT_ & int_sts)) {
-               /* mask software interrupt */
-               spin_lock_irqsave(&pd->int_lock, flags);
-               int_ctl = smsc9420_reg_read(pd, INT_CTL);
-               int_ctl &= (~INT_CTL_SW_INT_EN_);
-               smsc9420_reg_write(pd, INT_CTL, int_ctl);
-               spin_unlock_irqrestore(&pd->int_lock, flags);
-
-               smsc9420_reg_write(pd, INT_STAT, INT_STAT_SW_INT_);
-               pd->software_irq_signal = true;
-               smp_wmb();
-
-               ret = IRQ_HANDLED;
-       }
-
-       /* to ensure PCI write completion, we must perform a PCI read */
-       smsc9420_pci_flush_write(pd);
-
-       return ret;
-}
-
-#ifdef CONFIG_NET_POLL_CONTROLLER
-static void smsc9420_poll_controller(struct net_device *dev)
-{
-       disable_irq(dev->irq);
-       smsc9420_isr(0, dev);
-       enable_irq(dev->irq);
-}
-#endif /* CONFIG_NET_POLL_CONTROLLER */
-
-static void smsc9420_dmac_soft_reset(struct smsc9420_pdata *pd)
-{
-       smsc9420_reg_write(pd, BUS_MODE, BUS_MODE_SWR_);
-       smsc9420_reg_read(pd, BUS_MODE);
-       udelay(2);
-       if (smsc9420_reg_read(pd, BUS_MODE) & BUS_MODE_SWR_)
-               smsc_warn(DRV, "Software reset not cleared");
-}
-
-static int smsc9420_stop(struct net_device *dev)
-{
-       struct smsc9420_pdata *pd = netdev_priv(dev);
-       u32 int_cfg;
-       ulong flags;
-
-       BUG_ON(!pd);
-       BUG_ON(!pd->phy_dev);
-
-       /* disable master interrupt */
-       spin_lock_irqsave(&pd->int_lock, flags);
-       int_cfg = smsc9420_reg_read(pd, INT_CFG) & (~INT_CFG_IRQ_EN_);
-       smsc9420_reg_write(pd, INT_CFG, int_cfg);
-       spin_unlock_irqrestore(&pd->int_lock, flags);
-
-       netif_tx_disable(dev);
-       napi_disable(&pd->napi);
-
-       smsc9420_stop_tx(pd);
-       smsc9420_free_tx_ring(pd);
-
-       smsc9420_stop_rx(pd);
-       smsc9420_free_rx_ring(pd);
-
-       free_irq(dev->irq, pd);
-
-       smsc9420_dmac_soft_reset(pd);
-
-       phy_stop(pd->phy_dev);
-
-       phy_disconnect(pd->phy_dev);
-       pd->phy_dev = NULL;
-       mdiobus_unregister(pd->mii_bus);
-       mdiobus_free(pd->mii_bus);
-
-       return 0;
-}
-
-static void smsc9420_rx_count_stats(struct net_device *dev, u32 desc_status)
-{
-       if (unlikely(desc_status & RDES0_ERROR_SUMMARY_)) {
-               dev->stats.rx_errors++;
-               if (desc_status & RDES0_DESCRIPTOR_ERROR_)
-                       dev->stats.rx_over_errors++;
-               else if (desc_status & (RDES0_FRAME_TOO_LONG_ |
-                       RDES0_RUNT_FRAME_ | RDES0_COLLISION_SEEN_))
-                       dev->stats.rx_frame_errors++;
-               else if (desc_status & RDES0_CRC_ERROR_)
-                       dev->stats.rx_crc_errors++;
-       }
-
-       if (unlikely(desc_status & RDES0_LENGTH_ERROR_))
-               dev->stats.rx_length_errors++;
-
-       if (unlikely(!((desc_status & RDES0_LAST_DESCRIPTOR_) &&
-               (desc_status & RDES0_FIRST_DESCRIPTOR_))))
-               dev->stats.rx_length_errors++;
-
-       if (desc_status & RDES0_MULTICAST_FRAME_)
-               dev->stats.multicast++;
-}
-
-static void smsc9420_rx_handoff(struct smsc9420_pdata *pd, const int index,
-                               const u32 status)
-{
-       struct net_device *dev = pd->dev;
-       struct sk_buff *skb;
-       u16 packet_length = (status & RDES0_FRAME_LENGTH_MASK_)
-               >> RDES0_FRAME_LENGTH_SHFT_;
-
-       /* remove crc from packet lendth */
-       packet_length -= 4;
-
-       if (pd->rx_csum)
-               packet_length -= 2;
-
-       dev->stats.rx_packets++;
-       dev->stats.rx_bytes += packet_length;
-
-       pci_unmap_single(pd->pdev, pd->rx_buffers[index].mapping,
-               PKT_BUF_SZ, PCI_DMA_FROMDEVICE);
-       pd->rx_buffers[index].mapping = 0;
-
-       skb = pd->rx_buffers[index].skb;
-       pd->rx_buffers[index].skb = NULL;
-
-       if (pd->rx_csum) {
-               u16 hw_csum = get_unaligned_le16(skb_tail_pointer(skb) +
-                       NET_IP_ALIGN + packet_length + 4);
-               put_unaligned_le16(hw_csum, &skb->csum);
-               skb->ip_summed = CHECKSUM_COMPLETE;
-       }
-
-       skb_reserve(skb, NET_IP_ALIGN);
-       skb_put(skb, packet_length);
-
-       skb->protocol = eth_type_trans(skb, dev);
-
-       netif_receive_skb(skb);
-}
-
-static int smsc9420_alloc_rx_buffer(struct smsc9420_pdata *pd, int index)
-{
-       struct sk_buff *skb = netdev_alloc_skb(pd->dev, PKT_BUF_SZ);
-       dma_addr_t mapping;
-
-       BUG_ON(pd->rx_buffers[index].skb);
-       BUG_ON(pd->rx_buffers[index].mapping);
-
-       if (unlikely(!skb)) {
-               smsc_warn(RX_ERR, "Failed to allocate new skb!");
-               return -ENOMEM;
-       }
-
-       skb->dev = pd->dev;
-
-       mapping = pci_map_single(pd->pdev, skb_tail_pointer(skb),
-                                PKT_BUF_SZ, PCI_DMA_FROMDEVICE);
-       if (pci_dma_mapping_error(pd->pdev, mapping)) {
-               dev_kfree_skb_any(skb);
-               smsc_warn(RX_ERR, "pci_map_single failed!");
-               return -ENOMEM;
-       }
-
-       pd->rx_buffers[index].skb = skb;
-       pd->rx_buffers[index].mapping = mapping;
-       pd->rx_ring[index].buffer1 = mapping + NET_IP_ALIGN;
-       pd->rx_ring[index].status = RDES0_OWN_;
-       wmb();
-
-       return 0;
-}
-
-static void smsc9420_alloc_new_rx_buffers(struct smsc9420_pdata *pd)
-{
-       while (pd->rx_ring_tail != pd->rx_ring_head) {
-               if (smsc9420_alloc_rx_buffer(pd, pd->rx_ring_tail))
-                       break;
-
-               pd->rx_ring_tail = (pd->rx_ring_tail + 1) % RX_RING_SIZE;
-       }
-}
-
-static int smsc9420_rx_poll(struct napi_struct *napi, int budget)
-{
-       struct smsc9420_pdata *pd =
-               container_of(napi, struct smsc9420_pdata, napi);
-       struct net_device *dev = pd->dev;
-       u32 drop_frame_cnt, dma_intr_ena, status;
-       int work_done;
-
-       for (work_done = 0; work_done < budget; work_done++) {
-               rmb();
-               status = pd->rx_ring[pd->rx_ring_head].status;
-
-               /* stop if DMAC owns this dma descriptor */
-               if (status & RDES0_OWN_)
-                       break;
-
-               smsc9420_rx_count_stats(dev, status);
-               smsc9420_rx_handoff(pd, pd->rx_ring_head, status);
-               pd->rx_ring_head = (pd->rx_ring_head + 1) % RX_RING_SIZE;
-               smsc9420_alloc_new_rx_buffers(pd);
-       }
-
-       drop_frame_cnt = smsc9420_reg_read(pd, MISS_FRAME_CNTR);
-       dev->stats.rx_dropped +=
-           (drop_frame_cnt & 0xFFFF) + ((drop_frame_cnt >> 17) & 0x3FF);
-
-       /* Kick RXDMA */
-       smsc9420_reg_write(pd, RX_POLL_DEMAND, 1);
-       smsc9420_pci_flush_write(pd);
-
-       if (work_done < budget) {
-               napi_complete(&pd->napi);
-
-               /* re-enable RX DMA interrupts */
-               dma_intr_ena = smsc9420_reg_read(pd, DMAC_INTR_ENA);
-               dma_intr_ena |= (DMAC_INTR_ENA_RX_ | DMAC_INTR_ENA_NIS_);
-               smsc9420_reg_write(pd, DMAC_INTR_ENA, dma_intr_ena);
-               smsc9420_pci_flush_write(pd);
-       }
-       return work_done;
-}
-
-static void
-smsc9420_tx_update_stats(struct net_device *dev, u32 status, u32 length)
-{
-       if (unlikely(status & TDES0_ERROR_SUMMARY_)) {
-               dev->stats.tx_errors++;
-               if (status & (TDES0_EXCESSIVE_DEFERRAL_ |
-                       TDES0_EXCESSIVE_COLLISIONS_))
-                       dev->stats.tx_aborted_errors++;
-
-               if (status & (TDES0_LOSS_OF_CARRIER_ | TDES0_NO_CARRIER_))
-                       dev->stats.tx_carrier_errors++;
-       } else {
-               dev->stats.tx_packets++;
-               dev->stats.tx_bytes += (length & 0x7FF);
-       }
-
-       if (unlikely(status & TDES0_EXCESSIVE_COLLISIONS_)) {
-               dev->stats.collisions += 16;
-       } else {
-               dev->stats.collisions +=
-                       (status & TDES0_COLLISION_COUNT_MASK_) >>
-                       TDES0_COLLISION_COUNT_SHFT_;
-       }
-
-       if (unlikely(status & TDES0_HEARTBEAT_FAIL_))
-               dev->stats.tx_heartbeat_errors++;
-}
-
-/* Check for completed dma transfers, update stats and free skbs */
-static void smsc9420_complete_tx(struct net_device *dev)
-{
-       struct smsc9420_pdata *pd = netdev_priv(dev);
-
-       while (pd->tx_ring_tail != pd->tx_ring_head) {
-               int index = pd->tx_ring_tail;
-               u32 status, length;
-
-               rmb();
-               status = pd->tx_ring[index].status;
-               length = pd->tx_ring[index].length;
-
-               /* Check if DMA still owns this descriptor */
-               if (unlikely(TDES0_OWN_ & status))
-                       break;
-
-               smsc9420_tx_update_stats(dev, status, length);
-
-               BUG_ON(!pd->tx_buffers[index].skb);
-               BUG_ON(!pd->tx_buffers[index].mapping);
-
-               pci_unmap_single(pd->pdev, pd->tx_buffers[index].mapping,
-                       pd->tx_buffers[index].skb->len, PCI_DMA_TODEVICE);
-               pd->tx_buffers[index].mapping = 0;
-
-               dev_kfree_skb_any(pd->tx_buffers[index].skb);
-               pd->tx_buffers[index].skb = NULL;
-
-               pd->tx_ring[index].buffer1 = 0;
-               wmb();
-
-               pd->tx_ring_tail = (pd->tx_ring_tail + 1) % TX_RING_SIZE;
-       }
-}
-
-static netdev_tx_t smsc9420_hard_start_xmit(struct sk_buff *skb,
-                                           struct net_device *dev)
-{
-       struct smsc9420_pdata *pd = netdev_priv(dev);
-       dma_addr_t mapping;
-       int index = pd->tx_ring_head;
-       u32 tmp_desc1;
-       bool about_to_take_last_desc =
-               (((pd->tx_ring_head + 2) % TX_RING_SIZE) == pd->tx_ring_tail);
-
-       smsc9420_complete_tx(dev);
-
-       rmb();
-       BUG_ON(pd->tx_ring[index].status & TDES0_OWN_);
-       BUG_ON(pd->tx_buffers[index].skb);
-       BUG_ON(pd->tx_buffers[index].mapping);
-
-       mapping = pci_map_single(pd->pdev, skb->data,
-                                skb->len, PCI_DMA_TODEVICE);
-       if (pci_dma_mapping_error(pd->pdev, mapping)) {
-               smsc_warn(TX_ERR, "pci_map_single failed, dropping packet");
-               return NETDEV_TX_BUSY;
-       }
-
-       pd->tx_buffers[index].skb = skb;
-       pd->tx_buffers[index].mapping = mapping;
-
-       tmp_desc1 = (TDES1_LS_ | ((u32)skb->len & 0x7FF));
-       if (unlikely(about_to_take_last_desc)) {
-               tmp_desc1 |= TDES1_IC_;
-               netif_stop_queue(pd->dev);
-       }
-
-       /* check if we are at the last descriptor and need to set EOR */
-       if (unlikely(index == (TX_RING_SIZE - 1)))
-               tmp_desc1 |= TDES1_TER_;
-
-       pd->tx_ring[index].buffer1 = mapping;
-       pd->tx_ring[index].length = tmp_desc1;
-       wmb();
-
-       /* increment head */
-       pd->tx_ring_head = (pd->tx_ring_head + 1) % TX_RING_SIZE;
-
-       /* assign ownership to DMAC */
-       pd->tx_ring[index].status = TDES0_OWN_;
-       wmb();
-
-       skb_tx_timestamp(skb);
-
-       /* kick the DMA */
-       smsc9420_reg_write(pd, TX_POLL_DEMAND, 1);
-       smsc9420_pci_flush_write(pd);
-
-       return NETDEV_TX_OK;
-}
-
-static struct net_device_stats *smsc9420_get_stats(struct net_device *dev)
-{
-       struct smsc9420_pdata *pd = netdev_priv(dev);
-       u32 counter = smsc9420_reg_read(pd, MISS_FRAME_CNTR);
-       dev->stats.rx_dropped +=
-           (counter & 0x0000FFFF) + ((counter >> 17) & 0x000003FF);
-       return &dev->stats;
-}
-
-static void smsc9420_set_multicast_list(struct net_device *dev)
-{
-       struct smsc9420_pdata *pd = netdev_priv(dev);
-       u32 mac_cr = smsc9420_reg_read(pd, MAC_CR);
-
-       if (dev->flags & IFF_PROMISC) {
-               smsc_dbg(HW, "Promiscuous Mode Enabled");
-               mac_cr |= MAC_CR_PRMS_;
-               mac_cr &= (~MAC_CR_MCPAS_);
-               mac_cr &= (~MAC_CR_HPFILT_);
-       } else if (dev->flags & IFF_ALLMULTI) {
-               smsc_dbg(HW, "Receive all Multicast Enabled");
-               mac_cr &= (~MAC_CR_PRMS_);
-               mac_cr |= MAC_CR_MCPAS_;
-               mac_cr &= (~MAC_CR_HPFILT_);
-       } else if (!netdev_mc_empty(dev)) {
-               struct netdev_hw_addr *ha;
-               u32 hash_lo = 0, hash_hi = 0;
-
-               smsc_dbg(HW, "Multicast filter enabled");
-               netdev_for_each_mc_addr(ha, dev) {
-                       u32 bit_num = smsc9420_hash(ha->addr);
-                       u32 mask = 1 << (bit_num & 0x1F);
-
-                       if (bit_num & 0x20)
-                               hash_hi |= mask;
-                       else
-                               hash_lo |= mask;
-
-               }
-               smsc9420_reg_write(pd, HASHH, hash_hi);
-               smsc9420_reg_write(pd, HASHL, hash_lo);
-
-               mac_cr &= (~MAC_CR_PRMS_);
-               mac_cr &= (~MAC_CR_MCPAS_);
-               mac_cr |= MAC_CR_HPFILT_;
-       } else {
-               smsc_dbg(HW, "Receive own packets only.");
-               smsc9420_reg_write(pd, HASHH, 0);
-               smsc9420_reg_write(pd, HASHL, 0);
-
-               mac_cr &= (~MAC_CR_PRMS_);
-               mac_cr &= (~MAC_CR_MCPAS_);
-               mac_cr &= (~MAC_CR_HPFILT_);
-       }
-
-       smsc9420_reg_write(pd, MAC_CR, mac_cr);
-       smsc9420_pci_flush_write(pd);
-}
-
-static void smsc9420_phy_update_flowcontrol(struct smsc9420_pdata *pd)
-{
-       struct phy_device *phy_dev = pd->phy_dev;
-       u32 flow;
-
-       if (phy_dev->duplex == DUPLEX_FULL) {
-               u16 lcladv = phy_read(phy_dev, MII_ADVERTISE);
-               u16 rmtadv = phy_read(phy_dev, MII_LPA);
-               u8 cap = mii_resolve_flowctrl_fdx(lcladv, rmtadv);
-
-               if (cap & FLOW_CTRL_RX)
-                       flow = 0xFFFF0002;
-               else
-                       flow = 0;
-
-               smsc_info(LINK, "rx pause %s, tx pause %s",
-                       (cap & FLOW_CTRL_RX ? "enabled" : "disabled"),
-                       (cap & FLOW_CTRL_TX ? "enabled" : "disabled"));
-       } else {
-               smsc_info(LINK, "half duplex");
-               flow = 0;
-       }
-
-       smsc9420_reg_write(pd, FLOW, flow);
-}
-
-/* Update link mode if anything has changed.  Called periodically when the
- * PHY is in polling mode, even if nothing has changed. */
-static void smsc9420_phy_adjust_link(struct net_device *dev)
-{
-       struct smsc9420_pdata *pd = netdev_priv(dev);
-       struct phy_device *phy_dev = pd->phy_dev;
-       int carrier;
-
-       if (phy_dev->duplex != pd->last_duplex) {
-               u32 mac_cr = smsc9420_reg_read(pd, MAC_CR);
-               if (phy_dev->duplex) {
-                       smsc_dbg(LINK, "full duplex mode");
-                       mac_cr |= MAC_CR_FDPX_;
-               } else {
-                       smsc_dbg(LINK, "half duplex mode");
-                       mac_cr &= ~MAC_CR_FDPX_;
-               }
-               smsc9420_reg_write(pd, MAC_CR, mac_cr);
-
-               smsc9420_phy_update_flowcontrol(pd);
-               pd->last_duplex = phy_dev->duplex;
-       }
-
-       carrier = netif_carrier_ok(dev);
-       if (carrier != pd->last_carrier) {
-               if (carrier)
-                       smsc_dbg(LINK, "carrier OK");
-               else
-                       smsc_dbg(LINK, "no carrier");
-               pd->last_carrier = carrier;
-       }
-}
-
-static int smsc9420_mii_probe(struct net_device *dev)
-{
-       struct smsc9420_pdata *pd = netdev_priv(dev);
-       struct phy_device *phydev = NULL;
-
-       BUG_ON(pd->phy_dev);
-
-       /* Device only supports internal PHY at address 1 */
-       if (!pd->mii_bus->phy_map[1]) {
-               pr_err("%s: no PHY found at address 1\n", dev->name);
-               return -ENODEV;
-       }
-
-       phydev = pd->mii_bus->phy_map[1];
-       smsc_info(PROBE, "PHY addr %d, phy_id 0x%08X", phydev->addr,
-               phydev->phy_id);
-
-       phydev = phy_connect(dev, dev_name(&phydev->dev),
-               smsc9420_phy_adjust_link, 0, PHY_INTERFACE_MODE_MII);
-
-       if (IS_ERR(phydev)) {
-               pr_err("%s: Could not attach to PHY\n", dev->name);
-               return PTR_ERR(phydev);
-       }
-
-       pr_info("%s: attached PHY driver [%s] (mii_bus:phy_addr=%s, irq=%d)\n",
-               dev->name, phydev->drv->name, dev_name(&phydev->dev), phydev->irq);
-
-       /* mask with MAC supported features */
-       phydev->supported &= (PHY_BASIC_FEATURES | SUPPORTED_Pause |
-                             SUPPORTED_Asym_Pause);
-       phydev->advertising = phydev->supported;
-
-       pd->phy_dev = phydev;
-       pd->last_duplex = -1;
-       pd->last_carrier = -1;
-
-       return 0;
-}
-
-static int smsc9420_mii_init(struct net_device *dev)
-{
-       struct smsc9420_pdata *pd = netdev_priv(dev);
-       int err = -ENXIO, i;
-
-       pd->mii_bus = mdiobus_alloc();
-       if (!pd->mii_bus) {
-               err = -ENOMEM;
-               goto err_out_1;
-       }
-       pd->mii_bus->name = DRV_MDIONAME;
-       snprintf(pd->mii_bus->id, MII_BUS_ID_SIZE, "%x",
-               (pd->pdev->bus->number << 8) | pd->pdev->devfn);
-       pd->mii_bus->priv = pd;
-       pd->mii_bus->read = smsc9420_mii_read;
-       pd->mii_bus->write = smsc9420_mii_write;
-       pd->mii_bus->irq = pd->phy_irq;
-       for (i = 0; i < PHY_MAX_ADDR; ++i)
-               pd->mii_bus->irq[i] = PHY_POLL;
-
-       /* Mask all PHYs except ID 1 (internal) */
-       pd->mii_bus->phy_mask = ~(1 << 1);
-
-       if (mdiobus_register(pd->mii_bus)) {
-               smsc_warn(PROBE, "Error registering mii bus");
-               goto err_out_free_bus_2;
-       }
-
-       if (smsc9420_mii_probe(dev) < 0) {
-               smsc_warn(PROBE, "Error probing mii bus");
-               goto err_out_unregister_bus_3;
-       }
-
-       return 0;
-
-err_out_unregister_bus_3:
-       mdiobus_unregister(pd->mii_bus);
-err_out_free_bus_2:
-       mdiobus_free(pd->mii_bus);
-err_out_1:
-       return err;
-}
-
-static int smsc9420_alloc_tx_ring(struct smsc9420_pdata *pd)
-{
-       int i;
-
-       BUG_ON(!pd->tx_ring);
-
-       pd->tx_buffers = kmalloc((sizeof(struct smsc9420_ring_info) *
-               TX_RING_SIZE), GFP_KERNEL);
-       if (!pd->tx_buffers) {
-               smsc_warn(IFUP, "Failed to allocated tx_buffers");
-               return -ENOMEM;
-       }
-
-       /* Initialize the TX Ring */
-       for (i = 0; i < TX_RING_SIZE; i++) {
-               pd->tx_buffers[i].skb = NULL;
-               pd->tx_buffers[i].mapping = 0;
-               pd->tx_ring[i].status = 0;
-               pd->tx_ring[i].length = 0;
-               pd->tx_ring[i].buffer1 = 0;
-               pd->tx_ring[i].buffer2 = 0;
-       }
-       pd->tx_ring[TX_RING_SIZE - 1].length = TDES1_TER_;
-       wmb();
-
-       pd->tx_ring_head = 0;
-       pd->tx_ring_tail = 0;
-
-       smsc9420_reg_write(pd, TX_BASE_ADDR, pd->tx_dma_addr);
-       smsc9420_pci_flush_write(pd);
-
-       return 0;
-}
-
-static int smsc9420_alloc_rx_ring(struct smsc9420_pdata *pd)
-{
-       int i;
-
-       BUG_ON(!pd->rx_ring);
-
-       pd->rx_buffers = kmalloc((sizeof(struct smsc9420_ring_info) *
-               RX_RING_SIZE), GFP_KERNEL);
-       if (pd->rx_buffers == NULL) {
-               smsc_warn(IFUP, "Failed to allocated rx_buffers");
-               goto out;
-       }
-
-       /* initialize the rx ring */
-       for (i = 0; i < RX_RING_SIZE; i++) {
-               pd->rx_ring[i].status = 0;
-               pd->rx_ring[i].length = PKT_BUF_SZ;
-               pd->rx_ring[i].buffer2 = 0;
-               pd->rx_buffers[i].skb = NULL;
-               pd->rx_buffers[i].mapping = 0;
-       }
-       pd->rx_ring[RX_RING_SIZE - 1].length = (PKT_BUF_SZ | RDES1_RER_);
-
-       /* now allocate the entire ring of skbs */
-       for (i = 0; i < RX_RING_SIZE; i++) {
-               if (smsc9420_alloc_rx_buffer(pd, i)) {
-                       smsc_warn(IFUP, "failed to allocate rx skb %d", i);
-                       goto out_free_rx_skbs;
-               }
-       }
-
-       pd->rx_ring_head = 0;
-       pd->rx_ring_tail = 0;
-
-       smsc9420_reg_write(pd, VLAN1, ETH_P_8021Q);
-       smsc_dbg(IFUP, "VLAN1 = 0x%08x", smsc9420_reg_read(pd, VLAN1));
-
-       if (pd->rx_csum) {
-               /* Enable RX COE */
-               u32 coe = smsc9420_reg_read(pd, COE_CR) | RX_COE_EN;
-               smsc9420_reg_write(pd, COE_CR, coe);
-               smsc_dbg(IFUP, "COE_CR = 0x%08x", coe);
-       }
-
-       smsc9420_reg_write(pd, RX_BASE_ADDR, pd->rx_dma_addr);
-       smsc9420_pci_flush_write(pd);
-
-       return 0;
-
-out_free_rx_skbs:
-       smsc9420_free_rx_ring(pd);
-out:
-       return -ENOMEM;
-}
-
-static int smsc9420_open(struct net_device *dev)
-{
-       struct smsc9420_pdata *pd;
-       u32 bus_mode, mac_cr, dmac_control, int_cfg, dma_intr_ena, int_ctl;
-       unsigned long flags;
-       int result = 0, timeout;
-
-       BUG_ON(!dev);
-       pd = netdev_priv(dev);
-       BUG_ON(!pd);
-
-       if (!is_valid_ether_addr(dev->dev_addr)) {
-               smsc_warn(IFUP, "dev_addr is not a valid MAC address");
-               result = -EADDRNOTAVAIL;
-               goto out_0;
-       }
-
-       netif_carrier_off(dev);
-
-       /* disable, mask and acknowledge all interrupts */
-       spin_lock_irqsave(&pd->int_lock, flags);
-       int_cfg = smsc9420_reg_read(pd, INT_CFG) & (~INT_CFG_IRQ_EN_);
-       smsc9420_reg_write(pd, INT_CFG, int_cfg);
-       smsc9420_reg_write(pd, INT_CTL, 0);
-       spin_unlock_irqrestore(&pd->int_lock, flags);
-       smsc9420_reg_write(pd, DMAC_INTR_ENA, 0);
-       smsc9420_reg_write(pd, INT_STAT, 0xFFFFFFFF);
-       smsc9420_pci_flush_write(pd);
-
-       if (request_irq(dev->irq, smsc9420_isr, IRQF_SHARED | IRQF_DISABLED,
-                       DRV_NAME, pd)) {
-               smsc_warn(IFUP, "Unable to use IRQ = %d", dev->irq);
-               result = -ENODEV;
-               goto out_0;
-       }
-
-       smsc9420_dmac_soft_reset(pd);
-
-       /* make sure MAC_CR is sane */
-       smsc9420_reg_write(pd, MAC_CR, 0);
-
-       smsc9420_set_mac_address(dev);
-
-       /* Configure GPIO pins to drive LEDs */
-       smsc9420_reg_write(pd, GPIO_CFG,
-               (GPIO_CFG_LED_3_ | GPIO_CFG_LED_2_ | GPIO_CFG_LED_1_));
-
-       bus_mode = BUS_MODE_DMA_BURST_LENGTH_16;
-
-#ifdef __BIG_ENDIAN
-       bus_mode |= BUS_MODE_DBO_;
-#endif
-
-       smsc9420_reg_write(pd, BUS_MODE, bus_mode);
-
-       smsc9420_pci_flush_write(pd);
-
-       /* set bus master bridge arbitration priority for Rx and TX DMA */
-       smsc9420_reg_write(pd, BUS_CFG, BUS_CFG_RXTXWEIGHT_4_1);
-
-       smsc9420_reg_write(pd, DMAC_CONTROL,
-               (DMAC_CONTROL_SF_ | DMAC_CONTROL_OSF_));
-
-       smsc9420_pci_flush_write(pd);
-
-       /* test the IRQ connection to the ISR */
-       smsc_dbg(IFUP, "Testing ISR using IRQ %d", dev->irq);
-       pd->software_irq_signal = false;
-
-       spin_lock_irqsave(&pd->int_lock, flags);
-       /* configure interrupt deassertion timer and enable interrupts */
-       int_cfg = smsc9420_reg_read(pd, INT_CFG) | INT_CFG_IRQ_EN_;
-       int_cfg &= ~(INT_CFG_INT_DEAS_MASK);
-       int_cfg |= (INT_DEAS_TIME & INT_CFG_INT_DEAS_MASK);
-       smsc9420_reg_write(pd, INT_CFG, int_cfg);
-
-       /* unmask software interrupt */
-       int_ctl = smsc9420_reg_read(pd, INT_CTL) | INT_CTL_SW_INT_EN_;
-       smsc9420_reg_write(pd, INT_CTL, int_ctl);
-       spin_unlock_irqrestore(&pd->int_lock, flags);
-       smsc9420_pci_flush_write(pd);
-
-       timeout = 1000;
-       while (timeout--) {
-               if (pd->software_irq_signal)
-                       break;
-               msleep(1);
-       }
-
-       /* disable interrupts */
-       spin_lock_irqsave(&pd->int_lock, flags);
-       int_cfg = smsc9420_reg_read(pd, INT_CFG) & (~INT_CFG_IRQ_EN_);
-       smsc9420_reg_write(pd, INT_CFG, int_cfg);
-       spin_unlock_irqrestore(&pd->int_lock, flags);
-
-       if (!pd->software_irq_signal) {
-               smsc_warn(IFUP, "ISR failed signaling test");
-               result = -ENODEV;
-               goto out_free_irq_1;
-       }
-
-       smsc_dbg(IFUP, "ISR passed test using IRQ %d", dev->irq);
-
-       result = smsc9420_alloc_tx_ring(pd);
-       if (result) {
-               smsc_warn(IFUP, "Failed to Initialize tx dma ring");
-               result = -ENOMEM;
-               goto out_free_irq_1;
-       }
-
-       result = smsc9420_alloc_rx_ring(pd);
-       if (result) {
-               smsc_warn(IFUP, "Failed to Initialize rx dma ring");
-               result = -ENOMEM;
-               goto out_free_tx_ring_2;
-       }
-
-       result = smsc9420_mii_init(dev);
-       if (result) {
-               smsc_warn(IFUP, "Failed to initialize Phy");
-               result = -ENODEV;
-               goto out_free_rx_ring_3;
-       }
-
-       /* Bring the PHY up */
-       phy_start(pd->phy_dev);
-
-       napi_enable(&pd->napi);
-
-       /* start tx and rx */
-       mac_cr = smsc9420_reg_read(pd, MAC_CR) | MAC_CR_TXEN_ | MAC_CR_RXEN_;
-       smsc9420_reg_write(pd, MAC_CR, mac_cr);
-
-       dmac_control = smsc9420_reg_read(pd, DMAC_CONTROL);
-       dmac_control |= DMAC_CONTROL_ST_ | DMAC_CONTROL_SR_;
-       smsc9420_reg_write(pd, DMAC_CONTROL, dmac_control);
-       smsc9420_pci_flush_write(pd);
-
-       dma_intr_ena = smsc9420_reg_read(pd, DMAC_INTR_ENA);
-       dma_intr_ena |=
-               (DMAC_INTR_ENA_TX_ | DMAC_INTR_ENA_RX_ | DMAC_INTR_ENA_NIS_);
-       smsc9420_reg_write(pd, DMAC_INTR_ENA, dma_intr_ena);
-       smsc9420_pci_flush_write(pd);
-
-       netif_wake_queue(dev);
-
-       smsc9420_reg_write(pd, RX_POLL_DEMAND, 1);
-
-       /* enable interrupts */
-       spin_lock_irqsave(&pd->int_lock, flags);
-       int_cfg = smsc9420_reg_read(pd, INT_CFG) | INT_CFG_IRQ_EN_;
-       smsc9420_reg_write(pd, INT_CFG, int_cfg);
-       spin_unlock_irqrestore(&pd->int_lock, flags);
-
-       return 0;
-
-out_free_rx_ring_3:
-       smsc9420_free_rx_ring(pd);
-out_free_tx_ring_2:
-       smsc9420_free_tx_ring(pd);
-out_free_irq_1:
-       free_irq(dev->irq, pd);
-out_0:
-       return result;
-}
-
-#ifdef CONFIG_PM
-
-static int smsc9420_suspend(struct pci_dev *pdev, pm_message_t state)
-{
-       struct net_device *dev = pci_get_drvdata(pdev);
-       struct smsc9420_pdata *pd = netdev_priv(dev);
-       u32 int_cfg;
-       ulong flags;
-
-       /* disable interrupts */
-       spin_lock_irqsave(&pd->int_lock, flags);
-       int_cfg = smsc9420_reg_read(pd, INT_CFG) & (~INT_CFG_IRQ_EN_);
-       smsc9420_reg_write(pd, INT_CFG, int_cfg);
-       spin_unlock_irqrestore(&pd->int_lock, flags);
-
-       if (netif_running(dev)) {
-               netif_tx_disable(dev);
-               smsc9420_stop_tx(pd);
-               smsc9420_free_tx_ring(pd);
-
-               napi_disable(&pd->napi);
-               smsc9420_stop_rx(pd);
-               smsc9420_free_rx_ring(pd);
-
-               free_irq(dev->irq, pd);
-
-               netif_device_detach(dev);
-       }
-
-       pci_save_state(pdev);
-       pci_enable_wake(pdev, pci_choose_state(pdev, state), 0);
-       pci_disable_device(pdev);
-       pci_set_power_state(pdev, pci_choose_state(pdev, state));
-
-       return 0;
-}
-
-static int smsc9420_resume(struct pci_dev *pdev)
-{
-       struct net_device *dev = pci_get_drvdata(pdev);
-       struct smsc9420_pdata *pd = netdev_priv(dev);
-       int err;
-
-       pci_set_power_state(pdev, PCI_D0);
-       pci_restore_state(pdev);
-
-       err = pci_enable_device(pdev);
-       if (err)
-               return err;
-
-       pci_set_master(pdev);
-
-       err = pci_enable_wake(pdev, 0, 0);
-       if (err)
-               smsc_warn(IFUP, "pci_enable_wake failed: %d", err);
-
-       if (netif_running(dev)) {
-               err = smsc9420_open(dev);
-               netif_device_attach(dev);
-       }
-       return err;
-}
-
-#endif /* CONFIG_PM */
-
-static const struct net_device_ops smsc9420_netdev_ops = {
-       .ndo_open               = smsc9420_open,
-       .ndo_stop               = smsc9420_stop,
-       .ndo_start_xmit         = smsc9420_hard_start_xmit,
-       .ndo_get_stats          = smsc9420_get_stats,
-       .ndo_set_multicast_list = smsc9420_set_multicast_list,
-       .ndo_do_ioctl           = smsc9420_do_ioctl,
-       .ndo_validate_addr      = eth_validate_addr,
-       .ndo_set_mac_address    = eth_mac_addr,
-#ifdef CONFIG_NET_POLL_CONTROLLER
-       .ndo_poll_controller    = smsc9420_poll_controller,
-#endif /* CONFIG_NET_POLL_CONTROLLER */
-};
-
-static int __devinit
-smsc9420_probe(struct pci_dev *pdev, const struct pci_device_id *id)
-{
-       struct net_device *dev;
-       struct smsc9420_pdata *pd;
-       void __iomem *virt_addr;
-       int result = 0;
-       u32 id_rev;
-
-       printk(KERN_INFO DRV_DESCRIPTION " version " DRV_VERSION "\n");
-
-       /* First do the PCI initialisation */
-       result = pci_enable_device(pdev);
-       if (unlikely(result)) {
-               printk(KERN_ERR "Cannot enable smsc9420\n");
-               goto out_0;
-       }
-
-       pci_set_master(pdev);
-
-       dev = alloc_etherdev(sizeof(*pd));
-       if (!dev) {
-               printk(KERN_ERR "ether device alloc failed\n");
-               goto out_disable_pci_device_1;
-       }
-
-       SET_NETDEV_DEV(dev, &pdev->dev);
-
-       if (!(pci_resource_flags(pdev, SMSC_BAR) & IORESOURCE_MEM)) {
-               printk(KERN_ERR "Cannot find PCI device base address\n");
-               goto out_free_netdev_2;
-       }
-
-       if ((pci_request_regions(pdev, DRV_NAME))) {
-               printk(KERN_ERR "Cannot obtain PCI resources, aborting.\n");
-               goto out_free_netdev_2;
-       }
-
-       if (pci_set_dma_mask(pdev, DMA_BIT_MASK(32))) {
-               printk(KERN_ERR "No usable DMA configuration, aborting.\n");
-               goto out_free_regions_3;
-       }
-
-       virt_addr = ioremap(pci_resource_start(pdev, SMSC_BAR),
-               pci_resource_len(pdev, SMSC_BAR));
-       if (!virt_addr) {
-               printk(KERN_ERR "Cannot map device registers, aborting.\n");
-               goto out_free_regions_3;
-       }
-
-       /* registers are double mapped with 0 offset for LE and 0x200 for BE */
-       virt_addr += LAN9420_CPSR_ENDIAN_OFFSET;
-
-       dev->base_addr = (ulong)virt_addr;
-
-       pd = netdev_priv(dev);
-
-       /* pci descriptors are created in the PCI consistent area */
-       pd->rx_ring = pci_alloc_consistent(pdev,
-               sizeof(struct smsc9420_dma_desc) * RX_RING_SIZE +
-               sizeof(struct smsc9420_dma_desc) * TX_RING_SIZE,
-               &pd->rx_dma_addr);
-
-       if (!pd->rx_ring)
-               goto out_free_io_4;
-
-       /* descriptors are aligned due to the nature of pci_alloc_consistent */
-       pd->tx_ring = (struct smsc9420_dma_desc *)
-           (pd->rx_ring + RX_RING_SIZE);
-       pd->tx_dma_addr = pd->rx_dma_addr +
-           sizeof(struct smsc9420_dma_desc) * RX_RING_SIZE;
-
-       pd->pdev = pdev;
-       pd->dev = dev;
-       pd->base_addr = virt_addr;
-       pd->msg_enable = smsc_debug;
-       pd->rx_csum = true;
-
-       smsc_dbg(PROBE, "lan_base=0x%08lx", (ulong)virt_addr);
-
-       id_rev = smsc9420_reg_read(pd, ID_REV);
-       switch (id_rev & 0xFFFF0000) {
-       case 0x94200000:
-               smsc_info(PROBE, "LAN9420 identified, ID_REV=0x%08X", id_rev);
-               break;
-       default:
-               smsc_warn(PROBE, "LAN9420 NOT identified");
-               smsc_warn(PROBE, "ID_REV=0x%08X", id_rev);
-               goto out_free_dmadesc_5;
-       }
-
-       smsc9420_dmac_soft_reset(pd);
-       smsc9420_eeprom_reload(pd);
-       smsc9420_check_mac_address(dev);
-
-       dev->netdev_ops = &smsc9420_netdev_ops;
-       dev->ethtool_ops = &smsc9420_ethtool_ops;
-       dev->irq = pdev->irq;
-
-       netif_napi_add(dev, &pd->napi, smsc9420_rx_poll, NAPI_WEIGHT);
-
-       result = register_netdev(dev);
-       if (result) {
-               smsc_warn(PROBE, "error %i registering device", result);
-               goto out_free_dmadesc_5;
-       }
-
-       pci_set_drvdata(pdev, dev);
-
-       spin_lock_init(&pd->int_lock);
-       spin_lock_init(&pd->phy_lock);
-
-       dev_info(&dev->dev, "MAC Address: %pM\n", dev->dev_addr);
-
-       return 0;
-
-out_free_dmadesc_5:
-       pci_free_consistent(pdev, sizeof(struct smsc9420_dma_desc) *
-               (RX_RING_SIZE + TX_RING_SIZE), pd->rx_ring, pd->rx_dma_addr);
-out_free_io_4:
-       iounmap(virt_addr - LAN9420_CPSR_ENDIAN_OFFSET);
-out_free_regions_3:
-       pci_release_regions(pdev);
-out_free_netdev_2:
-       free_netdev(dev);
-out_disable_pci_device_1:
-       pci_disable_device(pdev);
-out_0:
-       return -ENODEV;
-}
-
-static void __devexit smsc9420_remove(struct pci_dev *pdev)
-{
-       struct net_device *dev;
-       struct smsc9420_pdata *pd;
-
-       dev = pci_get_drvdata(pdev);
-       if (!dev)
-               return;
-
-       pci_set_drvdata(pdev, NULL);
-
-       pd = netdev_priv(dev);
-       unregister_netdev(dev);
-
-       /* tx_buffers and rx_buffers are freed in stop */
-       BUG_ON(pd->tx_buffers);
-       BUG_ON(pd->rx_buffers);
-
-       BUG_ON(!pd->tx_ring);
-       BUG_ON(!pd->rx_ring);
-
-       pci_free_consistent(pdev, sizeof(struct smsc9420_dma_desc) *
-               (RX_RING_SIZE + TX_RING_SIZE), pd->rx_ring, pd->rx_dma_addr);
-
-       iounmap(pd->base_addr - LAN9420_CPSR_ENDIAN_OFFSET);
-       pci_release_regions(pdev);
-       free_netdev(dev);
-       pci_disable_device(pdev);
-}
-
-static struct pci_driver smsc9420_driver = {
-       .name = DRV_NAME,
-       .id_table = smsc9420_id_table,
-       .probe = smsc9420_probe,
-       .remove = __devexit_p(smsc9420_remove),
-#ifdef CONFIG_PM
-       .suspend = smsc9420_suspend,
-       .resume = smsc9420_resume,
-#endif /* CONFIG_PM */
-};
-
-static int __init smsc9420_init_module(void)
-{
-       smsc_debug = netif_msg_init(debug, SMSC_MSG_DEFAULT);
-
-       return pci_register_driver(&smsc9420_driver);
-}
-
-static void __exit smsc9420_exit_module(void)
-{
-       pci_unregister_driver(&smsc9420_driver);
-}
-
-module_init(smsc9420_init_module);
-module_exit(smsc9420_exit_module);
diff --git a/drivers/net/smsc9420.h b/drivers/net/smsc9420.h
deleted file mode 100644 (file)
index e441402..0000000
+++ /dev/null
@@ -1,276 +0,0 @@
- /***************************************************************************
- *
- * Copyright (C) 2007,2008  SMSC
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU General Public License
- * as published by the Free Software Foundation; either version 2
- * of the License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
- *
- ***************************************************************************
- */
-
-#ifndef _SMSC9420_H
-#define _SMSC9420_H
-
-#define TX_RING_SIZE                   (32)
-#define RX_RING_SIZE                   (128)
-
-/* interrupt deassertion in multiples of 10us */
-#define INT_DEAS_TIME                  (50)
-
-#define NAPI_WEIGHT                    (64)
-#define SMSC_BAR                       (3)
-
-#ifdef __BIG_ENDIAN
-/* Register set is duplicated for BE at an offset of 0x200 */
-#define LAN9420_CPSR_ENDIAN_OFFSET     (0x200)
-#else
-#define LAN9420_CPSR_ENDIAN_OFFSET     (0)
-#endif
-
-#define PCI_VENDOR_ID_9420             (0x1055)
-#define PCI_DEVICE_ID_9420             (0xE420)
-
-#define LAN_REGISTER_EXTENT            (0x400)
-
-#define SMSC9420_EEPROM_SIZE           ((u32)11)
-#define SMSC9420_EEPROM_MAGIC          (0x9420)
-
-#define PKT_BUF_SZ                     (VLAN_ETH_FRAME_LEN + NET_IP_ALIGN + 4)
-
-/***********************************************/
-/* DMA Controller Control and Status Registers */
-/***********************************************/
-#define BUS_MODE                       (0x00)
-#define BUS_MODE_SWR_                  (BIT(0))
-#define BUS_MODE_DMA_BURST_LENGTH_1    (BIT(8))
-#define BUS_MODE_DMA_BURST_LENGTH_2    (BIT(9))
-#define BUS_MODE_DMA_BURST_LENGTH_4    (BIT(10))
-#define BUS_MODE_DMA_BURST_LENGTH_8    (BIT(11))
-#define BUS_MODE_DMA_BURST_LENGTH_16   (BIT(12))
-#define BUS_MODE_DMA_BURST_LENGTH_32   (BIT(13))
-#define BUS_MODE_DBO_                  (BIT(20))
-
-#define TX_POLL_DEMAND                 (0x04)
-
-#define RX_POLL_DEMAND                 (0x08)
-
-#define RX_BASE_ADDR                   (0x0C)
-
-#define TX_BASE_ADDR                   (0x10)
-
-#define DMAC_STATUS                    (0x14)
-#define DMAC_STS_TS_                   (7 << 20)
-#define DMAC_STS_RS_                   (7 << 17)
-#define DMAC_STS_NIS_                  (BIT(16))
-#define DMAC_STS_AIS_                  (BIT(15))
-#define DMAC_STS_RWT_                  (BIT(9))
-#define DMAC_STS_RXPS_                 (BIT(8))
-#define DMAC_STS_RXBU_                 (BIT(7))
-#define DMAC_STS_RX_                   (BIT(6))
-#define DMAC_STS_TXUNF_                        (BIT(5))
-#define DMAC_STS_TXBU_                 (BIT(2))
-#define DMAC_STS_TXPS_                 (BIT(1))
-#define DMAC_STS_TX_                   (BIT(0))
-
-#define DMAC_CONTROL                   (0x18)
-#define DMAC_CONTROL_TTM_              (BIT(22))
-#define DMAC_CONTROL_SF_               (BIT(21))
-#define DMAC_CONTROL_ST_               (BIT(13))
-#define DMAC_CONTROL_OSF_              (BIT(2))
-#define DMAC_CONTROL_SR_               (BIT(1))
-
-#define DMAC_INTR_ENA                  (0x1C)
-#define DMAC_INTR_ENA_NIS_             (BIT(16))
-#define DMAC_INTR_ENA_AIS_             (BIT(15))
-#define DMAC_INTR_ENA_RWT_             (BIT(9))
-#define DMAC_INTR_ENA_RXPS_            (BIT(8))
-#define DMAC_INTR_ENA_RXBU_            (BIT(7))
-#define DMAC_INTR_ENA_RX_              (BIT(6))
-#define DMAC_INTR_ENA_TXBU_            (BIT(2))
-#define DMAC_INTR_ENA_TXPS_            (BIT(1))
-#define DMAC_INTR_ENA_TX_              (BIT(0))
-
-#define MISS_FRAME_CNTR                        (0x20)
-
-#define TX_BUFF_ADDR                   (0x50)
-
-#define RX_BUFF_ADDR                   (0x54)
-
-/* Transmit Descriptor Bit Defs */
-#define TDES0_OWN_                     (0x80000000)
-#define TDES0_ERROR_SUMMARY_           (0x00008000)
-#define TDES0_LOSS_OF_CARRIER_         (0x00000800)
-#define TDES0_NO_CARRIER_              (0x00000400)
-#define TDES0_LATE_COLLISION_          (0x00000200)
-#define TDES0_EXCESSIVE_COLLISIONS_    (0x00000100)
-#define TDES0_HEARTBEAT_FAIL_          (0x00000080)
-#define TDES0_COLLISION_COUNT_MASK_    (0x00000078)
-#define TDES0_COLLISION_COUNT_SHFT_    (3)
-#define TDES0_EXCESSIVE_DEFERRAL_      (0x00000004)
-#define TDES0_DEFERRED_                        (0x00000001)
-
-#define TDES1_IC_                      0x80000000
-#define TDES1_LS_                      0x40000000
-#define TDES1_FS_                      0x20000000
-#define TDES1_TXCSEN_                  0x08000000
-#define TDES1_TER_                     (BIT(25))
-#define TDES1_TCH_                     0x01000000
-
-/* Receive Descriptor 0 Bit Defs */
-#define RDES0_OWN_                     (0x80000000)
-#define RDES0_FRAME_LENGTH_MASK_       (0x07FF0000)
-#define RDES0_FRAME_LENGTH_SHFT_       (16)
-#define RDES0_ERROR_SUMMARY_           (0x00008000)
-#define RDES0_DESCRIPTOR_ERROR_                (0x00004000)
-#define RDES0_LENGTH_ERROR_            (0x00001000)
-#define RDES0_RUNT_FRAME_              (0x00000800)
-#define RDES0_MULTICAST_FRAME_         (0x00000400)
-#define RDES0_FIRST_DESCRIPTOR_                (0x00000200)
-#define RDES0_LAST_DESCRIPTOR_         (0x00000100)
-#define RDES0_FRAME_TOO_LONG_          (0x00000080)
-#define RDES0_COLLISION_SEEN_          (0x00000040)
-#define RDES0_FRAME_TYPE_              (0x00000020)
-#define RDES0_WATCHDOG_TIMEOUT_                (0x00000010)
-#define RDES0_MII_ERROR_               (0x00000008)
-#define RDES0_DRIBBLING_BIT_           (0x00000004)
-#define RDES0_CRC_ERROR_               (0x00000002)
-
-/* Receive Descriptor 1 Bit Defs */
-#define RDES1_RER_                     (0x02000000)
-
-/***********************************************/
-/*       MAC Control and Status Registers      */
-/***********************************************/
-#define MAC_CR                         (0x80)
-#define MAC_CR_RXALL_                  (0x80000000)
-#define MAC_CR_DIS_RXOWN_              (0x00800000)
-#define MAC_CR_LOOPBK_                 (0x00200000)
-#define MAC_CR_FDPX_                   (0x00100000)
-#define MAC_CR_MCPAS_                  (0x00080000)
-#define MAC_CR_PRMS_                   (0x00040000)
-#define MAC_CR_INVFILT_                        (0x00020000)
-#define MAC_CR_PASSBAD_                        (0x00010000)
-#define MAC_CR_HFILT_                  (0x00008000)
-#define MAC_CR_HPFILT_                 (0x00002000)
-#define MAC_CR_LCOLL_                  (0x00001000)
-#define MAC_CR_DIS_BCAST_              (0x00000800)
-#define MAC_CR_DIS_RTRY_               (0x00000400)
-#define MAC_CR_PADSTR_                 (0x00000100)
-#define MAC_CR_BOLMT_MSK               (0x000000C0)
-#define MAC_CR_MFCHK_                  (0x00000020)
-#define MAC_CR_TXEN_                   (0x00000008)
-#define MAC_CR_RXEN_                   (0x00000004)
-
-#define ADDRH                          (0x84)
-
-#define ADDRL                          (0x88)
-
-#define HASHH                          (0x8C)
-
-#define HASHL                          (0x90)
-
-#define MII_ACCESS                     (0x94)
-#define MII_ACCESS_MII_BUSY_           (0x00000001)
-#define MII_ACCESS_MII_WRITE_          (0x00000002)
-#define MII_ACCESS_MII_READ_           (0x00000000)
-#define MII_ACCESS_INDX_MSK_           (0x000007C0)
-#define MII_ACCESS_PHYADDR_MSK_                (0x0000F8C0)
-#define MII_ACCESS_INDX_SHFT_CNT       (6)
-#define MII_ACCESS_PHYADDR_SHFT_CNT    (11)
-
-#define MII_DATA                       (0x98)
-
-#define FLOW                           (0x9C)
-
-#define VLAN1                          (0xA0)
-
-#define VLAN2                          (0xA4)
-
-#define WUFF                           (0xA8)
-
-#define WUCSR                          (0xAC)
-
-#define COE_CR                         (0xB0)
-#define TX_COE_EN                      (0x00010000)
-#define RX_COE_MODE                    (0x00000002)
-#define RX_COE_EN                      (0x00000001)
-
-/***********************************************/
-/*     System Control and Status Registers     */
-/***********************************************/
-#define ID_REV                         (0xC0)
-
-#define INT_CTL                                (0xC4)
-#define INT_CTL_SW_INT_EN_             (0x00008000)
-#define INT_CTL_SBERR_INT_EN_          (1 << 12)
-#define INT_CTL_MBERR_INT_EN_          (1 << 13)
-#define INT_CTL_GPT_INT_EN_            (0x00000008)
-#define INT_CTL_PHY_INT_EN_            (0x00000004)
-#define INT_CTL_WAKE_INT_EN_           (0x00000002)
-
-#define INT_STAT                       (0xC8)
-#define INT_STAT_SW_INT_               (1 << 15)
-#define INT_STAT_MBERR_INT_            (1 << 13)
-#define INT_STAT_SBERR_INT_            (1 << 12)
-#define INT_STAT_GPT_INT_              (1 << 3)
-#define INT_STAT_PHY_INT_              (0x00000004)
-#define INT_STAT_WAKE_INT_             (0x00000002)
-#define INT_STAT_DMAC_INT_             (0x00000001)
-
-#define INT_CFG                                (0xCC)
-#define INT_CFG_IRQ_INT_               (0x00080000)
-#define INT_CFG_IRQ_EN_                        (0x00040000)
-#define INT_CFG_INT_DEAS_CLR_          (0x00000200)
-#define INT_CFG_INT_DEAS_MASK          (0x000000FF)
-
-#define GPIO_CFG                       (0xD0)
-#define GPIO_CFG_LED_3_                        (0x40000000)
-#define GPIO_CFG_LED_2_                        (0x20000000)
-#define GPIO_CFG_LED_1_                        (0x10000000)
-#define GPIO_CFG_EEPR_EN_              (0x00700000)
-
-#define GPT_CFG                                (0xD4)
-#define GPT_CFG_TIMER_EN_              (0x20000000)
-
-#define GPT_CNT                                (0xD8)
-
-#define BUS_CFG                                (0xDC)
-#define BUS_CFG_RXTXWEIGHT_1_1         (0 << 25)
-#define BUS_CFG_RXTXWEIGHT_2_1         (1 << 25)
-#define BUS_CFG_RXTXWEIGHT_3_1         (2 << 25)
-#define BUS_CFG_RXTXWEIGHT_4_1         (3 << 25)
-
-#define PMT_CTRL                       (0xE0)
-
-#define FREE_RUN                       (0xF4)
-
-#define E2P_CMD                                (0xF8)
-#define E2P_CMD_EPC_BUSY_              (0x80000000)
-#define E2P_CMD_EPC_CMD_               (0x70000000)
-#define E2P_CMD_EPC_CMD_READ_          (0x00000000)
-#define E2P_CMD_EPC_CMD_EWDS_          (0x10000000)
-#define E2P_CMD_EPC_CMD_EWEN_          (0x20000000)
-#define E2P_CMD_EPC_CMD_WRITE_         (0x30000000)
-#define E2P_CMD_EPC_CMD_WRAL_          (0x40000000)
-#define E2P_CMD_EPC_CMD_ERASE_         (0x50000000)
-#define E2P_CMD_EPC_CMD_ERAL_          (0x60000000)
-#define E2P_CMD_EPC_CMD_RELOAD_                (0x70000000)
-#define E2P_CMD_EPC_TIMEOUT_           (0x00000200)
-#define E2P_CMD_MAC_ADDR_LOADED_       (0x00000100)
-#define E2P_CMD_EPC_ADDR_              (0x000000FF)
-
-#define E2P_DATA                       (0xFC)
-#define E2P_DATA_EEPROM_DATA_          (0x000000FF)
-
-#endif /* _SMSC9420_H */