blob: 34195c407fb2a21413cb0974b6a6b698d3e1f0e4 [file] [log] [blame]
Linus Torvalds1da177e2005-04-16 15:20:36 -07001/*======================================================================
2
3 A PCMCIA ethernet driver for the 3com 3c589 card.
Alexander Kurzf64e9692010-03-31 02:42:10 +00004
Linus Torvalds1da177e2005-04-16 15:20:36 -07005 Copyright (C) 1999 David A. Hinds -- dahinds@users.sourceforge.net
6
7 3c589_cs.c 1.162 2001/10/13 00:08:50
8
9 The network driver code is based on Donald Becker's 3c589 code:
Alexander Kurzf64e9692010-03-31 02:42:10 +000010
Linus Torvalds1da177e2005-04-16 15:20:36 -070011 Written 1994 by Donald Becker.
12 Copyright 1993 United States Government as represented by the
13 Director, National Security Agency. This software may be used and
14 distributed according to the terms of the GNU General Public License,
15 incorporated herein by reference.
16 Donald Becker may be reached at becker@scyld.com
Alexander Kurzf64e9692010-03-31 02:42:10 +000017
Alan Cox113aa832008-10-13 19:01:08 -070018 Updated for 2.5.x by Alan Cox <alan@lxorguk.ukuu.org.uk>
Linus Torvalds1da177e2005-04-16 15:20:36 -070019
20======================================================================*/
21
22#define DRV_NAME "3c589_cs"
23#define DRV_VERSION "1.162-ac"
24
25#include <linux/module.h>
26#include <linux/init.h>
27#include <linux/kernel.h>
28#include <linux/ptrace.h>
29#include <linux/slab.h>
30#include <linux/string.h>
31#include <linux/timer.h>
32#include <linux/interrupt.h>
33#include <linux/in.h>
34#include <linux/delay.h>
35#include <linux/ethtool.h>
36#include <linux/netdevice.h>
37#include <linux/etherdevice.h>
38#include <linux/skbuff.h>
39#include <linux/if_arp.h>
40#include <linux/ioport.h>
41#include <linux/bitops.h>
Marcelo Feitoza Parisiff5688a2006-01-09 18:37:15 -080042#include <linux/jiffies.h>
Linus Torvalds1da177e2005-04-16 15:20:36 -070043
Linus Torvalds1da177e2005-04-16 15:20:36 -070044#include <pcmcia/cistpl.h>
45#include <pcmcia/cisreg.h>
46#include <pcmcia/ciscode.h>
47#include <pcmcia/ds.h>
48
49#include <asm/uaccess.h>
50#include <asm/io.h>
51#include <asm/system.h>
52
53/* To minimize the size of the driver source I only define operating
54 constants if they are used several times. You'll need the manual
55 if you want to understand driver details. */
56/* Offsets from base I/O address. */
57#define EL3_DATA 0x00
58#define EL3_TIMER 0x0a
59#define EL3_CMD 0x0e
60#define EL3_STATUS 0x0e
61
62#define EEPROM_READ 0x0080
63#define EEPROM_BUSY 0x8000
64
65#define EL3WINDOW(win_num) outw(SelectWindow + (win_num), ioaddr + EL3_CMD)
66
67/* The top five bits written to EL3_CMD are a command, the lower
68 11 bits are the parameter, if applicable. */
69enum c509cmd {
Alexander Kurzf64e9692010-03-31 02:42:10 +000070 TotalReset = 0<<11,
71 SelectWindow = 1<<11,
72 StartCoax = 2<<11,
73 RxDisable = 3<<11,
74 RxEnable = 4<<11,
75 RxReset = 5<<11,
76 RxDiscard = 8<<11,
77 TxEnable = 9<<11,
78 TxDisable = 10<<11,
79 TxReset = 11<<11,
80 FakeIntr = 12<<11,
81 AckIntr = 13<<11,
82 SetIntrEnb = 14<<11,
83 SetStatusEnb = 15<<11,
84 SetRxFilter = 16<<11,
85 SetRxThreshold = 17<<11,
86 SetTxThreshold = 18<<11,
87 SetTxStart = 19<<11,
88 StatsEnable = 21<<11,
89 StatsDisable = 22<<11,
90 StopCoax = 23<<11
Linus Torvalds1da177e2005-04-16 15:20:36 -070091};
92
93enum c509status {
Alexander Kurzf64e9692010-03-31 02:42:10 +000094 IntLatch = 0x0001,
95 AdapterFailure = 0x0002,
96 TxComplete = 0x0004,
97 TxAvailable = 0x0008,
98 RxComplete = 0x0010,
99 RxEarly = 0x0020,
100 IntReq = 0x0040,
101 StatsFull = 0x0080,
102 CmdBusy = 0x1000
Linus Torvalds1da177e2005-04-16 15:20:36 -0700103};
104
105/* The SetRxFilter command accepts the following classes: */
106enum RxFilter {
Alexander Kurzf64e9692010-03-31 02:42:10 +0000107 RxStation = 1,
108 RxMulticast = 2,
109 RxBroadcast = 4,
110 RxProm = 8
Linus Torvalds1da177e2005-04-16 15:20:36 -0700111};
112
113/* Register window 1 offsets, the window used in normal operation. */
114#define TX_FIFO 0x00
115#define RX_FIFO 0x00
Alexander Kurzf64e9692010-03-31 02:42:10 +0000116#define RX_STATUS 0x08
117#define TX_STATUS 0x0B
Linus Torvalds1da177e2005-04-16 15:20:36 -0700118#define TX_FREE 0x0C /* Remaining free bytes in Tx buffer. */
119
120#define WN0_IRQ 0x08 /* Window 0: Set IRQ line in bits 12-15. */
121#define WN4_MEDIA 0x0A /* Window 4: Various transcvr/media bits. */
122#define MEDIA_TP 0x00C0 /* Enable link beat and jabber for 10baseT. */
123#define MEDIA_LED 0x0001 /* Enable link light on 3C589E cards. */
124
125/* Time in jiffies before concluding Tx hung */
126#define TX_TIMEOUT ((400*HZ)/1000)
127
128struct el3_private {
Dominik Brodowskifd238232006-03-05 10:45:09 +0100129 struct pcmcia_device *p_dev;
Alexander Kurzf64e9692010-03-31 02:42:10 +0000130 /* For transceiver monitoring */
131 struct timer_list media;
132 u16 media_status;
133 u16 fast_poll;
134 unsigned long last_irq;
135 spinlock_t lock;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700136};
137
Jeff Garzik21c0f272007-09-25 00:11:34 -0400138static const char *if_names[] = { "auto", "10baseT", "10base2", "AUI" };
Linus Torvalds1da177e2005-04-16 15:20:36 -0700139
140/*====================================================================*/
141
142/* Module parameters */
143
144MODULE_AUTHOR("David Hinds <dahinds@users.sourceforge.net>");
145MODULE_DESCRIPTION("3Com 3c589 series PCMCIA ethernet driver");
146MODULE_LICENSE("GPL");
147
148#define INT_MODULE_PARM(n, v) static int n = v; module_param(n, int, 0)
149
150/* Special hook for setting if_port when module is loaded */
151INT_MODULE_PARM(if_port, 0);
152
Linus Torvalds1da177e2005-04-16 15:20:36 -0700153
154/*====================================================================*/
155
Dominik Brodowski15b99ac2006-03-31 17:26:06 +0200156static int tc589_config(struct pcmcia_device *link);
Dominik Brodowskifba395e2006-03-31 17:21:06 +0200157static void tc589_release(struct pcmcia_device *link);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700158
Olof Johansson906da802008-02-04 22:27:35 -0800159static u16 read_eeprom(unsigned int ioaddr, int index);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700160static void tc589_reset(struct net_device *dev);
161static void media_check(unsigned long arg);
162static int el3_config(struct net_device *dev, struct ifmap *map);
163static int el3_open(struct net_device *dev);
Stephen Hemmingerdbf02fa2009-08-31 19:50:49 +0000164static netdev_tx_t el3_start_xmit(struct sk_buff *skb,
165 struct net_device *dev);
David Howells7d12e782006-10-05 14:55:46 +0100166static irqreturn_t el3_interrupt(int irq, void *dev_id);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700167static void update_stats(struct net_device *dev);
168static struct net_device_stats *el3_get_stats(struct net_device *dev);
169static int el3_rx(struct net_device *dev);
170static int el3_close(struct net_device *dev);
171static void el3_tx_timeout(struct net_device *dev);
Ken Kawasakie445bb42009-07-19 13:08:12 +0000172static void set_rx_mode(struct net_device *dev);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700173static void set_multicast_list(struct net_device *dev);
Jeff Garzik7282d492006-09-13 14:30:00 -0400174static const struct ethtool_ops netdev_ethtool_ops;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700175
Dominik Brodowskicc3b4862005-11-14 21:23:14 +0100176static void tc589_detach(struct pcmcia_device *p_dev);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700177
Linus Torvalds1da177e2005-04-16 15:20:36 -0700178/*======================================================================
179
180 tc589_attach() creates an "instance" of the driver, allocating
181 local data structures for one device. The device is registered
182 with Card Services.
183
184======================================================================*/
185
Stephen Hemminger97161d42009-03-20 19:36:01 +0000186static const struct net_device_ops el3_netdev_ops = {
Alexander Kurzf64e9692010-03-31 02:42:10 +0000187 .ndo_open = el3_open,
188 .ndo_stop = el3_close,
Stephen Hemminger97161d42009-03-20 19:36:01 +0000189 .ndo_start_xmit = el3_start_xmit,
Alexander Kurzf64e9692010-03-31 02:42:10 +0000190 .ndo_tx_timeout = el3_tx_timeout,
Stephen Hemminger97161d42009-03-20 19:36:01 +0000191 .ndo_set_config = el3_config,
192 .ndo_get_stats = el3_get_stats,
193 .ndo_set_multicast_list = set_multicast_list,
194 .ndo_change_mtu = eth_change_mtu,
Alexander Kurzf64e9692010-03-31 02:42:10 +0000195 .ndo_set_mac_address = eth_mac_addr,
Stephen Hemminger97161d42009-03-20 19:36:01 +0000196 .ndo_validate_addr = eth_validate_addr,
197};
198
Dominik Brodowski15b99ac2006-03-31 17:26:06 +0200199static int tc589_probe(struct pcmcia_device *link)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700200{
201 struct el3_private *lp;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700202 struct net_device *dev;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700203
Dominik Brodowskidd0fab52009-10-24 15:51:05 +0200204 dev_dbg(&link->dev, "3c589_attach()\n");
Dominik Brodowskif8cfa612005-11-14 21:25:51 +0100205
Linus Torvalds1da177e2005-04-16 15:20:36 -0700206 /* Create new ethernet device */
207 dev = alloc_etherdev(sizeof(struct el3_private));
208 if (!dev)
Dominik Brodowskif8cfa612005-11-14 21:25:51 +0100209 return -ENOMEM;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700210 lp = netdev_priv(dev);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700211 link->priv = dev;
Dominik Brodowskifba395e2006-03-31 17:21:06 +0200212 lp->p_dev = link;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700213
214 spin_lock_init(&lp->lock);
Dominik Brodowski90abdc32010-07-24 17:23:51 +0200215 link->resource[0]->end = 16;
216 link->resource[0]->flags |= IO_DATA_PATH_WIDTH_16;
Dominik Brodowskieb141202010-03-07 12:21:16 +0100217
Dominik Brodowski1ac71e52010-07-29 19:27:09 +0200218 link->config_flags |= CONF_ENABLE_IRQ;
Dominik Brodowski7feabb62010-07-29 18:35:47 +0200219 link->config_index = 1;
Dominik Brodowskif8cfa612005-11-14 21:25:51 +0100220
Stephen Hemminger97161d42009-03-20 19:36:01 +0000221 dev->netdev_ops = &el3_netdev_ops;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700222 dev->watchdog_timeo = TX_TIMEOUT;
Stephen Hemminger97161d42009-03-20 19:36:01 +0000223
Linus Torvalds1da177e2005-04-16 15:20:36 -0700224 SET_ETHTOOL_OPS(dev, &netdev_ethtool_ops);
225
Dominik Brodowski15b99ac2006-03-31 17:26:06 +0200226 return tc589_config(link);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700227} /* tc589_attach */
228
229/*======================================================================
230
231 This deletes a driver "instance". The device is de-registered
232 with Card Services. If it has been released, all local data
233 structures are freed. Otherwise, the structures will be freed
234 when the device is released.
235
236======================================================================*/
237
Dominik Brodowskifba395e2006-03-31 17:21:06 +0200238static void tc589_detach(struct pcmcia_device *link)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700239{
240 struct net_device *dev = link->priv;
Dominik Brodowskib4635812005-11-14 21:25:35 +0100241
Dominik Brodowskidd0fab52009-10-24 15:51:05 +0200242 dev_dbg(&link->dev, "3c589_detach\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -0700243
Dominik Brodowskic7c2fa02010-03-20 19:39:26 +0100244 unregister_netdev(dev);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700245
Dominik Brodowskie2d40962006-03-02 00:09:29 +0100246 tc589_release(link);
Dominik Brodowskicc3b4862005-11-14 21:23:14 +0100247
Linus Torvalds1da177e2005-04-16 15:20:36 -0700248 free_netdev(dev);
249} /* tc589_detach */
250
251/*======================================================================
252
253 tc589_config() is scheduled to run after a CARD_INSERTION event
254 is received, to configure the PCMCIA socket, and to make the
255 ethernet device available to the system.
Alexander Kurzf64e9692010-03-31 02:42:10 +0000256
Linus Torvalds1da177e2005-04-16 15:20:36 -0700257======================================================================*/
258
Dominik Brodowski15b99ac2006-03-31 17:26:06 +0200259static int tc589_config(struct pcmcia_device *link)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700260{
Linus Torvalds1da177e2005-04-16 15:20:36 -0700261 struct net_device *dev = link->priv;
Al Virob1e247a2007-12-22 18:56:13 +0000262 __be16 *phys_addr;
Dominik Brodowskidd0fab52009-10-24 15:51:05 +0200263 int ret, i, j, multi = 0, fifo;
Olof Johansson906da802008-02-04 22:27:35 -0800264 unsigned int ioaddr;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700265 char *ram_split[] = {"5:3", "3:1", "1:1", "3:5"};
Dominik Brodowskidddfbd82009-10-18 23:54:24 +0200266 u8 *buf;
267 size_t len;
Alexander Kurzf64e9692010-03-31 02:42:10 +0000268
Dominik Brodowskidd0fab52009-10-24 15:51:05 +0200269 dev_dbg(&link->dev, "3c589_config\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -0700270
Al Virob1e247a2007-12-22 18:56:13 +0000271 phys_addr = (__be16 *)dev->dev_addr;
Dominik Brodowskiefd50582006-10-25 21:28:53 -0400272 /* Is this a 3c562? */
273 if (link->manf_id != MANFID_3COM)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700274 printk(KERN_INFO "3c589_cs: hmmm, is this really a "
275 "3Com card??\n");
Dominik Brodowskiefd50582006-10-25 21:28:53 -0400276 multi = (link->card_id == PRODID_3COM_3C562);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700277
Dominik Brodowski90abdc32010-07-24 17:23:51 +0200278 link->io_lines = 16;
279
Linus Torvalds1da177e2005-04-16 15:20:36 -0700280 /* For the 3c562, the base address must be xx00-xx7f */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700281 for (i = j = 0; j < 0x400; j += 0x10) {
282 if (multi && (j & 0x80)) continue;
Dominik Brodowski90abdc32010-07-24 17:23:51 +0200283 link->resource[0]->start = j ^ 0x300;
284 i = pcmcia_request_io(link);
Dominik Brodowski4c89e882008-08-03 10:07:45 +0200285 if (i == 0)
286 break;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700287 }
Dominik Brodowskidd0fab52009-10-24 15:51:05 +0200288 if (i != 0)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700289 goto failed;
Dominik Brodowskidd0fab52009-10-24 15:51:05 +0200290
Dominik Brodowskieb141202010-03-07 12:21:16 +0100291 ret = pcmcia_request_irq(link, el3_interrupt);
Dominik Brodowskidd0fab52009-10-24 15:51:05 +0200292 if (ret)
293 goto failed;
294
Dominik Brodowski1ac71e52010-07-29 19:27:09 +0200295 ret = pcmcia_enable_device(link);
Dominik Brodowskidd0fab52009-10-24 15:51:05 +0200296 if (ret)
297 goto failed;
Alexander Kurzf64e9692010-03-31 02:42:10 +0000298
Dominik Brodowskieb141202010-03-07 12:21:16 +0100299 dev->irq = link->irq;
Dominik Brodowski9a017a92010-07-24 15:58:54 +0200300 dev->base_addr = link->resource[0]->start;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700301 ioaddr = dev->base_addr;
302 EL3WINDOW(0);
303
304 /* The 3c589 has an extra EEPROM for configuration info, including
305 the hardware address. The 3c562 puts the address in the CIS. */
Dominik Brodowskidddfbd82009-10-18 23:54:24 +0200306 len = pcmcia_get_tuple(link, 0x88, &buf);
307 if (buf && len >= 6) {
308 for (i = 0; i < 3; i++)
309 phys_addr[i] = htons(le16_to_cpu(buf[i*2]));
310 kfree(buf);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700311 } else {
Dominik Brodowskidddfbd82009-10-18 23:54:24 +0200312 kfree(buf); /* 0 < len < 6 */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700313 for (i = 0; i < 3; i++)
314 phys_addr[i] = htons(read_eeprom(ioaddr, i));
Al Virob1e247a2007-12-22 18:56:13 +0000315 if (phys_addr[0] == htons(0x6060)) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700316 printk(KERN_ERR "3c589_cs: IO port conflict at 0x%03lx"
317 "-0x%03lx\n", dev->base_addr, dev->base_addr+15);
318 goto failed;
319 }
320 }
321
322 /* The address and resource configuration register aren't loaded from
323 the EEPROM and *must* be set to 0 and IRQ3 for the PCMCIA version. */
324 outw(0x3f00, ioaddr + 8);
325 fifo = inl(ioaddr);
326
327 /* The if_port symbol can be set when the module is loaded */
328 if ((if_port >= 0) && (if_port <= 3))
329 dev->if_port = if_port;
330 else
331 printk(KERN_ERR "3c589_cs: invalid if_port requested\n");
Alexander Kurzf64e9692010-03-31 02:42:10 +0000332
Dominik Brodowskidd2e5a12009-11-03 10:27:34 +0100333 SET_NETDEV_DEV(dev, &link->dev);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700334
335 if (register_netdev(dev) != 0) {
336 printk(KERN_ERR "3c589_cs: register_netdev() failed\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -0700337 goto failed;
338 }
339
Alexander Kurzf64e9692010-03-31 02:42:10 +0000340 netdev_info(dev, "3Com 3c%s, io %#3lx, irq %d, hw_addr %pM\n",
341 (multi ? "562" : "589"), dev->base_addr, dev->irq,
342 dev->dev_addr);
343 netdev_info(dev, " %dK FIFO split %s Rx:Tx, %s xcvr\n",
344 (fifo & 7) ? 32 : 8, ram_split[(fifo >> 16) & 3],
345 if_names[dev->if_port]);
Dominik Brodowski15b99ac2006-03-31 17:26:06 +0200346 return 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700347
Linus Torvalds1da177e2005-04-16 15:20:36 -0700348failed:
349 tc589_release(link);
Dominik Brodowski15b99ac2006-03-31 17:26:06 +0200350 return -ENODEV;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700351} /* tc589_config */
352
353/*======================================================================
354
355 After a card is removed, tc589_release() will unregister the net
356 device, and release the PCMCIA configuration. If the device is
357 still open, this will be postponed until it is closed.
Alexander Kurzf64e9692010-03-31 02:42:10 +0000358
Linus Torvalds1da177e2005-04-16 15:20:36 -0700359======================================================================*/
360
Dominik Brodowskifba395e2006-03-31 17:21:06 +0200361static void tc589_release(struct pcmcia_device *link)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700362{
Dominik Brodowskifba395e2006-03-31 17:21:06 +0200363 pcmcia_disable_device(link);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700364}
365
Dominik Brodowskifba395e2006-03-31 17:21:06 +0200366static int tc589_suspend(struct pcmcia_device *link)
Dominik Brodowski98e4c282005-11-14 21:21:18 +0100367{
Dominik Brodowski98e4c282005-11-14 21:21:18 +0100368 struct net_device *dev = link->priv;
369
Dominik Brodowskie2d40962006-03-02 00:09:29 +0100370 if (link->open)
Dominik Brodowski8661bb52006-03-02 00:02:33 +0100371 netif_device_detach(dev);
Dominik Brodowski98e4c282005-11-14 21:21:18 +0100372
373 return 0;
374}
375
Dominik Brodowskifba395e2006-03-31 17:21:06 +0200376static int tc589_resume(struct pcmcia_device *link)
Dominik Brodowski98e4c282005-11-14 21:21:18 +0100377{
Dominik Brodowski98e4c282005-11-14 21:21:18 +0100378 struct net_device *dev = link->priv;
379
Alexander Kurzf64e9692010-03-31 02:42:10 +0000380 if (link->open) {
Dominik Brodowski8661bb52006-03-02 00:02:33 +0100381 tc589_reset(dev);
382 netif_device_attach(dev);
Dominik Brodowski98e4c282005-11-14 21:21:18 +0100383 }
384
385 return 0;
386}
387
Linus Torvalds1da177e2005-04-16 15:20:36 -0700388/*====================================================================*/
389
390/*
391 Use this for commands that may take time to finish
392*/
393static void tc589_wait_for_completion(struct net_device *dev, int cmd)
394{
395 int i = 100;
396 outw(cmd, dev->base_addr + EL3_CMD);
397 while (--i > 0)
398 if (!(inw(dev->base_addr + EL3_STATUS) & 0x1000)) break;
399 if (i == 0)
Alexander Kurzf64e9692010-03-31 02:42:10 +0000400 netdev_warn(dev, "command 0x%04x did not complete!\n", cmd);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700401}
402
403/*
404 Read a word from the EEPROM using the regular EEPROM access register.
405 Assume that we are in register window zero.
406*/
Olof Johansson906da802008-02-04 22:27:35 -0800407static u16 read_eeprom(unsigned int ioaddr, int index)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700408{
409 int i;
410 outw(EEPROM_READ + index, ioaddr + 10);
411 /* Reading the eeprom takes 162 us */
412 for (i = 1620; i >= 0; i--)
413 if ((inw(ioaddr + 10) & EEPROM_BUSY) == 0)
414 break;
415 return inw(ioaddr + 12);
416}
417
418/*
419 Set transceiver type, perhaps to something other than what the user
420 specified in dev->if_port.
421*/
422static void tc589_set_xcvr(struct net_device *dev, int if_port)
423{
424 struct el3_private *lp = netdev_priv(dev);
Olof Johansson906da802008-02-04 22:27:35 -0800425 unsigned int ioaddr = dev->base_addr;
Alexander Kurzf64e9692010-03-31 02:42:10 +0000426
Linus Torvalds1da177e2005-04-16 15:20:36 -0700427 EL3WINDOW(0);
428 switch (if_port) {
429 case 0: case 1: outw(0, ioaddr + 6); break;
430 case 2: outw(3<<14, ioaddr + 6); break;
431 case 3: outw(1<<14, ioaddr + 6); break;
432 }
433 /* On PCMCIA, this just turns on the LED */
434 outw((if_port == 2) ? StartCoax : StopCoax, ioaddr + EL3_CMD);
435 /* 10baseT interface, enable link beat and jabber check. */
436 EL3WINDOW(4);
437 outw(MEDIA_LED | ((if_port < 2) ? MEDIA_TP : 0), ioaddr + WN4_MEDIA);
438 EL3WINDOW(1);
439 if (if_port == 2)
440 lp->media_status = ((dev->if_port == 0) ? 0x8000 : 0x4000);
441 else
442 lp->media_status = ((dev->if_port == 0) ? 0x4010 : 0x8800);
443}
444
445static void dump_status(struct net_device *dev)
446{
Olof Johansson906da802008-02-04 22:27:35 -0800447 unsigned int ioaddr = dev->base_addr;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700448 EL3WINDOW(1);
Alexander Kurzf64e9692010-03-31 02:42:10 +0000449 netdev_info(dev, " irq status %04x, rx status %04x, tx status %02x tx free %04x\n",
450 inw(ioaddr+EL3_STATUS), inw(ioaddr+RX_STATUS),
451 inb(ioaddr+TX_STATUS), inw(ioaddr+TX_FREE));
Linus Torvalds1da177e2005-04-16 15:20:36 -0700452 EL3WINDOW(4);
Alexander Kurzf64e9692010-03-31 02:42:10 +0000453 netdev_info(dev, " diagnostics: fifo %04x net %04x ethernet %04x media %04x\n",
454 inw(ioaddr+0x04), inw(ioaddr+0x06), inw(ioaddr+0x08),
455 inw(ioaddr+0x0a));
Linus Torvalds1da177e2005-04-16 15:20:36 -0700456 EL3WINDOW(1);
457}
458
459/* Reset and restore all of the 3c589 registers. */
460static void tc589_reset(struct net_device *dev)
461{
Olof Johansson906da802008-02-04 22:27:35 -0800462 unsigned int ioaddr = dev->base_addr;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700463 int i;
Alexander Kurzf64e9692010-03-31 02:42:10 +0000464
Linus Torvalds1da177e2005-04-16 15:20:36 -0700465 EL3WINDOW(0);
Alexander Kurzf64e9692010-03-31 02:42:10 +0000466 outw(0x0001, ioaddr + 4); /* Activate board. */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700467 outw(0x3f00, ioaddr + 8); /* Set the IRQ line. */
Alexander Kurzf64e9692010-03-31 02:42:10 +0000468
Linus Torvalds1da177e2005-04-16 15:20:36 -0700469 /* Set the station address in window 2. */
470 EL3WINDOW(2);
471 for (i = 0; i < 6; i++)
472 outb(dev->dev_addr[i], ioaddr + i);
473
474 tc589_set_xcvr(dev, dev->if_port);
Alexander Kurzf64e9692010-03-31 02:42:10 +0000475
Linus Torvalds1da177e2005-04-16 15:20:36 -0700476 /* Switch to the stats window, and clear all stats by reading. */
477 outw(StatsDisable, ioaddr + EL3_CMD);
478 EL3WINDOW(6);
479 for (i = 0; i < 9; i++)
480 inb(ioaddr+i);
481 inw(ioaddr + 10);
482 inw(ioaddr + 12);
Alexander Kurzf64e9692010-03-31 02:42:10 +0000483
Linus Torvalds1da177e2005-04-16 15:20:36 -0700484 /* Switch to register set 1 for normal use. */
485 EL3WINDOW(1);
486
Ken Kawasakie445bb42009-07-19 13:08:12 +0000487 set_rx_mode(dev);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700488 outw(StatsEnable, ioaddr + EL3_CMD); /* Turn on statistics. */
489 outw(RxEnable, ioaddr + EL3_CMD); /* Enable the receiver. */
490 outw(TxEnable, ioaddr + EL3_CMD); /* Enable transmitter. */
491 /* Allow status bits to be seen. */
492 outw(SetStatusEnb | 0xff, ioaddr + EL3_CMD);
493 /* Ack all pending events, and set active indicator mask. */
494 outw(AckIntr | IntLatch | TxAvailable | RxEarly | IntReq,
495 ioaddr + EL3_CMD);
496 outw(SetIntrEnb | IntLatch | TxAvailable | RxComplete | StatsFull
497 | AdapterFailure, ioaddr + EL3_CMD);
498}
499
500static void netdev_get_drvinfo(struct net_device *dev,
501 struct ethtool_drvinfo *info)
502{
503 strcpy(info->driver, DRV_NAME);
504 strcpy(info->version, DRV_VERSION);
505 sprintf(info->bus_info, "PCMCIA 0x%lx", dev->base_addr);
506}
507
Jeff Garzik7282d492006-09-13 14:30:00 -0400508static const struct ethtool_ops netdev_ethtool_ops = {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700509 .get_drvinfo = netdev_get_drvinfo,
Linus Torvalds1da177e2005-04-16 15:20:36 -0700510};
511
512static int el3_config(struct net_device *dev, struct ifmap *map)
513{
514 if ((map->port != (u_char)(-1)) && (map->port != dev->if_port)) {
515 if (map->port <= 3) {
516 dev->if_port = map->port;
Alexander Kurzf64e9692010-03-31 02:42:10 +0000517 netdev_info(dev, "switched to %s port\n", if_names[dev->if_port]);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700518 tc589_set_xcvr(dev, dev->if_port);
519 } else
520 return -EINVAL;
521 }
522 return 0;
523}
524
525static int el3_open(struct net_device *dev)
526{
527 struct el3_private *lp = netdev_priv(dev);
Dominik Brodowskifba395e2006-03-31 17:21:06 +0200528 struct pcmcia_device *link = lp->p_dev;
Alexander Kurzf64e9692010-03-31 02:42:10 +0000529
Dominik Brodowski9940ec32006-03-05 11:04:33 +0100530 if (!pcmcia_dev_present(link))
Linus Torvalds1da177e2005-04-16 15:20:36 -0700531 return -ENODEV;
532
533 link->open++;
534 netif_start_queue(dev);
Alexander Kurzf64e9692010-03-31 02:42:10 +0000535
Linus Torvalds1da177e2005-04-16 15:20:36 -0700536 tc589_reset(dev);
537 init_timer(&lp->media);
538 lp->media.function = &media_check;
539 lp->media.data = (unsigned long) dev;
540 lp->media.expires = jiffies + HZ;
541 add_timer(&lp->media);
542
Dominik Brodowskidd0fab52009-10-24 15:51:05 +0200543 dev_dbg(&link->dev, "%s: opened, status %4.4x.\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -0700544 dev->name, inw(dev->base_addr + EL3_STATUS));
Alexander Kurzf64e9692010-03-31 02:42:10 +0000545
Linus Torvalds1da177e2005-04-16 15:20:36 -0700546 return 0;
547}
548
549static void el3_tx_timeout(struct net_device *dev)
550{
Olof Johansson906da802008-02-04 22:27:35 -0800551 unsigned int ioaddr = dev->base_addr;
Alexander Kurzf64e9692010-03-31 02:42:10 +0000552
553 netdev_warn(dev, "Transmit timed out!\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -0700554 dump_status(dev);
Paulius Zaleckascd652842008-04-30 01:20:20 +0300555 dev->stats.tx_errors++;
Eric Dumazet1ae5dc32010-05-10 05:01:31 -0700556 dev->trans_start = jiffies; /* prevent tx timeout */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700557 /* Issue TX_RESET and TX_START commands. */
558 tc589_wait_for_completion(dev, TxReset);
559 outw(TxEnable, ioaddr + EL3_CMD);
560 netif_wake_queue(dev);
561}
562
563static void pop_tx_status(struct net_device *dev)
564{
Olof Johansson906da802008-02-04 22:27:35 -0800565 unsigned int ioaddr = dev->base_addr;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700566 int i;
Alexander Kurzf64e9692010-03-31 02:42:10 +0000567
Linus Torvalds1da177e2005-04-16 15:20:36 -0700568 /* Clear the Tx status stack. */
569 for (i = 32; i > 0; i--) {
570 u_char tx_status = inb(ioaddr + TX_STATUS);
571 if (!(tx_status & 0x84)) break;
572 /* reset transmitter on jabber error or underrun */
573 if (tx_status & 0x30)
Alexander Kurzf64e9692010-03-31 02:42:10 +0000574 tc589_wait_for_completion(dev, TxReset);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700575 if (tx_status & 0x38) {
Alexander Kurzf64e9692010-03-31 02:42:10 +0000576 netdev_dbg(dev, "transmit error: status 0x%02x\n", tx_status);
577 outw(TxEnable, ioaddr + EL3_CMD);
578 dev->stats.tx_aborted_errors++;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700579 }
580 outb(0x00, ioaddr + TX_STATUS); /* Pop the status stack. */
581 }
582}
583
Stephen Hemmingerdbf02fa2009-08-31 19:50:49 +0000584static netdev_tx_t el3_start_xmit(struct sk_buff *skb,
585 struct net_device *dev)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700586{
Olof Johansson906da802008-02-04 22:27:35 -0800587 unsigned int ioaddr = dev->base_addr;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700588 struct el3_private *priv = netdev_priv(dev);
Komurod08d2832006-12-02 11:53:27 +0900589 unsigned long flags;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700590
Alexander Kurzf64e9692010-03-31 02:42:10 +0000591 netdev_dbg(dev, "el3_start_xmit(length = %ld) called, status %4.4x.\n",
592 (long)skb->len, inw(ioaddr + EL3_STATUS));
Linus Torvalds1da177e2005-04-16 15:20:36 -0700593
Alexander Kurzf64e9692010-03-31 02:42:10 +0000594 spin_lock_irqsave(&priv->lock, flags);
Komurod08d2832006-12-02 11:53:27 +0900595
Paulius Zaleckascd652842008-04-30 01:20:20 +0300596 dev->stats.tx_bytes += skb->len;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700597
598 /* Put out the doubleword header... */
599 outw(skb->len, ioaddr + TX_FIFO);
600 outw(0x00, ioaddr + TX_FIFO);
601 /* ... and the packet rounded to a doubleword. */
602 outsl(ioaddr + TX_FIFO, skb->data, (skb->len + 3) >> 2);
603
Linus Torvalds1da177e2005-04-16 15:20:36 -0700604 if (inw(ioaddr + TX_FREE) <= 1536) {
605 netif_stop_queue(dev);
606 /* Interrupt us when the FIFO has room for max-sized packet. */
607 outw(SetTxThreshold + 1536, ioaddr + EL3_CMD);
608 }
609
Linus Torvalds1da177e2005-04-16 15:20:36 -0700610 pop_tx_status(dev);
Alexander Kurzf64e9692010-03-31 02:42:10 +0000611 spin_unlock_irqrestore(&priv->lock, flags);
Patrick McHardy63ac9b92007-07-02 16:08:28 +0200612 dev_kfree_skb(skb);
Alexander Kurzf64e9692010-03-31 02:42:10 +0000613
Patrick McHardy6ed10652009-06-23 06:03:08 +0000614 return NETDEV_TX_OK;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700615}
616
617/* The EL3 interrupt handler. */
David Howells7d12e782006-10-05 14:55:46 +0100618static irqreturn_t el3_interrupt(int irq, void *dev_id)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700619{
620 struct net_device *dev = (struct net_device *) dev_id;
621 struct el3_private *lp = netdev_priv(dev);
Olof Johansson906da802008-02-04 22:27:35 -0800622 unsigned int ioaddr;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700623 __u16 status;
624 int i = 0, handled = 1;
Alexander Kurzf64e9692010-03-31 02:42:10 +0000625
Linus Torvalds1da177e2005-04-16 15:20:36 -0700626 if (!netif_device_present(dev))
627 return IRQ_NONE;
628
629 ioaddr = dev->base_addr;
630
Alexander Kurzf64e9692010-03-31 02:42:10 +0000631 netdev_dbg(dev, "interrupt, status %4.4x.\n", inw(ioaddr + EL3_STATUS));
Linus Torvalds1da177e2005-04-16 15:20:36 -0700632
Alexander Kurzf64e9692010-03-31 02:42:10 +0000633 spin_lock(&lp->lock);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700634 while ((status = inw(ioaddr + EL3_STATUS)) &
635 (IntLatch | RxComplete | StatsFull)) {
636 if ((status & 0xe000) != 0x2000) {
Alexander Kurzf64e9692010-03-31 02:42:10 +0000637 netdev_dbg(dev, "interrupt from dead card\n");
638 handled = 0;
639 break;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700640 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700641 if (status & RxComplete)
Alexander Kurzf64e9692010-03-31 02:42:10 +0000642 el3_rx(dev);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700643 if (status & TxAvailable) {
Alexander Kurzf64e9692010-03-31 02:42:10 +0000644 netdev_dbg(dev, " TX room bit was handled.\n");
645 /* There's room in the FIFO for a full-sized packet. */
646 outw(AckIntr | TxAvailable, ioaddr + EL3_CMD);
647 netif_wake_queue(dev);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700648 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700649 if (status & TxComplete)
Alexander Kurzf64e9692010-03-31 02:42:10 +0000650 pop_tx_status(dev);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700651 if (status & (AdapterFailure | RxEarly | StatsFull)) {
652 /* Handle all uncommon interrupts. */
653 if (status & StatsFull) /* Empty statistics. */
654 update_stats(dev);
655 if (status & RxEarly) { /* Rx early is unused. */
656 el3_rx(dev);
657 outw(AckIntr | RxEarly, ioaddr + EL3_CMD);
658 }
659 if (status & AdapterFailure) {
660 u16 fifo_diag;
661 EL3WINDOW(4);
662 fifo_diag = inw(ioaddr + 4);
663 EL3WINDOW(1);
Alexander Kurzf64e9692010-03-31 02:42:10 +0000664 netdev_warn(dev, "adapter failure, FIFO diagnostic register %04x.\n",
665 fifo_diag);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700666 if (fifo_diag & 0x0400) {
667 /* Tx overrun */
668 tc589_wait_for_completion(dev, TxReset);
669 outw(TxEnable, ioaddr + EL3_CMD);
670 }
671 if (fifo_diag & 0x2000) {
672 /* Rx underrun */
673 tc589_wait_for_completion(dev, RxReset);
Ken Kawasakie445bb42009-07-19 13:08:12 +0000674 set_rx_mode(dev);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700675 outw(RxEnable, ioaddr + EL3_CMD);
676 }
677 outw(AckIntr | AdapterFailure, ioaddr + EL3_CMD);
678 }
679 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700680 if (++i > 10) {
Alexander Kurzf64e9692010-03-31 02:42:10 +0000681 netdev_err(dev, "infinite loop in interrupt, status %4.4x.\n",
682 status);
683 /* Clear all interrupts */
684 outw(AckIntr | 0xFF, ioaddr + EL3_CMD);
685 break;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700686 }
687 /* Acknowledge the IRQ. */
688 outw(AckIntr | IntReq | IntLatch, ioaddr + EL3_CMD);
689 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700690 lp->last_irq = jiffies;
Alexander Kurzf64e9692010-03-31 02:42:10 +0000691 spin_unlock(&lp->lock);
692 netdev_dbg(dev, "exiting interrupt, status %4.4x.\n",
693 inw(ioaddr + EL3_STATUS));
Linus Torvalds1da177e2005-04-16 15:20:36 -0700694 return IRQ_RETVAL(handled);
695}
696
697static void media_check(unsigned long arg)
698{
699 struct net_device *dev = (struct net_device *)(arg);
700 struct el3_private *lp = netdev_priv(dev);
Olof Johansson906da802008-02-04 22:27:35 -0800701 unsigned int ioaddr = dev->base_addr;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700702 u16 media, errs;
703 unsigned long flags;
704
705 if (!netif_device_present(dev)) goto reschedule;
706
Linus Torvalds1da177e2005-04-16 15:20:36 -0700707 /* Check for pending interrupt with expired latency timer: with
708 this, we can limp along even if the interrupt is blocked */
709 if ((inw(ioaddr + EL3_STATUS) & IntLatch) &&
710 (inb(ioaddr + EL3_TIMER) == 0xff)) {
711 if (!lp->fast_poll)
Alexander Kurzf64e9692010-03-31 02:42:10 +0000712 netdev_warn(dev, "interrupt(s) dropped!\n");
Ken Kawasaki671c8802009-12-12 14:44:11 +0000713
714 local_irq_save(flags);
Komurod08d2832006-12-02 11:53:27 +0900715 el3_interrupt(dev->irq, dev);
Ken Kawasaki671c8802009-12-12 14:44:11 +0000716 local_irq_restore(flags);
717
Linus Torvalds1da177e2005-04-16 15:20:36 -0700718 lp->fast_poll = HZ;
719 }
720 if (lp->fast_poll) {
721 lp->fast_poll--;
722 lp->media.expires = jiffies + HZ/100;
723 add_timer(&lp->media);
724 return;
725 }
726
727 /* lp->lock guards the EL3 window. Window should always be 1 except
728 when the lock is held */
Alexander Kurzf64e9692010-03-31 02:42:10 +0000729 spin_lock_irqsave(&lp->lock, flags);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700730 EL3WINDOW(4);
731 media = inw(ioaddr+WN4_MEDIA) & 0xc810;
732
733 /* Ignore collisions unless we've had no irq's recently */
Marcelo Feitoza Parisiff5688a2006-01-09 18:37:15 -0800734 if (time_before(jiffies, lp->last_irq + HZ)) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700735 media &= ~0x0010;
736 } else {
737 /* Try harder to detect carrier errors */
738 EL3WINDOW(6);
739 outw(StatsDisable, ioaddr + EL3_CMD);
740 errs = inb(ioaddr + 0);
741 outw(StatsEnable, ioaddr + EL3_CMD);
Paulius Zaleckascd652842008-04-30 01:20:20 +0300742 dev->stats.tx_carrier_errors += errs;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700743 if (errs || (lp->media_status & 0x0010)) media |= 0x0010;
744 }
745
746 if (media != lp->media_status) {
747 if ((media & lp->media_status & 0x8000) &&
748 ((lp->media_status ^ media) & 0x0800))
Alexander Kurzf64e9692010-03-31 02:42:10 +0000749 netdev_info(dev, "%s link beat\n",
750 (lp->media_status & 0x0800 ? "lost" : "found"));
Linus Torvalds1da177e2005-04-16 15:20:36 -0700751 else if ((media & lp->media_status & 0x4000) &&
752 ((lp->media_status ^ media) & 0x0010))
Alexander Kurzf64e9692010-03-31 02:42:10 +0000753 netdev_info(dev, "coax cable %s\n",
754 (lp->media_status & 0x0010 ? "ok" : "problem"));
Linus Torvalds1da177e2005-04-16 15:20:36 -0700755 if (dev->if_port == 0) {
756 if (media & 0x8000) {
757 if (media & 0x0800)
Alexander Kurzf64e9692010-03-31 02:42:10 +0000758 netdev_info(dev, "flipped to 10baseT\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -0700759 else
Alexander Kurzf64e9692010-03-31 02:42:10 +0000760 tc589_set_xcvr(dev, 2);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700761 } else if (media & 0x4000) {
762 if (media & 0x0010)
763 tc589_set_xcvr(dev, 1);
764 else
Alexander Kurzf64e9692010-03-31 02:42:10 +0000765 netdev_info(dev, "flipped to 10base2\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -0700766 }
767 }
768 lp->media_status = media;
769 }
Alexander Kurzf64e9692010-03-31 02:42:10 +0000770
Linus Torvalds1da177e2005-04-16 15:20:36 -0700771 EL3WINDOW(1);
Alexander Kurzf64e9692010-03-31 02:42:10 +0000772 spin_unlock_irqrestore(&lp->lock, flags);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700773
774reschedule:
775 lp->media.expires = jiffies + HZ;
776 add_timer(&lp->media);
777}
778
779static struct net_device_stats *el3_get_stats(struct net_device *dev)
780{
781 struct el3_private *lp = netdev_priv(dev);
782 unsigned long flags;
Dominik Brodowskifba395e2006-03-31 17:21:06 +0200783 struct pcmcia_device *link = lp->p_dev;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700784
Dominik Brodowski9940ec32006-03-05 11:04:33 +0100785 if (pcmcia_dev_present(link)) {
Alexander Kurzf64e9692010-03-31 02:42:10 +0000786 spin_lock_irqsave(&lp->lock, flags);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700787 update_stats(dev);
788 spin_unlock_irqrestore(&lp->lock, flags);
789 }
Paulius Zaleckascd652842008-04-30 01:20:20 +0300790 return &dev->stats;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700791}
792
793/*
794 Update statistics. We change to register window 6, so this should be run
795 single-threaded if the device is active. This is expected to be a rare
796 operation, and it's simpler for the rest of the driver to assume that
797 window 1 is always valid rather than use a special window-state variable.
Alexander Kurzf64e9692010-03-31 02:42:10 +0000798
Linus Torvalds1da177e2005-04-16 15:20:36 -0700799 Caller must hold the lock for this
800*/
801static void update_stats(struct net_device *dev)
802{
Olof Johansson906da802008-02-04 22:27:35 -0800803 unsigned int ioaddr = dev->base_addr;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700804
Alexander Kurzf64e9692010-03-31 02:42:10 +0000805 netdev_dbg(dev, "updating the statistics.\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -0700806 /* Turn off statistics updates while reading. */
807 outw(StatsDisable, ioaddr + EL3_CMD);
808 /* Switch to the stats window, and read everything. */
809 EL3WINDOW(6);
Alexander Kurzf64e9692010-03-31 02:42:10 +0000810 dev->stats.tx_carrier_errors += inb(ioaddr + 0);
Paulius Zaleckascd652842008-04-30 01:20:20 +0300811 dev->stats.tx_heartbeat_errors += inb(ioaddr + 1);
Alexander Kurzf64e9692010-03-31 02:42:10 +0000812 /* Multiple collisions. */ inb(ioaddr + 2);
Paulius Zaleckascd652842008-04-30 01:20:20 +0300813 dev->stats.collisions += inb(ioaddr + 3);
814 dev->stats.tx_window_errors += inb(ioaddr + 4);
815 dev->stats.rx_fifo_errors += inb(ioaddr + 5);
816 dev->stats.tx_packets += inb(ioaddr + 6);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700817 /* Rx packets */ inb(ioaddr + 7);
818 /* Tx deferrals */ inb(ioaddr + 8);
819 /* Rx octets */ inw(ioaddr + 10);
820 /* Tx octets */ inw(ioaddr + 12);
Alexander Kurzf64e9692010-03-31 02:42:10 +0000821
Linus Torvalds1da177e2005-04-16 15:20:36 -0700822 /* Back to window 1, and turn statistics back on. */
823 EL3WINDOW(1);
824 outw(StatsEnable, ioaddr + EL3_CMD);
825}
826
827static int el3_rx(struct net_device *dev)
828{
Olof Johansson906da802008-02-04 22:27:35 -0800829 unsigned int ioaddr = dev->base_addr;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700830 int worklimit = 32;
831 short rx_status;
Alexander Kurzf64e9692010-03-31 02:42:10 +0000832
833 netdev_dbg(dev, "in rx_packet(), status %4.4x, rx_status %4.4x.\n",
834 inw(ioaddr+EL3_STATUS), inw(ioaddr+RX_STATUS));
Linus Torvalds1da177e2005-04-16 15:20:36 -0700835 while (!((rx_status = inw(ioaddr + RX_STATUS)) & 0x8000) &&
Roel Kluinb9bdcd92009-03-04 00:05:56 -0800836 worklimit > 0) {
837 worklimit--;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700838 if (rx_status & 0x4000) { /* Error, update stats. */
839 short error = rx_status & 0x3800;
Paulius Zaleckascd652842008-04-30 01:20:20 +0300840 dev->stats.rx_errors++;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700841 switch (error) {
Paulius Zaleckascd652842008-04-30 01:20:20 +0300842 case 0x0000: dev->stats.rx_over_errors++; break;
843 case 0x0800: dev->stats.rx_length_errors++; break;
844 case 0x1000: dev->stats.rx_frame_errors++; break;
845 case 0x1800: dev->stats.rx_length_errors++; break;
846 case 0x2000: dev->stats.rx_frame_errors++; break;
847 case 0x2800: dev->stats.rx_crc_errors++; break;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700848 }
849 } else {
850 short pkt_len = rx_status & 0x7ff;
851 struct sk_buff *skb;
Alexander Kurzf64e9692010-03-31 02:42:10 +0000852
Linus Torvalds1da177e2005-04-16 15:20:36 -0700853 skb = dev_alloc_skb(pkt_len+5);
Alexander Kurzf64e9692010-03-31 02:42:10 +0000854
855 netdev_dbg(dev, " Receiving packet size %d status %4.4x.\n",
856 pkt_len, rx_status);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700857 if (skb != NULL) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700858 skb_reserve(skb, 2);
859 insl(ioaddr+RX_FIFO, skb_put(skb, pkt_len),
860 (pkt_len+3)>>2);
861 skb->protocol = eth_type_trans(skb, dev);
862 netif_rx(skb);
Paulius Zaleckascd652842008-04-30 01:20:20 +0300863 dev->stats.rx_packets++;
864 dev->stats.rx_bytes += pkt_len;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700865 } else {
Alexander Kurzf64e9692010-03-31 02:42:10 +0000866 netdev_dbg(dev, "couldn't allocate a sk_buff of size %d.\n",
867 pkt_len);
Paulius Zaleckascd652842008-04-30 01:20:20 +0300868 dev->stats.rx_dropped++;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700869 }
870 }
871 /* Pop the top of the Rx FIFO */
872 tc589_wait_for_completion(dev, RxDiscard);
873 }
874 if (worklimit == 0)
Alexander Kurzf64e9692010-03-31 02:42:10 +0000875 netdev_warn(dev, "too much work in el3_rx!\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -0700876 return 0;
877}
878
Ken Kawasakie445bb42009-07-19 13:08:12 +0000879static void set_rx_mode(struct net_device *dev)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700880{
Olof Johansson906da802008-02-04 22:27:35 -0800881 unsigned int ioaddr = dev->base_addr;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700882 u16 opts = SetRxFilter | RxStation | RxBroadcast;
883
Linus Torvalds1da177e2005-04-16 15:20:36 -0700884 if (dev->flags & IFF_PROMISC)
885 opts |= RxMulticast | RxProm;
Jiri Pirko4cd24ea2010-02-08 04:30:35 +0000886 else if (!netdev_mc_empty(dev) || (dev->flags & IFF_ALLMULTI))
Linus Torvalds1da177e2005-04-16 15:20:36 -0700887 opts |= RxMulticast;
888 outw(opts, ioaddr + EL3_CMD);
889}
890
Ken Kawasakie445bb42009-07-19 13:08:12 +0000891static void set_multicast_list(struct net_device *dev)
892{
893 struct el3_private *priv = netdev_priv(dev);
894 unsigned long flags;
895
896 spin_lock_irqsave(&priv->lock, flags);
897 set_rx_mode(dev);
898 spin_unlock_irqrestore(&priv->lock, flags);
899}
900
Linus Torvalds1da177e2005-04-16 15:20:36 -0700901static int el3_close(struct net_device *dev)
902{
903 struct el3_private *lp = netdev_priv(dev);
Dominik Brodowskifba395e2006-03-31 17:21:06 +0200904 struct pcmcia_device *link = lp->p_dev;
Olof Johansson906da802008-02-04 22:27:35 -0800905 unsigned int ioaddr = dev->base_addr;
Alexander Kurzf64e9692010-03-31 02:42:10 +0000906
Dominik Brodowskidd0fab52009-10-24 15:51:05 +0200907 dev_dbg(&link->dev, "%s: shutting down ethercard.\n", dev->name);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700908
Dominik Brodowski9940ec32006-03-05 11:04:33 +0100909 if (pcmcia_dev_present(link)) {
Paulius Zaleckascd652842008-04-30 01:20:20 +0300910 /* Turn off statistics ASAP. We update dev->stats below. */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700911 outw(StatsDisable, ioaddr + EL3_CMD);
Alexander Kurzf64e9692010-03-31 02:42:10 +0000912
Linus Torvalds1da177e2005-04-16 15:20:36 -0700913 /* Disable the receiver and transmitter. */
914 outw(RxDisable, ioaddr + EL3_CMD);
915 outw(TxDisable, ioaddr + EL3_CMD);
Alexander Kurzf64e9692010-03-31 02:42:10 +0000916
Linus Torvalds1da177e2005-04-16 15:20:36 -0700917 if (dev->if_port == 2)
918 /* Turn off thinnet power. Green! */
919 outw(StopCoax, ioaddr + EL3_CMD);
920 else if (dev->if_port == 1) {
921 /* Disable link beat and jabber */
922 EL3WINDOW(4);
923 outw(0, ioaddr + WN4_MEDIA);
924 }
Alexander Kurzf64e9692010-03-31 02:42:10 +0000925
Linus Torvalds1da177e2005-04-16 15:20:36 -0700926 /* Switching back to window 0 disables the IRQ. */
927 EL3WINDOW(0);
928 /* But we explicitly zero the IRQ line select anyway. */
929 outw(0x0f00, ioaddr + WN0_IRQ);
Alexander Kurzf64e9692010-03-31 02:42:10 +0000930
Linus Torvalds1da177e2005-04-16 15:20:36 -0700931 /* Check if the card still exists */
932 if ((inw(ioaddr+EL3_STATUS) & 0xe000) == 0x2000)
933 update_stats(dev);
934 }
935
936 link->open--;
937 netif_stop_queue(dev);
938 del_timer_sync(&lp->media);
Alexander Kurzf64e9692010-03-31 02:42:10 +0000939
Linus Torvalds1da177e2005-04-16 15:20:36 -0700940 return 0;
941}
942
Dominik Brodowski7ffec582005-06-27 16:28:19 -0700943static struct pcmcia_device_id tc589_ids[] = {
944 PCMCIA_MFC_DEVICE_MANF_CARD(0, 0x0101, 0x0562),
945 PCMCIA_MFC_DEVICE_PROD_ID1(0, "Motorola MARQUIS", 0xf03e4e77),
946 PCMCIA_DEVICE_MANF_CARD(0x0101, 0x0589),
947 PCMCIA_DEVICE_PROD_ID12("Farallon", "ENet", 0x58d93fc4, 0x992c2202),
Ken Kawasakif0a3a152009-05-01 19:21:26 -0700948 PCMCIA_MFC_DEVICE_CIS_MANF_CARD(0, 0x0101, 0x0035, "cis/3CXEM556.cis"),
949 PCMCIA_MFC_DEVICE_CIS_MANF_CARD(0, 0x0101, 0x003d, "cis/3CXEM556.cis"),
Dominik Brodowski7ffec582005-06-27 16:28:19 -0700950 PCMCIA_DEVICE_NULL,
951};
952MODULE_DEVICE_TABLE(pcmcia, tc589_ids);
953
Linus Torvalds1da177e2005-04-16 15:20:36 -0700954static struct pcmcia_driver tc589_driver = {
955 .owner = THIS_MODULE,
956 .drv = {
957 .name = "3c589_cs",
958 },
Dominik Brodowski15b99ac2006-03-31 17:26:06 +0200959 .probe = tc589_probe,
Dominik Brodowskicc3b4862005-11-14 21:23:14 +0100960 .remove = tc589_detach,
Alexander Kurzf64e9692010-03-31 02:42:10 +0000961 .id_table = tc589_ids,
Dominik Brodowski98e4c282005-11-14 21:21:18 +0100962 .suspend = tc589_suspend,
963 .resume = tc589_resume,
Linus Torvalds1da177e2005-04-16 15:20:36 -0700964};
965
966static int __init init_tc589(void)
967{
968 return pcmcia_register_driver(&tc589_driver);
969}
970
971static void __exit exit_tc589(void)
972{
973 pcmcia_unregister_driver(&tc589_driver);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700974}
975
976module_init(init_tc589);
977module_exit(exit_tc589);