1 /*- 2 * Copyright (c) 2014 Ruslan Bukin <br@bsdpad.com> 3 * 4 * This software was developed by SRI International and the University of 5 * Cambridge Computer Laboratory under DARPA/AFRL contract (FA8750-10-C-0237) 6 * ("CTSRD"), as part of the DARPA CRASH research programme. 7 * 8 * Redistribution and use in source and binary forms, with or without 9 * modification, are permitted provided that the following conditions 10 * are met: 11 * 1. Redistributions of source code must retain the above copyright 12 * notice, this list of conditions and the following disclaimer. 13 * 2. Redistributions in binary form must reproduce the above copyright 14 * notice, this list of conditions and the following disclaimer in the 15 * documentation and/or other materials provided with the distribution. 16 * 17 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 18 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 19 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 20 * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 21 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 22 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 23 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 24 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 25 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 26 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 27 * SUCH DAMAGE. 28 */ 29 30 /* 31 * Ethernet media access controller (EMAC) 32 * Chapter 17, Altera Cyclone V Device Handbook (CV-5V2 2014.07.22) 33 * 34 * EMAC is an instance of the Synopsys DesignWare 3504-0 35 * Universal 10/100/1000 Ethernet MAC (DWC_gmac). 36 */ 37 38 #include <sys/param.h> 39 #include <sys/systm.h> 40 #include <sys/bus.h> 41 #include <sys/gpio.h> 42 #include <sys/kernel.h> 43 #include <sys/lock.h> 44 #include <sys/malloc.h> 45 #include <sys/mbuf.h> 46 #include <sys/module.h> 47 #include <sys/mutex.h> 48 #include <sys/rman.h> 49 #include <sys/socket.h> 50 #include <sys/sockio.h> 51 52 #include <net/bpf.h> 53 #include <net/if.h> 54 #include <net/ethernet.h> 55 #include <net/if_dl.h> 56 #include <net/if_media.h> 57 #include <net/if_types.h> 58 #include <net/if_var.h> 59 60 #include <machine/bus.h> 61 62 #include <dev/extres/clk/clk.h> 63 #include <dev/extres/hwreset/hwreset.h> 64 65 #include <dev/mii/mii.h> 66 #include <dev/mii/miivar.h> 67 #include <dev/ofw/ofw_bus.h> 68 #include <dev/ofw/ofw_bus_subr.h> 69 #include <dev/mii/mii_fdt.h> 70 71 #include <dev/dwc/if_dwcvar.h> 72 #include <dev/dwc/dwc1000_core.h> 73 #include <dev/dwc/dwc1000_dma.h> 74 75 #include "if_dwc_if.h" 76 #include "gpio_if.h" 77 #include "miibus_if.h" 78 79 static struct resource_spec dwc_spec[] = { 80 { SYS_RES_MEMORY, 0, RF_ACTIVE }, 81 { SYS_RES_IRQ, 0, RF_ACTIVE }, 82 { -1, 0 } 83 }; 84 85 static void dwc_stop_locked(struct dwc_softc *sc); 86 87 static void dwc_tick(void *arg); 88 89 /* 90 * Media functions 91 */ 92 93 static void 94 dwc_media_status(if_t ifp, struct ifmediareq *ifmr) 95 { 96 struct dwc_softc *sc; 97 struct mii_data *mii; 98 99 sc = if_getsoftc(ifp); 100 mii = sc->mii_softc; 101 DWC_LOCK(sc); 102 mii_pollstat(mii); 103 ifmr->ifm_active = mii->mii_media_active; 104 ifmr->ifm_status = mii->mii_media_status; 105 DWC_UNLOCK(sc); 106 } 107 108 static int 109 dwc_media_change_locked(struct dwc_softc *sc) 110 { 111 112 return (mii_mediachg(sc->mii_softc)); 113 } 114 115 static int 116 dwc_media_change(if_t ifp) 117 { 118 struct dwc_softc *sc; 119 int error; 120 121 sc = if_getsoftc(ifp); 122 123 DWC_LOCK(sc); 124 error = dwc_media_change_locked(sc); 125 DWC_UNLOCK(sc); 126 return (error); 127 } 128 129 /* 130 * if_ functions 131 */ 132 133 static void 134 dwc_txstart_locked(struct dwc_softc *sc) 135 { 136 if_t ifp; 137 138 DWC_ASSERT_LOCKED(sc); 139 140 if (!sc->link_is_up) 141 return; 142 143 ifp = sc->ifp; 144 145 if ((if_getdrvflags(ifp) & (IFF_DRV_RUNNING|IFF_DRV_OACTIVE)) != 146 IFF_DRV_RUNNING) 147 return; 148 dma1000_txstart(sc); 149 } 150 151 static void 152 dwc_txstart(if_t ifp) 153 { 154 struct dwc_softc *sc = if_getsoftc(ifp); 155 156 DWC_LOCK(sc); 157 dwc_txstart_locked(sc); 158 DWC_UNLOCK(sc); 159 } 160 161 static void 162 dwc_init_locked(struct dwc_softc *sc) 163 { 164 if_t ifp = sc->ifp; 165 166 DWC_ASSERT_LOCKED(sc); 167 168 if (if_getdrvflags(ifp) & IFF_DRV_RUNNING) 169 return; 170 171 /* 172 * Call mii_mediachg() which will call back into dwc1000_miibus_statchg() 173 * to set up the remaining config registers based on current media. 174 */ 175 mii_mediachg(sc->mii_softc); 176 177 dwc1000_setup_rxfilter(sc); 178 dwc1000_core_setup(sc); 179 dwc1000_enable_mac(sc, true); 180 dwc1000_enable_csum_offload(sc); 181 dma1000_start(sc); 182 183 if_setdrvflagbits(ifp, IFF_DRV_RUNNING, IFF_DRV_OACTIVE); 184 185 callout_reset(&sc->dwc_callout, hz, dwc_tick, sc); 186 } 187 188 static void 189 dwc_init(void *if_softc) 190 { 191 struct dwc_softc *sc = if_softc; 192 193 DWC_LOCK(sc); 194 dwc_init_locked(sc); 195 DWC_UNLOCK(sc); 196 } 197 198 static void 199 dwc_stop_locked(struct dwc_softc *sc) 200 { 201 if_t ifp; 202 203 DWC_ASSERT_LOCKED(sc); 204 205 ifp = sc->ifp; 206 if_setdrvflagbits(ifp, 0, IFF_DRV_RUNNING | IFF_DRV_OACTIVE); 207 sc->tx_watchdog_count = 0; 208 sc->stats_harvest_count = 0; 209 210 callout_stop(&sc->dwc_callout); 211 212 dma1000_stop(sc); 213 dwc1000_enable_mac(sc, false); 214 } 215 216 static int 217 dwc_ioctl(if_t ifp, u_long cmd, caddr_t data) 218 { 219 struct dwc_softc *sc; 220 struct mii_data *mii; 221 struct ifreq *ifr; 222 int flags, mask, error; 223 224 sc = if_getsoftc(ifp); 225 ifr = (struct ifreq *)data; 226 227 error = 0; 228 switch (cmd) { 229 case SIOCSIFFLAGS: 230 DWC_LOCK(sc); 231 if (if_getflags(ifp) & IFF_UP) { 232 if (if_getdrvflags(ifp) & IFF_DRV_RUNNING) { 233 flags = if_getflags(ifp) ^ sc->if_flags; 234 if ((flags & (IFF_PROMISC|IFF_ALLMULTI)) != 0) 235 dwc1000_setup_rxfilter(sc); 236 } else { 237 if (!sc->is_detaching) 238 dwc_init_locked(sc); 239 } 240 } else { 241 if (if_getdrvflags(ifp) & IFF_DRV_RUNNING) 242 dwc_stop_locked(sc); 243 } 244 sc->if_flags = if_getflags(ifp); 245 DWC_UNLOCK(sc); 246 break; 247 case SIOCADDMULTI: 248 case SIOCDELMULTI: 249 if (if_getdrvflags(ifp) & IFF_DRV_RUNNING) { 250 DWC_LOCK(sc); 251 dwc1000_setup_rxfilter(sc); 252 DWC_UNLOCK(sc); 253 } 254 break; 255 case SIOCSIFMEDIA: 256 case SIOCGIFMEDIA: 257 mii = sc->mii_softc; 258 error = ifmedia_ioctl(ifp, ifr, &mii->mii_media, cmd); 259 break; 260 case SIOCSIFCAP: 261 mask = ifr->ifr_reqcap ^ if_getcapenable(ifp); 262 if (mask & IFCAP_VLAN_MTU) { 263 /* No work to do except acknowledge the change took */ 264 if_togglecapenable(ifp, IFCAP_VLAN_MTU); 265 } 266 if (mask & IFCAP_RXCSUM) 267 if_togglecapenable(ifp, IFCAP_RXCSUM); 268 if (mask & IFCAP_TXCSUM) 269 if_togglecapenable(ifp, IFCAP_TXCSUM); 270 if ((if_getcapenable(ifp) & IFCAP_TXCSUM) != 0) 271 if_sethwassistbits(ifp, CSUM_IP | CSUM_UDP | CSUM_TCP, 0); 272 else 273 if_sethwassistbits(ifp, 0, CSUM_IP | CSUM_UDP | CSUM_TCP); 274 275 if (if_getdrvflags(ifp) & IFF_DRV_RUNNING) { 276 DWC_LOCK(sc); 277 dwc1000_enable_csum_offload(sc); 278 DWC_UNLOCK(sc); 279 } 280 break; 281 282 default: 283 error = ether_ioctl(ifp, cmd, data); 284 break; 285 } 286 287 return (error); 288 } 289 290 /* 291 * Interrupts functions 292 */ 293 294 295 static void 296 dwc_intr(void *arg) 297 { 298 struct dwc_softc *sc; 299 int rv; 300 301 sc = arg; 302 DWC_LOCK(sc); 303 dwc1000_intr(sc); 304 rv = dma1000_intr(sc); 305 if (rv == EIO) { 306 device_printf(sc->dev, 307 "Ethernet DMA error, restarting controller.\n"); 308 dwc_stop_locked(sc); 309 dwc_init_locked(sc); 310 } 311 DWC_UNLOCK(sc); 312 } 313 314 static void 315 dwc_tick(void *arg) 316 { 317 struct dwc_softc *sc; 318 if_t ifp; 319 int link_was_up; 320 321 sc = arg; 322 323 DWC_ASSERT_LOCKED(sc); 324 325 ifp = sc->ifp; 326 327 if ((if_getdrvflags(ifp) & IFF_DRV_RUNNING) == 0) 328 return; 329 330 /* 331 * Typical tx watchdog. If this fires it indicates that we enqueued 332 * packets for output and never got a txdone interrupt for them. Maybe 333 * it's a missed interrupt somehow, just pretend we got one. 334 */ 335 if (sc->tx_watchdog_count > 0) { 336 if (--sc->tx_watchdog_count == 0) { 337 dma1000_txfinish_locked(sc); 338 } 339 } 340 341 /* Gather stats from hardware counters. */ 342 dwc1000_harvest_stats(sc); 343 344 /* Check the media status. */ 345 link_was_up = sc->link_is_up; 346 mii_tick(sc->mii_softc); 347 if (sc->link_is_up && !link_was_up) 348 dwc_txstart_locked(sc); 349 350 /* Schedule another check one second from now. */ 351 callout_reset(&sc->dwc_callout, hz, dwc_tick, sc); 352 } 353 354 static int 355 dwc_reset_phy(struct dwc_softc *sc) 356 { 357 pcell_t gpio_prop[4]; 358 pcell_t delay_prop[3]; 359 phandle_t gpio_node; 360 device_t gpio; 361 uint32_t pin, flags; 362 uint32_t pin_value; 363 364 /* 365 * All those properties are deprecated but still used in some DTS. 366 * The new way to deal with this is to use the generic bindings 367 * present in the ethernet-phy node. 368 */ 369 if (OF_getencprop(sc->node, "snps,reset-gpio", 370 gpio_prop, sizeof(gpio_prop)) <= 0) 371 return (0); 372 373 if (OF_getencprop(sc->node, "snps,reset-delays-us", 374 delay_prop, sizeof(delay_prop)) <= 0) { 375 device_printf(sc->dev, 376 "Wrong property for snps,reset-delays-us"); 377 return (ENXIO); 378 } 379 380 gpio_node = OF_node_from_xref(gpio_prop[0]); 381 if ((gpio = OF_device_from_xref(gpio_prop[0])) == NULL) { 382 device_printf(sc->dev, 383 "Can't find gpio controller for phy reset\n"); 384 return (ENXIO); 385 } 386 387 if (GPIO_MAP_GPIOS(gpio, sc->node, gpio_node, 388 nitems(gpio_prop) - 1, 389 gpio_prop + 1, &pin, &flags) != 0) { 390 device_printf(sc->dev, "Can't map gpio for phy reset\n"); 391 return (ENXIO); 392 } 393 394 pin_value = GPIO_PIN_LOW; 395 if (OF_hasprop(sc->node, "snps,reset-active-low")) 396 pin_value = GPIO_PIN_HIGH; 397 398 GPIO_PIN_SETFLAGS(gpio, pin, GPIO_PIN_OUTPUT); 399 GPIO_PIN_SET(gpio, pin, pin_value); 400 DELAY(delay_prop[0] * 5); 401 GPIO_PIN_SET(gpio, pin, !pin_value); 402 DELAY(delay_prop[1] * 5); 403 GPIO_PIN_SET(gpio, pin, pin_value); 404 DELAY(delay_prop[2] * 5); 405 406 return (0); 407 } 408 409 static int 410 dwc_clock_init(struct dwc_softc *sc) 411 { 412 int rv; 413 int64_t freq; 414 415 /* Required clock */ 416 rv = clk_get_by_ofw_name(sc->dev, 0, "stmmaceth", &sc->clk_stmmaceth); 417 if (rv != 0) { 418 device_printf(sc->dev, "Cannot get GMAC main clock\n"); 419 return (ENXIO); 420 } 421 if ((rv = clk_enable(sc->clk_stmmaceth)) != 0) { 422 device_printf(sc->dev, "could not enable main clock\n"); 423 return (rv); 424 } 425 426 /* Optional clock */ 427 rv = clk_get_by_ofw_name(sc->dev, 0, "pclk", &sc->clk_pclk); 428 if (rv != 0) 429 return (0); 430 if ((rv = clk_enable(sc->clk_pclk)) != 0) { 431 device_printf(sc->dev, "could not enable peripheral clock\n"); 432 return (rv); 433 } 434 435 if (bootverbose) { 436 clk_get_freq(sc->clk_stmmaceth, &freq); 437 device_printf(sc->dev, "MAC clock(%s) freq: %jd\n", 438 clk_get_name(sc->clk_stmmaceth), (intmax_t)freq); 439 } 440 441 return (0); 442 } 443 444 static int 445 dwc_reset_deassert(struct dwc_softc *sc) 446 { 447 int rv; 448 449 /* Required reset */ 450 rv = hwreset_get_by_ofw_name(sc->dev, 0, "stmmaceth", &sc->rst_stmmaceth); 451 if (rv != 0) { 452 device_printf(sc->dev, "Cannot get GMAC reset\n"); 453 return (ENXIO); 454 } 455 rv = hwreset_deassert(sc->rst_stmmaceth); 456 if (rv != 0) { 457 device_printf(sc->dev, "could not de-assert GMAC reset\n"); 458 return (rv); 459 } 460 461 /* Optional reset */ 462 rv = hwreset_get_by_ofw_name(sc->dev, 0, "ahb", &sc->rst_ahb); 463 if (rv != 0) 464 return (0); 465 rv = hwreset_deassert(sc->rst_ahb); 466 if (rv != 0) { 467 device_printf(sc->dev, "could not de-assert AHB reset\n"); 468 return (rv); 469 } 470 471 return (0); 472 } 473 474 /* 475 * Probe/Attach functions 476 */ 477 478 static int 479 dwc_probe(device_t dev) 480 { 481 482 if (!ofw_bus_status_okay(dev)) 483 return (ENXIO); 484 485 if (!ofw_bus_is_compatible(dev, "snps,dwmac")) 486 return (ENXIO); 487 488 device_set_desc(dev, "Gigabit Ethernet Controller"); 489 return (BUS_PROBE_DEFAULT); 490 } 491 492 static int 493 dwc_attach(device_t dev) 494 { 495 uint8_t macaddr[ETHER_ADDR_LEN]; 496 struct dwc_softc *sc; 497 if_t ifp; 498 int error; 499 uint32_t pbl; 500 501 sc = device_get_softc(dev); 502 sc->dev = dev; 503 sc->rx_idx = 0; 504 sc->tx_desccount = TX_DESC_COUNT; 505 sc->tx_mapcount = 0; 506 507 sc->node = ofw_bus_get_node(dev); 508 sc->phy_mode = mii_fdt_get_contype(sc->node); 509 switch (sc->phy_mode) { 510 case MII_CONTYPE_RGMII: 511 case MII_CONTYPE_RGMII_ID: 512 case MII_CONTYPE_RGMII_RXID: 513 case MII_CONTYPE_RGMII_TXID: 514 case MII_CONTYPE_RMII: 515 case MII_CONTYPE_MII: 516 break; 517 default: 518 device_printf(dev, "Unsupported MII type\n"); 519 return (ENXIO); 520 } 521 522 if (OF_getencprop(sc->node, "snps,pbl", &pbl, sizeof(uint32_t)) <= 0) 523 pbl = DMA_DEFAULT_PBL; 524 if (OF_getencprop(sc->node, "snps,txpbl", &sc->txpbl, sizeof(uint32_t)) <= 0) 525 sc->txpbl = pbl; 526 if (OF_getencprop(sc->node, "snps,rxpbl", &sc->rxpbl, sizeof(uint32_t)) <= 0) 527 sc->rxpbl = pbl; 528 if (OF_hasprop(sc->node, "snps,no-pbl-x8") == 1) 529 sc->nopblx8 = true; 530 if (OF_hasprop(sc->node, "snps,fixed-burst") == 1) 531 sc->fixed_burst = true; 532 if (OF_hasprop(sc->node, "snps,mixed-burst") == 1) 533 sc->mixed_burst = true; 534 if (OF_hasprop(sc->node, "snps,aal") == 1) 535 sc->aal = true; 536 537 error = clk_set_assigned(dev, ofw_bus_get_node(dev)); 538 if (error != 0) { 539 device_printf(dev, "clk_set_assigned failed\n"); 540 return (error); 541 } 542 543 /* Enable main clock */ 544 if ((error = dwc_clock_init(sc)) != 0) 545 return (error); 546 /* De-assert main reset */ 547 if ((error = dwc_reset_deassert(sc)) != 0) 548 return (error); 549 550 if (IF_DWC_INIT(dev) != 0) 551 return (ENXIO); 552 553 if ((sc->mii_clk = IF_DWC_MII_CLK(dev)) < 0) { 554 device_printf(dev, "Cannot get mii clock value %d\n", -sc->mii_clk); 555 return (ENXIO); 556 } 557 558 if (bus_alloc_resources(dev, dwc_spec, sc->res)) { 559 device_printf(dev, "could not allocate resources\n"); 560 return (ENXIO); 561 } 562 563 /* Read MAC before reset */ 564 dwc1000_get_hwaddr(sc, macaddr); 565 566 /* Reset the PHY if needed */ 567 if (dwc_reset_phy(sc) != 0) { 568 device_printf(dev, "Can't reset the PHY\n"); 569 bus_release_resources(dev, dwc_spec, sc->res); 570 return (ENXIO); 571 } 572 573 /* Reset */ 574 if ((error = dma1000_reset(sc)) != 0) { 575 device_printf(sc->dev, "Can't reset DMA controller.\n"); 576 bus_release_resources(sc->dev, dwc_spec, sc->res); 577 return (error); 578 } 579 580 if (dma1000_init(sc)) { 581 bus_release_resources(dev, dwc_spec, sc->res); 582 return (ENXIO); 583 } 584 585 mtx_init(&sc->mtx, device_get_nameunit(sc->dev), 586 MTX_NETWORK_LOCK, MTX_DEF); 587 588 callout_init_mtx(&sc->dwc_callout, &sc->mtx, 0); 589 590 /* Setup interrupt handler. */ 591 error = bus_setup_intr(dev, sc->res[1], INTR_TYPE_NET | INTR_MPSAFE, 592 NULL, dwc_intr, sc, &sc->intr_cookie); 593 if (error != 0) { 594 device_printf(dev, "could not setup interrupt handler.\n"); 595 bus_release_resources(dev, dwc_spec, sc->res); 596 return (ENXIO); 597 } 598 599 /* Set up the ethernet interface. */ 600 sc->ifp = ifp = if_alloc(IFT_ETHER); 601 602 if_setsoftc(ifp, sc); 603 if_initname(ifp, device_get_name(dev), device_get_unit(dev)); 604 if_setflags(sc->ifp, IFF_BROADCAST | IFF_SIMPLEX | IFF_MULTICAST); 605 if_setstartfn(ifp, dwc_txstart); 606 if_setioctlfn(ifp, dwc_ioctl); 607 if_setinitfn(ifp, dwc_init); 608 if_setsendqlen(ifp, TX_MAP_COUNT - 1); 609 if_setsendqready(sc->ifp); 610 if_sethwassist(sc->ifp, CSUM_IP | CSUM_UDP | CSUM_TCP); 611 if_setcapabilities(sc->ifp, IFCAP_VLAN_MTU | IFCAP_HWCSUM); 612 if_setcapenable(sc->ifp, if_getcapabilities(sc->ifp)); 613 614 /* Attach the mii driver. */ 615 error = mii_attach(dev, &sc->miibus, ifp, dwc_media_change, 616 dwc_media_status, BMSR_DEFCAPMASK, MII_PHY_ANY, 617 MII_OFFSET_ANY, 0); 618 619 if (error != 0) { 620 device_printf(dev, "PHY attach failed\n"); 621 bus_teardown_intr(dev, sc->res[1], sc->intr_cookie); 622 bus_release_resources(dev, dwc_spec, sc->res); 623 return (ENXIO); 624 } 625 sc->mii_softc = device_get_softc(sc->miibus); 626 627 /* All ready to run, attach the ethernet interface. */ 628 ether_ifattach(ifp, macaddr); 629 sc->is_attached = true; 630 631 return (0); 632 } 633 634 static int 635 dwc_detach(device_t dev) 636 { 637 struct dwc_softc *sc; 638 639 sc = device_get_softc(dev); 640 641 /* 642 * Disable and tear down interrupts before anything else, so we don't 643 * race with the handler. 644 */ 645 dwc1000_intr_disable(sc); 646 if (sc->intr_cookie != NULL) { 647 bus_teardown_intr(dev, sc->res[1], sc->intr_cookie); 648 } 649 650 if (sc->is_attached) { 651 DWC_LOCK(sc); 652 sc->is_detaching = true; 653 dwc_stop_locked(sc); 654 DWC_UNLOCK(sc); 655 callout_drain(&sc->dwc_callout); 656 ether_ifdetach(sc->ifp); 657 } 658 659 if (sc->miibus != NULL) { 660 device_delete_child(dev, sc->miibus); 661 sc->miibus = NULL; 662 } 663 bus_generic_detach(dev); 664 665 /* Free DMA descriptors */ 666 dma1000_free(sc); 667 668 if (sc->ifp != NULL) { 669 if_free(sc->ifp); 670 sc->ifp = NULL; 671 } 672 673 bus_release_resources(dev, dwc_spec, sc->res); 674 675 mtx_destroy(&sc->mtx); 676 return (0); 677 } 678 679 static device_method_t dwc_methods[] = { 680 DEVMETHOD(device_probe, dwc_probe), 681 DEVMETHOD(device_attach, dwc_attach), 682 DEVMETHOD(device_detach, dwc_detach), 683 684 /* MII Interface */ 685 DEVMETHOD(miibus_readreg, dwc1000_miibus_read_reg), 686 DEVMETHOD(miibus_writereg, dwc1000_miibus_write_reg), 687 DEVMETHOD(miibus_statchg, dwc1000_miibus_statchg), 688 689 { 0, 0 } 690 }; 691 692 driver_t dwc_driver = { 693 "dwc", 694 dwc_methods, 695 sizeof(struct dwc_softc), 696 }; 697 698 DRIVER_MODULE(dwc, simplebus, dwc_driver, 0, 0); 699 DRIVER_MODULE(miibus, dwc, miibus_driver, 0, 0); 700 701 MODULE_DEPEND(dwc, ether, 1, 1, 1); 702 MODULE_DEPEND(dwc, miibus, 1, 1, 1); 703