blob: 39246d457ac2020cb94dea9e3a901cab4b8d5a8d [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);
Stephen Hemminger613573252009-08-31 19:50:58 +000084static netdev_tx_t seeq8005_send_packet(struct sk_buff *skb,
85 struct net_device *dev);
David Howells7d12e782006-10-05 14:55:46 +010086static irqreturn_t seeq8005_interrupt(int irq, void *dev_id);
Linus Torvalds1da177e2005-04-16 15:20:36 -070087static void seeq8005_rx(struct net_device *dev);
88static int seeq8005_close(struct net_device *dev);
Linus Torvalds1da177e2005-04-16 15:20:36 -070089static void set_multicast_list(struct net_device *dev);
90
91/* Example routines you must write ;->. */
92#define tx_done(dev) (inw(SEEQ_STATUS) & SEEQSTAT_TX_ON)
93static void hardware_send_packet(struct net_device *dev, char *buf, int length);
94extern void seeq8005_init(struct net_device *dev, int startp);
95static inline void wait_for_buffer(struct net_device *dev);
96
Jeff Garzik6aa20a22006-09-13 13:24:59 -040097
Linus Torvalds1da177e2005-04-16 15:20:36 -070098/* Check for a network adaptor of this type, and return '0' iff one exists.
99 If dev->base_addr == 0, probe all likely locations.
100 If dev->base_addr == 1, always return failure.
101 */
102
103static int io = 0x320;
104static int irq = 10;
105
106struct net_device * __init seeq8005_probe(int unit)
107{
108 struct net_device *dev = alloc_etherdev(sizeof(struct net_local));
109 unsigned *port;
110 int err = 0;
111
112 if (!dev)
113 return ERR_PTR(-ENODEV);
114
115 if (unit >= 0) {
116 sprintf(dev->name, "eth%d", unit);
117 netdev_boot_setup_check(dev);
118 io = dev->base_addr;
119 irq = dev->irq;
120 }
121
122 if (io > 0x1ff) { /* Check a single specified location. */
123 err = seeq8005_probe1(dev, io);
124 } else if (io != 0) { /* Don't probe at all. */
125 err = -ENXIO;
126 } else {
127 for (port = seeq8005_portlist; *port; port++) {
128 if (seeq8005_probe1(dev, *port) == 0)
129 break;
130 }
131 if (!*port)
132 err = -ENODEV;
133 }
134 if (err)
135 goto out;
136 err = register_netdev(dev);
137 if (err)
138 goto out1;
139 return dev;
140out1:
141 release_region(dev->base_addr, SEEQ8005_IO_EXTENT);
142out:
143 free_netdev(dev);
144 return ERR_PTR(err);
145}
146
Stephen Hemmingerb20417d2009-03-26 15:11:28 +0000147static const struct net_device_ops seeq8005_netdev_ops = {
148 .ndo_open = seeq8005_open,
149 .ndo_stop = seeq8005_close,
150 .ndo_start_xmit = seeq8005_send_packet,
151 .ndo_tx_timeout = seeq8005_timeout,
152 .ndo_set_multicast_list = set_multicast_list,
153 .ndo_change_mtu = eth_change_mtu,
154 .ndo_set_mac_address = eth_mac_addr,
155 .ndo_validate_addr = eth_validate_addr,
156};
157
Linus Torvalds1da177e2005-04-16 15:20:36 -0700158/* This is the real probe routine. Linux has a history of friendly device
159 probes on the ISA bus. A good device probes avoids doing writes, and
160 verifies that the correct device exists and functions. */
161
162static int __init seeq8005_probe1(struct net_device *dev, int ioaddr)
163{
164 static unsigned version_printed;
165 int i,j;
166 unsigned char SA_prom[32];
167 int old_cfg1;
168 int old_cfg2;
169 int old_stat;
170 int old_dmaar;
171 int old_rear;
172 int retval;
173
174 if (!request_region(ioaddr, SEEQ8005_IO_EXTENT, "seeq8005"))
175 return -ENODEV;
176
177 if (net_debug>1)
178 printk("seeq8005: probing at 0x%x\n",ioaddr);
179
180 old_stat = inw(SEEQ_STATUS); /* read status register */
181 if (old_stat == 0xffff) {
182 retval = -ENODEV;
183 goto out; /* assume that 0xffff == no device */
184 }
185 if ( (old_stat & 0x1800) != 0x1800 ) { /* assume that unused bits are 1, as my manual says */
186 if (net_debug>1) {
187 printk("seeq8005: reserved stat bits != 0x1800\n");
188 printk(" == 0x%04x\n",old_stat);
189 }
190 retval = -ENODEV;
191 goto out;
192 }
193
194 old_rear = inw(SEEQ_REA);
195 if (old_rear == 0xffff) {
196 outw(0,SEEQ_REA);
197 if (inw(SEEQ_REA) == 0xffff) { /* assume that 0xffff == no device */
198 retval = -ENODEV;
199 goto out;
200 }
201 } else if ((old_rear & 0xff00) != 0xff00) { /* assume that unused bits are 1 */
202 if (net_debug>1) {
203 printk("seeq8005: unused rear bits != 0xff00\n");
204 printk(" == 0x%04x\n",old_rear);
205 }
206 retval = -ENODEV;
207 goto out;
208 }
Jeff Garzik6aa20a22006-09-13 13:24:59 -0400209
Linus Torvalds1da177e2005-04-16 15:20:36 -0700210 old_cfg2 = inw(SEEQ_CFG2); /* read CFG2 register */
211 old_cfg1 = inw(SEEQ_CFG1);
212 old_dmaar = inw(SEEQ_DMAAR);
Jeff Garzik6aa20a22006-09-13 13:24:59 -0400213
Linus Torvalds1da177e2005-04-16 15:20:36 -0700214 if (net_debug>4) {
215 printk("seeq8005: stat = 0x%04x\n",old_stat);
216 printk("seeq8005: cfg1 = 0x%04x\n",old_cfg1);
217 printk("seeq8005: cfg2 = 0x%04x\n",old_cfg2);
218 printk("seeq8005: raer = 0x%04x\n",old_rear);
219 printk("seeq8005: dmaar= 0x%04x\n",old_dmaar);
220 }
Jeff Garzik6aa20a22006-09-13 13:24:59 -0400221
Linus Torvalds1da177e2005-04-16 15:20:36 -0700222 outw( SEEQCMD_FIFO_WRITE | SEEQCMD_SET_ALL_OFF, SEEQ_CMD); /* setup for reading PROM */
223 outw( 0, SEEQ_DMAAR); /* set starting PROM address */
224 outw( SEEQCFG1_BUFFER_PROM, SEEQ_CFG1); /* set buffer to look at PROM */
225
226
227 j=0;
228 for(i=0; i <32; i++) {
229 j+= SA_prom[i] = inw(SEEQ_BUFFER) & 0xff;
230 }
231
232#if 0
233 /* untested because I only have the one card */
234 if ( (j&0xff) != 0 ) { /* checksum appears to be 8bit = 0 */
235 if (net_debug>1) { /* check this before deciding that we have a card */
236 printk("seeq8005: prom sum error\n");
237 }
238 outw( old_stat, SEEQ_STATUS);
239 outw( old_dmaar, SEEQ_DMAAR);
240 outw( old_cfg1, SEEQ_CFG1);
241 retval = -ENODEV;
242 goto out;
243 }
244#endif
245
246 outw( SEEQCFG2_RESET, SEEQ_CFG2); /* reset the card */
247 udelay(5);
248 outw( SEEQCMD_SET_ALL_OFF, SEEQ_CMD);
Jeff Garzik6aa20a22006-09-13 13:24:59 -0400249
Linus Torvalds1da177e2005-04-16 15:20:36 -0700250 if (net_debug) {
251 printk("seeq8005: prom sum = 0x%08x\n",j);
252 for(j=0; j<32; j+=16) {
253 printk("seeq8005: prom %02x: ",j);
254 for(i=0;i<16;i++) {
255 printk("%02x ",SA_prom[j|i]);
256 }
257 printk(" ");
258 for(i=0;i<16;i++) {
259 if ((SA_prom[j|i]>31)&&(SA_prom[j|i]<127)) {
260 printk("%c", SA_prom[j|i]);
261 } else {
262 printk(" ");
263 }
264 }
265 printk("\n");
266 }
267 }
268
Jeff Garzik6aa20a22006-09-13 13:24:59 -0400269#if 0
270 /*
Linus Torvalds1da177e2005-04-16 15:20:36 -0700271 * testing the packet buffer memory doesn't work yet
Jeff Garzik6aa20a22006-09-13 13:24:59 -0400272 * but all other buffer accesses do
Linus Torvalds1da177e2005-04-16 15:20:36 -0700273 * - fixing is not a priority
274 */
275 if (net_debug>1) { /* test packet buffer memory */
276 printk("seeq8005: testing packet buffer ... ");
277 outw( SEEQCFG1_BUFFER_BUFFER, SEEQ_CFG1);
278 outw( SEEQCMD_FIFO_WRITE | SEEQCMD_SET_ALL_OFF, SEEQ_CMD);
279 outw( 0 , SEEQ_DMAAR);
280 for(i=0;i<32768;i++) {
281 outw(0x5a5a, SEEQ_BUFFER);
282 }
283 j=jiffies+HZ;
284 while ( ((inw(SEEQ_STATUS) & SEEQSTAT_FIFO_EMPTY) != SEEQSTAT_FIFO_EMPTY) && time_before(jiffies, j) )
285 mb();
286 outw( 0 , SEEQ_DMAAR);
287 while ( ((inw(SEEQ_STATUS) & SEEQSTAT_WINDOW_INT) != SEEQSTAT_WINDOW_INT) && time_before(jiffies, j+HZ))
288 mb();
289 if ( (inw(SEEQ_STATUS) & SEEQSTAT_WINDOW_INT) == SEEQSTAT_WINDOW_INT)
290 outw( SEEQCMD_WINDOW_INT_ACK | (inw(SEEQ_STATUS)& SEEQCMD_INT_MASK), SEEQ_CMD);
291 outw( SEEQCMD_FIFO_READ | SEEQCMD_SET_ALL_OFF, SEEQ_CMD);
292 j=0;
293 for(i=0;i<32768;i++) {
294 if (inw(SEEQ_BUFFER) != 0x5a5a)
295 j++;
296 }
297 if (j) {
298 printk("%i\n",j);
299 } else {
300 printk("ok.\n");
301 }
302 }
303#endif
304
305 if (net_debug && version_printed++ == 0)
306 printk(version);
307
308 printk("%s: %s found at %#3x, ", dev->name, "seeq8005", ioaddr);
309
310 /* Fill in the 'dev' fields. */
311 dev->base_addr = ioaddr;
312 dev->irq = irq;
313
314 /* Retrieve and print the ethernet address. */
315 for (i = 0; i < 6; i++)
Joe Perches0795af52007-10-03 17:59:30 -0700316 dev->dev_addr[i] = SA_prom[i+6];
Johannes Berge1749612008-10-27 15:59:26 -0700317 printk("%pM", dev->dev_addr);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700318
319 if (dev->irq == 0xff)
320 ; /* Do nothing: a user-level program will set it. */
321 else if (dev->irq < 2) { /* "Auto-IRQ" */
322 unsigned long cookie = probe_irq_on();
Jeff Garzik6aa20a22006-09-13 13:24:59 -0400323
Linus Torvalds1da177e2005-04-16 15:20:36 -0700324 outw( SEEQCMD_RX_INT_EN | SEEQCMD_SET_RX_ON | SEEQCMD_SET_RX_OFF, SEEQ_CMD );
325
326 dev->irq = probe_irq_off(cookie);
Jeff Garzik6aa20a22006-09-13 13:24:59 -0400327
Linus Torvalds1da177e2005-04-16 15:20:36 -0700328 if (net_debug >= 2)
329 printk(" autoirq is %d\n", dev->irq);
330 } else if (dev->irq == 2)
331 /* Fixup for users that don't know that IRQ 2 is really IRQ 9,
Jeff Garzik6aa20a22006-09-13 13:24:59 -0400332 * or don't know which one to set.
Linus Torvalds1da177e2005-04-16 15:20:36 -0700333 */
334 dev->irq = 9;
335
336#if 0
337 {
338 int irqval = request_irq(dev->irq, &seeq8005_interrupt, 0, "seeq8005", dev);
339 if (irqval) {
340 printk ("%s: unable to get IRQ %d (irqval=%d).\n", dev->name,
341 dev->irq, irqval);
342 retval = -EAGAIN;
343 goto out;
344 }
345 }
346#endif
Stephen Hemmingerb20417d2009-03-26 15:11:28 +0000347 dev->netdev_ops = &seeq8005_netdev_ops;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700348 dev->watchdog_timeo = HZ/20;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700349 dev->flags &= ~IFF_MULTICAST;
350
351 return 0;
352out:
353 release_region(ioaddr, SEEQ8005_IO_EXTENT);
354 return retval;
355}
356
Jeff Garzik6aa20a22006-09-13 13:24:59 -0400357
Linus Torvalds1da177e2005-04-16 15:20:36 -0700358/* Open/initialize the board. This is called (in the current kernel)
359 sometime after booting when the 'ifconfig' program is run.
360
361 This routine should set everything up anew at each open, even
362 registers that "should" only need to be set once at boot, so that
363 there is non-reboot way to recover if something goes wrong.
364 */
365static int seeq8005_open(struct net_device *dev)
366{
367 struct net_local *lp = netdev_priv(dev);
368
369 {
370 int irqval = request_irq(dev->irq, &seeq8005_interrupt, 0, "seeq8005", dev);
371 if (irqval) {
372 printk ("%s: unable to get IRQ %d (irqval=%d).\n", dev->name,
373 dev->irq, irqval);
374 return -EAGAIN;
375 }
376 }
377
378 /* Reset the hardware here. Don't forget to set the station address. */
379 seeq8005_init(dev, 1);
380
381 lp->open_time = jiffies;
382
383 netif_start_queue(dev);
384 return 0;
385}
386
387static void seeq8005_timeout(struct net_device *dev)
388{
389 int ioaddr = dev->base_addr;
390 printk(KERN_WARNING "%s: transmit timed out, %s?\n", dev->name,
391 tx_done(dev) ? "IRQ conflict" : "network cable problem");
392 /* Try to restart the adaptor. */
393 seeq8005_init(dev, 1);
394 dev->trans_start = jiffies;
395 netif_wake_queue(dev);
396}
397
Stephen Hemminger613573252009-08-31 19:50:58 +0000398static netdev_tx_t seeq8005_send_packet(struct sk_buff *skb,
399 struct net_device *dev)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700400{
Linus Torvalds1da177e2005-04-16 15:20:36 -0700401 short length = skb->len;
402 unsigned char *buf;
403
404 if (length < ETH_ZLEN) {
Herbert Xu5b057c62006-06-23 02:06:41 -0700405 if (skb_padto(skb, ETH_ZLEN))
Patrick McHardy6ed10652009-06-23 06:03:08 +0000406 return NETDEV_TX_OK;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700407 length = ETH_ZLEN;
408 }
409 buf = skb->data;
410
411 /* Block a timer-based transmit from overlapping */
412 netif_stop_queue(dev);
Jeff Garzik6aa20a22006-09-13 13:24:59 -0400413
414 hardware_send_packet(dev, buf, length);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700415 dev->trans_start = jiffies;
Jeff Garzik09f75cd2007-10-03 17:41:50 -0700416 dev->stats.tx_bytes += length;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700417 dev_kfree_skb (skb);
418 /* You might need to clean up and record Tx statistics here. */
419
Patrick McHardy6ed10652009-06-23 06:03:08 +0000420 return NETDEV_TX_OK;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700421}
Jeff Garzik6aa20a22006-09-13 13:24:59 -0400422
Linus Torvalds1da177e2005-04-16 15:20:36 -0700423/*
424 * wait_for_buffer
425 *
426 * This routine waits for the SEEQ chip to assert that the FIFO is ready
427 * by checking for a window interrupt, and then clearing it. This has to
428 * occur in the interrupt handler!
429 */
430inline void wait_for_buffer(struct net_device * dev)
431{
432 int ioaddr = dev->base_addr;
433 unsigned long tmp;
434 int status;
Jeff Garzik6aa20a22006-09-13 13:24:59 -0400435
Linus Torvalds1da177e2005-04-16 15:20:36 -0700436 tmp = jiffies + HZ;
437 while ( ( ((status=inw(SEEQ_STATUS)) & SEEQSTAT_WINDOW_INT) != SEEQSTAT_WINDOW_INT) && time_before(jiffies, tmp))
438 cpu_relax();
Jeff Garzik6aa20a22006-09-13 13:24:59 -0400439
Linus Torvalds1da177e2005-04-16 15:20:36 -0700440 if ( (status & SEEQSTAT_WINDOW_INT) == SEEQSTAT_WINDOW_INT)
441 outw( SEEQCMD_WINDOW_INT_ACK | (status & SEEQCMD_INT_MASK), SEEQ_CMD);
442}
Jeff Garzik6aa20a22006-09-13 13:24:59 -0400443
Linus Torvalds1da177e2005-04-16 15:20:36 -0700444/* The typical workload of the driver:
445 Handle the network interface interrupts. */
David Howells7d12e782006-10-05 14:55:46 +0100446static irqreturn_t seeq8005_interrupt(int irq, void *dev_id)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700447{
448 struct net_device *dev = dev_id;
449 struct net_local *lp;
450 int ioaddr, status, boguscount = 0;
451 int handled = 0;
452
453 ioaddr = dev->base_addr;
454 lp = netdev_priv(dev);
455
456 status = inw(SEEQ_STATUS);
457 do {
458 if (net_debug >2) {
459 printk("%s: int, status=0x%04x\n",dev->name,status);
460 }
Jeff Garzik6aa20a22006-09-13 13:24:59 -0400461
Linus Torvalds1da177e2005-04-16 15:20:36 -0700462 if (status & SEEQSTAT_WINDOW_INT) {
463 handled = 1;
464 outw( SEEQCMD_WINDOW_INT_ACK | (status & SEEQCMD_INT_MASK), SEEQ_CMD);
465 if (net_debug) {
466 printk("%s: window int!\n",dev->name);
467 }
468 }
469 if (status & SEEQSTAT_TX_INT) {
470 handled = 1;
471 outw( SEEQCMD_TX_INT_ACK | (status & SEEQCMD_INT_MASK), SEEQ_CMD);
Jeff Garzik09f75cd2007-10-03 17:41:50 -0700472 dev->stats.tx_packets++;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700473 netif_wake_queue(dev); /* Inform upper layers. */
474 }
475 if (status & SEEQSTAT_RX_INT) {
476 handled = 1;
477 /* Got a packet(s). */
478 seeq8005_rx(dev);
479 }
480 status = inw(SEEQ_STATUS);
481 } while ( (++boguscount < 10) && (status & SEEQSTAT_ANY_INT)) ;
482
483 if(net_debug>2) {
484 printk("%s: eoi\n",dev->name);
485 }
486 return IRQ_RETVAL(handled);
487}
488
489/* We have a good packet(s), get it/them out of the buffers. */
490static void seeq8005_rx(struct net_device *dev)
491{
492 struct net_local *lp = netdev_priv(dev);
493 int boguscount = 10;
494 int pkt_hdr;
495 int ioaddr = dev->base_addr;
496
497 do {
498 int next_packet;
499 int pkt_len;
500 int i;
501 int status;
502
503 status = inw(SEEQ_STATUS);
504 outw( lp->receive_ptr, SEEQ_DMAAR);
505 outw(SEEQCMD_FIFO_READ | SEEQCMD_RX_INT_ACK | (status & SEEQCMD_INT_MASK), SEEQ_CMD);
506 wait_for_buffer(dev);
507 next_packet = ntohs(inw(SEEQ_BUFFER));
508 pkt_hdr = inw(SEEQ_BUFFER);
Jeff Garzik6aa20a22006-09-13 13:24:59 -0400509
Linus Torvalds1da177e2005-04-16 15:20:36 -0700510 if (net_debug>2) {
511 printk("%s: 0x%04x recv next=0x%04x, hdr=0x%04x\n",dev->name,lp->receive_ptr,next_packet,pkt_hdr);
512 }
Jeff Garzik6aa20a22006-09-13 13:24:59 -0400513
Linus Torvalds1da177e2005-04-16 15:20:36 -0700514 if ((next_packet == 0) || ((pkt_hdr & SEEQPKTH_CHAIN)==0)) { /* Read all the frames? */
515 return; /* Done for now */
516 }
Jeff Garzik6aa20a22006-09-13 13:24:59 -0400517
Linus Torvalds1da177e2005-04-16 15:20:36 -0700518 if ((pkt_hdr & SEEQPKTS_DONE)==0)
519 break;
Jeff Garzik6aa20a22006-09-13 13:24:59 -0400520
Linus Torvalds1da177e2005-04-16 15:20:36 -0700521 if (next_packet < lp->receive_ptr) {
522 pkt_len = (next_packet + 0x10000 - ((DEFAULT_TEA+1)<<8)) - lp->receive_ptr - 4;
523 } else {
524 pkt_len = next_packet - lp->receive_ptr - 4;
525 }
Jeff Garzik6aa20a22006-09-13 13:24:59 -0400526
Linus Torvalds1da177e2005-04-16 15:20:36 -0700527 if (next_packet < ((DEFAULT_TEA+1)<<8)) { /* is the next_packet address sane? */
528 printk("%s: recv packet ring corrupt, resetting board\n",dev->name);
529 seeq8005_init(dev,1);
530 return;
531 }
Jeff Garzik6aa20a22006-09-13 13:24:59 -0400532
Linus Torvalds1da177e2005-04-16 15:20:36 -0700533 lp->receive_ptr = next_packet;
Jeff Garzik6aa20a22006-09-13 13:24:59 -0400534
Linus Torvalds1da177e2005-04-16 15:20:36 -0700535 if (net_debug>2) {
536 printk("%s: recv len=0x%04x\n",dev->name,pkt_len);
537 }
538
539 if (pkt_hdr & SEEQPKTS_ANY_ERROR) { /* There was an error. */
Jeff Garzik09f75cd2007-10-03 17:41:50 -0700540 dev->stats.rx_errors++;
541 if (pkt_hdr & SEEQPKTS_SHORT) dev->stats.rx_frame_errors++;
542 if (pkt_hdr & SEEQPKTS_DRIB) dev->stats.rx_frame_errors++;
543 if (pkt_hdr & SEEQPKTS_OVERSIZE) dev->stats.rx_over_errors++;
544 if (pkt_hdr & SEEQPKTS_CRC_ERR) dev->stats.rx_crc_errors++;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700545 /* skip over this packet */
546 outw( SEEQCMD_FIFO_WRITE | SEEQCMD_DMA_INT_ACK | (status & SEEQCMD_INT_MASK), SEEQ_CMD);
547 outw( (lp->receive_ptr & 0xff00)>>8, SEEQ_REA);
548 } else {
549 /* Malloc up new buffer. */
550 struct sk_buff *skb;
551 unsigned char *buf;
552
553 skb = dev_alloc_skb(pkt_len);
554 if (skb == NULL) {
555 printk("%s: Memory squeeze, dropping packet.\n", dev->name);
Jeff Garzik09f75cd2007-10-03 17:41:50 -0700556 dev->stats.rx_dropped++;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700557 break;
558 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700559 skb_reserve(skb, 2); /* align data on 16 byte */
560 buf = skb_put(skb,pkt_len);
Jeff Garzik6aa20a22006-09-13 13:24:59 -0400561
Linus Torvalds1da177e2005-04-16 15:20:36 -0700562 insw(SEEQ_BUFFER, buf, (pkt_len + 1) >> 1);
Jeff Garzik6aa20a22006-09-13 13:24:59 -0400563
Linus Torvalds1da177e2005-04-16 15:20:36 -0700564 if (net_debug>2) {
565 char * p = buf;
566 printk("%s: recv ",dev->name);
567 for(i=0;i<14;i++) {
568 printk("%02x ",*(p++)&0xff);
569 }
570 printk("\n");
571 }
572
573 skb->protocol=eth_type_trans(skb,dev);
574 netif_rx(skb);
Jeff Garzik09f75cd2007-10-03 17:41:50 -0700575 dev->stats.rx_packets++;
576 dev->stats.rx_bytes += pkt_len;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700577 }
578 } while ((--boguscount) && (pkt_hdr & SEEQPKTH_CHAIN));
579
580 /* If any worth-while packets have been received, netif_rx()
581 has done a mark_bh(NET_BH) for us and will work on them
582 when we get to the bottom-half routine. */
583 return;
584}
585
586/* The inverse routine to net_open(). */
587static int seeq8005_close(struct net_device *dev)
588{
589 struct net_local *lp = netdev_priv(dev);
590 int ioaddr = dev->base_addr;
591
592 lp->open_time = 0;
593
594 netif_stop_queue(dev);
Jeff Garzik6aa20a22006-09-13 13:24:59 -0400595
Linus Torvalds1da177e2005-04-16 15:20:36 -0700596 /* Flush the Tx and disable Rx here. */
597 outw( SEEQCMD_SET_ALL_OFF, SEEQ_CMD);
598
599 free_irq(dev->irq, dev);
600
601 /* Update the statistics here. */
602
603 return 0;
604
605}
606
Linus Torvalds1da177e2005-04-16 15:20:36 -0700607/* Set or clear the multicast filter for this adaptor.
608 num_addrs == -1 Promiscuous mode, receive all packets
609 num_addrs == 0 Normal mode, clear multicast list
610 num_addrs > 0 Multicast mode, receive normal and MC packets, and do
611 best-effort filtering.
612 */
613static void set_multicast_list(struct net_device *dev)
614{
615/*
616 * I _could_ do up to 6 addresses here, but won't (yet?)
617 */
618
619#if 0
620 int ioaddr = dev->base_addr;
621/*
622 * hmm, not even sure if my matching works _anyway_ - seem to be receiving
623 * _everything_ . . .
624 */
Jeff Garzik6aa20a22006-09-13 13:24:59 -0400625
Linus Torvalds1da177e2005-04-16 15:20:36 -0700626 if (num_addrs) { /* Enable promiscuous mode */
627 outw( (inw(SEEQ_CFG1) & ~SEEQCFG1_MATCH_MASK)| SEEQCFG1_MATCH_ALL, SEEQ_CFG1);
628 dev->flags|=IFF_PROMISC;
629 } else { /* Disable promiscuous mode, use normal mode */
630 outw( (inw(SEEQ_CFG1) & ~SEEQCFG1_MATCH_MASK)| SEEQCFG1_MATCH_BROAD, SEEQ_CFG1);
631 }
632#endif
633}
634
635void seeq8005_init(struct net_device *dev, int startp)
636{
637 struct net_local *lp = netdev_priv(dev);
638 int ioaddr = dev->base_addr;
639 int i;
Jeff Garzik6aa20a22006-09-13 13:24:59 -0400640
Linus Torvalds1da177e2005-04-16 15:20:36 -0700641 outw(SEEQCFG2_RESET, SEEQ_CFG2); /* reset device */
642 udelay(5);
Jeff Garzik6aa20a22006-09-13 13:24:59 -0400643
Linus Torvalds1da177e2005-04-16 15:20:36 -0700644 outw( SEEQCMD_FIFO_WRITE | SEEQCMD_SET_ALL_OFF, SEEQ_CMD);
645 outw( 0, SEEQ_DMAAR); /* load start address into both low and high byte */
646/* wait_for_buffer(dev); */ /* I think that you only need a wait for memory buffer */
647 outw( SEEQCFG1_BUFFER_MAC0, SEEQ_CFG1);
Jeff Garzik6aa20a22006-09-13 13:24:59 -0400648
Linus Torvalds1da177e2005-04-16 15:20:36 -0700649 for(i=0;i<6;i++) { /* set Station address */
650 outb(dev->dev_addr[i], SEEQ_BUFFER);
651 udelay(2);
652 }
Jeff Garzik6aa20a22006-09-13 13:24:59 -0400653
Linus Torvalds1da177e2005-04-16 15:20:36 -0700654 outw( SEEQCFG1_BUFFER_TEA, SEEQ_CFG1); /* set xmit end area pointer to 16K */
655 outb( DEFAULT_TEA, SEEQ_BUFFER); /* this gives us 16K of send buffer and 48K of recv buffer */
Jeff Garzik6aa20a22006-09-13 13:24:59 -0400656
Linus Torvalds1da177e2005-04-16 15:20:36 -0700657 lp->receive_ptr = (DEFAULT_TEA+1)<<8; /* so we can find our packet_header */
658 outw( lp->receive_ptr, SEEQ_RPR); /* Receive Pointer Register is set to recv buffer memory */
Jeff Garzik6aa20a22006-09-13 13:24:59 -0400659
Linus Torvalds1da177e2005-04-16 15:20:36 -0700660 outw( 0x00ff, SEEQ_REA); /* Receive Area End */
661
662 if (net_debug>4) {
663 printk("%s: SA0 = ",dev->name);
664
665 outw( SEEQCMD_FIFO_READ | SEEQCMD_SET_ALL_OFF, SEEQ_CMD);
666 outw( 0, SEEQ_DMAAR);
667 outw( SEEQCFG1_BUFFER_MAC0, SEEQ_CFG1);
Jeff Garzik6aa20a22006-09-13 13:24:59 -0400668
Linus Torvalds1da177e2005-04-16 15:20:36 -0700669 for(i=0;i<6;i++) {
670 printk("%02x ",inb(SEEQ_BUFFER));
671 }
672 printk("\n");
673 }
Jeff Garzik6aa20a22006-09-13 13:24:59 -0400674
Linus Torvalds1da177e2005-04-16 15:20:36 -0700675 outw( SEEQCFG1_MAC0_EN | SEEQCFG1_MATCH_BROAD | SEEQCFG1_BUFFER_BUFFER, SEEQ_CFG1);
676 outw( SEEQCFG2_AUTO_REA | SEEQCFG2_CTRLO, SEEQ_CFG2);
677 outw( SEEQCMD_SET_RX_ON | SEEQCMD_TX_INT_EN | SEEQCMD_RX_INT_EN, SEEQ_CMD);
678
679 if (net_debug>4) {
680 int old_cfg1;
681 old_cfg1 = inw(SEEQ_CFG1);
682 printk("%s: stat = 0x%04x\n",dev->name,inw(SEEQ_STATUS));
683 printk("%s: cfg1 = 0x%04x\n",dev->name,old_cfg1);
684 printk("%s: cfg2 = 0x%04x\n",dev->name,inw(SEEQ_CFG2));
685 printk("%s: raer = 0x%04x\n",dev->name,inw(SEEQ_REA));
686 printk("%s: dmaar= 0x%04x\n",dev->name,inw(SEEQ_DMAAR));
Jeff Garzik6aa20a22006-09-13 13:24:59 -0400687
Linus Torvalds1da177e2005-04-16 15:20:36 -0700688 }
Jeff Garzik6aa20a22006-09-13 13:24:59 -0400689}
Linus Torvalds1da177e2005-04-16 15:20:36 -0700690
691
692static void hardware_send_packet(struct net_device * dev, char *buf, int length)
693{
694 int ioaddr = dev->base_addr;
695 int status = inw(SEEQ_STATUS);
696 int transmit_ptr = 0;
Marcelo Feitoza Parisiff5688a2006-01-09 18:37:15 -0800697 unsigned long tmp;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700698
699 if (net_debug>4) {
700 printk("%s: send 0x%04x\n",dev->name,length);
701 }
Jeff Garzik6aa20a22006-09-13 13:24:59 -0400702
Linus Torvalds1da177e2005-04-16 15:20:36 -0700703 /* Set FIFO to writemode and set packet-buffer address */
704 outw( SEEQCMD_FIFO_WRITE | (status & SEEQCMD_INT_MASK), SEEQ_CMD);
705 outw( transmit_ptr, SEEQ_DMAAR);
Jeff Garzik6aa20a22006-09-13 13:24:59 -0400706
Linus Torvalds1da177e2005-04-16 15:20:36 -0700707 /* output SEEQ Packet header barfage */
708 outw( htons(length + 4), SEEQ_BUFFER);
709 outw( SEEQPKTH_XMIT | SEEQPKTH_DATA_FOLLOWS | SEEQPKTH_XMIT_INT_EN, SEEQ_BUFFER );
Jeff Garzik6aa20a22006-09-13 13:24:59 -0400710
Linus Torvalds1da177e2005-04-16 15:20:36 -0700711 /* blat the buffer */
712 outsw( SEEQ_BUFFER, buf, (length +1) >> 1);
713 /* paranoia !! */
714 outw( 0, SEEQ_BUFFER);
715 outw( 0, SEEQ_BUFFER);
Jeff Garzik6aa20a22006-09-13 13:24:59 -0400716
Linus Torvalds1da177e2005-04-16 15:20:36 -0700717 /* set address of start of transmit chain */
718 outw( transmit_ptr, SEEQ_TPR);
Jeff Garzik6aa20a22006-09-13 13:24:59 -0400719
Linus Torvalds1da177e2005-04-16 15:20:36 -0700720 /* drain FIFO */
721 tmp = jiffies;
Marcelo Feitoza Parisiff5688a2006-01-09 18:37:15 -0800722 while ( (((status=inw(SEEQ_STATUS)) & SEEQSTAT_FIFO_EMPTY) == 0) && time_before(jiffies, tmp + HZ))
Linus Torvalds1da177e2005-04-16 15:20:36 -0700723 mb();
Jeff Garzik6aa20a22006-09-13 13:24:59 -0400724
Linus Torvalds1da177e2005-04-16 15:20:36 -0700725 /* doit ! */
726 outw( SEEQCMD_WINDOW_INT_ACK | SEEQCMD_SET_TX_ON | (status & SEEQCMD_INT_MASK), SEEQ_CMD);
Jeff Garzik6aa20a22006-09-13 13:24:59 -0400727
Linus Torvalds1da177e2005-04-16 15:20:36 -0700728}
729
730
731#ifdef MODULE
732
733static struct net_device *dev_seeq;
734MODULE_LICENSE("GPL");
735module_param(io, int, 0);
736module_param(irq, int, 0);
737MODULE_PARM_DESC(io, "SEEQ 8005 I/O base address");
738MODULE_PARM_DESC(irq, "SEEQ 8005 IRQ number");
739
Andrew Mortonc971ef42006-08-14 23:00:08 -0700740int __init init_module(void)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700741{
742 dev_seeq = seeq8005_probe(-1);
743 if (IS_ERR(dev_seeq))
744 return PTR_ERR(dev_seeq);
745 return 0;
746}
747
Al Viroafc8eb42006-06-14 18:50:53 -0400748void __exit cleanup_module(void)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700749{
750 unregister_netdev(dev_seeq);
751 release_region(dev_seeq->base_addr, SEEQ8005_IO_EXTENT);
752 free_netdev(dev_seeq);
753}
754
755#endif /* MODULE */