1702b53ddSSøren Schmidt /*- 24d846d26SWarner Losh * SPDX-License-Identifier: BSD-2-Clause 3702b53ddSSøren Schmidt * 4702b53ddSSøren Schmidt * Copyright (c) 2022 Soren Schmidt <sos@deepcore.dk> 5702b53ddSSøren Schmidt * Copyright (c) 2022 Jared McNeill <jmcneill@invisible.ca> 6702b53ddSSøren Schmidt * All rights reserved. 7702b53ddSSøren Schmidt * 8702b53ddSSøren Schmidt * Redistribution and use in source and binary forms, with or without 9702b53ddSSøren Schmidt * modification, are permitted provided that the following conditions 10702b53ddSSøren Schmidt * are met: 11702b53ddSSøren Schmidt * 1. Redistributions of source code must retain the above copyright 12702b53ddSSøren Schmidt * notice, this list of conditions and the following disclaimer. 13702b53ddSSøren Schmidt * 2. Redistributions in binary form must reproduce the above copyright 14702b53ddSSøren Schmidt * notice, this list of conditions and the following disclaimer in the 15702b53ddSSøren Schmidt * documentation and/or other materials provided with the distribution. 16702b53ddSSøren Schmidt * 17702b53ddSSøren Schmidt * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR 18702b53ddSSøren Schmidt * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES 19702b53ddSSøren Schmidt * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. 20702b53ddSSøren Schmidt * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, 21702b53ddSSøren Schmidt * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, 22702b53ddSSøren Schmidt * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; 23702b53ddSSøren Schmidt * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED 24702b53ddSSøren Schmidt * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, 25702b53ddSSøren Schmidt * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 26702b53ddSSøren Schmidt * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 27702b53ddSSøren Schmidt * SUCH DAMAGE. 28702b53ddSSøren Schmidt * 29702b53ddSSøren Schmidt * $Id: eqos.c 1059 2022-12-08 19:32:32Z sos $ 30702b53ddSSøren Schmidt */ 31702b53ddSSøren Schmidt 32702b53ddSSøren Schmidt /* 33702b53ddSSøren Schmidt * DesignWare Ethernet Quality-of-Service controller 34702b53ddSSøren Schmidt */ 35702b53ddSSøren Schmidt 36702b53ddSSøren Schmidt #include "opt_platform.h" 37fdafd315SWarner Losh 38702b53ddSSøren Schmidt #include <sys/param.h> 39702b53ddSSøren Schmidt #include <sys/systm.h> 40702b53ddSSøren Schmidt #include <sys/kernel.h> 41702b53ddSSøren Schmidt #include <sys/mutex.h> 42702b53ddSSøren Schmidt #include <sys/rman.h> 43702b53ddSSøren Schmidt #include <sys/endian.h> 44702b53ddSSøren Schmidt #include <sys/module.h> 45702b53ddSSøren Schmidt #include <sys/bus.h> 46702b53ddSSøren Schmidt #include <sys/callout.h> 47702b53ddSSøren Schmidt #include <sys/socket.h> 48702b53ddSSøren Schmidt #include <sys/sockio.h> 49702b53ddSSøren Schmidt #include <sys/mbuf.h> 50702b53ddSSøren Schmidt #include <sys/systm.h> 51702b53ddSSøren Schmidt #include <machine/bus.h> 52702b53ddSSøren Schmidt 53702b53ddSSøren Schmidt #include <net/ethernet.h> 54702b53ddSSøren Schmidt #include <net/if.h> 55702b53ddSSøren Schmidt #include <net/if_dl.h> 56702b53ddSSøren Schmidt #include <net/if_media.h> 57702b53ddSSøren Schmidt #include <net/if_types.h> 58702b53ddSSøren Schmidt #include <net/bpf.h> 59702b53ddSSøren Schmidt 60702b53ddSSøren Schmidt #include <dev/mii/mii.h> 61702b53ddSSøren Schmidt #include <dev/mii/miivar.h> 62702b53ddSSøren Schmidt 63702b53ddSSøren Schmidt #include "miibus_if.h" 64702b53ddSSøren Schmidt #include "if_eqos_if.h" 65702b53ddSSøren Schmidt 66702b53ddSSøren Schmidt #ifdef FDT 67702b53ddSSøren Schmidt #include <dev/ofw/openfirm.h> 68702b53ddSSøren Schmidt #include <dev/ofw/ofw_bus.h> 69702b53ddSSøren Schmidt #include <dev/ofw/ofw_bus_subr.h> 70be82b3a0SEmmanuel Vadot #include <dev/clk/clk.h> 71702b53ddSSøren Schmidt #endif 72702b53ddSSøren Schmidt 73702b53ddSSøren Schmidt #include <dev/eqos/if_eqos_reg.h> 74702b53ddSSøren Schmidt #include <dev/eqos/if_eqos_var.h> 75702b53ddSSøren Schmidt 76702b53ddSSøren Schmidt #define DESC_BOUNDARY (1ULL << 32) 77702b53ddSSøren Schmidt #define DESC_ALIGN sizeof(struct eqos_dma_desc) 78702b53ddSSøren Schmidt #define DESC_OFFSET(n) ((n) * sizeof(struct eqos_dma_desc)) 79702b53ddSSøren Schmidt 80702b53ddSSøren Schmidt #define TX_DESC_COUNT EQOS_DMA_DESC_COUNT 81702b53ddSSøren Schmidt #define TX_DESC_SIZE (TX_DESC_COUNT * DESC_ALIGN) 82702b53ddSSøren Schmidt #define TX_MAX_SEGS (TX_DESC_COUNT / 2) 83702b53ddSSøren Schmidt #define TX_NEXT(n) (((n) + 1 ) % TX_DESC_COUNT) 84702b53ddSSøren Schmidt #define TX_QUEUED(h, t) ((((h) - (t)) + TX_DESC_COUNT) % TX_DESC_COUNT) 85702b53ddSSøren Schmidt 86702b53ddSSøren Schmidt #define RX_DESC_COUNT EQOS_DMA_DESC_COUNT 87702b53ddSSøren Schmidt #define RX_DESC_SIZE (RX_DESC_COUNT * DESC_ALIGN) 88702b53ddSSøren Schmidt #define RX_NEXT(n) (((n) + 1) % RX_DESC_COUNT) 89702b53ddSSøren Schmidt 90702b53ddSSøren Schmidt #define MII_BUSY_RETRY 1000 91702b53ddSSøren Schmidt #define WATCHDOG_TIMEOUT_SECS 3 92702b53ddSSøren Schmidt 93702b53ddSSøren Schmidt #define EQOS_LOCK(sc) mtx_lock(&(sc)->lock) 94702b53ddSSøren Schmidt #define EQOS_UNLOCK(sc) mtx_unlock(&(sc)->lock) 95702b53ddSSøren Schmidt #define EQOS_ASSERT_LOCKED(sc) mtx_assert(&(sc)->lock, MA_OWNED) 96702b53ddSSøren Schmidt 97702b53ddSSøren Schmidt #define RD4(sc, o) bus_read_4(sc->res[EQOS_RES_MEM], (o)) 98702b53ddSSøren Schmidt #define WR4(sc, o, v) bus_write_4(sc->res[EQOS_RES_MEM], (o), (v)) 99702b53ddSSøren Schmidt 100702b53ddSSøren Schmidt 101702b53ddSSøren Schmidt static struct resource_spec eqos_spec[] = { 102702b53ddSSøren Schmidt { SYS_RES_MEMORY, 0, RF_ACTIVE }, 103702b53ddSSøren Schmidt { SYS_RES_IRQ, 0, RF_ACTIVE }, 104702b53ddSSøren Schmidt { -1, 0 } 105702b53ddSSøren Schmidt }; 106702b53ddSSøren Schmidt 107702b53ddSSøren Schmidt static void eqos_tick(void *softc); 108702b53ddSSøren Schmidt 109702b53ddSSøren Schmidt 110702b53ddSSøren Schmidt static int 111702b53ddSSøren Schmidt eqos_miibus_readreg(device_t dev, int phy, int reg) 112702b53ddSSøren Schmidt { 113702b53ddSSøren Schmidt struct eqos_softc *sc = device_get_softc(dev); 114702b53ddSSøren Schmidt uint32_t addr; 115702b53ddSSøren Schmidt int retry, val; 116702b53ddSSøren Schmidt 117702b53ddSSøren Schmidt addr = sc->csr_clock_range | 118702b53ddSSøren Schmidt (phy << GMAC_MAC_MDIO_ADDRESS_PA_SHIFT) | 119702b53ddSSøren Schmidt (reg << GMAC_MAC_MDIO_ADDRESS_RDA_SHIFT) | 120702b53ddSSøren Schmidt GMAC_MAC_MDIO_ADDRESS_GOC_READ | GMAC_MAC_MDIO_ADDRESS_GB; 121702b53ddSSøren Schmidt WR4(sc, GMAC_MAC_MDIO_ADDRESS, addr); 122702b53ddSSøren Schmidt 123702b53ddSSøren Schmidt DELAY(100); 124702b53ddSSøren Schmidt 125702b53ddSSøren Schmidt for (retry = MII_BUSY_RETRY; retry > 0; retry--) { 126702b53ddSSøren Schmidt addr = RD4(sc, GMAC_MAC_MDIO_ADDRESS); 127702b53ddSSøren Schmidt if (!(addr & GMAC_MAC_MDIO_ADDRESS_GB)) { 128702b53ddSSøren Schmidt val = RD4(sc, GMAC_MAC_MDIO_DATA) & 0xFFFF; 129702b53ddSSøren Schmidt break; 130702b53ddSSøren Schmidt } 131702b53ddSSøren Schmidt DELAY(10); 132702b53ddSSøren Schmidt } 133702b53ddSSøren Schmidt if (!retry) { 134702b53ddSSøren Schmidt device_printf(dev, "phy read timeout, phy=%d reg=%d\n", 135702b53ddSSøren Schmidt phy, reg); 136702b53ddSSøren Schmidt return (ETIMEDOUT); 137702b53ddSSøren Schmidt } 138702b53ddSSøren Schmidt return (val); 139702b53ddSSøren Schmidt } 140702b53ddSSøren Schmidt 141702b53ddSSøren Schmidt static int 142702b53ddSSøren Schmidt eqos_miibus_writereg(device_t dev, int phy, int reg, int val) 143702b53ddSSøren Schmidt { 144702b53ddSSøren Schmidt struct eqos_softc *sc = device_get_softc(dev); 145702b53ddSSøren Schmidt uint32_t addr; 146702b53ddSSøren Schmidt int retry; 147702b53ddSSøren Schmidt 148702b53ddSSøren Schmidt WR4(sc, GMAC_MAC_MDIO_DATA, val); 149702b53ddSSøren Schmidt 150702b53ddSSøren Schmidt addr = sc->csr_clock_range | 151702b53ddSSøren Schmidt (phy << GMAC_MAC_MDIO_ADDRESS_PA_SHIFT) | 152702b53ddSSøren Schmidt (reg << GMAC_MAC_MDIO_ADDRESS_RDA_SHIFT) | 153702b53ddSSøren Schmidt GMAC_MAC_MDIO_ADDRESS_GOC_WRITE | GMAC_MAC_MDIO_ADDRESS_GB; 154702b53ddSSøren Schmidt WR4(sc, GMAC_MAC_MDIO_ADDRESS, addr); 155702b53ddSSøren Schmidt 156702b53ddSSøren Schmidt DELAY(100); 157702b53ddSSøren Schmidt 158702b53ddSSøren Schmidt for (retry = MII_BUSY_RETRY; retry > 0; retry--) { 159702b53ddSSøren Schmidt addr = RD4(sc, GMAC_MAC_MDIO_ADDRESS); 160702b53ddSSøren Schmidt if (!(addr & GMAC_MAC_MDIO_ADDRESS_GB)) 161702b53ddSSøren Schmidt break; 162702b53ddSSøren Schmidt DELAY(10); 163702b53ddSSøren Schmidt } 164702b53ddSSøren Schmidt if (!retry) { 165702b53ddSSøren Schmidt device_printf(dev, "phy write timeout, phy=%d reg=%d\n", 166702b53ddSSøren Schmidt phy, reg); 167702b53ddSSøren Schmidt return (ETIMEDOUT); 168702b53ddSSøren Schmidt } 169702b53ddSSøren Schmidt return (0); 170702b53ddSSøren Schmidt } 171702b53ddSSøren Schmidt 172702b53ddSSøren Schmidt static void 173702b53ddSSøren Schmidt eqos_miibus_statchg(device_t dev) 174702b53ddSSøren Schmidt { 175702b53ddSSøren Schmidt struct eqos_softc *sc = device_get_softc(dev); 176702b53ddSSøren Schmidt struct mii_data *mii = device_get_softc(sc->miibus); 177702b53ddSSøren Schmidt uint32_t reg; 178702b53ddSSøren Schmidt 179702b53ddSSøren Schmidt EQOS_ASSERT_LOCKED(sc); 180702b53ddSSøren Schmidt 181702b53ddSSøren Schmidt if (mii->mii_media_status & IFM_ACTIVE) 182702b53ddSSøren Schmidt sc->link_up = true; 183702b53ddSSøren Schmidt else 184702b53ddSSøren Schmidt sc->link_up = false; 185702b53ddSSøren Schmidt 186702b53ddSSøren Schmidt reg = RD4(sc, GMAC_MAC_CONFIGURATION); 187702b53ddSSøren Schmidt 188702b53ddSSøren Schmidt switch (IFM_SUBTYPE(mii->mii_media_active)) { 189702b53ddSSøren Schmidt case IFM_10_T: 190702b53ddSSøren Schmidt reg |= GMAC_MAC_CONFIGURATION_PS; 191702b53ddSSøren Schmidt reg &= ~GMAC_MAC_CONFIGURATION_FES; 192702b53ddSSøren Schmidt break; 193702b53ddSSøren Schmidt case IFM_100_TX: 194702b53ddSSøren Schmidt reg |= GMAC_MAC_CONFIGURATION_PS; 195702b53ddSSøren Schmidt reg |= GMAC_MAC_CONFIGURATION_FES; 196702b53ddSSøren Schmidt break; 197702b53ddSSøren Schmidt case IFM_1000_T: 198702b53ddSSøren Schmidt case IFM_1000_SX: 199702b53ddSSøren Schmidt reg &= ~GMAC_MAC_CONFIGURATION_PS; 200702b53ddSSøren Schmidt reg &= ~GMAC_MAC_CONFIGURATION_FES; 201702b53ddSSøren Schmidt break; 202702b53ddSSøren Schmidt case IFM_2500_T: 203702b53ddSSøren Schmidt case IFM_2500_SX: 204702b53ddSSøren Schmidt reg &= ~GMAC_MAC_CONFIGURATION_PS; 205702b53ddSSøren Schmidt reg |= GMAC_MAC_CONFIGURATION_FES; 206702b53ddSSøren Schmidt break; 207702b53ddSSøren Schmidt default: 208702b53ddSSøren Schmidt sc->link_up = false; 209702b53ddSSøren Schmidt return; 210702b53ddSSøren Schmidt } 211702b53ddSSøren Schmidt 212702b53ddSSøren Schmidt if ((IFM_OPTIONS(mii->mii_media_active) & IFM_FDX)) 213702b53ddSSøren Schmidt reg |= GMAC_MAC_CONFIGURATION_DM; 214702b53ddSSøren Schmidt else 215702b53ddSSøren Schmidt reg &= ~GMAC_MAC_CONFIGURATION_DM; 216702b53ddSSøren Schmidt 217702b53ddSSøren Schmidt WR4(sc, GMAC_MAC_CONFIGURATION, reg); 218702b53ddSSøren Schmidt 2195ba0691dSSøren Schmidt IF_EQOS_SET_SPEED(dev, IFM_SUBTYPE(mii->mii_media_active)); 220702b53ddSSøren Schmidt 221702b53ddSSøren Schmidt WR4(sc, GMAC_MAC_1US_TIC_COUNTER, (sc->csr_clock / 1000000) - 1); 222702b53ddSSøren Schmidt } 223702b53ddSSøren Schmidt 224702b53ddSSøren Schmidt static void 225a472fd7aSJustin Hibbits eqos_media_status(if_t ifp, struct ifmediareq *ifmr) 226702b53ddSSøren Schmidt { 227a472fd7aSJustin Hibbits struct eqos_softc *sc = if_getsoftc(ifp); 228702b53ddSSøren Schmidt struct mii_data *mii = device_get_softc(sc->miibus); 229702b53ddSSøren Schmidt 230702b53ddSSøren Schmidt EQOS_LOCK(sc); 231702b53ddSSøren Schmidt mii_pollstat(mii); 232702b53ddSSøren Schmidt ifmr->ifm_active = mii->mii_media_active; 233702b53ddSSøren Schmidt ifmr->ifm_status = mii->mii_media_status; 234702b53ddSSøren Schmidt EQOS_UNLOCK(sc); 235702b53ddSSøren Schmidt } 236702b53ddSSøren Schmidt 237702b53ddSSøren Schmidt static int 238a472fd7aSJustin Hibbits eqos_media_change(if_t ifp) 239702b53ddSSøren Schmidt { 240a472fd7aSJustin Hibbits struct eqos_softc *sc = if_getsoftc(ifp); 241702b53ddSSøren Schmidt int error; 242702b53ddSSøren Schmidt 243702b53ddSSøren Schmidt EQOS_LOCK(sc); 244702b53ddSSøren Schmidt error = mii_mediachg(device_get_softc(sc->miibus)); 245702b53ddSSøren Schmidt EQOS_UNLOCK(sc); 246702b53ddSSøren Schmidt return (error); 247702b53ddSSøren Schmidt } 248702b53ddSSøren Schmidt 249702b53ddSSøren Schmidt static void 250702b53ddSSøren Schmidt eqos_setup_txdesc(struct eqos_softc *sc, int index, int flags, 251702b53ddSSøren Schmidt bus_addr_t paddr, u_int len, u_int total_len) 252702b53ddSSøren Schmidt { 253702b53ddSSøren Schmidt uint32_t tdes2, tdes3; 254702b53ddSSøren Schmidt 255702b53ddSSøren Schmidt if (!paddr || !len) { 256702b53ddSSøren Schmidt tdes2 = 0; 257702b53ddSSøren Schmidt tdes3 = flags; 258702b53ddSSøren Schmidt } else { 259702b53ddSSøren Schmidt tdes2 = (flags & EQOS_TDES3_LD) ? EQOS_TDES2_IOC : 0; 260702b53ddSSøren Schmidt tdes3 = flags; 261702b53ddSSøren Schmidt } 262702b53ddSSøren Schmidt bus_dmamap_sync(sc->tx.desc_tag, sc->tx.desc_map, BUS_DMASYNC_PREWRITE); 263702b53ddSSøren Schmidt sc->tx.desc_ring[index].des0 = htole32((uint32_t)paddr); 264702b53ddSSøren Schmidt sc->tx.desc_ring[index].des1 = htole32((uint32_t)(paddr >> 32)); 265702b53ddSSøren Schmidt sc->tx.desc_ring[index].des2 = htole32(tdes2 | len); 266702b53ddSSøren Schmidt sc->tx.desc_ring[index].des3 = htole32(tdes3 | total_len); 267702b53ddSSøren Schmidt } 268702b53ddSSøren Schmidt 269702b53ddSSøren Schmidt static int 270702b53ddSSøren Schmidt eqos_setup_txbuf(struct eqos_softc *sc, struct mbuf *m) 271702b53ddSSøren Schmidt { 272702b53ddSSøren Schmidt bus_dma_segment_t segs[TX_MAX_SEGS]; 273702b53ddSSøren Schmidt int first = sc->tx.head; 274702b53ddSSøren Schmidt int error, nsegs, idx; 275702b53ddSSøren Schmidt uint32_t flags; 276702b53ddSSøren Schmidt 277702b53ddSSøren Schmidt error = bus_dmamap_load_mbuf_sg(sc->tx.buf_tag, 278702b53ddSSøren Schmidt sc->tx.buf_map[first].map, m, segs, &nsegs, 0); 279702b53ddSSøren Schmidt if (error == EFBIG) { 280702b53ddSSøren Schmidt struct mbuf *mb; 281702b53ddSSøren Schmidt 282702b53ddSSøren Schmidt device_printf(sc->dev, "TX packet too big trying defrag\n"); 283702b53ddSSøren Schmidt bus_dmamap_unload(sc->tx.buf_tag, sc->tx.buf_map[first].map); 284702b53ddSSøren Schmidt if (!(mb = m_defrag(m, M_NOWAIT))) 285702b53ddSSøren Schmidt return (ENOMEM); 286702b53ddSSøren Schmidt m = mb; 287702b53ddSSøren Schmidt error = bus_dmamap_load_mbuf_sg(sc->tx.buf_tag, 288702b53ddSSøren Schmidt sc->tx.buf_map[first].map, m, segs, &nsegs, 0); 289702b53ddSSøren Schmidt } 290702b53ddSSøren Schmidt if (error) 291702b53ddSSøren Schmidt return (ENOMEM); 292702b53ddSSøren Schmidt 293702b53ddSSøren Schmidt if (TX_QUEUED(sc->tx.head, sc->tx.tail) + nsegs > TX_DESC_COUNT) { 294702b53ddSSøren Schmidt bus_dmamap_unload(sc->tx.buf_tag, sc->tx.buf_map[first].map); 295702b53ddSSøren Schmidt device_printf(sc->dev, "TX packet no more queue space\n"); 296702b53ddSSøren Schmidt return (ENOMEM); 297702b53ddSSøren Schmidt } 298702b53ddSSøren Schmidt 299702b53ddSSøren Schmidt bus_dmamap_sync(sc->tx.buf_tag, sc->tx.buf_map[first].map, 300702b53ddSSøren Schmidt BUS_DMASYNC_PREWRITE); 301702b53ddSSøren Schmidt 302702b53ddSSøren Schmidt sc->tx.buf_map[first].mbuf = m; 303702b53ddSSøren Schmidt 304702b53ddSSøren Schmidt for (flags = EQOS_TDES3_FD, idx = 0; idx < nsegs; idx++) { 305702b53ddSSøren Schmidt if (idx == (nsegs - 1)) 306702b53ddSSøren Schmidt flags |= EQOS_TDES3_LD; 307702b53ddSSøren Schmidt eqos_setup_txdesc(sc, sc->tx.head, flags, segs[idx].ds_addr, 308702b53ddSSøren Schmidt segs[idx].ds_len, m->m_pkthdr.len); 309702b53ddSSøren Schmidt flags &= ~EQOS_TDES3_FD; 310702b53ddSSøren Schmidt flags |= EQOS_TDES3_OWN; 311702b53ddSSøren Schmidt sc->tx.head = TX_NEXT(sc->tx.head); 312702b53ddSSøren Schmidt } 313702b53ddSSøren Schmidt 314702b53ddSSøren Schmidt /* 315702b53ddSSøren Schmidt * Defer setting OWN bit on the first descriptor 316702b53ddSSøren Schmidt * until all descriptors have been updated 317702b53ddSSøren Schmidt */ 318702b53ddSSøren Schmidt bus_dmamap_sync(sc->tx.desc_tag, sc->tx.desc_map, BUS_DMASYNC_PREWRITE); 319702b53ddSSøren Schmidt sc->tx.desc_ring[first].des3 |= htole32(EQOS_TDES3_OWN); 320702b53ddSSøren Schmidt 321702b53ddSSøren Schmidt return (0); 322702b53ddSSøren Schmidt } 323702b53ddSSøren Schmidt 324702b53ddSSøren Schmidt static void 325702b53ddSSøren Schmidt eqos_setup_rxdesc(struct eqos_softc *sc, int index, bus_addr_t paddr) 326702b53ddSSøren Schmidt { 327702b53ddSSøren Schmidt 328702b53ddSSøren Schmidt sc->rx.desc_ring[index].des0 = htole32((uint32_t)paddr); 329702b53ddSSøren Schmidt sc->rx.desc_ring[index].des1 = htole32((uint32_t)(paddr >> 32)); 330702b53ddSSøren Schmidt sc->rx.desc_ring[index].des2 = htole32(0); 331702b53ddSSøren Schmidt bus_dmamap_sync(sc->rx.desc_tag, sc->rx.desc_map, BUS_DMASYNC_PREWRITE); 332702b53ddSSøren Schmidt sc->rx.desc_ring[index].des3 = htole32(EQOS_RDES3_OWN | EQOS_RDES3_IOC | 333702b53ddSSøren Schmidt EQOS_RDES3_BUF1V); 334702b53ddSSøren Schmidt } 335702b53ddSSøren Schmidt 336702b53ddSSøren Schmidt static int 337702b53ddSSøren Schmidt eqos_setup_rxbuf(struct eqos_softc *sc, int index, struct mbuf *m) 338702b53ddSSøren Schmidt { 339702b53ddSSøren Schmidt struct bus_dma_segment seg; 340702b53ddSSøren Schmidt int error, nsegs; 341702b53ddSSøren Schmidt 342702b53ddSSøren Schmidt m_adj(m, ETHER_ALIGN); 343702b53ddSSøren Schmidt 344702b53ddSSøren Schmidt error = bus_dmamap_load_mbuf_sg(sc->rx.buf_tag, 345702b53ddSSøren Schmidt sc->rx.buf_map[index].map, m, &seg, &nsegs, 0); 346702b53ddSSøren Schmidt if (error) 347702b53ddSSøren Schmidt return (error); 348702b53ddSSøren Schmidt 349702b53ddSSøren Schmidt bus_dmamap_sync(sc->rx.buf_tag, sc->rx.buf_map[index].map, 350702b53ddSSøren Schmidt BUS_DMASYNC_PREREAD); 351702b53ddSSøren Schmidt 352702b53ddSSøren Schmidt sc->rx.buf_map[index].mbuf = m; 353702b53ddSSøren Schmidt eqos_setup_rxdesc(sc, index, seg.ds_addr); 354702b53ddSSøren Schmidt 355702b53ddSSøren Schmidt return (0); 356702b53ddSSøren Schmidt } 357702b53ddSSøren Schmidt 358702b53ddSSøren Schmidt static struct mbuf * 359702b53ddSSøren Schmidt eqos_alloc_mbufcl(struct eqos_softc *sc) 360702b53ddSSøren Schmidt { 361702b53ddSSøren Schmidt struct mbuf *m; 362702b53ddSSøren Schmidt 363702b53ddSSøren Schmidt if ((m = m_getcl(M_NOWAIT, MT_DATA, M_PKTHDR))) 364702b53ddSSøren Schmidt m->m_pkthdr.len = m->m_len = m->m_ext.ext_size; 365702b53ddSSøren Schmidt return (m); 366702b53ddSSøren Schmidt } 367702b53ddSSøren Schmidt 368702b53ddSSøren Schmidt static void 369702b53ddSSøren Schmidt eqos_enable_intr(struct eqos_softc *sc) 370702b53ddSSøren Schmidt { 371702b53ddSSøren Schmidt 372702b53ddSSøren Schmidt WR4(sc, GMAC_DMA_CHAN0_INTR_ENABLE, 373702b53ddSSøren Schmidt GMAC_DMA_CHAN0_INTR_ENABLE_NIE | GMAC_DMA_CHAN0_INTR_ENABLE_AIE | 374702b53ddSSøren Schmidt GMAC_DMA_CHAN0_INTR_ENABLE_FBE | GMAC_DMA_CHAN0_INTR_ENABLE_RIE | 375702b53ddSSøren Schmidt GMAC_DMA_CHAN0_INTR_ENABLE_TIE); 376702b53ddSSøren Schmidt } 377702b53ddSSøren Schmidt 378702b53ddSSøren Schmidt static void 379702b53ddSSøren Schmidt eqos_disable_intr(struct eqos_softc *sc) 380702b53ddSSøren Schmidt { 381702b53ddSSøren Schmidt 382702b53ddSSøren Schmidt WR4(sc, GMAC_DMA_CHAN0_INTR_ENABLE, 0); 383702b53ddSSøren Schmidt } 384702b53ddSSøren Schmidt 385702b53ddSSøren Schmidt static uint32_t 386702b53ddSSøren Schmidt eqos_bitrev32(uint32_t x) 387702b53ddSSøren Schmidt { 388702b53ddSSøren Schmidt 389702b53ddSSøren Schmidt x = (((x & 0xaaaaaaaa) >> 1) | ((x & 0x55555555) << 1)); 390702b53ddSSøren Schmidt x = (((x & 0xcccccccc) >> 2) | ((x & 0x33333333) << 2)); 391702b53ddSSøren Schmidt x = (((x & 0xf0f0f0f0) >> 4) | ((x & 0x0f0f0f0f) << 4)); 392702b53ddSSøren Schmidt x = (((x & 0xff00ff00) >> 8) | ((x & 0x00ff00ff) << 8)); 393702b53ddSSøren Schmidt return ((x >> 16) | (x << 16)); 394702b53ddSSøren Schmidt } 395702b53ddSSøren Schmidt 396702b53ddSSøren Schmidt static u_int 397702b53ddSSøren Schmidt eqos_hash_maddr(void *arg, struct sockaddr_dl *sdl, u_int cnt) 398702b53ddSSøren Schmidt { 399702b53ddSSøren Schmidt uint32_t crc, *hash = arg; 400702b53ddSSøren Schmidt 401702b53ddSSøren Schmidt crc = ether_crc32_le(LLADDR(sdl), ETHER_ADDR_LEN); 402702b53ddSSøren Schmidt crc &= 0x7f; 403702b53ddSSøren Schmidt crc = eqos_bitrev32(~crc) >> 26; 404702b53ddSSøren Schmidt hash[crc >> 5] |= 1 << (crc & 0x1f); 405702b53ddSSøren Schmidt return (1); 406702b53ddSSøren Schmidt } 407702b53ddSSøren Schmidt 408702b53ddSSøren Schmidt static void 409702b53ddSSøren Schmidt eqos_setup_rxfilter(struct eqos_softc *sc) 410702b53ddSSøren Schmidt { 411a472fd7aSJustin Hibbits if_t ifp = sc->ifp; 412702b53ddSSøren Schmidt uint32_t pfil, hash[2]; 413702b53ddSSøren Schmidt const uint8_t *eaddr; 414702b53ddSSøren Schmidt uint32_t val; 415702b53ddSSøren Schmidt 416702b53ddSSøren Schmidt EQOS_ASSERT_LOCKED(sc); 417702b53ddSSøren Schmidt 418702b53ddSSøren Schmidt pfil = RD4(sc, GMAC_MAC_PACKET_FILTER); 419702b53ddSSøren Schmidt pfil &= ~(GMAC_MAC_PACKET_FILTER_PR | 420702b53ddSSøren Schmidt GMAC_MAC_PACKET_FILTER_PM | 421702b53ddSSøren Schmidt GMAC_MAC_PACKET_FILTER_HMC | 422702b53ddSSøren Schmidt GMAC_MAC_PACKET_FILTER_PCF_MASK); 423702b53ddSSøren Schmidt hash[0] = hash[1] = 0xffffffff; 424702b53ddSSøren Schmidt 425a472fd7aSJustin Hibbits if ((if_getflags(ifp) & IFF_PROMISC)) { 426702b53ddSSøren Schmidt pfil |= GMAC_MAC_PACKET_FILTER_PR | 427702b53ddSSøren Schmidt GMAC_MAC_PACKET_FILTER_PCF_ALL; 428a472fd7aSJustin Hibbits } else if ((if_getflags(ifp) & IFF_ALLMULTI)) { 429702b53ddSSøren Schmidt pfil |= GMAC_MAC_PACKET_FILTER_PM; 430702b53ddSSøren Schmidt } else { 431702b53ddSSøren Schmidt hash[0] = hash[1] = 0; 432702b53ddSSøren Schmidt pfil |= GMAC_MAC_PACKET_FILTER_HMC; 433702b53ddSSøren Schmidt if_foreach_llmaddr(ifp, eqos_hash_maddr, hash); 434702b53ddSSøren Schmidt } 435702b53ddSSøren Schmidt 436702b53ddSSøren Schmidt /* Write our unicast address */ 437a472fd7aSJustin Hibbits eaddr = if_getlladdr(ifp); 438702b53ddSSøren Schmidt val = eaddr[4] | (eaddr[5] << 8); 439702b53ddSSøren Schmidt WR4(sc, GMAC_MAC_ADDRESS0_HIGH, val); 440702b53ddSSøren Schmidt val = eaddr[0] | (eaddr[1] << 8) | (eaddr[2] << 16) | 441702b53ddSSøren Schmidt (eaddr[3] << 24); 442702b53ddSSøren Schmidt WR4(sc, GMAC_MAC_ADDRESS0_LOW, val); 443702b53ddSSøren Schmidt 444702b53ddSSøren Schmidt /* Multicast hash filters */ 445*bf8d4cfeSPeter Jeremy WR4(sc, GMAC_MAC_HASH_TABLE_REG0, hash[0]); 446*bf8d4cfeSPeter Jeremy WR4(sc, GMAC_MAC_HASH_TABLE_REG1, hash[1]); 447702b53ddSSøren Schmidt 448702b53ddSSøren Schmidt /* Packet filter config */ 449702b53ddSSøren Schmidt WR4(sc, GMAC_MAC_PACKET_FILTER, pfil); 450702b53ddSSøren Schmidt } 451702b53ddSSøren Schmidt 452702b53ddSSøren Schmidt static int 453702b53ddSSøren Schmidt eqos_reset(struct eqos_softc *sc) 454702b53ddSSøren Schmidt { 455702b53ddSSøren Schmidt uint32_t val; 456702b53ddSSøren Schmidt int retry; 457702b53ddSSøren Schmidt 458702b53ddSSøren Schmidt WR4(sc, GMAC_DMA_MODE, GMAC_DMA_MODE_SWR); 459702b53ddSSøren Schmidt for (retry = 2000; retry > 0; retry--) { 460702b53ddSSøren Schmidt DELAY(1000); 461702b53ddSSøren Schmidt val = RD4(sc, GMAC_DMA_MODE); 462702b53ddSSøren Schmidt if (!(val & GMAC_DMA_MODE_SWR)) 463702b53ddSSøren Schmidt return (0); 464702b53ddSSøren Schmidt } 465702b53ddSSøren Schmidt return (ETIMEDOUT); 466702b53ddSSøren Schmidt } 467702b53ddSSøren Schmidt 468702b53ddSSøren Schmidt static void 469702b53ddSSøren Schmidt eqos_init_rings(struct eqos_softc *sc) 470702b53ddSSøren Schmidt { 471702b53ddSSøren Schmidt 472702b53ddSSøren Schmidt WR4(sc, GMAC_DMA_CHAN0_TX_BASE_ADDR_HI, 473702b53ddSSøren Schmidt (uint32_t)(sc->tx.desc_ring_paddr >> 32)); 474702b53ddSSøren Schmidt WR4(sc, GMAC_DMA_CHAN0_TX_BASE_ADDR, 475702b53ddSSøren Schmidt (uint32_t)sc->tx.desc_ring_paddr); 476702b53ddSSøren Schmidt WR4(sc, GMAC_DMA_CHAN0_TX_RING_LEN, TX_DESC_COUNT - 1); 477702b53ddSSøren Schmidt 478702b53ddSSøren Schmidt WR4(sc, GMAC_DMA_CHAN0_RX_BASE_ADDR_HI, 479702b53ddSSøren Schmidt (uint32_t)(sc->rx.desc_ring_paddr >> 32)); 480702b53ddSSøren Schmidt WR4(sc, GMAC_DMA_CHAN0_RX_BASE_ADDR, 481702b53ddSSøren Schmidt (uint32_t)sc->rx.desc_ring_paddr); 482702b53ddSSøren Schmidt WR4(sc, GMAC_DMA_CHAN0_RX_RING_LEN, RX_DESC_COUNT - 1); 483702b53ddSSøren Schmidt 484702b53ddSSøren Schmidt WR4(sc, GMAC_DMA_CHAN0_RX_END_ADDR, 485702b53ddSSøren Schmidt (uint32_t)sc->rx.desc_ring_paddr + DESC_OFFSET(RX_DESC_COUNT)); 486702b53ddSSøren Schmidt } 487702b53ddSSøren Schmidt 488702b53ddSSøren Schmidt static void 489702b53ddSSøren Schmidt eqos_init(void *if_softc) 490702b53ddSSøren Schmidt { 491702b53ddSSøren Schmidt struct eqos_softc *sc = if_softc; 492a472fd7aSJustin Hibbits if_t ifp = sc->ifp; 493702b53ddSSøren Schmidt struct mii_data *mii = device_get_softc(sc->miibus); 494702b53ddSSøren Schmidt uint32_t val; 495702b53ddSSøren Schmidt 496702b53ddSSøren Schmidt if (if_getdrvflags(ifp) & IFF_DRV_RUNNING) 497702b53ddSSøren Schmidt return; 498702b53ddSSøren Schmidt 499702b53ddSSøren Schmidt EQOS_LOCK(sc); 500702b53ddSSøren Schmidt 501702b53ddSSøren Schmidt eqos_init_rings(sc); 502702b53ddSSøren Schmidt 503702b53ddSSøren Schmidt eqos_setup_rxfilter(sc); 504702b53ddSSøren Schmidt 505702b53ddSSøren Schmidt WR4(sc, GMAC_MAC_1US_TIC_COUNTER, (sc->csr_clock / 1000000) - 1); 506702b53ddSSøren Schmidt 507702b53ddSSøren Schmidt /* Enable transmit and receive DMA */ 508702b53ddSSøren Schmidt val = RD4(sc, GMAC_DMA_CHAN0_CONTROL); 509702b53ddSSøren Schmidt val &= ~GMAC_DMA_CHAN0_CONTROL_DSL_MASK; 510702b53ddSSøren Schmidt val |= ((DESC_ALIGN - 16) / 8) << GMAC_DMA_CHAN0_CONTROL_DSL_SHIFT; 511702b53ddSSøren Schmidt val |= GMAC_DMA_CHAN0_CONTROL_PBLX8; 512702b53ddSSøren Schmidt WR4(sc, GMAC_DMA_CHAN0_CONTROL, val); 513702b53ddSSøren Schmidt val = RD4(sc, GMAC_DMA_CHAN0_TX_CONTROL); 514702b53ddSSøren Schmidt val |= GMAC_DMA_CHAN0_TX_CONTROL_OSP; 515702b53ddSSøren Schmidt val |= GMAC_DMA_CHAN0_TX_CONTROL_START; 516702b53ddSSøren Schmidt WR4(sc, GMAC_DMA_CHAN0_TX_CONTROL, val); 517702b53ddSSøren Schmidt val = RD4(sc, GMAC_DMA_CHAN0_RX_CONTROL); 518702b53ddSSøren Schmidt val &= ~GMAC_DMA_CHAN0_RX_CONTROL_RBSZ_MASK; 519702b53ddSSøren Schmidt val |= (MCLBYTES << GMAC_DMA_CHAN0_RX_CONTROL_RBSZ_SHIFT); 520702b53ddSSøren Schmidt val |= GMAC_DMA_CHAN0_RX_CONTROL_START; 521702b53ddSSøren Schmidt WR4(sc, GMAC_DMA_CHAN0_RX_CONTROL, val); 522702b53ddSSøren Schmidt 523702b53ddSSøren Schmidt /* Disable counters */ 524702b53ddSSøren Schmidt WR4(sc, GMAC_MMC_CONTROL, 525702b53ddSSøren Schmidt GMAC_MMC_CONTROL_CNTFREEZ | 526702b53ddSSøren Schmidt GMAC_MMC_CONTROL_CNTPRST | 527702b53ddSSøren Schmidt GMAC_MMC_CONTROL_CNTPRSTLVL); 528702b53ddSSøren Schmidt 529702b53ddSSøren Schmidt /* Configure operation modes */ 530702b53ddSSøren Schmidt WR4(sc, GMAC_MTL_TXQ0_OPERATION_MODE, 531702b53ddSSøren Schmidt GMAC_MTL_TXQ0_OPERATION_MODE_TSF | 532702b53ddSSøren Schmidt GMAC_MTL_TXQ0_OPERATION_MODE_TXQEN_EN); 533702b53ddSSøren Schmidt WR4(sc, GMAC_MTL_RXQ0_OPERATION_MODE, 534702b53ddSSøren Schmidt GMAC_MTL_RXQ0_OPERATION_MODE_RSF | 535702b53ddSSøren Schmidt GMAC_MTL_RXQ0_OPERATION_MODE_FEP | 536702b53ddSSøren Schmidt GMAC_MTL_RXQ0_OPERATION_MODE_FUP); 537702b53ddSSøren Schmidt 538702b53ddSSøren Schmidt /* Enable flow control */ 539702b53ddSSøren Schmidt val = RD4(sc, GMAC_MAC_Q0_TX_FLOW_CTRL); 540702b53ddSSøren Schmidt val |= 0xFFFFU << GMAC_MAC_Q0_TX_FLOW_CTRL_PT_SHIFT; 541702b53ddSSøren Schmidt val |= GMAC_MAC_Q0_TX_FLOW_CTRL_TFE; 542702b53ddSSøren Schmidt WR4(sc, GMAC_MAC_Q0_TX_FLOW_CTRL, val); 543702b53ddSSøren Schmidt val = RD4(sc, GMAC_MAC_RX_FLOW_CTRL); 544702b53ddSSøren Schmidt val |= GMAC_MAC_RX_FLOW_CTRL_RFE; 545702b53ddSSøren Schmidt WR4(sc, GMAC_MAC_RX_FLOW_CTRL, val); 546702b53ddSSøren Schmidt 547702b53ddSSøren Schmidt /* set RX queue mode. must be in DCB mode. */ 548702b53ddSSøren Schmidt WR4(sc, GMAC_RXQ_CTRL0, (GMAC_RXQ_CTRL0_EN_MASK << 16) | 549702b53ddSSøren Schmidt GMAC_RXQ_CTRL0_EN_DCB); 550702b53ddSSøren Schmidt 551702b53ddSSøren Schmidt /* Enable transmitter and receiver */ 552702b53ddSSøren Schmidt val = RD4(sc, GMAC_MAC_CONFIGURATION); 553702b53ddSSøren Schmidt val |= GMAC_MAC_CONFIGURATION_BE; 554702b53ddSSøren Schmidt val |= GMAC_MAC_CONFIGURATION_JD; 555702b53ddSSøren Schmidt val |= GMAC_MAC_CONFIGURATION_JE; 556702b53ddSSøren Schmidt val |= GMAC_MAC_CONFIGURATION_DCRS; 557702b53ddSSøren Schmidt val |= GMAC_MAC_CONFIGURATION_TE; 558702b53ddSSøren Schmidt val |= GMAC_MAC_CONFIGURATION_RE; 559702b53ddSSøren Schmidt WR4(sc, GMAC_MAC_CONFIGURATION, val); 560702b53ddSSøren Schmidt 561702b53ddSSøren Schmidt eqos_enable_intr(sc); 562702b53ddSSøren Schmidt 563702b53ddSSøren Schmidt if_setdrvflagbits(ifp, IFF_DRV_RUNNING, IFF_DRV_OACTIVE); 564702b53ddSSøren Schmidt 565702b53ddSSøren Schmidt mii_mediachg(mii); 566702b53ddSSøren Schmidt callout_reset(&sc->callout, hz, eqos_tick, sc); 567702b53ddSSøren Schmidt 568702b53ddSSøren Schmidt EQOS_UNLOCK(sc); 569702b53ddSSøren Schmidt } 570702b53ddSSøren Schmidt 571702b53ddSSøren Schmidt static void 572a472fd7aSJustin Hibbits eqos_start_locked(if_t ifp) 573702b53ddSSøren Schmidt { 574a472fd7aSJustin Hibbits struct eqos_softc *sc = if_getsoftc(ifp); 575702b53ddSSøren Schmidt struct mbuf *m; 576702b53ddSSøren Schmidt int pending = 0; 577702b53ddSSøren Schmidt 578702b53ddSSøren Schmidt if (!sc->link_up) 579702b53ddSSøren Schmidt return; 580702b53ddSSøren Schmidt 581702b53ddSSøren Schmidt if ((if_getdrvflags(ifp) & (IFF_DRV_RUNNING|IFF_DRV_OACTIVE)) != 582702b53ddSSøren Schmidt IFF_DRV_RUNNING) 583702b53ddSSøren Schmidt return; 584702b53ddSSøren Schmidt 585702b53ddSSøren Schmidt while (true) { 586702b53ddSSøren Schmidt if (TX_QUEUED(sc->tx.head, sc->tx.tail) >= 587702b53ddSSøren Schmidt TX_DESC_COUNT - TX_MAX_SEGS) { 588702b53ddSSøren Schmidt if_setdrvflagbits(ifp, IFF_DRV_OACTIVE, 0); 589702b53ddSSøren Schmidt break; 590702b53ddSSøren Schmidt } 591702b53ddSSøren Schmidt 592702b53ddSSøren Schmidt if (!(m = if_dequeue(ifp))) 593702b53ddSSøren Schmidt break; 594702b53ddSSøren Schmidt 595702b53ddSSøren Schmidt if (eqos_setup_txbuf(sc, m)) { 596702b53ddSSøren Schmidt if_sendq_prepend(ifp, m); 597702b53ddSSøren Schmidt if_setdrvflagbits(ifp, IFF_DRV_OACTIVE, 0); 598702b53ddSSøren Schmidt break; 599702b53ddSSøren Schmidt } 6002a371643SJustin Hibbits bpf_mtap_if(ifp, m); 601702b53ddSSøren Schmidt pending++; 602702b53ddSSøren Schmidt } 603702b53ddSSøren Schmidt 604702b53ddSSøren Schmidt if (pending) { 605702b53ddSSøren Schmidt bus_dmamap_sync(sc->tx.desc_tag, sc->tx.desc_map, 606702b53ddSSøren Schmidt BUS_DMASYNC_PREREAD | BUS_DMASYNC_PREWRITE); 607702b53ddSSøren Schmidt 608702b53ddSSøren Schmidt /* Start and run TX DMA */ 609702b53ddSSøren Schmidt WR4(sc, GMAC_DMA_CHAN0_TX_END_ADDR, 610702b53ddSSøren Schmidt (uint32_t)sc->tx.desc_ring_paddr + DESC_OFFSET(sc->tx.head)); 611702b53ddSSøren Schmidt sc->tx_watchdog = WATCHDOG_TIMEOUT_SECS; 612702b53ddSSøren Schmidt } 613702b53ddSSøren Schmidt } 614702b53ddSSøren Schmidt 615702b53ddSSøren Schmidt static void 616a472fd7aSJustin Hibbits eqos_start(if_t ifp) 617702b53ddSSøren Schmidt { 618a472fd7aSJustin Hibbits struct eqos_softc *sc = if_getsoftc(ifp); 619702b53ddSSøren Schmidt 620702b53ddSSøren Schmidt EQOS_LOCK(sc); 621702b53ddSSøren Schmidt eqos_start_locked(ifp); 622702b53ddSSøren Schmidt EQOS_UNLOCK(sc); 623702b53ddSSøren Schmidt } 624702b53ddSSøren Schmidt 625702b53ddSSøren Schmidt static void 626702b53ddSSøren Schmidt eqos_stop(struct eqos_softc *sc) 627702b53ddSSøren Schmidt { 628a472fd7aSJustin Hibbits if_t ifp = sc->ifp; 629702b53ddSSøren Schmidt uint32_t val; 630702b53ddSSøren Schmidt int retry; 631702b53ddSSøren Schmidt 632702b53ddSSøren Schmidt EQOS_LOCK(sc); 633702b53ddSSøren Schmidt 634702b53ddSSøren Schmidt if_setdrvflagbits(ifp, 0, IFF_DRV_RUNNING | IFF_DRV_OACTIVE); 635702b53ddSSøren Schmidt 636702b53ddSSøren Schmidt callout_stop(&sc->callout); 637702b53ddSSøren Schmidt 638702b53ddSSøren Schmidt /* Disable receiver */ 639702b53ddSSøren Schmidt val = RD4(sc, GMAC_MAC_CONFIGURATION); 640702b53ddSSøren Schmidt val &= ~GMAC_MAC_CONFIGURATION_RE; 641702b53ddSSøren Schmidt WR4(sc, GMAC_MAC_CONFIGURATION, val); 642702b53ddSSøren Schmidt 643702b53ddSSøren Schmidt /* Stop receive DMA */ 644702b53ddSSøren Schmidt val = RD4(sc, GMAC_DMA_CHAN0_RX_CONTROL); 645702b53ddSSøren Schmidt val &= ~GMAC_DMA_CHAN0_RX_CONTROL_START; 646702b53ddSSøren Schmidt WR4(sc, GMAC_DMA_CHAN0_RX_CONTROL, val); 647702b53ddSSøren Schmidt 648702b53ddSSøren Schmidt /* Stop transmit DMA */ 649702b53ddSSøren Schmidt val = RD4(sc, GMAC_DMA_CHAN0_TX_CONTROL); 650702b53ddSSøren Schmidt val &= ~GMAC_DMA_CHAN0_TX_CONTROL_START; 651702b53ddSSøren Schmidt WR4(sc, GMAC_DMA_CHAN0_TX_CONTROL, val); 652702b53ddSSøren Schmidt 653702b53ddSSøren Schmidt /* Flush data in the TX FIFO */ 654702b53ddSSøren Schmidt val = RD4(sc, GMAC_MTL_TXQ0_OPERATION_MODE); 655702b53ddSSøren Schmidt val |= GMAC_MTL_TXQ0_OPERATION_MODE_FTQ; 656702b53ddSSøren Schmidt WR4(sc, GMAC_MTL_TXQ0_OPERATION_MODE, val); 657702b53ddSSøren Schmidt for (retry = 10000; retry > 0; retry--) { 658702b53ddSSøren Schmidt val = RD4(sc, GMAC_MTL_TXQ0_OPERATION_MODE); 659702b53ddSSøren Schmidt if (!(val & GMAC_MTL_TXQ0_OPERATION_MODE_FTQ)) 660702b53ddSSøren Schmidt break; 661702b53ddSSøren Schmidt DELAY(10); 662702b53ddSSøren Schmidt } 663702b53ddSSøren Schmidt if (!retry) 664702b53ddSSøren Schmidt device_printf(sc->dev, "timeout flushing TX queue\n"); 665702b53ddSSøren Schmidt 666702b53ddSSøren Schmidt /* Disable transmitter */ 667702b53ddSSøren Schmidt val = RD4(sc, GMAC_MAC_CONFIGURATION); 668702b53ddSSøren Schmidt val &= ~GMAC_MAC_CONFIGURATION_TE; 669702b53ddSSøren Schmidt WR4(sc, GMAC_MAC_CONFIGURATION, val); 670702b53ddSSøren Schmidt 671702b53ddSSøren Schmidt eqos_disable_intr(sc); 672702b53ddSSøren Schmidt 673702b53ddSSøren Schmidt EQOS_UNLOCK(sc); 674702b53ddSSøren Schmidt } 675702b53ddSSøren Schmidt 676702b53ddSSøren Schmidt static void 677702b53ddSSøren Schmidt eqos_rxintr(struct eqos_softc *sc) 678702b53ddSSøren Schmidt { 679a472fd7aSJustin Hibbits if_t ifp = sc->ifp; 680702b53ddSSøren Schmidt struct mbuf *m; 681702b53ddSSøren Schmidt uint32_t rdes3; 682702b53ddSSøren Schmidt int error, length; 683702b53ddSSøren Schmidt 684702b53ddSSøren Schmidt while (true) { 685702b53ddSSøren Schmidt rdes3 = le32toh(sc->rx.desc_ring[sc->rx.head].des3); 686702b53ddSSøren Schmidt if ((rdes3 & EQOS_RDES3_OWN)) 687702b53ddSSøren Schmidt break; 688702b53ddSSøren Schmidt 689702b53ddSSøren Schmidt if (rdes3 & (EQOS_RDES3_OE | EQOS_RDES3_RE)) 690551921a7SGordon Bergling printf("Receive error rdes3=%08x\n", rdes3); 691702b53ddSSøren Schmidt 692702b53ddSSøren Schmidt bus_dmamap_sync(sc->rx.buf_tag, 693702b53ddSSøren Schmidt sc->rx.buf_map[sc->rx.head].map, BUS_DMASYNC_POSTREAD); 694702b53ddSSøren Schmidt bus_dmamap_unload(sc->rx.buf_tag, 695702b53ddSSøren Schmidt sc->rx.buf_map[sc->rx.head].map); 696702b53ddSSøren Schmidt 697702b53ddSSøren Schmidt length = rdes3 & EQOS_RDES3_LENGTH_MASK; 698702b53ddSSøren Schmidt if (length) { 699702b53ddSSøren Schmidt m = sc->rx.buf_map[sc->rx.head].mbuf; 700702b53ddSSøren Schmidt m->m_pkthdr.rcvif = ifp; 701702b53ddSSøren Schmidt m->m_pkthdr.len = length; 702702b53ddSSøren Schmidt m->m_len = length; 703702b53ddSSøren Schmidt m->m_nextpkt = NULL; 704702b53ddSSøren Schmidt 705702b53ddSSøren Schmidt /* Remove trailing FCS */ 706702b53ddSSøren Schmidt m_adj(m, -ETHER_CRC_LEN); 707702b53ddSSøren Schmidt 708702b53ddSSøren Schmidt EQOS_UNLOCK(sc); 709a472fd7aSJustin Hibbits if_input(ifp, m); 710702b53ddSSøren Schmidt EQOS_LOCK(sc); 711702b53ddSSøren Schmidt } 712702b53ddSSøren Schmidt 713702b53ddSSøren Schmidt if ((m = eqos_alloc_mbufcl(sc))) { 714702b53ddSSøren Schmidt if ((error = eqos_setup_rxbuf(sc, sc->rx.head, m))) 715702b53ddSSøren Schmidt printf("ERROR: Hole in RX ring!!\n"); 716702b53ddSSøren Schmidt } 717702b53ddSSøren Schmidt else 718702b53ddSSøren Schmidt if_inc_counter(ifp, IFCOUNTER_IERRORS, 1); 719702b53ddSSøren Schmidt 720702b53ddSSøren Schmidt if_inc_counter(ifp, IFCOUNTER_IPACKETS, 1); 721702b53ddSSøren Schmidt 722702b53ddSSøren Schmidt WR4(sc, GMAC_DMA_CHAN0_RX_END_ADDR, 723702b53ddSSøren Schmidt (uint32_t)sc->rx.desc_ring_paddr + DESC_OFFSET(sc->rx.head)); 724702b53ddSSøren Schmidt 725702b53ddSSøren Schmidt sc->rx.head = RX_NEXT(sc->rx.head); 726702b53ddSSøren Schmidt } 727702b53ddSSøren Schmidt } 728702b53ddSSøren Schmidt 729702b53ddSSøren Schmidt static void 730702b53ddSSøren Schmidt eqos_txintr(struct eqos_softc *sc) 731702b53ddSSøren Schmidt { 732a472fd7aSJustin Hibbits if_t ifp = sc->ifp; 733702b53ddSSøren Schmidt struct eqos_bufmap *bmap; 734702b53ddSSøren Schmidt uint32_t tdes3; 735702b53ddSSøren Schmidt 736702b53ddSSøren Schmidt EQOS_ASSERT_LOCKED(sc); 737702b53ddSSøren Schmidt 738702b53ddSSøren Schmidt while (sc->tx.tail != sc->tx.head) { 739702b53ddSSøren Schmidt tdes3 = le32toh(sc->tx.desc_ring[sc->tx.tail].des3); 740702b53ddSSøren Schmidt if ((tdes3 & EQOS_TDES3_OWN)) 741702b53ddSSøren Schmidt break; 742702b53ddSSøren Schmidt 743702b53ddSSøren Schmidt bmap = &sc->tx.buf_map[sc->tx.tail]; 744702b53ddSSøren Schmidt if (bmap->mbuf) { 745702b53ddSSøren Schmidt bus_dmamap_sync(sc->tx.buf_tag, bmap->map, 746702b53ddSSøren Schmidt BUS_DMASYNC_POSTWRITE); 747702b53ddSSøren Schmidt bus_dmamap_unload(sc->tx.buf_tag, bmap->map); 748702b53ddSSøren Schmidt m_freem(bmap->mbuf); 749702b53ddSSøren Schmidt bmap->mbuf = NULL; 750702b53ddSSøren Schmidt } 751702b53ddSSøren Schmidt 752702b53ddSSøren Schmidt eqos_setup_txdesc(sc, sc->tx.tail, 0, 0, 0, 0); 753702b53ddSSøren Schmidt 754702b53ddSSøren Schmidt if_setdrvflagbits(ifp, 0, IFF_DRV_OACTIVE); 755702b53ddSSøren Schmidt 756702b53ddSSøren Schmidt /* Last descriptor in a packet contains DMA status */ 757702b53ddSSøren Schmidt if ((tdes3 & EQOS_TDES3_LD)) { 758702b53ddSSøren Schmidt if ((tdes3 & EQOS_TDES3_DE)) { 759702b53ddSSøren Schmidt if_inc_counter(ifp, IFCOUNTER_OERRORS, 1); 760702b53ddSSøren Schmidt } else if ((tdes3 & EQOS_TDES3_ES)) { 761702b53ddSSøren Schmidt if_inc_counter(ifp, IFCOUNTER_OERRORS, 1); 762702b53ddSSøren Schmidt } else { 763702b53ddSSøren Schmidt if_inc_counter(ifp, IFCOUNTER_OPACKETS, 1); 764702b53ddSSøren Schmidt } 765702b53ddSSøren Schmidt } 766702b53ddSSøren Schmidt sc->tx.tail = TX_NEXT(sc->tx.tail); 767702b53ddSSøren Schmidt } 768702b53ddSSøren Schmidt if (sc->tx.tail == sc->tx.head) 769702b53ddSSøren Schmidt sc->tx_watchdog = 0; 770702b53ddSSøren Schmidt eqos_start_locked(sc->ifp); 771702b53ddSSøren Schmidt } 772702b53ddSSøren Schmidt 773702b53ddSSøren Schmidt static void 774702b53ddSSøren Schmidt eqos_intr_mtl(struct eqos_softc *sc, uint32_t mtl_status) 775702b53ddSSøren Schmidt { 776702b53ddSSøren Schmidt uint32_t mtl_istat = 0; 777702b53ddSSøren Schmidt 778702b53ddSSøren Schmidt if ((mtl_status & GMAC_MTL_INTERRUPT_STATUS_Q0IS)) { 779702b53ddSSøren Schmidt uint32_t mtl_clear = 0; 780702b53ddSSøren Schmidt 781702b53ddSSøren Schmidt mtl_istat = RD4(sc, GMAC_MTL_Q0_INTERRUPT_CTRL_STATUS); 782702b53ddSSøren Schmidt if ((mtl_istat & GMAC_MTL_Q0_INTERRUPT_CTRL_STATUS_RXOVFIS)) { 783702b53ddSSøren Schmidt mtl_clear |= GMAC_MTL_Q0_INTERRUPT_CTRL_STATUS_RXOVFIS; 784702b53ddSSøren Schmidt } 785702b53ddSSøren Schmidt if ((mtl_istat & GMAC_MTL_Q0_INTERRUPT_CTRL_STATUS_TXUNFIS)) { 786702b53ddSSøren Schmidt mtl_clear |= GMAC_MTL_Q0_INTERRUPT_CTRL_STATUS_TXUNFIS; 787702b53ddSSøren Schmidt } 788702b53ddSSøren Schmidt if (mtl_clear) { 789702b53ddSSøren Schmidt mtl_clear |= (mtl_istat & 790702b53ddSSøren Schmidt (GMAC_MTL_Q0_INTERRUPT_CTRL_STATUS_RXOIE | 791702b53ddSSøren Schmidt GMAC_MTL_Q0_INTERRUPT_CTRL_STATUS_TXUIE)); 792702b53ddSSøren Schmidt WR4(sc, GMAC_MTL_Q0_INTERRUPT_CTRL_STATUS, mtl_clear); 793702b53ddSSøren Schmidt } 794702b53ddSSøren Schmidt } 795702b53ddSSøren Schmidt if (bootverbose) 796702b53ddSSøren Schmidt device_printf(sc->dev, 797702b53ddSSøren Schmidt "GMAC_MTL_INTERRUPT_STATUS = 0x%08X, " 798702b53ddSSøren Schmidt "GMAC_MTL_INTERRUPT_STATUS_Q0IS = 0x%08X\n", 799702b53ddSSøren Schmidt mtl_status, mtl_istat); 800702b53ddSSøren Schmidt } 801702b53ddSSøren Schmidt 802702b53ddSSøren Schmidt static void 803702b53ddSSøren Schmidt eqos_tick(void *softc) 804702b53ddSSøren Schmidt { 805702b53ddSSøren Schmidt struct eqos_softc *sc = softc; 806702b53ddSSøren Schmidt struct mii_data *mii = device_get_softc(sc->miibus); 807702b53ddSSøren Schmidt bool link_status; 808702b53ddSSøren Schmidt 809702b53ddSSøren Schmidt EQOS_ASSERT_LOCKED(sc); 810702b53ddSSøren Schmidt 811702b53ddSSøren Schmidt if (sc->tx_watchdog > 0) 812702b53ddSSøren Schmidt if (!--sc->tx_watchdog) { 813702b53ddSSøren Schmidt device_printf(sc->dev, "watchdog timeout\n"); 814702b53ddSSøren Schmidt eqos_txintr(sc); 815702b53ddSSøren Schmidt } 816702b53ddSSøren Schmidt 817702b53ddSSøren Schmidt link_status = sc->link_up; 818702b53ddSSøren Schmidt mii_tick(mii); 819702b53ddSSøren Schmidt if (sc->link_up && !link_status) 820702b53ddSSøren Schmidt eqos_start_locked(sc->ifp); 821702b53ddSSøren Schmidt 822702b53ddSSøren Schmidt callout_reset(&sc->callout, hz, eqos_tick, sc); 823702b53ddSSøren Schmidt } 824702b53ddSSøren Schmidt 825702b53ddSSøren Schmidt static void 826702b53ddSSøren Schmidt eqos_intr(void *arg) 827702b53ddSSøren Schmidt { 828702b53ddSSøren Schmidt struct eqos_softc *sc = arg; 829702b53ddSSøren Schmidt uint32_t mac_status, mtl_status, dma_status, rx_tx_status; 830702b53ddSSøren Schmidt 831702b53ddSSøren Schmidt mac_status = RD4(sc, GMAC_MAC_INTERRUPT_STATUS); 832702b53ddSSøren Schmidt mac_status &= RD4(sc, GMAC_MAC_INTERRUPT_ENABLE); 833702b53ddSSøren Schmidt 834702b53ddSSøren Schmidt if (mac_status) 835702b53ddSSøren Schmidt device_printf(sc->dev, "MAC interrupt\n"); 836702b53ddSSøren Schmidt 837702b53ddSSøren Schmidt if ((mtl_status = RD4(sc, GMAC_MTL_INTERRUPT_STATUS))) 838702b53ddSSøren Schmidt eqos_intr_mtl(sc, mtl_status); 839702b53ddSSøren Schmidt 840702b53ddSSøren Schmidt dma_status = RD4(sc, GMAC_DMA_CHAN0_STATUS); 841702b53ddSSøren Schmidt dma_status &= RD4(sc, GMAC_DMA_CHAN0_INTR_ENABLE); 842702b53ddSSøren Schmidt 843702b53ddSSøren Schmidt if (dma_status) 844702b53ddSSøren Schmidt WR4(sc, GMAC_DMA_CHAN0_STATUS, dma_status); 845702b53ddSSøren Schmidt 846702b53ddSSøren Schmidt EQOS_LOCK(sc); 847702b53ddSSøren Schmidt 848702b53ddSSøren Schmidt if (dma_status & GMAC_DMA_CHAN0_STATUS_RI) 849702b53ddSSøren Schmidt eqos_rxintr(sc); 850702b53ddSSøren Schmidt 851702b53ddSSøren Schmidt if (dma_status & GMAC_DMA_CHAN0_STATUS_TI) 852702b53ddSSøren Schmidt eqos_txintr(sc); 853702b53ddSSøren Schmidt 854702b53ddSSøren Schmidt EQOS_UNLOCK(sc); 855702b53ddSSøren Schmidt 856702b53ddSSøren Schmidt if (!(mac_status | mtl_status | dma_status)) { 857702b53ddSSøren Schmidt device_printf(sc->dev, 858702b53ddSSøren Schmidt "spurious interrupt mac=%08x mtl=%08x dma=%08x\n", 859702b53ddSSøren Schmidt RD4(sc, GMAC_MAC_INTERRUPT_STATUS), 860702b53ddSSøren Schmidt RD4(sc, GMAC_MTL_INTERRUPT_STATUS), 861702b53ddSSøren Schmidt RD4(sc, GMAC_DMA_CHAN0_STATUS)); 862702b53ddSSøren Schmidt } 863702b53ddSSøren Schmidt if ((rx_tx_status = RD4(sc, GMAC_MAC_RX_TX_STATUS))) 864702b53ddSSøren Schmidt device_printf(sc->dev, "RX/TX status interrupt\n"); 865702b53ddSSøren Schmidt } 866702b53ddSSøren Schmidt 867702b53ddSSøren Schmidt static int 868a472fd7aSJustin Hibbits eqos_ioctl(if_t ifp, u_long cmd, caddr_t data) 869702b53ddSSøren Schmidt { 870a472fd7aSJustin Hibbits struct eqos_softc *sc = if_getsoftc(ifp); 871702b53ddSSøren Schmidt struct ifreq *ifr = (struct ifreq *)data; 872702b53ddSSøren Schmidt struct mii_data *mii; 873702b53ddSSøren Schmidt int flags, mask; 874702b53ddSSøren Schmidt int error = 0; 875702b53ddSSøren Schmidt 876702b53ddSSøren Schmidt switch (cmd) { 877702b53ddSSøren Schmidt case SIOCSIFFLAGS: 878702b53ddSSøren Schmidt if (if_getflags(ifp) & IFF_UP) { 879702b53ddSSøren Schmidt if (if_getdrvflags(ifp) & IFF_DRV_RUNNING) { 880702b53ddSSøren Schmidt flags = if_getflags(ifp); 881702b53ddSSøren Schmidt if ((flags & (IFF_PROMISC|IFF_ALLMULTI))) { 882702b53ddSSøren Schmidt EQOS_LOCK(sc); 883702b53ddSSøren Schmidt eqos_setup_rxfilter(sc); 884702b53ddSSøren Schmidt EQOS_UNLOCK(sc); 885702b53ddSSøren Schmidt } 886702b53ddSSøren Schmidt } 887702b53ddSSøren Schmidt else { 888702b53ddSSøren Schmidt eqos_init(sc); 889702b53ddSSøren Schmidt } 890702b53ddSSøren Schmidt } 891702b53ddSSøren Schmidt else { 892702b53ddSSøren Schmidt if (if_getdrvflags(ifp) & IFF_DRV_RUNNING) 893702b53ddSSøren Schmidt eqos_stop(sc); 894702b53ddSSøren Schmidt } 895702b53ddSSøren Schmidt break; 896702b53ddSSøren Schmidt 897702b53ddSSøren Schmidt case SIOCADDMULTI: 898702b53ddSSøren Schmidt case SIOCDELMULTI: 899702b53ddSSøren Schmidt if (if_getdrvflags(ifp) & IFF_DRV_RUNNING) { 900702b53ddSSøren Schmidt EQOS_LOCK(sc); 901702b53ddSSøren Schmidt eqos_setup_rxfilter(sc); 902702b53ddSSøren Schmidt EQOS_UNLOCK(sc); 903702b53ddSSøren Schmidt } 904702b53ddSSøren Schmidt break; 905702b53ddSSøren Schmidt 906702b53ddSSøren Schmidt case SIOCSIFMEDIA: 907702b53ddSSøren Schmidt case SIOCGIFMEDIA: 908702b53ddSSøren Schmidt mii = device_get_softc(sc->miibus); 909702b53ddSSøren Schmidt error = ifmedia_ioctl(ifp, ifr, &mii->mii_media, cmd); 910702b53ddSSøren Schmidt break; 911702b53ddSSøren Schmidt 912702b53ddSSøren Schmidt case SIOCSIFCAP: 913702b53ddSSøren Schmidt mask = ifr->ifr_reqcap ^ if_getcapenable(ifp); 914702b53ddSSøren Schmidt if (mask & IFCAP_VLAN_MTU) 915702b53ddSSøren Schmidt if_togglecapenable(ifp, IFCAP_VLAN_MTU); 916702b53ddSSøren Schmidt if (mask & IFCAP_RXCSUM) 917702b53ddSSøren Schmidt if_togglecapenable(ifp, IFCAP_RXCSUM); 918702b53ddSSøren Schmidt if (mask & IFCAP_TXCSUM) 919702b53ddSSøren Schmidt if_togglecapenable(ifp, IFCAP_TXCSUM); 920702b53ddSSøren Schmidt if ((if_getcapenable(ifp) & IFCAP_TXCSUM)) 921702b53ddSSøren Schmidt if_sethwassistbits(ifp, 922702b53ddSSøren Schmidt CSUM_IP | CSUM_UDP | CSUM_TCP, 0); 923702b53ddSSøren Schmidt else 924702b53ddSSøren Schmidt if_sethwassistbits(ifp, 925702b53ddSSøren Schmidt 0, CSUM_IP | CSUM_UDP | CSUM_TCP); 926702b53ddSSøren Schmidt break; 927702b53ddSSøren Schmidt 928702b53ddSSøren Schmidt default: 929702b53ddSSøren Schmidt error = ether_ioctl(ifp, cmd, data); 930702b53ddSSøren Schmidt break; 931702b53ddSSøren Schmidt } 932702b53ddSSøren Schmidt 933702b53ddSSøren Schmidt return (error); 934702b53ddSSøren Schmidt } 935702b53ddSSøren Schmidt 936702b53ddSSøren Schmidt static void 937702b53ddSSøren Schmidt eqos_get_eaddr(struct eqos_softc *sc, uint8_t *eaddr) 938702b53ddSSøren Schmidt { 939702b53ddSSøren Schmidt uint32_t maclo, machi; 940702b53ddSSøren Schmidt 941702b53ddSSøren Schmidt maclo = htobe32(RD4(sc, GMAC_MAC_ADDRESS0_LOW)); 942702b53ddSSøren Schmidt machi = htobe16(RD4(sc, GMAC_MAC_ADDRESS0_HIGH) & 0xFFFF); 943702b53ddSSøren Schmidt 944702b53ddSSøren Schmidt /* if no valid MAC address generate random */ 945702b53ddSSøren Schmidt if (maclo == 0xffffffff && machi == 0xffff) { 946702b53ddSSøren Schmidt maclo = 0xf2 | (arc4random() & 0xffff0000); 947702b53ddSSøren Schmidt machi = arc4random() & 0x0000ffff; 948702b53ddSSøren Schmidt } 949702b53ddSSøren Schmidt eaddr[0] = maclo & 0xff; 950702b53ddSSøren Schmidt eaddr[1] = (maclo >> 8) & 0xff; 951702b53ddSSøren Schmidt eaddr[2] = (maclo >> 16) & 0xff; 952702b53ddSSøren Schmidt eaddr[3] = (maclo >> 24) & 0xff; 953702b53ddSSøren Schmidt eaddr[4] = machi & 0xff; 954702b53ddSSøren Schmidt eaddr[5] = (machi >> 8) & 0xff; 955702b53ddSSøren Schmidt } 956702b53ddSSøren Schmidt 957702b53ddSSøren Schmidt static void 958702b53ddSSøren Schmidt eqos_axi_configure(struct eqos_softc *sc) 959702b53ddSSøren Schmidt { 960702b53ddSSøren Schmidt uint32_t val; 961702b53ddSSøren Schmidt 962702b53ddSSøren Schmidt val = RD4(sc, GMAC_DMA_SYSBUS_MODE); 963702b53ddSSøren Schmidt 964702b53ddSSøren Schmidt /* Max Write Outstanding Req Limit */ 965702b53ddSSøren Schmidt val &= ~GMAC_DMA_SYSBUS_MODE_WR_OSR_LMT_MASK; 966702b53ddSSøren Schmidt val |= 0x03 << GMAC_DMA_SYSBUS_MODE_WR_OSR_LMT_SHIFT; 967702b53ddSSøren Schmidt 968702b53ddSSøren Schmidt /* Max Read Outstanding Req Limit */ 969702b53ddSSøren Schmidt val &= ~GMAC_DMA_SYSBUS_MODE_RD_OSR_LMT_MASK; 970702b53ddSSøren Schmidt val |= 0x07 << GMAC_DMA_SYSBUS_MODE_RD_OSR_LMT_SHIFT; 971702b53ddSSøren Schmidt 972702b53ddSSøren Schmidt /* Allowed Burst Length's */ 973702b53ddSSøren Schmidt val |= GMAC_DMA_SYSBUS_MODE_BLEN16; 974702b53ddSSøren Schmidt val |= GMAC_DMA_SYSBUS_MODE_BLEN8; 975702b53ddSSøren Schmidt val |= GMAC_DMA_SYSBUS_MODE_BLEN4; 976702b53ddSSøren Schmidt 977702b53ddSSøren Schmidt /* Fixed Burst Length */ 978702b53ddSSøren Schmidt val |= GMAC_DMA_SYSBUS_MODE_MB; 979702b53ddSSøren Schmidt 980702b53ddSSøren Schmidt WR4(sc, GMAC_DMA_SYSBUS_MODE, val); 981702b53ddSSøren Schmidt } 982702b53ddSSøren Schmidt 983702b53ddSSøren Schmidt static void 984702b53ddSSøren Schmidt eqos_get1paddr(void *arg, bus_dma_segment_t *segs, int nsegs, int error) 985702b53ddSSøren Schmidt { 986702b53ddSSøren Schmidt 987702b53ddSSøren Schmidt if (!error) 988702b53ddSSøren Schmidt *(bus_addr_t *)arg = segs[0].ds_addr; 989702b53ddSSøren Schmidt } 990702b53ddSSøren Schmidt 991702b53ddSSøren Schmidt static int 992702b53ddSSøren Schmidt eqos_setup_dma(struct eqos_softc *sc) 993702b53ddSSøren Schmidt { 994702b53ddSSøren Schmidt struct mbuf *m; 995702b53ddSSøren Schmidt int error, i; 996702b53ddSSøren Schmidt 997702b53ddSSøren Schmidt /* Set up TX descriptor ring, descriptors, and dma maps */ 998702b53ddSSøren Schmidt if ((error = bus_dma_tag_create(bus_get_dma_tag(sc->dev), 999702b53ddSSøren Schmidt DESC_ALIGN, DESC_BOUNDARY, 1000702b53ddSSøren Schmidt BUS_SPACE_MAXADDR_32BIT, 1001702b53ddSSøren Schmidt BUS_SPACE_MAXADDR, NULL, NULL, 1002702b53ddSSøren Schmidt TX_DESC_SIZE, 1, TX_DESC_SIZE, 0, 1003702b53ddSSøren Schmidt NULL, NULL, &sc->tx.desc_tag))) { 1004702b53ddSSøren Schmidt device_printf(sc->dev, "could not create TX ring DMA tag\n"); 1005702b53ddSSøren Schmidt return (error); 1006702b53ddSSøren Schmidt } 1007702b53ddSSøren Schmidt 1008702b53ddSSøren Schmidt if ((error = bus_dmamem_alloc(sc->tx.desc_tag, 1009702b53ddSSøren Schmidt (void**)&sc->tx.desc_ring, 1010702b53ddSSøren Schmidt BUS_DMA_COHERENT | BUS_DMA_WAITOK | BUS_DMA_ZERO, 1011702b53ddSSøren Schmidt &sc->tx.desc_map))) { 1012702b53ddSSøren Schmidt device_printf(sc->dev, 1013702b53ddSSøren Schmidt "could not allocate TX descriptor ring.\n"); 1014702b53ddSSøren Schmidt return (error); 1015702b53ddSSøren Schmidt } 1016702b53ddSSøren Schmidt 1017702b53ddSSøren Schmidt if ((error = bus_dmamap_load(sc->tx.desc_tag, sc->tx.desc_map, 1018702b53ddSSøren Schmidt sc->tx.desc_ring, 1019702b53ddSSøren Schmidt TX_DESC_SIZE, eqos_get1paddr, &sc->tx.desc_ring_paddr, 0))) { 1020702b53ddSSøren Schmidt device_printf(sc->dev, 1021702b53ddSSøren Schmidt "could not load TX descriptor ring map.\n"); 1022702b53ddSSøren Schmidt return (error); 1023702b53ddSSøren Schmidt } 1024702b53ddSSøren Schmidt 1025702b53ddSSøren Schmidt if ((error = bus_dma_tag_create(bus_get_dma_tag(sc->dev), 1, 0, 1026702b53ddSSøren Schmidt BUS_SPACE_MAXADDR_32BIT, 1027702b53ddSSøren Schmidt BUS_SPACE_MAXADDR, NULL, NULL, 1028702b53ddSSøren Schmidt MCLBYTES*TX_MAX_SEGS, TX_MAX_SEGS, 1029702b53ddSSøren Schmidt MCLBYTES, 0, NULL, NULL, 1030702b53ddSSøren Schmidt &sc->tx.buf_tag))) { 1031702b53ddSSøren Schmidt device_printf(sc->dev, "could not create TX buffer DMA tag.\n"); 1032702b53ddSSøren Schmidt return (error); 1033702b53ddSSøren Schmidt } 1034702b53ddSSøren Schmidt 1035702b53ddSSøren Schmidt for (i = 0; i < TX_DESC_COUNT; i++) { 1036702b53ddSSøren Schmidt if ((error = bus_dmamap_create(sc->tx.buf_tag, BUS_DMA_COHERENT, 1037702b53ddSSøren Schmidt &sc->tx.buf_map[i].map))) { 1038702b53ddSSøren Schmidt device_printf(sc->dev, "cannot create TX buffer map\n"); 1039702b53ddSSøren Schmidt return (error); 1040702b53ddSSøren Schmidt } 1041702b53ddSSøren Schmidt eqos_setup_txdesc(sc, i, EQOS_TDES3_OWN, 0, 0, 0); 1042702b53ddSSøren Schmidt } 1043702b53ddSSøren Schmidt 1044702b53ddSSøren Schmidt /* Set up RX descriptor ring, descriptors, dma maps, and mbufs */ 1045702b53ddSSøren Schmidt if ((error = bus_dma_tag_create(bus_get_dma_tag(sc->dev), 1046702b53ddSSøren Schmidt DESC_ALIGN, DESC_BOUNDARY, 1047702b53ddSSøren Schmidt BUS_SPACE_MAXADDR_32BIT, 1048702b53ddSSøren Schmidt BUS_SPACE_MAXADDR, NULL, NULL, 1049702b53ddSSøren Schmidt RX_DESC_SIZE, 1, RX_DESC_SIZE, 0, 1050702b53ddSSøren Schmidt NULL, NULL, &sc->rx.desc_tag))) { 1051702b53ddSSøren Schmidt device_printf(sc->dev, "could not create RX ring DMA tag.\n"); 1052702b53ddSSøren Schmidt return (error); 1053702b53ddSSøren Schmidt } 1054702b53ddSSøren Schmidt 1055702b53ddSSøren Schmidt if ((error = bus_dmamem_alloc(sc->rx.desc_tag, 1056702b53ddSSøren Schmidt (void **)&sc->rx.desc_ring, 1057702b53ddSSøren Schmidt BUS_DMA_COHERENT | BUS_DMA_WAITOK | BUS_DMA_ZERO, 1058702b53ddSSøren Schmidt &sc->rx.desc_map))) { 1059702b53ddSSøren Schmidt device_printf(sc->dev, 1060702b53ddSSøren Schmidt "could not allocate RX descriptor ring.\n"); 1061702b53ddSSøren Schmidt return (error); 1062702b53ddSSøren Schmidt } 1063702b53ddSSøren Schmidt 1064702b53ddSSøren Schmidt if ((error = bus_dmamap_load(sc->rx.desc_tag, sc->rx.desc_map, 1065702b53ddSSøren Schmidt sc->rx.desc_ring, RX_DESC_SIZE, eqos_get1paddr, 1066702b53ddSSøren Schmidt &sc->rx.desc_ring_paddr, 0))) { 1067702b53ddSSøren Schmidt device_printf(sc->dev, 1068702b53ddSSøren Schmidt "could not load RX descriptor ring map.\n"); 1069702b53ddSSøren Schmidt return (error); 1070702b53ddSSøren Schmidt } 1071702b53ddSSøren Schmidt 1072702b53ddSSøren Schmidt if ((error = bus_dma_tag_create(bus_get_dma_tag(sc->dev), 1, 0, 1073702b53ddSSøren Schmidt BUS_SPACE_MAXADDR_32BIT, 1074702b53ddSSøren Schmidt BUS_SPACE_MAXADDR, NULL, NULL, 1075702b53ddSSøren Schmidt MCLBYTES, 1, 1076702b53ddSSøren Schmidt MCLBYTES, 0, NULL, NULL, 1077702b53ddSSøren Schmidt &sc->rx.buf_tag))) { 1078702b53ddSSøren Schmidt device_printf(sc->dev, "could not create RX buf DMA tag.\n"); 1079702b53ddSSøren Schmidt return (error); 1080702b53ddSSøren Schmidt } 1081702b53ddSSøren Schmidt 1082702b53ddSSøren Schmidt for (i = 0; i < RX_DESC_COUNT; i++) { 1083702b53ddSSøren Schmidt if ((error = bus_dmamap_create(sc->rx.buf_tag, BUS_DMA_COHERENT, 1084702b53ddSSøren Schmidt &sc->rx.buf_map[i].map))) { 1085702b53ddSSøren Schmidt device_printf(sc->dev, "cannot create RX buffer map\n"); 1086702b53ddSSøren Schmidt return (error); 1087702b53ddSSøren Schmidt } 1088702b53ddSSøren Schmidt if (!(m = eqos_alloc_mbufcl(sc))) { 1089702b53ddSSøren Schmidt device_printf(sc->dev, "cannot allocate RX mbuf\n"); 1090702b53ddSSøren Schmidt return (ENOMEM); 1091702b53ddSSøren Schmidt } 1092702b53ddSSøren Schmidt if ((error = eqos_setup_rxbuf(sc, i, m))) { 1093702b53ddSSøren Schmidt device_printf(sc->dev, "cannot create RX buffer\n"); 1094702b53ddSSøren Schmidt return (error); 1095702b53ddSSøren Schmidt } 1096702b53ddSSøren Schmidt } 1097702b53ddSSøren Schmidt 1098702b53ddSSøren Schmidt if (bootverbose) 1099702b53ddSSøren Schmidt device_printf(sc->dev, "TX ring @ 0x%lx, RX ring @ 0x%lx\n", 1100702b53ddSSøren Schmidt sc->tx.desc_ring_paddr, sc->rx.desc_ring_paddr); 1101702b53ddSSøren Schmidt return (0); 1102702b53ddSSøren Schmidt } 1103702b53ddSSøren Schmidt 1104702b53ddSSøren Schmidt static int 1105702b53ddSSøren Schmidt eqos_attach(device_t dev) 1106702b53ddSSøren Schmidt { 1107702b53ddSSøren Schmidt struct eqos_softc *sc = device_get_softc(dev); 1108a472fd7aSJustin Hibbits if_t ifp; 1109702b53ddSSøren Schmidt uint32_t ver; 1110702b53ddSSøren Schmidt uint8_t eaddr[ETHER_ADDR_LEN]; 1111702b53ddSSøren Schmidt u_int userver, snpsver; 1112702b53ddSSøren Schmidt int error; 1113702b53ddSSøren Schmidt int n; 1114702b53ddSSøren Schmidt 1115702b53ddSSøren Schmidt /* setup resources */ 1116702b53ddSSøren Schmidt if (bus_alloc_resources(dev, eqos_spec, sc->res)) { 1117702b53ddSSøren Schmidt device_printf(dev, "Could not allocate resources\n"); 1118702b53ddSSøren Schmidt bus_release_resources(dev, eqos_spec, sc->res); 1119702b53ddSSøren Schmidt return (ENXIO); 1120702b53ddSSøren Schmidt } 1121702b53ddSSøren Schmidt 1122bd077139SEmmanuel Vadot if ((error = IF_EQOS_INIT(dev))) 1123bd077139SEmmanuel Vadot return (error); 1124bd077139SEmmanuel Vadot 1125702b53ddSSøren Schmidt sc->dev = dev; 1126702b53ddSSøren Schmidt ver = RD4(sc, GMAC_MAC_VERSION); 1127702b53ddSSøren Schmidt userver = (ver & GMAC_MAC_VERSION_USERVER_MASK) >> 1128702b53ddSSøren Schmidt GMAC_MAC_VERSION_USERVER_SHIFT; 1129702b53ddSSøren Schmidt snpsver = ver & GMAC_MAC_VERSION_SNPSVER_MASK; 1130702b53ddSSøren Schmidt 1131702b53ddSSøren Schmidt if (snpsver != 0x51) { 113296812bd1SEmmanuel Vadot device_printf(dev, "EQOS version 0x%02x not supported\n", 1133702b53ddSSøren Schmidt snpsver); 1134702b53ddSSøren Schmidt return (ENXIO); 1135702b53ddSSøren Schmidt } 1136702b53ddSSøren Schmidt 1137702b53ddSSøren Schmidt for (n = 0; n < 4; n++) 1138702b53ddSSøren Schmidt sc->hw_feature[n] = RD4(sc, GMAC_MAC_HW_FEATURE(n)); 1139702b53ddSSøren Schmidt 1140702b53ddSSøren Schmidt if (bootverbose) { 1141702b53ddSSøren Schmidt device_printf(dev, "DesignWare EQOS ver 0x%02x (0x%02x)\n", 1142702b53ddSSøren Schmidt snpsver, userver); 1143702b53ddSSøren Schmidt device_printf(dev, "hw features %08x %08x %08x %08x\n", 1144702b53ddSSøren Schmidt sc->hw_feature[0], sc->hw_feature[1], 1145702b53ddSSøren Schmidt sc->hw_feature[2], sc->hw_feature[3]); 1146702b53ddSSøren Schmidt } 1147702b53ddSSøren Schmidt 1148702b53ddSSøren Schmidt mtx_init(&sc->lock, "eqos lock", MTX_NETWORK_LOCK, MTX_DEF); 1149702b53ddSSøren Schmidt callout_init_mtx(&sc->callout, &sc->lock, 0); 1150702b53ddSSøren Schmidt 1151702b53ddSSøren Schmidt eqos_get_eaddr(sc, eaddr); 1152702b53ddSSøren Schmidt if (bootverbose) 1153702b53ddSSøren Schmidt device_printf(sc->dev, "Ethernet address %6D\n", eaddr, ":"); 1154702b53ddSSøren Schmidt 1155702b53ddSSøren Schmidt /* Soft reset EMAC core */ 1156702b53ddSSøren Schmidt if ((error = eqos_reset(sc))) { 1157702b53ddSSøren Schmidt device_printf(sc->dev, "reset timeout!\n"); 1158702b53ddSSøren Schmidt return (error); 1159702b53ddSSøren Schmidt } 1160702b53ddSSøren Schmidt 1161702b53ddSSøren Schmidt /* Configure AXI Bus mode parameters */ 1162702b53ddSSøren Schmidt eqos_axi_configure(sc); 1163702b53ddSSøren Schmidt 1164702b53ddSSøren Schmidt /* Setup DMA descriptors */ 1165702b53ddSSøren Schmidt if (eqos_setup_dma(sc)) { 1166702b53ddSSøren Schmidt device_printf(sc->dev, "failed to setup DMA descriptors\n"); 1167702b53ddSSøren Schmidt return (EINVAL); 1168702b53ddSSøren Schmidt } 1169702b53ddSSøren Schmidt 1170702b53ddSSøren Schmidt /* setup interrupt delivery */ 1171702b53ddSSøren Schmidt if ((bus_setup_intr(dev, sc->res[EQOS_RES_IRQ0], EQOS_INTR_FLAGS, 1172702b53ddSSøren Schmidt NULL, eqos_intr, sc, &sc->irq_handle))) { 1173702b53ddSSøren Schmidt device_printf(dev, "unable to setup 1st interrupt\n"); 1174702b53ddSSøren Schmidt bus_release_resources(dev, eqos_spec, sc->res); 1175702b53ddSSøren Schmidt return (ENXIO); 1176702b53ddSSøren Schmidt } 1177702b53ddSSøren Schmidt 1178702b53ddSSøren Schmidt /* Setup ethernet interface */ 1179702b53ddSSøren Schmidt ifp = sc->ifp = if_alloc(IFT_ETHER); 1180a472fd7aSJustin Hibbits if_setsoftc(ifp, sc); 1181702b53ddSSøren Schmidt if_initname(ifp, device_get_name(sc->dev), device_get_unit(sc->dev)); 1182702b53ddSSøren Schmidt if_setflags(sc->ifp, IFF_BROADCAST | IFF_SIMPLEX | IFF_MULTICAST); 1183702b53ddSSøren Schmidt if_setstartfn(ifp, eqos_start); 1184702b53ddSSøren Schmidt if_setioctlfn(ifp, eqos_ioctl); 1185702b53ddSSøren Schmidt if_setinitfn(ifp, eqos_init); 1186702b53ddSSøren Schmidt if_setsendqlen(ifp, TX_DESC_COUNT - 1); 1187702b53ddSSøren Schmidt if_setsendqready(ifp); 1188702b53ddSSøren Schmidt if_setcapabilities(ifp, IFCAP_VLAN_MTU /*| IFCAP_HWCSUM*/); 1189702b53ddSSøren Schmidt if_setcapenable(ifp, if_getcapabilities(ifp)); 1190702b53ddSSøren Schmidt 1191702b53ddSSøren Schmidt /* Attach MII driver */ 1192702b53ddSSøren Schmidt if ((error = mii_attach(sc->dev, &sc->miibus, ifp, eqos_media_change, 1193702b53ddSSøren Schmidt eqos_media_status, BMSR_DEFCAPMASK, MII_PHY_ANY, 1194702b53ddSSøren Schmidt MII_OFFSET_ANY, 0))) { 1195702b53ddSSøren Schmidt device_printf(sc->dev, "PHY attach failed\n"); 1196702b53ddSSøren Schmidt return (ENXIO); 1197702b53ddSSøren Schmidt } 1198702b53ddSSøren Schmidt 1199702b53ddSSøren Schmidt /* Attach ethernet interface */ 1200702b53ddSSøren Schmidt ether_ifattach(ifp, eaddr); 1201702b53ddSSøren Schmidt 1202702b53ddSSøren Schmidt return (0); 1203702b53ddSSøren Schmidt } 1204702b53ddSSøren Schmidt 1205702b53ddSSøren Schmidt static int 1206702b53ddSSøren Schmidt eqos_detach(device_t dev) 1207702b53ddSSøren Schmidt { 1208702b53ddSSøren Schmidt struct eqos_softc *sc = device_get_softc(dev); 1209702b53ddSSøren Schmidt int i; 1210702b53ddSSøren Schmidt 1211702b53ddSSøren Schmidt if (device_is_attached(dev)) { 1212702b53ddSSøren Schmidt EQOS_LOCK(sc); 1213702b53ddSSøren Schmidt eqos_stop(sc); 1214702b53ddSSøren Schmidt EQOS_UNLOCK(sc); 1215a472fd7aSJustin Hibbits if_setflagbits(sc->ifp, 0, IFF_UP); 1216702b53ddSSøren Schmidt ether_ifdetach(sc->ifp); 1217702b53ddSSøren Schmidt } 1218702b53ddSSøren Schmidt 1219702b53ddSSøren Schmidt bus_generic_detach(dev); 1220702b53ddSSøren Schmidt 1221702b53ddSSøren Schmidt if (sc->irq_handle) 1222702b53ddSSøren Schmidt bus_teardown_intr(dev, sc->res[EQOS_RES_IRQ0], 1223702b53ddSSøren Schmidt sc->irq_handle); 1224702b53ddSSøren Schmidt 1225702b53ddSSøren Schmidt if (sc->ifp) 1226702b53ddSSøren Schmidt if_free(sc->ifp); 1227702b53ddSSøren Schmidt 1228702b53ddSSøren Schmidt bus_release_resources(dev, eqos_spec, sc->res); 1229702b53ddSSøren Schmidt 1230702b53ddSSøren Schmidt if (sc->tx.desc_tag) { 1231702b53ddSSøren Schmidt if (sc->tx.desc_map) { 1232702b53ddSSøren Schmidt bus_dmamap_unload(sc->tx.desc_tag, sc->tx.desc_map); 1233702b53ddSSøren Schmidt bus_dmamem_free(sc->tx.desc_tag, sc->tx.desc_ring, 1234702b53ddSSøren Schmidt sc->tx.desc_map); 1235702b53ddSSøren Schmidt } 1236702b53ddSSøren Schmidt bus_dma_tag_destroy(sc->tx.desc_tag); 1237702b53ddSSøren Schmidt } 1238702b53ddSSøren Schmidt if (sc->tx.buf_tag) { 1239702b53ddSSøren Schmidt for (i = 0; i < TX_DESC_COUNT; i++) { 1240702b53ddSSøren Schmidt m_free(sc->tx.buf_map[i].mbuf); 1241702b53ddSSøren Schmidt bus_dmamap_destroy(sc->tx.buf_tag, 1242702b53ddSSøren Schmidt sc->tx.buf_map[i].map); 1243702b53ddSSøren Schmidt } 1244702b53ddSSøren Schmidt bus_dma_tag_destroy(sc->tx.buf_tag); 1245702b53ddSSøren Schmidt } 1246702b53ddSSøren Schmidt 1247702b53ddSSøren Schmidt if (sc->rx.desc_tag) { 1248702b53ddSSøren Schmidt if (sc->rx.desc_map) { 1249702b53ddSSøren Schmidt bus_dmamap_unload(sc->rx.desc_tag, sc->rx.desc_map); 1250702b53ddSSøren Schmidt bus_dmamem_free(sc->rx.desc_tag, sc->rx.desc_ring, 1251702b53ddSSøren Schmidt sc->rx.desc_map); 1252702b53ddSSøren Schmidt } 1253702b53ddSSøren Schmidt bus_dma_tag_destroy(sc->rx.desc_tag); 1254702b53ddSSøren Schmidt } 1255702b53ddSSøren Schmidt if (sc->rx.buf_tag) { 1256702b53ddSSøren Schmidt for (i = 0; i < RX_DESC_COUNT; i++) { 1257702b53ddSSøren Schmidt m_free(sc->rx.buf_map[i].mbuf); 1258702b53ddSSøren Schmidt bus_dmamap_destroy(sc->rx.buf_tag, 1259702b53ddSSøren Schmidt sc->rx.buf_map[i].map); 1260702b53ddSSøren Schmidt } 1261702b53ddSSøren Schmidt bus_dma_tag_destroy(sc->rx.buf_tag); 1262702b53ddSSøren Schmidt } 1263702b53ddSSøren Schmidt 1264702b53ddSSøren Schmidt mtx_destroy(&sc->lock); 1265702b53ddSSøren Schmidt 1266702b53ddSSøren Schmidt return (0); 1267702b53ddSSøren Schmidt } 1268702b53ddSSøren Schmidt 1269702b53ddSSøren Schmidt 1270702b53ddSSøren Schmidt static device_method_t eqos_methods[] = { 1271702b53ddSSøren Schmidt /* Device Interface */ 1272702b53ddSSøren Schmidt DEVMETHOD(device_attach, eqos_attach), 1273702b53ddSSøren Schmidt DEVMETHOD(device_detach, eqos_detach), 1274702b53ddSSøren Schmidt 1275702b53ddSSøren Schmidt /* MII Interface */ 1276702b53ddSSøren Schmidt DEVMETHOD(miibus_readreg, eqos_miibus_readreg), 1277702b53ddSSøren Schmidt DEVMETHOD(miibus_writereg, eqos_miibus_writereg), 1278702b53ddSSøren Schmidt DEVMETHOD(miibus_statchg, eqos_miibus_statchg), 1279702b53ddSSøren Schmidt 1280702b53ddSSøren Schmidt DEVMETHOD_END 1281702b53ddSSøren Schmidt }; 1282702b53ddSSøren Schmidt 1283702b53ddSSøren Schmidt driver_t eqos_driver = { 1284702b53ddSSøren Schmidt "eqos", 1285702b53ddSSøren Schmidt eqos_methods, 1286702b53ddSSøren Schmidt sizeof(struct eqos_softc), 1287702b53ddSSøren Schmidt }; 1288702b53ddSSøren Schmidt 1289702b53ddSSøren Schmidt DRIVER_MODULE(miibus, eqos, miibus_driver, 0, 0); 1290