/* 3c574.c: A PCMCIA ethernet driver for the 3com 3c574 "RoadRunner".
Written 1993-1998 by
Donald Becker, becker@scyld.com, (driver core) and
David Hinds, dahinds@users.sourceforge.net (from his PC card code).
Locking fixes (C) Copyright 2003 Red Hat Inc
This software may be used and distributed according to the terms of
the GNU General Public License, incorporated herein by reference.
This driver derives from Donald Becker's 3c509 core, which has the
following copyright:
Copyright 1993 United States Government as represented by the
Director, National Security Agency.
*/
/*
Theory of Operation
I. Board Compatibility
This device driver is designed for the 3Com 3c574 PC card Fast Ethernet
Adapter.
II. Board-specific settings
None -- PC cards are autoconfigured.
III. Driver operation
The 3c574 uses a Boomerang-style interface, without the bus-master capability.
See the Boomerang driver and documentation for most details.
IV. Notes and chip documentation.
Two added registers are used to enhance PIO performance, RunnerRdCtrl and
RunnerWrCtrl. These are 11 bit down-counters that are preloaded with the
count of word (16 bits) reads or writes the driver is about to do to the Rx
or Tx FIFO. The chip is then able to hide the internal-PCI-bus to PC-card
translation latency by buffering the I/O operations with an 8 word FIFO.
Note: No other chip accesses are permitted when this buffer is used.
A second enhancement is that both attribute and common memory space
0x0800-0x0fff can translated to the PIO FIFO. Thus memory operations (faster
with *some* PCcard bridges) may be used instead of I/O operations.
This is enabled by setting the 0x10 bit in the PCMCIA LAN COR.
Some slow PC card bridges work better if they never see a WAIT signal.
This is configured by setting the 0x20 bit in the PCMCIA LAN COR.
Only do this after testing that it is reliable and improves performance.
The upper five bits of RunnerRdCtrl are used to window into PCcard
configuration space registers. Window 0 is the regular Boomerang/Odie
register set, 1-5 are various PC card control registers, and 16-31 are
the (reversed!) CIS table.
A final note: writing the InternalConfig register in window 3 with an
invalid ramWidth is Very Bad.
V. References
http://www.scyld.com/expert/NWay.html
http://www.national.com/pf/DP/DP83840.html
Thanks to Terry Murphy of 3Com for providing development information for
earlier 3Com products.
*/
#include <linux/module.h>
#include <linux/kernel.h>
#include <linux/init.h>
#include <linux/slab.h>
#include <linux/string.h>
#include <linux/timer.h>
#include <linux/interrupt.h>
#include <linux/in.h>
#include <linux/delay.h>
#include <linux/netdevice.h>
#include <linux/etherdevice.h>
#include <linux/skbuff.h>
#include <linux/if_arp.h>
#include <linux/ioport.h>
#include <linux/ethtool.h>
#include <linux/bitops.h>
#include <linux/mii.h>
#include <pcmcia/cistpl.h>
#include <pcmcia/cisreg.h>
#include <pcmcia/ciscode.h>
#include <pcmcia/ds.h>
#include <asm/uaccess.h>
#include <asm/io.h>
#include <asm/system.h>
/*====================================================================*/
/* Module parameters */
MODULE_AUTHOR("David Hinds <dahinds@users.sourceforge.net>");
MODULE_DESCRIPTION("3Com 3c574 series PCMCIA ethernet driver");
MODULE_LICENSE("GPL");
#define INT_MODULE_PARM(n, v) static int n = v; module_param(n, int, 0)
/* Maximum events (Rx packets, etc.) to handle at each interrupt. */
INT_MODULE_PARM(max_interrupt_work, 32);
/* Force full duplex modes? */
INT_MODULE_PARM(full_duplex, 0);
/* Autodetect link polarity reversal? */
INT_MODULE_PARM(auto_polarity, 1);
/*====================================================================*/
/* Time in jiffies before concluding the transmitter is hung. */
#define TX_TIMEOUT ((800*HZ)/1000)
/* To minimize the size of the driver source and make the driver more
readable not all constants are symbolically defined.
You'll need the manual if you want to understand driver details anyway. */
/* Offsets from base I/O address. */
#define EL3_DATA 0x00
#define EL3_CMD 0x0e
#define EL3_STATUS 0x0e
#define EL3WINDOW(win_num) outw(SelectWindow + (win_num), ioaddr + EL3_CMD)
/* The top five bits written to EL3_CMD are a command, the lower
11 bits are the parameter, if applicable. */
enum el3_cmds {
TotalReset = 0<<11, SelectWindow = 1<<11, StartCoax = 2<<11,
RxDisable = 3<<11, RxEnable = 4<<11, RxReset = 5<<11, RxDiscard = 8<<11,
TxEnable = 9<<11, TxDisable = 10<<11, TxReset = 11<<11,
FakeIntr = 12<<11, AckIntr = 13<<11, SetIntrEnb = 14<<11,
SetStatusEnb = 15<<11, SetRxFilter = 16<<11, SetRxThreshold = 17<<11,
SetTxThreshold = 18<<11, SetTxStart = 19<<11, StatsEnable = 21<<11,
StatsDisable = 22<<11, StopCoax = 23<<11,
};
enum elxl_status {
IntLatch = 0x0001, AdapterFailure = 0x0002, TxComplete = 0x0004,
TxAvailable = 0x0008, RxComplete = 0x0010, RxEarly = 0x0020,
IntReq = 0x0040, StatsFull = 0x0080, CmdBusy = 0x1000 };
/* The SetRxFilter command accepts the f