blob: 374832cca11fd092a42ee15719a8421f106e4f24 [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>
Linus Torvalds1da177e2005-04-16 15:20:36 -070040#include <linux/string.h>
41#include <linux/init.h>
42#include <linux/delay.h>
43#include <linux/errno.h>
44#include <linux/netdevice.h>
45#include <linux/etherdevice.h>
46#include <linux/skbuff.h>
47#include <linux/bitops.h>
Marcelo Feitoza Parisiff5688a2006-01-09 18:37:15 -080048#include <linux/jiffies.h>
Linus Torvalds1da177e2005-04-16 15:20:36 -070049
50#include <asm/system.h>
51#include <asm/io.h>
52#include <asm/dma.h>
53
54#include "seeq8005.h"
55
56/* First, a few definitions that the brave might change. */
57/* A zero-terminated list of I/O addresses to be probed. */
58static unsigned int seeq8005_portlist[] __initdata =
59 { 0x300, 0x320, 0x340, 0x360, 0};
60
61/* use 0 for production, 1 for verification, >2 for debug */
62#ifndef NET_DEBUG
63#define NET_DEBUG 1
64#endif
65static unsigned int net_debug = NET_DEBUG;
66
67/* Information that need to be kept for each board. */
68struct net_local {
Linus Torvalds1da177e2005-04-16 15:20:36 -070069 unsigned short receive_ptr; /* What address in packet memory do we expect a recv_pkt_header? */
70 long open_time; /* Useless example local info. */
71};
72
73/* The station (ethernet) address prefix, used for IDing the board. */
74#define SA_ADDR0 0x00
75#define SA_ADDR1 0x80
76#define SA_ADDR2 0x4b
77
78/* Index to functions, as function prototypes. */
79
80static int seeq8005_probe1(struct net_device *dev, int ioaddr);
81static int seeq8005_open(struct net_device *dev);
82static void seeq8005_timeout(struct net_device *dev);
Stephen Hemminger613573252009-08-31 19:50:58 +000083static netdev_tx_t seeq8005_send_packet(struct sk_buff *skb,
84 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
Stephen Hemmingerb20417d2009-03-26 15:11:28 +0000146static const struct net_device_ops seeq8005_netdev_ops = {
147 .ndo_open = seeq8005_open,
148 .ndo_stop = seeq8005_close,
149 .ndo_start_xmit = seeq8005_send_packet,
150 .ndo_tx_timeout = seeq8005_timeout,
151 .ndo_set_multicast_list = set_multicast_list,
152 .ndo_change_mtu = eth_change_mtu,
153 .ndo_set_mac_address = eth_mac_addr,
154 .ndo_validate_addr = eth_validate_addr,
155};
156
Linus Torvalds1da177e2005-04-16 15:20:36 -0700157/* This is the real probe routine. Linux has a history of friendly device
158 probes on the ISA bus. A good device probes avoids doing writes, and
159 verifies that the correct device exists and functions. */
160
161static int __init seeq8005_probe1(struct net_device *dev, int ioaddr)
162{
163 static unsigned version_printed;
164 int i,j;
165 unsigned char SA_prom[32];
166 int old_cfg1;
167 int old_cfg2;
168 int old_stat;
169 int old_dmaar;
170 int old_rear;
171 int retval;
172
173 if (!request_region(ioaddr, SEEQ8005_IO_EXTENT, "seeq8005"))
174 return -ENODEV;
175
176 if (net_debug>1)
177 printk("seeq8005: probing at 0x%x\n",ioaddr);
178
179 old_stat = inw(SEEQ_STATUS); /* read status register */
180 if (old_stat == 0xffff) {
181 retval = -ENODEV;
182 goto out; /* assume that 0xffff == no device */
183 }
184 if ( (old_stat & 0x1800) != 0x1800 ) { /* assume that unused bits are 1, as my manual says */
185 if (net_debug>1) {
186 printk("seeq8005: reserved stat bits != 0x1800\n");
187 printk(" == 0x%04x\n",old_stat);
188 }
189 retval = -ENODEV;
190 goto out;
191 }
192
193 old_rear = inw(SEEQ_REA);
194 if (old_rear == 0xffff) {
195 outw(0,SEEQ_REA);
196 if (inw(SEEQ_REA) == 0xffff) { /* assume that 0xffff == no device */
197 retval = -ENODEV;
198 goto out;
199 }
200 } else if ((old_rear & 0xff00) != 0xff00) { /* assume that unused bits are 1 */
201 if (net_debug>1) {
202 printk("seeq8005: unused rear bits != 0xff00\n");
203 printk(" == 0x%04x\n",old_rear);
204 }
205 retval = -ENODEV;
206 goto out;
207 }
Jeff Garzik6aa20a22006-09-13 13:24:59 -0400208
Linus Torvalds1da177e2005-04-16 15:20:36 -0700209 old_cfg2 = inw(SEEQ_CFG2); /* read CFG2 register */
210 old_cfg1 = inw(SEEQ_CFG1);
211 old_dmaar = inw(SEEQ_DMAAR);
Jeff Garzik6aa20a22006-09-13 13:24:59 -0400212
Linus Torvalds1da177e2005-04-16 15:20:36 -0700213 if (net_debug>4) {
214 printk("seeq8005: stat = 0x%04x\n",old_stat);
215 printk("seeq8005: cfg1 = 0x%04x\n",old_cfg1);
216 printk("seeq8005: cfg2 = 0x%04x\n",old_cfg2);
217 printk("seeq8005: raer = 0x%04x\n",old_rear);
218 printk("seeq8005: dmaar= 0x%04x\n",old_dmaar);
219 }
Jeff Garzik6aa20a22006-09-13 13:24:59 -0400220
Linus Torvalds1da177e2005-04-16 15:20:36 -0700221 outw( SEEQCMD_FIFO_WRITE | SEEQCMD_SET_ALL_OFF, SEEQ_CMD); /* setup for reading PROM */
222 outw( 0, SEEQ_DMAAR); /* set starting PROM address */
223 outw( SEEQCFG1_BUFFER_PROM, SEEQ_CFG1); /* set buffer to look at PROM */
224
225
226 j=0;
227 for(i=0; i <32; i++) {
228 j+= SA_prom[i] = inw(SEEQ_BUFFER) & 0xff;
229 }
230
231#if 0
232 /* untested because I only have the one card */
233 if ( (j&0xff) != 0 ) { /* checksum appears to be 8bit = 0 */
234 if (net_debug>1) { /* check this before deciding that we have a card */
235 printk("seeq8005: prom sum error\n");
236 }
237 outw( old_stat, SEEQ_STATUS);
238 outw( old_dmaar, SEEQ_DMAAR);
239 outw( old_cfg1, SEEQ_CFG1);
240 retval = -ENODEV;
241 goto out;
242 }
243#endif
244
245 outw( SEEQCFG2_RESET, SEEQ_CFG2); /* reset the card */
246 udelay(5);
247 outw( SEEQCMD_SET_ALL_OFF, SEEQ_CMD);
Jeff Garzik6aa20a22006-09-13 13:24:59 -0400248
Linus Torvalds1da177e2005-04-16 15:20:36 -0700249 if (net_debug) {
250 printk("seeq8005: prom sum = 0x%08x\n",j);
251 for(j=0; j<32; j+=16) {
252 printk("seeq8005: prom %02x: ",j);
253 for(i=0;i<16;i++) {
254 printk("%02x ",SA_prom[j|i]);
255 }
256 printk(" ");
257 for(i=0;i<16;i++) {
258 if ((SA_prom[j|i]>31)&&(SA_prom[j|i]<127)) {
259 printk("%c", SA_prom[j|i]);
260 } else {
261 printk(" ");
262 }
263 }
264 printk("\n");
265 }
266 }
267
Jeff Garzik6aa20a22006-09-13 13:24:59 -0400268#if 0
269 /*
Linus Torvalds1da177e2005-04-16 15:20:36 -0700270 * testing the packet buffer memory doesn't work yet
Jeff Garzik6aa20a22006-09-13 13:24:59 -0400271 * but all other buffer accesses do
Linus Torvalds1da177e2005-04-16 15:20:36 -0700272 * - fixing is not a priority
273 */
274 if (net_debug>1) { /* test packet buffer memory */
275 printk("seeq8005: testing packet buffer ... ");
276 outw( SEEQCFG1_BUFFER_BUFFER, SEEQ_CFG1);
277 outw( SEEQCMD_FIFO_WRITE | SEEQCMD_SET_ALL_OFF, SEEQ_CMD);
278 outw( 0 , SEEQ_DMAAR);
279 for(i=0;i<32768;i++) {
280 outw(0x5a5a, SEEQ_BUFFER);
281 }
282 j=jiffies+HZ;
283 while ( ((inw(SEEQ_STATUS) & SEEQSTAT_FIFO_EMPTY) != SEEQSTAT_FIFO_EMPTY) && time_before(jiffies, j) )
284 mb();
285 outw( 0 , SEEQ_DMAAR);
286 while ( ((inw(SEEQ_STATUS) & SEEQSTAT_WINDOW_INT) != SEEQSTAT_WINDOW_INT) && time_before(jiffies, j+HZ))
287 mb();
288 if ( (inw(SEEQ_STATUS) & SEEQSTAT_WINDOW_INT) == SEEQSTAT_WINDOW_INT)
289 outw( SEEQCMD_WINDOW_INT_ACK | (inw(SEEQ_STATUS)& SEEQCMD_INT_MASK), SEEQ_CMD);
290 outw( SEEQCMD_FIFO_READ | SEEQCMD_SET_ALL_OFF, SEEQ_CMD);
291 j=0;
292 for(i=0;i<32768;i++) {
293 if (inw(SEEQ_BUFFER) != 0x5a5a)
294 j++;
295 }
296 if (j) {
297 printk("%i\n",j);
298 } else {
299 printk("ok.\n");
300 }
301 }
302#endif
303
304 if (net_debug && version_printed++ == 0)
305 printk(version);
306
307 printk("%s: %s found at %#3x, ", dev->name, "seeq8005", ioaddr);
308
309 /* Fill in the 'dev' fields. */
310 dev->base_addr = ioaddr;
311 dev->irq = irq;
312
313 /* Retrieve and print the ethernet address. */
314 for (i = 0; i < 6; i++)
Joe Perches0795af52007-10-03 17:59:30 -0700315 dev->dev_addr[i] = SA_prom[i+6];
Johannes Berge1749612008-10-27 15:59:26 -0700316 printk("%pM", dev->dev_addr);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700317
318 if (dev->irq == 0xff)
319 ; /* Do nothing: a user-level program will set it. */
320 else if (dev->irq < 2) { /* "Auto-IRQ" */
321 unsigned long cookie = probe_irq_on();
Jeff Garzik6aa20a22006-09-13 13:24:59 -0400322
Linus Torvalds1da177e2005-04-16 15:20:36 -0700323 outw( SEEQCMD_RX_INT_EN | SEEQCMD_SET_RX_ON | SEEQCMD_SET_RX_OFF, SEEQ_CMD );
324
325 dev->irq = probe_irq_off(cookie);
Jeff Garzik6aa20a22006-09-13 13:24:59 -0400326
Linus Torvalds1da177e2005-04-16 15:20:36 -0700327 if (net_debug >= 2)
328 printk(" autoirq is %d\n", dev->irq);
329 } else if (dev->irq == 2)
330 /* Fixup for users that don't know that IRQ 2 is really IRQ 9,
Jeff Garzik6aa20a22006-09-13 13:24:59 -0400331 * or don't know which one to set.
Linus Torvalds1da177e2005-04-16 15:20:36 -0700332 */
333 dev->irq = 9;
334
335#if 0
336 {
Joe Perchesa0607fd2009-11-18 23:29:17 -0800337 int irqval = request_irq(dev->irq, seeq8005_interrupt, 0, "seeq8005", dev);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700338 if (irqval) {
339 printk ("%s: unable to get IRQ %d (irqval=%d).\n", dev->name,
340 dev->irq, irqval);
341 retval = -EAGAIN;
342 goto out;
343 }
344 }
345#endif
Stephen Hemmingerb20417d2009-03-26 15:11:28 +0000346 dev->netdev_ops = &seeq8005_netdev_ops;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700347 dev->watchdog_timeo = HZ/20;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700348 dev->flags &= ~IFF_MULTICAST;
349
350 return 0;
351out:
352 release_region(ioaddr, SEEQ8005_IO_EXTENT);
353 return retval;
354}
355
Jeff Garzik6aa20a22006-09-13 13:24:59 -0400356
Linus Torvalds1da177e2005-04-16 15:20:36 -0700357/* Open/initialize the board. This is called (in the current kernel)
358 sometime after booting when the 'ifconfig' program is run.
359
360 This routine should set everything up anew at each open, even
361 registers that "should" only need to be set once at boot, so that
362 there is non-reboot way to recover if something goes wrong.
363 */
364static int seeq8005_open(struct net_device *dev)
365{
366 struct net_local *lp = netdev_priv(dev);
367
368 {
Joe Perchesa0607fd2009-11-18 23:29:17 -0800369 int irqval = request_irq(dev->irq, seeq8005_interrupt, 0, "seeq8005", dev);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700370 if (irqval) {
371 printk ("%s: unable to get IRQ %d (irqval=%d).\n", dev->name,
372 dev->irq, irqval);
373 return -EAGAIN;
374 }
375 }
376
377 /* Reset the hardware here. Don't forget to set the station address. */
378 seeq8005_init(dev, 1);
379
380 lp->open_time = jiffies;
381
382 netif_start_queue(dev);
383 return 0;
384}
385
386static void seeq8005_timeout(struct net_device *dev)
387{
388 int ioaddr = dev->base_addr;
389 printk(KERN_WARNING "%s: transmit timed out, %s?\n", dev->name,
390 tx_done(dev) ? "IRQ conflict" : "network cable problem");
391 /* Try to restart the adaptor. */
392 seeq8005_init(dev, 1);
393 dev->trans_start = jiffies;
394 netif_wake_queue(dev);
395}
396
Stephen Hemminger613573252009-08-31 19:50:58 +0000397static netdev_tx_t seeq8005_send_packet(struct sk_buff *skb,
398 struct net_device *dev)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700399{
Linus Torvalds1da177e2005-04-16 15:20:36 -0700400 short length = skb->len;
401 unsigned char *buf;
402
403 if (length < ETH_ZLEN) {
Herbert Xu5b057c62006-06-23 02:06:41 -0700404 if (skb_padto(skb, ETH_ZLEN))
Patrick McHardy6ed10652009-06-23 06:03:08 +0000405 return NETDEV_TX_OK;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700406 length = ETH_ZLEN;
407 }
408 buf = skb->data;
409
410 /* Block a timer-based transmit from overlapping */
411 netif_stop_queue(dev);
Jeff Garzik6aa20a22006-09-13 13:24:59 -0400412
413 hardware_send_packet(dev, buf, length);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700414 dev->trans_start = jiffies;
Jeff Garzik09f75cd2007-10-03 17:41:50 -0700415 dev->stats.tx_bytes += length;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700416 dev_kfree_skb (skb);
417 /* You might need to clean up and record Tx statistics here. */
418
Patrick McHardy6ed10652009-06-23 06:03:08 +0000419 return NETDEV_TX_OK;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700420}
Jeff Garzik6aa20a22006-09-13 13:24:59 -0400421
Linus Torvalds1da177e2005-04-16 15:20:36 -0700422/*
423 * wait_for_buffer
424 *
425 * This routine waits for the SEEQ chip to assert that the FIFO is ready
426 * by checking for a window interrupt, and then clearing it. This has to
427 * occur in the interrupt handler!
428 */
429inline void wait_for_buffer(struct net_device * dev)
430{
431 int ioaddr = dev->base_addr;
432 unsigned long tmp;
433 int status;
Jeff Garzik6aa20a22006-09-13 13:24:59 -0400434
Linus Torvalds1da177e2005-04-16 15:20:36 -0700435 tmp = jiffies + HZ;
436 while ( ( ((status=inw(SEEQ_STATUS)) & SEEQSTAT_WINDOW_INT) != SEEQSTAT_WINDOW_INT) && time_before(jiffies, tmp))
437 cpu_relax();
Jeff Garzik6aa20a22006-09-13 13:24:59 -0400438
Linus Torvalds1da177e2005-04-16 15:20:36 -0700439 if ( (status & SEEQSTAT_WINDOW_INT) == SEEQSTAT_WINDOW_INT)
440 outw( SEEQCMD_WINDOW_INT_ACK | (status & SEEQCMD_INT_MASK), SEEQ_CMD);
441}
Jeff Garzik6aa20a22006-09-13 13:24:59 -0400442
Linus Torvalds1da177e2005-04-16 15:20:36 -0700443/* The typical workload of the driver:
444 Handle the network interface interrupts. */
David Howells7d12e782006-10-05 14:55:46 +0100445static irqreturn_t seeq8005_interrupt(int irq, void *dev_id)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700446{
447 struct net_device *dev = dev_id;
448 struct net_local *lp;
449 int ioaddr, status, boguscount = 0;
450 int handled = 0;
451
452 ioaddr = dev->base_addr;
453 lp = netdev_priv(dev);
454
455 status = inw(SEEQ_STATUS);
456 do {
457 if (net_debug >2) {
458 printk("%s: int, status=0x%04x\n",dev->name,status);
459 }
Jeff Garzik6aa20a22006-09-13 13:24:59 -0400460
Linus Torvalds1da177e2005-04-16 15:20:36 -0700461 if (status & SEEQSTAT_WINDOW_INT) {
462 handled = 1;
463 outw( SEEQCMD_WINDOW_INT_ACK | (status & SEEQCMD_INT_MASK), SEEQ_CMD);
464 if (net_debug) {
465 printk("%s: window int!\n",dev->name);
466 }
467 }
468 if (status & SEEQSTAT_TX_INT) {
469 handled = 1;
470 outw( SEEQCMD_TX_INT_ACK | (status & SEEQCMD_INT_MASK), SEEQ_CMD);
Jeff Garzik09f75cd2007-10-03 17:41:50 -0700471 dev->stats.tx_packets++;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700472 netif_wake_queue(dev); /* Inform upper layers. */
473 }
474 if (status & SEEQSTAT_RX_INT) {
475 handled = 1;
476 /* Got a packet(s). */
477 seeq8005_rx(dev);
478 }
479 status = inw(SEEQ_STATUS);
480 } while ( (++boguscount < 10) && (status & SEEQSTAT_ANY_INT)) ;
481
482 if(net_debug>2) {
483 printk("%s: eoi\n",dev->name);
484 }
485 return IRQ_RETVAL(handled);
486}
487
488/* We have a good packet(s), get it/them out of the buffers. */
489static void seeq8005_rx(struct net_device *dev)
490{
491 struct net_local *lp = netdev_priv(dev);
492 int boguscount = 10;
493 int pkt_hdr;
494 int ioaddr = dev->base_addr;
495
496 do {
497 int next_packet;
498 int pkt_len;
499 int i;
500 int status;
501
502 status = inw(SEEQ_STATUS);
503 outw( lp->receive_ptr, SEEQ_DMAAR);
504 outw(SEEQCMD_FIFO_READ | SEEQCMD_RX_INT_ACK | (status & SEEQCMD_INT_MASK), SEEQ_CMD);
505 wait_for_buffer(dev);
506 next_packet = ntohs(inw(SEEQ_BUFFER));
507 pkt_hdr = inw(SEEQ_BUFFER);
Jeff Garzik6aa20a22006-09-13 13:24:59 -0400508
Linus Torvalds1da177e2005-04-16 15:20:36 -0700509 if (net_debug>2) {
510 printk("%s: 0x%04x recv next=0x%04x, hdr=0x%04x\n",dev->name,lp->receive_ptr,next_packet,pkt_hdr);
511 }
Jeff Garzik6aa20a22006-09-13 13:24:59 -0400512
Linus Torvalds1da177e2005-04-16 15:20:36 -0700513 if ((next_packet == 0) || ((pkt_hdr & SEEQPKTH_CHAIN)==0)) { /* Read all the frames? */
514 return; /* Done for now */
515 }
Jeff Garzik6aa20a22006-09-13 13:24:59 -0400516
Linus Torvalds1da177e2005-04-16 15:20:36 -0700517 if ((pkt_hdr & SEEQPKTS_DONE)==0)
518 break;
Jeff Garzik6aa20a22006-09-13 13:24:59 -0400519
Linus Torvalds1da177e2005-04-16 15:20:36 -0700520 if (next_packet < lp->receive_ptr) {
521 pkt_len = (next_packet + 0x10000 - ((DEFAULT_TEA+1)<<8)) - lp->receive_ptr - 4;
522 } else {
523 pkt_len = next_packet - lp->receive_ptr - 4;
524 }
Jeff Garzik6aa20a22006-09-13 13:24:59 -0400525
Linus Torvalds1da177e2005-04-16 15:20:36 -0700526 if (next_packet < ((DEFAULT_TEA+1)<<8)) { /* is the next_packet address sane? */
527 printk("%s: recv packet ring corrupt, resetting board\n",dev->name);
528 seeq8005_init(dev,1);
529 return;
530 }
Jeff Garzik6aa20a22006-09-13 13:24:59 -0400531
Linus Torvalds1da177e2005-04-16 15:20:36 -0700532 lp->receive_ptr = next_packet;
Jeff Garzik6aa20a22006-09-13 13:24:59 -0400533
Linus Torvalds1da177e2005-04-16 15:20:36 -0700534 if (net_debug>2) {
535 printk("%s: recv len=0x%04x\n",dev->name,pkt_len);
536 }
537
538 if (pkt_hdr & SEEQPKTS_ANY_ERROR) { /* There was an error. */
Jeff Garzik09f75cd2007-10-03 17:41:50 -0700539 dev->stats.rx_errors++;
540 if (pkt_hdr & SEEQPKTS_SHORT) dev->stats.rx_frame_errors++;
541 if (pkt_hdr & SEEQPKTS_DRIB) dev->stats.rx_frame_errors++;
542 if (pkt_hdr & SEEQPKTS_OVERSIZE) dev->stats.rx_over_errors++;
543 if (pkt_hdr & SEEQPKTS_CRC_ERR) dev->stats.rx_crc_errors++;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700544 /* skip over this packet */
545 outw( SEEQCMD_FIFO_WRITE | SEEQCMD_DMA_INT_ACK | (status & SEEQCMD_INT_MASK), SEEQ_CMD);
546 outw( (lp->receive_ptr & 0xff00)>>8, SEEQ_REA);
547 } else {
548 /* Malloc up new buffer. */
549 struct sk_buff *skb;
550 unsigned char *buf;
551
552 skb = dev_alloc_skb(pkt_len);
553 if (skb == NULL) {
554 printk("%s: Memory squeeze, dropping packet.\n", dev->name);
Jeff Garzik09f75cd2007-10-03 17:41:50 -0700555 dev->stats.rx_dropped++;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700556 break;
557 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700558 skb_reserve(skb, 2); /* align data on 16 byte */
559 buf = skb_put(skb,pkt_len);
Jeff Garzik6aa20a22006-09-13 13:24:59 -0400560
Linus Torvalds1da177e2005-04-16 15:20:36 -0700561 insw(SEEQ_BUFFER, buf, (pkt_len + 1) >> 1);
Jeff Garzik6aa20a22006-09-13 13:24:59 -0400562
Linus Torvalds1da177e2005-04-16 15:20:36 -0700563 if (net_debug>2) {
564 char * p = buf;
565 printk("%s: recv ",dev->name);
566 for(i=0;i<14;i++) {
567 printk("%02x ",*(p++)&0xff);
568 }
569 printk("\n");
570 }
571
572 skb->protocol=eth_type_trans(skb,dev);
573 netif_rx(skb);
Jeff Garzik09f75cd2007-10-03 17:41:50 -0700574 dev->stats.rx_packets++;
575 dev->stats.rx_bytes += pkt_len;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700576 }
577 } while ((--boguscount) && (pkt_hdr & SEEQPKTH_CHAIN));
578
579 /* If any worth-while packets have been received, netif_rx()
580 has done a mark_bh(NET_BH) for us and will work on them
581 when we get to the bottom-half routine. */
582 return;
583}
584
585/* The inverse routine to net_open(). */
586static int seeq8005_close(struct net_device *dev)
587{
588 struct net_local *lp = netdev_priv(dev);
589 int ioaddr = dev->base_addr;
590
591 lp->open_time = 0;
592
593 netif_stop_queue(dev);
Jeff Garzik6aa20a22006-09-13 13:24:59 -0400594
Linus Torvalds1da177e2005-04-16 15:20:36 -0700595 /* Flush the Tx and disable Rx here. */
596 outw( SEEQCMD_SET_ALL_OFF, SEEQ_CMD);
597
598 free_irq(dev->irq, dev);
599
600 /* Update the statistics here. */
601
602 return 0;
603
604}
605
Linus Torvalds1da177e2005-04-16 15:20:36 -0700606/* Set or clear the multicast filter for this adaptor.
607 num_addrs == -1 Promiscuous mode, receive all packets
608 num_addrs == 0 Normal mode, clear multicast list
609 num_addrs > 0 Multicast mode, receive normal and MC packets, and do
610 best-effort filtering.
611 */
612static void set_multicast_list(struct net_device *dev)
613{
614/*
615 * I _could_ do up to 6 addresses here, but won't (yet?)
616 */
617
618#if 0
619 int ioaddr = dev->base_addr;
620/*
621 * hmm, not even sure if my matching works _anyway_ - seem to be receiving
622 * _everything_ . . .
623 */
Jeff Garzik6aa20a22006-09-13 13:24:59 -0400624
Linus Torvalds1da177e2005-04-16 15:20:36 -0700625 if (num_addrs) { /* Enable promiscuous mode */
626 outw( (inw(SEEQ_CFG1) & ~SEEQCFG1_MATCH_MASK)| SEEQCFG1_MATCH_ALL, SEEQ_CFG1);
627 dev->flags|=IFF_PROMISC;
628 } else { /* Disable promiscuous mode, use normal mode */
629 outw( (inw(SEEQ_CFG1) & ~SEEQCFG1_MATCH_MASK)| SEEQCFG1_MATCH_BROAD, SEEQ_CFG1);
630 }
631#endif
632}
633
634void seeq8005_init(struct net_device *dev, int startp)
635{
636 struct net_local *lp = netdev_priv(dev);
637 int ioaddr = dev->base_addr;
638 int i;
Jeff Garzik6aa20a22006-09-13 13:24:59 -0400639
Linus Torvalds1da177e2005-04-16 15:20:36 -0700640 outw(SEEQCFG2_RESET, SEEQ_CFG2); /* reset device */
641 udelay(5);
Jeff Garzik6aa20a22006-09-13 13:24:59 -0400642
Linus Torvalds1da177e2005-04-16 15:20:36 -0700643 outw( SEEQCMD_FIFO_WRITE | SEEQCMD_SET_ALL_OFF, SEEQ_CMD);
644 outw( 0, SEEQ_DMAAR); /* load start address into both low and high byte */
645/* wait_for_buffer(dev); */ /* I think that you only need a wait for memory buffer */
646 outw( SEEQCFG1_BUFFER_MAC0, SEEQ_CFG1);
Jeff Garzik6aa20a22006-09-13 13:24:59 -0400647
Linus Torvalds1da177e2005-04-16 15:20:36 -0700648 for(i=0;i<6;i++) { /* set Station address */
649 outb(dev->dev_addr[i], SEEQ_BUFFER);
650 udelay(2);
651 }
Jeff Garzik6aa20a22006-09-13 13:24:59 -0400652
Linus Torvalds1da177e2005-04-16 15:20:36 -0700653 outw( SEEQCFG1_BUFFER_TEA, SEEQ_CFG1); /* set xmit end area pointer to 16K */
654 outb( DEFAULT_TEA, SEEQ_BUFFER); /* this gives us 16K of send buffer and 48K of recv buffer */
Jeff Garzik6aa20a22006-09-13 13:24:59 -0400655
Linus Torvalds1da177e2005-04-16 15:20:36 -0700656 lp->receive_ptr = (DEFAULT_TEA+1)<<8; /* so we can find our packet_header */
657 outw( lp->receive_ptr, SEEQ_RPR); /* Receive Pointer Register is set to recv buffer memory */
Jeff Garzik6aa20a22006-09-13 13:24:59 -0400658
Linus Torvalds1da177e2005-04-16 15:20:36 -0700659 outw( 0x00ff, SEEQ_REA); /* Receive Area End */
660
661 if (net_debug>4) {
662 printk("%s: SA0 = ",dev->name);
663
664 outw( SEEQCMD_FIFO_READ | SEEQCMD_SET_ALL_OFF, SEEQ_CMD);
665 outw( 0, SEEQ_DMAAR);
666 outw( SEEQCFG1_BUFFER_MAC0, SEEQ_CFG1);
Jeff Garzik6aa20a22006-09-13 13:24:59 -0400667
Linus Torvalds1da177e2005-04-16 15:20:36 -0700668 for(i=0;i<6;i++) {
669 printk("%02x ",inb(SEEQ_BUFFER));
670 }
671 printk("\n");
672 }
Jeff Garzik6aa20a22006-09-13 13:24:59 -0400673
Linus Torvalds1da177e2005-04-16 15:20:36 -0700674 outw( SEEQCFG1_MAC0_EN | SEEQCFG1_MATCH_BROAD | SEEQCFG1_BUFFER_BUFFER, SEEQ_CFG1);
675 outw( SEEQCFG2_AUTO_REA | SEEQCFG2_CTRLO, SEEQ_CFG2);
676 outw( SEEQCMD_SET_RX_ON | SEEQCMD_TX_INT_EN | SEEQCMD_RX_INT_EN, SEEQ_CMD);
677
678 if (net_debug>4) {
679 int old_cfg1;
680 old_cfg1 = inw(SEEQ_CFG1);
681 printk("%s: stat = 0x%04x\n",dev->name,inw(SEEQ_STATUS));
682 printk("%s: cfg1 = 0x%04x\n",dev->name,old_cfg1);
683 printk("%s: cfg2 = 0x%04x\n",dev->name,inw(SEEQ_CFG2));
684 printk("%s: raer = 0x%04x\n",dev->name,inw(SEEQ_REA));
685 printk("%s: dmaar= 0x%04x\n",dev->name,inw(SEEQ_DMAAR));
Jeff Garzik6aa20a22006-09-13 13:24:59 -0400686
Linus Torvalds1da177e2005-04-16 15:20:36 -0700687 }
Jeff Garzik6aa20a22006-09-13 13:24:59 -0400688}
Linus Torvalds1da177e2005-04-16 15:20:36 -0700689
690
691static void hardware_send_packet(struct net_device * dev, char *buf, int length)
692{
693 int ioaddr = dev->base_addr;
694 int status = inw(SEEQ_STATUS);
695 int transmit_ptr = 0;
Marcelo Feitoza Parisiff5688a2006-01-09 18:37:15 -0800696 unsigned long tmp;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700697
698 if (net_debug>4) {
699 printk("%s: send 0x%04x\n",dev->name,length);
700 }
Jeff Garzik6aa20a22006-09-13 13:24:59 -0400701
Linus Torvalds1da177e2005-04-16 15:20:36 -0700702 /* Set FIFO to writemode and set packet-buffer address */
703 outw( SEEQCMD_FIFO_WRITE | (status & SEEQCMD_INT_MASK), SEEQ_CMD);
704 outw( transmit_ptr, SEEQ_DMAAR);
Jeff Garzik6aa20a22006-09-13 13:24:59 -0400705
Linus Torvalds1da177e2005-04-16 15:20:36 -0700706 /* output SEEQ Packet header barfage */
707 outw( htons(length + 4), SEEQ_BUFFER);
708 outw( SEEQPKTH_XMIT | SEEQPKTH_DATA_FOLLOWS | SEEQPKTH_XMIT_INT_EN, SEEQ_BUFFER );
Jeff Garzik6aa20a22006-09-13 13:24:59 -0400709
Linus Torvalds1da177e2005-04-16 15:20:36 -0700710 /* blat the buffer */
711 outsw( SEEQ_BUFFER, buf, (length +1) >> 1);
712 /* paranoia !! */
713 outw( 0, SEEQ_BUFFER);
714 outw( 0, SEEQ_BUFFER);
Jeff Garzik6aa20a22006-09-13 13:24:59 -0400715
Linus Torvalds1da177e2005-04-16 15:20:36 -0700716 /* set address of start of transmit chain */
717 outw( transmit_ptr, SEEQ_TPR);
Jeff Garzik6aa20a22006-09-13 13:24:59 -0400718
Linus Torvalds1da177e2005-04-16 15:20:36 -0700719 /* drain FIFO */
720 tmp = jiffies;
Marcelo Feitoza Parisiff5688a2006-01-09 18:37:15 -0800721 while ( (((status=inw(SEEQ_STATUS)) & SEEQSTAT_FIFO_EMPTY) == 0) && time_before(jiffies, tmp + HZ))
Linus Torvalds1da177e2005-04-16 15:20:36 -0700722 mb();
Jeff Garzik6aa20a22006-09-13 13:24:59 -0400723
Linus Torvalds1da177e2005-04-16 15:20:36 -0700724 /* doit ! */
725 outw( SEEQCMD_WINDOW_INT_ACK | SEEQCMD_SET_TX_ON | (status & SEEQCMD_INT_MASK), SEEQ_CMD);
Jeff Garzik6aa20a22006-09-13 13:24:59 -0400726
Linus Torvalds1da177e2005-04-16 15:20:36 -0700727}
728
729
730#ifdef MODULE
731
732static struct net_device *dev_seeq;
733MODULE_LICENSE("GPL");
734module_param(io, int, 0);
735module_param(irq, int, 0);
736MODULE_PARM_DESC(io, "SEEQ 8005 I/O base address");
737MODULE_PARM_DESC(irq, "SEEQ 8005 IRQ number");
738
Andrew Mortonc971ef42006-08-14 23:00:08 -0700739int __init init_module(void)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700740{
741 dev_seeq = seeq8005_probe(-1);
742 if (IS_ERR(dev_seeq))
743 return PTR_ERR(dev_seeq);
744 return 0;
745}
746
Al Viroafc8eb42006-06-14 18:50:53 -0400747void __exit cleanup_module(void)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700748{
749 unregister_netdev(dev_seeq);
750 release_region(dev_seeq->base_addr, SEEQ8005_IO_EXTENT);
751 free_netdev(dev_seeq);
752}
753
754#endif /* MODULE */