if_es.c revision 1.10 1 /* $NetBSD: if_es.c,v 1.10 1996/03/17 05:58:45 mhitch 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/netisr.h>
52 #include <net/route.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_ether.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 ESDEBUG
77 #define USEPKTBUF
78
79 /*
80 * Ethernet software status per interface.
81 *
82 * Each interface is referenced by a network interface structure,
83 * es_if, which the routing code uses to locate the interface.
84 * This structure contains the output queue for the interface, its address, ...
85 */
86 struct es_softc {
87 struct device sc_dev;
88 struct isr sc_isr;
89 struct arpcom sc_arpcom; /* common Ethernet structures */
90 void *sc_base; /* base address of board */
91 short sc_iflags;
92 unsigned short sc_intctl;
93 #ifdef ESDEBUG
94 int sc_debug;
95 short sc_intbusy;
96 short sc_smcbusy;
97 #endif
98 };
99
100 #if NBPFILTER > 0
101 #include <net/bpf.h>
102 #include <net/bpfdesc.h>
103 #endif
104
105 #ifdef ESDEBUG
106 /* console error messages */
107 int esdebug = 0;
108 int estxints = 0; /* IST_TX with TX enabled */
109 int estxint2 = 0; /* IST_TX active after IST_TX_EMPTY */
110 int estxint3 = 0; /* IST_TX interrupt processed */
111 int estxint4 = 0; /* ~TEMPTY counts */
112 int estxint5 = 0; /* IST_TX_EMPTY interrupts */
113 #endif
114
115 int esintr __P((struct es_softc *));
116 void esstart __P((struct ifnet *));
117 void eswatchdog __P((int));
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
124 int esmatch __P((struct device *, void *, void *));
125 void esattach __P((struct device *, struct device *, void *));
126
127 struct cfattach es_ca = {
128 sizeof(struct es_softc), esmatch, esattach
129 };
130
131 struct cfdriver es_cd = {
132 NULL, "es", DV_IFNET
133 };
134
135 int
136 esmatch(parent, match, aux)
137 struct device *parent;
138 void *match, *aux;
139 {
140 struct zbus_args *zap = aux;
141
142 /* Ameristar A4066 ethernet card */
143 if (zap->manid == 1053 && zap->prodid == 10)
144 return(1);
145
146 return (0);
147 }
148
149 /*
150 * Interface exists: make available by filling in network interface
151 * record. System will initialize the interface when it is ready
152 * to accept packets.
153 */
154 void
155 esattach(parent, self, aux)
156 struct device *parent, *self;
157 void *aux;
158 {
159 struct es_softc *sc = (void *)self;
160 struct zbus_args *zap = aux;
161 struct ifnet *ifp = &sc->sc_arpcom.ac_if;
162 unsigned long ser;
163
164 sc->sc_base = zap->va;
165 #ifdef ESDEBUG
166 /* MLHDEBUG
167 * MLHDEBUG remove first 4 and last 3 pages of the A4066 memory
168 * MLHDEBUG and use the 5th page to access the SMC
169 */
170 sc->sc_base = zap->va + 0x8000; /* MLHDEBUG */
171 physunaccess(zap->va, 0x8000); /* MLHDEBUG */
172 physunaccess(zap->va + 0xa000, 0x6000); /* MLHDEBUG */
173 #endif
174
175 /*
176 * Manufacturer decides the 3 first bytes, i.e. ethernet vendor ID.
177 * (Currently only Ameristar.)
178 */
179 sc->sc_arpcom.ac_enaddr[0] = 0x00;
180 sc->sc_arpcom.ac_enaddr[1] = 0x00;
181 sc->sc_arpcom.ac_enaddr[2] = 0x9f;
182
183 /*
184 * Serial number for board contains last 3 bytes.
185 */
186 ser = (unsigned long) zap->serno;
187
188 sc->sc_arpcom.ac_enaddr[3] = (ser >> 16) & 0xff;
189 sc->sc_arpcom.ac_enaddr[4] = (ser >> 8) & 0xff;
190 sc->sc_arpcom.ac_enaddr[5] = (ser ) & 0xff;
191
192 /* Initialize ifnet structure. */
193 ifp->if_unit = sc->sc_dev.dv_unit;
194 ifp->if_name = es_cd.cd_name;
195 ifp->if_output = ether_output;
196 ifp->if_ioctl = esioctl;
197 ifp->if_start = esstart;
198 ifp->if_watchdog = eswatchdog;
199 /* XXX IFF_MULTICAST */
200 ifp->if_flags = IFF_BROADCAST | IFF_SIMPLEX | IFF_NOTRAILERS;
201
202 /* Attach the interface. */
203 if_attach(ifp);
204 ether_ifattach(ifp);
205
206 /* Print additional info when attached. */
207 printf(": address %s\n", ether_sprintf(sc->sc_arpcom.ac_enaddr));
208
209 #if NBPFILTER > 0
210 bpfattach(&ifp->if_bpf, ifp, DLT_EN10MB, sizeof(struct ether_header));
211 #endif
212
213 sc->sc_isr.isr_intr = esintr;
214 sc->sc_isr.isr_arg = sc;
215 sc->sc_isr.isr_ipl = 2;
216 add_isr(&sc->sc_isr);
217 }
218
219 #ifdef ESDEBUG
220 void
221 es_dump_smcregs(where, smc)
222 char *where;
223 union smcregs *smc;
224 {
225 u_short cur_bank = smc->b0.bsr & 0x0300;
226
227 printf("SMC registers %08x from %s bank %04x\n", smc, where,
228 smc->b0.bsr);
229 smc->b0.bsr = BSR_BANK0;
230 printf("TCR %04x EPHSR %04x RCR %04x ECR %04x MIR %04x MCR %04x\n",
231 SWAP(smc->b0.tcr), SWAP(smc->b0.ephsr), SWAP(smc->b0.rcr),
232 SWAP(smc->b0.ecr), SWAP(smc->b0.mir), SWAP(smc->b0.mcr));
233 smc->b1.bsr = BSR_BANK1;
234 printf("CR %04x BAR %04x IAR %04x %04x %04x GPR %04x CTR %04x\n",
235 SWAP(smc->b1.cr), SWAP(smc->b1.bar), smc->b1.iar[0], smc->b1.iar[1],
236 smc->b1.iar[2], smc->b1.gpr, SWAP(smc->b1.ctr));
237 smc->b2.bsr = BSR_BANK2;
238 printf("MMUCR %04x PNR %02x ARR %02x FIFO %04x PTR %04x",
239 SWAP(smc->b2.mmucr), smc->b2.pnr, smc->b2.arr, smc->b2.fifo,
240 SWAP(smc->b2.ptr));
241 printf(" DATA %04x %04x IST %02x MSK %02x\n", smc->b2.data,
242 smc->b2.datax, smc->b2.ist, smc->b2.msk);
243 smc->b3.bsr = BSR_BANK3;
244 printf("MT %04x %04x %04x %04x\n",
245 smc->b3.mt[0], smc->b3.mt[1], smc->b3.mt[2], smc->b3.mt[3]);
246 smc->b3.bsr = cur_bank;
247 }
248 #endif
249
250 void
251 esstop(sc)
252 struct es_softc* sc;
253 {
254 }
255
256 void
257 esinit(sc)
258 struct es_softc *sc;
259 {
260 struct ifnet *ifp = &sc->sc_arpcom.ac_if;
261 union smcregs *smc = sc->sc_base;
262 int s;
263
264 s = splnet();
265
266 #ifdef ESDEBUG
267 if (ifp->if_flags & IFF_RUNNING)
268 es_dump_smcregs("esinit", smc);
269 #endif
270 smc->b0.bsr = BSR_BANK0; /* Select bank 0 */
271 smc->b0.rcr = RCR_EPH_RST;
272 smc->b0.rcr = 0;
273 smc->b3.bsr = BSR_BANK3; /* Select bank 3 */
274 smc->b3.mt[0] = 0; /* clear Multicast table */
275 smc->b3.mt[1] = 0;
276 smc->b3.mt[2] = 0;
277 smc->b3.mt[3] = 0;
278 /* XXX set Multicast table from Multicast list */
279 smc->b1.bsr = BSR_BANK1; /* Select bank 1 */
280 smc->b1.cr = CR_RAM32K | CR_NO_WAIT_ST | CR_SET_SQLCH;
281 smc->b1.ctr = CTR_AUTO_RLSE;
282 smc->b1.iar[0] = *((unsigned short *) &sc->sc_arpcom.ac_enaddr[0]);
283 smc->b1.iar[1] = *((unsigned short *) &sc->sc_arpcom.ac_enaddr[2]);
284 smc->b1.iar[2] = *((unsigned short *) &sc->sc_arpcom.ac_enaddr[4]);
285 smc->b2.bsr = BSR_BANK2; /* Select bank 2 */
286 smc->b2.mmucr = MMUCR_RESET;
287 smc->b0.bsr = BSR_BANK0; /* Select bank 0 */
288 smc->b0.mcr = SWAP(0x0020); /* reserve 8K for transmit buffers */
289 smc->b0.tcr = TCR_PAD_EN | TCR_TXENA + TCR_MON_CSN;
290 smc->b0.rcr = RCR_FILT_CAR | RCR_STRIP_CRC | RCR_RXEN;
291 /* XXX add multicast/promiscuous flags */
292 smc->b2.bsr = BSR_BANK2; /* Select bank 2 */
293 smc->b2.msk = sc->sc_intctl = MSK_RX_OVRN | MSK_RX;
294
295 /* Interface is now 'running', with no output active. */
296 ifp->if_flags |= IFF_RUNNING;
297 ifp->if_flags &= ~IFF_OACTIVE;
298
299 /* Attempt to start output, if any. */
300 esstart(ifp);
301
302 splx(s);
303 }
304
305 int
306 esintr(sc)
307 struct es_softc *sc;
308 {
309 int i;
310 u_short intsts, intact;
311 union smcregs *smc;
312 int s = splnet();
313
314 smc = sc->sc_base;
315 #ifdef ESDEBUG
316 while ((smc->b2.bsr & 0x0300) != BSR_BANK2 &&
317 sc->sc_arpcom.ac_if.if_flags & IFF_RUNNING) {
318 printf("%s: intr BSR not 2: %04x\n", sc->sc_dev.dv_xname,
319 smc->b2.bsr);
320 smc->b2.bsr = BSR_BANK2;
321 }
322 #endif
323 intsts = smc->b2.ist;
324 intact = smc->b2.msk & intsts;
325 if ((intact) == 0) {
326 splx(s);
327 return (0);
328 }
329 #ifdef ESDEBUG
330 if (esdebug)
331 printf ("%s: esintr ist %02x msk %02x",
332 sc->sc_dev.dv_xname, intsts, smc->b2.msk);
333 if (sc->sc_intbusy++) {
334 printf("%s: esintr re-entered\n", sc->sc_dev.dv_xname);
335 panic("esintr re-entered");
336 }
337 #endif
338 smc->b2.msk = 0;
339 #ifdef ESDEBUG
340 if (esdebug)
341 printf ("=>%02x%02x pnr %02x arr %02x fifo %04x\n",
342 smc->b2.ist, smc->b2.ist, smc->b2.pnr, smc->b2.arr,
343 smc->b2.fifo);
344 #endif
345 if (intact & IST_ALLOC) {
346 sc->sc_intctl &= ~MSK_ALLOC;
347 #ifdef ESDEBUG
348 if (esdebug || 1)
349 printf ("%s: ist %02x", sc->sc_dev.dv_xname,
350 intsts);
351 #endif
352 if ((smc->b2.arr & ARR_FAILED) == 0) {
353 u_char save_pnr;
354 #ifdef ESDEBUG
355 if (esdebug || 1)
356 printf (" arr %02x\n", smc->b2.arr);
357 #endif
358 save_pnr = smc->b2.pnr;
359 smc->b2.pnr = smc->b2.arr;
360 smc->b2.mmucr = MMUCR_RLSPKT;
361 while (smc->b2.mmucr & MMUCR_BUSY)
362 ;
363 smc->b2.pnr = save_pnr;
364 sc->sc_arpcom.ac_if.if_flags &= ~IFF_OACTIVE;
365 }
366 #ifdef ESDEBUG
367 else if (esdebug || 1)
368 printf (" IST_ALLOC with ARR_FAILED?\n");
369 #endif
370 }
371 #ifdef ESDEBUG
372 while ((smc->b2.bsr & 0x0300) != BSR_BANK2) {
373 printf("%s: intr+ BSR not 2: %04x\n", sc->sc_dev.dv_xname,
374 smc->b2.bsr);
375 smc->b2.bsr = BSR_BANK2;
376 }
377 #endif
378 while ((smc->b2.fifo & FIFO_REMPTY) == 0) {
379 esrint(sc);
380 }
381 #ifdef ESDEBUG
382 while ((smc->b2.bsr & 0x0300) != BSR_BANK2) {
383 printf("%s: intr++ BSR not 2: %04x\n", sc->sc_dev.dv_xname,
384 smc->b2.bsr);
385 smc->b2.bsr = BSR_BANK2;
386 }
387 #endif
388 if (intact & IST_RX_OVRN) {
389 printf ("%s: Overrun ist %02x", sc->sc_dev.dv_xname,
390 intsts);
391 smc->b2.ist = ACK_RX_OVRN;
392 printf ("->%02x\n", smc->b2.ist);
393 sc->sc_arpcom.ac_if.if_ierrors++;
394 }
395 if (intact & IST_TX_EMPTY) {
396 u_short ecr;
397 #ifdef ESDEBUG
398 if (esdebug)
399 printf ("%s: TX EMPTY %02x",
400 sc->sc_dev.dv_xname, intsts);
401 ++estxint5; /* count # IST_TX_EMPTY ints */
402 #endif
403 smc->b2.ist = ACK_TX_EMPTY;
404 sc->sc_intctl &= ~(MSK_TX_EMPTY | MSK_TX);
405 #ifdef ESDEBUG
406 if (esdebug)
407 printf ("->%02x intcl %x pnr %02x arr %02x\n",
408 smc->b2.ist, sc->sc_intctl, smc->b2.pnr,
409 smc->b2.arr);
410 #endif
411 if (smc->b2.ist & IST_TX) {
412 intact |= IST_TX;
413 #ifdef ESDEBUG
414 ++estxint2; /* count # TX after TX_EMPTY */
415 #endif
416 } else {
417 smc->b0.bsr = BSR_BANK0;
418 ecr = smc->b0.ecr; /* Get error counters */
419 if (ecr & 0xff00)
420 sc->sc_arpcom.ac_if.if_collisions += ((ecr >> 8) & 15) +
421 ((ecr >> 11) & 0x1e);
422 smc->b2.bsr = BSR_BANK2;
423 #if 0
424 smc->b2.mmucr = MMUCR_RESET_TX; /* XXX reset TX FIFO */
425 #endif
426 }
427 }
428 if (intact & IST_TX) {
429 u_char tx_pnr, save_pnr;
430 u_short save_ptr, ephsr, tcr;
431 int n = 0;
432 #ifdef ESDEBUG
433 if (esdebug) {
434 printf ("%s: TX INT ist %02x",
435 sc->sc_dev.dv_xname, intsts);
436 printf ("->%02x\n", smc->b2.ist);
437 }
438 ++estxint3; /* count # IST_TX */
439 #endif
440 zzzz:
441 ++estxint4; /* count # ~TEMPTY */
442 smc->b0.bsr = BSR_BANK0;
443 ephsr = smc->b0.ephsr; /* get EPHSR */
444 tcr = smc->b0.tcr; /* and TCR */
445 smc->b2.bsr = BSR_BANK2;
446 save_ptr = smc->b2.ptr;
447 save_pnr = smc->b2.pnr;
448 tx_pnr = smc->b2.fifo >> 8; /* pktno from completion fifo */
449 smc->b2.pnr = tx_pnr; /* set TX packet number */
450 smc->b2.ptr = PTR_READ; /* point to status word */
451 #if 0 /* XXXX */
452 printf("%s: esintr TXINT IST %02x PNR %02x(%d)",
453 sc->sc_dev.dv_xname, smc->b2.ist,
454 tx_pnr, n);
455 printf(" Status %04x", smc->b2.data);
456 printf(" EPHSR %04x\n", ephsr);
457 #endif
458 if ((smc->b2.data & EPHSR_TX_SUC) == 0 && (tcr & TCR_TXENA) == 0) {
459 /*
460 * Transmitter was stopped for some error. Enqueue
461 * the packet again and restart the transmitter.
462 * May need some check to limit the number of retries.
463 */
464 smc->b2.mmucr = MMUCR_ENQ_TX;
465 smc->b0.bsr = BSR_BANK0;
466 smc->b0.tcr |= TCR_TXENA;
467 smc->b2.bsr = BSR_BANK2;
468 sc->sc_arpcom.ac_if.if_oerrors++;
469 sc->sc_intctl |= MSK_TX_EMPTY | MSK_TX;
470 } else {
471 /*
472 * This shouldn't have happened: IST_TX indicates
473 * the TX completion FIFO is not empty, but the
474 * status for the packet on the completion FIFO
475 * shows that the transmit was sucessful. Since
476 * AutoRelease is being used, a sucessful transmit
477 * should not result in a packet on the completion
478 * FIFO. Also, that packet doesn't seem to want
479 * to be acknowledged. If this occurs, just reset
480 * the TX FIFOs.
481 */
482 #if 1
483 if (smc->b2.ist & IST_TX_EMPTY) {
484 smc->b2.mmucr = MMUCR_RESET_TX;
485 sc->sc_intctl &= ~(MSK_TX_EMPTY | MSK_TX);
486 }
487 #endif
488 #ifdef ESDEBUG
489 ++estxints; /* count IST_TX with TX enabled */
490 #endif
491 }
492 smc->b2.pnr = save_pnr;
493 smc->b2.ptr = save_ptr;
494 smc->b2.ist = ACK_TX;
495
496 if ((smc->b2.fifo & FIFO_TEMPTY) == 0 && n++ < 32) {
497 #if 0 /* XXXX */
498 printf("%s: multiple TX int(%2d) pnr %02x ist %02x fifo %04x",
499 sc->sc_dev.dv_xname, n, tx_pnr, smc->b2.ist, smc->b2.fifo);
500 smc->w2.istmsk = ACK_TX << 8;
501 printf(" %04x\n", smc->b2.fifo);
502 #endif
503 if (tx_pnr != (smc->b2.fifo >> 8))
504 goto zzzz;
505 }
506 }
507 /* output packets */
508 estint(sc);
509 #ifdef ESDEBUG
510 while ((smc->b2.bsr & 0x0300) != BSR_BANK2) {
511 printf("%s: intr+++ BSR not 2: %04x\n", sc->sc_dev.dv_xname,
512 smc->b2.bsr);
513 smc->b2.bsr = BSR_BANK2;
514 }
515 #endif
516 smc->b2.msk = sc->sc_intctl;
517 #ifdef ESDEBUG
518 if (--sc->sc_intbusy) {
519 printf("%s: esintr busy on exit\n", sc->sc_dev.dv_xname);
520 panic("esintr busy on exit");
521 }
522 #endif
523 splx(s);
524 return (1);
525 }
526
527 void
528 esrint(sc)
529 struct es_softc *sc;
530 {
531 union smcregs *smc = sc->sc_base;
532 int i;
533 u_short len;
534 short cnt;
535 u_short pktctlw, pktlen, *buf;
536 u_long *lbuf;
537 volatile u_short *data;
538 volatile u_long *ldata;
539 struct ifnet *ifp;
540 struct mbuf *top, **mp, *m;
541 struct ether_header *eh;
542 #ifdef USEPKTBUF
543 u_char *b, pktbuf[1530];
544 #endif
545
546 #ifdef ESDEBUG
547 if (esdebug)
548 printf ("%s: esrint fifo %04x", sc->sc_dev.dv_xname,
549 smc->b2.fifo);
550 if (sc->sc_smcbusy++) {
551 printf("%s: esrint re-entered\n");
552 panic("esrint re-entered");
553 }
554 while ((smc->b2.bsr & 0x0300) != BSR_BANK2) {
555 printf("%s: rint BSR not 2: %04x\n", sc->sc_dev.dv_xname,
556 smc->b2.bsr);
557 smc->b2.bsr = BSR_BANK2;
558 }
559 #endif
560 data = (u_short *)&smc->b2.data;
561 smc->b2.ptr = PTR_RCV | PTR_AUTOINCR | PTR_READ | SWAP(0x0002);
562 (void) smc->b2.mmucr;
563 #ifdef ESDEBUG
564 if (esdebug)
565 printf ("->%04x", smc->b2.fifo);
566 #endif
567 len = *data;
568 len = SWAP(len); /* Careful of macro side-effects */
569 #ifdef ESDEBUG
570 if (esdebug)
571 printf (" length %d", len);
572 #endif
573 smc->b2.ptr = PTR_RCV | PTR_AUTOINCR + PTR_READ | SWAP(0x0000);
574 (void) smc->b2.mmucr;
575 pktctlw = *data;
576 pktlen = *data;
577 pktctlw = SWAP(pktctlw);
578 pktlen = SWAP(pktlen) - 6;
579 if (pktctlw & RFSW_ODDFRM)
580 pktlen++;
581 if (len > 1530) {
582 printf("%s: Corrupted packet length-sts %04x bytcnt %04x len %04x bank %04x\n",
583 sc->sc_dev.dv_xname, pktctlw, pktlen, len, smc->b2.bsr);
584 /* XXX ignore packet, or just truncate? */
585 #if defined(ESDEBUG) && defined(DDB)
586 if ((smc->b2.bsr & 0x0300) != BSR_BANK2)
587 Debugger();
588 #endif
589 smc->b2.bsr = BSR_BANK2;
590 smc->b2.mmucr = MMUCR_REMRLS_RX;
591 while (smc->b2.mmucr & MMUCR_BUSY)
592 ;
593 ++sc->sc_arpcom.ac_if.if_ierrors;
594 #ifdef ESDEBUG
595 if (--sc->sc_smcbusy) {
596 printf("%s: esrintr busy on bad packet exit\n",
597 sc->sc_dev.dv_xname);
598 panic("esrintr busy on exit");
599 }
600 #endif
601 return;
602 }
603 #ifdef USEPKTBUF
604 #if 0
605 lbuf = (u_long *) pktbuf;
606 ldata = (u_long *)data;
607 cnt = (len - 4) / 4;
608 while (cnt--)
609 *lbuf++ = *ldata;
610 if ((len - 4) & 2) {
611 buf = (u_short *) lbuf;
612 *buf = *data;
613 }
614 #else
615 buf = (u_short *)pktbuf;
616 cnt = (len - 4) / 2;
617 while (cnt--)
618 *buf++ = *data;
619 #endif
620 smc->b2.mmucr = MMUCR_REMRLS_RX;
621 while (smc->b2.mmucr & MMUCR_BUSY)
622 ;
623 #ifdef ESDEBUG
624 if (pktctlw & (RFSW_ALGNERR | RFSW_BADCRC | RFSW_TOOLNG | RFSW_TOOSHORT)) {
625 printf ("%s: Packet error %04x\n", sc->sc_dev.dv_xname, pktctlw);
626 /* count input error? */
627 }
628 if (esdebug) {
629 printf (" pktctlw %04x pktlen %04x fifo %04x\n", pktctlw, pktlen,
630 smc->b2.fifo);
631 for (i = 0; i < pktlen; ++i)
632 printf ("%02x%s", pktbuf[i], ((i & 31) == 31) ? "\n" :
633 "");
634 if (i & 31)
635 printf ("\n");
636 }
637 #endif
638 #else /* USEPKTBUF */
639 /* XXX copy directly from controller to mbuf */
640 #ifdef ESDEBUG
641 if (pktctlw & (RFSW_ALGNERR | RFSW_BADCRC | RFSW_TOOLNG | RFSW_TOOSHORT)) {
642 printf ("%s: Packet error %04x\n", sc->sc_dev.dv_xname, pktctlw);
643 /* count input error? */
644 }
645 if (esdebug) {
646 printf (" pktctlw %04x pktlen %04x fifo %04x\n", pktctlw, pktlen,
647 smc->b2.fifo);
648 }
649 #endif
650 #endif /* USEPKTBUF */
651 ifp = &sc->sc_arpcom.ac_if;
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 (sc->sc_arpcom.ac_if.if_bpf) {
716 bpf_mtap(sc->sc_arpcom.ac_if.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_arpcom.ac_if.if_flags & IFF_PROMISC) &&
724 (eh->ether_dhost[0] & 1) == 0 && /* !mcast and !bcast */
725 bcmp(eh->ether_dhost, sc->sc_arpcom.ac_enaddr,
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_arpcom.ac_if);
751 }
752
753 void
754 esstart(ifp)
755 struct ifnet *ifp;
756 {
757 struct es_softc *sc = es_cd.cd_devs[ifp->if_unit];
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 u_long *lbuf;
769 volatile u_long *ldata;
770 short cnt;
771 int i;
772 u_char active_pnr;
773
774 if ((sc->sc_arpcom.ac_if.if_flags & (IFF_RUNNING | IFF_OACTIVE)) !=
775 IFF_RUNNING)
776 return;
777
778 #ifdef ESDEBUG
779 if (sc->sc_smcbusy++) {
780 printf("%s: esstart re-entered\n", sc->sc_dev.dv_xname);
781 panic("esstart re-entred");
782 }
783 while ((smc->b2.bsr & 0x0300) != BSR_BANK2) {
784 printf("%s: esstart BSR not 2: %04x\n", sc->sc_dev.dv_xname,
785 smc->b2.bsr);
786 smc->b2.bsr = BSR_BANK2;
787 }
788 #endif
789 for (;;) {
790 int xxx;
791 /*
792 * Sneak a peek at the next packet to get the length
793 * and see if the SMC 91C90 can accept it.
794 */
795 m = sc->sc_arpcom.ac_if.if_snd.ifq_head;
796 if (!m)
797 break;
798 #ifdef ESDEBUG
799 if (esdebug && (m->m_next || m->m_len & 1))
800 printf("%s: esstart m_next %x m_len %d\n", sc->sc_dev.dv_xname,
801 m->m_next, m->m_len);
802 #endif
803 for (m0 = m, pktlen = 0; m0; m0 = m0->m_next)
804 pktlen += m0->m_len;
805 pktctlw = 0;
806 pktlen += 4;
807 if (pktlen & 1)
808 ++pktlen; /* control byte after last byte */
809 else
810 pktlen += 2; /* control byte after pad byte */
811 smc->b2.mmucr = MMUCR_ALLOC | (pktlen & 0x0700);
812 for (i = 0; i <= 5; ++i)
813 if ((smc->b2.arr & ARR_FAILED) == 0)
814 break;
815 if (smc->b2.arr & ARR_FAILED) {
816 sc->sc_arpcom.ac_if.if_flags |= IFF_OACTIVE;
817 sc->sc_intctl |= MSK_ALLOC;
818 break;
819 }
820 active_pnr = smc->b2.pnr = smc->b2.arr;
821
822 #ifdef ESDEBUG
823 while ((smc->b2.bsr & 0x0300) != BSR_BANK2) {
824 printf("%s: esstart+ BSR not 2: %04x\n", sc->sc_dev.dv_xname,
825 smc->b2.bsr);
826 smc->b2.bsr = BSR_BANK2;
827 }
828 #endif
829 IF_DEQUEUE(&sc->sc_arpcom.ac_if.if_snd, m);
830 xxx = splhigh();
831 smc->b2.ptr = PTR_AUTOINCR;
832 (void) smc->b2.mmucr;
833 data = (u_short *)&smc->b2.data;
834 *data = SWAP(pktctlw);
835 *data = SWAP(pktlen);
836 #ifdef ESDEBUG
837 while ((smc->b2.bsr & 0x0300) != BSR_BANK2) {
838 printf("%s: esstart++ BSR not 2: %04x\n", sc->sc_dev.dv_xname,
839 smc->b2.bsr);
840 smc->b2.bsr = BSR_BANK2;
841 }
842 #endif
843 #ifdef USEPKTBUF
844 i = 0;
845 for (m0 = m; m; m = m->m_next) {
846 bcopy(mtod(m, caddr_t), (char *)pktbuf + i, m->m_len);
847 i += m->m_len;
848 }
849
850 if (i & 1) /* Figure out where to put control byte */
851 pktbuf[i/2] = (pktbuf[i/2] & 0xff00) | CTLB_ODD;
852 else
853 pktbuf[i/2] = 0;
854 pktlen -= 4;
855 #ifdef ESDEBUG
856 if (pktlen > sizeof(pktbuf))
857 printf("%s: esstart packet longer than pktbuf\n",
858 sc->sc_dev.dv_xname);
859 #endif
860 #if 0 /* doesn't quite work? */
861 lbuf = (u_long *)(pktbuf);
862 ldata = (u_long *)data;
863 cnt = pktlen / 4;
864 while(cnt--)
865 *ldata = *lbuf++;
866 if (pktlen & 2) {
867 buf = (u_short *)lbuf;
868 *data = *buf;
869 }
870 #else
871 buf = pktbuf;
872 cnt = pktlen / 2;
873 while (cnt--)
874 *data = *buf++;
875 #endif
876 #else /* USEPKTBUF */
877 pktctlw = 0;
878 oddbyte = needbyte = 0;
879 for (m0 = m; m; m = m->m_next) {
880 buf = mtod(m, u_short *);
881 cnt = m->m_len / 2;
882 if (needbyte) {
883 oddbyte |= *buf >> 8;
884 *data = oddbyte;
885 }
886 while (cnt--)
887 *data = *buf++;
888 if (m->m_len & 1)
889 pktctlw = (*buf & 0xff00) | CTLB_ODD;
890 if (m->m_len & 1 && m->m_next)
891 printf("%s: esstart odd byte count in mbuf\n",
892 sc->sc_dev.dv_xname);
893 }
894 *data = pktctlw;
895 #endif /* USEPKTBUF */
896 splx(xxx);
897 #ifdef ESDEBUG
898 while ((smc->b2.bsr & 0x0300) != BSR_BANK2) {
899 printf("%s: esstart+++ BSR not 2: %04x\n", sc->sc_dev.dv_xname,
900 smc->b2.bsr);
901 smc->b2.bsr = BSR_BANK2;
902 }
903 #endif
904 smc->b2.mmucr = MMUCR_ENQ_TX;
905 if (smc->b2.pnr != active_pnr)
906 printf("%s: esstart - PNR changed %x->%x\n",
907 sc->sc_dev.dv_xname, active_pnr, smc->b2.pnr);
908 #if NBPFILTER > 0
909 if (sc->sc_arpcom.ac_if.if_bpf)
910 bpf_mtap(sc->sc_arpcom.ac_if.if_bpf, m0);
911 #endif
912 m_freem(m0);
913 sc->sc_arpcom.ac_if.if_opackets++; /* move to interrupt? */
914 sc->sc_intctl |= MSK_TX_EMPTY | MSK_TX;
915 }
916 smc->b2.msk = sc->sc_intctl;
917 #ifdef ESDEBUG
918 while ((smc->b2.bsr & 0x0300) != BSR_BANK2) {
919 printf("%s: esstart++++ BSR not 2: %04x\n", sc->sc_dev.dv_xname,
920 smc->b2.bsr);
921 smc->b2.bsr = BSR_BANK2;
922 }
923 if (--sc->sc_smcbusy) {
924 printf("%s: esstart busy on exit\n", sc->sc_dev.dv_xname);
925 panic("esstart busy on exit");
926 }
927 #endif
928 }
929
930 int
931 esioctl(ifp, command, data)
932 register struct ifnet *ifp;
933 u_long command;
934 caddr_t data;
935 {
936 struct es_softc *sc = es_cd.cd_devs[ifp->if_unit];
937 register struct ifaddr *ifa = (struct ifaddr *)data;
938 struct ifreq *ifr = (struct ifreq *)data;
939 int s, error = 0;
940
941 s = splnet();
942
943 switch (command) {
944
945 case SIOCSIFADDR:
946 ifp->if_flags |= IFF_UP;
947
948 switch (ifa->ifa_addr->sa_family) {
949 #ifdef INET
950 case AF_INET:
951 esinit(sc);
952 arp_ifinit(&sc->sc_arpcom, ifa);
953 break;
954 #endif
955 #ifdef NS
956 case AF_NS:
957 {
958 register struct ns_addr *ina = &IA_SNS(ifa)->sns_addr;
959
960 if (ns_nullhost(*ina))
961 ina->x_host =
962 *(union ns_host *)(sc->sc_arpcom.ac_enaddr);
963 else
964 bcopy(ina->x_host.c_host,
965 sc->sc_arpcom.ac_enaddr,
966 sizeof(sc->sc_arpcom.ac_enaddr));
967 /* Set new address. */
968 esinit(sc);
969 break;
970 #endif
971 default:
972 esinit(sc);
973 break;
974 }
975 break;
976
977 case SIOCSIFFLAGS:
978 /*
979 * If interface is marked down and it is running, then stop it
980 */
981 if ((ifp->if_flags & IFF_UP) == 0 &&
982 (ifp->if_flags & IFF_RUNNING) != 0) {
983 /*
984 * If interface is marked down and it is running, then
985 * stop it.
986 */
987 esstop(sc);
988 ifp->if_flags &= ~IFF_RUNNING;
989 } else if ((ifp->if_flags & IFF_UP) != 0 &&
990 (ifp->if_flags & IFF_RUNNING) == 0) {
991 /*
992 * If interface is marked up and it is stopped, then
993 * start it.
994 */
995 esinit(sc);
996 } else {
997 /*
998 * Reset the interface to pick up changes in any other
999 * flags that affect hardware registers.
1000 */
1001 esstop(sc);
1002 esinit(sc);
1003 }
1004 #ifdef ESDEBUG
1005 if (ifp->if_flags & IFF_DEBUG)
1006 esdebug = sc->sc_debug = 1;
1007 else
1008 esdebug = sc->sc_debug = 0;
1009 #endif
1010 break;
1011
1012 case SIOCADDMULTI:
1013 case SIOCDELMULTI:
1014 error = (command == SIOCADDMULTI) ?
1015 ether_addmulti(ifr, &sc->sc_arpcom) :
1016 ether_delmulti(ifr, &sc->sc_arpcom);
1017
1018 if (error == ENETRESET) {
1019 /*
1020 * Multicast list has changed; set the hardware filter
1021 * accordingly.
1022 */
1023 /* XXX */
1024 error = 0;
1025 }
1026 break;
1027
1028 default:
1029 error = EINVAL;
1030 }
1031
1032 splx(s);
1033 return (error);
1034 }
1035
1036 void
1037 esreset(sc)
1038 struct es_softc *sc;
1039 {
1040 int s;
1041
1042 s = splnet();
1043 esstop(sc);
1044 esinit(sc);
1045 splx(s);
1046 }
1047
1048 void
1049 eswatchdog(unit)
1050 int unit;
1051 {
1052 struct es_softc *sc = es_cd.cd_devs[unit];
1053
1054 log(LOG_ERR, "%s: device timeout\n", sc->sc_dev.dv_xname);
1055 ++sc->sc_arpcom.ac_if.if_oerrors;
1056
1057 esreset(sc);
1058 }
1059