1 /* $NetBSD: if_bm.c,v 1.19 2002/10/02 05:30:41 thorpej 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 <uvm/uvm_extern.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 CFATTACH_DECL(bm, sizeof(struct bmac_softc), 128 bmac_match, bmac_attach, NULL, NULL); 129 130 struct mii_bitbang_ops bmac_mbo = { 131 bmac_mbo_read, bmac_mbo_write, 132 { MIFDO, MIFDI, MIFDC, MIFDIR, 0 } 133 }; 134 135 int 136 bmac_read_reg(sc, off) 137 struct bmac_softc *sc; 138 int off; 139 { 140 return in16rb(sc->sc_regs + off); 141 } 142 143 void 144 bmac_write_reg(sc, off, val) 145 struct bmac_softc *sc; 146 int off, val; 147 { 148 out16rb(sc->sc_regs + off, val); 149 } 150 151 void 152 bmac_set_bits(sc, off, val) 153 struct bmac_softc *sc; 154 int off, val; 155 { 156 val |= bmac_read_reg(sc, off); 157 bmac_write_reg(sc, off, val); 158 } 159 160 void 161 bmac_reset_bits(sc, off, val) 162 struct bmac_softc *sc; 163 int off, val; 164 { 165 bmac_write_reg(sc, off, bmac_read_reg(sc, off) & ~val); 166 } 167 168 int 169 bmac_match(parent, cf, aux) 170 struct device *parent; 171 struct cfdata *cf; 172 void *aux; 173 { 174 struct confargs *ca = aux; 175 176 if (ca->ca_nreg < 24 || ca->ca_nintr < 12) 177 return 0; 178 179 if (strcmp(ca->ca_name, "bmac") == 0) /* bmac */ 180 return 1; 181 if (strcmp(ca->ca_name, "ethernet") == 0) /* bmac+ */ 182 return 1; 183 184 return 0; 185 } 186 187 void 188 bmac_attach(parent, self, aux) 189 struct device *parent, *self; 190 void *aux; 191 { 192 struct confargs *ca = aux; 193 struct bmac_softc *sc = (void *)self; 194 struct ifnet *ifp = &sc->sc_if; 195 struct mii_data *mii = &sc->sc_mii; 196 u_char laddr[6]; 197 198 callout_init(&sc->sc_tick_ch); 199 200 sc->sc_flags =0; 201 if (strcmp(ca->ca_name, "ethernet") == 0) { 202 char name[64]; 203 204 memset(name, 0, 64); 205 OF_package_to_path(ca->ca_node, name, sizeof(name)); 206 OF_open(name); 207 sc->sc_flags |= BMAC_BMACPLUS; 208 } 209 210 ca->ca_reg[0] += ca->ca_baseaddr; 211 ca->ca_reg[2] += ca->ca_baseaddr; 212 ca->ca_reg[4] += ca->ca_baseaddr; 213 214 sc->sc_regs = (vaddr_t)mapiodev(ca->ca_reg[0], NBPG); 215 216 bmac_write_reg(sc, INTDISABLE, NoEventsMask); 217 218 if (OF_getprop(ca->ca_node, "local-mac-address", laddr, 6) == -1 && 219 OF_getprop(ca->ca_node, "mac-address", laddr, 6) == -1) { 220 printf(": cannot get mac-address\n"); 221 return; 222 } 223 memcpy(sc->sc_enaddr, laddr, 6); 224 225 sc->sc_txdma = mapiodev(ca->ca_reg[2], NBPG); 226 sc->sc_rxdma = mapiodev(ca->ca_reg[4], NBPG); 227 sc->sc_txcmd = dbdma_alloc(BMAC_TXBUFS * sizeof(dbdma_command_t)); 228 sc->sc_rxcmd = dbdma_alloc((BMAC_RXBUFS + 1) * sizeof(dbdma_command_t)); 229 sc->sc_txbuf = malloc(BMAC_BUFLEN * BMAC_TXBUFS, M_DEVBUF, M_NOWAIT); 230 sc->sc_rxbuf = malloc(BMAC_BUFLEN * BMAC_RXBUFS, M_DEVBUF, M_NOWAIT); 231 if (sc->sc_txbuf == NULL || sc->sc_rxbuf == NULL || 232 sc->sc_txcmd == NULL || sc->sc_rxcmd == NULL) { 233 printf("cannot allocate memory\n"); 234 return; 235 } 236 237 printf(" irq %d,%d: address %s\n", ca->ca_intr[0], ca->ca_intr[2], 238 ether_sprintf(laddr)); 239 240 intr_establish(ca->ca_intr[0], IST_LEVEL, IPL_NET, bmac_intr, sc); 241 intr_establish(ca->ca_intr[2], IST_LEVEL, IPL_NET, bmac_rint, sc); 242 243 memcpy(ifp->if_xname, sc->sc_dev.dv_xname, IFNAMSIZ); 244 ifp->if_softc = sc; 245 ifp->if_ioctl = bmac_ioctl; 246 ifp->if_start = bmac_start; 247 ifp->if_flags = 248 IFF_BROADCAST | IFF_SIMPLEX | IFF_NOTRAILERS | IFF_MULTICAST; 249 ifp->if_watchdog = bmac_watchdog; 250 IFQ_SET_READY(&ifp->if_snd); 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 274 /* 275 * Reset and enable bmac by heathrow FCR. 276 */ 277 void 278 bmac_reset_chip(sc) 279 struct bmac_softc *sc; 280 { 281 u_int v; 282 283 dbdma_reset(sc->sc_txdma); 284 dbdma_reset(sc->sc_rxdma); 285 286 v = in32rb(heathrow_FCR); 287 288 v |= EnetEnable; 289 out32rb(heathrow_FCR, v); 290 delay(50000); 291 292 v |= ResetEnetCell; 293 out32rb(heathrow_FCR, v); 294 delay(50000); 295 296 v &= ~ResetEnetCell; 297 out32rb(heathrow_FCR, v); 298 delay(50000); 299 300 out32rb(heathrow_FCR, v); 301 } 302 303 void 304 bmac_init(sc) 305 struct bmac_softc *sc; 306 { 307 struct ifnet *ifp = &sc->sc_if; 308 struct ether_header *eh; 309 caddr_t data; 310 int i, tb, bmcr; 311 u_short *p; 312 313 bmac_reset_chip(sc); 314 315 /* XXX */ 316 bmcr = bmac_mii_readreg((struct device *)sc, 0, MII_BMCR); 317 bmcr &= ~BMCR_ISO; 318 bmac_mii_writereg((struct device *)sc, 0, MII_BMCR, bmcr); 319 320 bmac_write_reg(sc, RXRST, RxResetValue); 321 bmac_write_reg(sc, TXRST, TxResetBit); 322 323 /* Wait for reset completion. */ 324 for (i = 1000; i > 0; i -= 10) { 325 if ((bmac_read_reg(sc, TXRST) & TxResetBit) == 0) 326 break; 327 delay(10); 328 } 329 if (i <= 0) 330 printf("%s: reset timeout\n", ifp->if_xname); 331 332 if (! (sc->sc_flags & BMAC_BMACPLUS)) 333 bmac_set_bits(sc, XCVRIF, ClkBit|SerialMode|COLActiveLow); 334 335 __asm __volatile ("mftb %0" : "=r"(tb)); 336 bmac_write_reg(sc, RSEED, tb); 337 bmac_set_bits(sc, XIFC, TxOutputEnable); 338 bmac_read_reg(sc, PAREG); 339 340 /* Reset various counters. */ 341 bmac_write_reg(sc, NCCNT, 0); 342 bmac_write_reg(sc, NTCNT, 0); 343 bmac_write_reg(sc, EXCNT, 0); 344 bmac_write_reg(sc, LTCNT, 0); 345 bmac_write_reg(sc, FRCNT, 0); 346 bmac_write_reg(sc, LECNT, 0); 347 bmac_write_reg(sc, AECNT, 0); 348 bmac_write_reg(sc, FECNT, 0); 349 bmac_write_reg(sc, RXCV, 0); 350 351 /* Set tx fifo information. */ 352 bmac_write_reg(sc, TXTH, 4); /* 4 octets before tx starts */ 353 354 bmac_write_reg(sc, TXFIFOCSR, 0); 355 bmac_write_reg(sc, TXFIFOCSR, TxFIFOEnable); 356 357 /* Set rx fifo information. */ 358 bmac_write_reg(sc, RXFIFOCSR, 0); 359 bmac_write_reg(sc, RXFIFOCSR, RxFIFOEnable); 360 361 /* Clear status register. */ 362 bmac_read_reg(sc, STATUS); 363 364 bmac_write_reg(sc, HASH3, 0); 365 bmac_write_reg(sc, HASH2, 0); 366 bmac_write_reg(sc, HASH1, 0); 367 bmac_write_reg(sc, HASH0, 0); 368 369 /* Set MAC address. */ 370 p = (u_short *)sc->sc_enaddr; 371 bmac_write_reg(sc, MADD0, *p++); 372 bmac_write_reg(sc, MADD1, *p++); 373 bmac_write_reg(sc, MADD2, *p); 374 375 bmac_write_reg(sc, RXCFG, 376 RxCRCEnable | RxHashFilterEnable | RxRejectOwnPackets); 377 378 if (ifp->if_flags & IFF_PROMISC) 379 bmac_set_bits(sc, RXCFG, RxPromiscEnable); 380 381 bmac_init_dma(sc); 382 383 /* Enable TX/RX */ 384 bmac_set_bits(sc, RXCFG, RxMACEnable); 385 bmac_set_bits(sc, TXCFG, TxMACEnable); 386 387 bmac_write_reg(sc, INTDISABLE, NormalIntEvents); 388 389 ifp->if_flags |= IFF_RUNNING; 390 ifp->if_flags &= ~IFF_OACTIVE; 391 ifp->if_timer = 0; 392 393 data = sc->sc_txbuf; 394 eh = (struct ether_header *)data; 395 396 memset(data, 0, sizeof(eh) + ETHERMIN); 397 memcpy(eh->ether_dhost, sc->sc_enaddr, ETHER_ADDR_LEN); 398 memcpy(eh->ether_shost, sc->sc_enaddr, ETHER_ADDR_LEN); 399 bmac_transmit_packet(sc, data, sizeof(eh) + ETHERMIN); 400 401 bmac_start(ifp); 402 403 callout_reset(&sc->sc_tick_ch, hz, bmac_mii_tick, sc); 404 } 405 406 void 407 bmac_init_dma(sc) 408 struct bmac_softc *sc; 409 { 410 dbdma_command_t *cmd = sc->sc_rxcmd; 411 int i; 412 413 dbdma_reset(sc->sc_txdma); 414 dbdma_reset(sc->sc_rxdma); 415 416 memset(sc->sc_txcmd, 0, BMAC_TXBUFS * sizeof(dbdma_command_t)); 417 memset(sc->sc_rxcmd, 0, (BMAC_RXBUFS + 1) * sizeof(dbdma_command_t)); 418 419 for (i = 0; i < BMAC_RXBUFS; i++) { 420 DBDMA_BUILD(cmd, DBDMA_CMD_IN_LAST, 0, BMAC_BUFLEN, 421 vtophys((vaddr_t)sc->sc_rxbuf + BMAC_BUFLEN * i), 422 DBDMA_INT_ALWAYS, DBDMA_WAIT_NEVER, DBDMA_BRANCH_NEVER); 423 cmd++; 424 } 425 DBDMA_BUILD(cmd, DBDMA_CMD_NOP, 0, 0, 0, 426 DBDMA_INT_NEVER, DBDMA_WAIT_NEVER, DBDMA_BRANCH_ALWAYS); 427 dbdma_st32(&cmd->d_cmddep, vtophys((vaddr_t)sc->sc_rxcmd)); 428 429 sc->sc_rxlast = 0; 430 431 dbdma_start(sc->sc_rxdma, sc->sc_rxcmd); 432 } 433 434 int 435 bmac_intr(v) 436 void *v; 437 { 438 struct bmac_softc *sc = v; 439 int stat; 440 441 stat = bmac_read_reg(sc, STATUS); 442 if (stat == 0) 443 return 0; 444 445 #ifdef BMAC_DEBUG 446 printf("bmac_intr status = 0x%x\n", stat); 447 #endif 448 449 if (stat & IntFrameSent) { 450 sc->sc_if.if_flags &= ~IFF_OACTIVE; 451 sc->sc_if.if_timer = 0; 452 sc->sc_if.if_opackets++; 453 bmac_start(&sc->sc_if); 454 } 455 456 /* XXX should do more! */ 457 458 return 1; 459 } 460 461 int 462 bmac_rint(v) 463 void *v; 464 { 465 struct bmac_softc *sc = v; 466 struct ifnet *ifp = &sc->sc_if; 467 struct mbuf *m; 468 dbdma_command_t *cmd; 469 int status, resid, count, datalen; 470 int i, n; 471 void *data; 472 473 i = sc->sc_rxlast; 474 for (n = 0; n < BMAC_RXBUFS; n++, i++) { 475 if (i == BMAC_RXBUFS) 476 i = 0; 477 cmd = &sc->sc_rxcmd[i]; 478 status = dbdma_ld16(&cmd->d_status); 479 resid = dbdma_ld16(&cmd->d_resid); 480 481 #ifdef BMAC_DEBUG 482 if (status != 0 && status != 0x8440 && status != 0x9440) 483 printf("bmac_rint status = 0x%x\n", status); 484 #endif 485 486 if ((status & DBDMA_CNTRL_ACTIVE) == 0) /* 0x9440 | 0x8440 */ 487 continue; 488 count = dbdma_ld16(&cmd->d_count); 489 datalen = count - resid - 2; /* 2 == framelen */ 490 if (datalen < sizeof(struct ether_header)) { 491 printf("%s: short packet len = %d\n", 492 ifp->if_xname, datalen); 493 goto next; 494 } 495 DBDMA_BUILD_CMD(cmd, DBDMA_CMD_STOP, 0, 0, 0, 0); 496 data = sc->sc_rxbuf + BMAC_BUFLEN * i; 497 498 /* XXX Sometimes bmac reads one extra byte. */ 499 if (datalen == ETHER_MAX_LEN + 1) 500 datalen--; 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 IFQ_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 memcpy(buff, mtod(m, caddr_t), 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_flags |= M_HASFCS; 672 m->m_pkthdr.rcvif = &sc->sc_if; 673 m->m_pkthdr.len = totlen; 674 len = MHLEN; 675 top = 0; 676 mp = ⊤ 677 678 while (totlen > 0) { 679 if (top) { 680 MGET(m, M_DONTWAIT, MT_DATA); 681 if (m == 0) { 682 m_freem(top); 683 return 0; 684 } 685 len = MLEN; 686 } 687 if (totlen >= MINCLSIZE) { 688 MCLGET(m, M_DONTWAIT); 689 if ((m->m_flags & M_EXT) == 0) { 690 m_free(m); 691 m_freem(top); 692 return 0; 693 } 694 len = MCLBYTES; 695 } 696 m->m_len = len = min(totlen, len); 697 memcpy(mtod(m, caddr_t), pkt, len); 698 pkt += len; 699 totlen -= len; 700 *mp = m; 701 mp = &m->m_next; 702 } 703 704 return top; 705 } 706 707 void 708 bmac_watchdog(ifp) 709 struct ifnet *ifp; 710 { 711 struct bmac_softc *sc = ifp->if_softc; 712 713 bmac_reset_bits(sc, RXCFG, RxMACEnable); 714 bmac_reset_bits(sc, TXCFG, TxMACEnable); 715 716 printf("%s: device timeout\n", ifp->if_xname); 717 ifp->if_oerrors++; 718 719 bmac_reset(sc); 720 } 721 722 int 723 bmac_ioctl(ifp, cmd, data) 724 struct ifnet *ifp; 725 u_long cmd; 726 caddr_t data; 727 { 728 struct bmac_softc *sc = ifp->if_softc; 729 struct ifaddr *ifa = (struct ifaddr *)data; 730 struct ifreq *ifr = (struct ifreq *)data; 731 int s, error = 0; 732 733 s = splnet(); 734 735 switch (cmd) { 736 737 case SIOCSIFADDR: 738 ifp->if_flags |= IFF_UP; 739 740 switch (ifa->ifa_addr->sa_family) { 741 #ifdef INET 742 case AF_INET: 743 bmac_init(sc); 744 arp_ifinit(ifp, ifa); 745 break; 746 #endif 747 #ifdef NS 748 case AF_NS: 749 { 750 struct ns_addr *ina = &IA_SNS(ifa)->sns_addr; 751 752 if (ns_nullhost(*ina)) 753 ina->x_host = 754 *(union ns_host *)LLADDR(ifp->if_sadl); 755 else { 756 memcpy(LLADDR(ifp->if_sadl), 757 ina->x_host.c_host, 758 sizeof(sc->sc_enaddr)); 759 } 760 /* Set new address. */ 761 bmac_init(sc); 762 break; 763 } 764 #endif 765 default: 766 bmac_init(sc); 767 break; 768 } 769 break; 770 771 case SIOCSIFFLAGS: 772 if ((ifp->if_flags & IFF_UP) == 0 && 773 (ifp->if_flags & IFF_RUNNING) != 0) { 774 /* 775 * If interface is marked down and it is running, then 776 * stop it. 777 */ 778 bmac_stop(sc); 779 ifp->if_flags &= ~IFF_RUNNING; 780 } else if ((ifp->if_flags & IFF_UP) != 0 && 781 (ifp->if_flags & IFF_RUNNING) == 0) { 782 /* 783 * If interface is marked up and it is stopped, then 784 * start it. 785 */ 786 bmac_init(sc); 787 } else { 788 /* 789 * Reset the interface to pick up changes in any other 790 * flags that affect hardware registers. 791 */ 792 /*bmac_stop(sc);*/ 793 bmac_init(sc); 794 } 795 #ifdef BMAC_DEBUG 796 if (ifp->if_flags & IFF_DEBUG) 797 sc->sc_flags |= BMAC_DEBUGFLAG; 798 #endif 799 break; 800 801 case SIOCADDMULTI: 802 case SIOCDELMULTI: 803 error = (cmd == SIOCADDMULTI) ? 804 ether_addmulti(ifr, &sc->sc_ethercom) : 805 ether_delmulti(ifr, &sc->sc_ethercom); 806 807 if (error == ENETRESET) { 808 /* 809 * Multicast list has changed; set the hardware filter 810 * accordingly. 811 */ 812 bmac_init(sc); 813 bmac_setladrf(sc); 814 error = 0; 815 } 816 break; 817 818 case SIOCGIFMEDIA: 819 case SIOCSIFMEDIA: 820 error = ifmedia_ioctl(ifp, ifr, &sc->sc_mii.mii_media, cmd); 821 break; 822 823 default: 824 error = EINVAL; 825 } 826 827 splx(s); 828 return error; 829 } 830 831 int 832 bmac_mediachange(ifp) 833 struct ifnet *ifp; 834 { 835 struct bmac_softc *sc = ifp->if_softc; 836 837 return mii_mediachg(&sc->sc_mii); 838 } 839 840 void 841 bmac_mediastatus(ifp, ifmr) 842 struct ifnet *ifp; 843 struct ifmediareq *ifmr; 844 { 845 struct bmac_softc *sc = ifp->if_softc; 846 847 mii_pollstat(&sc->sc_mii); 848 849 ifmr->ifm_status = sc->sc_mii.mii_media_status; 850 ifmr->ifm_active = sc->sc_mii.mii_media_active; 851 } 852 853 /* 854 * Set up the logical address filter. 855 */ 856 void 857 bmac_setladrf(sc) 858 struct bmac_softc *sc; 859 { 860 struct ifnet *ifp = &sc->sc_if; 861 struct ether_multi *enm; 862 struct ether_multistep step; 863 u_int32_t crc; 864 u_int16_t hash[4]; 865 int x; 866 867 /* 868 * Set up multicast address filter by passing all multicast addresses 869 * through a crc generator, and then using the high order 6 bits as an 870 * index into the 64 bit logical address filter. The high order bit 871 * selects the word, while the rest of the bits select the bit within 872 * the word. 873 */ 874 875 if (ifp->if_flags & IFF_PROMISC) { 876 bmac_set_bits(sc, RXCFG, RxPromiscEnable); 877 return; 878 } 879 880 if (ifp->if_flags & IFF_ALLMULTI) { 881 hash[3] = hash[2] = hash[1] = hash[0] = 0xffff; 882 goto chipit; 883 } 884 885 hash[3] = hash[2] = hash[1] = hash[0] = 0; 886 887 ETHER_FIRST_MULTI(step, &sc->sc_ethercom, enm); 888 while (enm != NULL) { 889 if (memcmp(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 hash[3] = hash[2] = hash[1] = hash[0] = 0xffff; 899 ifp->if_flags |= IFF_ALLMULTI; 900 goto chipit; 901 } 902 903 crc = ether_crc32_le(enm->enm_addrlo, ETHER_ADDR_LEN); 904 905 /* Just want the 6 most significant bits. */ 906 crc >>= 26; 907 908 /* Set the corresponding bit in the filter. */ 909 hash[crc >> 4] |= 1 << (crc & 0xf); 910 911 ETHER_NEXT_MULTI(step, enm); 912 } 913 914 ifp->if_flags &= ~IFF_ALLMULTI; 915 916 chipit: 917 bmac_write_reg(sc, HASH0, hash[0]); 918 bmac_write_reg(sc, HASH1, hash[1]); 919 bmac_write_reg(sc, HASH2, hash[2]); 920 bmac_write_reg(sc, HASH3, hash[3]); 921 x = bmac_read_reg(sc, RXCFG); 922 x &= ~RxPromiscEnable; 923 x |= RxHashFilterEnable; 924 bmac_write_reg(sc, RXCFG, x); 925 } 926 927 int 928 bmac_mii_readreg(dev, phy, reg) 929 struct device *dev; 930 int phy, reg; 931 { 932 return mii_bitbang_readreg(dev, &bmac_mbo, phy, reg); 933 } 934 935 void 936 bmac_mii_writereg(dev, phy, reg, val) 937 struct device *dev; 938 int phy, reg, val; 939 { 940 mii_bitbang_writereg(dev, &bmac_mbo, phy, reg, val); 941 } 942 943 u_int32_t 944 bmac_mbo_read(dev) 945 struct device *dev; 946 { 947 struct bmac_softc *sc = (void *)dev; 948 949 return bmac_read_reg(sc, MIFCSR); 950 } 951 952 void 953 bmac_mbo_write(dev, val) 954 struct device *dev; 955 u_int32_t val; 956 { 957 struct bmac_softc *sc = (void *)dev; 958 959 bmac_write_reg(sc, MIFCSR, val); 960 } 961 962 void 963 bmac_mii_statchg(dev) 964 struct device *dev; 965 { 966 struct bmac_softc *sc = (void *)dev; 967 int x; 968 969 /* Update duplex mode in TX configuration */ 970 x = bmac_read_reg(sc, TXCFG); 971 if ((IFM_OPTIONS(sc->sc_mii.mii_media_active) & IFM_FDX) != 0) 972 x |= TxFullDuplex; 973 else 974 x &= ~TxFullDuplex; 975 bmac_write_reg(sc, TXCFG, x); 976 977 #ifdef BMAC_DEBUG 978 printf("bmac_mii_statchg 0x%x\n", 979 IFM_OPTIONS(sc->sc_mii.mii_media_active)); 980 #endif 981 } 982 983 void 984 bmac_mii_tick(v) 985 void *v; 986 { 987 struct bmac_softc *sc = v; 988 int s; 989 990 s = splnet(); 991 mii_tick(&sc->sc_mii); 992 splx(s); 993 994 callout_reset(&sc->sc_tick_ch, hz, bmac_mii_tick, sc); 995 } 996