if_bm.c revision 1.1.4.2 1 /* $NetBSD: if_bm.c,v 1.1.4.2 1999/07/01 23:12:04 thorpej Exp $ */
2
3 /*-
4 * Copyright (C) 1998, 1999 Tsubai Masanari. All rights reserved.
5 *
6 * Redistribution and use in source and binary forms, with or without
7 * modification, are permitted provided that the following conditions
8 * are met:
9 * 1. Redistributions of source code must retain the above copyright
10 * notice, this list of conditions and the following disclaimer.
11 * 2. Redistributions in binary form must reproduce the above copyright
12 * notice, this list of conditions and the following disclaimer in the
13 * documentation and/or other materials provided with the distribution.
14 * 3. The name of the author may not be used to endorse or promote products
15 * derived from this software without specific prior written permission.
16 *
17 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
18 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
19 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
20 * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
21 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
22 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
23 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
24 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
25 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
26 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
27 */
28
29 #include "opt_inet.h"
30 #include "opt_ns.h"
31 #include "bpfilter.h"
32
33 #include <sys/param.h>
34 #include <sys/device.h>
35 #include <sys/ioctl.h>
36 #include <sys/mbuf.h>
37 #include <sys/socket.h>
38 #include <sys/systm.h>
39
40 #include <net/if.h>
41 #include <net/if_ether.h>
42 #include <net/if_media.h>
43
44 #if NBPFILTER > 0
45 #include <net/bpf.h>
46 #include <net/bpfdesc.h>
47 #endif
48
49 #include <vm/vm.h>
50
51 #include <dev/ofw/openfirm.h>
52
53 #include <machine/autoconf.h>
54 #include <machine/pio.h>
55
56 #include <macppc/dev/dbdma.h>
57 #include <macppc/dev/if_bmreg.h>
58
59 #define BMAC_TXBUFS 2
60 #define BMAC_RXBUFS 16
61 #define BMAC_BUFLEN 2048
62
63 struct bmac_softc {
64 struct device sc_dev;
65 struct ethercom sc_ethercom;
66 #define sc_if sc_ethercom.ec_if
67 struct ifmedia sc_media;
68 vaddr_t sc_regs;
69 dbdma_regmap_t *sc_txdma;
70 dbdma_regmap_t *sc_rxdma;
71 dbdma_command_t *sc_txcmd;
72 dbdma_command_t *sc_rxcmd;
73 caddr_t sc_txbuf;
74 caddr_t sc_rxbuf;
75 int sc_rxlast;
76 int sc_flags;
77 int sc_debug;
78 u_char sc_enaddr[6];
79 };
80
81 #define BMAC_BMACPLUS 0x01
82
83 extern u_int *heathrow_FCR;
84
85 static __inline int bmac_read_reg __P((struct bmac_softc *, int));
86 static __inline void bmac_write_reg __P((struct bmac_softc *, int, int));
87 static __inline void bmac_set_bits __P((struct bmac_softc *, int, int));
88 static __inline void bmac_reset_bits __P((struct bmac_softc *, int, int));
89
90 static int bmac_match __P((struct device *, struct cfdata *, void *));
91 static void bmac_attach __P((struct device *, struct device *, void *));
92 static void bmac_reset_chip __P((struct bmac_softc *));
93 static void bmac_init __P((struct bmac_softc *));
94 static void bmac_init_dma __P((struct bmac_softc *));
95 static int bmac_intr __P((void *));
96 static int bmac_rint __P((void *));
97 static void bmac_reset __P((struct bmac_softc *));
98 static void bmac_stop __P((struct bmac_softc *));
99 static void bmac_start __P((struct ifnet *));
100 static void bmac_transmit_packet __P((struct bmac_softc *, void *, int));
101 static int bmac_put __P((struct bmac_softc *, caddr_t, struct mbuf *));
102 static struct mbuf *bmac_get __P((struct bmac_softc *, caddr_t, int));
103 static void bmac_watchdog __P((struct ifnet *));
104 static int bmac_ioctl __P((struct ifnet *, u_long, caddr_t));
105 static int bmac_mediachange __P((struct ifnet *));
106 static void bmac_mediastatus __P((struct ifnet *, struct ifmediareq *));
107 static void bmac_setladrf __P((struct bmac_softc *));
108
109 struct cfattach bm_ca = {
110 sizeof(struct bmac_softc), bmac_match, bmac_attach
111 };
112
113 int
114 bmac_read_reg(sc, off)
115 struct bmac_softc *sc;
116 int off;
117 {
118 return in16rb(sc->sc_regs + off);
119 }
120
121 void
122 bmac_write_reg(sc, off, val)
123 struct bmac_softc *sc;
124 int off, val;
125 {
126 out16rb(sc->sc_regs + off, val);
127 }
128
129 void
130 bmac_set_bits(sc, off, val)
131 struct bmac_softc *sc;
132 int off, val;
133 {
134 val |= bmac_read_reg(sc, off);
135 bmac_write_reg(sc, off, val);
136 }
137
138 void
139 bmac_reset_bits(sc, off, val)
140 struct bmac_softc *sc;
141 int off, val;
142 {
143 bmac_write_reg(sc, off, bmac_read_reg(sc, off) & ~val);
144 }
145
146 int
147 bmac_match(parent, cf, aux)
148 struct device *parent;
149 struct cfdata *cf;
150 void *aux;
151 {
152 struct confargs *ca = aux;
153
154 if (ca->ca_nreg < 24 || ca->ca_nintr < 12)
155 return 0;
156
157 if (strcmp(ca->ca_name, "bmac") == 0) /* bmac */
158 return 1;
159 if (strcmp(ca->ca_name, "ethernet") == 0) /* bmac+ */
160 return 1;
161
162 return 0;
163 }
164
165 void
166 bmac_attach(parent, self, aux)
167 struct device *parent, *self;
168 void *aux;
169 {
170 struct confargs *ca = aux;
171 struct bmac_softc *sc = (void *)self;
172 struct ifnet *ifp = &sc->sc_if;
173 u_char laddr[6];
174 int i;
175
176 sc->sc_flags =0;
177 if (strcmp(ca->ca_name, "ethernet") == 0) {
178 char name[64];
179
180 bzero(name, 64);
181 OF_package_to_path(ca->ca_node, name, sizeof(name));
182 OF_open(name);
183 sc->sc_flags |= BMAC_BMACPLUS;
184 }
185
186 ca->ca_reg[0] += ca->ca_baseaddr;
187 ca->ca_reg[2] += ca->ca_baseaddr;
188 ca->ca_reg[4] += ca->ca_baseaddr;
189
190 sc->sc_regs = (vaddr_t)mapiodev(ca->ca_reg[0], NBPG);
191
192 bmac_write_reg(sc, INTDISABLE, NoEventsMask);
193
194 if (OF_getprop(ca->ca_node, "local-mac-address", laddr, 6) == -1 &&
195 OF_getprop(ca->ca_node, "mac-address", laddr, 6) == -1) {
196 printf(": cannot get mac-address\n");
197 return;
198 }
199 bcopy(laddr, sc->sc_enaddr, 6);
200
201 sc->sc_txdma = mapiodev(ca->ca_reg[2], NBPG);
202 sc->sc_rxdma = mapiodev(ca->ca_reg[4], NBPG);
203 sc->sc_txcmd = dbdma_alloc(BMAC_TXBUFS * sizeof(dbdma_command_t));
204 sc->sc_rxcmd = dbdma_alloc((BMAC_RXBUFS + 1) * sizeof(dbdma_command_t));
205 sc->sc_txbuf = malloc(BMAC_BUFLEN * BMAC_TXBUFS, M_DEVBUF, M_NOWAIT);
206 sc->sc_rxbuf = malloc(BMAC_BUFLEN * BMAC_RXBUFS, M_DEVBUF, M_NOWAIT);
207 if (sc->sc_txbuf == NULL || sc->sc_rxbuf == NULL ||
208 sc->sc_txcmd == NULL || sc->sc_rxcmd == NULL) {
209 printf("cannot allocate memory\n");
210 return;
211 }
212
213 printf(" irq %d,%d: address %s\n", ca->ca_intr[0], ca->ca_intr[2],
214 ether_sprintf(laddr));
215
216 intr_establish(ca->ca_intr[0], IST_LEVEL, IPL_NET, bmac_intr, sc);
217 intr_establish(ca->ca_intr[2], IST_LEVEL, IPL_NET, bmac_rint, sc);
218
219 bcopy(sc->sc_dev.dv_xname, ifp->if_xname, IFNAMSIZ);
220 ifp->if_softc = sc;
221 ifp->if_ioctl = bmac_ioctl;
222 ifp->if_start = bmac_start;
223 ifp->if_flags =
224 IFF_BROADCAST | IFF_SIMPLEX | IFF_NOTRAILERS | IFF_MULTICAST;
225 ifp->if_watchdog = bmac_watchdog;
226
227 ifmedia_init(&sc->sc_media, 0, bmac_mediachange, bmac_mediastatus);
228 ifmedia_add(&sc->sc_media, IFM_ETHER|IFM_10_T, 0, NULL);
229 ifmedia_set(&sc->sc_media, IFM_ETHER|IFM_10_T);
230
231 bmac_reset_chip(sc);
232
233 if_attach(ifp);
234 ether_ifattach(ifp, sc->sc_enaddr);
235
236 #if NBPFILTER > 0
237 bpfattach(&ifp->if_bpf, ifp, DLT_EN10MB, sizeof(struct ether_header));
238 #endif
239 }
240
241 /*
242 * Reset and enable bmac by heathrow FCR.
243 */
244 void
245 bmac_reset_chip(sc)
246 struct bmac_softc *sc;
247 {
248 u_int v;
249
250 dbdma_reset(sc->sc_txdma);
251 dbdma_reset(sc->sc_rxdma);
252
253 v = in32rb(heathrow_FCR);
254
255 v |= EnetEnable;
256 out32rb(heathrow_FCR, v);
257 delay(50000);
258
259 v |= ResetEnetCell;
260 out32rb(heathrow_FCR, v);
261 delay(50000);
262
263 v &= ~ResetEnetCell;
264 out32rb(heathrow_FCR, v);
265 delay(50000);
266
267 out32rb(heathrow_FCR, v);
268 }
269
270 void
271 bmac_init(sc)
272 struct bmac_softc *sc;
273 {
274 struct ifnet *ifp = &sc->sc_if;
275 struct ether_header *eh;
276 caddr_t data;
277 int i, tb;
278 u_short *p;
279
280 bmac_reset_chip(sc);
281
282 bmac_write_reg(sc, RXRST, RxResetValue);
283 bmac_write_reg(sc, TXRST, TxResetBit);
284
285 /* Wait for reset completion. */
286 while (bmac_read_reg(sc, TXRST) & TxResetBit);
287
288 if (! (sc->sc_flags & BMAC_BMACPLUS))
289 bmac_set_bits(sc, XCVRIF, ClkBit|SerialMode|COLActiveLow);
290
291 __asm __volatile ("mftb %0" : "=r"(tb));
292 bmac_write_reg(sc, RSEED, tb);
293 bmac_set_bits(sc, XIFC, TxOutputEnable);
294 bmac_read_reg(sc, PAREG);
295
296 /* Reset various counters. */
297 bmac_write_reg(sc, NCCNT, 0);
298 bmac_write_reg(sc, NTCNT, 0);
299 bmac_write_reg(sc, EXCNT, 0);
300 bmac_write_reg(sc, LTCNT, 0);
301 bmac_write_reg(sc, FRCNT, 0);
302 bmac_write_reg(sc, LECNT, 0);
303 bmac_write_reg(sc, AECNT, 0);
304 bmac_write_reg(sc, FECNT, 0);
305 bmac_write_reg(sc, RXCV, 0);
306
307 /* Set tx fifo information. */
308 bmac_write_reg(sc, TXTH, 4); /* 4 octets before tx starts */
309
310 bmac_write_reg(sc, TXFIFOCSR, 0);
311 bmac_write_reg(sc, TXFIFOCSR, TxFIFOEnable);
312
313 /* Set rx fifo information. */
314 bmac_write_reg(sc, RXFIFOCSR, 0);
315 bmac_write_reg(sc, RXFIFOCSR, RxFIFOEnable);
316
317 /* Clear status register. */
318 bmac_read_reg(sc, STATUS);
319
320 bmac_write_reg(sc, HASH3, 0);
321 bmac_write_reg(sc, HASH2, 0);
322 bmac_write_reg(sc, HASH1, 0);
323 bmac_write_reg(sc, HASH0, 0);
324
325 /* Set MAC address. */
326 p = (u_short *)sc->sc_enaddr;
327 bmac_write_reg(sc, MADD0, *p++);
328 bmac_write_reg(sc, MADD1, *p++);
329 bmac_write_reg(sc, MADD2, *p);
330
331 bmac_write_reg(sc, RXCFG,
332 RxCRCEnable | RxHashFilterEnable | RxRejectOwnPackets);
333
334 if (ifp->if_flags & IFF_PROMISC)
335 bmac_set_bits(sc, RXCFG, RxPromiscEnable);
336
337 bmac_init_dma(sc);
338
339 /* Enable TX/RX */
340 bmac_set_bits(sc, RXCFG, RxMACEnable);
341 bmac_set_bits(sc, TXCFG, TxMACEnable);
342
343 bmac_write_reg(sc, INTDISABLE, NormalIntEvents);
344
345 ifp->if_flags |= IFF_RUNNING;
346 ifp->if_flags &= ~IFF_OACTIVE;
347 ifp->if_timer = 0;
348
349 data = sc->sc_txbuf;
350 eh = (struct ether_header *)data;
351
352 bzero(data, sizeof(eh) + ETHERMIN);
353 bcopy(sc->sc_enaddr, eh->ether_dhost, ETHER_ADDR_LEN);
354 bcopy(sc->sc_enaddr, eh->ether_shost, ETHER_ADDR_LEN);
355 bmac_transmit_packet(sc, data, sizeof(eh) + ETHERMIN);
356
357 bmac_start(ifp);
358 }
359
360 void
361 bmac_init_dma(sc)
362 struct bmac_softc *sc;
363 {
364 dbdma_command_t *cmd = sc->sc_rxcmd;
365 int i;
366
367 dbdma_reset(sc->sc_txdma);
368 dbdma_reset(sc->sc_rxdma);
369
370 bzero(sc->sc_txcmd, BMAC_TXBUFS * sizeof(dbdma_command_t));
371 bzero(sc->sc_rxcmd, (BMAC_RXBUFS + 1) * sizeof(dbdma_command_t));
372
373 for (i = 0; i < BMAC_RXBUFS; i++) {
374 DBDMA_BUILD(cmd, DBDMA_CMD_IN_LAST, 0, BMAC_BUFLEN,
375 vtophys(sc->sc_rxbuf + BMAC_BUFLEN * i),
376 DBDMA_INT_ALWAYS, DBDMA_WAIT_NEVER, DBDMA_BRANCH_NEVER);
377 cmd++;
378 }
379 DBDMA_BUILD(cmd, DBDMA_CMD_NOP, 0, 0, 0,
380 DBDMA_INT_NEVER, DBDMA_WAIT_NEVER, DBDMA_BRANCH_ALWAYS);
381 dbdma_st32(&cmd->d_cmddep, vtophys(sc->sc_rxcmd));
382
383 sc->sc_rxlast = 0;
384
385 dbdma_start(sc->sc_rxdma, sc->sc_rxcmd);
386 }
387
388 int
389 bmac_intr(v)
390 void *v;
391 {
392 struct bmac_softc *sc = v;
393 int stat;
394
395 stat = bmac_read_reg(sc, STATUS);
396 if (stat == 0)
397 return 0;
398
399 #ifdef BMAC_DEBUG
400 printf("bmac_intr status = 0x%x\n", stat);
401 #endif
402
403 if (stat & IntFrameSent) {
404 sc->sc_if.if_flags &= ~IFF_OACTIVE;
405 sc->sc_if.if_timer = 0;
406 sc->sc_if.if_opackets++;
407 bmac_start(&sc->sc_if);
408 }
409
410 /* XXX should do more! */
411
412 return 1;
413 }
414
415 int
416 bmac_rint(v)
417 void *v;
418 {
419 struct bmac_softc *sc = v;
420 struct ifnet *ifp = &sc->sc_if;
421 struct mbuf *m;
422 dbdma_command_t *cmd;
423 int status, resid, count, datalen;
424 int i, n;
425 void *data;
426
427 i = sc->sc_rxlast;
428 for (n = 0; n < BMAC_RXBUFS; n++, i++) {
429 if (i == BMAC_RXBUFS)
430 i = 0;
431 cmd = &sc->sc_rxcmd[i];
432 status = dbdma_ld16(&cmd->d_status);
433 resid = dbdma_ld16(&cmd->d_resid);
434
435 #ifdef BMAC_DEBUG
436 if (status != 0 && status != 0x8440 && status != 0x9440)
437 printf("bmac_rint status = 0x%x\n", status);
438 #endif
439
440 if ((status & DBDMA_CNTRL_ACTIVE) == 0) /* 0x9440 | 0x8440 */
441 continue;
442 count = dbdma_ld16(&cmd->d_count);
443 datalen = count - resid;
444 if (datalen < sizeof(struct ether_header)) {
445 printf("%s: short packet len = %d\n",
446 ifp->if_xname, datalen);
447 goto next;
448 }
449 DBDMA_BUILD_CMD(cmd, DBDMA_CMD_STOP, 0, 0, 0, 0);
450 data = sc->sc_rxbuf + BMAC_BUFLEN * i;
451 m = bmac_get(sc, data, datalen);
452
453 if (m == NULL) {
454 ifp->if_ierrors++;
455 goto next;
456 }
457
458 #if NBPFILTER > 0
459 /*
460 * Check if there's a BPF listener on this interface.
461 * If so, hand off the raw packet to BPF.
462 */
463 if (ifp->if_bpf)
464 bpf_mtap(ifp->if_bpf, m);
465 #endif
466 (*ifp->if_input)(ifp, m);
467 ifp->if_ipackets++;
468
469 next:
470 DBDMA_BUILD_CMD(cmd, DBDMA_CMD_IN_LAST, 0, DBDMA_INT_ALWAYS,
471 DBDMA_WAIT_NEVER, DBDMA_BRANCH_NEVER);
472
473 cmd->d_status = 0;
474 cmd->d_resid = 0;
475 sc->sc_rxlast = i + 1;
476 }
477 dbdma_continue(sc->sc_rxdma);
478
479 return 1;
480 }
481
482 void
483 bmac_reset(sc)
484 struct bmac_softc *sc;
485 {
486 int s;
487
488 s = splnet();
489 bmac_init(sc);
490 splx(s);
491 }
492
493 void
494 bmac_stop(sc)
495 struct bmac_softc *sc;
496 {
497 struct ifnet *ifp = &sc->sc_if;
498 int s;
499
500 s = splnet();
501
502 /* Disable TX/RX. */
503 bmac_reset_bits(sc, TXCFG, TxMACEnable);
504 bmac_reset_bits(sc, RXCFG, RxMACEnable);
505
506 /* Disable all interrupts. */
507 bmac_write_reg(sc, INTDISABLE, NoEventsMask);
508
509 dbdma_stop(sc->sc_txdma);
510 dbdma_stop(sc->sc_rxdma);
511
512 ifp->if_flags &= ~(IFF_UP | IFF_RUNNING);
513 ifp->if_timer = 0;
514
515 splx(s);
516 }
517
518 void
519 bmac_start(ifp)
520 struct ifnet *ifp;
521 {
522 struct bmac_softc *sc = ifp->if_softc;
523 struct mbuf *m;
524 int tlen;
525
526 if ((ifp->if_flags & (IFF_RUNNING | IFF_OACTIVE)) != IFF_RUNNING)
527 return;
528
529 while (1) {
530 if (ifp->if_flags & IFF_OACTIVE)
531 return;
532
533 IF_DEQUEUE(&ifp->if_snd, m);
534 if (m == 0)
535 break;
536 #if NBPFILTER > 0
537 /*
538 * If BPF is listening on this interface, let it see the
539 * packet before we commit it to the wire.
540 */
541 if (ifp->if_bpf)
542 bpf_mtap(ifp->if_bpf, m);
543 #endif
544
545 ifp->if_flags |= IFF_OACTIVE;
546 tlen = bmac_put(sc, sc->sc_txbuf, m);
547
548 /* 5 seconds to watch for failing to transmit */
549 ifp->if_timer = 5;
550 ifp->if_opackets++; /* # of pkts */
551
552 bmac_transmit_packet(sc, sc->sc_txbuf, tlen);
553 }
554 }
555
556 void
557 bmac_transmit_packet(sc, buff, len)
558 struct bmac_softc *sc;
559 void *buff;
560 int len;
561 {
562 dbdma_command_t *cmd = sc->sc_txcmd;
563 vaddr_t va = (vaddr_t)buff;
564
565 #ifdef BMAC_DEBUG
566 if (vtophys(va) + len - 1 != vtophys(va + len - 1))
567 panic("bmac_transmit_packet");
568 #endif
569
570 DBDMA_BUILD(cmd, DBDMA_CMD_OUT_LAST, 0, len, vtophys(va),
571 DBDMA_INT_NEVER, DBDMA_WAIT_NEVER, DBDMA_BRANCH_NEVER);
572 cmd++;
573 DBDMA_BUILD(cmd, DBDMA_CMD_STOP, 0, 0, 0,
574 DBDMA_INT_ALWAYS, DBDMA_WAIT_NEVER, DBDMA_BRANCH_NEVER);
575
576 dbdma_start(sc->sc_txdma, sc->sc_txcmd);
577 }
578
579 int
580 bmac_put(sc, buff, m)
581 struct bmac_softc *sc;
582 caddr_t buff;
583 struct mbuf *m;
584 {
585 struct mbuf *n;
586 int len, tlen = 0;
587
588 for (; m; m = n) {
589 len = m->m_len;
590 if (len == 0) {
591 MFREE(m, n);
592 continue;
593 }
594 bcopy(mtod(m, caddr_t), buff, len);
595 buff += len;
596 tlen += len;
597 MFREE(m, n);
598 }
599 if (tlen > NBPG)
600 panic("%s: putpacket packet overflow", sc->sc_dev.dv_xname);
601
602 return tlen;
603 }
604
605 struct mbuf *
606 bmac_get(sc, pkt, totlen)
607 struct bmac_softc *sc;
608 caddr_t pkt;
609 int totlen;
610 {
611 struct mbuf *m;
612 struct mbuf *top, **mp;
613 int len;
614
615 MGETHDR(m, M_DONTWAIT, MT_DATA);
616 if (m == 0)
617 return 0;
618 m->m_pkthdr.rcvif = &sc->sc_if;
619 m->m_pkthdr.len = totlen;
620 len = MHLEN;
621 top = 0;
622 mp = ⊤
623
624 while (totlen > 0) {
625 if (top) {
626 MGET(m, M_DONTWAIT, MT_DATA);
627 if (m == 0) {
628 m_freem(top);
629 return 0;
630 }
631 len = MLEN;
632 }
633 if (totlen >= MINCLSIZE) {
634 MCLGET(m, M_DONTWAIT);
635 if ((m->m_flags & M_EXT) == 0) {
636 m_free(m);
637 m_freem(top);
638 return 0;
639 }
640 len = MCLBYTES;
641 }
642 m->m_len = len = min(totlen, len);
643 bcopy(pkt, mtod(m, caddr_t), len);
644 pkt += len;
645 totlen -= len;
646 *mp = m;
647 mp = &m->m_next;
648 }
649
650 return top;
651 }
652
653 void
654 bmac_watchdog(ifp)
655 struct ifnet *ifp;
656 {
657 struct bmac_softc *sc = ifp->if_softc;
658
659 bmac_reset_bits(sc, RXCFG, RxMACEnable);
660 bmac_reset_bits(sc, TXCFG, TxMACEnable);
661
662 printf("%s: device timeout\n", ifp->if_xname);
663 ifp->if_oerrors++;
664
665 bmac_reset(sc);
666 }
667
668 int
669 bmac_ioctl(ifp, cmd, data)
670 struct ifnet *ifp;
671 u_long cmd;
672 caddr_t data;
673 {
674 struct bmac_softc *sc = ifp->if_softc;
675 struct ifaddr *ifa = (struct ifaddr *)data;
676 struct ifreq *ifr = (struct ifreq *)data;
677 int s, error = 0;
678 int temp;
679
680 s = splnet();
681
682 switch (cmd) {
683
684 case SIOCSIFADDR:
685 ifp->if_flags |= IFF_UP;
686
687 switch (ifa->ifa_addr->sa_family) {
688 #ifdef INET
689 case AF_INET:
690 bmac_init(sc);
691 arp_ifinit(ifp, ifa);
692 break;
693 #endif
694 #ifdef NS
695 case AF_NS:
696 {
697 struct ns_addr *ina = &IA_SNS(ifa)->sns_addr;
698
699 if (ns_nullhost(*ina))
700 ina->x_host =
701 *(union ns_host *)LLADDR(ifp->if_sadl);
702 else {
703 bcopy(ina->x_host.c_host,
704 LLADDR(ifp->if_sadl),
705 sizeof(sc->sc_enaddr));
706 }
707 /* Set new address. */
708 bmac_init(sc);
709 break;
710 }
711 #endif
712 default:
713 bmac_init(sc);
714 break;
715 }
716 break;
717
718 case SIOCSIFFLAGS:
719 if ((ifp->if_flags & IFF_UP) == 0 &&
720 (ifp->if_flags & IFF_RUNNING) != 0) {
721 /*
722 * If interface is marked down and it is running, then
723 * stop it.
724 */
725 bmac_stop(sc);
726 ifp->if_flags &= ~IFF_RUNNING;
727 } else if ((ifp->if_flags & IFF_UP) != 0 &&
728 (ifp->if_flags & IFF_RUNNING) == 0) {
729 /*
730 * If interface is marked up and it is stopped, then
731 * start it.
732 */
733 bmac_init(sc);
734 } else {
735 /*
736 * Reset the interface to pick up changes in any other
737 * flags that affect hardware registers.
738 */
739 /*bmac_stop(sc);*/
740 bmac_init(sc);
741 }
742 #ifdef BMAC_DEBUG
743 if (ifp->if_flags & IFF_DEBUG)
744 sc->sc_debug = 1;
745 else
746 sc->sc_debug = 0;
747 #endif
748 break;
749
750 case SIOCADDMULTI:
751 case SIOCDELMULTI:
752 error = (cmd == SIOCADDMULTI) ?
753 ether_addmulti(ifr, &sc->sc_ethercom) :
754 ether_delmulti(ifr, &sc->sc_ethercom);
755
756 if (error == ENETRESET) {
757 /*
758 * Multicast list has changed; set the hardware filter
759 * accordingly.
760 */
761 bmac_init(sc);
762 bmac_setladrf(sc);
763 error = 0;
764 }
765 break;
766
767 case SIOCGIFMEDIA:
768 case SIOCSIFMEDIA:
769 error = ifmedia_ioctl(ifp, ifr, &sc->sc_media, cmd);
770 break;
771
772 default:
773 error = EINVAL;
774 }
775
776 splx(s);
777 return error;
778 }
779
780 int
781 bmac_mediachange(ifp)
782 struct ifnet *ifp;
783 {
784 return EINVAL;
785 }
786
787 void
788 bmac_mediastatus(ifp, ifmr)
789 struct ifnet *ifp;
790 struct ifmediareq *ifmr;
791 {
792 if ((ifp->if_flags & IFF_UP) == 0)
793 return;
794
795 ifmr->ifm_status = IFM_AVALID;
796 ifmr->ifm_status |= IFM_ACTIVE;
797 }
798
799 #define MC_POLY_BE 0x04c11db7UL /* mcast crc, big endian */
800 #define MC_POLY_LE 0xedb88320UL /* mcast crc, little endian */
801
802 /*
803 * Set up the logical address filter.
804 */
805 void
806 bmac_setladrf(sc)
807 struct bmac_softc *sc;
808 {
809 struct ifnet *ifp = &sc->sc_if;
810 struct ether_multi *enm;
811 struct ether_multistep step;
812 int i, j;
813 u_int32_t crc;
814 u_int16_t hash[4];
815 u_int8_t octet;
816
817 /*
818 * Set up multicast address filter by passing all multicast addresses
819 * through a crc generator, and then using the high order 6 bits as an
820 * index into the 64 bit logical address filter. The high order bit
821 * selects the word, while the rest of the bits select the bit within
822 * the word.
823 */
824
825 if (ifp->if_flags & IFF_ALLMULTI)
826 goto allmulti;
827
828 if (ifp->if_flags & IFF_PROMISC) {
829 bmac_set_bits(sc, RXCFG, RxPromiscEnable);
830 goto allmulti;
831 }
832
833 hash[3] = hash[2] = hash[1] = hash[0] = 0;
834 ETHER_FIRST_MULTI(step, &sc->sc_ethercom, enm);
835 while (enm != NULL) {
836 if (bcmp(enm->enm_addrlo, enm->enm_addrhi, ETHER_ADDR_LEN)) {
837 /*
838 * We must listen to a range of multicast addresses.
839 * For now, just accept all multicasts, rather than
840 * trying to set only those filter bits needed to match
841 * the range. (At this time, the only use of address
842 * ranges is for IP multicast routing, for which the
843 * range is big enough to require all bits set.)
844 */
845 goto allmulti;
846 }
847
848 crc = 0xffffffff;
849 for (i = 0; i < ETHER_ADDR_LEN; i++) {
850 octet = enm->enm_addrlo[i];
851
852 for (j = 0; j < 8; j++) {
853 if ((crc & 1) ^ (octet & 1)) {
854 crc >>= 1;
855 crc ^= MC_POLY_LE;
856 }
857 else
858 crc >>= 1;
859 octet >>= 1;
860 }
861 }
862
863 /* Just want the 6 most significant bits. */
864 crc >>= 26;
865
866 /* Set the corresponding bit in the filter. */
867 hash[crc >> 4] |= 1 << (crc & 0xf);
868
869 ETHER_NEXT_MULTI(step, enm);
870 }
871 bmac_write_reg(sc, HASH3, hash[3]);
872 bmac_write_reg(sc, HASH2, hash[2]);
873 bmac_write_reg(sc, HASH1, hash[1]);
874 bmac_write_reg(sc, HASH0, hash[0]);
875 ifp->if_flags &= ~IFF_ALLMULTI;
876 return;
877
878 allmulti:
879 ifp->if_flags |= IFF_ALLMULTI;
880 bmac_write_reg(sc, HASH3, 0xffff);
881 bmac_write_reg(sc, HASH2, 0xffff);
882 bmac_write_reg(sc, HASH1, 0xffff);
883 bmac_write_reg(sc, HASH0, 0xffff);
884 }
885