1 |
1626 |
jcastillo |
/* 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 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 |
|
|
|
17 |
|
|
static 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
|
23 |
|
|
|
24 |
|
|
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/kernel.h>
|
34 |
|
|
#include <linux/sched.h>
|
35 |
|
|
#include <linux/types.h>
|
36 |
|
|
#include <linux/fcntl.h>
|
37 |
|
|
#include <linux/interrupt.h>
|
38 |
|
|
#include <linux/ptrace.h>
|
39 |
|
|
#include <linux/ioport.h>
|
40 |
|
|
#include <linux/in.h>
|
41 |
|
|
#include <linux/malloc.h>
|
42 |
|
|
#include <linux/string.h>
|
43 |
|
|
#include <asm/system.h>
|
44 |
|
|
#include <asm/bitops.h>
|
45 |
|
|
#include <asm/io.h>
|
46 |
|
|
#include <asm/dma.h>
|
47 |
|
|
#include <linux/errno.h>
|
48 |
|
|
|
49 |
|
|
#include <linux/netdevice.h>
|
50 |
|
|
#include <linux/etherdevice.h>
|
51 |
|
|
#include <linux/skbuff.h>
|
52 |
|
|
#include "seeq8005.h"
|
53 |
|
|
|
54 |
|
|
/* First, a few definitions that the brave might change. */
|
55 |
|
|
/* A zero-terminated list of I/O addresses to be probed. */
|
56 |
|
|
static unsigned int seeq8005_portlist[] =
|
57 |
|
|
{ 0x300, 0x320, 0x340, 0x360, 0};
|
58 |
|
|
|
59 |
|
|
/* use 0 for production, 1 for verification, >2 for debug */
|
60 |
|
|
#ifndef NET_DEBUG
|
61 |
|
|
#define NET_DEBUG 1
|
62 |
|
|
#endif
|
63 |
|
|
static unsigned int net_debug = NET_DEBUG;
|
64 |
|
|
|
65 |
|
|
/* Information that need to be kept for each board. */
|
66 |
|
|
struct net_local {
|
67 |
|
|
struct enet_statistics stats;
|
68 |
|
|
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 |
|
|
|
79 |
|
|
extern int seeq8005_probe(struct device *dev);
|
80 |
|
|
|
81 |
|
|
static int seeq8005_probe1(struct device *dev, int ioaddr);
|
82 |
|
|
static int seeq8005_open(struct device *dev);
|
83 |
|
|
static int seeq8005_send_packet(struct sk_buff *skb, struct device *dev);
|
84 |
|
|
static void seeq8005_interrupt(int irq, void *dev_id, struct pt_regs *regs);
|
85 |
|
|
static void seeq8005_rx(struct device *dev);
|
86 |
|
|
static int seeq8005_close(struct device *dev);
|
87 |
|
|
static struct enet_statistics *seeq8005_get_stats(struct device *dev);
|
88 |
|
|
static void set_multicast_list(struct device *dev);
|
89 |
|
|
|
90 |
|
|
/* Example routines you must write ;->. */
|
91 |
|
|
#define tx_done(dev) (inw(SEEQ_STATUS) & SEEQSTAT_TX_ON)
|
92 |
|
|
extern void hardware_send_packet(struct device *dev, char *buf, int length);
|
93 |
|
|
extern void seeq8005_init(struct device *dev, int startp);
|
94 |
|
|
inline void wait_for_buffer(struct device *dev);
|
95 |
|
|
|
96 |
|
|
|
97 |
|
|
/* 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 |
|
|
If dev->base_addr == 2, allocate space for the device and return success
|
101 |
|
|
(detachable devices only).
|
102 |
|
|
*/
|
103 |
|
|
#ifdef HAVE_DEVLIST
|
104 |
|
|
/* Support for a alternate probe manager, which will eliminate the
|
105 |
|
|
boilerplate below. */
|
106 |
|
|
struct netdev_entry seeq8005_drv =
|
107 |
|
|
{"seeq8005", seeq8005_probe1, SEEQ8005_IO_EXTENT, seeq8005_portlist};
|
108 |
|
|
#else
|
109 |
|
|
int
|
110 |
|
|
seeq8005_probe(struct device *dev)
|
111 |
|
|
{
|
112 |
|
|
int i;
|
113 |
|
|
int base_addr = dev ? dev->base_addr : 0;
|
114 |
|
|
|
115 |
|
|
if (base_addr > 0x1ff) /* Check a single specified location. */
|
116 |
|
|
return seeq8005_probe1(dev, base_addr);
|
117 |
|
|
else if (base_addr != 0) /* Don't probe at all. */
|
118 |
|
|
return ENXIO;
|
119 |
|
|
|
120 |
|
|
for (i = 0; seeq8005_portlist[i]; i++) {
|
121 |
|
|
int ioaddr = seeq8005_portlist[i];
|
122 |
|
|
if (check_region(ioaddr, SEEQ8005_IO_EXTENT))
|
123 |
|
|
continue;
|
124 |
|
|
if (seeq8005_probe1(dev, ioaddr) == 0)
|
125 |
|
|
return 0;
|
126 |
|
|
}
|
127 |
|
|
|
128 |
|
|
return ENODEV;
|
129 |
|
|
}
|
130 |
|
|
#endif
|
131 |
|
|
|
132 |
|
|
/* This is the real probe routine. Linux has a history of friendly device
|
133 |
|
|
probes on the ISA bus. A good device probes avoids doing writes, and
|
134 |
|
|
verifies that the correct device exists and functions. */
|
135 |
|
|
|
136 |
|
|
static int seeq8005_probe1(struct device *dev, int ioaddr)
|
137 |
|
|
{
|
138 |
|
|
static unsigned version_printed = 0;
|
139 |
|
|
int i,j;
|
140 |
|
|
unsigned char SA_prom[32];
|
141 |
|
|
int old_cfg1;
|
142 |
|
|
int old_cfg2;
|
143 |
|
|
int old_stat;
|
144 |
|
|
int old_dmaar;
|
145 |
|
|
int old_rear;
|
146 |
|
|
|
147 |
|
|
if (net_debug>1)
|
148 |
|
|
printk("seeq8005: probing at 0x%x\n",ioaddr);
|
149 |
|
|
|
150 |
|
|
old_stat = inw(SEEQ_STATUS); /* read status register */
|
151 |
|
|
if (old_stat == 0xffff)
|
152 |
|
|
return ENODEV; /* assume that 0xffff == no device */
|
153 |
|
|
if ( (old_stat & 0x1800) != 0x1800 ) { /* assume that unused bits are 1, as my manual says */
|
154 |
|
|
if (net_debug>1) {
|
155 |
|
|
printk("seeq8005: reserved stat bits != 0x1800\n");
|
156 |
|
|
printk(" == 0x%04x\n",old_stat);
|
157 |
|
|
}
|
158 |
|
|
return ENODEV;
|
159 |
|
|
}
|
160 |
|
|
|
161 |
|
|
old_rear = inw(SEEQ_REA);
|
162 |
|
|
if (old_rear == 0xffff) {
|
163 |
|
|
outw(0,SEEQ_REA);
|
164 |
|
|
if (inw(SEEQ_REA) == 0xffff) { /* assume that 0xffff == no device */
|
165 |
|
|
return ENODEV;
|
166 |
|
|
}
|
167 |
|
|
} else if ((old_rear & 0xff00) != 0xff00) { /* assume that unused bits are 1 */
|
168 |
|
|
if (net_debug>1) {
|
169 |
|
|
printk("seeq8005: unused rear bits != 0xff00\n");
|
170 |
|
|
printk(" == 0x%04x\n",old_rear);
|
171 |
|
|
}
|
172 |
|
|
return ENODEV;
|
173 |
|
|
}
|
174 |
|
|
|
175 |
|
|
old_cfg2 = inw(SEEQ_CFG2); /* read CFG2 register */
|
176 |
|
|
old_cfg1 = inw(SEEQ_CFG1);
|
177 |
|
|
old_dmaar = inw(SEEQ_DMAAR);
|
178 |
|
|
|
179 |
|
|
if (net_debug>4) {
|
180 |
|
|
printk("seeq8005: stat = 0x%04x\n",old_stat);
|
181 |
|
|
printk("seeq8005: cfg1 = 0x%04x\n",old_cfg1);
|
182 |
|
|
printk("seeq8005: cfg2 = 0x%04x\n",old_cfg2);
|
183 |
|
|
printk("seeq8005: raer = 0x%04x\n",old_rear);
|
184 |
|
|
printk("seeq8005: dmaar= 0x%04x\n",old_dmaar);
|
185 |
|
|
}
|
186 |
|
|
|
187 |
|
|
outw( SEEQCMD_FIFO_WRITE | SEEQCMD_SET_ALL_OFF, SEEQ_CMD); /* setup for reading PROM */
|
188 |
|
|
outw( 0, SEEQ_DMAAR); /* set starting PROM address */
|
189 |
|
|
outw( SEEQCFG1_BUFFER_PROM, SEEQ_CFG1); /* set buffer to look at PROM */
|
190 |
|
|
|
191 |
|
|
|
192 |
|
|
j=0;
|
193 |
|
|
for(i=0; i <32; i++) {
|
194 |
|
|
j+= SA_prom[i] = inw(SEEQ_BUFFER) & 0xff;
|
195 |
|
|
}
|
196 |
|
|
|
197 |
|
|
#if 0
|
198 |
|
|
/* untested because I only have the one card */
|
199 |
|
|
if ( (j&0xff) != 0 ) { /* checksum appears to be 8bit = 0 */
|
200 |
|
|
if (net_debug>1) { /* check this before deciding that we have a card */
|
201 |
|
|
printk("seeq8005: prom sum error\n");
|
202 |
|
|
}
|
203 |
|
|
outw( old_stat, SEEQ_STATUS);
|
204 |
|
|
outw( old_dmaar, SEEQ_DMAAR);
|
205 |
|
|
outw( old_cfg1, SEEQ_CFG1);
|
206 |
|
|
return ENODEV;
|
207 |
|
|
}
|
208 |
|
|
#endif
|
209 |
|
|
|
210 |
|
|
outw( SEEQCFG2_RESET, SEEQ_CFG2); /* reset the card */
|
211 |
|
|
SLOW_DOWN_IO; /* have to wait 4us after a reset - should be fixed */
|
212 |
|
|
SLOW_DOWN_IO;
|
213 |
|
|
SLOW_DOWN_IO;
|
214 |
|
|
SLOW_DOWN_IO;
|
215 |
|
|
outw( SEEQCMD_SET_ALL_OFF, SEEQ_CMD);
|
216 |
|
|
|
217 |
|
|
if (net_debug) {
|
218 |
|
|
printk("seeq8005: prom sum = 0x%08x\n",j);
|
219 |
|
|
for(j=0; j<32; j+=16) {
|
220 |
|
|
printk("seeq8005: prom %02x: ",j);
|
221 |
|
|
for(i=0;i<16;i++) {
|
222 |
|
|
printk("%02x ",SA_prom[j|i]);
|
223 |
|
|
}
|
224 |
|
|
printk(" ");
|
225 |
|
|
for(i=0;i<16;i++) {
|
226 |
|
|
if ((SA_prom[j|i]>31)&&(SA_prom[j|i]<127)) {
|
227 |
|
|
printk("%c", SA_prom[j|i]);
|
228 |
|
|
} else {
|
229 |
|
|
printk(" ");
|
230 |
|
|
}
|
231 |
|
|
}
|
232 |
|
|
printk("\n");
|
233 |
|
|
}
|
234 |
|
|
}
|
235 |
|
|
|
236 |
|
|
#if 0
|
237 |
|
|
/*
|
238 |
|
|
* testing the packet buffer memory doesn't work yet
|
239 |
|
|
* but all other buffer accesses do
|
240 |
|
|
* - fixing is not a priority
|
241 |
|
|
*/
|
242 |
|
|
if (net_debug>1) { /* test packet buffer memory */
|
243 |
|
|
printk("seeq8005: testing packet buffer ... ");
|
244 |
|
|
outw( SEEQCFG1_BUFFER_BUFFER, SEEQ_CFG1);
|
245 |
|
|
outw( SEEQCMD_FIFO_WRITE | SEEQCMD_SET_ALL_OFF, SEEQ_CMD);
|
246 |
|
|
outw( 0 , SEEQ_DMAAR);
|
247 |
|
|
for(i=0;i<32768;i++) {
|
248 |
|
|
outw(0x5a5a, SEEQ_BUFFER);
|
249 |
|
|
}
|
250 |
|
|
j=jiffies+HZ;
|
251 |
|
|
while ( ((inw(SEEQ_STATUS) & SEEQSTAT_FIFO_EMPTY) != SEEQSTAT_FIFO_EMPTY) && jiffies < j )
|
252 |
|
|
mb();
|
253 |
|
|
outw( 0 , SEEQ_DMAAR);
|
254 |
|
|
while ( ((inw(SEEQ_STATUS) & SEEQSTAT_WINDOW_INT) != SEEQSTAT_WINDOW_INT) && jiffies < j+HZ)
|
255 |
|
|
mb();
|
256 |
|
|
if ( (inw(SEEQ_STATUS) & SEEQSTAT_WINDOW_INT) == SEEQSTAT_WINDOW_INT)
|
257 |
|
|
outw( SEEQCMD_WINDOW_INT_ACK | (inw(SEEQ_STATUS)& SEEQCMD_INT_MASK), SEEQ_CMD);
|
258 |
|
|
outw( SEEQCMD_FIFO_READ | SEEQCMD_SET_ALL_OFF, SEEQ_CMD);
|
259 |
|
|
j=0;
|
260 |
|
|
for(i=0;i<32768;i++) {
|
261 |
|
|
if (inw(SEEQ_BUFFER) != 0x5a5a)
|
262 |
|
|
j++;
|
263 |
|
|
}
|
264 |
|
|
if (j) {
|
265 |
|
|
printk("%i\n",j);
|
266 |
|
|
} else {
|
267 |
|
|
printk("ok.\n");
|
268 |
|
|
}
|
269 |
|
|
}
|
270 |
|
|
#endif
|
271 |
|
|
|
272 |
|
|
/* Allocate a new 'dev' if needed. */
|
273 |
|
|
if (dev == NULL)
|
274 |
|
|
dev = init_etherdev(0, sizeof(struct net_local));
|
275 |
|
|
|
276 |
|
|
if (net_debug && version_printed++ == 0)
|
277 |
|
|
printk(version);
|
278 |
|
|
|
279 |
|
|
printk("%s: %s found at %#3x, ", dev->name, "seeq8005", ioaddr);
|
280 |
|
|
|
281 |
|
|
/* Fill in the 'dev' fields. */
|
282 |
|
|
dev->base_addr = ioaddr;
|
283 |
|
|
|
284 |
|
|
/* Retrieve and print the ethernet address. */
|
285 |
|
|
for (i = 0; i < 6; i++)
|
286 |
|
|
printk(" %2.2x", dev->dev_addr[i] = SA_prom[i+6]);
|
287 |
|
|
|
288 |
|
|
if (dev->irq == 0xff)
|
289 |
|
|
; /* Do nothing: a user-level program will set it. */
|
290 |
|
|
else if (dev->irq < 2) { /* "Auto-IRQ" */
|
291 |
|
|
autoirq_setup(0);
|
292 |
|
|
|
293 |
|
|
outw( SEEQCMD_RX_INT_EN | SEEQCMD_SET_RX_ON | SEEQCMD_SET_RX_OFF, SEEQ_CMD );
|
294 |
|
|
|
295 |
|
|
dev->irq = autoirq_report(0);
|
296 |
|
|
|
297 |
|
|
if (net_debug >= 2)
|
298 |
|
|
printk(" autoirq is %d\n", dev->irq);
|
299 |
|
|
} else if (dev->irq == 2)
|
300 |
|
|
/* Fixup for users that don't know that IRQ 2 is really IRQ 9,
|
301 |
|
|
* or don't know which one to set.
|
302 |
|
|
*/
|
303 |
|
|
dev->irq = 9;
|
304 |
|
|
|
305 |
|
|
#if 0
|
306 |
|
|
{
|
307 |
|
|
int irqval = request_irq(dev->irq, &seeq8005_interrupt, 0, "seeq8005", NULL);
|
308 |
|
|
if (irqval) {
|
309 |
|
|
printk ("%s: unable to get IRQ %d (irqval=%d).\n", dev->name,
|
310 |
|
|
dev->irq, irqval);
|
311 |
|
|
return EAGAIN;
|
312 |
|
|
}
|
313 |
|
|
}
|
314 |
|
|
#endif
|
315 |
|
|
|
316 |
|
|
/* Grab the region so we can find another board if autoIRQ fails. */
|
317 |
|
|
request_region(ioaddr, SEEQ8005_IO_EXTENT,"seeq8005");
|
318 |
|
|
|
319 |
|
|
/* Initialize the device structure. */
|
320 |
|
|
dev->priv = kmalloc(sizeof(struct net_local), GFP_KERNEL);
|
321 |
|
|
if (dev->priv == NULL)
|
322 |
|
|
return -ENOMEM;
|
323 |
|
|
memset(dev->priv, 0, sizeof(struct net_local));
|
324 |
|
|
|
325 |
|
|
dev->open = seeq8005_open;
|
326 |
|
|
dev->stop = seeq8005_close;
|
327 |
|
|
dev->hard_start_xmit = seeq8005_send_packet;
|
328 |
|
|
dev->get_stats = seeq8005_get_stats;
|
329 |
|
|
dev->set_multicast_list = &set_multicast_list;
|
330 |
|
|
|
331 |
|
|
/* Fill in the fields of the device structure with ethernet values. */
|
332 |
|
|
ether_setup(dev);
|
333 |
|
|
|
334 |
|
|
dev->flags &= ~IFF_MULTICAST;
|
335 |
|
|
|
336 |
|
|
return 0;
|
337 |
|
|
}
|
338 |
|
|
|
339 |
|
|
|
340 |
|
|
/* Open/initialize the board. This is called (in the current kernel)
|
341 |
|
|
sometime after booting when the 'ifconfig' program is run.
|
342 |
|
|
|
343 |
|
|
This routine should set everything up anew at each open, even
|
344 |
|
|
registers that "should" only need to be set once at boot, so that
|
345 |
|
|
there is non-reboot way to recover if something goes wrong.
|
346 |
|
|
*/
|
347 |
|
|
static int
|
348 |
|
|
seeq8005_open(struct device *dev)
|
349 |
|
|
{
|
350 |
|
|
struct net_local *lp = (struct net_local *)dev->priv;
|
351 |
|
|
|
352 |
|
|
{
|
353 |
|
|
int irqval = request_irq(dev->irq, &seeq8005_interrupt, 0, "seeq8005", NULL);
|
354 |
|
|
if (irqval) {
|
355 |
|
|
printk ("%s: unable to get IRQ %d (irqval=%d).\n", dev->name,
|
356 |
|
|
dev->irq, irqval);
|
357 |
|
|
return EAGAIN;
|
358 |
|
|
}
|
359 |
|
|
}
|
360 |
|
|
irq2dev_map[dev->irq] = dev;
|
361 |
|
|
|
362 |
|
|
/* Reset the hardware here. Don't forget to set the station address. */
|
363 |
|
|
seeq8005_init(dev, 1);
|
364 |
|
|
|
365 |
|
|
lp->open_time = jiffies;
|
366 |
|
|
|
367 |
|
|
dev->tbusy = 0;
|
368 |
|
|
dev->interrupt = 0;
|
369 |
|
|
dev->start = 1;
|
370 |
|
|
return 0;
|
371 |
|
|
}
|
372 |
|
|
|
373 |
|
|
static int
|
374 |
|
|
seeq8005_send_packet(struct sk_buff *skb, struct device *dev)
|
375 |
|
|
{
|
376 |
|
|
int ioaddr = dev->base_addr;
|
377 |
|
|
|
378 |
|
|
if (dev->tbusy) {
|
379 |
|
|
/* If we get here, some higher level has decided we are broken.
|
380 |
|
|
There should really be a "kick me" function call instead. */
|
381 |
|
|
int tickssofar = jiffies - dev->trans_start;
|
382 |
|
|
if (tickssofar < 5)
|
383 |
|
|
return 1;
|
384 |
|
|
printk("%s: transmit timed out, %s?\n", dev->name,
|
385 |
|
|
tx_done(dev) ? "IRQ conflict" : "network cable problem");
|
386 |
|
|
/* Try to restart the adaptor. */
|
387 |
|
|
seeq8005_init(dev, 1);
|
388 |
|
|
dev->tbusy=0;
|
389 |
|
|
dev->trans_start = jiffies;
|
390 |
|
|
}
|
391 |
|
|
|
392 |
|
|
/* If some higher layer thinks we've missed an tx-done interrupt
|
393 |
|
|
we are passed NULL. Caution: dev_tint() handles the cli()/sti()
|
394 |
|
|
itself. */
|
395 |
|
|
if (skb == NULL) {
|
396 |
|
|
dev_tint(dev);
|
397 |
|
|
return 0;
|
398 |
|
|
}
|
399 |
|
|
|
400 |
|
|
/* Block a timer-based transmit from overlapping. This could better be
|
401 |
|
|
done with atomic_swap(1, dev->tbusy), but set_bit() works as well. */
|
402 |
|
|
if (set_bit(0, (void*)&dev->tbusy) != 0)
|
403 |
|
|
printk("%s: Transmitter access conflict.\n", dev->name);
|
404 |
|
|
else {
|
405 |
|
|
short length = ETH_ZLEN < skb->len ? skb->len : ETH_ZLEN;
|
406 |
|
|
unsigned char *buf = skb->data;
|
407 |
|
|
|
408 |
|
|
hardware_send_packet(dev, buf, length);
|
409 |
|
|
dev->trans_start = jiffies;
|
410 |
|
|
}
|
411 |
|
|
dev_kfree_skb (skb, FREE_WRITE);
|
412 |
|
|
|
413 |
|
|
/* You might need to clean up and record Tx statistics here. */
|
414 |
|
|
|
415 |
|
|
return 0;
|
416 |
|
|
}
|
417 |
|
|
|
418 |
|
|
/* The typical workload of the driver:
|
419 |
|
|
Handle the network interface interrupts. */
|
420 |
|
|
static void
|
421 |
|
|
seeq8005_interrupt(int irq, void *dev_id, struct pt_regs * regs)
|
422 |
|
|
{
|
423 |
|
|
struct device *dev = (struct device *)(irq2dev_map[irq]);
|
424 |
|
|
struct net_local *lp;
|
425 |
|
|
int ioaddr, status, boguscount = 0;
|
426 |
|
|
|
427 |
|
|
if (dev == NULL) {
|
428 |
|
|
printk ("net_interrupt(): irq %d for unknown device.\n", irq);
|
429 |
|
|
return;
|
430 |
|
|
}
|
431 |
|
|
|
432 |
|
|
if (dev->interrupt)
|
433 |
|
|
printk ("%s: Re-entering the interrupt handler.\n", dev->name);
|
434 |
|
|
dev->interrupt = 1;
|
435 |
|
|
|
436 |
|
|
ioaddr = dev->base_addr;
|
437 |
|
|
lp = (struct net_local *)dev->priv;
|
438 |
|
|
|
439 |
|
|
status = inw(SEEQ_STATUS);
|
440 |
|
|
do {
|
441 |
|
|
if (net_debug >2) {
|
442 |
|
|
printk("%s: int, status=0x%04x\n",dev->name,status);
|
443 |
|
|
}
|
444 |
|
|
|
445 |
|
|
if (status & SEEQSTAT_WINDOW_INT) {
|
446 |
|
|
outw( SEEQCMD_WINDOW_INT_ACK | (status & SEEQCMD_INT_MASK), SEEQ_CMD);
|
447 |
|
|
if (net_debug) {
|
448 |
|
|
printk("%s: window int!\n",dev->name);
|
449 |
|
|
}
|
450 |
|
|
}
|
451 |
|
|
if (status & SEEQSTAT_TX_INT) {
|
452 |
|
|
outw( SEEQCMD_TX_INT_ACK | (status & SEEQCMD_INT_MASK), SEEQ_CMD);
|
453 |
|
|
lp->stats.tx_packets++;
|
454 |
|
|
dev->tbusy = 0;
|
455 |
|
|
mark_bh(NET_BH); /* Inform upper layers. */
|
456 |
|
|
}
|
457 |
|
|
if (status & SEEQSTAT_RX_INT) {
|
458 |
|
|
/* Got a packet(s). */
|
459 |
|
|
seeq8005_rx(dev);
|
460 |
|
|
}
|
461 |
|
|
status = inw(SEEQ_STATUS);
|
462 |
|
|
} while ( (++boguscount < 10) && (status & SEEQSTAT_ANY_INT)) ;
|
463 |
|
|
|
464 |
|
|
if(net_debug>2) {
|
465 |
|
|
printk("%s: eoi\n",dev->name);
|
466 |
|
|
}
|
467 |
|
|
dev->interrupt = 0;
|
468 |
|
|
return;
|
469 |
|
|
}
|
470 |
|
|
|
471 |
|
|
/* We have a good packet(s), get it/them out of the buffers. */
|
472 |
|
|
static void
|
473 |
|
|
seeq8005_rx(struct device *dev)
|
474 |
|
|
{
|
475 |
|
|
struct net_local *lp = (struct net_local *)dev->priv;
|
476 |
|
|
int boguscount = 10;
|
477 |
|
|
int pkt_hdr;
|
478 |
|
|
int ioaddr = dev->base_addr;
|
479 |
|
|
|
480 |
|
|
do {
|
481 |
|
|
int next_packet;
|
482 |
|
|
int pkt_len;
|
483 |
|
|
int i;
|
484 |
|
|
int status;
|
485 |
|
|
|
486 |
|
|
status = inw(SEEQ_STATUS);
|
487 |
|
|
outw( lp->receive_ptr, SEEQ_DMAAR);
|
488 |
|
|
outw(SEEQCMD_FIFO_READ | SEEQCMD_RX_INT_ACK | (status & SEEQCMD_INT_MASK), SEEQ_CMD);
|
489 |
|
|
wait_for_buffer(dev);
|
490 |
|
|
next_packet = ntohs(inw(SEEQ_BUFFER));
|
491 |
|
|
pkt_hdr = inw(SEEQ_BUFFER);
|
492 |
|
|
|
493 |
|
|
if (net_debug>2) {
|
494 |
|
|
printk("%s: 0x%04x recv next=0x%04x, hdr=0x%04x\n",dev->name,lp->receive_ptr,next_packet,pkt_hdr);
|
495 |
|
|
}
|
496 |
|
|
|
497 |
|
|
if ((next_packet == 0) || ((pkt_hdr & SEEQPKTH_CHAIN)==0)) { /* Read all the frames? */
|
498 |
|
|
return; /* Done for now */
|
499 |
|
|
}
|
500 |
|
|
|
501 |
|
|
if ((pkt_hdr & SEEQPKTS_DONE)==0)
|
502 |
|
|
break;
|
503 |
|
|
|
504 |
|
|
if (next_packet < lp->receive_ptr) {
|
505 |
|
|
pkt_len = (next_packet + 0x10000 - ((DEFAULT_TEA+1)<<8)) - lp->receive_ptr - 4;
|
506 |
|
|
} else {
|
507 |
|
|
pkt_len = next_packet - lp->receive_ptr - 4;
|
508 |
|
|
}
|
509 |
|
|
|
510 |
|
|
if (next_packet < ((DEFAULT_TEA+1)<<8)) { /* is the next_packet address sane? */
|
511 |
|
|
printk("%s: recv packet ring corrupt, resetting board\n",dev->name);
|
512 |
|
|
seeq8005_init(dev,1);
|
513 |
|
|
return;
|
514 |
|
|
}
|
515 |
|
|
|
516 |
|
|
lp->receive_ptr = next_packet;
|
517 |
|
|
|
518 |
|
|
if (net_debug>2) {
|
519 |
|
|
printk("%s: recv len=0x%04x\n",dev->name,pkt_len);
|
520 |
|
|
}
|
521 |
|
|
|
522 |
|
|
if (pkt_hdr & SEEQPKTS_ANY_ERROR) { /* There was an error. */
|
523 |
|
|
lp->stats.rx_errors++;
|
524 |
|
|
if (pkt_hdr & SEEQPKTS_SHORT) lp->stats.rx_frame_errors++;
|
525 |
|
|
if (pkt_hdr & SEEQPKTS_DRIB) lp->stats.rx_frame_errors++;
|
526 |
|
|
if (pkt_hdr & SEEQPKTS_OVERSIZE) lp->stats.rx_over_errors++;
|
527 |
|
|
if (pkt_hdr & SEEQPKTS_CRC_ERR) lp->stats.rx_crc_errors++;
|
528 |
|
|
/* skip over this packet */
|
529 |
|
|
outw( SEEQCMD_FIFO_WRITE | SEEQCMD_DMA_INT_ACK | (status & SEEQCMD_INT_MASK), SEEQ_CMD);
|
530 |
|
|
outw( (lp->receive_ptr & 0xff00)>>8, SEEQ_REA);
|
531 |
|
|
} else {
|
532 |
|
|
/* Malloc up new buffer. */
|
533 |
|
|
struct sk_buff *skb;
|
534 |
|
|
unsigned char *buf;
|
535 |
|
|
|
536 |
|
|
skb = dev_alloc_skb(pkt_len);
|
537 |
|
|
if (skb == NULL) {
|
538 |
|
|
printk("%s: Memory squeeze, dropping packet.\n", dev->name);
|
539 |
|
|
lp->stats.rx_dropped++;
|
540 |
|
|
break;
|
541 |
|
|
}
|
542 |
|
|
skb->dev = dev;
|
543 |
|
|
skb_reserve(skb, 2); /* align data on 16 byte */
|
544 |
|
|
buf = skb_put(skb,pkt_len);
|
545 |
|
|
|
546 |
|
|
insw(SEEQ_BUFFER, buf, (pkt_len + 1) >> 1);
|
547 |
|
|
|
548 |
|
|
if (net_debug>2) {
|
549 |
|
|
char * p = buf;
|
550 |
|
|
printk("%s: recv ",dev->name);
|
551 |
|
|
for(i=0;i<14;i++) {
|
552 |
|
|
printk("%02x ",*(p++)&0xff);
|
553 |
|
|
}
|
554 |
|
|
printk("\n");
|
555 |
|
|
}
|
556 |
|
|
|
557 |
|
|
skb->protocol=eth_type_trans(skb,dev);
|
558 |
|
|
netif_rx(skb);
|
559 |
|
|
lp->stats.rx_packets++;
|
560 |
|
|
}
|
561 |
|
|
} while ((--boguscount) && (pkt_hdr & SEEQPKTH_CHAIN));
|
562 |
|
|
|
563 |
|
|
/* If any worth-while packets have been received, netif_rx()
|
564 |
|
|
has done a mark_bh(NET_BH) for us and will work on them
|
565 |
|
|
when we get to the bottom-half routine. */
|
566 |
|
|
return;
|
567 |
|
|
}
|
568 |
|
|
|
569 |
|
|
/* The inverse routine to net_open(). */
|
570 |
|
|
static int
|
571 |
|
|
seeq8005_close(struct device *dev)
|
572 |
|
|
{
|
573 |
|
|
struct net_local *lp = (struct net_local *)dev->priv;
|
574 |
|
|
int ioaddr = dev->base_addr;
|
575 |
|
|
|
576 |
|
|
lp->open_time = 0;
|
577 |
|
|
|
578 |
|
|
dev->tbusy = 1;
|
579 |
|
|
dev->start = 0;
|
580 |
|
|
|
581 |
|
|
/* Flush the Tx and disable Rx here. */
|
582 |
|
|
outw( SEEQCMD_SET_ALL_OFF, SEEQ_CMD);
|
583 |
|
|
|
584 |
|
|
free_irq(dev->irq, NULL);
|
585 |
|
|
|
586 |
|
|
irq2dev_map[dev->irq] = 0;
|
587 |
|
|
|
588 |
|
|
/* Update the statistics here. */
|
589 |
|
|
|
590 |
|
|
return 0;
|
591 |
|
|
|
592 |
|
|
}
|
593 |
|
|
|
594 |
|
|
/* Get the current statistics. This may be called with the card open or
|
595 |
|
|
closed. */
|
596 |
|
|
static struct enet_statistics *
|
597 |
|
|
seeq8005_get_stats(struct device *dev)
|
598 |
|
|
{
|
599 |
|
|
struct net_local *lp = (struct net_local *)dev->priv;
|
600 |
|
|
|
601 |
|
|
return &lp->stats;
|
602 |
|
|
}
|
603 |
|
|
|
604 |
|
|
/* Set or clear the multicast filter for this adaptor.
|
605 |
|
|
num_addrs == -1 Promiscuous mode, receive all packets
|
606 |
|
|
num_addrs == 0 Normal mode, clear multicast list
|
607 |
|
|
num_addrs > 0 Multicast mode, receive normal and MC packets, and do
|
608 |
|
|
best-effort filtering.
|
609 |
|
|
*/
|
610 |
|
|
static void
|
611 |
|
|
set_multicast_list(struct device *dev)
|
612 |
|
|
{
|
613 |
|
|
/*
|
614 |
|
|
* I _could_ do up to 6 addresses here, but won't (yet?)
|
615 |
|
|
*/
|
616 |
|
|
|
617 |
|
|
#if 0
|
618 |
|
|
int ioaddr = dev->base_addr;
|
619 |
|
|
/*
|
620 |
|
|
* hmm, not even sure if my matching works _anyway_ - seem to be receiving
|
621 |
|
|
* _everything_ . . .
|
622 |
|
|
*/
|
623 |
|
|
|
624 |
|
|
if (num_addrs) { /* Enable promiscuous mode */
|
625 |
|
|
outw( (inw(SEEQ_CFG1) & ~SEEQCFG1_MATCH_MASK)| SEEQCFG1_MATCH_ALL, SEEQ_CFG1);
|
626 |
|
|
dev->flags|=IFF_PROMISC;
|
627 |
|
|
} else { /* Disable promiscuous mode, use normal mode */
|
628 |
|
|
outw( (inw(SEEQ_CFG1) & ~SEEQCFG1_MATCH_MASK)| SEEQCFG1_MATCH_BROAD, SEEQ_CFG1);
|
629 |
|
|
}
|
630 |
|
|
#endif
|
631 |
|
|
}
|
632 |
|
|
|
633 |
|
|
void seeq8005_init(struct device *dev, int startp)
|
634 |
|
|
{
|
635 |
|
|
struct net_local *lp = (struct net_local *)dev->priv;
|
636 |
|
|
int ioaddr = dev->base_addr;
|
637 |
|
|
int i;
|
638 |
|
|
|
639 |
|
|
outw(SEEQCFG2_RESET, SEEQ_CFG2); /* reset device */
|
640 |
|
|
SLOW_DOWN_IO; /* have to wait 4us after a reset - should be fixed */
|
641 |
|
|
SLOW_DOWN_IO;
|
642 |
|
|
SLOW_DOWN_IO;
|
643 |
|
|
SLOW_DOWN_IO;
|
644 |
|
|
|
645 |
|
|
outw( SEEQCMD_FIFO_WRITE | SEEQCMD_SET_ALL_OFF, SEEQ_CMD);
|
646 |
|
|
outw( 0, SEEQ_DMAAR); /* load start address into both low and high byte */
|
647 |
|
|
/* wait_for_buffer(dev); */ /* I think that you only need a wait for memory buffer */
|
648 |
|
|
outw( SEEQCFG1_BUFFER_MAC0, SEEQ_CFG1);
|
649 |
|
|
|
650 |
|
|
for(i=0;i<6;i++) { /* set Station address */
|
651 |
|
|
outb(dev->dev_addr[i], SEEQ_BUFFER);
|
652 |
|
|
SLOW_DOWN_IO;
|
653 |
|
|
}
|
654 |
|
|
|
655 |
|
|
outw( SEEQCFG1_BUFFER_TEA, SEEQ_CFG1); /* set xmit end area pointer to 16K */
|
656 |
|
|
outb( DEFAULT_TEA, SEEQ_BUFFER); /* this gives us 16K of send buffer and 48K of recv buffer */
|
657 |
|
|
|
658 |
|
|
lp->receive_ptr = (DEFAULT_TEA+1)<<8; /* so we can find our packet_header */
|
659 |
|
|
outw( lp->receive_ptr, SEEQ_RPR); /* Receive Pointer Register is set to recv buffer memory */
|
660 |
|
|
|
661 |
|
|
outw( 0x00ff, SEEQ_REA); /* Receive Area End */
|
662 |
|
|
|
663 |
|
|
if (net_debug>4) {
|
664 |
|
|
printk("%s: SA0 = ",dev->name);
|
665 |
|
|
|
666 |
|
|
outw( SEEQCMD_FIFO_READ | SEEQCMD_SET_ALL_OFF, SEEQ_CMD);
|
667 |
|
|
outw( 0, SEEQ_DMAAR);
|
668 |
|
|
outw( SEEQCFG1_BUFFER_MAC0, SEEQ_CFG1);
|
669 |
|
|
|
670 |
|
|
for(i=0;i<6;i++) {
|
671 |
|
|
printk("%02x ",inb(SEEQ_BUFFER));
|
672 |
|
|
}
|
673 |
|
|
printk("\n");
|
674 |
|
|
}
|
675 |
|
|
|
676 |
|
|
outw( SEEQCFG1_MAC0_EN | SEEQCFG1_MATCH_BROAD | SEEQCFG1_BUFFER_BUFFER, SEEQ_CFG1);
|
677 |
|
|
outw( SEEQCFG2_AUTO_REA | SEEQCFG2_CTRLO, SEEQ_CFG2);
|
678 |
|
|
outw( SEEQCMD_SET_RX_ON | SEEQCMD_TX_INT_EN | SEEQCMD_RX_INT_EN, SEEQ_CMD);
|
679 |
|
|
|
680 |
|
|
if (net_debug>4) {
|
681 |
|
|
int old_cfg1;
|
682 |
|
|
old_cfg1 = inw(SEEQ_CFG1);
|
683 |
|
|
printk("%s: stat = 0x%04x\n",dev->name,inw(SEEQ_STATUS));
|
684 |
|
|
printk("%s: cfg1 = 0x%04x\n",dev->name,old_cfg1);
|
685 |
|
|
printk("%s: cfg2 = 0x%04x\n",dev->name,inw(SEEQ_CFG2));
|
686 |
|
|
printk("%s: raer = 0x%04x\n",dev->name,inw(SEEQ_REA));
|
687 |
|
|
printk("%s: dmaar= 0x%04x\n",dev->name,inw(SEEQ_DMAAR));
|
688 |
|
|
|
689 |
|
|
}
|
690 |
|
|
}
|
691 |
|
|
|
692 |
|
|
|
693 |
|
|
void hardware_send_packet(struct device * dev, char *buf, int length)
|
694 |
|
|
{
|
695 |
|
|
int ioaddr = dev->base_addr;
|
696 |
|
|
int status = inw(SEEQ_STATUS);
|
697 |
|
|
int transmit_ptr = 0;
|
698 |
|
|
int tmp;
|
699 |
|
|
|
700 |
|
|
if (net_debug>4) {
|
701 |
|
|
printk("%s: send 0x%04x\n",dev->name,length);
|
702 |
|
|
}
|
703 |
|
|
|
704 |
|
|
/* Set FIFO to writemode and set packet-buffer address */
|
705 |
|
|
outw( SEEQCMD_FIFO_WRITE | (status & SEEQCMD_INT_MASK), SEEQ_CMD);
|
706 |
|
|
outw( transmit_ptr, SEEQ_DMAAR);
|
707 |
|
|
|
708 |
|
|
/* output SEEQ Packet header barfage */
|
709 |
|
|
outw( htons(length + 4), SEEQ_BUFFER);
|
710 |
|
|
outw( SEEQPKTH_XMIT | SEEQPKTH_DATA_FOLLOWS | SEEQPKTH_XMIT_INT_EN, SEEQ_BUFFER );
|
711 |
|
|
|
712 |
|
|
/* blat the buffer */
|
713 |
|
|
outsw( SEEQ_BUFFER, buf, (length +1) >> 1);
|
714 |
|
|
/* paranoia !! */
|
715 |
|
|
outw( 0, SEEQ_BUFFER);
|
716 |
|
|
outw( 0, SEEQ_BUFFER);
|
717 |
|
|
|
718 |
|
|
/* set address of start of transmit chain */
|
719 |
|
|
outw( transmit_ptr, SEEQ_TPR);
|
720 |
|
|
|
721 |
|
|
/* drain FIFO */
|
722 |
|
|
tmp = jiffies;
|
723 |
|
|
while ( (((status=inw(SEEQ_STATUS)) & SEEQSTAT_FIFO_EMPTY) == 0) && (jiffies < tmp + HZ))
|
724 |
|
|
mb();
|
725 |
|
|
|
726 |
|
|
/* doit ! */
|
727 |
|
|
outw( SEEQCMD_WINDOW_INT_ACK | SEEQCMD_SET_TX_ON | (status & SEEQCMD_INT_MASK), SEEQ_CMD);
|
728 |
|
|
|
729 |
|
|
}
|
730 |
|
|
|
731 |
|
|
|
732 |
|
|
/*
|
733 |
|
|
* wait_for_buffer
|
734 |
|
|
*
|
735 |
|
|
* This routine waits for the SEEQ chip to assert that the FIFO is ready
|
736 |
|
|
* by checking for a window interrupt, and then clearing it
|
737 |
|
|
*/
|
738 |
|
|
inline void wait_for_buffer(struct device * dev)
|
739 |
|
|
{
|
740 |
|
|
int ioaddr = dev->base_addr;
|
741 |
|
|
int tmp;
|
742 |
|
|
int status;
|
743 |
|
|
|
744 |
|
|
tmp = jiffies + HZ;
|
745 |
|
|
while ( ( ((status=inw(SEEQ_STATUS)) & SEEQSTAT_WINDOW_INT) != SEEQSTAT_WINDOW_INT) && jiffies < tmp)
|
746 |
|
|
mb();
|
747 |
|
|
|
748 |
|
|
if ( (status & SEEQSTAT_WINDOW_INT) == SEEQSTAT_WINDOW_INT)
|
749 |
|
|
outw( SEEQCMD_WINDOW_INT_ACK | (status & SEEQCMD_INT_MASK), SEEQ_CMD);
|
750 |
|
|
}
|
751 |
|
|
|
752 |
|
|
|
753 |
|
|
/*
|
754 |
|
|
* Local variables:
|
755 |
|
|
* compile-command: "gcc -D__KERNEL__ -I/usr/src/linux/net/inet -Wall -Wstrict-prototypes -O6 -m486 -c skeleton.c"
|
756 |
|
|
* version-control: t
|
757 |
|
|
* kept-new-versions: 5
|
758 |
|
|
* tab-width: 4
|
759 |
|
|
* End:
|
760 |
|
|
*/
|