blob: 48c64fb20eecf164b9022aae727e6dc86e8f5290 [file] [log] [blame]
Linus Torvalds1da177e2005-04-16 15:20:36 -07001/* seeq8005.c: A network driver for linux. */
2/*
3 Based on skeleton.c,
4 Written 1993-94 by Donald Becker.
5 See the skeleton.c file for further copyright information.
6
7 This software may be used and distributed according to the terms
8 of the GNU General Public License, incorporated herein by reference.
9
10 The author may be reached as hamish@zot.apana.org.au
11
12 This file is a network device driver for the SEEQ 8005 chipset and
13 the Linux operating system.
14
15*/
16
17static const char version[] =
18 "seeq8005.c:v1.00 8/07/95 Hamish Coleman (hamish@zot.apana.org.au)\n";
19
20/*
21 Sources:
22 SEEQ 8005 databook
Jeff Garzik6aa20a22006-09-13 13:24:59 -040023
Linus Torvalds1da177e2005-04-16 15:20:36 -070024 Version history:
25 1.00 Public release. cosmetic changes (no warnings now)
26 0.68 Turning per- packet,interrupt debug messages off - testing for release.
27 0.67 timing problems/bad buffer reads seem to be fixed now
28 0.63 *!@$ protocol=eth_type_trans -- now packets flow
29 0.56 Send working
30 0.48 Receive working
31*/
32
33#include <linux/module.h>
34#include <linux/kernel.h>
35#include <linux/types.h>
36#include <linux/fcntl.h>
37#include <linux/interrupt.h>
38#include <linux/ioport.h>
39#include <linux/in.h>
40#include <linux/slab.h>
41#include <linux/string.h>
42#include <linux/init.h>
43#include <linux/delay.h>
44#include <linux/errno.h>
45#include <linux/netdevice.h>
46#include <linux/etherdevice.h>
47#include <linux/skbuff.h>
48#include <linux/bitops.h>
Marcelo Feitoza Parisiff5688a2006-01-09 18:37:15 -080049#include <linux/jiffies.h>
Linus Torvalds1da177e2005-04-16 15:20:36 -070050
51#include <asm/system.h>
52#include <asm/io.h>
53#include <asm/dma.h>
54
55#include "seeq8005.h"
56
57/* First, a few definitions that the brave might change. */
58/* A zero-terminated list of I/O addresses to be probed. */
59static unsigned int seeq8005_portlist[] __initdata =
60 { 0x300, 0x320, 0x340, 0x360, 0};
61
62/* use 0 for production, 1 for verification, >2 for debug */
63#ifndef NET_DEBUG
64#define NET_DEBUG 1
65#endif
66static unsigned int net_debug = NET_DEBUG;
67
68/* Information that need to be kept for each board. */
69struct net_local {
Linus Torvalds1da177e2005-04-16 15:20:36 -070070 unsigned short receive_ptr; /* What address in packet memory do we expect a recv_pkt_header? */
71 long open_time; /* Useless example local info. */
72};
73
74/* The station (ethernet) address prefix, used for IDing the board. */
75#define SA_ADDR0 0x00
76#define SA_ADDR1 0x80
77#define SA_ADDR2 0x4b
78
79/* Index to functions, as function prototypes. */
80
81static int seeq8005_probe1(struct net_device *dev, int ioaddr);
82static int seeq8005_open(struct net_device *dev);
83static void seeq8005_timeout(struct net_device *dev);
84static int seeq8005_send_packet(struct sk_buff *skb, struct net_device *dev);
David Howells7d12e782006-10-05 14:55:46 +010085static irqreturn_t seeq8005_interrupt(int irq, void *dev_id);
Linus Torvalds1da177e2005-04-16 15:20:36 -070086static void seeq8005_rx(struct net_device *dev);
87static int seeq8005_close(struct net_device *dev);
Linus Torvalds1da177e2005-04-16 15:20:36 -070088static void set_multicast_list(struct net_device *dev);
89
90/* Example routines you must write ;->. */
91#define tx_done(dev) (inw(SEEQ_STATUS) & SEEQSTAT_TX_ON)
92static void hardware_send_packet(struct net_device *dev, char *buf, int length);
93extern void seeq8005_init(struct net_device *dev, int startp);
94static inline void wait_for_buffer(struct net_device *dev);
95
Jeff Garzik6aa20a22006-09-13 13:24:59 -040096
Linus Torvalds1da177e2005-04-16 15:20:36 -070097/* Check for a network adaptor of this type, and return '0' iff one exists.
98 If dev->base_addr == 0, probe all likely locations.
99 If dev->base_addr == 1, always return failure.
100 */
101
102static int io = 0x320;
103static int irq = 10;
104
105struct net_device * __init seeq8005_probe(int unit)
106{
107 struct net_device *dev = alloc_etherdev(sizeof(struct net_local));
108 unsigned *port;
109 int err = 0;
110
111 if (!dev)
112 return ERR_PTR(-ENODEV);
113
114 if (unit >= 0) {
115 sprintf(dev->name, "eth%d", unit);
116 netdev_boot_setup_check(dev);
117 io = dev->base_addr;
118 irq = dev->irq;
119 }
120
121 if (io > 0x1ff) { /* Check a single specified location. */
122 err = seeq8005_probe1(dev, io);
123 } else if (io != 0) { /* Don't probe at all. */
124 err = -ENXIO;
125 } else {
126 for (port = seeq8005_portlist; *port; port++) {
127 if (seeq8005_probe1(dev, *port) == 0)
128 break;
129 }
130 if (!*port)
131 err = -ENODEV;
132 }
133 if (err)
134 goto out;
135 err = register_netdev(dev);
136 if (err)
137 goto out1;
138 return dev;
139out1:
140 release_region(dev->base_addr, SEEQ8005_IO_EXTENT);
141out:
142 free_netdev(dev);
143 return ERR_PTR(err);
144}
145
146/* This is the real probe routine. Linux has a history of friendly device
147 probes on the ISA bus. A good device probes avoids doing writes, and
148 verifies that the correct device exists and functions. */
149
150static int __init seeq8005_probe1(struct net_device *dev, int ioaddr)
151{
152 static unsigned version_printed;
153 int i,j;
154 unsigned char SA_prom[32];
155 int old_cfg1;
156 int old_cfg2;
157 int old_stat;
158 int old_dmaar;
159 int old_rear;
160 int retval;
Joe Perches0795af52007-10-03 17:59:30 -0700161 DECLARE_MAC_BUF(mac);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700162
163 if (!request_region(ioaddr, SEEQ8005_IO_EXTENT, "seeq8005"))
164 return -ENODEV;
165
166 if (net_debug>1)
167 printk("seeq8005: probing at 0x%x\n",ioaddr);
168
169 old_stat = inw(SEEQ_STATUS); /* read status register */
170 if (old_stat == 0xffff) {
171 retval = -ENODEV;
172 goto out; /* assume that 0xffff == no device */
173 }
174 if ( (old_stat & 0x1800) != 0x1800 ) { /* assume that unused bits are 1, as my manual says */
175 if (net_debug>1) {
176 printk("seeq8005: reserved stat bits != 0x1800\n");
177 printk(" == 0x%04x\n",old_stat);
178 }
179 retval = -ENODEV;
180 goto out;
181 }
182
183 old_rear = inw(SEEQ_REA);
184 if (old_rear == 0xffff) {
185 outw(0,SEEQ_REA);
186 if (inw(SEEQ_REA) == 0xffff) { /* assume that 0xffff == no device */
187 retval = -ENODEV;
188 goto out;
189 }
190 } else if ((old_rear & 0xff00) != 0xff00) { /* assume that unused bits are 1 */
191 if (net_debug>1) {
192 printk("seeq8005: unused rear bits != 0xff00\n");
193 printk(" == 0x%04x\n",old_rear);
194 }
195 retval = -ENODEV;
196 goto out;
197 }
Jeff Garzik6aa20a22006-09-13 13:24:59 -0400198
Linus Torvalds1da177e2005-04-16 15:20:36 -0700199 old_cfg2 = inw(SEEQ_CFG2); /* read CFG2 register */
200 old_cfg1 = inw(SEEQ_CFG1);
201 old_dmaar = inw(SEEQ_DMAAR);
Jeff Garzik6aa20a22006-09-13 13:24:59 -0400202
Linus Torvalds1da177e2005-04-16 15:20:36 -0700203 if (net_debug>4) {
204 printk("seeq8005: stat = 0x%04x\n",old_stat);
205 printk("seeq8005: cfg1 = 0x%04x\n",old_cfg1);
206 printk("seeq8005: cfg2 = 0x%04x\n",old_cfg2);
207 printk("seeq8005: raer = 0x%04x\n",old_rear);
208 printk("seeq8005: dmaar= 0x%04x\n",old_dmaar);
209 }
Jeff Garzik6aa20a22006-09-13 13:24:59 -0400210
Linus Torvalds1da177e2005-04-16 15:20:36 -0700211 outw( SEEQCMD_FIFO_WRITE | SEEQCMD_SET_ALL_OFF, SEEQ_CMD); /* setup for reading PROM */
212 outw( 0, SEEQ_DMAAR); /* set starting PROM address */
213 outw( SEEQCFG1_BUFFER_PROM, SEEQ_CFG1); /* set buffer to look at PROM */
214
215
216 j=0;
217 for(i=0; i <32; i++) {
218 j+= SA_prom[i] = inw(SEEQ_BUFFER) & 0xff;
219 }
220
221#if 0
222 /* untested because I only have the one card */
223 if ( (j&0xff) != 0 ) { /* checksum appears to be 8bit = 0 */
224 if (net_debug>1) { /* check this before deciding that we have a card */
225 printk("seeq8005: prom sum error\n");
226 }
227 outw( old_stat, SEEQ_STATUS);
228 outw( old_dmaar, SEEQ_DMAAR);
229 outw( old_cfg1, SEEQ_CFG1);
230 retval = -ENODEV;
231 goto out;
232 }
233#endif
234
235 outw( SEEQCFG2_RESET, SEEQ_CFG2); /* reset the card */
236 udelay(5);
237 outw( SEEQCMD_SET_ALL_OFF, SEEQ_CMD);
Jeff Garzik6aa20a22006-09-13 13:24:59 -0400238
Linus Torvalds1da177e2005-04-16 15:20:36 -0700239 if (net_debug) {
240 printk("seeq8005: prom sum = 0x%08x\n",j);
241 for(j=0; j<32; j+=16) {
242 printk("seeq8005: prom %02x: ",j);
243 for(i=0;i<16;i++) {
244 printk("%02x ",SA_prom[j|i]);
245 }
246 printk(" ");
247 for(i=0;i<16;i++) {
248 if ((SA_prom[j|i]>31)&&(SA_prom[j|i]<127)) {
249 printk("%c", SA_prom[j|i]);
250 } else {
251 printk(" ");
252 }
253 }
254 printk("\n");
255 }
256 }
257
Jeff Garzik6aa20a22006-09-13 13:24:59 -0400258#if 0
259 /*
Linus Torvalds1da177e2005-04-16 15:20:36 -0700260 * testing the packet buffer memory doesn't work yet
Jeff Garzik6aa20a22006-09-13 13:24:59 -0400261 * but all other buffer accesses do
Linus Torvalds1da177e2005-04-16 15:20:36 -0700262 * - fixing is not a priority
263 */
264 if (net_debug>1) { /* test packet buffer memory */
265 printk("seeq8005: testing packet buffer ... ");
266 outw( SEEQCFG1_BUFFER_BUFFER, SEEQ_CFG1);
267 outw( SEEQCMD_FIFO_WRITE | SEEQCMD_SET_ALL_OFF, SEEQ_CMD);
268 outw( 0 , SEEQ_DMAAR);
269 for(i=0;i<32768;i++) {
270 outw(0x5a5a, SEEQ_BUFFER);
271 }
272 j=jiffies+HZ;
273 while ( ((inw(SEEQ_STATUS) & SEEQSTAT_FIFO_EMPTY) != SEEQSTAT_FIFO_EMPTY) && time_before(jiffies, j) )
274 mb();
275 outw( 0 , SEEQ_DMAAR);
276 while ( ((inw(SEEQ_STATUS) & SEEQSTAT_WINDOW_INT) != SEEQSTAT_WINDOW_INT) && time_before(jiffies, j+HZ))
277 mb();
278 if ( (inw(SEEQ_STATUS) & SEEQSTAT_WINDOW_INT) == SEEQSTAT_WINDOW_INT)
279 outw( SEEQCMD_WINDOW_INT_ACK | (inw(SEEQ_STATUS)& SEEQCMD_INT_MASK), SEEQ_CMD);
280 outw( SEEQCMD_FIFO_READ | SEEQCMD_SET_ALL_OFF, SEEQ_CMD);
281 j=0;
282 for(i=0;i<32768;i++) {
283 if (inw(SEEQ_BUFFER) != 0x5a5a)
284 j++;
285 }
286 if (j) {
287 printk("%i\n",j);
288 } else {
289 printk("ok.\n");
290 }
291 }
292#endif
293
294 if (net_debug && version_printed++ == 0)
295 printk(version);
296
297 printk("%s: %s found at %#3x, ", dev->name, "seeq8005", ioaddr);
298
299 /* Fill in the 'dev' fields. */
300 dev->base_addr = ioaddr;
301 dev->irq = irq;
302
303 /* Retrieve and print the ethernet address. */
304 for (i = 0; i < 6; i++)
Joe Perches0795af52007-10-03 17:59:30 -0700305 dev->dev_addr[i] = SA_prom[i+6];
306 printk("%s", print_mac(mac, dev->dev_addr));
Linus Torvalds1da177e2005-04-16 15:20:36 -0700307
308 if (dev->irq == 0xff)
309 ; /* Do nothing: a user-level program will set it. */
310 else if (dev->irq < 2) { /* "Auto-IRQ" */
311 unsigned long cookie = probe_irq_on();
Jeff Garzik6aa20a22006-09-13 13:24:59 -0400312
Linus Torvalds1da177e2005-04-16 15:20:36 -0700313 outw( SEEQCMD_RX_INT_EN | SEEQCMD_SET_RX_ON | SEEQCMD_SET_RX_OFF, SEEQ_CMD );
314
315 dev->irq = probe_irq_off(cookie);
Jeff Garzik6aa20a22006-09-13 13:24:59 -0400316
Linus Torvalds1da177e2005-04-16 15:20:36 -0700317 if (net_debug >= 2)
318 printk(" autoirq is %d\n", dev->irq);
319 } else if (dev->irq == 2)
320 /* Fixup for users that don't know that IRQ 2 is really IRQ 9,
Jeff Garzik6aa20a22006-09-13 13:24:59 -0400321 * or don't know which one to set.
Linus Torvalds1da177e2005-04-16 15:20:36 -0700322 */
323 dev->irq = 9;
324
325#if 0
326 {
327 int irqval = request_irq(dev->irq, &seeq8005_interrupt, 0, "seeq8005", dev);
328 if (irqval) {
329 printk ("%s: unable to get IRQ %d (irqval=%d).\n", dev->name,
330 dev->irq, irqval);
331 retval = -EAGAIN;
332 goto out;
333 }
334 }
335#endif
336 dev->open = seeq8005_open;
337 dev->stop = seeq8005_close;
338 dev->hard_start_xmit = seeq8005_send_packet;
339 dev->tx_timeout = seeq8005_timeout;
340 dev->watchdog_timeo = HZ/20;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700341 dev->set_multicast_list = set_multicast_list;
342 dev->flags &= ~IFF_MULTICAST;
343
344 return 0;
345out:
346 release_region(ioaddr, SEEQ8005_IO_EXTENT);
347 return retval;
348}
349
Jeff Garzik6aa20a22006-09-13 13:24:59 -0400350
Linus Torvalds1da177e2005-04-16 15:20:36 -0700351/* Open/initialize the board. This is called (in the current kernel)
352 sometime after booting when the 'ifconfig' program is run.
353
354 This routine should set everything up anew at each open, even
355 registers that "should" only need to be set once at boot, so that
356 there is non-reboot way to recover if something goes wrong.
357 */
358static int seeq8005_open(struct net_device *dev)
359{
360 struct net_local *lp = netdev_priv(dev);
361
362 {
363 int irqval = request_irq(dev->irq, &seeq8005_interrupt, 0, "seeq8005", dev);
364 if (irqval) {
365 printk ("%s: unable to get IRQ %d (irqval=%d).\n", dev->name,
366 dev->irq, irqval);
367 return -EAGAIN;
368 }
369 }
370
371 /* Reset the hardware here. Don't forget to set the station address. */
372 seeq8005_init(dev, 1);
373
374 lp->open_time = jiffies;
375
376 netif_start_queue(dev);
377 return 0;
378}
379
380static void seeq8005_timeout(struct net_device *dev)
381{
382 int ioaddr = dev->base_addr;
383 printk(KERN_WARNING "%s: transmit timed out, %s?\n", dev->name,
384 tx_done(dev) ? "IRQ conflict" : "network cable problem");
385 /* Try to restart the adaptor. */
386 seeq8005_init(dev, 1);
387 dev->trans_start = jiffies;
388 netif_wake_queue(dev);
389}
390
391static int seeq8005_send_packet(struct sk_buff *skb, struct net_device *dev)
392{
Linus Torvalds1da177e2005-04-16 15:20:36 -0700393 short length = skb->len;
394 unsigned char *buf;
395
396 if (length < ETH_ZLEN) {
Herbert Xu5b057c62006-06-23 02:06:41 -0700397 if (skb_padto(skb, ETH_ZLEN))
Linus Torvalds1da177e2005-04-16 15:20:36 -0700398 return 0;
399 length = ETH_ZLEN;
400 }
401 buf = skb->data;
402
403 /* Block a timer-based transmit from overlapping */
404 netif_stop_queue(dev);
Jeff Garzik6aa20a22006-09-13 13:24:59 -0400405
406 hardware_send_packet(dev, buf, length);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700407 dev->trans_start = jiffies;
Jeff Garzik09f75cd2007-10-03 17:41:50 -0700408 dev->stats.tx_bytes += length;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700409 dev_kfree_skb (skb);
410 /* You might need to clean up and record Tx statistics here. */
411
412 return 0;
413}
Jeff Garzik6aa20a22006-09-13 13:24:59 -0400414
Linus Torvalds1da177e2005-04-16 15:20:36 -0700415/*
416 * wait_for_buffer
417 *
418 * This routine waits for the SEEQ chip to assert that the FIFO is ready
419 * by checking for a window interrupt, and then clearing it. This has to
420 * occur in the interrupt handler!
421 */
422inline void wait_for_buffer(struct net_device * dev)
423{
424 int ioaddr = dev->base_addr;
425 unsigned long tmp;
426 int status;
Jeff Garzik6aa20a22006-09-13 13:24:59 -0400427
Linus Torvalds1da177e2005-04-16 15:20:36 -0700428 tmp = jiffies + HZ;
429 while ( ( ((status=inw(SEEQ_STATUS)) & SEEQSTAT_WINDOW_INT) != SEEQSTAT_WINDOW_INT) && time_before(jiffies, tmp))
430 cpu_relax();
Jeff Garzik6aa20a22006-09-13 13:24:59 -0400431
Linus Torvalds1da177e2005-04-16 15:20:36 -0700432 if ( (status & SEEQSTAT_WINDOW_INT) == SEEQSTAT_WINDOW_INT)
433 outw( SEEQCMD_WINDOW_INT_ACK | (status & SEEQCMD_INT_MASK), SEEQ_CMD);
434}
Jeff Garzik6aa20a22006-09-13 13:24:59 -0400435
Linus Torvalds1da177e2005-04-16 15:20:36 -0700436/* The typical workload of the driver:
437 Handle the network interface interrupts. */
David Howells7d12e782006-10-05 14:55:46 +0100438static irqreturn_t seeq8005_interrupt(int irq, void *dev_id)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700439{
440 struct net_device *dev = dev_id;
441 struct net_local *lp;
442 int ioaddr, status, boguscount = 0;
443 int handled = 0;
444
445 ioaddr = dev->base_addr;
446 lp = netdev_priv(dev);
447
448 status = inw(SEEQ_STATUS);
449 do {
450 if (net_debug >2) {
451 printk("%s: int, status=0x%04x\n",dev->name,status);
452 }
Jeff Garzik6aa20a22006-09-13 13:24:59 -0400453
Linus Torvalds1da177e2005-04-16 15:20:36 -0700454 if (status & SEEQSTAT_WINDOW_INT) {
455 handled = 1;
456 outw( SEEQCMD_WINDOW_INT_ACK | (status & SEEQCMD_INT_MASK), SEEQ_CMD);
457 if (net_debug) {
458 printk("%s: window int!\n",dev->name);
459 }
460 }
461 if (status & SEEQSTAT_TX_INT) {
462 handled = 1;
463 outw( SEEQCMD_TX_INT_ACK | (status & SEEQCMD_INT_MASK), SEEQ_CMD);
Jeff Garzik09f75cd2007-10-03 17:41:50 -0700464 dev->stats.tx_packets++;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700465 netif_wake_queue(dev); /* Inform upper layers. */
466 }
467 if (status & SEEQSTAT_RX_INT) {
468 handled = 1;
469 /* Got a packet(s). */
470 seeq8005_rx(dev);
471 }
472 status = inw(SEEQ_STATUS);
473 } while ( (++boguscount < 10) && (status & SEEQSTAT_ANY_INT)) ;
474
475 if(net_debug>2) {
476 printk("%s: eoi\n",dev->name);
477 }
478 return IRQ_RETVAL(handled);
479}
480
481/* We have a good packet(s), get it/them out of the buffers. */
482static void seeq8005_rx(struct net_device *dev)
483{
484 struct net_local *lp = netdev_priv(dev);
485 int boguscount = 10;
486 int pkt_hdr;
487 int ioaddr = dev->base_addr;
488
489 do {
490 int next_packet;
491 int pkt_len;
492 int i;
493 int status;
494
495 status = inw(SEEQ_STATUS);
496 outw( lp->receive_ptr, SEEQ_DMAAR);
497 outw(SEEQCMD_FIFO_READ | SEEQCMD_RX_INT_ACK | (status & SEEQCMD_INT_MASK), SEEQ_CMD);
498 wait_for_buffer(dev);
499 next_packet = ntohs(inw(SEEQ_BUFFER));
500 pkt_hdr = inw(SEEQ_BUFFER);
Jeff Garzik6aa20a22006-09-13 13:24:59 -0400501
Linus Torvalds1da177e2005-04-16 15:20:36 -0700502 if (net_debug>2) {
503 printk("%s: 0x%04x recv next=0x%04x, hdr=0x%04x\n",dev->name,lp->receive_ptr,next_packet,pkt_hdr);
504 }
Jeff Garzik6aa20a22006-09-13 13:24:59 -0400505
Linus Torvalds1da177e2005-04-16 15:20:36 -0700506 if ((next_packet == 0) || ((pkt_hdr & SEEQPKTH_CHAIN)==0)) { /* Read all the frames? */
507 return; /* Done for now */
508 }
Jeff Garzik6aa20a22006-09-13 13:24:59 -0400509
Linus Torvalds1da177e2005-04-16 15:20:36 -0700510 if ((pkt_hdr & SEEQPKTS_DONE)==0)
511 break;
Jeff Garzik6aa20a22006-09-13 13:24:59 -0400512
Linus Torvalds1da177e2005-04-16 15:20:36 -0700513 if (next_packet < lp->receive_ptr) {
514 pkt_len = (next_packet + 0x10000 - ((DEFAULT_TEA+1)<<8)) - lp->receive_ptr - 4;
515 } else {
516 pkt_len = next_packet - lp->receive_ptr - 4;
517 }
Jeff Garzik6aa20a22006-09-13 13:24:59 -0400518
Linus Torvalds1da177e2005-04-16 15:20:36 -0700519 if (next_packet < ((DEFAULT_TEA+1)<<8)) { /* is the next_packet address sane? */
520 printk("%s: recv packet ring corrupt, resetting board\n",dev->name);
521 seeq8005_init(dev,1);
522 return;
523 }
Jeff Garzik6aa20a22006-09-13 13:24:59 -0400524
Linus Torvalds1da177e2005-04-16 15:20:36 -0700525 lp->receive_ptr = next_packet;
Jeff Garzik6aa20a22006-09-13 13:24:59 -0400526
Linus Torvalds1da177e2005-04-16 15:20:36 -0700527 if (net_debug>2) {
528 printk("%s: recv len=0x%04x\n",dev->name,pkt_len);
529 }
530
531 if (pkt_hdr & SEEQPKTS_ANY_ERROR) { /* There was an error. */
Jeff Garzik09f75cd2007-10-03 17:41:50 -0700532 dev->stats.rx_errors++;
533 if (pkt_hdr & SEEQPKTS_SHORT) dev->stats.rx_frame_errors++;
534 if (pkt_hdr & SEEQPKTS_DRIB) dev->stats.rx_frame_errors++;
535 if (pkt_hdr & SEEQPKTS_OVERSIZE) dev->stats.rx_over_errors++;
536 if (pkt_hdr & SEEQPKTS_CRC_ERR) dev->stats.rx_crc_errors++;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700537 /* skip over this packet */
538 outw( SEEQCMD_FIFO_WRITE | SEEQCMD_DMA_INT_ACK | (status & SEEQCMD_INT_MASK), SEEQ_CMD);
539 outw( (lp->receive_ptr & 0xff00)>>8, SEEQ_REA);
540 } else {
541 /* Malloc up new buffer. */
542 struct sk_buff *skb;
543 unsigned char *buf;
544
545 skb = dev_alloc_skb(pkt_len);
546 if (skb == NULL) {
547 printk("%s: Memory squeeze, dropping packet.\n", dev->name);
Jeff Garzik09f75cd2007-10-03 17:41:50 -0700548 dev->stats.rx_dropped++;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700549 break;
550 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700551 skb_reserve(skb, 2); /* align data on 16 byte */
552 buf = skb_put(skb,pkt_len);
Jeff Garzik6aa20a22006-09-13 13:24:59 -0400553
Linus Torvalds1da177e2005-04-16 15:20:36 -0700554 insw(SEEQ_BUFFER, buf, (pkt_len + 1) >> 1);
Jeff Garzik6aa20a22006-09-13 13:24:59 -0400555
Linus Torvalds1da177e2005-04-16 15:20:36 -0700556 if (net_debug>2) {
557 char * p = buf;
558 printk("%s: recv ",dev->name);
559 for(i=0;i<14;i++) {
560 printk("%02x ",*(p++)&0xff);
561 }
562 printk("\n");
563 }
564
565 skb->protocol=eth_type_trans(skb,dev);
566 netif_rx(skb);
567 dev->last_rx = jiffies;
Jeff Garzik09f75cd2007-10-03 17:41:50 -0700568 dev->stats.rx_packets++;
569 dev->stats.rx_bytes += pkt_len;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700570 }
571 } while ((--boguscount) && (pkt_hdr & SEEQPKTH_CHAIN));
572
573 /* If any worth-while packets have been received, netif_rx()
574 has done a mark_bh(NET_BH) for us and will work on them
575 when we get to the bottom-half routine. */
576 return;
577}
578
579/* The inverse routine to net_open(). */
580static int seeq8005_close(struct net_device *dev)
581{
582 struct net_local *lp = netdev_priv(dev);
583 int ioaddr = dev->base_addr;
584
585 lp->open_time = 0;
586
587 netif_stop_queue(dev);
Jeff Garzik6aa20a22006-09-13 13:24:59 -0400588
Linus Torvalds1da177e2005-04-16 15:20:36 -0700589 /* Flush the Tx and disable Rx here. */
590 outw( SEEQCMD_SET_ALL_OFF, SEEQ_CMD);
591
592 free_irq(dev->irq, dev);
593
594 /* Update the statistics here. */
595
596 return 0;
597
598}
599
Linus Torvalds1da177e2005-04-16 15:20:36 -0700600/* Set or clear the multicast filter for this adaptor.
601 num_addrs == -1 Promiscuous mode, receive all packets
602 num_addrs == 0 Normal mode, clear multicast list
603 num_addrs > 0 Multicast mode, receive normal and MC packets, and do
604 best-effort filtering.
605 */
606static void set_multicast_list(struct net_device *dev)
607{
608/*
609 * I _could_ do up to 6 addresses here, but won't (yet?)
610 */
611
612#if 0
613 int ioaddr = dev->base_addr;
614/*
615 * hmm, not even sure if my matching works _anyway_ - seem to be receiving
616 * _everything_ . . .
617 */
Jeff Garzik6aa20a22006-09-13 13:24:59 -0400618
Linus Torvalds1da177e2005-04-16 15:20:36 -0700619 if (num_addrs) { /* Enable promiscuous mode */
620 outw( (inw(SEEQ_CFG1) & ~SEEQCFG1_MATCH_MASK)| SEEQCFG1_MATCH_ALL, SEEQ_CFG1);
621 dev->flags|=IFF_PROMISC;
622 } else { /* Disable promiscuous mode, use normal mode */
623 outw( (inw(SEEQ_CFG1) & ~SEEQCFG1_MATCH_MASK)| SEEQCFG1_MATCH_BROAD, SEEQ_CFG1);
624 }
625#endif
626}
627
628void seeq8005_init(struct net_device *dev, int startp)
629{
630 struct net_local *lp = netdev_priv(dev);
631 int ioaddr = dev->base_addr;
632 int i;
Jeff Garzik6aa20a22006-09-13 13:24:59 -0400633
Linus Torvalds1da177e2005-04-16 15:20:36 -0700634 outw(SEEQCFG2_RESET, SEEQ_CFG2); /* reset device */
635 udelay(5);
Jeff Garzik6aa20a22006-09-13 13:24:59 -0400636
Linus Torvalds1da177e2005-04-16 15:20:36 -0700637 outw( SEEQCMD_FIFO_WRITE | SEEQCMD_SET_ALL_OFF, SEEQ_CMD);
638 outw( 0, SEEQ_DMAAR); /* load start address into both low and high byte */
639/* wait_for_buffer(dev); */ /* I think that you only need a wait for memory buffer */
640 outw( SEEQCFG1_BUFFER_MAC0, SEEQ_CFG1);
Jeff Garzik6aa20a22006-09-13 13:24:59 -0400641
Linus Torvalds1da177e2005-04-16 15:20:36 -0700642 for(i=0;i<6;i++) { /* set Station address */
643 outb(dev->dev_addr[i], SEEQ_BUFFER);
644 udelay(2);
645 }
Jeff Garzik6aa20a22006-09-13 13:24:59 -0400646
Linus Torvalds1da177e2005-04-16 15:20:36 -0700647 outw( SEEQCFG1_BUFFER_TEA, SEEQ_CFG1); /* set xmit end area pointer to 16K */
648 outb( DEFAULT_TEA, SEEQ_BUFFER); /* this gives us 16K of send buffer and 48K of recv buffer */
Jeff Garzik6aa20a22006-09-13 13:24:59 -0400649
Linus Torvalds1da177e2005-04-16 15:20:36 -0700650 lp->receive_ptr = (DEFAULT_TEA+1)<<8; /* so we can find our packet_header */
651 outw( lp->receive_ptr, SEEQ_RPR); /* Receive Pointer Register is set to recv buffer memory */
Jeff Garzik6aa20a22006-09-13 13:24:59 -0400652
Linus Torvalds1da177e2005-04-16 15:20:36 -0700653 outw( 0x00ff, SEEQ_REA); /* Receive Area End */
654
655 if (net_debug>4) {
656 printk("%s: SA0 = ",dev->name);
657
658 outw( SEEQCMD_FIFO_READ | SEEQCMD_SET_ALL_OFF, SEEQ_CMD);
659 outw( 0, SEEQ_DMAAR);
660 outw( SEEQCFG1_BUFFER_MAC0, SEEQ_CFG1);
Jeff Garzik6aa20a22006-09-13 13:24:59 -0400661
Linus Torvalds1da177e2005-04-16 15:20:36 -0700662 for(i=0;i<6;i++) {
663 printk("%02x ",inb(SEEQ_BUFFER));
664 }
665 printk("\n");
666 }
Jeff Garzik6aa20a22006-09-13 13:24:59 -0400667
Linus Torvalds1da177e2005-04-16 15:20:36 -0700668 outw( SEEQCFG1_MAC0_EN | SEEQCFG1_MATCH_BROAD | SEEQCFG1_BUFFER_BUFFER, SEEQ_CFG1);
669 outw( SEEQCFG2_AUTO_REA | SEEQCFG2_CTRLO, SEEQ_CFG2);
670 outw( SEEQCMD_SET_RX_ON | SEEQCMD_TX_INT_EN | SEEQCMD_RX_INT_EN, SEEQ_CMD);
671
672 if (net_debug>4) {
673 int old_cfg1;
674 old_cfg1 = inw(SEEQ_CFG1);
675 printk("%s: stat = 0x%04x\n",dev->name,inw(SEEQ_STATUS));
676 printk("%s: cfg1 = 0x%04x\n",dev->name,old_cfg1);
677 printk("%s: cfg2 = 0x%04x\n",dev->name,inw(SEEQ_CFG2));
678 printk("%s: raer = 0x%04x\n",dev->name,inw(SEEQ_REA));
679 printk("%s: dmaar= 0x%04x\n",dev->name,inw(SEEQ_DMAAR));
Jeff Garzik6aa20a22006-09-13 13:24:59 -0400680
Linus Torvalds1da177e2005-04-16 15:20:36 -0700681 }
Jeff Garzik6aa20a22006-09-13 13:24:59 -0400682}
Linus Torvalds1da177e2005-04-16 15:20:36 -0700683
684
685static void hardware_send_packet(struct net_device * dev, char *buf, int length)
686{
687 int ioaddr = dev->base_addr;
688 int status = inw(SEEQ_STATUS);
689 int transmit_ptr = 0;
Marcelo Feitoza Parisiff5688a2006-01-09 18:37:15 -0800690 unsigned long tmp;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700691
692 if (net_debug>4) {
693 printk("%s: send 0x%04x\n",dev->name,length);
694 }
Jeff Garzik6aa20a22006-09-13 13:24:59 -0400695
Linus Torvalds1da177e2005-04-16 15:20:36 -0700696 /* Set FIFO to writemode and set packet-buffer address */
697 outw( SEEQCMD_FIFO_WRITE | (status & SEEQCMD_INT_MASK), SEEQ_CMD);
698 outw( transmit_ptr, SEEQ_DMAAR);
Jeff Garzik6aa20a22006-09-13 13:24:59 -0400699
Linus Torvalds1da177e2005-04-16 15:20:36 -0700700 /* output SEEQ Packet header barfage */
701 outw( htons(length + 4), SEEQ_BUFFER);
702 outw( SEEQPKTH_XMIT | SEEQPKTH_DATA_FOLLOWS | SEEQPKTH_XMIT_INT_EN, SEEQ_BUFFER );
Jeff Garzik6aa20a22006-09-13 13:24:59 -0400703
Linus Torvalds1da177e2005-04-16 15:20:36 -0700704 /* blat the buffer */
705 outsw( SEEQ_BUFFER, buf, (length +1) >> 1);
706 /* paranoia !! */
707 outw( 0, SEEQ_BUFFER);
708 outw( 0, SEEQ_BUFFER);
Jeff Garzik6aa20a22006-09-13 13:24:59 -0400709
Linus Torvalds1da177e2005-04-16 15:20:36 -0700710 /* set address of start of transmit chain */
711 outw( transmit_ptr, SEEQ_TPR);
Jeff Garzik6aa20a22006-09-13 13:24:59 -0400712
Linus Torvalds1da177e2005-04-16 15:20:36 -0700713 /* drain FIFO */
714 tmp = jiffies;
Marcelo Feitoza Parisiff5688a2006-01-09 18:37:15 -0800715 while ( (((status=inw(SEEQ_STATUS)) & SEEQSTAT_FIFO_EMPTY) == 0) && time_before(jiffies, tmp + HZ))
Linus Torvalds1da177e2005-04-16 15:20:36 -0700716 mb();
Jeff Garzik6aa20a22006-09-13 13:24:59 -0400717
Linus Torvalds1da177e2005-04-16 15:20:36 -0700718 /* doit ! */
719 outw( SEEQCMD_WINDOW_INT_ACK | SEEQCMD_SET_TX_ON | (status & SEEQCMD_INT_MASK), SEEQ_CMD);
Jeff Garzik6aa20a22006-09-13 13:24:59 -0400720
Linus Torvalds1da177e2005-04-16 15:20:36 -0700721}
722
723
724#ifdef MODULE
725
726static struct net_device *dev_seeq;
727MODULE_LICENSE("GPL");
728module_param(io, int, 0);
729module_param(irq, int, 0);
730MODULE_PARM_DESC(io, "SEEQ 8005 I/O base address");
731MODULE_PARM_DESC(irq, "SEEQ 8005 IRQ number");
732
Andrew Mortonc971ef42006-08-14 23:00:08 -0700733int __init init_module(void)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700734{
735 dev_seeq = seeq8005_probe(-1);
736 if (IS_ERR(dev_seeq))
737 return PTR_ERR(dev_seeq);
738 return 0;
739}
740
Al Viroafc8eb42006-06-14 18:50:53 -0400741void __exit cleanup_module(void)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700742{
743 unregister_netdev(dev_seeq);
744 release_region(dev_seeq->base_addr, SEEQ8005_IO_EXTENT);
745 free_netdev(dev_seeq);
746}
747
748#endif /* MODULE */
Jeff Garzik6aa20a22006-09-13 13:24:59 -0400749
Linus Torvalds1da177e2005-04-16 15:20:36 -0700750/*
751 * Local variables:
752 * compile-command: "gcc -D__KERNEL__ -I/usr/src/linux/net/inet -Wall -Wstrict-prototypes -O6 -m486 -c skeleton.c"
753 * version-control: t
754 * kept-new-versions: 5
755 * tab-width: 4
756 * End:
757 */