162306a36Sopenharmony_ci/*
262306a36Sopenharmony_ci * Amiga Linux/68k A2065 Ethernet Driver
362306a36Sopenharmony_ci *
462306a36Sopenharmony_ci * (C) Copyright 1995-2003 by Geert Uytterhoeven <geert@linux-m68k.org>
562306a36Sopenharmony_ci *
662306a36Sopenharmony_ci * Fixes and tips by:
762306a36Sopenharmony_ci *	- Janos Farkas (CHEXUM@sparta.banki.hu)
862306a36Sopenharmony_ci *	- Jes Degn Soerensen (jds@kom.auc.dk)
962306a36Sopenharmony_ci *	- Matt Domsch (Matt_Domsch@dell.com)
1062306a36Sopenharmony_ci *
1162306a36Sopenharmony_ci * ----------------------------------------------------------------------------
1262306a36Sopenharmony_ci *
1362306a36Sopenharmony_ci * This program is based on
1462306a36Sopenharmony_ci *
1562306a36Sopenharmony_ci *	ariadne.?:	Amiga Linux/68k Ariadne Ethernet Driver
1662306a36Sopenharmony_ci *			(C) Copyright 1995 by Geert Uytterhoeven,
1762306a36Sopenharmony_ci *                                            Peter De Schrijver
1862306a36Sopenharmony_ci *
1962306a36Sopenharmony_ci *	lance.c:	An AMD LANCE ethernet driver for linux.
2062306a36Sopenharmony_ci *			Written 1993-94 by Donald Becker.
2162306a36Sopenharmony_ci *
2262306a36Sopenharmony_ci *	Am79C960:	PCnet(tm)-ISA Single-Chip Ethernet Controller
2362306a36Sopenharmony_ci *			Advanced Micro Devices
2462306a36Sopenharmony_ci *			Publication #16907, Rev. B, Amendment/0, May 1994
2562306a36Sopenharmony_ci *
2662306a36Sopenharmony_ci * ----------------------------------------------------------------------------
2762306a36Sopenharmony_ci *
2862306a36Sopenharmony_ci * This file is subject to the terms and conditions of the GNU General Public
2962306a36Sopenharmony_ci * License.  See the file COPYING in the main directory of the Linux
3062306a36Sopenharmony_ci * distribution for more details.
3162306a36Sopenharmony_ci *
3262306a36Sopenharmony_ci * ----------------------------------------------------------------------------
3362306a36Sopenharmony_ci *
3462306a36Sopenharmony_ci * The A2065 is a Zorro-II board made by Commodore/Ameristar. It contains:
3562306a36Sopenharmony_ci *
3662306a36Sopenharmony_ci *	- an Am7990 Local Area Network Controller for Ethernet (LANCE) with
3762306a36Sopenharmony_ci *	  both 10BASE-2 (thin coax) and AUI (DB-15) connectors
3862306a36Sopenharmony_ci */
3962306a36Sopenharmony_ci
4062306a36Sopenharmony_ci#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
4162306a36Sopenharmony_ci
4262306a36Sopenharmony_ci/*#define DEBUG*/
4362306a36Sopenharmony_ci/*#define TEST_HITS*/
4462306a36Sopenharmony_ci
4562306a36Sopenharmony_ci#include <linux/errno.h>
4662306a36Sopenharmony_ci#include <linux/netdevice.h>
4762306a36Sopenharmony_ci#include <linux/etherdevice.h>
4862306a36Sopenharmony_ci#include <linux/module.h>
4962306a36Sopenharmony_ci#include <linux/stddef.h>
5062306a36Sopenharmony_ci#include <linux/kernel.h>
5162306a36Sopenharmony_ci#include <linux/interrupt.h>
5262306a36Sopenharmony_ci#include <linux/ioport.h>
5362306a36Sopenharmony_ci#include <linux/skbuff.h>
5462306a36Sopenharmony_ci#include <linux/string.h>
5562306a36Sopenharmony_ci#include <linux/init.h>
5662306a36Sopenharmony_ci#include <linux/crc32.h>
5762306a36Sopenharmony_ci#include <linux/zorro.h>
5862306a36Sopenharmony_ci#include <linux/bitops.h>
5962306a36Sopenharmony_ci
6062306a36Sopenharmony_ci#include <asm/byteorder.h>
6162306a36Sopenharmony_ci#include <asm/irq.h>
6262306a36Sopenharmony_ci#include <asm/amigaints.h>
6362306a36Sopenharmony_ci#include <asm/amigahw.h>
6462306a36Sopenharmony_ci
6562306a36Sopenharmony_ci#include "a2065.h"
6662306a36Sopenharmony_ci
6762306a36Sopenharmony_ci/* Transmit/Receive Ring Definitions */
6862306a36Sopenharmony_ci
6962306a36Sopenharmony_ci#define LANCE_LOG_TX_BUFFERS	(2)
7062306a36Sopenharmony_ci#define LANCE_LOG_RX_BUFFERS	(4)
7162306a36Sopenharmony_ci
7262306a36Sopenharmony_ci#define TX_RING_SIZE		(1 << LANCE_LOG_TX_BUFFERS)
7362306a36Sopenharmony_ci#define RX_RING_SIZE		(1 << LANCE_LOG_RX_BUFFERS)
7462306a36Sopenharmony_ci
7562306a36Sopenharmony_ci#define TX_RING_MOD_MASK	(TX_RING_SIZE - 1)
7662306a36Sopenharmony_ci#define RX_RING_MOD_MASK	(RX_RING_SIZE - 1)
7762306a36Sopenharmony_ci
7862306a36Sopenharmony_ci#define PKT_BUF_SIZE		(1544)
7962306a36Sopenharmony_ci#define RX_BUFF_SIZE            PKT_BUF_SIZE
8062306a36Sopenharmony_ci#define TX_BUFF_SIZE            PKT_BUF_SIZE
8162306a36Sopenharmony_ci
8262306a36Sopenharmony_ci/* Layout of the Lance's RAM Buffer */
8362306a36Sopenharmony_ci
8462306a36Sopenharmony_cistruct lance_init_block {
8562306a36Sopenharmony_ci	unsigned short mode;		/* Pre-set mode (reg. 15) */
8662306a36Sopenharmony_ci	unsigned char phys_addr[6];     /* Physical ethernet address */
8762306a36Sopenharmony_ci	unsigned filter[2];		/* Multicast filter. */
8862306a36Sopenharmony_ci
8962306a36Sopenharmony_ci	/* Receive and transmit ring base, along with extra bits. */
9062306a36Sopenharmony_ci	unsigned short rx_ptr;		/* receive descriptor addr */
9162306a36Sopenharmony_ci	unsigned short rx_len;		/* receive len and high addr */
9262306a36Sopenharmony_ci	unsigned short tx_ptr;		/* transmit descriptor addr */
9362306a36Sopenharmony_ci	unsigned short tx_len;		/* transmit len and high addr */
9462306a36Sopenharmony_ci
9562306a36Sopenharmony_ci	/* The Tx and Rx ring entries must aligned on 8-byte boundaries. */
9662306a36Sopenharmony_ci	struct lance_rx_desc brx_ring[RX_RING_SIZE];
9762306a36Sopenharmony_ci	struct lance_tx_desc btx_ring[TX_RING_SIZE];
9862306a36Sopenharmony_ci
9962306a36Sopenharmony_ci	char rx_buf[RX_RING_SIZE][RX_BUFF_SIZE];
10062306a36Sopenharmony_ci	char tx_buf[TX_RING_SIZE][TX_BUFF_SIZE];
10162306a36Sopenharmony_ci};
10262306a36Sopenharmony_ci
10362306a36Sopenharmony_ci/* Private Device Data */
10462306a36Sopenharmony_ci
10562306a36Sopenharmony_cistruct lance_private {
10662306a36Sopenharmony_ci	char *name;
10762306a36Sopenharmony_ci	volatile struct lance_regs *ll;
10862306a36Sopenharmony_ci	volatile struct lance_init_block *init_block;	    /* Hosts view */
10962306a36Sopenharmony_ci	volatile struct lance_init_block *lance_init_block; /* Lance view */
11062306a36Sopenharmony_ci
11162306a36Sopenharmony_ci	int rx_new, tx_new;
11262306a36Sopenharmony_ci	int rx_old, tx_old;
11362306a36Sopenharmony_ci
11462306a36Sopenharmony_ci	int lance_log_rx_bufs, lance_log_tx_bufs;
11562306a36Sopenharmony_ci	int rx_ring_mod_mask, tx_ring_mod_mask;
11662306a36Sopenharmony_ci
11762306a36Sopenharmony_ci	int tpe;		      /* cable-selection is TPE */
11862306a36Sopenharmony_ci	int auto_select;	      /* cable-selection by carrier */
11962306a36Sopenharmony_ci	unsigned short busmaster_regval;
12062306a36Sopenharmony_ci
12162306a36Sopenharmony_ci	struct timer_list         multicast_timer;
12262306a36Sopenharmony_ci	struct net_device	  *dev;
12362306a36Sopenharmony_ci};
12462306a36Sopenharmony_ci
12562306a36Sopenharmony_ci#define LANCE_ADDR(x) ((int)(x) & ~0xff000000)
12662306a36Sopenharmony_ci
12762306a36Sopenharmony_ci/* Load the CSR registers */
12862306a36Sopenharmony_cistatic void load_csrs(struct lance_private *lp)
12962306a36Sopenharmony_ci{
13062306a36Sopenharmony_ci	volatile struct lance_regs *ll = lp->ll;
13162306a36Sopenharmony_ci	volatile struct lance_init_block *aib = lp->lance_init_block;
13262306a36Sopenharmony_ci	int leptr = LANCE_ADDR(aib);
13362306a36Sopenharmony_ci
13462306a36Sopenharmony_ci	ll->rap = LE_CSR1;
13562306a36Sopenharmony_ci	ll->rdp = (leptr & 0xFFFF);
13662306a36Sopenharmony_ci	ll->rap = LE_CSR2;
13762306a36Sopenharmony_ci	ll->rdp = leptr >> 16;
13862306a36Sopenharmony_ci	ll->rap = LE_CSR3;
13962306a36Sopenharmony_ci	ll->rdp = lp->busmaster_regval;
14062306a36Sopenharmony_ci
14162306a36Sopenharmony_ci	/* Point back to csr0 */
14262306a36Sopenharmony_ci	ll->rap = LE_CSR0;
14362306a36Sopenharmony_ci}
14462306a36Sopenharmony_ci
14562306a36Sopenharmony_ci/* Setup the Lance Rx and Tx rings */
14662306a36Sopenharmony_cistatic void lance_init_ring(struct net_device *dev)
14762306a36Sopenharmony_ci{
14862306a36Sopenharmony_ci	struct lance_private *lp = netdev_priv(dev);
14962306a36Sopenharmony_ci	volatile struct lance_init_block *ib = lp->init_block;
15062306a36Sopenharmony_ci	volatile struct lance_init_block *aib = lp->lance_init_block;
15162306a36Sopenharmony_ci					/* for LANCE_ADDR computations */
15262306a36Sopenharmony_ci	int leptr;
15362306a36Sopenharmony_ci	int i;
15462306a36Sopenharmony_ci
15562306a36Sopenharmony_ci	/* Lock out other processes while setting up hardware */
15662306a36Sopenharmony_ci	netif_stop_queue(dev);
15762306a36Sopenharmony_ci	lp->rx_new = lp->tx_new = 0;
15862306a36Sopenharmony_ci	lp->rx_old = lp->tx_old = 0;
15962306a36Sopenharmony_ci
16062306a36Sopenharmony_ci	ib->mode = 0;
16162306a36Sopenharmony_ci
16262306a36Sopenharmony_ci	/* Copy the ethernet address to the lance init block
16362306a36Sopenharmony_ci	 * Note that on the sparc you need to swap the ethernet address.
16462306a36Sopenharmony_ci	 */
16562306a36Sopenharmony_ci	ib->phys_addr[0] = dev->dev_addr[1];
16662306a36Sopenharmony_ci	ib->phys_addr[1] = dev->dev_addr[0];
16762306a36Sopenharmony_ci	ib->phys_addr[2] = dev->dev_addr[3];
16862306a36Sopenharmony_ci	ib->phys_addr[3] = dev->dev_addr[2];
16962306a36Sopenharmony_ci	ib->phys_addr[4] = dev->dev_addr[5];
17062306a36Sopenharmony_ci	ib->phys_addr[5] = dev->dev_addr[4];
17162306a36Sopenharmony_ci
17262306a36Sopenharmony_ci	/* Setup the Tx ring entries */
17362306a36Sopenharmony_ci	netdev_dbg(dev, "TX rings:\n");
17462306a36Sopenharmony_ci	for (i = 0; i <= 1 << lp->lance_log_tx_bufs; i++) {
17562306a36Sopenharmony_ci		leptr = LANCE_ADDR(&aib->tx_buf[i][0]);
17662306a36Sopenharmony_ci		ib->btx_ring[i].tmd0      = leptr;
17762306a36Sopenharmony_ci		ib->btx_ring[i].tmd1_hadr = leptr >> 16;
17862306a36Sopenharmony_ci		ib->btx_ring[i].tmd1_bits = 0;
17962306a36Sopenharmony_ci		ib->btx_ring[i].length    = 0xf000; /* The ones required by tmd2 */
18062306a36Sopenharmony_ci		ib->btx_ring[i].misc      = 0;
18162306a36Sopenharmony_ci		if (i < 3)
18262306a36Sopenharmony_ci			netdev_dbg(dev, "%d: 0x%08x\n", i, leptr);
18362306a36Sopenharmony_ci	}
18462306a36Sopenharmony_ci
18562306a36Sopenharmony_ci	/* Setup the Rx ring entries */
18662306a36Sopenharmony_ci	netdev_dbg(dev, "RX rings:\n");
18762306a36Sopenharmony_ci	for (i = 0; i < 1 << lp->lance_log_rx_bufs; i++) {
18862306a36Sopenharmony_ci		leptr = LANCE_ADDR(&aib->rx_buf[i][0]);
18962306a36Sopenharmony_ci
19062306a36Sopenharmony_ci		ib->brx_ring[i].rmd0      = leptr;
19162306a36Sopenharmony_ci		ib->brx_ring[i].rmd1_hadr = leptr >> 16;
19262306a36Sopenharmony_ci		ib->brx_ring[i].rmd1_bits = LE_R1_OWN;
19362306a36Sopenharmony_ci		ib->brx_ring[i].length    = -RX_BUFF_SIZE | 0xf000;
19462306a36Sopenharmony_ci		ib->brx_ring[i].mblength  = 0;
19562306a36Sopenharmony_ci		if (i < 3)
19662306a36Sopenharmony_ci			netdev_dbg(dev, "%d: 0x%08x\n", i, leptr);
19762306a36Sopenharmony_ci	}
19862306a36Sopenharmony_ci
19962306a36Sopenharmony_ci	/* Setup the initialization block */
20062306a36Sopenharmony_ci
20162306a36Sopenharmony_ci	/* Setup rx descriptor pointer */
20262306a36Sopenharmony_ci	leptr = LANCE_ADDR(&aib->brx_ring);
20362306a36Sopenharmony_ci	ib->rx_len = (lp->lance_log_rx_bufs << 13) | (leptr >> 16);
20462306a36Sopenharmony_ci	ib->rx_ptr = leptr;
20562306a36Sopenharmony_ci	netdev_dbg(dev, "RX ptr: %08x\n", leptr);
20662306a36Sopenharmony_ci
20762306a36Sopenharmony_ci	/* Setup tx descriptor pointer */
20862306a36Sopenharmony_ci	leptr = LANCE_ADDR(&aib->btx_ring);
20962306a36Sopenharmony_ci	ib->tx_len = (lp->lance_log_tx_bufs << 13) | (leptr >> 16);
21062306a36Sopenharmony_ci	ib->tx_ptr = leptr;
21162306a36Sopenharmony_ci	netdev_dbg(dev, "TX ptr: %08x\n", leptr);
21262306a36Sopenharmony_ci
21362306a36Sopenharmony_ci	/* Clear the multicast filter */
21462306a36Sopenharmony_ci	ib->filter[0] = 0;
21562306a36Sopenharmony_ci	ib->filter[1] = 0;
21662306a36Sopenharmony_ci}
21762306a36Sopenharmony_ci
21862306a36Sopenharmony_cistatic int init_restart_lance(struct lance_private *lp)
21962306a36Sopenharmony_ci{
22062306a36Sopenharmony_ci	volatile struct lance_regs *ll = lp->ll;
22162306a36Sopenharmony_ci	int i;
22262306a36Sopenharmony_ci
22362306a36Sopenharmony_ci	ll->rap = LE_CSR0;
22462306a36Sopenharmony_ci	ll->rdp = LE_C0_INIT;
22562306a36Sopenharmony_ci
22662306a36Sopenharmony_ci	/* Wait for the lance to complete initialization */
22762306a36Sopenharmony_ci	for (i = 0; (i < 100) && !(ll->rdp & (LE_C0_ERR | LE_C0_IDON)); i++)
22862306a36Sopenharmony_ci		barrier();
22962306a36Sopenharmony_ci	if ((i == 100) || (ll->rdp & LE_C0_ERR)) {
23062306a36Sopenharmony_ci		pr_err("unopened after %d ticks, csr0=%04x\n", i, ll->rdp);
23162306a36Sopenharmony_ci		return -EIO;
23262306a36Sopenharmony_ci	}
23362306a36Sopenharmony_ci
23462306a36Sopenharmony_ci	/* Clear IDON by writing a "1", enable interrupts and start lance */
23562306a36Sopenharmony_ci	ll->rdp = LE_C0_IDON;
23662306a36Sopenharmony_ci	ll->rdp = LE_C0_INEA | LE_C0_STRT;
23762306a36Sopenharmony_ci
23862306a36Sopenharmony_ci	return 0;
23962306a36Sopenharmony_ci}
24062306a36Sopenharmony_ci
24162306a36Sopenharmony_cistatic int lance_rx(struct net_device *dev)
24262306a36Sopenharmony_ci{
24362306a36Sopenharmony_ci	struct lance_private *lp = netdev_priv(dev);
24462306a36Sopenharmony_ci	volatile struct lance_init_block *ib = lp->init_block;
24562306a36Sopenharmony_ci	volatile struct lance_regs *ll = lp->ll;
24662306a36Sopenharmony_ci	volatile struct lance_rx_desc *rd;
24762306a36Sopenharmony_ci	unsigned char bits;
24862306a36Sopenharmony_ci
24962306a36Sopenharmony_ci#ifdef TEST_HITS
25062306a36Sopenharmony_ci	int i;
25162306a36Sopenharmony_ci	char buf[RX_RING_SIZE + 1];
25262306a36Sopenharmony_ci
25362306a36Sopenharmony_ci	for (i = 0; i < RX_RING_SIZE; i++) {
25462306a36Sopenharmony_ci		char r1_own = ib->brx_ring[i].rmd1_bits & LE_R1_OWN;
25562306a36Sopenharmony_ci		if (i == lp->rx_new)
25662306a36Sopenharmony_ci			buf[i] = r1_own ? '_' : 'X';
25762306a36Sopenharmony_ci		else
25862306a36Sopenharmony_ci			buf[i] = r1_own ? '.' : '1';
25962306a36Sopenharmony_ci	}
26062306a36Sopenharmony_ci	buf[RX_RING_SIZE] = 0;
26162306a36Sopenharmony_ci
26262306a36Sopenharmony_ci	pr_debug("RxRing TestHits: [%s]\n", buf);
26362306a36Sopenharmony_ci#endif
26462306a36Sopenharmony_ci
26562306a36Sopenharmony_ci	ll->rdp = LE_C0_RINT | LE_C0_INEA;
26662306a36Sopenharmony_ci	for (rd = &ib->brx_ring[lp->rx_new];
26762306a36Sopenharmony_ci	     !((bits = rd->rmd1_bits) & LE_R1_OWN);
26862306a36Sopenharmony_ci	     rd = &ib->brx_ring[lp->rx_new]) {
26962306a36Sopenharmony_ci
27062306a36Sopenharmony_ci		/* We got an incomplete frame? */
27162306a36Sopenharmony_ci		if ((bits & LE_R1_POK) != LE_R1_POK) {
27262306a36Sopenharmony_ci			dev->stats.rx_over_errors++;
27362306a36Sopenharmony_ci			dev->stats.rx_errors++;
27462306a36Sopenharmony_ci			continue;
27562306a36Sopenharmony_ci		} else if (bits & LE_R1_ERR) {
27662306a36Sopenharmony_ci			/* Count only the end frame as a rx error,
27762306a36Sopenharmony_ci			 * not the beginning
27862306a36Sopenharmony_ci			 */
27962306a36Sopenharmony_ci			if (bits & LE_R1_BUF)
28062306a36Sopenharmony_ci				dev->stats.rx_fifo_errors++;
28162306a36Sopenharmony_ci			if (bits & LE_R1_CRC)
28262306a36Sopenharmony_ci				dev->stats.rx_crc_errors++;
28362306a36Sopenharmony_ci			if (bits & LE_R1_OFL)
28462306a36Sopenharmony_ci				dev->stats.rx_over_errors++;
28562306a36Sopenharmony_ci			if (bits & LE_R1_FRA)
28662306a36Sopenharmony_ci				dev->stats.rx_frame_errors++;
28762306a36Sopenharmony_ci			if (bits & LE_R1_EOP)
28862306a36Sopenharmony_ci				dev->stats.rx_errors++;
28962306a36Sopenharmony_ci		} else {
29062306a36Sopenharmony_ci			int len = (rd->mblength & 0xfff) - 4;
29162306a36Sopenharmony_ci			struct sk_buff *skb = netdev_alloc_skb(dev, len + 2);
29262306a36Sopenharmony_ci
29362306a36Sopenharmony_ci			if (!skb) {
29462306a36Sopenharmony_ci				dev->stats.rx_dropped++;
29562306a36Sopenharmony_ci				rd->mblength = 0;
29662306a36Sopenharmony_ci				rd->rmd1_bits = LE_R1_OWN;
29762306a36Sopenharmony_ci				lp->rx_new = (lp->rx_new + 1) & lp->rx_ring_mod_mask;
29862306a36Sopenharmony_ci				return 0;
29962306a36Sopenharmony_ci			}
30062306a36Sopenharmony_ci
30162306a36Sopenharmony_ci			skb_reserve(skb, 2);		/* 16 byte align */
30262306a36Sopenharmony_ci			skb_put(skb, len);		/* make room */
30362306a36Sopenharmony_ci			skb_copy_to_linear_data(skb,
30462306a36Sopenharmony_ci				 (unsigned char *)&ib->rx_buf[lp->rx_new][0],
30562306a36Sopenharmony_ci				 len);
30662306a36Sopenharmony_ci			skb->protocol = eth_type_trans(skb, dev);
30762306a36Sopenharmony_ci			netif_rx(skb);
30862306a36Sopenharmony_ci			dev->stats.rx_packets++;
30962306a36Sopenharmony_ci			dev->stats.rx_bytes += len;
31062306a36Sopenharmony_ci		}
31162306a36Sopenharmony_ci
31262306a36Sopenharmony_ci		/* Return the packet to the pool */
31362306a36Sopenharmony_ci		rd->mblength = 0;
31462306a36Sopenharmony_ci		rd->rmd1_bits = LE_R1_OWN;
31562306a36Sopenharmony_ci		lp->rx_new = (lp->rx_new + 1) & lp->rx_ring_mod_mask;
31662306a36Sopenharmony_ci	}
31762306a36Sopenharmony_ci	return 0;
31862306a36Sopenharmony_ci}
31962306a36Sopenharmony_ci
32062306a36Sopenharmony_cistatic int lance_tx(struct net_device *dev)
32162306a36Sopenharmony_ci{
32262306a36Sopenharmony_ci	struct lance_private *lp = netdev_priv(dev);
32362306a36Sopenharmony_ci	volatile struct lance_init_block *ib = lp->init_block;
32462306a36Sopenharmony_ci	volatile struct lance_regs *ll = lp->ll;
32562306a36Sopenharmony_ci	volatile struct lance_tx_desc *td;
32662306a36Sopenharmony_ci	int i, j;
32762306a36Sopenharmony_ci	int status;
32862306a36Sopenharmony_ci
32962306a36Sopenharmony_ci	/* csr0 is 2f3 */
33062306a36Sopenharmony_ci	ll->rdp = LE_C0_TINT | LE_C0_INEA;
33162306a36Sopenharmony_ci	/* csr0 is 73 */
33262306a36Sopenharmony_ci
33362306a36Sopenharmony_ci	j = lp->tx_old;
33462306a36Sopenharmony_ci	for (i = j; i != lp->tx_new; i = j) {
33562306a36Sopenharmony_ci		td = &ib->btx_ring[i];
33662306a36Sopenharmony_ci
33762306a36Sopenharmony_ci		/* If we hit a packet not owned by us, stop */
33862306a36Sopenharmony_ci		if (td->tmd1_bits & LE_T1_OWN)
33962306a36Sopenharmony_ci			break;
34062306a36Sopenharmony_ci
34162306a36Sopenharmony_ci		if (td->tmd1_bits & LE_T1_ERR) {
34262306a36Sopenharmony_ci			status = td->misc;
34362306a36Sopenharmony_ci
34462306a36Sopenharmony_ci			dev->stats.tx_errors++;
34562306a36Sopenharmony_ci			if (status & LE_T3_RTY)
34662306a36Sopenharmony_ci				dev->stats.tx_aborted_errors++;
34762306a36Sopenharmony_ci			if (status & LE_T3_LCOL)
34862306a36Sopenharmony_ci				dev->stats.tx_window_errors++;
34962306a36Sopenharmony_ci
35062306a36Sopenharmony_ci			if (status & LE_T3_CLOS) {
35162306a36Sopenharmony_ci				dev->stats.tx_carrier_errors++;
35262306a36Sopenharmony_ci				if (lp->auto_select) {
35362306a36Sopenharmony_ci					lp->tpe = 1 - lp->tpe;
35462306a36Sopenharmony_ci					netdev_err(dev, "Carrier Lost, trying %s\n",
35562306a36Sopenharmony_ci						   lp->tpe ? "TPE" : "AUI");
35662306a36Sopenharmony_ci					/* Stop the lance */
35762306a36Sopenharmony_ci					ll->rap = LE_CSR0;
35862306a36Sopenharmony_ci					ll->rdp = LE_C0_STOP;
35962306a36Sopenharmony_ci					lance_init_ring(dev);
36062306a36Sopenharmony_ci					load_csrs(lp);
36162306a36Sopenharmony_ci					init_restart_lance(lp);
36262306a36Sopenharmony_ci					return 0;
36362306a36Sopenharmony_ci				}
36462306a36Sopenharmony_ci			}
36562306a36Sopenharmony_ci
36662306a36Sopenharmony_ci			/* buffer errors and underflows turn off
36762306a36Sopenharmony_ci			 * the transmitter, so restart the adapter
36862306a36Sopenharmony_ci			 */
36962306a36Sopenharmony_ci			if (status & (LE_T3_BUF | LE_T3_UFL)) {
37062306a36Sopenharmony_ci				dev->stats.tx_fifo_errors++;
37162306a36Sopenharmony_ci
37262306a36Sopenharmony_ci				netdev_err(dev, "Tx: ERR_BUF|ERR_UFL, restarting\n");
37362306a36Sopenharmony_ci				/* Stop the lance */
37462306a36Sopenharmony_ci				ll->rap = LE_CSR0;
37562306a36Sopenharmony_ci				ll->rdp = LE_C0_STOP;
37662306a36Sopenharmony_ci				lance_init_ring(dev);
37762306a36Sopenharmony_ci				load_csrs(lp);
37862306a36Sopenharmony_ci				init_restart_lance(lp);
37962306a36Sopenharmony_ci				return 0;
38062306a36Sopenharmony_ci			}
38162306a36Sopenharmony_ci		} else if ((td->tmd1_bits & LE_T1_POK) == LE_T1_POK) {
38262306a36Sopenharmony_ci			/* So we don't count the packet more than once. */
38362306a36Sopenharmony_ci			td->tmd1_bits &= ~(LE_T1_POK);
38462306a36Sopenharmony_ci
38562306a36Sopenharmony_ci			/* One collision before packet was sent. */
38662306a36Sopenharmony_ci			if (td->tmd1_bits & LE_T1_EONE)
38762306a36Sopenharmony_ci				dev->stats.collisions++;
38862306a36Sopenharmony_ci
38962306a36Sopenharmony_ci			/* More than one collision, be optimistic. */
39062306a36Sopenharmony_ci			if (td->tmd1_bits & LE_T1_EMORE)
39162306a36Sopenharmony_ci				dev->stats.collisions += 2;
39262306a36Sopenharmony_ci
39362306a36Sopenharmony_ci			dev->stats.tx_packets++;
39462306a36Sopenharmony_ci		}
39562306a36Sopenharmony_ci
39662306a36Sopenharmony_ci		j = (j + 1) & lp->tx_ring_mod_mask;
39762306a36Sopenharmony_ci	}
39862306a36Sopenharmony_ci	lp->tx_old = j;
39962306a36Sopenharmony_ci	ll->rdp = LE_C0_TINT | LE_C0_INEA;
40062306a36Sopenharmony_ci	return 0;
40162306a36Sopenharmony_ci}
40262306a36Sopenharmony_ci
40362306a36Sopenharmony_cistatic int lance_tx_buffs_avail(struct lance_private *lp)
40462306a36Sopenharmony_ci{
40562306a36Sopenharmony_ci	if (lp->tx_old <= lp->tx_new)
40662306a36Sopenharmony_ci		return lp->tx_old + lp->tx_ring_mod_mask - lp->tx_new;
40762306a36Sopenharmony_ci	return lp->tx_old - lp->tx_new - 1;
40862306a36Sopenharmony_ci}
40962306a36Sopenharmony_ci
41062306a36Sopenharmony_cistatic irqreturn_t lance_interrupt(int irq, void *dev_id)
41162306a36Sopenharmony_ci{
41262306a36Sopenharmony_ci	struct net_device *dev = dev_id;
41362306a36Sopenharmony_ci	struct lance_private *lp = netdev_priv(dev);
41462306a36Sopenharmony_ci	volatile struct lance_regs *ll = lp->ll;
41562306a36Sopenharmony_ci	int csr0;
41662306a36Sopenharmony_ci
41762306a36Sopenharmony_ci	ll->rap = LE_CSR0;		/* LANCE Controller Status */
41862306a36Sopenharmony_ci	csr0 = ll->rdp;
41962306a36Sopenharmony_ci
42062306a36Sopenharmony_ci	if (!(csr0 & LE_C0_INTR))	/* Check if any interrupt has */
42162306a36Sopenharmony_ci		return IRQ_NONE;	/* been generated by the Lance. */
42262306a36Sopenharmony_ci
42362306a36Sopenharmony_ci	/* Acknowledge all the interrupt sources ASAP */
42462306a36Sopenharmony_ci	ll->rdp = csr0 & ~(LE_C0_INEA | LE_C0_TDMD | LE_C0_STOP | LE_C0_STRT |
42562306a36Sopenharmony_ci			   LE_C0_INIT);
42662306a36Sopenharmony_ci
42762306a36Sopenharmony_ci	if (csr0 & LE_C0_ERR) {
42862306a36Sopenharmony_ci		/* Clear the error condition */
42962306a36Sopenharmony_ci		ll->rdp = LE_C0_BABL | LE_C0_ERR | LE_C0_MISS | LE_C0_INEA;
43062306a36Sopenharmony_ci	}
43162306a36Sopenharmony_ci
43262306a36Sopenharmony_ci	if (csr0 & LE_C0_RINT)
43362306a36Sopenharmony_ci		lance_rx(dev);
43462306a36Sopenharmony_ci
43562306a36Sopenharmony_ci	if (csr0 & LE_C0_TINT)
43662306a36Sopenharmony_ci		lance_tx(dev);
43762306a36Sopenharmony_ci
43862306a36Sopenharmony_ci	/* Log misc errors. */
43962306a36Sopenharmony_ci	if (csr0 & LE_C0_BABL)
44062306a36Sopenharmony_ci		dev->stats.tx_errors++;       /* Tx babble. */
44162306a36Sopenharmony_ci	if (csr0 & LE_C0_MISS)
44262306a36Sopenharmony_ci		dev->stats.rx_errors++;       /* Missed a Rx frame. */
44362306a36Sopenharmony_ci	if (csr0 & LE_C0_MERR) {
44462306a36Sopenharmony_ci		netdev_err(dev, "Bus master arbitration failure, status %04x\n",
44562306a36Sopenharmony_ci			   csr0);
44662306a36Sopenharmony_ci		/* Restart the chip. */
44762306a36Sopenharmony_ci		ll->rdp = LE_C0_STRT;
44862306a36Sopenharmony_ci	}
44962306a36Sopenharmony_ci
45062306a36Sopenharmony_ci	if (netif_queue_stopped(dev) && lance_tx_buffs_avail(lp) > 0)
45162306a36Sopenharmony_ci		netif_wake_queue(dev);
45262306a36Sopenharmony_ci
45362306a36Sopenharmony_ci	ll->rap = LE_CSR0;
45462306a36Sopenharmony_ci	ll->rdp = (LE_C0_BABL | LE_C0_CERR | LE_C0_MISS | LE_C0_MERR |
45562306a36Sopenharmony_ci		   LE_C0_IDON | LE_C0_INEA);
45662306a36Sopenharmony_ci	return IRQ_HANDLED;
45762306a36Sopenharmony_ci}
45862306a36Sopenharmony_ci
45962306a36Sopenharmony_cistatic int lance_open(struct net_device *dev)
46062306a36Sopenharmony_ci{
46162306a36Sopenharmony_ci	struct lance_private *lp = netdev_priv(dev);
46262306a36Sopenharmony_ci	volatile struct lance_regs *ll = lp->ll;
46362306a36Sopenharmony_ci	int ret;
46462306a36Sopenharmony_ci
46562306a36Sopenharmony_ci	/* Stop the Lance */
46662306a36Sopenharmony_ci	ll->rap = LE_CSR0;
46762306a36Sopenharmony_ci	ll->rdp = LE_C0_STOP;
46862306a36Sopenharmony_ci
46962306a36Sopenharmony_ci	/* Install the Interrupt handler */
47062306a36Sopenharmony_ci	ret = request_irq(IRQ_AMIGA_PORTS, lance_interrupt, IRQF_SHARED,
47162306a36Sopenharmony_ci			  dev->name, dev);
47262306a36Sopenharmony_ci	if (ret)
47362306a36Sopenharmony_ci		return ret;
47462306a36Sopenharmony_ci
47562306a36Sopenharmony_ci	load_csrs(lp);
47662306a36Sopenharmony_ci	lance_init_ring(dev);
47762306a36Sopenharmony_ci
47862306a36Sopenharmony_ci	netif_start_queue(dev);
47962306a36Sopenharmony_ci
48062306a36Sopenharmony_ci	return init_restart_lance(lp);
48162306a36Sopenharmony_ci}
48262306a36Sopenharmony_ci
48362306a36Sopenharmony_cistatic int lance_close(struct net_device *dev)
48462306a36Sopenharmony_ci{
48562306a36Sopenharmony_ci	struct lance_private *lp = netdev_priv(dev);
48662306a36Sopenharmony_ci	volatile struct lance_regs *ll = lp->ll;
48762306a36Sopenharmony_ci
48862306a36Sopenharmony_ci	netif_stop_queue(dev);
48962306a36Sopenharmony_ci	del_timer_sync(&lp->multicast_timer);
49062306a36Sopenharmony_ci
49162306a36Sopenharmony_ci	/* Stop the card */
49262306a36Sopenharmony_ci	ll->rap = LE_CSR0;
49362306a36Sopenharmony_ci	ll->rdp = LE_C0_STOP;
49462306a36Sopenharmony_ci
49562306a36Sopenharmony_ci	free_irq(IRQ_AMIGA_PORTS, dev);
49662306a36Sopenharmony_ci	return 0;
49762306a36Sopenharmony_ci}
49862306a36Sopenharmony_ci
49962306a36Sopenharmony_cistatic inline int lance_reset(struct net_device *dev)
50062306a36Sopenharmony_ci{
50162306a36Sopenharmony_ci	struct lance_private *lp = netdev_priv(dev);
50262306a36Sopenharmony_ci	volatile struct lance_regs *ll = lp->ll;
50362306a36Sopenharmony_ci	int status;
50462306a36Sopenharmony_ci
50562306a36Sopenharmony_ci	/* Stop the lance */
50662306a36Sopenharmony_ci	ll->rap = LE_CSR0;
50762306a36Sopenharmony_ci	ll->rdp = LE_C0_STOP;
50862306a36Sopenharmony_ci
50962306a36Sopenharmony_ci	load_csrs(lp);
51062306a36Sopenharmony_ci
51162306a36Sopenharmony_ci	lance_init_ring(dev);
51262306a36Sopenharmony_ci	netif_trans_update(dev); /* prevent tx timeout */
51362306a36Sopenharmony_ci	netif_start_queue(dev);
51462306a36Sopenharmony_ci
51562306a36Sopenharmony_ci	status = init_restart_lance(lp);
51662306a36Sopenharmony_ci	netdev_dbg(dev, "Lance restart=%d\n", status);
51762306a36Sopenharmony_ci
51862306a36Sopenharmony_ci	return status;
51962306a36Sopenharmony_ci}
52062306a36Sopenharmony_ci
52162306a36Sopenharmony_cistatic void lance_tx_timeout(struct net_device *dev, unsigned int txqueue)
52262306a36Sopenharmony_ci{
52362306a36Sopenharmony_ci	struct lance_private *lp = netdev_priv(dev);
52462306a36Sopenharmony_ci	volatile struct lance_regs *ll = lp->ll;
52562306a36Sopenharmony_ci
52662306a36Sopenharmony_ci	netdev_err(dev, "transmit timed out, status %04x, reset\n", ll->rdp);
52762306a36Sopenharmony_ci	lance_reset(dev);
52862306a36Sopenharmony_ci	netif_wake_queue(dev);
52962306a36Sopenharmony_ci}
53062306a36Sopenharmony_ci
53162306a36Sopenharmony_cistatic netdev_tx_t lance_start_xmit(struct sk_buff *skb,
53262306a36Sopenharmony_ci				    struct net_device *dev)
53362306a36Sopenharmony_ci{
53462306a36Sopenharmony_ci	struct lance_private *lp = netdev_priv(dev);
53562306a36Sopenharmony_ci	volatile struct lance_regs *ll = lp->ll;
53662306a36Sopenharmony_ci	volatile struct lance_init_block *ib = lp->init_block;
53762306a36Sopenharmony_ci	int entry, skblen;
53862306a36Sopenharmony_ci	int status = NETDEV_TX_OK;
53962306a36Sopenharmony_ci	unsigned long flags;
54062306a36Sopenharmony_ci
54162306a36Sopenharmony_ci	if (skb_padto(skb, ETH_ZLEN))
54262306a36Sopenharmony_ci		return NETDEV_TX_OK;
54362306a36Sopenharmony_ci	skblen = max_t(unsigned, skb->len, ETH_ZLEN);
54462306a36Sopenharmony_ci
54562306a36Sopenharmony_ci	local_irq_save(flags);
54662306a36Sopenharmony_ci
54762306a36Sopenharmony_ci	if (!lance_tx_buffs_avail(lp))
54862306a36Sopenharmony_ci		goto out_free;
54962306a36Sopenharmony_ci
55062306a36Sopenharmony_ci	/* dump the packet */
55162306a36Sopenharmony_ci	print_hex_dump_debug("skb->data: ", DUMP_PREFIX_NONE, 16, 1, skb->data,
55262306a36Sopenharmony_ci			     64, true);
55362306a36Sopenharmony_ci
55462306a36Sopenharmony_ci	entry = lp->tx_new & lp->tx_ring_mod_mask;
55562306a36Sopenharmony_ci	ib->btx_ring[entry].length = (-skblen) | 0xf000;
55662306a36Sopenharmony_ci	ib->btx_ring[entry].misc = 0;
55762306a36Sopenharmony_ci
55862306a36Sopenharmony_ci	skb_copy_from_linear_data(skb, (void *)&ib->tx_buf[entry][0], skblen);
55962306a36Sopenharmony_ci
56062306a36Sopenharmony_ci	/* Now, give the packet to the lance */
56162306a36Sopenharmony_ci	ib->btx_ring[entry].tmd1_bits = (LE_T1_POK | LE_T1_OWN);
56262306a36Sopenharmony_ci	lp->tx_new = (lp->tx_new+1) & lp->tx_ring_mod_mask;
56362306a36Sopenharmony_ci	dev->stats.tx_bytes += skblen;
56462306a36Sopenharmony_ci
56562306a36Sopenharmony_ci	if (lance_tx_buffs_avail(lp) <= 0)
56662306a36Sopenharmony_ci		netif_stop_queue(dev);
56762306a36Sopenharmony_ci
56862306a36Sopenharmony_ci	/* Kick the lance: transmit now */
56962306a36Sopenharmony_ci	ll->rdp = LE_C0_INEA | LE_C0_TDMD;
57062306a36Sopenharmony_ci out_free:
57162306a36Sopenharmony_ci	dev_kfree_skb(skb);
57262306a36Sopenharmony_ci
57362306a36Sopenharmony_ci	local_irq_restore(flags);
57462306a36Sopenharmony_ci
57562306a36Sopenharmony_ci	return status;
57662306a36Sopenharmony_ci}
57762306a36Sopenharmony_ci
57862306a36Sopenharmony_ci/* taken from the depca driver */
57962306a36Sopenharmony_cistatic void lance_load_multicast(struct net_device *dev)
58062306a36Sopenharmony_ci{
58162306a36Sopenharmony_ci	struct lance_private *lp = netdev_priv(dev);
58262306a36Sopenharmony_ci	volatile struct lance_init_block *ib = lp->init_block;
58362306a36Sopenharmony_ci	volatile u16 *mcast_table = (u16 *)&ib->filter;
58462306a36Sopenharmony_ci	struct netdev_hw_addr *ha;
58562306a36Sopenharmony_ci	u32 crc;
58662306a36Sopenharmony_ci
58762306a36Sopenharmony_ci	/* set all multicast bits */
58862306a36Sopenharmony_ci	if (dev->flags & IFF_ALLMULTI) {
58962306a36Sopenharmony_ci		ib->filter[0] = 0xffffffff;
59062306a36Sopenharmony_ci		ib->filter[1] = 0xffffffff;
59162306a36Sopenharmony_ci		return;
59262306a36Sopenharmony_ci	}
59362306a36Sopenharmony_ci	/* clear the multicast filter */
59462306a36Sopenharmony_ci	ib->filter[0] = 0;
59562306a36Sopenharmony_ci	ib->filter[1] = 0;
59662306a36Sopenharmony_ci
59762306a36Sopenharmony_ci	/* Add addresses */
59862306a36Sopenharmony_ci	netdev_for_each_mc_addr(ha, dev) {
59962306a36Sopenharmony_ci		crc = ether_crc_le(6, ha->addr);
60062306a36Sopenharmony_ci		crc = crc >> 26;
60162306a36Sopenharmony_ci		mcast_table[crc >> 4] |= 1 << (crc & 0xf);
60262306a36Sopenharmony_ci	}
60362306a36Sopenharmony_ci}
60462306a36Sopenharmony_ci
60562306a36Sopenharmony_cistatic void lance_set_multicast(struct net_device *dev)
60662306a36Sopenharmony_ci{
60762306a36Sopenharmony_ci	struct lance_private *lp = netdev_priv(dev);
60862306a36Sopenharmony_ci	volatile struct lance_init_block *ib = lp->init_block;
60962306a36Sopenharmony_ci	volatile struct lance_regs *ll = lp->ll;
61062306a36Sopenharmony_ci
61162306a36Sopenharmony_ci	if (!netif_running(dev))
61262306a36Sopenharmony_ci		return;
61362306a36Sopenharmony_ci
61462306a36Sopenharmony_ci	if (lp->tx_old != lp->tx_new) {
61562306a36Sopenharmony_ci		mod_timer(&lp->multicast_timer, jiffies + 4);
61662306a36Sopenharmony_ci		netif_wake_queue(dev);
61762306a36Sopenharmony_ci		return;
61862306a36Sopenharmony_ci	}
61962306a36Sopenharmony_ci
62062306a36Sopenharmony_ci	netif_stop_queue(dev);
62162306a36Sopenharmony_ci
62262306a36Sopenharmony_ci	ll->rap = LE_CSR0;
62362306a36Sopenharmony_ci	ll->rdp = LE_C0_STOP;
62462306a36Sopenharmony_ci	lance_init_ring(dev);
62562306a36Sopenharmony_ci
62662306a36Sopenharmony_ci	if (dev->flags & IFF_PROMISC) {
62762306a36Sopenharmony_ci		ib->mode |= LE_MO_PROM;
62862306a36Sopenharmony_ci	} else {
62962306a36Sopenharmony_ci		ib->mode &= ~LE_MO_PROM;
63062306a36Sopenharmony_ci		lance_load_multicast(dev);
63162306a36Sopenharmony_ci	}
63262306a36Sopenharmony_ci	load_csrs(lp);
63362306a36Sopenharmony_ci	init_restart_lance(lp);
63462306a36Sopenharmony_ci	netif_wake_queue(dev);
63562306a36Sopenharmony_ci}
63662306a36Sopenharmony_ci
63762306a36Sopenharmony_cistatic void lance_set_multicast_retry(struct timer_list *t)
63862306a36Sopenharmony_ci{
63962306a36Sopenharmony_ci	struct lance_private *lp = from_timer(lp, t, multicast_timer);
64062306a36Sopenharmony_ci
64162306a36Sopenharmony_ci	lance_set_multicast(lp->dev);
64262306a36Sopenharmony_ci}
64362306a36Sopenharmony_ci
64462306a36Sopenharmony_cistatic int a2065_init_one(struct zorro_dev *z,
64562306a36Sopenharmony_ci			  const struct zorro_device_id *ent);
64662306a36Sopenharmony_cistatic void a2065_remove_one(struct zorro_dev *z);
64762306a36Sopenharmony_ci
64862306a36Sopenharmony_ci
64962306a36Sopenharmony_cistatic const struct zorro_device_id a2065_zorro_tbl[] = {
65062306a36Sopenharmony_ci	{ ZORRO_PROD_CBM_A2065_1 },
65162306a36Sopenharmony_ci	{ ZORRO_PROD_CBM_A2065_2 },
65262306a36Sopenharmony_ci	{ ZORRO_PROD_AMERISTAR_A2065 },
65362306a36Sopenharmony_ci	{ 0 }
65462306a36Sopenharmony_ci};
65562306a36Sopenharmony_ciMODULE_DEVICE_TABLE(zorro, a2065_zorro_tbl);
65662306a36Sopenharmony_ci
65762306a36Sopenharmony_cistatic struct zorro_driver a2065_driver = {
65862306a36Sopenharmony_ci	.name		= "a2065",
65962306a36Sopenharmony_ci	.id_table	= a2065_zorro_tbl,
66062306a36Sopenharmony_ci	.probe		= a2065_init_one,
66162306a36Sopenharmony_ci	.remove		= a2065_remove_one,
66262306a36Sopenharmony_ci};
66362306a36Sopenharmony_ci
66462306a36Sopenharmony_cistatic const struct net_device_ops lance_netdev_ops = {
66562306a36Sopenharmony_ci	.ndo_open		= lance_open,
66662306a36Sopenharmony_ci	.ndo_stop		= lance_close,
66762306a36Sopenharmony_ci	.ndo_start_xmit		= lance_start_xmit,
66862306a36Sopenharmony_ci	.ndo_tx_timeout		= lance_tx_timeout,
66962306a36Sopenharmony_ci	.ndo_set_rx_mode	= lance_set_multicast,
67062306a36Sopenharmony_ci	.ndo_validate_addr	= eth_validate_addr,
67162306a36Sopenharmony_ci	.ndo_set_mac_address	= eth_mac_addr,
67262306a36Sopenharmony_ci};
67362306a36Sopenharmony_ci
67462306a36Sopenharmony_cistatic int a2065_init_one(struct zorro_dev *z,
67562306a36Sopenharmony_ci			  const struct zorro_device_id *ent)
67662306a36Sopenharmony_ci{
67762306a36Sopenharmony_ci	struct net_device *dev;
67862306a36Sopenharmony_ci	struct lance_private *priv;
67962306a36Sopenharmony_ci	unsigned long board = z->resource.start;
68062306a36Sopenharmony_ci	unsigned long base_addr = board + A2065_LANCE;
68162306a36Sopenharmony_ci	unsigned long mem_start = board + A2065_RAM;
68262306a36Sopenharmony_ci	struct resource *r1, *r2;
68362306a36Sopenharmony_ci	u8 addr[ETH_ALEN];
68462306a36Sopenharmony_ci	u32 serial;
68562306a36Sopenharmony_ci	int err;
68662306a36Sopenharmony_ci
68762306a36Sopenharmony_ci	r1 = request_mem_region(base_addr, sizeof(struct lance_regs),
68862306a36Sopenharmony_ci				"Am7990");
68962306a36Sopenharmony_ci	if (!r1)
69062306a36Sopenharmony_ci		return -EBUSY;
69162306a36Sopenharmony_ci	r2 = request_mem_region(mem_start, A2065_RAM_SIZE, "RAM");
69262306a36Sopenharmony_ci	if (!r2) {
69362306a36Sopenharmony_ci		release_mem_region(base_addr, sizeof(struct lance_regs));
69462306a36Sopenharmony_ci		return -EBUSY;
69562306a36Sopenharmony_ci	}
69662306a36Sopenharmony_ci
69762306a36Sopenharmony_ci	dev = alloc_etherdev(sizeof(struct lance_private));
69862306a36Sopenharmony_ci	if (!dev) {
69962306a36Sopenharmony_ci		release_mem_region(base_addr, sizeof(struct lance_regs));
70062306a36Sopenharmony_ci		release_mem_region(mem_start, A2065_RAM_SIZE);
70162306a36Sopenharmony_ci		return -ENOMEM;
70262306a36Sopenharmony_ci	}
70362306a36Sopenharmony_ci
70462306a36Sopenharmony_ci	priv = netdev_priv(dev);
70562306a36Sopenharmony_ci
70662306a36Sopenharmony_ci	r1->name = dev->name;
70762306a36Sopenharmony_ci	r2->name = dev->name;
70862306a36Sopenharmony_ci
70962306a36Sopenharmony_ci	serial = be32_to_cpu(z->rom.er_SerialNumber);
71062306a36Sopenharmony_ci	addr[0] = 0x00;
71162306a36Sopenharmony_ci	if (z->id != ZORRO_PROD_AMERISTAR_A2065) {	/* Commodore */
71262306a36Sopenharmony_ci		addr[1] = 0x80;
71362306a36Sopenharmony_ci		addr[2] = 0x10;
71462306a36Sopenharmony_ci	} else {					/* Ameristar */
71562306a36Sopenharmony_ci		addr[1] = 0x00;
71662306a36Sopenharmony_ci		addr[2] = 0x9f;
71762306a36Sopenharmony_ci	}
71862306a36Sopenharmony_ci	addr[3] = (serial >> 16) & 0xff;
71962306a36Sopenharmony_ci	addr[4] = (serial >> 8) & 0xff;
72062306a36Sopenharmony_ci	addr[5] = serial & 0xff;
72162306a36Sopenharmony_ci	eth_hw_addr_set(dev, addr);
72262306a36Sopenharmony_ci	dev->base_addr = (unsigned long)ZTWO_VADDR(base_addr);
72362306a36Sopenharmony_ci	dev->mem_start = (unsigned long)ZTWO_VADDR(mem_start);
72462306a36Sopenharmony_ci	dev->mem_end = dev->mem_start + A2065_RAM_SIZE;
72562306a36Sopenharmony_ci
72662306a36Sopenharmony_ci	priv->ll = (volatile struct lance_regs *)dev->base_addr;
72762306a36Sopenharmony_ci	priv->init_block = (struct lance_init_block *)dev->mem_start;
72862306a36Sopenharmony_ci	priv->lance_init_block = (struct lance_init_block *)A2065_RAM;
72962306a36Sopenharmony_ci	priv->auto_select = 0;
73062306a36Sopenharmony_ci	priv->busmaster_regval = LE_C3_BSWP;
73162306a36Sopenharmony_ci
73262306a36Sopenharmony_ci	priv->lance_log_rx_bufs = LANCE_LOG_RX_BUFFERS;
73362306a36Sopenharmony_ci	priv->lance_log_tx_bufs = LANCE_LOG_TX_BUFFERS;
73462306a36Sopenharmony_ci	priv->rx_ring_mod_mask = RX_RING_MOD_MASK;
73562306a36Sopenharmony_ci	priv->tx_ring_mod_mask = TX_RING_MOD_MASK;
73662306a36Sopenharmony_ci	priv->dev = dev;
73762306a36Sopenharmony_ci
73862306a36Sopenharmony_ci	dev->netdev_ops = &lance_netdev_ops;
73962306a36Sopenharmony_ci	dev->watchdog_timeo = 5*HZ;
74062306a36Sopenharmony_ci	dev->dma = 0;
74162306a36Sopenharmony_ci
74262306a36Sopenharmony_ci	timer_setup(&priv->multicast_timer, lance_set_multicast_retry, 0);
74362306a36Sopenharmony_ci
74462306a36Sopenharmony_ci	err = register_netdev(dev);
74562306a36Sopenharmony_ci	if (err) {
74662306a36Sopenharmony_ci		release_mem_region(base_addr, sizeof(struct lance_regs));
74762306a36Sopenharmony_ci		release_mem_region(mem_start, A2065_RAM_SIZE);
74862306a36Sopenharmony_ci		free_netdev(dev);
74962306a36Sopenharmony_ci		return err;
75062306a36Sopenharmony_ci	}
75162306a36Sopenharmony_ci	zorro_set_drvdata(z, dev);
75262306a36Sopenharmony_ci
75362306a36Sopenharmony_ci	netdev_info(dev, "A2065 at 0x%08lx, Ethernet Address %pM\n",
75462306a36Sopenharmony_ci		    board, dev->dev_addr);
75562306a36Sopenharmony_ci
75662306a36Sopenharmony_ci	return 0;
75762306a36Sopenharmony_ci}
75862306a36Sopenharmony_ci
75962306a36Sopenharmony_ci
76062306a36Sopenharmony_cistatic void a2065_remove_one(struct zorro_dev *z)
76162306a36Sopenharmony_ci{
76262306a36Sopenharmony_ci	struct net_device *dev = zorro_get_drvdata(z);
76362306a36Sopenharmony_ci
76462306a36Sopenharmony_ci	unregister_netdev(dev);
76562306a36Sopenharmony_ci	release_mem_region(ZTWO_PADDR(dev->base_addr),
76662306a36Sopenharmony_ci			   sizeof(struct lance_regs));
76762306a36Sopenharmony_ci	release_mem_region(ZTWO_PADDR(dev->mem_start), A2065_RAM_SIZE);
76862306a36Sopenharmony_ci	free_netdev(dev);
76962306a36Sopenharmony_ci}
77062306a36Sopenharmony_ci
77162306a36Sopenharmony_cistatic int __init a2065_init_module(void)
77262306a36Sopenharmony_ci{
77362306a36Sopenharmony_ci	return zorro_register_driver(&a2065_driver);
77462306a36Sopenharmony_ci}
77562306a36Sopenharmony_ci
77662306a36Sopenharmony_cistatic void __exit a2065_cleanup_module(void)
77762306a36Sopenharmony_ci{
77862306a36Sopenharmony_ci	zorro_unregister_driver(&a2065_driver);
77962306a36Sopenharmony_ci}
78062306a36Sopenharmony_ci
78162306a36Sopenharmony_cimodule_init(a2065_init_module);
78262306a36Sopenharmony_cimodule_exit(a2065_cleanup_module);
78362306a36Sopenharmony_ci
78462306a36Sopenharmony_ciMODULE_LICENSE("GPL");
785