15d43fd68SRuslan Bukin /*-
25d43fd68SRuslan Bukin * Copyright (c) 2014 Ruslan Bukin <br@bsdpad.com>
35d43fd68SRuslan Bukin *
45d43fd68SRuslan Bukin * This software was developed by SRI International and the University of
55d43fd68SRuslan Bukin * Cambridge Computer Laboratory under DARPA/AFRL contract (FA8750-10-C-0237)
65d43fd68SRuslan Bukin * ("CTSRD"), as part of the DARPA CRASH research programme.
75d43fd68SRuslan Bukin *
85d43fd68SRuslan Bukin * Redistribution and use in source and binary forms, with or without
95d43fd68SRuslan Bukin * modification, are permitted provided that the following conditions
105d43fd68SRuslan Bukin * are met:
115d43fd68SRuslan Bukin * 1. Redistributions of source code must retain the above copyright
125d43fd68SRuslan Bukin * notice, this list of conditions and the following disclaimer.
135d43fd68SRuslan Bukin * 2. Redistributions in binary form must reproduce the above copyright
145d43fd68SRuslan Bukin * notice, this list of conditions and the following disclaimer in the
155d43fd68SRuslan Bukin * documentation and/or other materials provided with the distribution.
165d43fd68SRuslan Bukin *
175d43fd68SRuslan Bukin * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
185d43fd68SRuslan Bukin * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
195d43fd68SRuslan Bukin * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
205d43fd68SRuslan Bukin * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
215d43fd68SRuslan Bukin * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
225d43fd68SRuslan Bukin * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
235d43fd68SRuslan Bukin * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
245d43fd68SRuslan Bukin * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
255d43fd68SRuslan Bukin * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
265d43fd68SRuslan Bukin * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
275d43fd68SRuslan Bukin * SUCH DAMAGE.
285d43fd68SRuslan Bukin */
295d43fd68SRuslan Bukin
305d43fd68SRuslan Bukin /*
315d43fd68SRuslan Bukin * Ethernet media access controller (EMAC)
325d43fd68SRuslan Bukin * Chapter 17, Altera Cyclone V Device Handbook (CV-5V2 2014.07.22)
335d43fd68SRuslan Bukin *
345d43fd68SRuslan Bukin * EMAC is an instance of the Synopsys DesignWare 3504-0
355d43fd68SRuslan Bukin * Universal 10/100/1000 Ethernet MAC (DWC_gmac).
365d43fd68SRuslan Bukin */
375d43fd68SRuslan Bukin
385d43fd68SRuslan Bukin #include <sys/param.h>
395d43fd68SRuslan Bukin #include <sys/systm.h>
405d43fd68SRuslan Bukin #include <sys/bus.h>
41d7acb49aSJared McNeill #include <sys/gpio.h>
425d43fd68SRuslan Bukin #include <sys/kernel.h>
435d43fd68SRuslan Bukin #include <sys/lock.h>
44da9a326bSLuiz Otavio O Souza #include <sys/malloc.h>
455d43fd68SRuslan Bukin #include <sys/mbuf.h>
46da9a326bSLuiz Otavio O Souza #include <sys/module.h>
475d43fd68SRuslan Bukin #include <sys/mutex.h>
48da9a326bSLuiz Otavio O Souza #include <sys/rman.h>
495d43fd68SRuslan Bukin #include <sys/socket.h>
505d43fd68SRuslan Bukin #include <sys/sockio.h>
515d43fd68SRuslan Bukin
525d43fd68SRuslan Bukin #include <net/bpf.h>
535d43fd68SRuslan Bukin #include <net/if.h>
545d43fd68SRuslan Bukin #include <net/ethernet.h>
555d43fd68SRuslan Bukin #include <net/if_dl.h>
565d43fd68SRuslan Bukin #include <net/if_media.h>
575d43fd68SRuslan Bukin #include <net/if_types.h>
585d43fd68SRuslan Bukin #include <net/if_var.h>
595d43fd68SRuslan Bukin
605d43fd68SRuslan Bukin #include <machine/bus.h>
615d43fd68SRuslan Bukin
62be82b3a0SEmmanuel Vadot #include <dev/clk/clk.h>
63*1f469a9fSEmmanuel Vadot #include <dev/hwreset/hwreset.h>
6450059a60SEmmanuel Vadot
655d43fd68SRuslan Bukin #include <dev/mii/mii.h>
665d43fd68SRuslan Bukin #include <dev/mii/miivar.h>
67da9a326bSLuiz Otavio O Souza #include <dev/ofw/ofw_bus.h>
68da9a326bSLuiz Otavio O Souza #include <dev/ofw/ofw_bus_subr.h>
69f77d8d10SEmmanuel Vadot #include <dev/mii/mii_fdt.h>
70da9a326bSLuiz Otavio O Souza
71c36125f6SEmmanuel Vadot #include <dev/dwc/if_dwcvar.h>
7262519d5aSEmmanuel Vadot #include <dev/dwc/dwc1000_core.h>
73972adf0fSEmmanuel Vadot #include <dev/dwc/dwc1000_dma.h>
74c36125f6SEmmanuel Vadot
755df53927SLuiz Otavio O Souza #include "if_dwc_if.h"
76d7acb49aSJared McNeill #include "gpio_if.h"
775d43fd68SRuslan Bukin #include "miibus_if.h"
785d43fd68SRuslan Bukin
795d43fd68SRuslan Bukin static struct resource_spec dwc_spec[] = {
805d43fd68SRuslan Bukin { SYS_RES_MEMORY, 0, RF_ACTIVE },
815d43fd68SRuslan Bukin { SYS_RES_IRQ, 0, RF_ACTIVE },
825d43fd68SRuslan Bukin { -1, 0 }
835d43fd68SRuslan Bukin };
845d43fd68SRuslan Bukin
855d43fd68SRuslan Bukin static void dwc_stop_locked(struct dwc_softc *sc);
865d43fd68SRuslan Bukin
872a35d391SEmmanuel Vadot static void dwc_tick(void *arg);
882a35d391SEmmanuel Vadot
892a35d391SEmmanuel Vadot /*
902a35d391SEmmanuel Vadot * Media functions
912a35d391SEmmanuel Vadot */
922a35d391SEmmanuel Vadot
932a35d391SEmmanuel Vadot static void
dwc_media_status(if_t ifp,struct ifmediareq * ifmr)94ca018790SMitchell Horne dwc_media_status(if_t ifp, struct ifmediareq *ifmr)
952a35d391SEmmanuel Vadot {
962a35d391SEmmanuel Vadot struct dwc_softc *sc;
972a35d391SEmmanuel Vadot struct mii_data *mii;
982a35d391SEmmanuel Vadot
99ca018790SMitchell Horne sc = if_getsoftc(ifp);
1002a35d391SEmmanuel Vadot mii = sc->mii_softc;
1012a35d391SEmmanuel Vadot DWC_LOCK(sc);
1022a35d391SEmmanuel Vadot mii_pollstat(mii);
1032a35d391SEmmanuel Vadot ifmr->ifm_active = mii->mii_media_active;
1042a35d391SEmmanuel Vadot ifmr->ifm_status = mii->mii_media_status;
1052a35d391SEmmanuel Vadot DWC_UNLOCK(sc);
1062a35d391SEmmanuel Vadot }
1072a35d391SEmmanuel Vadot
1082a35d391SEmmanuel Vadot static int
dwc_media_change_locked(struct dwc_softc * sc)1092a35d391SEmmanuel Vadot dwc_media_change_locked(struct dwc_softc *sc)
1102a35d391SEmmanuel Vadot {
1112a35d391SEmmanuel Vadot
1122a35d391SEmmanuel Vadot return (mii_mediachg(sc->mii_softc));
1132a35d391SEmmanuel Vadot }
1142a35d391SEmmanuel Vadot
1152a35d391SEmmanuel Vadot static int
dwc_media_change(if_t ifp)116ca018790SMitchell Horne dwc_media_change(if_t ifp)
1172a35d391SEmmanuel Vadot {
1182a35d391SEmmanuel Vadot struct dwc_softc *sc;
1192a35d391SEmmanuel Vadot int error;
1202a35d391SEmmanuel Vadot
121ca018790SMitchell Horne sc = if_getsoftc(ifp);
1222a35d391SEmmanuel Vadot
1232a35d391SEmmanuel Vadot DWC_LOCK(sc);
1242a35d391SEmmanuel Vadot error = dwc_media_change_locked(sc);
1252a35d391SEmmanuel Vadot DWC_UNLOCK(sc);
1262a35d391SEmmanuel Vadot return (error);
1272a35d391SEmmanuel Vadot }
1282a35d391SEmmanuel Vadot
1292a35d391SEmmanuel Vadot /*
1302a35d391SEmmanuel Vadot * if_ functions
1312a35d391SEmmanuel Vadot */
1322a35d391SEmmanuel Vadot
133f88e0af6SEmmanuel Vadot static void
dwc_txstart_locked(struct dwc_softc * sc)1342a35d391SEmmanuel Vadot dwc_txstart_locked(struct dwc_softc *sc)
1355d43fd68SRuslan Bukin {
136ca018790SMitchell Horne if_t ifp;
1372a35d391SEmmanuel Vadot
1382a35d391SEmmanuel Vadot DWC_ASSERT_LOCKED(sc);
1392a35d391SEmmanuel Vadot
1402a35d391SEmmanuel Vadot if (!sc->link_is_up)
1412a35d391SEmmanuel Vadot return;
1422a35d391SEmmanuel Vadot
1432a35d391SEmmanuel Vadot ifp = sc->ifp;
1442a35d391SEmmanuel Vadot
1453bbd11eeSEmmanuel Vadot if ((if_getdrvflags(ifp) & (IFF_DRV_RUNNING|IFF_DRV_OACTIVE)) !=
1463bbd11eeSEmmanuel Vadot IFF_DRV_RUNNING)
1472a35d391SEmmanuel Vadot return;
148afa0f66eSEmmanuel Vadot dma1000_txstart(sc);
1492a35d391SEmmanuel Vadot }
1502a35d391SEmmanuel Vadot
1512a35d391SEmmanuel Vadot static void
dwc_txstart(if_t ifp)152ca018790SMitchell Horne dwc_txstart(if_t ifp)
1532a35d391SEmmanuel Vadot {
154ca018790SMitchell Horne struct dwc_softc *sc = if_getsoftc(ifp);
1552a35d391SEmmanuel Vadot
1562a35d391SEmmanuel Vadot DWC_LOCK(sc);
1572a35d391SEmmanuel Vadot dwc_txstart_locked(sc);
1582a35d391SEmmanuel Vadot DWC_UNLOCK(sc);
1592a35d391SEmmanuel Vadot }
1602a35d391SEmmanuel Vadot
1612a35d391SEmmanuel Vadot static void
dwc_init_locked(struct dwc_softc * sc)1622a35d391SEmmanuel Vadot dwc_init_locked(struct dwc_softc *sc)
1632a35d391SEmmanuel Vadot {
164ca018790SMitchell Horne if_t ifp = sc->ifp;
1652a35d391SEmmanuel Vadot
1662a35d391SEmmanuel Vadot DWC_ASSERT_LOCKED(sc);
1672a35d391SEmmanuel Vadot
1683bbd11eeSEmmanuel Vadot if (if_getdrvflags(ifp) & IFF_DRV_RUNNING)
1692a35d391SEmmanuel Vadot return;
1702a35d391SEmmanuel Vadot
1716501fcdcSJiahao LI /*
17262519d5aSEmmanuel Vadot * Call mii_mediachg() which will call back into dwc1000_miibus_statchg()
1736501fcdcSJiahao LI * to set up the remaining config registers based on current media.
1746501fcdcSJiahao LI */
1756501fcdcSJiahao LI mii_mediachg(sc->mii_softc);
1766501fcdcSJiahao LI
17762519d5aSEmmanuel Vadot dwc1000_setup_rxfilter(sc);
17862519d5aSEmmanuel Vadot dwc1000_core_setup(sc);
17962519d5aSEmmanuel Vadot dwc1000_enable_mac(sc, true);
18062519d5aSEmmanuel Vadot dwc1000_enable_csum_offload(sc);
181972adf0fSEmmanuel Vadot dma1000_start(sc);
1822a35d391SEmmanuel Vadot
1832a35d391SEmmanuel Vadot if_setdrvflagbits(ifp, IFF_DRV_RUNNING, IFF_DRV_OACTIVE);
1845d43fd68SRuslan Bukin
1852a35d391SEmmanuel Vadot callout_reset(&sc->dwc_callout, hz, dwc_tick, sc);
1862a35d391SEmmanuel Vadot }
1872a35d391SEmmanuel Vadot
1882a35d391SEmmanuel Vadot static void
dwc_init(void * if_softc)1892a35d391SEmmanuel Vadot dwc_init(void *if_softc)
1902a35d391SEmmanuel Vadot {
1912a35d391SEmmanuel Vadot struct dwc_softc *sc = if_softc;
1922a35d391SEmmanuel Vadot
1932a35d391SEmmanuel Vadot DWC_LOCK(sc);
1942a35d391SEmmanuel Vadot dwc_init_locked(sc);
1952a35d391SEmmanuel Vadot DWC_UNLOCK(sc);
1962a35d391SEmmanuel Vadot }
1972a35d391SEmmanuel Vadot
1982a35d391SEmmanuel Vadot static void
dwc_stop_locked(struct dwc_softc * sc)1992a35d391SEmmanuel Vadot dwc_stop_locked(struct dwc_softc *sc)
2002a35d391SEmmanuel Vadot {
201ca018790SMitchell Horne if_t ifp;
2022a35d391SEmmanuel Vadot
2032a35d391SEmmanuel Vadot DWC_ASSERT_LOCKED(sc);
2042a35d391SEmmanuel Vadot
2052a35d391SEmmanuel Vadot ifp = sc->ifp;
2063bbd11eeSEmmanuel Vadot if_setdrvflagbits(ifp, 0, IFF_DRV_RUNNING | IFF_DRV_OACTIVE);
2072a35d391SEmmanuel Vadot sc->tx_watchdog_count = 0;
2082a35d391SEmmanuel Vadot sc->stats_harvest_count = 0;
2092a35d391SEmmanuel Vadot
2102a35d391SEmmanuel Vadot callout_stop(&sc->dwc_callout);
2112a35d391SEmmanuel Vadot
212972adf0fSEmmanuel Vadot dma1000_stop(sc);
21362519d5aSEmmanuel Vadot dwc1000_enable_mac(sc, false);
2142a35d391SEmmanuel Vadot }
2152a35d391SEmmanuel Vadot
2162a35d391SEmmanuel Vadot static int
dwc_ioctl(if_t ifp,u_long cmd,caddr_t data)217ca018790SMitchell Horne dwc_ioctl(if_t ifp, u_long cmd, caddr_t data)
2182a35d391SEmmanuel Vadot {
2192a35d391SEmmanuel Vadot struct dwc_softc *sc;
2202a35d391SEmmanuel Vadot struct mii_data *mii;
2212a35d391SEmmanuel Vadot struct ifreq *ifr;
2223bbd11eeSEmmanuel Vadot int flags, mask, error;
2232a35d391SEmmanuel Vadot
224ca018790SMitchell Horne sc = if_getsoftc(ifp);
2252a35d391SEmmanuel Vadot ifr = (struct ifreq *)data;
2262a35d391SEmmanuel Vadot
2272a35d391SEmmanuel Vadot error = 0;
2282a35d391SEmmanuel Vadot switch (cmd) {
2292a35d391SEmmanuel Vadot case SIOCSIFFLAGS:
2302a35d391SEmmanuel Vadot DWC_LOCK(sc);
2313bbd11eeSEmmanuel Vadot if (if_getflags(ifp) & IFF_UP) {
2323bbd11eeSEmmanuel Vadot if (if_getdrvflags(ifp) & IFF_DRV_RUNNING) {
2333bbd11eeSEmmanuel Vadot flags = if_getflags(ifp) ^ sc->if_flags;
2343bbd11eeSEmmanuel Vadot if ((flags & (IFF_PROMISC|IFF_ALLMULTI)) != 0)
23562519d5aSEmmanuel Vadot dwc1000_setup_rxfilter(sc);
2365d43fd68SRuslan Bukin } else {
2372a35d391SEmmanuel Vadot if (!sc->is_detaching)
2382a35d391SEmmanuel Vadot dwc_init_locked(sc);
2392a35d391SEmmanuel Vadot }
2402a35d391SEmmanuel Vadot } else {
2413bbd11eeSEmmanuel Vadot if (if_getdrvflags(ifp) & IFF_DRV_RUNNING)
2422a35d391SEmmanuel Vadot dwc_stop_locked(sc);
2432a35d391SEmmanuel Vadot }
2443bbd11eeSEmmanuel Vadot sc->if_flags = if_getflags(ifp);
2452a35d391SEmmanuel Vadot DWC_UNLOCK(sc);
2462a35d391SEmmanuel Vadot break;
2472a35d391SEmmanuel Vadot case SIOCADDMULTI:
2482a35d391SEmmanuel Vadot case SIOCDELMULTI:
2493bbd11eeSEmmanuel Vadot if (if_getdrvflags(ifp) & IFF_DRV_RUNNING) {
2502a35d391SEmmanuel Vadot DWC_LOCK(sc);
25162519d5aSEmmanuel Vadot dwc1000_setup_rxfilter(sc);
2522a35d391SEmmanuel Vadot DWC_UNLOCK(sc);
2532a35d391SEmmanuel Vadot }
2542a35d391SEmmanuel Vadot break;
2552a35d391SEmmanuel Vadot case SIOCSIFMEDIA:
2562a35d391SEmmanuel Vadot case SIOCGIFMEDIA:
2572a35d391SEmmanuel Vadot mii = sc->mii_softc;
2582a35d391SEmmanuel Vadot error = ifmedia_ioctl(ifp, ifr, &mii->mii_media, cmd);
2592a35d391SEmmanuel Vadot break;
2602a35d391SEmmanuel Vadot case SIOCSIFCAP:
2613bbd11eeSEmmanuel Vadot mask = ifr->ifr_reqcap ^ if_getcapenable(ifp);
2622a35d391SEmmanuel Vadot if (mask & IFCAP_VLAN_MTU) {
2632a35d391SEmmanuel Vadot /* No work to do except acknowledge the change took */
2643bbd11eeSEmmanuel Vadot if_togglecapenable(ifp, IFCAP_VLAN_MTU);
2652a35d391SEmmanuel Vadot }
26698ea5a7bSEmmanuel Vadot if (mask & IFCAP_RXCSUM)
26798ea5a7bSEmmanuel Vadot if_togglecapenable(ifp, IFCAP_RXCSUM);
26898ea5a7bSEmmanuel Vadot if (mask & IFCAP_TXCSUM)
26998ea5a7bSEmmanuel Vadot if_togglecapenable(ifp, IFCAP_TXCSUM);
27098ea5a7bSEmmanuel Vadot if ((if_getcapenable(ifp) & IFCAP_TXCSUM) != 0)
27198ea5a7bSEmmanuel Vadot if_sethwassistbits(ifp, CSUM_IP | CSUM_UDP | CSUM_TCP, 0);
27298ea5a7bSEmmanuel Vadot else
27398ea5a7bSEmmanuel Vadot if_sethwassistbits(ifp, 0, CSUM_IP | CSUM_UDP | CSUM_TCP);
27435c9edabSJiahao Li
27535c9edabSJiahao Li if (if_getdrvflags(ifp) & IFF_DRV_RUNNING) {
27635c9edabSJiahao Li DWC_LOCK(sc);
27762519d5aSEmmanuel Vadot dwc1000_enable_csum_offload(sc);
27835c9edabSJiahao Li DWC_UNLOCK(sc);
27935c9edabSJiahao Li }
2802a35d391SEmmanuel Vadot break;
2812a35d391SEmmanuel Vadot
2822a35d391SEmmanuel Vadot default:
2832a35d391SEmmanuel Vadot error = ether_ioctl(ifp, cmd, data);
2842a35d391SEmmanuel Vadot break;
2852a35d391SEmmanuel Vadot }
2862a35d391SEmmanuel Vadot
2872a35d391SEmmanuel Vadot return (error);
2882a35d391SEmmanuel Vadot }
2892a35d391SEmmanuel Vadot
2902a35d391SEmmanuel Vadot /*
2912a35d391SEmmanuel Vadot * Interrupts functions
2922a35d391SEmmanuel Vadot */
2932a35d391SEmmanuel Vadot
2942a35d391SEmmanuel Vadot
2952a35d391SEmmanuel Vadot static void
dwc_intr(void * arg)2962a35d391SEmmanuel Vadot dwc_intr(void *arg)
2972a35d391SEmmanuel Vadot {
2982a35d391SEmmanuel Vadot struct dwc_softc *sc;
29929776aa4SEmmanuel Vadot int rv;
3002a35d391SEmmanuel Vadot
3012a35d391SEmmanuel Vadot sc = arg;
3022a35d391SEmmanuel Vadot DWC_LOCK(sc);
30329776aa4SEmmanuel Vadot dwc1000_intr(sc);
30429776aa4SEmmanuel Vadot rv = dma1000_intr(sc);
30529776aa4SEmmanuel Vadot if (rv == EIO) {
3062a35d391SEmmanuel Vadot device_printf(sc->dev,
3072a35d391SEmmanuel Vadot "Ethernet DMA error, restarting controller.\n");
3082a35d391SEmmanuel Vadot dwc_stop_locked(sc);
3092a35d391SEmmanuel Vadot dwc_init_locked(sc);
3102a35d391SEmmanuel Vadot }
3112a35d391SEmmanuel Vadot DWC_UNLOCK(sc);
3122a35d391SEmmanuel Vadot }
3132a35d391SEmmanuel Vadot
3142a35d391SEmmanuel Vadot static void
dwc_tick(void * arg)3152a35d391SEmmanuel Vadot dwc_tick(void *arg)
3162a35d391SEmmanuel Vadot {
3172a35d391SEmmanuel Vadot struct dwc_softc *sc;
318ca018790SMitchell Horne if_t ifp;
3192a35d391SEmmanuel Vadot int link_was_up;
3202a35d391SEmmanuel Vadot
3212a35d391SEmmanuel Vadot sc = arg;
3222a35d391SEmmanuel Vadot
3232a35d391SEmmanuel Vadot DWC_ASSERT_LOCKED(sc);
3242a35d391SEmmanuel Vadot
3252a35d391SEmmanuel Vadot ifp = sc->ifp;
3262a35d391SEmmanuel Vadot
3273bbd11eeSEmmanuel Vadot if ((if_getdrvflags(ifp) & IFF_DRV_RUNNING) == 0)
3282a35d391SEmmanuel Vadot return;
3292a35d391SEmmanuel Vadot
3302a35d391SEmmanuel Vadot /*
3312a35d391SEmmanuel Vadot * Typical tx watchdog. If this fires it indicates that we enqueued
3322a35d391SEmmanuel Vadot * packets for output and never got a txdone interrupt for them. Maybe
3332a35d391SEmmanuel Vadot * it's a missed interrupt somehow, just pretend we got one.
3342a35d391SEmmanuel Vadot */
3352a35d391SEmmanuel Vadot if (sc->tx_watchdog_count > 0) {
3362a35d391SEmmanuel Vadot if (--sc->tx_watchdog_count == 0) {
337972adf0fSEmmanuel Vadot dma1000_txfinish_locked(sc);
3382a35d391SEmmanuel Vadot }
3392a35d391SEmmanuel Vadot }
3402a35d391SEmmanuel Vadot
3412a35d391SEmmanuel Vadot /* Gather stats from hardware counters. */
34262519d5aSEmmanuel Vadot dwc1000_harvest_stats(sc);
3432a35d391SEmmanuel Vadot
3442a35d391SEmmanuel Vadot /* Check the media status. */
3452a35d391SEmmanuel Vadot link_was_up = sc->link_is_up;
3462a35d391SEmmanuel Vadot mii_tick(sc->mii_softc);
3472a35d391SEmmanuel Vadot if (sc->link_is_up && !link_was_up)
3482a35d391SEmmanuel Vadot dwc_txstart_locked(sc);
3492a35d391SEmmanuel Vadot
3502a35d391SEmmanuel Vadot /* Schedule another check one second from now. */
3512a35d391SEmmanuel Vadot callout_reset(&sc->dwc_callout, hz, dwc_tick, sc);
3522a35d391SEmmanuel Vadot }
3532a35d391SEmmanuel Vadot
354d7acb49aSJared McNeill static int
dwc_reset_phy(struct dwc_softc * sc)355f114aaddSEmmanuel Vadot dwc_reset_phy(struct dwc_softc *sc)
356d7acb49aSJared McNeill {
357d7acb49aSJared McNeill pcell_t gpio_prop[4];
358d7acb49aSJared McNeill pcell_t delay_prop[3];
359f114aaddSEmmanuel Vadot phandle_t gpio_node;
360d7acb49aSJared McNeill device_t gpio;
361d7acb49aSJared McNeill uint32_t pin, flags;
362d7acb49aSJared McNeill uint32_t pin_value;
363d7acb49aSJared McNeill
364f114aaddSEmmanuel Vadot /*
365f114aaddSEmmanuel Vadot * All those properties are deprecated but still used in some DTS.
366f114aaddSEmmanuel Vadot * The new way to deal with this is to use the generic bindings
367f114aaddSEmmanuel Vadot * present in the ethernet-phy node.
368f114aaddSEmmanuel Vadot */
369f114aaddSEmmanuel Vadot if (OF_getencprop(sc->node, "snps,reset-gpio",
370d7acb49aSJared McNeill gpio_prop, sizeof(gpio_prop)) <= 0)
371d7acb49aSJared McNeill return (0);
372d7acb49aSJared McNeill
373f114aaddSEmmanuel Vadot if (OF_getencprop(sc->node, "snps,reset-delays-us",
374d7acb49aSJared McNeill delay_prop, sizeof(delay_prop)) <= 0) {
375f114aaddSEmmanuel Vadot device_printf(sc->dev,
376d7acb49aSJared McNeill "Wrong property for snps,reset-delays-us");
377d7acb49aSJared McNeill return (ENXIO);
378d7acb49aSJared McNeill }
379d7acb49aSJared McNeill
380d7acb49aSJared McNeill gpio_node = OF_node_from_xref(gpio_prop[0]);
381d7acb49aSJared McNeill if ((gpio = OF_device_from_xref(gpio_prop[0])) == NULL) {
382f114aaddSEmmanuel Vadot device_printf(sc->dev,
383d7acb49aSJared McNeill "Can't find gpio controller for phy reset\n");
384d7acb49aSJared McNeill return (ENXIO);
385d7acb49aSJared McNeill }
386d7acb49aSJared McNeill
387f114aaddSEmmanuel Vadot if (GPIO_MAP_GPIOS(gpio, sc->node, gpio_node,
38873a1170aSPedro F. Giffuni nitems(gpio_prop) - 1,
389d7acb49aSJared McNeill gpio_prop + 1, &pin, &flags) != 0) {
390f114aaddSEmmanuel Vadot device_printf(sc->dev, "Can't map gpio for phy reset\n");
391d7acb49aSJared McNeill return (ENXIO);
392d7acb49aSJared McNeill }
393d7acb49aSJared McNeill
394d7acb49aSJared McNeill pin_value = GPIO_PIN_LOW;
395f114aaddSEmmanuel Vadot if (OF_hasprop(sc->node, "snps,reset-active-low"))
396d7acb49aSJared McNeill pin_value = GPIO_PIN_HIGH;
397d7acb49aSJared McNeill
398d7acb49aSJared McNeill GPIO_PIN_SETFLAGS(gpio, pin, GPIO_PIN_OUTPUT);
399d7acb49aSJared McNeill GPIO_PIN_SET(gpio, pin, pin_value);
400c069412eSEmmanuel Vadot DELAY(delay_prop[0] * 5);
401d7acb49aSJared McNeill GPIO_PIN_SET(gpio, pin, !pin_value);
402c069412eSEmmanuel Vadot DELAY(delay_prop[1] * 5);
403d7acb49aSJared McNeill GPIO_PIN_SET(gpio, pin, pin_value);
404c069412eSEmmanuel Vadot DELAY(delay_prop[2] * 5);
405d7acb49aSJared McNeill
406d7acb49aSJared McNeill return (0);
407d7acb49aSJared McNeill }
408d7acb49aSJared McNeill
4096a05f063SJared McNeill static int
dwc_clock_init(struct dwc_softc * sc)41050059a60SEmmanuel Vadot dwc_clock_init(struct dwc_softc *sc)
4116a05f063SJared McNeill {
41250059a60SEmmanuel Vadot int rv;
413824cfb47SOleksandr Tymoshenko int64_t freq;
4146a05f063SJared McNeill
41550059a60SEmmanuel Vadot /* Required clock */
41650059a60SEmmanuel Vadot rv = clk_get_by_ofw_name(sc->dev, 0, "stmmaceth", &sc->clk_stmmaceth);
41750059a60SEmmanuel Vadot if (rv != 0) {
41850059a60SEmmanuel Vadot device_printf(sc->dev, "Cannot get GMAC main clock\n");
41950059a60SEmmanuel Vadot return (ENXIO);
4206a05f063SJared McNeill }
42150059a60SEmmanuel Vadot if ((rv = clk_enable(sc->clk_stmmaceth)) != 0) {
42250059a60SEmmanuel Vadot device_printf(sc->dev, "could not enable main clock\n");
42350059a60SEmmanuel Vadot return (rv);
4246a05f063SJared McNeill }
4256a05f063SJared McNeill
42650059a60SEmmanuel Vadot /* Optional clock */
42750059a60SEmmanuel Vadot rv = clk_get_by_ofw_name(sc->dev, 0, "pclk", &sc->clk_pclk);
42850059a60SEmmanuel Vadot if (rv != 0)
42950059a60SEmmanuel Vadot return (0);
43050059a60SEmmanuel Vadot if ((rv = clk_enable(sc->clk_pclk)) != 0) {
43150059a60SEmmanuel Vadot device_printf(sc->dev, "could not enable peripheral clock\n");
43250059a60SEmmanuel Vadot return (rv);
4336a05f063SJared McNeill }
43450059a60SEmmanuel Vadot
43550059a60SEmmanuel Vadot if (bootverbose) {
43650059a60SEmmanuel Vadot clk_get_freq(sc->clk_stmmaceth, &freq);
43750059a60SEmmanuel Vadot device_printf(sc->dev, "MAC clock(%s) freq: %jd\n",
43850059a60SEmmanuel Vadot clk_get_name(sc->clk_stmmaceth), (intmax_t)freq);
43950059a60SEmmanuel Vadot }
44050059a60SEmmanuel Vadot
44150059a60SEmmanuel Vadot return (0);
44250059a60SEmmanuel Vadot }
44350059a60SEmmanuel Vadot
44450059a60SEmmanuel Vadot static int
dwc_reset_deassert(struct dwc_softc * sc)44550059a60SEmmanuel Vadot dwc_reset_deassert(struct dwc_softc *sc)
44650059a60SEmmanuel Vadot {
44750059a60SEmmanuel Vadot int rv;
44850059a60SEmmanuel Vadot
44950059a60SEmmanuel Vadot /* Required reset */
45050059a60SEmmanuel Vadot rv = hwreset_get_by_ofw_name(sc->dev, 0, "stmmaceth", &sc->rst_stmmaceth);
45150059a60SEmmanuel Vadot if (rv != 0) {
45250059a60SEmmanuel Vadot device_printf(sc->dev, "Cannot get GMAC reset\n");
45350059a60SEmmanuel Vadot return (ENXIO);
45450059a60SEmmanuel Vadot }
45550059a60SEmmanuel Vadot rv = hwreset_deassert(sc->rst_stmmaceth);
45650059a60SEmmanuel Vadot if (rv != 0) {
45750059a60SEmmanuel Vadot device_printf(sc->dev, "could not de-assert GMAC reset\n");
45850059a60SEmmanuel Vadot return (rv);
45950059a60SEmmanuel Vadot }
46050059a60SEmmanuel Vadot
46150059a60SEmmanuel Vadot /* Optional reset */
46250059a60SEmmanuel Vadot rv = hwreset_get_by_ofw_name(sc->dev, 0, "ahb", &sc->rst_ahb);
46350059a60SEmmanuel Vadot if (rv != 0)
46450059a60SEmmanuel Vadot return (0);
46550059a60SEmmanuel Vadot rv = hwreset_deassert(sc->rst_ahb);
46650059a60SEmmanuel Vadot if (rv != 0) {
46750059a60SEmmanuel Vadot device_printf(sc->dev, "could not de-assert AHB reset\n");
46850059a60SEmmanuel Vadot return (rv);
4696a05f063SJared McNeill }
4706a05f063SJared McNeill
4716a05f063SJared McNeill return (0);
4726a05f063SJared McNeill }
4736a05f063SJared McNeill
47427f03f16SEmmanuel Vadot /*
47527f03f16SEmmanuel Vadot * Probe/Attach functions
47627f03f16SEmmanuel Vadot */
47727f03f16SEmmanuel Vadot
4785d43fd68SRuslan Bukin static int
dwc_probe(device_t dev)4795d43fd68SRuslan Bukin dwc_probe(device_t dev)
4805d43fd68SRuslan Bukin {
4815d43fd68SRuslan Bukin
4825d43fd68SRuslan Bukin if (!ofw_bus_status_okay(dev))
4835d43fd68SRuslan Bukin return (ENXIO);
4845d43fd68SRuslan Bukin
4855d43fd68SRuslan Bukin if (!ofw_bus_is_compatible(dev, "snps,dwmac"))
4865d43fd68SRuslan Bukin return (ENXIO);
4875d43fd68SRuslan Bukin
4885d43fd68SRuslan Bukin device_set_desc(dev, "Gigabit Ethernet Controller");
4895d43fd68SRuslan Bukin return (BUS_PROBE_DEFAULT);
4905d43fd68SRuslan Bukin }
4915d43fd68SRuslan Bukin
4925d43fd68SRuslan Bukin static int
dwc_attach(device_t dev)4935d43fd68SRuslan Bukin dwc_attach(device_t dev)
4945d43fd68SRuslan Bukin {
4955d43fd68SRuslan Bukin uint8_t macaddr[ETHER_ADDR_LEN];
4965d43fd68SRuslan Bukin struct dwc_softc *sc;
497ca018790SMitchell Horne if_t ifp;
498363b7c39SEmmanuel Vadot int error;
4995d88a52bSEmmanuel Vadot uint32_t pbl;
5005d43fd68SRuslan Bukin
5015d43fd68SRuslan Bukin sc = device_get_softc(dev);
5025d43fd68SRuslan Bukin sc->dev = dev;
5035d43fd68SRuslan Bukin sc->rx_idx = 0;
504e5232621SOleksandr Tymoshenko sc->tx_desccount = TX_DESC_COUNT;
505e5232621SOleksandr Tymoshenko sc->tx_mapcount = 0;
5065df53927SLuiz Otavio O Souza
507f114aaddSEmmanuel Vadot sc->node = ofw_bus_get_node(dev);
508801fb66aSEmmanuel Vadot sc->phy_mode = mii_fdt_get_contype(sc->node);
509801fb66aSEmmanuel Vadot switch (sc->phy_mode) {
510f77d8d10SEmmanuel Vadot case MII_CONTYPE_RGMII:
511f77d8d10SEmmanuel Vadot case MII_CONTYPE_RGMII_ID:
512f77d8d10SEmmanuel Vadot case MII_CONTYPE_RGMII_RXID:
513f77d8d10SEmmanuel Vadot case MII_CONTYPE_RGMII_TXID:
514f77d8d10SEmmanuel Vadot case MII_CONTYPE_RMII:
515da6252a6SEmmanuel Vadot case MII_CONTYPE_MII:
516da6252a6SEmmanuel Vadot break;
517f77d8d10SEmmanuel Vadot default:
518f77d8d10SEmmanuel Vadot device_printf(dev, "Unsupported MII type\n");
519f77d8d10SEmmanuel Vadot return (ENXIO);
520824cfb47SOleksandr Tymoshenko }
521824cfb47SOleksandr Tymoshenko
522f114aaddSEmmanuel Vadot if (OF_getencprop(sc->node, "snps,pbl", &pbl, sizeof(uint32_t)) <= 0)
523cef444d0SEmmanuel Vadot pbl = DMA_DEFAULT_PBL;
5245d88a52bSEmmanuel Vadot if (OF_getencprop(sc->node, "snps,txpbl", &sc->txpbl, sizeof(uint32_t)) <= 0)
5255d88a52bSEmmanuel Vadot sc->txpbl = pbl;
5265d88a52bSEmmanuel Vadot if (OF_getencprop(sc->node, "snps,rxpbl", &sc->rxpbl, sizeof(uint32_t)) <= 0)
5275d88a52bSEmmanuel Vadot sc->rxpbl = pbl;
528f114aaddSEmmanuel Vadot if (OF_hasprop(sc->node, "snps,no-pbl-x8") == 1)
5295d88a52bSEmmanuel Vadot sc->nopblx8 = true;
530f114aaddSEmmanuel Vadot if (OF_hasprop(sc->node, "snps,fixed-burst") == 1)
5315d88a52bSEmmanuel Vadot sc->fixed_burst = true;
532f4bb6ea5SEmmanuel Vadot if (OF_hasprop(sc->node, "snps,mixed-burst") == 1)
5335d88a52bSEmmanuel Vadot sc->mixed_burst = true;
534b69c49d1SEmmanuel Vadot if (OF_hasprop(sc->node, "snps,aal") == 1)
5355d88a52bSEmmanuel Vadot sc->aal = true;
5365e38d9e4SEmmanuel Vadot
53750059a60SEmmanuel Vadot error = clk_set_assigned(dev, ofw_bus_get_node(dev));
53850059a60SEmmanuel Vadot if (error != 0) {
53950059a60SEmmanuel Vadot device_printf(dev, "clk_set_assigned failed\n");
54050059a60SEmmanuel Vadot return (error);
54150059a60SEmmanuel Vadot }
5425d43fd68SRuslan Bukin
54350059a60SEmmanuel Vadot /* Enable main clock */
54450059a60SEmmanuel Vadot if ((error = dwc_clock_init(sc)) != 0)
54550059a60SEmmanuel Vadot return (error);
54650059a60SEmmanuel Vadot /* De-assert main reset */
54750059a60SEmmanuel Vadot if ((error = dwc_reset_deassert(sc)) != 0)
54850059a60SEmmanuel Vadot return (error);
54950059a60SEmmanuel Vadot
55050059a60SEmmanuel Vadot if (IF_DWC_INIT(dev) != 0)
5516a05f063SJared McNeill return (ENXIO);
5526a05f063SJared McNeill
5537854d0f6SEmmanuel Vadot if ((sc->mii_clk = IF_DWC_MII_CLK(dev)) < 0) {
5547854d0f6SEmmanuel Vadot device_printf(dev, "Cannot get mii clock value %d\n", -sc->mii_clk);
5557854d0f6SEmmanuel Vadot return (ENXIO);
5567854d0f6SEmmanuel Vadot }
5577854d0f6SEmmanuel Vadot
5585d43fd68SRuslan Bukin if (bus_alloc_resources(dev, dwc_spec, sc->res)) {
5595d43fd68SRuslan Bukin device_printf(dev, "could not allocate resources\n");
5605d43fd68SRuslan Bukin return (ENXIO);
5615d43fd68SRuslan Bukin }
5625d43fd68SRuslan Bukin
5635d43fd68SRuslan Bukin /* Read MAC before reset */
56462519d5aSEmmanuel Vadot dwc1000_get_hwaddr(sc, macaddr);
5655d43fd68SRuslan Bukin
566d7acb49aSJared McNeill /* Reset the PHY if needed */
567f114aaddSEmmanuel Vadot if (dwc_reset_phy(sc) != 0) {
568d7acb49aSJared McNeill device_printf(dev, "Can't reset the PHY\n");
56930f16ad4SEmmanuel Vadot bus_release_resources(dev, dwc_spec, sc->res);
570d7acb49aSJared McNeill return (ENXIO);
571d7acb49aSJared McNeill }
572d7acb49aSJared McNeill
5735d43fd68SRuslan Bukin /* Reset */
574363b7c39SEmmanuel Vadot if ((error = dma1000_reset(sc)) != 0) {
575363b7c39SEmmanuel Vadot device_printf(sc->dev, "Can't reset DMA controller.\n");
576363b7c39SEmmanuel Vadot bus_release_resources(sc->dev, dwc_spec, sc->res);
577363b7c39SEmmanuel Vadot return (error);
5785d43fd68SRuslan Bukin }
5795d43fd68SRuslan Bukin
580972adf0fSEmmanuel Vadot if (dma1000_init(sc)) {
58130f16ad4SEmmanuel Vadot bus_release_resources(dev, dwc_spec, sc->res);
5825d43fd68SRuslan Bukin return (ENXIO);
58330f16ad4SEmmanuel Vadot }
5845d43fd68SRuslan Bukin
585d8e5258dSRuslan Bukin mtx_init(&sc->mtx, device_get_nameunit(sc->dev),
586d8e5258dSRuslan Bukin MTX_NETWORK_LOCK, MTX_DEF);
587d8e5258dSRuslan Bukin
588d8e5258dSRuslan Bukin callout_init_mtx(&sc->dwc_callout, &sc->mtx, 0);
589d8e5258dSRuslan Bukin
590d8e5258dSRuslan Bukin /* Setup interrupt handler. */
591d8e5258dSRuslan Bukin error = bus_setup_intr(dev, sc->res[1], INTR_TYPE_NET | INTR_MPSAFE,
592d8e5258dSRuslan Bukin NULL, dwc_intr, sc, &sc->intr_cookie);
593d8e5258dSRuslan Bukin if (error != 0) {
594d8e5258dSRuslan Bukin device_printf(dev, "could not setup interrupt handler.\n");
59530f16ad4SEmmanuel Vadot bus_release_resources(dev, dwc_spec, sc->res);
596d8e5258dSRuslan Bukin return (ENXIO);
597d8e5258dSRuslan Bukin }
598d8e5258dSRuslan Bukin
5995d43fd68SRuslan Bukin /* Set up the ethernet interface. */
6005d43fd68SRuslan Bukin sc->ifp = ifp = if_alloc(IFT_ETHER);
6015d43fd68SRuslan Bukin
602ca018790SMitchell Horne if_setsoftc(ifp, sc);
6035d43fd68SRuslan Bukin if_initname(ifp, device_get_name(dev), device_get_unit(dev));
6043bbd11eeSEmmanuel Vadot if_setflags(sc->ifp, IFF_BROADCAST | IFF_SIMPLEX | IFF_MULTICAST);
6053bbd11eeSEmmanuel Vadot if_setstartfn(ifp, dwc_txstart);
6063bbd11eeSEmmanuel Vadot if_setioctlfn(ifp, dwc_ioctl);
6073bbd11eeSEmmanuel Vadot if_setinitfn(ifp, dwc_init);
608e5232621SOleksandr Tymoshenko if_setsendqlen(ifp, TX_MAP_COUNT - 1);
6093bbd11eeSEmmanuel Vadot if_setsendqready(sc->ifp);
61098ea5a7bSEmmanuel Vadot if_sethwassist(sc->ifp, CSUM_IP | CSUM_UDP | CSUM_TCP);
61198ea5a7bSEmmanuel Vadot if_setcapabilities(sc->ifp, IFCAP_VLAN_MTU | IFCAP_HWCSUM);
6123bbd11eeSEmmanuel Vadot if_setcapenable(sc->ifp, if_getcapabilities(sc->ifp));
6135d43fd68SRuslan Bukin
6145d43fd68SRuslan Bukin /* Attach the mii driver. */
6155d43fd68SRuslan Bukin error = mii_attach(dev, &sc->miibus, ifp, dwc_media_change,
6165d43fd68SRuslan Bukin dwc_media_status, BMSR_DEFCAPMASK, MII_PHY_ANY,
6175d43fd68SRuslan Bukin MII_OFFSET_ANY, 0);
6185d43fd68SRuslan Bukin
6195d43fd68SRuslan Bukin if (error != 0) {
6205d43fd68SRuslan Bukin device_printf(dev, "PHY attach failed\n");
62130f16ad4SEmmanuel Vadot bus_teardown_intr(dev, sc->res[1], sc->intr_cookie);
62230f16ad4SEmmanuel Vadot bus_release_resources(dev, dwc_spec, sc->res);
6235d43fd68SRuslan Bukin return (ENXIO);
6245d43fd68SRuslan Bukin }
6255d43fd68SRuslan Bukin sc->mii_softc = device_get_softc(sc->miibus);
6265d43fd68SRuslan Bukin
6275d43fd68SRuslan Bukin /* All ready to run, attach the ethernet interface. */
6285d43fd68SRuslan Bukin ether_ifattach(ifp, macaddr);
6295d43fd68SRuslan Bukin sc->is_attached = true;
6305d43fd68SRuslan Bukin
6315d43fd68SRuslan Bukin return (0);
6325d43fd68SRuslan Bukin }
6335d43fd68SRuslan Bukin
63427b39e58SMitchell Horne static int
dwc_detach(device_t dev)63527b39e58SMitchell Horne dwc_detach(device_t dev)
63627b39e58SMitchell Horne {
63727b39e58SMitchell Horne struct dwc_softc *sc;
63827b39e58SMitchell Horne
63927b39e58SMitchell Horne sc = device_get_softc(dev);
64027b39e58SMitchell Horne
64127b39e58SMitchell Horne /*
64227b39e58SMitchell Horne * Disable and tear down interrupts before anything else, so we don't
64327b39e58SMitchell Horne * race with the handler.
64427b39e58SMitchell Horne */
64529776aa4SEmmanuel Vadot dwc1000_intr_disable(sc);
64627b39e58SMitchell Horne if (sc->intr_cookie != NULL) {
64727b39e58SMitchell Horne bus_teardown_intr(dev, sc->res[1], sc->intr_cookie);
64827b39e58SMitchell Horne }
64927b39e58SMitchell Horne
65027b39e58SMitchell Horne if (sc->is_attached) {
65127b39e58SMitchell Horne DWC_LOCK(sc);
65227b39e58SMitchell Horne sc->is_detaching = true;
65327b39e58SMitchell Horne dwc_stop_locked(sc);
65427b39e58SMitchell Horne DWC_UNLOCK(sc);
65527b39e58SMitchell Horne callout_drain(&sc->dwc_callout);
65627b39e58SMitchell Horne ether_ifdetach(sc->ifp);
65727b39e58SMitchell Horne }
65827b39e58SMitchell Horne
65927b39e58SMitchell Horne bus_generic_detach(dev);
66027b39e58SMitchell Horne
66127b39e58SMitchell Horne /* Free DMA descriptors */
662972adf0fSEmmanuel Vadot dma1000_free(sc);
66327b39e58SMitchell Horne
66427b39e58SMitchell Horne if (sc->ifp != NULL) {
66527b39e58SMitchell Horne if_free(sc->ifp);
66627b39e58SMitchell Horne sc->ifp = NULL;
66727b39e58SMitchell Horne }
66827b39e58SMitchell Horne
66927b39e58SMitchell Horne bus_release_resources(dev, dwc_spec, sc->res);
67027b39e58SMitchell Horne
67127b39e58SMitchell Horne mtx_destroy(&sc->mtx);
67227b39e58SMitchell Horne return (0);
67327b39e58SMitchell Horne }
67427b39e58SMitchell Horne
6755d43fd68SRuslan Bukin static device_method_t dwc_methods[] = {
6765d43fd68SRuslan Bukin DEVMETHOD(device_probe, dwc_probe),
6775d43fd68SRuslan Bukin DEVMETHOD(device_attach, dwc_attach),
67827b39e58SMitchell Horne DEVMETHOD(device_detach, dwc_detach),
6795d43fd68SRuslan Bukin
6805d43fd68SRuslan Bukin /* MII Interface */
68162519d5aSEmmanuel Vadot DEVMETHOD(miibus_readreg, dwc1000_miibus_read_reg),
68262519d5aSEmmanuel Vadot DEVMETHOD(miibus_writereg, dwc1000_miibus_write_reg),
68362519d5aSEmmanuel Vadot DEVMETHOD(miibus_statchg, dwc1000_miibus_statchg),
6845d43fd68SRuslan Bukin
6855d43fd68SRuslan Bukin { 0, 0 }
6865d43fd68SRuslan Bukin };
6875d43fd68SRuslan Bukin
6885df53927SLuiz Otavio O Souza driver_t dwc_driver = {
6895d43fd68SRuslan Bukin "dwc",
6905d43fd68SRuslan Bukin dwc_methods,
6915d43fd68SRuslan Bukin sizeof(struct dwc_softc),
6925d43fd68SRuslan Bukin };
6935d43fd68SRuslan Bukin
694e55d0536SJohn Baldwin DRIVER_MODULE(dwc, simplebus, dwc_driver, 0, 0);
6953e38757dSJohn Baldwin DRIVER_MODULE(miibus, dwc, miibus_driver, 0, 0);
6965d43fd68SRuslan Bukin
6975d43fd68SRuslan Bukin MODULE_DEPEND(dwc, ether, 1, 1, 1);
6985d43fd68SRuslan Bukin MODULE_DEPEND(dwc, miibus, 1, 1, 1);
699