blob: 684bab7810156998f3fd366b27ac1b645d5169e7 [file] [log] [blame]
Linus Torvalds1da177e2005-04-16 15:20:36 -07001/*
2 Written 1997-1998 by Donald Becker.
3
4 This software may be used and distributed according to the terms
5 of the GNU General Public License, incorporated herein by reference.
6
7 This driver is for the 3Com ISA EtherLink XL "Corkscrew" 3c515 ethercard.
8
9 The author may be reached as becker@scyld.com, or C/O
10 Scyld Computing Corporation
11 410 Severn Ave., Suite 210
12 Annapolis MD 21403
13
14
Jeff Garzik6aa20a22006-09-13 13:24:59 -040015 2000/2/2- Added support for kernel-level ISAPnP
Linus Torvalds1da177e2005-04-16 15:20:36 -070016 by Stephen Frost <sfrost@snowman.net> and Alessandro Zummo
17 Cleaned up for 2.3.x/softnet by Jeff Garzik and Alan Cox.
Jeff Garzik6aa20a22006-09-13 13:24:59 -040018
Linus Torvalds1da177e2005-04-16 15:20:36 -070019 2001/11/17 - Added ethtool support (jgarzik)
Jeff Garzik6aa20a22006-09-13 13:24:59 -040020
Linus Torvalds1da177e2005-04-16 15:20:36 -070021 2002/10/28 - Locking updates for 2.5 (alan@redhat.com)
22
23*/
24
25#define DRV_NAME "3c515"
26#define DRV_VERSION "0.99t-ac"
27#define DRV_RELDATE "28-Oct-2002"
28
29static char *version =
30DRV_NAME ".c:v" DRV_VERSION " " DRV_RELDATE " becker@scyld.com and others\n";
31
32#define CORKSCREW 1
33
34/* "Knobs" that adjust features and parameters. */
35/* Set the copy breakpoint for the copy-only-tiny-frames scheme.
36 Setting to > 1512 effectively disables this feature. */
37static int rx_copybreak = 200;
38
39/* Allow setting MTU to a larger size, bypassing the normal ethernet setup. */
40static const int mtu = 1500;
41
42/* Maximum events (Rx packets, etc.) to handle at each interrupt. */
43static int max_interrupt_work = 20;
44
45/* Enable the automatic media selection code -- usually set. */
46#define AUTOMEDIA 1
47
48/* Allow the use of fragment bus master transfers instead of only
49 programmed-I/O for Vortex cards. Full-bus-master transfers are always
50 enabled by default on Boomerang cards. If VORTEX_BUS_MASTER is defined,
51 the feature may be turned on using 'options'. */
52#define VORTEX_BUS_MASTER
53
54/* A few values that may be tweaked. */
55/* Keep the ring sizes a power of two for efficiency. */
56#define TX_RING_SIZE 16
57#define RX_RING_SIZE 16
58#define PKT_BUF_SZ 1536 /* Size of each temporary Rx buffer. */
59
Linus Torvalds1da177e2005-04-16 15:20:36 -070060#include <linux/module.h>
61#include <linux/isapnp.h>
62#include <linux/kernel.h>
63#include <linux/netdevice.h>
64#include <linux/string.h>
65#include <linux/errno.h>
66#include <linux/in.h>
67#include <linux/ioport.h>
68#include <linux/slab.h>
69#include <linux/skbuff.h>
70#include <linux/etherdevice.h>
71#include <linux/interrupt.h>
72#include <linux/timer.h>
73#include <linux/ethtool.h>
74#include <linux/bitops.h>
75
76#include <asm/uaccess.h>
77#include <asm/io.h>
78#include <asm/dma.h>
79
80#define NEW_MULTICAST
81#include <linux/delay.h>
82
83#define MAX_UNITS 8
84
85MODULE_AUTHOR("Donald Becker <becker@scyld.com>");
86MODULE_DESCRIPTION("3Com 3c515 Corkscrew driver");
87MODULE_LICENSE("GPL");
88MODULE_VERSION(DRV_VERSION);
89
90/* "Knobs" for adjusting internal parameters. */
91/* Put out somewhat more debugging messages. (0 - no msg, 1 minimal msgs). */
92#define DRIVER_DEBUG 1
93/* Some values here only for performance evaluation and path-coverage
94 debugging. */
95static int rx_nocopy, rx_copy, queued_packet;
96
97/* Number of times to check to see if the Tx FIFO has space, used in some
98 limited cases. */
99#define WAIT_TX_AVAIL 200
100
101/* Operational parameter that usually are not changed. */
102#define TX_TIMEOUT 40 /* Time in jiffies before concluding Tx hung */
103
104/* The size here is somewhat misleading: the Corkscrew also uses the ISA
105 aliased registers at <base>+0x400.
106 */
107#define CORKSCREW_TOTAL_SIZE 0x20
108
109#ifdef DRIVER_DEBUG
110static int corkscrew_debug = DRIVER_DEBUG;
111#else
112static int corkscrew_debug = 1;
113#endif
114
115#define CORKSCREW_ID 10
116
117/*
118 Theory of Operation
119
120I. Board Compatibility
121
122This device driver is designed for the 3Com 3c515 ISA Fast EtherLink XL,
1233Com's ISA bus adapter for Fast Ethernet. Due to the unique I/O port layout,
124it's not practical to integrate this driver with the other EtherLink drivers.
125
126II. Board-specific settings
127
128The Corkscrew has an EEPROM for configuration, but no special settings are
129needed for Linux.
130
131III. Driver operation
132
133The 3c515 series use an interface that's very similar to the 3c900 "Boomerang"
134PCI cards, with the bus master interface extensively modified to work with
135the ISA bus.
136
137The card is capable of full-bus-master transfers with separate
138lists of transmit and receive descriptors, similar to the AMD LANCE/PCnet,
139DEC Tulip and Intel Speedo3.
140
141This driver uses a "RX_COPYBREAK" scheme rather than a fixed intermediate
142receive buffer. This scheme allocates full-sized skbuffs as receive
143buffers. The value RX_COPYBREAK is used as the copying breakpoint: it is
144chosen to trade-off the memory wasted by passing the full-sized skbuff to
145the queue layer for all frames vs. the copying cost of copying a frame to a
146correctly-sized skbuff.
147
148
149IIIC. Synchronization
150The driver runs as two independent, single-threaded flows of control. One
151is the send-packet routine, which enforces single-threaded use by the netif
152layer. The other thread is the interrupt handler, which is single
153threaded by the hardware and other software.
154
155IV. Notes
156
157Thanks to Terry Murphy of 3Com for providing documentation and a development
158board.
159
160The names "Vortex", "Boomerang" and "Corkscrew" are the internal 3Com
161project names. I use these names to eliminate confusion -- 3Com product
162numbers and names are very similar and often confused.
163
164The new chips support both ethernet (1.5K) and FDDI (4.5K) frame sizes!
165This driver only supports ethernet frames because of the recent MTU limit
166of 1.5K, but the changes to support 4.5K are minimal.
167*/
168
169/* Operational definitions.
170 These are not used by other compilation units and thus are not
171 exported in a ".h" file.
172
173 First the windows. There are eight register windows, with the command
174 and status registers available in each.
175 */
176#define EL3WINDOW(win_num) outw(SelectWindow + (win_num), ioaddr + EL3_CMD)
177#define EL3_CMD 0x0e
178#define EL3_STATUS 0x0e
179
180/* The top five bits written to EL3_CMD are a command, the lower
181 11 bits are the parameter, if applicable.
182 Note that 11 parameters bits was fine for ethernet, but the new chips
183 can handle FDDI length frames (~4500 octets) and now parameters count
184 32-bit 'Dwords' rather than octets. */
185
186enum corkscrew_cmd {
187 TotalReset = 0 << 11, SelectWindow = 1 << 11, StartCoax = 2 << 11,
188 RxDisable = 3 << 11, RxEnable = 4 << 11, RxReset = 5 << 11,
189 UpStall = 6 << 11, UpUnstall = (6 << 11) + 1, DownStall = (6 << 11) + 2,
Jeff Garzik6aa20a22006-09-13 13:24:59 -0400190 DownUnstall = (6 << 11) + 3, RxDiscard = 8 << 11, TxEnable = 9 << 11,
191 TxDisable = 10 << 11, TxReset = 11 << 11, FakeIntr = 12 << 11,
192 AckIntr = 13 << 11, SetIntrEnb = 14 << 11, SetStatusEnb = 15 << 11,
Linus Torvalds1da177e2005-04-16 15:20:36 -0700193 SetRxFilter = 16 << 11, SetRxThreshold = 17 << 11,
194 SetTxThreshold = 18 << 11, SetTxStart = 19 << 11, StartDMAUp = 20 << 11,
195 StartDMADown = (20 << 11) + 1, StatsEnable = 21 << 11,
196 StatsDisable = 22 << 11, StopCoax = 23 << 11,
197};
198
199/* The SetRxFilter command accepts the following classes: */
200enum RxFilter {
201 RxStation = 1, RxMulticast = 2, RxBroadcast = 4, RxProm = 8
202};
203
204/* Bits in the general status register. */
205enum corkscrew_status {
206 IntLatch = 0x0001, AdapterFailure = 0x0002, TxComplete = 0x0004,
207 TxAvailable = 0x0008, RxComplete = 0x0010, RxEarly = 0x0020,
208 IntReq = 0x0040, StatsFull = 0x0080,
209 DMADone = 1 << 8, DownComplete = 1 << 9, UpComplete = 1 << 10,
210 DMAInProgress = 1 << 11, /* DMA controller is still busy. */
211 CmdInProgress = 1 << 12, /* EL3_CMD is still busy. */
212};
213
214/* Register window 1 offsets, the window used in normal operation.
215 On the Corkscrew this window is always mapped at offsets 0x10-0x1f. */
216enum Window1 {
217 TX_FIFO = 0x10, RX_FIFO = 0x10, RxErrors = 0x14,
218 RxStatus = 0x18, Timer = 0x1A, TxStatus = 0x1B,
219 TxFree = 0x1C, /* Remaining free bytes in Tx buffer. */
220};
221enum Window0 {
222 Wn0IRQ = 0x08,
223#if defined(CORKSCREW)
224 Wn0EepromCmd = 0x200A, /* Corkscrew EEPROM command register. */
225 Wn0EepromData = 0x200C, /* Corkscrew EEPROM results register. */
226#else
227 Wn0EepromCmd = 10, /* Window 0: EEPROM command register. */
228 Wn0EepromData = 12, /* Window 0: EEPROM results register. */
229#endif
230};
231enum Win0_EEPROM_bits {
232 EEPROM_Read = 0x80, EEPROM_WRITE = 0x40, EEPROM_ERASE = 0xC0,
233 EEPROM_EWENB = 0x30, /* Enable erasing/writing for 10 msec. */
234 EEPROM_EWDIS = 0x00, /* Disable EWENB before 10 msec timeout. */
235};
236
237/* EEPROM locations. */
238enum eeprom_offset {
239 PhysAddr01 = 0, PhysAddr23 = 1, PhysAddr45 = 2, ModelID = 3,
240 EtherLink3ID = 7,
241};
242
243enum Window3 { /* Window 3: MAC/config bits. */
244 Wn3_Config = 0, Wn3_MAC_Ctrl = 6, Wn3_Options = 8,
245};
Al Virob6659822008-01-13 14:17:35 +0000246enum wn3_config {
247 Ram_size = 7,
248 Ram_width = 8,
249 Ram_speed = 0x30,
250 Rom_size = 0xc0,
251 Ram_split_shift = 16,
252 Ram_split = 3 << Ram_split_shift,
253 Xcvr_shift = 20,
254 Xcvr = 7 << Xcvr_shift,
255 Autoselect = 0x1000000,
Linus Torvalds1da177e2005-04-16 15:20:36 -0700256};
257
258enum Window4 {
259 Wn4_NetDiag = 6, Wn4_Media = 10, /* Window 4: Xcvr/media bits. */
260};
261enum Win4_Media_bits {
262 Media_SQE = 0x0008, /* Enable SQE error counting for AUI. */
263 Media_10TP = 0x00C0, /* Enable link beat and jabber for 10baseT. */
264 Media_Lnk = 0x0080, /* Enable just link beat for 100TX/100FX. */
265 Media_LnkBeat = 0x0800,
266};
267enum Window7 { /* Window 7: Bus Master control. */
268 Wn7_MasterAddr = 0, Wn7_MasterLen = 6, Wn7_MasterStatus = 12,
269};
270
271/* Boomerang-style bus master control registers. Note ISA aliases! */
272enum MasterCtrl {
273 PktStatus = 0x400, DownListPtr = 0x404, FragAddr = 0x408, FragLen =
274 0x40c,
275 TxFreeThreshold = 0x40f, UpPktStatus = 0x410, UpListPtr = 0x418,
276};
277
278/* The Rx and Tx descriptor lists.
279 Caution Alpha hackers: these types are 32 bits! Note also the 8 byte
280 alignment contraint on tx_ring[] and rx_ring[]. */
281struct boom_rx_desc {
282 u32 next;
283 s32 status;
284 u32 addr;
285 s32 length;
286};
287
288/* Values for the Rx status entry. */
289enum rx_desc_status {
290 RxDComplete = 0x00008000, RxDError = 0x4000,
291 /* See boomerang_rx() for actual error bits */
292};
293
294struct boom_tx_desc {
295 u32 next;
296 s32 status;
297 u32 addr;
298 s32 length;
299};
300
301struct corkscrew_private {
302 const char *product_name;
303 struct list_head list;
304 struct net_device *our_dev;
305 /* The Rx and Tx rings are here to keep them quad-word-aligned. */
306 struct boom_rx_desc rx_ring[RX_RING_SIZE];
307 struct boom_tx_desc tx_ring[TX_RING_SIZE];
308 /* The addresses of transmit- and receive-in-place skbuffs. */
309 struct sk_buff *rx_skbuff[RX_RING_SIZE];
310 struct sk_buff *tx_skbuff[TX_RING_SIZE];
311 unsigned int cur_rx, cur_tx; /* The next free ring entry */
312 unsigned int dirty_rx, dirty_tx;/* The ring entries to be free()ed. */
313 struct net_device_stats stats;
314 struct sk_buff *tx_skb; /* Packet being eaten by bus master ctrl. */
315 struct timer_list timer; /* Media selection timer. */
316 int capabilities ; /* Adapter capabilities word. */
317 int options; /* User-settable misc. driver options. */
318 int last_rx_packets; /* For media autoselection. */
319 unsigned int available_media:8, /* From Wn3_Options */
320 media_override:3, /* Passed-in media type. */
321 default_media:3, /* Read from the EEPROM. */
322 full_duplex:1, autoselect:1, bus_master:1, /* Vortex can only do a fragment bus-m. */
323 full_bus_master_tx:1, full_bus_master_rx:1, /* Boomerang */
324 tx_full:1;
325 spinlock_t lock;
326 struct device *dev;
327};
328
329/* The action to take with a media selection timer tick.
330 Note that we deviate from the 3Com order by checking 10base2 before AUI.
331 */
332enum xcvr_types {
333 XCVR_10baseT = 0, XCVR_AUI, XCVR_10baseTOnly, XCVR_10base2, XCVR_100baseTx,
334 XCVR_100baseFx, XCVR_MII = 6, XCVR_Default = 8,
335};
336
337static struct media_table {
338 char *name;
339 unsigned int media_bits:16, /* Bits to set in Wn4_Media register. */
340 mask:8, /* The transceiver-present bit in Wn3_Config. */
341 next:8; /* The media type to try next. */
342 short wait; /* Time before we check media status. */
Jeff Garzik6aa20a22006-09-13 13:24:59 -0400343} media_tbl[] = {
344 { "10baseT", Media_10TP, 0x08, XCVR_10base2, (14 * HZ) / 10 },
345 { "10Mbs AUI", Media_SQE, 0x20, XCVR_Default, (1 * HZ) / 10},
346 { "undefined", 0, 0x80, XCVR_10baseT, 10000},
347 { "10base2", 0, 0x10, XCVR_AUI, (1 * HZ) / 10},
348 { "100baseTX", Media_Lnk, 0x02, XCVR_100baseFx, (14 * HZ) / 10},
349 { "100baseFX", Media_Lnk, 0x04, XCVR_MII, (14 * HZ) / 10},
350 { "MII", 0, 0x40, XCVR_10baseT, 3 * HZ},
351 { "undefined", 0, 0x01, XCVR_10baseT, 10000},
Linus Torvalds1da177e2005-04-16 15:20:36 -0700352 { "Default", 0, 0xFF, XCVR_10baseT, 10000},
353};
354
355#ifdef __ISAPNP__
356static struct isapnp_device_id corkscrew_isapnp_adapters[] = {
357 { ISAPNP_ANY_ID, ISAPNP_ANY_ID,
358 ISAPNP_VENDOR('T', 'C', 'M'), ISAPNP_FUNCTION(0x5051),
359 (long) "3Com Fast EtherLink ISA" },
360 { } /* terminate list */
361};
362
363MODULE_DEVICE_TABLE(isapnp, corkscrew_isapnp_adapters);
364
365static int nopnp;
366#endif /* __ISAPNP__ */
367
368static struct net_device *corkscrew_scan(int unit);
b1fc5502005-05-12 20:11:55 -0400369static int corkscrew_setup(struct net_device *dev, int ioaddr,
Linus Torvalds1da177e2005-04-16 15:20:36 -0700370 struct pnp_dev *idev, int card_number);
371static int corkscrew_open(struct net_device *dev);
372static void corkscrew_timer(unsigned long arg);
373static int corkscrew_start_xmit(struct sk_buff *skb,
374 struct net_device *dev);
375static int corkscrew_rx(struct net_device *dev);
376static void corkscrew_timeout(struct net_device *dev);
377static int boomerang_rx(struct net_device *dev);
David Howells7d12e782006-10-05 14:55:46 +0100378static irqreturn_t corkscrew_interrupt(int irq, void *dev_id);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700379static int corkscrew_close(struct net_device *dev);
380static void update_stats(int addr, struct net_device *dev);
381static struct net_device_stats *corkscrew_get_stats(struct net_device *dev);
382static void set_rx_mode(struct net_device *dev);
Jeff Garzik7282d492006-09-13 14:30:00 -0400383static const struct ethtool_ops netdev_ethtool_ops;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700384
Jeff Garzik6aa20a22006-09-13 13:24:59 -0400385
386/*
Linus Torvalds1da177e2005-04-16 15:20:36 -0700387 Unfortunately maximizing the shared code between the integrated and
388 module version of the driver results in a complicated set of initialization
389 procedures.
390 init_module() -- modules / tc59x_init() -- built-in
391 The wrappers for corkscrew_scan()
392 corkscrew_scan() The common routine that scans for PCI and EISA cards
393 corkscrew_found_device() Allocate a device structure when we find a card.
394 Different versions exist for modules and built-in.
395 corkscrew_probe1() Fill in the device structure -- this is separated
396 so that the modules code can put it in dev->init.
397*/
398/* This driver uses 'options' to pass the media type, full-duplex flag, etc. */
399/* Note: this is the only limit on the number of cards supported!! */
400static int options[MAX_UNITS] = { -1, -1, -1, -1, -1, -1, -1, -1, };
401
402#ifdef MODULE
403static int debug = -1;
404
405module_param(debug, int, 0);
406module_param_array(options, int, NULL, 0);
407module_param(rx_copybreak, int, 0);
408module_param(max_interrupt_work, int, 0);
409MODULE_PARM_DESC(debug, "3c515 debug level (0-6)");
410MODULE_PARM_DESC(options, "3c515: Bits 0-2: media type, bit 3: full duplex, bit 4: bus mastering");
411MODULE_PARM_DESC(rx_copybreak, "3c515 copy breakpoint for copy-only-tiny-frames");
412MODULE_PARM_DESC(max_interrupt_work, "3c515 maximum events handled per interrupt");
413
414/* A list of all installed Vortex devices, for removing the driver module. */
415/* we will need locking (and refcounting) if we ever use it for more */
416static LIST_HEAD(root_corkscrew_dev);
417
418int init_module(void)
419{
420 int found = 0;
421 if (debug >= 0)
422 corkscrew_debug = debug;
423 if (corkscrew_debug)
424 printk(version);
425 while (corkscrew_scan(-1))
426 found++;
427 return found ? 0 : -ENODEV;
428}
429
430#else
431struct net_device *tc515_probe(int unit)
432{
433 struct net_device *dev = corkscrew_scan(unit);
434 static int printed;
435
436 if (!dev)
437 return ERR_PTR(-ENODEV);
438
439 if (corkscrew_debug > 0 && !printed) {
440 printed = 1;
441 printk(version);
442 }
443
444 return dev;
445}
446#endif /* not MODULE */
447
448static int check_device(unsigned ioaddr)
449{
450 int timer;
451
452 if (!request_region(ioaddr, CORKSCREW_TOTAL_SIZE, "3c515"))
453 return 0;
454 /* Check the resource configuration for a matching ioaddr. */
455 if ((inw(ioaddr + 0x2002) & 0x1f0) != (ioaddr & 0x1f0)) {
456 release_region(ioaddr, CORKSCREW_TOTAL_SIZE);
457 return 0;
458 }
459 /* Verify by reading the device ID from the EEPROM. */
460 outw(EEPROM_Read + 7, ioaddr + Wn0EepromCmd);
461 /* Pause for at least 162 us. for the read to take place. */
462 for (timer = 4; timer >= 0; timer--) {
463 udelay(162);
464 if ((inw(ioaddr + Wn0EepromCmd) & 0x0200) == 0)
465 break;
466 }
467 if (inw(ioaddr + Wn0EepromData) != 0x6d50) {
468 release_region(ioaddr, CORKSCREW_TOTAL_SIZE);
469 return 0;
470 }
471 return 1;
472}
473
474static void cleanup_card(struct net_device *dev)
475{
476 struct corkscrew_private *vp = netdev_priv(dev);
477 list_del_init(&vp->list);
478 if (dev->dma)
479 free_dma(dev->dma);
480 outw(TotalReset, dev->base_addr + EL3_CMD);
481 release_region(dev->base_addr, CORKSCREW_TOTAL_SIZE);
482 if (vp->dev)
483 pnp_device_detach(to_pnp_dev(vp->dev));
484}
485
486static struct net_device *corkscrew_scan(int unit)
487{
488 struct net_device *dev;
489 static int cards_found = 0;
490 static int ioaddr;
491 int err;
492#ifdef __ISAPNP__
493 short i;
494 static int pnp_cards;
495#endif
496
497 dev = alloc_etherdev(sizeof(struct corkscrew_private));
498 if (!dev)
499 return ERR_PTR(-ENOMEM);
500
501 if (unit >= 0) {
502 sprintf(dev->name, "eth%d", unit);
503 netdev_boot_setup_check(dev);
504 }
505
Linus Torvalds1da177e2005-04-16 15:20:36 -0700506#ifdef __ISAPNP__
507 if(nopnp == 1)
508 goto no_pnp;
509 for(i=0; corkscrew_isapnp_adapters[i].vendor != 0; i++) {
510 struct pnp_dev *idev = NULL;
511 int irq;
512 while((idev = pnp_find_dev(NULL,
513 corkscrew_isapnp_adapters[i].vendor,
514 corkscrew_isapnp_adapters[i].function,
515 idev))) {
516
517 if (pnp_device_attach(idev) < 0)
518 continue;
519 if (pnp_activate_dev(idev) < 0) {
520 printk("pnp activate failed (out of resources?)\n");
521 pnp_device_detach(idev);
522 continue;
523 }
524 if (!pnp_port_valid(idev, 0) || !pnp_irq_valid(idev, 0)) {
525 pnp_device_detach(idev);
526 continue;
527 }
528 ioaddr = pnp_port_start(idev, 0);
529 irq = pnp_irq(idev, 0);
530 if (!check_device(ioaddr)) {
531 pnp_device_detach(idev);
532 continue;
533 }
534 if(corkscrew_debug)
535 printk ("ISAPNP reports %s at i/o 0x%x, irq %d\n",
536 (char*) corkscrew_isapnp_adapters[i].driver_data, ioaddr, irq);
537 printk(KERN_INFO "3c515 Resource configuration register %#4.4x, DCR %4.4x.\n",
538 inl(ioaddr + 0x2002), inw(ioaddr + 0x2000));
539 /* irq = inw(ioaddr + 0x2002) & 15; */ /* Use the irq from isapnp */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700540 SET_NETDEV_DEV(dev, &idev->dev);
541 pnp_cards++;
b1fc5502005-05-12 20:11:55 -0400542 err = corkscrew_setup(dev, ioaddr, idev, cards_found++);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700543 if (!err)
544 return dev;
545 cleanup_card(dev);
546 }
547 }
548no_pnp:
549#endif /* __ISAPNP__ */
550
551 /* Check all locations on the ISA bus -- evil! */
552 for (ioaddr = 0x100; ioaddr < 0x400; ioaddr += 0x20) {
553 if (!check_device(ioaddr))
554 continue;
555
556 printk(KERN_INFO "3c515 Resource configuration register %#4.4x, DCR %4.4x.\n",
557 inl(ioaddr + 0x2002), inw(ioaddr + 0x2000));
b1fc5502005-05-12 20:11:55 -0400558 err = corkscrew_setup(dev, ioaddr, NULL, cards_found++);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700559 if (!err)
560 return dev;
561 cleanup_card(dev);
562 }
563 free_netdev(dev);
564 return NULL;
565}
566
b1fc5502005-05-12 20:11:55 -0400567static int corkscrew_setup(struct net_device *dev, int ioaddr,
Linus Torvalds1da177e2005-04-16 15:20:36 -0700568 struct pnp_dev *idev, int card_number)
569{
570 struct corkscrew_private *vp = netdev_priv(dev);
571 unsigned int eeprom[0x40], checksum = 0; /* EEPROM contents */
572 int i;
573 int irq;
Joe Perches0795af52007-10-03 17:59:30 -0700574 DECLARE_MAC_BUF(mac);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700575
576 if (idev) {
577 irq = pnp_irq(idev, 0);
578 vp->dev = &idev->dev;
579 } else {
580 irq = inw(ioaddr + 0x2002) & 15;
581 }
582
583 dev->base_addr = ioaddr;
584 dev->irq = irq;
585 dev->dma = inw(ioaddr + 0x2000) & 7;
586 vp->product_name = "3c515";
587 vp->options = dev->mem_start;
588 vp->our_dev = dev;
589
590 if (!vp->options) {
591 if (card_number >= MAX_UNITS)
592 vp->options = -1;
593 else
594 vp->options = options[card_number];
595 }
596
597 if (vp->options >= 0) {
598 vp->media_override = vp->options & 7;
599 if (vp->media_override == 2)
600 vp->media_override = 0;
601 vp->full_duplex = (vp->options & 8) ? 1 : 0;
602 vp->bus_master = (vp->options & 16) ? 1 : 0;
603 } else {
604 vp->media_override = 7;
605 vp->full_duplex = 0;
606 vp->bus_master = 0;
607 }
608#ifdef MODULE
609 list_add(&vp->list, &root_corkscrew_dev);
610#endif
611
612 printk(KERN_INFO "%s: 3Com %s at %#3x,", dev->name, vp->product_name, ioaddr);
613
614 spin_lock_init(&vp->lock);
Jeff Garzik6aa20a22006-09-13 13:24:59 -0400615
Linus Torvalds1da177e2005-04-16 15:20:36 -0700616 /* Read the station address from the EEPROM. */
617 EL3WINDOW(0);
618 for (i = 0; i < 0x18; i++) {
Al Virob6659822008-01-13 14:17:35 +0000619 __be16 *phys_addr = (__be16 *) dev->dev_addr;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700620 int timer;
621 outw(EEPROM_Read + i, ioaddr + Wn0EepromCmd);
622 /* Pause for at least 162 us. for the read to take place. */
623 for (timer = 4; timer >= 0; timer--) {
624 udelay(162);
625 if ((inw(ioaddr + Wn0EepromCmd) & 0x0200) == 0)
626 break;
627 }
628 eeprom[i] = inw(ioaddr + Wn0EepromData);
629 checksum ^= eeprom[i];
630 if (i < 3)
631 phys_addr[i] = htons(eeprom[i]);
632 }
633 checksum = (checksum ^ (checksum >> 8)) & 0xff;
634 if (checksum != 0x00)
635 printk(" ***INVALID CHECKSUM %4.4x*** ", checksum);
Joe Perches0795af52007-10-03 17:59:30 -0700636 printk(" %s", print_mac(mac, dev->dev_addr));
Linus Torvalds1da177e2005-04-16 15:20:36 -0700637 if (eeprom[16] == 0x11c7) { /* Corkscrew */
638 if (request_dma(dev->dma, "3c515")) {
639 printk(", DMA %d allocation failed", dev->dma);
640 dev->dma = 0;
641 } else
642 printk(", DMA %d", dev->dma);
643 }
644 printk(", IRQ %d\n", dev->irq);
645 /* Tell them about an invalid IRQ. */
646 if (corkscrew_debug && (dev->irq <= 0 || dev->irq > 15))
647 printk(KERN_WARNING " *** Warning: this IRQ is unlikely to work! ***\n");
648
649 {
650 char *ram_split[] = { "5:3", "3:1", "1:1", "3:5" };
Al Virob6659822008-01-13 14:17:35 +0000651 __u32 config;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700652 EL3WINDOW(3);
653 vp->available_media = inw(ioaddr + Wn3_Options);
Al Virob6659822008-01-13 14:17:35 +0000654 config = inl(ioaddr + Wn3_Config);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700655 if (corkscrew_debug > 1)
656 printk(KERN_INFO " Internal config register is %4.4x, transceivers %#x.\n",
Al Virob6659822008-01-13 14:17:35 +0000657 config, inw(ioaddr + Wn3_Options));
Linus Torvalds1da177e2005-04-16 15:20:36 -0700658 printk(KERN_INFO " %dK %s-wide RAM %s Rx:Tx split, %s%s interface.\n",
Al Virob6659822008-01-13 14:17:35 +0000659 8 << config & Ram_size,
660 config & Ram_width ? "word" : "byte",
661 ram_split[(config & Ram_split) >> Ram_split_shift],
662 config & Autoselect ? "autoselect/" : "",
663 media_tbl[(config & Xcvr) >> Xcvr_shift].name);
664 vp->default_media = (config & Xcvr) >> Xcvr_shift;
665 vp->autoselect = config & Autoselect ? 1 : 0;
666 dev->if_port = vp->default_media;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700667 }
668 if (vp->media_override != 7) {
669 printk(KERN_INFO " Media override to transceiver type %d (%s).\n",
670 vp->media_override,
671 media_tbl[vp->media_override].name);
672 dev->if_port = vp->media_override;
673 }
674
675 vp->capabilities = eeprom[16];
676 vp->full_bus_master_tx = (vp->capabilities & 0x20) ? 1 : 0;
677 /* Rx is broken at 10mbps, so we always disable it. */
678 /* vp->full_bus_master_rx = 0; */
679 vp->full_bus_master_rx = (vp->capabilities & 0x20) ? 1 : 0;
680
681 /* The 3c51x-specific entries in the device structure. */
682 dev->open = &corkscrew_open;
683 dev->hard_start_xmit = &corkscrew_start_xmit;
684 dev->tx_timeout = &corkscrew_timeout;
685 dev->watchdog_timeo = (400 * HZ) / 1000;
686 dev->stop = &corkscrew_close;
687 dev->get_stats = &corkscrew_get_stats;
688 dev->set_multicast_list = &set_rx_mode;
689 dev->ethtool_ops = &netdev_ethtool_ops;
b1fc5502005-05-12 20:11:55 -0400690
691 return register_netdev(dev);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700692}
Jeff Garzik6aa20a22006-09-13 13:24:59 -0400693
Linus Torvalds1da177e2005-04-16 15:20:36 -0700694
695static int corkscrew_open(struct net_device *dev)
696{
697 int ioaddr = dev->base_addr;
698 struct corkscrew_private *vp = netdev_priv(dev);
Al Virob6659822008-01-13 14:17:35 +0000699 __u32 config;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700700 int i;
701
702 /* Before initializing select the active media port. */
703 EL3WINDOW(3);
704 if (vp->full_duplex)
705 outb(0x20, ioaddr + Wn3_MAC_Ctrl); /* Set the full-duplex bit. */
Al Virob6659822008-01-13 14:17:35 +0000706 config = inl(ioaddr + Wn3_Config);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700707
708 if (vp->media_override != 7) {
709 if (corkscrew_debug > 1)
710 printk(KERN_INFO "%s: Media override to transceiver %d (%s).\n",
711 dev->name, vp->media_override,
712 media_tbl[vp->media_override].name);
713 dev->if_port = vp->media_override;
714 } else if (vp->autoselect) {
715 /* Find first available media type, starting with 100baseTx. */
716 dev->if_port = 4;
Jeff Garzik6aa20a22006-09-13 13:24:59 -0400717 while (!(vp->available_media & media_tbl[dev->if_port].mask))
Linus Torvalds1da177e2005-04-16 15:20:36 -0700718 dev->if_port = media_tbl[dev->if_port].next;
719
720 if (corkscrew_debug > 1)
721 printk("%s: Initial media type %s.\n",
722 dev->name, media_tbl[dev->if_port].name);
723
724 init_timer(&vp->timer);
725 vp->timer.expires = jiffies + media_tbl[dev->if_port].wait;
726 vp->timer.data = (unsigned long) dev;
727 vp->timer.function = &corkscrew_timer; /* timer handler */
728 add_timer(&vp->timer);
729 } else
730 dev->if_port = vp->default_media;
731
Al Virob6659822008-01-13 14:17:35 +0000732 config = (config & ~Xcvr) | (dev->if_port << Xcvr_shift);
733 outl(config, ioaddr + Wn3_Config);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700734
735 if (corkscrew_debug > 1) {
736 printk("%s: corkscrew_open() InternalConfig %8.8x.\n",
Al Virob6659822008-01-13 14:17:35 +0000737 dev->name, config);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700738 }
739
740 outw(TxReset, ioaddr + EL3_CMD);
741 for (i = 20; i >= 0; i--)
742 if (!(inw(ioaddr + EL3_STATUS) & CmdInProgress))
743 break;
744
745 outw(RxReset, ioaddr + EL3_CMD);
746 /* Wait a few ticks for the RxReset command to complete. */
747 for (i = 20; i >= 0; i--)
748 if (!(inw(ioaddr + EL3_STATUS) & CmdInProgress))
749 break;
750
751 outw(SetStatusEnb | 0x00, ioaddr + EL3_CMD);
752
753 /* Use the now-standard shared IRQ implementation. */
754 if (vp->capabilities == 0x11c7) {
755 /* Corkscrew: Cannot share ISA resources. */
756 if (dev->irq == 0
757 || dev->dma == 0
758 || request_irq(dev->irq, &corkscrew_interrupt, 0,
759 vp->product_name, dev)) return -EAGAIN;
760 enable_dma(dev->dma);
761 set_dma_mode(dev->dma, DMA_MODE_CASCADE);
Thomas Gleixner1fb9df52006-07-01 19:29:39 -0700762 } else if (request_irq(dev->irq, &corkscrew_interrupt, IRQF_SHARED,
Linus Torvalds1da177e2005-04-16 15:20:36 -0700763 vp->product_name, dev)) {
764 return -EAGAIN;
765 }
766
767 if (corkscrew_debug > 1) {
768 EL3WINDOW(4);
769 printk("%s: corkscrew_open() irq %d media status %4.4x.\n",
770 dev->name, dev->irq, inw(ioaddr + Wn4_Media));
771 }
772
773 /* Set the station address and mask in window 2 each time opened. */
774 EL3WINDOW(2);
775 for (i = 0; i < 6; i++)
776 outb(dev->dev_addr[i], ioaddr + i);
777 for (; i < 12; i += 2)
778 outw(0, ioaddr + i);
779
780 if (dev->if_port == 3)
781 /* Start the thinnet transceiver. We should really wait 50ms... */
782 outw(StartCoax, ioaddr + EL3_CMD);
783 EL3WINDOW(4);
784 outw((inw(ioaddr + Wn4_Media) & ~(Media_10TP | Media_SQE)) |
785 media_tbl[dev->if_port].media_bits, ioaddr + Wn4_Media);
786
787 /* Switch to the stats window, and clear all stats by reading. */
788 outw(StatsDisable, ioaddr + EL3_CMD);
789 EL3WINDOW(6);
790 for (i = 0; i < 10; i++)
791 inb(ioaddr + i);
792 inw(ioaddr + 10);
793 inw(ioaddr + 12);
794 /* New: On the Vortex we must also clear the BadSSD counter. */
795 EL3WINDOW(4);
796 inb(ioaddr + 12);
797 /* ..and on the Boomerang we enable the extra statistics bits. */
798 outw(0x0040, ioaddr + Wn4_NetDiag);
799
800 /* Switch to register set 7 for normal use. */
801 EL3WINDOW(7);
802
803 if (vp->full_bus_master_rx) { /* Boomerang bus master. */
804 vp->cur_rx = vp->dirty_rx = 0;
805 if (corkscrew_debug > 2)
806 printk("%s: Filling in the Rx ring.\n",
807 dev->name);
808 for (i = 0; i < RX_RING_SIZE; i++) {
809 struct sk_buff *skb;
810 if (i < (RX_RING_SIZE - 1))
811 vp->rx_ring[i].next =
812 isa_virt_to_bus(&vp->rx_ring[i + 1]);
813 else
814 vp->rx_ring[i].next = 0;
815 vp->rx_ring[i].status = 0; /* Clear complete bit. */
816 vp->rx_ring[i].length = PKT_BUF_SZ | 0x80000000;
817 skb = dev_alloc_skb(PKT_BUF_SZ);
818 vp->rx_skbuff[i] = skb;
819 if (skb == NULL)
820 break; /* Bad news! */
821 skb->dev = dev; /* Mark as being used by this device. */
822 skb_reserve(skb, 2); /* Align IP on 16 byte boundaries */
David S. Miller689be432005-06-28 15:25:31 -0700823 vp->rx_ring[i].addr = isa_virt_to_bus(skb->data);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700824 }
825 vp->rx_ring[i - 1].next = isa_virt_to_bus(&vp->rx_ring[0]); /* Wrap the ring. */
826 outl(isa_virt_to_bus(&vp->rx_ring[0]), ioaddr + UpListPtr);
827 }
828 if (vp->full_bus_master_tx) { /* Boomerang bus master Tx. */
829 vp->cur_tx = vp->dirty_tx = 0;
830 outb(PKT_BUF_SZ >> 8, ioaddr + TxFreeThreshold); /* Room for a packet. */
831 /* Clear the Tx ring. */
832 for (i = 0; i < TX_RING_SIZE; i++)
833 vp->tx_skbuff[i] = NULL;
834 outl(0, ioaddr + DownListPtr);
835 }
836 /* Set receiver mode: presumably accept b-case and phys addr only. */
837 set_rx_mode(dev);
838 outw(StatsEnable, ioaddr + EL3_CMD); /* Turn on statistics. */
839
840 netif_start_queue(dev);
841
842 outw(RxEnable, ioaddr + EL3_CMD); /* Enable the receiver. */
843 outw(TxEnable, ioaddr + EL3_CMD); /* Enable transmitter. */
844 /* Allow status bits to be seen. */
845 outw(SetStatusEnb | AdapterFailure | IntReq | StatsFull |
846 (vp->full_bus_master_tx ? DownComplete : TxAvailable) |
847 (vp->full_bus_master_rx ? UpComplete : RxComplete) |
848 (vp->bus_master ? DMADone : 0), ioaddr + EL3_CMD);
849 /* Ack all pending events, and set active indicator mask. */
850 outw(AckIntr | IntLatch | TxAvailable | RxEarly | IntReq,
851 ioaddr + EL3_CMD);
852 outw(SetIntrEnb | IntLatch | TxAvailable | RxComplete | StatsFull
853 | (vp->bus_master ? DMADone : 0) | UpComplete | DownComplete,
854 ioaddr + EL3_CMD);
855
856 return 0;
857}
858
859static void corkscrew_timer(unsigned long data)
860{
861#ifdef AUTOMEDIA
862 struct net_device *dev = (struct net_device *) data;
863 struct corkscrew_private *vp = netdev_priv(dev);
864 int ioaddr = dev->base_addr;
865 unsigned long flags;
866 int ok = 0;
867
868 if (corkscrew_debug > 1)
869 printk("%s: Media selection timer tick happened, %s.\n",
870 dev->name, media_tbl[dev->if_port].name);
871
872 spin_lock_irqsave(&vp->lock, flags);
Jeff Garzik6aa20a22006-09-13 13:24:59 -0400873
Linus Torvalds1da177e2005-04-16 15:20:36 -0700874 {
875 int old_window = inw(ioaddr + EL3_CMD) >> 13;
876 int media_status;
877 EL3WINDOW(4);
878 media_status = inw(ioaddr + Wn4_Media);
879 switch (dev->if_port) {
880 case 0:
881 case 4:
882 case 5: /* 10baseT, 100baseTX, 100baseFX */
883 if (media_status & Media_LnkBeat) {
884 ok = 1;
885 if (corkscrew_debug > 1)
886 printk("%s: Media %s has link beat, %x.\n",
887 dev->name,
888 media_tbl[dev->if_port].name,
889 media_status);
890 } else if (corkscrew_debug > 1)
891 printk("%s: Media %s is has no link beat, %x.\n",
892 dev->name,
893 media_tbl[dev->if_port].name,
894 media_status);
895
896 break;
897 default: /* Other media types handled by Tx timeouts. */
898 if (corkscrew_debug > 1)
899 printk("%s: Media %s is has no indication, %x.\n",
900 dev->name,
901 media_tbl[dev->if_port].name,
902 media_status);
903 ok = 1;
904 }
905 if (!ok) {
Al Virob6659822008-01-13 14:17:35 +0000906 __u32 config;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700907
908 do {
909 dev->if_port =
910 media_tbl[dev->if_port].next;
911 }
912 while (!(vp->available_media & media_tbl[dev->if_port].mask));
Jeff Garzik6aa20a22006-09-13 13:24:59 -0400913
Linus Torvalds1da177e2005-04-16 15:20:36 -0700914 if (dev->if_port == 8) { /* Go back to default. */
915 dev->if_port = vp->default_media;
916 if (corkscrew_debug > 1)
917 printk("%s: Media selection failing, using default %s port.\n",
918 dev->name,
919 media_tbl[dev->if_port].name);
920 } else {
921 if (corkscrew_debug > 1)
922 printk("%s: Media selection failed, now trying %s port.\n",
923 dev->name,
924 media_tbl[dev->if_port].name);
925 vp->timer.expires = jiffies + media_tbl[dev->if_port].wait;
926 add_timer(&vp->timer);
927 }
928 outw((media_status & ~(Media_10TP | Media_SQE)) |
929 media_tbl[dev->if_port].media_bits,
930 ioaddr + Wn4_Media);
931
932 EL3WINDOW(3);
Al Virob6659822008-01-13 14:17:35 +0000933 config = inl(ioaddr + Wn3_Config);
934 config = (config & ~Xcvr) | (dev->if_port << Xcvr_shift);
935 outl(config, ioaddr + Wn3_Config);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700936
937 outw(dev->if_port == 3 ? StartCoax : StopCoax,
938 ioaddr + EL3_CMD);
939 }
940 EL3WINDOW(old_window);
941 }
Jeff Garzik6aa20a22006-09-13 13:24:59 -0400942
Linus Torvalds1da177e2005-04-16 15:20:36 -0700943 spin_unlock_irqrestore(&vp->lock, flags);
944 if (corkscrew_debug > 1)
945 printk("%s: Media selection timer finished, %s.\n",
946 dev->name, media_tbl[dev->if_port].name);
947
948#endif /* AUTOMEDIA */
949 return;
950}
951
952static void corkscrew_timeout(struct net_device *dev)
953{
954 int i;
955 struct corkscrew_private *vp = netdev_priv(dev);
956 int ioaddr = dev->base_addr;
957
958 printk(KERN_WARNING
959 "%s: transmit timed out, tx_status %2.2x status %4.4x.\n",
960 dev->name, inb(ioaddr + TxStatus),
961 inw(ioaddr + EL3_STATUS));
962 /* Slight code bloat to be user friendly. */
963 if ((inb(ioaddr + TxStatus) & 0x88) == 0x88)
964 printk(KERN_WARNING
965 "%s: Transmitter encountered 16 collisions -- network"
966 " network cable problem?\n", dev->name);
967#ifndef final_version
968 printk(" Flags; bus-master %d, full %d; dirty %d current %d.\n",
969 vp->full_bus_master_tx, vp->tx_full, vp->dirty_tx,
970 vp->cur_tx);
971 printk(" Down list %8.8x vs. %p.\n", inl(ioaddr + DownListPtr),
972 &vp->tx_ring[0]);
973 for (i = 0; i < TX_RING_SIZE; i++) {
974 printk(" %d: %p length %8.8x status %8.8x\n", i,
975 &vp->tx_ring[i],
976 vp->tx_ring[i].length, vp->tx_ring[i].status);
977 }
978#endif
979 /* Issue TX_RESET and TX_START commands. */
980 outw(TxReset, ioaddr + EL3_CMD);
981 for (i = 20; i >= 0; i--)
982 if (!(inw(ioaddr + EL3_STATUS) & CmdInProgress))
983 break;
984 outw(TxEnable, ioaddr + EL3_CMD);
985 dev->trans_start = jiffies;
986 vp->stats.tx_errors++;
987 vp->stats.tx_dropped++;
988 netif_wake_queue(dev);
989}
990
991static int corkscrew_start_xmit(struct sk_buff *skb,
992 struct net_device *dev)
993{
994 struct corkscrew_private *vp = netdev_priv(dev);
995 int ioaddr = dev->base_addr;
996
997 /* Block a timer-based transmit from overlapping. */
998
999 netif_stop_queue(dev);
1000
1001 if (vp->full_bus_master_tx) { /* BOOMERANG bus-master */
1002 /* Calculate the next Tx descriptor entry. */
1003 int entry = vp->cur_tx % TX_RING_SIZE;
1004 struct boom_tx_desc *prev_entry;
Eric Sesterhenncb958182006-08-19 19:37:57 +02001005 unsigned long flags;
1006 int i;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001007
1008 if (vp->tx_full) /* No room to transmit with */
1009 return 1;
1010 if (vp->cur_tx != 0)
1011 prev_entry = &vp->tx_ring[(vp->cur_tx - 1) % TX_RING_SIZE];
1012 else
1013 prev_entry = NULL;
1014 if (corkscrew_debug > 3)
1015 printk("%s: Trying to send a packet, Tx index %d.\n",
1016 dev->name, vp->cur_tx);
1017 /* vp->tx_full = 1; */
1018 vp->tx_skbuff[entry] = skb;
1019 vp->tx_ring[entry].next = 0;
1020 vp->tx_ring[entry].addr = isa_virt_to_bus(skb->data);
1021 vp->tx_ring[entry].length = skb->len | 0x80000000;
1022 vp->tx_ring[entry].status = skb->len | 0x80000000;
1023
1024 spin_lock_irqsave(&vp->lock, flags);
1025 outw(DownStall, ioaddr + EL3_CMD);
1026 /* Wait for the stall to complete. */
1027 for (i = 20; i >= 0; i--)
Jeff Garzik6aa20a22006-09-13 13:24:59 -04001028 if ((inw(ioaddr + EL3_STATUS) & CmdInProgress) == 0)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001029 break;
1030 if (prev_entry)
1031 prev_entry->next = isa_virt_to_bus(&vp->tx_ring[entry]);
1032 if (inl(ioaddr + DownListPtr) == 0) {
1033 outl(isa_virt_to_bus(&vp->tx_ring[entry]),
1034 ioaddr + DownListPtr);
1035 queued_packet++;
1036 }
1037 outw(DownUnstall, ioaddr + EL3_CMD);
1038 spin_unlock_irqrestore(&vp->lock, flags);
1039
1040 vp->cur_tx++;
1041 if (vp->cur_tx - vp->dirty_tx > TX_RING_SIZE - 1)
1042 vp->tx_full = 1;
1043 else { /* Clear previous interrupt enable. */
1044 if (prev_entry)
1045 prev_entry->status &= ~0x80000000;
1046 netif_wake_queue(dev);
1047 }
1048 dev->trans_start = jiffies;
1049 return 0;
1050 }
1051 /* Put out the doubleword header... */
1052 outl(skb->len, ioaddr + TX_FIFO);
1053 vp->stats.tx_bytes += skb->len;
1054#ifdef VORTEX_BUS_MASTER
1055 if (vp->bus_master) {
1056 /* Set the bus-master controller to transfer the packet. */
1057 outl((int) (skb->data), ioaddr + Wn7_MasterAddr);
1058 outw((skb->len + 3) & ~3, ioaddr + Wn7_MasterLen);
1059 vp->tx_skb = skb;
1060 outw(StartDMADown, ioaddr + EL3_CMD);
1061 /* queue will be woken at the DMADone interrupt. */
1062 } else {
1063 /* ... and the packet rounded to a doubleword. */
1064 outsl(ioaddr + TX_FIFO, skb->data, (skb->len + 3) >> 2);
1065 dev_kfree_skb(skb);
1066 if (inw(ioaddr + TxFree) > 1536) {
1067 netif_wake_queue(dev);
1068 } else
1069 /* Interrupt us when the FIFO has room for max-sized packet. */
1070 outw(SetTxThreshold + (1536 >> 2),
1071 ioaddr + EL3_CMD);
1072 }
1073#else
1074 /* ... and the packet rounded to a doubleword. */
1075 outsl(ioaddr + TX_FIFO, skb->data, (skb->len + 3) >> 2);
1076 dev_kfree_skb(skb);
1077 if (inw(ioaddr + TxFree) > 1536) {
1078 netif_wake_queue(dev);
1079 } else
1080 /* Interrupt us when the FIFO has room for max-sized packet. */
1081 outw(SetTxThreshold + (1536 >> 2), ioaddr + EL3_CMD);
1082#endif /* bus master */
1083
1084 dev->trans_start = jiffies;
1085
1086 /* Clear the Tx status stack. */
1087 {
1088 short tx_status;
1089 int i = 4;
1090
1091 while (--i > 0 && (tx_status = inb(ioaddr + TxStatus)) > 0) {
1092 if (tx_status & 0x3C) { /* A Tx-disabling error occurred. */
1093 if (corkscrew_debug > 2)
1094 printk("%s: Tx error, status %2.2x.\n",
1095 dev->name, tx_status);
1096 if (tx_status & 0x04)
1097 vp->stats.tx_fifo_errors++;
1098 if (tx_status & 0x38)
1099 vp->stats.tx_aborted_errors++;
1100 if (tx_status & 0x30) {
1101 int j;
1102 outw(TxReset, ioaddr + EL3_CMD);
1103 for (j = 20; j >= 0; j--)
Jeff Garzik6aa20a22006-09-13 13:24:59 -04001104 if (!(inw(ioaddr + EL3_STATUS) & CmdInProgress))
Linus Torvalds1da177e2005-04-16 15:20:36 -07001105 break;
1106 }
1107 outw(TxEnable, ioaddr + EL3_CMD);
1108 }
1109 outb(0x00, ioaddr + TxStatus); /* Pop the status stack. */
1110 }
1111 }
1112 return 0;
1113}
1114
1115/* The interrupt handler does all of the Rx thread work and cleans up
1116 after the Tx thread. */
1117
David Howells7d12e782006-10-05 14:55:46 +01001118static irqreturn_t corkscrew_interrupt(int irq, void *dev_id)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001119{
1120 /* Use the now-standard shared IRQ implementation. */
1121 struct net_device *dev = dev_id;
1122 struct corkscrew_private *lp = netdev_priv(dev);
1123 int ioaddr, status;
1124 int latency;
1125 int i = max_interrupt_work;
1126
1127 ioaddr = dev->base_addr;
1128 latency = inb(ioaddr + Timer);
1129
1130 spin_lock(&lp->lock);
Jeff Garzik6aa20a22006-09-13 13:24:59 -04001131
Linus Torvalds1da177e2005-04-16 15:20:36 -07001132 status = inw(ioaddr + EL3_STATUS);
1133
1134 if (corkscrew_debug > 4)
1135 printk("%s: interrupt, status %4.4x, timer %d.\n",
1136 dev->name, status, latency);
1137 if ((status & 0xE000) != 0xE000) {
1138 static int donedidthis;
1139 /* Some interrupt controllers store a bogus interrupt from boot-time.
1140 Ignore a single early interrupt, but don't hang the machine for
1141 other interrupt problems. */
1142 if (donedidthis++ > 100) {
1143 printk(KERN_ERR "%s: Bogus interrupt, bailing. Status %4.4x, start=%d.\n",
1144 dev->name, status, netif_running(dev));
1145 free_irq(dev->irq, dev);
1146 dev->irq = -1;
1147 }
1148 }
1149
1150 do {
1151 if (corkscrew_debug > 5)
1152 printk("%s: In interrupt loop, status %4.4x.\n",
1153 dev->name, status);
1154 if (status & RxComplete)
1155 corkscrew_rx(dev);
1156
1157 if (status & TxAvailable) {
1158 if (corkscrew_debug > 5)
1159 printk(" TX room bit was handled.\n");
1160 /* There's room in the FIFO for a full-sized packet. */
1161 outw(AckIntr | TxAvailable, ioaddr + EL3_CMD);
1162 netif_wake_queue(dev);
1163 }
1164 if (status & DownComplete) {
1165 unsigned int dirty_tx = lp->dirty_tx;
1166
1167 while (lp->cur_tx - dirty_tx > 0) {
1168 int entry = dirty_tx % TX_RING_SIZE;
1169 if (inl(ioaddr + DownListPtr) == isa_virt_to_bus(&lp->tx_ring[entry]))
1170 break; /* It still hasn't been processed. */
1171 if (lp->tx_skbuff[entry]) {
1172 dev_kfree_skb_irq(lp->tx_skbuff[entry]);
1173 lp->tx_skbuff[entry] = NULL;
1174 }
1175 dirty_tx++;
1176 }
1177 lp->dirty_tx = dirty_tx;
1178 outw(AckIntr | DownComplete, ioaddr + EL3_CMD);
1179 if (lp->tx_full && (lp->cur_tx - dirty_tx <= TX_RING_SIZE - 1)) {
1180 lp->tx_full = 0;
1181 netif_wake_queue(dev);
1182 }
1183 }
1184#ifdef VORTEX_BUS_MASTER
1185 if (status & DMADone) {
1186 outw(0x1000, ioaddr + Wn7_MasterStatus); /* Ack the event. */
1187 dev_kfree_skb_irq(lp->tx_skb); /* Release the transferred buffer */
1188 netif_wake_queue(dev);
1189 }
1190#endif
1191 if (status & UpComplete) {
1192 boomerang_rx(dev);
1193 outw(AckIntr | UpComplete, ioaddr + EL3_CMD);
1194 }
1195 if (status & (AdapterFailure | RxEarly | StatsFull)) {
1196 /* Handle all uncommon interrupts at once. */
1197 if (status & RxEarly) { /* Rx early is unused. */
1198 corkscrew_rx(dev);
1199 outw(AckIntr | RxEarly, ioaddr + EL3_CMD);
1200 }
1201 if (status & StatsFull) { /* Empty statistics. */
1202 static int DoneDidThat;
1203 if (corkscrew_debug > 4)
1204 printk("%s: Updating stats.\n", dev->name);
1205 update_stats(ioaddr, dev);
1206 /* DEBUG HACK: Disable statistics as an interrupt source. */
1207 /* This occurs when we have the wrong media type! */
1208 if (DoneDidThat == 0 && inw(ioaddr + EL3_STATUS) & StatsFull) {
1209 int win, reg;
1210 printk("%s: Updating stats failed, disabling stats as an"
1211 " interrupt source.\n", dev->name);
1212 for (win = 0; win < 8; win++) {
1213 EL3WINDOW(win);
1214 printk("\n Vortex window %d:", win);
1215 for (reg = 0; reg < 16; reg++)
1216 printk(" %2.2x", inb(ioaddr + reg));
1217 }
1218 EL3WINDOW(7);
1219 outw(SetIntrEnb | TxAvailable |
1220 RxComplete | AdapterFailure |
1221 UpComplete | DownComplete |
1222 TxComplete, ioaddr + EL3_CMD);
1223 DoneDidThat++;
1224 }
1225 }
1226 if (status & AdapterFailure) {
1227 /* Adapter failure requires Rx reset and reinit. */
1228 outw(RxReset, ioaddr + EL3_CMD);
1229 /* Set the Rx filter to the current state. */
1230 set_rx_mode(dev);
1231 outw(RxEnable, ioaddr + EL3_CMD); /* Re-enable the receiver. */
1232 outw(AckIntr | AdapterFailure,
1233 ioaddr + EL3_CMD);
1234 }
1235 }
1236
1237 if (--i < 0) {
1238 printk(KERN_ERR "%s: Too much work in interrupt, status %4.4x. "
1239 "Disabling functions (%4.4x).\n", dev->name,
1240 status, SetStatusEnb | ((~status) & 0x7FE));
1241 /* Disable all pending interrupts. */
1242 outw(SetStatusEnb | ((~status) & 0x7FE), ioaddr + EL3_CMD);
1243 outw(AckIntr | 0x7FF, ioaddr + EL3_CMD);
1244 break;
1245 }
1246 /* Acknowledge the IRQ. */
1247 outw(AckIntr | IntReq | IntLatch, ioaddr + EL3_CMD);
1248
1249 } while ((status = inw(ioaddr + EL3_STATUS)) & (IntLatch | RxComplete));
Jeff Garzik6aa20a22006-09-13 13:24:59 -04001250
Linus Torvalds1da177e2005-04-16 15:20:36 -07001251 spin_unlock(&lp->lock);
1252
1253 if (corkscrew_debug > 4)
1254 printk("%s: exiting interrupt, status %4.4x.\n", dev->name, status);
1255 return IRQ_HANDLED;
1256}
1257
1258static int corkscrew_rx(struct net_device *dev)
1259{
1260 struct corkscrew_private *vp = netdev_priv(dev);
1261 int ioaddr = dev->base_addr;
1262 int i;
1263 short rx_status;
1264
1265 if (corkscrew_debug > 5)
1266 printk(" In rx_packet(), status %4.4x, rx_status %4.4x.\n",
1267 inw(ioaddr + EL3_STATUS), inw(ioaddr + RxStatus));
1268 while ((rx_status = inw(ioaddr + RxStatus)) > 0) {
1269 if (rx_status & 0x4000) { /* Error, update stats. */
1270 unsigned char rx_error = inb(ioaddr + RxErrors);
1271 if (corkscrew_debug > 2)
1272 printk(" Rx error: status %2.2x.\n",
1273 rx_error);
1274 vp->stats.rx_errors++;
1275 if (rx_error & 0x01)
1276 vp->stats.rx_over_errors++;
1277 if (rx_error & 0x02)
1278 vp->stats.rx_length_errors++;
1279 if (rx_error & 0x04)
1280 vp->stats.rx_frame_errors++;
1281 if (rx_error & 0x08)
1282 vp->stats.rx_crc_errors++;
1283 if (rx_error & 0x10)
1284 vp->stats.rx_length_errors++;
1285 } else {
1286 /* The packet length: up to 4.5K!. */
1287 short pkt_len = rx_status & 0x1fff;
1288 struct sk_buff *skb;
1289
1290 skb = dev_alloc_skb(pkt_len + 5 + 2);
1291 if (corkscrew_debug > 4)
1292 printk("Receiving packet size %d status %4.4x.\n",
1293 pkt_len, rx_status);
1294 if (skb != NULL) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001295 skb_reserve(skb, 2); /* Align IP on 16 byte boundaries */
1296 /* 'skb_put()' points to the start of sk_buff data area. */
1297 insl(ioaddr + RX_FIFO,
1298 skb_put(skb, pkt_len),
1299 (pkt_len + 3) >> 2);
1300 outw(RxDiscard, ioaddr + EL3_CMD); /* Pop top Rx packet. */
1301 skb->protocol = eth_type_trans(skb, dev);
1302 netif_rx(skb);
1303 dev->last_rx = jiffies;
1304 vp->stats.rx_packets++;
1305 vp->stats.rx_bytes += pkt_len;
1306 /* Wait a limited time to go to next packet. */
1307 for (i = 200; i >= 0; i--)
Jeff Garzik6aa20a22006-09-13 13:24:59 -04001308 if (! (inw(ioaddr + EL3_STATUS) & CmdInProgress))
Linus Torvalds1da177e2005-04-16 15:20:36 -07001309 break;
1310 continue;
1311 } else if (corkscrew_debug)
1312 printk("%s: Couldn't allocate a sk_buff of size %d.\n", dev->name, pkt_len);
1313 }
1314 outw(RxDiscard, ioaddr + EL3_CMD);
1315 vp->stats.rx_dropped++;
1316 /* Wait a limited time to skip this packet. */
1317 for (i = 200; i >= 0; i--)
1318 if (!(inw(ioaddr + EL3_STATUS) & CmdInProgress))
1319 break;
1320 }
1321 return 0;
1322}
1323
1324static int boomerang_rx(struct net_device *dev)
1325{
1326 struct corkscrew_private *vp = netdev_priv(dev);
1327 int entry = vp->cur_rx % RX_RING_SIZE;
1328 int ioaddr = dev->base_addr;
1329 int rx_status;
1330
1331 if (corkscrew_debug > 5)
1332 printk(" In boomerang_rx(), status %4.4x, rx_status %4.4x.\n",
1333 inw(ioaddr + EL3_STATUS), inw(ioaddr + RxStatus));
1334 while ((rx_status = vp->rx_ring[entry].status) & RxDComplete) {
1335 if (rx_status & RxDError) { /* Error, update stats. */
1336 unsigned char rx_error = rx_status >> 16;
1337 if (corkscrew_debug > 2)
1338 printk(" Rx error: status %2.2x.\n",
1339 rx_error);
1340 vp->stats.rx_errors++;
1341 if (rx_error & 0x01)
1342 vp->stats.rx_over_errors++;
1343 if (rx_error & 0x02)
1344 vp->stats.rx_length_errors++;
1345 if (rx_error & 0x04)
1346 vp->stats.rx_frame_errors++;
1347 if (rx_error & 0x08)
1348 vp->stats.rx_crc_errors++;
1349 if (rx_error & 0x10)
1350 vp->stats.rx_length_errors++;
1351 } else {
1352 /* The packet length: up to 4.5K!. */
1353 short pkt_len = rx_status & 0x1fff;
1354 struct sk_buff *skb;
1355
1356 vp->stats.rx_bytes += pkt_len;
1357 if (corkscrew_debug > 4)
1358 printk("Receiving packet size %d status %4.4x.\n",
1359 pkt_len, rx_status);
1360
1361 /* Check if the packet is long enough to just accept without
1362 copying to a properly sized skbuff. */
1363 if (pkt_len < rx_copybreak
1364 && (skb = dev_alloc_skb(pkt_len + 4)) != 0) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001365 skb_reserve(skb, 2); /* Align IP on 16 byte boundaries */
1366 /* 'skb_put()' points to the start of sk_buff data area. */
1367 memcpy(skb_put(skb, pkt_len),
1368 isa_bus_to_virt(vp->rx_ring[entry].
1369 addr), pkt_len);
1370 rx_copy++;
1371 } else {
1372 void *temp;
1373 /* Pass up the skbuff already on the Rx ring. */
1374 skb = vp->rx_skbuff[entry];
1375 vp->rx_skbuff[entry] = NULL;
1376 temp = skb_put(skb, pkt_len);
1377 /* Remove this checking code for final release. */
1378 if (isa_bus_to_virt(vp->rx_ring[entry].addr) != temp)
1379 printk("%s: Warning -- the skbuff addresses do not match"
1380 " in boomerang_rx: %p vs. %p / %p.\n",
1381 dev->name,
1382 isa_bus_to_virt(vp->
1383 rx_ring[entry].
1384 addr), skb->head,
1385 temp);
1386 rx_nocopy++;
1387 }
1388 skb->protocol = eth_type_trans(skb, dev);
1389 netif_rx(skb);
1390 dev->last_rx = jiffies;
1391 vp->stats.rx_packets++;
1392 }
1393 entry = (++vp->cur_rx) % RX_RING_SIZE;
1394 }
1395 /* Refill the Rx ring buffers. */
1396 for (; vp->cur_rx - vp->dirty_rx > 0; vp->dirty_rx++) {
1397 struct sk_buff *skb;
1398 entry = vp->dirty_rx % RX_RING_SIZE;
1399 if (vp->rx_skbuff[entry] == NULL) {
1400 skb = dev_alloc_skb(PKT_BUF_SZ);
1401 if (skb == NULL)
1402 break; /* Bad news! */
1403 skb->dev = dev; /* Mark as being used by this device. */
1404 skb_reserve(skb, 2); /* Align IP on 16 byte boundaries */
David S. Miller689be432005-06-28 15:25:31 -07001405 vp->rx_ring[entry].addr = isa_virt_to_bus(skb->data);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001406 vp->rx_skbuff[entry] = skb;
1407 }
1408 vp->rx_ring[entry].status = 0; /* Clear complete bit. */
1409 }
1410 return 0;
1411}
1412
1413static int corkscrew_close(struct net_device *dev)
1414{
1415 struct corkscrew_private *vp = netdev_priv(dev);
1416 int ioaddr = dev->base_addr;
1417 int i;
1418
1419 netif_stop_queue(dev);
1420
1421 if (corkscrew_debug > 1) {
1422 printk("%s: corkscrew_close() status %4.4x, Tx status %2.2x.\n",
1423 dev->name, inw(ioaddr + EL3_STATUS),
1424 inb(ioaddr + TxStatus));
1425 printk("%s: corkscrew close stats: rx_nocopy %d rx_copy %d"
1426 " tx_queued %d.\n", dev->name, rx_nocopy, rx_copy,
1427 queued_packet);
1428 }
1429
1430 del_timer(&vp->timer);
1431
1432 /* Turn off statistics ASAP. We update lp->stats below. */
1433 outw(StatsDisable, ioaddr + EL3_CMD);
1434
1435 /* Disable the receiver and transmitter. */
1436 outw(RxDisable, ioaddr + EL3_CMD);
1437 outw(TxDisable, ioaddr + EL3_CMD);
1438
1439 if (dev->if_port == XCVR_10base2)
1440 /* Turn off thinnet power. Green! */
1441 outw(StopCoax, ioaddr + EL3_CMD);
1442
1443 free_irq(dev->irq, dev);
1444
1445 outw(SetIntrEnb | 0x0000, ioaddr + EL3_CMD);
1446
1447 update_stats(ioaddr, dev);
1448 if (vp->full_bus_master_rx) { /* Free Boomerang bus master Rx buffers. */
1449 outl(0, ioaddr + UpListPtr);
1450 for (i = 0; i < RX_RING_SIZE; i++)
1451 if (vp->rx_skbuff[i]) {
1452 dev_kfree_skb(vp->rx_skbuff[i]);
1453 vp->rx_skbuff[i] = NULL;
1454 }
1455 }
1456 if (vp->full_bus_master_tx) { /* Free Boomerang bus master Tx buffers. */
1457 outl(0, ioaddr + DownListPtr);
1458 for (i = 0; i < TX_RING_SIZE; i++)
1459 if (vp->tx_skbuff[i]) {
1460 dev_kfree_skb(vp->tx_skbuff[i]);
1461 vp->tx_skbuff[i] = NULL;
1462 }
1463 }
1464
1465 return 0;
1466}
1467
1468static struct net_device_stats *corkscrew_get_stats(struct net_device *dev)
1469{
1470 struct corkscrew_private *vp = netdev_priv(dev);
1471 unsigned long flags;
1472
1473 if (netif_running(dev)) {
1474 spin_lock_irqsave(&vp->lock, flags);
1475 update_stats(dev->base_addr, dev);
1476 spin_unlock_irqrestore(&vp->lock, flags);
1477 }
1478 return &vp->stats;
1479}
1480
1481/* Update statistics.
1482 Unlike with the EL3 we need not worry about interrupts changing
1483 the window setting from underneath us, but we must still guard
1484 against a race condition with a StatsUpdate interrupt updating the
1485 table. This is done by checking that the ASM (!) code generated uses
1486 atomic updates with '+='.
1487 */
1488static void update_stats(int ioaddr, struct net_device *dev)
1489{
1490 struct corkscrew_private *vp = netdev_priv(dev);
1491
1492 /* Unlike the 3c5x9 we need not turn off stats updates while reading. */
1493 /* Switch to the stats window, and read everything. */
1494 EL3WINDOW(6);
1495 vp->stats.tx_carrier_errors += inb(ioaddr + 0);
1496 vp->stats.tx_heartbeat_errors += inb(ioaddr + 1);
1497 /* Multiple collisions. */ inb(ioaddr + 2);
1498 vp->stats.collisions += inb(ioaddr + 3);
1499 vp->stats.tx_window_errors += inb(ioaddr + 4);
1500 vp->stats.rx_fifo_errors += inb(ioaddr + 5);
1501 vp->stats.tx_packets += inb(ioaddr + 6);
1502 vp->stats.tx_packets += (inb(ioaddr + 9) & 0x30) << 4;
1503 /* Rx packets */ inb(ioaddr + 7);
1504 /* Must read to clear */
1505 /* Tx deferrals */ inb(ioaddr + 8);
1506 /* Don't bother with register 9, an extension of registers 6&7.
1507 If we do use the 6&7 values the atomic update assumption above
1508 is invalid. */
1509 inw(ioaddr + 10); /* Total Rx and Tx octets. */
1510 inw(ioaddr + 12);
1511 /* New: On the Vortex we must also clear the BadSSD counter. */
1512 EL3WINDOW(4);
1513 inb(ioaddr + 12);
1514
1515 /* We change back to window 7 (not 1) with the Vortex. */
1516 EL3WINDOW(7);
1517 return;
1518}
1519
1520/* This new version of set_rx_mode() supports v1.4 kernels.
1521 The Vortex chip has no documented multicast filter, so the only
1522 multicast setting is to receive all multicast frames. At least
1523 the chip has a very clean way to set the mode, unlike many others. */
1524static void set_rx_mode(struct net_device *dev)
1525{
1526 int ioaddr = dev->base_addr;
1527 short new_mode;
1528
1529 if (dev->flags & IFF_PROMISC) {
1530 if (corkscrew_debug > 3)
1531 printk("%s: Setting promiscuous mode.\n",
1532 dev->name);
1533 new_mode = SetRxFilter | RxStation | RxMulticast | RxBroadcast | RxProm;
1534 } else if ((dev->mc_list) || (dev->flags & IFF_ALLMULTI)) {
1535 new_mode = SetRxFilter | RxStation | RxMulticast | RxBroadcast;
1536 } else
1537 new_mode = SetRxFilter | RxStation | RxBroadcast;
1538
1539 outw(new_mode, ioaddr + EL3_CMD);
1540}
1541
1542static void netdev_get_drvinfo(struct net_device *dev,
1543 struct ethtool_drvinfo *info)
1544{
1545 strcpy(info->driver, DRV_NAME);
1546 strcpy(info->version, DRV_VERSION);
1547 sprintf(info->bus_info, "ISA 0x%lx", dev->base_addr);
1548}
1549
1550static u32 netdev_get_msglevel(struct net_device *dev)
1551{
1552 return corkscrew_debug;
1553}
1554
1555static void netdev_set_msglevel(struct net_device *dev, u32 level)
1556{
1557 corkscrew_debug = level;
1558}
1559
Jeff Garzik7282d492006-09-13 14:30:00 -04001560static const struct ethtool_ops netdev_ethtool_ops = {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001561 .get_drvinfo = netdev_get_drvinfo,
1562 .get_msglevel = netdev_get_msglevel,
1563 .set_msglevel = netdev_set_msglevel,
1564};
1565
Jeff Garzik6aa20a22006-09-13 13:24:59 -04001566
Linus Torvalds1da177e2005-04-16 15:20:36 -07001567#ifdef MODULE
1568void cleanup_module(void)
1569{
1570 while (!list_empty(&root_corkscrew_dev)) {
1571 struct net_device *dev;
1572 struct corkscrew_private *vp;
1573
1574 vp = list_entry(root_corkscrew_dev.next,
1575 struct corkscrew_private, list);
1576 dev = vp->our_dev;
1577 unregister_netdev(dev);
1578 cleanup_card(dev);
1579 free_netdev(dev);
1580 }
1581}
1582#endif /* MODULE */
Jeff Garzik6aa20a22006-09-13 13:24:59 -04001583
Linus Torvalds1da177e2005-04-16 15:20:36 -07001584/*
1585 * Local variables:
1586 * compile-command: "gcc -DMODULE -D__KERNEL__ -Wall -Wstrict-prototypes -O6 -c 3c515.c"
1587 * c-indent-level: 4
1588 * tab-width: 4
1589 * End:
1590 */