1*3836e7c7Smiod /* $OpenBSD: bcmgenet.c,v 1.8 2024/11/05 18:58:59 miod Exp $ */ 2d3a0e4e9Skettenis /* $NetBSD: bcmgenet.c,v 1.3 2020/02/27 17:30:07 jmcneill Exp $ */ 3d3a0e4e9Skettenis 4d3a0e4e9Skettenis /*- 5d3a0e4e9Skettenis * Copyright (c) 2020 Jared McNeill <jmcneill@invisible.ca> 6d3a0e4e9Skettenis * Copyright (c) 2020 Mark Kettenis <kettenis@openbsd.org> 7d3a0e4e9Skettenis * All rights reserved. 8d3a0e4e9Skettenis * 9d3a0e4e9Skettenis * Redistribution and use in source and binary forms, with or without 10d3a0e4e9Skettenis * modification, are permitted provided that the following conditions 11d3a0e4e9Skettenis * are met: 12d3a0e4e9Skettenis * 1. Redistributions of source code must retain the above copyright 13d3a0e4e9Skettenis * notice, this list of conditions and the following disclaimer. 14d3a0e4e9Skettenis * 2. Redistributions in binary form must reproduce the above copyright 15d3a0e4e9Skettenis * notice, this list of conditions and the following disclaimer in the 16d3a0e4e9Skettenis * documentation and/or other materials provided with the distribution. 17d3a0e4e9Skettenis * 18d3a0e4e9Skettenis * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR 19d3a0e4e9Skettenis * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES 20d3a0e4e9Skettenis * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. 21d3a0e4e9Skettenis * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, 22d3a0e4e9Skettenis * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, 23d3a0e4e9Skettenis * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; 24d3a0e4e9Skettenis * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED 25d3a0e4e9Skettenis * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, 26d3a0e4e9Skettenis * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 27d3a0e4e9Skettenis * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 28d3a0e4e9Skettenis * SUCH DAMAGE. 29d3a0e4e9Skettenis */ 30d3a0e4e9Skettenis 31d3a0e4e9Skettenis /* 32d3a0e4e9Skettenis * Broadcom GENETv5 33d3a0e4e9Skettenis */ 34d3a0e4e9Skettenis 35d3a0e4e9Skettenis #include <sys/param.h> 36d3a0e4e9Skettenis #include <sys/device.h> 37d3a0e4e9Skettenis #include <sys/systm.h> 38d3a0e4e9Skettenis #include <sys/kernel.h> 39d3a0e4e9Skettenis #include <sys/mbuf.h> 40d3a0e4e9Skettenis #include <sys/queue.h> 41d3a0e4e9Skettenis #include <sys/socket.h> 42d3a0e4e9Skettenis #include <sys/sockio.h> 43d3a0e4e9Skettenis #include <sys/timeout.h> 44d3a0e4e9Skettenis 45d3a0e4e9Skettenis #include <net/if.h> 46d3a0e4e9Skettenis #include <net/if_dl.h> 47d3a0e4e9Skettenis #include <net/if_media.h> 48d3a0e4e9Skettenis #include <net/bpf.h> 49d3a0e4e9Skettenis 50d3a0e4e9Skettenis #include <netinet/in.h> 51d3a0e4e9Skettenis #include <netinet/if_ether.h> 52d3a0e4e9Skettenis 53d3a0e4e9Skettenis #include <machine/bus.h> 54d3a0e4e9Skettenis #include <machine/intr.h> 55d3a0e4e9Skettenis 56d3a0e4e9Skettenis #include <dev/mii/miivar.h> 57d3a0e4e9Skettenis 58d3a0e4e9Skettenis #include <dev/ic/bcmgenetreg.h> 59d3a0e4e9Skettenis #include <dev/ic/bcmgenetvar.h> 60d3a0e4e9Skettenis 61d3a0e4e9Skettenis CTASSERT(MCLBYTES == 2048); 62d3a0e4e9Skettenis 63d3a0e4e9Skettenis #ifdef GENET_DEBUG 64d3a0e4e9Skettenis #define DPRINTF(...) printf(##__VA_ARGS__) 65d3a0e4e9Skettenis #else 66d3a0e4e9Skettenis #define DPRINTF(...) ((void)0) 67d3a0e4e9Skettenis #endif 68d3a0e4e9Skettenis 69d3a0e4e9Skettenis #define TX_SKIP(n, o) (((n) + (o)) & (GENET_DMA_DESC_COUNT - 1)) 70d3a0e4e9Skettenis #define TX_NEXT(n) TX_SKIP(n, 1) 71d3a0e4e9Skettenis #define RX_NEXT(n) (((n) + 1) & (GENET_DMA_DESC_COUNT - 1)) 72d3a0e4e9Skettenis 73d3a0e4e9Skettenis #define TX_MAX_SEGS 128 74d3a0e4e9Skettenis #define TX_DESC_COUNT GENET_DMA_DESC_COUNT 75d3a0e4e9Skettenis #define RX_DESC_COUNT GENET_DMA_DESC_COUNT 76d3a0e4e9Skettenis #define MII_BUSY_RETRY 1000 77d3a0e4e9Skettenis #define GENET_MAX_MDF_FILTER 17 78d3a0e4e9Skettenis 79d3a0e4e9Skettenis #define RD4(sc, reg) \ 80d3a0e4e9Skettenis bus_space_read_4((sc)->sc_bst, (sc)->sc_bsh, (reg)) 81d3a0e4e9Skettenis #define WR4(sc, reg, val) \ 82d3a0e4e9Skettenis bus_space_write_4((sc)->sc_bst, (sc)->sc_bsh, (reg), (val)) 83d3a0e4e9Skettenis 84d3a0e4e9Skettenis struct cfdriver bse_cd = { 85*3836e7c7Smiod NULL, "bse", DV_IFNET 86d3a0e4e9Skettenis }; 87d3a0e4e9Skettenis 88d3a0e4e9Skettenis int 89d3a0e4e9Skettenis genet_media_change(struct ifnet *ifp) 90d3a0e4e9Skettenis { 91d3a0e4e9Skettenis struct genet_softc *sc = ifp->if_softc; 92d3a0e4e9Skettenis 93d3a0e4e9Skettenis if (LIST_FIRST(&sc->sc_mii.mii_phys)) 94d3a0e4e9Skettenis mii_mediachg(&sc->sc_mii); 95d3a0e4e9Skettenis 96d3a0e4e9Skettenis return (0); 97d3a0e4e9Skettenis } 98d3a0e4e9Skettenis 99d3a0e4e9Skettenis void 100d3a0e4e9Skettenis genet_media_status(struct ifnet *ifp, struct ifmediareq *ifmr) 101d3a0e4e9Skettenis { 102d3a0e4e9Skettenis struct genet_softc *sc = ifp->if_softc; 103d3a0e4e9Skettenis 104d3a0e4e9Skettenis if (LIST_FIRST(&sc->sc_mii.mii_phys)) { 105d3a0e4e9Skettenis mii_pollstat(&sc->sc_mii); 106d3a0e4e9Skettenis ifmr->ifm_active = sc->sc_mii.mii_media_active; 107d3a0e4e9Skettenis ifmr->ifm_status = sc->sc_mii.mii_media_status; 108d3a0e4e9Skettenis } 109d3a0e4e9Skettenis } 110d3a0e4e9Skettenis 111d3a0e4e9Skettenis int 112d3a0e4e9Skettenis genet_mii_readreg(struct device *dev, int phy, int reg) 113d3a0e4e9Skettenis { 114d3a0e4e9Skettenis struct genet_softc *sc = (struct genet_softc *)dev; 115d3a0e4e9Skettenis int retry; 116d3a0e4e9Skettenis 117d3a0e4e9Skettenis WR4(sc, GENET_MDIO_CMD, 118d3a0e4e9Skettenis GENET_MDIO_READ | GENET_MDIO_START_BUSY | 119d3a0e4e9Skettenis __SHIFTIN(phy, GENET_MDIO_PMD) | 120d3a0e4e9Skettenis __SHIFTIN(reg, GENET_MDIO_REG)); 121d3a0e4e9Skettenis for (retry = MII_BUSY_RETRY; retry > 0; retry--) { 122d3a0e4e9Skettenis if ((RD4(sc, GENET_MDIO_CMD) & GENET_MDIO_START_BUSY) == 0) 123d3a0e4e9Skettenis return RD4(sc, GENET_MDIO_CMD) & 0xffff; 124d3a0e4e9Skettenis delay(10); 125d3a0e4e9Skettenis } 126d3a0e4e9Skettenis 127d3a0e4e9Skettenis printf("%s: phy read timeout, phy=%d reg=%d\n", 128d3a0e4e9Skettenis sc->sc_dev.dv_xname, phy, reg); 129d3a0e4e9Skettenis return 0; 130d3a0e4e9Skettenis } 131d3a0e4e9Skettenis 132d3a0e4e9Skettenis void 133d3a0e4e9Skettenis genet_mii_writereg(struct device *dev, int phy, int reg, int val) 134d3a0e4e9Skettenis { 135d3a0e4e9Skettenis struct genet_softc *sc = (struct genet_softc *)dev; 136d3a0e4e9Skettenis int retry; 137d3a0e4e9Skettenis 138d3a0e4e9Skettenis WR4(sc, GENET_MDIO_CMD, 139d3a0e4e9Skettenis val | GENET_MDIO_WRITE | GENET_MDIO_START_BUSY | 140d3a0e4e9Skettenis __SHIFTIN(phy, GENET_MDIO_PMD) | 141d3a0e4e9Skettenis __SHIFTIN(reg, GENET_MDIO_REG)); 142d3a0e4e9Skettenis for (retry = MII_BUSY_RETRY; retry > 0; retry--) { 143d3a0e4e9Skettenis if ((RD4(sc, GENET_MDIO_CMD) & GENET_MDIO_START_BUSY) == 0) 144d3a0e4e9Skettenis return; 145d3a0e4e9Skettenis delay(10); 146d3a0e4e9Skettenis } 147d3a0e4e9Skettenis 148d3a0e4e9Skettenis printf("%s: phy write timeout, phy=%d reg=%d\n", 149d3a0e4e9Skettenis sc->sc_dev.dv_xname, phy, reg); 150d3a0e4e9Skettenis } 151d3a0e4e9Skettenis 152d3a0e4e9Skettenis void 153d3a0e4e9Skettenis genet_update_link(struct genet_softc *sc) 154d3a0e4e9Skettenis { 155d3a0e4e9Skettenis struct mii_data *mii = &sc->sc_mii; 156d3a0e4e9Skettenis uint32_t val; 157d3a0e4e9Skettenis u_int speed; 158d3a0e4e9Skettenis 159d3a0e4e9Skettenis if (IFM_SUBTYPE(mii->mii_media_active) == IFM_1000_T || 160d3a0e4e9Skettenis IFM_SUBTYPE(mii->mii_media_active) == IFM_1000_SX) 161d3a0e4e9Skettenis speed = GENET_UMAC_CMD_SPEED_1000; 162d3a0e4e9Skettenis else if (IFM_SUBTYPE(mii->mii_media_active) == IFM_100_TX) 163d3a0e4e9Skettenis speed = GENET_UMAC_CMD_SPEED_100; 164d3a0e4e9Skettenis else 165d3a0e4e9Skettenis speed = GENET_UMAC_CMD_SPEED_10; 166d3a0e4e9Skettenis 167d3a0e4e9Skettenis val = RD4(sc, GENET_EXT_RGMII_OOB_CTRL); 168d3a0e4e9Skettenis val &= ~GENET_EXT_RGMII_OOB_OOB_DISABLE; 169d3a0e4e9Skettenis val |= GENET_EXT_RGMII_OOB_RGMII_LINK; 170d3a0e4e9Skettenis val |= GENET_EXT_RGMII_OOB_RGMII_MODE_EN; 171d3a0e4e9Skettenis if (sc->sc_phy_mode == GENET_PHY_MODE_RGMII) 172d3a0e4e9Skettenis val |= GENET_EXT_RGMII_OOB_ID_MODE_DISABLE; 173d3a0e4e9Skettenis else 174d3a0e4e9Skettenis val &= ~GENET_EXT_RGMII_OOB_ID_MODE_DISABLE; 175d3a0e4e9Skettenis WR4(sc, GENET_EXT_RGMII_OOB_CTRL, val); 176d3a0e4e9Skettenis 177d3a0e4e9Skettenis val = RD4(sc, GENET_UMAC_CMD); 178d3a0e4e9Skettenis val &= ~GENET_UMAC_CMD_SPEED; 179d3a0e4e9Skettenis val |= __SHIFTIN(speed, GENET_UMAC_CMD_SPEED); 180d3a0e4e9Skettenis WR4(sc, GENET_UMAC_CMD, val); 181d3a0e4e9Skettenis } 182d3a0e4e9Skettenis 183d3a0e4e9Skettenis void 184d3a0e4e9Skettenis genet_mii_statchg(struct device *self) 185d3a0e4e9Skettenis { 186d3a0e4e9Skettenis struct genet_softc *sc = (struct genet_softc *)self; 187d3a0e4e9Skettenis 188d3a0e4e9Skettenis genet_update_link(sc); 189d3a0e4e9Skettenis } 190d3a0e4e9Skettenis 191d3a0e4e9Skettenis void 192d3a0e4e9Skettenis genet_setup_txdesc(struct genet_softc *sc, int index, int flags, 193d3a0e4e9Skettenis bus_addr_t paddr, u_int len) 194d3a0e4e9Skettenis { 195d3a0e4e9Skettenis uint32_t status; 196d3a0e4e9Skettenis 197d3a0e4e9Skettenis status = flags | __SHIFTIN(len, GENET_TX_DESC_STATUS_BUFLEN); 198d3a0e4e9Skettenis ++sc->sc_tx.queued; 199d3a0e4e9Skettenis 200d3a0e4e9Skettenis WR4(sc, GENET_TX_DESC_ADDRESS_LO(index), (uint32_t)paddr); 201d3a0e4e9Skettenis WR4(sc, GENET_TX_DESC_ADDRESS_HI(index), (uint32_t)(paddr >> 32)); 202d3a0e4e9Skettenis WR4(sc, GENET_TX_DESC_STATUS(index), status); 203d3a0e4e9Skettenis } 204d3a0e4e9Skettenis 205d3a0e4e9Skettenis int 206d3a0e4e9Skettenis genet_setup_txbuf(struct genet_softc *sc, int index, struct mbuf *m) 207d3a0e4e9Skettenis { 208d3a0e4e9Skettenis bus_dma_segment_t *segs; 209d3a0e4e9Skettenis int error, nsegs, cur, i; 210d3a0e4e9Skettenis uint32_t flags; 211d3a0e4e9Skettenis 212d3a0e4e9Skettenis /* 213d3a0e4e9Skettenis * XXX Hardware doesn't seem to like small fragments. For now 214d3a0e4e9Skettenis * just look at the first fragment and defrag if it is smaller 215d3a0e4e9Skettenis * than the minimum Ethernet packet size. 216d3a0e4e9Skettenis */ 217d3a0e4e9Skettenis if (m->m_len < ETHER_MIN_LEN - ETHER_CRC_LEN) { 218d3a0e4e9Skettenis if (m_defrag(m, M_DONTWAIT)) 219d3a0e4e9Skettenis return 0; 220d3a0e4e9Skettenis } 221d3a0e4e9Skettenis 222d3a0e4e9Skettenis error = bus_dmamap_load_mbuf(sc->sc_tx.buf_tag, 223d3a0e4e9Skettenis sc->sc_tx.buf_map[index].map, m, BUS_DMA_WRITE | BUS_DMA_NOWAIT); 224d3a0e4e9Skettenis if (error == EFBIG) { 225d3a0e4e9Skettenis if (m_defrag(m, M_DONTWAIT)) 226d3a0e4e9Skettenis return 0; 227d3a0e4e9Skettenis error = bus_dmamap_load_mbuf(sc->sc_tx.buf_tag, 228d3a0e4e9Skettenis sc->sc_tx.buf_map[index].map, m, 229d3a0e4e9Skettenis BUS_DMA_WRITE | BUS_DMA_NOWAIT); 230d3a0e4e9Skettenis } 231d3a0e4e9Skettenis if (error != 0) 232d3a0e4e9Skettenis return 0; 233d3a0e4e9Skettenis 234d3a0e4e9Skettenis segs = sc->sc_tx.buf_map[index].map->dm_segs; 235d3a0e4e9Skettenis nsegs = sc->sc_tx.buf_map[index].map->dm_nsegs; 236d3a0e4e9Skettenis 237d3a0e4e9Skettenis if (sc->sc_tx.queued >= GENET_DMA_DESC_COUNT - nsegs) { 238d3a0e4e9Skettenis bus_dmamap_unload(sc->sc_tx.buf_tag, 239d3a0e4e9Skettenis sc->sc_tx.buf_map[index].map); 240d3a0e4e9Skettenis return -1; 241d3a0e4e9Skettenis } 242d3a0e4e9Skettenis 243d3a0e4e9Skettenis flags = GENET_TX_DESC_STATUS_SOP | 244d3a0e4e9Skettenis GENET_TX_DESC_STATUS_CRC | 245d3a0e4e9Skettenis GENET_TX_DESC_STATUS_QTAG; 246d3a0e4e9Skettenis 247d3a0e4e9Skettenis for (cur = index, i = 0; i < nsegs; i++) { 248d3a0e4e9Skettenis sc->sc_tx.buf_map[cur].mbuf = (i == 0 ? m : NULL); 249d3a0e4e9Skettenis if (i == nsegs - 1) 250d3a0e4e9Skettenis flags |= GENET_TX_DESC_STATUS_EOP; 251d3a0e4e9Skettenis 252d3a0e4e9Skettenis genet_setup_txdesc(sc, cur, flags, segs[i].ds_addr, 253d3a0e4e9Skettenis segs[i].ds_len); 254d3a0e4e9Skettenis 255d3a0e4e9Skettenis if (i == 0) { 256d3a0e4e9Skettenis flags &= ~GENET_TX_DESC_STATUS_SOP; 257d3a0e4e9Skettenis flags &= ~GENET_TX_DESC_STATUS_CRC; 258d3a0e4e9Skettenis } 259d3a0e4e9Skettenis cur = TX_NEXT(cur); 260d3a0e4e9Skettenis } 261d3a0e4e9Skettenis 262d3a0e4e9Skettenis bus_dmamap_sync(sc->sc_tx.buf_tag, sc->sc_tx.buf_map[index].map, 263d3a0e4e9Skettenis 0, sc->sc_tx.buf_map[index].map->dm_mapsize, BUS_DMASYNC_PREWRITE); 264d3a0e4e9Skettenis 265d3a0e4e9Skettenis return nsegs; 266d3a0e4e9Skettenis } 267d3a0e4e9Skettenis 268d3a0e4e9Skettenis void 269d3a0e4e9Skettenis genet_setup_rxdesc(struct genet_softc *sc, int index, 270d3a0e4e9Skettenis bus_addr_t paddr, bus_size_t len) 271d3a0e4e9Skettenis { 272d3a0e4e9Skettenis WR4(sc, GENET_RX_DESC_ADDRESS_LO(index), (uint32_t)paddr); 273d3a0e4e9Skettenis WR4(sc, GENET_RX_DESC_ADDRESS_HI(index), (uint32_t)(paddr >> 32)); 274d3a0e4e9Skettenis } 275d3a0e4e9Skettenis 276d3a0e4e9Skettenis int 277d3a0e4e9Skettenis genet_setup_rxbuf(struct genet_softc *sc, int index, struct mbuf *m) 278d3a0e4e9Skettenis { 279d3a0e4e9Skettenis int error; 280d3a0e4e9Skettenis 281d3a0e4e9Skettenis error = bus_dmamap_load_mbuf(sc->sc_rx.buf_tag, 282d3a0e4e9Skettenis sc->sc_rx.buf_map[index].map, m, BUS_DMA_READ | BUS_DMA_NOWAIT); 283d3a0e4e9Skettenis if (error != 0) 284d3a0e4e9Skettenis return error; 285d3a0e4e9Skettenis 286d3a0e4e9Skettenis bus_dmamap_sync(sc->sc_rx.buf_tag, sc->sc_rx.buf_map[index].map, 287d3a0e4e9Skettenis 0, sc->sc_rx.buf_map[index].map->dm_mapsize, 288d3a0e4e9Skettenis BUS_DMASYNC_PREREAD); 289d3a0e4e9Skettenis 290d3a0e4e9Skettenis sc->sc_rx.buf_map[index].mbuf = m; 291d3a0e4e9Skettenis genet_setup_rxdesc(sc, index, 292d3a0e4e9Skettenis sc->sc_rx.buf_map[index].map->dm_segs[0].ds_addr, 293d3a0e4e9Skettenis sc->sc_rx.buf_map[index].map->dm_segs[0].ds_len); 294d3a0e4e9Skettenis 295d3a0e4e9Skettenis return 0; 296d3a0e4e9Skettenis } 297d3a0e4e9Skettenis 298d3a0e4e9Skettenis struct mbuf * 299d3a0e4e9Skettenis genet_alloc_mbufcl(struct genet_softc *sc) 300d3a0e4e9Skettenis { 301d3a0e4e9Skettenis struct mbuf *m; 302d3a0e4e9Skettenis 303471f2571Sjan m = MCLGETL(NULL, M_DONTWAIT, MCLBYTES); 304d3a0e4e9Skettenis if (m != NULL) 305d3a0e4e9Skettenis m->m_pkthdr.len = m->m_len = m->m_ext.ext_size; 306d3a0e4e9Skettenis 307d3a0e4e9Skettenis return m; 308d3a0e4e9Skettenis } 309d3a0e4e9Skettenis 310d3a0e4e9Skettenis void 311d3a0e4e9Skettenis genet_fill_rx_ring(struct genet_softc *sc, int qid) 312d3a0e4e9Skettenis { 313d3a0e4e9Skettenis struct mbuf *m; 314d3a0e4e9Skettenis uint32_t cidx, index, total; 315d3a0e4e9Skettenis u_int slots; 316d3a0e4e9Skettenis int error; 317d3a0e4e9Skettenis 318d3a0e4e9Skettenis cidx = sc->sc_rx.cidx; 319d3a0e4e9Skettenis total = (sc->sc_rx.pidx - cidx) & 0xffff; 320d3a0e4e9Skettenis KASSERT(total <= RX_DESC_COUNT); 321d3a0e4e9Skettenis 322d3a0e4e9Skettenis index = sc->sc_rx.cidx & (RX_DESC_COUNT - 1); 323d3a0e4e9Skettenis for (slots = if_rxr_get(&sc->sc_rx_ring, total); 324d3a0e4e9Skettenis slots > 0; slots--) { 325d3a0e4e9Skettenis if ((m = genet_alloc_mbufcl(sc)) == NULL) { 326d3a0e4e9Skettenis printf("%s: cannot allocate RX mbuf\n", 327d3a0e4e9Skettenis sc->sc_dev.dv_xname); 328d3a0e4e9Skettenis break; 329d3a0e4e9Skettenis } 330d3a0e4e9Skettenis error = genet_setup_rxbuf(sc, index, m); 331d3a0e4e9Skettenis if (error != 0) { 332d3a0e4e9Skettenis printf("%s: cannot create RX buffer\n", 333d3a0e4e9Skettenis sc->sc_dev.dv_xname); 334d3a0e4e9Skettenis m_freem(m); 335d3a0e4e9Skettenis break; 336d3a0e4e9Skettenis } 337d3a0e4e9Skettenis 338d3a0e4e9Skettenis cidx = (cidx + 1) & 0xffff; 339d3a0e4e9Skettenis index = RX_NEXT(index); 340d3a0e4e9Skettenis } 341d3a0e4e9Skettenis if_rxr_put(&sc->sc_rx_ring, slots); 342d3a0e4e9Skettenis 343d3a0e4e9Skettenis if (sc->sc_rx.cidx != cidx) { 344d3a0e4e9Skettenis sc->sc_rx.cidx = cidx; 345d3a0e4e9Skettenis WR4(sc, GENET_RX_DMA_CONS_INDEX(qid), sc->sc_rx.cidx); 346d3a0e4e9Skettenis } 347d3a0e4e9Skettenis 348d3a0e4e9Skettenis if (if_rxr_inuse(&sc->sc_rx_ring) == 0) 349d3a0e4e9Skettenis timeout_add(&sc->sc_rxto, 1); 350d3a0e4e9Skettenis } 351d3a0e4e9Skettenis 352d3a0e4e9Skettenis void 353d3a0e4e9Skettenis genet_rxtick(void *arg) 354d3a0e4e9Skettenis { 355d3a0e4e9Skettenis genet_fill_rx_ring(arg, GENET_DMA_DEFAULT_QUEUE); 356d3a0e4e9Skettenis } 357d3a0e4e9Skettenis 358d3a0e4e9Skettenis void 359d3a0e4e9Skettenis genet_enable_intr(struct genet_softc *sc) 360d3a0e4e9Skettenis { 361d3a0e4e9Skettenis WR4(sc, GENET_INTRL2_CPU_CLEAR_MASK, 362d3a0e4e9Skettenis GENET_IRQ_TXDMA_DONE | GENET_IRQ_RXDMA_DONE); 363d3a0e4e9Skettenis } 364d3a0e4e9Skettenis 365d3a0e4e9Skettenis void 366d3a0e4e9Skettenis genet_disable_intr(struct genet_softc *sc) 367d3a0e4e9Skettenis { 368d3a0e4e9Skettenis /* Disable interrupts */ 369d3a0e4e9Skettenis WR4(sc, GENET_INTRL2_CPU_SET_MASK, 0xffffffff); 370d3a0e4e9Skettenis WR4(sc, GENET_INTRL2_CPU_CLEAR, 0xffffffff); 371d3a0e4e9Skettenis } 372d3a0e4e9Skettenis 373d3a0e4e9Skettenis void 374d3a0e4e9Skettenis genet_tick(void *softc) 375d3a0e4e9Skettenis { 376d3a0e4e9Skettenis struct genet_softc *sc = softc; 377d3a0e4e9Skettenis struct mii_data *mii = &sc->sc_mii; 378d3a0e4e9Skettenis int s = splnet(); 379d3a0e4e9Skettenis 380d3a0e4e9Skettenis mii_tick(mii); 381d3a0e4e9Skettenis timeout_add_sec(&sc->sc_stat_ch, 1); 382d3a0e4e9Skettenis 383d3a0e4e9Skettenis splx(s); 384d3a0e4e9Skettenis } 385d3a0e4e9Skettenis 386d3a0e4e9Skettenis void 387d3a0e4e9Skettenis genet_setup_rxfilter_mdf(struct genet_softc *sc, u_int n, const uint8_t *ea) 388d3a0e4e9Skettenis { 389d3a0e4e9Skettenis uint32_t addr0 = (ea[0] << 8) | ea[1]; 390d3a0e4e9Skettenis uint32_t addr1 = (ea[2] << 24) | (ea[3] << 16) | (ea[4] << 8) | ea[5]; 391d3a0e4e9Skettenis 392d3a0e4e9Skettenis WR4(sc, GENET_UMAC_MDF_ADDR0(n), addr0); 393d3a0e4e9Skettenis WR4(sc, GENET_UMAC_MDF_ADDR1(n), addr1); 394d3a0e4e9Skettenis } 395d3a0e4e9Skettenis 396d3a0e4e9Skettenis void 397d3a0e4e9Skettenis genet_setup_rxfilter(struct genet_softc *sc) 398d3a0e4e9Skettenis { 399d3a0e4e9Skettenis struct arpcom *ac = &sc->sc_ac; 400d3a0e4e9Skettenis struct ifnet *ifp = &ac->ac_if; 401d3a0e4e9Skettenis struct ether_multistep step; 402d3a0e4e9Skettenis struct ether_multi *enm; 403d3a0e4e9Skettenis uint32_t cmd, mdf_ctrl; 404d3a0e4e9Skettenis u_int n; 405d3a0e4e9Skettenis 406d3a0e4e9Skettenis cmd = RD4(sc, GENET_UMAC_CMD); 407d3a0e4e9Skettenis 408d3a0e4e9Skettenis /* 409d3a0e4e9Skettenis * Count the required number of hardware filters. We need one 410d3a0e4e9Skettenis * for each multicast address, plus one for our own address and 411d3a0e4e9Skettenis * the broadcast address. 412d3a0e4e9Skettenis */ 413d3a0e4e9Skettenis ETHER_FIRST_MULTI(step, ac, enm); 414d3a0e4e9Skettenis for (n = 2; enm != NULL; n++) 415d3a0e4e9Skettenis ETHER_NEXT_MULTI(step, enm); 416d3a0e4e9Skettenis 417d3a0e4e9Skettenis if (n > GENET_MAX_MDF_FILTER || ac->ac_multirangecnt > 0) 418d3a0e4e9Skettenis ifp->if_flags |= IFF_ALLMULTI; 419d3a0e4e9Skettenis else 420d3a0e4e9Skettenis ifp->if_flags &= ~IFF_ALLMULTI; 421d3a0e4e9Skettenis 422d3a0e4e9Skettenis if ((ifp->if_flags & (IFF_PROMISC|IFF_ALLMULTI)) != 0) { 423d3a0e4e9Skettenis cmd |= GENET_UMAC_CMD_PROMISC; 424d3a0e4e9Skettenis mdf_ctrl = 0; 425d3a0e4e9Skettenis } else { 426d3a0e4e9Skettenis cmd &= ~GENET_UMAC_CMD_PROMISC; 427d3a0e4e9Skettenis genet_setup_rxfilter_mdf(sc, 0, etherbroadcastaddr); 428d3a0e4e9Skettenis genet_setup_rxfilter_mdf(sc, 1, LLADDR(ifp->if_sadl)); 429d3a0e4e9Skettenis ETHER_FIRST_MULTI(step, ac, enm); 430d3a0e4e9Skettenis for (n = 2; enm != NULL; n++) { 431d3a0e4e9Skettenis genet_setup_rxfilter_mdf(sc, n, enm->enm_addrlo); 432d3a0e4e9Skettenis ETHER_NEXT_MULTI(step, enm); 433d3a0e4e9Skettenis } 434d3a0e4e9Skettenis mdf_ctrl = __BITS(GENET_MAX_MDF_FILTER - 1, 435d3a0e4e9Skettenis GENET_MAX_MDF_FILTER - n); 436d3a0e4e9Skettenis } 437d3a0e4e9Skettenis 438d3a0e4e9Skettenis WR4(sc, GENET_UMAC_CMD, cmd); 439d3a0e4e9Skettenis WR4(sc, GENET_UMAC_MDF_CTRL, mdf_ctrl); 440d3a0e4e9Skettenis } 441d3a0e4e9Skettenis 442d24dc994Santon void 443d24dc994Santon genet_disable_dma(struct genet_softc *sc) 444d24dc994Santon { 445d24dc994Santon uint32_t val; 446d24dc994Santon 447d24dc994Santon /* Disable receiver */ 448d24dc994Santon val = RD4(sc, GENET_UMAC_CMD); 449d24dc994Santon val &= ~GENET_UMAC_CMD_RXEN; 450d24dc994Santon WR4(sc, GENET_UMAC_CMD, val); 451d24dc994Santon 452d24dc994Santon /* Stop receive DMA */ 453d24dc994Santon val = RD4(sc, GENET_RX_DMA_CTRL); 454d24dc994Santon val &= ~GENET_RX_DMA_CTRL_EN; 455d24dc994Santon val &= ~GENET_RX_DMA_CTRL_RBUF_EN(GENET_DMA_DEFAULT_QUEUE); 456d24dc994Santon WR4(sc, GENET_RX_DMA_CTRL, val); 457d24dc994Santon 458d24dc994Santon /* Stop transmit DMA */ 459d24dc994Santon val = RD4(sc, GENET_TX_DMA_CTRL); 460d24dc994Santon val &= ~GENET_TX_DMA_CTRL_EN; 461d24dc994Santon val &= ~GENET_TX_DMA_CTRL_RBUF_EN(GENET_DMA_DEFAULT_QUEUE); 462d24dc994Santon WR4(sc, GENET_TX_DMA_CTRL, val); 463d24dc994Santon 464d24dc994Santon /* Flush data in the TX FIFO */ 465d24dc994Santon WR4(sc, GENET_UMAC_TX_FLUSH, 1); 466d24dc994Santon delay(10); 467d24dc994Santon WR4(sc, GENET_UMAC_TX_FLUSH, 0); 468d24dc994Santon 469d24dc994Santon /* Disable transmitter */ 470d24dc994Santon val = RD4(sc, GENET_UMAC_CMD); 471d24dc994Santon val &= ~GENET_UMAC_CMD_TXEN; 472d24dc994Santon WR4(sc, GENET_UMAC_CMD, val); 473d24dc994Santon } 474d24dc994Santon 475d3a0e4e9Skettenis int 476d3a0e4e9Skettenis genet_reset(struct genet_softc *sc) 477d3a0e4e9Skettenis { 478d3a0e4e9Skettenis uint32_t val; 479d3a0e4e9Skettenis 480d24dc994Santon genet_disable_dma(sc); 481d24dc994Santon 482d3a0e4e9Skettenis val = RD4(sc, GENET_SYS_RBUF_FLUSH_CTRL); 483d3a0e4e9Skettenis val |= GENET_SYS_RBUF_FLUSH_RESET; 484d3a0e4e9Skettenis WR4(sc, GENET_SYS_RBUF_FLUSH_CTRL, val); 485d3a0e4e9Skettenis delay(10); 486d3a0e4e9Skettenis 487d3a0e4e9Skettenis val &= ~GENET_SYS_RBUF_FLUSH_RESET; 488d3a0e4e9Skettenis WR4(sc, GENET_SYS_RBUF_FLUSH_CTRL, val); 489d3a0e4e9Skettenis delay(10); 490d3a0e4e9Skettenis 491d3a0e4e9Skettenis WR4(sc, GENET_SYS_RBUF_FLUSH_CTRL, 0); 492d3a0e4e9Skettenis delay(10); 493d3a0e4e9Skettenis 494d3a0e4e9Skettenis WR4(sc, GENET_UMAC_CMD, 0); 495d3a0e4e9Skettenis WR4(sc, GENET_UMAC_CMD, 496d3a0e4e9Skettenis GENET_UMAC_CMD_LCL_LOOP_EN | GENET_UMAC_CMD_SW_RESET); 497d3a0e4e9Skettenis delay(10); 498d3a0e4e9Skettenis WR4(sc, GENET_UMAC_CMD, 0); 499d3a0e4e9Skettenis 500d3a0e4e9Skettenis WR4(sc, GENET_UMAC_MIB_CTRL, GENET_UMAC_MIB_RESET_RUNT | 501d3a0e4e9Skettenis GENET_UMAC_MIB_RESET_RX | GENET_UMAC_MIB_RESET_TX); 502d3a0e4e9Skettenis WR4(sc, GENET_UMAC_MIB_CTRL, 0); 503d3a0e4e9Skettenis 504d3a0e4e9Skettenis WR4(sc, GENET_UMAC_MAX_FRAME_LEN, 1536); 505d3a0e4e9Skettenis 506d3a0e4e9Skettenis val = RD4(sc, GENET_RBUF_CTRL); 507d3a0e4e9Skettenis val |= GENET_RBUF_ALIGN_2B; 508d3a0e4e9Skettenis WR4(sc, GENET_RBUF_CTRL, val); 509d3a0e4e9Skettenis 510d3a0e4e9Skettenis WR4(sc, GENET_RBUF_TBUF_SIZE_CTRL, 1); 511d3a0e4e9Skettenis 512d3a0e4e9Skettenis return 0; 513d3a0e4e9Skettenis } 514d3a0e4e9Skettenis 515d3a0e4e9Skettenis void 516d3a0e4e9Skettenis genet_init_rings(struct genet_softc *sc, int qid) 517d3a0e4e9Skettenis { 518d3a0e4e9Skettenis uint32_t val; 519d3a0e4e9Skettenis 520d3a0e4e9Skettenis /* TX ring */ 521d3a0e4e9Skettenis 522d3a0e4e9Skettenis sc->sc_tx.next = 0; 523d3a0e4e9Skettenis sc->sc_tx.queued = 0; 524d3a0e4e9Skettenis sc->sc_tx.cidx = sc->sc_tx.pidx = 0; 525d3a0e4e9Skettenis 526d3a0e4e9Skettenis WR4(sc, GENET_TX_SCB_BURST_SIZE, 0x08); 527d3a0e4e9Skettenis 528d3a0e4e9Skettenis WR4(sc, GENET_TX_DMA_READ_PTR_LO(qid), 0); 529d3a0e4e9Skettenis WR4(sc, GENET_TX_DMA_READ_PTR_HI(qid), 0); 530d3a0e4e9Skettenis WR4(sc, GENET_TX_DMA_CONS_INDEX(qid), sc->sc_tx.cidx); 531d3a0e4e9Skettenis WR4(sc, GENET_TX_DMA_PROD_INDEX(qid), sc->sc_tx.pidx); 532d3a0e4e9Skettenis WR4(sc, GENET_TX_DMA_RING_BUF_SIZE(qid), 533d3a0e4e9Skettenis __SHIFTIN(TX_DESC_COUNT, GENET_TX_DMA_RING_BUF_SIZE_DESC_COUNT) | 534d3a0e4e9Skettenis __SHIFTIN(MCLBYTES, GENET_TX_DMA_RING_BUF_SIZE_BUF_LENGTH)); 535d3a0e4e9Skettenis WR4(sc, GENET_TX_DMA_START_ADDR_LO(qid), 0); 536d3a0e4e9Skettenis WR4(sc, GENET_TX_DMA_START_ADDR_HI(qid), 0); 537d3a0e4e9Skettenis WR4(sc, GENET_TX_DMA_END_ADDR_LO(qid), 538d3a0e4e9Skettenis TX_DESC_COUNT * GENET_DMA_DESC_SIZE / 4 - 1); 539d3a0e4e9Skettenis WR4(sc, GENET_TX_DMA_END_ADDR_HI(qid), 0); 540d3a0e4e9Skettenis WR4(sc, GENET_TX_DMA_MBUF_DONE_THRES(qid), 1); 541d3a0e4e9Skettenis WR4(sc, GENET_TX_DMA_FLOW_PERIOD(qid), 0); 542d3a0e4e9Skettenis WR4(sc, GENET_TX_DMA_WRITE_PTR_LO(qid), 0); 543d3a0e4e9Skettenis WR4(sc, GENET_TX_DMA_WRITE_PTR_HI(qid), 0); 544d3a0e4e9Skettenis 545d3a0e4e9Skettenis WR4(sc, GENET_TX_DMA_RING_CFG, __BIT(qid)); /* enable */ 546d3a0e4e9Skettenis 547d3a0e4e9Skettenis /* Enable transmit DMA */ 548d3a0e4e9Skettenis val = RD4(sc, GENET_TX_DMA_CTRL); 549d3a0e4e9Skettenis val |= GENET_TX_DMA_CTRL_EN; 5501da4269eSanton val |= GENET_TX_DMA_CTRL_RBUF_EN(qid); 551d3a0e4e9Skettenis WR4(sc, GENET_TX_DMA_CTRL, val); 552d3a0e4e9Skettenis 553d3a0e4e9Skettenis /* RX ring */ 554d3a0e4e9Skettenis 555d3a0e4e9Skettenis sc->sc_rx.next = 0; 556d3a0e4e9Skettenis sc->sc_rx.cidx = 0; 557d3a0e4e9Skettenis sc->sc_rx.pidx = RX_DESC_COUNT; 558d3a0e4e9Skettenis 559d3a0e4e9Skettenis WR4(sc, GENET_RX_SCB_BURST_SIZE, 0x08); 560d3a0e4e9Skettenis 561d3a0e4e9Skettenis WR4(sc, GENET_RX_DMA_WRITE_PTR_LO(qid), 0); 562d3a0e4e9Skettenis WR4(sc, GENET_RX_DMA_WRITE_PTR_HI(qid), 0); 563d3a0e4e9Skettenis WR4(sc, GENET_RX_DMA_PROD_INDEX(qid), sc->sc_rx.pidx); 564d3a0e4e9Skettenis WR4(sc, GENET_RX_DMA_CONS_INDEX(qid), sc->sc_rx.cidx); 565d3a0e4e9Skettenis WR4(sc, GENET_RX_DMA_RING_BUF_SIZE(qid), 566d3a0e4e9Skettenis __SHIFTIN(RX_DESC_COUNT, GENET_RX_DMA_RING_BUF_SIZE_DESC_COUNT) | 567d3a0e4e9Skettenis __SHIFTIN(MCLBYTES, GENET_RX_DMA_RING_BUF_SIZE_BUF_LENGTH)); 568d3a0e4e9Skettenis WR4(sc, GENET_RX_DMA_START_ADDR_LO(qid), 0); 569d3a0e4e9Skettenis WR4(sc, GENET_RX_DMA_START_ADDR_HI(qid), 0); 570d3a0e4e9Skettenis WR4(sc, GENET_RX_DMA_END_ADDR_LO(qid), 571d3a0e4e9Skettenis RX_DESC_COUNT * GENET_DMA_DESC_SIZE / 4 - 1); 572d3a0e4e9Skettenis WR4(sc, GENET_RX_DMA_END_ADDR_HI(qid), 0); 573d3a0e4e9Skettenis WR4(sc, GENET_RX_DMA_XON_XOFF_THRES(qid), 574d3a0e4e9Skettenis __SHIFTIN(5, GENET_RX_DMA_XON_XOFF_THRES_LO) | 575d3a0e4e9Skettenis __SHIFTIN(RX_DESC_COUNT >> 4, GENET_RX_DMA_XON_XOFF_THRES_HI)); 576d3a0e4e9Skettenis WR4(sc, GENET_RX_DMA_READ_PTR_LO(qid), 0); 577d3a0e4e9Skettenis WR4(sc, GENET_RX_DMA_READ_PTR_HI(qid), 0); 578d3a0e4e9Skettenis 579d3a0e4e9Skettenis WR4(sc, GENET_RX_DMA_RING_CFG, __BIT(qid)); /* enable */ 580d3a0e4e9Skettenis 581d3a0e4e9Skettenis if_rxr_init(&sc->sc_rx_ring, 2, RX_DESC_COUNT); 582d3a0e4e9Skettenis genet_fill_rx_ring(sc, qid); 583d3a0e4e9Skettenis 584d3a0e4e9Skettenis /* Enable receive DMA */ 585d3a0e4e9Skettenis val = RD4(sc, GENET_RX_DMA_CTRL); 586d3a0e4e9Skettenis val |= GENET_RX_DMA_CTRL_EN; 5871da4269eSanton val |= GENET_RX_DMA_CTRL_RBUF_EN(qid); 588d3a0e4e9Skettenis WR4(sc, GENET_RX_DMA_CTRL, val); 589d3a0e4e9Skettenis } 590d3a0e4e9Skettenis 591d3a0e4e9Skettenis int 592d3a0e4e9Skettenis genet_init(struct genet_softc *sc) 593d3a0e4e9Skettenis { 594d3a0e4e9Skettenis struct ifnet *ifp = &sc->sc_ac.ac_if; 595d3a0e4e9Skettenis struct mii_data *mii = &sc->sc_mii; 596d3a0e4e9Skettenis uint32_t val; 597d3a0e4e9Skettenis uint8_t *enaddr = LLADDR(ifp->if_sadl); 598d3a0e4e9Skettenis 599d3a0e4e9Skettenis if (ifp->if_flags & IFF_RUNNING) 600d3a0e4e9Skettenis return 0; 601d3a0e4e9Skettenis 602d3a0e4e9Skettenis if (sc->sc_phy_mode == GENET_PHY_MODE_RGMII || 603d3a0e4e9Skettenis sc->sc_phy_mode == GENET_PHY_MODE_RGMII_ID || 604d3a0e4e9Skettenis sc->sc_phy_mode == GENET_PHY_MODE_RGMII_RXID || 605d3a0e4e9Skettenis sc->sc_phy_mode == GENET_PHY_MODE_RGMII_TXID) 606d3a0e4e9Skettenis WR4(sc, GENET_SYS_PORT_CTRL, 607d3a0e4e9Skettenis GENET_SYS_PORT_MODE_EXT_GPHY); 608d3a0e4e9Skettenis 609d3a0e4e9Skettenis /* Write hardware address */ 610d3a0e4e9Skettenis val = enaddr[3] | (enaddr[2] << 8) | (enaddr[1] << 16) | 611d3a0e4e9Skettenis (enaddr[0] << 24); 612d3a0e4e9Skettenis WR4(sc, GENET_UMAC_MAC0, val); 613d3a0e4e9Skettenis val = enaddr[5] | (enaddr[4] << 8); 614d3a0e4e9Skettenis WR4(sc, GENET_UMAC_MAC1, val); 615d3a0e4e9Skettenis 616d3a0e4e9Skettenis /* Setup RX filter */ 617d3a0e4e9Skettenis genet_setup_rxfilter(sc); 618d3a0e4e9Skettenis 619d3a0e4e9Skettenis /* Setup TX/RX rings */ 620d3a0e4e9Skettenis genet_init_rings(sc, GENET_DMA_DEFAULT_QUEUE); 621d3a0e4e9Skettenis 622d3a0e4e9Skettenis /* Enable transmitter and receiver */ 623d3a0e4e9Skettenis val = RD4(sc, GENET_UMAC_CMD); 624d3a0e4e9Skettenis val |= GENET_UMAC_CMD_TXEN; 625d3a0e4e9Skettenis val |= GENET_UMAC_CMD_RXEN; 626d3a0e4e9Skettenis WR4(sc, GENET_UMAC_CMD, val); 627d3a0e4e9Skettenis 628d3a0e4e9Skettenis /* Enable interrupts */ 629d3a0e4e9Skettenis genet_enable_intr(sc); 630d3a0e4e9Skettenis 631d3a0e4e9Skettenis ifp->if_flags |= IFF_RUNNING; 632d3a0e4e9Skettenis ifq_clr_oactive(&ifp->if_snd); 633d3a0e4e9Skettenis 634d3a0e4e9Skettenis mii_mediachg(mii); 635d3a0e4e9Skettenis timeout_add_sec(&sc->sc_stat_ch, 1); 636d3a0e4e9Skettenis 637d3a0e4e9Skettenis return 0; 638d3a0e4e9Skettenis } 639d3a0e4e9Skettenis 640d3a0e4e9Skettenis void 641d3a0e4e9Skettenis genet_stop(struct genet_softc *sc) 642d3a0e4e9Skettenis { 643d3a0e4e9Skettenis struct ifnet *ifp = &sc->sc_ac.ac_if; 644d3a0e4e9Skettenis struct genet_bufmap *bmap; 645d3a0e4e9Skettenis int i; 646d3a0e4e9Skettenis 647d3a0e4e9Skettenis timeout_del(&sc->sc_rxto); 648d3a0e4e9Skettenis timeout_del(&sc->sc_stat_ch); 649d3a0e4e9Skettenis 650d3a0e4e9Skettenis mii_down(&sc->sc_mii); 651d3a0e4e9Skettenis 652d24dc994Santon genet_disable_dma(sc); 653d3a0e4e9Skettenis 654d3a0e4e9Skettenis /* Disable interrupts */ 655d3a0e4e9Skettenis genet_disable_intr(sc); 656d3a0e4e9Skettenis 657d3a0e4e9Skettenis ifp->if_flags &= ~IFF_RUNNING; 658d3a0e4e9Skettenis ifq_clr_oactive(&ifp->if_snd); 659d3a0e4e9Skettenis ifp->if_timer = 0; 660d3a0e4e9Skettenis 661d3a0e4e9Skettenis intr_barrier(sc->sc_ih); 662d3a0e4e9Skettenis 663d3a0e4e9Skettenis /* Clean RX ring. */ 664d3a0e4e9Skettenis for (i = 0; i < RX_DESC_COUNT; i++) { 665d3a0e4e9Skettenis bmap = &sc->sc_rx.buf_map[i]; 666d3a0e4e9Skettenis if (bmap->mbuf) { 667d3a0e4e9Skettenis bus_dmamap_sync(sc->sc_dmat, bmap->map, 0, 668d3a0e4e9Skettenis bmap->map->dm_mapsize, BUS_DMASYNC_POSTREAD); 669d3a0e4e9Skettenis bus_dmamap_unload(sc->sc_dmat, bmap->map); 670d3a0e4e9Skettenis m_freem(bmap->mbuf); 671d3a0e4e9Skettenis bmap->mbuf = NULL; 672d3a0e4e9Skettenis } 673d3a0e4e9Skettenis } 674d3a0e4e9Skettenis 675d3a0e4e9Skettenis /* Clean TX ring. */ 676d3a0e4e9Skettenis for (i = 0; i < TX_DESC_COUNT; i++) { 677d3a0e4e9Skettenis bmap = &sc->sc_tx.buf_map[i]; 678d3a0e4e9Skettenis if (bmap->mbuf) { 679d3a0e4e9Skettenis bus_dmamap_sync(sc->sc_dmat, bmap->map, 0, 680d3a0e4e9Skettenis bmap->map->dm_mapsize, BUS_DMASYNC_POSTWRITE); 681d3a0e4e9Skettenis bus_dmamap_unload(sc->sc_dmat, bmap->map); 682d3a0e4e9Skettenis m_freem(bmap->mbuf); 683d3a0e4e9Skettenis bmap->mbuf = NULL; 684d3a0e4e9Skettenis } 685d3a0e4e9Skettenis } 686d3a0e4e9Skettenis } 687d3a0e4e9Skettenis 688d3a0e4e9Skettenis void 689d3a0e4e9Skettenis genet_rxintr(struct genet_softc *sc, int qid) 690d3a0e4e9Skettenis { 691d3a0e4e9Skettenis struct ifnet *ifp = &sc->sc_ac.ac_if; 692d3a0e4e9Skettenis struct mbuf_list ml = MBUF_LIST_INITIALIZER(); 693d3a0e4e9Skettenis struct mbuf *m; 694d3a0e4e9Skettenis int index, len, n; 695d3a0e4e9Skettenis uint32_t status, pidx, total; 696d3a0e4e9Skettenis 697d3a0e4e9Skettenis pidx = RD4(sc, GENET_RX_DMA_PROD_INDEX(qid)) & 0xffff; 698d3a0e4e9Skettenis total = (pidx - sc->sc_rx.pidx) & 0xffff; 699d3a0e4e9Skettenis 700d3a0e4e9Skettenis DPRINTF("RX pidx=%08x total=%d\n", pidx, total); 701d3a0e4e9Skettenis 702d3a0e4e9Skettenis index = sc->sc_rx.next; 703d3a0e4e9Skettenis for (n = 0; n < total; n++) { 704d3a0e4e9Skettenis status = RD4(sc, GENET_RX_DESC_STATUS(index)); 705d3a0e4e9Skettenis len = __SHIFTOUT(status, GENET_RX_DESC_STATUS_BUFLEN); 706d3a0e4e9Skettenis 707d3a0e4e9Skettenis /* XXX check for errors */ 708d3a0e4e9Skettenis 709d3a0e4e9Skettenis bus_dmamap_sync(sc->sc_rx.buf_tag, sc->sc_rx.buf_map[index].map, 710d3a0e4e9Skettenis 0, sc->sc_rx.buf_map[index].map->dm_mapsize, 711d3a0e4e9Skettenis BUS_DMASYNC_POSTREAD); 712d3a0e4e9Skettenis bus_dmamap_unload(sc->sc_rx.buf_tag, sc->sc_rx.buf_map[index].map); 713d3a0e4e9Skettenis 714d3a0e4e9Skettenis DPRINTF("RX [#%d] index=%02x status=%08x len=%d adj_len=%d\n", 715d3a0e4e9Skettenis n, index, status, len, len - ETHER_ALIGN); 716d3a0e4e9Skettenis 717d3a0e4e9Skettenis m = sc->sc_rx.buf_map[index].mbuf; 718d3a0e4e9Skettenis sc->sc_rx.buf_map[index].mbuf = NULL; 719d3a0e4e9Skettenis 720d3a0e4e9Skettenis if (len > ETHER_ALIGN) { 721d3a0e4e9Skettenis m_adj(m, ETHER_ALIGN); 722d3a0e4e9Skettenis 723d3a0e4e9Skettenis m->m_len = m->m_pkthdr.len = len - ETHER_ALIGN; 724d3a0e4e9Skettenis m->m_nextpkt = NULL; 725d3a0e4e9Skettenis 726d3a0e4e9Skettenis ml_enqueue(&ml, m); 727d3a0e4e9Skettenis } else { 728d3a0e4e9Skettenis ifp->if_ierrors++; 729d3a0e4e9Skettenis m_freem(m); 730d3a0e4e9Skettenis } 731d3a0e4e9Skettenis 732d3a0e4e9Skettenis if_rxr_put(&sc->sc_rx_ring, 1); 733d3a0e4e9Skettenis 734d3a0e4e9Skettenis index = RX_NEXT(index); 735d3a0e4e9Skettenis } 736d3a0e4e9Skettenis 737d3a0e4e9Skettenis if (sc->sc_rx.pidx != pidx) { 738d3a0e4e9Skettenis sc->sc_rx.next = index; 739d3a0e4e9Skettenis sc->sc_rx.pidx = pidx; 740d3a0e4e9Skettenis 741af89bcb2Sdlg if (ifiq_input(&ifp->if_rcv, &ml)) 742af89bcb2Sdlg if_rxr_livelocked(&sc->sc_rx_ring); 743af89bcb2Sdlg 744d3a0e4e9Skettenis genet_fill_rx_ring(sc, qid); 745d3a0e4e9Skettenis } 746d3a0e4e9Skettenis } 747d3a0e4e9Skettenis 748d3a0e4e9Skettenis void 749d3a0e4e9Skettenis genet_txintr(struct genet_softc *sc, int qid) 750d3a0e4e9Skettenis { 751d3a0e4e9Skettenis struct ifnet *ifp = &sc->sc_ac.ac_if; 752d3a0e4e9Skettenis struct genet_bufmap *bmap; 753d3a0e4e9Skettenis uint32_t cidx, total; 754d3a0e4e9Skettenis int i; 755d3a0e4e9Skettenis 756d3a0e4e9Skettenis cidx = RD4(sc, GENET_TX_DMA_CONS_INDEX(qid)) & 0xffff; 757d3a0e4e9Skettenis total = (cidx - sc->sc_tx.cidx) & 0xffff; 758d3a0e4e9Skettenis 759d3a0e4e9Skettenis for (i = sc->sc_tx.next; sc->sc_tx.queued > 0 && total > 0; 760d3a0e4e9Skettenis i = TX_NEXT(i), total--) { 761d3a0e4e9Skettenis /* XXX check for errors */ 762d3a0e4e9Skettenis 763d3a0e4e9Skettenis bmap = &sc->sc_tx.buf_map[i]; 764d3a0e4e9Skettenis if (bmap->mbuf != NULL) { 765d3a0e4e9Skettenis bus_dmamap_sync(sc->sc_tx.buf_tag, bmap->map, 766d3a0e4e9Skettenis 0, bmap->map->dm_mapsize, 767d3a0e4e9Skettenis BUS_DMASYNC_POSTWRITE); 768d3a0e4e9Skettenis bus_dmamap_unload(sc->sc_tx.buf_tag, bmap->map); 769d3a0e4e9Skettenis m_freem(bmap->mbuf); 770d3a0e4e9Skettenis bmap->mbuf = NULL; 771d3a0e4e9Skettenis } 772d3a0e4e9Skettenis 773d3a0e4e9Skettenis --sc->sc_tx.queued; 774d3a0e4e9Skettenis } 775d3a0e4e9Skettenis 776d3a0e4e9Skettenis if (sc->sc_tx.queued == 0) 777d3a0e4e9Skettenis ifp->if_timer = 0; 778d3a0e4e9Skettenis 779d3a0e4e9Skettenis if (sc->sc_tx.cidx != cidx) { 780d3a0e4e9Skettenis sc->sc_tx.next = i; 781d3a0e4e9Skettenis sc->sc_tx.cidx = cidx; 782d3a0e4e9Skettenis 783d3a0e4e9Skettenis if (ifq_is_oactive(&ifp->if_snd)) 784d3a0e4e9Skettenis ifq_restart(&ifp->if_snd); 785d3a0e4e9Skettenis } 786d3a0e4e9Skettenis } 787d3a0e4e9Skettenis 788d3a0e4e9Skettenis void 789d3a0e4e9Skettenis genet_start(struct ifnet *ifp) 790d3a0e4e9Skettenis { 791d3a0e4e9Skettenis struct genet_softc *sc = ifp->if_softc; 792d3a0e4e9Skettenis struct mbuf *m; 793d3a0e4e9Skettenis const int qid = GENET_DMA_DEFAULT_QUEUE; 794d3a0e4e9Skettenis int nsegs, index, cnt; 795d3a0e4e9Skettenis 796d3a0e4e9Skettenis if ((ifp->if_flags & IFF_RUNNING) == 0) 797d3a0e4e9Skettenis return; 798d3a0e4e9Skettenis if (ifq_is_oactive(&ifp->if_snd)) 799d3a0e4e9Skettenis return; 800d3a0e4e9Skettenis 801d3a0e4e9Skettenis index = sc->sc_tx.pidx & (TX_DESC_COUNT - 1); 802d3a0e4e9Skettenis cnt = 0; 803d3a0e4e9Skettenis 804d3a0e4e9Skettenis for (;;) { 805d3a0e4e9Skettenis m = ifq_deq_begin(&ifp->if_snd); 806d3a0e4e9Skettenis if (m == NULL) 807d3a0e4e9Skettenis break; 808d3a0e4e9Skettenis 809d3a0e4e9Skettenis nsegs = genet_setup_txbuf(sc, index, m); 810d3a0e4e9Skettenis if (nsegs == -1) { 811d3a0e4e9Skettenis ifq_deq_rollback(&ifp->if_snd, m); 812d3a0e4e9Skettenis ifq_set_oactive(&ifp->if_snd); 813d3a0e4e9Skettenis break; 814d3a0e4e9Skettenis } 815d3a0e4e9Skettenis if (nsegs == 0) { 816d3a0e4e9Skettenis ifq_deq_commit(&ifp->if_snd, m); 817d3a0e4e9Skettenis m_freem(m); 818d3a0e4e9Skettenis ifp->if_oerrors++; 819d3a0e4e9Skettenis continue; 820d3a0e4e9Skettenis } 821d3a0e4e9Skettenis ifq_deq_commit(&ifp->if_snd, m); 822d3a0e4e9Skettenis if (ifp->if_bpf) 823d3a0e4e9Skettenis bpf_mtap(ifp->if_bpf, m, BPF_DIRECTION_OUT); 824d3a0e4e9Skettenis 825d3a0e4e9Skettenis index = TX_SKIP(index, nsegs); 826d3a0e4e9Skettenis 827d3a0e4e9Skettenis sc->sc_tx.pidx = (sc->sc_tx.pidx + nsegs) & 0xffff; 828d3a0e4e9Skettenis cnt++; 829d3a0e4e9Skettenis } 830d3a0e4e9Skettenis 831d3a0e4e9Skettenis if (cnt != 0) { 832d3a0e4e9Skettenis WR4(sc, GENET_TX_DMA_PROD_INDEX(qid), sc->sc_tx.pidx); 833d3a0e4e9Skettenis ifp->if_timer = 5; 834d3a0e4e9Skettenis } 835d3a0e4e9Skettenis } 836d3a0e4e9Skettenis 837d3a0e4e9Skettenis int 838d3a0e4e9Skettenis genet_intr(void *arg) 839d3a0e4e9Skettenis { 840d3a0e4e9Skettenis struct genet_softc *sc = arg; 841d3a0e4e9Skettenis struct ifnet *ifp = &sc->sc_ac.ac_if; 842d3a0e4e9Skettenis uint32_t val; 843d3a0e4e9Skettenis 844d3a0e4e9Skettenis val = RD4(sc, GENET_INTRL2_CPU_STAT); 845d3a0e4e9Skettenis val &= ~RD4(sc, GENET_INTRL2_CPU_STAT_MASK); 846d3a0e4e9Skettenis WR4(sc, GENET_INTRL2_CPU_CLEAR, val); 847d3a0e4e9Skettenis 848d3a0e4e9Skettenis if (val & GENET_IRQ_RXDMA_DONE) 849d3a0e4e9Skettenis genet_rxintr(sc, GENET_DMA_DEFAULT_QUEUE); 850d3a0e4e9Skettenis 851d3a0e4e9Skettenis if (val & GENET_IRQ_TXDMA_DONE) { 852d3a0e4e9Skettenis genet_txintr(sc, GENET_DMA_DEFAULT_QUEUE); 853d3a0e4e9Skettenis if (ifq_is_oactive(&ifp->if_snd)) 854d3a0e4e9Skettenis ifq_restart(&ifp->if_snd); 855d3a0e4e9Skettenis } 856d3a0e4e9Skettenis 857d3a0e4e9Skettenis return 1; 858d3a0e4e9Skettenis } 859d3a0e4e9Skettenis 860d3a0e4e9Skettenis int 861d3a0e4e9Skettenis genet_ioctl(struct ifnet *ifp, u_long cmd, caddr_t addr) 862d3a0e4e9Skettenis { 863d3a0e4e9Skettenis struct genet_softc *sc = ifp->if_softc; 864d3a0e4e9Skettenis struct ifreq *ifr = (struct ifreq *)addr; 865d3a0e4e9Skettenis int error = 0, s; 866d3a0e4e9Skettenis 867d3a0e4e9Skettenis s = splnet(); 868d3a0e4e9Skettenis 869d3a0e4e9Skettenis switch (cmd) { 870d3a0e4e9Skettenis case SIOCSIFADDR: 871d3a0e4e9Skettenis ifp->if_flags |= IFF_UP; 872d3a0e4e9Skettenis /* FALLTHROUGH */ 873d3a0e4e9Skettenis case SIOCSIFFLAGS: 874d3a0e4e9Skettenis if (ifp->if_flags & IFF_UP) { 875d3a0e4e9Skettenis if (ifp->if_flags & IFF_RUNNING) 876d3a0e4e9Skettenis error = ENETRESET; 877d3a0e4e9Skettenis else 878d3a0e4e9Skettenis genet_init(sc); 879d3a0e4e9Skettenis } else { 880d3a0e4e9Skettenis if (ifp->if_flags & IFF_RUNNING) 881d3a0e4e9Skettenis genet_stop(sc); 882d3a0e4e9Skettenis } 883d3a0e4e9Skettenis break; 884d3a0e4e9Skettenis 885d3a0e4e9Skettenis case SIOCGIFMEDIA: 886d3a0e4e9Skettenis case SIOCSIFMEDIA: 887d3a0e4e9Skettenis error = ifmedia_ioctl(ifp, ifr, &sc->sc_mii.mii_media, cmd); 888d3a0e4e9Skettenis break; 889d3a0e4e9Skettenis 890d3a0e4e9Skettenis case SIOCGIFRXR: 891d3a0e4e9Skettenis error = if_rxr_ioctl((struct if_rxrinfo *)ifr->ifr_data, 892d3a0e4e9Skettenis NULL, MCLBYTES, &sc->sc_rx_ring); 893d3a0e4e9Skettenis break; 894d3a0e4e9Skettenis 895d3a0e4e9Skettenis default: 896d3a0e4e9Skettenis error = ether_ioctl(ifp, &sc->sc_ac, cmd, addr); 897d3a0e4e9Skettenis break; 898d3a0e4e9Skettenis } 899d3a0e4e9Skettenis 900d3a0e4e9Skettenis if (error == ENETRESET) { 901d3a0e4e9Skettenis if (ifp->if_flags & IFF_RUNNING) 902d3a0e4e9Skettenis genet_setup_rxfilter(sc); 903d3a0e4e9Skettenis error = 0; 904d3a0e4e9Skettenis } 905d3a0e4e9Skettenis 906d3a0e4e9Skettenis splx(s); 907d3a0e4e9Skettenis return error; 908d3a0e4e9Skettenis } 909d3a0e4e9Skettenis 910d3a0e4e9Skettenis int 911d3a0e4e9Skettenis genet_setup_dma(struct genet_softc *sc, int qid) 912d3a0e4e9Skettenis { 913d3a0e4e9Skettenis int error, i; 914d3a0e4e9Skettenis 915d3a0e4e9Skettenis /* Setup TX ring */ 916d3a0e4e9Skettenis sc->sc_tx.buf_tag = sc->sc_dmat; 917d3a0e4e9Skettenis for (i = 0; i < TX_DESC_COUNT; i++) { 918d3a0e4e9Skettenis error = bus_dmamap_create(sc->sc_tx.buf_tag, MCLBYTES, 919d3a0e4e9Skettenis TX_MAX_SEGS, MCLBYTES, 0, BUS_DMA_WAITOK, 920d3a0e4e9Skettenis &sc->sc_tx.buf_map[i].map); 921d3a0e4e9Skettenis if (error != 0) { 922d3a0e4e9Skettenis printf("%s: cannot create TX buffer map\n", 923d3a0e4e9Skettenis sc->sc_dev.dv_xname); 924d3a0e4e9Skettenis return error; 925d3a0e4e9Skettenis } 926d3a0e4e9Skettenis } 927d3a0e4e9Skettenis 928d3a0e4e9Skettenis /* Setup RX ring */ 929d3a0e4e9Skettenis sc->sc_rx.buf_tag = sc->sc_dmat; 930d3a0e4e9Skettenis for (i = 0; i < RX_DESC_COUNT; i++) { 931d3a0e4e9Skettenis error = bus_dmamap_create(sc->sc_rx.buf_tag, MCLBYTES, 932d3a0e4e9Skettenis 1, MCLBYTES, 0, BUS_DMA_WAITOK, 933d3a0e4e9Skettenis &sc->sc_rx.buf_map[i].map); 934d3a0e4e9Skettenis if (error != 0) { 935d3a0e4e9Skettenis printf("%s: cannot create RX buffer map\n", 936d3a0e4e9Skettenis sc->sc_dev.dv_xname); 937d3a0e4e9Skettenis return error; 938d3a0e4e9Skettenis } 939d3a0e4e9Skettenis } 940d3a0e4e9Skettenis 941d3a0e4e9Skettenis return 0; 942d3a0e4e9Skettenis } 943d3a0e4e9Skettenis 944d3a0e4e9Skettenis int 945d3a0e4e9Skettenis genet_attach(struct genet_softc *sc) 946d3a0e4e9Skettenis { 947d3a0e4e9Skettenis struct mii_data *mii = &sc->sc_mii; 948d3a0e4e9Skettenis struct ifnet *ifp = &sc->sc_ac.ac_if; 949d3a0e4e9Skettenis int mii_flags = 0; 950d3a0e4e9Skettenis 951d3a0e4e9Skettenis switch (sc->sc_phy_mode) { 952d3a0e4e9Skettenis case GENET_PHY_MODE_RGMII_ID: 953d3a0e4e9Skettenis mii_flags |= MIIF_RXID | MIIF_TXID; 954d3a0e4e9Skettenis break; 955d3a0e4e9Skettenis case GENET_PHY_MODE_RGMII_RXID: 956d3a0e4e9Skettenis mii_flags |= MIIF_RXID; 957d3a0e4e9Skettenis break; 958d3a0e4e9Skettenis case GENET_PHY_MODE_RGMII_TXID: 959d3a0e4e9Skettenis mii_flags |= MIIF_TXID; 960d3a0e4e9Skettenis break; 961d3a0e4e9Skettenis case GENET_PHY_MODE_RGMII: 962d3a0e4e9Skettenis default: 963d3a0e4e9Skettenis break; 964d3a0e4e9Skettenis } 965d3a0e4e9Skettenis 966d3a0e4e9Skettenis printf(": address %s\n", ether_sprintf(sc->sc_lladdr)); 967d3a0e4e9Skettenis 968d3a0e4e9Skettenis /* Soft reset EMAC core */ 969d3a0e4e9Skettenis genet_reset(sc); 970d3a0e4e9Skettenis 971d3a0e4e9Skettenis /* Setup DMA descriptors */ 972d3a0e4e9Skettenis if (genet_setup_dma(sc, GENET_DMA_DEFAULT_QUEUE) != 0) { 973d3a0e4e9Skettenis printf("%s: failed to setup DMA descriptors\n", 974d3a0e4e9Skettenis sc->sc_dev.dv_xname); 975d3a0e4e9Skettenis return EINVAL; 976d3a0e4e9Skettenis } 977d3a0e4e9Skettenis 978d3a0e4e9Skettenis timeout_set(&sc->sc_stat_ch, genet_tick, sc); 979d3a0e4e9Skettenis timeout_set(&sc->sc_rxto, genet_rxtick, sc); 980d3a0e4e9Skettenis 981d3a0e4e9Skettenis /* Setup ethernet interface */ 982d3a0e4e9Skettenis ifp->if_softc = sc; 983d3a0e4e9Skettenis snprintf(ifp->if_xname, IFNAMSIZ, "%s", sc->sc_dev.dv_xname); 984d3a0e4e9Skettenis ifp->if_flags = IFF_BROADCAST | IFF_SIMPLEX | IFF_MULTICAST; 985d3a0e4e9Skettenis ifp->if_start = genet_start; 986d3a0e4e9Skettenis ifp->if_ioctl = genet_ioctl; 987cf96265bSbluhm ifq_init_maxlen(&ifp->if_snd, IFQ_MAXLEN); 988d3a0e4e9Skettenis 989d3a0e4e9Skettenis /* 802.1Q VLAN-sized frames are supported */ 990d3a0e4e9Skettenis ifp->if_capabilities = IFCAP_VLAN_MTU; 991d3a0e4e9Skettenis 992d3a0e4e9Skettenis /* Attach MII driver */ 993d3a0e4e9Skettenis ifmedia_init(&mii->mii_media, 0, genet_media_change, genet_media_status); 994d3a0e4e9Skettenis mii->mii_ifp = ifp; 995d3a0e4e9Skettenis mii->mii_readreg = genet_mii_readreg; 996d3a0e4e9Skettenis mii->mii_writereg = genet_mii_writereg; 997d3a0e4e9Skettenis mii->mii_statchg = genet_mii_statchg; 998d3a0e4e9Skettenis mii_attach(&sc->sc_dev, mii, 0xffffffff, sc->sc_phy_id, 999d3a0e4e9Skettenis MII_OFFSET_ANY, mii_flags); 1000d3a0e4e9Skettenis 1001d3a0e4e9Skettenis if (LIST_EMPTY(&mii->mii_phys)) { 1002d3a0e4e9Skettenis printf("%s: no PHY found!\n", sc->sc_dev.dv_xname); 1003d3a0e4e9Skettenis ifmedia_add(&mii->mii_media, IFM_ETHER|IFM_MANUAL, 0, NULL); 1004d3a0e4e9Skettenis ifmedia_set(&mii->mii_media, IFM_ETHER|IFM_MANUAL); 1005d3a0e4e9Skettenis } 1006d3a0e4e9Skettenis ifmedia_set(&mii->mii_media, IFM_ETHER | IFM_AUTO); 1007d3a0e4e9Skettenis 1008d3a0e4e9Skettenis /* Attach interface */ 1009d3a0e4e9Skettenis if_attach(ifp); 1010d3a0e4e9Skettenis 1011d3a0e4e9Skettenis /* Attach ethernet interface */ 1012d3a0e4e9Skettenis ether_ifattach(ifp); 1013d3a0e4e9Skettenis 1014d3a0e4e9Skettenis return 0; 1015d3a0e4e9Skettenis } 1016d3a0e4e9Skettenis 1017d3a0e4e9Skettenis void 1018d3a0e4e9Skettenis genet_lladdr_read(struct genet_softc *sc, uint8_t *lladdr) 1019d3a0e4e9Skettenis { 1020d3a0e4e9Skettenis uint32_t maclo, machi; 1021d3a0e4e9Skettenis 1022d3a0e4e9Skettenis maclo = RD4(sc, GENET_UMAC_MAC0); 1023d3a0e4e9Skettenis machi = RD4(sc, GENET_UMAC_MAC1); 1024d3a0e4e9Skettenis 1025d3a0e4e9Skettenis lladdr[0] = (maclo >> 24) & 0xff; 1026d3a0e4e9Skettenis lladdr[1] = (maclo >> 16) & 0xff; 1027d3a0e4e9Skettenis lladdr[2] = (maclo >> 8) & 0xff; 1028d3a0e4e9Skettenis lladdr[3] = (maclo >> 0) & 0xff; 1029d3a0e4e9Skettenis lladdr[4] = (machi >> 8) & 0xff; 1030d3a0e4e9Skettenis lladdr[5] = (machi >> 0) & 0xff; 1031d3a0e4e9Skettenis } 1032