blob: ff824e11f0b6865a74a0f55de50f7a02d659e75c [file] [log] [blame]
Linus Torvalds1da177e2005-04-16 15:20:36 -07001/* 3c574.c: A PCMCIA ethernet driver for the 3com 3c574 "RoadRunner".
2
3 Written 1993-1998 by
4 Donald Becker, becker@scyld.com, (driver core) and
5 David Hinds, dahinds@users.sourceforge.net (from his PC card code).
6 Locking fixes (C) Copyright 2003 Red Hat Inc
7
8 This software may be used and distributed according to the terms of
9 the GNU General Public License, incorporated herein by reference.
10
11 This driver derives from Donald Becker's 3c509 core, which has the
12 following copyright:
13 Copyright 1993 United States Government as represented by the
14 Director, National Security Agency.
15
16
17*/
18
19/*
20 Theory of Operation
21
22I. Board Compatibility
23
24This device driver is designed for the 3Com 3c574 PC card Fast Ethernet
25Adapter.
26
27II. Board-specific settings
28
29None -- PC cards are autoconfigured.
30
31III. Driver operation
32
33The 3c574 uses a Boomerang-style interface, without the bus-master capability.
34See the Boomerang driver and documentation for most details.
35
36IV. Notes and chip documentation.
37
38Two added registers are used to enhance PIO performance, RunnerRdCtrl and
39RunnerWrCtrl. These are 11 bit down-counters that are preloaded with the
40count of word (16 bits) reads or writes the driver is about to do to the Rx
41or Tx FIFO. The chip is then able to hide the internal-PCI-bus to PC-card
42translation latency by buffering the I/O operations with an 8 word FIFO.
43Note: No other chip accesses are permitted when this buffer is used.
44
45A second enhancement is that both attribute and common memory space
460x0800-0x0fff can translated to the PIO FIFO. Thus memory operations (faster
47with *some* PCcard bridges) may be used instead of I/O operations.
48This is enabled by setting the 0x10 bit in the PCMCIA LAN COR.
49
50Some slow PC card bridges work better if they never see a WAIT signal.
51This is configured by setting the 0x20 bit in the PCMCIA LAN COR.
52Only do this after testing that it is reliable and improves performance.
53
54The upper five bits of RunnerRdCtrl are used to window into PCcard
55configuration space registers. Window 0 is the regular Boomerang/Odie
56register set, 1-5 are various PC card control registers, and 16-31 are
57the (reversed!) CIS table.
58
59A final note: writing the InternalConfig register in window 3 with an
60invalid ramWidth is Very Bad.
61
62V. References
63
64http://www.scyld.com/expert/NWay.html
65http://www.national.com/pf/DP/DP83840.html
66
67Thanks to Terry Murphy of 3Com for providing development information for
68earlier 3Com products.
69
70*/
71
72#include <linux/module.h>
73#include <linux/kernel.h>
74#include <linux/init.h>
75#include <linux/slab.h>
76#include <linux/string.h>
77#include <linux/timer.h>
78#include <linux/interrupt.h>
79#include <linux/in.h>
80#include <linux/delay.h>
81#include <linux/netdevice.h>
82#include <linux/etherdevice.h>
83#include <linux/skbuff.h>
84#include <linux/if_arp.h>
85#include <linux/ioport.h>
86#include <linux/ethtool.h>
87#include <linux/bitops.h>
Ben Hutchings0fa0ee052009-09-03 10:41:17 +000088#include <linux/mii.h>
Linus Torvalds1da177e2005-04-16 15:20:36 -070089
Linus Torvalds1da177e2005-04-16 15:20:36 -070090#include <pcmcia/cistpl.h>
91#include <pcmcia/cisreg.h>
92#include <pcmcia/ciscode.h>
93#include <pcmcia/ds.h>
Linus Torvalds1da177e2005-04-16 15:20:36 -070094
95#include <asm/uaccess.h>
96#include <asm/io.h>
97#include <asm/system.h>
98
99/*====================================================================*/
100
101/* Module parameters */
102
103MODULE_AUTHOR("David Hinds <dahinds@users.sourceforge.net>");
104MODULE_DESCRIPTION("3Com 3c574 series PCMCIA ethernet driver");
105MODULE_LICENSE("GPL");
106
107#define INT_MODULE_PARM(n, v) static int n = v; module_param(n, int, 0)
108
109/* Maximum events (Rx packets, etc.) to handle at each interrupt. */
110INT_MODULE_PARM(max_interrupt_work, 32);
111
112/* Force full duplex modes? */
113INT_MODULE_PARM(full_duplex, 0);
114
115/* Autodetect link polarity reversal? */
116INT_MODULE_PARM(auto_polarity, 1);
117
Linus Torvalds1da177e2005-04-16 15:20:36 -0700118
119/*====================================================================*/
120
121/* Time in jiffies before concluding the transmitter is hung. */
122#define TX_TIMEOUT ((800*HZ)/1000)
123
124/* To minimize the size of the driver source and make the driver more
125 readable not all constants are symbolically defined.
126 You'll need the manual if you want to understand driver details anyway. */
127/* Offsets from base I/O address. */
128#define EL3_DATA 0x00
129#define EL3_CMD 0x0e
130#define EL3_STATUS 0x0e
131
132#define EL3WINDOW(win_num) outw(SelectWindow + (win_num), ioaddr + EL3_CMD)
133
134/* The top five bits written to EL3_CMD are a command, the lower
135 11 bits are the parameter, if applicable. */
136enum el3_cmds {
137 TotalReset = 0<<11, SelectWindow = 1<<11, StartCoax = 2<<11,
138 RxDisable = 3<<11, RxEnable = 4<<11, RxReset = 5<<11, RxDiscard = 8<<11,
139 TxEnable = 9<<11, TxDisable = 10<<11, TxReset = 11<<11,
140 FakeIntr = 12<<11, AckIntr = 13<<11, SetIntrEnb = 14<<11,
141 SetStatusEnb = 15<<11, SetRxFilter = 16<<11, SetRxThreshold = 17<<11,
142 SetTxThreshold = 18<<11, SetTxStart = 19<<11, StatsEnable = 21<<11,
143 StatsDisable = 22<<11, StopCoax = 23<<11,
144};
145
146enum elxl_status {
147 IntLatch = 0x0001, AdapterFailure = 0x0002, TxComplete = 0x0004,
148 TxAvailable = 0x0008, RxComplete = 0x0010, RxEarly = 0x0020,
149 IntReq = 0x0040, StatsFull = 0x0080, CmdBusy = 0x1000 };
150
151/* The SetRxFilter command accepts the following classes: */
152enum RxFilter {
153 RxStation = 1, RxMulticast = 2, RxBroadcast = 4, RxProm = 8
154};
155
156enum Window0 {
157 Wn0EepromCmd = 10, Wn0EepromData = 12, /* EEPROM command/address, data. */
158 IntrStatus=0x0E, /* Valid in all windows. */
159};
160/* These assumes the larger EEPROM. */
161enum Win0_EEPROM_cmds {
162 EEPROM_Read = 0x200, EEPROM_WRITE = 0x100, EEPROM_ERASE = 0x300,
163 EEPROM_EWENB = 0x30, /* Enable erasing/writing for 10 msec. */
164 EEPROM_EWDIS = 0x00, /* Disable EWENB before 10 msec timeout. */
165};
166
167/* Register window 1 offsets, the window used in normal operation.
168 On the "Odie" this window is always mapped at offsets 0x10-0x1f.
169 Except for TxFree, which is overlapped by RunnerWrCtrl. */
170enum Window1 {
171 TX_FIFO = 0x10, RX_FIFO = 0x10, RxErrors = 0x14,
172 RxStatus = 0x18, Timer=0x1A, TxStatus = 0x1B,
173 TxFree = 0x0C, /* Remaining free bytes in Tx buffer. */
174 RunnerRdCtrl = 0x16, RunnerWrCtrl = 0x1c,
175};
176
177enum Window3 { /* Window 3: MAC/config bits. */
178 Wn3_Config=0, Wn3_MAC_Ctrl=6, Wn3_Options=8,
179};
Al Virob6659822008-01-13 14:17:35 +0000180enum wn3_config {
181 Ram_size = 7,
182 Ram_width = 8,
183 Ram_speed = 0x30,
184 Rom_size = 0xc0,
185 Ram_split_shift = 16,
186 Ram_split = 3 << Ram_split_shift,
187 Xcvr_shift = 20,
188 Xcvr = 7 << Xcvr_shift,
189 Autoselect = 0x1000000,
Linus Torvalds1da177e2005-04-16 15:20:36 -0700190};
191
192enum Window4 { /* Window 4: Xcvr/media bits. */
193 Wn4_FIFODiag = 4, Wn4_NetDiag = 6, Wn4_PhysicalMgmt=8, Wn4_Media = 10,
194};
195
196#define MEDIA_TP 0x00C0 /* Enable link beat and jabber for 10baseT. */
197
198struct el3_private {
Dominik Brodowskifd238232006-03-05 10:45:09 +0100199 struct pcmcia_device *p_dev;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700200 u16 advertising, partner; /* NWay media advertisement */
201 unsigned char phys; /* MII device address */
202 unsigned int autoselect:1, default_media:3; /* Read from the EEPROM/Wn3_Config. */
203 /* for transceiver monitoring */
204 struct timer_list media;
205 unsigned short media_status;
206 unsigned short fast_poll;
207 unsigned long last_irq;
208 spinlock_t window_lock; /* Guards the Window selection */
209};
210
211/* Set iff a MII transceiver on any interface requires mdio preamble.
212 This only set with the original DP83840 on older 3c905 boards, so the extra
213 code size of a per-interface flag is not worthwhile. */
214static char mii_preamble_required = 0;
215
216/* Index of functions. */
217
Dominik Brodowski15b99ac2006-03-31 17:26:06 +0200218static int tc574_config(struct pcmcia_device *link);
Dominik Brodowskifba395e2006-03-31 17:21:06 +0200219static void tc574_release(struct pcmcia_device *link);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700220
Olof Johansson906da802008-02-04 22:27:35 -0800221static void mdio_sync(unsigned int ioaddr, int bits);
222static int mdio_read(unsigned int ioaddr, int phy_id, int location);
223static void mdio_write(unsigned int ioaddr, int phy_id, int location,
224 int value);
225static unsigned short read_eeprom(unsigned int ioaddr, int index);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700226static void tc574_wait_for_completion(struct net_device *dev, int cmd);
227
228static void tc574_reset(struct net_device *dev);
229static void media_check(unsigned long arg);
230static int el3_open(struct net_device *dev);
Stephen Hemmingerdbf02fa2009-08-31 19:50:49 +0000231static netdev_tx_t el3_start_xmit(struct sk_buff *skb,
232 struct net_device *dev);
David Howells7d12e782006-10-05 14:55:46 +0100233static irqreturn_t el3_interrupt(int irq, void *dev_id);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700234static void update_stats(struct net_device *dev);
235static struct net_device_stats *el3_get_stats(struct net_device *dev);
236static int el3_rx(struct net_device *dev, int worklimit);
237static int el3_close(struct net_device *dev);
238static void el3_tx_timeout(struct net_device *dev);
239static int el3_ioctl(struct net_device *dev, struct ifreq *rq, int cmd);
Jeff Garzik7282d492006-09-13 14:30:00 -0400240static const struct ethtool_ops netdev_ethtool_ops;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700241static void set_rx_mode(struct net_device *dev);
Ken Kawasakie3eef532009-10-13 00:32:55 -0700242static void set_multicast_list(struct net_device *dev);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700243
Dominik Brodowskicc3b4862005-11-14 21:23:14 +0100244static void tc574_detach(struct pcmcia_device *p_dev);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700245
Linus Torvalds1da177e2005-04-16 15:20:36 -0700246/*
247 tc574_attach() creates an "instance" of the driver, allocating
248 local data structures for one device. The device is registered
249 with Card Services.
250*/
Stephen Hemmingerfb72e2f2009-03-20 19:36:02 +0000251static const struct net_device_ops el3_netdev_ops = {
252 .ndo_open = el3_open,
253 .ndo_stop = el3_close,
254 .ndo_start_xmit = el3_start_xmit,
255 .ndo_tx_timeout = el3_tx_timeout,
256 .ndo_get_stats = el3_get_stats,
257 .ndo_do_ioctl = el3_ioctl,
Ken Kawasakie3eef532009-10-13 00:32:55 -0700258 .ndo_set_multicast_list = set_multicast_list,
Stephen Hemmingerfb72e2f2009-03-20 19:36:02 +0000259 .ndo_change_mtu = eth_change_mtu,
260 .ndo_set_mac_address = eth_mac_addr,
261 .ndo_validate_addr = eth_validate_addr,
262};
Linus Torvalds1da177e2005-04-16 15:20:36 -0700263
Dominik Brodowski15b99ac2006-03-31 17:26:06 +0200264static int tc574_probe(struct pcmcia_device *link)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700265{
266 struct el3_private *lp;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700267 struct net_device *dev;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700268
Dominik Brodowskidd0fab52009-10-24 15:51:05 +0200269 dev_dbg(&link->dev, "3c574_attach()\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -0700270
271 /* Create the PC card device object. */
272 dev = alloc_etherdev(sizeof(struct el3_private));
273 if (!dev)
Dominik Brodowskif8cfa612005-11-14 21:25:51 +0100274 return -ENOMEM;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700275 lp = netdev_priv(dev);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700276 link->priv = dev;
Dominik Brodowskifba395e2006-03-31 17:21:06 +0200277 lp->p_dev = link;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700278
279 spin_lock_init(&lp->window_lock);
Dominik Brodowski90abdc32010-07-24 17:23:51 +0200280 link->resource[0]->end = 32;
281 link->resource[0]->flags |= IO_DATA_PATH_WIDTH_16;
Dominik Brodowski1ac71e52010-07-29 19:27:09 +0200282 link->config_flags |= CONF_ENABLE_IRQ;
Dominik Brodowski7feabb62010-07-29 18:35:47 +0200283 link->config_index = 1;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700284
Stephen Hemmingerfb72e2f2009-03-20 19:36:02 +0000285 dev->netdev_ops = &el3_netdev_ops;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700286 SET_ETHTOOL_OPS(dev, &netdev_ethtool_ops);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700287 dev->watchdog_timeo = TX_TIMEOUT;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700288
Dominik Brodowski15b99ac2006-03-31 17:26:06 +0200289 return tc574_config(link);
Dominik Brodowski22620542010-08-15 08:38:38 +0200290}
Linus Torvalds1da177e2005-04-16 15:20:36 -0700291
Dominik Brodowskifba395e2006-03-31 17:21:06 +0200292static void tc574_detach(struct pcmcia_device *link)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700293{
294 struct net_device *dev = link->priv;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700295
Dominik Brodowskidd0fab52009-10-24 15:51:05 +0200296 dev_dbg(&link->dev, "3c574_detach()\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -0700297
Dominik Brodowskic7c2fa02010-03-20 19:39:26 +0100298 unregister_netdev(dev);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700299
Dominik Brodowskie2d40962006-03-02 00:09:29 +0100300 tc574_release(link);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700301
Linus Torvalds1da177e2005-04-16 15:20:36 -0700302 free_netdev(dev);
303} /* tc574_detach */
304
Arjan van de Venf71e1302006-03-03 21:33:57 -0500305static const char *ram_split[] = {"5:3", "3:1", "1:1", "3:5"};
Linus Torvalds1da177e2005-04-16 15:20:36 -0700306
Dominik Brodowski15b99ac2006-03-31 17:26:06 +0200307static int tc574_config(struct pcmcia_device *link)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700308{
Linus Torvalds1da177e2005-04-16 15:20:36 -0700309 struct net_device *dev = link->priv;
310 struct el3_private *lp = netdev_priv(dev);
Dominik Brodowskidd0fab52009-10-24 15:51:05 +0200311 int ret, i, j;
Olof Johansson906da802008-02-04 22:27:35 -0800312 unsigned int ioaddr;
Al Virob1e247a2007-12-22 18:56:13 +0000313 __be16 *phys_addr;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700314 char *cardname;
Al Virob6659822008-01-13 14:17:35 +0000315 __u32 config;
Dominik Brodowskidddfbd82009-10-18 23:54:24 +0200316 u8 *buf;
317 size_t len;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700318
Al Virob1e247a2007-12-22 18:56:13 +0000319 phys_addr = (__be16 *)dev->dev_addr;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700320
Dominik Brodowskidd0fab52009-10-24 15:51:05 +0200321 dev_dbg(&link->dev, "3c574_config()\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -0700322
Dominik Brodowski90abdc32010-07-24 17:23:51 +0200323 link->io_lines = 16;
324
Linus Torvalds1da177e2005-04-16 15:20:36 -0700325 for (i = j = 0; j < 0x400; j += 0x20) {
Dominik Brodowski90abdc32010-07-24 17:23:51 +0200326 link->resource[0]->start = j ^ 0x300;
327 i = pcmcia_request_io(link);
Dominik Brodowski4c89e882008-08-03 10:07:45 +0200328 if (i == 0)
329 break;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700330 }
Dominik Brodowskidd0fab52009-10-24 15:51:05 +0200331 if (i != 0)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700332 goto failed;
Dominik Brodowskidd0fab52009-10-24 15:51:05 +0200333
Dominik Brodowskieb141202010-03-07 12:21:16 +0100334 ret = pcmcia_request_irq(link, el3_interrupt);
Dominik Brodowskidd0fab52009-10-24 15:51:05 +0200335 if (ret)
336 goto failed;
337
Dominik Brodowski1ac71e52010-07-29 19:27:09 +0200338 ret = pcmcia_enable_device(link);
Dominik Brodowskidd0fab52009-10-24 15:51:05 +0200339 if (ret)
340 goto failed;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700341
Dominik Brodowskieb141202010-03-07 12:21:16 +0100342 dev->irq = link->irq;
Dominik Brodowski9a017a92010-07-24 15:58:54 +0200343 dev->base_addr = link->resource[0]->start;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700344
345 ioaddr = dev->base_addr;
346
347 /* The 3c574 normally uses an EEPROM for configuration info, including
348 the hardware address. The future products may include a modem chip
349 and put the address in the CIS. */
Dominik Brodowskidddfbd82009-10-18 23:54:24 +0200350
351 len = pcmcia_get_tuple(link, 0x88, &buf);
352 if (buf && len >= 6) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700353 for (i = 0; i < 3; i++)
Dominik Brodowskidddfbd82009-10-18 23:54:24 +0200354 phys_addr[i] = htons(le16_to_cpu(buf[i * 2]));
355 kfree(buf);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700356 } else {
Dominik Brodowskidddfbd82009-10-18 23:54:24 +0200357 kfree(buf); /* 0 < len < 6 */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700358 EL3WINDOW(0);
359 for (i = 0; i < 3; i++)
360 phys_addr[i] = htons(read_eeprom(ioaddr, i + 10));
Al Virob1e247a2007-12-22 18:56:13 +0000361 if (phys_addr[0] == htons(0x6060)) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700362 printk(KERN_NOTICE "3c574_cs: IO port conflict at 0x%03lx"
363 "-0x%03lx\n", dev->base_addr, dev->base_addr+15);
364 goto failed;
365 }
366 }
Dominik Brodowskia9606fd2006-06-04 18:06:13 +0200367 if (link->prod_id[1])
368 cardname = link->prod_id[1];
369 else
Linus Torvalds1da177e2005-04-16 15:20:36 -0700370 cardname = "3Com 3c574";
371
372 {
373 u_char mcr;
374 outw(2<<11, ioaddr + RunnerRdCtrl);
375 mcr = inb(ioaddr + 2);
376 outw(0<<11, ioaddr + RunnerRdCtrl);
377 printk(KERN_INFO " ASIC rev %d,", mcr>>3);
378 EL3WINDOW(3);
Al Virob6659822008-01-13 14:17:35 +0000379 config = inl(ioaddr + Wn3_Config);
380 lp->default_media = (config & Xcvr) >> Xcvr_shift;
381 lp->autoselect = config & Autoselect ? 1 : 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700382 }
383
384 init_timer(&lp->media);
385
386 {
387 int phy;
388
389 /* Roadrunner only: Turn on the MII transceiver */
390 outw(0x8040, ioaddr + Wn3_Options);
391 mdelay(1);
392 outw(0xc040, ioaddr + Wn3_Options);
393 tc574_wait_for_completion(dev, TxReset);
394 tc574_wait_for_completion(dev, RxReset);
395 mdelay(1);
396 outw(0x8040, ioaddr + Wn3_Options);
397
398 EL3WINDOW(4);
399 for (phy = 1; phy <= 32; phy++) {
400 int mii_status;
401 mdio_sync(ioaddr, 32);
402 mii_status = mdio_read(ioaddr, phy & 0x1f, 1);
403 if (mii_status != 0xffff) {
404 lp->phys = phy & 0x1f;
Dominik Brodowskidd0fab52009-10-24 15:51:05 +0200405 dev_dbg(&link->dev, " MII transceiver at "
406 "index %d, status %x.\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -0700407 phy, mii_status);
408 if ((mii_status & 0x0040) == 0)
409 mii_preamble_required = 1;
410 break;
411 }
412 }
413 if (phy > 32) {
414 printk(KERN_NOTICE " No MII transceivers found!\n");
415 goto failed;
416 }
417 i = mdio_read(ioaddr, lp->phys, 16) | 0x40;
418 mdio_write(ioaddr, lp->phys, 16, i);
419 lp->advertising = mdio_read(ioaddr, lp->phys, 4);
420 if (full_duplex) {
421 /* Only advertise the FD media types. */
422 lp->advertising &= ~0x02a0;
423 mdio_write(ioaddr, lp->phys, 4, lp->advertising);
424 }
425 }
426
Dominik Brodowskidd2e5a12009-11-03 10:27:34 +0100427 SET_NETDEV_DEV(dev, &link->dev);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700428
429 if (register_netdev(dev) != 0) {
430 printk(KERN_NOTICE "3c574_cs: register_netdev() failed\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -0700431 goto failed;
432 }
433
Joe Perches0795af52007-10-03 17:59:30 -0700434 printk(KERN_INFO "%s: %s at io %#3lx, irq %d, "
Johannes Berge1749612008-10-27 15:59:26 -0700435 "hw_addr %pM.\n",
Joe Perches0795af52007-10-03 17:59:30 -0700436 dev->name, cardname, dev->base_addr, dev->irq,
Johannes Berge1749612008-10-27 15:59:26 -0700437 dev->dev_addr);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700438 printk(" %dK FIFO split %s Rx:Tx, %sMII interface.\n",
Al Virob6659822008-01-13 14:17:35 +0000439 8 << config & Ram_size,
440 ram_split[(config & Ram_split) >> Ram_split_shift],
441 config & Autoselect ? "autoselect " : "");
Linus Torvalds1da177e2005-04-16 15:20:36 -0700442
Dominik Brodowski15b99ac2006-03-31 17:26:06 +0200443 return 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700444
Linus Torvalds1da177e2005-04-16 15:20:36 -0700445failed:
446 tc574_release(link);
Dominik Brodowski15b99ac2006-03-31 17:26:06 +0200447 return -ENODEV;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700448
449} /* tc574_config */
450
Dominik Brodowskifba395e2006-03-31 17:21:06 +0200451static void tc574_release(struct pcmcia_device *link)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700452{
Dominik Brodowskifba395e2006-03-31 17:21:06 +0200453 pcmcia_disable_device(link);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700454}
455
Dominik Brodowskifba395e2006-03-31 17:21:06 +0200456static int tc574_suspend(struct pcmcia_device *link)
Dominik Brodowski98e4c282005-11-14 21:21:18 +0100457{
Dominik Brodowski98e4c282005-11-14 21:21:18 +0100458 struct net_device *dev = link->priv;
459
Dominik Brodowskie2d40962006-03-02 00:09:29 +0100460 if (link->open)
Dominik Brodowski8661bb52006-03-02 00:02:33 +0100461 netif_device_detach(dev);
Dominik Brodowski98e4c282005-11-14 21:21:18 +0100462
463 return 0;
464}
465
Dominik Brodowskifba395e2006-03-31 17:21:06 +0200466static int tc574_resume(struct pcmcia_device *link)
Dominik Brodowski98e4c282005-11-14 21:21:18 +0100467{
Dominik Brodowski98e4c282005-11-14 21:21:18 +0100468 struct net_device *dev = link->priv;
469
Dominik Brodowskie2d40962006-03-02 00:09:29 +0100470 if (link->open) {
Dominik Brodowski8661bb52006-03-02 00:02:33 +0100471 tc574_reset(dev);
472 netif_device_attach(dev);
Dominik Brodowski98e4c282005-11-14 21:21:18 +0100473 }
474
475 return 0;
476}
477
Linus Torvalds1da177e2005-04-16 15:20:36 -0700478static void dump_status(struct net_device *dev)
479{
Olof Johansson906da802008-02-04 22:27:35 -0800480 unsigned int ioaddr = dev->base_addr;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700481 EL3WINDOW(1);
482 printk(KERN_INFO " irq status %04x, rx status %04x, tx status "
483 "%02x, tx free %04x\n", inw(ioaddr+EL3_STATUS),
484 inw(ioaddr+RxStatus), inb(ioaddr+TxStatus),
485 inw(ioaddr+TxFree));
486 EL3WINDOW(4);
487 printk(KERN_INFO " diagnostics: fifo %04x net %04x ethernet %04x"
488 " media %04x\n", inw(ioaddr+0x04), inw(ioaddr+0x06),
489 inw(ioaddr+0x08), inw(ioaddr+0x0a));
490 EL3WINDOW(1);
491}
492
493/*
494 Use this for commands that may take time to finish
495*/
496static void tc574_wait_for_completion(struct net_device *dev, int cmd)
497{
498 int i = 1500;
499 outw(cmd, dev->base_addr + EL3_CMD);
500 while (--i > 0)
501 if (!(inw(dev->base_addr + EL3_STATUS) & 0x1000)) break;
502 if (i == 0)
503 printk(KERN_NOTICE "%s: command 0x%04x did not complete!\n", dev->name, cmd);
504}
505
506/* Read a word from the EEPROM using the regular EEPROM access register.
507 Assume that we are in register window zero.
508 */
Olof Johansson906da802008-02-04 22:27:35 -0800509static unsigned short read_eeprom(unsigned int ioaddr, int index)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700510{
511 int timer;
512 outw(EEPROM_Read + index, ioaddr + Wn0EepromCmd);
513 /* Pause for at least 162 usec for the read to take place. */
514 for (timer = 1620; timer >= 0; timer--) {
515 if ((inw(ioaddr + Wn0EepromCmd) & 0x8000) == 0)
516 break;
517 }
518 return inw(ioaddr + Wn0EepromData);
519}
520
521/* MII transceiver control section.
522 Read and write the MII registers using software-generated serial
523 MDIO protocol. See the MII specifications or DP83840A data sheet
524 for details.
525 The maxium data clock rate is 2.5 Mhz. The timing is easily met by the
526 slow PC card interface. */
527
528#define MDIO_SHIFT_CLK 0x01
529#define MDIO_DIR_WRITE 0x04
530#define MDIO_DATA_WRITE0 (0x00 | MDIO_DIR_WRITE)
531#define MDIO_DATA_WRITE1 (0x02 | MDIO_DIR_WRITE)
532#define MDIO_DATA_READ 0x02
533#define MDIO_ENB_IN 0x00
534
535/* Generate the preamble required for initial synchronization and
536 a few older transceivers. */
Olof Johansson906da802008-02-04 22:27:35 -0800537static void mdio_sync(unsigned int ioaddr, int bits)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700538{
Olof Johansson906da802008-02-04 22:27:35 -0800539 unsigned int mdio_addr = ioaddr + Wn4_PhysicalMgmt;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700540
541 /* Establish sync by sending at least 32 logic ones. */
542 while (-- bits >= 0) {
543 outw(MDIO_DATA_WRITE1, mdio_addr);
544 outw(MDIO_DATA_WRITE1 | MDIO_SHIFT_CLK, mdio_addr);
545 }
546}
547
Olof Johansson906da802008-02-04 22:27:35 -0800548static int mdio_read(unsigned int ioaddr, int phy_id, int location)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700549{
550 int i;
551 int read_cmd = (0xf6 << 10) | (phy_id << 5) | location;
552 unsigned int retval = 0;
Olof Johansson906da802008-02-04 22:27:35 -0800553 unsigned int mdio_addr = ioaddr + Wn4_PhysicalMgmt;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700554
555 if (mii_preamble_required)
556 mdio_sync(ioaddr, 32);
557
558 /* Shift the read command bits out. */
559 for (i = 14; i >= 0; i--) {
560 int dataval = (read_cmd&(1<<i)) ? MDIO_DATA_WRITE1 : MDIO_DATA_WRITE0;
561 outw(dataval, mdio_addr);
562 outw(dataval | MDIO_SHIFT_CLK, mdio_addr);
563 }
564 /* Read the two transition, 16 data, and wire-idle bits. */
565 for (i = 19; i > 0; i--) {
566 outw(MDIO_ENB_IN, mdio_addr);
567 retval = (retval << 1) | ((inw(mdio_addr) & MDIO_DATA_READ) ? 1 : 0);
568 outw(MDIO_ENB_IN | MDIO_SHIFT_CLK, mdio_addr);
569 }
570 return (retval>>1) & 0xffff;
571}
572
Olof Johansson906da802008-02-04 22:27:35 -0800573static void mdio_write(unsigned int ioaddr, int phy_id, int location, int value)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700574{
575 int write_cmd = 0x50020000 | (phy_id << 23) | (location << 18) | value;
Olof Johansson906da802008-02-04 22:27:35 -0800576 unsigned int mdio_addr = ioaddr + Wn4_PhysicalMgmt;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700577 int i;
578
579 if (mii_preamble_required)
580 mdio_sync(ioaddr, 32);
581
582 /* Shift the command bits out. */
583 for (i = 31; i >= 0; i--) {
584 int dataval = (write_cmd&(1<<i)) ? MDIO_DATA_WRITE1 : MDIO_DATA_WRITE0;
585 outw(dataval, mdio_addr);
586 outw(dataval | MDIO_SHIFT_CLK, mdio_addr);
587 }
588 /* Leave the interface idle. */
589 for (i = 1; i >= 0; i--) {
590 outw(MDIO_ENB_IN, mdio_addr);
591 outw(MDIO_ENB_IN | MDIO_SHIFT_CLK, mdio_addr);
592 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700593}
594
595/* Reset and restore all of the 3c574 registers. */
596static void tc574_reset(struct net_device *dev)
597{
598 struct el3_private *lp = netdev_priv(dev);
599 int i;
Olof Johansson906da802008-02-04 22:27:35 -0800600 unsigned int ioaddr = dev->base_addr;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700601 unsigned long flags;
602
603 tc574_wait_for_completion(dev, TotalReset|0x10);
604
605 spin_lock_irqsave(&lp->window_lock, flags);
606 /* Clear any transactions in progress. */
607 outw(0, ioaddr + RunnerWrCtrl);
608 outw(0, ioaddr + RunnerRdCtrl);
609
610 /* Set the station address and mask. */
611 EL3WINDOW(2);
612 for (i = 0; i < 6; i++)
613 outb(dev->dev_addr[i], ioaddr + i);
614 for (; i < 12; i+=2)
615 outw(0, ioaddr + i);
616
617 /* Reset config options */
618 EL3WINDOW(3);
619 outb((dev->mtu > 1500 ? 0x40 : 0), ioaddr + Wn3_MAC_Ctrl);
620 outl((lp->autoselect ? 0x01000000 : 0) | 0x0062001b,
621 ioaddr + Wn3_Config);
622 /* Roadrunner only: Turn on the MII transceiver. */
623 outw(0x8040, ioaddr + Wn3_Options);
624 mdelay(1);
625 outw(0xc040, ioaddr + Wn3_Options);
626 EL3WINDOW(1);
627 spin_unlock_irqrestore(&lp->window_lock, flags);
628
629 tc574_wait_for_completion(dev, TxReset);
630 tc574_wait_for_completion(dev, RxReset);
631 mdelay(1);
632 spin_lock_irqsave(&lp->window_lock, flags);
633 EL3WINDOW(3);
634 outw(0x8040, ioaddr + Wn3_Options);
635
636 /* Switch to the stats window, and clear all stats by reading. */
637 outw(StatsDisable, ioaddr + EL3_CMD);
638 EL3WINDOW(6);
639 for (i = 0; i < 10; i++)
640 inb(ioaddr + i);
641 inw(ioaddr + 10);
642 inw(ioaddr + 12);
643 EL3WINDOW(4);
644 inb(ioaddr + 12);
645 inb(ioaddr + 13);
646
647 /* .. enable any extra statistics bits.. */
648 outw(0x0040, ioaddr + Wn4_NetDiag);
649
650 EL3WINDOW(1);
651 spin_unlock_irqrestore(&lp->window_lock, flags);
652
653 /* .. re-sync MII and re-fill what NWay is advertising. */
654 mdio_sync(ioaddr, 32);
655 mdio_write(ioaddr, lp->phys, 4, lp->advertising);
656 if (!auto_polarity) {
657 /* works for TDK 78Q2120 series MII's */
Richard Knutsson1569d9e2008-02-04 22:27:39 -0800658 i = mdio_read(ioaddr, lp->phys, 16) | 0x20;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700659 mdio_write(ioaddr, lp->phys, 16, i);
660 }
661
662 spin_lock_irqsave(&lp->window_lock, flags);
663 /* Switch to register set 1 for normal use, just for TxFree. */
664 set_rx_mode(dev);
665 spin_unlock_irqrestore(&lp->window_lock, flags);
666 outw(StatsEnable, ioaddr + EL3_CMD); /* Turn on statistics. */
667 outw(RxEnable, ioaddr + EL3_CMD); /* Enable the receiver. */
668 outw(TxEnable, ioaddr + EL3_CMD); /* Enable transmitter. */
669 /* Allow status bits to be seen. */
670 outw(SetStatusEnb | 0xff, ioaddr + EL3_CMD);
671 /* Ack all pending events, and set active indicator mask. */
672 outw(AckIntr | IntLatch | TxAvailable | RxEarly | IntReq,
673 ioaddr + EL3_CMD);
674 outw(SetIntrEnb | IntLatch | TxAvailable | RxComplete | StatsFull
675 | AdapterFailure | RxEarly, ioaddr + EL3_CMD);
676}
677
678static int el3_open(struct net_device *dev)
679{
680 struct el3_private *lp = netdev_priv(dev);
Dominik Brodowskifba395e2006-03-31 17:21:06 +0200681 struct pcmcia_device *link = lp->p_dev;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700682
Dominik Brodowski9940ec32006-03-05 11:04:33 +0100683 if (!pcmcia_dev_present(link))
Linus Torvalds1da177e2005-04-16 15:20:36 -0700684 return -ENODEV;
685
686 link->open++;
687 netif_start_queue(dev);
688
689 tc574_reset(dev);
690 lp->media.function = &media_check;
691 lp->media.data = (unsigned long) dev;
692 lp->media.expires = jiffies + HZ;
693 add_timer(&lp->media);
694
Dominik Brodowskidd0fab52009-10-24 15:51:05 +0200695 dev_dbg(&link->dev, "%s: opened, status %4.4x.\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -0700696 dev->name, inw(dev->base_addr + EL3_STATUS));
697
698 return 0;
699}
700
701static void el3_tx_timeout(struct net_device *dev)
702{
Olof Johansson906da802008-02-04 22:27:35 -0800703 unsigned int ioaddr = dev->base_addr;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700704
705 printk(KERN_NOTICE "%s: Transmit timed out!\n", dev->name);
706 dump_status(dev);
Paulius Zaleckas2e8d31d2008-04-30 01:08:26 +0300707 dev->stats.tx_errors++;
Eric Dumazet1ae5dc32010-05-10 05:01:31 -0700708 dev->trans_start = jiffies; /* prevent tx timeout */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700709 /* Issue TX_RESET and TX_START commands. */
710 tc574_wait_for_completion(dev, TxReset);
711 outw(TxEnable, ioaddr + EL3_CMD);
712 netif_wake_queue(dev);
713}
714
715static void pop_tx_status(struct net_device *dev)
716{
Olof Johansson906da802008-02-04 22:27:35 -0800717 unsigned int ioaddr = dev->base_addr;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700718 int i;
719
720 /* Clear the Tx status stack. */
721 for (i = 32; i > 0; i--) {
722 u_char tx_status = inb(ioaddr + TxStatus);
723 if (!(tx_status & 0x84))
724 break;
725 /* reset transmitter on jabber error or underrun */
726 if (tx_status & 0x30)
727 tc574_wait_for_completion(dev, TxReset);
728 if (tx_status & 0x38) {
Dominik Brodowskidd0fab52009-10-24 15:51:05 +0200729 pr_debug("%s: transmit error: status 0x%02x\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -0700730 dev->name, tx_status);
731 outw(TxEnable, ioaddr + EL3_CMD);
Paulius Zaleckas2e8d31d2008-04-30 01:08:26 +0300732 dev->stats.tx_aborted_errors++;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700733 }
734 outb(0x00, ioaddr + TxStatus); /* Pop the status stack. */
735 }
736}
737
Stephen Hemmingerdbf02fa2009-08-31 19:50:49 +0000738static netdev_tx_t el3_start_xmit(struct sk_buff *skb,
739 struct net_device *dev)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700740{
Olof Johansson906da802008-02-04 22:27:35 -0800741 unsigned int ioaddr = dev->base_addr;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700742 struct el3_private *lp = netdev_priv(dev);
743 unsigned long flags;
744
Dominik Brodowskidd0fab52009-10-24 15:51:05 +0200745 pr_debug("%s: el3_start_xmit(length = %ld) called, "
Linus Torvalds1da177e2005-04-16 15:20:36 -0700746 "status %4.4x.\n", dev->name, (long)skb->len,
747 inw(ioaddr + EL3_STATUS));
748
749 spin_lock_irqsave(&lp->window_lock, flags);
Alexander Kurzdf245dc2010-04-16 03:01:01 +0000750
751 dev->stats.tx_bytes += skb->len;
752
753 /* Put out the doubleword header... */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700754 outw(skb->len, ioaddr + TX_FIFO);
755 outw(0, ioaddr + TX_FIFO);
Alexander Kurzdf245dc2010-04-16 03:01:01 +0000756 /* ... and the packet rounded to a doubleword. */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700757 outsl(ioaddr + TX_FIFO, skb->data, (skb->len+3)>>2);
758
Linus Torvalds1da177e2005-04-16 15:20:36 -0700759 /* TxFree appears only in Window 1, not offset 0x1c. */
760 if (inw(ioaddr + TxFree) <= 1536) {
761 netif_stop_queue(dev);
762 /* Interrupt us when the FIFO has room for max-sized packet.
763 The threshold is in units of dwords. */
764 outw(SetTxThreshold + (1536>>2), ioaddr + EL3_CMD);
765 }
766
767 pop_tx_status(dev);
768 spin_unlock_irqrestore(&lp->window_lock, flags);
769 dev_kfree_skb(skb);
Patrick McHardy6ed10652009-06-23 06:03:08 +0000770 return NETDEV_TX_OK;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700771}
772
773/* The EL3 interrupt handler. */
David Howells7d12e782006-10-05 14:55:46 +0100774static irqreturn_t el3_interrupt(int irq, void *dev_id)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700775{
776 struct net_device *dev = (struct net_device *) dev_id;
777 struct el3_private *lp = netdev_priv(dev);
Olof Johansson906da802008-02-04 22:27:35 -0800778 unsigned int ioaddr;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700779 unsigned status;
780 int work_budget = max_interrupt_work;
781 int handled = 0;
782
783 if (!netif_device_present(dev))
784 return IRQ_NONE;
785 ioaddr = dev->base_addr;
786
Dominik Brodowskidd0fab52009-10-24 15:51:05 +0200787 pr_debug("%s: interrupt, status %4.4x.\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -0700788 dev->name, inw(ioaddr + EL3_STATUS));
789
790 spin_lock(&lp->window_lock);
791
792 while ((status = inw(ioaddr + EL3_STATUS)) &
793 (IntLatch | RxComplete | RxEarly | StatsFull)) {
794 if (!netif_device_present(dev) ||
795 ((status & 0xe000) != 0x2000)) {
Dominik Brodowskidd0fab52009-10-24 15:51:05 +0200796 pr_debug("%s: Interrupt from dead card\n", dev->name);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700797 break;
798 }
799
800 handled = 1;
801
802 if (status & RxComplete)
803 work_budget = el3_rx(dev, work_budget);
804
805 if (status & TxAvailable) {
Dominik Brodowskidd0fab52009-10-24 15:51:05 +0200806 pr_debug(" TX room bit was handled.\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -0700807 /* There's room in the FIFO for a full-sized packet. */
808 outw(AckIntr | TxAvailable, ioaddr + EL3_CMD);
809 netif_wake_queue(dev);
810 }
811
812 if (status & TxComplete)
813 pop_tx_status(dev);
814
815 if (status & (AdapterFailure | RxEarly | StatsFull)) {
816 /* Handle all uncommon interrupts. */
817 if (status & StatsFull)
818 update_stats(dev);
819 if (status & RxEarly) {
820 work_budget = el3_rx(dev, work_budget);
821 outw(AckIntr | RxEarly, ioaddr + EL3_CMD);
822 }
823 if (status & AdapterFailure) {
824 u16 fifo_diag;
825 EL3WINDOW(4);
826 fifo_diag = inw(ioaddr + Wn4_FIFODiag);
827 EL3WINDOW(1);
828 printk(KERN_NOTICE "%s: adapter failure, FIFO diagnostic"
829 " register %04x.\n", dev->name, fifo_diag);
830 if (fifo_diag & 0x0400) {
831 /* Tx overrun */
832 tc574_wait_for_completion(dev, TxReset);
833 outw(TxEnable, ioaddr + EL3_CMD);
834 }
835 if (fifo_diag & 0x2000) {
836 /* Rx underrun */
837 tc574_wait_for_completion(dev, RxReset);
838 set_rx_mode(dev);
839 outw(RxEnable, ioaddr + EL3_CMD);
840 }
841 outw(AckIntr | AdapterFailure, ioaddr + EL3_CMD);
842 }
843 }
844
845 if (--work_budget < 0) {
Dominik Brodowskidd0fab52009-10-24 15:51:05 +0200846 pr_debug("%s: Too much work in interrupt, "
Linus Torvalds1da177e2005-04-16 15:20:36 -0700847 "status %4.4x.\n", dev->name, status);
848 /* Clear all interrupts */
849 outw(AckIntr | 0xFF, ioaddr + EL3_CMD);
850 break;
851 }
852 /* Acknowledge the IRQ. */
853 outw(AckIntr | IntReq | IntLatch, ioaddr + EL3_CMD);
854 }
855
Dominik Brodowskidd0fab52009-10-24 15:51:05 +0200856 pr_debug("%s: exiting interrupt, status %4.4x.\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -0700857 dev->name, inw(ioaddr + EL3_STATUS));
858
859 spin_unlock(&lp->window_lock);
860 return IRQ_RETVAL(handled);
861}
862
863/*
864 This timer serves two purposes: to check for missed interrupts
865 (and as a last resort, poll the NIC for events), and to monitor
866 the MII, reporting changes in cable status.
867*/
868static void media_check(unsigned long arg)
869{
870 struct net_device *dev = (struct net_device *) arg;
871 struct el3_private *lp = netdev_priv(dev);
Olof Johansson906da802008-02-04 22:27:35 -0800872 unsigned int ioaddr = dev->base_addr;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700873 unsigned long flags;
874 unsigned short /* cable, */ media, partner;
875
876 if (!netif_device_present(dev))
877 goto reschedule;
878
879 /* Check for pending interrupt with expired latency timer: with
880 this, we can limp along even if the interrupt is blocked */
881 if ((inw(ioaddr + EL3_STATUS) & IntLatch) && (inb(ioaddr + Timer) == 0xff)) {
882 if (!lp->fast_poll)
883 printk(KERN_INFO "%s: interrupt(s) dropped!\n", dev->name);
Ken Kawasaki671c8802009-12-12 14:44:11 +0000884
885 local_irq_save(flags);
Komuroe363d132007-02-10 11:57:35 +0900886 el3_interrupt(dev->irq, dev);
Ken Kawasaki671c8802009-12-12 14:44:11 +0000887 local_irq_restore(flags);
888
Linus Torvalds1da177e2005-04-16 15:20:36 -0700889 lp->fast_poll = HZ;
890 }
891 if (lp->fast_poll) {
892 lp->fast_poll--;
893 lp->media.expires = jiffies + 2*HZ/100;
894 add_timer(&lp->media);
895 return;
896 }
897
898 spin_lock_irqsave(&lp->window_lock, flags);
899 EL3WINDOW(4);
900 media = mdio_read(ioaddr, lp->phys, 1);
901 partner = mdio_read(ioaddr, lp->phys, 5);
902 EL3WINDOW(1);
903
904 if (media != lp->media_status) {
905 if ((media ^ lp->media_status) & 0x0004)
906 printk(KERN_INFO "%s: %s link beat\n", dev->name,
907 (lp->media_status & 0x0004) ? "lost" : "found");
908 if ((media ^ lp->media_status) & 0x0020) {
909 lp->partner = 0;
910 if (lp->media_status & 0x0020) {
911 printk(KERN_INFO "%s: autonegotiation restarted\n",
912 dev->name);
913 } else if (partner) {
914 partner &= lp->advertising;
915 lp->partner = partner;
916 printk(KERN_INFO "%s: autonegotiation complete: "
917 "%sbaseT-%cD selected\n", dev->name,
918 ((partner & 0x0180) ? "100" : "10"),
919 ((partner & 0x0140) ? 'F' : 'H'));
920 } else {
921 printk(KERN_INFO "%s: link partner did not autonegotiate\n",
922 dev->name);
923 }
924
925 EL3WINDOW(3);
926 outb((partner & 0x0140 ? 0x20 : 0) |
927 (dev->mtu > 1500 ? 0x40 : 0), ioaddr + Wn3_MAC_Ctrl);
928 EL3WINDOW(1);
929
930 }
931 if (media & 0x0010)
932 printk(KERN_INFO "%s: remote fault detected\n",
933 dev->name);
934 if (media & 0x0002)
935 printk(KERN_INFO "%s: jabber detected\n", dev->name);
936 lp->media_status = media;
937 }
938 spin_unlock_irqrestore(&lp->window_lock, flags);
939
940reschedule:
941 lp->media.expires = jiffies + HZ;
942 add_timer(&lp->media);
943}
944
945static struct net_device_stats *el3_get_stats(struct net_device *dev)
946{
947 struct el3_private *lp = netdev_priv(dev);
948
949 if (netif_device_present(dev)) {
950 unsigned long flags;
951 spin_lock_irqsave(&lp->window_lock, flags);
952 update_stats(dev);
953 spin_unlock_irqrestore(&lp->window_lock, flags);
954 }
Paulius Zaleckas2e8d31d2008-04-30 01:08:26 +0300955 return &dev->stats;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700956}
957
958/* Update statistics.
959 Suprisingly this need not be run single-threaded, but it effectively is.
960 The counters clear when read, so the adds must merely be atomic.
961 */
962static void update_stats(struct net_device *dev)
963{
Olof Johansson906da802008-02-04 22:27:35 -0800964 unsigned int ioaddr = dev->base_addr;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700965 u8 rx, tx, up;
966
Dominik Brodowskidd0fab52009-10-24 15:51:05 +0200967 pr_debug("%s: updating the statistics.\n", dev->name);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700968
969 if (inw(ioaddr+EL3_STATUS) == 0xffff) /* No card. */
970 return;
971
972 /* Unlike the 3c509 we need not turn off stats updates while reading. */
973 /* Switch to the stats window, and read everything. */
974 EL3WINDOW(6);
Paulius Zaleckas2e8d31d2008-04-30 01:08:26 +0300975 dev->stats.tx_carrier_errors += inb(ioaddr + 0);
976 dev->stats.tx_heartbeat_errors += inb(ioaddr + 1);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700977 /* Multiple collisions. */ inb(ioaddr + 2);
Paulius Zaleckas2e8d31d2008-04-30 01:08:26 +0300978 dev->stats.collisions += inb(ioaddr + 3);
979 dev->stats.tx_window_errors += inb(ioaddr + 4);
980 dev->stats.rx_fifo_errors += inb(ioaddr + 5);
981 dev->stats.tx_packets += inb(ioaddr + 6);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700982 up = inb(ioaddr + 9);
Paulius Zaleckas2e8d31d2008-04-30 01:08:26 +0300983 dev->stats.tx_packets += (up&0x30) << 4;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700984 /* Rx packets */ inb(ioaddr + 7);
985 /* Tx deferrals */ inb(ioaddr + 8);
986 rx = inw(ioaddr + 10);
987 tx = inw(ioaddr + 12);
988
989 EL3WINDOW(4);
990 /* BadSSD */ inb(ioaddr + 12);
991 up = inb(ioaddr + 13);
992
Linus Torvalds1da177e2005-04-16 15:20:36 -0700993 EL3WINDOW(1);
994}
995
996static int el3_rx(struct net_device *dev, int worklimit)
997{
Olof Johansson906da802008-02-04 22:27:35 -0800998 unsigned int ioaddr = dev->base_addr;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700999 short rx_status;
1000
Dominik Brodowskidd0fab52009-10-24 15:51:05 +02001001 pr_debug("%s: in rx_packet(), status %4.4x, rx_status %4.4x.\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07001002 dev->name, inw(ioaddr+EL3_STATUS), inw(ioaddr+RxStatus));
1003 while (!((rx_status = inw(ioaddr + RxStatus)) & 0x8000) &&
Roel Kluinb9bdcd92009-03-04 00:05:56 -08001004 worklimit > 0) {
1005 worklimit--;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001006 if (rx_status & 0x4000) { /* Error, update stats. */
1007 short error = rx_status & 0x3800;
Paulius Zaleckas2e8d31d2008-04-30 01:08:26 +03001008 dev->stats.rx_errors++;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001009 switch (error) {
Paulius Zaleckas2e8d31d2008-04-30 01:08:26 +03001010 case 0x0000: dev->stats.rx_over_errors++; break;
1011 case 0x0800: dev->stats.rx_length_errors++; break;
1012 case 0x1000: dev->stats.rx_frame_errors++; break;
1013 case 0x1800: dev->stats.rx_length_errors++; break;
1014 case 0x2000: dev->stats.rx_frame_errors++; break;
1015 case 0x2800: dev->stats.rx_crc_errors++; break;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001016 }
1017 } else {
1018 short pkt_len = rx_status & 0x7ff;
1019 struct sk_buff *skb;
1020
1021 skb = dev_alloc_skb(pkt_len+5);
1022
Dominik Brodowskidd0fab52009-10-24 15:51:05 +02001023 pr_debug(" Receiving packet size %d status %4.4x.\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07001024 pkt_len, rx_status);
1025 if (skb != NULL) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001026 skb_reserve(skb, 2);
1027 insl(ioaddr+RX_FIFO, skb_put(skb, pkt_len),
1028 ((pkt_len+3)>>2));
1029 skb->protocol = eth_type_trans(skb, dev);
1030 netif_rx(skb);
Paulius Zaleckas2e8d31d2008-04-30 01:08:26 +03001031 dev->stats.rx_packets++;
1032 dev->stats.rx_bytes += pkt_len;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001033 } else {
Dominik Brodowskidd0fab52009-10-24 15:51:05 +02001034 pr_debug("%s: couldn't allocate a sk_buff of"
Linus Torvalds1da177e2005-04-16 15:20:36 -07001035 " size %d.\n", dev->name, pkt_len);
Paulius Zaleckas2e8d31d2008-04-30 01:08:26 +03001036 dev->stats.rx_dropped++;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001037 }
1038 }
1039 tc574_wait_for_completion(dev, RxDiscard);
1040 }
1041
1042 return worklimit;
1043}
1044
1045static void netdev_get_drvinfo(struct net_device *dev,
1046 struct ethtool_drvinfo *info)
1047{
1048 strcpy(info->driver, "3c574_cs");
1049}
1050
Jeff Garzik7282d492006-09-13 14:30:00 -04001051static const struct ethtool_ops netdev_ethtool_ops = {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001052 .get_drvinfo = netdev_get_drvinfo,
1053};
1054
1055/* Provide ioctl() calls to examine the MII xcvr state. */
1056static int el3_ioctl(struct net_device *dev, struct ifreq *rq, int cmd)
1057{
1058 struct el3_private *lp = netdev_priv(dev);
Olof Johansson906da802008-02-04 22:27:35 -08001059 unsigned int ioaddr = dev->base_addr;
Ben Hutchings0fa0ee052009-09-03 10:41:17 +00001060 struct mii_ioctl_data *data = if_mii(rq);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001061 int phy = lp->phys & 0x1f;
1062
Dominik Brodowskidd0fab52009-10-24 15:51:05 +02001063 pr_debug("%s: In ioct(%-.6s, %#4.4x) %4.4x %4.4x %4.4x %4.4x.\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07001064 dev->name, rq->ifr_ifrn.ifrn_name, cmd,
Ben Hutchings0fa0ee052009-09-03 10:41:17 +00001065 data->phy_id, data->reg_num, data->val_in, data->val_out);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001066
1067 switch(cmd) {
1068 case SIOCGMIIPHY: /* Get the address of the PHY in use. */
Ben Hutchings0fa0ee052009-09-03 10:41:17 +00001069 data->phy_id = phy;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001070 case SIOCGMIIREG: /* Read the specified MII register. */
1071 {
1072 int saved_window;
1073 unsigned long flags;
1074
1075 spin_lock_irqsave(&lp->window_lock, flags);
1076 saved_window = inw(ioaddr + EL3_CMD) >> 13;
1077 EL3WINDOW(4);
Ben Hutchings0fa0ee052009-09-03 10:41:17 +00001078 data->val_out = mdio_read(ioaddr, data->phy_id & 0x1f,
1079 data->reg_num & 0x1f);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001080 EL3WINDOW(saved_window);
1081 spin_unlock_irqrestore(&lp->window_lock, flags);
1082 return 0;
1083 }
1084 case SIOCSMIIREG: /* Write the specified MII register */
1085 {
1086 int saved_window;
1087 unsigned long flags;
1088
Linus Torvalds1da177e2005-04-16 15:20:36 -07001089 spin_lock_irqsave(&lp->window_lock, flags);
1090 saved_window = inw(ioaddr + EL3_CMD) >> 13;
1091 EL3WINDOW(4);
Ben Hutchings0fa0ee052009-09-03 10:41:17 +00001092 mdio_write(ioaddr, data->phy_id & 0x1f,
1093 data->reg_num & 0x1f, data->val_in);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001094 EL3WINDOW(saved_window);
1095 spin_unlock_irqrestore(&lp->window_lock, flags);
1096 return 0;
1097 }
1098 default:
1099 return -EOPNOTSUPP;
1100 }
1101}
1102
1103/* The Odie chip has a 64 bin multicast filter, but the bit layout is not
1104 documented. Until it is we revert to receiving all multicast frames when
1105 any multicast reception is desired.
1106 Note: My other drivers emit a log message whenever promiscuous mode is
1107 entered to help detect password sniffers. This is less desirable on
1108 typical PC card machines, so we omit the message.
1109 */
1110
1111static void set_rx_mode(struct net_device *dev)
1112{
Olof Johansson906da802008-02-04 22:27:35 -08001113 unsigned int ioaddr = dev->base_addr;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001114
1115 if (dev->flags & IFF_PROMISC)
1116 outw(SetRxFilter | RxStation | RxMulticast | RxBroadcast | RxProm,
1117 ioaddr + EL3_CMD);
Jiri Pirko4cd24ea2010-02-08 04:30:35 +00001118 else if (!netdev_mc_empty(dev) || (dev->flags & IFF_ALLMULTI))
Linus Torvalds1da177e2005-04-16 15:20:36 -07001119 outw(SetRxFilter|RxStation|RxMulticast|RxBroadcast, ioaddr + EL3_CMD);
1120 else
1121 outw(SetRxFilter | RxStation | RxBroadcast, ioaddr + EL3_CMD);
1122}
1123
Ken Kawasakie3eef532009-10-13 00:32:55 -07001124static void set_multicast_list(struct net_device *dev)
1125{
1126 struct el3_private *lp = netdev_priv(dev);
1127 unsigned long flags;
1128
1129 spin_lock_irqsave(&lp->window_lock, flags);
1130 set_rx_mode(dev);
1131 spin_unlock_irqrestore(&lp->window_lock, flags);
1132}
1133
Linus Torvalds1da177e2005-04-16 15:20:36 -07001134static int el3_close(struct net_device *dev)
1135{
Olof Johansson906da802008-02-04 22:27:35 -08001136 unsigned int ioaddr = dev->base_addr;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001137 struct el3_private *lp = netdev_priv(dev);
Dominik Brodowskifba395e2006-03-31 17:21:06 +02001138 struct pcmcia_device *link = lp->p_dev;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001139
Dominik Brodowskidd0fab52009-10-24 15:51:05 +02001140 dev_dbg(&link->dev, "%s: shutting down ethercard.\n", dev->name);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001141
Dominik Brodowski9940ec32006-03-05 11:04:33 +01001142 if (pcmcia_dev_present(link)) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001143 unsigned long flags;
1144
1145 /* Turn off statistics ASAP. We update lp->stats below. */
1146 outw(StatsDisable, ioaddr + EL3_CMD);
1147
1148 /* Disable the receiver and transmitter. */
1149 outw(RxDisable, ioaddr + EL3_CMD);
1150 outw(TxDisable, ioaddr + EL3_CMD);
1151
1152 /* Note: Switching to window 0 may disable the IRQ. */
1153 EL3WINDOW(0);
1154 spin_lock_irqsave(&lp->window_lock, flags);
1155 update_stats(dev);
1156 spin_unlock_irqrestore(&lp->window_lock, flags);
Daniel Ritzb9a6eaf2005-04-10 20:27:45 +02001157
1158 /* force interrupts off */
1159 outw(SetIntrEnb | 0x0000, ioaddr + EL3_CMD);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001160 }
1161
1162 link->open--;
1163 netif_stop_queue(dev);
1164 del_timer_sync(&lp->media);
1165
1166 return 0;
1167}
1168
Dominik Brodowski270b6e92005-06-27 16:28:18 -07001169static struct pcmcia_device_id tc574_ids[] = {
1170 PCMCIA_DEVICE_MANF_CARD(0x0101, 0x0574),
Ken Kawasakif0a3a152009-05-01 19:21:26 -07001171 PCMCIA_MFC_DEVICE_CIS_MANF_CARD(0, 0x0101, 0x0556, "cis/3CCFEM556.cis"),
Dominik Brodowski270b6e92005-06-27 16:28:18 -07001172 PCMCIA_DEVICE_NULL,
1173};
1174MODULE_DEVICE_TABLE(pcmcia, tc574_ids);
1175
Linus Torvalds1da177e2005-04-16 15:20:36 -07001176static struct pcmcia_driver tc574_driver = {
1177 .owner = THIS_MODULE,
Dominik Brodowski2e9b9812010-08-08 11:36:26 +02001178 .name = "3c574_cs",
Dominik Brodowski15b99ac2006-03-31 17:26:06 +02001179 .probe = tc574_probe,
Dominik Brodowskicc3b4862005-11-14 21:23:14 +01001180 .remove = tc574_detach,
Dominik Brodowski270b6e92005-06-27 16:28:18 -07001181 .id_table = tc574_ids,
Dominik Brodowski98e4c282005-11-14 21:21:18 +01001182 .suspend = tc574_suspend,
1183 .resume = tc574_resume,
Linus Torvalds1da177e2005-04-16 15:20:36 -07001184};
1185
1186static int __init init_tc574(void)
1187{
1188 return pcmcia_register_driver(&tc574_driver);
1189}
1190
1191static void __exit exit_tc574(void)
1192{
1193 pcmcia_unregister_driver(&tc574_driver);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001194}
1195
1196module_init(init_tc574);
1197module_exit(exit_tc574);