1*f51cb083Sbluhm /* $OpenBSD: dwqe.c,v 1.17 2024/03/04 23:50:20 bluhm Exp $ */ 2305ac5f9Spatrick /* 3305ac5f9Spatrick * Copyright (c) 2008, 2019 Mark Kettenis <kettenis@openbsd.org> 4305ac5f9Spatrick * Copyright (c) 2017, 2022 Patrick Wildt <patrick@blueri.se> 5305ac5f9Spatrick * 6305ac5f9Spatrick * Permission to use, copy, modify, and distribute this software for any 7305ac5f9Spatrick * purpose with or without fee is hereby granted, provided that the above 8305ac5f9Spatrick * copyright notice and this permission notice appear in all copies. 9305ac5f9Spatrick * 10305ac5f9Spatrick * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES 11305ac5f9Spatrick * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF 12305ac5f9Spatrick * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR 13305ac5f9Spatrick * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES 14305ac5f9Spatrick * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN 15305ac5f9Spatrick * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF 16305ac5f9Spatrick * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. 17305ac5f9Spatrick */ 18305ac5f9Spatrick 19305ac5f9Spatrick /* 20305ac5f9Spatrick * Driver for the Synopsys Designware ethernet controller. 21305ac5f9Spatrick */ 22305ac5f9Spatrick 23305ac5f9Spatrick #include "bpfilter.h" 24305ac5f9Spatrick 25305ac5f9Spatrick #include <sys/param.h> 26305ac5f9Spatrick #include <sys/systm.h> 27305ac5f9Spatrick #include <sys/device.h> 28305ac5f9Spatrick #include <sys/kernel.h> 29305ac5f9Spatrick #include <sys/malloc.h> 30305ac5f9Spatrick #include <sys/mbuf.h> 31305ac5f9Spatrick #include <sys/queue.h> 32305ac5f9Spatrick #include <sys/socket.h> 33305ac5f9Spatrick #include <sys/sockio.h> 34305ac5f9Spatrick #include <sys/timeout.h> 35305ac5f9Spatrick 36305ac5f9Spatrick #include <machine/bus.h> 37305ac5f9Spatrick 38305ac5f9Spatrick #include <net/if.h> 39305ac5f9Spatrick #include <net/if_media.h> 40305ac5f9Spatrick 41305ac5f9Spatrick #include <dev/mii/mii.h> 42305ac5f9Spatrick #include <dev/mii/miivar.h> 43305ac5f9Spatrick 44305ac5f9Spatrick #if NBPFILTER > 0 45305ac5f9Spatrick #include <net/bpf.h> 46305ac5f9Spatrick #endif 47305ac5f9Spatrick 48305ac5f9Spatrick #include <netinet/in.h> 49305ac5f9Spatrick #include <netinet/if_ether.h> 50305ac5f9Spatrick 51305ac5f9Spatrick #include <dev/ic/dwqevar.h> 52305ac5f9Spatrick #include <dev/ic/dwqereg.h> 53305ac5f9Spatrick 54305ac5f9Spatrick struct cfdriver dwqe_cd = { 55305ac5f9Spatrick NULL, "dwqe", DV_IFNET 56305ac5f9Spatrick }; 57305ac5f9Spatrick 58305ac5f9Spatrick uint32_t dwqe_read(struct dwqe_softc *, bus_addr_t); 59305ac5f9Spatrick void dwqe_write(struct dwqe_softc *, bus_addr_t, uint32_t); 60305ac5f9Spatrick 61305ac5f9Spatrick int dwqe_ioctl(struct ifnet *, u_long, caddr_t); 62305ac5f9Spatrick void dwqe_start(struct ifqueue *); 63305ac5f9Spatrick void dwqe_watchdog(struct ifnet *); 64305ac5f9Spatrick 65305ac5f9Spatrick int dwqe_media_change(struct ifnet *); 66305ac5f9Spatrick void dwqe_media_status(struct ifnet *, struct ifmediareq *); 67305ac5f9Spatrick 6845f5f3c8Sdlg void dwqe_mii_attach(struct dwqe_softc *); 69305ac5f9Spatrick int dwqe_mii_readreg(struct device *, int, int); 70305ac5f9Spatrick void dwqe_mii_writereg(struct device *, int, int, int); 71305ac5f9Spatrick void dwqe_mii_statchg(struct device *); 72305ac5f9Spatrick 73305ac5f9Spatrick void dwqe_lladdr_read(struct dwqe_softc *, uint8_t *); 74305ac5f9Spatrick void dwqe_lladdr_write(struct dwqe_softc *); 75305ac5f9Spatrick 76305ac5f9Spatrick void dwqe_tick(void *); 77305ac5f9Spatrick void dwqe_rxtick(void *); 78305ac5f9Spatrick 79305ac5f9Spatrick int dwqe_intr(void *); 80305ac5f9Spatrick void dwqe_tx_proc(struct dwqe_softc *); 81305ac5f9Spatrick void dwqe_rx_proc(struct dwqe_softc *); 82305ac5f9Spatrick 83305ac5f9Spatrick void dwqe_up(struct dwqe_softc *); 84305ac5f9Spatrick void dwqe_down(struct dwqe_softc *); 85305ac5f9Spatrick void dwqe_iff(struct dwqe_softc *); 86305ac5f9Spatrick int dwqe_encap(struct dwqe_softc *, struct mbuf *, int *, int *); 87305ac5f9Spatrick 88305ac5f9Spatrick void dwqe_reset(struct dwqe_softc *); 89305ac5f9Spatrick 90305ac5f9Spatrick struct dwqe_dmamem * 91305ac5f9Spatrick dwqe_dmamem_alloc(struct dwqe_softc *, bus_size_t, bus_size_t); 92305ac5f9Spatrick void dwqe_dmamem_free(struct dwqe_softc *, struct dwqe_dmamem *); 93305ac5f9Spatrick struct mbuf *dwqe_alloc_mbuf(struct dwqe_softc *, bus_dmamap_t); 94305ac5f9Spatrick void dwqe_fill_rx_ring(struct dwqe_softc *); 95305ac5f9Spatrick 96305ac5f9Spatrick int 97305ac5f9Spatrick dwqe_attach(struct dwqe_softc *sc) 98305ac5f9Spatrick { 99305ac5f9Spatrick struct ifnet *ifp; 100305ac5f9Spatrick uint32_t version, mode; 101305ac5f9Spatrick int i; 102305ac5f9Spatrick 103305ac5f9Spatrick version = dwqe_read(sc, GMAC_VERSION); 1044fa84378Skettenis printf(": rev 0x%02x, address %s\n", version & GMAC_VERSION_SNPS_MASK, 105305ac5f9Spatrick ether_sprintf(sc->sc_lladdr)); 106305ac5f9Spatrick 107305ac5f9Spatrick for (i = 0; i < 4; i++) 108305ac5f9Spatrick sc->sc_hw_feature[i] = dwqe_read(sc, GMAC_MAC_HW_FEATURE(i)); 109305ac5f9Spatrick 11047707f8eSdlg timeout_set(&sc->sc_phy_tick, dwqe_tick, sc); 111305ac5f9Spatrick timeout_set(&sc->sc_rxto, dwqe_rxtick, sc); 112305ac5f9Spatrick 113305ac5f9Spatrick ifp = &sc->sc_ac.ac_if; 114305ac5f9Spatrick ifp->if_softc = sc; 115305ac5f9Spatrick ifp->if_flags = IFF_BROADCAST | IFF_SIMPLEX | IFF_MULTICAST; 116305ac5f9Spatrick ifp->if_xflags = IFXF_MPSAFE; 117305ac5f9Spatrick ifp->if_ioctl = dwqe_ioctl; 118305ac5f9Spatrick ifp->if_qstart = dwqe_start; 119305ac5f9Spatrick ifp->if_watchdog = dwqe_watchdog; 120cf96265bSbluhm ifq_init_maxlen(&ifp->if_snd, DWQE_NTXDESC - 1); 121305ac5f9Spatrick bcopy(sc->sc_dev.dv_xname, ifp->if_xname, IFNAMSIZ); 122305ac5f9Spatrick 123305ac5f9Spatrick ifp->if_capabilities = IFCAP_VLAN_MTU; 124305ac5f9Spatrick 125305ac5f9Spatrick sc->sc_mii.mii_ifp = ifp; 126305ac5f9Spatrick sc->sc_mii.mii_readreg = dwqe_mii_readreg; 127305ac5f9Spatrick sc->sc_mii.mii_writereg = dwqe_mii_writereg; 128305ac5f9Spatrick sc->sc_mii.mii_statchg = dwqe_mii_statchg; 129305ac5f9Spatrick 130305ac5f9Spatrick ifmedia_init(&sc->sc_media, 0, dwqe_media_change, dwqe_media_status); 131305ac5f9Spatrick 132305ac5f9Spatrick dwqe_reset(sc); 133305ac5f9Spatrick 134305ac5f9Spatrick /* Configure DMA engine. */ 135305ac5f9Spatrick mode = dwqe_read(sc, GMAC_SYS_BUS_MODE); 136305ac5f9Spatrick if (sc->sc_fixed_burst) 137305ac5f9Spatrick mode |= GMAC_SYS_BUS_MODE_FB; 138305ac5f9Spatrick if (sc->sc_mixed_burst) 139305ac5f9Spatrick mode |= GMAC_SYS_BUS_MODE_MB; 140305ac5f9Spatrick if (sc->sc_aal) 141305ac5f9Spatrick mode |= GMAC_SYS_BUS_MODE_AAL; 142305ac5f9Spatrick dwqe_write(sc, GMAC_SYS_BUS_MODE, mode); 143305ac5f9Spatrick 144305ac5f9Spatrick /* Configure channel 0. */ 145305ac5f9Spatrick mode = dwqe_read(sc, GMAC_CHAN_CONTROL(0)); 146305ac5f9Spatrick if (sc->sc_8xpbl) 147305ac5f9Spatrick mode |= GMAC_CHAN_CONTROL_8XPBL; 148305ac5f9Spatrick dwqe_write(sc, GMAC_CHAN_CONTROL(0), mode); 149305ac5f9Spatrick 150305ac5f9Spatrick mode = dwqe_read(sc, GMAC_CHAN_TX_CONTROL(0)); 151305ac5f9Spatrick mode &= ~GMAC_CHAN_TX_CONTROL_PBL_MASK; 152305ac5f9Spatrick mode |= sc->sc_txpbl << GMAC_CHAN_TX_CONTROL_PBL_SHIFT; 153305ac5f9Spatrick mode |= GMAC_CHAN_TX_CONTROL_OSP; 154305ac5f9Spatrick dwqe_write(sc, GMAC_CHAN_TX_CONTROL(0), mode); 155f6ce44eeSjsg mode = dwqe_read(sc, GMAC_CHAN_RX_CONTROL(0)); 156305ac5f9Spatrick mode &= ~GMAC_CHAN_RX_CONTROL_RPBL_MASK; 157305ac5f9Spatrick mode |= sc->sc_rxpbl << GMAC_CHAN_RX_CONTROL_RPBL_SHIFT; 158305ac5f9Spatrick dwqe_write(sc, GMAC_CHAN_RX_CONTROL(0), mode); 159305ac5f9Spatrick 160305ac5f9Spatrick /* Configure AXI master. */ 161305ac5f9Spatrick if (sc->sc_axi_config) { 162305ac5f9Spatrick int i; 163305ac5f9Spatrick 164305ac5f9Spatrick mode = dwqe_read(sc, GMAC_SYS_BUS_MODE); 165305ac5f9Spatrick 166305ac5f9Spatrick mode &= ~GMAC_SYS_BUS_MODE_EN_LPI; 167305ac5f9Spatrick if (sc->sc_lpi_en) 168305ac5f9Spatrick mode |= GMAC_SYS_BUS_MODE_EN_LPI; 169305ac5f9Spatrick mode &= ~GMAC_SYS_BUS_MODE_LPI_XIT_FRM; 170305ac5f9Spatrick if (sc->sc_xit_frm) 171305ac5f9Spatrick mode |= GMAC_SYS_BUS_MODE_LPI_XIT_FRM; 172305ac5f9Spatrick 173305ac5f9Spatrick mode &= ~GMAC_SYS_BUS_MODE_WR_OSR_LMT_MASK; 174305ac5f9Spatrick mode |= (sc->sc_wr_osr_lmt << GMAC_SYS_BUS_MODE_WR_OSR_LMT_SHIFT); 175305ac5f9Spatrick mode &= ~GMAC_SYS_BUS_MODE_RD_OSR_LMT_MASK; 176305ac5f9Spatrick mode |= (sc->sc_rd_osr_lmt << GMAC_SYS_BUS_MODE_RD_OSR_LMT_SHIFT); 177305ac5f9Spatrick 178305ac5f9Spatrick for (i = 0; i < nitems(sc->sc_blen); i++) { 179305ac5f9Spatrick switch (sc->sc_blen[i]) { 180305ac5f9Spatrick case 256: 181305ac5f9Spatrick mode |= GMAC_SYS_BUS_MODE_BLEN_256; 182305ac5f9Spatrick break; 183305ac5f9Spatrick case 128: 184305ac5f9Spatrick mode |= GMAC_SYS_BUS_MODE_BLEN_128; 185305ac5f9Spatrick break; 186305ac5f9Spatrick case 64: 187305ac5f9Spatrick mode |= GMAC_SYS_BUS_MODE_BLEN_64; 188305ac5f9Spatrick break; 189305ac5f9Spatrick case 32: 190305ac5f9Spatrick mode |= GMAC_SYS_BUS_MODE_BLEN_32; 191305ac5f9Spatrick break; 192305ac5f9Spatrick case 16: 193305ac5f9Spatrick mode |= GMAC_SYS_BUS_MODE_BLEN_16; 194305ac5f9Spatrick break; 195305ac5f9Spatrick case 8: 196305ac5f9Spatrick mode |= GMAC_SYS_BUS_MODE_BLEN_8; 197305ac5f9Spatrick break; 198305ac5f9Spatrick case 4: 199305ac5f9Spatrick mode |= GMAC_SYS_BUS_MODE_BLEN_4; 200305ac5f9Spatrick break; 201305ac5f9Spatrick } 202305ac5f9Spatrick } 203305ac5f9Spatrick 204305ac5f9Spatrick dwqe_write(sc, GMAC_SYS_BUS_MODE, mode); 205305ac5f9Spatrick } 206305ac5f9Spatrick 20745f5f3c8Sdlg if (!sc->sc_fixed_link) 20845f5f3c8Sdlg dwqe_mii_attach(sc); 20945f5f3c8Sdlg 21045f5f3c8Sdlg if_attach(ifp); 21145f5f3c8Sdlg ether_ifattach(ifp); 21245f5f3c8Sdlg 21345f5f3c8Sdlg /* Disable interrupts. */ 21445f5f3c8Sdlg dwqe_write(sc, GMAC_INT_EN, 0); 21545f5f3c8Sdlg dwqe_write(sc, GMAC_CHAN_INTR_ENA(0), 0); 21645f5f3c8Sdlg 21745f5f3c8Sdlg return 0; 21845f5f3c8Sdlg } 21945f5f3c8Sdlg 22045f5f3c8Sdlg void 22145f5f3c8Sdlg dwqe_mii_attach(struct dwqe_softc *sc) 22245f5f3c8Sdlg { 22345f5f3c8Sdlg int mii_flags = 0; 22445f5f3c8Sdlg 225e9f49f11Skettenis switch (sc->sc_phy_mode) { 226e9f49f11Skettenis case DWQE_PHY_MODE_RGMII: 227e9f49f11Skettenis mii_flags |= MIIF_SETDELAY; 228e9f49f11Skettenis break; 229e9f49f11Skettenis case DWQE_PHY_MODE_RGMII_ID: 230e9f49f11Skettenis mii_flags |= MIIF_SETDELAY | MIIF_RXID | MIIF_TXID; 231e9f49f11Skettenis break; 232e9f49f11Skettenis case DWQE_PHY_MODE_RGMII_RXID: 233e9f49f11Skettenis mii_flags |= MIIF_SETDELAY | MIIF_RXID; 234e9f49f11Skettenis break; 235e9f49f11Skettenis case DWQE_PHY_MODE_RGMII_TXID: 236e9f49f11Skettenis mii_flags |= MIIF_SETDELAY | MIIF_TXID; 237e9f49f11Skettenis break; 238e9f49f11Skettenis default: 239e9f49f11Skettenis break; 240e9f49f11Skettenis } 241e9f49f11Skettenis 242305ac5f9Spatrick mii_attach(&sc->sc_dev, &sc->sc_mii, 0xffffffff, sc->sc_phyloc, 243e9f49f11Skettenis (sc->sc_phyloc == MII_PHY_ANY) ? 0 : MII_OFFSET_ANY, mii_flags); 244305ac5f9Spatrick if (LIST_FIRST(&sc->sc_mii.mii_phys) == NULL) { 245305ac5f9Spatrick printf("%s: no PHY found!\n", sc->sc_dev.dv_xname); 246305ac5f9Spatrick ifmedia_add(&sc->sc_media, IFM_ETHER|IFM_MANUAL, 0, NULL); 247305ac5f9Spatrick ifmedia_set(&sc->sc_media, IFM_ETHER|IFM_MANUAL); 248305ac5f9Spatrick } else 249305ac5f9Spatrick ifmedia_set(&sc->sc_media, IFM_ETHER|IFM_AUTO); 250305ac5f9Spatrick } 251305ac5f9Spatrick 252305ac5f9Spatrick uint32_t 253305ac5f9Spatrick dwqe_read(struct dwqe_softc *sc, bus_addr_t addr) 254305ac5f9Spatrick { 255305ac5f9Spatrick return bus_space_read_4(sc->sc_iot, sc->sc_ioh, addr); 256305ac5f9Spatrick } 257305ac5f9Spatrick 258305ac5f9Spatrick void 259305ac5f9Spatrick dwqe_write(struct dwqe_softc *sc, bus_addr_t addr, uint32_t data) 260305ac5f9Spatrick { 261305ac5f9Spatrick bus_space_write_4(sc->sc_iot, sc->sc_ioh, addr, data); 262305ac5f9Spatrick } 263305ac5f9Spatrick 264305ac5f9Spatrick void 265305ac5f9Spatrick dwqe_lladdr_read(struct dwqe_softc *sc, uint8_t *lladdr) 266305ac5f9Spatrick { 267305ac5f9Spatrick uint32_t machi, maclo; 268305ac5f9Spatrick 269305ac5f9Spatrick machi = dwqe_read(sc, GMAC_MAC_ADDR0_HI); 270305ac5f9Spatrick maclo = dwqe_read(sc, GMAC_MAC_ADDR0_LO); 271305ac5f9Spatrick 272305ac5f9Spatrick if (machi || maclo) { 273305ac5f9Spatrick lladdr[0] = (maclo >> 0) & 0xff; 274305ac5f9Spatrick lladdr[1] = (maclo >> 8) & 0xff; 275305ac5f9Spatrick lladdr[2] = (maclo >> 16) & 0xff; 276305ac5f9Spatrick lladdr[3] = (maclo >> 24) & 0xff; 277305ac5f9Spatrick lladdr[4] = (machi >> 0) & 0xff; 278305ac5f9Spatrick lladdr[5] = (machi >> 8) & 0xff; 279305ac5f9Spatrick } else { 280305ac5f9Spatrick ether_fakeaddr(&sc->sc_ac.ac_if); 281305ac5f9Spatrick } 282305ac5f9Spatrick } 283305ac5f9Spatrick 284305ac5f9Spatrick void 285305ac5f9Spatrick dwqe_lladdr_write(struct dwqe_softc *sc) 286305ac5f9Spatrick { 287305ac5f9Spatrick dwqe_write(sc, GMAC_MAC_ADDR0_HI, 288305ac5f9Spatrick sc->sc_lladdr[5] << 8 | sc->sc_lladdr[4] << 0); 289305ac5f9Spatrick dwqe_write(sc, GMAC_MAC_ADDR0_LO, 290305ac5f9Spatrick sc->sc_lladdr[3] << 24 | sc->sc_lladdr[2] << 16 | 291305ac5f9Spatrick sc->sc_lladdr[1] << 8 | sc->sc_lladdr[0] << 0); 292305ac5f9Spatrick } 293305ac5f9Spatrick 294305ac5f9Spatrick void 295305ac5f9Spatrick dwqe_start(struct ifqueue *ifq) 296305ac5f9Spatrick { 297305ac5f9Spatrick struct ifnet *ifp = ifq->ifq_if; 298305ac5f9Spatrick struct dwqe_softc *sc = ifp->if_softc; 299305ac5f9Spatrick struct mbuf *m; 300305ac5f9Spatrick int error, idx, left, used; 301305ac5f9Spatrick 302305ac5f9Spatrick if (!(ifp->if_flags & IFF_RUNNING)) 303305ac5f9Spatrick return; 304305ac5f9Spatrick if (ifq_is_oactive(&ifp->if_snd)) 305305ac5f9Spatrick return; 306305ac5f9Spatrick if (ifq_empty(&ifp->if_snd)) 307305ac5f9Spatrick return; 308305ac5f9Spatrick if (!sc->sc_link) 309305ac5f9Spatrick return; 310305ac5f9Spatrick 311305ac5f9Spatrick idx = sc->sc_tx_prod; 312305ac5f9Spatrick left = sc->sc_tx_cons; 313305ac5f9Spatrick if (left <= idx) 314305ac5f9Spatrick left += DWQE_NTXDESC; 315305ac5f9Spatrick left -= idx; 316305ac5f9Spatrick used = 0; 317305ac5f9Spatrick 318305ac5f9Spatrick for (;;) { 319305ac5f9Spatrick if (used + DWQE_NTXSEGS + 1 > left) { 320305ac5f9Spatrick ifq_set_oactive(ifq); 321305ac5f9Spatrick break; 322305ac5f9Spatrick } 323305ac5f9Spatrick 324305ac5f9Spatrick m = ifq_dequeue(ifq); 325305ac5f9Spatrick if (m == NULL) 326305ac5f9Spatrick break; 327305ac5f9Spatrick 328305ac5f9Spatrick error = dwqe_encap(sc, m, &idx, &used); 329305ac5f9Spatrick if (error == EFBIG) { 330305ac5f9Spatrick m_freem(m); /* give up: drop it */ 331305ac5f9Spatrick ifp->if_oerrors++; 332305ac5f9Spatrick continue; 333305ac5f9Spatrick } 334305ac5f9Spatrick 335305ac5f9Spatrick #if NBPFILTER > 0 336305ac5f9Spatrick if (ifp->if_bpf) 337305ac5f9Spatrick bpf_mtap(ifp->if_bpf, m, BPF_DIRECTION_OUT); 338305ac5f9Spatrick #endif 339305ac5f9Spatrick } 340305ac5f9Spatrick 341555d2e79Suwe if (used > 0) { 342305ac5f9Spatrick sc->sc_tx_prod = idx; 343305ac5f9Spatrick 344305ac5f9Spatrick /* Set a timeout in case the chip goes out to lunch. */ 345305ac5f9Spatrick ifp->if_timer = 5; 346555d2e79Suwe 347555d2e79Suwe /* 348555d2e79Suwe * Start the transmit process after the last in-use Tx 349555d2e79Suwe * descriptor's OWN bit has been updated. 350555d2e79Suwe */ 351555d2e79Suwe dwqe_write(sc, GMAC_CHAN_TX_END_ADDR(0), DWQE_DMA_DVA(sc->sc_txring) + 352555d2e79Suwe idx * sizeof(struct dwqe_desc)); 353305ac5f9Spatrick } 354305ac5f9Spatrick } 355305ac5f9Spatrick 356305ac5f9Spatrick int 357305ac5f9Spatrick dwqe_ioctl(struct ifnet *ifp, u_long cmd, caddr_t addr) 358305ac5f9Spatrick { 359305ac5f9Spatrick struct dwqe_softc *sc = ifp->if_softc; 360305ac5f9Spatrick struct ifreq *ifr = (struct ifreq *)addr; 361305ac5f9Spatrick int error = 0, s; 362305ac5f9Spatrick 363305ac5f9Spatrick s = splnet(); 364305ac5f9Spatrick 365305ac5f9Spatrick switch (cmd) { 366305ac5f9Spatrick case SIOCSIFADDR: 367305ac5f9Spatrick ifp->if_flags |= IFF_UP; 368305ac5f9Spatrick /* FALLTHROUGH */ 369305ac5f9Spatrick case SIOCSIFFLAGS: 370305ac5f9Spatrick if (ifp->if_flags & IFF_UP) { 371305ac5f9Spatrick if (ifp->if_flags & IFF_RUNNING) 372305ac5f9Spatrick error = ENETRESET; 373305ac5f9Spatrick else 374305ac5f9Spatrick dwqe_up(sc); 375305ac5f9Spatrick } else { 376305ac5f9Spatrick if (ifp->if_flags & IFF_RUNNING) 377305ac5f9Spatrick dwqe_down(sc); 378305ac5f9Spatrick } 379305ac5f9Spatrick break; 380305ac5f9Spatrick 381305ac5f9Spatrick case SIOCGIFMEDIA: 382305ac5f9Spatrick case SIOCSIFMEDIA: 38345f5f3c8Sdlg if (sc->sc_fixed_link) 38445f5f3c8Sdlg error = ENOTTY; 38545f5f3c8Sdlg else 386305ac5f9Spatrick error = ifmedia_ioctl(ifp, ifr, &sc->sc_media, cmd); 387305ac5f9Spatrick break; 388305ac5f9Spatrick 389305ac5f9Spatrick case SIOCGIFRXR: 390305ac5f9Spatrick error = if_rxr_ioctl((struct if_rxrinfo *)ifr->ifr_data, 391305ac5f9Spatrick NULL, MCLBYTES, &sc->sc_rx_ring); 392305ac5f9Spatrick break; 393305ac5f9Spatrick 394305ac5f9Spatrick default: 395305ac5f9Spatrick error = ether_ioctl(ifp, &sc->sc_ac, cmd, addr); 396305ac5f9Spatrick break; 397305ac5f9Spatrick } 398305ac5f9Spatrick 399305ac5f9Spatrick if (error == ENETRESET) { 400305ac5f9Spatrick if (ifp->if_flags & IFF_RUNNING) 401305ac5f9Spatrick dwqe_iff(sc); 402305ac5f9Spatrick error = 0; 403305ac5f9Spatrick } 404305ac5f9Spatrick 405305ac5f9Spatrick splx(s); 406305ac5f9Spatrick return (error); 407305ac5f9Spatrick } 408305ac5f9Spatrick 409305ac5f9Spatrick void 410305ac5f9Spatrick dwqe_watchdog(struct ifnet *ifp) 411305ac5f9Spatrick { 412305ac5f9Spatrick printf("%s\n", __func__); 413305ac5f9Spatrick } 414305ac5f9Spatrick 415305ac5f9Spatrick int 416305ac5f9Spatrick dwqe_media_change(struct ifnet *ifp) 417305ac5f9Spatrick { 418305ac5f9Spatrick struct dwqe_softc *sc = ifp->if_softc; 419305ac5f9Spatrick 420305ac5f9Spatrick if (LIST_FIRST(&sc->sc_mii.mii_phys)) 421305ac5f9Spatrick mii_mediachg(&sc->sc_mii); 422305ac5f9Spatrick 423305ac5f9Spatrick return (0); 424305ac5f9Spatrick } 425305ac5f9Spatrick 426305ac5f9Spatrick void 427305ac5f9Spatrick dwqe_media_status(struct ifnet *ifp, struct ifmediareq *ifmr) 428305ac5f9Spatrick { 429305ac5f9Spatrick struct dwqe_softc *sc = ifp->if_softc; 430305ac5f9Spatrick 431305ac5f9Spatrick if (LIST_FIRST(&sc->sc_mii.mii_phys)) { 432305ac5f9Spatrick mii_pollstat(&sc->sc_mii); 433305ac5f9Spatrick ifmr->ifm_active = sc->sc_mii.mii_media_active; 434305ac5f9Spatrick ifmr->ifm_status = sc->sc_mii.mii_media_status; 435305ac5f9Spatrick } 436305ac5f9Spatrick } 437305ac5f9Spatrick 438305ac5f9Spatrick int 439305ac5f9Spatrick dwqe_mii_readreg(struct device *self, int phy, int reg) 440305ac5f9Spatrick { 441305ac5f9Spatrick struct dwqe_softc *sc = (void *)self; 442305ac5f9Spatrick int n; 443305ac5f9Spatrick 444305ac5f9Spatrick dwqe_write(sc, GMAC_MAC_MDIO_ADDR, 4450738886aSkettenis (sc->sc_clk << GMAC_MAC_MDIO_ADDR_CR_SHIFT) | 446305ac5f9Spatrick (phy << GMAC_MAC_MDIO_ADDR_PA_SHIFT) | 447305ac5f9Spatrick (reg << GMAC_MAC_MDIO_ADDR_RDA_SHIFT) | 448305ac5f9Spatrick GMAC_MAC_MDIO_ADDR_GOC_READ | 449305ac5f9Spatrick GMAC_MAC_MDIO_ADDR_GB); 450305ac5f9Spatrick 4519fb70083Sdlg for (n = 0; n < 2000; n++) { 4529fb70083Sdlg delay(10); 453305ac5f9Spatrick if ((dwqe_read(sc, GMAC_MAC_MDIO_ADDR) & GMAC_MAC_MDIO_ADDR_GB) == 0) 454305ac5f9Spatrick return dwqe_read(sc, GMAC_MAC_MDIO_DATA); 455305ac5f9Spatrick } 456305ac5f9Spatrick 457305ac5f9Spatrick printf("%s: mii_read timeout\n", sc->sc_dev.dv_xname); 458305ac5f9Spatrick return (0); 459305ac5f9Spatrick } 460305ac5f9Spatrick 461305ac5f9Spatrick void 462305ac5f9Spatrick dwqe_mii_writereg(struct device *self, int phy, int reg, int val) 463305ac5f9Spatrick { 464305ac5f9Spatrick struct dwqe_softc *sc = (void *)self; 465305ac5f9Spatrick int n; 466305ac5f9Spatrick 467305ac5f9Spatrick dwqe_write(sc, GMAC_MAC_MDIO_DATA, val); 468305ac5f9Spatrick dwqe_write(sc, GMAC_MAC_MDIO_ADDR, 4690738886aSkettenis (sc->sc_clk << GMAC_MAC_MDIO_ADDR_CR_SHIFT) | 470305ac5f9Spatrick (phy << GMAC_MAC_MDIO_ADDR_PA_SHIFT) | 471305ac5f9Spatrick (reg << GMAC_MAC_MDIO_ADDR_RDA_SHIFT) | 472305ac5f9Spatrick GMAC_MAC_MDIO_ADDR_GOC_WRITE | 473305ac5f9Spatrick GMAC_MAC_MDIO_ADDR_GB); 4749fb70083Sdlg 4759fb70083Sdlg for (n = 0; n < 2000; n++) { 4769fb70083Sdlg delay(10); 477305ac5f9Spatrick if ((dwqe_read(sc, GMAC_MAC_MDIO_ADDR) & GMAC_MAC_MDIO_ADDR_GB) == 0) 478305ac5f9Spatrick return; 479305ac5f9Spatrick } 480305ac5f9Spatrick 481305ac5f9Spatrick printf("%s: mii_write timeout\n", sc->sc_dev.dv_xname); 482305ac5f9Spatrick } 483305ac5f9Spatrick 484305ac5f9Spatrick void 485305ac5f9Spatrick dwqe_mii_statchg(struct device *self) 486305ac5f9Spatrick { 487305ac5f9Spatrick struct dwqe_softc *sc = (void *)self; 488566e78fcSdlg struct ifnet *ifp = &sc->sc_ac.ac_if; 489305ac5f9Spatrick uint32_t conf; 490305ac5f9Spatrick 491305ac5f9Spatrick conf = dwqe_read(sc, GMAC_MAC_CONF); 492305ac5f9Spatrick conf &= ~(GMAC_MAC_CONF_PS | GMAC_MAC_CONF_FES); 493305ac5f9Spatrick 494566e78fcSdlg switch (ifp->if_baudrate) { 495566e78fcSdlg case IF_Mbps(1000): 496305ac5f9Spatrick sc->sc_link = 1; 497305ac5f9Spatrick break; 498566e78fcSdlg case IF_Mbps(100): 499305ac5f9Spatrick conf |= GMAC_MAC_CONF_PS | GMAC_MAC_CONF_FES; 500305ac5f9Spatrick sc->sc_link = 1; 501305ac5f9Spatrick break; 502566e78fcSdlg case IF_Mbps(10): 503305ac5f9Spatrick conf |= GMAC_MAC_CONF_PS; 504305ac5f9Spatrick sc->sc_link = 1; 505305ac5f9Spatrick break; 506305ac5f9Spatrick default: 507305ac5f9Spatrick sc->sc_link = 0; 508305ac5f9Spatrick return; 509305ac5f9Spatrick } 510305ac5f9Spatrick 511305ac5f9Spatrick if (sc->sc_link == 0) 512305ac5f9Spatrick return; 513305ac5f9Spatrick 514305ac5f9Spatrick conf &= ~GMAC_MAC_CONF_DM; 515566e78fcSdlg if (ifp->if_link_state == LINK_STATE_FULL_DUPLEX) 516305ac5f9Spatrick conf |= GMAC_MAC_CONF_DM; 517305ac5f9Spatrick 518305ac5f9Spatrick dwqe_write(sc, GMAC_MAC_CONF, conf); 519305ac5f9Spatrick } 520305ac5f9Spatrick 521305ac5f9Spatrick void 522305ac5f9Spatrick dwqe_tick(void *arg) 523305ac5f9Spatrick { 524305ac5f9Spatrick struct dwqe_softc *sc = arg; 525305ac5f9Spatrick int s; 526305ac5f9Spatrick 527305ac5f9Spatrick s = splnet(); 528305ac5f9Spatrick mii_tick(&sc->sc_mii); 529305ac5f9Spatrick splx(s); 530305ac5f9Spatrick 53147707f8eSdlg timeout_add_sec(&sc->sc_phy_tick, 1); 532305ac5f9Spatrick } 533305ac5f9Spatrick 534305ac5f9Spatrick void 535305ac5f9Spatrick dwqe_rxtick(void *arg) 536305ac5f9Spatrick { 537305ac5f9Spatrick struct dwqe_softc *sc = arg; 538305ac5f9Spatrick int s; 539305ac5f9Spatrick 540305ac5f9Spatrick s = splnet(); 541305ac5f9Spatrick 542305ac5f9Spatrick /* TODO: disable RXQ? */ 543305ac5f9Spatrick printf("%s:%d\n", __func__, __LINE__); 544305ac5f9Spatrick 545305ac5f9Spatrick bus_dmamap_sync(sc->sc_dmat, DWQE_DMA_MAP(sc->sc_rxring), 546305ac5f9Spatrick 0, DWQE_DMA_LEN(sc->sc_rxring), 547305ac5f9Spatrick BUS_DMASYNC_POSTREAD|BUS_DMASYNC_POSTWRITE); 548305ac5f9Spatrick 549305ac5f9Spatrick dwqe_write(sc, GMAC_CHAN_RX_BASE_ADDR_HI(0), 0); 550305ac5f9Spatrick dwqe_write(sc, GMAC_CHAN_RX_BASE_ADDR(0), 0); 551305ac5f9Spatrick 552305ac5f9Spatrick sc->sc_rx_prod = sc->sc_rx_cons = 0; 553305ac5f9Spatrick dwqe_fill_rx_ring(sc); 554305ac5f9Spatrick 555305ac5f9Spatrick bus_dmamap_sync(sc->sc_dmat, DWQE_DMA_MAP(sc->sc_rxring), 556305ac5f9Spatrick 0, DWQE_DMA_LEN(sc->sc_rxring), 557305ac5f9Spatrick BUS_DMASYNC_PREREAD|BUS_DMASYNC_PREWRITE); 558305ac5f9Spatrick 559305ac5f9Spatrick dwqe_write(sc, GMAC_CHAN_RX_BASE_ADDR_HI(0), DWQE_DMA_DVA(sc->sc_rxring) >> 32); 560305ac5f9Spatrick dwqe_write(sc, GMAC_CHAN_RX_BASE_ADDR(0), DWQE_DMA_DVA(sc->sc_rxring)); 561305ac5f9Spatrick 562305ac5f9Spatrick /* TODO: re-enable RXQ? */ 563305ac5f9Spatrick 564305ac5f9Spatrick splx(s); 565305ac5f9Spatrick } 566305ac5f9Spatrick 567305ac5f9Spatrick int 568305ac5f9Spatrick dwqe_intr(void *arg) 569305ac5f9Spatrick { 570305ac5f9Spatrick struct dwqe_softc *sc = arg; 571305ac5f9Spatrick uint32_t reg; 572305ac5f9Spatrick 573305ac5f9Spatrick reg = dwqe_read(sc, GMAC_INT_STATUS); 574305ac5f9Spatrick dwqe_write(sc, GMAC_INT_STATUS, reg); 575305ac5f9Spatrick 576305ac5f9Spatrick reg = dwqe_read(sc, GMAC_CHAN_STATUS(0)); 577305ac5f9Spatrick dwqe_write(sc, GMAC_CHAN_STATUS(0), reg); 578305ac5f9Spatrick 579305ac5f9Spatrick if (reg & GMAC_CHAN_STATUS_RI) 580305ac5f9Spatrick dwqe_rx_proc(sc); 581305ac5f9Spatrick 582305ac5f9Spatrick if (reg & GMAC_CHAN_STATUS_TI) 583305ac5f9Spatrick dwqe_tx_proc(sc); 584305ac5f9Spatrick 585305ac5f9Spatrick return (1); 586305ac5f9Spatrick } 587305ac5f9Spatrick 588305ac5f9Spatrick void 589305ac5f9Spatrick dwqe_tx_proc(struct dwqe_softc *sc) 590305ac5f9Spatrick { 591305ac5f9Spatrick struct ifnet *ifp = &sc->sc_ac.ac_if; 592305ac5f9Spatrick struct dwqe_desc *txd; 593305ac5f9Spatrick struct dwqe_buf *txb; 594305ac5f9Spatrick int idx, txfree; 595305ac5f9Spatrick 596305ac5f9Spatrick bus_dmamap_sync(sc->sc_dmat, DWQE_DMA_MAP(sc->sc_txring), 0, 597305ac5f9Spatrick DWQE_DMA_LEN(sc->sc_txring), 598305ac5f9Spatrick BUS_DMASYNC_POSTREAD | BUS_DMASYNC_POSTWRITE); 599305ac5f9Spatrick 600305ac5f9Spatrick txfree = 0; 601305ac5f9Spatrick while (sc->sc_tx_cons != sc->sc_tx_prod) { 602305ac5f9Spatrick idx = sc->sc_tx_cons; 603305ac5f9Spatrick KASSERT(idx < DWQE_NTXDESC); 604305ac5f9Spatrick 605305ac5f9Spatrick txd = &sc->sc_txdesc[idx]; 606305ac5f9Spatrick if (txd->sd_tdes3 & TDES3_OWN) 607305ac5f9Spatrick break; 608305ac5f9Spatrick 609e8974f33Skettenis if (txd->sd_tdes3 & TDES3_ES) 610e8974f33Skettenis ifp->if_oerrors++; 611e8974f33Skettenis 612305ac5f9Spatrick txb = &sc->sc_txbuf[idx]; 613305ac5f9Spatrick if (txb->tb_m) { 614305ac5f9Spatrick bus_dmamap_sync(sc->sc_dmat, txb->tb_map, 0, 615305ac5f9Spatrick txb->tb_map->dm_mapsize, BUS_DMASYNC_POSTWRITE); 616305ac5f9Spatrick bus_dmamap_unload(sc->sc_dmat, txb->tb_map); 617305ac5f9Spatrick 618305ac5f9Spatrick m_freem(txb->tb_m); 619305ac5f9Spatrick txb->tb_m = NULL; 620305ac5f9Spatrick } 621305ac5f9Spatrick 622305ac5f9Spatrick txfree++; 623305ac5f9Spatrick 624305ac5f9Spatrick if (sc->sc_tx_cons == (DWQE_NTXDESC - 1)) 625305ac5f9Spatrick sc->sc_tx_cons = 0; 626305ac5f9Spatrick else 627305ac5f9Spatrick sc->sc_tx_cons++; 628305ac5f9Spatrick 629305ac5f9Spatrick txd->sd_tdes3 = 0; 630305ac5f9Spatrick } 631305ac5f9Spatrick 632305ac5f9Spatrick if (sc->sc_tx_cons == sc->sc_tx_prod) 633305ac5f9Spatrick ifp->if_timer = 0; 634305ac5f9Spatrick 635305ac5f9Spatrick if (txfree) { 636305ac5f9Spatrick if (ifq_is_oactive(&ifp->if_snd)) 637305ac5f9Spatrick ifq_restart(&ifp->if_snd); 638305ac5f9Spatrick } 639305ac5f9Spatrick } 640305ac5f9Spatrick 641305ac5f9Spatrick void 642305ac5f9Spatrick dwqe_rx_proc(struct dwqe_softc *sc) 643305ac5f9Spatrick { 644305ac5f9Spatrick struct ifnet *ifp = &sc->sc_ac.ac_if; 645305ac5f9Spatrick struct dwqe_desc *rxd; 646305ac5f9Spatrick struct dwqe_buf *rxb; 647305ac5f9Spatrick struct mbuf_list ml = MBUF_LIST_INITIALIZER(); 648305ac5f9Spatrick struct mbuf *m; 649305ac5f9Spatrick int idx, len, cnt, put; 650305ac5f9Spatrick 651305ac5f9Spatrick if ((ifp->if_flags & IFF_RUNNING) == 0) 652305ac5f9Spatrick return; 653305ac5f9Spatrick 654305ac5f9Spatrick bus_dmamap_sync(sc->sc_dmat, DWQE_DMA_MAP(sc->sc_rxring), 0, 655305ac5f9Spatrick DWQE_DMA_LEN(sc->sc_rxring), 656305ac5f9Spatrick BUS_DMASYNC_POSTREAD | BUS_DMASYNC_POSTWRITE); 657305ac5f9Spatrick 658305ac5f9Spatrick cnt = if_rxr_inuse(&sc->sc_rx_ring); 659305ac5f9Spatrick put = 0; 660305ac5f9Spatrick while (put < cnt) { 661305ac5f9Spatrick idx = sc->sc_rx_cons; 662305ac5f9Spatrick KASSERT(idx < DWQE_NRXDESC); 663305ac5f9Spatrick 664305ac5f9Spatrick rxd = &sc->sc_rxdesc[idx]; 665305ac5f9Spatrick if (rxd->sd_tdes3 & RDES3_OWN) 666305ac5f9Spatrick break; 667305ac5f9Spatrick 668305ac5f9Spatrick len = rxd->sd_tdes3 & RDES3_LENGTH; 669305ac5f9Spatrick rxb = &sc->sc_rxbuf[idx]; 670305ac5f9Spatrick KASSERT(rxb->tb_m); 671305ac5f9Spatrick 672305ac5f9Spatrick bus_dmamap_sync(sc->sc_dmat, rxb->tb_map, 0, 673305ac5f9Spatrick len, BUS_DMASYNC_POSTREAD); 674305ac5f9Spatrick bus_dmamap_unload(sc->sc_dmat, rxb->tb_map); 675305ac5f9Spatrick 676b58ef082Skettenis m = rxb->tb_m; 677b58ef082Skettenis rxb->tb_m = NULL; 678b58ef082Skettenis 679b58ef082Skettenis if (rxd->sd_tdes3 & RDES3_ES) { 680b58ef082Skettenis ifp->if_ierrors++; 681b58ef082Skettenis m_freem(m); 682b58ef082Skettenis } else { 683305ac5f9Spatrick /* Strip off CRC. */ 684305ac5f9Spatrick len -= ETHER_CRC_LEN; 685305ac5f9Spatrick KASSERT(len > 0); 686305ac5f9Spatrick 687305ac5f9Spatrick m->m_pkthdr.len = m->m_len = len; 688305ac5f9Spatrick 689305ac5f9Spatrick ml_enqueue(&ml, m); 690b58ef082Skettenis } 691305ac5f9Spatrick 692305ac5f9Spatrick put++; 693305ac5f9Spatrick if (sc->sc_rx_cons == (DWQE_NRXDESC - 1)) 694305ac5f9Spatrick sc->sc_rx_cons = 0; 695305ac5f9Spatrick else 696305ac5f9Spatrick sc->sc_rx_cons++; 697305ac5f9Spatrick } 698305ac5f9Spatrick 699305ac5f9Spatrick if_rxr_put(&sc->sc_rx_ring, put); 700305ac5f9Spatrick if (ifiq_input(&ifp->if_rcv, &ml)) 701305ac5f9Spatrick if_rxr_livelocked(&sc->sc_rx_ring); 702305ac5f9Spatrick 703305ac5f9Spatrick dwqe_fill_rx_ring(sc); 704305ac5f9Spatrick 705305ac5f9Spatrick bus_dmamap_sync(sc->sc_dmat, DWQE_DMA_MAP(sc->sc_rxring), 0, 706305ac5f9Spatrick DWQE_DMA_LEN(sc->sc_rxring), 707305ac5f9Spatrick BUS_DMASYNC_PREREAD | BUS_DMASYNC_PREWRITE); 708305ac5f9Spatrick } 709305ac5f9Spatrick 710305ac5f9Spatrick void 711305ac5f9Spatrick dwqe_up(struct dwqe_softc *sc) 712305ac5f9Spatrick { 713305ac5f9Spatrick struct ifnet *ifp = &sc->sc_ac.ac_if; 714305ac5f9Spatrick struct dwqe_buf *txb, *rxb; 7156e9149a4Sstsp uint32_t mode, reg, fifosz, tqs, rqs; 716305ac5f9Spatrick int i; 717305ac5f9Spatrick 718305ac5f9Spatrick /* Allocate Tx descriptor ring. */ 719305ac5f9Spatrick sc->sc_txring = dwqe_dmamem_alloc(sc, 720305ac5f9Spatrick DWQE_NTXDESC * sizeof(struct dwqe_desc), 8); 721305ac5f9Spatrick sc->sc_txdesc = DWQE_DMA_KVA(sc->sc_txring); 722305ac5f9Spatrick 723305ac5f9Spatrick sc->sc_txbuf = malloc(sizeof(struct dwqe_buf) * DWQE_NTXDESC, 724305ac5f9Spatrick M_DEVBUF, M_WAITOK); 725305ac5f9Spatrick for (i = 0; i < DWQE_NTXDESC; i++) { 726305ac5f9Spatrick txb = &sc->sc_txbuf[i]; 727305ac5f9Spatrick bus_dmamap_create(sc->sc_dmat, MCLBYTES, DWQE_NTXSEGS, 728305ac5f9Spatrick MCLBYTES, 0, BUS_DMA_WAITOK, &txb->tb_map); 729305ac5f9Spatrick txb->tb_m = NULL; 730305ac5f9Spatrick } 731305ac5f9Spatrick 732305ac5f9Spatrick bus_dmamap_sync(sc->sc_dmat, DWQE_DMA_MAP(sc->sc_txring), 733305ac5f9Spatrick 0, DWQE_DMA_LEN(sc->sc_txring), BUS_DMASYNC_PREWRITE); 734305ac5f9Spatrick 735305ac5f9Spatrick sc->sc_tx_prod = sc->sc_tx_cons = 0; 736305ac5f9Spatrick 737305ac5f9Spatrick dwqe_write(sc, GMAC_CHAN_TX_BASE_ADDR_HI(0), DWQE_DMA_DVA(sc->sc_txring) >> 32); 738305ac5f9Spatrick dwqe_write(sc, GMAC_CHAN_TX_BASE_ADDR(0), DWQE_DMA_DVA(sc->sc_txring)); 739305ac5f9Spatrick dwqe_write(sc, GMAC_CHAN_TX_RING_LEN(0), DWQE_NTXDESC - 1); 740305ac5f9Spatrick dwqe_write(sc, GMAC_CHAN_TX_END_ADDR(0), DWQE_DMA_DVA(sc->sc_txring)); 741305ac5f9Spatrick 742305ac5f9Spatrick /* Allocate descriptor ring. */ 743305ac5f9Spatrick sc->sc_rxring = dwqe_dmamem_alloc(sc, 744305ac5f9Spatrick DWQE_NRXDESC * sizeof(struct dwqe_desc), 8); 745305ac5f9Spatrick sc->sc_rxdesc = DWQE_DMA_KVA(sc->sc_rxring); 746305ac5f9Spatrick 747305ac5f9Spatrick sc->sc_rxbuf = malloc(sizeof(struct dwqe_buf) * DWQE_NRXDESC, 748305ac5f9Spatrick M_DEVBUF, M_WAITOK); 749305ac5f9Spatrick 750305ac5f9Spatrick for (i = 0; i < DWQE_NRXDESC; i++) { 751305ac5f9Spatrick rxb = &sc->sc_rxbuf[i]; 752305ac5f9Spatrick bus_dmamap_create(sc->sc_dmat, MCLBYTES, 1, 753305ac5f9Spatrick MCLBYTES, 0, BUS_DMA_WAITOK, &rxb->tb_map); 754305ac5f9Spatrick rxb->tb_m = NULL; 755305ac5f9Spatrick } 756305ac5f9Spatrick 757*f51cb083Sbluhm if_rxr_init(&sc->sc_rx_ring, 2, DWQE_NRXDESC - 1); 758305ac5f9Spatrick 759305ac5f9Spatrick dwqe_write(sc, GMAC_CHAN_RX_BASE_ADDR_HI(0), DWQE_DMA_DVA(sc->sc_rxring) >> 32); 760305ac5f9Spatrick dwqe_write(sc, GMAC_CHAN_RX_BASE_ADDR(0), DWQE_DMA_DVA(sc->sc_rxring)); 761305ac5f9Spatrick dwqe_write(sc, GMAC_CHAN_RX_RING_LEN(0), DWQE_NRXDESC - 1); 762305ac5f9Spatrick 763305ac5f9Spatrick sc->sc_rx_prod = sc->sc_rx_cons = 0; 764305ac5f9Spatrick dwqe_fill_rx_ring(sc); 765305ac5f9Spatrick 766305ac5f9Spatrick bus_dmamap_sync(sc->sc_dmat, DWQE_DMA_MAP(sc->sc_rxring), 767305ac5f9Spatrick 0, DWQE_DMA_LEN(sc->sc_rxring), 768305ac5f9Spatrick BUS_DMASYNC_PREREAD|BUS_DMASYNC_PREWRITE); 769305ac5f9Spatrick 770305ac5f9Spatrick dwqe_lladdr_write(sc); 771305ac5f9Spatrick 772305ac5f9Spatrick /* Configure media. */ 773305ac5f9Spatrick if (LIST_FIRST(&sc->sc_mii.mii_phys)) 774305ac5f9Spatrick mii_mediachg(&sc->sc_mii); 775305ac5f9Spatrick 776305ac5f9Spatrick /* Program promiscuous mode and multicast filters. */ 777305ac5f9Spatrick dwqe_iff(sc); 778305ac5f9Spatrick 779305ac5f9Spatrick ifp->if_flags |= IFF_RUNNING; 780305ac5f9Spatrick ifq_clr_oactive(&ifp->if_snd); 781305ac5f9Spatrick 782b97405d6Sstsp dwqe_write(sc, GMAC_MAC_1US_TIC_CTR, (sc->sc_clkrate / 1000000) - 1); 783305ac5f9Spatrick 784305ac5f9Spatrick /* Start receive DMA */ 785305ac5f9Spatrick reg = dwqe_read(sc, GMAC_CHAN_RX_CONTROL(0)); 786305ac5f9Spatrick reg |= GMAC_CHAN_RX_CONTROL_SR; 787305ac5f9Spatrick dwqe_write(sc, GMAC_CHAN_RX_CONTROL(0), reg); 788305ac5f9Spatrick 789305ac5f9Spatrick /* Start transmit DMA */ 790305ac5f9Spatrick reg = dwqe_read(sc, GMAC_CHAN_TX_CONTROL(0)); 791305ac5f9Spatrick reg |= GMAC_CHAN_TX_CONTROL_ST; 792305ac5f9Spatrick dwqe_write(sc, GMAC_CHAN_TX_CONTROL(0), reg); 793305ac5f9Spatrick 794305ac5f9Spatrick mode = dwqe_read(sc, GMAC_MTL_CHAN_RX_OP_MODE(0)); 795305ac5f9Spatrick if (sc->sc_force_thresh_dma_mode) { 796305ac5f9Spatrick mode &= ~GMAC_MTL_CHAN_RX_OP_MODE_RSF; 797305ac5f9Spatrick mode &= ~GMAC_MTL_CHAN_RX_OP_MODE_RTC_MASK; 798305ac5f9Spatrick mode |= GMAC_MTL_CHAN_RX_OP_MODE_RTC_128; 799305ac5f9Spatrick } else { 800305ac5f9Spatrick mode |= GMAC_MTL_CHAN_RX_OP_MODE_RSF; 801305ac5f9Spatrick } 802305ac5f9Spatrick mode &= ~GMAC_MTL_CHAN_RX_OP_MODE_RQS_MASK; 8036e9149a4Sstsp if (sc->sc_rxfifo_size) 8046e9149a4Sstsp fifosz = sc->sc_rxfifo_size; 8056e9149a4Sstsp else 8066e9149a4Sstsp fifosz = (128 << 8076e9149a4Sstsp GMAC_MAC_HW_FEATURE1_RXFIFOSIZE(sc->sc_hw_feature[1])); 8086e9149a4Sstsp rqs = fifosz / 256 - 1; 8096e9149a4Sstsp mode |= (rqs << GMAC_MTL_CHAN_RX_OP_MODE_RQS_SHIFT) & 8106e9149a4Sstsp GMAC_MTL_CHAN_RX_OP_MODE_RQS_MASK; 8116e9149a4Sstsp if (fifosz >= 4096) { 8126e9149a4Sstsp mode |= GMAC_MTL_CHAN_RX_OP_MODE_EHFC; 8136e9149a4Sstsp mode &= ~GMAC_MTL_CHAN_RX_OP_MODE_RFD_MASK; 8146e9149a4Sstsp mode |= 0x3 << GMAC_MTL_CHAN_RX_OP_MODE_RFD_SHIFT; 8156e9149a4Sstsp mode &= ~GMAC_MTL_CHAN_RX_OP_MODE_RFA_MASK; 8166e9149a4Sstsp mode |= 0x1 << GMAC_MTL_CHAN_RX_OP_MODE_RFA_SHIFT; 8176e9149a4Sstsp } 818305ac5f9Spatrick dwqe_write(sc, GMAC_MTL_CHAN_RX_OP_MODE(0), mode); 819305ac5f9Spatrick 820305ac5f9Spatrick mode = dwqe_read(sc, GMAC_MTL_CHAN_TX_OP_MODE(0)); 821305ac5f9Spatrick if (sc->sc_force_thresh_dma_mode) { 822305ac5f9Spatrick mode &= ~GMAC_MTL_CHAN_TX_OP_MODE_TSF; 823305ac5f9Spatrick mode &= ~GMAC_MTL_CHAN_TX_OP_MODE_TTC_MASK; 824e8974f33Skettenis mode |= GMAC_MTL_CHAN_TX_OP_MODE_TTC_512; 825305ac5f9Spatrick } else { 826305ac5f9Spatrick mode |= GMAC_MTL_CHAN_TX_OP_MODE_TSF; 827305ac5f9Spatrick } 828305ac5f9Spatrick mode &= ~GMAC_MTL_CHAN_TX_OP_MODE_TXQEN_MASK; 829305ac5f9Spatrick mode |= GMAC_MTL_CHAN_TX_OP_MODE_TXQEN; 830305ac5f9Spatrick mode &= ~GMAC_MTL_CHAN_TX_OP_MODE_TQS_MASK; 8316e9149a4Sstsp if (sc->sc_txfifo_size) 8326e9149a4Sstsp fifosz = sc->sc_txfifo_size; 8336e9149a4Sstsp else 8346e9149a4Sstsp fifosz = (128 << 8356e9149a4Sstsp GMAC_MAC_HW_FEATURE1_TXFIFOSIZE(sc->sc_hw_feature[1])); 8366e9149a4Sstsp tqs = (fifosz / 256) - 1; 8376e9149a4Sstsp mode |= (tqs << GMAC_MTL_CHAN_TX_OP_MODE_TQS_SHIFT) & 8386e9149a4Sstsp GMAC_MTL_CHAN_TX_OP_MODE_TQS_MASK; 839305ac5f9Spatrick dwqe_write(sc, GMAC_MTL_CHAN_TX_OP_MODE(0), mode); 840305ac5f9Spatrick 841305ac5f9Spatrick reg = dwqe_read(sc, GMAC_QX_TX_FLOW_CTRL(0)); 842305ac5f9Spatrick reg |= 0xffffU << GMAC_QX_TX_FLOW_CTRL_PT_SHIFT; 843305ac5f9Spatrick reg |= GMAC_QX_TX_FLOW_CTRL_TFE; 844305ac5f9Spatrick dwqe_write(sc, GMAC_QX_TX_FLOW_CTRL(0), reg); 845305ac5f9Spatrick reg = dwqe_read(sc, GMAC_RX_FLOW_CTRL); 846305ac5f9Spatrick reg |= GMAC_RX_FLOW_CTRL_RFE; 847305ac5f9Spatrick dwqe_write(sc, GMAC_RX_FLOW_CTRL, reg); 848305ac5f9Spatrick 849305ac5f9Spatrick dwqe_write(sc, GMAC_RXQ_CTRL0, GMAC_RXQ_CTRL0_DCB_QUEUE_EN(0)); 850305ac5f9Spatrick 851305ac5f9Spatrick dwqe_write(sc, GMAC_MAC_CONF, dwqe_read(sc, GMAC_MAC_CONF) | 852305ac5f9Spatrick GMAC_MAC_CONF_BE | GMAC_MAC_CONF_JD | GMAC_MAC_CONF_JE | 853305ac5f9Spatrick GMAC_MAC_CONF_DCRS | GMAC_MAC_CONF_TE | GMAC_MAC_CONF_RE); 854305ac5f9Spatrick 855305ac5f9Spatrick dwqe_write(sc, GMAC_CHAN_INTR_ENA(0), 856305ac5f9Spatrick GMAC_CHAN_INTR_ENA_NIE | 857305ac5f9Spatrick GMAC_CHAN_INTR_ENA_AIE | 858305ac5f9Spatrick GMAC_CHAN_INTR_ENA_FBE | 859305ac5f9Spatrick GMAC_CHAN_INTR_ENA_RIE | 860305ac5f9Spatrick GMAC_CHAN_INTR_ENA_TIE); 861305ac5f9Spatrick 86245f5f3c8Sdlg if (!sc->sc_fixed_link) 86347707f8eSdlg timeout_add_sec(&sc->sc_phy_tick, 1); 864305ac5f9Spatrick } 865305ac5f9Spatrick 866305ac5f9Spatrick void 867305ac5f9Spatrick dwqe_down(struct dwqe_softc *sc) 868305ac5f9Spatrick { 869305ac5f9Spatrick struct ifnet *ifp = &sc->sc_ac.ac_if; 870305ac5f9Spatrick struct dwqe_buf *txb, *rxb; 871305ac5f9Spatrick uint32_t reg; 872305ac5f9Spatrick int i; 873305ac5f9Spatrick 874305ac5f9Spatrick timeout_del(&sc->sc_rxto); 87545f5f3c8Sdlg if (!sc->sc_fixed_link) 87647707f8eSdlg timeout_del(&sc->sc_phy_tick); 877305ac5f9Spatrick 878305ac5f9Spatrick ifp->if_flags &= ~IFF_RUNNING; 879305ac5f9Spatrick ifq_clr_oactive(&ifp->if_snd); 880305ac5f9Spatrick ifp->if_timer = 0; 881305ac5f9Spatrick 882305ac5f9Spatrick /* Disable receiver */ 883305ac5f9Spatrick reg = dwqe_read(sc, GMAC_MAC_CONF); 884305ac5f9Spatrick reg &= ~GMAC_MAC_CONF_RE; 885305ac5f9Spatrick dwqe_write(sc, GMAC_MAC_CONF, reg); 886305ac5f9Spatrick 887305ac5f9Spatrick /* Stop receive DMA */ 888305ac5f9Spatrick reg = dwqe_read(sc, GMAC_CHAN_RX_CONTROL(0)); 889305ac5f9Spatrick reg &= ~GMAC_CHAN_RX_CONTROL_SR; 890305ac5f9Spatrick dwqe_write(sc, GMAC_CHAN_RX_CONTROL(0), reg); 891305ac5f9Spatrick 892305ac5f9Spatrick /* Stop transmit DMA */ 893305ac5f9Spatrick reg = dwqe_read(sc, GMAC_CHAN_TX_CONTROL(0)); 894305ac5f9Spatrick reg &= ~GMAC_CHAN_TX_CONTROL_ST; 895305ac5f9Spatrick dwqe_write(sc, GMAC_CHAN_TX_CONTROL(0), reg); 896305ac5f9Spatrick 897305ac5f9Spatrick /* Flush data in the TX FIFO */ 898305ac5f9Spatrick reg = dwqe_read(sc, GMAC_MTL_CHAN_TX_OP_MODE(0)); 899305ac5f9Spatrick reg |= GMAC_MTL_CHAN_TX_OP_MODE_FTQ; 900305ac5f9Spatrick dwqe_write(sc, GMAC_MTL_CHAN_TX_OP_MODE(0), reg); 901305ac5f9Spatrick /* Wait for flush to complete */ 902305ac5f9Spatrick for (i = 10000; i > 0; i--) { 903305ac5f9Spatrick reg = dwqe_read(sc, GMAC_MTL_CHAN_TX_OP_MODE(0)); 904305ac5f9Spatrick if ((reg & GMAC_MTL_CHAN_TX_OP_MODE_FTQ) == 0) 905305ac5f9Spatrick break; 906305ac5f9Spatrick delay(1); 907305ac5f9Spatrick } 908305ac5f9Spatrick if (i == 0) { 909305ac5f9Spatrick printf("%s: timeout flushing TX queue\n", 910305ac5f9Spatrick sc->sc_dev.dv_xname); 911305ac5f9Spatrick } 912305ac5f9Spatrick 913305ac5f9Spatrick /* Disable transmitter */ 914305ac5f9Spatrick reg = dwqe_read(sc, GMAC_MAC_CONF); 915305ac5f9Spatrick reg &= ~GMAC_MAC_CONF_TE; 916305ac5f9Spatrick dwqe_write(sc, GMAC_MAC_CONF, reg); 917305ac5f9Spatrick 918305ac5f9Spatrick dwqe_write(sc, GMAC_CHAN_INTR_ENA(0), 0); 919305ac5f9Spatrick 920305ac5f9Spatrick intr_barrier(sc->sc_ih); 921305ac5f9Spatrick ifq_barrier(&ifp->if_snd); 922305ac5f9Spatrick 923305ac5f9Spatrick for (i = 0; i < DWQE_NTXDESC; i++) { 924305ac5f9Spatrick txb = &sc->sc_txbuf[i]; 925305ac5f9Spatrick if (txb->tb_m) { 926305ac5f9Spatrick bus_dmamap_sync(sc->sc_dmat, txb->tb_map, 0, 927305ac5f9Spatrick txb->tb_map->dm_mapsize, BUS_DMASYNC_POSTWRITE); 928305ac5f9Spatrick bus_dmamap_unload(sc->sc_dmat, txb->tb_map); 929305ac5f9Spatrick m_freem(txb->tb_m); 930305ac5f9Spatrick } 931305ac5f9Spatrick bus_dmamap_destroy(sc->sc_dmat, txb->tb_map); 932305ac5f9Spatrick } 933305ac5f9Spatrick 934305ac5f9Spatrick dwqe_dmamem_free(sc, sc->sc_txring); 935305ac5f9Spatrick free(sc->sc_txbuf, M_DEVBUF, 0); 936305ac5f9Spatrick 937305ac5f9Spatrick for (i = 0; i < DWQE_NRXDESC; i++) { 938305ac5f9Spatrick rxb = &sc->sc_rxbuf[i]; 939305ac5f9Spatrick if (rxb->tb_m) { 940305ac5f9Spatrick bus_dmamap_sync(sc->sc_dmat, rxb->tb_map, 0, 941305ac5f9Spatrick rxb->tb_map->dm_mapsize, BUS_DMASYNC_POSTREAD); 942305ac5f9Spatrick bus_dmamap_unload(sc->sc_dmat, rxb->tb_map); 943305ac5f9Spatrick m_freem(rxb->tb_m); 944305ac5f9Spatrick } 945305ac5f9Spatrick bus_dmamap_destroy(sc->sc_dmat, rxb->tb_map); 946305ac5f9Spatrick } 947305ac5f9Spatrick 948305ac5f9Spatrick dwqe_dmamem_free(sc, sc->sc_rxring); 949305ac5f9Spatrick free(sc->sc_rxbuf, M_DEVBUF, 0); 950305ac5f9Spatrick } 951305ac5f9Spatrick 952305ac5f9Spatrick /* Bit Reversal - http://aggregate.org/MAGIC/#Bit%20Reversal */ 953305ac5f9Spatrick static uint32_t 954305ac5f9Spatrick bitrev32(uint32_t x) 955305ac5f9Spatrick { 956305ac5f9Spatrick x = (((x & 0xaaaaaaaa) >> 1) | ((x & 0x55555555) << 1)); 957305ac5f9Spatrick x = (((x & 0xcccccccc) >> 2) | ((x & 0x33333333) << 2)); 958305ac5f9Spatrick x = (((x & 0xf0f0f0f0) >> 4) | ((x & 0x0f0f0f0f) << 4)); 959305ac5f9Spatrick x = (((x & 0xff00ff00) >> 8) | ((x & 0x00ff00ff) << 8)); 960305ac5f9Spatrick 961305ac5f9Spatrick return (x >> 16) | (x << 16); 962305ac5f9Spatrick } 963305ac5f9Spatrick 964305ac5f9Spatrick void 965305ac5f9Spatrick dwqe_iff(struct dwqe_softc *sc) 966305ac5f9Spatrick { 967305ac5f9Spatrick struct arpcom *ac = &sc->sc_ac; 968305ac5f9Spatrick struct ifnet *ifp = &sc->sc_ac.ac_if; 969305ac5f9Spatrick struct ether_multi *enm; 970305ac5f9Spatrick struct ether_multistep step; 971305ac5f9Spatrick uint32_t crc, hash[2], hashbit, hashreg; 972305ac5f9Spatrick uint32_t reg; 973305ac5f9Spatrick 974305ac5f9Spatrick reg = 0; 975305ac5f9Spatrick 976305ac5f9Spatrick ifp->if_flags &= ~IFF_ALLMULTI; 977305ac5f9Spatrick bzero(hash, sizeof(hash)); 978305ac5f9Spatrick if (ifp->if_flags & IFF_PROMISC || ac->ac_multirangecnt > 0) { 979305ac5f9Spatrick ifp->if_flags |= IFF_ALLMULTI; 980305ac5f9Spatrick reg |= GMAC_MAC_PACKET_FILTER_PM; 981305ac5f9Spatrick if (ifp->if_flags & IFF_PROMISC) 982305ac5f9Spatrick reg |= GMAC_MAC_PACKET_FILTER_PR | 983305ac5f9Spatrick GMAC_MAC_PACKET_FILTER_PCF_ALL; 984305ac5f9Spatrick } else { 985305ac5f9Spatrick reg |= GMAC_MAC_PACKET_FILTER_HMC; 986305ac5f9Spatrick ETHER_FIRST_MULTI(step, ac, enm); 987305ac5f9Spatrick while (enm != NULL) { 988305ac5f9Spatrick crc = ether_crc32_le(enm->enm_addrlo, 989305ac5f9Spatrick ETHER_ADDR_LEN) & 0x7f; 990305ac5f9Spatrick 991305ac5f9Spatrick crc = bitrev32(~crc) >> 26; 992305ac5f9Spatrick hashreg = (crc >> 5); 993305ac5f9Spatrick hashbit = (crc & 0x1f); 994305ac5f9Spatrick hash[hashreg] |= (1 << hashbit); 995305ac5f9Spatrick 996305ac5f9Spatrick ETHER_NEXT_MULTI(step, enm); 997305ac5f9Spatrick } 998305ac5f9Spatrick } 999305ac5f9Spatrick 1000305ac5f9Spatrick dwqe_lladdr_write(sc); 1001305ac5f9Spatrick 1002305ac5f9Spatrick dwqe_write(sc, GMAC_MAC_HASH_TAB_REG0, hash[0]); 1003305ac5f9Spatrick dwqe_write(sc, GMAC_MAC_HASH_TAB_REG1, hash[1]); 1004305ac5f9Spatrick 1005305ac5f9Spatrick dwqe_write(sc, GMAC_MAC_PACKET_FILTER, reg); 1006305ac5f9Spatrick } 1007305ac5f9Spatrick 1008305ac5f9Spatrick int 1009305ac5f9Spatrick dwqe_encap(struct dwqe_softc *sc, struct mbuf *m, int *idx, int *used) 1010305ac5f9Spatrick { 1011305ac5f9Spatrick struct dwqe_desc *txd, *txd_start; 1012305ac5f9Spatrick bus_dmamap_t map; 1013305ac5f9Spatrick int cur, frag, i; 1014305ac5f9Spatrick 1015305ac5f9Spatrick cur = frag = *idx; 1016305ac5f9Spatrick map = sc->sc_txbuf[cur].tb_map; 1017305ac5f9Spatrick 1018305ac5f9Spatrick if (bus_dmamap_load_mbuf(sc->sc_dmat, map, m, BUS_DMA_NOWAIT)) { 1019305ac5f9Spatrick if (m_defrag(m, M_DONTWAIT)) 1020305ac5f9Spatrick return (EFBIG); 1021305ac5f9Spatrick if (bus_dmamap_load_mbuf(sc->sc_dmat, map, m, BUS_DMA_NOWAIT)) 1022305ac5f9Spatrick return (EFBIG); 1023305ac5f9Spatrick } 1024305ac5f9Spatrick 1025305ac5f9Spatrick /* Sync the DMA map. */ 1026305ac5f9Spatrick bus_dmamap_sync(sc->sc_dmat, map, 0, map->dm_mapsize, 1027305ac5f9Spatrick BUS_DMASYNC_PREWRITE); 1028305ac5f9Spatrick 1029305ac5f9Spatrick txd = txd_start = &sc->sc_txdesc[frag]; 1030305ac5f9Spatrick for (i = 0; i < map->dm_nsegs; i++) { 1031305ac5f9Spatrick /* TODO: check for 32-bit vs 64-bit support */ 1032305ac5f9Spatrick KASSERT((map->dm_segs[i].ds_addr >> 32) == 0); 1033305ac5f9Spatrick 1034305ac5f9Spatrick txd->sd_tdes0 = (uint32_t)map->dm_segs[i].ds_addr; 1035305ac5f9Spatrick txd->sd_tdes1 = (uint32_t)(map->dm_segs[i].ds_addr >> 32); 1036305ac5f9Spatrick txd->sd_tdes2 = map->dm_segs[i].ds_len; 1037305ac5f9Spatrick txd->sd_tdes3 = m->m_pkthdr.len; 1038305ac5f9Spatrick if (i == 0) 1039305ac5f9Spatrick txd->sd_tdes3 |= TDES3_FS; 1040305ac5f9Spatrick if (i == (map->dm_nsegs - 1)) { 1041305ac5f9Spatrick txd->sd_tdes2 |= TDES2_IC; 1042305ac5f9Spatrick txd->sd_tdes3 |= TDES3_LS; 1043305ac5f9Spatrick } 1044305ac5f9Spatrick if (i != 0) 1045305ac5f9Spatrick txd->sd_tdes3 |= TDES3_OWN; 1046305ac5f9Spatrick 1047305ac5f9Spatrick bus_dmamap_sync(sc->sc_dmat, DWQE_DMA_MAP(sc->sc_txring), 1048305ac5f9Spatrick frag * sizeof(*txd), sizeof(*txd), BUS_DMASYNC_PREWRITE); 1049305ac5f9Spatrick 1050305ac5f9Spatrick cur = frag; 1051305ac5f9Spatrick if (frag == (DWQE_NTXDESC - 1)) { 1052305ac5f9Spatrick txd = &sc->sc_txdesc[0]; 1053305ac5f9Spatrick frag = 0; 1054305ac5f9Spatrick } else { 1055305ac5f9Spatrick txd++; 1056305ac5f9Spatrick frag++; 1057305ac5f9Spatrick } 1058305ac5f9Spatrick KASSERT(frag != sc->sc_tx_cons); 1059305ac5f9Spatrick } 1060305ac5f9Spatrick 1061305ac5f9Spatrick txd_start->sd_tdes3 |= TDES3_OWN; 1062305ac5f9Spatrick bus_dmamap_sync(sc->sc_dmat, DWQE_DMA_MAP(sc->sc_txring), 1063305ac5f9Spatrick *idx * sizeof(*txd), sizeof(*txd), BUS_DMASYNC_PREWRITE); 1064305ac5f9Spatrick 1065305ac5f9Spatrick KASSERT(sc->sc_txbuf[cur].tb_m == NULL); 1066305ac5f9Spatrick sc->sc_txbuf[*idx].tb_map = sc->sc_txbuf[cur].tb_map; 1067305ac5f9Spatrick sc->sc_txbuf[cur].tb_map = map; 1068305ac5f9Spatrick sc->sc_txbuf[cur].tb_m = m; 1069305ac5f9Spatrick 1070305ac5f9Spatrick *idx = frag; 1071305ac5f9Spatrick *used += map->dm_nsegs; 1072305ac5f9Spatrick 1073305ac5f9Spatrick return (0); 1074305ac5f9Spatrick } 1075305ac5f9Spatrick 1076305ac5f9Spatrick void 1077305ac5f9Spatrick dwqe_reset(struct dwqe_softc *sc) 1078305ac5f9Spatrick { 1079305ac5f9Spatrick int n; 1080305ac5f9Spatrick 1081305ac5f9Spatrick dwqe_write(sc, GMAC_BUS_MODE, dwqe_read(sc, GMAC_BUS_MODE) | 1082305ac5f9Spatrick GMAC_BUS_MODE_SWR); 1083305ac5f9Spatrick 1084305ac5f9Spatrick for (n = 0; n < 30000; n++) { 1085305ac5f9Spatrick if ((dwqe_read(sc, GMAC_BUS_MODE) & 1086305ac5f9Spatrick GMAC_BUS_MODE_SWR) == 0) 1087305ac5f9Spatrick return; 1088305ac5f9Spatrick delay(10); 1089305ac5f9Spatrick } 1090305ac5f9Spatrick 1091305ac5f9Spatrick printf("%s: reset timeout\n", sc->sc_dev.dv_xname); 1092305ac5f9Spatrick } 1093305ac5f9Spatrick 1094305ac5f9Spatrick struct dwqe_dmamem * 1095305ac5f9Spatrick dwqe_dmamem_alloc(struct dwqe_softc *sc, bus_size_t size, bus_size_t align) 1096305ac5f9Spatrick { 1097305ac5f9Spatrick struct dwqe_dmamem *tdm; 1098305ac5f9Spatrick int nsegs; 1099305ac5f9Spatrick 1100305ac5f9Spatrick tdm = malloc(sizeof(*tdm), M_DEVBUF, M_WAITOK | M_ZERO); 1101305ac5f9Spatrick tdm->tdm_size = size; 1102305ac5f9Spatrick 1103305ac5f9Spatrick if (bus_dmamap_create(sc->sc_dmat, size, 1, size, 0, 1104305ac5f9Spatrick BUS_DMA_WAITOK | BUS_DMA_ALLOCNOW, &tdm->tdm_map) != 0) 1105305ac5f9Spatrick goto tdmfree; 1106305ac5f9Spatrick 1107305ac5f9Spatrick if (bus_dmamem_alloc(sc->sc_dmat, size, align, 0, &tdm->tdm_seg, 1, 1108305ac5f9Spatrick &nsegs, BUS_DMA_WAITOK) != 0) 1109305ac5f9Spatrick goto destroy; 1110305ac5f9Spatrick 1111305ac5f9Spatrick if (bus_dmamem_map(sc->sc_dmat, &tdm->tdm_seg, nsegs, size, 1112305ac5f9Spatrick &tdm->tdm_kva, BUS_DMA_WAITOK | BUS_DMA_COHERENT) != 0) 1113305ac5f9Spatrick goto free; 1114305ac5f9Spatrick 1115305ac5f9Spatrick if (bus_dmamap_load(sc->sc_dmat, tdm->tdm_map, tdm->tdm_kva, size, 1116305ac5f9Spatrick NULL, BUS_DMA_WAITOK) != 0) 1117305ac5f9Spatrick goto unmap; 1118305ac5f9Spatrick 1119305ac5f9Spatrick bzero(tdm->tdm_kva, size); 1120305ac5f9Spatrick 1121305ac5f9Spatrick return (tdm); 1122305ac5f9Spatrick 1123305ac5f9Spatrick unmap: 1124305ac5f9Spatrick bus_dmamem_unmap(sc->sc_dmat, tdm->tdm_kva, size); 1125305ac5f9Spatrick free: 1126305ac5f9Spatrick bus_dmamem_free(sc->sc_dmat, &tdm->tdm_seg, 1); 1127305ac5f9Spatrick destroy: 1128305ac5f9Spatrick bus_dmamap_destroy(sc->sc_dmat, tdm->tdm_map); 1129305ac5f9Spatrick tdmfree: 1130305ac5f9Spatrick free(tdm, M_DEVBUF, 0); 1131305ac5f9Spatrick 1132305ac5f9Spatrick return (NULL); 1133305ac5f9Spatrick } 1134305ac5f9Spatrick 1135305ac5f9Spatrick void 1136305ac5f9Spatrick dwqe_dmamem_free(struct dwqe_softc *sc, struct dwqe_dmamem *tdm) 1137305ac5f9Spatrick { 1138305ac5f9Spatrick bus_dmamem_unmap(sc->sc_dmat, tdm->tdm_kva, tdm->tdm_size); 1139305ac5f9Spatrick bus_dmamem_free(sc->sc_dmat, &tdm->tdm_seg, 1); 1140305ac5f9Spatrick bus_dmamap_destroy(sc->sc_dmat, tdm->tdm_map); 1141305ac5f9Spatrick free(tdm, M_DEVBUF, 0); 1142305ac5f9Spatrick } 1143305ac5f9Spatrick 1144305ac5f9Spatrick struct mbuf * 1145305ac5f9Spatrick dwqe_alloc_mbuf(struct dwqe_softc *sc, bus_dmamap_t map) 1146305ac5f9Spatrick { 1147305ac5f9Spatrick struct mbuf *m = NULL; 1148305ac5f9Spatrick 1149305ac5f9Spatrick m = MCLGETL(NULL, M_DONTWAIT, MCLBYTES); 1150305ac5f9Spatrick if (!m) 1151305ac5f9Spatrick return (NULL); 1152305ac5f9Spatrick m->m_len = m->m_pkthdr.len = MCLBYTES; 1153305ac5f9Spatrick m_adj(m, ETHER_ALIGN); 1154305ac5f9Spatrick 1155305ac5f9Spatrick if (bus_dmamap_load_mbuf(sc->sc_dmat, map, m, BUS_DMA_NOWAIT) != 0) { 1156305ac5f9Spatrick printf("%s: could not load mbuf DMA map", DEVNAME(sc)); 1157305ac5f9Spatrick m_freem(m); 1158305ac5f9Spatrick return (NULL); 1159305ac5f9Spatrick } 1160305ac5f9Spatrick 1161305ac5f9Spatrick bus_dmamap_sync(sc->sc_dmat, map, 0, 1162305ac5f9Spatrick m->m_pkthdr.len, BUS_DMASYNC_PREREAD); 1163305ac5f9Spatrick 1164305ac5f9Spatrick return (m); 1165305ac5f9Spatrick } 1166305ac5f9Spatrick 1167305ac5f9Spatrick void 1168305ac5f9Spatrick dwqe_fill_rx_ring(struct dwqe_softc *sc) 1169305ac5f9Spatrick { 1170305ac5f9Spatrick struct dwqe_desc *rxd; 1171305ac5f9Spatrick struct dwqe_buf *rxb; 1172305ac5f9Spatrick u_int slots; 1173305ac5f9Spatrick 1174305ac5f9Spatrick for (slots = if_rxr_get(&sc->sc_rx_ring, DWQE_NRXDESC); 1175305ac5f9Spatrick slots > 0; slots--) { 1176305ac5f9Spatrick rxb = &sc->sc_rxbuf[sc->sc_rx_prod]; 1177305ac5f9Spatrick rxb->tb_m = dwqe_alloc_mbuf(sc, rxb->tb_map); 1178305ac5f9Spatrick if (rxb->tb_m == NULL) 1179305ac5f9Spatrick break; 1180305ac5f9Spatrick 1181305ac5f9Spatrick /* TODO: check for 32-bit vs 64-bit support */ 11824fa84378Skettenis KASSERT((rxb->tb_map->dm_segs[0].ds_addr >> 32) == 0); 1183305ac5f9Spatrick 1184305ac5f9Spatrick rxd = &sc->sc_rxdesc[sc->sc_rx_prod]; 11854fa84378Skettenis rxd->sd_tdes0 = (uint32_t)rxb->tb_map->dm_segs[0].ds_addr; 11864fa84378Skettenis rxd->sd_tdes1 = (uint32_t)(rxb->tb_map->dm_segs[0].ds_addr >> 32); 1187305ac5f9Spatrick rxd->sd_tdes2 = 0; 1188305ac5f9Spatrick rxd->sd_tdes3 = RDES3_OWN | RDES3_IC | RDES3_BUF1V; 1189305ac5f9Spatrick 1190305ac5f9Spatrick if (sc->sc_rx_prod == (DWQE_NRXDESC - 1)) 1191305ac5f9Spatrick sc->sc_rx_prod = 0; 1192305ac5f9Spatrick else 1193305ac5f9Spatrick sc->sc_rx_prod++; 1194305ac5f9Spatrick } 1195305ac5f9Spatrick if_rxr_put(&sc->sc_rx_ring, slots); 1196305ac5f9Spatrick 1197305ac5f9Spatrick dwqe_write(sc, GMAC_CHAN_RX_END_ADDR(0), DWQE_DMA_DVA(sc->sc_rxring) + 1198305ac5f9Spatrick sc->sc_rx_prod * sizeof(*rxd)); 1199305ac5f9Spatrick 1200305ac5f9Spatrick if (if_rxr_inuse(&sc->sc_rx_ring) == 0) 1201305ac5f9Spatrick timeout_add(&sc->sc_rxto, 1); 1202305ac5f9Spatrick } 1203