blob: 7f2baf5eae26a1543a87f681379c71df95638d2c [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/cs.h>
47#include <pcmcia/cistpl.h>
48#include <pcmcia/cisreg.h>
49#include <pcmcia/ciscode.h>
50#include <pcmcia/ds.h>
51
52#include <asm/uaccess.h>
53#include <asm/io.h>
54#include <asm/system.h>
55
56/* To minimize the size of the driver source I only define operating
57 constants if they are used several times. You'll need the manual
58 if you want to understand driver details. */
59/* Offsets from base I/O address. */
60#define EL3_DATA 0x00
61#define EL3_TIMER 0x0a
62#define EL3_CMD 0x0e
63#define EL3_STATUS 0x0e
64
65#define EEPROM_READ 0x0080
66#define EEPROM_BUSY 0x8000
67
68#define EL3WINDOW(win_num) outw(SelectWindow + (win_num), ioaddr + EL3_CMD)
69
70/* The top five bits written to EL3_CMD are a command, the lower
71 11 bits are the parameter, if applicable. */
72enum c509cmd {
Alexander Kurzf64e9692010-03-31 02:42:10 +000073 TotalReset = 0<<11,
74 SelectWindow = 1<<11,
75 StartCoax = 2<<11,
76 RxDisable = 3<<11,
77 RxEnable = 4<<11,
78 RxReset = 5<<11,
79 RxDiscard = 8<<11,
80 TxEnable = 9<<11,
81 TxDisable = 10<<11,
82 TxReset = 11<<11,
83 FakeIntr = 12<<11,
84 AckIntr = 13<<11,
85 SetIntrEnb = 14<<11,
86 SetStatusEnb = 15<<11,
87 SetRxFilter = 16<<11,
88 SetRxThreshold = 17<<11,
89 SetTxThreshold = 18<<11,
90 SetTxStart = 19<<11,
91 StatsEnable = 21<<11,
92 StatsDisable = 22<<11,
93 StopCoax = 23<<11
Linus Torvalds1da177e2005-04-16 15:20:36 -070094};
95
96enum c509status {
Alexander Kurzf64e9692010-03-31 02:42:10 +000097 IntLatch = 0x0001,
98 AdapterFailure = 0x0002,
99 TxComplete = 0x0004,
100 TxAvailable = 0x0008,
101 RxComplete = 0x0010,
102 RxEarly = 0x0020,
103 IntReq = 0x0040,
104 StatsFull = 0x0080,
105 CmdBusy = 0x1000
Linus Torvalds1da177e2005-04-16 15:20:36 -0700106};
107
108/* The SetRxFilter command accepts the following classes: */
109enum RxFilter {
Alexander Kurzf64e9692010-03-31 02:42:10 +0000110 RxStation = 1,
111 RxMulticast = 2,
112 RxBroadcast = 4,
113 RxProm = 8
Linus Torvalds1da177e2005-04-16 15:20:36 -0700114};
115
116/* Register window 1 offsets, the window used in normal operation. */
117#define TX_FIFO 0x00
118#define RX_FIFO 0x00
Alexander Kurzf64e9692010-03-31 02:42:10 +0000119#define RX_STATUS 0x08
120#define TX_STATUS 0x0B
Linus Torvalds1da177e2005-04-16 15:20:36 -0700121#define TX_FREE 0x0C /* Remaining free bytes in Tx buffer. */
122
123#define WN0_IRQ 0x08 /* Window 0: Set IRQ line in bits 12-15. */
124#define WN4_MEDIA 0x0A /* Window 4: Various transcvr/media bits. */
125#define MEDIA_TP 0x00C0 /* Enable link beat and jabber for 10baseT. */
126#define MEDIA_LED 0x0001 /* Enable link light on 3C589E cards. */
127
128/* Time in jiffies before concluding Tx hung */
129#define TX_TIMEOUT ((400*HZ)/1000)
130
131struct el3_private {
Dominik Brodowskifd238232006-03-05 10:45:09 +0100132 struct pcmcia_device *p_dev;
Alexander Kurzf64e9692010-03-31 02:42:10 +0000133 /* For transceiver monitoring */
134 struct timer_list media;
135 u16 media_status;
136 u16 fast_poll;
137 unsigned long last_irq;
138 spinlock_t lock;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700139};
140
Jeff Garzik21c0f272007-09-25 00:11:34 -0400141static const char *if_names[] = { "auto", "10baseT", "10base2", "AUI" };
Linus Torvalds1da177e2005-04-16 15:20:36 -0700142
143/*====================================================================*/
144
145/* Module parameters */
146
147MODULE_AUTHOR("David Hinds <dahinds@users.sourceforge.net>");
148MODULE_DESCRIPTION("3Com 3c589 series PCMCIA ethernet driver");
149MODULE_LICENSE("GPL");
150
151#define INT_MODULE_PARM(n, v) static int n = v; module_param(n, int, 0)
152
153/* Special hook for setting if_port when module is loaded */
154INT_MODULE_PARM(if_port, 0);
155
Linus Torvalds1da177e2005-04-16 15:20:36 -0700156
157/*====================================================================*/
158
Dominik Brodowski15b99ac2006-03-31 17:26:06 +0200159static int tc589_config(struct pcmcia_device *link);
Dominik Brodowskifba395e2006-03-31 17:21:06 +0200160static void tc589_release(struct pcmcia_device *link);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700161
Olof Johansson906da802008-02-04 22:27:35 -0800162static u16 read_eeprom(unsigned int ioaddr, int index);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700163static void tc589_reset(struct net_device *dev);
164static void media_check(unsigned long arg);
165static int el3_config(struct net_device *dev, struct ifmap *map);
166static int el3_open(struct net_device *dev);
Stephen Hemmingerdbf02fa2009-08-31 19:50:49 +0000167static netdev_tx_t el3_start_xmit(struct sk_buff *skb,
168 struct net_device *dev);
David Howells7d12e782006-10-05 14:55:46 +0100169static irqreturn_t el3_interrupt(int irq, void *dev_id);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700170static void update_stats(struct net_device *dev);
171static struct net_device_stats *el3_get_stats(struct net_device *dev);
172static int el3_rx(struct net_device *dev);
173static int el3_close(struct net_device *dev);
174static void el3_tx_timeout(struct net_device *dev);
Ken Kawasakie445bb42009-07-19 13:08:12 +0000175static void set_rx_mode(struct net_device *dev);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700176static void set_multicast_list(struct net_device *dev);
Jeff Garzik7282d492006-09-13 14:30:00 -0400177static const struct ethtool_ops netdev_ethtool_ops;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700178
Dominik Brodowskicc3b4862005-11-14 21:23:14 +0100179static void tc589_detach(struct pcmcia_device *p_dev);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700180
Linus Torvalds1da177e2005-04-16 15:20:36 -0700181/*======================================================================
182
183 tc589_attach() creates an "instance" of the driver, allocating
184 local data structures for one device. The device is registered
185 with Card Services.
186
187======================================================================*/
188
Stephen Hemminger97161d42009-03-20 19:36:01 +0000189static const struct net_device_ops el3_netdev_ops = {
Alexander Kurzf64e9692010-03-31 02:42:10 +0000190 .ndo_open = el3_open,
191 .ndo_stop = el3_close,
Stephen Hemminger97161d42009-03-20 19:36:01 +0000192 .ndo_start_xmit = el3_start_xmit,
Alexander Kurzf64e9692010-03-31 02:42:10 +0000193 .ndo_tx_timeout = el3_tx_timeout,
Stephen Hemminger97161d42009-03-20 19:36:01 +0000194 .ndo_set_config = el3_config,
195 .ndo_get_stats = el3_get_stats,
196 .ndo_set_multicast_list = set_multicast_list,
197 .ndo_change_mtu = eth_change_mtu,
Alexander Kurzf64e9692010-03-31 02:42:10 +0000198 .ndo_set_mac_address = eth_mac_addr,
Stephen Hemminger97161d42009-03-20 19:36:01 +0000199 .ndo_validate_addr = eth_validate_addr,
200};
201
Dominik Brodowski15b99ac2006-03-31 17:26:06 +0200202static int tc589_probe(struct pcmcia_device *link)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700203{
204 struct el3_private *lp;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700205 struct net_device *dev;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700206
Dominik Brodowskidd0fab52009-10-24 15:51:05 +0200207 dev_dbg(&link->dev, "3c589_attach()\n");
Dominik Brodowskif8cfa612005-11-14 21:25:51 +0100208
Linus Torvalds1da177e2005-04-16 15:20:36 -0700209 /* Create new ethernet device */
210 dev = alloc_etherdev(sizeof(struct el3_private));
211 if (!dev)
Dominik Brodowskif8cfa612005-11-14 21:25:51 +0100212 return -ENOMEM;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700213 lp = netdev_priv(dev);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700214 link->priv = dev;
Dominik Brodowskifba395e2006-03-31 17:21:06 +0200215 lp->p_dev = link;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700216
217 spin_lock_init(&lp->lock);
Dominik Brodowski90abdc32010-07-24 17:23:51 +0200218 link->resource[0]->end = 16;
219 link->resource[0]->flags |= IO_DATA_PATH_WIDTH_16;
Dominik Brodowskieb141202010-03-07 12:21:16 +0100220
Linus Torvalds1da177e2005-04-16 15:20:36 -0700221 link->conf.Attributes = CONF_ENABLE_IRQ;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700222 link->conf.IntType = INT_MEMORY_AND_IO;
223 link->conf.ConfigIndex = 1;
Dominik Brodowskif8cfa612005-11-14 21:25:51 +0100224
Stephen Hemminger97161d42009-03-20 19:36:01 +0000225 dev->netdev_ops = &el3_netdev_ops;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700226 dev->watchdog_timeo = TX_TIMEOUT;
Stephen Hemminger97161d42009-03-20 19:36:01 +0000227
Linus Torvalds1da177e2005-04-16 15:20:36 -0700228 SET_ETHTOOL_OPS(dev, &netdev_ethtool_ops);
229
Dominik Brodowski15b99ac2006-03-31 17:26:06 +0200230 return tc589_config(link);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700231} /* tc589_attach */
232
233/*======================================================================
234
235 This deletes a driver "instance". The device is de-registered
236 with Card Services. If it has been released, all local data
237 structures are freed. Otherwise, the structures will be freed
238 when the device is released.
239
240======================================================================*/
241
Dominik Brodowskifba395e2006-03-31 17:21:06 +0200242static void tc589_detach(struct pcmcia_device *link)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700243{
244 struct net_device *dev = link->priv;
Dominik Brodowskib4635812005-11-14 21:25:35 +0100245
Dominik Brodowskidd0fab52009-10-24 15:51:05 +0200246 dev_dbg(&link->dev, "3c589_detach\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -0700247
Dominik Brodowskic7c2fa02010-03-20 19:39:26 +0100248 unregister_netdev(dev);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700249
Dominik Brodowskie2d40962006-03-02 00:09:29 +0100250 tc589_release(link);
Dominik Brodowskicc3b4862005-11-14 21:23:14 +0100251
Linus Torvalds1da177e2005-04-16 15:20:36 -0700252 free_netdev(dev);
253} /* tc589_detach */
254
255/*======================================================================
256
257 tc589_config() is scheduled to run after a CARD_INSERTION event
258 is received, to configure the PCMCIA socket, and to make the
259 ethernet device available to the system.
Alexander Kurzf64e9692010-03-31 02:42:10 +0000260
Linus Torvalds1da177e2005-04-16 15:20:36 -0700261======================================================================*/
262
Dominik Brodowski15b99ac2006-03-31 17:26:06 +0200263static int tc589_config(struct pcmcia_device *link)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700264{
Linus Torvalds1da177e2005-04-16 15:20:36 -0700265 struct net_device *dev = link->priv;
Al Virob1e247a2007-12-22 18:56:13 +0000266 __be16 *phys_addr;
Dominik Brodowskidd0fab52009-10-24 15:51:05 +0200267 int ret, i, j, multi = 0, fifo;
Olof Johansson906da802008-02-04 22:27:35 -0800268 unsigned int ioaddr;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700269 char *ram_split[] = {"5:3", "3:1", "1:1", "3:5"};
Dominik Brodowskidddfbd82009-10-18 23:54:24 +0200270 u8 *buf;
271 size_t len;
Alexander Kurzf64e9692010-03-31 02:42:10 +0000272
Dominik Brodowskidd0fab52009-10-24 15:51:05 +0200273 dev_dbg(&link->dev, "3c589_config\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -0700274
Al Virob1e247a2007-12-22 18:56:13 +0000275 phys_addr = (__be16 *)dev->dev_addr;
Dominik Brodowskiefd50582006-10-25 21:28:53 -0400276 /* Is this a 3c562? */
277 if (link->manf_id != MANFID_3COM)
Joe Perches636b8112010-08-12 12:22:51 +0000278 dev_info(&link->dev, "hmmm, is this really a 3Com card??\n");
Dominik Brodowskiefd50582006-10-25 21:28:53 -0400279 multi = (link->card_id == PRODID_3COM_3C562);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700280
Dominik Brodowski90abdc32010-07-24 17:23:51 +0200281 link->io_lines = 16;
282
Linus Torvalds1da177e2005-04-16 15:20:36 -0700283 /* For the 3c562, the base address must be xx00-xx7f */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700284 for (i = j = 0; j < 0x400; j += 0x10) {
285 if (multi && (j & 0x80)) continue;
Dominik Brodowski90abdc32010-07-24 17:23:51 +0200286 link->resource[0]->start = j ^ 0x300;
287 i = pcmcia_request_io(link);
Dominik Brodowski4c89e882008-08-03 10:07:45 +0200288 if (i == 0)
289 break;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700290 }
Dominik Brodowskidd0fab52009-10-24 15:51:05 +0200291 if (i != 0)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700292 goto failed;
Dominik Brodowskidd0fab52009-10-24 15:51:05 +0200293
Dominik Brodowskieb141202010-03-07 12:21:16 +0100294 ret = pcmcia_request_irq(link, el3_interrupt);
Dominik Brodowskidd0fab52009-10-24 15:51:05 +0200295 if (ret)
296 goto failed;
297
298 ret = pcmcia_request_configuration(link, &link->conf);
299 if (ret)
300 goto failed;
Alexander Kurzf64e9692010-03-31 02:42:10 +0000301
Dominik Brodowskieb141202010-03-07 12:21:16 +0100302 dev->irq = link->irq;
Dominik Brodowski9a017a92010-07-24 15:58:54 +0200303 dev->base_addr = link->resource[0]->start;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700304 ioaddr = dev->base_addr;
305 EL3WINDOW(0);
306
307 /* The 3c589 has an extra EEPROM for configuration info, including
308 the hardware address. The 3c562 puts the address in the CIS. */
Dominik Brodowskidddfbd82009-10-18 23:54:24 +0200309 len = pcmcia_get_tuple(link, 0x88, &buf);
310 if (buf && len >= 6) {
311 for (i = 0; i < 3; i++)
312 phys_addr[i] = htons(le16_to_cpu(buf[i*2]));
313 kfree(buf);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700314 } else {
Dominik Brodowskidddfbd82009-10-18 23:54:24 +0200315 kfree(buf); /* 0 < len < 6 */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700316 for (i = 0; i < 3; i++)
317 phys_addr[i] = htons(read_eeprom(ioaddr, i));
Al Virob1e247a2007-12-22 18:56:13 +0000318 if (phys_addr[0] == htons(0x6060)) {
Joe Perches636b8112010-08-12 12:22:51 +0000319 dev_err(&link->dev, "IO port conflict at 0x%03lx-0x%03lx\n",
320 dev->base_addr, dev->base_addr+15);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700321 goto failed;
322 }
323 }
324
325 /* The address and resource configuration register aren't loaded from
326 the EEPROM and *must* be set to 0 and IRQ3 for the PCMCIA version. */
327 outw(0x3f00, ioaddr + 8);
328 fifo = inl(ioaddr);
329
330 /* The if_port symbol can be set when the module is loaded */
331 if ((if_port >= 0) && (if_port <= 3))
332 dev->if_port = if_port;
333 else
Joe Perches636b8112010-08-12 12:22:51 +0000334 dev_err(&link->dev, "invalid if_port requested\n");
Alexander Kurzf64e9692010-03-31 02:42:10 +0000335
Dominik Brodowskidd2e5a12009-11-03 10:27:34 +0100336 SET_NETDEV_DEV(dev, &link->dev);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700337
338 if (register_netdev(dev) != 0) {
Joe Perches636b8112010-08-12 12:22:51 +0000339 dev_err(&link->dev, "register_netdev() failed\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -0700340 goto failed;
341 }
342
Alexander Kurzf64e9692010-03-31 02:42:10 +0000343 netdev_info(dev, "3Com 3c%s, io %#3lx, irq %d, hw_addr %pM\n",
344 (multi ? "562" : "589"), dev->base_addr, dev->irq,
345 dev->dev_addr);
346 netdev_info(dev, " %dK FIFO split %s Rx:Tx, %s xcvr\n",
347 (fifo & 7) ? 32 : 8, ram_split[(fifo >> 16) & 3],
348 if_names[dev->if_port]);
Dominik Brodowski15b99ac2006-03-31 17:26:06 +0200349 return 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700350
Linus Torvalds1da177e2005-04-16 15:20:36 -0700351failed:
352 tc589_release(link);
Dominik Brodowski15b99ac2006-03-31 17:26:06 +0200353 return -ENODEV;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700354} /* tc589_config */
355
356/*======================================================================
357
358 After a card is removed, tc589_release() will unregister the net
359 device, and release the PCMCIA configuration. If the device is
360 still open, this will be postponed until it is closed.
Alexander Kurzf64e9692010-03-31 02:42:10 +0000361
Linus Torvalds1da177e2005-04-16 15:20:36 -0700362======================================================================*/
363
Dominik Brodowskifba395e2006-03-31 17:21:06 +0200364static void tc589_release(struct pcmcia_device *link)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700365{
Dominik Brodowskifba395e2006-03-31 17:21:06 +0200366 pcmcia_disable_device(link);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700367}
368
Dominik Brodowskifba395e2006-03-31 17:21:06 +0200369static int tc589_suspend(struct pcmcia_device *link)
Dominik Brodowski98e4c282005-11-14 21:21:18 +0100370{
Dominik Brodowski98e4c282005-11-14 21:21:18 +0100371 struct net_device *dev = link->priv;
372
Dominik Brodowskie2d40962006-03-02 00:09:29 +0100373 if (link->open)
Dominik Brodowski8661bb52006-03-02 00:02:33 +0100374 netif_device_detach(dev);
Dominik Brodowski98e4c282005-11-14 21:21:18 +0100375
376 return 0;
377}
378
Dominik Brodowskifba395e2006-03-31 17:21:06 +0200379static int tc589_resume(struct pcmcia_device *link)
Dominik Brodowski98e4c282005-11-14 21:21:18 +0100380{
Dominik Brodowski98e4c282005-11-14 21:21:18 +0100381 struct net_device *dev = link->priv;
382
Alexander Kurzf64e9692010-03-31 02:42:10 +0000383 if (link->open) {
Dominik Brodowski8661bb52006-03-02 00:02:33 +0100384 tc589_reset(dev);
385 netif_device_attach(dev);
Dominik Brodowski98e4c282005-11-14 21:21:18 +0100386 }
387
388 return 0;
389}
390
Linus Torvalds1da177e2005-04-16 15:20:36 -0700391/*====================================================================*/
392
393/*
394 Use this for commands that may take time to finish
395*/
396static void tc589_wait_for_completion(struct net_device *dev, int cmd)
397{
398 int i = 100;
399 outw(cmd, dev->base_addr + EL3_CMD);
400 while (--i > 0)
401 if (!(inw(dev->base_addr + EL3_STATUS) & 0x1000)) break;
402 if (i == 0)
Alexander Kurzf64e9692010-03-31 02:42:10 +0000403 netdev_warn(dev, "command 0x%04x did not complete!\n", cmd);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700404}
405
406/*
407 Read a word from the EEPROM using the regular EEPROM access register.
408 Assume that we are in register window zero.
409*/
Olof Johansson906da802008-02-04 22:27:35 -0800410static u16 read_eeprom(unsigned int ioaddr, int index)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700411{
412 int i;
413 outw(EEPROM_READ + index, ioaddr + 10);
414 /* Reading the eeprom takes 162 us */
415 for (i = 1620; i >= 0; i--)
416 if ((inw(ioaddr + 10) & EEPROM_BUSY) == 0)
417 break;
418 return inw(ioaddr + 12);
419}
420
421/*
422 Set transceiver type, perhaps to something other than what the user
423 specified in dev->if_port.
424*/
425static void tc589_set_xcvr(struct net_device *dev, int if_port)
426{
427 struct el3_private *lp = netdev_priv(dev);
Olof Johansson906da802008-02-04 22:27:35 -0800428 unsigned int ioaddr = dev->base_addr;
Alexander Kurzf64e9692010-03-31 02:42:10 +0000429
Linus Torvalds1da177e2005-04-16 15:20:36 -0700430 EL3WINDOW(0);
431 switch (if_port) {
432 case 0: case 1: outw(0, ioaddr + 6); break;
433 case 2: outw(3<<14, ioaddr + 6); break;
434 case 3: outw(1<<14, ioaddr + 6); break;
435 }
436 /* On PCMCIA, this just turns on the LED */
437 outw((if_port == 2) ? StartCoax : StopCoax, ioaddr + EL3_CMD);
438 /* 10baseT interface, enable link beat and jabber check. */
439 EL3WINDOW(4);
440 outw(MEDIA_LED | ((if_port < 2) ? MEDIA_TP : 0), ioaddr + WN4_MEDIA);
441 EL3WINDOW(1);
442 if (if_port == 2)
443 lp->media_status = ((dev->if_port == 0) ? 0x8000 : 0x4000);
444 else
445 lp->media_status = ((dev->if_port == 0) ? 0x4010 : 0x8800);
446}
447
448static void dump_status(struct net_device *dev)
449{
Olof Johansson906da802008-02-04 22:27:35 -0800450 unsigned int ioaddr = dev->base_addr;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700451 EL3WINDOW(1);
Alexander Kurzf64e9692010-03-31 02:42:10 +0000452 netdev_info(dev, " irq status %04x, rx status %04x, tx status %02x tx free %04x\n",
453 inw(ioaddr+EL3_STATUS), inw(ioaddr+RX_STATUS),
454 inb(ioaddr+TX_STATUS), inw(ioaddr+TX_FREE));
Linus Torvalds1da177e2005-04-16 15:20:36 -0700455 EL3WINDOW(4);
Alexander Kurzf64e9692010-03-31 02:42:10 +0000456 netdev_info(dev, " diagnostics: fifo %04x net %04x ethernet %04x media %04x\n",
457 inw(ioaddr+0x04), inw(ioaddr+0x06), inw(ioaddr+0x08),
458 inw(ioaddr+0x0a));
Linus Torvalds1da177e2005-04-16 15:20:36 -0700459 EL3WINDOW(1);
460}
461
462/* Reset and restore all of the 3c589 registers. */
463static void tc589_reset(struct net_device *dev)
464{
Olof Johansson906da802008-02-04 22:27:35 -0800465 unsigned int ioaddr = dev->base_addr;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700466 int i;
Alexander Kurzf64e9692010-03-31 02:42:10 +0000467
Linus Torvalds1da177e2005-04-16 15:20:36 -0700468 EL3WINDOW(0);
Alexander Kurzf64e9692010-03-31 02:42:10 +0000469 outw(0x0001, ioaddr + 4); /* Activate board. */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700470 outw(0x3f00, ioaddr + 8); /* Set the IRQ line. */
Alexander Kurzf64e9692010-03-31 02:42:10 +0000471
Linus Torvalds1da177e2005-04-16 15:20:36 -0700472 /* Set the station address in window 2. */
473 EL3WINDOW(2);
474 for (i = 0; i < 6; i++)
475 outb(dev->dev_addr[i], ioaddr + i);
476
477 tc589_set_xcvr(dev, dev->if_port);
Alexander Kurzf64e9692010-03-31 02:42:10 +0000478
Linus Torvalds1da177e2005-04-16 15:20:36 -0700479 /* Switch to the stats window, and clear all stats by reading. */
480 outw(StatsDisable, ioaddr + EL3_CMD);
481 EL3WINDOW(6);
482 for (i = 0; i < 9; i++)
483 inb(ioaddr+i);
484 inw(ioaddr + 10);
485 inw(ioaddr + 12);
Alexander Kurzf64e9692010-03-31 02:42:10 +0000486
Linus Torvalds1da177e2005-04-16 15:20:36 -0700487 /* Switch to register set 1 for normal use. */
488 EL3WINDOW(1);
489
Ken Kawasakie445bb42009-07-19 13:08:12 +0000490 set_rx_mode(dev);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700491 outw(StatsEnable, ioaddr + EL3_CMD); /* Turn on statistics. */
492 outw(RxEnable, ioaddr + EL3_CMD); /* Enable the receiver. */
493 outw(TxEnable, ioaddr + EL3_CMD); /* Enable transmitter. */
494 /* Allow status bits to be seen. */
495 outw(SetStatusEnb | 0xff, ioaddr + EL3_CMD);
496 /* Ack all pending events, and set active indicator mask. */
497 outw(AckIntr | IntLatch | TxAvailable | RxEarly | IntReq,
498 ioaddr + EL3_CMD);
499 outw(SetIntrEnb | IntLatch | TxAvailable | RxComplete | StatsFull
500 | AdapterFailure, ioaddr + EL3_CMD);
501}
502
503static void netdev_get_drvinfo(struct net_device *dev,
504 struct ethtool_drvinfo *info)
505{
506 strcpy(info->driver, DRV_NAME);
507 strcpy(info->version, DRV_VERSION);
508 sprintf(info->bus_info, "PCMCIA 0x%lx", dev->base_addr);
509}
510
Jeff Garzik7282d492006-09-13 14:30:00 -0400511static const struct ethtool_ops netdev_ethtool_ops = {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700512 .get_drvinfo = netdev_get_drvinfo,
Linus Torvalds1da177e2005-04-16 15:20:36 -0700513};
514
515static int el3_config(struct net_device *dev, struct ifmap *map)
516{
517 if ((map->port != (u_char)(-1)) && (map->port != dev->if_port)) {
518 if (map->port <= 3) {
519 dev->if_port = map->port;
Alexander Kurzf64e9692010-03-31 02:42:10 +0000520 netdev_info(dev, "switched to %s port\n", if_names[dev->if_port]);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700521 tc589_set_xcvr(dev, dev->if_port);
522 } else
523 return -EINVAL;
524 }
525 return 0;
526}
527
528static int el3_open(struct net_device *dev)
529{
530 struct el3_private *lp = netdev_priv(dev);
Dominik Brodowskifba395e2006-03-31 17:21:06 +0200531 struct pcmcia_device *link = lp->p_dev;
Alexander Kurzf64e9692010-03-31 02:42:10 +0000532
Dominik Brodowski9940ec32006-03-05 11:04:33 +0100533 if (!pcmcia_dev_present(link))
Linus Torvalds1da177e2005-04-16 15:20:36 -0700534 return -ENODEV;
535
536 link->open++;
537 netif_start_queue(dev);
Alexander Kurzf64e9692010-03-31 02:42:10 +0000538
Linus Torvalds1da177e2005-04-16 15:20:36 -0700539 tc589_reset(dev);
540 init_timer(&lp->media);
Joe Perchesc061b182010-08-23 18:20:03 +0000541 lp->media.function = media_check;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700542 lp->media.data = (unsigned long) dev;
543 lp->media.expires = jiffies + HZ;
544 add_timer(&lp->media);
545
Dominik Brodowskidd0fab52009-10-24 15:51:05 +0200546 dev_dbg(&link->dev, "%s: opened, status %4.4x.\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -0700547 dev->name, inw(dev->base_addr + EL3_STATUS));
Alexander Kurzf64e9692010-03-31 02:42:10 +0000548
Linus Torvalds1da177e2005-04-16 15:20:36 -0700549 return 0;
550}
551
552static void el3_tx_timeout(struct net_device *dev)
553{
Olof Johansson906da802008-02-04 22:27:35 -0800554 unsigned int ioaddr = dev->base_addr;
Alexander Kurzf64e9692010-03-31 02:42:10 +0000555
556 netdev_warn(dev, "Transmit timed out!\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -0700557 dump_status(dev);
Paulius Zaleckascd652842008-04-30 01:20:20 +0300558 dev->stats.tx_errors++;
Eric Dumazet1ae5dc32010-05-10 05:01:31 -0700559 dev->trans_start = jiffies; /* prevent tx timeout */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700560 /* Issue TX_RESET and TX_START commands. */
561 tc589_wait_for_completion(dev, TxReset);
562 outw(TxEnable, ioaddr + EL3_CMD);
563 netif_wake_queue(dev);
564}
565
566static void pop_tx_status(struct net_device *dev)
567{
Olof Johansson906da802008-02-04 22:27:35 -0800568 unsigned int ioaddr = dev->base_addr;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700569 int i;
Alexander Kurzf64e9692010-03-31 02:42:10 +0000570
Linus Torvalds1da177e2005-04-16 15:20:36 -0700571 /* Clear the Tx status stack. */
572 for (i = 32; i > 0; i--) {
573 u_char tx_status = inb(ioaddr + TX_STATUS);
574 if (!(tx_status & 0x84)) break;
575 /* reset transmitter on jabber error or underrun */
576 if (tx_status & 0x30)
Alexander Kurzf64e9692010-03-31 02:42:10 +0000577 tc589_wait_for_completion(dev, TxReset);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700578 if (tx_status & 0x38) {
Alexander Kurzf64e9692010-03-31 02:42:10 +0000579 netdev_dbg(dev, "transmit error: status 0x%02x\n", tx_status);
580 outw(TxEnable, ioaddr + EL3_CMD);
581 dev->stats.tx_aborted_errors++;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700582 }
583 outb(0x00, ioaddr + TX_STATUS); /* Pop the status stack. */
584 }
585}
586
Stephen Hemmingerdbf02fa2009-08-31 19:50:49 +0000587static netdev_tx_t el3_start_xmit(struct sk_buff *skb,
588 struct net_device *dev)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700589{
Olof Johansson906da802008-02-04 22:27:35 -0800590 unsigned int ioaddr = dev->base_addr;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700591 struct el3_private *priv = netdev_priv(dev);
Komurod08d2832006-12-02 11:53:27 +0900592 unsigned long flags;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700593
Alexander Kurzf64e9692010-03-31 02:42:10 +0000594 netdev_dbg(dev, "el3_start_xmit(length = %ld) called, status %4.4x.\n",
595 (long)skb->len, inw(ioaddr + EL3_STATUS));
Linus Torvalds1da177e2005-04-16 15:20:36 -0700596
Alexander Kurzf64e9692010-03-31 02:42:10 +0000597 spin_lock_irqsave(&priv->lock, flags);
Komurod08d2832006-12-02 11:53:27 +0900598
Paulius Zaleckascd652842008-04-30 01:20:20 +0300599 dev->stats.tx_bytes += skb->len;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700600
601 /* Put out the doubleword header... */
602 outw(skb->len, ioaddr + TX_FIFO);
603 outw(0x00, ioaddr + TX_FIFO);
604 /* ... and the packet rounded to a doubleword. */
605 outsl(ioaddr + TX_FIFO, skb->data, (skb->len + 3) >> 2);
606
Linus Torvalds1da177e2005-04-16 15:20:36 -0700607 if (inw(ioaddr + TX_FREE) <= 1536) {
608 netif_stop_queue(dev);
609 /* Interrupt us when the FIFO has room for max-sized packet. */
610 outw(SetTxThreshold + 1536, ioaddr + EL3_CMD);
611 }
612
Linus Torvalds1da177e2005-04-16 15:20:36 -0700613 pop_tx_status(dev);
Alexander Kurzf64e9692010-03-31 02:42:10 +0000614 spin_unlock_irqrestore(&priv->lock, flags);
Patrick McHardy63ac9b92007-07-02 16:08:28 +0200615 dev_kfree_skb(skb);
Alexander Kurzf64e9692010-03-31 02:42:10 +0000616
Patrick McHardy6ed10652009-06-23 06:03:08 +0000617 return NETDEV_TX_OK;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700618}
619
620/* The EL3 interrupt handler. */
David Howells7d12e782006-10-05 14:55:46 +0100621static irqreturn_t el3_interrupt(int irq, void *dev_id)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700622{
623 struct net_device *dev = (struct net_device *) dev_id;
624 struct el3_private *lp = netdev_priv(dev);
Olof Johansson906da802008-02-04 22:27:35 -0800625 unsigned int ioaddr;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700626 __u16 status;
627 int i = 0, handled = 1;
Alexander Kurzf64e9692010-03-31 02:42:10 +0000628
Linus Torvalds1da177e2005-04-16 15:20:36 -0700629 if (!netif_device_present(dev))
630 return IRQ_NONE;
631
632 ioaddr = dev->base_addr;
633
Alexander Kurzf64e9692010-03-31 02:42:10 +0000634 netdev_dbg(dev, "interrupt, status %4.4x.\n", inw(ioaddr + EL3_STATUS));
Linus Torvalds1da177e2005-04-16 15:20:36 -0700635
Alexander Kurzf64e9692010-03-31 02:42:10 +0000636 spin_lock(&lp->lock);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700637 while ((status = inw(ioaddr + EL3_STATUS)) &
638 (IntLatch | RxComplete | StatsFull)) {
639 if ((status & 0xe000) != 0x2000) {
Alexander Kurzf64e9692010-03-31 02:42:10 +0000640 netdev_dbg(dev, "interrupt from dead card\n");
641 handled = 0;
642 break;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700643 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700644 if (status & RxComplete)
Alexander Kurzf64e9692010-03-31 02:42:10 +0000645 el3_rx(dev);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700646 if (status & TxAvailable) {
Alexander Kurzf64e9692010-03-31 02:42:10 +0000647 netdev_dbg(dev, " TX room bit was handled.\n");
648 /* There's room in the FIFO for a full-sized packet. */
649 outw(AckIntr | TxAvailable, ioaddr + EL3_CMD);
650 netif_wake_queue(dev);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700651 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700652 if (status & TxComplete)
Alexander Kurzf64e9692010-03-31 02:42:10 +0000653 pop_tx_status(dev);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700654 if (status & (AdapterFailure | RxEarly | StatsFull)) {
655 /* Handle all uncommon interrupts. */
656 if (status & StatsFull) /* Empty statistics. */
657 update_stats(dev);
658 if (status & RxEarly) { /* Rx early is unused. */
659 el3_rx(dev);
660 outw(AckIntr | RxEarly, ioaddr + EL3_CMD);
661 }
662 if (status & AdapterFailure) {
663 u16 fifo_diag;
664 EL3WINDOW(4);
665 fifo_diag = inw(ioaddr + 4);
666 EL3WINDOW(1);
Alexander Kurzf64e9692010-03-31 02:42:10 +0000667 netdev_warn(dev, "adapter failure, FIFO diagnostic register %04x.\n",
668 fifo_diag);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700669 if (fifo_diag & 0x0400) {
670 /* Tx overrun */
671 tc589_wait_for_completion(dev, TxReset);
672 outw(TxEnable, ioaddr + EL3_CMD);
673 }
674 if (fifo_diag & 0x2000) {
675 /* Rx underrun */
676 tc589_wait_for_completion(dev, RxReset);
Ken Kawasakie445bb42009-07-19 13:08:12 +0000677 set_rx_mode(dev);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700678 outw(RxEnable, ioaddr + EL3_CMD);
679 }
680 outw(AckIntr | AdapterFailure, ioaddr + EL3_CMD);
681 }
682 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700683 if (++i > 10) {
Alexander Kurzf64e9692010-03-31 02:42:10 +0000684 netdev_err(dev, "infinite loop in interrupt, status %4.4x.\n",
685 status);
686 /* Clear all interrupts */
687 outw(AckIntr | 0xFF, ioaddr + EL3_CMD);
688 break;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700689 }
690 /* Acknowledge the IRQ. */
691 outw(AckIntr | IntReq | IntLatch, ioaddr + EL3_CMD);
692 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700693 lp->last_irq = jiffies;
Alexander Kurzf64e9692010-03-31 02:42:10 +0000694 spin_unlock(&lp->lock);
695 netdev_dbg(dev, "exiting interrupt, status %4.4x.\n",
696 inw(ioaddr + EL3_STATUS));
Linus Torvalds1da177e2005-04-16 15:20:36 -0700697 return IRQ_RETVAL(handled);
698}
699
700static void media_check(unsigned long arg)
701{
702 struct net_device *dev = (struct net_device *)(arg);
703 struct el3_private *lp = netdev_priv(dev);
Olof Johansson906da802008-02-04 22:27:35 -0800704 unsigned int ioaddr = dev->base_addr;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700705 u16 media, errs;
706 unsigned long flags;
707
708 if (!netif_device_present(dev)) goto reschedule;
709
Linus Torvalds1da177e2005-04-16 15:20:36 -0700710 /* Check for pending interrupt with expired latency timer: with
711 this, we can limp along even if the interrupt is blocked */
712 if ((inw(ioaddr + EL3_STATUS) & IntLatch) &&
713 (inb(ioaddr + EL3_TIMER) == 0xff)) {
714 if (!lp->fast_poll)
Alexander Kurzf64e9692010-03-31 02:42:10 +0000715 netdev_warn(dev, "interrupt(s) dropped!\n");
Ken Kawasaki671c8802009-12-12 14:44:11 +0000716
717 local_irq_save(flags);
Komurod08d2832006-12-02 11:53:27 +0900718 el3_interrupt(dev->irq, dev);
Ken Kawasaki671c8802009-12-12 14:44:11 +0000719 local_irq_restore(flags);
720
Linus Torvalds1da177e2005-04-16 15:20:36 -0700721 lp->fast_poll = HZ;
722 }
723 if (lp->fast_poll) {
724 lp->fast_poll--;
725 lp->media.expires = jiffies + HZ/100;
726 add_timer(&lp->media);
727 return;
728 }
729
730 /* lp->lock guards the EL3 window. Window should always be 1 except
731 when the lock is held */
Alexander Kurzf64e9692010-03-31 02:42:10 +0000732 spin_lock_irqsave(&lp->lock, flags);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700733 EL3WINDOW(4);
734 media = inw(ioaddr+WN4_MEDIA) & 0xc810;
735
736 /* Ignore collisions unless we've had no irq's recently */
Marcelo Feitoza Parisiff5688a2006-01-09 18:37:15 -0800737 if (time_before(jiffies, lp->last_irq + HZ)) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700738 media &= ~0x0010;
739 } else {
740 /* Try harder to detect carrier errors */
741 EL3WINDOW(6);
742 outw(StatsDisable, ioaddr + EL3_CMD);
743 errs = inb(ioaddr + 0);
744 outw(StatsEnable, ioaddr + EL3_CMD);
Paulius Zaleckascd652842008-04-30 01:20:20 +0300745 dev->stats.tx_carrier_errors += errs;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700746 if (errs || (lp->media_status & 0x0010)) media |= 0x0010;
747 }
748
749 if (media != lp->media_status) {
750 if ((media & lp->media_status & 0x8000) &&
751 ((lp->media_status ^ media) & 0x0800))
Alexander Kurzf64e9692010-03-31 02:42:10 +0000752 netdev_info(dev, "%s link beat\n",
753 (lp->media_status & 0x0800 ? "lost" : "found"));
Linus Torvalds1da177e2005-04-16 15:20:36 -0700754 else if ((media & lp->media_status & 0x4000) &&
755 ((lp->media_status ^ media) & 0x0010))
Alexander Kurzf64e9692010-03-31 02:42:10 +0000756 netdev_info(dev, "coax cable %s\n",
757 (lp->media_status & 0x0010 ? "ok" : "problem"));
Linus Torvalds1da177e2005-04-16 15:20:36 -0700758 if (dev->if_port == 0) {
759 if (media & 0x8000) {
760 if (media & 0x0800)
Alexander Kurzf64e9692010-03-31 02:42:10 +0000761 netdev_info(dev, "flipped to 10baseT\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -0700762 else
Alexander Kurzf64e9692010-03-31 02:42:10 +0000763 tc589_set_xcvr(dev, 2);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700764 } else if (media & 0x4000) {
765 if (media & 0x0010)
766 tc589_set_xcvr(dev, 1);
767 else
Alexander Kurzf64e9692010-03-31 02:42:10 +0000768 netdev_info(dev, "flipped to 10base2\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -0700769 }
770 }
771 lp->media_status = media;
772 }
Alexander Kurzf64e9692010-03-31 02:42:10 +0000773
Linus Torvalds1da177e2005-04-16 15:20:36 -0700774 EL3WINDOW(1);
Alexander Kurzf64e9692010-03-31 02:42:10 +0000775 spin_unlock_irqrestore(&lp->lock, flags);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700776
777reschedule:
778 lp->media.expires = jiffies + HZ;
779 add_timer(&lp->media);
780}
781
782static struct net_device_stats *el3_get_stats(struct net_device *dev)
783{
784 struct el3_private *lp = netdev_priv(dev);
785 unsigned long flags;
Dominik Brodowskifba395e2006-03-31 17:21:06 +0200786 struct pcmcia_device *link = lp->p_dev;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700787
Dominik Brodowski9940ec32006-03-05 11:04:33 +0100788 if (pcmcia_dev_present(link)) {
Alexander Kurzf64e9692010-03-31 02:42:10 +0000789 spin_lock_irqsave(&lp->lock, flags);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700790 update_stats(dev);
791 spin_unlock_irqrestore(&lp->lock, flags);
792 }
Paulius Zaleckascd652842008-04-30 01:20:20 +0300793 return &dev->stats;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700794}
795
796/*
797 Update statistics. We change to register window 6, so this should be run
798 single-threaded if the device is active. This is expected to be a rare
799 operation, and it's simpler for the rest of the driver to assume that
800 window 1 is always valid rather than use a special window-state variable.
Alexander Kurzf64e9692010-03-31 02:42:10 +0000801
Linus Torvalds1da177e2005-04-16 15:20:36 -0700802 Caller must hold the lock for this
803*/
804static void update_stats(struct net_device *dev)
805{
Olof Johansson906da802008-02-04 22:27:35 -0800806 unsigned int ioaddr = dev->base_addr;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700807
Alexander Kurzf64e9692010-03-31 02:42:10 +0000808 netdev_dbg(dev, "updating the statistics.\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -0700809 /* Turn off statistics updates while reading. */
810 outw(StatsDisable, ioaddr + EL3_CMD);
811 /* Switch to the stats window, and read everything. */
812 EL3WINDOW(6);
Alexander Kurzf64e9692010-03-31 02:42:10 +0000813 dev->stats.tx_carrier_errors += inb(ioaddr + 0);
Paulius Zaleckascd652842008-04-30 01:20:20 +0300814 dev->stats.tx_heartbeat_errors += inb(ioaddr + 1);
Alexander Kurzf64e9692010-03-31 02:42:10 +0000815 /* Multiple collisions. */ inb(ioaddr + 2);
Paulius Zaleckascd652842008-04-30 01:20:20 +0300816 dev->stats.collisions += inb(ioaddr + 3);
817 dev->stats.tx_window_errors += inb(ioaddr + 4);
818 dev->stats.rx_fifo_errors += inb(ioaddr + 5);
819 dev->stats.tx_packets += inb(ioaddr + 6);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700820 /* Rx packets */ inb(ioaddr + 7);
821 /* Tx deferrals */ inb(ioaddr + 8);
822 /* Rx octets */ inw(ioaddr + 10);
823 /* Tx octets */ inw(ioaddr + 12);
Alexander Kurzf64e9692010-03-31 02:42:10 +0000824
Linus Torvalds1da177e2005-04-16 15:20:36 -0700825 /* Back to window 1, and turn statistics back on. */
826 EL3WINDOW(1);
827 outw(StatsEnable, ioaddr + EL3_CMD);
828}
829
830static int el3_rx(struct net_device *dev)
831{
Olof Johansson906da802008-02-04 22:27:35 -0800832 unsigned int ioaddr = dev->base_addr;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700833 int worklimit = 32;
834 short rx_status;
Alexander Kurzf64e9692010-03-31 02:42:10 +0000835
836 netdev_dbg(dev, "in rx_packet(), status %4.4x, rx_status %4.4x.\n",
837 inw(ioaddr+EL3_STATUS), inw(ioaddr+RX_STATUS));
Linus Torvalds1da177e2005-04-16 15:20:36 -0700838 while (!((rx_status = inw(ioaddr + RX_STATUS)) & 0x8000) &&
Roel Kluinb9bdcd92009-03-04 00:05:56 -0800839 worklimit > 0) {
840 worklimit--;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700841 if (rx_status & 0x4000) { /* Error, update stats. */
842 short error = rx_status & 0x3800;
Paulius Zaleckascd652842008-04-30 01:20:20 +0300843 dev->stats.rx_errors++;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700844 switch (error) {
Paulius Zaleckascd652842008-04-30 01:20:20 +0300845 case 0x0000: dev->stats.rx_over_errors++; break;
846 case 0x0800: dev->stats.rx_length_errors++; break;
847 case 0x1000: dev->stats.rx_frame_errors++; break;
848 case 0x1800: dev->stats.rx_length_errors++; break;
849 case 0x2000: dev->stats.rx_frame_errors++; break;
850 case 0x2800: dev->stats.rx_crc_errors++; break;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700851 }
852 } else {
853 short pkt_len = rx_status & 0x7ff;
854 struct sk_buff *skb;
Alexander Kurzf64e9692010-03-31 02:42:10 +0000855
Linus Torvalds1da177e2005-04-16 15:20:36 -0700856 skb = dev_alloc_skb(pkt_len+5);
Alexander Kurzf64e9692010-03-31 02:42:10 +0000857
858 netdev_dbg(dev, " Receiving packet size %d status %4.4x.\n",
859 pkt_len, rx_status);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700860 if (skb != NULL) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700861 skb_reserve(skb, 2);
862 insl(ioaddr+RX_FIFO, skb_put(skb, pkt_len),
863 (pkt_len+3)>>2);
864 skb->protocol = eth_type_trans(skb, dev);
865 netif_rx(skb);
Paulius Zaleckascd652842008-04-30 01:20:20 +0300866 dev->stats.rx_packets++;
867 dev->stats.rx_bytes += pkt_len;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700868 } else {
Alexander Kurzf64e9692010-03-31 02:42:10 +0000869 netdev_dbg(dev, "couldn't allocate a sk_buff of size %d.\n",
870 pkt_len);
Paulius Zaleckascd652842008-04-30 01:20:20 +0300871 dev->stats.rx_dropped++;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700872 }
873 }
874 /* Pop the top of the Rx FIFO */
875 tc589_wait_for_completion(dev, RxDiscard);
876 }
877 if (worklimit == 0)
Alexander Kurzf64e9692010-03-31 02:42:10 +0000878 netdev_warn(dev, "too much work in el3_rx!\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -0700879 return 0;
880}
881
Ken Kawasakie445bb42009-07-19 13:08:12 +0000882static void set_rx_mode(struct net_device *dev)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700883{
Olof Johansson906da802008-02-04 22:27:35 -0800884 unsigned int ioaddr = dev->base_addr;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700885 u16 opts = SetRxFilter | RxStation | RxBroadcast;
886
Linus Torvalds1da177e2005-04-16 15:20:36 -0700887 if (dev->flags & IFF_PROMISC)
888 opts |= RxMulticast | RxProm;
Jiri Pirko4cd24ea2010-02-08 04:30:35 +0000889 else if (!netdev_mc_empty(dev) || (dev->flags & IFF_ALLMULTI))
Linus Torvalds1da177e2005-04-16 15:20:36 -0700890 opts |= RxMulticast;
891 outw(opts, ioaddr + EL3_CMD);
892}
893
Ken Kawasakie445bb42009-07-19 13:08:12 +0000894static void set_multicast_list(struct net_device *dev)
895{
896 struct el3_private *priv = netdev_priv(dev);
897 unsigned long flags;
898
899 spin_lock_irqsave(&priv->lock, flags);
900 set_rx_mode(dev);
901 spin_unlock_irqrestore(&priv->lock, flags);
902}
903
Linus Torvalds1da177e2005-04-16 15:20:36 -0700904static int el3_close(struct net_device *dev)
905{
906 struct el3_private *lp = netdev_priv(dev);
Dominik Brodowskifba395e2006-03-31 17:21:06 +0200907 struct pcmcia_device *link = lp->p_dev;
Olof Johansson906da802008-02-04 22:27:35 -0800908 unsigned int ioaddr = dev->base_addr;
Alexander Kurzf64e9692010-03-31 02:42:10 +0000909
Dominik Brodowskidd0fab52009-10-24 15:51:05 +0200910 dev_dbg(&link->dev, "%s: shutting down ethercard.\n", dev->name);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700911
Dominik Brodowski9940ec32006-03-05 11:04:33 +0100912 if (pcmcia_dev_present(link)) {
Paulius Zaleckascd652842008-04-30 01:20:20 +0300913 /* Turn off statistics ASAP. We update dev->stats below. */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700914 outw(StatsDisable, ioaddr + EL3_CMD);
Alexander Kurzf64e9692010-03-31 02:42:10 +0000915
Linus Torvalds1da177e2005-04-16 15:20:36 -0700916 /* Disable the receiver and transmitter. */
917 outw(RxDisable, ioaddr + EL3_CMD);
918 outw(TxDisable, ioaddr + EL3_CMD);
Alexander Kurzf64e9692010-03-31 02:42:10 +0000919
Linus Torvalds1da177e2005-04-16 15:20:36 -0700920 if (dev->if_port == 2)
921 /* Turn off thinnet power. Green! */
922 outw(StopCoax, ioaddr + EL3_CMD);
923 else if (dev->if_port == 1) {
924 /* Disable link beat and jabber */
925 EL3WINDOW(4);
926 outw(0, ioaddr + WN4_MEDIA);
927 }
Alexander Kurzf64e9692010-03-31 02:42:10 +0000928
Linus Torvalds1da177e2005-04-16 15:20:36 -0700929 /* Switching back to window 0 disables the IRQ. */
930 EL3WINDOW(0);
931 /* But we explicitly zero the IRQ line select anyway. */
932 outw(0x0f00, ioaddr + WN0_IRQ);
Alexander Kurzf64e9692010-03-31 02:42:10 +0000933
Linus Torvalds1da177e2005-04-16 15:20:36 -0700934 /* Check if the card still exists */
935 if ((inw(ioaddr+EL3_STATUS) & 0xe000) == 0x2000)
936 update_stats(dev);
937 }
938
939 link->open--;
940 netif_stop_queue(dev);
941 del_timer_sync(&lp->media);
Alexander Kurzf64e9692010-03-31 02:42:10 +0000942
Linus Torvalds1da177e2005-04-16 15:20:36 -0700943 return 0;
944}
945
Dominik Brodowski7ffec582005-06-27 16:28:19 -0700946static struct pcmcia_device_id tc589_ids[] = {
947 PCMCIA_MFC_DEVICE_MANF_CARD(0, 0x0101, 0x0562),
948 PCMCIA_MFC_DEVICE_PROD_ID1(0, "Motorola MARQUIS", 0xf03e4e77),
949 PCMCIA_DEVICE_MANF_CARD(0x0101, 0x0589),
950 PCMCIA_DEVICE_PROD_ID12("Farallon", "ENet", 0x58d93fc4, 0x992c2202),
Ken Kawasakif0a3a152009-05-01 19:21:26 -0700951 PCMCIA_MFC_DEVICE_CIS_MANF_CARD(0, 0x0101, 0x0035, "cis/3CXEM556.cis"),
952 PCMCIA_MFC_DEVICE_CIS_MANF_CARD(0, 0x0101, 0x003d, "cis/3CXEM556.cis"),
Dominik Brodowski7ffec582005-06-27 16:28:19 -0700953 PCMCIA_DEVICE_NULL,
954};
955MODULE_DEVICE_TABLE(pcmcia, tc589_ids);
956
Linus Torvalds1da177e2005-04-16 15:20:36 -0700957static struct pcmcia_driver tc589_driver = {
958 .owner = THIS_MODULE,
959 .drv = {
960 .name = "3c589_cs",
961 },
Dominik Brodowski15b99ac2006-03-31 17:26:06 +0200962 .probe = tc589_probe,
Dominik Brodowskicc3b4862005-11-14 21:23:14 +0100963 .remove = tc589_detach,
Alexander Kurzf64e9692010-03-31 02:42:10 +0000964 .id_table = tc589_ids,
Dominik Brodowski98e4c282005-11-14 21:21:18 +0100965 .suspend = tc589_suspend,
966 .resume = tc589_resume,
Linus Torvalds1da177e2005-04-16 15:20:36 -0700967};
968
969static int __init init_tc589(void)
970{
971 return pcmcia_register_driver(&tc589_driver);
972}
973
974static void __exit exit_tc589(void)
975{
976 pcmcia_unregister_driver(&tc589_driver);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700977}
978
979module_init(init_tc589);
980module_exit(exit_tc589);