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