blob: da410f036869cd4cb4f9368acfc4441c027f2278 [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
Joe Perches636b8112010-08-12 12:22:51 +000022#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
23
Linus Torvalds1da177e2005-04-16 15:20:36 -070024#define DRV_NAME "3c589_cs"
25#define DRV_VERSION "1.162-ac"
26
27#include <linux/module.h>
28#include <linux/init.h>
29#include <linux/kernel.h>
30#include <linux/ptrace.h>
31#include <linux/slab.h>
32#include <linux/string.h>
33#include <linux/timer.h>
34#include <linux/interrupt.h>
35#include <linux/in.h>
36#include <linux/delay.h>
37#include <linux/ethtool.h>
38#include <linux/netdevice.h>
39#include <linux/etherdevice.h>
40#include <linux/skbuff.h>
41#include <linux/if_arp.h>
42#include <linux/ioport.h>
43#include <linux/bitops.h>
Marcelo Feitoza Parisiff5688a2006-01-09 18:37:15 -080044#include <linux/jiffies.h>
Linus Torvalds1da177e2005-04-16 15:20:36 -070045
Linus Torvalds1da177e2005-04-16 15:20:36 -070046#include <pcmcia/cistpl.h>
47#include <pcmcia/cisreg.h>
48#include <pcmcia/ciscode.h>
49#include <pcmcia/ds.h>
50
51#include <asm/uaccess.h>
52#include <asm/io.h>
53#include <asm/system.h>
54
55/* To minimize the size of the driver source I only define operating
56 constants if they are used several times. You'll need the manual
57 if you want to understand driver details. */
58/* Offsets from base I/O address. */
59#define EL3_DATA 0x00
60#define EL3_TIMER 0x0a
61#define EL3_CMD 0x0e
62#define EL3_STATUS 0x0e
63
64#define EEPROM_READ 0x0080
65#define EEPROM_BUSY 0x8000
66
67#define EL3WINDOW(win_num) outw(SelectWindow + (win_num), ioaddr + EL3_CMD)
68
69/* The top five bits written to EL3_CMD are a command, the lower
70 11 bits are the parameter, if applicable. */
71enum c509cmd {
Alexander Kurzf64e9692010-03-31 02:42:10 +000072 TotalReset = 0<<11,
73 SelectWindow = 1<<11,
74 StartCoax = 2<<11,
75 RxDisable = 3<<11,
76 RxEnable = 4<<11,
77 RxReset = 5<<11,
78 RxDiscard = 8<<11,
79 TxEnable = 9<<11,
80 TxDisable = 10<<11,
81 TxReset = 11<<11,
82 FakeIntr = 12<<11,
83 AckIntr = 13<<11,
84 SetIntrEnb = 14<<11,
85 SetStatusEnb = 15<<11,
86 SetRxFilter = 16<<11,
87 SetRxThreshold = 17<<11,
88 SetTxThreshold = 18<<11,
89 SetTxStart = 19<<11,
90 StatsEnable = 21<<11,
91 StatsDisable = 22<<11,
92 StopCoax = 23<<11
Linus Torvalds1da177e2005-04-16 15:20:36 -070093};
94
95enum c509status {
Alexander Kurzf64e9692010-03-31 02:42:10 +000096 IntLatch = 0x0001,
97 AdapterFailure = 0x0002,
98 TxComplete = 0x0004,
99 TxAvailable = 0x0008,
100 RxComplete = 0x0010,
101 RxEarly = 0x0020,
102 IntReq = 0x0040,
103 StatsFull = 0x0080,
104 CmdBusy = 0x1000
Linus Torvalds1da177e2005-04-16 15:20:36 -0700105};
106
107/* The SetRxFilter command accepts the following classes: */
108enum RxFilter {
Alexander Kurzf64e9692010-03-31 02:42:10 +0000109 RxStation = 1,
110 RxMulticast = 2,
111 RxBroadcast = 4,
112 RxProm = 8
Linus Torvalds1da177e2005-04-16 15:20:36 -0700113};
114
115/* Register window 1 offsets, the window used in normal operation. */
116#define TX_FIFO 0x00
117#define RX_FIFO 0x00
Alexander Kurzf64e9692010-03-31 02:42:10 +0000118#define RX_STATUS 0x08
119#define TX_STATUS 0x0B
Linus Torvalds1da177e2005-04-16 15:20:36 -0700120#define TX_FREE 0x0C /* Remaining free bytes in Tx buffer. */
121
122#define WN0_IRQ 0x08 /* Window 0: Set IRQ line in bits 12-15. */
123#define WN4_MEDIA 0x0A /* Window 4: Various transcvr/media bits. */
124#define MEDIA_TP 0x00C0 /* Enable link beat and jabber for 10baseT. */
125#define MEDIA_LED 0x0001 /* Enable link light on 3C589E cards. */
126
127/* Time in jiffies before concluding Tx hung */
128#define TX_TIMEOUT ((400*HZ)/1000)
129
130struct el3_private {
Dominik Brodowskifd238232006-03-05 10:45:09 +0100131 struct pcmcia_device *p_dev;
Alexander Kurzf64e9692010-03-31 02:42:10 +0000132 /* For transceiver monitoring */
133 struct timer_list media;
134 u16 media_status;
135 u16 fast_poll;
136 unsigned long last_irq;
137 spinlock_t lock;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700138};
139
Jeff Garzik21c0f272007-09-25 00:11:34 -0400140static const char *if_names[] = { "auto", "10baseT", "10base2", "AUI" };
Linus Torvalds1da177e2005-04-16 15:20:36 -0700141
142/*====================================================================*/
143
144/* Module parameters */
145
146MODULE_AUTHOR("David Hinds <dahinds@users.sourceforge.net>");
147MODULE_DESCRIPTION("3Com 3c589 series PCMCIA ethernet driver");
148MODULE_LICENSE("GPL");
149
150#define INT_MODULE_PARM(n, v) static int n = v; module_param(n, int, 0)
151
152/* Special hook for setting if_port when module is loaded */
153INT_MODULE_PARM(if_port, 0);
154
Linus Torvalds1da177e2005-04-16 15:20:36 -0700155
156/*====================================================================*/
157
Dominik Brodowski15b99ac2006-03-31 17:26:06 +0200158static int tc589_config(struct pcmcia_device *link);
Dominik Brodowskifba395e2006-03-31 17:21:06 +0200159static void tc589_release(struct pcmcia_device *link);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700160
Olof Johansson906da802008-02-04 22:27:35 -0800161static u16 read_eeprom(unsigned int ioaddr, int index);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700162static void tc589_reset(struct net_device *dev);
163static void media_check(unsigned long arg);
164static int el3_config(struct net_device *dev, struct ifmap *map);
165static int el3_open(struct net_device *dev);
Stephen Hemmingerdbf02fa2009-08-31 19:50:49 +0000166static netdev_tx_t el3_start_xmit(struct sk_buff *skb,
167 struct net_device *dev);
David Howells7d12e782006-10-05 14:55:46 +0100168static irqreturn_t el3_interrupt(int irq, void *dev_id);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700169static void update_stats(struct net_device *dev);
170static struct net_device_stats *el3_get_stats(struct net_device *dev);
171static int el3_rx(struct net_device *dev);
172static int el3_close(struct net_device *dev);
173static void el3_tx_timeout(struct net_device *dev);
Ken Kawasakie445bb42009-07-19 13:08:12 +0000174static void set_rx_mode(struct net_device *dev);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700175static void set_multicast_list(struct net_device *dev);
Jeff Garzik7282d492006-09-13 14:30:00 -0400176static const struct ethtool_ops netdev_ethtool_ops;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700177
Dominik Brodowskicc3b4862005-11-14 21:23:14 +0100178static void tc589_detach(struct pcmcia_device *p_dev);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700179
Stephen Hemminger97161d42009-03-20 19:36:01 +0000180static const struct net_device_ops el3_netdev_ops = {
Alexander Kurzf64e9692010-03-31 02:42:10 +0000181 .ndo_open = el3_open,
182 .ndo_stop = el3_close,
Stephen Hemminger97161d42009-03-20 19:36:01 +0000183 .ndo_start_xmit = el3_start_xmit,
Alexander Kurzf64e9692010-03-31 02:42:10 +0000184 .ndo_tx_timeout = el3_tx_timeout,
Stephen Hemminger97161d42009-03-20 19:36:01 +0000185 .ndo_set_config = el3_config,
186 .ndo_get_stats = el3_get_stats,
Jiri Pirkoafc4b132011-08-16 06:29:01 +0000187 .ndo_set_rx_mode = set_multicast_list,
Stephen Hemminger97161d42009-03-20 19:36:01 +0000188 .ndo_change_mtu = eth_change_mtu,
Alexander Kurzf64e9692010-03-31 02:42:10 +0000189 .ndo_set_mac_address = eth_mac_addr,
Stephen Hemminger97161d42009-03-20 19:36:01 +0000190 .ndo_validate_addr = eth_validate_addr,
191};
192
Dominik Brodowski15b99ac2006-03-31 17:26:06 +0200193static int tc589_probe(struct pcmcia_device *link)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700194{
195 struct el3_private *lp;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700196 struct net_device *dev;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700197
Dominik Brodowskidd0fab52009-10-24 15:51:05 +0200198 dev_dbg(&link->dev, "3c589_attach()\n");
Dominik Brodowskif8cfa612005-11-14 21:25:51 +0100199
Linus Torvalds1da177e2005-04-16 15:20:36 -0700200 /* Create new ethernet device */
201 dev = alloc_etherdev(sizeof(struct el3_private));
202 if (!dev)
Dominik Brodowskif8cfa612005-11-14 21:25:51 +0100203 return -ENOMEM;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700204 lp = netdev_priv(dev);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700205 link->priv = dev;
Dominik Brodowskifba395e2006-03-31 17:21:06 +0200206 lp->p_dev = link;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700207
208 spin_lock_init(&lp->lock);
Dominik Brodowski90abdc32010-07-24 17:23:51 +0200209 link->resource[0]->end = 16;
210 link->resource[0]->flags |= IO_DATA_PATH_WIDTH_16;
Dominik Brodowskieb141202010-03-07 12:21:16 +0100211
Dominik Brodowski1ac71e52010-07-29 19:27:09 +0200212 link->config_flags |= CONF_ENABLE_IRQ;
Dominik Brodowski7feabb62010-07-29 18:35:47 +0200213 link->config_index = 1;
Dominik Brodowskif8cfa612005-11-14 21:25:51 +0100214
Stephen Hemminger97161d42009-03-20 19:36:01 +0000215 dev->netdev_ops = &el3_netdev_ops;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700216 dev->watchdog_timeo = TX_TIMEOUT;
Stephen Hemminger97161d42009-03-20 19:36:01 +0000217
Linus Torvalds1da177e2005-04-16 15:20:36 -0700218 SET_ETHTOOL_OPS(dev, &netdev_ethtool_ops);
219
Dominik Brodowski15b99ac2006-03-31 17:26:06 +0200220 return tc589_config(link);
Dominik Brodowski22620542010-08-15 08:38:38 +0200221}
Linus Torvalds1da177e2005-04-16 15:20:36 -0700222
Dominik Brodowskifba395e2006-03-31 17:21:06 +0200223static void tc589_detach(struct pcmcia_device *link)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700224{
225 struct net_device *dev = link->priv;
Dominik Brodowskib4635812005-11-14 21:25:35 +0100226
Dominik Brodowskidd0fab52009-10-24 15:51:05 +0200227 dev_dbg(&link->dev, "3c589_detach\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -0700228
Dominik Brodowskic7c2fa02010-03-20 19:39:26 +0100229 unregister_netdev(dev);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700230
Dominik Brodowskie2d40962006-03-02 00:09:29 +0100231 tc589_release(link);
Dominik Brodowskicc3b4862005-11-14 21:23:14 +0100232
Linus Torvalds1da177e2005-04-16 15:20:36 -0700233 free_netdev(dev);
234} /* tc589_detach */
235
Dominik Brodowski15b99ac2006-03-31 17:26:06 +0200236static int tc589_config(struct pcmcia_device *link)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700237{
Linus Torvalds1da177e2005-04-16 15:20:36 -0700238 struct net_device *dev = link->priv;
Al Virob1e247a2007-12-22 18:56:13 +0000239 __be16 *phys_addr;
Dominik Brodowskidd0fab52009-10-24 15:51:05 +0200240 int ret, i, j, multi = 0, fifo;
Olof Johansson906da802008-02-04 22:27:35 -0800241 unsigned int ioaddr;
Joe Perches99101d32010-09-13 18:23:54 +0000242 static const char * const ram_split[] = {"5:3", "3:1", "1:1", "3:5"};
Dominik Brodowskidddfbd82009-10-18 23:54:24 +0200243 u8 *buf;
244 size_t len;
Alexander Kurzf64e9692010-03-31 02:42:10 +0000245
Dominik Brodowskidd0fab52009-10-24 15:51:05 +0200246 dev_dbg(&link->dev, "3c589_config\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -0700247
Al Virob1e247a2007-12-22 18:56:13 +0000248 phys_addr = (__be16 *)dev->dev_addr;
Dominik Brodowskiefd50582006-10-25 21:28:53 -0400249 /* Is this a 3c562? */
250 if (link->manf_id != MANFID_3COM)
Joe Perches636b8112010-08-12 12:22:51 +0000251 dev_info(&link->dev, "hmmm, is this really a 3Com card??\n");
Dominik Brodowskiefd50582006-10-25 21:28:53 -0400252 multi = (link->card_id == PRODID_3COM_3C562);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700253
Dominik Brodowski90abdc32010-07-24 17:23:51 +0200254 link->io_lines = 16;
255
Linus Torvalds1da177e2005-04-16 15:20:36 -0700256 /* For the 3c562, the base address must be xx00-xx7f */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700257 for (i = j = 0; j < 0x400; j += 0x10) {
258 if (multi && (j & 0x80)) continue;
Dominik Brodowski90abdc32010-07-24 17:23:51 +0200259 link->resource[0]->start = j ^ 0x300;
260 i = pcmcia_request_io(link);
Dominik Brodowski4c89e882008-08-03 10:07:45 +0200261 if (i == 0)
262 break;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700263 }
Dominik Brodowskidd0fab52009-10-24 15:51:05 +0200264 if (i != 0)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700265 goto failed;
Dominik Brodowskidd0fab52009-10-24 15:51:05 +0200266
Dominik Brodowskieb141202010-03-07 12:21:16 +0100267 ret = pcmcia_request_irq(link, el3_interrupt);
Dominik Brodowskidd0fab52009-10-24 15:51:05 +0200268 if (ret)
269 goto failed;
270
Dominik Brodowski1ac71e52010-07-29 19:27:09 +0200271 ret = pcmcia_enable_device(link);
Dominik Brodowskidd0fab52009-10-24 15:51:05 +0200272 if (ret)
273 goto failed;
Alexander Kurzf64e9692010-03-31 02:42:10 +0000274
Dominik Brodowskieb141202010-03-07 12:21:16 +0100275 dev->irq = link->irq;
Dominik Brodowski9a017a92010-07-24 15:58:54 +0200276 dev->base_addr = link->resource[0]->start;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700277 ioaddr = dev->base_addr;
278 EL3WINDOW(0);
279
280 /* The 3c589 has an extra EEPROM for configuration info, including
281 the hardware address. The 3c562 puts the address in the CIS. */
Dominik Brodowskidddfbd82009-10-18 23:54:24 +0200282 len = pcmcia_get_tuple(link, 0x88, &buf);
283 if (buf && len >= 6) {
284 for (i = 0; i < 3; i++)
285 phys_addr[i] = htons(le16_to_cpu(buf[i*2]));
286 kfree(buf);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700287 } else {
Dominik Brodowskidddfbd82009-10-18 23:54:24 +0200288 kfree(buf); /* 0 < len < 6 */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700289 for (i = 0; i < 3; i++)
290 phys_addr[i] = htons(read_eeprom(ioaddr, i));
Al Virob1e247a2007-12-22 18:56:13 +0000291 if (phys_addr[0] == htons(0x6060)) {
Joe Perches636b8112010-08-12 12:22:51 +0000292 dev_err(&link->dev, "IO port conflict at 0x%03lx-0x%03lx\n",
293 dev->base_addr, dev->base_addr+15);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700294 goto failed;
295 }
296 }
297
298 /* The address and resource configuration register aren't loaded from
299 the EEPROM and *must* be set to 0 and IRQ3 for the PCMCIA version. */
300 outw(0x3f00, ioaddr + 8);
301 fifo = inl(ioaddr);
302
303 /* The if_port symbol can be set when the module is loaded */
304 if ((if_port >= 0) && (if_port <= 3))
305 dev->if_port = if_port;
306 else
Joe Perches636b8112010-08-12 12:22:51 +0000307 dev_err(&link->dev, "invalid if_port requested\n");
Alexander Kurzf64e9692010-03-31 02:42:10 +0000308
Dominik Brodowskidd2e5a12009-11-03 10:27:34 +0100309 SET_NETDEV_DEV(dev, &link->dev);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700310
311 if (register_netdev(dev) != 0) {
Joe Perches636b8112010-08-12 12:22:51 +0000312 dev_err(&link->dev, "register_netdev() failed\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -0700313 goto failed;
314 }
315
Alexander Kurzf64e9692010-03-31 02:42:10 +0000316 netdev_info(dev, "3Com 3c%s, io %#3lx, irq %d, hw_addr %pM\n",
317 (multi ? "562" : "589"), dev->base_addr, dev->irq,
318 dev->dev_addr);
319 netdev_info(dev, " %dK FIFO split %s Rx:Tx, %s xcvr\n",
320 (fifo & 7) ? 32 : 8, ram_split[(fifo >> 16) & 3],
321 if_names[dev->if_port]);
Dominik Brodowski15b99ac2006-03-31 17:26:06 +0200322 return 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700323
Linus Torvalds1da177e2005-04-16 15:20:36 -0700324failed:
325 tc589_release(link);
Dominik Brodowski15b99ac2006-03-31 17:26:06 +0200326 return -ENODEV;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700327} /* tc589_config */
328
Dominik Brodowskifba395e2006-03-31 17:21:06 +0200329static void tc589_release(struct pcmcia_device *link)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700330{
Dominik Brodowskifba395e2006-03-31 17:21:06 +0200331 pcmcia_disable_device(link);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700332}
333
Dominik Brodowskifba395e2006-03-31 17:21:06 +0200334static int tc589_suspend(struct pcmcia_device *link)
Dominik Brodowski98e4c282005-11-14 21:21:18 +0100335{
Dominik Brodowski98e4c282005-11-14 21:21:18 +0100336 struct net_device *dev = link->priv;
337
Dominik Brodowskie2d40962006-03-02 00:09:29 +0100338 if (link->open)
Dominik Brodowski8661bb52006-03-02 00:02:33 +0100339 netif_device_detach(dev);
Dominik Brodowski98e4c282005-11-14 21:21:18 +0100340
341 return 0;
342}
343
Dominik Brodowskifba395e2006-03-31 17:21:06 +0200344static int tc589_resume(struct pcmcia_device *link)
Dominik Brodowski98e4c282005-11-14 21:21:18 +0100345{
Dominik Brodowski98e4c282005-11-14 21:21:18 +0100346 struct net_device *dev = link->priv;
347
Alexander Kurzf64e9692010-03-31 02:42:10 +0000348 if (link->open) {
Dominik Brodowski8661bb52006-03-02 00:02:33 +0100349 tc589_reset(dev);
350 netif_device_attach(dev);
Dominik Brodowski98e4c282005-11-14 21:21:18 +0100351 }
352
353 return 0;
354}
355
Linus Torvalds1da177e2005-04-16 15:20:36 -0700356/*====================================================================*/
357
358/*
359 Use this for commands that may take time to finish
360*/
361static void tc589_wait_for_completion(struct net_device *dev, int cmd)
362{
363 int i = 100;
364 outw(cmd, dev->base_addr + EL3_CMD);
365 while (--i > 0)
366 if (!(inw(dev->base_addr + EL3_STATUS) & 0x1000)) break;
367 if (i == 0)
Alexander Kurzf64e9692010-03-31 02:42:10 +0000368 netdev_warn(dev, "command 0x%04x did not complete!\n", cmd);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700369}
370
371/*
372 Read a word from the EEPROM using the regular EEPROM access register.
373 Assume that we are in register window zero.
374*/
Olof Johansson906da802008-02-04 22:27:35 -0800375static u16 read_eeprom(unsigned int ioaddr, int index)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700376{
377 int i;
378 outw(EEPROM_READ + index, ioaddr + 10);
379 /* Reading the eeprom takes 162 us */
380 for (i = 1620; i >= 0; i--)
381 if ((inw(ioaddr + 10) & EEPROM_BUSY) == 0)
382 break;
383 return inw(ioaddr + 12);
384}
385
386/*
387 Set transceiver type, perhaps to something other than what the user
388 specified in dev->if_port.
389*/
390static void tc589_set_xcvr(struct net_device *dev, int if_port)
391{
392 struct el3_private *lp = netdev_priv(dev);
Olof Johansson906da802008-02-04 22:27:35 -0800393 unsigned int ioaddr = dev->base_addr;
Alexander Kurzf64e9692010-03-31 02:42:10 +0000394
Linus Torvalds1da177e2005-04-16 15:20:36 -0700395 EL3WINDOW(0);
396 switch (if_port) {
397 case 0: case 1: outw(0, ioaddr + 6); break;
398 case 2: outw(3<<14, ioaddr + 6); break;
399 case 3: outw(1<<14, ioaddr + 6); break;
400 }
401 /* On PCMCIA, this just turns on the LED */
402 outw((if_port == 2) ? StartCoax : StopCoax, ioaddr + EL3_CMD);
403 /* 10baseT interface, enable link beat and jabber check. */
404 EL3WINDOW(4);
405 outw(MEDIA_LED | ((if_port < 2) ? MEDIA_TP : 0), ioaddr + WN4_MEDIA);
406 EL3WINDOW(1);
407 if (if_port == 2)
408 lp->media_status = ((dev->if_port == 0) ? 0x8000 : 0x4000);
409 else
410 lp->media_status = ((dev->if_port == 0) ? 0x4010 : 0x8800);
411}
412
413static void dump_status(struct net_device *dev)
414{
Olof Johansson906da802008-02-04 22:27:35 -0800415 unsigned int ioaddr = dev->base_addr;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700416 EL3WINDOW(1);
Alexander Kurzf64e9692010-03-31 02:42:10 +0000417 netdev_info(dev, " irq status %04x, rx status %04x, tx status %02x tx free %04x\n",
418 inw(ioaddr+EL3_STATUS), inw(ioaddr+RX_STATUS),
419 inb(ioaddr+TX_STATUS), inw(ioaddr+TX_FREE));
Linus Torvalds1da177e2005-04-16 15:20:36 -0700420 EL3WINDOW(4);
Alexander Kurzf64e9692010-03-31 02:42:10 +0000421 netdev_info(dev, " diagnostics: fifo %04x net %04x ethernet %04x media %04x\n",
422 inw(ioaddr+0x04), inw(ioaddr+0x06), inw(ioaddr+0x08),
423 inw(ioaddr+0x0a));
Linus Torvalds1da177e2005-04-16 15:20:36 -0700424 EL3WINDOW(1);
425}
426
427/* Reset and restore all of the 3c589 registers. */
428static void tc589_reset(struct net_device *dev)
429{
Olof Johansson906da802008-02-04 22:27:35 -0800430 unsigned int ioaddr = dev->base_addr;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700431 int i;
Alexander Kurzf64e9692010-03-31 02:42:10 +0000432
Linus Torvalds1da177e2005-04-16 15:20:36 -0700433 EL3WINDOW(0);
Alexander Kurzf64e9692010-03-31 02:42:10 +0000434 outw(0x0001, ioaddr + 4); /* Activate board. */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700435 outw(0x3f00, ioaddr + 8); /* Set the IRQ line. */
Alexander Kurzf64e9692010-03-31 02:42:10 +0000436
Linus Torvalds1da177e2005-04-16 15:20:36 -0700437 /* Set the station address in window 2. */
438 EL3WINDOW(2);
439 for (i = 0; i < 6; i++)
440 outb(dev->dev_addr[i], ioaddr + i);
441
442 tc589_set_xcvr(dev, dev->if_port);
Alexander Kurzf64e9692010-03-31 02:42:10 +0000443
Linus Torvalds1da177e2005-04-16 15:20:36 -0700444 /* Switch to the stats window, and clear all stats by reading. */
445 outw(StatsDisable, ioaddr + EL3_CMD);
446 EL3WINDOW(6);
447 for (i = 0; i < 9; i++)
448 inb(ioaddr+i);
449 inw(ioaddr + 10);
450 inw(ioaddr + 12);
Alexander Kurzf64e9692010-03-31 02:42:10 +0000451
Linus Torvalds1da177e2005-04-16 15:20:36 -0700452 /* Switch to register set 1 for normal use. */
453 EL3WINDOW(1);
454
Ken Kawasakie445bb42009-07-19 13:08:12 +0000455 set_rx_mode(dev);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700456 outw(StatsEnable, ioaddr + EL3_CMD); /* Turn on statistics. */
457 outw(RxEnable, ioaddr + EL3_CMD); /* Enable the receiver. */
458 outw(TxEnable, ioaddr + EL3_CMD); /* Enable transmitter. */
459 /* Allow status bits to be seen. */
460 outw(SetStatusEnb | 0xff, ioaddr + EL3_CMD);
461 /* Ack all pending events, and set active indicator mask. */
462 outw(AckIntr | IntLatch | TxAvailable | RxEarly | IntReq,
463 ioaddr + EL3_CMD);
464 outw(SetIntrEnb | IntLatch | TxAvailable | RxComplete | StatsFull
465 | AdapterFailure, ioaddr + EL3_CMD);
466}
467
468static void netdev_get_drvinfo(struct net_device *dev,
469 struct ethtool_drvinfo *info)
470{
Rick Jones68aad782011-11-07 13:29:27 +0000471 strlcpy(info->driver, DRV_NAME, sizeof(info->driver));
472 strlcpy(info->version, DRV_VERSION, sizeof(info->version));
473 snprintf(info->bus_info, sizeof(info->bus_info),
474 "PCMCIA 0x%lx", dev->base_addr);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700475}
476
Jeff Garzik7282d492006-09-13 14:30:00 -0400477static const struct ethtool_ops netdev_ethtool_ops = {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700478 .get_drvinfo = netdev_get_drvinfo,
Linus Torvalds1da177e2005-04-16 15:20:36 -0700479};
480
481static int el3_config(struct net_device *dev, struct ifmap *map)
482{
483 if ((map->port != (u_char)(-1)) && (map->port != dev->if_port)) {
484 if (map->port <= 3) {
485 dev->if_port = map->port;
Alexander Kurzf64e9692010-03-31 02:42:10 +0000486 netdev_info(dev, "switched to %s port\n", if_names[dev->if_port]);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700487 tc589_set_xcvr(dev, dev->if_port);
488 } else
489 return -EINVAL;
490 }
491 return 0;
492}
493
494static int el3_open(struct net_device *dev)
495{
496 struct el3_private *lp = netdev_priv(dev);
Dominik Brodowskifba395e2006-03-31 17:21:06 +0200497 struct pcmcia_device *link = lp->p_dev;
Alexander Kurzf64e9692010-03-31 02:42:10 +0000498
Dominik Brodowski9940ec32006-03-05 11:04:33 +0100499 if (!pcmcia_dev_present(link))
Linus Torvalds1da177e2005-04-16 15:20:36 -0700500 return -ENODEV;
501
502 link->open++;
503 netif_start_queue(dev);
Alexander Kurzf64e9692010-03-31 02:42:10 +0000504
Linus Torvalds1da177e2005-04-16 15:20:36 -0700505 tc589_reset(dev);
506 init_timer(&lp->media);
Joe Perchesc061b182010-08-23 18:20:03 +0000507 lp->media.function = media_check;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700508 lp->media.data = (unsigned long) dev;
509 lp->media.expires = jiffies + HZ;
510 add_timer(&lp->media);
511
Dominik Brodowskidd0fab52009-10-24 15:51:05 +0200512 dev_dbg(&link->dev, "%s: opened, status %4.4x.\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -0700513 dev->name, inw(dev->base_addr + EL3_STATUS));
Alexander Kurzf64e9692010-03-31 02:42:10 +0000514
Linus Torvalds1da177e2005-04-16 15:20:36 -0700515 return 0;
516}
517
518static void el3_tx_timeout(struct net_device *dev)
519{
Olof Johansson906da802008-02-04 22:27:35 -0800520 unsigned int ioaddr = dev->base_addr;
Alexander Kurzf64e9692010-03-31 02:42:10 +0000521
522 netdev_warn(dev, "Transmit timed out!\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -0700523 dump_status(dev);
Paulius Zaleckascd65284f2008-04-30 01:20:20 +0300524 dev->stats.tx_errors++;
Eric Dumazet1ae5dc32010-05-10 05:01:31 -0700525 dev->trans_start = jiffies; /* prevent tx timeout */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700526 /* Issue TX_RESET and TX_START commands. */
527 tc589_wait_for_completion(dev, TxReset);
528 outw(TxEnable, ioaddr + EL3_CMD);
529 netif_wake_queue(dev);
530}
531
532static void pop_tx_status(struct net_device *dev)
533{
Olof Johansson906da802008-02-04 22:27:35 -0800534 unsigned int ioaddr = dev->base_addr;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700535 int i;
Alexander Kurzf64e9692010-03-31 02:42:10 +0000536
Linus Torvalds1da177e2005-04-16 15:20:36 -0700537 /* Clear the Tx status stack. */
538 for (i = 32; i > 0; i--) {
539 u_char tx_status = inb(ioaddr + TX_STATUS);
540 if (!(tx_status & 0x84)) break;
541 /* reset transmitter on jabber error or underrun */
542 if (tx_status & 0x30)
Alexander Kurzf64e9692010-03-31 02:42:10 +0000543 tc589_wait_for_completion(dev, TxReset);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700544 if (tx_status & 0x38) {
Alexander Kurzf64e9692010-03-31 02:42:10 +0000545 netdev_dbg(dev, "transmit error: status 0x%02x\n", tx_status);
546 outw(TxEnable, ioaddr + EL3_CMD);
547 dev->stats.tx_aborted_errors++;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700548 }
549 outb(0x00, ioaddr + TX_STATUS); /* Pop the status stack. */
550 }
551}
552
Stephen Hemmingerdbf02fa2009-08-31 19:50:49 +0000553static netdev_tx_t el3_start_xmit(struct sk_buff *skb,
554 struct net_device *dev)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700555{
Olof Johansson906da802008-02-04 22:27:35 -0800556 unsigned int ioaddr = dev->base_addr;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700557 struct el3_private *priv = netdev_priv(dev);
Komurod08d2832006-12-02 11:53:27 +0900558 unsigned long flags;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700559
Alexander Kurzf64e9692010-03-31 02:42:10 +0000560 netdev_dbg(dev, "el3_start_xmit(length = %ld) called, status %4.4x.\n",
561 (long)skb->len, inw(ioaddr + EL3_STATUS));
Linus Torvalds1da177e2005-04-16 15:20:36 -0700562
Alexander Kurzf64e9692010-03-31 02:42:10 +0000563 spin_lock_irqsave(&priv->lock, flags);
Komurod08d2832006-12-02 11:53:27 +0900564
Paulius Zaleckascd65284f2008-04-30 01:20:20 +0300565 dev->stats.tx_bytes += skb->len;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700566
567 /* Put out the doubleword header... */
568 outw(skb->len, ioaddr + TX_FIFO);
569 outw(0x00, ioaddr + TX_FIFO);
570 /* ... and the packet rounded to a doubleword. */
571 outsl(ioaddr + TX_FIFO, skb->data, (skb->len + 3) >> 2);
572
Linus Torvalds1da177e2005-04-16 15:20:36 -0700573 if (inw(ioaddr + TX_FREE) <= 1536) {
574 netif_stop_queue(dev);
575 /* Interrupt us when the FIFO has room for max-sized packet. */
576 outw(SetTxThreshold + 1536, ioaddr + EL3_CMD);
577 }
578
Linus Torvalds1da177e2005-04-16 15:20:36 -0700579 pop_tx_status(dev);
Alexander Kurzf64e9692010-03-31 02:42:10 +0000580 spin_unlock_irqrestore(&priv->lock, flags);
Patrick McHardy63ac9b92007-07-02 16:08:28 +0200581 dev_kfree_skb(skb);
Alexander Kurzf64e9692010-03-31 02:42:10 +0000582
Patrick McHardy6ed10652009-06-23 06:03:08 +0000583 return NETDEV_TX_OK;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700584}
585
586/* The EL3 interrupt handler. */
David Howells7d12e782006-10-05 14:55:46 +0100587static irqreturn_t el3_interrupt(int irq, void *dev_id)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700588{
589 struct net_device *dev = (struct net_device *) dev_id;
590 struct el3_private *lp = netdev_priv(dev);
Olof Johansson906da802008-02-04 22:27:35 -0800591 unsigned int ioaddr;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700592 __u16 status;
593 int i = 0, handled = 1;
Alexander Kurzf64e9692010-03-31 02:42:10 +0000594
Linus Torvalds1da177e2005-04-16 15:20:36 -0700595 if (!netif_device_present(dev))
596 return IRQ_NONE;
597
598 ioaddr = dev->base_addr;
599
Alexander Kurzf64e9692010-03-31 02:42:10 +0000600 netdev_dbg(dev, "interrupt, status %4.4x.\n", inw(ioaddr + EL3_STATUS));
Linus Torvalds1da177e2005-04-16 15:20:36 -0700601
Alexander Kurzf64e9692010-03-31 02:42:10 +0000602 spin_lock(&lp->lock);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700603 while ((status = inw(ioaddr + EL3_STATUS)) &
604 (IntLatch | RxComplete | StatsFull)) {
605 if ((status & 0xe000) != 0x2000) {
Alexander Kurzf64e9692010-03-31 02:42:10 +0000606 netdev_dbg(dev, "interrupt from dead card\n");
607 handled = 0;
608 break;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700609 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700610 if (status & RxComplete)
Alexander Kurzf64e9692010-03-31 02:42:10 +0000611 el3_rx(dev);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700612 if (status & TxAvailable) {
Alexander Kurzf64e9692010-03-31 02:42:10 +0000613 netdev_dbg(dev, " TX room bit was handled.\n");
614 /* There's room in the FIFO for a full-sized packet. */
615 outw(AckIntr | TxAvailable, ioaddr + EL3_CMD);
616 netif_wake_queue(dev);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700617 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700618 if (status & TxComplete)
Alexander Kurzf64e9692010-03-31 02:42:10 +0000619 pop_tx_status(dev);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700620 if (status & (AdapterFailure | RxEarly | StatsFull)) {
621 /* Handle all uncommon interrupts. */
622 if (status & StatsFull) /* Empty statistics. */
623 update_stats(dev);
624 if (status & RxEarly) { /* Rx early is unused. */
625 el3_rx(dev);
626 outw(AckIntr | RxEarly, ioaddr + EL3_CMD);
627 }
628 if (status & AdapterFailure) {
629 u16 fifo_diag;
630 EL3WINDOW(4);
631 fifo_diag = inw(ioaddr + 4);
632 EL3WINDOW(1);
Alexander Kurzf64e9692010-03-31 02:42:10 +0000633 netdev_warn(dev, "adapter failure, FIFO diagnostic register %04x.\n",
634 fifo_diag);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700635 if (fifo_diag & 0x0400) {
636 /* Tx overrun */
637 tc589_wait_for_completion(dev, TxReset);
638 outw(TxEnable, ioaddr + EL3_CMD);
639 }
640 if (fifo_diag & 0x2000) {
641 /* Rx underrun */
642 tc589_wait_for_completion(dev, RxReset);
Ken Kawasakie445bb42009-07-19 13:08:12 +0000643 set_rx_mode(dev);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700644 outw(RxEnable, ioaddr + EL3_CMD);
645 }
646 outw(AckIntr | AdapterFailure, ioaddr + EL3_CMD);
647 }
648 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700649 if (++i > 10) {
Alexander Kurzf64e9692010-03-31 02:42:10 +0000650 netdev_err(dev, "infinite loop in interrupt, status %4.4x.\n",
651 status);
652 /* Clear all interrupts */
653 outw(AckIntr | 0xFF, ioaddr + EL3_CMD);
654 break;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700655 }
656 /* Acknowledge the IRQ. */
657 outw(AckIntr | IntReq | IntLatch, ioaddr + EL3_CMD);
658 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700659 lp->last_irq = jiffies;
Alexander Kurzf64e9692010-03-31 02:42:10 +0000660 spin_unlock(&lp->lock);
661 netdev_dbg(dev, "exiting interrupt, status %4.4x.\n",
662 inw(ioaddr + EL3_STATUS));
Linus Torvalds1da177e2005-04-16 15:20:36 -0700663 return IRQ_RETVAL(handled);
664}
665
666static void media_check(unsigned long arg)
667{
668 struct net_device *dev = (struct net_device *)(arg);
669 struct el3_private *lp = netdev_priv(dev);
Olof Johansson906da802008-02-04 22:27:35 -0800670 unsigned int ioaddr = dev->base_addr;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700671 u16 media, errs;
672 unsigned long flags;
673
674 if (!netif_device_present(dev)) goto reschedule;
675
Linus Torvalds1da177e2005-04-16 15:20:36 -0700676 /* Check for pending interrupt with expired latency timer: with
677 this, we can limp along even if the interrupt is blocked */
678 if ((inw(ioaddr + EL3_STATUS) & IntLatch) &&
679 (inb(ioaddr + EL3_TIMER) == 0xff)) {
680 if (!lp->fast_poll)
Alexander Kurzf64e9692010-03-31 02:42:10 +0000681 netdev_warn(dev, "interrupt(s) dropped!\n");
Ken Kawasaki671c8802009-12-12 14:44:11 +0000682
683 local_irq_save(flags);
Komurod08d2832006-12-02 11:53:27 +0900684 el3_interrupt(dev->irq, dev);
Ken Kawasaki671c8802009-12-12 14:44:11 +0000685 local_irq_restore(flags);
686
Linus Torvalds1da177e2005-04-16 15:20:36 -0700687 lp->fast_poll = HZ;
688 }
689 if (lp->fast_poll) {
690 lp->fast_poll--;
691 lp->media.expires = jiffies + HZ/100;
692 add_timer(&lp->media);
693 return;
694 }
695
696 /* lp->lock guards the EL3 window. Window should always be 1 except
697 when the lock is held */
Alexander Kurzf64e9692010-03-31 02:42:10 +0000698 spin_lock_irqsave(&lp->lock, flags);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700699 EL3WINDOW(4);
700 media = inw(ioaddr+WN4_MEDIA) & 0xc810;
701
702 /* Ignore collisions unless we've had no irq's recently */
Marcelo Feitoza Parisiff5688a2006-01-09 18:37:15 -0800703 if (time_before(jiffies, lp->last_irq + HZ)) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700704 media &= ~0x0010;
705 } else {
706 /* Try harder to detect carrier errors */
707 EL3WINDOW(6);
708 outw(StatsDisable, ioaddr + EL3_CMD);
709 errs = inb(ioaddr + 0);
710 outw(StatsEnable, ioaddr + EL3_CMD);
Paulius Zaleckascd65284f2008-04-30 01:20:20 +0300711 dev->stats.tx_carrier_errors += errs;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700712 if (errs || (lp->media_status & 0x0010)) media |= 0x0010;
713 }
714
715 if (media != lp->media_status) {
716 if ((media & lp->media_status & 0x8000) &&
717 ((lp->media_status ^ media) & 0x0800))
Alexander Kurzf64e9692010-03-31 02:42:10 +0000718 netdev_info(dev, "%s link beat\n",
719 (lp->media_status & 0x0800 ? "lost" : "found"));
Linus Torvalds1da177e2005-04-16 15:20:36 -0700720 else if ((media & lp->media_status & 0x4000) &&
721 ((lp->media_status ^ media) & 0x0010))
Alexander Kurzf64e9692010-03-31 02:42:10 +0000722 netdev_info(dev, "coax cable %s\n",
723 (lp->media_status & 0x0010 ? "ok" : "problem"));
Linus Torvalds1da177e2005-04-16 15:20:36 -0700724 if (dev->if_port == 0) {
725 if (media & 0x8000) {
726 if (media & 0x0800)
Alexander Kurzf64e9692010-03-31 02:42:10 +0000727 netdev_info(dev, "flipped to 10baseT\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -0700728 else
Alexander Kurzf64e9692010-03-31 02:42:10 +0000729 tc589_set_xcvr(dev, 2);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700730 } else if (media & 0x4000) {
731 if (media & 0x0010)
732 tc589_set_xcvr(dev, 1);
733 else
Alexander Kurzf64e9692010-03-31 02:42:10 +0000734 netdev_info(dev, "flipped to 10base2\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -0700735 }
736 }
737 lp->media_status = media;
738 }
Alexander Kurzf64e9692010-03-31 02:42:10 +0000739
Linus Torvalds1da177e2005-04-16 15:20:36 -0700740 EL3WINDOW(1);
Alexander Kurzf64e9692010-03-31 02:42:10 +0000741 spin_unlock_irqrestore(&lp->lock, flags);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700742
743reschedule:
744 lp->media.expires = jiffies + HZ;
745 add_timer(&lp->media);
746}
747
748static struct net_device_stats *el3_get_stats(struct net_device *dev)
749{
750 struct el3_private *lp = netdev_priv(dev);
751 unsigned long flags;
Dominik Brodowskifba395e2006-03-31 17:21:06 +0200752 struct pcmcia_device *link = lp->p_dev;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700753
Dominik Brodowski9940ec32006-03-05 11:04:33 +0100754 if (pcmcia_dev_present(link)) {
Alexander Kurzf64e9692010-03-31 02:42:10 +0000755 spin_lock_irqsave(&lp->lock, flags);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700756 update_stats(dev);
757 spin_unlock_irqrestore(&lp->lock, flags);
758 }
Paulius Zaleckascd65284f2008-04-30 01:20:20 +0300759 return &dev->stats;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700760}
761
762/*
763 Update statistics. We change to register window 6, so this should be run
764 single-threaded if the device is active. This is expected to be a rare
765 operation, and it's simpler for the rest of the driver to assume that
766 window 1 is always valid rather than use a special window-state variable.
Alexander Kurzf64e9692010-03-31 02:42:10 +0000767
Linus Torvalds1da177e2005-04-16 15:20:36 -0700768 Caller must hold the lock for this
769*/
770static void update_stats(struct net_device *dev)
771{
Olof Johansson906da802008-02-04 22:27:35 -0800772 unsigned int ioaddr = dev->base_addr;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700773
Alexander Kurzf64e9692010-03-31 02:42:10 +0000774 netdev_dbg(dev, "updating the statistics.\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -0700775 /* Turn off statistics updates while reading. */
776 outw(StatsDisable, ioaddr + EL3_CMD);
777 /* Switch to the stats window, and read everything. */
778 EL3WINDOW(6);
Alexander Kurzf64e9692010-03-31 02:42:10 +0000779 dev->stats.tx_carrier_errors += inb(ioaddr + 0);
Paulius Zaleckascd65284f2008-04-30 01:20:20 +0300780 dev->stats.tx_heartbeat_errors += inb(ioaddr + 1);
Alexander Kurzf64e9692010-03-31 02:42:10 +0000781 /* Multiple collisions. */ inb(ioaddr + 2);
Paulius Zaleckascd65284f2008-04-30 01:20:20 +0300782 dev->stats.collisions += inb(ioaddr + 3);
783 dev->stats.tx_window_errors += inb(ioaddr + 4);
784 dev->stats.rx_fifo_errors += inb(ioaddr + 5);
785 dev->stats.tx_packets += inb(ioaddr + 6);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700786 /* Rx packets */ inb(ioaddr + 7);
787 /* Tx deferrals */ inb(ioaddr + 8);
788 /* Rx octets */ inw(ioaddr + 10);
789 /* Tx octets */ inw(ioaddr + 12);
Alexander Kurzf64e9692010-03-31 02:42:10 +0000790
Linus Torvalds1da177e2005-04-16 15:20:36 -0700791 /* Back to window 1, and turn statistics back on. */
792 EL3WINDOW(1);
793 outw(StatsEnable, ioaddr + EL3_CMD);
794}
795
796static int el3_rx(struct net_device *dev)
797{
Olof Johansson906da802008-02-04 22:27:35 -0800798 unsigned int ioaddr = dev->base_addr;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700799 int worklimit = 32;
800 short rx_status;
Alexander Kurzf64e9692010-03-31 02:42:10 +0000801
802 netdev_dbg(dev, "in rx_packet(), status %4.4x, rx_status %4.4x.\n",
803 inw(ioaddr+EL3_STATUS), inw(ioaddr+RX_STATUS));
Linus Torvalds1da177e2005-04-16 15:20:36 -0700804 while (!((rx_status = inw(ioaddr + RX_STATUS)) & 0x8000) &&
Roel Kluinb9bdcd92009-03-04 00:05:56 -0800805 worklimit > 0) {
806 worklimit--;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700807 if (rx_status & 0x4000) { /* Error, update stats. */
808 short error = rx_status & 0x3800;
Paulius Zaleckascd65284f2008-04-30 01:20:20 +0300809 dev->stats.rx_errors++;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700810 switch (error) {
Paulius Zaleckascd65284f2008-04-30 01:20:20 +0300811 case 0x0000: dev->stats.rx_over_errors++; break;
812 case 0x0800: dev->stats.rx_length_errors++; break;
813 case 0x1000: dev->stats.rx_frame_errors++; break;
814 case 0x1800: dev->stats.rx_length_errors++; break;
815 case 0x2000: dev->stats.rx_frame_errors++; break;
816 case 0x2800: dev->stats.rx_crc_errors++; break;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700817 }
818 } else {
819 short pkt_len = rx_status & 0x7ff;
820 struct sk_buff *skb;
Alexander Kurzf64e9692010-03-31 02:42:10 +0000821
Linus Torvalds1da177e2005-04-16 15:20:36 -0700822 skb = dev_alloc_skb(pkt_len+5);
Alexander Kurzf64e9692010-03-31 02:42:10 +0000823
824 netdev_dbg(dev, " Receiving packet size %d status %4.4x.\n",
825 pkt_len, rx_status);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700826 if (skb != NULL) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700827 skb_reserve(skb, 2);
828 insl(ioaddr+RX_FIFO, skb_put(skb, pkt_len),
829 (pkt_len+3)>>2);
830 skb->protocol = eth_type_trans(skb, dev);
831 netif_rx(skb);
Paulius Zaleckascd65284f2008-04-30 01:20:20 +0300832 dev->stats.rx_packets++;
833 dev->stats.rx_bytes += pkt_len;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700834 } else {
Alexander Kurzf64e9692010-03-31 02:42:10 +0000835 netdev_dbg(dev, "couldn't allocate a sk_buff of size %d.\n",
836 pkt_len);
Paulius Zaleckascd65284f2008-04-30 01:20:20 +0300837 dev->stats.rx_dropped++;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700838 }
839 }
840 /* Pop the top of the Rx FIFO */
841 tc589_wait_for_completion(dev, RxDiscard);
842 }
843 if (worklimit == 0)
Alexander Kurzf64e9692010-03-31 02:42:10 +0000844 netdev_warn(dev, "too much work in el3_rx!\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -0700845 return 0;
846}
847
Ken Kawasakie445bb42009-07-19 13:08:12 +0000848static void set_rx_mode(struct net_device *dev)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700849{
Olof Johansson906da802008-02-04 22:27:35 -0800850 unsigned int ioaddr = dev->base_addr;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700851 u16 opts = SetRxFilter | RxStation | RxBroadcast;
852
Linus Torvalds1da177e2005-04-16 15:20:36 -0700853 if (dev->flags & IFF_PROMISC)
854 opts |= RxMulticast | RxProm;
Jiri Pirko4cd24ea2010-02-08 04:30:35 +0000855 else if (!netdev_mc_empty(dev) || (dev->flags & IFF_ALLMULTI))
Linus Torvalds1da177e2005-04-16 15:20:36 -0700856 opts |= RxMulticast;
857 outw(opts, ioaddr + EL3_CMD);
858}
859
Ken Kawasakie445bb42009-07-19 13:08:12 +0000860static void set_multicast_list(struct net_device *dev)
861{
862 struct el3_private *priv = netdev_priv(dev);
863 unsigned long flags;
864
865 spin_lock_irqsave(&priv->lock, flags);
866 set_rx_mode(dev);
867 spin_unlock_irqrestore(&priv->lock, flags);
868}
869
Linus Torvalds1da177e2005-04-16 15:20:36 -0700870static int el3_close(struct net_device *dev)
871{
872 struct el3_private *lp = netdev_priv(dev);
Dominik Brodowskifba395e2006-03-31 17:21:06 +0200873 struct pcmcia_device *link = lp->p_dev;
Olof Johansson906da802008-02-04 22:27:35 -0800874 unsigned int ioaddr = dev->base_addr;
Alexander Kurzf64e9692010-03-31 02:42:10 +0000875
Dominik Brodowskidd0fab52009-10-24 15:51:05 +0200876 dev_dbg(&link->dev, "%s: shutting down ethercard.\n", dev->name);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700877
Dominik Brodowski9940ec32006-03-05 11:04:33 +0100878 if (pcmcia_dev_present(link)) {
Paulius Zaleckascd65284f2008-04-30 01:20:20 +0300879 /* Turn off statistics ASAP. We update dev->stats below. */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700880 outw(StatsDisable, ioaddr + EL3_CMD);
Alexander Kurzf64e9692010-03-31 02:42:10 +0000881
Linus Torvalds1da177e2005-04-16 15:20:36 -0700882 /* Disable the receiver and transmitter. */
883 outw(RxDisable, ioaddr + EL3_CMD);
884 outw(TxDisable, ioaddr + EL3_CMD);
Alexander Kurzf64e9692010-03-31 02:42:10 +0000885
Linus Torvalds1da177e2005-04-16 15:20:36 -0700886 if (dev->if_port == 2)
887 /* Turn off thinnet power. Green! */
888 outw(StopCoax, ioaddr + EL3_CMD);
889 else if (dev->if_port == 1) {
890 /* Disable link beat and jabber */
891 EL3WINDOW(4);
892 outw(0, ioaddr + WN4_MEDIA);
893 }
Alexander Kurzf64e9692010-03-31 02:42:10 +0000894
Linus Torvalds1da177e2005-04-16 15:20:36 -0700895 /* Switching back to window 0 disables the IRQ. */
896 EL3WINDOW(0);
897 /* But we explicitly zero the IRQ line select anyway. */
898 outw(0x0f00, ioaddr + WN0_IRQ);
Alexander Kurzf64e9692010-03-31 02:42:10 +0000899
Linus Torvalds1da177e2005-04-16 15:20:36 -0700900 /* Check if the card still exists */
901 if ((inw(ioaddr+EL3_STATUS) & 0xe000) == 0x2000)
902 update_stats(dev);
903 }
904
905 link->open--;
906 netif_stop_queue(dev);
907 del_timer_sync(&lp->media);
Alexander Kurzf64e9692010-03-31 02:42:10 +0000908
Linus Torvalds1da177e2005-04-16 15:20:36 -0700909 return 0;
910}
911
Joe Perches25f8f542011-05-03 19:29:01 -0700912static const struct pcmcia_device_id tc589_ids[] = {
Dominik Brodowski7ffec582005-06-27 16:28:19 -0700913 PCMCIA_MFC_DEVICE_MANF_CARD(0, 0x0101, 0x0562),
914 PCMCIA_MFC_DEVICE_PROD_ID1(0, "Motorola MARQUIS", 0xf03e4e77),
915 PCMCIA_DEVICE_MANF_CARD(0x0101, 0x0589),
916 PCMCIA_DEVICE_PROD_ID12("Farallon", "ENet", 0x58d93fc4, 0x992c2202),
Ken Kawasakif0a3a152009-05-01 19:21:26 -0700917 PCMCIA_MFC_DEVICE_CIS_MANF_CARD(0, 0x0101, 0x0035, "cis/3CXEM556.cis"),
918 PCMCIA_MFC_DEVICE_CIS_MANF_CARD(0, 0x0101, 0x003d, "cis/3CXEM556.cis"),
Dominik Brodowski7ffec582005-06-27 16:28:19 -0700919 PCMCIA_DEVICE_NULL,
920};
921MODULE_DEVICE_TABLE(pcmcia, tc589_ids);
922
Linus Torvalds1da177e2005-04-16 15:20:36 -0700923static struct pcmcia_driver tc589_driver = {
924 .owner = THIS_MODULE,
Dominik Brodowski2e9b9812010-08-08 11:36:26 +0200925 .name = "3c589_cs",
Dominik Brodowski15b99ac2006-03-31 17:26:06 +0200926 .probe = tc589_probe,
Dominik Brodowskicc3b4862005-11-14 21:23:14 +0100927 .remove = tc589_detach,
Alexander Kurzf64e9692010-03-31 02:42:10 +0000928 .id_table = tc589_ids,
Dominik Brodowski98e4c282005-11-14 21:21:18 +0100929 .suspend = tc589_suspend,
930 .resume = tc589_resume,
Linus Torvalds1da177e2005-04-16 15:20:36 -0700931};
932
933static int __init init_tc589(void)
934{
935 return pcmcia_register_driver(&tc589_driver);
936}
937
938static void __exit exit_tc589(void)
939{
940 pcmcia_unregister_driver(&tc589_driver);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700941}
942
943module_init(init_tc589);
944module_exit(exit_tc589);