Blame view

drivers/net/3c505.c 47.4 KB
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
  /*
   * Linux Ethernet device driver for the 3Com Etherlink Plus (3C505)
   *      By Craig Southeren, Juha Laiho and Philip Blundell
   *
   * 3c505.c      This module implements an interface to the 3Com
   *              Etherlink Plus (3c505) Ethernet card. Linux device
   *              driver interface reverse engineered from the Linux 3C509
   *              device drivers. Some 3C505 information gleaned from
   *              the Crynwr packet driver. Still this driver would not
   *              be here without 3C505 technical reference provided by
   *              3Com.
   *
   * $Id: 3c505.c,v 1.10 1996/04/16 13:06:27 phil Exp $
   *
   * Authors:     Linux 3c505 device driver by
   *                      Craig Southeren, <craigs@ineluki.apana.org.au>
   *              Final debugging by
   *                      Andrew Tridgell, <tridge@nimbus.anu.edu.au>
   *              Auto irq/address, tuning, cleanup and v1.1.4+ kernel mods by
   *                      Juha Laiho, <jlaiho@ichaos.nullnet.fi>
   *              Linux 3C509 driver by
   *                      Donald Becker, <becker@super.org>
   *			(Now at <becker@scyld.com>)
   *              Crynwr packet driver by
   *                      Krishnan Gopalan and Gregg Stefancik,
   *                      Clemson University Engineering Computer Operations.
   *                      Portions of the code have been adapted from the 3c505
   *                         driver for NCSA Telnet by Bruce Orchard and later
   *                         modified by Warren Van Houten and krus@diku.dk.
   *              3C505 technical information provided by
   *                      Terry Murphy, of 3Com Network Adapter Division
   *              Linux 1.3.0 changes by
   *                      Alan Cox <Alan.Cox@linux.org>
   *              More debugging, DMA support, currently maintained by
   *                      Philip Blundell <philb@gnu.org>
   *              Multicard/soft configurable dma channel/rev 2 hardware support
   *                      by Christopher Collins <ccollins@pcug.org.au>
   *		Ethtool support (jgarzik), 11/17/2001
   */
  
  #define DRV_NAME	"3c505"
  #define DRV_VERSION	"1.10a"
  
  
  /* Theory of operation:
   *
   * The 3c505 is quite an intelligent board.  All communication with it is done
   * by means of Primary Command Blocks (PCBs); these are transferred using PIO
   * through the command register.  The card has 256k of on-board RAM, which is
   * used to buffer received packets.  It might seem at first that more buffers
   * are better, but in fact this isn't true.  From my tests, it seems that
   * more than about 10 buffers are unnecessary, and there is a noticeable
   * performance hit in having more active on the card.  So the majority of the
   * card's memory isn't, in fact, used.  Sadly, the card only has one transmit
   * buffer and, short of loading our own firmware into it (which is what some
   * drivers resort to) there's nothing we can do about this.
   *
   * We keep up to 4 "receive packet" commands active on the board at a time.
   * When a packet comes in, so long as there is a receive command active, the
   * board will send us a "packet received" PCB and then add the data for that
   * packet to the DMA queue.  If a DMA transfer is not already in progress, we
   * set one up to start uploading the data.  We have to maintain a list of
   * backlogged receive packets, because the card may decide to tell us about
   * a newly-arrived packet at any time, and we may not be able to start a DMA
   * transfer immediately (ie one may already be going on).  We can't NAK the
   * PCB, because then it would throw the packet away.
   *
   * Trying to send a PCB to the card at the wrong moment seems to have bad
   * effects.  If we send it a transmit PCB while a receive DMA is happening,
   * it will just NAK the PCB and so we will have wasted our time.  Worse, it
   * sometimes seems to interrupt the transfer.  The majority of the low-level
   * code is protected by one huge semaphore -- "busy" -- which is set whenever
   * it probably isn't safe to do anything to the card.  The receive routine
   * must gain a lock on "busy" before it can start a DMA transfer, and the
   * transmit routine must gain a lock before it sends the first PCB to the card.
   * The send_pcb() routine also has an internal semaphore to protect it against
   * being re-entered (which would be disastrous) -- this is needed because
   * several things can happen asynchronously (re-priming the receiver and
   * asking the card for statistics, for example).  send_pcb() will also refuse
   * to talk to the card at all if a DMA upload is happening.  The higher-level
   * networking code will reschedule a later retry if some part of the driver
   * is blocked.  In practice, this doesn't seem to happen very often.
   */
  
  /* This driver may now work with revision 2.x hardware, since all the read
   * operations on the HCR have been removed (we now keep our own softcopy).
   * But I don't have an old card to test it on.
   *
   * This has had the bad effect that the autoprobe routine is now a bit
   * less friendly to other devices.  However, it was never very good.
   * before, so I doubt it will hurt anybody.
   */
  
  /* The driver is a mess.  I took Craig's and Juha's code, and hacked it firstly
   * to make it more reliable, and secondly to add DMA mode.  Many things could
   * probably be done better; the concurrency protection is particularly awful.
   */
  
  #include <linux/module.h>
  #include <linux/kernel.h>
  #include <linux/string.h>
  #include <linux/interrupt.h>
  #include <linux/errno.h>
  #include <linux/in.h>
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
105
106
107
108
109
  #include <linux/ioport.h>
  #include <linux/spinlock.h>
  #include <linux/ethtool.h>
  #include <linux/delay.h>
  #include <linux/bitops.h>
5a0e3ad6a   Tejun Heo   include cleanup: ...
110
  #include <linux/gfp.h>
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
  
  #include <asm/uaccess.h>
  #include <asm/io.h>
  #include <asm/dma.h>
  
  #include <linux/netdevice.h>
  #include <linux/etherdevice.h>
  #include <linux/skbuff.h>
  #include <linux/init.h>
  
  #include "3c505.h"
  
  /*********************************************************
   *
   *  define debug messages here as common strings to reduce space
   *
   *********************************************************/
646cdb328   Alexander Beregalov   3c50x: convert pr...
128
  #define filename __FILE__
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
129

646cdb328   Alexander Beregalov   3c50x: convert pr...
130
131
  #define timeout_msg "*** timeout at %s:%s (line %d) ***
  "
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
132
  #define TIMEOUT_MSG(lineno) \
646cdb328   Alexander Beregalov   3c50x: convert pr...
133
  	pr_notice(timeout_msg, filename, __func__, (lineno))
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
134

646cdb328   Alexander Beregalov   3c50x: convert pr...
135
136
  #define invalid_pcb_msg "*** invalid pcb length %d at %s:%s (line %d) ***
  "
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
137
  #define INVALID_PCB_MSG(len) \
646cdb328   Alexander Beregalov   3c50x: convert pr...
138
  	pr_notice(invalid_pcb_msg, (len), filename, __func__, __LINE__)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
139

646cdb328   Alexander Beregalov   3c50x: convert pr...
140
  #define search_msg "%s: Looking for 3c505 adapter at address %#x..."
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
141

646cdb328   Alexander Beregalov   3c50x: convert pr...
142
  #define stilllooking_msg "still looking..."
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
143

646cdb328   Alexander Beregalov   3c50x: convert pr...
144
145
  #define found_msg "found.
  "
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
146

646cdb328   Alexander Beregalov   3c50x: convert pr...
147
148
  #define notfound_msg "not found (reason = %d)
  "
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
149

646cdb328   Alexander Beregalov   3c50x: convert pr...
150
151
  #define couldnot_msg "%s: 3c505 not found
  "
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
  
  /*********************************************************
   *
   *  various other debug stuff
   *
   *********************************************************/
  
  #ifdef ELP_DEBUG
  static int elp_debug = ELP_DEBUG;
  #else
  static int elp_debug;
  #endif
  #define debug elp_debug
  
  /*
   *  0 = no messages (well, some)
   *  1 = messages when high level commands performed
   *  2 = messages when low level commands performed
   *  3 = messages when interrupts received
   */
  
  /*****************************************************************
   *
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
   * List of I/O-addresses we try to auto-sense
   * Last element MUST BE 0!
   *****************************************************************/
  
  static int addr_list[] __initdata = {0x300, 0x280, 0x310, 0};
  
  /* Dma Memory related stuff */
  
  static unsigned long dma_mem_alloc(int size)
  {
  	int order = get_order(size);
  	return __get_dma_pages(GFP_KERNEL, order);
  }
  
  
  /*****************************************************************
   *
   * Functions for I/O (note the inline !)
   *
   *****************************************************************/
  
  static inline unsigned char inb_status(unsigned int base_addr)
  {
  	return inb(base_addr + PORT_STATUS);
  }
  
  static inline int inb_command(unsigned int base_addr)
  {
  	return inb(base_addr + PORT_COMMAND);
  }
  
  static inline void outb_control(unsigned char val, struct net_device *dev)
  {
  	outb(val, dev->base_addr + PORT_CONTROL);
454d7c9b1   Wang Chen   netdevice: safe c...
209
  	((elp_device *)(netdev_priv(dev)))->hcr_val = val;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
210
  }
454d7c9b1   Wang Chen   netdevice: safe c...
211
  #define HCR_VAL(x)   (((elp_device *)(netdev_priv(x)))->hcr_val)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
  
  static inline void outb_command(unsigned char val, unsigned int base_addr)
  {
  	outb(val, base_addr + PORT_COMMAND);
  }
  
  static inline unsigned int backlog_next(unsigned int n)
  {
  	return (n + 1) % BACKLOG_SIZE;
  }
  
  /*****************************************************************
   *
   *  useful functions for accessing the adapter
   *
   *****************************************************************/
  
  /*
   * use this routine when accessing the ASF bits as they are
   * changed asynchronously by the adapter
   */
  
  /* get adapter PCB status */
  #define	GET_ASF(addr) \
  	(get_status(addr)&ASF_PCB_MASK)
  
  static inline int get_status(unsigned int base_addr)
  {
  	unsigned long timeout = jiffies + 10*HZ/100;
  	register int stat1;
  	do {
  		stat1 = inb_status(base_addr);
  	} while (stat1 != inb_status(base_addr) && time_before(jiffies, timeout));
  	if (time_after_eq(jiffies, timeout))
  		TIMEOUT_MSG(__LINE__);
  	return stat1;
  }
  
  static inline void set_hsf(struct net_device *dev, int hsf)
  {
454d7c9b1   Wang Chen   netdevice: safe c...
252
  	elp_device *adapter = netdev_priv(dev);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
253
254
255
256
257
258
  	unsigned long flags;
  
  	spin_lock_irqsave(&adapter->lock, flags);
  	outb_control((HCR_VAL(dev) & ~HSF_PCB_MASK) | hsf, dev);
  	spin_unlock_irqrestore(&adapter->lock, flags);
  }
