1 /* $NetBSD: if_gm.c,v 1.31 2007/10/17 19:55:18 garbled Exp $ */ 2 3 /*- 4 * Copyright (c) 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 <sys/cdefs.h> 30 __KERNEL_RCSID(0, "$NetBSD: if_gm.c,v 1.31 2007/10/17 19:55:18 garbled Exp $"); 31 32 #include "opt_inet.h" 33 #include "rnd.h" 34 #include "bpfilter.h" 35 36 #include <sys/param.h> 37 #include <sys/device.h> 38 #include <sys/ioctl.h> 39 #include <sys/kernel.h> 40 #include <sys/mbuf.h> 41 #include <sys/socket.h> 42 #include <sys/systm.h> 43 #include <sys/callout.h> 44 45 #if NRND > 0 46 #include <sys/rnd.h> 47 #endif 48 49 #include <uvm/uvm_extern.h> 50 51 #include <net/if.h> 52 #include <net/if_ether.h> 53 #include <net/if_media.h> 54 55 #if NBPFILTER > 0 56 #include <net/bpf.h> 57 #endif 58 59 #ifdef INET 60 #include <netinet/in.h> 61 #include <netinet/if_inarp.h> 62 #endif 63 64 #include <dev/mii/mii.h> 65 #include <dev/mii/miivar.h> 66 67 #include <dev/pci/pcivar.h> 68 #include <dev/pci/pcireg.h> 69 #include <dev/pci/pcidevs.h> 70 71 #include <dev/ofw/openfirm.h> 72 #include <macppc/dev/if_gmreg.h> 73 #include <machine/pio.h> 74 75 #define NTXBUF 4 76 #define NRXBUF 32 77 78 struct gmac_softc { 79 struct device sc_dev; 80 struct ethercom sc_ethercom; 81 vaddr_t sc_reg; 82 struct gmac_dma *sc_txlist; 83 struct gmac_dma *sc_rxlist; 84 int sc_txnext; 85 int sc_rxlast; 86 void *sc_txbuf[NTXBUF]; 87 void *sc_rxbuf[NRXBUF]; 88 struct mii_data sc_mii; 89 struct callout sc_tick_ch; 90 char sc_laddr[6]; 91 92 #if NRND > 0 93 rndsource_element_t sc_rnd_source; /* random source */ 94 #endif 95 }; 96 97 #define sc_if sc_ethercom.ec_if 98 99 int gmac_match __P((struct device *, struct cfdata *, void *)); 100 void gmac_attach __P((struct device *, struct device *, void *)); 101 102 static inline u_int gmac_read_reg __P((struct gmac_softc *, int)); 103 static inline void gmac_write_reg __P((struct gmac_softc *, int, u_int)); 104 105 static inline void gmac_start_txdma __P((struct gmac_softc *)); 106 static inline void gmac_start_rxdma __P((struct gmac_softc *)); 107 static inline void gmac_stop_txdma __P((struct gmac_softc *)); 108 static inline void gmac_stop_rxdma __P((struct gmac_softc *)); 109 110 int gmac_intr __P((void *)); 111 void gmac_tint __P((struct gmac_softc *)); 112 void gmac_rint __P((struct gmac_softc *)); 113 struct mbuf * gmac_get __P((struct gmac_softc *, void *, int)); 114 void gmac_start __P((struct ifnet *)); 115 int gmac_put __P((struct gmac_softc *, void *, struct mbuf *)); 116 117 void gmac_stop __P((struct gmac_softc *)); 118 void gmac_reset __P((struct gmac_softc *)); 119 void gmac_init __P((struct gmac_softc *)); 120 void gmac_init_mac __P((struct gmac_softc *)); 121 void gmac_setladrf __P((struct gmac_softc *)); 122 123 int gmac_ioctl __P((struct ifnet *, u_long, void *)); 124 void gmac_watchdog __P((struct ifnet *)); 125 126 int gmac_mediachange __P((struct ifnet *)); 127 void gmac_mediastatus __P((struct ifnet *, struct ifmediareq *)); 128 int gmac_mii_readreg __P((struct device *, int, int)); 129 void gmac_mii_writereg __P((struct device *, int, int, int)); 130 void gmac_mii_statchg __P((struct device *)); 131 void gmac_mii_tick __P((void *)); 132 133 CFATTACH_DECL(gm, sizeof(struct gmac_softc), 134 gmac_match, gmac_attach, NULL, NULL); 135 136 int 137 gmac_match(parent, match, aux) 138 struct device *parent; 139 struct cfdata *match; 140 void *aux; 141 { 142 struct pci_attach_args *pa = aux; 143 144 if (PCI_VENDOR(pa->pa_id) == PCI_VENDOR_APPLE && 145 (PCI_PRODUCT(pa->pa_id) == PCI_PRODUCT_APPLE_GMAC || 146 PCI_PRODUCT(pa->pa_id) == PCI_PRODUCT_APPLE_GMAC2 || 147 PCI_PRODUCT(pa->pa_id) == PCI_PRODUCT_APPLE_GMAC3)) 148 return 1; 149 150 return 0; 151 } 152 153 void 154 gmac_attach(parent, self, aux) 155 struct device *parent, *self; 156 void *aux; 157 { 158 struct gmac_softc *sc = (void *)self; 159 struct pci_attach_args *pa = aux; 160 struct ifnet *ifp = &sc->sc_if; 161 struct mii_data *mii = &sc->sc_mii; 162 pci_intr_handle_t ih; 163 const char *intrstr = NULL; 164 int node, i; 165 char *p; 166 struct gmac_dma *dp; 167 u_int32_t reg[10]; 168 u_char laddr[6]; 169 170 node = pcidev_to_ofdev(pa->pa_pc, pa->pa_tag); 171 if (node == 0) { 172 printf(": cannot find gmac node\n"); 173 return; 174 } 175 176 OF_getprop(node, "local-mac-address", laddr, sizeof laddr); 177 OF_getprop(node, "assigned-addresses", reg, sizeof reg); 178 179 memcpy(sc->sc_laddr, laddr, sizeof laddr); 180 sc->sc_reg = reg[2]; 181 182 if (pci_intr_map(pa, &ih)) { 183 printf(": unable to map interrupt\n"); 184 return; 185 } 186 intrstr = pci_intr_string(pa->pa_pc, ih); 187 188 if (pci_intr_establish(pa->pa_pc, ih, IPL_NET, gmac_intr, sc) == NULL) { 189 printf(": unable to establish interrupt"); 190 if (intrstr) 191 printf(" at %s", intrstr); 192 printf("\n"); 193 return; 194 } 195 196 /* Setup packet buffers and DMA descriptors. */ 197 p = malloc((NRXBUF + NTXBUF) * 2048 + 3 * 0x800, M_DEVBUF, M_NOWAIT); 198 if (p == NULL) { 199 printf(": cannot malloc buffers\n"); 200 return; 201 } 202 p = (void *)roundup((vaddr_t)p, 0x800); 203 memset(p, 0, 2048 * (NRXBUF + NTXBUF) + 2 * 0x800); 204 205 sc->sc_rxlist = (void *)p; 206 p += 0x800; 207 sc->sc_txlist = (void *)p; 208 p += 0x800; 209 210 dp = sc->sc_rxlist; 211 for (i = 0; i < NRXBUF; i++) { 212 sc->sc_rxbuf[i] = p; 213 dp->address = htole32(vtophys((vaddr_t)p)); 214 dp->cmd = htole32(GMAC_OWN); 215 dp++; 216 p += 2048; 217 } 218 219 dp = sc->sc_txlist; 220 for (i = 0; i < NTXBUF; i++) { 221 sc->sc_txbuf[i] = p; 222 dp->address = htole32(vtophys((vaddr_t)p)); 223 dp++; 224 p += 2048; 225 } 226 227 printf(": Ethernet address %s\n", ether_sprintf(laddr)); 228 printf("%s: interrupting at %s\n", sc->sc_dev.dv_xname, intrstr); 229 230 callout_init(&sc->sc_tick_ch, 0); 231 232 gmac_reset(sc); 233 gmac_init_mac(sc); 234 235 memcpy(ifp->if_xname, sc->sc_dev.dv_xname, IFNAMSIZ); 236 ifp->if_softc = sc; 237 ifp->if_ioctl = gmac_ioctl; 238 ifp->if_start = gmac_start; 239 ifp->if_watchdog = gmac_watchdog; 240 ifp->if_flags = 241 IFF_BROADCAST | IFF_SIMPLEX | IFF_NOTRAILERS | IFF_MULTICAST; 242 IFQ_SET_READY(&ifp->if_snd); 243 244 mii->mii_ifp = ifp; 245 mii->mii_readreg = gmac_mii_readreg; 246 mii->mii_writereg = gmac_mii_writereg; 247 mii->mii_statchg = gmac_mii_statchg; 248 249 ifmedia_init(&mii->mii_media, 0, gmac_mediachange, gmac_mediastatus); 250 mii_attach(self, mii, 0xffffffff, MII_PHY_ANY, MII_OFFSET_ANY, 0); 251 252 /* Choose a default media. */ 253 if (LIST_FIRST(&mii->mii_phys) == NULL) { 254 ifmedia_add(&mii->mii_media, IFM_ETHER|IFM_NONE, 0, NULL); 255 ifmedia_set(&mii->mii_media, IFM_ETHER|IFM_NONE); 256 } else 257 ifmedia_set(&mii->mii_media, IFM_ETHER|IFM_AUTO); 258 259 if_attach(ifp); 260 ether_ifattach(ifp, laddr); 261 #if NRND > 0 262 rnd_attach_source(&sc->sc_rnd_source, sc->sc_dev.dv_xname, 263 RND_TYPE_NET, 0); 264 #endif 265 } 266 267 u_int 268 gmac_read_reg(sc, reg) 269 struct gmac_softc *sc; 270 int reg; 271 { 272 return in32rb(sc->sc_reg + reg); 273 } 274 275 void 276 gmac_write_reg(sc, reg, val) 277 struct gmac_softc *sc; 278 int reg; 279 u_int val; 280 { 281 out32rb(sc->sc_reg + reg, val); 282 } 283 284 void 285 gmac_start_txdma(sc) 286 struct gmac_softc *sc; 287 { 288 u_int x; 289 290 x = gmac_read_reg(sc, GMAC_TXDMACONFIG); 291 x |= 1; 292 gmac_write_reg(sc, GMAC_TXDMACONFIG, x); 293 x = gmac_read_reg(sc, GMAC_TXMACCONFIG); 294 x |= 1; 295 gmac_write_reg(sc, GMAC_TXMACCONFIG, x); 296 } 297 298 void 299 gmac_start_rxdma(sc) 300 struct gmac_softc *sc; 301 { 302 u_int x; 303 304 x = gmac_read_reg(sc, GMAC_RXDMACONFIG); 305 x |= 1; 306 gmac_write_reg(sc, GMAC_RXDMACONFIG, x); 307 x = gmac_read_reg(sc, GMAC_RXMACCONFIG); 308 x |= 1; 309 gmac_write_reg(sc, GMAC_RXMACCONFIG, x); 310 } 311 312 void 313 gmac_stop_txdma(sc) 314 struct gmac_softc *sc; 315 { 316 u_int x; 317 318 x = gmac_read_reg(sc, GMAC_TXDMACONFIG); 319 x &= ~1; 320 gmac_write_reg(sc, GMAC_TXDMACONFIG, x); 321 x = gmac_read_reg(sc, GMAC_TXMACCONFIG); 322 x &= ~1; 323 gmac_write_reg(sc, GMAC_TXMACCONFIG, x); 324 } 325 326 void 327 gmac_stop_rxdma(sc) 328 struct gmac_softc *sc; 329 { 330 u_int x; 331 332 x = gmac_read_reg(sc, GMAC_RXDMACONFIG); 333 x &= ~1; 334 gmac_write_reg(sc, GMAC_RXDMACONFIG, x); 335 x = gmac_read_reg(sc, GMAC_RXMACCONFIG); 336 x &= ~1; 337 gmac_write_reg(sc, GMAC_RXMACCONFIG, x); 338 } 339 340 int 341 gmac_intr(v) 342 void *v; 343 { 344 struct gmac_softc *sc = v; 345 u_int status; 346 347 status = gmac_read_reg(sc, GMAC_STATUS) & 0xff; 348 if (status == 0) 349 return 0; 350 351 if (status & GMAC_INT_RXDONE) 352 gmac_rint(sc); 353 354 if (status & GMAC_INT_TXEMPTY) 355 gmac_tint(sc); 356 357 #if NRND > 0 358 rnd_add_uint32(&sc->sc_rnd_source, status); 359 #endif 360 return 1; 361 } 362 363 void 364 gmac_tint(sc) 365 struct gmac_softc *sc; 366 { 367 struct ifnet *ifp = &sc->sc_if; 368 369 ifp->if_flags &= ~IFF_OACTIVE; 370 ifp->if_timer = 0; 371 gmac_start(ifp); 372 } 373 374 void 375 gmac_rint(sc) 376 struct gmac_softc *sc; 377 { 378 struct ifnet *ifp = &sc->sc_if; 379 volatile struct gmac_dma *dp; 380 struct mbuf *m; 381 int i, j, len; 382 u_int cmd; 383 384 for (i = sc->sc_rxlast;; i++) { 385 if (i == NRXBUF) 386 i = 0; 387 388 dp = &sc->sc_rxlist[i]; 389 cmd = le32toh(dp->cmd); 390 if (cmd & GMAC_OWN) 391 break; 392 len = (cmd >> 16) & GMAC_LEN_MASK; 393 len -= 4; /* CRC */ 394 395 if (le32toh(dp->cmd_hi) & 0x40000000) { 396 ifp->if_ierrors++; 397 goto next; 398 } 399 400 m = gmac_get(sc, sc->sc_rxbuf[i], len); 401 if (m == NULL) { 402 ifp->if_ierrors++; 403 goto next; 404 } 405 406 #if NBPFILTER > 0 407 /* 408 * Check if there's a BPF listener on this interface. 409 * If so, hand off the raw packet to BPF. 410 */ 411 if (ifp->if_bpf) 412 bpf_mtap(ifp->if_bpf, m); 413 #endif 414 (*ifp->if_input)(ifp, m); 415 ifp->if_ipackets++; 416 417 next: 418 dp->cmd_hi = 0; 419 __asm volatile ("sync"); 420 dp->cmd = htole32(GMAC_OWN); 421 } 422 sc->sc_rxlast = i; 423 424 /* XXX Make sure free buffers have GMAC_OWN. */ 425 i++; 426 for (j = 1; j < NRXBUF; j++) { 427 if (i == NRXBUF) 428 i = 0; 429 dp = &sc->sc_rxlist[i++]; 430 dp->cmd = htole32(GMAC_OWN); 431 } 432 } 433 434 struct mbuf * 435 gmac_get(sc, pkt, totlen) 436 struct gmac_softc *sc; 437 void *pkt; 438 int totlen; 439 { 440 struct mbuf *m; 441 struct mbuf *top, **mp; 442 int len; 443 444 MGETHDR(m, M_DONTWAIT, MT_DATA); 445 if (m == 0) 446 return 0; 447 m->m_pkthdr.rcvif = &sc->sc_if; 448 m->m_pkthdr.len = totlen; 449 len = MHLEN; 450 top = 0; 451 mp = ⊤ 452 453 while (totlen > 0) { 454 if (top) { 455 MGET(m, M_DONTWAIT, MT_DATA); 456 if (m == 0) { 457 m_freem(top); 458 return 0; 459 } 460 len = MLEN; 461 } 462 if (totlen >= MINCLSIZE) { 463 MCLGET(m, M_DONTWAIT); 464 if ((m->m_flags & M_EXT) == 0) { 465 m_free(m); 466 m_freem(top); 467 return 0; 468 } 469 len = MCLBYTES; 470 } 471 m->m_len = len = min(totlen, len); 472 memcpy(mtod(m, void *), pkt, len); 473 pkt += len; 474 totlen -= len; 475 *mp = m; 476 mp = &m->m_next; 477 } 478 479 return top; 480 } 481 482 void 483 gmac_start(ifp) 484 struct ifnet *ifp; 485 { 486 struct gmac_softc *sc = ifp->if_softc; 487 struct mbuf *m; 488 void *buff; 489 int i, tlen; 490 volatile struct gmac_dma *dp; 491 492 if ((ifp->if_flags & (IFF_RUNNING | IFF_OACTIVE)) != IFF_RUNNING) 493 return; 494 495 for (;;) { 496 if (ifp->if_flags & IFF_OACTIVE) 497 break; 498 499 IFQ_DEQUEUE(&ifp->if_snd, m); 500 if (m == 0) 501 break; 502 503 /* 5 seconds to watch for failing to transmit */ 504 ifp->if_timer = 5; 505 ifp->if_opackets++; /* # of pkts */ 506 507 i = sc->sc_txnext; 508 buff = sc->sc_txbuf[i]; 509 tlen = gmac_put(sc, buff, m); 510 511 dp = &sc->sc_txlist[i]; 512 dp->cmd_hi = 0; 513 dp->address_hi = 0; 514 dp->cmd = htole32(tlen | GMAC_OWN | GMAC_SOP); 515 516 i++; 517 if (i == NTXBUF) 518 i = 0; 519 __asm volatile ("sync"); 520 521 gmac_write_reg(sc, GMAC_TXDMAKICK, i); 522 sc->sc_txnext = i; 523 524 #if NBPFILTER > 0 525 /* 526 * If BPF is listening on this interface, let it see the 527 * packet before we commit it to the wire. 528 */ 529 if (ifp->if_bpf) 530 bpf_mtap(ifp->if_bpf, m); 531 #endif 532 m_freem(m); 533 534 i++; 535 if (i == NTXBUF) 536 i = 0; 537 if (i == gmac_read_reg(sc, GMAC_TXDMACOMPLETE)) { 538 ifp->if_flags |= IFF_OACTIVE; 539 break; 540 } 541 } 542 } 543 544 int 545 gmac_put(sc, buff, m) 546 struct gmac_softc *sc; 547 void *buff; 548 struct mbuf *m; 549 { 550 int len, tlen = 0; 551 552 for (; m; m = m->m_next) { 553 len = m->m_len; 554 if (len == 0) 555 continue; 556 memcpy(buff, mtod(m, void *), len); 557 buff += len; 558 tlen += len; 559 } 560 if (tlen > 2048) 561 panic("%s: gmac_put packet overflow", sc->sc_dev.dv_xname); 562 563 return tlen; 564 } 565 566 void 567 gmac_reset(sc) 568 struct gmac_softc *sc; 569 { 570 int i, s; 571 572 s = splnet(); 573 574 gmac_stop_txdma(sc); 575 gmac_stop_rxdma(sc); 576 577 gmac_write_reg(sc, GMAC_SOFTWARERESET, 3); 578 for (i = 10; i > 0; i--) { 579 delay(300000); /* XXX long delay */ 580 if ((gmac_read_reg(sc, GMAC_SOFTWARERESET) & 3) == 0) 581 break; 582 } 583 if (i == 0) 584 printf("%s: reset timeout\n", sc->sc_dev.dv_xname); 585 586 sc->sc_txnext = 0; 587 sc->sc_rxlast = 0; 588 for (i = 0; i < NRXBUF; i++) 589 sc->sc_rxlist[i].cmd = htole32(GMAC_OWN); 590 __asm volatile ("sync"); 591 592 gmac_write_reg(sc, GMAC_TXDMADESCBASEHI, 0); 593 gmac_write_reg(sc, GMAC_TXDMADESCBASELO, 594 vtophys((vaddr_t)sc->sc_txlist)); 595 gmac_write_reg(sc, GMAC_RXDMADESCBASEHI, 0); 596 gmac_write_reg(sc, GMAC_RXDMADESCBASELO, 597 vtophys((vaddr_t)sc->sc_rxlist)); 598 gmac_write_reg(sc, GMAC_RXDMAKICK, NRXBUF); 599 600 splx(s); 601 } 602 603 void 604 gmac_stop(sc) 605 struct gmac_softc *sc; 606 { 607 struct ifnet *ifp = &sc->sc_if; 608 int s; 609 610 s = splnet(); 611 612 callout_stop(&sc->sc_tick_ch); 613 mii_down(&sc->sc_mii); 614 615 gmac_stop_txdma(sc); 616 gmac_stop_rxdma(sc); 617 618 gmac_write_reg(sc, GMAC_INTMASK, 0xffffffff); 619 620 ifp->if_flags &= ~(IFF_UP | IFF_RUNNING); 621 ifp->if_timer = 0; 622 623 splx(s); 624 } 625 626 void 627 gmac_init_mac(sc) 628 struct gmac_softc *sc; 629 { 630 int i, tb; 631 char *laddr = sc->sc_laddr; 632 633 if ((mfpvr() >> 16) == MPC601) 634 tb = mfrtcl(); 635 else 636 tb = mftbl(); 637 gmac_write_reg(sc, GMAC_RANDOMSEED, tb); 638 639 /* init-mii */ 640 gmac_write_reg(sc, GMAC_DATAPATHMODE, 4); 641 gmac_mii_writereg(&sc->sc_dev, 0, 0, 0x1000); 642 643 gmac_write_reg(sc, GMAC_TXDMACONFIG, 0xffc00); 644 gmac_write_reg(sc, GMAC_RXDMACONFIG, 0); 645 gmac_write_reg(sc, GMAC_MACPAUSE, 0x1bf0); 646 gmac_write_reg(sc, GMAC_INTERPACKETGAP0, 0); 647 gmac_write_reg(sc, GMAC_INTERPACKETGAP1, 8); 648 gmac_write_reg(sc, GMAC_INTERPACKETGAP2, 4); 649 gmac_write_reg(sc, GMAC_MINFRAMESIZE, ETHER_MIN_LEN); 650 gmac_write_reg(sc, GMAC_MAXFRAMESIZE, ETHER_MAX_LEN); 651 gmac_write_reg(sc, GMAC_PASIZE, 7); 652 gmac_write_reg(sc, GMAC_JAMSIZE, 4); 653 gmac_write_reg(sc, GMAC_ATTEMPTLIMIT,0x10); 654 gmac_write_reg(sc, GMAC_MACCNTLTYPE, 0x8808); 655 656 gmac_write_reg(sc, GMAC_MACADDRESS0, (laddr[4] << 8) | laddr[5]); 657 gmac_write_reg(sc, GMAC_MACADDRESS1, (laddr[2] << 8) | laddr[3]); 658 gmac_write_reg(sc, GMAC_MACADDRESS2, (laddr[0] << 8) | laddr[1]); 659 gmac_write_reg(sc, GMAC_MACADDRESS3, 0); 660 gmac_write_reg(sc, GMAC_MACADDRESS4, 0); 661 gmac_write_reg(sc, GMAC_MACADDRESS5, 0); 662 gmac_write_reg(sc, GMAC_MACADDRESS6, 1); 663 gmac_write_reg(sc, GMAC_MACADDRESS7, 0xc200); 664 gmac_write_reg(sc, GMAC_MACADDRESS8, 0x0180); 665 gmac_write_reg(sc, GMAC_MACADDRFILT0, 0); 666 gmac_write_reg(sc, GMAC_MACADDRFILT1, 0); 667 gmac_write_reg(sc, GMAC_MACADDRFILT2, 0); 668 gmac_write_reg(sc, GMAC_MACADDRFILT2_1MASK, 0); 669 gmac_write_reg(sc, GMAC_MACADDRFILT0MASK, 0); 670 671 for (i = 0; i < 0x6c; i += 4) 672 gmac_write_reg(sc, GMAC_HASHTABLE0 + i, 0); 673 674 gmac_write_reg(sc, GMAC_SLOTTIME, 0x40); 675 676 if (IFM_OPTIONS(sc->sc_mii.mii_media_active) & IFM_FDX) { 677 gmac_write_reg(sc, GMAC_TXMACCONFIG, 6); 678 gmac_write_reg(sc, GMAC_XIFCONFIG, 1); 679 } else { 680 gmac_write_reg(sc, GMAC_TXMACCONFIG, 0); 681 gmac_write_reg(sc, GMAC_XIFCONFIG, 5); 682 } 683 684 if (0) /* g-bit? */ 685 gmac_write_reg(sc, GMAC_MACCTRLCONFIG, 3); 686 else 687 gmac_write_reg(sc, GMAC_MACCTRLCONFIG, 0); 688 } 689 690 void 691 gmac_setladrf(sc) 692 struct gmac_softc *sc; 693 { 694 struct ifnet *ifp = &sc->sc_if; 695 struct ether_multi *enm; 696 struct ether_multistep step; 697 struct ethercom *ec = &sc->sc_ethercom; 698 u_int32_t crc; 699 u_int32_t hash[16]; 700 u_int v; 701 int i; 702 703 /* Clear hash table */ 704 for (i = 0; i < 16; i++) 705 hash[i] = 0; 706 707 /* Get current RX configuration */ 708 v = gmac_read_reg(sc, GMAC_RXMACCONFIG); 709 710 if ((ifp->if_flags & IFF_PROMISC) != 0) { 711 /* Turn on promiscuous mode; turn off the hash filter */ 712 v |= GMAC_RXMAC_PR; 713 v &= ~GMAC_RXMAC_HEN; 714 ifp->if_flags |= IFF_ALLMULTI; 715 goto chipit; 716 } 717 718 /* Turn off promiscuous mode; turn on the hash filter */ 719 v &= ~GMAC_RXMAC_PR; 720 v |= GMAC_RXMAC_HEN; 721 722 /* 723 * Set up multicast address filter by passing all multicast addresses 724 * through a crc generator, and then using the high order 8 bits as an 725 * index into the 256 bit logical address filter. The high order bit 726 * selects the word, while the rest of the bits select the bit within 727 * the word. 728 */ 729 730 ETHER_FIRST_MULTI(step, ec, enm); 731 while (enm != NULL) { 732 if (memcmp(enm->enm_addrlo, enm->enm_addrhi, 6)) { 733 /* 734 * We must listen to a range of multicast addresses. 735 * For now, just accept all multicasts, rather than 736 * trying to set only those filter bits needed to match 737 * the range. (At this time, the only use of address 738 * ranges is for IP multicast routing, for which the 739 * range is big enough to require all bits set.) 740 */ 741 for (i = 0; i < 16; i++) 742 hash[i] = 0xffff; 743 ifp->if_flags |= IFF_ALLMULTI; 744 goto chipit; 745 } 746 747 crc = ether_crc32_le(enm->enm_addrlo, ETHER_ADDR_LEN); 748 749 /* Just want the 8 most significant bits. */ 750 crc >>= 24; 751 752 /* Set the corresponding bit in the filter. */ 753 hash[crc >> 4] |= 1 << (crc & 0xf); 754 755 ETHER_NEXT_MULTI(step, enm); 756 } 757 758 ifp->if_flags &= ~IFF_ALLMULTI; 759 760 chipit: 761 /* Now load the hash table into the chip */ 762 for (i = 0; i < 16; i++) 763 gmac_write_reg(sc, GMAC_HASHTABLE0 + i * 4, hash[i]); 764 765 gmac_write_reg(sc, GMAC_RXMACCONFIG, v); 766 } 767 768 void 769 gmac_init(sc) 770 struct gmac_softc *sc; 771 { 772 struct ifnet *ifp = &sc->sc_if; 773 774 gmac_stop_txdma(sc); 775 gmac_stop_rxdma(sc); 776 777 gmac_init_mac(sc); 778 gmac_setladrf(sc); 779 780 gmac_start_txdma(sc); 781 gmac_start_rxdma(sc); 782 783 gmac_write_reg(sc, GMAC_INTMASK, ~(GMAC_INT_TXEMPTY | GMAC_INT_RXDONE)); 784 785 ifp->if_flags |= IFF_RUNNING; 786 ifp->if_flags &= ~IFF_OACTIVE; 787 ifp->if_timer = 0; 788 789 callout_reset(&sc->sc_tick_ch, 1, gmac_mii_tick, sc); 790 791 gmac_start(ifp); 792 } 793 794 int 795 gmac_ioctl(ifp, cmd, data) 796 struct ifnet *ifp; 797 u_long cmd; 798 void *data; 799 { 800 struct gmac_softc *sc = ifp->if_softc; 801 struct ifaddr *ifa = (struct ifaddr *)data; 802 struct ifreq *ifr = (struct ifreq *)data; 803 int s, error = 0; 804 805 s = splnet(); 806 807 switch (cmd) { 808 809 case SIOCSIFADDR: 810 ifp->if_flags |= IFF_UP; 811 812 switch (ifa->ifa_addr->sa_family) { 813 #ifdef INET 814 case AF_INET: 815 gmac_init(sc); 816 arp_ifinit(ifp, ifa); 817 break; 818 #endif 819 default: 820 gmac_init(sc); 821 break; 822 } 823 break; 824 825 case SIOCSIFFLAGS: 826 if ((ifp->if_flags & IFF_UP) == 0 && 827 (ifp->if_flags & IFF_RUNNING) != 0) { 828 /* 829 * If interface is marked down and it is running, then 830 * stop it. 831 */ 832 gmac_stop(sc); 833 ifp->if_flags &= ~IFF_RUNNING; 834 } else if ((ifp->if_flags & IFF_UP) != 0 && 835 (ifp->if_flags & IFF_RUNNING) == 0) { 836 /* 837 * If interface is marked up and it is stopped, then 838 * start it. 839 */ 840 gmac_init(sc); 841 } else { 842 /* 843 * Reset the interface to pick up changes in any other 844 * flags that affect hardware registers. 845 */ 846 gmac_reset(sc); 847 gmac_init(sc); 848 } 849 #ifdef GMAC_DEBUG 850 if (ifp->if_flags & IFF_DEBUG) 851 sc->sc_flags |= GMAC_DEBUGFLAG; 852 #endif 853 break; 854 855 case SIOCADDMULTI: 856 case SIOCDELMULTI: 857 if ((error = ether_ioctl(ifp, cmd, data)) == ENETRESET) { 858 /* 859 * Multicast list has changed; set the hardware filter 860 * accordingly. 861 */ 862 if (ifp->if_flags & IFF_RUNNING) { 863 gmac_init(sc); 864 /* gmac_setladrf(sc); */ 865 } 866 error = 0; 867 } 868 break; 869 870 case SIOCGIFMEDIA: 871 case SIOCSIFMEDIA: 872 error = ifmedia_ioctl(ifp, ifr, &sc->sc_mii.mii_media, cmd); 873 break; 874 875 default: 876 error = EINVAL; 877 } 878 879 splx(s); 880 return error; 881 } 882 883 void 884 gmac_watchdog(ifp) 885 struct ifnet *ifp; 886 { 887 struct gmac_softc *sc = ifp->if_softc; 888 889 printf("%s: device timeout\n", ifp->if_xname); 890 ifp->if_oerrors++; 891 892 gmac_reset(sc); 893 gmac_init(sc); 894 } 895 896 int 897 gmac_mediachange(ifp) 898 struct ifnet *ifp; 899 { 900 struct gmac_softc *sc = ifp->if_softc; 901 902 return mii_mediachg(&sc->sc_mii); 903 } 904 905 void 906 gmac_mediastatus(ifp, ifmr) 907 struct ifnet *ifp; 908 struct ifmediareq *ifmr; 909 { 910 struct gmac_softc *sc = ifp->if_softc; 911 912 mii_pollstat(&sc->sc_mii); 913 914 ifmr->ifm_status = sc->sc_mii.mii_media_status; 915 ifmr->ifm_active = sc->sc_mii.mii_media_active; 916 } 917 918 int 919 gmac_mii_readreg(dev, phy, reg) 920 struct device *dev; 921 int phy, reg; 922 { 923 struct gmac_softc *sc = (void *)dev; 924 int i; 925 926 gmac_write_reg(sc, GMAC_MIFFRAMEOUTPUT, 927 0x60020000 | (phy << 23) | (reg << 18)); 928 929 for (i = 1000; i >= 0; i -= 10) { 930 if (gmac_read_reg(sc, GMAC_MIFFRAMEOUTPUT) & 0x10000) 931 break; 932 delay(10); 933 } 934 if (i < 0) { 935 printf("%s: gmac_mii_readreg: timeout\n", sc->sc_dev.dv_xname); 936 return 0; 937 } 938 939 return gmac_read_reg(sc, GMAC_MIFFRAMEOUTPUT) & 0xffff; 940 } 941 942 void 943 gmac_mii_writereg(dev, phy, reg, val) 944 struct device *dev; 945 int phy, reg, val; 946 { 947 struct gmac_softc *sc = (void *)dev; 948 int i; 949 950 gmac_write_reg(sc, GMAC_MIFFRAMEOUTPUT, 951 0x50020000 | (phy << 23) | (reg << 18) | (val & 0xffff)); 952 953 for (i = 1000; i >= 0; i -= 10) { 954 if (gmac_read_reg(sc, GMAC_MIFFRAMEOUTPUT) & 0x10000) 955 break; 956 delay(10); 957 } 958 if (i < 0) 959 printf("%s: gmac_mii_writereg: timeout\n", sc->sc_dev.dv_xname); 960 } 961 962 void 963 gmac_mii_statchg(dev) 964 struct device *dev; 965 { 966 struct gmac_softc *sc = (void *)dev; 967 968 gmac_stop_txdma(sc); 969 gmac_stop_rxdma(sc); 970 971 if (IFM_OPTIONS(sc->sc_mii.mii_media_active) & IFM_FDX) { 972 gmac_write_reg(sc, GMAC_TXMACCONFIG, 6); 973 gmac_write_reg(sc, GMAC_XIFCONFIG, 1); 974 } else { 975 gmac_write_reg(sc, GMAC_TXMACCONFIG, 0); 976 gmac_write_reg(sc, GMAC_XIFCONFIG, 5); 977 } 978 979 if (0) /* g-bit? */ 980 gmac_write_reg(sc, GMAC_MACCTRLCONFIG, 3); 981 else 982 gmac_write_reg(sc, GMAC_MACCTRLCONFIG, 0); 983 984 gmac_start_txdma(sc); 985 gmac_start_rxdma(sc); 986 } 987 988 void 989 gmac_mii_tick(v) 990 void *v; 991 { 992 struct gmac_softc *sc = v; 993 int s; 994 995 s = splnet(); 996 mii_tick(&sc->sc_mii); 997 splx(s); 998 999 callout_reset(&sc->sc_tick_ch, hz, gmac_mii_tick, sc); 1000 } 1001