blob: d6e50de711861fb7357f1b29df8ce99a55d72fdb [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
Linus Torvalds1da177e2005-04-16 15:20:36 -070050#include <asm/io.h>
51#include <asm/dma.h>
52
53#include "seeq8005.h"
54
55/* First, a few definitions that the brave might change. */
56/* A zero-terminated list of I/O addresses to be probed. */
57static unsigned int seeq8005_portlist[] __initdata =
58 { 0x300, 0x320, 0x340, 0x360, 0};
59
60/* use 0 for production, 1 for verification, >2 for debug */
61#ifndef NET_DEBUG
62#define NET_DEBUG 1
63#endif
64static unsigned int net_debug = NET_DEBUG;
65
66/* Information that need to be kept for each board. */
67struct net_local {
Linus Torvalds1da177e2005-04-16 15:20:36 -070068 unsigned short receive_ptr; /* What address in packet memory do we expect a recv_pkt_header? */
69 long open_time; /* Useless example local info. */
70};
71
72/* The station (ethernet) address prefix, used for IDing the board. */
73#define SA_ADDR0 0x00
74#define SA_ADDR1 0x80
75#define SA_ADDR2 0x4b
76
77/* Index to functions, as function prototypes. */
78
79static int seeq8005_probe1(struct net_device *dev, int ioaddr);
80static int seeq8005_open(struct net_device *dev);
81static void seeq8005_timeout(struct net_device *dev);
Stephen Hemminger613573252009-08-31 19:50:58 +000082static netdev_tx_t seeq8005_send_packet(struct sk_buff *skb,
83 struct net_device *dev);
David Howells7d12e782006-10-05 14:55:46 +010084static irqreturn_t seeq8005_interrupt(int irq, void *dev_id);
Linus Torvalds1da177e2005-04-16 15:20:36 -070085static void seeq8005_rx(struct net_device *dev);
86static int seeq8005_close(struct net_device *dev);
Linus Torvalds1da177e2005-04-16 15:20:36 -070087static void set_multicast_list(struct net_device *dev);
88
89/* Example routines you must write ;->. */
90#define tx_done(dev) (inw(SEEQ_STATUS) & SEEQSTAT_TX_ON)
91static void hardware_send_packet(struct net_device *dev, char *buf, int length);
92extern void seeq8005_init(struct net_device *dev, int startp);
93static inline void wait_for_buffer(struct net_device *dev);
94
Jeff Garzik6aa20a22006-09-13 13:24:59 -040095
Linus Torvalds1da177e2005-04-16 15:20:36 -070096/* Check for a network adaptor of this type, and return '0' iff one exists.
97 If dev->base_addr == 0, probe all likely locations.
98 If dev->base_addr == 1, always return failure.
99 */
100
101static int io = 0x320;
102static int irq = 10;
103
104struct net_device * __init seeq8005_probe(int unit)
105{
106 struct net_device *dev = alloc_etherdev(sizeof(struct net_local));
107 unsigned *port;
108 int err = 0;
109
110 if (!dev)
111 return ERR_PTR(-ENODEV);
112
113 if (unit >= 0) {
114 sprintf(dev->name, "eth%d", unit);
115 netdev_boot_setup_check(dev);
116 io = dev->base_addr;
117 irq = dev->irq;
118 }
119
120 if (io > 0x1ff) { /* Check a single specified location. */
121 err = seeq8005_probe1(dev, io);
122 } else if (io != 0) { /* Don't probe at all. */
123 err = -ENXIO;
124 } else {
125 for (port = seeq8005_portlist; *port; port++) {
126 if (seeq8005_probe1(dev, *port) == 0)
127 break;
128 }
129 if (!*port)
130 err = -ENODEV;
131 }
132 if (err)
133 goto out;
134 err = register_netdev(dev);
135 if (err)
136 goto out1;
137 return dev;
138out1:
139 release_region(dev->base_addr, SEEQ8005_IO_EXTENT);
140out:
141 free_netdev(dev);
142 return ERR_PTR(err);
143}
144
Stephen Hemmingerb20417d2009-03-26 15:11:28 +0000145static const struct net_device_ops seeq8005_netdev_ops = {
146 .ndo_open = seeq8005_open,
147 .ndo_stop = seeq8005_close,
148 .ndo_start_xmit = seeq8005_send_packet,
149 .ndo_tx_timeout = seeq8005_timeout,
Jiri Pirkoafc4b132011-08-16 06:29:01 +0000150 .ndo_set_rx_mode = set_multicast_list,
Stephen Hemmingerb20417d2009-03-26 15:11:28 +0000151 .ndo_change_mtu = eth_change_mtu,
152 .ndo_set_mac_address = eth_mac_addr,
153 .ndo_validate_addr = eth_validate_addr,
154};
155
Linus Torvalds1da177e2005-04-16 15:20:36 -0700156/* This is the real probe routine. Linux has a history of friendly device
157 probes on the ISA bus. A good device probes avoids doing writes, and
158 verifies that the correct device exists and functions. */
159
160static int __init seeq8005_probe1(struct net_device *dev, int ioaddr)
161{
162 static unsigned version_printed;
163 int i,j;
164 unsigned char SA_prom[32];
165 int old_cfg1;
166 int old_cfg2;
167 int old_stat;
168 int old_dmaar;
169 int old_rear;
170 int retval;
171
172 if (!request_region(ioaddr, SEEQ8005_IO_EXTENT, "seeq8005"))
173 return -ENODEV;
174
175 if (net_debug>1)
176 printk("seeq8005: probing at 0x%x\n",ioaddr);
177
178 old_stat = inw(SEEQ_STATUS); /* read status register */
179 if (old_stat == 0xffff) {
180 retval = -ENODEV;
181 goto out; /* assume that 0xffff == no device */
182 }
183 if ( (old_stat & 0x1800) != 0x1800 ) { /* assume that unused bits are 1, as my manual says */
184 if (net_debug>1) {
185 printk("seeq8005: reserved stat bits != 0x1800\n");
186 printk(" == 0x%04x\n",old_stat);
187 }
188 retval = -ENODEV;
189 goto out;
190 }
191
192 old_rear = inw(SEEQ_REA);
193 if (old_rear == 0xffff) {
194 outw(0,SEEQ_REA);
195 if (inw(SEEQ_REA) == 0xffff) { /* assume that 0xffff == no device */
196 retval = -ENODEV;
197 goto out;
198 }
199 } else if ((old_rear & 0xff00) != 0xff00) { /* assume that unused bits are 1 */
200 if (net_debug>1) {
201 printk("seeq8005: unused rear bits != 0xff00\n");
202 printk(" == 0x%04x\n",old_rear);
203 }
204 retval = -ENODEV;
205 goto out;
206 }
Jeff Garzik6aa20a22006-09-13 13:24:59 -0400207
Linus Torvalds1da177e2005-04-16 15:20:36 -0700208 old_cfg2 = inw(SEEQ_CFG2); /* read CFG2 register */
209 old_cfg1 = inw(SEEQ_CFG1);
210 old_dmaar = inw(SEEQ_DMAAR);
Jeff Garzik6aa20a22006-09-13 13:24:59 -0400211
Linus Torvalds1da177e2005-04-16 15:20:36 -0700212 if (net_debug>4) {
213 printk("seeq8005: stat = 0x%04x\n",old_stat);
214 printk("seeq8005: cfg1 = 0x%04x\n",old_cfg1);
215 printk("seeq8005: cfg2 = 0x%04x\n",old_cfg2);
216 printk("seeq8005: raer = 0x%04x\n",old_rear);
217 printk("seeq8005: dmaar= 0x%04x\n",old_dmaar);
218 }
Jeff Garzik6aa20a22006-09-13 13:24:59 -0400219
Linus Torvalds1da177e2005-04-16 15:20:36 -0700220 outw( SEEQCMD_FIFO_WRITE | SEEQCMD_SET_ALL_OFF, SEEQ_CMD); /* setup for reading PROM */
221 outw( 0, SEEQ_DMAAR); /* set starting PROM address */
222 outw( SEEQCFG1_BUFFER_PROM, SEEQ_CFG1); /* set buffer to look at PROM */
223
224
225 j=0;
226 for(i=0; i <32; i++) {
227 j+= SA_prom[i] = inw(SEEQ_BUFFER) & 0xff;
228 }
229
230#if 0
231 /* untested because I only have the one card */
232 if ( (j&0xff) != 0 ) { /* checksum appears to be 8bit = 0 */
233 if (net_debug>1) { /* check this before deciding that we have a card */
234 printk("seeq8005: prom sum error\n");
235 }
236 outw( old_stat, SEEQ_STATUS);
237 outw( old_dmaar, SEEQ_DMAAR);
238 outw( old_cfg1, SEEQ_CFG1);
239 retval = -ENODEV;
240 goto out;
241 }
242#endif
243
244 outw( SEEQCFG2_RESET, SEEQ_CFG2); /* reset the card */
245 udelay(5);
246 outw( SEEQCMD_SET_ALL_OFF, SEEQ_CMD);
Jeff Garzik6aa20a22006-09-13 13:24:59 -0400247
Linus Torvalds1da177e2005-04-16 15:20:36 -0700248 if (net_debug) {
249 printk("seeq8005: prom sum = 0x%08x\n",j);
250 for(j=0; j<32; j+=16) {
251 printk("seeq8005: prom %02x: ",j);
252 for(i=0;i<16;i++) {
253 printk("%02x ",SA_prom[j|i]);
254 }
255 printk(" ");
256 for(i=0;i<16;i++) {
257 if ((SA_prom[j|i]>31)&&(SA_prom[j|i]<127)) {
258 printk("%c", SA_prom[j|i]);
259 } else {
260 printk(" ");
261 }
262 }
263 printk("\n");
264 }
265 }
266
Jeff Garzik6aa20a22006-09-13 13:24:59 -0400267#if 0
268 /*
Linus Torvalds1da177e2005-04-16 15:20:36 -0700269 * testing the packet buffer memory doesn't work yet
Jeff Garzik6aa20a22006-09-13 13:24:59 -0400270 * but all other buffer accesses do
Linus Torvalds1da177e2005-04-16 15:20:36 -0700271 * - fixing is not a priority
272 */
273 if (net_debug>1) { /* test packet buffer memory */
274 printk("seeq8005: testing packet buffer ... ");
275 outw( SEEQCFG1_BUFFER_BUFFER, SEEQ_CFG1);
276 outw( SEEQCMD_FIFO_WRITE | SEEQCMD_SET_ALL_OFF, SEEQ_CMD);
277 outw( 0 , SEEQ_DMAAR);
278 for(i=0;i<32768;i++) {
279 outw(0x5a5a, SEEQ_BUFFER);
280 }
281 j=jiffies+HZ;
282 while ( ((inw(SEEQ_STATUS) & SEEQSTAT_FIFO_EMPTY) != SEEQSTAT_FIFO_EMPTY) && time_before(jiffies, j) )
283 mb();
284 outw( 0 , SEEQ_DMAAR);
285 while ( ((inw(SEEQ_STATUS) & SEEQSTAT_WINDOW_INT) != SEEQSTAT_WINDOW_INT) && time_before(jiffies, j+HZ))
286 mb();
287 if ( (inw(SEEQ_STATUS) & SEEQSTAT_WINDOW_INT) == SEEQSTAT_WINDOW_INT)
288 outw( SEEQCMD_WINDOW_INT_ACK | (inw(SEEQ_STATUS)& SEEQCMD_INT_MASK), SEEQ_CMD);
289 outw( SEEQCMD_FIFO_READ | SEEQCMD_SET_ALL_OFF, SEEQ_CMD);
290 j=0;
291 for(i=0;i<32768;i++) {
292 if (inw(SEEQ_BUFFER) != 0x5a5a)
293 j++;
294 }
295 if (j) {
296 printk("%i\n",j);
297 } else {
298 printk("ok.\n");
299 }
300 }
301#endif
302
303 if (net_debug && version_printed++ == 0)
304 printk(version);
305
306 printk("%s: %s found at %#3x, ", dev->name, "seeq8005", ioaddr);
307
308 /* Fill in the 'dev' fields. */
309 dev->base_addr = ioaddr;
310 dev->irq = irq;
311
312 /* Retrieve and print the ethernet address. */
313 for (i = 0; i < 6; i++)
Joe Perches0795af52007-10-03 17:59:30 -0700314 dev->dev_addr[i] = SA_prom[i+6];
Johannes Berge1749612008-10-27 15:59:26 -0700315 printk("%pM", dev->dev_addr);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700316
317 if (dev->irq == 0xff)
318 ; /* Do nothing: a user-level program will set it. */
319 else if (dev->irq < 2) { /* "Auto-IRQ" */
320 unsigned long cookie = probe_irq_on();
Jeff Garzik6aa20a22006-09-13 13:24:59 -0400321
Linus Torvalds1da177e2005-04-16 15:20:36 -0700322 outw( SEEQCMD_RX_INT_EN | SEEQCMD_SET_RX_ON | SEEQCMD_SET_RX_OFF, SEEQ_CMD );
323
324 dev->irq = probe_irq_off(cookie);
Jeff Garzik6aa20a22006-09-13 13:24:59 -0400325
Linus Torvalds1da177e2005-04-16 15:20:36 -0700326 if (net_debug >= 2)
327 printk(" autoirq is %d\n", dev->irq);
328 } else if (dev->irq == 2)
329 /* Fixup for users that don't know that IRQ 2 is really IRQ 9,
Jeff Garzik6aa20a22006-09-13 13:24:59 -0400330 * or don't know which one to set.
Linus Torvalds1da177e2005-04-16 15:20:36 -0700331 */
332 dev->irq = 9;
333
334#if 0
335 {
Joe Perchesa0607fd2009-11-18 23:29:17 -0800336 int irqval = request_irq(dev->irq, seeq8005_interrupt, 0, "seeq8005", dev);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700337 if (irqval) {
338 printk ("%s: unable to get IRQ %d (irqval=%d).\n", dev->name,
339 dev->irq, irqval);
340 retval = -EAGAIN;
341 goto out;
342 }
343 }
344#endif
Stephen Hemmingerb20417d2009-03-26 15:11:28 +0000345 dev->netdev_ops = &seeq8005_netdev_ops;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700346 dev->watchdog_timeo = HZ/20;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700347 dev->flags &= ~IFF_MULTICAST;
348
349 return 0;
350out:
351 release_region(ioaddr, SEEQ8005_IO_EXTENT);
352 return retval;
353}
354
Jeff Garzik6aa20a22006-09-13 13:24:59 -0400355
Linus Torvalds1da177e2005-04-16 15:20:36 -0700356/* Open/initialize the board. This is called (in the current kernel)
357 sometime after booting when the 'ifconfig' program is run.
358
359 This routine should set everything up anew at each open, even
360 registers that "should" only need to be set once at boot, so that
361 there is non-reboot way to recover if something goes wrong.
362 */
363static int seeq8005_open(struct net_device *dev)
364{
365 struct net_local *lp = netdev_priv(dev);
366
367 {
Joe Perchesa0607fd2009-11-18 23:29:17 -0800368 int irqval = request_irq(dev->irq, seeq8005_interrupt, 0, "seeq8005", dev);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700369 if (irqval) {
370 printk ("%s: unable to get IRQ %d (irqval=%d).\n", dev->name,
371 dev->irq, irqval);
372 return -EAGAIN;
373 }
374 }
375
376 /* Reset the hardware here. Don't forget to set the station address. */
377 seeq8005_init(dev, 1);
378
379 lp->open_time = jiffies;
380
381 netif_start_queue(dev);
382 return 0;
383}
384
385static void seeq8005_timeout(struct net_device *dev)
386{
387 int ioaddr = dev->base_addr;
388 printk(KERN_WARNING "%s: transmit timed out, %s?\n", dev->name,
389 tx_done(dev) ? "IRQ conflict" : "network cable problem");
390 /* Try to restart the adaptor. */
391 seeq8005_init(dev, 1);
Eric Dumazet1ae5dc32010-05-10 05:01:31 -0700392 dev->trans_start = jiffies; /* prevent tx timeout */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700393 netif_wake_queue(dev);
394}
395
Stephen Hemminger613573252009-08-31 19:50:58 +0000396static netdev_tx_t seeq8005_send_packet(struct sk_buff *skb,
397 struct net_device *dev)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700398{
Linus Torvalds1da177e2005-04-16 15:20:36 -0700399 short length = skb->len;
400 unsigned char *buf;
401
402 if (length < ETH_ZLEN) {
Herbert Xu5b057c62006-06-23 02:06:41 -0700403 if (skb_padto(skb, ETH_ZLEN))
Patrick McHardy6ed10652009-06-23 06:03:08 +0000404 return NETDEV_TX_OK;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700405 length = ETH_ZLEN;
406 }
407 buf = skb->data;
408
409 /* Block a timer-based transmit from overlapping */
410 netif_stop_queue(dev);
Jeff Garzik6aa20a22006-09-13 13:24:59 -0400411
412 hardware_send_packet(dev, buf, length);
Jeff Garzik09f75cd2007-10-03 17:41:50 -0700413 dev->stats.tx_bytes += length;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700414 dev_kfree_skb (skb);
415 /* You might need to clean up and record Tx statistics here. */
416
Patrick McHardy6ed10652009-06-23 06:03:08 +0000417 return NETDEV_TX_OK;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700418}
Jeff Garzik6aa20a22006-09-13 13:24:59 -0400419
Linus Torvalds1da177e2005-04-16 15:20:36 -0700420/*
421 * wait_for_buffer
422 *
423 * This routine waits for the SEEQ chip to assert that the FIFO is ready
424 * by checking for a window interrupt, and then clearing it. This has to
425 * occur in the interrupt handler!
426 */
427inline void wait_for_buffer(struct net_device * dev)
428{
429 int ioaddr = dev->base_addr;
430 unsigned long tmp;
431 int status;
Jeff Garzik6aa20a22006-09-13 13:24:59 -0400432
Linus Torvalds1da177e2005-04-16 15:20:36 -0700433 tmp = jiffies + HZ;
434 while ( ( ((status=inw(SEEQ_STATUS)) & SEEQSTAT_WINDOW_INT) != SEEQSTAT_WINDOW_INT) && time_before(jiffies, tmp))
435 cpu_relax();
Jeff Garzik6aa20a22006-09-13 13:24:59 -0400436
Linus Torvalds1da177e2005-04-16 15:20:36 -0700437 if ( (status & SEEQSTAT_WINDOW_INT) == SEEQSTAT_WINDOW_INT)
438 outw( SEEQCMD_WINDOW_INT_ACK | (status & SEEQCMD_INT_MASK), SEEQ_CMD);
439}
Jeff Garzik6aa20a22006-09-13 13:24:59 -0400440
Linus Torvalds1da177e2005-04-16 15:20:36 -0700441/* The typical workload of the driver:
442 Handle the network interface interrupts. */
David Howells7d12e782006-10-05 14:55:46 +0100443static irqreturn_t seeq8005_interrupt(int irq, void *dev_id)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700444{
445 struct net_device *dev = dev_id;
446 struct net_local *lp;
447 int ioaddr, status, boguscount = 0;
448 int handled = 0;
449
450 ioaddr = dev->base_addr;
451 lp = netdev_priv(dev);
452
453 status = inw(SEEQ_STATUS);
454 do {
455 if (net_debug >2) {
456 printk("%s: int, status=0x%04x\n",dev->name,status);
457 }
Jeff Garzik6aa20a22006-09-13 13:24:59 -0400458
Linus Torvalds1da177e2005-04-16 15:20:36 -0700459 if (status & SEEQSTAT_WINDOW_INT) {
460 handled = 1;
461 outw( SEEQCMD_WINDOW_INT_ACK | (status & SEEQCMD_INT_MASK), SEEQ_CMD);
462 if (net_debug) {
463 printk("%s: window int!\n",dev->name);
464 }
465 }
466 if (status & SEEQSTAT_TX_INT) {
467 handled = 1;
468 outw( SEEQCMD_TX_INT_ACK | (status & SEEQCMD_INT_MASK), SEEQ_CMD);
Jeff Garzik09f75cd2007-10-03 17:41:50 -0700469 dev->stats.tx_packets++;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700470 netif_wake_queue(dev); /* Inform upper layers. */
471 }
472 if (status & SEEQSTAT_RX_INT) {
473 handled = 1;
474 /* Got a packet(s). */
475 seeq8005_rx(dev);
476 }
477 status = inw(SEEQ_STATUS);
478 } while ( (++boguscount < 10) && (status & SEEQSTAT_ANY_INT)) ;
479
480 if(net_debug>2) {
481 printk("%s: eoi\n",dev->name);
482 }
483 return IRQ_RETVAL(handled);
484}
485
486/* We have a good packet(s), get it/them out of the buffers. */
487static void seeq8005_rx(struct net_device *dev)
488{
489 struct net_local *lp = netdev_priv(dev);
490 int boguscount = 10;
491 int pkt_hdr;
492 int ioaddr = dev->base_addr;
493
494 do {
495 int next_packet;
496 int pkt_len;
497 int i;
498 int status;
499
500 status = inw(SEEQ_STATUS);
501 outw( lp->receive_ptr, SEEQ_DMAAR);
502 outw(SEEQCMD_FIFO_READ | SEEQCMD_RX_INT_ACK | (status & SEEQCMD_INT_MASK), SEEQ_CMD);
503 wait_for_buffer(dev);
504 next_packet = ntohs(inw(SEEQ_BUFFER));
505 pkt_hdr = inw(SEEQ_BUFFER);
Jeff Garzik6aa20a22006-09-13 13:24:59 -0400506
Linus Torvalds1da177e2005-04-16 15:20:36 -0700507 if (net_debug>2) {
508 printk("%s: 0x%04x recv next=0x%04x, hdr=0x%04x\n",dev->name,lp->receive_ptr,next_packet,pkt_hdr);
509 }
Jeff Garzik6aa20a22006-09-13 13:24:59 -0400510
Linus Torvalds1da177e2005-04-16 15:20:36 -0700511 if ((next_packet == 0) || ((pkt_hdr & SEEQPKTH_CHAIN)==0)) { /* Read all the frames? */
512 return; /* Done for now */
513 }
Jeff Garzik6aa20a22006-09-13 13:24:59 -0400514
Linus Torvalds1da177e2005-04-16 15:20:36 -0700515 if ((pkt_hdr & SEEQPKTS_DONE)==0)
516 break;
Jeff Garzik6aa20a22006-09-13 13:24:59 -0400517
Linus Torvalds1da177e2005-04-16 15:20:36 -0700518 if (next_packet < lp->receive_ptr) {
519 pkt_len = (next_packet + 0x10000 - ((DEFAULT_TEA+1)<<8)) - lp->receive_ptr - 4;
520 } else {
521 pkt_len = next_packet - lp->receive_ptr - 4;
522 }
Jeff Garzik6aa20a22006-09-13 13:24:59 -0400523
Linus Torvalds1da177e2005-04-16 15:20:36 -0700524 if (next_packet < ((DEFAULT_TEA+1)<<8)) { /* is the next_packet address sane? */
525 printk("%s: recv packet ring corrupt, resetting board\n",dev->name);
526 seeq8005_init(dev,1);
527 return;
528 }
Jeff Garzik6aa20a22006-09-13 13:24:59 -0400529
Linus Torvalds1da177e2005-04-16 15:20:36 -0700530 lp->receive_ptr = next_packet;
Jeff Garzik6aa20a22006-09-13 13:24:59 -0400531
Linus Torvalds1da177e2005-04-16 15:20:36 -0700532 if (net_debug>2) {
533 printk("%s: recv len=0x%04x\n",dev->name,pkt_len);
534 }
535
536 if (pkt_hdr & SEEQPKTS_ANY_ERROR) { /* There was an error. */
Jeff Garzik09f75cd2007-10-03 17:41:50 -0700537 dev->stats.rx_errors++;
538 if (pkt_hdr & SEEQPKTS_SHORT) dev->stats.rx_frame_errors++;
539 if (pkt_hdr & SEEQPKTS_DRIB) dev->stats.rx_frame_errors++;
540 if (pkt_hdr & SEEQPKTS_OVERSIZE) dev->stats.rx_over_errors++;
541 if (pkt_hdr & SEEQPKTS_CRC_ERR) dev->stats.rx_crc_errors++;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700542 /* skip over this packet */
543 outw( SEEQCMD_FIFO_WRITE | SEEQCMD_DMA_INT_ACK | (status & SEEQCMD_INT_MASK), SEEQ_CMD);
544 outw( (lp->receive_ptr & 0xff00)>>8, SEEQ_REA);
545 } else {
546 /* Malloc up new buffer. */
547 struct sk_buff *skb;
548 unsigned char *buf;
549
Pradeep A. Dalvidae2e9f2012-02-06 11:16:13 +0000550 skb = netdev_alloc_skb(dev, pkt_len);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700551 if (skb == NULL) {
552 printk("%s: Memory squeeze, dropping packet.\n", dev->name);
Jeff Garzik09f75cd2007-10-03 17:41:50 -0700553 dev->stats.rx_dropped++;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700554 break;
555 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700556 skb_reserve(skb, 2); /* align data on 16 byte */
557 buf = skb_put(skb,pkt_len);
Jeff Garzik6aa20a22006-09-13 13:24:59 -0400558
Linus Torvalds1da177e2005-04-16 15:20:36 -0700559 insw(SEEQ_BUFFER, buf, (pkt_len + 1) >> 1);
Jeff Garzik6aa20a22006-09-13 13:24:59 -0400560
Linus Torvalds1da177e2005-04-16 15:20:36 -0700561 if (net_debug>2) {
562 char * p = buf;
563 printk("%s: recv ",dev->name);
564 for(i=0;i<14;i++) {
565 printk("%02x ",*(p++)&0xff);
566 }
567 printk("\n");
568 }
569
570 skb->protocol=eth_type_trans(skb,dev);
571 netif_rx(skb);
Jeff Garzik09f75cd2007-10-03 17:41:50 -0700572 dev->stats.rx_packets++;
573 dev->stats.rx_bytes += pkt_len;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700574 }
575 } while ((--boguscount) && (pkt_hdr & SEEQPKTH_CHAIN));
576
577 /* If any worth-while packets have been received, netif_rx()
578 has done a mark_bh(NET_BH) for us and will work on them
579 when we get to the bottom-half routine. */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700580}
581
582/* The inverse routine to net_open(). */
583static int seeq8005_close(struct net_device *dev)
584{
585 struct net_local *lp = netdev_priv(dev);
586 int ioaddr = dev->base_addr;
587
588 lp->open_time = 0;
589
590 netif_stop_queue(dev);
Jeff Garzik6aa20a22006-09-13 13:24:59 -0400591
Linus Torvalds1da177e2005-04-16 15:20:36 -0700592 /* Flush the Tx and disable Rx here. */
593 outw( SEEQCMD_SET_ALL_OFF, SEEQ_CMD);
594
595 free_irq(dev->irq, dev);
596
597 /* Update the statistics here. */
598
599 return 0;
600
601}
602
Linus Torvalds1da177e2005-04-16 15:20:36 -0700603/* Set or clear the multicast filter for this adaptor.
604 num_addrs == -1 Promiscuous mode, receive all packets
605 num_addrs == 0 Normal mode, clear multicast list
606 num_addrs > 0 Multicast mode, receive normal and MC packets, and do
607 best-effort filtering.
608 */
609static void set_multicast_list(struct net_device *dev)
610{
611/*
612 * I _could_ do up to 6 addresses here, but won't (yet?)
613 */
614
615#if 0
616 int ioaddr = dev->base_addr;
617/*
618 * hmm, not even sure if my matching works _anyway_ - seem to be receiving
619 * _everything_ . . .
620 */
Jeff Garzik6aa20a22006-09-13 13:24:59 -0400621
Linus Torvalds1da177e2005-04-16 15:20:36 -0700622 if (num_addrs) { /* Enable promiscuous mode */
623 outw( (inw(SEEQ_CFG1) & ~SEEQCFG1_MATCH_MASK)| SEEQCFG1_MATCH_ALL, SEEQ_CFG1);
624 dev->flags|=IFF_PROMISC;
625 } else { /* Disable promiscuous mode, use normal mode */
626 outw( (inw(SEEQ_CFG1) & ~SEEQCFG1_MATCH_MASK)| SEEQCFG1_MATCH_BROAD, SEEQ_CFG1);
627 }
628#endif
629}
630
631void seeq8005_init(struct net_device *dev, int startp)
632{
633 struct net_local *lp = netdev_priv(dev);
634 int ioaddr = dev->base_addr;
635 int i;
Jeff Garzik6aa20a22006-09-13 13:24:59 -0400636
Linus Torvalds1da177e2005-04-16 15:20:36 -0700637 outw(SEEQCFG2_RESET, SEEQ_CFG2); /* reset device */
638 udelay(5);
Jeff Garzik6aa20a22006-09-13 13:24:59 -0400639
Linus Torvalds1da177e2005-04-16 15:20:36 -0700640 outw( SEEQCMD_FIFO_WRITE | SEEQCMD_SET_ALL_OFF, SEEQ_CMD);
641 outw( 0, SEEQ_DMAAR); /* load start address into both low and high byte */
642/* wait_for_buffer(dev); */ /* I think that you only need a wait for memory buffer */
643 outw( SEEQCFG1_BUFFER_MAC0, SEEQ_CFG1);
Jeff Garzik6aa20a22006-09-13 13:24:59 -0400644
Linus Torvalds1da177e2005-04-16 15:20:36 -0700645 for(i=0;i<6;i++) { /* set Station address */
646 outb(dev->dev_addr[i], SEEQ_BUFFER);
647 udelay(2);
648 }
Jeff Garzik6aa20a22006-09-13 13:24:59 -0400649
Linus Torvalds1da177e2005-04-16 15:20:36 -0700650 outw( SEEQCFG1_BUFFER_TEA, SEEQ_CFG1); /* set xmit end area pointer to 16K */
651 outb( DEFAULT_TEA, SEEQ_BUFFER); /* this gives us 16K of send buffer and 48K of recv buffer */
Jeff Garzik6aa20a22006-09-13 13:24:59 -0400652
Linus Torvalds1da177e2005-04-16 15:20:36 -0700653 lp->receive_ptr = (DEFAULT_TEA+1)<<8; /* so we can find our packet_header */
654 outw( lp->receive_ptr, SEEQ_RPR); /* Receive Pointer Register is set to recv buffer memory */
Jeff Garzik6aa20a22006-09-13 13:24:59 -0400655
Linus Torvalds1da177e2005-04-16 15:20:36 -0700656 outw( 0x00ff, SEEQ_REA); /* Receive Area End */
657
658 if (net_debug>4) {
659 printk("%s: SA0 = ",dev->name);
660
661 outw( SEEQCMD_FIFO_READ | SEEQCMD_SET_ALL_OFF, SEEQ_CMD);
662 outw( 0, SEEQ_DMAAR);
663 outw( SEEQCFG1_BUFFER_MAC0, SEEQ_CFG1);
Jeff Garzik6aa20a22006-09-13 13:24:59 -0400664
Linus Torvalds1da177e2005-04-16 15:20:36 -0700665 for(i=0;i<6;i++) {
666 printk("%02x ",inb(SEEQ_BUFFER));
667 }
668 printk("\n");
669 }
Jeff Garzik6aa20a22006-09-13 13:24:59 -0400670
Linus Torvalds1da177e2005-04-16 15:20:36 -0700671 outw( SEEQCFG1_MAC0_EN | SEEQCFG1_MATCH_BROAD | SEEQCFG1_BUFFER_BUFFER, SEEQ_CFG1);
672 outw( SEEQCFG2_AUTO_REA | SEEQCFG2_CTRLO, SEEQ_CFG2);
673 outw( SEEQCMD_SET_RX_ON | SEEQCMD_TX_INT_EN | SEEQCMD_RX_INT_EN, SEEQ_CMD);
674
675 if (net_debug>4) {
676 int old_cfg1;
677 old_cfg1 = inw(SEEQ_CFG1);
678 printk("%s: stat = 0x%04x\n",dev->name,inw(SEEQ_STATUS));
679 printk("%s: cfg1 = 0x%04x\n",dev->name,old_cfg1);
680 printk("%s: cfg2 = 0x%04x\n",dev->name,inw(SEEQ_CFG2));
681 printk("%s: raer = 0x%04x\n",dev->name,inw(SEEQ_REA));
682 printk("%s: dmaar= 0x%04x\n",dev->name,inw(SEEQ_DMAAR));
Jeff Garzik6aa20a22006-09-13 13:24:59 -0400683
Linus Torvalds1da177e2005-04-16 15:20:36 -0700684 }
Jeff Garzik6aa20a22006-09-13 13:24:59 -0400685}
Linus Torvalds1da177e2005-04-16 15:20:36 -0700686
687
688static void hardware_send_packet(struct net_device * dev, char *buf, int length)
689{
690 int ioaddr = dev->base_addr;
691 int status = inw(SEEQ_STATUS);
692 int transmit_ptr = 0;
Marcelo Feitoza Parisiff5688a2006-01-09 18:37:15 -0800693 unsigned long tmp;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700694
695 if (net_debug>4) {
696 printk("%s: send 0x%04x\n",dev->name,length);
697 }
Jeff Garzik6aa20a22006-09-13 13:24:59 -0400698
Linus Torvalds1da177e2005-04-16 15:20:36 -0700699 /* Set FIFO to writemode and set packet-buffer address */
700 outw( SEEQCMD_FIFO_WRITE | (status & SEEQCMD_INT_MASK), SEEQ_CMD);
701 outw( transmit_ptr, SEEQ_DMAAR);
Jeff Garzik6aa20a22006-09-13 13:24:59 -0400702
Linus Torvalds1da177e2005-04-16 15:20:36 -0700703 /* output SEEQ Packet header barfage */
704 outw( htons(length + 4), SEEQ_BUFFER);
705 outw( SEEQPKTH_XMIT | SEEQPKTH_DATA_FOLLOWS | SEEQPKTH_XMIT_INT_EN, SEEQ_BUFFER );
Jeff Garzik6aa20a22006-09-13 13:24:59 -0400706
Linus Torvalds1da177e2005-04-16 15:20:36 -0700707 /* blat the buffer */
708 outsw( SEEQ_BUFFER, buf, (length +1) >> 1);
709 /* paranoia !! */
710 outw( 0, SEEQ_BUFFER);
711 outw( 0, SEEQ_BUFFER);
Jeff Garzik6aa20a22006-09-13 13:24:59 -0400712
Linus Torvalds1da177e2005-04-16 15:20:36 -0700713 /* set address of start of transmit chain */
714 outw( transmit_ptr, SEEQ_TPR);
Jeff Garzik6aa20a22006-09-13 13:24:59 -0400715
Linus Torvalds1da177e2005-04-16 15:20:36 -0700716 /* drain FIFO */
717 tmp = jiffies;
Marcelo Feitoza Parisiff5688a2006-01-09 18:37:15 -0800718 while ( (((status=inw(SEEQ_STATUS)) & SEEQSTAT_FIFO_EMPTY) == 0) && time_before(jiffies, tmp + HZ))
Linus Torvalds1da177e2005-04-16 15:20:36 -0700719 mb();
Jeff Garzik6aa20a22006-09-13 13:24:59 -0400720
Linus Torvalds1da177e2005-04-16 15:20:36 -0700721 /* doit ! */
722 outw( SEEQCMD_WINDOW_INT_ACK | SEEQCMD_SET_TX_ON | (status & SEEQCMD_INT_MASK), SEEQ_CMD);
Jeff Garzik6aa20a22006-09-13 13:24:59 -0400723
Linus Torvalds1da177e2005-04-16 15:20:36 -0700724}
725
726
727#ifdef MODULE
728
729static struct net_device *dev_seeq;
730MODULE_LICENSE("GPL");
731module_param(io, int, 0);
732module_param(irq, int, 0);
733MODULE_PARM_DESC(io, "SEEQ 8005 I/O base address");
734MODULE_PARM_DESC(irq, "SEEQ 8005 IRQ number");
735
Andrew Mortonc971ef42006-08-14 23:00:08 -0700736int __init init_module(void)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700737{
738 dev_seeq = seeq8005_probe(-1);
Devendra Naga17a2bf72012-07-29 03:28:47 +0000739 return PTR_RET(dev_seeq);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700740}
741
Al Viroafc8eb42006-06-14 18:50:53 -0400742void __exit cleanup_module(void)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700743{
744 unregister_netdev(dev_seeq);
745 release_region(dev_seeq->base_addr, SEEQ8005_IO_EXTENT);
746 free_netdev(dev_seeq);
747}
748
749#endif /* MODULE */