1*4fa84378Skettenis /* $OpenBSD: dwqe.c,v 1.2 2023/02/15 14:10:58 kettenis 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 #include <machine/fdt.h> 38305ac5f9Spatrick 39305ac5f9Spatrick #include <net/if.h> 40305ac5f9Spatrick #include <net/if_media.h> 41305ac5f9Spatrick 42305ac5f9Spatrick #include <dev/ofw/openfirm.h> 43305ac5f9Spatrick #include <dev/ofw/ofw_clock.h> 44305ac5f9Spatrick #include <dev/ofw/ofw_gpio.h> 45305ac5f9Spatrick #include <dev/ofw/ofw_misc.h> 46305ac5f9Spatrick #include <dev/ofw/ofw_pinctrl.h> 47305ac5f9Spatrick #include <dev/ofw/ofw_regulator.h> 48305ac5f9Spatrick #include <dev/ofw/fdt.h> 49305ac5f9Spatrick 50305ac5f9Spatrick #include <dev/mii/mii.h> 51305ac5f9Spatrick #include <dev/mii/miivar.h> 52305ac5f9Spatrick 53305ac5f9Spatrick #if NBPFILTER > 0 54305ac5f9Spatrick #include <net/bpf.h> 55305ac5f9Spatrick #endif 56305ac5f9Spatrick 57305ac5f9Spatrick #include <netinet/in.h> 58305ac5f9Spatrick #include <netinet/if_ether.h> 59305ac5f9Spatrick 60305ac5f9Spatrick #include <dev/ic/dwqevar.h> 61305ac5f9Spatrick #include <dev/ic/dwqereg.h> 62305ac5f9Spatrick 63305ac5f9Spatrick struct cfdriver dwqe_cd = { 64305ac5f9Spatrick NULL, "dwqe", DV_IFNET 65305ac5f9Spatrick }; 66305ac5f9Spatrick 67305ac5f9Spatrick uint32_t dwqe_read(struct dwqe_softc *, bus_addr_t); 68305ac5f9Spatrick void dwqe_write(struct dwqe_softc *, bus_addr_t, uint32_t); 69305ac5f9Spatrick 70305ac5f9Spatrick int dwqe_ioctl(struct ifnet *, u_long, caddr_t); 71305ac5f9Spatrick void dwqe_start(struct ifqueue *); 72305ac5f9Spatrick void dwqe_watchdog(struct ifnet *); 73305ac5f9Spatrick 74305ac5f9Spatrick int dwqe_media_change(struct ifnet *); 75305ac5f9Spatrick void dwqe_media_status(struct ifnet *, struct ifmediareq *); 76305ac5f9Spatrick 77305ac5f9Spatrick int dwqe_mii_readreg(struct device *, int, int); 78305ac5f9Spatrick void dwqe_mii_writereg(struct device *, int, int, int); 79305ac5f9Spatrick void dwqe_mii_statchg(struct device *); 80305ac5f9Spatrick 81305ac5f9Spatrick void dwqe_lladdr_read(struct dwqe_softc *, uint8_t *); 82305ac5f9Spatrick void dwqe_lladdr_write(struct dwqe_softc *); 83305ac5f9Spatrick 84305ac5f9Spatrick void dwqe_tick(void *); 85305ac5f9Spatrick void dwqe_rxtick(void *); 86305ac5f9Spatrick 87305ac5f9Spatrick int dwqe_intr(void *); 88305ac5f9Spatrick void dwqe_tx_proc(struct dwqe_softc *); 89305ac5f9Spatrick void dwqe_rx_proc(struct dwqe_softc *); 90305ac5f9Spatrick 91305ac5f9Spatrick void dwqe_up(struct dwqe_softc *); 92305ac5f9Spatrick void dwqe_down(struct dwqe_softc *); 93305ac5f9Spatrick void dwqe_iff(struct dwqe_softc *); 94305ac5f9Spatrick int dwqe_encap(struct dwqe_softc *, struct mbuf *, int *, int *); 95305ac5f9Spatrick 96305ac5f9Spatrick void dwqe_reset(struct dwqe_softc *); 97305ac5f9Spatrick 98305ac5f9Spatrick struct dwqe_dmamem * 99305ac5f9Spatrick dwqe_dmamem_alloc(struct dwqe_softc *, bus_size_t, bus_size_t); 100305ac5f9Spatrick void dwqe_dmamem_free(struct dwqe_softc *, struct dwqe_dmamem *); 101305ac5f9Spatrick struct mbuf *dwqe_alloc_mbuf(struct dwqe_softc *, bus_dmamap_t); 102305ac5f9Spatrick void dwqe_fill_rx_ring(struct dwqe_softc *); 103305ac5f9Spatrick 104305ac5f9Spatrick int 105305ac5f9Spatrick dwqe_attach(struct dwqe_softc *sc) 106305ac5f9Spatrick { 107305ac5f9Spatrick struct ifnet *ifp; 108305ac5f9Spatrick uint32_t version, mode; 109305ac5f9Spatrick int i; 110305ac5f9Spatrick 111305ac5f9Spatrick version = dwqe_read(sc, GMAC_VERSION); 112*4fa84378Skettenis printf(": rev 0x%02x, address %s\n", version & GMAC_VERSION_SNPS_MASK, 113305ac5f9Spatrick ether_sprintf(sc->sc_lladdr)); 114305ac5f9Spatrick 115305ac5f9Spatrick for (i = 0; i < 4; i++) 116305ac5f9Spatrick sc->sc_hw_feature[i] = dwqe_read(sc, GMAC_MAC_HW_FEATURE(i)); 117305ac5f9Spatrick 118305ac5f9Spatrick timeout_set(&sc->sc_tick, dwqe_tick, sc); 119305ac5f9Spatrick timeout_set(&sc->sc_rxto, dwqe_rxtick, sc); 120305ac5f9Spatrick 121305ac5f9Spatrick ifp = &sc->sc_ac.ac_if; 122305ac5f9Spatrick ifp->if_softc = sc; 123305ac5f9Spatrick ifp->if_flags = IFF_BROADCAST | IFF_SIMPLEX | IFF_MULTICAST; 124305ac5f9Spatrick ifp->if_xflags = IFXF_MPSAFE; 125305ac5f9Spatrick ifp->if_ioctl = dwqe_ioctl; 126305ac5f9Spatrick ifp->if_qstart = dwqe_start; 127305ac5f9Spatrick ifp->if_watchdog = dwqe_watchdog; 128305ac5f9Spatrick ifq_set_maxlen(&ifp->if_snd, DWQE_NTXDESC - 1); 129305ac5f9Spatrick bcopy(sc->sc_dev.dv_xname, ifp->if_xname, IFNAMSIZ); 130305ac5f9Spatrick 131305ac5f9Spatrick ifp->if_capabilities = IFCAP_VLAN_MTU; 132305ac5f9Spatrick 133305ac5f9Spatrick sc->sc_mii.mii_ifp = ifp; 134305ac5f9Spatrick sc->sc_mii.mii_readreg = dwqe_mii_readreg; 135305ac5f9Spatrick sc->sc_mii.mii_writereg = dwqe_mii_writereg; 136305ac5f9Spatrick sc->sc_mii.mii_statchg = dwqe_mii_statchg; 137305ac5f9Spatrick 138305ac5f9Spatrick ifmedia_init(&sc->sc_media, 0, dwqe_media_change, dwqe_media_status); 139305ac5f9Spatrick 140305ac5f9Spatrick dwqe_reset(sc); 141305ac5f9Spatrick 142305ac5f9Spatrick /* Configure DMA engine. */ 143305ac5f9Spatrick mode = dwqe_read(sc, GMAC_SYS_BUS_MODE); 144305ac5f9Spatrick if (sc->sc_fixed_burst) 145305ac5f9Spatrick mode |= GMAC_SYS_BUS_MODE_FB; 146305ac5f9Spatrick if (sc->sc_mixed_burst) 147305ac5f9Spatrick mode |= GMAC_SYS_BUS_MODE_MB; 148305ac5f9Spatrick if (sc->sc_aal) 149305ac5f9Spatrick mode |= GMAC_SYS_BUS_MODE_AAL; 150305ac5f9Spatrick dwqe_write(sc, GMAC_SYS_BUS_MODE, mode); 151305ac5f9Spatrick 152305ac5f9Spatrick /* Configure channel 0. */ 153305ac5f9Spatrick mode = dwqe_read(sc, GMAC_CHAN_CONTROL(0)); 154305ac5f9Spatrick if (sc->sc_8xpbl) 155305ac5f9Spatrick mode |= GMAC_CHAN_CONTROL_8XPBL; 156305ac5f9Spatrick dwqe_write(sc, GMAC_CHAN_CONTROL(0), mode); 157305ac5f9Spatrick 158305ac5f9Spatrick mode = dwqe_read(sc, GMAC_CHAN_TX_CONTROL(0)); 159305ac5f9Spatrick mode &= ~GMAC_CHAN_TX_CONTROL_PBL_MASK; 160305ac5f9Spatrick mode |= sc->sc_txpbl << GMAC_CHAN_TX_CONTROL_PBL_SHIFT; 161305ac5f9Spatrick mode |= GMAC_CHAN_TX_CONTROL_OSP; 162305ac5f9Spatrick dwqe_write(sc, GMAC_CHAN_TX_CONTROL(0), mode); 163305ac5f9Spatrick mode &= ~GMAC_CHAN_RX_CONTROL_RPBL_MASK; 164305ac5f9Spatrick mode |= sc->sc_rxpbl << GMAC_CHAN_RX_CONTROL_RPBL_SHIFT; 165305ac5f9Spatrick mode = dwqe_read(sc, GMAC_CHAN_RX_CONTROL(0)); 166305ac5f9Spatrick dwqe_write(sc, GMAC_CHAN_RX_CONTROL(0), mode); 167305ac5f9Spatrick 168305ac5f9Spatrick /* Configure AXI master. */ 169305ac5f9Spatrick if (sc->sc_axi_config) { 170305ac5f9Spatrick int i; 171305ac5f9Spatrick 172305ac5f9Spatrick mode = dwqe_read(sc, GMAC_SYS_BUS_MODE); 173305ac5f9Spatrick 174305ac5f9Spatrick mode &= ~GMAC_SYS_BUS_MODE_EN_LPI; 175305ac5f9Spatrick if (sc->sc_lpi_en) 176305ac5f9Spatrick mode |= GMAC_SYS_BUS_MODE_EN_LPI; 177305ac5f9Spatrick mode &= ~GMAC_SYS_BUS_MODE_LPI_XIT_FRM; 178305ac5f9Spatrick if (sc->sc_xit_frm) 179305ac5f9Spatrick mode |= GMAC_SYS_BUS_MODE_LPI_XIT_FRM; 180305ac5f9Spatrick 181305ac5f9Spatrick mode &= ~GMAC_SYS_BUS_MODE_WR_OSR_LMT_MASK; 182305ac5f9Spatrick mode |= (sc->sc_wr_osr_lmt << GMAC_SYS_BUS_MODE_WR_OSR_LMT_SHIFT); 183305ac5f9Spatrick mode &= ~GMAC_SYS_BUS_MODE_RD_OSR_LMT_MASK; 184305ac5f9Spatrick mode |= (sc->sc_rd_osr_lmt << GMAC_SYS_BUS_MODE_RD_OSR_LMT_SHIFT); 185305ac5f9Spatrick 186305ac5f9Spatrick for (i = 0; i < nitems(sc->sc_blen); i++) { 187305ac5f9Spatrick switch (sc->sc_blen[i]) { 188305ac5f9Spatrick case 256: 189305ac5f9Spatrick mode |= GMAC_SYS_BUS_MODE_BLEN_256; 190305ac5f9Spatrick break; 191305ac5f9Spatrick case 128: 192305ac5f9Spatrick mode |= GMAC_SYS_BUS_MODE_BLEN_128; 193305ac5f9Spatrick break; 194305ac5f9Spatrick case 64: 195305ac5f9Spatrick mode |= GMAC_SYS_BUS_MODE_BLEN_64; 196305ac5f9Spatrick break; 197305ac5f9Spatrick case 32: 198305ac5f9Spatrick mode |= GMAC_SYS_BUS_MODE_BLEN_32; 199305ac5f9Spatrick break; 200305ac5f9Spatrick case 16: 201305ac5f9Spatrick mode |= GMAC_SYS_BUS_MODE_BLEN_16; 202305ac5f9Spatrick break; 203305ac5f9Spatrick case 8: 204305ac5f9Spatrick mode |= GMAC_SYS_BUS_MODE_BLEN_8; 205305ac5f9Spatrick break; 206305ac5f9Spatrick case 4: 207305ac5f9Spatrick mode |= GMAC_SYS_BUS_MODE_BLEN_4; 208305ac5f9Spatrick break; 209305ac5f9Spatrick } 210305ac5f9Spatrick } 211305ac5f9Spatrick 212305ac5f9Spatrick dwqe_write(sc, GMAC_SYS_BUS_MODE, mode); 213305ac5f9Spatrick } 214305ac5f9Spatrick 215305ac5f9Spatrick mii_attach(&sc->sc_dev, &sc->sc_mii, 0xffffffff, sc->sc_phyloc, 216305ac5f9Spatrick (sc->sc_phyloc == MII_PHY_ANY) ? 0 : MII_OFFSET_ANY, 0); 217305ac5f9Spatrick if (LIST_FIRST(&sc->sc_mii.mii_phys) == NULL) { 218305ac5f9Spatrick printf("%s: no PHY found!\n", sc->sc_dev.dv_xname); 219305ac5f9Spatrick ifmedia_add(&sc->sc_media, IFM_ETHER|IFM_MANUAL, 0, NULL); 220305ac5f9Spatrick ifmedia_set(&sc->sc_media, IFM_ETHER|IFM_MANUAL); 221305ac5f9Spatrick } else 222305ac5f9Spatrick ifmedia_set(&sc->sc_media, IFM_ETHER|IFM_AUTO); 223305ac5f9Spatrick 224305ac5f9Spatrick if_attach(ifp); 225305ac5f9Spatrick ether_ifattach(ifp); 226305ac5f9Spatrick 227305ac5f9Spatrick /* Disable interrupts. */ 228305ac5f9Spatrick dwqe_write(sc, GMAC_INT_EN, 0); 229305ac5f9Spatrick dwqe_write(sc, GMAC_CHAN_INTR_ENA(0), 0); 230305ac5f9Spatrick 231305ac5f9Spatrick return 0; 232305ac5f9Spatrick } 233305ac5f9Spatrick 234305ac5f9Spatrick uint32_t 235305ac5f9Spatrick dwqe_read(struct dwqe_softc *sc, bus_addr_t addr) 236305ac5f9Spatrick { 237305ac5f9Spatrick return bus_space_read_4(sc->sc_iot, sc->sc_ioh, addr); 238305ac5f9Spatrick } 239305ac5f9Spatrick 240305ac5f9Spatrick void 241305ac5f9Spatrick dwqe_write(struct dwqe_softc *sc, bus_addr_t addr, uint32_t data) 242305ac5f9Spatrick { 243305ac5f9Spatrick bus_space_write_4(sc->sc_iot, sc->sc_ioh, addr, data); 244305ac5f9Spatrick } 245305ac5f9Spatrick 246305ac5f9Spatrick void 247305ac5f9Spatrick dwqe_lladdr_read(struct dwqe_softc *sc, uint8_t *lladdr) 248305ac5f9Spatrick { 249305ac5f9Spatrick uint32_t machi, maclo; 250305ac5f9Spatrick 251305ac5f9Spatrick machi = dwqe_read(sc, GMAC_MAC_ADDR0_HI); 252305ac5f9Spatrick maclo = dwqe_read(sc, GMAC_MAC_ADDR0_LO); 253305ac5f9Spatrick 254305ac5f9Spatrick if (machi || maclo) { 255305ac5f9Spatrick lladdr[0] = (maclo >> 0) & 0xff; 256305ac5f9Spatrick lladdr[1] = (maclo >> 8) & 0xff; 257305ac5f9Spatrick lladdr[2] = (maclo >> 16) & 0xff; 258305ac5f9Spatrick lladdr[3] = (maclo >> 24) & 0xff; 259305ac5f9Spatrick lladdr[4] = (machi >> 0) & 0xff; 260305ac5f9Spatrick lladdr[5] = (machi >> 8) & 0xff; 261305ac5f9Spatrick } else { 262305ac5f9Spatrick ether_fakeaddr(&sc->sc_ac.ac_if); 263305ac5f9Spatrick } 264305ac5f9Spatrick } 265305ac5f9Spatrick 266305ac5f9Spatrick void 267305ac5f9Spatrick dwqe_lladdr_write(struct dwqe_softc *sc) 268305ac5f9Spatrick { 269305ac5f9Spatrick dwqe_write(sc, GMAC_MAC_ADDR0_HI, 270305ac5f9Spatrick sc->sc_lladdr[5] << 8 | sc->sc_lladdr[4] << 0); 271305ac5f9Spatrick dwqe_write(sc, GMAC_MAC_ADDR0_LO, 272305ac5f9Spatrick sc->sc_lladdr[3] << 24 | sc->sc_lladdr[2] << 16 | 273305ac5f9Spatrick sc->sc_lladdr[1] << 8 | sc->sc_lladdr[0] << 0); 274305ac5f9Spatrick } 275305ac5f9Spatrick 276305ac5f9Spatrick void 277305ac5f9Spatrick dwqe_start(struct ifqueue *ifq) 278305ac5f9Spatrick { 279305ac5f9Spatrick struct ifnet *ifp = ifq->ifq_if; 280305ac5f9Spatrick struct dwqe_softc *sc = ifp->if_softc; 281305ac5f9Spatrick struct mbuf *m; 282305ac5f9Spatrick int error, idx, left, used; 283305ac5f9Spatrick 284305ac5f9Spatrick if (!(ifp->if_flags & IFF_RUNNING)) 285305ac5f9Spatrick return; 286305ac5f9Spatrick if (ifq_is_oactive(&ifp->if_snd)) 287305ac5f9Spatrick return; 288305ac5f9Spatrick if (ifq_empty(&ifp->if_snd)) 289305ac5f9Spatrick return; 290305ac5f9Spatrick if (!sc->sc_link) 291305ac5f9Spatrick return; 292305ac5f9Spatrick 293305ac5f9Spatrick idx = sc->sc_tx_prod; 294305ac5f9Spatrick left = sc->sc_tx_cons; 295305ac5f9Spatrick if (left <= idx) 296305ac5f9Spatrick left += DWQE_NTXDESC; 297305ac5f9Spatrick left -= idx; 298305ac5f9Spatrick used = 0; 299305ac5f9Spatrick 300305ac5f9Spatrick for (;;) { 301305ac5f9Spatrick if (used + DWQE_NTXSEGS + 1 > left) { 302305ac5f9Spatrick ifq_set_oactive(ifq); 303305ac5f9Spatrick break; 304305ac5f9Spatrick } 305305ac5f9Spatrick 306305ac5f9Spatrick m = ifq_dequeue(ifq); 307305ac5f9Spatrick if (m == NULL) 308305ac5f9Spatrick break; 309305ac5f9Spatrick 310305ac5f9Spatrick error = dwqe_encap(sc, m, &idx, &used); 311305ac5f9Spatrick if (error == EFBIG) { 312305ac5f9Spatrick m_freem(m); /* give up: drop it */ 313305ac5f9Spatrick ifp->if_oerrors++; 314305ac5f9Spatrick continue; 315305ac5f9Spatrick } 316305ac5f9Spatrick 317305ac5f9Spatrick #if NBPFILTER > 0 318305ac5f9Spatrick if (ifp->if_bpf) 319305ac5f9Spatrick bpf_mtap(ifp->if_bpf, m, BPF_DIRECTION_OUT); 320305ac5f9Spatrick #endif 321305ac5f9Spatrick } 322305ac5f9Spatrick 323305ac5f9Spatrick if (sc->sc_tx_prod != idx) { 324305ac5f9Spatrick sc->sc_tx_prod = idx; 325305ac5f9Spatrick 326305ac5f9Spatrick /* Set a timeout in case the chip goes out to lunch. */ 327305ac5f9Spatrick ifp->if_timer = 5; 328305ac5f9Spatrick } 329305ac5f9Spatrick } 330305ac5f9Spatrick 331305ac5f9Spatrick int 332305ac5f9Spatrick dwqe_ioctl(struct ifnet *ifp, u_long cmd, caddr_t addr) 333305ac5f9Spatrick { 334305ac5f9Spatrick struct dwqe_softc *sc = ifp->if_softc; 335305ac5f9Spatrick struct ifreq *ifr = (struct ifreq *)addr; 336305ac5f9Spatrick int error = 0, s; 337305ac5f9Spatrick 338305ac5f9Spatrick s = splnet(); 339305ac5f9Spatrick 340305ac5f9Spatrick switch (cmd) { 341305ac5f9Spatrick case SIOCSIFADDR: 342305ac5f9Spatrick ifp->if_flags |= IFF_UP; 343305ac5f9Spatrick /* FALLTHROUGH */ 344305ac5f9Spatrick case SIOCSIFFLAGS: 345305ac5f9Spatrick if (ifp->if_flags & IFF_UP) { 346305ac5f9Spatrick if (ifp->if_flags & IFF_RUNNING) 347305ac5f9Spatrick error = ENETRESET; 348305ac5f9Spatrick else 349305ac5f9Spatrick dwqe_up(sc); 350305ac5f9Spatrick } else { 351305ac5f9Spatrick if (ifp->if_flags & IFF_RUNNING) 352305ac5f9Spatrick dwqe_down(sc); 353305ac5f9Spatrick } 354305ac5f9Spatrick break; 355305ac5f9Spatrick 356305ac5f9Spatrick case SIOCGIFMEDIA: 357305ac5f9Spatrick case SIOCSIFMEDIA: 358305ac5f9Spatrick error = ifmedia_ioctl(ifp, ifr, &sc->sc_media, cmd); 359305ac5f9Spatrick break; 360305ac5f9Spatrick 361305ac5f9Spatrick case SIOCGIFRXR: 362305ac5f9Spatrick error = if_rxr_ioctl((struct if_rxrinfo *)ifr->ifr_data, 363305ac5f9Spatrick NULL, MCLBYTES, &sc->sc_rx_ring); 364305ac5f9Spatrick break; 365305ac5f9Spatrick 366305ac5f9Spatrick default: 367305ac5f9Spatrick error = ether_ioctl(ifp, &sc->sc_ac, cmd, addr); 368305ac5f9Spatrick break; 369305ac5f9Spatrick } 370305ac5f9Spatrick 371305ac5f9Spatrick if (error == ENETRESET) { 372305ac5f9Spatrick if (ifp->if_flags & IFF_RUNNING) 373305ac5f9Spatrick dwqe_iff(sc); 374305ac5f9Spatrick error = 0; 375305ac5f9Spatrick } 376305ac5f9Spatrick 377305ac5f9Spatrick splx(s); 378305ac5f9Spatrick return (error); 379305ac5f9Spatrick } 380305ac5f9Spatrick 381305ac5f9Spatrick void 382305ac5f9Spatrick dwqe_watchdog(struct ifnet *ifp) 383305ac5f9Spatrick { 384305ac5f9Spatrick printf("%s\n", __func__); 385305ac5f9Spatrick } 386305ac5f9Spatrick 387305ac5f9Spatrick int 388305ac5f9Spatrick dwqe_media_change(struct ifnet *ifp) 389305ac5f9Spatrick { 390305ac5f9Spatrick struct dwqe_softc *sc = ifp->if_softc; 391305ac5f9Spatrick 392305ac5f9Spatrick if (LIST_FIRST(&sc->sc_mii.mii_phys)) 393305ac5f9Spatrick mii_mediachg(&sc->sc_mii); 394305ac5f9Spatrick 395305ac5f9Spatrick return (0); 396305ac5f9Spatrick } 397305ac5f9Spatrick 398305ac5f9Spatrick void 399305ac5f9Spatrick dwqe_media_status(struct ifnet *ifp, struct ifmediareq *ifmr) 400305ac5f9Spatrick { 401305ac5f9Spatrick struct dwqe_softc *sc = ifp->if_softc; 402305ac5f9Spatrick 403305ac5f9Spatrick if (LIST_FIRST(&sc->sc_mii.mii_phys)) { 404305ac5f9Spatrick mii_pollstat(&sc->sc_mii); 405305ac5f9Spatrick ifmr->ifm_active = sc->sc_mii.mii_media_active; 406305ac5f9Spatrick ifmr->ifm_status = sc->sc_mii.mii_media_status; 407305ac5f9Spatrick } 408305ac5f9Spatrick } 409305ac5f9Spatrick 410305ac5f9Spatrick int 411305ac5f9Spatrick dwqe_mii_readreg(struct device *self, int phy, int reg) 412305ac5f9Spatrick { 413305ac5f9Spatrick struct dwqe_softc *sc = (void *)self; 414305ac5f9Spatrick int n; 415305ac5f9Spatrick 416305ac5f9Spatrick dwqe_write(sc, GMAC_MAC_MDIO_ADDR, 417305ac5f9Spatrick sc->sc_clk << GMAC_MAC_MDIO_ADDR_CR_SHIFT | 418305ac5f9Spatrick (phy << GMAC_MAC_MDIO_ADDR_PA_SHIFT) | 419305ac5f9Spatrick (reg << GMAC_MAC_MDIO_ADDR_RDA_SHIFT) | 420305ac5f9Spatrick GMAC_MAC_MDIO_ADDR_GOC_READ | 421305ac5f9Spatrick GMAC_MAC_MDIO_ADDR_GB); 422305ac5f9Spatrick delay(10000); 423305ac5f9Spatrick 424305ac5f9Spatrick for (n = 0; n < 1000; n++) { 425305ac5f9Spatrick if ((dwqe_read(sc, GMAC_MAC_MDIO_ADDR) & GMAC_MAC_MDIO_ADDR_GB) == 0) 426305ac5f9Spatrick return dwqe_read(sc, GMAC_MAC_MDIO_DATA); 427305ac5f9Spatrick delay(10); 428305ac5f9Spatrick } 429305ac5f9Spatrick 430305ac5f9Spatrick printf("%s: mii_read timeout\n", sc->sc_dev.dv_xname); 431305ac5f9Spatrick return (0); 432305ac5f9Spatrick } 433305ac5f9Spatrick 434305ac5f9Spatrick void 435305ac5f9Spatrick dwqe_mii_writereg(struct device *self, int phy, int reg, int val) 436305ac5f9Spatrick { 437305ac5f9Spatrick struct dwqe_softc *sc = (void *)self; 438305ac5f9Spatrick int n; 439305ac5f9Spatrick 440305ac5f9Spatrick dwqe_write(sc, GMAC_MAC_MDIO_DATA, val); 441305ac5f9Spatrick dwqe_write(sc, GMAC_MAC_MDIO_ADDR, 442305ac5f9Spatrick sc->sc_clk << GMAC_MAC_MDIO_ADDR_CR_SHIFT | 443305ac5f9Spatrick (phy << GMAC_MAC_MDIO_ADDR_PA_SHIFT) | 444305ac5f9Spatrick (reg << GMAC_MAC_MDIO_ADDR_RDA_SHIFT) | 445305ac5f9Spatrick GMAC_MAC_MDIO_ADDR_GOC_WRITE | 446305ac5f9Spatrick GMAC_MAC_MDIO_ADDR_GB); 447305ac5f9Spatrick delay(10000); 448305ac5f9Spatrick for (n = 0; n < 1000; n++) { 449305ac5f9Spatrick if ((dwqe_read(sc, GMAC_MAC_MDIO_ADDR) & GMAC_MAC_MDIO_ADDR_GB) == 0) 450305ac5f9Spatrick return; 451305ac5f9Spatrick delay(10); 452305ac5f9Spatrick } 453305ac5f9Spatrick 454305ac5f9Spatrick printf("%s: mii_write timeout\n", sc->sc_dev.dv_xname); 455305ac5f9Spatrick } 456305ac5f9Spatrick 457305ac5f9Spatrick void 458305ac5f9Spatrick dwqe_mii_statchg(struct device *self) 459305ac5f9Spatrick { 460305ac5f9Spatrick struct dwqe_softc *sc = (void *)self; 461305ac5f9Spatrick uint32_t conf; 462305ac5f9Spatrick 463305ac5f9Spatrick conf = dwqe_read(sc, GMAC_MAC_CONF); 464305ac5f9Spatrick conf &= ~(GMAC_MAC_CONF_PS | GMAC_MAC_CONF_FES); 465305ac5f9Spatrick 466305ac5f9Spatrick switch (IFM_SUBTYPE(sc->sc_mii.mii_media_active)) { 467305ac5f9Spatrick case IFM_1000_SX: 468305ac5f9Spatrick case IFM_1000_LX: 469305ac5f9Spatrick case IFM_1000_CX: 470305ac5f9Spatrick case IFM_1000_T: 471305ac5f9Spatrick sc->sc_link = 1; 472305ac5f9Spatrick break; 473305ac5f9Spatrick case IFM_100_TX: 474305ac5f9Spatrick conf |= GMAC_MAC_CONF_PS | GMAC_MAC_CONF_FES; 475305ac5f9Spatrick sc->sc_link = 1; 476305ac5f9Spatrick break; 477305ac5f9Spatrick case IFM_10_T: 478305ac5f9Spatrick conf |= GMAC_MAC_CONF_PS; 479305ac5f9Spatrick sc->sc_link = 1; 480305ac5f9Spatrick break; 481305ac5f9Spatrick default: 482305ac5f9Spatrick sc->sc_link = 0; 483305ac5f9Spatrick return; 484305ac5f9Spatrick } 485305ac5f9Spatrick 486305ac5f9Spatrick if (sc->sc_link == 0) 487305ac5f9Spatrick return; 488305ac5f9Spatrick 489305ac5f9Spatrick conf &= ~GMAC_MAC_CONF_DM; 490305ac5f9Spatrick if ((sc->sc_mii.mii_media_active & IFM_GMASK) == IFM_FDX) 491305ac5f9Spatrick conf |= GMAC_MAC_CONF_DM; 492305ac5f9Spatrick 493305ac5f9Spatrick dwqe_write(sc, GMAC_MAC_CONF, conf); 494305ac5f9Spatrick } 495305ac5f9Spatrick 496305ac5f9Spatrick void 497305ac5f9Spatrick dwqe_tick(void *arg) 498305ac5f9Spatrick { 499305ac5f9Spatrick struct dwqe_softc *sc = arg; 500305ac5f9Spatrick int s; 501305ac5f9Spatrick 502305ac5f9Spatrick s = splnet(); 503305ac5f9Spatrick mii_tick(&sc->sc_mii); 504305ac5f9Spatrick splx(s); 505305ac5f9Spatrick 506305ac5f9Spatrick timeout_add_sec(&sc->sc_tick, 1); 507305ac5f9Spatrick } 508305ac5f9Spatrick 509305ac5f9Spatrick void 510305ac5f9Spatrick dwqe_rxtick(void *arg) 511305ac5f9Spatrick { 512305ac5f9Spatrick struct dwqe_softc *sc = arg; 513305ac5f9Spatrick int s; 514305ac5f9Spatrick 515305ac5f9Spatrick s = splnet(); 516305ac5f9Spatrick 517305ac5f9Spatrick /* TODO: disable RXQ? */ 518305ac5f9Spatrick printf("%s:%d\n", __func__, __LINE__); 519305ac5f9Spatrick 520305ac5f9Spatrick bus_dmamap_sync(sc->sc_dmat, DWQE_DMA_MAP(sc->sc_rxring), 521305ac5f9Spatrick 0, DWQE_DMA_LEN(sc->sc_rxring), 522305ac5f9Spatrick BUS_DMASYNC_POSTREAD|BUS_DMASYNC_POSTWRITE); 523305ac5f9Spatrick 524305ac5f9Spatrick dwqe_write(sc, GMAC_CHAN_RX_BASE_ADDR_HI(0), 0); 525305ac5f9Spatrick dwqe_write(sc, GMAC_CHAN_RX_BASE_ADDR(0), 0); 526305ac5f9Spatrick 527305ac5f9Spatrick sc->sc_rx_prod = sc->sc_rx_cons = 0; 528305ac5f9Spatrick dwqe_fill_rx_ring(sc); 529305ac5f9Spatrick 530305ac5f9Spatrick bus_dmamap_sync(sc->sc_dmat, DWQE_DMA_MAP(sc->sc_rxring), 531305ac5f9Spatrick 0, DWQE_DMA_LEN(sc->sc_rxring), 532305ac5f9Spatrick BUS_DMASYNC_PREREAD|BUS_DMASYNC_PREWRITE); 533305ac5f9Spatrick 534305ac5f9Spatrick dwqe_write(sc, GMAC_CHAN_RX_BASE_ADDR_HI(0), DWQE_DMA_DVA(sc->sc_rxring) >> 32); 535305ac5f9Spatrick dwqe_write(sc, GMAC_CHAN_RX_BASE_ADDR(0), DWQE_DMA_DVA(sc->sc_rxring)); 536305ac5f9Spatrick 537305ac5f9Spatrick /* TODO: re-enable RXQ? */ 538305ac5f9Spatrick 539305ac5f9Spatrick splx(s); 540305ac5f9Spatrick } 541305ac5f9Spatrick 542305ac5f9Spatrick int 543305ac5f9Spatrick dwqe_intr(void *arg) 544305ac5f9Spatrick { 545305ac5f9Spatrick struct dwqe_softc *sc = arg; 546305ac5f9Spatrick uint32_t reg; 547305ac5f9Spatrick 548305ac5f9Spatrick reg = dwqe_read(sc, GMAC_INT_STATUS); 549305ac5f9Spatrick dwqe_write(sc, GMAC_INT_STATUS, reg); 550305ac5f9Spatrick 551305ac5f9Spatrick reg = dwqe_read(sc, GMAC_CHAN_STATUS(0)); 552305ac5f9Spatrick dwqe_write(sc, GMAC_CHAN_STATUS(0), reg); 553305ac5f9Spatrick 554305ac5f9Spatrick if (reg & GMAC_CHAN_STATUS_RI) 555305ac5f9Spatrick dwqe_rx_proc(sc); 556305ac5f9Spatrick 557305ac5f9Spatrick if (reg & GMAC_CHAN_STATUS_TI) 558305ac5f9Spatrick dwqe_tx_proc(sc); 559305ac5f9Spatrick 560305ac5f9Spatrick return (1); 561305ac5f9Spatrick } 562305ac5f9Spatrick 563305ac5f9Spatrick void 564305ac5f9Spatrick dwqe_tx_proc(struct dwqe_softc *sc) 565305ac5f9Spatrick { 566305ac5f9Spatrick struct ifnet *ifp = &sc->sc_ac.ac_if; 567305ac5f9Spatrick struct dwqe_desc *txd; 568305ac5f9Spatrick struct dwqe_buf *txb; 569305ac5f9Spatrick int idx, txfree; 570305ac5f9Spatrick 571305ac5f9Spatrick bus_dmamap_sync(sc->sc_dmat, DWQE_DMA_MAP(sc->sc_txring), 0, 572305ac5f9Spatrick DWQE_DMA_LEN(sc->sc_txring), 573305ac5f9Spatrick BUS_DMASYNC_POSTREAD | BUS_DMASYNC_POSTWRITE); 574305ac5f9Spatrick 575305ac5f9Spatrick txfree = 0; 576305ac5f9Spatrick while (sc->sc_tx_cons != sc->sc_tx_prod) { 577305ac5f9Spatrick idx = sc->sc_tx_cons; 578305ac5f9Spatrick KASSERT(idx < DWQE_NTXDESC); 579305ac5f9Spatrick 580305ac5f9Spatrick txd = &sc->sc_txdesc[idx]; 581305ac5f9Spatrick if (txd->sd_tdes3 & TDES3_OWN) 582305ac5f9Spatrick break; 583305ac5f9Spatrick 584305ac5f9Spatrick txb = &sc->sc_txbuf[idx]; 585305ac5f9Spatrick if (txb->tb_m) { 586305ac5f9Spatrick bus_dmamap_sync(sc->sc_dmat, txb->tb_map, 0, 587305ac5f9Spatrick txb->tb_map->dm_mapsize, BUS_DMASYNC_POSTWRITE); 588305ac5f9Spatrick bus_dmamap_unload(sc->sc_dmat, txb->tb_map); 589305ac5f9Spatrick 590305ac5f9Spatrick m_freem(txb->tb_m); 591305ac5f9Spatrick txb->tb_m = NULL; 592305ac5f9Spatrick } 593305ac5f9Spatrick 594305ac5f9Spatrick txfree++; 595305ac5f9Spatrick 596305ac5f9Spatrick if (sc->sc_tx_cons == (DWQE_NTXDESC - 1)) 597305ac5f9Spatrick sc->sc_tx_cons = 0; 598305ac5f9Spatrick else 599305ac5f9Spatrick sc->sc_tx_cons++; 600305ac5f9Spatrick 601305ac5f9Spatrick txd->sd_tdes3 = 0; 602305ac5f9Spatrick } 603305ac5f9Spatrick 604305ac5f9Spatrick if (sc->sc_tx_cons == sc->sc_tx_prod) 605305ac5f9Spatrick ifp->if_timer = 0; 606305ac5f9Spatrick 607305ac5f9Spatrick if (txfree) { 608305ac5f9Spatrick if (ifq_is_oactive(&ifp->if_snd)) 609305ac5f9Spatrick ifq_restart(&ifp->if_snd); 610305ac5f9Spatrick } 611305ac5f9Spatrick } 612305ac5f9Spatrick 613305ac5f9Spatrick void 614305ac5f9Spatrick dwqe_rx_proc(struct dwqe_softc *sc) 615305ac5f9Spatrick { 616305ac5f9Spatrick struct ifnet *ifp = &sc->sc_ac.ac_if; 617305ac5f9Spatrick struct dwqe_desc *rxd; 618305ac5f9Spatrick struct dwqe_buf *rxb; 619305ac5f9Spatrick struct mbuf_list ml = MBUF_LIST_INITIALIZER(); 620305ac5f9Spatrick struct mbuf *m; 621305ac5f9Spatrick int idx, len, cnt, put; 622305ac5f9Spatrick 623305ac5f9Spatrick if ((ifp->if_flags & IFF_RUNNING) == 0) 624305ac5f9Spatrick return; 625305ac5f9Spatrick 626305ac5f9Spatrick bus_dmamap_sync(sc->sc_dmat, DWQE_DMA_MAP(sc->sc_rxring), 0, 627305ac5f9Spatrick DWQE_DMA_LEN(sc->sc_rxring), 628305ac5f9Spatrick BUS_DMASYNC_POSTREAD | BUS_DMASYNC_POSTWRITE); 629305ac5f9Spatrick 630305ac5f9Spatrick cnt = if_rxr_inuse(&sc->sc_rx_ring); 631305ac5f9Spatrick put = 0; 632305ac5f9Spatrick while (put < cnt) { 633305ac5f9Spatrick idx = sc->sc_rx_cons; 634305ac5f9Spatrick KASSERT(idx < DWQE_NRXDESC); 635305ac5f9Spatrick 636305ac5f9Spatrick rxd = &sc->sc_rxdesc[idx]; 637305ac5f9Spatrick if (rxd->sd_tdes3 & RDES3_OWN) 638305ac5f9Spatrick break; 639305ac5f9Spatrick 640305ac5f9Spatrick len = rxd->sd_tdes3 & RDES3_LENGTH; 641305ac5f9Spatrick rxb = &sc->sc_rxbuf[idx]; 642305ac5f9Spatrick KASSERT(rxb->tb_m); 643305ac5f9Spatrick 644305ac5f9Spatrick bus_dmamap_sync(sc->sc_dmat, rxb->tb_map, 0, 645305ac5f9Spatrick len, BUS_DMASYNC_POSTREAD); 646305ac5f9Spatrick bus_dmamap_unload(sc->sc_dmat, rxb->tb_map); 647305ac5f9Spatrick 648305ac5f9Spatrick /* Strip off CRC. */ 649305ac5f9Spatrick len -= ETHER_CRC_LEN; 650305ac5f9Spatrick KASSERT(len > 0); 651305ac5f9Spatrick 652305ac5f9Spatrick m = rxb->tb_m; 653305ac5f9Spatrick rxb->tb_m = NULL; 654305ac5f9Spatrick m->m_pkthdr.len = m->m_len = len; 655305ac5f9Spatrick 656305ac5f9Spatrick ml_enqueue(&ml, m); 657305ac5f9Spatrick 658305ac5f9Spatrick put++; 659305ac5f9Spatrick if (sc->sc_rx_cons == (DWQE_NRXDESC - 1)) 660305ac5f9Spatrick sc->sc_rx_cons = 0; 661305ac5f9Spatrick else 662305ac5f9Spatrick sc->sc_rx_cons++; 663305ac5f9Spatrick } 664305ac5f9Spatrick 665305ac5f9Spatrick if_rxr_put(&sc->sc_rx_ring, put); 666305ac5f9Spatrick if (ifiq_input(&ifp->if_rcv, &ml)) 667305ac5f9Spatrick if_rxr_livelocked(&sc->sc_rx_ring); 668305ac5f9Spatrick 669305ac5f9Spatrick dwqe_fill_rx_ring(sc); 670305ac5f9Spatrick 671305ac5f9Spatrick bus_dmamap_sync(sc->sc_dmat, DWQE_DMA_MAP(sc->sc_rxring), 0, 672305ac5f9Spatrick DWQE_DMA_LEN(sc->sc_rxring), 673305ac5f9Spatrick BUS_DMASYNC_PREREAD | BUS_DMASYNC_PREWRITE); 674305ac5f9Spatrick 675305ac5f9Spatrick } 676305ac5f9Spatrick 677305ac5f9Spatrick void 678305ac5f9Spatrick dwqe_up(struct dwqe_softc *sc) 679305ac5f9Spatrick { 680305ac5f9Spatrick struct ifnet *ifp = &sc->sc_ac.ac_if; 681305ac5f9Spatrick struct dwqe_buf *txb, *rxb; 682305ac5f9Spatrick uint32_t mode, reg, tqs, rqs; 683305ac5f9Spatrick int i; 684305ac5f9Spatrick 685305ac5f9Spatrick /* Allocate Tx descriptor ring. */ 686305ac5f9Spatrick sc->sc_txring = dwqe_dmamem_alloc(sc, 687305ac5f9Spatrick DWQE_NTXDESC * sizeof(struct dwqe_desc), 8); 688305ac5f9Spatrick sc->sc_txdesc = DWQE_DMA_KVA(sc->sc_txring); 689305ac5f9Spatrick 690305ac5f9Spatrick sc->sc_txbuf = malloc(sizeof(struct dwqe_buf) * DWQE_NTXDESC, 691305ac5f9Spatrick M_DEVBUF, M_WAITOK); 692305ac5f9Spatrick for (i = 0; i < DWQE_NTXDESC; i++) { 693305ac5f9Spatrick txb = &sc->sc_txbuf[i]; 694305ac5f9Spatrick bus_dmamap_create(sc->sc_dmat, MCLBYTES, DWQE_NTXSEGS, 695305ac5f9Spatrick MCLBYTES, 0, BUS_DMA_WAITOK, &txb->tb_map); 696305ac5f9Spatrick txb->tb_m = NULL; 697305ac5f9Spatrick } 698305ac5f9Spatrick 699305ac5f9Spatrick bus_dmamap_sync(sc->sc_dmat, DWQE_DMA_MAP(sc->sc_txring), 700305ac5f9Spatrick 0, DWQE_DMA_LEN(sc->sc_txring), BUS_DMASYNC_PREWRITE); 701305ac5f9Spatrick 702305ac5f9Spatrick sc->sc_tx_prod = sc->sc_tx_cons = 0; 703305ac5f9Spatrick 704305ac5f9Spatrick dwqe_write(sc, GMAC_CHAN_TX_BASE_ADDR_HI(0), DWQE_DMA_DVA(sc->sc_txring) >> 32); 705305ac5f9Spatrick dwqe_write(sc, GMAC_CHAN_TX_BASE_ADDR(0), DWQE_DMA_DVA(sc->sc_txring)); 706305ac5f9Spatrick dwqe_write(sc, GMAC_CHAN_TX_RING_LEN(0), DWQE_NTXDESC - 1); 707305ac5f9Spatrick dwqe_write(sc, GMAC_CHAN_TX_END_ADDR(0), DWQE_DMA_DVA(sc->sc_txring)); 708305ac5f9Spatrick 709305ac5f9Spatrick /* Allocate descriptor ring. */ 710305ac5f9Spatrick sc->sc_rxring = dwqe_dmamem_alloc(sc, 711305ac5f9Spatrick DWQE_NRXDESC * sizeof(struct dwqe_desc), 8); 712305ac5f9Spatrick sc->sc_rxdesc = DWQE_DMA_KVA(sc->sc_rxring); 713305ac5f9Spatrick 714305ac5f9Spatrick sc->sc_rxbuf = malloc(sizeof(struct dwqe_buf) * DWQE_NRXDESC, 715305ac5f9Spatrick M_DEVBUF, M_WAITOK); 716305ac5f9Spatrick 717305ac5f9Spatrick for (i = 0; i < DWQE_NRXDESC; i++) { 718305ac5f9Spatrick rxb = &sc->sc_rxbuf[i]; 719305ac5f9Spatrick bus_dmamap_create(sc->sc_dmat, MCLBYTES, 1, 720305ac5f9Spatrick MCLBYTES, 0, BUS_DMA_WAITOK, &rxb->tb_map); 721305ac5f9Spatrick rxb->tb_m = NULL; 722305ac5f9Spatrick } 723305ac5f9Spatrick 724305ac5f9Spatrick if_rxr_init(&sc->sc_rx_ring, 2, DWQE_NRXDESC); 725305ac5f9Spatrick 726305ac5f9Spatrick dwqe_write(sc, GMAC_CHAN_RX_BASE_ADDR_HI(0), DWQE_DMA_DVA(sc->sc_rxring) >> 32); 727305ac5f9Spatrick dwqe_write(sc, GMAC_CHAN_RX_BASE_ADDR(0), DWQE_DMA_DVA(sc->sc_rxring)); 728305ac5f9Spatrick dwqe_write(sc, GMAC_CHAN_RX_RING_LEN(0), DWQE_NRXDESC - 1); 729305ac5f9Spatrick 730305ac5f9Spatrick sc->sc_rx_prod = sc->sc_rx_cons = 0; 731305ac5f9Spatrick dwqe_fill_rx_ring(sc); 732305ac5f9Spatrick 733305ac5f9Spatrick bus_dmamap_sync(sc->sc_dmat, DWQE_DMA_MAP(sc->sc_rxring), 734305ac5f9Spatrick 0, DWQE_DMA_LEN(sc->sc_rxring), 735305ac5f9Spatrick BUS_DMASYNC_PREREAD|BUS_DMASYNC_PREWRITE); 736305ac5f9Spatrick 737305ac5f9Spatrick dwqe_lladdr_write(sc); 738305ac5f9Spatrick 739305ac5f9Spatrick /* Configure media. */ 740305ac5f9Spatrick if (LIST_FIRST(&sc->sc_mii.mii_phys)) 741305ac5f9Spatrick mii_mediachg(&sc->sc_mii); 742305ac5f9Spatrick 743305ac5f9Spatrick /* Program promiscuous mode and multicast filters. */ 744305ac5f9Spatrick dwqe_iff(sc); 745305ac5f9Spatrick 746305ac5f9Spatrick ifp->if_flags |= IFF_RUNNING; 747305ac5f9Spatrick ifq_clr_oactive(&ifp->if_snd); 748305ac5f9Spatrick 749305ac5f9Spatrick dwqe_write(sc, GMAC_MAC_1US_TIC_CTR, (sc->sc_clk / 1000000) - 1); 750305ac5f9Spatrick 751305ac5f9Spatrick /* Start receive DMA */ 752305ac5f9Spatrick reg = dwqe_read(sc, GMAC_CHAN_RX_CONTROL(0)); 753305ac5f9Spatrick reg |= GMAC_CHAN_RX_CONTROL_SR; 754305ac5f9Spatrick dwqe_write(sc, GMAC_CHAN_RX_CONTROL(0), reg); 755305ac5f9Spatrick 756305ac5f9Spatrick /* Start transmit DMA */ 757305ac5f9Spatrick reg = dwqe_read(sc, GMAC_CHAN_TX_CONTROL(0)); 758305ac5f9Spatrick reg |= GMAC_CHAN_TX_CONTROL_ST; 759305ac5f9Spatrick dwqe_write(sc, GMAC_CHAN_TX_CONTROL(0), reg); 760305ac5f9Spatrick 761305ac5f9Spatrick mode = dwqe_read(sc, GMAC_MTL_CHAN_RX_OP_MODE(0)); 762305ac5f9Spatrick if (sc->sc_force_thresh_dma_mode) { 763305ac5f9Spatrick mode &= ~GMAC_MTL_CHAN_RX_OP_MODE_RSF; 764305ac5f9Spatrick mode &= ~GMAC_MTL_CHAN_RX_OP_MODE_RTC_MASK; 765305ac5f9Spatrick mode |= GMAC_MTL_CHAN_RX_OP_MODE_RTC_128; 766305ac5f9Spatrick } else { 767305ac5f9Spatrick mode |= GMAC_MTL_CHAN_RX_OP_MODE_RSF; 768305ac5f9Spatrick } 769305ac5f9Spatrick mode &= ~GMAC_MTL_CHAN_RX_OP_MODE_RQS_MASK; 770305ac5f9Spatrick rqs = (128 << GMAC_MAC_HW_FEATURE1_RXFIFOSIZE(sc->sc_hw_feature[1]) / 771305ac5f9Spatrick 256) - 1; 772305ac5f9Spatrick mode |= rqs << GMAC_MTL_CHAN_RX_OP_MODE_RQS_SHIFT; 773305ac5f9Spatrick dwqe_write(sc, GMAC_MTL_CHAN_RX_OP_MODE(0), mode); 774305ac5f9Spatrick 775305ac5f9Spatrick mode = dwqe_read(sc, GMAC_MTL_CHAN_TX_OP_MODE(0)); 776305ac5f9Spatrick if (sc->sc_force_thresh_dma_mode) { 777305ac5f9Spatrick mode &= ~GMAC_MTL_CHAN_TX_OP_MODE_TSF; 778305ac5f9Spatrick mode &= ~GMAC_MTL_CHAN_TX_OP_MODE_TTC_MASK; 779305ac5f9Spatrick mode |= GMAC_MTL_CHAN_TX_OP_MODE_TTC_128; 780305ac5f9Spatrick } else { 781305ac5f9Spatrick mode |= GMAC_MTL_CHAN_TX_OP_MODE_TSF; 782305ac5f9Spatrick } 783305ac5f9Spatrick mode &= ~GMAC_MTL_CHAN_TX_OP_MODE_TXQEN_MASK; 784305ac5f9Spatrick mode |= GMAC_MTL_CHAN_TX_OP_MODE_TXQEN; 785305ac5f9Spatrick mode &= ~GMAC_MTL_CHAN_TX_OP_MODE_TQS_MASK; 786305ac5f9Spatrick tqs = (128 << GMAC_MAC_HW_FEATURE1_TXFIFOSIZE(sc->sc_hw_feature[1]) / 787305ac5f9Spatrick 256) - 1; 788305ac5f9Spatrick mode |= tqs << GMAC_MTL_CHAN_TX_OP_MODE_TQS_SHIFT; 789305ac5f9Spatrick dwqe_write(sc, GMAC_MTL_CHAN_TX_OP_MODE(0), mode); 790305ac5f9Spatrick 791305ac5f9Spatrick reg = dwqe_read(sc, GMAC_QX_TX_FLOW_CTRL(0)); 792305ac5f9Spatrick reg |= 0xffffU << GMAC_QX_TX_FLOW_CTRL_PT_SHIFT; 793305ac5f9Spatrick reg |= GMAC_QX_TX_FLOW_CTRL_TFE; 794305ac5f9Spatrick dwqe_write(sc, GMAC_QX_TX_FLOW_CTRL(0), reg); 795305ac5f9Spatrick reg = dwqe_read(sc, GMAC_RX_FLOW_CTRL); 796305ac5f9Spatrick reg |= GMAC_RX_FLOW_CTRL_RFE; 797305ac5f9Spatrick dwqe_write(sc, GMAC_RX_FLOW_CTRL, reg); 798305ac5f9Spatrick 799305ac5f9Spatrick dwqe_write(sc, GMAC_RXQ_CTRL0, GMAC_RXQ_CTRL0_DCB_QUEUE_EN(0)); 800305ac5f9Spatrick 801305ac5f9Spatrick dwqe_write(sc, GMAC_MAC_CONF, dwqe_read(sc, GMAC_MAC_CONF) | 802305ac5f9Spatrick GMAC_MAC_CONF_BE | GMAC_MAC_CONF_JD | GMAC_MAC_CONF_JE | 803305ac5f9Spatrick GMAC_MAC_CONF_DCRS | GMAC_MAC_CONF_TE | GMAC_MAC_CONF_RE); 804305ac5f9Spatrick 805305ac5f9Spatrick dwqe_write(sc, GMAC_CHAN_INTR_ENA(0), 806305ac5f9Spatrick GMAC_CHAN_INTR_ENA_NIE | 807305ac5f9Spatrick GMAC_CHAN_INTR_ENA_AIE | 808305ac5f9Spatrick GMAC_CHAN_INTR_ENA_FBE | 809305ac5f9Spatrick GMAC_CHAN_INTR_ENA_RIE | 810305ac5f9Spatrick GMAC_CHAN_INTR_ENA_TIE); 811305ac5f9Spatrick 812305ac5f9Spatrick timeout_add_sec(&sc->sc_tick, 1); 813305ac5f9Spatrick } 814305ac5f9Spatrick 815305ac5f9Spatrick void 816305ac5f9Spatrick dwqe_down(struct dwqe_softc *sc) 817305ac5f9Spatrick { 818305ac5f9Spatrick struct ifnet *ifp = &sc->sc_ac.ac_if; 819305ac5f9Spatrick struct dwqe_buf *txb, *rxb; 820305ac5f9Spatrick uint32_t reg; 821305ac5f9Spatrick int i; 822305ac5f9Spatrick 823305ac5f9Spatrick timeout_del(&sc->sc_rxto); 824305ac5f9Spatrick timeout_del(&sc->sc_tick); 825305ac5f9Spatrick 826305ac5f9Spatrick ifp->if_flags &= ~IFF_RUNNING; 827305ac5f9Spatrick ifq_clr_oactive(&ifp->if_snd); 828305ac5f9Spatrick ifp->if_timer = 0; 829305ac5f9Spatrick 830305ac5f9Spatrick /* Disable receiver */ 831305ac5f9Spatrick reg = dwqe_read(sc, GMAC_MAC_CONF); 832305ac5f9Spatrick reg &= ~GMAC_MAC_CONF_RE; 833305ac5f9Spatrick dwqe_write(sc, GMAC_MAC_CONF, reg); 834305ac5f9Spatrick 835305ac5f9Spatrick /* Stop receive DMA */ 836305ac5f9Spatrick reg = dwqe_read(sc, GMAC_CHAN_RX_CONTROL(0)); 837305ac5f9Spatrick reg &= ~GMAC_CHAN_RX_CONTROL_SR; 838305ac5f9Spatrick dwqe_write(sc, GMAC_CHAN_RX_CONTROL(0), reg); 839305ac5f9Spatrick 840305ac5f9Spatrick /* Stop transmit DMA */ 841305ac5f9Spatrick reg = dwqe_read(sc, GMAC_CHAN_TX_CONTROL(0)); 842305ac5f9Spatrick reg &= ~GMAC_CHAN_TX_CONTROL_ST; 843305ac5f9Spatrick dwqe_write(sc, GMAC_CHAN_TX_CONTROL(0), reg); 844305ac5f9Spatrick 845305ac5f9Spatrick /* Flush data in the TX FIFO */ 846305ac5f9Spatrick reg = dwqe_read(sc, GMAC_MTL_CHAN_TX_OP_MODE(0)); 847305ac5f9Spatrick reg |= GMAC_MTL_CHAN_TX_OP_MODE_FTQ; 848305ac5f9Spatrick dwqe_write(sc, GMAC_MTL_CHAN_TX_OP_MODE(0), reg); 849305ac5f9Spatrick /* Wait for flush to complete */ 850305ac5f9Spatrick for (i = 10000; i > 0; i--) { 851305ac5f9Spatrick reg = dwqe_read(sc, GMAC_MTL_CHAN_TX_OP_MODE(0)); 852305ac5f9Spatrick if ((reg & GMAC_MTL_CHAN_TX_OP_MODE_FTQ) == 0) 853305ac5f9Spatrick break; 854305ac5f9Spatrick delay(1); 855305ac5f9Spatrick } 856305ac5f9Spatrick if (i == 0) { 857305ac5f9Spatrick printf("%s: timeout flushing TX queue\n", 858305ac5f9Spatrick sc->sc_dev.dv_xname); 859305ac5f9Spatrick } 860305ac5f9Spatrick 861305ac5f9Spatrick /* Disable transmitter */ 862305ac5f9Spatrick reg = dwqe_read(sc, GMAC_MAC_CONF); 863305ac5f9Spatrick reg &= ~GMAC_MAC_CONF_TE; 864305ac5f9Spatrick dwqe_write(sc, GMAC_MAC_CONF, reg); 865305ac5f9Spatrick 866305ac5f9Spatrick dwqe_write(sc, GMAC_CHAN_INTR_ENA(0), 0); 867305ac5f9Spatrick 868305ac5f9Spatrick intr_barrier(sc->sc_ih); 869305ac5f9Spatrick ifq_barrier(&ifp->if_snd); 870305ac5f9Spatrick 871305ac5f9Spatrick for (i = 0; i < DWQE_NTXDESC; i++) { 872305ac5f9Spatrick txb = &sc->sc_txbuf[i]; 873305ac5f9Spatrick if (txb->tb_m) { 874305ac5f9Spatrick bus_dmamap_sync(sc->sc_dmat, txb->tb_map, 0, 875305ac5f9Spatrick txb->tb_map->dm_mapsize, BUS_DMASYNC_POSTWRITE); 876305ac5f9Spatrick bus_dmamap_unload(sc->sc_dmat, txb->tb_map); 877305ac5f9Spatrick m_freem(txb->tb_m); 878305ac5f9Spatrick } 879305ac5f9Spatrick bus_dmamap_destroy(sc->sc_dmat, txb->tb_map); 880305ac5f9Spatrick } 881305ac5f9Spatrick 882305ac5f9Spatrick dwqe_dmamem_free(sc, sc->sc_txring); 883305ac5f9Spatrick free(sc->sc_txbuf, M_DEVBUF, 0); 884305ac5f9Spatrick 885305ac5f9Spatrick for (i = 0; i < DWQE_NRXDESC; i++) { 886305ac5f9Spatrick rxb = &sc->sc_rxbuf[i]; 887305ac5f9Spatrick if (rxb->tb_m) { 888305ac5f9Spatrick bus_dmamap_sync(sc->sc_dmat, rxb->tb_map, 0, 889305ac5f9Spatrick rxb->tb_map->dm_mapsize, BUS_DMASYNC_POSTREAD); 890305ac5f9Spatrick bus_dmamap_unload(sc->sc_dmat, rxb->tb_map); 891305ac5f9Spatrick m_freem(rxb->tb_m); 892305ac5f9Spatrick } 893305ac5f9Spatrick bus_dmamap_destroy(sc->sc_dmat, rxb->tb_map); 894305ac5f9Spatrick } 895305ac5f9Spatrick 896305ac5f9Spatrick dwqe_dmamem_free(sc, sc->sc_rxring); 897305ac5f9Spatrick free(sc->sc_rxbuf, M_DEVBUF, 0); 898305ac5f9Spatrick } 899305ac5f9Spatrick 900305ac5f9Spatrick /* Bit Reversal - http://aggregate.org/MAGIC/#Bit%20Reversal */ 901305ac5f9Spatrick static uint32_t 902305ac5f9Spatrick bitrev32(uint32_t x) 903305ac5f9Spatrick { 904305ac5f9Spatrick x = (((x & 0xaaaaaaaa) >> 1) | ((x & 0x55555555) << 1)); 905305ac5f9Spatrick x = (((x & 0xcccccccc) >> 2) | ((x & 0x33333333) << 2)); 906305ac5f9Spatrick x = (((x & 0xf0f0f0f0) >> 4) | ((x & 0x0f0f0f0f) << 4)); 907305ac5f9Spatrick x = (((x & 0xff00ff00) >> 8) | ((x & 0x00ff00ff) << 8)); 908305ac5f9Spatrick 909305ac5f9Spatrick return (x >> 16) | (x << 16); 910305ac5f9Spatrick } 911305ac5f9Spatrick 912305ac5f9Spatrick void 913305ac5f9Spatrick dwqe_iff(struct dwqe_softc *sc) 914305ac5f9Spatrick { 915305ac5f9Spatrick struct arpcom *ac = &sc->sc_ac; 916305ac5f9Spatrick struct ifnet *ifp = &sc->sc_ac.ac_if; 917305ac5f9Spatrick struct ether_multi *enm; 918305ac5f9Spatrick struct ether_multistep step; 919305ac5f9Spatrick uint32_t crc, hash[2], hashbit, hashreg; 920305ac5f9Spatrick uint32_t reg; 921305ac5f9Spatrick 922305ac5f9Spatrick reg = 0; 923305ac5f9Spatrick 924305ac5f9Spatrick ifp->if_flags &= ~IFF_ALLMULTI; 925305ac5f9Spatrick bzero(hash, sizeof(hash)); 926305ac5f9Spatrick if (ifp->if_flags & IFF_PROMISC || ac->ac_multirangecnt > 0) { 927305ac5f9Spatrick ifp->if_flags |= IFF_ALLMULTI; 928305ac5f9Spatrick reg |= GMAC_MAC_PACKET_FILTER_PM; 929305ac5f9Spatrick if (ifp->if_flags & IFF_PROMISC) 930305ac5f9Spatrick reg |= GMAC_MAC_PACKET_FILTER_PR | 931305ac5f9Spatrick GMAC_MAC_PACKET_FILTER_PCF_ALL; 932305ac5f9Spatrick } else { 933305ac5f9Spatrick reg |= GMAC_MAC_PACKET_FILTER_HMC; 934305ac5f9Spatrick ETHER_FIRST_MULTI(step, ac, enm); 935305ac5f9Spatrick while (enm != NULL) { 936305ac5f9Spatrick crc = ether_crc32_le(enm->enm_addrlo, 937305ac5f9Spatrick ETHER_ADDR_LEN) & 0x7f; 938305ac5f9Spatrick 939305ac5f9Spatrick crc = bitrev32(~crc) >> 26; 940305ac5f9Spatrick hashreg = (crc >> 5); 941305ac5f9Spatrick hashbit = (crc & 0x1f); 942305ac5f9Spatrick hash[hashreg] |= (1 << hashbit); 943305ac5f9Spatrick 944305ac5f9Spatrick ETHER_NEXT_MULTI(step, enm); 945305ac5f9Spatrick } 946305ac5f9Spatrick } 947305ac5f9Spatrick 948305ac5f9Spatrick dwqe_lladdr_write(sc); 949305ac5f9Spatrick 950305ac5f9Spatrick dwqe_write(sc, GMAC_MAC_HASH_TAB_REG0, hash[0]); 951305ac5f9Spatrick dwqe_write(sc, GMAC_MAC_HASH_TAB_REG1, hash[1]); 952305ac5f9Spatrick 953305ac5f9Spatrick dwqe_write(sc, GMAC_MAC_PACKET_FILTER, reg); 954305ac5f9Spatrick } 955305ac5f9Spatrick 956305ac5f9Spatrick int 957305ac5f9Spatrick dwqe_encap(struct dwqe_softc *sc, struct mbuf *m, int *idx, int *used) 958305ac5f9Spatrick { 959305ac5f9Spatrick struct dwqe_desc *txd, *txd_start; 960305ac5f9Spatrick bus_dmamap_t map; 961305ac5f9Spatrick int cur, frag, i; 962305ac5f9Spatrick 963305ac5f9Spatrick cur = frag = *idx; 964305ac5f9Spatrick map = sc->sc_txbuf[cur].tb_map; 965305ac5f9Spatrick 966305ac5f9Spatrick if (bus_dmamap_load_mbuf(sc->sc_dmat, map, m, BUS_DMA_NOWAIT)) { 967305ac5f9Spatrick if (m_defrag(m, M_DONTWAIT)) 968305ac5f9Spatrick return (EFBIG); 969305ac5f9Spatrick if (bus_dmamap_load_mbuf(sc->sc_dmat, map, m, BUS_DMA_NOWAIT)) 970305ac5f9Spatrick return (EFBIG); 971305ac5f9Spatrick } 972305ac5f9Spatrick 973305ac5f9Spatrick /* Sync the DMA map. */ 974305ac5f9Spatrick bus_dmamap_sync(sc->sc_dmat, map, 0, map->dm_mapsize, 975305ac5f9Spatrick BUS_DMASYNC_PREWRITE); 976305ac5f9Spatrick 977305ac5f9Spatrick txd = txd_start = &sc->sc_txdesc[frag]; 978305ac5f9Spatrick for (i = 0; i < map->dm_nsegs; i++) { 979305ac5f9Spatrick /* TODO: check for 32-bit vs 64-bit support */ 980305ac5f9Spatrick KASSERT((map->dm_segs[i].ds_addr >> 32) == 0); 981305ac5f9Spatrick 982305ac5f9Spatrick txd->sd_tdes0 = (uint32_t)map->dm_segs[i].ds_addr; 983305ac5f9Spatrick txd->sd_tdes1 = (uint32_t)(map->dm_segs[i].ds_addr >> 32); 984305ac5f9Spatrick txd->sd_tdes2 = map->dm_segs[i].ds_len; 985305ac5f9Spatrick txd->sd_tdes3 = m->m_pkthdr.len; 986305ac5f9Spatrick if (i == 0) 987305ac5f9Spatrick txd->sd_tdes3 |= TDES3_FS; 988305ac5f9Spatrick if (i == (map->dm_nsegs - 1)) { 989305ac5f9Spatrick txd->sd_tdes2 |= TDES2_IC; 990305ac5f9Spatrick txd->sd_tdes3 |= TDES3_LS; 991305ac5f9Spatrick } 992305ac5f9Spatrick if (i != 0) 993305ac5f9Spatrick txd->sd_tdes3 |= TDES3_OWN; 994305ac5f9Spatrick 995305ac5f9Spatrick bus_dmamap_sync(sc->sc_dmat, DWQE_DMA_MAP(sc->sc_txring), 996305ac5f9Spatrick frag * sizeof(*txd), sizeof(*txd), BUS_DMASYNC_PREWRITE); 997305ac5f9Spatrick 998305ac5f9Spatrick cur = frag; 999305ac5f9Spatrick if (frag == (DWQE_NTXDESC - 1)) { 1000305ac5f9Spatrick txd = &sc->sc_txdesc[0]; 1001305ac5f9Spatrick frag = 0; 1002305ac5f9Spatrick } else { 1003305ac5f9Spatrick txd++; 1004305ac5f9Spatrick frag++; 1005305ac5f9Spatrick } 1006305ac5f9Spatrick KASSERT(frag != sc->sc_tx_cons); 1007305ac5f9Spatrick } 1008305ac5f9Spatrick 1009305ac5f9Spatrick txd_start->sd_tdes3 |= TDES3_OWN; 1010305ac5f9Spatrick bus_dmamap_sync(sc->sc_dmat, DWQE_DMA_MAP(sc->sc_txring), 1011305ac5f9Spatrick *idx * sizeof(*txd), sizeof(*txd), BUS_DMASYNC_PREWRITE); 1012305ac5f9Spatrick 1013305ac5f9Spatrick dwqe_write(sc, GMAC_CHAN_TX_END_ADDR(0), DWQE_DMA_DVA(sc->sc_txring) + 1014*4fa84378Skettenis frag * sizeof(*txd)); 1015305ac5f9Spatrick 1016305ac5f9Spatrick KASSERT(sc->sc_txbuf[cur].tb_m == NULL); 1017305ac5f9Spatrick sc->sc_txbuf[*idx].tb_map = sc->sc_txbuf[cur].tb_map; 1018305ac5f9Spatrick sc->sc_txbuf[cur].tb_map = map; 1019305ac5f9Spatrick sc->sc_txbuf[cur].tb_m = m; 1020305ac5f9Spatrick 1021305ac5f9Spatrick *idx = frag; 1022305ac5f9Spatrick *used += map->dm_nsegs; 1023305ac5f9Spatrick 1024305ac5f9Spatrick return (0); 1025305ac5f9Spatrick } 1026305ac5f9Spatrick 1027305ac5f9Spatrick void 1028305ac5f9Spatrick dwqe_reset(struct dwqe_softc *sc) 1029305ac5f9Spatrick { 1030305ac5f9Spatrick int n; 1031305ac5f9Spatrick 1032305ac5f9Spatrick dwqe_write(sc, GMAC_BUS_MODE, dwqe_read(sc, GMAC_BUS_MODE) | 1033305ac5f9Spatrick GMAC_BUS_MODE_SWR); 1034305ac5f9Spatrick 1035305ac5f9Spatrick for (n = 0; n < 30000; n++) { 1036305ac5f9Spatrick if ((dwqe_read(sc, GMAC_BUS_MODE) & 1037305ac5f9Spatrick GMAC_BUS_MODE_SWR) == 0) 1038305ac5f9Spatrick return; 1039305ac5f9Spatrick delay(10); 1040305ac5f9Spatrick } 1041305ac5f9Spatrick 1042305ac5f9Spatrick printf("%s: reset timeout\n", sc->sc_dev.dv_xname); 1043305ac5f9Spatrick } 1044305ac5f9Spatrick 1045305ac5f9Spatrick struct dwqe_dmamem * 1046305ac5f9Spatrick dwqe_dmamem_alloc(struct dwqe_softc *sc, bus_size_t size, bus_size_t align) 1047305ac5f9Spatrick { 1048305ac5f9Spatrick struct dwqe_dmamem *tdm; 1049305ac5f9Spatrick int nsegs; 1050305ac5f9Spatrick 1051305ac5f9Spatrick tdm = malloc(sizeof(*tdm), M_DEVBUF, M_WAITOK | M_ZERO); 1052305ac5f9Spatrick tdm->tdm_size = size; 1053305ac5f9Spatrick 1054305ac5f9Spatrick if (bus_dmamap_create(sc->sc_dmat, size, 1, size, 0, 1055305ac5f9Spatrick BUS_DMA_WAITOK | BUS_DMA_ALLOCNOW, &tdm->tdm_map) != 0) 1056305ac5f9Spatrick goto tdmfree; 1057305ac5f9Spatrick 1058305ac5f9Spatrick if (bus_dmamem_alloc(sc->sc_dmat, size, align, 0, &tdm->tdm_seg, 1, 1059305ac5f9Spatrick &nsegs, BUS_DMA_WAITOK) != 0) 1060305ac5f9Spatrick goto destroy; 1061305ac5f9Spatrick 1062305ac5f9Spatrick if (bus_dmamem_map(sc->sc_dmat, &tdm->tdm_seg, nsegs, size, 1063305ac5f9Spatrick &tdm->tdm_kva, BUS_DMA_WAITOK | BUS_DMA_COHERENT) != 0) 1064305ac5f9Spatrick goto free; 1065305ac5f9Spatrick 1066305ac5f9Spatrick if (bus_dmamap_load(sc->sc_dmat, tdm->tdm_map, tdm->tdm_kva, size, 1067305ac5f9Spatrick NULL, BUS_DMA_WAITOK) != 0) 1068305ac5f9Spatrick goto unmap; 1069305ac5f9Spatrick 1070305ac5f9Spatrick bzero(tdm->tdm_kva, size); 1071305ac5f9Spatrick 1072305ac5f9Spatrick return (tdm); 1073305ac5f9Spatrick 1074305ac5f9Spatrick unmap: 1075305ac5f9Spatrick bus_dmamem_unmap(sc->sc_dmat, tdm->tdm_kva, size); 1076305ac5f9Spatrick free: 1077305ac5f9Spatrick bus_dmamem_free(sc->sc_dmat, &tdm->tdm_seg, 1); 1078305ac5f9Spatrick destroy: 1079305ac5f9Spatrick bus_dmamap_destroy(sc->sc_dmat, tdm->tdm_map); 1080305ac5f9Spatrick tdmfree: 1081305ac5f9Spatrick free(tdm, M_DEVBUF, 0); 1082305ac5f9Spatrick 1083305ac5f9Spatrick return (NULL); 1084305ac5f9Spatrick } 1085305ac5f9Spatrick 1086305ac5f9Spatrick void 1087305ac5f9Spatrick dwqe_dmamem_free(struct dwqe_softc *sc, struct dwqe_dmamem *tdm) 1088305ac5f9Spatrick { 1089305ac5f9Spatrick bus_dmamem_unmap(sc->sc_dmat, tdm->tdm_kva, tdm->tdm_size); 1090305ac5f9Spatrick bus_dmamem_free(sc->sc_dmat, &tdm->tdm_seg, 1); 1091305ac5f9Spatrick bus_dmamap_destroy(sc->sc_dmat, tdm->tdm_map); 1092305ac5f9Spatrick free(tdm, M_DEVBUF, 0); 1093305ac5f9Spatrick } 1094305ac5f9Spatrick 1095305ac5f9Spatrick struct mbuf * 1096305ac5f9Spatrick dwqe_alloc_mbuf(struct dwqe_softc *sc, bus_dmamap_t map) 1097305ac5f9Spatrick { 1098305ac5f9Spatrick struct mbuf *m = NULL; 1099305ac5f9Spatrick 1100305ac5f9Spatrick m = MCLGETL(NULL, M_DONTWAIT, MCLBYTES); 1101305ac5f9Spatrick if (!m) 1102305ac5f9Spatrick return (NULL); 1103305ac5f9Spatrick m->m_len = m->m_pkthdr.len = MCLBYTES; 1104305ac5f9Spatrick m_adj(m, ETHER_ALIGN); 1105305ac5f9Spatrick 1106305ac5f9Spatrick if (bus_dmamap_load_mbuf(sc->sc_dmat, map, m, BUS_DMA_NOWAIT) != 0) { 1107305ac5f9Spatrick printf("%s: could not load mbuf DMA map", DEVNAME(sc)); 1108305ac5f9Spatrick m_freem(m); 1109305ac5f9Spatrick return (NULL); 1110305ac5f9Spatrick } 1111305ac5f9Spatrick 1112305ac5f9Spatrick bus_dmamap_sync(sc->sc_dmat, map, 0, 1113305ac5f9Spatrick m->m_pkthdr.len, BUS_DMASYNC_PREREAD); 1114305ac5f9Spatrick 1115305ac5f9Spatrick return (m); 1116305ac5f9Spatrick } 1117305ac5f9Spatrick 1118305ac5f9Spatrick void 1119305ac5f9Spatrick dwqe_fill_rx_ring(struct dwqe_softc *sc) 1120305ac5f9Spatrick { 1121305ac5f9Spatrick struct dwqe_desc *rxd; 1122305ac5f9Spatrick struct dwqe_buf *rxb; 1123305ac5f9Spatrick u_int slots; 1124305ac5f9Spatrick 1125305ac5f9Spatrick for (slots = if_rxr_get(&sc->sc_rx_ring, DWQE_NRXDESC); 1126305ac5f9Spatrick slots > 0; slots--) { 1127305ac5f9Spatrick rxb = &sc->sc_rxbuf[sc->sc_rx_prod]; 1128305ac5f9Spatrick rxb->tb_m = dwqe_alloc_mbuf(sc, rxb->tb_map); 1129305ac5f9Spatrick if (rxb->tb_m == NULL) 1130305ac5f9Spatrick break; 1131305ac5f9Spatrick 1132305ac5f9Spatrick /* TODO: check for 32-bit vs 64-bit support */ 1133*4fa84378Skettenis KASSERT((rxb->tb_map->dm_segs[0].ds_addr >> 32) == 0); 1134305ac5f9Spatrick 1135305ac5f9Spatrick rxd = &sc->sc_rxdesc[sc->sc_rx_prod]; 1136*4fa84378Skettenis rxd->sd_tdes0 = (uint32_t)rxb->tb_map->dm_segs[0].ds_addr; 1137*4fa84378Skettenis rxd->sd_tdes1 = (uint32_t)(rxb->tb_map->dm_segs[0].ds_addr >> 32); 1138305ac5f9Spatrick rxd->sd_tdes2 = 0; 1139305ac5f9Spatrick rxd->sd_tdes3 = RDES3_OWN | RDES3_IC | RDES3_BUF1V; 1140305ac5f9Spatrick 1141305ac5f9Spatrick if (sc->sc_rx_prod == (DWQE_NRXDESC - 1)) 1142305ac5f9Spatrick sc->sc_rx_prod = 0; 1143305ac5f9Spatrick else 1144305ac5f9Spatrick sc->sc_rx_prod++; 1145305ac5f9Spatrick } 1146305ac5f9Spatrick if_rxr_put(&sc->sc_rx_ring, slots); 1147305ac5f9Spatrick 1148305ac5f9Spatrick dwqe_write(sc, GMAC_CHAN_RX_END_ADDR(0), DWQE_DMA_DVA(sc->sc_rxring) + 1149305ac5f9Spatrick sc->sc_rx_prod * sizeof(*rxd)); 1150305ac5f9Spatrick 1151305ac5f9Spatrick if (if_rxr_inuse(&sc->sc_rx_ring) == 0) 1152305ac5f9Spatrick timeout_add(&sc->sc_rxto, 1); 1153305ac5f9Spatrick } 1154