df570f933   Richard Knutsson   drivers/net/3c505...
259
  static bool start_receive(struct net_device *, pcb_struct *);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
260

77933d727   Jesper Juhl   [PATCH] clean up ...
261
  static inline void adapter_reset(struct net_device *dev)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
262
263
  {
  	unsigned long timeout;
454d7c9b1   Wang Chen   netdevice: safe c...
264
  	elp_device *adapter = netdev_priv(dev);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
  	unsigned char orig_hcr = adapter->hcr_val;
  
  	outb_control(0, dev);
  
  	if (inb_status(dev->base_addr) & ACRF) {
  		do {
  			inb_command(dev->base_addr);
  			timeout = jiffies + 2*HZ/100;
  			while (time_before_eq(jiffies, timeout) && !(inb_status(dev->base_addr) & ACRF));
  		} while (inb_status(dev->base_addr) & ACRF);
  		set_hsf(dev, HSF_PCB_NAK);
  	}
  	outb_control(adapter->hcr_val | ATTN | DIR, dev);
  	mdelay(10);
  	outb_control(adapter->hcr_val & ~ATTN, dev);
  	mdelay(10);
  	outb_control(adapter->hcr_val | FLSH, dev);
  	mdelay(10);
  	outb_control(adapter->hcr_val & ~FLSH, dev);
  	mdelay(10);
  
  	outb_control(orig_hcr, dev);
  	if (!start_receive(dev, &adapter->tx_pcb))
646cdb328   Alexander Beregalov   3c50x: convert pr...
288
289
  		pr_err("%s: start receive command failed
  ", dev->name);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
290
291
292
293
294
295
296
297
  }
  
  /* Check to make sure that a DMA transfer hasn't timed out.  This should
   * never happen in theory, but seems to occur occasionally if the card gets
   * prodded at the wrong time.
   */
  static inline void check_3c505_dma(struct net_device *dev)
  {
454d7c9b1   Wang Chen   netdevice: safe c...
298
  	elp_device *adapter = netdev_priv(dev);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
299
300
  	if (adapter->dmaing && time_after(jiffies, adapter->current_dma.start_time + 10)) {
  		unsigned long flags, f;
646cdb328   Alexander Beregalov   3c50x: convert pr...
301
302
303
304
  		pr_err("%s: DMA %s timed out, %d bytes left
  ", dev->name,
  			adapter->current_dma.direction ? "download" : "upload",
  			get_dma_residue(dev->dma));
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
305
306
307
  		spin_lock_irqsave(&adapter->lock, flags);
  		adapter->dmaing = 0;
  		adapter->busy = 0;
6aa20a223   Jeff Garzik   drivers/net: Trim...
308

1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
309
310
311
  		f=claim_dma_lock();
  		disable_dma(dev->dma);
  		release_dma_lock(f);
6aa20a223   Jeff Garzik   drivers/net: Trim...
312

1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
313
314
315
316
317
318
319
320
  		if (adapter->rx_active)
  			adapter->rx_active--;
  		outb_control(adapter->hcr_val & ~(DMAE | TCEN | DIR), dev);
  		spin_unlock_irqrestore(&adapter->lock, flags);
  	}
  }
  
  /* Primitive functions used by send_pcb() */
df570f933   Richard Knutsson   drivers/net/3c505...
321
  static inline bool send_pcb_slow(unsigned int base_addr, unsigned char byte)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
322
323
324
325
326
  {
  	unsigned long timeout;
  	outb_command(byte, base_addr);
  	for (timeout = jiffies + 5*HZ/100; time_before(jiffies, timeout);) {
  		if (inb_status(base_addr) & HCRE)
df570f933   Richard Knutsson   drivers/net/3c505...
327
  			return false;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
328
  	}
646cdb328   Alexander Beregalov   3c50x: convert pr...
329
330
  	pr_warning("3c505: send_pcb_slow timed out
  ");
df570f933   Richard Knutsson   drivers/net/3c505...
331
  	return true;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
332
  }
df570f933   Richard Knutsson   drivers/net/3c505...
333
  static inline bool send_pcb_fast(unsigned int base_addr, unsigned char byte)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
334
335
336
337
338
  {
  	unsigned int timeout;
  	outb_command(byte, base_addr);
  	for (timeout = 0; timeout < 40000; timeout++) {
  		if (inb_status(base_addr) & HCRE)
df570f933   Richard Knutsson   drivers/net/3c505...
339
  			return false;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
340
  	}
646cdb328   Alexander Beregalov   3c50x: convert pr...
341
342
  	pr_warning("3c505: send_pcb_fast timed out
  ");
df570f933   Richard Knutsson   drivers/net/3c505...
343
  	return true;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
344
345
346
347
348
  }
  
  /* Check to see if the receiver needs restarting, and kick it if so */
  static inline void prime_rx(struct net_device *dev)
  {
454d7c9b1   Wang Chen   netdevice: safe c...
349
  	elp_device *adapter = netdev_priv(dev);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
  	while (adapter->rx_active < ELP_RX_PCBS && netif_running(dev)) {
  		if (!start_receive(dev, &adapter->itx_pcb))
  			break;
  	}
  }
  
  /*****************************************************************
   *
   * send_pcb
   *   Send a PCB to the adapter.
   *
   *	output byte to command reg  --<--+
   *	wait until HCRE is non zero      |
   *	loop until all bytes sent   -->--+
   *	set HSF1 and HSF2 to 1
   *	output pcb length
   *	wait until ASF give ACK or NAK
   *	set HSF1 and HSF2 to 0
   *
   *****************************************************************/
  
  /* This can be quite slow -- the adapter is allowed to take up to 40ms
   * to respond to the initial interrupt.
   *
   * We run initially with interrupts turned on, but with a semaphore set
   * so that nobody tries to re-enter this code.  Once the first byte has
   * gone through, we turn interrupts off and then send the others (the
   * timeout is reduced to 500us).
   */
df570f933   Richard Knutsson   drivers/net/3c505...
379
  static bool send_pcb(struct net_device *dev, pcb_struct * pcb)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
380
381
382
  {
  	int i;
  	unsigned long timeout;
454d7c9b1   Wang Chen   netdevice: safe c...
383
  	elp_device *adapter = netdev_priv(dev);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
384
385
386
387
388
  	unsigned long flags;
  
  	check_3c505_dma(dev);
  
  	if (adapter->dmaing && adapter->current_dma.direction == 0)
df570f933   Richard Knutsson   drivers/net/3c505...
389
  		return false;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
390
391
392
393
  
  	/* Avoid contention */
  	if (test_and_set_bit(1, &adapter->send_pcb_semaphore)) {
  		if (elp_debug >= 3) {
646cdb328   Alexander Beregalov   3c50x: convert pr...
394
395
  			pr_debug("%s: send_pcb entered while threaded
  ", dev->name);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
396
  		}
df570f933   Richard Knutsson   drivers/net/3c505...
397
  		return false;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
  	}
  	/*
  	 * load each byte into the command register and
  	 * wait for the HCRE bit to indicate the adapter
  	 * had read the byte
  	 */
  	set_hsf(dev, 0);
  
  	if (send_pcb_slow(dev->base_addr, pcb->command))
  		goto abort;
  
  	spin_lock_irqsave(&adapter->lock, flags);
  
  	if (send_pcb_fast(dev->base_addr, pcb->length))
  		goto sti_abort;
  
  	for (i = 0; i < pcb->length; i++) {
  		if (send_pcb_fast(dev->base_addr, pcb->data.raw[i]))
  			goto sti_abort;
  	}
  
  	outb_control(adapter->hcr_val | 3, dev);	/* signal end of PCB */
  	outb_command(2 + pcb->length, dev->base_addr);
  
  	/* now wait for the acknowledgement */
  	spin_unlock_irqrestore(&adapter->lock, flags);
  
  	for (timeout = jiffies + 5*HZ/100; time_before(jiffies, timeout);) {
  		switch (GET_ASF(dev->base_addr)) {
  		case ASF_PCB_ACK:
  			adapter->send_pcb_semaphore = 0;
df570f933   Richard Knutsson   drivers/net/3c505...
429
  			return true;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
430
431
432
  
  		case ASF_PCB_NAK:
  #ifdef ELP_DEBUG
646cdb328   Alexander Beregalov   3c50x: convert pr...
433
434
  			pr_debug("%s: send_pcb got NAK
  ", dev->name);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
435
436
437
438
439
440
  #endif
  			goto abort;
  		}
  	}
  
  	if (elp_debug >= 1)
646cdb328   Alexander Beregalov   3c50x: convert pr...
441
442
443
  		pr_debug("%s: timeout waiting for PCB acknowledge (status %02x)
  ",
  			dev->name, inb_status(dev->base_addr));
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
444
445
446
447
448
449
  	goto abort;
  
        sti_abort:
  	spin_unlock_irqrestore(&adapter->lock, flags);
        abort:
  	adapter->send_pcb_semaphore = 0;
df570f933   Richard Knutsson   drivers/net/3c505...
450
  	return false;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
  }
  
  
  /*****************************************************************
   *
   * receive_pcb
   *   Read a PCB from the adapter
   *
   *	wait for ACRF to be non-zero        ---<---+
   *	input a byte                               |
   *	if ASF1 and ASF2 were not both one         |
   *		before byte was read, loop      --->---+
   *	set HSF1 and HSF2 for ack
   *
   *****************************************************************/
df570f933   Richard Knutsson   drivers/net/3c505...
466
  static bool receive_pcb(struct net_device *dev, pcb_struct * pcb)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
467
468
469
470
471
472
  {
  	int i, j;
  	int total_length;
  	int stat;
  	unsigned long timeout;
  	unsigned long flags;
454d7c9b1   Wang Chen   netdevice: safe c...
473
  	elp_device *adapter = netdev_priv(dev);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
474
475
476
477
478
479
480
481
  
  	set_hsf(dev, 0);
  
  	/* get the command code */
  	timeout = jiffies + 2*HZ/100;
  	while (((stat = get_status(dev->base_addr)) & ACRF) == 0 && time_before(jiffies, timeout));
  	if (time_after_eq(jiffies, timeout)) {
  		TIMEOUT_MSG(__LINE__);
df570f933   Richard Knutsson   drivers/net/3c505...
482
  		return false;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
483
484
485
486
487
488
489
490
  	}
  	pcb->command = inb_command(dev->base_addr);
  
  	/* read the data length */
  	timeout = jiffies + 3*HZ/100;
  	while (((stat = get_status(dev->base_addr)) & ACRF) == 0 && time_before(jiffies, timeout));
  	if (time_after_eq(jiffies, timeout)) {
  		TIMEOUT_MSG(__LINE__);
646cdb328   Alexander Beregalov   3c50x: convert pr...
491
492
  		pr_info("%s: status %02x
  ", dev->name, stat);
df570f933   Richard Knutsson   drivers/net/3c505...
493
  		return false;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
494
495
496
497
498
499
  	}
  	pcb->length = inb_command(dev->base_addr);
  
  	if (pcb->length > MAX_PCB_DATA) {
  		INVALID_PCB_MSG(pcb->length);
  		adapter_reset(dev);
df570f933   Richard Knutsson   drivers/net/3c505...
500
  		return false;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
501
502
503
  	}
  	/* read the data */
  	spin_lock_irqsave(&adapter->lock, flags);
501aa061b   Roel Kluin   3c505: do not set...
504
505
506
507
508
509
510
511
512
513
  	for (i = 0; i < MAX_PCB_DATA; i++) {
  		for (j = 0; j < 20000; j++) {
  			stat = get_status(dev->base_addr);
  			if (stat & ACRF)
  				break;
  		}
  		pcb->data.raw[i] = inb_command(dev->base_addr);
  		if ((stat & ASF_PCB_MASK) == ASF_PCB_END || j >= 20000)
  			break;
  	}
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
514
  	spin_unlock_irqrestore(&adapter->lock, flags);
501aa061b   Roel Kluin   3c505: do not set...
515
516
517
518
  	if (i >= MAX_PCB_DATA) {
  		INVALID_PCB_MSG(i);
  		return false;
  	}
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
519
520
  	if (j >= 20000) {
  		TIMEOUT_MSG(__LINE__);
df570f933   Richard Knutsson   drivers/net/3c505...
521
  		return false;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
522
  	}
501aa061b   Roel Kluin   3c505: do not set...
523
524
  	/* the last "data" byte was really the length! */
  	total_length = pcb->data.raw[i];
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
525
526
527
528
  
  	/* safety check total length vs data length */
  	if (total_length != (pcb->length + 2)) {
  		if (elp_debug >= 2)
646cdb328   Alexander Beregalov   3c50x: convert pr...
529
530
  			pr_warning("%s: mangled PCB received
  ", dev->name);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
531
  		set_hsf(dev, HSF_PCB_NAK);
df570f933   Richard Knutsson   drivers/net/3c505...
532
  		return false;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
533
534
535
536
537
538
  	}
  
  	if (pcb->command == CMD_RECEIVE_PACKET_COMPLETE) {
  		if (test_and_set_bit(0, (void *) &adapter->busy)) {
  			if (backlog_next(adapter->rx_backlog.in) == adapter->rx_backlog.out) {
  				set_hsf(dev, HSF_PCB_NAK);
646cdb328   Alexander Beregalov   3c50x: convert pr...
539
540
  				pr_warning("%s: PCB rejected, transfer in progress and backlog full
  ", dev->name);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
541
  				pcb->command = 0;
df570f933   Richard Knutsson   drivers/net/3c505...
542
  				return true;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
543
544
545
546
547
548
  			} else {
  				pcb->command = 0xff;
  			}
  		}
  	}
  	set_hsf(dev, HSF_PCB_ACK);
df570f933   Richard Knutsson   drivers/net/3c505...
549
  	return true;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
550
551
552
553
554
555
556
557
  }
  
  /******************************************************
   *
   *  queue a receive command on the adapter so we will get an
   *  interrupt when a packet is received.
   *
   ******************************************************/
df570f933   Richard Knutsson   drivers/net/3c505...
558
  static bool start_receive(struct net_device *dev, pcb_struct * tx_pcb)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
559
  {
df570f933   Richard Knutsson   drivers/net/3c505...
560
  	bool status;
454d7c9b1   Wang Chen   netdevice: safe c...
561
  	elp_device *adapter = netdev_priv(dev);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
562
563
  
  	if (elp_debug >= 3)
646cdb328   Alexander Beregalov   3c50x: convert pr...
564
565
  		pr_debug("%s: restarting receiver
  ", dev->name);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
  	tx_pcb->command = CMD_RECEIVE_PACKET;
  	tx_pcb->length = sizeof(struct Rcv_pkt);
  	tx_pcb->data.rcv_pkt.buf_seg
  	    = tx_pcb->data.rcv_pkt.buf_ofs = 0;		/* Unused */
  	tx_pcb->data.rcv_pkt.buf_len = 1600;
  	tx_pcb->data.rcv_pkt.timeout = 0;	/* set timeout to zero */
  	status = send_pcb(dev, tx_pcb);
  	if (status)
  		adapter->rx_active++;
  	return status;
  }
  
  /******************************************************
   *
   * extract a packet from the adapter
   * this routine is only called from within the interrupt
   * service routine, so no cli/sti calls are needed
   * note that the length is always assumed to be even
   *
   ******************************************************/
  
  static void receive_packet(struct net_device *dev, int len)
  {
  	int rlen;
454d7c9b1   Wang Chen   netdevice: safe c...
590
  	elp_device *adapter = netdev_priv(dev);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
591
592
593
594
595
596
597
598
  	void *target;
  	struct sk_buff *skb;
  	unsigned long flags;
  
  	rlen = (len + 1) & ~1;
  	skb = dev_alloc_skb(rlen + 2);
  
  	if (!skb) {
646cdb328   Alexander Beregalov   3c50x: convert pr...
599
600
  		pr_warning("%s: memory squeeze, dropping packet
  ", dev->name);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
  		target = adapter->dma_buffer;
  		adapter->current_dma.target = NULL;
  		/* FIXME: stats */
  		return;
  	}
  
  	skb_reserve(skb, 2);
  	target = skb_put(skb, rlen);
  	if ((unsigned long)(target + rlen) >= MAX_DMA_ADDRESS) {
  		adapter->current_dma.target = target;
  		target = adapter->dma_buffer;
  	} else {
  		adapter->current_dma.target = NULL;
  	}
  
  	/* if this happens, we die */
  	if (test_and_set_bit(0, (void *) &adapter->dmaing))
646cdb328   Alexander Beregalov   3c50x: convert pr...
618
619
620
  		pr_err("%s: rx blocked, DMA in progress, dir %d
  ",
  			dev->name, adapter->current_dma.direction);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
621

1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
  	adapter->current_dma.direction = 0;
  	adapter->current_dma.length = rlen;
  	adapter->current_dma.skb = skb;
  	adapter->current_dma.start_time = jiffies;
  
  	outb_control(adapter->hcr_val | DIR | TCEN | DMAE, dev);
  
  	flags=claim_dma_lock();
  	disable_dma(dev->dma);
  	clear_dma_ff(dev->dma);
  	set_dma_mode(dev->dma, 0x04);	/* dma read */
  	set_dma_addr(dev->dma, isa_virt_to_bus(target));
  	set_dma_count(dev->dma, rlen);
  	enable_dma(dev->dma);
  	release_dma_lock(flags);
  
  	if (elp_debug >= 3) {
646cdb328   Alexander Beregalov   3c50x: convert pr...
639
640
  		pr_debug("%s: rx DMA transfer started
  ", dev->name);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
641
642
643
644
645
646
  	}
  
  	if (adapter->rx_active)
  		adapter->rx_active--;
  
  	if (!adapter->busy)
646cdb328   Alexander Beregalov   3c50x: convert pr...
647
648
  		pr_warning("%s: receive_packet called, busy not set.
  ", dev->name);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
649
650
651
652
653
654
655
  }
  
  /******************************************************
   *
   * interrupt handler
   *
   ******************************************************/
7d12e780e   David Howells   IRQ: Maintain reg...
656
  static irqreturn_t elp_interrupt(int irq, void *dev_id)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
657
658
659
660
  {
  	int len;
  	int dlen;
  	int icount = 0;
454d7c9b1   Wang Chen   netdevice: safe c...
661
662
  	struct net_device *dev = dev_id;
  	elp_device *adapter = netdev_priv(dev);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
663
  	unsigned long timeout;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
664
665
666
667
668
669
670
  	spin_lock(&adapter->lock);
  
  	do {
  		/*
  		 * has a DMA transfer finished?
  		 */
  		if (inb_status(dev->base_addr) & DONE) {
646cdb328   Alexander Beregalov   3c50x: convert pr...
671
672
673
674
675
676
677
678
679
  			if (!adapter->dmaing)
  				pr_warning("%s: phantom DMA completed
  ", dev->name);
  
  			if (elp_debug >= 3)
  				pr_debug("%s: %s DMA complete, status %02x
  ", dev->name,
  					adapter->current_dma.direction ? "tx" : "rx",
  					inb_status(dev->base_addr));
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
680
681
682
683
684
685
686
687
688
689
690
691
  
  			outb_control(adapter->hcr_val & ~(DMAE | TCEN | DIR), dev);
  			if (adapter->current_dma.direction) {
  				dev_kfree_skb_irq(adapter->current_dma.skb);
  			} else {
  				struct sk_buff *skb = adapter->current_dma.skb;
  				if (skb) {
  					if (adapter->current_dma.target) {
  				  	/* have already done the skb_put() */
  				  	memcpy(adapter->current_dma.target, adapter->dma_buffer, adapter->current_dma.length);
  					}
  					skb->protocol = eth_type_trans(skb,dev);
ba0f6caeb   Paulius Zaleckas   3c505: use netsta...
692
  					dev->stats.rx_bytes += skb->len;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
693
  					netif_rx(skb);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
694
695
696
697
698
699
700
  				}
  			}
  			adapter->dmaing = 0;
  			if (adapter->rx_backlog.in != adapter->rx_backlog.out) {
  				int t = adapter->rx_backlog.length[adapter->rx_backlog.out];
  				adapter->rx_backlog.out = backlog_next(adapter->rx_backlog.out);
  				if (elp_debug >= 2)
646cdb328   Alexander Beregalov   3c50x: convert pr...
701
702
  					pr_debug("%s: receiving backlogged packet (%d)
  ", dev->name, t);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
703
704
705
706
707
708
709
710
711
712
713
714
715
716
717
  				receive_packet(dev, t);
  			} else {
  				adapter->busy = 0;
  			}
  		} else {
  			/* has one timed out? */
  			check_3c505_dma(dev);
  		}
  
  		/*
  		 * receive a PCB from the adapter
  		 */
  		timeout = jiffies + 3*HZ/100;
  		while ((inb_status(dev->base_addr) & ACRF) != 0 && time_before(jiffies, timeout)) {
  			if (receive_pcb(dev, &adapter->irx_pcb)) {
6aa20a223   Jeff Garzik   drivers/net: Trim...
718
  				switch (adapter->irx_pcb.command)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
719
720
721
722
723
724
725
726
727
728
729
730
731
732
  				{
  				case 0:
  					break;
  					/*
  					 * received a packet - this must be handled fast
  					 */
  				case 0xff:
  				case CMD_RECEIVE_PACKET_COMPLETE:
  					/* if the device isn't open, don't pass packets up the stack */
  					if (!netif_running(dev))
  						break;
  					len = adapter->irx_pcb.data.rcv_resp.pkt_len;
  					dlen = adapter->irx_pcb.data.rcv_resp.buf_len;
  					if (adapter->irx_pcb.data.rcv_resp.timeout != 0) {
646cdb328   Alexander Beregalov   3c50x: convert pr...
733
734
  						pr_err("%s: interrupt - packet not received correctly
  ", dev->name);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
735
736
  					} else {
  						if (elp_debug >= 3) {
646cdb328   Alexander Beregalov   3c50x: convert pr...
737
738
739
  							pr_debug("%s: interrupt - packet received of length %i (%i)
  ",
  								dev->name, len, dlen);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
740
741
742
  						}
  						if (adapter->irx_pcb.command == 0xff) {
  							if (elp_debug >= 2)
646cdb328   Alexander Beregalov   3c50x: convert pr...
743
744
745
  								pr_debug("%s: adding packet to backlog (len = %d)
  ",
  									dev->name, dlen);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
746
747
748
749
750
751
  							adapter->rx_backlog.length[adapter->rx_backlog.in] = dlen;
  							adapter->rx_backlog.in = backlog_next(adapter->rx_backlog.in);
  						} else {
  							receive_packet(dev, dlen);
  						}
  						if (elp_debug >= 3)
646cdb328   Alexander Beregalov   3c50x: convert pr...
752
753
  							pr_debug("%s: packet received
  ", dev->name);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
754
755
756
757
758
759
760
761
762
  					}
  					break;
  
  					/*
  					 * 82586 configured correctly
  					 */
  				case CMD_CONFIGURE_82586_RESPONSE:
  					adapter->got[CMD_CONFIGURE_82586] = 1;
  					if (elp_debug >= 3)
646cdb328   Alexander Beregalov   3c50x: convert pr...
763
764
  						pr_debug("%s: interrupt - configure response received
  ", dev->name);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
765
766
767
768
769
770
771
772
  					break;
  
  					/*
  					 * Adapter memory configuration
  					 */
  				case CMD_CONFIGURE_ADAPTER_RESPONSE:
  					adapter->got[CMD_CONFIGURE_ADAPTER_MEMORY] = 1;
  					if (elp_debug >= 3)
646cdb328   Alexander Beregalov   3c50x: convert pr...
773
774
  						pr_debug("%s: Adapter memory configuration %s.
  ", dev->name,
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
775
776
777
778
779
780
781
782
783
  						       adapter->irx_pcb.data.failed ? "failed" : "succeeded");
  					break;
  
  					/*
  					 * Multicast list loading
  					 */
  				case CMD_LOAD_MULTICAST_RESPONSE:
  					adapter->got[CMD_LOAD_MULTICAST_LIST] = 1;
  					if (elp_debug >= 3)
646cdb328   Alexander Beregalov   3c50x: convert pr...
784
785
  						pr_debug("%s: Multicast address list loading %s.
  ", dev->name,
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
786
787
788
789
790
791
792
793
794
  						       adapter->irx_pcb.data.failed ? "failed" : "succeeded");
  					break;
  
  					/*
  					 * Station address setting
  					 */
  				case CMD_SET_ADDRESS_RESPONSE:
  					adapter->got[CMD_SET_STATION_ADDRESS] = 1;
  					if (elp_debug >= 3)
646cdb328   Alexander Beregalov   3c50x: convert pr...
795
796
  						pr_debug("%s: Ethernet address setting %s.
  ", dev->name,
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
797
798
799
800
801
802
803
804
  						       adapter->irx_pcb.data.failed ? "failed" : "succeeded");
  					break;
  
  
  					/*
  					 * received board statistics
  					 */
  				case CMD_NETWORK_STATISTICS_RESPONSE:
ba0f6caeb   Paulius Zaleckas   3c505: use netsta...
805
806
807
808
809
810
  					dev->stats.rx_packets += adapter->irx_pcb.data.netstat.tot_recv;
  					dev->stats.tx_packets += adapter->irx_pcb.data.netstat.tot_xmit;
  					dev->stats.rx_crc_errors += adapter->irx_pcb.data.netstat.err_CRC;
  					dev->stats.rx_frame_errors += adapter->irx_pcb.data.netstat.err_align;
  					dev->stats.rx_fifo_errors += adapter->irx_pcb.data.netstat.err_ovrrun;
  					dev->stats.rx_over_errors += adapter->irx_pcb.data.netstat.err_res;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
811
812
  					adapter->got[CMD_NETWORK_STATISTICS] = 1;
  					if (elp_debug >= 3)
646cdb328   Alexander Beregalov   3c50x: convert pr...
813
814
  						pr_debug("%s: interrupt - statistics response received
  ", dev->name);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
815
816
817
818
819
820
821
  					break;
  
  					/*
  					 * sent a packet
  					 */
  				case CMD_TRANSMIT_PACKET_COMPLETE:
  					if (elp_debug >= 3)
646cdb328   Alexander Beregalov   3c50x: convert pr...
822
823
  						pr_debug("%s: interrupt - packet sent
  ", dev->name);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
824
825
826
827
  					if (!netif_running(dev))
  						break;
  					switch (adapter->irx_pcb.data.xmit_resp.c_stat) {
  					case 0xffff:
ba0f6caeb   Paulius Zaleckas   3c505: use netsta...
828
  						dev->stats.tx_aborted_errors++;
646cdb328   Alexander Beregalov   3c50x: convert pr...
829
830
  						pr_info("%s: transmit timed out, network cable problem?
  ", dev->name);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
831
832
  						break;
  					case 0xfffe:
ba0f6caeb   Paulius Zaleckas   3c505: use netsta...
833
  						dev->stats.tx_fifo_errors++;
646cdb328   Alexander Beregalov   3c50x: convert pr...
834
835
  						pr_info("%s: transmit timed out, FIFO underrun
  ", dev->name);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
836
837
838
839
840
841
842
843
844
  						break;
  					}
  					netif_wake_queue(dev);
  					break;
  
  					/*
  					 * some unknown PCB
  					 */
  				default:
646cdb328   Alexander Beregalov   3c50x: convert pr...
845
846
847
  					pr_debug("%s: unknown PCB received - %2.2x
  ",
  						dev->name, adapter->irx_pcb.command);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
848
849
850
  					break;
  				}
  			} else {
646cdb328   Alexander Beregalov   3c50x: convert pr...
851
852
  				pr_warning("%s: failed to read PCB on interrupt
  ", dev->name);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
853
854
855
856
857
858
859
860
861
862
863
864
865
866
867
868
869
870
871
872
873
874
875
876
  				adapter_reset(dev);
  			}
  		}
  
  	} while (icount++ < 5 && (inb_status(dev->base_addr) & (ACRF | DONE)));
  
  	prime_rx(dev);
  
  	/*
  	 * indicate no longer in interrupt routine
  	 */
  	spin_unlock(&adapter->lock);
  	return IRQ_HANDLED;
  }
  
  
  /******************************************************
   *
   * open the board
   *
   ******************************************************/
  
  static int elp_open(struct net_device *dev)
  {
454d7c9b1   Wang Chen   netdevice: safe c...
877
  	elp_device *adapter = netdev_priv(dev);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
878
  	int retval;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
879
  	if (elp_debug >= 3)
646cdb328   Alexander Beregalov   3c50x: convert pr...
880
881
  		pr_debug("%s: request to open device
  ", dev->name);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
882
883
884
885
886
  
  	/*
  	 * make sure we actually found the device
  	 */
  	if (adapter == NULL) {
646cdb328   Alexander Beregalov   3c50x: convert pr...
887
888
  		pr_err("%s: Opening a non-existent physical device
  ", dev->name);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
889
890
891
892
893
894
895
896
897
898
899
900
901
902
903
904
905
906
907
908
909
910
  		return -EAGAIN;
  	}
  	/*
  	 * disable interrupts on the board
  	 */
  	outb_control(0, dev);
  
  	/*
  	 * clear any pending interrupts
  	 */
  	inb_command(dev->base_addr);
  	adapter_reset(dev);
  
  	/*
  	 * no receive PCBs active
  	 */
  	adapter->rx_active = 0;
  
  	adapter->busy = 0;
  	adapter->send_pcb_semaphore = 0;
  	adapter->rx_backlog.in = 0;
  	adapter->rx_backlog.out = 0;
6aa20a223   Jeff Garzik   drivers/net: Trim...
911

1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
912
913
914
915
916
  	spin_lock_init(&adapter->lock);
  
  	/*
  	 * install our interrupt service routine
  	 */
a0607fd3a   Joe Perches   drivers/net: requ...
917
  	if ((retval = request_irq(dev->irq, elp_interrupt, 0, dev->name, dev))) {
646cdb328   Alexander Beregalov   3c50x: convert pr...
918
919
  		pr_err("%s: could not allocate IRQ%d
  ", dev->name, dev->irq);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
920
921
922
923
  		return retval;
  	}
  	if ((retval = request_dma(dev->dma, dev->name))) {
  		free_irq(dev->irq, dev);
646cdb328   Alexander Beregalov   3c50x: convert pr...
924
925
  		pr_err("%s: could not allocate DMA%d channel
  ", dev->name, dev->dma);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
926
927
928
929
  		return retval;
  	}
  	adapter->dma_buffer = (void *) dma_mem_alloc(DMA_BUFFER_SIZE);
  	if (!adapter->dma_buffer) {
646cdb328   Alexander Beregalov   3c50x: convert pr...
930
931
  		pr_err("%s: could not allocate DMA buffer
  ", dev->name);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
932
933
934
935
936
937
938
939
940
941
942
943
944
945
946
  		free_dma(dev->dma);
  		free_irq(dev->irq, dev);
  		return -ENOMEM;
  	}
  	adapter->dmaing = 0;
  
  	/*
  	 * enable interrupts on the board
  	 */
  	outb_control(CMDE, dev);
  
  	/*
  	 * configure adapter memory: we need 10 multicast addresses, default==0
  	 */
  	if (elp_debug >= 3)
646cdb328   Alexander Beregalov   3c50x: convert pr...
947
948
  		pr_debug("%s: sending 3c505 memory configuration command
  ", dev->name);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
949
950
951
952
953
954
955
956
957
958
  	adapter->tx_pcb.command = CMD_CONFIGURE_ADAPTER_MEMORY;
  	adapter->tx_pcb.data.memconf.cmd_q = 10;
  	adapter->tx_pcb.data.memconf.rcv_q = 20;
  	adapter->tx_pcb.data.memconf.mcast = 10;
  	adapter->tx_pcb.data.memconf.frame = 20;
  	adapter->tx_pcb.data.memconf.rcv_b = 20;
  	adapter->tx_pcb.data.memconf.progs = 0;
  	adapter->tx_pcb.length = sizeof(struct Memconf);
  	adapter->got[CMD_CONFIGURE_ADAPTER_MEMORY] = 0;
  	if (!send_pcb(dev, &adapter->tx_pcb))
646cdb328   Alexander Beregalov   3c50x: convert pr...
959
960
  		pr_err("%s: couldn't send memory configuration command
  ", dev->name);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
961
962
963
964
965
966
967
968
969
970
971
972
  	else {
  		unsigned long timeout = jiffies + TIMEOUT;
  		while (adapter->got[CMD_CONFIGURE_ADAPTER_MEMORY] == 0 && time_before(jiffies, timeout));
  		if (time_after_eq(jiffies, timeout))
  			TIMEOUT_MSG(__LINE__);
  	}
  
  
  	/*
  	 * configure adapter to receive broadcast messages and wait for response
  	 */
  	if (elp_debug >= 3)
646cdb328   Alexander Beregalov   3c50x: convert pr...
973
974
  		pr_debug("%s: sending 82586 configure command
  ", dev->name);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
975
976
977
978
979
  	adapter->tx_pcb.command = CMD_CONFIGURE_82586;
  	adapter->tx_pcb.data.configure = NO_LOOPBACK | RECV_BROAD;
  	adapter->tx_pcb.length = 2;
  	adapter->got[CMD_CONFIGURE_82586] = 0;
  	if (!send_pcb(dev, &adapter->tx_pcb))
646cdb328   Alexander Beregalov   3c50x: convert pr...
980
981
  		pr_err("%s: couldn't send 82586 configure command
  ", dev->name);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
982
983
984
985
986
987
988
989
990
991
992
993
994
995
996
  	else {
  		unsigned long timeout = jiffies + TIMEOUT;
  		while (adapter->got[CMD_CONFIGURE_82586] == 0 && time_before(jiffies, timeout));
  		if (time_after_eq(jiffies, timeout))
  			TIMEOUT_MSG(__LINE__);
  	}
  
  	/* enable burst-mode DMA */
  	/* outb(0x1, dev->base_addr + PORT_AUXDMA); */
  
  	/*
  	 * queue receive commands to provide buffering
  	 */
  	prime_rx(dev);
  	if (elp_debug >= 3)
646cdb328   Alexander Beregalov   3c50x: convert pr...
997
998
  		pr_debug("%s: %d receive PCBs active
  ", dev->name, adapter->rx_active);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
999
1000
1001
1002
1003
1004
1005
1006
1007
1008
1009
1010
1011
1012
1013
  
  	/*
  	 * device is now officially open!
  	 */
  
  	netif_start_queue(dev);
  	return 0;
  }
  
  
  /******************************************************
   *
   * send a packet to the adapter
   *
   ******************************************************/
27a1de95a   Stephen Hemminger   3com: convert dri...
1014
  static netdev_tx_t send_packet(struct net_device *dev, struct sk_buff *skb)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1015
  {
454d7c9b1   Wang Chen   netdevice: safe c...
1016
  	elp_device *adapter = netdev_priv(dev);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1017
1018
1019
1020
1021
1022
1023
1024
1025
1026
  	unsigned long target;
  	unsigned long flags;
  
  	/*
  	 * make sure the length is even and no shorter than 60 bytes
  	 */
  	unsigned int nlen = (((skb->len < 60) ? 60 : skb->len) + 1) & (~1);
  
  	if (test_and_set_bit(0, (void *) &adapter->busy)) {
  		if (elp_debug >= 2)
646cdb328   Alexander Beregalov   3c50x: convert pr...
1027
1028
  			pr_debug("%s: transmit blocked
  ", dev->name);
df570f933   Richard Knutsson   drivers/net/3c505...
1029
  		return false;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1030
  	}
ba0f6caeb   Paulius Zaleckas   3c505: use netsta...
1031
  	dev->stats.tx_bytes += nlen;
6aa20a223   Jeff Garzik   drivers/net: Trim...
1032

1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1033
1034
1035
1036
1037
1038
1039
1040
1041
1042
1043
1044
  	/*
  	 * send the adapter a transmit packet command. Ignore segment and offset
  	 * and make sure the length is even
  	 */
  	adapter->tx_pcb.command = CMD_TRANSMIT_PACKET;
  	adapter->tx_pcb.length = sizeof(struct Xmit_pkt);
  	adapter->tx_pcb.data.xmit_pkt.buf_ofs
  	    = adapter->tx_pcb.data.xmit_pkt.buf_seg = 0;	/* Unused */
  	adapter->tx_pcb.data.xmit_pkt.pkt_len = nlen;
  
  	if (!send_pcb(dev, &adapter->tx_pcb)) {
  		adapter->busy = 0;
df570f933   Richard Knutsson   drivers/net/3c505...
1045
  		return false;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1046
1047
1048
  	}
  	/* if this happens, we die */
  	if (test_and_set_bit(0, (void *) &adapter->dmaing))
646cdb328   Alexander Beregalov   3c50x: convert pr...
1049
1050
  		pr_debug("%s: tx: DMA %d in progress
  ", dev->name, adapter->current_dma.direction);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1051
1052
1053
1054
1055
  
  	adapter->current_dma.direction = 1;
  	adapter->current_dma.start_time = jiffies;
  
  	if ((unsigned long)(skb->data + nlen) >= MAX_DMA_ADDRESS || nlen != skb->len) {
d626f62b1   Arnaldo Carvalho de Melo   [SK_BUFF]: Introd...
1056
  		skb_copy_from_linear_data(skb, adapter->dma_buffer, nlen);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1057
1058
1059
1060
1061
1062
1063
1064
1065
1066
1067
1068
1069
1070
1071
1072
1073
  		memset(adapter->dma_buffer+skb->len, 0, nlen-skb->len);
  		target = isa_virt_to_bus(adapter->dma_buffer);
  	}
  	else {
  		target = isa_virt_to_bus(skb->data);
  	}
  	adapter->current_dma.skb = skb;
  
  	flags=claim_dma_lock();
  	disable_dma(dev->dma);
  	clear_dma_ff(dev->dma);
  	set_dma_mode(dev->dma, 0x48);	/* dma memory -> io */
  	set_dma_addr(dev->dma, target);
  	set_dma_count(dev->dma, nlen);
  	outb_control(adapter->hcr_val | DMAE | TCEN, dev);
  	enable_dma(dev->dma);
  	release_dma_lock(flags);
6aa20a223   Jeff Garzik   drivers/net: Trim...
1074

1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1075
  	if (elp_debug >= 3)
646cdb328   Alexander Beregalov   3c50x: convert pr...
1076
1077
  		pr_debug("%s: DMA transfer started
  ", dev->name);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1078

df570f933   Richard Knutsson   drivers/net/3c505...
1079
  	return true;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1080
1081
1082
1083
1084
  }
  
  /*
   *	The upper layer thinks we timed out
   */
6aa20a223   Jeff Garzik   drivers/net: Trim...
1085

1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1086
1087
  static void elp_timeout(struct net_device *dev)
  {
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1088
1089
1090
  	int stat;
  
  	stat = inb_status(dev->base_addr);
646cdb328   Alexander Beregalov   3c50x: convert pr...
1091
1092
1093
  	pr_warning("%s: transmit timed out, lost %s?
  ", dev->name,
  		   (stat & ACRF) ? "interrupt" : "command");
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1094
  	if (elp_debug >= 1)
646cdb328   Alexander Beregalov   3c50x: convert pr...
1095
1096
  		pr_debug("%s: status %#02x
  ", dev->name, stat);
1ae5dc342   Eric Dumazet   net: trans_start ...
1097
  	dev->trans_start = jiffies; /* prevent tx timeout */
ba0f6caeb   Paulius Zaleckas   3c505: use netsta...
1098
  	dev->stats.tx_dropped++;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1099
1100
1101
1102
1103
1104
1105
1106
1107
  	netif_wake_queue(dev);
  }
  
  /******************************************************
   *
   * start the transmitter
   *    return 0 if sent OK, else return 1
   *
   ******************************************************/
27a1de95a   Stephen Hemminger   3com: convert dri...
1108
  static netdev_tx_t elp_start_xmit(struct sk_buff *skb, struct net_device *dev)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1109
1110
  {
  	unsigned long flags;
454d7c9b1   Wang Chen   netdevice: safe c...
1111
  	elp_device *adapter = netdev_priv(dev);
6aa20a223   Jeff Garzik   drivers/net: Trim...
1112

1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1113
1114
1115
1116
  	spin_lock_irqsave(&adapter->lock, flags);
  	check_3c505_dma(dev);
  
  	if (elp_debug >= 3)
646cdb328   Alexander Beregalov   3c50x: convert pr...
1117
1118
  		pr_debug("%s: request to send packet of length %d
  ", dev->name, (int) skb->len);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1119
1120
  
  	netif_stop_queue(dev);
6aa20a223   Jeff Garzik   drivers/net: Trim...
1121

1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1122
1123
1124
1125
1126
  	/*
  	 * send the packet at skb->data for skb->len
  	 */
  	if (!send_packet(dev, skb)) {
  		if (elp_debug >= 2) {
646cdb328   Alexander Beregalov   3c50x: convert pr...
1127
1128
  			pr_debug("%s: failed to transmit packet
  ", dev->name);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1129
1130
  		}
  		spin_unlock_irqrestore(&adapter->lock, flags);
5b5481402   Patrick McHardy   net: use symbolic...
1131
  		return NETDEV_TX_BUSY;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1132
1133
  	}
  	if (elp_debug >= 3)
646cdb328   Alexander Beregalov   3c50x: convert pr...
1134
1135
  		pr_debug("%s: packet of length %d sent
  ", dev->name, (int) skb->len);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1136

1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1137
1138
1139
  	prime_rx(dev);
  	spin_unlock_irqrestore(&adapter->lock, flags);
  	netif_start_queue(dev);
6ed106549   Patrick McHardy   net: use NETDEV_T...
1140
  	return NETDEV_TX_OK;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1141
1142
1143
1144
1145
1146
1147
1148
1149
1150
  }
  
  /******************************************************
   *
   * return statistics on the board
   *
   ******************************************************/
  
  static struct net_device_stats *elp_get_stats(struct net_device *dev)
  {
454d7c9b1   Wang Chen   netdevice: safe c...
1151
  	elp_device *adapter = netdev_priv(dev);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1152
1153
  
  	if (elp_debug >= 3)
646cdb328   Alexander Beregalov   3c50x: convert pr...
1154
1155
  		pr_debug("%s: request for stats
  ", dev->name);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1156
1157
1158
1159
  
  	/* If the device is closed, just return the latest stats we have,
  	   - we cannot ask from the adapter without interrupts */
  	if (!netif_running(dev))
ba0f6caeb   Paulius Zaleckas   3c505: use netsta...
1160
  		return &dev->stats;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1161
1162
1163
1164
1165
1166
  
  	/* send a get statistics command to the board */
  	adapter->tx_pcb.command = CMD_NETWORK_STATISTICS;
  	adapter->tx_pcb.length = 0;
  	adapter->got[CMD_NETWORK_STATISTICS] = 0;
  	if (!send_pcb(dev, &adapter->tx_pcb))
646cdb328   Alexander Beregalov   3c50x: convert pr...
1167
1168
  		pr_err("%s: couldn't send get statistics command
  ", dev->name);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1169
1170
1171
1172
1173
  	else {
  		unsigned long timeout = jiffies + TIMEOUT;
  		while (adapter->got[CMD_NETWORK_STATISTICS] == 0 && time_before(jiffies, timeout));
  		if (time_after_eq(jiffies, timeout)) {
  			TIMEOUT_MSG(__LINE__);
ba0f6caeb   Paulius Zaleckas   3c505: use netsta...
1174
  			return &dev->stats;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1175
1176
1177
1178
  		}
  	}
  
  	/* statistics are now up to date */
ba0f6caeb   Paulius Zaleckas   3c505: use netsta...
1179
  	return &dev->stats;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1180
1181
1182
1183
1184
1185
1186
1187
1188
1189
1190
1191
1192
1193
1194
1195
1196
1197
1198
1199
  }
  
  
  static void netdev_get_drvinfo(struct net_device *dev,
  			       struct ethtool_drvinfo *info)
  {
  	strcpy(info->driver, DRV_NAME);
  	strcpy(info->version, DRV_VERSION);
  	sprintf(info->bus_info, "ISA 0x%lx", dev->base_addr);
  }
  
  static u32 netdev_get_msglevel(struct net_device *dev)
  {
  	return debug;
  }
  
  static void netdev_set_msglevel(struct net_device *dev, u32 level)
  {
  	debug = level;
  }
7282d491e   Jeff Garzik   drivers/net: cons...
1200
  static const struct ethtool_ops netdev_ethtool_ops = {
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1201
1202
1203
1204
1205
1206
1207
1208
1209
1210
1211
1212
1213
  	.get_drvinfo		= netdev_get_drvinfo,
  	.get_msglevel		= netdev_get_msglevel,
  	.set_msglevel		= netdev_set_msglevel,
  };
  
  /******************************************************
   *
   * close the board
   *
   ******************************************************/
  
  static int elp_close(struct net_device *dev)
  {
454d7c9b1   Wang Chen   netdevice: safe c...
1214
  	elp_device *adapter = netdev_priv(dev);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1215
1216
  
  	if (elp_debug >= 3)
646cdb328   Alexander Beregalov   3c50x: convert pr...
1217
1218
  		pr_debug("%s: request to close device
  ", dev->name);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1219
1220
1221
1222
1223
1224
1225
1226
1227
1228
1229
1230
1231
1232
1233
1234
1235
1236
1237
1238
1239
1240
1241
1242
1243
1244
1245
1246
1247
1248
1249
1250
1251
1252
1253
1254
1255
  
  	netif_stop_queue(dev);
  
  	/* Someone may request the device statistic information even when
  	 * the interface is closed. The following will update the statistics
  	 * structure in the driver, so we'll be able to give current statistics.
  	 */
  	(void) elp_get_stats(dev);
  
  	/*
  	 * disable interrupts on the board
  	 */
  	outb_control(0, dev);
  
  	/*
  	 * release the IRQ
  	 */
  	free_irq(dev->irq, dev);
  
  	free_dma(dev->dma);
  	free_pages((unsigned long) adapter->dma_buffer, get_order(DMA_BUFFER_SIZE));
  
  	return 0;
  }
  
  
  /************************************************************
   *
   * Set multicast list
   * num_addrs==0: clear mc_list
   * num_addrs==-1: set promiscuous mode
   * num_addrs>0: set mc_list
   *
   ************************************************************/
  
  static void elp_set_mc_list(struct net_device *dev)
  {
454d7c9b1   Wang Chen   netdevice: safe c...
1256
  	elp_device *adapter = netdev_priv(dev);
22bedad3c   Jiri Pirko   net: convert mult...
1257
  	struct netdev_hw_addr *ha;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1258
1259
1260
1261
  	int i;
  	unsigned long flags;
  
  	if (elp_debug >= 3)
646cdb328   Alexander Beregalov   3c50x: convert pr...
1262
1263
  		pr_debug("%s: request to set multicast list
  ", dev->name);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1264
1265
  
  	spin_lock_irqsave(&adapter->lock, flags);
6aa20a223   Jeff Garzik   drivers/net: Trim...
1266

1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1267
1268
1269
1270
  	if (!(dev->flags & (IFF_PROMISC | IFF_ALLMULTI))) {
  		/* send a "load multicast list" command to the board, max 10 addrs/cmd */
  		/* if num_addrs==0 the list will be cleared */
  		adapter->tx_pcb.command = CMD_LOAD_MULTICAST_LIST;
4cd24eaf0   Jiri Pirko   net: use netdev_m...
1271
  		adapter->tx_pcb.length = 6 * netdev_mc_count(dev);
59ce25d9e   Jiri Pirko   3c5xx: use netdev...
1272
  		i = 0;
22bedad3c   Jiri Pirko   net: convert mult...
1273
1274
1275
  		netdev_for_each_mc_addr(ha, dev)
  			memcpy(adapter->tx_pcb.data.multicast[i++],
  			       ha->addr, 6);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1276
1277
  		adapter->got[CMD_LOAD_MULTICAST_LIST] = 0;
  		if (!send_pcb(dev, &adapter->tx_pcb))
646cdb328   Alexander Beregalov   3c50x: convert pr...
1278
1279
  			pr_err("%s: couldn't send set_multicast command
  ", dev->name);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1280
1281
1282
1283
1284
1285
1286
  		else {
  			unsigned long timeout = jiffies + TIMEOUT;
  			while (adapter->got[CMD_LOAD_MULTICAST_LIST] == 0 && time_before(jiffies, timeout));
  			if (time_after_eq(jiffies, timeout)) {
  				TIMEOUT_MSG(__LINE__);
  			}
  		}
4cd24eaf0   Jiri Pirko   net: use netdev_m...
1287
  		if (!netdev_mc_empty(dev))
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1288
1289
1290
1291
1292
1293
1294
1295
1296
1297
  			adapter->tx_pcb.data.configure = NO_LOOPBACK | RECV_BROAD | RECV_MULTI;
  		else		/* num_addrs == 0 */
  			adapter->tx_pcb.data.configure = NO_LOOPBACK | RECV_BROAD;
  	} else
  		adapter->tx_pcb.data.configure = NO_LOOPBACK | RECV_PROMISC;
  	/*
  	 * configure adapter to receive messages (as specified above)
  	 * and wait for response
  	 */
  	if (elp_debug >= 3)
646cdb328   Alexander Beregalov   3c50x: convert pr...
1298
1299
  		pr_debug("%s: sending 82586 configure command
  ", dev->name);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1300
1301
1302
1303
1304
1305
  	adapter->tx_pcb.command = CMD_CONFIGURE_82586;
  	adapter->tx_pcb.length = 2;
  	adapter->got[CMD_CONFIGURE_82586] = 0;
  	if (!send_pcb(dev, &adapter->tx_pcb))
  	{
  		spin_unlock_irqrestore(&adapter->lock, flags);
646cdb328   Alexander Beregalov   3c50x: convert pr...
1306
1307
  		pr_err("%s: couldn't send 82586 configure command
  ", dev->name);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1308
1309
1310
1311
1312
1313
1314
1315
1316
1317
1318
1319
1320
1321
1322
1323
1324
1325
1326
1327
1328
1329
1330
1331
1332
1333
1334
1335
  	}
  	else {
  		unsigned long timeout = jiffies + TIMEOUT;
  		spin_unlock_irqrestore(&adapter->lock, flags);
  		while (adapter->got[CMD_CONFIGURE_82586] == 0 && time_before(jiffies, timeout));
  		if (time_after_eq(jiffies, timeout))
  			TIMEOUT_MSG(__LINE__);
  	}
  }
  
  /************************************************************
   *
   * A couple of tests to see if there's 3C505 or not
   * Called only by elp_autodetect
   ************************************************************/
  
  static int __init elp_sense(struct net_device *dev)
  {
  	int addr = dev->base_addr;
  	const char *name = dev->name;
  	byte orig_HSR;
  
  	if (!request_region(addr, ELP_IO_EXTENT, "3c505"))
  		return -ENODEV;
  
  	orig_HSR = inb_status(addr);
  
  	if (elp_debug > 0)
646cdb328   Alexander Beregalov   3c50x: convert pr...
1336
  		pr_debug(search_msg, name, addr);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1337
1338
1339
  
  	if (orig_HSR == 0xff) {
  		if (elp_debug > 0)
646cdb328   Alexander Beregalov   3c50x: convert pr...
1340
  			pr_cont(notfound_msg, 1);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1341
1342
1343
1344
1345
  		goto out;
  	}
  
  	/* Wait for a while; the adapter may still be booting up */
  	if (elp_debug > 0)
646cdb328   Alexander Beregalov   3c50x: convert pr...
1346
  		pr_cont(stilllooking_msg);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1347
1348
1349
1350
  
  	if (orig_HSR & DIR) {
  		/* If HCR.DIR is up, we pull it down. HSR.DIR should follow. */
  		outb(0, dev->base_addr + PORT_CONTROL);
c56943e65   Domen Puncer   [PATCH] net/3c505...
1351
  		msleep(300);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1352
1353
  		if (inb_status(addr) & DIR) {
  			if (elp_debug > 0)
646cdb328   Alexander Beregalov   3c50x: convert pr...
1354
  				pr_cont(notfound_msg, 2);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1355
1356
1357
1358
1359
  			goto out;
  		}
  	} else {
  		/* If HCR.DIR is down, we pull it up. HSR.DIR should follow. */
  		outb(DIR, dev->base_addr + PORT_CONTROL);
c56943e65   Domen Puncer   [PATCH] net/3c505...
1360
  		msleep(300);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1361
1362
  		if (!(inb_status(addr) & DIR)) {
  			if (elp_debug > 0)
646cdb328   Alexander Beregalov   3c50x: convert pr...
1363
  				pr_cont(notfound_msg, 3);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1364
1365
1366
1367
1368
1369
1370
  			goto out;
  		}
  	}
  	/*
  	 * It certainly looks like a 3c505.
  	 */
  	if (elp_debug > 0)
646cdb328   Alexander Beregalov   3c50x: convert pr...
1371
  		pr_cont(found_msg);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1372
1373
1374
1375
1376
1377
1378
1379
1380
1381
1382
1383
1384
1385
1386
1387
1388
1389
1390
1391
1392
1393
1394
1395
1396
1397
1398
1399
1400
1401
  
  	return 0;
  out:
  	release_region(addr, ELP_IO_EXTENT);
  	return -ENODEV;
  }
  
  /*************************************************************
   *
   * Search through addr_list[] and try to find a 3C505
   * Called only by eplus_probe
   *************************************************************/
  
  static int __init elp_autodetect(struct net_device *dev)
  {
  	int idx = 0;
  
  	/* if base address set, then only check that address
  	   otherwise, run through the table */
  	if (dev->base_addr != 0) {	/* dev->base_addr == 0 ==> plain autodetect */
  		if (elp_sense(dev) == 0)
  			return dev->base_addr;
  	} else
  		while ((dev->base_addr = addr_list[idx++])) {
  			if (elp_sense(dev) == 0)
  				return dev->base_addr;
  		}
  
  	/* could not find an adapter */
  	if (elp_debug > 0)
646cdb328   Alexander Beregalov   3c50x: convert pr...
1402
  		pr_debug(couldnot_msg, dev->name);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1403
1404
1405
  
  	return 0;		/* Because of this, the layer above will return -ENODEV */
  }
e6c42b782   Stephen Hemminger   3c505: convert to...
1406
1407
1408
1409
1410
1411
1412
1413
1414
1415
1416
  static const struct net_device_ops elp_netdev_ops = {
  	.ndo_open		= elp_open,
  	.ndo_stop		= elp_close,
  	.ndo_get_stats 		= elp_get_stats,
  	.ndo_start_xmit		= elp_start_xmit,
  	.ndo_tx_timeout 	= elp_timeout,
  	.ndo_set_multicast_list = elp_set_mc_list,
  	.ndo_change_mtu		= eth_change_mtu,
  	.ndo_set_mac_address 	= eth_mac_addr,
  	.ndo_validate_addr	= eth_validate_addr,
  };
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1417
1418
1419
1420
1421
1422
1423
1424
1425
1426
1427
1428
1429
1430
1431
1432
1433
1434
1435
1436
1437
1438
1439
1440
  
  /******************************************************
   *
   * probe for an Etherlink Plus board at the specified address
   *
   ******************************************************/
  
  /* There are three situations we need to be able to detect here:
  
   *  a) the card is idle
   *  b) the card is still booting up
   *  c) the card is stuck in a strange state (some DOS drivers do this)
   *
   * In case (a), all is well.  In case (b), we wait 10 seconds to see if the
   * card finishes booting, and carry on if so.  In case (c), we do a hard reset,
   * loop round, and hope for the best.
   *
   * This is all very unpleasant, but hopefully avoids the problems with the old
   * probe code (which had a 15-second delay if the card was idle, and didn't
   * work at all if it was in a weird state).
   */
  
  static int __init elplus_setup(struct net_device *dev)
  {
454d7c9b1   Wang Chen   netdevice: safe c...
1441
  	elp_device *adapter = netdev_priv(dev);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1442
1443
1444
1445
  	int i, tries, tries1, okay;
  	unsigned long timeout;
  	unsigned long cookie = 0;
  	int err = -ENODEV;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1446
1447
1448
1449
1450
1451
1452
1453
1454
1455
1456
1457
1458
1459
1460
1461
1462
1463
1464
1465
1466
1467
1468
1469
1470
1471
1472
1473
1474
  	/*
  	 *  setup adapter structure
  	 */
  
  	dev->base_addr = elp_autodetect(dev);
  	if (!dev->base_addr)
  		return -ENODEV;
  
  	adapter->send_pcb_semaphore = 0;
  
  	for (tries1 = 0; tries1 < 3; tries1++) {
  		outb_control((adapter->hcr_val | CMDE) & ~DIR, dev);
  		/* First try to write just one byte, to see if the card is
  		 * responding at all normally.
  		 */
  		timeout = jiffies + 5*HZ/100;
  		okay = 0;
  		while (time_before(jiffies, timeout) && !(inb_status(dev->base_addr) & HCRE));
  		if ((inb_status(dev->base_addr) & HCRE)) {
  			outb_command(0, dev->base_addr);	/* send a spurious byte */
  			timeout = jiffies + 5*HZ/100;
  			while (time_before(jiffies, timeout) && !(inb_status(dev->base_addr) & HCRE));
  			if (inb_status(dev->base_addr) & HCRE)
  				okay = 1;
  		}
  		if (!okay) {
  			/* Nope, it's ignoring the command register.  This means that
  			 * either it's still booting up, or it's died.
  			 */
646cdb328   Alexander Beregalov   3c50x: convert pr...
1475
  			pr_err("%s: command register wouldn't drain, ", dev->name);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1476
1477
1478
1479
  			if ((inb_status(dev->base_addr) & 7) == 3) {
  				/* If the adapter status is 3, it *could* still be booting.
  				 * Give it the benefit of the doubt for 10 seconds.
  				 */
646cdb328   Alexander Beregalov   3c50x: convert pr...
1480
1481
  				pr_cont("assuming 3c505 still starting
  ");
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1482
1483
1484
  				timeout = jiffies + 10*HZ;
  				while (time_before(jiffies, timeout) && (inb_status(dev->base_addr) & 7));
  				if (inb_status(dev->base_addr) & 7) {
646cdb328   Alexander Beregalov   3c50x: convert pr...
1485
1486
  					pr_err("%s: 3c505 failed to start
  ", dev->name);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1487
1488
1489
1490
1491
1492
1493
  				} else {
  					okay = 1;  /* It started */
  				}
  			} else {
  				/* Otherwise, it must just be in a strange
  				 * state.  We probably need to kick it.
  				 */
646cdb328   Alexander Beregalov   3c50x: convert pr...
1494
1495
  				pr_cont("3c505 is sulking
  ");
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1496
1497
1498
1499
1500
1501
1502
1503
1504
1505
1506
1507
  			}
  		}
  		for (tries = 0; tries < 5 && okay; tries++) {
  
  			/*
  			 * Try to set the Ethernet address, to make sure that the board
  			 * is working.
  			 */
  			adapter->tx_pcb.command = CMD_STATION_ADDRESS;
  			adapter->tx_pcb.length = 0;
  			cookie = probe_irq_on();
  			if (!send_pcb(dev, &adapter->tx_pcb)) {
646cdb328   Alexander Beregalov   3c50x: convert pr...
1508
1509
  				pr_err("%s: could not send first PCB
  ", dev->name);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1510
1511
1512
1513
  				probe_irq_off(cookie);
  				continue;
  			}
  			if (!receive_pcb(dev, &adapter->rx_pcb)) {
646cdb328   Alexander Beregalov   3c50x: convert pr...
1514
1515
  				pr_err("%s: could not read first PCB
  ", dev->name);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1516
1517
1518
1519
1520
  				probe_irq_off(cookie);
  				continue;
  			}
  			if ((adapter->rx_pcb.command != CMD_ADDRESS_RESPONSE) ||
  			    (adapter->rx_pcb.length != 6)) {
646cdb328   Alexander Beregalov   3c50x: convert pr...
1521
1522
1523
  				pr_err("%s: first PCB wrong (%d, %d)
  ", dev->name,
  					adapter->rx_pcb.command, adapter->rx_pcb.length);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1524
1525
1526
1527
1528
1529
1530
1531
  				probe_irq_off(cookie);
  				continue;
  			}
  			goto okay;
  		}
  		/* It's broken.  Do a hard reset to re-initialise the board,
  		 * and try again.
  		 */
646cdb328   Alexander Beregalov   3c50x: convert pr...
1532
1533
  		pr_info("%s: resetting adapter
  ", dev->name);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1534
1535
1536
  		outb_control(adapter->hcr_val | FLSH | ATTN, dev);
  		outb_control(adapter->hcr_val & ~(FLSH | ATTN), dev);
  	}
646cdb328   Alexander Beregalov   3c50x: convert pr...
1537
1538
  	pr_err("%s: failed to initialise 3c505
  ", dev->name);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1539
1540
1541
1542
1543
1544
  	goto out;
  
        okay:
  	if (dev->irq) {		/* Is there a preset IRQ? */
  		int rpt = probe_irq_off(cookie);
  		if (dev->irq != rpt) {
646cdb328   Alexander Beregalov   3c50x: convert pr...
1545
1546
  			pr_warning("%s: warning, irq %d configured but %d detected
  ", dev->name, dev->irq, rpt);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1547
1548
1549
1550
1551
1552
  		}
  		/* if dev->irq == probe_irq_off(cookie), all is well */
  	} else		       /* No preset IRQ; just use what we can detect */
  		dev->irq = probe_irq_off(cookie);
  	switch (dev->irq) {    /* Legal, sane? */
  	case 0:
646cdb328   Alexander Beregalov   3c50x: convert pr...
1553
1554
  		pr_err("%s: IRQ probe failed: check 3c505 jumpers.
  ",
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1555
1556
1557
1558
1559
1560
  		       dev->name);
  		goto out;
  	case 1:
  	case 6:
  	case 8:
  	case 13:
646cdb328   Alexander Beregalov   3c50x: convert pr...
1561
1562
  		pr_err("%s: Impossible IRQ %d reported by probe_irq_off().
  ",
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1563
1564
1565
1566
1567
1568
1569
1570
1571
1572
1573
1574
1575
1576
1577
1578
1579
1580
1581
1582
1583
  		       dev->name, dev->irq);
  		       goto out;
  	}
  	/*
  	 *  Now we have the IRQ number so we can disable the interrupts from
  	 *  the board until the board is opened.
  	 */
  	outb_control(adapter->hcr_val & ~CMDE, dev);
  
  	/*
  	 * copy Ethernet address into structure
  	 */
  	for (i = 0; i < 6; i++)
  		dev->dev_addr[i] = adapter->rx_pcb.data.eth_addr[i];
  
  	/* find a DMA channel */
  	if (!dev->dma) {
  		if (dev->mem_start) {
  			dev->dma = dev->mem_start & 7;
  		}
  		else {
646cdb328   Alexander Beregalov   3c50x: convert pr...
1584
1585
  			pr_warning("%s: warning, DMA channel not specified, using default
  ", dev->name);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1586
1587
1588
1589
1590
1591
1592
  			dev->dma = ELP_DMA;
  		}
  	}
  
  	/*
  	 * print remainder of startup message
  	 */
646cdb328   Alexander Beregalov   3c50x: convert pr...
1593
1594
  	pr_info("%s: 3c505 at %#lx, irq %d, dma %d, addr %pM, ",
  		dev->name, dev->base_addr, dev->irq, dev->dma, dev->dev_addr);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1595
1596
1597
1598
1599
1600
1601
1602
1603
1604
  	/*
  	 * read more information from the adapter
  	 */
  
  	adapter->tx_pcb.command = CMD_ADAPTER_INFO;
  	adapter->tx_pcb.length = 0;
  	if (!send_pcb(dev, &adapter->tx_pcb) ||
  	    !receive_pcb(dev, &adapter->rx_pcb) ||
  	    (adapter->rx_pcb.command != CMD_ADAPTER_INFO_RESPONSE) ||
  	    (adapter->rx_pcb.length != 10)) {
646cdb328   Alexander Beregalov   3c50x: convert pr...
1605
1606
  		pr_cont("not responding to second PCB
  ");
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1607
  	}
646cdb328   Alexander Beregalov   3c50x: convert pr...
1608
1609
1610
  	pr_cont("rev %d.%d, %dk
  ", adapter->rx_pcb.data.info.major_vers,
  		adapter->rx_pcb.data.info.minor_vers, adapter->rx_pcb.data.info.RAM_sz);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1611
1612
1613
1614
1615
1616
1617
1618
1619
1620
1621
1622
1623
1624
1625
1626
  
  	/*
  	 * reconfigure the adapter memory to better suit our purposes
  	 */
  	adapter->tx_pcb.command = CMD_CONFIGURE_ADAPTER_MEMORY;
  	adapter->tx_pcb.length = 12;
  	adapter->tx_pcb.data.memconf.cmd_q = 8;
  	adapter->tx_pcb.data.memconf.rcv_q = 8;
  	adapter->tx_pcb.data.memconf.mcast = 10;
  	adapter->tx_pcb.data.memconf.frame = 10;
  	adapter->tx_pcb.data.memconf.rcv_b = 10;
  	adapter->tx_pcb.data.memconf.progs = 0;
  	if (!send_pcb(dev, &adapter->tx_pcb) ||
  	    !receive_pcb(dev, &adapter->rx_pcb) ||
  	    (adapter->rx_pcb.command != CMD_CONFIGURE_ADAPTER_RESPONSE) ||
  	    (adapter->rx_pcb.length != 2)) {
646cdb328   Alexander Beregalov   3c50x: convert pr...
1627
1628
  		pr_err("%s: could not configure adapter memory
  ", dev->name);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1629
1630
  	}
  	if (adapter->rx_pcb.data.configure) {
646cdb328   Alexander Beregalov   3c50x: convert pr...
1631
1632
  		pr_err("%s: adapter configuration failed
  ", dev->name);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1633
  	}
e6c42b782   Stephen Hemminger   3c505: convert to...
1634
  	dev->netdev_ops = &elp_netdev_ops;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1635
  	dev->watchdog_timeo = 10*HZ;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1636
  	dev->ethtool_ops = &netdev_ethtool_ops;		/* local */
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1637
1638
1639
1640
1641
1642
1643
1644
1645
1646
1647
1648
1649
1650
1651
1652
1653
1654
1655
1656
1657
1658
1659
1660
1661
1662
1663
1664
1665
1666
1667
1668
1669
1670
1671
1672
1673
1674
1675
1676
1677
1678
  	dev->mem_start = dev->mem_end = 0;
  
  	err = register_netdev(dev);
  	if (err)
  		goto out;
  
  	return 0;
  out:
  	release_region(dev->base_addr, ELP_IO_EXTENT);
  	return err;
  }
  
  #ifndef MODULE
  struct net_device * __init elplus_probe(int unit)
  {
  	struct net_device *dev = alloc_etherdev(sizeof(elp_device));
  	int err;
  	if (!dev)
  		return ERR_PTR(-ENOMEM);
  
  	sprintf(dev->name, "eth%d", unit);
  	netdev_boot_setup_check(dev);
  
  	err = elplus_setup(dev);
  	if (err) {
  		free_netdev(dev);
  		return ERR_PTR(err);
  	}
  	return dev;
  }
  
  #else
  static struct net_device *dev_3c505[ELP_MAX_CARDS];
  static int io[ELP_MAX_CARDS];
  static int irq[ELP_MAX_CARDS];
  static int dma[ELP_MAX_CARDS];
  module_param_array(io, int, NULL, 0);
  module_param_array(irq, int, NULL, 0);
  module_param_array(dma, int, NULL, 0);
  MODULE_PARM_DESC(io, "EtherLink Plus I/O base address(es)");
  MODULE_PARM_DESC(irq, "EtherLink Plus IRQ number(s) (assigned)");
  MODULE_PARM_DESC(dma, "EtherLink Plus DMA channel(s)");
96e672c79   Randy Dunlap   [PATCH] 3c5zz eth...
1679
  int __init init_module(void)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1680
1681
1682
1683
1684
1685
1686
1687
1688
1689
1690
1691
1692
1693
  {
  	int this_dev, found = 0;
  
  	for (this_dev = 0; this_dev < ELP_MAX_CARDS; this_dev++) {
  		struct net_device *dev = alloc_etherdev(sizeof(elp_device));
  		if (!dev)
  			break;
  
  		dev->irq = irq[this_dev];
  		dev->base_addr = io[this_dev];
  		if (dma[this_dev]) {
  			dev->dma = dma[this_dev];
  		} else {
  			dev->dma = ELP_DMA;
646cdb328   Alexander Beregalov   3c50x: convert pr...
1694
1695
  			pr_warning("3c505.c: warning, using default DMA channel,
  ");
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1696
1697
1698
1699
1700
1701
  		}
  		if (io[this_dev] == 0) {
  			if (this_dev) {
  				free_netdev(dev);
  				break;
  			}
646cdb328   Alexander Beregalov   3c50x: convert pr...
1702
1703
  			pr_notice("3c505.c: module autoprobe not recommended, give io=xx.
  ");
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1704
1705
  		}
  		if (elplus_setup(dev) != 0) {
646cdb328   Alexander Beregalov   3c50x: convert pr...
1706
1707
  			pr_warning("3c505.c: Failed to register card at 0x%x.
  ", io[this_dev]);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1708
1709
1710
1711
1712
1713
1714
1715
1716
1717
  			free_netdev(dev);
  			break;
  		}
  		dev_3c505[this_dev] = dev;
  		found++;
  	}
  	if (!found)
  		return -ENODEV;
  	return 0;
  }
afc8eb46c   Al Viro   [PATCH] trivial m...
1718
  void __exit cleanup_module(void)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1719
1720
1721
1722
1723
1724
1725
1726
1727
1728
1729
1730
1731
1732
1733
  {
  	int this_dev;
  
  	for (this_dev = 0; this_dev < ELP_MAX_CARDS; this_dev++) {
  		struct net_device *dev = dev_3c505[this_dev];
  		if (dev) {
  			unregister_netdev(dev);
  			release_region(dev->base_addr, ELP_IO_EXTENT);
  			free_netdev(dev);
  		}
  	}
  }
  
  #endif				/* MODULE */
  MODULE_LICENSE("GPL");