1*6e9149a4Sstsp /* $OpenBSD: dwqe.c,v 1.14 2023/10/11 12:52:00 stsp 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; 120305ac5f9Spatrick ifq_set_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 341305ac5f9Spatrick if (sc->sc_tx_prod != idx) { 342305ac5f9Spatrick sc->sc_tx_prod = idx; 343305ac5f9Spatrick 344305ac5f9Spatrick /* Set a timeout in case the chip goes out to lunch. */ 345305ac5f9Spatrick ifp->if_timer = 5; 346305ac5f9Spatrick } 347305ac5f9Spatrick } 348305ac5f9Spatrick 349305ac5f9Spatrick int 350305ac5f9Spatrick dwqe_ioctl(struct ifnet *ifp, u_long cmd, caddr_t addr) 351305ac5f9Spatrick { 352305ac5f9Spatrick struct dwqe_softc *sc = ifp->if_softc; 353305ac5f9Spatrick struct ifreq *ifr = (struct ifreq *)addr; 354305ac5f9Spatrick int error = 0, s; 355305ac5f9Spatrick 356305ac5f9Spatrick s = splnet(); 357305ac5f9Spatrick 358305ac5f9Spatrick switch (cmd) { 359305ac5f9Spatrick case SIOCSIFADDR: 360305ac5f9Spatrick ifp->if_flags |= IFF_UP; 361305ac5f9Spatrick /* FALLTHROUGH */ 362305ac5f9Spatrick case SIOCSIFFLAGS: 363305ac5f9Spatrick if (ifp->if_flags & IFF_UP) { 364305ac5f9Spatrick if (ifp->if_flags & IFF_RUNNING) 365305ac5f9Spatrick error = ENETRESET; 366305ac5f9Spatrick else 367305ac5f9Spatrick dwqe_up(sc); 368305ac5f9Spatrick } else { 369305ac5f9Spatrick if (ifp->if_flags & IFF_RUNNING) 370305ac5f9Spatrick dwqe_down(sc); 371305ac5f9Spatrick } 372305ac5f9Spatrick break; 373305ac5f9Spatrick 374305ac5f9Spatrick case SIOCGIFMEDIA: 375305ac5f9Spatrick case SIOCSIFMEDIA: 37645f5f3c8Sdlg if (sc->sc_fixed_link) 37745f5f3c8Sdlg error = ENOTTY; 37845f5f3c8Sdlg else 379305ac5f9Spatrick error = ifmedia_ioctl(ifp, ifr, &sc->sc_media, cmd); 380305ac5f9Spatrick break; 381305ac5f9Spatrick 382305ac5f9Spatrick case SIOCGIFRXR: 383305ac5f9Spatrick error = if_rxr_ioctl((struct if_rxrinfo *)ifr->ifr_data, 384305ac5f9Spatrick NULL, MCLBYTES, &sc->sc_rx_ring); 385305ac5f9Spatrick break; 386305ac5f9Spatrick 387305ac5f9Spatrick default: 388305ac5f9Spatrick error = ether_ioctl(ifp, &sc->sc_ac, cmd, addr); 389305ac5f9Spatrick break; 390305ac5f9Spatrick } 391305ac5f9Spatrick 392305ac5f9Spatrick if (error == ENETRESET) { 393305ac5f9Spatrick if (ifp->if_flags & IFF_RUNNING) 394305ac5f9Spatrick dwqe_iff(sc); 395305ac5f9Spatrick error = 0; 396305ac5f9Spatrick } 397305ac5f9Spatrick 398305ac5f9Spatrick splx(s); 399305ac5f9Spatrick return (error); 400305ac5f9Spatrick } 401305ac5f9Spatrick 402305ac5f9Spatrick void 403305ac5f9Spatrick dwqe_watchdog(struct ifnet *ifp) 404305ac5f9Spatrick { 405305ac5f9Spatrick printf("%s\n", __func__); 406305ac5f9Spatrick } 407305ac5f9Spatrick 408305ac5f9Spatrick int 409305ac5f9Spatrick dwqe_media_change(struct ifnet *ifp) 410305ac5f9Spatrick { 411305ac5f9Spatrick struct dwqe_softc *sc = ifp->if_softc; 412305ac5f9Spatrick 413305ac5f9Spatrick if (LIST_FIRST(&sc->sc_mii.mii_phys)) 414305ac5f9Spatrick mii_mediachg(&sc->sc_mii); 415305ac5f9Spatrick 416305ac5f9Spatrick return (0); 417305ac5f9Spatrick } 418305ac5f9Spatrick 419305ac5f9Spatrick void 420305ac5f9Spatrick dwqe_media_status(struct ifnet *ifp, struct ifmediareq *ifmr) 421305ac5f9Spatrick { 422305ac5f9Spatrick struct dwqe_softc *sc = ifp->if_softc; 423305ac5f9Spatrick 424305ac5f9Spatrick if (LIST_FIRST(&sc->sc_mii.mii_phys)) { 425305ac5f9Spatrick mii_pollstat(&sc->sc_mii); 426305ac5f9Spatrick ifmr->ifm_active = sc->sc_mii.mii_media_active; 427305ac5f9Spatrick ifmr->ifm_status = sc->sc_mii.mii_media_status; 428305ac5f9Spatrick } 429305ac5f9Spatrick } 430305ac5f9Spatrick 431305ac5f9Spatrick int 432305ac5f9Spatrick dwqe_mii_readreg(struct device *self, int phy, int reg) 433305ac5f9Spatrick { 434305ac5f9Spatrick struct dwqe_softc *sc = (void *)self; 435305ac5f9Spatrick int n; 436305ac5f9Spatrick 437305ac5f9Spatrick dwqe_write(sc, GMAC_MAC_MDIO_ADDR, 4380738886aSkettenis (sc->sc_clk << GMAC_MAC_MDIO_ADDR_CR_SHIFT) | 439305ac5f9Spatrick (phy << GMAC_MAC_MDIO_ADDR_PA_SHIFT) | 440305ac5f9Spatrick (reg << GMAC_MAC_MDIO_ADDR_RDA_SHIFT) | 441305ac5f9Spatrick GMAC_MAC_MDIO_ADDR_GOC_READ | 442305ac5f9Spatrick GMAC_MAC_MDIO_ADDR_GB); 443305ac5f9Spatrick 4449fb70083Sdlg for (n = 0; n < 2000; n++) { 4459fb70083Sdlg delay(10); 446305ac5f9Spatrick if ((dwqe_read(sc, GMAC_MAC_MDIO_ADDR) & GMAC_MAC_MDIO_ADDR_GB) == 0) 447305ac5f9Spatrick return dwqe_read(sc, GMAC_MAC_MDIO_DATA); 448305ac5f9Spatrick } 449305ac5f9Spatrick 450305ac5f9Spatrick printf("%s: mii_read timeout\n", sc->sc_dev.dv_xname); 451305ac5f9Spatrick return (0); 452305ac5f9Spatrick } 453305ac5f9Spatrick 454305ac5f9Spatrick void 455305ac5f9Spatrick dwqe_mii_writereg(struct device *self, int phy, int reg, int val) 456305ac5f9Spatrick { 457305ac5f9Spatrick struct dwqe_softc *sc = (void *)self; 458305ac5f9Spatrick int n; 459305ac5f9Spatrick 460305ac5f9Spatrick dwqe_write(sc, GMAC_MAC_MDIO_DATA, val); 461305ac5f9Spatrick dwqe_write(sc, GMAC_MAC_MDIO_ADDR, 4620738886aSkettenis (sc->sc_clk << GMAC_MAC_MDIO_ADDR_CR_SHIFT) | 463305ac5f9Spatrick (phy << GMAC_MAC_MDIO_ADDR_PA_SHIFT) | 464305ac5f9Spatrick (reg << GMAC_MAC_MDIO_ADDR_RDA_SHIFT) | 465305ac5f9Spatrick GMAC_MAC_MDIO_ADDR_GOC_WRITE | 466305ac5f9Spatrick GMAC_MAC_MDIO_ADDR_GB); 4679fb70083Sdlg 4689fb70083Sdlg for (n = 0; n < 2000; n++) { 4699fb70083Sdlg delay(10); 470305ac5f9Spatrick if ((dwqe_read(sc, GMAC_MAC_MDIO_ADDR) & GMAC_MAC_MDIO_ADDR_GB) == 0) 471305ac5f9Spatrick return; 472305ac5f9Spatrick } 473305ac5f9Spatrick 474305ac5f9Spatrick printf("%s: mii_write timeout\n", sc->sc_dev.dv_xname); 475305ac5f9Spatrick } 476305ac5f9Spatrick 477305ac5f9Spatrick void 478305ac5f9Spatrick dwqe_mii_statchg(struct device *self) 479305ac5f9Spatrick { 480305ac5f9Spatrick struct dwqe_softc *sc = (void *)self; 481566e78fcSdlg struct ifnet *ifp = &sc->sc_ac.ac_if; 482305ac5f9Spatrick uint32_t conf; 483305ac5f9Spatrick 484305ac5f9Spatrick conf = dwqe_read(sc, GMAC_MAC_CONF); 485305ac5f9Spatrick conf &= ~(GMAC_MAC_CONF_PS | GMAC_MAC_CONF_FES); 486305ac5f9Spatrick 487566e78fcSdlg switch (ifp->if_baudrate) { 488566e78fcSdlg case IF_Mbps(1000): 489305ac5f9Spatrick sc->sc_link = 1; 490305ac5f9Spatrick break; 491566e78fcSdlg case IF_Mbps(100): 492305ac5f9Spatrick conf |= GMAC_MAC_CONF_PS | GMAC_MAC_CONF_FES; 493305ac5f9Spatrick sc->sc_link = 1; 494305ac5f9Spatrick break; 495566e78fcSdlg case IF_Mbps(10): 496305ac5f9Spatrick conf |= GMAC_MAC_CONF_PS; 497305ac5f9Spatrick sc->sc_link = 1; 498305ac5f9Spatrick break; 499305ac5f9Spatrick default: 500305ac5f9Spatrick sc->sc_link = 0; 501305ac5f9Spatrick return; 502305ac5f9Spatrick } 503305ac5f9Spatrick 504305ac5f9Spatrick if (sc->sc_link == 0) 505305ac5f9Spatrick return; 506305ac5f9Spatrick 507305ac5f9Spatrick conf &= ~GMAC_MAC_CONF_DM; 508566e78fcSdlg if (ifp->if_link_state == LINK_STATE_FULL_DUPLEX) 509305ac5f9Spatrick conf |= GMAC_MAC_CONF_DM; 510305ac5f9Spatrick 511305ac5f9Spatrick dwqe_write(sc, GMAC_MAC_CONF, conf); 512305ac5f9Spatrick } 513305ac5f9Spatrick 514305ac5f9Spatrick void 515305ac5f9Spatrick dwqe_tick(void *arg) 516305ac5f9Spatrick { 517305ac5f9Spatrick struct dwqe_softc *sc = arg; 518305ac5f9Spatrick int s; 519305ac5f9Spatrick 520305ac5f9Spatrick s = splnet(); 521305ac5f9Spatrick mii_tick(&sc->sc_mii); 522305ac5f9Spatrick splx(s); 523305ac5f9Spatrick 52447707f8eSdlg timeout_add_sec(&sc->sc_phy_tick, 1); 525305ac5f9Spatrick } 526305ac5f9Spatrick 527305ac5f9Spatrick void 528305ac5f9Spatrick dwqe_rxtick(void *arg) 529305ac5f9Spatrick { 530305ac5f9Spatrick struct dwqe_softc *sc = arg; 531305ac5f9Spatrick int s; 532305ac5f9Spatrick 533305ac5f9Spatrick s = splnet(); 534305ac5f9Spatrick 535305ac5f9Spatrick /* TODO: disable RXQ? */ 536305ac5f9Spatrick printf("%s:%d\n", __func__, __LINE__); 537305ac5f9Spatrick 538305ac5f9Spatrick bus_dmamap_sync(sc->sc_dmat, DWQE_DMA_MAP(sc->sc_rxring), 539305ac5f9Spatrick 0, DWQE_DMA_LEN(sc->sc_rxring), 540305ac5f9Spatrick BUS_DMASYNC_POSTREAD|BUS_DMASYNC_POSTWRITE); 541305ac5f9Spatrick 542305ac5f9Spatrick dwqe_write(sc, GMAC_CHAN_RX_BASE_ADDR_HI(0), 0); 543305ac5f9Spatrick dwqe_write(sc, GMAC_CHAN_RX_BASE_ADDR(0), 0); 544305ac5f9Spatrick 545305ac5f9Spatrick sc->sc_rx_prod = sc->sc_rx_cons = 0; 546305ac5f9Spatrick dwqe_fill_rx_ring(sc); 547305ac5f9Spatrick 548305ac5f9Spatrick bus_dmamap_sync(sc->sc_dmat, DWQE_DMA_MAP(sc->sc_rxring), 549305ac5f9Spatrick 0, DWQE_DMA_LEN(sc->sc_rxring), 550305ac5f9Spatrick BUS_DMASYNC_PREREAD|BUS_DMASYNC_PREWRITE); 551305ac5f9Spatrick 552305ac5f9Spatrick dwqe_write(sc, GMAC_CHAN_RX_BASE_ADDR_HI(0), DWQE_DMA_DVA(sc->sc_rxring) >> 32); 553305ac5f9Spatrick dwqe_write(sc, GMAC_CHAN_RX_BASE_ADDR(0), DWQE_DMA_DVA(sc->sc_rxring)); 554305ac5f9Spatrick 555305ac5f9Spatrick /* TODO: re-enable RXQ? */ 556305ac5f9Spatrick 557305ac5f9Spatrick splx(s); 558305ac5f9Spatrick } 559305ac5f9Spatrick 560305ac5f9Spatrick int 561305ac5f9Spatrick dwqe_intr(void *arg) 562305ac5f9Spatrick { 563305ac5f9Spatrick struct dwqe_softc *sc = arg; 564305ac5f9Spatrick uint32_t reg; 565305ac5f9Spatrick 566305ac5f9Spatrick reg = dwqe_read(sc, GMAC_INT_STATUS); 567305ac5f9Spatrick dwqe_write(sc, GMAC_INT_STATUS, reg); 568305ac5f9Spatrick 569305ac5f9Spatrick reg = dwqe_read(sc, GMAC_CHAN_STATUS(0)); 570305ac5f9Spatrick dwqe_write(sc, GMAC_CHAN_STATUS(0), reg); 571305ac5f9Spatrick 572305ac5f9Spatrick if (reg & GMAC_CHAN_STATUS_RI) 573305ac5f9Spatrick dwqe_rx_proc(sc); 574305ac5f9Spatrick 575305ac5f9Spatrick if (reg & GMAC_CHAN_STATUS_TI) 576305ac5f9Spatrick dwqe_tx_proc(sc); 577305ac5f9Spatrick 578305ac5f9Spatrick return (1); 579305ac5f9Spatrick } 580305ac5f9Spatrick 581305ac5f9Spatrick void 582305ac5f9Spatrick dwqe_tx_proc(struct dwqe_softc *sc) 583305ac5f9Spatrick { 584305ac5f9Spatrick struct ifnet *ifp = &sc->sc_ac.ac_if; 585305ac5f9Spatrick struct dwqe_desc *txd; 586305ac5f9Spatrick struct dwqe_buf *txb; 587305ac5f9Spatrick int idx, txfree; 588305ac5f9Spatrick 589305ac5f9Spatrick bus_dmamap_sync(sc->sc_dmat, DWQE_DMA_MAP(sc->sc_txring), 0, 590305ac5f9Spatrick DWQE_DMA_LEN(sc->sc_txring), 591305ac5f9Spatrick BUS_DMASYNC_POSTREAD | BUS_DMASYNC_POSTWRITE); 592305ac5f9Spatrick 593305ac5f9Spatrick txfree = 0; 594305ac5f9Spatrick while (sc->sc_tx_cons != sc->sc_tx_prod) { 595305ac5f9Spatrick idx = sc->sc_tx_cons; 596305ac5f9Spatrick KASSERT(idx < DWQE_NTXDESC); 597305ac5f9Spatrick 598305ac5f9Spatrick txd = &sc->sc_txdesc[idx]; 599305ac5f9Spatrick if (txd->sd_tdes3 & TDES3_OWN) 600305ac5f9Spatrick break; 601305ac5f9Spatrick 602e8974f33Skettenis if (txd->sd_tdes3 & TDES3_ES) 603e8974f33Skettenis ifp->if_oerrors++; 604e8974f33Skettenis 605305ac5f9Spatrick txb = &sc->sc_txbuf[idx]; 606305ac5f9Spatrick if (txb->tb_m) { 607305ac5f9Spatrick bus_dmamap_sync(sc->sc_dmat, txb->tb_map, 0, 608305ac5f9Spatrick txb->tb_map->dm_mapsize, BUS_DMASYNC_POSTWRITE); 609305ac5f9Spatrick bus_dmamap_unload(sc->sc_dmat, txb->tb_map); 610305ac5f9Spatrick 611305ac5f9Spatrick m_freem(txb->tb_m); 612305ac5f9Spatrick txb->tb_m = NULL; 613305ac5f9Spatrick } 614305ac5f9Spatrick 615305ac5f9Spatrick txfree++; 616305ac5f9Spatrick 617305ac5f9Spatrick if (sc->sc_tx_cons == (DWQE_NTXDESC - 1)) 618305ac5f9Spatrick sc->sc_tx_cons = 0; 619305ac5f9Spatrick else 620305ac5f9Spatrick sc->sc_tx_cons++; 621305ac5f9Spatrick 622305ac5f9Spatrick txd->sd_tdes3 = 0; 623305ac5f9Spatrick } 624305ac5f9Spatrick 625305ac5f9Spatrick if (sc->sc_tx_cons == sc->sc_tx_prod) 626305ac5f9Spatrick ifp->if_timer = 0; 627305ac5f9Spatrick 628305ac5f9Spatrick if (txfree) { 629305ac5f9Spatrick if (ifq_is_oactive(&ifp->if_snd)) 630305ac5f9Spatrick ifq_restart(&ifp->if_snd); 631305ac5f9Spatrick } 632305ac5f9Spatrick } 633305ac5f9Spatrick 634305ac5f9Spatrick void 635305ac5f9Spatrick dwqe_rx_proc(struct dwqe_softc *sc) 636305ac5f9Spatrick { 637305ac5f9Spatrick struct ifnet *ifp = &sc->sc_ac.ac_if; 638305ac5f9Spatrick struct dwqe_desc *rxd; 639305ac5f9Spatrick struct dwqe_buf *rxb; 640305ac5f9Spatrick struct mbuf_list ml = MBUF_LIST_INITIALIZER(); 641305ac5f9Spatrick struct mbuf *m; 642305ac5f9Spatrick int idx, len, cnt, put; 643305ac5f9Spatrick 644305ac5f9Spatrick if ((ifp->if_flags & IFF_RUNNING) == 0) 645305ac5f9Spatrick return; 646305ac5f9Spatrick 647305ac5f9Spatrick bus_dmamap_sync(sc->sc_dmat, DWQE_DMA_MAP(sc->sc_rxring), 0, 648305ac5f9Spatrick DWQE_DMA_LEN(sc->sc_rxring), 649305ac5f9Spatrick BUS_DMASYNC_POSTREAD | BUS_DMASYNC_POSTWRITE); 650305ac5f9Spatrick 651305ac5f9Spatrick cnt = if_rxr_inuse(&sc->sc_rx_ring); 652305ac5f9Spatrick put = 0; 653305ac5f9Spatrick while (put < cnt) { 654305ac5f9Spatrick idx = sc->sc_rx_cons; 655305ac5f9Spatrick KASSERT(idx < DWQE_NRXDESC); 656305ac5f9Spatrick 657305ac5f9Spatrick rxd = &sc->sc_rxdesc[idx]; 658305ac5f9Spatrick if (rxd->sd_tdes3 & RDES3_OWN) 659305ac5f9Spatrick break; 660305ac5f9Spatrick 661305ac5f9Spatrick len = rxd->sd_tdes3 & RDES3_LENGTH; 662305ac5f9Spatrick rxb = &sc->sc_rxbuf[idx]; 663305ac5f9Spatrick KASSERT(rxb->tb_m); 664305ac5f9Spatrick 665305ac5f9Spatrick bus_dmamap_sync(sc->sc_dmat, rxb->tb_map, 0, 666305ac5f9Spatrick len, BUS_DMASYNC_POSTREAD); 667305ac5f9Spatrick bus_dmamap_unload(sc->sc_dmat, rxb->tb_map); 668305ac5f9Spatrick 669b58ef082Skettenis m = rxb->tb_m; 670b58ef082Skettenis rxb->tb_m = NULL; 671b58ef082Skettenis 672b58ef082Skettenis if (rxd->sd_tdes3 & RDES3_ES) { 673b58ef082Skettenis ifp->if_ierrors++; 674b58ef082Skettenis m_freem(m); 675b58ef082Skettenis } else { 676305ac5f9Spatrick /* Strip off CRC. */ 677305ac5f9Spatrick len -= ETHER_CRC_LEN; 678305ac5f9Spatrick KASSERT(len > 0); 679305ac5f9Spatrick 680305ac5f9Spatrick m->m_pkthdr.len = m->m_len = len; 681305ac5f9Spatrick 682305ac5f9Spatrick ml_enqueue(&ml, m); 683b58ef082Skettenis } 684305ac5f9Spatrick 685305ac5f9Spatrick put++; 686305ac5f9Spatrick if (sc->sc_rx_cons == (DWQE_NRXDESC - 1)) 687305ac5f9Spatrick sc->sc_rx_cons = 0; 688305ac5f9Spatrick else 689305ac5f9Spatrick sc->sc_rx_cons++; 690305ac5f9Spatrick } 691305ac5f9Spatrick 692305ac5f9Spatrick if_rxr_put(&sc->sc_rx_ring, put); 693305ac5f9Spatrick if (ifiq_input(&ifp->if_rcv, &ml)) 694305ac5f9Spatrick if_rxr_livelocked(&sc->sc_rx_ring); 695305ac5f9Spatrick 696305ac5f9Spatrick dwqe_fill_rx_ring(sc); 697305ac5f9Spatrick 698305ac5f9Spatrick bus_dmamap_sync(sc->sc_dmat, DWQE_DMA_MAP(sc->sc_rxring), 0, 699305ac5f9Spatrick DWQE_DMA_LEN(sc->sc_rxring), 700305ac5f9Spatrick BUS_DMASYNC_PREREAD | BUS_DMASYNC_PREWRITE); 701305ac5f9Spatrick } 702305ac5f9Spatrick 703305ac5f9Spatrick void 704305ac5f9Spatrick dwqe_up(struct dwqe_softc *sc) 705305ac5f9Spatrick { 706305ac5f9Spatrick struct ifnet *ifp = &sc->sc_ac.ac_if; 707305ac5f9Spatrick struct dwqe_buf *txb, *rxb; 708*6e9149a4Sstsp uint32_t mode, reg, fifosz, tqs, rqs; 709305ac5f9Spatrick int i; 710305ac5f9Spatrick 711305ac5f9Spatrick /* Allocate Tx descriptor ring. */ 712305ac5f9Spatrick sc->sc_txring = dwqe_dmamem_alloc(sc, 713305ac5f9Spatrick DWQE_NTXDESC * sizeof(struct dwqe_desc), 8); 714305ac5f9Spatrick sc->sc_txdesc = DWQE_DMA_KVA(sc->sc_txring); 715305ac5f9Spatrick 716305ac5f9Spatrick sc->sc_txbuf = malloc(sizeof(struct dwqe_buf) * DWQE_NTXDESC, 717305ac5f9Spatrick M_DEVBUF, M_WAITOK); 718305ac5f9Spatrick for (i = 0; i < DWQE_NTXDESC; i++) { 719305ac5f9Spatrick txb = &sc->sc_txbuf[i]; 720305ac5f9Spatrick bus_dmamap_create(sc->sc_dmat, MCLBYTES, DWQE_NTXSEGS, 721305ac5f9Spatrick MCLBYTES, 0, BUS_DMA_WAITOK, &txb->tb_map); 722305ac5f9Spatrick txb->tb_m = NULL; 723305ac5f9Spatrick } 724305ac5f9Spatrick 725305ac5f9Spatrick bus_dmamap_sync(sc->sc_dmat, DWQE_DMA_MAP(sc->sc_txring), 726305ac5f9Spatrick 0, DWQE_DMA_LEN(sc->sc_txring), BUS_DMASYNC_PREWRITE); 727305ac5f9Spatrick 728305ac5f9Spatrick sc->sc_tx_prod = sc->sc_tx_cons = 0; 729305ac5f9Spatrick 730305ac5f9Spatrick dwqe_write(sc, GMAC_CHAN_TX_BASE_ADDR_HI(0), DWQE_DMA_DVA(sc->sc_txring) >> 32); 731305ac5f9Spatrick dwqe_write(sc, GMAC_CHAN_TX_BASE_ADDR(0), DWQE_DMA_DVA(sc->sc_txring)); 732305ac5f9Spatrick dwqe_write(sc, GMAC_CHAN_TX_RING_LEN(0), DWQE_NTXDESC - 1); 733305ac5f9Spatrick dwqe_write(sc, GMAC_CHAN_TX_END_ADDR(0), DWQE_DMA_DVA(sc->sc_txring)); 734305ac5f9Spatrick 735305ac5f9Spatrick /* Allocate descriptor ring. */ 736305ac5f9Spatrick sc->sc_rxring = dwqe_dmamem_alloc(sc, 737305ac5f9Spatrick DWQE_NRXDESC * sizeof(struct dwqe_desc), 8); 738305ac5f9Spatrick sc->sc_rxdesc = DWQE_DMA_KVA(sc->sc_rxring); 739305ac5f9Spatrick 740305ac5f9Spatrick sc->sc_rxbuf = malloc(sizeof(struct dwqe_buf) * DWQE_NRXDESC, 741305ac5f9Spatrick M_DEVBUF, M_WAITOK); 742305ac5f9Spatrick 743305ac5f9Spatrick for (i = 0; i < DWQE_NRXDESC; i++) { 744305ac5f9Spatrick rxb = &sc->sc_rxbuf[i]; 745305ac5f9Spatrick bus_dmamap_create(sc->sc_dmat, MCLBYTES, 1, 746305ac5f9Spatrick MCLBYTES, 0, BUS_DMA_WAITOK, &rxb->tb_map); 747305ac5f9Spatrick rxb->tb_m = NULL; 748305ac5f9Spatrick } 749305ac5f9Spatrick 750305ac5f9Spatrick if_rxr_init(&sc->sc_rx_ring, 2, DWQE_NRXDESC); 751305ac5f9Spatrick 752305ac5f9Spatrick dwqe_write(sc, GMAC_CHAN_RX_BASE_ADDR_HI(0), DWQE_DMA_DVA(sc->sc_rxring) >> 32); 753305ac5f9Spatrick dwqe_write(sc, GMAC_CHAN_RX_BASE_ADDR(0), DWQE_DMA_DVA(sc->sc_rxring)); 754305ac5f9Spatrick dwqe_write(sc, GMAC_CHAN_RX_RING_LEN(0), DWQE_NRXDESC - 1); 755305ac5f9Spatrick 756305ac5f9Spatrick sc->sc_rx_prod = sc->sc_rx_cons = 0; 757305ac5f9Spatrick dwqe_fill_rx_ring(sc); 758305ac5f9Spatrick 759305ac5f9Spatrick bus_dmamap_sync(sc->sc_dmat, DWQE_DMA_MAP(sc->sc_rxring), 760305ac5f9Spatrick 0, DWQE_DMA_LEN(sc->sc_rxring), 761305ac5f9Spatrick BUS_DMASYNC_PREREAD|BUS_DMASYNC_PREWRITE); 762305ac5f9Spatrick 763305ac5f9Spatrick dwqe_lladdr_write(sc); 764305ac5f9Spatrick 765305ac5f9Spatrick /* Configure media. */ 766305ac5f9Spatrick if (LIST_FIRST(&sc->sc_mii.mii_phys)) 767305ac5f9Spatrick mii_mediachg(&sc->sc_mii); 768305ac5f9Spatrick 769305ac5f9Spatrick /* Program promiscuous mode and multicast filters. */ 770305ac5f9Spatrick dwqe_iff(sc); 771305ac5f9Spatrick 772305ac5f9Spatrick ifp->if_flags |= IFF_RUNNING; 773305ac5f9Spatrick ifq_clr_oactive(&ifp->if_snd); 774305ac5f9Spatrick 775b97405d6Sstsp dwqe_write(sc, GMAC_MAC_1US_TIC_CTR, (sc->sc_clkrate / 1000000) - 1); 776305ac5f9Spatrick 777305ac5f9Spatrick /* Start receive DMA */ 778305ac5f9Spatrick reg = dwqe_read(sc, GMAC_CHAN_RX_CONTROL(0)); 779305ac5f9Spatrick reg |= GMAC_CHAN_RX_CONTROL_SR; 780305ac5f9Spatrick dwqe_write(sc, GMAC_CHAN_RX_CONTROL(0), reg); 781305ac5f9Spatrick 782305ac5f9Spatrick /* Start transmit DMA */ 783305ac5f9Spatrick reg = dwqe_read(sc, GMAC_CHAN_TX_CONTROL(0)); 784305ac5f9Spatrick reg |= GMAC_CHAN_TX_CONTROL_ST; 785305ac5f9Spatrick dwqe_write(sc, GMAC_CHAN_TX_CONTROL(0), reg); 786305ac5f9Spatrick 787305ac5f9Spatrick mode = dwqe_read(sc, GMAC_MTL_CHAN_RX_OP_MODE(0)); 788305ac5f9Spatrick if (sc->sc_force_thresh_dma_mode) { 789305ac5f9Spatrick mode &= ~GMAC_MTL_CHAN_RX_OP_MODE_RSF; 790305ac5f9Spatrick mode &= ~GMAC_MTL_CHAN_RX_OP_MODE_RTC_MASK; 791305ac5f9Spatrick mode |= GMAC_MTL_CHAN_RX_OP_MODE_RTC_128; 792305ac5f9Spatrick } else { 793305ac5f9Spatrick mode |= GMAC_MTL_CHAN_RX_OP_MODE_RSF; 794305ac5f9Spatrick } 795305ac5f9Spatrick mode &= ~GMAC_MTL_CHAN_RX_OP_MODE_RQS_MASK; 796*6e9149a4Sstsp if (sc->sc_rxfifo_size) 797*6e9149a4Sstsp fifosz = sc->sc_rxfifo_size; 798*6e9149a4Sstsp else 799*6e9149a4Sstsp fifosz = (128 << 800*6e9149a4Sstsp GMAC_MAC_HW_FEATURE1_RXFIFOSIZE(sc->sc_hw_feature[1])); 801*6e9149a4Sstsp rqs = fifosz / 256 - 1; 802*6e9149a4Sstsp mode |= (rqs << GMAC_MTL_CHAN_RX_OP_MODE_RQS_SHIFT) & 803*6e9149a4Sstsp GMAC_MTL_CHAN_RX_OP_MODE_RQS_MASK; 804*6e9149a4Sstsp if (fifosz >= 4096) { 805*6e9149a4Sstsp mode |= GMAC_MTL_CHAN_RX_OP_MODE_EHFC; 806*6e9149a4Sstsp mode &= ~GMAC_MTL_CHAN_RX_OP_MODE_RFD_MASK; 807*6e9149a4Sstsp mode |= 0x3 << GMAC_MTL_CHAN_RX_OP_MODE_RFD_SHIFT; 808*6e9149a4Sstsp mode &= ~GMAC_MTL_CHAN_RX_OP_MODE_RFA_MASK; 809*6e9149a4Sstsp mode |= 0x1 << GMAC_MTL_CHAN_RX_OP_MODE_RFA_SHIFT; 810*6e9149a4Sstsp } 811305ac5f9Spatrick dwqe_write(sc, GMAC_MTL_CHAN_RX_OP_MODE(0), mode); 812305ac5f9Spatrick 813305ac5f9Spatrick mode = dwqe_read(sc, GMAC_MTL_CHAN_TX_OP_MODE(0)); 814305ac5f9Spatrick if (sc->sc_force_thresh_dma_mode) { 815305ac5f9Spatrick mode &= ~GMAC_MTL_CHAN_TX_OP_MODE_TSF; 816305ac5f9Spatrick mode &= ~GMAC_MTL_CHAN_TX_OP_MODE_TTC_MASK; 817e8974f33Skettenis mode |= GMAC_MTL_CHAN_TX_OP_MODE_TTC_512; 818305ac5f9Spatrick } else { 819305ac5f9Spatrick mode |= GMAC_MTL_CHAN_TX_OP_MODE_TSF; 820305ac5f9Spatrick } 821305ac5f9Spatrick mode &= ~GMAC_MTL_CHAN_TX_OP_MODE_TXQEN_MASK; 822305ac5f9Spatrick mode |= GMAC_MTL_CHAN_TX_OP_MODE_TXQEN; 823305ac5f9Spatrick mode &= ~GMAC_MTL_CHAN_TX_OP_MODE_TQS_MASK; 824*6e9149a4Sstsp if (sc->sc_txfifo_size) 825*6e9149a4Sstsp fifosz = sc->sc_txfifo_size; 826*6e9149a4Sstsp else 827*6e9149a4Sstsp fifosz = (128 << 828*6e9149a4Sstsp GMAC_MAC_HW_FEATURE1_TXFIFOSIZE(sc->sc_hw_feature[1])); 829*6e9149a4Sstsp tqs = (fifosz / 256) - 1; 830*6e9149a4Sstsp mode |= (tqs << GMAC_MTL_CHAN_TX_OP_MODE_TQS_SHIFT) & 831*6e9149a4Sstsp GMAC_MTL_CHAN_TX_OP_MODE_TQS_MASK; 832305ac5f9Spatrick dwqe_write(sc, GMAC_MTL_CHAN_TX_OP_MODE(0), mode); 833305ac5f9Spatrick 834305ac5f9Spatrick reg = dwqe_read(sc, GMAC_QX_TX_FLOW_CTRL(0)); 835305ac5f9Spatrick reg |= 0xffffU << GMAC_QX_TX_FLOW_CTRL_PT_SHIFT; 836305ac5f9Spatrick reg |= GMAC_QX_TX_FLOW_CTRL_TFE; 837305ac5f9Spatrick dwqe_write(sc, GMAC_QX_TX_FLOW_CTRL(0), reg); 838305ac5f9Spatrick reg = dwqe_read(sc, GMAC_RX_FLOW_CTRL); 839305ac5f9Spatrick reg |= GMAC_RX_FLOW_CTRL_RFE; 840305ac5f9Spatrick dwqe_write(sc, GMAC_RX_FLOW_CTRL, reg); 841305ac5f9Spatrick 842305ac5f9Spatrick dwqe_write(sc, GMAC_RXQ_CTRL0, GMAC_RXQ_CTRL0_DCB_QUEUE_EN(0)); 843305ac5f9Spatrick 844305ac5f9Spatrick dwqe_write(sc, GMAC_MAC_CONF, dwqe_read(sc, GMAC_MAC_CONF) | 845305ac5f9Spatrick GMAC_MAC_CONF_BE | GMAC_MAC_CONF_JD | GMAC_MAC_CONF_JE | 846305ac5f9Spatrick GMAC_MAC_CONF_DCRS | GMAC_MAC_CONF_TE | GMAC_MAC_CONF_RE); 847305ac5f9Spatrick 848305ac5f9Spatrick dwqe_write(sc, GMAC_CHAN_INTR_ENA(0), 849305ac5f9Spatrick GMAC_CHAN_INTR_ENA_NIE | 850305ac5f9Spatrick GMAC_CHAN_INTR_ENA_AIE | 851305ac5f9Spatrick GMAC_CHAN_INTR_ENA_FBE | 852305ac5f9Spatrick GMAC_CHAN_INTR_ENA_RIE | 853305ac5f9Spatrick GMAC_CHAN_INTR_ENA_TIE); 854305ac5f9Spatrick 85545f5f3c8Sdlg if (!sc->sc_fixed_link) 85647707f8eSdlg timeout_add_sec(&sc->sc_phy_tick, 1); 857305ac5f9Spatrick } 858305ac5f9Spatrick 859305ac5f9Spatrick void 860305ac5f9Spatrick dwqe_down(struct dwqe_softc *sc) 861305ac5f9Spatrick { 862305ac5f9Spatrick struct ifnet *ifp = &sc->sc_ac.ac_if; 863305ac5f9Spatrick struct dwqe_buf *txb, *rxb; 864305ac5f9Spatrick uint32_t reg; 865305ac5f9Spatrick int i; 866305ac5f9Spatrick 867305ac5f9Spatrick timeout_del(&sc->sc_rxto); 86845f5f3c8Sdlg if (!sc->sc_fixed_link) 86947707f8eSdlg timeout_del(&sc->sc_phy_tick); 870305ac5f9Spatrick 871305ac5f9Spatrick ifp->if_flags &= ~IFF_RUNNING; 872305ac5f9Spatrick ifq_clr_oactive(&ifp->if_snd); 873305ac5f9Spatrick ifp->if_timer = 0; 874305ac5f9Spatrick 875305ac5f9Spatrick /* Disable receiver */ 876305ac5f9Spatrick reg = dwqe_read(sc, GMAC_MAC_CONF); 877305ac5f9Spatrick reg &= ~GMAC_MAC_CONF_RE; 878305ac5f9Spatrick dwqe_write(sc, GMAC_MAC_CONF, reg); 879305ac5f9Spatrick 880305ac5f9Spatrick /* Stop receive DMA */ 881305ac5f9Spatrick reg = dwqe_read(sc, GMAC_CHAN_RX_CONTROL(0)); 882305ac5f9Spatrick reg &= ~GMAC_CHAN_RX_CONTROL_SR; 883305ac5f9Spatrick dwqe_write(sc, GMAC_CHAN_RX_CONTROL(0), reg); 884305ac5f9Spatrick 885305ac5f9Spatrick /* Stop transmit DMA */ 886305ac5f9Spatrick reg = dwqe_read(sc, GMAC_CHAN_TX_CONTROL(0)); 887305ac5f9Spatrick reg &= ~GMAC_CHAN_TX_CONTROL_ST; 888305ac5f9Spatrick dwqe_write(sc, GMAC_CHAN_TX_CONTROL(0), reg); 889305ac5f9Spatrick 890305ac5f9Spatrick /* Flush data in the TX FIFO */ 891305ac5f9Spatrick reg = dwqe_read(sc, GMAC_MTL_CHAN_TX_OP_MODE(0)); 892305ac5f9Spatrick reg |= GMAC_MTL_CHAN_TX_OP_MODE_FTQ; 893305ac5f9Spatrick dwqe_write(sc, GMAC_MTL_CHAN_TX_OP_MODE(0), reg); 894305ac5f9Spatrick /* Wait for flush to complete */ 895305ac5f9Spatrick for (i = 10000; i > 0; i--) { 896305ac5f9Spatrick reg = dwqe_read(sc, GMAC_MTL_CHAN_TX_OP_MODE(0)); 897305ac5f9Spatrick if ((reg & GMAC_MTL_CHAN_TX_OP_MODE_FTQ) == 0) 898305ac5f9Spatrick break; 899305ac5f9Spatrick delay(1); 900305ac5f9Spatrick } 901305ac5f9Spatrick if (i == 0) { 902305ac5f9Spatrick printf("%s: timeout flushing TX queue\n", 903305ac5f9Spatrick sc->sc_dev.dv_xname); 904305ac5f9Spatrick } 905305ac5f9Spatrick 906305ac5f9Spatrick /* Disable transmitter */ 907305ac5f9Spatrick reg = dwqe_read(sc, GMAC_MAC_CONF); 908305ac5f9Spatrick reg &= ~GMAC_MAC_CONF_TE; 909305ac5f9Spatrick dwqe_write(sc, GMAC_MAC_CONF, reg); 910305ac5f9Spatrick 911305ac5f9Spatrick dwqe_write(sc, GMAC_CHAN_INTR_ENA(0), 0); 912305ac5f9Spatrick 913305ac5f9Spatrick intr_barrier(sc->sc_ih); 914305ac5f9Spatrick ifq_barrier(&ifp->if_snd); 915305ac5f9Spatrick 916305ac5f9Spatrick for (i = 0; i < DWQE_NTXDESC; i++) { 917305ac5f9Spatrick txb = &sc->sc_txbuf[i]; 918305ac5f9Spatrick if (txb->tb_m) { 919305ac5f9Spatrick bus_dmamap_sync(sc->sc_dmat, txb->tb_map, 0, 920305ac5f9Spatrick txb->tb_map->dm_mapsize, BUS_DMASYNC_POSTWRITE); 921305ac5f9Spatrick bus_dmamap_unload(sc->sc_dmat, txb->tb_map); 922305ac5f9Spatrick m_freem(txb->tb_m); 923305ac5f9Spatrick } 924305ac5f9Spatrick bus_dmamap_destroy(sc->sc_dmat, txb->tb_map); 925305ac5f9Spatrick } 926305ac5f9Spatrick 927305ac5f9Spatrick dwqe_dmamem_free(sc, sc->sc_txring); 928305ac5f9Spatrick free(sc->sc_txbuf, M_DEVBUF, 0); 929305ac5f9Spatrick 930305ac5f9Spatrick for (i = 0; i < DWQE_NRXDESC; i++) { 931305ac5f9Spatrick rxb = &sc->sc_rxbuf[i]; 932305ac5f9Spatrick if (rxb->tb_m) { 933305ac5f9Spatrick bus_dmamap_sync(sc->sc_dmat, rxb->tb_map, 0, 934305ac5f9Spatrick rxb->tb_map->dm_mapsize, BUS_DMASYNC_POSTREAD); 935305ac5f9Spatrick bus_dmamap_unload(sc->sc_dmat, rxb->tb_map); 936305ac5f9Spatrick m_freem(rxb->tb_m); 937305ac5f9Spatrick } 938305ac5f9Spatrick bus_dmamap_destroy(sc->sc_dmat, rxb->tb_map); 939305ac5f9Spatrick } 940305ac5f9Spatrick 941305ac5f9Spatrick dwqe_dmamem_free(sc, sc->sc_rxring); 942305ac5f9Spatrick free(sc->sc_rxbuf, M_DEVBUF, 0); 943305ac5f9Spatrick } 944305ac5f9Spatrick 945305ac5f9Spatrick /* Bit Reversal - http://aggregate.org/MAGIC/#Bit%20Reversal */ 946305ac5f9Spatrick static uint32_t 947305ac5f9Spatrick bitrev32(uint32_t x) 948305ac5f9Spatrick { 949305ac5f9Spatrick x = (((x & 0xaaaaaaaa) >> 1) | ((x & 0x55555555) << 1)); 950305ac5f9Spatrick x = (((x & 0xcccccccc) >> 2) | ((x & 0x33333333) << 2)); 951305ac5f9Spatrick x = (((x & 0xf0f0f0f0) >> 4) | ((x & 0x0f0f0f0f) << 4)); 952305ac5f9Spatrick x = (((x & 0xff00ff00) >> 8) | ((x & 0x00ff00ff) << 8)); 953305ac5f9Spatrick 954305ac5f9Spatrick return (x >> 16) | (x << 16); 955305ac5f9Spatrick } 956305ac5f9Spatrick 957305ac5f9Spatrick void 958305ac5f9Spatrick dwqe_iff(struct dwqe_softc *sc) 959305ac5f9Spatrick { 960305ac5f9Spatrick struct arpcom *ac = &sc->sc_ac; 961305ac5f9Spatrick struct ifnet *ifp = &sc->sc_ac.ac_if; 962305ac5f9Spatrick struct ether_multi *enm; 963305ac5f9Spatrick struct ether_multistep step; 964305ac5f9Spatrick uint32_t crc, hash[2], hashbit, hashreg; 965305ac5f9Spatrick uint32_t reg; 966305ac5f9Spatrick 967305ac5f9Spatrick reg = 0; 968305ac5f9Spatrick 969305ac5f9Spatrick ifp->if_flags &= ~IFF_ALLMULTI; 970305ac5f9Spatrick bzero(hash, sizeof(hash)); 971305ac5f9Spatrick if (ifp->if_flags & IFF_PROMISC || ac->ac_multirangecnt > 0) { 972305ac5f9Spatrick ifp->if_flags |= IFF_ALLMULTI; 973305ac5f9Spatrick reg |= GMAC_MAC_PACKET_FILTER_PM; 974305ac5f9Spatrick if (ifp->if_flags & IFF_PROMISC) 975305ac5f9Spatrick reg |= GMAC_MAC_PACKET_FILTER_PR | 976305ac5f9Spatrick GMAC_MAC_PACKET_FILTER_PCF_ALL; 977305ac5f9Spatrick } else { 978305ac5f9Spatrick reg |= GMAC_MAC_PACKET_FILTER_HMC; 979305ac5f9Spatrick ETHER_FIRST_MULTI(step, ac, enm); 980305ac5f9Spatrick while (enm != NULL) { 981305ac5f9Spatrick crc = ether_crc32_le(enm->enm_addrlo, 982305ac5f9Spatrick ETHER_ADDR_LEN) & 0x7f; 983305ac5f9Spatrick 984305ac5f9Spatrick crc = bitrev32(~crc) >> 26; 985305ac5f9Spatrick hashreg = (crc >> 5); 986305ac5f9Spatrick hashbit = (crc & 0x1f); 987305ac5f9Spatrick hash[hashreg] |= (1 << hashbit); 988305ac5f9Spatrick 989305ac5f9Spatrick ETHER_NEXT_MULTI(step, enm); 990305ac5f9Spatrick } 991305ac5f9Spatrick } 992305ac5f9Spatrick 993305ac5f9Spatrick dwqe_lladdr_write(sc); 994305ac5f9Spatrick 995305ac5f9Spatrick dwqe_write(sc, GMAC_MAC_HASH_TAB_REG0, hash[0]); 996305ac5f9Spatrick dwqe_write(sc, GMAC_MAC_HASH_TAB_REG1, hash[1]); 997305ac5f9Spatrick 998305ac5f9Spatrick dwqe_write(sc, GMAC_MAC_PACKET_FILTER, reg); 999305ac5f9Spatrick } 1000305ac5f9Spatrick 1001305ac5f9Spatrick int 1002305ac5f9Spatrick dwqe_encap(struct dwqe_softc *sc, struct mbuf *m, int *idx, int *used) 1003305ac5f9Spatrick { 1004305ac5f9Spatrick struct dwqe_desc *txd, *txd_start; 1005305ac5f9Spatrick bus_dmamap_t map; 1006305ac5f9Spatrick int cur, frag, i; 1007305ac5f9Spatrick 1008305ac5f9Spatrick cur = frag = *idx; 1009305ac5f9Spatrick map = sc->sc_txbuf[cur].tb_map; 1010305ac5f9Spatrick 1011305ac5f9Spatrick if (bus_dmamap_load_mbuf(sc->sc_dmat, map, m, BUS_DMA_NOWAIT)) { 1012305ac5f9Spatrick if (m_defrag(m, M_DONTWAIT)) 1013305ac5f9Spatrick return (EFBIG); 1014305ac5f9Spatrick if (bus_dmamap_load_mbuf(sc->sc_dmat, map, m, BUS_DMA_NOWAIT)) 1015305ac5f9Spatrick return (EFBIG); 1016305ac5f9Spatrick } 1017305ac5f9Spatrick 1018305ac5f9Spatrick /* Sync the DMA map. */ 1019305ac5f9Spatrick bus_dmamap_sync(sc->sc_dmat, map, 0, map->dm_mapsize, 1020305ac5f9Spatrick BUS_DMASYNC_PREWRITE); 1021305ac5f9Spatrick 1022305ac5f9Spatrick txd = txd_start = &sc->sc_txdesc[frag]; 1023305ac5f9Spatrick for (i = 0; i < map->dm_nsegs; i++) { 1024305ac5f9Spatrick /* TODO: check for 32-bit vs 64-bit support */ 1025305ac5f9Spatrick KASSERT((map->dm_segs[i].ds_addr >> 32) == 0); 1026305ac5f9Spatrick 1027305ac5f9Spatrick txd->sd_tdes0 = (uint32_t)map->dm_segs[i].ds_addr; 1028305ac5f9Spatrick txd->sd_tdes1 = (uint32_t)(map->dm_segs[i].ds_addr >> 32); 1029305ac5f9Spatrick txd->sd_tdes2 = map->dm_segs[i].ds_len; 1030305ac5f9Spatrick txd->sd_tdes3 = m->m_pkthdr.len; 1031305ac5f9Spatrick if (i == 0) 1032305ac5f9Spatrick txd->sd_tdes3 |= TDES3_FS; 1033305ac5f9Spatrick if (i == (map->dm_nsegs - 1)) { 1034305ac5f9Spatrick txd->sd_tdes2 |= TDES2_IC; 1035305ac5f9Spatrick txd->sd_tdes3 |= TDES3_LS; 1036305ac5f9Spatrick } 1037305ac5f9Spatrick if (i != 0) 1038305ac5f9Spatrick txd->sd_tdes3 |= TDES3_OWN; 1039305ac5f9Spatrick 1040305ac5f9Spatrick bus_dmamap_sync(sc->sc_dmat, DWQE_DMA_MAP(sc->sc_txring), 1041305ac5f9Spatrick frag * sizeof(*txd), sizeof(*txd), BUS_DMASYNC_PREWRITE); 1042305ac5f9Spatrick 1043305ac5f9Spatrick cur = frag; 1044305ac5f9Spatrick if (frag == (DWQE_NTXDESC - 1)) { 1045305ac5f9Spatrick txd = &sc->sc_txdesc[0]; 1046305ac5f9Spatrick frag = 0; 1047305ac5f9Spatrick } else { 1048305ac5f9Spatrick txd++; 1049305ac5f9Spatrick frag++; 1050305ac5f9Spatrick } 1051305ac5f9Spatrick KASSERT(frag != sc->sc_tx_cons); 1052305ac5f9Spatrick } 1053305ac5f9Spatrick 1054305ac5f9Spatrick txd_start->sd_tdes3 |= TDES3_OWN; 1055305ac5f9Spatrick bus_dmamap_sync(sc->sc_dmat, DWQE_DMA_MAP(sc->sc_txring), 1056305ac5f9Spatrick *idx * sizeof(*txd), sizeof(*txd), BUS_DMASYNC_PREWRITE); 1057305ac5f9Spatrick 1058305ac5f9Spatrick dwqe_write(sc, GMAC_CHAN_TX_END_ADDR(0), DWQE_DMA_DVA(sc->sc_txring) + 10594fa84378Skettenis frag * sizeof(*txd)); 1060305ac5f9Spatrick 1061305ac5f9Spatrick KASSERT(sc->sc_txbuf[cur].tb_m == NULL); 1062305ac5f9Spatrick sc->sc_txbuf[*idx].tb_map = sc->sc_txbuf[cur].tb_map; 1063305ac5f9Spatrick sc->sc_txbuf[cur].tb_map = map; 1064305ac5f9Spatrick sc->sc_txbuf[cur].tb_m = m; 1065305ac5f9Spatrick 1066305ac5f9Spatrick *idx = frag; 1067305ac5f9Spatrick *used += map->dm_nsegs; 1068305ac5f9Spatrick 1069305ac5f9Spatrick return (0); 1070305ac5f9Spatrick } 1071305ac5f9Spatrick 1072305ac5f9Spatrick void 1073305ac5f9Spatrick dwqe_reset(struct dwqe_softc *sc) 1074305ac5f9Spatrick { 1075305ac5f9Spatrick int n; 1076305ac5f9Spatrick 1077305ac5f9Spatrick dwqe_write(sc, GMAC_BUS_MODE, dwqe_read(sc, GMAC_BUS_MODE) | 1078305ac5f9Spatrick GMAC_BUS_MODE_SWR); 1079305ac5f9Spatrick 1080305ac5f9Spatrick for (n = 0; n < 30000; n++) { 1081305ac5f9Spatrick if ((dwqe_read(sc, GMAC_BUS_MODE) & 1082305ac5f9Spatrick GMAC_BUS_MODE_SWR) == 0) 1083305ac5f9Spatrick return; 1084305ac5f9Spatrick delay(10); 1085305ac5f9Spatrick } 1086305ac5f9Spatrick 1087305ac5f9Spatrick printf("%s: reset timeout\n", sc->sc_dev.dv_xname); 1088305ac5f9Spatrick } 1089305ac5f9Spatrick 1090305ac5f9Spatrick struct dwqe_dmamem * 1091305ac5f9Spatrick dwqe_dmamem_alloc(struct dwqe_softc *sc, bus_size_t size, bus_size_t align) 1092305ac5f9Spatrick { 1093305ac5f9Spatrick struct dwqe_dmamem *tdm; 1094305ac5f9Spatrick int nsegs; 1095305ac5f9Spatrick 1096305ac5f9Spatrick tdm = malloc(sizeof(*tdm), M_DEVBUF, M_WAITOK | M_ZERO); 1097305ac5f9Spatrick tdm->tdm_size = size; 1098305ac5f9Spatrick 1099305ac5f9Spatrick if (bus_dmamap_create(sc->sc_dmat, size, 1, size, 0, 1100305ac5f9Spatrick BUS_DMA_WAITOK | BUS_DMA_ALLOCNOW, &tdm->tdm_map) != 0) 1101305ac5f9Spatrick goto tdmfree; 1102305ac5f9Spatrick 1103305ac5f9Spatrick if (bus_dmamem_alloc(sc->sc_dmat, size, align, 0, &tdm->tdm_seg, 1, 1104305ac5f9Spatrick &nsegs, BUS_DMA_WAITOK) != 0) 1105305ac5f9Spatrick goto destroy; 1106305ac5f9Spatrick 1107305ac5f9Spatrick if (bus_dmamem_map(sc->sc_dmat, &tdm->tdm_seg, nsegs, size, 1108305ac5f9Spatrick &tdm->tdm_kva, BUS_DMA_WAITOK | BUS_DMA_COHERENT) != 0) 1109305ac5f9Spatrick goto free; 1110305ac5f9Spatrick 1111305ac5f9Spatrick if (bus_dmamap_load(sc->sc_dmat, tdm->tdm_map, tdm->tdm_kva, size, 1112305ac5f9Spatrick NULL, BUS_DMA_WAITOK) != 0) 1113305ac5f9Spatrick goto unmap; 1114305ac5f9Spatrick 1115305ac5f9Spatrick bzero(tdm->tdm_kva, size); 1116305ac5f9Spatrick 1117305ac5f9Spatrick return (tdm); 1118305ac5f9Spatrick 1119305ac5f9Spatrick unmap: 1120305ac5f9Spatrick bus_dmamem_unmap(sc->sc_dmat, tdm->tdm_kva, size); 1121305ac5f9Spatrick free: 1122305ac5f9Spatrick bus_dmamem_free(sc->sc_dmat, &tdm->tdm_seg, 1); 1123305ac5f9Spatrick destroy: 1124305ac5f9Spatrick bus_dmamap_destroy(sc->sc_dmat, tdm->tdm_map); 1125305ac5f9Spatrick tdmfree: 1126305ac5f9Spatrick free(tdm, M_DEVBUF, 0); 1127305ac5f9Spatrick 1128305ac5f9Spatrick return (NULL); 1129305ac5f9Spatrick } 1130305ac5f9Spatrick 1131305ac5f9Spatrick void 1132305ac5f9Spatrick dwqe_dmamem_free(struct dwqe_softc *sc, struct dwqe_dmamem *tdm) 1133305ac5f9Spatrick { 1134305ac5f9Spatrick bus_dmamem_unmap(sc->sc_dmat, tdm->tdm_kva, tdm->tdm_size); 1135305ac5f9Spatrick bus_dmamem_free(sc->sc_dmat, &tdm->tdm_seg, 1); 1136305ac5f9Spatrick bus_dmamap_destroy(sc->sc_dmat, tdm->tdm_map); 1137305ac5f9Spatrick free(tdm, M_DEVBUF, 0); 1138305ac5f9Spatrick } 1139305ac5f9Spatrick 1140305ac5f9Spatrick struct mbuf * 1141305ac5f9Spatrick dwqe_alloc_mbuf(struct dwqe_softc *sc, bus_dmamap_t map) 1142305ac5f9Spatrick { 1143305ac5f9Spatrick struct mbuf *m = NULL; 1144305ac5f9Spatrick 1145305ac5f9Spatrick m = MCLGETL(NULL, M_DONTWAIT, MCLBYTES); 1146305ac5f9Spatrick if (!m) 1147305ac5f9Spatrick return (NULL); 1148305ac5f9Spatrick m->m_len = m->m_pkthdr.len = MCLBYTES; 1149305ac5f9Spatrick m_adj(m, ETHER_ALIGN); 1150305ac5f9Spatrick 1151305ac5f9Spatrick if (bus_dmamap_load_mbuf(sc->sc_dmat, map, m, BUS_DMA_NOWAIT) != 0) { 1152305ac5f9Spatrick printf("%s: could not load mbuf DMA map", DEVNAME(sc)); 1153305ac5f9Spatrick m_freem(m); 1154305ac5f9Spatrick return (NULL); 1155305ac5f9Spatrick } 1156305ac5f9Spatrick 1157305ac5f9Spatrick bus_dmamap_sync(sc->sc_dmat, map, 0, 1158305ac5f9Spatrick m->m_pkthdr.len, BUS_DMASYNC_PREREAD); 1159305ac5f9Spatrick 1160305ac5f9Spatrick return (m); 1161305ac5f9Spatrick } 1162305ac5f9Spatrick 1163305ac5f9Spatrick void 1164305ac5f9Spatrick dwqe_fill_rx_ring(struct dwqe_softc *sc) 1165305ac5f9Spatrick { 1166305ac5f9Spatrick struct dwqe_desc *rxd; 1167305ac5f9Spatrick struct dwqe_buf *rxb; 1168305ac5f9Spatrick u_int slots; 1169305ac5f9Spatrick 1170305ac5f9Spatrick for (slots = if_rxr_get(&sc->sc_rx_ring, DWQE_NRXDESC); 1171305ac5f9Spatrick slots > 0; slots--) { 1172305ac5f9Spatrick rxb = &sc->sc_rxbuf[sc->sc_rx_prod]; 1173305ac5f9Spatrick rxb->tb_m = dwqe_alloc_mbuf(sc, rxb->tb_map); 1174305ac5f9Spatrick if (rxb->tb_m == NULL) 1175305ac5f9Spatrick break; 1176305ac5f9Spatrick 1177305ac5f9Spatrick /* TODO: check for 32-bit vs 64-bit support */ 11784fa84378Skettenis KASSERT((rxb->tb_map->dm_segs[0].ds_addr >> 32) == 0); 1179305ac5f9Spatrick 1180305ac5f9Spatrick rxd = &sc->sc_rxdesc[sc->sc_rx_prod]; 11814fa84378Skettenis rxd->sd_tdes0 = (uint32_t)rxb->tb_map->dm_segs[0].ds_addr; 11824fa84378Skettenis rxd->sd_tdes1 = (uint32_t)(rxb->tb_map->dm_segs[0].ds_addr >> 32); 1183305ac5f9Spatrick rxd->sd_tdes2 = 0; 1184305ac5f9Spatrick rxd->sd_tdes3 = RDES3_OWN | RDES3_IC | RDES3_BUF1V; 1185305ac5f9Spatrick 1186305ac5f9Spatrick if (sc->sc_rx_prod == (DWQE_NRXDESC - 1)) 1187305ac5f9Spatrick sc->sc_rx_prod = 0; 1188305ac5f9Spatrick else 1189305ac5f9Spatrick sc->sc_rx_prod++; 1190305ac5f9Spatrick } 1191305ac5f9Spatrick if_rxr_put(&sc->sc_rx_ring, slots); 1192305ac5f9Spatrick 1193305ac5f9Spatrick dwqe_write(sc, GMAC_CHAN_RX_END_ADDR(0), DWQE_DMA_DVA(sc->sc_rxring) + 1194305ac5f9Spatrick sc->sc_rx_prod * sizeof(*rxd)); 1195305ac5f9Spatrick 1196305ac5f9Spatrick if (if_rxr_inuse(&sc->sc_rx_ring) == 0) 1197305ac5f9Spatrick timeout_add(&sc->sc_rxto, 1); 1198305ac5f9Spatrick } 1199