1*5d43fd68SRuslan Bukin /*- 2*5d43fd68SRuslan Bukin * Copyright (c) 2014 Ruslan Bukin <br@bsdpad.com> 3*5d43fd68SRuslan Bukin * All rights reserved. 4*5d43fd68SRuslan Bukin * 5*5d43fd68SRuslan Bukin * This software was developed by SRI International and the University of 6*5d43fd68SRuslan Bukin * Cambridge Computer Laboratory under DARPA/AFRL contract (FA8750-10-C-0237) 7*5d43fd68SRuslan Bukin * ("CTSRD"), as part of the DARPA CRASH research programme. 8*5d43fd68SRuslan Bukin * 9*5d43fd68SRuslan Bukin * Redistribution and use in source and binary forms, with or without 10*5d43fd68SRuslan Bukin * modification, are permitted provided that the following conditions 11*5d43fd68SRuslan Bukin * are met: 12*5d43fd68SRuslan Bukin * 1. Redistributions of source code must retain the above copyright 13*5d43fd68SRuslan Bukin * notice, this list of conditions and the following disclaimer. 14*5d43fd68SRuslan Bukin * 2. Redistributions in binary form must reproduce the above copyright 15*5d43fd68SRuslan Bukin * notice, this list of conditions and the following disclaimer in the 16*5d43fd68SRuslan Bukin * documentation and/or other materials provided with the distribution. 17*5d43fd68SRuslan Bukin * 18*5d43fd68SRuslan Bukin * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 19*5d43fd68SRuslan Bukin * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 20*5d43fd68SRuslan Bukin * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 21*5d43fd68SRuslan Bukin * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 22*5d43fd68SRuslan Bukin * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 23*5d43fd68SRuslan Bukin * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 24*5d43fd68SRuslan Bukin * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 25*5d43fd68SRuslan Bukin * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 26*5d43fd68SRuslan Bukin * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 27*5d43fd68SRuslan Bukin * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 28*5d43fd68SRuslan Bukin * SUCH DAMAGE. 29*5d43fd68SRuslan Bukin */ 30*5d43fd68SRuslan Bukin 31*5d43fd68SRuslan Bukin /* 32*5d43fd68SRuslan Bukin * Ethernet media access controller (EMAC) 33*5d43fd68SRuslan Bukin * Chapter 17, Altera Cyclone V Device Handbook (CV-5V2 2014.07.22) 34*5d43fd68SRuslan Bukin * 35*5d43fd68SRuslan Bukin * EMAC is an instance of the Synopsys DesignWare 3504-0 36*5d43fd68SRuslan Bukin * Universal 10/100/1000 Ethernet MAC (DWC_gmac). 37*5d43fd68SRuslan Bukin */ 38*5d43fd68SRuslan Bukin 39*5d43fd68SRuslan Bukin #include <sys/cdefs.h> 40*5d43fd68SRuslan Bukin __FBSDID("$FreeBSD$"); 41*5d43fd68SRuslan Bukin 42*5d43fd68SRuslan Bukin #include <sys/param.h> 43*5d43fd68SRuslan Bukin #include <sys/systm.h> 44*5d43fd68SRuslan Bukin #include <sys/bus.h> 45*5d43fd68SRuslan Bukin #include <sys/kernel.h> 46*5d43fd68SRuslan Bukin #include <sys/module.h> 47*5d43fd68SRuslan Bukin #include <sys/malloc.h> 48*5d43fd68SRuslan Bukin #include <sys/rman.h> 49*5d43fd68SRuslan Bukin #include <sys/timeet.h> 50*5d43fd68SRuslan Bukin #include <sys/timetc.h> 51*5d43fd68SRuslan Bukin #include <sys/endian.h> 52*5d43fd68SRuslan Bukin #include <sys/lock.h> 53*5d43fd68SRuslan Bukin #include <sys/mbuf.h> 54*5d43fd68SRuslan Bukin #include <sys/mutex.h> 55*5d43fd68SRuslan Bukin #include <sys/socket.h> 56*5d43fd68SRuslan Bukin #include <sys/sockio.h> 57*5d43fd68SRuslan Bukin #include <sys/sysctl.h> 58*5d43fd68SRuslan Bukin 59*5d43fd68SRuslan Bukin #include <dev/fdt/fdt_common.h> 60*5d43fd68SRuslan Bukin #include <dev/ofw/openfirm.h> 61*5d43fd68SRuslan Bukin #include <dev/ofw/ofw_bus.h> 62*5d43fd68SRuslan Bukin #include <dev/ofw/ofw_bus_subr.h> 63*5d43fd68SRuslan Bukin 64*5d43fd68SRuslan Bukin #include <net/bpf.h> 65*5d43fd68SRuslan Bukin #include <net/if.h> 66*5d43fd68SRuslan Bukin #include <net/ethernet.h> 67*5d43fd68SRuslan Bukin #include <net/if_dl.h> 68*5d43fd68SRuslan Bukin #include <net/if_media.h> 69*5d43fd68SRuslan Bukin #include <net/if_types.h> 70*5d43fd68SRuslan Bukin #include <net/if_var.h> 71*5d43fd68SRuslan Bukin #include <net/if_vlan_var.h> 72*5d43fd68SRuslan Bukin 73*5d43fd68SRuslan Bukin #include <machine/bus.h> 74*5d43fd68SRuslan Bukin #include <machine/fdt.h> 75*5d43fd68SRuslan Bukin #include <machine/cpu.h> 76*5d43fd68SRuslan Bukin #include <machine/intr.h> 77*5d43fd68SRuslan Bukin 78*5d43fd68SRuslan Bukin #include <dev/mii/mii.h> 79*5d43fd68SRuslan Bukin #include <dev/mii/miivar.h> 80*5d43fd68SRuslan Bukin #include "miibus_if.h" 81*5d43fd68SRuslan Bukin 82*5d43fd68SRuslan Bukin #define READ4(_sc, _reg) \ 83*5d43fd68SRuslan Bukin bus_read_4((_sc)->res[0], _reg) 84*5d43fd68SRuslan Bukin #define WRITE4(_sc, _reg, _val) \ 85*5d43fd68SRuslan Bukin bus_write_4((_sc)->res[0], _reg, _val) 86*5d43fd68SRuslan Bukin 87*5d43fd68SRuslan Bukin #define WATCHDOG_TIMEOUT_SECS 5 88*5d43fd68SRuslan Bukin #define STATS_HARVEST_INTERVAL 2 89*5d43fd68SRuslan Bukin #define MII_CLK_VAL 2 90*5d43fd68SRuslan Bukin 91*5d43fd68SRuslan Bukin #include <dev/dwc/if_dwc.h> 92*5d43fd68SRuslan Bukin 93*5d43fd68SRuslan Bukin #define DWC_LOCK(sc) mtx_lock(&(sc)->mtx) 94*5d43fd68SRuslan Bukin #define DWC_UNLOCK(sc) mtx_unlock(&(sc)->mtx) 95*5d43fd68SRuslan Bukin #define DWC_ASSERT_LOCKED(sc) mtx_assert(&(sc)->mtx, MA_OWNED); 96*5d43fd68SRuslan Bukin #define DWC_ASSERT_UNLOCKED(sc) mtx_assert(&(sc)->mtx, MA_NOTOWNED); 97*5d43fd68SRuslan Bukin 98*5d43fd68SRuslan Bukin #define DDESC_TDES0_OWN (1 << 31) 99*5d43fd68SRuslan Bukin #define DDESC_TDES0_TXINT (1 << 30) 100*5d43fd68SRuslan Bukin #define DDESC_TDES0_TXLAST (1 << 29) 101*5d43fd68SRuslan Bukin #define DDESC_TDES0_TXFIRST (1 << 28) 102*5d43fd68SRuslan Bukin #define DDESC_TDES0_TXCRCDIS (1 << 27) 103*5d43fd68SRuslan Bukin #define DDESC_TDES0_TXRINGEND (1 << 21) 104*5d43fd68SRuslan Bukin #define DDESC_TDES0_TXCHAIN (1 << 20) 105*5d43fd68SRuslan Bukin 106*5d43fd68SRuslan Bukin #define DDESC_RDES0_OWN (1 << 31) 107*5d43fd68SRuslan Bukin #define DDESC_RDES0_FL_MASK 0x3fff 108*5d43fd68SRuslan Bukin #define DDESC_RDES0_FL_SHIFT 16 /* Frame Length */ 109*5d43fd68SRuslan Bukin #define DDESC_RDES1_CHAINED (1 << 14) 110*5d43fd68SRuslan Bukin 111*5d43fd68SRuslan Bukin struct dwc_bufmap { 112*5d43fd68SRuslan Bukin bus_dmamap_t map; 113*5d43fd68SRuslan Bukin struct mbuf *mbuf; 114*5d43fd68SRuslan Bukin }; 115*5d43fd68SRuslan Bukin 116*5d43fd68SRuslan Bukin /* 117*5d43fd68SRuslan Bukin * A hardware buffer descriptor. Rx and Tx buffers have the same descriptor 118*5d43fd68SRuslan Bukin * layout, but the bits in the flags field have different meanings. 119*5d43fd68SRuslan Bukin */ 120*5d43fd68SRuslan Bukin struct dwc_hwdesc 121*5d43fd68SRuslan Bukin { 122*5d43fd68SRuslan Bukin uint32_t tdes0; 123*5d43fd68SRuslan Bukin uint32_t tdes1; 124*5d43fd68SRuslan Bukin uint32_t addr; /* pointer to buffer data */ 125*5d43fd68SRuslan Bukin uint32_t addr_next; /* link to next descriptor */ 126*5d43fd68SRuslan Bukin }; 127*5d43fd68SRuslan Bukin 128*5d43fd68SRuslan Bukin /* 129*5d43fd68SRuslan Bukin * Driver data and defines. 130*5d43fd68SRuslan Bukin */ 131*5d43fd68SRuslan Bukin #define RX_DESC_COUNT 1024 132*5d43fd68SRuslan Bukin #define RX_DESC_SIZE (sizeof(struct dwc_hwdesc) * RX_DESC_COUNT) 133*5d43fd68SRuslan Bukin #define TX_DESC_COUNT 1024 134*5d43fd68SRuslan Bukin #define TX_DESC_SIZE (sizeof(struct dwc_hwdesc) * TX_DESC_COUNT) 135*5d43fd68SRuslan Bukin 136*5d43fd68SRuslan Bukin /* 137*5d43fd68SRuslan Bukin * The hardware imposes alignment restrictions on various objects involved in 138*5d43fd68SRuslan Bukin * DMA transfers. These values are expressed in bytes (not bits). 139*5d43fd68SRuslan Bukin */ 140*5d43fd68SRuslan Bukin #define DWC_DESC_RING_ALIGN 2048 141*5d43fd68SRuslan Bukin 142*5d43fd68SRuslan Bukin struct dwc_softc { 143*5d43fd68SRuslan Bukin struct resource *res[2]; 144*5d43fd68SRuslan Bukin bus_space_tag_t bst; 145*5d43fd68SRuslan Bukin bus_space_handle_t bsh; 146*5d43fd68SRuslan Bukin device_t dev; 147*5d43fd68SRuslan Bukin int mii_clk; 148*5d43fd68SRuslan Bukin device_t miibus; 149*5d43fd68SRuslan Bukin struct mii_data * mii_softc; 150*5d43fd68SRuslan Bukin struct ifnet *ifp; 151*5d43fd68SRuslan Bukin int if_flags; 152*5d43fd68SRuslan Bukin struct mtx mtx; 153*5d43fd68SRuslan Bukin void * intr_cookie; 154*5d43fd68SRuslan Bukin struct callout dwc_callout; 155*5d43fd68SRuslan Bukin uint8_t phy_conn_type; 156*5d43fd68SRuslan Bukin uint8_t mactype; 157*5d43fd68SRuslan Bukin boolean_t link_is_up; 158*5d43fd68SRuslan Bukin boolean_t is_attached; 159*5d43fd68SRuslan Bukin boolean_t is_detaching; 160*5d43fd68SRuslan Bukin int tx_watchdog_count; 161*5d43fd68SRuslan Bukin int stats_harvest_count; 162*5d43fd68SRuslan Bukin 163*5d43fd68SRuslan Bukin /* RX */ 164*5d43fd68SRuslan Bukin bus_dma_tag_t rxdesc_tag; 165*5d43fd68SRuslan Bukin bus_dmamap_t rxdesc_map; 166*5d43fd68SRuslan Bukin struct dwc_hwdesc *rxdesc_ring; 167*5d43fd68SRuslan Bukin bus_addr_t rxdesc_ring_paddr; 168*5d43fd68SRuslan Bukin bus_dma_tag_t rxbuf_tag; 169*5d43fd68SRuslan Bukin struct dwc_bufmap rxbuf_map[RX_DESC_COUNT]; 170*5d43fd68SRuslan Bukin uint32_t rx_idx; 171*5d43fd68SRuslan Bukin 172*5d43fd68SRuslan Bukin /* TX */ 173*5d43fd68SRuslan Bukin bus_dma_tag_t txdesc_tag; 174*5d43fd68SRuslan Bukin bus_dmamap_t txdesc_map; 175*5d43fd68SRuslan Bukin struct dwc_hwdesc *txdesc_ring; 176*5d43fd68SRuslan Bukin bus_addr_t txdesc_ring_paddr; 177*5d43fd68SRuslan Bukin bus_dma_tag_t txbuf_tag; 178*5d43fd68SRuslan Bukin struct dwc_bufmap txbuf_map[RX_DESC_COUNT]; 179*5d43fd68SRuslan Bukin uint32_t tx_idx_head; 180*5d43fd68SRuslan Bukin uint32_t tx_idx_tail; 181*5d43fd68SRuslan Bukin int txcount; 182*5d43fd68SRuslan Bukin }; 183*5d43fd68SRuslan Bukin 184*5d43fd68SRuslan Bukin static struct resource_spec dwc_spec[] = { 185*5d43fd68SRuslan Bukin { SYS_RES_MEMORY, 0, RF_ACTIVE }, 186*5d43fd68SRuslan Bukin { SYS_RES_IRQ, 0, RF_ACTIVE }, 187*5d43fd68SRuslan Bukin { -1, 0 } 188*5d43fd68SRuslan Bukin }; 189*5d43fd68SRuslan Bukin 190*5d43fd68SRuslan Bukin static void dwc_txfinish_locked(struct dwc_softc *sc); 191*5d43fd68SRuslan Bukin static void dwc_rxfinish_locked(struct dwc_softc *sc); 192*5d43fd68SRuslan Bukin static void dwc_stop_locked(struct dwc_softc *sc); 193*5d43fd68SRuslan Bukin static void dwc_setup_rxfilter(struct dwc_softc *sc); 194*5d43fd68SRuslan Bukin 195*5d43fd68SRuslan Bukin static inline uint32_t 196*5d43fd68SRuslan Bukin next_rxidx(struct dwc_softc *sc, uint32_t curidx) 197*5d43fd68SRuslan Bukin { 198*5d43fd68SRuslan Bukin 199*5d43fd68SRuslan Bukin return ((curidx + 1) % RX_DESC_COUNT); 200*5d43fd68SRuslan Bukin } 201*5d43fd68SRuslan Bukin 202*5d43fd68SRuslan Bukin static inline uint32_t 203*5d43fd68SRuslan Bukin next_txidx(struct dwc_softc *sc, uint32_t curidx) 204*5d43fd68SRuslan Bukin { 205*5d43fd68SRuslan Bukin 206*5d43fd68SRuslan Bukin return ((curidx + 1) % TX_DESC_COUNT); 207*5d43fd68SRuslan Bukin } 208*5d43fd68SRuslan Bukin 209*5d43fd68SRuslan Bukin static void 210*5d43fd68SRuslan Bukin dwc_get1paddr(void *arg, bus_dma_segment_t *segs, int nsegs, int error) 211*5d43fd68SRuslan Bukin { 212*5d43fd68SRuslan Bukin 213*5d43fd68SRuslan Bukin if (error != 0) 214*5d43fd68SRuslan Bukin return; 215*5d43fd68SRuslan Bukin *(bus_addr_t *)arg = segs[0].ds_addr; 216*5d43fd68SRuslan Bukin } 217*5d43fd68SRuslan Bukin 218*5d43fd68SRuslan Bukin inline static uint32_t 219*5d43fd68SRuslan Bukin dwc_setup_txdesc(struct dwc_softc *sc, int idx, bus_addr_t paddr, 220*5d43fd68SRuslan Bukin uint32_t len) 221*5d43fd68SRuslan Bukin { 222*5d43fd68SRuslan Bukin uint32_t flags; 223*5d43fd68SRuslan Bukin uint32_t nidx; 224*5d43fd68SRuslan Bukin 225*5d43fd68SRuslan Bukin nidx = next_txidx(sc, idx); 226*5d43fd68SRuslan Bukin 227*5d43fd68SRuslan Bukin /* Addr/len 0 means we're clearing the descriptor after xmit done. */ 228*5d43fd68SRuslan Bukin if (paddr == 0 || len == 0) { 229*5d43fd68SRuslan Bukin flags = 0; 230*5d43fd68SRuslan Bukin --sc->txcount; 231*5d43fd68SRuslan Bukin } else { 232*5d43fd68SRuslan Bukin flags = DDESC_TDES0_TXCHAIN | DDESC_TDES0_TXFIRST 233*5d43fd68SRuslan Bukin | DDESC_TDES0_TXLAST | DDESC_TDES0_TXINT; 234*5d43fd68SRuslan Bukin ++sc->txcount; 235*5d43fd68SRuslan Bukin } 236*5d43fd68SRuslan Bukin 237*5d43fd68SRuslan Bukin sc->txdesc_ring[idx].addr = (uint32_t)(paddr); 238*5d43fd68SRuslan Bukin sc->txdesc_ring[idx].tdes0 = flags; 239*5d43fd68SRuslan Bukin sc->txdesc_ring[idx].tdes1 = len; 240*5d43fd68SRuslan Bukin 241*5d43fd68SRuslan Bukin if (paddr && len) { 242*5d43fd68SRuslan Bukin wmb(); 243*5d43fd68SRuslan Bukin sc->txdesc_ring[idx].tdes0 |= DDESC_TDES0_OWN; 244*5d43fd68SRuslan Bukin wmb(); 245*5d43fd68SRuslan Bukin } 246*5d43fd68SRuslan Bukin 247*5d43fd68SRuslan Bukin return (nidx); 248*5d43fd68SRuslan Bukin } 249*5d43fd68SRuslan Bukin 250*5d43fd68SRuslan Bukin static int 251*5d43fd68SRuslan Bukin dwc_setup_txbuf(struct dwc_softc *sc, int idx, struct mbuf **mp) 252*5d43fd68SRuslan Bukin { 253*5d43fd68SRuslan Bukin struct bus_dma_segment seg; 254*5d43fd68SRuslan Bukin int error, nsegs; 255*5d43fd68SRuslan Bukin struct mbuf * m; 256*5d43fd68SRuslan Bukin 257*5d43fd68SRuslan Bukin if ((m = m_defrag(*mp, M_NOWAIT)) == NULL) 258*5d43fd68SRuslan Bukin return (ENOMEM); 259*5d43fd68SRuslan Bukin *mp = m; 260*5d43fd68SRuslan Bukin 261*5d43fd68SRuslan Bukin error = bus_dmamap_load_mbuf_sg(sc->txbuf_tag, sc->txbuf_map[idx].map, 262*5d43fd68SRuslan Bukin m, &seg, &nsegs, 0); 263*5d43fd68SRuslan Bukin if (error != 0) { 264*5d43fd68SRuslan Bukin return (ENOMEM); 265*5d43fd68SRuslan Bukin } 266*5d43fd68SRuslan Bukin 267*5d43fd68SRuslan Bukin KASSERT(nsegs == 1, ("%s: %d segments returned!", __func__, nsegs)); 268*5d43fd68SRuslan Bukin 269*5d43fd68SRuslan Bukin bus_dmamap_sync(sc->txbuf_tag, sc->txbuf_map[idx].map, 270*5d43fd68SRuslan Bukin BUS_DMASYNC_PREWRITE); 271*5d43fd68SRuslan Bukin 272*5d43fd68SRuslan Bukin sc->txbuf_map[idx].mbuf = m; 273*5d43fd68SRuslan Bukin 274*5d43fd68SRuslan Bukin dwc_setup_txdesc(sc, idx, seg.ds_addr, seg.ds_len); 275*5d43fd68SRuslan Bukin 276*5d43fd68SRuslan Bukin return (0); 277*5d43fd68SRuslan Bukin } 278*5d43fd68SRuslan Bukin 279*5d43fd68SRuslan Bukin static void 280*5d43fd68SRuslan Bukin dwc_txstart_locked(struct dwc_softc *sc) 281*5d43fd68SRuslan Bukin { 282*5d43fd68SRuslan Bukin struct ifnet *ifp; 283*5d43fd68SRuslan Bukin struct mbuf *m; 284*5d43fd68SRuslan Bukin int enqueued; 285*5d43fd68SRuslan Bukin 286*5d43fd68SRuslan Bukin DWC_ASSERT_LOCKED(sc); 287*5d43fd68SRuslan Bukin 288*5d43fd68SRuslan Bukin if (!sc->link_is_up) 289*5d43fd68SRuslan Bukin return; 290*5d43fd68SRuslan Bukin 291*5d43fd68SRuslan Bukin ifp = sc->ifp; 292*5d43fd68SRuslan Bukin 293*5d43fd68SRuslan Bukin if (ifp->if_drv_flags & IFF_DRV_OACTIVE) { 294*5d43fd68SRuslan Bukin return; 295*5d43fd68SRuslan Bukin } 296*5d43fd68SRuslan Bukin 297*5d43fd68SRuslan Bukin enqueued = 0; 298*5d43fd68SRuslan Bukin 299*5d43fd68SRuslan Bukin for (;;) { 300*5d43fd68SRuslan Bukin if (sc->txcount == (TX_DESC_COUNT-1)) { 301*5d43fd68SRuslan Bukin ifp->if_drv_flags |= IFF_DRV_OACTIVE; 302*5d43fd68SRuslan Bukin break; 303*5d43fd68SRuslan Bukin } 304*5d43fd68SRuslan Bukin 305*5d43fd68SRuslan Bukin IFQ_DRV_DEQUEUE(&ifp->if_snd, m); 306*5d43fd68SRuslan Bukin if (m == NULL) 307*5d43fd68SRuslan Bukin break; 308*5d43fd68SRuslan Bukin if (dwc_setup_txbuf(sc, sc->tx_idx_head, &m) != 0) { 309*5d43fd68SRuslan Bukin IFQ_DRV_PREPEND(&ifp->if_snd, m); 310*5d43fd68SRuslan Bukin break; 311*5d43fd68SRuslan Bukin } 312*5d43fd68SRuslan Bukin BPF_MTAP(ifp, m); 313*5d43fd68SRuslan Bukin sc->tx_idx_head = next_txidx(sc, sc->tx_idx_head); 314*5d43fd68SRuslan Bukin ++enqueued; 315*5d43fd68SRuslan Bukin } 316*5d43fd68SRuslan Bukin 317*5d43fd68SRuslan Bukin if (enqueued != 0) { 318*5d43fd68SRuslan Bukin WRITE4(sc, TRANSMIT_POLL_DEMAND, 0x1); 319*5d43fd68SRuslan Bukin sc->tx_watchdog_count = WATCHDOG_TIMEOUT_SECS; 320*5d43fd68SRuslan Bukin } 321*5d43fd68SRuslan Bukin } 322*5d43fd68SRuslan Bukin 323*5d43fd68SRuslan Bukin static void 324*5d43fd68SRuslan Bukin dwc_txstart(struct ifnet *ifp) 325*5d43fd68SRuslan Bukin { 326*5d43fd68SRuslan Bukin struct dwc_softc *sc = ifp->if_softc; 327*5d43fd68SRuslan Bukin 328*5d43fd68SRuslan Bukin DWC_LOCK(sc); 329*5d43fd68SRuslan Bukin dwc_txstart_locked(sc); 330*5d43fd68SRuslan Bukin DWC_UNLOCK(sc); 331*5d43fd68SRuslan Bukin } 332*5d43fd68SRuslan Bukin 333*5d43fd68SRuslan Bukin static void 334*5d43fd68SRuslan Bukin dwc_stop_locked(struct dwc_softc *sc) 335*5d43fd68SRuslan Bukin { 336*5d43fd68SRuslan Bukin struct ifnet *ifp; 337*5d43fd68SRuslan Bukin int reg; 338*5d43fd68SRuslan Bukin 339*5d43fd68SRuslan Bukin DWC_ASSERT_LOCKED(sc); 340*5d43fd68SRuslan Bukin 341*5d43fd68SRuslan Bukin ifp = sc->ifp; 342*5d43fd68SRuslan Bukin ifp->if_drv_flags &= ~(IFF_DRV_RUNNING | IFF_DRV_OACTIVE); 343*5d43fd68SRuslan Bukin sc->tx_watchdog_count = 0; 344*5d43fd68SRuslan Bukin sc->stats_harvest_count = 0; 345*5d43fd68SRuslan Bukin 346*5d43fd68SRuslan Bukin callout_stop(&sc->dwc_callout); 347*5d43fd68SRuslan Bukin 348*5d43fd68SRuslan Bukin /* Stop DMA TX */ 349*5d43fd68SRuslan Bukin reg = READ4(sc, OPERATION_MODE); 350*5d43fd68SRuslan Bukin reg &= ~(MODE_ST); 351*5d43fd68SRuslan Bukin WRITE4(sc, OPERATION_MODE, reg); 352*5d43fd68SRuslan Bukin 353*5d43fd68SRuslan Bukin /* Flush TX */ 354*5d43fd68SRuslan Bukin reg = READ4(sc, OPERATION_MODE); 355*5d43fd68SRuslan Bukin reg |= (MODE_FTF); 356*5d43fd68SRuslan Bukin WRITE4(sc, OPERATION_MODE, reg); 357*5d43fd68SRuslan Bukin 358*5d43fd68SRuslan Bukin /* Stop transmitters */ 359*5d43fd68SRuslan Bukin reg = READ4(sc, MAC_CONFIGURATION); 360*5d43fd68SRuslan Bukin reg &= ~(CONF_TE | CONF_RE); 361*5d43fd68SRuslan Bukin WRITE4(sc, MAC_CONFIGURATION, reg); 362*5d43fd68SRuslan Bukin 363*5d43fd68SRuslan Bukin /* Stop DMA RX */ 364*5d43fd68SRuslan Bukin reg = READ4(sc, OPERATION_MODE); 365*5d43fd68SRuslan Bukin reg &= ~(MODE_SR); 366*5d43fd68SRuslan Bukin WRITE4(sc, OPERATION_MODE, reg); 367*5d43fd68SRuslan Bukin } 368*5d43fd68SRuslan Bukin 369*5d43fd68SRuslan Bukin static void dwc_clear_stats(struct dwc_softc *sc) 370*5d43fd68SRuslan Bukin { 371*5d43fd68SRuslan Bukin int reg; 372*5d43fd68SRuslan Bukin 373*5d43fd68SRuslan Bukin reg = READ4(sc, MMC_CONTROL); 374*5d43fd68SRuslan Bukin reg |= (MMC_CONTROL_CNTRST); 375*5d43fd68SRuslan Bukin WRITE4(sc, MMC_CONTROL, reg); 376*5d43fd68SRuslan Bukin } 377*5d43fd68SRuslan Bukin 378*5d43fd68SRuslan Bukin static void 379*5d43fd68SRuslan Bukin dwc_harvest_stats(struct dwc_softc *sc) 380*5d43fd68SRuslan Bukin { 381*5d43fd68SRuslan Bukin struct ifnet *ifp; 382*5d43fd68SRuslan Bukin 383*5d43fd68SRuslan Bukin /* We don't need to harvest too often. */ 384*5d43fd68SRuslan Bukin if (++sc->stats_harvest_count < STATS_HARVEST_INTERVAL) 385*5d43fd68SRuslan Bukin return; 386*5d43fd68SRuslan Bukin 387*5d43fd68SRuslan Bukin sc->stats_harvest_count = 0; 388*5d43fd68SRuslan Bukin ifp = sc->ifp; 389*5d43fd68SRuslan Bukin 390*5d43fd68SRuslan Bukin if_inc_counter(ifp, IFCOUNTER_IPACKETS, READ4(sc, RXFRAMECOUNT_GB)); 391*5d43fd68SRuslan Bukin if_inc_counter(ifp, IFCOUNTER_IMCASTS, READ4(sc, RXMULTICASTFRAMES_G)); 392*5d43fd68SRuslan Bukin if_inc_counter(ifp, IFCOUNTER_IERRORS, 393*5d43fd68SRuslan Bukin READ4(sc, RXOVERSIZE_G) + READ4(sc, RXUNDERSIZE_G) + 394*5d43fd68SRuslan Bukin READ4(sc, RXCRCERROR) + READ4(sc, RXALIGNMENTERROR) + 395*5d43fd68SRuslan Bukin READ4(sc, RXRUNTERROR) + READ4(sc, RXJABBERERROR) + 396*5d43fd68SRuslan Bukin READ4(sc, RXLENGTHERROR)); 397*5d43fd68SRuslan Bukin 398*5d43fd68SRuslan Bukin if_inc_counter(ifp, IFCOUNTER_OPACKETS, READ4(sc, TXFRAMECOUNT_G)); 399*5d43fd68SRuslan Bukin if_inc_counter(ifp, IFCOUNTER_OMCASTS, READ4(sc, TXMULTICASTFRAMES_G)); 400*5d43fd68SRuslan Bukin if_inc_counter(ifp, IFCOUNTER_OERRORS, 401*5d43fd68SRuslan Bukin READ4(sc, TXOVERSIZE_G) + READ4(sc, TXEXCESSDEF) + 402*5d43fd68SRuslan Bukin READ4(sc, TXCARRIERERR) + READ4(sc, TXUNDERFLOWERROR)); 403*5d43fd68SRuslan Bukin 404*5d43fd68SRuslan Bukin if_inc_counter(ifp, IFCOUNTER_COLLISIONS, 405*5d43fd68SRuslan Bukin READ4(sc, TXEXESSCOL) + READ4(sc, TXLATECOL)); 406*5d43fd68SRuslan Bukin 407*5d43fd68SRuslan Bukin dwc_clear_stats(sc); 408*5d43fd68SRuslan Bukin } 409*5d43fd68SRuslan Bukin 410*5d43fd68SRuslan Bukin static void 411*5d43fd68SRuslan Bukin dwc_tick(void *arg) 412*5d43fd68SRuslan Bukin { 413*5d43fd68SRuslan Bukin struct dwc_softc *sc; 414*5d43fd68SRuslan Bukin struct ifnet *ifp; 415*5d43fd68SRuslan Bukin int link_was_up; 416*5d43fd68SRuslan Bukin 417*5d43fd68SRuslan Bukin sc = arg; 418*5d43fd68SRuslan Bukin 419*5d43fd68SRuslan Bukin DWC_ASSERT_LOCKED(sc); 420*5d43fd68SRuslan Bukin 421*5d43fd68SRuslan Bukin ifp = sc->ifp; 422*5d43fd68SRuslan Bukin 423*5d43fd68SRuslan Bukin if (!(ifp->if_drv_flags & IFF_DRV_RUNNING)) 424*5d43fd68SRuslan Bukin return; 425*5d43fd68SRuslan Bukin 426*5d43fd68SRuslan Bukin /* 427*5d43fd68SRuslan Bukin * Typical tx watchdog. If this fires it indicates that we enqueued 428*5d43fd68SRuslan Bukin * packets for output and never got a txdone interrupt for them. Maybe 429*5d43fd68SRuslan Bukin * it's a missed interrupt somehow, just pretend we got one. 430*5d43fd68SRuslan Bukin */ 431*5d43fd68SRuslan Bukin if (sc->tx_watchdog_count > 0) { 432*5d43fd68SRuslan Bukin if (--sc->tx_watchdog_count == 0) { 433*5d43fd68SRuslan Bukin dwc_txfinish_locked(sc); 434*5d43fd68SRuslan Bukin } 435*5d43fd68SRuslan Bukin } 436*5d43fd68SRuslan Bukin 437*5d43fd68SRuslan Bukin /* Gather stats from hardware counters. */ 438*5d43fd68SRuslan Bukin dwc_harvest_stats(sc); 439*5d43fd68SRuslan Bukin 440*5d43fd68SRuslan Bukin /* Check the media status. */ 441*5d43fd68SRuslan Bukin link_was_up = sc->link_is_up; 442*5d43fd68SRuslan Bukin mii_tick(sc->mii_softc); 443*5d43fd68SRuslan Bukin if (sc->link_is_up && !link_was_up) 444*5d43fd68SRuslan Bukin dwc_txstart_locked(sc); 445*5d43fd68SRuslan Bukin 446*5d43fd68SRuslan Bukin /* Schedule another check one second from now. */ 447*5d43fd68SRuslan Bukin callout_reset(&sc->dwc_callout, hz, dwc_tick, sc); 448*5d43fd68SRuslan Bukin } 449*5d43fd68SRuslan Bukin 450*5d43fd68SRuslan Bukin static void 451*5d43fd68SRuslan Bukin dwc_init_locked(struct dwc_softc *sc) 452*5d43fd68SRuslan Bukin { 453*5d43fd68SRuslan Bukin struct ifnet *ifp = sc->ifp; 454*5d43fd68SRuslan Bukin int reg; 455*5d43fd68SRuslan Bukin 456*5d43fd68SRuslan Bukin DWC_ASSERT_LOCKED(sc); 457*5d43fd68SRuslan Bukin 458*5d43fd68SRuslan Bukin if (ifp->if_drv_flags & IFF_DRV_RUNNING) 459*5d43fd68SRuslan Bukin return; 460*5d43fd68SRuslan Bukin 461*5d43fd68SRuslan Bukin ifp->if_drv_flags |= IFF_DRV_RUNNING; 462*5d43fd68SRuslan Bukin 463*5d43fd68SRuslan Bukin dwc_setup_rxfilter(sc); 464*5d43fd68SRuslan Bukin 465*5d43fd68SRuslan Bukin /* Initializa DMA and enable transmitters */ 466*5d43fd68SRuslan Bukin reg = READ4(sc, OPERATION_MODE); 467*5d43fd68SRuslan Bukin reg |= (MODE_TSF | MODE_OSF | MODE_FUF); 468*5d43fd68SRuslan Bukin reg &= ~(MODE_RSF); 469*5d43fd68SRuslan Bukin reg |= (MODE_RTC_LEV32 << MODE_RTC_SHIFT); 470*5d43fd68SRuslan Bukin WRITE4(sc, OPERATION_MODE, reg); 471*5d43fd68SRuslan Bukin 472*5d43fd68SRuslan Bukin WRITE4(sc, INTERRUPT_ENABLE, INT_EN_DEFAULT); 473*5d43fd68SRuslan Bukin 474*5d43fd68SRuslan Bukin /* Start DMA */ 475*5d43fd68SRuslan Bukin reg = READ4(sc, OPERATION_MODE); 476*5d43fd68SRuslan Bukin reg |= (MODE_ST | MODE_SR); 477*5d43fd68SRuslan Bukin WRITE4(sc, OPERATION_MODE, reg); 478*5d43fd68SRuslan Bukin 479*5d43fd68SRuslan Bukin /* Enable transmitters */ 480*5d43fd68SRuslan Bukin reg = READ4(sc, MAC_CONFIGURATION); 481*5d43fd68SRuslan Bukin reg |= (CONF_JD | CONF_ACS | CONF_BE); 482*5d43fd68SRuslan Bukin reg |= (CONF_TE | CONF_RE); 483*5d43fd68SRuslan Bukin WRITE4(sc, MAC_CONFIGURATION, reg); 484*5d43fd68SRuslan Bukin 485*5d43fd68SRuslan Bukin /* 486*5d43fd68SRuslan Bukin * Call mii_mediachg() which will call back into dwc_miibus_statchg() 487*5d43fd68SRuslan Bukin * to set up the remaining config registers based on current media. 488*5d43fd68SRuslan Bukin */ 489*5d43fd68SRuslan Bukin mii_mediachg(sc->mii_softc); 490*5d43fd68SRuslan Bukin callout_reset(&sc->dwc_callout, hz, dwc_tick, sc); 491*5d43fd68SRuslan Bukin } 492*5d43fd68SRuslan Bukin 493*5d43fd68SRuslan Bukin static void 494*5d43fd68SRuslan Bukin dwc_init(void *if_softc) 495*5d43fd68SRuslan Bukin { 496*5d43fd68SRuslan Bukin struct dwc_softc *sc = if_softc; 497*5d43fd68SRuslan Bukin 498*5d43fd68SRuslan Bukin DWC_LOCK(sc); 499*5d43fd68SRuslan Bukin dwc_init_locked(sc); 500*5d43fd68SRuslan Bukin DWC_UNLOCK(sc); 501*5d43fd68SRuslan Bukin } 502*5d43fd68SRuslan Bukin 503*5d43fd68SRuslan Bukin inline static uint32_t 504*5d43fd68SRuslan Bukin dwc_setup_rxdesc(struct dwc_softc *sc, int idx, bus_addr_t paddr) 505*5d43fd68SRuslan Bukin { 506*5d43fd68SRuslan Bukin uint32_t nidx; 507*5d43fd68SRuslan Bukin 508*5d43fd68SRuslan Bukin sc->rxdesc_ring[idx].addr = (uint32_t)paddr; 509*5d43fd68SRuslan Bukin nidx = next_rxidx(sc, idx); 510*5d43fd68SRuslan Bukin sc->rxdesc_ring[idx].addr_next = sc->rxdesc_ring_paddr + \ 511*5d43fd68SRuslan Bukin (nidx * sizeof(struct dwc_hwdesc)); 512*5d43fd68SRuslan Bukin sc->rxdesc_ring[idx].tdes1 = DDESC_RDES1_CHAINED | MCLBYTES; 513*5d43fd68SRuslan Bukin 514*5d43fd68SRuslan Bukin wmb(); 515*5d43fd68SRuslan Bukin sc->rxdesc_ring[idx].tdes0 = DDESC_RDES0_OWN; 516*5d43fd68SRuslan Bukin wmb(); 517*5d43fd68SRuslan Bukin 518*5d43fd68SRuslan Bukin return (nidx); 519*5d43fd68SRuslan Bukin } 520*5d43fd68SRuslan Bukin 521*5d43fd68SRuslan Bukin static int 522*5d43fd68SRuslan Bukin dwc_setup_rxbuf(struct dwc_softc *sc, int idx, struct mbuf *m) 523*5d43fd68SRuslan Bukin { 524*5d43fd68SRuslan Bukin struct bus_dma_segment seg; 525*5d43fd68SRuslan Bukin int error, nsegs; 526*5d43fd68SRuslan Bukin 527*5d43fd68SRuslan Bukin m_adj(m, ETHER_ALIGN); 528*5d43fd68SRuslan Bukin 529*5d43fd68SRuslan Bukin error = bus_dmamap_load_mbuf_sg(sc->rxbuf_tag, sc->rxbuf_map[idx].map, 530*5d43fd68SRuslan Bukin m, &seg, &nsegs, 0); 531*5d43fd68SRuslan Bukin if (error != 0) { 532*5d43fd68SRuslan Bukin return (error); 533*5d43fd68SRuslan Bukin } 534*5d43fd68SRuslan Bukin 535*5d43fd68SRuslan Bukin KASSERT(nsegs == 1, ("%s: %d segments returned!", __func__, nsegs)); 536*5d43fd68SRuslan Bukin 537*5d43fd68SRuslan Bukin bus_dmamap_sync(sc->rxbuf_tag, sc->rxbuf_map[idx].map, 538*5d43fd68SRuslan Bukin BUS_DMASYNC_PREREAD); 539*5d43fd68SRuslan Bukin 540*5d43fd68SRuslan Bukin sc->rxbuf_map[idx].mbuf = m; 541*5d43fd68SRuslan Bukin dwc_setup_rxdesc(sc, idx, seg.ds_addr); 542*5d43fd68SRuslan Bukin 543*5d43fd68SRuslan Bukin return (0); 544*5d43fd68SRuslan Bukin } 545*5d43fd68SRuslan Bukin 546*5d43fd68SRuslan Bukin static struct mbuf * 547*5d43fd68SRuslan Bukin dwc_alloc_mbufcl(struct dwc_softc *sc) 548*5d43fd68SRuslan Bukin { 549*5d43fd68SRuslan Bukin struct mbuf *m; 550*5d43fd68SRuslan Bukin 551*5d43fd68SRuslan Bukin m = m_getcl(M_NOWAIT, MT_DATA, M_PKTHDR); 552*5d43fd68SRuslan Bukin m->m_pkthdr.len = m->m_len = m->m_ext.ext_size; 553*5d43fd68SRuslan Bukin 554*5d43fd68SRuslan Bukin return (m); 555*5d43fd68SRuslan Bukin } 556*5d43fd68SRuslan Bukin 557*5d43fd68SRuslan Bukin static void 558*5d43fd68SRuslan Bukin dwc_media_status(struct ifnet * ifp, struct ifmediareq *ifmr) 559*5d43fd68SRuslan Bukin { 560*5d43fd68SRuslan Bukin struct dwc_softc *sc; 561*5d43fd68SRuslan Bukin struct mii_data *mii; 562*5d43fd68SRuslan Bukin 563*5d43fd68SRuslan Bukin sc = ifp->if_softc; 564*5d43fd68SRuslan Bukin mii = sc->mii_softc; 565*5d43fd68SRuslan Bukin DWC_LOCK(sc); 566*5d43fd68SRuslan Bukin mii_pollstat(mii); 567*5d43fd68SRuslan Bukin ifmr->ifm_active = mii->mii_media_active; 568*5d43fd68SRuslan Bukin ifmr->ifm_status = mii->mii_media_status; 569*5d43fd68SRuslan Bukin DWC_UNLOCK(sc); 570*5d43fd68SRuslan Bukin } 571*5d43fd68SRuslan Bukin 572*5d43fd68SRuslan Bukin static int 573*5d43fd68SRuslan Bukin dwc_media_change_locked(struct dwc_softc *sc) 574*5d43fd68SRuslan Bukin { 575*5d43fd68SRuslan Bukin 576*5d43fd68SRuslan Bukin return (mii_mediachg(sc->mii_softc)); 577*5d43fd68SRuslan Bukin } 578*5d43fd68SRuslan Bukin 579*5d43fd68SRuslan Bukin static int 580*5d43fd68SRuslan Bukin dwc_media_change(struct ifnet * ifp) 581*5d43fd68SRuslan Bukin { 582*5d43fd68SRuslan Bukin struct dwc_softc *sc; 583*5d43fd68SRuslan Bukin int error; 584*5d43fd68SRuslan Bukin 585*5d43fd68SRuslan Bukin sc = ifp->if_softc; 586*5d43fd68SRuslan Bukin 587*5d43fd68SRuslan Bukin DWC_LOCK(sc); 588*5d43fd68SRuslan Bukin error = dwc_media_change_locked(sc); 589*5d43fd68SRuslan Bukin DWC_UNLOCK(sc); 590*5d43fd68SRuslan Bukin return (error); 591*5d43fd68SRuslan Bukin } 592*5d43fd68SRuslan Bukin 593*5d43fd68SRuslan Bukin static const uint8_t nibbletab[] = { 594*5d43fd68SRuslan Bukin /* 0x0 0000 -> 0000 */ 0x0, 595*5d43fd68SRuslan Bukin /* 0x1 0001 -> 1000 */ 0x8, 596*5d43fd68SRuslan Bukin /* 0x2 0010 -> 0100 */ 0x4, 597*5d43fd68SRuslan Bukin /* 0x3 0011 -> 1100 */ 0xc, 598*5d43fd68SRuslan Bukin /* 0x4 0100 -> 0010 */ 0x2, 599*5d43fd68SRuslan Bukin /* 0x5 0101 -> 1010 */ 0xa, 600*5d43fd68SRuslan Bukin /* 0x6 0110 -> 0110 */ 0x6, 601*5d43fd68SRuslan Bukin /* 0x7 0111 -> 1110 */ 0xe, 602*5d43fd68SRuslan Bukin /* 0x8 1000 -> 0001 */ 0x1, 603*5d43fd68SRuslan Bukin /* 0x9 1001 -> 1001 */ 0x9, 604*5d43fd68SRuslan Bukin /* 0xa 1010 -> 0101 */ 0x5, 605*5d43fd68SRuslan Bukin /* 0xb 1011 -> 1101 */ 0xd, 606*5d43fd68SRuslan Bukin /* 0xc 1100 -> 0011 */ 0x3, 607*5d43fd68SRuslan Bukin /* 0xd 1101 -> 1011 */ 0xb, 608*5d43fd68SRuslan Bukin /* 0xe 1110 -> 0111 */ 0x7, 609*5d43fd68SRuslan Bukin /* 0xf 1111 -> 1111 */ 0xf, }; 610*5d43fd68SRuslan Bukin 611*5d43fd68SRuslan Bukin static uint8_t 612*5d43fd68SRuslan Bukin bitreverse(uint8_t x) 613*5d43fd68SRuslan Bukin { 614*5d43fd68SRuslan Bukin 615*5d43fd68SRuslan Bukin return (nibbletab[x & 0xf] << 4) | nibbletab[x >> 4]; 616*5d43fd68SRuslan Bukin } 617*5d43fd68SRuslan Bukin 618*5d43fd68SRuslan Bukin static void 619*5d43fd68SRuslan Bukin dwc_setup_rxfilter(struct dwc_softc *sc) 620*5d43fd68SRuslan Bukin { 621*5d43fd68SRuslan Bukin struct ifmultiaddr *ifma; 622*5d43fd68SRuslan Bukin struct ifnet *ifp; 623*5d43fd68SRuslan Bukin uint8_t *eaddr; 624*5d43fd68SRuslan Bukin uint32_t crc; 625*5d43fd68SRuslan Bukin uint8_t val; 626*5d43fd68SRuslan Bukin int hashbit; 627*5d43fd68SRuslan Bukin int hashreg; 628*5d43fd68SRuslan Bukin int ffval; 629*5d43fd68SRuslan Bukin int reg; 630*5d43fd68SRuslan Bukin int lo; 631*5d43fd68SRuslan Bukin int hi; 632*5d43fd68SRuslan Bukin 633*5d43fd68SRuslan Bukin DWC_ASSERT_LOCKED(sc); 634*5d43fd68SRuslan Bukin 635*5d43fd68SRuslan Bukin ifp = sc->ifp; 636*5d43fd68SRuslan Bukin 637*5d43fd68SRuslan Bukin /* 638*5d43fd68SRuslan Bukin * Set the multicast (group) filter hash. 639*5d43fd68SRuslan Bukin */ 640*5d43fd68SRuslan Bukin if ((ifp->if_flags & IFF_ALLMULTI)) 641*5d43fd68SRuslan Bukin ffval = (FRAME_FILTER_PM); 642*5d43fd68SRuslan Bukin else { 643*5d43fd68SRuslan Bukin ffval = (FRAME_FILTER_HMC); 644*5d43fd68SRuslan Bukin if_maddr_rlock(ifp); 645*5d43fd68SRuslan Bukin TAILQ_FOREACH(ifma, &sc->ifp->if_multiaddrs, ifma_link) { 646*5d43fd68SRuslan Bukin if (ifma->ifma_addr->sa_family != AF_LINK) 647*5d43fd68SRuslan Bukin continue; 648*5d43fd68SRuslan Bukin crc = ether_crc32_le(LLADDR((struct sockaddr_dl *) 649*5d43fd68SRuslan Bukin ifma->ifma_addr), ETHER_ADDR_LEN); 650*5d43fd68SRuslan Bukin 651*5d43fd68SRuslan Bukin /* Take lower 8 bits and reverse it */ 652*5d43fd68SRuslan Bukin val = bitreverse(~crc & 0xff); 653*5d43fd68SRuslan Bukin hashreg = (val >> 5); 654*5d43fd68SRuslan Bukin hashbit = (val & 31); 655*5d43fd68SRuslan Bukin 656*5d43fd68SRuslan Bukin reg = READ4(sc, HASH_TABLE_REG(hashreg)); 657*5d43fd68SRuslan Bukin reg |= (1 << hashbit); 658*5d43fd68SRuslan Bukin WRITE4(sc, HASH_TABLE_REG(hashreg), reg); 659*5d43fd68SRuslan Bukin } 660*5d43fd68SRuslan Bukin if_maddr_runlock(ifp); 661*5d43fd68SRuslan Bukin } 662*5d43fd68SRuslan Bukin 663*5d43fd68SRuslan Bukin /* 664*5d43fd68SRuslan Bukin * Set the individual address filter hash. 665*5d43fd68SRuslan Bukin */ 666*5d43fd68SRuslan Bukin if (ifp->if_flags & IFF_PROMISC) 667*5d43fd68SRuslan Bukin ffval |= (FRAME_FILTER_PR); 668*5d43fd68SRuslan Bukin 669*5d43fd68SRuslan Bukin /* 670*5d43fd68SRuslan Bukin * Set the primary address. 671*5d43fd68SRuslan Bukin */ 672*5d43fd68SRuslan Bukin eaddr = IF_LLADDR(ifp); 673*5d43fd68SRuslan Bukin lo = eaddr[0] | (eaddr[1] << 8) | (eaddr[2] << 16) | 674*5d43fd68SRuslan Bukin (eaddr[3] << 24); 675*5d43fd68SRuslan Bukin hi = eaddr[4] | (eaddr[5] << 8); 676*5d43fd68SRuslan Bukin WRITE4(sc, MAC_ADDRESS_LOW(0), lo); 677*5d43fd68SRuslan Bukin WRITE4(sc, MAC_ADDRESS_HIGH(0), hi); 678*5d43fd68SRuslan Bukin WRITE4(sc, MAC_FRAME_FILTER, ffval); 679*5d43fd68SRuslan Bukin } 680*5d43fd68SRuslan Bukin 681*5d43fd68SRuslan Bukin static int 682*5d43fd68SRuslan Bukin dwc_ioctl(struct ifnet *ifp, u_long cmd, caddr_t data) 683*5d43fd68SRuslan Bukin { 684*5d43fd68SRuslan Bukin struct dwc_softc *sc; 685*5d43fd68SRuslan Bukin struct mii_data *mii; 686*5d43fd68SRuslan Bukin struct ifreq *ifr; 687*5d43fd68SRuslan Bukin int mask, error; 688*5d43fd68SRuslan Bukin 689*5d43fd68SRuslan Bukin sc = ifp->if_softc; 690*5d43fd68SRuslan Bukin ifr = (struct ifreq *)data; 691*5d43fd68SRuslan Bukin 692*5d43fd68SRuslan Bukin error = 0; 693*5d43fd68SRuslan Bukin switch (cmd) { 694*5d43fd68SRuslan Bukin case SIOCSIFFLAGS: 695*5d43fd68SRuslan Bukin DWC_LOCK(sc); 696*5d43fd68SRuslan Bukin if (ifp->if_flags & IFF_UP) { 697*5d43fd68SRuslan Bukin if (ifp->if_drv_flags & IFF_DRV_RUNNING) { 698*5d43fd68SRuslan Bukin if ((ifp->if_flags ^ sc->if_flags) & 699*5d43fd68SRuslan Bukin (IFF_PROMISC | IFF_ALLMULTI)) 700*5d43fd68SRuslan Bukin dwc_setup_rxfilter(sc); 701*5d43fd68SRuslan Bukin } else { 702*5d43fd68SRuslan Bukin if (!sc->is_detaching) 703*5d43fd68SRuslan Bukin dwc_init_locked(sc); 704*5d43fd68SRuslan Bukin } 705*5d43fd68SRuslan Bukin } else { 706*5d43fd68SRuslan Bukin if (ifp->if_drv_flags & IFF_DRV_RUNNING) 707*5d43fd68SRuslan Bukin dwc_stop_locked(sc); 708*5d43fd68SRuslan Bukin } 709*5d43fd68SRuslan Bukin sc->if_flags = ifp->if_flags; 710*5d43fd68SRuslan Bukin DWC_UNLOCK(sc); 711*5d43fd68SRuslan Bukin break; 712*5d43fd68SRuslan Bukin case SIOCADDMULTI: 713*5d43fd68SRuslan Bukin case SIOCDELMULTI: 714*5d43fd68SRuslan Bukin if (ifp->if_drv_flags & IFF_DRV_RUNNING) { 715*5d43fd68SRuslan Bukin DWC_LOCK(sc); 716*5d43fd68SRuslan Bukin dwc_setup_rxfilter(sc); 717*5d43fd68SRuslan Bukin DWC_UNLOCK(sc); 718*5d43fd68SRuslan Bukin } 719*5d43fd68SRuslan Bukin break; 720*5d43fd68SRuslan Bukin case SIOCSIFMEDIA: 721*5d43fd68SRuslan Bukin case SIOCGIFMEDIA: 722*5d43fd68SRuslan Bukin mii = sc->mii_softc; 723*5d43fd68SRuslan Bukin error = ifmedia_ioctl(ifp, ifr, &mii->mii_media, cmd); 724*5d43fd68SRuslan Bukin break; 725*5d43fd68SRuslan Bukin case SIOCSIFCAP: 726*5d43fd68SRuslan Bukin mask = ifp->if_capenable ^ ifr->ifr_reqcap; 727*5d43fd68SRuslan Bukin if (mask & IFCAP_VLAN_MTU) { 728*5d43fd68SRuslan Bukin /* No work to do except acknowledge the change took */ 729*5d43fd68SRuslan Bukin ifp->if_capenable ^= IFCAP_VLAN_MTU; 730*5d43fd68SRuslan Bukin } 731*5d43fd68SRuslan Bukin break; 732*5d43fd68SRuslan Bukin 733*5d43fd68SRuslan Bukin default: 734*5d43fd68SRuslan Bukin error = ether_ioctl(ifp, cmd, data); 735*5d43fd68SRuslan Bukin break; 736*5d43fd68SRuslan Bukin } 737*5d43fd68SRuslan Bukin 738*5d43fd68SRuslan Bukin return (error); 739*5d43fd68SRuslan Bukin } 740*5d43fd68SRuslan Bukin 741*5d43fd68SRuslan Bukin static void 742*5d43fd68SRuslan Bukin dwc_txfinish_locked(struct dwc_softc *sc) 743*5d43fd68SRuslan Bukin { 744*5d43fd68SRuslan Bukin struct dwc_bufmap *bmap; 745*5d43fd68SRuslan Bukin struct dwc_hwdesc *desc; 746*5d43fd68SRuslan Bukin struct ifnet *ifp; 747*5d43fd68SRuslan Bukin 748*5d43fd68SRuslan Bukin DWC_ASSERT_LOCKED(sc); 749*5d43fd68SRuslan Bukin 750*5d43fd68SRuslan Bukin ifp = sc->ifp; 751*5d43fd68SRuslan Bukin 752*5d43fd68SRuslan Bukin while (sc->tx_idx_tail != sc->tx_idx_head) { 753*5d43fd68SRuslan Bukin desc = &sc->txdesc_ring[sc->tx_idx_tail]; 754*5d43fd68SRuslan Bukin if ((desc->tdes0 & DDESC_TDES0_OWN) != 0) 755*5d43fd68SRuslan Bukin break; 756*5d43fd68SRuslan Bukin bmap = &sc->txbuf_map[sc->tx_idx_tail]; 757*5d43fd68SRuslan Bukin bus_dmamap_sync(sc->txbuf_tag, bmap->map, 758*5d43fd68SRuslan Bukin BUS_DMASYNC_POSTWRITE); 759*5d43fd68SRuslan Bukin bus_dmamap_unload(sc->txbuf_tag, bmap->map); 760*5d43fd68SRuslan Bukin m_freem(bmap->mbuf); 761*5d43fd68SRuslan Bukin bmap->mbuf = NULL; 762*5d43fd68SRuslan Bukin dwc_setup_txdesc(sc, sc->tx_idx_tail, 0, 0); 763*5d43fd68SRuslan Bukin sc->tx_idx_tail = next_txidx(sc, sc->tx_idx_tail); 764*5d43fd68SRuslan Bukin } 765*5d43fd68SRuslan Bukin 766*5d43fd68SRuslan Bukin /* If there are no buffers outstanding, muzzle the watchdog. */ 767*5d43fd68SRuslan Bukin if (sc->tx_idx_tail == sc->tx_idx_head) { 768*5d43fd68SRuslan Bukin sc->tx_watchdog_count = 0; 769*5d43fd68SRuslan Bukin } 770*5d43fd68SRuslan Bukin } 771*5d43fd68SRuslan Bukin 772*5d43fd68SRuslan Bukin static void 773*5d43fd68SRuslan Bukin dwc_rxfinish_locked(struct dwc_softc *sc) 774*5d43fd68SRuslan Bukin { 775*5d43fd68SRuslan Bukin struct ifnet *ifp; 776*5d43fd68SRuslan Bukin struct mbuf *m0; 777*5d43fd68SRuslan Bukin struct mbuf *m; 778*5d43fd68SRuslan Bukin int error; 779*5d43fd68SRuslan Bukin int rdes0; 780*5d43fd68SRuslan Bukin int idx; 781*5d43fd68SRuslan Bukin int len; 782*5d43fd68SRuslan Bukin 783*5d43fd68SRuslan Bukin ifp = sc->ifp; 784*5d43fd68SRuslan Bukin 785*5d43fd68SRuslan Bukin for (;;) { 786*5d43fd68SRuslan Bukin idx = sc->rx_idx; 787*5d43fd68SRuslan Bukin 788*5d43fd68SRuslan Bukin rdes0 = sc->rxdesc_ring[idx].tdes0; 789*5d43fd68SRuslan Bukin if ((rdes0 & DDESC_RDES0_OWN) != 0) 790*5d43fd68SRuslan Bukin break; 791*5d43fd68SRuslan Bukin 792*5d43fd68SRuslan Bukin bus_dmamap_sync(sc->rxbuf_tag, sc->rxbuf_map[idx].map, 793*5d43fd68SRuslan Bukin BUS_DMASYNC_POSTREAD); 794*5d43fd68SRuslan Bukin bus_dmamap_unload(sc->rxbuf_tag, sc->rxbuf_map[idx].map); 795*5d43fd68SRuslan Bukin 796*5d43fd68SRuslan Bukin len = (rdes0 >> DDESC_RDES0_FL_SHIFT) & DDESC_RDES0_FL_MASK; 797*5d43fd68SRuslan Bukin if (len != 0) { 798*5d43fd68SRuslan Bukin m = sc->rxbuf_map[idx].mbuf; 799*5d43fd68SRuslan Bukin m->m_pkthdr.rcvif = ifp; 800*5d43fd68SRuslan Bukin m->m_pkthdr.len = len; 801*5d43fd68SRuslan Bukin m->m_len = len; 802*5d43fd68SRuslan Bukin ifp->if_ipackets++; 803*5d43fd68SRuslan Bukin 804*5d43fd68SRuslan Bukin DWC_UNLOCK(sc); 805*5d43fd68SRuslan Bukin (*ifp->if_input)(ifp, m); 806*5d43fd68SRuslan Bukin DWC_LOCK(sc); 807*5d43fd68SRuslan Bukin } else { 808*5d43fd68SRuslan Bukin /* XXX Zero-length packet ? */ 809*5d43fd68SRuslan Bukin } 810*5d43fd68SRuslan Bukin 811*5d43fd68SRuslan Bukin if ((m0 = dwc_alloc_mbufcl(sc)) != NULL) { 812*5d43fd68SRuslan Bukin if ((error = dwc_setup_rxbuf(sc, idx, m0)) != 0) { 813*5d43fd68SRuslan Bukin /* 814*5d43fd68SRuslan Bukin * XXX Now what? 815*5d43fd68SRuslan Bukin * We've got a hole in the rx ring. 816*5d43fd68SRuslan Bukin */ 817*5d43fd68SRuslan Bukin } 818*5d43fd68SRuslan Bukin } else 819*5d43fd68SRuslan Bukin if_inc_counter(sc->ifp, IFCOUNTER_IQDROPS, 1); 820*5d43fd68SRuslan Bukin 821*5d43fd68SRuslan Bukin sc->rx_idx = next_rxidx(sc, sc->rx_idx); 822*5d43fd68SRuslan Bukin } 823*5d43fd68SRuslan Bukin } 824*5d43fd68SRuslan Bukin 825*5d43fd68SRuslan Bukin static void 826*5d43fd68SRuslan Bukin dwc_intr(void *arg) 827*5d43fd68SRuslan Bukin { 828*5d43fd68SRuslan Bukin struct dwc_softc *sc; 829*5d43fd68SRuslan Bukin uint32_t reg; 830*5d43fd68SRuslan Bukin 831*5d43fd68SRuslan Bukin sc = arg; 832*5d43fd68SRuslan Bukin 833*5d43fd68SRuslan Bukin DWC_LOCK(sc); 834*5d43fd68SRuslan Bukin 835*5d43fd68SRuslan Bukin reg = READ4(sc, INTERRUPT_STATUS); 836*5d43fd68SRuslan Bukin if (reg) { 837*5d43fd68SRuslan Bukin mii_mediachg(sc->mii_softc); 838*5d43fd68SRuslan Bukin READ4(sc, SGMII_RGMII_SMII_CTRL_STATUS); 839*5d43fd68SRuslan Bukin } 840*5d43fd68SRuslan Bukin 841*5d43fd68SRuslan Bukin reg = READ4(sc, DMA_STATUS); 842*5d43fd68SRuslan Bukin if (reg & DMA_STATUS_NIS) { 843*5d43fd68SRuslan Bukin if (reg & DMA_STATUS_RI) 844*5d43fd68SRuslan Bukin dwc_rxfinish_locked(sc); 845*5d43fd68SRuslan Bukin 846*5d43fd68SRuslan Bukin if (reg & DMA_STATUS_TI) 847*5d43fd68SRuslan Bukin dwc_txfinish_locked(sc); 848*5d43fd68SRuslan Bukin } 849*5d43fd68SRuslan Bukin 850*5d43fd68SRuslan Bukin if (reg & DMA_STATUS_AIS) { 851*5d43fd68SRuslan Bukin if (reg & DMA_STATUS_FBI) { 852*5d43fd68SRuslan Bukin /* Fatal bus error */ 853*5d43fd68SRuslan Bukin device_printf(sc->dev, 854*5d43fd68SRuslan Bukin "Ethernet DMA error, restarting controller.\n"); 855*5d43fd68SRuslan Bukin dwc_stop_locked(sc); 856*5d43fd68SRuslan Bukin dwc_init_locked(sc); 857*5d43fd68SRuslan Bukin } 858*5d43fd68SRuslan Bukin } 859*5d43fd68SRuslan Bukin 860*5d43fd68SRuslan Bukin WRITE4(sc, DMA_STATUS, reg & DMA_STATUS_INTR_MASK); 861*5d43fd68SRuslan Bukin DWC_UNLOCK(sc); 862*5d43fd68SRuslan Bukin } 863*5d43fd68SRuslan Bukin 864*5d43fd68SRuslan Bukin static int 865*5d43fd68SRuslan Bukin setup_dma(struct dwc_softc *sc) 866*5d43fd68SRuslan Bukin { 867*5d43fd68SRuslan Bukin struct mbuf *m; 868*5d43fd68SRuslan Bukin int error; 869*5d43fd68SRuslan Bukin int nidx; 870*5d43fd68SRuslan Bukin int idx; 871*5d43fd68SRuslan Bukin 872*5d43fd68SRuslan Bukin /* 873*5d43fd68SRuslan Bukin * Set up TX descriptor ring, descriptors, and dma maps. 874*5d43fd68SRuslan Bukin */ 875*5d43fd68SRuslan Bukin error = bus_dma_tag_create( 876*5d43fd68SRuslan Bukin bus_get_dma_tag(sc->dev), /* Parent tag. */ 877*5d43fd68SRuslan Bukin DWC_DESC_RING_ALIGN, 0, /* alignment, boundary */ 878*5d43fd68SRuslan Bukin BUS_SPACE_MAXADDR_32BIT, /* lowaddr */ 879*5d43fd68SRuslan Bukin BUS_SPACE_MAXADDR, /* highaddr */ 880*5d43fd68SRuslan Bukin NULL, NULL, /* filter, filterarg */ 881*5d43fd68SRuslan Bukin TX_DESC_SIZE, 1, /* maxsize, nsegments */ 882*5d43fd68SRuslan Bukin TX_DESC_SIZE, /* maxsegsize */ 883*5d43fd68SRuslan Bukin 0, /* flags */ 884*5d43fd68SRuslan Bukin NULL, NULL, /* lockfunc, lockarg */ 885*5d43fd68SRuslan Bukin &sc->txdesc_tag); 886*5d43fd68SRuslan Bukin if (error != 0) { 887*5d43fd68SRuslan Bukin device_printf(sc->dev, 888*5d43fd68SRuslan Bukin "could not create TX ring DMA tag.\n"); 889*5d43fd68SRuslan Bukin goto out; 890*5d43fd68SRuslan Bukin } 891*5d43fd68SRuslan Bukin 892*5d43fd68SRuslan Bukin error = bus_dmamem_alloc(sc->txdesc_tag, (void**)&sc->txdesc_ring, 893*5d43fd68SRuslan Bukin BUS_DMA_COHERENT | BUS_DMA_WAITOK | BUS_DMA_ZERO, 894*5d43fd68SRuslan Bukin &sc->txdesc_map); 895*5d43fd68SRuslan Bukin if (error != 0) { 896*5d43fd68SRuslan Bukin device_printf(sc->dev, 897*5d43fd68SRuslan Bukin "could not allocate TX descriptor ring.\n"); 898*5d43fd68SRuslan Bukin goto out; 899*5d43fd68SRuslan Bukin } 900*5d43fd68SRuslan Bukin 901*5d43fd68SRuslan Bukin error = bus_dmamap_load(sc->txdesc_tag, sc->txdesc_map, 902*5d43fd68SRuslan Bukin sc->txdesc_ring, TX_DESC_SIZE, dwc_get1paddr, 903*5d43fd68SRuslan Bukin &sc->txdesc_ring_paddr, 0); 904*5d43fd68SRuslan Bukin if (error != 0) { 905*5d43fd68SRuslan Bukin device_printf(sc->dev, 906*5d43fd68SRuslan Bukin "could not load TX descriptor ring map.\n"); 907*5d43fd68SRuslan Bukin goto out; 908*5d43fd68SRuslan Bukin } 909*5d43fd68SRuslan Bukin 910*5d43fd68SRuslan Bukin for (idx = 0; idx < TX_DESC_COUNT; idx++) { 911*5d43fd68SRuslan Bukin sc->txdesc_ring[idx].tdes0 = DDESC_TDES0_TXCHAIN; 912*5d43fd68SRuslan Bukin sc->txdesc_ring[idx].tdes1 = 0; 913*5d43fd68SRuslan Bukin nidx = next_txidx(sc, idx); 914*5d43fd68SRuslan Bukin sc->txdesc_ring[idx].addr_next = sc->txdesc_ring_paddr + \ 915*5d43fd68SRuslan Bukin (nidx * sizeof(struct dwc_hwdesc)); 916*5d43fd68SRuslan Bukin } 917*5d43fd68SRuslan Bukin 918*5d43fd68SRuslan Bukin error = bus_dma_tag_create( 919*5d43fd68SRuslan Bukin bus_get_dma_tag(sc->dev), /* Parent tag. */ 920*5d43fd68SRuslan Bukin 1, 0, /* alignment, boundary */ 921*5d43fd68SRuslan Bukin BUS_SPACE_MAXADDR_32BIT, /* lowaddr */ 922*5d43fd68SRuslan Bukin BUS_SPACE_MAXADDR, /* highaddr */ 923*5d43fd68SRuslan Bukin NULL, NULL, /* filter, filterarg */ 924*5d43fd68SRuslan Bukin MCLBYTES, 1, /* maxsize, nsegments */ 925*5d43fd68SRuslan Bukin MCLBYTES, /* maxsegsize */ 926*5d43fd68SRuslan Bukin 0, /* flags */ 927*5d43fd68SRuslan Bukin NULL, NULL, /* lockfunc, lockarg */ 928*5d43fd68SRuslan Bukin &sc->txbuf_tag); 929*5d43fd68SRuslan Bukin if (error != 0) { 930*5d43fd68SRuslan Bukin device_printf(sc->dev, 931*5d43fd68SRuslan Bukin "could not create TX ring DMA tag.\n"); 932*5d43fd68SRuslan Bukin goto out; 933*5d43fd68SRuslan Bukin } 934*5d43fd68SRuslan Bukin 935*5d43fd68SRuslan Bukin for (idx = 0; idx < TX_DESC_COUNT; idx++) { 936*5d43fd68SRuslan Bukin error = bus_dmamap_create(sc->txbuf_tag, BUS_DMA_COHERENT, 937*5d43fd68SRuslan Bukin &sc->txbuf_map[idx].map); 938*5d43fd68SRuslan Bukin if (error != 0) { 939*5d43fd68SRuslan Bukin device_printf(sc->dev, 940*5d43fd68SRuslan Bukin "could not create TX buffer DMA map.\n"); 941*5d43fd68SRuslan Bukin goto out; 942*5d43fd68SRuslan Bukin } 943*5d43fd68SRuslan Bukin dwc_setup_txdesc(sc, idx, 0, 0); 944*5d43fd68SRuslan Bukin } 945*5d43fd68SRuslan Bukin 946*5d43fd68SRuslan Bukin /* 947*5d43fd68SRuslan Bukin * Set up RX descriptor ring, descriptors, dma maps, and mbufs. 948*5d43fd68SRuslan Bukin */ 949*5d43fd68SRuslan Bukin error = bus_dma_tag_create( 950*5d43fd68SRuslan Bukin bus_get_dma_tag(sc->dev), /* Parent tag. */ 951*5d43fd68SRuslan Bukin DWC_DESC_RING_ALIGN, 0, /* alignment, boundary */ 952*5d43fd68SRuslan Bukin BUS_SPACE_MAXADDR_32BIT, /* lowaddr */ 953*5d43fd68SRuslan Bukin BUS_SPACE_MAXADDR, /* highaddr */ 954*5d43fd68SRuslan Bukin NULL, NULL, /* filter, filterarg */ 955*5d43fd68SRuslan Bukin RX_DESC_SIZE, 1, /* maxsize, nsegments */ 956*5d43fd68SRuslan Bukin RX_DESC_SIZE, /* maxsegsize */ 957*5d43fd68SRuslan Bukin 0, /* flags */ 958*5d43fd68SRuslan Bukin NULL, NULL, /* lockfunc, lockarg */ 959*5d43fd68SRuslan Bukin &sc->rxdesc_tag); 960*5d43fd68SRuslan Bukin if (error != 0) { 961*5d43fd68SRuslan Bukin device_printf(sc->dev, 962*5d43fd68SRuslan Bukin "could not create RX ring DMA tag.\n"); 963*5d43fd68SRuslan Bukin goto out; 964*5d43fd68SRuslan Bukin } 965*5d43fd68SRuslan Bukin 966*5d43fd68SRuslan Bukin error = bus_dmamem_alloc(sc->rxdesc_tag, (void **)&sc->rxdesc_ring, 967*5d43fd68SRuslan Bukin BUS_DMA_COHERENT | BUS_DMA_WAITOK | BUS_DMA_ZERO, 968*5d43fd68SRuslan Bukin &sc->rxdesc_map); 969*5d43fd68SRuslan Bukin if (error != 0) { 970*5d43fd68SRuslan Bukin device_printf(sc->dev, 971*5d43fd68SRuslan Bukin "could not allocate RX descriptor ring.\n"); 972*5d43fd68SRuslan Bukin goto out; 973*5d43fd68SRuslan Bukin } 974*5d43fd68SRuslan Bukin 975*5d43fd68SRuslan Bukin error = bus_dmamap_load(sc->rxdesc_tag, sc->rxdesc_map, 976*5d43fd68SRuslan Bukin sc->rxdesc_ring, RX_DESC_SIZE, dwc_get1paddr, 977*5d43fd68SRuslan Bukin &sc->rxdesc_ring_paddr, 0); 978*5d43fd68SRuslan Bukin if (error != 0) { 979*5d43fd68SRuslan Bukin device_printf(sc->dev, 980*5d43fd68SRuslan Bukin "could not load RX descriptor ring map.\n"); 981*5d43fd68SRuslan Bukin goto out; 982*5d43fd68SRuslan Bukin } 983*5d43fd68SRuslan Bukin 984*5d43fd68SRuslan Bukin error = bus_dma_tag_create( 985*5d43fd68SRuslan Bukin bus_get_dma_tag(sc->dev), /* Parent tag. */ 986*5d43fd68SRuslan Bukin 1, 0, /* alignment, boundary */ 987*5d43fd68SRuslan Bukin BUS_SPACE_MAXADDR_32BIT, /* lowaddr */ 988*5d43fd68SRuslan Bukin BUS_SPACE_MAXADDR, /* highaddr */ 989*5d43fd68SRuslan Bukin NULL, NULL, /* filter, filterarg */ 990*5d43fd68SRuslan Bukin MCLBYTES, 1, /* maxsize, nsegments */ 991*5d43fd68SRuslan Bukin MCLBYTES, /* maxsegsize */ 992*5d43fd68SRuslan Bukin 0, /* flags */ 993*5d43fd68SRuslan Bukin NULL, NULL, /* lockfunc, lockarg */ 994*5d43fd68SRuslan Bukin &sc->rxbuf_tag); 995*5d43fd68SRuslan Bukin if (error != 0) { 996*5d43fd68SRuslan Bukin device_printf(sc->dev, 997*5d43fd68SRuslan Bukin "could not create RX buf DMA tag.\n"); 998*5d43fd68SRuslan Bukin goto out; 999*5d43fd68SRuslan Bukin } 1000*5d43fd68SRuslan Bukin 1001*5d43fd68SRuslan Bukin for (idx = 0; idx < RX_DESC_COUNT; idx++) { 1002*5d43fd68SRuslan Bukin error = bus_dmamap_create(sc->rxbuf_tag, BUS_DMA_COHERENT, 1003*5d43fd68SRuslan Bukin &sc->rxbuf_map[idx].map); 1004*5d43fd68SRuslan Bukin if (error != 0) { 1005*5d43fd68SRuslan Bukin device_printf(sc->dev, 1006*5d43fd68SRuslan Bukin "could not create RX buffer DMA map.\n"); 1007*5d43fd68SRuslan Bukin goto out; 1008*5d43fd68SRuslan Bukin } 1009*5d43fd68SRuslan Bukin if ((m = dwc_alloc_mbufcl(sc)) == NULL) { 1010*5d43fd68SRuslan Bukin device_printf(sc->dev, "Could not alloc mbuf\n"); 1011*5d43fd68SRuslan Bukin error = ENOMEM; 1012*5d43fd68SRuslan Bukin goto out; 1013*5d43fd68SRuslan Bukin } 1014*5d43fd68SRuslan Bukin if ((error = dwc_setup_rxbuf(sc, idx, m)) != 0) { 1015*5d43fd68SRuslan Bukin device_printf(sc->dev, 1016*5d43fd68SRuslan Bukin "could not create new RX buffer.\n"); 1017*5d43fd68SRuslan Bukin goto out; 1018*5d43fd68SRuslan Bukin } 1019*5d43fd68SRuslan Bukin } 1020*5d43fd68SRuslan Bukin 1021*5d43fd68SRuslan Bukin out: 1022*5d43fd68SRuslan Bukin if (error != 0) 1023*5d43fd68SRuslan Bukin return (ENXIO); 1024*5d43fd68SRuslan Bukin 1025*5d43fd68SRuslan Bukin return (0); 1026*5d43fd68SRuslan Bukin } 1027*5d43fd68SRuslan Bukin 1028*5d43fd68SRuslan Bukin static int 1029*5d43fd68SRuslan Bukin dwc_get_hwaddr(struct dwc_softc *sc, uint8_t *hwaddr) 1030*5d43fd68SRuslan Bukin { 1031*5d43fd68SRuslan Bukin int rnd; 1032*5d43fd68SRuslan Bukin int lo; 1033*5d43fd68SRuslan Bukin int hi; 1034*5d43fd68SRuslan Bukin 1035*5d43fd68SRuslan Bukin /* 1036*5d43fd68SRuslan Bukin * Try to recover a MAC address from the running hardware. If there's 1037*5d43fd68SRuslan Bukin * something non-zero there, assume the bootloader did the right thing 1038*5d43fd68SRuslan Bukin * and just use it. 1039*5d43fd68SRuslan Bukin * 1040*5d43fd68SRuslan Bukin * Otherwise, set the address to a convenient locally assigned address, 1041*5d43fd68SRuslan Bukin * 'bsd' + random 24 low-order bits. 'b' is 0x62, which has the locally 1042*5d43fd68SRuslan Bukin * assigned bit set, and the broadcast/multicast bit clear. 1043*5d43fd68SRuslan Bukin */ 1044*5d43fd68SRuslan Bukin lo = READ4(sc, MAC_ADDRESS_LOW(0)); 1045*5d43fd68SRuslan Bukin hi = READ4(sc, MAC_ADDRESS_HIGH(0)) & 0xffff; 1046*5d43fd68SRuslan Bukin if ((lo != 0xffffffff) || (hi != 0xffff)) { 1047*5d43fd68SRuslan Bukin hwaddr[0] = (lo >> 0) & 0xff; 1048*5d43fd68SRuslan Bukin hwaddr[1] = (lo >> 8) & 0xff; 1049*5d43fd68SRuslan Bukin hwaddr[2] = (lo >> 16) & 0xff; 1050*5d43fd68SRuslan Bukin hwaddr[3] = (lo >> 24) & 0xff; 1051*5d43fd68SRuslan Bukin hwaddr[4] = (hi >> 0) & 0xff; 1052*5d43fd68SRuslan Bukin hwaddr[5] = (hi >> 8) & 0xff; 1053*5d43fd68SRuslan Bukin } else { 1054*5d43fd68SRuslan Bukin rnd = arc4random() & 0x00ffffff; 1055*5d43fd68SRuslan Bukin hwaddr[0] = 'b'; 1056*5d43fd68SRuslan Bukin hwaddr[1] = 's'; 1057*5d43fd68SRuslan Bukin hwaddr[2] = 'd'; 1058*5d43fd68SRuslan Bukin hwaddr[3] = rnd >> 16; 1059*5d43fd68SRuslan Bukin hwaddr[4] = rnd >> 8; 1060*5d43fd68SRuslan Bukin hwaddr[5] = rnd >> 0; 1061*5d43fd68SRuslan Bukin } 1062*5d43fd68SRuslan Bukin 1063*5d43fd68SRuslan Bukin return (0); 1064*5d43fd68SRuslan Bukin } 1065*5d43fd68SRuslan Bukin 1066*5d43fd68SRuslan Bukin static int 1067*5d43fd68SRuslan Bukin dwc_probe(device_t dev) 1068*5d43fd68SRuslan Bukin { 1069*5d43fd68SRuslan Bukin 1070*5d43fd68SRuslan Bukin if (!ofw_bus_status_okay(dev)) 1071*5d43fd68SRuslan Bukin return (ENXIO); 1072*5d43fd68SRuslan Bukin 1073*5d43fd68SRuslan Bukin if (!ofw_bus_is_compatible(dev, "snps,dwmac")) 1074*5d43fd68SRuslan Bukin return (ENXIO); 1075*5d43fd68SRuslan Bukin 1076*5d43fd68SRuslan Bukin device_set_desc(dev, "Gigabit Ethernet Controller"); 1077*5d43fd68SRuslan Bukin return (BUS_PROBE_DEFAULT); 1078*5d43fd68SRuslan Bukin } 1079*5d43fd68SRuslan Bukin 1080*5d43fd68SRuslan Bukin static int 1081*5d43fd68SRuslan Bukin dwc_attach(device_t dev) 1082*5d43fd68SRuslan Bukin { 1083*5d43fd68SRuslan Bukin uint8_t macaddr[ETHER_ADDR_LEN]; 1084*5d43fd68SRuslan Bukin struct dwc_softc *sc; 1085*5d43fd68SRuslan Bukin struct ifnet *ifp; 1086*5d43fd68SRuslan Bukin int error; 1087*5d43fd68SRuslan Bukin int reg; 1088*5d43fd68SRuslan Bukin int i; 1089*5d43fd68SRuslan Bukin 1090*5d43fd68SRuslan Bukin sc = device_get_softc(dev); 1091*5d43fd68SRuslan Bukin sc->dev = dev; 1092*5d43fd68SRuslan Bukin sc->mii_clk = MII_CLK_VAL; 1093*5d43fd68SRuslan Bukin sc->rx_idx = 0; 1094*5d43fd68SRuslan Bukin 1095*5d43fd68SRuslan Bukin sc->txcount = TX_DESC_COUNT; 1096*5d43fd68SRuslan Bukin 1097*5d43fd68SRuslan Bukin if (bus_alloc_resources(dev, dwc_spec, sc->res)) { 1098*5d43fd68SRuslan Bukin device_printf(dev, "could not allocate resources\n"); 1099*5d43fd68SRuslan Bukin return (ENXIO); 1100*5d43fd68SRuslan Bukin } 1101*5d43fd68SRuslan Bukin 1102*5d43fd68SRuslan Bukin /* Memory interface */ 1103*5d43fd68SRuslan Bukin sc->bst = rman_get_bustag(sc->res[0]); 1104*5d43fd68SRuslan Bukin sc->bsh = rman_get_bushandle(sc->res[0]); 1105*5d43fd68SRuslan Bukin 1106*5d43fd68SRuslan Bukin mtx_init(&sc->mtx, device_get_nameunit(sc->dev), 1107*5d43fd68SRuslan Bukin MTX_NETWORK_LOCK, MTX_DEF); 1108*5d43fd68SRuslan Bukin 1109*5d43fd68SRuslan Bukin callout_init_mtx(&sc->dwc_callout, &sc->mtx, 0); 1110*5d43fd68SRuslan Bukin 1111*5d43fd68SRuslan Bukin /* Setup interrupt handler. */ 1112*5d43fd68SRuslan Bukin error = bus_setup_intr(dev, sc->res[1], INTR_TYPE_NET | INTR_MPSAFE, 1113*5d43fd68SRuslan Bukin NULL, dwc_intr, sc, &sc->intr_cookie); 1114*5d43fd68SRuslan Bukin if (error != 0) { 1115*5d43fd68SRuslan Bukin device_printf(dev, "could not setup interrupt handler.\n"); 1116*5d43fd68SRuslan Bukin return (ENXIO); 1117*5d43fd68SRuslan Bukin } 1118*5d43fd68SRuslan Bukin 1119*5d43fd68SRuslan Bukin /* Read MAC before reset */ 1120*5d43fd68SRuslan Bukin if (dwc_get_hwaddr(sc, macaddr)) { 1121*5d43fd68SRuslan Bukin device_printf(sc->dev, "can't get mac\n"); 1122*5d43fd68SRuslan Bukin return (ENXIO); 1123*5d43fd68SRuslan Bukin } 1124*5d43fd68SRuslan Bukin 1125*5d43fd68SRuslan Bukin /* Reset */ 1126*5d43fd68SRuslan Bukin reg = READ4(sc, BUS_MODE); 1127*5d43fd68SRuslan Bukin reg |= (BUS_MODE_SWR); 1128*5d43fd68SRuslan Bukin WRITE4(sc, BUS_MODE, reg); 1129*5d43fd68SRuslan Bukin 1130*5d43fd68SRuslan Bukin for (i = 0; i < 100; i++) { 1131*5d43fd68SRuslan Bukin if ((READ4(sc, BUS_MODE) & BUS_MODE_SWR) == 0) 1132*5d43fd68SRuslan Bukin break; 1133*5d43fd68SRuslan Bukin DELAY(10); 1134*5d43fd68SRuslan Bukin } 1135*5d43fd68SRuslan Bukin if (i == 0) { 1136*5d43fd68SRuslan Bukin device_printf(sc->dev, "Can't reset DWC.\n"); 1137*5d43fd68SRuslan Bukin return (ENXIO); 1138*5d43fd68SRuslan Bukin } 1139*5d43fd68SRuslan Bukin 1140*5d43fd68SRuslan Bukin reg = READ4(sc, BUS_MODE); 1141*5d43fd68SRuslan Bukin reg |= (BUS_MODE_EIGHTXPBL); 1142*5d43fd68SRuslan Bukin reg |= (BUS_MODE_PBL_BEATS_8 << BUS_MODE_PBL_SHIFT); 1143*5d43fd68SRuslan Bukin WRITE4(sc, BUS_MODE, reg); 1144*5d43fd68SRuslan Bukin 1145*5d43fd68SRuslan Bukin /* 1146*5d43fd68SRuslan Bukin * DMA must be stop while changing descriptor list addresses. 1147*5d43fd68SRuslan Bukin */ 1148*5d43fd68SRuslan Bukin reg = READ4(sc, OPERATION_MODE); 1149*5d43fd68SRuslan Bukin reg &= ~(MODE_ST | MODE_SR); 1150*5d43fd68SRuslan Bukin WRITE4(sc, OPERATION_MODE, reg); 1151*5d43fd68SRuslan Bukin 1152*5d43fd68SRuslan Bukin if (setup_dma(sc)) 1153*5d43fd68SRuslan Bukin return (ENXIO); 1154*5d43fd68SRuslan Bukin 1155*5d43fd68SRuslan Bukin /* Setup addresses */ 1156*5d43fd68SRuslan Bukin WRITE4(sc, RX_DESCR_LIST_ADDR, sc->rxdesc_ring_paddr); 1157*5d43fd68SRuslan Bukin WRITE4(sc, TX_DESCR_LIST_ADDR, sc->txdesc_ring_paddr); 1158*5d43fd68SRuslan Bukin 1159*5d43fd68SRuslan Bukin /* Set up the ethernet interface. */ 1160*5d43fd68SRuslan Bukin sc->ifp = ifp = if_alloc(IFT_ETHER); 1161*5d43fd68SRuslan Bukin 1162*5d43fd68SRuslan Bukin ifp->if_softc = sc; 1163*5d43fd68SRuslan Bukin if_initname(ifp, device_get_name(dev), device_get_unit(dev)); 1164*5d43fd68SRuslan Bukin ifp->if_flags = IFF_BROADCAST | IFF_SIMPLEX | IFF_MULTICAST; 1165*5d43fd68SRuslan Bukin ifp->if_capabilities = IFCAP_VLAN_MTU; 1166*5d43fd68SRuslan Bukin ifp->if_capenable = ifp->if_capabilities; 1167*5d43fd68SRuslan Bukin ifp->if_start = dwc_txstart; 1168*5d43fd68SRuslan Bukin ifp->if_ioctl = dwc_ioctl; 1169*5d43fd68SRuslan Bukin ifp->if_init = dwc_init; 1170*5d43fd68SRuslan Bukin IFQ_SET_MAXLEN(&ifp->if_snd, TX_DESC_COUNT - 1); 1171*5d43fd68SRuslan Bukin ifp->if_snd.ifq_drv_maxlen = TX_DESC_COUNT - 1; 1172*5d43fd68SRuslan Bukin IFQ_SET_READY(&ifp->if_snd); 1173*5d43fd68SRuslan Bukin ifp->if_hdrlen = sizeof(struct ether_vlan_header); 1174*5d43fd68SRuslan Bukin 1175*5d43fd68SRuslan Bukin /* Attach the mii driver. */ 1176*5d43fd68SRuslan Bukin error = mii_attach(dev, &sc->miibus, ifp, dwc_media_change, 1177*5d43fd68SRuslan Bukin dwc_media_status, BMSR_DEFCAPMASK, MII_PHY_ANY, 1178*5d43fd68SRuslan Bukin MII_OFFSET_ANY, 0); 1179*5d43fd68SRuslan Bukin 1180*5d43fd68SRuslan Bukin if (error != 0) { 1181*5d43fd68SRuslan Bukin device_printf(dev, "PHY attach failed\n"); 1182*5d43fd68SRuslan Bukin return (ENXIO); 1183*5d43fd68SRuslan Bukin } 1184*5d43fd68SRuslan Bukin sc->mii_softc = device_get_softc(sc->miibus); 1185*5d43fd68SRuslan Bukin 1186*5d43fd68SRuslan Bukin /* All ready to run, attach the ethernet interface. */ 1187*5d43fd68SRuslan Bukin ether_ifattach(ifp, macaddr); 1188*5d43fd68SRuslan Bukin sc->is_attached = true; 1189*5d43fd68SRuslan Bukin 1190*5d43fd68SRuslan Bukin return (0); 1191*5d43fd68SRuslan Bukin } 1192*5d43fd68SRuslan Bukin 1193*5d43fd68SRuslan Bukin static int 1194*5d43fd68SRuslan Bukin dwc_miibus_read_reg(device_t dev, int phy, int reg) 1195*5d43fd68SRuslan Bukin { 1196*5d43fd68SRuslan Bukin struct dwc_softc *sc; 1197*5d43fd68SRuslan Bukin uint16_t mii; 1198*5d43fd68SRuslan Bukin size_t cnt; 1199*5d43fd68SRuslan Bukin int rv = 0; 1200*5d43fd68SRuslan Bukin 1201*5d43fd68SRuslan Bukin sc = device_get_softc(dev); 1202*5d43fd68SRuslan Bukin 1203*5d43fd68SRuslan Bukin mii = ((phy & GMII_ADDRESS_PA_MASK) << GMII_ADDRESS_PA_SHIFT) 1204*5d43fd68SRuslan Bukin | ((reg & GMII_ADDRESS_GR_MASK) << GMII_ADDRESS_GR_SHIFT) 1205*5d43fd68SRuslan Bukin | (sc->mii_clk << GMII_ADDRESS_CR_SHIFT) 1206*5d43fd68SRuslan Bukin | GMII_ADDRESS_GB; /* Busy flag */ 1207*5d43fd68SRuslan Bukin 1208*5d43fd68SRuslan Bukin WRITE4(sc, GMII_ADDRESS, mii); 1209*5d43fd68SRuslan Bukin 1210*5d43fd68SRuslan Bukin for (cnt = 0; cnt < 1000; cnt++) { 1211*5d43fd68SRuslan Bukin if (!(READ4(sc, GMII_ADDRESS) & GMII_ADDRESS_GB)) { 1212*5d43fd68SRuslan Bukin rv = READ4(sc, GMII_DATA); 1213*5d43fd68SRuslan Bukin break; 1214*5d43fd68SRuslan Bukin } 1215*5d43fd68SRuslan Bukin DELAY(10); 1216*5d43fd68SRuslan Bukin } 1217*5d43fd68SRuslan Bukin 1218*5d43fd68SRuslan Bukin return rv; 1219*5d43fd68SRuslan Bukin } 1220*5d43fd68SRuslan Bukin 1221*5d43fd68SRuslan Bukin static int 1222*5d43fd68SRuslan Bukin dwc_miibus_write_reg(device_t dev, int phy, int reg, int val) 1223*5d43fd68SRuslan Bukin { 1224*5d43fd68SRuslan Bukin struct dwc_softc *sc; 1225*5d43fd68SRuslan Bukin uint16_t mii; 1226*5d43fd68SRuslan Bukin size_t cnt; 1227*5d43fd68SRuslan Bukin 1228*5d43fd68SRuslan Bukin sc = device_get_softc(dev); 1229*5d43fd68SRuslan Bukin 1230*5d43fd68SRuslan Bukin mii = ((phy & GMII_ADDRESS_PA_MASK) << GMII_ADDRESS_PA_SHIFT) 1231*5d43fd68SRuslan Bukin | ((reg & GMII_ADDRESS_GR_MASK) << GMII_ADDRESS_GR_SHIFT) 1232*5d43fd68SRuslan Bukin | (sc->mii_clk << GMII_ADDRESS_CR_SHIFT) 1233*5d43fd68SRuslan Bukin | GMII_ADDRESS_GB | GMII_ADDRESS_GW; 1234*5d43fd68SRuslan Bukin 1235*5d43fd68SRuslan Bukin WRITE4(sc, GMII_DATA, val); 1236*5d43fd68SRuslan Bukin WRITE4(sc, GMII_ADDRESS, mii); 1237*5d43fd68SRuslan Bukin 1238*5d43fd68SRuslan Bukin for (cnt = 0; cnt < 1000; cnt++) { 1239*5d43fd68SRuslan Bukin if (!(READ4(sc, GMII_ADDRESS) & GMII_ADDRESS_GB)) { 1240*5d43fd68SRuslan Bukin break; 1241*5d43fd68SRuslan Bukin } 1242*5d43fd68SRuslan Bukin DELAY(10); 1243*5d43fd68SRuslan Bukin } 1244*5d43fd68SRuslan Bukin 1245*5d43fd68SRuslan Bukin return (0); 1246*5d43fd68SRuslan Bukin } 1247*5d43fd68SRuslan Bukin 1248*5d43fd68SRuslan Bukin static void 1249*5d43fd68SRuslan Bukin dwc_miibus_statchg(device_t dev) 1250*5d43fd68SRuslan Bukin { 1251*5d43fd68SRuslan Bukin struct dwc_softc *sc; 1252*5d43fd68SRuslan Bukin struct mii_data *mii; 1253*5d43fd68SRuslan Bukin int reg; 1254*5d43fd68SRuslan Bukin 1255*5d43fd68SRuslan Bukin /* 1256*5d43fd68SRuslan Bukin * Called by the MII bus driver when the PHY establishes 1257*5d43fd68SRuslan Bukin * link to set the MAC interface registers. 1258*5d43fd68SRuslan Bukin */ 1259*5d43fd68SRuslan Bukin 1260*5d43fd68SRuslan Bukin sc = device_get_softc(dev); 1261*5d43fd68SRuslan Bukin 1262*5d43fd68SRuslan Bukin DWC_ASSERT_LOCKED(sc); 1263*5d43fd68SRuslan Bukin 1264*5d43fd68SRuslan Bukin mii = sc->mii_softc; 1265*5d43fd68SRuslan Bukin 1266*5d43fd68SRuslan Bukin if (mii->mii_media_status & IFM_ACTIVE) 1267*5d43fd68SRuslan Bukin sc->link_is_up = true; 1268*5d43fd68SRuslan Bukin else 1269*5d43fd68SRuslan Bukin sc->link_is_up = false; 1270*5d43fd68SRuslan Bukin 1271*5d43fd68SRuslan Bukin reg = READ4(sc, MAC_CONFIGURATION); 1272*5d43fd68SRuslan Bukin switch (IFM_SUBTYPE(mii->mii_media_active)) { 1273*5d43fd68SRuslan Bukin case IFM_1000_T: 1274*5d43fd68SRuslan Bukin case IFM_1000_SX: 1275*5d43fd68SRuslan Bukin reg &= ~(CONF_FES | CONF_PS); 1276*5d43fd68SRuslan Bukin break; 1277*5d43fd68SRuslan Bukin case IFM_100_TX: 1278*5d43fd68SRuslan Bukin reg |= (CONF_FES | CONF_PS); 1279*5d43fd68SRuslan Bukin break; 1280*5d43fd68SRuslan Bukin case IFM_10_T: 1281*5d43fd68SRuslan Bukin reg &= ~(CONF_FES); 1282*5d43fd68SRuslan Bukin reg |= (CONF_PS); 1283*5d43fd68SRuslan Bukin break; 1284*5d43fd68SRuslan Bukin case IFM_NONE: 1285*5d43fd68SRuslan Bukin sc->link_is_up = false; 1286*5d43fd68SRuslan Bukin return; 1287*5d43fd68SRuslan Bukin default: 1288*5d43fd68SRuslan Bukin sc->link_is_up = false; 1289*5d43fd68SRuslan Bukin device_printf(dev, "Unsupported media %u\n", 1290*5d43fd68SRuslan Bukin IFM_SUBTYPE(mii->mii_media_active)); 1291*5d43fd68SRuslan Bukin return; 1292*5d43fd68SRuslan Bukin } 1293*5d43fd68SRuslan Bukin if ((IFM_OPTIONS(mii->mii_media_active) & IFM_FDX) != 0) 1294*5d43fd68SRuslan Bukin reg |= (CONF_DM); 1295*5d43fd68SRuslan Bukin else 1296*5d43fd68SRuslan Bukin reg &= ~(CONF_DM); 1297*5d43fd68SRuslan Bukin WRITE4(sc, MAC_CONFIGURATION, reg); 1298*5d43fd68SRuslan Bukin } 1299*5d43fd68SRuslan Bukin 1300*5d43fd68SRuslan Bukin static device_method_t dwc_methods[] = { 1301*5d43fd68SRuslan Bukin DEVMETHOD(device_probe, dwc_probe), 1302*5d43fd68SRuslan Bukin DEVMETHOD(device_attach, dwc_attach), 1303*5d43fd68SRuslan Bukin 1304*5d43fd68SRuslan Bukin /* MII Interface */ 1305*5d43fd68SRuslan Bukin DEVMETHOD(miibus_readreg, dwc_miibus_read_reg), 1306*5d43fd68SRuslan Bukin DEVMETHOD(miibus_writereg, dwc_miibus_write_reg), 1307*5d43fd68SRuslan Bukin DEVMETHOD(miibus_statchg, dwc_miibus_statchg), 1308*5d43fd68SRuslan Bukin 1309*5d43fd68SRuslan Bukin { 0, 0 } 1310*5d43fd68SRuslan Bukin }; 1311*5d43fd68SRuslan Bukin 1312*5d43fd68SRuslan Bukin static driver_t dwc_driver = { 1313*5d43fd68SRuslan Bukin "dwc", 1314*5d43fd68SRuslan Bukin dwc_methods, 1315*5d43fd68SRuslan Bukin sizeof(struct dwc_softc), 1316*5d43fd68SRuslan Bukin }; 1317*5d43fd68SRuslan Bukin 1318*5d43fd68SRuslan Bukin static devclass_t dwc_devclass; 1319*5d43fd68SRuslan Bukin 1320*5d43fd68SRuslan Bukin DRIVER_MODULE(dwc, simplebus, dwc_driver, dwc_devclass, 0, 0); 1321*5d43fd68SRuslan Bukin DRIVER_MODULE(miibus, dwc, miibus_driver, miibus_devclass, 0, 0); 1322*5d43fd68SRuslan Bukin 1323*5d43fd68SRuslan Bukin MODULE_DEPEND(dwc, ether, 1, 1, 1); 1324*5d43fd68SRuslan Bukin MODULE_DEPEND(dwc, miibus, 1, 1, 1); 1325