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