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