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