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