public inbox for netdev@vger.kernel.org
 help / color / mirror / Atom feed
* [PATCH net 00/18] Remove a number of ISA and PCMCIA Ethernet drivers
@ 2026-04-21 19:31 Andrew Lunn
  2026-04-21 19:31 ` [PATCH net 01/18] drivers: net: 3com: 3c509: Remove this driver Andrew Lunn
                   ` (21 more replies)
  0 siblings, 22 replies; 28+ messages in thread
From: Andrew Lunn @ 2026-04-21 19:31 UTC (permalink / raw)
  To: Andrew Lunn, David S. Miller, Eric Dumazet, Jakub Kicinski,
	Paolo Abeni, Simon Horman, Jonathan Corbet, Shuah Khan
  Cc: linux-kernel, netdev, linux-doc, Andrew Lunn

These old drivers have not been much of a Maintenance burden until
recently. Now there are more newbies using AI and fuzzers finding
issues, resulting in more work for Maintainers. Fixing these old
drivers make little sense, if it is not clear they have users.

These are all ISA and PCMCIA Ethernet devices, mostly from the last
century, a couple from 2001 or 2002. It seems unlikely they are still
used. However, remove them one patch at a time so they can be brought
back if somebody still has the hardware, runs modern kernels and wants
to take up the roll of driver Maintainer.

Signed-off-by: Andrew Lunn <andrew@lunn.ch>
---
Andrew Lunn (18):
      drivers: net: 3com: 3c509: Remove this driver
      drivers: net: 3com: 3c515: Remove this driver
      drivers: net: 3com: 3c574: Remove this driver
      drivers: net: 3com: 3c589: Remove this driver
      drivers: net: 3com: 3c59x: Remove this driver
      drivers: net: amd: Remove hplance and mvme147
      drivers: net: amd: lance: Remove this driver
      drivers: net: amd: nmclan: Remove this driver
      drivers: net: smsc: smc9194: Remove this driver
      drivers: net: smsc: smc91c92: Remove this driver
      drivers: net: cirrus: cs89x0: Remove this driver
      drivers: net: cirrus: mac89x0: Remove this driver
      drivers: net: fujitsu: fmvj18x: Remove this driver
      drivers: net: xircom: xirc2ps: Remove this driver
      drivers: net: 8390: AX88190: Remove this driver
      drivers: net: 8390: pcnet: Remove this driver
      drivers: net: 8390: ultra: Remove this driver
      drivers: net: 8390: wd80x3: Remove this driver

 .../device_drivers/ethernet/3com/vortex.rst        |  459 ---
 MAINTAINERS                                        |    7 -
 drivers/net/ethernet/3com/3c509.c                  | 1448 ---------
 drivers/net/ethernet/3com/3c515.c                  | 1566 ---------
 drivers/net/ethernet/3com/3c574_cs.c               | 1164 -------
 drivers/net/ethernet/3com/3c589_cs.c               |  974 ------
 drivers/net/ethernet/3com/3c59x.c                  | 3357 --------------------
 drivers/net/ethernet/3com/Kconfig                  |   66 -
 drivers/net/ethernet/3com/Makefile                 |    5 -
 drivers/net/ethernet/8390/Kconfig                  |   52 -
 drivers/net/ethernet/8390/Makefile                 |    4 -
 drivers/net/ethernet/8390/axnet_cs.c               | 1707 ----------
 drivers/net/ethernet/8390/pcnet_cs.c               | 1717 ----------
 drivers/net/ethernet/8390/smc-ultra.c              |  630 ----
 drivers/net/ethernet/8390/wd.c                     |  575 ----
 drivers/net/ethernet/Kconfig                       |    2 -
 drivers/net/ethernet/amd/7990.c                    |  671 ----
 drivers/net/ethernet/amd/7990.h                    |  251 --
 drivers/net/ethernet/amd/Kconfig                   |   39 -
 drivers/net/ethernet/amd/Makefile                  |    4 -
 drivers/net/ethernet/amd/hplance.c                 |  238 --
 drivers/net/ethernet/amd/hplance.h                 |   27 -
 drivers/net/ethernet/amd/lance.c                   | 1317 --------
 drivers/net/ethernet/amd/mvme147.c                 |  198 --
 drivers/net/ethernet/amd/nmclan_cs.c               | 1508 ---------
 drivers/net/ethernet/cirrus/Kconfig                |   40 -
 drivers/net/ethernet/cirrus/Makefile               |    2 -
 drivers/net/ethernet/cirrus/cs89x0.c               | 1915 -----------
 drivers/net/ethernet/cirrus/cs89x0.h               |  461 ---
 drivers/net/ethernet/cirrus/mac89x0.c              |  577 ----
 drivers/net/ethernet/fujitsu/Kconfig               |   30 -
 drivers/net/ethernet/fujitsu/Makefile              |    6 -
 drivers/net/ethernet/fujitsu/fmvj18x_cs.c          | 1176 -------
 drivers/net/ethernet/smsc/Kconfig                  |   27 -
 drivers/net/ethernet/smsc/Makefile                 |    2 -
 drivers/net/ethernet/smsc/smc9194.c                | 1535 ---------
 drivers/net/ethernet/smsc/smc91c92_cs.c            | 2059 ------------
 drivers/net/ethernet/xircom/Kconfig                |   30 -
 drivers/net/ethernet/xircom/Makefile               |    6 -
 drivers/net/ethernet/xircom/xirc2ps_cs.c           | 1794 -----------
 40 files changed, 27646 deletions(-)
---
base-commit: 1f5ffc672165ff851063a5fd044b727ab2517ae3
change-id: 20260421-v7-0-0-net-next-driver-removal-v1-47c88c987b34

Best regards,
-- 
Andrew Lunn <andrew@lunn.ch>


^ permalink raw reply	[flat|nested] 28+ messages in thread

* [PATCH net 01/18] drivers: net: 3com: 3c509: Remove this driver
  2026-04-21 19:31 [PATCH net 00/18] Remove a number of ISA and PCMCIA Ethernet drivers Andrew Lunn
@ 2026-04-21 19:31 ` Andrew Lunn
  2026-04-21 19:31 ` [PATCH net 02/18] drivers: net: 3com: 3c515: " Andrew Lunn
                   ` (20 subsequent siblings)
  21 siblings, 0 replies; 28+ messages in thread
From: Andrew Lunn @ 2026-04-21 19:31 UTC (permalink / raw)
  To: Andrew Lunn, David S. Miller, Eric Dumazet, Jakub Kicinski,
	Paolo Abeni, Simon Horman, Jonathan Corbet, Shuah Khan
  Cc: linux-kernel, netdev, linux-doc, Andrew Lunn

The 3c509 was written by Donald Becker between 1993-2000. It is an ISA
device, so unlikely to be used with modern kernels.

Signed-off-by: Andrew Lunn <andrew@lunn.ch>
---
 drivers/net/ethernet/3com/3c509.c  | 1448 ------------------------------------
 drivers/net/ethernet/3com/Kconfig  |   14 -
 drivers/net/ethernet/3com/Makefile |    1 -
 3 files changed, 1463 deletions(-)

diff --git a/drivers/net/ethernet/3com/3c509.c b/drivers/net/ethernet/3com/3c509.c
deleted file mode 100644
index fb68339e1511..000000000000
--- a/drivers/net/ethernet/3com/3c509.c
+++ /dev/null
@@ -1,1448 +0,0 @@
-/* 3c509.c: A 3c509 EtherLink3 ethernet driver for linux. */
-/*
-	Written 1993-2000 by Donald Becker.
-
-	Copyright 1994-2000 by Donald Becker.
-	Copyright 1993 United States Government as represented by the
-	Director, National Security Agency.	 This software may be used and
-	distributed according to the terms of the GNU General Public License,
-	incorporated herein by reference.
-
-	This driver is for the 3Com EtherLinkIII series.
-
-	The author may be reached as becker@scyld.com, or C/O
-	Scyld Computing Corporation
-	410 Severn Ave., Suite 210
-	Annapolis MD 21403
-
-	Known limitations:
-	Because of the way 3c509 ISA detection works it's difficult to predict
-	a priori which of several ISA-mode cards will be detected first.
-
-	This driver does not use predictive interrupt mode, resulting in higher
-	packet latency but lower overhead.  If interrupts are disabled for an
-	unusually long time it could also result in missed packets, but in
-	practice this rarely happens.
-
-
-	FIXES:
-		Alan Cox:       Removed the 'Unexpected interrupt' bug.
-		Michael Meskes:	Upgraded to Donald Becker's version 1.07.
-		Alan Cox:	Increased the eeprom delay. Regardless of
-				what the docs say some people definitely
-				get problems with lower (but in card spec)
-				delays
-		v1.10 4/21/97 Fixed module code so that multiple cards may be detected,
-				other cleanups.  -djb
-		Andrea Arcangeli:	Upgraded to Donald Becker's version 1.12.
-		Rick Payne:	Fixed SMP race condition
-		v1.13 9/8/97 Made 'max_interrupt_work' an insmod-settable variable -djb
-		v1.14 10/15/97 Avoided waiting..discard message for fast machines -djb
-		v1.15 1/31/98 Faster recovery for Tx errors. -djb
-		v1.16 2/3/98 Different ID port handling to avoid sound cards. -djb
-		v1.18 12Mar2001 Andrew Morton
-			- Avoid bogus detect of 3c590's (Andrzej Krzysztofowicz)
-			- Reviewed against 1.18 from scyld.com
-		v1.18a 17Nov2001 Jeff Garzik <jgarzik@pobox.com>
-			- ethtool support
-		v1.18b 1Mar2002 Zwane Mwaikambo <zwane@commfireservices.com>
-			- Power Management support
-		v1.18c 1Mar2002 David Ruggiero <jdr@farfalle.com>
-			- Full duplex support
-		v1.19  16Oct2002 Zwane Mwaikambo <zwane@linuxpower.ca>
-			- Additional ethtool features
-		v1.19a 28Oct2002 Davud Ruggiero <jdr@farfalle.com>
-			- Increase *read_eeprom udelay to workaround oops with 2 cards.
-		v1.19b 08Nov2002 Marc Zyngier <maz@wild-wind.fr.eu.org>
-			- Introduce driver model for EISA cards.
-		v1.20  04Feb2008 Ondrej Zary <linux@rainbow-software.org>
-			- convert to isa_driver and pnp_driver and some cleanups
-*/
-
-#define DRV_NAME	"3c509"
-
-/* A few values that may be tweaked. */
-
-/* Time in jiffies before concluding the transmitter is hung. */
-#define TX_TIMEOUT  (400*HZ/1000)
-
-#include <linux/module.h>
-#include <linux/isa.h>
-#include <linux/pnp.h>
-#include <linux/string.h>
-#include <linux/interrupt.h>
-#include <linux/errno.h>
-#include <linux/in.h>
-#include <linux/ioport.h>
-#include <linux/init.h>
-#include <linux/netdevice.h>
-#include <linux/etherdevice.h>
-#include <linux/pm.h>
-#include <linux/skbuff.h>
-#include <linux/delay.h>	/* for udelay() */
-#include <linux/spinlock.h>
-#include <linux/ethtool.h>
-#include <linux/device.h>
-#include <linux/eisa.h>
-#include <linux/bitops.h>
-
-#include <linux/uaccess.h>
-#include <asm/io.h>
-#include <asm/irq.h>
-
-#ifdef EL3_DEBUG
-static int el3_debug = EL3_DEBUG;
-#else
-static int el3_debug = 2;
-#endif
-
-/* Used to do a global count of all the cards in the system.  Must be
- * a global variable so that the eisa probe routines can increment
- * it */
-static int el3_cards = 0;
-#define EL3_MAX_CARDS 8
-
-/* To minimize the size of the driver source I only define operating
-   constants if they are used several times.  You'll need the manual
-   anyway if you want to understand driver details. */
-/* Offsets from base I/O address. */
-#define EL3_DATA 0x00
-#define EL3_CMD 0x0e
-#define EL3_STATUS 0x0e
-#define	EEPROM_READ 0x80
-
-#define EL3_IO_EXTENT	16
-
-#define EL3WINDOW(win_num) outw(SelectWindow + (win_num), ioaddr + EL3_CMD)
-
-
-/* The top five bits written to EL3_CMD are a command, the lower
-   11 bits are the parameter, if applicable. */
-enum c509cmd {
-	TotalReset = 0<<11, SelectWindow = 1<<11, StartCoax = 2<<11,
-	RxDisable = 3<<11, RxEnable = 4<<11, RxReset = 5<<11, RxDiscard = 8<<11,
-	TxEnable = 9<<11, TxDisable = 10<<11, TxReset = 11<<11,
-	FakeIntr = 12<<11, AckIntr = 13<<11, SetIntrEnb = 14<<11,
-	SetStatusEnb = 15<<11, SetRxFilter = 16<<11, SetRxThreshold = 17<<11,
-	SetTxThreshold = 18<<11, SetTxStart = 19<<11, StatsEnable = 21<<11,
-	StatsDisable = 22<<11, StopCoax = 23<<11, PowerUp = 27<<11,
-	PowerDown = 28<<11, PowerAuto = 29<<11};
-
-enum c509status {
-	IntLatch = 0x0001, AdapterFailure = 0x0002, TxComplete = 0x0004,
-	TxAvailable = 0x0008, RxComplete = 0x0010, RxEarly = 0x0020,
-	IntReq = 0x0040, StatsFull = 0x0080, CmdBusy = 0x1000, };
-
-/* The SetRxFilter command accepts the following classes: */
-enum RxFilter {
-	RxStation = 1, RxMulticast = 2, RxBroadcast = 4, RxProm = 8 };
-
-/* Register window 1 offsets, the window used in normal operation. */
-#define TX_FIFO		0x00
-#define RX_FIFO		0x00
-#define RX_STATUS 	0x08
-#define TX_STATUS 	0x0B
-#define TX_FREE		0x0C		/* Remaining free bytes in Tx buffer. */
-
-#define WN0_CONF_CTRL	0x04		/* Window 0: Configuration control register */
-#define WN0_ADDR_CONF	0x06		/* Window 0: Address configuration register */
-#define WN0_IRQ		0x08		/* Window 0: Set IRQ line in bits 12-15. */
-#define WN4_MEDIA	0x0A		/* Window 4: Various transcvr/media bits. */
-#define	MEDIA_TP	0x00C0		/* Enable link beat and jabber for 10baseT. */
-#define WN4_NETDIAG	0x06		/* Window 4: Net diagnostic */
-#define FD_ENABLE	0x8000		/* Enable full-duplex ("external loopback") */
-
-/*
- * Must be a power of two (we use a binary and in the
- * circular queue)
- */
-#define SKB_QUEUE_SIZE	64
-
-enum el3_cardtype { EL3_ISA, EL3_PNP, EL3_EISA };
-
-struct el3_private {
-	spinlock_t lock;
-	/* skb send-queue */
-	int head, size;
-	struct sk_buff *queue[SKB_QUEUE_SIZE];
-	enum el3_cardtype type;
-};
-static int id_port;
-static int current_tag;
-static struct net_device *el3_devs[EL3_MAX_CARDS];
-
-/* Parameters that may be passed into the module. */
-static int debug = -1;
-static int irq[] = {-1, -1, -1, -1, -1, -1, -1, -1};
-/* Maximum events (Rx packets, etc.) to handle at each interrupt. */
-static int max_interrupt_work = 10;
-#ifdef CONFIG_PNP
-static int nopnp;
-#endif
-
-static int el3_common_init(struct net_device *dev);
-static void el3_common_remove(struct net_device *dev);
-static ushort id_read_eeprom(int index);
-static ushort read_eeprom(int ioaddr, int index);
-static int el3_open(struct net_device *dev);
-static netdev_tx_t el3_start_xmit(struct sk_buff *skb, struct net_device *dev);
-static irqreturn_t el3_interrupt(int irq, void *dev_id);
-static void update_stats(struct net_device *dev);
-static struct net_device_stats *el3_get_stats(struct net_device *dev);
-static int el3_rx(struct net_device *dev);
-static int el3_close(struct net_device *dev);
-static void set_multicast_list(struct net_device *dev);
-static void el3_tx_timeout (struct net_device *dev, unsigned int txqueue);
-static void el3_down(struct net_device *dev);
-static void el3_up(struct net_device *dev);
-static const struct ethtool_ops ethtool_ops;
-#ifdef CONFIG_PM
-static int el3_suspend(struct device *, pm_message_t);
-static int el3_resume(struct device *);
-#else
-#define el3_suspend NULL
-#define el3_resume NULL
-#endif
-
-
-/* generic device remove for all device types */
-static int el3_device_remove (struct device *device);
-#ifdef CONFIG_NET_POLL_CONTROLLER
-static void el3_poll_controller(struct net_device *dev);
-#endif
-
-/* Return 0 on success, 1 on error, 2 when found already detected PnP card */
-static int el3_isa_id_sequence(__be16 *phys_addr)
-{
-	short lrs_state = 0xff;
-	int i;
-
-	/* ISA boards are detected by sending the ID sequence to the
-	   ID_PORT.  We find cards past the first by setting the 'current_tag'
-	   on cards as they are found.  Cards with their tag set will not
-	   respond to subsequent ID sequences. */
-
-	outb(0x00, id_port);
-	outb(0x00, id_port);
-	for (i = 0; i < 255; i++) {
-		outb(lrs_state, id_port);
-		lrs_state <<= 1;
-		lrs_state = lrs_state & 0x100 ? lrs_state ^ 0xcf : lrs_state;
-	}
-	/* For the first probe, clear all board's tag registers. */
-	if (current_tag == 0)
-		outb(0xd0, id_port);
-	else			/* Otherwise kill off already-found boards. */
-		outb(0xd8, id_port);
-	if (id_read_eeprom(7) != 0x6d50)
-		return 1;
-	/* Read in EEPROM data, which does contention-select.
-	   Only the lowest address board will stay "on-line".
-	   3Com got the byte order backwards. */
-	for (i = 0; i < 3; i++)
-		phys_addr[i] = htons(id_read_eeprom(i));
-#ifdef CONFIG_PNP
-	if (!nopnp) {
-		/* The ISA PnP 3c509 cards respond to the ID sequence too.
-		   This check is needed in order not to register them twice. */
-		for (i = 0; i < el3_cards; i++) {
-			struct el3_private *lp = netdev_priv(el3_devs[i]);
-			if (lp->type == EL3_PNP &&
-			    ether_addr_equal((u8 *)phys_addr, el3_devs[i]->dev_addr)) {
-				if (el3_debug > 3)
-					pr_debug("3c509 with address %02x %02x %02x %02x %02x %02x was found by ISAPnP\n",
-						phys_addr[0] & 0xff, phys_addr[0] >> 8,
-						phys_addr[1] & 0xff, phys_addr[1] >> 8,
-						phys_addr[2] & 0xff, phys_addr[2] >> 8);
-				/* Set the adaptor tag so that the next card can be found. */
-				outb(0xd0 + ++current_tag, id_port);
-				return 2;
-			}
-		}
-	}
-#endif /* CONFIG_PNP */
-	return 0;
-
-}
-
-static void el3_dev_fill(struct net_device *dev, __be16 *phys_addr, int ioaddr,
-			 int irq, int if_port, enum el3_cardtype type)
-{
-	struct el3_private *lp = netdev_priv(dev);
-
-	eth_hw_addr_set(dev, (u8 *)phys_addr);
-	dev->base_addr = ioaddr;
-	dev->irq = irq;
-	dev->if_port = if_port;
-	lp->type = type;
-}
-
-static int el3_isa_match(struct device *pdev, unsigned int ndev)
-{
-	struct net_device *dev;
-	int ioaddr, isa_irq, if_port, err;
-	unsigned int iobase;
-	__be16 phys_addr[3];
-
-	while ((err = el3_isa_id_sequence(phys_addr)) == 2)
-		;	/* Skip to next card when PnP card found */
-	if (err == 1)
-		return 0;
-
-	iobase = id_read_eeprom(8);
-	if_port = iobase >> 14;
-	ioaddr = 0x200 + ((iobase & 0x1f) << 4);
-	if (irq[el3_cards] > 1 && irq[el3_cards] < 16)
-		isa_irq = irq[el3_cards];
-	else
-		isa_irq = id_read_eeprom(9) >> 12;
-
-	dev = alloc_etherdev(sizeof(struct el3_private));
-	if (!dev)
-		return -ENOMEM;
-
-	SET_NETDEV_DEV(dev, pdev);
-
-	if (!request_region(ioaddr, EL3_IO_EXTENT, "3c509-isa")) {
-		free_netdev(dev);
-		return 0;
-	}
-
-	/* Set the adaptor tag so that the next card can be found. */
-	outb(0xd0 + ++current_tag, id_port);
-
-	/* Activate the adaptor at the EEPROM location. */
-	outb((ioaddr >> 4) | 0xe0, id_port);
-
-	EL3WINDOW(0);
-	if (inw(ioaddr) != 0x6d50) {
-		free_netdev(dev);
-		return 0;
-	}
-
-	/* Free the interrupt so that some other card can use it. */
-	outw(0x0f00, ioaddr + WN0_IRQ);
-
-	el3_dev_fill(dev, phys_addr, ioaddr, isa_irq, if_port, EL3_ISA);
-	dev_set_drvdata(pdev, dev);
-	if (el3_common_init(dev)) {
-		free_netdev(dev);
-		return 0;
-	}
-
-	el3_devs[el3_cards++] = dev;
-	return 1;
-}
-
-static void el3_isa_remove(struct device *pdev,
-				    unsigned int ndev)
-{
-	el3_device_remove(pdev);
-	dev_set_drvdata(pdev, NULL);
-}
-
-#ifdef CONFIG_PM
-static int el3_isa_suspend(struct device *dev, unsigned int n,
-			   pm_message_t state)
-{
-	current_tag = 0;
-	return el3_suspend(dev, state);
-}
-
-static int el3_isa_resume(struct device *dev, unsigned int n)
-{
-	struct net_device *ndev = dev_get_drvdata(dev);
-	int ioaddr = ndev->base_addr, err;
-	__be16 phys_addr[3];
-
-	while ((err = el3_isa_id_sequence(phys_addr)) == 2)
-		;	/* Skip to next card when PnP card found */
-	if (err == 1)
-		return 0;
-	/* Set the adaptor tag so that the next card can be found. */
-	outb(0xd0 + ++current_tag, id_port);
-	/* Enable the card */
-	outb((ioaddr >> 4) | 0xe0, id_port);
-	EL3WINDOW(0);
-	if (inw(ioaddr) != 0x6d50)
-		return 1;
-	/* Free the interrupt so that some other card can use it. */
-	outw(0x0f00, ioaddr + WN0_IRQ);
-	return el3_resume(dev);
-}
-#endif
-
-static struct isa_driver el3_isa_driver = {
-	.match		= el3_isa_match,
-	.remove		= el3_isa_remove,
-#ifdef CONFIG_PM
-	.suspend	= el3_isa_suspend,
-	.resume		= el3_isa_resume,
-#endif
-	.driver		= {
-		.name	= "3c509"
-	},
-};
-static int isa_registered;
-
-#ifdef CONFIG_PNP
-static const struct pnp_device_id el3_pnp_ids[] = {
-	{ .id = "TCM5090" }, /* 3Com Etherlink III (TP) */
-	{ .id = "TCM5091" }, /* 3Com Etherlink III */
-	{ .id = "TCM5094" }, /* 3Com Etherlink III (combo) */
-	{ .id = "TCM5095" }, /* 3Com Etherlink III (TPO) */
-	{ .id = "TCM5098" }, /* 3Com Etherlink III (TPC) */
-	{ .id = "PNP80f7" }, /* 3Com Etherlink III compatible */
-	{ .id = "PNP80f8" }, /* 3Com Etherlink III compatible */
-	{ .id = "" }
-};
-MODULE_DEVICE_TABLE(pnp, el3_pnp_ids);
-
-static int el3_pnp_probe(struct pnp_dev *pdev, const struct pnp_device_id *id)
-{
-	short i;
-	int ioaddr, irq, if_port;
-	__be16 phys_addr[3];
-	struct net_device *dev = NULL;
-	int err;
-
-	ioaddr = pnp_port_start(pdev, 0);
-	if (!request_region(ioaddr, EL3_IO_EXTENT, "3c509-pnp"))
-		return -EBUSY;
-	irq = pnp_irq(pdev, 0);
-	EL3WINDOW(0);
-	for (i = 0; i < 3; i++)
-		phys_addr[i] = htons(read_eeprom(ioaddr, i));
-	if_port = read_eeprom(ioaddr, 8) >> 14;
-	dev = alloc_etherdev(sizeof(struct el3_private));
-	if (!dev) {
-		release_region(ioaddr, EL3_IO_EXTENT);
-		return -ENOMEM;
-	}
-	SET_NETDEV_DEV(dev, &pdev->dev);
-
-	el3_dev_fill(dev, phys_addr, ioaddr, irq, if_port, EL3_PNP);
-	pnp_set_drvdata(pdev, dev);
-	err = el3_common_init(dev);
-
-	if (err) {
-		pnp_set_drvdata(pdev, NULL);
-		free_netdev(dev);
-		return err;
-	}
-
-	el3_devs[el3_cards++] = dev;
-	return 0;
-}
-
-static void el3_pnp_remove(struct pnp_dev *pdev)
-{
-	el3_common_remove(pnp_get_drvdata(pdev));
-	pnp_set_drvdata(pdev, NULL);
-}
-
-#ifdef CONFIG_PM
-static int el3_pnp_suspend(struct pnp_dev *pdev, pm_message_t state)
-{
-	return el3_suspend(&pdev->dev, state);
-}
-
-static int el3_pnp_resume(struct pnp_dev *pdev)
-{
-	return el3_resume(&pdev->dev);
-}
-#endif
-
-static struct pnp_driver el3_pnp_driver = {
-	.name		= "3c509",
-	.id_table	= el3_pnp_ids,
-	.probe		= el3_pnp_probe,
-	.remove		= el3_pnp_remove,
-#ifdef CONFIG_PM
-	.suspend	= el3_pnp_suspend,
-	.resume		= el3_pnp_resume,
-#endif
-};
-static int pnp_registered;
-#endif /* CONFIG_PNP */
-
-#ifdef CONFIG_EISA
-static const struct eisa_device_id el3_eisa_ids[] = {
-		{ "TCM5090" },
-		{ "TCM5091" },
-		{ "TCM5092" },
-		{ "TCM5093" },
-		{ "TCM5094" },
-		{ "TCM5095" },
-		{ "TCM5098" },
-		{ "" }
-};
-MODULE_DEVICE_TABLE(eisa, el3_eisa_ids);
-
-static int el3_eisa_probe (struct device *device);
-
-static struct eisa_driver el3_eisa_driver = {
-		.id_table = el3_eisa_ids,
-		.driver   = {
-				.name    = "3c579",
-				.probe   = el3_eisa_probe,
-				.remove  = el3_device_remove,
-				.suspend = el3_suspend,
-				.resume  = el3_resume,
-		}
-};
-static int eisa_registered;
-#endif
-
-static const struct net_device_ops netdev_ops = {
-	.ndo_open 		= el3_open,
-	.ndo_stop	 	= el3_close,
-	.ndo_start_xmit 	= el3_start_xmit,
-	.ndo_get_stats 		= el3_get_stats,
-	.ndo_set_rx_mode	= set_multicast_list,
-	.ndo_tx_timeout 	= el3_tx_timeout,
-	.ndo_set_mac_address 	= eth_mac_addr,
-	.ndo_validate_addr	= eth_validate_addr,
-#ifdef CONFIG_NET_POLL_CONTROLLER
-	.ndo_poll_controller	= el3_poll_controller,
-#endif
-};
-
-static int el3_common_init(struct net_device *dev)
-{
-	struct el3_private *lp = netdev_priv(dev);
-	int err;
-	static const char * const if_names[] = {
-		"10baseT", "AUI", "undefined", "BNC"
-	};
-
-	spin_lock_init(&lp->lock);
-
-	if (dev->mem_start & 0x05) { /* xcvr codes 1/3/4/12 */
-		dev->if_port = (dev->mem_start & 0x0f);
-	} else { /* xcvr codes 0/8 */
-		/* use eeprom value, but save user's full-duplex selection */
-		dev->if_port |= (dev->mem_start & 0x08);
-	}
-
-	/* The EL3-specific entries in the device structure. */
-	dev->netdev_ops = &netdev_ops;
-	dev->watchdog_timeo = TX_TIMEOUT;
-	dev->ethtool_ops = &ethtool_ops;
-
-	err = register_netdev(dev);
-	if (err) {
-		pr_err("Failed to register 3c5x9 at %#3.3lx, IRQ %d.\n",
-			dev->base_addr, dev->irq);
-		release_region(dev->base_addr, EL3_IO_EXTENT);
-		return err;
-	}
-
-	pr_info("%s: 3c5x9 found at %#3.3lx, %s port, address %pM, IRQ %d.\n",
-	       dev->name, dev->base_addr, if_names[(dev->if_port & 0x03)],
-	       dev->dev_addr, dev->irq);
-
-	return 0;
-
-}
-
-static void el3_common_remove (struct net_device *dev)
-{
-	unregister_netdev (dev);
-	release_region(dev->base_addr, EL3_IO_EXTENT);
-	free_netdev (dev);
-}
-
-#ifdef CONFIG_EISA
-static int el3_eisa_probe(struct device *device)
-{
-	short i;
-	int ioaddr, irq, if_port;
-	__be16 phys_addr[3];
-	struct net_device *dev = NULL;
-	struct eisa_device *edev;
-	int err;
-
-	/* Yeepee, The driver framework is calling us ! */
-	edev = to_eisa_device (device);
-	ioaddr = edev->base_addr;
-
-	if (!request_region(ioaddr, EL3_IO_EXTENT, "3c579-eisa"))
-		return -EBUSY;
-
-	/* Change the register set to the configuration window 0. */
-	outw(SelectWindow | 0, ioaddr + 0xC80 + EL3_CMD);
-
-	irq = inw(ioaddr + WN0_IRQ) >> 12;
-	if_port = inw(ioaddr + 6)>>14;
-	for (i = 0; i < 3; i++)
-		phys_addr[i] = htons(read_eeprom(ioaddr, i));
-
-	/* Restore the "Product ID" to the EEPROM read register. */
-	read_eeprom(ioaddr, 3);
-
-	dev = alloc_etherdev(sizeof (struct el3_private));
-	if (dev == NULL) {
-		release_region(ioaddr, EL3_IO_EXTENT);
-		return -ENOMEM;
-	}
-
-	SET_NETDEV_DEV(dev, device);
-
-	el3_dev_fill(dev, phys_addr, ioaddr, irq, if_port, EL3_EISA);
-	eisa_set_drvdata (edev, dev);
-	err = el3_common_init(dev);
-
-	if (err) {
-		eisa_set_drvdata (edev, NULL);
-		free_netdev(dev);
-		return err;
-	}
-
-	el3_devs[el3_cards++] = dev;
-	return 0;
-}
-#endif
-
-/* This remove works for all device types.
- *
- * The net dev must be stored in the driver data field */
-static int el3_device_remove(struct device *device)
-{
-	struct net_device *dev;
-
-	dev = dev_get_drvdata(device);
-
-	el3_common_remove (dev);
-	return 0;
-}
-
-/* Read a word from the EEPROM using the regular EEPROM access register.
-   Assume that we are in register window zero.
- */
-static ushort read_eeprom(int ioaddr, int index)
-{
-	outw(EEPROM_READ + index, ioaddr + 10);
-	/* Pause for at least 162 us. for the read to take place.
-	   Some chips seem to require much longer */
-	mdelay(2);
-	return inw(ioaddr + 12);
-}
-
-/* Read a word from the EEPROM when in the ISA ID probe state. */
-static ushort id_read_eeprom(int index)
-{
-	int bit, word = 0;
-
-	/* Issue read command, and pause for at least 162 us. for it to complete.
-	   Assume extra-fast 16Mhz bus. */
-	outb(EEPROM_READ + index, id_port);
-
-	/* Pause for at least 162 us. for the read to take place. */
-	/* Some chips seem to require much longer */
-	mdelay(4);
-
-	for (bit = 15; bit >= 0; bit--)
-		word = (word << 1) + (inb(id_port) & 0x01);
-
-	if (el3_debug > 3)
-		pr_debug("  3c509 EEPROM word %d %#4.4x.\n", index, word);
-
-	return word;
-}
-
-
-static int
-el3_open(struct net_device *dev)
-{
-	int ioaddr = dev->base_addr;
-	int i;
-
-	outw(TxReset, ioaddr + EL3_CMD);
-	outw(RxReset, ioaddr + EL3_CMD);
-	outw(SetStatusEnb | 0x00, ioaddr + EL3_CMD);
-
-	i = request_irq(dev->irq, el3_interrupt, 0, dev->name, dev);
-	if (i)
-		return i;
-
-	EL3WINDOW(0);
-	if (el3_debug > 3)
-		pr_debug("%s: Opening, IRQ %d	 status@%x %4.4x.\n", dev->name,
-			   dev->irq, ioaddr + EL3_STATUS, inw(ioaddr + EL3_STATUS));
-
-	el3_up(dev);
-
-	if (el3_debug > 3)
-		pr_debug("%s: Opened 3c509  IRQ %d  status %4.4x.\n",
-			   dev->name, dev->irq, inw(ioaddr + EL3_STATUS));
-
-	return 0;
-}
-
-static void
-el3_tx_timeout (struct net_device *dev, unsigned int txqueue)
-{
-	int ioaddr = dev->base_addr;
-
-	/* Transmitter timeout, serious problems. */
-	pr_warn("%s: transmit timed out, Tx_status %2.2x status %4.4x Tx FIFO room %d\n",
-		dev->name, inb(ioaddr + TX_STATUS), inw(ioaddr + EL3_STATUS),
-		inw(ioaddr + TX_FREE));
-	dev->stats.tx_errors++;
-	netif_trans_update(dev); /* prevent tx timeout */
-	/* Issue TX_RESET and TX_START commands. */
-	outw(TxReset, ioaddr + EL3_CMD);
-	outw(TxEnable, ioaddr + EL3_CMD);
-	netif_wake_queue(dev);
-}
-
-
-static netdev_tx_t
-el3_start_xmit(struct sk_buff *skb, struct net_device *dev)
-{
-	struct el3_private *lp = netdev_priv(dev);
-	int ioaddr = dev->base_addr;
-	unsigned long flags;
-
-	netif_stop_queue (dev);
-
-	dev->stats.tx_bytes += skb->len;
-
-	if (el3_debug > 4) {
-		pr_debug("%s: el3_start_xmit(length = %u) called, status %4.4x.\n",
-			   dev->name, skb->len, inw(ioaddr + EL3_STATUS));
-	}
-	/*
-	 *	We lock the driver against other processors. Note
-	 *	we don't need to lock versus the IRQ as we suspended
-	 *	that. This means that we lose the ability to take
-	 *	an RX during a TX upload. That sucks a bit with SMP
-	 *	on an original 3c509 (2K buffer)
-	 *
-	 *	Using disable_irq stops us crapping on other
-	 *	time sensitive devices.
-	 */
-
-	spin_lock_irqsave(&lp->lock, flags);
-
-	/* Put out the doubleword header... */
-	outw(skb->len, ioaddr + TX_FIFO);
-	outw(0x00, ioaddr + TX_FIFO);
-	/* ... and the packet rounded to a doubleword. */
-	outsl(ioaddr + TX_FIFO, skb->data, (skb->len + 3) >> 2);
-
-	if (inw(ioaddr + TX_FREE) > 1536)
-		netif_start_queue(dev);
-	else
-		/* Interrupt us when the FIFO has room for max-sized packet. */
-		outw(SetTxThreshold + 1536, ioaddr + EL3_CMD);
-
-	spin_unlock_irqrestore(&lp->lock, flags);
-
-	dev_consume_skb_any (skb);
-
-	/* Clear the Tx status stack. */
-	{
-		short tx_status;
-		int i = 4;
-
-		while (--i > 0	&&	(tx_status = inb(ioaddr + TX_STATUS)) > 0) {
-			if (tx_status & 0x38) dev->stats.tx_aborted_errors++;
-			if (tx_status & 0x30) outw(TxReset, ioaddr + EL3_CMD);
-			if (tx_status & 0x3C) outw(TxEnable, ioaddr + EL3_CMD);
-			outb(0x00, ioaddr + TX_STATUS); /* Pop the status stack. */
-		}
-	}
-	return NETDEV_TX_OK;
-}
-
-/* The EL3 interrupt handler. */
-static irqreturn_t
-el3_interrupt(int irq, void *dev_id)
-{
-	struct net_device *dev = dev_id;
-	struct el3_private *lp;
-	int ioaddr, status;
-	int i = max_interrupt_work;
-
-	lp = netdev_priv(dev);
-	spin_lock(&lp->lock);
-
-	ioaddr = dev->base_addr;
-
-	if (el3_debug > 4) {
-		status = inw(ioaddr + EL3_STATUS);
-		pr_debug("%s: interrupt, status %4.4x.\n", dev->name, status);
-	}
-
-	while ((status = inw(ioaddr + EL3_STATUS)) &
-		   (IntLatch | RxComplete | StatsFull)) {
-
-		if (status & RxComplete)
-			el3_rx(dev);
-
-		if (status & TxAvailable) {
-			if (el3_debug > 5)
-				pr_debug("	TX room bit was handled.\n");
-			/* There's room in the FIFO for a full-sized packet. */
-			outw(AckIntr | TxAvailable, ioaddr + EL3_CMD);
-			netif_wake_queue (dev);
-		}
-		if (status & (AdapterFailure | RxEarly | StatsFull | TxComplete)) {
-			/* Handle all uncommon interrupts. */
-			if (status & StatsFull)				/* Empty statistics. */
-				update_stats(dev);
-			if (status & RxEarly) {				/* Rx early is unused. */
-				el3_rx(dev);
-				outw(AckIntr | RxEarly, ioaddr + EL3_CMD);
-			}
-			if (status & TxComplete) {			/* Really Tx error. */
-				short tx_status;
-				int i = 4;
-
-				while (--i>0 && (tx_status = inb(ioaddr + TX_STATUS)) > 0) {
-					if (tx_status & 0x38) dev->stats.tx_aborted_errors++;
-					if (tx_status & 0x30) outw(TxReset, ioaddr + EL3_CMD);
-					if (tx_status & 0x3C) outw(TxEnable, ioaddr + EL3_CMD);
-					outb(0x00, ioaddr + TX_STATUS); /* Pop the status stack. */
-				}
-			}
-			if (status & AdapterFailure) {
-				/* Adapter failure requires Rx reset and reinit. */
-				outw(RxReset, ioaddr + EL3_CMD);
-				/* Set the Rx filter to the current state. */
-				outw(SetRxFilter | RxStation | RxBroadcast
-					 | (dev->flags & IFF_ALLMULTI ? RxMulticast : 0)
-					 | (dev->flags & IFF_PROMISC ? RxProm : 0),
-					 ioaddr + EL3_CMD);
-				outw(RxEnable, ioaddr + EL3_CMD); /* Re-enable the receiver. */
-				outw(AckIntr | AdapterFailure, ioaddr + EL3_CMD);
-			}
-		}
-
-		if (--i < 0) {
-			pr_err("%s: Infinite loop in interrupt, status %4.4x.\n",
-				   dev->name, status);
-			/* Clear all interrupts. */
-			outw(AckIntr | 0xFF, ioaddr + EL3_CMD);
-			break;
-		}
-		/* Acknowledge the IRQ. */
-		outw(AckIntr | IntReq | IntLatch, ioaddr + EL3_CMD); /* Ack IRQ */
-	}
-
-	if (el3_debug > 4) {
-		pr_debug("%s: exiting interrupt, status %4.4x.\n", dev->name,
-			   inw(ioaddr + EL3_STATUS));
-	}
-	spin_unlock(&lp->lock);
-	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 el3_poll_controller(struct net_device *dev)
-{
-	disable_irq(dev->irq);
-	el3_interrupt(dev->irq, dev);
-	enable_irq(dev->irq);
-}
-#endif
-
-static struct net_device_stats *
-el3_get_stats(struct net_device *dev)
-{
-	struct el3_private *lp = netdev_priv(dev);
-	unsigned long flags;
-
-	/*
-	 *	This is fast enough not to bother with disable IRQ
-	 *	stuff.
-	 */
-
-	spin_lock_irqsave(&lp->lock, flags);
-	update_stats(dev);
-	spin_unlock_irqrestore(&lp->lock, flags);
-	return &dev->stats;
-}
-
-/*  Update statistics.  We change to register window 6, so this should be run
-	single-threaded if the device is active. This is expected to be a rare
-	operation, and it's simpler for the rest of the driver to assume that
-	window 1 is always valid rather than use a special window-state variable.
-	*/
-static void update_stats(struct net_device *dev)
-{
-	int ioaddr = dev->base_addr;
-
-	if (el3_debug > 5)
-		pr_debug("   Updating the statistics.\n");
-	/* Turn off statistics updates while reading. */
-	outw(StatsDisable, ioaddr + EL3_CMD);
-	/* Switch to the stats window, and read everything. */
-	EL3WINDOW(6);
-	dev->stats.tx_carrier_errors 	+= inb(ioaddr + 0);
-	dev->stats.tx_heartbeat_errors	+= inb(ioaddr + 1);
-	/* Multiple collisions. */	   inb(ioaddr + 2);
-	dev->stats.collisions		+= inb(ioaddr + 3);
-	dev->stats.tx_window_errors	+= inb(ioaddr + 4);
-	dev->stats.rx_fifo_errors	+= inb(ioaddr + 5);
-	dev->stats.tx_packets		+= inb(ioaddr + 6);
-	/* Rx packets	*/		   inb(ioaddr + 7);
-	/* Tx deferrals */		   inb(ioaddr + 8);
-	inw(ioaddr + 10);	/* Total Rx and Tx octets. */
-	inw(ioaddr + 12);
-
-	/* Back to window 1, and turn statistics back on. */
-	EL3WINDOW(1);
-	outw(StatsEnable, ioaddr + EL3_CMD);
-}
-
-static int
-el3_rx(struct net_device *dev)
-{
-	int ioaddr = dev->base_addr;
-	short rx_status;
-
-	if (el3_debug > 5)
-		pr_debug("   In rx_packet(), status %4.4x, rx_status %4.4x.\n",
-			   inw(ioaddr+EL3_STATUS), inw(ioaddr+RX_STATUS));
-	while ((rx_status = inw(ioaddr + RX_STATUS)) > 0) {
-		if (rx_status & 0x4000) { /* Error, update stats. */
-			short error = rx_status & 0x3800;
-
-			outw(RxDiscard, ioaddr + EL3_CMD);
-			dev->stats.rx_errors++;
-			switch (error) {
-			case 0x0000:		dev->stats.rx_over_errors++; break;
-			case 0x0800:		dev->stats.rx_length_errors++; break;
-			case 0x1000:		dev->stats.rx_frame_errors++; break;
-			case 0x1800:		dev->stats.rx_length_errors++; break;
-			case 0x2000:		dev->stats.rx_frame_errors++; break;
-			case 0x2800:		dev->stats.rx_crc_errors++; break;
-			}
-		} else {
-			short pkt_len = rx_status & 0x7ff;
-			struct sk_buff *skb;
-
-			skb = netdev_alloc_skb(dev, pkt_len + 5);
-			if (el3_debug > 4)
-				pr_debug("Receiving packet size %d status %4.4x.\n",
-					   pkt_len, rx_status);
-			if (skb != NULL) {
-				skb_reserve(skb, 2);     /* Align IP on 16 byte */
-
-				/* 'skb->data' points to the start of sk_buff data area. */
-				insl(ioaddr + RX_FIFO, skb_put(skb,pkt_len),
-					 (pkt_len + 3) >> 2);
-
-				outw(RxDiscard, ioaddr + EL3_CMD); /* Pop top Rx packet. */
-				skb->protocol = eth_type_trans(skb,dev);
-				netif_rx(skb);
-				dev->stats.rx_bytes += pkt_len;
-				dev->stats.rx_packets++;
-				continue;
-			}
-			outw(RxDiscard, ioaddr + EL3_CMD);
-			dev->stats.rx_dropped++;
-			if (el3_debug)
-				pr_debug("%s: Couldn't allocate a sk_buff of size %d.\n",
-					   dev->name, pkt_len);
-		}
-		inw(ioaddr + EL3_STATUS); 				/* Delay. */
-		while (inw(ioaddr + EL3_STATUS) & 0x1000)
-			pr_debug("	Waiting for 3c509 to discard packet, status %x.\n",
-				   inw(ioaddr + EL3_STATUS) );
-	}
-
-	return 0;
-}
-
-/*
- *     Set or clear the multicast filter for this adaptor.
- */
-static void
-set_multicast_list(struct net_device *dev)
-{
-	unsigned long flags;
-	struct el3_private *lp = netdev_priv(dev);
-	int ioaddr = dev->base_addr;
-	int mc_count = netdev_mc_count(dev);
-
-	if (el3_debug > 1) {
-		static int old;
-		if (old != mc_count) {
-			old = mc_count;
-			pr_debug("%s: Setting Rx mode to %d addresses.\n",
-				 dev->name, mc_count);
-		}
-	}
-	spin_lock_irqsave(&lp->lock, flags);
-	if (dev->flags&IFF_PROMISC) {
-		outw(SetRxFilter | RxStation | RxMulticast | RxBroadcast | RxProm,
-			 ioaddr + EL3_CMD);
-	}
-	else if (mc_count || (dev->flags&IFF_ALLMULTI)) {
-		outw(SetRxFilter | RxStation | RxMulticast | RxBroadcast, ioaddr + EL3_CMD);
-	}
-	else
-		outw(SetRxFilter | RxStation | RxBroadcast, ioaddr + EL3_CMD);
-	spin_unlock_irqrestore(&lp->lock, flags);
-}
-
-static int
-el3_close(struct net_device *dev)
-{
-	int ioaddr = dev->base_addr;
-	struct el3_private *lp = netdev_priv(dev);
-
-	if (el3_debug > 2)
-		pr_debug("%s: Shutting down ethercard.\n", dev->name);
-
-	el3_down(dev);
-
-	free_irq(dev->irq, dev);
-	/* Switching back to window 0 disables the IRQ. */
-	EL3WINDOW(0);
-	if (lp->type != EL3_EISA) {
-		/* But we explicitly zero the IRQ line select anyway. Don't do
-		 * it on EISA cards, it prevents the module from getting an
-		 * IRQ after unload+reload... */
-		outw(0x0f00, ioaddr + WN0_IRQ);
-	}
-
-	return 0;
-}
-
-static int
-el3_link_ok(struct net_device *dev)
-{
-	int ioaddr = dev->base_addr;
-	u16 tmp;
-
-	EL3WINDOW(4);
-	tmp = inw(ioaddr + WN4_MEDIA);
-	EL3WINDOW(1);
-	return tmp & (1<<11);
-}
-
-static void
-el3_netdev_get_ecmd(struct net_device *dev, struct ethtool_link_ksettings *cmd)
-{
-	u16 tmp;
-	int ioaddr = dev->base_addr;
-	u32 supported;
-
-	EL3WINDOW(0);
-	/* obtain current transceiver via WN4_MEDIA? */
-	tmp = inw(ioaddr + WN0_ADDR_CONF);
-	switch (tmp >> 14) {
-	case 0:
-		cmd->base.port = PORT_TP;
-		break;
-	case 1:
-		cmd->base.port = PORT_AUI;
-		break;
-	case 3:
-		cmd->base.port = PORT_BNC;
-		break;
-	default:
-		break;
-	}
-
-	cmd->base.duplex = DUPLEX_HALF;
-	supported = 0;
-	tmp = inw(ioaddr + WN0_CONF_CTRL);
-	if (tmp & (1<<13))
-		supported |= SUPPORTED_AUI;
-	if (tmp & (1<<12))
-		supported |= SUPPORTED_BNC;
-	if (tmp & (1<<9)) {
-		supported |= SUPPORTED_TP | SUPPORTED_10baseT_Half |
-				SUPPORTED_10baseT_Full;	/* hmm... */
-		EL3WINDOW(4);
-		tmp = inw(ioaddr + WN4_NETDIAG);
-		if (tmp & FD_ENABLE)
-			cmd->base.duplex = DUPLEX_FULL;
-	}
-
-	ethtool_convert_legacy_u32_to_link_mode(cmd->link_modes.supported,
-						supported);
-	cmd->base.speed = SPEED_10;
-	EL3WINDOW(1);
-}
-
-static int
-el3_netdev_set_ecmd(struct net_device *dev,
-		    const struct ethtool_link_ksettings *cmd)
-{
-	u16 tmp;
-	int ioaddr = dev->base_addr;
-
-	if (cmd->base.speed != SPEED_10)
-		return -EINVAL;
-	if ((cmd->base.duplex != DUPLEX_HALF) &&
-	    (cmd->base.duplex != DUPLEX_FULL))
-		return -EINVAL;
-
-	/* change XCVR type */
-	EL3WINDOW(0);
-	tmp = inw(ioaddr + WN0_ADDR_CONF);
-	switch (cmd->base.port) {
-	case PORT_TP:
-		tmp &= ~(3<<14);
-		dev->if_port = 0;
-		break;
-	case PORT_AUI:
-		tmp |= (1<<14);
-		dev->if_port = 1;
-		break;
-	case PORT_BNC:
-		tmp |= (3<<14);
-		dev->if_port = 3;
-		break;
-	default:
-		return -EINVAL;
-	}
-
-	outw(tmp, ioaddr + WN0_ADDR_CONF);
-	if (dev->if_port == 3) {
-		/* fire up the DC-DC convertor if BNC gets enabled */
-		tmp = inw(ioaddr + WN0_ADDR_CONF);
-		if (tmp & (3 << 14)) {
-			outw(StartCoax, ioaddr + EL3_CMD);
-			udelay(800);
-		} else
-			return -EIO;
-	}
-
-	EL3WINDOW(4);
-	tmp = inw(ioaddr + WN4_NETDIAG);
-	if (cmd->base.duplex == DUPLEX_FULL)
-		tmp |= FD_ENABLE;
-	else
-		tmp &= ~FD_ENABLE;
-	outw(tmp, ioaddr + WN4_NETDIAG);
-	EL3WINDOW(1);
-
-	return 0;
-}
-
-static void el3_get_drvinfo(struct net_device *dev, struct ethtool_drvinfo *info)
-{
-	strscpy(info->driver, DRV_NAME, sizeof(info->driver));
-}
-
-static int el3_get_link_ksettings(struct net_device *dev,
-				  struct ethtool_link_ksettings *cmd)
-{
-	struct el3_private *lp = netdev_priv(dev);
-
-	spin_lock_irq(&lp->lock);
-	el3_netdev_get_ecmd(dev, cmd);
-	spin_unlock_irq(&lp->lock);
-	return 0;
-}
-
-static int el3_set_link_ksettings(struct net_device *dev,
-				  const struct ethtool_link_ksettings *cmd)
-{
-	struct el3_private *lp = netdev_priv(dev);
-	int ret;
-
-	spin_lock_irq(&lp->lock);
-	ret = el3_netdev_set_ecmd(dev, cmd);
-	spin_unlock_irq(&lp->lock);
-	return ret;
-}
-
-static u32 el3_get_link(struct net_device *dev)
-{
-	struct el3_private *lp = netdev_priv(dev);
-	u32 ret;
-
-	spin_lock_irq(&lp->lock);
-	ret = el3_link_ok(dev);
-	spin_unlock_irq(&lp->lock);
-	return ret;
-}
-
-static u32 el3_get_msglevel(struct net_device *dev)
-{
-	return el3_debug;
-}
-
-static void el3_set_msglevel(struct net_device *dev, u32 v)
-{
-	el3_debug = v;
-}
-
-static const struct ethtool_ops ethtool_ops = {
-	.get_drvinfo = el3_get_drvinfo,
-	.get_link = el3_get_link,
-	.get_msglevel = el3_get_msglevel,
-	.set_msglevel = el3_set_msglevel,
-	.get_link_ksettings = el3_get_link_ksettings,
-	.set_link_ksettings = el3_set_link_ksettings,
-};
-
-static void
-el3_down(struct net_device *dev)
-{
-	int ioaddr = dev->base_addr;
-
-	netif_stop_queue(dev);
-
-	/* Turn off statistics ASAP.  We update lp->stats below. */
-	outw(StatsDisable, ioaddr + EL3_CMD);
-
-	/* Disable the receiver and transmitter. */
-	outw(RxDisable, ioaddr + EL3_CMD);
-	outw(TxDisable, ioaddr + EL3_CMD);
-
-	if (dev->if_port == 3)
-		/* Turn off thinnet power.  Green! */
-		outw(StopCoax, ioaddr + EL3_CMD);
-	else if (dev->if_port == 0) {
-		/* Disable link beat and jabber, if_port may change here next open(). */
-		EL3WINDOW(4);
-		outw(inw(ioaddr + WN4_MEDIA) & ~MEDIA_TP, ioaddr + WN4_MEDIA);
-	}
-
-	outw(SetIntrEnb | 0x0000, ioaddr + EL3_CMD);
-
-	update_stats(dev);
-}
-
-static void
-el3_up(struct net_device *dev)
-{
-	int i, sw_info, net_diag;
-	int ioaddr = dev->base_addr;
-
-	/* Activating the board required and does no harm otherwise */
-	outw(0x0001, ioaddr + 4);
-
-	/* Set the IRQ line. */
-	outw((dev->irq << 12) | 0x0f00, ioaddr + WN0_IRQ);
-
-	/* Set the station address in window 2 each time opened. */
-	EL3WINDOW(2);
-
-	for (i = 0; i < 6; i++)
-		outb(dev->dev_addr[i], ioaddr + i);
-
-	if ((dev->if_port & 0x03) == 3) /* BNC interface */
-		/* Start the thinnet transceiver. We should really wait 50ms...*/
-		outw(StartCoax, ioaddr + EL3_CMD);
-	else if ((dev->if_port & 0x03) == 0) { /* 10baseT interface */
-		/* Combine secondary sw_info word (the adapter level) and primary
-			sw_info word (duplex setting plus other useless bits) */
-		EL3WINDOW(0);
-		sw_info = (read_eeprom(ioaddr, 0x14) & 0x400f) |
-			(read_eeprom(ioaddr, 0x0d) & 0xBff0);
-
-		EL3WINDOW(4);
-		net_diag = inw(ioaddr + WN4_NETDIAG);
-		net_diag = (net_diag | FD_ENABLE); /* temporarily assume full-duplex will be set */
-		pr_info("%s: ", dev->name);
-		switch (dev->if_port & 0x0c) {
-			case 12:
-				/* force full-duplex mode if 3c5x9b */
-				if (sw_info & 0x000f) {
-					pr_cont("Forcing 3c5x9b full-duplex mode");
-					break;
-				}
-				fallthrough;
-			case 8:
-				/* set full-duplex mode based on eeprom config setting */
-				if ((sw_info & 0x000f) && (sw_info & 0x8000)) {
-					pr_cont("Setting 3c5x9b full-duplex mode (from EEPROM configuration bit)");
-					break;
-				}
-				fallthrough;
-			default:
-				/* xcvr=(0 || 4) OR user has an old 3c5x9 non "B" model */
-				pr_cont("Setting 3c5x9/3c5x9B half-duplex mode");
-				net_diag = (net_diag & ~FD_ENABLE); /* disable full duplex */
-		}
-
-		outw(net_diag, ioaddr + WN4_NETDIAG);
-		pr_cont(" if_port: %d, sw_info: %4.4x\n", dev->if_port, sw_info);
-		if (el3_debug > 3)
-			pr_debug("%s: 3c5x9 net diag word is now: %4.4x.\n", dev->name, net_diag);
-		/* Enable link beat and jabber check. */
-		outw(inw(ioaddr + WN4_MEDIA) | MEDIA_TP, ioaddr + WN4_MEDIA);
-	}
-
-	/* Switch to the stats window, and clear all stats by reading. */
-	outw(StatsDisable, ioaddr + EL3_CMD);
-	EL3WINDOW(6);
-	for (i = 0; i < 9; i++)
-		inb(ioaddr + i);
-	inw(ioaddr + 10);
-	inw(ioaddr + 12);
-
-	/* Switch to register set 1 for normal use. */
-	EL3WINDOW(1);
-
-	/* Accept b-case and phys addr only. */
-	outw(SetRxFilter | RxStation | RxBroadcast, ioaddr + EL3_CMD);
-	outw(StatsEnable, ioaddr + EL3_CMD); /* Turn on statistics. */
-
-	outw(RxEnable, ioaddr + EL3_CMD); /* Enable the receiver. */
-	outw(TxEnable, ioaddr + EL3_CMD); /* Enable transmitter. */
-	/* Allow status bits to be seen. */
-	outw(SetStatusEnb | 0xff, ioaddr + EL3_CMD);
-	/* Ack all pending events, and set active indicator mask. */
-	outw(AckIntr | IntLatch | TxAvailable | RxEarly | IntReq,
-		 ioaddr + EL3_CMD);
-	outw(SetIntrEnb | IntLatch|TxAvailable|TxComplete|RxComplete|StatsFull,
-		 ioaddr + EL3_CMD);
-
-	netif_start_queue(dev);
-}
-
-/* Power Management support functions */
-#ifdef CONFIG_PM
-
-static int
-el3_suspend(struct device *pdev, pm_message_t state)
-{
-	unsigned long flags;
-	struct net_device *dev;
-	struct el3_private *lp;
-	int ioaddr;
-
-	dev = dev_get_drvdata(pdev);
-	lp = netdev_priv(dev);
-	ioaddr = dev->base_addr;
-
-	spin_lock_irqsave(&lp->lock, flags);
-
-	if (netif_running(dev))
-		netif_device_detach(dev);
-
-	el3_down(dev);
-	outw(PowerDown, ioaddr + EL3_CMD);
-
-	spin_unlock_irqrestore(&lp->lock, flags);
-	return 0;
-}
-
-static int
-el3_resume(struct device *pdev)
-{
-	unsigned long flags;
-	struct net_device *dev;
-	struct el3_private *lp;
-	int ioaddr;
-
-	dev = dev_get_drvdata(pdev);
-	lp = netdev_priv(dev);
-	ioaddr = dev->base_addr;
-
-	spin_lock_irqsave(&lp->lock, flags);
-
-	outw(PowerUp, ioaddr + EL3_CMD);
-	EL3WINDOW(0);
-	el3_up(dev);
-
-	if (netif_running(dev))
-		netif_device_attach(dev);
-
-	spin_unlock_irqrestore(&lp->lock, flags);
-	return 0;
-}
-
-#endif /* CONFIG_PM */
-
-module_param(debug,int, 0);
-module_param_hw_array(irq, int, irq, NULL, 0);
-module_param(max_interrupt_work, int, 0);
-MODULE_PARM_DESC(debug, "debug level (0-6)");
-MODULE_PARM_DESC(irq, "IRQ number(s) (assigned)");
-MODULE_PARM_DESC(max_interrupt_work, "maximum events handled per interrupt");
-#ifdef CONFIG_PNP
-module_param(nopnp, int, 0);
-MODULE_PARM_DESC(nopnp, "disable ISA PnP support (0-1)");
-#endif	/* CONFIG_PNP */
-MODULE_DESCRIPTION("3Com Etherlink III (3c509, 3c509B, 3c529, 3c579) ethernet driver");
-MODULE_LICENSE("GPL");
-
-static int __init el3_init_module(void)
-{
-	int ret = 0;
-
-	if (debug >= 0)
-		el3_debug = debug;
-
-#ifdef CONFIG_PNP
-	if (!nopnp) {
-		ret = pnp_register_driver(&el3_pnp_driver);
-		if (!ret)
-			pnp_registered = 1;
-	}
-#endif
-	/* Select an open I/O location at 0x1*0 to do ISA contention select. */
-	/* Start with 0x110 to avoid some sound cards.*/
-	for (id_port = 0x110 ; id_port < 0x200; id_port += 0x10) {
-		if (!request_region(id_port, 1, "3c509-control"))
-			continue;
-		outb(0x00, id_port);
-		outb(0xff, id_port);
-		if (inb(id_port) & 0x01)
-			break;
-		else
-			release_region(id_port, 1);
-	}
-	if (id_port >= 0x200) {
-		id_port = 0;
-		pr_err("No I/O port available for 3c509 activation.\n");
-	} else {
-		ret = isa_register_driver(&el3_isa_driver, EL3_MAX_CARDS);
-		if (!ret)
-			isa_registered = 1;
-	}
-#ifdef CONFIG_EISA
-	ret = eisa_driver_register(&el3_eisa_driver);
-	if (!ret)
-		eisa_registered = 1;
-#endif
-
-#ifdef CONFIG_PNP
-	if (pnp_registered)
-		ret = 0;
-#endif
-	if (isa_registered)
-		ret = 0;
-#ifdef CONFIG_EISA
-	if (eisa_registered)
-		ret = 0;
-#endif
-	return ret;
-}
-
-static void __exit el3_cleanup_module(void)
-{
-#ifdef CONFIG_PNP
-	if (pnp_registered)
-		pnp_unregister_driver(&el3_pnp_driver);
-#endif
-	if (isa_registered)
-		isa_unregister_driver(&el3_isa_driver);
-	if (id_port)
-		release_region(id_port, 1);
-#ifdef CONFIG_EISA
-	if (eisa_registered)
-		eisa_driver_unregister(&el3_eisa_driver);
-#endif
-}
-
-module_init (el3_init_module);
-module_exit (el3_cleanup_module);
diff --git a/drivers/net/ethernet/3com/Kconfig b/drivers/net/ethernet/3com/Kconfig
index 1fbab79e2be4..c05a1b63c1c9 100644
--- a/drivers/net/ethernet/3com/Kconfig
+++ b/drivers/net/ethernet/3com/Kconfig
@@ -17,20 +17,6 @@ config NET_VENDOR_3COM
 
 if NET_VENDOR_3COM
 
-config EL3
-	tristate "3c509/3c579 \"EtherLink III\" support"
-	depends on (ISA || EISA)
-	help
-	  If you have a network (Ethernet) card belonging to the 3Com
-	  EtherLinkIII series, say Y here.
-
-	  If your card is not working you may need to use the DOS
-	  setup disk to disable Plug & Play mode, and to select the default
-	  media type.
-
-	  To compile this driver as a module, choose M here. The module
-	  will be called 3c509.
-
 config 3C515
 	tristate "3c515 ISA \"Fast EtherLink\""
 	depends on ISA && ISA_DMA_API && !PPC32
diff --git a/drivers/net/ethernet/3com/Makefile b/drivers/net/ethernet/3com/Makefile
index f8b73babc510..f7623fa2d441 100644
--- a/drivers/net/ethernet/3com/Makefile
+++ b/drivers/net/ethernet/3com/Makefile
@@ -3,7 +3,6 @@
 # Makefile for the 3Com Ethernet device drivers
 #
 
-obj-$(CONFIG_EL3) += 3c509.o
 obj-$(CONFIG_3C515) += 3c515.o
 obj-$(CONFIG_PCMCIA_3C589) += 3c589_cs.o
 obj-$(CONFIG_PCMCIA_3C574) += 3c574_cs.o

-- 
2.53.0


^ permalink raw reply related	[flat|nested] 28+ messages in thread

* [PATCH net 02/18] drivers: net: 3com: 3c515: Remove this driver
  2026-04-21 19:31 [PATCH net 00/18] Remove a number of ISA and PCMCIA Ethernet drivers Andrew Lunn
  2026-04-21 19:31 ` [PATCH net 01/18] drivers: net: 3com: 3c509: Remove this driver Andrew Lunn
@ 2026-04-21 19:31 ` Andrew Lunn
  2026-04-21 19:31 ` [PATCH net 03/18] drivers: net: 3com: 3c574: " Andrew Lunn
                   ` (19 subsequent siblings)
  21 siblings, 0 replies; 28+ messages in thread
From: Andrew Lunn @ 2026-04-21 19:31 UTC (permalink / raw)
  To: Andrew Lunn, David S. Miller, Eric Dumazet, Jakub Kicinski,
	Paolo Abeni, Simon Horman, Jonathan Corbet, Shuah Khan
  Cc: linux-kernel, netdev, linux-doc, Andrew Lunn

The 3c515 was written by Donald Becker between 1997-1998. It is an ISA
device, so unlikely to be used with modern kernels.

Signed-off-by: Andrew Lunn <andrew@lunn.ch>
---
 drivers/net/ethernet/3com/3c515.c  | 1566 ------------------------------------
 drivers/net/ethernet/3com/Kconfig  |   11 -
 drivers/net/ethernet/3com/Makefile |    1 -
 3 files changed, 1578 deletions(-)

diff --git a/drivers/net/ethernet/3com/3c515.c b/drivers/net/ethernet/3com/3c515.c
deleted file mode 100644
index 2227c83a4862..000000000000
--- a/drivers/net/ethernet/3com/3c515.c
+++ /dev/null
@@ -1,1566 +0,0 @@
-/*
-	Written 1997-1998 by Donald Becker.
-
-	This software may be used and distributed according to the terms
-	of the GNU General Public License, incorporated herein by reference.
-
-	This driver is for the 3Com ISA EtherLink XL "Corkscrew" 3c515 ethercard.
-
-	The author may be reached as becker@scyld.com, or C/O
-	Scyld Computing Corporation
-	410 Severn Ave., Suite 210
-	Annapolis MD 21403
-
-
-	2000/2/2- Added support for kernel-level ISAPnP
-		by Stephen Frost <sfrost@snowman.net> and Alessandro Zummo
-	Cleaned up for 2.3.x/softnet by Jeff Garzik and Alan Cox.
-
-	2001/11/17 - Added ethtool support (jgarzik)
-
-	2002/10/28 - Locking updates for 2.5 (alan@lxorguk.ukuu.org.uk)
-
-*/
-
-#define DRV_NAME		"3c515"
-
-#define CORKSCREW 1
-
-/* "Knobs" that adjust features and parameters. */
-/* Set the copy breakpoint for the copy-only-tiny-frames scheme.
-   Setting to > 1512 effectively disables this feature. */
-static int rx_copybreak = 200;
-
-/* Maximum events (Rx packets, etc.) to handle at each interrupt. */
-static int max_interrupt_work = 20;
-
-/* Enable the automatic media selection code -- usually set. */
-#define AUTOMEDIA 1
-
-/* Allow the use of fragment bus master transfers instead of only
-   programmed-I/O for Vortex cards.  Full-bus-master transfers are always
-   enabled by default on Boomerang cards.  If VORTEX_BUS_MASTER is defined,
-   the feature may be turned on using 'options'. */
-#define VORTEX_BUS_MASTER
-
-/* A few values that may be tweaked. */
-/* Keep the ring sizes a power of two for efficiency. */
-#define TX_RING_SIZE	16
-#define RX_RING_SIZE	16
-#define PKT_BUF_SZ		1536	/* Size of each temporary Rx buffer. */
-
-#include <linux/module.h>
-#include <linux/isapnp.h>
-#include <linux/kernel.h>
-#include <linux/netdevice.h>
-#include <linux/string.h>
-#include <linux/errno.h>
-#include <linux/in.h>
-#include <linux/ioport.h>
-#include <linux/skbuff.h>
-#include <linux/etherdevice.h>
-#include <linux/interrupt.h>
-#include <linux/timer.h>
-#include <linux/ethtool.h>
-#include <linux/bitops.h>
-#include <linux/uaccess.h>
-
-#include <net/Space.h>
-
-#include <asm/io.h>
-#include <asm/dma.h>
-
-#define NEW_MULTICAST
-#include <linux/delay.h>
-
-#define MAX_UNITS 8
-
-MODULE_AUTHOR("Donald Becker <becker@scyld.com>");
-MODULE_DESCRIPTION("3Com 3c515 Corkscrew driver");
-MODULE_LICENSE("GPL");
-
-/* "Knobs" for adjusting internal parameters. */
-/* Put out somewhat more debugging messages. (0 - no msg, 1 minimal msgs). */
-#define DRIVER_DEBUG 1
-/* Some values here only for performance evaluation and path-coverage
-   debugging. */
-static int rx_nocopy, rx_copy, queued_packet;
-
-/* Number of times to check to see if the Tx FIFO has space, used in some
-   limited cases. */
-#define WAIT_TX_AVAIL 200
-
-/* Operational parameter that usually are not changed. */
-#define TX_TIMEOUT  ((4*HZ)/10)	/* Time in jiffies before concluding Tx hung */
-
-/* The size here is somewhat misleading: the Corkscrew also uses the ISA
-   aliased registers at <base>+0x400.
-   */
-#define CORKSCREW_TOTAL_SIZE 0x20
-
-#ifdef DRIVER_DEBUG
-static int corkscrew_debug = DRIVER_DEBUG;
-#else
-static int corkscrew_debug = 1;
-#endif
-
-#define CORKSCREW_ID 10
-
-/*
-				Theory of Operation
-
-I. Board Compatibility
-
-This device driver is designed for the 3Com 3c515 ISA Fast EtherLink XL,
-3Com's ISA bus adapter for Fast Ethernet.  Due to the unique I/O port layout,
-it's not practical to integrate this driver with the other EtherLink drivers.
-
-II. Board-specific settings
-
-The Corkscrew has an EEPROM for configuration, but no special settings are
-needed for Linux.
-
-III. Driver operation
-
-The 3c515 series use an interface that's very similar to the 3c900 "Boomerang"
-PCI cards, with the bus master interface extensively modified to work with
-the ISA bus.
-
-The card is capable of full-bus-master transfers with separate
-lists of transmit and receive descriptors, similar to the AMD LANCE/PCnet,
-DEC Tulip and Intel Speedo3.
-
-This driver uses a "RX_COPYBREAK" scheme rather than a fixed intermediate
-receive buffer.  This scheme allocates full-sized skbuffs as receive
-buffers.  The value RX_COPYBREAK is used as the copying breakpoint: it is
-chosen to trade-off the memory wasted by passing the full-sized skbuff to
-the queue layer for all frames vs. the copying cost of copying a frame to a
-correctly-sized skbuff.
-
-
-IIIC. Synchronization
-The driver runs as two independent, single-threaded flows of control.  One
-is the send-packet routine, which enforces single-threaded use by the netif
-layer.  The other thread is the interrupt handler, which is single
-threaded by the hardware and other software.
-
-IV. Notes
-
-Thanks to Terry Murphy of 3Com for providing documentation and a development
-board.
-
-The names "Vortex", "Boomerang" and "Corkscrew" are the internal 3Com
-project names.  I use these names to eliminate confusion -- 3Com product
-numbers and names are very similar and often confused.
-
-The new chips support both ethernet (1.5K) and FDDI (4.5K) frame sizes!
-This driver only supports ethernet frames because of the recent MTU limit
-of 1.5K, but the changes to support 4.5K are minimal.
-*/
-
-/* Operational definitions.
-   These are not used by other compilation units and thus are not
-   exported in a ".h" file.
-
-   First the windows.  There are eight register windows, with the command
-   and status registers available in each.
-   */
-#define EL3WINDOW(win_num) outw(SelectWindow + (win_num), ioaddr + EL3_CMD)
-#define EL3_CMD 0x0e
-#define EL3_STATUS 0x0e
-
-/* The top five bits written to EL3_CMD are a command, the lower
-   11 bits are the parameter, if applicable.
-   Note that 11 parameters bits was fine for ethernet, but the new chips
-   can handle FDDI length frames (~4500 octets) and now parameters count
-   32-bit 'Dwords' rather than octets. */
-
-enum corkscrew_cmd {
-	TotalReset = 0 << 11, SelectWindow = 1 << 11, StartCoax = 2 << 11,
-	RxDisable = 3 << 11, RxEnable = 4 << 11, RxReset = 5 << 11,
-	UpStall = 6 << 11, UpUnstall = (6 << 11) + 1, DownStall = (6 << 11) + 2,
-	DownUnstall = (6 << 11) + 3, RxDiscard = 8 << 11, TxEnable = 9 << 11,
-	TxDisable = 10 << 11, TxReset = 11 << 11, FakeIntr = 12 << 11,
-	AckIntr = 13 << 11, SetIntrEnb = 14 << 11, SetStatusEnb = 15 << 11,
-	SetRxFilter = 16 << 11, SetRxThreshold = 17 << 11,
-	SetTxThreshold = 18 << 11, SetTxStart = 19 << 11, StartDMAUp = 20 << 11,
-	StartDMADown = (20 << 11) + 1, StatsEnable = 21 << 11,
-	StatsDisable = 22 << 11, StopCoax = 23 << 11,
-};
-
-/* The SetRxFilter command accepts the following classes: */
-enum RxFilter {
-	RxStation = 1, RxMulticast = 2, RxBroadcast = 4, RxProm = 8
-};
-
-/* Bits in the general status register. */
-enum corkscrew_status {
-	IntLatch = 0x0001, AdapterFailure = 0x0002, TxComplete = 0x0004,
-	TxAvailable = 0x0008, RxComplete = 0x0010, RxEarly = 0x0020,
-	IntReq = 0x0040, StatsFull = 0x0080,
-	DMADone = 1 << 8, DownComplete = 1 << 9, UpComplete = 1 << 10,
-	DMAInProgress = 1 << 11,	/* DMA controller is still busy. */
-	CmdInProgress = 1 << 12,	/* EL3_CMD is still busy. */
-};
-
-/* Register window 1 offsets, the window used in normal operation.
-   On the Corkscrew this window is always mapped at offsets 0x10-0x1f. */
-enum Window1 {
-	TX_FIFO = 0x10, RX_FIFO = 0x10, RxErrors = 0x14,
-	RxStatus = 0x18, Timer = 0x1A, TxStatus = 0x1B,
-	TxFree = 0x1C,		/* Remaining free bytes in Tx buffer. */
-};
-enum Window0 {
-	Wn0IRQ = 0x08,
-#if defined(CORKSCREW)
-	Wn0EepromCmd = 0x200A,	/* Corkscrew EEPROM command register. */
-	Wn0EepromData = 0x200C,	/* Corkscrew EEPROM results register. */
-#else
-	Wn0EepromCmd = 10,	/* Window 0: EEPROM command register. */
-	Wn0EepromData = 12,	/* Window 0: EEPROM results register. */
-#endif
-};
-enum Win0_EEPROM_bits {
-	EEPROM_Read = 0x80, EEPROM_WRITE = 0x40, EEPROM_ERASE = 0xC0,
-	EEPROM_EWENB = 0x30,	/* Enable erasing/writing for 10 msec. */
-	EEPROM_EWDIS = 0x00,	/* Disable EWENB before 10 msec timeout. */
-};
-
-/* EEPROM locations. */
-enum eeprom_offset {
-	PhysAddr01 = 0, PhysAddr23 = 1, PhysAddr45 = 2, ModelID = 3,
-	EtherLink3ID = 7,
-};
-
-enum Window3 {			/* Window 3: MAC/config bits. */
-	Wn3_Config = 0, Wn3_MAC_Ctrl = 6, Wn3_Options = 8,
-};
-enum wn3_config {
-	Ram_size = 7,
-	Ram_width = 8,
-	Ram_speed = 0x30,
-	Rom_size = 0xc0,
-	Ram_split_shift = 16,
-	Ram_split = 3 << Ram_split_shift,
-	Xcvr_shift = 20,
-	Xcvr = 7 << Xcvr_shift,
-	Autoselect = 0x1000000,
-};
-
-enum Window4 {
-	Wn4_NetDiag = 6, Wn4_Media = 10,	/* Window 4: Xcvr/media bits. */
-};
-enum Win4_Media_bits {
-	Media_SQE = 0x0008,	/* Enable SQE error counting for AUI. */
-	Media_10TP = 0x00C0,	/* Enable link beat and jabber for 10baseT. */
-	Media_Lnk = 0x0080,	/* Enable just link beat for 100TX/100FX. */
-	Media_LnkBeat = 0x0800,
-};
-enum Window7 {			/* Window 7: Bus Master control. */
-	Wn7_MasterAddr = 0, Wn7_MasterLen = 6, Wn7_MasterStatus = 12,
-};
-
-/* Boomerang-style bus master control registers.  Note ISA aliases! */
-enum MasterCtrl {
-	PktStatus = 0x400, DownListPtr = 0x404, FragAddr = 0x408, FragLen =
-	    0x40c,
-	TxFreeThreshold = 0x40f, UpPktStatus = 0x410, UpListPtr = 0x418,
-};
-
-/* The Rx and Tx descriptor lists.
-   Caution Alpha hackers: these types are 32 bits!  Note also the 8 byte
-   alignment contraint on tx_ring[] and rx_ring[]. */
-struct boom_rx_desc {
-	u32 next;
-	s32 status;
-	u32 addr;
-	s32 length;
-};
-
-/* Values for the Rx status entry. */
-enum rx_desc_status {
-	RxDComplete = 0x00008000, RxDError = 0x4000,
-	/* See boomerang_rx() for actual error bits */
-};
-
-struct boom_tx_desc {
-	u32 next;
-	s32 status;
-	u32 addr;
-	s32 length;
-};
-
-struct corkscrew_private {
-	const char *product_name;
-	struct list_head list;
-	struct net_device *our_dev;
-	/* The Rx and Tx rings are here to keep them quad-word-aligned. */
-	struct boom_rx_desc rx_ring[RX_RING_SIZE];
-	struct boom_tx_desc tx_ring[TX_RING_SIZE];
-	/* The addresses of transmit- and receive-in-place skbuffs. */
-	struct sk_buff *rx_skbuff[RX_RING_SIZE];
-	struct sk_buff *tx_skbuff[TX_RING_SIZE];
-	unsigned int cur_rx, cur_tx;	/* The next free ring entry */
-	unsigned int dirty_rx, dirty_tx;/* The ring entries to be free()ed. */
-	struct sk_buff *tx_skb;	/* Packet being eaten by bus master ctrl.  */
-	struct timer_list timer;	/* Media selection timer. */
-	int capabilities	;	/* Adapter capabilities word. */
-	int options;			/* User-settable misc. driver options. */
-	int last_rx_packets;		/* For media autoselection. */
-	unsigned int available_media:8,	/* From Wn3_Options */
-		media_override:3,	/* Passed-in media type. */
-		default_media:3,	/* Read from the EEPROM. */
-		full_duplex:1, autoselect:1, bus_master:1,	/* Vortex can only do a fragment bus-m. */
-		full_bus_master_tx:1, full_bus_master_rx:1,	/* Boomerang  */
-		tx_full:1;
-	spinlock_t lock;
-	struct device *dev;
-};
-
-/* The action to take with a media selection timer tick.
-   Note that we deviate from the 3Com order by checking 10base2 before AUI.
- */
-enum xcvr_types {
-	XCVR_10baseT = 0, XCVR_AUI, XCVR_10baseTOnly, XCVR_10base2, XCVR_100baseTx,
-	XCVR_100baseFx, XCVR_MII = 6, XCVR_Default = 8,
-};
-
-static struct media_table {
-	char *name;
-	unsigned int media_bits:16,	/* Bits to set in Wn4_Media register. */
-		mask:8,			/* The transceiver-present bit in Wn3_Config. */
-		next:8;			/* The media type to try next. */
-	short wait;			/* Time before we check media status. */
-} media_tbl[] = {
-	{ "10baseT", Media_10TP, 0x08, XCVR_10base2, (14 * HZ) / 10 },
-	{ "10Mbs AUI", Media_SQE, 0x20, XCVR_Default, (1 * HZ) / 10},
-	{ "undefined", 0, 0x80, XCVR_10baseT, 10000},
-	{ "10base2", 0, 0x10, XCVR_AUI, (1 * HZ) / 10},
-	{ "100baseTX", Media_Lnk, 0x02, XCVR_100baseFx, (14 * HZ) / 10},
-	{ "100baseFX", Media_Lnk, 0x04, XCVR_MII, (14 * HZ) / 10},
-	{ "MII", 0, 0x40, XCVR_10baseT, 3 * HZ},
-	{ "undefined", 0, 0x01, XCVR_10baseT, 10000},
-	{ "Default", 0, 0xFF, XCVR_10baseT, 10000},
-};
-
-#ifdef __ISAPNP__
-static struct isapnp_device_id corkscrew_isapnp_adapters[] = {
-	{	ISAPNP_ANY_ID, ISAPNP_ANY_ID,
-		ISAPNP_VENDOR('T', 'C', 'M'), ISAPNP_FUNCTION(0x5051),
-		(long) "3Com Fast EtherLink ISA" },
-	{ }	/* terminate list */
-};
-
-MODULE_DEVICE_TABLE(isapnp, corkscrew_isapnp_adapters);
-
-static int nopnp;
-#endif /* __ISAPNP__ */
-
-static struct net_device *corkscrew_scan(int unit);
-static int corkscrew_setup(struct net_device *dev, int ioaddr,
-			    struct pnp_dev *idev, int card_number);
-static int corkscrew_open(struct net_device *dev);
-static void corkscrew_timer(struct timer_list *t);
-static netdev_tx_t corkscrew_start_xmit(struct sk_buff *skb,
-					struct net_device *dev);
-static int corkscrew_rx(struct net_device *dev);
-static void corkscrew_timeout(struct net_device *dev, unsigned int txqueue);
-static int boomerang_rx(struct net_device *dev);
-static irqreturn_t corkscrew_interrupt(int irq, void *dev_id);
-static int corkscrew_close(struct net_device *dev);
-static void update_stats(int addr, struct net_device *dev);
-static struct net_device_stats *corkscrew_get_stats(struct net_device *dev);
-static void set_rx_mode(struct net_device *dev);
-static const struct ethtool_ops netdev_ethtool_ops;
-
-
-/*
-   Unfortunately maximizing the shared code between the integrated and
-   module version of the driver results in a complicated set of initialization
-   procedures.
-   init_module() -- modules /  tc59x_init()  -- built-in
-		The wrappers for corkscrew_scan()
-   corkscrew_scan()  		 The common routine that scans for PCI and EISA cards
-   corkscrew_found_device() Allocate a device structure when we find a card.
-					Different versions exist for modules and built-in.
-   corkscrew_probe1()		Fill in the device structure -- this is separated
-					so that the modules code can put it in dev->init.
-*/
-/* This driver uses 'options' to pass the media type, full-duplex flag, etc. */
-/* Note: this is the only limit on the number of cards supported!! */
-static int options[MAX_UNITS] = { -1, -1, -1, -1, -1, -1, -1, -1, };
-
-#ifdef MODULE
-static int debug = -1;
-
-module_param(debug, int, 0);
-module_param_array(options, int, NULL, 0);
-module_param(rx_copybreak, int, 0);
-module_param(max_interrupt_work, int, 0);
-MODULE_PARM_DESC(debug, "3c515 debug level (0-6)");
-MODULE_PARM_DESC(options, "3c515: Bits 0-2: media type, bit 3: full duplex, bit 4: bus mastering");
-MODULE_PARM_DESC(rx_copybreak, "3c515 copy breakpoint for copy-only-tiny-frames");
-MODULE_PARM_DESC(max_interrupt_work, "3c515 maximum events handled per interrupt");
-
-/* A list of all installed Vortex devices, for removing the driver module. */
-/* we will need locking (and refcounting) if we ever use it for more */
-static LIST_HEAD(root_corkscrew_dev);
-
-static int corkscrew_init_module(void)
-{
-	int found = 0;
-	if (debug >= 0)
-		corkscrew_debug = debug;
-	while (corkscrew_scan(-1))
-		found++;
-	return found ? 0 : -ENODEV;
-}
-module_init(corkscrew_init_module);
-
-#else
-struct net_device *tc515_probe(int unit)
-{
-	struct net_device *dev = corkscrew_scan(unit);
-
-	if (!dev)
-		return ERR_PTR(-ENODEV);
-
-	return dev;
-}
-#endif				/* not MODULE */
-
-static int check_device(unsigned ioaddr)
-{
-	int timer;
-
-	if (!request_region(ioaddr, CORKSCREW_TOTAL_SIZE, "3c515"))
-		return 0;
-	/* Check the resource configuration for a matching ioaddr. */
-	if ((inw(ioaddr + 0x2002) & 0x1f0) != (ioaddr & 0x1f0)) {
-		release_region(ioaddr, CORKSCREW_TOTAL_SIZE);
-		return 0;
-	}
-	/* Verify by reading the device ID from the EEPROM. */
-	outw(EEPROM_Read + 7, ioaddr + Wn0EepromCmd);
-	/* Pause for at least 162 us. for the read to take place. */
-	for (timer = 4; timer >= 0; timer--) {
-		udelay(162);
-		if ((inw(ioaddr + Wn0EepromCmd) & 0x0200) == 0)
-			break;
-	}
-	if (inw(ioaddr + Wn0EepromData) != 0x6d50) {
-		release_region(ioaddr, CORKSCREW_TOTAL_SIZE);
-		return 0;
-	}
-	return 1;
-}
-
-static void cleanup_card(struct net_device *dev)
-{
-	struct corkscrew_private *vp = netdev_priv(dev);
-	list_del_init(&vp->list);
-	if (dev->dma)
-		free_dma(dev->dma);
-	outw(TotalReset, dev->base_addr + EL3_CMD);
-	release_region(dev->base_addr, CORKSCREW_TOTAL_SIZE);
-	if (vp->dev)
-		pnp_device_detach(to_pnp_dev(vp->dev));
-}
-
-static struct net_device *corkscrew_scan(int unit)
-{
-	struct net_device *dev;
-	static int cards_found = 0;
-	static int ioaddr;
-	int err;
-#ifdef __ISAPNP__
-	short i;
-	static int pnp_cards;
-#endif
-
-	dev = alloc_etherdev(sizeof(struct corkscrew_private));
-	if (!dev)
-		return ERR_PTR(-ENOMEM);
-
-	if (unit >= 0) {
-		sprintf(dev->name, "eth%d", unit);
-		netdev_boot_setup_check(dev);
-	}
-
-#ifdef __ISAPNP__
-	if(nopnp == 1)
-		goto no_pnp;
-	for(i=0; corkscrew_isapnp_adapters[i].vendor != 0; i++) {
-		struct pnp_dev *idev = NULL;
-		int irq;
-		while((idev = pnp_find_dev(NULL,
-					   corkscrew_isapnp_adapters[i].vendor,
-					   corkscrew_isapnp_adapters[i].function,
-					   idev))) {
-
-			if (pnp_device_attach(idev) < 0)
-				continue;
-			if (pnp_activate_dev(idev) < 0) {
-				pr_warn("pnp activate failed (out of resources?)\n");
-				pnp_device_detach(idev);
-				continue;
-			}
-			if (!pnp_port_valid(idev, 0) || !pnp_irq_valid(idev, 0)) {
-				pnp_device_detach(idev);
-				continue;
-			}
-			ioaddr = pnp_port_start(idev, 0);
-			irq = pnp_irq(idev, 0);
-			if (!check_device(ioaddr)) {
-				pnp_device_detach(idev);
-				continue;
-			}
-			if(corkscrew_debug)
-				pr_debug("ISAPNP reports %s at i/o 0x%x, irq %d\n",
-					(char*) corkscrew_isapnp_adapters[i].driver_data, ioaddr, irq);
-			pr_info("3c515 Resource configuration register %#4.4x, DCR %4.4x.\n",
-		     		inl(ioaddr + 0x2002), inw(ioaddr + 0x2000));
-			/* irq = inw(ioaddr + 0x2002) & 15; */ /* Use the irq from isapnp */
-			SET_NETDEV_DEV(dev, &idev->dev);
-			pnp_cards++;
-			err = corkscrew_setup(dev, ioaddr, idev, cards_found++);
-			if (!err)
-				return dev;
-			cleanup_card(dev);
-		}
-	}
-no_pnp:
-#endif /* __ISAPNP__ */
-
-	/* Check all locations on the ISA bus -- evil! */
-	for (ioaddr = 0x100; ioaddr < 0x400; ioaddr += 0x20) {
-		if (!check_device(ioaddr))
-			continue;
-
-		pr_info("3c515 Resource configuration register %#4.4x, DCR %4.4x.\n",
-		     inl(ioaddr + 0x2002), inw(ioaddr + 0x2000));
-		err = corkscrew_setup(dev, ioaddr, NULL, cards_found++);
-		if (!err)
-			return dev;
-		cleanup_card(dev);
-	}
-	free_netdev(dev);
-	return NULL;
-}
-
-
-static const struct net_device_ops netdev_ops = {
-	.ndo_open		= corkscrew_open,
-	.ndo_stop		= corkscrew_close,
-	.ndo_start_xmit		= corkscrew_start_xmit,
-	.ndo_tx_timeout		= corkscrew_timeout,
-	.ndo_get_stats		= corkscrew_get_stats,
-	.ndo_set_rx_mode	= set_rx_mode,
-	.ndo_set_mac_address 	= eth_mac_addr,
-	.ndo_validate_addr	= eth_validate_addr,
-};
-
-
-static int corkscrew_setup(struct net_device *dev, int ioaddr,
-			    struct pnp_dev *idev, int card_number)
-{
-	struct corkscrew_private *vp = netdev_priv(dev);
-	unsigned int eeprom[0x40], checksum = 0;	/* EEPROM contents */
-	__be16 addr[ETH_ALEN / 2];
-	int i;
-	int irq;
-
-#ifdef __ISAPNP__
-	if (idev) {
-		irq = pnp_irq(idev, 0);
-		vp->dev = &idev->dev;
-	} else {
-		irq = inw(ioaddr + 0x2002) & 15;
-	}
-#else
-	irq = inw(ioaddr + 0x2002) & 15;
-#endif
-
-	dev->base_addr = ioaddr;
-	dev->irq = irq;
-	dev->dma = inw(ioaddr + 0x2000) & 7;
-	vp->product_name = "3c515";
-	vp->options = dev->mem_start;
-	vp->our_dev = dev;
-
-	if (!vp->options) {
-		 if (card_number >= MAX_UNITS)
-			vp->options = -1;
-		else
-			vp->options = options[card_number];
-	}
-
-	if (vp->options >= 0) {
-		vp->media_override = vp->options & 7;
-		if (vp->media_override == 2)
-			vp->media_override = 0;
-		vp->full_duplex = (vp->options & 8) ? 1 : 0;
-		vp->bus_master = (vp->options & 16) ? 1 : 0;
-	} else {
-		vp->media_override = 7;
-		vp->full_duplex = 0;
-		vp->bus_master = 0;
-	}
-#ifdef MODULE
-	list_add(&vp->list, &root_corkscrew_dev);
-#endif
-
-	pr_info("%s: 3Com %s at %#3x,", dev->name, vp->product_name, ioaddr);
-
-	spin_lock_init(&vp->lock);
-
-	timer_setup(&vp->timer, corkscrew_timer, 0);
-
-	/* Read the station address from the EEPROM. */
-	EL3WINDOW(0);
-	for (i = 0; i < 0x18; i++) {
-		int timer;
-		outw(EEPROM_Read + i, ioaddr + Wn0EepromCmd);
-		/* Pause for at least 162 us. for the read to take place. */
-		for (timer = 4; timer >= 0; timer--) {
-			udelay(162);
-			if ((inw(ioaddr + Wn0EepromCmd) & 0x0200) == 0)
-				break;
-		}
-		eeprom[i] = inw(ioaddr + Wn0EepromData);
-		checksum ^= eeprom[i];
-		if (i < 3)
-			addr[i] = htons(eeprom[i]);
-	}
-	eth_hw_addr_set(dev, (u8 *)addr);
-	checksum = (checksum ^ (checksum >> 8)) & 0xff;
-	if (checksum != 0x00)
-		pr_cont(" ***INVALID CHECKSUM %4.4x*** ", checksum);
-	pr_cont(" %pM", dev->dev_addr);
-	if (eeprom[16] == 0x11c7) {	/* Corkscrew */
-		if (request_dma(dev->dma, "3c515")) {
-			pr_cont(", DMA %d allocation failed", dev->dma);
-			dev->dma = 0;
-		} else
-			pr_cont(", DMA %d", dev->dma);
-	}
-	pr_cont(", IRQ %d\n", dev->irq);
-	/* Tell them about an invalid IRQ. */
-	if (corkscrew_debug && (dev->irq <= 0 || dev->irq > 15))
-		pr_warn(" *** Warning: this IRQ is unlikely to work! ***\n");
-
-	{
-		static const char * const ram_split[] = {
-			"5:3", "3:1", "1:1", "3:5"
-		};
-		__u32 config;
-		EL3WINDOW(3);
-		vp->available_media = inw(ioaddr + Wn3_Options);
-		config = inl(ioaddr + Wn3_Config);
-		if (corkscrew_debug > 1)
-			pr_info("  Internal config register is %4.4x, transceivers %#x.\n",
-				config, inw(ioaddr + Wn3_Options));
-		pr_info("  %dK %s-wide RAM %s Rx:Tx split, %s%s interface.\n",
-			8 << config & Ram_size,
-			config & Ram_width ? "word" : "byte",
-			ram_split[(config & Ram_split) >> Ram_split_shift],
-			config & Autoselect ? "autoselect/" : "",
-			media_tbl[(config & Xcvr) >> Xcvr_shift].name);
-		vp->default_media = (config & Xcvr) >> Xcvr_shift;
-		vp->autoselect = config & Autoselect ? 1 : 0;
-		dev->if_port = vp->default_media;
-	}
-	if (vp->media_override != 7) {
-		pr_info("  Media override to transceiver type %d (%s).\n",
-		       vp->media_override,
-		       media_tbl[vp->media_override].name);
-		dev->if_port = vp->media_override;
-	}
-
-	vp->capabilities = eeprom[16];
-	vp->full_bus_master_tx = (vp->capabilities & 0x20) ? 1 : 0;
-	/* Rx is broken at 10mbps, so we always disable it. */
-	/* vp->full_bus_master_rx = 0; */
-	vp->full_bus_master_rx = (vp->capabilities & 0x20) ? 1 : 0;
-
-	/* The 3c51x-specific entries in the device structure. */
-	dev->netdev_ops = &netdev_ops;
-	dev->watchdog_timeo = (400 * HZ) / 1000;
-	dev->ethtool_ops = &netdev_ethtool_ops;
-
-	return register_netdev(dev);
-}
-
-
-static int corkscrew_open(struct net_device *dev)
-{
-	int ioaddr = dev->base_addr;
-	struct corkscrew_private *vp = netdev_priv(dev);
-	bool armtimer = false;
-	__u32 config;
-	int i;
-
-	/* Before initializing select the active media port. */
-	EL3WINDOW(3);
-	if (vp->full_duplex)
-		outb(0x20, ioaddr + Wn3_MAC_Ctrl);	/* Set the full-duplex bit. */
-	config = inl(ioaddr + Wn3_Config);
-
-	if (vp->media_override != 7) {
-		if (corkscrew_debug > 1)
-			pr_info("%s: Media override to transceiver %d (%s).\n",
-				dev->name, vp->media_override,
-				media_tbl[vp->media_override].name);
-		dev->if_port = vp->media_override;
-	} else if (vp->autoselect) {
-		/* Find first available media type, starting with 100baseTx. */
-		dev->if_port = 4;
-		while (!(vp->available_media & media_tbl[dev->if_port].mask))
-			dev->if_port = media_tbl[dev->if_port].next;
-
-		if (corkscrew_debug > 1)
-			pr_debug("%s: Initial media type %s.\n",
-			       dev->name, media_tbl[dev->if_port].name);
-		armtimer = true;
-	} else
-		dev->if_port = vp->default_media;
-
-	config = (config & ~Xcvr) | (dev->if_port << Xcvr_shift);
-	outl(config, ioaddr + Wn3_Config);
-
-	if (corkscrew_debug > 1) {
-		pr_debug("%s: corkscrew_open() InternalConfig %8.8x.\n",
-		       dev->name, config);
-	}
-
-	outw(TxReset, ioaddr + EL3_CMD);
-	for (i = 20; i >= 0; i--)
-		if (!(inw(ioaddr + EL3_STATUS) & CmdInProgress))
-			break;
-
-	outw(RxReset, ioaddr + EL3_CMD);
-	/* Wait a few ticks for the RxReset command to complete. */
-	for (i = 20; i >= 0; i--)
-		if (!(inw(ioaddr + EL3_STATUS) & CmdInProgress))
-			break;
-
-	outw(SetStatusEnb | 0x00, ioaddr + EL3_CMD);
-
-	/* Use the now-standard shared IRQ implementation. */
-	if (vp->capabilities == 0x11c7) {
-		/* Corkscrew: Cannot share ISA resources. */
-		if (dev->irq == 0 ||
-		    dev->dma == 0 ||
-		    request_irq(dev->irq, corkscrew_interrupt, 0,
-				vp->product_name, dev))
-			return -EAGAIN;
-		enable_dma(dev->dma);
-		set_dma_mode(dev->dma, DMA_MODE_CASCADE);
-	} else if (request_irq(dev->irq, corkscrew_interrupt, IRQF_SHARED,
-			       vp->product_name, dev)) {
-		return -EAGAIN;
-	}
-
-	if (armtimer)
-		mod_timer(&vp->timer, jiffies + media_tbl[dev->if_port].wait);
-
-	if (corkscrew_debug > 1) {
-		EL3WINDOW(4);
-		pr_debug("%s: corkscrew_open() irq %d media status %4.4x.\n",
-		       dev->name, dev->irq, inw(ioaddr + Wn4_Media));
-	}
-
-	/* Set the station address and mask in window 2 each time opened. */
-	EL3WINDOW(2);
-	for (i = 0; i < 6; i++)
-		outb(dev->dev_addr[i], ioaddr + i);
-	for (; i < 12; i += 2)
-		outw(0, ioaddr + i);
-
-	if (dev->if_port == 3)
-		/* Start the thinnet transceiver. We should really wait 50ms... */
-		outw(StartCoax, ioaddr + EL3_CMD);
-	EL3WINDOW(4);
-	outw((inw(ioaddr + Wn4_Media) & ~(Media_10TP | Media_SQE)) |
-	     media_tbl[dev->if_port].media_bits, ioaddr + Wn4_Media);
-
-	/* Switch to the stats window, and clear all stats by reading. */
-	outw(StatsDisable, ioaddr + EL3_CMD);
-	EL3WINDOW(6);
-	for (i = 0; i < 10; i++)
-		inb(ioaddr + i);
-	inw(ioaddr + 10);
-	inw(ioaddr + 12);
-	/* New: On the Vortex we must also clear the BadSSD counter. */
-	EL3WINDOW(4);
-	inb(ioaddr + 12);
-	/* ..and on the Boomerang we enable the extra statistics bits. */
-	outw(0x0040, ioaddr + Wn4_NetDiag);
-
-	/* Switch to register set 7 for normal use. */
-	EL3WINDOW(7);
-
-	if (vp->full_bus_master_rx) {	/* Boomerang bus master. */
-		vp->cur_rx = vp->dirty_rx = 0;
-		if (corkscrew_debug > 2)
-			pr_debug("%s:  Filling in the Rx ring.\n", dev->name);
-		for (i = 0; i < RX_RING_SIZE; i++) {
-			struct sk_buff *skb;
-			if (i < (RX_RING_SIZE - 1))
-				vp->rx_ring[i].next =
-				    isa_virt_to_bus(&vp->rx_ring[i + 1]);
-			else
-				vp->rx_ring[i].next = 0;
-			vp->rx_ring[i].status = 0;	/* Clear complete bit. */
-			vp->rx_ring[i].length = PKT_BUF_SZ | 0x80000000;
-			skb = netdev_alloc_skb(dev, PKT_BUF_SZ);
-			vp->rx_skbuff[i] = skb;
-			if (skb == NULL)
-				break;	/* Bad news!  */
-			skb_reserve(skb, 2);	/* Align IP on 16 byte boundaries */
-			vp->rx_ring[i].addr = isa_virt_to_bus(skb->data);
-		}
-		if (i != 0)
-			vp->rx_ring[i - 1].next =
-				isa_virt_to_bus(&vp->rx_ring[0]);	/* Wrap the ring. */
-		outl(isa_virt_to_bus(&vp->rx_ring[0]), ioaddr + UpListPtr);
-	}
-	if (vp->full_bus_master_tx) {	/* Boomerang bus master Tx. */
-		vp->cur_tx = vp->dirty_tx = 0;
-		outb(PKT_BUF_SZ >> 8, ioaddr + TxFreeThreshold);	/* Room for a packet. */
-		/* Clear the Tx ring. */
-		for (i = 0; i < TX_RING_SIZE; i++)
-			vp->tx_skbuff[i] = NULL;
-		outl(0, ioaddr + DownListPtr);
-	}
-	/* Set receiver mode: presumably accept b-case and phys addr only. */
-	set_rx_mode(dev);
-	outw(StatsEnable, ioaddr + EL3_CMD);	/* Turn on statistics. */
-
-	netif_start_queue(dev);
-
-	outw(RxEnable, ioaddr + EL3_CMD);	/* Enable the receiver. */
-	outw(TxEnable, ioaddr + EL3_CMD);	/* Enable transmitter. */
-	/* Allow status bits to be seen. */
-	outw(SetStatusEnb | AdapterFailure | IntReq | StatsFull |
-	     (vp->full_bus_master_tx ? DownComplete : TxAvailable) |
-	     (vp->full_bus_master_rx ? UpComplete : RxComplete) |
-	     (vp->bus_master ? DMADone : 0), ioaddr + EL3_CMD);
-	/* Ack all pending events, and set active indicator mask. */
-	outw(AckIntr | IntLatch | TxAvailable | RxEarly | IntReq,
-	     ioaddr + EL3_CMD);
-	outw(SetIntrEnb | IntLatch | TxAvailable | RxComplete | StatsFull
-	     | (vp->bus_master ? DMADone : 0) | UpComplete | DownComplete,
-	     ioaddr + EL3_CMD);
-
-	return 0;
-}
-
-static void corkscrew_timer(struct timer_list *t)
-{
-#ifdef AUTOMEDIA
-	struct corkscrew_private *vp = timer_container_of(vp, t, timer);
-	struct net_device *dev = vp->our_dev;
-	int ioaddr = dev->base_addr;
-	unsigned long flags;
-	int ok = 0;
-
-	if (corkscrew_debug > 1)
-		pr_debug("%s: Media selection timer tick happened, %s.\n",
-		       dev->name, media_tbl[dev->if_port].name);
-
-	spin_lock_irqsave(&vp->lock, flags);
-
-	{
-		int old_window = inw(ioaddr + EL3_CMD) >> 13;
-		int media_status;
-		EL3WINDOW(4);
-		media_status = inw(ioaddr + Wn4_Media);
-		switch (dev->if_port) {
-		case 0:
-		case 4:
-		case 5:	/* 10baseT, 100baseTX, 100baseFX  */
-			if (media_status & Media_LnkBeat) {
-				ok = 1;
-				if (corkscrew_debug > 1)
-					pr_debug("%s: Media %s has link beat, %x.\n",
-						dev->name,
-						media_tbl[dev->if_port].name,
-						media_status);
-			} else if (corkscrew_debug > 1)
-				pr_debug("%s: Media %s is has no link beat, %x.\n",
-					dev->name,
-					media_tbl[dev->if_port].name,
-					media_status);
-
-			break;
-		default:	/* Other media types handled by Tx timeouts. */
-			if (corkscrew_debug > 1)
-				pr_debug("%s: Media %s is has no indication, %x.\n",
-					dev->name,
-					media_tbl[dev->if_port].name,
-					media_status);
-			ok = 1;
-		}
-		if (!ok) {
-			__u32 config;
-
-			do {
-				dev->if_port =
-				    media_tbl[dev->if_port].next;
-			}
-			while (!(vp->available_media & media_tbl[dev->if_port].mask));
-
-			if (dev->if_port == 8) {	/* Go back to default. */
-				dev->if_port = vp->default_media;
-				if (corkscrew_debug > 1)
-					pr_debug("%s: Media selection failing, using default %s port.\n",
-						dev->name,
-						media_tbl[dev->if_port].name);
-			} else {
-				if (corkscrew_debug > 1)
-					pr_debug("%s: Media selection failed, now trying %s port.\n",
-						dev->name,
-						media_tbl[dev->if_port].name);
-				vp->timer.expires = jiffies + media_tbl[dev->if_port].wait;
-				add_timer(&vp->timer);
-			}
-			outw((media_status & ~(Media_10TP | Media_SQE)) |
-			     media_tbl[dev->if_port].media_bits,
-			     ioaddr + Wn4_Media);
-
-			EL3WINDOW(3);
-			config = inl(ioaddr + Wn3_Config);
-			config = (config & ~Xcvr) | (dev->if_port << Xcvr_shift);
-			outl(config, ioaddr + Wn3_Config);
-
-			outw(dev->if_port == 3 ? StartCoax : StopCoax,
-			     ioaddr + EL3_CMD);
-		}
-		EL3WINDOW(old_window);
-	}
-
-	spin_unlock_irqrestore(&vp->lock, flags);
-	if (corkscrew_debug > 1)
-		pr_debug("%s: Media selection timer finished, %s.\n",
-		       dev->name, media_tbl[dev->if_port].name);
-
-#endif				/* AUTOMEDIA */
-}
-
-static void corkscrew_timeout(struct net_device *dev, unsigned int txqueue)
-{
-	int i;
-	struct corkscrew_private *vp = netdev_priv(dev);
-	int ioaddr = dev->base_addr;
-
-	pr_warn("%s: transmit timed out, tx_status %2.2x status %4.4x\n",
-		dev->name, inb(ioaddr + TxStatus),
-		inw(ioaddr + EL3_STATUS));
-	/* Slight code bloat to be user friendly. */
-	if ((inb(ioaddr + TxStatus) & 0x88) == 0x88)
-		pr_warn("%s: Transmitter encountered 16 collisions -- network cable problem?\n",
-			dev->name);
-#ifndef final_version
-	pr_debug("  Flags; bus-master %d, full %d; dirty %d current %d.\n",
-	       vp->full_bus_master_tx, vp->tx_full, vp->dirty_tx,
-	       vp->cur_tx);
-	pr_debug("  Down list %8.8x vs. %p.\n", inl(ioaddr + DownListPtr),
-	       &vp->tx_ring[0]);
-	for (i = 0; i < TX_RING_SIZE; i++) {
-		pr_debug("  %d: %p  length %8.8x status %8.8x\n", i,
-		       &vp->tx_ring[i],
-		       vp->tx_ring[i].length, vp->tx_ring[i].status);
-	}
-#endif
-	/* Issue TX_RESET and TX_START commands. */
-	outw(TxReset, ioaddr + EL3_CMD);
-	for (i = 20; i >= 0; i--)
-		if (!(inw(ioaddr + EL3_STATUS) & CmdInProgress))
-			break;
-	outw(TxEnable, ioaddr + EL3_CMD);
-	netif_trans_update(dev); /* prevent tx timeout */
-	dev->stats.tx_errors++;
-	dev->stats.tx_dropped++;
-	netif_wake_queue(dev);
-}
-
-static netdev_tx_t corkscrew_start_xmit(struct sk_buff *skb,
-					struct net_device *dev)
-{
-	struct corkscrew_private *vp = netdev_priv(dev);
-	int ioaddr = dev->base_addr;
-
-	/* Block a timer-based transmit from overlapping. */
-
-	netif_stop_queue(dev);
-
-	if (vp->full_bus_master_tx) {	/* BOOMERANG bus-master */
-		/* Calculate the next Tx descriptor entry. */
-		int entry = vp->cur_tx % TX_RING_SIZE;
-		struct boom_tx_desc *prev_entry;
-		unsigned long flags;
-		int i;
-
-		if (vp->tx_full)	/* No room to transmit with */
-			return NETDEV_TX_BUSY;
-		if (vp->cur_tx != 0)
-			prev_entry = &vp->tx_ring[(vp->cur_tx - 1) % TX_RING_SIZE];
-		else
-			prev_entry = NULL;
-		if (corkscrew_debug > 3)
-			pr_debug("%s: Trying to send a packet, Tx index %d.\n",
-				dev->name, vp->cur_tx);
-		/* vp->tx_full = 1; */
-		vp->tx_skbuff[entry] = skb;
-		vp->tx_ring[entry].next = 0;
-		vp->tx_ring[entry].addr = isa_virt_to_bus(skb->data);
-		vp->tx_ring[entry].length = skb->len | 0x80000000;
-		vp->tx_ring[entry].status = skb->len | 0x80000000;
-
-		spin_lock_irqsave(&vp->lock, flags);
-		outw(DownStall, ioaddr + EL3_CMD);
-		/* Wait for the stall to complete. */
-		for (i = 20; i >= 0; i--)
-			if ((inw(ioaddr + EL3_STATUS) & CmdInProgress) == 0)
-				break;
-		if (prev_entry)
-			prev_entry->next = isa_virt_to_bus(&vp->tx_ring[entry]);
-		if (inl(ioaddr + DownListPtr) == 0) {
-			outl(isa_virt_to_bus(&vp->tx_ring[entry]),
-			     ioaddr + DownListPtr);
-			queued_packet++;
-		}
-		outw(DownUnstall, ioaddr + EL3_CMD);
-		spin_unlock_irqrestore(&vp->lock, flags);
-
-		vp->cur_tx++;
-		if (vp->cur_tx - vp->dirty_tx > TX_RING_SIZE - 1)
-			vp->tx_full = 1;
-		else {		/* Clear previous interrupt enable. */
-			if (prev_entry)
-				prev_entry->status &= ~0x80000000;
-			netif_wake_queue(dev);
-		}
-		return NETDEV_TX_OK;
-	}
-	/* Put out the doubleword header... */
-	outl(skb->len, ioaddr + TX_FIFO);
-	dev->stats.tx_bytes += skb->len;
-#ifdef VORTEX_BUS_MASTER
-	if (vp->bus_master) {
-		/* Set the bus-master controller to transfer the packet. */
-		outl(isa_virt_to_bus(skb->data), ioaddr + Wn7_MasterAddr);
-		outw((skb->len + 3) & ~3, ioaddr + Wn7_MasterLen);
-		vp->tx_skb = skb;
-		outw(StartDMADown, ioaddr + EL3_CMD);
-		/* queue will be woken at the DMADone interrupt. */
-	} else {
-		/* ... and the packet rounded to a doubleword. */
-		outsl(ioaddr + TX_FIFO, skb->data, (skb->len + 3) >> 2);
-		dev_kfree_skb(skb);
-		if (inw(ioaddr + TxFree) > 1536) {
-			netif_wake_queue(dev);
-		} else
-			/* Interrupt us when the FIFO has room for max-sized packet. */
-			outw(SetTxThreshold + (1536 >> 2),
-			     ioaddr + EL3_CMD);
-	}
-#else
-	/* ... and the packet rounded to a doubleword. */
-	outsl(ioaddr + TX_FIFO, skb->data, (skb->len + 3) >> 2);
-	dev_kfree_skb(skb);
-	if (inw(ioaddr + TxFree) > 1536) {
-		netif_wake_queue(dev);
-	} else
-		/* Interrupt us when the FIFO has room for max-sized packet. */
-		outw(SetTxThreshold + (1536 >> 2), ioaddr + EL3_CMD);
-#endif				/* bus master */
-
-
-	/* Clear the Tx status stack. */
-	{
-		short tx_status;
-		int i = 4;
-
-		while (--i > 0 && (tx_status = inb(ioaddr + TxStatus)) > 0) {
-			if (tx_status & 0x3C) {	/* A Tx-disabling error occurred.  */
-				if (corkscrew_debug > 2)
-					pr_debug("%s: Tx error, status %2.2x.\n",
-						dev->name, tx_status);
-				if (tx_status & 0x04)
-					dev->stats.tx_fifo_errors++;
-				if (tx_status & 0x38)
-					dev->stats.tx_aborted_errors++;
-				if (tx_status & 0x30) {
-					int j;
-					outw(TxReset, ioaddr + EL3_CMD);
-					for (j = 20; j >= 0; j--)
-						if (!(inw(ioaddr + EL3_STATUS) & CmdInProgress))
-							break;
-				}
-				outw(TxEnable, ioaddr + EL3_CMD);
-			}
-			outb(0x00, ioaddr + TxStatus);	/* Pop the status stack. */
-		}
-	}
-	return NETDEV_TX_OK;
-}
-
-/* The interrupt handler does all of the Rx thread work and cleans up
-   after the Tx thread. */
-
-static irqreturn_t corkscrew_interrupt(int irq, void *dev_id)
-{
-	/* Use the now-standard shared IRQ implementation. */
-	struct net_device *dev = dev_id;
-	struct corkscrew_private *lp = netdev_priv(dev);
-	int ioaddr, status;
-	int latency;
-	int i = max_interrupt_work;
-
-	ioaddr = dev->base_addr;
-	latency = inb(ioaddr + Timer);
-
-	spin_lock(&lp->lock);
-
-	status = inw(ioaddr + EL3_STATUS);
-
-	if (corkscrew_debug > 4)
-		pr_debug("%s: interrupt, status %4.4x, timer %d.\n",
-			dev->name, status, latency);
-	if ((status & 0xE000) != 0xE000) {
-		static int donedidthis;
-		/* Some interrupt controllers store a bogus interrupt from boot-time.
-		   Ignore a single early interrupt, but don't hang the machine for
-		   other interrupt problems. */
-		if (donedidthis++ > 100) {
-			pr_err("%s: Bogus interrupt, bailing. Status %4.4x, start=%d.\n",
-				   dev->name, status, netif_running(dev));
-			free_irq(dev->irq, dev);
-			dev->irq = -1;
-		}
-	}
-
-	do {
-		if (corkscrew_debug > 5)
-			pr_debug("%s: In interrupt loop, status %4.4x.\n",
-			       dev->name, status);
-		if (status & RxComplete)
-			corkscrew_rx(dev);
-
-		if (status & TxAvailable) {
-			if (corkscrew_debug > 5)
-				pr_debug("	TX room bit was handled.\n");
-			/* There's room in the FIFO for a full-sized packet. */
-			outw(AckIntr | TxAvailable, ioaddr + EL3_CMD);
-			netif_wake_queue(dev);
-		}
-		if (status & DownComplete) {
-			unsigned int dirty_tx = lp->dirty_tx;
-
-			while (lp->cur_tx - dirty_tx > 0) {
-				int entry = dirty_tx % TX_RING_SIZE;
-				if (inl(ioaddr + DownListPtr) == isa_virt_to_bus(&lp->tx_ring[entry]))
-					break;	/* It still hasn't been processed. */
-				if (lp->tx_skbuff[entry]) {
-					dev_consume_skb_irq(lp->tx_skbuff[entry]);
-					lp->tx_skbuff[entry] = NULL;
-				}
-				dirty_tx++;
-			}
-			lp->dirty_tx = dirty_tx;
-			outw(AckIntr | DownComplete, ioaddr + EL3_CMD);
-			if (lp->tx_full && (lp->cur_tx - dirty_tx <= TX_RING_SIZE - 1)) {
-				lp->tx_full = 0;
-				netif_wake_queue(dev);
-			}
-		}
-#ifdef VORTEX_BUS_MASTER
-		if (status & DMADone) {
-			outw(0x1000, ioaddr + Wn7_MasterStatus);	/* Ack the event. */
-			dev_consume_skb_irq(lp->tx_skb);	/* Release the transferred buffer */
-			netif_wake_queue(dev);
-		}
-#endif
-		if (status & UpComplete) {
-			boomerang_rx(dev);
-			outw(AckIntr | UpComplete, ioaddr + EL3_CMD);
-		}
-		if (status & (AdapterFailure | RxEarly | StatsFull)) {
-			/* Handle all uncommon interrupts at once. */
-			if (status & RxEarly) {	/* Rx early is unused. */
-				corkscrew_rx(dev);
-				outw(AckIntr | RxEarly, ioaddr + EL3_CMD);
-			}
-			if (status & StatsFull) {	/* Empty statistics. */
-				static int DoneDidThat;
-				if (corkscrew_debug > 4)
-					pr_debug("%s: Updating stats.\n", dev->name);
-				update_stats(ioaddr, dev);
-				/* DEBUG HACK: Disable statistics as an interrupt source. */
-				/* This occurs when we have the wrong media type! */
-				if (DoneDidThat == 0 && inw(ioaddr + EL3_STATUS) & StatsFull) {
-					int win, reg;
-					pr_notice("%s: Updating stats failed, disabling stats as an interrupt source.\n",
-						dev->name);
-					for (win = 0; win < 8; win++) {
-						EL3WINDOW(win);
-						pr_notice("Vortex window %d:", win);
-						for (reg = 0; reg < 16; reg++)
-							pr_cont(" %2.2x", inb(ioaddr + reg));
-						pr_cont("\n");
-					}
-					EL3WINDOW(7);
-					outw(SetIntrEnb | TxAvailable |
-					     RxComplete | AdapterFailure |
-					     UpComplete | DownComplete |
-					     TxComplete, ioaddr + EL3_CMD);
-					DoneDidThat++;
-				}
-			}
-			if (status & AdapterFailure) {
-				/* Adapter failure requires Rx reset and reinit. */
-				outw(RxReset, ioaddr + EL3_CMD);
-				/* Set the Rx filter to the current state. */
-				set_rx_mode(dev);
-				outw(RxEnable, ioaddr + EL3_CMD);	/* Re-enable the receiver. */
-				outw(AckIntr | AdapterFailure,
-				     ioaddr + EL3_CMD);
-			}
-		}
-
-		if (--i < 0) {
-			pr_err("%s: Too much work in interrupt, status %4.4x. Disabling functions (%4.4x).\n",
-				dev->name, status, SetStatusEnb | ((~status) & 0x7FE));
-			/* Disable all pending interrupts. */
-			outw(SetStatusEnb | ((~status) & 0x7FE), ioaddr + EL3_CMD);
-			outw(AckIntr | 0x7FF, ioaddr + EL3_CMD);
-			break;
-		}
-		/* Acknowledge the IRQ. */
-		outw(AckIntr | IntReq | IntLatch, ioaddr + EL3_CMD);
-
-	} while ((status = inw(ioaddr + EL3_STATUS)) & (IntLatch | RxComplete));
-
-	spin_unlock(&lp->lock);
-
-	if (corkscrew_debug > 4)
-		pr_debug("%s: exiting interrupt, status %4.4x.\n", dev->name, status);
-	return IRQ_HANDLED;
-}
-
-static int corkscrew_rx(struct net_device *dev)
-{
-	int ioaddr = dev->base_addr;
-	int i;
-	short rx_status;
-
-	if (corkscrew_debug > 5)
-		pr_debug("   In rx_packet(), status %4.4x, rx_status %4.4x.\n",
-		     inw(ioaddr + EL3_STATUS), inw(ioaddr + RxStatus));
-	while ((rx_status = inw(ioaddr + RxStatus)) > 0) {
-		if (rx_status & 0x4000) {	/* Error, update stats. */
-			unsigned char rx_error = inb(ioaddr + RxErrors);
-			if (corkscrew_debug > 2)
-				pr_debug(" Rx error: status %2.2x.\n",
-				       rx_error);
-			dev->stats.rx_errors++;
-			if (rx_error & 0x01)
-				dev->stats.rx_over_errors++;
-			if (rx_error & 0x02)
-				dev->stats.rx_length_errors++;
-			if (rx_error & 0x04)
-				dev->stats.rx_frame_errors++;
-			if (rx_error & 0x08)
-				dev->stats.rx_crc_errors++;
-			if (rx_error & 0x10)
-				dev->stats.rx_length_errors++;
-		} else {
-			/* The packet length: up to 4.5K!. */
-			short pkt_len = rx_status & 0x1fff;
-			struct sk_buff *skb;
-
-			skb = netdev_alloc_skb(dev, pkt_len + 5 + 2);
-			if (corkscrew_debug > 4)
-				pr_debug("Receiving packet size %d status %4.4x.\n",
-				     pkt_len, rx_status);
-			if (skb != NULL) {
-				skb_reserve(skb, 2);	/* Align IP on 16 byte boundaries */
-				/* 'skb_put()' points to the start of sk_buff data area. */
-				insl(ioaddr + RX_FIFO,
-				     skb_put(skb, pkt_len),
-				     (pkt_len + 3) >> 2);
-				outw(RxDiscard, ioaddr + EL3_CMD);	/* Pop top Rx packet. */
-				skb->protocol = eth_type_trans(skb, dev);
-				netif_rx(skb);
-				dev->stats.rx_packets++;
-				dev->stats.rx_bytes += pkt_len;
-				/* Wait a limited time to go to next packet. */
-				for (i = 200; i >= 0; i--)
-					if (! (inw(ioaddr + EL3_STATUS) & CmdInProgress))
-						break;
-				continue;
-			} else if (corkscrew_debug)
-				pr_debug("%s: Couldn't allocate a sk_buff of size %d.\n", dev->name, pkt_len);
-		}
-		outw(RxDiscard, ioaddr + EL3_CMD);
-		dev->stats.rx_dropped++;
-		/* Wait a limited time to skip this packet. */
-		for (i = 200; i >= 0; i--)
-			if (!(inw(ioaddr + EL3_STATUS) & CmdInProgress))
-				break;
-	}
-	return 0;
-}
-
-static int boomerang_rx(struct net_device *dev)
-{
-	struct corkscrew_private *vp = netdev_priv(dev);
-	int entry = vp->cur_rx % RX_RING_SIZE;
-	int ioaddr = dev->base_addr;
-	int rx_status;
-
-	if (corkscrew_debug > 5)
-		pr_debug("   In boomerang_rx(), status %4.4x, rx_status %4.4x.\n",
-			inw(ioaddr + EL3_STATUS), inw(ioaddr + RxStatus));
-	while ((rx_status = vp->rx_ring[entry].status) & RxDComplete) {
-		if (rx_status & RxDError) {	/* Error, update stats. */
-			unsigned char rx_error = rx_status >> 16;
-			if (corkscrew_debug > 2)
-				pr_debug(" Rx error: status %2.2x.\n",
-				       rx_error);
-			dev->stats.rx_errors++;
-			if (rx_error & 0x01)
-				dev->stats.rx_over_errors++;
-			if (rx_error & 0x02)
-				dev->stats.rx_length_errors++;
-			if (rx_error & 0x04)
-				dev->stats.rx_frame_errors++;
-			if (rx_error & 0x08)
-				dev->stats.rx_crc_errors++;
-			if (rx_error & 0x10)
-				dev->stats.rx_length_errors++;
-		} else {
-			/* The packet length: up to 4.5K!. */
-			short pkt_len = rx_status & 0x1fff;
-			struct sk_buff *skb;
-
-			dev->stats.rx_bytes += pkt_len;
-			if (corkscrew_debug > 4)
-				pr_debug("Receiving packet size %d status %4.4x.\n",
-				     pkt_len, rx_status);
-
-			/* Check if the packet is long enough to just accept without
-			   copying to a properly sized skbuff. */
-			if (pkt_len < rx_copybreak &&
-			    (skb = netdev_alloc_skb(dev, pkt_len + 4)) != NULL) {
-				skb_reserve(skb, 2);	/* Align IP on 16 byte boundaries */
-				/* 'skb_put()' points to the start of sk_buff data area. */
-				skb_put_data(skb,
-					     isa_bus_to_virt(vp->rx_ring[entry].addr),
-					     pkt_len);
-				rx_copy++;
-			} else {
-				void *temp;
-				/* Pass up the skbuff already on the Rx ring. */
-				skb = vp->rx_skbuff[entry];
-				vp->rx_skbuff[entry] = NULL;
-				temp = skb_put(skb, pkt_len);
-				/* Remove this checking code for final release. */
-				if (isa_bus_to_virt(vp->rx_ring[entry].addr) != temp)
-					pr_warn("%s: Warning -- the skbuff addresses do not match in boomerang_rx: %p vs. %p / %p\n",
-						dev->name,
-						isa_bus_to_virt(vp->rx_ring[entry].addr),
-						skb->head, temp);
-				rx_nocopy++;
-			}
-			skb->protocol = eth_type_trans(skb, dev);
-			netif_rx(skb);
-			dev->stats.rx_packets++;
-		}
-		entry = (++vp->cur_rx) % RX_RING_SIZE;
-	}
-	/* Refill the Rx ring buffers. */
-	for (; vp->cur_rx - vp->dirty_rx > 0; vp->dirty_rx++) {
-		struct sk_buff *skb;
-		entry = vp->dirty_rx % RX_RING_SIZE;
-		if (vp->rx_skbuff[entry] == NULL) {
-			skb = netdev_alloc_skb(dev, PKT_BUF_SZ);
-			if (skb == NULL)
-				break;	/* Bad news!  */
-			skb_reserve(skb, 2);	/* Align IP on 16 byte boundaries */
-			vp->rx_ring[entry].addr = isa_virt_to_bus(skb->data);
-			vp->rx_skbuff[entry] = skb;
-		}
-		vp->rx_ring[entry].status = 0;	/* Clear complete bit. */
-	}
-	return 0;
-}
-
-static int corkscrew_close(struct net_device *dev)
-{
-	struct corkscrew_private *vp = netdev_priv(dev);
-	int ioaddr = dev->base_addr;
-	int i;
-
-	netif_stop_queue(dev);
-
-	if (corkscrew_debug > 1) {
-		pr_debug("%s: corkscrew_close() status %4.4x, Tx status %2.2x.\n",
-		     dev->name, inw(ioaddr + EL3_STATUS),
-		     inb(ioaddr + TxStatus));
-		pr_debug("%s: corkscrew close stats: rx_nocopy %d rx_copy %d tx_queued %d.\n",
-			dev->name, rx_nocopy, rx_copy, queued_packet);
-	}
-
-	timer_delete_sync(&vp->timer);
-
-	/* Turn off statistics ASAP.  We update lp->stats below. */
-	outw(StatsDisable, ioaddr + EL3_CMD);
-
-	/* Disable the receiver and transmitter. */
-	outw(RxDisable, ioaddr + EL3_CMD);
-	outw(TxDisable, ioaddr + EL3_CMD);
-
-	if (dev->if_port == XCVR_10base2)
-		/* Turn off thinnet power.  Green! */
-		outw(StopCoax, ioaddr + EL3_CMD);
-
-	free_irq(dev->irq, dev);
-
-	outw(SetIntrEnb | 0x0000, ioaddr + EL3_CMD);
-
-	update_stats(ioaddr, dev);
-	if (vp->full_bus_master_rx) {	/* Free Boomerang bus master Rx buffers. */
-		outl(0, ioaddr + UpListPtr);
-		for (i = 0; i < RX_RING_SIZE; i++)
-			if (vp->rx_skbuff[i]) {
-				dev_kfree_skb(vp->rx_skbuff[i]);
-				vp->rx_skbuff[i] = NULL;
-			}
-	}
-	if (vp->full_bus_master_tx) {	/* Free Boomerang bus master Tx buffers. */
-		outl(0, ioaddr + DownListPtr);
-		for (i = 0; i < TX_RING_SIZE; i++)
-			if (vp->tx_skbuff[i]) {
-				dev_kfree_skb(vp->tx_skbuff[i]);
-				vp->tx_skbuff[i] = NULL;
-			}
-	}
-
-	return 0;
-}
-
-static struct net_device_stats *corkscrew_get_stats(struct net_device *dev)
-{
-	struct corkscrew_private *vp = netdev_priv(dev);
-	unsigned long flags;
-
-	if (netif_running(dev)) {
-		spin_lock_irqsave(&vp->lock, flags);
-		update_stats(dev->base_addr, dev);
-		spin_unlock_irqrestore(&vp->lock, flags);
-	}
-	return &dev->stats;
-}
-
-/*  Update statistics.
-	Unlike with the EL3 we need not worry about interrupts changing
-	the window setting from underneath us, but we must still guard
-	against a race condition with a StatsUpdate interrupt updating the
-	table.  This is done by checking that the ASM (!) code generated uses
-	atomic updates with '+='.
-	*/
-static void update_stats(int ioaddr, struct net_device *dev)
-{
-	/* Unlike the 3c5x9 we need not turn off stats updates while reading. */
-	/* Switch to the stats window, and read everything. */
-	EL3WINDOW(6);
-	dev->stats.tx_carrier_errors += inb(ioaddr + 0);
-	dev->stats.tx_heartbeat_errors += inb(ioaddr + 1);
-	/* Multiple collisions. */ inb(ioaddr + 2);
-	dev->stats.collisions += inb(ioaddr + 3);
-	dev->stats.tx_window_errors += inb(ioaddr + 4);
-	dev->stats.rx_fifo_errors += inb(ioaddr + 5);
-	dev->stats.tx_packets += inb(ioaddr + 6);
-	dev->stats.tx_packets += (inb(ioaddr + 9) & 0x30) << 4;
-						/* Rx packets   */ inb(ioaddr + 7);
-						/* Must read to clear */
-	/* Tx deferrals */ inb(ioaddr + 8);
-	/* Don't bother with register 9, an extension of registers 6&7.
-	   If we do use the 6&7 values the atomic update assumption above
-	   is invalid. */
-	inw(ioaddr + 10);	/* Total Rx and Tx octets. */
-	inw(ioaddr + 12);
-	/* New: On the Vortex we must also clear the BadSSD counter. */
-	EL3WINDOW(4);
-	inb(ioaddr + 12);
-
-	/* We change back to window 7 (not 1) with the Vortex. */
-	EL3WINDOW(7);
-}
-
-/* This new version of set_rx_mode() supports v1.4 kernels.
-   The Vortex chip has no documented multicast filter, so the only
-   multicast setting is to receive all multicast frames.  At least
-   the chip has a very clean way to set the mode, unlike many others. */
-static void set_rx_mode(struct net_device *dev)
-{
-	int ioaddr = dev->base_addr;
-	unsigned short new_mode;
-
-	if (dev->flags & IFF_PROMISC) {
-		if (corkscrew_debug > 3)
-			pr_debug("%s: Setting promiscuous mode.\n",
-			       dev->name);
-		new_mode = SetRxFilter | RxStation | RxMulticast | RxBroadcast | RxProm;
-	} else if (!netdev_mc_empty(dev) || dev->flags & IFF_ALLMULTI) {
-		new_mode = SetRxFilter | RxStation | RxMulticast | RxBroadcast;
-	} else
-		new_mode = SetRxFilter | RxStation | RxBroadcast;
-
-	outw(new_mode, ioaddr + EL3_CMD);
-}
-
-static void netdev_get_drvinfo(struct net_device *dev,
-			       struct ethtool_drvinfo *info)
-{
-	strscpy(info->driver, DRV_NAME, sizeof(info->driver));
-	snprintf(info->bus_info, sizeof(info->bus_info), "ISA 0x%lx",
-		 dev->base_addr);
-}
-
-static u32 netdev_get_msglevel(struct net_device *dev)
-{
-	return corkscrew_debug;
-}
-
-static void netdev_set_msglevel(struct net_device *dev, u32 level)
-{
-	corkscrew_debug = level;
-}
-
-static const struct ethtool_ops netdev_ethtool_ops = {
-	.get_drvinfo		= netdev_get_drvinfo,
-	.get_msglevel		= netdev_get_msglevel,
-	.set_msglevel		= netdev_set_msglevel,
-};
-
-#ifdef MODULE
-static void __exit corkscrew_exit_module(void)
-{
-	while (!list_empty(&root_corkscrew_dev)) {
-		struct net_device *dev;
-		struct corkscrew_private *vp;
-
-		vp = list_entry(root_corkscrew_dev.next,
-				struct corkscrew_private, list);
-		dev = vp->our_dev;
-		unregister_netdev(dev);
-		cleanup_card(dev);
-		free_netdev(dev);
-	}
-}
-module_exit(corkscrew_exit_module);
-#endif				/* MODULE */
diff --git a/drivers/net/ethernet/3com/Kconfig b/drivers/net/ethernet/3com/Kconfig
index c05a1b63c1c9..3fd3202d9776 100644
--- a/drivers/net/ethernet/3com/Kconfig
+++ b/drivers/net/ethernet/3com/Kconfig
@@ -17,17 +17,6 @@ config NET_VENDOR_3COM
 
 if NET_VENDOR_3COM
 
-config 3C515
-	tristate "3c515 ISA \"Fast EtherLink\""
-	depends on ISA && ISA_DMA_API && !PPC32
-	select NETDEV_LEGACY_INIT
-	help
-	  If you have a 3Com ISA EtherLink XL "Corkscrew" 3c515 Fast Ethernet
-	  network card, say Y here.
-
-	  To compile this driver as a module, choose M here. The module
-	  will be called 3c515.
-
 config PCMCIA_3C574
 	tristate "3Com 3c574 PCMCIA support"
 	depends on PCMCIA && HAS_IOPORT
diff --git a/drivers/net/ethernet/3com/Makefile b/drivers/net/ethernet/3com/Makefile
index f7623fa2d441..babfd93d5d53 100644
--- a/drivers/net/ethernet/3com/Makefile
+++ b/drivers/net/ethernet/3com/Makefile
@@ -3,7 +3,6 @@
 # Makefile for the 3Com Ethernet device drivers
 #
 
-obj-$(CONFIG_3C515) += 3c515.o
 obj-$(CONFIG_PCMCIA_3C589) += 3c589_cs.o
 obj-$(CONFIG_PCMCIA_3C574) += 3c574_cs.o
 obj-$(CONFIG_VORTEX) += 3c59x.o

-- 
2.53.0


^ permalink raw reply related	[flat|nested] 28+ messages in thread

* [PATCH net 03/18] drivers: net: 3com: 3c574: Remove this driver
  2026-04-21 19:31 [PATCH net 00/18] Remove a number of ISA and PCMCIA Ethernet drivers Andrew Lunn
  2026-04-21 19:31 ` [PATCH net 01/18] drivers: net: 3com: 3c509: Remove this driver Andrew Lunn
  2026-04-21 19:31 ` [PATCH net 02/18] drivers: net: 3com: 3c515: " Andrew Lunn
@ 2026-04-21 19:31 ` Andrew Lunn
  2026-04-21 19:31 ` [PATCH net 04/18] drivers: net: 3com: 3c589: " Andrew Lunn
                   ` (18 subsequent siblings)
  21 siblings, 0 replies; 28+ messages in thread
From: Andrew Lunn @ 2026-04-21 19:31 UTC (permalink / raw)
  To: Andrew Lunn, David S. Miller, Eric Dumazet, Jakub Kicinski,
	Paolo Abeni, Simon Horman, Jonathan Corbet, Shuah Khan
  Cc: linux-kernel, netdev, linux-doc, Andrew Lunn

The 3c574 was written by Donald Becker between 19973-1998. It is an
PCMCIA device, so unlikely to be used with modern kernels.

Signed-off-by: Andrew Lunn <andrew@lunn.ch>
---
 drivers/net/ethernet/3com/3c574_cs.c | 1164 ----------------------------------
 drivers/net/ethernet/3com/Kconfig    |   10 -
 drivers/net/ethernet/3com/Makefile   |    1 -
 3 files changed, 1175 deletions(-)

diff --git a/drivers/net/ethernet/3com/3c574_cs.c b/drivers/net/ethernet/3com/3c574_cs.c
deleted file mode 100644
index 1f2070497a75..000000000000
--- a/drivers/net/ethernet/3com/3c574_cs.c
+++ /dev/null
@@ -1,1164 +0,0 @@
-/* 3c574.c: A PCMCIA ethernet driver for the 3com 3c574 "RoadRunner".
-
-	Written 1993-1998 by
-	Donald Becker, becker@scyld.com, (driver core) and
-	David Hinds, dahinds@users.sourceforge.net (from his PC card code).
-	Locking fixes (C) Copyright 2003 Red Hat Inc
-
-	This software may be used and distributed according to the terms of
-	the GNU General Public License, incorporated herein by reference.
-
-	This driver derives from Donald Becker's 3c509 core, which has the
-	following copyright:
-	Copyright 1993 United States Government as represented by the
-	Director, National Security Agency.
-	
-
-*/
-
-/*
-				Theory of Operation
-
-I. Board Compatibility
-
-This device driver is designed for the 3Com 3c574 PC card Fast Ethernet
-Adapter.
-
-II. Board-specific settings
-
-None -- PC cards are autoconfigured.
-
-III. Driver operation
-
-The 3c574 uses a Boomerang-style interface, without the bus-master capability.
-See the Boomerang driver and documentation for most details.
-
-IV. Notes and chip documentation.
-
-Two added registers are used to enhance PIO performance, RunnerRdCtrl and
-RunnerWrCtrl.  These are 11 bit down-counters that are preloaded with the
-count of word (16 bits) reads or writes the driver is about to do to the Rx
-or Tx FIFO.  The chip is then able to hide the internal-PCI-bus to PC-card
-translation latency by buffering the I/O operations with an 8 word FIFO.
-Note: No other chip accesses are permitted when this buffer is used.
-
-A second enhancement is that both attribute and common memory space
-0x0800-0x0fff can translated to the PIO FIFO.  Thus memory operations (faster
-with *some* PCcard bridges) may be used instead of I/O operations.
-This is enabled by setting the 0x10 bit in the PCMCIA LAN COR.
-
-Some slow PC card bridges work better if they never see a WAIT signal.
-This is configured by setting the 0x20 bit in the PCMCIA LAN COR.
-Only do this after testing that it is reliable and improves performance.
-
-The upper five bits of RunnerRdCtrl are used to window into PCcard
-configuration space registers.  Window 0 is the regular Boomerang/Odie
-register set, 1-5 are various PC card control registers, and 16-31 are
-the (reversed!) CIS table.
-
-A final note: writing the InternalConfig register in window 3 with an
-invalid ramWidth is Very Bad.
-
-V. References
-
-http://www.scyld.com/expert/NWay.html
-http://www.national.com/opf/DP/DP83840A.html
-
-Thanks to Terry Murphy of 3Com for providing development information for
-earlier 3Com products.
-
-*/
-
-#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
-
-#include <linux/module.h>
-#include <linux/kernel.h>
-#include <linux/slab.h>
-#include <linux/string.h>
-#include <linux/timer.h>
-#include <linux/interrupt.h>
-#include <linux/in.h>
-#include <linux/delay.h>
-#include <linux/netdevice.h>
-#include <linux/etherdevice.h>
-#include <linux/skbuff.h>
-#include <linux/if_arp.h>
-#include <linux/ioport.h>
-#include <linux/bitops.h>
-#include <linux/mii.h>
-
-#include <pcmcia/cistpl.h>
-#include <pcmcia/cisreg.h>
-#include <pcmcia/ciscode.h>
-#include <pcmcia/ds.h>
-
-#include <linux/uaccess.h>
-#include <asm/io.h>
-
-/*====================================================================*/
-
-/* Module parameters */
-
-MODULE_AUTHOR("David Hinds <dahinds@users.sourceforge.net>");
-MODULE_DESCRIPTION("3Com 3c574 series PCMCIA ethernet driver");
-MODULE_LICENSE("GPL");
-
-#define INT_MODULE_PARM(n, v) static int n = v; module_param(n, int, 0)
-
-/* Maximum events (Rx packets, etc.) to handle at each interrupt. */
-INT_MODULE_PARM(max_interrupt_work, 32);
-
-/* Force full duplex modes? */
-INT_MODULE_PARM(full_duplex, 0);
-
-/* Autodetect link polarity reversal? */
-INT_MODULE_PARM(auto_polarity, 1);
-
-
-/*====================================================================*/
-
-/* Time in jiffies before concluding the transmitter is hung. */
-#define TX_TIMEOUT  ((800*HZ)/1000)
-
-/* To minimize the size of the driver source and make the driver more
-   readable not all constants are symbolically defined.
-   You'll need the manual if you want to understand driver details anyway. */
-/* Offsets from base I/O address. */
-#define EL3_DATA	0x00
-#define EL3_CMD		0x0e
-#define EL3_STATUS	0x0e
-
-#define EL3WINDOW(win_num) outw(SelectWindow + (win_num), ioaddr + EL3_CMD)
-
-/* The top five bits written to EL3_CMD are a command, the lower
-   11 bits are the parameter, if applicable. */
-enum el3_cmds {
-	TotalReset = 0<<11, SelectWindow = 1<<11, StartCoax = 2<<11,
-	RxDisable = 3<<11, RxEnable = 4<<11, RxReset = 5<<11, RxDiscard = 8<<11,
-	TxEnable = 9<<11, TxDisable = 10<<11, TxReset = 11<<11,
-	FakeIntr = 12<<11, AckIntr = 13<<11, SetIntrEnb = 14<<11,
-	SetStatusEnb = 15<<11, SetRxFilter = 16<<11, SetRxThreshold = 17<<11,
-	SetTxThreshold = 18<<11, SetTxStart = 19<<11, StatsEnable = 21<<11,
-	StatsDisable = 22<<11, StopCoax = 23<<11,
-};
-
-enum elxl_status {
-	IntLatch = 0x0001, AdapterFailure = 0x0002, TxComplete = 0x0004,
-	TxAvailable = 0x0008, RxComplete = 0x0010, RxEarly = 0x0020,
-	IntReq = 0x0040, StatsFull = 0x0080, CmdBusy = 0x1000 };
-
-/* The SetRxFilter command accepts the following classes: */
-enum RxFilter {
-	RxStation = 1, RxMulticast = 2, RxBroadcast = 4, RxProm = 8
-};
-
-enum Window0 {
-	Wn0EepromCmd = 10, Wn0EepromData = 12, /* EEPROM command/address, data. */
-	IntrStatus=0x0E,		/* Valid in all windows. */
-};
-/* These assumes the larger EEPROM. */
-enum Win0_EEPROM_cmds {
-	EEPROM_Read = 0x200, EEPROM_WRITE = 0x100, EEPROM_ERASE = 0x300,
-	EEPROM_EWENB = 0x30,		/* Enable erasing/writing for 10 msec. */
-	EEPROM_EWDIS = 0x00,		/* Disable EWENB before 10 msec timeout. */
-};
-
-/* Register window 1 offsets, the window used in normal operation.
-   On the "Odie" this window is always mapped at offsets 0x10-0x1f.
-   Except for TxFree, which is overlapped by RunnerWrCtrl. */
-enum Window1 {
-	TX_FIFO = 0x10,  RX_FIFO = 0x10,  RxErrors = 0x14,
-	RxStatus = 0x18,  Timer=0x1A, TxStatus = 0x1B,
-	TxFree = 0x0C, /* Remaining free bytes in Tx buffer. */
-	RunnerRdCtrl = 0x16, RunnerWrCtrl = 0x1c,
-};
-
-enum Window3 {			/* Window 3: MAC/config bits. */
-	Wn3_Config=0, Wn3_MAC_Ctrl=6, Wn3_Options=8,
-};
-enum wn3_config {
-	Ram_size = 7,
-	Ram_width = 8,
-	Ram_speed = 0x30,
-	Rom_size = 0xc0,
-	Ram_split_shift = 16,
-	Ram_split = 3 << Ram_split_shift,
-	Xcvr_shift = 20,
-	Xcvr = 7 << Xcvr_shift,
-	Autoselect = 0x1000000,
-};
-
-enum Window4 {		/* Window 4: Xcvr/media bits. */
-	Wn4_FIFODiag = 4, Wn4_NetDiag = 6, Wn4_PhysicalMgmt=8, Wn4_Media = 10,
-};
-
-#define MEDIA_TP	0x00C0	/* Enable link beat and jabber for 10baseT. */
-
-struct el3_private {
-	struct pcmcia_device	*p_dev;
-	u16 advertising, partner;		/* NWay media advertisement */
-	unsigned char phys;			/* MII device address */
-	unsigned int autoselect:1, default_media:3;	/* Read from the EEPROM/Wn3_Config. */
-	/* for transceiver monitoring */
-	struct timer_list media;
-	unsigned short media_status;
-	unsigned short fast_poll;
-	unsigned long last_irq;
-	spinlock_t window_lock;			/* Guards the Window selection */
-};
-
-/* Set iff a MII transceiver on any interface requires mdio preamble.
-   This only set with the original DP83840 on older 3c905 boards, so the extra
-   code size of a per-interface flag is not worthwhile. */
-static char mii_preamble_required = 0;
-
-/* Index of functions. */
-
-static int tc574_config(struct pcmcia_device *link);
-static void tc574_release(struct pcmcia_device *link);
-
-static void mdio_sync(unsigned int ioaddr, int bits);
-static int mdio_read(unsigned int ioaddr, int phy_id, int location);
-static void mdio_write(unsigned int ioaddr, int phy_id, int location,
-		       int value);
-static unsigned short read_eeprom(unsigned int ioaddr, int index);
-static void tc574_wait_for_completion(struct net_device *dev, int cmd);
-
-static void tc574_reset(struct net_device *dev);
-static void media_check(struct timer_list *t);
-static int el3_open(struct net_device *dev);
-static netdev_tx_t el3_start_xmit(struct sk_buff *skb,
-					struct net_device *dev);
-static irqreturn_t el3_interrupt(int irq, void *dev_id);
-static void update_stats(struct net_device *dev);
-static struct net_device_stats *el3_get_stats(struct net_device *dev);
-static int el3_rx(struct net_device *dev, int worklimit);
-static int el3_close(struct net_device *dev);
-static void el3_tx_timeout(struct net_device *dev, unsigned int txqueue);
-static int el3_ioctl(struct net_device *dev, struct ifreq *rq, int cmd);
-static void set_rx_mode(struct net_device *dev);
-static void set_multicast_list(struct net_device *dev);
-
-static void tc574_detach(struct pcmcia_device *p_dev);
-
-/*
-	tc574_attach() creates an "instance" of the driver, allocating
-	local data structures for one device.  The device is registered
-	with Card Services.
-*/
-static const struct net_device_ops el3_netdev_ops = {
-	.ndo_open 		= el3_open,
-	.ndo_stop 		= el3_close,
-	.ndo_start_xmit		= el3_start_xmit,
-	.ndo_tx_timeout 	= el3_tx_timeout,
-	.ndo_get_stats		= el3_get_stats,
-	.ndo_eth_ioctl		= el3_ioctl,
-	.ndo_set_rx_mode	= set_multicast_list,
-	.ndo_set_mac_address 	= eth_mac_addr,
-	.ndo_validate_addr	= eth_validate_addr,
-};
-
-static int tc574_probe(struct pcmcia_device *link)
-{
-	struct el3_private *lp;
-	struct net_device *dev;
-
-	dev_dbg(&link->dev, "3c574_attach()\n");
-
-	/* Create the PC card device object. */
-	dev = alloc_etherdev(sizeof(struct el3_private));
-	if (!dev)
-		return -ENOMEM;
-	lp = netdev_priv(dev);
-	link->priv = dev;
-	lp->p_dev = link;
-
-	spin_lock_init(&lp->window_lock);
-	link->resource[0]->end = 32;
-	link->resource[0]->flags |= IO_DATA_PATH_WIDTH_16;
-	link->config_flags |= CONF_ENABLE_IRQ;
-	link->config_index = 1;
-
-	dev->netdev_ops = &el3_netdev_ops;
-	dev->watchdog_timeo = TX_TIMEOUT;
-
-	return tc574_config(link);
-}
-
-static void tc574_detach(struct pcmcia_device *link)
-{
-	struct net_device *dev = link->priv;
-
-	dev_dbg(&link->dev, "3c574_detach()\n");
-
-	unregister_netdev(dev);
-
-	tc574_release(link);
-
-	free_netdev(dev);
-} /* tc574_detach */
-
-static const char *ram_split[] = {"5:3", "3:1", "1:1", "3:5"};
-
-static int tc574_config(struct pcmcia_device *link)
-{
-	struct net_device *dev = link->priv;
-	struct el3_private *lp = netdev_priv(dev);
-	int ret, i, j;
-	__be16 addr[ETH_ALEN / 2];
-	unsigned int ioaddr;
-	char *cardname;
-	__u32 config;
-	u8 *buf;
-	size_t len;
-
-	dev_dbg(&link->dev, "3c574_config()\n");
-
-	link->io_lines = 16;
-
-	for (i = j = 0; j < 0x400; j += 0x20) {
-		link->resource[0]->start = j ^ 0x300;
-		i = pcmcia_request_io(link);
-		if (i == 0)
-			break;
-	}
-	if (i != 0)
-		goto failed;
-
-	ret = pcmcia_request_irq(link, el3_interrupt);
-	if (ret)
-		goto failed;
-
-	ret = pcmcia_enable_device(link);
-	if (ret)
-		goto failed;
-
-	dev->irq = link->irq;
-	dev->base_addr = link->resource[0]->start;
-
-	ioaddr = dev->base_addr;
-
-	/* The 3c574 normally uses an EEPROM for configuration info, including
-	   the hardware address.  The future products may include a modem chip
-	   and put the address in the CIS. */
-
-	len = pcmcia_get_tuple(link, 0x88, &buf);
-	if (buf && len >= 6) {
-		for (i = 0; i < 3; i++)
-			addr[i] = htons(le16_to_cpu(buf[i * 2]));
-		kfree(buf);
-	} else {
-		kfree(buf); /* 0 < len < 6 */
-		EL3WINDOW(0);
-		for (i = 0; i < 3; i++)
-			addr[i] = htons(read_eeprom(ioaddr, i + 10));
-		if (addr[0] == htons(0x6060)) {
-			pr_notice("IO port conflict at 0x%03lx-0x%03lx\n",
-				  dev->base_addr, dev->base_addr+15);
-			goto failed;
-		}
-	}
-	eth_hw_addr_set(dev, (u8 *)addr);
-	if (link->prod_id[1])
-		cardname = link->prod_id[1];
-	else
-		cardname = "3Com 3c574";
-
-	{
-		u_char mcr;
-		outw(2<<11, ioaddr + RunnerRdCtrl);
-		mcr = inb(ioaddr + 2);
-		outw(0<<11, ioaddr + RunnerRdCtrl);
-		pr_info("  ASIC rev %d,", mcr>>3);
-		EL3WINDOW(3);
-		config = inl(ioaddr + Wn3_Config);
-		lp->default_media = (config & Xcvr) >> Xcvr_shift;
-		lp->autoselect = config & Autoselect ? 1 : 0;
-	}
-
-	timer_setup(&lp->media, media_check, 0);
-
-	{
-		int phy;
-		
-		/* Roadrunner only: Turn on the MII transceiver */
-		outw(0x8040, ioaddr + Wn3_Options);
-		mdelay(1);
-		outw(0xc040, ioaddr + Wn3_Options);
-		tc574_wait_for_completion(dev, TxReset);
-		tc574_wait_for_completion(dev, RxReset);
-		mdelay(1);
-		outw(0x8040, ioaddr + Wn3_Options);
-		
-		EL3WINDOW(4);
-		for (phy = 1; phy <= 32; phy++) {
-			int mii_status;
-			mdio_sync(ioaddr, 32);
-			mii_status = mdio_read(ioaddr, phy & 0x1f, 1);
-			if (mii_status != 0xffff) {
-				lp->phys = phy & 0x1f;
-				dev_dbg(&link->dev, "  MII transceiver at "
-					"index %d, status %x.\n",
-					  phy, mii_status);
-				if ((mii_status & 0x0040) == 0)
-					mii_preamble_required = 1;
-				break;
-			}
-		}
-		if (phy > 32) {
-			pr_notice("  No MII transceivers found!\n");
-			goto failed;
-		}
-		i = mdio_read(ioaddr, lp->phys, 16) | 0x40;
-		mdio_write(ioaddr, lp->phys, 16, i);
-		lp->advertising = mdio_read(ioaddr, lp->phys, 4);
-		if (full_duplex) {
-			/* Only advertise the FD media types. */
-			lp->advertising &= ~0x02a0;
-			mdio_write(ioaddr, lp->phys, 4, lp->advertising);
-		}
-	}
-
-	SET_NETDEV_DEV(dev, &link->dev);
-
-	if (register_netdev(dev) != 0) {
-		pr_notice("register_netdev() failed\n");
-		goto failed;
-	}
-
-	netdev_info(dev, "%s at io %#3lx, irq %d, hw_addr %pM\n",
-		    cardname, dev->base_addr, dev->irq, dev->dev_addr);
-	netdev_info(dev, " %dK FIFO split %s Rx:Tx, %sMII interface.\n",
-		    8 << (config & Ram_size),
-		    ram_split[(config & Ram_split) >> Ram_split_shift],
-		    config & Autoselect ? "autoselect " : "");
-
-	return 0;
-
-failed:
-	tc574_release(link);
-	return -ENODEV;
-
-} /* tc574_config */
-
-static void tc574_release(struct pcmcia_device *link)
-{
-	pcmcia_disable_device(link);
-}
-
-static int tc574_suspend(struct pcmcia_device *link)
-{
-	struct net_device *dev = link->priv;
-
-	if (link->open)
-		netif_device_detach(dev);
-
-	return 0;
-}
-
-static int tc574_resume(struct pcmcia_device *link)
-{
-	struct net_device *dev = link->priv;
-
-	if (link->open) {
-		tc574_reset(dev);
-		netif_device_attach(dev);
-	}
-
-	return 0;
-}
-
-static void dump_status(struct net_device *dev)
-{
-	unsigned int ioaddr = dev->base_addr;
-	EL3WINDOW(1);
-	netdev_info(dev, "  irq status %04x, rx status %04x, tx status %02x, tx free %04x\n",
-		    inw(ioaddr+EL3_STATUS),
-		    inw(ioaddr+RxStatus), inb(ioaddr+TxStatus),
-		    inw(ioaddr+TxFree));
-	EL3WINDOW(4);
-	netdev_info(dev, "  diagnostics: fifo %04x net %04x ethernet %04x media %04x\n",
-		    inw(ioaddr+0x04), inw(ioaddr+0x06),
-		    inw(ioaddr+0x08), inw(ioaddr+0x0a));
-	EL3WINDOW(1);
-}
-
-/*
-  Use this for commands that may take time to finish
-*/
-static void tc574_wait_for_completion(struct net_device *dev, int cmd)
-{
-	int i = 1500;
-	outw(cmd, dev->base_addr + EL3_CMD);
-	while (--i > 0)
-		if (!(inw(dev->base_addr + EL3_STATUS) & 0x1000)) break;
-	if (i == 0)
-		netdev_notice(dev, "command 0x%04x did not complete!\n", cmd);
-}
-
-/* Read a word from the EEPROM using the regular EEPROM access register.
-   Assume that we are in register window zero.
- */
-static unsigned short read_eeprom(unsigned int ioaddr, int index)
-{
-	int timer;
-	outw(EEPROM_Read + index, ioaddr + Wn0EepromCmd);
-	/* Pause for at least 162 usec for the read to take place. */
-	for (timer = 1620; timer >= 0; timer--) {
-		if ((inw(ioaddr + Wn0EepromCmd) & 0x8000) == 0)
-			break;
-	}
-	return inw(ioaddr + Wn0EepromData);
-}
-
-/* MII transceiver control section.
-   Read and write the MII registers using software-generated serial
-   MDIO protocol.  See the MII specifications or DP83840A data sheet
-   for details.
-   The maxium data clock rate is 2.5 Mhz.  The timing is easily met by the
-   slow PC card interface. */
-
-#define MDIO_SHIFT_CLK	0x01
-#define MDIO_DIR_WRITE	0x04
-#define MDIO_DATA_WRITE0 (0x00 | MDIO_DIR_WRITE)
-#define MDIO_DATA_WRITE1 (0x02 | MDIO_DIR_WRITE)
-#define MDIO_DATA_READ	0x02
-#define MDIO_ENB_IN		0x00
-
-/* Generate the preamble required for initial synchronization and
-   a few older transceivers. */
-static void mdio_sync(unsigned int ioaddr, int bits)
-{
-	unsigned int mdio_addr = ioaddr + Wn4_PhysicalMgmt;
-
-	/* Establish sync by sending at least 32 logic ones. */
-	while (-- bits >= 0) {
-		outw(MDIO_DATA_WRITE1, mdio_addr);
-		outw(MDIO_DATA_WRITE1 | MDIO_SHIFT_CLK, mdio_addr);
-	}
-}
-
-static int mdio_read(unsigned int ioaddr, int phy_id, int location)
-{
-	int i;
-	int read_cmd = (0xf6 << 10) | (phy_id << 5) | location;
-	unsigned int retval = 0;
-	unsigned int mdio_addr = ioaddr + Wn4_PhysicalMgmt;
-
-	if (mii_preamble_required)
-		mdio_sync(ioaddr, 32);
-
-	/* Shift the read command bits out. */
-	for (i = 14; i >= 0; i--) {
-		int dataval = (read_cmd&(1<<i)) ? MDIO_DATA_WRITE1 : MDIO_DATA_WRITE0;
-		outw(dataval, mdio_addr);
-		outw(dataval | MDIO_SHIFT_CLK, mdio_addr);
-	}
-	/* Read the two transition, 16 data, and wire-idle bits. */
-	for (i = 19; i > 0; i--) {
-		outw(MDIO_ENB_IN, mdio_addr);
-		retval = (retval << 1) | ((inw(mdio_addr) & MDIO_DATA_READ) ? 1 : 0);
-		outw(MDIO_ENB_IN | MDIO_SHIFT_CLK, mdio_addr);
-	}
-	return (retval>>1) & 0xffff;
-}
-
-static void mdio_write(unsigned int ioaddr, int phy_id, int location, int value)
-{
-	int write_cmd = 0x50020000 | (phy_id << 23) | (location << 18) | value;
-	unsigned int mdio_addr = ioaddr + Wn4_PhysicalMgmt;
-	int i;
-
-	if (mii_preamble_required)
-		mdio_sync(ioaddr, 32);
-
-	/* Shift the command bits out. */
-	for (i = 31; i >= 0; i--) {
-		int dataval = (write_cmd&(1<<i)) ? MDIO_DATA_WRITE1 : MDIO_DATA_WRITE0;
-		outw(dataval, mdio_addr);
-		outw(dataval | MDIO_SHIFT_CLK, mdio_addr);
-	}
-	/* Leave the interface idle. */
-	for (i = 1; i >= 0; i--) {
-		outw(MDIO_ENB_IN, mdio_addr);
-		outw(MDIO_ENB_IN | MDIO_SHIFT_CLK, mdio_addr);
-	}
-}
-
-/* Reset and restore all of the 3c574 registers. */
-static void tc574_reset(struct net_device *dev)
-{
-	struct el3_private *lp = netdev_priv(dev);
-	int i;
-	unsigned int ioaddr = dev->base_addr;
-	unsigned long flags;
-
-	tc574_wait_for_completion(dev, TotalReset|0x10);
-
-	spin_lock_irqsave(&lp->window_lock, flags);
-	/* Clear any transactions in progress. */
-	outw(0, ioaddr + RunnerWrCtrl);
-	outw(0, ioaddr + RunnerRdCtrl);
-
-	/* Set the station address and mask. */
-	EL3WINDOW(2);
-	for (i = 0; i < 6; i++)
-		outb(dev->dev_addr[i], ioaddr + i);
-	for (; i < 12; i+=2)
-		outw(0, ioaddr + i);
-
-	/* Reset config options */
-	EL3WINDOW(3);
-	outb((dev->mtu > 1500 ? 0x40 : 0), ioaddr + Wn3_MAC_Ctrl);
-	outl((lp->autoselect ? 0x01000000 : 0) | 0x0062001b,
-		 ioaddr + Wn3_Config);
-	/* Roadrunner only: Turn on the MII transceiver. */
-	outw(0x8040, ioaddr + Wn3_Options);
-	mdelay(1);
-	outw(0xc040, ioaddr + Wn3_Options);
-	EL3WINDOW(1);
-	spin_unlock_irqrestore(&lp->window_lock, flags);
-	
-	tc574_wait_for_completion(dev, TxReset);
-	tc574_wait_for_completion(dev, RxReset);
-	mdelay(1);
-	spin_lock_irqsave(&lp->window_lock, flags);
-	EL3WINDOW(3);
-	outw(0x8040, ioaddr + Wn3_Options);
-
-	/* Switch to the stats window, and clear all stats by reading. */
-	outw(StatsDisable, ioaddr + EL3_CMD);
-	EL3WINDOW(6);
-	for (i = 0; i < 10; i++)
-		inb(ioaddr + i);
-	inw(ioaddr + 10);
-	inw(ioaddr + 12);
-	EL3WINDOW(4);
-	inb(ioaddr + 12);
-	inb(ioaddr + 13);
-
-	/* .. enable any extra statistics bits.. */
-	outw(0x0040, ioaddr + Wn4_NetDiag);
-	
-	EL3WINDOW(1);
-	spin_unlock_irqrestore(&lp->window_lock, flags);
-	
-	/* .. re-sync MII and re-fill what NWay is advertising. */
-	mdio_sync(ioaddr, 32);
-	mdio_write(ioaddr, lp->phys, 4, lp->advertising);
-	if (!auto_polarity) {
-		/* works for TDK 78Q2120 series MII's */
-		i = mdio_read(ioaddr, lp->phys, 16) | 0x20;
-		mdio_write(ioaddr, lp->phys, 16, i);
-	}
-
-	spin_lock_irqsave(&lp->window_lock, flags);
-	/* Switch to register set 1 for normal use, just for TxFree. */
-	set_rx_mode(dev);
-	spin_unlock_irqrestore(&lp->window_lock, flags);
-	outw(StatsEnable, ioaddr + EL3_CMD); /* Turn on statistics. */
-	outw(RxEnable, ioaddr + EL3_CMD); /* Enable the receiver. */
-	outw(TxEnable, ioaddr + EL3_CMD); /* Enable transmitter. */
-	/* Allow status bits to be seen. */
-	outw(SetStatusEnb | 0xff, ioaddr + EL3_CMD);
-	/* Ack all pending events, and set active indicator mask. */
-	outw(AckIntr | IntLatch | TxAvailable | RxEarly | IntReq,
-		 ioaddr + EL3_CMD);
-	outw(SetIntrEnb | IntLatch | TxAvailable | RxComplete | StatsFull
-		 | AdapterFailure | RxEarly, ioaddr + EL3_CMD);
-}
-
-static int el3_open(struct net_device *dev)
-{
-	struct el3_private *lp = netdev_priv(dev);
-	struct pcmcia_device *link = lp->p_dev;
-
-	if (!pcmcia_dev_present(link))
-		return -ENODEV;
-	
-	link->open++;
-	netif_start_queue(dev);
-	
-	tc574_reset(dev);
-	lp->media.expires = jiffies + HZ;
-	add_timer(&lp->media);
-	
-	dev_dbg(&link->dev, "%s: opened, status %4.4x.\n",
-		  dev->name, inw(dev->base_addr + EL3_STATUS));
-	
-	return 0;
-}
-
-static void el3_tx_timeout(struct net_device *dev, unsigned int txqueue)
-{
-	unsigned int ioaddr = dev->base_addr;
-	
-	netdev_notice(dev, "Transmit timed out!\n");
-	dump_status(dev);
-	dev->stats.tx_errors++;
-	netif_trans_update(dev); /* prevent tx timeout */
-	/* Issue TX_RESET and TX_START commands. */
-	tc574_wait_for_completion(dev, TxReset);
-	outw(TxEnable, ioaddr + EL3_CMD);
-	netif_wake_queue(dev);
-}
-
-static void pop_tx_status(struct net_device *dev)
-{
-	unsigned int ioaddr = dev->base_addr;
-	int i;
-    
-	/* Clear the Tx status stack. */
-	for (i = 32; i > 0; i--) {
-		u_char tx_status = inb(ioaddr + TxStatus);
-		if (!(tx_status & 0x84))
-			break;
-		/* reset transmitter on jabber error or underrun */
-		if (tx_status & 0x30)
-			tc574_wait_for_completion(dev, TxReset);
-		if (tx_status & 0x38) {
-			pr_debug("%s: transmit error: status 0x%02x\n",
-				  dev->name, tx_status);
-			outw(TxEnable, ioaddr + EL3_CMD);
-			dev->stats.tx_aborted_errors++;
-		}
-		outb(0x00, ioaddr + TxStatus); /* Pop the status stack. */
-	}
-}
-
-static netdev_tx_t el3_start_xmit(struct sk_buff *skb,
-					struct net_device *dev)
-{
-	unsigned int ioaddr = dev->base_addr;
-	struct el3_private *lp = netdev_priv(dev);
-	unsigned long flags;
-
-	pr_debug("%s: el3_start_xmit(length = %ld) called, "
-		  "status %4.4x.\n", dev->name, (long)skb->len,
-		  inw(ioaddr + EL3_STATUS));
-
-	spin_lock_irqsave(&lp->window_lock, flags);
-
-	dev->stats.tx_bytes += skb->len;
-
-	/* Put out the doubleword header... */
-	outw(skb->len, ioaddr + TX_FIFO);
-	outw(0, ioaddr + TX_FIFO);
-	/* ... and the packet rounded to a doubleword. */
-	outsl(ioaddr + TX_FIFO, skb->data, (skb->len+3)>>2);
-
-	/* TxFree appears only in Window 1, not offset 0x1c. */
-	if (inw(ioaddr + TxFree) <= 1536) {
-		netif_stop_queue(dev);
-		/* Interrupt us when the FIFO has room for max-sized packet. 
-		   The threshold is in units of dwords. */
-		outw(SetTxThreshold + (1536>>2), ioaddr + EL3_CMD);
-	}
-
-	pop_tx_status(dev);
-	spin_unlock_irqrestore(&lp->window_lock, flags);
-	dev_kfree_skb(skb);
-	return NETDEV_TX_OK;
-}
-
-/* The EL3 interrupt handler. */
-static irqreturn_t el3_interrupt(int irq, void *dev_id)
-{
-	struct net_device *dev = (struct net_device *) dev_id;
-	struct el3_private *lp = netdev_priv(dev);
-	unsigned int ioaddr;
-	unsigned status;
-	int work_budget = max_interrupt_work;
-	int handled = 0;
-
-	if (!netif_device_present(dev))
-		return IRQ_NONE;
-	ioaddr = dev->base_addr;
-
-	pr_debug("%s: interrupt, status %4.4x.\n",
-		  dev->name, inw(ioaddr + EL3_STATUS));
-
-	spin_lock(&lp->window_lock);
-	
-	while ((status = inw(ioaddr + EL3_STATUS)) &
-		   (IntLatch | RxComplete | RxEarly | StatsFull)) {
-		if (!netif_device_present(dev) ||
-			((status & 0xe000) != 0x2000)) {
-			pr_debug("%s: Interrupt from dead card\n", dev->name);
-			break;
-		}
-
-		handled = 1;
-
-		if (status & RxComplete)
-			work_budget = el3_rx(dev, work_budget);
-
-		if (status & TxAvailable) {
-			pr_debug("  TX room bit was handled.\n");
-			/* There's room in the FIFO for a full-sized packet. */
-			outw(AckIntr | TxAvailable, ioaddr + EL3_CMD);
-			netif_wake_queue(dev);
-		}
-
-		if (status & TxComplete)
-			pop_tx_status(dev);
-
-		if (status & (AdapterFailure | RxEarly | StatsFull)) {
-			/* Handle all uncommon interrupts. */
-			if (status & StatsFull)
-				update_stats(dev);
-			if (status & RxEarly) {
-				work_budget = el3_rx(dev, work_budget);
-				outw(AckIntr | RxEarly, ioaddr + EL3_CMD);
-			}
-			if (status & AdapterFailure) {
-				u16 fifo_diag;
-				EL3WINDOW(4);
-				fifo_diag = inw(ioaddr + Wn4_FIFODiag);
-				EL3WINDOW(1);
-				netdev_notice(dev, "adapter failure, FIFO diagnostic register %04x\n",
-					      fifo_diag);
-				if (fifo_diag & 0x0400) {
-					/* Tx overrun */
-					tc574_wait_for_completion(dev, TxReset);
-					outw(TxEnable, ioaddr + EL3_CMD);
-				}
-				if (fifo_diag & 0x2000) {
-					/* Rx underrun */
-					tc574_wait_for_completion(dev, RxReset);
-					set_rx_mode(dev);
-					outw(RxEnable, ioaddr + EL3_CMD);
-				}
-				outw(AckIntr | AdapterFailure, ioaddr + EL3_CMD);
-			}
-		}
-
-		if (--work_budget < 0) {
-			pr_debug("%s: Too much work in interrupt, "
-				  "status %4.4x.\n", dev->name, status);
-			/* Clear all interrupts */
-			outw(AckIntr | 0xFF, ioaddr + EL3_CMD);
-			break;
-		}
-		/* Acknowledge the IRQ. */
-		outw(AckIntr | IntReq | IntLatch, ioaddr + EL3_CMD);
-	}
-
-	pr_debug("%s: exiting interrupt, status %4.4x.\n",
-		  dev->name, inw(ioaddr + EL3_STATUS));
-		  
-	spin_unlock(&lp->window_lock);
-	return IRQ_RETVAL(handled);
-}
-
-/*
-    This timer serves two purposes: to check for missed interrupts
-	(and as a last resort, poll the NIC for events), and to monitor
-	the MII, reporting changes in cable status.
-*/
-static void media_check(struct timer_list *t)
-{
-	struct el3_private *lp = timer_container_of(lp, t, media);
-	struct net_device *dev = lp->p_dev->priv;
-	unsigned int ioaddr = dev->base_addr;
-	unsigned long flags;
-	unsigned short /* cable, */ media, partner;
-
-	if (!netif_device_present(dev))
-		goto reschedule;
-	
-	/* Check for pending interrupt with expired latency timer: with
-	   this, we can limp along even if the interrupt is blocked */
-	if ((inw(ioaddr + EL3_STATUS) & IntLatch) && (inb(ioaddr + Timer) == 0xff)) {
-		if (!lp->fast_poll)
-			netdev_info(dev, "interrupt(s) dropped!\n");
-
-		local_irq_save(flags);
-		el3_interrupt(dev->irq, dev);
-		local_irq_restore(flags);
-
-		lp->fast_poll = HZ;
-	}
-	if (lp->fast_poll) {
-		lp->fast_poll--;
-		lp->media.expires = jiffies + 2*HZ/100;
-		add_timer(&lp->media);
-		return;
-	}
-
-	spin_lock_irqsave(&lp->window_lock, flags);
-	EL3WINDOW(4);
-	media = mdio_read(ioaddr, lp->phys, 1);
-	partner = mdio_read(ioaddr, lp->phys, 5);
-	EL3WINDOW(1);
-	
-	if (media != lp->media_status) {
-		if ((media ^ lp->media_status) & 0x0004)
-			netdev_info(dev, "%s link beat\n",
-				    (lp->media_status & 0x0004) ? "lost" : "found");
-		if ((media ^ lp->media_status) & 0x0020) {
-			lp->partner = 0;
-			if (lp->media_status & 0x0020) {
-				netdev_info(dev, "autonegotiation restarted\n");
-			} else if (partner) {
-				partner &= lp->advertising;
-				lp->partner = partner;
-				netdev_info(dev, "autonegotiation complete: "
-					    "%dbaseT-%cD selected\n",
-					    (partner & 0x0180) ? 100 : 10,
-					    (partner & 0x0140) ? 'F' : 'H');
-			} else {
-				netdev_info(dev, "link partner did not autonegotiate\n");
-			}
-
-			EL3WINDOW(3);
-			outb((partner & 0x0140 ? 0x20 : 0) |
-				 (dev->mtu > 1500 ? 0x40 : 0), ioaddr + Wn3_MAC_Ctrl);
-			EL3WINDOW(1);
-
-		}
-		if (media & 0x0010)
-			netdev_info(dev, "remote fault detected\n");
-		if (media & 0x0002)
-			netdev_info(dev, "jabber detected\n");
-		lp->media_status = media;
-	}
-	spin_unlock_irqrestore(&lp->window_lock, flags);
-
-reschedule:
-	lp->media.expires = jiffies + HZ;
-	add_timer(&lp->media);
-}
-
-static struct net_device_stats *el3_get_stats(struct net_device *dev)
-{
-	struct el3_private *lp = netdev_priv(dev);
-
-	if (netif_device_present(dev)) {
-		unsigned long flags;
-		spin_lock_irqsave(&lp->window_lock, flags);
-		update_stats(dev);
-		spin_unlock_irqrestore(&lp->window_lock, flags);
-	}
-	return &dev->stats;
-}
-
-/*  Update statistics.
-	Surprisingly this need not be run single-threaded, but it effectively is.
-	The counters clear when read, so the adds must merely be atomic.
- */
-static void update_stats(struct net_device *dev)
-{
-	unsigned int ioaddr = dev->base_addr;
-	u8 up;
-
-	pr_debug("%s: updating the statistics.\n", dev->name);
-
-	if (inw(ioaddr+EL3_STATUS) == 0xffff) /* No card. */
-		return;
-		
-	/* Unlike the 3c509 we need not turn off stats updates while reading. */
-	/* Switch to the stats window, and read everything. */
-	EL3WINDOW(6);
-	dev->stats.tx_carrier_errors 		+= inb(ioaddr + 0);
-	dev->stats.tx_heartbeat_errors		+= inb(ioaddr + 1);
-	/* Multiple collisions. */	   	inb(ioaddr + 2);
-	dev->stats.collisions			+= inb(ioaddr + 3);
-	dev->stats.tx_window_errors		+= inb(ioaddr + 4);
-	dev->stats.rx_fifo_errors		+= inb(ioaddr + 5);
-	dev->stats.tx_packets			+= inb(ioaddr + 6);
-	up		 			 = inb(ioaddr + 9);
-	dev->stats.tx_packets			+= (up&0x30) << 4;
-	/* Rx packets   */			   inb(ioaddr + 7);
-	/* Tx deferrals */			   inb(ioaddr + 8);
-	/* rx */				   inw(ioaddr + 10);
-	/* tx */				   inw(ioaddr + 12);
-
-	EL3WINDOW(4);
-	/* BadSSD */				   inb(ioaddr + 12);
-	up					 = inb(ioaddr + 13);
-
-	EL3WINDOW(1);
-}
-
-static int el3_rx(struct net_device *dev, int worklimit)
-{
-	unsigned int ioaddr = dev->base_addr;
-	short rx_status;
-	
-	pr_debug("%s: in rx_packet(), status %4.4x, rx_status %4.4x.\n",
-		  dev->name, inw(ioaddr+EL3_STATUS), inw(ioaddr+RxStatus));
-	while (!((rx_status = inw(ioaddr + RxStatus)) & 0x8000) &&
-			worklimit > 0) {
-		worklimit--;
-		if (rx_status & 0x4000) { /* Error, update stats. */
-			short error = rx_status & 0x3800;
-			dev->stats.rx_errors++;
-			switch (error) {
-			case 0x0000:	dev->stats.rx_over_errors++; break;
-			case 0x0800:	dev->stats.rx_length_errors++; break;
-			case 0x1000:	dev->stats.rx_frame_errors++; break;
-			case 0x1800:	dev->stats.rx_length_errors++; break;
-			case 0x2000:	dev->stats.rx_frame_errors++; break;
-			case 0x2800:	dev->stats.rx_crc_errors++; break;
-			}
-		} else {
-			short pkt_len = rx_status & 0x7ff;
-			struct sk_buff *skb;
-
-			skb = netdev_alloc_skb(dev, pkt_len + 5);
-
-			pr_debug("  Receiving packet size %d status %4.4x.\n",
-				  pkt_len, rx_status);
-			if (skb != NULL) {
-				skb_reserve(skb, 2);
-				insl(ioaddr+RX_FIFO, skb_put(skb, pkt_len),
-						((pkt_len+3)>>2));
-				skb->protocol = eth_type_trans(skb, dev);
-				netif_rx(skb);
-				dev->stats.rx_packets++;
-				dev->stats.rx_bytes += pkt_len;
-			} else {
-				pr_debug("%s: couldn't allocate a sk_buff of"
-					  " size %d.\n", dev->name, pkt_len);
-				dev->stats.rx_dropped++;
-			}
-		}
-		tc574_wait_for_completion(dev, RxDiscard);
-	}
-
-	return worklimit;
-}
-
-/* Provide ioctl() calls to examine the MII xcvr state. */
-static int el3_ioctl(struct net_device *dev, struct ifreq *rq, int cmd)
-{
-	struct el3_private *lp = netdev_priv(dev);
-	unsigned int ioaddr = dev->base_addr;
-	struct mii_ioctl_data *data = if_mii(rq);
-	int phy = lp->phys & 0x1f;
-
-	pr_debug("%s: In ioct(%-.6s, %#4.4x) %4.4x %4.4x %4.4x %4.4x.\n",
-		  dev->name, rq->ifr_ifrn.ifrn_name, cmd,
-		  data->phy_id, data->reg_num, data->val_in, data->val_out);
-
-	switch(cmd) {
-	case SIOCGMIIPHY:		/* Get the address of the PHY in use. */
-		data->phy_id = phy;
-		fallthrough;
-	case SIOCGMIIREG:		/* Read the specified MII register. */
-		{
-			int saved_window;
-			unsigned long flags;
-
-			spin_lock_irqsave(&lp->window_lock, flags);
-			saved_window = inw(ioaddr + EL3_CMD) >> 13;
-			EL3WINDOW(4);
-			data->val_out = mdio_read(ioaddr, data->phy_id & 0x1f,
-						  data->reg_num & 0x1f);
-			EL3WINDOW(saved_window);
-			spin_unlock_irqrestore(&lp->window_lock, flags);
-			return 0;
-		}
-	case SIOCSMIIREG:		/* Write the specified MII register */
-		{
-			int saved_window;
-                       unsigned long flags;
-
-			spin_lock_irqsave(&lp->window_lock, flags);
-			saved_window = inw(ioaddr + EL3_CMD) >> 13;
-			EL3WINDOW(4);
-			mdio_write(ioaddr, data->phy_id & 0x1f,
-				   data->reg_num & 0x1f, data->val_in);
-			EL3WINDOW(saved_window);
-			spin_unlock_irqrestore(&lp->window_lock, flags);
-			return 0;
-		}
-	default:
-		return -EOPNOTSUPP;
-	}
-}
-
-/* The Odie chip has a 64 bin multicast filter, but the bit layout is not
-   documented.  Until it is we revert to receiving all multicast frames when
-   any multicast reception is desired.
-   Note: My other drivers emit a log message whenever promiscuous mode is
-   entered to help detect password sniffers.  This is less desirable on
-   typical PC card machines, so we omit the message.
-   */
-
-static void set_rx_mode(struct net_device *dev)
-{
-	unsigned int ioaddr = dev->base_addr;
-
-	if (dev->flags & IFF_PROMISC)
-		outw(SetRxFilter | RxStation | RxMulticast | RxBroadcast | RxProm,
-			 ioaddr + EL3_CMD);
-	else if (!netdev_mc_empty(dev) || (dev->flags & IFF_ALLMULTI))
-		outw(SetRxFilter|RxStation|RxMulticast|RxBroadcast, ioaddr + EL3_CMD);
-	else
-		outw(SetRxFilter | RxStation | RxBroadcast, ioaddr + EL3_CMD);
-}
-
-static void set_multicast_list(struct net_device *dev)
-{
-	struct el3_private *lp = netdev_priv(dev);
-	unsigned long flags;
-
-	spin_lock_irqsave(&lp->window_lock, flags);
-	set_rx_mode(dev);
-	spin_unlock_irqrestore(&lp->window_lock, flags);
-}
-
-static int el3_close(struct net_device *dev)
-{
-	unsigned int ioaddr = dev->base_addr;
-	struct el3_private *lp = netdev_priv(dev);
-	struct pcmcia_device *link = lp->p_dev;
-
-	dev_dbg(&link->dev, "%s: shutting down ethercard.\n", dev->name);
-	
-	if (pcmcia_dev_present(link)) {
-		unsigned long flags;
-
-		/* Turn off statistics ASAP.  We update lp->stats below. */
-		outw(StatsDisable, ioaddr + EL3_CMD);
-		
-		/* Disable the receiver and transmitter. */
-		outw(RxDisable, ioaddr + EL3_CMD);
-		outw(TxDisable, ioaddr + EL3_CMD);
-		
-		/* Note: Switching to window 0 may disable the IRQ. */
-		EL3WINDOW(0);
-		spin_lock_irqsave(&lp->window_lock, flags);
-		update_stats(dev);
-		spin_unlock_irqrestore(&lp->window_lock, flags);
-
-		/* force interrupts off */
-		outw(SetIntrEnb | 0x0000, ioaddr + EL3_CMD);
-	}
-
-	link->open--;
-	netif_stop_queue(dev);
-	timer_delete_sync(&lp->media);
-
-	return 0;
-}
-
-static const struct pcmcia_device_id tc574_ids[] = {
-	PCMCIA_DEVICE_MANF_CARD(0x0101, 0x0574),
-	PCMCIA_MFC_DEVICE_CIS_MANF_CARD(0, 0x0101, 0x0556, "cis/3CCFEM556.cis"),
-	PCMCIA_DEVICE_NULL,
-};
-MODULE_DEVICE_TABLE(pcmcia, tc574_ids);
-
-static struct pcmcia_driver tc574_driver = {
-	.owner		= THIS_MODULE,
-	.name		= "3c574_cs",
-	.probe		= tc574_probe,
-	.remove		= tc574_detach,
-	.id_table       = tc574_ids,
-	.suspend	= tc574_suspend,
-	.resume		= tc574_resume,
-};
-module_pcmcia_driver(tc574_driver);
diff --git a/drivers/net/ethernet/3com/Kconfig b/drivers/net/ethernet/3com/Kconfig
index 3fd3202d9776..294403ad7141 100644
--- a/drivers/net/ethernet/3com/Kconfig
+++ b/drivers/net/ethernet/3com/Kconfig
@@ -17,16 +17,6 @@ config NET_VENDOR_3COM
 
 if NET_VENDOR_3COM
 
-config PCMCIA_3C574
-	tristate "3Com 3c574 PCMCIA support"
-	depends on PCMCIA && HAS_IOPORT
-	help
-	  Say Y here if you intend to attach a 3Com 3c574 or compatible PCMCIA
-	  (PC-card) Fast Ethernet card to your computer.
-
-	  To compile this driver as a module, choose M here: the module will be
-	  called 3c574_cs.  If unsure, say N.
-
 config PCMCIA_3C589
 	tristate "3Com 3c589 PCMCIA support"
 	depends on PCMCIA && HAS_IOPORT
diff --git a/drivers/net/ethernet/3com/Makefile b/drivers/net/ethernet/3com/Makefile
index babfd93d5d53..45fb9af9b5c7 100644
--- a/drivers/net/ethernet/3com/Makefile
+++ b/drivers/net/ethernet/3com/Makefile
@@ -4,6 +4,5 @@
 #
 
 obj-$(CONFIG_PCMCIA_3C589) += 3c589_cs.o
-obj-$(CONFIG_PCMCIA_3C574) += 3c574_cs.o
 obj-$(CONFIG_VORTEX) += 3c59x.o
 obj-$(CONFIG_TYPHOON) += typhoon.o

-- 
2.53.0


^ permalink raw reply related	[flat|nested] 28+ messages in thread

* [PATCH net 04/18] drivers: net: 3com: 3c589: Remove this driver
  2026-04-21 19:31 [PATCH net 00/18] Remove a number of ISA and PCMCIA Ethernet drivers Andrew Lunn
                   ` (2 preceding siblings ...)
  2026-04-21 19:31 ` [PATCH net 03/18] drivers: net: 3com: 3c574: " Andrew Lunn
@ 2026-04-21 19:31 ` Andrew Lunn
  2026-04-21 19:31 ` [PATCH net 05/18] drivers: net: 3com: 3c59x: " Andrew Lunn
                   ` (17 subsequent siblings)
  21 siblings, 0 replies; 28+ messages in thread
From: Andrew Lunn @ 2026-04-21 19:31 UTC (permalink / raw)
  To: Andrew Lunn, David S. Miller, Eric Dumazet, Jakub Kicinski,
	Paolo Abeni, Simon Horman, Jonathan Corbet, Shuah Khan
  Cc: linux-kernel, netdev, linux-doc, Andrew Lunn

The 3c589 was written by David A. Hinds 2001. It is an PCMCIA device,
so unlikely to be used with modern kernels.

Signed-off-by: Andrew Lunn <andrew@lunn.ch>
---
 drivers/net/ethernet/3com/3c589_cs.c | 974 -----------------------------------
 drivers/net/ethernet/3com/Kconfig    |  10 -
 drivers/net/ethernet/3com/Makefile   |   1 -
 3 files changed, 985 deletions(-)

diff --git a/drivers/net/ethernet/3com/3c589_cs.c b/drivers/net/ethernet/3com/3c589_cs.c
deleted file mode 100644
index ea49be43b8c3..000000000000
--- a/drivers/net/ethernet/3com/3c589_cs.c
+++ /dev/null
@@ -1,974 +0,0 @@
-/* ======================================================================
- *
- * A PCMCIA ethernet driver for the 3com 3c589 card.
- *
- * Copyright (C) 1999 David A. Hinds -- dahinds@users.sourceforge.net
- *
- * 3c589_cs.c 1.162 2001/10/13 00:08:50
- *
- * The network driver code is based on Donald Becker's 3c589 code:
- *
- * Written 1994 by Donald Becker.
- * Copyright 1993 United States Government as represented by the
- * Director, National Security Agency.  This software may be used and
- * distributed according to the terms of the GNU General Public License,
- * incorporated herein by reference.
- * Donald Becker may be reached at becker@scyld.com
- *
- * Updated for 2.5.x by Alan Cox <alan@lxorguk.ukuu.org.uk>
- *
- * ======================================================================
- */
-
-#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
-
-#define DRV_NAME	"3c589_cs"
-
-#include <linux/module.h>
-#include <linux/kernel.h>
-#include <linux/ptrace.h>
-#include <linux/slab.h>
-#include <linux/string.h>
-#include <linux/timer.h>
-#include <linux/interrupt.h>
-#include <linux/in.h>
-#include <linux/delay.h>
-#include <linux/ethtool.h>
-#include <linux/netdevice.h>
-#include <linux/etherdevice.h>
-#include <linux/skbuff.h>
-#include <linux/if_arp.h>
-#include <linux/ioport.h>
-#include <linux/bitops.h>
-#include <linux/jiffies.h>
-#include <linux/uaccess.h>
-#include <linux/io.h>
-
-#include <pcmcia/cistpl.h>
-#include <pcmcia/cisreg.h>
-#include <pcmcia/ciscode.h>
-#include <pcmcia/ds.h>
-
-
-/* To minimize the size of the driver source I only define operating
- * constants if they are used several times. You'll need the manual
- * if you want to understand driver details.
- */
-
-/* Offsets from base I/O address. */
-#define EL3_DATA	0x00
-#define EL3_TIMER	0x0a
-#define EL3_CMD		0x0e
-#define EL3_STATUS	0x0e
-
-#define EEPROM_READ	0x0080
-#define EEPROM_BUSY	0x8000
-
-#define EL3WINDOW(win_num) outw(SelectWindow + (win_num), ioaddr + EL3_CMD)
-
-/* The top five bits written to EL3_CMD are a command, the lower
- * 11 bits are the parameter, if applicable.
- */
-
-enum c509cmd {
-	TotalReset	= 0<<11,
-	SelectWindow	= 1<<11,
-	StartCoax	= 2<<11,
-	RxDisable	= 3<<11,
-	RxEnable	= 4<<11,
-	RxReset		= 5<<11,
-	RxDiscard	= 8<<11,
-	TxEnable	= 9<<11,
-	TxDisable	= 10<<11,
-	TxReset		= 11<<11,
-	FakeIntr	= 12<<11,
-	AckIntr		= 13<<11,
-	SetIntrEnb	= 14<<11,
-	SetStatusEnb	= 15<<11,
-	SetRxFilter	= 16<<11,
-	SetRxThreshold	= 17<<11,
-	SetTxThreshold	= 18<<11,
-	SetTxStart	= 19<<11,
-	StatsEnable	= 21<<11,
-	StatsDisable	= 22<<11,
-	StopCoax	= 23<<11
-};
-
-enum c509status {
-	IntLatch	= 0x0001,
-	AdapterFailure	= 0x0002,
-	TxComplete	= 0x0004,
-	TxAvailable	= 0x0008,
-	RxComplete	= 0x0010,
-	RxEarly		= 0x0020,
-	IntReq		= 0x0040,
-	StatsFull	= 0x0080,
-	CmdBusy		= 0x1000
-};
-
-/* The SetRxFilter command accepts the following classes: */
-enum RxFilter {
-	RxStation	= 1,
-	RxMulticast	= 2,
-	RxBroadcast	= 4,
-	RxProm		= 8
-};
-
-/* Register window 1 offsets, the window used in normal operation. */
-#define TX_FIFO		0x00
-#define RX_FIFO		0x00
-#define RX_STATUS	0x08
-#define TX_STATUS	0x0B
-#define TX_FREE		0x0C	/* Remaining free bytes in Tx buffer. */
-
-#define WN0_IRQ		0x08	/* Window 0: Set IRQ line in bits 12-15. */
-#define WN4_MEDIA	0x0A	/* Window 4: Various transcvr/media bits. */
-#define MEDIA_TP	0x00C0	/* Enable link beat and jabber for 10baseT. */
-#define MEDIA_LED	0x0001	/* Enable link light on 3C589E cards. */
-
-/* Time in jiffies before concluding Tx hung */
-#define TX_TIMEOUT	((400*HZ)/1000)
-
-struct el3_private {
-	struct pcmcia_device	*p_dev;
-	/* For transceiver monitoring */
-	struct timer_list	media;
-	u16			media_status;
-	u16			fast_poll;
-	unsigned long		last_irq;
-	spinlock_t		lock;
-};
-
-static const char *if_names[] = { "auto", "10baseT", "10base2", "AUI" };
-
-/*====================================================================*/
-
-/* Module parameters */
-
-MODULE_AUTHOR("David Hinds <dahinds@users.sourceforge.net>");
-MODULE_DESCRIPTION("3Com 3c589 series PCMCIA ethernet driver");
-MODULE_LICENSE("GPL");
-
-#define INT_MODULE_PARM(n, v) static int n = v; module_param(n, int, 0)
-
-/* Special hook for setting if_port when module is loaded */
-INT_MODULE_PARM(if_port, 0);
-
-
-/*====================================================================*/
-
-static int tc589_config(struct pcmcia_device *link);
-static void tc589_release(struct pcmcia_device *link);
-
-static u16 read_eeprom(unsigned int ioaddr, int index);
-static void tc589_reset(struct net_device *dev);
-static void media_check(struct timer_list *t);
-static int el3_config(struct net_device *dev, struct ifmap *map);
-static int el3_open(struct net_device *dev);
-static netdev_tx_t el3_start_xmit(struct sk_buff *skb,
-					struct net_device *dev);
-static irqreturn_t el3_interrupt(int irq, void *dev_id);
-static void update_stats(struct net_device *dev);
-static struct net_device_stats *el3_get_stats(struct net_device *dev);
-static int el3_rx(struct net_device *dev);
-static int el3_close(struct net_device *dev);
-static void el3_tx_timeout(struct net_device *dev, unsigned int txqueue);
-static void set_rx_mode(struct net_device *dev);
-static void set_multicast_list(struct net_device *dev);
-static const struct ethtool_ops netdev_ethtool_ops;
-
-static void tc589_detach(struct pcmcia_device *p_dev);
-
-static const struct net_device_ops el3_netdev_ops = {
-	.ndo_open		= el3_open,
-	.ndo_stop		= el3_close,
-	.ndo_start_xmit		= el3_start_xmit,
-	.ndo_tx_timeout		= el3_tx_timeout,
-	.ndo_set_config		= el3_config,
-	.ndo_get_stats		= el3_get_stats,
-	.ndo_set_rx_mode	= set_multicast_list,
-	.ndo_set_mac_address	= eth_mac_addr,
-	.ndo_validate_addr	= eth_validate_addr,
-};
-
-static int tc589_probe(struct pcmcia_device *link)
-{
-	struct el3_private *lp;
-	struct net_device *dev;
-	int ret;
-
-	dev_dbg(&link->dev, "3c589_attach()\n");
-
-	/* Create new ethernet device */
-	dev = alloc_etherdev(sizeof(struct el3_private));
-	if (!dev)
-		return -ENOMEM;
-	lp = netdev_priv(dev);
-	link->priv = dev;
-	lp->p_dev = link;
-
-	spin_lock_init(&lp->lock);
-	link->resource[0]->end = 16;
-	link->resource[0]->flags |= IO_DATA_PATH_WIDTH_16;
-
-	link->config_flags |= CONF_ENABLE_IRQ;
-	link->config_index = 1;
-
-	dev->netdev_ops = &el3_netdev_ops;
-	dev->watchdog_timeo = TX_TIMEOUT;
-
-	dev->ethtool_ops = &netdev_ethtool_ops;
-
-	ret = tc589_config(link);
-	if (ret)
-		goto err_free_netdev;
-
-	return 0;
-
-err_free_netdev:
-	free_netdev(dev);
-	return ret;
-}
-
-static void tc589_detach(struct pcmcia_device *link)
-{
-	struct net_device *dev = link->priv;
-
-	dev_dbg(&link->dev, "3c589_detach\n");
-
-	unregister_netdev(dev);
-
-	tc589_release(link);
-
-	free_netdev(dev);
-} /* tc589_detach */
-
-static int tc589_config(struct pcmcia_device *link)
-{
-	struct net_device *dev = link->priv;
-	int ret, i, j, multi = 0, fifo;
-	__be16 addr[ETH_ALEN / 2];
-	unsigned int ioaddr;
-	static const char * const ram_split[] = {"5:3", "3:1", "1:1", "3:5"};
-	u8 *buf;
-	size_t len;
-
-	dev_dbg(&link->dev, "3c589_config\n");
-
-	/* Is this a 3c562? */
-	if (link->manf_id != MANFID_3COM)
-		dev_info(&link->dev, "hmmm, is this really a 3Com card??\n");
-	multi = (link->card_id == PRODID_3COM_3C562);
-
-	link->io_lines = 16;
-
-	/* For the 3c562, the base address must be xx00-xx7f */
-	for (i = j = 0; j < 0x400; j += 0x10) {
-		if (multi && (j & 0x80))
-			continue;
-		link->resource[0]->start = j ^ 0x300;
-		i = pcmcia_request_io(link);
-		if (i == 0)
-			break;
-	}
-	if (i != 0)
-		goto failed;
-
-	ret = pcmcia_request_irq(link, el3_interrupt);
-	if (ret)
-		goto failed;
-
-	ret = pcmcia_enable_device(link);
-	if (ret)
-		goto failed;
-
-	dev->irq = link->irq;
-	dev->base_addr = link->resource[0]->start;
-	ioaddr = dev->base_addr;
-	EL3WINDOW(0);
-
-	/* The 3c589 has an extra EEPROM for configuration info, including
-	 * the hardware address.  The 3c562 puts the address in the CIS.
-	 */
-	len = pcmcia_get_tuple(link, 0x88, &buf);
-	if (buf && len >= 6) {
-		for (i = 0; i < 3; i++)
-			addr[i] = htons(le16_to_cpu(buf[i*2]));
-		kfree(buf);
-	} else {
-		kfree(buf); /* 0 < len < 6 */
-		for (i = 0; i < 3; i++)
-			addr[i] = htons(read_eeprom(ioaddr, i));
-		if (addr[0] == htons(0x6060)) {
-			dev_err(&link->dev, "IO port conflict at 0x%03lx-0x%03lx\n",
-					dev->base_addr, dev->base_addr+15);
-			goto failed;
-		}
-	}
-	eth_hw_addr_set(dev, (u8 *)addr);
-
-	/* The address and resource configuration register aren't loaded from
-	 * the EEPROM and *must* be set to 0 and IRQ3 for the PCMCIA version.
-	 */
-
-	outw(0x3f00, ioaddr + 8);
-	fifo = inl(ioaddr);
-
-	/* The if_port symbol can be set when the module is loaded */
-	if ((if_port >= 0) && (if_port <= 3))
-		dev->if_port = if_port;
-	else
-		dev_err(&link->dev, "invalid if_port requested\n");
-
-	SET_NETDEV_DEV(dev, &link->dev);
-
-	if (register_netdev(dev) != 0) {
-		dev_err(&link->dev, "register_netdev() failed\n");
-		goto failed;
-	}
-
-	netdev_info(dev, "3Com 3c%s, io %#3lx, irq %d, hw_addr %pM\n",
-			(multi ? "562" : "589"), dev->base_addr, dev->irq,
-			dev->dev_addr);
-	netdev_info(dev, "  %dK FIFO split %s Rx:Tx, %s xcvr\n",
-			(fifo & 7) ? 32 : 8, ram_split[(fifo >> 16) & 3],
-			if_names[dev->if_port]);
-	return 0;
-
-failed:
-	tc589_release(link);
-	return -ENODEV;
-} /* tc589_config */
-
-static void tc589_release(struct pcmcia_device *link)
-{
-	pcmcia_disable_device(link);
-}
-
-static int tc589_suspend(struct pcmcia_device *link)
-{
-	struct net_device *dev = link->priv;
-
-	if (link->open)
-		netif_device_detach(dev);
-
-	return 0;
-}
-
-static int tc589_resume(struct pcmcia_device *link)
-{
-	struct net_device *dev = link->priv;
-
-	if (link->open) {
-		tc589_reset(dev);
-		netif_device_attach(dev);
-	}
-
-	return 0;
-}
-
-/*====================================================================*/
-
-/* Use this for commands that may take time to finish */
-
-static void tc589_wait_for_completion(struct net_device *dev, int cmd)
-{
-	int i = 100;
-	outw(cmd, dev->base_addr + EL3_CMD);
-	while (--i > 0)
-		if (!(inw(dev->base_addr + EL3_STATUS) & 0x1000))
-			break;
-	if (i == 0)
-		netdev_warn(dev, "command 0x%04x did not complete!\n", cmd);
-}
-
-/* Read a word from the EEPROM using the regular EEPROM access register.
- * Assume that we are in register window zero.
- */
-
-static u16 read_eeprom(unsigned int ioaddr, int index)
-{
-	int i;
-	outw(EEPROM_READ + index, ioaddr + 10);
-	/* Reading the eeprom takes 162 us */
-	for (i = 1620; i >= 0; i--)
-		if ((inw(ioaddr + 10) & EEPROM_BUSY) == 0)
-			break;
-	return inw(ioaddr + 12);
-}
-
-/* Set transceiver type, perhaps to something other than what the user
- * specified in dev->if_port.
- */
-
-static void tc589_set_xcvr(struct net_device *dev, int if_port)
-{
-	struct el3_private *lp = netdev_priv(dev);
-	unsigned int ioaddr = dev->base_addr;
-
-	EL3WINDOW(0);
-	switch (if_port) {
-	case 0:
-	case 1:
-		outw(0, ioaddr + 6);
-		break;
-	case 2:
-		outw(3<<14, ioaddr + 6);
-		break;
-	case 3:
-		outw(1<<14, ioaddr + 6);
-		break;
-	}
-	/* On PCMCIA, this just turns on the LED */
-	outw((if_port == 2) ? StartCoax : StopCoax, ioaddr + EL3_CMD);
-	/* 10baseT interface, enable link beat and jabber check. */
-	EL3WINDOW(4);
-	outw(MEDIA_LED | ((if_port < 2) ? MEDIA_TP : 0), ioaddr + WN4_MEDIA);
-	EL3WINDOW(1);
-	if (if_port == 2)
-		lp->media_status = ((dev->if_port == 0) ? 0x8000 : 0x4000);
-	else
-		lp->media_status = ((dev->if_port == 0) ? 0x4010 : 0x8800);
-}
-
-static void dump_status(struct net_device *dev)
-{
-	unsigned int ioaddr = dev->base_addr;
-	EL3WINDOW(1);
-	netdev_info(dev, "  irq status %04x, rx status %04x, tx status %02x  tx free %04x\n",
-			inw(ioaddr+EL3_STATUS), inw(ioaddr+RX_STATUS),
-			inb(ioaddr+TX_STATUS), inw(ioaddr+TX_FREE));
-	EL3WINDOW(4);
-	netdev_info(dev, "  diagnostics: fifo %04x net %04x ethernet %04x media %04x\n",
-			inw(ioaddr+0x04), inw(ioaddr+0x06), inw(ioaddr+0x08),
-			inw(ioaddr+0x0a));
-	EL3WINDOW(1);
-}
-
-/* Reset and restore all of the 3c589 registers. */
-static void tc589_reset(struct net_device *dev)
-{
-	unsigned int ioaddr = dev->base_addr;
-	int i;
-
-	EL3WINDOW(0);
-	outw(0x0001, ioaddr + 4);			/* Activate board. */
-	outw(0x3f00, ioaddr + 8);			/* Set the IRQ line. */
-
-	/* Set the station address in window 2. */
-	EL3WINDOW(2);
-	for (i = 0; i < 6; i++)
-		outb(dev->dev_addr[i], ioaddr + i);
-
-	tc589_set_xcvr(dev, dev->if_port);
-
-	/* Switch to the stats window, and clear all stats by reading. */
-	outw(StatsDisable, ioaddr + EL3_CMD);
-	EL3WINDOW(6);
-	for (i = 0; i < 9; i++)
-		inb(ioaddr+i);
-	inw(ioaddr + 10);
-	inw(ioaddr + 12);
-
-	/* Switch to register set 1 for normal use. */
-	EL3WINDOW(1);
-
-	set_rx_mode(dev);
-	outw(StatsEnable, ioaddr + EL3_CMD); /* Turn on statistics. */
-	outw(RxEnable, ioaddr + EL3_CMD); /* Enable the receiver. */
-	outw(TxEnable, ioaddr + EL3_CMD); /* Enable transmitter. */
-	/* Allow status bits to be seen. */
-	outw(SetStatusEnb | 0xff, ioaddr + EL3_CMD);
-	/* Ack all pending events, and set active indicator mask. */
-	outw(AckIntr | IntLatch | TxAvailable | RxEarly | IntReq,
-	 ioaddr + EL3_CMD);
-	outw(SetIntrEnb | IntLatch | TxAvailable | RxComplete | StatsFull
-	 | AdapterFailure, ioaddr + EL3_CMD);
-}
-
-static void netdev_get_drvinfo(struct net_device *dev,
-			       struct ethtool_drvinfo *info)
-{
-	strscpy(info->driver, DRV_NAME, sizeof(info->driver));
-	snprintf(info->bus_info, sizeof(info->bus_info),
-		"PCMCIA 0x%lx", dev->base_addr);
-}
-
-static const struct ethtool_ops netdev_ethtool_ops = {
-	.get_drvinfo		= netdev_get_drvinfo,
-};
-
-static int el3_config(struct net_device *dev, struct ifmap *map)
-{
-	if ((map->port != (u_char)(-1)) && (map->port != dev->if_port)) {
-		if (map->port <= 3) {
-			WRITE_ONCE(dev->if_port, map->port);
-			netdev_info(dev, "switched to %s port\n", if_names[dev->if_port]);
-			tc589_set_xcvr(dev, dev->if_port);
-		} else {
-			return -EINVAL;
-		}
-	}
-	return 0;
-}
-
-static int el3_open(struct net_device *dev)
-{
-	struct el3_private *lp = netdev_priv(dev);
-	struct pcmcia_device *link = lp->p_dev;
-
-	if (!pcmcia_dev_present(link))
-		return -ENODEV;
-
-	link->open++;
-	netif_start_queue(dev);
-
-	tc589_reset(dev);
-	timer_setup(&lp->media, media_check, 0);
-	mod_timer(&lp->media, jiffies + HZ);
-
-	dev_dbg(&link->dev, "%s: opened, status %4.4x.\n",
-	  dev->name, inw(dev->base_addr + EL3_STATUS));
-
-	return 0;
-}
-
-static void el3_tx_timeout(struct net_device *dev, unsigned int txqueue)
-{
-	unsigned int ioaddr = dev->base_addr;
-
-	netdev_warn(dev, "Transmit timed out!\n");
-	dump_status(dev);
-	dev->stats.tx_errors++;
-	netif_trans_update(dev); /* prevent tx timeout */
-	/* Issue TX_RESET and TX_START commands. */
-	tc589_wait_for_completion(dev, TxReset);
-	outw(TxEnable, ioaddr + EL3_CMD);
-	netif_wake_queue(dev);
-}
-
-static void pop_tx_status(struct net_device *dev)
-{
-	unsigned int ioaddr = dev->base_addr;
-	int i;
-
-	/* Clear the Tx status stack. */
-	for (i = 32; i > 0; i--) {
-		u_char tx_status = inb(ioaddr + TX_STATUS);
-		if (!(tx_status & 0x84))
-			break;
-		/* reset transmitter on jabber error or underrun */
-		if (tx_status & 0x30)
-			tc589_wait_for_completion(dev, TxReset);
-		if (tx_status & 0x38) {
-			netdev_dbg(dev, "transmit error: status 0x%02x\n", tx_status);
-			outw(TxEnable, ioaddr + EL3_CMD);
-			dev->stats.tx_aborted_errors++;
-		}
-		outb(0x00, ioaddr + TX_STATUS); /* Pop the status stack. */
-	}
-}
-
-static netdev_tx_t el3_start_xmit(struct sk_buff *skb,
-					struct net_device *dev)
-{
-	unsigned int ioaddr = dev->base_addr;
-	struct el3_private *priv = netdev_priv(dev);
-	unsigned long flags;
-
-	netdev_dbg(dev, "el3_start_xmit(length = %ld) called, status %4.4x.\n",
-	       (long)skb->len, inw(ioaddr + EL3_STATUS));
-
-	spin_lock_irqsave(&priv->lock, flags);
-
-	dev->stats.tx_bytes += skb->len;
-
-	/* Put out the doubleword header... */
-	outw(skb->len, ioaddr + TX_FIFO);
-	outw(0x00, ioaddr + TX_FIFO);
-	/* ... and the packet rounded to a doubleword. */
-	outsl(ioaddr + TX_FIFO, skb->data, (skb->len + 3) >> 2);
-
-	if (inw(ioaddr + TX_FREE) <= 1536) {
-		netif_stop_queue(dev);
-		/* Interrupt us when the FIFO has room for max-sized packet. */
-		outw(SetTxThreshold + 1536, ioaddr + EL3_CMD);
-	}
-
-	pop_tx_status(dev);
-	spin_unlock_irqrestore(&priv->lock, flags);
-	dev_kfree_skb(skb);
-
-	return NETDEV_TX_OK;
-}
-
-/* The EL3 interrupt handler. */
-static irqreturn_t el3_interrupt(int irq, void *dev_id)
-{
-	struct net_device *dev = (struct net_device *) dev_id;
-	struct el3_private *lp = netdev_priv(dev);
-	unsigned int ioaddr;
-	__u16 status;
-	int i = 0, handled = 1;
-
-	if (!netif_device_present(dev))
-		return IRQ_NONE;
-
-	ioaddr = dev->base_addr;
-
-	netdev_dbg(dev, "interrupt, status %4.4x.\n", inw(ioaddr + EL3_STATUS));
-
-	spin_lock(&lp->lock);
-	while ((status = inw(ioaddr + EL3_STATUS)) &
-	(IntLatch | RxComplete | StatsFull)) {
-		if ((status & 0xe000) != 0x2000) {
-			netdev_dbg(dev, "interrupt from dead card\n");
-			handled = 0;
-			break;
-		}
-		if (status & RxComplete)
-			el3_rx(dev);
-		if (status & TxAvailable) {
-			netdev_dbg(dev, "    TX room bit was handled.\n");
-			/* There's room in the FIFO for a full-sized packet. */
-			outw(AckIntr | TxAvailable, ioaddr + EL3_CMD);
-			netif_wake_queue(dev);
-		}
-		if (status & TxComplete)
-			pop_tx_status(dev);
-		if (status & (AdapterFailure | RxEarly | StatsFull)) {
-			/* Handle all uncommon interrupts. */
-			if (status & StatsFull)		/* Empty statistics. */
-				update_stats(dev);
-			if (status & RxEarly) {
-				/* Rx early is unused. */
-				el3_rx(dev);
-				outw(AckIntr | RxEarly, ioaddr + EL3_CMD);
-			}
-			if (status & AdapterFailure) {
-				u16 fifo_diag;
-				EL3WINDOW(4);
-				fifo_diag = inw(ioaddr + 4);
-				EL3WINDOW(1);
-				netdev_warn(dev, "adapter failure, FIFO diagnostic register %04x.\n",
-			    fifo_diag);
-				if (fifo_diag & 0x0400) {
-					/* Tx overrun */
-					tc589_wait_for_completion(dev, TxReset);
-					outw(TxEnable, ioaddr + EL3_CMD);
-				}
-				if (fifo_diag & 0x2000) {
-					/* Rx underrun */
-					tc589_wait_for_completion(dev, RxReset);
-					set_rx_mode(dev);
-					outw(RxEnable, ioaddr + EL3_CMD);
-				}
-				outw(AckIntr | AdapterFailure, ioaddr + EL3_CMD);
-			}
-		}
-		if (++i > 10) {
-			netdev_err(dev, "infinite loop in interrupt, status %4.4x.\n",
-					status);
-			/* Clear all interrupts */
-			outw(AckIntr | 0xFF, ioaddr + EL3_CMD);
-			break;
-		}
-		/* Acknowledge the IRQ. */
-		outw(AckIntr | IntReq | IntLatch, ioaddr + EL3_CMD);
-	}
-	lp->last_irq = jiffies;
-	spin_unlock(&lp->lock);
-	netdev_dbg(dev, "exiting interrupt, status %4.4x.\n",
-			inw(ioaddr + EL3_STATUS));
-	return IRQ_RETVAL(handled);
-}
-
-static void media_check(struct timer_list *t)
-{
-	struct el3_private *lp = timer_container_of(lp, t, media);
-	struct net_device *dev = lp->p_dev->priv;
-	unsigned int ioaddr = dev->base_addr;
-	u16 media, errs;
-	unsigned long flags;
-
-	if (!netif_device_present(dev))
-		goto reschedule;
-
-	/* Check for pending interrupt with expired latency timer: with
-	 * this, we can limp along even if the interrupt is blocked
-	 */
-	if ((inw(ioaddr + EL3_STATUS) & IntLatch) &&
-	(inb(ioaddr + EL3_TIMER) == 0xff)) {
-		if (!lp->fast_poll)
-			netdev_warn(dev, "interrupt(s) dropped!\n");
-
-		local_irq_save(flags);
-		el3_interrupt(dev->irq, dev);
-		local_irq_restore(flags);
-
-		lp->fast_poll = HZ;
-	}
-	if (lp->fast_poll) {
-		lp->fast_poll--;
-		lp->media.expires = jiffies + HZ/100;
-		add_timer(&lp->media);
-		return;
-	}
-
-	/* lp->lock guards the EL3 window. Window should always be 1 except
-	 * when the lock is held
-	 */
-
-	spin_lock_irqsave(&lp->lock, flags);
-	EL3WINDOW(4);
-	media = inw(ioaddr+WN4_MEDIA) & 0xc810;
-
-	/* Ignore collisions unless we've had no irq's recently */
-	if (time_before(jiffies, lp->last_irq + HZ)) {
-		media &= ~0x0010;
-	} else {
-		/* Try harder to detect carrier errors */
-		EL3WINDOW(6);
-		outw(StatsDisable, ioaddr + EL3_CMD);
-		errs = inb(ioaddr + 0);
-		outw(StatsEnable, ioaddr + EL3_CMD);
-		dev->stats.tx_carrier_errors += errs;
-		if (errs || (lp->media_status & 0x0010))
-			media |= 0x0010;
-	}
-
-	if (media != lp->media_status) {
-		if ((media & lp->media_status & 0x8000) &&
-				((lp->media_status ^ media) & 0x0800))
-		netdev_info(dev, "%s link beat\n",
-				(lp->media_status & 0x0800 ? "lost" : "found"));
-		else if ((media & lp->media_status & 0x4000) &&
-		 ((lp->media_status ^ media) & 0x0010))
-		netdev_info(dev, "coax cable %s\n",
-				(lp->media_status & 0x0010 ? "ok" : "problem"));
-		if (dev->if_port == 0) {
-			if (media & 0x8000) {
-				if (media & 0x0800)
-					netdev_info(dev, "flipped to 10baseT\n");
-				else
-			tc589_set_xcvr(dev, 2);
-			} else if (media & 0x4000) {
-				if (media & 0x0010)
-					tc589_set_xcvr(dev, 1);
-				else
-					netdev_info(dev, "flipped to 10base2\n");
-			}
-		}
-		lp->media_status = media;
-	}
-
-	EL3WINDOW(1);
-	spin_unlock_irqrestore(&lp->lock, flags);
-
-reschedule:
-	lp->media.expires = jiffies + HZ;
-	add_timer(&lp->media);
-}
-
-static struct net_device_stats *el3_get_stats(struct net_device *dev)
-{
-	struct el3_private *lp = netdev_priv(dev);
-	unsigned long flags;
-	struct pcmcia_device *link = lp->p_dev;
-
-	if (pcmcia_dev_present(link)) {
-		spin_lock_irqsave(&lp->lock, flags);
-		update_stats(dev);
-		spin_unlock_irqrestore(&lp->lock, flags);
-	}
-	return &dev->stats;
-}
-
-/* Update statistics.  We change to register window 6, so this should be run
-* single-threaded if the device is active. This is expected to be a rare
-* operation, and it's simpler for the rest of the driver to assume that
-* window 1 is always valid rather than use a special window-state variable.
-*
-* Caller must hold the lock for this
-*/
-
-static void update_stats(struct net_device *dev)
-{
-	unsigned int ioaddr = dev->base_addr;
-
-	netdev_dbg(dev, "updating the statistics.\n");
-	/* Turn off statistics updates while reading. */
-	outw(StatsDisable, ioaddr + EL3_CMD);
-	/* Switch to the stats window, and read everything. */
-	EL3WINDOW(6);
-	dev->stats.tx_carrier_errors	+= inb(ioaddr + 0);
-	dev->stats.tx_heartbeat_errors	+= inb(ioaddr + 1);
-	/* Multiple collisions. */
-	inb(ioaddr + 2);
-	dev->stats.collisions		+= inb(ioaddr + 3);
-	dev->stats.tx_window_errors		+= inb(ioaddr + 4);
-	dev->stats.rx_fifo_errors		+= inb(ioaddr + 5);
-	dev->stats.tx_packets		+= inb(ioaddr + 6);
-	/* Rx packets   */
-	inb(ioaddr + 7);
-	/* Tx deferrals */
-	inb(ioaddr + 8);
-	/* Rx octets */
-	inw(ioaddr + 10);
-	/* Tx octets */
-	inw(ioaddr + 12);
-
-	/* Back to window 1, and turn statistics back on. */
-	EL3WINDOW(1);
-	outw(StatsEnable, ioaddr + EL3_CMD);
-}
-
-static int el3_rx(struct net_device *dev)
-{
-	unsigned int ioaddr = dev->base_addr;
-	int worklimit = 32;
-	short rx_status;
-
-	netdev_dbg(dev, "in rx_packet(), status %4.4x, rx_status %4.4x.\n",
-	       inw(ioaddr+EL3_STATUS), inw(ioaddr+RX_STATUS));
-	while (!((rx_status = inw(ioaddr + RX_STATUS)) & 0x8000) &&
-		    worklimit > 0) {
-		worklimit--;
-		if (rx_status & 0x4000) { /* Error, update stats. */
-			short error = rx_status & 0x3800;
-			dev->stats.rx_errors++;
-			switch (error) {
-			case 0x0000:
-				dev->stats.rx_over_errors++;
-				break;
-			case 0x0800:
-				dev->stats.rx_length_errors++;
-				break;
-			case 0x1000:
-				dev->stats.rx_frame_errors++;
-				break;
-			case 0x1800:
-				dev->stats.rx_length_errors++;
-				break;
-			case 0x2000:
-				dev->stats.rx_frame_errors++;
-				break;
-			case 0x2800:
-				dev->stats.rx_crc_errors++;
-				break;
-			}
-		} else {
-			short pkt_len = rx_status & 0x7ff;
-			struct sk_buff *skb;
-
-			skb = netdev_alloc_skb(dev, pkt_len + 5);
-
-			netdev_dbg(dev, "    Receiving packet size %d status %4.4x.\n",
-		       pkt_len, rx_status);
-			if (skb != NULL) {
-				skb_reserve(skb, 2);
-				insl(ioaddr+RX_FIFO, skb_put(skb, pkt_len),
-			(pkt_len+3)>>2);
-				skb->protocol = eth_type_trans(skb, dev);
-				netif_rx(skb);
-				dev->stats.rx_packets++;
-				dev->stats.rx_bytes += pkt_len;
-			} else {
-				netdev_dbg(dev, "couldn't allocate a sk_buff of size %d.\n",
-			   pkt_len);
-				dev->stats.rx_dropped++;
-			}
-		}
-		/* Pop the top of the Rx FIFO */
-		tc589_wait_for_completion(dev, RxDiscard);
-	}
-	if (worklimit == 0)
-		netdev_warn(dev, "too much work in el3_rx!\n");
-	return 0;
-}
-
-static void set_rx_mode(struct net_device *dev)
-{
-	unsigned int ioaddr = dev->base_addr;
-	u16 opts = SetRxFilter | RxStation | RxBroadcast;
-
-	if (dev->flags & IFF_PROMISC)
-		opts |= RxMulticast | RxProm;
-	else if (!netdev_mc_empty(dev) || (dev->flags & IFF_ALLMULTI))
-		opts |= RxMulticast;
-	outw(opts, ioaddr + EL3_CMD);
-}
-
-static void set_multicast_list(struct net_device *dev)
-{
-	struct el3_private *priv = netdev_priv(dev);
-	unsigned long flags;
-
-	spin_lock_irqsave(&priv->lock, flags);
-	set_rx_mode(dev);
-	spin_unlock_irqrestore(&priv->lock, flags);
-}
-
-static int el3_close(struct net_device *dev)
-{
-	struct el3_private *lp = netdev_priv(dev);
-	struct pcmcia_device *link = lp->p_dev;
-	unsigned int ioaddr = dev->base_addr;
-
-	dev_dbg(&link->dev, "%s: shutting down ethercard.\n", dev->name);
-
-	if (pcmcia_dev_present(link)) {
-		/* Turn off statistics ASAP.  We update dev->stats below. */
-		outw(StatsDisable, ioaddr + EL3_CMD);
-
-		/* Disable the receiver and transmitter. */
-		outw(RxDisable, ioaddr + EL3_CMD);
-		outw(TxDisable, ioaddr + EL3_CMD);
-
-		if (dev->if_port == 2)
-			/* Turn off thinnet power.  Green! */
-			outw(StopCoax, ioaddr + EL3_CMD);
-		else if (dev->if_port == 1) {
-			/* Disable link beat and jabber */
-			EL3WINDOW(4);
-			outw(0, ioaddr + WN4_MEDIA);
-		}
-
-		/* Switching back to window 0 disables the IRQ. */
-		EL3WINDOW(0);
-		/* But we explicitly zero the IRQ line select anyway. */
-		outw(0x0f00, ioaddr + WN0_IRQ);
-
-		/* Check if the card still exists */
-		if ((inw(ioaddr+EL3_STATUS) & 0xe000) == 0x2000)
-			update_stats(dev);
-	}
-
-	link->open--;
-	netif_stop_queue(dev);
-	timer_delete_sync(&lp->media);
-
-	return 0;
-}
-
-static const struct pcmcia_device_id tc589_ids[] = {
-	PCMCIA_MFC_DEVICE_MANF_CARD(0, 0x0101, 0x0562),
-	PCMCIA_MFC_DEVICE_PROD_ID1(0, "Motorola MARQUIS", 0xf03e4e77),
-	PCMCIA_DEVICE_MANF_CARD(0x0101, 0x0589),
-	PCMCIA_DEVICE_PROD_ID12("Farallon", "ENet", 0x58d93fc4, 0x992c2202),
-	PCMCIA_MFC_DEVICE_CIS_MANF_CARD(0, 0x0101, 0x0035, "cis/3CXEM556.cis"),
-	PCMCIA_MFC_DEVICE_CIS_MANF_CARD(0, 0x0101, 0x003d, "cis/3CXEM556.cis"),
-	PCMCIA_DEVICE_NULL,
-};
-MODULE_DEVICE_TABLE(pcmcia, tc589_ids);
-
-static struct pcmcia_driver tc589_driver = {
-	.owner		= THIS_MODULE,
-	.name		= "3c589_cs",
-	.probe		= tc589_probe,
-	.remove		= tc589_detach,
-	.id_table	= tc589_ids,
-	.suspend	= tc589_suspend,
-	.resume		= tc589_resume,
-};
-module_pcmcia_driver(tc589_driver);
diff --git a/drivers/net/ethernet/3com/Kconfig b/drivers/net/ethernet/3com/Kconfig
index 294403ad7141..399cb6c56198 100644
--- a/drivers/net/ethernet/3com/Kconfig
+++ b/drivers/net/ethernet/3com/Kconfig
@@ -17,16 +17,6 @@ config NET_VENDOR_3COM
 
 if NET_VENDOR_3COM
 
-config PCMCIA_3C589
-	tristate "3Com 3c589 PCMCIA support"
-	depends on PCMCIA && HAS_IOPORT
-	help
-	  Say Y here if you intend to attach a 3Com 3c589 or compatible PCMCIA
-	  (PC-card) Ethernet card to your computer.
-
-	  To compile this driver as a module, choose M here: the module will be
-	  called 3c589_cs.  If unsure, say N.
-
 config VORTEX
 	tristate "3c590/3c900 series (592/595/597) \"Vortex/Boomerang\" support"
 	depends on (PCI || EISA) && HAS_IOPORT_MAP
diff --git a/drivers/net/ethernet/3com/Makefile b/drivers/net/ethernet/3com/Makefile
index 45fb9af9b5c7..5c4d07f1d456 100644
--- a/drivers/net/ethernet/3com/Makefile
+++ b/drivers/net/ethernet/3com/Makefile
@@ -3,6 +3,5 @@
 # Makefile for the 3Com Ethernet device drivers
 #
 
-obj-$(CONFIG_PCMCIA_3C589) += 3c589_cs.o
 obj-$(CONFIG_VORTEX) += 3c59x.o
 obj-$(CONFIG_TYPHOON) += typhoon.o

-- 
2.53.0


^ permalink raw reply related	[flat|nested] 28+ messages in thread

* [PATCH net 05/18] drivers: net: 3com: 3c59x: Remove this driver
  2026-04-21 19:31 [PATCH net 00/18] Remove a number of ISA and PCMCIA Ethernet drivers Andrew Lunn
                   ` (3 preceding siblings ...)
  2026-04-21 19:31 ` [PATCH net 04/18] drivers: net: 3com: 3c589: " Andrew Lunn
@ 2026-04-21 19:31 ` Andrew Lunn
  2026-04-21 19:31 ` [PATCH net 06/18] drivers: net: amd: Remove hplance and mvme147 Andrew Lunn
                   ` (16 subsequent siblings)
  21 siblings, 0 replies; 28+ messages in thread
From: Andrew Lunn @ 2026-04-21 19:31 UTC (permalink / raw)
  To: Andrew Lunn, David S. Miller, Eric Dumazet, Jakub Kicinski,
	Paolo Abeni, Simon Horman, Jonathan Corbet, Shuah Khan
  Cc: linux-kernel, netdev, linux-doc, Andrew Lunn

The 3c59x was written by Donald Becker between 1996-1999. It is an
EISA and PCI Fast Ethernet device, so unlikely to be used with modern
kernels.

Signed-off-by: Andrew Lunn <andrew@lunn.ch>
---
 .../device_drivers/ethernet/3com/vortex.rst        |  459 ---
 MAINTAINERS                                        |    7 -
 drivers/net/ethernet/3com/3c59x.c                  | 3357 --------------------
 drivers/net/ethernet/3com/Kconfig                  |   21 -
 drivers/net/ethernet/3com/Makefile                 |    1 -
 5 files changed, 3845 deletions(-)

diff --git a/Documentation/networking/device_drivers/ethernet/3com/vortex.rst b/Documentation/networking/device_drivers/ethernet/3com/vortex.rst
deleted file mode 100644
index a060f84c4f96..000000000000
--- a/Documentation/networking/device_drivers/ethernet/3com/vortex.rst
+++ /dev/null
@@ -1,459 +0,0 @@
-.. SPDX-License-Identifier: GPL-2.0
-
-=========================
-3Com Vortex device driver
-=========================
-
-Andrew Morton
-
-30 April 2000
-
-
-This document describes the usage and errata of the 3Com "Vortex" device
-driver for Linux, 3c59x.c.
-
-The driver was written by Donald Becker <becker@scyld.com>
-
-Don is no longer the prime maintainer of this version of the driver.
-Please report problems to one or more of:
-
-- Andrew Morton
-- Netdev mailing list <netdev@vger.kernel.org>
-- Linux kernel mailing list <linux-kernel@vger.kernel.org>
-
-Please note the 'Reporting and Diagnosing Problems' section at the end
-of this file.
-
-
-Since kernel 2.3.99-pre6, this driver incorporates the support for the
-3c575-series Cardbus cards which used to be handled by 3c575_cb.c.
-
-This driver supports the following hardware:
-
-	- 3c590 Vortex 10Mbps
-	- 3c592 EISA 10Mbps Demon/Vortex
-	- 3c597 EISA Fast Demon/Vortex
-	- 3c595 Vortex 100baseTx
-	- 3c595 Vortex 100baseT4
-	- 3c595 Vortex 100base-MII
-	- 3c900 Boomerang 10baseT
-	- 3c900 Boomerang 10Mbps Combo
-	- 3c900 Cyclone 10Mbps TPO
-	- 3c900 Cyclone 10Mbps Combo
-	- 3c900 Cyclone 10Mbps TPC
-	- 3c900B-FL Cyclone 10base-FL
-	- 3c905 Boomerang 100baseTx
-	- 3c905 Boomerang 100baseT4
-	- 3c905B Cyclone 100baseTx
-	- 3c905B Cyclone 10/100/BNC
-	- 3c905B-FX Cyclone 100baseFx
-	- 3c905C Tornado
-	- 3c920B-EMB-WNM (ATI Radeon 9100 IGP)
-	- 3c980 Cyclone
-	- 3c980C Python-T
-	- 3cSOHO100-TX Hurricane
-	- 3c555 Laptop Hurricane
-	- 3c556 Laptop Tornado
-	- 3c556B Laptop Hurricane
-	- 3c575 [Megahertz] 10/100 LAN  CardBus
-	- 3c575 Boomerang CardBus
-	- 3CCFE575BT Cyclone CardBus
-	- 3CCFE575CT Tornado CardBus
-	- 3CCFE656 Cyclone CardBus
-	- 3CCFEM656B Cyclone+Winmodem CardBus
-	- 3CXFEM656C Tornado+Winmodem CardBus
-	- 3c450 HomePNA Tornado
-	- 3c920 Tornado
-	- 3c982 Hydra Dual Port A
-	- 3c982 Hydra Dual Port B
-	- 3c905B-T4
-	- 3c920B-EMB-WNM Tornado
-
-Module parameters
-=================
-
-There are several parameters which may be provided to the driver when
-its module is loaded.  These are usually placed in ``/etc/modprobe.d/*.conf``
-configuration files.  Example::
-
-    options 3c59x debug=3 rx_copybreak=300
-
-If you are using the PCMCIA tools (cardmgr) then the options may be
-placed in /etc/pcmcia/config.opts::
-
-    module "3c59x" opts "debug=3 rx_copybreak=300"
-
-
-The supported parameters are:
-
-debug=N
-
-  Where N is a number from 0 to 7.  Anything above 3 produces a lot
-  of output in your system logs.  debug=1 is default.
-
-options=N1,N2,N3,...
-
-  Each number in the list provides an option to the corresponding
-  network card.  So if you have two 3c905's and you wish to provide
-  them with option 0x204 you would use::
-
-    options=0x204,0x204
-
-  The individual options are composed of a number of bitfields which
-  have the following meanings:
-
-  Possible media type settings
-
-	==	=================================
-	0	10baseT
-	1	10Mbs AUI
-	2	undefined
-	3	10base2 (BNC)
-	4	100base-TX
-	5	100base-FX
-	6	MII (Media Independent Interface)
-	7	Use default setting from EEPROM
-	8       Autonegotiate
-	9       External MII
-	10      Use default setting from EEPROM
-	==	=================================
-
-  When generating a value for the 'options' setting, the above media
-  selection values may be OR'ed (or added to) the following:
-
-  ======  =============================================
-  0x8000  Set driver debugging level to 7
-  0x4000  Set driver debugging level to 2
-  0x0400  Enable Wake-on-LAN
-  0x0200  Force full duplex mode.
-  0x0010  Bus-master enable bit (Old Vortex cards only)
-  ======  =============================================
-
-  For example::
-
-    insmod 3c59x options=0x204
-
-  will force full-duplex 100base-TX, rather than allowing the usual
-  autonegotiation.
-
-global_options=N
-
-  Sets the ``options`` parameter for all 3c59x NICs in the machine.
-  Entries in the ``options`` array above will override any setting of
-  this.
-
-full_duplex=N1,N2,N3...
-
-  Similar to bit 9 of 'options'.  Forces the corresponding card into
-  full-duplex mode.  Please use this in preference to the ``options``
-  parameter.
-
-  In fact, please don't use this at all! You're better off getting
-  autonegotiation working properly.
-
-global_full_duplex=N1
-
-  Sets full duplex mode for all 3c59x NICs in the machine.  Entries
-  in the ``full_duplex`` array above will override any setting of this.
-
-flow_ctrl=N1,N2,N3...
-
-  Use 802.3x MAC-layer flow control.  The 3com cards only support the
-  PAUSE command, which means that they will stop sending packets for a
-  short period if they receive a PAUSE frame from the link partner.
-
-  The driver only allows flow control on a link which is operating in
-  full duplex mode.
-
-  This feature does not appear to work on the 3c905 - only 3c905B and
-  3c905C have been tested.
-
-  The 3com cards appear to only respond to PAUSE frames which are
-  sent to the reserved destination address of 01:80:c2:00:00:01.  They
-  do not honour PAUSE frames which are sent to the station MAC address.
-
-rx_copybreak=M
-
-  The driver preallocates 32 full-sized (1536 byte) network buffers
-  for receiving.  When a packet arrives, the driver has to decide
-  whether to leave the packet in its full-sized buffer, or to allocate
-  a smaller buffer and copy the packet across into it.
-
-  This is a speed/space tradeoff.
-
-  The value of rx_copybreak is used to decide when to make the copy.
-  If the packet size is less than rx_copybreak, the packet is copied.
-  The default value for rx_copybreak is 200 bytes.
-
-max_interrupt_work=N
-
-  The driver's interrupt service routine can handle many receive and
-  transmit packets in a single invocation.  It does this in a loop.
-  The value of max_interrupt_work governs how many times the interrupt
-  service routine will loop.  The default value is 32 loops.  If this
-  is exceeded the interrupt service routine gives up and generates a
-  warning message "eth0: Too much work in interrupt".
-
-hw_checksums=N1,N2,N3,...
-
-  Recent 3com NICs are able to generate IPv4, TCP and UDP checksums
-  in hardware.  Linux has used the Rx checksumming for a long time.
-  The "zero copy" patch which is planned for the 2.4 kernel series
-  allows you to make use of the NIC's DMA scatter/gather and transmit
-  checksumming as well.
-
-  The driver is set up so that, when the zerocopy patch is applied,
-  all Tornado and Cyclone devices will use S/G and Tx checksums.
-
-  This module parameter has been provided so you can override this
-  decision.  If you think that Tx checksums are causing a problem, you
-  may disable the feature with ``hw_checksums=0``.
-
-  If you think your NIC should be performing Tx checksumming and the
-  driver isn't enabling it, you can force the use of hardware Tx
-  checksumming with ``hw_checksums=1``.
-
-  The driver drops a message in the logfiles to indicate whether or
-  not it is using hardware scatter/gather and hardware Tx checksums.
-
-  Scatter/gather and hardware checksums provide considerable
-  performance improvement for the sendfile() system call, but a small
-  decrease in throughput for send().  There is no effect upon receive
-  efficiency.
-
-compaq_ioaddr=N,
-compaq_irq=N,
-compaq_device_id=N
-
-  "Variables to work-around the Compaq PCI BIOS32 problem"....
-
-watchdog=N
-
-  Sets the time duration (in milliseconds) after which the kernel
-  decides that the transmitter has become stuck and needs to be reset.
-  This is mainly for debugging purposes, although it may be advantageous
-  to increase this value on LANs which have very high collision rates.
-  The default value is 5000 (5.0 seconds).
-
-enable_wol=N1,N2,N3,...
-
-  Enable Wake-on-LAN support for the relevant interface.  Donald
-  Becker's ``ether-wake`` application may be used to wake suspended
-  machines.
-
-  Also enables the NIC's power management support.
-
-global_enable_wol=N
-
-  Sets enable_wol mode for all 3c59x NICs in the machine.  Entries in
-  the ``enable_wol`` array above will override any setting of this.
-
-Media selection
----------------
-
-A number of the older NICs such as the 3c590 and 3c900 series have
-10base2 and AUI interfaces.
-
-Prior to January, 2001 this driver would autoselect the 10base2 or AUI
-port if it didn't detect activity on the 10baseT port.  It would then
-get stuck on the 10base2 port and a driver reload was necessary to
-switch back to 10baseT.  This behaviour could not be prevented with a
-module option override.
-
-Later (current) versions of the driver _do_ support locking of the
-media type.  So if you load the driver module with
-
-	modprobe 3c59x options=0
-
-it will permanently select the 10baseT port.  Automatic selection of
-other media types does not occur.
-
-
-Transmit error, Tx status register 82
--------------------------------------
-
-This is a common error which is almost always caused by another host on
-the same network being in full-duplex mode, while this host is in
-half-duplex mode.  You need to find that other host and make it run in
-half-duplex mode or fix this host to run in full-duplex mode.
-
-As a last resort, you can force the 3c59x driver into full-duplex mode
-with
-
-	options 3c59x full_duplex=1
-
-but this has to be viewed as a workaround for broken network gear and
-should only really be used for equipment which cannot autonegotiate.
-
-
-Additional resources
---------------------
-
-Details of the device driver implementation are at the top of the source file.
-
-Additional documentation is available at Don Becker's Linux Drivers site:
-
-     http://www.scyld.com/vortex.html
-
-Donald Becker's driver development site:
-
-     http://www.scyld.com/network.html
-
-Donald's vortex-diag program is useful for inspecting the NIC's state:
-
-     http://www.scyld.com/ethercard_diag.html
-
-Donald's mii-diag program may be used for inspecting and manipulating
-the NIC's Media Independent Interface subsystem:
-
-     http://www.scyld.com/ethercard_diag.html#mii-diag
-
-Donald's wake-on-LAN page:
-
-     http://www.scyld.com/wakeonlan.html
-
-3Com's DOS-based application for setting up the NICs EEPROMs:
-
-	ftp://ftp.3com.com/pub/nic/3c90x/3c90xx2.exe
-
-
-Autonegotiation notes
----------------------
-
-  The driver uses a one-minute heartbeat for adapting to changes in
-  the external LAN environment if link is up and 5 seconds if link is down.
-  This means that when, for example, a machine is unplugged from a hubbed
-  10baseT LAN plugged into a  switched 100baseT LAN, the throughput
-  will be quite dreadful for up to sixty seconds.  Be patient.
-
-  Cisco interoperability note from Walter Wong <wcw+@CMU.EDU>:
-
-  On a side note, adding HAS_NWAY seems to share a problem with the
-  Cisco 6509 switch.  Specifically, you need to change the spanning
-  tree parameter for the port the machine is plugged into to 'portfast'
-  mode.  Otherwise, the negotiation fails.  This has been an issue
-  we've noticed for a while but haven't had the time to track down.
-
-  Cisco switches    (Jeff Busch <jbusch@deja.com>)
-
-    My "standard config" for ports to which PC's/servers connect directly::
-
-	interface FastEthernet0/N
-	description machinename
-	load-interval 30
-	spanning-tree portfast
-
-    If autonegotiation is a problem, you may need to specify "speed
-    100" and "duplex full" as well (or "speed 10" and "duplex half").
-
-    WARNING: DO NOT hook up hubs/switches/bridges to these
-    specially-configured ports! The switch will become very confused.
-
-
-Reporting and diagnosing problems
----------------------------------
-
-Maintainers find that accurate and complete problem reports are
-invaluable in resolving driver problems.  We are frequently not able to
-reproduce problems and must rely on your patience and efforts to get to
-the bottom of the problem.
-
-If you believe you have a driver problem here are some of the
-steps you should take:
-
-- Is it really a driver problem?
-
-   Eliminate some variables: try different cards, different
-   computers, different cables, different ports on the switch/hub,
-   different versions of the kernel or of the driver, etc.
-
-- OK, it's a driver problem.
-
-   You need to generate a report.  Typically this is an email to the
-   maintainer and/or netdev@vger.kernel.org.  The maintainer's
-   email address will be in the driver source or in the MAINTAINERS file.
-
-- The contents of your report will vary a lot depending upon the
-  problem.  If it's a kernel crash then you should refer to
-  'Documentation/admin-guide/reporting-issues.rst'.
-
-  But for most problems it is useful to provide the following:
-
-   - Kernel version, driver version
-
-   - A copy of the banner message which the driver generates when
-     it is initialised.  For example:
-
-     eth0: 3Com PCI 3c905C Tornado at 0xa400,  00:50:da:6a:88:f0, IRQ 19
-     8K byte-wide RAM 5:3 Rx:Tx split, autoselect/Autonegotiate interface.
-     MII transceiver found at address 24, status 782d.
-     Enabling bus-master transmits and whole-frame receives.
-
-     NOTE: You must provide the ``debug=2`` modprobe option to generate
-     a full detection message.  Please do this::
-
-	modprobe 3c59x debug=2
-
-   - If it is a PCI device, the relevant output from 'lspci -vx', eg::
-
-       00:09.0 Ethernet controller: 3Com Corporation 3c905C-TX [Fast Etherlink] (rev 74)
-	       Subsystem: 3Com Corporation: Unknown device 9200
-	       Flags: bus master, medium devsel, latency 32, IRQ 19
-	       I/O ports at a400 [size=128]
-	       Memory at db000000 (32-bit, non-prefetchable) [size=128]
-	       Expansion ROM at <unassigned> [disabled] [size=128K]
-	       Capabilities: [dc] Power Management version 2
-       00: b7 10 00 92 07 00 10 02 74 00 00 02 08 20 00 00
-       10: 01 a4 00 00 00 00 00 db 00 00 00 00 00 00 00 00
-       20: 00 00 00 00 00 00 00 00 00 00 00 00 b7 10 00 10
-       30: 00 00 00 00 dc 00 00 00 00 00 00 00 05 01 0a 0a
-
-   - A description of the environment: 10baseT? 100baseT?
-     full/half duplex? switched or hubbed?
-
-   - Any additional module parameters which you may be providing to the driver.
-
-   - Any kernel logs which are produced.  The more the merrier.
-     If this is a large file and you are sending your report to a
-     mailing list, mention that you have the logfile, but don't send
-     it.  If you're reporting direct to the maintainer then just send
-     it.
-
-     To ensure that all kernel logs are available, add the
-     following line to /etc/syslog.conf::
-
-	 kern.* /var/log/messages
-
-     Then restart syslogd with::
-
-	 /etc/rc.d/init.d/syslog restart
-
-     (The above may vary, depending upon which Linux distribution you use).
-
-    - If your problem is reproducible then that's great.  Try the
-      following:
-
-      1) Increase the debug level.  Usually this is done via:
-
-	 a) modprobe driver debug=7
-	 b) In /etc/modprobe.d/driver.conf:
-	    options driver debug=7
-
-      2) Recreate the problem with the higher debug level,
-	 send all logs to the maintainer.
-
-      3) Download you card's diagnostic tool from Donald
-	 Becker's website <http://www.scyld.com/ethercard_diag.html>.
-	 Download mii-diag.c as well.  Build these.
-
-	 a) Run 'vortex-diag -aaee' and 'mii-diag -v' when the card is
-	    working correctly.  Save the output.
-
-	 b) Run the above commands when the card is malfunctioning.  Send
-	    both sets of output.
-
-Finally, please be patient and be prepared to do some work.  You may
-end up working on this problem for a week or more as the maintainer
-asks more questions, asks for more tests, asks for patches to be
-applied, etc.  At the end of it all, the problem may even remain
-unresolved.
diff --git a/MAINTAINERS b/MAINTAINERS
index e7dc9e6fad2e..188b10f2c859 100644
--- a/MAINTAINERS
+++ b/MAINTAINERS
@@ -67,13 +67,6 @@ Maintainers List
           first. When adding to this list, please keep the entries in
           alphabetical order.
 
-3C59X NETWORK DRIVER
-M:	Steffen Klassert <klassert@kernel.org>
-L:	netdev@vger.kernel.org
-S:	Odd Fixes
-F:	Documentation/networking/device_drivers/ethernet/3com/vortex.rst
-F:	drivers/net/ethernet/3com/3c59x.c
-
 3CR990 NETWORK DRIVER
 M:	David Dillow <dave@thedillows.org>
 L:	netdev@vger.kernel.org
diff --git a/drivers/net/ethernet/3com/3c59x.c b/drivers/net/ethernet/3com/3c59x.c
deleted file mode 100644
index 4fe4efdb3737..000000000000
--- a/drivers/net/ethernet/3com/3c59x.c
+++ /dev/null
@@ -1,3357 +0,0 @@
-/* EtherLinkXL.c: A 3Com EtherLink PCI III/XL ethernet driver for linux. */
-/*
-	Written 1996-1999 by Donald Becker.
-
-	This software may be used and distributed according to the terms
-	of the GNU General Public License, incorporated herein by reference.
-
-	This driver is for the 3Com "Vortex" and "Boomerang" series ethercards.
-	Members of the series include Fast EtherLink 3c590/3c592/3c595/3c597
-	and the EtherLink XL 3c900 and 3c905 cards.
-
-	Problem reports and questions should be directed to
-	vortex@scyld.com
-
-	The author may be reached as becker@scyld.com, or C/O
-	Scyld Computing Corporation
-	410 Severn Ave., Suite 210
-	Annapolis MD 21403
-
-*/
-
-/*
- * FIXME: This driver _could_ support MTU changing, but doesn't.  See Don's hamachi.c implementation
- * as well as other drivers
- *
- * NOTE: If you make 'vortex_debug' a constant (#define vortex_debug 0) the driver shrinks by 2k
- * due to dead code elimination.  There will be some performance benefits from this due to
- * elimination of all the tests and reduced cache footprint.
- */
-
-
-#define DRV_NAME	"3c59x"
-
-
-
-/* A few values that may be tweaked. */
-/* Keep the ring sizes a power of two for efficiency. */
-#define TX_RING_SIZE	16
-#define RX_RING_SIZE	32
-#define PKT_BUF_SZ		1536			/* Size of each temporary Rx buffer.*/
-
-/* "Knobs" that adjust features and parameters. */
-/* Set the copy breakpoint for the copy-only-tiny-frames scheme.
-   Setting to > 1512 effectively disables this feature. */
-#ifndef __arm__
-static int rx_copybreak = 200;
-#else
-/* ARM systems perform better by disregarding the bus-master
-   transfer capability of these cards. -- rmk */
-static int rx_copybreak = 1513;
-#endif
-/* Allow setting MTU to a larger size, bypassing the normal ethernet setup. */
-static const int mtu = 1500;
-/* Maximum events (Rx packets, etc.) to handle at each interrupt. */
-static int max_interrupt_work = 32;
-/* Tx timeout interval (millisecs) */
-static int watchdog = 5000;
-
-/* Allow aggregation of Tx interrupts.  Saves CPU load at the cost
- * of possible Tx stalls if the system is blocking interrupts
- * somewhere else.  Undefine this to disable.
- */
-#define tx_interrupt_mitigation 1
-
-/* Put out somewhat more debugging messages. (0: no msg, 1 minimal .. 6). */
-#define vortex_debug debug
-#ifdef VORTEX_DEBUG
-static int vortex_debug = VORTEX_DEBUG;
-#else
-static int vortex_debug = 1;
-#endif
-
-#include <linux/module.h>
-#include <linux/kernel.h>
-#include <linux/string.h>
-#include <linux/timer.h>
-#include <linux/errno.h>
-#include <linux/in.h>
-#include <linux/ioport.h>
-#include <linux/interrupt.h>
-#include <linux/pci.h>
-#include <linux/mii.h>
-#include <linux/init.h>
-#include <linux/netdevice.h>
-#include <linux/etherdevice.h>
-#include <linux/skbuff.h>
-#include <linux/ethtool.h>
-#include <linux/highmem.h>
-#include <linux/eisa.h>
-#include <linux/bitops.h>
-#include <linux/jiffies.h>
-#include <linux/gfp.h>
-#include <asm/irq.h>			/* For nr_irqs only. */
-#include <asm/io.h>
-#include <linux/uaccess.h>
-
-/* Kernel compatibility defines, some common to David Hinds' PCMCIA package.
-   This is only in the support-all-kernels source code. */
-
-#define RUN_AT(x) (jiffies + (x))
-
-#include <linux/delay.h>
-
-
-static const char version[] =
-	DRV_NAME ": Donald Becker and others.\n";
-
-MODULE_AUTHOR("Donald Becker <becker@scyld.com>");
-MODULE_DESCRIPTION("3Com 3c59x/3c9xx ethernet driver ");
-MODULE_LICENSE("GPL");
-
-
-/* Operational parameter that usually are not changed. */
-
-/* The Vortex size is twice that of the original EtherLinkIII series: the
-   runtime register window, window 1, is now always mapped in.
-   The Boomerang size is twice as large as the Vortex -- it has additional
-   bus master control registers. */
-#define VORTEX_TOTAL_SIZE 0x20
-#define BOOMERANG_TOTAL_SIZE 0x40
-
-/* Set iff a MII transceiver on any interface requires mdio preamble.
-   This only set with the original DP83840 on older 3c905 boards, so the extra
-   code size of a per-interface flag is not worthwhile. */
-static char mii_preamble_required;
-
-#define PFX DRV_NAME ": "
-
-
-
-/*
-				Theory of Operation
-
-I. Board Compatibility
-
-This device driver is designed for the 3Com FastEtherLink and FastEtherLink
-XL, 3Com's PCI to 10/100baseT adapters.  It also works with the 10Mbs
-versions of the FastEtherLink cards.  The supported product IDs are
-  3c590, 3c592, 3c595, 3c597, 3c900, 3c905
-
-The related ISA 3c515 is supported with a separate driver, 3c515.c, included
-with the kernel source or available from
-    cesdis.gsfc.nasa.gov:/pub/linux/drivers/3c515.html
-
-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 should be set to assign the
-PCI INTA signal to an otherwise unused system IRQ line.
-
-The EEPROM settings for media type and forced-full-duplex are observed.
-The EEPROM media type should be left at the default "autoselect" unless using
-10base2 or AUI connections which cannot be reliably detected.
-
-III. Driver operation
-
-The 3c59x series use an interface that's very similar to the previous 3c5x9
-series.  The primary interface is two programmed-I/O FIFOs, with an
-alternate single-contiguous-region bus-master transfer (see next).
-
-The 3c900 "Boomerang" series uses a full-bus-master interface with separate
-lists of transmit and receive descriptors, similar to the AMD LANCE/PCnet,
-DEC Tulip and Intel Speedo3.  The first chip version retains a compatible
-programmed-I/O interface that has been removed in 'B' and subsequent board
-revisions.
-
-One extension that is advertised in a very large font is that the adapters
-are capable of being bus masters.  On the Vortex chip this capability was
-only for a single contiguous region making it far less useful than the full
-bus master capability.  There is a significant performance impact of taking
-an extra interrupt or polling for the completion of each transfer, as well
-as difficulty sharing the single transfer engine between the transmit and
-receive threads.  Using DMA transfers is a win only with large blocks or
-with the flawed versions of the Intel Orion motherboard PCI controller.
-
-The Boomerang chip's full-bus-master interface is useful, and has the
-currently-unused advantages over other similar chips that queued transmit
-packets may be reordered and receive buffer groups are associated with a
-single frame.
-
-With full-bus-master support, this driver uses a "RX_COPYBREAK" scheme.
-Rather than a fixed intermediate receive buffer, this scheme allocates
-full-sized skbuffs as receive buffers.  The value RX_COPYBREAK is used as
-the copying breakpoint: it is chosen to trade-off the memory wasted by
-passing the full-sized skbuff to the queue layer for all frames vs. the
-copying cost of copying a frame to a correctly-sized skbuff.
-
-IIIC. Synchronization
-The driver runs as two independent, single-threaded flows of control.  One
-is the send-packet routine, which enforces single-threaded use by the
-dev->tbusy flag.  The other thread is the interrupt handler, which is single
-threaded by the hardware and other software.
-
-IV. Notes
-
-Thanks to Cameron Spitzer and Terry Murphy of 3Com for providing development
-3c590, 3c595, and 3c900 boards.
-The name "Vortex" is the internal 3Com project name for the PCI ASIC, and
-the EISA version is called "Demon".  According to Terry these names come
-from rides at the local amusement park.
-
-The new chips support both ethernet (1.5K) and FDDI (4.5K) packet sizes!
-This driver only supports ethernet packets because of the skbuff allocation
-limit of 4K.
-*/
-
-/* This table drives the PCI probe routines.  It's mostly boilerplate in all
-   of the drivers, and will likely be provided by some future kernel.
-*/
-enum pci_flags_bit {
-	PCI_USES_MASTER=4,
-};
-
-enum {	IS_VORTEX=1, IS_BOOMERANG=2, IS_CYCLONE=4, IS_TORNADO=8,
-	EEPROM_8BIT=0x10,	/* AKPM: Uses 0x230 as the base bitmaps for EEPROM reads */
-	HAS_PWR_CTRL=0x20, HAS_MII=0x40, HAS_NWAY=0x80, HAS_CB_FNS=0x100,
-	INVERT_MII_PWR=0x200, INVERT_LED_PWR=0x400, MAX_COLLISION_RESET=0x800,
-	EEPROM_OFFSET=0x1000, HAS_HWCKSM=0x2000, WNO_XCVR_PWR=0x4000,
-	EXTRA_PREAMBLE=0x8000, EEPROM_RESET=0x10000, };
-
-enum vortex_chips {
-	CH_3C590 = 0,
-	CH_3C592,
-	CH_3C597,
-	CH_3C595_1,
-	CH_3C595_2,
-
-	CH_3C595_3,
-	CH_3C900_1,
-	CH_3C900_2,
-	CH_3C900_3,
-	CH_3C900_4,
-
-	CH_3C900_5,
-	CH_3C900B_FL,
-	CH_3C905_1,
-	CH_3C905_2,
-	CH_3C905B_TX,
-	CH_3C905B_1,
-
-	CH_3C905B_2,
-	CH_3C905B_FX,
-	CH_3C905C,
-	CH_3C9202,
-	CH_3C980,
-	CH_3C9805,
-
-	CH_3CSOHO100_TX,
-	CH_3C555,
-	CH_3C556,
-	CH_3C556B,
-	CH_3C575,
-
-	CH_3C575_1,
-	CH_3CCFE575,
-	CH_3CCFE575CT,
-	CH_3CCFE656,
-	CH_3CCFEM656,
-
-	CH_3CCFEM656_1,
-	CH_3C450,
-	CH_3C920,
-	CH_3C982A,
-	CH_3C982B,
-
-	CH_905BT4,
-	CH_920B_EMB_WNM,
-};
-
-
-/* note: this array directly indexed by above enums, and MUST
- * be kept in sync with both the enums above, and the PCI device
- * table below
- */
-static struct vortex_chip_info {
-	const char *name;
-	int flags;
-	int drv_flags;
-	int io_size;
-} vortex_info_tbl[] = {
-	{"3c590 Vortex 10Mbps",
-	 PCI_USES_MASTER, IS_VORTEX, 32, },
-	{"3c592 EISA 10Mbps Demon/Vortex",					/* AKPM: from Don's 3c59x_cb.c 0.49H */
-	 PCI_USES_MASTER, IS_VORTEX, 32, },
-	{"3c597 EISA Fast Demon/Vortex",					/* AKPM: from Don's 3c59x_cb.c 0.49H */
-	 PCI_USES_MASTER, IS_VORTEX, 32, },
-	{"3c595 Vortex 100baseTx",
-	 PCI_USES_MASTER, IS_VORTEX, 32, },
-	{"3c595 Vortex 100baseT4",
-	 PCI_USES_MASTER, IS_VORTEX, 32, },
-
-	{"3c595 Vortex 100base-MII",
-	 PCI_USES_MASTER, IS_VORTEX, 32, },
-	{"3c900 Boomerang 10baseT",
-	 PCI_USES_MASTER, IS_BOOMERANG|EEPROM_RESET, 64, },
-	{"3c900 Boomerang 10Mbps Combo",
-	 PCI_USES_MASTER, IS_BOOMERANG|EEPROM_RESET, 64, },
-	{"3c900 Cyclone 10Mbps TPO",						/* AKPM: from Don's 0.99M */
-	 PCI_USES_MASTER, IS_CYCLONE|HAS_HWCKSM, 128, },
-	{"3c900 Cyclone 10Mbps Combo",
-	 PCI_USES_MASTER, IS_CYCLONE|HAS_HWCKSM, 128, },
-
-	{"3c900 Cyclone 10Mbps TPC",						/* AKPM: from Don's 0.99M */
-	 PCI_USES_MASTER, IS_CYCLONE|HAS_HWCKSM, 128, },
-	{"3c900B-FL Cyclone 10base-FL",
-	 PCI_USES_MASTER, IS_CYCLONE|HAS_HWCKSM, 128, },
-	{"3c905 Boomerang 100baseTx",
-	 PCI_USES_MASTER, IS_BOOMERANG|HAS_MII|EEPROM_RESET, 64, },
-	{"3c905 Boomerang 100baseT4",
-	 PCI_USES_MASTER, IS_BOOMERANG|HAS_MII|EEPROM_RESET, 64, },
-	{"3C905B-TX Fast Etherlink XL PCI",
-	 PCI_USES_MASTER, IS_CYCLONE|HAS_NWAY|HAS_HWCKSM|EXTRA_PREAMBLE, 128, },
-	{"3c905B Cyclone 100baseTx",
-	 PCI_USES_MASTER, IS_CYCLONE|HAS_NWAY|HAS_HWCKSM|EXTRA_PREAMBLE, 128, },
-
-	{"3c905B Cyclone 10/100/BNC",
-	 PCI_USES_MASTER, IS_CYCLONE|HAS_NWAY|HAS_HWCKSM, 128, },
-	{"3c905B-FX Cyclone 100baseFx",
-	 PCI_USES_MASTER, IS_CYCLONE|HAS_HWCKSM, 128, },
-	{"3c905C Tornado",
-	PCI_USES_MASTER, IS_TORNADO|HAS_NWAY|HAS_HWCKSM|EXTRA_PREAMBLE, 128, },
-	{"3c920B-EMB-WNM (ATI Radeon 9100 IGP)",
-	 PCI_USES_MASTER, IS_TORNADO|HAS_MII|HAS_HWCKSM, 128, },
-	{"3c980 Cyclone",
-	 PCI_USES_MASTER, IS_CYCLONE|HAS_HWCKSM|EXTRA_PREAMBLE, 128, },
-
-	{"3c980C Python-T",
-	 PCI_USES_MASTER, IS_CYCLONE|HAS_NWAY|HAS_HWCKSM, 128, },
-	{"3cSOHO100-TX Hurricane",
-	 PCI_USES_MASTER, IS_CYCLONE|HAS_NWAY|HAS_HWCKSM|EXTRA_PREAMBLE, 128, },
-	{"3c555 Laptop Hurricane",
-	 PCI_USES_MASTER, IS_CYCLONE|EEPROM_8BIT|HAS_HWCKSM, 128, },
-	{"3c556 Laptop Tornado",
-	 PCI_USES_MASTER, IS_TORNADO|HAS_NWAY|EEPROM_8BIT|HAS_CB_FNS|INVERT_MII_PWR|
-									HAS_HWCKSM, 128, },
-	{"3c556B Laptop Hurricane",
-	 PCI_USES_MASTER, IS_TORNADO|HAS_NWAY|EEPROM_OFFSET|HAS_CB_FNS|INVERT_MII_PWR|
-	                                WNO_XCVR_PWR|HAS_HWCKSM, 128, },
-
-	{"3c575 [Megahertz] 10/100 LAN 	CardBus",
-	PCI_USES_MASTER, IS_BOOMERANG|HAS_MII|EEPROM_8BIT, 128, },
-	{"3c575 Boomerang CardBus",
-	 PCI_USES_MASTER, IS_BOOMERANG|HAS_MII|EEPROM_8BIT, 128, },
-	{"3CCFE575BT Cyclone CardBus",
-	 PCI_USES_MASTER, IS_CYCLONE|HAS_NWAY|HAS_CB_FNS|EEPROM_8BIT|
-									INVERT_LED_PWR|HAS_HWCKSM, 128, },
-	{"3CCFE575CT Tornado CardBus",
-	 PCI_USES_MASTER, IS_TORNADO|HAS_NWAY|HAS_CB_FNS|EEPROM_8BIT|INVERT_MII_PWR|
-									MAX_COLLISION_RESET|HAS_HWCKSM, 128, },
-	{"3CCFE656 Cyclone CardBus",
-	 PCI_USES_MASTER, IS_CYCLONE|HAS_NWAY|HAS_CB_FNS|EEPROM_8BIT|INVERT_MII_PWR|
-									INVERT_LED_PWR|HAS_HWCKSM, 128, },
-
-	{"3CCFEM656B Cyclone+Winmodem CardBus",
-	 PCI_USES_MASTER, IS_CYCLONE|HAS_NWAY|HAS_CB_FNS|EEPROM_8BIT|INVERT_MII_PWR|
-									INVERT_LED_PWR|HAS_HWCKSM, 128, },
-	{"3CXFEM656C Tornado+Winmodem CardBus",			/* From pcmcia-cs-3.1.5 */
-	 PCI_USES_MASTER, IS_TORNADO|HAS_NWAY|HAS_CB_FNS|EEPROM_8BIT|INVERT_MII_PWR|
-									MAX_COLLISION_RESET|HAS_HWCKSM, 128, },
-	{"3c450 HomePNA Tornado",						/* AKPM: from Don's 0.99Q */
-	 PCI_USES_MASTER, IS_TORNADO|HAS_NWAY|HAS_HWCKSM, 128, },
-	{"3c920 Tornado",
-	 PCI_USES_MASTER, IS_TORNADO|HAS_NWAY|HAS_HWCKSM, 128, },
-	{"3c982 Hydra Dual Port A",
-	 PCI_USES_MASTER, IS_TORNADO|HAS_HWCKSM|HAS_NWAY, 128, },
-
-	{"3c982 Hydra Dual Port B",
-	 PCI_USES_MASTER, IS_TORNADO|HAS_HWCKSM|HAS_NWAY, 128, },
-	{"3c905B-T4",
-	 PCI_USES_MASTER, IS_CYCLONE|HAS_NWAY|HAS_HWCKSM|EXTRA_PREAMBLE, 128, },
-	{"3c920B-EMB-WNM Tornado",
-	 PCI_USES_MASTER, IS_TORNADO|HAS_NWAY|HAS_HWCKSM, 128, },
-
-	{NULL,}, /* NULL terminated list. */
-};
-
-
-static const struct pci_device_id vortex_pci_tbl[] = {
-	{ 0x10B7, 0x5900, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CH_3C590 },
-	{ 0x10B7, 0x5920, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CH_3C592 },
-	{ 0x10B7, 0x5970, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CH_3C597 },
-	{ 0x10B7, 0x5950, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CH_3C595_1 },
-	{ 0x10B7, 0x5951, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CH_3C595_2 },
-
-	{ 0x10B7, 0x5952, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CH_3C595_3 },
-	{ 0x10B7, 0x9000, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CH_3C900_1 },
-	{ 0x10B7, 0x9001, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CH_3C900_2 },
-	{ 0x10B7, 0x9004, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CH_3C900_3 },
-	{ 0x10B7, 0x9005, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CH_3C900_4 },
-
-	{ 0x10B7, 0x9006, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CH_3C900_5 },
-	{ 0x10B7, 0x900A, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CH_3C900B_FL },
-	{ 0x10B7, 0x9050, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CH_3C905_1 },
-	{ 0x10B7, 0x9051, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CH_3C905_2 },
-	{ 0x10B7, 0x9054, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CH_3C905B_TX },
-	{ 0x10B7, 0x9055, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CH_3C905B_1 },
-
-	{ 0x10B7, 0x9058, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CH_3C905B_2 },
-	{ 0x10B7, 0x905A, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CH_3C905B_FX },
-	{ 0x10B7, 0x9200, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CH_3C905C },
-	{ 0x10B7, 0x9202, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CH_3C9202 },
-	{ 0x10B7, 0x9800, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CH_3C980 },
-	{ 0x10B7, 0x9805, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CH_3C9805 },
-
-	{ 0x10B7, 0x7646, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CH_3CSOHO100_TX },
-	{ 0x10B7, 0x5055, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CH_3C555 },
-	{ 0x10B7, 0x6055, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CH_3C556 },
-	{ 0x10B7, 0x6056, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CH_3C556B },
-	{ 0x10B7, 0x5b57, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CH_3C575 },
-
-	{ 0x10B7, 0x5057, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CH_3C575_1 },
-	{ 0x10B7, 0x5157, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CH_3CCFE575 },
-	{ 0x10B7, 0x5257, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CH_3CCFE575CT },
-	{ 0x10B7, 0x6560, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CH_3CCFE656 },
-	{ 0x10B7, 0x6562, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CH_3CCFEM656 },
-
-	{ 0x10B7, 0x6564, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CH_3CCFEM656_1 },
-	{ 0x10B7, 0x4500, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CH_3C450 },
-	{ 0x10B7, 0x9201, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CH_3C920 },
-	{ 0x10B7, 0x1201, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CH_3C982A },
-	{ 0x10B7, 0x1202, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CH_3C982B },
-
-	{ 0x10B7, 0x9056, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CH_905BT4 },
-	{ 0x10B7, 0x9210, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CH_920B_EMB_WNM },
-
-	{0,}						/* 0 terminated list. */
-};
-MODULE_DEVICE_TABLE(pci, vortex_pci_tbl);
-
-
-/* Operational definitions.
-   These are not used by other compilation units and thus are not
-   exported in a ".h" file.
-
-   First the windows.  There are eight register windows, with the command
-   and status registers available in each.
-   */
-#define EL3_CMD 0x0e
-#define EL3_STATUS 0x0e
-
-/* The top five bits written to EL3_CMD are a command, the lower
-   11 bits are the parameter, if applicable.
-   Note that 11 parameters bits was fine for ethernet, but the new chip
-   can handle FDDI length frames (~4500 octets) and now parameters count
-   32-bit 'Dwords' rather than octets. */
-
-enum vortex_cmd {
-	TotalReset = 0<<11, SelectWindow = 1<<11, StartCoax = 2<<11,
-	RxDisable = 3<<11, RxEnable = 4<<11, RxReset = 5<<11,
-	UpStall = 6<<11, UpUnstall = (6<<11)+1,
-	DownStall = (6<<11)+2, DownUnstall = (6<<11)+3,
-	RxDiscard = 8<<11, TxEnable = 9<<11, TxDisable = 10<<11, TxReset = 11<<11,
-	FakeIntr = 12<<11, AckIntr = 13<<11, SetIntrEnb = 14<<11,
-	SetStatusEnb = 15<<11, SetRxFilter = 16<<11, SetRxThreshold = 17<<11,
-	SetTxThreshold = 18<<11, SetTxStart = 19<<11,
-	StartDMAUp = 20<<11, StartDMADown = (20<<11)+1, StatsEnable = 21<<11,
-	StatsDisable = 22<<11, StopCoax = 23<<11, SetFilterBit = 25<<11,};
-
-/* The SetRxFilter command accepts the following classes: */
-enum RxFilter {
-	RxStation = 1, RxMulticast = 2, RxBroadcast = 4, RxProm = 8 };
-
-/* Bits in the general status register. */
-enum vortex_status {
-	IntLatch = 0x0001, HostError = 0x0002, TxComplete = 0x0004,
-	TxAvailable = 0x0008, RxComplete = 0x0010, RxEarly = 0x0020,
-	IntReq = 0x0040, StatsFull = 0x0080,
-	DMADone = 1<<8, DownComplete = 1<<9, UpComplete = 1<<10,
-	DMAInProgress = 1<<11,			/* DMA controller is still busy.*/
-	CmdInProgress = 1<<12,			/* EL3_CMD is still busy.*/
-};
-
-/* Register window 1 offsets, the window used in normal operation.
-   On the Vortex this window is always mapped at offsets 0x10-0x1f. */
-enum Window1 {
-	TX_FIFO = 0x10,  RX_FIFO = 0x10,  RxErrors = 0x14,
-	RxStatus = 0x18,  Timer=0x1A, TxStatus = 0x1B,
-	TxFree = 0x1C, /* Remaining free bytes in Tx buffer. */
-};
-enum Window0 {
-	Wn0EepromCmd = 10,		/* Window 0: EEPROM command register. */
-	Wn0EepromData = 12,		/* Window 0: EEPROM results register. */
-	IntrStatus=0x0E,		/* Valid in all windows. */
-};
-enum Win0_EEPROM_bits {
-	EEPROM_Read = 0x80, EEPROM_WRITE = 0x40, EEPROM_ERASE = 0xC0,
-	EEPROM_EWENB = 0x30,		/* Enable erasing/writing for 10 msec. */
-	EEPROM_EWDIS = 0x00,		/* Disable EWENB before 10 msec timeout. */
-};
-/* EEPROM locations. */
-enum eeprom_offset {
-	PhysAddr01=0, PhysAddr23=1, PhysAddr45=2, ModelID=3,
-	EtherLink3ID=7, IFXcvrIO=8, IRQLine=9,
-	NodeAddr01=10, NodeAddr23=11, NodeAddr45=12,
-	DriverTune=13, Checksum=15};
-
-enum Window2 {			/* Window 2. */
-	Wn2_ResetOptions=12,
-};
-enum Window3 {			/* Window 3: MAC/config bits. */
-	Wn3_Config=0, Wn3_MaxPktSize=4, Wn3_MAC_Ctrl=6, Wn3_Options=8,
-};
-
-#define BFEXT(value, offset, bitcount)  \
-    ((((unsigned long)(value)) >> (offset)) & ((1 << (bitcount)) - 1))
-
-#define BFINS(lhs, rhs, offset, bitcount)					\
-	(((lhs) & ~((((1 << (bitcount)) - 1)) << (offset))) |	\
-	(((rhs) & ((1 << (bitcount)) - 1)) << (offset)))
-
-#define RAM_SIZE(v)		BFEXT(v, 0, 3)
-#define RAM_WIDTH(v)	BFEXT(v, 3, 1)
-#define RAM_SPEED(v)	BFEXT(v, 4, 2)
-#define ROM_SIZE(v)		BFEXT(v, 6, 2)
-#define RAM_SPLIT(v)	BFEXT(v, 16, 2)
-#define XCVR(v)			BFEXT(v, 20, 4)
-#define AUTOSELECT(v)	BFEXT(v, 24, 1)
-
-enum Window4 {		/* Window 4: Xcvr/media bits. */
-	Wn4_FIFODiag = 4, Wn4_NetDiag = 6, Wn4_PhysicalMgmt=8, Wn4_Media = 10,
-};
-enum Win4_Media_bits {
-	Media_SQE = 0x0008,		/* Enable SQE error counting for AUI. */
-	Media_10TP = 0x00C0,	/* Enable link beat and jabber for 10baseT. */
-	Media_Lnk = 0x0080,		/* Enable just link beat for 100TX/100FX. */
-	Media_LnkBeat = 0x0800,
-};
-enum Window7 {					/* Window 7: Bus Master control. */
-	Wn7_MasterAddr = 0, Wn7_VlanEtherType=4, Wn7_MasterLen = 6,
-	Wn7_MasterStatus = 12,
-};
-/* Boomerang bus master control registers. */
-enum MasterCtrl {
-	PktStatus = 0x20, DownListPtr = 0x24, FragAddr = 0x28, FragLen = 0x2c,
-	TxFreeThreshold = 0x2f, UpPktStatus = 0x30, UpListPtr = 0x38,
-};
-
-/* The Rx and Tx descriptor lists.
-   Caution Alpha hackers: these types are 32 bits!  Note also the 8 byte
-   alignment contraint on tx_ring[] and rx_ring[]. */
-#define LAST_FRAG 	0x80000000			/* Last Addr/Len pair in descriptor. */
-#define DN_COMPLETE	0x00010000			/* This packet has been downloaded */
-struct boom_rx_desc {
-	__le32 next;					/* Last entry points to 0.   */
-	__le32 status;
-	__le32 addr;					/* Up to 63 addr/len pairs possible. */
-	__le32 length;					/* Set LAST_FRAG to indicate last pair. */
-};
-/* Values for the Rx status entry. */
-enum rx_desc_status {
-	RxDComplete=0x00008000, RxDError=0x4000,
-	/* See boomerang_rx() for actual error bits */
-	IPChksumErr=1<<25, TCPChksumErr=1<<26, UDPChksumErr=1<<27,
-	IPChksumValid=1<<29, TCPChksumValid=1<<30, UDPChksumValid=1<<31,
-};
-
-#ifdef MAX_SKB_FRAGS
-#define DO_ZEROCOPY 1
-#else
-#define DO_ZEROCOPY 0
-#endif
-
-struct boom_tx_desc {
-	__le32 next;					/* Last entry points to 0.   */
-	__le32 status;					/* bits 0:12 length, others see below.  */
-#if DO_ZEROCOPY
-	struct {
-		__le32 addr;
-		__le32 length;
-	} frag[1+MAX_SKB_FRAGS];
-#else
-		__le32 addr;
-		__le32 length;
-#endif
-};
-
-/* Values for the Tx status entry. */
-enum tx_desc_status {
-	CRCDisable=0x2000, TxDComplete=0x8000,
-	AddIPChksum=0x02000000, AddTCPChksum=0x04000000, AddUDPChksum=0x08000000,
-	TxIntrUploaded=0x80000000,		/* IRQ when in FIFO, but maybe not sent. */
-};
-
-/* Chip features we care about in vp->capabilities, read from the EEPROM. */
-enum ChipCaps { CapBusMaster=0x20, CapPwrMgmt=0x2000 };
-
-struct vortex_extra_stats {
-	unsigned long tx_deferred;
-	unsigned long tx_max_collisions;
-	unsigned long tx_multiple_collisions;
-	unsigned long tx_single_collisions;
-	unsigned long rx_bad_ssd;
-};
-
-struct vortex_private {
-	/* The Rx and Tx rings should be quad-word-aligned. */
-	struct boom_rx_desc* rx_ring;
-	struct boom_tx_desc* tx_ring;
-	dma_addr_t rx_ring_dma;
-	dma_addr_t tx_ring_dma;
-	/* The addresses of transmit- and receive-in-place skbuffs. */
-	struct sk_buff* rx_skbuff[RX_RING_SIZE];
-	struct sk_buff* tx_skbuff[TX_RING_SIZE];
-	unsigned int cur_rx, cur_tx;		/* The next free ring entry */
-	unsigned int dirty_tx;	/* The ring entries to be free()ed. */
-	struct vortex_extra_stats xstats;	/* NIC-specific extra stats */
-	struct sk_buff *tx_skb;				/* Packet being eaten by bus master ctrl.  */
-	dma_addr_t tx_skb_dma;				/* Allocated DMA address for bus master ctrl DMA.   */
-
-	/* PCI configuration space information. */
-	struct device *gendev;
-	void __iomem *ioaddr;			/* IO address space */
-	void __iomem *cb_fn_base;		/* CardBus function status addr space. */
-
-	/* Some values here only for performance evaluation and path-coverage */
-	int rx_nocopy, rx_copy, queued_packet, rx_csumhits;
-	int card_idx;
-
-	/* The remainder are related to chip state, mostly media selection. */
-	struct timer_list timer;			/* Media selection timer. */
-	int options;						/* User-settable misc. driver options. */
-	unsigned int media_override:4, 		/* Passed-in media type. */
-		default_media:4,				/* Read from the EEPROM/Wn3_Config. */
-		full_duplex:1, autoselect:1,
-		bus_master:1,					/* Vortex can only do a fragment bus-m. */
-		full_bus_master_tx:1, full_bus_master_rx:2, /* Boomerang  */
-		flow_ctrl:1,					/* Use 802.3x flow control (PAUSE only) */
-		partner_flow_ctrl:1,			/* Partner supports flow control */
-		has_nway:1,
-		enable_wol:1,					/* Wake-on-LAN is enabled */
-		pm_state_valid:1,				/* pci_dev->saved_config_space has sane contents */
-		open:1,
-		medialock:1,
-		large_frames:1,			/* accept large frames */
-		handling_irq:1;			/* private in_irq indicator */
-	/* {get|set}_wol operations are already serialized by rtnl.
-	 * no additional locking is required for the enable_wol and acpi_set_WOL()
-	 */
-	int drv_flags;
-	u16 status_enable;
-	u16 intr_enable;
-	u16 available_media;				/* From Wn3_Options. */
-	u16 capabilities, info1, info2;		/* Various, from EEPROM. */
-	u16 advertising;					/* NWay media advertisement */
-	unsigned char phys[2];				/* MII device addresses. */
-	u16 deferred;						/* Resend these interrupts when we
-										 * bale from the ISR */
-	u16 io_size;						/* Size of PCI region (for release_region) */
-
-	/* Serialises access to hardware other than MII and variables below.
-	 * The lock hierarchy is rtnl_lock > {lock, mii_lock} > window_lock. */
-	spinlock_t lock;
-
-	spinlock_t mii_lock;		/* Serialises access to MII */
-	struct mii_if_info mii;		/* MII lib hooks/info */
-	spinlock_t window_lock;		/* Serialises access to windowed regs */
-	int window;			/* Register window */
-};
-
-static void window_set(struct vortex_private *vp, int window)
-{
-	if (window != vp->window) {
-		iowrite16(SelectWindow + window, vp->ioaddr + EL3_CMD);
-		vp->window = window;
-	}
-}
-
-#define DEFINE_WINDOW_IO(size)						\
-static u ## size							\
-window_read ## size(struct vortex_private *vp, int window, int addr)	\
-{									\
-	unsigned long flags;						\
-	u ## size ret;							\
-	spin_lock_irqsave(&vp->window_lock, flags);			\
-	window_set(vp, window);						\
-	ret = ioread ## size(vp->ioaddr + addr);			\
-	spin_unlock_irqrestore(&vp->window_lock, flags);		\
-	return ret;							\
-}									\
-static void								\
-window_write ## size(struct vortex_private *vp, u ## size value,	\
-		     int window, int addr)				\
-{									\
-	unsigned long flags;						\
-	spin_lock_irqsave(&vp->window_lock, flags);			\
-	window_set(vp, window);						\
-	iowrite ## size(value, vp->ioaddr + addr);			\
-	spin_unlock_irqrestore(&vp->window_lock, flags);		\
-}
-DEFINE_WINDOW_IO(8)
-DEFINE_WINDOW_IO(16)
-DEFINE_WINDOW_IO(32)
-
-#ifdef CONFIG_PCI
-#define DEVICE_PCI(dev) ((dev_is_pci(dev)) ? to_pci_dev((dev)) : NULL)
-#else
-#define DEVICE_PCI(dev) NULL
-#endif
-
-#define VORTEX_PCI(vp)							\
-	((struct pci_dev *) (((vp)->gendev) ? DEVICE_PCI((vp)->gendev) : NULL))
-
-#ifdef CONFIG_EISA
-#define DEVICE_EISA(dev) (((dev)->bus == &eisa_bus_type) ? to_eisa_device((dev)) : NULL)
-#else
-#define DEVICE_EISA(dev) NULL
-#endif
-
-#define VORTEX_EISA(vp)							\
-	((struct eisa_device *) (((vp)->gendev) ? DEVICE_EISA((vp)->gendev) : NULL))
-
-/* The action to take with a media selection timer tick.
-   Note that we deviate from the 3Com order by checking 10base2 before AUI.
- */
-enum xcvr_types {
-	XCVR_10baseT=0, XCVR_AUI, XCVR_10baseTOnly, XCVR_10base2, XCVR_100baseTx,
-	XCVR_100baseFx, XCVR_MII=6, XCVR_NWAY=8, XCVR_ExtMII=9, XCVR_Default=10,
-};
-
-static const struct media_table {
-	char *name;
-	unsigned int media_bits:16,		/* Bits to set in Wn4_Media register. */
-		mask:8,						/* The transceiver-present bit in Wn3_Config.*/
-		next:8;						/* The media type to try next. */
-	int wait;						/* Time before we check media status. */
-} media_tbl[] = {
-  {	"10baseT",   Media_10TP,0x08, XCVR_10base2, (14*HZ)/10},
-  { "10Mbs AUI", Media_SQE, 0x20, XCVR_Default, (1*HZ)/10},
-  { "undefined", 0,			0x80, XCVR_10baseT, 10000},
-  { "10base2",   0,			0x10, XCVR_AUI,		(1*HZ)/10},
-  { "100baseTX", Media_Lnk, 0x02, XCVR_100baseFx, (14*HZ)/10},
-  { "100baseFX", Media_Lnk, 0x04, XCVR_MII,		(14*HZ)/10},
-  { "MII",		 0,			0x41, XCVR_10baseT, 3*HZ },
-  { "undefined", 0,			0x01, XCVR_10baseT, 10000},
-  { "Autonegotiate", 0,		0x41, XCVR_10baseT, 3*HZ},
-  { "MII-External",	 0,		0x41, XCVR_10baseT, 3*HZ },
-  { "Default",	 0,			0xFF, XCVR_10baseT, 10000},
-};
-
-static struct {
-	const char str[ETH_GSTRING_LEN];
-} ethtool_stats_keys[] = {
-	{ "tx_deferred" },
-	{ "tx_max_collisions" },
-	{ "tx_multiple_collisions" },
-	{ "tx_single_collisions" },
-	{ "rx_bad_ssd" },
-};
-
-/* number of ETHTOOL_GSTATS u64's */
-#define VORTEX_NUM_STATS    5
-
-static int vortex_probe1(struct device *gendev, void __iomem *ioaddr, int irq,
-				   int chip_idx, int card_idx);
-static int vortex_up(struct net_device *dev);
-static void vortex_down(struct net_device *dev, int final);
-static int vortex_open(struct net_device *dev);
-static void mdio_sync(struct vortex_private *vp, int bits);
-static int mdio_read(struct net_device *dev, int phy_id, int location);
-static void mdio_write(struct net_device *vp, int phy_id, int location, int value);
-static void vortex_timer(struct timer_list *t);
-static netdev_tx_t vortex_start_xmit(struct sk_buff *skb,
-				     struct net_device *dev);
-static netdev_tx_t boomerang_start_xmit(struct sk_buff *skb,
-					struct net_device *dev);
-static int vortex_rx(struct net_device *dev);
-static int boomerang_rx(struct net_device *dev);
-static irqreturn_t vortex_boomerang_interrupt(int irq, void *dev_id);
-static irqreturn_t _vortex_interrupt(int irq, struct net_device *dev);
-static irqreturn_t _boomerang_interrupt(int irq, struct net_device *dev);
-static int vortex_close(struct net_device *dev);
-static void dump_tx_ring(struct net_device *dev);
-static void update_stats(void __iomem *ioaddr, struct net_device *dev);
-static struct net_device_stats *vortex_get_stats(struct net_device *dev);
-static void set_rx_mode(struct net_device *dev);
-#ifdef CONFIG_PCI
-static int vortex_ioctl(struct net_device *dev, struct ifreq *rq, int cmd);
-#endif
-static void vortex_tx_timeout(struct net_device *dev, unsigned int txqueue);
-static void acpi_set_WOL(struct net_device *dev);
-static const struct ethtool_ops vortex_ethtool_ops;
-static void set_8021q_mode(struct net_device *dev, int enable);
-
-/* This driver uses 'options' to pass the media type, full-duplex flag, etc. */
-/* Option count limit only -- unlimited interfaces are supported. */
-#define MAX_UNITS 8
-static int options[MAX_UNITS] = { [0 ... MAX_UNITS-1] = -1 };
-static int full_duplex[MAX_UNITS] = {[0 ... MAX_UNITS-1] = -1 };
-static int hw_checksums[MAX_UNITS] = {[0 ... MAX_UNITS-1] = -1 };
-static int flow_ctrl[MAX_UNITS] = {[0 ... MAX_UNITS-1] = -1 };
-static int enable_wol[MAX_UNITS] = {[0 ... MAX_UNITS-1] = -1 };
-static int use_mmio[MAX_UNITS] = {[0 ... MAX_UNITS-1] = -1 };
-static int global_options = -1;
-static int global_full_duplex = -1;
-static int global_enable_wol = -1;
-static int global_use_mmio = -1;
-
-/* Variables to work-around the Compaq PCI BIOS32 problem. */
-static int compaq_ioaddr, compaq_irq, compaq_device_id = 0x5900;
-static struct net_device *compaq_net_device;
-
-static int vortex_cards_found;
-
-module_param(debug, int, 0);
-module_param(global_options, int, 0);
-module_param_array(options, int, NULL, 0);
-module_param(global_full_duplex, int, 0);
-module_param_array(full_duplex, int, NULL, 0);
-module_param_array(hw_checksums, int, NULL, 0);
-module_param_array(flow_ctrl, int, NULL, 0);
-module_param(global_enable_wol, int, 0);
-module_param_array(enable_wol, int, NULL, 0);
-module_param(rx_copybreak, int, 0);
-module_param(max_interrupt_work, int, 0);
-module_param_hw(compaq_ioaddr, int, ioport, 0);
-module_param_hw(compaq_irq, int, irq, 0);
-module_param(compaq_device_id, int, 0);
-module_param(watchdog, int, 0);
-module_param(global_use_mmio, int, 0);
-module_param_array(use_mmio, int, NULL, 0);
-MODULE_PARM_DESC(debug, "3c59x debug level (0-6)");
-MODULE_PARM_DESC(options, "3c59x: Bits 0-3: media type, bit 4: bus mastering, bit 9: full duplex");
-MODULE_PARM_DESC(global_options, "3c59x: same as options, but applies to all NICs if options is unset");
-MODULE_PARM_DESC(full_duplex, "3c59x full duplex setting(s) (1)");
-MODULE_PARM_DESC(global_full_duplex, "3c59x: same as full_duplex, but applies to all NICs if full_duplex is unset");
-MODULE_PARM_DESC(hw_checksums, "3c59x Hardware checksum checking by adapter(s) (0-1)");
-MODULE_PARM_DESC(flow_ctrl, "3c59x 802.3x flow control usage (PAUSE only) (0-1)");
-MODULE_PARM_DESC(enable_wol, "3c59x: Turn on Wake-on-LAN for adapter(s) (0-1)");
-MODULE_PARM_DESC(global_enable_wol, "3c59x: same as enable_wol, but applies to all NICs if enable_wol is unset");
-MODULE_PARM_DESC(rx_copybreak, "3c59x copy breakpoint for copy-only-tiny-frames");
-MODULE_PARM_DESC(max_interrupt_work, "3c59x maximum events handled per interrupt");
-MODULE_PARM_DESC(compaq_ioaddr, "3c59x PCI I/O base address (Compaq BIOS problem workaround)");
-MODULE_PARM_DESC(compaq_irq, "3c59x PCI IRQ number (Compaq BIOS problem workaround)");
-MODULE_PARM_DESC(compaq_device_id, "3c59x PCI device ID (Compaq BIOS problem workaround)");
-MODULE_PARM_DESC(watchdog, "3c59x transmit timeout in milliseconds");
-MODULE_PARM_DESC(global_use_mmio, "3c59x: same as use_mmio, but applies to all NICs if options is unset");
-MODULE_PARM_DESC(use_mmio, "3c59x: use memory-mapped PCI I/O resource (0-1)");
-
-#ifdef CONFIG_NET_POLL_CONTROLLER
-static void poll_vortex(struct net_device *dev)
-{
-	vortex_boomerang_interrupt(dev->irq, dev);
-}
-#endif
-
-#ifdef CONFIG_PM
-
-static int vortex_suspend(struct device *dev)
-{
-	struct net_device *ndev = dev_get_drvdata(dev);
-
-	if (!ndev || !netif_running(ndev))
-		return 0;
-
-	netif_device_detach(ndev);
-	vortex_down(ndev, 1);
-
-	return 0;
-}
-
-static int vortex_resume(struct device *dev)
-{
-	struct net_device *ndev = dev_get_drvdata(dev);
-	int err;
-
-	if (!ndev || !netif_running(ndev))
-		return 0;
-
-	err = vortex_up(ndev);
-	if (err)
-		return err;
-
-	netif_device_attach(ndev);
-
-	return 0;
-}
-
-static const struct dev_pm_ops vortex_pm_ops = {
-	.suspend = vortex_suspend,
-	.resume = vortex_resume,
-	.freeze = vortex_suspend,
-	.thaw = vortex_resume,
-	.poweroff = vortex_suspend,
-	.restore = vortex_resume,
-};
-
-#define VORTEX_PM_OPS (&vortex_pm_ops)
-
-#else /* !CONFIG_PM */
-
-#define VORTEX_PM_OPS NULL
-
-#endif /* !CONFIG_PM */
-
-#ifdef CONFIG_EISA
-static const struct eisa_device_id vortex_eisa_ids[] = {
-	{ "TCM5920", CH_3C592 },
-	{ "TCM5970", CH_3C597 },
-	{ "" }
-};
-MODULE_DEVICE_TABLE(eisa, vortex_eisa_ids);
-
-static int vortex_eisa_probe(struct device *device)
-{
-	void __iomem *ioaddr;
-	struct eisa_device *edev;
-
-	edev = to_eisa_device(device);
-
-	if (!request_region(edev->base_addr, VORTEX_TOTAL_SIZE, DRV_NAME))
-		return -EBUSY;
-
-	ioaddr = ioport_map(edev->base_addr, VORTEX_TOTAL_SIZE);
-
-	if (vortex_probe1(device, ioaddr, ioread16(ioaddr + 0xC88) >> 12,
-					  edev->id.driver_data, vortex_cards_found)) {
-		release_region(edev->base_addr, VORTEX_TOTAL_SIZE);
-		return -ENODEV;
-	}
-
-	vortex_cards_found++;
-
-	return 0;
-}
-
-static int vortex_eisa_remove(struct device *device)
-{
-	struct eisa_device *edev;
-	struct net_device *dev;
-	struct vortex_private *vp;
-	void __iomem *ioaddr;
-
-	edev = to_eisa_device(device);
-	dev = eisa_get_drvdata(edev);
-
-	if (!dev) {
-		pr_err("vortex_eisa_remove called for Compaq device!\n");
-		BUG();
-	}
-
-	vp = netdev_priv(dev);
-	ioaddr = vp->ioaddr;
-
-	unregister_netdev(dev);
-	iowrite16(TotalReset|0x14, ioaddr + EL3_CMD);
-	release_region(edev->base_addr, VORTEX_TOTAL_SIZE);
-
-	free_netdev(dev);
-	return 0;
-}
-
-static struct eisa_driver vortex_eisa_driver = {
-	.id_table = vortex_eisa_ids,
-	.driver   = {
-		.name    = "3c59x",
-		.probe   = vortex_eisa_probe,
-		.remove  = vortex_eisa_remove
-	}
-};
-
-#endif /* CONFIG_EISA */
-
-/* returns count found (>= 0), or negative on error */
-static int __init vortex_eisa_init(void)
-{
-	int eisa_found = 0;
-	int orig_cards_found = vortex_cards_found;
-
-#ifdef CONFIG_EISA
-	int err;
-
-	err = eisa_driver_register (&vortex_eisa_driver);
-	if (!err) {
-		/*
-		 * Because of the way EISA bus is probed, we cannot assume
-		 * any device have been found when we exit from
-		 * eisa_driver_register (the bus root driver may not be
-		 * initialized yet). So we blindly assume something was
-		 * found, and let the sysfs magic happened...
-		 */
-		eisa_found = 1;
-	}
-#endif
-
-	/* Special code to work-around the Compaq PCI BIOS32 problem. */
-	if (compaq_ioaddr) {
-		vortex_probe1(NULL, ioport_map(compaq_ioaddr, VORTEX_TOTAL_SIZE),
-			      compaq_irq, compaq_device_id, vortex_cards_found++);
-	}
-
-	return vortex_cards_found - orig_cards_found + eisa_found;
-}
-
-/* returns count (>= 0), or negative on error */
-static int vortex_init_one(struct pci_dev *pdev,
-			   const struct pci_device_id *ent)
-{
-	int rc, unit, pci_bar;
-	struct vortex_chip_info *vci;
-	void __iomem *ioaddr;
-
-	/* wake up and enable device */
-	rc = pci_enable_device(pdev);
-	if (rc < 0)
-		goto out;
-
-	rc = pci_request_regions(pdev, DRV_NAME);
-	if (rc < 0)
-		goto out_disable;
-
-	unit = vortex_cards_found;
-
-	if (global_use_mmio < 0 && (unit >= MAX_UNITS || use_mmio[unit] < 0)) {
-		/* Determine the default if the user didn't override us */
-		vci = &vortex_info_tbl[ent->driver_data];
-		pci_bar = vci->drv_flags & (IS_CYCLONE | IS_TORNADO) ? 1 : 0;
-	} else if (unit < MAX_UNITS && use_mmio[unit] >= 0)
-		pci_bar = use_mmio[unit] ? 1 : 0;
-	else
-		pci_bar = global_use_mmio ? 1 : 0;
-
-	ioaddr = pci_iomap(pdev, pci_bar, 0);
-	if (!ioaddr) /* If mapping fails, fall-back to BAR 0... */
-		ioaddr = pci_iomap(pdev, 0, 0);
-	if (!ioaddr) {
-		rc = -ENOMEM;
-		goto out_release;
-	}
-
-	rc = vortex_probe1(&pdev->dev, ioaddr, pdev->irq,
-			   ent->driver_data, unit);
-	if (rc < 0)
-		goto out_iounmap;
-
-	vortex_cards_found++;
-	goto out;
-
-out_iounmap:
-	pci_iounmap(pdev, ioaddr);
-out_release:
-	pci_release_regions(pdev);
-out_disable:
-	pci_disable_device(pdev);
-out:
-	return rc;
-}
-
-static const struct net_device_ops boomrang_netdev_ops = {
-	.ndo_open		= vortex_open,
-	.ndo_stop		= vortex_close,
-	.ndo_start_xmit		= boomerang_start_xmit,
-	.ndo_tx_timeout		= vortex_tx_timeout,
-	.ndo_get_stats		= vortex_get_stats,
-#ifdef CONFIG_PCI
-	.ndo_eth_ioctl		= vortex_ioctl,
-#endif
-	.ndo_set_rx_mode	= set_rx_mode,
-	.ndo_set_mac_address 	= eth_mac_addr,
-	.ndo_validate_addr	= eth_validate_addr,
-#ifdef CONFIG_NET_POLL_CONTROLLER
-	.ndo_poll_controller	= poll_vortex,
-#endif
-};
-
-static const struct net_device_ops vortex_netdev_ops = {
-	.ndo_open		= vortex_open,
-	.ndo_stop		= vortex_close,
-	.ndo_start_xmit		= vortex_start_xmit,
-	.ndo_tx_timeout		= vortex_tx_timeout,
-	.ndo_get_stats		= vortex_get_stats,
-#ifdef CONFIG_PCI
-	.ndo_eth_ioctl		= vortex_ioctl,
-#endif
-	.ndo_set_rx_mode	= set_rx_mode,
-	.ndo_set_mac_address 	= eth_mac_addr,
-	.ndo_validate_addr	= eth_validate_addr,
-#ifdef CONFIG_NET_POLL_CONTROLLER
-	.ndo_poll_controller	= poll_vortex,
-#endif
-};
-
-/*
- * Start up the PCI/EISA device which is described by *gendev.
- * Return 0 on success.
- *
- * NOTE: pdev can be NULL, for the case of a Compaq device
- */
-static int vortex_probe1(struct device *gendev, void __iomem *ioaddr, int irq,
-			 int chip_idx, int card_idx)
-{
-	struct vortex_private *vp;
-	int option;
-	unsigned int eeprom[0x40], checksum = 0;		/* EEPROM contents */
-	__be16 addr[ETH_ALEN / 2];
-	int i, step;
-	struct net_device *dev;
-	static int printed_version;
-	int retval, print_info;
-	struct vortex_chip_info * const vci = &vortex_info_tbl[chip_idx];
-	const char *print_name = "3c59x";
-	struct pci_dev *pdev = NULL;
-	struct eisa_device *edev = NULL;
-
-	if (!printed_version) {
-		pr_info("%s", version);
-		printed_version = 1;
-	}
-
-	if (gendev) {
-		if ((pdev = DEVICE_PCI(gendev))) {
-			print_name = pci_name(pdev);
-		}
-
-		if ((edev = DEVICE_EISA(gendev))) {
-			print_name = dev_name(&edev->dev);
-		}
-	}
-
-	dev = alloc_etherdev(sizeof(*vp));
-	retval = -ENOMEM;
-	if (!dev)
-		goto out;
-
-	SET_NETDEV_DEV(dev, gendev);
-	vp = netdev_priv(dev);
-
-	option = global_options;
-
-	/* The lower four bits are the media type. */
-	if (dev->mem_start) {
-		/*
-		 * The 'options' param is passed in as the third arg to the
-		 * LILO 'ether=' argument for non-modular use
-		 */
-		option = dev->mem_start;
-	}
-	else if (card_idx < MAX_UNITS) {
-		if (options[card_idx] >= 0)
-			option = options[card_idx];
-	}
-
-	if (option > 0) {
-		if (option & 0x8000)
-			vortex_debug = 7;
-		if (option & 0x4000)
-			vortex_debug = 2;
-		if (option & 0x0400)
-			vp->enable_wol = 1;
-	}
-
-	print_info = (vortex_debug > 1);
-	if (print_info)
-		pr_info("See Documentation/networking/device_drivers/ethernet/3com/vortex.rst\n");
-
-	pr_info("%s: 3Com %s %s at %p.\n",
-	       print_name,
-	       pdev ? "PCI" : "EISA",
-	       vci->name,
-	       ioaddr);
-
-	dev->base_addr = (unsigned long)ioaddr;
-	dev->irq = irq;
-	dev->mtu = mtu;
-	vp->ioaddr = ioaddr;
-	vp->large_frames = mtu > 1500;
-	vp->drv_flags = vci->drv_flags;
-	vp->has_nway = (vci->drv_flags & HAS_NWAY) ? 1 : 0;
-	vp->io_size = vci->io_size;
-	vp->card_idx = card_idx;
-	vp->window = -1;
-
-	/* module list only for Compaq device */
-	if (gendev == NULL) {
-		compaq_net_device = dev;
-	}
-
-	/* PCI-only startup logic */
-	if (pdev) {
-		/* enable bus-mastering if necessary */
-		if (vci->flags & PCI_USES_MASTER)
-			pci_set_master(pdev);
-
-		if (vci->drv_flags & IS_VORTEX) {
-			u8 pci_latency;
-			u8 new_latency = 248;
-
-			/* Check the PCI latency value.  On the 3c590 series the latency timer
-			   must be set to the maximum value to avoid data corruption that occurs
-			   when the timer expires during a transfer.  This bug exists the Vortex
-			   chip only. */
-			pci_read_config_byte(pdev, PCI_LATENCY_TIMER, &pci_latency);
-			if (pci_latency < new_latency) {
-				pr_info("%s: Overriding PCI latency timer (CFLT) setting of %d, new value is %d.\n",
-					print_name, pci_latency, new_latency);
-				pci_write_config_byte(pdev, PCI_LATENCY_TIMER, new_latency);
-			}
-		}
-	}
-
-	spin_lock_init(&vp->lock);
-	spin_lock_init(&vp->mii_lock);
-	spin_lock_init(&vp->window_lock);
-	vp->gendev = gendev;
-	vp->mii.dev = dev;
-	vp->mii.mdio_read = mdio_read;
-	vp->mii.mdio_write = mdio_write;
-	vp->mii.phy_id_mask = 0x1f;
-	vp->mii.reg_num_mask = 0x1f;
-
-	/* Makes sure rings are at least 16 byte aligned. */
-	vp->rx_ring = dma_alloc_coherent(gendev, sizeof(struct boom_rx_desc) * RX_RING_SIZE
-					   + sizeof(struct boom_tx_desc) * TX_RING_SIZE,
-					   &vp->rx_ring_dma, GFP_KERNEL);
-	retval = -ENOMEM;
-	if (!vp->rx_ring)
-		goto free_device;
-
-	vp->tx_ring = (struct boom_tx_desc *)(vp->rx_ring + RX_RING_SIZE);
-	vp->tx_ring_dma = vp->rx_ring_dma + sizeof(struct boom_rx_desc) * RX_RING_SIZE;
-
-	/* if we are a PCI driver, we store info in pdev->driver_data
-	 * instead of a module list */
-	if (pdev)
-		pci_set_drvdata(pdev, dev);
-	if (edev)
-		eisa_set_drvdata(edev, dev);
-
-	vp->media_override = 7;
-	if (option >= 0) {
-		vp->media_override = ((option & 7) == 2)  ?  0  :  option & 15;
-		if (vp->media_override != 7)
-			vp->medialock = 1;
-		vp->full_duplex = (option & 0x200) ? 1 : 0;
-		vp->bus_master = (option & 16) ? 1 : 0;
-	}
-
-	if (global_full_duplex > 0)
-		vp->full_duplex = 1;
-	if (global_enable_wol > 0)
-		vp->enable_wol = 1;
-
-	if (card_idx < MAX_UNITS) {
-		if (full_duplex[card_idx] > 0)
-			vp->full_duplex = 1;
-		if (flow_ctrl[card_idx] > 0)
-			vp->flow_ctrl = 1;
-		if (enable_wol[card_idx] > 0)
-			vp->enable_wol = 1;
-	}
-
-	vp->mii.force_media = vp->full_duplex;
-	vp->options = option;
-	/* Read the station address from the EEPROM. */
-	{
-		int base;
-
-		if (vci->drv_flags & EEPROM_8BIT)
-			base = 0x230;
-		else if (vci->drv_flags & EEPROM_OFFSET)
-			base = EEPROM_Read + 0x30;
-		else
-			base = EEPROM_Read;
-
-		for (i = 0; i < 0x40; i++) {
-			int timer;
-			window_write16(vp, base + i, 0, Wn0EepromCmd);
-			/* Pause for at least 162 us. for the read to take place. */
-			for (timer = 10; timer >= 0; timer--) {
-				udelay(162);
-				if ((window_read16(vp, 0, Wn0EepromCmd) &
-				     0x8000) == 0)
-					break;
-			}
-			eeprom[i] = window_read16(vp, 0, Wn0EepromData);
-		}
-	}
-	for (i = 0; i < 0x18; i++)
-		checksum ^= eeprom[i];
-	checksum = (checksum ^ (checksum >> 8)) & 0xff;
-	if (checksum != 0x00) {		/* Grrr, needless incompatible change 3Com. */
-		while (i < 0x21)
-			checksum ^= eeprom[i++];
-		checksum = (checksum ^ (checksum >> 8)) & 0xff;
-	}
-	if ((checksum != 0x00) && !(vci->drv_flags & IS_TORNADO))
-		pr_cont(" ***INVALID CHECKSUM %4.4x*** ", checksum);
-	for (i = 0; i < 3; i++)
-		addr[i] = htons(eeprom[i + 10]);
-	eth_hw_addr_set(dev, (u8 *)addr);
-	if (print_info)
-		pr_cont(" %pM", dev->dev_addr);
-	/* Unfortunately an all zero eeprom passes the checksum and this
-	   gets found in the wild in failure cases. Crypto is hard 8) */
-	if (!is_valid_ether_addr(dev->dev_addr)) {
-		retval = -EINVAL;
-		pr_err("*** EEPROM MAC address is invalid.\n");
-		goto free_ring;	/* With every pack */
-	}
-	for (i = 0; i < 6; i++)
-		window_write8(vp, dev->dev_addr[i], 2, i);
-
-	if (print_info)
-		pr_cont(", IRQ %d\n", dev->irq);
-	/* Tell them about an invalid IRQ. */
-	if (dev->irq <= 0 || dev->irq >= irq_get_nr_irqs())
-		pr_warn(" *** Warning: IRQ %d is unlikely to work! ***\n",
-			dev->irq);
-
-	step = (window_read8(vp, 4, Wn4_NetDiag) & 0x1e) >> 1;
-	if (print_info) {
-		pr_info("  product code %02x%02x rev %02x.%d date %02d-%02d-%02d\n",
-			eeprom[6]&0xff, eeprom[6]>>8, eeprom[0x14],
-			step, (eeprom[4]>>5) & 15, eeprom[4] & 31, eeprom[4]>>9);
-	}
-
-
-	if (pdev && vci->drv_flags & HAS_CB_FNS) {
-		unsigned short n;
-
-		vp->cb_fn_base = pci_iomap(pdev, 2, 0);
-		if (!vp->cb_fn_base) {
-			retval = -ENOMEM;
-			goto free_ring;
-		}
-
-		if (print_info) {
-			pr_info("%s: CardBus functions mapped %16.16llx->%p\n",
-				print_name,
-				(unsigned long long)pci_resource_start(pdev, 2),
-				vp->cb_fn_base);
-		}
-
-		n = window_read16(vp, 2, Wn2_ResetOptions) & ~0x4010;
-		if (vp->drv_flags & INVERT_LED_PWR)
-			n |= 0x10;
-		if (vp->drv_flags & INVERT_MII_PWR)
-			n |= 0x4000;
-		window_write16(vp, n, 2, Wn2_ResetOptions);
-		if (vp->drv_flags & WNO_XCVR_PWR) {
-			window_write16(vp, 0x0800, 0, 0);
-		}
-	}
-
-	/* Extract our information from the EEPROM data. */
-	vp->info1 = eeprom[13];
-	vp->info2 = eeprom[15];
-	vp->capabilities = eeprom[16];
-
-	if (vp->info1 & 0x8000) {
-		vp->full_duplex = 1;
-		if (print_info)
-			pr_info("Full duplex capable\n");
-	}
-
-	{
-		static const char * const ram_split[] = {"5:3", "3:1", "1:1", "3:5"};
-		unsigned int config;
-		vp->available_media = window_read16(vp, 3, Wn3_Options);
-		if ((vp->available_media & 0xff) == 0)		/* Broken 3c916 */
-			vp->available_media = 0x40;
-		config = window_read32(vp, 3, Wn3_Config);
-		if (print_info) {
-			pr_debug("  Internal config register is %4.4x, transceivers %#x.\n",
-				config, window_read16(vp, 3, Wn3_Options));
-			pr_info("  %dK %s-wide RAM %s Rx:Tx split, %s%s interface.\n",
-				   8 << RAM_SIZE(config),
-				   RAM_WIDTH(config) ? "word" : "byte",
-				   ram_split[RAM_SPLIT(config)],
-				   AUTOSELECT(config) ? "autoselect/" : "",
-				   XCVR(config) > XCVR_ExtMII ? "<invalid transceiver>" :
-				   media_tbl[XCVR(config)].name);
-		}
-		vp->default_media = XCVR(config);
-		if (vp->default_media == XCVR_NWAY)
-			vp->has_nway = 1;
-		vp->autoselect = AUTOSELECT(config);
-	}
-
-	if (vp->media_override != 7) {
-		pr_info("%s:  Media override to transceiver type %d (%s).\n",
-				print_name, vp->media_override,
-				media_tbl[vp->media_override].name);
-		dev->if_port = vp->media_override;
-	} else
-		dev->if_port = vp->default_media;
-
-	if ((vp->available_media & 0x40) || (vci->drv_flags & HAS_NWAY) ||
-		dev->if_port == XCVR_MII || dev->if_port == XCVR_NWAY) {
-		int phy, phy_idx = 0;
-		mii_preamble_required++;
-		if (vp->drv_flags & EXTRA_PREAMBLE)
-			mii_preamble_required++;
-		mdio_sync(vp, 32);
-		mdio_read(dev, 24, MII_BMSR);
-		for (phy = 0; phy < 32 && phy_idx < 1; phy++) {
-			int mii_status, phyx;
-
-			/*
-			 * For the 3c905CX we look at index 24 first, because it bogusly
-			 * reports an external PHY at all indices
-			 */
-			if (phy == 0)
-				phyx = 24;
-			else if (phy <= 24)
-				phyx = phy - 1;
-			else
-				phyx = phy;
-			mii_status = mdio_read(dev, phyx, MII_BMSR);
-			if (mii_status  &&  mii_status != 0xffff) {
-				vp->phys[phy_idx++] = phyx;
-				if (print_info) {
-					pr_info("  MII transceiver found at address %d, status %4x.\n",
-						phyx, mii_status);
-				}
-				if ((mii_status & 0x0040) == 0)
-					mii_preamble_required++;
-			}
-		}
-		mii_preamble_required--;
-		if (phy_idx == 0) {
-			pr_warn("  ***WARNING*** No MII transceivers found!\n");
-			vp->phys[0] = 24;
-		} else {
-			vp->advertising = mdio_read(dev, vp->phys[0], MII_ADVERTISE);
-			if (vp->full_duplex) {
-				/* Only advertise the FD media types. */
-				vp->advertising &= ~0x02A0;
-				mdio_write(dev, vp->phys[0], 4, vp->advertising);
-			}
-		}
-		vp->mii.phy_id = vp->phys[0];
-	}
-
-	if (vp->capabilities & CapBusMaster) {
-		vp->full_bus_master_tx = 1;
-		if (print_info) {
-			pr_info("  Enabling bus-master transmits and %s receives.\n",
-			(vp->info2 & 1) ? "early" : "whole-frame" );
-		}
-		vp->full_bus_master_rx = (vp->info2 & 1) ? 1 : 2;
-		vp->bus_master = 0;		/* AKPM: vortex only */
-	}
-
-	/* The 3c59x-specific entries in the device structure. */
-	if (vp->full_bus_master_tx) {
-		dev->netdev_ops = &boomrang_netdev_ops;
-		/* Actually, it still should work with iommu. */
-		if (card_idx < MAX_UNITS &&
-		    ((hw_checksums[card_idx] == -1 && (vp->drv_flags & HAS_HWCKSM)) ||
-				hw_checksums[card_idx] == 1)) {
-			dev->features |= NETIF_F_IP_CSUM | NETIF_F_SG;
-		}
-	} else
-		dev->netdev_ops =  &vortex_netdev_ops;
-
-	if (print_info) {
-		pr_info("%s: scatter/gather %sabled. h/w checksums %sabled\n",
-				print_name,
-				(dev->features & NETIF_F_SG) ? "en":"dis",
-				(dev->features & NETIF_F_IP_CSUM) ? "en":"dis");
-	}
-
-	dev->ethtool_ops = &vortex_ethtool_ops;
-	dev->watchdog_timeo = (watchdog * HZ) / 1000;
-
-	if (pdev) {
-		vp->pm_state_valid = 1;
-		pci_save_state(pdev);
-		acpi_set_WOL(dev);
-	}
-	retval = register_netdev(dev);
-	if (retval == 0)
-		return 0;
-
-free_ring:
-	dma_free_coherent(gendev,
-		sizeof(struct boom_rx_desc) * RX_RING_SIZE +
-		sizeof(struct boom_tx_desc) * TX_RING_SIZE,
-		vp->rx_ring, vp->rx_ring_dma);
-free_device:
-	free_netdev(dev);
-	pr_err(PFX "vortex_probe1 fails.  Returns %d\n", retval);
-out:
-	return retval;
-}
-
-static void
-issue_and_wait(struct net_device *dev, int cmd)
-{
-	struct vortex_private *vp = netdev_priv(dev);
-	void __iomem *ioaddr = vp->ioaddr;
-	int i;
-
-	iowrite16(cmd, ioaddr + EL3_CMD);
-	for (i = 0; i < 2000; i++) {
-		if (!(ioread16(ioaddr + EL3_STATUS) & CmdInProgress))
-			return;
-	}
-
-	/* OK, that didn't work.  Do it the slow way.  One second */
-	for (i = 0; i < 100000; i++) {
-		if (!(ioread16(ioaddr + EL3_STATUS) & CmdInProgress)) {
-			if (vortex_debug > 1)
-				pr_info("%s: command 0x%04x took %d usecs\n",
-					   dev->name, cmd, i * 10);
-			return;
-		}
-		udelay(10);
-	}
-	pr_err("%s: command 0x%04x did not complete! Status=0x%x\n",
-			   dev->name, cmd, ioread16(ioaddr + EL3_STATUS));
-}
-
-static void
-vortex_set_duplex(struct net_device *dev)
-{
-	struct vortex_private *vp = netdev_priv(dev);
-
-	pr_info("%s:  setting %s-duplex.\n",
-		dev->name, (vp->full_duplex) ? "full" : "half");
-
-	/* Set the full-duplex bit. */
-	window_write16(vp,
-		       ((vp->info1 & 0x8000) || vp->full_duplex ? 0x20 : 0) |
-		       (vp->large_frames ? 0x40 : 0) |
-		       ((vp->full_duplex && vp->flow_ctrl && vp->partner_flow_ctrl) ?
-			0x100 : 0),
-		       3, Wn3_MAC_Ctrl);
-}
-
-static void vortex_check_media(struct net_device *dev, unsigned int init)
-{
-	struct vortex_private *vp = netdev_priv(dev);
-	unsigned int ok_to_print = 0;
-
-	if (vortex_debug > 3)
-		ok_to_print = 1;
-
-	if (mii_check_media(&vp->mii, ok_to_print, init)) {
-		vp->full_duplex = vp->mii.full_duplex;
-		vortex_set_duplex(dev);
-	} else if (init) {
-		vortex_set_duplex(dev);
-	}
-}
-
-static int
-vortex_up(struct net_device *dev)
-{
-	struct vortex_private *vp = netdev_priv(dev);
-	void __iomem *ioaddr = vp->ioaddr;
-	unsigned int config;
-	int i, mii_reg5, err = 0;
-
-	if (VORTEX_PCI(vp)) {
-		pci_set_power_state(VORTEX_PCI(vp), PCI_D0);	/* Go active */
-		if (vp->pm_state_valid)
-			pci_restore_state(VORTEX_PCI(vp));
-		err = pci_enable_device(VORTEX_PCI(vp));
-		if (err) {
-			pr_warn("%s: Could not enable device\n", dev->name);
-			goto err_out;
-		}
-	}
-
-	/* Before initializing select the active media port. */
-	config = window_read32(vp, 3, Wn3_Config);
-
-	if (vp->media_override != 7) {
-		pr_info("%s: Media override to transceiver %d (%s).\n",
-			   dev->name, vp->media_override,
-			   media_tbl[vp->media_override].name);
-		dev->if_port = vp->media_override;
-	} else if (vp->autoselect) {
-		if (vp->has_nway) {
-			if (vortex_debug > 1)
-				pr_info("%s: using NWAY device table, not %d\n",
-								dev->name, dev->if_port);
-			dev->if_port = XCVR_NWAY;
-		} else {
-			/* Find first available media type, starting with 100baseTx. */
-			dev->if_port = XCVR_100baseTx;
-			while (! (vp->available_media & media_tbl[dev->if_port].mask))
-				dev->if_port = media_tbl[dev->if_port].next;
-			if (vortex_debug > 1)
-				pr_info("%s: first available media type: %s\n",
-					dev->name, media_tbl[dev->if_port].name);
-		}
-	} else {
-		dev->if_port = vp->default_media;
-		if (vortex_debug > 1)
-			pr_info("%s: using default media %s\n",
-				dev->name, media_tbl[dev->if_port].name);
-	}
-
-	timer_setup(&vp->timer, vortex_timer, 0);
-	mod_timer(&vp->timer, RUN_AT(media_tbl[dev->if_port].wait));
-
-	if (vortex_debug > 1)
-		pr_debug("%s: Initial media type %s.\n",
-			   dev->name, media_tbl[dev->if_port].name);
-
-	vp->full_duplex = vp->mii.force_media;
-	config = BFINS(config, dev->if_port, 20, 4);
-	if (vortex_debug > 6)
-		pr_debug("vortex_up(): writing 0x%x to InternalConfig\n", config);
-	window_write32(vp, config, 3, Wn3_Config);
-
-	if (dev->if_port == XCVR_MII || dev->if_port == XCVR_NWAY) {
-		mdio_read(dev, vp->phys[0], MII_BMSR);
-		mii_reg5 = mdio_read(dev, vp->phys[0], MII_LPA);
-		vp->partner_flow_ctrl = ((mii_reg5 & 0x0400) != 0);
-		vp->mii.full_duplex = vp->full_duplex;
-
-		vortex_check_media(dev, 1);
-	}
-	else
-		vortex_set_duplex(dev);
-
-	issue_and_wait(dev, TxReset);
-	/*
-	 * Don't reset the PHY - that upsets autonegotiation during DHCP operations.
-	 */
-	issue_and_wait(dev, RxReset|0x04);
-
-
-	iowrite16(SetStatusEnb | 0x00, ioaddr + EL3_CMD);
-
-	if (vortex_debug > 1) {
-		pr_debug("%s: vortex_up() irq %d media status %4.4x.\n",
-			   dev->name, dev->irq, window_read16(vp, 4, Wn4_Media));
-	}
-
-	/* Set the station address and mask in window 2 each time opened. */
-	for (i = 0; i < 6; i++)
-		window_write8(vp, dev->dev_addr[i], 2, i);
-	for (; i < 12; i+=2)
-		window_write16(vp, 0, 2, i);
-
-	if (vp->cb_fn_base) {
-		unsigned short n = window_read16(vp, 2, Wn2_ResetOptions) & ~0x4010;
-		if (vp->drv_flags & INVERT_LED_PWR)
-			n |= 0x10;
-		if (vp->drv_flags & INVERT_MII_PWR)
-			n |= 0x4000;
-		window_write16(vp, n, 2, Wn2_ResetOptions);
-	}
-
-	if (dev->if_port == XCVR_10base2)
-		/* Start the thinnet transceiver. We should really wait 50ms...*/
-		iowrite16(StartCoax, ioaddr + EL3_CMD);
-	if (dev->if_port != XCVR_NWAY) {
-		window_write16(vp,
-			       (window_read16(vp, 4, Wn4_Media) &
-				~(Media_10TP|Media_SQE)) |
-			       media_tbl[dev->if_port].media_bits,
-			       4, Wn4_Media);
-	}
-
-	/* Switch to the stats window, and clear all stats by reading. */
-	iowrite16(StatsDisable, ioaddr + EL3_CMD);
-	for (i = 0; i < 10; i++)
-		window_read8(vp, 6, i);
-	window_read16(vp, 6, 10);
-	window_read16(vp, 6, 12);
-	/* New: On the Vortex we must also clear the BadSSD counter. */
-	window_read8(vp, 4, 12);
-	/* ..and on the Boomerang we enable the extra statistics bits. */
-	window_write16(vp, 0x0040, 4, Wn4_NetDiag);
-
-	if (vp->full_bus_master_rx) { /* Boomerang bus master. */
-		vp->cur_rx = 0;
-		/* Initialize the RxEarly register as recommended. */
-		iowrite16(SetRxThreshold + (1536>>2), ioaddr + EL3_CMD);
-		iowrite32(0x0020, ioaddr + PktStatus);
-		iowrite32(vp->rx_ring_dma, ioaddr + UpListPtr);
-	}
-	if (vp->full_bus_master_tx) { 		/* Boomerang bus master Tx. */
-		vp->cur_tx = vp->dirty_tx = 0;
-		if (vp->drv_flags & IS_BOOMERANG)
-			iowrite8(PKT_BUF_SZ>>8, ioaddr + TxFreeThreshold); /* Room for a packet. */
-		/* Clear the Rx, Tx rings. */
-		for (i = 0; i < RX_RING_SIZE; i++)	/* AKPM: this is done in vortex_open, too */
-			vp->rx_ring[i].status = 0;
-		for (i = 0; i < TX_RING_SIZE; i++)
-			vp->tx_skbuff[i] = NULL;
-		iowrite32(0, ioaddr + DownListPtr);
-	}
-	/* Set receiver mode: presumably accept b-case and phys addr only. */
-	set_rx_mode(dev);
-	/* enable 802.1q tagged frames */
-	set_8021q_mode(dev, 1);
-	iowrite16(StatsEnable, ioaddr + EL3_CMD); /* Turn on statistics. */
-
-	iowrite16(RxEnable, ioaddr + EL3_CMD); /* Enable the receiver. */
-	iowrite16(TxEnable, ioaddr + EL3_CMD); /* Enable transmitter. */
-	/* Allow status bits to be seen. */
-	vp->status_enable = SetStatusEnb | HostError|IntReq|StatsFull|TxComplete|
-		(vp->full_bus_master_tx ? DownComplete : TxAvailable) |
-		(vp->full_bus_master_rx ? UpComplete : RxComplete) |
-		(vp->bus_master ? DMADone : 0);
-	vp->intr_enable = SetIntrEnb | IntLatch | TxAvailable |
-		(vp->full_bus_master_rx ? 0 : RxComplete) |
-		StatsFull | HostError | TxComplete | IntReq
-		| (vp->bus_master ? DMADone : 0) | UpComplete | DownComplete;
-	iowrite16(vp->status_enable, ioaddr + EL3_CMD);
-	/* Ack all pending events, and set active indicator mask. */
-	iowrite16(AckIntr | IntLatch | TxAvailable | RxEarly | IntReq,
-		 ioaddr + EL3_CMD);
-	iowrite16(vp->intr_enable, ioaddr + EL3_CMD);
-	if (vp->cb_fn_base)			/* The PCMCIA people are idiots.  */
-		iowrite32(0x8000, vp->cb_fn_base + 4);
-	netif_start_queue (dev);
-	netdev_reset_queue(dev);
-err_out:
-	return err;
-}
-
-static int
-vortex_open(struct net_device *dev)
-{
-	struct vortex_private *vp = netdev_priv(dev);
-	int i;
-	int retval;
-	dma_addr_t dma;
-
-	/* Use the now-standard shared IRQ implementation. */
-	if ((retval = request_irq(dev->irq, vortex_boomerang_interrupt, IRQF_SHARED, dev->name, dev))) {
-		pr_err("%s: Could not reserve IRQ %d\n", dev->name, dev->irq);
-		goto err;
-	}
-
-	if (vp->full_bus_master_rx) { /* Boomerang bus master. */
-		if (vortex_debug > 2)
-			pr_debug("%s:  Filling in the Rx ring.\n", dev->name);
-		for (i = 0; i < RX_RING_SIZE; i++) {
-			struct sk_buff *skb;
-			vp->rx_ring[i].next = cpu_to_le32(vp->rx_ring_dma + sizeof(struct boom_rx_desc) * (i+1));
-			vp->rx_ring[i].status = 0;	/* Clear complete bit. */
-			vp->rx_ring[i].length = cpu_to_le32(PKT_BUF_SZ | LAST_FRAG);
-
-			skb = __netdev_alloc_skb(dev, PKT_BUF_SZ + NET_IP_ALIGN,
-						 GFP_KERNEL);
-			vp->rx_skbuff[i] = skb;
-			if (skb == NULL)
-				break;			/* Bad news!  */
-
-			skb_reserve(skb, NET_IP_ALIGN);	/* Align IP on 16 byte boundaries */
-			dma = dma_map_single(vp->gendev, skb->data,
-					     PKT_BUF_SZ, DMA_FROM_DEVICE);
-			if (dma_mapping_error(vp->gendev, dma))
-				break;
-			vp->rx_ring[i].addr = cpu_to_le32(dma);
-		}
-		if (i != RX_RING_SIZE) {
-			pr_emerg("%s: no memory for rx ring\n", dev->name);
-			retval = -ENOMEM;
-			goto err_free_skb;
-		}
-		/* Wrap the ring. */
-		vp->rx_ring[i-1].next = cpu_to_le32(vp->rx_ring_dma);
-	}
-
-	retval = vortex_up(dev);
-	if (!retval)
-		goto out;
-
-err_free_skb:
-	for (i = 0; i < RX_RING_SIZE; i++) {
-		if (vp->rx_skbuff[i]) {
-			dev_kfree_skb(vp->rx_skbuff[i]);
-			vp->rx_skbuff[i] = NULL;
-		}
-	}
-	free_irq(dev->irq, dev);
-err:
-	if (vortex_debug > 1)
-		pr_err("%s: vortex_open() fails: returning %d\n", dev->name, retval);
-out:
-	return retval;
-}
-
-static void
-vortex_timer(struct timer_list *t)
-{
-	struct vortex_private *vp = timer_container_of(vp, t, timer);
-	struct net_device *dev = vp->mii.dev;
-	void __iomem *ioaddr = vp->ioaddr;
-	int next_tick = 60*HZ;
-	int ok = 0;
-	int media_status;
-
-	if (vortex_debug > 2) {
-		pr_debug("%s: Media selection timer tick happened, %s.\n",
-			   dev->name, media_tbl[dev->if_port].name);
-		pr_debug("dev->watchdog_timeo=%d\n", dev->watchdog_timeo);
-	}
-
-	media_status = window_read16(vp, 4, Wn4_Media);
-	switch (dev->if_port) {
-	case XCVR_10baseT:  case XCVR_100baseTx:  case XCVR_100baseFx:
-		if (media_status & Media_LnkBeat) {
-			netif_carrier_on(dev);
-			ok = 1;
-			if (vortex_debug > 1)
-				pr_debug("%s: Media %s has link beat, %x.\n",
-					   dev->name, media_tbl[dev->if_port].name, media_status);
-		} else {
-			netif_carrier_off(dev);
-			if (vortex_debug > 1) {
-				pr_debug("%s: Media %s has no link beat, %x.\n",
-					   dev->name, media_tbl[dev->if_port].name, media_status);
-			}
-		}
-		break;
-	case XCVR_MII: case XCVR_NWAY:
-		{
-			ok = 1;
-			vortex_check_media(dev, 0);
-		}
-		break;
-	  default:					/* Other media types handled by Tx timeouts. */
-		if (vortex_debug > 1)
-		  pr_debug("%s: Media %s has no indication, %x.\n",
-				 dev->name, media_tbl[dev->if_port].name, media_status);
-		ok = 1;
-	}
-
-	if (dev->flags & IFF_SLAVE || !netif_carrier_ok(dev))
-		next_tick = 5*HZ;
-
-	if (vp->medialock)
-		goto leave_media_alone;
-
-	if (!ok) {
-		unsigned int config;
-
-		spin_lock_irq(&vp->lock);
-
-		do {
-			dev->if_port = media_tbl[dev->if_port].next;
-		} while ( ! (vp->available_media & media_tbl[dev->if_port].mask));
-		if (dev->if_port == XCVR_Default) { /* Go back to default. */
-		  dev->if_port = vp->default_media;
-		  if (vortex_debug > 1)
-			pr_debug("%s: Media selection failing, using default %s port.\n",
-				   dev->name, media_tbl[dev->if_port].name);
-		} else {
-			if (vortex_debug > 1)
-				pr_debug("%s: Media selection failed, now trying %s port.\n",
-					   dev->name, media_tbl[dev->if_port].name);
-			next_tick = media_tbl[dev->if_port].wait;
-		}
-		window_write16(vp,
-			       (media_status & ~(Media_10TP|Media_SQE)) |
-			       media_tbl[dev->if_port].media_bits,
-			       4, Wn4_Media);
-
-		config = window_read32(vp, 3, Wn3_Config);
-		config = BFINS(config, dev->if_port, 20, 4);
-		window_write32(vp, config, 3, Wn3_Config);
-
-		iowrite16(dev->if_port == XCVR_10base2 ? StartCoax : StopCoax,
-			 ioaddr + EL3_CMD);
-		if (vortex_debug > 1)
-			pr_debug("wrote 0x%08x to Wn3_Config\n", config);
-		/* AKPM: FIXME: Should reset Rx & Tx here.  P60 of 3c90xc.pdf */
-
-		spin_unlock_irq(&vp->lock);
-	}
-
-leave_media_alone:
-	if (vortex_debug > 2)
-	  pr_debug("%s: Media selection timer finished, %s.\n",
-			 dev->name, media_tbl[dev->if_port].name);
-
-	mod_timer(&vp->timer, RUN_AT(next_tick));
-	if (vp->deferred)
-		iowrite16(FakeIntr, ioaddr + EL3_CMD);
-}
-
-static void vortex_tx_timeout(struct net_device *dev, unsigned int txqueue)
-{
-	struct vortex_private *vp = netdev_priv(dev);
-	void __iomem *ioaddr = vp->ioaddr;
-
-	pr_err("%s: transmit timed out, tx_status %2.2x status %4.4x.\n",
-		   dev->name, ioread8(ioaddr + TxStatus),
-		   ioread16(ioaddr + EL3_STATUS));
-	pr_err("  diagnostics: net %04x media %04x dma %08x fifo %04x\n",
-			window_read16(vp, 4, Wn4_NetDiag),
-			window_read16(vp, 4, Wn4_Media),
-			ioread32(ioaddr + PktStatus),
-			window_read16(vp, 4, Wn4_FIFODiag));
-	/* Slight code bloat to be user friendly. */
-	if ((ioread8(ioaddr + TxStatus) & 0x88) == 0x88)
-		pr_err("%s: Transmitter encountered 16 collisions --"
-			   " network cable problem?\n", dev->name);
-	if (ioread16(ioaddr + EL3_STATUS) & IntLatch) {
-		pr_err("%s: Interrupt posted but not delivered --"
-			   " IRQ blocked by another device?\n", dev->name);
-		/* Bad idea here.. but we might as well handle a few events. */
-		vortex_boomerang_interrupt(dev->irq, dev);
-	}
-
-	if (vortex_debug > 0)
-		dump_tx_ring(dev);
-
-	issue_and_wait(dev, TxReset);
-
-	dev->stats.tx_errors++;
-	if (vp->full_bus_master_tx) {
-		pr_debug("%s: Resetting the Tx ring pointer.\n", dev->name);
-		if (vp->cur_tx - vp->dirty_tx > 0  &&  ioread32(ioaddr + DownListPtr) == 0)
-			iowrite32(vp->tx_ring_dma + (vp->dirty_tx % TX_RING_SIZE) * sizeof(struct boom_tx_desc),
-				 ioaddr + DownListPtr);
-		if (vp->cur_tx - vp->dirty_tx < TX_RING_SIZE) {
-			netif_wake_queue (dev);
-			netdev_reset_queue (dev);
-		}
-		if (vp->drv_flags & IS_BOOMERANG)
-			iowrite8(PKT_BUF_SZ>>8, ioaddr + TxFreeThreshold);
-		iowrite16(DownUnstall, ioaddr + EL3_CMD);
-	} else {
-		dev->stats.tx_dropped++;
-		netif_wake_queue(dev);
-		netdev_reset_queue(dev);
-	}
-	/* Issue Tx Enable */
-	iowrite16(TxEnable, ioaddr + EL3_CMD);
-	netif_trans_update(dev); /* prevent tx timeout */
-}
-
-/*
- * Handle uncommon interrupt sources.  This is a separate routine to minimize
- * the cache impact.
- */
-static void
-vortex_error(struct net_device *dev, int status)
-{
-	struct vortex_private *vp = netdev_priv(dev);
-	void __iomem *ioaddr = vp->ioaddr;
-	int do_tx_reset = 0, reset_mask = 0;
-	unsigned char tx_status = 0;
-
-	if (vortex_debug > 2) {
-		pr_err("%s: vortex_error(), status=0x%x\n", dev->name, status);
-	}
-
-	if (status & TxComplete) {			/* Really "TxError" for us. */
-		tx_status = ioread8(ioaddr + TxStatus);
-		/* Presumably a tx-timeout. We must merely re-enable. */
-		if (vortex_debug > 2 ||
-		    (tx_status != 0x88 && vortex_debug > 0)) {
-			pr_err("%s: Transmit error, Tx status register %2.2x.\n",
-				   dev->name, tx_status);
-			if (tx_status == 0x82) {
-				pr_err("Probably a duplex mismatch.  See "
-						"Documentation/networking/device_drivers/ethernet/3com/vortex.rst\n");
-			}
-			dump_tx_ring(dev);
-		}
-		if (tx_status & 0x14)  dev->stats.tx_fifo_errors++;
-		if (tx_status & 0x38)  dev->stats.tx_aborted_errors++;
-		if (tx_status & 0x08)  vp->xstats.tx_max_collisions++;
-		iowrite8(0, ioaddr + TxStatus);
-		if (tx_status & 0x30) {			/* txJabber or txUnderrun */
-			do_tx_reset = 1;
-		} else if ((tx_status & 0x08) && (vp->drv_flags & MAX_COLLISION_RESET))  {	/* maxCollisions */
-			do_tx_reset = 1;
-			reset_mask = 0x0108;		/* Reset interface logic, but not download logic */
-		} else {				/* Merely re-enable the transmitter. */
-			iowrite16(TxEnable, ioaddr + EL3_CMD);
-		}
-	}
-
-	if (status & RxEarly)				/* Rx early is unused. */
-		iowrite16(AckIntr | RxEarly, ioaddr + EL3_CMD);
-
-	if (status & StatsFull) {			/* Empty statistics. */
-		static int DoneDidThat;
-		if (vortex_debug > 4)
-			pr_debug("%s: Updating stats.\n", dev->name);
-		update_stats(ioaddr, dev);
-		/* HACK: Disable statistics as an interrupt source. */
-		/* This occurs when we have the wrong media type! */
-		if (DoneDidThat == 0  &&
-			ioread16(ioaddr + EL3_STATUS) & StatsFull) {
-			pr_warn("%s: Updating statistics failed, disabling stats as an interrupt source\n",
-				dev->name);
-			iowrite16(SetIntrEnb |
-				  (window_read16(vp, 5, 10) & ~StatsFull),
-				  ioaddr + EL3_CMD);
-			vp->intr_enable &= ~StatsFull;
-			DoneDidThat++;
-		}
-	}
-	if (status & IntReq) {		/* Restore all interrupt sources.  */
-		iowrite16(vp->status_enable, ioaddr + EL3_CMD);
-		iowrite16(vp->intr_enable, ioaddr + EL3_CMD);
-	}
-	if (status & HostError) {
-		u16 fifo_diag;
-		fifo_diag = window_read16(vp, 4, Wn4_FIFODiag);
-		pr_err("%s: Host error, FIFO diagnostic register %4.4x.\n",
-			   dev->name, fifo_diag);
-		/* Adapter failure requires Tx/Rx reset and reinit. */
-		if (vp->full_bus_master_tx) {
-			int bus_status = ioread32(ioaddr + PktStatus);
-			/* 0x80000000 PCI master abort. */
-			/* 0x40000000 PCI target abort. */
-			if (vortex_debug)
-				pr_err("%s: PCI bus error, bus status %8.8x\n", dev->name, bus_status);
-
-			/* In this case, blow the card away */
-			/* Must not enter D3 or we can't legally issue the reset! */
-			vortex_down(dev, 0);
-			issue_and_wait(dev, TotalReset | 0xff);
-			vortex_up(dev);		/* AKPM: bug.  vortex_up() assumes that the rx ring is full. It may not be. */
-		} else if (fifo_diag & 0x0400)
-			do_tx_reset = 1;
-		if (fifo_diag & 0x3000) {
-			/* Reset Rx fifo and upload logic */
-			issue_and_wait(dev, RxReset|0x07);
-			/* Set the Rx filter to the current state. */
-			set_rx_mode(dev);
-			/* enable 802.1q VLAN tagged frames */
-			set_8021q_mode(dev, 1);
-			iowrite16(RxEnable, ioaddr + EL3_CMD); /* Re-enable the receiver. */
-			iowrite16(AckIntr | HostError, ioaddr + EL3_CMD);
-		}
-	}
-
-	if (do_tx_reset) {
-		issue_and_wait(dev, TxReset|reset_mask);
-		iowrite16(TxEnable, ioaddr + EL3_CMD);
-		if (!vp->full_bus_master_tx)
-			netif_wake_queue(dev);
-	}
-}
-
-static netdev_tx_t
-vortex_start_xmit(struct sk_buff *skb, struct net_device *dev)
-{
-	struct vortex_private *vp = netdev_priv(dev);
-	void __iomem *ioaddr = vp->ioaddr;
-	int skblen = skb->len;
-
-	/* Put out the doubleword header... */
-	iowrite32(skb->len, ioaddr + TX_FIFO);
-	if (vp->bus_master) {
-		/* Set the bus-master controller to transfer the packet. */
-		int len = (skb->len + 3) & ~3;
-		vp->tx_skb_dma = dma_map_single(vp->gendev, skb->data, len,
-						DMA_TO_DEVICE);
-		if (dma_mapping_error(vp->gendev, vp->tx_skb_dma)) {
-			dev_kfree_skb_any(skb);
-			dev->stats.tx_dropped++;
-			return NETDEV_TX_OK;
-		}
-
-		spin_lock_irq(&vp->window_lock);
-		window_set(vp, 7);
-		iowrite32(vp->tx_skb_dma, ioaddr + Wn7_MasterAddr);
-		iowrite16(len, ioaddr + Wn7_MasterLen);
-		spin_unlock_irq(&vp->window_lock);
-		vp->tx_skb = skb;
-		skb_tx_timestamp(skb);
-		iowrite16(StartDMADown, ioaddr + EL3_CMD);
-		/* netif_wake_queue() will be called at the DMADone interrupt. */
-	} else {
-		/* ... and the packet rounded to a doubleword. */
-		skb_tx_timestamp(skb);
-		iowrite32_rep(ioaddr + TX_FIFO, skb->data, (skb->len + 3) >> 2);
-		dev_consume_skb_any (skb);
-		if (ioread16(ioaddr + TxFree) > 1536) {
-			netif_start_queue (dev);	/* AKPM: redundant? */
-		} else {
-			/* Interrupt us when the FIFO has room for max-sized packet. */
-			netif_stop_queue(dev);
-			iowrite16(SetTxThreshold + (1536>>2), ioaddr + EL3_CMD);
-		}
-	}
-
-	netdev_sent_queue(dev, skblen);
-
-	/* Clear the Tx status stack. */
-	{
-		int tx_status;
-		int i = 32;
-
-		while (--i > 0	&&	(tx_status = ioread8(ioaddr + TxStatus)) > 0) {
-			if (tx_status & 0x3C) {		/* A Tx-disabling error occurred.  */
-				if (vortex_debug > 2)
-				  pr_debug("%s: Tx error, status %2.2x.\n",
-						 dev->name, tx_status);
-				if (tx_status & 0x04) dev->stats.tx_fifo_errors++;
-				if (tx_status & 0x38) dev->stats.tx_aborted_errors++;
-				if (tx_status & 0x30) {
-					issue_and_wait(dev, TxReset);
-				}
-				iowrite16(TxEnable, ioaddr + EL3_CMD);
-			}
-			iowrite8(0x00, ioaddr + TxStatus); /* Pop the status stack. */
-		}
-	}
-	return NETDEV_TX_OK;
-}
-
-static netdev_tx_t
-boomerang_start_xmit(struct sk_buff *skb, struct net_device *dev)
-{
-	struct vortex_private *vp = netdev_priv(dev);
-	void __iomem *ioaddr = vp->ioaddr;
-	/* Calculate the next Tx descriptor entry. */
-	int entry = vp->cur_tx % TX_RING_SIZE;
-	int skblen = skb->len;
-	struct boom_tx_desc *prev_entry = &vp->tx_ring[(vp->cur_tx-1) % TX_RING_SIZE];
-	unsigned long flags;
-	dma_addr_t dma_addr;
-
-	if (vortex_debug > 6) {
-		pr_debug("boomerang_start_xmit()\n");
-		pr_debug("%s: Trying to send a packet, Tx index %d.\n",
-			   dev->name, vp->cur_tx);
-	}
-
-	/*
-	 * We can't allow a recursion from our interrupt handler back into the
-	 * tx routine, as they take the same spin lock, and that causes
-	 * deadlock.  Just return NETDEV_TX_BUSY and let the stack try again in
-	 * a bit
-	 */
-	if (vp->handling_irq)
-		return NETDEV_TX_BUSY;
-
-	if (vp->cur_tx - vp->dirty_tx >= TX_RING_SIZE) {
-		if (vortex_debug > 0)
-			pr_warn("%s: BUG! Tx Ring full, refusing to send buffer\n",
-				dev->name);
-		netif_stop_queue(dev);
-		return NETDEV_TX_BUSY;
-	}
-
-	vp->tx_skbuff[entry] = skb;
-
-	vp->tx_ring[entry].next = 0;
-#if DO_ZEROCOPY
-	if (skb->ip_summed != CHECKSUM_PARTIAL)
-			vp->tx_ring[entry].status = cpu_to_le32(skb->len | TxIntrUploaded);
-	else
-			vp->tx_ring[entry].status = cpu_to_le32(skb->len | TxIntrUploaded | AddTCPChksum | AddUDPChksum);
-
-	if (!skb_shinfo(skb)->nr_frags) {
-		dma_addr = dma_map_single(vp->gendev, skb->data, skb->len,
-					  DMA_TO_DEVICE);
-		if (dma_mapping_error(vp->gendev, dma_addr))
-			goto out_dma_err;
-
-		vp->tx_ring[entry].frag[0].addr = cpu_to_le32(dma_addr);
-		vp->tx_ring[entry].frag[0].length = cpu_to_le32(skb->len | LAST_FRAG);
-	} else {
-		int i;
-
-		dma_addr = dma_map_single(vp->gendev, skb->data,
-					  skb_headlen(skb), DMA_TO_DEVICE);
-		if (dma_mapping_error(vp->gendev, dma_addr))
-			goto out_dma_err;
-
-		vp->tx_ring[entry].frag[0].addr = cpu_to_le32(dma_addr);
-		vp->tx_ring[entry].frag[0].length = cpu_to_le32(skb_headlen(skb));
-
-		for (i = 0; i < skb_shinfo(skb)->nr_frags; i++) {
-			skb_frag_t *frag = &skb_shinfo(skb)->frags[i];
-
-			dma_addr = skb_frag_dma_map(vp->gendev, frag,
-						    0,
-						    skb_frag_size(frag),
-						    DMA_TO_DEVICE);
-			if (dma_mapping_error(vp->gendev, dma_addr)) {
-				for(i = i-1; i >= 0; i--)
-					dma_unmap_page(vp->gendev,
-						       le32_to_cpu(vp->tx_ring[entry].frag[i+1].addr),
-						       le32_to_cpu(vp->tx_ring[entry].frag[i+1].length),
-						       DMA_TO_DEVICE);
-
-				dma_unmap_single(vp->gendev,
-						 le32_to_cpu(vp->tx_ring[entry].frag[0].addr),
-						 le32_to_cpu(vp->tx_ring[entry].frag[0].length),
-						 DMA_TO_DEVICE);
-
-				goto out_dma_err;
-			}
-
-			vp->tx_ring[entry].frag[i+1].addr =
-						cpu_to_le32(dma_addr);
-
-			if (i == skb_shinfo(skb)->nr_frags-1)
-					vp->tx_ring[entry].frag[i+1].length = cpu_to_le32(skb_frag_size(frag)|LAST_FRAG);
-			else
-					vp->tx_ring[entry].frag[i+1].length = cpu_to_le32(skb_frag_size(frag));
-		}
-	}
-#else
-	dma_addr = dma_map_single(vp->gendev, skb->data, skb->len, DMA_TO_DEVICE);
-	if (dma_mapping_error(vp->gendev, dma_addr))
-		goto out_dma_err;
-	vp->tx_ring[entry].addr = cpu_to_le32(dma_addr);
-	vp->tx_ring[entry].length = cpu_to_le32(skb->len | LAST_FRAG);
-	vp->tx_ring[entry].status = cpu_to_le32(skb->len | TxIntrUploaded);
-#endif
-
-	spin_lock_irqsave(&vp->lock, flags);
-	/* Wait for the stall to complete. */
-	issue_and_wait(dev, DownStall);
-	prev_entry->next = cpu_to_le32(vp->tx_ring_dma + entry * sizeof(struct boom_tx_desc));
-	if (ioread32(ioaddr + DownListPtr) == 0) {
-		iowrite32(vp->tx_ring_dma + entry * sizeof(struct boom_tx_desc), ioaddr + DownListPtr);
-		vp->queued_packet++;
-	}
-
-	vp->cur_tx++;
-	netdev_sent_queue(dev, skblen);
-
-	if (vp->cur_tx - vp->dirty_tx > TX_RING_SIZE - 1) {
-		netif_stop_queue (dev);
-	} else {					/* Clear previous interrupt enable. */
-#if defined(tx_interrupt_mitigation)
-		/* Dubious. If in boomeang_interrupt "faster" cyclone ifdef
-		 * were selected, this would corrupt DN_COMPLETE. No?
-		 */
-		prev_entry->status &= cpu_to_le32(~TxIntrUploaded);
-#endif
-	}
-	skb_tx_timestamp(skb);
-	iowrite16(DownUnstall, ioaddr + EL3_CMD);
-	spin_unlock_irqrestore(&vp->lock, flags);
-out:
-	return NETDEV_TX_OK;
-out_dma_err:
-	dev_err(vp->gendev, "Error mapping dma buffer\n");
-	goto out;
-}
-
-/* The interrupt handler does all of the Rx thread work and cleans up
-   after the Tx thread. */
-
-/*
- * This is the ISR for the vortex series chips.
- * full_bus_master_tx == 0 && full_bus_master_rx == 0
- */
-
-static irqreturn_t
-_vortex_interrupt(int irq, struct net_device *dev)
-{
-	struct vortex_private *vp = netdev_priv(dev);
-	void __iomem *ioaddr;
-	int status;
-	int work_done = max_interrupt_work;
-	int handled = 0;
-	unsigned int bytes_compl = 0, pkts_compl = 0;
-
-	ioaddr = vp->ioaddr;
-
-	status = ioread16(ioaddr + EL3_STATUS);
-
-	if (vortex_debug > 6)
-		pr_debug("vortex_interrupt(). status=0x%4x\n", status);
-
-	if ((status & IntLatch) == 0)
-		goto handler_exit;		/* No interrupt: shared IRQs cause this */
-	handled = 1;
-
-	if (status & IntReq) {
-		status |= vp->deferred;
-		vp->deferred = 0;
-	}
-
-	if (status == 0xffff)		/* h/w no longer present (hotplug)? */
-		goto handler_exit;
-
-	if (vortex_debug > 4)
-		pr_debug("%s: interrupt, status %4.4x, latency %d ticks.\n",
-			   dev->name, status, ioread8(ioaddr + Timer));
-
-	spin_lock(&vp->window_lock);
-	window_set(vp, 7);
-
-	do {
-		if (vortex_debug > 5)
-				pr_debug("%s: In interrupt loop, status %4.4x.\n",
-					   dev->name, status);
-		if (status & RxComplete)
-			vortex_rx(dev);
-
-		if (status & TxAvailable) {
-			if (vortex_debug > 5)
-				pr_debug("	TX room bit was handled.\n");
-			/* There's room in the FIFO for a full-sized packet. */
-			iowrite16(AckIntr | TxAvailable, ioaddr + EL3_CMD);
-			netif_wake_queue (dev);
-		}
-
-		if (status & DMADone) {
-			if (ioread16(ioaddr + Wn7_MasterStatus) & 0x1000) {
-				iowrite16(0x1000, ioaddr + Wn7_MasterStatus); /* Ack the event. */
-				dma_unmap_single(vp->gendev, vp->tx_skb_dma, (vp->tx_skb->len + 3) & ~3, DMA_TO_DEVICE);
-				pkts_compl++;
-				bytes_compl += vp->tx_skb->len;
-				dev_consume_skb_irq(vp->tx_skb); /* Release the transferred buffer */
-				if (ioread16(ioaddr + TxFree) > 1536) {
-					/*
-					 * AKPM: FIXME: I don't think we need this.  If the queue was stopped due to
-					 * insufficient FIFO room, the TxAvailable test will succeed and call
-					 * netif_wake_queue()
-					 */
-					netif_wake_queue(dev);
-				} else { /* Interrupt when FIFO has room for max-sized packet. */
-					iowrite16(SetTxThreshold + (1536>>2), ioaddr + EL3_CMD);
-					netif_stop_queue(dev);
-				}
-			}
-		}
-		/* Check for all uncommon interrupts at once. */
-		if (status & (HostError | RxEarly | StatsFull | TxComplete | IntReq)) {
-			if (status == 0xffff)
-				break;
-			if (status & RxEarly)
-				vortex_rx(dev);
-			spin_unlock(&vp->window_lock);
-			vortex_error(dev, status);
-			spin_lock(&vp->window_lock);
-			window_set(vp, 7);
-		}
-
-		if (--work_done < 0) {
-			pr_warn("%s: Too much work in interrupt, status %4.4x\n",
-				dev->name, status);
-			/* Disable all pending interrupts. */
-			do {
-				vp->deferred |= status;
-				iowrite16(SetStatusEnb | (~vp->deferred & vp->status_enable),
-					 ioaddr + EL3_CMD);
-				iowrite16(AckIntr | (vp->deferred & 0x7ff), ioaddr + EL3_CMD);
-			} while ((status = ioread16(ioaddr + EL3_CMD)) & IntLatch);
-			/* The timer will reenable interrupts. */
-			mod_timer(&vp->timer, jiffies + 1*HZ);
-			break;
-		}
-		/* Acknowledge the IRQ. */
-		iowrite16(AckIntr | IntReq | IntLatch, ioaddr + EL3_CMD);
-	} while ((status = ioread16(ioaddr + EL3_STATUS)) & (IntLatch | RxComplete));
-
-	netdev_completed_queue(dev, pkts_compl, bytes_compl);
-	spin_unlock(&vp->window_lock);
-
-	if (vortex_debug > 4)
-		pr_debug("%s: exiting interrupt, status %4.4x.\n",
-			   dev->name, status);
-handler_exit:
-	return IRQ_RETVAL(handled);
-}
-
-/*
- * This is the ISR for the boomerang series chips.
- * full_bus_master_tx == 1 && full_bus_master_rx == 1
- */
-
-static irqreturn_t
-_boomerang_interrupt(int irq, struct net_device *dev)
-{
-	struct vortex_private *vp = netdev_priv(dev);
-	void __iomem *ioaddr;
-	int status;
-	int work_done = max_interrupt_work;
-	int handled = 0;
-	unsigned int bytes_compl = 0, pkts_compl = 0;
-
-	ioaddr = vp->ioaddr;
-
-	vp->handling_irq = 1;
-
-	status = ioread16(ioaddr + EL3_STATUS);
-
-	if (vortex_debug > 6)
-		pr_debug("boomerang_interrupt. status=0x%4x\n", status);
-
-	if ((status & IntLatch) == 0)
-		goto handler_exit;		/* No interrupt: shared IRQs can cause this */
-	handled = 1;
-
-	if (status == 0xffff) {		/* h/w no longer present (hotplug)? */
-		if (vortex_debug > 1)
-			pr_debug("boomerang_interrupt(1): status = 0xffff\n");
-		goto handler_exit;
-	}
-
-	if (status & IntReq) {
-		status |= vp->deferred;
-		vp->deferred = 0;
-	}
-
-	if (vortex_debug > 4)
-		pr_debug("%s: interrupt, status %4.4x, latency %d ticks.\n",
-			   dev->name, status, ioread8(ioaddr + Timer));
-	do {
-		if (vortex_debug > 5)
-				pr_debug("%s: In interrupt loop, status %4.4x.\n",
-					   dev->name, status);
-		if (status & UpComplete) {
-			iowrite16(AckIntr | UpComplete, ioaddr + EL3_CMD);
-			if (vortex_debug > 5)
-				pr_debug("boomerang_interrupt->boomerang_rx\n");
-			boomerang_rx(dev);
-		}
-
-		if (status & DownComplete) {
-			unsigned int dirty_tx = vp->dirty_tx;
-
-			iowrite16(AckIntr | DownComplete, ioaddr + EL3_CMD);
-			while (vp->cur_tx - dirty_tx > 0) {
-				int entry = dirty_tx % TX_RING_SIZE;
-#if 1	/* AKPM: the latter is faster, but cyclone-only */
-				if (ioread32(ioaddr + DownListPtr) ==
-					vp->tx_ring_dma + entry * sizeof(struct boom_tx_desc))
-					break;			/* It still hasn't been processed. */
-#else
-				if ((vp->tx_ring[entry].status & DN_COMPLETE) == 0)
-					break;			/* It still hasn't been processed. */
-#endif
-
-				if (vp->tx_skbuff[entry]) {
-					struct sk_buff *skb = vp->tx_skbuff[entry];
-#if DO_ZEROCOPY
-					int i;
-					dma_unmap_single(vp->gendev,
-							le32_to_cpu(vp->tx_ring[entry].frag[0].addr),
-							le32_to_cpu(vp->tx_ring[entry].frag[0].length)&0xFFF,
-							DMA_TO_DEVICE);
-
-					for (i=1; i<=skb_shinfo(skb)->nr_frags; i++)
-							dma_unmap_page(vp->gendev,
-											 le32_to_cpu(vp->tx_ring[entry].frag[i].addr),
-											 le32_to_cpu(vp->tx_ring[entry].frag[i].length)&0xFFF,
-											 DMA_TO_DEVICE);
-#else
-					dma_unmap_single(vp->gendev,
-						le32_to_cpu(vp->tx_ring[entry].addr), skb->len, DMA_TO_DEVICE);
-#endif
-					pkts_compl++;
-					bytes_compl += skb->len;
-					dev_consume_skb_irq(skb);
-					vp->tx_skbuff[entry] = NULL;
-				} else {
-					pr_debug("boomerang_interrupt: no skb!\n");
-				}
-				/* dev->stats.tx_packets++;  Counted below. */
-				dirty_tx++;
-			}
-			vp->dirty_tx = dirty_tx;
-			if (vp->cur_tx - dirty_tx <= TX_RING_SIZE - 1) {
-				if (vortex_debug > 6)
-					pr_debug("boomerang_interrupt: wake queue\n");
-				netif_wake_queue (dev);
-			}
-		}
-
-		/* Check for all uncommon interrupts at once. */
-		if (status & (HostError | RxEarly | StatsFull | TxComplete | IntReq))
-			vortex_error(dev, status);
-
-		if (--work_done < 0) {
-			pr_warn("%s: Too much work in interrupt, status %4.4x\n",
-				dev->name, status);
-			/* Disable all pending interrupts. */
-			do {
-				vp->deferred |= status;
-				iowrite16(SetStatusEnb | (~vp->deferred & vp->status_enable),
-					 ioaddr + EL3_CMD);
-				iowrite16(AckIntr | (vp->deferred & 0x7ff), ioaddr + EL3_CMD);
-			} while ((status = ioread16(ioaddr + EL3_CMD)) & IntLatch);
-			/* The timer will reenable interrupts. */
-			mod_timer(&vp->timer, jiffies + 1*HZ);
-			break;
-		}
-		/* Acknowledge the IRQ. */
-		iowrite16(AckIntr | IntReq | IntLatch, ioaddr + EL3_CMD);
-		if (vp->cb_fn_base)			/* The PCMCIA people are idiots.  */
-			iowrite32(0x8000, vp->cb_fn_base + 4);
-
-	} while ((status = ioread16(ioaddr + EL3_STATUS)) & IntLatch);
-	netdev_completed_queue(dev, pkts_compl, bytes_compl);
-
-	if (vortex_debug > 4)
-		pr_debug("%s: exiting interrupt, status %4.4x.\n",
-			   dev->name, status);
-handler_exit:
-	vp->handling_irq = 0;
-	return IRQ_RETVAL(handled);
-}
-
-static irqreturn_t
-vortex_boomerang_interrupt(int irq, void *dev_id)
-{
-	struct net_device *dev = dev_id;
-	struct vortex_private *vp = netdev_priv(dev);
-	unsigned long flags;
-	irqreturn_t ret;
-
-	spin_lock_irqsave(&vp->lock, flags);
-
-	if (vp->full_bus_master_rx)
-		ret = _boomerang_interrupt(dev->irq, dev);
-	else
-		ret = _vortex_interrupt(dev->irq, dev);
-
-	spin_unlock_irqrestore(&vp->lock, flags);
-
-	return ret;
-}
-
-static int vortex_rx(struct net_device *dev)
-{
-	struct vortex_private *vp = netdev_priv(dev);
-	void __iomem *ioaddr = vp->ioaddr;
-	int i;
-	short rx_status;
-
-	if (vortex_debug > 5)
-		pr_debug("vortex_rx(): status %4.4x, rx_status %4.4x.\n",
-			   ioread16(ioaddr+EL3_STATUS), ioread16(ioaddr+RxStatus));
-	while ((rx_status = ioread16(ioaddr + RxStatus)) > 0) {
-		if (rx_status & 0x4000) { /* Error, update stats. */
-			unsigned char rx_error = ioread8(ioaddr + RxErrors);
-			if (vortex_debug > 2)
-				pr_debug(" Rx error: status %2.2x.\n", rx_error);
-			dev->stats.rx_errors++;
-			if (rx_error & 0x01)  dev->stats.rx_over_errors++;
-			if (rx_error & 0x02)  dev->stats.rx_length_errors++;
-			if (rx_error & 0x04)  dev->stats.rx_frame_errors++;
-			if (rx_error & 0x08)  dev->stats.rx_crc_errors++;
-			if (rx_error & 0x10)  dev->stats.rx_length_errors++;
-		} else {
-			/* The packet length: up to 4.5K!. */
-			int pkt_len = rx_status & 0x1fff;
-			struct sk_buff *skb;
-
-			skb = netdev_alloc_skb(dev, pkt_len + 5);
-			if (vortex_debug > 4)
-				pr_debug("Receiving packet size %d status %4.4x.\n",
-					   pkt_len, rx_status);
-			if (skb != NULL) {
-				skb_reserve(skb, 2);	/* Align IP on 16 byte boundaries */
-				/* 'skb_put()' points to the start of sk_buff data area. */
-				if (vp->bus_master &&
-					! (ioread16(ioaddr + Wn7_MasterStatus) & 0x8000)) {
-					dma_addr_t dma = dma_map_single(vp->gendev, skb_put(skb, pkt_len),
-									   pkt_len, DMA_FROM_DEVICE);
-					iowrite32(dma, ioaddr + Wn7_MasterAddr);
-					iowrite16((skb->len + 3) & ~3, ioaddr + Wn7_MasterLen);
-					iowrite16(StartDMAUp, ioaddr + EL3_CMD);
-					while (ioread16(ioaddr + Wn7_MasterStatus) & 0x8000)
-						;
-					dma_unmap_single(vp->gendev, dma, pkt_len, DMA_FROM_DEVICE);
-				} else {
-					ioread32_rep(ioaddr + RX_FIFO,
-					             skb_put(skb, pkt_len),
-						     (pkt_len + 3) >> 2);
-				}
-				iowrite16(RxDiscard, ioaddr + EL3_CMD); /* Pop top Rx packet. */
-				skb->protocol = eth_type_trans(skb, dev);
-				netif_rx(skb);
-				dev->stats.rx_packets++;
-				/* Wait a limited time to go to next packet. */
-				for (i = 200; i >= 0; i--)
-					if ( ! (ioread16(ioaddr + EL3_STATUS) & CmdInProgress))
-						break;
-				continue;
-			} else if (vortex_debug > 0)
-				pr_notice("%s: No memory to allocate a sk_buff of size %d.\n",
-					dev->name, pkt_len);
-			dev->stats.rx_dropped++;
-		}
-		issue_and_wait(dev, RxDiscard);
-	}
-
-	return 0;
-}
-
-static int
-boomerang_rx(struct net_device *dev)
-{
-	struct vortex_private *vp = netdev_priv(dev);
-	int entry = vp->cur_rx % RX_RING_SIZE;
-	void __iomem *ioaddr = vp->ioaddr;
-	int rx_status;
-	int rx_work_limit = RX_RING_SIZE;
-
-	if (vortex_debug > 5)
-		pr_debug("boomerang_rx(): status %4.4x\n", ioread16(ioaddr+EL3_STATUS));
-
-	while ((rx_status = le32_to_cpu(vp->rx_ring[entry].status)) & RxDComplete){
-		if (--rx_work_limit < 0)
-			break;
-		if (rx_status & RxDError) { /* Error, update stats. */
-			unsigned char rx_error = rx_status >> 16;
-			if (vortex_debug > 2)
-				pr_debug(" Rx error: status %2.2x.\n", rx_error);
-			dev->stats.rx_errors++;
-			if (rx_error & 0x01)  dev->stats.rx_over_errors++;
-			if (rx_error & 0x02)  dev->stats.rx_length_errors++;
-			if (rx_error & 0x04)  dev->stats.rx_frame_errors++;
-			if (rx_error & 0x08)  dev->stats.rx_crc_errors++;
-			if (rx_error & 0x10)  dev->stats.rx_length_errors++;
-		} else {
-			/* The packet length: up to 4.5K!. */
-			int pkt_len = rx_status & 0x1fff;
-			struct sk_buff *skb, *newskb;
-			dma_addr_t newdma;
-			dma_addr_t dma = le32_to_cpu(vp->rx_ring[entry].addr);
-
-			if (vortex_debug > 4)
-				pr_debug("Receiving packet size %d status %4.4x.\n",
-					   pkt_len, rx_status);
-
-			/* Check if the packet is long enough to just accept without
-			   copying to a properly sized skbuff. */
-			if (pkt_len < rx_copybreak &&
-			    (skb = netdev_alloc_skb(dev, pkt_len + 2)) != NULL) {
-				skb_reserve(skb, 2);	/* Align IP on 16 byte boundaries */
-				dma_sync_single_for_cpu(vp->gendev, dma, PKT_BUF_SZ, DMA_FROM_DEVICE);
-				/* 'skb_put()' points to the start of sk_buff data area. */
-				skb_put_data(skb, vp->rx_skbuff[entry]->data,
-					     pkt_len);
-				dma_sync_single_for_device(vp->gendev, dma, PKT_BUF_SZ, DMA_FROM_DEVICE);
-				vp->rx_copy++;
-			} else {
-				/* Pre-allocate the replacement skb.  If it or its
-				 * mapping fails then recycle the buffer thats already
-				 * in place
-				 */
-				newskb = netdev_alloc_skb_ip_align(dev, PKT_BUF_SZ);
-				if (!newskb) {
-					dev->stats.rx_dropped++;
-					goto clear_complete;
-				}
-				newdma = dma_map_single(vp->gendev, newskb->data,
-							PKT_BUF_SZ, DMA_FROM_DEVICE);
-				if (dma_mapping_error(vp->gendev, newdma)) {
-					dev->stats.rx_dropped++;
-					consume_skb(newskb);
-					goto clear_complete;
-				}
-
-				/* Pass up the skbuff already on the Rx ring. */
-				skb = vp->rx_skbuff[entry];
-				vp->rx_skbuff[entry] = newskb;
-				vp->rx_ring[entry].addr = cpu_to_le32(newdma);
-				skb_put(skb, pkt_len);
-				dma_unmap_single(vp->gendev, dma, PKT_BUF_SZ, DMA_FROM_DEVICE);
-				vp->rx_nocopy++;
-			}
-			skb->protocol = eth_type_trans(skb, dev);
-			{					/* Use hardware checksum info. */
-				int csum_bits = rx_status & 0xee000000;
-				if (csum_bits &&
-					(csum_bits == (IPChksumValid | TCPChksumValid) ||
-					 csum_bits == (IPChksumValid | UDPChksumValid))) {
-					skb->ip_summed = CHECKSUM_UNNECESSARY;
-					vp->rx_csumhits++;
-				}
-			}
-			netif_rx(skb);
-			dev->stats.rx_packets++;
-		}
-
-clear_complete:
-		vp->rx_ring[entry].status = 0;	/* Clear complete bit. */
-		iowrite16(UpUnstall, ioaddr + EL3_CMD);
-		entry = (++vp->cur_rx) % RX_RING_SIZE;
-	}
-	return 0;
-}
-
-static void
-vortex_down(struct net_device *dev, int final_down)
-{
-	struct vortex_private *vp = netdev_priv(dev);
-	void __iomem *ioaddr = vp->ioaddr;
-
-	netdev_reset_queue(dev);
-	netif_stop_queue(dev);
-
-	timer_delete_sync(&vp->timer);
-
-	/* Turn off statistics ASAP.  We update dev->stats below. */
-	iowrite16(StatsDisable, ioaddr + EL3_CMD);
-
-	/* Disable the receiver and transmitter. */
-	iowrite16(RxDisable, ioaddr + EL3_CMD);
-	iowrite16(TxDisable, ioaddr + EL3_CMD);
-
-	/* Disable receiving 802.1q tagged frames */
-	set_8021q_mode(dev, 0);
-
-	if (dev->if_port == XCVR_10base2)
-		/* Turn off thinnet power.  Green! */
-		iowrite16(StopCoax, ioaddr + EL3_CMD);
-
-	iowrite16(SetIntrEnb | 0x0000, ioaddr + EL3_CMD);
-
-	update_stats(ioaddr, dev);
-	if (vp->full_bus_master_rx)
-		iowrite32(0, ioaddr + UpListPtr);
-	if (vp->full_bus_master_tx)
-		iowrite32(0, ioaddr + DownListPtr);
-
-	if (final_down && VORTEX_PCI(vp)) {
-		vp->pm_state_valid = 1;
-		pci_save_state(VORTEX_PCI(vp));
-		acpi_set_WOL(dev);
-	}
-}
-
-static int
-vortex_close(struct net_device *dev)
-{
-	struct vortex_private *vp = netdev_priv(dev);
-	void __iomem *ioaddr = vp->ioaddr;
-	int i;
-
-	if (netif_device_present(dev))
-		vortex_down(dev, 1);
-
-	if (vortex_debug > 1) {
-		pr_debug("%s: vortex_close() status %4.4x, Tx status %2.2x.\n",
-			   dev->name, ioread16(ioaddr + EL3_STATUS), ioread8(ioaddr + TxStatus));
-		pr_debug("%s: vortex close stats: rx_nocopy %d rx_copy %d"
-			   " tx_queued %d Rx pre-checksummed %d.\n",
-			   dev->name, vp->rx_nocopy, vp->rx_copy, vp->queued_packet, vp->rx_csumhits);
-	}
-
-#if DO_ZEROCOPY
-	if (vp->rx_csumhits &&
-	    (vp->drv_flags & HAS_HWCKSM) == 0 &&
-	    (vp->card_idx >= MAX_UNITS || hw_checksums[vp->card_idx] == -1)) {
-		pr_warn("%s supports hardware checksums, and we're not using them!\n",
-			dev->name);
-	}
-#endif
-
-	free_irq(dev->irq, dev);
-
-	if (vp->full_bus_master_rx) { /* Free Boomerang bus master Rx buffers. */
-		for (i = 0; i < RX_RING_SIZE; i++)
-			if (vp->rx_skbuff[i]) {
-				dma_unmap_single(vp->gendev, le32_to_cpu(vp->rx_ring[i].addr),
-									PKT_BUF_SZ, DMA_FROM_DEVICE);
-				dev_kfree_skb(vp->rx_skbuff[i]);
-				vp->rx_skbuff[i] = NULL;
-			}
-	}
-	if (vp->full_bus_master_tx) { /* Free Boomerang bus master Tx buffers. */
-		for (i = 0; i < TX_RING_SIZE; i++) {
-			if (vp->tx_skbuff[i]) {
-				struct sk_buff *skb = vp->tx_skbuff[i];
-#if DO_ZEROCOPY
-				int k;
-
-				for (k=0; k<=skb_shinfo(skb)->nr_frags; k++)
-						dma_unmap_single(vp->gendev,
-										 le32_to_cpu(vp->tx_ring[i].frag[k].addr),
-										 le32_to_cpu(vp->tx_ring[i].frag[k].length)&0xFFF,
-										 DMA_TO_DEVICE);
-#else
-				dma_unmap_single(vp->gendev, le32_to_cpu(vp->tx_ring[i].addr), skb->len, DMA_TO_DEVICE);
-#endif
-				dev_kfree_skb(skb);
-				vp->tx_skbuff[i] = NULL;
-			}
-		}
-	}
-
-	return 0;
-}
-
-static void
-dump_tx_ring(struct net_device *dev)
-{
-	if (vortex_debug > 0) {
-		struct vortex_private *vp = netdev_priv(dev);
-		void __iomem *ioaddr = vp->ioaddr;
-
-		if (vp->full_bus_master_tx) {
-			int i;
-			int stalled = ioread32(ioaddr + PktStatus) & 0x04;	/* Possible racy. But it's only debug stuff */
-
-			pr_err("  Flags; bus-master %d, dirty %d(%d) current %d(%d)\n",
-					vp->full_bus_master_tx,
-					vp->dirty_tx, vp->dirty_tx % TX_RING_SIZE,
-					vp->cur_tx, vp->cur_tx % TX_RING_SIZE);
-			pr_err("  Transmit list %8.8x vs. %p.\n",
-				   ioread32(ioaddr + DownListPtr),
-				   &vp->tx_ring[vp->dirty_tx % TX_RING_SIZE]);
-			issue_and_wait(dev, DownStall);
-			for (i = 0; i < TX_RING_SIZE; i++) {
-				unsigned int length;
-
-#if DO_ZEROCOPY
-				length = le32_to_cpu(vp->tx_ring[i].frag[0].length);
-#else
-				length = le32_to_cpu(vp->tx_ring[i].length);
-#endif
-				pr_err("  %d: @%p  length %8.8x status %8.8x\n",
-					   i, &vp->tx_ring[i], length,
-					   le32_to_cpu(vp->tx_ring[i].status));
-			}
-			if (!stalled)
-				iowrite16(DownUnstall, ioaddr + EL3_CMD);
-		}
-	}
-}
-
-static struct net_device_stats *vortex_get_stats(struct net_device *dev)
-{
-	struct vortex_private *vp = netdev_priv(dev);
-	void __iomem *ioaddr = vp->ioaddr;
-	unsigned long flags;
-
-	if (netif_device_present(dev)) {	/* AKPM: Used to be netif_running */
-		spin_lock_irqsave (&vp->lock, flags);
-		update_stats(ioaddr, dev);
-		spin_unlock_irqrestore (&vp->lock, flags);
-	}
-	return &dev->stats;
-}
-
-/*  Update statistics.
-	Unlike with the EL3 we need not worry about interrupts changing
-	the window setting from underneath us, but we must still guard
-	against a race condition with a StatsUpdate interrupt updating the
-	table.  This is done by checking that the ASM (!) code generated uses
-	atomic updates with '+='.
-	*/
-static void update_stats(void __iomem *ioaddr, struct net_device *dev)
-{
-	struct vortex_private *vp = netdev_priv(dev);
-
-	/* Unlike the 3c5x9 we need not turn off stats updates while reading. */
-	/* Switch to the stats window, and read everything. */
-	dev->stats.tx_carrier_errors		+= window_read8(vp, 6, 0);
-	dev->stats.tx_heartbeat_errors		+= window_read8(vp, 6, 1);
-	dev->stats.tx_window_errors		+= window_read8(vp, 6, 4);
-	dev->stats.rx_fifo_errors		+= window_read8(vp, 6, 5);
-	dev->stats.tx_packets			+= window_read8(vp, 6, 6);
-	dev->stats.tx_packets			+= (window_read8(vp, 6, 9) &
-						    0x30) << 4;
-	/* Rx packets	*/			window_read8(vp, 6, 7);   /* Must read to clear */
-	/* Don't bother with register 9, an extension of registers 6&7.
-	   If we do use the 6&7 values the atomic update assumption above
-	   is invalid. */
-	dev->stats.rx_bytes 			+= window_read16(vp, 6, 10);
-	dev->stats.tx_bytes 			+= window_read16(vp, 6, 12);
-	/* Extra stats for get_ethtool_stats() */
-	vp->xstats.tx_multiple_collisions	+= window_read8(vp, 6, 2);
-	vp->xstats.tx_single_collisions         += window_read8(vp, 6, 3);
-	vp->xstats.tx_deferred			+= window_read8(vp, 6, 8);
-	vp->xstats.rx_bad_ssd			+= window_read8(vp, 4, 12);
-
-	dev->stats.collisions = vp->xstats.tx_multiple_collisions
-		+ vp->xstats.tx_single_collisions
-		+ vp->xstats.tx_max_collisions;
-
-	{
-		u8 up = window_read8(vp, 4, 13);
-		dev->stats.rx_bytes += (up & 0x0f) << 16;
-		dev->stats.tx_bytes += (up & 0xf0) << 12;
-	}
-}
-
-static int vortex_nway_reset(struct net_device *dev)
-{
-	struct vortex_private *vp = netdev_priv(dev);
-
-	return mii_nway_restart(&vp->mii);
-}
-
-static int vortex_get_link_ksettings(struct net_device *dev,
-				     struct ethtool_link_ksettings *cmd)
-{
-	struct vortex_private *vp = netdev_priv(dev);
-
-	mii_ethtool_get_link_ksettings(&vp->mii, cmd);
-
-	return 0;
-}
-
-static int vortex_set_link_ksettings(struct net_device *dev,
-				     const struct ethtool_link_ksettings *cmd)
-{
-	struct vortex_private *vp = netdev_priv(dev);
-
-	return mii_ethtool_set_link_ksettings(&vp->mii, cmd);
-}
-
-static u32 vortex_get_msglevel(struct net_device *dev)
-{
-	return vortex_debug;
-}
-
-static void vortex_set_msglevel(struct net_device *dev, u32 dbg)
-{
-	vortex_debug = dbg;
-}
-
-static int vortex_get_sset_count(struct net_device *dev, int sset)
-{
-	switch (sset) {
-	case ETH_SS_STATS:
-		return VORTEX_NUM_STATS;
-	default:
-		return -EOPNOTSUPP;
-	}
-}
-
-static void vortex_get_ethtool_stats(struct net_device *dev,
-	struct ethtool_stats *stats, u64 *data)
-{
-	struct vortex_private *vp = netdev_priv(dev);
-	void __iomem *ioaddr = vp->ioaddr;
-	unsigned long flags;
-
-	spin_lock_irqsave(&vp->lock, flags);
-	update_stats(ioaddr, dev);
-	spin_unlock_irqrestore(&vp->lock, flags);
-
-	data[0] = vp->xstats.tx_deferred;
-	data[1] = vp->xstats.tx_max_collisions;
-	data[2] = vp->xstats.tx_multiple_collisions;
-	data[3] = vp->xstats.tx_single_collisions;
-	data[4] = vp->xstats.rx_bad_ssd;
-}
-
-
-static void vortex_get_strings(struct net_device *dev, u32 stringset, u8 *data)
-{
-	switch (stringset) {
-	case ETH_SS_STATS:
-		memcpy(data, &ethtool_stats_keys, sizeof(ethtool_stats_keys));
-		break;
-	default:
-		WARN_ON(1);
-		break;
-	}
-}
-
-static void vortex_get_drvinfo(struct net_device *dev,
-					struct ethtool_drvinfo *info)
-{
-	struct vortex_private *vp = netdev_priv(dev);
-
-	strscpy(info->driver, DRV_NAME, sizeof(info->driver));
-	if (VORTEX_PCI(vp)) {
-		strscpy(info->bus_info, pci_name(VORTEX_PCI(vp)),
-			sizeof(info->bus_info));
-	} else {
-		if (VORTEX_EISA(vp))
-			strscpy(info->bus_info, dev_name(vp->gendev),
-				sizeof(info->bus_info));
-		else
-			snprintf(info->bus_info, sizeof(info->bus_info),
-				"EISA 0x%lx %d", dev->base_addr, dev->irq);
-	}
-}
-
-static void vortex_get_wol(struct net_device *dev, struct ethtool_wolinfo *wol)
-{
-	struct vortex_private *vp = netdev_priv(dev);
-
-	if (!VORTEX_PCI(vp))
-		return;
-
-	wol->supported = WAKE_MAGIC;
-
-	wol->wolopts = 0;
-	if (vp->enable_wol)
-		wol->wolopts |= WAKE_MAGIC;
-}
-
-static int vortex_set_wol(struct net_device *dev, struct ethtool_wolinfo *wol)
-{
-	struct vortex_private *vp = netdev_priv(dev);
-
-	if (!VORTEX_PCI(vp))
-		return -EOPNOTSUPP;
-
-	if (wol->wolopts & ~WAKE_MAGIC)
-		return -EINVAL;
-
-	if (wol->wolopts & WAKE_MAGIC)
-		vp->enable_wol = 1;
-	else
-		vp->enable_wol = 0;
-	acpi_set_WOL(dev);
-
-	return 0;
-}
-
-static const struct ethtool_ops vortex_ethtool_ops = {
-	.get_drvinfo		= vortex_get_drvinfo,
-	.get_strings            = vortex_get_strings,
-	.get_msglevel           = vortex_get_msglevel,
-	.set_msglevel           = vortex_set_msglevel,
-	.get_ethtool_stats      = vortex_get_ethtool_stats,
-	.get_sset_count		= vortex_get_sset_count,
-	.get_link               = ethtool_op_get_link,
-	.nway_reset             = vortex_nway_reset,
-	.get_wol                = vortex_get_wol,
-	.set_wol                = vortex_set_wol,
-	.get_ts_info		= ethtool_op_get_ts_info,
-	.get_link_ksettings     = vortex_get_link_ksettings,
-	.set_link_ksettings     = vortex_set_link_ksettings,
-};
-
-#ifdef CONFIG_PCI
-/*
- *	Must power the device up to do MDIO operations
- */
-static int vortex_ioctl(struct net_device *dev, struct ifreq *rq, int cmd)
-{
-	int err;
-	struct vortex_private *vp = netdev_priv(dev);
-	pci_power_t state = 0;
-
-	if(VORTEX_PCI(vp))
-		state = VORTEX_PCI(vp)->current_state;
-
-	/* The kernel core really should have pci_get_power_state() */
-
-	if(state != 0)
-		pci_set_power_state(VORTEX_PCI(vp), PCI_D0);
-	err = generic_mii_ioctl(&vp->mii, if_mii(rq), cmd, NULL);
-	if(state != 0)
-		pci_set_power_state(VORTEX_PCI(vp), state);
-
-	return err;
-}
-#endif
-
-
-/* Pre-Cyclone chips have no documented multicast filter, so the only
-   multicast setting is to receive all multicast frames.  At least
-   the chip has a very clean way to set the mode, unlike many others. */
-static void set_rx_mode(struct net_device *dev)
-{
-	struct vortex_private *vp = netdev_priv(dev);
-	void __iomem *ioaddr = vp->ioaddr;
-	int new_mode;
-
-	if (dev->flags & IFF_PROMISC) {
-		if (vortex_debug > 3)
-			pr_notice("%s: Setting promiscuous mode.\n", dev->name);
-		new_mode = SetRxFilter|RxStation|RxMulticast|RxBroadcast|RxProm;
-	} else	if (!netdev_mc_empty(dev) || dev->flags & IFF_ALLMULTI) {
-		new_mode = SetRxFilter|RxStation|RxMulticast|RxBroadcast;
-	} else
-		new_mode = SetRxFilter | RxStation | RxBroadcast;
-
-	iowrite16(new_mode, ioaddr + EL3_CMD);
-}
-
-#if IS_ENABLED(CONFIG_VLAN_8021Q)
-/* Setup the card so that it can receive frames with an 802.1q VLAN tag.
-   Note that this must be done after each RxReset due to some backwards
-   compatibility logic in the Cyclone and Tornado ASICs */
-
-/* The Ethernet Type used for 802.1q tagged frames */
-#define VLAN_ETHER_TYPE 0x8100
-
-static void set_8021q_mode(struct net_device *dev, int enable)
-{
-	struct vortex_private *vp = netdev_priv(dev);
-	int mac_ctrl;
-
-	if ((vp->drv_flags&IS_CYCLONE) || (vp->drv_flags&IS_TORNADO)) {
-		/* cyclone and tornado chipsets can recognize 802.1q
-		 * tagged frames and treat them correctly */
-
-		int max_pkt_size = dev->mtu+14;	/* MTU+Ethernet header */
-		if (enable)
-			max_pkt_size += 4;	/* 802.1Q VLAN tag */
-
-		window_write16(vp, max_pkt_size, 3, Wn3_MaxPktSize);
-
-		/* set VlanEtherType to let the hardware checksumming
-		   treat tagged frames correctly */
-		window_write16(vp, VLAN_ETHER_TYPE, 7, Wn7_VlanEtherType);
-	} else {
-		/* on older cards we have to enable large frames */
-
-		vp->large_frames = dev->mtu > 1500 || enable;
-
-		mac_ctrl = window_read16(vp, 3, Wn3_MAC_Ctrl);
-		if (vp->large_frames)
-			mac_ctrl |= 0x40;
-		else
-			mac_ctrl &= ~0x40;
-		window_write16(vp, mac_ctrl, 3, Wn3_MAC_Ctrl);
-	}
-}
-#else
-
-static void set_8021q_mode(struct net_device *dev, int enable)
-{
-}
-
-
-#endif
-
-/* MII transceiver control section.
-   Read and write the MII registers using software-generated serial
-   MDIO protocol.  See the MII specifications or DP83840A data sheet
-   for details. */
-
-/* The maximum data clock rate is 2.5 Mhz.  The minimum timing is usually
-   met by back-to-back PCI I/O cycles, but we insert a delay to avoid
-   "overclocking" issues. */
-static void mdio_delay(struct vortex_private *vp)
-{
-	window_read32(vp, 4, Wn4_PhysicalMgmt);
-}
-
-#define MDIO_SHIFT_CLK	0x01
-#define MDIO_DIR_WRITE	0x04
-#define MDIO_DATA_WRITE0 (0x00 | MDIO_DIR_WRITE)
-#define MDIO_DATA_WRITE1 (0x02 | MDIO_DIR_WRITE)
-#define MDIO_DATA_READ	0x02
-#define MDIO_ENB_IN		0x00
-
-/* Generate the preamble required for initial synchronization and
-   a few older transceivers. */
-static void mdio_sync(struct vortex_private *vp, int bits)
-{
-	/* Establish sync by sending at least 32 logic ones. */
-	while (-- bits >= 0) {
-		window_write16(vp, MDIO_DATA_WRITE1, 4, Wn4_PhysicalMgmt);
-		mdio_delay(vp);
-		window_write16(vp, MDIO_DATA_WRITE1 | MDIO_SHIFT_CLK,
-			       4, Wn4_PhysicalMgmt);
-		mdio_delay(vp);
-	}
-}
-
-static int mdio_read(struct net_device *dev, int phy_id, int location)
-{
-	int i;
-	struct vortex_private *vp = netdev_priv(dev);
-	int read_cmd = (0xf6 << 10) | (phy_id << 5) | location;
-	unsigned int retval = 0;
-
-	spin_lock_bh(&vp->mii_lock);
-
-	if (mii_preamble_required)
-		mdio_sync(vp, 32);
-
-	/* Shift the read command bits out. */
-	for (i = 14; i >= 0; i--) {
-		int dataval = (read_cmd&(1<<i)) ? MDIO_DATA_WRITE1 : MDIO_DATA_WRITE0;
-		window_write16(vp, dataval, 4, Wn4_PhysicalMgmt);
-		mdio_delay(vp);
-		window_write16(vp, dataval | MDIO_SHIFT_CLK,
-			       4, Wn4_PhysicalMgmt);
-		mdio_delay(vp);
-	}
-	/* Read the two transition, 16 data, and wire-idle bits. */
-	for (i = 19; i > 0; i--) {
-		window_write16(vp, MDIO_ENB_IN, 4, Wn4_PhysicalMgmt);
-		mdio_delay(vp);
-		retval = (retval << 1) |
-			((window_read16(vp, 4, Wn4_PhysicalMgmt) &
-			  MDIO_DATA_READ) ? 1 : 0);
-		window_write16(vp, MDIO_ENB_IN | MDIO_SHIFT_CLK,
-			       4, Wn4_PhysicalMgmt);
-		mdio_delay(vp);
-	}
-
-	spin_unlock_bh(&vp->mii_lock);
-
-	return retval & 0x20000 ? 0xffff : retval>>1 & 0xffff;
-}
-
-static void mdio_write(struct net_device *dev, int phy_id, int location, int value)
-{
-	struct vortex_private *vp = netdev_priv(dev);
-	int write_cmd = 0x50020000 | (phy_id << 23) | (location << 18) | value;
-	int i;
-
-	spin_lock_bh(&vp->mii_lock);
-
-	if (mii_preamble_required)
-		mdio_sync(vp, 32);
-
-	/* Shift the command bits out. */
-	for (i = 31; i >= 0; i--) {
-		int dataval = (write_cmd&(1<<i)) ? MDIO_DATA_WRITE1 : MDIO_DATA_WRITE0;
-		window_write16(vp, dataval, 4, Wn4_PhysicalMgmt);
-		mdio_delay(vp);
-		window_write16(vp, dataval | MDIO_SHIFT_CLK,
-			       4, Wn4_PhysicalMgmt);
-		mdio_delay(vp);
-	}
-	/* Leave the interface idle. */
-	for (i = 1; i >= 0; i--) {
-		window_write16(vp, MDIO_ENB_IN, 4, Wn4_PhysicalMgmt);
-		mdio_delay(vp);
-		window_write16(vp, MDIO_ENB_IN | MDIO_SHIFT_CLK,
-			       4, Wn4_PhysicalMgmt);
-		mdio_delay(vp);
-	}
-
-	spin_unlock_bh(&vp->mii_lock);
-}
-
-/* ACPI: Advanced Configuration and Power Interface. */
-/* Set Wake-On-LAN mode and put the board into D3 (power-down) state. */
-static void acpi_set_WOL(struct net_device *dev)
-{
-	struct vortex_private *vp = netdev_priv(dev);
-	void __iomem *ioaddr = vp->ioaddr;
-
-	device_set_wakeup_enable(vp->gendev, vp->enable_wol);
-
-	if (vp->enable_wol) {
-		/* Power up on: 1==Downloaded Filter, 2==Magic Packets, 4==Link Status. */
-		window_write16(vp, 2, 7, 0x0c);
-		/* The RxFilter must accept the WOL frames. */
-		iowrite16(SetRxFilter|RxStation|RxMulticast|RxBroadcast, ioaddr + EL3_CMD);
-		iowrite16(RxEnable, ioaddr + EL3_CMD);
-
-		if (pci_enable_wake(VORTEX_PCI(vp), PCI_D3hot, 1)) {
-			pr_info("%s: WOL not supported.\n", pci_name(VORTEX_PCI(vp)));
-
-			vp->enable_wol = 0;
-			return;
-		}
-
-		if (VORTEX_PCI(vp)->current_state < PCI_D3hot)
-			return;
-
-		/* Change the power state to D3; RxEnable doesn't take effect. */
-		pci_set_power_state(VORTEX_PCI(vp), PCI_D3hot);
-	}
-}
-
-
-static void vortex_remove_one(struct pci_dev *pdev)
-{
-	struct net_device *dev = pci_get_drvdata(pdev);
-	struct vortex_private *vp;
-
-	if (!dev) {
-		pr_err("vortex_remove_one called for Compaq device!\n");
-		BUG();
-	}
-
-	vp = netdev_priv(dev);
-
-	if (vp->cb_fn_base)
-		pci_iounmap(pdev, vp->cb_fn_base);
-
-	unregister_netdev(dev);
-
-	pci_set_power_state(pdev, PCI_D0);	/* Go active */
-	if (vp->pm_state_valid)
-		pci_restore_state(pdev);
-	pci_disable_device(pdev);
-
-	/* Should really use issue_and_wait() here */
-	iowrite16(TotalReset | ((vp->drv_flags & EEPROM_RESET) ? 0x04 : 0x14),
-	     vp->ioaddr + EL3_CMD);
-
-	pci_iounmap(pdev, vp->ioaddr);
-
-	dma_free_coherent(&pdev->dev,
-			sizeof(struct boom_rx_desc) * RX_RING_SIZE +
-			sizeof(struct boom_tx_desc) * TX_RING_SIZE,
-			vp->rx_ring, vp->rx_ring_dma);
-
-	pci_release_regions(pdev);
-
-	free_netdev(dev);
-}
-
-
-static struct pci_driver vortex_driver = {
-	.name		= "3c59x",
-	.probe		= vortex_init_one,
-	.remove		= vortex_remove_one,
-	.id_table	= vortex_pci_tbl,
-	.driver.pm	= VORTEX_PM_OPS,
-};
-
-
-static int vortex_have_pci;
-static int vortex_have_eisa;
-
-
-static int __init vortex_init(void)
-{
-	int pci_rc, eisa_rc;
-
-	pci_rc = pci_register_driver(&vortex_driver);
-	eisa_rc = vortex_eisa_init();
-
-	if (pci_rc == 0)
-		vortex_have_pci = 1;
-	if (eisa_rc > 0)
-		vortex_have_eisa = 1;
-
-	return (vortex_have_pci + vortex_have_eisa) ? 0 : -ENODEV;
-}
-
-
-static void __exit vortex_eisa_cleanup(void)
-{
-	void __iomem *ioaddr;
-
-#ifdef CONFIG_EISA
-	/* Take care of the EISA devices */
-	eisa_driver_unregister(&vortex_eisa_driver);
-#endif
-
-	if (compaq_net_device) {
-		ioaddr = ioport_map(compaq_net_device->base_addr,
-		                    VORTEX_TOTAL_SIZE);
-
-		unregister_netdev(compaq_net_device);
-		iowrite16(TotalReset, ioaddr + EL3_CMD);
-		release_region(compaq_net_device->base_addr,
-		               VORTEX_TOTAL_SIZE);
-
-		free_netdev(compaq_net_device);
-	}
-}
-
-
-static void __exit vortex_cleanup(void)
-{
-	if (vortex_have_pci)
-		pci_unregister_driver(&vortex_driver);
-	if (vortex_have_eisa)
-		vortex_eisa_cleanup();
-}
-
-
-module_init(vortex_init);
-module_exit(vortex_cleanup);
diff --git a/drivers/net/ethernet/3com/Kconfig b/drivers/net/ethernet/3com/Kconfig
index 399cb6c56198..5db57c4bc6fb 100644
--- a/drivers/net/ethernet/3com/Kconfig
+++ b/drivers/net/ethernet/3com/Kconfig
@@ -17,27 +17,6 @@ config NET_VENDOR_3COM
 
 if NET_VENDOR_3COM
 
-config VORTEX
-	tristate "3c590/3c900 series (592/595/597) \"Vortex/Boomerang\" support"
-	depends on (PCI || EISA) && HAS_IOPORT_MAP
-	select MII
-	help
-	  This option enables driver support for a large number of 10Mbps and
-	  10/100Mbps EISA, PCI and Cardbus 3Com network cards:
-
-	  "Vortex"    (Fast EtherLink 3c590/3c592/3c595/3c597) EISA and PCI
-	  "Boomerang" (EtherLink XL 3c900 or 3c905)            PCI
-	  "Cyclone"   (3c540/3c900/3c905/3c980/3c575/3c656)    PCI and Cardbus
-	  "Tornado"   (3c905)                                  PCI
-	  "Hurricane" (3c555/3cSOHO)                           PCI
-
-	  If you have such a card, say Y here.  More specific information is in
-	  <file:Documentation/networking/device_drivers/ethernet/3com/vortex.rst>
-	  and in the comments at the beginning of
-	  <file:drivers/net/ethernet/3com/3c59x.c>.
-
-	  To compile this support as a module, choose M here.
-
 config TYPHOON
 	tristate "3cr990 series \"Typhoon\" support"
 	depends on PCI
diff --git a/drivers/net/ethernet/3com/Makefile b/drivers/net/ethernet/3com/Makefile
index 5c4d07f1d456..6e250add60fe 100644
--- a/drivers/net/ethernet/3com/Makefile
+++ b/drivers/net/ethernet/3com/Makefile
@@ -3,5 +3,4 @@
 # Makefile for the 3Com Ethernet device drivers
 #
 
-obj-$(CONFIG_VORTEX) += 3c59x.o
 obj-$(CONFIG_TYPHOON) += typhoon.o

-- 
2.53.0


^ permalink raw reply related	[flat|nested] 28+ messages in thread

* [PATCH net 06/18] drivers: net: amd: Remove hplance and mvme147
  2026-04-21 19:31 [PATCH net 00/18] Remove a number of ISA and PCMCIA Ethernet drivers Andrew Lunn
                   ` (4 preceding siblings ...)
  2026-04-21 19:31 ` [PATCH net 05/18] drivers: net: 3com: 3c59x: " Andrew Lunn
@ 2026-04-21 19:31 ` Andrew Lunn
  2026-04-21 21:38   ` Daniel Palmer
  2026-04-21 19:31 ` [PATCH net 07/18] drivers: net: amd: lance: Remove this driver Andrew Lunn
                   ` (15 subsequent siblings)
  21 siblings, 1 reply; 28+ messages in thread
From: Andrew Lunn @ 2026-04-21 19:31 UTC (permalink / raw)
  To: Andrew Lunn, David S. Miller, Eric Dumazet, Jakub Kicinski,
	Paolo Abeni, Simon Horman, Jonathan Corbet, Shuah Khan
  Cc: linux-kernel, netdev, linux-doc, Andrew Lunn

These drivers use the 7990 core with wrappers for the HP300 and
Motorola MVME147 SBC circa 1998. It is unlikely they are used with a
modern kernel.

Signed-off-by: Andrew Lunn <andrew@lunn.ch>
---
 drivers/net/ethernet/amd/7990.c    | 671 -------------------------------------
 drivers/net/ethernet/amd/7990.h    | 251 --------------
 drivers/net/ethernet/amd/Kconfig   |  18 -
 drivers/net/ethernet/amd/Makefile  |   2 -
 drivers/net/ethernet/amd/hplance.c | 238 -------------
 drivers/net/ethernet/amd/hplance.h |  27 --
 drivers/net/ethernet/amd/mvme147.c | 198 -----------
 7 files changed, 1405 deletions(-)

diff --git a/drivers/net/ethernet/amd/7990.c b/drivers/net/ethernet/amd/7990.c
deleted file mode 100644
index 27792a52b6cf..000000000000
--- a/drivers/net/ethernet/amd/7990.c
+++ /dev/null
@@ -1,671 +0,0 @@
-// SPDX-License-Identifier: GPL-2.0-only
-/*
- * 7990.c -- LANCE ethernet IC generic routines.
- * This is an attempt to separate out the bits of various ethernet
- * drivers that are common because they all use the AMD 7990 LANCE
- * (Local Area Network Controller for Ethernet) chip.
- *
- * Copyright (C) 05/1998 Peter Maydell <pmaydell@chiark.greenend.org.uk>
- *
- * Most of this stuff was obtained by looking at other LANCE drivers,
- * in particular a2065.[ch]. The AMD C-LANCE datasheet was also helpful.
- * NB: this was made easy by the fact that Jes Sorensen had cleaned up
- * most of a2025 and sunlance with the aim of merging them, so the
- * common code was pretty obvious.
- */
-#include <linux/crc32.h>
-#include <linux/delay.h>
-#include <linux/errno.h>
-#include <linux/netdevice.h>
-#include <linux/etherdevice.h>
-#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/route.h>
-#include <linux/string.h>
-#include <linux/skbuff.h>
-#include <linux/pgtable.h>
-#include <asm/irq.h>
-/* Used for the temporal inet entries and routing */
-#include <linux/socket.h>
-#include <linux/bitops.h>
-
-#include <asm/io.h>
-#include <asm/dma.h>
-#ifdef CONFIG_HP300
-#include <asm/blinken.h>
-#endif
-
-#include "7990.h"
-
-#define WRITERAP(lp, x)	out_be16(lp->base + LANCE_RAP, (x))
-#define WRITERDP(lp, x)	out_be16(lp->base + LANCE_RDP, (x))
-#define READRDP(lp)	in_be16(lp->base + LANCE_RDP)
-
-#if IS_ENABLED(CONFIG_HPLANCE)
-#include "hplance.h"
-
-#undef WRITERAP
-#undef WRITERDP
-#undef READRDP
-
-#if IS_ENABLED(CONFIG_MVME147_NET)
-
-/* Lossage Factor Nine, Mr Sulu. */
-#define WRITERAP(lp, x)	(lp->writerap(lp, x))
-#define WRITERDP(lp, x)	(lp->writerdp(lp, x))
-#define READRDP(lp)	(lp->readrdp(lp))
-
-#else
-
-/* These inlines can be used if only CONFIG_HPLANCE is defined */
-static inline void WRITERAP(struct lance_private *lp, __u16 value)
-{
-	do {
-		out_be16(lp->base + HPLANCE_REGOFF + LANCE_RAP, value);
-	} while ((in_8(lp->base + HPLANCE_STATUS) & LE_ACK) == 0);
-}
-
-static inline void WRITERDP(struct lance_private *lp, __u16 value)
-{
-	do {
-		out_be16(lp->base + HPLANCE_REGOFF + LANCE_RDP, value);
-	} while ((in_8(lp->base + HPLANCE_STATUS) & LE_ACK) == 0);
-}
-
-static inline __u16 READRDP(struct lance_private *lp)
-{
-	__u16 value;
-	do {
-		value = in_be16(lp->base + HPLANCE_REGOFF + LANCE_RDP);
-	} while ((in_8(lp->base + HPLANCE_STATUS) & LE_ACK) == 0);
-	return value;
-}
-
-#endif
-#endif /* IS_ENABLED(CONFIG_HPLANCE) */
-
-/* debugging output macros, various flavours */
-/* #define TEST_HITS */
-#ifdef UNDEF
-#define PRINT_RINGS() \
-do { \
-	int t; \
-	for (t = 0; t < RX_RING_SIZE; t++) { \
-		printk("R%d: @(%02X %04X) len %04X, mblen %04X, bits %02X\n", \
-		       t, ib->brx_ring[t].rmd1_hadr, ib->brx_ring[t].rmd0, \
-		       ib->brx_ring[t].length, \
-		       ib->brx_ring[t].mblength, ib->brx_ring[t].rmd1_bits); \
-	} \
-	for (t = 0; t < TX_RING_SIZE; t++) { \
-		printk("T%d: @(%02X %04X) len %04X, misc %04X, bits %02X\n", \
-		       t, ib->btx_ring[t].tmd1_hadr, ib->btx_ring[t].tmd0, \
-		       ib->btx_ring[t].length, \
-		       ib->btx_ring[t].misc, ib->btx_ring[t].tmd1_bits); \
-	} \
-} while (0)
-#else
-#define PRINT_RINGS()
-#endif
-
-/* Load the CSR registers. The LANCE has to be STOPped when we do this! */
-static void load_csrs(struct lance_private *lp)
-{
-	volatile struct lance_init_block *aib = lp->lance_init_block;
-	int leptr;
-
-	leptr = LANCE_ADDR(aib);
-
-	WRITERAP(lp, LE_CSR1);                    /* load address of init block */
-	WRITERDP(lp, leptr & 0xFFFF);
-	WRITERAP(lp, LE_CSR2);
-	WRITERDP(lp, leptr >> 16);
-	WRITERAP(lp, LE_CSR3);
-	WRITERDP(lp, lp->busmaster_regval);       /* set byteswap/ALEctrl/byte ctrl */
-
-	/* Point back to csr0 */
-	WRITERAP(lp, LE_CSR0);
-}
-
-/* #define to 0 or 1 appropriately */
-#define DEBUG_IRING 0
-/* Set up the Lance Rx and Tx rings and the init block */
-static void lance_init_ring(struct net_device *dev)
-{
-	struct lance_private *lp = netdev_priv(dev);
-	volatile struct lance_init_block *ib = lp->init_block;
-	volatile struct lance_init_block *aib; /* for LANCE_ADDR computations */
-	int leptr;
-	int i;
-
-	aib = lp->lance_init_block;
-
-	lp->rx_new = lp->tx_new = 0;
-	lp->rx_old = lp->tx_old = 0;
-
-	ib->mode = LE_MO_PROM;                             /* normal, enable Tx & Rx */
-
-	/* Copy the ethernet address to the lance init block
-	 * Notice that we do a byteswap if we're big endian.
-	 * [I think this is the right criterion; at least, sunlance,
-	 * a2065 and atarilance do the byteswap and lance.c (PC) doesn't.
-	 * However, the datasheet says that the BSWAP bit doesn't affect
-	 * the init block, so surely it should be low byte first for
-	 * everybody? Um.]
-	 * We could define the ib->physaddr as three 16bit values and
-	 * use (addr[1] << 8) | addr[0] & co, but this is more efficient.
-	 */
-#ifdef __BIG_ENDIAN
-	ib->phys_addr[0] = dev->dev_addr[1];
-	ib->phys_addr[1] = dev->dev_addr[0];
-	ib->phys_addr[2] = dev->dev_addr[3];
-	ib->phys_addr[3] = dev->dev_addr[2];
-	ib->phys_addr[4] = dev->dev_addr[5];
-	ib->phys_addr[5] = dev->dev_addr[4];
-#else
-	for (i = 0; i < 6; i++)
-	       ib->phys_addr[i] = dev->dev_addr[i];
-#endif
-
-	if (DEBUG_IRING)
-		printk("TX rings:\n");
-
-	lp->tx_full = 0;
-	/* Setup the Tx ring entries */
-	for (i = 0; i < (1 << lp->lance_log_tx_bufs); i++) {
-		leptr = LANCE_ADDR(&aib->tx_buf[i][0]);
-		ib->btx_ring[i].tmd0      = leptr;
-		ib->btx_ring[i].tmd1_hadr = leptr >> 16;
-		ib->btx_ring[i].tmd1_bits = 0;
-		ib->btx_ring[i].length    = 0xf000; /* The ones required by tmd2 */
-		ib->btx_ring[i].misc      = 0;
-		if (DEBUG_IRING)
-			printk("%d: 0x%8.8x\n", i, leptr);
-	}
-
-	/* Setup the Rx ring entries */
-	if (DEBUG_IRING)
-		printk("RX rings:\n");
-	for (i = 0; i < (1 << lp->lance_log_rx_bufs); i++) {
-		leptr = LANCE_ADDR(&aib->rx_buf[i][0]);
-
-		ib->brx_ring[i].rmd0      = leptr;
-		ib->brx_ring[i].rmd1_hadr = leptr >> 16;
-		ib->brx_ring[i].rmd1_bits = LE_R1_OWN;
-		/* 0xf000 == bits that must be one (reserved, presumably) */
-		ib->brx_ring[i].length    = -RX_BUFF_SIZE | 0xf000;
-		ib->brx_ring[i].mblength  = 0;
-		if (DEBUG_IRING)
-			printk("%d: 0x%8.8x\n", i, leptr);
-	}
-
-	/* Setup the initialization block */
-
-	/* Setup rx descriptor pointer */
-	leptr = LANCE_ADDR(&aib->brx_ring);
-	ib->rx_len = (lp->lance_log_rx_bufs << 13) | (leptr >> 16);
-	ib->rx_ptr = leptr;
-	if (DEBUG_IRING)
-		printk("RX ptr: %8.8x\n", leptr);
-
-	/* Setup tx descriptor pointer */
-	leptr = LANCE_ADDR(&aib->btx_ring);
-	ib->tx_len = (lp->lance_log_tx_bufs << 13) | (leptr >> 16);
-	ib->tx_ptr = leptr;
-	if (DEBUG_IRING)
-		printk("TX ptr: %8.8x\n", leptr);
-
-	/* Clear the multicast filter */
-	ib->filter[0] = 0;
-	ib->filter[1] = 0;
-	PRINT_RINGS();
-}
-
-/* LANCE must be STOPped before we do this, too... */
-static int init_restart_lance(struct lance_private *lp)
-{
-	int i;
-
-	WRITERAP(lp, LE_CSR0);
-	WRITERDP(lp, LE_C0_INIT);
-
-	/* Need a hook here for sunlance ledma stuff */
-
-	/* Wait for the lance to complete initialization */
-	for (i = 0; (i < 100) && !(READRDP(lp) & (LE_C0_ERR | LE_C0_IDON)); i++)
-		barrier();
-	if ((i == 100) || (READRDP(lp) & LE_C0_ERR)) {
-		printk("LANCE unopened after %d ticks, csr0=%4.4x.\n", i, READRDP(lp));
-		return -1;
-	}
-
-	/* Clear IDON by writing a "1", enable interrupts and start lance */
-	WRITERDP(lp, LE_C0_IDON);
-	WRITERDP(lp, LE_C0_INEA | LE_C0_STRT);
-
-	return 0;
-}
-
-static int lance_reset(struct net_device *dev)
-{
-	struct lance_private *lp = netdev_priv(dev);
-	int status;
-
-	/* Stop the lance */
-	WRITERAP(lp, LE_CSR0);
-	WRITERDP(lp, LE_C0_STOP);
-
-	load_csrs(lp);
-	lance_init_ring(dev);
-	netif_trans_update(dev); /* prevent tx timeout */
-	status = init_restart_lance(lp);
-#ifdef DEBUG_DRIVER
-	printk("Lance restart=%d\n", status);
-#endif
-	return status;
-}
-
-static int lance_rx(struct net_device *dev)
-{
-	struct lance_private *lp = netdev_priv(dev);
-	volatile struct lance_init_block *ib = lp->init_block;
-	volatile struct lance_rx_desc *rd;
-	unsigned char bits;
-#ifdef TEST_HITS
-	int i;
-#endif
-
-#ifdef TEST_HITS
-	printk("[");
-	for (i = 0; i < RX_RING_SIZE; i++) {
-		if (i == lp->rx_new)
-			printk("%s",
-			       ib->brx_ring[i].rmd1_bits & LE_R1_OWN ? "_" : "X");
-		else
-			printk("%s",
-			      ib->brx_ring[i].rmd1_bits & LE_R1_OWN ? "." : "1");
-	}
-	printk("]");
-#endif
-#ifdef CONFIG_HP300
-	blinken_leds(0x40, 0);
-#endif
-	WRITERDP(lp, LE_C0_RINT | LE_C0_INEA);     /* ack Rx int, reenable ints */
-	for (rd = &ib->brx_ring[lp->rx_new];     /* For each Rx ring we own... */
-	     !((bits = rd->rmd1_bits) & LE_R1_OWN);
-	     rd = &ib->brx_ring[lp->rx_new]) {
-
-		/* We got an incomplete frame? */
-		if ((bits & LE_R1_POK) != LE_R1_POK) {
-			dev->stats.rx_over_errors++;
-			dev->stats.rx_errors++;
-			continue;
-		} else if (bits & LE_R1_ERR) {
-			/* Count only the end frame as a rx error,
-			 * not the beginning
-			 */
-			if (bits & LE_R1_BUF)
-				dev->stats.rx_fifo_errors++;
-			if (bits & LE_R1_CRC)
-				dev->stats.rx_crc_errors++;
-			if (bits & LE_R1_OFL)
-				dev->stats.rx_over_errors++;
-			if (bits & LE_R1_FRA)
-				dev->stats.rx_frame_errors++;
-			if (bits & LE_R1_EOP)
-				dev->stats.rx_errors++;
-		} else {
-			int len = (rd->mblength & 0xfff) - 4;
-			struct sk_buff *skb = netdev_alloc_skb(dev, len + 2);
-
-			if (!skb) {
-				dev->stats.rx_dropped++;
-				rd->mblength = 0;
-				rd->rmd1_bits = LE_R1_OWN;
-				lp->rx_new = (lp->rx_new + 1) & lp->rx_ring_mod_mask;
-				return 0;
-			}
-
-			skb_reserve(skb, 2);           /* 16 byte align */
-			skb_put(skb, len);             /* make room */
-			skb_copy_to_linear_data(skb,
-					 (unsigned char *)&(ib->rx_buf[lp->rx_new][0]),
-					 len);
-			skb->protocol = eth_type_trans(skb, dev);
-			netif_rx(skb);
-			dev->stats.rx_packets++;
-			dev->stats.rx_bytes += len;
-		}
-
-		/* Return the packet to the pool */
-		rd->mblength = 0;
-		rd->rmd1_bits = LE_R1_OWN;
-		lp->rx_new = (lp->rx_new + 1) & lp->rx_ring_mod_mask;
-	}
-	return 0;
-}
-
-static int lance_tx(struct net_device *dev)
-{
-	struct lance_private *lp = netdev_priv(dev);
-	volatile struct lance_init_block *ib = lp->init_block;
-	volatile struct lance_tx_desc *td;
-	int i, j;
-	int status;
-
-#ifdef CONFIG_HP300
-	blinken_leds(0x80, 0);
-#endif
-	/* csr0 is 2f3 */
-	WRITERDP(lp, LE_C0_TINT | LE_C0_INEA);
-	/* csr0 is 73 */
-
-	j = lp->tx_old;
-	for (i = j; i != lp->tx_new; i = j) {
-		td = &ib->btx_ring[i];
-
-		/* If we hit a packet not owned by us, stop */
-		if (td->tmd1_bits & LE_T1_OWN)
-			break;
-
-		if (td->tmd1_bits & LE_T1_ERR) {
-			status = td->misc;
-
-			dev->stats.tx_errors++;
-			if (status & LE_T3_RTY)
-				dev->stats.tx_aborted_errors++;
-			if (status & LE_T3_LCOL)
-				dev->stats.tx_window_errors++;
-
-			if (status & LE_T3_CLOS) {
-				dev->stats.tx_carrier_errors++;
-				if (lp->auto_select) {
-					lp->tpe = 1 - lp->tpe;
-					printk("%s: Carrier Lost, trying %s\n",
-					       dev->name,
-					       lp->tpe ? "TPE" : "AUI");
-					/* Stop the lance */
-					WRITERAP(lp, LE_CSR0);
-					WRITERDP(lp, LE_C0_STOP);
-					lance_init_ring(dev);
-					load_csrs(lp);
-					init_restart_lance(lp);
-					return 0;
-				}
-			}
-
-			/* buffer errors and underflows turn off the transmitter */
-			/* Restart the adapter */
-			if (status & (LE_T3_BUF|LE_T3_UFL)) {
-				dev->stats.tx_fifo_errors++;
-
-				printk("%s: Tx: ERR_BUF|ERR_UFL, restarting\n",
-				       dev->name);
-				/* Stop the lance */
-				WRITERAP(lp, LE_CSR0);
-				WRITERDP(lp, LE_C0_STOP);
-				lance_init_ring(dev);
-				load_csrs(lp);
-				init_restart_lance(lp);
-				return 0;
-			}
-		} else if ((td->tmd1_bits & LE_T1_POK) == LE_T1_POK) {
-			/*
-			 * So we don't count the packet more than once.
-			 */
-			td->tmd1_bits &= ~(LE_T1_POK);
-
-			/* One collision before packet was sent. */
-			if (td->tmd1_bits & LE_T1_EONE)
-				dev->stats.collisions++;
-
-			/* More than one collision, be optimistic. */
-			if (td->tmd1_bits & LE_T1_EMORE)
-				dev->stats.collisions += 2;
-
-			dev->stats.tx_packets++;
-		}
-
-		j = (j + 1) & lp->tx_ring_mod_mask;
-	}
-	lp->tx_old = j;
-	WRITERDP(lp, LE_C0_TINT | LE_C0_INEA);
-	return 0;
-}
-
-static irqreturn_t
-lance_interrupt(int irq, void *dev_id)
-{
-	struct net_device *dev = (struct net_device *)dev_id;
-	struct lance_private *lp = netdev_priv(dev);
-	int csr0;
-
-	spin_lock(&lp->devlock);
-
-	WRITERAP(lp, LE_CSR0);              /* LANCE Controller Status */
-	csr0 = READRDP(lp);
-
-	PRINT_RINGS();
-
-	if (!(csr0 & LE_C0_INTR)) {     /* Check if any interrupt has */
-		spin_unlock(&lp->devlock);
-		return IRQ_NONE;        /* been generated by the Lance. */
-	}
-
-	/* Acknowledge all the interrupt sources ASAP */
-	WRITERDP(lp, csr0 & ~(LE_C0_INEA|LE_C0_TDMD|LE_C0_STOP|LE_C0_STRT|LE_C0_INIT));
-
-	if ((csr0 & LE_C0_ERR)) {
-		/* Clear the error condition */
-		WRITERDP(lp, LE_C0_BABL|LE_C0_ERR|LE_C0_MISS|LE_C0_INEA);
-	}
-
-	if (csr0 & LE_C0_RINT)
-		lance_rx(dev);
-
-	if (csr0 & LE_C0_TINT)
-		lance_tx(dev);
-
-	/* Log misc errors. */
-	if (csr0 & LE_C0_BABL)
-		dev->stats.tx_errors++;       /* Tx babble. */
-	if (csr0 & LE_C0_MISS)
-		dev->stats.rx_errors++;       /* Missed a Rx frame. */
-	if (csr0 & LE_C0_MERR) {
-		printk("%s: Bus master arbitration failure, status %4.4x.\n",
-		       dev->name, csr0);
-		/* Restart the chip. */
-		WRITERDP(lp, LE_C0_STRT);
-	}
-
-	if (lp->tx_full && netif_queue_stopped(dev) && (TX_BUFFS_AVAIL >= 0)) {
-		lp->tx_full = 0;
-		netif_wake_queue(dev);
-	}
-
-	WRITERAP(lp, LE_CSR0);
-	WRITERDP(lp, LE_C0_BABL|LE_C0_CERR|LE_C0_MISS|LE_C0_MERR|LE_C0_IDON|LE_C0_INEA);
-
-	spin_unlock(&lp->devlock);
-	return IRQ_HANDLED;
-}
-
-int lance_open(struct net_device *dev)
-{
-	struct lance_private *lp = netdev_priv(dev);
-	int res;
-
-	/* Install the Interrupt handler. Or we could shunt this out to specific drivers? */
-	if (request_irq(lp->irq, lance_interrupt, IRQF_SHARED, lp->name, dev))
-		return -EAGAIN;
-
-	res = lance_reset(dev);
-	spin_lock_init(&lp->devlock);
-	netif_start_queue(dev);
-
-	return res;
-}
-EXPORT_SYMBOL_GPL(lance_open);
-
-int lance_close(struct net_device *dev)
-{
-	struct lance_private *lp = netdev_priv(dev);
-
-	netif_stop_queue(dev);
-
-	/* Stop the LANCE */
-	WRITERAP(lp, LE_CSR0);
-	WRITERDP(lp, LE_C0_STOP);
-
-	free_irq(lp->irq, dev);
-
-	return 0;
-}
-EXPORT_SYMBOL_GPL(lance_close);
-
-void lance_tx_timeout(struct net_device *dev, unsigned int txqueue)
-{
-	printk("lance_tx_timeout\n");
-	lance_reset(dev);
-	netif_trans_update(dev); /* prevent tx timeout */
-	netif_wake_queue(dev);
-}
-EXPORT_SYMBOL_GPL(lance_tx_timeout);
-
-netdev_tx_t lance_start_xmit(struct sk_buff *skb, struct net_device *dev)
-{
-	struct lance_private *lp = netdev_priv(dev);
-	volatile struct lance_init_block *ib = lp->init_block;
-	int entry, skblen, len;
-	static int outs;
-	unsigned long flags;
-
-	netif_stop_queue(dev);
-
-	if (!TX_BUFFS_AVAIL) {
-		dev_consume_skb_any(skb);
-		return NETDEV_TX_OK;
-	}
-
-	skblen = skb->len;
-
-#ifdef DEBUG_DRIVER
-	/* dump the packet */
-	{
-		int i;
-
-		for (i = 0; i < 64; i++) {
-			if ((i % 16) == 0)
-				printk("\n");
-			printk("%2.2x ", skb->data[i]);
-		}
-	}
-#endif
-	len = (skblen <= ETH_ZLEN) ? ETH_ZLEN : skblen;
-	entry = lp->tx_new & lp->tx_ring_mod_mask;
-	ib->btx_ring[entry].length = (-len) | 0xf000;
-	ib->btx_ring[entry].misc = 0;
-
-	if (skb->len < ETH_ZLEN)
-		memset((void *)&ib->tx_buf[entry][0], 0, ETH_ZLEN);
-	skb_copy_from_linear_data(skb, (void *)&ib->tx_buf[entry][0], skblen);
-
-	/* Now, give the packet to the lance */
-	ib->btx_ring[entry].tmd1_bits = (LE_T1_POK|LE_T1_OWN);
-	lp->tx_new = (lp->tx_new + 1) & lp->tx_ring_mod_mask;
-
-	outs++;
-	/* Kick the lance: transmit now */
-	WRITERDP(lp, LE_C0_INEA | LE_C0_TDMD);
-	dev_consume_skb_any(skb);
-
-	spin_lock_irqsave(&lp->devlock, flags);
-	if (TX_BUFFS_AVAIL)
-		netif_start_queue(dev);
-	else
-		lp->tx_full = 1;
-	spin_unlock_irqrestore(&lp->devlock, flags);
-
-	return NETDEV_TX_OK;
-}
-EXPORT_SYMBOL_GPL(lance_start_xmit);
-
-/* taken from the depca driver via a2065.c */
-static void lance_load_multicast(struct net_device *dev)
-{
-	struct lance_private *lp = netdev_priv(dev);
-	volatile struct lance_init_block *ib = lp->init_block;
-	volatile u16 *mcast_table = (u16 *)&ib->filter;
-	struct netdev_hw_addr *ha;
-	u32 crc;
-
-	/* set all multicast bits */
-	if (dev->flags & IFF_ALLMULTI) {
-		ib->filter[0] = 0xffffffff;
-		ib->filter[1] = 0xffffffff;
-		return;
-	}
-	/* clear the multicast filter */
-	ib->filter[0] = 0;
-	ib->filter[1] = 0;
-
-	/* Add addresses */
-	netdev_for_each_mc_addr(ha, dev) {
-		crc = ether_crc_le(6, ha->addr);
-		crc = crc >> 26;
-		mcast_table[crc >> 4] |= 1 << (crc & 0xf);
-	}
-}
-
-
-void lance_set_multicast(struct net_device *dev)
-{
-	struct lance_private *lp = netdev_priv(dev);
-	volatile struct lance_init_block *ib = lp->init_block;
-	int stopped;
-
-	stopped = netif_queue_stopped(dev);
-	if (!stopped)
-		netif_stop_queue(dev);
-
-	while (lp->tx_old != lp->tx_new)
-		schedule();
-
-	WRITERAP(lp, LE_CSR0);
-	WRITERDP(lp, LE_C0_STOP);
-	lance_init_ring(dev);
-
-	if (dev->flags & IFF_PROMISC) {
-		ib->mode |= LE_MO_PROM;
-	} else {
-		ib->mode &= ~LE_MO_PROM;
-		lance_load_multicast(dev);
-	}
-	load_csrs(lp);
-	init_restart_lance(lp);
-
-	if (!stopped)
-		netif_start_queue(dev);
-}
-EXPORT_SYMBOL_GPL(lance_set_multicast);
-
-#ifdef CONFIG_NET_POLL_CONTROLLER
-void lance_poll(struct net_device *dev)
-{
-	struct lance_private *lp = netdev_priv(dev);
-
-	spin_lock(&lp->devlock);
-	WRITERAP(lp, LE_CSR0);
-	WRITERDP(lp, LE_C0_STRT);
-	spin_unlock(&lp->devlock);
-	lance_interrupt(dev->irq, dev);
-}
-EXPORT_SYMBOL_GPL(lance_poll);
-#endif
-
-MODULE_DESCRIPTION("LANCE Ethernet IC generic routines");
-MODULE_LICENSE("GPL");
diff --git a/drivers/net/ethernet/amd/7990.h b/drivers/net/ethernet/amd/7990.h
deleted file mode 100644
index e53551daeea1..000000000000
--- a/drivers/net/ethernet/amd/7990.h
+++ /dev/null
@@ -1,251 +0,0 @@
-/* SPDX-License-Identifier: GPL-2.0 */
-/*
- * 7990.h -- LANCE ethernet IC generic routines.
- * This is an attempt to separate out the bits of various ethernet
- * drivers that are common because they all use the AMD 7990 LANCE
- * (Local Area Network Controller for Ethernet) chip.
- *
- * Copyright (C) 05/1998 Peter Maydell <pmaydell@chiark.greenend.org.uk>
- *
- * Most of this stuff was obtained by looking at other LANCE drivers,
- * in particular a2065.[ch]. The AMD C-LANCE datasheet was also helpful.
- */
-
-#ifndef _7990_H
-#define _7990_H
-
-/* The lance only has two register locations. We communicate mostly via memory. */
-#define LANCE_RDP	0	/* Register Data Port */
-#define LANCE_RAP	2	/* Register Address Port */
-
-/* Transmit/receive ring definitions.
- * We allow the specific drivers to override these defaults if they want to.
- * NB: according to lance.c, increasing the number of buffers is a waste
- * of space and reduces the chance that an upper layer will be able to
- * reorder queued Tx packets based on priority. [Clearly there is a minimum
- * limit too: too small and we drop rx packets and can't tx at full speed.]
- * 4+4 seems to be the usual setting; the atarilance driver uses 3 and 5.
- */
-
-/* Blast! This won't work. The problem is that we can't specify a default
- * setting because that would cause the lance_init_block struct to be
- * too long (and overflow the RAM on shared-memory cards like the HP LANCE.
- */
-#ifndef LANCE_LOG_TX_BUFFERS
-#define LANCE_LOG_TX_BUFFERS 1
-#define LANCE_LOG_RX_BUFFERS 3
-#endif
-
-#define TX_RING_SIZE		(1 << LANCE_LOG_TX_BUFFERS)
-#define RX_RING_SIZE		(1 << LANCE_LOG_RX_BUFFERS)
-#define TX_RING_MOD_MASK	(TX_RING_SIZE - 1)
-#define RX_RING_MOD_MASK	(RX_RING_SIZE - 1)
-#define TX_RING_LEN_BITS	((LANCE_LOG_TX_BUFFERS) << 29)
-#define RX_RING_LEN_BITS	((LANCE_LOG_RX_BUFFERS) << 29)
-#define PKT_BUFF_SIZE		(1544)
-#define RX_BUFF_SIZE		PKT_BUFF_SIZE
-#define TX_BUFF_SIZE		PKT_BUFF_SIZE
-
-/* Each receive buffer is described by a receive message descriptor (RMD) */
-struct lance_rx_desc {
-	volatile unsigned short rmd0;	    /* low address of packet */
-	volatile unsigned char  rmd1_bits;  /* descriptor bits */
-	volatile unsigned char  rmd1_hadr;  /* high address of packet */
-	volatile short    length;	    /* This length is 2s complement (negative)!
-					     * Buffer length */
-	volatile unsigned short mblength;   /* Actual number of bytes received */
-};
-
-/* Ditto for TMD: */
-struct lance_tx_desc {
-	volatile unsigned short tmd0;	    /* low address of packet */
-	volatile unsigned char  tmd1_bits;  /* descriptor bits */
-	volatile unsigned char  tmd1_hadr;  /* high address of packet */
-	volatile short    length;	    /* Length is 2s complement (negative)! */
-	volatile unsigned short misc;
-};
-
-/* There are three memory structures accessed by the LANCE:
- * the initialization block, the receive and transmit descriptor rings,
- * and the data buffers themselves. In fact we might as well put the
- * init block,the Tx and Rx rings and the buffers together in memory:
- */
-struct lance_init_block {
-	volatile unsigned short mode;		/* Pre-set mode (reg. 15) */
-	volatile unsigned char phys_addr[6];	/* Physical ethernet address */
-	volatile unsigned filter[2];		/* Multicast filter (64 bits) */
-
-	/* Receive and transmit ring base, along with extra bits. */
-	volatile unsigned short rx_ptr;		/* receive descriptor addr */
-	volatile unsigned short rx_len;		/* receive len and high addr */
-	volatile unsigned short tx_ptr;		/* transmit descriptor addr */
-	volatile unsigned short tx_len;		/* transmit len and high addr */
-
-	/* The Tx and Rx ring entries must be aligned on 8-byte boundaries.
-	 * This will be true if this whole struct is 8-byte aligned.
-	 */
-	volatile struct lance_tx_desc btx_ring[TX_RING_SIZE];
-	volatile struct lance_rx_desc brx_ring[RX_RING_SIZE];
-
-	volatile char tx_buf[TX_RING_SIZE][TX_BUFF_SIZE];
-	volatile char rx_buf[RX_RING_SIZE][RX_BUFF_SIZE];
-	/* we use this just to make the struct big enough that we can move its startaddr
-	 * in order to force alignment to an eight byte boundary.
-	 */
-};
-
-/* This is where we keep all the stuff the driver needs to know about.
- * I'm definitely unhappy about the mechanism for allowing specific
- * drivers to add things...
- */
-struct lance_private {
-	const char *name;
-	unsigned long base;
-	volatile struct lance_init_block *init_block; /* CPU address of RAM */
-	volatile struct lance_init_block *lance_init_block; /* LANCE address of RAM */
-
-	int rx_new, tx_new;
-	int rx_old, tx_old;
-
-	int lance_log_rx_bufs, lance_log_tx_bufs;
-	int rx_ring_mod_mask, tx_ring_mod_mask;
-
-	int tpe;			/* TPE is selected */
-	int auto_select;		/* cable-selection is by carrier */
-	unsigned short busmaster_regval;
-
-	unsigned int irq;		/* IRQ to register */
-
-	/* This is because the HP LANCE is disgusting and you have to check
-	 * a DIO-specific register every time you read/write the LANCE regs :-<
-	 * [could we get away with making these some sort of macro?]
-	 */
-	void (*writerap)(void *, unsigned short);
-	void (*writerdp)(void *, unsigned short);
-	unsigned short (*readrdp)(void *);
-	spinlock_t devlock;
-	char tx_full;
-};
-
-/*
- *		Am7990 Control and Status Registers
- */
-#define LE_CSR0		0x0000	/* LANCE Controller Status */
-#define LE_CSR1		0x0001	/* IADR[15:0] (bit0==0 ie word aligned) */
-#define LE_CSR2		0x0002	/* IADR[23:16] (high bits reserved) */
-#define LE_CSR3		0x0003	/* Misc */
-
-/*
- *		Bit definitions for CSR0 (LANCE Controller Status)
- */
-#define LE_C0_ERR	0x8000	/* Error = BABL | CERR | MISS | MERR */
-#define LE_C0_BABL	0x4000	/* Babble: Transmitted too many bits */
-#define LE_C0_CERR	0x2000	/* No Heartbeat (10BASE-T) */
-#define LE_C0_MISS	0x1000	/* Missed Frame (no rx buffer to put it in) */
-#define LE_C0_MERR	0x0800	/* Memory Error */
-#define LE_C0_RINT	0x0400	/* Receive Interrupt */
-#define LE_C0_TINT	0x0200	/* Transmit Interrupt */
-#define LE_C0_IDON	0x0100	/* Initialization Done */
-#define LE_C0_INTR	0x0080	/* Interrupt Flag
-				   = BABL | MISS | MERR | RINT | TINT | IDON */
-#define LE_C0_INEA	0x0040	/* Interrupt Enable */
-#define LE_C0_RXON	0x0020	/* Receive On */
-#define LE_C0_TXON	0x0010	/* Transmit On */
-#define LE_C0_TDMD	0x0008	/* Transmit Demand */
-#define LE_C0_STOP	0x0004	/* Stop */
-#define LE_C0_STRT	0x0002	/* Start */
-#define LE_C0_INIT	0x0001	/* Initialize */
-
-
-/*
- *		Bit definitions for CSR3
- */
-#define LE_C3_BSWP	0x0004	/* Byte Swap (on for big endian byte order) */
-#define LE_C3_ACON	0x0002	/* ALE Control (on for active low ALE) */
-#define LE_C3_BCON	0x0001	/* Byte Control */
-
-
-/*
- *		Mode Flags
- */
-#define LE_MO_PROM	0x8000	/* Promiscuous Mode */
-/* these next ones 0x4000 -- 0x0080 are not available on the LANCE 7990,
- * but they are in NetBSD's am7990.h, presumably for backwards-compatible chips
- */
-#define LE_MO_DRCVBC	0x4000	/* disable receive broadcast */
-#define LE_MO_DRCVPA	0x2000	/* disable physical address detection */
-#define LE_MO_DLNKTST	0x1000	/* disable link status */
-#define LE_MO_DAPC	0x0800	/* disable automatic polarity correction */
-#define LE_MO_MENDECL	0x0400	/* MENDEC loopback mode */
-#define LE_MO_LRTTSEL	0x0200	/* lower RX threshold / TX mode selection */
-#define LE_MO_PSEL1	0x0100	/* port selection bit1 */
-#define LE_MO_PSEL0	0x0080	/* port selection bit0 */
-/* and this one is from the C-LANCE data sheet... */
-#define LE_MO_EMBA	0x0080	/* Enable Modified Backoff Algorithm
-				   (C-LANCE, not original LANCE) */
-#define LE_MO_INTL	0x0040	/* Internal Loopback */
-#define LE_MO_DRTY	0x0020	/* Disable Retry */
-#define LE_MO_FCOLL	0x0010	/* Force Collision */
-#define LE_MO_DXMTFCS	0x0008	/* Disable Transmit CRC */
-#define LE_MO_LOOP	0x0004	/* Loopback Enable */
-#define LE_MO_DTX	0x0002	/* Disable Transmitter */
-#define LE_MO_DRX	0x0001	/* Disable Receiver */
-
-
-/*
- *		Receive Flags
- */
-#define LE_R1_OWN	0x80	/* LANCE owns the descriptor */
-#define LE_R1_ERR	0x40	/* Error */
-#define LE_R1_FRA	0x20	/* Framing Error */
-#define LE_R1_OFL	0x10	/* Overflow Error */
-#define LE_R1_CRC	0x08	/* CRC Error */
-#define LE_R1_BUF	0x04	/* Buffer Error */
-#define LE_R1_SOP	0x02	/* Start of Packet */
-#define LE_R1_EOP	0x01	/* End of Packet */
-#define LE_R1_POK	0x03	/* Packet is complete: SOP + EOP */
-
-
-/*
- *		Transmit Flags
- */
-#define LE_T1_OWN	0x80	/* LANCE owns the descriptor */
-#define LE_T1_ERR	0x40	/* Error */
-#define LE_T1_RES	0x20	/* Reserved, LANCE writes this with a zero */
-#define LE_T1_EMORE	0x10	/* More than one retry needed */
-#define LE_T1_EONE	0x08	/* One retry needed */
-#define LE_T1_EDEF	0x04	/* Deferred */
-#define LE_T1_SOP	0x02	/* Start of Packet */
-#define LE_T1_EOP	0x01	/* End of Packet */
-#define LE_T1_POK	0x03	/* Packet is complete: SOP + EOP */
-
-/*
- *		Error Flags
- */
-#define LE_T3_BUF	0x8000	/* Buffer Error */
-#define LE_T3_UFL	0x4000	/* Underflow Error */
-#define LE_T3_LCOL	0x1000	/* Late Collision */
-#define LE_T3_CLOS	0x0800	/* Loss of Carrier */
-#define LE_T3_RTY	0x0400	/* Retry Error */
-#define LE_T3_TDR	0x03ff	/* Time Domain Reflectometry */
-
-/* Miscellaneous useful macros */
-
-#define TX_BUFFS_AVAIL ((lp->tx_old <= lp->tx_new) ? \
-			lp->tx_old + lp->tx_ring_mod_mask - lp->tx_new : \
-			lp->tx_old - lp->tx_new - 1)
-
-/* The LANCE only uses 24 bit addresses. This does the obvious thing. */
-#define LANCE_ADDR(x) ((int)(x) & ~0xff000000)
-
-/* Now the prototypes we export */
-int lance_open(struct net_device *dev);
-int lance_close(struct net_device *dev);
-netdev_tx_t lance_start_xmit(struct sk_buff *skb, struct net_device *dev);
-void lance_set_multicast(struct net_device *dev);
-void lance_tx_timeout(struct net_device *dev, unsigned int txqueue);
-#ifdef CONFIG_NET_POLL_CONTROLLER
-void lance_poll(struct net_device *dev);
-#endif
-
-#endif /* ndef _7990_H */
diff --git a/drivers/net/ethernet/amd/Kconfig b/drivers/net/ethernet/amd/Kconfig
index 45e8d698781c..9e83f3aa435a 100644
--- a/drivers/net/ethernet/amd/Kconfig
+++ b/drivers/net/ethernet/amd/Kconfig
@@ -93,14 +93,6 @@ config DECLANCE
 	  DEC (now Compaq) based on the AMD LANCE chipset, including the
 	  DEPCA series.  (This chipset is better known via the NE2100 cards.)
 
-config HPLANCE
-	tristate "HP on-board LANCE support"
-	depends on DIO
-	select CRC32
-	help
-	  If you want to use the builtin "LANCE" Ethernet controller on an
-	  HP300 machine, say Y here.
-
 config MIPS_AU1X00_ENET
 	tristate "MIPS AU1000 Ethernet support"
 	depends on MIPS_ALCHEMY
@@ -110,16 +102,6 @@ config MIPS_AU1X00_ENET
 	  If you have an Alchemy Semi AU1X00 based system
 	  say Y.  Otherwise, say N.
 
-config MVME147_NET
-	tristate "MVME147 (LANCE) Ethernet support"
-	depends on MVME147
-	select CRC32
-	help
-	  Support for the on-board Ethernet interface on the Motorola MVME147
-	  single-board computer.  Say Y here to include the
-	  driver for this chip in your kernel.
-	  To compile this driver as a module, choose M here.
-
 config PCMCIA_NMCLAN
 	tristate "New Media PCMCIA support"
 	depends on PCMCIA && HAS_IOPORT
diff --git a/drivers/net/ethernet/amd/Makefile b/drivers/net/ethernet/amd/Makefile
index 2dcfb84731e1..387ec74e8e95 100644
--- a/drivers/net/ethernet/amd/Makefile
+++ b/drivers/net/ethernet/amd/Makefile
@@ -8,10 +8,8 @@ obj-$(CONFIG_AMD8111_ETH) += amd8111e.o
 obj-$(CONFIG_ARIADNE) += ariadne.o
 obj-$(CONFIG_ATARILANCE) += atarilance.o
 obj-$(CONFIG_DECLANCE) += declance.o
-obj-$(CONFIG_HPLANCE) += hplance.o 7990.o
 obj-$(CONFIG_LANCE) += lance.o
 obj-$(CONFIG_MIPS_AU1X00_ENET) += au1000_eth.o
-obj-$(CONFIG_MVME147_NET) += mvme147.o 7990.o
 obj-$(CONFIG_PCMCIA_NMCLAN) += nmclan_cs.o
 obj-$(CONFIG_PCNET32) += pcnet32.o
 obj-$(CONFIG_SUN3LANCE) += sun3lance.o
diff --git a/drivers/net/ethernet/amd/hplance.c b/drivers/net/ethernet/amd/hplance.c
deleted file mode 100644
index df42294530cb..000000000000
--- a/drivers/net/ethernet/amd/hplance.c
+++ /dev/null
@@ -1,238 +0,0 @@
-// SPDX-License-Identifier: GPL-2.0-only
-/* hplance.c  : the  Linux/hp300/lance ethernet driver
- *
- * Copyright (C) 05/1998 Peter Maydell <pmaydell@chiark.greenend.org.uk>
- * Based on the Sun Lance driver and the NetBSD HP Lance driver
- * Uses the generic 7990.c LANCE code.
- */
-
-#include <linux/module.h>
-#include <linux/kernel.h>
-#include <linux/types.h>
-#include <linux/interrupt.h>
-#include <linux/ioport.h>
-#include <linux/string.h>
-#include <linux/delay.h>
-#include <linux/init.h>
-#include <linux/errno.h>
-#include <linux/pgtable.h>
-/* Used for the temporal inet entries and routing */
-#include <linux/socket.h>
-#include <linux/route.h>
-#include <linux/dio.h>
-#include <linux/netdevice.h>
-#include <linux/etherdevice.h>
-#include <linux/skbuff.h>
-
-#include <asm/io.h>
-
-#include "hplance.h"
-
-/* We have 16392 bytes of RAM for the init block and buffers. This places
- * an upper limit on the number of buffers we can use. NetBSD uses 8 Rx
- * buffers and 2 Tx buffers, it takes (8 + 2) * 1544 bytes.
- */
-#define LANCE_LOG_TX_BUFFERS 1
-#define LANCE_LOG_RX_BUFFERS 3
-
-#include "7990.h"                                 /* use generic LANCE code */
-
-/* Our private data structure */
-struct hplance_private {
-	struct lance_private lance;
-};
-
-/* function prototypes... This is easy because all the grot is in the
- * generic LANCE support. All we have to support is probing for boards,
- * plus board-specific init, open and close actions.
- * Oh, and we need to tell the generic code how to read and write LANCE registers...
- */
-static int hplance_init_one(struct dio_dev *d, const struct dio_device_id *ent);
-static void hplance_init(struct net_device *dev, struct dio_dev *d);
-static void hplance_remove_one(struct dio_dev *d);
-static void hplance_writerap(void *priv, unsigned short value);
-static void hplance_writerdp(void *priv, unsigned short value);
-static unsigned short hplance_readrdp(void *priv);
-static int hplance_open(struct net_device *dev);
-static int hplance_close(struct net_device *dev);
-
-static struct dio_device_id hplance_dio_tbl[] = {
-	{ DIO_ID_LAN },
-	{ 0 }
-};
-
-static struct dio_driver hplance_driver = {
-	.name      = "hplance",
-	.id_table  = hplance_dio_tbl,
-	.probe     = hplance_init_one,
-	.remove    = hplance_remove_one,
-};
-
-static const struct net_device_ops hplance_netdev_ops = {
-	.ndo_open		= hplance_open,
-	.ndo_stop		= hplance_close,
-	.ndo_start_xmit		= lance_start_xmit,
-	.ndo_set_rx_mode	= lance_set_multicast,
-	.ndo_validate_addr	= eth_validate_addr,
-	.ndo_set_mac_address	= eth_mac_addr,
-#ifdef CONFIG_NET_POLL_CONTROLLER
-	.ndo_poll_controller	= lance_poll,
-#endif
-};
-
-/* Find all the HP Lance boards and initialise them... */
-static int hplance_init_one(struct dio_dev *d, const struct dio_device_id *ent)
-{
-	struct net_device *dev;
-	int err = -ENOMEM;
-
-	dev = alloc_etherdev(sizeof(struct hplance_private));
-	if (!dev)
-		goto out;
-
-	err = -EBUSY;
-	if (!request_mem_region(dio_resource_start(d),
-				dio_resource_len(d), d->name))
-		goto out_free_netdev;
-
-	hplance_init(dev, d);
-	err = register_netdev(dev);
-	if (err)
-		goto out_release_mem_region;
-
-	dio_set_drvdata(d, dev);
-
-	printk(KERN_INFO "%s: %s; select code %d, addr %pM, irq %d\n",
-	       dev->name, d->name, d->scode, dev->dev_addr, d->ipl);
-
-	return 0;
-
- out_release_mem_region:
-	release_mem_region(dio_resource_start(d), dio_resource_len(d));
- out_free_netdev:
-	free_netdev(dev);
- out:
-	return err;
-}
-
-static void hplance_remove_one(struct dio_dev *d)
-{
-	struct net_device *dev = dio_get_drvdata(d);
-
-	unregister_netdev(dev);
-	release_mem_region(dio_resource_start(d), dio_resource_len(d));
-	free_netdev(dev);
-}
-
-/* Initialise a single lance board at the given DIO device */
-static void hplance_init(struct net_device *dev, struct dio_dev *d)
-{
-	unsigned long va = (d->resource.start + DIO_VIRADDRBASE);
-	struct hplance_private *lp;
-	u8 addr[ETH_ALEN];
-	int i;
-
-	/* reset the board */
-	out_8(va + DIO_IDOFF, 0xff);
-	udelay(100);                              /* ariba! ariba! udelay! udelay! */
-
-	/* Fill the dev fields */
-	dev->base_addr = va;
-	dev->netdev_ops = &hplance_netdev_ops;
-	dev->dma = 0;
-
-	for (i = 0; i < 6; i++) {
-		/* The NVRAM holds our ethernet address, one nibble per byte,
-		 * at bytes NVRAMOFF+1,3,5,7,9...
-		 */
-		addr[i] = ((in_8(va + HPLANCE_NVRAMOFF + i*4 + 1) & 0xF) << 4)
-			| (in_8(va + HPLANCE_NVRAMOFF + i*4 + 3) & 0xF);
-	}
-	eth_hw_addr_set(dev, addr);
-
-	lp = netdev_priv(dev);
-	lp->lance.name = d->name;
-	lp->lance.base = va;
-	lp->lance.init_block = (struct lance_init_block *)(va + HPLANCE_MEMOFF); /* CPU addr */
-	lp->lance.lance_init_block = NULL;              /* LANCE addr of same RAM */
-	lp->lance.busmaster_regval = LE_C3_BSWP;        /* we're bigendian */
-	lp->lance.irq = d->ipl;
-	lp->lance.writerap = hplance_writerap;
-	lp->lance.writerdp = hplance_writerdp;
-	lp->lance.readrdp = hplance_readrdp;
-	lp->lance.lance_log_rx_bufs = LANCE_LOG_RX_BUFFERS;
-	lp->lance.lance_log_tx_bufs = LANCE_LOG_TX_BUFFERS;
-	lp->lance.rx_ring_mod_mask = RX_RING_MOD_MASK;
-	lp->lance.tx_ring_mod_mask = TX_RING_MOD_MASK;
-}
-
-/* This is disgusting. We have to check the DIO status register for ack every
- * time we read or write the LANCE registers.
- */
-static void hplance_writerap(void *priv, unsigned short value)
-{
-	struct lance_private *lp = (struct lance_private *)priv;
-
-	do {
-		out_be16(lp->base + HPLANCE_REGOFF + LANCE_RAP, value);
-	} while ((in_8(lp->base + HPLANCE_STATUS) & LE_ACK) == 0);
-}
-
-static void hplance_writerdp(void *priv, unsigned short value)
-{
-	struct lance_private *lp = (struct lance_private *)priv;
-
-	do {
-		out_be16(lp->base + HPLANCE_REGOFF + LANCE_RDP, value);
-	} while ((in_8(lp->base + HPLANCE_STATUS) & LE_ACK) == 0);
-}
-
-static unsigned short hplance_readrdp(void *priv)
-{
-	struct lance_private *lp = (struct lance_private *)priv;
-	__u16 value;
-
-	do {
-		value = in_be16(lp->base + HPLANCE_REGOFF + LANCE_RDP);
-	} while ((in_8(lp->base + HPLANCE_STATUS) & LE_ACK) == 0);
-	return value;
-}
-
-static int hplance_open(struct net_device *dev)
-{
-	int status;
-	struct lance_private *lp = netdev_priv(dev);
-
-	status = lance_open(dev);                 /* call generic lance open code */
-	if (status)
-		return status;
-	/* enable interrupts at board level. */
-	out_8(lp->base + HPLANCE_STATUS, LE_IE);
-
-	return 0;
-}
-
-static int hplance_close(struct net_device *dev)
-{
-	struct lance_private *lp = netdev_priv(dev);
-
-	out_8(lp->base + HPLANCE_STATUS, 0);	/* disable interrupts at boardlevel */
-	lance_close(dev);
-	return 0;
-}
-
-static int __init hplance_init_module(void)
-{
-	return dio_register_driver(&hplance_driver);
-}
-
-static void __exit hplance_cleanup_module(void)
-{
-	dio_unregister_driver(&hplance_driver);
-}
-
-module_init(hplance_init_module);
-module_exit(hplance_cleanup_module);
-
-MODULE_DESCRIPTION("HP300 on-board LANCE Ethernet driver");
-MODULE_LICENSE("GPL");
diff --git a/drivers/net/ethernet/amd/hplance.h b/drivers/net/ethernet/amd/hplance.h
deleted file mode 100644
index bc845a2c60c1..000000000000
--- a/drivers/net/ethernet/amd/hplance.h
+++ /dev/null
@@ -1,27 +0,0 @@
-/* SPDX-License-Identifier: GPL-2.0 */
-/* Random defines and structures for the HP Lance driver.
- * Copyright (C) 05/1998 Peter Maydell <pmaydell@chiark.greenend.org.uk>
- * Based on the Sun Lance driver and the NetBSD HP Lance driver
- */
-
-/* Registers */
-#define HPLANCE_ID		0x01		/* DIO register: ID byte */
-#define HPLANCE_STATUS		0x03		/* DIO register: interrupt enable/status */
-
-/* Control and status bits for the status register */
-#define LE_IE 0x80                                /* interrupt enable */
-#define LE_IR 0x40                                /* interrupt requested */
-#define LE_LOCK 0x08                              /* lock status register */
-#define LE_ACK 0x04                               /* ack of lock */
-#define LE_JAB 0x02                               /* loss of tx clock (???) */
-/* We can also extract the IPL from the status register with the standard
- * DIO_IPL(hplance) macro, or using dio_scodetoipl()
- */
-
-/* These are the offsets for the DIO regs (hplance_reg), lance_ioreg,
- * memory and NVRAM:
- */
-#define HPLANCE_IDOFF 0                           /* board baseaddr */
-#define HPLANCE_REGOFF 0x4000                     /* lance registers */
-#define HPLANCE_MEMOFF 0x8000                     /* struct lance_init_block */
-#define HPLANCE_NVRAMOFF 0xC008                   /* etheraddress as one *nibble* per byte */
diff --git a/drivers/net/ethernet/amd/mvme147.c b/drivers/net/ethernet/amd/mvme147.c
deleted file mode 100644
index f19b04b92fa9..000000000000
--- a/drivers/net/ethernet/amd/mvme147.c
+++ /dev/null
@@ -1,198 +0,0 @@
-// SPDX-License-Identifier: GPL-2.0-only
-/* mvme147.c  : the  Linux/mvme147/lance ethernet driver
- *
- * Copyright (C) 05/1998 Peter Maydell <pmaydell@chiark.greenend.org.uk>
- * Based on the Sun Lance driver and the NetBSD HP Lance driver
- * Uses the generic 7990.c LANCE code.
- */
-
-#include <linux/module.h>
-#include <linux/kernel.h>
-#include <linux/types.h>
-#include <linux/interrupt.h>
-#include <linux/ioport.h>
-#include <linux/string.h>
-#include <linux/delay.h>
-#include <linux/init.h>
-#include <linux/errno.h>
-#include <linux/gfp.h>
-#include <linux/pgtable.h>
-/* Used for the temporal inet entries and routing */
-#include <linux/socket.h>
-#include <linux/route.h>
-#include <linux/netdevice.h>
-#include <linux/etherdevice.h>
-#include <linux/skbuff.h>
-
-#include <asm/io.h>
-#include <asm/mvme147hw.h>
-
-/* We have 32K of RAM for the init block and buffers. This places
- * an upper limit on the number of buffers we can use. NetBSD uses 8 Rx
- * buffers and 2 Tx buffers, it takes (8 + 2) * 1544 bytes.
- */
-#define LANCE_LOG_TX_BUFFERS 1
-#define LANCE_LOG_RX_BUFFERS 3
-
-#include "7990.h"                                 /* use generic LANCE code */
-
-/* Our private data structure */
-struct m147lance_private {
-	struct lance_private lance;
-	unsigned long ram;
-};
-
-/* function prototypes... This is easy because all the grot is in the
- * generic LANCE support. All we have to support is probing for boards,
- * plus board-specific init, open and close actions.
- * Oh, and we need to tell the generic code how to read and write LANCE registers...
- */
-static int m147lance_open(struct net_device *dev);
-static int m147lance_close(struct net_device *dev);
-static void m147lance_writerap(struct lance_private *lp, unsigned short value);
-static void m147lance_writerdp(struct lance_private *lp, unsigned short value);
-static unsigned short m147lance_readrdp(struct lance_private *lp);
-
-typedef void (*writerap_t)(void *, unsigned short);
-typedef void (*writerdp_t)(void *, unsigned short);
-typedef unsigned short (*readrdp_t)(void *);
-
-static const struct net_device_ops lance_netdev_ops = {
-	.ndo_open		= m147lance_open,
-	.ndo_stop		= m147lance_close,
-	.ndo_start_xmit		= lance_start_xmit,
-	.ndo_set_rx_mode	= lance_set_multicast,
-	.ndo_tx_timeout		= lance_tx_timeout,
-	.ndo_validate_addr	= eth_validate_addr,
-	.ndo_set_mac_address	= eth_mac_addr,
-};
-
-/* Initialise the one and only on-board 7990 */
-static struct net_device * __init mvme147lance_probe(void)
-{
-	struct net_device *dev;
-	static int called;
-	static const char name[] = "MVME147 LANCE";
-	struct m147lance_private *lp;
-	u8 macaddr[ETH_ALEN];
-	u_long *addr;
-	u_long address;
-	int err;
-
-	if (!MACH_IS_MVME147 || called)
-		return ERR_PTR(-ENODEV);
-	called++;
-
-	dev = alloc_etherdev(sizeof(struct m147lance_private));
-	if (!dev)
-		return ERR_PTR(-ENOMEM);
-
-	/* Fill the dev fields */
-	dev->base_addr = (unsigned long)MVME147_LANCE_BASE;
-	dev->netdev_ops = &lance_netdev_ops;
-	dev->dma = 0;
-
-	addr = (u_long *)ETHERNET_ADDRESS;
-	address = *addr;
-	macaddr[0] = 0x08;
-	macaddr[1] = 0x00;
-	macaddr[2] = 0x3e;
-	address = address >> 8;
-	macaddr[5] = address&0xff;
-	address = address >> 8;
-	macaddr[4] = address&0xff;
-	address = address >> 8;
-	macaddr[3] = address&0xff;
-	eth_hw_addr_set(dev, macaddr);
-
-	lp = netdev_priv(dev);
-	lp->ram = __get_dma_pages(GFP_ATOMIC, 3);	/* 32K */
-	if (!lp->ram) {
-		printk("%s: No memory for LANCE buffers\n", dev->name);
-		free_netdev(dev);
-		return ERR_PTR(-ENOMEM);
-	}
-
-	lp->lance.name = name;
-	lp->lance.base = dev->base_addr;
-	lp->lance.init_block = (struct lance_init_block *)(lp->ram); /* CPU addr */
-	lp->lance.lance_init_block = (struct lance_init_block *)(lp->ram);                 /* LANCE addr of same RAM */
-	lp->lance.busmaster_regval = LE_C3_BSWP;        /* we're bigendian */
-	lp->lance.irq = MVME147_LANCE_IRQ;
-	lp->lance.writerap = (writerap_t)m147lance_writerap;
-	lp->lance.writerdp = (writerdp_t)m147lance_writerdp;
-	lp->lance.readrdp = (readrdp_t)m147lance_readrdp;
-	lp->lance.lance_log_rx_bufs = LANCE_LOG_RX_BUFFERS;
-	lp->lance.lance_log_tx_bufs = LANCE_LOG_TX_BUFFERS;
-	lp->lance.rx_ring_mod_mask = RX_RING_MOD_MASK;
-	lp->lance.tx_ring_mod_mask = TX_RING_MOD_MASK;
-
-	err = register_netdev(dev);
-	if (err) {
-		free_pages(lp->ram, 3);
-		free_netdev(dev);
-		return ERR_PTR(err);
-	}
-
-	netdev_info(dev, "MVME147 at 0x%08lx, irq %d, Hardware Address %pM\n",
-		    dev->base_addr, MVME147_LANCE_IRQ, dev->dev_addr);
-
-	return dev;
-}
-
-static void m147lance_writerap(struct lance_private *lp, unsigned short value)
-{
-	out_be16(lp->base + LANCE_RAP, value);
-}
-
-static void m147lance_writerdp(struct lance_private *lp, unsigned short value)
-{
-	out_be16(lp->base + LANCE_RDP, value);
-}
-
-static unsigned short m147lance_readrdp(struct lance_private *lp)
-{
-	return in_be16(lp->base + LANCE_RDP);
-}
-
-static int m147lance_open(struct net_device *dev)
-{
-	int status;
-
-	status = lance_open(dev);                 /* call generic lance open code */
-	if (status)
-		return status;
-	/* enable interrupts at board level. */
-	m147_pcc->lan_cntrl = 0;       /* clear the interrupts (if any) */
-	m147_pcc->lan_cntrl = 0x08 | 0x04;     /* Enable irq 4 */
-
-	return 0;
-}
-
-static int m147lance_close(struct net_device *dev)
-{
-	/* disable interrupts at boardlevel */
-	m147_pcc->lan_cntrl = 0x0; /* disable interrupts */
-	lance_close(dev);
-	return 0;
-}
-
-MODULE_DESCRIPTION("MVME147 LANCE Ethernet driver");
-MODULE_LICENSE("GPL");
-
-static struct net_device *dev_mvme147_lance;
-static int __init m147lance_init(void)
-{
-	dev_mvme147_lance = mvme147lance_probe();
-	return PTR_ERR_OR_ZERO(dev_mvme147_lance);
-}
-module_init(m147lance_init);
-
-static void __exit m147lance_exit(void)
-{
-	struct m147lance_private *lp = netdev_priv(dev_mvme147_lance);
-	unregister_netdev(dev_mvme147_lance);
-	free_pages(lp->ram, 3);
-	free_netdev(dev_mvme147_lance);
-}
-module_exit(m147lance_exit);

-- 
2.53.0


^ permalink raw reply related	[flat|nested] 28+ messages in thread

* [PATCH net 07/18] drivers: net: amd: lance: Remove this driver
  2026-04-21 19:31 [PATCH net 00/18] Remove a number of ISA and PCMCIA Ethernet drivers Andrew Lunn
                   ` (5 preceding siblings ...)
  2026-04-21 19:31 ` [PATCH net 06/18] drivers: net: amd: Remove hplance and mvme147 Andrew Lunn
@ 2026-04-21 19:31 ` Andrew Lunn
  2026-04-21 19:31 ` [PATCH net 08/18] drivers: net: amd: nmclan: " Andrew Lunn
                   ` (14 subsequent siblings)
  21 siblings, 0 replies; 28+ messages in thread
From: Andrew Lunn @ 2026-04-21 19:31 UTC (permalink / raw)
  To: Andrew Lunn, David S. Miller, Eric Dumazet, Jakub Kicinski,
	Paolo Abeni, Simon Horman, Jonathan Corbet, Shuah Khan
  Cc: linux-kernel, netdev, linux-doc, Andrew Lunn

The lance was written by Donald Becker between 1993-1998. It is an ISA
device, so unlikely to be used with modern kernels.

Signed-off-by: Andrew Lunn <andrew@lunn.ch>
---
 drivers/net/ethernet/amd/Kconfig  |   11 -
 drivers/net/ethernet/amd/Makefile |    1 -
 drivers/net/ethernet/amd/lance.c  | 1317 -------------------------------------
 3 files changed, 1329 deletions(-)

diff --git a/drivers/net/ethernet/amd/Kconfig b/drivers/net/ethernet/amd/Kconfig
index 9e83f3aa435a..f08b2ce8b952 100644
--- a/drivers/net/ethernet/amd/Kconfig
+++ b/drivers/net/ethernet/amd/Kconfig
@@ -43,17 +43,6 @@ config AMD8111_ETH
 	  To compile this driver as a module, choose M here. The module
 	  will be called amd8111e.
 
-config LANCE
-	tristate "AMD LANCE and PCnet (AT1500 and NE2100) support"
-	depends on ISA && ISA_DMA_API && !ARM && !PPC32
-	select NETDEV_LEGACY_INIT
-	help
-	  If you have a network (Ethernet) card of this type, say Y here.
-	  Some LinkSys cards are of this type.
-
-	  To compile this driver as a module, choose M here: the module
-	  will be called lance.  This is recommended.
-
 config PCNET32
 	tristate "AMD PCnet32 PCI support"
 	depends on PCI && HAS_IOPORT
diff --git a/drivers/net/ethernet/amd/Makefile b/drivers/net/ethernet/amd/Makefile
index 387ec74e8e95..d0aebfeedec3 100644
--- a/drivers/net/ethernet/amd/Makefile
+++ b/drivers/net/ethernet/amd/Makefile
@@ -8,7 +8,6 @@ obj-$(CONFIG_AMD8111_ETH) += amd8111e.o
 obj-$(CONFIG_ARIADNE) += ariadne.o
 obj-$(CONFIG_ATARILANCE) += atarilance.o
 obj-$(CONFIG_DECLANCE) += declance.o
-obj-$(CONFIG_LANCE) += lance.o
 obj-$(CONFIG_MIPS_AU1X00_ENET) += au1000_eth.o
 obj-$(CONFIG_PCMCIA_NMCLAN) += nmclan_cs.o
 obj-$(CONFIG_PCNET32) += pcnet32.o
diff --git a/drivers/net/ethernet/amd/lance.c b/drivers/net/ethernet/amd/lance.c
deleted file mode 100644
index 98afd8cb0efb..000000000000
--- a/drivers/net/ethernet/amd/lance.c
+++ /dev/null
@@ -1,1317 +0,0 @@
-/* lance.c: An AMD LANCE/PCnet ethernet driver for Linux. */
-/*
-	Written/copyright 1993-1998 by Donald Becker.
-
-	Copyright 1993 United States Government as represented by the
-	Director, National Security Agency.
-	This software may be used and distributed according to the terms
-	of the GNU General Public License, incorporated herein by reference.
-
-	This driver is for the Allied Telesis AT1500 and HP J2405A, and should work
-	with most other LANCE-based bus-master (NE2100/NE2500) ethercards.
-
-	The author may be reached as becker@scyld.com, or C/O
-	Scyld Computing Corporation
-	410 Severn Ave., Suite 210
-	Annapolis MD 21403
-
-	Andrey V. Savochkin:
-	- alignment problem with 1.3.* kernel and some minor changes.
-	Thomas Bogendoerfer (tsbogend@bigbug.franken.de):
-	- added support for Linux/Alpha, but removed most of it, because
-        it worked only for the PCI chip.
-      - added hook for the 32bit lance driver
-      - added PCnetPCI II (79C970A) to chip table
-	Paul Gortmaker (gpg109@rsphy1.anu.edu.au):
-	- hopefully fix above so Linux/Alpha can use ISA cards too.
-    8/20/96 Fixed 7990 autoIRQ failure and reversed unneeded alignment -djb
-    v1.12 10/27/97 Module support -djb
-    v1.14  2/3/98 Module support modified, made PCI support optional -djb
-    v1.15 5/27/99 Fixed bug in the cleanup_module(). dev->priv was freed
-                  before unregister_netdev() which caused NULL pointer
-                  reference later in the chain (in rtnetlink_fill_ifinfo())
-                  -- Mika Kuoppala <miku@iki.fi>
-
-    Forward ported v1.14 to 2.1.129, merged the PCI and misc changes from
-    the 2.1 version of the old driver - Alan Cox
-
-    Get rid of check_region, check kmalloc return in lance_probe1
-    Arnaldo Carvalho de Melo <acme@conectiva.com.br> - 11/01/2001
-
-	Reworked detection, added support for Racal InterLan EtherBlaster cards
-	Vesselin Kostadinov <vesok at yahoo dot com > - 22/4/2004
-*/
-
-static const char version[] = "lance.c:v1.16 2006/11/09 dplatt@3do.com, becker@cesdis.gsfc.nasa.gov\n";
-
-#include <linux/module.h>
-#include <linux/kernel.h>
-#include <linux/string.h>
-#include <linux/delay.h>
-#include <linux/errno.h>
-#include <linux/ioport.h>
-#include <linux/slab.h>
-#include <linux/interrupt.h>
-#include <linux/pci.h>
-#include <linux/init.h>
-#include <linux/netdevice.h>
-#include <linux/etherdevice.h>
-#include <linux/skbuff.h>
-#include <linux/mm.h>
-#include <linux/bitops.h>
-#include <net/Space.h>
-
-#include <asm/io.h>
-#include <asm/dma.h>
-
-static unsigned int lance_portlist[] __initdata = { 0x300, 0x320, 0x340, 0x360, 0};
-static int lance_probe1(struct net_device *dev, int ioaddr, int irq, int options);
-static int __init do_lance_probe(struct net_device *dev);
-
-
-static struct card {
-	char id_offset14;
-	char id_offset15;
-} cards[] = {
-	{	//"normal"
-		.id_offset14 = 0x57,
-		.id_offset15 = 0x57,
-	},
-	{	//NI6510EB
-		.id_offset14 = 0x52,
-		.id_offset15 = 0x44,
-	},
-	{	//Racal InterLan EtherBlaster
-		.id_offset14 = 0x52,
-		.id_offset15 = 0x49,
-	},
-};
-#define NUM_CARDS 3
-
-#ifdef LANCE_DEBUG
-static int lance_debug = LANCE_DEBUG;
-#else
-static int lance_debug = 1;
-#endif
-
-/*
-				Theory of Operation
-
-I. Board Compatibility
-
-This device driver is designed for the AMD 79C960, the "PCnet-ISA
-single-chip ethernet controller for ISA".  This chip is used in a wide
-variety of boards from vendors such as Allied Telesis, HP, Kingston,
-and Boca.  This driver is also intended to work with older AMD 7990
-designs, such as the NE1500 and NE2100, and newer 79C961.  For convenience,
-I use the name LANCE to refer to all of the AMD chips, even though it properly
-refers only to the original 7990.
-
-II. Board-specific settings
-
-The driver is designed to work the boards that use the faster
-bus-master mode, rather than in shared memory mode.	 (Only older designs
-have on-board buffer memory needed to support the slower shared memory mode.)
-
-Most ISA boards have jumpered settings for the I/O base, IRQ line, and DMA
-channel.  This driver probes the likely base addresses:
-{0x300, 0x320, 0x340, 0x360}.
-After the board is found it generates a DMA-timeout interrupt and uses
-autoIRQ to find the IRQ line.  The DMA channel can be set with the low bits
-of the otherwise-unused dev->mem_start value (aka PARAM1).  If unset it is
-probed for by enabling each free DMA channel in turn and checking if
-initialization succeeds.
-
-The HP-J2405A board is an exception: with this board it is easy to read the
-EEPROM-set values for the base, IRQ, and DMA.  (Of course you must already
-_know_ the base address -- that field is for writing the EEPROM.)
-
-III. Driver operation
-
-IIIa. Ring buffers
-The LANCE uses ring buffers of Tx and Rx descriptors.  Each entry describes
-the base and length of the data buffer, along with status bits.	 The length
-of these buffers is set by LANCE_LOG_{RX,TX}_BUFFERS, which is log_2() of
-the buffer length (rather than being directly the buffer length) for
-implementation ease.  The current values are 2 (Tx) and 4 (Rx), which leads to
-ring sizes of 4 (Tx) and 16 (Rx).  Increasing the number of ring entries
-needlessly uses extra space and reduces the chance that an upper layer will
-be able to reorder queued Tx packets based on priority.	 Decreasing the number
-of entries makes it more difficult to achieve back-to-back packet transmission
-and increases the chance that Rx ring will overflow.  (Consider the worst case
-of receiving back-to-back minimum-sized packets.)
-
-The LANCE has the capability to "chain" both Rx and Tx buffers, but this driver
-statically allocates full-sized (slightly oversized -- PKT_BUF_SZ) buffers to
-avoid the administrative overhead. For the Rx side this avoids dynamically
-allocating full-sized buffers "just in case", at the expense of a
-memory-to-memory data copy for each packet received.  For most systems this
-is a good tradeoff: the Rx buffer will always be in low memory, the copy
-is inexpensive, and it primes the cache for later packet processing.  For Tx
-the buffers are only used when needed as low-memory bounce buffers.
-
-IIIB. 16M memory limitations.
-For the ISA bus master mode all structures used directly by the LANCE,
-the initialization block, Rx and Tx rings, and data buffers, must be
-accessible from the ISA bus, i.e. in the lower 16M of real memory.
-This is a problem for current Linux kernels on >16M machines. The network
-devices are initialized after memory initialization, and the kernel doles out
-memory from the top of memory downward.	 The current solution is to have a
-special network initialization routine that's called before memory
-initialization; this will eventually be generalized for all network devices.
-As mentioned before, low-memory "bounce-buffers" are used when needed.
-
-IIIC. Synchronization
-The driver runs as two independent, single-threaded flows of control.  One
-is the send-packet routine, which enforces single-threaded use by the
-dev->tbusy flag.  The other thread is the interrupt handler, which is single
-threaded by the hardware and other software.
-
-The send packet thread has partial control over the Tx ring and 'dev->tbusy'
-flag.  It sets the tbusy flag whenever it's queuing a Tx packet. If the next
-queue slot is empty, it clears the tbusy flag when finished otherwise it sets
-the 'lp->tx_full' flag.
-
-The interrupt handler has exclusive control over the Rx ring and records stats
-from the Tx ring. (The Tx-done interrupt can't be selectively turned off, so
-we can't avoid the interrupt overhead by having the Tx routine reap the Tx
-stats.)	 After reaping the stats, it marks the queue entry as empty by setting
-the 'base' to zero. Iff the 'lp->tx_full' flag is set, it clears both the
-tx_full and tbusy flags.
-
-*/
-
-/* Set the number of Tx and Rx buffers, using Log_2(# buffers).
-   Reasonable default values are 16 Tx buffers, and 16 Rx buffers.
-   That translates to 4 and 4 (16 == 2^^4).
-   This is a compile-time option for efficiency.
-   */
-#ifndef LANCE_LOG_TX_BUFFERS
-#define LANCE_LOG_TX_BUFFERS 4
-#define LANCE_LOG_RX_BUFFERS 4
-#endif
-
-#define TX_RING_SIZE			(1 << (LANCE_LOG_TX_BUFFERS))
-#define TX_RING_MOD_MASK		(TX_RING_SIZE - 1)
-#define TX_RING_LEN_BITS		((LANCE_LOG_TX_BUFFERS) << 29)
-
-#define RX_RING_SIZE			(1 << (LANCE_LOG_RX_BUFFERS))
-#define RX_RING_MOD_MASK		(RX_RING_SIZE - 1)
-#define RX_RING_LEN_BITS		((LANCE_LOG_RX_BUFFERS) << 29)
-
-#define PKT_BUF_SZ		1544
-
-/* Offsets from base I/O address. */
-#define LANCE_DATA 0x10
-#define LANCE_ADDR 0x12
-#define LANCE_RESET 0x14
-#define LANCE_BUS_IF 0x16
-#define LANCE_TOTAL_SIZE 0x18
-
-#define TX_TIMEOUT	(HZ/5)
-
-/* The LANCE Rx and Tx ring descriptors. */
-struct lance_rx_head {
-	s32 base;
-	s16 buf_length;			/* This length is 2s complement (negative)! */
-	s16 msg_length;			/* This length is "normal". */
-};
-
-struct lance_tx_head {
-	s32 base;
-	s16 length;				/* Length is 2s complement (negative)! */
-	s16 misc;
-};
-
-/* The LANCE initialization block, described in databook. */
-struct lance_init_block {
-	u16 mode;		/* Pre-set mode (reg. 15) */
-	u8  phys_addr[6]; /* Physical ethernet address */
-	u32 filter[2];			/* Multicast filter (unused). */
-	/* Receive and transmit ring base, along with extra bits. */
-	u32  rx_ring;			/* Tx and Rx ring base pointers */
-	u32  tx_ring;
-};
-
-struct lance_private {
-	/* The Tx and Rx ring entries must be aligned on 8-byte boundaries. */
-	struct lance_rx_head rx_ring[RX_RING_SIZE];
-	struct lance_tx_head tx_ring[TX_RING_SIZE];
-	struct lance_init_block	init_block;
-	const char *name;
-	/* 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];
-	unsigned long rx_buffs;		/* Address of Rx and Tx buffers. */
-	/* Tx low-memory "bounce buffer" address. */
-	char (*tx_bounce_buffs)[PKT_BUF_SZ];
-	int cur_rx, cur_tx;			/* The next free ring entry */
-	int dirty_rx, dirty_tx;		/* The ring entries to be free()ed. */
-	int dma;
-	unsigned char chip_version;	/* See lance_chip_type. */
-	spinlock_t devlock;
-};
-
-#define LANCE_MUST_PAD          0x00000001
-#define LANCE_ENABLE_AUTOSELECT 0x00000002
-#define LANCE_MUST_REINIT_RING  0x00000004
-#define LANCE_MUST_UNRESET      0x00000008
-#define LANCE_HAS_MISSED_FRAME  0x00000010
-
-/* A mapping from the chip ID number to the part number and features.
-   These are from the datasheets -- in real life the '970 version
-   reportedly has the same ID as the '965. */
-static struct lance_chip_type {
-	int id_number;
-	const char *name;
-	int flags;
-} chip_table[] = {
-	{0x0000, "LANCE 7990",				/* Ancient lance chip.  */
-		LANCE_MUST_PAD + LANCE_MUST_UNRESET},
-	{0x0003, "PCnet/ISA 79C960",		/* 79C960 PCnet/ISA.  */
-		LANCE_ENABLE_AUTOSELECT + LANCE_MUST_REINIT_RING +
-			LANCE_HAS_MISSED_FRAME},
-	{0x2260, "PCnet/ISA+ 79C961",		/* 79C961 PCnet/ISA+, Plug-n-Play.  */
-		LANCE_ENABLE_AUTOSELECT + LANCE_MUST_REINIT_RING +
-			LANCE_HAS_MISSED_FRAME},
-	{0x2420, "PCnet/PCI 79C970",		/* 79C970 or 79C974 PCnet-SCSI, PCI. */
-		LANCE_ENABLE_AUTOSELECT + LANCE_MUST_REINIT_RING +
-			LANCE_HAS_MISSED_FRAME},
-	/* Bug: the PCnet/PCI actually uses the PCnet/VLB ID number, so just call
-		it the PCnet32. */
-	{0x2430, "PCnet32",					/* 79C965 PCnet for VL bus. */
-		LANCE_ENABLE_AUTOSELECT + LANCE_MUST_REINIT_RING +
-			LANCE_HAS_MISSED_FRAME},
-        {0x2621, "PCnet/PCI-II 79C970A",        /* 79C970A PCInetPCI II. */
-                LANCE_ENABLE_AUTOSELECT + LANCE_MUST_REINIT_RING +
-                        LANCE_HAS_MISSED_FRAME},
-	{0x0, 	 "PCnet (unknown)",
-		LANCE_ENABLE_AUTOSELECT + LANCE_MUST_REINIT_RING +
-			LANCE_HAS_MISSED_FRAME},
-};
-
-enum {OLD_LANCE = 0, PCNET_ISA=1, PCNET_ISAP=2, PCNET_PCI=3, PCNET_VLB=4, PCNET_PCI_II=5, LANCE_UNKNOWN=6};
-
-
-/* Non-zero if lance_probe1() needs to allocate low-memory bounce buffers.
-   Assume yes until we know the memory size. */
-static unsigned char lance_need_isa_bounce_buffers = 1;
-
-static int lance_open(struct net_device *dev);
-static void lance_init_ring(struct net_device *dev, gfp_t mode);
-static netdev_tx_t lance_start_xmit(struct sk_buff *skb,
-				    struct net_device *dev);
-static int lance_rx(struct net_device *dev);
-static irqreturn_t lance_interrupt(int irq, void *dev_id);
-static int lance_close(struct net_device *dev);
-static struct net_device_stats *lance_get_stats(struct net_device *dev);
-static void set_multicast_list(struct net_device *dev);
-static void lance_tx_timeout (struct net_device *dev, unsigned int txqueue);
-
-
-
-#ifdef MODULE
-#define MAX_CARDS		8	/* Max number of interfaces (cards) per module */
-
-static struct net_device *dev_lance[MAX_CARDS];
-static int io[MAX_CARDS];
-static int dma[MAX_CARDS];
-static int irq[MAX_CARDS];
-
-module_param_hw_array(io, int, ioport, NULL, 0);
-module_param_hw_array(dma, int, dma, NULL, 0);
-module_param_hw_array(irq, int, irq, NULL, 0);
-module_param(lance_debug, int, 0);
-MODULE_PARM_DESC(io, "LANCE/PCnet I/O base address(es),required");
-MODULE_PARM_DESC(dma, "LANCE/PCnet ISA DMA channel (ignored for some devices)");
-MODULE_PARM_DESC(irq, "LANCE/PCnet IRQ number (ignored for some devices)");
-MODULE_PARM_DESC(lance_debug, "LANCE/PCnet debug level (0-7)");
-
-static int __init lance_init_module(void)
-{
-	struct net_device *dev;
-	int this_dev, found = 0;
-
-	for (this_dev = 0; this_dev < MAX_CARDS; this_dev++) {
-		if (io[this_dev] == 0)  {
-			if (this_dev != 0) /* only complain once */
-				break;
-			printk(KERN_NOTICE "lance.c: Module autoprobing not allowed. Append \"io=0xNNN\" value(s).\n");
-			return -EPERM;
-		}
-		dev = alloc_etherdev(0);
-		if (!dev)
-			break;
-		dev->irq = irq[this_dev];
-		dev->base_addr = io[this_dev];
-		dev->dma = dma[this_dev];
-		if (do_lance_probe(dev) == 0) {
-			dev_lance[found++] = dev;
-			continue;
-		}
-		free_netdev(dev);
-		break;
-	}
-	if (found != 0)
-		return 0;
-	return -ENXIO;
-}
-module_init(lance_init_module);
-
-static void cleanup_card(struct net_device *dev)
-{
-	struct lance_private *lp = dev->ml_priv;
-	if (dev->dma != 4)
-		free_dma(dev->dma);
-	release_region(dev->base_addr, LANCE_TOTAL_SIZE);
-	kfree(lp->tx_bounce_buffs);
-	kfree((void*)lp->rx_buffs);
-	kfree(lp);
-}
-
-static void __exit lance_cleanup_module(void)
-{
-	int this_dev;
-
-	for (this_dev = 0; this_dev < MAX_CARDS; this_dev++) {
-		struct net_device *dev = dev_lance[this_dev];
-		if (dev) {
-			unregister_netdev(dev);
-			cleanup_card(dev);
-			free_netdev(dev);
-		}
-	}
-}
-module_exit(lance_cleanup_module);
-#endif /* MODULE */
-MODULE_DESCRIPTION("AMD LANCE/PCnet Ethernet driver");
-MODULE_LICENSE("GPL");
-
-
-/* Starting in v2.1.*, the LANCE/PCnet probe is now similar to the other
-   board probes now that kmalloc() can allocate ISA DMA-able regions.
-   This also allows the LANCE driver to be used as a module.
-   */
-static int __init do_lance_probe(struct net_device *dev)
-{
-	unsigned int *port;
-	int result;
-
-	if (high_memory <= phys_to_virt(16*1024*1024))
-		lance_need_isa_bounce_buffers = 0;
-
-	for (port = lance_portlist; *port; port++) {
-		int ioaddr = *port;
-		struct resource *r = request_region(ioaddr, LANCE_TOTAL_SIZE,
-							"lance-probe");
-
-		if (r) {
-			/* Detect the card with minimal I/O reads */
-			char offset14 = inb(ioaddr + 14);
-			int card;
-			for (card = 0; card < NUM_CARDS; ++card)
-				if (cards[card].id_offset14 == offset14)
-					break;
-			if (card < NUM_CARDS) {/*yes, the first byte matches*/
-				char offset15 = inb(ioaddr + 15);
-				for (card = 0; card < NUM_CARDS; ++card)
-					if ((cards[card].id_offset14 == offset14) &&
-						(cards[card].id_offset15 == offset15))
-						break;
-			}
-			if (card < NUM_CARDS) { /*Signature OK*/
-				result = lance_probe1(dev, ioaddr, 0, 0);
-				if (!result) {
-					struct lance_private *lp = dev->ml_priv;
-					int ver = lp->chip_version;
-
-					r->name = chip_table[ver].name;
-					return 0;
-				}
-			}
-			release_region(ioaddr, LANCE_TOTAL_SIZE);
-		}
-	}
-	return -ENODEV;
-}
-
-#ifndef MODULE
-struct net_device * __init lance_probe(int unit)
-{
-	struct net_device *dev = alloc_etherdev(0);
-	int err;
-
-	if (!dev)
-		return ERR_PTR(-ENODEV);
-
-	sprintf(dev->name, "eth%d", unit);
-	netdev_boot_setup_check(dev);
-
-	err = do_lance_probe(dev);
-	if (err)
-		goto out;
-	return dev;
-out:
-	free_netdev(dev);
-	return ERR_PTR(err);
-}
-#endif
-
-static const struct net_device_ops lance_netdev_ops = {
-	.ndo_open 		= lance_open,
-	.ndo_start_xmit		= lance_start_xmit,
-	.ndo_stop		= lance_close,
-	.ndo_get_stats		= lance_get_stats,
-	.ndo_set_rx_mode	= set_multicast_list,
-	.ndo_tx_timeout		= lance_tx_timeout,
-	.ndo_set_mac_address 	= eth_mac_addr,
-	.ndo_validate_addr	= eth_validate_addr,
-};
-
-static int __init lance_probe1(struct net_device *dev, int ioaddr, int irq, int options)
-{
-	struct lance_private *lp;
-	unsigned long dma_channels;	/* Mark spuriously-busy DMA channels */
-	int i, reset_val, lance_version;
-	const char *chipname;
-	/* Flags for specific chips or boards. */
-	unsigned char hpJ2405A = 0;	/* HP ISA adaptor */
-	int hp_builtin = 0;		/* HP on-board ethernet. */
-	static int did_version;		/* Already printed version info. */
-	unsigned long flags;
-	int err = -ENOMEM;
-	void __iomem *bios;
-	u8 addr[ETH_ALEN];
-
-	/* First we look for special cases.
-	   Check for HP's on-board ethernet by looking for 'HP' in the BIOS.
-	   There are two HP versions, check the BIOS for the configuration port.
-	   This method provided by L. Julliard, Laurent_Julliard@grenoble.hp.com.
-	   */
-	bios = ioremap(0xf00f0, 0x14);
-	if (!bios)
-		return -ENOMEM;
-	if (readw(bios + 0x12) == 0x5048)  {
-		static const short ioaddr_table[] = { 0x300, 0x320, 0x340, 0x360};
-		int hp_port = (readl(bios + 1) & 1)  ? 0x499 : 0x99;
-		/* We can have boards other than the built-in!  Verify this is on-board. */
-		if ((inb(hp_port) & 0xc0) == 0x80 &&
-		    ioaddr_table[inb(hp_port) & 3] == ioaddr)
-			hp_builtin = hp_port;
-	}
-	iounmap(bios);
-	/* We also recognize the HP Vectra on-board here, but check below. */
-	hpJ2405A = (inb(ioaddr) == 0x08 && inb(ioaddr+1) == 0x00 &&
-		    inb(ioaddr+2) == 0x09);
-
-	/* Reset the LANCE.	 */
-	reset_val = inw(ioaddr+LANCE_RESET); /* Reset the LANCE */
-
-	/* The Un-Reset needed is only needed for the real NE2100, and will
-	   confuse the HP board. */
-	if (!hpJ2405A)
-		outw(reset_val, ioaddr+LANCE_RESET);
-
-	outw(0x0000, ioaddr+LANCE_ADDR); /* Switch to window 0 */
-	if (inw(ioaddr+LANCE_DATA) != 0x0004)
-		return -ENODEV;
-
-	/* Get the version of the chip. */
-	outw(88, ioaddr+LANCE_ADDR);
-	if (inw(ioaddr+LANCE_ADDR) != 88) {
-		lance_version = 0;
-	} else {			/* Good, it's a newer chip. */
-		int chip_version = inw(ioaddr+LANCE_DATA);
-		outw(89, ioaddr+LANCE_ADDR);
-		chip_version |= inw(ioaddr+LANCE_DATA) << 16;
-		if (lance_debug > 2)
-			printk("  LANCE chip version is %#x.\n", chip_version);
-		if ((chip_version & 0xfff) != 0x003)
-			return -ENODEV;
-		chip_version = (chip_version >> 12) & 0xffff;
-		for (lance_version = 1; chip_table[lance_version].id_number; lance_version++) {
-			if (chip_table[lance_version].id_number == chip_version)
-				break;
-		}
-	}
-
-	/* We can't allocate private data from alloc_etherdev() because it must
-	   a ISA DMA-able region. */
-	chipname = chip_table[lance_version].name;
-	printk("%s: %s at %#3x, ", dev->name, chipname, ioaddr);
-
-	/* There is a 16 byte station address PROM at the base address.
-	   The first six bytes are the station address. */
-	for (i = 0; i < 6; i++)
-		addr[i] = inb(ioaddr + i);
-	eth_hw_addr_set(dev, addr);
-	printk("%pM", dev->dev_addr);
-
-	dev->base_addr = ioaddr;
-	/* Make certain the data structures used by the LANCE are aligned and DMAble. */
-
-	lp = kzalloc_obj(*lp, GFP_DMA | GFP_KERNEL);
-	if (!lp)
-		return -ENOMEM;
-	if (lance_debug > 6) printk(" (#0x%05lx)", (unsigned long)lp);
-	dev->ml_priv = lp;
-	lp->name = chipname;
-	lp->rx_buffs = (unsigned long)kmalloc_array(RX_RING_SIZE, PKT_BUF_SZ,
-						    GFP_DMA | GFP_KERNEL);
-	if (!lp->rx_buffs)
-		goto out_lp;
-	if (lance_need_isa_bounce_buffers) {
-		lp->tx_bounce_buffs = kmalloc_array(TX_RING_SIZE, PKT_BUF_SZ,
-						    GFP_DMA | GFP_KERNEL);
-		if (!lp->tx_bounce_buffs)
-			goto out_rx;
-	} else
-		lp->tx_bounce_buffs = NULL;
-
-	lp->chip_version = lance_version;
-	spin_lock_init(&lp->devlock);
-
-	lp->init_block.mode = 0x0003;		/* Disable Rx and Tx. */
-	for (i = 0; i < 6; i++)
-		lp->init_block.phys_addr[i] = dev->dev_addr[i];
-	lp->init_block.filter[0] = 0x00000000;
-	lp->init_block.filter[1] = 0x00000000;
-	lp->init_block.rx_ring = ((u32)isa_virt_to_bus(lp->rx_ring) & 0xffffff) | RX_RING_LEN_BITS;
-	lp->init_block.tx_ring = ((u32)isa_virt_to_bus(lp->tx_ring) & 0xffffff) | TX_RING_LEN_BITS;
-
-	outw(0x0001, ioaddr+LANCE_ADDR);
-	inw(ioaddr+LANCE_ADDR);
-	outw((short) (u32) isa_virt_to_bus(&lp->init_block), ioaddr+LANCE_DATA);
-	outw(0x0002, ioaddr+LANCE_ADDR);
-	inw(ioaddr+LANCE_ADDR);
-	outw(((u32)isa_virt_to_bus(&lp->init_block)) >> 16, ioaddr+LANCE_DATA);
-	outw(0x0000, ioaddr+LANCE_ADDR);
-	inw(ioaddr+LANCE_ADDR);
-
-	if (irq) {					/* Set iff PCI card. */
-		dev->dma = 4;			/* Native bus-master, no DMA channel needed. */
-		dev->irq = irq;
-	} else if (hp_builtin) {
-		static const char dma_tbl[4] = {3, 5, 6, 0};
-		static const char irq_tbl[4] = {3, 4, 5, 9};
-		unsigned char port_val = inb(hp_builtin);
-		dev->dma = dma_tbl[(port_val >> 4) & 3];
-		dev->irq = irq_tbl[(port_val >> 2) & 3];
-		printk(" HP Vectra IRQ %d DMA %d.\n", dev->irq, dev->dma);
-	} else if (hpJ2405A) {
-		static const char dma_tbl[4] = {3, 5, 6, 7};
-		static const char irq_tbl[8] = {3, 4, 5, 9, 10, 11, 12, 15};
-		short reset_val = inw(ioaddr+LANCE_RESET);
-		dev->dma = dma_tbl[(reset_val >> 2) & 3];
-		dev->irq = irq_tbl[(reset_val >> 4) & 7];
-		printk(" HP J2405A IRQ %d DMA %d.\n", dev->irq, dev->dma);
-	} else if (lance_version == PCNET_ISAP) {		/* The plug-n-play version. */
-		short bus_info;
-		outw(8, ioaddr+LANCE_ADDR);
-		bus_info = inw(ioaddr+LANCE_BUS_IF);
-		dev->dma = bus_info & 0x07;
-		dev->irq = (bus_info >> 4) & 0x0F;
-	} else {
-		/* The DMA channel may be passed in PARAM1. */
-		if (dev->mem_start & 0x07)
-			dev->dma = dev->mem_start & 0x07;
-	}
-
-	if (dev->dma == 0) {
-		/* Read the DMA channel status register, so that we can avoid
-		   stuck DMA channels in the DMA detection below. */
-		dma_channels = ((inb(DMA1_STAT_REG) >> 4) & 0x0f) |
-			(inb(DMA2_STAT_REG) & 0xf0);
-	}
-	err = -ENODEV;
-	if (dev->irq >= 2)
-		printk(" assigned IRQ %d", dev->irq);
-	else if (lance_version != 0)  {	/* 7990 boards need DMA detection first. */
-		unsigned long irq_mask;
-
-		/* To auto-IRQ we enable the initialization-done and DMA error
-		   interrupts. For ISA boards we get a DMA error, but VLB and PCI
-		   boards will work. */
-		irq_mask = probe_irq_on();
-
-		/* Trigger an initialization just for the interrupt. */
-		outw(0x0041, ioaddr+LANCE_DATA);
-
-		mdelay(20);
-		dev->irq = probe_irq_off(irq_mask);
-		if (dev->irq)
-			printk(", probed IRQ %d", dev->irq);
-		else {
-			printk(", failed to detect IRQ line.\n");
-			goto out_tx;
-		}
-
-		/* Check for the initialization done bit, 0x0100, which means
-		   that we don't need a DMA channel. */
-		if (inw(ioaddr+LANCE_DATA) & 0x0100)
-			dev->dma = 4;
-	}
-
-	if (dev->dma == 4) {
-		printk(", no DMA needed.\n");
-	} else if (dev->dma) {
-		if (request_dma(dev->dma, chipname)) {
-			printk("DMA %d allocation failed.\n", dev->dma);
-			goto out_tx;
-		} else
-			printk(", assigned DMA %d.\n", dev->dma);
-	} else {			/* OK, we have to auto-DMA. */
-		for (i = 0; i < 4; i++) {
-			static const char dmas[] = { 5, 6, 7, 3 };
-			int dma = dmas[i];
-			int boguscnt;
-
-			/* Don't enable a permanently busy DMA channel, or the machine
-			   will hang. */
-			if (test_bit(dma, &dma_channels))
-				continue;
-			outw(0x7f04, ioaddr+LANCE_DATA); /* Clear the memory error bits. */
-			if (request_dma(dma, chipname))
-				continue;
-
-			flags=claim_dma_lock();
-			set_dma_mode(dma, DMA_MODE_CASCADE);
-			enable_dma(dma);
-			release_dma_lock(flags);
-
-			/* Trigger an initialization. */
-			outw(0x0001, ioaddr+LANCE_DATA);
-			for (boguscnt = 100; boguscnt > 0; --boguscnt)
-				if (inw(ioaddr+LANCE_DATA) & 0x0900)
-					break;
-			if (inw(ioaddr+LANCE_DATA) & 0x0100) {
-				dev->dma = dma;
-				printk(", DMA %d.\n", dev->dma);
-				break;
-			} else {
-				flags=claim_dma_lock();
-				disable_dma(dma);
-				release_dma_lock(flags);
-				free_dma(dma);
-			}
-		}
-		if (i == 4) {			/* Failure: bail. */
-			printk("DMA detection failed.\n");
-			goto out_tx;
-		}
-	}
-
-	if (lance_version == 0 && dev->irq == 0) {
-		/* We may auto-IRQ now that we have a DMA channel. */
-		/* Trigger an initialization just for the interrupt. */
-		unsigned long irq_mask;
-
-		irq_mask = probe_irq_on();
-		outw(0x0041, ioaddr+LANCE_DATA);
-
-		mdelay(40);
-		dev->irq = probe_irq_off(irq_mask);
-		if (dev->irq == 0) {
-			printk("  Failed to detect the 7990 IRQ line.\n");
-			goto out_dma;
-		}
-		printk("  Auto-IRQ detected IRQ%d.\n", dev->irq);
-	}
-
-	if (chip_table[lp->chip_version].flags & LANCE_ENABLE_AUTOSELECT) {
-		/* Turn on auto-select of media (10baseT or BNC) so that the user
-		   can watch the LEDs even if the board isn't opened. */
-		outw(0x0002, ioaddr+LANCE_ADDR);
-		/* Don't touch 10base2 power bit. */
-		outw(inw(ioaddr+LANCE_BUS_IF) | 0x0002, ioaddr+LANCE_BUS_IF);
-	}
-
-	if (lance_debug > 0  &&  did_version++ == 0)
-		printk(version);
-
-	/* The LANCE-specific entries in the device structure. */
-	dev->netdev_ops = &lance_netdev_ops;
-	dev->watchdog_timeo = TX_TIMEOUT;
-
-	err = register_netdev(dev);
-	if (err)
-		goto out_dma;
-	return 0;
-out_dma:
-	if (dev->dma != 4)
-		free_dma(dev->dma);
-out_tx:
-	kfree(lp->tx_bounce_buffs);
-out_rx:
-	kfree((void*)lp->rx_buffs);
-out_lp:
-	kfree(lp);
-	return err;
-}
-
-
-static int
-lance_open(struct net_device *dev)
-{
-	struct lance_private *lp = dev->ml_priv;
-	int ioaddr = dev->base_addr;
-	int i;
-
-	if (dev->irq == 0 ||
-		request_irq(dev->irq, lance_interrupt, 0, dev->name, dev)) {
-		return -EAGAIN;
-	}
-
-	/* We used to allocate DMA here, but that was silly.
-	   DMA lines can't be shared!  We now permanently allocate them. */
-
-	/* Reset the LANCE */
-	inw(ioaddr+LANCE_RESET);
-
-	/* The DMA controller is used as a no-operation slave, "cascade mode". */
-	if (dev->dma != 4) {
-		unsigned long flags=claim_dma_lock();
-		enable_dma(dev->dma);
-		set_dma_mode(dev->dma, DMA_MODE_CASCADE);
-		release_dma_lock(flags);
-	}
-
-	/* Un-Reset the LANCE, needed only for the NE2100. */
-	if (chip_table[lp->chip_version].flags & LANCE_MUST_UNRESET)
-		outw(0, ioaddr+LANCE_RESET);
-
-	if (chip_table[lp->chip_version].flags & LANCE_ENABLE_AUTOSELECT) {
-		/* This is 79C960-specific: Turn on auto-select of media (AUI, BNC). */
-		outw(0x0002, ioaddr+LANCE_ADDR);
-		/* Only touch autoselect bit. */
-		outw(inw(ioaddr+LANCE_BUS_IF) | 0x0002, ioaddr+LANCE_BUS_IF);
-	}
-
-	if (lance_debug > 1)
-		printk("%s: lance_open() irq %d dma %d tx/rx rings %#x/%#x init %#x.\n",
-			   dev->name, dev->irq, dev->dma,
-		           (u32) isa_virt_to_bus(lp->tx_ring),
-		           (u32) isa_virt_to_bus(lp->rx_ring),
-			   (u32) isa_virt_to_bus(&lp->init_block));
-
-	lance_init_ring(dev, GFP_KERNEL);
-	/* Re-initialize the LANCE, and start it when done. */
-	outw(0x0001, ioaddr+LANCE_ADDR);
-	outw((short) (u32) isa_virt_to_bus(&lp->init_block), ioaddr+LANCE_DATA);
-	outw(0x0002, ioaddr+LANCE_ADDR);
-	outw(((u32)isa_virt_to_bus(&lp->init_block)) >> 16, ioaddr+LANCE_DATA);
-
-	outw(0x0004, ioaddr+LANCE_ADDR);
-	outw(0x0915, ioaddr+LANCE_DATA);
-
-	outw(0x0000, ioaddr+LANCE_ADDR);
-	outw(0x0001, ioaddr+LANCE_DATA);
-
-	netif_start_queue (dev);
-
-	i = 0;
-	while (i++ < 100)
-		if (inw(ioaddr+LANCE_DATA) & 0x0100)
-			break;
-	/*
-	 * We used to clear the InitDone bit, 0x0100, here but Mark Stockton
-	 * reports that doing so triggers a bug in the '974.
-	 */
-	outw(0x0042, ioaddr+LANCE_DATA);
-
-	if (lance_debug > 2)
-		printk("%s: LANCE open after %d ticks, init block %#x csr0 %4.4x.\n",
-			   dev->name, i, (u32) isa_virt_to_bus(&lp->init_block), inw(ioaddr+LANCE_DATA));
-
-	return 0;					/* Always succeed */
-}
-
-/* The LANCE has been halted for one reason or another (busmaster memory
-   arbitration error, Tx FIFO underflow, driver stopped it to reconfigure,
-   etc.).  Modern LANCE variants always reload their ring-buffer
-   configuration when restarted, so we must reinitialize our ring
-   context before restarting.  As part of this reinitialization,
-   find all packets still on the Tx ring and pretend that they had been
-   sent (in effect, drop the packets on the floor) - the higher-level
-   protocols will time out and retransmit.  It'd be better to shuffle
-   these skbs to a temp list and then actually re-Tx them after
-   restarting the chip, but I'm too lazy to do so right now.  dplatt@3do.com
-*/
-
-static void
-lance_purge_ring(struct net_device *dev)
-{
-	struct lance_private *lp = dev->ml_priv;
-	int i;
-
-	/* Free all the skbuffs in the Rx and Tx queues. */
-	for (i = 0; i < RX_RING_SIZE; i++) {
-		struct sk_buff *skb = lp->rx_skbuff[i];
-		lp->rx_skbuff[i] = NULL;
-		lp->rx_ring[i].base = 0;		/* Not owned by LANCE chip. */
-		if (skb)
-			dev_kfree_skb_any(skb);
-	}
-	for (i = 0; i < TX_RING_SIZE; i++) {
-		if (lp->tx_skbuff[i]) {
-			dev_kfree_skb_any(lp->tx_skbuff[i]);
-			lp->tx_skbuff[i] = NULL;
-		}
-	}
-}
-
-
-/* Initialize the LANCE Rx and Tx rings. */
-static void
-lance_init_ring(struct net_device *dev, gfp_t gfp)
-{
-	struct lance_private *lp = dev->ml_priv;
-	int i;
-
-	lp->cur_rx = lp->cur_tx = 0;
-	lp->dirty_rx = lp->dirty_tx = 0;
-
-	for (i = 0; i < RX_RING_SIZE; i++) {
-		struct sk_buff *skb;
-		void *rx_buff;
-
-		skb = alloc_skb(PKT_BUF_SZ, GFP_DMA | gfp);
-		lp->rx_skbuff[i] = skb;
-		if (skb)
-			rx_buff = skb->data;
-		else
-			rx_buff = kmalloc(PKT_BUF_SZ, GFP_DMA | gfp);
-		if (!rx_buff)
-			lp->rx_ring[i].base = 0;
-		else
-			lp->rx_ring[i].base = (u32)isa_virt_to_bus(rx_buff) | 0x80000000;
-		lp->rx_ring[i].buf_length = -PKT_BUF_SZ;
-	}
-	/* The Tx buffer address is filled in as needed, but we do need to clear
-	   the upper ownership bit. */
-	for (i = 0; i < TX_RING_SIZE; i++) {
-		lp->tx_skbuff[i] = NULL;
-		lp->tx_ring[i].base = 0;
-	}
-
-	lp->init_block.mode = 0x0000;
-	for (i = 0; i < 6; i++)
-		lp->init_block.phys_addr[i] = dev->dev_addr[i];
-	lp->init_block.filter[0] = 0x00000000;
-	lp->init_block.filter[1] = 0x00000000;
-	lp->init_block.rx_ring = ((u32)isa_virt_to_bus(lp->rx_ring) & 0xffffff) | RX_RING_LEN_BITS;
-	lp->init_block.tx_ring = ((u32)isa_virt_to_bus(lp->tx_ring) & 0xffffff) | TX_RING_LEN_BITS;
-}
-
-static void
-lance_restart(struct net_device *dev, unsigned int csr0_bits, int must_reinit)
-{
-	struct lance_private *lp = dev->ml_priv;
-
-	if (must_reinit ||
-		(chip_table[lp->chip_version].flags & LANCE_MUST_REINIT_RING)) {
-		lance_purge_ring(dev);
-		lance_init_ring(dev, GFP_ATOMIC);
-	}
-	outw(0x0000,    dev->base_addr + LANCE_ADDR);
-	outw(csr0_bits, dev->base_addr + LANCE_DATA);
-}
-
-
-static void lance_tx_timeout (struct net_device *dev, unsigned int txqueue)
-{
-	struct lance_private *lp = (struct lance_private *) dev->ml_priv;
-	int ioaddr = dev->base_addr;
-
-	outw (0, ioaddr + LANCE_ADDR);
-	printk ("%s: transmit timed out, status %4.4x, resetting.\n",
-		dev->name, inw (ioaddr + LANCE_DATA));
-	outw (0x0004, ioaddr + LANCE_DATA);
-	dev->stats.tx_errors++;
-#ifndef final_version
-	if (lance_debug > 3) {
-		int i;
-		printk (" Ring data dump: dirty_tx %d cur_tx %d%s cur_rx %d.",
-		  lp->dirty_tx, lp->cur_tx, netif_queue_stopped(dev) ? " (full)" : "",
-			lp->cur_rx);
-		for (i = 0; i < RX_RING_SIZE; i++)
-			printk ("%s %08x %04x %04x", i & 0x3 ? "" : "\n ",
-			 lp->rx_ring[i].base, -lp->rx_ring[i].buf_length,
-				lp->rx_ring[i].msg_length);
-		for (i = 0; i < TX_RING_SIZE; i++)
-			printk ("%s %08x %04x %04x", i & 0x3 ? "" : "\n ",
-			     lp->tx_ring[i].base, -lp->tx_ring[i].length,
-				lp->tx_ring[i].misc);
-		printk ("\n");
-	}
-#endif
-	lance_restart (dev, 0x0043, 1);
-
-	netif_trans_update(dev); /* prevent tx timeout */
-	netif_wake_queue (dev);
-}
-
-
-static netdev_tx_t lance_start_xmit(struct sk_buff *skb,
-				    struct net_device *dev)
-{
-	struct lance_private *lp = dev->ml_priv;
-	int ioaddr = dev->base_addr;
-	int entry;
-	unsigned long flags;
-
-	spin_lock_irqsave(&lp->devlock, flags);
-
-	if (lance_debug > 3) {
-		outw(0x0000, ioaddr+LANCE_ADDR);
-		printk("%s: lance_start_xmit() called, csr0 %4.4x.\n", dev->name,
-			   inw(ioaddr+LANCE_DATA));
-		outw(0x0000, ioaddr+LANCE_DATA);
-	}
-
-	/* Fill in a Tx ring entry */
-
-	/* Mask to ring buffer boundary. */
-	entry = lp->cur_tx & TX_RING_MOD_MASK;
-
-	/* Caution: the write order is important here, set the base address
-	   with the "ownership" bits last. */
-
-	/* The old LANCE chips doesn't automatically pad buffers to min. size. */
-	if (chip_table[lp->chip_version].flags & LANCE_MUST_PAD) {
-		if (skb->len < ETH_ZLEN) {
-			if (skb_padto(skb, ETH_ZLEN))
-				goto out;
-			lp->tx_ring[entry].length = -ETH_ZLEN;
-		}
-		else
-			lp->tx_ring[entry].length = -skb->len;
-	} else
-		lp->tx_ring[entry].length = -skb->len;
-
-	lp->tx_ring[entry].misc = 0x0000;
-
-	dev->stats.tx_bytes += skb->len;
-
-	/* If any part of this buffer is >16M we must copy it to a low-memory
-	   buffer. */
-	if ((u32)isa_virt_to_bus(skb->data) + skb->len > 0x01000000) {
-		if (lance_debug > 5)
-			printk("%s: bouncing a high-memory packet (%#x).\n",
-				   dev->name, (u32)isa_virt_to_bus(skb->data));
-		skb_copy_from_linear_data(skb, &lp->tx_bounce_buffs[entry], skb->len);
-		lp->tx_ring[entry].base =
-			((u32)isa_virt_to_bus((lp->tx_bounce_buffs + entry)) & 0xffffff) | 0x83000000;
-		dev_consume_skb_irq(skb);
-	} else {
-		lp->tx_skbuff[entry] = skb;
-		lp->tx_ring[entry].base = ((u32)isa_virt_to_bus(skb->data) & 0xffffff) | 0x83000000;
-	}
-	lp->cur_tx++;
-
-	/* Trigger an immediate send poll. */
-	outw(0x0000, ioaddr+LANCE_ADDR);
-	outw(0x0048, ioaddr+LANCE_DATA);
-
-	if ((lp->cur_tx - lp->dirty_tx) >= TX_RING_SIZE)
-		netif_stop_queue(dev);
-
-out:
-	spin_unlock_irqrestore(&lp->devlock, flags);
-	return NETDEV_TX_OK;
-}
-
-/* The LANCE interrupt handler. */
-static irqreturn_t lance_interrupt(int irq, void *dev_id)
-{
-	struct net_device *dev = dev_id;
-	struct lance_private *lp;
-	int csr0, ioaddr, boguscnt=10;
-	int must_restart;
-
-	ioaddr = dev->base_addr;
-	lp = dev->ml_priv;
-
-	spin_lock (&lp->devlock);
-
-	outw(0x00, dev->base_addr + LANCE_ADDR);
-	while ((csr0 = inw(dev->base_addr + LANCE_DATA)) & 0x8600 &&
-	       --boguscnt >= 0) {
-		/* Acknowledge all of the current interrupt sources ASAP. */
-		outw(csr0 & ~0x004f, dev->base_addr + LANCE_DATA);
-
-		must_restart = 0;
-
-		if (lance_debug > 5)
-			printk("%s: interrupt  csr0=%#2.2x new csr=%#2.2x.\n",
-				   dev->name, csr0, inw(dev->base_addr + LANCE_DATA));
-
-		if (csr0 & 0x0400)			/* Rx interrupt */
-			lance_rx(dev);
-
-		if (csr0 & 0x0200) {		/* Tx-done interrupt */
-			int dirty_tx = lp->dirty_tx;
-
-			while (dirty_tx < lp->cur_tx) {
-				int entry = dirty_tx & TX_RING_MOD_MASK;
-				int status = lp->tx_ring[entry].base;
-
-				if (status < 0)
-					break;			/* It still hasn't been Txed */
-
-				lp->tx_ring[entry].base = 0;
-
-				if (status & 0x40000000) {
-					/* There was an major error, log it. */
-					int err_status = lp->tx_ring[entry].misc;
-					dev->stats.tx_errors++;
-					if (err_status & 0x0400)
-						dev->stats.tx_aborted_errors++;
-					if (err_status & 0x0800)
-						dev->stats.tx_carrier_errors++;
-					if (err_status & 0x1000)
-						dev->stats.tx_window_errors++;
-					if (err_status & 0x4000) {
-						/* Ackk!  On FIFO errors the Tx unit is turned off! */
-						dev->stats.tx_fifo_errors++;
-						/* Remove this verbosity later! */
-						printk("%s: Tx FIFO error! Status %4.4x.\n",
-							   dev->name, csr0);
-						/* Restart the chip. */
-						must_restart = 1;
-					}
-				} else {
-					if (status & 0x18000000)
-						dev->stats.collisions++;
-					dev->stats.tx_packets++;
-				}
-
-				/* We must free the original skb if it's not a data-only copy
-				   in the bounce buffer. */
-				if (lp->tx_skbuff[entry]) {
-					dev_consume_skb_irq(lp->tx_skbuff[entry]);
-					lp->tx_skbuff[entry] = NULL;
-				}
-				dirty_tx++;
-			}
-
-#ifndef final_version
-			if (lp->cur_tx - dirty_tx >= TX_RING_SIZE) {
-				printk("out-of-sync dirty pointer, %d vs. %d, full=%s.\n",
-					   dirty_tx, lp->cur_tx,
-					   netif_queue_stopped(dev) ? "yes" : "no");
-				dirty_tx += TX_RING_SIZE;
-			}
-#endif
-
-			/* if the ring is no longer full, accept more packets */
-			if (netif_queue_stopped(dev) &&
-			    dirty_tx > lp->cur_tx - TX_RING_SIZE + 2)
-				netif_wake_queue (dev);
-
-			lp->dirty_tx = dirty_tx;
-		}
-
-		/* Log misc errors. */
-		if (csr0 & 0x4000)
-			dev->stats.tx_errors++; /* Tx babble. */
-		if (csr0 & 0x1000)
-			dev->stats.rx_errors++; /* Missed a Rx frame. */
-		if (csr0 & 0x0800) {
-			printk("%s: Bus master arbitration failure, status %4.4x.\n",
-				   dev->name, csr0);
-			/* Restart the chip. */
-			must_restart = 1;
-		}
-
-		if (must_restart) {
-			/* stop the chip to clear the error condition, then restart */
-			outw(0x0000, dev->base_addr + LANCE_ADDR);
-			outw(0x0004, dev->base_addr + LANCE_DATA);
-			lance_restart(dev, 0x0002, 0);
-		}
-	}
-
-	/* Clear any other interrupt, and set interrupt enable. */
-	outw(0x0000, dev->base_addr + LANCE_ADDR);
-	outw(0x7940, dev->base_addr + LANCE_DATA);
-
-	if (lance_debug > 4)
-		printk("%s: exiting interrupt, csr%d=%#4.4x.\n",
-			   dev->name, inw(ioaddr + LANCE_ADDR),
-			   inw(dev->base_addr + LANCE_DATA));
-
-	spin_unlock (&lp->devlock);
-	return IRQ_HANDLED;
-}
-
-static int
-lance_rx(struct net_device *dev)
-{
-	struct lance_private *lp = dev->ml_priv;
-	int entry = lp->cur_rx & RX_RING_MOD_MASK;
-	int i;
-
-	/* If we own the next entry, it's a new packet. Send it up. */
-	while (lp->rx_ring[entry].base >= 0) {
-		int status = lp->rx_ring[entry].base >> 24;
-
-		if (status != 0x03) {			/* There was an error. */
-			/* There is a tricky error noted by John Murphy,
-			   <murf@perftech.com> to Russ Nelson: Even with full-sized
-			   buffers it's possible for a jabber packet to use two
-			   buffers, with only the last correctly noting the error. */
-			if (status & 0x01)	/* Only count a general error at the */
-				dev->stats.rx_errors++; /* end of a packet.*/
-			if (status & 0x20)
-				dev->stats.rx_frame_errors++;
-			if (status & 0x10)
-				dev->stats.rx_over_errors++;
-			if (status & 0x08)
-				dev->stats.rx_crc_errors++;
-			if (status & 0x04)
-				dev->stats.rx_fifo_errors++;
-			lp->rx_ring[entry].base &= 0x03ffffff;
-		}
-		else
-		{
-			/* Malloc up new buffer, compatible with net3. */
-			short pkt_len = (lp->rx_ring[entry].msg_length & 0xfff)-4;
-			struct sk_buff *skb;
-
-			if(pkt_len<60)
-			{
-				printk("%s: Runt packet!\n",dev->name);
-				dev->stats.rx_errors++;
-			}
-			else
-			{
-				skb = dev_alloc_skb(pkt_len+2);
-				if (!skb)
-				{
-					printk("%s: Memory squeeze, deferring packet.\n", dev->name);
-					for (i=0; i < RX_RING_SIZE; i++)
-						if (lp->rx_ring[(entry+i) & RX_RING_MOD_MASK].base < 0)
-							break;
-
-					if (i > RX_RING_SIZE -2)
-					{
-						dev->stats.rx_dropped++;
-						lp->rx_ring[entry].base |= 0x80000000;
-						lp->cur_rx++;
-					}
-					break;
-				}
-				skb_reserve(skb,2);	/* 16 byte align */
-				skb_put(skb,pkt_len);	/* Make room */
-				skb_copy_to_linear_data(skb,
-					(unsigned char *)isa_bus_to_virt((lp->rx_ring[entry].base & 0x00ffffff)),
-					pkt_len);
-				skb->protocol=eth_type_trans(skb,dev);
-				netif_rx(skb);
-				dev->stats.rx_packets++;
-				dev->stats.rx_bytes += pkt_len;
-			}
-		}
-		/* The docs say that the buffer length isn't touched, but Andrew Boyd
-		   of QNX reports that some revs of the 79C965 clear it. */
-		lp->rx_ring[entry].buf_length = -PKT_BUF_SZ;
-		lp->rx_ring[entry].base |= 0x80000000;
-		entry = (++lp->cur_rx) & RX_RING_MOD_MASK;
-	}
-
-	/* We should check that at least two ring entries are free.	 If not,
-	   we should free one and mark stats->rx_dropped++. */
-
-	return 0;
-}
-
-static int
-lance_close(struct net_device *dev)
-{
-	int ioaddr = dev->base_addr;
-	struct lance_private *lp = dev->ml_priv;
-
-	netif_stop_queue (dev);
-
-	if (chip_table[lp->chip_version].flags & LANCE_HAS_MISSED_FRAME) {
-		outw(112, ioaddr+LANCE_ADDR);
-		dev->stats.rx_missed_errors = inw(ioaddr+LANCE_DATA);
-	}
-	outw(0, ioaddr+LANCE_ADDR);
-
-	if (lance_debug > 1)
-		printk("%s: Shutting down ethercard, status was %2.2x.\n",
-			   dev->name, inw(ioaddr+LANCE_DATA));
-
-	/* We stop the LANCE here -- it occasionally polls
-	   memory if we don't. */
-	outw(0x0004, ioaddr+LANCE_DATA);
-
-	if (dev->dma != 4)
-	{
-		unsigned long flags=claim_dma_lock();
-		disable_dma(dev->dma);
-		release_dma_lock(flags);
-	}
-	free_irq(dev->irq, dev);
-
-	lance_purge_ring(dev);
-
-	return 0;
-}
-
-static struct net_device_stats *lance_get_stats(struct net_device *dev)
-{
-	struct lance_private *lp = dev->ml_priv;
-
-	if (chip_table[lp->chip_version].flags & LANCE_HAS_MISSED_FRAME) {
-		short ioaddr = dev->base_addr;
-		short saved_addr;
-		unsigned long flags;
-
-		spin_lock_irqsave(&lp->devlock, flags);
-		saved_addr = inw(ioaddr+LANCE_ADDR);
-		outw(112, ioaddr+LANCE_ADDR);
-		dev->stats.rx_missed_errors = inw(ioaddr+LANCE_DATA);
-		outw(saved_addr, ioaddr+LANCE_ADDR);
-		spin_unlock_irqrestore(&lp->devlock, flags);
-	}
-
-	return &dev->stats;
-}
-
-/* Set or clear the multicast filter for this adaptor.
- */
-
-static void set_multicast_list(struct net_device *dev)
-{
-	short ioaddr = dev->base_addr;
-
-	outw(0, ioaddr+LANCE_ADDR);
-	outw(0x0004, ioaddr+LANCE_DATA); /* Temporarily stop the lance.	 */
-
-	if (dev->flags&IFF_PROMISC) {
-		outw(15, ioaddr+LANCE_ADDR);
-		outw(0x8000, ioaddr+LANCE_DATA); /* Set promiscuous mode */
-	} else {
-		short multicast_table[4];
-		int i;
-		int num_addrs=netdev_mc_count(dev);
-		if(dev->flags&IFF_ALLMULTI)
-			num_addrs=1;
-		/* FIXIT: We don't use the multicast table, but rely on upper-layer filtering. */
-		memset(multicast_table, (num_addrs == 0) ? 0 : -1, sizeof(multicast_table));
-		for (i = 0; i < 4; i++) {
-			outw(8 + i, ioaddr+LANCE_ADDR);
-			outw(multicast_table[i], ioaddr+LANCE_DATA);
-		}
-		outw(15, ioaddr+LANCE_ADDR);
-		outw(0x0000, ioaddr+LANCE_DATA); /* Unset promiscuous mode */
-	}
-
-	lance_restart(dev, 0x0142, 0); /*  Resume normal operation */
-
-}
-

-- 
2.53.0


^ permalink raw reply related	[flat|nested] 28+ messages in thread

* [PATCH net 08/18] drivers: net: amd: nmclan: Remove this driver
  2026-04-21 19:31 [PATCH net 00/18] Remove a number of ISA and PCMCIA Ethernet drivers Andrew Lunn
                   ` (6 preceding siblings ...)
  2026-04-21 19:31 ` [PATCH net 07/18] drivers: net: amd: lance: Remove this driver Andrew Lunn
@ 2026-04-21 19:31 ` Andrew Lunn
  2026-04-21 19:31 ` [PATCH net 09/18] drivers: net: smsc: smc9194: " Andrew Lunn
                   ` (13 subsequent siblings)
  21 siblings, 0 replies; 28+ messages in thread
From: Andrew Lunn @ 2026-04-21 19:31 UTC (permalink / raw)
  To: Andrew Lunn, David S. Miller, Eric Dumazet, Jakub Kicinski,
	Paolo Abeni, Simon Horman, Jonathan Corbet, Shuah Khan
  Cc: linux-kernel, netdev, linux-doc, Andrew Lunn

The nmclan was written by Roger C Pao in 1995. It is an PCMCIA device,
so unlikely to be used with modern kernels.

Signed-off-by: Andrew Lunn <andrew@lunn.ch>
---
 drivers/net/ethernet/amd/Kconfig     |   10 -
 drivers/net/ethernet/amd/Makefile    |    1 -
 drivers/net/ethernet/amd/nmclan_cs.c | 1508 ----------------------------------
 3 files changed, 1519 deletions(-)

diff --git a/drivers/net/ethernet/amd/Kconfig b/drivers/net/ethernet/amd/Kconfig
index f08b2ce8b952..69cd0b3d098c 100644
--- a/drivers/net/ethernet/amd/Kconfig
+++ b/drivers/net/ethernet/amd/Kconfig
@@ -91,16 +91,6 @@ config MIPS_AU1X00_ENET
 	  If you have an Alchemy Semi AU1X00 based system
 	  say Y.  Otherwise, say N.
 
-config PCMCIA_NMCLAN
-	tristate "New Media PCMCIA support"
-	depends on PCMCIA && HAS_IOPORT
-	help
-	  Say Y here if you intend to attach a New Media Ethernet or LiveWire
-	  PCMCIA (PC-card) Ethernet card to your computer.
-
-	  To compile this driver as a module, choose M here: the module will be
-	  called nmclan_cs.  If unsure, say N.
-
 config SUN3LANCE
 	tristate "Sun3/Sun3x on-board LANCE support"
 	depends on (SUN3 || SUN3X)
diff --git a/drivers/net/ethernet/amd/Makefile b/drivers/net/ethernet/amd/Makefile
index d0aebfeedec3..a352f1be2b45 100644
--- a/drivers/net/ethernet/amd/Makefile
+++ b/drivers/net/ethernet/amd/Makefile
@@ -9,7 +9,6 @@ obj-$(CONFIG_ARIADNE) += ariadne.o
 obj-$(CONFIG_ATARILANCE) += atarilance.o
 obj-$(CONFIG_DECLANCE) += declance.o
 obj-$(CONFIG_MIPS_AU1X00_ENET) += au1000_eth.o
-obj-$(CONFIG_PCMCIA_NMCLAN) += nmclan_cs.o
 obj-$(CONFIG_PCNET32) += pcnet32.o
 obj-$(CONFIG_SUN3LANCE) += sun3lance.o
 obj-$(CONFIG_SUNLANCE) += sunlance.o
diff --git a/drivers/net/ethernet/amd/nmclan_cs.c b/drivers/net/ethernet/amd/nmclan_cs.c
deleted file mode 100644
index 37054a670407..000000000000
--- a/drivers/net/ethernet/amd/nmclan_cs.c
+++ /dev/null
@@ -1,1508 +0,0 @@
-/* ----------------------------------------------------------------------------
-Linux PCMCIA ethernet adapter driver for the New Media Ethernet LAN.
-  nmclan_cs.c,v 0.16 1995/07/01 06:42:17 rpao Exp rpao
-
-  The Ethernet LAN uses the Advanced Micro Devices (AMD) Am79C940 Media
-  Access Controller for Ethernet (MACE).  It is essentially the Am2150
-  PCMCIA Ethernet card contained in the Am2150 Demo Kit.
-
-Written by Roger C. Pao <rpao@paonet.org>
-  Copyright 1995 Roger C. Pao
-  Linux 2.5 cleanups Copyright Red Hat 2003
-
-  This software may be used and distributed according to the terms of
-  the GNU General Public License.
-
-Ported to Linux 1.3.* network driver environment by
-  Matti Aarnio <mea@utu.fi>
-
-References
-
-  Am2150 Technical Reference Manual, Revision 1.0, August 17, 1993
-  Am79C940 (MACE) Data Sheet, 1994
-  Am79C90 (C-LANCE) Data Sheet, 1994
-  Linux PCMCIA Programmer's Guide v1.17
-  /usr/src/linux/net/inet/dev.c, Linux kernel 1.2.8
-
-  Eric Mears, New Media Corporation
-  Tom Pollard, New Media Corporation
-  Dean Siasoyco, New Media Corporation
-  Ken Lesniak, Silicon Graphics, Inc. <lesniak@boston.sgi.com>
-  Donald Becker <becker@scyld.com>
-  David Hinds <dahinds@users.sourceforge.net>
-
-  The Linux client driver is based on the 3c589_cs.c client driver by
-  David Hinds.
-
-  The Linux network driver outline is based on the 3c589_cs.c driver,
-  the 8390.c driver, and the example skeleton.c kernel code, which are
-  by Donald Becker.
-
-  The Am2150 network driver hardware interface code is based on the
-  OS/9000 driver for the New Media Ethernet LAN by Eric Mears.
-
-  Special thanks for testing and help in debugging this driver goes
-  to Ken Lesniak.
-
--------------------------------------------------------------------------------
-Driver Notes and Issues
--------------------------------------------------------------------------------
-
-1. Developed on a Dell 320SLi
-   PCMCIA Card Services 2.6.2
-   Linux dell 1.2.10 #1 Thu Jun 29 20:23:41 PDT 1995 i386
-
-2. rc.pcmcia may require loading pcmcia_core with io_speed=300:
-   'insmod pcmcia_core.o io_speed=300'.
-   This will avoid problems with fast systems which causes rx_framecnt
-   to return random values.
-
-3. If hot extraction does not work for you, use 'ifconfig eth0 down'
-   before extraction.
-
-4. There is a bad slow-down problem in this driver.
-
-5. Future: Multicast processing.  In the meantime, do _not_ compile your
-   kernel with multicast ip enabled.
-
--------------------------------------------------------------------------------
-History
--------------------------------------------------------------------------------
-Log: nmclan_cs.c,v
- * 2.5.75-ac1 2003/07/11 Alan Cox <alan@lxorguk.ukuu.org.uk>
- * Fixed hang on card eject as we probe it
- * Cleaned up to use new style locking.
- *
- * Revision 0.16  1995/07/01  06:42:17  rpao
- * Bug fix: nmclan_reset() called CardServices incorrectly.
- *
- * Revision 0.15  1995/05/24  08:09:47  rpao
- * Re-implement MULTI_TX dev->tbusy handling.
- *
- * Revision 0.14  1995/05/23  03:19:30  rpao
- * Added, in nmclan_config(), "tuple.Attributes = 0;".
- * Modified MACE ID check to ignore chip revision level.
- * Avoid tx_free_frames race condition between _start_xmit and _interrupt.
- *
- * Revision 0.13  1995/05/18  05:56:34  rpao
- * Statistics changes.
- * Bug fix: nmclan_reset did not enable TX and RX: call restore_multicast_list.
- * Bug fix: mace_interrupt checks ~MACE_IMR_DEFAULT.  Fixes driver lockup.
- *
- * Revision 0.12  1995/05/14  00:12:23  rpao
- * Statistics overhaul.
- *
-
-95/05/13 rpao	V0.10a
-		Bug fix: MACE statistics counters used wrong I/O ports.
-		Bug fix: mace_interrupt() needed to allow statistics to be
-		processed without RX or TX interrupts pending.
-95/05/11 rpao	V0.10
-		Multiple transmit request processing.
-		Modified statistics to use MACE counters where possible.
-95/05/10 rpao	V0.09 Bug fix: Must use IO_DATA_PATH_WIDTH_AUTO.
-		*Released
-95/05/10 rpao	V0.08
-		Bug fix: Make all non-exported functions private by using
-		static keyword.
-		Bug fix: Test IntrCnt _before_ reading MACE_IR.
-95/05/10 rpao	V0.07 Statistics.
-95/05/09 rpao	V0.06 Fix rx_framecnt problem by addition of PCIC wait states.
-
----------------------------------------------------------------------------- */
-
-#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
-
-#define DRV_NAME	"nmclan_cs"
-
-/* ----------------------------------------------------------------------------
-Conditional Compilation Options
----------------------------------------------------------------------------- */
-
-#define MULTI_TX			0
-#define RESET_ON_TIMEOUT		1
-#define TX_INTERRUPTABLE		1
-#define RESET_XILINX			0
-
-/* ----------------------------------------------------------------------------
-Include Files
----------------------------------------------------------------------------- */
-
-#include <linux/module.h>
-#include <linux/kernel.h>
-#include <linux/ptrace.h>
-#include <linux/slab.h>
-#include <linux/string.h>
-#include <linux/timer.h>
-#include <linux/interrupt.h>
-#include <linux/in.h>
-#include <linux/delay.h>
-#include <linux/ethtool.h>
-#include <linux/netdevice.h>
-#include <linux/etherdevice.h>
-#include <linux/skbuff.h>
-#include <linux/if_arp.h>
-#include <linux/ioport.h>
-#include <linux/bitops.h>
-
-#include <pcmcia/cisreg.h>
-#include <pcmcia/cistpl.h>
-#include <pcmcia/ds.h>
-
-#include <linux/uaccess.h>
-#include <asm/io.h>
-
-/* ----------------------------------------------------------------------------
-Defines
----------------------------------------------------------------------------- */
-
-#define MACE_LADRF_LEN			8
-					/* 8 bytes in Logical Address Filter */
-
-/* Loop Control Defines */
-#define MACE_MAX_IR_ITERATIONS		10
-#define MACE_MAX_RX_ITERATIONS		12
-	/*
-	TBD: Dean brought this up, and I assumed the hardware would
-	handle it:
-
-	If MACE_MAX_RX_ITERATIONS is > 1, rx_framecnt may still be
-	non-zero when the isr exits.  We may not get another interrupt
-	to process the remaining packets for some time.
-	*/
-
-/*
-The Am2150 has a Xilinx XC3042 field programmable gate array (FPGA)
-which manages the interface between the MACE and the PCMCIA bus.  It
-also includes buffer management for the 32K x 8 SRAM to control up to
-four transmit and 12 receive frames at a time.
-*/
-#define AM2150_MAX_TX_FRAMES		4
-#define AM2150_MAX_RX_FRAMES		12
-
-/* Am2150 Ethernet Card I/O Mapping */
-#define AM2150_RCV			0x00
-#define AM2150_XMT			0x04
-#define AM2150_XMT_SKIP			0x09
-#define AM2150_RCV_NEXT			0x0A
-#define AM2150_RCV_FRAME_COUNT		0x0B
-#define AM2150_MACE_BANK		0x0C
-#define AM2150_MACE_BASE		0x10
-
-/* MACE Registers */
-#define MACE_RCVFIFO			0
-#define MACE_XMTFIFO			1
-#define MACE_XMTFC			2
-#define MACE_XMTFS			3
-#define MACE_XMTRC			4
-#define MACE_RCVFC			5
-#define MACE_RCVFS			6
-#define MACE_FIFOFC			7
-#define MACE_IR				8
-#define MACE_IMR			9
-#define MACE_PR				10
-#define MACE_BIUCC			11
-#define MACE_FIFOCC			12
-#define MACE_MACCC			13
-#define MACE_PLSCC			14
-#define MACE_PHYCC			15
-#define MACE_CHIPIDL			16
-#define MACE_CHIPIDH			17
-#define MACE_IAC			18
-/* Reserved */
-#define MACE_LADRF			20
-#define MACE_PADR			21
-/* Reserved */
-/* Reserved */
-#define MACE_MPC			24
-/* Reserved */
-#define MACE_RNTPC			26
-#define MACE_RCVCC			27
-/* Reserved */
-#define MACE_UTR			29
-#define MACE_RTR1			30
-#define MACE_RTR2			31
-
-/* MACE Bit Masks */
-#define MACE_XMTRC_EXDEF		0x80
-#define MACE_XMTRC_XMTRC		0x0F
-
-#define MACE_XMTFS_XMTSV		0x80
-#define MACE_XMTFS_UFLO			0x40
-#define MACE_XMTFS_LCOL			0x20
-#define MACE_XMTFS_MORE			0x10
-#define MACE_XMTFS_ONE			0x08
-#define MACE_XMTFS_DEFER		0x04
-#define MACE_XMTFS_LCAR			0x02
-#define MACE_XMTFS_RTRY			0x01
-
-#define MACE_RCVFS_RCVSTS		0xF000
-#define MACE_RCVFS_OFLO			0x8000
-#define MACE_RCVFS_CLSN			0x4000
-#define MACE_RCVFS_FRAM			0x2000
-#define MACE_RCVFS_FCS			0x1000
-
-#define MACE_FIFOFC_RCVFC		0xF0
-#define MACE_FIFOFC_XMTFC		0x0F
-
-#define MACE_IR_JAB			0x80
-#define MACE_IR_BABL			0x40
-#define MACE_IR_CERR			0x20
-#define MACE_IR_RCVCCO			0x10
-#define MACE_IR_RNTPCO			0x08
-#define MACE_IR_MPCO			0x04
-#define MACE_IR_RCVINT			0x02
-#define MACE_IR_XMTINT			0x01
-
-#define MACE_MACCC_PROM			0x80
-#define MACE_MACCC_DXMT2PD		0x40
-#define MACE_MACCC_EMBA			0x20
-#define MACE_MACCC_RESERVED		0x10
-#define MACE_MACCC_DRCVPA		0x08
-#define MACE_MACCC_DRCVBC		0x04
-#define MACE_MACCC_ENXMT		0x02
-#define MACE_MACCC_ENRCV		0x01
-
-#define MACE_PHYCC_LNKFL		0x80
-#define MACE_PHYCC_DLNKTST		0x40
-#define MACE_PHYCC_REVPOL		0x20
-#define MACE_PHYCC_DAPC			0x10
-#define MACE_PHYCC_LRT			0x08
-#define MACE_PHYCC_ASEL			0x04
-#define MACE_PHYCC_RWAKE		0x02
-#define MACE_PHYCC_AWAKE		0x01
-
-#define MACE_IAC_ADDRCHG		0x80
-#define MACE_IAC_PHYADDR		0x04
-#define MACE_IAC_LOGADDR		0x02
-
-#define MACE_UTR_RTRE			0x80
-#define MACE_UTR_RTRD			0x40
-#define MACE_UTR_RPA			0x20
-#define MACE_UTR_FCOLL			0x10
-#define MACE_UTR_RCVFCSE		0x08
-#define MACE_UTR_LOOP_INCL_MENDEC	0x06
-#define MACE_UTR_LOOP_NO_MENDEC		0x04
-#define MACE_UTR_LOOP_EXTERNAL		0x02
-#define MACE_UTR_LOOP_NONE		0x00
-#define MACE_UTR_RESERVED		0x01
-
-/* Switch MACE register bank (only 0 and 1 are valid) */
-#define MACEBANK(win_num) outb((win_num), ioaddr + AM2150_MACE_BANK)
-
-#define MACE_IMR_DEFAULT \
-  (0xFF - \
-    ( \
-      MACE_IR_CERR | \
-      MACE_IR_RCVCCO | \
-      MACE_IR_RNTPCO | \
-      MACE_IR_MPCO | \
-      MACE_IR_RCVINT | \
-      MACE_IR_XMTINT \
-    ) \
-  )
-#undef MACE_IMR_DEFAULT
-#define MACE_IMR_DEFAULT 0x00 /* New statistics handling: grab everything */
-
-#define TX_TIMEOUT		((400*HZ)/1000)
-
-/* ----------------------------------------------------------------------------
-Type Definitions
----------------------------------------------------------------------------- */
-
-typedef struct _mace_statistics {
-    /* MACE_XMTFS */
-    int xmtsv;
-    int uflo;
-    int lcol;
-    int more;
-    int one;
-    int defer;
-    int lcar;
-    int rtry;
-
-    /* MACE_XMTRC */
-    int exdef;
-    int xmtrc;
-
-    /* RFS1--Receive Status (RCVSTS) */
-    int oflo;
-    int clsn;
-    int fram;
-    int fcs;
-
-    /* RFS2--Runt Packet Count (RNTPC) */
-    int rfs_rntpc;
-
-    /* RFS3--Receive Collision Count (RCVCC) */
-    int rfs_rcvcc;
-
-    /* MACE_IR */
-    int jab;
-    int babl;
-    int cerr;
-    int rcvcco;
-    int rntpco;
-    int mpco;
-
-    /* MACE_MPC */
-    int mpc;
-
-    /* MACE_RNTPC */
-    int rntpc;
-
-    /* MACE_RCVCC */
-    int rcvcc;
-} mace_statistics;
-
-typedef struct _mace_private {
-	struct pcmcia_device	*p_dev;
-    mace_statistics mace_stats; /* MACE chip statistics counters */
-
-    /* restore_multicast_list() state variables */
-    int multicast_ladrf[MACE_LADRF_LEN]; /* Logical address filter */
-    int multicast_num_addrs;
-
-    char tx_free_frames; /* Number of free transmit frame buffers */
-    char tx_irq_disabled; /* MACE TX interrupt disabled */
-
-    spinlock_t bank_lock; /* Must be held if you step off bank 0 */
-} mace_private;
-
-/* ----------------------------------------------------------------------------
-Private Global Variables
----------------------------------------------------------------------------- */
-
-static const char *if_names[]={
-    "Auto", "10baseT", "BNC",
-};
-
-/* ----------------------------------------------------------------------------
-Parameters
-	These are the parameters that can be set during loading with
-	'insmod'.
----------------------------------------------------------------------------- */
-
-MODULE_DESCRIPTION("New Media PCMCIA ethernet driver");
-MODULE_LICENSE("GPL");
-
-#define INT_MODULE_PARM(n, v) static int n = v; module_param(n, int, 0)
-
-/* 0=auto, 1=10baseT, 2 = 10base2, default=auto */
-INT_MODULE_PARM(if_port, 0);
-
-
-/* ----------------------------------------------------------------------------
-Function Prototypes
----------------------------------------------------------------------------- */
-
-static int nmclan_config(struct pcmcia_device *link);
-static void nmclan_release(struct pcmcia_device *link);
-
-static void nmclan_reset(struct net_device *dev);
-static int mace_config(struct net_device *dev, struct ifmap *map);
-static int mace_open(struct net_device *dev);
-static int mace_close(struct net_device *dev);
-static netdev_tx_t mace_start_xmit(struct sk_buff *skb,
-					 struct net_device *dev);
-static void mace_tx_timeout(struct net_device *dev, unsigned int txqueue);
-static irqreturn_t mace_interrupt(int irq, void *dev_id);
-static struct net_device_stats *mace_get_stats(struct net_device *dev);
-static int mace_rx(struct net_device *dev, unsigned char RxCnt);
-static void restore_multicast_list(struct net_device *dev);
-static void set_multicast_list(struct net_device *dev);
-static const struct ethtool_ops netdev_ethtool_ops;
-
-
-static void nmclan_detach(struct pcmcia_device *p_dev);
-
-static const struct net_device_ops mace_netdev_ops = {
-	.ndo_open		= mace_open,
-	.ndo_stop		= mace_close,
-	.ndo_start_xmit		= mace_start_xmit,
-	.ndo_tx_timeout		= mace_tx_timeout,
-	.ndo_set_config		= mace_config,
-	.ndo_get_stats		= mace_get_stats,
-	.ndo_set_rx_mode	= set_multicast_list,
-	.ndo_set_mac_address 	= eth_mac_addr,
-	.ndo_validate_addr	= eth_validate_addr,
-};
-
-static int nmclan_probe(struct pcmcia_device *link)
-{
-    mace_private *lp;
-    struct net_device *dev;
-
-    dev_dbg(&link->dev, "nmclan_attach()\n");
-
-    /* Create new ethernet device */
-    dev = alloc_etherdev(sizeof(mace_private));
-    if (!dev)
-	    return -ENOMEM;
-    lp = netdev_priv(dev);
-    lp->p_dev = link;
-    link->priv = dev;
-
-    spin_lock_init(&lp->bank_lock);
-    link->resource[0]->end = 32;
-    link->resource[0]->flags |= IO_DATA_PATH_WIDTH_AUTO;
-    link->config_flags |= CONF_ENABLE_IRQ;
-    link->config_index = 1;
-    link->config_regs = PRESENT_OPTION;
-
-    lp->tx_free_frames=AM2150_MAX_TX_FRAMES;
-
-    dev->netdev_ops = &mace_netdev_ops;
-    dev->ethtool_ops = &netdev_ethtool_ops;
-    dev->watchdog_timeo = TX_TIMEOUT;
-
-    return nmclan_config(link);
-} /* nmclan_attach */
-
-static void nmclan_detach(struct pcmcia_device *link)
-{
-    struct net_device *dev = link->priv;
-
-    dev_dbg(&link->dev, "nmclan_detach\n");
-
-    unregister_netdev(dev);
-
-    nmclan_release(link);
-
-    free_netdev(dev);
-} /* nmclan_detach */
-
-/* ----------------------------------------------------------------------------
-mace_read
-	Reads a MACE register.  This is bank independent; however, the
-	caller must ensure that this call is not interruptable.  We are
-	assuming that during normal operation, the MACE is always in
-	bank 0.
----------------------------------------------------------------------------- */
-static int mace_read(mace_private *lp, unsigned int ioaddr, int reg)
-{
-  int data = 0xFF;
-  unsigned long flags;
-
-  switch (reg >> 4) {
-  case 0: /* register 0-15 */
-      data = inb(ioaddr + AM2150_MACE_BASE + reg);
-      break;
-  case 1: /* register 16-31 */
-      spin_lock_irqsave(&lp->bank_lock, flags);
-      MACEBANK(1);
-      data = inb(ioaddr + AM2150_MACE_BASE + (reg & 0x0F));
-      MACEBANK(0);
-      spin_unlock_irqrestore(&lp->bank_lock, flags);
-      break;
-  }
-  return data & 0xFF;
-} /* mace_read */
-
-/* ----------------------------------------------------------------------------
-mace_write
-	Writes to a MACE register.  This is bank independent; however,
-	the caller must ensure that this call is not interruptable.  We
-	are assuming that during normal operation, the MACE is always in
-	bank 0.
----------------------------------------------------------------------------- */
-static void mace_write(mace_private *lp, unsigned int ioaddr, int reg,
-		       int data)
-{
-  unsigned long flags;
-
-  switch (reg >> 4) {
-  case 0: /* register 0-15 */
-      outb(data & 0xFF, ioaddr + AM2150_MACE_BASE + reg);
-      break;
-  case 1: /* register 16-31 */
-      spin_lock_irqsave(&lp->bank_lock, flags);
-      MACEBANK(1);
-      outb(data & 0xFF, ioaddr + AM2150_MACE_BASE + (reg & 0x0F));
-      MACEBANK(0);
-      spin_unlock_irqrestore(&lp->bank_lock, flags);
-      break;
-  }
-} /* mace_write */
-
-/* ----------------------------------------------------------------------------
-mace_init
-	Resets the MACE chip.
----------------------------------------------------------------------------- */
-static int mace_init(mace_private *lp, unsigned int ioaddr,
-		     const char *enet_addr)
-{
-  int i;
-  int ct = 0;
-
-  /* MACE Software reset */
-  mace_write(lp, ioaddr, MACE_BIUCC, 1);
-  while (mace_read(lp, ioaddr, MACE_BIUCC) & 0x01) {
-    /* Wait for reset bit to be cleared automatically after <= 200ns */;
-    if(++ct > 500)
-    {
-	pr_err("reset failed, card removed?\n");
-	return -1;
-    }
-    udelay(1);
-  }
-  mace_write(lp, ioaddr, MACE_BIUCC, 0);
-
-  /* The Am2150 requires that the MACE FIFOs operate in burst mode. */
-  mace_write(lp, ioaddr, MACE_FIFOCC, 0x0F);
-
-  mace_write(lp,ioaddr, MACE_RCVFC, 0); /* Disable Auto Strip Receive */
-  mace_write(lp, ioaddr, MACE_IMR, 0xFF); /* Disable all interrupts until _open */
-
-  /*
-   * Bit 2-1 PORTSEL[1-0] Port Select.
-   * 00 AUI/10Base-2
-   * 01 10Base-T
-   * 10 DAI Port (reserved in Am2150)
-   * 11 GPSI
-   * For this card, only the first two are valid.
-   * So, PLSCC should be set to
-   * 0x00 for 10Base-2
-   * 0x02 for 10Base-T
-   * Or just set ASEL in PHYCC below!
-   */
-  switch (if_port) {
-  case 1:
-      mace_write(lp, ioaddr, MACE_PLSCC, 0x02);
-      break;
-  case 2:
-      mace_write(lp, ioaddr, MACE_PLSCC, 0x00);
-      break;
-  default:
-      mace_write(lp, ioaddr, MACE_PHYCC, /* ASEL */ 4);
-      /* ASEL Auto Select.  When set, the PORTSEL[1-0] bits are overridden,
-	 and the MACE device will automatically select the operating media
-	 interface port. */
-      break;
-  }
-
-  mace_write(lp, ioaddr, MACE_IAC, MACE_IAC_ADDRCHG | MACE_IAC_PHYADDR);
-  /* Poll ADDRCHG bit */
-  ct = 0;
-  while (mace_read(lp, ioaddr, MACE_IAC) & MACE_IAC_ADDRCHG)
-  {
-	if(++ ct > 500)
-	{
-		pr_err("ADDRCHG timeout, card removed?\n");
-		return -1;
-	}
-  }
-  /* Set PADR register */
-  for (i = 0; i < ETH_ALEN; i++)
-    mace_write(lp, ioaddr, MACE_PADR, enet_addr[i]);
-
-  /* MAC Configuration Control Register should be written last */
-  /* Let set_multicast_list set this. */
-  /* mace_write(lp, ioaddr, MACE_MACCC, MACE_MACCC_ENXMT | MACE_MACCC_ENRCV); */
-  mace_write(lp, ioaddr, MACE_MACCC, 0x00);
-  return 0;
-} /* mace_init */
-
-static int nmclan_config(struct pcmcia_device *link)
-{
-  struct net_device *dev = link->priv;
-  mace_private *lp = netdev_priv(dev);
-  u8 *buf;
-  size_t len;
-  int i, ret;
-  unsigned int ioaddr;
-
-  dev_dbg(&link->dev, "nmclan_config\n");
-
-  link->io_lines = 5;
-  ret = pcmcia_request_io(link);
-  if (ret)
-	  goto failed;
-  ret = pcmcia_request_irq(link, mace_interrupt);
-  if (ret)
-	  goto failed;
-  ret = pcmcia_enable_device(link);
-  if (ret)
-	  goto failed;
-
-  dev->irq = link->irq;
-  dev->base_addr = link->resource[0]->start;
-
-  ioaddr = dev->base_addr;
-
-  /* Read the ethernet address from the CIS. */
-  len = pcmcia_get_tuple(link, 0x80, &buf);
-  if (!buf || len < ETH_ALEN) {
-	  kfree(buf);
-	  goto failed;
-  }
-  eth_hw_addr_set(dev, buf);
-  kfree(buf);
-
-  /* Verify configuration by reading the MACE ID. */
-  {
-    char sig[2];
-
-    sig[0] = mace_read(lp, ioaddr, MACE_CHIPIDL);
-    sig[1] = mace_read(lp, ioaddr, MACE_CHIPIDH);
-    if ((sig[0] == 0x40) && ((sig[1] & 0x0F) == 0x09)) {
-      dev_dbg(&link->dev, "nmclan_cs configured: mace id=%x %x\n",
-	    sig[0], sig[1]);
-    } else {
-      pr_notice("mace id not found: %x %x should be 0x40 0x?9\n",
-		sig[0], sig[1]);
-      goto failed;
-    }
-  }
-
-  if(mace_init(lp, ioaddr, dev->dev_addr) == -1)
-	goto failed;
-
-  /* The if_port symbol can be set when the module is loaded */
-  if (if_port <= 2)
-    dev->if_port = if_port;
-  else
-    pr_notice("invalid if_port requested\n");
-
-  SET_NETDEV_DEV(dev, &link->dev);
-
-  i = register_netdev(dev);
-  if (i != 0) {
-    pr_notice("register_netdev() failed\n");
-    goto failed;
-  }
-
-  netdev_info(dev, "nmclan: port %#3lx, irq %d, %s port, hw_addr %pM\n",
-	      dev->base_addr, dev->irq, if_names[dev->if_port], dev->dev_addr);
-  return 0;
-
-failed:
-	nmclan_release(link);
-	return -ENODEV;
-} /* nmclan_config */
-
-static void nmclan_release(struct pcmcia_device *link)
-{
-	dev_dbg(&link->dev, "nmclan_release\n");
-	pcmcia_disable_device(link);
-}
-
-static int nmclan_suspend(struct pcmcia_device *link)
-{
-	struct net_device *dev = link->priv;
-
-	if (link->open)
-		netif_device_detach(dev);
-
-	return 0;
-}
-
-static int nmclan_resume(struct pcmcia_device *link)
-{
-	struct net_device *dev = link->priv;
-
-	if (link->open) {
-		nmclan_reset(dev);
-		netif_device_attach(dev);
-	}
-
-	return 0;
-}
-
-
-/* ----------------------------------------------------------------------------
-nmclan_reset
-	Reset and restore all of the Xilinx and MACE registers.
----------------------------------------------------------------------------- */
-static void nmclan_reset(struct net_device *dev)
-{
-  mace_private *lp = netdev_priv(dev);
-
-#if RESET_XILINX
-  struct pcmcia_device *link = &lp->link;
-  u8 OrigCorValue;
-
-  /* Save original COR value */
-  pcmcia_read_config_byte(link, CISREG_COR, &OrigCorValue);
-
-  /* Reset Xilinx */
-  dev_dbg(&link->dev, "nmclan_reset: OrigCorValue=0x%x, resetting...\n",
-	OrigCorValue);
-  pcmcia_write_config_byte(link, CISREG_COR, COR_SOFT_RESET);
-  /* Need to wait for 20 ms for PCMCIA to finish reset. */
-
-  /* Restore original COR configuration index */
-  pcmcia_write_config_byte(link, CISREG_COR,
-			  (COR_LEVEL_REQ | (OrigCorValue & COR_CONFIG_MASK)));
-  /* Xilinx is now completely reset along with the MACE chip. */
-  lp->tx_free_frames=AM2150_MAX_TX_FRAMES;
-
-#endif /* #if RESET_XILINX */
-
-  /* Xilinx is now completely reset along with the MACE chip. */
-  lp->tx_free_frames=AM2150_MAX_TX_FRAMES;
-
-  /* Reinitialize the MACE chip for operation. */
-  mace_init(lp, dev->base_addr, dev->dev_addr);
-  mace_write(lp, dev->base_addr, MACE_IMR, MACE_IMR_DEFAULT);
-
-  /* Restore the multicast list and enable TX and RX. */
-  restore_multicast_list(dev);
-} /* nmclan_reset */
-
-/* ----------------------------------------------------------------------------
-mace_config
-	[Someone tell me what this is supposed to do?  Is if_port a defined
-	standard?  If so, there should be defines to indicate 1=10Base-T,
-	2=10Base-2, etc. including limited automatic detection.]
----------------------------------------------------------------------------- */
-static int mace_config(struct net_device *dev, struct ifmap *map)
-{
-  if ((map->port != (u_char)(-1)) && (map->port != dev->if_port)) {
-    if (map->port <= 2) {
-      WRITE_ONCE(dev->if_port, map->port);
-      netdev_info(dev, "switched to %s port\n", if_names[dev->if_port]);
-    } else
-      return -EINVAL;
-  }
-  return 0;
-} /* mace_config */
-
-/* ----------------------------------------------------------------------------
-mace_open
-	Open device driver.
----------------------------------------------------------------------------- */
-static int mace_open(struct net_device *dev)
-{
-  unsigned int ioaddr = dev->base_addr;
-  mace_private *lp = netdev_priv(dev);
-  struct pcmcia_device *link = lp->p_dev;
-
-  if (!pcmcia_dev_present(link))
-    return -ENODEV;
-
-  link->open++;
-
-  MACEBANK(0);
-
-  netif_start_queue(dev);
-  nmclan_reset(dev);
-
-  return 0; /* Always succeed */
-} /* mace_open */
-
-/* ----------------------------------------------------------------------------
-mace_close
-	Closes device driver.
----------------------------------------------------------------------------- */
-static int mace_close(struct net_device *dev)
-{
-  unsigned int ioaddr = dev->base_addr;
-  mace_private *lp = netdev_priv(dev);
-  struct pcmcia_device *link = lp->p_dev;
-
-  dev_dbg(&link->dev, "%s: shutting down ethercard.\n", dev->name);
-
-  /* Mask off all interrupts from the MACE chip. */
-  outb(0xFF, ioaddr + AM2150_MACE_BASE + MACE_IMR);
-
-  link->open--;
-  netif_stop_queue(dev);
-
-  return 0;
-} /* mace_close */
-
-static void netdev_get_drvinfo(struct net_device *dev,
-			       struct ethtool_drvinfo *info)
-{
-	strscpy(info->driver, DRV_NAME, sizeof(info->driver));
-	snprintf(info->bus_info, sizeof(info->bus_info),
-		"PCMCIA 0x%lx", dev->base_addr);
-}
-
-static const struct ethtool_ops netdev_ethtool_ops = {
-	.get_drvinfo		= netdev_get_drvinfo,
-};
-
-/* ----------------------------------------------------------------------------
-mace_start_xmit
-	This routine begins the packet transmit function.  When completed,
-	it will generate a transmit interrupt.
-
-	According to /usr/src/linux/net/inet/dev.c, if _start_xmit
-	returns 0, the "packet is now solely the responsibility of the
-	driver."  If _start_xmit returns non-zero, the "transmission
-	failed, put skb back into a list."
----------------------------------------------------------------------------- */
-
-static void mace_tx_timeout(struct net_device *dev, unsigned int txqueue)
-{
-  mace_private *lp = netdev_priv(dev);
-  struct pcmcia_device *link = lp->p_dev;
-
-  netdev_notice(dev, "transmit timed out -- ");
-#if RESET_ON_TIMEOUT
-  pr_cont("resetting card\n");
-  pcmcia_reset_card(link->socket);
-#else /* #if RESET_ON_TIMEOUT */
-  pr_cont("NOT resetting card\n");
-#endif /* #if RESET_ON_TIMEOUT */
-  netif_trans_update(dev); /* prevent tx timeout */
-  netif_wake_queue(dev);
-}
-
-static netdev_tx_t mace_start_xmit(struct sk_buff *skb,
-					 struct net_device *dev)
-{
-  mace_private *lp = netdev_priv(dev);
-  unsigned int ioaddr = dev->base_addr;
-
-  netif_stop_queue(dev);
-
-  pr_debug("%s: mace_start_xmit(length = %ld) called.\n",
-	dev->name, (long)skb->len);
-
-#if (!TX_INTERRUPTABLE)
-  /* Disable MACE TX interrupts. */
-  outb(MACE_IMR_DEFAULT | MACE_IR_XMTINT,
-    ioaddr + AM2150_MACE_BASE + MACE_IMR);
-  lp->tx_irq_disabled=1;
-#endif /* #if (!TX_INTERRUPTABLE) */
-
-  {
-    /* This block must not be interrupted by another transmit request!
-       mace_tx_timeout will take care of timer-based retransmissions from
-       the upper layers.  The interrupt handler is guaranteed never to
-       service a transmit interrupt while we are in here.
-    */
-
-    dev->stats.tx_bytes += skb->len;
-    lp->tx_free_frames--;
-
-    /* WARNING: Write the _exact_ number of bytes written in the header! */
-    /* Put out the word header [must be an outw()] . . . */
-    outw(skb->len, ioaddr + AM2150_XMT);
-    /* . . . and the packet [may be any combination of outw() and outb()] */
-    outsw(ioaddr + AM2150_XMT, skb->data, skb->len >> 1);
-    if (skb->len & 1) {
-      /* Odd byte transfer */
-      outb(skb->data[skb->len-1], ioaddr + AM2150_XMT);
-    }
-
-#if MULTI_TX
-    if (lp->tx_free_frames > 0)
-      netif_start_queue(dev);
-#endif /* #if MULTI_TX */
-  }
-
-#if (!TX_INTERRUPTABLE)
-  /* Re-enable MACE TX interrupts. */
-  lp->tx_irq_disabled=0;
-  outb(MACE_IMR_DEFAULT, ioaddr + AM2150_MACE_BASE + MACE_IMR);
-#endif /* #if (!TX_INTERRUPTABLE) */
-
-  dev_kfree_skb(skb);
-
-  return NETDEV_TX_OK;
-} /* mace_start_xmit */
-
-/* ----------------------------------------------------------------------------
-mace_interrupt
-	The interrupt handler.
----------------------------------------------------------------------------- */
-static irqreturn_t mace_interrupt(int irq, void *dev_id)
-{
-  struct net_device *dev = (struct net_device *) dev_id;
-  mace_private *lp = netdev_priv(dev);
-  unsigned int ioaddr;
-  int status;
-  int IntrCnt = MACE_MAX_IR_ITERATIONS;
-
-  if (!dev) {
-    pr_debug("mace_interrupt(): irq 0x%X for unknown device.\n",
-	  irq);
-    return IRQ_NONE;
-  }
-
-  ioaddr = dev->base_addr;
-
-  if (lp->tx_irq_disabled) {
-    const char *msg;
-    if (lp->tx_irq_disabled)
-      msg = "Interrupt with tx_irq_disabled";
-    else
-      msg = "Re-entering the interrupt handler";
-    netdev_notice(dev, "%s [isr=%02X, imr=%02X]\n",
-		  msg,
-		  inb(ioaddr + AM2150_MACE_BASE + MACE_IR),
-		  inb(ioaddr + AM2150_MACE_BASE + MACE_IMR));
-    /* WARNING: MACE_IR has been read! */
-    return IRQ_NONE;
-  }
-
-  if (!netif_device_present(dev)) {
-    netdev_dbg(dev, "interrupt from dead card\n");
-    return IRQ_NONE;
-  }
-
-  do {
-    /* WARNING: MACE_IR is a READ/CLEAR port! */
-    status = inb(ioaddr + AM2150_MACE_BASE + MACE_IR);
-    if (!(status & ~MACE_IMR_DEFAULT) && IntrCnt == MACE_MAX_IR_ITERATIONS)
-      return IRQ_NONE;
-
-    pr_debug("mace_interrupt: irq 0x%X status 0x%X.\n", irq, status);
-
-    if (status & MACE_IR_RCVINT) {
-      mace_rx(dev, MACE_MAX_RX_ITERATIONS);
-    }
-
-    if (status & MACE_IR_XMTINT) {
-      unsigned char fifofc;
-      unsigned char xmtrc;
-      unsigned char xmtfs;
-
-      fifofc = inb(ioaddr + AM2150_MACE_BASE + MACE_FIFOFC);
-      if ((fifofc & MACE_FIFOFC_XMTFC)==0) {
-	dev->stats.tx_errors++;
-	outb(0xFF, ioaddr + AM2150_XMT_SKIP);
-      }
-
-      /* Transmit Retry Count (XMTRC, reg 4) */
-      xmtrc = inb(ioaddr + AM2150_MACE_BASE + MACE_XMTRC);
-      if (xmtrc & MACE_XMTRC_EXDEF) lp->mace_stats.exdef++;
-      lp->mace_stats.xmtrc += (xmtrc & MACE_XMTRC_XMTRC);
-
-      if (
-        (xmtfs = inb(ioaddr + AM2150_MACE_BASE + MACE_XMTFS)) &
-        MACE_XMTFS_XMTSV /* Transmit Status Valid */
-      ) {
-	lp->mace_stats.xmtsv++;
-
-	if (xmtfs & ~MACE_XMTFS_XMTSV) {
-	  if (xmtfs & MACE_XMTFS_UFLO) {
-	    /* Underflow.  Indicates that the Transmit FIFO emptied before
-	       the end of frame was reached. */
-	    lp->mace_stats.uflo++;
-	  }
-	  if (xmtfs & MACE_XMTFS_LCOL) {
-	    /* Late Collision */
-	    lp->mace_stats.lcol++;
-	  }
-	  if (xmtfs & MACE_XMTFS_MORE) {
-	    /* MORE than one retry was needed */
-	    lp->mace_stats.more++;
-	  }
-	  if (xmtfs & MACE_XMTFS_ONE) {
-	    /* Exactly ONE retry occurred */
-	    lp->mace_stats.one++;
-	  }
-	  if (xmtfs & MACE_XMTFS_DEFER) {
-	    /* Transmission was defered */
-	    lp->mace_stats.defer++;
-	  }
-	  if (xmtfs & MACE_XMTFS_LCAR) {
-	    /* Loss of carrier */
-	    lp->mace_stats.lcar++;
-	  }
-	  if (xmtfs & MACE_XMTFS_RTRY) {
-	    /* Retry error: transmit aborted after 16 attempts */
-	    lp->mace_stats.rtry++;
-	  }
-        } /* if (xmtfs & ~MACE_XMTFS_XMTSV) */
-
-      } /* if (xmtfs & MACE_XMTFS_XMTSV) */
-
-      dev->stats.tx_packets++;
-      lp->tx_free_frames++;
-      netif_wake_queue(dev);
-    } /* if (status & MACE_IR_XMTINT) */
-
-    if (status & ~MACE_IMR_DEFAULT & ~MACE_IR_RCVINT & ~MACE_IR_XMTINT) {
-      if (status & MACE_IR_JAB) {
-        /* Jabber Error.  Excessive transmit duration (20-150ms). */
-        lp->mace_stats.jab++;
-      }
-      if (status & MACE_IR_BABL) {
-        /* Babble Error.  >1518 bytes transmitted. */
-        lp->mace_stats.babl++;
-      }
-      if (status & MACE_IR_CERR) {
-	/* Collision Error.  CERR indicates the absence of the
-	   Signal Quality Error Test message after a packet
-	   transmission. */
-        lp->mace_stats.cerr++;
-      }
-      if (status & MACE_IR_RCVCCO) {
-        /* Receive Collision Count Overflow; */
-        lp->mace_stats.rcvcco++;
-      }
-      if (status & MACE_IR_RNTPCO) {
-        /* Runt Packet Count Overflow */
-        lp->mace_stats.rntpco++;
-      }
-      if (status & MACE_IR_MPCO) {
-        /* Missed Packet Count Overflow */
-        lp->mace_stats.mpco++;
-      }
-    } /* if (status & ~MACE_IMR_DEFAULT & ~MACE_IR_RCVINT & ~MACE_IR_XMTINT) */
-
-  } while ((status & ~MACE_IMR_DEFAULT) && (--IntrCnt));
-
-  return IRQ_HANDLED;
-} /* mace_interrupt */
-
-/* ----------------------------------------------------------------------------
-mace_rx
-	Receives packets.
----------------------------------------------------------------------------- */
-static int mace_rx(struct net_device *dev, unsigned char RxCnt)
-{
-  mace_private *lp = netdev_priv(dev);
-  unsigned int ioaddr = dev->base_addr;
-  unsigned char rx_framecnt;
-  unsigned short rx_status;
-
-  while (
-    ((rx_framecnt = inb(ioaddr + AM2150_RCV_FRAME_COUNT)) > 0) &&
-    (rx_framecnt <= 12) && /* rx_framecnt==0xFF if card is extracted. */
-    (RxCnt--)
-  ) {
-    rx_status = inw(ioaddr + AM2150_RCV);
-
-    pr_debug("%s: in mace_rx(), framecnt 0x%X, rx_status"
-	  " 0x%X.\n", dev->name, rx_framecnt, rx_status);
-
-    if (rx_status & MACE_RCVFS_RCVSTS) { /* Error, update stats. */
-      dev->stats.rx_errors++;
-      if (rx_status & MACE_RCVFS_OFLO) {
-        lp->mace_stats.oflo++;
-      }
-      if (rx_status & MACE_RCVFS_CLSN) {
-        lp->mace_stats.clsn++;
-      }
-      if (rx_status & MACE_RCVFS_FRAM) {
-	lp->mace_stats.fram++;
-      }
-      if (rx_status & MACE_RCVFS_FCS) {
-        lp->mace_stats.fcs++;
-      }
-    } else {
-      short pkt_len = (rx_status & ~MACE_RCVFS_RCVSTS) - 4;
-        /* Auto Strip is off, always subtract 4 */
-      struct sk_buff *skb;
-
-      lp->mace_stats.rfs_rntpc += inb(ioaddr + AM2150_RCV);
-        /* runt packet count */
-      lp->mace_stats.rfs_rcvcc += inb(ioaddr + AM2150_RCV);
-        /* rcv collision count */
-
-      pr_debug("    receiving packet size 0x%X rx_status"
-	    " 0x%X.\n", pkt_len, rx_status);
-
-      skb = netdev_alloc_skb(dev, pkt_len + 2);
-
-      if (skb) {
-	skb_reserve(skb, 2);
-	insw(ioaddr + AM2150_RCV, skb_put(skb, pkt_len), pkt_len>>1);
-	if (pkt_len & 1)
-	    *(skb_tail_pointer(skb) - 1) = inb(ioaddr + AM2150_RCV);
-	skb->protocol = eth_type_trans(skb, dev);
-
-	netif_rx(skb); /* Send the packet to the upper (protocol) layers. */
-
-	dev->stats.rx_packets++;
-	dev->stats.rx_bytes += pkt_len;
-	outb(0xFF, ioaddr + AM2150_RCV_NEXT); /* skip to next frame */
-	continue;
-      } else {
-	pr_debug("%s: couldn't allocate a sk_buff of size"
-	      " %d.\n", dev->name, pkt_len);
-	dev->stats.rx_dropped++;
-      }
-    }
-    outb(0xFF, ioaddr + AM2150_RCV_NEXT); /* skip to next frame */
-  } /* while */
-
-  return 0;
-} /* mace_rx */
-
-/* ----------------------------------------------------------------------------
-pr_linux_stats
----------------------------------------------------------------------------- */
-static void pr_linux_stats(struct net_device_stats *pstats)
-{
-  pr_debug("pr_linux_stats\n");
-  pr_debug(" rx_packets=%-7ld        tx_packets=%ld\n",
-	(long)pstats->rx_packets, (long)pstats->tx_packets);
-  pr_debug(" rx_errors=%-7ld         tx_errors=%ld\n",
-	(long)pstats->rx_errors, (long)pstats->tx_errors);
-  pr_debug(" rx_dropped=%-7ld        tx_dropped=%ld\n",
-	(long)pstats->rx_dropped, (long)pstats->tx_dropped);
-  pr_debug(" multicast=%-7ld         collisions=%ld\n",
-	(long)pstats->multicast, (long)pstats->collisions);
-
-  pr_debug(" rx_length_errors=%-7ld  rx_over_errors=%ld\n",
-	(long)pstats->rx_length_errors, (long)pstats->rx_over_errors);
-  pr_debug(" rx_crc_errors=%-7ld     rx_frame_errors=%ld\n",
-	(long)pstats->rx_crc_errors, (long)pstats->rx_frame_errors);
-  pr_debug(" rx_fifo_errors=%-7ld    rx_missed_errors=%ld\n",
-	(long)pstats->rx_fifo_errors, (long)pstats->rx_missed_errors);
-
-  pr_debug(" tx_aborted_errors=%-7ld tx_carrier_errors=%ld\n",
-	(long)pstats->tx_aborted_errors, (long)pstats->tx_carrier_errors);
-  pr_debug(" tx_fifo_errors=%-7ld    tx_heartbeat_errors=%ld\n",
-	(long)pstats->tx_fifo_errors, (long)pstats->tx_heartbeat_errors);
-  pr_debug(" tx_window_errors=%ld\n",
-	(long)pstats->tx_window_errors);
-} /* pr_linux_stats */
-
-/* ----------------------------------------------------------------------------
-pr_mace_stats
----------------------------------------------------------------------------- */
-static void pr_mace_stats(mace_statistics *pstats)
-{
-  pr_debug("pr_mace_stats\n");
-
-  pr_debug(" xmtsv=%-7d             uflo=%d\n",
-	pstats->xmtsv, pstats->uflo);
-  pr_debug(" lcol=%-7d              more=%d\n",
-	pstats->lcol, pstats->more);
-  pr_debug(" one=%-7d               defer=%d\n",
-	pstats->one, pstats->defer);
-  pr_debug(" lcar=%-7d              rtry=%d\n",
-	pstats->lcar, pstats->rtry);
-
-  /* MACE_XMTRC */
-  pr_debug(" exdef=%-7d             xmtrc=%d\n",
-	pstats->exdef, pstats->xmtrc);
-
-  /* RFS1--Receive Status (RCVSTS) */
-  pr_debug(" oflo=%-7d              clsn=%d\n",
-	pstats->oflo, pstats->clsn);
-  pr_debug(" fram=%-7d              fcs=%d\n",
-	pstats->fram, pstats->fcs);
-
-  /* RFS2--Runt Packet Count (RNTPC) */
-  /* RFS3--Receive Collision Count (RCVCC) */
-  pr_debug(" rfs_rntpc=%-7d         rfs_rcvcc=%d\n",
-	pstats->rfs_rntpc, pstats->rfs_rcvcc);
-
-  /* MACE_IR */
-  pr_debug(" jab=%-7d               babl=%d\n",
-	pstats->jab, pstats->babl);
-  pr_debug(" cerr=%-7d              rcvcco=%d\n",
-	pstats->cerr, pstats->rcvcco);
-  pr_debug(" rntpco=%-7d            mpco=%d\n",
-	pstats->rntpco, pstats->mpco);
-
-  /* MACE_MPC */
-  pr_debug(" mpc=%d\n", pstats->mpc);
-
-  /* MACE_RNTPC */
-  pr_debug(" rntpc=%d\n", pstats->rntpc);
-
-  /* MACE_RCVCC */
-  pr_debug(" rcvcc=%d\n", pstats->rcvcc);
-
-} /* pr_mace_stats */
-
-/* ----------------------------------------------------------------------------
-update_stats
-	Update statistics.  We change to register window 1, so this
-	should be run single-threaded if the device is active. This is
-	expected to be a rare operation, and it's simpler for the rest
-	of the driver to assume that window 0 is always valid rather
-	than use a special window-state variable.
-
-	oflo & uflo should _never_ occur since it would mean the Xilinx
-	was not able to transfer data between the MACE FIFO and the
-	card's SRAM fast enough.  If this happens, something is
-	seriously wrong with the hardware.
----------------------------------------------------------------------------- */
-static void update_stats(unsigned int ioaddr, struct net_device *dev)
-{
-  mace_private *lp = netdev_priv(dev);
-
-  lp->mace_stats.rcvcc += mace_read(lp, ioaddr, MACE_RCVCC);
-  lp->mace_stats.rntpc += mace_read(lp, ioaddr, MACE_RNTPC);
-  lp->mace_stats.mpc += mace_read(lp, ioaddr, MACE_MPC);
-  /* At this point, mace_stats is fully updated for this call.
-     We may now update the netdev stats. */
-
-  /* The MACE has no equivalent for netdev stats field which are commented
-     out. */
-
-  /* dev->stats.multicast; */
-  dev->stats.collisions =
-    lp->mace_stats.rcvcco * 256 + lp->mace_stats.rcvcc;
-    /* Collision: The MACE may retry sending a packet 15 times
-       before giving up.  The retry count is in XMTRC.
-       Does each retry constitute a collision?
-       If so, why doesn't the RCVCC record these collisions? */
-
-  /* detailed rx_errors: */
-  dev->stats.rx_length_errors =
-    lp->mace_stats.rntpco * 256 + lp->mace_stats.rntpc;
-  /* dev->stats.rx_over_errors */
-  dev->stats.rx_crc_errors = lp->mace_stats.fcs;
-  dev->stats.rx_frame_errors = lp->mace_stats.fram;
-  dev->stats.rx_fifo_errors = lp->mace_stats.oflo;
-  dev->stats.rx_missed_errors =
-    lp->mace_stats.mpco * 256 + lp->mace_stats.mpc;
-
-  /* detailed tx_errors */
-  dev->stats.tx_aborted_errors = lp->mace_stats.rtry;
-  dev->stats.tx_carrier_errors = lp->mace_stats.lcar;
-    /* LCAR usually results from bad cabling. */
-  dev->stats.tx_fifo_errors = lp->mace_stats.uflo;
-  dev->stats.tx_heartbeat_errors = lp->mace_stats.cerr;
-  /* dev->stats.tx_window_errors; */
-} /* update_stats */
-
-/* ----------------------------------------------------------------------------
-mace_get_stats
-	Gathers ethernet statistics from the MACE chip.
----------------------------------------------------------------------------- */
-static struct net_device_stats *mace_get_stats(struct net_device *dev)
-{
-  mace_private *lp = netdev_priv(dev);
-
-  update_stats(dev->base_addr, dev);
-
-  pr_debug("%s: updating the statistics.\n", dev->name);
-  pr_linux_stats(&dev->stats);
-  pr_mace_stats(&lp->mace_stats);
-
-  return &dev->stats;
-} /* net_device_stats */
-
-/* ----------------------------------------------------------------------------
-updateCRC
-	Modified from Am79C90 data sheet.
----------------------------------------------------------------------------- */
-
-#ifdef BROKEN_MULTICAST
-
-static void updateCRC(int *CRC, int bit)
-{
-  static const int poly[]={
-    1,1,1,0, 1,1,0,1,
-    1,0,1,1, 1,0,0,0,
-    1,0,0,0, 0,0,1,1,
-    0,0,1,0, 0,0,0,0
-  }; /* CRC polynomial.  poly[n] = coefficient of the x**n term of the
-	CRC generator polynomial. */
-
-  int j;
-
-  /* shift CRC and control bit (CRC[32]) */
-  for (j = 32; j > 0; j--)
-    CRC[j] = CRC[j-1];
-  CRC[0] = 0;
-
-  /* If bit XOR(control bit) = 1, set CRC = CRC XOR polynomial. */
-  if (bit ^ CRC[32])
-    for (j = 0; j < 32; j++)
-      CRC[j] ^= poly[j];
-} /* updateCRC */
-
-/* ----------------------------------------------------------------------------
-BuildLAF
-	Build logical address filter.
-	Modified from Am79C90 data sheet.
-
-Input
-	ladrf: logical address filter (contents initialized to 0)
-	adr: ethernet address
----------------------------------------------------------------------------- */
-static void BuildLAF(int *ladrf, int *adr)
-{
-  int CRC[33]={1}; /* CRC register, 1 word/bit + extra control bit */
-
-  int i, byte; /* temporary array indices */
-  int hashcode; /* the output object */
-
-  CRC[32]=0;
-
-  for (byte = 0; byte < 6; byte++)
-    for (i = 0; i < 8; i++)
-      updateCRC(CRC, (adr[byte] >> i) & 1);
-
-  hashcode = 0;
-  for (i = 0; i < 6; i++)
-    hashcode = (hashcode << 1) + CRC[i];
-
-  byte = hashcode >> 3;
-  ladrf[byte] |= (1 << (hashcode & 7));
-
-#ifdef PCMCIA_DEBUG
-  if (0)
-    printk(KERN_DEBUG "    adr =%pM\n", adr);
-  printk(KERN_DEBUG "    hashcode = %d(decimal), ladrf[0:63] =", hashcode);
-  for (i = 0; i < 8; i++)
-    pr_cont(" %02X", ladrf[i]);
-  pr_cont("\n");
-#endif
-} /* BuildLAF */
-
-/* ----------------------------------------------------------------------------
-restore_multicast_list
-	Restores the multicast filter for MACE chip to the last
-	set_multicast_list() call.
-
-Input
-	multicast_num_addrs
-	multicast_ladrf[]
----------------------------------------------------------------------------- */
-static void restore_multicast_list(struct net_device *dev)
-{
-  mace_private *lp = netdev_priv(dev);
-  int num_addrs = lp->multicast_num_addrs;
-  int *ladrf = lp->multicast_ladrf;
-  unsigned int ioaddr = dev->base_addr;
-  int i;
-
-  pr_debug("%s: restoring Rx mode to %d addresses.\n",
-	dev->name, num_addrs);
-
-  if (num_addrs > 0) {
-
-    pr_debug("Attempt to restore multicast list detected.\n");
-
-    mace_write(lp, ioaddr, MACE_IAC, MACE_IAC_ADDRCHG | MACE_IAC_LOGADDR);
-    /* Poll ADDRCHG bit */
-    while (mace_read(lp, ioaddr, MACE_IAC) & MACE_IAC_ADDRCHG)
-      ;
-    /* Set LADRF register */
-    for (i = 0; i < MACE_LADRF_LEN; i++)
-      mace_write(lp, ioaddr, MACE_LADRF, ladrf[i]);
-
-    mace_write(lp, ioaddr, MACE_UTR, MACE_UTR_RCVFCSE | MACE_UTR_LOOP_EXTERNAL);
-    mace_write(lp, ioaddr, MACE_MACCC, MACE_MACCC_ENXMT | MACE_MACCC_ENRCV);
-
-  } else if (num_addrs < 0) {
-
-    /* Promiscuous mode: receive all packets */
-    mace_write(lp, ioaddr, MACE_UTR, MACE_UTR_LOOP_EXTERNAL);
-    mace_write(lp, ioaddr, MACE_MACCC,
-      MACE_MACCC_PROM | MACE_MACCC_ENXMT | MACE_MACCC_ENRCV
-    );
-
-  } else {
-
-    /* Normal mode */
-    mace_write(lp, ioaddr, MACE_UTR, MACE_UTR_LOOP_EXTERNAL);
-    mace_write(lp, ioaddr, MACE_MACCC, MACE_MACCC_ENXMT | MACE_MACCC_ENRCV);
-
-  }
-} /* restore_multicast_list */
-
-/* ----------------------------------------------------------------------------
-set_multicast_list
-	Set or clear the multicast filter for this adaptor.
-
-Input
-	num_addrs == -1	Promiscuous mode, receive all packets
-	num_addrs == 0	Normal mode, clear multicast list
-	num_addrs > 0	Multicast mode, receive normal and MC packets, and do
-			best-effort filtering.
-Output
-	multicast_num_addrs
-	multicast_ladrf[]
----------------------------------------------------------------------------- */
-
-static void set_multicast_list(struct net_device *dev)
-{
-  mace_private *lp = netdev_priv(dev);
-  int adr[ETH_ALEN] = {0}; /* Ethernet address */
-  struct netdev_hw_addr *ha;
-
-#ifdef PCMCIA_DEBUG
-  {
-    static int old;
-    if (netdev_mc_count(dev) != old) {
-      old = netdev_mc_count(dev);
-      pr_debug("%s: setting Rx mode to %d addresses.\n",
-	    dev->name, old);
-    }
-  }
-#endif
-
-  /* Set multicast_num_addrs. */
-  lp->multicast_num_addrs = netdev_mc_count(dev);
-
-  /* Set multicast_ladrf. */
-  if (num_addrs > 0) {
-    /* Calculate multicast logical address filter */
-    memset(lp->multicast_ladrf, 0, MACE_LADRF_LEN);
-    netdev_for_each_mc_addr(ha, dev) {
-      memcpy(adr, ha->addr, ETH_ALEN);
-      BuildLAF(lp->multicast_ladrf, adr);
-    }
-  }
-
-  restore_multicast_list(dev);
-
-} /* set_multicast_list */
-
-#endif /* BROKEN_MULTICAST */
-
-static void restore_multicast_list(struct net_device *dev)
-{
-  unsigned int ioaddr = dev->base_addr;
-  mace_private *lp = netdev_priv(dev);
-
-  pr_debug("%s: restoring Rx mode to %d addresses.\n", dev->name,
-	lp->multicast_num_addrs);
-
-  if (dev->flags & IFF_PROMISC) {
-    /* Promiscuous mode: receive all packets */
-    mace_write(lp,ioaddr, MACE_UTR, MACE_UTR_LOOP_EXTERNAL);
-    mace_write(lp, ioaddr, MACE_MACCC,
-      MACE_MACCC_PROM | MACE_MACCC_ENXMT | MACE_MACCC_ENRCV
-    );
-  } else {
-    /* Normal mode */
-    mace_write(lp, ioaddr, MACE_UTR, MACE_UTR_LOOP_EXTERNAL);
-    mace_write(lp, ioaddr, MACE_MACCC, MACE_MACCC_ENXMT | MACE_MACCC_ENRCV);
-  }
-} /* restore_multicast_list */
-
-static void set_multicast_list(struct net_device *dev)
-{
-  mace_private *lp = netdev_priv(dev);
-
-#ifdef PCMCIA_DEBUG
-  {
-    static int old;
-    if (netdev_mc_count(dev) != old) {
-      old = netdev_mc_count(dev);
-      pr_debug("%s: setting Rx mode to %d addresses.\n",
-	    dev->name, old);
-    }
-  }
-#endif
-
-  lp->multicast_num_addrs = netdev_mc_count(dev);
-  restore_multicast_list(dev);
-
-} /* set_multicast_list */
-
-static const struct pcmcia_device_id nmclan_ids[] = {
-	PCMCIA_DEVICE_PROD_ID12("New Media Corporation", "Ethernet", 0x085a850b, 0x00b2e941),
-	PCMCIA_DEVICE_PROD_ID12("Portable Add-ons", "Ethernet+", 0xebf1d60, 0xad673aaf),
-	PCMCIA_DEVICE_NULL,
-};
-MODULE_DEVICE_TABLE(pcmcia, nmclan_ids);
-
-static struct pcmcia_driver nmclan_cs_driver = {
-	.owner		= THIS_MODULE,
-	.name		= "nmclan_cs",
-	.probe		= nmclan_probe,
-	.remove		= nmclan_detach,
-	.id_table       = nmclan_ids,
-	.suspend	= nmclan_suspend,
-	.resume		= nmclan_resume,
-};
-module_pcmcia_driver(nmclan_cs_driver);

-- 
2.53.0


^ permalink raw reply related	[flat|nested] 28+ messages in thread

* [PATCH net 09/18] drivers: net: smsc: smc9194: Remove this driver
  2026-04-21 19:31 [PATCH net 00/18] Remove a number of ISA and PCMCIA Ethernet drivers Andrew Lunn
                   ` (7 preceding siblings ...)
  2026-04-21 19:31 ` [PATCH net 08/18] drivers: net: amd: nmclan: " Andrew Lunn
@ 2026-04-21 19:31 ` Andrew Lunn
  2026-04-21 19:31 ` [PATCH net 10/18] drivers: net: smsc: smc91c92: " Andrew Lunn
                   ` (12 subsequent siblings)
  21 siblings, 0 replies; 28+ messages in thread
From: Andrew Lunn @ 2026-04-21 19:31 UTC (permalink / raw)
  To: Andrew Lunn, David S. Miller, Eric Dumazet, Jakub Kicinski,
	Paolo Abeni, Simon Horman, Jonathan Corbet, Shuah Khan
  Cc: linux-kernel, netdev, linux-doc, Andrew Lunn

The smc9194 was written by Erik Stahlman in 1996. It is an ISA device,
so unlikely to be used with modern kernels.

Signed-off-by: Andrew Lunn <andrew@lunn.ch>
---
 drivers/net/ethernet/smsc/Kconfig   |   15 -
 drivers/net/ethernet/smsc/Makefile  |    1 -
 drivers/net/ethernet/smsc/smc9194.c | 1535 -----------------------------------
 3 files changed, 1551 deletions(-)

diff --git a/drivers/net/ethernet/smsc/Kconfig b/drivers/net/ethernet/smsc/Kconfig
index 13ce9086a9ca..d25bbcc98854 100644
--- a/drivers/net/ethernet/smsc/Kconfig
+++ b/drivers/net/ethernet/smsc/Kconfig
@@ -19,21 +19,6 @@ config NET_VENDOR_SMSC
 
 if NET_VENDOR_SMSC
 
-config SMC9194
-	tristate "SMC 9194 support"
-	depends on ISA
-	select CRC32
-	select NETDEV_LEGACY_INIT
-	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/device_drivers/ethernet/smsc/smc9.rst>.
-
-	  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
diff --git a/drivers/net/ethernet/smsc/Makefile b/drivers/net/ethernet/smsc/Makefile
index 1501fa364c13..afea0b94c2a4 100644
--- a/drivers/net/ethernet/smsc/Makefile
+++ b/drivers/net/ethernet/smsc/Makefile
@@ -3,7 +3,6 @@
 # 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
diff --git a/drivers/net/ethernet/smsc/smc9194.c b/drivers/net/ethernet/smsc/smc9194.c
deleted file mode 100644
index e2e7b1c68563..000000000000
--- a/drivers/net/ethernet/smsc/smc9194.c
+++ /dev/null
@@ -1,1535 +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)";
-
-#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
-
-/*
- .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;
-};
-
-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},
-};
-/*
- . 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, unsigned int txqueue);
-
-/*
- . 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! */
-		netdev_dbg(dev, 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 );
-		outw( *((word *)(buf + (length & 0xFFFFFFFC))),ioaddr +DATA_1);
-	}
-	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);
-
-	netif_trans_update(dev);
-
-	/* 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_rx_mode	= smc_set_multicast_list,
-	.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;
-	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;
-	u8 addr[ETH_ALEN];
-
-	/* 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;
-	}
-	/* 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;
-	}
-
-	/*  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. */
-
-	pr_info_once("%s\n", 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  );
-		addr[i + 1] = address >> 8;
-		addr[i] = address & 0xFF;
-	}
-	eth_hw_addr_set(dev, addr);
-
-	/* 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.. */
-
-	netdev_info(dev, "%s(r:%d) at %#3x IRQ:%d INTF:%s MEM:%db ",
-		    version_string, revision_register & 0xF, ioaddr, dev->irq,
-		    if_string, memory);
-	/*
-	 . Print the Ethernet address
-	*/
-	netdev_info(dev, "ADDR: %pM\n", dev->dev_addr);
-
-	/* Grab the IRQ */
-	retval = request_irq(dev->irq, smc_interrupt, 0, DRV_NAME, dev);
-	if (retval) {
-		netdev_warn(dev, "%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
-	print_hex_dump_debug(DRV_NAME, DUMP_PREFIX_OFFSET, 16, 1,
-			     buf, length, true);
-#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, unsigned int txqueue)
-{
-	/* If we get here, some higher level has decided we are broken.
-	   There should really be a "kick me" function call instead. */
-	netdev_warn(dev, 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 );
-	netif_trans_update(dev); /* 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 = netdev_alloc_skb(dev, packet_length + 5);
-		if ( skb == NULL ) {
-			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  ) {
-		netdev_dbg(dev, 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 ) {
-		netdev_info(dev, 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_DESCRIPTION("SMC 9194 Ethernet driver");
-MODULE_LICENSE("GPL");
-
-module_param_hw(io, int, ioport, 0);
-module_param_hw(irq, int, irq, 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)");
-
-static int __init smc_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);
-	return PTR_ERR_OR_ZERO(devSMC9194);
-}
-module_init(smc_init_module);
-
-static void __exit smc_cleanup_module(void)
-{
-	unregister_netdev(devSMC9194);
-	free_irq(devSMC9194->irq, devSMC9194);
-	release_region(devSMC9194->base_addr, SMC_IO_EXTENT);
-	free_netdev(devSMC9194);
-}
-module_exit(smc_cleanup_module);
-
-#endif /* MODULE */

-- 
2.53.0


^ permalink raw reply related	[flat|nested] 28+ messages in thread

* [PATCH net 10/18] drivers: net: smsc: smc91c92: Remove this driver
  2026-04-21 19:31 [PATCH net 00/18] Remove a number of ISA and PCMCIA Ethernet drivers Andrew Lunn
                   ` (8 preceding siblings ...)
  2026-04-21 19:31 ` [PATCH net 09/18] drivers: net: smsc: smc9194: " Andrew Lunn
@ 2026-04-21 19:31 ` Andrew Lunn
  2026-04-21 19:31 ` [PATCH net 11/18] drivers: net: cirrus: cs89x0: " Andrew Lunn
                   ` (11 subsequent siblings)
  21 siblings, 0 replies; 28+ messages in thread
From: Andrew Lunn @ 2026-04-21 19:31 UTC (permalink / raw)
  To: Andrew Lunn, David S. Miller, Eric Dumazet, Jakub Kicinski,
	Paolo Abeni, Simon Horman, Jonathan Corbet, Shuah Khan
  Cc: linux-kernel, netdev, linux-doc, Andrew Lunn

The smc91c92 was written by David A Hinds in 1999. It is an PCMCIA
device, so unlikely to be used with modern kernels.

Signed-off-by: Andrew Lunn <andrew@lunn.ch>
---
 drivers/net/ethernet/smsc/Kconfig       |   12 -
 drivers/net/ethernet/smsc/Makefile      |    1 -
 drivers/net/ethernet/smsc/smc91c92_cs.c | 2059 -------------------------------
 3 files changed, 2072 deletions(-)

diff --git a/drivers/net/ethernet/smsc/Kconfig b/drivers/net/ethernet/smsc/Kconfig
index d25bbcc98854..66bca803b19c 100644
--- a/drivers/net/ethernet/smsc/Kconfig
+++ b/drivers/net/ethernet/smsc/Kconfig
@@ -37,18 +37,6 @@ config SMC91X
 	  The module will be called smc91x.  If you want to compile it as a
 	  module, say M here and read <file:Documentation/kbuild/modules.rst>.
 
-config PCMCIA_SMC91C92
-	tristate "SMC 91Cxx PCMCIA support"
-	depends on PCMCIA && HAS_IOPORT
-	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
diff --git a/drivers/net/ethernet/smsc/Makefile b/drivers/net/ethernet/smsc/Makefile
index afea0b94c2a4..ab6f03f7ba17 100644
--- a/drivers/net/ethernet/smsc/Makefile
+++ b/drivers/net/ethernet/smsc/Makefile
@@ -4,7 +4,6 @@
 #
 
 obj-$(CONFIG_SMC91X) += smc91x.o
-obj-$(CONFIG_PCMCIA_SMC91C92) += smc91c92_cs.o
 obj-$(CONFIG_EPIC100) += epic100.o
 obj-$(CONFIG_SMSC9420) += smsc9420.o
 obj-$(CONFIG_SMSC911X) += smsc911x.o
diff --git a/drivers/net/ethernet/smsc/smc91c92_cs.c b/drivers/net/ethernet/smsc/smc91c92_cs.c
deleted file mode 100644
index cc0c75694351..000000000000
--- a/drivers/net/ethernet/smsc/smc91c92_cs.c
+++ /dev/null
@@ -1,2059 +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/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 <linux/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;
-    unsigned long		last_rx;
-};
-
-/* 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, unsigned int txqueue);
-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(struct timer_list *t);
-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_rx_mode	= set_rx_mode,
-	.ndo_eth_ioctl		= smc_ioctl,
-	.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;
-    dev->ethtool_ops = &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)
-{
-    u8 mac[ETH_ALEN];
-    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);
-	}
-	mac[i] = da;
-    }
-    eth_hw_addr_set(dev, mac);
-    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;
-    u8 mac[ETH_ALEN];
-    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);
-	mac[2*i]   = addr & 0xff;
-	mac[2*i+1] = (addr >> 8) & 0xff;
-    }
-    eth_hw_addr_set(dev, mac);
-
-    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;
-
-	if (tuple->TupleDataLen < 8)
-		return -EINVAL;
-	if (tuple->TupleData[0] != 0x04)
-		return -EINVAL;
-
-	eth_hw_addr_set(dev, &tuple->TupleData[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) {
-			netdev_err(dev, "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) {
-	    netdev_info(dev, "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_dbg(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);
-    timer_setup(&smc->media, media_check, 0);
-    mod_timer(&smc->media, jiffies + HZ);
-
-    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--;
-    timer_delete_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);
-    netif_trans_update(dev);
-    netif_start_queue(dev);
-}
-
-/*====================================================================*/
-
-static void smc_tx_timeout(struct net_device *dev, unsigned int txqueue)
-{
-    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);
-    netif_trans_update(dev); /* 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_dbg(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. */
-    netdev_dbg(dev, "memory allocation deferred.\n");
-    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);
-    netdev_dbg(dev, "Ethernet protocol handler interrupt, status %4.4x.\n",
-	       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;
-
-    netdev_dbg(dev, "SMC91c92 interrupt %d at %#x.\n",
-	       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. */
-	netdev_dbg(dev, "SMC91c92 interrupt %d for non-existent/ejected device.\n",
-		   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;
-	netdev_dbg(dev, "Status is %#2.2x (mask %#2.2x).\n",
-		   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);
-
-    netdev_dbg(dev, "  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);
-
-    netdev_dbg(dev, "Exiting interrupt IRQ%d.\n", 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;
-
-    netdev_dbg(dev, "Receive status %4.4x length %d.\n",
-	       rx_status, packet_length);
-
-    if (!(rx_status & RS_ERRORS)) {
-	/* do stuff to make a new packet */
-	struct sk_buff *skb;
-	struct smc_private *smc = netdev_priv(dev);
-	
-	/* Note: packet_length adds 5 or 6 extra bytes here! */
-	skb = netdev_alloc_skb(dev, packet_length+2);
-	
-	if (skb == NULL) {
-	    netdev_dbg(dev, "Low memory, packet dropped.\n");
-	    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);
-	smc->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;
-	WRITE_ONCE(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;
-
-    netdev_dbg(dev, "smc91c92 reset called.\n");
-
-    /* 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(struct timer_list *t)
-{
-    struct smc_private *smc = timer_container_of(smc, t, media);
-    struct net_device *dev = smc->mii_if.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, smc->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 void smc_netdev_get_ecmd(struct net_device *dev,
-				struct ethtool_link_ksettings *ecmd)
-{
-	u16 tmp;
-	unsigned int ioaddr = dev->base_addr;
-	u32 supported;
-
-	supported = (SUPPORTED_TP | SUPPORTED_AUI |
-		     SUPPORTED_10baseT_Half | SUPPORTED_10baseT_Full);
-
-	SMC_SELECT_BANK(1);
-	tmp = inw(ioaddr + CONFIG);
-	ecmd->base.port = (tmp & CFG_AUI_SELECT) ? PORT_AUI : PORT_TP;
-	ecmd->base.speed = SPEED_10;
-	ecmd->base.phy_address = ioaddr + MGMT;
-
-	SMC_SELECT_BANK(0);
-	tmp = inw(ioaddr + TCR);
-	ecmd->base.duplex = (tmp & TCR_FDUPLX) ? DUPLEX_FULL : DUPLEX_HALF;
-
-	ethtool_convert_legacy_u32_to_link_mode(ecmd->link_modes.supported,
-						supported);
-}
-
-static int smc_netdev_set_ecmd(struct net_device *dev,
-			       const struct ethtool_link_ksettings *ecmd)
-{
-	u16 tmp;
-	unsigned int ioaddr = dev->base_addr;
-
-	if (ecmd->base.speed != SPEED_10)
-		return -EINVAL;
-	if (ecmd->base.duplex != DUPLEX_HALF &&
-	    ecmd->base.duplex != DUPLEX_FULL)
-		return -EINVAL;
-	if (ecmd->base.port != PORT_TP && ecmd->base.port != PORT_AUI)
-		return -EINVAL;
-
-	if (ecmd->base.port == PORT_AUI)
-		smc_set_xcvr(dev, 1);
-	else
-		smc_set_xcvr(dev, 0);
-
-	SMC_SELECT_BANK(0);
-	tmp = inw(ioaddr + TCR);
-	if (ecmd->base.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)
-{
-	strscpy(info->driver, DRV_NAME, sizeof(info->driver));
-	strscpy(info->version, DRV_VERSION, sizeof(info->version));
-}
-
-static int smc_get_link_ksettings(struct net_device *dev,
-				  struct ethtool_link_ksettings *ecmd)
-{
-	struct smc_private *smc = netdev_priv(dev);
-	unsigned int ioaddr = dev->base_addr;
-	u16 saved_bank = inw(ioaddr + BANK_SELECT);
-	unsigned long flags;
-
-	spin_lock_irqsave(&smc->lock, flags);
-	SMC_SELECT_BANK(3);
-	if (smc->cfg & CFG_MII_SELECT)
-		mii_ethtool_get_link_ksettings(&smc->mii_if, ecmd);
-	else
-		smc_netdev_get_ecmd(dev, ecmd);
-	SMC_SELECT_BANK(saved_bank);
-	spin_unlock_irqrestore(&smc->lock, flags);
-	return 0;
-}
-
-static int smc_set_link_ksettings(struct net_device *dev,
-				  const struct ethtool_link_ksettings *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_set_link_ksettings(&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_link = smc_get_link,
-	.nway_reset = smc_nway_reset,
-	.get_link_ksettings = smc_get_link_ksettings,
-	.set_link_ksettings = smc_set_link_ksettings,
-};
-
-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,
-};
-module_pcmcia_driver(smc91c92_cs_driver);

-- 
2.53.0


^ permalink raw reply related	[flat|nested] 28+ messages in thread

* [PATCH net 11/18] drivers: net: cirrus: cs89x0: Remove this driver
  2026-04-21 19:31 [PATCH net 00/18] Remove a number of ISA and PCMCIA Ethernet drivers Andrew Lunn
                   ` (9 preceding siblings ...)
  2026-04-21 19:31 ` [PATCH net 10/18] drivers: net: smsc: smc91c92: " Andrew Lunn
@ 2026-04-21 19:31 ` Andrew Lunn
  2026-04-21 19:31 ` [PATCH net 12/18] drivers: net: cirrus: mac89x0: " Andrew Lunn
                   ` (10 subsequent siblings)
  21 siblings, 0 replies; 28+ messages in thread
From: Andrew Lunn @ 2026-04-21 19:31 UTC (permalink / raw)
  To: Andrew Lunn, David S. Miller, Eric Dumazet, Jakub Kicinski,
	Paolo Abeni, Simon Horman, Jonathan Corbet, Shuah Khan
  Cc: linux-kernel, netdev, linux-doc, Andrew Lunn

The cs89x0 was written by Bonald Becker 1993 to 1994. It is an ISA
device, so unlikely to be used with modern kernels.

Signed-off-by: Andrew Lunn <andrew@lunn.ch>
---
 drivers/net/ethernet/cirrus/Kconfig  |   30 -
 drivers/net/ethernet/cirrus/Makefile |    1 -
 drivers/net/ethernet/cirrus/cs89x0.c | 1915 ----------------------------------
 3 files changed, 1946 deletions(-)

diff --git a/drivers/net/ethernet/cirrus/Kconfig b/drivers/net/ethernet/cirrus/Kconfig
index 5bdf731d9503..1a0c7b3bfcd6 100644
--- a/drivers/net/ethernet/cirrus/Kconfig
+++ b/drivers/net/ethernet/cirrus/Kconfig
@@ -17,36 +17,6 @@ config NET_VENDOR_CIRRUS
 
 if NET_VENDOR_CIRRUS
 
-config CS89x0
-	tristate
-
-config CS89x0_ISA
-	tristate "CS89x0 ISA driver support"
-	depends on HAS_IOPORT_MAP
-	depends on ISA
-	depends on !PPC32
-	depends on CS89x0_PLATFORM=n
-	select NETDEV_LEGACY_INIT
-	select CS89x0
-	help
-	  Support for CS89x0 chipset based Ethernet cards. If you have a
-	  network (Ethernet) card of this type, say Y and read the file
-	  <file:Documentation/networking/device_drivers/ethernet/cirrus/cs89x0.rst>.
-
-	  To compile this driver as a module, choose M here. The module
-	  will be called cs89x0.
-
-config CS89x0_PLATFORM
-	tristate "CS89x0 platform driver support"
-	depends on ARM || (COMPILE_TEST && !PPC)
-	select CS89x0
-	help
-	  Say Y to compile the cs89x0 platform driver. This makes this driver
-	  suitable for use on certain evaluation boards such as the iMX21ADS.
-
-	  To compile this driver as a module, choose M here. The module
-	  will be called cs89x0.
-
 config EP93XX_ETH
 	tristate "EP93xx Ethernet support"
 	depends on (ARM && ARCH_EP93XX) || COMPILE_TEST
diff --git a/drivers/net/ethernet/cirrus/Makefile b/drivers/net/ethernet/cirrus/Makefile
index 84865e593788..cb740939d976 100644
--- a/drivers/net/ethernet/cirrus/Makefile
+++ b/drivers/net/ethernet/cirrus/Makefile
@@ -3,6 +3,5 @@
 # Makefile for the Cirrus network device drivers.
 #
 
-obj-$(CONFIG_CS89x0) += cs89x0.o
 obj-$(CONFIG_EP93XX_ETH) += ep93xx_eth.o
 obj-$(CONFIG_MAC89x0) += mac89x0.o
diff --git a/drivers/net/ethernet/cirrus/cs89x0.c b/drivers/net/ethernet/cirrus/cs89x0.c
deleted file mode 100644
index fa5857923db4..000000000000
--- a/drivers/net/ethernet/cirrus/cs89x0.c
+++ /dev/null
@@ -1,1915 +0,0 @@
-/* cs89x0.c: A Crystal Semiconductor (Now Cirrus Logic) CS89[02]0
- *           driver for linux.
- * Written 1996 by Russell Nelson, with reference to skeleton.c
- * written 1993-1994 by Donald Becker.
- *
- * This software may be used and distributed according to the terms
- * of the GNU General Public License, incorporated herein by reference.
- *
- * The author may be reached at nelson@crynwr.com, Crynwr
- * Software, 521 Pleasant Valley Rd., Potsdam, NY 13676
- *
- * Other contributors:
- * Mike Cruse        : mcruse@cti-ltd.com
- * Russ Nelson
- * Melody Lee        : ethernet@crystal.cirrus.com
- * Alan Cox
- * Andrew Morton
- * Oskar Schirmer    : oskar@scara.com
- * Deepak Saxena     : dsaxena@plexity.net
- * Dmitry Pervushin  : dpervushin@ru.mvista.com
- * Deepak Saxena     : dsaxena@plexity.net
- * Domenico Andreoli : cavokz@gmail.com
- */
-
-
-/*
- * Set this to zero to disable DMA code
- *
- * Note that even if DMA is turned off we still support the 'dma' and  'use_dma'
- * module options so we don't break any startup scripts.
- */
-#ifndef CONFIG_ISA_DMA_API
-#define ALLOW_DMA	0
-#else
-#define ALLOW_DMA	1
-#endif
-
-/*
- * Set this to zero to remove all the debug statements via
- * dead code elimination
- */
-#define DEBUGGING	1
-
-/* Sources:
- *	Crynwr packet driver epktisa.
- *	Crystal Semiconductor data sheets.
- */
-
-#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
-
-#include <linux/module.h>
-#include <linux/printk.h>
-#include <linux/errno.h>
-#include <linux/netdevice.h>
-#include <linux/etherdevice.h>
-#include <linux/of.h>
-#include <linux/platform_device.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/jiffies.h>
-#include <linux/skbuff.h>
-#include <linux/spinlock.h>
-#include <linux/string.h>
-#include <linux/init.h>
-#include <linux/bitops.h>
-#include <linux/delay.h>
-#include <linux/gfp.h>
-#include <linux/io.h>
-
-#include <net/Space.h>
-
-#include <asm/irq.h>
-#include <linux/atomic.h>
-#if ALLOW_DMA
-#include <asm/dma.h>
-#endif
-
-#include "cs89x0.h"
-
-#define cs89_dbg(val, level, fmt, ...)				\
-do {								\
-	if (val <= net_debug)					\
-		pr_##level(fmt, ##__VA_ARGS__);			\
-} while (0)
-
-static char version[] __initdata =
-	"v2.4.3-pre1 Russell Nelson <nelson@crynwr.com>, Andrew Morton";
-
-#define DRV_NAME "cs89x0"
-
-/* First, a few definitions that the brave might change.
- * A zero-terminated list of I/O addresses to be probed. Some special flags..
- * Addr & 1 = Read back the address port, look for signature and reset
- * the page window before probing
- * Addr & 3 = Reset the page window and probe
- * The CLPS eval board has the Cirrus chip at 0x80090300, in ARM IO space,
- * but it is possible that a Cirrus board could be plugged into the ISA
- * slots.
- */
-/* The cs8900 has 4 IRQ pins, software selectable. cs8900_irq_map maps
- * them to system IRQ numbers. This mapping is card specific and is set to
- * the configuration of the Cirrus Eval board for this chip.
- */
-#if IS_ENABLED(CONFIG_CS89x0_ISA)
-static unsigned int netcard_portlist[] __used __initdata = {
-	0x300, 0x320, 0x340, 0x360, 0x200, 0x220, 0x240,
-	0x260, 0x280, 0x2a0, 0x2c0, 0x2e0, 0
-};
-static unsigned int cs8900_irq_map[] = {
-	10, 11, 12, 5
-};
-#endif
-
-#if DEBUGGING
-static unsigned int net_debug = DEBUGGING;
-#else
-#define net_debug 0	/* gcc will remove all the debug code for us */
-#endif
-
-/* The number of low I/O ports used by the ethercard. */
-#define NETCARD_IO_EXTENT	16
-
-/* we allow the user to override various values normally set in the EEPROM */
-#define FORCE_RJ45	0x0001    /* pick one of these three */
-#define FORCE_AUI	0x0002
-#define FORCE_BNC	0x0004
-
-#define FORCE_AUTO	0x0010    /* pick one of these three */
-#define FORCE_HALF	0x0020
-#define FORCE_FULL	0x0030
-
-/* Information that need to be kept for each board. */
-struct net_local {
-	int chip_type;		/* one of: CS8900, CS8920, CS8920M */
-	char chip_revision;	/* revision letter of the chip ('A'...) */
-	int send_cmd;		/* the proper send command: TX_NOW, TX_AFTER_381, or TX_AFTER_ALL */
-	int auto_neg_cnf;	/* auto-negotiation word from EEPROM */
-	int adapter_cnf;	/* adapter configuration from EEPROM */
-	int isa_config;		/* ISA configuration from EEPROM */
-	int irq_map;		/* IRQ map from EEPROM */
-	int rx_mode;		/* what mode are we in? 0, RX_MULTCAST_ACCEPT, or RX_ALL_ACCEPT */
-	int curr_rx_cfg;	/* a copy of PP_RxCFG */
-	int linectl;		/* either 0 or LOW_RX_SQUELCH, depending on configuration. */
-	int send_underrun;	/* keep track of how many underruns in a row we get */
-	int force;		/* force various values; see FORCE* above. */
-	spinlock_t lock;
-	void __iomem *virt_addr;/* CS89x0 virtual address. */
-#if ALLOW_DMA
-	int use_dma;		/* Flag: we're using dma */
-	int dma;		/* DMA channel */
-	int dmasize;		/* 16 or 64 */
-	unsigned char *dma_buff;	/* points to the beginning of the buffer */
-	unsigned char *end_dma_buff;	/* points to the end of the buffer */
-	unsigned char *rx_dma_ptr;	/* points to the next packet  */
-#endif
-};
-
-/* Example routines you must write ;->. */
-#define tx_done(dev) 1
-
-/*
- * Permit 'cs89x0_dma=N' in the kernel boot environment
- */
-#if !defined(MODULE)
-#if ALLOW_DMA
-static int g_cs89x0_dma;
-
-static int __init dma_fn(char *str)
-{
-	g_cs89x0_dma = simple_strtol(str, NULL, 0);
-	return 1;
-}
-
-__setup("cs89x0_dma=", dma_fn);
-#endif	/* ALLOW_DMA */
-
-static int g_cs89x0_media__force;
-
-static int __init media_fn(char *str)
-{
-	if (!strcmp(str, "rj45"))
-		g_cs89x0_media__force = FORCE_RJ45;
-	else if (!strcmp(str, "aui"))
-		g_cs89x0_media__force = FORCE_AUI;
-	else if (!strcmp(str, "bnc"))
-		g_cs89x0_media__force = FORCE_BNC;
-
-	return 1;
-}
-
-__setup("cs89x0_media=", media_fn);
-#endif
-
-static void readwords(struct net_local *lp, int portno, void *buf, int length)
-{
-	u8 *buf8 = (u8 *)buf;
-
-	do {
-		u16 tmp16;
-
-		tmp16 = ioread16(lp->virt_addr + portno);
-		*buf8++ = (u8)tmp16;
-		*buf8++ = (u8)(tmp16 >> 8);
-	} while (--length);
-}
-
-static void writewords(struct net_local *lp, int portno, void *buf, int length)
-{
-	u8 *buf8 = (u8 *)buf;
-
-	do {
-		u16 tmp16;
-
-		tmp16 = *buf8++;
-		tmp16 |= (*buf8++) << 8;
-		iowrite16(tmp16, lp->virt_addr + portno);
-	} while (--length);
-}
-
-static u16
-readreg(struct net_device *dev, u16 regno)
-{
-	struct net_local *lp = netdev_priv(dev);
-
-	iowrite16(regno, lp->virt_addr + ADD_PORT);
-	return ioread16(lp->virt_addr + DATA_PORT);
-}
-
-static void
-writereg(struct net_device *dev, u16 regno, u16 value)
-{
-	struct net_local *lp = netdev_priv(dev);
-
-	iowrite16(regno, lp->virt_addr + ADD_PORT);
-	iowrite16(value, lp->virt_addr + DATA_PORT);
-}
-
-static int __init
-wait_eeprom_ready(struct net_device *dev)
-{
-	unsigned long timeout = jiffies;
-	/* check to see if the EEPROM is ready,
-	 * a timeout is used just in case EEPROM is ready when
-	 * SI_BUSY in the PP_SelfST is clear
-	 */
-	while (readreg(dev, PP_SelfST) & SI_BUSY)
-		if (time_after_eq(jiffies, timeout + 40))
-			return -1;
-	return 0;
-}
-
-static int __init
-get_eeprom_data(struct net_device *dev, int off, int len, int *buffer)
-{
-	int i;
-
-	cs89_dbg(3, info, "EEPROM data from %x for %x:", off, len);
-	for (i = 0; i < len; i++) {
-		if (wait_eeprom_ready(dev) < 0)
-			return -1;
-		/* Now send the EEPROM read command and EEPROM location to read */
-		writereg(dev, PP_EECMD, (off + i) | EEPROM_READ_CMD);
-		if (wait_eeprom_ready(dev) < 0)
-			return -1;
-		buffer[i] = readreg(dev, PP_EEData);
-		cs89_dbg(3, cont, " %04x", buffer[i]);
-	}
-	cs89_dbg(3, cont, "\n");
-	return 0;
-}
-
-static int  __init
-get_eeprom_cksum(int off, int len, int *buffer)
-{
-	int i, cksum;
-
-	cksum = 0;
-	for (i = 0; i < len; i++)
-		cksum += buffer[i];
-	cksum &= 0xffff;
-	if (cksum == 0)
-		return 0;
-	return -1;
-}
-
-static void
-write_irq(struct net_device *dev, int chip_type, int irq)
-{
-	int i;
-
-	if (chip_type == CS8900) {
-#if IS_ENABLED(CONFIG_CS89x0_ISA)
-		/* Search the mapping table for the corresponding IRQ pin. */
-		for (i = 0; i != ARRAY_SIZE(cs8900_irq_map); i++)
-			if (cs8900_irq_map[i] == irq)
-				break;
-		/* Not found */
-		if (i == ARRAY_SIZE(cs8900_irq_map))
-			i = 3;
-#else
-		/* INTRQ0 pin is used for interrupt generation. */
-		i = 0;
-#endif
-		writereg(dev, PP_CS8900_ISAINT, i);
-	} else {
-		writereg(dev, PP_CS8920_ISAINT, irq);
-	}
-}
-
-static void
-count_rx_errors(int status, struct net_device *dev)
-{
-	dev->stats.rx_errors++;
-	if (status & RX_RUNT)
-		dev->stats.rx_length_errors++;
-	if (status & RX_EXTRA_DATA)
-		dev->stats.rx_length_errors++;
-	if ((status & RX_CRC_ERROR) && !(status & (RX_EXTRA_DATA | RX_RUNT)))
-		/* per str 172 */
-		dev->stats.rx_crc_errors++;
-	if (status & RX_DRIBBLE)
-		dev->stats.rx_frame_errors++;
-}
-
-/*********************************
- * This page contains DMA routines
- *********************************/
-
-#if ALLOW_DMA
-
-#define dma_page_eq(ptr1, ptr2) ((long)(ptr1) >> 17 == (long)(ptr2) >> 17)
-
-static void
-get_dma_channel(struct net_device *dev)
-{
-	struct net_local *lp = netdev_priv(dev);
-
-	if (lp->dma) {
-		dev->dma = lp->dma;
-		lp->isa_config |= ISA_RxDMA;
-	} else {
-		if ((lp->isa_config & ANY_ISA_DMA) == 0)
-			return;
-		dev->dma = lp->isa_config & DMA_NO_MASK;
-		if (lp->chip_type == CS8900)
-			dev->dma += 5;
-		if (dev->dma < 5 || dev->dma > 7) {
-			lp->isa_config &= ~ANY_ISA_DMA;
-			return;
-		}
-	}
-}
-
-static void
-write_dma(struct net_device *dev, int chip_type, int dma)
-{
-	struct net_local *lp = netdev_priv(dev);
-	if ((lp->isa_config & ANY_ISA_DMA) == 0)
-		return;
-	if (chip_type == CS8900)
-		writereg(dev, PP_CS8900_ISADMA, dma - 5);
-	else
-		writereg(dev, PP_CS8920_ISADMA, dma);
-}
-
-static void
-set_dma_cfg(struct net_device *dev)
-{
-	struct net_local *lp = netdev_priv(dev);
-
-	if (lp->use_dma) {
-		if ((lp->isa_config & ANY_ISA_DMA) == 0) {
-			cs89_dbg(3, err, "set_dma_cfg(): no DMA\n");
-			return;
-		}
-		if (lp->isa_config & ISA_RxDMA) {
-			lp->curr_rx_cfg |= RX_DMA_ONLY;
-			cs89_dbg(3, info, "set_dma_cfg(): RX_DMA_ONLY\n");
-		} else {
-			lp->curr_rx_cfg |= AUTO_RX_DMA;	/* not that we support it... */
-			cs89_dbg(3, info, "set_dma_cfg(): AUTO_RX_DMA\n");
-		}
-	}
-}
-
-static int
-dma_bufcfg(struct net_device *dev)
-{
-	struct net_local *lp = netdev_priv(dev);
-	if (lp->use_dma)
-		return (lp->isa_config & ANY_ISA_DMA) ? RX_DMA_ENBL : 0;
-	else
-		return 0;
-}
-
-static int
-dma_busctl(struct net_device *dev)
-{
-	int retval = 0;
-	struct net_local *lp = netdev_priv(dev);
-	if (lp->use_dma) {
-		if (lp->isa_config & ANY_ISA_DMA)
-			retval |= RESET_RX_DMA; /* Reset the DMA pointer */
-		if (lp->isa_config & DMA_BURST)
-			retval |= DMA_BURST_MODE; /* Does ISA config specify DMA burst ? */
-		if (lp->dmasize == 64)
-			retval |= RX_DMA_SIZE_64K; /* did they ask for 64K? */
-		retval |= MEMORY_ON;	/* we need memory enabled to use DMA. */
-	}
-	return retval;
-}
-
-static void
-dma_rx(struct net_device *dev)
-{
-	struct net_local *lp = netdev_priv(dev);
-	struct sk_buff *skb;
-	int status, length;
-	unsigned char *bp = lp->rx_dma_ptr;
-
-	status = bp[0] + (bp[1] << 8);
-	length = bp[2] + (bp[3] << 8);
-	bp += 4;
-
-	cs89_dbg(5, debug, "%s: receiving DMA packet at %lx, status %x, length %x\n",
-		 dev->name, (unsigned long)bp, status, length);
-
-	if ((status & RX_OK) == 0) {
-		count_rx_errors(status, dev);
-		goto skip_this_frame;
-	}
-
-	/* Malloc up new buffer. */
-	skb = netdev_alloc_skb(dev, length + 2);
-	if (skb == NULL) {
-		dev->stats.rx_dropped++;
-
-		/* AKPM: advance bp to the next frame */
-skip_this_frame:
-		bp += (length + 3) & ~3;
-		if (bp >= lp->end_dma_buff)
-			bp -= lp->dmasize * 1024;
-		lp->rx_dma_ptr = bp;
-		return;
-	}
-	skb_reserve(skb, 2);	/* longword align L3 header */
-
-	if (bp + length > lp->end_dma_buff) {
-		int semi_cnt = lp->end_dma_buff - bp;
-		skb_put_data(skb, bp, semi_cnt);
-		skb_put_data(skb, lp->dma_buff, length - semi_cnt);
-	} else {
-		skb_put_data(skb, bp, length);
-	}
-	bp += (length + 3) & ~3;
-	if (bp >= lp->end_dma_buff)
-		bp -= lp->dmasize*1024;
-	lp->rx_dma_ptr = bp;
-
-	cs89_dbg(3, info, "%s: received %d byte DMA packet of type %x\n",
-		 dev->name, length,
-		 ((skb->data[ETH_ALEN + ETH_ALEN] << 8) |
-		  skb->data[ETH_ALEN + ETH_ALEN + 1]));
-
-	skb->protocol = eth_type_trans(skb, dev);
-	netif_rx(skb);
-	dev->stats.rx_packets++;
-	dev->stats.rx_bytes += length;
-}
-
-static void release_dma_buff(struct net_local *lp)
-{
-	if (lp->dma_buff) {
-		free_pages((unsigned long)(lp->dma_buff),
-			   get_order(lp->dmasize * 1024));
-		lp->dma_buff = NULL;
-	}
-}
-
-#endif	/* ALLOW_DMA */
-
-static void
-control_dc_dc(struct net_device *dev, int on_not_off)
-{
-	struct net_local *lp = netdev_priv(dev);
-	unsigned int selfcontrol;
-	unsigned long timenow = jiffies;
-	/* control the DC to DC convertor in the SelfControl register.
-	 * Note: This is hooked up to a general purpose pin, might not
-	 * always be a DC to DC convertor.
-	 */
-
-	selfcontrol = HCB1_ENBL; /* Enable the HCB1 bit as an output */
-	if (((lp->adapter_cnf & A_CNF_DC_DC_POLARITY) != 0) ^ on_not_off)
-		selfcontrol |= HCB1;
-	else
-		selfcontrol &= ~HCB1;
-	writereg(dev, PP_SelfCTL, selfcontrol);
-
-	/* Wait for the DC/DC converter to power up - 500ms */
-	while (time_before(jiffies, timenow + HZ))
-		;
-}
-
-/* send a test packet - return true if carrier bits are ok */
-static int
-send_test_pkt(struct net_device *dev)
-{
-	struct net_local *lp = netdev_priv(dev);
-	char test_packet[] = {
-		0, 0, 0, 0, 0, 0,  0, 0, 0, 0, 0, 0,
-		0, 46,		/* A 46 in network order */
-		0, 0,		/* DSAP=0 & SSAP=0 fields */
-		0xf3, 0		/* Control (Test Req + P bit set) */
-	};
-	unsigned long timenow = jiffies;
-
-	writereg(dev, PP_LineCTL, readreg(dev, PP_LineCTL) | SERIAL_TX_ON);
-
-	memcpy(test_packet,            dev->dev_addr, ETH_ALEN);
-	memcpy(test_packet + ETH_ALEN, dev->dev_addr, ETH_ALEN);
-
-	iowrite16(TX_AFTER_ALL, lp->virt_addr + TX_CMD_PORT);
-	iowrite16(ETH_ZLEN, lp->virt_addr + TX_LEN_PORT);
-
-	/* Test to see if the chip has allocated memory for the packet */
-	while (time_before(jiffies, timenow + 5))
-		if (readreg(dev, PP_BusST) & READY_FOR_TX_NOW)
-			break;
-	if (time_after_eq(jiffies, timenow + 5))
-		return 0;	/* this shouldn't happen */
-
-	/* Write the contents of the packet */
-	writewords(lp, TX_FRAME_PORT, test_packet, (ETH_ZLEN + 1) >> 1);
-
-	cs89_dbg(1, debug, "Sending test packet ");
-	/* wait a couple of jiffies for packet to be received */
-	for (timenow = jiffies; time_before(jiffies, timenow + 3);)
-		;
-	if ((readreg(dev, PP_TxEvent) & TX_SEND_OK_BITS) == TX_OK) {
-		cs89_dbg(1, cont, "succeeded\n");
-		return 1;
-	}
-	cs89_dbg(1, cont, "failed\n");
-	return 0;
-}
-
-#define DETECTED_NONE  0
-#define DETECTED_RJ45H 1
-#define DETECTED_RJ45F 2
-#define DETECTED_AUI   3
-#define DETECTED_BNC   4
-
-static int
-detect_tp(struct net_device *dev)
-{
-	struct net_local *lp = netdev_priv(dev);
-	unsigned long timenow = jiffies;
-	int fdx;
-
-	cs89_dbg(1, debug, "%s: Attempting TP\n", dev->name);
-
-	/* If connected to another full duplex capable 10-Base-T card
-	 * the link pulses seem to be lost when the auto detect bit in
-	 * the LineCTL is set.  To overcome this the auto detect bit will
-	 * be cleared whilst testing the 10-Base-T interface.  This would
-	 * not be necessary for the sparrow chip but is simpler to do it
-	 * anyway.
-	 */
-	writereg(dev, PP_LineCTL, lp->linectl & ~AUI_ONLY);
-	control_dc_dc(dev, 0);
-
-	/* Delay for the hardware to work out if the TP cable is present
-	 * - 150ms
-	 */
-	for (timenow = jiffies; time_before(jiffies, timenow + 15);)
-		;
-	if ((readreg(dev, PP_LineST) & LINK_OK) == 0)
-		return DETECTED_NONE;
-
-	if (lp->chip_type == CS8900) {
-		switch (lp->force & 0xf0) {
-#if 0
-		case FORCE_AUTO:
-			pr_info("%s: cs8900 doesn't autonegotiate\n",
-				dev->name);
-			return DETECTED_NONE;
-#endif
-			/* CS8900 doesn't support AUTO, change to HALF*/
-		case FORCE_AUTO:
-			lp->force &= ~FORCE_AUTO;
-			lp->force |= FORCE_HALF;
-			break;
-		case FORCE_HALF:
-			break;
-		case FORCE_FULL:
-			writereg(dev, PP_TestCTL,
-				 readreg(dev, PP_TestCTL) | FDX_8900);
-			break;
-		}
-		fdx = readreg(dev, PP_TestCTL) & FDX_8900;
-	} else {
-		switch (lp->force & 0xf0) {
-		case FORCE_AUTO:
-			lp->auto_neg_cnf = AUTO_NEG_ENABLE;
-			break;
-		case FORCE_HALF:
-			lp->auto_neg_cnf = 0;
-			break;
-		case FORCE_FULL:
-			lp->auto_neg_cnf = RE_NEG_NOW | ALLOW_FDX;
-			break;
-		}
-
-		writereg(dev, PP_AutoNegCTL, lp->auto_neg_cnf & AUTO_NEG_MASK);
-
-		if ((lp->auto_neg_cnf & AUTO_NEG_BITS) == AUTO_NEG_ENABLE) {
-			pr_info("%s: negotiating duplex...\n", dev->name);
-			while (readreg(dev, PP_AutoNegST) & AUTO_NEG_BUSY) {
-				if (time_after(jiffies, timenow + 4000)) {
-					pr_err("**** Full / half duplex auto-negotiation timed out ****\n");
-					break;
-				}
-			}
-		}
-		fdx = readreg(dev, PP_AutoNegST) & FDX_ACTIVE;
-	}
-	if (fdx)
-		return DETECTED_RJ45F;
-	else
-		return DETECTED_RJ45H;
-}
-
-static int
-detect_bnc(struct net_device *dev)
-{
-	struct net_local *lp = netdev_priv(dev);
-
-	cs89_dbg(1, debug, "%s: Attempting BNC\n", dev->name);
-	control_dc_dc(dev, 1);
-
-	writereg(dev, PP_LineCTL, (lp->linectl & ~AUTO_AUI_10BASET) | AUI_ONLY);
-
-	if (send_test_pkt(dev))
-		return DETECTED_BNC;
-	else
-		return DETECTED_NONE;
-}
-
-static int
-detect_aui(struct net_device *dev)
-{
-	struct net_local *lp = netdev_priv(dev);
-
-	cs89_dbg(1, debug, "%s: Attempting AUI\n", dev->name);
-	control_dc_dc(dev, 0);
-
-	writereg(dev, PP_LineCTL, (lp->linectl & ~AUTO_AUI_10BASET) | AUI_ONLY);
-
-	if (send_test_pkt(dev))
-		return DETECTED_AUI;
-	else
-		return DETECTED_NONE;
-}
-
-/* We have a good packet(s), get it/them out of the buffers. */
-static void
-net_rx(struct net_device *dev)
-{
-	struct net_local *lp = netdev_priv(dev);
-	struct sk_buff *skb;
-	int status, length;
-
-	status = ioread16(lp->virt_addr + RX_FRAME_PORT);
-	length = ioread16(lp->virt_addr + RX_FRAME_PORT);
-
-	if ((status & RX_OK) == 0) {
-		count_rx_errors(status, dev);
-		return;
-	}
-
-	/* Malloc up new buffer. */
-	skb = netdev_alloc_skb(dev, length + 2);
-	if (skb == NULL) {
-		dev->stats.rx_dropped++;
-		return;
-	}
-	skb_reserve(skb, 2);	/* longword align L3 header */
-
-	readwords(lp, RX_FRAME_PORT, skb_put(skb, length), length >> 1);
-	if (length & 1)
-		skb->data[length-1] = ioread16(lp->virt_addr + RX_FRAME_PORT);
-
-	cs89_dbg(3, debug, "%s: received %d byte packet of type %x\n",
-		 dev->name, length,
-		 (skb->data[ETH_ALEN + ETH_ALEN] << 8) |
-		 skb->data[ETH_ALEN + ETH_ALEN + 1]);
-
-	skb->protocol = eth_type_trans(skb, dev);
-	netif_rx(skb);
-	dev->stats.rx_packets++;
-	dev->stats.rx_bytes += length;
-}
-
-/* The typical workload of the driver:
- * Handle the network interface interrupts.
- */
-
-static irqreturn_t net_interrupt(int irq, void *dev_id)
-{
-	struct net_device *dev = dev_id;
-	struct net_local *lp;
-	int status;
-	int handled = 0;
-
-	lp = netdev_priv(dev);
-
-	/* we MUST read all the events out of the ISQ, otherwise we'll never
-	 * get interrupted again.  As a consequence, we can't have any limit
-	 * on the number of times we loop in the interrupt handler.  The
-	 * hardware guarantees that eventually we'll run out of events.  Of
-	 * course, if you're on a slow machine, and packets are arriving
-	 * faster than you can read them off, you're screwed.  Hasta la
-	 * vista, baby!
-	 */
-	while ((status = ioread16(lp->virt_addr + ISQ_PORT))) {
-		cs89_dbg(4, debug, "%s: event=%04x\n", dev->name, status);
-		handled = 1;
-		switch (status & ISQ_EVENT_MASK) {
-		case ISQ_RECEIVER_EVENT:
-			/* Got a packet(s). */
-			net_rx(dev);
-			break;
-		case ISQ_TRANSMITTER_EVENT:
-			dev->stats.tx_packets++;
-			netif_wake_queue(dev);	/* Inform upper layers. */
-			if ((status & (TX_OK |
-				       TX_LOST_CRS |
-				       TX_SQE_ERROR |
-				       TX_LATE_COL |
-				       TX_16_COL)) != TX_OK) {
-				if ((status & TX_OK) == 0)
-					dev->stats.tx_errors++;
-				if (status & TX_LOST_CRS)
-					dev->stats.tx_carrier_errors++;
-				if (status & TX_SQE_ERROR)
-					dev->stats.tx_heartbeat_errors++;
-				if (status & TX_LATE_COL)
-					dev->stats.tx_window_errors++;
-				if (status & TX_16_COL)
-					dev->stats.tx_aborted_errors++;
-			}
-			break;
-		case ISQ_BUFFER_EVENT:
-			if (status & READY_FOR_TX) {
-				/* we tried to transmit a packet earlier,
-				 * but inexplicably ran out of buffers.
-				 * That shouldn't happen since we only ever
-				 * load one packet.  Shrug.  Do the right
-				 * thing anyway.
-				 */
-				netif_wake_queue(dev);	/* Inform upper layers. */
-			}
-			if (status & TX_UNDERRUN) {
-				cs89_dbg(0, err, "%s: transmit underrun\n",
-					 dev->name);
-				lp->send_underrun++;
-				if (lp->send_underrun == 3)
-					lp->send_cmd = TX_AFTER_381;
-				else if (lp->send_underrun == 6)
-					lp->send_cmd = TX_AFTER_ALL;
-				/* transmit cycle is done, although
-				 * frame wasn't transmitted - this
-				 * avoids having to wait for the upper
-				 * layers to timeout on us, in the
-				 * event of a tx underrun
-				 */
-				netif_wake_queue(dev);	/* Inform upper layers. */
-			}
-#if ALLOW_DMA
-			if (lp->use_dma && (status & RX_DMA)) {
-				int count = readreg(dev, PP_DmaFrameCnt);
-				while (count) {
-					cs89_dbg(5, debug,
-						 "%s: receiving %d DMA frames\n",
-						 dev->name, count);
-					if (count > 1)
-						cs89_dbg(2, debug,
-							 "%s: receiving %d DMA frames\n",
-							 dev->name, count);
-					dma_rx(dev);
-					if (--count == 0)
-						count = readreg(dev, PP_DmaFrameCnt);
-					if (count > 0)
-						cs89_dbg(2, debug,
-							 "%s: continuing with %d DMA frames\n",
-							 dev->name, count);
-				}
-			}
-#endif
-			break;
-		case ISQ_RX_MISS_EVENT:
-			dev->stats.rx_missed_errors += (status >> 6);
-			break;
-		case ISQ_TX_COL_EVENT:
-			dev->stats.collisions += (status >> 6);
-			break;
-		}
-	}
-	return IRQ_RETVAL(handled);
-}
-
-/* Open/initialize the board.  This is called (in the current kernel)
-   sometime after booting when the 'ifconfig' program is run.
-
-   This routine should set everything up anew at each open, even
-   registers that "should" only need to be set once at boot, so that
-   there is non-reboot way to recover if something goes wrong.
-*/
-
-/* AKPM: do we need to do any locking here? */
-
-static int
-net_open(struct net_device *dev)
-{
-	struct net_local *lp = netdev_priv(dev);
-	int result = 0;
-	int i;
-	int ret;
-
-	if (dev->irq < 2) {
-		/* Allow interrupts to be generated by the chip */
-/* Cirrus' release had this: */
-#if 0
-		writereg(dev, PP_BusCTL, readreg(dev, PP_BusCTL) | ENABLE_IRQ);
-#endif
-/* And 2.3.47 had this: */
-		writereg(dev, PP_BusCTL, ENABLE_IRQ | MEMORY_ON);
-
-		for (i = 2; i < CS8920_NO_INTS; i++) {
-			if ((1 << i) & lp->irq_map) {
-				if (request_irq(i, net_interrupt, 0, dev->name,
-						dev) == 0) {
-					dev->irq = i;
-					write_irq(dev, lp->chip_type, i);
-					/* writereg(dev, PP_BufCFG, GENERATE_SW_INTERRUPT); */
-					break;
-				}
-			}
-		}
-
-		if (i >= CS8920_NO_INTS) {
-			writereg(dev, PP_BusCTL, 0);	/* disable interrupts. */
-			pr_err("can't get an interrupt\n");
-			ret = -EAGAIN;
-			goto bad_out;
-		}
-	} else {
-#if IS_ENABLED(CONFIG_CS89x0_ISA)
-		if (((1 << dev->irq) & lp->irq_map) == 0) {
-			pr_err("%s: IRQ %d is not in our map of allowable IRQs, which is %x\n",
-			       dev->name, dev->irq, lp->irq_map);
-			ret = -EAGAIN;
-			goto bad_out;
-		}
-#endif
-/* FIXME: Cirrus' release had this: */
-		writereg(dev, PP_BusCTL, readreg(dev, PP_BusCTL)|ENABLE_IRQ);
-/* And 2.3.47 had this: */
-#if 0
-		writereg(dev, PP_BusCTL, ENABLE_IRQ | MEMORY_ON);
-#endif
-		write_irq(dev, lp->chip_type, dev->irq);
-		ret = request_irq(dev->irq, net_interrupt, 0, dev->name, dev);
-		if (ret) {
-			pr_err("request_irq(%d) failed\n", dev->irq);
-			goto bad_out;
-		}
-	}
-
-#if ALLOW_DMA
-	if (lp->use_dma && (lp->isa_config & ANY_ISA_DMA)) {
-		unsigned long flags;
-		lp->dma_buff = (unsigned char *)__get_dma_pages(GFP_KERNEL,
-								get_order(lp->dmasize * 1024));
-		if (!lp->dma_buff) {
-			pr_err("%s: cannot get %dK memory for DMA\n",
-			       dev->name, lp->dmasize);
-			goto release_irq;
-		}
-		cs89_dbg(1, debug, "%s: dma %lx %lx\n",
-			 dev->name,
-			 (unsigned long)lp->dma_buff,
-			 (unsigned long)isa_virt_to_bus(lp->dma_buff));
-		if ((unsigned long)lp->dma_buff >= MAX_DMA_ADDRESS ||
-		    !dma_page_eq(lp->dma_buff,
-				 lp->dma_buff + lp->dmasize * 1024 - 1)) {
-			pr_err("%s: not usable as DMA buffer\n", dev->name);
-			goto release_irq;
-		}
-		memset(lp->dma_buff, 0, lp->dmasize * 1024);	/* Why? */
-		if (request_dma(dev->dma, dev->name)) {
-			pr_err("%s: cannot get dma channel %d\n",
-			       dev->name, dev->dma);
-			goto release_irq;
-		}
-		write_dma(dev, lp->chip_type, dev->dma);
-		lp->rx_dma_ptr = lp->dma_buff;
-		lp->end_dma_buff = lp->dma_buff + lp->dmasize * 1024;
-		spin_lock_irqsave(&lp->lock, flags);
-		disable_dma(dev->dma);
-		clear_dma_ff(dev->dma);
-		set_dma_mode(dev->dma, DMA_RX_MODE); /* auto_init as well */
-		set_dma_addr(dev->dma, isa_virt_to_bus(lp->dma_buff));
-		set_dma_count(dev->dma, lp->dmasize * 1024);
-		enable_dma(dev->dma);
-		spin_unlock_irqrestore(&lp->lock, flags);
-	}
-#endif	/* ALLOW_DMA */
-
-	/* set the Ethernet address */
-	for (i = 0; i < ETH_ALEN / 2; i++)
-		writereg(dev, PP_IA + i * 2,
-			 (dev->dev_addr[i * 2] |
-			  (dev->dev_addr[i * 2 + 1] << 8)));
-
-	/* while we're testing the interface, leave interrupts disabled */
-	writereg(dev, PP_BusCTL, MEMORY_ON);
-
-	/* Set the LineCTL quintuplet based on adapter configuration read from EEPROM */
-	if ((lp->adapter_cnf & A_CNF_EXTND_10B_2) &&
-	    (lp->adapter_cnf & A_CNF_LOW_RX_SQUELCH))
-		lp->linectl = LOW_RX_SQUELCH;
-	else
-		lp->linectl = 0;
-
-	/* check to make sure that they have the "right" hardware available */
-	switch (lp->adapter_cnf & A_CNF_MEDIA_TYPE) {
-	case A_CNF_MEDIA_10B_T:
-		result = lp->adapter_cnf & A_CNF_10B_T;
-		break;
-	case A_CNF_MEDIA_AUI:
-		result = lp->adapter_cnf & A_CNF_AUI;
-		break;
-	case A_CNF_MEDIA_10B_2:
-		result = lp->adapter_cnf & A_CNF_10B_2;
-		break;
-	default:
-		result = lp->adapter_cnf & (A_CNF_10B_T |
-					    A_CNF_AUI |
-					    A_CNF_10B_2);
-	}
-	if (!result) {
-		pr_err("%s: EEPROM is configured for unavailable media\n",
-		       dev->name);
-release_dma:
-#if ALLOW_DMA
-		free_dma(dev->dma);
-release_irq:
-		release_dma_buff(lp);
-#endif
-		writereg(dev, PP_LineCTL,
-			 readreg(dev, PP_LineCTL) & ~(SERIAL_TX_ON | SERIAL_RX_ON));
-		free_irq(dev->irq, dev);
-		ret = -EAGAIN;
-		goto bad_out;
-	}
-
-	/* set the hardware to the configured choice */
-	switch (lp->adapter_cnf & A_CNF_MEDIA_TYPE) {
-	case A_CNF_MEDIA_10B_T:
-		result = detect_tp(dev);
-		if (result == DETECTED_NONE) {
-			pr_warn("%s: 10Base-T (RJ-45) has no cable\n",
-				dev->name);
-			if (lp->auto_neg_cnf & IMM_BIT) /* check "ignore missing media" bit */
-				result = DETECTED_RJ45H; /* Yes! I don't care if I see a link pulse */
-		}
-		break;
-	case A_CNF_MEDIA_AUI:
-		result = detect_aui(dev);
-		if (result == DETECTED_NONE) {
-			pr_warn("%s: 10Base-5 (AUI) has no cable\n", dev->name);
-			if (lp->auto_neg_cnf & IMM_BIT) /* check "ignore missing media" bit */
-				result = DETECTED_AUI; /* Yes! I don't care if I see a carrier */
-		}
-		break;
-	case A_CNF_MEDIA_10B_2:
-		result = detect_bnc(dev);
-		if (result == DETECTED_NONE) {
-			pr_warn("%s: 10Base-2 (BNC) has no cable\n", dev->name);
-			if (lp->auto_neg_cnf & IMM_BIT) /* check "ignore missing media" bit */
-				result = DETECTED_BNC; /* Yes! I don't care if I can xmit a packet */
-		}
-		break;
-	case A_CNF_MEDIA_AUTO:
-		writereg(dev, PP_LineCTL, lp->linectl | AUTO_AUI_10BASET);
-		if (lp->adapter_cnf & A_CNF_10B_T) {
-			result = detect_tp(dev);
-			if (result != DETECTED_NONE)
-				break;
-		}
-		if (lp->adapter_cnf & A_CNF_AUI) {
-			result = detect_aui(dev);
-			if (result != DETECTED_NONE)
-				break;
-		}
-		if (lp->adapter_cnf & A_CNF_10B_2) {
-			result = detect_bnc(dev);
-			if (result != DETECTED_NONE)
-				break;
-		}
-		pr_err("%s: no media detected\n", dev->name);
-		goto release_dma;
-	}
-	switch (result) {
-	case DETECTED_NONE:
-		pr_err("%s: no network cable attached to configured media\n",
-		       dev->name);
-		goto release_dma;
-	case DETECTED_RJ45H:
-		pr_info("%s: using half-duplex 10Base-T (RJ-45)\n", dev->name);
-		break;
-	case DETECTED_RJ45F:
-		pr_info("%s: using full-duplex 10Base-T (RJ-45)\n", dev->name);
-		break;
-	case DETECTED_AUI:
-		pr_info("%s: using 10Base-5 (AUI)\n", dev->name);
-		break;
-	case DETECTED_BNC:
-		pr_info("%s: using 10Base-2 (BNC)\n", dev->name);
-		break;
-	}
-
-	/* Turn on both receive and transmit operations */
-	writereg(dev, PP_LineCTL,
-		 readreg(dev, PP_LineCTL) | SERIAL_RX_ON | SERIAL_TX_ON);
-
-	/* Receive only error free packets addressed to this card */
-	lp->rx_mode = 0;
-	writereg(dev, PP_RxCTL, DEF_RX_ACCEPT);
-
-	lp->curr_rx_cfg = RX_OK_ENBL | RX_CRC_ERROR_ENBL;
-
-	if (lp->isa_config & STREAM_TRANSFER)
-		lp->curr_rx_cfg |= RX_STREAM_ENBL;
-#if ALLOW_DMA
-	set_dma_cfg(dev);
-#endif
-	writereg(dev, PP_RxCFG, lp->curr_rx_cfg);
-
-	writereg(dev, PP_TxCFG, (TX_LOST_CRS_ENBL |
-				 TX_SQE_ERROR_ENBL |
-				 TX_OK_ENBL |
-				 TX_LATE_COL_ENBL |
-				 TX_JBR_ENBL |
-				 TX_ANY_COL_ENBL |
-				 TX_16_COL_ENBL));
-
-	writereg(dev, PP_BufCFG, (READY_FOR_TX_ENBL |
-				  RX_MISS_COUNT_OVRFLOW_ENBL |
-#if ALLOW_DMA
-				  dma_bufcfg(dev) |
-#endif
-				  TX_COL_COUNT_OVRFLOW_ENBL |
-				  TX_UNDERRUN_ENBL));
-
-	/* now that we've got our act together, enable everything */
-	writereg(dev, PP_BusCTL, (ENABLE_IRQ
-				  | (dev->mem_start ? MEMORY_ON : 0) /* turn memory on */
-#if ALLOW_DMA
-				  | dma_busctl(dev)
-#endif
-			 ));
-	netif_start_queue(dev);
-	cs89_dbg(1, debug, "net_open() succeeded\n");
-	return 0;
-bad_out:
-	return ret;
-}
-
-/* The inverse routine to net_open(). */
-static int
-net_close(struct net_device *dev)
-{
-#if ALLOW_DMA
-	struct net_local *lp = netdev_priv(dev);
-#endif
-
-	netif_stop_queue(dev);
-
-	writereg(dev, PP_RxCFG, 0);
-	writereg(dev, PP_TxCFG, 0);
-	writereg(dev, PP_BufCFG, 0);
-	writereg(dev, PP_BusCTL, 0);
-
-	free_irq(dev->irq, dev);
-
-#if ALLOW_DMA
-	if (lp->use_dma && lp->dma) {
-		free_dma(dev->dma);
-		release_dma_buff(lp);
-	}
-#endif
-
-	/* Update the statistics here. */
-	return 0;
-}
-
-/* Get the current statistics.
- * This may be called with the card open or closed.
- */
-static struct net_device_stats *
-net_get_stats(struct net_device *dev)
-{
-	struct net_local *lp = netdev_priv(dev);
-	unsigned long flags;
-
-	spin_lock_irqsave(&lp->lock, flags);
-	/* Update the statistics from the device registers. */
-	dev->stats.rx_missed_errors += (readreg(dev, PP_RxMiss) >> 6);
-	dev->stats.collisions += (readreg(dev, PP_TxCol) >> 6);
-	spin_unlock_irqrestore(&lp->lock, flags);
-
-	return &dev->stats;
-}
-
-static void net_timeout(struct net_device *dev, unsigned int txqueue)
-{
-	/* If we get here, some higher level has decided we are broken.
-	   There should really be a "kick me" function call instead. */
-	cs89_dbg(0, err, "%s: transmit timed out, %s?\n",
-		 dev->name,
-		 tx_done(dev) ? "IRQ conflict" : "network cable problem");
-	/* Try to restart the adaptor. */
-	netif_wake_queue(dev);
-}
-
-static netdev_tx_t net_send_packet(struct sk_buff *skb, struct net_device *dev)
-{
-	struct net_local *lp = netdev_priv(dev);
-	unsigned long flags;
-
-	cs89_dbg(3, debug, "%s: sent %d byte packet of type %x\n",
-		 dev->name, skb->len,
-		 ((skb->data[ETH_ALEN + ETH_ALEN] << 8) |
-		  skb->data[ETH_ALEN + ETH_ALEN + 1]));
-
-	/* keep the upload from being interrupted, since we
-	 * ask the chip to start transmitting before the
-	 * whole packet has been completely uploaded.
-	 */
-
-	spin_lock_irqsave(&lp->lock, flags);
-	netif_stop_queue(dev);
-
-	/* initiate a transmit sequence */
-	iowrite16(lp->send_cmd, lp->virt_addr + TX_CMD_PORT);
-	iowrite16(skb->len, lp->virt_addr + TX_LEN_PORT);
-
-	/* Test to see if the chip has allocated memory for the packet */
-	if ((readreg(dev, PP_BusST) & READY_FOR_TX_NOW) == 0) {
-		/* Gasp!  It hasn't.  But that shouldn't happen since
-		 * we're waiting for TxOk, so return 1 and requeue this packet.
-		 */
-
-		spin_unlock_irqrestore(&lp->lock, flags);
-		cs89_dbg(0, err, "Tx buffer not free!\n");
-		return NETDEV_TX_BUSY;
-	}
-	/* Write the contents of the packet */
-	writewords(lp, TX_FRAME_PORT, skb->data, (skb->len + 1) >> 1);
-	spin_unlock_irqrestore(&lp->lock, flags);
-	dev->stats.tx_bytes += skb->len;
-	dev_consume_skb_any(skb);
-
-	/* We DO NOT call netif_wake_queue() here.
-	 * We also DO NOT call netif_start_queue().
-	 *
-	 * Either of these would cause another bottom half run through
-	 * net_send_packet() before this packet has fully gone out.
-	 * That causes us to hit the "Gasp!" above and the send is rescheduled.
-	 * it runs like a dog.  We just return and wait for the Tx completion
-	 * interrupt handler to restart the netdevice layer
-	 */
-
-	return NETDEV_TX_OK;
-}
-
-static void set_multicast_list(struct net_device *dev)
-{
-	struct net_local *lp = netdev_priv(dev);
-	unsigned long flags;
-	u16 cfg;
-
-	spin_lock_irqsave(&lp->lock, flags);
-	if (dev->flags & IFF_PROMISC)
-		lp->rx_mode = RX_ALL_ACCEPT;
-	else if ((dev->flags & IFF_ALLMULTI) || !netdev_mc_empty(dev))
-		/* The multicast-accept list is initialized to accept-all,
-		 * and we rely on higher-level filtering for now.
-		 */
-		lp->rx_mode = RX_MULTCAST_ACCEPT;
-	else
-		lp->rx_mode = 0;
-
-	writereg(dev, PP_RxCTL, DEF_RX_ACCEPT | lp->rx_mode);
-
-	/* in promiscuous mode, we accept errored packets,
-	 * so we have to enable interrupts on them also
-	 */
-	cfg = lp->curr_rx_cfg;
-	if (lp->rx_mode == RX_ALL_ACCEPT)
-		cfg |= RX_CRC_ERROR_ENBL | RX_RUNT_ENBL | RX_EXTRA_DATA_ENBL;
-	writereg(dev, PP_RxCFG, cfg);
-	spin_unlock_irqrestore(&lp->lock, flags);
-}
-
-static int set_mac_address(struct net_device *dev, void *p)
-{
-	int i;
-	struct sockaddr *addr = p;
-
-	if (netif_running(dev))
-		return -EBUSY;
-
-	eth_hw_addr_set(dev, addr->sa_data);
-
-	cs89_dbg(0, debug, "%s: Setting MAC address to %pM\n",
-		 dev->name, dev->dev_addr);
-
-	/* set the Ethernet address */
-	for (i = 0; i < ETH_ALEN / 2; i++)
-		writereg(dev, PP_IA + i * 2,
-			 (dev->dev_addr[i * 2] |
-			  (dev->dev_addr[i * 2 + 1] << 8)));
-
-	return 0;
-}
-
-#ifdef CONFIG_NET_POLL_CONTROLLER
-/*
- * Polling receive - used by netconsole and other diagnostic tools
- * to allow network i/o with interrupts disabled.
- */
-static void net_poll_controller(struct net_device *dev)
-{
-	disable_irq(dev->irq);
-	net_interrupt(dev->irq, dev);
-	enable_irq(dev->irq);
-}
-#endif
-
-static const struct net_device_ops net_ops = {
-	.ndo_open		= net_open,
-	.ndo_stop		= net_close,
-	.ndo_tx_timeout		= net_timeout,
-	.ndo_start_xmit		= net_send_packet,
-	.ndo_get_stats		= net_get_stats,
-	.ndo_set_rx_mode	= set_multicast_list,
-	.ndo_set_mac_address	= set_mac_address,
-#ifdef CONFIG_NET_POLL_CONTROLLER
-	.ndo_poll_controller	= net_poll_controller,
-#endif
-	.ndo_validate_addr	= eth_validate_addr,
-};
-
-static void __init reset_chip(struct net_device *dev)
-{
-#if !defined(CONFIG_MACH_MX31ADS)
-	struct net_local *lp = netdev_priv(dev);
-	unsigned long reset_start_time;
-
-	writereg(dev, PP_SelfCTL, readreg(dev, PP_SelfCTL) | POWER_ON_RESET);
-
-	/* wait 30 ms */
-	msleep(30);
-
-	if (lp->chip_type != CS8900) {
-		/* Hardware problem requires PNP registers to be reconfigured after a reset */
-		iowrite16(PP_CS8920_ISAINT, lp->virt_addr + ADD_PORT);
-		iowrite8(dev->irq, lp->virt_addr + DATA_PORT);
-		iowrite8(0, lp->virt_addr + DATA_PORT + 1);
-
-		iowrite16(PP_CS8920_ISAMemB, lp->virt_addr + ADD_PORT);
-		iowrite8((dev->mem_start >> 16) & 0xff,
-			 lp->virt_addr + DATA_PORT);
-		iowrite8((dev->mem_start >> 8) & 0xff,
-			 lp->virt_addr + DATA_PORT + 1);
-	}
-
-	/* Wait until the chip is reset */
-	reset_start_time = jiffies;
-	while ((readreg(dev, PP_SelfST) & INIT_DONE) == 0 &&
-	       time_before(jiffies, reset_start_time + 2))
-		;
-#endif /* !CONFIG_MACH_MX31ADS */
-}
-
-/* This is the real probe routine.
- * Linux has a history of friendly device probes on the ISA bus.
- * A good device probes avoids doing writes, and
- * verifies that the correct device exists and functions.
- * Return 0 on success.
- */
-static int __init
-cs89x0_probe1(struct net_device *dev, void __iomem *ioaddr, int modular)
-{
-	struct net_local *lp = netdev_priv(dev);
-	int i;
-	int tmp;
-	unsigned rev_type = 0;
-	int eeprom_buff[CHKSUM_LEN];
-	u8 addr[ETH_ALEN];
-	int retval;
-
-	/* Initialize the device structure. */
-	if (!modular) {
-		memset(lp, 0, sizeof(*lp));
-		spin_lock_init(&lp->lock);
-#ifndef MODULE
-#if ALLOW_DMA
-		if (g_cs89x0_dma) {
-			lp->use_dma = 1;
-			lp->dma = g_cs89x0_dma;
-			lp->dmasize = 16;	/* Could make this an option... */
-		}
-#endif
-		lp->force = g_cs89x0_media__force;
-#endif
-	}
-
-	pr_debug("PP_addr at %p[%x]: 0x%x\n",
-		 ioaddr, ADD_PORT, ioread16(ioaddr + ADD_PORT));
-	iowrite16(PP_ChipID, ioaddr + ADD_PORT);
-
-	tmp = ioread16(ioaddr + DATA_PORT);
-	if (tmp != CHIP_EISA_ID_SIG) {
-		pr_debug("%s: incorrect signature at %p[%x]: 0x%x!="
-			 CHIP_EISA_ID_SIG_STR "\n",
-			 dev->name, ioaddr, DATA_PORT, tmp);
-		retval = -ENODEV;
-		goto out1;
-	}
-
-	lp->virt_addr = ioaddr;
-
-	/* get the chip type */
-	rev_type = readreg(dev, PRODUCT_ID_ADD);
-	lp->chip_type = rev_type & ~REVISON_BITS;
-	lp->chip_revision = ((rev_type & REVISON_BITS) >> 8) + 'A';
-
-	/* Check the chip type and revision in order to set the correct
-	 * send command.  CS8920 revision C and CS8900 revision F can use
-	 * the faster send.
-	 */
-	lp->send_cmd = TX_AFTER_381;
-	if (lp->chip_type == CS8900 && lp->chip_revision >= 'F')
-		lp->send_cmd = TX_NOW;
-	if (lp->chip_type != CS8900 && lp->chip_revision >= 'C')
-		lp->send_cmd = TX_NOW;
-
-	pr_info_once("%s\n", version);
-
-	pr_info("%s: cs89%c0%s rev %c found at %p ",
-		dev->name,
-		lp->chip_type == CS8900  ? '0' : '2',
-		lp->chip_type == CS8920M ? "M" : "",
-		lp->chip_revision,
-		lp->virt_addr);
-
-	reset_chip(dev);
-
-	/* Here we read the current configuration of the chip.
-	 * If there is no Extended EEPROM then the idea is to not disturb
-	 * the chip configuration, it should have been correctly setup by
-	 * automatic EEPROM read on reset. So, if the chip says it read
-	 * the EEPROM the driver will always do *something* instead of
-	 * complain that adapter_cnf is 0.
-	 */
-
-	if ((readreg(dev, PP_SelfST) & (EEPROM_OK | EEPROM_PRESENT)) ==
-	    (EEPROM_OK | EEPROM_PRESENT)) {
-		/* Load the MAC. */
-		for (i = 0; i < ETH_ALEN / 2; i++) {
-			unsigned int Addr;
-			Addr = readreg(dev, PP_IA + i * 2);
-			addr[i * 2] = Addr & 0xFF;
-			addr[i * 2 + 1] = Addr >> 8;
-		}
-		eth_hw_addr_set(dev, addr);
-
-		/* Load the Adapter Configuration.
-		 * Note:  Barring any more specific information from some
-		 * other source (ie EEPROM+Schematics), we would not know
-		 * how to operate a 10Base2 interface on the AUI port.
-		 * However, since we  do read the status of HCB1 and use
-		 * settings that always result in calls to control_dc_dc(dev,0)
-		 * a BNC interface should work if the enable pin
-		 * (dc/dc converter) is on HCB1.
-		 * It will be called AUI however.
-		 */
-
-		lp->adapter_cnf = 0;
-		i = readreg(dev, PP_LineCTL);
-		/* Preserve the setting of the HCB1 pin. */
-		if ((i & (HCB1 | HCB1_ENBL)) == (HCB1 | HCB1_ENBL))
-			lp->adapter_cnf |= A_CNF_DC_DC_POLARITY;
-		/* Save the sqelch bit */
-		if ((i & LOW_RX_SQUELCH) == LOW_RX_SQUELCH)
-			lp->adapter_cnf |= A_CNF_EXTND_10B_2 | A_CNF_LOW_RX_SQUELCH;
-		/* Check if the card is in 10Base-t only mode */
-		if ((i & (AUI_ONLY | AUTO_AUI_10BASET)) == 0)
-			lp->adapter_cnf |=  A_CNF_10B_T | A_CNF_MEDIA_10B_T;
-		/* Check if the card is in AUI only mode */
-		if ((i & (AUI_ONLY | AUTO_AUI_10BASET)) == AUI_ONLY)
-			lp->adapter_cnf |=  A_CNF_AUI | A_CNF_MEDIA_AUI;
-		/* Check if the card is in Auto mode. */
-		if ((i & (AUI_ONLY | AUTO_AUI_10BASET)) == AUTO_AUI_10BASET)
-			lp->adapter_cnf |=  A_CNF_AUI | A_CNF_10B_T |
-				A_CNF_MEDIA_AUI | A_CNF_MEDIA_10B_T | A_CNF_MEDIA_AUTO;
-
-		cs89_dbg(1, info, "%s: PP_LineCTL=0x%x, adapter_cnf=0x%x\n",
-			 dev->name, i, lp->adapter_cnf);
-
-		/* IRQ. Other chips already probe, see below. */
-		if (lp->chip_type == CS8900)
-			lp->isa_config = readreg(dev, PP_CS8900_ISAINT) & INT_NO_MASK;
-
-		pr_cont("[Cirrus EEPROM] ");
-	}
-
-	pr_cont("\n");
-
-	/* First check to see if an EEPROM is attached. */
-
-	if ((readreg(dev, PP_SelfST) & EEPROM_PRESENT) == 0)
-		pr_warn("No EEPROM, relying on command line....\n");
-	else if (get_eeprom_data(dev, START_EEPROM_DATA, CHKSUM_LEN, eeprom_buff) < 0) {
-		pr_warn("EEPROM read failed, relying on command line\n");
-	} else if (get_eeprom_cksum(START_EEPROM_DATA, CHKSUM_LEN, eeprom_buff) < 0) {
-		/* Check if the chip was able to read its own configuration starting
-		   at 0 in the EEPROM*/
-		if ((readreg(dev, PP_SelfST) & (EEPROM_OK | EEPROM_PRESENT)) !=
-		    (EEPROM_OK | EEPROM_PRESENT))
-			pr_warn("Extended EEPROM checksum bad and no Cirrus EEPROM, relying on command line\n");
-
-	} else {
-		/* This reads an extended EEPROM that is not documented
-		 * in the CS8900 datasheet.
-		 */
-
-		/* get transmission control word  but keep the autonegotiation bits */
-		if (!lp->auto_neg_cnf)
-			lp->auto_neg_cnf = eeprom_buff[AUTO_NEG_CNF_OFFSET / 2];
-		/* Store adapter configuration */
-		if (!lp->adapter_cnf)
-			lp->adapter_cnf = eeprom_buff[ADAPTER_CNF_OFFSET / 2];
-		/* Store ISA configuration */
-		lp->isa_config = eeprom_buff[ISA_CNF_OFFSET / 2];
-		dev->mem_start = eeprom_buff[PACKET_PAGE_OFFSET / 2] << 8;
-
-		/* eeprom_buff has 32-bit ints, so we can't just memcpy it */
-		/* store the initial memory base address */
-		for (i = 0; i < ETH_ALEN / 2; i++) {
-			addr[i * 2] = eeprom_buff[i];
-			addr[i * 2 + 1] = eeprom_buff[i] >> 8;
-		}
-		eth_hw_addr_set(dev, addr);
-		cs89_dbg(1, debug, "%s: new adapter_cnf: 0x%x\n",
-			 dev->name, lp->adapter_cnf);
-	}
-
-	/* allow them to force multiple transceivers.  If they force multiple, autosense */
-	{
-		int count = 0;
-		if (lp->force & FORCE_RJ45) {
-			lp->adapter_cnf |= A_CNF_10B_T;
-			count++;
-		}
-		if (lp->force & FORCE_AUI) {
-			lp->adapter_cnf |= A_CNF_AUI;
-			count++;
-		}
-		if (lp->force & FORCE_BNC) {
-			lp->adapter_cnf |= A_CNF_10B_2;
-			count++;
-		}
-		if (count > 1)
-			lp->adapter_cnf |= A_CNF_MEDIA_AUTO;
-		else if (lp->force & FORCE_RJ45)
-			lp->adapter_cnf |= A_CNF_MEDIA_10B_T;
-		else if (lp->force & FORCE_AUI)
-			lp->adapter_cnf |= A_CNF_MEDIA_AUI;
-		else if (lp->force & FORCE_BNC)
-			lp->adapter_cnf |= A_CNF_MEDIA_10B_2;
-	}
-
-	cs89_dbg(1, debug, "%s: after force 0x%x, adapter_cnf=0x%x\n",
-		 dev->name, lp->force, lp->adapter_cnf);
-
-	/* FIXME: We don't let you set dc-dc polarity or low RX squelch from the command line: add it here */
-
-	/* FIXME: We don't let you set the IMM bit from the command line: add it to lp->auto_neg_cnf here */
-
-	/* FIXME: we don't set the Ethernet address on the command line.  Use
-	 * ifconfig IFACE hw ether AABBCCDDEEFF
-	 */
-
-	pr_info("media %s%s%s",
-		(lp->adapter_cnf & A_CNF_10B_T) ? "RJ-45," : "",
-		(lp->adapter_cnf & A_CNF_AUI) ? "AUI," : "",
-		(lp->adapter_cnf & A_CNF_10B_2) ? "BNC," : "");
-
-	lp->irq_map = 0xffff;
-
-	/* If this is a CS8900 then no pnp soft */
-	if (lp->chip_type != CS8900 &&
-	    /* Check if the ISA IRQ has been set  */
-	    (i = readreg(dev, PP_CS8920_ISAINT) & 0xff,
-	     (i != 0 && i < CS8920_NO_INTS))) {
-		if (!dev->irq)
-			dev->irq = i;
-	} else {
-		i = lp->isa_config & INT_NO_MASK;
-#if IS_ENABLED(CONFIG_CS89x0_ISA)
-		if (lp->chip_type == CS8900) {
-			/* Translate the IRQ using the IRQ mapping table. */
-			if (i >= ARRAY_SIZE(cs8900_irq_map))
-				pr_err("invalid ISA interrupt number %d\n", i);
-			else
-				i = cs8900_irq_map[i];
-
-			lp->irq_map = CS8900_IRQ_MAP; /* fixed IRQ map for CS8900 */
-		} else {
-			int irq_map_buff[IRQ_MAP_LEN/2];
-
-			if (get_eeprom_data(dev, IRQ_MAP_EEPROM_DATA,
-					    IRQ_MAP_LEN / 2,
-					    irq_map_buff) >= 0) {
-				if ((irq_map_buff[0] & 0xff) == PNP_IRQ_FRMT)
-					lp->irq_map = ((irq_map_buff[0] >> 8) |
-						       (irq_map_buff[1] << 8));
-			}
-		}
-#endif
-		if (!dev->irq)
-			dev->irq = i;
-	}
-
-	pr_cont(" IRQ %d", dev->irq);
-
-#if ALLOW_DMA
-	if (lp->use_dma) {
-		get_dma_channel(dev);
-		pr_cont(", DMA %d", dev->dma);
-	} else
-#endif
-		pr_cont(", programmed I/O");
-
-	/* print the ethernet address. */
-	pr_cont(", MAC %pM\n", dev->dev_addr);
-
-	dev->netdev_ops	= &net_ops;
-	dev->watchdog_timeo = HZ;
-
-	cs89_dbg(0, info, "cs89x0_probe1() successful\n");
-
-	retval = register_netdev(dev);
-	if (retval)
-		goto out2;
-	return 0;
-out2:
-	iowrite16(PP_ChipID, lp->virt_addr + ADD_PORT);
-out1:
-	return retval;
-}
-
-#if IS_ENABLED(CONFIG_CS89x0_ISA)
-/*
- * This function converts the I/O port address used by the cs89x0_probe() and
- * init_module() functions to the I/O memory address used by the
- * cs89x0_probe1() function.
- */
-static int __init
-cs89x0_ioport_probe(struct net_device *dev, unsigned long ioport, int modular)
-{
-	struct net_local *lp = netdev_priv(dev);
-	int ret;
-	void __iomem *io_mem;
-
-	if (!lp)
-		return -ENOMEM;
-
-	dev->base_addr = ioport;
-
-	if (!request_region(ioport, NETCARD_IO_EXTENT, DRV_NAME)) {
-		ret = -EBUSY;
-		goto out;
-	}
-
-	io_mem = ioport_map(ioport & ~3, NETCARD_IO_EXTENT);
-	if (!io_mem) {
-		ret = -ENOMEM;
-		goto release;
-	}
-
-	/* if they give us an odd I/O address, then do ONE write to
-	 * the address port, to get it back to address zero, where we
-	 * expect to find the EISA signature word. An IO with a base of 0x3
-	 * will skip the test for the ADD_PORT.
-	 */
-	if (ioport & 1) {
-		cs89_dbg(1, info, "%s: odd ioaddr 0x%lx\n", dev->name, ioport);
-		if ((ioport & 2) != 2) {
-			if ((ioread16(io_mem + ADD_PORT) & ADD_MASK) !=
-			    ADD_SIG) {
-				pr_err("%s: bad signature 0x%x\n",
-				       dev->name, ioread16(io_mem + ADD_PORT));
-				ret = -ENODEV;
-				goto unmap;
-			}
-		}
-	}
-
-	ret = cs89x0_probe1(dev, io_mem, modular);
-	if (!ret)
-		goto out;
-unmap:
-	ioport_unmap(io_mem);
-release:
-	release_region(ioport, NETCARD_IO_EXTENT);
-out:
-	return ret;
-}
-
-#ifndef MODULE
-/* Check for a network adaptor of this type, and return '0' iff one exists.
- * If dev->base_addr == 0, probe all likely locations.
- * If dev->base_addr == 1, always return failure.
- * If dev->base_addr == 2, allocate space for the device and return success
- * (detachable devices only).
- * Return 0 on success.
- */
-
-struct net_device * __init cs89x0_probe(int unit)
-{
-	struct net_device *dev = alloc_etherdev(sizeof(struct net_local));
-	unsigned *port;
-	int err = 0;
-	int irq;
-	int io;
-
-	if (!dev)
-		return ERR_PTR(-ENODEV);
-
-	sprintf(dev->name, "eth%d", unit);
-	netdev_boot_setup_check(dev);
-	io = dev->base_addr;
-	irq = dev->irq;
-
-	cs89_dbg(0, info, "cs89x0_probe(0x%x)\n", io);
-
-	if (io > 0x1ff)	{	/* Check a single specified location. */
-		err = cs89x0_ioport_probe(dev, io, 0);
-	} else if (io != 0) {	/* Don't probe at all. */
-		err = -ENXIO;
-	} else {
-		for (port = netcard_portlist; *port; port++) {
-			if (cs89x0_ioport_probe(dev, *port, 0) == 0)
-				break;
-			dev->irq = irq;
-		}
-		if (!*port)
-			err = -ENODEV;
-	}
-	if (err)
-		goto out;
-	return dev;
-out:
-	free_netdev(dev);
-	pr_warn("no cs8900 or cs8920 detected.  Be sure to disable PnP with SETUP\n");
-	return ERR_PTR(err);
-}
-#else
-static struct net_device *dev_cs89x0;
-
-/* Support the 'debug' module parm even if we're compiled for non-debug to
- * avoid breaking someone's startup scripts
- */
-
-static int io;
-static int irq;
-static int debug;
-static char media[8];
-static int duplex = -1;
-
-static int use_dma;			/* These generate unused var warnings if ALLOW_DMA = 0 */
-static int dma;
-static int dmasize = 16;		/* or 64 */
-
-module_param_hw(io, int, ioport, 0);
-module_param_hw(irq, int, irq, 0);
-module_param(debug, int, 0);
-module_param_string(media, media, sizeof(media), 0);
-module_param(duplex, int, 0);
-module_param_hw(dma , int, dma, 0);
-module_param(dmasize , int, 0);
-module_param(use_dma , int, 0);
-MODULE_PARM_DESC(io, "cs89x0 I/O base address");
-MODULE_PARM_DESC(irq, "cs89x0 IRQ number");
-#if DEBUGGING
-MODULE_PARM_DESC(debug, "cs89x0 debug level (0-6)");
-#else
-MODULE_PARM_DESC(debug, "(ignored)");
-#endif
-MODULE_PARM_DESC(media, "Set cs89x0 adapter(s) media type(s) (rj45,bnc,aui)");
-/* No other value than -1 for duplex seems to be currently interpreted */
-MODULE_PARM_DESC(duplex, "(ignored)");
-#if ALLOW_DMA
-MODULE_PARM_DESC(dma , "cs89x0 ISA DMA channel; ignored if use_dma=0");
-MODULE_PARM_DESC(dmasize , "cs89x0 DMA size in kB (16,64); ignored if use_dma=0");
-MODULE_PARM_DESC(use_dma , "cs89x0 using DMA (0-1)");
-#else
-MODULE_PARM_DESC(dma , "(ignored)");
-MODULE_PARM_DESC(dmasize , "(ignored)");
-MODULE_PARM_DESC(use_dma , "(ignored)");
-#endif
-
-MODULE_AUTHOR("Mike Cruse, Russwll Nelson <nelson@crynwr.com>, Andrew Morton");
-MODULE_LICENSE("GPL");
-
-/*
- * media=t             - specify media type
- * or media=2
- * or media=aui
- * or medai=auto
- * duplex=0            - specify forced half/full/autonegotiate duplex
- * debug=#             - debug level
- *
- * Default Chip Configuration:
- * DMA Burst = enabled
- * IOCHRDY Enabled = enabled
- * UseSA = enabled
- * CS8900 defaults to half-duplex if not specified on command-line
- * CS8920 defaults to autoneg if not specified on command-line
- * Use reset defaults for other config parameters
- *
- * Assumptions:
- * media type specified is supported (circuitry is present)
- * if memory address is > 1MB, then required mem decode hw is present
- * if 10B-2, then agent other than driver will enable DC/DC converter
- * (hw or software util)
- */
-
-static int __init cs89x0_isa_init_module(void)
-{
-	struct net_device *dev;
-	struct net_local *lp;
-	int ret = 0;
-
-#if DEBUGGING
-	net_debug = debug;
-#else
-	debug = 0;
-#endif
-	dev = alloc_etherdev(sizeof(struct net_local));
-	if (!dev)
-		return -ENOMEM;
-
-	dev->irq = irq;
-	dev->base_addr = io;
-	lp = netdev_priv(dev);
-
-#if ALLOW_DMA
-	if (use_dma) {
-		lp->use_dma = use_dma;
-		lp->dma = dma;
-		lp->dmasize = dmasize;
-	}
-#endif
-
-	spin_lock_init(&lp->lock);
-
-	/* boy, they'd better get these right */
-	if (!strcmp(media, "rj45"))
-		lp->adapter_cnf = A_CNF_MEDIA_10B_T | A_CNF_10B_T;
-	else if (!strcmp(media, "aui"))
-		lp->adapter_cnf = A_CNF_MEDIA_AUI   | A_CNF_AUI;
-	else if (!strcmp(media, "bnc"))
-		lp->adapter_cnf = A_CNF_MEDIA_10B_2 | A_CNF_10B_2;
-	else
-		lp->adapter_cnf = A_CNF_MEDIA_10B_T | A_CNF_10B_T;
-
-	if (duplex == -1)
-		lp->auto_neg_cnf = AUTO_NEG_ENABLE;
-
-	if (io == 0) {
-		pr_err("Module autoprobing not allowed\n");
-		pr_err("Append io=0xNNN\n");
-		ret = -EPERM;
-		goto out;
-	} else if (io <= 0x1ff) {
-		ret = -ENXIO;
-		goto out;
-	}
-
-#if ALLOW_DMA
-	if (use_dma && dmasize != 16 && dmasize != 64) {
-		pr_err("dma size must be either 16K or 64K, not %dK\n",
-		       dmasize);
-		ret = -EPERM;
-		goto out;
-	}
-#endif
-	ret = cs89x0_ioport_probe(dev, io, 1);
-	if (ret)
-		goto out;
-
-	dev_cs89x0 = dev;
-	return 0;
-out:
-	free_netdev(dev);
-	return ret;
-}
-module_init(cs89x0_isa_init_module);
-
-static void __exit cs89x0_isa_cleanup_module(void)
-{
-	struct net_local *lp = netdev_priv(dev_cs89x0);
-
-	unregister_netdev(dev_cs89x0);
-	iowrite16(PP_ChipID, lp->virt_addr + ADD_PORT);
-	ioport_unmap(lp->virt_addr);
-	release_region(dev_cs89x0->base_addr, NETCARD_IO_EXTENT);
-	free_netdev(dev_cs89x0);
-}
-module_exit(cs89x0_isa_cleanup_module);
-#endif /* MODULE */
-#endif /* CONFIG_CS89x0_ISA */
-
-#if IS_ENABLED(CONFIG_CS89x0_PLATFORM)
-static int __init cs89x0_platform_probe(struct platform_device *pdev)
-{
-	struct net_device *dev = alloc_etherdev(sizeof(struct net_local));
-	void __iomem *virt_addr;
-	int err;
-
-	if (!dev)
-		return -ENOMEM;
-
-	dev->irq = platform_get_irq(pdev, 0);
-	if (dev->irq < 0) {
-		err = dev->irq;
-		goto free;
-	}
-
-	virt_addr = devm_platform_ioremap_resource(pdev, 0);
-	if (IS_ERR(virt_addr)) {
-		err = PTR_ERR(virt_addr);
-		goto free;
-	}
-
-	err = cs89x0_probe1(dev, virt_addr, 0);
-	if (err) {
-		dev_warn(&dev->dev, "no cs8900 or cs8920 detected\n");
-		goto free;
-	}
-
-	platform_set_drvdata(pdev, dev);
-	return 0;
-
-free:
-	free_netdev(dev);
-	return err;
-}
-
-static void cs89x0_platform_remove(struct platform_device *pdev)
-{
-	struct net_device *dev = platform_get_drvdata(pdev);
-
-	/* This platform_get_resource() call will not return NULL, because
-	 * the same call in cs89x0_platform_probe() has returned a non NULL
-	 * value.
-	 */
-	unregister_netdev(dev);
-	free_netdev(dev);
-}
-
-static const struct of_device_id __maybe_unused cs89x0_match[] = {
-	{ .compatible = "cirrus,cs8900", },
-	{ .compatible = "cirrus,cs8920", },
-	{ },
-};
-MODULE_DEVICE_TABLE(of, cs89x0_match);
-
-static struct platform_driver cs89x0_driver = {
-	.driver	= {
-		.name		= DRV_NAME,
-		.of_match_table	= of_match_ptr(cs89x0_match),
-	},
-	.remove = cs89x0_platform_remove,
-};
-
-module_platform_driver_probe(cs89x0_driver, cs89x0_platform_probe);
-
-#endif /* CONFIG_CS89x0_PLATFORM */
-
-MODULE_LICENSE("GPL");
-MODULE_DESCRIPTION("Crystal Semiconductor (Now Cirrus Logic) CS89[02]0 network driver");
-MODULE_AUTHOR("Russell Nelson <nelson@crynwr.com>");

-- 
2.53.0


^ permalink raw reply related	[flat|nested] 28+ messages in thread

* [PATCH net 12/18] drivers: net: cirrus: mac89x0: Remove this driver
  2026-04-21 19:31 [PATCH net 00/18] Remove a number of ISA and PCMCIA Ethernet drivers Andrew Lunn
                   ` (10 preceding siblings ...)
  2026-04-21 19:31 ` [PATCH net 11/18] drivers: net: cirrus: cs89x0: " Andrew Lunn
@ 2026-04-21 19:31 ` Andrew Lunn
  2026-04-21 21:34   ` Daniel Palmer
  2026-04-21 19:31 ` [PATCH net 13/18] drivers: net: fujitsu: fmvj18x: " Andrew Lunn
                   ` (9 subsequent siblings)
  21 siblings, 1 reply; 28+ messages in thread
From: Andrew Lunn @ 2026-04-21 19:31 UTC (permalink / raw)
  To: Andrew Lunn, David S. Miller, Eric Dumazet, Jakub Kicinski,
	Paolo Abeni, Simon Horman, Jonathan Corbet, Shuah Khan
  Cc: linux-kernel, netdev, linux-doc, Andrew Lunn

The mac89x0 was written by Russell Nelson in 1996. It is an MAC
device, so unlikely to be used with modern kernels.

Signed-off-by: Andrew Lunn <andrew@lunn.ch>
---
 drivers/net/ethernet/cirrus/Kconfig   |  10 -
 drivers/net/ethernet/cirrus/Makefile  |   1 -
 drivers/net/ethernet/cirrus/cs89x0.h  | 461 ---------------------------
 drivers/net/ethernet/cirrus/mac89x0.c | 577 ----------------------------------
 4 files changed, 1049 deletions(-)

diff --git a/drivers/net/ethernet/cirrus/Kconfig b/drivers/net/ethernet/cirrus/Kconfig
index 1a0c7b3bfcd6..786d379e79fe 100644
--- a/drivers/net/ethernet/cirrus/Kconfig
+++ b/drivers/net/ethernet/cirrus/Kconfig
@@ -25,14 +25,4 @@ config EP93XX_ETH
 	  This is a driver for the ethernet hardware included in EP93xx CPUs.
 	  Say Y if you are building a kernel for EP93xx based devices.
 
-config MAC89x0
-	tristate "Macintosh CS89x0 based ethernet cards"
-	depends on MAC
-	help
-	  Support for CS89x0 chipset based Ethernet cards.  If you have a
-	  Nubus or LC-PDS network (Ethernet) card of this type, say Y here.
-
-	  To compile this driver as a module, choose M here. This module will
-	  be called mac89x0.
-
 endif # NET_VENDOR_CIRRUS
diff --git a/drivers/net/ethernet/cirrus/Makefile b/drivers/net/ethernet/cirrus/Makefile
index cb740939d976..03800af0f0e1 100644
--- a/drivers/net/ethernet/cirrus/Makefile
+++ b/drivers/net/ethernet/cirrus/Makefile
@@ -4,4 +4,3 @@
 #
 
 obj-$(CONFIG_EP93XX_ETH) += ep93xx_eth.o
-obj-$(CONFIG_MAC89x0) += mac89x0.o
diff --git a/drivers/net/ethernet/cirrus/cs89x0.h b/drivers/net/ethernet/cirrus/cs89x0.h
deleted file mode 100644
index 210f9ec9af4b..000000000000
--- a/drivers/net/ethernet/cirrus/cs89x0.h
+++ /dev/null
@@ -1,461 +0,0 @@
-/*  Copyright, 1988-1992, Russell Nelson, Crynwr Software
-
-   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, version 1.
-
-   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., 675 Mass Ave, Cambridge, MA 02139, USA.
-   */
-
-
-#define PP_ChipID 0x0000	/* offset   0h -> Corp -ID              */
-				/* offset   2h -> Model/Product Number  */
-				/* offset   3h -> Chip Revision Number  */
-
-#define PP_ISAIOB 0x0020	/*  IO base address */
-#define PP_CS8900_ISAINT 0x0022	/*  ISA interrupt select */
-#define PP_CS8920_ISAINT 0x0370	/*  ISA interrupt select */
-#define PP_CS8900_ISADMA 0x0024	/*  ISA Rec DMA channel */
-#define PP_CS8920_ISADMA 0x0374	/*  ISA Rec DMA channel */
-#define PP_ISASOF 0x0026	/*  ISA DMA offset */
-#define PP_DmaFrameCnt 0x0028	/*  ISA DMA Frame count */
-#define PP_DmaByteCnt 0x002A	/*  ISA DMA Byte count */
-#define PP_CS8900_ISAMemB 0x002C	/*  Memory base */
-#define PP_CS8920_ISAMemB 0x0348 /*  */
-
-#define PP_ISABootBase 0x0030	/*  Boot Prom base  */
-#define PP_ISABootMask 0x0034	/*  Boot Prom Mask */
-
-/* EEPROM data and command registers */
-#define PP_EECMD 0x0040		/*  NVR Interface Command register */
-#define PP_EEData 0x0042	/*  NVR Interface Data Register */
-#define PP_DebugReg 0x0044	/*  Debug Register */
-
-#define PP_RxCFG 0x0102		/*  Rx Bus config */
-#define PP_RxCTL 0x0104		/*  Receive Control Register */
-#define PP_TxCFG 0x0106		/*  Transmit Config Register */
-#define PP_TxCMD 0x0108		/*  Transmit Command Register */
-#define PP_BufCFG 0x010A	/*  Bus configuration Register */
-#define PP_LineCTL 0x0112	/*  Line Config Register */
-#define PP_SelfCTL 0x0114	/*  Self Command Register */
-#define PP_BusCTL 0x0116	/*  ISA bus control Register */
-#define PP_TestCTL 0x0118	/*  Test Register */
-#define PP_AutoNegCTL 0x011C	/*  Auto Negotiation Ctrl */
-
-#define PP_ISQ 0x0120		/*  Interrupt Status */
-#define PP_RxEvent 0x0124	/*  Rx Event Register */
-#define PP_TxEvent 0x0128	/*  Tx Event Register */
-#define PP_BufEvent 0x012C	/*  Bus Event Register */
-#define PP_RxMiss 0x0130	/*  Receive Miss Count */
-#define PP_TxCol 0x0132		/*  Transmit Collision Count */
-#define PP_LineST 0x0134	/*  Line State Register */
-#define PP_SelfST 0x0136	/*  Self State register */
-#define PP_BusST 0x0138		/*  Bus Status */
-#define PP_TDR 0x013C		/*  Time Domain Reflectometry */
-#define PP_AutoNegST 0x013E	/*  Auto Neg Status */
-#define PP_TxCommand 0x0144	/*  Tx Command */
-#define PP_TxLength 0x0146	/*  Tx Length */
-#define PP_LAF 0x0150		/*  Hash Table */
-#define PP_IA 0x0158		/*  Physical Address Register */
-
-#define PP_RxStatus 0x0400	/*  Receive start of frame */
-#define PP_RxLength 0x0402	/*  Receive Length of frame */
-#define PP_RxFrame 0x0404	/*  Receive frame pointer */
-#define PP_TxFrame 0x0A00	/*  Transmit frame pointer */
-
-/*  Primary I/O Base Address. If no I/O base is supplied by the user, then this */
-/*  can be used as the default I/O base to access the PacketPage Area. */
-#define DEFAULTIOBASE 0x0300
-#define FIRST_IO 0x020C		/*  First I/O port to check */
-#define LAST_IO 0x037C		/*  Last I/O port to check (+10h) */
-#define ADD_MASK 0x3000		/*  Mask it use of the ADD_PORT register */
-#define ADD_SIG 0x3000		/*  Expected ID signature */
-
-/* On Macs, we only need use the ISA I/O stuff until we do MEMORY_ON */
-#ifdef CONFIG_MAC
-#define LCSLOTBASE 0xfee00000
-#define MMIOBASE 0x40000
-#endif
-
-#define CHIP_EISA_ID_SIG 0x630E   /*  Product ID Code for Crystal Chip (CS8900 spec 4.3) */
-#define CHIP_EISA_ID_SIG_STR "0x630E"
-
-#ifdef IBMEIPKT
-#define EISA_ID_SIG 0x4D24	/*  IBM */
-#define PART_NO_SIG 0x1010	/*  IBM */
-#define MONGOOSE_BIT 0x0000	/*  IBM */
-#else
-#define EISA_ID_SIG 0x630E	/*  PnP Vendor ID (same as chip id for Crystal board) */
-#define PART_NO_SIG 0x4000	/*  ID code CS8920 board (PnP Vendor Product code) */
-#define MONGOOSE_BIT 0x2000	/*  PART_NO_SIG + MONGOOSE_BUT => ID of mongoose */
-#endif
-
-#define PRODUCT_ID_ADD 0x0002   /*  Address of product ID */
-
-/*  Mask to find out the types of  registers */
-#define REG_TYPE_MASK 0x001F
-
-/*  Eeprom Commands */
-#define ERSE_WR_ENBL 0x00F0
-#define ERSE_WR_DISABLE 0x0000
-
-/*  Defines Control/Config register quintuplet numbers */
-#define RX_BUF_CFG 0x0003
-#define RX_CONTROL 0x0005
-#define TX_CFG 0x0007
-#define TX_COMMAND 0x0009
-#define BUF_CFG 0x000B
-#define LINE_CONTROL 0x0013
-#define SELF_CONTROL 0x0015
-#define BUS_CONTROL 0x0017
-#define TEST_CONTROL 0x0019
-
-/*  Defines Status/Count registers quintuplet numbers */
-#define RX_EVENT 0x0004
-#define TX_EVENT 0x0008
-#define BUF_EVENT 0x000C
-#define RX_MISS_COUNT 0x0010
-#define TX_COL_COUNT 0x0012
-#define LINE_STATUS 0x0014
-#define SELF_STATUS 0x0016
-#define BUS_STATUS 0x0018
-#define TDR 0x001C
-
-/* PP_RxCFG - Receive  Configuration and Interrupt Mask bit definition -  Read/write */
-#define SKIP_1 0x0040
-#define RX_STREAM_ENBL 0x0080
-#define RX_OK_ENBL 0x0100
-#define RX_DMA_ONLY 0x0200
-#define AUTO_RX_DMA 0x0400
-#define BUFFER_CRC 0x0800
-#define RX_CRC_ERROR_ENBL 0x1000
-#define RX_RUNT_ENBL 0x2000
-#define RX_EXTRA_DATA_ENBL 0x4000
-
-/* PP_RxCTL - Receive Control bit definition - Read/write */
-#define RX_IA_HASH_ACCEPT 0x0040
-#define RX_PROM_ACCEPT 0x0080
-#define RX_OK_ACCEPT 0x0100
-#define RX_MULTCAST_ACCEPT 0x0200
-#define RX_IA_ACCEPT 0x0400
-#define RX_BROADCAST_ACCEPT 0x0800
-#define RX_BAD_CRC_ACCEPT 0x1000
-#define RX_RUNT_ACCEPT 0x2000
-#define RX_EXTRA_DATA_ACCEPT 0x4000
-#define RX_ALL_ACCEPT (RX_PROM_ACCEPT|RX_BAD_CRC_ACCEPT|RX_RUNT_ACCEPT|RX_EXTRA_DATA_ACCEPT)
-/*  Default receive mode - individually addressed, broadcast, and error free */
-#define DEF_RX_ACCEPT (RX_IA_ACCEPT | RX_BROADCAST_ACCEPT | RX_OK_ACCEPT)
-
-/* PP_TxCFG - Transmit Configuration Interrupt Mask bit definition - Read/write */
-#define TX_LOST_CRS_ENBL 0x0040
-#define TX_SQE_ERROR_ENBL 0x0080
-#define TX_OK_ENBL 0x0100
-#define TX_LATE_COL_ENBL 0x0200
-#define TX_JBR_ENBL 0x0400
-#define TX_ANY_COL_ENBL 0x0800
-#define TX_16_COL_ENBL 0x8000
-
-/* PP_TxCMD - Transmit Command bit definition - Read-only */
-#define TX_START_4_BYTES 0x0000
-#define TX_START_64_BYTES 0x0040
-#define TX_START_128_BYTES 0x0080
-#define TX_START_ALL_BYTES 0x00C0
-#define TX_FORCE 0x0100
-#define TX_ONE_COL 0x0200
-#define TX_TWO_PART_DEFF_DISABLE 0x0400
-#define TX_NO_CRC 0x1000
-#define TX_RUNT 0x2000
-
-/* PP_BufCFG - Buffer Configuration Interrupt Mask bit definition - Read/write */
-#define GENERATE_SW_INTERRUPT 0x0040
-#define RX_DMA_ENBL 0x0080
-#define READY_FOR_TX_ENBL 0x0100
-#define TX_UNDERRUN_ENBL 0x0200
-#define RX_MISS_ENBL 0x0400
-#define RX_128_BYTE_ENBL 0x0800
-#define TX_COL_COUNT_OVRFLOW_ENBL 0x1000
-#define RX_MISS_COUNT_OVRFLOW_ENBL 0x2000
-#define RX_DEST_MATCH_ENBL 0x8000
-
-/* PP_LineCTL - Line Control bit definition - Read/write */
-#define SERIAL_RX_ON 0x0040
-#define SERIAL_TX_ON 0x0080
-#define AUI_ONLY 0x0100
-#define AUTO_AUI_10BASET 0x0200
-#define MODIFIED_BACKOFF 0x0800
-#define NO_AUTO_POLARITY 0x1000
-#define TWO_PART_DEFDIS 0x2000
-#define LOW_RX_SQUELCH 0x4000
-
-/* PP_SelfCTL - Software Self Control bit definition - Read/write */
-#define POWER_ON_RESET 0x0040
-#define SW_STOP 0x0100
-#define SLEEP_ON 0x0200
-#define AUTO_WAKEUP 0x0400
-#define HCB0_ENBL 0x1000
-#define HCB1_ENBL 0x2000
-#define HCB0 0x4000
-#define HCB1 0x8000
-
-/* PP_BusCTL - ISA Bus Control bit definition - Read/write */
-#define RESET_RX_DMA 0x0040
-#define MEMORY_ON 0x0400
-#define DMA_BURST_MODE 0x0800
-#define IO_CHANNEL_READY_ON 0x1000
-#define RX_DMA_SIZE_64K 0x2000
-#define ENABLE_IRQ 0x8000
-
-/* PP_TestCTL - Test Control bit definition - Read/write */
-#define LINK_OFF 0x0080
-#define ENDEC_LOOPBACK 0x0200
-#define AUI_LOOPBACK 0x0400
-#define BACKOFF_OFF 0x0800
-#define FDX_8900 0x4000
-#define FAST_TEST 0x8000
-
-/* PP_RxEvent - Receive Event Bit definition - Read-only */
-#define RX_IA_HASHED 0x0040
-#define RX_DRIBBLE 0x0080
-#define RX_OK 0x0100
-#define RX_HASHED 0x0200
-#define RX_IA 0x0400
-#define RX_BROADCAST 0x0800
-#define RX_CRC_ERROR 0x1000
-#define RX_RUNT 0x2000
-#define RX_EXTRA_DATA 0x4000
-
-#define HASH_INDEX_MASK 0x0FC00
-
-/* PP_TxEvent - Transmit Event Bit definition - Read-only */
-#define TX_LOST_CRS 0x0040
-#define TX_SQE_ERROR 0x0080
-#define TX_OK 0x0100
-#define TX_LATE_COL 0x0200
-#define TX_JBR 0x0400
-#define TX_16_COL 0x8000
-#define TX_SEND_OK_BITS (TX_OK|TX_LOST_CRS)
-#define TX_COL_COUNT_MASK 0x7800
-
-/* PP_BufEvent - Buffer Event Bit definition - Read-only */
-#define SW_INTERRUPT 0x0040
-#define RX_DMA 0x0080
-#define READY_FOR_TX 0x0100
-#define TX_UNDERRUN 0x0200
-#define RX_MISS 0x0400
-#define RX_128_BYTE 0x0800
-#define TX_COL_OVRFLW 0x1000
-#define RX_MISS_OVRFLW 0x2000
-#define RX_DEST_MATCH 0x8000
-
-/* PP_LineST - Ethernet Line Status bit definition - Read-only */
-#define LINK_OK 0x0080
-#define AUI_ON 0x0100
-#define TENBASET_ON 0x0200
-#define POLARITY_OK 0x1000
-#define CRS_OK 0x4000
-
-/* PP_SelfST - Chip Software Status bit definition */
-#define ACTIVE_33V 0x0040
-#define INIT_DONE 0x0080
-#define SI_BUSY 0x0100
-#define EEPROM_PRESENT 0x0200
-#define EEPROM_OK 0x0400
-#define EL_PRESENT 0x0800
-#define EE_SIZE_64 0x1000
-
-/* PP_BusST - ISA Bus Status bit definition */
-#define TX_BID_ERROR 0x0080
-#define READY_FOR_TX_NOW 0x0100
-
-/* PP_AutoNegCTL - Auto Negotiation Control bit definition */
-#define RE_NEG_NOW 0x0040
-#define ALLOW_FDX 0x0080
-#define AUTO_NEG_ENABLE 0x0100
-#define NLP_ENABLE 0x0200
-#define FORCE_FDX 0x8000
-#define AUTO_NEG_BITS (FORCE_FDX|NLP_ENABLE|AUTO_NEG_ENABLE)
-#define AUTO_NEG_MASK (FORCE_FDX|NLP_ENABLE|AUTO_NEG_ENABLE|ALLOW_FDX|RE_NEG_NOW)
-
-/* PP_AutoNegST - Auto Negotiation Status bit definition */
-#define AUTO_NEG_BUSY 0x0080
-#define FLP_LINK 0x0100
-#define FLP_LINK_GOOD 0x0800
-#define LINK_FAULT 0x1000
-#define HDX_ACTIVE 0x4000
-#define FDX_ACTIVE 0x8000
-
-/*  The following block defines the ISQ event types */
-#define ISQ_RECEIVER_EVENT 0x04
-#define ISQ_TRANSMITTER_EVENT 0x08
-#define ISQ_BUFFER_EVENT 0x0c
-#define ISQ_RX_MISS_EVENT 0x10
-#define ISQ_TX_COL_EVENT 0x12
-
-#define ISQ_EVENT_MASK 0x003F   /*  ISQ mask to find out type of event */
-#define ISQ_HIST 16		/*  small history buffer */
-#define AUTOINCREMENT 0x8000	/*  Bit mask to set bit-15 for autoincrement */
-
-#define TXRXBUFSIZE 0x0600
-#define RXDMABUFSIZE 0x8000
-#define RXDMASIZE 0x4000
-#define TXRX_LENGTH_MASK 0x07FF
-
-/*  rx options bits */
-#define RCV_WITH_RXON	1       /*  Set SerRx ON */
-#define RCV_COUNTS	2       /*  Use Framecnt1 */
-#define RCV_PONG	4       /*  Pong respondent */
-#define RCV_DONG	8       /*  Dong operation */
-#define RCV_POLLING	0x10	/*  Poll RxEvent */
-#define RCV_ISQ		0x20	/*  Use ISQ, int */
-#define RCV_AUTO_DMA	0x100	/*  Set AutoRxDMAE */
-#define RCV_DMA		0x200	/*  Set RxDMA only */
-#define RCV_DMA_ALL	0x400	/*  Copy all DMA'ed */
-#define RCV_FIXED_DATA	0x800	/*  Every frame same */
-#define RCV_IO		0x1000	/*  Use ISA IO only */
-#define RCV_MEMORY	0x2000	/*  Use ISA Memory */
-
-#define RAM_SIZE	0x1000       /*  The card has 4k bytes or RAM */
-#define PKT_START PP_TxFrame  /*  Start of packet RAM */
-
-#define RX_FRAME_PORT	0x0000
-#define TX_FRAME_PORT RX_FRAME_PORT
-#define TX_CMD_PORT	0x0004
-#define TX_NOW		0x0000       /*  Tx packet after   5 bytes copied */
-#define TX_AFTER_381	0x0040       /*  Tx packet after 381 bytes copied */
-#define TX_AFTER_ALL	0x00c0       /*  Tx packet after all bytes copied */
-#define TX_LEN_PORT	0x0006
-#define ISQ_PORT	0x0008
-#define ADD_PORT	0x000A
-#define DATA_PORT	0x000C
-
-#define EEPROM_WRITE_EN		0x00F0
-#define EEPROM_WRITE_DIS	0x0000
-#define EEPROM_WRITE_CMD	0x0100
-#define EEPROM_READ_CMD		0x0200
-
-/*  Receive Header */
-/*  Description of header of each packet in receive area of memory */
-#define RBUF_EVENT_LOW	0   /*  Low byte of RxEvent - status of received frame */
-#define RBUF_EVENT_HIGH	1   /*  High byte of RxEvent - status of received frame */
-#define RBUF_LEN_LOW	2   /*  Length of received data - low byte */
-#define RBUF_LEN_HI	3   /*  Length of received data - high byte */
-#define RBUF_HEAD_LEN	4   /*  Length of this header */
-
-#define CHIP_READ 0x1   /*  Used to mark state of the repins code (chip or dma) */
-#define DMA_READ 0x2   /*  Used to mark state of the repins code (chip or dma) */
-
-/*  for bios scan */
-/*  */
-#ifdef CSDEBUG
-/*  use these values for debugging bios scan */
-#define BIOS_START_SEG 0x00000
-#define BIOS_OFFSET_INC 0x0010
-#else
-#define BIOS_START_SEG 0x0c000
-#define BIOS_OFFSET_INC 0x0200
-#endif
-
-#define BIOS_LAST_OFFSET 0x0fc00
-
-/*  Byte offsets into the EEPROM configuration buffer */
-#define ISA_CNF_OFFSET 0x6
-#define TX_CTL_OFFSET (ISA_CNF_OFFSET + 8)			/*  8900 eeprom */
-#define AUTO_NEG_CNF_OFFSET (ISA_CNF_OFFSET + 8)		/*  8920 eeprom */
-
-  /*  the assumption here is that the bits in the eeprom are generally  */
-  /*  in the same position as those in the autonegctl register. */
-  /*  Of course the IMM bit is not in that register so it must be  */
-  /*  masked out */
-#define EE_FORCE_FDX  0x8000
-#define EE_NLP_ENABLE 0x0200
-#define EE_AUTO_NEG_ENABLE 0x0100
-#define EE_ALLOW_FDX 0x0080
-#define EE_AUTO_NEG_CNF_MASK (EE_FORCE_FDX|EE_NLP_ENABLE|EE_AUTO_NEG_ENABLE|EE_ALLOW_FDX)
-
-#define IMM_BIT 0x0040		/*  ignore missing media	 */
-
-#define ADAPTER_CNF_OFFSET (AUTO_NEG_CNF_OFFSET + 2)
-#define A_CNF_10B_T 0x0001
-#define A_CNF_AUI 0x0002
-#define A_CNF_10B_2 0x0004
-#define A_CNF_MEDIA_TYPE 0x0070
-#define A_CNF_MEDIA_AUTO 0x0070
-#define A_CNF_MEDIA_10B_T 0x0020
-#define A_CNF_MEDIA_AUI 0x0040
-#define A_CNF_MEDIA_10B_2 0x0010
-#define A_CNF_DC_DC_POLARITY 0x0080
-#define A_CNF_NO_AUTO_POLARITY 0x2000
-#define A_CNF_LOW_RX_SQUELCH 0x4000
-#define A_CNF_EXTND_10B_2 0x8000
-
-#define PACKET_PAGE_OFFSET 0x8
-
-/*  Bit definitions for the ISA configuration word from the EEPROM */
-#define INT_NO_MASK 0x000F
-#define DMA_NO_MASK 0x0070
-#define ISA_DMA_SIZE 0x0200
-#define ISA_AUTO_RxDMA 0x0400
-#define ISA_RxDMA 0x0800
-#define DMA_BURST 0x1000
-#define STREAM_TRANSFER 0x2000
-#define ANY_ISA_DMA (ISA_AUTO_RxDMA | ISA_RxDMA)
-
-/*  DMA controller registers */
-#define DMA_BASE 0x00     /*  DMA controller base */
-#define DMA_BASE_2 0x0C0    /*  DMA controller base */
-
-#define DMA_STAT 0x0D0    /*  DMA controller status register */
-#define DMA_MASK 0x0D4    /*  DMA controller mask register */
-#define DMA_MODE 0x0D6    /*  DMA controller mode register */
-#define DMA_RESETFF 0x0D8    /*  DMA controller first/last flip flop */
-
-/*  DMA data */
-#define DMA_DISABLE 0x04     /*  Disable channel n */
-#define DMA_ENABLE 0x00     /*  Enable channel n */
-/*  Demand transfers, incr. address, auto init, writes, ch. n */
-#define DMA_RX_MODE 0x14
-/*  Demand transfers, incr. address, auto init, reads, ch. n */
-#define DMA_TX_MODE 0x18
-
-#define DMA_SIZE (16*1024) /*  Size of dma buffer - 16k */
-
-#define CS8900 0x0000
-#define CS8920 0x4000
-#define CS8920M 0x6000
-#define REVISON_BITS 0x1F00
-#define EEVER_NUMBER 0x12
-#define CHKSUM_LEN 0x14
-#define CHKSUM_VAL 0x0000
-#define START_EEPROM_DATA 0x001c /*  Offset into eeprom for start of data */
-#define IRQ_MAP_EEPROM_DATA 0x0046 /*  Offset into eeprom for the IRQ map */
-#define IRQ_MAP_LEN 0x0004 /*  No of bytes to read for the IRQ map */
-#define PNP_IRQ_FRMT 0x0022 /*  PNP small item IRQ format */
-#define CS8900_IRQ_MAP 0x1c20 /*  This IRQ map is fixed */
-
-#define CS8920_NO_INTS 0x0F   /*  Max CS8920 interrupt select # */
-
-#define PNP_ADD_PORT 0x0279
-#define PNP_WRITE_PORT 0x0A79
-
-#define GET_PNP_ISA_STRUCT 0x40
-#define PNP_ISA_STRUCT_LEN 0x06
-#define PNP_CSN_CNT_OFF 0x01
-#define PNP_RD_PORT_OFF 0x02
-#define PNP_FUNCTION_OK 0x00
-#define PNP_WAKE 0x03
-#define PNP_RSRC_DATA 0x04
-#define PNP_RSRC_READY 0x01
-#define PNP_STATUS 0x05
-#define PNP_ACTIVATE 0x30
-#define PNP_CNF_IO_H 0x60
-#define PNP_CNF_IO_L 0x61
-#define PNP_CNF_INT 0x70
-#define PNP_CNF_DMA 0x74
-#define PNP_CNF_MEM 0x48
diff --git a/drivers/net/ethernet/cirrus/mac89x0.c b/drivers/net/ethernet/cirrus/mac89x0.c
deleted file mode 100644
index 6723df9b65d9..000000000000
--- a/drivers/net/ethernet/cirrus/mac89x0.c
+++ /dev/null
@@ -1,577 +0,0 @@
-/* mac89x0.c: A Crystal Semiconductor CS89[02]0 driver for linux. */
-/*
-	Written 1996 by Russell Nelson, with reference to skeleton.c
-	written 1993-1994 by Donald Becker.
-
-	This software may be used and distributed according to the terms
-	of the GNU General Public License, incorporated herein by reference.
-
-	The author may be reached at nelson@crynwr.com, Crynwr
-	Software, 11 Grant St., Potsdam, NY 13676
-
-  Changelog:
-
-  Mike Cruse        : mcruse@cti-ltd.com
-                    : Changes for Linux 2.0 compatibility.
-                    : Added dev_id parameter in net_interrupt(),
-                    : request_irq() and free_irq(). Just NULL for now.
-
-  Mike Cruse        : Added MOD_INC_USE_COUNT and MOD_DEC_USE_COUNT macros
-                    : in net_open() and net_close() so kerneld would know
-                    : that the module is in use and wouldn't eject the
-                    : driver prematurely.
-
-  Mike Cruse        : Rewrote init_module() and cleanup_module using 8390.c
-                    : as an example. Disabled autoprobing in init_module(),
-                    : not a good thing to do to other devices while Linux
-                    : is running from all accounts.
-
-  Alan Cox          : Removed 1.2 support, added 2.1 extra counters.
-
-  David Huggins-Daines <dhd@debian.org>
-
-  Split this off into mac89x0.c, and gutted it of all parts which are
-  not relevant to the existing CS8900 cards on the Macintosh
-  (i.e. basically the Daynaport CS and LC cards).  To be precise:
-
-    * Removed all the media-detection stuff, because these cards are
-    TP-only.
-
-    * Lobotomized the ISA interrupt bogosity, because these cards use
-    a hardwired NuBus interrupt and a magic ISAIRQ value in the card.
-
-    * Basically eliminated everything not relevant to getting the
-    cards minimally functioning on the Macintosh.
-
-  I might add that these cards are badly designed even from the Mac
-  standpoint, in that Dayna, in their infinite wisdom, used NuBus slot
-  I/O space and NuBus interrupts for these cards, but neglected to
-  provide anything even remotely resembling a NuBus ROM.  Therefore we
-  have to probe for them in a brain-damaged ISA-like fashion.
-
-  Arnaldo Carvalho de Melo <acme@conectiva.com.br> - 11/01/2001
-  check kmalloc and release the allocated memory on failure in
-  mac89x0_probe and in init_module
-  use local_irq_{save,restore}(flags) in net_get_stat, not just
-  local_irq_{dis,en}able()
-*/
-
-#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
-
-static const char version[] =
-"cs89x0.c:v1.02 11/26/96 Russell Nelson <nelson@crynwr.com>\n";
-
-#include <linux/module.h>
-
-/*
-  Sources:
-
-	Crynwr packet driver epktisa.
-
-	Crystal Semiconductor data sheets.
-
-*/
-
-#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/nubus.h>
-#include <linux/errno.h>
-#include <linux/init.h>
-#include <linux/netdevice.h>
-#include <linux/platform_device.h>
-#include <linux/etherdevice.h>
-#include <linux/skbuff.h>
-#include <linux/delay.h>
-#include <linux/bitops.h>
-#include <linux/gfp.h>
-
-#include <asm/io.h>
-#include <asm/hwtest.h>
-#include <asm/macints.h>
-
-#include "cs89x0.h"
-
-static int debug = -1;
-module_param(debug, int, 0);
-MODULE_PARM_DESC(debug, "debug message level");
-
-/* Information that need to be kept for each board. */
-struct net_local {
-	int msg_enable;
-	int chip_type;		/* one of: CS8900, CS8920, CS8920M */
-	char chip_revision;	/* revision letter of the chip ('A'...) */
-	int send_cmd;		/* the propercommand used to send a packet. */
-	int rx_mode;
-	int curr_rx_cfg;
-        int send_underrun;      /* keep track of how many underruns in a row we get */
-};
-
-/* Index to functions, as function prototypes. */
-static int net_open(struct net_device *dev);
-static netdev_tx_t net_send_packet(struct sk_buff *skb, struct net_device *dev);
-static irqreturn_t net_interrupt(int irq, void *dev_id);
-static void set_multicast_list(struct net_device *dev);
-static void net_rx(struct net_device *dev);
-static int net_close(struct net_device *dev);
-static struct net_device_stats *net_get_stats(struct net_device *dev);
-static int set_mac_address(struct net_device *dev, void *addr);
-
-/* For reading/writing registers ISA-style */
-static inline int
-readreg_io(struct net_device *dev, int portno)
-{
-	nubus_writew(swab16(portno), dev->base_addr + ADD_PORT);
-	return swab16(nubus_readw(dev->base_addr + DATA_PORT));
-}
-
-static inline void
-writereg_io(struct net_device *dev, int portno, int value)
-{
-	nubus_writew(swab16(portno), dev->base_addr + ADD_PORT);
-	nubus_writew(swab16(value), dev->base_addr + DATA_PORT);
-}
-
-/* These are for reading/writing registers in shared memory */
-static inline int
-readreg(struct net_device *dev, int portno)
-{
-	return swab16(nubus_readw(dev->mem_start + portno));
-}
-
-static inline void
-writereg(struct net_device *dev, int portno, int value)
-{
-	nubus_writew(swab16(value), dev->mem_start + portno);
-}
-
-static const struct net_device_ops mac89x0_netdev_ops = {
-	.ndo_open		= net_open,
-	.ndo_stop		= net_close,
-	.ndo_start_xmit		= net_send_packet,
-	.ndo_get_stats		= net_get_stats,
-	.ndo_set_rx_mode	= set_multicast_list,
-	.ndo_set_mac_address	= set_mac_address,
-	.ndo_validate_addr	= eth_validate_addr,
-};
-
-/* Probe for the CS8900 card in slot E.  We won't bother looking
-   anywhere else until we have a really good reason to do so. */
-static int mac89x0_device_probe(struct platform_device *pdev)
-{
-	struct net_device *dev;
-	struct net_local *lp;
-	int i, slot;
-	unsigned rev_type = 0;
-	unsigned long ioaddr;
-	unsigned short sig;
-	int err = -ENODEV;
-	struct nubus_rsrc *fres;
-
-	dev = alloc_etherdev(sizeof(struct net_local));
-	if (!dev)
-		return -ENOMEM;
-
-	/* We might have to parameterize this later */
-	slot = 0xE;
-	/* Get out now if there's a real NuBus card in slot E */
-	for_each_func_rsrc(fres)
-		if (fres->board->slot == slot)
-			goto out;
-
-	/* The pseudo-ISA bits always live at offset 0x300 (gee,
-           wonder why...) */
-	ioaddr = (unsigned long)
-		nubus_slot_addr(slot) | (((slot&0xf) << 20) + DEFAULTIOBASE);
-	{
-		int card_present;
-
-		card_present = (hwreg_present((void *)ioaddr + 4) &&
-				hwreg_present((void *)ioaddr + DATA_PORT));
-		if (!card_present)
-			goto out;
-	}
-
-	nubus_writew(0, ioaddr + ADD_PORT);
-	sig = nubus_readw(ioaddr + DATA_PORT);
-	if (sig != swab16(CHIP_EISA_ID_SIG))
-		goto out;
-
-	SET_NETDEV_DEV(dev, &pdev->dev);
-
-	/* Initialize the net_device structure. */
-	lp = netdev_priv(dev);
-
-	lp->msg_enable = netif_msg_init(debug, 0);
-
-	/* Fill in the 'dev' fields. */
-	dev->base_addr = ioaddr;
-	dev->mem_start = (unsigned long)
-		nubus_slot_addr(slot) | (((slot&0xf) << 20) + MMIOBASE);
-	dev->mem_end = dev->mem_start + 0x1000;
-
-	/* Turn on shared memory */
-	writereg_io(dev, PP_BusCTL, MEMORY_ON);
-
-	/* get the chip type */
-	rev_type = readreg(dev, PRODUCT_ID_ADD);
-	lp->chip_type = rev_type &~ REVISON_BITS;
-	lp->chip_revision = ((rev_type & REVISON_BITS) >> 8) + 'A';
-
-	/* Check the chip type and revision in order to set the correct send command
-	CS8920 revision C and CS8900 revision F can use the faster send. */
-	lp->send_cmd = TX_AFTER_381;
-	if (lp->chip_type == CS8900 && lp->chip_revision >= 'F')
-		lp->send_cmd = TX_NOW;
-	if (lp->chip_type != CS8900 && lp->chip_revision >= 'C')
-		lp->send_cmd = TX_NOW;
-
-	netif_dbg(lp, drv, dev, "%s", version);
-
-	pr_info("cs89%c0%s rev %c found at %#8lx\n",
-		lp->chip_type == CS8900 ? '0' : '2',
-		lp->chip_type == CS8920M ? "M" : "",
-		lp->chip_revision, dev->base_addr);
-
-	/* Try to read the MAC address */
-	if ((readreg(dev, PP_SelfST) & (EEPROM_PRESENT | EEPROM_OK)) == 0) {
-		pr_info("No EEPROM, giving up now.\n");
-		goto out1;
-        } else {
-		u8 addr[ETH_ALEN];
-
-                for (i = 0; i < ETH_ALEN; i += 2) {
-			/* Big-endian (why??!) */
-			unsigned short s = readreg(dev, PP_IA + i);
-			addr[i] = s >> 8;
-			addr[i+1] = s & 0xff;
-                }
-		eth_hw_addr_set(dev, addr);
-        }
-
-	dev->irq = SLOT2IRQ(slot);
-
-	/* print the IRQ and ethernet address. */
-
-	pr_info("MAC %pM, IRQ %d\n", dev->dev_addr, dev->irq);
-
-	dev->netdev_ops		= &mac89x0_netdev_ops;
-
-	err = register_netdev(dev);
-	if (err)
-		goto out1;
-
-	platform_set_drvdata(pdev, dev);
-	return 0;
-out1:
-	nubus_writew(0, dev->base_addr + ADD_PORT);
-out:
-	free_netdev(dev);
-	return err;
-}
-
-/* Open/initialize the board.  This is called (in the current kernel)
-   sometime after booting when the 'ifconfig' program is run.
-
-   This routine should set everything up anew at each open, even
-   registers that "should" only need to be set once at boot, so that
-   there is non-reboot way to recover if something goes wrong.
-   */
-static int
-net_open(struct net_device *dev)
-{
-	struct net_local *lp = netdev_priv(dev);
-	int i;
-
-	/* Disable the interrupt for now */
-	writereg(dev, PP_BusCTL, readreg(dev, PP_BusCTL) & ~ENABLE_IRQ);
-
-	/* Grab the interrupt */
-	if (request_irq(dev->irq, net_interrupt, 0, "cs89x0", dev))
-		return -EAGAIN;
-
-	/* Set up the IRQ - Apparently magic */
-	if (lp->chip_type == CS8900)
-		writereg(dev, PP_CS8900_ISAINT, 0);
-	else
-		writereg(dev, PP_CS8920_ISAINT, 0);
-
-	/* set the Ethernet address */
-	for (i=0; i < ETH_ALEN/2; i++)
-		writereg(dev, PP_IA+i*2, dev->dev_addr[i*2] | (dev->dev_addr[i*2+1] << 8));
-
-	/* Turn on both receive and transmit operations */
-	writereg(dev, PP_LineCTL, readreg(dev, PP_LineCTL) | SERIAL_RX_ON | SERIAL_TX_ON);
-
-	/* Receive only error free packets addressed to this card */
-	lp->rx_mode = 0;
-	writereg(dev, PP_RxCTL, DEF_RX_ACCEPT);
-
-	lp->curr_rx_cfg = RX_OK_ENBL | RX_CRC_ERROR_ENBL;
-
-	writereg(dev, PP_RxCFG, lp->curr_rx_cfg);
-
-	writereg(dev, PP_TxCFG, TX_LOST_CRS_ENBL | TX_SQE_ERROR_ENBL | TX_OK_ENBL |
-	       TX_LATE_COL_ENBL | TX_JBR_ENBL | TX_ANY_COL_ENBL | TX_16_COL_ENBL);
-
-	writereg(dev, PP_BufCFG, READY_FOR_TX_ENBL | RX_MISS_COUNT_OVRFLOW_ENBL |
-		 TX_COL_COUNT_OVRFLOW_ENBL | TX_UNDERRUN_ENBL);
-
-	/* now that we've got our act together, enable everything */
-	writereg(dev, PP_BusCTL, readreg(dev, PP_BusCTL) | ENABLE_IRQ);
-	netif_start_queue(dev);
-	return 0;
-}
-
-static netdev_tx_t
-net_send_packet(struct sk_buff *skb, struct net_device *dev)
-{
-	struct net_local *lp = netdev_priv(dev);
-	unsigned long flags;
-
-	netif_dbg(lp, tx_queued, dev, "sent %d byte packet of type %x\n",
-		  skb->len, skb->data[ETH_ALEN + ETH_ALEN] << 8 |
-		  skb->data[ETH_ALEN + ETH_ALEN + 1]);
-
-	/* keep the upload from being interrupted, since we
-	   ask the chip to start transmitting before the
-	   whole packet has been completely uploaded. */
-	local_irq_save(flags);
-	netif_stop_queue(dev);
-
-	/* initiate a transmit sequence */
-	writereg(dev, PP_TxCMD, lp->send_cmd);
-	writereg(dev, PP_TxLength, skb->len);
-
-	/* Test to see if the chip has allocated memory for the packet */
-	if ((readreg(dev, PP_BusST) & READY_FOR_TX_NOW) == 0) {
-		/* Gasp!  It hasn't.  But that shouldn't happen since
-		   we're waiting for TxOk, so return 1 and requeue this packet. */
-		local_irq_restore(flags);
-		return NETDEV_TX_BUSY;
-	}
-
-	/* Write the contents of the packet */
-	skb_copy_from_linear_data(skb, (void *)(dev->mem_start + PP_TxFrame),
-				  skb->len+1);
-
-	local_irq_restore(flags);
-	dev_kfree_skb (skb);
-
-	return NETDEV_TX_OK;
-}
-
-/* The typical workload of the driver:
-   Handle the network interface interrupts. */
-static irqreturn_t net_interrupt(int irq, void *dev_id)
-{
-	struct net_device *dev = dev_id;
-	struct net_local *lp;
-	int ioaddr, status;
-
-	ioaddr = dev->base_addr;
-	lp = netdev_priv(dev);
-
-	/* we MUST read all the events out of the ISQ, otherwise we'll never
-           get interrupted again.  As a consequence, we can't have any limit
-           on the number of times we loop in the interrupt handler.  The
-           hardware guarantees that eventually we'll run out of events.  Of
-           course, if you're on a slow machine, and packets are arriving
-           faster than you can read them off, you're screwed.  Hasta la
-           vista, baby!  */
-	while ((status = swab16(nubus_readw(dev->base_addr + ISQ_PORT)))) {
-		netif_dbg(lp, intr, dev, "status=%04x\n", status);
-		switch(status & ISQ_EVENT_MASK) {
-		case ISQ_RECEIVER_EVENT:
-			/* Got a packet(s). */
-			net_rx(dev);
-			break;
-		case ISQ_TRANSMITTER_EVENT:
-			dev->stats.tx_packets++;
-			netif_wake_queue(dev);
-			if ((status & TX_OK) == 0)
-				dev->stats.tx_errors++;
-			if (status & TX_LOST_CRS)
-				dev->stats.tx_carrier_errors++;
-			if (status & TX_SQE_ERROR)
-				dev->stats.tx_heartbeat_errors++;
-			if (status & TX_LATE_COL)
-				dev->stats.tx_window_errors++;
-			if (status & TX_16_COL)
-				dev->stats.tx_aborted_errors++;
-			break;
-		case ISQ_BUFFER_EVENT:
-			if (status & READY_FOR_TX) {
-				/* we tried to transmit a packet earlier,
-                                   but inexplicably ran out of buffers.
-                                   That shouldn't happen since we only ever
-                                   load one packet.  Shrug.  Do the right
-                                   thing anyway. */
-				netif_wake_queue(dev);
-			}
-			if (status & TX_UNDERRUN) {
-				netif_dbg(lp, tx_err, dev, "transmit underrun\n");
-                                lp->send_underrun++;
-                                if (lp->send_underrun == 3) lp->send_cmd = TX_AFTER_381;
-                                else if (lp->send_underrun == 6) lp->send_cmd = TX_AFTER_ALL;
-                        }
-			break;
-		case ISQ_RX_MISS_EVENT:
-			dev->stats.rx_missed_errors += (status >> 6);
-			break;
-		case ISQ_TX_COL_EVENT:
-			dev->stats.collisions += (status >> 6);
-			break;
-		}
-	}
-	return IRQ_HANDLED;
-}
-
-/* We have a good packet(s), get it/them out of the buffers. */
-static void
-net_rx(struct net_device *dev)
-{
-	struct net_local *lp = netdev_priv(dev);
-	struct sk_buff *skb;
-	int status, length;
-
-	status = readreg(dev, PP_RxStatus);
-	if ((status & RX_OK) == 0) {
-		dev->stats.rx_errors++;
-		if (status & RX_RUNT)
-				dev->stats.rx_length_errors++;
-		if (status & RX_EXTRA_DATA)
-				dev->stats.rx_length_errors++;
-		if ((status & RX_CRC_ERROR) &&
-		    !(status & (RX_EXTRA_DATA|RX_RUNT)))
-			/* per str 172 */
-			dev->stats.rx_crc_errors++;
-		if (status & RX_DRIBBLE)
-				dev->stats.rx_frame_errors++;
-		return;
-	}
-
-	length = readreg(dev, PP_RxLength);
-	/* Malloc up new buffer. */
-	skb = alloc_skb(length, GFP_ATOMIC);
-	if (skb == NULL) {
-		dev->stats.rx_dropped++;
-		return;
-	}
-	skb_put(skb, length);
-
-	skb_copy_to_linear_data(skb, (void *)(dev->mem_start + PP_RxFrame),
-				length);
-
-	netif_dbg(lp, rx_status, dev, "received %d byte packet of type %x\n",
-		  length, skb->data[ETH_ALEN + ETH_ALEN] << 8 |
-		  skb->data[ETH_ALEN + ETH_ALEN + 1]);
-
-        skb->protocol=eth_type_trans(skb,dev);
-	netif_rx(skb);
-	dev->stats.rx_packets++;
-	dev->stats.rx_bytes += length;
-}
-
-/* The inverse routine to net_open(). */
-static int
-net_close(struct net_device *dev)
-{
-
-	writereg(dev, PP_RxCFG, 0);
-	writereg(dev, PP_TxCFG, 0);
-	writereg(dev, PP_BufCFG, 0);
-	writereg(dev, PP_BusCTL, 0);
-
-	netif_stop_queue(dev);
-
-	free_irq(dev->irq, dev);
-
-	/* Update the statistics here. */
-
-	return 0;
-
-}
-
-/* Get the current statistics.	This may be called with the card open or
-   closed. */
-static struct net_device_stats *
-net_get_stats(struct net_device *dev)
-{
-	unsigned long flags;
-
-	local_irq_save(flags);
-	/* Update the statistics from the device registers. */
-	dev->stats.rx_missed_errors += (readreg(dev, PP_RxMiss) >> 6);
-	dev->stats.collisions += (readreg(dev, PP_TxCol) >> 6);
-	local_irq_restore(flags);
-
-	return &dev->stats;
-}
-
-static void set_multicast_list(struct net_device *dev)
-{
-	struct net_local *lp = netdev_priv(dev);
-
-	if(dev->flags&IFF_PROMISC)
-	{
-		lp->rx_mode = RX_ALL_ACCEPT;
-	} else if ((dev->flags & IFF_ALLMULTI) || !netdev_mc_empty(dev)) {
-		/* The multicast-accept list is initialized to accept-all, and we
-		   rely on higher-level filtering for now. */
-		lp->rx_mode = RX_MULTCAST_ACCEPT;
-	}
-	else
-		lp->rx_mode = 0;
-
-	writereg(dev, PP_RxCTL, DEF_RX_ACCEPT | lp->rx_mode);
-
-	/* in promiscuous mode, we accept errored packets, so we have to enable interrupts on them also */
-	writereg(dev, PP_RxCFG, lp->curr_rx_cfg |
-	     (lp->rx_mode == RX_ALL_ACCEPT? (RX_CRC_ERROR_ENBL|RX_RUNT_ENBL|RX_EXTRA_DATA_ENBL) : 0));
-}
-
-
-static int set_mac_address(struct net_device *dev, void *addr)
-{
-	struct sockaddr *saddr = addr;
-	int i;
-
-	if (!is_valid_ether_addr(saddr->sa_data))
-		return -EADDRNOTAVAIL;
-
-	eth_hw_addr_set(dev, saddr->sa_data);
-	netdev_info(dev, "Setting MAC address to %pM\n", dev->dev_addr);
-
-	/* set the Ethernet address */
-	for (i=0; i < ETH_ALEN/2; i++)
-		writereg(dev, PP_IA+i*2, dev->dev_addr[i*2] | (dev->dev_addr[i*2+1] << 8));
-
-	return 0;
-}
-
-MODULE_DESCRIPTION("Macintosh CS89x0-based Ethernet driver");
-MODULE_LICENSE("GPL");
-
-static void mac89x0_device_remove(struct platform_device *pdev)
-{
-	struct net_device *dev = platform_get_drvdata(pdev);
-
-	unregister_netdev(dev);
-	nubus_writew(0, dev->base_addr + ADD_PORT);
-	free_netdev(dev);
-}
-
-static struct platform_driver mac89x0_platform_driver = {
-	.probe = mac89x0_device_probe,
-	.remove = mac89x0_device_remove,
-	.driver = {
-		.name = "mac89x0",
-	},
-};
-
-module_platform_driver(mac89x0_platform_driver);

-- 
2.53.0


^ permalink raw reply related	[flat|nested] 28+ messages in thread

* [PATCH net 13/18] drivers: net: fujitsu: fmvj18x: Remove this driver
  2026-04-21 19:31 [PATCH net 00/18] Remove a number of ISA and PCMCIA Ethernet drivers Andrew Lunn
                   ` (11 preceding siblings ...)
  2026-04-21 19:31 ` [PATCH net 12/18] drivers: net: cirrus: mac89x0: " Andrew Lunn
@ 2026-04-21 19:31 ` Andrew Lunn
  2026-04-21 19:31 ` [PATCH net 14/18] drivers: net: xircom: xirc2ps: " Andrew Lunn
                   ` (8 subsequent siblings)
  21 siblings, 0 replies; 28+ messages in thread
From: Andrew Lunn @ 2026-04-21 19:31 UTC (permalink / raw)
  To: Andrew Lunn, David S. Miller, Eric Dumazet, Jakub Kicinski,
	Paolo Abeni, Simon Horman, Jonathan Corbet, Shuah Khan
  Cc: linux-kernel, netdev, linux-doc, Andrew Lunn

The fmvj18x was written by Shingo Fujimoto in 2002. It is an PCMCIA
device, so unlikely to be used with modern kernels.

Signed-off-by: Andrew Lunn <andrew@lunn.ch>
---
 drivers/net/ethernet/Kconfig              |    1 -
 drivers/net/ethernet/fujitsu/Kconfig      |   30 -
 drivers/net/ethernet/fujitsu/Makefile     |    6 -
 drivers/net/ethernet/fujitsu/fmvj18x_cs.c | 1176 -----------------------------
 4 files changed, 1213 deletions(-)

diff --git a/drivers/net/ethernet/Kconfig b/drivers/net/ethernet/Kconfig
index bdc29d143160..c94e8f27af94 100644
--- a/drivers/net/ethernet/Kconfig
+++ b/drivers/net/ethernet/Kconfig
@@ -61,7 +61,6 @@ source "drivers/net/ethernet/engleder/Kconfig"
 source "drivers/net/ethernet/ezchip/Kconfig"
 source "drivers/net/ethernet/faraday/Kconfig"
 source "drivers/net/ethernet/freescale/Kconfig"
-source "drivers/net/ethernet/fujitsu/Kconfig"
 source "drivers/net/ethernet/fungible/Kconfig"
 source "drivers/net/ethernet/google/Kconfig"
 source "drivers/net/ethernet/hisilicon/Kconfig"
diff --git a/drivers/net/ethernet/fujitsu/Kconfig b/drivers/net/ethernet/fujitsu/Kconfig
deleted file mode 100644
index 06a28bce5d27..000000000000
--- a/drivers/net/ethernet/fujitsu/Kconfig
+++ /dev/null
@@ -1,30 +0,0 @@
-# SPDX-License-Identifier: GPL-2.0-only
-#
-# Fujitsu Network device configuration
-#
-
-config NET_VENDOR_FUJITSU
-	bool "Fujitsu devices"
-	default y
-	depends on PCMCIA
-	help
-	  If you have a network (Ethernet) card belonging to this class, say Y.
-
-	  Note that the answer to this question doesn't directly affect the
-	  the questions about Fujitsu cards. If you say Y, you will be asked for
-	  your specific card in the following questions.
-
-if NET_VENDOR_FUJITSU
-
-config PCMCIA_FMVJ18X
-	tristate "Fujitsu FMV-J18x PCMCIA support"
-	depends on PCMCIA && HAS_IOPORT
-	select CRC32
-	help
-	  Say Y here if you intend to attach a Fujitsu FMV-J18x or compatible
-	  PCMCIA (PC-card) Ethernet card to your computer.
-
-	  To compile this driver as a module, choose M here: the module will be
-	  called fmvj18x_cs.  If unsure, say N.
-
-endif # NET_VENDOR_FUJITSU
diff --git a/drivers/net/ethernet/fujitsu/Makefile b/drivers/net/ethernet/fujitsu/Makefile
deleted file mode 100644
index 74feebbf4572..000000000000
--- a/drivers/net/ethernet/fujitsu/Makefile
+++ /dev/null
@@ -1,6 +0,0 @@
-# SPDX-License-Identifier: GPL-2.0-only
-#
-# Makefile for the Fujitsu network device drivers.
-#
-
-obj-$(CONFIG_PCMCIA_FMVJ18X) += fmvj18x_cs.o
diff --git a/drivers/net/ethernet/fujitsu/fmvj18x_cs.c b/drivers/net/ethernet/fujitsu/fmvj18x_cs.c
deleted file mode 100644
index 4859493471db..000000000000
--- a/drivers/net/ethernet/fujitsu/fmvj18x_cs.c
+++ /dev/null
@@ -1,1176 +0,0 @@
-/*======================================================================
-    fmvj18x_cs.c 2.8 2002/03/23
-
-    A fmvj18x (and its compatibles) PCMCIA client driver
-
-    Contributed by Shingo Fujimoto, shingo@flab.fujitsu.co.jp
-
-    TDK LAK-CD021 and CONTEC C-NET(PC)C support added by 
-    Nobuhiro Katayama, kata-n@po.iijnet.or.jp
-
-    The PCMCIA client code is based on code written by David Hinds.
-    Network code is based on the "FMV-18x driver" by Yutaka TAMIYA
-    but is actually largely Donald Becker's AT1700 driver, which
-    carries the following attribution:
-
-    Written 1993-94 by Donald Becker.
-
-    Copyright 1993 United States Government as represented by the
-    Director, National Security Agency.
-    
-    This software may be used and distributed according to the terms
-    of the GNU General Public License, incorporated herein by reference.
-    
-    The author may be reached as becker@scyld.com, or C/O
-    Scyld Computing Corporation
-    410 Severn Ave., Suite 210
-    Annapolis MD 21403
-   
-======================================================================*/
-
-#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
-
-#define DRV_NAME	"fmvj18x_cs"
-#define DRV_VERSION	"2.9"
-
-#include <linux/module.h>
-#include <linux/kernel.h>
-#include <linux/ptrace.h>
-#include <linux/slab.h>
-#include <linux/string.h>
-#include <linux/timer.h>
-#include <linux/interrupt.h>
-#include <linux/in.h>
-#include <linux/delay.h>
-#include <linux/ethtool.h>
-#include <linux/netdevice.h>
-#include <linux/etherdevice.h>
-#include <linux/skbuff.h>
-#include <linux/if_arp.h>
-#include <linux/ioport.h>
-#include <linux/crc32.h>
-
-#include <pcmcia/cistpl.h>
-#include <pcmcia/ciscode.h>
-#include <pcmcia/ds.h>
-
-#include <linux/uaccess.h>
-#include <asm/io.h>
-
-/*====================================================================*/
-
-/* Module parameters */
-
-MODULE_DESCRIPTION("fmvj18x and compatible PCMCIA ethernet driver");
-MODULE_LICENSE("GPL");
-
-#define INT_MODULE_PARM(n, v) static int n = v; module_param(n, int, 0)
-
-/* SRAM configuration */
-/* 0:4KB*2 TX buffer   else:8KB*2 TX buffer */
-INT_MODULE_PARM(sram_config, 0);
-
-
-/*====================================================================*/
-/*
-    PCMCIA event handlers
- */
-static int fmvj18x_config(struct pcmcia_device *link);
-static int fmvj18x_get_hwinfo(struct pcmcia_device *link, u_char *node_id);
-static int fmvj18x_setup_mfc(struct pcmcia_device *link);
-static void fmvj18x_release(struct pcmcia_device *link);
-static void fmvj18x_detach(struct pcmcia_device *p_dev);
-
-/*
-    LAN controller(MBH86960A) specific routines
- */
-static int fjn_config(struct net_device *dev, struct ifmap *map);
-static int fjn_open(struct net_device *dev);
-static int fjn_close(struct net_device *dev);
-static netdev_tx_t fjn_start_xmit(struct sk_buff *skb,
-					struct net_device *dev);
-static irqreturn_t fjn_interrupt(int irq, void *dev_id);
-static void fjn_rx(struct net_device *dev);
-static void fjn_reset(struct net_device *dev);
-static void set_rx_mode(struct net_device *dev);
-static void fjn_tx_timeout(struct net_device *dev, unsigned int txqueue);
-static const struct ethtool_ops netdev_ethtool_ops;
-
-/*
-    card type
- */
-enum cardtype { MBH10302, MBH10304, TDK, CONTEC, LA501, UNGERMANN,
-	       XXX10304, NEC, KME
-};
-
-/*
-    driver specific data structure
-*/
-struct local_info {
-	struct pcmcia_device	*p_dev;
-    long open_time;
-    uint tx_started:1;
-    uint tx_queue;
-    u_short tx_queue_len;
-    enum cardtype cardtype;
-    u_short sent;
-    u_char __iomem *base;
-};
-
-#define MC_FILTERBREAK 64
-
-/*====================================================================*/
-/* 
-    ioport offset from the base address 
- */
-#define TX_STATUS               0 /* transmit status register */
-#define RX_STATUS               1 /* receive status register */
-#define TX_INTR                 2 /* transmit interrupt mask register */
-#define RX_INTR                 3 /* receive interrupt mask register */
-#define TX_MODE                 4 /* transmit mode register */
-#define RX_MODE                 5 /* receive mode register */
-#define CONFIG_0                6 /* configuration register 0 */
-#define CONFIG_1                7 /* configuration register 1 */
-
-#define NODE_ID                 8 /* node ID register            (bank 0) */
-#define MAR_ADR                 8 /* multicast address registers (bank 1) */
-
-#define DATAPORT                8 /* buffer mem port registers   (bank 2) */
-#define TX_START               10 /* transmit start register */
-#define COL_CTRL               11 /* 16 collision control register */
-#define BMPR12                 12 /* reserved */
-#define BMPR13                 13 /* reserved */
-#define RX_SKIP                14 /* skip received packet register */
-
-#define LAN_CTRL               16 /* LAN card control register */
-
-#define MAC_ID               0x1a /* hardware address */
-#define UNGERMANN_MAC_ID     0x18 /* UNGERMANN-BASS hardware address */
-
-/* 
-    control bits 
- */
-#define ENA_TMT_OK           0x80
-#define ENA_TMT_REC          0x20
-#define ENA_COL              0x04
-#define ENA_16_COL           0x02
-#define ENA_TBUS_ERR         0x01
-
-#define ENA_PKT_RDY          0x80
-#define ENA_BUS_ERR          0x40
-#define ENA_LEN_ERR          0x08
-#define ENA_ALG_ERR          0x04
-#define ENA_CRC_ERR          0x02
-#define ENA_OVR_FLO          0x01
-
-/* flags */
-#define F_TMT_RDY            0x80 /* can accept new packet */
-#define F_NET_BSY            0x40 /* carrier is detected */
-#define F_TMT_OK             0x20 /* send packet successfully */
-#define F_SRT_PKT            0x10 /* short packet error */
-#define F_COL_ERR            0x04 /* collision error */
-#define F_16_COL             0x02 /* 16 collision error */
-#define F_TBUS_ERR           0x01 /* bus read error */
-
-#define F_PKT_RDY            0x80 /* packet(s) in buffer */
-#define F_BUS_ERR            0x40 /* bus read error */
-#define F_LEN_ERR            0x08 /* short packet */
-#define F_ALG_ERR            0x04 /* frame error */
-#define F_CRC_ERR            0x02 /* CRC error */
-#define F_OVR_FLO            0x01 /* overflow error */
-
-#define F_BUF_EMP            0x40 /* receive buffer is empty */
-
-#define F_SKP_PKT            0x05 /* drop packet in buffer */
-
-/* default bitmaps */
-#define D_TX_INTR  ( ENA_TMT_OK )
-#define D_RX_INTR  ( ENA_PKT_RDY | ENA_LEN_ERR \
-		   | ENA_ALG_ERR | ENA_CRC_ERR | ENA_OVR_FLO )
-#define TX_STAT_M  ( F_TMT_RDY )
-#define RX_STAT_M  ( F_PKT_RDY | F_LEN_ERR \
-                   | F_ALG_ERR | F_CRC_ERR | F_OVR_FLO )
-
-/* commands */
-#define D_TX_MODE            0x06 /* no tests, detect carrier */
-#define ID_MATCHED           0x02 /* (RX_MODE) */
-#define RECV_ALL             0x03 /* (RX_MODE) */
-#define CONFIG0_DFL          0x5a /* 16bit bus, 4K x 2 Tx queues */
-#define CONFIG0_DFL_1        0x5e /* 16bit bus, 8K x 2 Tx queues */
-#define CONFIG0_RST          0xda /* Data Link Controller off (CONFIG_0) */
-#define CONFIG0_RST_1        0xde /* Data Link Controller off (CONFIG_0) */
-#define BANK_0               0xa0 /* bank 0 (CONFIG_1) */
-#define BANK_1               0xa4 /* bank 1 (CONFIG_1) */
-#define BANK_2               0xa8 /* bank 2 (CONFIG_1) */
-#define CHIP_OFF             0x80 /* contrl chip power off (CONFIG_1) */
-#define DO_TX                0x80 /* do transmit packet */
-#define SEND_PKT             0x81 /* send a packet */
-#define AUTO_MODE            0x07 /* Auto skip packet on 16 col detected */
-#define MANU_MODE            0x03 /* Stop and skip packet on 16 col */
-#define TDK_AUTO_MODE        0x47 /* Auto skip packet on 16 col detected */
-#define TDK_MANU_MODE        0x43 /* Stop and skip packet on 16 col */
-#define INTR_OFF             0x0d /* LAN controller ignores interrupts */
-#define INTR_ON              0x1d /* LAN controller will catch interrupts */
-
-#define TX_TIMEOUT		((400*HZ)/1000)
-
-#define BANK_0U              0x20 /* bank 0 (CONFIG_1) */
-#define BANK_1U              0x24 /* bank 1 (CONFIG_1) */
-#define BANK_2U              0x28 /* bank 2 (CONFIG_1) */
-
-static const struct net_device_ops fjn_netdev_ops = {
-	.ndo_open 		= fjn_open,
-	.ndo_stop		= fjn_close,
-	.ndo_start_xmit 	= fjn_start_xmit,
-	.ndo_tx_timeout 	= fjn_tx_timeout,
-	.ndo_set_config 	= fjn_config,
-	.ndo_set_rx_mode	= set_rx_mode,
-	.ndo_set_mac_address 	= eth_mac_addr,
-	.ndo_validate_addr	= eth_validate_addr,
-};
-
-static int fmvj18x_probe(struct pcmcia_device *link)
-{
-    struct local_info *lp;
-    struct net_device *dev;
-
-    dev_dbg(&link->dev, "fmvj18x_attach()\n");
-
-    /* Make up a FMVJ18x specific data structure */
-    dev = alloc_etherdev(sizeof(struct local_info));
-    if (!dev)
-	return -ENOMEM;
-    lp = netdev_priv(dev);
-    link->priv = dev;
-    lp->p_dev = link;
-    lp->base = NULL;
-
-    /* The io structure describes IO port mapping */
-    link->resource[0]->end = 32;
-    link->resource[0]->flags |= IO_DATA_PATH_WIDTH_AUTO;
-
-    /* General socket configuration */
-    link->config_flags |= CONF_ENABLE_IRQ;
-
-    dev->netdev_ops = &fjn_netdev_ops;
-    dev->watchdog_timeo = TX_TIMEOUT;
-
-    dev->ethtool_ops = &netdev_ethtool_ops;
-
-    return fmvj18x_config(link);
-} /* fmvj18x_attach */
-
-/*====================================================================*/
-
-static void fmvj18x_detach(struct pcmcia_device *link)
-{
-    struct net_device *dev = link->priv;
-
-    dev_dbg(&link->dev, "fmvj18x_detach\n");
-
-    unregister_netdev(dev);
-
-    fmvj18x_release(link);
-
-    free_netdev(dev);
-} /* fmvj18x_detach */
-
-/*====================================================================*/
-
-static int mfc_try_io_port(struct pcmcia_device *link)
-{
-    int i, ret;
-    static const unsigned int serial_base[5] =
-	{ 0x3f8, 0x2f8, 0x3e8, 0x2e8, 0x0 };
-
-    for (i = 0; i < 5; i++) {
-	link->resource[1]->start = serial_base[i];
-	link->resource[1]->flags |= IO_DATA_PATH_WIDTH_8;
-	if (link->resource[1]->start == 0) {
-	    link->resource[1]->end = 0;
-	    pr_notice("out of resource for serial\n");
-	}
-	ret = pcmcia_request_io(link);
-	if (ret == 0)
-		return ret;
-    }
-    return ret;
-}
-
-static int ungermann_try_io_port(struct pcmcia_device *link)
-{
-    int ret;
-    unsigned int ioaddr;
-    /*
-	Ungermann-Bass Access/CARD accepts 0x300,0x320,0x340,0x360
-	0x380,0x3c0 only for ioport.
-    */
-    for (ioaddr = 0x300; ioaddr < 0x3e0; ioaddr += 0x20) {
-	link->resource[0]->start = ioaddr;
-	ret = pcmcia_request_io(link);
-	if (ret == 0) {
-	    /* calculate ConfigIndex value */
-	    link->config_index =
-		((link->resource[0]->start & 0x0f0) >> 3) | 0x22;
-	    return ret;
-	}
-    }
-    return ret;	/* RequestIO failed */
-}
-
-static int fmvj18x_ioprobe(struct pcmcia_device *p_dev, void *priv_data)
-{
-	return 0; /* strange, but that's what the code did already before... */
-}
-
-static int fmvj18x_config(struct pcmcia_device *link)
-{
-    struct net_device *dev = link->priv;
-    struct local_info *lp = netdev_priv(dev);
-    int i, ret;
-    unsigned int ioaddr;
-    enum cardtype cardtype;
-    char *card_name = "unknown";
-    u8 *buf;
-    size_t len;
-    u_char buggybuf[32];
-    u8 addr[ETH_ALEN];
-
-    dev_dbg(&link->dev, "fmvj18x_config\n");
-
-    link->io_lines = 5;
-
-    len = pcmcia_get_tuple(link, CISTPL_FUNCE, &buf);
-    kfree(buf);
-
-    if (len) {
-	/* Yes, I have CISTPL_FUNCE. Let's check CISTPL_MANFID */
-	ret = pcmcia_loop_config(link, fmvj18x_ioprobe, NULL);
-	if (ret != 0)
-		goto failed;
-
-	switch (link->manf_id) {
-	case MANFID_TDK:
-	    cardtype = TDK;
-	    if (link->card_id == PRODID_TDK_GN3410 ||
-		link->card_id == PRODID_TDK_NP9610 ||
-		link->card_id == PRODID_TDK_MN3200) {
-		/* MultiFunction Card */
-		link->config_base = 0x800;
-		link->config_index = 0x47;
-		link->resource[1]->end = 8;
-	    }
-	    break;
-	case MANFID_NEC:
-	    cardtype = NEC; /* MultiFunction Card */
-	    link->config_base = 0x800;
-	    link->config_index = 0x47;
-	    link->resource[1]->end = 8;
-	    break;
-	case MANFID_KME:
-	    cardtype = KME; /* MultiFunction Card */
-	    link->config_base = 0x800;
-	    link->config_index = 0x47;
-	    link->resource[1]->end = 8;
-	    break;
-	case MANFID_CONTEC:
-	    cardtype = CONTEC;
-	    break;
-	case MANFID_FUJITSU:
-	    if (link->config_base == 0x0fe0)
-		cardtype = MBH10302;
-	    else if (link->card_id == PRODID_FUJITSU_MBH10302) 
-                /* RATOC REX-5588/9822/4886's PRODID are 0004(=MBH10302),
-                   but these are MBH10304 based card. */ 
-		cardtype = MBH10304;
-	    else if (link->card_id == PRODID_FUJITSU_MBH10304)
-		cardtype = MBH10304;
-	    else
-		cardtype = LA501;
-	    break;
-	default:
-	    cardtype = MBH10304;
-	}
-    } else {
-	/* old type card */
-	switch (link->manf_id) {
-	case MANFID_FUJITSU:
-	    if (link->card_id == PRODID_FUJITSU_MBH10304) {
-		cardtype = XXX10304;    /* MBH10304 with buggy CIS */
-		link->config_index = 0x20;
-	    } else {
-		cardtype = MBH10302;    /* NextCom NC5310, etc. */
-		link->config_index = 1;
-	    }
-	    break;
-	case MANFID_UNGERMANN:
-	    cardtype = UNGERMANN;
-	    break;
-	default:
-	    cardtype = MBH10302;
-	    link->config_index = 1;
-	}
-    }
-
-    if (link->resource[1]->end != 0) {
-	ret = mfc_try_io_port(link);
-	if (ret != 0) goto failed;
-    } else if (cardtype == UNGERMANN) {
-	ret = ungermann_try_io_port(link);
-	if (ret != 0) goto failed;
-    } else { 
-	    ret = pcmcia_request_io(link);
-	    if (ret)
-		    goto failed;
-    }
-    ret = pcmcia_request_irq(link, fjn_interrupt);
-    if (ret)
-	    goto failed;
-    ret = pcmcia_enable_device(link);
-    if (ret)
-	    goto failed;
-
-    dev->irq = link->irq;
-    dev->base_addr = link->resource[0]->start;
-
-    if (resource_size(link->resource[1]) != 0) {
-	ret = fmvj18x_setup_mfc(link);
-	if (ret != 0) goto failed;
-    }
-
-    ioaddr = dev->base_addr;
-
-    /* Reset controller */
-    if (sram_config == 0) 
-	outb(CONFIG0_RST, ioaddr + CONFIG_0);
-    else
-	outb(CONFIG0_RST_1, ioaddr + CONFIG_0);
-
-    /* Power On chip and select bank 0 */
-    if (cardtype == MBH10302)
-	outb(BANK_0, ioaddr + CONFIG_1);
-    else
-	outb(BANK_0U, ioaddr + CONFIG_1);
-    
-    /* Set hardware address */
-    switch (cardtype) {
-    case MBH10304:
-    case TDK:
-    case LA501:
-    case CONTEC:
-    case NEC:
-    case KME:
-	if (cardtype == MBH10304) {
-	    card_name = "FMV-J182";
-
-	    len = pcmcia_get_tuple(link, CISTPL_FUNCE, &buf);
-	    if (len < 11) {
-		    kfree(buf);
-		    goto failed;
-	    }
-	    /* Read MACID from CIS */
-	    eth_hw_addr_set(dev, &buf[5]);
-	    kfree(buf);
-	} else {
-	    if (pcmcia_get_mac_from_cis(link, dev))
-		goto failed;
-	    if( cardtype == TDK ) {
-		card_name = "TDK LAK-CD021";
-	    } else if( cardtype == LA501 ) {
-		card_name = "LA501";
-	    } else if( cardtype == NEC ) {
-		card_name = "PK-UG-J001";
-	    } else if( cardtype == KME ) {
-		card_name = "Panasonic";
-	    } else {
-		card_name = "C-NET(PC)C";
-	    }
-	}
-	break;
-    case UNGERMANN:
-	/* Read MACID from register */
-	for (i = 0; i < 6; i++) 
-	    addr[i] = inb(ioaddr + UNGERMANN_MAC_ID + i);
-	eth_hw_addr_set(dev, addr);
-	card_name = "Access/CARD";
-	break;
-    case XXX10304:
-	/* Read MACID from Buggy CIS */
-	if (fmvj18x_get_hwinfo(link, buggybuf) == -1) {
-	    pr_notice("unable to read hardware net address\n");
-	    goto failed;
-	}
-	eth_hw_addr_set(dev, buggybuf);
-	card_name = "FMV-J182";
-	break;
-    case MBH10302:
-    default:
-	/* Read MACID from register */
-	for (i = 0; i < 6; i++) 
-	    addr[i] = inb(ioaddr + MAC_ID + i);
-	eth_hw_addr_set(dev, addr);
-	card_name = "FMV-J181";
-	break;
-    }
-
-    lp->cardtype = cardtype;
-    SET_NETDEV_DEV(dev, &link->dev);
-
-    if (register_netdev(dev) != 0) {
-	pr_notice("register_netdev() failed\n");
-	goto failed;
-    }
-
-    /* print current configuration */
-    netdev_info(dev, "%s, sram %s, port %#3lx, irq %d, hw_addr %pM\n",
-		card_name, sram_config == 0 ? "4K TX*2" : "8K TX*2",
-		dev->base_addr, dev->irq, dev->dev_addr);
-
-    return 0;
-    
-failed:
-    fmvj18x_release(link);
-    return -ENODEV;
-} /* fmvj18x_config */
-/*====================================================================*/
-
-static int fmvj18x_get_hwinfo(struct pcmcia_device *link, u_char *node_id)
-{
-    u_char __iomem *base;
-    int i, j;
-
-    /* Allocate a small memory window */
-    link->resource[2]->flags |= WIN_DATA_WIDTH_8|WIN_MEMORY_TYPE_AM|WIN_ENABLE;
-    link->resource[2]->start = 0; link->resource[2]->end = 0;
-    i = pcmcia_request_window(link, link->resource[2], 0);
-    if (i != 0)
-	return -1;
-
-    base = ioremap(link->resource[2]->start, resource_size(link->resource[2]));
-    if (!base) {
-	pcmcia_release_window(link, link->resource[2]);
-	return -1;
-    }
-
-    pcmcia_map_mem_page(link, link->resource[2], 0);
-
-    /*
-     *  MBH10304 CISTPL_FUNCE_LAN_NODE_ID format
-     *  22 0d xx xx xx 04 06 yy yy yy yy yy yy ff
-     *  'xx' is garbage.
-     *  'yy' is MAC address.
-    */ 
-    for (i = 0; i < 0x200; i++) {
-	if (readb(base+i*2) == 0x22) {	
-		if (readb(base+(i-1)*2) == 0xff &&
-		    readb(base+(i+5)*2) == 0x04 &&
-		    readb(base+(i+6)*2) == 0x06 &&
-		    readb(base+(i+13)*2) == 0xff)
-			break;
-	}
-    }
-
-    if (i != 0x200) {
-	for (j = 0 ; j < 6; j++,i++) {
-	    node_id[j] = readb(base+(i+7)*2);
-	}
-    }
-
-    iounmap(base);
-    j = pcmcia_release_window(link, link->resource[2]);
-    return (i != 0x200) ? 0 : -1;
-
-} /* fmvj18x_get_hwinfo */
-/*====================================================================*/
-
-static int fmvj18x_setup_mfc(struct pcmcia_device *link)
-{
-    int i;
-    struct net_device *dev = link->priv;
-    unsigned int ioaddr;
-    struct local_info *lp = netdev_priv(dev);
-
-    /* Allocate a small memory window */
-    link->resource[3]->flags = WIN_DATA_WIDTH_8|WIN_MEMORY_TYPE_AM|WIN_ENABLE;
-    link->resource[3]->start = link->resource[3]->end = 0;
-    i = pcmcia_request_window(link, link->resource[3], 0);
-    if (i != 0)
-	return -1;
-
-    lp->base = ioremap(link->resource[3]->start,
-		       resource_size(link->resource[3]));
-    if (lp->base == NULL) {
-	netdev_notice(dev, "ioremap failed\n");
-	return -1;
-    }
-
-    i = pcmcia_map_mem_page(link, link->resource[3], 0);
-    if (i != 0) {
-	iounmap(lp->base);
-	lp->base = NULL;
-	return -1;
-    }
-    
-    ioaddr = dev->base_addr;
-    writeb(0x47, lp->base+0x800);	/* Config Option Register of LAN */
-    writeb(0x0,  lp->base+0x802);	/* Config and Status Register */
-
-    writeb(ioaddr & 0xff, lp->base+0x80a);	  /* I/O Base(Low) of LAN */
-    writeb((ioaddr >> 8) & 0xff, lp->base+0x80c); /* I/O Base(High) of LAN */
-   
-    writeb(0x45, lp->base+0x820);	/* Config Option Register of Modem */
-    writeb(0x8,  lp->base+0x822);	/* Config and Status Register */
-
-    return 0;
-
-}
-/*====================================================================*/
-
-static void fmvj18x_release(struct pcmcia_device *link)
-{
-
-    struct net_device *dev = link->priv;
-    struct local_info *lp = netdev_priv(dev);
-    u_char __iomem *tmp;
-
-    dev_dbg(&link->dev, "fmvj18x_release\n");
-
-    if (lp->base != NULL) {
-	tmp = lp->base;
-	lp->base = NULL;    /* set NULL before iounmap */
-	iounmap(tmp);
-    }
-
-    pcmcia_disable_device(link);
-
-}
-
-static int fmvj18x_suspend(struct pcmcia_device *link)
-{
-	struct net_device *dev = link->priv;
-
-	if (link->open)
-		netif_device_detach(dev);
-
-	return 0;
-}
-
-static int fmvj18x_resume(struct pcmcia_device *link)
-{
-	struct net_device *dev = link->priv;
-
-	if (link->open) {
-		fjn_reset(dev);
-		netif_device_attach(dev);
-	}
-
-	return 0;
-}
-
-/*====================================================================*/
-
-static const struct pcmcia_device_id fmvj18x_ids[] = {
-	PCMCIA_DEVICE_MANF_CARD(0x0004, 0x0004),
-	PCMCIA_DEVICE_PROD_ID12("EAGLE Technology", "NE200 ETHERNET LAN MBH10302 04", 0x528c88c4, 0x74f91e59),
-	PCMCIA_DEVICE_PROD_ID12("Eiger Labs,Inc", "EPX-10BT PC Card Ethernet 10BT", 0x53af556e, 0x877f9922),
-	PCMCIA_DEVICE_PROD_ID12("Eiger labs,Inc.", "EPX-10BT PC Card Ethernet 10BT", 0xf47e6c66, 0x877f9922),
-	PCMCIA_DEVICE_PROD_ID12("FUJITSU", "LAN Card(FMV-J182)", 0x6ee5a3d8, 0x5baf31db),
-	PCMCIA_DEVICE_PROD_ID12("FUJITSU", "MBH10308", 0x6ee5a3d8, 0x3f04875e),
-	PCMCIA_DEVICE_PROD_ID12("FUJITSU TOWA", "LA501", 0xb8451188, 0x12939ba2),
-	PCMCIA_DEVICE_PROD_ID12("HITACHI", "HT-4840-11", 0xf4f43949, 0x773910f4),
-	PCMCIA_DEVICE_PROD_ID12("NextComK.K.", "NC5310B Ver1.0       ", 0x8cef4d3a, 0x075fc7b6),
-	PCMCIA_DEVICE_PROD_ID12("NextComK.K.", "NC5310 Ver1.0        ", 0x8cef4d3a, 0xbccf43e6),
-	PCMCIA_DEVICE_PROD_ID12("RATOC System Inc.", "10BASE_T CARD R280", 0x85c10e17, 0xd9413666),
-	PCMCIA_DEVICE_PROD_ID12("TDK", "LAC-CD02x", 0x1eae9475, 0x8fa0ee70),
-	PCMCIA_DEVICE_PROD_ID12("TDK", "LAC-CF010", 0x1eae9475, 0x7683bc9a),
-	PCMCIA_DEVICE_PROD_ID1("CONTEC Co.,Ltd.", 0x58d8fee2),
-	PCMCIA_DEVICE_PROD_ID1("PCMCIA LAN MBH10304  ES", 0x2599f454),
-	PCMCIA_DEVICE_PROD_ID1("PCMCIA MBH10302", 0x8f4005da),
-	PCMCIA_DEVICE_PROD_ID1("UBKK,V2.0", 0x90888080),
-	PCMCIA_PFC_DEVICE_PROD_ID12(0, "TDK", "GlobalNetworker 3410/3412", 0x1eae9475, 0xd9a93bed),
-	PCMCIA_PFC_DEVICE_PROD_ID12(0, "NEC", "PK-UG-J001" ,0x18df0ba0 ,0x831b1064),
-	PCMCIA_PFC_DEVICE_MANF_CARD(0, 0x0105, 0x0d0a),
-	PCMCIA_PFC_DEVICE_MANF_CARD(0, 0x0105, 0x0e0a),
-	PCMCIA_PFC_DEVICE_MANF_CARD(0, 0x0032, 0x0e01),
-	PCMCIA_PFC_DEVICE_MANF_CARD(0, 0x0032, 0x0a05),
-	PCMCIA_PFC_DEVICE_MANF_CARD(0, 0x0032, 0x0b05),
-	PCMCIA_PFC_DEVICE_MANF_CARD(0, 0x0032, 0x1101),
-	PCMCIA_DEVICE_NULL,
-};
-MODULE_DEVICE_TABLE(pcmcia, fmvj18x_ids);
-
-static struct pcmcia_driver fmvj18x_cs_driver = {
-	.owner		= THIS_MODULE,
-	.name		= "fmvj18x_cs",
-	.probe		= fmvj18x_probe,
-	.remove		= fmvj18x_detach,
-	.id_table       = fmvj18x_ids,
-	.suspend	= fmvj18x_suspend,
-	.resume		= fmvj18x_resume,
-};
-module_pcmcia_driver(fmvj18x_cs_driver);
-
-/*====================================================================*/
-
-static irqreturn_t fjn_interrupt(int dummy, void *dev_id)
-{
-    struct net_device *dev = dev_id;
-    struct local_info *lp = netdev_priv(dev);
-    unsigned int ioaddr;
-    unsigned short tx_stat, rx_stat;
-
-    ioaddr = dev->base_addr;
-
-    /* avoid multiple interrupts */
-    outw(0x0000, ioaddr + TX_INTR);
-
-    /* wait for a while */
-    udelay(1);
-
-    /* get status */
-    tx_stat = inb(ioaddr + TX_STATUS);
-    rx_stat = inb(ioaddr + RX_STATUS);
-
-    /* clear status */
-    outb(tx_stat, ioaddr + TX_STATUS);
-    outb(rx_stat, ioaddr + RX_STATUS);
-    
-    pr_debug("%s: interrupt, rx_status %02x.\n", dev->name, rx_stat);
-    pr_debug("               tx_status %02x.\n", tx_stat);
-    
-    if (rx_stat || (inb(ioaddr + RX_MODE) & F_BUF_EMP) == 0) {
-	/* there is packet(s) in rx buffer */
-	fjn_rx(dev);
-    }
-    if (tx_stat & F_TMT_RDY) {
-	dev->stats.tx_packets += lp->sent ;
-        lp->sent = 0 ;
-	if (lp->tx_queue) {
-	    outb(DO_TX | lp->tx_queue, ioaddr + TX_START);
-	    lp->sent = lp->tx_queue ;
-	    lp->tx_queue = 0;
-	    lp->tx_queue_len = 0;
-	    netif_trans_update(dev);
-	} else {
-	    lp->tx_started = 0;
-	}
-	netif_wake_queue(dev);
-    }
-    pr_debug("%s: exiting interrupt,\n", dev->name);
-    pr_debug("    tx_status %02x, rx_status %02x.\n", tx_stat, rx_stat);
-
-    outb(D_TX_INTR, ioaddr + TX_INTR);
-    outb(D_RX_INTR, ioaddr + RX_INTR);
-
-    if (lp->base != NULL) {
-	/* Ack interrupt for multifunction card */
-	writeb(0x01, lp->base+0x802);
-	writeb(0x09, lp->base+0x822);
-    }
-
-    return IRQ_HANDLED;
-
-} /* fjn_interrupt */
-
-/*====================================================================*/
-
-static void fjn_tx_timeout(struct net_device *dev, unsigned int txqueue)
-{
-    struct local_info *lp = netdev_priv(dev);
-    unsigned int ioaddr = dev->base_addr;
-
-    netdev_notice(dev, "transmit timed out with status %04x, %s?\n",
-		  htons(inw(ioaddr + TX_STATUS)),
-		  inb(ioaddr + TX_STATUS) & F_TMT_RDY
-		  ? "IRQ conflict" : "network cable problem");
-    netdev_notice(dev, "timeout registers: %04x %04x %04x "
-		  "%04x %04x %04x %04x %04x.\n",
-		  htons(inw(ioaddr + 0)), htons(inw(ioaddr + 2)),
-		  htons(inw(ioaddr + 4)), htons(inw(ioaddr + 6)),
-		  htons(inw(ioaddr + 8)), htons(inw(ioaddr + 10)),
-		  htons(inw(ioaddr + 12)), htons(inw(ioaddr + 14)));
-    dev->stats.tx_errors++;
-    /* ToDo: We should try to restart the adaptor... */
-    local_irq_disable();
-    fjn_reset(dev);
-
-    lp->tx_started = 0;
-    lp->tx_queue = 0;
-    lp->tx_queue_len = 0;
-    lp->sent = 0;
-    lp->open_time = jiffies;
-    local_irq_enable();
-    netif_wake_queue(dev);
-}
-
-static netdev_tx_t fjn_start_xmit(struct sk_buff *skb,
-					struct net_device *dev)
-{
-    struct local_info *lp = netdev_priv(dev);
-    unsigned int ioaddr = dev->base_addr;
-    short length = skb->len;
-    
-    if (length < ETH_ZLEN)
-    {
-	if (skb_padto(skb, ETH_ZLEN))
-		return NETDEV_TX_OK;
-	length = ETH_ZLEN;
-    }
-
-    netif_stop_queue(dev);
-
-    {
-	unsigned char *buf = skb->data;
-
-	if (length > ETH_FRAME_LEN) {
-	    netdev_notice(dev, "Attempting to send a large packet (%d bytes)\n",
-			  length);
-	    return NETDEV_TX_BUSY;
-	}
-
-	netdev_dbg(dev, "Transmitting a packet of length %lu\n",
-		   (unsigned long)skb->len);
-	dev->stats.tx_bytes += skb->len;
-
-	/* Disable both interrupts. */
-	outw(0x0000, ioaddr + TX_INTR);
-
-	/* wait for a while */
-	udelay(1);
-
-	outw(length, ioaddr + DATAPORT);
-	outsw(ioaddr + DATAPORT, buf, (length + 1) >> 1);
-
-	lp->tx_queue++;
-	lp->tx_queue_len += ((length+3) & ~1);
-
-	if (lp->tx_started == 0) {
-	    /* If the Tx is idle, always trigger a transmit. */
-	    outb(DO_TX | lp->tx_queue, ioaddr + TX_START);
-	    lp->sent = lp->tx_queue ;
-	    lp->tx_queue = 0;
-	    lp->tx_queue_len = 0;
-	    lp->tx_started = 1;
-	    netif_start_queue(dev);
-	} else {
-	    if( sram_config == 0 ) {
-		if (lp->tx_queue_len < (4096 - (ETH_FRAME_LEN +2)) )
-		    /* Yes, there is room for one more packet. */
-		    netif_start_queue(dev);
-	    } else {
-		if (lp->tx_queue_len < (8192 - (ETH_FRAME_LEN +2)) && 
-						lp->tx_queue < 127 )
-		    /* Yes, there is room for one more packet. */
-		    netif_start_queue(dev);
-	    }
-	}
-
-	/* Re-enable interrupts */
-	outb(D_TX_INTR, ioaddr + TX_INTR);
-	outb(D_RX_INTR, ioaddr + RX_INTR);
-    }
-    dev_kfree_skb (skb);
-
-    return NETDEV_TX_OK;
-} /* fjn_start_xmit */
-
-/*====================================================================*/
-
-static void fjn_reset(struct net_device *dev)
-{
-    struct local_info *lp = netdev_priv(dev);
-    unsigned int ioaddr = dev->base_addr;
-    int i;
-
-    netdev_dbg(dev, "fjn_reset() called\n");
-
-    /* Reset controller */
-    if( sram_config == 0 ) 
-	outb(CONFIG0_RST, ioaddr + CONFIG_0);
-    else
-	outb(CONFIG0_RST_1, ioaddr + CONFIG_0);
-
-    /* Power On chip and select bank 0 */
-    if (lp->cardtype == MBH10302)
-	outb(BANK_0, ioaddr + CONFIG_1);
-    else
-	outb(BANK_0U, ioaddr + CONFIG_1);
-
-    /* Set Tx modes */
-    outb(D_TX_MODE, ioaddr + TX_MODE);
-    /* set Rx modes */
-    outb(ID_MATCHED, ioaddr + RX_MODE);
-
-    /* Set hardware address */
-    for (i = 0; i < 6; i++) 
-        outb(dev->dev_addr[i], ioaddr + NODE_ID + i);
-
-    /* (re)initialize the multicast table */
-    set_rx_mode(dev);
-
-    /* Switch to bank 2 (runtime mode) */
-    if (lp->cardtype == MBH10302)
-	outb(BANK_2, ioaddr + CONFIG_1);
-    else
-	outb(BANK_2U, ioaddr + CONFIG_1);
-
-    /* set 16col ctrl bits */
-    if( lp->cardtype == TDK || lp->cardtype == CONTEC) 
-        outb(TDK_AUTO_MODE, ioaddr + COL_CTRL);
-    else
-        outb(AUTO_MODE, ioaddr + COL_CTRL);
-
-    /* clear Reserved Regs */
-    outb(0x00, ioaddr + BMPR12);
-    outb(0x00, ioaddr + BMPR13);
-
-    /* reset Skip packet reg. */
-    outb(0x01, ioaddr + RX_SKIP);
-
-    /* Enable Tx and Rx */
-    if( sram_config == 0 )
-	outb(CONFIG0_DFL, ioaddr + CONFIG_0);
-    else
-	outb(CONFIG0_DFL_1, ioaddr + CONFIG_0);
-
-    /* Init receive pointer ? */
-    inw(ioaddr + DATAPORT);
-    inw(ioaddr + DATAPORT);
-
-    /* Clear all status */
-    outb(0xff, ioaddr + TX_STATUS);
-    outb(0xff, ioaddr + RX_STATUS);
-
-    if (lp->cardtype == MBH10302)
-	outb(INTR_OFF, ioaddr + LAN_CTRL);
-
-    /* Turn on Rx interrupts */
-    outb(D_TX_INTR, ioaddr + TX_INTR);
-    outb(D_RX_INTR, ioaddr + RX_INTR);
-
-    /* Turn on interrupts from LAN card controller */
-    if (lp->cardtype == MBH10302)
-	outb(INTR_ON, ioaddr + LAN_CTRL);
-} /* fjn_reset */
-
-/*====================================================================*/
-
-static void fjn_rx(struct net_device *dev)
-{
-    unsigned int ioaddr = dev->base_addr;
-    int boguscount = 10;	/* 5 -> 10: by agy 19940922 */
-
-    pr_debug("%s: in rx_packet(), rx_status %02x.\n",
-	  dev->name, inb(ioaddr + RX_STATUS));
-
-    while ((inb(ioaddr + RX_MODE) & F_BUF_EMP) == 0) {
-	u_short status = inw(ioaddr + DATAPORT);
-
-	netdev_dbg(dev, "Rxing packet mode %02x status %04x.\n",
-		   inb(ioaddr + RX_MODE), status);
-#ifndef final_version
-	if (status == 0) {
-	    outb(F_SKP_PKT, ioaddr + RX_SKIP);
-	    break;
-	}
-#endif
-	if ((status & 0xF0) != 0x20) {	/* There was an error. */
-	    dev->stats.rx_errors++;
-	    if (status & F_LEN_ERR) dev->stats.rx_length_errors++;
-	    if (status & F_ALG_ERR) dev->stats.rx_frame_errors++;
-	    if (status & F_CRC_ERR) dev->stats.rx_crc_errors++;
-	    if (status & F_OVR_FLO) dev->stats.rx_over_errors++;
-	} else {
-	    u_short pkt_len = inw(ioaddr + DATAPORT);
-	    /* Malloc up new buffer. */
-	    struct sk_buff *skb;
-
-	    if (pkt_len > 1550) {
-		netdev_notice(dev, "The FMV-18x claimed a very large packet, size %d\n",
-			      pkt_len);
-		outb(F_SKP_PKT, ioaddr + RX_SKIP);
-		dev->stats.rx_errors++;
-		break;
-	    }
-	    skb = netdev_alloc_skb(dev, pkt_len + 2);
-	    if (skb == NULL) {
-		outb(F_SKP_PKT, ioaddr + RX_SKIP);
-		dev->stats.rx_dropped++;
-		break;
-	    }
-
-	    skb_reserve(skb, 2);
-	    insw(ioaddr + DATAPORT, skb_put(skb, pkt_len),
-		 (pkt_len + 1) >> 1);
-	    skb->protocol = eth_type_trans(skb, dev);
-
-	    {
-		int i;
-		pr_debug("%s: Rxed packet of length %d: ",
-			dev->name, pkt_len);
-		for (i = 0; i < 14; i++)
-			pr_debug(" %02x", skb->data[i]);
-		pr_debug(".\n");
-	    }
-
-	    netif_rx(skb);
-	    dev->stats.rx_packets++;
-	    dev->stats.rx_bytes += pkt_len;
-	}
-	if (--boguscount <= 0)
-	    break;
-    }
-
-    /* If any worth-while packets have been received, dev_rint()
-	   has done a netif_wake_queue() for us and will work on them
-	   when we get to the bottom-half routine. */
-/*
-    if (lp->cardtype != TDK) {
-	int i;
-	for (i = 0; i < 20; i++) {
-	    if ((inb(ioaddr + RX_MODE) & F_BUF_EMP) == F_BUF_EMP)
-		break;
-	    (void)inw(ioaddr + DATAPORT);  /+ dummy status read +/
-	    outb(F_SKP_PKT, ioaddr + RX_SKIP);
-	}
-
-	if (i > 0)
-	    pr_debug("%s: Exint Rx packet with mode %02x after "
-		  "%d ticks.\n", dev->name, inb(ioaddr + RX_MODE), i);
-    }
-*/
-} /* fjn_rx */
-
-/*====================================================================*/
-
-static void netdev_get_drvinfo(struct net_device *dev,
-			       struct ethtool_drvinfo *info)
-{
-	strscpy(info->driver, DRV_NAME, sizeof(info->driver));
-	strscpy(info->version, DRV_VERSION, sizeof(info->version));
-	snprintf(info->bus_info, sizeof(info->bus_info),
-		"PCMCIA 0x%lx", dev->base_addr);
-}
-
-static const struct ethtool_ops netdev_ethtool_ops = {
-	.get_drvinfo		= netdev_get_drvinfo,
-};
-
-static int fjn_config(struct net_device *dev, struct ifmap *map){
-    return 0;
-}
-
-static int fjn_open(struct net_device *dev)
-{
-    struct local_info *lp = netdev_priv(dev);
-    struct pcmcia_device *link = lp->p_dev;
-
-    pr_debug("fjn_open('%s').\n", dev->name);
-
-    if (!pcmcia_dev_present(link))
-	return -ENODEV;
-    
-    link->open++;
-    
-    fjn_reset(dev);
-    
-    lp->tx_started = 0;
-    lp->tx_queue = 0;
-    lp->tx_queue_len = 0;
-    lp->open_time = jiffies;
-    netif_start_queue(dev);
-    
-    return 0;
-} /* fjn_open */
-
-/*====================================================================*/
-
-static int fjn_close(struct net_device *dev)
-{
-    struct local_info *lp = netdev_priv(dev);
-    struct pcmcia_device *link = lp->p_dev;
-    unsigned int ioaddr = dev->base_addr;
-
-    pr_debug("fjn_close('%s').\n", dev->name);
-
-    lp->open_time = 0;
-    netif_stop_queue(dev);
-
-    /* Set configuration register 0 to disable Tx and Rx. */
-    if( sram_config == 0 ) 
-	outb(CONFIG0_RST ,ioaddr + CONFIG_0);
-    else
-	outb(CONFIG0_RST_1 ,ioaddr + CONFIG_0);
-
-    /* Update the statistics -- ToDo. */
-
-    /* Power-down the chip.  Green, green, green! */
-    outb(CHIP_OFF ,ioaddr + CONFIG_1);
-
-    /* Set the ethernet adaptor disable IRQ */
-    if (lp->cardtype == MBH10302)
-	outb(INTR_OFF, ioaddr + LAN_CTRL);
-
-    link->open--;
-
-    return 0;
-} /* fjn_close */
-
-/*====================================================================*/
-
-/*
-  Set the multicast/promiscuous mode for this adaptor.
-*/
-
-static void set_rx_mode(struct net_device *dev)
-{
-    unsigned int ioaddr = dev->base_addr;
-    u_char mc_filter[8];		 /* Multicast hash filter */
-    u_long flags;
-    int i;
-    
-    int saved_bank;
-    int saved_config_0 = inb(ioaddr + CONFIG_0);
-     
-    local_irq_save(flags); 
-
-    /* Disable Tx and Rx */
-    if (sram_config == 0) 
-	outb(CONFIG0_RST, ioaddr + CONFIG_0);
-    else
-	outb(CONFIG0_RST_1, ioaddr + CONFIG_0);
-
-    if (dev->flags & IFF_PROMISC) {
-	memset(mc_filter, 0xff, sizeof(mc_filter));
-	outb(3, ioaddr + RX_MODE);	/* Enable promiscuous mode */
-    } else if (netdev_mc_count(dev) > MC_FILTERBREAK ||
-	       (dev->flags & IFF_ALLMULTI)) {
-	/* Too many to filter perfectly -- accept all multicasts. */
-	memset(mc_filter, 0xff, sizeof(mc_filter));
-	outb(2, ioaddr + RX_MODE);	/* Use normal mode. */
-    } else if (netdev_mc_empty(dev)) {
-	memset(mc_filter, 0x00, sizeof(mc_filter));
-	outb(1, ioaddr + RX_MODE);	/* Ignore almost all multicasts. */
-    } else {
-	struct netdev_hw_addr *ha;
-
-	memset(mc_filter, 0, sizeof(mc_filter));
-	netdev_for_each_mc_addr(ha, dev) {
-	    unsigned int bit = ether_crc_le(ETH_ALEN, ha->addr) >> 26;
-	    mc_filter[bit >> 3] |= (1 << (bit & 7));
-	}
-	outb(2, ioaddr + RX_MODE);	/* Use normal mode. */
-    }
-
-    /* Switch to bank 1 and set the multicast table. */
-    saved_bank = inb(ioaddr + CONFIG_1);
-    outb(0xe4, ioaddr + CONFIG_1);
-
-    for (i = 0; i < 8; i++)
-	outb(mc_filter[i], ioaddr + MAR_ADR + i);
-    outb(saved_bank, ioaddr + CONFIG_1);
-
-    outb(saved_config_0, ioaddr + CONFIG_0);
-
-    local_irq_restore(flags);
-}

-- 
2.53.0


^ permalink raw reply related	[flat|nested] 28+ messages in thread

* [PATCH net 14/18] drivers: net: xircom: xirc2ps: Remove this driver
  2026-04-21 19:31 [PATCH net 00/18] Remove a number of ISA and PCMCIA Ethernet drivers Andrew Lunn
                   ` (12 preceding siblings ...)
  2026-04-21 19:31 ` [PATCH net 13/18] drivers: net: fujitsu: fmvj18x: " Andrew Lunn
@ 2026-04-21 19:31 ` Andrew Lunn
  2026-04-21 19:31 ` [PATCH net 15/18] drivers: net: 8390: AX88190: " Andrew Lunn
                   ` (7 subsequent siblings)
  21 siblings, 0 replies; 28+ messages in thread
From: Andrew Lunn @ 2026-04-21 19:31 UTC (permalink / raw)
  To: Andrew Lunn, David S. Miller, Eric Dumazet, Jakub Kicinski,
	Paolo Abeni, Simon Horman, Jonathan Corbet, Shuah Khan
  Cc: linux-kernel, netdev, linux-doc, Andrew Lunn

The xirc2ps was written by Werner Koch in 1997. It is an PCMCIA
device, so unlikely to be used with modern kernels.

Signed-off-by: Andrew Lunn <andrew@lunn.ch>
---
 drivers/net/ethernet/Kconfig             |    1 -
 drivers/net/ethernet/xircom/Kconfig      |   30 -
 drivers/net/ethernet/xircom/Makefile     |    6 -
 drivers/net/ethernet/xircom/xirc2ps_cs.c | 1794 ------------------------------
 4 files changed, 1831 deletions(-)

diff --git a/drivers/net/ethernet/Kconfig b/drivers/net/ethernet/Kconfig
index c94e8f27af94..5171d9046ea4 100644
--- a/drivers/net/ethernet/Kconfig
+++ b/drivers/net/ethernet/Kconfig
@@ -188,6 +188,5 @@ source "drivers/net/ethernet/via/Kconfig"
 source "drivers/net/ethernet/wangxun/Kconfig"
 source "drivers/net/ethernet/wiznet/Kconfig"
 source "drivers/net/ethernet/xilinx/Kconfig"
-source "drivers/net/ethernet/xircom/Kconfig"
 
 endif # ETHERNET
diff --git a/drivers/net/ethernet/xircom/Kconfig b/drivers/net/ethernet/xircom/Kconfig
deleted file mode 100644
index bfbdcf758afb..000000000000
--- a/drivers/net/ethernet/xircom/Kconfig
+++ /dev/null
@@ -1,30 +0,0 @@
-# SPDX-License-Identifier: GPL-2.0-only
-#
-# Xircom network device configuration
-#
-
-config NET_VENDOR_XIRCOM
-	bool "Xircom devices"
-	default y
-	depends on PCMCIA
-	help
-	  If you have a network (Ethernet) card belonging to this class, say Y.
-
-	  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 Xircom cards. If you say Y, you will be asked for
-	  your specific card in the following questions.
-
-if NET_VENDOR_XIRCOM
-
-config PCMCIA_XIRC2PS
-	tristate "Xircom 16-bit PCMCIA support"
-	depends on PCMCIA && HAS_IOPORT
-	help
-	  Say Y here if you intend to attach a Xircom 16-bit 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 xirc2ps_cs.  If unsure, say N.
-
-endif # NET_VENDOR_XIRCOM
diff --git a/drivers/net/ethernet/xircom/Makefile b/drivers/net/ethernet/xircom/Makefile
deleted file mode 100644
index 07667fefafc2..000000000000
--- a/drivers/net/ethernet/xircom/Makefile
+++ /dev/null
@@ -1,6 +0,0 @@
-# SPDX-License-Identifier: GPL-2.0-only
-#
-# Makefile for the Xircom network device drivers.
-#
-
-obj-$(CONFIG_PCMCIA_XIRC2PS) += xirc2ps_cs.o
diff --git a/drivers/net/ethernet/xircom/xirc2ps_cs.c b/drivers/net/ethernet/xircom/xirc2ps_cs.c
deleted file mode 100644
index 97e88886253f..000000000000
--- a/drivers/net/ethernet/xircom/xirc2ps_cs.c
+++ /dev/null
@@ -1,1794 +0,0 @@
-/* [xirc2ps_cs.c wk 03.11.99] (1.40 1999/11/18 00:06:03)
- * Xircom CreditCard Ethernet Adapter IIps driver
- * Xircom Realport 10/100 (RE-100) driver 
- *
- * This driver supports various Xircom CreditCard Ethernet adapters
- * including the CE2, CE IIps, RE-10, CEM28, CEM33, CE33, CEM56,
- * CE3-100, CE3B, RE-100, REM10BT, and REM56G-100.
- *
- * 2000-09-24 <psheer@icon.co.za> The Xircom CE3B-100 may not
- * autodetect the media properly. In this case use the
- * if_port=1 (for 10BaseT) or if_port=4 (for 100BaseT) options
- * to force the media type.
- * 
- * Written originally by Werner Koch based on David Hinds' skeleton of the
- * PCMCIA driver.
- *
- * Copyright (c) 1997,1998 Werner Koch (dd9jn)
- *
- * This driver 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.
- *
- * It 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, see <http://www.gnu.org/licenses/>.
- *
- *
- * ALTERNATIVELY, this driver may be distributed under the terms of
- * the following license, in which case the provisions of this license
- * are required INSTEAD OF the GNU General Public License.  (This clause
- * is necessary due to a potential bad interaction between the GPL and
- * the restrictions contained in a BSD-style copyright.)
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions
- * are met:
- * 1. Redistributions of source code must retain the above copyright
- *    notice, and the entire permission notice in its entirety,
- *    including the disclaimer of warranties.
- * 2. Redistributions in binary form must reproduce the above copyright
- *    notice, this list of conditions and the following disclaimer in the
- *    documentation and/or other materials provided with the distribution.
- * 3. The name of the author may not be used to endorse or promote
- *    products derived from this software without specific prior
- *    written permission.
- *
- * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED
- * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
- * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
- * DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT,
- * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
- * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
- * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
- * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
- * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
- * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
- * OF THE POSSIBILITY OF SUCH DAMAGE.
- */
-
-#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
-
-#include <linux/module.h>
-#include <linux/kernel.h>
-#include <linux/init.h>
-#include <linux/ptrace.h>
-#include <linux/slab.h>
-#include <linux/string.h>
-#include <linux/timer.h>
-#include <linux/interrupt.h>
-#include <linux/in.h>
-#include <linux/delay.h>
-#include <linux/ethtool.h>
-#include <linux/netdevice.h>
-#include <linux/etherdevice.h>
-#include <linux/skbuff.h>
-#include <linux/if_arp.h>
-#include <linux/ioport.h>
-#include <linux/bitops.h>
-#include <linux/mii.h>
-
-#include <pcmcia/cistpl.h>
-#include <pcmcia/cisreg.h>
-#include <pcmcia/ciscode.h>
-
-#include <asm/io.h>
-#include <linux/uaccess.h>
-
-#ifndef MANFID_COMPAQ
-  #define MANFID_COMPAQ 	   0x0138
-  #define MANFID_COMPAQ2	   0x0183  /* is this correct? */
-#endif
-
-#include <pcmcia/ds.h>
-
-/* Time in jiffies before concluding Tx hung */
-#define TX_TIMEOUT	((400*HZ)/1000)
-
-/****************
- * Some constants used to access the hardware
- */
-
-/* Register offsets and value constans */
-#define XIRCREG_CR  0	/* Command register (wr) */
-enum xirc_cr {
-    TransmitPacket = 0x01,
-    SoftReset = 0x02,
-    EnableIntr = 0x04,
-    ForceIntr  = 0x08,
-    ClearTxFIFO = 0x10,
-    ClearRxOvrun = 0x20,
-    RestartTx	 = 0x40
-};
-#define XIRCREG_ESR 0	/* Ethernet status register (rd) */
-enum xirc_esr {
-    FullPktRcvd = 0x01, /* full packet in receive buffer */
-    PktRejected = 0x04, /* a packet has been rejected */
-    TxPktPend = 0x08,	/* TX Packet Pending */
-    IncorPolarity = 0x10,
-    MediaSelect = 0x20	/* set if TP, clear if AUI */
-};
-#define XIRCREG_PR  1	/* Page Register select */
-#define XIRCREG_EDP 4	/* Ethernet Data Port Register */
-#define XIRCREG_ISR 6	/* Ethernet Interrupt Status Register */
-enum xirc_isr {
-    TxBufOvr = 0x01,	/* TX Buffer Overflow */
-    PktTxed  = 0x02,	/* Packet Transmitted */
-    MACIntr  = 0x04,	/* MAC Interrupt occurred */
-    TxResGrant = 0x08,	/* Tx Reservation Granted */
-    RxFullPkt = 0x20,	/* Rx Full Packet */
-    RxPktRej  = 0x40,	/* Rx Packet Rejected */
-    ForcedIntr= 0x80	/* Forced Interrupt */
-};
-#define XIRCREG1_IMR0 12 /* Ethernet Interrupt Mask Register (on page 1)*/
-#define XIRCREG1_IMR1 13
-#define XIRCREG0_TSO  8  /* Transmit Space Open Register (on page 0)*/
-#define XIRCREG0_TRS  10 /* Transmit reservation Size Register (page 0)*/
-#define XIRCREG0_DO   12 /* Data Offset Register (page 0) (wr) */
-#define XIRCREG0_RSR  12 /* Receive Status Register (page 0) (rd) */
-enum xirc_rsr {
-    PhyPkt = 0x01,	/* set:physical packet, clear: multicast packet */
-    BrdcstPkt = 0x02,	/* set if it is a broadcast packet */
-    PktTooLong = 0x04,	/* set if packet length > 1518 */
-    AlignErr = 0x10,	/* incorrect CRC and last octet not complete */
-    CRCErr = 0x20,	/* incorrect CRC and last octet is complete */
-    PktRxOk = 0x80	/* received ok */
-};
-#define XIRCREG0_PTR 13 /* packets transmitted register (rd) */
-#define XIRCREG0_RBC 14 /* receive byte count regsister (rd) */
-#define XIRCREG1_ECR 14 /* ethernet configurationn register */
-enum xirc_ecr {
-    FullDuplex = 0x04,	/* enable full duplex mode */
-    LongTPMode = 0x08,	/* adjust for longer lengths of TP cable */
-    DisablePolCor = 0x10,/* disable auto polarity correction */
-    DisableLinkPulse = 0x20, /* disable link pulse generation */
-    DisableAutoTx = 0x40, /* disable auto-transmit */
-};
-#define XIRCREG2_RBS 8	/* receive buffer start register */
-#define XIRCREG2_LED 10 /* LED Configuration register */
-/* values for the leds:    Bits 2-0 for led 1
- *  0 disabled		   Bits 5-3 for led 2
- *  1 collision
- *  2 noncollision
- *  3 link_detected
- *  4 incor_polarity
- *  5 jabber
- *  6 auto_assertion
- *  7 rx_tx_activity
- */
-#define XIRCREG2_MSR 12 /* Mohawk specific register */
-
-#define XIRCREG4_GPR0 8 /* General Purpose Register 0 */
-#define XIRCREG4_GPR1 9 /* General Purpose Register 1 */
-#define XIRCREG2_GPR2 13 /* General Purpose Register 2 (page2!)*/
-#define XIRCREG4_BOV 10 /* Bonding Version Register */
-#define XIRCREG4_LMA 12 /* Local Memory Address Register */
-#define XIRCREG4_LMD 14 /* Local Memory Data Port */
-/* MAC register can only by accessed with 8 bit operations */
-#define XIRCREG40_CMD0 8    /* Command Register (wr) */
-enum xirc_cmd { 	    /* Commands */
-    Transmit = 0x01,
-    EnableRecv = 0x04,
-    DisableRecv = 0x08,
-    Abort = 0x10,
-    Online = 0x20,
-    IntrAck = 0x40,
-    Offline = 0x80
-};
-#define XIRCREG5_RHSA0	10  /* Rx Host Start Address */
-#define XIRCREG40_RXST0 9   /* Receive Status Register */
-#define XIRCREG40_TXST0 11  /* Transmit Status Register 0 */
-#define XIRCREG40_TXST1 12  /* Transmit Status Register 10 */
-#define XIRCREG40_RMASK0 13  /* Receive Mask Register */
-#define XIRCREG40_TMASK0 14  /* Transmit Mask Register 0 */
-#define XIRCREG40_TMASK1 15  /* Transmit Mask Register 0 */
-#define XIRCREG42_SWC0	8   /* Software Configuration 0 */
-#define XIRCREG42_SWC1	9   /* Software Configuration 1 */
-#define XIRCREG42_BOC	10  /* Back-Off Configuration */
-#define XIRCREG44_TDR0	8   /* Time Domain Reflectometry 0 */
-#define XIRCREG44_TDR1	9   /* Time Domain Reflectometry 1 */
-#define XIRCREG44_RXBC_LO 10 /* Rx Byte Count 0 (rd) */
-#define XIRCREG44_RXBC_HI 11 /* Rx Byte Count 1 (rd) */
-#define XIRCREG45_REV	 15 /* Revision Register (rd) */
-#define XIRCREG50_IA	8   /* Individual Address (8-13) */
-
-static const char *if_names[] = { "Auto", "10BaseT", "10Base2", "AUI", "100BaseT" };
-
-/* card types */
-#define XIR_UNKNOWN  0	/* unknown: not supported */
-#define XIR_CE	     1	/* (prodid 1) different hardware: not supported */
-#define XIR_CE2      2	/* (prodid 2) */
-#define XIR_CE3      3	/* (prodid 3) */
-#define XIR_CEM      4	/* (prodid 1) different hardware: not supported */
-#define XIR_CEM2     5	/* (prodid 2) */
-#define XIR_CEM3     6	/* (prodid 3) */
-#define XIR_CEM33    7	/* (prodid 4) */
-#define XIR_CEM56M   8	/* (prodid 5) */
-#define XIR_CEM56    9	/* (prodid 6) */
-#define XIR_CM28    10	/* (prodid 3) modem only: not supported here */
-#define XIR_CM33    11	/* (prodid 4) modem only: not supported here */
-#define XIR_CM56    12	/* (prodid 5) modem only: not supported here */
-#define XIR_CG	    13	/* (prodid 1) GSM modem only: not supported */
-#define XIR_CBE     14	/* (prodid 1) cardbus ethernet: not supported */
-/*====================================================================*/
-
-/* Module parameters */
-
-MODULE_DESCRIPTION("Xircom PCMCIA ethernet driver");
-MODULE_LICENSE("Dual MPL/GPL");
-
-#define INT_MODULE_PARM(n, v) static int n = v; module_param(n, int, 0)
-
-INT_MODULE_PARM(if_port,	0);
-INT_MODULE_PARM(full_duplex,	0);
-INT_MODULE_PARM(do_sound, 	1);
-INT_MODULE_PARM(lockup_hack,	0);  /* anti lockup hack */
-
-/*====================================================================*/
-
-/* We do not process more than these number of bytes during one
- * interrupt. (Of course we receive complete packets, so this is not
- * an exact value).
- * Something between 2000..22000; first value gives best interrupt latency,
- * the second enables the usage of the complete on-chip buffer. We use the
- * high value as the initial value.
- */
-static unsigned maxrx_bytes = 22000;
-
-/* MII management prototypes */
-static void mii_idle(unsigned int ioaddr);
-static void mii_putbit(unsigned int ioaddr, unsigned data);
-static int  mii_getbit(unsigned int ioaddr);
-static void mii_wbits(unsigned int ioaddr, unsigned data, int len);
-static unsigned mii_rd(unsigned int ioaddr, u_char phyaddr, u_char phyreg);
-static void mii_wr(unsigned int ioaddr, u_char phyaddr, u_char phyreg,
-		   unsigned data, int len);
-
-static int has_ce2_string(struct pcmcia_device * link);
-static int xirc2ps_config(struct pcmcia_device * link);
-static void xirc2ps_release(struct pcmcia_device * link);
-static void xirc2ps_detach(struct pcmcia_device *p_dev);
-
-static irqreturn_t xirc2ps_interrupt(int irq, void *dev_id);
-
-struct local_info {
-	struct net_device	*dev;
-	struct pcmcia_device	*p_dev;
-
-    int card_type;
-    int probe_port;
-    int silicon; /* silicon revision. 0=old CE2, 1=Scipper, 4=Mohawk */
-    int mohawk;  /* a CE3 type card */
-    int dingo;	 /* a CEM56 type card */
-    int new_mii; /* has full 10baseT/100baseT MII */
-    int modem;	 /* is a multi function card (i.e with a modem) */
-    void __iomem *dingo_ccr; /* only used for CEM56 cards */
-    unsigned last_ptr_value; /* last packets transmitted value */
-    const char *manf_str;
-    struct work_struct tx_timeout_task;
-};
-
-/****************
- * Some more prototypes
- */
-static netdev_tx_t do_start_xmit(struct sk_buff *skb,
-				       struct net_device *dev);
-static void xirc_tx_timeout(struct net_device *dev, unsigned int txqueue);
-static void xirc2ps_tx_timeout_task(struct work_struct *work);
-static void set_addresses(struct net_device *dev);
-static void set_multicast_list(struct net_device *dev);
-static int set_card_type(struct pcmcia_device *link);
-static int do_config(struct net_device *dev, struct ifmap *map);
-static int do_open(struct net_device *dev);
-static int do_ioctl(struct net_device *dev, struct ifreq *rq, int cmd);
-static const struct ethtool_ops netdev_ethtool_ops;
-static void hardreset(struct net_device *dev);
-static void do_reset(struct net_device *dev, int full);
-static int init_mii(struct net_device *dev);
-static void do_powerdown(struct net_device *dev);
-static int do_stop(struct net_device *dev);
-
-/*=============== Helper functions =========================*/
-#define SelectPage(pgnr)   outb((pgnr), ioaddr + XIRCREG_PR)
-#define GetByte(reg)	   ((unsigned)inb(ioaddr + (reg)))
-#define GetWord(reg)	   ((unsigned)inw(ioaddr + (reg)))
-#define PutByte(reg,value) outb((value), ioaddr+(reg))
-#define PutWord(reg,value) outw((value), ioaddr+(reg))
-
-/*====== Functions used for debugging =================================*/
-#if 0 /* reading regs may change system status */
-static void
-PrintRegisters(struct net_device *dev)
-{
-    unsigned int ioaddr = dev->base_addr;
-
-    if (pc_debug > 1) {
-	int i, page;
-
-	printk(KERN_DEBUG pr_fmt("Register  common: "));
-	for (i = 0; i < 8; i++)
-	    pr_cont(" %2.2x", GetByte(i));
-	pr_cont("\n");
-	for (page = 0; page <= 8; page++) {
-	    printk(KERN_DEBUG pr_fmt("Register page %2x: "), page);
-	    SelectPage(page);
-	    for (i = 8; i < 16; i++)
-		pr_cont(" %2.2x", GetByte(i));
-	    pr_cont("\n");
-	}
-	for (page=0x40 ; page <= 0x5f; page++) {
-		if (page == 0x43 || (page >= 0x46 && page <= 0x4f) ||
-		    (page >= 0x51 && page <=0x5e))
-			continue;
-	    printk(KERN_DEBUG pr_fmt("Register page %2x: "), page);
-	    SelectPage(page);
-	    for (i = 8; i < 16; i++)
-		pr_cont(" %2.2x", GetByte(i));
-	    pr_cont("\n");
-	}
-    }
-}
-#endif /* 0 */
-
-/*============== MII Management functions ===============*/
-
-/****************
- * Turn around for read
- */
-static void
-mii_idle(unsigned int ioaddr)
-{
-    PutByte(XIRCREG2_GPR2, 0x04|0); /* drive MDCK low */
-    udelay(1);
-    PutByte(XIRCREG2_GPR2, 0x04|1); /* and drive MDCK high */
-    udelay(1);
-}
-
-/****************
- * Write a bit to MDI/O
- */
-static void
-mii_putbit(unsigned int ioaddr, unsigned data)
-{
-  #if 1
-    if (data) {
-	PutByte(XIRCREG2_GPR2, 0x0c|2|0); /* set MDIO */
-	udelay(1);
-	PutByte(XIRCREG2_GPR2, 0x0c|2|1); /* and drive MDCK high */
-	udelay(1);
-    } else {
-	PutByte(XIRCREG2_GPR2, 0x0c|0|0); /* clear MDIO */
-	udelay(1);
-	PutByte(XIRCREG2_GPR2, 0x0c|0|1); /* and drive MDCK high */
-	udelay(1);
-    }
-  #else
-    if (data) {
-	PutWord(XIRCREG2_GPR2-1, 0x0e0e);
-	udelay(1);
-	PutWord(XIRCREG2_GPR2-1, 0x0f0f);
-	udelay(1);
-    } else {
-	PutWord(XIRCREG2_GPR2-1, 0x0c0c);
-	udelay(1);
-	PutWord(XIRCREG2_GPR2-1, 0x0d0d);
-	udelay(1);
-    }
-  #endif
-}
-
-/****************
- * Get a bit from MDI/O
- */
-static int
-mii_getbit(unsigned int ioaddr)
-{
-    unsigned d;
-
-    PutByte(XIRCREG2_GPR2, 4|0); /* drive MDCK low */
-    udelay(1);
-    d = GetByte(XIRCREG2_GPR2); /* read MDIO */
-    PutByte(XIRCREG2_GPR2, 4|1); /* drive MDCK high again */
-    udelay(1);
-    return d & 0x20; /* read MDIO */
-}
-
-static void
-mii_wbits(unsigned int ioaddr, unsigned data, int len)
-{
-    unsigned m = 1 << (len-1);
-    for (; m; m >>= 1)
-	mii_putbit(ioaddr, data & m);
-}
-
-static unsigned
-mii_rd(unsigned int ioaddr,	u_char phyaddr, u_char phyreg)
-{
-    int i;
-    unsigned data=0, m;
-
-    SelectPage(2);
-    for (i=0; i < 32; i++)		/* 32 bit preamble */
-	mii_putbit(ioaddr, 1);
-    mii_wbits(ioaddr, 0x06, 4); 	/* Start and opcode for read */
-    mii_wbits(ioaddr, phyaddr, 5);	/* PHY address to be accessed */
-    mii_wbits(ioaddr, phyreg, 5);	/* PHY register to read */
-    mii_idle(ioaddr);			/* turn around */
-    mii_getbit(ioaddr);
-
-    for (m = 1<<15; m; m >>= 1)
-	if (mii_getbit(ioaddr))
-	    data |= m;
-    mii_idle(ioaddr);
-    return data;
-}
-
-static void
-mii_wr(unsigned int ioaddr, u_char phyaddr, u_char phyreg, unsigned data,
-       int len)
-{
-    int i;
-
-    SelectPage(2);
-    for (i=0; i < 32; i++)		/* 32 bit preamble */
-	mii_putbit(ioaddr, 1);
-    mii_wbits(ioaddr, 0x05, 4); 	/* Start and opcode for write */
-    mii_wbits(ioaddr, phyaddr, 5);	/* PHY address to be accessed */
-    mii_wbits(ioaddr, phyreg, 5);	/* PHY Register to write */
-    mii_putbit(ioaddr, 1);		/* turn around */
-    mii_putbit(ioaddr, 0);
-    mii_wbits(ioaddr, data, len);	/* And write the data */
-    mii_idle(ioaddr);
-}
-
-/*============= Main bulk of functions	=========================*/
-
-static const struct net_device_ops netdev_ops = {
-	.ndo_open		= do_open,
-	.ndo_stop		= do_stop,
-	.ndo_start_xmit		= do_start_xmit,
-	.ndo_tx_timeout 	= xirc_tx_timeout,
-	.ndo_set_config		= do_config,
-	.ndo_eth_ioctl		= do_ioctl,
-	.ndo_set_rx_mode	= set_multicast_list,
-	.ndo_set_mac_address 	= eth_mac_addr,
-	.ndo_validate_addr	= eth_validate_addr,
-};
-
-static int
-xirc2ps_probe(struct pcmcia_device *link)
-{
-    struct net_device *dev;
-    struct local_info *local;
-
-    dev_dbg(&link->dev, "attach()\n");
-
-    /* Allocate the device structure */
-    dev = alloc_etherdev(sizeof(struct local_info));
-    if (!dev)
-	    return -ENOMEM;
-    local = netdev_priv(dev);
-    local->dev = dev;
-    local->p_dev = link;
-    link->priv = dev;
-
-    /* General socket configuration */
-    link->config_index = 1;
-
-    /* Fill in card specific entries */
-    dev->netdev_ops = &netdev_ops;
-    dev->ethtool_ops = &netdev_ethtool_ops;
-    dev->watchdog_timeo = TX_TIMEOUT;
-    INIT_WORK(&local->tx_timeout_task, xirc2ps_tx_timeout_task);
-
-    return xirc2ps_config(link);
-} /* xirc2ps_attach */
-
-static void
-xirc2ps_detach(struct pcmcia_device *link)
-{
-    struct net_device *dev = link->priv;
-    struct local_info *local = netdev_priv(dev);
-
-    netif_carrier_off(dev);
-    netif_tx_disable(dev);
-    cancel_work_sync(&local->tx_timeout_task);
-
-    dev_dbg(&link->dev, "detach\n");
-
-    unregister_netdev(dev);
-
-    xirc2ps_release(link);
-
-    free_netdev(dev);
-} /* xirc2ps_detach */
-
-/****************
- * Detect the type of the card. s is the buffer with the data of tuple 0x20
- * Returns: 0 := not supported
- *		       mediaid=11 and prodid=47
- * Media-Id bits:
- *  Ethernet	    0x01
- *  Tokenring	    0x02
- *  Arcnet	    0x04
- *  Wireless	    0x08
- *  Modem	    0x10
- *  GSM only	    0x20
- * Prod-Id bits:
- *  Pocket	    0x10
- *  External	    0x20
- *  Creditcard	    0x40
- *  Cardbus	    0x80
- *
- */
-static int
-set_card_type(struct pcmcia_device *link)
-{
-    struct net_device *dev = link->priv;
-    struct local_info *local = netdev_priv(dev);
-    u8 *buf;
-    unsigned int cisrev, mediaid, prodid;
-    size_t len;
-
-    len = pcmcia_get_tuple(link, CISTPL_MANFID, &buf);
-    if (len < 5) {
-	    dev_err(&link->dev, "invalid CIS -- sorry\n");
-	    return 0;
-    }
-
-    cisrev = buf[2];
-    mediaid = buf[3];
-    prodid = buf[4];
-
-    dev_dbg(&link->dev, "cisrev=%02x mediaid=%02x prodid=%02x\n",
-	  cisrev, mediaid, prodid);
-
-    local->mohawk = 0;
-    local->dingo = 0;
-    local->modem = 0;
-    local->card_type = XIR_UNKNOWN;
-    if (!(prodid & 0x40)) {
-	pr_notice("Oops: Not a creditcard\n");
-	return 0;
-    }
-    if (!(mediaid & 0x01)) {
-	pr_notice("Not an Ethernet card\n");
-	return 0;
-    }
-    if (mediaid & 0x10) {
-	local->modem = 1;
-	switch(prodid & 15) {
-	  case 1: local->card_type = XIR_CEM   ; break;
-	  case 2: local->card_type = XIR_CEM2  ; break;
-	  case 3: local->card_type = XIR_CEM3  ; break;
-	  case 4: local->card_type = XIR_CEM33 ; break;
-	  case 5: local->card_type = XIR_CEM56M;
-		  local->mohawk = 1;
-		  break;
-	  case 6:
-	  case 7: /* 7 is the RealPort 10/56 */
-		  local->card_type = XIR_CEM56 ;
-		  local->mohawk = 1;
-		  local->dingo = 1;
-		  break;
-	}
-    } else {
-	switch(prodid & 15) {
-	  case 1: local->card_type = has_ce2_string(link)? XIR_CE2 : XIR_CE ;
-		  break;
-	  case 2: local->card_type = XIR_CE2; break;
-	  case 3: local->card_type = XIR_CE3;
-		  local->mohawk = 1;
-		  break;
-	}
-    }
-    if (local->card_type == XIR_CE || local->card_type == XIR_CEM) {
-	pr_notice("Sorry, this is an old CE card\n");
-	return 0;
-    }
-    if (local->card_type == XIR_UNKNOWN)
-	pr_notice("unknown card (mediaid=%02x prodid=%02x)\n", mediaid, prodid);
-
-    return 1;
-}
-
-/****************
- * There are some CE2 cards out which claim to be a CE card.
- * This function looks for a "CE2" in the 3rd version field.
- * Returns: true if this is a CE2
- */
-static int
-has_ce2_string(struct pcmcia_device * p_dev)
-{
-	if (p_dev->prod_id[2] && strstr(p_dev->prod_id[2], "CE2"))
-		return 1;
-	return 0;
-}
-
-static int
-xirc2ps_config_modem(struct pcmcia_device *p_dev, void *priv_data)
-{
-	unsigned int ioaddr;
-
-	if ((p_dev->resource[0]->start & 0xf) == 8)
-		return -ENODEV;
-
-	p_dev->resource[0]->end = 16;
-	p_dev->resource[1]->end = 8;
-	p_dev->resource[0]->flags &= ~IO_DATA_PATH_WIDTH;
-	p_dev->resource[0]->flags |= IO_DATA_PATH_WIDTH_16;
-	p_dev->resource[1]->flags &= ~IO_DATA_PATH_WIDTH;
-	p_dev->resource[1]->flags |= IO_DATA_PATH_WIDTH_8;
-	p_dev->io_lines = 10;
-
-	p_dev->resource[1]->start = p_dev->resource[0]->start;
-	for (ioaddr = 0x300; ioaddr < 0x400; ioaddr += 0x10) {
-		p_dev->resource[0]->start = ioaddr;
-		if (!pcmcia_request_io(p_dev))
-			return 0;
-	}
-	return -ENODEV;
-}
-
-static int
-xirc2ps_config_check(struct pcmcia_device *p_dev, void *priv_data)
-{
-	int *pass = priv_data;
-	resource_size_t tmp = p_dev->resource[1]->start;
-
-	tmp += (*pass ? (p_dev->config_index & 0x20 ? -24 : 8)
-		: (p_dev->config_index & 0x20 ?   8 : -24));
-
-	if ((p_dev->resource[0]->start & 0xf) == 8)
-		return -ENODEV;
-
-	p_dev->resource[0]->end = 18;
-	p_dev->resource[1]->end = 8;
-	p_dev->resource[0]->flags &= ~IO_DATA_PATH_WIDTH;
-	p_dev->resource[0]->flags |= IO_DATA_PATH_WIDTH_16;
-	p_dev->resource[1]->flags &= ~IO_DATA_PATH_WIDTH;
-	p_dev->resource[1]->flags |= IO_DATA_PATH_WIDTH_8;
-	p_dev->io_lines = 10;
-
-	p_dev->resource[1]->start = p_dev->resource[0]->start;
-	p_dev->resource[0]->start = tmp;
-	return pcmcia_request_io(p_dev);
-}
-
-
-static int pcmcia_get_mac_ce(struct pcmcia_device *p_dev,
-			     tuple_t *tuple,
-			     void *priv)
-{
-	struct net_device *dev = priv;
-
-	if (tuple->TupleDataLen != 13)
-		return -EINVAL;
-	if ((tuple->TupleData[0] != 2) || (tuple->TupleData[1] != 1) ||
-		(tuple->TupleData[2] != 6))
-		return -EINVAL;
-	/* another try	(James Lehmer's CE2 version 4.1)*/
-	dev_addr_mod(dev, 2, &tuple->TupleData[2], 4);
-	return 0;
-};
-
-
-static int
-xirc2ps_config(struct pcmcia_device * link)
-{
-    struct net_device *dev = link->priv;
-    struct local_info *local = netdev_priv(dev);
-    unsigned int ioaddr;
-    int err;
-    u8 *buf;
-    size_t len;
-
-    local->dingo_ccr = NULL;
-
-    dev_dbg(&link->dev, "config\n");
-
-    /* Is this a valid	card */
-    if (link->has_manf_id == 0) {
-	pr_notice("manfid not found in CIS\n");
-	goto failure;
-    }
-
-    switch (link->manf_id) {
-      case MANFID_XIRCOM:
-	local->manf_str = "Xircom";
-	break;
-      case MANFID_ACCTON:
-	local->manf_str = "Accton";
-	break;
-      case MANFID_COMPAQ:
-      case MANFID_COMPAQ2:
-	local->manf_str = "Compaq";
-	break;
-      case MANFID_INTEL:
-	local->manf_str = "Intel";
-	break;
-      case MANFID_TOSHIBA:
-	local->manf_str = "Toshiba";
-	break;
-      default:
-	pr_notice("Unknown Card Manufacturer ID: 0x%04x\n",
-		  (unsigned)link->manf_id);
-	goto failure;
-    }
-    dev_dbg(&link->dev, "found %s card\n", local->manf_str);
-
-    if (!set_card_type(link)) {
-	pr_notice("this card is not supported\n");
-	goto failure;
-    }
-
-    /* get the ethernet address from the CIS */
-    err = pcmcia_get_mac_from_cis(link, dev);
-
-    /* not found: try to get the node-id from tuple 0x89 */
-    if (err) {
-	    len = pcmcia_get_tuple(link, 0x89, &buf);
-	    /* data layout looks like tuple 0x22 */
-	    if (buf && len == 8) {
-		    if (*buf == CISTPL_FUNCE_LAN_NODE_ID)
-			    dev_addr_mod(dev, 2, &buf[2], 4);
-		    else
-			    err = -1;
-	    }
-	    kfree(buf);
-    }
-
-    if (err)
-	err = pcmcia_loop_tuple(link, CISTPL_FUNCE, pcmcia_get_mac_ce, dev);
-
-    if (err) {
-	pr_notice("node-id not found in CIS\n");
-	goto failure;
-    }
-
-    if (local->modem) {
-	int pass;
-	link->config_flags |= CONF_AUTO_SET_IO;
-
-	if (local->dingo) {
-	    /* Take the Modem IO port from the CIS and scan for a free
-	     * Ethernet port */
-	    if (!pcmcia_loop_config(link, xirc2ps_config_modem, NULL))
-		    goto port_found;
-	} else {
-	    /* We do 2 passes here: The first one uses the regular mapping and
-	     * the second tries again, thereby considering that the 32 ports are
-	     * mirrored every 32 bytes. Actually we use a mirrored port for
-	     * the Mako if (on the first pass) the COR bit 5 is set.
-	     */
-	    for (pass=0; pass < 2; pass++)
-		    if (!pcmcia_loop_config(link, xirc2ps_config_check,
-						    &pass))
-			    goto port_found;
-	    /* if special option:
-	     * try to configure as Ethernet only.
-	     * .... */
-	}
-	pr_notice("no ports available\n");
-    } else {
-	link->io_lines = 10;
-	link->resource[0]->end = 16;
-	link->resource[0]->flags |= IO_DATA_PATH_WIDTH_16;
-	for (ioaddr = 0x300; ioaddr < 0x400; ioaddr += 0x10) {
-	    link->resource[0]->start = ioaddr;
-	    if (!(err = pcmcia_request_io(link)))
-		goto port_found;
-	}
-	link->resource[0]->start = 0; /* let CS decide */
-	if ((err = pcmcia_request_io(link)))
-	    goto config_error;
-    }
-  port_found:
-
-    /****************
-     * Now allocate an interrupt line.	Note that this does not
-     * actually assign a handler to the interrupt.
-     */
-    if ((err=pcmcia_request_irq(link, xirc2ps_interrupt)))
-	goto config_error;
-
-    link->config_flags |= CONF_ENABLE_IRQ;
-    if (do_sound)
-	    link->config_flags |= CONF_ENABLE_SPKR;
-
-    if ((err = pcmcia_enable_device(link)))
-	goto config_error;
-
-    if (local->dingo) {
-	/* Reset the modem's BAR to the correct value
-	 * This is necessary because in the RequestConfiguration call,
-	 * the base address of the ethernet port (BasePort1) is written
-	 * to the BAR registers of the modem.
-	 */
-	err = pcmcia_write_config_byte(link, CISREG_IOBASE_0, (u8)
-				link->resource[1]->start & 0xff);
-	if (err)
-	    goto config_error;
-
-	err = pcmcia_write_config_byte(link, CISREG_IOBASE_1,
-				(link->resource[1]->start >> 8) & 0xff);
-	if (err)
-	    goto config_error;
-
-	/* There is no config entry for the Ethernet part which
-	 * is at 0x0800. So we allocate a window into the attribute
-	 * memory and write direct to the CIS registers
-	 */
-	link->resource[2]->flags = WIN_DATA_WIDTH_8 | WIN_MEMORY_TYPE_AM |
-					WIN_ENABLE;
-	link->resource[2]->start = link->resource[2]->end = 0;
-	if ((err = pcmcia_request_window(link, link->resource[2], 0)))
-	    goto config_error;
-
-	local->dingo_ccr = ioremap(link->resource[2]->start, 0x1000) + 0x0800;
-	if ((err = pcmcia_map_mem_page(link, link->resource[2], 0)))
-	    goto config_error;
-
-	/* Setup the CCRs; there are no infos in the CIS about the Ethernet
-	 * part.
-	 */
-	writeb(0x47, local->dingo_ccr + CISREG_COR);
-	ioaddr = link->resource[0]->start;
-	writeb(ioaddr & 0xff	  , local->dingo_ccr + CISREG_IOBASE_0);
-	writeb((ioaddr >> 8)&0xff , local->dingo_ccr + CISREG_IOBASE_1);
-
-      #if 0
-	{
-	    u_char tmp;
-	    pr_info("ECOR:");
-	    for (i=0; i < 7; i++) {
-		tmp = readb(local->dingo_ccr + i*2);
-		pr_cont(" %02x", tmp);
-	    }
-	    pr_cont("\n");
-	    pr_info("DCOR:");
-	    for (i=0; i < 4; i++) {
-		tmp = readb(local->dingo_ccr + 0x20 + i*2);
-		pr_cont(" %02x", tmp);
-	    }
-	    pr_cont("\n");
-	    pr_info("SCOR:");
-	    for (i=0; i < 10; i++) {
-		tmp = readb(local->dingo_ccr + 0x40 + i*2);
-		pr_cont(" %02x", tmp);
-	    }
-	    pr_cont("\n");
-	}
-      #endif
-
-	writeb(0x01, local->dingo_ccr + 0x20);
-	writeb(0x0c, local->dingo_ccr + 0x22);
-	writeb(0x00, local->dingo_ccr + 0x24);
-	writeb(0x00, local->dingo_ccr + 0x26);
-	writeb(0x00, local->dingo_ccr + 0x28);
-    }
-
-    /* The if_port symbol can be set when the module is loaded */
-    local->probe_port=0;
-    if (!if_port) {
-	local->probe_port = dev->if_port = 1;
-    } else if ((if_port >= 1 && if_port <= 2) ||
-	       (local->mohawk && if_port==4))
-	dev->if_port = if_port;
-    else
-	pr_notice("invalid if_port requested\n");
-
-    /* we can now register the device with the net subsystem */
-    dev->irq = link->irq;
-    dev->base_addr = link->resource[0]->start;
-
-    if (local->dingo)
-	do_reset(dev, 1); /* a kludge to make the cem56 work */
-
-    SET_NETDEV_DEV(dev, &link->dev);
-
-    if ((err=register_netdev(dev))) {
-	pr_notice("register_netdev() failed\n");
-	goto config_error;
-    }
-
-    /* give some infos about the hardware */
-    netdev_info(dev, "%s: port %#3lx, irq %d, hwaddr %pM\n",
-		local->manf_str, (u_long)dev->base_addr, (int)dev->irq,
-		dev->dev_addr);
-
-    return 0;
-
-  config_error:
-    xirc2ps_release(link);
-    return -ENODEV;
-
-  failure:
-    return -ENODEV;
-} /* xirc2ps_config */
-
-static void
-xirc2ps_release(struct pcmcia_device *link)
-{
-	dev_dbg(&link->dev, "release\n");
-
-	if (link->resource[2]->end) {
-		struct net_device *dev = link->priv;
-		struct local_info *local = netdev_priv(dev);
-		if (local->dingo)
-			iounmap(local->dingo_ccr - 0x0800);
-	}
-	pcmcia_disable_device(link);
-} /* xirc2ps_release */
-
-/*====================================================================*/
-
-
-static int xirc2ps_suspend(struct pcmcia_device *link)
-{
-	struct net_device *dev = link->priv;
-
-	if (link->open) {
-		netif_device_detach(dev);
-		do_powerdown(dev);
-	}
-
-	return 0;
-}
-
-static int xirc2ps_resume(struct pcmcia_device *link)
-{
-	struct net_device *dev = link->priv;
-
-	if (link->open) {
-		do_reset(dev,1);
-		netif_device_attach(dev);
-	}
-
-	return 0;
-}
-
-
-/*====================================================================*/
-
-/****************
- * This is the Interrupt service route.
- */
-static irqreturn_t
-xirc2ps_interrupt(int irq, void *dev_id)
-{
-    struct net_device *dev = (struct net_device *)dev_id;
-    struct local_info *lp = netdev_priv(dev);
-    unsigned int ioaddr;
-    u_char saved_page;
-    unsigned bytes_rcvd;
-    unsigned int_status, eth_status, rx_status, tx_status;
-    unsigned rsr, pktlen;
-    ulong start_ticks = jiffies; /* fixme: jiffies rollover every 497 days
-				  * is this something to worry about?
-				  * -- on a laptop?
-				  */
-
-    if (!netif_device_present(dev))
-	return IRQ_HANDLED;
-
-    ioaddr = dev->base_addr;
-    if (lp->mohawk) { /* must disable the interrupt */
-	PutByte(XIRCREG_CR, 0);
-    }
-
-    pr_debug("%s: interrupt %d at %#x.\n", dev->name, irq, ioaddr);
-
-    saved_page = GetByte(XIRCREG_PR);
-    /* Read the ISR to see whats the cause for the interrupt.
-     * This also clears the interrupt flags on CE2 cards
-     */
-    int_status = GetByte(XIRCREG_ISR);
-    bytes_rcvd = 0;
-  loop_entry:
-    if (int_status == 0xff) { /* card may be ejected */
-	pr_debug("%s: interrupt %d for dead card\n", dev->name, irq);
-	goto leave;
-    }
-    eth_status = GetByte(XIRCREG_ESR);
-
-    SelectPage(0x40);
-    rx_status  = GetByte(XIRCREG40_RXST0);
-    PutByte(XIRCREG40_RXST0, (~rx_status & 0xff));
-    tx_status = GetByte(XIRCREG40_TXST0);
-    tx_status |= GetByte(XIRCREG40_TXST1) << 8;
-    PutByte(XIRCREG40_TXST0, 0);
-    PutByte(XIRCREG40_TXST1, 0);
-
-    pr_debug("%s: ISR=%#2.2x ESR=%#2.2x RSR=%#2.2x TSR=%#4.4x\n",
-	  dev->name, int_status, eth_status, rx_status, tx_status);
-
-    /***** receive section ******/
-    SelectPage(0);
-    while (eth_status & FullPktRcvd) {
-	rsr = GetByte(XIRCREG0_RSR);
-	if (bytes_rcvd > maxrx_bytes && (rsr & PktRxOk)) {
-	    /* too many bytes received during this int, drop the rest of the
-	     * packets */
-	    dev->stats.rx_dropped++;
-	    pr_debug("%s: RX drop, too much done\n", dev->name);
-	} else if (rsr & PktRxOk) {
-	    struct sk_buff *skb;
-
-	    pktlen = GetWord(XIRCREG0_RBC);
-	    bytes_rcvd += pktlen;
-
-	    pr_debug("rsr=%#02x packet_length=%u\n", rsr, pktlen);
-
-	    /* 1 extra so we can use insw */
-	    skb = netdev_alloc_skb(dev, pktlen + 3);
-	    if (!skb) {
-		dev->stats.rx_dropped++;
-	    } else { /* okay get the packet */
-		skb_reserve(skb, 2);
-		if (lp->silicon == 0 ) { /* work around a hardware bug */
-		    unsigned rhsa; /* receive start address */
-
-		    SelectPage(5);
-		    rhsa = GetWord(XIRCREG5_RHSA0);
-		    SelectPage(0);
-		    rhsa += 3; /* skip control infos */
-		    if (rhsa >= 0x8000)
-			rhsa = 0;
-		    if (rhsa + pktlen > 0x8000) {
-			unsigned i;
-			u_char *buf = skb_put(skb, pktlen);
-			for (i=0; i < pktlen ; i++, rhsa++) {
-			    buf[i] = GetByte(XIRCREG_EDP);
-			    if (rhsa == 0x8000) {
-				rhsa = 0;
-				i--;
-			    }
-			}
-		    } else {
-			insw(ioaddr+XIRCREG_EDP,
-				skb_put(skb, pktlen), (pktlen+1)>>1);
-		    }
-		}
-	      #if 0
-		else if (lp->mohawk) {
-		    /* To use this 32 bit access we should use
-		     * a manual optimized loop
-		     * Also the words are swapped, we can get more
-		     * performance by using 32 bit access and swapping
-		     * the words in a register. Will need this for cardbus
-		     *
-		     * Note: don't forget to change the ALLOC_SKB to .. +3
-		     */
-		    unsigned i;
-		    u_long *p = skb_put(skb, pktlen);
-		    register u_long a;
-		    unsigned int edpreg = ioaddr+XIRCREG_EDP-2;
-		    for (i=0; i < len ; i += 4, p++) {
-			a = inl(edpreg);
-			__asm__("rorl $16,%0\n\t"
-				:"=q" (a)
-				: "0" (a));
-			*p = a;
-		    }
-		}
-	      #endif
-		else {
-		    insw(ioaddr+XIRCREG_EDP, skb_put(skb, pktlen),
-			    (pktlen+1)>>1);
-		}
-		skb->protocol = eth_type_trans(skb, dev);
-		netif_rx(skb);
-		dev->stats.rx_packets++;
-		dev->stats.rx_bytes += pktlen;
-		if (!(rsr & PhyPkt))
-		    dev->stats.multicast++;
-	    }
-	} else { /* bad packet */
-	    pr_debug("rsr=%#02x\n", rsr);
-	}
-	if (rsr & PktTooLong) {
-	    dev->stats.rx_frame_errors++;
-	    pr_debug("%s: Packet too long\n", dev->name);
-	}
-	if (rsr & CRCErr) {
-	    dev->stats.rx_crc_errors++;
-	    pr_debug("%s: CRC error\n", dev->name);
-	}
-	if (rsr & AlignErr) {
-	    dev->stats.rx_fifo_errors++; /* okay ? */
-	    pr_debug("%s: Alignment error\n", dev->name);
-	}
-
-	/* clear the received/dropped/error packet */
-	PutWord(XIRCREG0_DO, 0x8000); /* issue cmd: skip_rx_packet */
-
-	/* get the new ethernet status */
-	eth_status = GetByte(XIRCREG_ESR);
-    }
-    if (rx_status & 0x10) { /* Receive overrun */
-	dev->stats.rx_over_errors++;
-	PutByte(XIRCREG_CR, ClearRxOvrun);
-	pr_debug("receive overrun cleared\n");
-    }
-
-    /***** transmit section ******/
-    if (int_status & PktTxed) {
-	unsigned n, nn;
-
-	n = lp->last_ptr_value;
-	nn = GetByte(XIRCREG0_PTR);
-	lp->last_ptr_value = nn;
-	if (nn < n) /* rollover */
-	    dev->stats.tx_packets += 256 - n;
-	else if (n == nn) { /* happens sometimes - don't know why */
-	    pr_debug("PTR not changed?\n");
-	} else
-	    dev->stats.tx_packets += lp->last_ptr_value - n;
-	netif_wake_queue(dev);
-    }
-    if (tx_status & 0x0002) {	/* Excessive collisions */
-	pr_debug("tx restarted due to excessive collisions\n");
-	PutByte(XIRCREG_CR, RestartTx);  /* restart transmitter process */
-    }
-    if (tx_status & 0x0040)
-	dev->stats.tx_aborted_errors++;
-
-    /* recalculate our work chunk so that we limit the duration of this
-     * ISR to about 1/10 of a second.
-     * Calculate only if we received a reasonable amount of bytes.
-     */
-    if (bytes_rcvd > 1000) {
-	u_long duration = jiffies - start_ticks;
-
-	if (duration >= HZ/10) { /* if more than about 1/10 second */
-	    maxrx_bytes = (bytes_rcvd * (HZ/10)) / duration;
-	    if (maxrx_bytes < 2000)
-		maxrx_bytes = 2000;
-	    else if (maxrx_bytes > 22000)
-		maxrx_bytes = 22000;
-	    pr_debug("set maxrx=%u (rcvd=%u ticks=%lu)\n",
-		  maxrx_bytes, bytes_rcvd, duration);
-	} else if (!duration && maxrx_bytes < 22000) {
-	    /* now much faster */
-	    maxrx_bytes += 2000;
-	    if (maxrx_bytes > 22000)
-		maxrx_bytes = 22000;
-	    pr_debug("set maxrx=%u\n", maxrx_bytes);
-	}
-    }
-
-  leave:
-    if (lockup_hack) {
-	if (int_status != 0xff && (int_status = GetByte(XIRCREG_ISR)) != 0)
-	    goto loop_entry;
-    }
-    SelectPage(saved_page);
-    PutByte(XIRCREG_CR, EnableIntr);  /* re-enable interrupts */
-    /* Instead of dropping packets during a receive, we could
-     * force an interrupt with this command:
-     *	  PutByte(XIRCREG_CR, EnableIntr|ForceIntr);
-     */
-    return IRQ_HANDLED;
-} /* xirc2ps_interrupt */
-
-/*====================================================================*/
-
-static void
-xirc2ps_tx_timeout_task(struct work_struct *work)
-{
-	struct local_info *local =
-		container_of(work, struct local_info, tx_timeout_task);
-	struct net_device *dev = local->dev;
-    /* reset the card */
-    do_reset(dev,1);
-    netif_trans_update(dev); /* prevent tx timeout */
-    netif_wake_queue(dev);
-}
-
-static void
-xirc_tx_timeout(struct net_device *dev, unsigned int txqueue)
-{
-    struct local_info *lp = netdev_priv(dev);
-    dev->stats.tx_errors++;
-    netdev_notice(dev, "transmit timed out\n");
-    schedule_work(&lp->tx_timeout_task);
-}
-
-static netdev_tx_t
-do_start_xmit(struct sk_buff *skb, struct net_device *dev)
-{
-    struct local_info *lp = netdev_priv(dev);
-    unsigned int ioaddr = dev->base_addr;
-    int okay;
-    unsigned freespace;
-    unsigned pktlen = skb->len;
-
-    pr_debug("do_start_xmit(skb=%p, dev=%p) len=%u\n",
-	  skb, dev, pktlen);
-
-
-    /* adjust the packet length to min. required
-     * and hope that the buffer is large enough
-     * to provide some random data.
-     * fixme: For Mohawk we can change this by sending
-     * a larger packetlen than we actually have; the chip will
-     * pad this in his buffer with random bytes
-     */
-    if (pktlen < ETH_ZLEN)
-    {
-        if (skb_padto(skb, ETH_ZLEN))
-		return NETDEV_TX_OK;
-	pktlen = ETH_ZLEN;
-    }
-
-    netif_stop_queue(dev);
-    SelectPage(0);
-    PutWord(XIRCREG0_TRS, (u_short)pktlen+2);
-    freespace = GetWord(XIRCREG0_TSO) & 0x7fff;
-    /* TRS doesn't work - (indeed it is eliminated with sil-rev 1) */
-    okay = pktlen +2 < freespace;
-    pr_debug("%s: avail. tx space=%u%s\n",
-	  dev->name, freespace, okay ? " (okay)":" (not enough)");
-    if (!okay) { /* not enough space */
-	return NETDEV_TX_BUSY;  /* upper layer may decide to requeue this packet */
-    }
-    /* send the packet */
-    PutWord(XIRCREG_EDP, (u_short)pktlen);
-    outsw(ioaddr+XIRCREG_EDP, skb->data, pktlen>>1);
-    if (pktlen & 1)
-	PutByte(XIRCREG_EDP, skb->data[pktlen-1]);
-
-    if (lp->mohawk)
-	PutByte(XIRCREG_CR, TransmitPacket|EnableIntr);
-
-    dev_kfree_skb (skb);
-    dev->stats.tx_bytes += pktlen;
-    netif_start_queue(dev);
-    return NETDEV_TX_OK;
-}
-
-struct set_address_info {
-	int reg_nr;
-	int page_nr;
-	int mohawk;
-	unsigned int ioaddr;
-};
-
-static void set_address(struct set_address_info *sa_info, const char *addr)
-{
-	unsigned int ioaddr = sa_info->ioaddr;
-	int i;
-
-	for (i = 0; i < 6; i++) {
-		if (sa_info->reg_nr > 15) {
-			sa_info->reg_nr = 8;
-			sa_info->page_nr++;
-			SelectPage(sa_info->page_nr);
-		}
-		if (sa_info->mohawk)
-			PutByte(sa_info->reg_nr++, addr[5 - i]);
-		else
-			PutByte(sa_info->reg_nr++, addr[i]);
-	}
-}
-
-/****************
- * Set all addresses: This first one is the individual address,
- * the next 9 addresses are taken from the multicast list and
- * the rest is filled with the individual address.
- */
-static void set_addresses(struct net_device *dev)
-{
-	unsigned int ioaddr = dev->base_addr;
-	struct local_info *lp = netdev_priv(dev);
-	struct netdev_hw_addr *ha;
-	struct set_address_info sa_info;
-	int i;
-
-	/*
-	 * Setup the info structure so that by first set_address call it will do
-	 * SelectPage with the right page number. Hence these ones here.
-	 */
-	sa_info.reg_nr = 15 + 1;
-	sa_info.page_nr = 0x50 - 1;
-	sa_info.mohawk = lp->mohawk;
-	sa_info.ioaddr = ioaddr;
-
-	set_address(&sa_info, dev->dev_addr);
-	i = 0;
-	netdev_for_each_mc_addr(ha, dev) {
-		if (i++ == 9)
-			break;
-		set_address(&sa_info, ha->addr);
-	}
-	while (i++ < 9)
-		set_address(&sa_info, dev->dev_addr);
-	SelectPage(0);
-}
-
-/****************
- * Set or clear the multicast filter for this adaptor.
- * We can filter up to 9 addresses, if more are requested we set
- * multicast promiscuous mode.
- */
-
-static void
-set_multicast_list(struct net_device *dev)
-{
-    unsigned int ioaddr = dev->base_addr;
-    unsigned value;
-
-    SelectPage(0x42);
-    value = GetByte(XIRCREG42_SWC1) & 0xC0;
-
-    if (dev->flags & IFF_PROMISC) { /* snoop */
-	PutByte(XIRCREG42_SWC1, value | 0x06); /* set MPE and PME */
-    } else if (netdev_mc_count(dev) > 9 || (dev->flags & IFF_ALLMULTI)) {
-	PutByte(XIRCREG42_SWC1, value | 0x02); /* set MPE */
-    } else if (!netdev_mc_empty(dev)) {
-	/* the chip can filter 9 addresses perfectly */
-	PutByte(XIRCREG42_SWC1, value | 0x01);
-	SelectPage(0x40);
-	PutByte(XIRCREG40_CMD0, Offline);
-	set_addresses(dev);
-	SelectPage(0x40);
-	PutByte(XIRCREG40_CMD0, EnableRecv | Online);
-    } else { /* standard usage */
-	PutByte(XIRCREG42_SWC1, value | 0x00);
-    }
-    SelectPage(0);
-}
-
-static int
-do_config(struct net_device *dev, struct ifmap *map)
-{
-    struct local_info *local = netdev_priv(dev);
-
-    pr_debug("do_config(%p)\n", dev);
-    if (map->port != 255 && map->port != dev->if_port) {
-	if (map->port > 4)
-	    return -EINVAL;
-	if (!map->port) {
-	    local->probe_port = 1;
-	    WRITE_ONCE(dev->if_port, 1);
-	} else {
-	    local->probe_port = 0;
-	    WRITE_ONCE(dev->if_port, map->port);
-	}
-	netdev_info(dev, "switching to %s port\n", if_names[dev->if_port]);
-	do_reset(dev,1);  /* not the fine way :-) */
-    }
-    return 0;
-}
-
-/****************
- * Open the driver
- */
-static int
-do_open(struct net_device *dev)
-{
-    struct local_info *lp = netdev_priv(dev);
-    struct pcmcia_device *link = lp->p_dev;
-
-    dev_dbg(&link->dev, "do_open(%p)\n", dev);
-
-    /* Check that the PCMCIA card is still here. */
-    /* Physical device present signature. */
-    if (!pcmcia_dev_present(link))
-	return -ENODEV;
-
-    /* okay */
-    link->open++;
-
-    netif_start_queue(dev);
-    do_reset(dev,1);
-
-    return 0;
-}
-
-static void netdev_get_drvinfo(struct net_device *dev,
-			       struct ethtool_drvinfo *info)
-{
-	strscpy(info->driver, "xirc2ps_cs", sizeof(info->driver));
-	snprintf(info->bus_info, sizeof(info->bus_info), "PCMCIA 0x%lx",
-		 dev->base_addr);
-}
-
-static const struct ethtool_ops netdev_ethtool_ops = {
-	.get_drvinfo		= netdev_get_drvinfo,
-};
-
-static int
-do_ioctl(struct net_device *dev, struct ifreq *rq, int cmd)
-{
-    struct local_info *local = netdev_priv(dev);
-    unsigned int ioaddr = dev->base_addr;
-    struct mii_ioctl_data *data = if_mii(rq);
-
-    pr_debug("%s: ioctl(%-.6s, %#04x) %04x %04x %04x %04x\n",
-	  dev->name, rq->ifr_ifrn.ifrn_name, cmd,
-	  data->phy_id, data->reg_num, data->val_in, data->val_out);
-
-    if (!local->mohawk)
-	return -EOPNOTSUPP;
-
-    switch(cmd) {
-      case SIOCGMIIPHY:		/* Get the address of the PHY in use. */
-	data->phy_id = 0;	/* we have only this address */
-	fallthrough;
-      case SIOCGMIIREG:		/* Read the specified MII register. */
-	data->val_out = mii_rd(ioaddr, data->phy_id & 0x1f,
-			       data->reg_num & 0x1f);
-	break;
-      case SIOCSMIIREG:		/* Write the specified MII register */
-	mii_wr(ioaddr, data->phy_id & 0x1f, data->reg_num & 0x1f, data->val_in,
-	       16);
-	break;
-      default:
-	return -EOPNOTSUPP;
-    }
-    return 0;
-}
-
-static void
-hardreset(struct net_device *dev)
-{
-    struct local_info *local = netdev_priv(dev);
-    unsigned int ioaddr = dev->base_addr;
-
-    SelectPage(4);
-    udelay(1);
-    PutByte(XIRCREG4_GPR1, 0);	     /* clear bit 0: power down */
-    msleep(40);				     /* wait 40 msec */
-    if (local->mohawk)
-	PutByte(XIRCREG4_GPR1, 1);	 /* set bit 0: power up */
-    else
-	PutByte(XIRCREG4_GPR1, 1 | 4);	 /* set bit 0: power up, bit 2: AIC */
-    msleep(20);			     /* wait 20 msec */
-}
-
-static void
-do_reset(struct net_device *dev, int full)
-{
-    struct local_info *local = netdev_priv(dev);
-    unsigned int ioaddr = dev->base_addr;
-    unsigned value;
-
-    pr_debug("%s: do_reset(%p,%d)\n", dev->name, dev, full);
-
-    hardreset(dev);
-    PutByte(XIRCREG_CR, SoftReset); /* set */
-    msleep(20);			     /* wait 20 msec */
-    PutByte(XIRCREG_CR, 0);	     /* clear */
-    msleep(40);			     /* wait 40 msec */
-    if (local->mohawk) {
-	SelectPage(4);
-	/* set pin GP1 and GP2 to output  (0x0c)
-	 * set GP1 to low to power up the ML6692 (0x00)
-	 * set GP2 to high to power up the 10Mhz chip  (0x02)
-	 */
-	PutByte(XIRCREG4_GPR0, 0x0e);
-    }
-
-    /* give the circuits some time to power up */
-    msleep(500);			/* about 500ms */
-
-    local->last_ptr_value = 0;
-    local->silicon = local->mohawk ? (GetByte(XIRCREG4_BOV) & 0x70) >> 4
-				   : (GetByte(XIRCREG4_BOV) & 0x30) >> 4;
-
-    if (local->probe_port) {
-	if (!local->mohawk) {
-	    SelectPage(4);
-	    PutByte(XIRCREG4_GPR0, 4);
-	    local->probe_port = 0;
-	}
-    } else if (dev->if_port == 2) { /* enable 10Base2 */
-	SelectPage(0x42);
-	PutByte(XIRCREG42_SWC1, 0xC0);
-    } else { /* enable 10BaseT */
-	SelectPage(0x42);
-	PutByte(XIRCREG42_SWC1, 0x80);
-    }
-    msleep(40);			     /* wait 40 msec to let it complete */
-
-  #if 0
-    {
-	SelectPage(0);
-	value = GetByte(XIRCREG_ESR);	 /* read the ESR */
-	pr_debug("%s: ESR is: %#02x\n", dev->name, value);
-    }
-  #endif
-
-    /* setup the ECR */
-    SelectPage(1);
-    PutByte(XIRCREG1_IMR0, 0xff); /* allow all ints */
-    PutByte(XIRCREG1_IMR1, 1	); /* and Set TxUnderrunDetect */
-    value = GetByte(XIRCREG1_ECR);
-  #if 0
-    if (local->mohawk)
-	value |= DisableLinkPulse;
-    PutByte(XIRCREG1_ECR, value);
-  #endif
-    pr_debug("%s: ECR is: %#02x\n", dev->name, value);
-
-    SelectPage(0x42);
-    PutByte(XIRCREG42_SWC0, 0x20); /* disable source insertion */
-
-    if (local->silicon != 1) {
-	/* set the local memory dividing line.
-	 * The comments in the sample code say that this is only
-	 * settable with the scipper version 2 which is revision 0.
-	 * Always for CE3 cards
-	 */
-	SelectPage(2);
-	PutWord(XIRCREG2_RBS, 0x2000);
-    }
-
-    if (full)
-	set_addresses(dev);
-
-    /* Hardware workaround:
-     * The receive byte pointer after reset is off by 1 so we need
-     * to move the offset pointer back to 0.
-     */
-    SelectPage(0);
-    PutWord(XIRCREG0_DO, 0x2000); /* change offset command, off=0 */
-
-    /* setup MAC IMRs and clear status registers */
-    SelectPage(0x40);		     /* Bit 7 ... bit 0 */
-    PutByte(XIRCREG40_RMASK0, 0xff); /* ROK, RAB, rsv, RO, CRC, AE, PTL, MP */
-    PutByte(XIRCREG40_TMASK0, 0xff); /* TOK, TAB, SQE, LL, TU, JAB, EXC, CRS */
-    PutByte(XIRCREG40_TMASK1, 0xb0); /* rsv, rsv, PTD, EXT, rsv,rsv,rsv, rsv*/
-    PutByte(XIRCREG40_RXST0,  0x00); /* ROK, RAB, REN, RO, CRC, AE, PTL, MP */
-    PutByte(XIRCREG40_TXST0,  0x00); /* TOK, TAB, SQE, LL, TU, JAB, EXC, CRS */
-    PutByte(XIRCREG40_TXST1,  0x00); /* TEN, rsv, PTD, EXT, retry_counter:4  */
-
-    if (full && local->mohawk && init_mii(dev)) {
-	if (dev->if_port == 4 || local->dingo || local->new_mii) {
-	    netdev_info(dev, "MII selected\n");
-	    SelectPage(2);
-	    PutByte(XIRCREG2_MSR, GetByte(XIRCREG2_MSR) | 0x08);
-	    msleep(20);
-	} else {
-	    netdev_info(dev, "MII detected; using 10mbs\n");
-	    SelectPage(0x42);
-	    if (dev->if_port == 2) /* enable 10Base2 */
-		PutByte(XIRCREG42_SWC1, 0xC0);
-	    else  /* enable 10BaseT */
-		PutByte(XIRCREG42_SWC1, 0x80);
-	    msleep(40);			/* wait 40 msec to let it complete */
-	}
-	if (full_duplex)
-	    PutByte(XIRCREG1_ECR, GetByte(XIRCREG1_ECR) | FullDuplex);
-    } else {  /* No MII */
-	SelectPage(0);
-	value = GetByte(XIRCREG_ESR);	 /* read the ESR */
-	dev->if_port = (value & MediaSelect) ? 1 : 2;
-    }
-
-    /* configure the LEDs */
-    SelectPage(2);
-    if (dev->if_port == 1 || dev->if_port == 4) /* TP: Link and Activity */
-	PutByte(XIRCREG2_LED, 0x3b);
-    else			      /* Coax: Not-Collision and Activity */
-	PutByte(XIRCREG2_LED, 0x3a);
-
-    if (local->dingo)
-	PutByte(0x0b, 0x04); /* 100 Mbit LED */
-
-    /* enable receiver and put the mac online */
-    if (full) {
-	set_multicast_list(dev);
-	SelectPage(0x40);
-	PutByte(XIRCREG40_CMD0, EnableRecv | Online);
-    }
-
-    /* setup Ethernet IMR and enable interrupts */
-    SelectPage(1);
-    PutByte(XIRCREG1_IMR0, 0xff);
-    udelay(1);
-    SelectPage(0);
-    PutByte(XIRCREG_CR, EnableIntr);
-    if (local->modem && !local->dingo) { /* do some magic */
-	if (!(GetByte(0x10) & 0x01))
-	    PutByte(0x10, 0x11); /* unmask master-int bit */
-    }
-
-    if (full)
-	netdev_info(dev, "media %s, silicon revision %d\n",
-		    if_names[dev->if_port], local->silicon);
-    /* We should switch back to page 0 to avoid a bug in revision 0
-     * where regs with offset below 8 can't be read after an access
-     * to the MAC registers */
-    SelectPage(0);
-}
-
-/****************
- * Initialize the Media-Independent-Interface
- * Returns: True if we have a good MII
- */
-static int
-init_mii(struct net_device *dev)
-{
-    struct local_info *local = netdev_priv(dev);
-    unsigned int ioaddr = dev->base_addr;
-    unsigned control, status, linkpartner;
-    int i;
-
-    if (if_port == 4 || if_port == 1) { /* force 100BaseT or 10BaseT */
-	dev->if_port = if_port;
-	local->probe_port = 0;
-	return 1;
-    }
-
-    status = mii_rd(ioaddr,  0, 1);
-    if ((status & 0xff00) != 0x7800)
-	return 0; /* No MII */
-
-    local->new_mii = (mii_rd(ioaddr, 0, 2) != 0xffff);
-    
-    if (local->probe_port)
-	control = 0x1000; /* auto neg */
-    else if (dev->if_port == 4)
-	control = 0x2000; /* no auto neg, 100mbs mode */
-    else
-	control = 0x0000; /* no auto neg, 10mbs mode */
-    mii_wr(ioaddr,  0, 0, control, 16);
-    udelay(100);
-    control = mii_rd(ioaddr, 0, 0);
-
-    if (control & 0x0400) {
-	netdev_notice(dev, "can't take PHY out of isolation mode\n");
-	local->probe_port = 0;
-	return 0;
-    }
-
-    if (local->probe_port) {
-	/* according to the DP83840A specs the auto negotiation process
-	 * may take up to 3.5 sec, so we use this also for our ML6692
-	 * Fixme: Better to use a timer here!
-	 */
-	for (i=0; i < 35; i++) {
-	    msleep(100);	 /* wait 100 msec */
-	    status = mii_rd(ioaddr,  0, 1);
-	    if ((status & 0x0020) && (status & 0x0004))
-		break;
-	}
-
-	if (!(status & 0x0020)) {
-	    netdev_info(dev, "autonegotiation failed; using 10mbs\n");
-	    if (!local->new_mii) {
-		control = 0x0000;
-		mii_wr(ioaddr,  0, 0, control, 16);
-		udelay(100);
-		SelectPage(0);
-		dev->if_port = (GetByte(XIRCREG_ESR) & MediaSelect) ? 1 : 2;
-	    }
-	} else {
-	    linkpartner = mii_rd(ioaddr, 0, 5);
-	    netdev_info(dev, "MII link partner: %04x\n", linkpartner);
-	    if (linkpartner & 0x0080) {
-		dev->if_port = 4;
-	    } else
-		dev->if_port = 1;
-	}
-    }
-
-    return 1;
-}
-
-static void
-do_powerdown(struct net_device *dev)
-{
-
-    unsigned int ioaddr = dev->base_addr;
-
-    pr_debug("do_powerdown(%p)\n", dev);
-
-    SelectPage(4);
-    PutByte(XIRCREG4_GPR1, 0);	     /* clear bit 0: power down */
-    SelectPage(0);
-}
-
-static int
-do_stop(struct net_device *dev)
-{
-    unsigned int ioaddr = dev->base_addr;
-    struct local_info *lp = netdev_priv(dev);
-    struct pcmcia_device *link = lp->p_dev;
-
-    dev_dbg(&link->dev, "do_stop(%p)\n", dev);
-
-    if (!link)
-	return -ENODEV;
-
-    netif_stop_queue(dev);
-
-    SelectPage(0);
-    PutByte(XIRCREG_CR, 0);  /* disable interrupts */
-    SelectPage(0x01);
-    PutByte(XIRCREG1_IMR0, 0x00); /* forbid all ints */
-    SelectPage(4);
-    PutByte(XIRCREG4_GPR1, 0);	/* clear bit 0: power down */
-    SelectPage(0);
-
-    link->open--;
-    return 0;
-}
-
-static const struct pcmcia_device_id xirc2ps_ids[] = {
-	PCMCIA_PFC_DEVICE_MANF_CARD(0, 0x0089, 0x110a),
-	PCMCIA_PFC_DEVICE_MANF_CARD(0, 0x0138, 0x110a),
-	PCMCIA_PFC_DEVICE_PROD_ID13(0, "Xircom", "CEM28", 0x2e3ee845, 0x0ea978ea),
-	PCMCIA_PFC_DEVICE_PROD_ID13(0, "Xircom", "CEM33", 0x2e3ee845, 0x80609023),
-	PCMCIA_PFC_DEVICE_PROD_ID13(0, "Xircom", "CEM56", 0x2e3ee845, 0xa650c32a),
-	PCMCIA_PFC_DEVICE_PROD_ID13(0, "Xircom", "REM10", 0x2e3ee845, 0x76df1d29),
-	PCMCIA_PFC_DEVICE_PROD_ID13(0, "Xircom", "XEM5600", 0x2e3ee845, 0xf1403719),
-	PCMCIA_PFC_DEVICE_PROD_ID12(0, "Xircom", "CreditCard Ethernet+Modem II", 0x2e3ee845, 0xeca401bf),
-	PCMCIA_DEVICE_MANF_CARD(0x01bf, 0x010a),
-	PCMCIA_DEVICE_PROD_ID13("Toshiba Information Systems", "TPCENET", 0x1b3b94fe, 0xf381c1a2),
-	PCMCIA_DEVICE_PROD_ID13("Xircom", "CE3-10/100", 0x2e3ee845, 0x0ec0ac37),
-	PCMCIA_DEVICE_PROD_ID13("Xircom", "PS-CE2-10", 0x2e3ee845, 0x947d9073),
-	PCMCIA_DEVICE_PROD_ID13("Xircom", "R2E-100BTX", 0x2e3ee845, 0x2464a6e3),
-	PCMCIA_DEVICE_PROD_ID13("Xircom", "RE-10", 0x2e3ee845, 0x3e08d609),
-	PCMCIA_DEVICE_PROD_ID13("Xircom", "XE2000", 0x2e3ee845, 0xf7188e46),
-	PCMCIA_DEVICE_PROD_ID12("Compaq", "Ethernet LAN Card", 0x54f7c49c, 0x9fd2f0a2),
-	PCMCIA_DEVICE_PROD_ID12("Compaq", "Netelligent 10/100 PC Card", 0x54f7c49c, 0xefe96769),
-	PCMCIA_DEVICE_PROD_ID12("Intel", "EtherExpress(TM) PRO/100 PC Card Mobile Adapter16", 0x816cc815, 0x174397db),
-	PCMCIA_DEVICE_PROD_ID12("Toshiba", "10/100 Ethernet PC Card", 0x44a09d9c, 0xb44deecf),
-	/* also matches CFE-10 cards! */
-	/* PCMCIA_DEVICE_MANF_CARD(0x0105, 0x010a), */
-	PCMCIA_DEVICE_NULL,
-};
-MODULE_DEVICE_TABLE(pcmcia, xirc2ps_ids);
-
-
-static struct pcmcia_driver xirc2ps_cs_driver = {
-	.owner		= THIS_MODULE,
-	.name		= "xirc2ps_cs",
-	.probe		= xirc2ps_probe,
-	.remove		= xirc2ps_detach,
-	.id_table       = xirc2ps_ids,
-	.suspend	= xirc2ps_suspend,
-	.resume		= xirc2ps_resume,
-};
-module_pcmcia_driver(xirc2ps_cs_driver);
-
-#ifndef MODULE
-static int __init setup_xirc2ps_cs(char *str)
-{
-	/* if_port, full_duplex, do_sound, lockup_hack
-	 */
-	int ints[10] = { -1 };
-
-	str = get_options(str, ARRAY_SIZE(ints), ints);
-
-#define MAYBE_SET(X,Y) if (ints[0] >= Y && ints[Y] != -1) { X = ints[Y]; }
-	MAYBE_SET(if_port, 3);
-	MAYBE_SET(full_duplex, 4);
-	MAYBE_SET(do_sound, 5);
-	MAYBE_SET(lockup_hack, 6);
-#undef  MAYBE_SET
-
-	return 1;
-}
-
-__setup("xirc2ps_cs=", setup_xirc2ps_cs);
-#endif

-- 
2.53.0


^ permalink raw reply related	[flat|nested] 28+ messages in thread

* [PATCH net 15/18] drivers: net: 8390: AX88190: Remove this driver
  2026-04-21 19:31 [PATCH net 00/18] Remove a number of ISA and PCMCIA Ethernet drivers Andrew Lunn
                   ` (13 preceding siblings ...)
  2026-04-21 19:31 ` [PATCH net 14/18] drivers: net: xircom: xirc2ps: " Andrew Lunn
@ 2026-04-21 19:31 ` Andrew Lunn
  2026-04-21 19:31 ` [PATCH net 16/18] drivers: net: 8390: pcnet: " Andrew Lunn
                   ` (6 subsequent siblings)
  21 siblings, 0 replies; 28+ messages in thread
From: Andrew Lunn @ 2026-04-21 19:31 UTC (permalink / raw)
  To: Andrew Lunn, David S. Miller, Eric Dumazet, Jakub Kicinski,
	Paolo Abeni, Simon Horman, Jonathan Corbet, Shuah Khan
  Cc: linux-kernel, netdev, linux-doc, Andrew Lunn

The ax88190 was written by David A. Hindsh in 2001. It is an PCMCIA
device, so unlikely to be used with modern kernels.

Signed-off-by: Andrew Lunn <andrew@lunn.ch>
---
 drivers/net/ethernet/8390/Kconfig    |   12 -
 drivers/net/ethernet/8390/Makefile   |    1 -
 drivers/net/ethernet/8390/axnet_cs.c | 1707 ----------------------------------
 3 files changed, 1720 deletions(-)

diff --git a/drivers/net/ethernet/8390/Kconfig b/drivers/net/ethernet/8390/Kconfig
index 345f250781c6..3dea042cc2eb 100644
--- a/drivers/net/ethernet/8390/Kconfig
+++ b/drivers/net/ethernet/8390/Kconfig
@@ -17,18 +17,6 @@ config NET_VENDOR_8390
 
 if NET_VENDOR_8390
 
-config PCMCIA_AXNET
-	tristate "Asix AX88190 PCMCIA support"
-	depends on PCMCIA && HAS_IOPORT
-	help
-	  Say Y here if you intend to attach an Asix AX88190-based PCMCIA
-	  (PC-card) Fast Ethernet card to your computer.  These cards are
-	  nearly NE2000 compatible but need a separate driver due to a few
-	  misfeatures.
-
-	  To compile this driver as a module, choose M here: the module will be
-	  called axnet_cs.  If unsure, say N.
-
 config AX88796
 	tristate "ASIX AX88796 NE2000 clone support" if !ZORRO
 	depends on (ARM || MIPS || SUPERH || ZORRO || COMPILE_TEST)
diff --git a/drivers/net/ethernet/8390/Makefile b/drivers/net/ethernet/8390/Makefile
index 85c83c566ec6..60220484b382 100644
--- a/drivers/net/ethernet/8390/Makefile
+++ b/drivers/net/ethernet/8390/Makefile
@@ -11,7 +11,6 @@ obj-$(CONFIG_HYDRA) += hydra.o
 obj-$(CONFIG_MCF8390) += mcf8390.o
 obj-$(CONFIG_NE2000) += ne.o 8390p.o
 obj-$(CONFIG_NE2K_PCI) += ne2k-pci.o 8390.o
-obj-$(CONFIG_PCMCIA_AXNET) += axnet_cs.o 8390.o
 obj-$(CONFIG_PCMCIA_PCNET) += pcnet_cs.o 8390.o
 obj-$(CONFIG_STNIC) += stnic.o 8390.o
 obj-$(CONFIG_ULTRA) += smc-ultra.o 8390.o
diff --git a/drivers/net/ethernet/8390/axnet_cs.c b/drivers/net/ethernet/8390/axnet_cs.c
deleted file mode 100644
index 7c8213011b5c..000000000000
--- a/drivers/net/ethernet/8390/axnet_cs.c
+++ /dev/null
@@ -1,1707 +0,0 @@
-// SPDX-License-Identifier: GPL-1.0+
-
-/*======================================================================
-
-    A PCMCIA ethernet driver for Asix AX88190-based cards
-
-    The Asix AX88190 is a NS8390-derived chipset with a few nasty
-    idiosyncracies that make it very inconvenient to support with a
-    standard 8390 driver.  This driver is based on pcnet_cs, with the
-    tweaked 8390 code grafted on the end.  Much of what I did was to
-    clean up and update a similar driver supplied by Asix, which was
-    adapted by William Lee, william@asix.com.tw.
-
-    Copyright (C) 2001 David A. Hinds -- dahinds@users.sourceforge.net
-
-    axnet_cs.c 1.28 2002/06/29 06:27:37
-
-    The network driver code is based on Donald Becker's NE2000 code:
-
-    Written 1992,1993 by Donald Becker.
-    Copyright 1993 United States Government as represented by the
-    Director, National Security Agency.
-    Donald Becker may be reached at becker@scyld.com
-
-======================================================================*/
-
-#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
-
-#include <linux/kernel.h>
-#include <linux/module.h>
-#include <linux/ptrace.h>
-#include <linux/string.h>
-#include <linux/timer.h>
-#include <linux/delay.h>
-#include <linux/spinlock.h>
-#include <linux/netdevice.h>
-#include <linux/etherdevice.h>
-#include <linux/crc32.h>
-#include <linux/mii.h>
-#include "8390.h"
-
-#include <pcmcia/cistpl.h>
-#include <pcmcia/ciscode.h>
-#include <pcmcia/ds.h>
-#include <pcmcia/cisreg.h>
-
-#include <asm/io.h>
-#include <asm/byteorder.h>
-#include <linux/uaccess.h>
-
-#define AXNET_CMD	0x00
-#define AXNET_DATAPORT	0x10	/* NatSemi-defined port window offset. */
-#define AXNET_RESET	0x1f	/* Issue a read to reset, a write to clear. */
-#define AXNET_MII_EEP	0x14	/* Offset of MII access port */
-#define AXNET_TEST	0x15	/* Offset of TEST Register port */
-#define AXNET_GPIO	0x17	/* Offset of General Purpose Register Port */
-
-#define AXNET_START_PG	0x40	/* First page of TX buffer */
-#define AXNET_STOP_PG	0x80	/* Last page +1 of RX ring */
-
-#define AXNET_RDC_TIMEOUT 0x02	/* Max wait in jiffies for Tx RDC */
-
-#define IS_AX88190	0x0001
-#define IS_AX88790	0x0002
-
-/*====================================================================*/
-
-/* Module parameters */
-
-MODULE_AUTHOR("David Hinds <dahinds@users.sourceforge.net>");
-MODULE_DESCRIPTION("Asix AX88190 PCMCIA ethernet driver");
-MODULE_LICENSE("GPL");
-
-
-/*====================================================================*/
-
-static int axnet_config(struct pcmcia_device *link);
-static void axnet_release(struct pcmcia_device *link);
-static int axnet_open(struct net_device *dev);
-static int axnet_close(struct net_device *dev);
-static int axnet_ioctl(struct net_device *dev, struct ifreq *rq, int cmd);
-static netdev_tx_t axnet_start_xmit(struct sk_buff *skb,
-					  struct net_device *dev);
-static struct net_device_stats *get_stats(struct net_device *dev);
-static void set_multicast_list(struct net_device *dev);
-static void axnet_tx_timeout(struct net_device *dev, unsigned int txqueue);
-static irqreturn_t ei_irq_wrapper(int irq, void *dev_id);
-static void ei_watchdog(struct timer_list *t);
-static void axnet_reset_8390(struct net_device *dev);
-
-static int mdio_read(unsigned int addr, int phy_id, int loc);
-static void mdio_write(unsigned int addr, int phy_id, int loc, int value);
-
-static void get_8390_hdr(struct net_device *,
-			 struct e8390_pkt_hdr *, int);
-static void block_input(struct net_device *dev, int count,
-			struct sk_buff *skb, int ring_offset);
-static void block_output(struct net_device *dev, int count,
-			 const u_char *buf, const int start_page);
-
-static void axnet_detach(struct pcmcia_device *p_dev);
-
-static void AX88190_init(struct net_device *dev, int startp);
-static int ax_open(struct net_device *dev);
-static int ax_close(struct net_device *dev);
-static irqreturn_t ax_interrupt(int irq, void *dev_id);
-
-/*====================================================================*/
-
-struct axnet_dev {
-	struct pcmcia_device	*p_dev;
-	caddr_t	base;
-	struct timer_list	watchdog;
-	int	stale, fast_poll;
-	u_short	link_status;
-	u_char	duplex_flag;
-	int	phy_id;
-	int	flags;
-	int	active_low;
-};
-
-static inline struct axnet_dev *PRIV(struct net_device *dev)
-{
-	void *p = (char *)netdev_priv(dev) + sizeof(struct ei_device);
-	return p;
-}
-
-static const struct net_device_ops axnet_netdev_ops = {
-	.ndo_open 		= axnet_open,
-	.ndo_stop		= axnet_close,
-	.ndo_eth_ioctl		= axnet_ioctl,
-	.ndo_start_xmit		= axnet_start_xmit,
-	.ndo_tx_timeout		= axnet_tx_timeout,
-	.ndo_get_stats		= get_stats,
-	.ndo_set_rx_mode	= set_multicast_list,
-	.ndo_set_mac_address 	= eth_mac_addr,
-	.ndo_validate_addr	= eth_validate_addr,
-};
-
-static int axnet_probe(struct pcmcia_device *link)
-{
-    struct axnet_dev *info;
-    struct net_device *dev;
-    struct ei_device *ei_local;
-
-    dev_dbg(&link->dev, "axnet_attach()\n");
-
-    dev = alloc_etherdev(sizeof(struct ei_device) + sizeof(struct axnet_dev));
-    if (!dev)
-	return -ENOMEM;
-
-    ei_local = netdev_priv(dev);
-    spin_lock_init(&ei_local->page_lock);
-
-    info = PRIV(dev);
-    info->p_dev = link;
-    link->priv = dev;
-    link->config_flags |= CONF_ENABLE_IRQ;
-
-    dev->netdev_ops = &axnet_netdev_ops;
-
-    dev->watchdog_timeo = TX_TIMEOUT;
-
-    return axnet_config(link);
-} /* axnet_attach */
-
-static void axnet_detach(struct pcmcia_device *link)
-{
-    struct net_device *dev = link->priv;
-
-    dev_dbg(&link->dev, "axnet_detach(0x%p)\n", link);
-
-    unregister_netdev(dev);
-
-    axnet_release(link);
-
-    free_netdev(dev);
-} /* axnet_detach */
-
-/*======================================================================
-
-    This probes for a card's hardware address by reading the PROM.
-
-======================================================================*/
-
-static int get_prom(struct pcmcia_device *link)
-{
-    struct net_device *dev = link->priv;
-    unsigned int ioaddr = dev->base_addr;
-    u8 addr[ETH_ALEN];
-    int i, j;
-
-    /* This is based on drivers/net/ethernet/8390/ne.c */
-    struct {
-	u_char value, offset;
-    } program_seq[] = {
-	{E8390_NODMA+E8390_PAGE0+E8390_STOP, E8390_CMD}, /* Select page 0*/
-	{0x01,	EN0_DCFG},	/* Set word-wide access. */
-	{0x00,	EN0_RCNTLO},	/* Clear the count regs. */
-	{0x00,	EN0_RCNTHI},
-	{0x00,	EN0_IMR},	/* Mask completion irq. */
-	{0xFF,	EN0_ISR},
-	{E8390_RXOFF|0x40, EN0_RXCR},	/* 0x60  Set to monitor */
-	{E8390_TXOFF, EN0_TXCR},	/* 0x02  and loopback mode. */
-	{0x10,	EN0_RCNTLO},
-	{0x00,	EN0_RCNTHI},
-	{0x00,	EN0_RSARLO},	/* DMA starting at 0x0400. */
-	{0x04,	EN0_RSARHI},
-	{E8390_RREAD+E8390_START, E8390_CMD},
-    };
-
-    /* Not much of a test, but the alternatives are messy */
-    if (link->config_base != 0x03c0)
-	return 0;
-
-    axnet_reset_8390(dev);
-    mdelay(10);
-
-    for (i = 0; i < ARRAY_SIZE(program_seq); i++)
-	outb_p(program_seq[i].value, ioaddr + program_seq[i].offset);
-
-    for (i = 0; i < 6; i += 2) {
-	j = inw(ioaddr + AXNET_DATAPORT);
-	addr[i] = j & 0xff;
-	addr[i+1] = j >> 8;
-    }
-    eth_hw_addr_set(dev, addr);
-
-    return 1;
-} /* get_prom */
-
-static int try_io_port(struct pcmcia_device *link)
-{
-    int j, ret;
-    link->resource[0]->flags &= ~IO_DATA_PATH_WIDTH;
-    link->resource[1]->flags &= ~IO_DATA_PATH_WIDTH;
-    if (link->resource[0]->end == 32) {
-	link->resource[0]->flags |= IO_DATA_PATH_WIDTH_AUTO;
-	/* for master/slave multifunction cards */
-	if (link->resource[1]->end > 0)
-	    link->resource[1]->flags |= IO_DATA_PATH_WIDTH_8;
-    } else {
-	/* This should be two 16-port windows */
-	link->resource[0]->flags |= IO_DATA_PATH_WIDTH_8;
-	link->resource[1]->flags |= IO_DATA_PATH_WIDTH_16;
-    }
-    if (link->resource[0]->start == 0) {
-	for (j = 0; j < 0x400; j += 0x20) {
-	    link->resource[0]->start = j ^ 0x300;
-	    link->resource[1]->start = (j ^ 0x300) + 0x10;
-	    link->io_lines = 16;
-	    ret = pcmcia_request_io(link);
-	    if (ret == 0)
-		    return ret;
-	}
-	return ret;
-    } else {
-	return pcmcia_request_io(link);
-    }
-}
-
-static int axnet_configcheck(struct pcmcia_device *p_dev, void *priv_data)
-{
-	if (p_dev->config_index == 0)
-		return -EINVAL;
-
-	p_dev->config_index = 0x05;
-	if (p_dev->resource[0]->end + p_dev->resource[1]->end < 32)
-		return -ENODEV;
-
-	return try_io_port(p_dev);
-}
-
-static int axnet_config(struct pcmcia_device *link)
-{
-    struct net_device *dev = link->priv;
-    struct axnet_dev *info = PRIV(dev);
-    int i, j, j2, ret;
-
-    dev_dbg(&link->dev, "axnet_config(0x%p)\n", link);
-
-    /* don't trust the CIS on this; Linksys got it wrong */
-    link->config_regs = 0x63;
-    link->config_flags |= CONF_ENABLE_IRQ | CONF_AUTO_SET_IO;
-    ret = pcmcia_loop_config(link, axnet_configcheck, NULL);
-    if (ret != 0)
-	goto failed;
-
-    if (!link->irq)
-	    goto failed;
-
-    if (resource_size(link->resource[1]) == 8)
-	link->config_flags |= CONF_ENABLE_SPKR;
-    
-    ret = pcmcia_enable_device(link);
-    if (ret)
-	    goto failed;
-
-    dev->irq = link->irq;
-    dev->base_addr = link->resource[0]->start;
-
-    if (!get_prom(link)) {
-	pr_notice("this is not an AX88190 card!\n");
-	pr_notice("use pcnet_cs instead.\n");
-	goto failed;
-    }
-
-    ei_status.name = "AX88190";
-    ei_status.word16 = 1;
-    ei_status.tx_start_page = AXNET_START_PG;
-    ei_status.rx_start_page = AXNET_START_PG + TX_PAGES;
-    ei_status.stop_page = AXNET_STOP_PG;
-    ei_status.reset_8390 = axnet_reset_8390;
-    ei_status.get_8390_hdr = get_8390_hdr;
-    ei_status.block_input = block_input;
-    ei_status.block_output = block_output;
-
-    if (inb(dev->base_addr + AXNET_TEST) != 0)
-	info->flags |= IS_AX88790;
-    else
-	info->flags |= IS_AX88190;
-
-    if (info->flags & IS_AX88790)
-	outb(0x10, dev->base_addr + AXNET_GPIO);  /* select Internal PHY */
-
-    info->active_low = 0;
-
-    for (i = 0; i < 32; i++) {
-	j = mdio_read(dev->base_addr + AXNET_MII_EEP, i, 1);
-	j2 = mdio_read(dev->base_addr + AXNET_MII_EEP, i, 2);
-	if (j == j2) continue;
-	if ((j != 0) && (j != 0xffff)) break;
-    }
-
-    if (i == 32) {
-	/* Maybe PHY is in power down mode. (PPD_SET = 1)
-	   Bit 2 of CCSR is active low. */
-	pcmcia_write_config_byte(link, CISREG_CCSR, 0x04);
-	for (i = 0; i < 32; i++) {
-	    j = mdio_read(dev->base_addr + AXNET_MII_EEP, i, 1);
-	    j2 = mdio_read(dev->base_addr + AXNET_MII_EEP, i, 2);
-	    if (j == j2) continue;
-	    if ((j != 0) && (j != 0xffff)) {
-		info->active_low = 1;
-		break;
-	    }
-	}
-    }
-
-    info->phy_id = (i < 32) ? i : -1;
-    SET_NETDEV_DEV(dev, &link->dev);
-
-    if (register_netdev(dev) != 0) {
-	pr_notice("register_netdev() failed\n");
-	goto failed;
-    }
-
-    netdev_info(dev, "Asix AX88%d90: io %#3lx, irq %d, hw_addr %pM\n",
-		((info->flags & IS_AX88790) ? 7 : 1),
-		dev->base_addr, dev->irq, dev->dev_addr);
-    if (info->phy_id != -1) {
-	netdev_dbg(dev, "  MII transceiver at index %d, status %x\n",
-		   info->phy_id, j);
-    } else {
-	netdev_notice(dev, "  No MII transceivers found!\n");
-    }
-    return 0;
-
-failed:
-    axnet_release(link);
-    return -ENODEV;
-} /* axnet_config */
-
-static void axnet_release(struct pcmcia_device *link)
-{
-	pcmcia_disable_device(link);
-}
-
-static int axnet_suspend(struct pcmcia_device *link)
-{
-	struct net_device *dev = link->priv;
-
-	if (link->open)
-		netif_device_detach(dev);
-
-	return 0;
-}
-
-static int axnet_resume(struct pcmcia_device *link)
-{
-	struct net_device *dev = link->priv;
-	struct axnet_dev *info = PRIV(dev);
-
-	if (link->open) {
-		if (info->active_low == 1)
-			pcmcia_write_config_byte(link, CISREG_CCSR, 0x04);
-
-		axnet_reset_8390(dev);
-		AX88190_init(dev, 1);
-		netif_device_attach(dev);
-	}
-
-	return 0;
-}
-
-
-/*======================================================================
-
-    MII interface support
-
-======================================================================*/
-
-#define MDIO_SHIFT_CLK		0x01
-#define MDIO_DATA_WRITE0	0x00
-#define MDIO_DATA_WRITE1	0x08
-#define MDIO_DATA_READ		0x04
-#define MDIO_MASK		0x0f
-#define MDIO_ENB_IN		0x02
-
-static void mdio_sync(unsigned int addr)
-{
-    int bits;
-    for (bits = 0; bits < 32; bits++) {
-	outb_p(MDIO_DATA_WRITE1, addr);
-	outb_p(MDIO_DATA_WRITE1 | MDIO_SHIFT_CLK, addr);
-    }
-}
-
-static int mdio_read(unsigned int addr, int phy_id, int loc)
-{
-    u_int cmd = (0xf6<<10)|(phy_id<<5)|loc;
-    int i, retval = 0;
-
-    mdio_sync(addr);
-    for (i = 14; i >= 0; i--) {
-	int dat = (cmd&(1<<i)) ? MDIO_DATA_WRITE1 : MDIO_DATA_WRITE0;
-	outb_p(dat, addr);
-	outb_p(dat | MDIO_SHIFT_CLK, addr);
-    }
-    for (i = 19; i > 0; i--) {
-	outb_p(MDIO_ENB_IN, addr);
-	retval = (retval << 1) | ((inb_p(addr) & MDIO_DATA_READ) != 0);
-	outb_p(MDIO_ENB_IN | MDIO_SHIFT_CLK, addr);
-    }
-    return (retval>>1) & 0xffff;
-}
-
-static void mdio_write(unsigned int addr, int phy_id, int loc, int value)
-{
-    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_p(dat, addr);
-	outb_p(dat | MDIO_SHIFT_CLK, addr);
-    }
-    for (i = 1; i >= 0; i--) {
-	outb_p(MDIO_ENB_IN, addr);
-	outb_p(MDIO_ENB_IN | MDIO_SHIFT_CLK, addr);
-    }
-}
-
-/*====================================================================*/
-
-static int axnet_open(struct net_device *dev)
-{
-    int ret;
-    struct axnet_dev *info = PRIV(dev);
-    struct pcmcia_device *link = info->p_dev;
-    unsigned int nic_base = dev->base_addr;
-    
-    dev_dbg(&link->dev, "axnet_open('%s')\n", dev->name);
-
-    if (!pcmcia_dev_present(link))
-	return -ENODEV;
-
-    outb_p(0xFF, nic_base + EN0_ISR); /* Clear bogus intr. */
-    ret = request_irq(dev->irq, ei_irq_wrapper, IRQF_SHARED, "axnet_cs", dev);
-    if (ret)
-	    return ret;
-
-    link->open++;
-
-    info->link_status = 0x00;
-    timer_setup(&info->watchdog, ei_watchdog, 0);
-    mod_timer(&info->watchdog, jiffies + HZ);
-
-    return ax_open(dev);
-} /* axnet_open */
-
-/*====================================================================*/
-
-static int axnet_close(struct net_device *dev)
-{
-    struct axnet_dev *info = PRIV(dev);
-    struct pcmcia_device *link = info->p_dev;
-
-    dev_dbg(&link->dev, "axnet_close('%s')\n", dev->name);
-
-    ax_close(dev);
-    free_irq(dev->irq, dev);
-    
-    link->open--;
-    netif_stop_queue(dev);
-    timer_delete_sync(&info->watchdog);
-
-    return 0;
-} /* axnet_close */
-
-/*======================================================================
-
-    Hard reset the card.  This used to pause for the same period that
-    a 8390 reset command required, but that shouldn't be necessary.
-
-======================================================================*/
-
-static void axnet_reset_8390(struct net_device *dev)
-{
-    unsigned int nic_base = dev->base_addr;
-    int i;
-
-    ei_status.txing = ei_status.dmaing = 0;
-
-    outb_p(E8390_NODMA+E8390_PAGE0+E8390_STOP, nic_base + E8390_CMD);
-
-    outb(inb(nic_base + AXNET_RESET), nic_base + AXNET_RESET);
-
-    for (i = 0; i < 100; i++) {
-	if ((inb_p(nic_base+EN0_ISR) & ENISR_RESET) != 0)
-	    break;
-	udelay(100);
-    }
-    outb_p(ENISR_RESET, nic_base + EN0_ISR); /* Ack intr. */
-    
-    if (i == 100)
-	netdev_err(dev, "axnet_reset_8390() did not complete\n");
-    
-} /* axnet_reset_8390 */
-
-/*====================================================================*/
-
-static irqreturn_t ei_irq_wrapper(int irq, void *dev_id)
-{
-    struct net_device *dev = dev_id;
-    PRIV(dev)->stale = 0;
-    return ax_interrupt(irq, dev_id);
-}
-
-static void ei_watchdog(struct timer_list *t)
-{
-    struct axnet_dev *info = timer_container_of(info, t, watchdog);
-    struct net_device *dev = info->p_dev->priv;
-    unsigned int nic_base = dev->base_addr;
-    unsigned int mii_addr = nic_base + AXNET_MII_EEP;
-    u_short link;
-
-    if (!netif_device_present(dev)) goto reschedule;
-
-    /* Check for pending interrupt with expired latency timer: with
-       this, we can limp along even if the interrupt is blocked */
-    if (info->stale++ && (inb_p(nic_base + EN0_ISR) & ENISR_ALL)) {
-	if (!info->fast_poll)
-	    netdev_info(dev, "interrupt(s) dropped!\n");
-	ei_irq_wrapper(dev->irq, dev);
-	info->fast_poll = HZ;
-    }
-    if (info->fast_poll) {
-	info->fast_poll--;
-	info->watchdog.expires = jiffies + 1;
-	add_timer(&info->watchdog);
-	return;
-    }
-
-    if (info->phy_id < 0)
-	goto reschedule;
-    link = mdio_read(mii_addr, info->phy_id, 1);
-    if (!link || (link == 0xffff)) {
-	netdev_info(dev, "MII is missing!\n");
-	info->phy_id = -1;
-	goto reschedule;
-    }
-
-    link &= 0x0004;
-    if (link != info->link_status) {
-	u_short p = mdio_read(mii_addr, info->phy_id, 5);
-	netdev_info(dev, "%s link beat\n", link ? "found" : "lost");
-	if (link) {
-	    info->duplex_flag = (p & 0x0140) ? 0x80 : 0x00;
-	    if (p)
-		netdev_info(dev, "autonegotiation complete: %dbaseT-%cD selected\n",
-			    (p & 0x0180) ? 100 : 10, (p & 0x0140) ? 'F' : 'H');
-	    else
-		netdev_info(dev, "link partner did not autonegotiate\n");
-	    AX88190_init(dev, 1);
-	}
-	info->link_status = link;
-    }
-
-reschedule:
-    info->watchdog.expires = jiffies + HZ;
-    add_timer(&info->watchdog);
-}
-
-/*====================================================================*/
-
-static int axnet_ioctl(struct net_device *dev, struct ifreq *rq, int cmd)
-{
-    struct axnet_dev *info = PRIV(dev);
-    struct mii_ioctl_data *data = if_mii(rq);
-    unsigned int mii_addr = dev->base_addr + AXNET_MII_EEP;
-    switch (cmd) {
-    case SIOCGMIIPHY:
-	data->phy_id = info->phy_id;
-	fallthrough;
-    case SIOCGMIIREG:		/* Read MII PHY register. */
-	data->val_out = mdio_read(mii_addr, data->phy_id, data->reg_num & 0x1f);
-	return 0;
-    case SIOCSMIIREG:		/* Write MII PHY register. */
-	mdio_write(mii_addr, data->phy_id, data->reg_num & 0x1f, data->val_in);
-	return 0;
-    }
-    return -EOPNOTSUPP;
-}
-
-/*====================================================================*/
-
-static void get_8390_hdr(struct net_device *dev,
-			 struct e8390_pkt_hdr *hdr,
-			 int ring_page)
-{
-    unsigned int nic_base = dev->base_addr;
-
-    outb_p(0, nic_base + EN0_RSARLO);		/* On page boundary */
-    outb_p(ring_page, nic_base + EN0_RSARHI);
-    outb_p(E8390_RREAD+E8390_START, nic_base + AXNET_CMD);
-
-    insw(nic_base + AXNET_DATAPORT, hdr,
-	    sizeof(struct e8390_pkt_hdr)>>1);
-    /* Fix for big endian systems */
-    hdr->count = le16_to_cpu(hdr->count);
-
-}
-
-/*====================================================================*/
-
-static void block_input(struct net_device *dev, int count,
-			struct sk_buff *skb, int ring_offset)
-{
-    unsigned int nic_base = dev->base_addr;
-    struct ei_device *ei_local = netdev_priv(dev);
-    char *buf = skb->data;
-
-    if ((netif_msg_rx_status(ei_local)) && (count != 4))
-	netdev_dbg(dev, "[bi=%d]\n", count+4);
-    outb_p(ring_offset & 0xff, nic_base + EN0_RSARLO);
-    outb_p(ring_offset >> 8, nic_base + EN0_RSARHI);
-    outb_p(E8390_RREAD+E8390_START, nic_base + AXNET_CMD);
-
-    insw(nic_base + AXNET_DATAPORT,buf,count>>1);
-    if (count & 0x01) {
-	buf[count-1] = inb(nic_base + AXNET_DATAPORT);
-    }
-}
-
-/*====================================================================*/
-
-static void block_output(struct net_device *dev, int count,
-			 const u_char *buf, const int start_page)
-{
-    unsigned int nic_base = dev->base_addr;
-
-    pr_debug("%s: [bo=%d]\n", dev->name, count);
-
-    /* Round the count up for word writes.  Do we need to do this?
-       What effect will an odd byte count have on the 8390?
-       I should check someday. */
-    if (count & 0x01)
-	count++;
-
-    outb_p(0x00, nic_base + EN0_RSARLO);
-    outb_p(start_page, nic_base + EN0_RSARHI);
-    outb_p(E8390_RWRITE+E8390_START, nic_base + AXNET_CMD);
-    outsw(nic_base + AXNET_DATAPORT, buf, count>>1);
-}
-
-static const struct pcmcia_device_id axnet_ids[] = {
-	PCMCIA_PFC_DEVICE_MANF_CARD(0, 0x016c, 0x0081),
-	PCMCIA_DEVICE_MANF_CARD(0x018a, 0x0301),
-	PCMCIA_DEVICE_MANF_CARD(0x01bf, 0x2328),
-	PCMCIA_DEVICE_MANF_CARD(0x026f, 0x0301),
-	PCMCIA_DEVICE_MANF_CARD(0x026f, 0x0303),
-	PCMCIA_DEVICE_MANF_CARD(0x026f, 0x0309),
-	PCMCIA_DEVICE_MANF_CARD(0x0274, 0x1106),
-	PCMCIA_DEVICE_MANF_CARD(0x8a01, 0xc1ab),
-	PCMCIA_DEVICE_MANF_CARD(0x021b, 0x0202), 
-	PCMCIA_DEVICE_MANF_CARD(0xffff, 0x1090),
-	PCMCIA_DEVICE_PROD_ID12("AmbiCom,Inc.", "Fast Ethernet PC Card(AMB8110)", 0x49b020a7, 0x119cc9fc),
-	PCMCIA_DEVICE_PROD_ID124("Fast Ethernet", "16-bit PC Card", "AX88190", 0xb4be14e3, 0x9a12eb6a, 0xab9be5ef),
-	PCMCIA_DEVICE_PROD_ID12("ASIX", "AX88190", 0x0959823b, 0xab9be5ef),
-	PCMCIA_DEVICE_PROD_ID12("Billionton", "LNA-100B", 0x552ab682, 0xbc3b87e1),
-	PCMCIA_DEVICE_PROD_ID12("CHEETAH ETHERCARD", "EN2228", 0x00fa7bc8, 0x00e990cc),
-	PCMCIA_DEVICE_PROD_ID12("CNet", "CNF301", 0xbc477dde, 0x78c5f40b),
-	PCMCIA_DEVICE_PROD_ID12("corega K.K.", "corega FEther PCC-TXD", 0x5261440f, 0x436768c5),
-	PCMCIA_DEVICE_PROD_ID12("corega K.K.", "corega FEtherII PCC-TXD", 0x5261440f, 0x730df72e),
-	PCMCIA_DEVICE_PROD_ID12("corega K.K.", "corega FEther PCC-TXM", 0x5261440f, 0x3abbd061),
-	PCMCIA_DEVICE_PROD_ID12("Dynalink", "L100C16", 0x55632fd5, 0x66bc2a90),
-	PCMCIA_DEVICE_PROD_ID12("IO DATA", "ETXPCM", 0x547e66dc, 0x233adac2),
-	PCMCIA_DEVICE_PROD_ID12("Linksys", "EtherFast 10/100 PC Card (PCMPC100 V3)", 0x0733cc81, 0x232019a8),
-	PCMCIA_DEVICE_PROD_ID12("MELCO", "LPC3-TX", 0x481e0094, 0xf91af609),
-	PCMCIA_DEVICE_PROD_ID12("NETGEAR", "FA411", 0x9aa79dc3, 0x40fad875),
-	PCMCIA_DEVICE_PROD_ID12("PCMCIA", "100BASE", 0x281f1c5d, 0x7c2add04),
-	PCMCIA_DEVICE_PROD_ID12("PCMCIA", "FastEtherCard", 0x281f1c5d, 0x7ef26116),
-	PCMCIA_DEVICE_PROD_ID12("PCMCIA", "FEP501", 0x281f1c5d, 0x2e272058),
-	PCMCIA_DEVICE_PROD_ID14("Network Everywhere", "AX88190", 0x820a67b6,  0xab9be5ef),
-	PCMCIA_DEVICE_NULL,
-};
-MODULE_DEVICE_TABLE(pcmcia, axnet_ids);
-
-static struct pcmcia_driver axnet_cs_driver = {
-	.owner		= THIS_MODULE,
-	.name		= "axnet_cs",
-	.probe		= axnet_probe,
-	.remove		= axnet_detach,
-	.id_table       = axnet_ids,
-	.suspend	= axnet_suspend,
-	.resume		= axnet_resume,
-};
-module_pcmcia_driver(axnet_cs_driver);
-
-/*====================================================================*/
-
-/* 8390.c: A general NS8390 ethernet driver core for linux. */
-/*
-	Written 1992-94 by Donald Becker.
-  
-	Copyright 1993 United States Government as represented by the
-	Director, National Security Agency.
-
-	This software may be used and distributed according to the terms
-	of the GNU General Public License, incorporated herein by reference.
-
-	The author may be reached as becker@scyld.com, or C/O
-	Scyld Computing Corporation
-	410 Severn Ave., Suite 210
-	Annapolis MD 21403
-
-  This is the chip-specific code for many 8390-based ethernet adaptors.
-  This is not a complete driver, it must be combined with board-specific
-  code such as ne.c, wd.c, 3c503.c, etc.
-
-  Seeing how at least eight drivers use this code, (not counting the
-  PCMCIA ones either) it is easy to break some card by what seems like
-  a simple innocent change. Please contact me or Donald if you think
-  you have found something that needs changing. -- PG
-
-  Changelog:
-
-  Paul Gortmaker	: remove set_bit lock, other cleanups.
-  Paul Gortmaker	: add ei_get_8390_hdr() so we can pass skb's to 
-			  ei_block_input() for eth_io_copy_and_sum().
-  Paul Gortmaker	: exchange static int ei_pingpong for a #define,
-			  also add better Tx error handling.
-  Paul Gortmaker	: rewrite Rx overrun handling as per NS specs.
-  Alexey Kuznetsov	: use the 8390's six bit hash multicast filter.
-  Paul Gortmaker	: tweak ANK's above multicast changes a bit.
-  Paul Gortmaker	: update packet statistics for v2.1.x
-  Alan Cox		: support arbitrary stupid port mappings on the
-			  68K Macintosh. Support >16bit I/O spaces
-  Paul Gortmaker	: add kmod support for auto-loading of the 8390
-			  module by all drivers that require it.
-  Alan Cox		: Spinlocking work, added 'BUG_83C690'
-  Paul Gortmaker	: Separate out Tx timeout code from Tx path.
-
-  Sources:
-  The National Semiconductor LAN Databook, and the 3Com 3c503 databook.
-
-  */
-
-#include <linux/bitops.h>
-#include <asm/irq.h>
-#include <linux/fcntl.h>
-#include <linux/in.h>
-#include <linux/interrupt.h>
-
-#define BUG_83C690
-
-/* These are the operational function interfaces to board-specific
-   routines.
-	void reset_8390(struct net_device *dev)
-		Resets the board associated with DEV, including a hardware reset of
-		the 8390.  This is only called when there is a transmit timeout, and
-		it is always followed by 8390_init().
-	void block_output(struct net_device *dev, int count, const unsigned char *buf,
-					  int start_page)
-		Write the COUNT bytes of BUF to the packet buffer at START_PAGE.  The
-		"page" value uses the 8390's 256-byte pages.
-	void get_8390_hdr(struct net_device *dev, struct e8390_hdr *hdr, int ring_page)
-		Read the 4 byte, page aligned 8390 header. *If* there is a
-		subsequent read, it will be of the rest of the packet.
-	void block_input(struct net_device *dev, int count, struct sk_buff *skb, int ring_offset)
-		Read COUNT bytes from the packet buffer into the skb data area. Start 
-		reading from RING_OFFSET, the address as the 8390 sees it.  This will always
-		follow the read of the 8390 header. 
-*/
-#define ei_reset_8390 (ei_local->reset_8390)
-#define ei_block_output (ei_local->block_output)
-#define ei_block_input (ei_local->block_input)
-#define ei_get_8390_hdr (ei_local->get_8390_hdr)
-
-/* Index to functions. */
-static void ei_tx_intr(struct net_device *dev);
-static void ei_tx_err(struct net_device *dev);
-static void ei_receive(struct net_device *dev);
-static void ei_rx_overrun(struct net_device *dev);
-
-/* Routines generic to NS8390-based boards. */
-static void NS8390_trigger_send(struct net_device *dev, unsigned int length,
-								int start_page);
-static void do_set_multicast_list(struct net_device *dev);
-
-/*
- *	SMP and the 8390 setup.
- *
- *	The 8390 isn't exactly designed to be multithreaded on RX/TX. There is
- *	a page register that controls bank and packet buffer access. We guard
- *	this with ei_local->page_lock. Nobody should assume or set the page other
- *	than zero when the lock is not held. Lock holders must restore page 0
- *	before unlocking. Even pure readers must take the lock to protect in 
- *	page 0.
- *
- *	To make life difficult the chip can also be very slow. We therefore can't
- *	just use spinlocks. For the longer lockups we disable the irq the device
- *	sits on and hold the lock. We must hold the lock because there is a dual
- *	processor case other than interrupts (get stats/set multicast list in
- *	parallel with each other and transmit).
- *
- *	Note: in theory we can just disable the irq on the card _but_ there is
- *	a latency on SMP irq delivery. So we can easily go "disable irq" "sync irqs"
- *	enter lock, take the queued irq. So we waddle instead of flying.
- *
- *	Finally by special arrangement for the purpose of being generally 
- *	annoying the transmit function is called bh atomic. That places
- *	restrictions on the user context callers as disable_irq won't save
- *	them.
- */
- 
-/**
- * ax_open - Open/initialize the board.
- * @dev: network device to initialize
- *
- * This routine goes all-out, setting everything
- * up anew at each open, even though many of these registers should only
- * need to be set once at boot.
- */
-static int ax_open(struct net_device *dev)
-{
-	unsigned long flags;
-	struct ei_device *ei_local = netdev_priv(dev);
-
-	/*
-	 *	Grab the page lock so we own the register set, then call
-	 *	the init function.
-	 */
-      
-      	spin_lock_irqsave(&ei_local->page_lock, flags);
-	AX88190_init(dev, 1);
-	/* Set the flag before we drop the lock, That way the IRQ arrives
-	   after its set and we get no silly warnings */
-	netif_start_queue(dev);
-      	spin_unlock_irqrestore(&ei_local->page_lock, flags);
-	ei_local->irqlock = 0;
-	return 0;
-}
-
-#define dev_lock(dev) (((struct ei_device *)netdev_priv(dev))->page_lock)
-
-/**
- * ax_close - shut down network device
- * @dev: network device to close
- *
- * Opposite of ax_open(). Only used when "ifconfig <devname> down" is done.
- */
-static int ax_close(struct net_device *dev)
-{
-	unsigned long flags;
-
-	/*
-	 *      Hold the page lock during close
-	 */
-
-	spin_lock_irqsave(&dev_lock(dev), flags);
-	AX88190_init(dev, 0);
-	spin_unlock_irqrestore(&dev_lock(dev), flags);
-	netif_stop_queue(dev);
-	return 0;
-}
-
-/**
- * axnet_tx_timeout - handle transmit time out condition
- * @dev: network device which has apparently fallen asleep
- * @txqueue: unused
- *
- * Called by kernel when device never acknowledges a transmit has
- * completed (or failed) - i.e. never posted a Tx related interrupt.
- */
-
-static void axnet_tx_timeout(struct net_device *dev, unsigned int txqueue)
-{
-	long e8390_base = dev->base_addr;
-	struct ei_device *ei_local = netdev_priv(dev);
-	int txsr, isr, tickssofar = jiffies - dev_trans_start(dev);
-	unsigned long flags;
-
-	dev->stats.tx_errors++;
-
-	spin_lock_irqsave(&ei_local->page_lock, flags);
-	txsr = inb(e8390_base+EN0_TSR);
-	isr = inb(e8390_base+EN0_ISR);
-	spin_unlock_irqrestore(&ei_local->page_lock, flags);
-
-	netdev_dbg(dev, "Tx timed out, %s TSR=%#2x, ISR=%#2x, t=%d.\n",
-		   (txsr & ENTSR_ABT) ? "excess collisions." :
-		   (isr) ? "lost interrupt?" : "cable problem?",
-		   txsr, isr, tickssofar);
-
-	if (!isr && !dev->stats.tx_packets) 
-	{
-		/* The 8390 probably hasn't gotten on the cable yet. */
-		ei_local->interface_num ^= 1;   /* Try a different xcvr.  */
-	}
-
-	/* Ugly but a reset can be slow, yet must be protected */
-		
-	spin_lock_irqsave(&ei_local->page_lock, flags);
-		
-	/* Try to restart the card.  Perhaps the user has fixed something. */
-	ei_reset_8390(dev);
-	AX88190_init(dev, 1);
-		
-	spin_unlock_irqrestore(&ei_local->page_lock, flags);
-	netif_wake_queue(dev);
-}
-    
-/**
- * axnet_start_xmit - begin packet transmission
- * @skb: packet to be sent
- * @dev: network device to which packet is sent
- *
- * Sends a packet to an 8390 network device.
- */
- 
-static netdev_tx_t axnet_start_xmit(struct sk_buff *skb,
-					  struct net_device *dev)
-{
-	long e8390_base = dev->base_addr;
-	struct ei_device *ei_local = netdev_priv(dev);
-	int length, send_length, output_page;
-	unsigned long flags;
-	u8 packet[ETH_ZLEN];
-	
-	netif_stop_queue(dev);
-
-	length = skb->len;
-
-	/* Mask interrupts from the ethercard. 
-	   SMP: We have to grab the lock here otherwise the IRQ handler
-	   on another CPU can flip window and race the IRQ mask set. We end
-	   up trashing the mcast filter not disabling irqs if we don't lock */
-	   
-	spin_lock_irqsave(&ei_local->page_lock, flags);
-	outb_p(0x00, e8390_base + EN0_IMR);
-	
-	/*
-	 *	Slow phase with lock held.
-	 */
-	 
-	ei_local->irqlock = 1;
-
-	send_length = max(length, ETH_ZLEN);
-
-	/*
-	 * We have two Tx slots available for use. Find the first free
-	 * slot, and then perform some sanity checks. With two Tx bufs,
-	 * you get very close to transmitting back-to-back packets. With
-	 * only one Tx buf, the transmitter sits idle while you reload the
-	 * card, leaving a substantial gap between each transmitted packet.
-	 */
-
-	if (ei_local->tx1 == 0) 
-	{
-		output_page = ei_local->tx_start_page;
-		ei_local->tx1 = send_length;
-		if ((netif_msg_tx_queued(ei_local)) &&
-		    ei_local->tx2 > 0)
-			netdev_dbg(dev,
-				   "idle transmitter tx2=%d, lasttx=%d, txing=%d\n",
-				   ei_local->tx2, ei_local->lasttx,
-				   ei_local->txing);
-	}
-	else if (ei_local->tx2 == 0) 
-	{
-		output_page = ei_local->tx_start_page + TX_PAGES/2;
-		ei_local->tx2 = send_length;
-		if ((netif_msg_tx_queued(ei_local)) &&
-		    ei_local->tx1 > 0)
-			netdev_dbg(dev,
-				   "idle transmitter, tx1=%d, lasttx=%d, txing=%d\n",
-				   ei_local->tx1, ei_local->lasttx,
-				   ei_local->txing);
-	}
-	else
-	{	/* We should never get here. */
-		netif_dbg(ei_local, tx_err, dev,
-			  "No Tx buffers free! tx1=%d tx2=%d last=%d\n",
-			  ei_local->tx1, ei_local->tx2,
-			  ei_local->lasttx);
-		ei_local->irqlock = 0;
-		netif_stop_queue(dev);
-		outb_p(ENISR_ALL, e8390_base + EN0_IMR);
-		spin_unlock_irqrestore(&ei_local->page_lock, flags);
-		dev->stats.tx_errors++;
-		return NETDEV_TX_BUSY;
-	}
-
-	/*
-	 * Okay, now upload the packet and trigger a send if the transmitter
-	 * isn't already sending. If it is busy, the interrupt handler will
-	 * trigger the send later, upon receiving a Tx done interrupt.
-	 */
-
-	if (length == skb->len)
-		ei_block_output(dev, length, skb->data, output_page);
-	else {
-		memset(packet, 0, ETH_ZLEN);
-		skb_copy_from_linear_data(skb, packet, skb->len);
-		ei_block_output(dev, length, packet, output_page);
-	}
-	
-	if (! ei_local->txing) 
-	{
-		ei_local->txing = 1;
-		NS8390_trigger_send(dev, send_length, output_page);
-		netif_trans_update(dev);
-		if (output_page == ei_local->tx_start_page) 
-		{
-			ei_local->tx1 = -1;
-			ei_local->lasttx = -1;
-		}
-		else 
-		{
-			ei_local->tx2 = -1;
-			ei_local->lasttx = -2;
-		}
-	}
-	else ei_local->txqueue++;
-
-	if (ei_local->tx1  &&  ei_local->tx2)
-		netif_stop_queue(dev);
-	else
-		netif_start_queue(dev);
-
-	/* Turn 8390 interrupts back on. */
-	ei_local->irqlock = 0;
-	outb_p(ENISR_ALL, e8390_base + EN0_IMR);
-	
-	spin_unlock_irqrestore(&ei_local->page_lock, flags);
-
-	dev_kfree_skb (skb);
-	dev->stats.tx_bytes += send_length;
-    
-	return NETDEV_TX_OK;
-}
-
-/**
- * ax_interrupt - handle the interrupts from an 8390
- * @irq: interrupt number
- * @dev_id: a pointer to the net_device
- *
- * Handle the ether interface interrupts. We pull packets from
- * the 8390 via the card specific functions and fire them at the networking
- * stack. We also handle transmit completions and wake the transmit path if
- * necessary. We also update the counters and do other housekeeping as
- * needed.
- */
-
-static irqreturn_t ax_interrupt(int irq, void *dev_id)
-{
-	struct net_device *dev = dev_id;
-	long e8390_base;
-	int interrupts, nr_serviced = 0, i;
-	struct ei_device *ei_local;
-	int handled = 0;
-	unsigned long flags;
-
-	e8390_base = dev->base_addr;
-	ei_local = netdev_priv(dev);
-
-	/*
-	 *	Protect the irq test too.
-	 */
-	 
-	spin_lock_irqsave(&ei_local->page_lock, flags);
-
-	if (ei_local->irqlock) {
-#if 1 /* This might just be an interrupt for a PCI device sharing this line */
-		const char *msg;
-		/* The "irqlock" check is only for testing. */
-		if (ei_local->irqlock)
-			msg = "Interrupted while interrupts are masked!";
-		else
-			msg = "Reentering the interrupt handler!";
-		netdev_info(dev, "%s, isr=%#2x imr=%#2x\n",
-			    msg,
-			    inb_p(e8390_base + EN0_ISR),
-			    inb_p(e8390_base + EN0_IMR));
-#endif
-		spin_unlock_irqrestore(&ei_local->page_lock, flags);
-		return IRQ_NONE;
-	}
-
-	netif_dbg(ei_local, intr, dev, "interrupt(isr=%#2.2x)\n",
-		  inb_p(e8390_base + EN0_ISR));
-
-	outb_p(0x00, e8390_base + EN0_ISR);
-	ei_local->irqlock = 1;
-   
-	/* !!Assumption!! -- we stay in page 0.	 Don't break this. */
-	while ((interrupts = inb_p(e8390_base + EN0_ISR)) != 0 &&
-	       ++nr_serviced < MAX_SERVICE)
-	{
-		if (!netif_running(dev) || (interrupts == 0xff)) {
-			netif_warn(ei_local, intr, dev,
-				   "interrupt from stopped card\n");
-			outb_p(interrupts, e8390_base + EN0_ISR);
-			interrupts = 0;
-			break;
-		}
-		handled = 1;
-
-		/* AX88190 bug fix. */
-		outb_p(interrupts, e8390_base + EN0_ISR);
-		for (i = 0; i < 10; i++) {
-			if (!(inb(e8390_base + EN0_ISR) & interrupts))
-				break;
-			outb_p(0, e8390_base + EN0_ISR);
-			outb_p(interrupts, e8390_base + EN0_ISR);
-		}
-		if (interrupts & ENISR_OVER) 
-			ei_rx_overrun(dev);
-		else if (interrupts & (ENISR_RX+ENISR_RX_ERR)) 
-		{
-			/* Got a good (?) packet. */
-			ei_receive(dev);
-		}
-		/* Push the next to-transmit packet through. */
-		if (interrupts & ENISR_TX)
-			ei_tx_intr(dev);
-		else if (interrupts & ENISR_TX_ERR)
-			ei_tx_err(dev);
-
-		if (interrupts & ENISR_COUNTERS) 
-		{
-			dev->stats.rx_frame_errors += inb_p(e8390_base + EN0_COUNTER0);
-			dev->stats.rx_crc_errors   += inb_p(e8390_base + EN0_COUNTER1);
-			dev->stats.rx_missed_errors+= inb_p(e8390_base + EN0_COUNTER2);
-		}
-	}
-    
-	if (interrupts && (netif_msg_intr(ei_local)))
-	{
-		handled = 1;
-		if (nr_serviced >= MAX_SERVICE) 
-		{
-			/* 0xFF is valid for a card removal */
-			if (interrupts != 0xFF)
-				netdev_warn(dev,
-					    "Too much work at interrupt, status %#2.2x\n",
-					    interrupts);
-			outb_p(ENISR_ALL, e8390_base + EN0_ISR); /* Ack. most intrs. */
-		} else {
-			netdev_warn(dev, "unknown interrupt %#2x\n",
-				    interrupts);
-			outb_p(0xff, e8390_base + EN0_ISR); /* Ack. all intrs. */
-		}
-	}
-
-	/* Turn 8390 interrupts back on. */
-	ei_local->irqlock = 0;
-	outb_p(ENISR_ALL, e8390_base + EN0_IMR);
-
-	spin_unlock_irqrestore(&ei_local->page_lock, flags);
-	return IRQ_RETVAL(handled);
-}
-
-/**
- * ei_tx_err - handle transmitter error
- * @dev: network device which threw the exception
- *
- * A transmitter error has happened. Most likely excess collisions (which
- * is a fairly normal condition). If the error is one where the Tx will
- * have been aborted, we try and send another one right away, instead of
- * letting the failed packet sit and collect dust in the Tx buffer. This
- * is a much better solution as it avoids kernel based Tx timeouts, and
- * an unnecessary card reset.
- *
- * Called with lock held.
- */
-
-static void ei_tx_err(struct net_device *dev)
-{
-	long e8390_base = dev->base_addr;
-	unsigned char txsr = inb_p(e8390_base+EN0_TSR);
-	unsigned char tx_was_aborted = txsr & (ENTSR_ABT+ENTSR_FU);
-
-#ifdef VERBOSE_ERROR_DUMP
-	netdev_dbg(dev, "transmitter error (%#2x):", txsr);
-	if (txsr & ENTSR_ABT)
-		pr_cont(" excess-collisions");
-	if (txsr & ENTSR_ND)
-		pr_cont(" non-deferral");
-	if (txsr & ENTSR_CRS)
-		pr_cont(" lost-carrier");
-	if (txsr & ENTSR_FU)
-		pr_cont(" FIFO-underrun");
-	if (txsr & ENTSR_CDH)
-		pr_cont(" lost-heartbeat");
-	pr_cont("\n");
-#endif
-
-	if (tx_was_aborted)
-		ei_tx_intr(dev);
-	else 
-	{
-		dev->stats.tx_errors++;
-		if (txsr & ENTSR_CRS) dev->stats.tx_carrier_errors++;
-		if (txsr & ENTSR_CDH) dev->stats.tx_heartbeat_errors++;
-		if (txsr & ENTSR_OWC) dev->stats.tx_window_errors++;
-	}
-}
-
-/**
- * ei_tx_intr - transmit interrupt handler
- * @dev: network device for which tx intr is handled
- *
- * We have finished a transmit: check for errors and then trigger the next
- * packet to be sent. Called with lock held.
- */
-
-static void ei_tx_intr(struct net_device *dev)
-{
-	long e8390_base = dev->base_addr;
-	struct ei_device *ei_local = netdev_priv(dev);
-	int status = inb(e8390_base + EN0_TSR);
-    
-	/*
-	 * There are two Tx buffers, see which one finished, and trigger
-	 * the send of another one if it exists.
-	 */
-	ei_local->txqueue--;
-
-	if (ei_local->tx1 < 0) 
-	{
-		if (ei_local->lasttx != 1 && ei_local->lasttx != -1)
-			netdev_err(dev, "%s: bogus last_tx_buffer %d, tx1=%d\n",
-				   ei_local->name, ei_local->lasttx,
-				   ei_local->tx1);
-		ei_local->tx1 = 0;
-		if (ei_local->tx2 > 0) 
-		{
-			ei_local->txing = 1;
-			NS8390_trigger_send(dev, ei_local->tx2, ei_local->tx_start_page + 6);
-			netif_trans_update(dev);
-			ei_local->tx2 = -1;
-			ei_local->lasttx = 2;
-		} else {
-			ei_local->lasttx = 20;
-			ei_local->txing = 0;
-		}
-	}
-	else if (ei_local->tx2 < 0) 
-	{
-		if (ei_local->lasttx != 2  &&  ei_local->lasttx != -2)
-			netdev_err(dev, "%s: bogus last_tx_buffer %d, tx2=%d\n",
-				   ei_local->name, ei_local->lasttx,
-				   ei_local->tx2);
-		ei_local->tx2 = 0;
-		if (ei_local->tx1 > 0) 
-		{
-			ei_local->txing = 1;
-			NS8390_trigger_send(dev, ei_local->tx1, ei_local->tx_start_page);
-			netif_trans_update(dev);
-			ei_local->tx1 = -1;
-			ei_local->lasttx = 1;
-		} else {
-			ei_local->lasttx = 10;
-			ei_local->txing = 0;
-		}
-	}
-//	else
-//		netdev_warn(dev, "unexpected TX-done interrupt, lasttx=%d\n",
-//			    ei_local->lasttx);
-
-	/* Minimize Tx latency: update the statistics after we restart TXing. */
-	if (status & ENTSR_COL)
-		dev->stats.collisions++;
-	if (status & ENTSR_PTX)
-		dev->stats.tx_packets++;
-	else 
-	{
-		dev->stats.tx_errors++;
-		if (status & ENTSR_ABT) 
-		{
-			dev->stats.tx_aborted_errors++;
-			dev->stats.collisions += 16;
-		}
-		if (status & ENTSR_CRS) 
-			dev->stats.tx_carrier_errors++;
-		if (status & ENTSR_FU) 
-			dev->stats.tx_fifo_errors++;
-		if (status & ENTSR_CDH)
-			dev->stats.tx_heartbeat_errors++;
-		if (status & ENTSR_OWC)
-			dev->stats.tx_window_errors++;
-	}
-	netif_wake_queue(dev);
-}
-
-/**
- * ei_receive - receive some packets
- * @dev: network device with which receive will be run
- *
- * We have a good packet(s), get it/them out of the buffers. 
- * Called with lock held.
- */
-
-static void ei_receive(struct net_device *dev)
-{
-	long e8390_base = dev->base_addr;
-	struct ei_device *ei_local = netdev_priv(dev);
-	unsigned char rxing_page, this_frame, next_frame;
-	unsigned short current_offset;
-	int rx_pkt_count = 0;
-	struct e8390_pkt_hdr rx_frame;
-    
-	while (++rx_pkt_count < 10) 
-	{
-		int pkt_len, pkt_stat;
-		
-		/* Get the rx page (incoming packet pointer). */
-		rxing_page = inb_p(e8390_base + EN1_CURPAG -1);
-		
-		/* Remove one frame from the ring.  Boundary is always a page behind. */
-		this_frame = inb_p(e8390_base + EN0_BOUNDARY) + 1;
-		if (this_frame >= ei_local->stop_page)
-			this_frame = ei_local->rx_start_page;
-		
-		/* Someday we'll omit the previous, iff we never get this message.
-		   (There is at least one clone claimed to have a problem.)  
-		   
-		   Keep quiet if it looks like a card removal. One problem here
-		   is that some clones crash in roughly the same way.
-		 */
-		if ((netif_msg_rx_err(ei_local)) &&
-		    this_frame != ei_local->current_page &&
-		    (this_frame != 0x0 || rxing_page != 0xFF))
-			netdev_err(dev, "mismatched read page pointers %2x vs %2x\n",
-				   this_frame, ei_local->current_page);
-		
-		if (this_frame == rxing_page)	/* Read all the frames? */
-			break;				/* Done for now */
-		
-		current_offset = this_frame << 8;
-		ei_get_8390_hdr(dev, &rx_frame, this_frame);
-		
-		pkt_len = rx_frame.count - sizeof(struct e8390_pkt_hdr);
-		pkt_stat = rx_frame.status;
-		
-		next_frame = this_frame + 1 + ((pkt_len+4)>>8);
-		
-		if (pkt_len < 60  ||  pkt_len > 1518) 
-		{
-			netif_err(ei_local, rx_err, dev,
-				  "bogus packet size: %d, status=%#2x nxpg=%#2x\n",
-				  rx_frame.count, rx_frame.status,
-				  rx_frame.next);
-			dev->stats.rx_errors++;
-			dev->stats.rx_length_errors++;
-		}
-		 else if ((pkt_stat & 0x0F) == ENRSR_RXOK) 
-		{
-			struct sk_buff *skb;
-			
-			skb = netdev_alloc_skb(dev, pkt_len + 2);
-			if (skb == NULL) 
-			{
-				netif_err(ei_local, rx_err, dev,
-					  "Couldn't allocate a sk_buff of size %d\n",
-					  pkt_len);
-				dev->stats.rx_dropped++;
-				break;
-			}
-			else
-			{
-				skb_reserve(skb,2);	/* IP headers on 16 byte boundaries */
-				skb_put(skb, pkt_len);	/* Make room */
-				ei_block_input(dev, pkt_len, skb, current_offset + sizeof(rx_frame));
-				skb->protocol=eth_type_trans(skb,dev);
-				netif_rx(skb);
-				dev->stats.rx_packets++;
-				dev->stats.rx_bytes += pkt_len;
-				if (pkt_stat & ENRSR_PHY)
-					dev->stats.multicast++;
-			}
-		} 
-		else 
-		{
-			netif_err(ei_local, rx_err, dev,
-				  "bogus packet: status=%#2x nxpg=%#2x size=%d\n",
-				  rx_frame.status, rx_frame.next,
-				  rx_frame.count);
-			dev->stats.rx_errors++;
-			/* NB: The NIC counts CRC, frame and missed errors. */
-			if (pkt_stat & ENRSR_FO)
-				dev->stats.rx_fifo_errors++;
-		}
-		next_frame = rx_frame.next;
-		
-		/* This _should_ never happen: it's here for avoiding bad clones. */
-		if (next_frame >= ei_local->stop_page) {
-			netdev_info(dev, "next frame inconsistency, %#2x\n",
-				    next_frame);
-			next_frame = ei_local->rx_start_page;
-		}
-		ei_local->current_page = next_frame;
-		outb_p(next_frame-1, e8390_base+EN0_BOUNDARY);
-	}
-}
-
-/**
- * ei_rx_overrun - handle receiver overrun
- * @dev: network device which threw exception
- *
- * We have a receiver overrun: we have to kick the 8390 to get it started
- * again. Problem is that you have to kick it exactly as NS prescribes in
- * the updated datasheets, or "the NIC may act in an unpredictable manner."
- * This includes causing "the NIC to defer indefinitely when it is stopped
- * on a busy network."  Ugh.
- * Called with lock held. Don't call this with the interrupts off or your
- * computer will hate you - it takes 10ms or so. 
- */
-
-static void ei_rx_overrun(struct net_device *dev)
-{
-	struct axnet_dev *info = PRIV(dev);
-	long e8390_base = dev->base_addr;
-	unsigned char was_txing, must_resend = 0;
-	struct ei_device *ei_local = netdev_priv(dev);
-    
-	/*
-	 * Record whether a Tx was in progress and then issue the
-	 * stop command.
-	 */
-	was_txing = inb_p(e8390_base+E8390_CMD) & E8390_TRANS;
-	outb_p(E8390_NODMA+E8390_PAGE0+E8390_STOP, e8390_base+E8390_CMD);
-
-	netif_dbg(ei_local, rx_err, dev, "Receiver overrun\n");
-	dev->stats.rx_over_errors++;
-    
-	/* 
-	 * Wait a full Tx time (1.2ms) + some guard time, NS says 1.6ms total.
-	 * We wait at least 2ms.
-	 */
-
-	mdelay(2);
-
-	/*
-	 * Reset RBCR[01] back to zero as per magic incantation.
-	 */
-	outb_p(0x00, e8390_base+EN0_RCNTLO);
-	outb_p(0x00, e8390_base+EN0_RCNTHI);
-
-	/*
-	 * See if any Tx was interrupted or not. According to NS, this
-	 * step is vital, and skipping it will cause no end of havoc.
-	 */
-
-	if (was_txing)
-	{ 
-		unsigned char tx_completed = inb_p(e8390_base+EN0_ISR) & (ENISR_TX+ENISR_TX_ERR);
-		if (!tx_completed)
-			must_resend = 1;
-	}
-
-	/*
-	 * Have to enter loopback mode and then restart the NIC before
-	 * you are allowed to slurp packets up off the ring.
-	 */
-	outb_p(E8390_TXOFF, e8390_base + EN0_TXCR);
-	outb_p(E8390_NODMA + E8390_PAGE0 + E8390_START, e8390_base + E8390_CMD);
-
-	/*
-	 * Clear the Rx ring of all the debris, and ack the interrupt.
-	 */
-	ei_receive(dev);
-
-	/*
-	 * Leave loopback mode, and resend any packet that got stopped.
-	 */
-	outb_p(E8390_TXCONFIG | info->duplex_flag, e8390_base + EN0_TXCR); 
-	if (must_resend)
-    		outb_p(E8390_NODMA + E8390_PAGE0 + E8390_START + E8390_TRANS, e8390_base + E8390_CMD);
-}
-
-/*
- *	Collect the stats. This is called unlocked and from several contexts.
- */
- 
-static struct net_device_stats *get_stats(struct net_device *dev)
-{
-	long ioaddr = dev->base_addr;
-	struct ei_device *ei_local = netdev_priv(dev);
-	unsigned long flags;
-    
-	/* If the card is stopped, just return the present stats. */
-	if (!netif_running(dev))
-		return &dev->stats;
-
-	spin_lock_irqsave(&ei_local->page_lock,flags);
-	/* Read the counter registers, assuming we are in page 0. */
-	dev->stats.rx_frame_errors += inb_p(ioaddr + EN0_COUNTER0);
-	dev->stats.rx_crc_errors   += inb_p(ioaddr + EN0_COUNTER1);
-	dev->stats.rx_missed_errors+= inb_p(ioaddr + EN0_COUNTER2);
-	spin_unlock_irqrestore(&ei_local->page_lock, flags);
-    
-	return &dev->stats;
-}
-
-/*
- * Form the 64 bit 8390 multicast table from the linked list of addresses
- * associated with this dev structure.
- */
- 
-static inline void make_mc_bits(u8 *bits, struct net_device *dev)
-{
-	struct netdev_hw_addr *ha;
-	u32 crc;
-
-	netdev_for_each_mc_addr(ha, dev) {
-		crc = ether_crc(ETH_ALEN, ha->addr);
-		/* 
-		 * The 8390 uses the 6 most significant bits of the
-		 * CRC to index the multicast table.
-		 */
-		bits[crc>>29] |= (1<<((crc>>26)&7));
-	}
-}
-
-/**
- * do_set_multicast_list - set/clear multicast filter
- * @dev: net device for which multicast filter is adjusted
- *
- *	Set or clear the multicast filter for this adaptor.
- *	Must be called with lock held. 
- */
- 
-static void do_set_multicast_list(struct net_device *dev)
-{
-	long e8390_base = dev->base_addr;
-	int i;
-	struct ei_device *ei_local = netdev_priv(dev);
-
-	if (!(dev->flags&(IFF_PROMISC|IFF_ALLMULTI))) {
-		memset(ei_local->mcfilter, 0, 8);
-		if (!netdev_mc_empty(dev))
-			make_mc_bits(ei_local->mcfilter, dev);
-	} else {
-		/* set to accept-all */
-		memset(ei_local->mcfilter, 0xFF, 8);
-	}
-
-	outb_p(E8390_NODMA + E8390_PAGE1, e8390_base + E8390_CMD);
-	for(i = 0; i < 8; i++) 
-	{
-		outb_p(ei_local->mcfilter[i], e8390_base + EN1_MULT_SHIFT(i));
-	}
-	outb_p(E8390_NODMA + E8390_PAGE0, e8390_base + E8390_CMD);
-
-	if(dev->flags&IFF_PROMISC)
-		outb_p(E8390_RXCONFIG | 0x58, e8390_base + EN0_RXCR);
-	else if (dev->flags & IFF_ALLMULTI || !netdev_mc_empty(dev))
-		outb_p(E8390_RXCONFIG | 0x48, e8390_base + EN0_RXCR);
-	else
-		outb_p(E8390_RXCONFIG | 0x40, e8390_base + EN0_RXCR);
-
-	outb_p(E8390_NODMA+E8390_PAGE0+E8390_START, e8390_base+E8390_CMD);
-}
-
-/*
- *	Called without lock held. This is invoked from user context and may
- *	be parallel to just about everything else. Its also fairly quick and
- *	not called too often. Must protect against both bh and irq users
- */
-
-static void set_multicast_list(struct net_device *dev)
-{
-	unsigned long flags;
-
-	spin_lock_irqsave(&dev_lock(dev), flags);
-	do_set_multicast_list(dev);
-	spin_unlock_irqrestore(&dev_lock(dev), flags);
-}	
-
-/* This page of functions should be 8390 generic */
-/* Follow National Semi's recommendations for initializing the "NIC". */
-
-/**
- * AX88190_init - initialize 8390 hardware
- * @dev: network device to initialize
- * @startp: boolean.  non-zero value to initiate chip processing
- *
- *	Must be called with lock held.
- */
-
-static void AX88190_init(struct net_device *dev, int startp)
-{
-	struct axnet_dev *info = PRIV(dev);
-	long e8390_base = dev->base_addr;
-	struct ei_device *ei_local = netdev_priv(dev);
-	int i;
-	int endcfg = ei_local->word16 ? (0x48 | ENDCFG_WTS) : 0x48;
-    
-	if(sizeof(struct e8390_pkt_hdr)!=4)
-    		panic("8390.c: header struct mispacked\n");    
-	/* Follow National Semi's recommendations for initing the DP83902. */
-	outb_p(E8390_NODMA+E8390_PAGE0+E8390_STOP, e8390_base+E8390_CMD); /* 0x21 */
-	outb_p(endcfg, e8390_base + EN0_DCFG);	/* 0x48 or 0x49 */
-	/* Clear the remote byte count registers. */
-	outb_p(0x00,  e8390_base + EN0_RCNTLO);
-	outb_p(0x00,  e8390_base + EN0_RCNTHI);
-	/* Set to monitor and loopback mode -- this is vital!. */
-	outb_p(E8390_RXOFF|0x40, e8390_base + EN0_RXCR); /* 0x60 */
-	outb_p(E8390_TXOFF, e8390_base + EN0_TXCR); /* 0x02 */
-	/* Set the transmit page and receive ring. */
-	outb_p(ei_local->tx_start_page, e8390_base + EN0_TPSR);
-	ei_local->tx1 = ei_local->tx2 = 0;
-	outb_p(ei_local->rx_start_page, e8390_base + EN0_STARTPG);
-	outb_p(ei_local->stop_page-1, e8390_base + EN0_BOUNDARY);	/* 3c503 says 0x3f,NS0x26*/
-	ei_local->current_page = ei_local->rx_start_page;		/* assert boundary+1 */
-	outb_p(ei_local->stop_page, e8390_base + EN0_STOPPG);
-	/* Clear the pending interrupts and mask. */
-	outb_p(0xFF, e8390_base + EN0_ISR);
-	outb_p(0x00,  e8390_base + EN0_IMR);
-    
-	/* Copy the station address into the DS8390 registers. */
-
-	outb_p(E8390_NODMA + E8390_PAGE1 + E8390_STOP, e8390_base+E8390_CMD); /* 0x61 */
-	for(i = 0; i < 6; i++) 
-	{
-		outb_p(dev->dev_addr[i], e8390_base + EN1_PHYS_SHIFT(i));
-		if(inb_p(e8390_base + EN1_PHYS_SHIFT(i))!=dev->dev_addr[i])
-			netdev_err(dev, "Hw. address read/write mismap %d\n", i);
-	}
-
-	outb_p(ei_local->rx_start_page, e8390_base + EN1_CURPAG);
-	outb_p(E8390_NODMA+E8390_PAGE0+E8390_STOP, e8390_base+E8390_CMD);
-
-	netif_start_queue(dev);
-	ei_local->tx1 = ei_local->tx2 = 0;
-	ei_local->txing = 0;
-
-	if (info->flags & IS_AX88790)	/* select Internal PHY */
-		outb(0x10, e8390_base + AXNET_GPIO);
-
-	if (startp) 
-	{
-		outb_p(0xff,  e8390_base + EN0_ISR);
-		outb_p(ENISR_ALL,  e8390_base + EN0_IMR);
-		outb_p(E8390_NODMA+E8390_PAGE0+E8390_START, e8390_base+E8390_CMD);
-		outb_p(E8390_TXCONFIG | info->duplex_flag,
-		       e8390_base + EN0_TXCR); /* xmit on. */
-		/* 3c503 TechMan says rxconfig only after the NIC is started. */
-		outb_p(E8390_RXCONFIG | 0x40, e8390_base + EN0_RXCR); /* rx on, */
-		do_set_multicast_list(dev);	/* (re)load the mcast table */
-	}
-}
-
-/* Trigger a transmit start, assuming the length is valid. 
-   Always called with the page lock held */
-   
-static void NS8390_trigger_send(struct net_device *dev, unsigned int length,
-								int start_page)
-{
-	long e8390_base = dev->base_addr;
- 	struct ei_device *ei_local __attribute((unused)) = netdev_priv(dev);
-    
-	if (inb_p(e8390_base) & E8390_TRANS) 
-	{
-		netdev_warn(dev, "trigger_send() called with the transmitter busy\n");
-		return;
-	}
-	outb_p(length & 0xff, e8390_base + EN0_TCNTLO);
-	outb_p(length >> 8, e8390_base + EN0_TCNTHI);
-	outb_p(start_page, e8390_base + EN0_TPSR);
-	outb_p(E8390_NODMA+E8390_TRANS+E8390_START, e8390_base+E8390_CMD);
-}

-- 
2.53.0


^ permalink raw reply related	[flat|nested] 28+ messages in thread

* [PATCH net 16/18] drivers: net: 8390: pcnet: Remove this driver
  2026-04-21 19:31 [PATCH net 00/18] Remove a number of ISA and PCMCIA Ethernet drivers Andrew Lunn
                   ` (14 preceding siblings ...)
  2026-04-21 19:31 ` [PATCH net 15/18] drivers: net: 8390: AX88190: " Andrew Lunn
@ 2026-04-21 19:31 ` Andrew Lunn
  2026-04-21 19:31 ` [PATCH net 17/18] drivers: net: 8390: ultra: " Andrew Lunn
                   ` (5 subsequent siblings)
  21 siblings, 0 replies; 28+ messages in thread
From: Andrew Lunn @ 2026-04-21 19:31 UTC (permalink / raw)
  To: Andrew Lunn, David S. Miller, Eric Dumazet, Jakub Kicinski,
	Paolo Abeni, Simon Horman, Jonathan Corbet, Shuah Khan
  Cc: linux-kernel, netdev, linux-doc, Andrew Lunn

The pcnet was written by David A. Hindsh in 1999. It is an PCMCIA
device, so unlikely to be used with modern kernels.

Signed-off-by: Andrew Lunn <andrew@lunn.ch>
---
 drivers/net/ethernet/8390/Kconfig    |   11 -
 drivers/net/ethernet/8390/Makefile   |    1 -
 drivers/net/ethernet/8390/pcnet_cs.c | 1717 ----------------------------------
 3 files changed, 1729 deletions(-)

diff --git a/drivers/net/ethernet/8390/Kconfig b/drivers/net/ethernet/8390/Kconfig
index 3dea042cc2eb..3e56806471a3 100644
--- a/drivers/net/ethernet/8390/Kconfig
+++ b/drivers/net/ethernet/8390/Kconfig
@@ -132,17 +132,6 @@ config APNE
 	  To compile this driver as a module, choose M here: the module
 	  will be called apne.
 
-config PCMCIA_PCNET
-	tristate "NE2000 compatible PCMCIA support"
-	depends on PCMCIA && HAS_IOPORT
-	select CRC32
-	help
-	  Say Y here if you intend to attach an NE2000 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 pcnet_cs.  If unsure, say N.
-
 config STNIC
 	tristate "National DP83902AV  support"
 	depends on SUPERH
diff --git a/drivers/net/ethernet/8390/Makefile b/drivers/net/ethernet/8390/Makefile
index 60220484b382..b215136a603b 100644
--- a/drivers/net/ethernet/8390/Makefile
+++ b/drivers/net/ethernet/8390/Makefile
@@ -11,7 +11,6 @@ obj-$(CONFIG_HYDRA) += hydra.o
 obj-$(CONFIG_MCF8390) += mcf8390.o
 obj-$(CONFIG_NE2000) += ne.o 8390p.o
 obj-$(CONFIG_NE2K_PCI) += ne2k-pci.o 8390.o
-obj-$(CONFIG_PCMCIA_PCNET) += pcnet_cs.o 8390.o
 obj-$(CONFIG_STNIC) += stnic.o 8390.o
 obj-$(CONFIG_ULTRA) += smc-ultra.o 8390.o
 obj-$(CONFIG_WD80x3) += wd.o 8390.o
diff --git a/drivers/net/ethernet/8390/pcnet_cs.c b/drivers/net/ethernet/8390/pcnet_cs.c
deleted file mode 100644
index 19f9c5db3f3b..000000000000
--- a/drivers/net/ethernet/8390/pcnet_cs.c
+++ /dev/null
@@ -1,1717 +0,0 @@
-// SPDX-License-Identifier: GPL-1.0+
-/*======================================================================
-
-    A PCMCIA ethernet driver for NS8390-based cards
-
-    This driver supports the D-Link DE-650 and Linksys EthernetCard
-    cards, the newer D-Link and Linksys combo cards, Accton EN2212
-    cards, the RPTI EP400, and the PreMax PE-200 in non-shared-memory
-    mode, and the IBM Credit Card Adapter, the NE4100, the Thomas
-    Conrad ethernet card, and the Kingston KNE-PCM/x in shared-memory
-    mode.  It will also handle the Socket EA card in either mode.
-
-    Copyright (C) 1999 David A. Hinds -- dahinds@users.sourceforge.net
-
-    pcnet_cs.c 1.153 2003/11/09 18:53:09
-
-    The network driver code is based on Donald Becker's NE2000 code:
-
-    Written 1992,1993 by Donald Becker.
-    Copyright 1993 United States Government as represented by the
-    Director, National Security Agency.
-    Donald Becker may be reached at becker@scyld.com
-
-    Based also on Keith Moore's changes to Don Becker's code, for IBM
-    CCAE support.  Drivers merged back together, and shared-memory
-    Socket EA support added, by Ken Raeburn, September 1995.
-
-======================================================================*/
-
-#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
-
-#include <linux/kernel.h>
-#include <linux/module.h>
-#include <linux/ptrace.h>
-#include <linux/string.h>
-#include <linux/timer.h>
-#include <linux/delay.h>
-#include <linux/netdevice.h>
-#include <linux/log2.h>
-#include <linux/etherdevice.h>
-#include <linux/mii.h>
-#include "8390.h"
-
-#include <pcmcia/cistpl.h>
-#include <pcmcia/ciscode.h>
-#include <pcmcia/ds.h>
-#include <pcmcia/cisreg.h>
-
-#include <asm/io.h>
-#include <asm/byteorder.h>
-#include <linux/uaccess.h>
-
-#define PCNET_CMD	0x00
-#define PCNET_DATAPORT	0x10	/* NatSemi-defined port window offset. */
-#define PCNET_RESET	0x1f	/* Issue a read to reset, a write to clear. */
-#define PCNET_MISC	0x18	/* For IBM CCAE and Socket EA cards */
-
-#define PCNET_START_PG	0x40	/* First page of TX buffer */
-#define PCNET_STOP_PG	0x80	/* Last page +1 of RX ring */
-
-/* Socket EA cards have a larger packet buffer */
-#define SOCKET_START_PG	0x01
-#define SOCKET_STOP_PG	0xff
-
-#define PCNET_RDC_TIMEOUT (2*HZ/100)	/* Max wait in jiffies for Tx RDC */
-
-static const char *if_names[] = { "auto", "10baseT", "10base2"};
-
-/*====================================================================*/
-
-/* Module parameters */
-
-MODULE_AUTHOR("David Hinds <dahinds@users.sourceforge.net>");
-MODULE_DESCRIPTION("NE2000 compatible PCMCIA ethernet driver");
-MODULE_LICENSE("GPL");
-
-#define INT_MODULE_PARM(n, v) static int n = v; module_param(n, int, 0)
-
-INT_MODULE_PARM(if_port,	1);	/* Transceiver type */
-INT_MODULE_PARM(use_big_buf,	1);	/* use 64K packet buffer? */
-INT_MODULE_PARM(mem_speed,	0);	/* shared mem speed, in ns */
-INT_MODULE_PARM(delay_output,	0);	/* pause after xmit? */
-INT_MODULE_PARM(delay_time,	4);	/* in usec */
-INT_MODULE_PARM(use_shmem,	-1);	/* use shared memory? */
-INT_MODULE_PARM(full_duplex,	0);	/* full duplex? */
-
-/* Ugh!  Let the user hardwire the hardware address for queer cards */
-static int hw_addr[6] = { 0, /* ... */ };
-module_param_array(hw_addr, int, NULL, 0);
-
-/*====================================================================*/
-
-static void mii_phy_probe(struct net_device *dev);
-static int pcnet_config(struct pcmcia_device *link);
-static void pcnet_release(struct pcmcia_device *link);
-static int pcnet_open(struct net_device *dev);
-static int pcnet_close(struct net_device *dev);
-static int ei_ioctl(struct net_device *dev, struct ifreq *rq, int cmd);
-static irqreturn_t ei_irq_wrapper(int irq, void *dev_id);
-static void ei_watchdog(struct timer_list *t);
-static void pcnet_reset_8390(struct net_device *dev);
-static int set_config(struct net_device *dev, struct ifmap *map);
-static int setup_shmem_window(struct pcmcia_device *link, int start_pg,
-			      int stop_pg, int cm_offset);
-static int setup_dma_config(struct pcmcia_device *link, int start_pg,
-			    int stop_pg);
-
-static void pcnet_detach(struct pcmcia_device *p_dev);
-
-/*====================================================================*/
-
-struct hw_info {
-    u_int	offset;
-    u_char	a0, a1, a2;
-    u_int	flags;
-};
-
-#define DELAY_OUTPUT	0x01
-#define HAS_MISC_REG	0x02
-#define USE_BIG_BUF	0x04
-#define HAS_IBM_MISC	0x08
-#define IS_DL10019	0x10
-#define IS_DL10022	0x20
-#define HAS_MII		0x40
-#define USE_SHMEM	0x80	/* autodetected */
-
-#define AM79C9XX_HOME_PHY	0x00006B90  /* HomePNA PHY */
-#define AM79C9XX_ETH_PHY	0x00006B70  /* 10baseT PHY */
-#define MII_PHYID_REV_MASK	0xfffffff0
-#define MII_PHYID_REG1		0x02
-#define MII_PHYID_REG2		0x03
-
-static struct hw_info hw_info[] = {
-    { /* Accton EN2212 */ 0x0ff0, 0x00, 0x00, 0xe8, DELAY_OUTPUT },
-    { /* Allied Telesis LA-PCM */ 0x0ff0, 0x00, 0x00, 0xf4, 0 },
-    { /* APEX MultiCard */ 0x03f4, 0x00, 0x20, 0xe5, 0 },
-    { /* ASANTE FriendlyNet */ 0x4910, 0x00, 0x00, 0x94,
-      DELAY_OUTPUT | HAS_IBM_MISC },
-    { /* Danpex EN-6200P2 */ 0x0110, 0x00, 0x40, 0xc7, 0 },
-    { /* DataTrek NetCard */ 0x0ff0, 0x00, 0x20, 0xe8, 0 },
-    { /* Dayna CommuniCard E */ 0x0110, 0x00, 0x80, 0x19, 0 },
-    { /* D-Link DE-650 */ 0x0040, 0x00, 0x80, 0xc8, 0 },
-    { /* EP-210 Ethernet */ 0x0110, 0x00, 0x40, 0x33, 0 },
-    { /* EP4000 Ethernet */ 0x01c0, 0x00, 0x00, 0xb4, 0 },
-    { /* Epson EEN10B */ 0x0ff0, 0x00, 0x00, 0x48,
-      HAS_MISC_REG | HAS_IBM_MISC },
-    { /* ELECOM Laneed LD-CDWA */ 0xb8, 0x08, 0x00, 0x42, 0 },
-    { /* Hypertec Ethernet */ 0x01c0, 0x00, 0x40, 0x4c, 0 },
-    { /* IBM CCAE */ 0x0ff0, 0x08, 0x00, 0x5a,
-      HAS_MISC_REG | HAS_IBM_MISC },
-    { /* IBM CCAE */ 0x0ff0, 0x00, 0x04, 0xac,
-      HAS_MISC_REG | HAS_IBM_MISC },
-    { /* IBM CCAE */ 0x0ff0, 0x00, 0x06, 0x29,
-      HAS_MISC_REG | HAS_IBM_MISC },
-    { /* IBM FME */ 0x0374, 0x08, 0x00, 0x5a,
-      HAS_MISC_REG | HAS_IBM_MISC },
-    { /* IBM FME */ 0x0374, 0x00, 0x04, 0xac,
-      HAS_MISC_REG | HAS_IBM_MISC },
-    { /* Kansai KLA-PCM/T */ 0x0ff0, 0x00, 0x60, 0x87,
-      HAS_MISC_REG | HAS_IBM_MISC },
-    { /* NSC DP83903 */ 0x0374, 0x08, 0x00, 0x17,
-      HAS_MISC_REG | HAS_IBM_MISC },
-    { /* NSC DP83903 */ 0x0374, 0x00, 0xc0, 0xa8,
-      HAS_MISC_REG | HAS_IBM_MISC },
-    { /* NSC DP83903 */ 0x0374, 0x00, 0xa0, 0xb0,
-      HAS_MISC_REG | HAS_IBM_MISC },
-    { /* NSC DP83903 */ 0x0198, 0x00, 0x20, 0xe0,
-      HAS_MISC_REG | HAS_IBM_MISC },
-    { /* I-O DATA PCLA/T */ 0x0ff0, 0x00, 0xa0, 0xb0, 0 },
-    { /* Katron PE-520 */ 0x0110, 0x00, 0x40, 0xf6, 0 },
-    { /* Kingston KNE-PCM/x */ 0x0ff0, 0x00, 0xc0, 0xf0,
-      HAS_MISC_REG | HAS_IBM_MISC },
-    { /* Kingston KNE-PCM/x */ 0x0ff0, 0xe2, 0x0c, 0x0f,
-      HAS_MISC_REG | HAS_IBM_MISC },
-    { /* Kingston KNE-PC2 */ 0x0180, 0x00, 0xc0, 0xf0, 0 },
-    { /* Maxtech PCN2000 */ 0x5000, 0x00, 0x00, 0xe8, 0 },
-    { /* NDC Instant-Link */ 0x003a, 0x00, 0x80, 0xc6, 0 },
-    { /* NE2000 Compatible */ 0x0ff0, 0x00, 0xa0, 0x0c, 0 },
-    { /* Network General Sniffer */ 0x0ff0, 0x00, 0x00, 0x65,
-      HAS_MISC_REG | HAS_IBM_MISC },
-    { /* Panasonic VEL211 */ 0x0ff0, 0x00, 0x80, 0x45,
-      HAS_MISC_REG | HAS_IBM_MISC },
-    { /* PreMax PE-200 */ 0x07f0, 0x00, 0x20, 0xe0, 0 },
-    { /* RPTI EP400 */ 0x0110, 0x00, 0x40, 0x95, 0 },
-    { /* SCM Ethernet */ 0x0ff0, 0x00, 0x20, 0xcb, 0 },
-    { /* Socket EA */ 0x4000, 0x00, 0xc0, 0x1b,
-      DELAY_OUTPUT | HAS_MISC_REG | USE_BIG_BUF },
-    { /* Socket LP-E CF+ */ 0x01c0, 0x00, 0xc0, 0x1b, 0 },
-    { /* SuperSocket RE450T */ 0x0110, 0x00, 0xe0, 0x98, 0 },
-    { /* Volktek NPL-402CT */ 0x0060, 0x00, 0x40, 0x05, 0 },
-    { /* NEC PC-9801N-J12 */ 0x0ff0, 0x00, 0x00, 0x4c, 0 },
-    { /* PCMCIA Technology OEM */ 0x01c8, 0x00, 0xa0, 0x0c, 0 }
-};
-
-#define NR_INFO		ARRAY_SIZE(hw_info)
-
-static struct hw_info default_info = { 0, 0, 0, 0, 0 };
-static struct hw_info dl10019_info = { 0, 0, 0, 0, IS_DL10019|HAS_MII };
-static struct hw_info dl10022_info = { 0, 0, 0, 0, IS_DL10022|HAS_MII };
-
-struct pcnet_dev {
-	struct pcmcia_device	*p_dev;
-    u_int		flags;
-    void		__iomem *base;
-    struct timer_list	watchdog;
-    int			stale, fast_poll;
-    u_char		phy_id;
-    u_char		eth_phy, pna_phy;
-    u_short		link_status;
-    u_long		mii_reset;
-};
-
-static inline struct pcnet_dev *PRIV(struct net_device *dev)
-{
-	char *p = netdev_priv(dev);
-	return (struct pcnet_dev *)(p + sizeof(struct ei_device));
-}
-
-static const struct net_device_ops pcnet_netdev_ops = {
-	.ndo_open		= pcnet_open,
-	.ndo_stop		= pcnet_close,
-	.ndo_set_config		= set_config,
-	.ndo_start_xmit 	= ei_start_xmit,
-	.ndo_get_stats		= ei_get_stats,
-	.ndo_eth_ioctl		= ei_ioctl,
-	.ndo_set_rx_mode	= ei_set_multicast_list,
-	.ndo_tx_timeout 	= ei_tx_timeout,
-	.ndo_set_mac_address 	= eth_mac_addr,
-	.ndo_validate_addr	= eth_validate_addr,
-#ifdef CONFIG_NET_POLL_CONTROLLER
-	.ndo_poll_controller 	= ei_poll,
-#endif
-};
-
-static int pcnet_probe(struct pcmcia_device *link)
-{
-    struct pcnet_dev *info;
-    struct net_device *dev;
-
-    dev_dbg(&link->dev, "pcnet_attach()\n");
-
-    /* Create new ethernet device */
-    dev = __alloc_ei_netdev(sizeof(struct pcnet_dev));
-    if (!dev) return -ENOMEM;
-    info = PRIV(dev);
-    info->p_dev = link;
-    link->priv = dev;
-
-    link->config_flags |= CONF_ENABLE_IRQ | CONF_AUTO_SET_IO;
-
-    dev->netdev_ops = &pcnet_netdev_ops;
-
-    return pcnet_config(link);
-} /* pcnet_attach */
-
-static void pcnet_detach(struct pcmcia_device *link)
-{
-	struct net_device *dev = link->priv;
-
-	dev_dbg(&link->dev, "pcnet_detach\n");
-
-	unregister_netdev(dev);
-
-	pcnet_release(link);
-
-	free_netdev(dev);
-} /* pcnet_detach */
-
-/*======================================================================
-
-    This probes for a card's hardware address, for card types that
-    encode this information in their CIS.
-
-======================================================================*/
-
-static struct hw_info *get_hwinfo(struct pcmcia_device *link)
-{
-    struct net_device *dev = link->priv;
-    u_char __iomem *base, *virt;
-    u8 addr[ETH_ALEN];
-    int i, j;
-
-    /* Allocate a small memory window */
-    link->resource[2]->flags |= WIN_DATA_WIDTH_8|WIN_MEMORY_TYPE_AM|WIN_ENABLE;
-    link->resource[2]->start = 0; link->resource[2]->end = 0;
-    i = pcmcia_request_window(link, link->resource[2], 0);
-    if (i != 0)
-	return NULL;
-
-    virt = ioremap(link->resource[2]->start,
-	    resource_size(link->resource[2]));
-    if (unlikely(!virt)) {
-	    pcmcia_release_window(link, link->resource[2]);
-	    return NULL;
-    }
-
-    for (i = 0; i < NR_INFO; i++) {
-	pcmcia_map_mem_page(link, link->resource[2],
-		hw_info[i].offset & ~(resource_size(link->resource[2])-1));
-	base = &virt[hw_info[i].offset & (resource_size(link->resource[2])-1)];
-	if ((readb(base+0) == hw_info[i].a0) &&
-	    (readb(base+2) == hw_info[i].a1) &&
-	    (readb(base+4) == hw_info[i].a2)) {
-		for (j = 0; j < 6; j++)
-			addr[j] = readb(base + (j<<1));
-		eth_hw_addr_set(dev, addr);
-		break;
-	}
-    }
-
-    iounmap(virt);
-    j = pcmcia_release_window(link, link->resource[2]);
-    return (i < NR_INFO) ? hw_info+i : NULL;
-} /* get_hwinfo */
-
-/*======================================================================
-
-    This probes for a card's hardware address by reading the PROM.
-    It checks the address against a list of known types, then falls
-    back to a simple NE2000 clone signature check.
-
-======================================================================*/
-
-static struct hw_info *get_prom(struct pcmcia_device *link)
-{
-    struct net_device *dev = link->priv;
-    unsigned int ioaddr = dev->base_addr;
-    u8 addr[ETH_ALEN];
-    u_char prom[32];
-    int i, j;
-
-    /* This is lifted straight from drivers/net/ethernet/8390/ne.c */
-    struct {
-	u_char value, offset;
-    } program_seq[] = {
-	{E8390_NODMA+E8390_PAGE0+E8390_STOP, E8390_CMD}, /* Select page 0*/
-	{0x48,	EN0_DCFG},	/* Set byte-wide (0x48) access. */
-	{0x00,	EN0_RCNTLO},	/* Clear the count regs. */
-	{0x00,	EN0_RCNTHI},
-	{0x00,	EN0_IMR},	/* Mask completion irq. */
-	{0xFF,	EN0_ISR},
-	{E8390_RXOFF, EN0_RXCR},	/* 0x20  Set to monitor */
-	{E8390_TXOFF, EN0_TXCR},	/* 0x02  and loopback mode. */
-	{32,	EN0_RCNTLO},
-	{0x00,	EN0_RCNTHI},
-	{0x00,	EN0_RSARLO},	/* DMA starting at 0x0000. */
-	{0x00,	EN0_RSARHI},
-	{E8390_RREAD+E8390_START, E8390_CMD},
-    };
-
-    pcnet_reset_8390(dev);
-    mdelay(10);
-
-    for (i = 0; i < ARRAY_SIZE(program_seq); i++)
-	outb_p(program_seq[i].value, ioaddr + program_seq[i].offset);
-
-    for (i = 0; i < 32; i++)
-	prom[i] = inb(ioaddr + PCNET_DATAPORT);
-    for (i = 0; i < NR_INFO; i++) {
-	if ((prom[0] == hw_info[i].a0) &&
-	    (prom[2] == hw_info[i].a1) &&
-	    (prom[4] == hw_info[i].a2))
-	    break;
-    }
-    if ((i < NR_INFO) || ((prom[28] == 0x57) && (prom[30] == 0x57))) {
-	for (j = 0; j < 6; j++)
-	    addr[j] = prom[j<<1];
-	eth_hw_addr_set(dev, addr);
-	return (i < NR_INFO) ? hw_info+i : &default_info;
-    }
-    return NULL;
-} /* get_prom */
-
-/*======================================================================
-
-    For DL10019 based cards, like the Linksys EtherFast
-
-======================================================================*/
-
-static struct hw_info *get_dl10019(struct pcmcia_device *link)
-{
-    struct net_device *dev = link->priv;
-    u8 addr[ETH_ALEN];
-    int i;
-    u_char sum;
-
-    for (sum = 0, i = 0x14; i < 0x1c; i++)
-	sum += inb_p(dev->base_addr + i);
-    if (sum != 0xff)
-	return NULL;
-    for (i = 0; i < 6; i++)
-	addr[i] = inb_p(dev->base_addr + 0x14 + i);
-    eth_hw_addr_set(dev, addr);
-    i = inb(dev->base_addr + 0x1f);
-    return ((i == 0x91)||(i == 0x99)) ? &dl10022_info : &dl10019_info;
-}
-
-/*======================================================================
-
-    For Asix AX88190 based cards
-
-======================================================================*/
-
-static struct hw_info *get_ax88190(struct pcmcia_device *link)
-{
-    struct net_device *dev = link->priv;
-    unsigned int ioaddr = dev->base_addr;
-    u8 addr[ETH_ALEN];
-    int i, j;
-
-    /* Not much of a test, but the alternatives are messy */
-    if (link->config_base != 0x03c0)
-	return NULL;
-
-    outb_p(0x01, ioaddr + EN0_DCFG);	/* Set word-wide access. */
-    outb_p(0x00, ioaddr + EN0_RSARLO);	/* DMA starting at 0x0400. */
-    outb_p(0x04, ioaddr + EN0_RSARHI);
-    outb_p(E8390_RREAD+E8390_START, ioaddr + E8390_CMD);
-
-    for (i = 0; i < 6; i += 2) {
-	j = inw(ioaddr + PCNET_DATAPORT);
-	addr[i] = j & 0xff;
-	addr[i+1] = j >> 8;
-    }
-    eth_hw_addr_set(dev, addr);
-    return NULL;
-}
-
-/*======================================================================
-
-    This should be totally unnecessary... but when we can't figure
-    out the hardware address any other way, we'll let the user hard
-    wire it when the module is initialized.
-
-======================================================================*/
-
-static struct hw_info *get_hwired(struct pcmcia_device *link)
-{
-    struct net_device *dev = link->priv;
-    u8 addr[ETH_ALEN];
-    int i;
-
-    for (i = 0; i < 6; i++)
-	if (hw_addr[i] != 0) break;
-    if (i == 6)
-	return NULL;
-
-    for (i = 0; i < 6; i++)
-	addr[i] = hw_addr[i];
-    eth_hw_addr_set(dev, addr);
-
-    return &default_info;
-} /* get_hwired */
-
-static int try_io_port(struct pcmcia_device *link)
-{
-    int j, ret;
-    link->resource[0]->flags &= ~IO_DATA_PATH_WIDTH;
-    link->resource[1]->flags &= ~IO_DATA_PATH_WIDTH;
-    if (link->resource[0]->end == 32) {
-	link->resource[0]->flags |= IO_DATA_PATH_WIDTH_AUTO;
-	if (link->resource[1]->end > 0) {
-	    /* for master/slave multifunction cards */
-	    link->resource[1]->flags |= IO_DATA_PATH_WIDTH_8;
-	}
-    } else {
-	/* This should be two 16-port windows */
-	link->resource[0]->flags |= IO_DATA_PATH_WIDTH_8;
-	link->resource[1]->flags |= IO_DATA_PATH_WIDTH_16;
-    }
-    if (link->resource[0]->start == 0) {
-	for (j = 0; j < 0x400; j += 0x20) {
-	    link->resource[0]->start = j ^ 0x300;
-	    link->resource[1]->start = (j ^ 0x300) + 0x10;
-	    link->io_lines = 16;
-	    ret = pcmcia_request_io(link);
-	    if (ret == 0)
-		    return ret;
-	}
-	return ret;
-    } else {
-	return pcmcia_request_io(link);
-    }
-}
-
-static int pcnet_confcheck(struct pcmcia_device *p_dev, void *priv_data)
-{
-	int *priv = priv_data;
-	int try = (*priv & 0x1);
-
-	*priv &= (p_dev->resource[2]->end >= 0x4000) ? 0x10 : ~0x10;
-
-	if (p_dev->config_index == 0)
-		return -EINVAL;
-
-	if (p_dev->resource[0]->end + p_dev->resource[1]->end < 32)
-		return -EINVAL;
-
-	if (try)
-		p_dev->io_lines = 16;
-	return try_io_port(p_dev);
-}
-
-static struct hw_info *pcnet_try_config(struct pcmcia_device *link,
-					int *has_shmem, int try)
-{
-	struct net_device *dev = link->priv;
-	struct hw_info *local_hw_info;
-	struct pcnet_dev *info = PRIV(dev);
-	int priv = try;
-	int ret;
-
-	ret = pcmcia_loop_config(link, pcnet_confcheck, &priv);
-	if (ret) {
-		dev_warn(&link->dev, "no useable port range found\n");
-		return NULL;
-	}
-	*has_shmem = (priv & 0x10);
-
-	if (!link->irq)
-		return NULL;
-
-	if (resource_size(link->resource[1]) == 8)
-		link->config_flags |= CONF_ENABLE_SPKR;
-
-	if ((link->manf_id == MANFID_IBM) &&
-	    (link->card_id == PRODID_IBM_HOME_AND_AWAY))
-		link->config_index |= 0x10;
-
-	ret = pcmcia_enable_device(link);
-	if (ret)
-		return NULL;
-
-	dev->irq = link->irq;
-	dev->base_addr = link->resource[0]->start;
-
-	if (info->flags & HAS_MISC_REG) {
-		if ((if_port == 1) || (if_port == 2))
-			dev->if_port = if_port;
-		else
-			dev_notice(&link->dev, "invalid if_port requested\n");
-	} else
-		dev->if_port = 0;
-
-	if ((link->config_base == 0x03c0) &&
-	    (link->manf_id == 0x149) && (link->card_id == 0xc1ab)) {
-		dev_info(&link->dev,
-			"this is an AX88190 card - use axnet_cs instead.\n");
-		return NULL;
-	}
-
-	local_hw_info = get_hwinfo(link);
-	if (!local_hw_info)
-		local_hw_info = get_prom(link);
-	if (!local_hw_info)
-		local_hw_info = get_dl10019(link);
-	if (!local_hw_info)
-		local_hw_info = get_ax88190(link);
-	if (!local_hw_info)
-		local_hw_info = get_hwired(link);
-
-	return local_hw_info;
-}
-
-static int pcnet_config(struct pcmcia_device *link)
-{
-    struct net_device *dev = link->priv;
-    struct pcnet_dev *info = PRIV(dev);
-    int start_pg, stop_pg, cm_offset;
-    int has_shmem = 0;
-    struct hw_info *local_hw_info;
-
-    dev_dbg(&link->dev, "pcnet_config\n");
-
-    local_hw_info = pcnet_try_config(link, &has_shmem, 0);
-    if (!local_hw_info) {
-	    /* check whether forcing io_lines to 16 helps... */
-	    pcmcia_disable_device(link);
-	    local_hw_info = pcnet_try_config(link, &has_shmem, 1);
-	    if (local_hw_info == NULL) {
-		    dev_notice(&link->dev, "unable to read hardware net"
-			    " address for io base %#3lx\n", dev->base_addr);
-		    goto failed;
-	    }
-    }
-
-    info->flags = local_hw_info->flags;
-    /* Check for user overrides */
-    info->flags |= (delay_output) ? DELAY_OUTPUT : 0;
-    if ((link->manf_id == MANFID_SOCKET) &&
-	((link->card_id == PRODID_SOCKET_LPE) ||
-	 (link->card_id == PRODID_SOCKET_LPE_CF) ||
-	 (link->card_id == PRODID_SOCKET_EIO)))
-	info->flags &= ~USE_BIG_BUF;
-    if (!use_big_buf)
-	info->flags &= ~USE_BIG_BUF;
-
-    if (info->flags & USE_BIG_BUF) {
-	start_pg = SOCKET_START_PG;
-	stop_pg = SOCKET_STOP_PG;
-	cm_offset = 0x10000;
-    } else {
-	start_pg = PCNET_START_PG;
-	stop_pg = PCNET_STOP_PG;
-	cm_offset = 0;
-    }
-
-    /* has_shmem is ignored if use_shmem != -1 */
-    if ((use_shmem == 0) || (!has_shmem && (use_shmem == -1)) ||
-	(setup_shmem_window(link, start_pg, stop_pg, cm_offset) != 0))
-	setup_dma_config(link, start_pg, stop_pg);
-
-    ei_status.name = "NE2000";
-    ei_status.word16 = 1;
-    ei_status.reset_8390 = pcnet_reset_8390;
-
-    if (info->flags & (IS_DL10019|IS_DL10022))
-	mii_phy_probe(dev);
-
-    SET_NETDEV_DEV(dev, &link->dev);
-
-    if (register_netdev(dev) != 0) {
-	pr_notice("register_netdev() failed\n");
-	goto failed;
-    }
-
-    if (info->flags & (IS_DL10019|IS_DL10022)) {
-	u_char id = inb(dev->base_addr + 0x1a);
-	netdev_info(dev, "NE2000 (DL100%d rev %02x): ",
-		    (info->flags & IS_DL10022) ? 22 : 19, id);
-	if (info->pna_phy)
-	    pr_cont("PNA, ");
-    } else {
-	netdev_info(dev, "NE2000 Compatible: ");
-    }
-    pr_cont("io %#3lx, irq %d,", dev->base_addr, dev->irq);
-    if (info->flags & USE_SHMEM)
-	pr_cont(" mem %#5lx,", dev->mem_start);
-    if (info->flags & HAS_MISC_REG)
-	pr_cont(" %s xcvr,", if_names[dev->if_port]);
-    pr_cont(" hw_addr %pM\n", dev->dev_addr);
-    return 0;
-
-failed:
-    pcnet_release(link);
-    return -ENODEV;
-} /* pcnet_config */
-
-static void pcnet_release(struct pcmcia_device *link)
-{
-	struct pcnet_dev *info = PRIV(link->priv);
-
-	dev_dbg(&link->dev, "pcnet_release\n");
-
-	if (info->flags & USE_SHMEM)
-		iounmap(info->base);
-
-	pcmcia_disable_device(link);
-}
-
-static int pcnet_suspend(struct pcmcia_device *link)
-{
-	struct net_device *dev = link->priv;
-
-	if (link->open)
-		netif_device_detach(dev);
-
-	return 0;
-}
-
-static int pcnet_resume(struct pcmcia_device *link)
-{
-	struct net_device *dev = link->priv;
-
-	if (link->open) {
-		pcnet_reset_8390(dev);
-		NS8390_init(dev, 1);
-		netif_device_attach(dev);
-	}
-
-	return 0;
-}
-
-
-/*======================================================================
-
-    MII interface support for DL10019 and DL10022 based cards
-
-    On the DL10019, the MII IO direction bit is 0x10; on the DL10022
-    it is 0x20.  Setting both bits seems to work on both card types.
-
-======================================================================*/
-
-#define DLINK_GPIO		0x1c
-#define DLINK_DIAG		0x1d
-#define DLINK_EEPROM		0x1e
-
-#define MDIO_SHIFT_CLK		0x80
-#define MDIO_DATA_OUT		0x40
-#define MDIO_DIR_WRITE		0x30
-#define MDIO_DATA_WRITE0	(MDIO_DIR_WRITE)
-#define MDIO_DATA_WRITE1	(MDIO_DIR_WRITE | MDIO_DATA_OUT)
-#define MDIO_DATA_READ		0x10
-#define MDIO_MASK		0x0f
-
-static void mdio_sync(unsigned int addr)
-{
-    int bits, mask = inb(addr) & MDIO_MASK;
-    for (bits = 0; bits < 32; bits++) {
-	outb(mask | MDIO_DATA_WRITE1, addr);
-	outb(mask | MDIO_DATA_WRITE1 | MDIO_SHIFT_CLK, addr);
-    }
-}
-
-static int mdio_read(unsigned int addr, int phy_id, int loc)
-{
-    u_int cmd = (0x06<<10)|(phy_id<<5)|loc;
-    int i, retval = 0, mask = inb(addr) & MDIO_MASK;
-
-    mdio_sync(addr);
-    for (i = 13; i >= 0; i--) {
-	int dat = (cmd&(1<<i)) ? MDIO_DATA_WRITE1 : MDIO_DATA_WRITE0;
-	outb(mask | dat, addr);
-	outb(mask | dat | MDIO_SHIFT_CLK, addr);
-    }
-    for (i = 19; i > 0; i--) {
-	outb(mask, addr);
-	retval = (retval << 1) | ((inb(addr) & MDIO_DATA_READ) != 0);
-	outb(mask | MDIO_SHIFT_CLK, addr);
-    }
-    return (retval>>1) & 0xffff;
-}
-
-static void mdio_write(unsigned int addr, int phy_id, int loc, int value)
-{
-    u_int cmd = (0x05<<28)|(phy_id<<23)|(loc<<18)|(1<<17)|value;
-    int i, mask = inb(addr) & MDIO_MASK;
-
-    mdio_sync(addr);
-    for (i = 31; i >= 0; i--) {
-	int dat = (cmd&(1<<i)) ? MDIO_DATA_WRITE1 : MDIO_DATA_WRITE0;
-	outb(mask | dat, addr);
-	outb(mask | dat | MDIO_SHIFT_CLK, addr);
-    }
-    for (i = 1; i >= 0; i--) {
-	outb(mask, addr);
-	outb(mask | MDIO_SHIFT_CLK, addr);
-    }
-}
-
-/*======================================================================
-
-    EEPROM access routines for DL10019 and DL10022 based cards
-
-======================================================================*/
-
-#define EE_EEP		0x40
-#define EE_ASIC		0x10
-#define EE_CS		0x08
-#define EE_CK		0x04
-#define EE_DO		0x02
-#define EE_DI		0x01
-#define EE_ADOT		0x01	/* DataOut for ASIC */
-#define EE_READ_CMD	0x06
-
-#define DL19FDUPLX	0x0400	/* DL10019 Full duplex mode */
-
-static int read_eeprom(unsigned int ioaddr, int location)
-{
-    int i, retval = 0;
-    unsigned int ee_addr = ioaddr + DLINK_EEPROM;
-    int read_cmd = location | (EE_READ_CMD << 8);
-
-    outb(0, ee_addr);
-    outb(EE_EEP|EE_CS, ee_addr);
-
-    /* Shift the read command bits out. */
-    for (i = 10; i >= 0; i--) {
-	short dataval = (read_cmd & (1 << i)) ? EE_DO : 0;
-	outb_p(EE_EEP|EE_CS|dataval, ee_addr);
-	outb_p(EE_EEP|EE_CS|dataval|EE_CK, ee_addr);
-    }
-    outb(EE_EEP|EE_CS, ee_addr);
-
-    for (i = 16; i > 0; i--) {
-	outb_p(EE_EEP|EE_CS | EE_CK, ee_addr);
-	retval = (retval << 1) | ((inb(ee_addr) & EE_DI) ? 1 : 0);
-	outb_p(EE_EEP|EE_CS, ee_addr);
-    }
-
-    /* Terminate the EEPROM access. */
-    outb(0, ee_addr);
-    return retval;
-}
-
-/*
-    The internal ASIC registers can be changed by EEPROM READ access
-    with EE_ASIC bit set.
-    In ASIC mode, EE_ADOT is used to output the data to the ASIC.
-*/
-
-static void write_asic(unsigned int ioaddr, int location, short asic_data)
-{
-	int i;
-	unsigned int ee_addr = ioaddr + DLINK_EEPROM;
-	short dataval;
-	int read_cmd = location | (EE_READ_CMD << 8);
-
-	asic_data |= read_eeprom(ioaddr, location);
-
-	outb(0, ee_addr);
-	outb(EE_ASIC|EE_CS|EE_DI, ee_addr);
-
-	read_cmd = read_cmd >> 1;
-
-	/* Shift the read command bits out. */
-	for (i = 9; i >= 0; i--) {
-		dataval = (read_cmd & (1 << i)) ? EE_DO : 0;
-		outb_p(EE_ASIC|EE_CS|EE_DI|dataval, ee_addr);
-		outb_p(EE_ASIC|EE_CS|EE_DI|dataval|EE_CK, ee_addr);
-		outb_p(EE_ASIC|EE_CS|EE_DI|dataval, ee_addr);
-	}
-	// sync
-	outb(EE_ASIC|EE_CS, ee_addr);
-	outb(EE_ASIC|EE_CS|EE_CK, ee_addr);
-	outb(EE_ASIC|EE_CS, ee_addr);
-
-	for (i = 15; i >= 0; i--) {
-		dataval = (asic_data & (1 << i)) ? EE_ADOT : 0;
-		outb_p(EE_ASIC|EE_CS|dataval, ee_addr);
-		outb_p(EE_ASIC|EE_CS|dataval|EE_CK, ee_addr);
-		outb_p(EE_ASIC|EE_CS|dataval, ee_addr);
-	}
-
-	/* Terminate the ASIC access. */
-	outb(EE_ASIC|EE_DI, ee_addr);
-	outb(EE_ASIC|EE_DI| EE_CK, ee_addr);
-	outb(EE_ASIC|EE_DI, ee_addr);
-
-	outb(0, ee_addr);
-}
-
-/*====================================================================*/
-
-static void set_misc_reg(struct net_device *dev)
-{
-    unsigned int nic_base = dev->base_addr;
-    struct pcnet_dev *info = PRIV(dev);
-    u_char tmp;
-
-    if (info->flags & HAS_MISC_REG) {
-	tmp = inb_p(nic_base + PCNET_MISC) & ~3;
-	if (dev->if_port == 2)
-	    tmp |= 1;
-	if (info->flags & USE_BIG_BUF)
-	    tmp |= 2;
-	if (info->flags & HAS_IBM_MISC)
-	    tmp |= 8;
-	outb_p(tmp, nic_base + PCNET_MISC);
-    }
-    if (info->flags & IS_DL10022) {
-	if (info->flags & HAS_MII) {
-	    /* Advertise 100F, 100H, 10F, 10H */
-	    mdio_write(nic_base + DLINK_GPIO, info->eth_phy, 4, 0x01e1);
-	    /* Restart MII autonegotiation */
-	    mdio_write(nic_base + DLINK_GPIO, info->eth_phy, 0, 0x0000);
-	    mdio_write(nic_base + DLINK_GPIO, info->eth_phy, 0, 0x1200);
-	    info->mii_reset = jiffies;
-	} else {
-	    outb(full_duplex ? 4 : 0, nic_base + DLINK_DIAG);
-	}
-    } else if (info->flags & IS_DL10019) {
-	/* Advertise 100F, 100H, 10F, 10H */
-	mdio_write(nic_base + DLINK_GPIO, info->eth_phy, 4, 0x01e1);
-	/* Restart MII autonegotiation */
-	mdio_write(nic_base + DLINK_GPIO, info->eth_phy, 0, 0x0000);
-	mdio_write(nic_base + DLINK_GPIO, info->eth_phy, 0, 0x1200);
-    }
-}
-
-/*====================================================================*/
-
-static void mii_phy_probe(struct net_device *dev)
-{
-    struct pcnet_dev *info = PRIV(dev);
-    unsigned int mii_addr = dev->base_addr + DLINK_GPIO;
-    int i;
-    u_int tmp, phyid;
-
-    for (i = 31; i >= 0; i--) {
-	tmp = mdio_read(mii_addr, i, 1);
-	if ((tmp == 0) || (tmp == 0xffff))
-	    continue;
-	tmp = mdio_read(mii_addr, i, MII_PHYID_REG1);
-	phyid = tmp << 16;
-	phyid |= mdio_read(mii_addr, i, MII_PHYID_REG2);
-	phyid &= MII_PHYID_REV_MASK;
-	netdev_dbg(dev, "MII at %d is 0x%08x\n", i, phyid);
-	if (phyid == AM79C9XX_HOME_PHY) {
-	    info->pna_phy = i;
-	} else if (phyid != AM79C9XX_ETH_PHY) {
-	    info->eth_phy = i;
-	}
-    }
-}
-
-static int pcnet_open(struct net_device *dev)
-{
-    int ret;
-    struct pcnet_dev *info = PRIV(dev);
-    struct pcmcia_device *link = info->p_dev;
-    unsigned int nic_base = dev->base_addr;
-
-    dev_dbg(&link->dev, "pcnet_open('%s')\n", dev->name);
-
-    if (!pcmcia_dev_present(link))
-	return -ENODEV;
-
-    set_misc_reg(dev);
-
-    outb_p(0xFF, nic_base + EN0_ISR); /* Clear bogus intr. */
-    ret = request_irq(dev->irq, ei_irq_wrapper, IRQF_SHARED, dev->name, dev);
-    if (ret)
-	    return ret;
-
-    link->open++;
-
-    info->phy_id = info->eth_phy;
-    info->link_status = 0x00;
-    timer_setup(&info->watchdog, ei_watchdog, 0);
-    mod_timer(&info->watchdog, jiffies + HZ);
-
-    return ei_open(dev);
-} /* pcnet_open */
-
-/*====================================================================*/
-
-static int pcnet_close(struct net_device *dev)
-{
-    struct pcnet_dev *info = PRIV(dev);
-    struct pcmcia_device *link = info->p_dev;
-
-    dev_dbg(&link->dev, "pcnet_close('%s')\n", dev->name);
-
-    ei_close(dev);
-    free_irq(dev->irq, dev);
-
-    link->open--;
-    netif_stop_queue(dev);
-    timer_delete_sync(&info->watchdog);
-
-    return 0;
-} /* pcnet_close */
-
-/*======================================================================
-
-    Hard reset the card.  This used to pause for the same period that
-    a 8390 reset command required, but that shouldn't be necessary.
-
-======================================================================*/
-
-static void pcnet_reset_8390(struct net_device *dev)
-{
-    unsigned int nic_base = dev->base_addr;
-    int i;
-
-    ei_status.txing = ei_status.dmaing = 0;
-
-    outb_p(E8390_NODMA+E8390_PAGE0+E8390_STOP, nic_base + E8390_CMD);
-
-    outb(inb(nic_base + PCNET_RESET), nic_base + PCNET_RESET);
-
-    for (i = 0; i < 100; i++) {
-	if ((inb_p(nic_base+EN0_ISR) & ENISR_RESET) != 0)
-	    break;
-	udelay(100);
-    }
-    outb_p(ENISR_RESET, nic_base + EN0_ISR); /* Ack intr. */
-
-    if (i == 100)
-	netdev_err(dev, "pcnet_reset_8390() did not complete.\n");
-
-    set_misc_reg(dev);
-
-} /* pcnet_reset_8390 */
-
-/*====================================================================*/
-
-static int set_config(struct net_device *dev, struct ifmap *map)
-{
-    struct pcnet_dev *info = PRIV(dev);
-    if ((map->port != (u_char)(-1)) && (map->port != dev->if_port)) {
-	if (!(info->flags & HAS_MISC_REG))
-	    return -EOPNOTSUPP;
-	else if ((map->port < 1) || (map->port > 2))
-	    return -EINVAL;
-	WRITE_ONCE(dev->if_port, map->port);
-	netdev_info(dev, "switched to %s port\n", if_names[dev->if_port]);
-	NS8390_init(dev, 1);
-    }
-    return 0;
-}
-
-/*====================================================================*/
-
-static irqreturn_t ei_irq_wrapper(int irq, void *dev_id)
-{
-    struct net_device *dev = dev_id;
-    struct pcnet_dev *info;
-    irqreturn_t ret = ei_interrupt(irq, dev_id);
-
-    if (ret == IRQ_HANDLED) {
-	    info = PRIV(dev);
-	    info->stale = 0;
-    }
-    return ret;
-}
-
-static void ei_watchdog(struct timer_list *t)
-{
-    struct pcnet_dev *info = timer_container_of(info, t, watchdog);
-    struct net_device *dev = info->p_dev->priv;
-    unsigned int nic_base = dev->base_addr;
-    unsigned int mii_addr = nic_base + DLINK_GPIO;
-    u_short link;
-
-    if (!netif_device_present(dev)) goto reschedule;
-
-    /* Check for pending interrupt with expired latency timer: with
-       this, we can limp along even if the interrupt is blocked */
-    if (info->stale++ && (inb_p(nic_base + EN0_ISR) & ENISR_ALL)) {
-	if (!info->fast_poll)
-	    netdev_info(dev, "interrupt(s) dropped!\n");
-	ei_irq_wrapper(dev->irq, dev);
-	info->fast_poll = HZ;
-    }
-    if (info->fast_poll) {
-	info->fast_poll--;
-	info->watchdog.expires = jiffies + 1;
-	add_timer(&info->watchdog);
-	return;
-    }
-
-    if (!(info->flags & HAS_MII))
-	goto reschedule;
-
-    mdio_read(mii_addr, info->phy_id, 1);
-    link = mdio_read(mii_addr, info->phy_id, 1);
-    if (!link || (link == 0xffff)) {
-	if (info->eth_phy) {
-	    info->phy_id = info->eth_phy = 0;
-	} else {
-	    netdev_info(dev, "MII is missing!\n");
-	    info->flags &= ~HAS_MII;
-	}
-	goto reschedule;
-    }
-
-    link &= 0x0004;
-    if (link != info->link_status) {
-	u_short p = mdio_read(mii_addr, info->phy_id, 5);
-	netdev_info(dev, "%s link beat\n", link ? "found" : "lost");
-	if (link && (info->flags & IS_DL10022)) {
-	    /* Disable collision detection on full duplex links */
-	    outb((p & 0x0140) ? 4 : 0, nic_base + DLINK_DIAG);
-	} else if (link && (info->flags & IS_DL10019)) {
-	    /* Disable collision detection on full duplex links */
-	    write_asic(dev->base_addr, 4, (p & 0x140) ? DL19FDUPLX : 0);
-	}
-	if (link) {
-	    if (info->phy_id == info->eth_phy) {
-		if (p)
-		    netdev_info(dev, "autonegotiation complete: "
-				"%sbaseT-%cD selected\n",
-				((p & 0x0180) ? "100" : "10"),
-				((p & 0x0140) ? 'F' : 'H'));
-		else
-		    netdev_info(dev, "link partner did not autonegotiate\n");
-	    }
-	    NS8390_init(dev, 1);
-	}
-	info->link_status = link;
-    }
-    if (info->pna_phy && time_after(jiffies, info->mii_reset + 6*HZ)) {
-	link = mdio_read(mii_addr, info->eth_phy, 1) & 0x0004;
-	if (((info->phy_id == info->pna_phy) && link) ||
-	    ((info->phy_id != info->pna_phy) && !link)) {
-	    /* isolate this MII and try flipping to the other one */
-	    mdio_write(mii_addr, info->phy_id, 0, 0x0400);
-	    info->phy_id ^= info->pna_phy ^ info->eth_phy;
-	    netdev_info(dev, "switched to %s transceiver\n",
-			(info->phy_id == info->eth_phy) ? "ethernet" : "PNA");
-	    mdio_write(mii_addr, info->phy_id, 0,
-		       (info->phy_id == info->eth_phy) ? 0x1000 : 0);
-	    info->link_status = 0;
-	    info->mii_reset = jiffies;
-	}
-    }
-
-reschedule:
-    info->watchdog.expires = jiffies + HZ;
-    add_timer(&info->watchdog);
-}
-
-/*====================================================================*/
-
-
-static int ei_ioctl(struct net_device *dev, struct ifreq *rq, int cmd)
-{
-    struct pcnet_dev *info = PRIV(dev);
-    struct mii_ioctl_data *data = if_mii(rq);
-    unsigned int mii_addr = dev->base_addr + DLINK_GPIO;
-
-    if (!(info->flags & (IS_DL10019|IS_DL10022)))
-	return -EINVAL;
-
-    switch (cmd) {
-    case SIOCGMIIPHY:
-	data->phy_id = info->phy_id;
-	fallthrough;
-    case SIOCGMIIREG:		/* Read MII PHY register. */
-	data->val_out = mdio_read(mii_addr, data->phy_id, data->reg_num & 0x1f);
-	return 0;
-    case SIOCSMIIREG:		/* Write MII PHY register. */
-	mdio_write(mii_addr, data->phy_id, data->reg_num & 0x1f, data->val_in);
-	return 0;
-    }
-    return -EOPNOTSUPP;
-}
-
-/*====================================================================*/
-
-static void dma_get_8390_hdr(struct net_device *dev,
-			     struct e8390_pkt_hdr *hdr,
-			     int ring_page)
-{
-    unsigned int nic_base = dev->base_addr;
-
-    if (ei_status.dmaing) {
-	netdev_err(dev, "DMAing conflict in dma_block_input."
-		   "[DMAstat:%1x][irqlock:%1x]\n",
-		   ei_status.dmaing, ei_status.irqlock);
-	return;
-    }
-
-    ei_status.dmaing |= 0x01;
-    outb_p(E8390_NODMA+E8390_PAGE0+E8390_START, nic_base + PCNET_CMD);
-    outb_p(sizeof(struct e8390_pkt_hdr), nic_base + EN0_RCNTLO);
-    outb_p(0, nic_base + EN0_RCNTHI);
-    outb_p(0, nic_base + EN0_RSARLO);		/* On page boundary */
-    outb_p(ring_page, nic_base + EN0_RSARHI);
-    outb_p(E8390_RREAD+E8390_START, nic_base + PCNET_CMD);
-
-    insw(nic_base + PCNET_DATAPORT, hdr,
-	    sizeof(struct e8390_pkt_hdr)>>1);
-    /* Fix for big endian systems */
-    hdr->count = le16_to_cpu(hdr->count);
-
-    outb_p(ENISR_RDC, nic_base + EN0_ISR);	/* Ack intr. */
-    ei_status.dmaing &= ~0x01;
-}
-
-/*====================================================================*/
-
-static void dma_block_input(struct net_device *dev, int count,
-			    struct sk_buff *skb, int ring_offset)
-{
-    unsigned int nic_base = dev->base_addr;
-    int xfer_count = count;
-    char *buf = skb->data;
-    struct ei_device *ei_local = netdev_priv(dev);
-
-    if ((netif_msg_rx_status(ei_local)) && (count != 4))
-	netdev_dbg(dev, "[bi=%d]\n", count+4);
-    if (ei_status.dmaing) {
-	netdev_err(dev, "DMAing conflict in dma_block_input."
-		   "[DMAstat:%1x][irqlock:%1x]\n",
-		   ei_status.dmaing, ei_status.irqlock);
-	return;
-    }
-    ei_status.dmaing |= 0x01;
-    outb_p(E8390_NODMA+E8390_PAGE0+E8390_START, nic_base + PCNET_CMD);
-    outb_p(count & 0xff, nic_base + EN0_RCNTLO);
-    outb_p(count >> 8, nic_base + EN0_RCNTHI);
-    outb_p(ring_offset & 0xff, nic_base + EN0_RSARLO);
-    outb_p(ring_offset >> 8, nic_base + EN0_RSARHI);
-    outb_p(E8390_RREAD+E8390_START, nic_base + PCNET_CMD);
-
-    insw(nic_base + PCNET_DATAPORT,buf,count>>1);
-    if (count & 0x01) {
-	buf[count-1] = inb(nic_base + PCNET_DATAPORT);
-	xfer_count++;
-    }
-
-    /* This was for the ALPHA version only, but enough people have been
-       encountering problems that it is still here. */
-#ifdef PCMCIA_DEBUG
-      /* DMA termination address check... */
-    if (netif_msg_rx_status(ei_local)) {
-	int addr, tries = 20;
-	do {
-	    /* DON'T check for 'inb_p(EN0_ISR) & ENISR_RDC' here
-	       -- it's broken for Rx on some cards! */
-	    int high = inb_p(nic_base + EN0_RSARHI);
-	    int low = inb_p(nic_base + EN0_RSARLO);
-	    addr = (high << 8) + low;
-	    if (((ring_offset + xfer_count) & 0xff) == (addr & 0xff))
-		break;
-	} while (--tries > 0);
-	if (tries <= 0)
-	    netdev_notice(dev, "RX transfer address mismatch,"
-			  "%#4.4x (expected) vs. %#4.4x (actual).\n",
-			  ring_offset + xfer_count, addr);
-    }
-#endif
-    outb_p(ENISR_RDC, nic_base + EN0_ISR);	/* Ack intr. */
-    ei_status.dmaing &= ~0x01;
-} /* dma_block_input */
-
-/*====================================================================*/
-
-static void dma_block_output(struct net_device *dev, int count,
-			     const u_char *buf, const int start_page)
-{
-    unsigned int nic_base = dev->base_addr;
-    struct pcnet_dev *info = PRIV(dev);
-#ifdef PCMCIA_DEBUG
-    int retries = 0;
-    struct ei_device *ei_local = netdev_priv(dev);
-#endif
-    u_long dma_start;
-
-#ifdef PCMCIA_DEBUG
-    netif_dbg(ei_local, tx_queued, dev, "[bo=%d]\n", count);
-#endif
-
-    /* Round the count up for word writes.  Do we need to do this?
-       What effect will an odd byte count have on the 8390?
-       I should check someday. */
-    if (count & 0x01)
-	count++;
-    if (ei_status.dmaing) {
-	netdev_err(dev, "DMAing conflict in dma_block_output."
-		   "[DMAstat:%1x][irqlock:%1x]\n",
-		   ei_status.dmaing, ei_status.irqlock);
-	return;
-    }
-    ei_status.dmaing |= 0x01;
-    /* We should already be in page 0, but to be safe... */
-    outb_p(E8390_PAGE0+E8390_START+E8390_NODMA, nic_base+PCNET_CMD);
-
-#ifdef PCMCIA_DEBUG
-  retry:
-#endif
-
-    outb_p(ENISR_RDC, nic_base + EN0_ISR);
-
-    /* Now the normal output. */
-    outb_p(count & 0xff, nic_base + EN0_RCNTLO);
-    outb_p(count >> 8,   nic_base + EN0_RCNTHI);
-    outb_p(0x00, nic_base + EN0_RSARLO);
-    outb_p(start_page, nic_base + EN0_RSARHI);
-
-    outb_p(E8390_RWRITE+E8390_START, nic_base + PCNET_CMD);
-    outsw(nic_base + PCNET_DATAPORT, buf, count>>1);
-
-    dma_start = jiffies;
-
-#ifdef PCMCIA_DEBUG
-    /* This was for the ALPHA version only, but enough people have been
-       encountering problems that it is still here. */
-    /* DMA termination address check... */
-    if (netif_msg_tx_queued(ei_local)) {
-	int addr, tries = 20;
-	do {
-	    int high = inb_p(nic_base + EN0_RSARHI);
-	    int low = inb_p(nic_base + EN0_RSARLO);
-	    addr = (high << 8) + low;
-	    if ((start_page << 8) + count == addr)
-		break;
-	} while (--tries > 0);
-	if (tries <= 0) {
-	    netdev_notice(dev, "Tx packet transfer address mismatch,"
-			  "%#4.4x (expected) vs. %#4.4x (actual).\n",
-			  (start_page << 8) + count, addr);
-	    if (retries++ == 0)
-		goto retry;
-	}
-    }
-#endif
-
-    while ((inb_p(nic_base + EN0_ISR) & ENISR_RDC) == 0)
-	if (time_after(jiffies, dma_start + PCNET_RDC_TIMEOUT)) {
-		netdev_warn(dev, "timeout waiting for Tx RDC.\n");
-		pcnet_reset_8390(dev);
-		NS8390_init(dev, 1);
-		break;
-	}
-
-    outb_p(ENISR_RDC, nic_base + EN0_ISR);	/* Ack intr. */
-    if (info->flags & DELAY_OUTPUT)
-	udelay((long)delay_time);
-    ei_status.dmaing &= ~0x01;
-}
-
-/*====================================================================*/
-
-static int setup_dma_config(struct pcmcia_device *link, int start_pg,
-			    int stop_pg)
-{
-    struct net_device *dev = link->priv;
-
-    ei_status.tx_start_page = start_pg;
-    ei_status.rx_start_page = start_pg + TX_PAGES;
-    ei_status.stop_page = stop_pg;
-
-    /* set up block i/o functions */
-    ei_status.get_8390_hdr = dma_get_8390_hdr;
-    ei_status.block_input = dma_block_input;
-    ei_status.block_output = dma_block_output;
-
-    return 0;
-}
-
-/*====================================================================*/
-
-static void copyin(void *dest, void __iomem *src, int c)
-{
-    u_short *d = dest;
-    u_short __iomem *s = src;
-    int odd;
-
-    if (c <= 0)
-	return;
-    odd = (c & 1); c >>= 1;
-
-    if (c) {
-	do { *d++ = __raw_readw(s++); } while (--c);
-    }
-    /* get last byte by fetching a word and masking */
-    if (odd)
-	*((u_char *)d) = readw(s) & 0xff;
-}
-
-static void copyout(void __iomem *dest, const void *src, int c)
-{
-    u_short __iomem *d = dest;
-    const u_short *s = src;
-    int odd;
-
-    if (c <= 0)
-	return;
-    odd = (c & 1); c >>= 1;
-
-    if (c) {
-	do { __raw_writew(*s++, d++); } while (--c);
-    }
-    /* copy last byte doing a read-modify-write */
-    if (odd)
-	writew((readw(d) & 0xff00) | *(u_char *)s, d);
-}
-
-/*====================================================================*/
-
-static void shmem_get_8390_hdr(struct net_device *dev,
-			       struct e8390_pkt_hdr *hdr,
-			       int ring_page)
-{
-    void __iomem *xfer_start = ei_status.mem + (TX_PAGES<<8)
-				+ (ring_page << 8)
-				- (ei_status.rx_start_page << 8);
-
-    copyin(hdr, xfer_start, sizeof(struct e8390_pkt_hdr));
-    /* Fix for big endian systems */
-    hdr->count = le16_to_cpu(hdr->count);
-}
-
-/*====================================================================*/
-
-static void shmem_block_input(struct net_device *dev, int count,
-			      struct sk_buff *skb, int ring_offset)
-{
-    void __iomem *base = ei_status.mem;
-    unsigned long offset = (TX_PAGES<<8) + ring_offset
-				- (ei_status.rx_start_page << 8);
-    char *buf = skb->data;
-
-    if (offset + count > ei_status.priv) {
-	/* We must wrap the input move. */
-	int semi_count = ei_status.priv - offset;
-	copyin(buf, base + offset, semi_count);
-	buf += semi_count;
-	offset = TX_PAGES<<8;
-	count -= semi_count;
-    }
-    copyin(buf, base + offset, count);
-}
-
-/*====================================================================*/
-
-static void shmem_block_output(struct net_device *dev, int count,
-			       const u_char *buf, const int start_page)
-{
-    void __iomem *shmem = ei_status.mem + (start_page << 8);
-    shmem -= ei_status.tx_start_page << 8;
-    copyout(shmem, buf, count);
-}
-
-/*====================================================================*/
-
-static int setup_shmem_window(struct pcmcia_device *link, int start_pg,
-			      int stop_pg, int cm_offset)
-{
-    struct net_device *dev = link->priv;
-    struct pcnet_dev *info = PRIV(dev);
-    int i, window_size, offset, ret;
-
-    window_size = (stop_pg - start_pg) << 8;
-    if (window_size > 32 * 1024)
-	window_size = 32 * 1024;
-
-    /* Make sure it's a power of two.  */
-    window_size = roundup_pow_of_two(window_size);
-
-    /* Allocate a memory window */
-    link->resource[3]->flags |= WIN_DATA_WIDTH_16|WIN_MEMORY_TYPE_CM|WIN_ENABLE;
-    link->resource[3]->flags |= WIN_USE_WAIT;
-    link->resource[3]->start = 0; link->resource[3]->end = window_size;
-    ret = pcmcia_request_window(link, link->resource[3], mem_speed);
-    if (ret)
-	    goto failed;
-
-    offset = (start_pg << 8) + cm_offset;
-    offset -= offset % window_size;
-    ret = pcmcia_map_mem_page(link, link->resource[3], offset);
-    if (ret)
-	    goto failed;
-
-    /* Try scribbling on the buffer */
-    info->base = ioremap(link->resource[3]->start,
-			resource_size(link->resource[3]));
-    if (unlikely(!info->base)) {
-	    ret = -ENOMEM;
-	    goto failed;
-    }
-
-    for (i = 0; i < (TX_PAGES<<8); i += 2)
-	__raw_writew((i>>1), info->base+offset+i);
-    udelay(100);
-    for (i = 0; i < (TX_PAGES<<8); i += 2)
-	if (__raw_readw(info->base+offset+i) != (i>>1)) break;
-    pcnet_reset_8390(dev);
-    if (i != (TX_PAGES<<8)) {
-	iounmap(info->base);
-	pcmcia_release_window(link, link->resource[3]);
-	info->base = NULL;
-	goto failed;
-    }
-
-    ei_status.mem = info->base + offset;
-    ei_status.priv = resource_size(link->resource[3]);
-    dev->mem_start = (u_long)ei_status.mem;
-    dev->mem_end = dev->mem_start + resource_size(link->resource[3]);
-
-    ei_status.tx_start_page = start_pg;
-    ei_status.rx_start_page = start_pg + TX_PAGES;
-    ei_status.stop_page = start_pg + (
-	    (resource_size(link->resource[3]) - offset) >> 8);
-
-    /* set up block i/o functions */
-    ei_status.get_8390_hdr = shmem_get_8390_hdr;
-    ei_status.block_input = shmem_block_input;
-    ei_status.block_output = shmem_block_output;
-
-    info->flags |= USE_SHMEM;
-    return 0;
-
-failed:
-    return 1;
-}
-
-/*====================================================================*/
-
-static const struct pcmcia_device_id pcnet_ids[] = {
-	PCMCIA_PFC_DEVICE_MANF_CARD(0, 0x0057, 0x0021),
-	PCMCIA_PFC_DEVICE_MANF_CARD(0, 0x0104, 0x000a),
-	PCMCIA_PFC_DEVICE_MANF_CARD(0, 0x0105, 0xea15),
-	PCMCIA_PFC_DEVICE_MANF_CARD(0, 0x0143, 0x3341),
-	PCMCIA_PFC_DEVICE_MANF_CARD(0, 0x0143, 0xc0ab),
-	PCMCIA_PFC_DEVICE_MANF_CARD(0, 0x021b, 0x0101),
-	PCMCIA_PFC_DEVICE_MANF_CARD(0, 0x08a1, 0xc0ab),
-	PCMCIA_PFC_DEVICE_PROD_ID12(0, "AnyCom", "Fast Ethernet + 56K COMBO", 0x578ba6e7, 0xb0ac62c4),
-	PCMCIA_PFC_DEVICE_PROD_ID12(0, "ATKK", "LM33-PCM-T", 0xba9eb7e2, 0x077c174e),
-	PCMCIA_PFC_DEVICE_PROD_ID12(0, "D-Link", "DME336T", 0x1a424a1c, 0xb23897ff),
-	PCMCIA_PFC_DEVICE_PROD_ID12(0, "Grey Cell", "GCS3000", 0x2a151fac, 0x48b932ae),
-	PCMCIA_PFC_DEVICE_PROD_ID12(0, "Linksys", "EtherFast 10&100 + 56K PC Card (PCMLM56)", 0x0733cc81, 0xb3765033),
-	PCMCIA_PFC_DEVICE_PROD_ID12(0, "LINKSYS", "PCMLM336", 0xf7cb0b07, 0x7a821b58),
-	PCMCIA_PFC_DEVICE_PROD_ID12(0, "MICRO RESEARCH", "COMBO-L/M-336", 0xb2ced065, 0x3ced0555),
-	PCMCIA_PFC_DEVICE_PROD_ID12(0, "PCMCIAs", "ComboCard", 0xdcfe12d3, 0xcd8906cc),
-	PCMCIA_PFC_DEVICE_PROD_ID12(0, "PCMCIAs", "LanModem", 0xdcfe12d3, 0xc67c648f),
-	PCMCIA_MFC_DEVICE_PROD_ID12(0, "IBM", "Home and Away 28.8 PC Card       ", 0xb569a6e5, 0x5bd4ff2c),
-	PCMCIA_MFC_DEVICE_PROD_ID12(0, "IBM", "Home and Away Credit Card Adapter", 0xb569a6e5, 0x4bdf15c3),
-	PCMCIA_MFC_DEVICE_PROD_ID12(0, "IBM", "w95 Home and Away Credit Card ", 0xb569a6e5, 0xae911c15),
-	PCMCIA_MFC_DEVICE_PROD_ID123(0, "APEX DATA", "MULTICARD", "ETHERNET-MODEM", 0x11c2da09, 0x7289dc5d, 0xaad95e1f),
-	PCMCIA_MFC_DEVICE_PROD_ID2(0, "FAX/Modem/Ethernet Combo Card ", 0x1ed59302),
-	PCMCIA_DEVICE_MANF_CARD(0x0057, 0x1004),
-	PCMCIA_DEVICE_MANF_CARD(0x0104, 0x000d),
-	PCMCIA_DEVICE_MANF_CARD(0x0104, 0x0075),
-	PCMCIA_DEVICE_MANF_CARD(0x0104, 0x0145),
-	PCMCIA_DEVICE_MANF_CARD(0x0149, 0x0230),
-	PCMCIA_DEVICE_MANF_CARD(0x0149, 0x4530),
-	PCMCIA_DEVICE_MANF_CARD(0x0149, 0xc1ab),
-	PCMCIA_DEVICE_MANF_CARD(0x0186, 0x0110),
-	PCMCIA_DEVICE_MANF_CARD(0x01bf, 0x8041),
-	PCMCIA_DEVICE_MANF_CARD(0x0213, 0x2452),
-	PCMCIA_DEVICE_MANF_CARD(0x026f, 0x0300),
-	PCMCIA_DEVICE_MANF_CARD(0x026f, 0x0307),
-	PCMCIA_DEVICE_MANF_CARD(0x026f, 0x030a),
-	PCMCIA_DEVICE_MANF_CARD(0x0274, 0x1103),
-	PCMCIA_DEVICE_MANF_CARD(0x0274, 0x1121),
-	PCMCIA_DEVICE_MANF_CARD(0xc001, 0x0009),
-	PCMCIA_DEVICE_PROD_ID12("2408LAN", "Ethernet", 0x352fff7f, 0x00b2e941),
-	PCMCIA_DEVICE_PROD_ID1234("Socket", "CF 10/100 Ethernet Card", "Revision B", "05/11/06", 0xb38bcc2e, 0x4de88352, 0xeaca6c8d, 0x7e57c22e),
-	PCMCIA_DEVICE_PROD_ID123("Cardwell", "PCMCIA", "ETHERNET", 0x9533672e, 0x281f1c5d, 0x3ff7175b),
-	PCMCIA_DEVICE_PROD_ID123("CNet  ", "CN30BC", "ETHERNET", 0x9fe55d3d, 0x85601198, 0x3ff7175b),
-	PCMCIA_DEVICE_PROD_ID123("Digital", "Ethernet", "Adapter", 0x9999ab35, 0x00b2e941, 0x4b0d829e),
-	PCMCIA_DEVICE_PROD_ID123("Edimax Technology Inc.", "PCMCIA", "Ethernet Card", 0x738a0019, 0x281f1c5d, 0x5e9d92c0),
-	PCMCIA_DEVICE_PROD_ID123("EFA   ", "EFA207", "ETHERNET", 0x3d294be4, 0xeb9aab6c, 0x3ff7175b),
-	PCMCIA_DEVICE_PROD_ID123("I-O DATA", "PCLA", "ETHERNET", 0x1d55d7ec, 0xe4c64d34, 0x3ff7175b),
-	PCMCIA_DEVICE_PROD_ID123("IO DATA", "PCLATE", "ETHERNET", 0x547e66dc, 0x6b260753, 0x3ff7175b),
-	PCMCIA_DEVICE_PROD_ID123("KingMax Technology Inc.", "EN10-T2", "PCMCIA Ethernet Card", 0x932b7189, 0x699e4436, 0x6f6652e0),
-	PCMCIA_DEVICE_PROD_ID123("PCMCIA", "PCMCIA-ETHERNET-CARD", "UE2216", 0x281f1c5d, 0xd4cd2f20, 0xb87add82),
-	PCMCIA_DEVICE_PROD_ID123("PCMCIA", "PCMCIA-ETHERNET-CARD", "UE2620", 0x281f1c5d, 0xd4cd2f20, 0x7d3d83a8),
-	PCMCIA_DEVICE_PROD_ID1("2412LAN", 0x67f236ab),
-	PCMCIA_DEVICE_PROD_ID12("ACCTON", "EN2212", 0xdfc6b5b2, 0xcb112a11),
-	PCMCIA_DEVICE_PROD_ID12("ACCTON", "EN2216-PCMCIA-ETHERNET", 0xdfc6b5b2, 0x5542bfff),
-	PCMCIA_DEVICE_PROD_ID12("Allied Telesis, K.K.", "CentreCOM LA100-PCM-T V2 100/10M LAN PC Card", 0xbb7fbdd7, 0xcd91cc68),
-	PCMCIA_DEVICE_PROD_ID12("Allied Telesis K.K.", "LA100-PCM V2", 0x36634a66, 0xc6d05997),
-	PCMCIA_DEVICE_PROD_ID12("Allied Telesis, K.K.", "CentreCOM LA-PCM_V2", 0xbb7fBdd7, 0x28e299f8),
-	PCMCIA_DEVICE_PROD_ID12("Allied Telesis K.K.", "LA-PCM V3", 0x36634a66, 0x62241d96),
-	PCMCIA_DEVICE_PROD_ID12("AmbiCom", "AMB8010", 0x5070a7f9, 0x82f96e96),
-	PCMCIA_DEVICE_PROD_ID12("AmbiCom", "AMB8610", 0x5070a7f9, 0x86741224),
-	PCMCIA_DEVICE_PROD_ID12("AmbiCom Inc", "AMB8002", 0x93b15570, 0x75ec3efb),
-	PCMCIA_DEVICE_PROD_ID12("AmbiCom Inc", "AMB8002T", 0x93b15570, 0x461c5247),
-	PCMCIA_DEVICE_PROD_ID12("AmbiCom Inc", "AMB8010", 0x93b15570, 0x82f96e96),
-	PCMCIA_DEVICE_PROD_ID12("AnyCom", "ECO Ethernet", 0x578ba6e7, 0x0a9888c1),
-	PCMCIA_DEVICE_PROD_ID12("AnyCom", "ECO Ethernet 10/100", 0x578ba6e7, 0x939fedbd),
-	PCMCIA_DEVICE_PROD_ID12("AROWANA", "PCMCIA Ethernet LAN Card", 0x313adbc8, 0x08d9f190),
-	PCMCIA_DEVICE_PROD_ID12("ASANTE", "FriendlyNet PC Card", 0x3a7ade0f, 0x41c64504),
-	PCMCIA_DEVICE_PROD_ID12("Billionton", "LNT-10TB", 0x552ab682, 0xeeb1ba6a),
-	PCMCIA_DEVICE_PROD_ID12("CF", "10Base-Ethernet", 0x44ebf863, 0x93ae4d79),
-	PCMCIA_DEVICE_PROD_ID12("CNet", "CN40BC Ethernet", 0xbc477dde, 0xfba775a7),
-	PCMCIA_DEVICE_PROD_ID12("COMPU-SHACK", "BASEline PCMCIA 10 MBit Ethernetadapter", 0xfa2e424d, 0xe9190d8a),
-	PCMCIA_DEVICE_PROD_ID12("COMPU-SHACK", "FASTline PCMCIA 10/100 Fast-Ethernet", 0xfa2e424d, 0x3953d9b9),
-	PCMCIA_DEVICE_PROD_ID12("CONTEC", "C-NET(PC)C-10L", 0x21cab552, 0xf6f90722),
-	PCMCIA_DEVICE_PROD_ID12("corega", "FEther PCC-TXF", 0x0a21501a, 0xa51564a2),
-	PCMCIA_DEVICE_PROD_ID12("corega", "Ether CF-TD", 0x0a21501a, 0x6589340a),
-	PCMCIA_DEVICE_PROD_ID12("corega K.K.", "corega Ether CF-TD LAN Card", 0x5261440f, 0x8797663b),
-	PCMCIA_DEVICE_PROD_ID12("corega K.K.", "corega EtherII PCC-T", 0x5261440f, 0xfa9d85bd),
-	PCMCIA_DEVICE_PROD_ID12("corega K.K.", "corega EtherII PCC-TD", 0x5261440f, 0xc49bd73d),
-	PCMCIA_DEVICE_PROD_ID12("Corega K.K.", "corega EtherII PCC-TD", 0xd4fdcbd8, 0xc49bd73d),
-	PCMCIA_DEVICE_PROD_ID12("corega K.K.", "corega Ether PCC-T", 0x5261440f, 0x6705fcaa),
-	PCMCIA_DEVICE_PROD_ID12("corega K.K.", "corega Ether PCC-TD", 0x5261440f, 0x47d5ca83),
-	PCMCIA_DEVICE_PROD_ID12("corega K.K.", "corega FastEther PCC-TX", 0x5261440f, 0x485e85d9),
-	PCMCIA_DEVICE_PROD_ID12("Corega,K.K.", "Ethernet LAN Card", 0x110d26d9, 0x9fd2f0a2),
-	PCMCIA_DEVICE_PROD_ID12("corega,K.K.", "Ethernet LAN Card", 0x9791a90e, 0x9fd2f0a2),
-	PCMCIA_DEVICE_PROD_ID12("corega K.K.", "(CG-LAPCCTXD)", 0x5261440f, 0x73ec0d88),
-	PCMCIA_DEVICE_PROD_ID12("CouplerlessPCMCIA", "100BASE", 0xee5af0ad, 0x7c2add04),
-	PCMCIA_DEVICE_PROD_ID12("CyQ've", "ELA-010", 0x77008979, 0x9d8d445d),
-	PCMCIA_DEVICE_PROD_ID12("CyQ've", "ELA-110E 10/100M LAN Card", 0x77008979, 0xfd184814),
-	PCMCIA_DEVICE_PROD_ID12("DataTrek.", "NetCard ", 0x5cd66d9d, 0x84697ce0),
-	PCMCIA_DEVICE_PROD_ID12("Dayna Communications, Inc.", "CommuniCard E", 0x0c629325, 0xb4e7dbaf),
-	PCMCIA_DEVICE_PROD_ID12("Digicom", "Palladio LAN 10/100", 0x697403d8, 0xe160b995),
-	PCMCIA_DEVICE_PROD_ID12("Digicom", "Palladio LAN 10/100 Dongless", 0x697403d8, 0xa6d3b233),
-	PCMCIA_DEVICE_PROD_ID12("DIGITAL", "DEPCM-XX", 0x69616cb3, 0xe600e76e),
-	PCMCIA_DEVICE_PROD_ID12("D-Link", "DE-650", 0x1a424a1c, 0xf28c8398),
-	PCMCIA_DEVICE_PROD_ID12("D-Link", "DE-660", 0x1a424a1c, 0xd9a1d05b),
-	PCMCIA_DEVICE_PROD_ID12("D-Link", "DE-660+", 0x1a424a1c, 0x50dcd0ec),
-	PCMCIA_DEVICE_PROD_ID12("D-Link", "DFE-650", 0x1a424a1c, 0x0f0073f9),
-	PCMCIA_DEVICE_PROD_ID12("Dual Speed", "10/100 PC Card", 0x725b842d, 0xf1efee84),
-	PCMCIA_DEVICE_PROD_ID12("Dual Speed", "10/100 Port Attached PC Card", 0x725b842d, 0x2db1f8e9),
-	PCMCIA_DEVICE_PROD_ID12("Dynalink", "L10BC", 0x55632fd5, 0xdc65f2b1),
-	PCMCIA_DEVICE_PROD_ID12("DYNALINK", "L10BC", 0x6a26d1cf, 0xdc65f2b1),
-	PCMCIA_DEVICE_PROD_ID12("DYNALINK", "L10C", 0x6a26d1cf, 0xc4f84efb),
-	PCMCIA_DEVICE_PROD_ID12("E-CARD", "E-CARD", 0x6701da11, 0x6701da11),
-	PCMCIA_DEVICE_PROD_ID12("EIGER Labs Inc.", "Ethernet 10BaseT card", 0x53c864c6, 0xedd059f6),
-	PCMCIA_DEVICE_PROD_ID12("EIGER Labs Inc.", "Ethernet Combo card", 0x53c864c6, 0x929c486c),
-	PCMCIA_DEVICE_PROD_ID12("Ethernet", "Adapter", 0x00b2e941, 0x4b0d829e),
-	PCMCIA_DEVICE_PROD_ID12("Ethernet Adapter", "E2000 PCMCIA Ethernet", 0x96767301, 0x71fbbc61),
-	PCMCIA_DEVICE_PROD_ID12("Ethernet PCMCIA adapter", "EP-210", 0x8dd86181, 0xf2b52517),
-	PCMCIA_DEVICE_PROD_ID12("Fast Ethernet", "Adapter", 0xb4be14e3, 0x4b0d829e),
-	PCMCIA_DEVICE_PROD_ID12("Grey Cell", "GCS2000", 0x2a151fac, 0xf00555cb),
-	PCMCIA_DEVICE_PROD_ID12("Grey Cell", "GCS2220", 0x2a151fac, 0xc1b7e327),
-	PCMCIA_DEVICE_PROD_ID12("GVC", "NIC-2000p", 0x76e171bd, 0x6eb1c947),
-	PCMCIA_DEVICE_PROD_ID12("IBM Corp.", "Ethernet", 0xe3736c88, 0x00b2e941),
-	PCMCIA_DEVICE_PROD_ID12("IC-CARD", "IC-CARD", 0x60cb09a6, 0x60cb09a6),
-	PCMCIA_DEVICE_PROD_ID12("IC-CARD+", "IC-CARD+", 0x93693494, 0x93693494),
-	PCMCIA_DEVICE_PROD_ID12("IO DATA", "PCETTX", 0x547e66dc, 0x6fc5459b),
-	PCMCIA_DEVICE_PROD_ID12("iPort", "10/100 Ethernet Card", 0x56c538d2, 0x11b0ffc0),
-	PCMCIA_DEVICE_PROD_ID12("KANSAI ELECTRIC CO.,LTD", "KLA-PCM/T", 0xb18dc3b4, 0xcc51a956),
-	PCMCIA_DEVICE_PROD_ID12("KENTRONICS", "KEP-230", 0xaf8144c9, 0x868f6616),
-	PCMCIA_DEVICE_PROD_ID12("KCI", "PE520 PCMCIA Ethernet Adapter", 0xa89b87d3, 0x1eb88e64),
-	PCMCIA_DEVICE_PROD_ID12("KINGMAX", "EN10T2T", 0x7bcb459a, 0xa5c81fa5),
-	PCMCIA_DEVICE_PROD_ID12("Kingston", "KNE-PC2", 0x1128e633, 0xce2a89b3),
-	PCMCIA_DEVICE_PROD_ID12("Kingston Technology Corp.", "EtheRx PC Card Ethernet Adapter", 0x313c7be3, 0x0afb54a2),
-	PCMCIA_DEVICE_PROD_ID12("Laneed", "LD-10/100CD", 0x1b7827b2, 0xcda71d1c),
-	PCMCIA_DEVICE_PROD_ID12("Laneed", "LD-CDF", 0x1b7827b2, 0xfec71e40),
-	PCMCIA_DEVICE_PROD_ID12("Laneed", "LD-CDL/T", 0x1b7827b2, 0x79fba4f7),
-	PCMCIA_DEVICE_PROD_ID12("Laneed", "LD-CDS", 0x1b7827b2, 0x931afaab),
-	PCMCIA_DEVICE_PROD_ID12("LEMEL", "LM-N89TX PRO", 0xbbefb52f, 0xd2897a97),
-	PCMCIA_DEVICE_PROD_ID12("Linksys", "Combo PCMCIA EthernetCard (EC2T)", 0x0733cc81, 0x32ee8c78),
-	PCMCIA_DEVICE_PROD_ID12("LINKSYS", "E-CARD", 0xf7cb0b07, 0x6701da11),
-	PCMCIA_DEVICE_PROD_ID12("Linksys", "EtherFast 10/100 Integrated PC Card (PCM100)", 0x0733cc81, 0x453c3f9d),
-	PCMCIA_DEVICE_PROD_ID12("Linksys", "EtherFast 10/100 PC Card (PCMPC100)", 0x0733cc81, 0x66c5a389),
-	PCMCIA_DEVICE_PROD_ID12("Linksys", "EtherFast 10/100 PC Card (PCMPC100 V2)", 0x0733cc81, 0x3a3b28e9),
-	PCMCIA_DEVICE_PROD_ID12("Linksys", "HomeLink Phoneline + 10/100 Network PC Card (PCM100H1)", 0x733cc81, 0x7a3e5c3a),
-	PCMCIA_DEVICE_PROD_ID12("Logitec", "LPM-LN100TX", 0x88fcdeda, 0x6d772737),
-	PCMCIA_DEVICE_PROD_ID12("Logitec", "LPM-LN100TE", 0x88fcdeda, 0x0e714bee),
-	PCMCIA_DEVICE_PROD_ID12("Logitec", "LPM-LN20T", 0x88fcdeda, 0x81090922),
-	PCMCIA_DEVICE_PROD_ID12("Logitec", "LPM-LN10TE", 0x88fcdeda, 0xc1e2521c),
-	PCMCIA_DEVICE_PROD_ID12("LONGSHINE", "PCMCIA Ethernet Card", 0xf866b0b0, 0x6f6652e0),
-	PCMCIA_DEVICE_PROD_ID12("MACNICA", "ME1-JEIDA", 0x20841b68, 0xaf8a3578),
-	PCMCIA_DEVICE_PROD_ID12("Macsense", "MPC-10", 0xd830297f, 0xd265c307),
-	PCMCIA_DEVICE_PROD_ID12("Matsushita Electric Industrial Co.,LTD.", "CF-VEL211", 0x44445376, 0x8ded41d4),
-	PCMCIA_DEVICE_PROD_ID12("MAXTECH", "PCN2000", 0x78d64bc0, 0xca0ca4b8),
-	PCMCIA_DEVICE_PROD_ID12("MELCO", "LPC2-T", 0x481e0094, 0xa2eb0cf3),
-	PCMCIA_DEVICE_PROD_ID12("MELCO", "LPC2-TX", 0x481e0094, 0x41a6916c),
-	PCMCIA_DEVICE_PROD_ID12("Microcom C.E.", "Travel Card LAN 10/100", 0x4b91cec7, 0xe70220d6),
-	PCMCIA_DEVICE_PROD_ID12("Microdyne", "NE4200", 0x2e6da59b, 0x0478e472),
-	PCMCIA_DEVICE_PROD_ID12("MIDORI ELEC.", "LT-PCMT", 0x648d55c1, 0xbde526c7),
-	PCMCIA_DEVICE_PROD_ID12("National Semiconductor", "InfoMover 4100", 0x36e1191f, 0x60c229b9),
-	PCMCIA_DEVICE_PROD_ID12("National Semiconductor", "InfoMover NE4100", 0x36e1191f, 0xa6617ec8),
-	PCMCIA_DEVICE_PROD_ID12("NEC", "PC-9801N-J12", 0x18df0ba0, 0xbc912d76),
-	PCMCIA_DEVICE_PROD_ID12("NETGEAR", "FA410TX", 0x9aa79dc3, 0x60e5bc0e),
-	PCMCIA_DEVICE_PROD_ID12("Network Everywhere", "Fast Ethernet 10/100 PC Card", 0x820a67b6, 0x31ed1a5f),
-	PCMCIA_DEVICE_PROD_ID12("NextCom K.K.", "Next Hawk", 0xaedaec74, 0xad050ef1),
-	PCMCIA_DEVICE_PROD_ID12("PCMCIA", "10/100Mbps Ethernet Card", 0x281f1c5d, 0x6e41773b),
-	PCMCIA_DEVICE_PROD_ID12("PCMCIA", "Ethernet", 0x281f1c5d, 0x00b2e941),
-	PCMCIA_DEVICE_PROD_ID12("PCMCIA", "ETHERNET", 0x281f1c5d, 0x3ff7175b),
-	PCMCIA_DEVICE_PROD_ID12("PCMCIA", "Ethernet 10BaseT Card", 0x281f1c5d, 0x4de2f6c8),
-	PCMCIA_DEVICE_PROD_ID12("PCMCIA", "Ethernet Card", 0x281f1c5d, 0x5e9d92c0),
-	PCMCIA_DEVICE_PROD_ID12("PCMCIA", "Ethernet Combo card", 0x281f1c5d, 0x929c486c),
-	PCMCIA_DEVICE_PROD_ID12("PCMCIA", "ETHERNET V1.0", 0x281f1c5d, 0x4d8817c8),
-	PCMCIA_DEVICE_PROD_ID12("PCMCIA", "FastEthernet", 0x281f1c5d, 0xfe871eeb),
-	PCMCIA_DEVICE_PROD_ID12("PCMCIA", "Fast-Ethernet", 0x281f1c5d, 0x45f1f3b4),
-	PCMCIA_DEVICE_PROD_ID12("PCMCIA", "FAST ETHERNET CARD", 0x281f1c5d, 0xec5dbca7),
-	PCMCIA_DEVICE_PROD_ID12("PCMCIA LAN", "Ethernet", 0x7500e246, 0x00b2e941),
-	PCMCIA_DEVICE_PROD_ID12("PCMCIA", "LNT-10TN", 0x281f1c5d, 0xe707f641),
-	PCMCIA_DEVICE_PROD_ID12("PCMCIAs", "ComboCard", 0xdcfe12d3, 0xcd8906cc),
-	PCMCIA_DEVICE_PROD_ID12("PCMCIA", "UE2212", 0x281f1c5d, 0xbf17199b),
-	PCMCIA_DEVICE_PROD_ID12("PCMCIA", "    Ethernet NE2000 Compatible", 0x281f1c5d, 0x42d5d7e1),
-	PCMCIA_DEVICE_PROD_ID12("PRETEC", "Ethernet CompactLAN 10baseT 3.3V", 0xebf91155, 0x30074c80),
-	PCMCIA_DEVICE_PROD_ID12("PRETEC", "Ethernet CompactLAN 10BaseT 3.3V", 0xebf91155, 0x7f5a4f50),
-	PCMCIA_DEVICE_PROD_ID12("Psion Dacom", "Gold Card Ethernet", 0xf5f025c2, 0x3a30e110),
-	PCMCIA_DEVICE_PROD_ID12("=RELIA==", "Ethernet", 0xcdd0644a, 0x00b2e941),
-	PCMCIA_DEVICE_PROD_ID12("RIOS Systems Co.", "PC CARD3 ETHERNET", 0x7dd33481, 0x10b41826),
-	PCMCIA_DEVICE_PROD_ID12("RP", "1625B Ethernet NE2000 Compatible", 0xe3e66e22, 0xb96150df),
-	PCMCIA_DEVICE_PROD_ID12("RPTI", "EP400 Ethernet NE2000 Compatible", 0xdc6f88fd, 0x4a7e2ae0),
-	PCMCIA_DEVICE_PROD_ID12("RPTI", "EP401 Ethernet NE2000 Compatible", 0xdc6f88fd, 0x4bcbd7fd),
-	PCMCIA_DEVICE_PROD_ID12("RPTI LTD.", "EP400", 0xc53ac515, 0x81e39388),
-	PCMCIA_DEVICE_PROD_ID12("SCM", "Ethernet Combo card", 0xbdc3b102, 0x929c486c),
-	PCMCIA_DEVICE_PROD_ID12("Seiko Epson Corp.", "Ethernet", 0x09928730, 0x00b2e941),
-	PCMCIA_DEVICE_PROD_ID12("SMC", "EZCard-10-PCMCIA", 0xc4f8b18b, 0xfb21d265),
-	PCMCIA_DEVICE_PROD_ID12("Socket Communications Inc", "Socket EA PCMCIA LAN Adapter Revision D", 0xc70a4760, 0x2ade483e),
-	PCMCIA_DEVICE_PROD_ID12("Socket Communications Inc", "Socket EA PCMCIA LAN Adapter Revision E", 0xc70a4760, 0x5dd978a8),
-	PCMCIA_DEVICE_PROD_ID12("TDK", "LAK-CD031 for PCMCIA", 0x1eae9475, 0x0ed386fa),
-	PCMCIA_DEVICE_PROD_ID12("Telecom Device K.K.", "SuperSocket RE450T", 0x466b05f0, 0x8b74bc4f),
-	PCMCIA_DEVICE_PROD_ID12("Telecom Device K.K.", "SuperSocket RE550T", 0x466b05f0, 0x33c8db2a),
-	PCMCIA_DEVICE_PROD_ID13("Hypertec",  "EP401", 0x8787bec7, 0xf6e4a31e),
-	PCMCIA_DEVICE_PROD_ID13("KingMax Technology Inc.", "Ethernet Card", 0x932b7189, 0x5e9d92c0),
-	PCMCIA_DEVICE_PROD_ID13("LONGSHINE", "EP401", 0xf866b0b0, 0xf6e4a31e),
-	PCMCIA_DEVICE_PROD_ID13("Xircom", "CFE-10", 0x2e3ee845, 0x22a49f89),
-	PCMCIA_DEVICE_PROD_ID1("CyQ've 10 Base-T LAN CARD", 0x94faf360),
-	PCMCIA_DEVICE_PROD_ID1("EP-210 PCMCIA LAN CARD.", 0x8850b4de),
-	PCMCIA_DEVICE_PROD_ID1("ETHER-C16", 0x06a8514f),
-	PCMCIA_DEVICE_PROD_ID1("NE2000 Compatible", 0x75b8ad5a),
-	PCMCIA_DEVICE_PROD_ID2("EN-6200P2", 0xa996d078),
-	/* too generic! */
-	/* PCMCIA_DEVICE_PROD_ID12("PCMCIA", "10/100 Ethernet Card", 0x281f1c5d, 0x11b0ffc0), */
-	PCMCIA_PFC_DEVICE_CIS_PROD_ID12(0, "PCMCIA", "EN2218-LAN/MODEM", 0x281f1c5d, 0x570f348e, "cis/PCMLM28.cis"),
-	PCMCIA_PFC_DEVICE_CIS_PROD_ID12(0, "PCMCIA", "UE2218-LAN/MODEM", 0x281f1c5d, 0x6fdcacee, "cis/PCMLM28.cis"),
-	PCMCIA_PFC_DEVICE_CIS_PROD_ID12(0, "Psion Dacom", "Gold Card V34 Ethernet", 0xf5f025c2, 0x338e8155, "cis/PCMLM28.cis"),
-	PCMCIA_PFC_DEVICE_CIS_PROD_ID12(0, "Psion Dacom", "Gold Card V34 Ethernet GSM", 0xf5f025c2, 0x4ae85d35, "cis/PCMLM28.cis"),
-	PCMCIA_PFC_DEVICE_CIS_PROD_ID12(0, "LINKSYS", "PCMLM28", 0xf7cb0b07, 0x66881874, "cis/PCMLM28.cis"),
-	PCMCIA_PFC_DEVICE_CIS_PROD_ID12(0, "TOSHIBA", "Modem/LAN Card", 0xb4585a1a, 0x53f922f8, "cis/PCMLM28.cis"),
-	PCMCIA_MFC_DEVICE_CIS_PROD_ID12(0, "DAYNA COMMUNICATIONS", "LAN AND MODEM MULTIFUNCTION", 0x8fdf8f89, 0xdd5ed9e8, "cis/DP83903.cis"),
-	PCMCIA_MFC_DEVICE_CIS_PROD_ID4(0, "NSC MF LAN/Modem", 0x58fc6056, "cis/DP83903.cis"),
-	PCMCIA_MFC_DEVICE_CIS_MANF_CARD(0, 0x0175, 0x0000, "cis/DP83903.cis"),
-	PCMCIA_DEVICE_CIS_PROD_ID12("Allied Telesis,K.K", "Ethernet LAN Card", 0x2ad62f3c, 0x9fd2f0a2, "cis/LA-PCM.cis"),
-	PCMCIA_DEVICE_CIS_PROD_ID12("KTI", "PE520 PLUS", 0xad180345, 0x9d58d392, "cis/PE520.cis"),
-	PCMCIA_DEVICE_CIS_PROD_ID12("NDC", "Ethernet", 0x01c43ae1, 0x00b2e941, "cis/NE2K.cis"),
-	PCMCIA_DEVICE_CIS_PROD_ID12("PMX   ", "PE-200", 0x34f3f1c8, 0x10b59f8c, "cis/PE-200.cis"),
-	PCMCIA_DEVICE_CIS_PROD_ID12("TAMARACK", "Ethernet", 0xcf434fba, 0x00b2e941, "cis/tamarack.cis"),
-	PCMCIA_DEVICE_PROD_ID12("Ethernet", "CF Size PC Card", 0x00b2e941, 0x43ac239b),
-	PCMCIA_DEVICE_PROD_ID123("Fast Ethernet", "CF Size PC Card", "1.0",
-		0xb4be14e3, 0x43ac239b, 0x0877b627),
-	PCMCIA_DEVICE_NULL
-};
-MODULE_DEVICE_TABLE(pcmcia, pcnet_ids);
-MODULE_FIRMWARE("cis/PCMLM28.cis");
-MODULE_FIRMWARE("cis/DP83903.cis");
-MODULE_FIRMWARE("cis/LA-PCM.cis");
-MODULE_FIRMWARE("cis/PE520.cis");
-MODULE_FIRMWARE("cis/NE2K.cis");
-MODULE_FIRMWARE("cis/PE-200.cis");
-MODULE_FIRMWARE("cis/tamarack.cis");
-
-static struct pcmcia_driver pcnet_driver = {
-	.name		= "pcnet_cs",
-	.probe		= pcnet_probe,
-	.remove		= pcnet_detach,
-	.owner		= THIS_MODULE,
-	.id_table	= pcnet_ids,
-	.suspend	= pcnet_suspend,
-	.resume		= pcnet_resume,
-};
-module_pcmcia_driver(pcnet_driver);

-- 
2.53.0


^ permalink raw reply related	[flat|nested] 28+ messages in thread

* [PATCH net 17/18] drivers: net: 8390: ultra: Remove this driver
  2026-04-21 19:31 [PATCH net 00/18] Remove a number of ISA and PCMCIA Ethernet drivers Andrew Lunn
                   ` (15 preceding siblings ...)
  2026-04-21 19:31 ` [PATCH net 16/18] drivers: net: 8390: pcnet: " Andrew Lunn
@ 2026-04-21 19:31 ` Andrew Lunn
  2026-04-21 19:31 ` [PATCH net 18/18] drivers: net: 8390: wd80x3: " Andrew Lunn
                   ` (4 subsequent siblings)
  21 siblings, 0 replies; 28+ messages in thread
From: Andrew Lunn @ 2026-04-21 19:31 UTC (permalink / raw)
  To: Andrew Lunn, David S. Miller, Eric Dumazet, Jakub Kicinski,
	Paolo Abeni, Simon Horman, Jonathan Corbet, Shuah Khan
  Cc: linux-kernel, netdev, linux-doc, Andrew Lunn

The ultra was written by Donald Becker 1993 to 1998. It is an ISA
device, so unlikely to be used with modern kernels.

Signed-off-by: Andrew Lunn <andrew@lunn.ch>
---
 drivers/net/ethernet/8390/Kconfig     |  18 -
 drivers/net/ethernet/8390/Makefile    |   1 -
 drivers/net/ethernet/8390/smc-ultra.c | 630 ----------------------------------
 3 files changed, 649 deletions(-)

diff --git a/drivers/net/ethernet/8390/Kconfig b/drivers/net/ethernet/8390/Kconfig
index 3e56806471a3..dd066b0a39d5 100644
--- a/drivers/net/ethernet/8390/Kconfig
+++ b/drivers/net/ethernet/8390/Kconfig
@@ -144,24 +144,6 @@ config STNIC
 
 	  If unsure, say N.
 
-config ULTRA
-	tristate "SMC Ultra support"
-	depends on ISA
-	select NETDEV_LEGACY_INIT
-	select CRC32
-	help
-	  If you have a network (Ethernet) card of this type, say Y here.
-
-	  Important: There have been many reports that, with some motherboards
-	  mixing an SMC Ultra and an Adaptec AHA154x SCSI card (or compatible,
-	  such as some BusLogic models) causes corruption problems with many
-	  operating systems. The Linux smc-ultra driver has a work-around for
-	  this but keep it in mind if you have such a SCSI card and have
-	  problems.
-
-	  To compile this driver as a module, choose M here. The module
-	  will be called smc-ultra.
-
 config WD80x3
 	tristate "WD80*3 support"
 	depends on ISA
diff --git a/drivers/net/ethernet/8390/Makefile b/drivers/net/ethernet/8390/Makefile
index b215136a603b..0afdccddda58 100644
--- a/drivers/net/ethernet/8390/Makefile
+++ b/drivers/net/ethernet/8390/Makefile
@@ -12,7 +12,6 @@ obj-$(CONFIG_MCF8390) += mcf8390.o
 obj-$(CONFIG_NE2000) += ne.o 8390p.o
 obj-$(CONFIG_NE2K_PCI) += ne2k-pci.o 8390.o
 obj-$(CONFIG_STNIC) += stnic.o 8390.o
-obj-$(CONFIG_ULTRA) += smc-ultra.o 8390.o
 obj-$(CONFIG_WD80x3) += wd.o 8390.o
 obj-$(CONFIG_XSURF100) += xsurf100.o
 obj-$(CONFIG_ZORRO8390) += zorro8390.o
diff --git a/drivers/net/ethernet/8390/smc-ultra.c b/drivers/net/ethernet/8390/smc-ultra.c
deleted file mode 100644
index 22ca804b2e95..000000000000
--- a/drivers/net/ethernet/8390/smc-ultra.c
+++ /dev/null
@@ -1,630 +0,0 @@
-// SPDX-License-Identifier: GPL-1.0+
-/* smc-ultra.c: A SMC Ultra ethernet driver for linux. */
-/*
-	This is a driver for the SMC Ultra and SMC EtherEZ ISA ethercards.
-
-	Written 1993-1998 by Donald Becker.
-
-	Copyright 1993 United States Government as represented by the
-	Director, National Security Agency.
-
-	The author may be reached as becker@scyld.com, or C/O
-	Scyld Computing Corporation
-	410 Severn Ave., Suite 210
-	Annapolis MD 21403
-
-	This driver uses the cards in the 8390-compatible mode.
-	Most of the run-time complexity is handled by the generic code in
-	8390.c.  The code in this file is responsible for
-
-		ultra_probe()	 	Detecting and initializing the card.
-		ultra_probe1()
-		ultra_probe_isapnp()
-
-		ultra_open()		The card-specific details of starting, stopping
-		ultra_reset_8390()	and resetting the 8390 NIC core.
-		ultra_close()
-
-		ultra_block_input()		Routines for reading and writing blocks of
-		ultra_block_output()	packet buffer memory.
-		ultra_pio_input()
-		ultra_pio_output()
-
-	This driver enables the shared memory only when doing the actual data
-	transfers to avoid a bug in early version of the card that corrupted
-	data transferred by a AHA1542.
-
-	This driver now supports the programmed-I/O (PIO) data transfer mode of
-	the EtherEZ. It does not use the non-8390-compatible "Altego" mode.
-	That support (if available) is in smc-ez.c.
-
-	Changelog:
-
-	Paul Gortmaker	: multiple card support for module users.
-	Donald Becker	: 4/17/96 PIO support, minor potential problems avoided.
-	Donald Becker	: 6/6/96 correctly set auto-wrap bit.
-	Alexander Sotirov : 1/20/01 Added support for ISAPnP cards
-
-	Note about the ISA PnP support:
-
-	This driver can not autoprobe for more than one SMC EtherEZ PnP card.
-	You have to configure the second card manually through the /proc/isapnp
-	interface and then load the module with an explicit io=0x___ option.
-*/
-
-static const char version[] =
-	"smc-ultra.c:v2.02 2/3/98 Donald Becker (becker@cesdis.gsfc.nasa.gov)\n";
-
-#include <linux/module.h>
-#include <linux/kernel.h>
-#include <linux/errno.h>
-#include <linux/string.h>
-#include <linux/init.h>
-#include <linux/interrupt.h>
-#include <linux/isapnp.h>
-#include <linux/netdevice.h>
-#include <linux/etherdevice.h>
-#include <net/Space.h>
-
-#include <asm/io.h>
-#include <asm/irq.h>
-
-#include "8390.h"
-
-#define DRV_NAME "smc-ultra"
-
-/* A zero-terminated list of I/O addresses to be probed. */
-static unsigned int ultra_portlist[] __initdata =
-{0x200, 0x220, 0x240, 0x280, 0x300, 0x340, 0x380, 0};
-
-static int ultra_probe1(struct net_device *dev, int ioaddr);
-
-#ifdef __ISAPNP__
-static int ultra_probe_isapnp(struct net_device *dev);
-#endif
-
-static int ultra_open(struct net_device *dev);
-static void ultra_reset_8390(struct net_device *dev);
-static void ultra_get_8390_hdr(struct net_device *dev, struct e8390_pkt_hdr *hdr,
-						int ring_page);
-static void ultra_block_input(struct net_device *dev, int count,
-						  struct sk_buff *skb, int ring_offset);
-static void ultra_block_output(struct net_device *dev, int count,
-							const unsigned char *buf, const int start_page);
-static void ultra_pio_get_hdr(struct net_device *dev, struct e8390_pkt_hdr *hdr,
-						int ring_page);
-static void ultra_pio_input(struct net_device *dev, int count,
-						  struct sk_buff *skb, int ring_offset);
-static void ultra_pio_output(struct net_device *dev, int count,
-							 const unsigned char *buf, const int start_page);
-static int ultra_close_card(struct net_device *dev);
-
-#ifdef __ISAPNP__
-static struct isapnp_device_id ultra_device_ids[] __initdata = {
-        {       ISAPNP_VENDOR('S','M','C'), ISAPNP_FUNCTION(0x8416),
-                ISAPNP_VENDOR('S','M','C'), ISAPNP_FUNCTION(0x8416),
-                (long) "SMC EtherEZ (8416)" },
-        { }	/* terminate list */
-};
-
-MODULE_DEVICE_TABLE(isapnp, ultra_device_ids);
-#endif
-
-static u32 ultra_msg_enable;
-
-#define START_PG		0x00	/* First page of TX buffer */
-
-#define ULTRA_CMDREG	0		/* Offset to ASIC command register. */
-#define	 ULTRA_RESET	0x80	/* Board reset, in ULTRA_CMDREG. */
-#define	 ULTRA_MEMENB	0x40	/* Enable the shared memory. */
-#define IOPD	0x02			/* I/O Pipe Data (16 bits), PIO operation. */
-#define IOPA	0x07			/* I/O Pipe Address for PIO operation. */
-#define ULTRA_NIC_OFFSET  16	/* NIC register offset from the base_addr. */
-#define ULTRA_IO_EXTENT 32
-#define EN0_ERWCNT		0x08	/* Early receive warning count. */
-
-#ifdef CONFIG_NET_POLL_CONTROLLER
-static void ultra_poll(struct net_device *dev)
-{
-	disable_irq(dev->irq);
-	ei_interrupt(dev->irq, dev);
-	enable_irq(dev->irq);
-}
-#endif
-/*	Probe for the Ultra.  This looks like a 8013 with the station
-	address PROM at I/O ports <base>+8 to <base>+13, with a checksum
-	following.
-*/
-
-static int __init do_ultra_probe(struct net_device *dev)
-{
-	int i;
-	int base_addr = dev->base_addr;
-	int irq = dev->irq;
-
-	if (base_addr > 0x1ff)		/* Check a single specified location. */
-		return ultra_probe1(dev, base_addr);
-	else if (base_addr != 0)	/* Don't probe at all. */
-		return -ENXIO;
-
-#ifdef __ISAPNP__
-	/* Look for any installed ISAPnP cards */
-	if (isapnp_present() && (ultra_probe_isapnp(dev) == 0))
-		return 0;
-#endif
-
-	for (i = 0; ultra_portlist[i]; i++) {
-		dev->irq = irq;
-		if (ultra_probe1(dev, ultra_portlist[i]) == 0)
-			return 0;
-	}
-
-	return -ENODEV;
-}
-
-#ifndef MODULE
-struct net_device * __init ultra_probe(int unit)
-{
-	struct net_device *dev = alloc_ei_netdev();
-	int err;
-
-	if (!dev)
-		return ERR_PTR(-ENOMEM);
-
-	sprintf(dev->name, "eth%d", unit);
-	netdev_boot_setup_check(dev);
-
-	err = do_ultra_probe(dev);
-	if (err)
-		goto out;
-	return dev;
-out:
-	free_netdev(dev);
-	return ERR_PTR(err);
-}
-#endif
-
-static const struct net_device_ops ultra_netdev_ops = {
-	.ndo_open		= ultra_open,
-	.ndo_stop		= ultra_close_card,
-
-	.ndo_start_xmit		= ei_start_xmit,
-	.ndo_tx_timeout		= ei_tx_timeout,
-	.ndo_get_stats		= ei_get_stats,
-	.ndo_set_rx_mode	= ei_set_multicast_list,
-	.ndo_validate_addr	= eth_validate_addr,
-	.ndo_set_mac_address 	= eth_mac_addr,
-#ifdef CONFIG_NET_POLL_CONTROLLER
-	.ndo_poll_controller 	= ultra_poll,
-#endif
-};
-
-static int __init ultra_probe1(struct net_device *dev, int ioaddr)
-{
-	int i, retval;
-	int checksum = 0;
-	u8 macaddr[ETH_ALEN];
-	const char *model_name;
-	unsigned char eeprom_irq = 0;
-	static unsigned version_printed;
-	/* Values from various config regs. */
-	unsigned char num_pages, irqreg, addr, piomode;
-	unsigned char idreg = inb(ioaddr + 7);
-	unsigned char reg4 = inb(ioaddr + 4) & 0x7f;
-	struct ei_device *ei_local = netdev_priv(dev);
-
-	if (!request_region(ioaddr, ULTRA_IO_EXTENT, DRV_NAME))
-		return -EBUSY;
-
-	/* Check the ID nibble. */
-	if ((idreg & 0xF0) != 0x20 			/* SMC Ultra */
-		&& (idreg & 0xF0) != 0x40) {		/* SMC EtherEZ */
-		retval = -ENODEV;
-		goto out;
-	}
-
-	/* Select the station address register set. */
-	outb(reg4, ioaddr + 4);
-
-	for (i = 0; i < 8; i++)
-		checksum += inb(ioaddr + 8 + i);
-	if ((checksum & 0xff) != 0xFF) {
-		retval = -ENODEV;
-		goto out;
-	}
-
-	if ((ultra_msg_enable & NETIF_MSG_DRV) && (version_printed++ == 0))
-		netdev_info(dev, version);
-
-	model_name = (idreg & 0xF0) == 0x20 ? "SMC Ultra" : "SMC EtherEZ";
-
-	for (i = 0; i < 6; i++)
-		macaddr[i] = inb(ioaddr + 8 + i);
-	eth_hw_addr_set(dev, macaddr);
-
-	netdev_info(dev, "%s at %#3x, %pM", model_name,
-		    ioaddr, dev->dev_addr);
-
-	/* Switch from the station address to the alternate register set and
-	   read the useful registers there. */
-	outb(0x80 | reg4, ioaddr + 4);
-
-	/* Enabled FINE16 mode to avoid BIOS ROM width mismatches @ reboot. */
-	outb(0x80 | inb(ioaddr + 0x0c), ioaddr + 0x0c);
-	piomode = inb(ioaddr + 0x8);
-	addr = inb(ioaddr + 0xb);
-	irqreg = inb(ioaddr + 0xd);
-
-	/* Switch back to the station address register set so that the MS-DOS driver
-	   can find the card after a warm boot. */
-	outb(reg4, ioaddr + 4);
-
-	if (dev->irq < 2) {
-		unsigned char irqmap[] = {0, 9, 3, 5, 7, 10, 11, 15};
-		int irq;
-
-		/* The IRQ bits are split. */
-		irq = irqmap[((irqreg & 0x40) >> 4) + ((irqreg & 0x0c) >> 2)];
-
-		if (irq == 0) {
-			pr_cont(", failed to detect IRQ line.\n");
-			retval =  -EAGAIN;
-			goto out;
-		}
-		dev->irq = irq;
-		eeprom_irq = 1;
-	}
-
-	/* The 8390 isn't at the base address, so fake the offset */
-	dev->base_addr = ioaddr+ULTRA_NIC_OFFSET;
-
-	{
-		static const int addr_tbl[4] = {
-			0x0C0000, 0x0E0000, 0xFC0000, 0xFE0000
-		};
-		static const short num_pages_tbl[4] = {
-			0x20, 0x40, 0x80, 0xff
-		};
-
-		dev->mem_start = ((addr & 0x0f) << 13) + addr_tbl[(addr >> 6) & 3] ;
-		num_pages = num_pages_tbl[(addr >> 4) & 3];
-	}
-
-	ei_status.name = model_name;
-	ei_status.word16 = 1;
-	ei_status.tx_start_page = START_PG;
-	ei_status.rx_start_page = START_PG + TX_PAGES;
-	ei_status.stop_page = num_pages;
-
-	ei_status.mem = ioremap(dev->mem_start, (ei_status.stop_page - START_PG)*256);
-	if (!ei_status.mem) {
-		pr_cont(", failed to ioremap.\n");
-		retval =  -ENOMEM;
-		goto out;
-	}
-
-	dev->mem_end = dev->mem_start + (ei_status.stop_page - START_PG)*256;
-
-	if (piomode) {
-		pr_cont(", %s IRQ %d programmed-I/O mode.\n",
-			eeprom_irq ? "EEPROM" : "assigned ", dev->irq);
-		ei_status.block_input = &ultra_pio_input;
-		ei_status.block_output = &ultra_pio_output;
-		ei_status.get_8390_hdr = &ultra_pio_get_hdr;
-	} else {
-		pr_cont(", %s IRQ %d memory %#lx-%#lx.\n",
-			eeprom_irq ? "" : "assigned ", dev->irq, dev->mem_start,
-			dev->mem_end-1);
-		ei_status.block_input = &ultra_block_input;
-		ei_status.block_output = &ultra_block_output;
-		ei_status.get_8390_hdr = &ultra_get_8390_hdr;
-	}
-	ei_status.reset_8390 = &ultra_reset_8390;
-
-	dev->netdev_ops = &ultra_netdev_ops;
-	NS8390_init(dev, 0);
-	ei_local->msg_enable = ultra_msg_enable;
-
-	retval = register_netdev(dev);
-	if (retval)
-		goto out;
-	return 0;
-out:
-	release_region(ioaddr, ULTRA_IO_EXTENT);
-	return retval;
-}
-
-#ifdef __ISAPNP__
-static int __init ultra_probe_isapnp(struct net_device *dev)
-{
-        int i;
-
-        for (i = 0; ultra_device_ids[i].vendor != 0; i++) {
-		struct pnp_dev *idev = NULL;
-
-                while ((idev = pnp_find_dev(NULL,
-                                            ultra_device_ids[i].vendor,
-                                            ultra_device_ids[i].function,
-                                            idev))) {
-                        /* Avoid already found cards from previous calls */
-                        if (pnp_device_attach(idev) < 0)
-				continue;
-                        if (pnp_activate_dev(idev) < 0) {
-                              __again:
-				pnp_device_detach(idev);
-				continue;
-                        }
-			/* if no io and irq, search for next */
-			if (!pnp_port_valid(idev, 0) || !pnp_irq_valid(idev, 0))
-				goto __again;
-                        /* found it */
-			dev->base_addr = pnp_port_start(idev, 0);
-			dev->irq = pnp_irq(idev, 0);
-			netdev_info(dev,
-				    "smc-ultra.c: ISAPnP reports %s at i/o %#lx, irq %d.\n",
-				    (char *) ultra_device_ids[i].driver_data,
-				    dev->base_addr, dev->irq);
-                        if (ultra_probe1(dev, dev->base_addr) != 0) {      /* Shouldn't happen. */
-				netdev_err(dev,
-					   "smc-ultra.c: Probe of ISAPnP card at %#lx failed.\n",
-					   dev->base_addr);
-				pnp_device_detach(idev);
-				return -ENXIO;
-                        }
-                        ei_status.priv = (unsigned long)idev;
-                        break;
-                }
-                if (!idev)
-                        continue;
-                return 0;
-        }
-
-        return -ENODEV;
-}
-#endif
-
-static int
-ultra_open(struct net_device *dev)
-{
-	int retval;
-	int ioaddr = dev->base_addr - ULTRA_NIC_OFFSET; /* ASIC addr */
-	unsigned char irq2reg[] = {0, 0, 0x04, 0x08, 0, 0x0C, 0, 0x40,
-				   0, 0x04, 0x44, 0x48, 0, 0, 0, 0x4C, };
-
-	retval = request_irq(dev->irq, ei_interrupt, 0, dev->name, dev);
-	if (retval)
-		return retval;
-
-	outb(0x00, ioaddr);	/* Disable shared memory for safety. */
-	outb(0x80, ioaddr + 5);
-	/* Set the IRQ line. */
-	outb(inb(ioaddr + 4) | 0x80, ioaddr + 4);
-	outb((inb(ioaddr + 13) & ~0x4C) | irq2reg[dev->irq], ioaddr + 13);
-	outb(inb(ioaddr + 4) & 0x7f, ioaddr + 4);
-
-	if (ei_status.block_input == &ultra_pio_input) {
-		outb(0x11, ioaddr + 6);		/* Enable interrupts and PIO. */
-		outb(0x01, ioaddr + 0x19);  	/* Enable ring read auto-wrap. */
-	} else
-		outb(0x01, ioaddr + 6);		/* Enable interrupts and memory. */
-	/* Set the early receive warning level in window 0 high enough not
-	   to receive ERW interrupts. */
-	outb_p(E8390_NODMA+E8390_PAGE0, dev->base_addr);
-	outb(0xff, dev->base_addr + EN0_ERWCNT);
-	ei_open(dev);
-	return 0;
-}
-
-static void
-ultra_reset_8390(struct net_device *dev)
-{
-	int cmd_port = dev->base_addr - ULTRA_NIC_OFFSET; /* ASIC base addr */
-	struct ei_device *ei_local = netdev_priv(dev);
-
-	outb(ULTRA_RESET, cmd_port);
-	netif_dbg(ei_local, hw, dev, "resetting Ultra, t=%ld...\n", jiffies);
-	ei_status.txing = 0;
-
-	outb(0x00, cmd_port);	/* Disable shared memory for safety. */
-	outb(0x80, cmd_port + 5);
-	if (ei_status.block_input == &ultra_pio_input)
-		outb(0x11, cmd_port + 6);		/* Enable interrupts and PIO. */
-	else
-		outb(0x01, cmd_port + 6);		/* Enable interrupts and memory. */
-
-	netif_dbg(ei_local, hw, dev, "reset done\n");
-}
-
-/* Grab the 8390 specific header. Similar to the block_input routine, but
-   we don't need to be concerned with ring wrap as the header will be at
-   the start of a page, so we optimize accordingly. */
-
-static void
-ultra_get_8390_hdr(struct net_device *dev, struct e8390_pkt_hdr *hdr, int ring_page)
-{
-	void __iomem *hdr_start = ei_status.mem + ((ring_page - START_PG)<<8);
-
-	outb(ULTRA_MEMENB, dev->base_addr - ULTRA_NIC_OFFSET);	/* shmem on */
-#ifdef __BIG_ENDIAN
-	/* Officially this is what we are doing, but the readl() is faster */
-	/* unfortunately it isn't endian aware of the struct               */
-	memcpy_fromio(hdr, hdr_start, sizeof(struct e8390_pkt_hdr));
-	hdr->count = le16_to_cpu(hdr->count);
-#else
-	((unsigned int*)hdr)[0] = readl(hdr_start);
-#endif
-	outb(0x00, dev->base_addr - ULTRA_NIC_OFFSET); /* shmem off */
-}
-
-/* Block input and output are easy on shared memory ethercards, the only
-   complication is when the ring buffer wraps. */
-
-static void
-ultra_block_input(struct net_device *dev, int count, struct sk_buff *skb, int ring_offset)
-{
-	void __iomem *xfer_start = ei_status.mem + ring_offset - (START_PG<<8);
-
-	/* Enable shared memory. */
-	outb(ULTRA_MEMENB, dev->base_addr - ULTRA_NIC_OFFSET);
-
-	if (ring_offset + count > ei_status.stop_page*256) {
-		/* We must wrap the input move. */
-		int semi_count = ei_status.stop_page*256 - ring_offset;
-		memcpy_fromio(skb->data, xfer_start, semi_count);
-		count -= semi_count;
-		memcpy_fromio(skb->data + semi_count, ei_status.mem + TX_PAGES * 256, count);
-	} else {
-		memcpy_fromio(skb->data, xfer_start, count);
-	}
-
-	outb(0x00, dev->base_addr - ULTRA_NIC_OFFSET);	/* Disable memory. */
-}
-
-static void
-ultra_block_output(struct net_device *dev, int count, const unsigned char *buf,
-				int start_page)
-{
-	void __iomem *shmem = ei_status.mem + ((start_page - START_PG)<<8);
-
-	/* Enable shared memory. */
-	outb(ULTRA_MEMENB, dev->base_addr - ULTRA_NIC_OFFSET);
-
-	memcpy_toio(shmem, buf, count);
-
-	outb(0x00, dev->base_addr - ULTRA_NIC_OFFSET); /* Disable memory. */
-}
-
-/* The identical operations for programmed I/O cards.
-   The PIO model is trivial to use: the 16 bit start address is written
-   byte-sequentially to IOPA, with no intervening I/O operations, and the
-   data is read or written to the IOPD data port.
-   The only potential complication is that the address register is shared
-   and must be always be rewritten between each read/write direction change.
-   This is no problem for us, as the 8390 code ensures that we are single
-   threaded. */
-static void ultra_pio_get_hdr(struct net_device *dev, struct e8390_pkt_hdr *hdr,
-						int ring_page)
-{
-	int ioaddr = dev->base_addr - ULTRA_NIC_OFFSET; /* ASIC addr */
-	outb(0x00, ioaddr + IOPA);	/* Set the address, LSB first. */
-	outb(ring_page, ioaddr + IOPA);
-	insw(ioaddr + IOPD, hdr, sizeof(struct e8390_pkt_hdr)>>1);
-}
-
-static void ultra_pio_input(struct net_device *dev, int count,
-						  struct sk_buff *skb, int ring_offset)
-{
-	int ioaddr = dev->base_addr - ULTRA_NIC_OFFSET; /* ASIC addr */
-    char *buf = skb->data;
-
-	/* For now set the address again, although it should already be correct. */
-	outb(ring_offset, ioaddr + IOPA);	/* Set the address, LSB first. */
-	outb(ring_offset >> 8, ioaddr + IOPA);
-	/* We know skbuffs are padded to at least word alignment. */
-	insw(ioaddr + IOPD, buf, (count+1)>>1);
-}
-static void ultra_pio_output(struct net_device *dev, int count,
-							const unsigned char *buf, const int start_page)
-{
-	int ioaddr = dev->base_addr - ULTRA_NIC_OFFSET; /* ASIC addr */
-	outb(0x00, ioaddr + IOPA);	/* Set the address, LSB first. */
-	outb(start_page, ioaddr + IOPA);
-	/* An extra odd byte is OK here as well. */
-	outsw(ioaddr + IOPD, buf, (count+1)>>1);
-}
-
-static int
-ultra_close_card(struct net_device *dev)
-{
-	int ioaddr = dev->base_addr - ULTRA_NIC_OFFSET; /* CMDREG */
-	struct ei_device *ei_local = netdev_priv(dev);
-
-	netif_stop_queue(dev);
-
-	netif_dbg(ei_local, ifdown, dev, "Shutting down ethercard.\n");
-
-	outb(0x00, ioaddr + 6);		/* Disable interrupts. */
-	free_irq(dev->irq, dev);
-
-	NS8390_init(dev, 0);
-
-	/* We should someday disable shared memory and change to 8-bit mode
-	   "just in case"... */
-
-	return 0;
-}
-
-
-#ifdef MODULE
-#define MAX_ULTRA_CARDS	4	/* Max number of Ultra cards per module */
-static struct net_device *dev_ultra[MAX_ULTRA_CARDS];
-static int io[MAX_ULTRA_CARDS];
-static int irq[MAX_ULTRA_CARDS];
-
-module_param_hw_array(io, int, ioport, NULL, 0);
-module_param_hw_array(irq, int, irq, NULL, 0);
-module_param_named(msg_enable, ultra_msg_enable, uint, 0444);
-MODULE_PARM_DESC(io, "I/O base address(es)");
-MODULE_PARM_DESC(irq, "IRQ number(s) (assigned)");
-MODULE_PARM_DESC(msg_enable, "Debug message level (see linux/netdevice.h for bitmap)");
-MODULE_DESCRIPTION("SMC Ultra/EtherEZ ISA/PnP Ethernet driver");
-MODULE_LICENSE("GPL");
-
-/* This is set up so that only a single autoprobe takes place per call.
-ISA device autoprobes on a running machine are not recommended. */
-static int __init ultra_init_module(void)
-{
-	struct net_device *dev;
-	int this_dev, found = 0;
-
-	for (this_dev = 0; this_dev < MAX_ULTRA_CARDS; this_dev++) {
-		if (io[this_dev] == 0)  {
-			if (this_dev != 0) break; /* only autoprobe 1st one */
-			printk(KERN_NOTICE "smc-ultra.c: Presently autoprobing (not recommended) for a single card.\n");
-		}
-		dev = alloc_ei_netdev();
-		if (!dev)
-			break;
-		dev->irq = irq[this_dev];
-		dev->base_addr = io[this_dev];
-		if (do_ultra_probe(dev) == 0) {
-			dev_ultra[found++] = dev;
-			continue;
-		}
-		free_netdev(dev);
-		printk(KERN_WARNING "smc-ultra.c: No SMC Ultra card found (i/o = 0x%x).\n", io[this_dev]);
-		break;
-	}
-	if (found)
-		return 0;
-	return -ENXIO;
-}
-module_init(ultra_init_module);
-
-static void cleanup_card(struct net_device *dev)
-{
-	/* NB: ultra_close_card() does free_irq */
-#ifdef __ISAPNP__
-	struct pnp_dev *idev = (struct pnp_dev *)ei_status.priv;
-	if (idev)
-		pnp_device_detach(idev);
-#endif
-	release_region(dev->base_addr - ULTRA_NIC_OFFSET, ULTRA_IO_EXTENT);
-	iounmap(ei_status.mem);
-}
-
-static void __exit ultra_cleanup_module(void)
-{
-	int this_dev;
-
-	for (this_dev = 0; this_dev < MAX_ULTRA_CARDS; this_dev++) {
-		struct net_device *dev = dev_ultra[this_dev];
-		if (dev) {
-			unregister_netdev(dev);
-			cleanup_card(dev);
-			free_netdev(dev);
-		}
-	}
-}
-module_exit(ultra_cleanup_module);
-#endif /* MODULE */

-- 
2.53.0


^ permalink raw reply related	[flat|nested] 28+ messages in thread

* [PATCH net 18/18] drivers: net: 8390: wd80x3: Remove this driver
  2026-04-21 19:31 [PATCH net 00/18] Remove a number of ISA and PCMCIA Ethernet drivers Andrew Lunn
                   ` (16 preceding siblings ...)
  2026-04-21 19:31 ` [PATCH net 17/18] drivers: net: 8390: ultra: " Andrew Lunn
@ 2026-04-21 19:31 ` Andrew Lunn
  2026-04-21 19:53 ` [PATCH net 00/18] Remove a number of ISA and PCMCIA Ethernet drivers Andrew Lunn
                   ` (3 subsequent siblings)
  21 siblings, 0 replies; 28+ messages in thread
From: Andrew Lunn @ 2026-04-21 19:31 UTC (permalink / raw)
  To: Andrew Lunn, David S. Miller, Eric Dumazet, Jakub Kicinski,
	Paolo Abeni, Simon Horman, Jonathan Corbet, Shuah Khan
  Cc: linux-kernel, netdev, linux-doc, Andrew Lunn

The wd80x3 was written by Donald Becker 1993 to 1994. It is an ISA
device, so unlikely to be used with modern kernels.

Signed-off-by: Andrew Lunn <andrew@lunn.ch>
---
 drivers/net/ethernet/8390/Kconfig  |  11 -
 drivers/net/ethernet/8390/Makefile |   1 -
 drivers/net/ethernet/8390/wd.c     | 575 -------------------------------------
 3 files changed, 587 deletions(-)

diff --git a/drivers/net/ethernet/8390/Kconfig b/drivers/net/ethernet/8390/Kconfig
index dd066b0a39d5..d2116d70ab5d 100644
--- a/drivers/net/ethernet/8390/Kconfig
+++ b/drivers/net/ethernet/8390/Kconfig
@@ -144,17 +144,6 @@ config STNIC
 
 	  If unsure, say N.
 
-config WD80x3
-	tristate "WD80*3 support"
-	depends on ISA
-	select NETDEV_LEGACY_INIT
-	select CRC32
-	help
-	  If you have a network (Ethernet) card of this type, say Y here.
-
-	  To compile this driver as a module, choose M here. The module
-	  will be called wd.
-
 config ZORRO8390
 	tristate "Zorro NS8390-based Ethernet support"
 	depends on ZORRO
diff --git a/drivers/net/ethernet/8390/Makefile b/drivers/net/ethernet/8390/Makefile
index 0afdccddda58..ad5145c30c85 100644
--- a/drivers/net/ethernet/8390/Makefile
+++ b/drivers/net/ethernet/8390/Makefile
@@ -12,6 +12,5 @@ obj-$(CONFIG_MCF8390) += mcf8390.o
 obj-$(CONFIG_NE2000) += ne.o 8390p.o
 obj-$(CONFIG_NE2K_PCI) += ne2k-pci.o 8390.o
 obj-$(CONFIG_STNIC) += stnic.o 8390.o
-obj-$(CONFIG_WD80x3) += wd.o 8390.o
 obj-$(CONFIG_XSURF100) += xsurf100.o
 obj-$(CONFIG_ZORRO8390) += zorro8390.o
diff --git a/drivers/net/ethernet/8390/wd.c b/drivers/net/ethernet/8390/wd.c
deleted file mode 100644
index ffd639477dfc..000000000000
--- a/drivers/net/ethernet/8390/wd.c
+++ /dev/null
@@ -1,575 +0,0 @@
-// SPDX-License-Identifier: GPL-1.0+
-/* wd.c: A WD80x3 ethernet driver for linux. */
-/*
-	Written 1993-94 by Donald Becker.
-
-	Copyright 1993 United States Government as represented by the
-	Director, National Security Agency.
-
-	The author may be reached as becker@scyld.com, or C/O
-	Scyld Computing Corporation
-	410 Severn Ave., Suite 210
-	Annapolis MD 21403
-
-	This is a driver for WD8003 and WD8013 "compatible" ethercards.
-
-	Thanks to Russ Nelson (nelson@crnwyr.com) for loaning me a WD8013.
-
-	Changelog:
-
-	Paul Gortmaker	: multiple card support for module users, support
-			  for non-standard memory sizes.
-
-
-*/
-
-static const char version[] =
-	"wd.c:v1.10 9/23/94 Donald Becker (becker@cesdis.gsfc.nasa.gov)\n";
-
-#include <linux/module.h>
-#include <linux/kernel.h>
-#include <linux/errno.h>
-#include <linux/string.h>
-#include <linux/init.h>
-#include <linux/interrupt.h>
-#include <linux/delay.h>
-#include <linux/netdevice.h>
-#include <linux/etherdevice.h>
-#include <net/Space.h>
-
-#include <asm/io.h>
-
-#include "8390.h"
-
-#define DRV_NAME "wd"
-
-/* A zero-terminated list of I/O addresses to be probed. */
-static unsigned int wd_portlist[] __initdata =
-{0x300, 0x280, 0x380, 0x240, 0};
-
-static int wd_probe1(struct net_device *dev, int ioaddr);
-
-static int wd_open(struct net_device *dev);
-static void wd_reset_8390(struct net_device *dev);
-static void wd_get_8390_hdr(struct net_device *dev, struct e8390_pkt_hdr *hdr,
-						int ring_page);
-static void wd_block_input(struct net_device *dev, int count,
-						  struct sk_buff *skb, int ring_offset);
-static void wd_block_output(struct net_device *dev, int count,
-							const unsigned char *buf, int start_page);
-static int wd_close(struct net_device *dev);
-
-static u32 wd_msg_enable;
-
-#define WD_START_PG		0x00	/* First page of TX buffer */
-#define WD03_STOP_PG	0x20	/* Last page +1 of RX ring */
-#define WD13_STOP_PG	0x40	/* Last page +1 of RX ring */
-
-#define WD_CMDREG		0		/* Offset to ASIC command register. */
-#define	 WD_RESET		0x80	/* Board reset, in WD_CMDREG. */
-#define	 WD_MEMENB		0x40	/* Enable the shared memory. */
-#define WD_CMDREG5		5		/* Offset to 16-bit-only ASIC register 5. */
-#define	 ISA16			0x80	/* Enable 16 bit access from the ISA bus. */
-#define	 NIC16			0x40	/* Enable 16 bit access from the 8390. */
-#define WD_NIC_OFFSET	16		/* Offset to the 8390 from the base_addr. */
-#define WD_IO_EXTENT	32
-
-
-/*	Probe for the WD8003 and WD8013.  These cards have the station
-	address PROM at I/O ports <base>+8 to <base>+13, with a checksum
-	following. A Soundblaster can have the same checksum as an WDethercard,
-	so we have an extra exclusionary check for it.
-
-	The wd_probe1() routine initializes the card and fills the
-	station address field. */
-
-static int __init do_wd_probe(struct net_device *dev)
-{
-	int i;
-	struct resource *r;
-	int base_addr = dev->base_addr;
-	int irq = dev->irq;
-	int mem_start = dev->mem_start;
-	int mem_end = dev->mem_end;
-
-	if (base_addr > 0x1ff) {	/* Check a user specified location. */
-		r = request_region(base_addr, WD_IO_EXTENT, "wd-probe");
-		if ( r == NULL)
-			return -EBUSY;
-		i = wd_probe1(dev, base_addr);
-		if (i != 0)
-			release_region(base_addr, WD_IO_EXTENT);
-		else
-			r->name = dev->name;
-		return i;
-	}
-	else if (base_addr != 0)	/* Don't probe at all. */
-		return -ENXIO;
-
-	for (i = 0; wd_portlist[i]; i++) {
-		int ioaddr = wd_portlist[i];
-		r = request_region(ioaddr, WD_IO_EXTENT, "wd-probe");
-		if (r == NULL)
-			continue;
-		if (wd_probe1(dev, ioaddr) == 0) {
-			r->name = dev->name;
-			return 0;
-		}
-		release_region(ioaddr, WD_IO_EXTENT);
-		dev->irq = irq;
-		dev->mem_start = mem_start;
-		dev->mem_end = mem_end;
-	}
-
-	return -ENODEV;
-}
-
-#ifndef MODULE
-struct net_device * __init wd_probe(int unit)
-{
-	struct net_device *dev = alloc_ei_netdev();
-	int err;
-
-	if (!dev)
-		return ERR_PTR(-ENOMEM);
-
-	sprintf(dev->name, "eth%d", unit);
-	netdev_boot_setup_check(dev);
-
-	err = do_wd_probe(dev);
-	if (err)
-		goto out;
-	return dev;
-out:
-	free_netdev(dev);
-	return ERR_PTR(err);
-}
-#endif
-
-static const struct net_device_ops wd_netdev_ops = {
-	.ndo_open		= wd_open,
-	.ndo_stop		= wd_close,
-	.ndo_start_xmit		= ei_start_xmit,
-	.ndo_tx_timeout		= ei_tx_timeout,
-	.ndo_get_stats		= ei_get_stats,
-	.ndo_set_rx_mode	= ei_set_multicast_list,
-	.ndo_validate_addr	= eth_validate_addr,
-	.ndo_set_mac_address 	= eth_mac_addr,
-#ifdef CONFIG_NET_POLL_CONTROLLER
-	.ndo_poll_controller 	= ei_poll,
-#endif
-};
-
-static int __init wd_probe1(struct net_device *dev, int ioaddr)
-{
-	int i;
-	int err;
-	int checksum = 0;
-	int ancient = 0;			/* An old card without config registers. */
-	int word16 = 0;				/* 0 = 8 bit, 1 = 16 bit */
-	u8 addr[ETH_ALEN];
-	const char *model_name;
-	static unsigned version_printed;
-	struct ei_device *ei_local = netdev_priv(dev);
-
-	for (i = 0; i < 8; i++)
-		checksum += inb(ioaddr + 8 + i);
-	if (inb(ioaddr + 8) == 0xff 	/* Extra check to avoid soundcard. */
-		|| inb(ioaddr + 9) == 0xff
-		|| (checksum & 0xff) != 0xFF)
-		return -ENODEV;
-
-	/* Check for semi-valid mem_start/end values if supplied. */
-	if ((dev->mem_start % 0x2000) || (dev->mem_end % 0x2000)) {
-		netdev_warn(dev,
-			    "wd.c: user supplied mem_start or mem_end not on 8kB boundary - ignored.\n");
-		dev->mem_start = 0;
-		dev->mem_end = 0;
-	}
-
-	if ((wd_msg_enable & NETIF_MSG_DRV) && (version_printed++ == 0))
-		netdev_info(dev, version);
-
-	for (i = 0; i < 6; i++)
-		addr[i] = inb(ioaddr + 8 + i);
-	eth_hw_addr_set(dev, addr);
-
-	netdev_info(dev, "WD80x3 at %#3x, %pM", ioaddr, dev->dev_addr);
-
-	/* The following PureData probe code was contributed by
-	   Mike Jagdis <jaggy@purplet.demon.co.uk>. Puredata does software
-	   configuration differently from others so we have to check for them.
-	   This detects an 8 bit, 16 bit or dumb (Toshiba, jumpered) card.
-	   */
-	if (inb(ioaddr+0) == 'P' && inb(ioaddr+1) == 'D') {
-		unsigned char reg5 = inb(ioaddr+5);
-
-		switch (inb(ioaddr+2)) {
-		case 0x03: word16 = 0; model_name = "PDI8023-8";	break;
-		case 0x05: word16 = 0; model_name = "PDUC8023";	break;
-		case 0x0a: word16 = 1; model_name = "PDI8023-16"; break;
-			/* Either 0x01 (dumb) or they've released a new version. */
-		default:	 word16 = 0; model_name = "PDI8023";	break;
-		}
-		dev->mem_start = ((reg5 & 0x1c) + 0xc0) << 12;
-		dev->irq = (reg5 & 0xe0) == 0xe0 ? 10 : (reg5 >> 5) + 1;
-	} else {								/* End of PureData probe */
-		/* This method of checking for a 16-bit board is borrowed from the
-		   we.c driver.  A simpler method is just to look in ASIC reg. 0x03.
-		   I'm comparing the two method in alpha test to make certain they
-		   return the same result. */
-		/* Check for the old 8 bit board - it has register 0/8 aliasing.
-		   Do NOT check i>=6 here -- it hangs the old 8003 boards! */
-		for (i = 0; i < 6; i++)
-			if (inb(ioaddr+i) != inb(ioaddr+8+i))
-				break;
-		if (i >= 6) {
-			ancient = 1;
-			model_name = "WD8003-old";
-			word16 = 0;
-		} else {
-			int tmp = inb(ioaddr+1); /* fiddle with 16bit bit */
-			outb( tmp ^ 0x01, ioaddr+1 ); /* attempt to clear 16bit bit */
-			if (((inb( ioaddr+1) & 0x01) == 0x01) /* A 16 bit card */
-				&& (tmp & 0x01) == 0x01	) {				/* In a 16 slot. */
-				int asic_reg5 = inb(ioaddr+WD_CMDREG5);
-				/* Magic to set ASIC to word-wide mode. */
-				outb( NIC16 | (asic_reg5&0x1f), ioaddr+WD_CMDREG5);
-				outb(tmp, ioaddr+1);
-				model_name = "WD8013";
-				word16 = 1;		/* We have a 16bit board here! */
-			} else {
-				model_name = "WD8003";
-				word16 = 0;
-			}
-			outb(tmp, ioaddr+1);			/* Restore original reg1 value. */
-		}
-#ifndef final_version
-		if ( !ancient && (inb(ioaddr+1) & 0x01) != (word16 & 0x01))
-			pr_cont("\nWD80?3: Bus width conflict, %d (probe) != %d (reg report).",
-				word16 ? 16 : 8,
-				(inb(ioaddr+1) & 0x01) ? 16 : 8);
-#endif
-	}
-
-#if defined(WD_SHMEM) && WD_SHMEM > 0x80000
-	/* Allow a compile-time override.	 */
-	dev->mem_start = WD_SHMEM;
-#else
-	if (dev->mem_start == 0) {
-		/* Sanity and old 8003 check */
-		int reg0 = inb(ioaddr);
-		if (reg0 == 0xff || reg0 == 0) {
-			/* Future plan: this could check a few likely locations first. */
-			dev->mem_start = 0xd0000;
-			pr_cont(" assigning address %#lx", dev->mem_start);
-		} else {
-			int high_addr_bits = inb(ioaddr+WD_CMDREG5) & 0x1f;
-			/* Some boards don't have the register 5 -- it returns 0xff. */
-			if (high_addr_bits == 0x1f || word16 == 0)
-				high_addr_bits = 0x01;
-			dev->mem_start = ((reg0&0x3f) << 13) + (high_addr_bits << 19);
-		}
-	}
-#endif
-
-	/* The 8390 isn't at the base address -- the ASIC regs are there! */
-	dev->base_addr = ioaddr+WD_NIC_OFFSET;
-
-	if (dev->irq < 2) {
-		static const int irqmap[] = {9, 3, 5, 7, 10, 11, 15, 4};
-		int reg1 = inb(ioaddr+1);
-		int reg4 = inb(ioaddr+4);
-		if (ancient || reg1 == 0xff) {	/* Ack!! No way to read the IRQ! */
-			short nic_addr = ioaddr+WD_NIC_OFFSET;
-			unsigned long irq_mask;
-
-			/* We have an old-style ethercard that doesn't report its IRQ
-			   line.  Do autoirq to find the IRQ line. Note that this IS NOT
-			   a reliable way to trigger an interrupt. */
-			outb_p(E8390_NODMA + E8390_STOP, nic_addr);
-			outb(0x00, nic_addr+EN0_IMR);	/* Disable all intrs. */
-
-			irq_mask = probe_irq_on();
-			outb_p(0xff, nic_addr + EN0_IMR);	/* Enable all interrupts. */
-			outb_p(0x00, nic_addr + EN0_RCNTLO);
-			outb_p(0x00, nic_addr + EN0_RCNTHI);
-			outb(E8390_RREAD+E8390_START, nic_addr); /* Trigger it... */
-			mdelay(20);
-			dev->irq = probe_irq_off(irq_mask);
-
-			outb_p(0x00, nic_addr+EN0_IMR);	/* Mask all intrs. again. */
-
-			if (wd_msg_enable & NETIF_MSG_PROBE)
-				pr_cont(" autoirq is %d", dev->irq);
-			if (dev->irq < 2)
-				dev->irq = word16 ? 10 : 5;
-		} else
-			dev->irq = irqmap[((reg4 >> 5) & 0x03) + (reg1 & 0x04)];
-	} else if (dev->irq == 2)		/* Fixup bogosity: IRQ2 is really IRQ9 */
-		dev->irq = 9;
-
-	/* Snarf the interrupt now.  There's no point in waiting since we cannot
-	   share and the board will usually be enabled. */
-	i = request_irq(dev->irq, ei_interrupt, 0, DRV_NAME, dev);
-	if (i) {
-		pr_cont(" unable to get IRQ %d.\n", dev->irq);
-		return i;
-	}
-
-	/* OK, were are certain this is going to work.  Setup the device. */
-	ei_status.name = model_name;
-	ei_status.word16 = word16;
-	ei_status.tx_start_page = WD_START_PG;
-	ei_status.rx_start_page = WD_START_PG + TX_PAGES;
-
-	/* Don't map in the shared memory until the board is actually opened. */
-
-	/* Some cards (eg WD8003EBT) can be jumpered for more (32k!) memory. */
-	if (dev->mem_end != 0) {
-		ei_status.stop_page = (dev->mem_end - dev->mem_start)/256;
-		ei_status.priv = dev->mem_end - dev->mem_start;
-	} else {
-		ei_status.stop_page = word16 ? WD13_STOP_PG : WD03_STOP_PG;
-		dev->mem_end = dev->mem_start + (ei_status.stop_page - WD_START_PG)*256;
-		ei_status.priv = (ei_status.stop_page - WD_START_PG)*256;
-	}
-
-	ei_status.mem = ioremap(dev->mem_start, ei_status.priv);
-	if (!ei_status.mem) {
-		free_irq(dev->irq, dev);
-		return -ENOMEM;
-	}
-
-	pr_cont(" %s, IRQ %d, shared memory at %#lx-%#lx.\n",
-		model_name, dev->irq, dev->mem_start, dev->mem_end-1);
-
-	ei_status.reset_8390 = wd_reset_8390;
-	ei_status.block_input = wd_block_input;
-	ei_status.block_output = wd_block_output;
-	ei_status.get_8390_hdr = wd_get_8390_hdr;
-
-	dev->netdev_ops = &wd_netdev_ops;
-	NS8390_init(dev, 0);
-	ei_local->msg_enable = wd_msg_enable;
-
-#if 1
-	/* Enable interrupt generation on softconfig cards -- M.U */
-	/* .. but possibly potentially unsafe - Donald */
-	if (inb(ioaddr+14) & 0x20)
-		outb(inb(ioaddr+4)|0x80, ioaddr+4);
-#endif
-
-	err = register_netdev(dev);
-	if (err) {
-		free_irq(dev->irq, dev);
-		iounmap(ei_status.mem);
-	}
-	return err;
-}
-
-static int
-wd_open(struct net_device *dev)
-{
-  int ioaddr = dev->base_addr - WD_NIC_OFFSET; /* WD_CMDREG */
-
-  /* Map in the shared memory. Always set register 0 last to remain
-	 compatible with very old boards. */
-  ei_status.reg0 = ((dev->mem_start>>13) & 0x3f) | WD_MEMENB;
-  ei_status.reg5 = ((dev->mem_start>>19) & 0x1f) | NIC16;
-
-  if (ei_status.word16)
-	  outb(ei_status.reg5, ioaddr+WD_CMDREG5);
-  outb(ei_status.reg0, ioaddr); /* WD_CMDREG */
-
-  return ei_open(dev);
-}
-
-static void
-wd_reset_8390(struct net_device *dev)
-{
-	int wd_cmd_port = dev->base_addr - WD_NIC_OFFSET; /* WD_CMDREG */
-	struct ei_device *ei_local = netdev_priv(dev);
-
-	outb(WD_RESET, wd_cmd_port);
-	netif_dbg(ei_local, hw, dev, "resetting the WD80x3 t=%lu...\n",
-		  jiffies);
-	ei_status.txing = 0;
-
-	/* Set up the ASIC registers, just in case something changed them. */
-	outb((((dev->mem_start>>13) & 0x3f)|WD_MEMENB), wd_cmd_port);
-	if (ei_status.word16)
-		outb(NIC16 | ((dev->mem_start>>19) & 0x1f), wd_cmd_port+WD_CMDREG5);
-
-	netif_dbg(ei_local, hw, dev, "reset done\n");
-}
-
-/* Grab the 8390 specific header. Similar to the block_input routine, but
-   we don't need to be concerned with ring wrap as the header will be at
-   the start of a page, so we optimize accordingly. */
-
-static void
-wd_get_8390_hdr(struct net_device *dev, struct e8390_pkt_hdr *hdr, int ring_page)
-{
-
-	int wd_cmdreg = dev->base_addr - WD_NIC_OFFSET; /* WD_CMDREG */
-	void __iomem *hdr_start = ei_status.mem + ((ring_page - WD_START_PG)<<8);
-
-	/* We'll always get a 4 byte header read followed by a packet read, so
-	   we enable 16 bit mode before the header, and disable after the body. */
-	if (ei_status.word16)
-		outb(ISA16 | ei_status.reg5, wd_cmdreg+WD_CMDREG5);
-
-#ifdef __BIG_ENDIAN
-	/* Officially this is what we are doing, but the readl() is faster */
-	/* unfortunately it isn't endian aware of the struct               */
-	memcpy_fromio(hdr, hdr_start, sizeof(struct e8390_pkt_hdr));
-	hdr->count = le16_to_cpu(hdr->count);
-#else
-	((unsigned int*)hdr)[0] = readl(hdr_start);
-#endif
-}
-
-/* Block input and output are easy on shared memory ethercards, and trivial
-   on the Western digital card where there is no choice of how to do it.
-   The only complications are that the ring buffer wraps, and need to map
-   switch between 8- and 16-bit modes. */
-
-static void
-wd_block_input(struct net_device *dev, int count, struct sk_buff *skb, int ring_offset)
-{
-	int wd_cmdreg = dev->base_addr - WD_NIC_OFFSET; /* WD_CMDREG */
-	unsigned long offset = ring_offset - (WD_START_PG<<8);
-	void __iomem *xfer_start = ei_status.mem + offset;
-
-	if (offset + count > ei_status.priv) {
-		/* We must wrap the input move. */
-		int semi_count = ei_status.priv - offset;
-		memcpy_fromio(skb->data, xfer_start, semi_count);
-		count -= semi_count;
-		memcpy_fromio(skb->data + semi_count, ei_status.mem + TX_PAGES * 256, count);
-	} else {
-		/* Packet is in one chunk -- we can copy + cksum. */
-		memcpy_fromio(skb->data, xfer_start, count);
-	}
-
-	/* Turn off 16 bit access so that reboot works.	 ISA brain-damage */
-	if (ei_status.word16)
-		outb(ei_status.reg5, wd_cmdreg+WD_CMDREG5);
-}
-
-static void
-wd_block_output(struct net_device *dev, int count, const unsigned char *buf,
-				int start_page)
-{
-	int wd_cmdreg = dev->base_addr - WD_NIC_OFFSET; /* WD_CMDREG */
-	void __iomem *shmem = ei_status.mem + ((start_page - WD_START_PG)<<8);
-
-
-	if (ei_status.word16) {
-		/* Turn on and off 16 bit access so that reboot works. */
-		outb(ISA16 | ei_status.reg5, wd_cmdreg+WD_CMDREG5);
-		memcpy_toio(shmem, buf, count);
-		outb(ei_status.reg5, wd_cmdreg+WD_CMDREG5);
-	} else
-		memcpy_toio(shmem, buf, count);
-}
-
-
-static int
-wd_close(struct net_device *dev)
-{
-	int wd_cmdreg = dev->base_addr - WD_NIC_OFFSET; /* WD_CMDREG */
-	struct ei_device *ei_local = netdev_priv(dev);
-
-	netif_dbg(ei_local, ifdown, dev, "Shutting down ethercard.\n");
-	ei_close(dev);
-
-	/* Change from 16-bit to 8-bit shared memory so reboot works. */
-	if (ei_status.word16)
-		outb(ei_status.reg5, wd_cmdreg + WD_CMDREG5 );
-
-	/* And disable the shared memory. */
-	outb(ei_status.reg0 & ~WD_MEMENB, wd_cmdreg);
-
-	return 0;
-}
-
-
-#ifdef MODULE
-#define MAX_WD_CARDS	4	/* Max number of wd cards per module */
-static struct net_device *dev_wd[MAX_WD_CARDS];
-static int io[MAX_WD_CARDS];
-static int irq[MAX_WD_CARDS];
-static int mem[MAX_WD_CARDS];
-static int mem_end[MAX_WD_CARDS];	/* for non std. mem size */
-
-module_param_hw_array(io, int, ioport, NULL, 0);
-module_param_hw_array(irq, int, irq, NULL, 0);
-module_param_hw_array(mem, int, iomem, NULL, 0);
-module_param_hw_array(mem_end, int, iomem, NULL, 0);
-module_param_named(msg_enable, wd_msg_enable, uint, 0444);
-MODULE_PARM_DESC(io, "I/O base address(es)");
-MODULE_PARM_DESC(irq, "IRQ number(s) (ignored for PureData boards)");
-MODULE_PARM_DESC(mem, "memory base address(es)(ignored for PureData boards)");
-MODULE_PARM_DESC(mem_end, "memory end address(es)");
-MODULE_PARM_DESC(msg_enable, "Debug message level (see linux/netdevice.h for bitmap)");
-MODULE_DESCRIPTION("ISA Western Digital wd8003/wd8013 ; SMC Elite, Elite16 ethernet driver");
-MODULE_LICENSE("GPL");
-
-/* This is set up so that only a single autoprobe takes place per call.
-ISA device autoprobes on a running machine are not recommended. */
-
-static int __init wd_init_module(void)
-{
-	struct net_device *dev;
-	int this_dev, found = 0;
-
-	for (this_dev = 0; this_dev < MAX_WD_CARDS; this_dev++) {
-		if (io[this_dev] == 0)  {
-			if (this_dev != 0) break; /* only autoprobe 1st one */
-			printk(KERN_NOTICE "wd.c: Presently autoprobing (not recommended) for a single card.\n");
-		}
-		dev = alloc_ei_netdev();
-		if (!dev)
-			break;
-		dev->irq = irq[this_dev];
-		dev->base_addr = io[this_dev];
-		dev->mem_start = mem[this_dev];
-		dev->mem_end = mem_end[this_dev];
-		if (do_wd_probe(dev) == 0) {
-			dev_wd[found++] = dev;
-			continue;
-		}
-		free_netdev(dev);
-		printk(KERN_WARNING "wd.c: No wd80x3 card found (i/o = 0x%x).\n", io[this_dev]);
-		break;
-	}
-	if (found)
-		return 0;
-	return -ENXIO;
-}
-module_init(wd_init_module);
-
-static void cleanup_card(struct net_device *dev)
-{
-	free_irq(dev->irq, dev);
-	release_region(dev->base_addr - WD_NIC_OFFSET, WD_IO_EXTENT);
-	iounmap(ei_status.mem);
-}
-
-static void __exit wd_cleanup_module(void)
-{
-	int this_dev;
-
-	for (this_dev = 0; this_dev < MAX_WD_CARDS; this_dev++) {
-		struct net_device *dev = dev_wd[this_dev];
-		if (dev) {
-			unregister_netdev(dev);
-			cleanup_card(dev);
-			free_netdev(dev);
-		}
-	}
-}
-module_exit(wd_cleanup_module);
-#endif /* MODULE */

-- 
2.53.0


^ permalink raw reply related	[flat|nested] 28+ messages in thread

* Re: [PATCH net 00/18] Remove a number of ISA and PCMCIA Ethernet drivers
  2026-04-21 19:31 [PATCH net 00/18] Remove a number of ISA and PCMCIA Ethernet drivers Andrew Lunn
                   ` (17 preceding siblings ...)
  2026-04-21 19:31 ` [PATCH net 18/18] drivers: net: 8390: wd80x3: " Andrew Lunn
@ 2026-04-21 19:53 ` Andrew Lunn
  2026-04-22  1:39   ` Jakub Kicinski
  2026-04-21 20:44 ` Byron Stanoszek
                   ` (2 subsequent siblings)
  21 siblings, 1 reply; 28+ messages in thread
From: Andrew Lunn @ 2026-04-21 19:53 UTC (permalink / raw)
  To: Andrew Lunn, David S. Miller, Eric Dumazet, Jakub Kicinski,
	Paolo Abeni, Simon Horman, Jonathan Corbet, Shuah Khan
  Cc: linux-kernel, netdev, linux-doc

On Tue, Apr 21, 2026 at 02:31:03PM -0500, Andrew Lunn wrote:
> These old drivers have not been much of a Maintenance burden until
> recently. Now there are more newbies using AI and fuzzers finding
> issues, resulting in more work for Maintainers. Fixing these old
> drivers make little sense, if it is not clear they have users.
> 
> These are all ISA and PCMCIA Ethernet devices, mostly from the last
> century, a couple from 2001 or 2002. It seems unlikely they are still
> used. However, remove them one patch at a time so they can be brought
> back if somebody still has the hardware, runs modern kernels and wants
> to take up the roll of driver Maintainer.
> 
> Signed-off-by: Andrew Lunn <andrew@lunn.ch>
> ---
> Andrew Lunn (18):

There should be 18 patches in this series, but it seems like b4 send
and exim are not working together too tell and have truncated it to 10
:-(

I maybe have a fix, but i will wait the usual 24 hours before
retrying.

>       drivers: net: 3com: 3c509: Remove this driver
>       drivers: net: 3com: 3c515: Remove this driver
>       drivers: net: 3com: 3c574: Remove this driver
>       drivers: net: 3com: 3c589: Remove this driver
>       drivers: net: 3com: 3c59x: Remove this driver
>       drivers: net: amd: Remove hplance and mvme147
>       drivers: net: amd: lance: Remove this driver
>       drivers: net: amd: nmclan: Remove this driver
>       drivers: net: smsc: smc9194: Remove this driver
>       drivers: net: smsc: smc91c92: Remove this driver
>       drivers: net: cirrus: cs89x0: Remove this driver
>       drivers: net: cirrus: mac89x0: Remove this driver
>       drivers: net: fujitsu: fmvj18x: Remove this driver
>       drivers: net: xircom: xirc2ps: Remove this driver
>       drivers: net: 8390: AX88190: Remove this driver
>       drivers: net: 8390: pcnet: Remove this driver
>       drivers: net: 8390: ultra: Remove this driver
>       drivers: net: 8390: wd80x3: Remove this driver

You should be able to tell from this what is missing, and i would like
to remove.

    Andrew

---
pw-bot: cr

^ permalink raw reply	[flat|nested] 28+ messages in thread

* Re: [PATCH net 00/18] Remove a number of ISA and PCMCIA Ethernet drivers
  2026-04-21 19:31 [PATCH net 00/18] Remove a number of ISA and PCMCIA Ethernet drivers Andrew Lunn
                   ` (18 preceding siblings ...)
  2026-04-21 19:53 ` [PATCH net 00/18] Remove a number of ISA and PCMCIA Ethernet drivers Andrew Lunn
@ 2026-04-21 20:44 ` Byron Stanoszek
  2026-04-21 22:30   ` Andrew Lunn
  2026-04-21 22:03 ` Daniel Palmer
  2026-04-22  5:42 ` John Paul Adrian Glaubitz
  21 siblings, 1 reply; 28+ messages in thread
From: Byron Stanoszek @ 2026-04-21 20:44 UTC (permalink / raw)
  To: Andrew Lunn
  Cc: Andrew Lunn, David S. Miller, Eric Dumazet, Jakub Kicinski,
	Paolo Abeni, Simon Horman, Jonathan Corbet, Shuah Khan,
	linux-kernel, netdev, linux-doc

On Tue, 21 Apr 2026, Andrew Lunn wrote:

> These old drivers have not been much of a Maintenance burden until
> recently. Now there are more newbies using AI and fuzzers finding
> issues, resulting in more work for Maintainers. Fixing these old
> drivers make little sense, if it is not clear they have users.
>
>      drivers: net: 3com: 3c59x: Remove this driver

Hi Andrew,

I happen to still use this driver on several hundred industrial PC
installations that were outfitted with 3com 3C905-B & CX cards 15+ years ago.
The old hardware still runs, therefore those cards haven't needed to be
replaced. I keep these systems up to date with the latest Linux kernel roughly
once per year.

I understand the maintenance burden, but I would be delighted to continue
receiving bug fixes for this driver via the mainline Linux kernel if you are
still willing to continue to support it.

Thanks and best regards,
  -Byron


^ permalink raw reply	[flat|nested] 28+ messages in thread

* Re: [PATCH net 12/18] drivers: net: cirrus: mac89x0: Remove this driver
  2026-04-21 19:31 ` [PATCH net 12/18] drivers: net: cirrus: mac89x0: " Andrew Lunn
@ 2026-04-21 21:34   ` Daniel Palmer
  0 siblings, 0 replies; 28+ messages in thread
From: Daniel Palmer @ 2026-04-21 21:34 UTC (permalink / raw)
  To: Andrew Lunn
  Cc: Andrew Lunn, David S. Miller, Eric Dumazet, Jakub Kicinski,
	Paolo Abeni, Simon Horman, Jonathan Corbet, Shuah Khan,
	linux-kernel, netdev, linux-doc

Hi Andrew,

On Wed, 22 Apr 2026 at 05:01, Andrew Lunn <andrew@lunn.ch> wrote:
>
> The mac89x0 was written by Russell Nelson in 1996. It is an MAC
> device, so unlikely to be used with modern kernels.
>
> Signed-off-by: Andrew Lunn <andrew@lunn.ch>

I think I might be using this with a mac and I'm running mainline.
FWIW the m68k mac stuff still works perfectly fine with modern kernels
and there are people using it.

^ permalink raw reply	[flat|nested] 28+ messages in thread

* Re: [PATCH net 06/18] drivers: net: amd: Remove hplance and mvme147
  2026-04-21 19:31 ` [PATCH net 06/18] drivers: net: amd: Remove hplance and mvme147 Andrew Lunn
@ 2026-04-21 21:38   ` Daniel Palmer
  0 siblings, 0 replies; 28+ messages in thread
From: Daniel Palmer @ 2026-04-21 21:38 UTC (permalink / raw)
  To: Andrew Lunn
  Cc: Andrew Lunn, David S. Miller, Eric Dumazet, Jakub Kicinski,
	Paolo Abeni, Simon Horman, Jonathan Corbet, Shuah Khan,
	linux-kernel, netdev, linux-doc

Hi Andrew,

On Wed, 22 Apr 2026 at 04:39, Andrew Lunn <andrew@lunn.ch> wrote:
>
> These drivers use the 7990 core with wrappers for the HP300 and
> Motorola MVME147 SBC circa 1998. It is unlikely they are used with a
> modern kernel.

I have an MVME147 blinking away running mainline using the mvme147 driver.
I think some of these need to be CC'd to the specific arch lists so
the few people using them get a chance to pipe up.
I think I'm the last person to have touched the mvme147, I don't mind
being a maintainer for it.

Cheers,

Daniel

^ permalink raw reply	[flat|nested] 28+ messages in thread

* Re: [PATCH net 00/18] Remove a number of ISA and PCMCIA Ethernet drivers
  2026-04-21 19:31 [PATCH net 00/18] Remove a number of ISA and PCMCIA Ethernet drivers Andrew Lunn
                   ` (19 preceding siblings ...)
  2026-04-21 20:44 ` Byron Stanoszek
@ 2026-04-21 22:03 ` Daniel Palmer
  2026-04-22  5:42 ` John Paul Adrian Glaubitz
  21 siblings, 0 replies; 28+ messages in thread
From: Daniel Palmer @ 2026-04-21 22:03 UTC (permalink / raw)
  To: Andrew Lunn
  Cc: Andrew Lunn, David S. Miller, Eric Dumazet, Jakub Kicinski,
	Paolo Abeni, Simon Horman, Jonathan Corbet, Shuah Khan,
	linux-kernel, netdev, linux-doc

Hi Andrew,

On Wed, 22 Apr 2026 at 04:32, Andrew Lunn <andrew@lunn.ch> wrote:
>
> These old drivers have not been much of a Maintenance burden until
> recently. Now there are more newbies using AI and fuzzers finding
> issues, resulting in more work for Maintainers. Fixing these old
> drivers make little sense, if it is not clear they have users.
>
> These are all ISA and PCMCIA Ethernet devices, mostly from the last
> century, a couple from 2001 or 2002. It seems unlikely they are still
> used. However, remove them one patch at a time so they can be brought
> back if somebody still has the hardware, runs modern kernels and wants
> to take up the roll of driver Maintainer.
>
> Signed-off-by: Andrew Lunn <andrew@lunn.ch>

I replied to the single patches for the ones I think I have off the
top of my head but maybe I have a few other these.
I think on x86 people running machines that have real ISA slots and a
modern kernel are going to be fairly rare but I think there is non-x86
hardware that has some of these and people are still using them.
I think the pcnet one is used in some PC emulators too?

This is just my opinion but I think it'd be good to give people a bit
more time before they get removed. I thought I was the only person
using the 68000 (a cpu from 1979) code in the m68k tree for years
until out of the blue a month or so ago someone popped up and asked if
I could fix a bug in it since I'd fixed a different bug in it
recently.

Maybe we could add a special thing in the maintainers for "this is
code only crazy people use" and have a rule to ignore untested AI
generated patches for it? :)

Thanks,

Daniel

^ permalink raw reply	[flat|nested] 28+ messages in thread

* Re: [PATCH net 00/18] Remove a number of ISA and PCMCIA Ethernet drivers
  2026-04-21 20:44 ` Byron Stanoszek
@ 2026-04-21 22:30   ` Andrew Lunn
  2026-04-22  3:03     ` Byron Stanoszek
  0 siblings, 1 reply; 28+ messages in thread
From: Andrew Lunn @ 2026-04-21 22:30 UTC (permalink / raw)
  To: Byron Stanoszek
  Cc: Andrew Lunn, David S. Miller, Eric Dumazet, Jakub Kicinski,
	Paolo Abeni, Simon Horman, Jonathan Corbet, Shuah Khan,
	linux-kernel, netdev, linux-doc

On Tue, Apr 21, 2026 at 04:44:11PM -0400, Byron Stanoszek wrote:
> On Tue, 21 Apr 2026, Andrew Lunn wrote:
> 
> > These old drivers have not been much of a Maintenance burden until
> > recently. Now there are more newbies using AI and fuzzers finding
> > issues, resulting in more work for Maintainers. Fixing these old
> > drivers make little sense, if it is not clear they have users.
> > 
> >      drivers: net: 3com: 3c59x: Remove this driver
> 
> Hi Andrew,
> 
> I happen to still use this driver on several hundred industrial PC
> installations that were outfitted with 3com 3C905-B & CX cards 15+ years ago.
> The old hardware still runs, therefore those cards haven't needed to be
> replaced. I keep these systems up to date with the latest Linux kernel roughly
> once per year.

So 6.18? 6.12?

> I understand the maintenance burden, but I would be delighted to continue
> receiving bug fixes for this driver via the mainline Linux kernel if you are
> still willing to continue to support it.

Looking at the history of 3c59x.c i see:

Date:   Tue Jan 6 10:47:21 2026 +0100

    net: 3com: 3c59x: fix possible null dereference in vortex_probe1()

Date:   Wed Jan 3 13:09:23 2018 -0500

    3c59x: fix missing dma_mapping_error check and bad ring refill logic

Date:   Thu Feb 25 13:02:50 2016 -0500

    3c59x: mask LAST_FRAG bit from length field in ring

Date:   Sun Feb 28 16:49:29 2016 +0900

    3c59x: Ensure to apply the expires time

Date:   Wed Jan 13 12:43:54 2016 -0500

    3c59x: fix another page map/single unmap imbalance

Date:   Wed Jan 13 12:43:53 2016 -0500

    3c59x: balance page maps and unmaps

Date:   Tue Jul 7 20:48:55 2015 +0200

    3c59x: Fix shared IRQ handling

So it looks like it was been pretty stable since 2016.

Could you live with v6.18, which has an expected EOL of December 2028?
If you are only updating once per year, security is not an issue, you
just want stability.

In fact, you might actually find stability starts going down in the
next couple of years, maybe sooner. What we expect to happen soon is a
lot more AI generated 'bug fixes', probably from newbies who are
unable to evaluate if the AI is generated good fixes or bad fixes, or
fixes which are theoretical rather than actual bugs etc. We netdev
Maintainers are already seeing the number of patches going up, and are
expecting to get overloaded. Which means quality will go down. We have
also seen the AI generated fixes are indiscriminate, neither the AI,
nor the human, care, or even look, to see if the driver is from the
last century. We Maintainers however would prefer spending our time on
drivers from the last ten years, maybe newer. So patches for these
older drivers is going to get less review, and bad patches will slip
through.

By dropping them for the current HEAD, we are reducing our surface
area. It will be interesting to see if the AI patches are only for
HEAD, or they start going back to older kernels to find 'bugs'.

However, just because a driver has gone from HEAD, it does not really
prevent us from taking patches for stable. But we Maintainers want to
avoid doing the triage work, figuring out good from bad.

We have not discussed it as a Maintainer team, but one thing which
might work is we add a entry for 3c59x.c in MAINTAINERS, in stable,
pointing to you. You can then validate patches, and tell us if they
are O.K. to queue for stable.

    Andrew

^ permalink raw reply	[flat|nested] 28+ messages in thread

* Re: [PATCH net 00/18] Remove a number of ISA and PCMCIA Ethernet drivers
  2026-04-21 19:53 ` [PATCH net 00/18] Remove a number of ISA and PCMCIA Ethernet drivers Andrew Lunn
@ 2026-04-22  1:39   ` Jakub Kicinski
  0 siblings, 0 replies; 28+ messages in thread
From: Jakub Kicinski @ 2026-04-22  1:39 UTC (permalink / raw)
  To: Andrew Lunn
  Cc: Andrew Lunn, David S. Miller, Eric Dumazet, Paolo Abeni,
	Simon Horman, Jonathan Corbet, Shuah Khan, linux-kernel, netdev,
	linux-doc

On Tue, 21 Apr 2026 21:53:38 +0200 Andrew Lunn wrote:
> There should be 18 patches in this series, but it seems like b4 send
> and exim are not working together too tell and have truncated it to 10
> :-(

Looks like they ended up coming thru and got nom-nomed by the AIs,
which flagged some omissions (in docs mostly). So I'll keep the series
as "changes requested".

Please feel free to ignore the 24h limit for this. We need the
deletions shipped to Linus by Thu.

^ permalink raw reply	[flat|nested] 28+ messages in thread

* Re: [PATCH net 00/18] Remove a number of ISA and PCMCIA Ethernet drivers
  2026-04-21 22:30   ` Andrew Lunn
@ 2026-04-22  3:03     ` Byron Stanoszek
  0 siblings, 0 replies; 28+ messages in thread
From: Byron Stanoszek @ 2026-04-22  3:03 UTC (permalink / raw)
  To: Andrew Lunn
  Cc: Andrew Lunn, David S. Miller, Eric Dumazet, Jakub Kicinski,
	Paolo Abeni, Simon Horman, Jonathan Corbet, Shuah Khan,
	linux-kernel, netdev, linux-doc

On Wed, 22 Apr 2026, Andrew Lunn wrote:
>
> Could you live with v6.18, which has an expected EOL of December 2028?
> If you are only updating once per year, security is not an issue, you
> just want stability.

I could for the time being, but this hasn't worked for me in the past. Usually
what happens is the PC breaks down, and the customer swaps in a new
backplane+SBC and moves all their PCI cards over. I then find I need to update
the kernel just to get the Intel DRM to work properly on the new CPU. Some of
these systems were installed back in the Linux 2.6 era, so I've gone through
several "Intel DRM not working" steps ever since CPUs started getting
integrated graphics. 2028 will come fast.

One thing worth mentioning though--these 3com cards are all PCI. They still
work perfectly fine on the newest hardware. Your subject says you're dropping
old ISA and PCMCIA support, so I don't fully understand why you included 3c59x
in the mix. Phoronix picked up this patch
(https://www.phoronix.com/news/Linux-Old-Network-AI), and according to the
comments, there are still people who use these cards (3c905s were very popular
back in the day). Would you be willing to leave this driver in mainline?

> However, just because a driver has gone from HEAD, it does not really
> prevent us from taking patches for stable. But we Maintainers want to
> avoid doing the triage work, figuring out good from bad.
>
> We have not discussed it as a Maintainer team, but one thing which
> might work is we add a entry for 3c59x.c in MAINTAINERS, in stable,
> pointing to you. You can then validate patches, and tell us if they
> are O.K. to queue for stable.

I'm sorry, but I already have enough going on to take up another maintainer
role. However, I thought Greg had some rule in place that said the stable
branches don't get any patches applied unless they also hit mainline. Is there
some exception for drivers in stable that don't exist in mainline anymore?

Thanks,
  -Byron


^ permalink raw reply	[flat|nested] 28+ messages in thread

* Re: [PATCH net 00/18] Remove a number of ISA and PCMCIA Ethernet drivers
  2026-04-21 19:31 [PATCH net 00/18] Remove a number of ISA and PCMCIA Ethernet drivers Andrew Lunn
                   ` (20 preceding siblings ...)
  2026-04-21 22:03 ` Daniel Palmer
@ 2026-04-22  5:42 ` John Paul Adrian Glaubitz
  21 siblings, 0 replies; 28+ messages in thread
From: John Paul Adrian Glaubitz @ 2026-04-22  5:42 UTC (permalink / raw)
  To: Andrew Lunn, Andrew Lunn, David S. Miller, Eric Dumazet,
	Jakub Kicinski, Paolo Abeni, Simon Horman, Jonathan Corbet,
	Shuah Khan
  Cc: linux-kernel, netdev, linux-doc

Hi Andrew,

On Tue, 2026-04-21 at 14:31 -0500, Andrew Lunn wrote:
> These old drivers have not been much of a Maintenance burden until
> recently. Now there are more newbies using AI and fuzzers finding
> issues, resulting in more work for Maintainers. Fixing these old
> drivers make little sense, if it is not clear they have users.
> 
> These are all ISA and PCMCIA Ethernet devices, mostly from the last
> century, a couple from 2001 or 2002. It seems unlikely they are still
> used. However, remove them one patch at a time so they can be brought
> back if somebody still has the hardware, runs modern kernels and wants
> to take up the roll of driver Maintainer.

They might still be used for retro-computing on various non-x86 computers
such as Alphas, older SPARC systems, PA-RISC and 68000 systems. Please don't
assume that every computer is just an x86 computer.

As for the AI-generated bug reports, I assume this will settle down sooner
or later when reporters realize not every issue is being addressed. Anyone
who is still using this old hardware won't be using them on machines directly
connected to the internet.

So, why bother? Just ignore those bug reports.

Adrian

-- 
 .''`.  John Paul Adrian Glaubitz
: :' :  Debian Developer
`. `'   Physicist
  `-    GPG: 62FF 8A75 84E0 2956 9546  0006 7426 3B37 F5B5 F913

^ permalink raw reply	[flat|nested] 28+ messages in thread

end of thread, other threads:[~2026-04-22  5:42 UTC | newest]

Thread overview: 28+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2026-04-21 19:31 [PATCH net 00/18] Remove a number of ISA and PCMCIA Ethernet drivers Andrew Lunn
2026-04-21 19:31 ` [PATCH net 01/18] drivers: net: 3com: 3c509: Remove this driver Andrew Lunn
2026-04-21 19:31 ` [PATCH net 02/18] drivers: net: 3com: 3c515: " Andrew Lunn
2026-04-21 19:31 ` [PATCH net 03/18] drivers: net: 3com: 3c574: " Andrew Lunn
2026-04-21 19:31 ` [PATCH net 04/18] drivers: net: 3com: 3c589: " Andrew Lunn
2026-04-21 19:31 ` [PATCH net 05/18] drivers: net: 3com: 3c59x: " Andrew Lunn
2026-04-21 19:31 ` [PATCH net 06/18] drivers: net: amd: Remove hplance and mvme147 Andrew Lunn
2026-04-21 21:38   ` Daniel Palmer
2026-04-21 19:31 ` [PATCH net 07/18] drivers: net: amd: lance: Remove this driver Andrew Lunn
2026-04-21 19:31 ` [PATCH net 08/18] drivers: net: amd: nmclan: " Andrew Lunn
2026-04-21 19:31 ` [PATCH net 09/18] drivers: net: smsc: smc9194: " Andrew Lunn
2026-04-21 19:31 ` [PATCH net 10/18] drivers: net: smsc: smc91c92: " Andrew Lunn
2026-04-21 19:31 ` [PATCH net 11/18] drivers: net: cirrus: cs89x0: " Andrew Lunn
2026-04-21 19:31 ` [PATCH net 12/18] drivers: net: cirrus: mac89x0: " Andrew Lunn
2026-04-21 21:34   ` Daniel Palmer
2026-04-21 19:31 ` [PATCH net 13/18] drivers: net: fujitsu: fmvj18x: " Andrew Lunn
2026-04-21 19:31 ` [PATCH net 14/18] drivers: net: xircom: xirc2ps: " Andrew Lunn
2026-04-21 19:31 ` [PATCH net 15/18] drivers: net: 8390: AX88190: " Andrew Lunn
2026-04-21 19:31 ` [PATCH net 16/18] drivers: net: 8390: pcnet: " Andrew Lunn
2026-04-21 19:31 ` [PATCH net 17/18] drivers: net: 8390: ultra: " Andrew Lunn
2026-04-21 19:31 ` [PATCH net 18/18] drivers: net: 8390: wd80x3: " Andrew Lunn
2026-04-21 19:53 ` [PATCH net 00/18] Remove a number of ISA and PCMCIA Ethernet drivers Andrew Lunn
2026-04-22  1:39   ` Jakub Kicinski
2026-04-21 20:44 ` Byron Stanoszek
2026-04-21 22:30   ` Andrew Lunn
2026-04-22  3:03     ` Byron Stanoszek
2026-04-21 22:03 ` Daniel Palmer
2026-04-22  5:42 ` John Paul Adrian Glaubitz

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox