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/cdefs.h> 395d43fd68SRuslan Bukin #include <sys/param.h> 405d43fd68SRuslan Bukin #include <sys/systm.h> 415d43fd68SRuslan Bukin #include <sys/bus.h> 42d7acb49aSJared McNeill #include <sys/gpio.h> 435d43fd68SRuslan Bukin #include <sys/kernel.h> 445d43fd68SRuslan Bukin #include <sys/lock.h> 45da9a326bSLuiz Otavio O Souza #include <sys/malloc.h> 465d43fd68SRuslan Bukin #include <sys/mbuf.h> 47da9a326bSLuiz Otavio O Souza #include <sys/module.h> 485d43fd68SRuslan Bukin #include <sys/mutex.h> 49da9a326bSLuiz Otavio O Souza #include <sys/rman.h> 505d43fd68SRuslan Bukin #include <sys/socket.h> 515d43fd68SRuslan Bukin #include <sys/sockio.h> 525d43fd68SRuslan Bukin 535d43fd68SRuslan Bukin #include <net/bpf.h> 545d43fd68SRuslan Bukin #include <net/if.h> 555d43fd68SRuslan Bukin #include <net/ethernet.h> 565d43fd68SRuslan Bukin #include <net/if_dl.h> 575d43fd68SRuslan Bukin #include <net/if_media.h> 585d43fd68SRuslan Bukin #include <net/if_types.h> 595d43fd68SRuslan Bukin #include <net/if_var.h> 605d43fd68SRuslan Bukin 615d43fd68SRuslan Bukin #include <machine/bus.h> 625d43fd68SRuslan Bukin 6350059a60SEmmanuel Vadot #include <dev/extres/clk/clk.h> 6450059a60SEmmanuel Vadot #include <dev/extres/hwreset/hwreset.h> 6550059a60SEmmanuel Vadot 665d43fd68SRuslan Bukin #include <dev/mii/mii.h> 675d43fd68SRuslan Bukin #include <dev/mii/miivar.h> 68da9a326bSLuiz Otavio O Souza #include <dev/ofw/ofw_bus.h> 69da9a326bSLuiz Otavio O Souza #include <dev/ofw/ofw_bus_subr.h> 70f77d8d10SEmmanuel Vadot #include <dev/mii/mii_fdt.h> 71da9a326bSLuiz Otavio O Souza 72c36125f6SEmmanuel Vadot #include <dev/dwc/if_dwcvar.h> 73972adf0fSEmmanuel Vadot #include <dev/dwc/dwc1000_reg.h> 7462519d5aSEmmanuel Vadot #include <dev/dwc/dwc1000_core.h> 75972adf0fSEmmanuel Vadot #include <dev/dwc/dwc1000_dma.h> 76c36125f6SEmmanuel Vadot 775df53927SLuiz Otavio O Souza #include "if_dwc_if.h" 78d7acb49aSJared McNeill #include "gpio_if.h" 795d43fd68SRuslan Bukin #include "miibus_if.h" 805d43fd68SRuslan Bukin 81d8e5258dSRuslan Bukin #define MAC_RESET_TIMEOUT 100 825d43fd68SRuslan Bukin 835d43fd68SRuslan Bukin static struct resource_spec dwc_spec[] = { 845d43fd68SRuslan Bukin { SYS_RES_MEMORY, 0, RF_ACTIVE }, 855d43fd68SRuslan Bukin { SYS_RES_IRQ, 0, RF_ACTIVE }, 865d43fd68SRuslan Bukin { -1, 0 } 875d43fd68SRuslan Bukin }; 885d43fd68SRuslan Bukin 895d43fd68SRuslan Bukin static void dwc_stop_locked(struct dwc_softc *sc); 905d43fd68SRuslan Bukin 912a35d391SEmmanuel Vadot static void dwc_tick(void *arg); 922a35d391SEmmanuel Vadot 932a35d391SEmmanuel Vadot /* 942a35d391SEmmanuel Vadot * Media functions 952a35d391SEmmanuel Vadot */ 962a35d391SEmmanuel Vadot 972a35d391SEmmanuel Vadot static void 98ca018790SMitchell Horne dwc_media_status(if_t ifp, struct ifmediareq *ifmr) 992a35d391SEmmanuel Vadot { 1002a35d391SEmmanuel Vadot struct dwc_softc *sc; 1012a35d391SEmmanuel Vadot struct mii_data *mii; 1022a35d391SEmmanuel Vadot 103ca018790SMitchell Horne sc = if_getsoftc(ifp); 1042a35d391SEmmanuel Vadot mii = sc->mii_softc; 1052a35d391SEmmanuel Vadot DWC_LOCK(sc); 1062a35d391SEmmanuel Vadot mii_pollstat(mii); 1072a35d391SEmmanuel Vadot ifmr->ifm_active = mii->mii_media_active; 1082a35d391SEmmanuel Vadot ifmr->ifm_status = mii->mii_media_status; 1092a35d391SEmmanuel Vadot DWC_UNLOCK(sc); 1102a35d391SEmmanuel Vadot } 1112a35d391SEmmanuel Vadot 1122a35d391SEmmanuel Vadot static int 1132a35d391SEmmanuel Vadot dwc_media_change_locked(struct dwc_softc *sc) 1142a35d391SEmmanuel Vadot { 1152a35d391SEmmanuel Vadot 1162a35d391SEmmanuel Vadot return (mii_mediachg(sc->mii_softc)); 1172a35d391SEmmanuel Vadot } 1182a35d391SEmmanuel Vadot 1192a35d391SEmmanuel Vadot static int 120ca018790SMitchell Horne dwc_media_change(if_t ifp) 1212a35d391SEmmanuel Vadot { 1222a35d391SEmmanuel Vadot struct dwc_softc *sc; 1232a35d391SEmmanuel Vadot int error; 1242a35d391SEmmanuel Vadot 125ca018790SMitchell Horne sc = if_getsoftc(ifp); 1262a35d391SEmmanuel Vadot 1272a35d391SEmmanuel Vadot DWC_LOCK(sc); 1282a35d391SEmmanuel Vadot error = dwc_media_change_locked(sc); 1292a35d391SEmmanuel Vadot DWC_UNLOCK(sc); 1302a35d391SEmmanuel Vadot return (error); 1312a35d391SEmmanuel Vadot } 1322a35d391SEmmanuel Vadot 1332a35d391SEmmanuel Vadot /* 1342a35d391SEmmanuel Vadot * if_ functions 1352a35d391SEmmanuel Vadot */ 1362a35d391SEmmanuel Vadot 137f88e0af6SEmmanuel Vadot static void 1382a35d391SEmmanuel Vadot dwc_txstart_locked(struct dwc_softc *sc) 1395d43fd68SRuslan Bukin { 140ca018790SMitchell Horne if_t ifp; 1412a35d391SEmmanuel Vadot 1422a35d391SEmmanuel Vadot DWC_ASSERT_LOCKED(sc); 1432a35d391SEmmanuel Vadot 1442a35d391SEmmanuel Vadot if (!sc->link_is_up) 1452a35d391SEmmanuel Vadot return; 1462a35d391SEmmanuel Vadot 1472a35d391SEmmanuel Vadot ifp = sc->ifp; 1482a35d391SEmmanuel Vadot 1493bbd11eeSEmmanuel Vadot if ((if_getdrvflags(ifp) & (IFF_DRV_RUNNING|IFF_DRV_OACTIVE)) != 1503bbd11eeSEmmanuel Vadot IFF_DRV_RUNNING) 1512a35d391SEmmanuel Vadot return; 152*afa0f66eSEmmanuel Vadot dma1000_txstart(sc); 1532a35d391SEmmanuel Vadot } 1542a35d391SEmmanuel Vadot 1552a35d391SEmmanuel Vadot static void 156ca018790SMitchell Horne dwc_txstart(if_t ifp) 1572a35d391SEmmanuel Vadot { 158ca018790SMitchell Horne struct dwc_softc *sc = if_getsoftc(ifp); 1592a35d391SEmmanuel Vadot 1602a35d391SEmmanuel Vadot DWC_LOCK(sc); 1612a35d391SEmmanuel Vadot dwc_txstart_locked(sc); 1622a35d391SEmmanuel Vadot DWC_UNLOCK(sc); 1632a35d391SEmmanuel Vadot } 1642a35d391SEmmanuel Vadot 1652a35d391SEmmanuel Vadot static void 1662a35d391SEmmanuel Vadot dwc_init_locked(struct dwc_softc *sc) 1672a35d391SEmmanuel Vadot { 168ca018790SMitchell Horne if_t ifp = sc->ifp; 1692a35d391SEmmanuel Vadot 1702a35d391SEmmanuel Vadot DWC_ASSERT_LOCKED(sc); 1712a35d391SEmmanuel Vadot 1723bbd11eeSEmmanuel Vadot if (if_getdrvflags(ifp) & IFF_DRV_RUNNING) 1732a35d391SEmmanuel Vadot return; 1742a35d391SEmmanuel Vadot 1756501fcdcSJiahao LI /* 17662519d5aSEmmanuel Vadot * Call mii_mediachg() which will call back into dwc1000_miibus_statchg() 1776501fcdcSJiahao LI * to set up the remaining config registers based on current media. 1786501fcdcSJiahao LI */ 1796501fcdcSJiahao LI mii_mediachg(sc->mii_softc); 1806501fcdcSJiahao LI 18162519d5aSEmmanuel Vadot dwc1000_setup_rxfilter(sc); 18262519d5aSEmmanuel Vadot dwc1000_core_setup(sc); 18362519d5aSEmmanuel Vadot dwc1000_enable_mac(sc, true); 18462519d5aSEmmanuel Vadot dwc1000_enable_csum_offload(sc); 185972adf0fSEmmanuel Vadot dma1000_start(sc); 1862a35d391SEmmanuel Vadot 1872a35d391SEmmanuel Vadot if_setdrvflagbits(ifp, IFF_DRV_RUNNING, IFF_DRV_OACTIVE); 1885d43fd68SRuslan Bukin 1892a35d391SEmmanuel Vadot callout_reset(&sc->dwc_callout, hz, dwc_tick, sc); 1902a35d391SEmmanuel Vadot } 1912a35d391SEmmanuel Vadot 1922a35d391SEmmanuel Vadot static void 1932a35d391SEmmanuel Vadot dwc_init(void *if_softc) 1942a35d391SEmmanuel Vadot { 1952a35d391SEmmanuel Vadot struct dwc_softc *sc = if_softc; 1962a35d391SEmmanuel Vadot 1972a35d391SEmmanuel Vadot DWC_LOCK(sc); 1982a35d391SEmmanuel Vadot dwc_init_locked(sc); 1992a35d391SEmmanuel Vadot DWC_UNLOCK(sc); 2002a35d391SEmmanuel Vadot } 2012a35d391SEmmanuel Vadot 2022a35d391SEmmanuel Vadot static void 2032a35d391SEmmanuel Vadot dwc_stop_locked(struct dwc_softc *sc) 2042a35d391SEmmanuel Vadot { 205ca018790SMitchell Horne if_t ifp; 2062a35d391SEmmanuel Vadot 2072a35d391SEmmanuel Vadot DWC_ASSERT_LOCKED(sc); 2082a35d391SEmmanuel Vadot 2092a35d391SEmmanuel Vadot ifp = sc->ifp; 2103bbd11eeSEmmanuel Vadot if_setdrvflagbits(ifp, 0, IFF_DRV_RUNNING | IFF_DRV_OACTIVE); 2112a35d391SEmmanuel Vadot sc->tx_watchdog_count = 0; 2122a35d391SEmmanuel Vadot sc->stats_harvest_count = 0; 2132a35d391SEmmanuel Vadot 2142a35d391SEmmanuel Vadot callout_stop(&sc->dwc_callout); 2152a35d391SEmmanuel Vadot 216972adf0fSEmmanuel Vadot dma1000_stop(sc); 21762519d5aSEmmanuel Vadot dwc1000_enable_mac(sc, false); 2182a35d391SEmmanuel Vadot } 2192a35d391SEmmanuel Vadot 2202a35d391SEmmanuel Vadot static int 221ca018790SMitchell Horne dwc_ioctl(if_t ifp, u_long cmd, caddr_t data) 2222a35d391SEmmanuel Vadot { 2232a35d391SEmmanuel Vadot struct dwc_softc *sc; 2242a35d391SEmmanuel Vadot struct mii_data *mii; 2252a35d391SEmmanuel Vadot struct ifreq *ifr; 2263bbd11eeSEmmanuel Vadot int flags, mask, error; 2272a35d391SEmmanuel Vadot 228ca018790SMitchell Horne sc = if_getsoftc(ifp); 2292a35d391SEmmanuel Vadot ifr = (struct ifreq *)data; 2302a35d391SEmmanuel Vadot 2312a35d391SEmmanuel Vadot error = 0; 2322a35d391SEmmanuel Vadot switch (cmd) { 2332a35d391SEmmanuel Vadot case SIOCSIFFLAGS: 2342a35d391SEmmanuel Vadot DWC_LOCK(sc); 2353bbd11eeSEmmanuel Vadot if (if_getflags(ifp) & IFF_UP) { 2363bbd11eeSEmmanuel Vadot if (if_getdrvflags(ifp) & IFF_DRV_RUNNING) { 2373bbd11eeSEmmanuel Vadot flags = if_getflags(ifp) ^ sc->if_flags; 2383bbd11eeSEmmanuel Vadot if ((flags & (IFF_PROMISC|IFF_ALLMULTI)) != 0) 23962519d5aSEmmanuel Vadot dwc1000_setup_rxfilter(sc); 2405d43fd68SRuslan Bukin } else { 2412a35d391SEmmanuel Vadot if (!sc->is_detaching) 2422a35d391SEmmanuel Vadot dwc_init_locked(sc); 2432a35d391SEmmanuel Vadot } 2442a35d391SEmmanuel Vadot } else { 2453bbd11eeSEmmanuel Vadot if (if_getdrvflags(ifp) & IFF_DRV_RUNNING) 2462a35d391SEmmanuel Vadot dwc_stop_locked(sc); 2472a35d391SEmmanuel Vadot } 2483bbd11eeSEmmanuel Vadot sc->if_flags = if_getflags(ifp); 2492a35d391SEmmanuel Vadot DWC_UNLOCK(sc); 2502a35d391SEmmanuel Vadot break; 2512a35d391SEmmanuel Vadot case SIOCADDMULTI: 2522a35d391SEmmanuel Vadot case SIOCDELMULTI: 2533bbd11eeSEmmanuel Vadot if (if_getdrvflags(ifp) & IFF_DRV_RUNNING) { 2542a35d391SEmmanuel Vadot DWC_LOCK(sc); 25562519d5aSEmmanuel Vadot dwc1000_setup_rxfilter(sc); 2562a35d391SEmmanuel Vadot DWC_UNLOCK(sc); 2572a35d391SEmmanuel Vadot } 2582a35d391SEmmanuel Vadot break; 2592a35d391SEmmanuel Vadot case SIOCSIFMEDIA: 2602a35d391SEmmanuel Vadot case SIOCGIFMEDIA: 2612a35d391SEmmanuel Vadot mii = sc->mii_softc; 2622a35d391SEmmanuel Vadot error = ifmedia_ioctl(ifp, ifr, &mii->mii_media, cmd); 2632a35d391SEmmanuel Vadot break; 2642a35d391SEmmanuel Vadot case SIOCSIFCAP: 2653bbd11eeSEmmanuel Vadot mask = ifr->ifr_reqcap ^ if_getcapenable(ifp); 2662a35d391SEmmanuel Vadot if (mask & IFCAP_VLAN_MTU) { 2672a35d391SEmmanuel Vadot /* No work to do except acknowledge the change took */ 2683bbd11eeSEmmanuel Vadot if_togglecapenable(ifp, IFCAP_VLAN_MTU); 2692a35d391SEmmanuel Vadot } 27098ea5a7bSEmmanuel Vadot if (mask & IFCAP_RXCSUM) 27198ea5a7bSEmmanuel Vadot if_togglecapenable(ifp, IFCAP_RXCSUM); 27298ea5a7bSEmmanuel Vadot if (mask & IFCAP_TXCSUM) 27398ea5a7bSEmmanuel Vadot if_togglecapenable(ifp, IFCAP_TXCSUM); 27498ea5a7bSEmmanuel Vadot if ((if_getcapenable(ifp) & IFCAP_TXCSUM) != 0) 27598ea5a7bSEmmanuel Vadot if_sethwassistbits(ifp, CSUM_IP | CSUM_UDP | CSUM_TCP, 0); 27698ea5a7bSEmmanuel Vadot else 27798ea5a7bSEmmanuel Vadot if_sethwassistbits(ifp, 0, CSUM_IP | CSUM_UDP | CSUM_TCP); 27835c9edabSJiahao Li 27935c9edabSJiahao Li if (if_getdrvflags(ifp) & IFF_DRV_RUNNING) { 28035c9edabSJiahao Li DWC_LOCK(sc); 28162519d5aSEmmanuel Vadot dwc1000_enable_csum_offload(sc); 28235c9edabSJiahao Li DWC_UNLOCK(sc); 28335c9edabSJiahao Li } 2842a35d391SEmmanuel Vadot break; 2852a35d391SEmmanuel Vadot 2862a35d391SEmmanuel Vadot default: 2872a35d391SEmmanuel Vadot error = ether_ioctl(ifp, cmd, data); 2882a35d391SEmmanuel Vadot break; 2892a35d391SEmmanuel Vadot } 2902a35d391SEmmanuel Vadot 2912a35d391SEmmanuel Vadot return (error); 2922a35d391SEmmanuel Vadot } 2932a35d391SEmmanuel Vadot 2942a35d391SEmmanuel Vadot /* 2952a35d391SEmmanuel Vadot * Interrupts functions 2962a35d391SEmmanuel Vadot */ 2972a35d391SEmmanuel Vadot 2982a35d391SEmmanuel Vadot 2992a35d391SEmmanuel Vadot static void 3002a35d391SEmmanuel Vadot dwc_intr(void *arg) 3012a35d391SEmmanuel Vadot { 3022a35d391SEmmanuel Vadot struct dwc_softc *sc; 3032a35d391SEmmanuel Vadot uint32_t reg; 3042a35d391SEmmanuel Vadot 3052a35d391SEmmanuel Vadot sc = arg; 3062a35d391SEmmanuel Vadot 3072a35d391SEmmanuel Vadot DWC_LOCK(sc); 3082a35d391SEmmanuel Vadot 3092a35d391SEmmanuel Vadot reg = READ4(sc, INTERRUPT_STATUS); 3102a35d391SEmmanuel Vadot if (reg) 3112a35d391SEmmanuel Vadot READ4(sc, SGMII_RGMII_SMII_CTRL_STATUS); 3122a35d391SEmmanuel Vadot 3132a35d391SEmmanuel Vadot reg = READ4(sc, DMA_STATUS); 3142a35d391SEmmanuel Vadot if (reg & DMA_STATUS_NIS) { 3152a35d391SEmmanuel Vadot if (reg & DMA_STATUS_RI) 316972adf0fSEmmanuel Vadot dma1000_rxfinish_locked(sc); 3172a35d391SEmmanuel Vadot 3182a35d391SEmmanuel Vadot if (reg & DMA_STATUS_TI) { 319972adf0fSEmmanuel Vadot dma1000_txfinish_locked(sc); 3202a35d391SEmmanuel Vadot dwc_txstart_locked(sc); 3212a35d391SEmmanuel Vadot } 3222a35d391SEmmanuel Vadot } 3232a35d391SEmmanuel Vadot 3242a35d391SEmmanuel Vadot if (reg & DMA_STATUS_AIS) { 3252a35d391SEmmanuel Vadot if (reg & DMA_STATUS_FBI) { 3262a35d391SEmmanuel Vadot /* Fatal bus error */ 3272a35d391SEmmanuel Vadot device_printf(sc->dev, 3282a35d391SEmmanuel Vadot "Ethernet DMA error, restarting controller.\n"); 3292a35d391SEmmanuel Vadot dwc_stop_locked(sc); 3302a35d391SEmmanuel Vadot dwc_init_locked(sc); 3312a35d391SEmmanuel Vadot } 3322a35d391SEmmanuel Vadot } 3332a35d391SEmmanuel Vadot 3342a35d391SEmmanuel Vadot WRITE4(sc, DMA_STATUS, reg & DMA_STATUS_INTR_MASK); 3352a35d391SEmmanuel Vadot DWC_UNLOCK(sc); 3362a35d391SEmmanuel Vadot } 3372a35d391SEmmanuel Vadot 3382a35d391SEmmanuel Vadot static void 3392a35d391SEmmanuel Vadot dwc_tick(void *arg) 3402a35d391SEmmanuel Vadot { 3412a35d391SEmmanuel Vadot struct dwc_softc *sc; 342ca018790SMitchell Horne if_t ifp; 3432a35d391SEmmanuel Vadot int link_was_up; 3442a35d391SEmmanuel Vadot 3452a35d391SEmmanuel Vadot sc = arg; 3462a35d391SEmmanuel Vadot 3472a35d391SEmmanuel Vadot DWC_ASSERT_LOCKED(sc); 3482a35d391SEmmanuel Vadot 3492a35d391SEmmanuel Vadot ifp = sc->ifp; 3502a35d391SEmmanuel Vadot 3513bbd11eeSEmmanuel Vadot if ((if_getdrvflags(ifp) & IFF_DRV_RUNNING) == 0) 3522a35d391SEmmanuel Vadot return; 3532a35d391SEmmanuel Vadot 3542a35d391SEmmanuel Vadot /* 3552a35d391SEmmanuel Vadot * Typical tx watchdog. If this fires it indicates that we enqueued 3562a35d391SEmmanuel Vadot * packets for output and never got a txdone interrupt for them. Maybe 3572a35d391SEmmanuel Vadot * it's a missed interrupt somehow, just pretend we got one. 3582a35d391SEmmanuel Vadot */ 3592a35d391SEmmanuel Vadot if (sc->tx_watchdog_count > 0) { 3602a35d391SEmmanuel Vadot if (--sc->tx_watchdog_count == 0) { 361972adf0fSEmmanuel Vadot dma1000_txfinish_locked(sc); 3622a35d391SEmmanuel Vadot } 3632a35d391SEmmanuel Vadot } 3642a35d391SEmmanuel Vadot 3652a35d391SEmmanuel Vadot /* Gather stats from hardware counters. */ 36662519d5aSEmmanuel Vadot dwc1000_harvest_stats(sc); 3672a35d391SEmmanuel Vadot 3682a35d391SEmmanuel Vadot /* Check the media status. */ 3692a35d391SEmmanuel Vadot link_was_up = sc->link_is_up; 3702a35d391SEmmanuel Vadot mii_tick(sc->mii_softc); 3712a35d391SEmmanuel Vadot if (sc->link_is_up && !link_was_up) 3722a35d391SEmmanuel Vadot dwc_txstart_locked(sc); 3732a35d391SEmmanuel Vadot 3742a35d391SEmmanuel Vadot /* Schedule another check one second from now. */ 3752a35d391SEmmanuel Vadot callout_reset(&sc->dwc_callout, hz, dwc_tick, sc); 3762a35d391SEmmanuel Vadot } 3772a35d391SEmmanuel Vadot 378d7acb49aSJared McNeill static int 379f114aaddSEmmanuel Vadot dwc_reset_phy(struct dwc_softc *sc) 380d7acb49aSJared McNeill { 381d7acb49aSJared McNeill pcell_t gpio_prop[4]; 382d7acb49aSJared McNeill pcell_t delay_prop[3]; 383f114aaddSEmmanuel Vadot phandle_t gpio_node; 384d7acb49aSJared McNeill device_t gpio; 385d7acb49aSJared McNeill uint32_t pin, flags; 386d7acb49aSJared McNeill uint32_t pin_value; 387d7acb49aSJared McNeill 388f114aaddSEmmanuel Vadot /* 389f114aaddSEmmanuel Vadot * All those properties are deprecated but still used in some DTS. 390f114aaddSEmmanuel Vadot * The new way to deal with this is to use the generic bindings 391f114aaddSEmmanuel Vadot * present in the ethernet-phy node. 392f114aaddSEmmanuel Vadot */ 393f114aaddSEmmanuel Vadot if (OF_getencprop(sc->node, "snps,reset-gpio", 394d7acb49aSJared McNeill gpio_prop, sizeof(gpio_prop)) <= 0) 395d7acb49aSJared McNeill return (0); 396d7acb49aSJared McNeill 397f114aaddSEmmanuel Vadot if (OF_getencprop(sc->node, "snps,reset-delays-us", 398d7acb49aSJared McNeill delay_prop, sizeof(delay_prop)) <= 0) { 399f114aaddSEmmanuel Vadot device_printf(sc->dev, 400d7acb49aSJared McNeill "Wrong property for snps,reset-delays-us"); 401d7acb49aSJared McNeill return (ENXIO); 402d7acb49aSJared McNeill } 403d7acb49aSJared McNeill 404d7acb49aSJared McNeill gpio_node = OF_node_from_xref(gpio_prop[0]); 405d7acb49aSJared McNeill if ((gpio = OF_device_from_xref(gpio_prop[0])) == NULL) { 406f114aaddSEmmanuel Vadot device_printf(sc->dev, 407d7acb49aSJared McNeill "Can't find gpio controller for phy reset\n"); 408d7acb49aSJared McNeill return (ENXIO); 409d7acb49aSJared McNeill } 410d7acb49aSJared McNeill 411f114aaddSEmmanuel Vadot if (GPIO_MAP_GPIOS(gpio, sc->node, gpio_node, 41273a1170aSPedro F. Giffuni nitems(gpio_prop) - 1, 413d7acb49aSJared McNeill gpio_prop + 1, &pin, &flags) != 0) { 414f114aaddSEmmanuel Vadot device_printf(sc->dev, "Can't map gpio for phy reset\n"); 415d7acb49aSJared McNeill return (ENXIO); 416d7acb49aSJared McNeill } 417d7acb49aSJared McNeill 418d7acb49aSJared McNeill pin_value = GPIO_PIN_LOW; 419f114aaddSEmmanuel Vadot if (OF_hasprop(sc->node, "snps,reset-active-low")) 420d7acb49aSJared McNeill pin_value = GPIO_PIN_HIGH; 421d7acb49aSJared McNeill 422d7acb49aSJared McNeill GPIO_PIN_SETFLAGS(gpio, pin, GPIO_PIN_OUTPUT); 423d7acb49aSJared McNeill GPIO_PIN_SET(gpio, pin, pin_value); 424c069412eSEmmanuel Vadot DELAY(delay_prop[0] * 5); 425d7acb49aSJared McNeill GPIO_PIN_SET(gpio, pin, !pin_value); 426c069412eSEmmanuel Vadot DELAY(delay_prop[1] * 5); 427d7acb49aSJared McNeill GPIO_PIN_SET(gpio, pin, pin_value); 428c069412eSEmmanuel Vadot DELAY(delay_prop[2] * 5); 429d7acb49aSJared McNeill 430d7acb49aSJared McNeill return (0); 431d7acb49aSJared McNeill } 432d7acb49aSJared McNeill 4336a05f063SJared McNeill static int 43450059a60SEmmanuel Vadot dwc_clock_init(struct dwc_softc *sc) 4356a05f063SJared McNeill { 43650059a60SEmmanuel Vadot int rv; 437824cfb47SOleksandr Tymoshenko int64_t freq; 4386a05f063SJared McNeill 43950059a60SEmmanuel Vadot /* Required clock */ 44050059a60SEmmanuel Vadot rv = clk_get_by_ofw_name(sc->dev, 0, "stmmaceth", &sc->clk_stmmaceth); 44150059a60SEmmanuel Vadot if (rv != 0) { 44250059a60SEmmanuel Vadot device_printf(sc->dev, "Cannot get GMAC main clock\n"); 44350059a60SEmmanuel Vadot return (ENXIO); 4446a05f063SJared McNeill } 44550059a60SEmmanuel Vadot if ((rv = clk_enable(sc->clk_stmmaceth)) != 0) { 44650059a60SEmmanuel Vadot device_printf(sc->dev, "could not enable main clock\n"); 44750059a60SEmmanuel Vadot return (rv); 4486a05f063SJared McNeill } 4496a05f063SJared McNeill 45050059a60SEmmanuel Vadot /* Optional clock */ 45150059a60SEmmanuel Vadot rv = clk_get_by_ofw_name(sc->dev, 0, "pclk", &sc->clk_pclk); 45250059a60SEmmanuel Vadot if (rv != 0) 45350059a60SEmmanuel Vadot return (0); 45450059a60SEmmanuel Vadot if ((rv = clk_enable(sc->clk_pclk)) != 0) { 45550059a60SEmmanuel Vadot device_printf(sc->dev, "could not enable peripheral clock\n"); 45650059a60SEmmanuel Vadot return (rv); 4576a05f063SJared McNeill } 45850059a60SEmmanuel Vadot 45950059a60SEmmanuel Vadot if (bootverbose) { 46050059a60SEmmanuel Vadot clk_get_freq(sc->clk_stmmaceth, &freq); 46150059a60SEmmanuel Vadot device_printf(sc->dev, "MAC clock(%s) freq: %jd\n", 46250059a60SEmmanuel Vadot clk_get_name(sc->clk_stmmaceth), (intmax_t)freq); 46350059a60SEmmanuel Vadot } 46450059a60SEmmanuel Vadot 46550059a60SEmmanuel Vadot return (0); 46650059a60SEmmanuel Vadot } 46750059a60SEmmanuel Vadot 46850059a60SEmmanuel Vadot static int 46950059a60SEmmanuel Vadot dwc_reset_deassert(struct dwc_softc *sc) 47050059a60SEmmanuel Vadot { 47150059a60SEmmanuel Vadot int rv; 47250059a60SEmmanuel Vadot 47350059a60SEmmanuel Vadot /* Required reset */ 47450059a60SEmmanuel Vadot rv = hwreset_get_by_ofw_name(sc->dev, 0, "stmmaceth", &sc->rst_stmmaceth); 47550059a60SEmmanuel Vadot if (rv != 0) { 47650059a60SEmmanuel Vadot device_printf(sc->dev, "Cannot get GMAC reset\n"); 47750059a60SEmmanuel Vadot return (ENXIO); 47850059a60SEmmanuel Vadot } 47950059a60SEmmanuel Vadot rv = hwreset_deassert(sc->rst_stmmaceth); 48050059a60SEmmanuel Vadot if (rv != 0) { 48150059a60SEmmanuel Vadot device_printf(sc->dev, "could not de-assert GMAC reset\n"); 48250059a60SEmmanuel Vadot return (rv); 48350059a60SEmmanuel Vadot } 48450059a60SEmmanuel Vadot 48550059a60SEmmanuel Vadot /* Optional reset */ 48650059a60SEmmanuel Vadot rv = hwreset_get_by_ofw_name(sc->dev, 0, "ahb", &sc->rst_ahb); 48750059a60SEmmanuel Vadot if (rv != 0) 48850059a60SEmmanuel Vadot return (0); 48950059a60SEmmanuel Vadot rv = hwreset_deassert(sc->rst_ahb); 49050059a60SEmmanuel Vadot if (rv != 0) { 49150059a60SEmmanuel Vadot device_printf(sc->dev, "could not de-assert AHB reset\n"); 49250059a60SEmmanuel Vadot return (rv); 4936a05f063SJared McNeill } 4946a05f063SJared McNeill 4956a05f063SJared McNeill return (0); 4966a05f063SJared McNeill } 4976a05f063SJared McNeill 49827f03f16SEmmanuel Vadot /* 49927f03f16SEmmanuel Vadot * Probe/Attach functions 50027f03f16SEmmanuel Vadot */ 50127f03f16SEmmanuel Vadot 5025d43fd68SRuslan Bukin static int 5035d43fd68SRuslan Bukin dwc_probe(device_t dev) 5045d43fd68SRuslan Bukin { 5055d43fd68SRuslan Bukin 5065d43fd68SRuslan Bukin if (!ofw_bus_status_okay(dev)) 5075d43fd68SRuslan Bukin return (ENXIO); 5085d43fd68SRuslan Bukin 5095d43fd68SRuslan Bukin if (!ofw_bus_is_compatible(dev, "snps,dwmac")) 5105d43fd68SRuslan Bukin return (ENXIO); 5115d43fd68SRuslan Bukin 5125d43fd68SRuslan Bukin device_set_desc(dev, "Gigabit Ethernet Controller"); 5135d43fd68SRuslan Bukin return (BUS_PROBE_DEFAULT); 5145d43fd68SRuslan Bukin } 5155d43fd68SRuslan Bukin 5165d43fd68SRuslan Bukin static int 5175d43fd68SRuslan Bukin dwc_attach(device_t dev) 5185d43fd68SRuslan Bukin { 5195d43fd68SRuslan Bukin uint8_t macaddr[ETHER_ADDR_LEN]; 5205d43fd68SRuslan Bukin struct dwc_softc *sc; 521ca018790SMitchell Horne if_t ifp; 522ff0752c8SLuiz Otavio O Souza int error, i; 523ff0752c8SLuiz Otavio O Souza uint32_t reg; 5243e5cd548SEmmanuel Vadot uint32_t txpbl, rxpbl, pbl; 5255e38d9e4SEmmanuel Vadot bool nopblx8 = false; 5265e38d9e4SEmmanuel Vadot bool fixed_burst = false; 527f4bb6ea5SEmmanuel Vadot bool mixed_burst = false; 528b69c49d1SEmmanuel Vadot bool aal = false; 5295d43fd68SRuslan Bukin 5305d43fd68SRuslan Bukin sc = device_get_softc(dev); 5315d43fd68SRuslan Bukin sc->dev = dev; 5325d43fd68SRuslan Bukin sc->rx_idx = 0; 533e5232621SOleksandr Tymoshenko sc->tx_desccount = TX_DESC_COUNT; 534e5232621SOleksandr Tymoshenko sc->tx_mapcount = 0; 5355df53927SLuiz Otavio O Souza sc->mii_clk = IF_DWC_MII_CLK(dev); 5365df53927SLuiz Otavio O Souza sc->mactype = IF_DWC_MAC_TYPE(dev); 5375df53927SLuiz Otavio O Souza 538f114aaddSEmmanuel Vadot sc->node = ofw_bus_get_node(dev); 539f114aaddSEmmanuel Vadot switch (mii_fdt_get_contype(sc->node)) { 540f77d8d10SEmmanuel Vadot case MII_CONTYPE_RGMII: 541f77d8d10SEmmanuel Vadot case MII_CONTYPE_RGMII_ID: 542f77d8d10SEmmanuel Vadot case MII_CONTYPE_RGMII_RXID: 543f77d8d10SEmmanuel Vadot case MII_CONTYPE_RGMII_TXID: 544824cfb47SOleksandr Tymoshenko sc->phy_mode = PHY_MODE_RGMII; 545f77d8d10SEmmanuel Vadot break; 546f77d8d10SEmmanuel Vadot case MII_CONTYPE_RMII: 547824cfb47SOleksandr Tymoshenko sc->phy_mode = PHY_MODE_RMII; 548f77d8d10SEmmanuel Vadot break; 549da6252a6SEmmanuel Vadot case MII_CONTYPE_MII: 550da6252a6SEmmanuel Vadot sc->phy_mode = PHY_MODE_MII; 551da6252a6SEmmanuel Vadot break; 552f77d8d10SEmmanuel Vadot default: 553f77d8d10SEmmanuel Vadot device_printf(dev, "Unsupported MII type\n"); 554f77d8d10SEmmanuel Vadot return (ENXIO); 555824cfb47SOleksandr Tymoshenko } 556824cfb47SOleksandr Tymoshenko 557f114aaddSEmmanuel Vadot if (OF_getencprop(sc->node, "snps,pbl", &pbl, sizeof(uint32_t)) <= 0) 5583e5cd548SEmmanuel Vadot pbl = BUS_MODE_DEFAULT_PBL; 559f114aaddSEmmanuel Vadot if (OF_getencprop(sc->node, "snps,txpbl", &txpbl, sizeof(uint32_t)) <= 0) 5603e5cd548SEmmanuel Vadot txpbl = pbl; 561f114aaddSEmmanuel Vadot if (OF_getencprop(sc->node, "snps,rxpbl", &rxpbl, sizeof(uint32_t)) <= 0) 5623e5cd548SEmmanuel Vadot rxpbl = pbl; 563f114aaddSEmmanuel Vadot if (OF_hasprop(sc->node, "snps,no-pbl-x8") == 1) 5645e38d9e4SEmmanuel Vadot nopblx8 = true; 565f114aaddSEmmanuel Vadot if (OF_hasprop(sc->node, "snps,fixed-burst") == 1) 5665e38d9e4SEmmanuel Vadot fixed_burst = true; 567f4bb6ea5SEmmanuel Vadot if (OF_hasprop(sc->node, "snps,mixed-burst") == 1) 568f4bb6ea5SEmmanuel Vadot mixed_burst = true; 569b69c49d1SEmmanuel Vadot if (OF_hasprop(sc->node, "snps,aal") == 1) 570b69c49d1SEmmanuel Vadot aal = true; 5715e38d9e4SEmmanuel Vadot 57250059a60SEmmanuel Vadot error = clk_set_assigned(dev, ofw_bus_get_node(dev)); 57350059a60SEmmanuel Vadot if (error != 0) { 57450059a60SEmmanuel Vadot device_printf(dev, "clk_set_assigned failed\n"); 57550059a60SEmmanuel Vadot return (error); 57650059a60SEmmanuel Vadot } 5775d43fd68SRuslan Bukin 57850059a60SEmmanuel Vadot /* Enable main clock */ 57950059a60SEmmanuel Vadot if ((error = dwc_clock_init(sc)) != 0) 58050059a60SEmmanuel Vadot return (error); 58150059a60SEmmanuel Vadot /* De-assert main reset */ 58250059a60SEmmanuel Vadot if ((error = dwc_reset_deassert(sc)) != 0) 58350059a60SEmmanuel Vadot return (error); 58450059a60SEmmanuel Vadot 58550059a60SEmmanuel Vadot if (IF_DWC_INIT(dev) != 0) 5866a05f063SJared McNeill return (ENXIO); 5876a05f063SJared McNeill 5885d43fd68SRuslan Bukin if (bus_alloc_resources(dev, dwc_spec, sc->res)) { 5895d43fd68SRuslan Bukin device_printf(dev, "could not allocate resources\n"); 5905d43fd68SRuslan Bukin return (ENXIO); 5915d43fd68SRuslan Bukin } 5925d43fd68SRuslan Bukin 5935d43fd68SRuslan Bukin /* Read MAC before reset */ 59462519d5aSEmmanuel Vadot dwc1000_get_hwaddr(sc, macaddr); 5955d43fd68SRuslan Bukin 596d7acb49aSJared McNeill /* Reset the PHY if needed */ 597f114aaddSEmmanuel Vadot if (dwc_reset_phy(sc) != 0) { 598d7acb49aSJared McNeill device_printf(dev, "Can't reset the PHY\n"); 59930f16ad4SEmmanuel Vadot bus_release_resources(dev, dwc_spec, sc->res); 600d7acb49aSJared McNeill return (ENXIO); 601d7acb49aSJared McNeill } 602d7acb49aSJared McNeill 6035d43fd68SRuslan Bukin /* Reset */ 6045d43fd68SRuslan Bukin reg = READ4(sc, BUS_MODE); 6055d43fd68SRuslan Bukin reg |= (BUS_MODE_SWR); 6065d43fd68SRuslan Bukin WRITE4(sc, BUS_MODE, reg); 6075d43fd68SRuslan Bukin 608d8e5258dSRuslan Bukin for (i = 0; i < MAC_RESET_TIMEOUT; i++) { 6095d43fd68SRuslan Bukin if ((READ4(sc, BUS_MODE) & BUS_MODE_SWR) == 0) 6105d43fd68SRuslan Bukin break; 6115d43fd68SRuslan Bukin DELAY(10); 6125d43fd68SRuslan Bukin } 613d8e5258dSRuslan Bukin if (i >= MAC_RESET_TIMEOUT) { 6145d43fd68SRuslan Bukin device_printf(sc->dev, "Can't reset DWC.\n"); 61530f16ad4SEmmanuel Vadot bus_release_resources(dev, dwc_spec, sc->res); 6165d43fd68SRuslan Bukin return (ENXIO); 6175d43fd68SRuslan Bukin } 6185d43fd68SRuslan Bukin 6195e38d9e4SEmmanuel Vadot reg = BUS_MODE_USP; 6205e38d9e4SEmmanuel Vadot if (!nopblx8) 6215e38d9e4SEmmanuel Vadot reg |= BUS_MODE_EIGHTXPBL; 6225e38d9e4SEmmanuel Vadot reg |= (txpbl << BUS_MODE_PBL_SHIFT); 6235e38d9e4SEmmanuel Vadot reg |= (rxpbl << BUS_MODE_RPBL_SHIFT); 6245e38d9e4SEmmanuel Vadot if (fixed_burst) 6255e38d9e4SEmmanuel Vadot reg |= BUS_MODE_FIXEDBURST; 626f4bb6ea5SEmmanuel Vadot if (mixed_burst) 627f4bb6ea5SEmmanuel Vadot reg |= BUS_MODE_MIXEDBURST; 628b69c49d1SEmmanuel Vadot if (aal) 629b69c49d1SEmmanuel Vadot reg |= BUS_MODE_AAL; 6303e5cd548SEmmanuel Vadot 6315d43fd68SRuslan Bukin WRITE4(sc, BUS_MODE, reg); 6325d43fd68SRuslan Bukin 6335d43fd68SRuslan Bukin /* 6345d43fd68SRuslan Bukin * DMA must be stop while changing descriptor list addresses. 6355d43fd68SRuslan Bukin */ 6365d43fd68SRuslan Bukin reg = READ4(sc, OPERATION_MODE); 6375d43fd68SRuslan Bukin reg &= ~(MODE_ST | MODE_SR); 6385d43fd68SRuslan Bukin WRITE4(sc, OPERATION_MODE, reg); 6395d43fd68SRuslan Bukin 640972adf0fSEmmanuel Vadot if (dma1000_init(sc)) { 64130f16ad4SEmmanuel Vadot bus_release_resources(dev, dwc_spec, sc->res); 6425d43fd68SRuslan Bukin return (ENXIO); 64330f16ad4SEmmanuel Vadot } 6445d43fd68SRuslan Bukin 6455d43fd68SRuslan Bukin /* Setup addresses */ 6465d43fd68SRuslan Bukin WRITE4(sc, RX_DESCR_LIST_ADDR, sc->rxdesc_ring_paddr); 6475d43fd68SRuslan Bukin WRITE4(sc, TX_DESCR_LIST_ADDR, sc->txdesc_ring_paddr); 6485d43fd68SRuslan Bukin 649d8e5258dSRuslan Bukin mtx_init(&sc->mtx, device_get_nameunit(sc->dev), 650d8e5258dSRuslan Bukin MTX_NETWORK_LOCK, MTX_DEF); 651d8e5258dSRuslan Bukin 652d8e5258dSRuslan Bukin callout_init_mtx(&sc->dwc_callout, &sc->mtx, 0); 653d8e5258dSRuslan Bukin 654d8e5258dSRuslan Bukin /* Setup interrupt handler. */ 655d8e5258dSRuslan Bukin error = bus_setup_intr(dev, sc->res[1], INTR_TYPE_NET | INTR_MPSAFE, 656d8e5258dSRuslan Bukin NULL, dwc_intr, sc, &sc->intr_cookie); 657d8e5258dSRuslan Bukin if (error != 0) { 658d8e5258dSRuslan Bukin device_printf(dev, "could not setup interrupt handler.\n"); 65930f16ad4SEmmanuel Vadot bus_release_resources(dev, dwc_spec, sc->res); 660d8e5258dSRuslan Bukin return (ENXIO); 661d8e5258dSRuslan Bukin } 662d8e5258dSRuslan Bukin 6635d43fd68SRuslan Bukin /* Set up the ethernet interface. */ 6645d43fd68SRuslan Bukin sc->ifp = ifp = if_alloc(IFT_ETHER); 6655d43fd68SRuslan Bukin 666ca018790SMitchell Horne if_setsoftc(ifp, sc); 6675d43fd68SRuslan Bukin if_initname(ifp, device_get_name(dev), device_get_unit(dev)); 6683bbd11eeSEmmanuel Vadot if_setflags(sc->ifp, IFF_BROADCAST | IFF_SIMPLEX | IFF_MULTICAST); 6693bbd11eeSEmmanuel Vadot if_setstartfn(ifp, dwc_txstart); 6703bbd11eeSEmmanuel Vadot if_setioctlfn(ifp, dwc_ioctl); 6713bbd11eeSEmmanuel Vadot if_setinitfn(ifp, dwc_init); 672e5232621SOleksandr Tymoshenko if_setsendqlen(ifp, TX_MAP_COUNT - 1); 6733bbd11eeSEmmanuel Vadot if_setsendqready(sc->ifp); 67498ea5a7bSEmmanuel Vadot if_sethwassist(sc->ifp, CSUM_IP | CSUM_UDP | CSUM_TCP); 67598ea5a7bSEmmanuel Vadot if_setcapabilities(sc->ifp, IFCAP_VLAN_MTU | IFCAP_HWCSUM); 6763bbd11eeSEmmanuel Vadot if_setcapenable(sc->ifp, if_getcapabilities(sc->ifp)); 6775d43fd68SRuslan Bukin 6785d43fd68SRuslan Bukin /* Attach the mii driver. */ 6795d43fd68SRuslan Bukin error = mii_attach(dev, &sc->miibus, ifp, dwc_media_change, 6805d43fd68SRuslan Bukin dwc_media_status, BMSR_DEFCAPMASK, MII_PHY_ANY, 6815d43fd68SRuslan Bukin MII_OFFSET_ANY, 0); 6825d43fd68SRuslan Bukin 6835d43fd68SRuslan Bukin if (error != 0) { 6845d43fd68SRuslan Bukin device_printf(dev, "PHY attach failed\n"); 68530f16ad4SEmmanuel Vadot bus_teardown_intr(dev, sc->res[1], sc->intr_cookie); 68630f16ad4SEmmanuel Vadot bus_release_resources(dev, dwc_spec, sc->res); 6875d43fd68SRuslan Bukin return (ENXIO); 6885d43fd68SRuslan Bukin } 6895d43fd68SRuslan Bukin sc->mii_softc = device_get_softc(sc->miibus); 6905d43fd68SRuslan Bukin 6915d43fd68SRuslan Bukin /* All ready to run, attach the ethernet interface. */ 6925d43fd68SRuslan Bukin ether_ifattach(ifp, macaddr); 6935d43fd68SRuslan Bukin sc->is_attached = true; 6945d43fd68SRuslan Bukin 6955d43fd68SRuslan Bukin return (0); 6965d43fd68SRuslan Bukin } 6975d43fd68SRuslan Bukin 69827b39e58SMitchell Horne static int 69927b39e58SMitchell Horne dwc_detach(device_t dev) 70027b39e58SMitchell Horne { 70127b39e58SMitchell Horne struct dwc_softc *sc; 70227b39e58SMitchell Horne 70327b39e58SMitchell Horne sc = device_get_softc(dev); 70427b39e58SMitchell Horne 70527b39e58SMitchell Horne /* 70627b39e58SMitchell Horne * Disable and tear down interrupts before anything else, so we don't 70727b39e58SMitchell Horne * race with the handler. 70827b39e58SMitchell Horne */ 70927b39e58SMitchell Horne WRITE4(sc, INTERRUPT_ENABLE, 0); 71027b39e58SMitchell Horne if (sc->intr_cookie != NULL) { 71127b39e58SMitchell Horne bus_teardown_intr(dev, sc->res[1], sc->intr_cookie); 71227b39e58SMitchell Horne } 71327b39e58SMitchell Horne 71427b39e58SMitchell Horne if (sc->is_attached) { 71527b39e58SMitchell Horne DWC_LOCK(sc); 71627b39e58SMitchell Horne sc->is_detaching = true; 71727b39e58SMitchell Horne dwc_stop_locked(sc); 71827b39e58SMitchell Horne DWC_UNLOCK(sc); 71927b39e58SMitchell Horne callout_drain(&sc->dwc_callout); 72027b39e58SMitchell Horne ether_ifdetach(sc->ifp); 72127b39e58SMitchell Horne } 72227b39e58SMitchell Horne 72327b39e58SMitchell Horne if (sc->miibus != NULL) { 72427b39e58SMitchell Horne device_delete_child(dev, sc->miibus); 72527b39e58SMitchell Horne sc->miibus = NULL; 72627b39e58SMitchell Horne } 72727b39e58SMitchell Horne bus_generic_detach(dev); 72827b39e58SMitchell Horne 72927b39e58SMitchell Horne /* Free DMA descriptors */ 730972adf0fSEmmanuel Vadot dma1000_free(sc); 73127b39e58SMitchell Horne 73227b39e58SMitchell Horne if (sc->ifp != NULL) { 73327b39e58SMitchell Horne if_free(sc->ifp); 73427b39e58SMitchell Horne sc->ifp = NULL; 73527b39e58SMitchell Horne } 73627b39e58SMitchell Horne 73727b39e58SMitchell Horne bus_release_resources(dev, dwc_spec, sc->res); 73827b39e58SMitchell Horne 73927b39e58SMitchell Horne mtx_destroy(&sc->mtx); 74027b39e58SMitchell Horne return (0); 74127b39e58SMitchell Horne } 74227b39e58SMitchell Horne 7435d43fd68SRuslan Bukin static device_method_t dwc_methods[] = { 7445d43fd68SRuslan Bukin DEVMETHOD(device_probe, dwc_probe), 7455d43fd68SRuslan Bukin DEVMETHOD(device_attach, dwc_attach), 74627b39e58SMitchell Horne DEVMETHOD(device_detach, dwc_detach), 7475d43fd68SRuslan Bukin 7485d43fd68SRuslan Bukin /* MII Interface */ 74962519d5aSEmmanuel Vadot DEVMETHOD(miibus_readreg, dwc1000_miibus_read_reg), 75062519d5aSEmmanuel Vadot DEVMETHOD(miibus_writereg, dwc1000_miibus_write_reg), 75162519d5aSEmmanuel Vadot DEVMETHOD(miibus_statchg, dwc1000_miibus_statchg), 7525d43fd68SRuslan Bukin 7535d43fd68SRuslan Bukin { 0, 0 } 7545d43fd68SRuslan Bukin }; 7555d43fd68SRuslan Bukin 7565df53927SLuiz Otavio O Souza driver_t dwc_driver = { 7575d43fd68SRuslan Bukin "dwc", 7585d43fd68SRuslan Bukin dwc_methods, 7595d43fd68SRuslan Bukin sizeof(struct dwc_softc), 7605d43fd68SRuslan Bukin }; 7615d43fd68SRuslan Bukin 762e55d0536SJohn Baldwin DRIVER_MODULE(dwc, simplebus, dwc_driver, 0, 0); 7633e38757dSJohn Baldwin DRIVER_MODULE(miibus, dwc, miibus_driver, 0, 0); 7645d43fd68SRuslan Bukin 7655d43fd68SRuslan Bukin MODULE_DEPEND(dwc, ether, 1, 1, 1); 7665d43fd68SRuslan Bukin MODULE_DEPEND(dwc, miibus, 1, 1, 1); 767