11da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/* 3c509.c: A 3c509 EtherLink3 ethernet driver for linux. */ 21da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/* 31da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds Written 1993-2000 by Donald Becker. 41da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 51da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds Copyright 1994-2000 by Donald Becker. 61da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds Copyright 1993 United States Government as represented by the 71da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds Director, National Security Agency. This software may be used and 81da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds distributed according to the terms of the GNU General Public License, 91da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds incorporated herein by reference. 101da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 111da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds This driver is for the 3Com EtherLinkIII series. 121da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 131da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds The author may be reached as becker@scyld.com, or C/O 141da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds Scyld Computing Corporation 151da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 410 Severn Ave., Suite 210 161da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds Annapolis MD 21403 171da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 181da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds Known limitations: 191da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds Because of the way 3c509 ISA detection works it's difficult to predict 201da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds a priori which of several ISA-mode cards will be detected first. 211da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 221da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds This driver does not use predictive interrupt mode, resulting in higher 231da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds packet latency but lower overhead. If interrupts are disabled for an 241da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds unusually long time it could also result in missed packets, but in 251da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds practice this rarely happens. 261da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 271da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 281da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds FIXES: 291da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds Alan Cox: Removed the 'Unexpected interrupt' bug. 301da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds Michael Meskes: Upgraded to Donald Becker's version 1.07. 316aa20a2235535605db6d6d2bd850298b2fe7f31eJeff Garzik Alan Cox: Increased the eeprom delay. Regardless of 321da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds what the docs say some people definitely 331da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds get problems with lower (but in card spec) 341da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds delays 351da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds v1.10 4/21/97 Fixed module code so that multiple cards may be detected, 361da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds other cleanups. -djb 371da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds Andrea Arcangeli: Upgraded to Donald Becker's version 1.12. 381da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds Rick Payne: Fixed SMP race condition 391da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds v1.13 9/8/97 Made 'max_interrupt_work' an insmod-settable variable -djb 401da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds v1.14 10/15/97 Avoided waiting..discard message for fast machines -djb 411da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds v1.15 1/31/98 Faster recovery for Tx errors. -djb 421da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds v1.16 2/3/98 Different ID port handling to avoid sound cards. -djb 43e1f8e87449147ffe5ea3de64a46af7de450ce279Francois Cami v1.18 12Mar2001 Andrew Morton 441da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds - Avoid bogus detect of 3c590's (Andrzej Krzysztofowicz) 451da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds - Reviewed against 1.18 from scyld.com 461da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds v1.18a 17Nov2001 Jeff Garzik <jgarzik@pobox.com> 471da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds - ethtool support 481da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds v1.18b 1Mar2002 Zwane Mwaikambo <zwane@commfireservices.com> 491da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds - Power Management support 501da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds v1.18c 1Mar2002 David Ruggiero <jdr@farfalle.com> 511da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds - Full duplex support 521da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds v1.19 16Oct2002 Zwane Mwaikambo <zwane@linuxpower.ca> 531da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds - Additional ethtool features 541da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds v1.19a 28Oct2002 Davud Ruggiero <jdr@farfalle.com> 551da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds - Increase *read_eeprom udelay to workaround oops with 2 cards. 561da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds v1.19b 08Nov2002 Marc Zyngier <maz@wild-wind.fr.eu.org> 57ac4bed1375c06af7c76b4615ae661791b62e93efOndrej Zary - Introduce driver model for EISA cards. 58ac4bed1375c06af7c76b4615ae661791b62e93efOndrej Zary v1.20 04Feb2008 Ondrej Zary <linux@rainbow-software.org> 59ac4bed1375c06af7c76b4615ae661791b62e93efOndrej Zary - convert to isa_driver and pnp_driver and some cleanups 601da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds*/ 611da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 621da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define DRV_NAME "3c509" 63ac4bed1375c06af7c76b4615ae661791b62e93efOndrej Zary#define DRV_VERSION "1.20" 64ac4bed1375c06af7c76b4615ae661791b62e93efOndrej Zary#define DRV_RELDATE "04Feb2008" 651da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 661da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/* A few values that may be tweaked. */ 671da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 681da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/* Time in jiffies before concluding the transmitter is hung. */ 691da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define TX_TIMEOUT (400*HZ/1000) 701da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 711da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <linux/module.h> 721da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <linux/mca.h> 73ac4bed1375c06af7c76b4615ae661791b62e93efOndrej Zary#include <linux/isa.h> 74ac4bed1375c06af7c76b4615ae661791b62e93efOndrej Zary#include <linux/pnp.h> 751da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <linux/string.h> 761da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <linux/interrupt.h> 771da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <linux/errno.h> 781da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <linux/in.h> 791da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <linux/ioport.h> 801da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <linux/init.h> 811da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <linux/netdevice.h> 821da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <linux/etherdevice.h> 831da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <linux/pm.h> 841da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <linux/skbuff.h> 851da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <linux/delay.h> /* for udelay() */ 861da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <linux/spinlock.h> 871da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <linux/ethtool.h> 881da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <linux/device.h> 891da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <linux/eisa.h> 901da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <linux/bitops.h> 911da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 921da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <asm/uaccess.h> 931da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <asm/io.h> 941da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <asm/irq.h> 951da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 9637b2a1791c8b8d630944afbe0745a08c8e8ae091Al Virostatic char version[] __devinitdata = DRV_NAME ".c:" DRV_VERSION " " DRV_RELDATE " becker@scyld.com\n"; 971da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 981da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#ifdef EL3_DEBUG 991da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic int el3_debug = EL3_DEBUG; 1001da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#else 1011da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic int el3_debug = 2; 1021da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#endif 1031da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 1041da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/* Used to do a global count of all the cards in the system. Must be 1051da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * a global variable so that the mca/eisa probe routines can increment 1061da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * it */ 1071da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic int el3_cards = 0; 108ac4bed1375c06af7c76b4615ae661791b62e93efOndrej Zary#define EL3_MAX_CARDS 8 1091da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 1101da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/* To minimize the size of the driver source I only define operating 1111da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds constants if they are used several times. You'll need the manual 1121da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds anyway if you want to understand driver details. */ 1131da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/* Offsets from base I/O address. */ 1141da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define EL3_DATA 0x00 1151da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define EL3_CMD 0x0e 1161da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define EL3_STATUS 0x0e 117ac4bed1375c06af7c76b4615ae661791b62e93efOndrej Zary#define EEPROM_READ 0x80 1181da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 1191da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define EL3_IO_EXTENT 16 1201da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 1211da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define EL3WINDOW(win_num) outw(SelectWindow + (win_num), ioaddr + EL3_CMD) 1221da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 1231da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 1241da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/* The top five bits written to EL3_CMD are a command, the lower 1251da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 11 bits are the parameter, if applicable. */ 1261da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsenum c509cmd { 1271da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds TotalReset = 0<<11, SelectWindow = 1<<11, StartCoax = 2<<11, 1281da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds RxDisable = 3<<11, RxEnable = 4<<11, RxReset = 5<<11, RxDiscard = 8<<11, 1291da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds TxEnable = 9<<11, TxDisable = 10<<11, TxReset = 11<<11, 1301da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds FakeIntr = 12<<11, AckIntr = 13<<11, SetIntrEnb = 14<<11, 1311da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds SetStatusEnb = 15<<11, SetRxFilter = 16<<11, SetRxThreshold = 17<<11, 1321da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds SetTxThreshold = 18<<11, SetTxStart = 19<<11, StatsEnable = 21<<11, 1331da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds StatsDisable = 22<<11, StopCoax = 23<<11, PowerUp = 27<<11, 1341da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds PowerDown = 28<<11, PowerAuto = 29<<11}; 1351da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 1361da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsenum c509status { 1371da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds IntLatch = 0x0001, AdapterFailure = 0x0002, TxComplete = 0x0004, 1381da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds TxAvailable = 0x0008, RxComplete = 0x0010, RxEarly = 0x0020, 1391da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds IntReq = 0x0040, StatsFull = 0x0080, CmdBusy = 0x1000, }; 1401da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 1411da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/* The SetRxFilter command accepts the following classes: */ 1421da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsenum RxFilter { 1431da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds RxStation = 1, RxMulticast = 2, RxBroadcast = 4, RxProm = 8 }; 1441da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 1451da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/* Register window 1 offsets, the window used in normal operation. */ 1461da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define TX_FIFO 0x00 1471da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define RX_FIFO 0x00 1481da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define RX_STATUS 0x08 1491da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define TX_STATUS 0x0B 1501da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define TX_FREE 0x0C /* Remaining free bytes in Tx buffer. */ 1511da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 1521da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define WN0_CONF_CTRL 0x04 /* Window 0: Configuration control register */ 1531da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define WN0_ADDR_CONF 0x06 /* Window 0: Address configuration register */ 1541da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define WN0_IRQ 0x08 /* Window 0: Set IRQ line in bits 12-15. */ 1551da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define WN4_MEDIA 0x0A /* Window 4: Various transcvr/media bits. */ 1561da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define MEDIA_TP 0x00C0 /* Enable link beat and jabber for 10baseT. */ 1571da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define WN4_NETDIAG 0x06 /* Window 4: Net diagnostic */ 1586aa20a2235535605db6d6d2bd850298b2fe7f31eJeff Garzik#define FD_ENABLE 0x8000 /* Enable full-duplex ("external loopback") */ 1591da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 1601da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/* 1611da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Must be a power of two (we use a binary and in the 1621da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * circular queue) 1631da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 1641da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define SKB_QUEUE_SIZE 64 1651da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 166ac4bed1375c06af7c76b4615ae661791b62e93efOndrej Zaryenum el3_cardtype { EL3_ISA, EL3_PNP, EL3_MCA, EL3_EISA }; 167ac4bed1375c06af7c76b4615ae661791b62e93efOndrej Zary 1681da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstruct el3_private { 1691da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds spinlock_t lock; 1701da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* skb send-queue */ 1711da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds int head, size; 1721da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds struct sk_buff *queue[SKB_QUEUE_SIZE]; 173ac4bed1375c06af7c76b4615ae661791b62e93efOndrej Zary enum el3_cardtype type; 1741da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}; 175ac4bed1375c06af7c76b4615ae661791b62e93efOndrej Zarystatic int id_port; 176ac4bed1375c06af7c76b4615ae661791b62e93efOndrej Zarystatic int current_tag; 177ac4bed1375c06af7c76b4615ae661791b62e93efOndrej Zarystatic struct net_device *el3_devs[EL3_MAX_CARDS]; 178ac4bed1375c06af7c76b4615ae661791b62e93efOndrej Zary 179ac4bed1375c06af7c76b4615ae661791b62e93efOndrej Zary/* Parameters that may be passed into the module. */ 180ac4bed1375c06af7c76b4615ae661791b62e93efOndrej Zarystatic int debug = -1; 181ac4bed1375c06af7c76b4615ae661791b62e93efOndrej Zarystatic int irq[] = {-1, -1, -1, -1, -1, -1, -1, -1}; 182ac4bed1375c06af7c76b4615ae661791b62e93efOndrej Zary/* Maximum events (Rx packets, etc.) to handle at each interrupt. */ 183ac4bed1375c06af7c76b4615ae661791b62e93efOndrej Zarystatic int max_interrupt_work = 10; 184ac4bed1375c06af7c76b4615ae661791b62e93efOndrej Zary#ifdef CONFIG_PNP 185ac4bed1375c06af7c76b4615ae661791b62e93efOndrej Zarystatic int nopnp; 186ac4bed1375c06af7c76b4615ae661791b62e93efOndrej Zary#endif 1871da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 188948252cb9e01d65a89ecadf67be5018351eee15eDavid S. Millerstatic int __devinit el3_common_init(struct net_device *dev); 189ac4bed1375c06af7c76b4615ae661791b62e93efOndrej Zarystatic void el3_common_remove(struct net_device *dev); 1901da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic ushort id_read_eeprom(int index); 1911da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic ushort read_eeprom(int ioaddr, int index); 1921da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic int el3_open(struct net_device *dev); 19327a1de95a1461ec0589005c293d6ac23a46cb72dStephen Hemmingerstatic netdev_tx_t el3_start_xmit(struct sk_buff *skb, struct net_device *dev); 1947d12e780e003f93433d49ce78cfedf4b4c52adc5David Howellsstatic irqreturn_t el3_interrupt(int irq, void *dev_id); 1951da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic void update_stats(struct net_device *dev); 1961da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic struct net_device_stats *el3_get_stats(struct net_device *dev); 1971da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic int el3_rx(struct net_device *dev); 1981da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic int el3_close(struct net_device *dev); 1991da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic void set_multicast_list(struct net_device *dev); 2001da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic void el3_tx_timeout (struct net_device *dev); 2011da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic void el3_down(struct net_device *dev); 2021da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic void el3_up(struct net_device *dev); 2037282d491ecaee9883233a0e27283c4c79486279aJeff Garzikstatic const struct ethtool_ops ethtool_ops; 204ac4bed1375c06af7c76b4615ae661791b62e93efOndrej Zary#ifdef CONFIG_PM 20560a89ff6d2681029b3d46b5d23dccf2903a254b4Pekka Enbergstatic int el3_suspend(struct device *, pm_message_t); 20660a89ff6d2681029b3d46b5d23dccf2903a254b4Pekka Enbergstatic int el3_resume(struct device *); 20760a89ff6d2681029b3d46b5d23dccf2903a254b4Pekka Enberg#else 20860a89ff6d2681029b3d46b5d23dccf2903a254b4Pekka Enberg#define el3_suspend NULL 20960a89ff6d2681029b3d46b5d23dccf2903a254b4Pekka Enberg#define el3_resume NULL 2101da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#endif 21160a89ff6d2681029b3d46b5d23dccf2903a254b4Pekka Enberg 21260a89ff6d2681029b3d46b5d23dccf2903a254b4Pekka Enberg 2131da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/* generic device remove for all device types */ 2141da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic int el3_device_remove (struct device *device); 2151da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#ifdef CONFIG_NET_POLL_CONTROLLER 2161da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic void el3_poll_controller(struct net_device *dev); 2171da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#endif 2181da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 219ac4bed1375c06af7c76b4615ae661791b62e93efOndrej Zary/* Return 0 on success, 1 on error, 2 when found already detected PnP card */ 220ac4bed1375c06af7c76b4615ae661791b62e93efOndrej Zarystatic int el3_isa_id_sequence(__be16 *phys_addr) 221ac4bed1375c06af7c76b4615ae661791b62e93efOndrej Zary{ 222ac4bed1375c06af7c76b4615ae661791b62e93efOndrej Zary short lrs_state = 0xff; 223ac4bed1375c06af7c76b4615ae661791b62e93efOndrej Zary int i; 224ac4bed1375c06af7c76b4615ae661791b62e93efOndrej Zary 225ac4bed1375c06af7c76b4615ae661791b62e93efOndrej Zary /* ISA boards are detected by sending the ID sequence to the 226ac4bed1375c06af7c76b4615ae661791b62e93efOndrej Zary ID_PORT. We find cards past the first by setting the 'current_tag' 227ac4bed1375c06af7c76b4615ae661791b62e93efOndrej Zary on cards as they are found. Cards with their tag set will not 228ac4bed1375c06af7c76b4615ae661791b62e93efOndrej Zary respond to subsequent ID sequences. */ 229ac4bed1375c06af7c76b4615ae661791b62e93efOndrej Zary 230ac4bed1375c06af7c76b4615ae661791b62e93efOndrej Zary outb(0x00, id_port); 231ac4bed1375c06af7c76b4615ae661791b62e93efOndrej Zary outb(0x00, id_port); 232ac4bed1375c06af7c76b4615ae661791b62e93efOndrej Zary for (i = 0; i < 255; i++) { 233ac4bed1375c06af7c76b4615ae661791b62e93efOndrej Zary outb(lrs_state, id_port); 234ac4bed1375c06af7c76b4615ae661791b62e93efOndrej Zary lrs_state <<= 1; 235ac4bed1375c06af7c76b4615ae661791b62e93efOndrej Zary lrs_state = lrs_state & 0x100 ? lrs_state ^ 0xcf : lrs_state; 236ac4bed1375c06af7c76b4615ae661791b62e93efOndrej Zary } 237ac4bed1375c06af7c76b4615ae661791b62e93efOndrej Zary /* For the first probe, clear all board's tag registers. */ 238ac4bed1375c06af7c76b4615ae661791b62e93efOndrej Zary if (current_tag == 0) 239ac4bed1375c06af7c76b4615ae661791b62e93efOndrej Zary outb(0xd0, id_port); 240ac4bed1375c06af7c76b4615ae661791b62e93efOndrej Zary else /* Otherwise kill off already-found boards. */ 241ac4bed1375c06af7c76b4615ae661791b62e93efOndrej Zary outb(0xd8, id_port); 242ac4bed1375c06af7c76b4615ae661791b62e93efOndrej Zary if (id_read_eeprom(7) != 0x6d50) 243ac4bed1375c06af7c76b4615ae661791b62e93efOndrej Zary return 1; 244ac4bed1375c06af7c76b4615ae661791b62e93efOndrej Zary /* Read in EEPROM data, which does contention-select. 245ac4bed1375c06af7c76b4615ae661791b62e93efOndrej Zary Only the lowest address board will stay "on-line". 246ac4bed1375c06af7c76b4615ae661791b62e93efOndrej Zary 3Com got the byte order backwards. */ 247ac4bed1375c06af7c76b4615ae661791b62e93efOndrej Zary for (i = 0; i < 3; i++) 248ac4bed1375c06af7c76b4615ae661791b62e93efOndrej Zary phys_addr[i] = htons(id_read_eeprom(i)); 249ac4bed1375c06af7c76b4615ae661791b62e93efOndrej Zary#ifdef CONFIG_PNP 250ac4bed1375c06af7c76b4615ae661791b62e93efOndrej Zary if (!nopnp) { 251ac4bed1375c06af7c76b4615ae661791b62e93efOndrej Zary /* The ISA PnP 3c509 cards respond to the ID sequence too. 252ac4bed1375c06af7c76b4615ae661791b62e93efOndrej Zary This check is needed in order not to register them twice. */ 253ac4bed1375c06af7c76b4615ae661791b62e93efOndrej Zary for (i = 0; i < el3_cards; i++) { 254ac4bed1375c06af7c76b4615ae661791b62e93efOndrej Zary struct el3_private *lp = netdev_priv(el3_devs[i]); 2558e95a2026f3b43f7c3d676adaccd2de9532e8dccJoe Perches if (lp->type == EL3_PNP && 2568e95a2026f3b43f7c3d676adaccd2de9532e8dccJoe Perches !memcmp(phys_addr, el3_devs[i]->dev_addr, 2578e95a2026f3b43f7c3d676adaccd2de9532e8dccJoe Perches ETH_ALEN)) { 258ac4bed1375c06af7c76b4615ae661791b62e93efOndrej Zary if (el3_debug > 3) 259646cdb32831eebe8c2f742c293d0d266326854d9Alexander Beregalov pr_debug("3c509 with address %02x %02x %02x %02x %02x %02x was found by ISAPnP\n", 260ac4bed1375c06af7c76b4615ae661791b62e93efOndrej Zary phys_addr[0] & 0xff, phys_addr[0] >> 8, 261ac4bed1375c06af7c76b4615ae661791b62e93efOndrej Zary phys_addr[1] & 0xff, phys_addr[1] >> 8, 262ac4bed1375c06af7c76b4615ae661791b62e93efOndrej Zary phys_addr[2] & 0xff, phys_addr[2] >> 8); 263ac4bed1375c06af7c76b4615ae661791b62e93efOndrej Zary /* Set the adaptor tag so that the next card can be found. */ 264ac4bed1375c06af7c76b4615ae661791b62e93efOndrej Zary outb(0xd0 + ++current_tag, id_port); 265ac4bed1375c06af7c76b4615ae661791b62e93efOndrej Zary return 2; 266ac4bed1375c06af7c76b4615ae661791b62e93efOndrej Zary } 267ac4bed1375c06af7c76b4615ae661791b62e93efOndrej Zary } 268ac4bed1375c06af7c76b4615ae661791b62e93efOndrej Zary } 269ac4bed1375c06af7c76b4615ae661791b62e93efOndrej Zary#endif /* CONFIG_PNP */ 270ac4bed1375c06af7c76b4615ae661791b62e93efOndrej Zary return 0; 271ac4bed1375c06af7c76b4615ae661791b62e93efOndrej Zary 272ac4bed1375c06af7c76b4615ae661791b62e93efOndrej Zary} 273ac4bed1375c06af7c76b4615ae661791b62e93efOndrej Zary 274ac4bed1375c06af7c76b4615ae661791b62e93efOndrej Zarystatic void __devinit el3_dev_fill(struct net_device *dev, __be16 *phys_addr, 275ac4bed1375c06af7c76b4615ae661791b62e93efOndrej Zary int ioaddr, int irq, int if_port, 276ac4bed1375c06af7c76b4615ae661791b62e93efOndrej Zary enum el3_cardtype type) 277ac4bed1375c06af7c76b4615ae661791b62e93efOndrej Zary{ 278ac4bed1375c06af7c76b4615ae661791b62e93efOndrej Zary struct el3_private *lp = netdev_priv(dev); 279ac4bed1375c06af7c76b4615ae661791b62e93efOndrej Zary 280ac4bed1375c06af7c76b4615ae661791b62e93efOndrej Zary memcpy(dev->dev_addr, phys_addr, ETH_ALEN); 281ac4bed1375c06af7c76b4615ae661791b62e93efOndrej Zary dev->base_addr = ioaddr; 282ac4bed1375c06af7c76b4615ae661791b62e93efOndrej Zary dev->irq = irq; 283ac4bed1375c06af7c76b4615ae661791b62e93efOndrej Zary dev->if_port = if_port; 284ac4bed1375c06af7c76b4615ae661791b62e93efOndrej Zary lp->type = type; 285ac4bed1375c06af7c76b4615ae661791b62e93efOndrej Zary} 286ac4bed1375c06af7c76b4615ae661791b62e93efOndrej Zary 287ac4bed1375c06af7c76b4615ae661791b62e93efOndrej Zarystatic int __devinit el3_isa_match(struct device *pdev, 288ac4bed1375c06af7c76b4615ae661791b62e93efOndrej Zary unsigned int ndev) 289ac4bed1375c06af7c76b4615ae661791b62e93efOndrej Zary{ 290ac4bed1375c06af7c76b4615ae661791b62e93efOndrej Zary struct net_device *dev; 291ac4bed1375c06af7c76b4615ae661791b62e93efOndrej Zary int ioaddr, isa_irq, if_port, err; 292ac4bed1375c06af7c76b4615ae661791b62e93efOndrej Zary unsigned int iobase; 293ac4bed1375c06af7c76b4615ae661791b62e93efOndrej Zary __be16 phys_addr[3]; 294ac4bed1375c06af7c76b4615ae661791b62e93efOndrej Zary 295ac4bed1375c06af7c76b4615ae661791b62e93efOndrej Zary while ((err = el3_isa_id_sequence(phys_addr)) == 2) 296ac4bed1375c06af7c76b4615ae661791b62e93efOndrej Zary ; /* Skip to next card when PnP card found */ 297ac4bed1375c06af7c76b4615ae661791b62e93efOndrej Zary if (err == 1) 298ac4bed1375c06af7c76b4615ae661791b62e93efOndrej Zary return 0; 299ac4bed1375c06af7c76b4615ae661791b62e93efOndrej Zary 300ac4bed1375c06af7c76b4615ae661791b62e93efOndrej Zary iobase = id_read_eeprom(8); 301ac4bed1375c06af7c76b4615ae661791b62e93efOndrej Zary if_port = iobase >> 14; 302ac4bed1375c06af7c76b4615ae661791b62e93efOndrej Zary ioaddr = 0x200 + ((iobase & 0x1f) << 4); 303ac4bed1375c06af7c76b4615ae661791b62e93efOndrej Zary if (irq[el3_cards] > 1 && irq[el3_cards] < 16) 304ac4bed1375c06af7c76b4615ae661791b62e93efOndrej Zary isa_irq = irq[el3_cards]; 305ac4bed1375c06af7c76b4615ae661791b62e93efOndrej Zary else 306ac4bed1375c06af7c76b4615ae661791b62e93efOndrej Zary isa_irq = id_read_eeprom(9) >> 12; 307ac4bed1375c06af7c76b4615ae661791b62e93efOndrej Zary 308ac4bed1375c06af7c76b4615ae661791b62e93efOndrej Zary dev = alloc_etherdev(sizeof(struct el3_private)); 309ac4bed1375c06af7c76b4615ae661791b62e93efOndrej Zary if (!dev) 310ac4bed1375c06af7c76b4615ae661791b62e93efOndrej Zary return -ENOMEM; 311ac4bed1375c06af7c76b4615ae661791b62e93efOndrej Zary 312ac4bed1375c06af7c76b4615ae661791b62e93efOndrej Zary netdev_boot_setup_check(dev); 313ac4bed1375c06af7c76b4615ae661791b62e93efOndrej Zary 314ac4bed1375c06af7c76b4615ae661791b62e93efOndrej Zary if (!request_region(ioaddr, EL3_IO_EXTENT, "3c509-isa")) { 315ac4bed1375c06af7c76b4615ae661791b62e93efOndrej Zary free_netdev(dev); 316ac4bed1375c06af7c76b4615ae661791b62e93efOndrej Zary return 0; 317ac4bed1375c06af7c76b4615ae661791b62e93efOndrej Zary } 318ac4bed1375c06af7c76b4615ae661791b62e93efOndrej Zary 319ac4bed1375c06af7c76b4615ae661791b62e93efOndrej Zary /* Set the adaptor tag so that the next card can be found. */ 320ac4bed1375c06af7c76b4615ae661791b62e93efOndrej Zary outb(0xd0 + ++current_tag, id_port); 321ac4bed1375c06af7c76b4615ae661791b62e93efOndrej Zary 322ac4bed1375c06af7c76b4615ae661791b62e93efOndrej Zary /* Activate the adaptor at the EEPROM location. */ 323ac4bed1375c06af7c76b4615ae661791b62e93efOndrej Zary outb((ioaddr >> 4) | 0xe0, id_port); 324ac4bed1375c06af7c76b4615ae661791b62e93efOndrej Zary 325ac4bed1375c06af7c76b4615ae661791b62e93efOndrej Zary EL3WINDOW(0); 326ac4bed1375c06af7c76b4615ae661791b62e93efOndrej Zary if (inw(ioaddr) != 0x6d50) { 327ac4bed1375c06af7c76b4615ae661791b62e93efOndrej Zary free_netdev(dev); 328ac4bed1375c06af7c76b4615ae661791b62e93efOndrej Zary return 0; 329ac4bed1375c06af7c76b4615ae661791b62e93efOndrej Zary } 330ac4bed1375c06af7c76b4615ae661791b62e93efOndrej Zary 331ac4bed1375c06af7c76b4615ae661791b62e93efOndrej Zary /* Free the interrupt so that some other card can use it. */ 332ac4bed1375c06af7c76b4615ae661791b62e93efOndrej Zary outw(0x0f00, ioaddr + WN0_IRQ); 333ac4bed1375c06af7c76b4615ae661791b62e93efOndrej Zary 334ac4bed1375c06af7c76b4615ae661791b62e93efOndrej Zary el3_dev_fill(dev, phys_addr, ioaddr, isa_irq, if_port, EL3_ISA); 335ac4bed1375c06af7c76b4615ae661791b62e93efOndrej Zary dev_set_drvdata(pdev, dev); 336ac4bed1375c06af7c76b4615ae661791b62e93efOndrej Zary if (el3_common_init(dev)) { 337ac4bed1375c06af7c76b4615ae661791b62e93efOndrej Zary free_netdev(dev); 338ac4bed1375c06af7c76b4615ae661791b62e93efOndrej Zary return 0; 339ac4bed1375c06af7c76b4615ae661791b62e93efOndrej Zary } 340ac4bed1375c06af7c76b4615ae661791b62e93efOndrej Zary 341ac4bed1375c06af7c76b4615ae661791b62e93efOndrej Zary el3_devs[el3_cards++] = dev; 342ac4bed1375c06af7c76b4615ae661791b62e93efOndrej Zary return 1; 343ac4bed1375c06af7c76b4615ae661791b62e93efOndrej Zary} 344ac4bed1375c06af7c76b4615ae661791b62e93efOndrej Zary 345ac4bed1375c06af7c76b4615ae661791b62e93efOndrej Zarystatic int __devexit el3_isa_remove(struct device *pdev, 346ac4bed1375c06af7c76b4615ae661791b62e93efOndrej Zary unsigned int ndev) 347ac4bed1375c06af7c76b4615ae661791b62e93efOndrej Zary{ 348ac4bed1375c06af7c76b4615ae661791b62e93efOndrej Zary el3_device_remove(pdev); 349ac4bed1375c06af7c76b4615ae661791b62e93efOndrej Zary dev_set_drvdata(pdev, NULL); 350ac4bed1375c06af7c76b4615ae661791b62e93efOndrej Zary return 0; 351ac4bed1375c06af7c76b4615ae661791b62e93efOndrej Zary} 352ac4bed1375c06af7c76b4615ae661791b62e93efOndrej Zary 353ac4bed1375c06af7c76b4615ae661791b62e93efOndrej Zary#ifdef CONFIG_PM 354ac4bed1375c06af7c76b4615ae661791b62e93efOndrej Zarystatic int el3_isa_suspend(struct device *dev, unsigned int n, 355ac4bed1375c06af7c76b4615ae661791b62e93efOndrej Zary pm_message_t state) 356ac4bed1375c06af7c76b4615ae661791b62e93efOndrej Zary{ 357ac4bed1375c06af7c76b4615ae661791b62e93efOndrej Zary current_tag = 0; 358ac4bed1375c06af7c76b4615ae661791b62e93efOndrej Zary return el3_suspend(dev, state); 359ac4bed1375c06af7c76b4615ae661791b62e93efOndrej Zary} 360ac4bed1375c06af7c76b4615ae661791b62e93efOndrej Zary 361ac4bed1375c06af7c76b4615ae661791b62e93efOndrej Zarystatic int el3_isa_resume(struct device *dev, unsigned int n) 362ac4bed1375c06af7c76b4615ae661791b62e93efOndrej Zary{ 363ac4bed1375c06af7c76b4615ae661791b62e93efOndrej Zary struct net_device *ndev = dev_get_drvdata(dev); 364ac4bed1375c06af7c76b4615ae661791b62e93efOndrej Zary int ioaddr = ndev->base_addr, err; 365ac4bed1375c06af7c76b4615ae661791b62e93efOndrej Zary __be16 phys_addr[3]; 366ac4bed1375c06af7c76b4615ae661791b62e93efOndrej Zary 367ac4bed1375c06af7c76b4615ae661791b62e93efOndrej Zary while ((err = el3_isa_id_sequence(phys_addr)) == 2) 368ac4bed1375c06af7c76b4615ae661791b62e93efOndrej Zary ; /* Skip to next card when PnP card found */ 369ac4bed1375c06af7c76b4615ae661791b62e93efOndrej Zary if (err == 1) 370ac4bed1375c06af7c76b4615ae661791b62e93efOndrej Zary return 0; 371ac4bed1375c06af7c76b4615ae661791b62e93efOndrej Zary /* Set the adaptor tag so that the next card can be found. */ 372ac4bed1375c06af7c76b4615ae661791b62e93efOndrej Zary outb(0xd0 + ++current_tag, id_port); 373ac4bed1375c06af7c76b4615ae661791b62e93efOndrej Zary /* Enable the card */ 374ac4bed1375c06af7c76b4615ae661791b62e93efOndrej Zary outb((ioaddr >> 4) | 0xe0, id_port); 375ac4bed1375c06af7c76b4615ae661791b62e93efOndrej Zary EL3WINDOW(0); 376ac4bed1375c06af7c76b4615ae661791b62e93efOndrej Zary if (inw(ioaddr) != 0x6d50) 377ac4bed1375c06af7c76b4615ae661791b62e93efOndrej Zary return 1; 378ac4bed1375c06af7c76b4615ae661791b62e93efOndrej Zary /* Free the interrupt so that some other card can use it. */ 379ac4bed1375c06af7c76b4615ae661791b62e93efOndrej Zary outw(0x0f00, ioaddr + WN0_IRQ); 380ac4bed1375c06af7c76b4615ae661791b62e93efOndrej Zary return el3_resume(dev); 381ac4bed1375c06af7c76b4615ae661791b62e93efOndrej Zary} 382ac4bed1375c06af7c76b4615ae661791b62e93efOndrej Zary#endif 383ac4bed1375c06af7c76b4615ae661791b62e93efOndrej Zary 384ac4bed1375c06af7c76b4615ae661791b62e93efOndrej Zarystatic struct isa_driver el3_isa_driver = { 385ac4bed1375c06af7c76b4615ae661791b62e93efOndrej Zary .match = el3_isa_match, 386ac4bed1375c06af7c76b4615ae661791b62e93efOndrej Zary .remove = __devexit_p(el3_isa_remove), 387ac4bed1375c06af7c76b4615ae661791b62e93efOndrej Zary#ifdef CONFIG_PM 388ac4bed1375c06af7c76b4615ae661791b62e93efOndrej Zary .suspend = el3_isa_suspend, 389ac4bed1375c06af7c76b4615ae661791b62e93efOndrej Zary .resume = el3_isa_resume, 390ac4bed1375c06af7c76b4615ae661791b62e93efOndrej Zary#endif 391ac4bed1375c06af7c76b4615ae661791b62e93efOndrej Zary .driver = { 392ac4bed1375c06af7c76b4615ae661791b62e93efOndrej Zary .name = "3c509" 393ac4bed1375c06af7c76b4615ae661791b62e93efOndrej Zary }, 394ac4bed1375c06af7c76b4615ae661791b62e93efOndrej Zary}; 395ac4bed1375c06af7c76b4615ae661791b62e93efOndrej Zarystatic int isa_registered; 396ac4bed1375c06af7c76b4615ae661791b62e93efOndrej Zary 397ac4bed1375c06af7c76b4615ae661791b62e93efOndrej Zary#ifdef CONFIG_PNP 398948252cb9e01d65a89ecadf67be5018351eee15eDavid S. Millerstatic struct pnp_device_id el3_pnp_ids[] = { 399ac4bed1375c06af7c76b4615ae661791b62e93efOndrej Zary { .id = "TCM5090" }, /* 3Com Etherlink III (TP) */ 400ac4bed1375c06af7c76b4615ae661791b62e93efOndrej Zary { .id = "TCM5091" }, /* 3Com Etherlink III */ 401ac4bed1375c06af7c76b4615ae661791b62e93efOndrej Zary { .id = "TCM5094" }, /* 3Com Etherlink III (combo) */ 402ac4bed1375c06af7c76b4615ae661791b62e93efOndrej Zary { .id = "TCM5095" }, /* 3Com Etherlink III (TPO) */ 403ac4bed1375c06af7c76b4615ae661791b62e93efOndrej Zary { .id = "TCM5098" }, /* 3Com Etherlink III (TPC) */ 404ac4bed1375c06af7c76b4615ae661791b62e93efOndrej Zary { .id = "PNP80f7" }, /* 3Com Etherlink III compatible */ 405ac4bed1375c06af7c76b4615ae661791b62e93efOndrej Zary { .id = "PNP80f8" }, /* 3Com Etherlink III compatible */ 406ac4bed1375c06af7c76b4615ae661791b62e93efOndrej Zary { .id = "" } 407ac4bed1375c06af7c76b4615ae661791b62e93efOndrej Zary}; 408ac4bed1375c06af7c76b4615ae661791b62e93efOndrej ZaryMODULE_DEVICE_TABLE(pnp, el3_pnp_ids); 409ac4bed1375c06af7c76b4615ae661791b62e93efOndrej Zary 410ac4bed1375c06af7c76b4615ae661791b62e93efOndrej Zarystatic int __devinit el3_pnp_probe(struct pnp_dev *pdev, 411ac4bed1375c06af7c76b4615ae661791b62e93efOndrej Zary const struct pnp_device_id *id) 412ac4bed1375c06af7c76b4615ae661791b62e93efOndrej Zary{ 413ac4bed1375c06af7c76b4615ae661791b62e93efOndrej Zary short i; 414ac4bed1375c06af7c76b4615ae661791b62e93efOndrej Zary int ioaddr, irq, if_port; 4154ec7ffa2df247054d422b48148ad82369a45e986Al Viro __be16 phys_addr[3]; 416ac4bed1375c06af7c76b4615ae661791b62e93efOndrej Zary struct net_device *dev = NULL; 417ac4bed1375c06af7c76b4615ae661791b62e93efOndrej Zary int err; 418ac4bed1375c06af7c76b4615ae661791b62e93efOndrej Zary 419ac4bed1375c06af7c76b4615ae661791b62e93efOndrej Zary ioaddr = pnp_port_start(pdev, 0); 420ac4bed1375c06af7c76b4615ae661791b62e93efOndrej Zary if (!request_region(ioaddr, EL3_IO_EXTENT, "3c509-pnp")) 421ac4bed1375c06af7c76b4615ae661791b62e93efOndrej Zary return -EBUSY; 422ac4bed1375c06af7c76b4615ae661791b62e93efOndrej Zary irq = pnp_irq(pdev, 0); 423ac4bed1375c06af7c76b4615ae661791b62e93efOndrej Zary EL3WINDOW(0); 424ac4bed1375c06af7c76b4615ae661791b62e93efOndrej Zary for (i = 0; i < 3; i++) 425ac4bed1375c06af7c76b4615ae661791b62e93efOndrej Zary phys_addr[i] = htons(read_eeprom(ioaddr, i)); 426ac4bed1375c06af7c76b4615ae661791b62e93efOndrej Zary if_port = read_eeprom(ioaddr, 8) >> 14; 427ac4bed1375c06af7c76b4615ae661791b62e93efOndrej Zary dev = alloc_etherdev(sizeof(struct el3_private)); 428ac4bed1375c06af7c76b4615ae661791b62e93efOndrej Zary if (!dev) { 429ac4bed1375c06af7c76b4615ae661791b62e93efOndrej Zary release_region(ioaddr, EL3_IO_EXTENT); 430ac4bed1375c06af7c76b4615ae661791b62e93efOndrej Zary return -ENOMEM; 431ac4bed1375c06af7c76b4615ae661791b62e93efOndrej Zary } 432ac4bed1375c06af7c76b4615ae661791b62e93efOndrej Zary SET_NETDEV_DEV(dev, &pdev->dev); 433ac4bed1375c06af7c76b4615ae661791b62e93efOndrej Zary netdev_boot_setup_check(dev); 434ac4bed1375c06af7c76b4615ae661791b62e93efOndrej Zary 435ac4bed1375c06af7c76b4615ae661791b62e93efOndrej Zary el3_dev_fill(dev, phys_addr, ioaddr, irq, if_port, EL3_PNP); 436ac4bed1375c06af7c76b4615ae661791b62e93efOndrej Zary pnp_set_drvdata(pdev, dev); 437ac4bed1375c06af7c76b4615ae661791b62e93efOndrej Zary err = el3_common_init(dev); 438ac4bed1375c06af7c76b4615ae661791b62e93efOndrej Zary 439ac4bed1375c06af7c76b4615ae661791b62e93efOndrej Zary if (err) { 440ac4bed1375c06af7c76b4615ae661791b62e93efOndrej Zary pnp_set_drvdata(pdev, NULL); 441ac4bed1375c06af7c76b4615ae661791b62e93efOndrej Zary free_netdev(dev); 442ac4bed1375c06af7c76b4615ae661791b62e93efOndrej Zary return err; 443ac4bed1375c06af7c76b4615ae661791b62e93efOndrej Zary } 444ac4bed1375c06af7c76b4615ae661791b62e93efOndrej Zary 445ac4bed1375c06af7c76b4615ae661791b62e93efOndrej Zary el3_devs[el3_cards++] = dev; 446ac4bed1375c06af7c76b4615ae661791b62e93efOndrej Zary return 0; 447ac4bed1375c06af7c76b4615ae661791b62e93efOndrej Zary} 448ac4bed1375c06af7c76b4615ae661791b62e93efOndrej Zary 449ac4bed1375c06af7c76b4615ae661791b62e93efOndrej Zarystatic void __devexit el3_pnp_remove(struct pnp_dev *pdev) 450ac4bed1375c06af7c76b4615ae661791b62e93efOndrej Zary{ 451ac4bed1375c06af7c76b4615ae661791b62e93efOndrej Zary el3_common_remove(pnp_get_drvdata(pdev)); 452ac4bed1375c06af7c76b4615ae661791b62e93efOndrej Zary pnp_set_drvdata(pdev, NULL); 453ac4bed1375c06af7c76b4615ae661791b62e93efOndrej Zary} 454ac4bed1375c06af7c76b4615ae661791b62e93efOndrej Zary 455ac4bed1375c06af7c76b4615ae661791b62e93efOndrej Zary#ifdef CONFIG_PM 456ac4bed1375c06af7c76b4615ae661791b62e93efOndrej Zarystatic int el3_pnp_suspend(struct pnp_dev *pdev, pm_message_t state) 457ac4bed1375c06af7c76b4615ae661791b62e93efOndrej Zary{ 458ac4bed1375c06af7c76b4615ae661791b62e93efOndrej Zary return el3_suspend(&pdev->dev, state); 459ac4bed1375c06af7c76b4615ae661791b62e93efOndrej Zary} 460ac4bed1375c06af7c76b4615ae661791b62e93efOndrej Zary 461ac4bed1375c06af7c76b4615ae661791b62e93efOndrej Zarystatic int el3_pnp_resume(struct pnp_dev *pdev) 462ac4bed1375c06af7c76b4615ae661791b62e93efOndrej Zary{ 463ac4bed1375c06af7c76b4615ae661791b62e93efOndrej Zary return el3_resume(&pdev->dev); 464ac4bed1375c06af7c76b4615ae661791b62e93efOndrej Zary} 465ac4bed1375c06af7c76b4615ae661791b62e93efOndrej Zary#endif 466ac4bed1375c06af7c76b4615ae661791b62e93efOndrej Zary 467ac4bed1375c06af7c76b4615ae661791b62e93efOndrej Zarystatic struct pnp_driver el3_pnp_driver = { 468ac4bed1375c06af7c76b4615ae661791b62e93efOndrej Zary .name = "3c509", 469ac4bed1375c06af7c76b4615ae661791b62e93efOndrej Zary .id_table = el3_pnp_ids, 470ac4bed1375c06af7c76b4615ae661791b62e93efOndrej Zary .probe = el3_pnp_probe, 471ac4bed1375c06af7c76b4615ae661791b62e93efOndrej Zary .remove = __devexit_p(el3_pnp_remove), 472ac4bed1375c06af7c76b4615ae661791b62e93efOndrej Zary#ifdef CONFIG_PM 473ac4bed1375c06af7c76b4615ae661791b62e93efOndrej Zary .suspend = el3_pnp_suspend, 474ac4bed1375c06af7c76b4615ae661791b62e93efOndrej Zary .resume = el3_pnp_resume, 475ac4bed1375c06af7c76b4615ae661791b62e93efOndrej Zary#endif 476ac4bed1375c06af7c76b4615ae661791b62e93efOndrej Zary}; 477ac4bed1375c06af7c76b4615ae661791b62e93efOndrej Zarystatic int pnp_registered; 478ac4bed1375c06af7c76b4615ae661791b62e93efOndrej Zary#endif /* CONFIG_PNP */ 479ac4bed1375c06af7c76b4615ae661791b62e93efOndrej Zary 4801da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#ifdef CONFIG_EISA 481948252cb9e01d65a89ecadf67be5018351eee15eDavid S. Millerstatic struct eisa_device_id el3_eisa_ids[] = { 482cf9f6e21c155d5add733b969c695837ead79eeabMaciej W. Rozycki { "TCM5090" }, 483cf9f6e21c155d5add733b969c695837ead79eeabMaciej W. Rozycki { "TCM5091" }, 4841da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds { "TCM5092" }, 4851da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds { "TCM5093" }, 486cf9f6e21c155d5add733b969c695837ead79eeabMaciej W. Rozycki { "TCM5094" }, 487f04e3f092a855ce798f274b38712b90d51b73bcaAdrian Bunk { "TCM5095" }, 488cf9f6e21c155d5add733b969c695837ead79eeabMaciej W. Rozycki { "TCM5098" }, 4891da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds { "" } 4901da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}; 49107563c711fbc25389e58ab9c9f0b9de2fce56760Michael TokarevMODULE_DEVICE_TABLE(eisa, el3_eisa_ids); 4921da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 4931da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic int el3_eisa_probe (struct device *device); 4941da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 4951da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic struct eisa_driver el3_eisa_driver = { 4961da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds .id_table = el3_eisa_ids, 4971da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds .driver = { 498ac4bed1375c06af7c76b4615ae661791b62e93efOndrej Zary .name = "3c579", 4991da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds .probe = el3_eisa_probe, 50060a89ff6d2681029b3d46b5d23dccf2903a254b4Pekka Enberg .remove = __devexit_p (el3_device_remove), 50160a89ff6d2681029b3d46b5d23dccf2903a254b4Pekka Enberg .suspend = el3_suspend, 50260a89ff6d2681029b3d46b5d23dccf2903a254b4Pekka Enberg .resume = el3_resume, 5031da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 5041da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}; 505ac4bed1375c06af7c76b4615ae661791b62e93efOndrej Zarystatic int eisa_registered; 5061da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#endif 5071da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 5081da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#ifdef CONFIG_MCA 5091da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic int el3_mca_probe(struct device *dev); 5101da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 511948252cb9e01d65a89ecadf67be5018351eee15eDavid S. Millerstatic short el3_mca_adapter_ids[] __initdata = { 5121da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 0x627c, 5131da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 0x627d, 5141da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 0x62db, 5151da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 0x62f6, 5161da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 0x62f7, 5171da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 0x0000 5181da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}; 5191da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 520948252cb9e01d65a89ecadf67be5018351eee15eDavid S. Millerstatic char *el3_mca_adapter_names[] __initdata = { 5211da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds "3Com 3c529 EtherLink III (10base2)", 5221da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds "3Com 3c529 EtherLink III (10baseT)", 5231da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds "3Com 3c529 EtherLink III (test mode)", 5241da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds "3Com 3c529 EtherLink III (TP or coax)", 5251da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds "3Com 3c529 EtherLink III (TP)", 5261da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds NULL 5271da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}; 5281da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 5291da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic struct mca_driver el3_mca_driver = { 5301da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds .id_table = el3_mca_adapter_ids, 5311da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds .driver = { 5321da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds .name = "3c529", 5331da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds .bus = &mca_bus_type, 5341da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds .probe = el3_mca_probe, 5351da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds .remove = __devexit_p(el3_device_remove), 53660a89ff6d2681029b3d46b5d23dccf2903a254b4Pekka Enberg .suspend = el3_suspend, 53760a89ff6d2681029b3d46b5d23dccf2903a254b4Pekka Enberg .resume = el3_resume, 5381da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds }, 5391da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}; 540ac4bed1375c06af7c76b4615ae661791b62e93efOndrej Zarystatic int mca_registered; 5411da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#endif /* CONFIG_MCA */ 5421da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 5433186ae8f3f5a30ecfed9faa76ce113830da39fbdStephen Hemmingerstatic const struct net_device_ops netdev_ops = { 5443186ae8f3f5a30ecfed9faa76ce113830da39fbdStephen Hemminger .ndo_open = el3_open, 5453186ae8f3f5a30ecfed9faa76ce113830da39fbdStephen Hemminger .ndo_stop = el3_close, 5463186ae8f3f5a30ecfed9faa76ce113830da39fbdStephen Hemminger .ndo_start_xmit = el3_start_xmit, 5473186ae8f3f5a30ecfed9faa76ce113830da39fbdStephen Hemminger .ndo_get_stats = el3_get_stats, 548afc4b13df143122f99a0eb10bfefb216c2806de0Jiri Pirko .ndo_set_rx_mode = set_multicast_list, 5493186ae8f3f5a30ecfed9faa76ce113830da39fbdStephen Hemminger .ndo_tx_timeout = el3_tx_timeout, 5503186ae8f3f5a30ecfed9faa76ce113830da39fbdStephen Hemminger .ndo_change_mtu = eth_change_mtu, 5513186ae8f3f5a30ecfed9faa76ce113830da39fbdStephen Hemminger .ndo_set_mac_address = eth_mac_addr, 5523186ae8f3f5a30ecfed9faa76ce113830da39fbdStephen Hemminger .ndo_validate_addr = eth_validate_addr, 5533186ae8f3f5a30ecfed9faa76ce113830da39fbdStephen Hemminger#ifdef CONFIG_NET_POLL_CONTROLLER 5543186ae8f3f5a30ecfed9faa76ce113830da39fbdStephen Hemminger .ndo_poll_controller = el3_poll_controller, 5553186ae8f3f5a30ecfed9faa76ce113830da39fbdStephen Hemminger#endif 5563186ae8f3f5a30ecfed9faa76ce113830da39fbdStephen Hemminger}; 5573186ae8f3f5a30ecfed9faa76ce113830da39fbdStephen Hemminger 55837b2a1791c8b8d630944afbe0745a08c8e8ae091Al Virostatic int __devinit el3_common_init(struct net_device *dev) 5591da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 5601da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds struct el3_private *lp = netdev_priv(dev); 5611da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds int err; 5620795af5729b18218767fab27c44b1384f72dc9adJoe Perches const char *if_names[] = {"10baseT", "AUI", "undefined", "BNC"}; 5631da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 5641da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds spin_lock_init(&lp->lock); 5651da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 5661da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (dev->mem_start & 0x05) { /* xcvr codes 1/3/4/12 */ 5671da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds dev->if_port = (dev->mem_start & 0x0f); 5681da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } else { /* xcvr codes 0/8 */ 5691da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* use eeprom value, but save user's full-duplex selection */ 5701da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds dev->if_port |= (dev->mem_start & 0x08); 5711da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 5721da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 5731da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* The EL3-specific entries in the device structure. */ 5743186ae8f3f5a30ecfed9faa76ce113830da39fbdStephen Hemminger dev->netdev_ops = &netdev_ops; 5751da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds dev->watchdog_timeo = TX_TIMEOUT; 5761da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds SET_ETHTOOL_OPS(dev, ðtool_ops); 5771da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 5781da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds err = register_netdev(dev); 5791da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (err) { 580646cdb32831eebe8c2f742c293d0d266326854d9Alexander Beregalov pr_err("Failed to register 3c5x9 at %#3.3lx, IRQ %d.\n", 5811da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds dev->base_addr, dev->irq); 5821da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds release_region(dev->base_addr, EL3_IO_EXTENT); 5831da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return err; 5841da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 5851da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 586646cdb32831eebe8c2f742c293d0d266326854d9Alexander Beregalov pr_info("%s: 3c5x9 found at %#3.3lx, %s port, address %pM, IRQ %d.\n", 5870795af5729b18218767fab27c44b1384f72dc9adJoe Perches dev->name, dev->base_addr, if_names[(dev->if_port & 0x03)], 588e174961ca1a0b28f7abf0be47973ad57cb74e5f0Johannes Berg dev->dev_addr, dev->irq); 5891da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 5901da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (el3_debug > 0) 591646cdb32831eebe8c2f742c293d0d266326854d9Alexander Beregalov pr_info("%s", version); 5921da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return 0; 5931da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 5941da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 5951da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 5961da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic void el3_common_remove (struct net_device *dev) 5971da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 5981da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds unregister_netdev (dev); 5991da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds release_region(dev->base_addr, EL3_IO_EXTENT); 6001da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds free_netdev (dev); 6011da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 6021da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 6031da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#ifdef CONFIG_MCA 604948252cb9e01d65a89ecadf67be5018351eee15eDavid S. Millerstatic int __init el3_mca_probe(struct device *device) 6051da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 6061da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* Based on Erik Nygren's (nygren@mit.edu) 3c529 patch, 6071da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * heavily modified by Chris Beauregard 6081da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * (cpbeaure@csclub.uwaterloo.ca) to support standard MCA 6091da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * probing. 6101da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * 6111da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * redone for multi-card detection by ZP Gu (zpg@castle.net) 6121da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * now works as a module */ 6131da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 6141da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds short i; 6151da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds int ioaddr, irq, if_port; 6164ec7ffa2df247054d422b48148ad82369a45e986Al Viro __be16 phys_addr[3]; 6171da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds struct net_device *dev = NULL; 6181da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds u_char pos4, pos5; 6191da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds struct mca_device *mdev = to_mca_device(device); 6201da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds int slot = mdev->slot; 6211da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds int err; 6221da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 6231da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds pos4 = mca_device_read_stored_pos(mdev, 4); 6241da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds pos5 = mca_device_read_stored_pos(mdev, 5); 6251da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 6261da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds ioaddr = ((short)((pos4&0xfc)|0x02)) << 8; 6271da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds irq = pos5 & 0x0f; 6281da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 6291da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 630646cdb32831eebe8c2f742c293d0d266326854d9Alexander Beregalov pr_info("3c529: found %s at slot %d\n", 631646cdb32831eebe8c2f742c293d0d266326854d9Alexander Beregalov el3_mca_adapter_names[mdev->index], slot + 1); 6321da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 6331da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* claim the slot */ 6341da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds strncpy(mdev->name, el3_mca_adapter_names[mdev->index], 6351da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds sizeof(mdev->name)); 6361da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds mca_device_set_claim(mdev, 1); 6371da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 6381da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if_port = pos4 & 0x03; 6391da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 6401da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds irq = mca_device_transform_irq(mdev, irq); 6416aa20a2235535605db6d6d2bd850298b2fe7f31eJeff Garzik ioaddr = mca_device_transform_ioport(mdev, ioaddr); 6421da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (el3_debug > 2) { 643646cdb32831eebe8c2f742c293d0d266326854d9Alexander Beregalov pr_debug("3c529: irq %d ioaddr 0x%x ifport %d\n", irq, ioaddr, if_port); 6441da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 6451da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds EL3WINDOW(0); 6464ec7ffa2df247054d422b48148ad82369a45e986Al Viro for (i = 0; i < 3; i++) 6474ec7ffa2df247054d422b48148ad82369a45e986Al Viro phys_addr[i] = htons(read_eeprom(ioaddr, i)); 6481da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 6491da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds dev = alloc_etherdev(sizeof (struct el3_private)); 6501da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (dev == NULL) { 6514ec7ffa2df247054d422b48148ad82369a45e986Al Viro release_region(ioaddr, EL3_IO_EXTENT); 6524ec7ffa2df247054d422b48148ad82369a45e986Al Viro return -ENOMEM; 6531da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 6541da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 6551da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds netdev_boot_setup_check(dev); 6561da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 657ac4bed1375c06af7c76b4615ae661791b62e93efOndrej Zary el3_dev_fill(dev, phys_addr, ioaddr, irq, if_port, EL3_MCA); 6581aec5bdfed91b50aedbcad43393bcb05033c7ef3Greg Kroah-Hartman dev_set_drvdata(device, dev); 6591da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds err = el3_common_init(dev); 6601da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 6611da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (err) { 6621aec5bdfed91b50aedbcad43393bcb05033c7ef3Greg Kroah-Hartman dev_set_drvdata(device, NULL); 6631da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds free_netdev(dev); 6641da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return -ENOMEM; 6651da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 6661da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 667ac4bed1375c06af7c76b4615ae661791b62e93efOndrej Zary el3_devs[el3_cards++] = dev; 6681da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return 0; 6691da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 6706aa20a2235535605db6d6d2bd850298b2fe7f31eJeff Garzik 6711da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#endif /* CONFIG_MCA */ 6721da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 6731da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#ifdef CONFIG_EISA 674948252cb9e01d65a89ecadf67be5018351eee15eDavid S. Millerstatic int __init el3_eisa_probe (struct device *device) 6751da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 6761da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds short i; 6771da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds int ioaddr, irq, if_port; 6784ec7ffa2df247054d422b48148ad82369a45e986Al Viro __be16 phys_addr[3]; 6791da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds struct net_device *dev = NULL; 6801da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds struct eisa_device *edev; 6811da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds int err; 6821da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 6831da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* Yeepee, The driver framework is calling us ! */ 6841da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds edev = to_eisa_device (device); 6851da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds ioaddr = edev->base_addr; 6866aa20a2235535605db6d6d2bd850298b2fe7f31eJeff Garzik 687ac4bed1375c06af7c76b4615ae661791b62e93efOndrej Zary if (!request_region(ioaddr, EL3_IO_EXTENT, "3c579-eisa")) 6881da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return -EBUSY; 6891da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 6901da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* Change the register set to the configuration window 0. */ 6911da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds outw(SelectWindow | 0, ioaddr + 0xC80 + EL3_CMD); 6921da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 6931da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds irq = inw(ioaddr + WN0_IRQ) >> 12; 6941da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if_port = inw(ioaddr + 6)>>14; 6951da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds for (i = 0; i < 3; i++) 6961da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds phys_addr[i] = htons(read_eeprom(ioaddr, i)); 6971da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 6981da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* Restore the "Product ID" to the EEPROM read register. */ 6991da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds read_eeprom(ioaddr, 3); 7001da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 7011da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds dev = alloc_etherdev(sizeof (struct el3_private)); 7021da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (dev == NULL) { 7031da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds release_region(ioaddr, EL3_IO_EXTENT); 7041da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return -ENOMEM; 7051da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 7061da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 7071da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds netdev_boot_setup_check(dev); 7081da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 709ac4bed1375c06af7c76b4615ae661791b62e93efOndrej Zary el3_dev_fill(dev, phys_addr, ioaddr, irq, if_port, EL3_EISA); 7101da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds eisa_set_drvdata (edev, dev); 7111da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds err = el3_common_init(dev); 7121da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 7131da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (err) { 7141da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds eisa_set_drvdata (edev, NULL); 7151da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds free_netdev(dev); 7161da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return err; 7171da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 7181da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 719ac4bed1375c06af7c76b4615ae661791b62e93efOndrej Zary el3_devs[el3_cards++] = dev; 7201da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return 0; 7211da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 7221da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#endif 7231da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 7241da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/* This remove works for all device types. 7251da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * 7261aec5bdfed91b50aedbcad43393bcb05033c7ef3Greg Kroah-Hartman * The net dev must be stored in the driver data field */ 7271da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic int __devexit el3_device_remove (struct device *device) 7281da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 7291da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds struct net_device *dev; 7301da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 7311aec5bdfed91b50aedbcad43393bcb05033c7ef3Greg Kroah-Hartman dev = dev_get_drvdata(device); 7321da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 7331da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds el3_common_remove (dev); 7341da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return 0; 7351da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 7361da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 7371da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/* Read a word from the EEPROM using the regular EEPROM access register. 7381da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds Assume that we are in register window zero. 7391da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 7401da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic ushort read_eeprom(int ioaddr, int index) 7411da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 7421da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds outw(EEPROM_READ + index, ioaddr + 10); 7436aa20a2235535605db6d6d2bd850298b2fe7f31eJeff Garzik /* Pause for at least 162 us. for the read to take place. 7441da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds Some chips seem to require much longer */ 7451da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds mdelay(2); 7461da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return inw(ioaddr + 12); 7471da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 7481da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 7491da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/* Read a word from the EEPROM when in the ISA ID probe state. */ 750ac4bed1375c06af7c76b4615ae661791b62e93efOndrej Zarystatic ushort id_read_eeprom(int index) 7511da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 7521da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds int bit, word = 0; 7531da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 7541da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* Issue read command, and pause for at least 162 us. for it to complete. 7551da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds Assume extra-fast 16Mhz bus. */ 7561da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds outb(EEPROM_READ + index, id_port); 7571da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 7581da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* Pause for at least 162 us. for the read to take place. */ 7591da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* Some chips seem to require much longer */ 7601da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds mdelay(4); 7616aa20a2235535605db6d6d2bd850298b2fe7f31eJeff Garzik 7621da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds for (bit = 15; bit >= 0; bit--) 7631da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds word = (word << 1) + (inb(id_port) & 0x01); 7641da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 7651da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (el3_debug > 3) 766646cdb32831eebe8c2f742c293d0d266326854d9Alexander Beregalov pr_debug(" 3c509 EEPROM word %d %#4.4x.\n", index, word); 7671da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 7681da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return word; 7691da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 7701da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 7711da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 7721da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic int 7731da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsel3_open(struct net_device *dev) 7741da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 7751da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds int ioaddr = dev->base_addr; 7761da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds int i; 7771da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 7781da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds outw(TxReset, ioaddr + EL3_CMD); 7791da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds outw(RxReset, ioaddr + EL3_CMD); 7801da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds outw(SetStatusEnb | 0x00, ioaddr + EL3_CMD); 7811da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 782a0607fd3a25ba1848a63a0d925e36d914735ab47Joe Perches i = request_irq(dev->irq, el3_interrupt, 0, dev->name, dev); 7831da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (i) 7841da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return i; 7851da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 7861da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds EL3WINDOW(0); 7871da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (el3_debug > 3) 788646cdb32831eebe8c2f742c293d0d266326854d9Alexander Beregalov pr_debug("%s: Opening, IRQ %d status@%x %4.4x.\n", dev->name, 7891da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds dev->irq, ioaddr + EL3_STATUS, inw(ioaddr + EL3_STATUS)); 7901da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 7911da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds el3_up(dev); 7921da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 7931da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (el3_debug > 3) 794646cdb32831eebe8c2f742c293d0d266326854d9Alexander Beregalov pr_debug("%s: Opened 3c509 IRQ %d status %4.4x.\n", 7951da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds dev->name, dev->irq, inw(ioaddr + EL3_STATUS)); 7961da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 7971da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return 0; 7981da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 7991da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 8001da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic void 8011da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsel3_tx_timeout (struct net_device *dev) 8021da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 8031da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds int ioaddr = dev->base_addr; 8041da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 8051da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* Transmitter timeout, serious problems. */ 806646cdb32831eebe8c2f742c293d0d266326854d9Alexander Beregalov pr_warning("%s: transmit timed out, Tx_status %2.2x status %4.4x Tx FIFO room %d.\n", 8071da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds dev->name, inb(ioaddr + TX_STATUS), inw(ioaddr + EL3_STATUS), 8081da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds inw(ioaddr + TX_FREE)); 809815f8802d201aba1ce343ba832daf639165f01a1Paulius Zaleckas dev->stats.tx_errors++; 8101ae5dc342ac78d7a42965fd1f323815f6f5ef2c1Eric Dumazet dev->trans_start = jiffies; /* prevent tx timeout */ 8111da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* Issue TX_RESET and TX_START commands. */ 8121da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds outw(TxReset, ioaddr + EL3_CMD); 8131da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds outw(TxEnable, ioaddr + EL3_CMD); 8141da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds netif_wake_queue(dev); 8151da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 8161da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 8171da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 81827a1de95a1461ec0589005c293d6ac23a46cb72dStephen Hemmingerstatic netdev_tx_t 8191da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsel3_start_xmit(struct sk_buff *skb, struct net_device *dev) 8201da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 8211da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds struct el3_private *lp = netdev_priv(dev); 8221da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds int ioaddr = dev->base_addr; 8231da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds unsigned long flags; 8241da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 8251da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds netif_stop_queue (dev); 8261da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 827815f8802d201aba1ce343ba832daf639165f01a1Paulius Zaleckas dev->stats.tx_bytes += skb->len; 8286aa20a2235535605db6d6d2bd850298b2fe7f31eJeff Garzik 8291da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (el3_debug > 4) { 830646cdb32831eebe8c2f742c293d0d266326854d9Alexander Beregalov pr_debug("%s: el3_start_xmit(length = %u) called, status %4.4x.\n", 8311da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds dev->name, skb->len, inw(ioaddr + EL3_STATUS)); 8321da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 8331da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#if 0 8341da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#ifndef final_version 8351da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds { /* Error-checking code, delete someday. */ 8361da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds ushort status = inw(ioaddr + EL3_STATUS); 8378e95a2026f3b43f7c3d676adaccd2de9532e8dccJoe Perches if (status & 0x0001 && /* IRQ line active, missed one. */ 8388e95a2026f3b43f7c3d676adaccd2de9532e8dccJoe Perches inw(ioaddr + EL3_STATUS) & 1) { /* Make sure. */ 839646cdb32831eebe8c2f742c293d0d266326854d9Alexander Beregalov pr_debug("%s: Missed interrupt, status then %04x now %04x" 8401da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds " Tx %2.2x Rx %4.4x.\n", dev->name, status, 8411da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds inw(ioaddr + EL3_STATUS), inb(ioaddr + TX_STATUS), 8421da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds inw(ioaddr + RX_STATUS)); 8431da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* Fake interrupt trigger by masking, acknowledge interrupts. */ 8441da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds outw(SetStatusEnb | 0x00, ioaddr + EL3_CMD); 8451da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds outw(AckIntr | IntLatch | TxAvailable | RxEarly | IntReq, 8461da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds ioaddr + EL3_CMD); 8471da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds outw(SetStatusEnb | 0xff, ioaddr + EL3_CMD); 8481da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 8491da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 8501da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#endif 8511da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#endif 8521da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* 8531da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * We lock the driver against other processors. Note 8541da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * we don't need to lock versus the IRQ as we suspended 8551da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * that. This means that we lose the ability to take 8561da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * an RX during a TX upload. That sucks a bit with SMP 8571da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * on an original 3c509 (2K buffer) 8581da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * 8591da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Using disable_irq stops us crapping on other 8601da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * time sensitive devices. 8611da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 8621da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 8631da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds spin_lock_irqsave(&lp->lock, flags); 8641da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 8651da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* Put out the doubleword header... */ 8661da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds outw(skb->len, ioaddr + TX_FIFO); 8671da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds outw(0x00, ioaddr + TX_FIFO); 8681da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* ... and the packet rounded to a doubleword. */ 8691da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds outsl(ioaddr + TX_FIFO, skb->data, (skb->len + 3) >> 2); 8701da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 8711da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (inw(ioaddr + TX_FREE) > 1536) 8721da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds netif_start_queue(dev); 8731da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds else 8741da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* Interrupt us when the FIFO has room for max-sized packet. */ 8751da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds outw(SetTxThreshold + 1536, ioaddr + EL3_CMD); 8761da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 8771da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds spin_unlock_irqrestore(&lp->lock, flags); 8781da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 8791da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds dev_kfree_skb (skb); 8801da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 8811da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* Clear the Tx status stack. */ 8821da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds { 8831da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds short tx_status; 8841da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds int i = 4; 8851da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 8861da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds while (--i > 0 && (tx_status = inb(ioaddr + TX_STATUS)) > 0) { 887815f8802d201aba1ce343ba832daf639165f01a1Paulius Zaleckas if (tx_status & 0x38) dev->stats.tx_aborted_errors++; 8881da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (tx_status & 0x30) outw(TxReset, ioaddr + EL3_CMD); 8891da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (tx_status & 0x3C) outw(TxEnable, ioaddr + EL3_CMD); 8901da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds outb(0x00, ioaddr + TX_STATUS); /* Pop the status stack. */ 8911da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 8921da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 8936ed106549d17474ca17a16057f4c0ed4eba5a7caPatrick McHardy return NETDEV_TX_OK; 8941da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 8951da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 8961da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/* The EL3 interrupt handler. */ 8971da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic irqreturn_t 8987d12e780e003f93433d49ce78cfedf4b4c52adc5David Howellsel3_interrupt(int irq, void *dev_id) 8991da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 900c31f28e778ab299a5035ea2bda64f245b8915d7cJeff Garzik struct net_device *dev = dev_id; 9011da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds struct el3_private *lp; 9021da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds int ioaddr, status; 9031da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds int i = max_interrupt_work; 9041da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 9051da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds lp = netdev_priv(dev); 9061da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds spin_lock(&lp->lock); 9071da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 9081da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds ioaddr = dev->base_addr; 9091da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 9101da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (el3_debug > 4) { 9111da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds status = inw(ioaddr + EL3_STATUS); 912646cdb32831eebe8c2f742c293d0d266326854d9Alexander Beregalov pr_debug("%s: interrupt, status %4.4x.\n", dev->name, status); 9131da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 9141da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 9151da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds while ((status = inw(ioaddr + EL3_STATUS)) & 9161da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds (IntLatch | RxComplete | StatsFull)) { 9171da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 9181da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (status & RxComplete) 9191da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds el3_rx(dev); 9201da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 9211da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (status & TxAvailable) { 9221da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (el3_debug > 5) 923646cdb32831eebe8c2f742c293d0d266326854d9Alexander Beregalov pr_debug(" TX room bit was handled.\n"); 9241da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* There's room in the FIFO for a full-sized packet. */ 9251da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds outw(AckIntr | TxAvailable, ioaddr + EL3_CMD); 9261da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds netif_wake_queue (dev); 9271da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 9281da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (status & (AdapterFailure | RxEarly | StatsFull | TxComplete)) { 9291da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* Handle all uncommon interrupts. */ 9301da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (status & StatsFull) /* Empty statistics. */ 9311da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds update_stats(dev); 9321da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (status & RxEarly) { /* Rx early is unused. */ 9331da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds el3_rx(dev); 9341da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds outw(AckIntr | RxEarly, ioaddr + EL3_CMD); 9351da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 9361da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (status & TxComplete) { /* Really Tx error. */ 9371da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds short tx_status; 9381da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds int i = 4; 9391da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 9401da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds while (--i>0 && (tx_status = inb(ioaddr + TX_STATUS)) > 0) { 941815f8802d201aba1ce343ba832daf639165f01a1Paulius Zaleckas if (tx_status & 0x38) dev->stats.tx_aborted_errors++; 9421da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (tx_status & 0x30) outw(TxReset, ioaddr + EL3_CMD); 9431da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (tx_status & 0x3C) outw(TxEnable, ioaddr + EL3_CMD); 9441da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds outb(0x00, ioaddr + TX_STATUS); /* Pop the status stack. */ 9451da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 9461da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 9471da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (status & AdapterFailure) { 9481da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* Adapter failure requires Rx reset and reinit. */ 9491da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds outw(RxReset, ioaddr + EL3_CMD); 9501da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* Set the Rx filter to the current state. */ 9511da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds outw(SetRxFilter | RxStation | RxBroadcast 9521da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds | (dev->flags & IFF_ALLMULTI ? RxMulticast : 0) 9531da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds | (dev->flags & IFF_PROMISC ? RxProm : 0), 9541da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds ioaddr + EL3_CMD); 9551da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds outw(RxEnable, ioaddr + EL3_CMD); /* Re-enable the receiver. */ 9561da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds outw(AckIntr | AdapterFailure, ioaddr + EL3_CMD); 9571da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 9581da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 9591da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 9601da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (--i < 0) { 961646cdb32831eebe8c2f742c293d0d266326854d9Alexander Beregalov pr_err("%s: Infinite loop in interrupt, status %4.4x.\n", 9621da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds dev->name, status); 9631da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* Clear all interrupts. */ 9641da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds outw(AckIntr | 0xFF, ioaddr + EL3_CMD); 9651da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds break; 9661da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 9671da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* Acknowledge the IRQ. */ 9681da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds outw(AckIntr | IntReq | IntLatch, ioaddr + EL3_CMD); /* Ack IRQ */ 9691da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 9701da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 9711da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (el3_debug > 4) { 972646cdb32831eebe8c2f742c293d0d266326854d9Alexander Beregalov pr_debug("%s: exiting interrupt, status %4.4x.\n", dev->name, 9731da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds inw(ioaddr + EL3_STATUS)); 9741da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 9751da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds spin_unlock(&lp->lock); 9761da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return IRQ_HANDLED; 9771da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 9781da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 9791da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 9801da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#ifdef CONFIG_NET_POLL_CONTROLLER 9811da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/* 9821da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Polling receive - used by netconsole and other diagnostic tools 9831da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * to allow network i/o with interrupts disabled. 9841da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 9851da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic void el3_poll_controller(struct net_device *dev) 9861da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 9871da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds disable_irq(dev->irq); 9887d12e780e003f93433d49ce78cfedf4b4c52adc5David Howells el3_interrupt(dev->irq, dev); 9891da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds enable_irq(dev->irq); 9901da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 9911da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#endif 9921da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 9931da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic struct net_device_stats * 9941da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsel3_get_stats(struct net_device *dev) 9951da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 9961da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds struct el3_private *lp = netdev_priv(dev); 9971da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds unsigned long flags; 9981da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 9991da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* 10001da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * This is fast enough not to bother with disable IRQ 10011da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * stuff. 10021da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 10036aa20a2235535605db6d6d2bd850298b2fe7f31eJeff Garzik 10041da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds spin_lock_irqsave(&lp->lock, flags); 10051da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds update_stats(dev); 10061da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds spin_unlock_irqrestore(&lp->lock, flags); 1007815f8802d201aba1ce343ba832daf639165f01a1Paulius Zaleckas return &dev->stats; 10081da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 10091da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 10101da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/* Update statistics. We change to register window 6, so this should be run 10111da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds single-threaded if the device is active. This is expected to be a rare 10121da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds operation, and it's simpler for the rest of the driver to assume that 10131da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds window 1 is always valid rather than use a special window-state variable. 10141da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 10151da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic void update_stats(struct net_device *dev) 10161da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 10171da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds int ioaddr = dev->base_addr; 10181da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 10191da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (el3_debug > 5) 1020646cdb32831eebe8c2f742c293d0d266326854d9Alexander Beregalov pr_debug(" Updating the statistics.\n"); 10211da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* Turn off statistics updates while reading. */ 10221da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds outw(StatsDisable, ioaddr + EL3_CMD); 10231da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* Switch to the stats window, and read everything. */ 10241da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds EL3WINDOW(6); 1025815f8802d201aba1ce343ba832daf639165f01a1Paulius Zaleckas dev->stats.tx_carrier_errors += inb(ioaddr + 0); 1026815f8802d201aba1ce343ba832daf639165f01a1Paulius Zaleckas dev->stats.tx_heartbeat_errors += inb(ioaddr + 1); 10271da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* Multiple collisions. */ inb(ioaddr + 2); 1028815f8802d201aba1ce343ba832daf639165f01a1Paulius Zaleckas dev->stats.collisions += inb(ioaddr + 3); 1029815f8802d201aba1ce343ba832daf639165f01a1Paulius Zaleckas dev->stats.tx_window_errors += inb(ioaddr + 4); 1030815f8802d201aba1ce343ba832daf639165f01a1Paulius Zaleckas dev->stats.rx_fifo_errors += inb(ioaddr + 5); 1031815f8802d201aba1ce343ba832daf639165f01a1Paulius Zaleckas dev->stats.tx_packets += inb(ioaddr + 6); 10321da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* Rx packets */ inb(ioaddr + 7); 10331da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* Tx deferrals */ inb(ioaddr + 8); 10341da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds inw(ioaddr + 10); /* Total Rx and Tx octets. */ 10351da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds inw(ioaddr + 12); 10361da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 10371da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* Back to window 1, and turn statistics back on. */ 10381da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds EL3WINDOW(1); 10391da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds outw(StatsEnable, ioaddr + EL3_CMD); 10401da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 10411da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 10421da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic int 10431da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsel3_rx(struct net_device *dev) 10441da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 10451da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds int ioaddr = dev->base_addr; 10461da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds short rx_status; 10471da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 10481da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (el3_debug > 5) 1049646cdb32831eebe8c2f742c293d0d266326854d9Alexander Beregalov pr_debug(" In rx_packet(), status %4.4x, rx_status %4.4x.\n", 10501da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds inw(ioaddr+EL3_STATUS), inw(ioaddr+RX_STATUS)); 10511da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds while ((rx_status = inw(ioaddr + RX_STATUS)) > 0) { 10521da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (rx_status & 0x4000) { /* Error, update stats. */ 10531da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds short error = rx_status & 0x3800; 10541da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 10551da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds outw(RxDiscard, ioaddr + EL3_CMD); 1056815f8802d201aba1ce343ba832daf639165f01a1Paulius Zaleckas dev->stats.rx_errors++; 10571da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds switch (error) { 1058815f8802d201aba1ce343ba832daf639165f01a1Paulius Zaleckas case 0x0000: dev->stats.rx_over_errors++; break; 1059815f8802d201aba1ce343ba832daf639165f01a1Paulius Zaleckas case 0x0800: dev->stats.rx_length_errors++; break; 1060815f8802d201aba1ce343ba832daf639165f01a1Paulius Zaleckas case 0x1000: dev->stats.rx_frame_errors++; break; 1061815f8802d201aba1ce343ba832daf639165f01a1Paulius Zaleckas case 0x1800: dev->stats.rx_length_errors++; break; 1062815f8802d201aba1ce343ba832daf639165f01a1Paulius Zaleckas case 0x2000: dev->stats.rx_frame_errors++; break; 1063815f8802d201aba1ce343ba832daf639165f01a1Paulius Zaleckas case 0x2800: dev->stats.rx_crc_errors++; break; 10641da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 10651da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } else { 10661da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds short pkt_len = rx_status & 0x7ff; 10671da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds struct sk_buff *skb; 10681da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 10691d266430546acf01438ae42d0a7370db4817e2adPradeep A Dalvi skb = netdev_alloc_skb(dev, pkt_len + 5); 10701da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (el3_debug > 4) 1071646cdb32831eebe8c2f742c293d0d266326854d9Alexander Beregalov pr_debug("Receiving packet size %d status %4.4x.\n", 10721da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds pkt_len, rx_status); 10731da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (skb != NULL) { 10741da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds skb_reserve(skb, 2); /* Align IP on 16 byte */ 10751da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 10761da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* 'skb->data' points to the start of sk_buff data area. */ 10771da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds insl(ioaddr + RX_FIFO, skb_put(skb,pkt_len), 10781da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds (pkt_len + 3) >> 2); 10791da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 10801da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds outw(RxDiscard, ioaddr + EL3_CMD); /* Pop top Rx packet. */ 10811da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds skb->protocol = eth_type_trans(skb,dev); 10821da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds netif_rx(skb); 1083f7f312a0c7e7a1947cf193e0e94a257ad7742cb2Wang Chen dev->stats.rx_bytes += pkt_len; 1084815f8802d201aba1ce343ba832daf639165f01a1Paulius Zaleckas dev->stats.rx_packets++; 10851da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds continue; 10861da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 10871da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds outw(RxDiscard, ioaddr + EL3_CMD); 1088815f8802d201aba1ce343ba832daf639165f01a1Paulius Zaleckas dev->stats.rx_dropped++; 10891da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (el3_debug) 1090646cdb32831eebe8c2f742c293d0d266326854d9Alexander Beregalov pr_debug("%s: Couldn't allocate a sk_buff of size %d.\n", 10911da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds dev->name, pkt_len); 10921da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 10931da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds inw(ioaddr + EL3_STATUS); /* Delay. */ 10941da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds while (inw(ioaddr + EL3_STATUS) & 0x1000) 1095646cdb32831eebe8c2f742c293d0d266326854d9Alexander Beregalov pr_debug(" Waiting for 3c509 to discard packet, status %x.\n", 10961da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds inw(ioaddr + EL3_STATUS) ); 10971da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 10981da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 10991da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return 0; 11001da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 11011da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 11021da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/* 11031da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Set or clear the multicast filter for this adaptor. 11041da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 11051da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic void 11061da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsset_multicast_list(struct net_device *dev) 11071da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 11081da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds unsigned long flags; 11091da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds struct el3_private *lp = netdev_priv(dev); 11101da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds int ioaddr = dev->base_addr; 11114cd24eaf0c6ee7f0242e34ee77ec899f255e66b5Jiri Pirko int mc_count = netdev_mc_count(dev); 11121da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 11131da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (el3_debug > 1) { 11141da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds static int old; 11154cd24eaf0c6ee7f0242e34ee77ec899f255e66b5Jiri Pirko if (old != mc_count) { 11164cd24eaf0c6ee7f0242e34ee77ec899f255e66b5Jiri Pirko old = mc_count; 11174cd24eaf0c6ee7f0242e34ee77ec899f255e66b5Jiri Pirko pr_debug("%s: Setting Rx mode to %d addresses.\n", 11184cd24eaf0c6ee7f0242e34ee77ec899f255e66b5Jiri Pirko dev->name, mc_count); 11191da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 11201da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 11211da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds spin_lock_irqsave(&lp->lock, flags); 11221da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (dev->flags&IFF_PROMISC) { 11231da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds outw(SetRxFilter | RxStation | RxMulticast | RxBroadcast | RxProm, 11241da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds ioaddr + EL3_CMD); 11251da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 11264cd24eaf0c6ee7f0242e34ee77ec899f255e66b5Jiri Pirko else if (mc_count || (dev->flags&IFF_ALLMULTI)) { 11271da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds outw(SetRxFilter | RxStation | RxMulticast | RxBroadcast, ioaddr + EL3_CMD); 11281da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 11291da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds else 11301da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds outw(SetRxFilter | RxStation | RxBroadcast, ioaddr + EL3_CMD); 11311da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds spin_unlock_irqrestore(&lp->lock, flags); 11321da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 11331da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 11341da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic int 11351da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsel3_close(struct net_device *dev) 11361da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 11371da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds int ioaddr = dev->base_addr; 11381da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds struct el3_private *lp = netdev_priv(dev); 11396aa20a2235535605db6d6d2bd850298b2fe7f31eJeff Garzik 11401da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (el3_debug > 2) 1141646cdb32831eebe8c2f742c293d0d266326854d9Alexander Beregalov pr_debug("%s: Shutting down ethercard.\n", dev->name); 11421da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 11431da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds el3_down(dev); 11441da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 11451da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds free_irq(dev->irq, dev); 11461da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* Switching back to window 0 disables the IRQ. */ 11471da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds EL3WINDOW(0); 11481da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (lp->type != EL3_EISA) { 11491da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* But we explicitly zero the IRQ line select anyway. Don't do 11501da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * it on EISA cards, it prevents the module from getting an 11511da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * IRQ after unload+reload... */ 11521da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds outw(0x0f00, ioaddr + WN0_IRQ); 11531da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 11541da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 11551da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return 0; 11561da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 11571da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 11586aa20a2235535605db6d6d2bd850298b2fe7f31eJeff Garzikstatic int 11591da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsel3_link_ok(struct net_device *dev) 11601da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 11611da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds int ioaddr = dev->base_addr; 11621da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds u16 tmp; 11631da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 11641da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds EL3WINDOW(4); 11651da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds tmp = inw(ioaddr + WN4_MEDIA); 11661da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds EL3WINDOW(1); 11671da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return tmp & (1<<11); 11681da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 11691da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 11701da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic int 11711da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsel3_netdev_get_ecmd(struct net_device *dev, struct ethtool_cmd *ecmd) 11721da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 11731da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds u16 tmp; 11741da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds int ioaddr = dev->base_addr; 11756aa20a2235535605db6d6d2bd850298b2fe7f31eJeff Garzik 11761da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds EL3WINDOW(0); 11776aa20a2235535605db6d6d2bd850298b2fe7f31eJeff Garzik /* obtain current transceiver via WN4_MEDIA? */ 11781da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds tmp = inw(ioaddr + WN0_ADDR_CONF); 11791da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds ecmd->transceiver = XCVR_INTERNAL; 11801da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds switch (tmp >> 14) { 11811da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds case 0: 11821da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds ecmd->port = PORT_TP; 11831da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds break; 11841da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds case 1: 11851da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds ecmd->port = PORT_AUI; 11861da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds ecmd->transceiver = XCVR_EXTERNAL; 11871da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds break; 11881da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds case 3: 11891da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds ecmd->port = PORT_BNC; 11901da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds default: 11911da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds break; 11921da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 11931da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 11941da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds ecmd->duplex = DUPLEX_HALF; 11951da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds ecmd->supported = 0; 11961da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds tmp = inw(ioaddr + WN0_CONF_CTRL); 11971da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (tmp & (1<<13)) 11981da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds ecmd->supported |= SUPPORTED_AUI; 11991da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (tmp & (1<<12)) 12001da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds ecmd->supported |= SUPPORTED_BNC; 12011da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (tmp & (1<<9)) { 12021da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds ecmd->supported |= SUPPORTED_TP | SUPPORTED_10baseT_Half | 12031da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds SUPPORTED_10baseT_Full; /* hmm... */ 12041da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds EL3WINDOW(4); 12051da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds tmp = inw(ioaddr + WN4_NETDIAG); 12061da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (tmp & FD_ENABLE) 12071da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds ecmd->duplex = DUPLEX_FULL; 12081da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 12091da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 1210707394972093e2056e1e8cc39be19cf9bcb3e7b3David Decotigny ethtool_cmd_speed_set(ecmd, SPEED_10); 12111da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds EL3WINDOW(1); 12121da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return 0; 12131da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 12141da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 12151da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic int 12161da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsel3_netdev_set_ecmd(struct net_device *dev, struct ethtool_cmd *ecmd) 12171da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 12181da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds u16 tmp; 12191da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds int ioaddr = dev->base_addr; 12201da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 12211da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (ecmd->speed != SPEED_10) 12221da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return -EINVAL; 12231da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if ((ecmd->duplex != DUPLEX_HALF) && (ecmd->duplex != DUPLEX_FULL)) 12241da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return -EINVAL; 12251da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if ((ecmd->transceiver != XCVR_INTERNAL) && (ecmd->transceiver != XCVR_EXTERNAL)) 12261da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return -EINVAL; 12271da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 12281da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* change XCVR type */ 12291da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds EL3WINDOW(0); 12301da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds tmp = inw(ioaddr + WN0_ADDR_CONF); 12311da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds switch (ecmd->port) { 12321da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds case PORT_TP: 12331da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds tmp &= ~(3<<14); 12341da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds dev->if_port = 0; 12351da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds break; 12361da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds case PORT_AUI: 12371da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds tmp |= (1<<14); 12381da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds dev->if_port = 1; 12391da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds break; 12401da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds case PORT_BNC: 12411da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds tmp |= (3<<14); 12421da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds dev->if_port = 3; 12431da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds break; 12441da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds default: 12451da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return -EINVAL; 12461da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 12471da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 12481da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds outw(tmp, ioaddr + WN0_ADDR_CONF); 12491da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (dev->if_port == 3) { 12501da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* fire up the DC-DC convertor if BNC gets enabled */ 12511da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds tmp = inw(ioaddr + WN0_ADDR_CONF); 12521da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (tmp & (3 << 14)) { 12531da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds outw(StartCoax, ioaddr + EL3_CMD); 12541da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds udelay(800); 12551da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } else 12561da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return -EIO; 12571da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 12581da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 12591da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds EL3WINDOW(4); 12601da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds tmp = inw(ioaddr + WN4_NETDIAG); 12611da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (ecmd->duplex == DUPLEX_FULL) 12621da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds tmp |= FD_ENABLE; 12631da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds else 12641da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds tmp &= ~FD_ENABLE; 12651da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds outw(tmp, ioaddr + WN4_NETDIAG); 12661da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds EL3WINDOW(1); 12671da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 12681da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return 0; 12691da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 12701da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 12711da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic void el3_get_drvinfo(struct net_device *dev, struct ethtool_drvinfo *info) 12721da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 12731da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds strcpy(info->driver, DRV_NAME); 12741da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds strcpy(info->version, DRV_VERSION); 12751da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 12761da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 12771da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic int el3_get_settings(struct net_device *dev, struct ethtool_cmd *ecmd) 12781da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 12791da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds struct el3_private *lp = netdev_priv(dev); 12801da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds int ret; 12811da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 12821da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds spin_lock_irq(&lp->lock); 12831da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds ret = el3_netdev_get_ecmd(dev, ecmd); 12841da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds spin_unlock_irq(&lp->lock); 12851da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return ret; 12861da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 12871da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 12881da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic int el3_set_settings(struct net_device *dev, struct ethtool_cmd *ecmd) 12891da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 12901da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds struct el3_private *lp = netdev_priv(dev); 12911da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds int ret; 12921da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 12931da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds spin_lock_irq(&lp->lock); 12941da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds ret = el3_netdev_set_ecmd(dev, ecmd); 12951da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds spin_unlock_irq(&lp->lock); 12961da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return ret; 12971da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 12981da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 12991da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic u32 el3_get_link(struct net_device *dev) 13001da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 13011da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds struct el3_private *lp = netdev_priv(dev); 13021da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds u32 ret; 13031da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 13041da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds spin_lock_irq(&lp->lock); 13051da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds ret = el3_link_ok(dev); 13061da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds spin_unlock_irq(&lp->lock); 13071da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return ret; 13081da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 13091da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 13101da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic u32 el3_get_msglevel(struct net_device *dev) 13111da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 13121da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return el3_debug; 13131da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 13141da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 13151da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic void el3_set_msglevel(struct net_device *dev, u32 v) 13161da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 13171da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds el3_debug = v; 13181da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 13191da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 13207282d491ecaee9883233a0e27283c4c79486279aJeff Garzikstatic const struct ethtool_ops ethtool_ops = { 13211da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds .get_drvinfo = el3_get_drvinfo, 13221da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds .get_settings = el3_get_settings, 13231da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds .set_settings = el3_set_settings, 13241da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds .get_link = el3_get_link, 13251da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds .get_msglevel = el3_get_msglevel, 13261da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds .set_msglevel = el3_set_msglevel, 13271da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}; 13281da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 13291da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic void 13301da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsel3_down(struct net_device *dev) 13311da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 13321da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds int ioaddr = dev->base_addr; 13331da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 13341da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds netif_stop_queue(dev); 13351da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 13361da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* Turn off statistics ASAP. We update lp->stats below. */ 13371da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds outw(StatsDisable, ioaddr + EL3_CMD); 13381da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 13391da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* Disable the receiver and transmitter. */ 13401da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds outw(RxDisable, ioaddr + EL3_CMD); 13411da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds outw(TxDisable, ioaddr + EL3_CMD); 13421da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 13431da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (dev->if_port == 3) 13441da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* Turn off thinnet power. Green! */ 13451da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds outw(StopCoax, ioaddr + EL3_CMD); 13461da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds else if (dev->if_port == 0) { 13471da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* Disable link beat and jabber, if_port may change here next open(). */ 13481da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds EL3WINDOW(4); 13491da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds outw(inw(ioaddr + WN4_MEDIA) & ~MEDIA_TP, ioaddr + WN4_MEDIA); 13501da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 13511da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 13521da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds outw(SetIntrEnb | 0x0000, ioaddr + EL3_CMD); 13531da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 13541da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds update_stats(dev); 13551da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 13561da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 13571da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic void 13581da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsel3_up(struct net_device *dev) 13591da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 13601da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds int i, sw_info, net_diag; 13611da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds int ioaddr = dev->base_addr; 13626aa20a2235535605db6d6d2bd850298b2fe7f31eJeff Garzik 13631da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* Activating the board required and does no harm otherwise */ 13641da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds outw(0x0001, ioaddr + 4); 13651da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 13661da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* Set the IRQ line. */ 13671da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds outw((dev->irq << 12) | 0x0f00, ioaddr + WN0_IRQ); 13681da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 13691da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* Set the station address in window 2 each time opened. */ 13701da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds EL3WINDOW(2); 13711da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 13721da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds for (i = 0; i < 6; i++) 13731da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds outb(dev->dev_addr[i], ioaddr + i); 13741da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 13751da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if ((dev->if_port & 0x03) == 3) /* BNC interface */ 13761da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* Start the thinnet transceiver. We should really wait 50ms...*/ 13771da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds outw(StartCoax, ioaddr + EL3_CMD); 13781da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds else if ((dev->if_port & 0x03) == 0) { /* 10baseT interface */ 13791da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* Combine secondary sw_info word (the adapter level) and primary 13801da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds sw_info word (duplex setting plus other useless bits) */ 13811da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds EL3WINDOW(0); 13826aa20a2235535605db6d6d2bd850298b2fe7f31eJeff Garzik sw_info = (read_eeprom(ioaddr, 0x14) & 0x400f) | 13831da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds (read_eeprom(ioaddr, 0x0d) & 0xBff0); 13841da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 13851da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds EL3WINDOW(4); 13861da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds net_diag = inw(ioaddr + WN4_NETDIAG); 13871da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds net_diag = (net_diag | FD_ENABLE); /* temporarily assume full-duplex will be set */ 1388646cdb32831eebe8c2f742c293d0d266326854d9Alexander Beregalov pr_info("%s: ", dev->name); 13891da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds switch (dev->if_port & 0x0c) { 13901da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds case 12: 13911da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* force full-duplex mode if 3c5x9b */ 13921da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (sw_info & 0x000f) { 1393646cdb32831eebe8c2f742c293d0d266326854d9Alexander Beregalov pr_cont("Forcing 3c5x9b full-duplex mode"); 13941da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds break; 13951da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 13961da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds case 8: 13971da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* set full-duplex mode based on eeprom config setting */ 13981da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if ((sw_info & 0x000f) && (sw_info & 0x8000)) { 1399646cdb32831eebe8c2f742c293d0d266326854d9Alexander Beregalov pr_cont("Setting 3c5x9b full-duplex mode (from EEPROM configuration bit)"); 14001da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds break; 14011da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 14021da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds default: 14031da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* xcvr=(0 || 4) OR user has an old 3c5x9 non "B" model */ 1404646cdb32831eebe8c2f742c293d0d266326854d9Alexander Beregalov pr_cont("Setting 3c5x9/3c5x9B half-duplex mode"); 14051da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds net_diag = (net_diag & ~FD_ENABLE); /* disable full duplex */ 14061da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 14071da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 14081da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds outw(net_diag, ioaddr + WN4_NETDIAG); 1409646cdb32831eebe8c2f742c293d0d266326854d9Alexander Beregalov pr_cont(" if_port: %d, sw_info: %4.4x\n", dev->if_port, sw_info); 14101da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (el3_debug > 3) 1411646cdb32831eebe8c2f742c293d0d266326854d9Alexander Beregalov pr_debug("%s: 3c5x9 net diag word is now: %4.4x.\n", dev->name, net_diag); 14121da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* Enable link beat and jabber check. */ 14131da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds outw(inw(ioaddr + WN4_MEDIA) | MEDIA_TP, ioaddr + WN4_MEDIA); 14141da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 14151da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 14161da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* Switch to the stats window, and clear all stats by reading. */ 14171da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds outw(StatsDisable, ioaddr + EL3_CMD); 14181da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds EL3WINDOW(6); 14191da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds for (i = 0; i < 9; i++) 14201da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds inb(ioaddr + i); 14211da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds inw(ioaddr + 10); 14221da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds inw(ioaddr + 12); 14231da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 14241da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* Switch to register set 1 for normal use. */ 14251da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds EL3WINDOW(1); 14261da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 14271da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* Accept b-case and phys addr only. */ 14281da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds outw(SetRxFilter | RxStation | RxBroadcast, ioaddr + EL3_CMD); 14291da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds outw(StatsEnable, ioaddr + EL3_CMD); /* Turn on statistics. */ 14301da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 14311da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds outw(RxEnable, ioaddr + EL3_CMD); /* Enable the receiver. */ 14321da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds outw(TxEnable, ioaddr + EL3_CMD); /* Enable transmitter. */ 14331da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* Allow status bits to be seen. */ 14341da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds outw(SetStatusEnb | 0xff, ioaddr + EL3_CMD); 14351da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* Ack all pending events, and set active indicator mask. */ 14361da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds outw(AckIntr | IntLatch | TxAvailable | RxEarly | IntReq, 14371da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds ioaddr + EL3_CMD); 14381da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds outw(SetIntrEnb | IntLatch|TxAvailable|TxComplete|RxComplete|StatsFull, 14391da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds ioaddr + EL3_CMD); 14401da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 14411da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds netif_start_queue(dev); 14421da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 14431da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 14441da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/* Power Management support functions */ 1445ac4bed1375c06af7c76b4615ae661791b62e93efOndrej Zary#ifdef CONFIG_PM 14461da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 14471da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic int 144860a89ff6d2681029b3d46b5d23dccf2903a254b4Pekka Enbergel3_suspend(struct device *pdev, pm_message_t state) 14491da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 14501da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds unsigned long flags; 14511da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds struct net_device *dev; 14521da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds struct el3_private *lp; 14531da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds int ioaddr; 14546aa20a2235535605db6d6d2bd850298b2fe7f31eJeff Garzik 14551aec5bdfed91b50aedbcad43393bcb05033c7ef3Greg Kroah-Hartman dev = dev_get_drvdata(pdev); 14561da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds lp = netdev_priv(dev); 14571da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds ioaddr = dev->base_addr; 14581da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 14591da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds spin_lock_irqsave(&lp->lock, flags); 14601da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 14611da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (netif_running(dev)) 14621da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds netif_device_detach(dev); 14631da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 14641da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds el3_down(dev); 14651da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds outw(PowerDown, ioaddr + EL3_CMD); 14661da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 14671da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds spin_unlock_irqrestore(&lp->lock, flags); 14681da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return 0; 14691da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 14701da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 14711da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic int 147260a89ff6d2681029b3d46b5d23dccf2903a254b4Pekka Enbergel3_resume(struct device *pdev) 14731da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 14741da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds unsigned long flags; 14751da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds struct net_device *dev; 14761da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds struct el3_private *lp; 14771da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds int ioaddr; 14786aa20a2235535605db6d6d2bd850298b2fe7f31eJeff Garzik 14791aec5bdfed91b50aedbcad43393bcb05033c7ef3Greg Kroah-Hartman dev = dev_get_drvdata(pdev); 14801da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds lp = netdev_priv(dev); 14811da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds ioaddr = dev->base_addr; 14821da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 14831da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds spin_lock_irqsave(&lp->lock, flags); 14841da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 14851da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds outw(PowerUp, ioaddr + EL3_CMD); 1486152abd139cca049c9b559a7cca762fa7fd9fd264Ondrej Zary EL3WINDOW(0); 14871da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds el3_up(dev); 14881da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 14891da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (netif_running(dev)) 14901da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds netif_device_attach(dev); 14916aa20a2235535605db6d6d2bd850298b2fe7f31eJeff Garzik 14921da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds spin_unlock_irqrestore(&lp->lock, flags); 14931da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return 0; 14941da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 14951da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 1496ac4bed1375c06af7c76b4615ae661791b62e93efOndrej Zary#endif /* CONFIG_PM */ 14971da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 14981da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsmodule_param(debug,int, 0); 14991da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsmodule_param_array(irq, int, NULL, 0); 15001da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsmodule_param(max_interrupt_work, int, 0); 15011da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus TorvaldsMODULE_PARM_DESC(debug, "debug level (0-6)"); 15021da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus TorvaldsMODULE_PARM_DESC(irq, "IRQ number(s) (assigned)"); 15031da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus TorvaldsMODULE_PARM_DESC(max_interrupt_work, "maximum events handled per interrupt"); 1504ac4bed1375c06af7c76b4615ae661791b62e93efOndrej Zary#ifdef CONFIG_PNP 15051da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsmodule_param(nopnp, int, 0); 15061da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus TorvaldsMODULE_PARM_DESC(nopnp, "disable ISA PnP support (0-1)"); 1507ac4bed1375c06af7c76b4615ae661791b62e93efOndrej Zary#endif /* CONFIG_PNP */ 1508ac4bed1375c06af7c76b4615ae661791b62e93efOndrej ZaryMODULE_DESCRIPTION("3Com Etherlink III (3c509, 3c509B, 3c529, 3c579) ethernet driver"); 15091da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus TorvaldsMODULE_LICENSE("GPL"); 15101da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 15111da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic int __init el3_init_module(void) 15121da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 15130992a5d029181421877a716eaf99145828ff7eaeAndrew Morton int ret = 0; 15141da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 15151da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (debug >= 0) 15161da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds el3_debug = debug; 15171da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 1518ac4bed1375c06af7c76b4615ae661791b62e93efOndrej Zary#ifdef CONFIG_PNP 1519ac4bed1375c06af7c76b4615ae661791b62e93efOndrej Zary if (!nopnp) { 1520ac4bed1375c06af7c76b4615ae661791b62e93efOndrej Zary ret = pnp_register_driver(&el3_pnp_driver); 1521ac4bed1375c06af7c76b4615ae661791b62e93efOndrej Zary if (!ret) 1522ac4bed1375c06af7c76b4615ae661791b62e93efOndrej Zary pnp_registered = 1; 1523ac4bed1375c06af7c76b4615ae661791b62e93efOndrej Zary } 1524ac4bed1375c06af7c76b4615ae661791b62e93efOndrej Zary#endif 1525ac4bed1375c06af7c76b4615ae661791b62e93efOndrej Zary /* Select an open I/O location at 0x1*0 to do ISA contention select. */ 1526ac4bed1375c06af7c76b4615ae661791b62e93efOndrej Zary /* Start with 0x110 to avoid some sound cards.*/ 1527ac4bed1375c06af7c76b4615ae661791b62e93efOndrej Zary for (id_port = 0x110 ; id_port < 0x200; id_port += 0x10) { 1528ac4bed1375c06af7c76b4615ae661791b62e93efOndrej Zary if (!request_region(id_port, 1, "3c509-control")) 1529ac4bed1375c06af7c76b4615ae661791b62e93efOndrej Zary continue; 1530ac4bed1375c06af7c76b4615ae661791b62e93efOndrej Zary outb(0x00, id_port); 1531ac4bed1375c06af7c76b4615ae661791b62e93efOndrej Zary outb(0xff, id_port); 1532ac4bed1375c06af7c76b4615ae661791b62e93efOndrej Zary if (inb(id_port) & 0x01) 1533ac4bed1375c06af7c76b4615ae661791b62e93efOndrej Zary break; 1534ac4bed1375c06af7c76b4615ae661791b62e93efOndrej Zary else 1535ac4bed1375c06af7c76b4615ae661791b62e93efOndrej Zary release_region(id_port, 1); 1536ac4bed1375c06af7c76b4615ae661791b62e93efOndrej Zary } 1537ac4bed1375c06af7c76b4615ae661791b62e93efOndrej Zary if (id_port >= 0x200) { 1538ac4bed1375c06af7c76b4615ae661791b62e93efOndrej Zary id_port = 0; 1539646cdb32831eebe8c2f742c293d0d266326854d9Alexander Beregalov pr_err("No I/O port available for 3c509 activation.\n"); 1540ac4bed1375c06af7c76b4615ae661791b62e93efOndrej Zary } else { 1541ac4bed1375c06af7c76b4615ae661791b62e93efOndrej Zary ret = isa_register_driver(&el3_isa_driver, EL3_MAX_CARDS); 1542ac4bed1375c06af7c76b4615ae661791b62e93efOndrej Zary if (!ret) 1543ac4bed1375c06af7c76b4615ae661791b62e93efOndrej Zary isa_registered = 1; 15441da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 15451da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#ifdef CONFIG_EISA 15460992a5d029181421877a716eaf99145828ff7eaeAndrew Morton ret = eisa_driver_register(&el3_eisa_driver); 1547ac4bed1375c06af7c76b4615ae661791b62e93efOndrej Zary if (!ret) 1548ac4bed1375c06af7c76b4615ae661791b62e93efOndrej Zary eisa_registered = 1; 15491da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#endif 15501da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#ifdef CONFIG_MCA 1551ac4bed1375c06af7c76b4615ae661791b62e93efOndrej Zary ret = mca_register_driver(&el3_mca_driver); 1552ac4bed1375c06af7c76b4615ae661791b62e93efOndrej Zary if (!ret) 1553ac4bed1375c06af7c76b4615ae661791b62e93efOndrej Zary mca_registered = 1; 1554ac4bed1375c06af7c76b4615ae661791b62e93efOndrej Zary#endif 1555ac4bed1375c06af7c76b4615ae661791b62e93efOndrej Zary 1556ac4bed1375c06af7c76b4615ae661791b62e93efOndrej Zary#ifdef CONFIG_PNP 1557ac4bed1375c06af7c76b4615ae661791b62e93efOndrej Zary if (pnp_registered) 1558ac4bed1375c06af7c76b4615ae661791b62e93efOndrej Zary ret = 0; 1559ac4bed1375c06af7c76b4615ae661791b62e93efOndrej Zary#endif 1560ac4bed1375c06af7c76b4615ae661791b62e93efOndrej Zary if (isa_registered) 1561ac4bed1375c06af7c76b4615ae661791b62e93efOndrej Zary ret = 0; 1562ac4bed1375c06af7c76b4615ae661791b62e93efOndrej Zary#ifdef CONFIG_EISA 1563ac4bed1375c06af7c76b4615ae661791b62e93efOndrej Zary if (eisa_registered) 1564ac4bed1375c06af7c76b4615ae661791b62e93efOndrej Zary ret = 0; 1565ac4bed1375c06af7c76b4615ae661791b62e93efOndrej Zary#endif 1566ac4bed1375c06af7c76b4615ae661791b62e93efOndrej Zary#ifdef CONFIG_MCA 1567ac4bed1375c06af7c76b4615ae661791b62e93efOndrej Zary if (mca_registered) 1568ac4bed1375c06af7c76b4615ae661791b62e93efOndrej Zary ret = 0; 15691da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#endif 15700992a5d029181421877a716eaf99145828ff7eaeAndrew Morton return ret; 15711da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 15721da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 15731da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic void __exit el3_cleanup_module(void) 15741da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 1575ac4bed1375c06af7c76b4615ae661791b62e93efOndrej Zary#ifdef CONFIG_PNP 1576ac4bed1375c06af7c76b4615ae661791b62e93efOndrej Zary if (pnp_registered) 1577ac4bed1375c06af7c76b4615ae661791b62e93efOndrej Zary pnp_unregister_driver(&el3_pnp_driver); 1578ac4bed1375c06af7c76b4615ae661791b62e93efOndrej Zary#endif 1579ac4bed1375c06af7c76b4615ae661791b62e93efOndrej Zary if (isa_registered) 1580ac4bed1375c06af7c76b4615ae661791b62e93efOndrej Zary isa_unregister_driver(&el3_isa_driver); 1581ac4bed1375c06af7c76b4615ae661791b62e93efOndrej Zary if (id_port) 1582ac4bed1375c06af7c76b4615ae661791b62e93efOndrej Zary release_region(id_port, 1); 15831da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#ifdef CONFIG_EISA 1584ac4bed1375c06af7c76b4615ae661791b62e93efOndrej Zary if (eisa_registered) 1585ac4bed1375c06af7c76b4615ae661791b62e93efOndrej Zary eisa_driver_unregister(&el3_eisa_driver); 15861da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#endif 15871da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#ifdef CONFIG_MCA 1588ac4bed1375c06af7c76b4615ae661791b62e93efOndrej Zary if (mca_registered) 1589ac4bed1375c06af7c76b4615ae661791b62e93efOndrej Zary mca_unregister_driver(&el3_mca_driver); 15901da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#endif 15911da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 15921da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 15931da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsmodule_init (el3_init_module); 15941da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsmodule_exit (el3_cleanup_module); 1595