11da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/*
21da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *  Amiga Linux/m68k Ariadne Ethernet Driver
31da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *
496de0e252cedffad61b3cb5e05662c591898e69aJan Engelhardt *  © Copyright 1995-2003 by Geert Uytterhoeven (geert@linux-m68k.org)
51da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *			     Peter De Schrijver (p2@mind.be)
61da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *
71da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *  ---------------------------------------------------------------------------
81da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *
91da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *  This program is based on
101da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *
111da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *	lance.c:	An AMD LANCE ethernet driver for linux.
121da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *			Written 1993-94 by Donald Becker.
131da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *
141da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *	Am79C960:	PCnet(tm)-ISA Single-Chip Ethernet Controller
151da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *			Advanced Micro Devices
161da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *			Publication #16907, Rev. B, Amendment/0, May 1994
171da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *
181da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *	MC68230:	Parallel Interface/Timer (PI/T)
191da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *			Motorola Semiconductors, December, 1983
201da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *
211da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *  ---------------------------------------------------------------------------
221da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *
231da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *  This file is subject to the terms and conditions of the GNU General Public
241da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *  License.  See the file COPYING in the main directory of the Linux
251da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *  distribution for more details.
261da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *
271da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *  ---------------------------------------------------------------------------
281da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *
291da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *  The Ariadne is a Zorro-II board made by Village Tronic. It contains:
301da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *
311da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *	- an Am79C960 PCnet-ISA Single-Chip Ethernet Controller with both
321da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *	  10BASE-2 (thin coax) and 10BASE-T (UTP) connectors
331da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *
341da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *	- an MC68230 Parallel Interface/Timer configured as 2 parallel ports
351da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */
361da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
377b5b0abdb6757011ab51eaf1227e3fcf3ab61d97Joe Perches#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
387b5b0abdb6757011ab51eaf1227e3fcf3ab61d97Joe Perches/*#define DEBUG*/
397b5b0abdb6757011ab51eaf1227e3fcf3ab61d97Joe Perches
401da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <linux/module.h>
411da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <linux/stddef.h>
421da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <linux/kernel.h>
431da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <linux/string.h>
441da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <linux/errno.h>
451da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <linux/ioport.h>
461da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <linux/netdevice.h>
471da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <linux/etherdevice.h>
481da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <linux/interrupt.h>
491da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <linux/skbuff.h>
501da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <linux/init.h>
511da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <linux/zorro.h>
521da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <linux/bitops.h>
531da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
541da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <asm/amigaints.h>
551da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <asm/amigahw.h>
561da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <asm/irq.h>
571da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
581da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include "ariadne.h"
591da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
601da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#ifdef ARIADNE_DEBUG
611da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsint ariadne_debug = ARIADNE_DEBUG;
621da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#else
631da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsint ariadne_debug = 1;
641da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#endif
651da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
667b5b0abdb6757011ab51eaf1227e3fcf3ab61d97Joe Perches/* Macros to Fix Endianness problems */
671da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
687b5b0abdb6757011ab51eaf1227e3fcf3ab61d97Joe Perches/* Swap the Bytes in a WORD */
697b5b0abdb6757011ab51eaf1227e3fcf3ab61d97Joe Perches#define swapw(x)	(((x >> 8) & 0x00ff) | ((x << 8) & 0xff00))
707b5b0abdb6757011ab51eaf1227e3fcf3ab61d97Joe Perches/* Get the Low BYTE in a WORD */
717b5b0abdb6757011ab51eaf1227e3fcf3ab61d97Joe Perches#define lowb(x)		(x & 0xff)
727b5b0abdb6757011ab51eaf1227e3fcf3ab61d97Joe Perches/* Get the Swapped High WORD in a LONG */
737b5b0abdb6757011ab51eaf1227e3fcf3ab61d97Joe Perches#define swhighw(x)	((((x) >> 8) & 0xff00) | (((x) >> 24) & 0x00ff))
747b5b0abdb6757011ab51eaf1227e3fcf3ab61d97Joe Perches/* Get the Swapped Low WORD in a LONG */
757b5b0abdb6757011ab51eaf1227e3fcf3ab61d97Joe Perches#define swloww(x)	((((x) << 8) & 0xff00) | (((x) >> 8) & 0x00ff))
761da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
777b5b0abdb6757011ab51eaf1227e3fcf3ab61d97Joe Perches/* Transmit/Receive Ring Definitions */
781da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
791da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define TX_RING_SIZE	5
801da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define RX_RING_SIZE	16
811da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
821da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define PKT_BUF_SIZE	1520
831da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
847b5b0abdb6757011ab51eaf1227e3fcf3ab61d97Joe Perches/* Private Device Data */
851da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
861da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstruct ariadne_private {
877b5b0abdb6757011ab51eaf1227e3fcf3ab61d97Joe Perches	volatile struct TDRE *tx_ring[TX_RING_SIZE];
887b5b0abdb6757011ab51eaf1227e3fcf3ab61d97Joe Perches	volatile struct RDRE *rx_ring[RX_RING_SIZE];
897b5b0abdb6757011ab51eaf1227e3fcf3ab61d97Joe Perches	volatile u_short *tx_buff[TX_RING_SIZE];
907b5b0abdb6757011ab51eaf1227e3fcf3ab61d97Joe Perches	volatile u_short *rx_buff[RX_RING_SIZE];
917b5b0abdb6757011ab51eaf1227e3fcf3ab61d97Joe Perches	int cur_tx, cur_rx;		/* The next free ring entry */
927b5b0abdb6757011ab51eaf1227e3fcf3ab61d97Joe Perches	int dirty_tx;			/* The ring entries to be free()ed */
937b5b0abdb6757011ab51eaf1227e3fcf3ab61d97Joe Perches	char tx_full;
941da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds};
951da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
967b5b0abdb6757011ab51eaf1227e3fcf3ab61d97Joe Perches/* Structure Created in the Ariadne's RAM Buffer */
971da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
981da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstruct lancedata {
997b5b0abdb6757011ab51eaf1227e3fcf3ab61d97Joe Perches	struct TDRE tx_ring[TX_RING_SIZE];
1007b5b0abdb6757011ab51eaf1227e3fcf3ab61d97Joe Perches	struct RDRE rx_ring[RX_RING_SIZE];
1017b5b0abdb6757011ab51eaf1227e3fcf3ab61d97Joe Perches	u_short tx_buff[TX_RING_SIZE][PKT_BUF_SIZE / sizeof(u_short)];
1027b5b0abdb6757011ab51eaf1227e3fcf3ab61d97Joe Perches	u_short rx_buff[RX_RING_SIZE][PKT_BUF_SIZE / sizeof(u_short)];
1031da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds};
1041da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
1051da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic void memcpyw(volatile u_short *dest, u_short *src, int len)
1061da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
1077b5b0abdb6757011ab51eaf1227e3fcf3ab61d97Joe Perches	while (len >= 2) {
1087b5b0abdb6757011ab51eaf1227e3fcf3ab61d97Joe Perches		*(dest++) = *(src++);
1097b5b0abdb6757011ab51eaf1227e3fcf3ab61d97Joe Perches		len -= 2;
1107b5b0abdb6757011ab51eaf1227e3fcf3ab61d97Joe Perches	}
1117b5b0abdb6757011ab51eaf1227e3fcf3ab61d97Joe Perches	if (len == 1)
1127b5b0abdb6757011ab51eaf1227e3fcf3ab61d97Joe Perches		*dest = (*(u_char *)src) << 8;
1131da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
1141da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
1157b5b0abdb6757011ab51eaf1227e3fcf3ab61d97Joe Perchesstatic void ariadne_init_ring(struct net_device *dev)
1167b5b0abdb6757011ab51eaf1227e3fcf3ab61d97Joe Perches{
1177b5b0abdb6757011ab51eaf1227e3fcf3ab61d97Joe Perches	struct ariadne_private *priv = netdev_priv(dev);
1187b5b0abdb6757011ab51eaf1227e3fcf3ab61d97Joe Perches	volatile struct lancedata *lancedata = (struct lancedata *)dev->mem_start;
1197b5b0abdb6757011ab51eaf1227e3fcf3ab61d97Joe Perches	int i;
1201da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
1217b5b0abdb6757011ab51eaf1227e3fcf3ab61d97Joe Perches	netif_stop_queue(dev);
1221da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
1237b5b0abdb6757011ab51eaf1227e3fcf3ab61d97Joe Perches	priv->tx_full = 0;
1247b5b0abdb6757011ab51eaf1227e3fcf3ab61d97Joe Perches	priv->cur_rx = priv->cur_tx = 0;
1257b5b0abdb6757011ab51eaf1227e3fcf3ab61d97Joe Perches	priv->dirty_tx = 0;
1267b5b0abdb6757011ab51eaf1227e3fcf3ab61d97Joe Perches
1277b5b0abdb6757011ab51eaf1227e3fcf3ab61d97Joe Perches	/* Set up TX Ring */
1287b5b0abdb6757011ab51eaf1227e3fcf3ab61d97Joe Perches	for (i = 0; i < TX_RING_SIZE; i++) {
1297b5b0abdb6757011ab51eaf1227e3fcf3ab61d97Joe Perches		volatile struct TDRE *t = &lancedata->tx_ring[i];
1307b5b0abdb6757011ab51eaf1227e3fcf3ab61d97Joe Perches		t->TMD0 = swloww(ARIADNE_RAM +
1317b5b0abdb6757011ab51eaf1227e3fcf3ab61d97Joe Perches				 offsetof(struct lancedata, tx_buff[i]));
1327b5b0abdb6757011ab51eaf1227e3fcf3ab61d97Joe Perches		t->TMD1 = swhighw(ARIADNE_RAM +
1337b5b0abdb6757011ab51eaf1227e3fcf3ab61d97Joe Perches				  offsetof(struct lancedata, tx_buff[i])) |
1347b5b0abdb6757011ab51eaf1227e3fcf3ab61d97Joe Perches			TF_STP | TF_ENP;
1357b5b0abdb6757011ab51eaf1227e3fcf3ab61d97Joe Perches		t->TMD2 = swapw((u_short)-PKT_BUF_SIZE);
1367b5b0abdb6757011ab51eaf1227e3fcf3ab61d97Joe Perches		t->TMD3 = 0;
1377b5b0abdb6757011ab51eaf1227e3fcf3ab61d97Joe Perches		priv->tx_ring[i] = &lancedata->tx_ring[i];
1387b5b0abdb6757011ab51eaf1227e3fcf3ab61d97Joe Perches		priv->tx_buff[i] = lancedata->tx_buff[i];
1397b5b0abdb6757011ab51eaf1227e3fcf3ab61d97Joe Perches		netdev_dbg(dev, "TX Entry %2d at %p, Buf at %p\n",
1407b5b0abdb6757011ab51eaf1227e3fcf3ab61d97Joe Perches			   i, &lancedata->tx_ring[i], lancedata->tx_buff[i]);
1417b5b0abdb6757011ab51eaf1227e3fcf3ab61d97Joe Perches	}
1421da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
1437b5b0abdb6757011ab51eaf1227e3fcf3ab61d97Joe Perches	/* Set up RX Ring */
1447b5b0abdb6757011ab51eaf1227e3fcf3ab61d97Joe Perches	for (i = 0; i < RX_RING_SIZE; i++) {
1457b5b0abdb6757011ab51eaf1227e3fcf3ab61d97Joe Perches		volatile struct RDRE *r = &lancedata->rx_ring[i];
1467b5b0abdb6757011ab51eaf1227e3fcf3ab61d97Joe Perches		r->RMD0 = swloww(ARIADNE_RAM +
1477b5b0abdb6757011ab51eaf1227e3fcf3ab61d97Joe Perches				 offsetof(struct lancedata, rx_buff[i]));
1487b5b0abdb6757011ab51eaf1227e3fcf3ab61d97Joe Perches		r->RMD1 = swhighw(ARIADNE_RAM +
1497b5b0abdb6757011ab51eaf1227e3fcf3ab61d97Joe Perches				  offsetof(struct lancedata, rx_buff[i])) |
1507b5b0abdb6757011ab51eaf1227e3fcf3ab61d97Joe Perches			RF_OWN;
1517b5b0abdb6757011ab51eaf1227e3fcf3ab61d97Joe Perches		r->RMD2 = swapw((u_short)-PKT_BUF_SIZE);
1527b5b0abdb6757011ab51eaf1227e3fcf3ab61d97Joe Perches		r->RMD3 = 0x0000;
1537b5b0abdb6757011ab51eaf1227e3fcf3ab61d97Joe Perches		priv->rx_ring[i] = &lancedata->rx_ring[i];
1547b5b0abdb6757011ab51eaf1227e3fcf3ab61d97Joe Perches		priv->rx_buff[i] = lancedata->rx_buff[i];
1557b5b0abdb6757011ab51eaf1227e3fcf3ab61d97Joe Perches		netdev_dbg(dev, "RX Entry %2d at %p, Buf at %p\n",
1567b5b0abdb6757011ab51eaf1227e3fcf3ab61d97Joe Perches			   i, &lancedata->rx_ring[i], lancedata->rx_buff[i]);
1577b5b0abdb6757011ab51eaf1227e3fcf3ab61d97Joe Perches	}
1587b5b0abdb6757011ab51eaf1227e3fcf3ab61d97Joe Perches}
159f97b1f2a416045c7a9c7e62d575a809bc32c0f1eAlexander Beregalov
1607b5b0abdb6757011ab51eaf1227e3fcf3ab61d97Joe Perchesstatic int ariadne_rx(struct net_device *dev)
1611da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
1627b5b0abdb6757011ab51eaf1227e3fcf3ab61d97Joe Perches	struct ariadne_private *priv = netdev_priv(dev);
1637b5b0abdb6757011ab51eaf1227e3fcf3ab61d97Joe Perches	int entry = priv->cur_rx % RX_RING_SIZE;
1647b5b0abdb6757011ab51eaf1227e3fcf3ab61d97Joe Perches	int i;
1651da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
1667b5b0abdb6757011ab51eaf1227e3fcf3ab61d97Joe Perches	/* If we own the next entry, it's a new packet. Send it up */
1677b5b0abdb6757011ab51eaf1227e3fcf3ab61d97Joe Perches	while (!(lowb(priv->rx_ring[entry]->RMD1) & RF_OWN)) {
1687b5b0abdb6757011ab51eaf1227e3fcf3ab61d97Joe Perches		int status = lowb(priv->rx_ring[entry]->RMD1);
1697b5b0abdb6757011ab51eaf1227e3fcf3ab61d97Joe Perches
1707b5b0abdb6757011ab51eaf1227e3fcf3ab61d97Joe Perches		if (status != (RF_STP | RF_ENP)) {	/* There was an error */
1717b5b0abdb6757011ab51eaf1227e3fcf3ab61d97Joe Perches			/* There is a tricky error noted by
1727b5b0abdb6757011ab51eaf1227e3fcf3ab61d97Joe Perches			 * John Murphy <murf@perftech.com> to Russ Nelson:
1737b5b0abdb6757011ab51eaf1227e3fcf3ab61d97Joe Perches			 * Even with full-sized buffers it's possible for a
1747b5b0abdb6757011ab51eaf1227e3fcf3ab61d97Joe Perches			 * jabber packet to use two buffers, with only the
1757b5b0abdb6757011ab51eaf1227e3fcf3ab61d97Joe Perches			 * last correctly noting the error
1767b5b0abdb6757011ab51eaf1227e3fcf3ab61d97Joe Perches			 */
1777b5b0abdb6757011ab51eaf1227e3fcf3ab61d97Joe Perches			/* Only count a general error at the end of a packet */
1787b5b0abdb6757011ab51eaf1227e3fcf3ab61d97Joe Perches			if (status & RF_ENP)
1797b5b0abdb6757011ab51eaf1227e3fcf3ab61d97Joe Perches				dev->stats.rx_errors++;
1807b5b0abdb6757011ab51eaf1227e3fcf3ab61d97Joe Perches			if (status & RF_FRAM)
1817b5b0abdb6757011ab51eaf1227e3fcf3ab61d97Joe Perches				dev->stats.rx_frame_errors++;
1827b5b0abdb6757011ab51eaf1227e3fcf3ab61d97Joe Perches			if (status & RF_OFLO)
1837b5b0abdb6757011ab51eaf1227e3fcf3ab61d97Joe Perches				dev->stats.rx_over_errors++;
1847b5b0abdb6757011ab51eaf1227e3fcf3ab61d97Joe Perches			if (status & RF_CRC)
1857b5b0abdb6757011ab51eaf1227e3fcf3ab61d97Joe Perches				dev->stats.rx_crc_errors++;
1867b5b0abdb6757011ab51eaf1227e3fcf3ab61d97Joe Perches			if (status & RF_BUFF)
1877b5b0abdb6757011ab51eaf1227e3fcf3ab61d97Joe Perches				dev->stats.rx_fifo_errors++;
1887b5b0abdb6757011ab51eaf1227e3fcf3ab61d97Joe Perches			priv->rx_ring[entry]->RMD1 &= 0xff00 | RF_STP | RF_ENP;
1897b5b0abdb6757011ab51eaf1227e3fcf3ab61d97Joe Perches		} else {
1907b5b0abdb6757011ab51eaf1227e3fcf3ab61d97Joe Perches			/* Malloc up new buffer, compatible with net-3 */
1917b5b0abdb6757011ab51eaf1227e3fcf3ab61d97Joe Perches			short pkt_len = swapw(priv->rx_ring[entry]->RMD3);
1927b5b0abdb6757011ab51eaf1227e3fcf3ab61d97Joe Perches			struct sk_buff *skb;
1937b5b0abdb6757011ab51eaf1227e3fcf3ab61d97Joe Perches
1941d266430546acf01438ae42d0a7370db4817e2adPradeep A Dalvi			skb = netdev_alloc_skb(dev, pkt_len + 2);
1957b5b0abdb6757011ab51eaf1227e3fcf3ab61d97Joe Perches			if (skb == NULL) {
1967b5b0abdb6757011ab51eaf1227e3fcf3ab61d97Joe Perches				netdev_warn(dev, "Memory squeeze, deferring packet\n");
1977b5b0abdb6757011ab51eaf1227e3fcf3ab61d97Joe Perches				for (i = 0; i < RX_RING_SIZE; i++)
1987b5b0abdb6757011ab51eaf1227e3fcf3ab61d97Joe Perches					if (lowb(priv->rx_ring[(entry + i) % RX_RING_SIZE]->RMD1) & RF_OWN)
1997b5b0abdb6757011ab51eaf1227e3fcf3ab61d97Joe Perches						break;
2007b5b0abdb6757011ab51eaf1227e3fcf3ab61d97Joe Perches
2017b5b0abdb6757011ab51eaf1227e3fcf3ab61d97Joe Perches				if (i > RX_RING_SIZE - 2) {
2027b5b0abdb6757011ab51eaf1227e3fcf3ab61d97Joe Perches					dev->stats.rx_dropped++;
2037b5b0abdb6757011ab51eaf1227e3fcf3ab61d97Joe Perches					priv->rx_ring[entry]->RMD1 |= RF_OWN;
2047b5b0abdb6757011ab51eaf1227e3fcf3ab61d97Joe Perches					priv->cur_rx++;
2057b5b0abdb6757011ab51eaf1227e3fcf3ab61d97Joe Perches				}
2067b5b0abdb6757011ab51eaf1227e3fcf3ab61d97Joe Perches				break;
2077b5b0abdb6757011ab51eaf1227e3fcf3ab61d97Joe Perches			}
2087b5b0abdb6757011ab51eaf1227e3fcf3ab61d97Joe Perches
2097b5b0abdb6757011ab51eaf1227e3fcf3ab61d97Joe Perches
2107b5b0abdb6757011ab51eaf1227e3fcf3ab61d97Joe Perches			skb_reserve(skb, 2);	/* 16 byte align */
2117b5b0abdb6757011ab51eaf1227e3fcf3ab61d97Joe Perches			skb_put(skb, pkt_len);	/* Make room */
2127b5b0abdb6757011ab51eaf1227e3fcf3ab61d97Joe Perches			skb_copy_to_linear_data(skb,
2137b5b0abdb6757011ab51eaf1227e3fcf3ab61d97Joe Perches						(const void *)priv->rx_buff[entry],
2147b5b0abdb6757011ab51eaf1227e3fcf3ab61d97Joe Perches						pkt_len);
2157b5b0abdb6757011ab51eaf1227e3fcf3ab61d97Joe Perches			skb->protocol = eth_type_trans(skb, dev);
2167b5b0abdb6757011ab51eaf1227e3fcf3ab61d97Joe Perches			netdev_dbg(dev, "RX pkt type 0x%04x from %pM to %pM data 0x%08x len %d\n",
2177b5b0abdb6757011ab51eaf1227e3fcf3ab61d97Joe Perches				   ((u_short *)skb->data)[6],
2187b5b0abdb6757011ab51eaf1227e3fcf3ab61d97Joe Perches				   skb->data + 6, skb->data,
2197b5b0abdb6757011ab51eaf1227e3fcf3ab61d97Joe Perches				   (int)skb->data, (int)skb->len);
2207b5b0abdb6757011ab51eaf1227e3fcf3ab61d97Joe Perches
2217b5b0abdb6757011ab51eaf1227e3fcf3ab61d97Joe Perches			netif_rx(skb);
2227b5b0abdb6757011ab51eaf1227e3fcf3ab61d97Joe Perches			dev->stats.rx_packets++;
2237b5b0abdb6757011ab51eaf1227e3fcf3ab61d97Joe Perches			dev->stats.rx_bytes += pkt_len;
2247b5b0abdb6757011ab51eaf1227e3fcf3ab61d97Joe Perches		}
2251da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
2267b5b0abdb6757011ab51eaf1227e3fcf3ab61d97Joe Perches		priv->rx_ring[entry]->RMD1 |= RF_OWN;
2277b5b0abdb6757011ab51eaf1227e3fcf3ab61d97Joe Perches		entry = (++priv->cur_rx) % RX_RING_SIZE;
2287b5b0abdb6757011ab51eaf1227e3fcf3ab61d97Joe Perches	}
2291da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
2307b5b0abdb6757011ab51eaf1227e3fcf3ab61d97Joe Perches	priv->cur_rx = priv->cur_rx % RX_RING_SIZE;
2311da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
2327b5b0abdb6757011ab51eaf1227e3fcf3ab61d97Joe Perches	/* We should check that at least two ring entries are free.
2337b5b0abdb6757011ab51eaf1227e3fcf3ab61d97Joe Perches	 * If not, we should free one and mark stats->rx_dropped++
2347b5b0abdb6757011ab51eaf1227e3fcf3ab61d97Joe Perches	 */
2351da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
2367b5b0abdb6757011ab51eaf1227e3fcf3ab61d97Joe Perches	return 0;
2371da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
2381da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
2397b5b0abdb6757011ab51eaf1227e3fcf3ab61d97Joe Perchesstatic irqreturn_t ariadne_interrupt(int irq, void *data)
2401da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
2417b5b0abdb6757011ab51eaf1227e3fcf3ab61d97Joe Perches	struct net_device *dev = (struct net_device *)data;
2427b5b0abdb6757011ab51eaf1227e3fcf3ab61d97Joe Perches	volatile struct Am79C960 *lance = (struct Am79C960 *)dev->base_addr;
2437b5b0abdb6757011ab51eaf1227e3fcf3ab61d97Joe Perches	struct ariadne_private *priv;
2447b5b0abdb6757011ab51eaf1227e3fcf3ab61d97Joe Perches	int csr0, boguscnt;
2457b5b0abdb6757011ab51eaf1227e3fcf3ab61d97Joe Perches	int handled = 0;
2467b5b0abdb6757011ab51eaf1227e3fcf3ab61d97Joe Perches
2477b5b0abdb6757011ab51eaf1227e3fcf3ab61d97Joe Perches	lance->RAP = CSR0;		/* PCnet-ISA Controller Status */
2487b5b0abdb6757011ab51eaf1227e3fcf3ab61d97Joe Perches
2497b5b0abdb6757011ab51eaf1227e3fcf3ab61d97Joe Perches	if (!(lance->RDP & INTR))	/* Check if any interrupt has been */
2507b5b0abdb6757011ab51eaf1227e3fcf3ab61d97Joe Perches		return IRQ_NONE;	/* generated by the board */
2517b5b0abdb6757011ab51eaf1227e3fcf3ab61d97Joe Perches
2527b5b0abdb6757011ab51eaf1227e3fcf3ab61d97Joe Perches	priv = netdev_priv(dev);
2537b5b0abdb6757011ab51eaf1227e3fcf3ab61d97Joe Perches
2547b5b0abdb6757011ab51eaf1227e3fcf3ab61d97Joe Perches	boguscnt = 10;
2557b5b0abdb6757011ab51eaf1227e3fcf3ab61d97Joe Perches	while ((csr0 = lance->RDP) & (ERR | RINT | TINT) && --boguscnt >= 0) {
2567b5b0abdb6757011ab51eaf1227e3fcf3ab61d97Joe Perches		/* Acknowledge all of the current interrupt sources ASAP */
2577b5b0abdb6757011ab51eaf1227e3fcf3ab61d97Joe Perches		lance->RDP = csr0 & ~(INEA | TDMD | STOP | STRT | INIT);
2587b5b0abdb6757011ab51eaf1227e3fcf3ab61d97Joe Perches
2597b5b0abdb6757011ab51eaf1227e3fcf3ab61d97Joe Perches#ifdef DEBUG
2607b5b0abdb6757011ab51eaf1227e3fcf3ab61d97Joe Perches		if (ariadne_debug > 5) {
2617b5b0abdb6757011ab51eaf1227e3fcf3ab61d97Joe Perches			netdev_dbg(dev, "interrupt  csr0=%#02x new csr=%#02x [",
2627b5b0abdb6757011ab51eaf1227e3fcf3ab61d97Joe Perches				   csr0, lance->RDP);
2637b5b0abdb6757011ab51eaf1227e3fcf3ab61d97Joe Perches			if (csr0 & INTR)
2647b5b0abdb6757011ab51eaf1227e3fcf3ab61d97Joe Perches				pr_cont(" INTR");
2657b5b0abdb6757011ab51eaf1227e3fcf3ab61d97Joe Perches			if (csr0 & INEA)
2667b5b0abdb6757011ab51eaf1227e3fcf3ab61d97Joe Perches				pr_cont(" INEA");
2677b5b0abdb6757011ab51eaf1227e3fcf3ab61d97Joe Perches			if (csr0 & RXON)
2687b5b0abdb6757011ab51eaf1227e3fcf3ab61d97Joe Perches				pr_cont(" RXON");
2697b5b0abdb6757011ab51eaf1227e3fcf3ab61d97Joe Perches			if (csr0 & TXON)
2707b5b0abdb6757011ab51eaf1227e3fcf3ab61d97Joe Perches				pr_cont(" TXON");
2717b5b0abdb6757011ab51eaf1227e3fcf3ab61d97Joe Perches			if (csr0 & TDMD)
2727b5b0abdb6757011ab51eaf1227e3fcf3ab61d97Joe Perches				pr_cont(" TDMD");
2737b5b0abdb6757011ab51eaf1227e3fcf3ab61d97Joe Perches			if (csr0 & STOP)
2747b5b0abdb6757011ab51eaf1227e3fcf3ab61d97Joe Perches				pr_cont(" STOP");
2757b5b0abdb6757011ab51eaf1227e3fcf3ab61d97Joe Perches			if (csr0 & STRT)
2767b5b0abdb6757011ab51eaf1227e3fcf3ab61d97Joe Perches				pr_cont(" STRT");
2777b5b0abdb6757011ab51eaf1227e3fcf3ab61d97Joe Perches			if (csr0 & INIT)
2787b5b0abdb6757011ab51eaf1227e3fcf3ab61d97Joe Perches				pr_cont(" INIT");
2797b5b0abdb6757011ab51eaf1227e3fcf3ab61d97Joe Perches			if (csr0 & ERR)
2807b5b0abdb6757011ab51eaf1227e3fcf3ab61d97Joe Perches				pr_cont(" ERR");
2817b5b0abdb6757011ab51eaf1227e3fcf3ab61d97Joe Perches			if (csr0 & BABL)
2827b5b0abdb6757011ab51eaf1227e3fcf3ab61d97Joe Perches				pr_cont(" BABL");
2837b5b0abdb6757011ab51eaf1227e3fcf3ab61d97Joe Perches			if (csr0 & CERR)
2847b5b0abdb6757011ab51eaf1227e3fcf3ab61d97Joe Perches				pr_cont(" CERR");
2857b5b0abdb6757011ab51eaf1227e3fcf3ab61d97Joe Perches			if (csr0 & MISS)
2867b5b0abdb6757011ab51eaf1227e3fcf3ab61d97Joe Perches				pr_cont(" MISS");
2877b5b0abdb6757011ab51eaf1227e3fcf3ab61d97Joe Perches			if (csr0 & MERR)
2887b5b0abdb6757011ab51eaf1227e3fcf3ab61d97Joe Perches				pr_cont(" MERR");
2897b5b0abdb6757011ab51eaf1227e3fcf3ab61d97Joe Perches			if (csr0 & RINT)
2907b5b0abdb6757011ab51eaf1227e3fcf3ab61d97Joe Perches				pr_cont(" RINT");
2917b5b0abdb6757011ab51eaf1227e3fcf3ab61d97Joe Perches			if (csr0 & TINT)
2927b5b0abdb6757011ab51eaf1227e3fcf3ab61d97Joe Perches				pr_cont(" TINT");
2937b5b0abdb6757011ab51eaf1227e3fcf3ab61d97Joe Perches			if (csr0 & IDON)
2947b5b0abdb6757011ab51eaf1227e3fcf3ab61d97Joe Perches				pr_cont(" IDON");
2957b5b0abdb6757011ab51eaf1227e3fcf3ab61d97Joe Perches			pr_cont(" ]\n");
2967b5b0abdb6757011ab51eaf1227e3fcf3ab61d97Joe Perches		}
2971da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#endif
2981da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
2997b5b0abdb6757011ab51eaf1227e3fcf3ab61d97Joe Perches		if (csr0 & RINT) {	/* Rx interrupt */
3007b5b0abdb6757011ab51eaf1227e3fcf3ab61d97Joe Perches			handled = 1;
3017b5b0abdb6757011ab51eaf1227e3fcf3ab61d97Joe Perches			ariadne_rx(dev);
3027b5b0abdb6757011ab51eaf1227e3fcf3ab61d97Joe Perches		}
3031da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
3047b5b0abdb6757011ab51eaf1227e3fcf3ab61d97Joe Perches		if (csr0 & TINT) {	/* Tx-done interrupt */
3057b5b0abdb6757011ab51eaf1227e3fcf3ab61d97Joe Perches			int dirty_tx = priv->dirty_tx;
3067b5b0abdb6757011ab51eaf1227e3fcf3ab61d97Joe Perches
3077b5b0abdb6757011ab51eaf1227e3fcf3ab61d97Joe Perches			handled = 1;
3087b5b0abdb6757011ab51eaf1227e3fcf3ab61d97Joe Perches			while (dirty_tx < priv->cur_tx) {
3097b5b0abdb6757011ab51eaf1227e3fcf3ab61d97Joe Perches				int entry = dirty_tx % TX_RING_SIZE;
3107b5b0abdb6757011ab51eaf1227e3fcf3ab61d97Joe Perches				int status = lowb(priv->tx_ring[entry]->TMD1);
3117b5b0abdb6757011ab51eaf1227e3fcf3ab61d97Joe Perches
3127b5b0abdb6757011ab51eaf1227e3fcf3ab61d97Joe Perches				if (status & TF_OWN)
3137b5b0abdb6757011ab51eaf1227e3fcf3ab61d97Joe Perches					break;	/* It still hasn't been Txed */
3147b5b0abdb6757011ab51eaf1227e3fcf3ab61d97Joe Perches
3157b5b0abdb6757011ab51eaf1227e3fcf3ab61d97Joe Perches				priv->tx_ring[entry]->TMD1 &= 0xff00;
3167b5b0abdb6757011ab51eaf1227e3fcf3ab61d97Joe Perches
3177b5b0abdb6757011ab51eaf1227e3fcf3ab61d97Joe Perches				if (status & TF_ERR) {
3187b5b0abdb6757011ab51eaf1227e3fcf3ab61d97Joe Perches					/* There was an major error, log it */
3197b5b0abdb6757011ab51eaf1227e3fcf3ab61d97Joe Perches					int err_status = priv->tx_ring[entry]->TMD3;
3207b5b0abdb6757011ab51eaf1227e3fcf3ab61d97Joe Perches					dev->stats.tx_errors++;
3217b5b0abdb6757011ab51eaf1227e3fcf3ab61d97Joe Perches					if (err_status & EF_RTRY)
3227b5b0abdb6757011ab51eaf1227e3fcf3ab61d97Joe Perches						dev->stats.tx_aborted_errors++;
3237b5b0abdb6757011ab51eaf1227e3fcf3ab61d97Joe Perches					if (err_status & EF_LCAR)
3247b5b0abdb6757011ab51eaf1227e3fcf3ab61d97Joe Perches						dev->stats.tx_carrier_errors++;
3257b5b0abdb6757011ab51eaf1227e3fcf3ab61d97Joe Perches					if (err_status & EF_LCOL)
3267b5b0abdb6757011ab51eaf1227e3fcf3ab61d97Joe Perches						dev->stats.tx_window_errors++;
3277b5b0abdb6757011ab51eaf1227e3fcf3ab61d97Joe Perches					if (err_status & EF_UFLO) {
3287b5b0abdb6757011ab51eaf1227e3fcf3ab61d97Joe Perches						/* Ackk!  On FIFO errors the Tx unit is turned off! */
3297b5b0abdb6757011ab51eaf1227e3fcf3ab61d97Joe Perches						dev->stats.tx_fifo_errors++;
3307b5b0abdb6757011ab51eaf1227e3fcf3ab61d97Joe Perches						/* Remove this verbosity later! */
3317b5b0abdb6757011ab51eaf1227e3fcf3ab61d97Joe Perches						netdev_err(dev, "Tx FIFO error! Status %04x\n",
3327b5b0abdb6757011ab51eaf1227e3fcf3ab61d97Joe Perches							   csr0);
3337b5b0abdb6757011ab51eaf1227e3fcf3ab61d97Joe Perches						/* Restart the chip */
3347b5b0abdb6757011ab51eaf1227e3fcf3ab61d97Joe Perches						lance->RDP = STRT;
3357b5b0abdb6757011ab51eaf1227e3fcf3ab61d97Joe Perches					}
3367b5b0abdb6757011ab51eaf1227e3fcf3ab61d97Joe Perches				} else {
3377b5b0abdb6757011ab51eaf1227e3fcf3ab61d97Joe Perches					if (status & (TF_MORE | TF_ONE))
3387b5b0abdb6757011ab51eaf1227e3fcf3ab61d97Joe Perches						dev->stats.collisions++;
3397b5b0abdb6757011ab51eaf1227e3fcf3ab61d97Joe Perches					dev->stats.tx_packets++;
3407b5b0abdb6757011ab51eaf1227e3fcf3ab61d97Joe Perches				}
3417b5b0abdb6757011ab51eaf1227e3fcf3ab61d97Joe Perches				dirty_tx++;
3427b5b0abdb6757011ab51eaf1227e3fcf3ab61d97Joe Perches			}
3431da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
3447b5b0abdb6757011ab51eaf1227e3fcf3ab61d97Joe Perches#ifndef final_version
3457b5b0abdb6757011ab51eaf1227e3fcf3ab61d97Joe Perches			if (priv->cur_tx - dirty_tx >= TX_RING_SIZE) {
3467b5b0abdb6757011ab51eaf1227e3fcf3ab61d97Joe Perches				netdev_err(dev, "out-of-sync dirty pointer, %d vs. %d, full=%d\n",
3477b5b0abdb6757011ab51eaf1227e3fcf3ab61d97Joe Perches					   dirty_tx, priv->cur_tx,
3487b5b0abdb6757011ab51eaf1227e3fcf3ab61d97Joe Perches					   priv->tx_full);
3497b5b0abdb6757011ab51eaf1227e3fcf3ab61d97Joe Perches				dirty_tx += TX_RING_SIZE;
3507b5b0abdb6757011ab51eaf1227e3fcf3ab61d97Joe Perches			}
3517b5b0abdb6757011ab51eaf1227e3fcf3ab61d97Joe Perches#endif
3521da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
3537b5b0abdb6757011ab51eaf1227e3fcf3ab61d97Joe Perches			if (priv->tx_full && netif_queue_stopped(dev) &&
3547b5b0abdb6757011ab51eaf1227e3fcf3ab61d97Joe Perches			    dirty_tx > priv->cur_tx - TX_RING_SIZE + 2) {
3557b5b0abdb6757011ab51eaf1227e3fcf3ab61d97Joe Perches				/* The ring is no longer full */
3567b5b0abdb6757011ab51eaf1227e3fcf3ab61d97Joe Perches				priv->tx_full = 0;
3577b5b0abdb6757011ab51eaf1227e3fcf3ab61d97Joe Perches				netif_wake_queue(dev);
3587b5b0abdb6757011ab51eaf1227e3fcf3ab61d97Joe Perches			}
3591da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
3607b5b0abdb6757011ab51eaf1227e3fcf3ab61d97Joe Perches			priv->dirty_tx = dirty_tx;
3617b5b0abdb6757011ab51eaf1227e3fcf3ab61d97Joe Perches		}
3621da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
3637b5b0abdb6757011ab51eaf1227e3fcf3ab61d97Joe Perches		/* Log misc errors */
3647b5b0abdb6757011ab51eaf1227e3fcf3ab61d97Joe Perches		if (csr0 & BABL) {
3657b5b0abdb6757011ab51eaf1227e3fcf3ab61d97Joe Perches			handled = 1;
3667b5b0abdb6757011ab51eaf1227e3fcf3ab61d97Joe Perches			dev->stats.tx_errors++;	/* Tx babble */
3677b5b0abdb6757011ab51eaf1227e3fcf3ab61d97Joe Perches		}
3687b5b0abdb6757011ab51eaf1227e3fcf3ab61d97Joe Perches		if (csr0 & MISS) {
3697b5b0abdb6757011ab51eaf1227e3fcf3ab61d97Joe Perches			handled = 1;
3707b5b0abdb6757011ab51eaf1227e3fcf3ab61d97Joe Perches			dev->stats.rx_errors++;	/* Missed a Rx frame */
3717b5b0abdb6757011ab51eaf1227e3fcf3ab61d97Joe Perches		}
3727b5b0abdb6757011ab51eaf1227e3fcf3ab61d97Joe Perches		if (csr0 & MERR) {
3737b5b0abdb6757011ab51eaf1227e3fcf3ab61d97Joe Perches			handled = 1;
3747b5b0abdb6757011ab51eaf1227e3fcf3ab61d97Joe Perches			netdev_err(dev, "Bus master arbitration failure, status %04x\n",
3757b5b0abdb6757011ab51eaf1227e3fcf3ab61d97Joe Perches				   csr0);
3767b5b0abdb6757011ab51eaf1227e3fcf3ab61d97Joe Perches			/* Restart the chip */
3777b5b0abdb6757011ab51eaf1227e3fcf3ab61d97Joe Perches			lance->RDP = STRT;
3787b5b0abdb6757011ab51eaf1227e3fcf3ab61d97Joe Perches		}
3797b5b0abdb6757011ab51eaf1227e3fcf3ab61d97Joe Perches	}
3801da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
3817b5b0abdb6757011ab51eaf1227e3fcf3ab61d97Joe Perches	/* Clear any other interrupt, and set interrupt enable */
3827b5b0abdb6757011ab51eaf1227e3fcf3ab61d97Joe Perches	lance->RAP = CSR0;		/* PCnet-ISA Controller Status */
3837b5b0abdb6757011ab51eaf1227e3fcf3ab61d97Joe Perches	lance->RDP = INEA | BABL | CERR | MISS | MERR | IDON;
3841da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
3857b5b0abdb6757011ab51eaf1227e3fcf3ab61d97Joe Perches	if (ariadne_debug > 4)
3867b5b0abdb6757011ab51eaf1227e3fcf3ab61d97Joe Perches		netdev_dbg(dev, "exiting interrupt, csr%d=%#04x\n",
3877b5b0abdb6757011ab51eaf1227e3fcf3ab61d97Joe Perches			   lance->RAP, lance->RDP);
3881da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
3897b5b0abdb6757011ab51eaf1227e3fcf3ab61d97Joe Perches	return IRQ_RETVAL(handled);
3907b5b0abdb6757011ab51eaf1227e3fcf3ab61d97Joe Perches}
3911da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
3927b5b0abdb6757011ab51eaf1227e3fcf3ab61d97Joe Perchesstatic int ariadne_open(struct net_device *dev)
3931da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
3947b5b0abdb6757011ab51eaf1227e3fcf3ab61d97Joe Perches	volatile struct Am79C960 *lance = (struct Am79C960 *)dev->base_addr;
3957b5b0abdb6757011ab51eaf1227e3fcf3ab61d97Joe Perches	u_short in;
3967b5b0abdb6757011ab51eaf1227e3fcf3ab61d97Joe Perches	u_long version;
3977b5b0abdb6757011ab51eaf1227e3fcf3ab61d97Joe Perches	int i;
3981da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
3997b5b0abdb6757011ab51eaf1227e3fcf3ab61d97Joe Perches	/* Reset the LANCE */
4007b5b0abdb6757011ab51eaf1227e3fcf3ab61d97Joe Perches	in = lance->Reset;
4017b5b0abdb6757011ab51eaf1227e3fcf3ab61d97Joe Perches
4027b5b0abdb6757011ab51eaf1227e3fcf3ab61d97Joe Perches	/* Stop the LANCE */
4037b5b0abdb6757011ab51eaf1227e3fcf3ab61d97Joe Perches	lance->RAP = CSR0;		/* PCnet-ISA Controller Status */
4047b5b0abdb6757011ab51eaf1227e3fcf3ab61d97Joe Perches	lance->RDP = STOP;
4057b5b0abdb6757011ab51eaf1227e3fcf3ab61d97Joe Perches
4067b5b0abdb6757011ab51eaf1227e3fcf3ab61d97Joe Perches	/* Check the LANCE version */
4077b5b0abdb6757011ab51eaf1227e3fcf3ab61d97Joe Perches	lance->RAP = CSR88;		/* Chip ID */
4087b5b0abdb6757011ab51eaf1227e3fcf3ab61d97Joe Perches	version = swapw(lance->RDP);
4097b5b0abdb6757011ab51eaf1227e3fcf3ab61d97Joe Perches	lance->RAP = CSR89;		/* Chip ID */
4107b5b0abdb6757011ab51eaf1227e3fcf3ab61d97Joe Perches	version |= swapw(lance->RDP) << 16;
4117b5b0abdb6757011ab51eaf1227e3fcf3ab61d97Joe Perches	if ((version & 0x00000fff) != 0x00000003) {
4127b5b0abdb6757011ab51eaf1227e3fcf3ab61d97Joe Perches		pr_warn("Couldn't find AMD Ethernet Chip\n");
4137b5b0abdb6757011ab51eaf1227e3fcf3ab61d97Joe Perches		return -EAGAIN;
4147b5b0abdb6757011ab51eaf1227e3fcf3ab61d97Joe Perches	}
4157b5b0abdb6757011ab51eaf1227e3fcf3ab61d97Joe Perches	if ((version & 0x0ffff000) != 0x00003000) {
4167b5b0abdb6757011ab51eaf1227e3fcf3ab61d97Joe Perches		pr_warn("Couldn't find Am79C960 (Wrong part number = %ld)\n",
4177b5b0abdb6757011ab51eaf1227e3fcf3ab61d97Joe Perches		       (version & 0x0ffff000) >> 12);
4187b5b0abdb6757011ab51eaf1227e3fcf3ab61d97Joe Perches		return -EAGAIN;
4197b5b0abdb6757011ab51eaf1227e3fcf3ab61d97Joe Perches	}
4201da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
4217b5b0abdb6757011ab51eaf1227e3fcf3ab61d97Joe Perches	netdev_dbg(dev, "Am79C960 (PCnet-ISA) Revision %ld\n",
4227b5b0abdb6757011ab51eaf1227e3fcf3ab61d97Joe Perches		   (version & 0xf0000000) >> 28);
4231da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
4247b5b0abdb6757011ab51eaf1227e3fcf3ab61d97Joe Perches	ariadne_init_ring(dev);
4251da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
4267b5b0abdb6757011ab51eaf1227e3fcf3ab61d97Joe Perches	/* Miscellaneous Stuff */
4277b5b0abdb6757011ab51eaf1227e3fcf3ab61d97Joe Perches	lance->RAP = CSR3;		/* Interrupt Masks and Deferral Control */
4287b5b0abdb6757011ab51eaf1227e3fcf3ab61d97Joe Perches	lance->RDP = 0x0000;
4297b5b0abdb6757011ab51eaf1227e3fcf3ab61d97Joe Perches	lance->RAP = CSR4;		/* Test and Features Control */
4307b5b0abdb6757011ab51eaf1227e3fcf3ab61d97Joe Perches	lance->RDP = DPOLL | APAD_XMT | MFCOM | RCVCCOM | TXSTRTM | JABM;
4311da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
4327b5b0abdb6757011ab51eaf1227e3fcf3ab61d97Joe Perches	/* Set the Multicast Table */
4337b5b0abdb6757011ab51eaf1227e3fcf3ab61d97Joe Perches	lance->RAP = CSR8;		/* Logical Address Filter, LADRF[15:0] */
4347b5b0abdb6757011ab51eaf1227e3fcf3ab61d97Joe Perches	lance->RDP = 0x0000;
4357b5b0abdb6757011ab51eaf1227e3fcf3ab61d97Joe Perches	lance->RAP = CSR9;		/* Logical Address Filter, LADRF[31:16] */
4367b5b0abdb6757011ab51eaf1227e3fcf3ab61d97Joe Perches	lance->RDP = 0x0000;
4377b5b0abdb6757011ab51eaf1227e3fcf3ab61d97Joe Perches	lance->RAP = CSR10;		/* Logical Address Filter, LADRF[47:32] */
4387b5b0abdb6757011ab51eaf1227e3fcf3ab61d97Joe Perches	lance->RDP = 0x0000;
4397b5b0abdb6757011ab51eaf1227e3fcf3ab61d97Joe Perches	lance->RAP = CSR11;		/* Logical Address Filter, LADRF[63:48] */
4407b5b0abdb6757011ab51eaf1227e3fcf3ab61d97Joe Perches	lance->RDP = 0x0000;
4411da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
4427b5b0abdb6757011ab51eaf1227e3fcf3ab61d97Joe Perches	/* Set the Ethernet Hardware Address */
4437b5b0abdb6757011ab51eaf1227e3fcf3ab61d97Joe Perches	lance->RAP = CSR12;		/* Physical Address Register, PADR[15:0] */
4447b5b0abdb6757011ab51eaf1227e3fcf3ab61d97Joe Perches	lance->RDP = ((u_short *)&dev->dev_addr[0])[0];
4457b5b0abdb6757011ab51eaf1227e3fcf3ab61d97Joe Perches	lance->RAP = CSR13;		/* Physical Address Register, PADR[31:16] */
4467b5b0abdb6757011ab51eaf1227e3fcf3ab61d97Joe Perches	lance->RDP = ((u_short *)&dev->dev_addr[0])[1];
4477b5b0abdb6757011ab51eaf1227e3fcf3ab61d97Joe Perches	lance->RAP = CSR14;		/* Physical Address Register, PADR[47:32] */
4487b5b0abdb6757011ab51eaf1227e3fcf3ab61d97Joe Perches	lance->RDP = ((u_short *)&dev->dev_addr[0])[2];
4491da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
4507b5b0abdb6757011ab51eaf1227e3fcf3ab61d97Joe Perches	/* Set the Init Block Mode */
4517b5b0abdb6757011ab51eaf1227e3fcf3ab61d97Joe Perches	lance->RAP = CSR15;		/* Mode Register */
4527b5b0abdb6757011ab51eaf1227e3fcf3ab61d97Joe Perches	lance->RDP = 0x0000;
4531da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
4547b5b0abdb6757011ab51eaf1227e3fcf3ab61d97Joe Perches	/* Set the Transmit Descriptor Ring Pointer */
4557b5b0abdb6757011ab51eaf1227e3fcf3ab61d97Joe Perches	lance->RAP = CSR30;		/* Base Address of Transmit Ring */
4567b5b0abdb6757011ab51eaf1227e3fcf3ab61d97Joe Perches	lance->RDP = swloww(ARIADNE_RAM + offsetof(struct lancedata, tx_ring));
4577b5b0abdb6757011ab51eaf1227e3fcf3ab61d97Joe Perches	lance->RAP = CSR31;		/* Base Address of transmit Ring */
4587b5b0abdb6757011ab51eaf1227e3fcf3ab61d97Joe Perches	lance->RDP = swhighw(ARIADNE_RAM + offsetof(struct lancedata, tx_ring));
4597b5b0abdb6757011ab51eaf1227e3fcf3ab61d97Joe Perches
4607b5b0abdb6757011ab51eaf1227e3fcf3ab61d97Joe Perches	/* Set the Receive Descriptor Ring Pointer */
4617b5b0abdb6757011ab51eaf1227e3fcf3ab61d97Joe Perches	lance->RAP = CSR24;		/* Base Address of Receive Ring */
4627b5b0abdb6757011ab51eaf1227e3fcf3ab61d97Joe Perches	lance->RDP = swloww(ARIADNE_RAM + offsetof(struct lancedata, rx_ring));
4637b5b0abdb6757011ab51eaf1227e3fcf3ab61d97Joe Perches	lance->RAP = CSR25;		/* Base Address of Receive Ring */
4647b5b0abdb6757011ab51eaf1227e3fcf3ab61d97Joe Perches	lance->RDP = swhighw(ARIADNE_RAM + offsetof(struct lancedata, rx_ring));
4657b5b0abdb6757011ab51eaf1227e3fcf3ab61d97Joe Perches
4667b5b0abdb6757011ab51eaf1227e3fcf3ab61d97Joe Perches	/* Set the Number of RX and TX Ring Entries */
4677b5b0abdb6757011ab51eaf1227e3fcf3ab61d97Joe Perches	lance->RAP = CSR76;		/* Receive Ring Length */
4687b5b0abdb6757011ab51eaf1227e3fcf3ab61d97Joe Perches	lance->RDP = swapw(((u_short)-RX_RING_SIZE));
4697b5b0abdb6757011ab51eaf1227e3fcf3ab61d97Joe Perches	lance->RAP = CSR78;		/* Transmit Ring Length */
4707b5b0abdb6757011ab51eaf1227e3fcf3ab61d97Joe Perches	lance->RDP = swapw(((u_short)-TX_RING_SIZE));
4717b5b0abdb6757011ab51eaf1227e3fcf3ab61d97Joe Perches
4727b5b0abdb6757011ab51eaf1227e3fcf3ab61d97Joe Perches	/* Enable Media Interface Port Auto Select (10BASE-2/10BASE-T) */
4737b5b0abdb6757011ab51eaf1227e3fcf3ab61d97Joe Perches	lance->RAP = ISACSR2;		/* Miscellaneous Configuration */
4747b5b0abdb6757011ab51eaf1227e3fcf3ab61d97Joe Perches	lance->IDP = ASEL;
4757b5b0abdb6757011ab51eaf1227e3fcf3ab61d97Joe Perches
4767b5b0abdb6757011ab51eaf1227e3fcf3ab61d97Joe Perches	/* LED Control */
4777b5b0abdb6757011ab51eaf1227e3fcf3ab61d97Joe Perches	lance->RAP = ISACSR5;		/* LED1 Status */
4787b5b0abdb6757011ab51eaf1227e3fcf3ab61d97Joe Perches	lance->IDP = PSE|XMTE;
4797b5b0abdb6757011ab51eaf1227e3fcf3ab61d97Joe Perches	lance->RAP = ISACSR6;	/* LED2 Status */
4807b5b0abdb6757011ab51eaf1227e3fcf3ab61d97Joe Perches	lance->IDP = PSE|COLE;
4817b5b0abdb6757011ab51eaf1227e3fcf3ab61d97Joe Perches	lance->RAP = ISACSR7;	/* LED3 Status */
4827b5b0abdb6757011ab51eaf1227e3fcf3ab61d97Joe Perches	lance->IDP = PSE|RCVE;
4837b5b0abdb6757011ab51eaf1227e3fcf3ab61d97Joe Perches
4847b5b0abdb6757011ab51eaf1227e3fcf3ab61d97Joe Perches	netif_start_queue(dev);
4857b5b0abdb6757011ab51eaf1227e3fcf3ab61d97Joe Perches
4867b5b0abdb6757011ab51eaf1227e3fcf3ab61d97Joe Perches	i = request_irq(IRQ_AMIGA_PORTS, ariadne_interrupt, IRQF_SHARED,
4877b5b0abdb6757011ab51eaf1227e3fcf3ab61d97Joe Perches			dev->name, dev);
4887b5b0abdb6757011ab51eaf1227e3fcf3ab61d97Joe Perches	if (i)
4897b5b0abdb6757011ab51eaf1227e3fcf3ab61d97Joe Perches		return i;
4907b5b0abdb6757011ab51eaf1227e3fcf3ab61d97Joe Perches
4917b5b0abdb6757011ab51eaf1227e3fcf3ab61d97Joe Perches	lance->RAP = CSR0;		/* PCnet-ISA Controller Status */
4927b5b0abdb6757011ab51eaf1227e3fcf3ab61d97Joe Perches	lance->RDP = INEA | STRT;
4937b5b0abdb6757011ab51eaf1227e3fcf3ab61d97Joe Perches
4947b5b0abdb6757011ab51eaf1227e3fcf3ab61d97Joe Perches	return 0;
4957b5b0abdb6757011ab51eaf1227e3fcf3ab61d97Joe Perches}
4961da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
4977b5b0abdb6757011ab51eaf1227e3fcf3ab61d97Joe Perchesstatic int ariadne_close(struct net_device *dev)
4987b5b0abdb6757011ab51eaf1227e3fcf3ab61d97Joe Perches{
4997b5b0abdb6757011ab51eaf1227e3fcf3ab61d97Joe Perches	volatile struct Am79C960 *lance = (struct Am79C960 *)dev->base_addr;
5001da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
5017b5b0abdb6757011ab51eaf1227e3fcf3ab61d97Joe Perches	netif_stop_queue(dev);
5021da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
5037b5b0abdb6757011ab51eaf1227e3fcf3ab61d97Joe Perches	lance->RAP = CSR112;		/* Missed Frame Count */
5047b5b0abdb6757011ab51eaf1227e3fcf3ab61d97Joe Perches	dev->stats.rx_missed_errors = swapw(lance->RDP);
5057b5b0abdb6757011ab51eaf1227e3fcf3ab61d97Joe Perches	lance->RAP = CSR0;		/* PCnet-ISA Controller Status */
5061da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
5077b5b0abdb6757011ab51eaf1227e3fcf3ab61d97Joe Perches	if (ariadne_debug > 1) {
5087b5b0abdb6757011ab51eaf1227e3fcf3ab61d97Joe Perches		netdev_dbg(dev, "Shutting down ethercard, status was %02x\n",
5097b5b0abdb6757011ab51eaf1227e3fcf3ab61d97Joe Perches			   lance->RDP);
5107b5b0abdb6757011ab51eaf1227e3fcf3ab61d97Joe Perches		netdev_dbg(dev, "%lu packets missed\n",
5117b5b0abdb6757011ab51eaf1227e3fcf3ab61d97Joe Perches			   dev->stats.rx_missed_errors);
5121da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
5131da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
5147b5b0abdb6757011ab51eaf1227e3fcf3ab61d97Joe Perches	/* We stop the LANCE here -- it occasionally polls memory if we don't */
5157b5b0abdb6757011ab51eaf1227e3fcf3ab61d97Joe Perches	lance->RDP = STOP;
5161da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
5177b5b0abdb6757011ab51eaf1227e3fcf3ab61d97Joe Perches	free_irq(IRQ_AMIGA_PORTS, dev);
5181da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
5197b5b0abdb6757011ab51eaf1227e3fcf3ab61d97Joe Perches	return 0;
5201da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
5211da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
5227b5b0abdb6757011ab51eaf1227e3fcf3ab61d97Joe Perchesstatic inline void ariadne_reset(struct net_device *dev)
5237b5b0abdb6757011ab51eaf1227e3fcf3ab61d97Joe Perches{
5247b5b0abdb6757011ab51eaf1227e3fcf3ab61d97Joe Perches	volatile struct Am79C960 *lance = (struct Am79C960 *)dev->base_addr;
5257b5b0abdb6757011ab51eaf1227e3fcf3ab61d97Joe Perches
5267b5b0abdb6757011ab51eaf1227e3fcf3ab61d97Joe Perches	lance->RAP = CSR0;	/* PCnet-ISA Controller Status */
5277b5b0abdb6757011ab51eaf1227e3fcf3ab61d97Joe Perches	lance->RDP = STOP;
5287b5b0abdb6757011ab51eaf1227e3fcf3ab61d97Joe Perches	ariadne_init_ring(dev);
5297b5b0abdb6757011ab51eaf1227e3fcf3ab61d97Joe Perches	lance->RDP = INEA | STRT;
5307b5b0abdb6757011ab51eaf1227e3fcf3ab61d97Joe Perches	netif_start_queue(dev);
5317b5b0abdb6757011ab51eaf1227e3fcf3ab61d97Joe Perches}
5321da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
5331da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic void ariadne_tx_timeout(struct net_device *dev)
5341da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
5357b5b0abdb6757011ab51eaf1227e3fcf3ab61d97Joe Perches	volatile struct Am79C960 *lance = (struct Am79C960 *)dev->base_addr;
5361da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
5377b5b0abdb6757011ab51eaf1227e3fcf3ab61d97Joe Perches	netdev_err(dev, "transmit timed out, status %04x, resetting\n",
5387b5b0abdb6757011ab51eaf1227e3fcf3ab61d97Joe Perches		   lance->RDP);
5397b5b0abdb6757011ab51eaf1227e3fcf3ab61d97Joe Perches	ariadne_reset(dev);
5407b5b0abdb6757011ab51eaf1227e3fcf3ab61d97Joe Perches	netif_wake_queue(dev);
5411da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
5421da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
54361357325f377889a1daffa14962d705dc814dd0eStephen Hemmingerstatic netdev_tx_t ariadne_start_xmit(struct sk_buff *skb,
54461357325f377889a1daffa14962d705dc814dd0eStephen Hemminger				      struct net_device *dev)
5451da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
5467b5b0abdb6757011ab51eaf1227e3fcf3ab61d97Joe Perches	struct ariadne_private *priv = netdev_priv(dev);
5477b5b0abdb6757011ab51eaf1227e3fcf3ab61d97Joe Perches	volatile struct Am79C960 *lance = (struct Am79C960 *)dev->base_addr;
5487b5b0abdb6757011ab51eaf1227e3fcf3ab61d97Joe Perches	int entry;
5497b5b0abdb6757011ab51eaf1227e3fcf3ab61d97Joe Perches	unsigned long flags;
5507b5b0abdb6757011ab51eaf1227e3fcf3ab61d97Joe Perches	int len = skb->len;
5511da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
5521da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#if 0
5537b5b0abdb6757011ab51eaf1227e3fcf3ab61d97Joe Perches	if (ariadne_debug > 3) {
5547b5b0abdb6757011ab51eaf1227e3fcf3ab61d97Joe Perches		lance->RAP = CSR0;	/* PCnet-ISA Controller Status */
5557b5b0abdb6757011ab51eaf1227e3fcf3ab61d97Joe Perches		netdev_dbg(dev, "%s: csr0 %04x\n", __func__, lance->RDP);
5567b5b0abdb6757011ab51eaf1227e3fcf3ab61d97Joe Perches		lance->RDP = 0x0000;
5577b5b0abdb6757011ab51eaf1227e3fcf3ab61d97Joe Perches	}
5581da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#endif
5591da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
5607b5b0abdb6757011ab51eaf1227e3fcf3ab61d97Joe Perches	/* FIXME: is the 79C960 new enough to do its own padding right ? */
5617b5b0abdb6757011ab51eaf1227e3fcf3ab61d97Joe Perches	if (skb->len < ETH_ZLEN) {
5627b5b0abdb6757011ab51eaf1227e3fcf3ab61d97Joe Perches		if (skb_padto(skb, ETH_ZLEN))
5637b5b0abdb6757011ab51eaf1227e3fcf3ab61d97Joe Perches			return NETDEV_TX_OK;
5647b5b0abdb6757011ab51eaf1227e3fcf3ab61d97Joe Perches		len = ETH_ZLEN;
5651da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
5661da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
5677b5b0abdb6757011ab51eaf1227e3fcf3ab61d97Joe Perches	/* Fill in a Tx ring entry */
5681da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
5697b5b0abdb6757011ab51eaf1227e3fcf3ab61d97Joe Perches	netdev_dbg(dev, "TX pkt type 0x%04x from %pM to %pM data 0x%08x len %d\n",
5707b5b0abdb6757011ab51eaf1227e3fcf3ab61d97Joe Perches		   ((u_short *)skb->data)[6],
5717b5b0abdb6757011ab51eaf1227e3fcf3ab61d97Joe Perches		   skb->data + 6, skb->data,
5727b5b0abdb6757011ab51eaf1227e3fcf3ab61d97Joe Perches		   (int)skb->data, (int)skb->len);
5731da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
5747b5b0abdb6757011ab51eaf1227e3fcf3ab61d97Joe Perches	local_irq_save(flags);
5751da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
5767b5b0abdb6757011ab51eaf1227e3fcf3ab61d97Joe Perches	entry = priv->cur_tx % TX_RING_SIZE;
5771da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
5787b5b0abdb6757011ab51eaf1227e3fcf3ab61d97Joe Perches	/* Caution: the write order is important here, set the base address with
5797b5b0abdb6757011ab51eaf1227e3fcf3ab61d97Joe Perches	   the "ownership" bits last */
5801da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
5817b5b0abdb6757011ab51eaf1227e3fcf3ab61d97Joe Perches	priv->tx_ring[entry]->TMD2 = swapw((u_short)-skb->len);
5827b5b0abdb6757011ab51eaf1227e3fcf3ab61d97Joe Perches	priv->tx_ring[entry]->TMD3 = 0x0000;
5837b5b0abdb6757011ab51eaf1227e3fcf3ab61d97Joe Perches	memcpyw(priv->tx_buff[entry], (u_short *)skb->data, len);
5841da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
5857b5b0abdb6757011ab51eaf1227e3fcf3ab61d97Joe Perches#ifdef DEBUG
5867b5b0abdb6757011ab51eaf1227e3fcf3ab61d97Joe Perches	print_hex_dump(KERN_DEBUG, "tx_buff: ", DUMP_PREFIX_OFFSET, 16, 1,
5877b5b0abdb6757011ab51eaf1227e3fcf3ab61d97Joe Perches		       (void *)priv->tx_buff[entry],
5887b5b0abdb6757011ab51eaf1227e3fcf3ab61d97Joe Perches		       skb->len > 64 ? 64 : skb->len, true);
5897b5b0abdb6757011ab51eaf1227e3fcf3ab61d97Joe Perches#endif
5901da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
5917b5b0abdb6757011ab51eaf1227e3fcf3ab61d97Joe Perches	priv->tx_ring[entry]->TMD1 = (priv->tx_ring[entry]->TMD1 & 0xff00)
5927b5b0abdb6757011ab51eaf1227e3fcf3ab61d97Joe Perches		| TF_OWN | TF_STP | TF_ENP;
5931da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
5947b5b0abdb6757011ab51eaf1227e3fcf3ab61d97Joe Perches	dev_kfree_skb(skb);
5951da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
5967b5b0abdb6757011ab51eaf1227e3fcf3ab61d97Joe Perches	priv->cur_tx++;
5977b5b0abdb6757011ab51eaf1227e3fcf3ab61d97Joe Perches	if ((priv->cur_tx >= TX_RING_SIZE) &&
5987b5b0abdb6757011ab51eaf1227e3fcf3ab61d97Joe Perches	    (priv->dirty_tx >= TX_RING_SIZE)) {
5991da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
6007b5b0abdb6757011ab51eaf1227e3fcf3ab61d97Joe Perches		netdev_dbg(dev, "*** Subtracting TX_RING_SIZE from cur_tx (%d) and dirty_tx (%d)\n",
6017b5b0abdb6757011ab51eaf1227e3fcf3ab61d97Joe Perches			   priv->cur_tx, priv->dirty_tx);
6021da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
6037b5b0abdb6757011ab51eaf1227e3fcf3ab61d97Joe Perches		priv->cur_tx -= TX_RING_SIZE;
6047b5b0abdb6757011ab51eaf1227e3fcf3ab61d97Joe Perches		priv->dirty_tx -= TX_RING_SIZE;
6051da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
6067b5b0abdb6757011ab51eaf1227e3fcf3ab61d97Joe Perches	dev->stats.tx_bytes += len;
6071da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
6087b5b0abdb6757011ab51eaf1227e3fcf3ab61d97Joe Perches	/* Trigger an immediate send poll */
6097b5b0abdb6757011ab51eaf1227e3fcf3ab61d97Joe Perches	lance->RAP = CSR0;		/* PCnet-ISA Controller Status */
6107b5b0abdb6757011ab51eaf1227e3fcf3ab61d97Joe Perches	lance->RDP = INEA | TDMD;
6111da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
6127b5b0abdb6757011ab51eaf1227e3fcf3ab61d97Joe Perches	if (lowb(priv->tx_ring[(entry + 1) % TX_RING_SIZE]->TMD1) != 0) {
6137b5b0abdb6757011ab51eaf1227e3fcf3ab61d97Joe Perches		netif_stop_queue(dev);
6147b5b0abdb6757011ab51eaf1227e3fcf3ab61d97Joe Perches		priv->tx_full = 1;
6157b5b0abdb6757011ab51eaf1227e3fcf3ab61d97Joe Perches	}
6167b5b0abdb6757011ab51eaf1227e3fcf3ab61d97Joe Perches	local_irq_restore(flags);
6171da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
6187b5b0abdb6757011ab51eaf1227e3fcf3ab61d97Joe Perches	return NETDEV_TX_OK;
6191da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
6201da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
6211da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic struct net_device_stats *ariadne_get_stats(struct net_device *dev)
6221da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
6237b5b0abdb6757011ab51eaf1227e3fcf3ab61d97Joe Perches	volatile struct Am79C960 *lance = (struct Am79C960 *)dev->base_addr;
6247b5b0abdb6757011ab51eaf1227e3fcf3ab61d97Joe Perches	short saved_addr;
6257b5b0abdb6757011ab51eaf1227e3fcf3ab61d97Joe Perches	unsigned long flags;
6267b5b0abdb6757011ab51eaf1227e3fcf3ab61d97Joe Perches
6277b5b0abdb6757011ab51eaf1227e3fcf3ab61d97Joe Perches	local_irq_save(flags);
6287b5b0abdb6757011ab51eaf1227e3fcf3ab61d97Joe Perches	saved_addr = lance->RAP;
6297b5b0abdb6757011ab51eaf1227e3fcf3ab61d97Joe Perches	lance->RAP = CSR112;		/* Missed Frame Count */
6307b5b0abdb6757011ab51eaf1227e3fcf3ab61d97Joe Perches	dev->stats.rx_missed_errors = swapw(lance->RDP);
6317b5b0abdb6757011ab51eaf1227e3fcf3ab61d97Joe Perches	lance->RAP = saved_addr;
6327b5b0abdb6757011ab51eaf1227e3fcf3ab61d97Joe Perches	local_irq_restore(flags);
6337b5b0abdb6757011ab51eaf1227e3fcf3ab61d97Joe Perches
6347b5b0abdb6757011ab51eaf1227e3fcf3ab61d97Joe Perches	return &dev->stats;
6351da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
6361da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
6371da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/* Set or clear the multicast filter for this adaptor.
6387b5b0abdb6757011ab51eaf1227e3fcf3ab61d97Joe Perches * num_addrs == -1	Promiscuous mode, receive all packets
6397b5b0abdb6757011ab51eaf1227e3fcf3ab61d97Joe Perches * num_addrs == 0	Normal mode, clear multicast list
6407b5b0abdb6757011ab51eaf1227e3fcf3ab61d97Joe Perches * num_addrs > 0	Multicast mode, receive normal and MC packets,
6417b5b0abdb6757011ab51eaf1227e3fcf3ab61d97Joe Perches * 			and do best-effort filtering.
6421da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */
6431da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic void set_multicast_list(struct net_device *dev)
6441da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
6457b5b0abdb6757011ab51eaf1227e3fcf3ab61d97Joe Perches	volatile struct Am79C960 *lance = (struct Am79C960 *)dev->base_addr;
6461da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
6477b5b0abdb6757011ab51eaf1227e3fcf3ab61d97Joe Perches	if (!netif_running(dev))
6487b5b0abdb6757011ab51eaf1227e3fcf3ab61d97Joe Perches		return;
6491da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
6507b5b0abdb6757011ab51eaf1227e3fcf3ab61d97Joe Perches	netif_stop_queue(dev);
6511da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
6527b5b0abdb6757011ab51eaf1227e3fcf3ab61d97Joe Perches	/* We take the simple way out and always enable promiscuous mode */
6537b5b0abdb6757011ab51eaf1227e3fcf3ab61d97Joe Perches	lance->RAP = CSR0;		/* PCnet-ISA Controller Status */
6547b5b0abdb6757011ab51eaf1227e3fcf3ab61d97Joe Perches	lance->RDP = STOP;		/* Temporarily stop the lance */
6557b5b0abdb6757011ab51eaf1227e3fcf3ab61d97Joe Perches	ariadne_init_ring(dev);
6561da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
6577b5b0abdb6757011ab51eaf1227e3fcf3ab61d97Joe Perches	if (dev->flags & IFF_PROMISC) {
6587b5b0abdb6757011ab51eaf1227e3fcf3ab61d97Joe Perches		lance->RAP = CSR15;	/* Mode Register */
6597b5b0abdb6757011ab51eaf1227e3fcf3ab61d97Joe Perches		lance->RDP = PROM;	/* Set promiscuous mode */
6607b5b0abdb6757011ab51eaf1227e3fcf3ab61d97Joe Perches	} else {
6617b5b0abdb6757011ab51eaf1227e3fcf3ab61d97Joe Perches		short multicast_table[4];
6627b5b0abdb6757011ab51eaf1227e3fcf3ab61d97Joe Perches		int num_addrs = netdev_mc_count(dev);
6637b5b0abdb6757011ab51eaf1227e3fcf3ab61d97Joe Perches		int i;
6647b5b0abdb6757011ab51eaf1227e3fcf3ab61d97Joe Perches		/* We don't use the multicast table,
6657b5b0abdb6757011ab51eaf1227e3fcf3ab61d97Joe Perches		 * but rely on upper-layer filtering
6667b5b0abdb6757011ab51eaf1227e3fcf3ab61d97Joe Perches		 */
6677b5b0abdb6757011ab51eaf1227e3fcf3ab61d97Joe Perches		memset(multicast_table, (num_addrs == 0) ? 0 : -1,
6687b5b0abdb6757011ab51eaf1227e3fcf3ab61d97Joe Perches		       sizeof(multicast_table));
6697b5b0abdb6757011ab51eaf1227e3fcf3ab61d97Joe Perches		for (i = 0; i < 4; i++) {
6707b5b0abdb6757011ab51eaf1227e3fcf3ab61d97Joe Perches			lance->RAP = CSR8 + (i << 8);
6717b5b0abdb6757011ab51eaf1227e3fcf3ab61d97Joe Perches					/* Logical Address Filter */
6727b5b0abdb6757011ab51eaf1227e3fcf3ab61d97Joe Perches			lance->RDP = swapw(multicast_table[i]);
6737b5b0abdb6757011ab51eaf1227e3fcf3ab61d97Joe Perches		}
6747b5b0abdb6757011ab51eaf1227e3fcf3ab61d97Joe Perches		lance->RAP = CSR15;	/* Mode Register */
6757b5b0abdb6757011ab51eaf1227e3fcf3ab61d97Joe Perches		lance->RDP = 0x0000;	/* Unset promiscuous mode */
6761da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
6771da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
6787b5b0abdb6757011ab51eaf1227e3fcf3ab61d97Joe Perches	lance->RAP = CSR0;		/* PCnet-ISA Controller Status */
6797b5b0abdb6757011ab51eaf1227e3fcf3ab61d97Joe Perches	lance->RDP = INEA | STRT | IDON;/* Resume normal operation */
6801da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
6817b5b0abdb6757011ab51eaf1227e3fcf3ab61d97Joe Perches	netif_wake_queue(dev);
6821da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
6831da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
6841da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
6851da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic void __devexit ariadne_remove_one(struct zorro_dev *z)
6861da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
6877b5b0abdb6757011ab51eaf1227e3fcf3ab61d97Joe Perches	struct net_device *dev = zorro_get_drvdata(z);
6881da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
6897b5b0abdb6757011ab51eaf1227e3fcf3ab61d97Joe Perches	unregister_netdev(dev);
6907b5b0abdb6757011ab51eaf1227e3fcf3ab61d97Joe Perches	release_mem_region(ZTWO_PADDR(dev->base_addr), sizeof(struct Am79C960));
6917b5b0abdb6757011ab51eaf1227e3fcf3ab61d97Joe Perches	release_mem_region(ZTWO_PADDR(dev->mem_start), ARIADNE_RAM_SIZE);
6927b5b0abdb6757011ab51eaf1227e3fcf3ab61d97Joe Perches	free_netdev(dev);
6931da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
6941da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
6957b5b0abdb6757011ab51eaf1227e3fcf3ab61d97Joe Perchesstatic struct zorro_device_id ariadne_zorro_tbl[] __devinitdata = {
6967b5b0abdb6757011ab51eaf1227e3fcf3ab61d97Joe Perches	{ ZORRO_PROD_VILLAGE_TRONIC_ARIADNE },
6977b5b0abdb6757011ab51eaf1227e3fcf3ab61d97Joe Perches	{ 0 }
6987b5b0abdb6757011ab51eaf1227e3fcf3ab61d97Joe Perches};
6997b5b0abdb6757011ab51eaf1227e3fcf3ab61d97Joe PerchesMODULE_DEVICE_TABLE(zorro, ariadne_zorro_tbl);
7007b5b0abdb6757011ab51eaf1227e3fcf3ab61d97Joe Perches
7017b5b0abdb6757011ab51eaf1227e3fcf3ab61d97Joe Perchesstatic const struct net_device_ops ariadne_netdev_ops = {
7027b5b0abdb6757011ab51eaf1227e3fcf3ab61d97Joe Perches	.ndo_open		= ariadne_open,
7037b5b0abdb6757011ab51eaf1227e3fcf3ab61d97Joe Perches	.ndo_stop		= ariadne_close,
7047b5b0abdb6757011ab51eaf1227e3fcf3ab61d97Joe Perches	.ndo_start_xmit		= ariadne_start_xmit,
7057b5b0abdb6757011ab51eaf1227e3fcf3ab61d97Joe Perches	.ndo_tx_timeout		= ariadne_tx_timeout,
7067b5b0abdb6757011ab51eaf1227e3fcf3ab61d97Joe Perches	.ndo_get_stats		= ariadne_get_stats,
707afc4b13df143122f99a0eb10bfefb216c2806de0Jiri Pirko	.ndo_set_rx_mode	= set_multicast_list,
7087b5b0abdb6757011ab51eaf1227e3fcf3ab61d97Joe Perches	.ndo_validate_addr	= eth_validate_addr,
7097b5b0abdb6757011ab51eaf1227e3fcf3ab61d97Joe Perches	.ndo_change_mtu		= eth_change_mtu,
7107b5b0abdb6757011ab51eaf1227e3fcf3ab61d97Joe Perches	.ndo_set_mac_address	= eth_mac_addr,
7117b5b0abdb6757011ab51eaf1227e3fcf3ab61d97Joe Perches};
7127b5b0abdb6757011ab51eaf1227e3fcf3ab61d97Joe Perches
7137b5b0abdb6757011ab51eaf1227e3fcf3ab61d97Joe Perchesstatic int __devinit ariadne_init_one(struct zorro_dev *z,
7147b5b0abdb6757011ab51eaf1227e3fcf3ab61d97Joe Perches				      const struct zorro_device_id *ent)
7157b5b0abdb6757011ab51eaf1227e3fcf3ab61d97Joe Perches{
7167b5b0abdb6757011ab51eaf1227e3fcf3ab61d97Joe Perches	unsigned long board = z->resource.start;
7177b5b0abdb6757011ab51eaf1227e3fcf3ab61d97Joe Perches	unsigned long base_addr = board + ARIADNE_LANCE;
7187b5b0abdb6757011ab51eaf1227e3fcf3ab61d97Joe Perches	unsigned long mem_start = board + ARIADNE_RAM;
7197b5b0abdb6757011ab51eaf1227e3fcf3ab61d97Joe Perches	struct resource *r1, *r2;
7207b5b0abdb6757011ab51eaf1227e3fcf3ab61d97Joe Perches	struct net_device *dev;
7217b5b0abdb6757011ab51eaf1227e3fcf3ab61d97Joe Perches	struct ariadne_private *priv;
7227b5b0abdb6757011ab51eaf1227e3fcf3ab61d97Joe Perches	int err;
7237b5b0abdb6757011ab51eaf1227e3fcf3ab61d97Joe Perches
7247b5b0abdb6757011ab51eaf1227e3fcf3ab61d97Joe Perches	r1 = request_mem_region(base_addr, sizeof(struct Am79C960), "Am79C960");
7257b5b0abdb6757011ab51eaf1227e3fcf3ab61d97Joe Perches	if (!r1)
7267b5b0abdb6757011ab51eaf1227e3fcf3ab61d97Joe Perches		return -EBUSY;
7277b5b0abdb6757011ab51eaf1227e3fcf3ab61d97Joe Perches	r2 = request_mem_region(mem_start, ARIADNE_RAM_SIZE, "RAM");
7287b5b0abdb6757011ab51eaf1227e3fcf3ab61d97Joe Perches	if (!r2) {
7297b5b0abdb6757011ab51eaf1227e3fcf3ab61d97Joe Perches		release_mem_region(base_addr, sizeof(struct Am79C960));
7307b5b0abdb6757011ab51eaf1227e3fcf3ab61d97Joe Perches		return -EBUSY;
7317b5b0abdb6757011ab51eaf1227e3fcf3ab61d97Joe Perches	}
7327b5b0abdb6757011ab51eaf1227e3fcf3ab61d97Joe Perches
7337b5b0abdb6757011ab51eaf1227e3fcf3ab61d97Joe Perches	dev = alloc_etherdev(sizeof(struct ariadne_private));
7347b5b0abdb6757011ab51eaf1227e3fcf3ab61d97Joe Perches	if (dev == NULL) {
7357b5b0abdb6757011ab51eaf1227e3fcf3ab61d97Joe Perches		release_mem_region(base_addr, sizeof(struct Am79C960));
7367b5b0abdb6757011ab51eaf1227e3fcf3ab61d97Joe Perches		release_mem_region(mem_start, ARIADNE_RAM_SIZE);
7377b5b0abdb6757011ab51eaf1227e3fcf3ab61d97Joe Perches		return -ENOMEM;
7387b5b0abdb6757011ab51eaf1227e3fcf3ab61d97Joe Perches	}
7397b5b0abdb6757011ab51eaf1227e3fcf3ab61d97Joe Perches
7407b5b0abdb6757011ab51eaf1227e3fcf3ab61d97Joe Perches	priv = netdev_priv(dev);
7417b5b0abdb6757011ab51eaf1227e3fcf3ab61d97Joe Perches
7427b5b0abdb6757011ab51eaf1227e3fcf3ab61d97Joe Perches	r1->name = dev->name;
7437b5b0abdb6757011ab51eaf1227e3fcf3ab61d97Joe Perches	r2->name = dev->name;
7447b5b0abdb6757011ab51eaf1227e3fcf3ab61d97Joe Perches
7457b5b0abdb6757011ab51eaf1227e3fcf3ab61d97Joe Perches	dev->dev_addr[0] = 0x00;
7467b5b0abdb6757011ab51eaf1227e3fcf3ab61d97Joe Perches	dev->dev_addr[1] = 0x60;
7477b5b0abdb6757011ab51eaf1227e3fcf3ab61d97Joe Perches	dev->dev_addr[2] = 0x30;
7487b5b0abdb6757011ab51eaf1227e3fcf3ab61d97Joe Perches	dev->dev_addr[3] = (z->rom.er_SerialNumber >> 16) & 0xff;
7497b5b0abdb6757011ab51eaf1227e3fcf3ab61d97Joe Perches	dev->dev_addr[4] = (z->rom.er_SerialNumber >> 8) & 0xff;
7507b5b0abdb6757011ab51eaf1227e3fcf3ab61d97Joe Perches	dev->dev_addr[5] = z->rom.er_SerialNumber & 0xff;
7517b5b0abdb6757011ab51eaf1227e3fcf3ab61d97Joe Perches	dev->base_addr = ZTWO_VADDR(base_addr);
7527b5b0abdb6757011ab51eaf1227e3fcf3ab61d97Joe Perches	dev->mem_start = ZTWO_VADDR(mem_start);
7537b5b0abdb6757011ab51eaf1227e3fcf3ab61d97Joe Perches	dev->mem_end = dev->mem_start + ARIADNE_RAM_SIZE;
7547b5b0abdb6757011ab51eaf1227e3fcf3ab61d97Joe Perches
7557b5b0abdb6757011ab51eaf1227e3fcf3ab61d97Joe Perches	dev->netdev_ops = &ariadne_netdev_ops;
7567b5b0abdb6757011ab51eaf1227e3fcf3ab61d97Joe Perches	dev->watchdog_timeo = 5 * HZ;
7577b5b0abdb6757011ab51eaf1227e3fcf3ab61d97Joe Perches
7587b5b0abdb6757011ab51eaf1227e3fcf3ab61d97Joe Perches	err = register_netdev(dev);
7597b5b0abdb6757011ab51eaf1227e3fcf3ab61d97Joe Perches	if (err) {
7607b5b0abdb6757011ab51eaf1227e3fcf3ab61d97Joe Perches		release_mem_region(base_addr, sizeof(struct Am79C960));
7617b5b0abdb6757011ab51eaf1227e3fcf3ab61d97Joe Perches		release_mem_region(mem_start, ARIADNE_RAM_SIZE);
7627b5b0abdb6757011ab51eaf1227e3fcf3ab61d97Joe Perches		free_netdev(dev);
7637b5b0abdb6757011ab51eaf1227e3fcf3ab61d97Joe Perches		return err;
7647b5b0abdb6757011ab51eaf1227e3fcf3ab61d97Joe Perches	}
7657b5b0abdb6757011ab51eaf1227e3fcf3ab61d97Joe Perches	zorro_set_drvdata(z, dev);
7667b5b0abdb6757011ab51eaf1227e3fcf3ab61d97Joe Perches
7677b5b0abdb6757011ab51eaf1227e3fcf3ab61d97Joe Perches	netdev_info(dev, "Ariadne at 0x%08lx, Ethernet Address %pM\n",
7687b5b0abdb6757011ab51eaf1227e3fcf3ab61d97Joe Perches		    board, dev->dev_addr);
7697b5b0abdb6757011ab51eaf1227e3fcf3ab61d97Joe Perches
7707b5b0abdb6757011ab51eaf1227e3fcf3ab61d97Joe Perches	return 0;
7717b5b0abdb6757011ab51eaf1227e3fcf3ab61d97Joe Perches}
7727b5b0abdb6757011ab51eaf1227e3fcf3ab61d97Joe Perches
7737b5b0abdb6757011ab51eaf1227e3fcf3ab61d97Joe Perchesstatic struct zorro_driver ariadne_driver = {
7747b5b0abdb6757011ab51eaf1227e3fcf3ab61d97Joe Perches	.name		= "ariadne",
7757b5b0abdb6757011ab51eaf1227e3fcf3ab61d97Joe Perches	.id_table	= ariadne_zorro_tbl,
7767b5b0abdb6757011ab51eaf1227e3fcf3ab61d97Joe Perches	.probe		= ariadne_init_one,
7777b5b0abdb6757011ab51eaf1227e3fcf3ab61d97Joe Perches	.remove		= __devexit_p(ariadne_remove_one),
7787b5b0abdb6757011ab51eaf1227e3fcf3ab61d97Joe Perches};
7797b5b0abdb6757011ab51eaf1227e3fcf3ab61d97Joe Perches
7801da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic int __init ariadne_init_module(void)
7811da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
7827b5b0abdb6757011ab51eaf1227e3fcf3ab61d97Joe Perches	return zorro_register_driver(&ariadne_driver);
7831da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
7841da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
7851da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic void __exit ariadne_cleanup_module(void)
7861da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
7877b5b0abdb6757011ab51eaf1227e3fcf3ab61d97Joe Perches	zorro_unregister_driver(&ariadne_driver);
7881da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
7891da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
7901da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsmodule_init(ariadne_init_module);
7911da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsmodule_exit(ariadne_cleanup_module);
7921da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
7931da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus TorvaldsMODULE_LICENSE("GPL");
794