if_es.c revision 1.19 1 /* $NetBSD: if_es.c,v 1.19 1998/01/12 10:39:51 thorpej Exp $ */
2
3 /*
4 * Copyright (c) 1995 Michael L. Hitch
5 * All rights reserved.
6 *
7 * Redistribution and use in source and binary forms, with or without
8 * modification, are permitted provided that the following conditions
9 * are met:
10 * 1. Redistributions of source code must retain the above copyright
11 * notice, this list of conditions and the following disclaimer.
12 * 2. Redistributions in binary form must reproduce the above copyright
13 * notice, this list of conditions and the following disclaimer in the
14 * documentation and/or other materials provided with the distribution.
15 * 3. All advertising materials mentioning features or use of this software
16 * must display the following acknowledgement:
17 * This product includes software developed by Michael L. Hitch.
18 * 4. The name of the author may not be used to endorse or promote products
19 * derived from this software without specific prior written permission
20 *
21 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
22 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
23 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
24 * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
25 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
26 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
27 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
28 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
29 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
30 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
31 */
32
33 /*
34 * SMC 91C90 Single-Chip Ethernet Controller
35 */
36
37 #include "bpfilter.h"
38
39 #include <sys/param.h>
40 #include <sys/systm.h>
41 #include <sys/mbuf.h>
42 #include <sys/buf.h>
43 #include <sys/protosw.h>
44 #include <sys/socket.h>
45 #include <sys/syslog.h>
46 #include <sys/ioctl.h>
47 #include <sys/errno.h>
48 #include <sys/device.h>
49
50 #include <net/if.h>
51 #include <net/if_dl.h>
52 #include <net/if_ether.h>
53
54 #ifdef INET
55 #include <netinet/in.h>
56 #include <netinet/in_systm.h>
57 #include <netinet/in_var.h>
58 #include <netinet/ip.h>
59 #include <netinet/if_inarp.h>
60 #endif
61
62 #ifdef NS
63 #include <netns/ns.h>
64 #include <netns/ns_if.h>
65 #endif
66
67 #include <machine/cpu.h>
68 #include <machine/mtpr.h>
69 #include <amiga/amiga/device.h>
70 #include <amiga/amiga/isr.h>
71 #include <amiga/dev/zbusvar.h>
72 #include <amiga/dev/if_esreg.h>
73
74 #define SWAP(x) (((x & 0xff) << 8) | ((x >> 8) & 0xff))
75
76 #define USEPKTBUF
77
78 /*
79 * Ethernet software status per interface.
80 *
81 * Each interface is referenced by a network interface structure,
82 * es_if, which the routing code uses to locate the interface.
83 * This structure contains the output queue for the interface, its address, ...
84 */
85 struct es_softc {
86 struct device sc_dev;
87 struct isr sc_isr;
88 struct ethercom sc_ethercom; /* common Ethernet structures */
89 void *sc_base; /* base address of board */
90 short sc_iflags;
91 unsigned short sc_intctl;
92 #ifdef ESDEBUG
93 int sc_debug;
94 short sc_intbusy; /* counter for interrupt rentered */
95 short sc_smcbusy; /* counter for other rentry checks */
96 #endif
97 };
98
99 #if NBPFILTER > 0
100 #include <net/bpf.h>
101 #include <net/bpfdesc.h>
102 #endif
103
104 #ifdef ESDEBUG
105 /* console error messages */
106 int esdebug = 0;
107 int estxints = 0; /* IST_TX with TX enabled */
108 int estxint2 = 0; /* IST_TX active after IST_TX_EMPTY */
109 int estxint3 = 0; /* IST_TX interrupt processed */
110 int estxint4 = 0; /* ~TEMPTY counts */
111 int estxint5 = 0; /* IST_TX_EMPTY interrupts */
112 void es_dump_smcregs __P((char *, union smcregs *));
113 #endif
114
115 int esintr __P((void *));
116 void esstart __P((struct ifnet *));
117 void eswatchdog __P((struct ifnet *));
118 int esioctl __P((struct ifnet *, u_long, caddr_t));
119 void esrint __P((struct es_softc *));
120 void estint __P((struct es_softc *));
121 void esinit __P((struct es_softc *));
122 void esreset __P((struct es_softc *));
123 void esstop __P((struct es_softc *));
124
125 int esmatch __P((struct device *, struct cfdata *, void *));
126 void esattach __P((struct device *, struct device *, void *));
127
128 struct cfattach es_ca = {
129 sizeof(struct es_softc), esmatch, esattach
130 };
131
132 int
133 esmatch(parent, cfp, aux)
134 struct device *parent;
135 struct cfdata *cfp;
136 void *aux;
137 {
138 struct zbus_args *zap = aux;
139
140 /* Ameristar A4066 ethernet card */
141 if (zap->manid == 1053 && zap->prodid == 10)
142 return(1);
143
144 return (0);
145 }
146
147 /*
148 * Interface exists: make available by filling in network interface
149 * record. System will initialize the interface when it is ready
150 * to accept packets.
151 */
152 void
153 esattach(parent, self, aux)
154 struct device *parent, *self;
155 void *aux;
156 {
157 struct es_softc *sc = (void *)self;
158 struct zbus_args *zap = aux;
159 struct ifnet *ifp = &sc->sc_ethercom.ec_if;
160 unsigned long ser;
161 u_int8_t myaddr[ETHER_ADDR_LEN];
162
163 sc->sc_base = zap->va;
164
165 /*
166 * Manufacturer decides the 3 first bytes, i.e. ethernet vendor ID.
167 * (Currently only Ameristar.)
168 */
169 myaddr[0] = 0x00;
170 myaddr[1] = 0x00;
171 myaddr[2] = 0x9f;
172
173 /*
174 * Serial number for board contains last 3 bytes.
175 */
176 ser = (unsigned long) zap->serno;
177
178 myaddr[3] = (ser >> 16) & 0xff;
179 myaddr[4] = (ser >> 8) & 0xff;
180 myaddr[5] = (ser ) & 0xff;
181
182 /* Initialize ifnet structure. */
183 bcopy(sc->sc_dev.dv_xname, ifp->if_xname, IFNAMSIZ);
184 ifp->if_softc = sc;
185 ifp->if_output = ether_output;
186 ifp->if_ioctl = esioctl;
187 ifp->if_start = esstart;
188 ifp->if_watchdog = eswatchdog;
189 /* XXX IFF_MULTICAST */
190 ifp->if_flags = IFF_BROADCAST | IFF_SIMPLEX | IFF_NOTRAILERS;
191
192 /* Attach the interface. */
193 if_attach(ifp);
194 ether_ifattach(ifp, myaddr);
195
196 /* Print additional info when attached. */
197 printf(": address %s\n", ether_sprintf(myaddr));
198
199 #if NBPFILTER > 0
200 bpfattach(&ifp->if_bpf, ifp, DLT_EN10MB, sizeof(struct ether_header));
201 #endif
202
203 sc->sc_isr.isr_intr = esintr;
204 sc->sc_isr.isr_arg = sc;
205 sc->sc_isr.isr_ipl = 2;
206 add_isr(&sc->sc_isr);
207 }
208
209 #ifdef ESDEBUG
210 void
211 es_dump_smcregs(where, smc)
212 char *where;
213 union smcregs *smc;
214 {
215 u_short cur_bank = smc->b0.bsr & BSR_MASK;
216
217 printf("SMC registers %p from %s bank %04x\n", smc, where,
218 smc->b0.bsr);
219 smc->b0.bsr = BSR_BANK0;
220 printf("TCR %04x EPHSR %04x RCR %04x ECR %04x MIR %04x MCR %04x\n",
221 SWAP(smc->b0.tcr), SWAP(smc->b0.ephsr), SWAP(smc->b0.rcr),
222 SWAP(smc->b0.ecr), SWAP(smc->b0.mir), SWAP(smc->b0.mcr));
223 smc->b1.bsr = BSR_BANK1;
224 printf("CR %04x BAR %04x IAR %04x %04x %04x GPR %04x CTR %04x\n",
225 SWAP(smc->b1.cr), SWAP(smc->b1.bar), smc->b1.iar[0], smc->b1.iar[1],
226 smc->b1.iar[2], smc->b1.gpr, SWAP(smc->b1.ctr));
227 smc->b2.bsr = BSR_BANK2;
228 printf("MMUCR %04x PNR %02x ARR %02x FIFO %04x PTR %04x",
229 SWAP(smc->b2.mmucr), smc->b2.pnr, smc->b2.arr, smc->b2.fifo,
230 SWAP(smc->b2.ptr));
231 printf(" DATA %04x %04x IST %02x MSK %02x\n", smc->b2.data,
232 smc->b2.datax, smc->b2.ist, smc->b2.msk);
233 smc->b3.bsr = BSR_BANK3;
234 printf("MT %04x %04x %04x %04x\n",
235 smc->b3.mt[0], smc->b3.mt[1], smc->b3.mt[2], smc->b3.mt[3]);
236 smc->b3.bsr = cur_bank;
237 }
238 #endif
239
240 void
241 esstop(sc)
242 struct es_softc* sc;
243 {
244 }
245
246 void
247 esinit(sc)
248 struct es_softc *sc;
249 {
250 struct ifnet *ifp = &sc->sc_ethercom.ec_if;
251 union smcregs *smc = sc->sc_base;
252 int s;
253
254 s = splnet();
255
256 #ifdef ESDEBUG
257 if (ifp->if_flags & IFF_RUNNING)
258 es_dump_smcregs("esinit", smc);
259 #endif
260 smc->b0.bsr = BSR_BANK0; /* Select bank 0 */
261 smc->b0.rcr = RCR_EPH_RST;
262 smc->b0.rcr = 0;
263 smc->b3.bsr = BSR_BANK3; /* Select bank 3 */
264 smc->b3.mt[0] = 0; /* clear Multicast table */
265 smc->b3.mt[1] = 0;
266 smc->b3.mt[2] = 0;
267 smc->b3.mt[3] = 0;
268 /* XXX set Multicast table from Multicast list */
269 smc->b1.bsr = BSR_BANK1; /* Select bank 1 */
270 smc->b1.cr = CR_RAM32K | CR_NO_WAIT_ST | CR_SET_SQLCH;
271 smc->b1.ctr = CTR_AUTO_RLSE;
272 smc->b1.iar[0] = *((unsigned short *) &LLADDR(ifp->if_sadl)[0]);
273 smc->b1.iar[1] = *((unsigned short *) &LLADDR(ifp->if_sadl)[2]);
274 smc->b1.iar[2] = *((unsigned short *) &LLADDR(ifp->if_sadl)[4]);
275 smc->b2.bsr = BSR_BANK2; /* Select bank 2 */
276 smc->b2.mmucr = MMUCR_RESET;
277 smc->b0.bsr = BSR_BANK0; /* Select bank 0 */
278 smc->b0.mcr = SWAP(0x0020); /* reserve 8K for transmit buffers */
279 smc->b0.tcr = TCR_PAD_EN | (TCR_TXENA + TCR_MON_CSN);
280 smc->b0.rcr = RCR_FILT_CAR | RCR_STRIP_CRC | RCR_RXEN;
281 /* XXX add multicast/promiscuous flags */
282 smc->b2.bsr = BSR_BANK2; /* Select bank 2 */
283 smc->b2.msk = sc->sc_intctl = MSK_RX_OVRN | MSK_RX;
284
285 /* Interface is now 'running', with no output active. */
286 ifp->if_flags |= IFF_RUNNING;
287 ifp->if_flags &= ~IFF_OACTIVE;
288
289 /* Attempt to start output, if any. */
290 esstart(ifp);
291
292 splx(s);
293 }
294
295 int
296 esintr(arg)
297 void *arg;
298 {
299 struct es_softc *sc = arg;
300 struct ifnet *ifp = &sc->sc_ethercom.ec_if;
301 u_short intsts, intact;
302 union smcregs *smc;
303 int s = splnet();
304
305 smc = sc->sc_base;
306 #ifdef ESDEBUG
307 while ((smc->b2.bsr & BSR_MASK) != BSR_BANK2 &&
308 ifp->if_flags & IFF_RUNNING) {
309 printf("%s: intr BSR not 2: %04x\n", sc->sc_dev.dv_xname,
310 smc->b2.bsr);
311 smc->b2.bsr = BSR_BANK2;
312 }
313 #endif
314 intsts = smc->b2.ist;
315 intact = smc->b2.msk & intsts;
316 if ((intact) == 0) {
317 splx(s);
318 return (0);
319 }
320 #ifdef ESDEBUG
321 if (esdebug)
322 printf ("%s: esintr ist %02x msk %02x",
323 sc->sc_dev.dv_xname, intsts, smc->b2.msk);
324 if (sc->sc_intbusy++) {
325 printf("%s: esintr re-entered\n", sc->sc_dev.dv_xname);
326 panic("esintr re-entered");
327 }
328 if (sc->sc_smcbusy)
329 printf("%s: esintr interrupted busy %d\n", sc->sc_dev.dv_xname,
330 sc->sc_smcbusy);
331 #endif
332 smc->b2.msk = 0;
333 #ifdef ESDEBUG
334 if (esdebug)
335 printf ("=>%02x%02x pnr %02x arr %02x fifo %04x\n",
336 smc->b2.ist, smc->b2.ist, smc->b2.pnr, smc->b2.arr,
337 smc->b2.fifo);
338 #endif
339 if (intact & IST_ALLOC) {
340 sc->sc_intctl &= ~MSK_ALLOC;
341 #ifdef ESDEBUG
342 if (esdebug || 1)
343 printf ("%s: ist %02x", sc->sc_dev.dv_xname,
344 intsts);
345 #endif
346 if ((smc->b2.arr & ARR_FAILED) == 0) {
347 u_char save_pnr;
348 #ifdef ESDEBUG
349 if (esdebug || 1)
350 printf (" arr %02x\n", smc->b2.arr);
351 #endif
352 save_pnr = smc->b2.pnr;
353 smc->b2.pnr = smc->b2.arr;
354 smc->b2.mmucr = MMUCR_RLSPKT;
355 while (smc->b2.mmucr & MMUCR_BUSY)
356 ;
357 smc->b2.pnr = save_pnr;
358 ifp->if_flags &= ~IFF_OACTIVE;
359 }
360 #ifdef ESDEBUG
361 else if (esdebug || 1)
362 printf (" IST_ALLOC with ARR_FAILED?\n");
363 #endif
364 }
365 #ifdef ESDEBUG
366 while ((smc->b2.bsr & BSR_MASK) != BSR_BANK2) {
367 printf("%s: intr+ BSR not 2: %04x\n", sc->sc_dev.dv_xname,
368 smc->b2.bsr);
369 smc->b2.bsr = BSR_BANK2;
370 }
371 #endif
372 while ((smc->b2.fifo & FIFO_REMPTY) == 0) {
373 esrint(sc);
374 }
375 #ifdef ESDEBUG
376 while ((smc->b2.bsr & BSR_MASK) != BSR_BANK2) {
377 printf("%s: intr++ BSR not 2: %04x\n", sc->sc_dev.dv_xname,
378 smc->b2.bsr);
379 smc->b2.bsr = BSR_BANK2;
380 }
381 #endif
382 if (intact & IST_RX_OVRN) {
383 printf ("%s: Overrun ist %02x", sc->sc_dev.dv_xname,
384 intsts);
385 smc->b2.ist = ACK_RX_OVRN;
386 printf ("->%02x\n", smc->b2.ist);
387 ifp->if_ierrors++;
388 }
389 if (intact & IST_TX_EMPTY) {
390 u_short ecr;
391 #ifdef ESDEBUG
392 if (esdebug)
393 printf ("%s: TX EMPTY %02x",
394 sc->sc_dev.dv_xname, intsts);
395 ++estxint5; /* count # IST_TX_EMPTY ints */
396 #endif
397 smc->b2.ist = ACK_TX_EMPTY;
398 sc->sc_intctl &= ~(MSK_TX_EMPTY | MSK_TX);
399 #ifdef ESDEBUG
400 if (esdebug)
401 printf ("->%02x intcl %x pnr %02x arr %02x\n",
402 smc->b2.ist, sc->sc_intctl, smc->b2.pnr,
403 smc->b2.arr);
404 #endif
405 if (smc->b2.ist & IST_TX) {
406 intact |= IST_TX;
407 #ifdef ESDEBUG
408 ++estxint2; /* count # TX after TX_EMPTY */
409 #endif
410 } else {
411 smc->b0.bsr = BSR_BANK0;
412 ecr = smc->b0.ecr; /* Get error counters */
413 if (ecr & 0xff00)
414 ifp->if_collisions += ((ecr >> 8) & 15) +
415 ((ecr >> 11) & 0x1e);
416 smc->b2.bsr = BSR_BANK2;
417 #if 0
418 smc->b2.mmucr = MMUCR_RESET_TX; /* XXX reset TX FIFO */
419 #endif
420 }
421 }
422 if (intact & IST_TX) {
423 u_char tx_pnr, save_pnr;
424 u_short save_ptr, ephsr, tcr;
425 int n = 0;
426 #ifdef ESDEBUG
427 if (esdebug) {
428 printf ("%s: TX INT ist %02x",
429 sc->sc_dev.dv_xname, intsts);
430 printf ("->%02x\n", smc->b2.ist);
431 }
432 ++estxint3; /* count # IST_TX */
433 #endif
434 zzzz:
435 #ifdef ESDEBUG
436 ++estxint4; /* count # ~TEMPTY */
437 #endif
438 smc->b0.bsr = BSR_BANK0;
439 ephsr = smc->b0.ephsr; /* get EPHSR */
440 tcr = smc->b0.tcr; /* and TCR */
441 smc->b2.bsr = BSR_BANK2;
442 save_ptr = smc->b2.ptr;
443 save_pnr = smc->b2.pnr;
444 tx_pnr = smc->b2.fifo >> 8; /* pktno from completion fifo */
445 smc->b2.pnr = tx_pnr; /* set TX packet number */
446 smc->b2.ptr = PTR_READ; /* point to status word */
447 #if 0 /* XXXX */
448 printf("%s: esintr TXINT IST %02x PNR %02x(%d)",
449 sc->sc_dev.dv_xname, smc->b2.ist,
450 tx_pnr, n);
451 printf(" Status %04x", smc->b2.data);
452 printf(" EPHSR %04x\n", ephsr);
453 #endif
454 if ((smc->b2.data & EPHSR_TX_SUC) == 0 && (tcr & TCR_TXENA) == 0) {
455 /*
456 * Transmitter was stopped for some error. Enqueue
457 * the packet again and restart the transmitter.
458 * May need some check to limit the number of retries.
459 */
460 smc->b2.mmucr = MMUCR_ENQ_TX;
461 smc->b0.bsr = BSR_BANK0;
462 smc->b0.tcr |= TCR_TXENA;
463 smc->b2.bsr = BSR_BANK2;
464 ifp->if_oerrors++;
465 sc->sc_intctl |= MSK_TX_EMPTY | MSK_TX;
466 } else {
467 /*
468 * This shouldn't have happened: IST_TX indicates
469 * the TX completion FIFO is not empty, but the
470 * status for the packet on the completion FIFO
471 * shows that the transmit was sucessful. Since
472 * AutoRelease is being used, a sucessful transmit
473 * should not result in a packet on the completion
474 * FIFO. Also, that packet doesn't seem to want
475 * to be acknowledged. If this occurs, just reset
476 * the TX FIFOs.
477 */
478 #if 1
479 if (smc->b2.ist & IST_TX_EMPTY) {
480 smc->b2.mmucr = MMUCR_RESET_TX;
481 sc->sc_intctl &= ~(MSK_TX_EMPTY | MSK_TX);
482 }
483 #endif
484 #ifdef ESDEBUG
485 ++estxints; /* count IST_TX with TX enabled */
486 #endif
487 }
488 smc->b2.pnr = save_pnr;
489 smc->b2.ptr = save_ptr;
490 smc->b2.ist = ACK_TX;
491
492 if ((smc->b2.fifo & FIFO_TEMPTY) == 0 && n++ < 32) {
493 #if 0 /* XXXX */
494 printf("%s: multiple TX int(%2d) pnr %02x ist %02x fifo %04x",
495 sc->sc_dev.dv_xname, n, tx_pnr, smc->b2.ist, smc->b2.fifo);
496 smc->w2.istmsk = ACK_TX << 8;
497 printf(" %04x\n", smc->b2.fifo);
498 #endif
499 if (tx_pnr != (smc->b2.fifo >> 8))
500 goto zzzz;
501 }
502 }
503 /* output packets */
504 estint(sc);
505 #ifdef ESDEBUG
506 while ((smc->b2.bsr & BSR_MASK) != BSR_BANK2) {
507 printf("%s: intr+++ BSR not 2: %04x\n", sc->sc_dev.dv_xname,
508 smc->b2.bsr);
509 smc->b2.bsr = BSR_BANK2;
510 }
511 #endif
512 smc->b2.msk = sc->sc_intctl;
513 #ifdef ESDEBUG
514 if (--sc->sc_intbusy) {
515 printf("%s: esintr busy on exit\n", sc->sc_dev.dv_xname);
516 panic("esintr busy on exit");
517 }
518 #endif
519 splx(s);
520 return (1);
521 }
522
523 void
524 esrint(sc)
525 struct es_softc *sc;
526 {
527 union smcregs *smc = sc->sc_base;
528 u_short len;
529 short cnt;
530 u_short pktctlw, pktlen, *buf;
531 volatile u_short *data;
532 #if 0
533 u_long *lbuf;
534 volatile u_long *ldata;
535 #endif
536 struct ifnet *ifp;
537 struct mbuf *top, **mp, *m;
538 struct ether_header *eh;
539 #ifdef USEPKTBUF
540 u_char *b, pktbuf[1530];
541 #endif
542 #ifdef ESDEBUG
543 int i;
544 #endif
545
546 ifp = &sc->sc_ethercom.ec_if;
547 #ifdef ESDEBUG
548 if (esdebug)
549 printf ("%s: esrint fifo %04x", sc->sc_dev.dv_xname,
550 smc->b2.fifo);
551 if (sc->sc_smcbusy++) {
552 printf("%s: esrint re-entered\n", sc->sc_dev.dv_xname);
553 panic("esrint re-entered");
554 }
555 while ((smc->b2.bsr & BSR_MASK) != BSR_BANK2) {
556 printf("%s: rint BSR not 2: %04x\n", sc->sc_dev.dv_xname,
557 smc->b2.bsr);
558 smc->b2.bsr = BSR_BANK2;
559 }
560 #endif
561 data = (u_short *)&smc->b2.data;
562 smc->b2.ptr = PTR_RCV | PTR_AUTOINCR | PTR_READ | SWAP(0x0002);
563 (void) smc->b2.mmucr;
564 #ifdef ESDEBUG
565 if (esdebug)
566 printf ("->%04x", smc->b2.fifo);
567 #endif
568 len = *data;
569 len = SWAP(len); /* Careful of macro side-effects */
570 #ifdef ESDEBUG
571 if (esdebug)
572 printf (" length %d", len);
573 #endif
574 smc->b2.ptr = PTR_RCV | (PTR_AUTOINCR + PTR_READ) | SWAP(0x0000);
575 (void) smc->b2.mmucr;
576 pktctlw = *data;
577 pktlen = *data;
578 pktctlw = SWAP(pktctlw);
579 pktlen = SWAP(pktlen) - 6;
580 if (pktctlw & RFSW_ODDFRM)
581 pktlen++;
582 if (len > 1530) {
583 printf("%s: Corrupted packet length-sts %04x bytcnt %04x len %04x bank %04x\n",
584 sc->sc_dev.dv_xname, pktctlw, pktlen, len, smc->b2.bsr);
585 /* XXX ignore packet, or just truncate? */
586 #if defined(ESDEBUG) && defined(DDB)
587 if ((smc->b2.bsr & BSR_MASK) != BSR_BANK2)
588 Debugger();
589 #endif
590 smc->b2.bsr = BSR_BANK2;
591 smc->b2.mmucr = MMUCR_REMRLS_RX;
592 while (smc->b2.mmucr & MMUCR_BUSY)
593 ;
594 ++ifp->if_ierrors;
595 #ifdef ESDEBUG
596 if (--sc->sc_smcbusy) {
597 printf("%s: esrintr busy on bad packet exit\n",
598 sc->sc_dev.dv_xname);
599 panic("esrintr busy on exit");
600 }
601 #endif
602 return;
603 }
604 #ifdef USEPKTBUF
605 #if 0
606 lbuf = (u_long *) pktbuf;
607 ldata = (u_long *)data;
608 cnt = (len - 4) / 4;
609 while (cnt--)
610 *lbuf++ = *ldata;
611 if ((len - 4) & 2) {
612 buf = (u_short *) lbuf;
613 *buf = *data;
614 }
615 #else
616 buf = (u_short *)pktbuf;
617 cnt = (len - 4) / 2;
618 while (cnt--)
619 *buf++ = *data;
620 #endif
621 smc->b2.mmucr = MMUCR_REMRLS_RX;
622 while (smc->b2.mmucr & MMUCR_BUSY)
623 ;
624 #ifdef ESDEBUG
625 if (pktctlw & (RFSW_ALGNERR | RFSW_BADCRC | RFSW_TOOLNG | RFSW_TOOSHORT)) {
626 printf ("%s: Packet error %04x\n", sc->sc_dev.dv_xname, pktctlw);
627 /* count input error? */
628 }
629 if (esdebug) {
630 printf (" pktctlw %04x pktlen %04x fifo %04x\n", pktctlw, pktlen,
631 smc->b2.fifo);
632 for (i = 0; i < pktlen; ++i)
633 printf ("%02x%s", pktbuf[i], ((i & 31) == 31) ? "\n" :
634 "");
635 if (i & 31)
636 printf ("\n");
637 }
638 #endif
639 #else /* USEPKTBUF */
640 /* XXX copy directly from controller to mbuf */
641 #ifdef ESDEBUG
642 if (pktctlw & (RFSW_ALGNERR | RFSW_BADCRC | RFSW_TOOLNG | RFSW_TOOSHORT)) {
643 printf ("%s: Packet error %04x\n", sc->sc_dev.dv_xname, pktctlw);
644 /* count input error? */
645 }
646 if (esdebug) {
647 printf (" pktctlw %04x pktlen %04x fifo %04x\n", pktctlw, pktlen,
648 smc->b2.fifo);
649 }
650 #endif
651 #endif /* USEPKTBUF */
652 ifp->if_ipackets++;
653 MGETHDR(m, M_DONTWAIT, MT_DATA);
654 if (m == NULL)
655 return;
656 m->m_pkthdr.rcvif = ifp;
657 m->m_pkthdr.len = pktlen;
658 len = MHLEN;
659 top = NULL;
660 mp = ⊤
661 #ifdef USEPKTBUF
662 b = pktbuf;
663 #endif
664 while (pktlen > 0) {
665 if (top) {
666 MGET(m, M_DONTWAIT, MT_DATA);
667 if (m == 0) {
668 m_freem(top);
669 return;
670 }
671 len = MLEN;
672 }
673 if (pktlen >= MINCLSIZE) {
674 MCLGET(m, M_DONTWAIT);
675 if (m->m_flags & M_EXT)
676 len = MCLBYTES;
677 }
678 m->m_len = len = min(pktlen, len);
679 #ifdef USEPKTBUF
680 bcopy((caddr_t)b, mtod(m, caddr_t), len);
681 b += len;
682 #else /* USEPKTBUF */
683 buf = mtod(m, u_short *);
684 cnt = len / 2;
685 while (cnt--)
686 *buf++ = *data;
687 if (len & 1)
688 *buf = *data; /* XXX should be byte store */
689 #ifdef ESDEBUG
690 if (esdebug) {
691 buf = mtod(m, u_short *);
692 for (i = 0; i < len; ++i)
693 printf ("%02x%s", ((u_char *)buf)[i],
694 ((i & 31) == 31) ? "\n" : "");
695 if (i & 31)
696 printf ("\n");
697 }
698 #endif
699 #endif /* USEPKTBUF */
700 pktlen -= len;
701 *mp = m;
702 mp = &m->m_next;
703 }
704 #ifndef USEPKTBUF
705 smc->b2.mmucr = MMUCR_REMRLS_RX;
706 while (smc->b2.mmucr & MMUCR_BUSY)
707 ;
708 #endif
709 eh = mtod(top, struct ether_header *);
710 #if NBPFILTER > 0
711 /*
712 * Check if there's a BPF listener on this interface. If so, hand off
713 * the raw packet to bpf.
714 */
715 if (ifp->if_bpf) {
716 bpf_mtap(ifp->if_bpf, top);
717
718 /*
719 * Note that the interface cannot be in promiscuous mode if
720 * there are no BPF listeners. And if we are in promiscuous
721 * mode, we have to check if this packet is really ours.
722 */
723 if ((sc->sc_ethercom.ec_if.if_flags & IFF_PROMISC) &&
724 (eh->ether_dhost[0] & 1) == 0 && /* !mcast and !bcast */
725 bcmp(eh->ether_dhost, LLADDR(ifp->if_sadl),
726 sizeof(eh->ether_dhost)) != 0) {
727 m_freem(top);
728 return;
729 }
730 }
731 #endif
732 top->m_pkthdr.len -= sizeof (*eh);
733 top->m_len -= sizeof (*eh);
734 top->m_data += sizeof (*eh);
735
736 ether_input(ifp, eh, top);
737 #ifdef ESDEBUG
738 if (--sc->sc_smcbusy) {
739 printf("%s: esintr busy on exit\n", sc->sc_dev.dv_xname);
740 panic("esintr busy on exit");
741 }
742 #endif
743 }
744
745 void
746 estint(sc)
747 struct es_softc *sc;
748 {
749
750 esstart(&sc->sc_ethercom.ec_if);
751 }
752
753 void
754 esstart(ifp)
755 struct ifnet *ifp;
756 {
757 struct es_softc *sc = ifp->if_softc;
758 union smcregs *smc = sc->sc_base;
759 struct mbuf *m0, *m;
760 #ifdef USEPKTBUF
761 u_short pktbuf[ETHERMTU + 2];
762 #else
763 u_short oddbyte, needbyte;
764 #endif
765 u_short pktctlw, pktlen;
766 u_short *buf;
767 volatile u_short *data;
768 #if 0
769 u_long *lbuf;
770 volatile u_long *ldata;
771 #endif
772 short cnt;
773 int i;
774 u_char active_pnr;
775
776 if ((sc->sc_ethercom.ec_if.if_flags & (IFF_RUNNING | IFF_OACTIVE)) !=
777 IFF_RUNNING)
778 return;
779
780 #ifdef ESDEBUG
781 if (sc->sc_smcbusy++) {
782 printf("%s: esstart re-entered\n", sc->sc_dev.dv_xname);
783 panic("esstart re-entred");
784 }
785 while ((smc->b2.bsr & BSR_MASK) != BSR_BANK2) {
786 printf("%s: esstart BSR not 2: %04x\n", sc->sc_dev.dv_xname,
787 smc->b2.bsr);
788 smc->b2.bsr = BSR_BANK2;
789 }
790 #endif
791 for (;;) {
792 #ifdef ESDEBUG
793 u_short start_ptr, end_ptr;
794 #endif
795 /*
796 * Sneak a peek at the next packet to get the length
797 * and see if the SMC 91C90 can accept it.
798 */
799 m = sc->sc_ethercom.ec_if.if_snd.ifq_head;
800 if (!m)
801 break;
802 #ifdef ESDEBUG
803 if (esdebug && (m->m_next || m->m_len & 1))
804 printf("%s: esstart m_next %p m_len %d\n",
805 sc->sc_dev.dv_xname, m->m_next, m->m_len);
806 #endif
807 for (m0 = m, pktlen = 0; m0; m0 = m0->m_next)
808 pktlen += m0->m_len;
809 pktctlw = 0;
810 pktlen += 4;
811 if (pktlen & 1)
812 ++pktlen; /* control byte after last byte */
813 else
814 pktlen += 2; /* control byte after pad byte */
815 smc->b2.mmucr = MMUCR_ALLOC | (pktlen & 0x0700);
816 for (i = 0; i <= 5; ++i)
817 if ((smc->b2.arr & ARR_FAILED) == 0)
818 break;
819 if (smc->b2.arr & ARR_FAILED) {
820 sc->sc_ethercom.ec_if.if_flags |= IFF_OACTIVE;
821 sc->sc_intctl |= MSK_ALLOC;
822 break;
823 }
824 active_pnr = smc->b2.pnr = smc->b2.arr;
825
826 #ifdef ESDEBUG
827 while ((smc->b2.bsr & BSR_MASK) != BSR_BANK2) {
828 printf("%s: esstart+ BSR not 2: %04x\n", sc->sc_dev.dv_xname,
829 smc->b2.bsr);
830 smc->b2.bsr = BSR_BANK2;
831 }
832 #endif
833 IF_DEQUEUE(&sc->sc_ethercom.ec_if.if_snd, m);
834 smc->b2.ptr = PTR_AUTOINCR;
835 (void) smc->b2.mmucr;
836 data = (u_short *)&smc->b2.data;
837 *data = SWAP(pktctlw);
838 *data = SWAP(pktlen);
839 #ifdef ESDEBUG
840 while ((smc->b2.bsr & BSR_MASK) != BSR_BANK2) {
841 printf("%s: esstart++ BSR not 2: %04x\n", sc->sc_dev.dv_xname,
842 smc->b2.bsr);
843 smc->b2.bsr = BSR_BANK2;
844 }
845 #endif
846 #ifdef USEPKTBUF
847 i = 0;
848 for (m0 = m; m; m = m->m_next) {
849 bcopy(mtod(m, caddr_t), (char *)pktbuf + i, m->m_len);
850 i += m->m_len;
851 }
852
853 if (i & 1) /* Figure out where to put control byte */
854 pktbuf[i/2] = (pktbuf[i/2] & 0xff00) | CTLB_ODD;
855 else
856 pktbuf[i/2] = 0;
857 pktlen -= 4;
858 #ifdef ESDEBUG
859 if (pktlen > sizeof(pktbuf) && i > (sizeof(pktbuf) * 2))
860 printf("%s: esstart packet longer than pktbuf\n",
861 sc->sc_dev.dv_xname);
862 #endif
863 #if 0 /* doesn't quite work? */
864 lbuf = (u_long *)(pktbuf);
865 ldata = (u_long *)data;
866 cnt = pktlen / 4;
867 while(cnt--)
868 *ldata = *lbuf++;
869 if (pktlen & 2) {
870 buf = (u_short *)lbuf;
871 *data = *buf;
872 }
873 #else
874 #ifdef ESDEBUG
875 while ((smc->b2.bsr & BSR_MASK) != BSR_BANK2) {
876 printf("%s: esstart++2 BSR not 2: %04x\n", sc->sc_dev.dv_xname,
877 smc->b2.bsr);
878 smc->b2.bsr = BSR_BANK2;
879 }
880 start_ptr = SWAP(smc->b2.ptr); /* save PTR before copy */
881 #endif
882 buf = pktbuf;
883 cnt = pktlen / 2;
884 while (cnt--)
885 *data = *buf++;
886 #ifdef ESDEBUG
887 end_ptr = SWAP(smc->b2.ptr); /* save PTR after copy */
888 #endif
889 #endif
890 #else /* USEPKTBUF */
891 pktctlw = 0;
892 oddbyte = needbyte = 0;
893 for (m0 = m; m; m = m->m_next) {
894 buf = mtod(m, u_short *);
895 cnt = m->m_len / 2;
896 if (needbyte) {
897 oddbyte |= *buf >> 8;
898 *data = oddbyte;
899 }
900 while (cnt--)
901 *data = *buf++;
902 if (m->m_len & 1)
903 pktctlw = (*buf & 0xff00) | CTLB_ODD;
904 if (m->m_len & 1 && m->m_next)
905 printf("%s: esstart odd byte count in mbuf\n",
906 sc->sc_dev.dv_xname);
907 }
908 *data = pktctlw;
909 #endif /* USEPKTBUF */
910 while ((smc->b2.bsr & BSR_MASK) != BSR_BANK2) {
911 /*
912 * The bank select register has changed. This seems
913 * to happen with my A2000/Zeus once in a while. It
914 * appears that the Ethernet chip resets while
915 * copying the transmit buffer. Requeue the current
916 * transmit buffer and reinitialize the interface.
917 * The initialize routine will take care of
918 * retransmitting the buffer. mhitch
919 */
920 #ifdef DIAGNOSTIC
921 printf("%s: esstart+++ BSR not 2: %04x\n",
922 sc->sc_dev.dv_xname, smc->b2.bsr);
923 #endif
924 smc->b2.bsr = BSR_BANK2;
925 #ifdef ESDEBUG
926 printf("start_ptr %04x end_ptr %04x cur ptr %04x\n",
927 start_ptr, end_ptr, SWAP(smc->b2.ptr));
928 --sc->sc_smcbusy;
929 #endif
930 IF_PREPEND(&sc->sc_ethercom.ec_if.if_snd, m0);
931 esinit(sc); /* It's really hosed - reset */
932 return;
933 }
934 smc->b2.mmucr = MMUCR_ENQ_TX;
935 if (smc->b2.pnr != active_pnr)
936 printf("%s: esstart - PNR changed %x->%x\n",
937 sc->sc_dev.dv_xname, active_pnr, smc->b2.pnr);
938 #if NBPFILTER > 0
939 if (sc->sc_ethercom.ec_if.if_bpf)
940 bpf_mtap(sc->sc_ethercom.ec_if.if_bpf, m0);
941 #endif
942 m_freem(m0);
943 sc->sc_ethercom.ec_if.if_opackets++; /* move to interrupt? */
944 sc->sc_intctl |= MSK_TX_EMPTY | MSK_TX;
945 }
946 smc->b2.msk = sc->sc_intctl;
947 #ifdef ESDEBUG
948 while ((smc->b2.bsr & BSR_MASK) != BSR_BANK2) {
949 printf("%s: esstart++++ BSR not 2: %04x\n", sc->sc_dev.dv_xname,
950 smc->b2.bsr);
951 smc->b2.bsr = BSR_BANK2;
952 }
953 if (--sc->sc_smcbusy) {
954 printf("%s: esstart busy on exit\n", sc->sc_dev.dv_xname);
955 panic("esstart busy on exit");
956 }
957 #endif
958 }
959
960 int
961 esioctl(ifp, command, data)
962 register struct ifnet *ifp;
963 u_long command;
964 caddr_t data;
965 {
966 struct es_softc *sc = ifp->if_softc;
967 register struct ifaddr *ifa = (struct ifaddr *)data;
968 struct ifreq *ifr = (struct ifreq *)data;
969 int s, error = 0;
970
971 s = splnet();
972
973 switch (command) {
974
975 case SIOCSIFADDR:
976 ifp->if_flags |= IFF_UP;
977
978 switch (ifa->ifa_addr->sa_family) {
979 #ifdef INET
980 case AF_INET:
981 esinit(sc);
982 arp_ifinit(ifp, ifa);
983 break;
984 #endif
985 #ifdef NS
986 case AF_NS:
987 {
988 register struct ns_addr *ina = &IA_SNS(ifa)->sns_addr;
989
990 if (ns_nullhost(*ina))
991 ina->x_host =
992 *(union ns_host *)LLADDR(ifp->if_sadl);
993 else
994 bcopy(ina->x_host.c_host,
995 LLADDR(ifp->if_sadl), ETHER_ADDR_LEN);
996 /* Set new address. */
997 esinit(sc);
998 break;
999 }
1000 #endif
1001 default:
1002 esinit(sc);
1003 break;
1004 }
1005 break;
1006
1007 case SIOCSIFFLAGS:
1008 /*
1009 * If interface is marked down and it is running, then stop it
1010 */
1011 if ((ifp->if_flags & IFF_UP) == 0 &&
1012 (ifp->if_flags & IFF_RUNNING) != 0) {
1013 /*
1014 * If interface is marked down and it is running, then
1015 * stop it.
1016 */
1017 esstop(sc);
1018 ifp->if_flags &= ~IFF_RUNNING;
1019 } else if ((ifp->if_flags & IFF_UP) != 0 &&
1020 (ifp->if_flags & IFF_RUNNING) == 0) {
1021 /*
1022 * If interface is marked up and it is stopped, then
1023 * start it.
1024 */
1025 esinit(sc);
1026 } else {
1027 /*
1028 * Reset the interface to pick up changes in any other
1029 * flags that affect hardware registers.
1030 */
1031 esstop(sc);
1032 esinit(sc);
1033 }
1034 #ifdef ESDEBUG
1035 if (ifp->if_flags & IFF_DEBUG)
1036 esdebug = sc->sc_debug = 1;
1037 else
1038 esdebug = sc->sc_debug = 0;
1039 #endif
1040 break;
1041
1042 case SIOCADDMULTI:
1043 case SIOCDELMULTI:
1044 error = (command == SIOCADDMULTI) ?
1045 ether_addmulti(ifr, &sc->sc_ethercom) :
1046 ether_delmulti(ifr, &sc->sc_ethercom);
1047
1048 if (error == ENETRESET) {
1049 /*
1050 * Multicast list has changed; set the hardware filter
1051 * accordingly.
1052 */
1053 /* XXX */
1054 error = 0;
1055 }
1056 break;
1057
1058 default:
1059 error = EINVAL;
1060 }
1061
1062 splx(s);
1063 return (error);
1064 }
1065
1066 void
1067 esreset(sc)
1068 struct es_softc *sc;
1069 {
1070 int s;
1071
1072 s = splnet();
1073 esstop(sc);
1074 esinit(sc);
1075 splx(s);
1076 }
1077
1078 void
1079 eswatchdog(ifp)
1080 struct ifnet *ifp;
1081 {
1082 struct es_softc *sc = ifp->if_softc;
1083
1084 log(LOG_ERR, "%s: device timeout\n", sc->sc_dev.dv_xname);
1085 ++ifp->if_oerrors;
1086
1087 esreset(sc);
1088 }
1089