162306a36Sopenharmony_ci// SPDX-License-Identifier: GPL-1.0+
262306a36Sopenharmony_ci/* ne.c: A general non-shared-memory NS8390 ethernet driver for linux. */
362306a36Sopenharmony_ci/*
462306a36Sopenharmony_ci    Written 1992-94 by Donald Becker.
562306a36Sopenharmony_ci
662306a36Sopenharmony_ci    Copyright 1993 United States Government as represented by the
762306a36Sopenharmony_ci    Director, National Security Agency.
862306a36Sopenharmony_ci
962306a36Sopenharmony_ci    The author may be reached as becker@scyld.com, or C/O
1062306a36Sopenharmony_ci    Scyld Computing Corporation, 410 Severn Ave., Suite 210, Annapolis MD 21403
1162306a36Sopenharmony_ci
1262306a36Sopenharmony_ci    This driver should work with many programmed-I/O 8390-based ethernet
1362306a36Sopenharmony_ci    boards.  Currently it supports the NE1000, NE2000, many clones,
1462306a36Sopenharmony_ci    and some Cabletron products.
1562306a36Sopenharmony_ci
1662306a36Sopenharmony_ci    Changelog:
1762306a36Sopenharmony_ci
1862306a36Sopenharmony_ci    Paul Gortmaker	: use ENISR_RDC to monitor Tx PIO uploads, made
1962306a36Sopenharmony_ci			  sanity checks and bad clone support optional.
2062306a36Sopenharmony_ci    Paul Gortmaker	: new reset code, reset card after probe at boot.
2162306a36Sopenharmony_ci    Paul Gortmaker	: multiple card support for module users.
2262306a36Sopenharmony_ci    Paul Gortmaker	: Support for PCI ne2k clones, similar to lance.c
2362306a36Sopenharmony_ci    Paul Gortmaker	: Allow users with bad cards to avoid full probe.
2462306a36Sopenharmony_ci    Paul Gortmaker	: PCI probe changes, more PCI cards supported.
2562306a36Sopenharmony_ci    rjohnson@analogic.com : Changed init order so an interrupt will only
2662306a36Sopenharmony_ci    occur after memory is allocated for dev->priv. Deallocated memory
2762306a36Sopenharmony_ci    last in cleanup_modue()
2862306a36Sopenharmony_ci    Richard Guenther    : Added support for ISAPnP cards
2962306a36Sopenharmony_ci    Paul Gortmaker	: Discontinued PCI support - use ne2k-pci.c instead.
3062306a36Sopenharmony_ci    Hayato Fujiwara	: Add m32r support.
3162306a36Sopenharmony_ci
3262306a36Sopenharmony_ci*/
3362306a36Sopenharmony_ci
3462306a36Sopenharmony_ci/* Routines for the NatSemi-based designs (NE[12]000). */
3562306a36Sopenharmony_ci
3662306a36Sopenharmony_cistatic const char version1[] =
3762306a36Sopenharmony_ci"ne.c:v1.10 9/23/94 Donald Becker (becker@scyld.com)\n";
3862306a36Sopenharmony_cistatic const char version2[] =
3962306a36Sopenharmony_ci"Last modified Nov 1, 2000 by Paul Gortmaker\n";
4062306a36Sopenharmony_ci
4162306a36Sopenharmony_ci
4262306a36Sopenharmony_ci#include <linux/module.h>
4362306a36Sopenharmony_ci#include <linux/kernel.h>
4462306a36Sopenharmony_ci#include <linux/errno.h>
4562306a36Sopenharmony_ci#include <linux/isapnp.h>
4662306a36Sopenharmony_ci#include <linux/init.h>
4762306a36Sopenharmony_ci#include <linux/interrupt.h>
4862306a36Sopenharmony_ci#include <linux/delay.h>
4962306a36Sopenharmony_ci#include <linux/netdevice.h>
5062306a36Sopenharmony_ci#include <linux/etherdevice.h>
5162306a36Sopenharmony_ci#include <linux/jiffies.h>
5262306a36Sopenharmony_ci#include <linux/platform_device.h>
5362306a36Sopenharmony_ci#include <net/Space.h>
5462306a36Sopenharmony_ci
5562306a36Sopenharmony_ci#include <asm/io.h>
5662306a36Sopenharmony_ci
5762306a36Sopenharmony_ci#include "8390.h"
5862306a36Sopenharmony_ci
5962306a36Sopenharmony_ci#define DRV_NAME "ne"
6062306a36Sopenharmony_ci
6162306a36Sopenharmony_ci/* Some defines that people can play with if so inclined. */
6262306a36Sopenharmony_ci
6362306a36Sopenharmony_ci/* Do we support clones that don't adhere to 14,15 of the SAprom ? */
6462306a36Sopenharmony_ci#define SUPPORT_NE_BAD_CLONES
6562306a36Sopenharmony_ci/* 0xbad = bad sig or no reset ack */
6662306a36Sopenharmony_ci#define BAD 0xbad
6762306a36Sopenharmony_ci
6862306a36Sopenharmony_ci#define MAX_NE_CARDS	4	/* Max number of NE cards per module */
6962306a36Sopenharmony_cistatic struct platform_device *pdev_ne[MAX_NE_CARDS];
7062306a36Sopenharmony_cistatic int io[MAX_NE_CARDS];
7162306a36Sopenharmony_cistatic int irq[MAX_NE_CARDS];
7262306a36Sopenharmony_cistatic int bad[MAX_NE_CARDS];
7362306a36Sopenharmony_cistatic u32 ne_msg_enable;
7462306a36Sopenharmony_ci
7562306a36Sopenharmony_ci#ifdef MODULE
7662306a36Sopenharmony_cimodule_param_hw_array(io, int, ioport, NULL, 0);
7762306a36Sopenharmony_cimodule_param_hw_array(irq, int, irq, NULL, 0);
7862306a36Sopenharmony_cimodule_param_array(bad, int, NULL, 0);
7962306a36Sopenharmony_cimodule_param_named(msg_enable, ne_msg_enable, uint, 0444);
8062306a36Sopenharmony_ciMODULE_PARM_DESC(io, "I/O base address(es),required");
8162306a36Sopenharmony_ciMODULE_PARM_DESC(irq, "IRQ number(s)");
8262306a36Sopenharmony_ciMODULE_PARM_DESC(bad, "Accept card(s) with bad signatures");
8362306a36Sopenharmony_ciMODULE_PARM_DESC(msg_enable, "Debug message level (see linux/netdevice.h for bitmap)");
8462306a36Sopenharmony_ciMODULE_DESCRIPTION("NE1000/NE2000 ISA/PnP Ethernet driver");
8562306a36Sopenharmony_ciMODULE_LICENSE("GPL");
8662306a36Sopenharmony_ci#endif /* MODULE */
8762306a36Sopenharmony_ci
8862306a36Sopenharmony_ci/* Do we perform extra sanity checks on stuff ? */
8962306a36Sopenharmony_ci/* #define NE_SANITY_CHECK */
9062306a36Sopenharmony_ci
9162306a36Sopenharmony_ci/* Do we implement the read before write bugfix ? */
9262306a36Sopenharmony_ci/* #define NE_RW_BUGFIX */
9362306a36Sopenharmony_ci
9462306a36Sopenharmony_ci/* Do we have a non std. amount of memory? (in units of 256 byte pages) */
9562306a36Sopenharmony_ci/* #define PACKETBUF_MEMSIZE	0x40 */
9662306a36Sopenharmony_ci
9762306a36Sopenharmony_ci/* This is set up so that no ISA autoprobe takes place. We can't guarantee
9862306a36Sopenharmony_cithat the ne2k probe is the last 8390 based probe to take place (as it
9962306a36Sopenharmony_ciis at boot) and so the probe will get confused by any other 8390 cards.
10062306a36Sopenharmony_ciISA device autoprobes on a running machine are not recommended anyway. */
10162306a36Sopenharmony_ci#if !defined(MODULE) && defined(CONFIG_ISA)
10262306a36Sopenharmony_ci/* Do we need a portlist for the ISA auto-probe ? */
10362306a36Sopenharmony_ci#define NEEDS_PORTLIST
10462306a36Sopenharmony_ci#endif
10562306a36Sopenharmony_ci
10662306a36Sopenharmony_ci/* A zero-terminated list of I/O addresses to be probed at boot. */
10762306a36Sopenharmony_ci#ifdef NEEDS_PORTLIST
10862306a36Sopenharmony_cistatic unsigned int netcard_portlist[] __initdata = {
10962306a36Sopenharmony_ci	0x300, 0x280, 0x320, 0x340, 0x360, 0x380, 0
11062306a36Sopenharmony_ci};
11162306a36Sopenharmony_ci#endif
11262306a36Sopenharmony_ci
11362306a36Sopenharmony_cistatic struct isapnp_device_id isapnp_clone_list[] __initdata = {
11462306a36Sopenharmony_ci	{	ISAPNP_CARD_ID('A','X','E',0x2011),
11562306a36Sopenharmony_ci		ISAPNP_VENDOR('A','X','E'), ISAPNP_FUNCTION(0x2011),
11662306a36Sopenharmony_ci		(long) "NetGear EA201" },
11762306a36Sopenharmony_ci	{	ISAPNP_ANY_ID, ISAPNP_ANY_ID,
11862306a36Sopenharmony_ci		ISAPNP_VENDOR('E','D','I'), ISAPNP_FUNCTION(0x0216),
11962306a36Sopenharmony_ci		(long) "NN NE2000" },
12062306a36Sopenharmony_ci	{	ISAPNP_ANY_ID, ISAPNP_ANY_ID,
12162306a36Sopenharmony_ci		ISAPNP_VENDOR('P','N','P'), ISAPNP_FUNCTION(0x80d6),
12262306a36Sopenharmony_ci		(long) "Generic PNP" },
12362306a36Sopenharmony_ci	{ }	/* terminate list */
12462306a36Sopenharmony_ci};
12562306a36Sopenharmony_ci
12662306a36Sopenharmony_ciMODULE_DEVICE_TABLE(isapnp, isapnp_clone_list);
12762306a36Sopenharmony_ci
12862306a36Sopenharmony_ci#ifdef SUPPORT_NE_BAD_CLONES
12962306a36Sopenharmony_ci/* A list of bad clones that we none-the-less recognize. */
13062306a36Sopenharmony_cistatic struct { const char *name8, *name16; unsigned char SAprefix[4];}
13162306a36Sopenharmony_cibad_clone_list[] __initdata = {
13262306a36Sopenharmony_ci    {"DE100", "DE200", {0x00, 0xDE, 0x01,}},
13362306a36Sopenharmony_ci    {"DE120", "DE220", {0x00, 0x80, 0xc8,}},
13462306a36Sopenharmony_ci    {"DFI1000", "DFI2000", {'D', 'F', 'I',}}, /* Original, eh?  */
13562306a36Sopenharmony_ci    {"EtherNext UTP8", "EtherNext UTP16", {0x00, 0x00, 0x79}},
13662306a36Sopenharmony_ci    {"NE1000","NE2000-invalid", {0x00, 0x00, 0xd8}}, /* Ancient real NE1000. */
13762306a36Sopenharmony_ci    {"NN1000", "NN2000",  {0x08, 0x03, 0x08}}, /* Outlaw no-name clone. */
13862306a36Sopenharmony_ci    {"4-DIM8","4-DIM16", {0x00,0x00,0x4d,}},  /* Outlaw 4-Dimension cards. */
13962306a36Sopenharmony_ci    {"Con-Intl_8", "Con-Intl_16", {0x00, 0x00, 0x24}}, /* Connect Int'nl */
14062306a36Sopenharmony_ci    {"ET-100","ET-200", {0x00, 0x45, 0x54}}, /* YANG and YA clone */
14162306a36Sopenharmony_ci    {"COMPEX","COMPEX16",{0x00,0x80,0x48}}, /* Broken ISA Compex cards */
14262306a36Sopenharmony_ci    {"E-LAN100", "E-LAN200", {0x00, 0x00, 0x5d}}, /* Broken ne1000 clones */
14362306a36Sopenharmony_ci    {"PCM-4823", "PCM-4823", {0x00, 0xc0, 0x6c}}, /* Broken Advantech MoBo */
14462306a36Sopenharmony_ci    {"REALTEK", "RTL8019", {0x00, 0x00, 0xe8}}, /* no-name with Realtek chip */
14562306a36Sopenharmony_ci#ifdef CONFIG_MACH_TX49XX
14662306a36Sopenharmony_ci    {"RBHMA4X00-RTL8019", "RBHMA4X00-RTL8019", {0x00, 0x60, 0x0a}},  /* Toshiba built-in */
14762306a36Sopenharmony_ci#endif
14862306a36Sopenharmony_ci    {"LCS-8834", "LCS-8836", {0x04, 0x04, 0x37}}, /* ShinyNet (SET) */
14962306a36Sopenharmony_ci    {NULL,}
15062306a36Sopenharmony_ci};
15162306a36Sopenharmony_ci#endif
15262306a36Sopenharmony_ci
15362306a36Sopenharmony_ci/* ---- No user-serviceable parts below ---- */
15462306a36Sopenharmony_ci
15562306a36Sopenharmony_ci#define NE_BASE	 (dev->base_addr)
15662306a36Sopenharmony_ci#define NE_CMD	 	0x00
15762306a36Sopenharmony_ci#define NE_DATAPORT	0x10	/* NatSemi-defined port window offset. */
15862306a36Sopenharmony_ci#define NE_RESET	0x1f	/* Issue a read to reset, a write to clear. */
15962306a36Sopenharmony_ci#define NE_IO_EXTENT	0x20
16062306a36Sopenharmony_ci
16162306a36Sopenharmony_ci#define NE1SM_START_PG	0x20	/* First page of TX buffer */
16262306a36Sopenharmony_ci#define NE1SM_STOP_PG 	0x40	/* Last page +1 of RX ring */
16362306a36Sopenharmony_ci#define NESM_START_PG	0x40	/* First page of TX buffer */
16462306a36Sopenharmony_ci#define NESM_STOP_PG	0x80	/* Last page +1 of RX ring */
16562306a36Sopenharmony_ci
16662306a36Sopenharmony_ci#if defined(CONFIG_MACH_TX49XX)
16762306a36Sopenharmony_ci#  define DCR_VAL 0x48		/* 8-bit mode */
16862306a36Sopenharmony_ci#elif defined(CONFIG_ATARI)	/* 8-bit mode on Atari, normal on Q40 */
16962306a36Sopenharmony_ci#  define DCR_VAL (MACH_IS_ATARI ? 0x48 : 0x49)
17062306a36Sopenharmony_ci#else
17162306a36Sopenharmony_ci#  define DCR_VAL 0x49
17262306a36Sopenharmony_ci#endif
17362306a36Sopenharmony_ci
17462306a36Sopenharmony_cistatic int ne_probe1(struct net_device *dev, unsigned long ioaddr);
17562306a36Sopenharmony_cistatic int ne_probe_isapnp(struct net_device *dev);
17662306a36Sopenharmony_ci
17762306a36Sopenharmony_cistatic void ne_reset_8390(struct net_device *dev);
17862306a36Sopenharmony_cistatic void ne_get_8390_hdr(struct net_device *dev, struct e8390_pkt_hdr *hdr,
17962306a36Sopenharmony_ci			  int ring_page);
18062306a36Sopenharmony_cistatic void ne_block_input(struct net_device *dev, int count,
18162306a36Sopenharmony_ci			  struct sk_buff *skb, int ring_offset);
18262306a36Sopenharmony_cistatic void ne_block_output(struct net_device *dev, const int count,
18362306a36Sopenharmony_ci		const unsigned char *buf, const int start_page);
18462306a36Sopenharmony_ci
18562306a36Sopenharmony_ci
18662306a36Sopenharmony_ci/*  Probe for various non-shared-memory ethercards.
18762306a36Sopenharmony_ci
18862306a36Sopenharmony_ci   NEx000-clone boards have a Station Address PROM (SAPROM) in the packet
18962306a36Sopenharmony_ci   buffer memory space.  NE2000 clones have 0x57,0x57 in bytes 0x0e,0x0f of
19062306a36Sopenharmony_ci   the SAPROM, while other supposed NE2000 clones must be detected by their
19162306a36Sopenharmony_ci   SA prefix.
19262306a36Sopenharmony_ci
19362306a36Sopenharmony_ci   Reading the SAPROM from a word-wide card with the 8390 set in byte-wide
19462306a36Sopenharmony_ci   mode results in doubled values, which can be detected and compensated for.
19562306a36Sopenharmony_ci
19662306a36Sopenharmony_ci   The probe is also responsible for initializing the card and filling
19762306a36Sopenharmony_ci   in the 'dev' and 'ei_status' structures.
19862306a36Sopenharmony_ci
19962306a36Sopenharmony_ci   We use the minimum memory size for some ethercard product lines, iff we can't
20062306a36Sopenharmony_ci   distinguish models.  You can increase the packet buffer size by setting
20162306a36Sopenharmony_ci   PACKETBUF_MEMSIZE.  Reported Cabletron packet buffer locations are:
20262306a36Sopenharmony_ci	E1010   starts at 0x100 and ends at 0x2000.
20362306a36Sopenharmony_ci	E1010-x starts at 0x100 and ends at 0x8000. ("-x" means "more memory")
20462306a36Sopenharmony_ci	E2010	 starts at 0x100 and ends at 0x4000.
20562306a36Sopenharmony_ci	E2010-x starts at 0x100 and ends at 0xffff.  */
20662306a36Sopenharmony_ci
20762306a36Sopenharmony_cistatic int __init do_ne_probe(struct net_device *dev)
20862306a36Sopenharmony_ci{
20962306a36Sopenharmony_ci	unsigned long base_addr = dev->base_addr;
21062306a36Sopenharmony_ci#ifdef NEEDS_PORTLIST
21162306a36Sopenharmony_ci	int orig_irq = dev->irq;
21262306a36Sopenharmony_ci#endif
21362306a36Sopenharmony_ci
21462306a36Sopenharmony_ci	/* First check any supplied i/o locations. User knows best. <cough> */
21562306a36Sopenharmony_ci	if (base_addr > 0x1ff) {	/* Check a single specified location. */
21662306a36Sopenharmony_ci		int ret = ne_probe1(dev, base_addr);
21762306a36Sopenharmony_ci		if (ret)
21862306a36Sopenharmony_ci			netdev_warn(dev, "ne.c: No NE*000 card found at "
21962306a36Sopenharmony_ci				    "i/o = %#lx\n", base_addr);
22062306a36Sopenharmony_ci		return ret;
22162306a36Sopenharmony_ci	}
22262306a36Sopenharmony_ci	else if (base_addr != 0)	/* Don't probe at all. */
22362306a36Sopenharmony_ci		return -ENXIO;
22462306a36Sopenharmony_ci
22562306a36Sopenharmony_ci	/* Then look for any installed ISAPnP clones */
22662306a36Sopenharmony_ci	if (isapnp_present() && (ne_probe_isapnp(dev) == 0))
22762306a36Sopenharmony_ci		return 0;
22862306a36Sopenharmony_ci
22962306a36Sopenharmony_ci#ifdef NEEDS_PORTLIST
23062306a36Sopenharmony_ci	/* Last resort. The semi-risky ISA auto-probe. */
23162306a36Sopenharmony_ci	for (base_addr = 0; netcard_portlist[base_addr] != 0; base_addr++) {
23262306a36Sopenharmony_ci		int ioaddr = netcard_portlist[base_addr];
23362306a36Sopenharmony_ci		dev->irq = orig_irq;
23462306a36Sopenharmony_ci		if (ne_probe1(dev, ioaddr) == 0)
23562306a36Sopenharmony_ci			return 0;
23662306a36Sopenharmony_ci	}
23762306a36Sopenharmony_ci#endif
23862306a36Sopenharmony_ci
23962306a36Sopenharmony_ci	return -ENODEV;
24062306a36Sopenharmony_ci}
24162306a36Sopenharmony_ci
24262306a36Sopenharmony_cistatic int __init ne_probe_isapnp(struct net_device *dev)
24362306a36Sopenharmony_ci{
24462306a36Sopenharmony_ci	int i;
24562306a36Sopenharmony_ci
24662306a36Sopenharmony_ci	for (i = 0; isapnp_clone_list[i].vendor != 0; i++) {
24762306a36Sopenharmony_ci		struct pnp_dev *idev = NULL;
24862306a36Sopenharmony_ci
24962306a36Sopenharmony_ci		while ((idev = pnp_find_dev(NULL,
25062306a36Sopenharmony_ci					    isapnp_clone_list[i].vendor,
25162306a36Sopenharmony_ci					    isapnp_clone_list[i].function,
25262306a36Sopenharmony_ci					    idev))) {
25362306a36Sopenharmony_ci			/* Avoid already found cards from previous calls */
25462306a36Sopenharmony_ci			if (pnp_device_attach(idev) < 0)
25562306a36Sopenharmony_ci				continue;
25662306a36Sopenharmony_ci			if (pnp_activate_dev(idev) < 0) {
25762306a36Sopenharmony_ci			      	pnp_device_detach(idev);
25862306a36Sopenharmony_ci			      	continue;
25962306a36Sopenharmony_ci			}
26062306a36Sopenharmony_ci			/* if no io and irq, search for next */
26162306a36Sopenharmony_ci			if (!pnp_port_valid(idev, 0) || !pnp_irq_valid(idev, 0)) {
26262306a36Sopenharmony_ci				pnp_device_detach(idev);
26362306a36Sopenharmony_ci				continue;
26462306a36Sopenharmony_ci			}
26562306a36Sopenharmony_ci			/* found it */
26662306a36Sopenharmony_ci			dev->base_addr = pnp_port_start(idev, 0);
26762306a36Sopenharmony_ci			dev->irq = pnp_irq(idev, 0);
26862306a36Sopenharmony_ci			netdev_info(dev,
26962306a36Sopenharmony_ci				    "ne.c: ISAPnP reports %s at i/o %#lx, irq %d.\n",
27062306a36Sopenharmony_ci				    (char *) isapnp_clone_list[i].driver_data,
27162306a36Sopenharmony_ci				    dev->base_addr, dev->irq);
27262306a36Sopenharmony_ci			if (ne_probe1(dev, dev->base_addr) != 0) {	/* Shouldn't happen. */
27362306a36Sopenharmony_ci				netdev_err(dev,
27462306a36Sopenharmony_ci					   "ne.c: Probe of ISAPnP card at %#lx failed.\n",
27562306a36Sopenharmony_ci					   dev->base_addr);
27662306a36Sopenharmony_ci				pnp_device_detach(idev);
27762306a36Sopenharmony_ci				return -ENXIO;
27862306a36Sopenharmony_ci			}
27962306a36Sopenharmony_ci			ei_status.priv = (unsigned long)idev;
28062306a36Sopenharmony_ci			break;
28162306a36Sopenharmony_ci		}
28262306a36Sopenharmony_ci		if (!idev)
28362306a36Sopenharmony_ci			continue;
28462306a36Sopenharmony_ci		return 0;
28562306a36Sopenharmony_ci	}
28662306a36Sopenharmony_ci
28762306a36Sopenharmony_ci	return -ENODEV;
28862306a36Sopenharmony_ci}
28962306a36Sopenharmony_ci
29062306a36Sopenharmony_cistatic int __init ne_probe1(struct net_device *dev, unsigned long ioaddr)
29162306a36Sopenharmony_ci{
29262306a36Sopenharmony_ci	int i;
29362306a36Sopenharmony_ci	unsigned char SA_prom[32];
29462306a36Sopenharmony_ci	int wordlength = 2;
29562306a36Sopenharmony_ci	const char *name = NULL;
29662306a36Sopenharmony_ci	int start_page, stop_page;
29762306a36Sopenharmony_ci	int neX000, ctron, copam, bad_card;
29862306a36Sopenharmony_ci	int reg0, ret;
29962306a36Sopenharmony_ci	static unsigned version_printed;
30062306a36Sopenharmony_ci	struct ei_device *ei_local = netdev_priv(dev);
30162306a36Sopenharmony_ci
30262306a36Sopenharmony_ci	if (!request_region(ioaddr, NE_IO_EXTENT, DRV_NAME))
30362306a36Sopenharmony_ci		return -EBUSY;
30462306a36Sopenharmony_ci
30562306a36Sopenharmony_ci	reg0 = inb_p(ioaddr);
30662306a36Sopenharmony_ci	if (reg0 == 0xFF) {
30762306a36Sopenharmony_ci		ret = -ENODEV;
30862306a36Sopenharmony_ci		goto err_out;
30962306a36Sopenharmony_ci	}
31062306a36Sopenharmony_ci
31162306a36Sopenharmony_ci	/* Do a preliminary verification that we have a 8390. */
31262306a36Sopenharmony_ci	{
31362306a36Sopenharmony_ci		int regd;
31462306a36Sopenharmony_ci		outb_p(E8390_NODMA+E8390_PAGE1+E8390_STOP, ioaddr + E8390_CMD);
31562306a36Sopenharmony_ci		regd = inb_p(ioaddr + 0x0d);
31662306a36Sopenharmony_ci		outb_p(0xff, ioaddr + 0x0d);
31762306a36Sopenharmony_ci		outb_p(E8390_NODMA+E8390_PAGE0, ioaddr + E8390_CMD);
31862306a36Sopenharmony_ci		inb_p(ioaddr + EN0_COUNTER0); /* Clear the counter by reading. */
31962306a36Sopenharmony_ci		if (inb_p(ioaddr + EN0_COUNTER0) != 0) {
32062306a36Sopenharmony_ci			outb_p(reg0, ioaddr);
32162306a36Sopenharmony_ci			outb_p(regd, ioaddr + 0x0d);	/* Restore the old values. */
32262306a36Sopenharmony_ci			ret = -ENODEV;
32362306a36Sopenharmony_ci			goto err_out;
32462306a36Sopenharmony_ci		}
32562306a36Sopenharmony_ci	}
32662306a36Sopenharmony_ci
32762306a36Sopenharmony_ci	if ((ne_msg_enable & NETIF_MSG_DRV) && (version_printed++ == 0))
32862306a36Sopenharmony_ci		netdev_info(dev, "%s%s", version1, version2);
32962306a36Sopenharmony_ci
33062306a36Sopenharmony_ci	netdev_info(dev, "NE*000 ethercard probe at %#3lx:", ioaddr);
33162306a36Sopenharmony_ci
33262306a36Sopenharmony_ci	/* A user with a poor card that fails to ack the reset, or that
33362306a36Sopenharmony_ci	   does not have a valid 0x57,0x57 signature can still use this
33462306a36Sopenharmony_ci	   without having to recompile. Specifying an i/o address along
33562306a36Sopenharmony_ci	   with an otherwise unused dev->mem_end value of "0xBAD" will
33662306a36Sopenharmony_ci	   cause the driver to skip these parts of the probe. */
33762306a36Sopenharmony_ci
33862306a36Sopenharmony_ci	bad_card = ((dev->base_addr != 0) && (dev->mem_end == BAD));
33962306a36Sopenharmony_ci
34062306a36Sopenharmony_ci	/* Reset card. Who knows what dain-bramaged state it was left in. */
34162306a36Sopenharmony_ci
34262306a36Sopenharmony_ci	{
34362306a36Sopenharmony_ci		unsigned long reset_start_time = jiffies;
34462306a36Sopenharmony_ci
34562306a36Sopenharmony_ci		/* DON'T change these to inb_p/outb_p or reset will fail on clones. */
34662306a36Sopenharmony_ci		outb(inb(ioaddr + NE_RESET), ioaddr + NE_RESET);
34762306a36Sopenharmony_ci
34862306a36Sopenharmony_ci		while ((inb_p(ioaddr + EN0_ISR) & ENISR_RESET) == 0)
34962306a36Sopenharmony_ci		if (time_after(jiffies, reset_start_time + 2*HZ/100)) {
35062306a36Sopenharmony_ci			if (bad_card) {
35162306a36Sopenharmony_ci				pr_cont(" (warning: no reset ack)");
35262306a36Sopenharmony_ci				break;
35362306a36Sopenharmony_ci			} else {
35462306a36Sopenharmony_ci				pr_cont(" not found (no reset ack).\n");
35562306a36Sopenharmony_ci				ret = -ENODEV;
35662306a36Sopenharmony_ci				goto err_out;
35762306a36Sopenharmony_ci			}
35862306a36Sopenharmony_ci		}
35962306a36Sopenharmony_ci
36062306a36Sopenharmony_ci		outb_p(0xff, ioaddr + EN0_ISR);		/* Ack all intr. */
36162306a36Sopenharmony_ci	}
36262306a36Sopenharmony_ci
36362306a36Sopenharmony_ci	/* Read the 16 bytes of station address PROM.
36462306a36Sopenharmony_ci	   We must first initialize registers, similar to NS8390p_init(eifdev, 0).
36562306a36Sopenharmony_ci	   We can't reliably read the SAPROM address without this.
36662306a36Sopenharmony_ci	   (I learned the hard way!). */
36762306a36Sopenharmony_ci	{
36862306a36Sopenharmony_ci		struct {unsigned char value, offset; } program_seq[] =
36962306a36Sopenharmony_ci		{
37062306a36Sopenharmony_ci			{E8390_NODMA+E8390_PAGE0+E8390_STOP, E8390_CMD}, /* Select page 0*/
37162306a36Sopenharmony_ci			{0x48,	EN0_DCFG},	/* Set byte-wide (0x48) access. */
37262306a36Sopenharmony_ci			{0x00,	EN0_RCNTLO},	/* Clear the count regs. */
37362306a36Sopenharmony_ci			{0x00,	EN0_RCNTHI},
37462306a36Sopenharmony_ci			{0x00,	EN0_IMR},	/* Mask completion irq. */
37562306a36Sopenharmony_ci			{0xFF,	EN0_ISR},
37662306a36Sopenharmony_ci			{E8390_RXOFF, EN0_RXCR},	/* 0x20  Set to monitor */
37762306a36Sopenharmony_ci			{E8390_TXOFF, EN0_TXCR},	/* 0x02  and loopback mode. */
37862306a36Sopenharmony_ci			{32,	EN0_RCNTLO},
37962306a36Sopenharmony_ci			{0x00,	EN0_RCNTHI},
38062306a36Sopenharmony_ci			{0x00,	EN0_RSARLO},	/* DMA starting at 0x0000. */
38162306a36Sopenharmony_ci			{0x00,	EN0_RSARHI},
38262306a36Sopenharmony_ci			{E8390_RREAD+E8390_START, E8390_CMD},
38362306a36Sopenharmony_ci		};
38462306a36Sopenharmony_ci
38562306a36Sopenharmony_ci		for (i = 0; i < ARRAY_SIZE(program_seq); i++)
38662306a36Sopenharmony_ci			outb_p(program_seq[i].value, ioaddr + program_seq[i].offset);
38762306a36Sopenharmony_ci
38862306a36Sopenharmony_ci	}
38962306a36Sopenharmony_ci	for(i = 0; i < 32 /*sizeof(SA_prom)*/; i+=2) {
39062306a36Sopenharmony_ci		SA_prom[i] = inb(ioaddr + NE_DATAPORT);
39162306a36Sopenharmony_ci		SA_prom[i+1] = inb(ioaddr + NE_DATAPORT);
39262306a36Sopenharmony_ci		if (SA_prom[i] != SA_prom[i+1])
39362306a36Sopenharmony_ci			wordlength = 1;
39462306a36Sopenharmony_ci	}
39562306a36Sopenharmony_ci
39662306a36Sopenharmony_ci	if (wordlength == 2)
39762306a36Sopenharmony_ci	{
39862306a36Sopenharmony_ci		for (i = 0; i < 16; i++)
39962306a36Sopenharmony_ci			SA_prom[i] = SA_prom[i+i];
40062306a36Sopenharmony_ci		/* We must set the 8390 for word mode. */
40162306a36Sopenharmony_ci		outb_p(DCR_VAL, ioaddr + EN0_DCFG);
40262306a36Sopenharmony_ci		start_page = NESM_START_PG;
40362306a36Sopenharmony_ci
40462306a36Sopenharmony_ci		/*
40562306a36Sopenharmony_ci		 * Realtek RTL8019AS datasheet says that the PSTOP register
40662306a36Sopenharmony_ci		 * shouldn't exceed 0x60 in 8-bit mode.
40762306a36Sopenharmony_ci		 * This chip can be identified by reading the signature from
40862306a36Sopenharmony_ci		 * the  remote byte count registers (otherwise write-only)...
40962306a36Sopenharmony_ci		 */
41062306a36Sopenharmony_ci		if ((DCR_VAL & 0x01) == 0 &&		/* 8-bit mode */
41162306a36Sopenharmony_ci		    inb(ioaddr + EN0_RCNTLO) == 0x50 &&
41262306a36Sopenharmony_ci		    inb(ioaddr + EN0_RCNTHI) == 0x70)
41362306a36Sopenharmony_ci			stop_page = 0x60;
41462306a36Sopenharmony_ci		else
41562306a36Sopenharmony_ci			stop_page = NESM_STOP_PG;
41662306a36Sopenharmony_ci	} else {
41762306a36Sopenharmony_ci		start_page = NE1SM_START_PG;
41862306a36Sopenharmony_ci		stop_page  = NE1SM_STOP_PG;
41962306a36Sopenharmony_ci	}
42062306a36Sopenharmony_ci
42162306a36Sopenharmony_ci	neX000 = (SA_prom[14] == 0x57  &&  SA_prom[15] == 0x57);
42262306a36Sopenharmony_ci	ctron =  (SA_prom[0] == 0x00 && SA_prom[1] == 0x00 && SA_prom[2] == 0x1d);
42362306a36Sopenharmony_ci	copam =  (SA_prom[14] == 0x49 && SA_prom[15] == 0x00);
42462306a36Sopenharmony_ci
42562306a36Sopenharmony_ci	/* Set up the rest of the parameters. */
42662306a36Sopenharmony_ci	if (neX000 || bad_card || copam) {
42762306a36Sopenharmony_ci		name = (wordlength == 2) ? "NE2000" : "NE1000";
42862306a36Sopenharmony_ci	}
42962306a36Sopenharmony_ci	else if (ctron)
43062306a36Sopenharmony_ci	{
43162306a36Sopenharmony_ci		name = (wordlength == 2) ? "Ctron-8" : "Ctron-16";
43262306a36Sopenharmony_ci		start_page = 0x01;
43362306a36Sopenharmony_ci		stop_page = (wordlength == 2) ? 0x40 : 0x20;
43462306a36Sopenharmony_ci	}
43562306a36Sopenharmony_ci	else
43662306a36Sopenharmony_ci	{
43762306a36Sopenharmony_ci#ifdef SUPPORT_NE_BAD_CLONES
43862306a36Sopenharmony_ci		/* Ack!  Well, there might be a *bad* NE*000 clone there.
43962306a36Sopenharmony_ci		   Check for total bogus addresses. */
44062306a36Sopenharmony_ci		for (i = 0; bad_clone_list[i].name8; i++)
44162306a36Sopenharmony_ci		{
44262306a36Sopenharmony_ci			if (SA_prom[0] == bad_clone_list[i].SAprefix[0] &&
44362306a36Sopenharmony_ci				SA_prom[1] == bad_clone_list[i].SAprefix[1] &&
44462306a36Sopenharmony_ci				SA_prom[2] == bad_clone_list[i].SAprefix[2])
44562306a36Sopenharmony_ci			{
44662306a36Sopenharmony_ci				if (wordlength == 2)
44762306a36Sopenharmony_ci				{
44862306a36Sopenharmony_ci					name = bad_clone_list[i].name16;
44962306a36Sopenharmony_ci				} else {
45062306a36Sopenharmony_ci					name = bad_clone_list[i].name8;
45162306a36Sopenharmony_ci				}
45262306a36Sopenharmony_ci				break;
45362306a36Sopenharmony_ci			}
45462306a36Sopenharmony_ci		}
45562306a36Sopenharmony_ci		if (bad_clone_list[i].name8 == NULL)
45662306a36Sopenharmony_ci		{
45762306a36Sopenharmony_ci			pr_cont(" not found (invalid signature %2.2x %2.2x).\n",
45862306a36Sopenharmony_ci				SA_prom[14], SA_prom[15]);
45962306a36Sopenharmony_ci			ret = -ENXIO;
46062306a36Sopenharmony_ci			goto err_out;
46162306a36Sopenharmony_ci		}
46262306a36Sopenharmony_ci#else
46362306a36Sopenharmony_ci		pr_cont(" not found.\n");
46462306a36Sopenharmony_ci		ret = -ENXIO;
46562306a36Sopenharmony_ci		goto err_out;
46662306a36Sopenharmony_ci#endif
46762306a36Sopenharmony_ci	}
46862306a36Sopenharmony_ci
46962306a36Sopenharmony_ci	if (dev->irq < 2)
47062306a36Sopenharmony_ci	{
47162306a36Sopenharmony_ci		unsigned long cookie = probe_irq_on();
47262306a36Sopenharmony_ci		outb_p(0x50, ioaddr + EN0_IMR);	/* Enable one interrupt. */
47362306a36Sopenharmony_ci		outb_p(0x00, ioaddr + EN0_RCNTLO);
47462306a36Sopenharmony_ci		outb_p(0x00, ioaddr + EN0_RCNTHI);
47562306a36Sopenharmony_ci		outb_p(E8390_RREAD+E8390_START, ioaddr); /* Trigger it... */
47662306a36Sopenharmony_ci		mdelay(10);		/* wait 10ms for interrupt to propagate */
47762306a36Sopenharmony_ci		outb_p(0x00, ioaddr + EN0_IMR); 		/* Mask it again. */
47862306a36Sopenharmony_ci		dev->irq = probe_irq_off(cookie);
47962306a36Sopenharmony_ci		if (ne_msg_enable & NETIF_MSG_PROBE)
48062306a36Sopenharmony_ci			pr_cont(" autoirq is %d", dev->irq);
48162306a36Sopenharmony_ci	} else if (dev->irq == 2)
48262306a36Sopenharmony_ci		/* Fixup for users that don't know that IRQ 2 is really IRQ 9,
48362306a36Sopenharmony_ci		   or don't know which one to set. */
48462306a36Sopenharmony_ci		dev->irq = 9;
48562306a36Sopenharmony_ci
48662306a36Sopenharmony_ci	if (! dev->irq) {
48762306a36Sopenharmony_ci		pr_cont(" failed to detect IRQ line.\n");
48862306a36Sopenharmony_ci		ret = -EAGAIN;
48962306a36Sopenharmony_ci		goto err_out;
49062306a36Sopenharmony_ci	}
49162306a36Sopenharmony_ci
49262306a36Sopenharmony_ci	/* Snarf the interrupt now.  There's no point in waiting since we cannot
49362306a36Sopenharmony_ci	   share and the board will usually be enabled. */
49462306a36Sopenharmony_ci	ret = request_irq(dev->irq, eip_interrupt, 0, name, dev);
49562306a36Sopenharmony_ci	if (ret) {
49662306a36Sopenharmony_ci		pr_cont(" unable to get IRQ %d (errno=%d).\n", dev->irq, ret);
49762306a36Sopenharmony_ci		goto err_out;
49862306a36Sopenharmony_ci	}
49962306a36Sopenharmony_ci
50062306a36Sopenharmony_ci	dev->base_addr = ioaddr;
50162306a36Sopenharmony_ci
50262306a36Sopenharmony_ci	eth_hw_addr_set(dev, SA_prom);
50362306a36Sopenharmony_ci
50462306a36Sopenharmony_ci	pr_cont("%pM\n", dev->dev_addr);
50562306a36Sopenharmony_ci
50662306a36Sopenharmony_ci	ei_status.name = name;
50762306a36Sopenharmony_ci	ei_status.tx_start_page = start_page;
50862306a36Sopenharmony_ci	ei_status.stop_page = stop_page;
50962306a36Sopenharmony_ci
51062306a36Sopenharmony_ci	/* Use 16-bit mode only if this wasn't overridden by DCR_VAL */
51162306a36Sopenharmony_ci	ei_status.word16 = (wordlength == 2 && (DCR_VAL & 0x01));
51262306a36Sopenharmony_ci
51362306a36Sopenharmony_ci	ei_status.rx_start_page = start_page + TX_PAGES;
51462306a36Sopenharmony_ci#ifdef PACKETBUF_MEMSIZE
51562306a36Sopenharmony_ci	 /* Allow the packet buffer size to be overridden by know-it-alls. */
51662306a36Sopenharmony_ci	ei_status.stop_page = ei_status.tx_start_page + PACKETBUF_MEMSIZE;
51762306a36Sopenharmony_ci#endif
51862306a36Sopenharmony_ci
51962306a36Sopenharmony_ci	ei_status.reset_8390 = &ne_reset_8390;
52062306a36Sopenharmony_ci	ei_status.block_input = &ne_block_input;
52162306a36Sopenharmony_ci	ei_status.block_output = &ne_block_output;
52262306a36Sopenharmony_ci	ei_status.get_8390_hdr = &ne_get_8390_hdr;
52362306a36Sopenharmony_ci	ei_status.priv = 0;
52462306a36Sopenharmony_ci
52562306a36Sopenharmony_ci	dev->netdev_ops = &eip_netdev_ops;
52662306a36Sopenharmony_ci	NS8390p_init(dev, 0);
52762306a36Sopenharmony_ci
52862306a36Sopenharmony_ci	ei_local->msg_enable = ne_msg_enable;
52962306a36Sopenharmony_ci	ret = register_netdev(dev);
53062306a36Sopenharmony_ci	if (ret)
53162306a36Sopenharmony_ci		goto out_irq;
53262306a36Sopenharmony_ci	netdev_info(dev, "%s found at %#lx, using IRQ %d.\n",
53362306a36Sopenharmony_ci		    name, ioaddr, dev->irq);
53462306a36Sopenharmony_ci	return 0;
53562306a36Sopenharmony_ci
53662306a36Sopenharmony_ciout_irq:
53762306a36Sopenharmony_ci	free_irq(dev->irq, dev);
53862306a36Sopenharmony_cierr_out:
53962306a36Sopenharmony_ci	release_region(ioaddr, NE_IO_EXTENT);
54062306a36Sopenharmony_ci	return ret;
54162306a36Sopenharmony_ci}
54262306a36Sopenharmony_ci
54362306a36Sopenharmony_ci/* Hard reset the card.  This used to pause for the same period that a
54462306a36Sopenharmony_ci   8390 reset command required, but that shouldn't be necessary. */
54562306a36Sopenharmony_ci
54662306a36Sopenharmony_cistatic void ne_reset_8390(struct net_device *dev)
54762306a36Sopenharmony_ci{
54862306a36Sopenharmony_ci	unsigned long reset_start_time = jiffies;
54962306a36Sopenharmony_ci	struct ei_device *ei_local = netdev_priv(dev);
55062306a36Sopenharmony_ci
55162306a36Sopenharmony_ci	netif_dbg(ei_local, hw, dev, "resetting the 8390 t=%ld...\n", jiffies);
55262306a36Sopenharmony_ci
55362306a36Sopenharmony_ci	/* DON'T change these to inb_p/outb_p or reset will fail on clones. */
55462306a36Sopenharmony_ci	outb(inb(NE_BASE + NE_RESET), NE_BASE + NE_RESET);
55562306a36Sopenharmony_ci
55662306a36Sopenharmony_ci	ei_status.txing = 0;
55762306a36Sopenharmony_ci	ei_status.dmaing = 0;
55862306a36Sopenharmony_ci
55962306a36Sopenharmony_ci	/* This check _should_not_ be necessary, omit eventually. */
56062306a36Sopenharmony_ci	while ((inb_p(NE_BASE+EN0_ISR) & ENISR_RESET) == 0)
56162306a36Sopenharmony_ci		if (time_after(jiffies, reset_start_time + 2*HZ/100)) {
56262306a36Sopenharmony_ci			netdev_err(dev, "ne_reset_8390() did not complete.\n");
56362306a36Sopenharmony_ci			break;
56462306a36Sopenharmony_ci		}
56562306a36Sopenharmony_ci	outb_p(ENISR_RESET, NE_BASE + EN0_ISR);	/* Ack intr. */
56662306a36Sopenharmony_ci}
56762306a36Sopenharmony_ci
56862306a36Sopenharmony_ci/* Grab the 8390 specific header. Similar to the block_input routine, but
56962306a36Sopenharmony_ci   we don't need to be concerned with ring wrap as the header will be at
57062306a36Sopenharmony_ci   the start of a page, so we optimize accordingly. */
57162306a36Sopenharmony_ci
57262306a36Sopenharmony_cistatic void ne_get_8390_hdr(struct net_device *dev, struct e8390_pkt_hdr *hdr, int ring_page)
57362306a36Sopenharmony_ci{
57462306a36Sopenharmony_ci	int nic_base = dev->base_addr;
57562306a36Sopenharmony_ci
57662306a36Sopenharmony_ci	/* This *shouldn't* happen. If it does, it's the last thing you'll see */
57762306a36Sopenharmony_ci
57862306a36Sopenharmony_ci	if (ei_status.dmaing)
57962306a36Sopenharmony_ci	{
58062306a36Sopenharmony_ci		netdev_err(dev, "DMAing conflict in ne_get_8390_hdr "
58162306a36Sopenharmony_ci			   "[DMAstat:%d][irqlock:%d].\n",
58262306a36Sopenharmony_ci			   ei_status.dmaing, ei_status.irqlock);
58362306a36Sopenharmony_ci		return;
58462306a36Sopenharmony_ci	}
58562306a36Sopenharmony_ci
58662306a36Sopenharmony_ci	ei_status.dmaing |= 0x01;
58762306a36Sopenharmony_ci	outb_p(E8390_NODMA+E8390_PAGE0+E8390_START, nic_base+ NE_CMD);
58862306a36Sopenharmony_ci	outb_p(sizeof(struct e8390_pkt_hdr), nic_base + EN0_RCNTLO);
58962306a36Sopenharmony_ci	outb_p(0, nic_base + EN0_RCNTHI);
59062306a36Sopenharmony_ci	outb_p(0, nic_base + EN0_RSARLO);		/* On page boundary */
59162306a36Sopenharmony_ci	outb_p(ring_page, nic_base + EN0_RSARHI);
59262306a36Sopenharmony_ci	outb_p(E8390_RREAD+E8390_START, nic_base + NE_CMD);
59362306a36Sopenharmony_ci
59462306a36Sopenharmony_ci	if (ei_status.word16)
59562306a36Sopenharmony_ci		insw(NE_BASE + NE_DATAPORT, hdr, sizeof(struct e8390_pkt_hdr)>>1);
59662306a36Sopenharmony_ci	else
59762306a36Sopenharmony_ci		insb(NE_BASE + NE_DATAPORT, hdr, sizeof(struct e8390_pkt_hdr));
59862306a36Sopenharmony_ci
59962306a36Sopenharmony_ci	outb_p(ENISR_RDC, nic_base + EN0_ISR);	/* Ack intr. */
60062306a36Sopenharmony_ci	ei_status.dmaing &= ~0x01;
60162306a36Sopenharmony_ci
60262306a36Sopenharmony_ci	le16_to_cpus(&hdr->count);
60362306a36Sopenharmony_ci}
60462306a36Sopenharmony_ci
60562306a36Sopenharmony_ci/* Block input and output, similar to the Crynwr packet driver.  If you
60662306a36Sopenharmony_ci   are porting to a new ethercard, look at the packet driver source for hints.
60762306a36Sopenharmony_ci   The NEx000 doesn't share the on-board packet memory -- you have to put
60862306a36Sopenharmony_ci   the packet out through the "remote DMA" dataport using outb. */
60962306a36Sopenharmony_ci
61062306a36Sopenharmony_cistatic void ne_block_input(struct net_device *dev, int count, struct sk_buff *skb, int ring_offset)
61162306a36Sopenharmony_ci{
61262306a36Sopenharmony_ci#ifdef NE_SANITY_CHECK
61362306a36Sopenharmony_ci	int xfer_count = count;
61462306a36Sopenharmony_ci	struct ei_device *ei_local = netdev_priv(dev);
61562306a36Sopenharmony_ci#endif
61662306a36Sopenharmony_ci	int nic_base = dev->base_addr;
61762306a36Sopenharmony_ci	char *buf = skb->data;
61862306a36Sopenharmony_ci
61962306a36Sopenharmony_ci	/* This *shouldn't* happen. If it does, it's the last thing you'll see */
62062306a36Sopenharmony_ci	if (ei_status.dmaing)
62162306a36Sopenharmony_ci	{
62262306a36Sopenharmony_ci		netdev_err(dev, "DMAing conflict in ne_block_input "
62362306a36Sopenharmony_ci			   "[DMAstat:%d][irqlock:%d].\n",
62462306a36Sopenharmony_ci			   ei_status.dmaing, ei_status.irqlock);
62562306a36Sopenharmony_ci		return;
62662306a36Sopenharmony_ci	}
62762306a36Sopenharmony_ci	ei_status.dmaing |= 0x01;
62862306a36Sopenharmony_ci	outb_p(E8390_NODMA+E8390_PAGE0+E8390_START, nic_base+ NE_CMD);
62962306a36Sopenharmony_ci	outb_p(count & 0xff, nic_base + EN0_RCNTLO);
63062306a36Sopenharmony_ci	outb_p(count >> 8, nic_base + EN0_RCNTHI);
63162306a36Sopenharmony_ci	outb_p(ring_offset & 0xff, nic_base + EN0_RSARLO);
63262306a36Sopenharmony_ci	outb_p(ring_offset >> 8, nic_base + EN0_RSARHI);
63362306a36Sopenharmony_ci	outb_p(E8390_RREAD+E8390_START, nic_base + NE_CMD);
63462306a36Sopenharmony_ci	if (ei_status.word16)
63562306a36Sopenharmony_ci	{
63662306a36Sopenharmony_ci		insw(NE_BASE + NE_DATAPORT,buf,count>>1);
63762306a36Sopenharmony_ci		if (count & 0x01)
63862306a36Sopenharmony_ci		{
63962306a36Sopenharmony_ci			buf[count-1] = inb(NE_BASE + NE_DATAPORT);
64062306a36Sopenharmony_ci#ifdef NE_SANITY_CHECK
64162306a36Sopenharmony_ci			xfer_count++;
64262306a36Sopenharmony_ci#endif
64362306a36Sopenharmony_ci		}
64462306a36Sopenharmony_ci	} else {
64562306a36Sopenharmony_ci		insb(NE_BASE + NE_DATAPORT, buf, count);
64662306a36Sopenharmony_ci	}
64762306a36Sopenharmony_ci
64862306a36Sopenharmony_ci#ifdef NE_SANITY_CHECK
64962306a36Sopenharmony_ci	/* This was for the ALPHA version only, but enough people have
65062306a36Sopenharmony_ci	   been encountering problems so it is still here.  If you see
65162306a36Sopenharmony_ci	   this message you either 1) have a slightly incompatible clone
65262306a36Sopenharmony_ci	   or 2) have noise/speed problems with your bus. */
65362306a36Sopenharmony_ci
65462306a36Sopenharmony_ci	if (netif_msg_rx_status(ei_local))
65562306a36Sopenharmony_ci	{
65662306a36Sopenharmony_ci		/* DMA termination address check... */
65762306a36Sopenharmony_ci		int addr, tries = 20;
65862306a36Sopenharmony_ci		do {
65962306a36Sopenharmony_ci			/* DON'T check for 'inb_p(EN0_ISR) & ENISR_RDC' here
66062306a36Sopenharmony_ci			   -- it's broken for Rx on some cards! */
66162306a36Sopenharmony_ci			int high = inb_p(nic_base + EN0_RSARHI);
66262306a36Sopenharmony_ci			int low = inb_p(nic_base + EN0_RSARLO);
66362306a36Sopenharmony_ci			addr = (high << 8) + low;
66462306a36Sopenharmony_ci			if (((ring_offset + xfer_count) & 0xff) == low)
66562306a36Sopenharmony_ci				break;
66662306a36Sopenharmony_ci		} while (--tries > 0);
66762306a36Sopenharmony_ci	 	if (tries <= 0)
66862306a36Sopenharmony_ci			netdev_warn(dev, "RX transfer address mismatch,"
66962306a36Sopenharmony_ci				    "%#4.4x (expected) vs. %#4.4x (actual).\n",
67062306a36Sopenharmony_ci				    ring_offset + xfer_count, addr);
67162306a36Sopenharmony_ci	}
67262306a36Sopenharmony_ci#endif
67362306a36Sopenharmony_ci	outb_p(ENISR_RDC, nic_base + EN0_ISR);	/* Ack intr. */
67462306a36Sopenharmony_ci	ei_status.dmaing &= ~0x01;
67562306a36Sopenharmony_ci}
67662306a36Sopenharmony_ci
67762306a36Sopenharmony_cistatic void ne_block_output(struct net_device *dev, int count,
67862306a36Sopenharmony_ci		const unsigned char *buf, const int start_page)
67962306a36Sopenharmony_ci{
68062306a36Sopenharmony_ci	int nic_base = NE_BASE;
68162306a36Sopenharmony_ci	unsigned long dma_start;
68262306a36Sopenharmony_ci#ifdef NE_SANITY_CHECK
68362306a36Sopenharmony_ci	int retries = 0;
68462306a36Sopenharmony_ci	struct ei_device *ei_local = netdev_priv(dev);
68562306a36Sopenharmony_ci#endif
68662306a36Sopenharmony_ci
68762306a36Sopenharmony_ci	/* Round the count up for word writes.  Do we need to do this?
68862306a36Sopenharmony_ci	   What effect will an odd byte count have on the 8390?
68962306a36Sopenharmony_ci	   I should check someday. */
69062306a36Sopenharmony_ci
69162306a36Sopenharmony_ci	if (ei_status.word16 && (count & 0x01))
69262306a36Sopenharmony_ci		count++;
69362306a36Sopenharmony_ci
69462306a36Sopenharmony_ci	/* This *shouldn't* happen. If it does, it's the last thing you'll see */
69562306a36Sopenharmony_ci	if (ei_status.dmaing)
69662306a36Sopenharmony_ci	{
69762306a36Sopenharmony_ci		netdev_err(dev, "DMAing conflict in ne_block_output."
69862306a36Sopenharmony_ci			   "[DMAstat:%d][irqlock:%d]\n",
69962306a36Sopenharmony_ci			   ei_status.dmaing, ei_status.irqlock);
70062306a36Sopenharmony_ci		return;
70162306a36Sopenharmony_ci	}
70262306a36Sopenharmony_ci	ei_status.dmaing |= 0x01;
70362306a36Sopenharmony_ci	/* We should already be in page 0, but to be safe... */
70462306a36Sopenharmony_ci	outb_p(E8390_PAGE0+E8390_START+E8390_NODMA, nic_base + NE_CMD);
70562306a36Sopenharmony_ci
70662306a36Sopenharmony_ci#ifdef NE_SANITY_CHECK
70762306a36Sopenharmony_ciretry:
70862306a36Sopenharmony_ci#endif
70962306a36Sopenharmony_ci
71062306a36Sopenharmony_ci#ifdef NE_RW_BUGFIX
71162306a36Sopenharmony_ci	/* Handle the read-before-write bug the same way as the
71262306a36Sopenharmony_ci	   Crynwr packet driver -- the NatSemi method doesn't work.
71362306a36Sopenharmony_ci	   Actually this doesn't always work either, but if you have
71462306a36Sopenharmony_ci	   problems with your NEx000 this is better than nothing! */
71562306a36Sopenharmony_ci
71662306a36Sopenharmony_ci	outb_p(0x42, nic_base + EN0_RCNTLO);
71762306a36Sopenharmony_ci	outb_p(0x00,   nic_base + EN0_RCNTHI);
71862306a36Sopenharmony_ci	outb_p(0x42, nic_base + EN0_RSARLO);
71962306a36Sopenharmony_ci	outb_p(0x00, nic_base + EN0_RSARHI);
72062306a36Sopenharmony_ci	outb_p(E8390_RREAD+E8390_START, nic_base + NE_CMD);
72162306a36Sopenharmony_ci	/* Make certain that the dummy read has occurred. */
72262306a36Sopenharmony_ci	udelay(6);
72362306a36Sopenharmony_ci#endif
72462306a36Sopenharmony_ci
72562306a36Sopenharmony_ci	outb_p(ENISR_RDC, nic_base + EN0_ISR);
72662306a36Sopenharmony_ci
72762306a36Sopenharmony_ci	/* Now the normal output. */
72862306a36Sopenharmony_ci	outb_p(count & 0xff, nic_base + EN0_RCNTLO);
72962306a36Sopenharmony_ci	outb_p(count >> 8,   nic_base + EN0_RCNTHI);
73062306a36Sopenharmony_ci	outb_p(0x00, nic_base + EN0_RSARLO);
73162306a36Sopenharmony_ci	outb_p(start_page, nic_base + EN0_RSARHI);
73262306a36Sopenharmony_ci
73362306a36Sopenharmony_ci	outb_p(E8390_RWRITE+E8390_START, nic_base + NE_CMD);
73462306a36Sopenharmony_ci	if (ei_status.word16) {
73562306a36Sopenharmony_ci		outsw(NE_BASE + NE_DATAPORT, buf, count>>1);
73662306a36Sopenharmony_ci	} else {
73762306a36Sopenharmony_ci		outsb(NE_BASE + NE_DATAPORT, buf, count);
73862306a36Sopenharmony_ci	}
73962306a36Sopenharmony_ci
74062306a36Sopenharmony_ci	dma_start = jiffies;
74162306a36Sopenharmony_ci
74262306a36Sopenharmony_ci#ifdef NE_SANITY_CHECK
74362306a36Sopenharmony_ci	/* This was for the ALPHA version only, but enough people have
74462306a36Sopenharmony_ci	   been encountering problems so it is still here. */
74562306a36Sopenharmony_ci
74662306a36Sopenharmony_ci	if (netif_msg_tx_queued(ei_local))
74762306a36Sopenharmony_ci	{
74862306a36Sopenharmony_ci		/* DMA termination address check... */
74962306a36Sopenharmony_ci		int addr, tries = 20;
75062306a36Sopenharmony_ci		do {
75162306a36Sopenharmony_ci			int high = inb_p(nic_base + EN0_RSARHI);
75262306a36Sopenharmony_ci			int low = inb_p(nic_base + EN0_RSARLO);
75362306a36Sopenharmony_ci			addr = (high << 8) + low;
75462306a36Sopenharmony_ci			if ((start_page << 8) + count == addr)
75562306a36Sopenharmony_ci				break;
75662306a36Sopenharmony_ci		} while (--tries > 0);
75762306a36Sopenharmony_ci
75862306a36Sopenharmony_ci		if (tries <= 0)
75962306a36Sopenharmony_ci		{
76062306a36Sopenharmony_ci			netdev_warn(dev, "Tx packet transfer address mismatch,"
76162306a36Sopenharmony_ci				    "%#4.4x (expected) vs. %#4.4x (actual).\n",
76262306a36Sopenharmony_ci				    (start_page << 8) + count, addr);
76362306a36Sopenharmony_ci			if (retries++ == 0)
76462306a36Sopenharmony_ci				goto retry;
76562306a36Sopenharmony_ci		}
76662306a36Sopenharmony_ci	}
76762306a36Sopenharmony_ci#endif
76862306a36Sopenharmony_ci
76962306a36Sopenharmony_ci	while ((inb_p(nic_base + EN0_ISR) & ENISR_RDC) == 0)
77062306a36Sopenharmony_ci		if (time_after(jiffies, dma_start + 2*HZ/100)) {		/* 20ms */
77162306a36Sopenharmony_ci			netdev_warn(dev, "timeout waiting for Tx RDC.\n");
77262306a36Sopenharmony_ci			ne_reset_8390(dev);
77362306a36Sopenharmony_ci			NS8390p_init(dev, 1);
77462306a36Sopenharmony_ci			break;
77562306a36Sopenharmony_ci		}
77662306a36Sopenharmony_ci
77762306a36Sopenharmony_ci	outb_p(ENISR_RDC, nic_base + EN0_ISR);	/* Ack intr. */
77862306a36Sopenharmony_ci	ei_status.dmaing &= ~0x01;
77962306a36Sopenharmony_ci}
78062306a36Sopenharmony_ci
78162306a36Sopenharmony_cistatic int __init ne_drv_probe(struct platform_device *pdev)
78262306a36Sopenharmony_ci{
78362306a36Sopenharmony_ci	struct net_device *dev;
78462306a36Sopenharmony_ci	int err, this_dev = pdev->id;
78562306a36Sopenharmony_ci	struct resource *res;
78662306a36Sopenharmony_ci
78762306a36Sopenharmony_ci	dev = alloc_eip_netdev();
78862306a36Sopenharmony_ci	if (!dev)
78962306a36Sopenharmony_ci		return -ENOMEM;
79062306a36Sopenharmony_ci
79162306a36Sopenharmony_ci	/* ne.c doesn't populate resources in platform_device, but
79262306a36Sopenharmony_ci	 * rbtx4927_ne_init and rbtx4938_ne_init do register devices
79362306a36Sopenharmony_ci	 * with resources.
79462306a36Sopenharmony_ci	 */
79562306a36Sopenharmony_ci	res = platform_get_resource(pdev, IORESOURCE_IO, 0);
79662306a36Sopenharmony_ci	if (res) {
79762306a36Sopenharmony_ci		dev->base_addr = res->start;
79862306a36Sopenharmony_ci		dev->irq = platform_get_irq(pdev, 0);
79962306a36Sopenharmony_ci	} else {
80062306a36Sopenharmony_ci		if (this_dev < 0 || this_dev >= MAX_NE_CARDS) {
80162306a36Sopenharmony_ci			free_netdev(dev);
80262306a36Sopenharmony_ci			return -EINVAL;
80362306a36Sopenharmony_ci		}
80462306a36Sopenharmony_ci		dev->base_addr = io[this_dev];
80562306a36Sopenharmony_ci		dev->irq = irq[this_dev];
80662306a36Sopenharmony_ci		dev->mem_end = bad[this_dev];
80762306a36Sopenharmony_ci	}
80862306a36Sopenharmony_ci	SET_NETDEV_DEV(dev, &pdev->dev);
80962306a36Sopenharmony_ci	err = do_ne_probe(dev);
81062306a36Sopenharmony_ci	if (err) {
81162306a36Sopenharmony_ci		free_netdev(dev);
81262306a36Sopenharmony_ci		return err;
81362306a36Sopenharmony_ci	}
81462306a36Sopenharmony_ci	platform_set_drvdata(pdev, dev);
81562306a36Sopenharmony_ci
81662306a36Sopenharmony_ci	/* Update with any values found by probing, don't update if
81762306a36Sopenharmony_ci	 * resources were specified.
81862306a36Sopenharmony_ci	 */
81962306a36Sopenharmony_ci	if (!res) {
82062306a36Sopenharmony_ci		io[this_dev] = dev->base_addr;
82162306a36Sopenharmony_ci		irq[this_dev] = dev->irq;
82262306a36Sopenharmony_ci	}
82362306a36Sopenharmony_ci	return 0;
82462306a36Sopenharmony_ci}
82562306a36Sopenharmony_ci
82662306a36Sopenharmony_cistatic int ne_drv_remove(struct platform_device *pdev)
82762306a36Sopenharmony_ci{
82862306a36Sopenharmony_ci	struct net_device *dev = platform_get_drvdata(pdev);
82962306a36Sopenharmony_ci
83062306a36Sopenharmony_ci	if (dev) {
83162306a36Sopenharmony_ci		struct pnp_dev *idev = (struct pnp_dev *)ei_status.priv;
83262306a36Sopenharmony_ci		netif_device_detach(dev);
83362306a36Sopenharmony_ci		unregister_netdev(dev);
83462306a36Sopenharmony_ci		if (idev)
83562306a36Sopenharmony_ci			pnp_device_detach(idev);
83662306a36Sopenharmony_ci		/* Careful ne_drv_remove can be called twice, once from
83762306a36Sopenharmony_ci		 * the platform_driver.remove and again when the
83862306a36Sopenharmony_ci		 * platform_device is being removed.
83962306a36Sopenharmony_ci		 */
84062306a36Sopenharmony_ci		ei_status.priv = 0;
84162306a36Sopenharmony_ci		free_irq(dev->irq, dev);
84262306a36Sopenharmony_ci		release_region(dev->base_addr, NE_IO_EXTENT);
84362306a36Sopenharmony_ci		free_netdev(dev);
84462306a36Sopenharmony_ci	}
84562306a36Sopenharmony_ci	return 0;
84662306a36Sopenharmony_ci}
84762306a36Sopenharmony_ci
84862306a36Sopenharmony_ci/* Remove unused devices or all if true. */
84962306a36Sopenharmony_cistatic void ne_loop_rm_unreg(int all)
85062306a36Sopenharmony_ci{
85162306a36Sopenharmony_ci	int this_dev;
85262306a36Sopenharmony_ci	struct platform_device *pdev;
85362306a36Sopenharmony_ci	for (this_dev = 0; this_dev < MAX_NE_CARDS; this_dev++) {
85462306a36Sopenharmony_ci		pdev = pdev_ne[this_dev];
85562306a36Sopenharmony_ci		/* No network device == unused */
85662306a36Sopenharmony_ci		if (pdev && (!platform_get_drvdata(pdev) || all)) {
85762306a36Sopenharmony_ci			ne_drv_remove(pdev);
85862306a36Sopenharmony_ci			platform_device_unregister(pdev);
85962306a36Sopenharmony_ci			pdev_ne[this_dev] = NULL;
86062306a36Sopenharmony_ci		}
86162306a36Sopenharmony_ci	}
86262306a36Sopenharmony_ci}
86362306a36Sopenharmony_ci
86462306a36Sopenharmony_ci#ifdef CONFIG_PM
86562306a36Sopenharmony_cistatic int ne_drv_suspend(struct platform_device *pdev, pm_message_t state)
86662306a36Sopenharmony_ci{
86762306a36Sopenharmony_ci	struct net_device *dev = platform_get_drvdata(pdev);
86862306a36Sopenharmony_ci
86962306a36Sopenharmony_ci	if (netif_running(dev)) {
87062306a36Sopenharmony_ci		struct pnp_dev *idev = (struct pnp_dev *)ei_status.priv;
87162306a36Sopenharmony_ci		netif_device_detach(dev);
87262306a36Sopenharmony_ci		if (idev)
87362306a36Sopenharmony_ci			pnp_stop_dev(idev);
87462306a36Sopenharmony_ci	}
87562306a36Sopenharmony_ci	return 0;
87662306a36Sopenharmony_ci}
87762306a36Sopenharmony_ci
87862306a36Sopenharmony_cistatic int ne_drv_resume(struct platform_device *pdev)
87962306a36Sopenharmony_ci{
88062306a36Sopenharmony_ci	struct net_device *dev = platform_get_drvdata(pdev);
88162306a36Sopenharmony_ci
88262306a36Sopenharmony_ci	if (netif_running(dev)) {
88362306a36Sopenharmony_ci		struct pnp_dev *idev = (struct pnp_dev *)ei_status.priv;
88462306a36Sopenharmony_ci		if (idev)
88562306a36Sopenharmony_ci			pnp_start_dev(idev);
88662306a36Sopenharmony_ci		ne_reset_8390(dev);
88762306a36Sopenharmony_ci		NS8390p_init(dev, 1);
88862306a36Sopenharmony_ci		netif_device_attach(dev);
88962306a36Sopenharmony_ci	}
89062306a36Sopenharmony_ci	return 0;
89162306a36Sopenharmony_ci}
89262306a36Sopenharmony_ci#else
89362306a36Sopenharmony_ci#define ne_drv_suspend NULL
89462306a36Sopenharmony_ci#define ne_drv_resume NULL
89562306a36Sopenharmony_ci#endif
89662306a36Sopenharmony_ci
89762306a36Sopenharmony_cistatic struct platform_driver ne_driver = {
89862306a36Sopenharmony_ci	.remove		= ne_drv_remove,
89962306a36Sopenharmony_ci	.suspend	= ne_drv_suspend,
90062306a36Sopenharmony_ci	.resume		= ne_drv_resume,
90162306a36Sopenharmony_ci	.driver		= {
90262306a36Sopenharmony_ci		.name	= DRV_NAME,
90362306a36Sopenharmony_ci	},
90462306a36Sopenharmony_ci};
90562306a36Sopenharmony_ci
90662306a36Sopenharmony_cistatic void __init ne_add_devices(void)
90762306a36Sopenharmony_ci{
90862306a36Sopenharmony_ci	int this_dev;
90962306a36Sopenharmony_ci	struct platform_device *pdev;
91062306a36Sopenharmony_ci
91162306a36Sopenharmony_ci	for (this_dev = 0; this_dev < MAX_NE_CARDS; this_dev++) {
91262306a36Sopenharmony_ci		if (pdev_ne[this_dev])
91362306a36Sopenharmony_ci			continue;
91462306a36Sopenharmony_ci		pdev = platform_device_register_simple(
91562306a36Sopenharmony_ci			DRV_NAME, this_dev, NULL, 0);
91662306a36Sopenharmony_ci		if (IS_ERR(pdev))
91762306a36Sopenharmony_ci			continue;
91862306a36Sopenharmony_ci		pdev_ne[this_dev] = pdev;
91962306a36Sopenharmony_ci	}
92062306a36Sopenharmony_ci}
92162306a36Sopenharmony_ci
92262306a36Sopenharmony_cistatic int __init ne_init(void)
92362306a36Sopenharmony_ci{
92462306a36Sopenharmony_ci	int retval;
92562306a36Sopenharmony_ci
92662306a36Sopenharmony_ci	if (IS_MODULE(CONFIG_NE2000))
92762306a36Sopenharmony_ci		ne_add_devices();
92862306a36Sopenharmony_ci
92962306a36Sopenharmony_ci	retval = platform_driver_probe(&ne_driver, ne_drv_probe);
93062306a36Sopenharmony_ci
93162306a36Sopenharmony_ci	if (IS_MODULE(CONFIG_NE2000) && retval) {
93262306a36Sopenharmony_ci		if (io[0] == 0)
93362306a36Sopenharmony_ci			pr_notice("ne.c: You must supply \"io=0xNNN\""
93462306a36Sopenharmony_ci			       " value(s) for ISA cards.\n");
93562306a36Sopenharmony_ci		ne_loop_rm_unreg(1);
93662306a36Sopenharmony_ci		return retval;
93762306a36Sopenharmony_ci	}
93862306a36Sopenharmony_ci
93962306a36Sopenharmony_ci	/* Unregister unused platform_devices. */
94062306a36Sopenharmony_ci	ne_loop_rm_unreg(0);
94162306a36Sopenharmony_ci	return retval;
94262306a36Sopenharmony_ci}
94362306a36Sopenharmony_cimodule_init(ne_init);
94462306a36Sopenharmony_ci
94562306a36Sopenharmony_ci#if !defined(MODULE) && defined(CONFIG_NETDEV_LEGACY_INIT)
94662306a36Sopenharmony_cistruct net_device * __init ne_probe(int unit)
94762306a36Sopenharmony_ci{
94862306a36Sopenharmony_ci	int this_dev;
94962306a36Sopenharmony_ci	struct net_device *dev;
95062306a36Sopenharmony_ci
95162306a36Sopenharmony_ci	/* Find an empty slot, that is no net_device and zero io port. */
95262306a36Sopenharmony_ci	this_dev = 0;
95362306a36Sopenharmony_ci	while ((pdev_ne[this_dev] && platform_get_drvdata(pdev_ne[this_dev])) ||
95462306a36Sopenharmony_ci		io[this_dev]) {
95562306a36Sopenharmony_ci		if (++this_dev == MAX_NE_CARDS)
95662306a36Sopenharmony_ci			return ERR_PTR(-ENOMEM);
95762306a36Sopenharmony_ci	}
95862306a36Sopenharmony_ci
95962306a36Sopenharmony_ci	/* Get irq, io from kernel command line */
96062306a36Sopenharmony_ci	dev = alloc_eip_netdev();
96162306a36Sopenharmony_ci	if (!dev)
96262306a36Sopenharmony_ci		return ERR_PTR(-ENOMEM);
96362306a36Sopenharmony_ci
96462306a36Sopenharmony_ci	sprintf(dev->name, "eth%d", unit);
96562306a36Sopenharmony_ci	netdev_boot_setup_check(dev);
96662306a36Sopenharmony_ci
96762306a36Sopenharmony_ci	io[this_dev] = dev->base_addr;
96862306a36Sopenharmony_ci	irq[this_dev] = dev->irq;
96962306a36Sopenharmony_ci	bad[this_dev] = dev->mem_end;
97062306a36Sopenharmony_ci
97162306a36Sopenharmony_ci	free_netdev(dev);
97262306a36Sopenharmony_ci
97362306a36Sopenharmony_ci	ne_add_devices();
97462306a36Sopenharmony_ci
97562306a36Sopenharmony_ci	/* return the first device found */
97662306a36Sopenharmony_ci	for (this_dev = 0; this_dev < MAX_NE_CARDS; this_dev++) {
97762306a36Sopenharmony_ci		if (pdev_ne[this_dev]) {
97862306a36Sopenharmony_ci			dev = platform_get_drvdata(pdev_ne[this_dev]);
97962306a36Sopenharmony_ci			if (dev)
98062306a36Sopenharmony_ci				return dev;
98162306a36Sopenharmony_ci		}
98262306a36Sopenharmony_ci	}
98362306a36Sopenharmony_ci
98462306a36Sopenharmony_ci	return ERR_PTR(-ENODEV);
98562306a36Sopenharmony_ci}
98662306a36Sopenharmony_ci#endif
98762306a36Sopenharmony_ci
98862306a36Sopenharmony_cistatic void __exit ne_exit(void)
98962306a36Sopenharmony_ci{
99062306a36Sopenharmony_ci	platform_driver_unregister(&ne_driver);
99162306a36Sopenharmony_ci	ne_loop_rm_unreg(1);
99262306a36Sopenharmony_ci}
99362306a36Sopenharmony_cimodule_exit(ne_exit);
994