Index: head/sys/arm64/broadcom/genet/if_genet.c =================================================================== --- head/sys/arm64/broadcom/genet/if_genet.c (revision 362352) +++ head/sys/arm64/broadcom/genet/if_genet.c (revision 362353) @@ -1,1739 +1,1764 @@ /*- * Copyright (c) 2020 Michael J Karels * Copyright (c) 2016, 2020 Jared McNeill * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. * * $FreeBSD$ */ /* * RPi4 (BCM 2711) Gigabit Ethernet ("GENET") controller * * This driver is derived in large part from bcmgenet.c from NetBSD by * Jared McNeill. Parts of the structure and other common code in * this driver have been copied from if_awg.c for the Allwinner EMAC, * also by Jared McNeill. */ #include "opt_device_polling.h" #include __FBSDID("$FreeBSD$"); #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #define __BIT(_x) (1 << (_x)) #include "if_genetreg.h" #include #include #include #include #include #include #define ICMPV6_HACK /* workaround for chip issue */ #ifdef ICMPV6_HACK #include #endif #include "syscon_if.h" #include "miibus_if.h" #include "gpio_if.h" #define RD4(sc, reg) bus_read_4((sc)->res[_RES_MAC], (reg)) #define WR4(sc, reg, val) bus_write_4((sc)->res[_RES_MAC], (reg), (val)) #define GEN_LOCK(sc) mtx_lock(&(sc)->mtx) #define GEN_UNLOCK(sc) mtx_unlock(&(sc)->mtx) #define GEN_ASSERT_LOCKED(sc) mtx_assert(&(sc)->mtx, MA_OWNED) #define GEN_ASSERT_UNLOCKED(sc) mtx_assert(&(sc)->mtx, MA_NOTOWNED) #define TX_DESC_COUNT GENET_DMA_DESC_COUNT #define RX_DESC_COUNT GENET_DMA_DESC_COUNT #define TX_NEXT(n, count) (((n) + 1) & ((count) - 1)) #define RX_NEXT(n, count) (((n) + 1) & ((count) - 1)) #define TX_MAX_SEGS 20 /* Maximum number of mbufs to send to if_input */ static int gen_rx_batch = 16 /* RX_BATCH_DEFAULT */; TUNABLE_INT("hw.gen.rx_batch", &gen_rx_batch); static struct ofw_compat_data compat_data[] = { { "brcm,genet-v1", 1 }, { "brcm,genet-v2", 2 }, { "brcm,genet-v3", 3 }, { "brcm,genet-v4", 4 }, { "brcm,genet-v5", 5 }, { NULL, 0 } }; enum { _RES_MAC, /* what to call this? */ _RES_IRQ1, _RES_IRQ2, _RES_NITEMS }; static struct resource_spec gen_spec[] = { { SYS_RES_MEMORY, 0, RF_ACTIVE }, { SYS_RES_IRQ, 0, RF_ACTIVE }, { SYS_RES_IRQ, 1, RF_ACTIVE }, { -1, 0 } }; /* structure per ring entry */ struct gen_ring_ent { bus_dmamap_t map; struct mbuf *mbuf; }; struct tx_queue { int hwindex; /* hardware index */ int nentries; u_int queued; /* or avail? */ u_int cur; u_int next; u_int prod_idx; u_int cons_idx; struct gen_ring_ent *entries; }; struct rx_queue { int hwindex; /* hardware index */ int nentries; u_int cur; u_int prod_idx; u_int cons_idx; struct gen_ring_ent *entries; }; struct gen_softc { struct resource *res[_RES_NITEMS]; struct mtx mtx; if_t ifp; device_t dev; device_t miibus; mii_contype_t phy_mode; struct callout stat_ch; struct task link_task; void *ih; void *ih2; int type; int if_flags; int link; bus_dma_tag_t tx_buf_tag; /* * The genet chip has multiple queues for transmit and receive. * This driver uses only one (queue 16, the default), but is cast * with multiple rings. The additional rings are used for different * priorities. */ #define DEF_TXQUEUE 0 #define NTXQUEUE 1 struct tx_queue tx_queue[NTXQUEUE]; struct gen_ring_ent tx_ring_ent[TX_DESC_COUNT]; /* ring entries */ bus_dma_tag_t rx_buf_tag; #define DEF_RXQUEUE 0 #define NRXQUEUE 1 struct rx_queue rx_queue[NRXQUEUE]; struct gen_ring_ent rx_ring_ent[RX_DESC_COUNT]; /* ring entries */ }; static void gen_init(void *softc); static void gen_start(if_t ifp); static void gen_destroy(struct gen_softc *sc); static int gen_encap(struct gen_softc *sc, struct mbuf **mp); static int gen_parse_tx(struct mbuf *m, int csum_flags); static int gen_ioctl(if_t ifp, u_long cmd, caddr_t data); static int gen_get_phy_mode(device_t dev); static bool gen_get_eaddr(device_t dev, struct ether_addr *eaddr); static void gen_set_enaddr(struct gen_softc *sc); static void gen_setup_rxfilter(struct gen_softc *sc); static void gen_reset(struct gen_softc *sc); static void gen_enable(struct gen_softc *sc); static void gen_dma_disable(device_t dev); static int gen_bus_dma_init(struct gen_softc *sc); static void gen_bus_dma_teardown(struct gen_softc *sc); static void gen_enable_intr(struct gen_softc *sc); static void gen_init_txrings(struct gen_softc *sc); static void gen_init_rxrings(struct gen_softc *sc); static void gen_intr(void *softc); static int gen_rxintr(struct gen_softc *sc, struct rx_queue *q); static void gen_txintr(struct gen_softc *sc, struct tx_queue *q); static void gen_intr2(void *softc); static int gen_newbuf_rx(struct gen_softc *sc, struct rx_queue *q, int index); static int gen_mapbuf_rx(struct gen_softc *sc, struct rx_queue *q, int index, struct mbuf *m); static void gen_link_task(void *arg, int pending); static void gen_media_status(if_t ifp, struct ifmediareq *ifmr); static int gen_media_change(if_t ifp); static void gen_tick(void *softc); static int gen_probe(device_t dev) { if (!ofw_bus_status_okay(dev)) return (ENXIO); if (ofw_bus_search_compatible(dev, compat_data)->ocd_data == 0) return (ENXIO); device_set_desc(dev, "RPi4 Gigabit Ethernet"); return (BUS_PROBE_DEFAULT); } static int gen_attach(device_t dev) { struct ether_addr eaddr; struct gen_softc *sc; - int major, minor, error; + int major, minor, error, mii_flags; bool eaddr_found; sc = device_get_softc(dev); sc->dev = dev; sc->type = ofw_bus_search_compatible(dev, compat_data)->ocd_data; if (bus_alloc_resources(dev, gen_spec, sc->res) != 0) { device_printf(dev, "cannot allocate resources for device\n"); error = ENXIO; goto fail; } major = (RD4(sc, GENET_SYS_REV_CTRL) & REV_MAJOR) >> REV_MAJOR_SHIFT; if (major != REV_MAJOR_V5) { device_printf(dev, "version %d is not supported\n", major); error = ENXIO; goto fail; } minor = (RD4(sc, GENET_SYS_REV_CTRL) & REV_MINOR) >> REV_MINOR_SHIFT; device_printf(dev, "GENET version 5.%d phy 0x%04x\n", minor, RD4(sc, GENET_SYS_REV_CTRL) & REV_PHY); mtx_init(&sc->mtx, device_get_nameunit(dev), MTX_NETWORK_LOCK, MTX_DEF); callout_init_mtx(&sc->stat_ch, &sc->mtx, 0); TASK_INIT(&sc->link_task, 0, gen_link_task, sc); error = gen_get_phy_mode(dev); if (error != 0) goto fail; bzero(&eaddr, sizeof(eaddr)); eaddr_found = gen_get_eaddr(dev, &eaddr); /* reset core */ gen_reset(sc); gen_dma_disable(dev); /* Setup DMA */ error = gen_bus_dma_init(sc); if (error != 0) { device_printf(dev, "cannot setup bus dma\n"); goto fail; } /* Install interrupt handlers */ error = bus_setup_intr(dev, sc->res[_RES_IRQ1], INTR_TYPE_NET | INTR_MPSAFE, NULL, gen_intr, sc, &sc->ih); if (error != 0) { device_printf(dev, "cannot setup interrupt handler1\n"); goto fail; } error = bus_setup_intr(dev, sc->res[_RES_IRQ2], INTR_TYPE_NET | INTR_MPSAFE, NULL, gen_intr2, sc, &sc->ih2); if (error != 0) { device_printf(dev, "cannot setup interrupt handler2\n"); goto fail; } /* Setup ethernet interface */ sc->ifp = if_alloc(IFT_ETHER); if_setsoftc(sc->ifp, sc); if_initname(sc->ifp, device_get_name(dev), device_get_unit(dev)); if_setflags(sc->ifp, IFF_BROADCAST | IFF_SIMPLEX | IFF_MULTICAST); if_setstartfn(sc->ifp, gen_start); if_setioctlfn(sc->ifp, gen_ioctl); if_setinitfn(sc->ifp, gen_init); if_setsendqlen(sc->ifp, TX_DESC_COUNT - 1); if_setsendqready(sc->ifp); #define GEN_CSUM_FEATURES (CSUM_UDP | CSUM_TCP) if_sethwassist(sc->ifp, GEN_CSUM_FEATURES); if_setcapabilities(sc->ifp, IFCAP_VLAN_MTU | IFCAP_HWCSUM | IFCAP_HWCSUM_IPV6); if_setcapenable(sc->ifp, if_getcapabilities(sc->ifp)); /* Attach MII driver */ + mii_flags = 0; + switch (sc->phy_mode) + { + case MII_CONTYPE_RGMII_ID: + mii_flags |= MIIF_RX_DELAY | MIIF_TX_DELAY; + break; + case MII_CONTYPE_RGMII_RXID: + mii_flags |= MIIF_RX_DELAY; + break; + case MII_CONTYPE_RGMII_TXID: + mii_flags |= MIIF_TX_DELAY; + break; + default: + break; + } error = mii_attach(dev, &sc->miibus, sc->ifp, gen_media_change, gen_media_status, BMSR_DEFCAPMASK, MII_PHY_ANY, MII_OFFSET_ANY, - MIIF_DOPAUSE); + mii_flags); if (error != 0) { device_printf(dev, "cannot attach PHY\n"); goto fail; } /* If address was not found, create one based on the hostid and name. */ if (eaddr_found == 0) ether_gen_addr(sc->ifp, &eaddr); /* Attach ethernet interface */ ether_ifattach(sc->ifp, eaddr.octet); fail: if (error) gen_destroy(sc); return (error); } /* Free resources after failed attach. This is not a complete detach. */ static void gen_destroy(struct gen_softc *sc) { if (sc->miibus) { /* can't happen */ device_delete_child(sc->dev, sc->miibus); sc->miibus = NULL; } bus_teardown_intr(sc->dev, sc->res[_RES_IRQ1], sc->ih); bus_teardown_intr(sc->dev, sc->res[_RES_IRQ2], sc->ih2); gen_bus_dma_teardown(sc); callout_drain(&sc->stat_ch); if (mtx_initialized(&sc->mtx)) mtx_destroy(&sc->mtx); bus_release_resources(sc->dev, gen_spec, sc->res); if (sc->ifp != NULL) { if_free(sc->ifp); sc->ifp = NULL; } } static int gen_get_phy_mode(device_t dev) { struct gen_softc *sc; phandle_t node; mii_contype_t type; int error = 0; sc = device_get_softc(dev); node = ofw_bus_get_node(dev); type = mii_fdt_get_contype(node); switch (type) { case MII_CONTYPE_RGMII: + case MII_CONTYPE_RGMII_ID: case MII_CONTYPE_RGMII_RXID: case MII_CONTYPE_RGMII_TXID: sc->phy_mode = type; break; default: device_printf(dev, "unknown phy-mode '%s'\n", mii_fdt_contype_to_name(type)); error = ENXIO; break; } return (error); } static bool gen_get_eaddr(device_t dev, struct ether_addr *eaddr) { struct gen_softc *sc; uint32_t maclo, machi, val; phandle_t node; sc = device_get_softc(dev); node = ofw_bus_get_node(dev); if (OF_getprop(node, "mac-address", eaddr->octet, ETHER_ADDR_LEN) != -1 || OF_getprop(node, "local-mac-address", eaddr->octet, ETHER_ADDR_LEN) != -1 || OF_getprop(node, "address", eaddr->octet, ETHER_ADDR_LEN) != -1) return (true); device_printf(dev, "No Ethernet address found in fdt!\n"); maclo = machi = 0; val = RD4(sc, GENET_SYS_RBUF_FLUSH_CTRL); if ((val & GENET_SYS_RBUF_FLUSH_RESET) == 0) { maclo = htobe32(RD4(sc, GENET_UMAC_MAC0)); machi = htobe16(RD4(sc, GENET_UMAC_MAC1) & 0xffff); } if (maclo == 0 && machi == 0) { if (bootverbose) device_printf(dev, "No Ethernet address found in controller\n"); return (false); } else { eaddr->octet[0] = maclo & 0xff; eaddr->octet[1] = (maclo >> 8) & 0xff; eaddr->octet[2] = (maclo >> 16) & 0xff; eaddr->octet[3] = (maclo >> 24) & 0xff; eaddr->octet[4] = machi & 0xff; eaddr->octet[5] = (machi >> 8) & 0xff; return (true); } } static void gen_reset(struct gen_softc *sc) { uint32_t val; val = RD4(sc, GENET_SYS_RBUF_FLUSH_CTRL); val |= GENET_SYS_RBUF_FLUSH_RESET; WR4(sc, GENET_SYS_RBUF_FLUSH_CTRL, val); DELAY(10); val &= ~GENET_SYS_RBUF_FLUSH_RESET; WR4(sc, GENET_SYS_RBUF_FLUSH_CTRL, val); DELAY(10); WR4(sc, GENET_SYS_RBUF_FLUSH_CTRL, 0); DELAY(10); WR4(sc, GENET_UMAC_CMD, 0); WR4(sc, GENET_UMAC_CMD, GENET_UMAC_CMD_LCL_LOOP_EN | GENET_UMAC_CMD_SW_RESET); DELAY(10); WR4(sc, GENET_UMAC_CMD, 0); WR4(sc, GENET_UMAC_MIB_CTRL, GENET_UMAC_MIB_RESET_RUNT | GENET_UMAC_MIB_RESET_RX | GENET_UMAC_MIB_RESET_TX); WR4(sc, GENET_UMAC_MIB_CTRL, 0); WR4(sc, GENET_UMAC_MAX_FRAME_LEN, 1536); val = RD4(sc, GENET_RBUF_CTRL); val |= GENET_RBUF_ALIGN_2B; WR4(sc, GENET_RBUF_CTRL, val); WR4(sc, GENET_RBUF_TBUF_SIZE_CTRL, 1); } static void gen_enable(struct gen_softc *sc) { u_int val; /* Enable transmitter and receiver */ val = RD4(sc, GENET_UMAC_CMD); val |= GENET_UMAC_CMD_TXEN; val |= GENET_UMAC_CMD_RXEN; WR4(sc, GENET_UMAC_CMD, val); /* Enable interrupts */ gen_enable_intr(sc); WR4(sc, GENET_INTRL2_CPU_CLEAR_MASK, GENET_IRQ_TXDMA_DONE | GENET_IRQ_RXDMA_DONE); } static void gen_enable_offload(struct gen_softc *sc) { uint32_t check_ctrl, buf_ctrl; check_ctrl = RD4(sc, GENET_RBUF_CHECK_CTRL); buf_ctrl = RD4(sc, GENET_RBUF_CTRL); if ((if_getcapenable(sc->ifp) & IFCAP_RXCSUM) != 0) { check_ctrl |= GENET_RBUF_CHECK_CTRL_EN; buf_ctrl |= GENET_RBUF_64B_EN; } else { check_ctrl &= ~GENET_RBUF_CHECK_CTRL_EN; buf_ctrl &= ~GENET_RBUF_64B_EN; } WR4(sc, GENET_RBUF_CHECK_CTRL, check_ctrl); WR4(sc, GENET_RBUF_CTRL, buf_ctrl); buf_ctrl = RD4(sc, GENET_TBUF_CTRL); if ((if_getcapenable(sc->ifp) & (IFCAP_TXCSUM | IFCAP_TXCSUM_IPV6)) != 0) buf_ctrl |= GENET_RBUF_64B_EN; else buf_ctrl &= ~GENET_RBUF_64B_EN; WR4(sc, GENET_TBUF_CTRL, buf_ctrl); } static void gen_dma_disable(device_t dev) { struct gen_softc *sc = device_get_softc(dev); int val; val = RD4(sc, GENET_TX_DMA_CTRL); val &= ~GENET_TX_DMA_CTRL_EN; val &= ~GENET_TX_DMA_CTRL_RBUF_EN(GENET_DMA_DEFAULT_QUEUE); WR4(sc, GENET_TX_DMA_CTRL, val); val = RD4(sc, GENET_RX_DMA_CTRL); val &= ~GENET_RX_DMA_CTRL_EN; val &= ~GENET_RX_DMA_CTRL_RBUF_EN(GENET_DMA_DEFAULT_QUEUE); WR4(sc, GENET_RX_DMA_CTRL, val); } static int gen_bus_dma_init(struct gen_softc *sc) { struct device *dev = sc->dev; int i, error; error = bus_dma_tag_create( bus_get_dma_tag(dev), /* Parent tag */ 4, 0, /* alignment, boundary */ BUS_SPACE_MAXADDR_40BIT, /* lowaddr */ BUS_SPACE_MAXADDR, /* highaddr */ NULL, NULL, /* filter, filterarg */ MCLBYTES, TX_MAX_SEGS, /* maxsize, nsegs */ MCLBYTES, /* maxsegsize */ 0, /* flags */ NULL, NULL, /* lockfunc, lockarg */ &sc->tx_buf_tag); if (error != 0) { device_printf(dev, "cannot create TX buffer tag\n"); return (error); } for (i = 0; i < TX_DESC_COUNT; i++) { error = bus_dmamap_create(sc->tx_buf_tag, 0, &sc->tx_ring_ent[i].map); if (error != 0) { device_printf(dev, "cannot create TX buffer map\n"); return (error); } } error = bus_dma_tag_create( bus_get_dma_tag(dev), /* Parent tag */ 4, 0, /* alignment, boundary */ BUS_SPACE_MAXADDR_40BIT, /* lowaddr */ BUS_SPACE_MAXADDR, /* highaddr */ NULL, NULL, /* filter, filterarg */ MCLBYTES, 1, /* maxsize, nsegs */ MCLBYTES, /* maxsegsize */ 0, /* flags */ NULL, NULL, /* lockfunc, lockarg */ &sc->rx_buf_tag); if (error != 0) { device_printf(dev, "cannot create RX buffer tag\n"); return (error); } for (i = 0; i < RX_DESC_COUNT; i++) { error = bus_dmamap_create(sc->rx_buf_tag, 0, &sc->rx_ring_ent[i].map); if (error != 0) { device_printf(dev, "cannot create RX buffer map\n"); return (error); } } return (0); } static void gen_bus_dma_teardown(struct gen_softc *sc) { int i, error; if (sc->tx_buf_tag != NULL) { for (i = 0; i < TX_DESC_COUNT; i++) { error = bus_dmamap_destroy(sc->tx_buf_tag, sc->tx_ring_ent[i].map); sc->tx_ring_ent[i].map = NULL; if (error) device_printf(sc->dev, "%s: bus_dmamap_destroy failed: %d\n", __func__, error); } error = bus_dma_tag_destroy(sc->tx_buf_tag); sc->tx_buf_tag = NULL; if (error) device_printf(sc->dev, "%s: bus_dma_tag_destroy failed: %d\n", __func__, error); } if (sc->tx_buf_tag != NULL) { for (i = 0; i < RX_DESC_COUNT; i++) { error = bus_dmamap_destroy(sc->rx_buf_tag, sc->rx_ring_ent[i].map); sc->rx_ring_ent[i].map = NULL; if (error) device_printf(sc->dev, "%s: bus_dmamap_destroy failed: %d\n", __func__, error); } error = bus_dma_tag_destroy(sc->rx_buf_tag); sc->rx_buf_tag = NULL; if (error) device_printf(sc->dev, "%s: bus_dma_tag_destroy failed: %d\n", __func__, error); } } static void gen_enable_intr(struct gen_softc *sc) { WR4(sc, GENET_INTRL2_CPU_CLEAR_MASK, GENET_IRQ_TXDMA_DONE | GENET_IRQ_RXDMA_DONE); } /* * "queue" is the software queue index (0-4); "qid" is the hardware index * (0-16). "base" is the starting index in the ring array. */ static void gen_init_txring(struct gen_softc *sc, int queue, int qid, int base, int nentries) { struct tx_queue *q; uint32_t val; q = &sc->tx_queue[queue]; q->entries = &sc->tx_ring_ent[base]; q->hwindex = qid; q->nentries = nentries; /* TX ring */ q->queued = 0; q->cons_idx = q->prod_idx = 0; WR4(sc, GENET_TX_SCB_BURST_SIZE, 0x08); WR4(sc, GENET_TX_DMA_READ_PTR_LO(qid), 0); WR4(sc, GENET_TX_DMA_READ_PTR_HI(qid), 0); WR4(sc, GENET_TX_DMA_CONS_INDEX(qid), 0); WR4(sc, GENET_TX_DMA_PROD_INDEX(qid), 0); WR4(sc, GENET_TX_DMA_RING_BUF_SIZE(qid), (nentries << GENET_TX_DMA_RING_BUF_SIZE_DESC_SHIFT) | (MCLBYTES & GENET_TX_DMA_RING_BUF_SIZE_BUF_LEN_MASK)); WR4(sc, GENET_TX_DMA_START_ADDR_LO(qid), 0); WR4(sc, GENET_TX_DMA_START_ADDR_HI(qid), 0); WR4(sc, GENET_TX_DMA_END_ADDR_LO(qid), TX_DESC_COUNT * GENET_DMA_DESC_SIZE / 4 - 1); WR4(sc, GENET_TX_DMA_END_ADDR_HI(qid), 0); WR4(sc, GENET_TX_DMA_MBUF_DONE_THRES(qid), 1); WR4(sc, GENET_TX_DMA_FLOW_PERIOD(qid), 0); WR4(sc, GENET_TX_DMA_WRITE_PTR_LO(qid), 0); WR4(sc, GENET_TX_DMA_WRITE_PTR_HI(qid), 0); WR4(sc, GENET_TX_DMA_RING_CFG, __BIT(qid)); /* enable */ /* Enable transmit DMA */ val = RD4(sc, GENET_TX_DMA_CTRL); val |= GENET_TX_DMA_CTRL_EN; val |= GENET_TX_DMA_CTRL_RBUF_EN(qid); WR4(sc, GENET_TX_DMA_CTRL, val); } /* * "queue" is the software queue index (0-4); "qid" is the hardware index * (0-16). "base" is the starting index in the ring array. */ static void gen_init_rxring(struct gen_softc *sc, int queue, int qid, int base, int nentries) { struct rx_queue *q; uint32_t val; int i; q = &sc->rx_queue[queue]; q->entries = &sc->rx_ring_ent[base]; q->hwindex = qid; q->nentries = nentries; q->cons_idx = q->prod_idx = 0; WR4(sc, GENET_RX_SCB_BURST_SIZE, 0x08); WR4(sc, GENET_RX_DMA_WRITE_PTR_LO(qid), 0); WR4(sc, GENET_RX_DMA_WRITE_PTR_HI(qid), 0); WR4(sc, GENET_RX_DMA_PROD_INDEX(qid), 0); WR4(sc, GENET_RX_DMA_CONS_INDEX(qid), 0); WR4(sc, GENET_RX_DMA_RING_BUF_SIZE(qid), (nentries << GENET_RX_DMA_RING_BUF_SIZE_DESC_SHIFT) | (MCLBYTES & GENET_RX_DMA_RING_BUF_SIZE_BUF_LEN_MASK)); WR4(sc, GENET_RX_DMA_START_ADDR_LO(qid), 0); WR4(sc, GENET_RX_DMA_START_ADDR_HI(qid), 0); WR4(sc, GENET_RX_DMA_END_ADDR_LO(qid), RX_DESC_COUNT * GENET_DMA_DESC_SIZE / 4 - 1); WR4(sc, GENET_RX_DMA_END_ADDR_HI(qid), 0); WR4(sc, GENET_RX_DMA_XON_XOFF_THRES(qid), (5 << GENET_RX_DMA_XON_XOFF_THRES_LO_SHIFT) | (RX_DESC_COUNT >> 4)); WR4(sc, GENET_RX_DMA_READ_PTR_LO(qid), 0); WR4(sc, GENET_RX_DMA_READ_PTR_HI(qid), 0); WR4(sc, GENET_RX_DMA_RING_CFG, __BIT(qid)); /* enable */ /* fill ring */ for (i = 0; i < RX_DESC_COUNT; i++) gen_newbuf_rx(sc, &sc->rx_queue[DEF_RXQUEUE], i); /* Enable receive DMA */ val = RD4(sc, GENET_RX_DMA_CTRL); val |= GENET_RX_DMA_CTRL_EN; val |= GENET_RX_DMA_CTRL_RBUF_EN(qid); WR4(sc, GENET_RX_DMA_CTRL, val); } static void gen_init_txrings(struct gen_softc *sc) { int base = 0; #ifdef PRI_RINGS int i; /* init priority rings */ for (i = 0; i < PRI_RINGS; i++) { gen_init_txring(sc, i, i, base, TX_DESC_PRICOUNT); sc->tx_queue[i].queue = i; base += TX_DESC_PRICOUNT; dma_ring_conf |= 1 << i; dma_control |= DMA_RENABLE(i); } #endif /* init GENET_DMA_DEFAULT_QUEUE (16) */ gen_init_txring(sc, DEF_TXQUEUE, GENET_DMA_DEFAULT_QUEUE, base, TX_DESC_COUNT); sc->tx_queue[DEF_TXQUEUE].hwindex = GENET_DMA_DEFAULT_QUEUE; } static void gen_init_rxrings(struct gen_softc *sc) { int base = 0; #ifdef PRI_RINGS int i; /* init priority rings */ for (i = 0; i < PRI_RINGS; i++) { gen_init_rxring(sc, i, i, base, TX_DESC_PRICOUNT); sc->rx_queue[i].queue = i; base += TX_DESC_PRICOUNT; dma_ring_conf |= 1 << i; dma_control |= DMA_RENABLE(i); } #endif /* init GENET_DMA_DEFAULT_QUEUE (16) */ gen_init_rxring(sc, DEF_RXQUEUE, GENET_DMA_DEFAULT_QUEUE, base, RX_DESC_COUNT); sc->rx_queue[DEF_RXQUEUE].hwindex = GENET_DMA_DEFAULT_QUEUE; } static void gen_init_locked(struct gen_softc *sc) { struct mii_data *mii; if_t ifp; mii = device_get_softc(sc->miibus); ifp = sc->ifp; GEN_ASSERT_LOCKED(sc); if (if_getdrvflags(ifp) & IFF_DRV_RUNNING) return; - if (sc->phy_mode == MII_CONTYPE_RGMII || - sc->phy_mode == MII_CONTYPE_RGMII_RXID) - WR4(sc, GENET_SYS_PORT_CTRL, - GENET_SYS_PORT_MODE_EXT_GPHY); + switch (sc->phy_mode) + { + case MII_CONTYPE_RGMII: + case MII_CONTYPE_RGMII_ID: + case MII_CONTYPE_RGMII_RXID: + case MII_CONTYPE_RGMII_TXID: + WR4(sc, GENET_SYS_PORT_CTRL, GENET_SYS_PORT_MODE_EXT_GPHY); + break; + default: + WR4(sc, GENET_SYS_PORT_CTRL, 0); + } gen_set_enaddr(sc); /* Setup RX filter */ gen_setup_rxfilter(sc); gen_init_txrings(sc); gen_init_rxrings(sc); gen_enable(sc); gen_enable_offload(sc); if_setdrvflagbits(ifp, IFF_DRV_RUNNING, IFF_DRV_OACTIVE); mii_mediachg(mii); callout_reset(&sc->stat_ch, hz, gen_tick, sc); } static void gen_init(void *softc) { struct gen_softc *sc; sc = softc; GEN_LOCK(sc); gen_init_locked(sc); GEN_UNLOCK(sc); } static uint8_t ether_broadcastaddr[] = { 0xff, 0xff, 0xff, 0xff, 0xff, 0xff }; static void gen_setup_rxfilter_mdf(struct gen_softc *sc, u_int n, const uint8_t *ea) { uint32_t addr0 = (ea[0] << 8) | ea[1]; uint32_t addr1 = (ea[2] << 24) | (ea[3] << 16) | (ea[4] << 8) | ea[5]; WR4(sc, GENET_UMAC_MDF_ADDR0(n), addr0); WR4(sc, GENET_UMAC_MDF_ADDR1(n), addr1); } static u_int gen_setup_multi(void *arg, struct sockaddr_dl *sdl, u_int count) { struct gen_softc *sc = arg; /* "count + 2" to account for unicast and broadcast */ gen_setup_rxfilter_mdf(sc, count + 2, LLADDR(sdl)); return (1); /* increment to count */ } static void gen_setup_rxfilter(struct gen_softc *sc) { struct ifnet *ifp = sc->ifp; uint32_t cmd, mdf_ctrl; u_int n; GEN_ASSERT_LOCKED(sc); cmd = RD4(sc, GENET_UMAC_CMD); /* * Count the required number of hardware filters. We need one * for each multicast address, plus one for our own address and * the broadcast address. */ n = if_llmaddr_count(ifp) + 2; if (n > GENET_MAX_MDF_FILTER) ifp->if_flags |= IFF_ALLMULTI; else ifp->if_flags &= ~IFF_ALLMULTI; if ((ifp->if_flags & (IFF_PROMISC|IFF_ALLMULTI)) != 0) { cmd |= GENET_UMAC_CMD_PROMISC; mdf_ctrl = 0; } else { cmd &= ~GENET_UMAC_CMD_PROMISC; gen_setup_rxfilter_mdf(sc, 0, ether_broadcastaddr); gen_setup_rxfilter_mdf(sc, 1, IF_LLADDR(ifp)); (void) if_foreach_llmaddr(ifp, gen_setup_multi, sc); mdf_ctrl = (__BIT(GENET_MAX_MDF_FILTER) - 1) &~ (__BIT(GENET_MAX_MDF_FILTER - n) - 1); } WR4(sc, GENET_UMAC_CMD, cmd); WR4(sc, GENET_UMAC_MDF_CTRL, mdf_ctrl); } static void gen_set_enaddr(struct gen_softc *sc) { uint8_t *enaddr; uint32_t val; if_t ifp; GEN_ASSERT_LOCKED(sc); ifp = sc->ifp; /* Write our unicast address */ enaddr = IF_LLADDR(ifp); /* Write hardware address */ val = enaddr[3] | (enaddr[2] << 8) | (enaddr[1] << 16) | (enaddr[0] << 24); WR4(sc, GENET_UMAC_MAC0, val); val = enaddr[5] | (enaddr[4] << 8); WR4(sc, GENET_UMAC_MAC1, val); } static void gen_start_locked(struct gen_softc *sc) { struct mbuf *m; if_t ifp; int cnt, err; GEN_ASSERT_LOCKED(sc); if (!sc->link) return; ifp = sc->ifp; if ((if_getdrvflags(ifp) & (IFF_DRV_RUNNING|IFF_DRV_OACTIVE)) != IFF_DRV_RUNNING) return; for (cnt = 0; ; cnt++) { m = if_dequeue(ifp); if (m == NULL) break; err = gen_encap(sc, &m); if (err != 0) { if (err == ENOBUFS) if_setdrvflagbits(ifp, IFF_DRV_OACTIVE, 0); if (m != NULL) if_sendq_prepend(ifp, m); break; } if_bpfmtap(ifp, m); } } static void gen_start(if_t ifp) { struct gen_softc *sc; sc = if_getsoftc(ifp); GEN_LOCK(sc); gen_start_locked(sc); GEN_UNLOCK(sc); } /* Test for any delayed checksum */ #define CSUM_DELAY_ANY (CSUM_TCP | CSUM_UDP | CSUM_IP6_TCP | CSUM_IP6_UDP) static int gen_encap(struct gen_softc *sc, struct mbuf **mp) { bus_dmamap_t map; bus_dma_segment_t segs[TX_MAX_SEGS]; int error, nsegs, cur, first, i, index, offset; uint32_t csuminfo, length_status, csum_flags = 0, csumdata; struct mbuf *m; struct statusblock *sb = NULL; struct tx_queue *q; struct gen_ring_ent *ent; GEN_ASSERT_LOCKED(sc); q = &sc->tx_queue[DEF_TXQUEUE]; m = *mp; #ifdef ICMPV6_HACK /* * Reflected ICMPv6 packets, e.g. echo replies, tend to get laid * out with only the Ethernet header in the first mbuf, and this * doesn't seem to work. */ #define ICMP6_LEN (sizeof(struct ether_header) + sizeof(struct ip6_hdr) + \ sizeof(struct icmp6_hdr)) if (m->m_len == sizeof(struct ether_header)) { int ether_type = mtod(m, struct ether_header *)->ether_type; if (ntohs(ether_type) == ETHERTYPE_IPV6 && m->m_next->m_len >= sizeof(struct ip6_hdr)) { struct ip6_hdr *ip6; ip6 = mtod(m->m_next, struct ip6_hdr *); if (ip6->ip6_nxt == IPPROTO_ICMPV6) { m = m_pullup(m, MIN(m->m_pkthdr.len, ICMP6_LEN)); if (m == NULL) { if (sc->ifp->if_flags & IFF_DEBUG) device_printf(sc->dev, "ICMPV6 pullup fail\n"); *mp = NULL; return (ENOMEM); } } } } #undef ICMP6_LEN #endif if ((if_getcapenable(sc->ifp) & (IFCAP_TXCSUM | IFCAP_TXCSUM_IPV6)) != 0) { csum_flags = m->m_pkthdr.csum_flags; csumdata = m->m_pkthdr.csum_data; M_PREPEND(m, sizeof(struct statusblock), M_NOWAIT); if (m == NULL) { if (sc->ifp->if_flags & IFF_DEBUG) device_printf(sc->dev, "prepend fail\n"); *mp = NULL; return (ENOMEM); } offset = gen_parse_tx(m, csum_flags); sb = mtod(m, struct statusblock *); if ((csum_flags & CSUM_DELAY_ANY) != 0) { csuminfo = (offset << TXCSUM_OFF_SHIFT) | (offset + csumdata); csuminfo |= TXCSUM_LEN_VALID; if (csum_flags & (CSUM_UDP | CSUM_IP6_UDP)) csuminfo |= TXCSUM_UDP; sb->txcsuminfo = csuminfo; } else sb->txcsuminfo = 0; } *mp = m; cur = first = q->cur; ent = &q->entries[cur]; map = ent->map; error = bus_dmamap_load_mbuf_sg(sc->tx_buf_tag, map, m, segs, &nsegs, BUS_DMA_NOWAIT); if (error == EFBIG) { m = m_collapse(m, M_NOWAIT, TX_MAX_SEGS); if (m == NULL) { device_printf(sc->dev, "gen_encap: m_collapse failed\n"); m_freem(*mp); *mp = NULL; return (ENOMEM); } *mp = m; error = bus_dmamap_load_mbuf_sg(sc->tx_buf_tag, map, m, segs, &nsegs, BUS_DMA_NOWAIT); if (error != 0) { m_freem(*mp); *mp = NULL; } } if (error != 0) { device_printf(sc->dev, "gen_encap: bus_dmamap_load_mbuf_sg failed\n"); return (error); } if (nsegs == 0) { m_freem(*mp); *mp = NULL; return (EIO); } /* Remove statusblock after mapping, before possible requeue or bpf. */ if (sb != NULL) { m->m_data += sizeof(struct statusblock); m->m_len -= sizeof(struct statusblock); m->m_pkthdr.len -= sizeof(struct statusblock); } if (q->queued + nsegs > q->nentries) { bus_dmamap_unload(sc->tx_buf_tag, map); return (ENOBUFS); } bus_dmamap_sync(sc->tx_buf_tag, map, BUS_DMASYNC_PREWRITE); index = q->prod_idx & (q->nentries - 1); for (i = 0; i < nsegs; i++) { ent = &q->entries[cur]; length_status = GENET_TX_DESC_STATUS_QTAG_MASK; if (i == 0) { length_status |= GENET_TX_DESC_STATUS_SOP | GENET_TX_DESC_STATUS_CRC; if ((csum_flags & CSUM_DELAY_ANY) != 0) length_status |= GENET_TX_DESC_STATUS_CKSUM; } if (i == nsegs - 1) length_status |= GENET_TX_DESC_STATUS_EOP; length_status |= segs[i].ds_len << GENET_TX_DESC_STATUS_BUFLEN_SHIFT; WR4(sc, GENET_TX_DESC_ADDRESS_LO(index), (uint32_t)segs[i].ds_addr); WR4(sc, GENET_TX_DESC_ADDRESS_HI(index), (uint32_t)(segs[i].ds_addr >> 32)); WR4(sc, GENET_TX_DESC_STATUS(index), length_status); ++q->queued; cur = TX_NEXT(cur, q->nentries); index = TX_NEXT(index, q->nentries); } q->prod_idx += nsegs; q->prod_idx &= GENET_TX_DMA_PROD_CONS_MASK; /* We probably don't need to write the producer index on every iter */ if (nsegs != 0) WR4(sc, GENET_TX_DMA_PROD_INDEX(q->hwindex), q->prod_idx); q->cur = cur; /* Store mbuf in the last segment */ q->entries[first].mbuf = m; return (0); } /* * Parse a packet to find the offset of the transport header for checksum * offload. Ensure that the link and network headers are contiguous with * the status block, or transmission fails. */ static int gen_parse_tx(struct mbuf *m, int csum_flags) { int offset, off_in_m; bool copy = false, shift = false; u_char *p, *copy_p = NULL; struct mbuf *m0 = m; uint16_t ether_type; if (m->m_len == sizeof(struct statusblock)) { /* M_PREPEND placed statusblock at end; move to beginning */ m->m_data = m->m_pktdat; copy_p = mtodo(m, sizeof(struct statusblock)); m = m->m_next; off_in_m = 0; p = mtod(m, u_char *); copy = true; } else { /* * If statusblock is not at beginning of mbuf (likely), * then remember to move mbuf contents down before copying * after them. */ if ((m->m_flags & M_EXT) == 0 && m->m_data != m->m_pktdat) shift = true; p = mtodo(m, sizeof(struct statusblock)); off_in_m = sizeof(struct statusblock); } /* * If headers need to be copied contiguous to statusblock, do so. * If copying to the internal mbuf data area, and the status block * is not at the beginning of that area, shift the status block (which * is empty) and following data. */ #define COPY(size) { \ int hsize = size; \ if (copy) { \ if (shift) { \ u_char *p0; \ shift = false; \ p0 = mtodo(m0, sizeof(struct statusblock)); \ m0->m_data = m0->m_pktdat; \ bcopy(p0, mtodo(m0, sizeof(struct statusblock)),\ m0->m_len - sizeof(struct statusblock)); \ copy_p = mtodo(m0, sizeof(struct statusblock)); \ } \ bcopy(p, copy_p, hsize); \ m0->m_len += hsize; \ m0->m_pkthdr.len += hsize; /* unneeded */ \ m->m_len -= hsize; \ m->m_data += hsize; \ } \ copy_p += hsize; \ } KASSERT((sizeof(struct statusblock) + sizeof(struct ether_vlan_header) + sizeof(struct ip6_hdr) <= MLEN), ("%s: mbuf too small", __func__)); if (((struct ether_header *)p)->ether_type == htons(ETHERTYPE_VLAN)) { offset = sizeof(struct ether_vlan_header); ether_type = ntohs(((struct ether_vlan_header *)p)->evl_proto); COPY(sizeof(struct ether_vlan_header)); if (m->m_len == off_in_m + sizeof(struct ether_vlan_header)) { m = m->m_next; off_in_m = 0; p = mtod(m, u_char *); copy = true; } else { off_in_m += sizeof(struct ether_vlan_header); p += sizeof(struct ether_vlan_header); } } else { offset = sizeof(struct ether_header); ether_type = ntohs(((struct ether_header *)p)->ether_type); COPY(sizeof(struct ether_header)); if (m->m_len == off_in_m + sizeof(struct ether_header)) { m = m->m_next; off_in_m = 0; p = mtod(m, u_char *); copy = true; } else { off_in_m += sizeof(struct ether_header); p += sizeof(struct ether_header); } } if (ether_type == ETHERTYPE_IP) { COPY(((struct ip *)p)->ip_hl << 2); offset += ((struct ip *)p)->ip_hl << 2; } else if (ether_type == ETHERTYPE_IPV6) { COPY(sizeof(struct ip6_hdr)); offset += sizeof(struct ip6_hdr); } else { /* * Unknown whether other cases require moving a header; * ARP works without. */ } return (offset); #undef COPY } static void gen_intr(void *arg) { struct gen_softc *sc = arg; uint32_t val; GEN_LOCK(sc); val = RD4(sc, GENET_INTRL2_CPU_STAT); val &= ~RD4(sc, GENET_INTRL2_CPU_STAT_MASK); WR4(sc, GENET_INTRL2_CPU_CLEAR, val); if (val & GENET_IRQ_RXDMA_DONE) gen_rxintr(sc, &sc->rx_queue[DEF_RXQUEUE]); if (val & GENET_IRQ_TXDMA_DONE) { gen_txintr(sc, &sc->tx_queue[DEF_TXQUEUE]); if (!if_sendq_empty(sc->ifp)) gen_start_locked(sc); } GEN_UNLOCK(sc); } static int gen_rxintr(struct gen_softc *sc, struct rx_queue *q) { if_t ifp; struct mbuf *m, *mh, *mt; struct statusblock *sb = NULL; int error, index, len, cnt, npkt, n; uint32_t status, prod_idx, total; ifp = sc->ifp; mh = mt = NULL; cnt = 0; npkt = 0; prod_idx = RD4(sc, GENET_RX_DMA_PROD_INDEX(q->hwindex)) & GENET_RX_DMA_PROD_CONS_MASK; total = (prod_idx - q->cons_idx) & GENET_RX_DMA_PROD_CONS_MASK; index = q->cons_idx & (RX_DESC_COUNT - 1); for (n = 0; n < total; n++) { bus_dmamap_sync(sc->rx_buf_tag, q->entries[index].map, BUS_DMASYNC_POSTREAD | BUS_DMASYNC_POSTWRITE); bus_dmamap_unload(sc->rx_buf_tag, q->entries[index].map); m = q->entries[index].mbuf; if ((if_getcapenable(ifp) & IFCAP_RXCSUM) != 0) { sb = mtod(m, struct statusblock *); status = sb->status_buflen; } else status = RD4(sc, GENET_RX_DESC_STATUS(index)); len = (status & GENET_RX_DESC_STATUS_BUFLEN_MASK) >> GENET_RX_DESC_STATUS_BUFLEN_SHIFT; /* check for errors */ if ((status & (GENET_RX_DESC_STATUS_SOP | GENET_RX_DESC_STATUS_EOP | GENET_RX_DESC_STATUS_RX_ERROR)) != (GENET_RX_DESC_STATUS_SOP | GENET_RX_DESC_STATUS_EOP)) { if (ifp->if_flags & IFF_DEBUG) device_printf(sc->dev, "error/frag %x csum %x\n", status, sb->rxcsum); if_inc_counter(ifp, IFCOUNTER_IERRORS, 1); continue; } error = gen_newbuf_rx(sc, q, index); if (error != 0) { if_inc_counter(ifp, IFCOUNTER_IQDROPS, 1); if (ifp->if_flags & IFF_DEBUG) device_printf(sc->dev, "gen_newbuf_rx %d\n", error); /* reuse previous mbuf */ (void) gen_mapbuf_rx(sc, q, index, m); continue; } if (sb != NULL) { if (status & GENET_RX_DESC_STATUS_CKSUM_OK) { /* L4 checksum checked; not sure about L3. */ m->m_pkthdr.csum_flags = CSUM_DATA_VALID | CSUM_PSEUDO_HDR; m->m_pkthdr.csum_data = 0xffff; } m->m_data += sizeof(struct statusblock); m->m_len -= sizeof(struct statusblock); len -= sizeof(struct statusblock); } if (len > ETHER_ALIGN) { m_adj(m, ETHER_ALIGN); len -= ETHER_ALIGN; } m->m_pkthdr.rcvif = ifp; m->m_pkthdr.len = len; m->m_len = len; if_inc_counter(ifp, IFCOUNTER_IPACKETS, 1); m->m_nextpkt = NULL; if (mh == NULL) mh = m; else mt->m_nextpkt = m; mt = m; ++cnt; ++npkt; index = RX_NEXT(index, q->nentries); q->cons_idx = (q->cons_idx + 1) & GENET_RX_DMA_PROD_CONS_MASK; WR4(sc, GENET_RX_DMA_CONS_INDEX(q->hwindex), q->cons_idx); if (cnt == gen_rx_batch) { GEN_UNLOCK(sc); if_input(ifp, mh); GEN_LOCK(sc); mh = mt = NULL; cnt = 0; } } if (mh != NULL) { GEN_UNLOCK(sc); if_input(ifp, mh); GEN_LOCK(sc); } return (npkt); } static void gen_txintr(struct gen_softc *sc, struct tx_queue *q) { uint32_t cons_idx, total; struct gen_ring_ent *ent; if_t ifp; int i, prog; GEN_ASSERT_LOCKED(sc); ifp = sc->ifp; cons_idx = RD4(sc, GENET_TX_DMA_CONS_INDEX(q->hwindex)) & GENET_TX_DMA_PROD_CONS_MASK; total = (cons_idx - q->cons_idx) & GENET_TX_DMA_PROD_CONS_MASK; prog = 0; for (i = q->next; q->queued > 0 && total > 0; i = TX_NEXT(i, q->nentries), total--) { /* XXX check for errors */ ent = &q->entries[i]; if (ent->mbuf != NULL) { bus_dmamap_sync(sc->tx_buf_tag, ent->map, BUS_DMASYNC_POSTWRITE); bus_dmamap_unload(sc->tx_buf_tag, ent->map); m_freem(ent->mbuf); ent->mbuf = NULL; if_inc_counter(ifp, IFCOUNTER_OPACKETS, 1); } prog++; --q->queued; } if (prog > 0) { q->next = i; if_setdrvflagbits(ifp, 0, IFF_DRV_OACTIVE); } q->cons_idx = cons_idx; } static void gen_intr2(void *arg) { struct gen_softc *sc = arg; device_printf(sc->dev, "gen_intr2\n"); } static int gen_newbuf_rx(struct gen_softc *sc, struct rx_queue *q, int index) { struct mbuf *m; m = m_getcl(M_NOWAIT, MT_DATA, M_PKTHDR); if (m == NULL) return (ENOBUFS); m->m_pkthdr.len = m->m_len = m->m_ext.ext_size; m_adj(m, ETHER_ALIGN); return (gen_mapbuf_rx(sc, q, index, m)); } static int gen_mapbuf_rx(struct gen_softc *sc, struct rx_queue *q, int index, struct mbuf *m) { bus_dma_segment_t seg; bus_dmamap_t map; int nsegs; map = q->entries[index].map; if (bus_dmamap_load_mbuf_sg(sc->rx_buf_tag, map, m, &seg, &nsegs, BUS_DMA_NOWAIT) != 0) { m_freem(m); return (ENOBUFS); } bus_dmamap_sync(sc->rx_buf_tag, map, BUS_DMASYNC_PREREAD); q->entries[index].mbuf = m; WR4(sc, GENET_RX_DESC_ADDRESS_LO(index), (uint32_t)seg.ds_addr); WR4(sc, GENET_RX_DESC_ADDRESS_HI(index), (uint32_t)(seg.ds_addr >> 32)); return (0); } static int gen_ioctl(if_t ifp, u_long cmd, caddr_t data) { struct gen_softc *sc; struct mii_data *mii; struct ifreq *ifr; int flags, enable, error; sc = if_getsoftc(ifp); mii = device_get_softc(sc->miibus); ifr = (struct ifreq *)data; error = 0; switch (cmd) { case SIOCSIFFLAGS: GEN_LOCK(sc); if (if_getflags(ifp) & IFF_UP) { if (if_getdrvflags(ifp) & IFF_DRV_RUNNING) { flags = if_getflags(ifp) ^ sc->if_flags; if ((flags & (IFF_PROMISC|IFF_ALLMULTI)) != 0) gen_setup_rxfilter(sc); } else gen_init_locked(sc); } else { if (if_getdrvflags(ifp) & IFF_DRV_RUNNING) gen_reset(sc); } sc->if_flags = if_getflags(ifp); GEN_UNLOCK(sc); break; case SIOCADDMULTI: case SIOCDELMULTI: if (if_getdrvflags(ifp) & IFF_DRV_RUNNING) { GEN_LOCK(sc); gen_setup_rxfilter(sc); GEN_UNLOCK(sc); } break; case SIOCSIFMEDIA: case SIOCGIFMEDIA: error = ifmedia_ioctl(ifp, ifr, &mii->mii_media, cmd); break; case SIOCSIFCAP: enable = if_getcapenable(ifp); flags = ifr->ifr_reqcap ^ enable; if (flags & IFCAP_RXCSUM) enable ^= IFCAP_RXCSUM; if (flags & IFCAP_RXCSUM_IPV6) enable ^= IFCAP_RXCSUM_IPV6; if (flags & IFCAP_TXCSUM) enable ^= IFCAP_TXCSUM; if (flags & IFCAP_TXCSUM_IPV6) enable ^= IFCAP_TXCSUM_IPV6; if (enable & (IFCAP_TXCSUM | IFCAP_TXCSUM_IPV6)) if_sethwassist(ifp, GEN_CSUM_FEATURES); else if_sethwassist(ifp, 0); if_setcapenable(ifp, enable); if (if_getdrvflags(ifp) & IFF_DRV_RUNNING) gen_enable_offload(sc); break; default: error = ether_ioctl(ifp, cmd, data); break; } return (error); } static void gen_tick(void *softc) { struct gen_softc *sc; struct mii_data *mii; if_t ifp; int link; sc = softc; ifp = sc->ifp; mii = device_get_softc(sc->miibus); GEN_ASSERT_LOCKED(sc); if ((if_getdrvflags(ifp) & IFF_DRV_RUNNING) == 0) return; link = sc->link; mii_tick(mii); if (sc->link && !link) gen_start_locked(sc); callout_reset(&sc->stat_ch, hz, gen_tick, sc); } #define MII_BUSY_RETRY 1000 static int gen_miibus_readreg(device_t dev, int phy, int reg) { struct gen_softc *sc; int retry, val; sc = device_get_softc(dev); val = 0; WR4(sc, GENET_MDIO_CMD, GENET_MDIO_READ | (phy << GENET_MDIO_ADDR_SHIFT) | (reg << GENET_MDIO_REG_SHIFT)); val = RD4(sc, GENET_MDIO_CMD); WR4(sc, GENET_MDIO_CMD, val | GENET_MDIO_START_BUSY); for (retry = MII_BUSY_RETRY; retry > 0; retry--) { if (((val = RD4(sc, GENET_MDIO_CMD)) & GENET_MDIO_START_BUSY) == 0) { if (val & GENET_MDIO_READ_FAILED) return (0); /* -1? */ val &= GENET_MDIO_VAL_MASK; break; } DELAY(10); } if (retry == 0) device_printf(dev, "phy read timeout, phy=%d reg=%d\n", phy, reg); return (val); } static int gen_miibus_writereg(device_t dev, int phy, int reg, int val) { struct gen_softc *sc; int retry; sc = device_get_softc(dev); WR4(sc, GENET_MDIO_CMD, GENET_MDIO_WRITE | (phy << GENET_MDIO_ADDR_SHIFT) | (reg << GENET_MDIO_REG_SHIFT) | (val & GENET_MDIO_VAL_MASK)); val = RD4(sc, GENET_MDIO_CMD); WR4(sc, GENET_MDIO_CMD, val | GENET_MDIO_START_BUSY); for (retry = MII_BUSY_RETRY; retry > 0; retry--) { val = RD4(sc, GENET_MDIO_CMD); if ((val & GENET_MDIO_START_BUSY) == 0) break; DELAY(10); } if (retry == 0) device_printf(dev, "phy write timeout, phy=%d reg=%d\n", phy, reg); return (0); } static void gen_update_link_locked(struct gen_softc *sc) { struct mii_data *mii; uint32_t val; u_int speed; GEN_ASSERT_LOCKED(sc); if ((if_getdrvflags(sc->ifp) & IFF_DRV_RUNNING) == 0) return; mii = device_get_softc(sc->miibus); if ((mii->mii_media_status & (IFM_ACTIVE | IFM_AVALID)) == (IFM_ACTIVE | IFM_AVALID)) { switch (IFM_SUBTYPE(mii->mii_media_active)) { case IFM_1000_T: case IFM_1000_SX: speed = GENET_UMAC_CMD_SPEED_1000; sc->link = 1; break; case IFM_100_TX: speed = GENET_UMAC_CMD_SPEED_100; sc->link = 1; break; case IFM_10_T: speed = GENET_UMAC_CMD_SPEED_10; sc->link = 1; break; default: sc->link = 0; break; } } else sc->link = 0; if (sc->link == 0) return; val = RD4(sc, GENET_EXT_RGMII_OOB_CTRL); val &= ~GENET_EXT_RGMII_OOB_OOB_DISABLE; val |= GENET_EXT_RGMII_OOB_RGMII_LINK; val |= GENET_EXT_RGMII_OOB_RGMII_MODE_EN; if (sc->phy_mode == MII_CONTYPE_RGMII) val |= GENET_EXT_RGMII_OOB_ID_MODE_DISABLE; + else + val &= ~GENET_EXT_RGMII_OOB_ID_MODE_DISABLE; WR4(sc, GENET_EXT_RGMII_OOB_CTRL, val); val = RD4(sc, GENET_UMAC_CMD); val &= ~GENET_UMAC_CMD_SPEED; val |= speed; WR4(sc, GENET_UMAC_CMD, val); } static void gen_link_task(void *arg, int pending) { struct gen_softc *sc; sc = arg; GEN_LOCK(sc); gen_update_link_locked(sc); GEN_UNLOCK(sc); } static void gen_miibus_statchg(device_t dev) { struct gen_softc *sc; sc = device_get_softc(dev); taskqueue_enqueue(taskqueue_swi, &sc->link_task); } static void gen_media_status(if_t ifp, struct ifmediareq *ifmr) { struct gen_softc *sc; struct mii_data *mii; sc = if_getsoftc(ifp); mii = device_get_softc(sc->miibus); GEN_LOCK(sc); mii_pollstat(mii); ifmr->ifm_active = mii->mii_media_active; ifmr->ifm_status = mii->mii_media_status; GEN_UNLOCK(sc); } static int gen_media_change(if_t ifp) { struct gen_softc *sc; struct mii_data *mii; int error; sc = if_getsoftc(ifp); mii = device_get_softc(sc->miibus); GEN_LOCK(sc); error = mii_mediachg(mii); GEN_UNLOCK(sc); return (error); } static device_method_t gen_methods[] = { /* Device interface */ DEVMETHOD(device_probe, gen_probe), DEVMETHOD(device_attach, gen_attach), /* MII interface */ DEVMETHOD(miibus_readreg, gen_miibus_readreg), DEVMETHOD(miibus_writereg, gen_miibus_writereg), DEVMETHOD(miibus_statchg, gen_miibus_statchg), DEVMETHOD_END }; static driver_t gen_driver = { "genet", gen_methods, sizeof(struct gen_softc), }; static devclass_t gen_devclass; DRIVER_MODULE(genet, simplebus, gen_driver, gen_devclass, 0, 0); DRIVER_MODULE(miibus, genet, miibus_driver, miibus_devclass, 0, 0); MODULE_DEPEND(genet, ether, 1, 1, 1); MODULE_DEPEND(genet, miibus, 1, 1, 1); Index: head/sys/dev/mii/brgphy.c =================================================================== --- head/sys/dev/mii/brgphy.c (revision 362352) +++ head/sys/dev/mii/brgphy.c (revision 362353) @@ -1,1096 +1,1135 @@ /*- * SPDX-License-Identifier: BSD-4-Clause * * Copyright (c) 2000 * Bill Paul . All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * 3. All advertising materials mentioning features or use of this software * must display the following acknowledgement: * This product includes software developed by Bill Paul. * 4. Neither the name of the author nor the names of any co-contributors * may be used to endorse or promote products derived from this software * without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY Bill Paul AND CONTRIBUTORS ``AS IS'' AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL Bill Paul OR THE VOICES IN HIS HEAD * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF * THE POSSIBILITY OF SUCH DAMAGE. */ #include __FBSDID("$FreeBSD$"); /* * Driver for the Broadcom BCM54xx/57xx 1000baseTX PHY. */ #include #include #include #include #include #include #include #include #include #include #include #include #include #include "miidevs.h" #include #include #include #include #include #include #include #include "miibus_if.h" static int brgphy_probe(device_t); static int brgphy_attach(device_t); struct brgphy_softc { struct mii_softc mii_sc; int serdes_flags; /* Keeps track of the serdes type used */ #define BRGPHY_5706S 0x0001 #define BRGPHY_5708S 0x0002 #define BRGPHY_NOANWAIT 0x0004 #define BRGPHY_5709S 0x0008 int bce_phy_flags; /* PHY flags transferred from the MAC driver */ }; static device_method_t brgphy_methods[] = { /* device interface */ DEVMETHOD(device_probe, brgphy_probe), DEVMETHOD(device_attach, brgphy_attach), DEVMETHOD(device_detach, mii_phy_detach), DEVMETHOD(device_shutdown, bus_generic_shutdown), DEVMETHOD_END }; static devclass_t brgphy_devclass; static driver_t brgphy_driver = { "brgphy", brgphy_methods, sizeof(struct brgphy_softc) }; DRIVER_MODULE(brgphy, miibus, brgphy_driver, brgphy_devclass, 0, 0); static int brgphy_service(struct mii_softc *, struct mii_data *, int); static void brgphy_setmedia(struct mii_softc *, int); static void brgphy_status(struct mii_softc *); static void brgphy_mii_phy_auto(struct mii_softc *, int); static void brgphy_reset(struct mii_softc *); static void brgphy_enable_loopback(struct mii_softc *); static void bcm5401_load_dspcode(struct mii_softc *); static void bcm5411_load_dspcode(struct mii_softc *); static void bcm54k2_load_dspcode(struct mii_softc *); static void brgphy_fixup_5704_a0_bug(struct mii_softc *); static void brgphy_fixup_adc_bug(struct mii_softc *); static void brgphy_fixup_adjust_trim(struct mii_softc *); static void brgphy_fixup_ber_bug(struct mii_softc *); static void brgphy_fixup_crc_bug(struct mii_softc *); static void brgphy_fixup_jitter_bug(struct mii_softc *); static void brgphy_ethernet_wirespeed(struct mii_softc *); +static void brgphy_bcm54xx_clock_delay(struct mii_softc *); static void brgphy_jumbo_settings(struct mii_softc *, u_long); static const struct mii_phydesc brgphys[] = { MII_PHY_DESC(BROADCOM, BCM5400), MII_PHY_DESC(BROADCOM, BCM5401), MII_PHY_DESC(BROADCOM, BCM5402), MII_PHY_DESC(BROADCOM, BCM5411), MII_PHY_DESC(BROADCOM, BCM5404), MII_PHY_DESC(BROADCOM, BCM5424), MII_PHY_DESC(BROADCOM, BCM54K2), MII_PHY_DESC(BROADCOM, BCM5701), MII_PHY_DESC(BROADCOM, BCM5703), MII_PHY_DESC(BROADCOM, BCM5704), MII_PHY_DESC(BROADCOM, BCM5705), MII_PHY_DESC(BROADCOM, BCM5706), MII_PHY_DESC(BROADCOM, BCM5714), MII_PHY_DESC(BROADCOM, BCM5421), MII_PHY_DESC(BROADCOM, BCM5750), MII_PHY_DESC(BROADCOM, BCM5752), MII_PHY_DESC(BROADCOM, BCM5780), MII_PHY_DESC(BROADCOM, BCM5708C), MII_PHY_DESC(BROADCOM, BCM5466), MII_PHY_DESC(BROADCOM2, BCM5478), MII_PHY_DESC(BROADCOM2, BCM5488), MII_PHY_DESC(BROADCOM2, BCM5482), MII_PHY_DESC(BROADCOM2, BCM5708S), MII_PHY_DESC(BROADCOM2, BCM5709C), MII_PHY_DESC(BROADCOM2, BCM5709S), MII_PHY_DESC(BROADCOM2, BCM5709CAX), MII_PHY_DESC(BROADCOM2, BCM5722), MII_PHY_DESC(BROADCOM2, BCM5755), MII_PHY_DESC(BROADCOM2, BCM5754), MII_PHY_DESC(BROADCOM2, BCM5761), MII_PHY_DESC(BROADCOM2, BCM5784), #ifdef notyet /* better handled by ukphy(4) until WARs are implemented */ MII_PHY_DESC(BROADCOM2, BCM5785), #endif MII_PHY_DESC(BROADCOM3, BCM54618SE), MII_PHY_DESC(BROADCOM3, BCM5717C), MII_PHY_DESC(BROADCOM3, BCM5719C), MII_PHY_DESC(BROADCOM3, BCM5720C), MII_PHY_DESC(BROADCOM3, BCM57765), MII_PHY_DESC(BROADCOM3, BCM57780), + MII_PHY_DESC(BROADCOM4, BCM54213PE), MII_PHY_DESC(BROADCOM4, BCM5725C), MII_PHY_DESC(xxBROADCOM_ALT1, BCM5906), MII_PHY_END }; static const struct mii_phy_funcs brgphy_funcs = { brgphy_service, brgphy_status, brgphy_reset }; static const struct hs21_type { const uint32_t id; const char *prod; } hs21_type_lists[] = { { 0x57081021, "IBM eServer BladeCenter HS21" }, { 0x57081011, "IBM eServer BladeCenter HS21 -[8853PAU]-" }, }; static int detect_hs21(struct bce_softc *bce_sc) { char *sysenv; int found, i; found = 0; sysenv = kern_getenv("smbios.system.product"); if (sysenv == NULL) return (found); for (i = 0; i < nitems(hs21_type_lists); i++) { if (bce_sc->bce_chipid == hs21_type_lists[i].id && strncmp(sysenv, hs21_type_lists[i].prod, strlen(hs21_type_lists[i].prod)) == 0) { found++; break; } } freeenv(sysenv); return (found); } /* Search for our PHY in the list of known PHYs */ static int brgphy_probe(device_t dev) { return (mii_phy_dev_probe(dev, brgphys, BUS_PROBE_DEFAULT)); } /* Attach the PHY to the MII bus */ static int brgphy_attach(device_t dev) { struct brgphy_softc *bsc; struct bge_softc *bge_sc = NULL; struct bce_softc *bce_sc = NULL; struct mii_softc *sc; bsc = device_get_softc(dev); sc = &bsc->mii_sc; mii_phy_dev_attach(dev, MIIF_NOISOLATE | MIIF_NOMANPAUSE, &brgphy_funcs, 0); bsc->serdes_flags = 0; /* Find the MAC driver associated with this PHY. */ if (mii_dev_mac_match(dev, "bge")) bge_sc = mii_dev_mac_softc(dev); else if (mii_dev_mac_match(dev, "bce")) bce_sc = mii_dev_mac_softc(dev); /* Handle any special cases based on the PHY ID */ switch (sc->mii_mpd_oui) { case MII_OUI_BROADCOM: switch (sc->mii_mpd_model) { case MII_MODEL_BROADCOM_BCM5706: case MII_MODEL_BROADCOM_BCM5714: /* * The 5464 PHY used in the 5706 supports both copper * and fiber interfaces over GMII. Need to check the * shadow registers to see which mode is actually * in effect, and therefore whether we have 5706C or * 5706S. */ PHY_WRITE(sc, BRGPHY_MII_SHADOW_1C, BRGPHY_SHADOW_1C_MODE_CTRL); if (PHY_READ(sc, BRGPHY_MII_SHADOW_1C) & BRGPHY_SHADOW_1C_ENA_1000X) { bsc->serdes_flags |= BRGPHY_5706S; sc->mii_flags |= MIIF_HAVEFIBER; } break; } break; case MII_OUI_BROADCOM2: switch (sc->mii_mpd_model) { case MII_MODEL_BROADCOM2_BCM5708S: bsc->serdes_flags |= BRGPHY_5708S; sc->mii_flags |= MIIF_HAVEFIBER; break; case MII_MODEL_BROADCOM2_BCM5709S: /* * XXX * 5720S and 5709S shares the same PHY id. * Assume 5720S PHY if parent device is bge(4). */ if (bge_sc != NULL) bsc->serdes_flags |= BRGPHY_5708S; else bsc->serdes_flags |= BRGPHY_5709S; sc->mii_flags |= MIIF_HAVEFIBER; break; } break; } PHY_RESET(sc); /* Read the PHY's capabilities. */ sc->mii_capabilities = PHY_READ(sc, MII_BMSR) & sc->mii_capmask; if (sc->mii_capabilities & BMSR_EXTSTAT) sc->mii_extcapabilities = PHY_READ(sc, MII_EXTSR); device_printf(dev, " "); /* Add the supported media types */ if ((sc->mii_flags & MIIF_HAVEFIBER) == 0) { mii_phy_add_media(sc); printf("\n"); } else { sc->mii_anegticks = MII_ANEGTICKS_GIGE; ifmedia_add(&sc->mii_pdata->mii_media, IFM_MAKEWORD(IFM_ETHER, IFM_1000_SX, IFM_FDX, sc->mii_inst), 0, NULL); printf("1000baseSX-FDX, "); /* * 2.5G support is a software enabled feature * on the 5708S and 5709S. */ if (bce_sc && (bce_sc->bce_phy_flags & BCE_PHY_2_5G_CAPABLE_FLAG)) { ifmedia_add(&sc->mii_pdata->mii_media, IFM_MAKEWORD(IFM_ETHER, IFM_2500_SX, IFM_FDX, sc->mii_inst), 0, NULL); printf("2500baseSX-FDX, "); } else if ((bsc->serdes_flags & BRGPHY_5708S) && bce_sc && (detect_hs21(bce_sc) != 0)) { /* * There appears to be certain silicon revision * in IBM HS21 blades that is having issues with * this driver wating for the auto-negotiation to * complete. This happens with a specific chip id * only and when the 1000baseSX-FDX is the only * mode. Workaround this issue since it's unlikely * to be ever addressed. */ printf("auto-neg workaround, "); bsc->serdes_flags |= BRGPHY_NOANWAIT; } ifmedia_add(&sc->mii_pdata->mii_media, IFM_MAKEWORD(IFM_ETHER, IFM_AUTO, 0, sc->mii_inst), 0, NULL); printf("auto\n"); } MIIBUS_MEDIAINIT(sc->mii_dev); return (0); } static int brgphy_service(struct mii_softc *sc, struct mii_data *mii, int cmd) { struct ifmedia_entry *ife = mii->mii_media.ifm_cur; int val; switch (cmd) { case MII_POLLSTAT: break; case MII_MEDIACHG: /* Todo: Why is this here? Is it really needed? */ PHY_RESET(sc); /* XXX hardware bug work-around */ switch (IFM_SUBTYPE(ife->ifm_media)) { case IFM_AUTO: brgphy_mii_phy_auto(sc, ife->ifm_media); break; case IFM_2500_SX: case IFM_1000_SX: case IFM_1000_T: case IFM_100_TX: case IFM_10_T: brgphy_setmedia(sc, ife->ifm_media); break; default: return (EINVAL); } break; case MII_TICK: /* Bail if autoneg isn't in process. */ if (IFM_SUBTYPE(ife->ifm_media) != IFM_AUTO) { sc->mii_ticks = 0; break; } /* * Check to see if we have link. If we do, we don't * need to restart the autonegotiation process. */ val = PHY_READ(sc, MII_BMSR) | PHY_READ(sc, MII_BMSR); if (val & BMSR_LINK) { sc->mii_ticks = 0; /* Reset autoneg timer. */ break; } /* Announce link loss right after it happens. */ if (sc->mii_ticks++ == 0) break; /* Only retry autonegotiation every mii_anegticks seconds. */ if (sc->mii_ticks <= sc->mii_anegticks) break; /* Retry autonegotiation */ sc->mii_ticks = 0; brgphy_mii_phy_auto(sc, ife->ifm_media); break; } /* Update the media status. */ PHY_STATUS(sc); /* * Callback if something changed. Note that we need to poke * the DSP on the Broadcom PHYs if the media changes. */ if (sc->mii_media_active != mii->mii_media_active || sc->mii_media_status != mii->mii_media_status || cmd == MII_MEDIACHG) { switch (sc->mii_mpd_oui) { case MII_OUI_BROADCOM: switch (sc->mii_mpd_model) { case MII_MODEL_BROADCOM_BCM5400: bcm5401_load_dspcode(sc); break; case MII_MODEL_BROADCOM_BCM5401: if (sc->mii_mpd_rev == 1 || sc->mii_mpd_rev == 3) bcm5401_load_dspcode(sc); break; case MII_MODEL_BROADCOM_BCM5411: bcm5411_load_dspcode(sc); break; case MII_MODEL_BROADCOM_BCM54K2: bcm54k2_load_dspcode(sc); break; } break; + case MII_OUI_BROADCOM4: + switch (sc->mii_mpd_model) { + case MII_MODEL_BROADCOM4_BCM54213PE: + brgphy_bcm54xx_clock_delay(sc); + break; + } } } mii_phy_update(sc, cmd); return (0); } /****************************************************************************/ /* Sets the PHY link speed. */ /* */ /* Returns: */ /* None */ /****************************************************************************/ static void brgphy_setmedia(struct mii_softc *sc, int media) { int bmcr = 0, gig; switch (IFM_SUBTYPE(media)) { case IFM_2500_SX: break; case IFM_1000_SX: case IFM_1000_T: bmcr = BRGPHY_S1000; break; case IFM_100_TX: bmcr = BRGPHY_S100; break; case IFM_10_T: default: bmcr = BRGPHY_S10; break; } if ((media & IFM_FDX) != 0) { bmcr |= BRGPHY_BMCR_FDX; gig = BRGPHY_1000CTL_AFD; } else { gig = BRGPHY_1000CTL_AHD; } /* Force loopback to disconnect PHY from Ethernet medium. */ brgphy_enable_loopback(sc); PHY_WRITE(sc, BRGPHY_MII_1000CTL, 0); PHY_WRITE(sc, BRGPHY_MII_ANAR, BRGPHY_SEL_TYPE); if (IFM_SUBTYPE(media) != IFM_1000_T && IFM_SUBTYPE(media) != IFM_1000_SX) { PHY_WRITE(sc, BRGPHY_MII_BMCR, bmcr); return; } if (IFM_SUBTYPE(media) == IFM_1000_T) { gig |= BRGPHY_1000CTL_MSE; if ((media & IFM_ETH_MASTER) != 0) gig |= BRGPHY_1000CTL_MSC; } PHY_WRITE(sc, BRGPHY_MII_1000CTL, gig); PHY_WRITE(sc, BRGPHY_MII_BMCR, bmcr | BRGPHY_BMCR_AUTOEN | BRGPHY_BMCR_STARTNEG); } /****************************************************************************/ /* Set the media status based on the PHY settings. */ /* */ /* Returns: */ /* None */ /****************************************************************************/ static void brgphy_status(struct mii_softc *sc) { struct brgphy_softc *bsc = (struct brgphy_softc *)sc; struct mii_data *mii = sc->mii_pdata; int aux, bmcr, bmsr, val, xstat; u_int flowstat; mii->mii_media_status = IFM_AVALID; mii->mii_media_active = IFM_ETHER; bmsr = PHY_READ(sc, BRGPHY_MII_BMSR) | PHY_READ(sc, BRGPHY_MII_BMSR); bmcr = PHY_READ(sc, BRGPHY_MII_BMCR); if (bmcr & BRGPHY_BMCR_LOOP) { mii->mii_media_active |= IFM_LOOP; } if ((bmcr & BRGPHY_BMCR_AUTOEN) && (bmsr & BRGPHY_BMSR_ACOMP) == 0 && (bsc->serdes_flags & BRGPHY_NOANWAIT) == 0) { /* Erg, still trying, I guess... */ mii->mii_media_active |= IFM_NONE; return; } if ((sc->mii_flags & MIIF_HAVEFIBER) == 0) { /* * NB: reading the ANAR, ANLPAR or 1000STS after the AUXSTS * wedges at least the PHY of BCM5704 (but not others). */ flowstat = mii_phy_flowstatus(sc); xstat = PHY_READ(sc, BRGPHY_MII_1000STS); aux = PHY_READ(sc, BRGPHY_MII_AUXSTS); /* If copper link is up, get the negotiated speed/duplex. */ if (aux & BRGPHY_AUXSTS_LINK) { mii->mii_media_status |= IFM_ACTIVE; switch (aux & BRGPHY_AUXSTS_AN_RES) { case BRGPHY_RES_1000FD: mii->mii_media_active |= IFM_1000_T | IFM_FDX; break; case BRGPHY_RES_1000HD: mii->mii_media_active |= IFM_1000_T | IFM_HDX; break; case BRGPHY_RES_100FD: mii->mii_media_active |= IFM_100_TX | IFM_FDX; break; case BRGPHY_RES_100T4: mii->mii_media_active |= IFM_100_T4; break; case BRGPHY_RES_100HD: mii->mii_media_active |= IFM_100_TX | IFM_HDX; break; case BRGPHY_RES_10FD: mii->mii_media_active |= IFM_10_T | IFM_FDX; break; case BRGPHY_RES_10HD: mii->mii_media_active |= IFM_10_T | IFM_HDX; break; default: mii->mii_media_active |= IFM_NONE; break; } if ((mii->mii_media_active & IFM_FDX) != 0) mii->mii_media_active |= flowstat; if (IFM_SUBTYPE(mii->mii_media_active) == IFM_1000_T && (xstat & BRGPHY_1000STS_MSR) != 0) mii->mii_media_active |= IFM_ETH_MASTER; } } else { /* Todo: Add support for flow control. */ /* If serdes link is up, get the negotiated speed/duplex. */ if (bmsr & BRGPHY_BMSR_LINK) { mii->mii_media_status |= IFM_ACTIVE; } /* Check the link speed/duplex based on the PHY type. */ if (bsc->serdes_flags & BRGPHY_5706S) { mii->mii_media_active |= IFM_1000_SX; /* If autoneg enabled, read negotiated duplex settings */ if (bmcr & BRGPHY_BMCR_AUTOEN) { val = PHY_READ(sc, BRGPHY_SERDES_ANAR) & PHY_READ(sc, BRGPHY_SERDES_ANLPAR); if (val & BRGPHY_SERDES_ANAR_FDX) mii->mii_media_active |= IFM_FDX; else mii->mii_media_active |= IFM_HDX; } } else if (bsc->serdes_flags & BRGPHY_5708S) { PHY_WRITE(sc, BRGPHY_5708S_BLOCK_ADDR, BRGPHY_5708S_DIG_PG0); xstat = PHY_READ(sc, BRGPHY_5708S_PG0_1000X_STAT1); /* Check for MRBE auto-negotiated speed results. */ switch (xstat & BRGPHY_5708S_PG0_1000X_STAT1_SPEED_MASK) { case BRGPHY_5708S_PG0_1000X_STAT1_SPEED_10: mii->mii_media_active |= IFM_10_FL; break; case BRGPHY_5708S_PG0_1000X_STAT1_SPEED_100: mii->mii_media_active |= IFM_100_FX; break; case BRGPHY_5708S_PG0_1000X_STAT1_SPEED_1G: mii->mii_media_active |= IFM_1000_SX; break; case BRGPHY_5708S_PG0_1000X_STAT1_SPEED_25G: mii->mii_media_active |= IFM_2500_SX; break; } /* Check for MRBE auto-negotiated duplex results. */ if (xstat & BRGPHY_5708S_PG0_1000X_STAT1_FDX) mii->mii_media_active |= IFM_FDX; else mii->mii_media_active |= IFM_HDX; } else if (bsc->serdes_flags & BRGPHY_5709S) { /* Select GP Status Block of the AN MMD, get autoneg results. */ PHY_WRITE(sc, BRGPHY_BLOCK_ADDR, BRGPHY_BLOCK_ADDR_GP_STATUS); xstat = PHY_READ(sc, BRGPHY_GP_STATUS_TOP_ANEG_STATUS); /* Restore IEEE0 block (assumed in all brgphy(4) code). */ PHY_WRITE(sc, BRGPHY_BLOCK_ADDR, BRGPHY_BLOCK_ADDR_COMBO_IEEE0); /* Check for MRBE auto-negotiated speed results. */ switch (xstat & BRGPHY_GP_STATUS_TOP_ANEG_SPEED_MASK) { case BRGPHY_GP_STATUS_TOP_ANEG_SPEED_10: mii->mii_media_active |= IFM_10_FL; break; case BRGPHY_GP_STATUS_TOP_ANEG_SPEED_100: mii->mii_media_active |= IFM_100_FX; break; case BRGPHY_GP_STATUS_TOP_ANEG_SPEED_1G: mii->mii_media_active |= IFM_1000_SX; break; case BRGPHY_GP_STATUS_TOP_ANEG_SPEED_25G: mii->mii_media_active |= IFM_2500_SX; break; } /* Check for MRBE auto-negotiated duplex results. */ if (xstat & BRGPHY_GP_STATUS_TOP_ANEG_FDX) mii->mii_media_active |= IFM_FDX; else mii->mii_media_active |= IFM_HDX; } } } static void brgphy_mii_phy_auto(struct mii_softc *sc, int media) { int anar, ktcr = 0; PHY_RESET(sc); if ((sc->mii_flags & MIIF_HAVEFIBER) == 0) { anar = BMSR_MEDIA_TO_ANAR(sc->mii_capabilities) | ANAR_CSMA; if ((media & IFM_FLOW) != 0 || (sc->mii_flags & MIIF_FORCEPAUSE) != 0) anar |= BRGPHY_ANAR_PC | BRGPHY_ANAR_ASP; PHY_WRITE(sc, BRGPHY_MII_ANAR, anar); ktcr = BRGPHY_1000CTL_AFD | BRGPHY_1000CTL_AHD; if (sc->mii_mpd_model == MII_MODEL_BROADCOM_BCM5701) ktcr |= BRGPHY_1000CTL_MSE | BRGPHY_1000CTL_MSC; PHY_WRITE(sc, BRGPHY_MII_1000CTL, ktcr); PHY_READ(sc, BRGPHY_MII_1000CTL); } else { anar = BRGPHY_SERDES_ANAR_FDX | BRGPHY_SERDES_ANAR_HDX; if ((media & IFM_FLOW) != 0 || (sc->mii_flags & MIIF_FORCEPAUSE) != 0) anar |= BRGPHY_SERDES_ANAR_BOTH_PAUSE; PHY_WRITE(sc, BRGPHY_SERDES_ANAR, anar); } PHY_WRITE(sc, BRGPHY_MII_BMCR, BRGPHY_BMCR_AUTOEN | BRGPHY_BMCR_STARTNEG); PHY_WRITE(sc, BRGPHY_MII_IMR, 0xFF00); } /* Enable loopback to force the link down. */ static void brgphy_enable_loopback(struct mii_softc *sc) { int i; PHY_WRITE(sc, BRGPHY_MII_BMCR, BRGPHY_BMCR_LOOP); for (i = 0; i < 15000; i++) { if (!(PHY_READ(sc, BRGPHY_MII_BMSR) & BRGPHY_BMSR_LINK)) break; DELAY(10); } } /* Turn off tap power management on 5401. */ static void bcm5401_load_dspcode(struct mii_softc *sc) { static const struct { int reg; uint16_t val; } dspcode[] = { { BRGPHY_MII_AUXCTL, 0x0c20 }, { BRGPHY_MII_DSP_ADDR_REG, 0x0012 }, { BRGPHY_MII_DSP_RW_PORT, 0x1804 }, { BRGPHY_MII_DSP_ADDR_REG, 0x0013 }, { BRGPHY_MII_DSP_RW_PORT, 0x1204 }, { BRGPHY_MII_DSP_ADDR_REG, 0x8006 }, { BRGPHY_MII_DSP_RW_PORT, 0x0132 }, { BRGPHY_MII_DSP_ADDR_REG, 0x8006 }, { BRGPHY_MII_DSP_RW_PORT, 0x0232 }, { BRGPHY_MII_DSP_ADDR_REG, 0x201f }, { BRGPHY_MII_DSP_RW_PORT, 0x0a20 }, { 0, 0 }, }; int i; for (i = 0; dspcode[i].reg != 0; i++) PHY_WRITE(sc, dspcode[i].reg, dspcode[i].val); DELAY(40); } static void bcm5411_load_dspcode(struct mii_softc *sc) { static const struct { int reg; uint16_t val; } dspcode[] = { { 0x1c, 0x8c23 }, { 0x1c, 0x8ca3 }, { 0x1c, 0x8c23 }, { 0, 0 }, }; int i; for (i = 0; dspcode[i].reg != 0; i++) PHY_WRITE(sc, dspcode[i].reg, dspcode[i].val); } void bcm54k2_load_dspcode(struct mii_softc *sc) { static const struct { int reg; uint16_t val; } dspcode[] = { { 4, 0x01e1 }, { 9, 0x0300 }, { 0, 0 }, }; int i; for (i = 0; dspcode[i].reg != 0; i++) PHY_WRITE(sc, dspcode[i].reg, dspcode[i].val); } static void brgphy_fixup_5704_a0_bug(struct mii_softc *sc) { static const struct { int reg; uint16_t val; } dspcode[] = { { 0x1c, 0x8d68 }, { 0x1c, 0x8d68 }, { 0, 0 }, }; int i; for (i = 0; dspcode[i].reg != 0; i++) PHY_WRITE(sc, dspcode[i].reg, dspcode[i].val); } static void brgphy_fixup_adc_bug(struct mii_softc *sc) { static const struct { int reg; uint16_t val; } dspcode[] = { { BRGPHY_MII_AUXCTL, 0x0c00 }, { BRGPHY_MII_DSP_ADDR_REG, 0x201f }, { BRGPHY_MII_DSP_RW_PORT, 0x2aaa }, { 0, 0 }, }; int i; for (i = 0; dspcode[i].reg != 0; i++) PHY_WRITE(sc, dspcode[i].reg, dspcode[i].val); } static void brgphy_fixup_adjust_trim(struct mii_softc *sc) { static const struct { int reg; uint16_t val; } dspcode[] = { { BRGPHY_MII_AUXCTL, 0x0c00 }, { BRGPHY_MII_DSP_ADDR_REG, 0x000a }, { BRGPHY_MII_DSP_RW_PORT, 0x110b }, { BRGPHY_MII_TEST1, 0x0014 }, { BRGPHY_MII_AUXCTL, 0x0400 }, { 0, 0 }, }; int i; for (i = 0; dspcode[i].reg != 0; i++) PHY_WRITE(sc, dspcode[i].reg, dspcode[i].val); } static void brgphy_fixup_ber_bug(struct mii_softc *sc) { static const struct { int reg; uint16_t val; } dspcode[] = { { BRGPHY_MII_AUXCTL, 0x0c00 }, { BRGPHY_MII_DSP_ADDR_REG, 0x000a }, { BRGPHY_MII_DSP_RW_PORT, 0x310b }, { BRGPHY_MII_DSP_ADDR_REG, 0x201f }, { BRGPHY_MII_DSP_RW_PORT, 0x9506 }, { BRGPHY_MII_DSP_ADDR_REG, 0x401f }, { BRGPHY_MII_DSP_RW_PORT, 0x14e2 }, { BRGPHY_MII_AUXCTL, 0x0400 }, { 0, 0 }, }; int i; for (i = 0; dspcode[i].reg != 0; i++) PHY_WRITE(sc, dspcode[i].reg, dspcode[i].val); } static void brgphy_fixup_crc_bug(struct mii_softc *sc) { static const struct { int reg; uint16_t val; } dspcode[] = { { BRGPHY_MII_DSP_RW_PORT, 0x0a75 }, { 0x1c, 0x8c68 }, { 0x1c, 0x8d68 }, { 0x1c, 0x8c68 }, { 0, 0 }, }; int i; for (i = 0; dspcode[i].reg != 0; i++) PHY_WRITE(sc, dspcode[i].reg, dspcode[i].val); } static void brgphy_fixup_jitter_bug(struct mii_softc *sc) { static const struct { int reg; uint16_t val; } dspcode[] = { { BRGPHY_MII_AUXCTL, 0x0c00 }, { BRGPHY_MII_DSP_ADDR_REG, 0x000a }, { BRGPHY_MII_DSP_RW_PORT, 0x010b }, { BRGPHY_MII_AUXCTL, 0x0400 }, { 0, 0 }, }; int i; for (i = 0; dspcode[i].reg != 0; i++) PHY_WRITE(sc, dspcode[i].reg, dspcode[i].val); } static void brgphy_fixup_disable_early_dac(struct mii_softc *sc) { uint32_t val; PHY_WRITE(sc, BRGPHY_MII_DSP_ADDR_REG, 0x0f08); val = PHY_READ(sc, BRGPHY_MII_DSP_RW_PORT); val &= ~(1 << 8); PHY_WRITE(sc, BRGPHY_MII_DSP_RW_PORT, val); } static void brgphy_ethernet_wirespeed(struct mii_softc *sc) { uint32_t val; /* Enable Ethernet@WireSpeed. */ PHY_WRITE(sc, BRGPHY_MII_AUXCTL, 0x7007); val = PHY_READ(sc, BRGPHY_MII_AUXCTL); PHY_WRITE(sc, BRGPHY_MII_AUXCTL, val | (1 << 15) | (1 << 4)); +} + +static void +brgphy_bcm54xx_clock_delay(struct mii_softc *sc) +{ + uint16_t val; + + if (!(sc->mii_flags & (MIIF_RX_DELAY | MIIF_TX_DELAY))) + /* Adjusting the clocks in rgmii mode causes packet losses. */ + return; + + PHY_WRITE(sc, BRGPHY_MII_AUXCTL, BRGPHY_AUXCTL_SHADOW_MISC | + BRGPHY_AUXCTL_SHADOW_MISC << BRGPHY_AUXCTL_MISC_READ_SHIFT); + val = PHY_READ(sc, BRGPHY_MII_AUXCTL); + val &= BRGPHY_AUXCTL_MISC_DATA_MASK; + if (sc->mii_flags & MIIF_RX_DELAY) + val |= BRGPHY_AUXCTL_MISC_RGMII_SKEW_EN; + else + val &= ~BRGPHY_AUXCTL_MISC_RGMII_SKEW_EN; + PHY_WRITE(sc, BRGPHY_MII_AUXCTL, BRGPHY_AUXCTL_MISC_WRITE_EN | + BRGPHY_AUXCTL_SHADOW_MISC | val); + + PHY_WRITE(sc, BRGPHY_MII_SHADOW_1C, BRGPHY_SHADOW_1C_CLK_CTRL); + val = PHY_READ(sc, BRGPHY_MII_SHADOW_1C); + val &= BRGPHY_SHADOW_1C_DATA_MASK; + if (sc->mii_flags & MIIF_TX_DELAY) + val |= BRGPHY_SHADOW_1C_GTXCLK_EN; + else + val &= ~BRGPHY_SHADOW_1C_GTXCLK_EN; + PHY_WRITE(sc, BRGPHY_MII_SHADOW_1C, BRGPHY_SHADOW_1C_WRITE_EN | + BRGPHY_SHADOW_1C_CLK_CTRL | val); } static void brgphy_jumbo_settings(struct mii_softc *sc, u_long mtu) { uint32_t val; /* Set or clear jumbo frame settings in the PHY. */ if (mtu > ETHER_MAX_LEN) { if (sc->mii_mpd_model == MII_MODEL_BROADCOM_BCM5401) { /* BCM5401 PHY cannot read-modify-write. */ PHY_WRITE(sc, BRGPHY_MII_AUXCTL, 0x4c20); } else { PHY_WRITE(sc, BRGPHY_MII_AUXCTL, 0x7); val = PHY_READ(sc, BRGPHY_MII_AUXCTL); PHY_WRITE(sc, BRGPHY_MII_AUXCTL, val | BRGPHY_AUXCTL_LONG_PKT); } val = PHY_READ(sc, BRGPHY_MII_PHY_EXTCTL); PHY_WRITE(sc, BRGPHY_MII_PHY_EXTCTL, val | BRGPHY_PHY_EXTCTL_HIGH_LA); } else { PHY_WRITE(sc, BRGPHY_MII_AUXCTL, 0x7); val = PHY_READ(sc, BRGPHY_MII_AUXCTL); PHY_WRITE(sc, BRGPHY_MII_AUXCTL, val & ~(BRGPHY_AUXCTL_LONG_PKT | 0x7)); val = PHY_READ(sc, BRGPHY_MII_PHY_EXTCTL); PHY_WRITE(sc, BRGPHY_MII_PHY_EXTCTL, val & ~BRGPHY_PHY_EXTCTL_HIGH_LA); } } static void brgphy_reset(struct mii_softc *sc) { struct bge_softc *bge_sc = NULL; struct bce_softc *bce_sc = NULL; if_t ifp; int i, val; /* * Perform a reset. Note that at least some Broadcom PHYs default to * being powered down as well as isolated after a reset but don't work * if one or both of these bits are cleared. However, they just work * fine if both bits remain set, so we don't use mii_phy_reset() here. */ PHY_WRITE(sc, BRGPHY_MII_BMCR, BRGPHY_BMCR_RESET); /* Wait 100ms for it to complete. */ for (i = 0; i < 100; i++) { if ((PHY_READ(sc, BRGPHY_MII_BMCR) & BRGPHY_BMCR_RESET) == 0) break; DELAY(1000); } /* Handle any PHY specific procedures following the reset. */ switch (sc->mii_mpd_oui) { case MII_OUI_BROADCOM: switch (sc->mii_mpd_model) { case MII_MODEL_BROADCOM_BCM5400: bcm5401_load_dspcode(sc); break; case MII_MODEL_BROADCOM_BCM5401: if (sc->mii_mpd_rev == 1 || sc->mii_mpd_rev == 3) bcm5401_load_dspcode(sc); break; case MII_MODEL_BROADCOM_BCM5411: bcm5411_load_dspcode(sc); break; case MII_MODEL_BROADCOM_BCM54K2: bcm54k2_load_dspcode(sc); break; } break; case MII_OUI_BROADCOM3: switch (sc->mii_mpd_model) { case MII_MODEL_BROADCOM3_BCM5717C: case MII_MODEL_BROADCOM3_BCM5719C: case MII_MODEL_BROADCOM3_BCM5720C: case MII_MODEL_BROADCOM3_BCM57765: return; } break; case MII_OUI_BROADCOM4: return; } ifp = sc->mii_pdata->mii_ifp; /* Find the driver associated with this PHY. */ if (mii_phy_mac_match(sc, "bge")) bge_sc = mii_phy_mac_softc(sc); else if (mii_phy_mac_match(sc, "bce")) bce_sc = mii_phy_mac_softc(sc); if (bge_sc) { /* Fix up various bugs */ if (bge_sc->bge_phy_flags & BGE_PHY_5704_A0_BUG) brgphy_fixup_5704_a0_bug(sc); if (bge_sc->bge_phy_flags & BGE_PHY_ADC_BUG) brgphy_fixup_adc_bug(sc); if (bge_sc->bge_phy_flags & BGE_PHY_ADJUST_TRIM) brgphy_fixup_adjust_trim(sc); if (bge_sc->bge_phy_flags & BGE_PHY_BER_BUG) brgphy_fixup_ber_bug(sc); if (bge_sc->bge_phy_flags & BGE_PHY_CRC_BUG) brgphy_fixup_crc_bug(sc); if (bge_sc->bge_phy_flags & BGE_PHY_JITTER_BUG) brgphy_fixup_jitter_bug(sc); if (bge_sc->bge_flags & BGE_FLAG_JUMBO) brgphy_jumbo_settings(sc, if_getmtu(ifp)); if ((bge_sc->bge_phy_flags & BGE_PHY_NO_WIRESPEED) == 0) brgphy_ethernet_wirespeed(sc); /* Enable Link LED on Dell boxes */ if (bge_sc->bge_phy_flags & BGE_PHY_NO_3LED) { PHY_WRITE(sc, BRGPHY_MII_PHY_EXTCTL, PHY_READ(sc, BRGPHY_MII_PHY_EXTCTL) & ~BRGPHY_PHY_EXTCTL_3_LED); } /* Adjust output voltage (From Linux driver) */ if (bge_sc->bge_asicrev == BGE_ASICREV_BCM5906) PHY_WRITE(sc, BRGPHY_MII_EPHY_PTEST, 0x12); } else if (bce_sc) { if (BCE_CHIP_NUM(bce_sc) == BCE_CHIP_NUM_5708 && (bce_sc->bce_phy_flags & BCE_PHY_SERDES_FLAG)) { /* Store autoneg capabilities/results in digital block (Page 0) */ PHY_WRITE(sc, BRGPHY_5708S_BLOCK_ADDR, BRGPHY_5708S_DIG3_PG2); PHY_WRITE(sc, BRGPHY_5708S_PG2_DIGCTL_3_0, BRGPHY_5708S_PG2_DIGCTL_3_0_USE_IEEE); PHY_WRITE(sc, BRGPHY_5708S_BLOCK_ADDR, BRGPHY_5708S_DIG_PG0); /* Enable fiber mode and autodetection */ PHY_WRITE(sc, BRGPHY_5708S_PG0_1000X_CTL1, PHY_READ(sc, BRGPHY_5708S_PG0_1000X_CTL1) | BRGPHY_5708S_PG0_1000X_CTL1_AUTODET_EN | BRGPHY_5708S_PG0_1000X_CTL1_FIBER_MODE); /* Enable parallel detection */ PHY_WRITE(sc, BRGPHY_5708S_PG0_1000X_CTL2, PHY_READ(sc, BRGPHY_5708S_PG0_1000X_CTL2) | BRGPHY_5708S_PG0_1000X_CTL2_PAR_DET_EN); /* Advertise 2.5G support through next page during autoneg */ if (bce_sc->bce_phy_flags & BCE_PHY_2_5G_CAPABLE_FLAG) PHY_WRITE(sc, BRGPHY_5708S_ANEG_NXT_PG_XMIT1, PHY_READ(sc, BRGPHY_5708S_ANEG_NXT_PG_XMIT1) | BRGPHY_5708S_ANEG_NXT_PG_XMIT1_25G); /* Increase TX signal amplitude */ if ((BCE_CHIP_ID(bce_sc) == BCE_CHIP_ID_5708_A0) || (BCE_CHIP_ID(bce_sc) == BCE_CHIP_ID_5708_B0) || (BCE_CHIP_ID(bce_sc) == BCE_CHIP_ID_5708_B1)) { PHY_WRITE(sc, BRGPHY_5708S_BLOCK_ADDR, BRGPHY_5708S_TX_MISC_PG5); PHY_WRITE(sc, BRGPHY_5708S_PG5_TXACTL1, PHY_READ(sc, BRGPHY_5708S_PG5_TXACTL1) & ~0x30); PHY_WRITE(sc, BRGPHY_5708S_BLOCK_ADDR, BRGPHY_5708S_DIG_PG0); } /* Backplanes use special driver/pre-driver/pre-emphasis values. */ if ((bce_sc->bce_shared_hw_cfg & BCE_SHARED_HW_CFG_PHY_BACKPLANE) && (bce_sc->bce_port_hw_cfg & BCE_PORT_HW_CFG_CFG_TXCTL3_MASK)) { PHY_WRITE(sc, BRGPHY_5708S_BLOCK_ADDR, BRGPHY_5708S_TX_MISC_PG5); PHY_WRITE(sc, BRGPHY_5708S_PG5_TXACTL3, bce_sc->bce_port_hw_cfg & BCE_PORT_HW_CFG_CFG_TXCTL3_MASK); PHY_WRITE(sc, BRGPHY_5708S_BLOCK_ADDR, BRGPHY_5708S_DIG_PG0); } } else if (BCE_CHIP_NUM(bce_sc) == BCE_CHIP_NUM_5709 && (bce_sc->bce_phy_flags & BCE_PHY_SERDES_FLAG)) { /* Select the SerDes Digital block of the AN MMD. */ PHY_WRITE(sc, BRGPHY_BLOCK_ADDR, BRGPHY_BLOCK_ADDR_SERDES_DIG); val = PHY_READ(sc, BRGPHY_SERDES_DIG_1000X_CTL1); val &= ~BRGPHY_SD_DIG_1000X_CTL1_AUTODET; val |= BRGPHY_SD_DIG_1000X_CTL1_FIBER; PHY_WRITE(sc, BRGPHY_SERDES_DIG_1000X_CTL1, val); /* Select the Over 1G block of the AN MMD. */ PHY_WRITE(sc, BRGPHY_BLOCK_ADDR, BRGPHY_BLOCK_ADDR_OVER_1G); /* Enable autoneg "Next Page" to advertise 2.5G support. */ val = PHY_READ(sc, BRGPHY_OVER_1G_UNFORMAT_PG1); if (bce_sc->bce_phy_flags & BCE_PHY_2_5G_CAPABLE_FLAG) val |= BRGPHY_5708S_ANEG_NXT_PG_XMIT1_25G; else val &= ~BRGPHY_5708S_ANEG_NXT_PG_XMIT1_25G; PHY_WRITE(sc, BRGPHY_OVER_1G_UNFORMAT_PG1, val); /* Select the Multi-Rate Backplane Ethernet block of the AN MMD. */ PHY_WRITE(sc, BRGPHY_BLOCK_ADDR, BRGPHY_BLOCK_ADDR_MRBE); /* Enable MRBE speed autoneg. */ val = PHY_READ(sc, BRGPHY_MRBE_MSG_PG5_NP); val |= BRGPHY_MRBE_MSG_PG5_NP_MBRE | BRGPHY_MRBE_MSG_PG5_NP_T2; PHY_WRITE(sc, BRGPHY_MRBE_MSG_PG5_NP, val); /* Select the Clause 73 User B0 block of the AN MMD. */ PHY_WRITE(sc, BRGPHY_BLOCK_ADDR, BRGPHY_BLOCK_ADDR_CL73_USER_B0); /* Enable MRBE speed autoneg. */ PHY_WRITE(sc, BRGPHY_CL73_USER_B0_MBRE_CTL1, BRGPHY_CL73_USER_B0_MBRE_CTL1_NP_AFT_BP | BRGPHY_CL73_USER_B0_MBRE_CTL1_STA_MGR | BRGPHY_CL73_USER_B0_MBRE_CTL1_ANEG); /* Restore IEEE0 block (assumed in all brgphy(4) code). */ PHY_WRITE(sc, BRGPHY_BLOCK_ADDR, BRGPHY_BLOCK_ADDR_COMBO_IEEE0); } else if (BCE_CHIP_NUM(bce_sc) == BCE_CHIP_NUM_5709) { if ((BCE_CHIP_REV(bce_sc) == BCE_CHIP_REV_Ax) || (BCE_CHIP_REV(bce_sc) == BCE_CHIP_REV_Bx)) brgphy_fixup_disable_early_dac(sc); brgphy_jumbo_settings(sc, if_getmtu(ifp)); brgphy_ethernet_wirespeed(sc); } else { brgphy_fixup_ber_bug(sc); brgphy_jumbo_settings(sc, if_getmtu(ifp)); brgphy_ethernet_wirespeed(sc); } } } Index: head/sys/dev/mii/brgphyreg.h =================================================================== --- head/sys/dev/mii/brgphyreg.h (revision 362352) +++ head/sys/dev/mii/brgphyreg.h (revision 362353) @@ -1,422 +1,438 @@ /*- * SPDX-License-Identifier: BSD-4-Clause * * Copyright (c) 2000 * Bill Paul . All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * 3. All advertising materials mentioning features or use of this software * must display the following acknowledgement: * This product includes software developed by Bill Paul. * 4. Neither the name of the author nor the names of any co-contributors * may be used to endorse or promote products derived from this software * without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY Bill Paul AND CONTRIBUTORS ``AS IS'' AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL Bill Paul OR THE VOICES IN HIS HEAD * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF * THE POSSIBILITY OF SUCH DAMAGE. * * $FreeBSD$ */ #ifndef _DEV_MII_BRGPHYREG_H_ #define _DEV_MII_BRGPHYREG_H_ /* * Broadcom BCM5400 registers */ #define BRGPHY_MII_BMCR 0x00 #define BRGPHY_BMCR_RESET 0x8000 #define BRGPHY_BMCR_LOOP 0x4000 #define BRGPHY_BMCR_SPD0 0x2000 /* Speed select, lower bit */ #define BRGPHY_BMCR_AUTOEN 0x1000 /* Autoneg enabled */ #define BRGPHY_BMCR_PDOWN 0x0800 /* Power down */ #define BRGPHY_BMCR_ISO 0x0400 /* Isolate */ #define BRGPHY_BMCR_STARTNEG 0x0200 /* Restart autoneg */ #define BRGPHY_BMCR_FDX 0x0100 /* Duplex mode */ #define BRGPHY_BMCR_CTEST 0x0080 /* Collision test enable */ #define BRGPHY_BMCR_SPD1 0x0040 /* Speed select, upper bit */ #define BRGPHY_S1000 BRGPHY_BMCR_SPD1 /* 1000mbps */ #define BRGPHY_S100 BRGPHY_BMCR_SPD0 /* 100mpbs */ #define BRGPHY_S10 0 /* 10mbps */ #define BRGPHY_MII_BMSR 0x01 #define BRGPHY_BMSR_EXTSTS 0x0100 /* Extended status present */ #define BRGPHY_BMSR_PRESUB 0x0040 /* Preamble surpression */ #define BRGPHY_BMSR_ACOMP 0x0020 /* Autoneg complete */ #define BRGPHY_BMSR_RFAULT 0x0010 /* Remote fault condition occurred */ #define BRGPHY_BMSR_ANEG 0x0008 /* Autoneg capable */ #define BRGPHY_BMSR_LINK 0x0004 /* Link status */ #define BRGPHY_BMSR_JABBER 0x0002 /* Jabber detected */ #define BRGPHY_BMSR_EXT 0x0001 /* Extended capability */ #define BRGPHY_MII_ANAR 0x04 #define BRGPHY_ANAR_NP 0x8000 /* Next page */ #define BRGPHY_ANAR_RF 0x2000 /* Remote fault */ #define BRGPHY_ANAR_ASP 0x0800 /* Asymmetric Pause */ #define BRGPHY_ANAR_PC 0x0400 /* Pause capable */ #define BRGPHY_ANAR_SEL 0x001F /* Selector field, 00001=Ethernet */ #define BRGPHY_MII_ANLPAR 0x05 #define BRGPHY_ANLPAR_NP 0x8000 /* Next page */ #define BRGPHY_ANLPAR_RF 0x2000 /* Remote fault */ #define BRGPHY_ANLPAR_ASP 0x0800 /* Asymmetric Pause */ #define BRGPHY_ANLPAR_PC 0x0400 /* Pause capable */ #define BRGPHY_ANLPAR_SEL 0x001F /* Selector field, 00001=Ethernet */ #define BRGPHY_SEL_TYPE 0x0001 /* Ethernet */ #define BRGPHY_MII_ANER 0x06 #define BRGPHY_ANER_PDF 0x0010 /* Parallel detection fault */ #define BRGPHY_ANER_LPNP 0x0008 /* Link partner can next page */ #define BRGPHY_ANER_NP 0x0004 /* Local PHY can next page */ #define BRGPHY_ANER_RX 0x0002 /* Next page received */ #define BRGPHY_ANER_LPAN 0x0001 /* Link partner autoneg capable */ #define BRGPHY_MII_NEXTP 0x07 /* Next page */ #define BRGPHY_MII_NEXTP_LP 0x08 /* Next page of link partner */ #define BRGPHY_MII_1000CTL 0x09 /* 1000baseT control */ #define BRGPHY_1000CTL_TST 0xE000 /* Test modes */ #define BRGPHY_1000CTL_MSE 0x1000 /* Master/Slave enable */ #define BRGPHY_1000CTL_MSC 0x0800 /* Master/Slave configuration */ #define BRGPHY_1000CTL_RD 0x0400 /* Repeater/DTE */ #define BRGPHY_1000CTL_AFD 0x0200 /* Advertise full duplex */ #define BRGPHY_1000CTL_AHD 0x0100 /* Advertise half duplex */ #define BRGPHY_MII_1000STS 0x0A /* 1000baseT status */ #define BRGPHY_1000STS_MSF 0x8000 /* Master/slave fault */ #define BRGPHY_1000STS_MSR 0x4000 /* Master/slave result */ #define BRGPHY_1000STS_LRS 0x2000 /* Local receiver status */ #define BRGPHY_1000STS_RRS 0x1000 /* Remote receiver status */ #define BRGPHY_1000STS_LPFD 0x0800 /* Link partner can FD */ #define BRGPHY_1000STS_LPHD 0x0400 /* Link partner can HD */ #define BRGPHY_1000STS_IEC 0x00FF /* Idle error count */ #define BRGPHY_MII_EXTSTS 0x0F /* Extended status */ #define BRGPHY_EXTSTS_X_FD_CAP 0x8000 /* 1000base-X FD capable */ #define BRGPHY_EXTSTS_X_HD_CAP 0x4000 /* 1000base-X HD capable */ #define BRGPHY_EXTSTS_T_FD_CAP 0x2000 /* 1000base-T FD capable */ #define BRGPHY_EXTSTS_T_HD_CAP 0x1000 /* 1000base-T HD capable */ #define BRGPHY_MII_PHY_EXTCTL 0x10 /* PHY extended control */ #define BRGPHY_PHY_EXTCTL_MAC_PHY 0x8000 /* 10BIT/GMI-interface */ #define BRGPHY_PHY_EXTCTL_DIS_CROSS 0x4000 /* Disable MDI crossover */ #define BRGPHY_PHY_EXTCTL_TX_DIS 0x2000 /* TX output disabled */ #define BRGPHY_PHY_EXTCTL_INT_DIS 0x1000 /* Interrupts disabled */ #define BRGPHY_PHY_EXTCTL_F_INT 0x0800 /* Force interrupt */ #define BRGPHY_PHY_EXTCTL_BY_45 0x0400 /* Bypass 4B5B-Decoder */ #define BRGPHY_PHY_EXTCTL_BY_SCR 0x0200 /* Bypass scrambler */ #define BRGPHY_PHY_EXTCTL_BY_MLT3 0x0100 /* Bypass MLT3 encoder */ #define BRGPHY_PHY_EXTCTL_BY_RXA 0x0080 /* Bypass RX alignment */ #define BRGPHY_PHY_EXTCTL_RES_SCR 0x0040 /* Reset scrambler */ #define BRGPHY_PHY_EXTCTL_EN_LTR 0x0020 /* Enable LED traffic mode */ #define BRGPHY_PHY_EXTCTL_LED_ON 0x0010 /* Force LEDs on */ #define BRGPHY_PHY_EXTCTL_LED_OFF 0x0008 /* Force LEDs off */ #define BRGPHY_PHY_EXTCTL_EX_IPG 0x0004 /* Extended TX IPG mode */ #define BRGPHY_PHY_EXTCTL_3_LED 0x0002 /* Three link LED mode */ #define BRGPHY_PHY_EXTCTL_HIGH_LA 0x0001 /* GMII Fifo Elasticy (?) */ #define BRGPHY_MII_PHY_EXTSTS 0x11 /* PHY extended status */ #define BRGPHY_PHY_EXTSTS_CROSS_STAT 0x2000 /* MDI crossover status */ #define BRGPHY_PHY_EXTSTS_INT_STAT 0x1000 /* Interrupt status */ #define BRGPHY_PHY_EXTSTS_RRS 0x0800 /* Remote receiver status */ #define BRGPHY_PHY_EXTSTS_LRS 0x0400 /* Local receiver status */ #define BRGPHY_PHY_EXTSTS_LOCKED 0x0200 /* Locked */ #define BRGPHY_PHY_EXTSTS_LS 0x0100 /* Link status */ #define BRGPHY_PHY_EXTSTS_RF 0x0080 /* Remove fault */ #define BRGPHY_PHY_EXTSTS_CE_ER 0x0040 /* Carrier ext error */ #define BRGPHY_PHY_EXTSTS_BAD_SSD 0x0020 /* Bad SSD */ #define BRGPHY_PHY_EXTSTS_BAD_ESD 0x0010 /* Bad ESS */ #define BRGPHY_PHY_EXTSTS_RX_ER 0x0008 /* RX error */ #define BRGPHY_PHY_EXTSTS_TX_ER 0x0004 /* TX error */ #define BRGPHY_PHY_EXTSTS_LOCK_ER 0x0002 /* Lock error */ #define BRGPHY_PHY_EXTSTS_MLT3_ER 0x0001 /* MLT3 code error */ #define BRGPHY_MII_RXERRCNT 0x12 /* RX error counter */ #define BRGPHY_MII_FCERRCNT 0x13 /* False carrier sense counter */ #define BGRPHY_FCERRCNT 0x00FF /* False carrier counter */ #define BRGPHY_MII_RXNOCNT 0x14 /* RX not OK counter */ #define BRGPHY_RXNOCNT_LOCAL 0xFF00 /* Local RX not OK counter */ #define BRGPHY_RXNOCNT_REMOTE 0x00FF /* Local RX not OK counter */ #define BRGPHY_MII_DSP_RW_PORT 0x15 /* DSP coefficient r/w port */ #define BRGPHY_MII_DSP_ADDR_REG 0x17 /* DSP coefficient addr register */ #define BRGPHY_MII_EPHY_PTEST 0x17 /* 5906 PHY register */ #define BRGPHY_DSP_TAP_NUMBER_MASK 0x00 #define BRGPHY_DSP_AGC_A 0x00 #define BRGPHY_DSP_AGC_B 0x01 #define BRGPHY_DSP_MSE_PAIR_STATUS 0x02 #define BRGPHY_DSP_SOFT_DECISION 0x03 #define BRGPHY_DSP_PHASE_REG 0x04 #define BRGPHY_DSP_SKEW 0x05 #define BRGPHY_DSP_POWER_SAVER_UPPER_BOUND 0x06 #define BRGPHY_DSP_POWER_SAVER_LOWER_BOUND 0x07 #define BRGPHY_DSP_LAST_ECHO 0x08 #define BRGPHY_DSP_FREQUENCY 0x09 #define BRGPHY_DSP_PLL_BANDWIDTH 0x0A #define BRGPHY_DSP_PLL_PHASE_OFFSET 0x0B #define BRGPHYDSP_FILTER_DCOFFSET 0x0C00 #define BRGPHY_DSP_FILTER_FEXT3 0x0B00 #define BRGPHY_DSP_FILTER_FEXT2 0x0A00 #define BRGPHY_DSP_FILTER_FEXT1 0x0900 #define BRGPHY_DSP_FILTER_FEXT0 0x0800 #define BRGPHY_DSP_FILTER_NEXT3 0x0700 #define BRGPHY_DSP_FILTER_NEXT2 0x0600 #define BRGPHY_DSP_FILTER_NEXT1 0x0500 #define BRGPHY_DSP_FILTER_NEXT0 0x0400 #define BRGPHY_DSP_FILTER_ECHO 0x0300 #define BRGPHY_DSP_FILTER_DFE 0x0200 #define BRGPHY_DSP_FILTER_FFE 0x0100 #define BRGPHY_DSP_CONTROL_ALL_FILTERS 0x1000 #define BRGPHY_DSP_SEL_CH_0 0x0000 #define BRGPHY_DSP_SEL_CH_1 0x2000 #define BRGPHY_DSP_SEL_CH_2 0x4000 #define BRGPHY_DSP_SEL_CH_3 0x6000 #define BRGPHY_MII_AUXCTL 0x18 /* AUX control */ #define BRGPHY_AUXCTL_LOW_SQ 0x8000 /* Low squelch */ #define BRGPHY_AUXCTL_LONG_PKT 0x4000 /* RX long packets */ #define BRGPHY_AUXCTL_ER_CTL 0x3000 /* Edgerate control */ #define BRGPHY_AUXCTL_TX_TST 0x0400 /* TX test, always 1 */ #define BRGPHY_AUXCTL_DIS_PRF 0x0080 /* dis part resp filter */ #define BRGPHY_AUXCTL_DIAG_MODE 0x0004 /* Diagnostic mode */ #define BRGPHY_MII_AUXSTS 0x19 /* AUX status */ #define BRGPHY_AUXSTS_ACOMP 0x8000 /* Autoneg complete */ #define BRGPHY_AUXSTS_AN_ACK 0x4000 /* Autoneg complete ack */ #define BRGPHY_AUXSTS_AN_ACK_D 0x2000 /* Autoneg complete ack detect */ #define BRGPHY_AUXSTS_AN_NPW 0x1000 /* Autoneg next page wait */ #define BRGPHY_AUXSTS_AN_RES 0x0700 /* Autoneg HCD */ #define BRGPHY_AUXSTS_PDF 0x0080 /* Parallel detect. fault */ #define BRGPHY_AUXSTS_RF 0x0040 /* Remote fault */ #define BRGPHY_AUXSTS_ANP_R 0x0020 /* Autoneg page received */ #define BRGPHY_AUXSTS_LP_ANAB 0x0010 /* Link partner autoneg ability */ #define BRGPHY_AUXSTS_LP_NPAB 0x0008 /* Link partner next page ability */ #define BRGPHY_AUXSTS_LINK 0x0004 /* Link status */ #define BRGPHY_AUXSTS_PRR 0x0002 /* Pause resolution-RX */ #define BRGPHY_AUXSTS_PRT 0x0001 /* Pause resolution-TX */ #define BRGPHY_RES_1000FD 0x0700 /* 1000baseT full duplex */ #define BRGPHY_RES_1000HD 0x0600 /* 1000baseT half duplex */ #define BRGPHY_RES_100FD 0x0500 /* 100baseT full duplex */ #define BRGPHY_RES_100T4 0x0400 /* 100baseT4 */ #define BRGPHY_RES_100HD 0x0300 /* 100baseT half duplex */ #define BRGPHY_RES_10FD 0x0200 /* 10baseT full duplex */ #define BRGPHY_RES_10HD 0x0100 /* 10baseT half duplex */ #define BRGPHY_MII_ISR 0x1A /* Interrupt status */ #define BRGPHY_ISR_PSERR 0x4000 /* Pair swap error */ #define BRGPHY_ISR_MDXI_SC 0x2000 /* MDIX Status Change */ #define BRGPHY_ISR_HCT 0x1000 /* Counter above 32K */ #define BRGPHY_ISR_LCT 0x0800 /* All counter below 128 */ #define BRGPHY_ISR_AN_PR 0x0400 /* Autoneg page received */ #define BRGPHY_ISR_NO_HDCL 0x0200 /* No HCD Link */ #define BRGPHY_ISR_NO_HDC 0x0100 /* No HCD */ #define BRGPHY_ISR_USHDC 0x0080 /* Negotiated Unsupported HCD */ #define BRGPHY_ISR_SCR_S_ERR 0x0040 /* Scrambler sync error */ #define BRGPHY_ISR_RRS_CHG 0x0020 /* Remote RX status change */ #define BRGPHY_ISR_LRS_CHG 0x0010 /* Local RX status change */ #define BRGPHY_ISR_DUP_CHG 0x0008 /* Duplex mode change */ #define BRGPHY_ISR_LSP_CHG 0x0004 /* Link speed changed */ #define BRGPHY_ISR_LNK_CHG 0x0002 /* Link status change */ #define BRGPHY_ISR_CRCERR 0x0001 /* CRC error */ #define BRGPHY_MII_IMR 0x1B /* Interrupt mask */ #define BRGPHY_IMR_PSERR 0x4000 /* Pair swap error */ #define BRGPHY_IMR_MDXI_SC 0x2000 /* MDIX Status Change */ #define BRGPHY_IMR_HCT 0x1000 /* Counter above 32K */ #define BRGPHY_IMR_LCT 0x0800 /* All counter below 128 */ #define BRGPHY_IMR_AN_PR 0x0400 /* Autoneg page received */ #define BRGPHY_IMR_NO_HDCL 0x0200 /* No HCD Link */ #define BRGPHY_IMR_NO_HDC 0x0100 /* No HCD */ #define BRGPHY_IMR_USHDC 0x0080 /* Negotiated Unsupported HCD */ #define BRGPHY_IMR_SCR_S_ERR 0x0040 /* Scrambler sync error */ #define BRGPHY_IMR_RRS_CHG 0x0020 /* Remote RX status change */ #define BRGPHY_IMR_LRS_CHG 0x0010 /* Local RX status change */ #define BRGPHY_IMR_DUP_CHG 0x0008 /* Duplex mode change */ #define BRGPHY_IMR_LSP_CHG 0x0004 /* Link speed changed */ #define BRGPHY_IMR_LNK_CHG 0x0002 /* Link status change */ #define BRGPHY_IMR_CRCERR 0x0001 /* CRC error */ /*******************************************************/ /* Begin: Shared SerDes PHY register definitions */ /*******************************************************/ /* SerDes autoneg is different from copper */ #define BRGPHY_SERDES_ANAR 0x04 #define BRGPHY_SERDES_ANAR_FDX 0x0020 #define BRGPHY_SERDES_ANAR_HDX 0x0040 #define BRGPHY_SERDES_ANAR_NO_PAUSE (0x0 << 7) #define BRGPHY_SERDES_ANAR_SYM_PAUSE (0x1 << 7) #define BRGPHY_SERDES_ANAR_ASYM_PAUSE (0x2 << 7) #define BRGPHY_SERDES_ANAR_BOTH_PAUSE (0x3 << 7) #define BRGPHY_SERDES_ANLPAR 0x05 #define BRGPHY_SERDES_ANLPAR_FDX 0x0020 #define BRGPHY_SERDES_ANLPAR_HDX 0x0040 #define BRGPHY_SERDES_ANLPAR_NO_PAUSE (0x0 << 7) #define BRGPHY_SERDES_ANLPAR_SYM_PAUSE (0x1 << 7) #define BRGPHY_SERDES_ANLPAR_ASYM_PAUSE (0x2 << 7) #define BRGPHY_SERDES_ANLPAR_BOTH_PAUSE (0x3 << 7) /*******************************************************/ /* End: Shared SerDes PHY register definitions */ /*******************************************************/ /*******************************************************/ /* Begin: PHY register values for the 5706 PHY */ /*******************************************************/ +/* + * Aux control shadow register, bits 0-2 select function (0x00 to + * 0x07). + */ +#define BRGPHY_AUXCTL_SHADOW_MISC 0x07 +#define BRGPHY_AUXCTL_MISC_DATA_MASK 0x7ff8 +#define BRGPHY_AUXCTL_MISC_READ_SHIFT 12 +#define BRGPHY_AUXCTL_MISC_WRITE_EN 0x8000 +#define BRGPHY_AUXCTL_MISC_RGMII_SKEW_EN 0x0200 +#define BRGPHY_AUXCTL_MISC_WIRESPEED_EN 0x0010 + /* * Shadow register 0x1C, bit 15 is write enable, * bits 14-10 select function (0x00 to 0x1F). */ #define BRGPHY_MII_SHADOW_1C 0x1C #define BRGPHY_SHADOW_1C_WRITE_EN 0x8000 #define BRGPHY_SHADOW_1C_SELECT_MASK 0x7C00 +#define BRGPHY_SHADOW_1C_DATA_MASK 0x03FF + +/* Shadow 0x1C Clock Alignment Control Register (select value 0x03) */ +#define BRGPHY_SHADOW_1C_CLK_CTRL (0x03 << 10) +#define BRGPHY_SHADOW_1C_GTXCLK_EN 0x0200 /* Shadow 0x1C Mode Control Register (select value 0x1F) */ #define BRGPHY_SHADOW_1C_MODE_CTRL (0x1F << 10) /* When set, Regs 0-0x0F are 1000X, else 1000T */ #define BRGPHY_SHADOW_1C_ENA_1000X 0x0001 #define BRGPHY_MII_TEST1 0x1E #define BRGPHY_TEST1_TRIM_EN 0x0010 #define BRGPHY_TEST1_CRC_EN 0x8000 #define BRGPHY_MII_TEST2 0x1F /*******************************************************/ /* End: PHY register values for the 5706 PHY */ /*******************************************************/ /*******************************************************/ /* Begin: PHY register values for the 5708S SerDes PHY */ /*******************************************************/ /* Autoneg Next Page Transmit 1 Regiser */ #define BRGPHY_5708S_ANEG_NXT_PG_XMIT1 0x0B #define BRGPHY_5708S_ANEG_NXT_PG_XMIT1_25G 0x0001 /* Use the BLOCK_ADDR register to select the page for registers 0x10 to 0x1E */ #define BRGPHY_5708S_BLOCK_ADDR 0x1f #define BRGPHY_5708S_DIG_PG0 0x0000 #define BRGPHY_5708S_DIG3_PG2 0x0002 #define BRGPHY_5708S_TX_MISC_PG5 0x0005 /* 5708S SerDes "Digital" Registers (page 0) */ #define BRGPHY_5708S_PG0_1000X_CTL1 0x10 #define BRGPHY_5708S_PG0_1000X_CTL1_AUTODET_EN 0x0010 #define BRGPHY_5708S_PG0_1000X_CTL1_FIBER_MODE 0x0001 #define BRGPHY_5708S_PG0_1000X_STAT1 0x14 #define BRGPHY_5708S_PG0_1000X_STAT1_LINK 0x0002 #define BRGPHY_5708S_PG0_1000X_STAT1_FDX 0x0004 #define BRGPHY_5708S_PG0_1000X_STAT1_SPEED_MASK 0x0018 #define BRGPHY_5708S_PG0_1000X_STAT1_SPEED_10 (0x0 << 3) #define BRGPHY_5708S_PG0_1000X_STAT1_SPEED_100 (0x1 << 3) #define BRGPHY_5708S_PG0_1000X_STAT1_SPEED_1G (0x2 << 3) #define BRGPHY_5708S_PG0_1000X_STAT1_SPEED_25G (0x3 << 3) #define BRGPHY_5708S_PG0_1000X_CTL2 0x11 #define BRGPHY_5708S_PG0_1000X_CTL2_PAR_DET_EN 0x0001 /* 5708S SerDes "Digital 3" Registers (page 2) */ #define BRGPHY_5708S_PG2_DIGCTL_3_0 0x10 #define BRGPHY_5708S_PG2_DIGCTL_3_0_USE_IEEE 0x0001 /* 5708S SerDes "TX Misc" Registers (page 5) */ #define BRGPHY_5708S_PG5_2500STATUS1 0x10 #define BRGPHY_5708S_PG5_TXACTL1 0x15 #define BRGPHY_5708S_PG5_TXACTL3 0x17 /*******************************************************/ /* End: PHY register values for the 5708S SerDes PHY */ /*******************************************************/ /*******************************************************/ /* Begin: PHY register values for the 5709S SerDes PHY */ /*******************************************************/ /* 5709S SerDes "General Purpose Status" Registers */ #define BRGPHY_BLOCK_ADDR_GP_STATUS 0x8120 #define BRGPHY_GP_STATUS_TOP_ANEG_STATUS 0x1B #define BRGPHY_GP_STATUS_TOP_ANEG_SPEED_MASK 0x3F00 #define BRGPHY_GP_STATUS_TOP_ANEG_SPEED_10 0x0000 #define BRGPHY_GP_STATUS_TOP_ANEG_SPEED_100 0x0100 #define BRGPHY_GP_STATUS_TOP_ANEG_SPEED_1G 0x0200 #define BRGPHY_GP_STATUS_TOP_ANEG_SPEED_25G 0x0300 #define BRGPHY_GP_STATUS_TOP_ANEG_SPEED_1GKX 0x0D00 #define BRGPHY_GP_STATUS_TOP_ANEG_FDX 0x0008 #define BRGPHY_GP_STATUS_TOP_ANEG_LINK_UP 0x0004 #define BRGPHY_GP_STATUS_TOP_ANEG_CL73_COMP 0x0001 /* 5709S SerDes "SerDes Digital" Registers */ #define BRGPHY_BLOCK_ADDR_SERDES_DIG 0x8300 #define BRGPHY_SERDES_DIG_1000X_CTL1 0x0010 #define BRGPHY_SD_DIG_1000X_CTL1_AUTODET 0x0010 #define BRGPHY_SD_DIG_1000X_CTL1_FIBER 0x0001 /* 5709S SerDes "Over 1G" Registers */ #define BRGPHY_BLOCK_ADDR_OVER_1G 0x8320 #define BRGPHY_OVER_1G_UNFORMAT_PG1 0x19 /* 5709S SerDes "Multi-Rate Backplane Ethernet" Registers */ #define BRGPHY_BLOCK_ADDR_MRBE 0x8350 #define BRGPHY_MRBE_MSG_PG5_NP 0x10 #define BRGPHY_MRBE_MSG_PG5_NP_MBRE 0x0001 #define BRGPHY_MRBE_MSG_PG5_NP_T2 0x0002 /* 5709S SerDes "IEEE Clause 73 User B0" Registers */ #define BRGPHY_BLOCK_ADDR_CL73_USER_B0 0x8370 #define BRGPHY_CL73_USER_B0_MBRE_CTL1 0x12 #define BRGPHY_CL73_USER_B0_MBRE_CTL1_NP_AFT_BP 0x2000 #define BRGPHY_CL73_USER_B0_MBRE_CTL1_STA_MGR 0x4000 #define BRGPHY_CL73_USER_B0_MBRE_CTL1_ANEG 0x8000 /* 5709S SerDes "IEEE Clause 73 User B0" Registers */ #define BRGPHY_BLOCK_ADDR_ADDR_EXT 0xFFD0 /* 5709S SerDes "Combo IEEE 0" Registers */ #define BRGPHY_BLOCK_ADDR_COMBO_IEEE0 0xFFE0 #define BRGPHY_ADDR_EXT 0x1E #define BRGPHY_BLOCK_ADDR 0x1F #define BRGPHY_ADDR_EXT_AN_MMD 0x3800 /*******************************************************/ /* End: PHY register values for the 5709S SerDes PHY */ /*******************************************************/ #define BRGPHY_INTRS \ ~(BRGPHY_IMR_LNK_CHG|BRGPHY_IMR_LSP_CHG|BRGPHY_IMR_DUP_CHG) #endif /* _DEV_BRGPHY_MIIREG_H_ */ Index: head/sys/dev/mii/miidevs =================================================================== --- head/sys/dev/mii/miidevs (revision 362352) +++ head/sys/dev/mii/miidevs (revision 362353) @@ -1,351 +1,352 @@ $FreeBSD$ /*$NetBSD: miidevs,v 1.105 2011/11/25 23:28:14 jakllsch Exp $*/ /*- * Copyright (c) 1998, 1999 The NetBSD Foundation, Inc. * All rights reserved. * * This code is derived from software contributed to The NetBSD Foundation * by Jason R. Thorpe of the Numerical Aerospace Simulation Facility, * NASA Ames Research Center. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE * POSSIBILITY OF SUCH DAMAGE. */ /* * List of known MII OUIs. * For a complete list see http://standards.ieee.org/regauth/oui/ * * XXX Vendors do obviously not agree how OUIs (24 bit) are mapped * to the 22 bits available in the id registers. * IEEE 802.3u-1995, subclause 22.2.4.3.1, figure 22-12, depicts the right * mapping; the bit positions are defined in IEEE 802-1990, figure 5.2. * (There is a formal 802.3 interpretation, number 1-07/98 of July 09 1998, * about this.) * The MII_OUI() macro in "mii.h" reflects this. * If a vendor uses a different mapping, an "xx" prefixed OUI is defined here * which is mangled accordingly to compensate. */ oui AGERE 0x00053d Agere Systems oui ALTIMA 0x0010a9 Altima Communications oui AMD 0x00001a Advanced Micro Devices oui BROADCOM 0x001018 Broadcom Corporation oui BROADCOM2 0x000af7 Broadcom Corporation oui BROADCOM3 0x001be9 Broadcom Corporation oui BROADCOM4 0x18c086 Broadcom Corporation oui CICADA 0x0003f1 Cicada Semiconductor oui DAVICOM 0x00606e Davicom Semiconductor oui ENABLESEMI 0x0010dd Enable Semiconductor oui ICPLUS 0x0090c3 IC Plus Corp. oui ICS 0x00a0be Integrated Circuit Systems oui INTEL 0x00aa00 Intel Corporation oui JMICRON 0x00d831 JMicron Technologies oui LEVEL1 0x00207b Level 1 oui MARVELL 0x005043 Marvell Semiconductor oui MICREL 0x0010a1 Micrel oui MYSON 0x00c0b4 Myson Technology oui NATSEMI 0x080017 National Semiconductor oui PMCSIERRA 0x00e004 PMC-Sierra oui QUALSEMI 0x006051 Quality Semiconductor oui RDC 0x00d02d RDC Semiconductor oui REALTEK 0x00e04c RealTek Semicondctor oui SEEQ 0x00a07d Seeq Technology oui SIS 0x00e006 Silicon Integrated Systems oui SMC 0x00800f SMC oui TI 0x080028 Texas Instruments oui TSC 0x00c039 TDK Semiconductor oui VITESSE 0x0001c1 Vitesse Semiconductor oui XAQTI 0x00e0ae XaQti Corp. /* Some Intel 82553's use an alternative OUI. */ oui xxINTEL 0x001f00 Intel Corporation /* Some VIA 6122's use an alternative OUI. */ oui xxCICADA 0x00c08f Cicada Semiconductor /* bad bitorder (bits "g" and "h" (= MSBs byte 1) lost) */ oui yyAMD 0x000058 Advanced Micro Devices oui xxATHEROS 0x00c82e Atheros Communications oui xxBROADCOM 0x000818 Broadcom Corporation oui xxBROADCOM_ALT1 0x0050ef Broadcom Corporation oui xxDAVICOM 0x000676 Davicom Semiconductor oui yyINTEL 0x005500 Intel Corporation oui xxJATO 0x0007c1 Jato Technologies oui xxMARVELL 0x000ac2 Marvell Semiconductor oui xxMYSON 0x00032d Myson Technology oui xxNATSEMI 0x1000e8 National Semiconductor oui xxQUALSEMI 0x00068a Quality Semiconductor oui xxTSC 0x00039c TDK Semiconductor oui xxVITESSE 0x008083 Vitesse Semiconductor /* bad byteorder (bits "q" and "r" (= LSBs byte 3) lost) */ oui xxLEVEL1 0x782000 Level 1 oui xxXAQTI 0xace000 XaQti Corp. /* Don't know what's going on here. */ oui xxASIX 0x000674 Asix Semiconductor oui yyDAVICOM 0x000602 Davicom Semiconductor oui xxICPLUS 0x0009c3 IC Plus Corp. oui xxPMCSIERRA 0x0009c0 PMC-Sierra oui xxPMCSIERRA2 0x009057 PMC-Sierra oui xxREALTEK 0x000732 RealTek Semicondctor oui yyREALTEK 0x000004 RealTek Semicondctor /* * List of known models. Grouped by oui. */ /* Agere Systems PHYs */ model AGERE ET1011 0x0001 ET1011 10/100/1000baseT PHY model AGERE ET1011C 0x0004 ET1011C 10/100/1000baseT PHY /* Altima Communications PHYs */ model ALTIMA ACXXX 0x0001 ACXXX 10/100 media interface model ALTIMA AC101L 0x0012 AC101L 10/100 media interface model ALTIMA AC101 0x0021 AC101 10/100 media interface /* AMD Am79C87[45] have ALTIMA OUI */ model ALTIMA Am79C875 0x0014 Am79C875 10/100 media interface model ALTIMA Am79C874 0x0021 Am79C874 10/100 media interface /* Advanced Micro Devices PHYs */ /* see Davicom DM9101 for Am79C873 */ model yyAMD 79C972_10T 0x0001 Am79C972 internal 10BASE-T interface model yyAMD 79c973phy 0x0036 Am79C973 internal 10/100 media interface model yyAMD 79c901 0x0037 Am79C901 10BASE-T interface model yyAMD 79c901home 0x0039 Am79C901 HomePNA 1.0 interface /* Atheros Communications/Attansic PHYs */ model xxATHEROS F1 0x0001 Atheros F1 10/100/1000 PHY model xxATHEROS F2 0x0002 Atheros F2 10/100 PHY model xxATHEROS AR8021 0x0004 Atheros AR8021 10/100/1000 PHY model xxATHEROS F1_7 0x0007 Atheros F1 10/100/1000 PHY /* Asix semiconductor PHYs */ model xxASIX AX88X9X 0x0031 Ax88x9x internal PHY /* Broadcom Corp. PHYs */ model xxBROADCOM 3C905B 0x0012 Broadcom 3c905B internal PHY model xxBROADCOM 3C905C 0x0017 Broadcom 3c905C internal PHY model xxBROADCOM BCM5201 0x0021 BCM5201 10/100 media interface model xxBROADCOM BCM5214 0x0028 BCM5214 Quad 10/100 media interface model xxBROADCOM BCM5221 0x001e BCM5221 10/100 media interface model xxBROADCOM BCM5222 0x0032 BCM5222 Dual 10/100 media interface model xxBROADCOM BCM4401 0x0036 BCM4401 10/100 media interface model xxBROADCOM BCM5365 0x0037 BCM5365 10/100 5-port PHY switch model BROADCOM BCM5400 0x0004 BCM5400 1000BASE-T media interface model BROADCOM BCM5401 0x0005 BCM5401 1000BASE-T media interface model BROADCOM BCM5402 0x0006 BCM5402 1000BASE-T media interface model BROADCOM BCM5411 0x0007 BCM5411 1000BASE-T media interface model BROADCOM BCM5404 0x0008 BCM5404 1000BASE-T media interface model BROADCOM BCM5424 0x000a BCM5424/BCM5234 1000BASE-T media interface model BROADCOM BCM5464 0x000b BCM5464 1000BASE-T media interface model BROADCOM BCM5461 0x000c BCM5461 1000BASE-T media interface model BROADCOM BCM5462 0x000d BCM5462 1000BASE-T media interface model BROADCOM BCM5421 0x000e BCM5421 1000BASE-T media interface model BROADCOM BCM5752 0x0010 BCM5752 1000BASE-T media interface model BROADCOM BCM5701 0x0011 BCM5701 1000BASE-T media interface model BROADCOM BCM5706 0x0015 BCM5706 1000BASE-T/SX media interface model BROADCOM BCM5703 0x0016 BCM5703 1000BASE-T media interface model BROADCOM BCM5750 0x0018 BCM5750 1000BASE-T media interface model BROADCOM BCM5704 0x0019 BCM5704 1000BASE-T media interface model BROADCOM BCM5705 0x001a BCM5705 1000BASE-T media interface model BROADCOM BCM54K2 0x002e BCM54K2 1000BASE-T media interface model BROADCOM BCM5714 0x0034 BCM5714 1000BASE-T media interface model BROADCOM BCM5780 0x0035 BCM5780 1000BASE-T media interface model BROADCOM BCM5708C 0x0036 BCM5708C 1000BASE-T media interface model BROADCOM BCM5466 0x003b BCM5466 1000BASE-T media interface model BROADCOM2 BCM5325 0x0003 BCM5325 10/100 5-port PHY switch model BROADCOM2 BCM5906 0x0004 BCM5906 10/100baseTX media interface model BROADCOM2 BCM5478 0x0008 BCM5478 1000BASE-T media interface model BROADCOM2 BCM5488 0x0009 BCM5488 1000BASE-T media interface model BROADCOM2 BCM5481 0x000a BCM5481 1000BASE-T media interface model BROADCOM2 BCM5482 0x000b BCM5482 1000BASE-T media interface model BROADCOM2 BCM5755 0x000c BCM5755 1000BASE-T media interface model BROADCOM2 BCM5754 0x000e BCM5754/BCM5787 1000BASE-T media interface model BROADCOM2 BCM5708S 0x0015 BCM5708S 1000/2500baseSX PHY model BROADCOM2 BCM5785 0x0016 BCM5785 1000BASE-T media interface model BROADCOM2 BCM5709CAX 0x002c BCM5709CAX 10/100/1000baseT PHY model BROADCOM2 BCM5722 0x002d BCM5722 1000BASE-T media interface model BROADCOM2 BCM5784 0x003a BCM5784 10/100/1000baseT PHY model BROADCOM2 BCM5709C 0x003c BCM5709 10/100/1000baseT PHY model BROADCOM2 BCM5761 0x003d BCM5761 10/100/1000baseT PHY model BROADCOM2 BCM5709S 0x003f BCM5709S/5720S 1000/2500baseSX PHY model BROADCOM3 BCM54618SE 0x000d BCM54618SE 10/100/1000BASE-T PHY model BROADCOM3 BCM57780 0x0019 BCM57780 1000BASE-T media interface model BROADCOM3 BCM5717C 0x0020 BCM5717C 1000BASE-T media interface model BROADCOM3 BCM5719C 0x0022 BCM5719C 1000BASE-T media interface model BROADCOM3 BCM57765 0x0024 BCM57765 1000BASE-T media interface model BROADCOM3 BCM5720C 0x0036 BCM5720C 1000BASE-T media interface +model BROADCOM4 BCM54213PE 0x000a BCM54213PE 1000BASE-T media interface model BROADCOM4 BCM5725C 0x0038 BCM5725C 1000BASE-T media interface model xxBROADCOM_ALT1 BCM5906 0x0004 BCM5906 10/100baseTX media interface /* Cicada Semiconductor PHYs (now owned by Vitesse?) */ model xxCICADA CS8201 0x0001 Cicada CS8201 10/100/1000TX PHY model xxCICADA CS8204 0x0004 Cicada CS8204 10/100/1000TX PHY model xxCICADA VSC8211 0x000b Cicada VSC8211 10/100/1000TX PHY model xxCICADA VSC8221 0x0015 Cicada CS8201 10/100/1000TX PHY model xxCICADA CS8201A 0x0020 Cicada CS8201 10/100/1000TX PHY model xxCICADA CS8201B 0x0021 Cicada CS8201 10/100/1000TX PHY model xxCICADA CS8244 0x002c Cicada CS8244 10/100/1000TX PHY model xxVITESSE VSC8601 0x0002 Vitesse VSC8601 10/100/1000TX PHY /* Davicom Semiconductor PHYs */ /* AMD Am79C873 seems to be a relabeled DM9101 */ model xxDAVICOM DM9101 0x0000 DM9101 (AMD Am79C873) 10/100 media interface model xxDAVICOM DM9102 0x0004 DM9102 10/100 media interface model yyDAVICOM DM9101 0x0000 DM9101 10/100 media interface /* IC Plus Corp. PHYs */ model xxICPLUS IP101 0x0005 IP101 10/100 PHY model xxICPLUS IP1000A 0x0008 IP100A 10/100/1000 media interface model xxICPLUS IP1001 0x0019 IP1001 10/100/1000 media interface /* Integrated Circuit Systems PHYs */ model ICS 1889 0x0001 ICS1889 10/100 media interface model ICS 1890 0x0002 ICS1890 10/100 media interface model ICS 1892 0x0003 ICS1892 10/100 media interface model ICS 1893 0x0004 ICS1893 10/100 media interface model ICS 1893C 0x0005 ICS1893C 10/100 media interface /* Intel Corporation PHYs */ model xxINTEL I82553 0x0000 i82553 10/100 media interface model yyINTEL I82555 0x0015 i82555 10/100 media interface model yyINTEL I82562EH 0x0017 i82562EH HomePNA interface model yyINTEL I82562G 0x0031 i82562G 10/100 media interface model yyINTEL I82562EM 0x0032 i82562EM 10/100 media interface model yyINTEL I82562ET 0x0033 i82562ET 10/100 media interface model yyINTEL I82553 0x0035 i82553 10/100 media interface model yyINTEL I82566 0x0039 i82566 10/100/1000 media interface model INTEL I82577 0x0005 i82577 10/100/1000 media interface model INTEL I82579 0x0009 i82579 10/100/1000 media interface model xxMARVELL I82563 0x000a i82563 10/100/1000 media interface model yyINTEL IGP01E1000 0x0038 Intel IGP01E1000 Gigabit PHY /* Jato Technologies PHYs */ model xxJATO BASEX 0x0000 Jato 1000baseX media interface /* JMicron Technologies PHYs */ model JMICRON JMP211 0x0021 JMP211 10/100/1000 media interface model JMICRON JMP202 0x0022 JMP202 10/100 media interface /* Level 1 PHYs */ model xxLEVEL1 LXT970 0x0000 LXT970 10/100 media interface model LEVEL1 LXT971 0x000e LXT971/2 10/100 media interface model LEVEL1 LXT973 0x0021 LXT973 10/100 Dual PHY model LEVEL1 LXT974 0x0004 LXT974 10/100 Quad PHY model LEVEL1 LXT975 0x0005 LXT975 10/100 Quad PHY model LEVEL1 LXT1000_OLD 0x0003 LXT1000 1000BASE-T media interface model LEVEL1 LXT1000 0x000c LXT1000 1000BASE-T media interface /* Marvell Semiconductor PHYs */ model xxMARVELL E1000 0x0000 Marvell 88E1000 Gigabit PHY model xxMARVELL E1011 0x0002 Marvell 88E1011 Gigabit PHY model xxMARVELL E1000_3 0x0003 Marvell 88E1000 Gigabit PHY model xxMARVELL E1000S 0x0004 Marvell 88E1000S Gigabit PHY model xxMARVELL E1000_5 0x0005 Marvell 88E1000 Gigabit PHY model xxMARVELL E1101 0x0006 Marvell 88E1101 Gigabit PHY model xxMARVELL E3082 0x0008 Marvell 88E3082 10/100 Fast Ethernet PHY model xxMARVELL E1112 0x0009 Marvell 88E1112 Gigabit PHY model xxMARVELL E1149 0x000b Marvell 88E1149 Gigabit PHY model xxMARVELL E1111 0x000c Marvell 88E1111 Gigabit PHY model xxMARVELL E1145 0x000d Marvell 88E1145 Quad Gigabit PHY model xxMARVELL E1116 0x0021 Marvell 88E1116 Gigabit PHY model xxMARVELL E1116R 0x0024 Marvell 88E1116R Gigabit PHY model xxMARVELL E1118 0x0022 Marvell 88E1118 Gigabit PHY model xxMARVELL E1149R 0x0025 Marvell 88E1149R Quad Gigabit PHY model xxMARVELL E3016 0x0026 Marvell 88E3016 10/100 Fast Ethernet PHY model xxMARVELL PHYG65G 0x0027 Marvell PHYG65G Gigabit PHY model xxMARVELL E1116R_29 0x0029 Marvell 88E1116R Gigabit PHY model MARVELL E1000 0x0005 Marvell 88E1000 Gigabit PHY model MARVELL E1011 0x0002 Marvell 88E1011 Gigabit PHY model MARVELL E1000_3 0x0003 Marvell 88E1000 Gigabit PHY model MARVELL E1000_5 0x0005 Marvell 88E1000 Gigabit PHY model MARVELL E1111 0x000c Marvell 88E1111 Gigabit PHY /* Micrel PHYs */ model MICREL KSZ8081 0x0016 Micrel KSZ8081 10/100 PHY model MICREL KSZ9021 0x0021 Micrel KSZ9021 10/100/1000 PHY model MICREL KSZ9031 0x0022 Micrel KSZ9031 10/100/1000 PHY /* Myson Technology PHYs */ model xxMYSON MTD972 0x0000 MTD972 10/100 media interface model MYSON MTD803 0x0000 MTD803 3-in-1 media interface /* National Semiconductor PHYs */ model xxNATSEMI DP83840 0x0000 DP83840 10/100 media interface model xxNATSEMI DP83843 0x0001 DP83843 10/100 media interface model xxNATSEMI DP83815 0x0002 DP83815 10/100 media interface model xxNATSEMI DP83847 0x0003 DP83847 10/100 media interface model xxNATSEMI DP83891 0x0005 DP83891 1000BASE-T media interface model xxNATSEMI DP83861 0x0006 DP83861 1000BASE-T media interface model xxNATSEMI DP83865 0x0007 DP83865 1000BASE-T media interface model xxNATSEMI DP83849 0x000a DP83849 10/100 media interface /* PMC Sierra PHYs */ model xxPMCSIERRA PM8351 0x0000 PM8351 OctalPHY Gigabit interface model xxPMCSIERRA2 PM8352 0x0002 PM8352 OctalPHY Gigabit interface model xxPMCSIERRA2 PM8353 0x0003 PM8353 QuadPHY Gigabit interface model PMCSIERRA PM8354 0x0004 PM8354 QuadPHY Gigabit interface /* Quality Semiconductor PHYs */ model xxQUALSEMI QS6612 0x0000 QS6612 10/100 media interface /* RDC Semiconductor PHYs */ model RDC R6040 0x0003 R6040 10/100 media interface /* RealTek Semicondctor PHYs */ model yyREALTEK RTL8201L 0x0020 RTL8201L 10/100 media interface model xxREALTEK RTL8169S 0x0011 RTL8169S/8110S/8211 1000BASE-T media interface model REALTEK RTL8305SC 0x0005 RTL8305SC 10/100 802.1q switch model REALTEK RTL8201E 0x0008 RTL8201E 10/100 media interface model REALTEK RTL8251 0x0000 RTL8251/8153 1000BASE-T media interface model REALTEK RTL8169S 0x0011 RTL8169S/8110S/8211 1000BASE-T media interface /* Seeq Seeq PHYs */ model SEEQ 80220 0x0003 Seeq 80220 10/100 media interface model SEEQ 84220 0x0004 Seeq 84220 10/100 media interface model SEEQ 80225 0x0008 Seeq 80225 10/100 media interface /* Silicon Integrated Systems PHYs */ model SIS 900 0x0000 SiS 900 10/100 media interface /* Texas Instruments PHYs */ model TI TLAN10T 0x0001 ThunderLAN 10BASE-T media interface model TI 100VGPMI 0x0002 ThunderLAN 100VG-AnyLan media interface model TI TNETE2101 0x0003 TNETE2101 media interface /* TDK Semiconductor PHYs */ model xxTSC 78Q2120 0x0014 78Q2120 10/100 media interface model xxTSC 78Q2121 0x0015 78Q2121 100BASE-TX media interface /* Vitesse Semiconductor (now Microsemi) */ model xxVITESSE VSC8501 0x0013 Vitesse VSC8501 10/100/1000TX PHY model xxVITESSE VSC8641 0x0003 Vitesse VSC8641 10/100/1000TX PHY /* XaQti Corp. PHYs */ model xxXAQTI XMACII 0x0000 XaQti Corp. XMAC II gigabit interface /* SMC */ model SMC LAN8710A 0x000F SMC LAN8710A 10/100 interface model SMC LAN8700 0x000C SMC LAN8700 10/100 interface Index: head/sys/dev/mii/miivar.h =================================================================== --- head/sys/dev/mii/miivar.h (revision 362352) +++ head/sys/dev/mii/miivar.h (revision 362353) @@ -1,289 +1,291 @@ /* $NetBSD: miivar.h,v 1.8 1999/04/23 04:24:32 thorpej Exp $ */ /*- * SPDX-License-Identifier: BSD-2-Clause-NetBSD * * Copyright (c) 1998, 1999 The NetBSD Foundation, Inc. * All rights reserved. * * This code is derived from software contributed to The NetBSD Foundation * by Jason R. Thorpe of the Numerical Aerospace Simulation Facility, * NASA Ames Research Center. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE * POSSIBILITY OF SUCH DAMAGE. * * $FreeBSD$ */ #ifndef _DEV_MII_MIIVAR_H_ #define _DEV_MII_MIIVAR_H_ #include #include /* XXX driver API temporary */ /* * Media Independent Interface data structure defintions */ struct mii_softc; /* * A network interface driver has one of these structures in its softc. * It is the interface from the network interface driver to the MII * layer. */ struct mii_data { struct ifmedia mii_media; /* media information */ if_t mii_ifp; /* pointer back to network interface */ /* * For network interfaces with multiple PHYs, a list of all * PHYs is required so they can all be notified when a media * request is made. */ LIST_HEAD(mii_listhead, mii_softc) mii_phys; u_int mii_instance; /* * PHY driver fills this in with active media status. */ u_int mii_media_status; u_int mii_media_active; }; typedef struct mii_data mii_data_t; /* * Functions provided by the PHY to perform various functions. */ struct mii_phy_funcs { int (*pf_service)(struct mii_softc *, struct mii_data *, int); void (*pf_status)(struct mii_softc *); void (*pf_reset)(struct mii_softc *); }; /* * Requests that can be made to the downcall. */ #define MII_TICK 1 /* once-per-second tick */ #define MII_MEDIACHG 2 /* user changed media; perform the switch */ #define MII_POLLSTAT 3 /* user requested media status; fill it in */ /* * Each PHY driver's softc has one of these as the first member. * XXX This would be better named "phy_softc", but this is the name * XXX BSDI used, and we would like to have the same interface. */ struct mii_softc { device_t mii_dev; /* generic device glue */ LIST_ENTRY(mii_softc) mii_list; /* entry on parent's PHY list */ uint32_t mii_mpd_oui; /* the PHY's OUI (MII_OUI())*/ uint32_t mii_mpd_model; /* the PHY's model (MII_MODEL())*/ uint32_t mii_mpd_rev; /* the PHY's revision (MII_REV())*/ u_int mii_capmask; /* capability mask for BMSR */ u_int mii_phy; /* our MII address */ u_int mii_offset; /* first PHY, second PHY, etc. */ u_int mii_inst; /* instance for ifmedia */ /* Our PHY functions. */ const struct mii_phy_funcs *mii_funcs; struct mii_data *mii_pdata; /* pointer to parent's mii_data */ u_int mii_flags; /* misc. flags; see below */ u_int mii_capabilities; /* capabilities from BMSR */ u_int mii_extcapabilities; /* extended capabilities */ u_int mii_ticks; /* MII_TICK counter */ u_int mii_anegticks; /* ticks before retrying aneg */ u_int mii_media_active; /* last active media */ u_int mii_media_status; /* last active status */ }; typedef struct mii_softc mii_softc_t; /* mii_flags */ #define MIIF_INITDONE 0x00000001 /* has been initialized (mii_data) */ #define MIIF_NOISOLATE 0x00000002 /* do not isolate the PHY */ #if 0 #define MIIF_NOLOOP 0x00000004 /* no loopback capability */ #endif #define MIIF_DOINGAUTO 0x00000008 /* doing autonegotiation (mii_softc) */ #define MIIF_AUTOTSLEEP 0x00000010 /* use tsleep(), not callout() */ #define MIIF_HAVEFIBER 0x00000020 /* from parent: has fiber interface */ #define MIIF_HAVE_GTCR 0x00000040 /* has 100base-T2/1000base-T CR */ #define MIIF_IS_1000X 0x00000080 /* is a 1000BASE-X device */ #define MIIF_DOPAUSE 0x00000100 /* advertise PAUSE capability */ #define MIIF_IS_HPNA 0x00000200 /* is a HomePNA device */ #define MIIF_FORCEANEG 0x00000400 /* force auto-negotiation */ +#define MIIF_RX_DELAY 0x00000800 /* add RX delay */ +#define MIIF_TX_DELAY 0x00001000 /* add TX delay */ #define MIIF_NOMANPAUSE 0x00100000 /* no manual PAUSE selection */ #define MIIF_FORCEPAUSE 0x00200000 /* force PAUSE advertisement */ #define MIIF_MACPRIV0 0x01000000 /* private to the MAC driver */ #define MIIF_MACPRIV1 0x02000000 /* private to the MAC driver */ #define MIIF_MACPRIV2 0x04000000 /* private to the MAC driver */ #define MIIF_PHYPRIV0 0x10000000 /* private to the PHY driver */ #define MIIF_PHYPRIV1 0x20000000 /* private to the PHY driver */ #define MIIF_PHYPRIV2 0x40000000 /* private to the PHY driver */ /* Default mii_anegticks values */ #define MII_ANEGTICKS 5 #define MII_ANEGTICKS_GIGE 17 #define MIIF_INHERIT_MASK (MIIF_NOISOLATE|MIIF_NOLOOP|MIIF_AUTOTSLEEP) /* * Special `locators' passed to mii_attach(). If one of these is not * an `any' value, we look for *that* PHY and configure it. If both * are not `any', that is an error, and mii_attach() will fail. */ #define MII_OFFSET_ANY -1 #define MII_PHY_ANY -1 /* * Constants used to describe the type of attachment between MAC and PHY. */ enum mii_contype { MII_CONTYPE_UNKNOWN, /* Must be have value 0. */ MII_CONTYPE_MII, MII_CONTYPE_GMII, MII_CONTYPE_SGMII, MII_CONTYPE_QSGMII, MII_CONTYPE_TBI, MII_CONTYPE_REVMII, /* Reverse MII */ MII_CONTYPE_RMII, MII_CONTYPE_RGMII, /* Delays provided by MAC or PCB */ MII_CONTYPE_RGMII_ID, /* Rx and tx delays provided by PHY */ MII_CONTYPE_RGMII_RXID, /* Only rx delay provided by PHY */ MII_CONTYPE_RGMII_TXID, /* Only tx delay provided by PHY */ MII_CONTYPE_RTBI, MII_CONTYPE_SMII, MII_CONTYPE_XGMII, MII_CONTYPE_TRGMII, MII_CONTYPE_2000BX, MII_CONTYPE_2500BX, MII_CONTYPE_RXAUI, MII_CONTYPE_COUNT /* Add new types before this line. */ }; typedef enum mii_contype mii_contype_t; static inline bool mii_contype_is_rgmii(mii_contype_t con) { return (con >= MII_CONTYPE_RGMII && con <= MII_CONTYPE_RGMII_TXID); } /* * Used to attach a PHY to a parent. */ struct mii_attach_args { struct mii_data *mii_data; /* pointer to parent data */ u_int mii_phyno; /* MII address */ u_int mii_offset; /* first PHY, second PHY, etc. */ uint32_t mii_id1; /* PHY ID register 1 */ uint32_t mii_id2; /* PHY ID register 2 */ u_int mii_capmask; /* capability mask for BMSR */ }; typedef struct mii_attach_args mii_attach_args_t; /* * Used to match a PHY. */ struct mii_phydesc { uint32_t mpd_oui; /* the PHY's OUI */ uint32_t mpd_model; /* the PHY's model */ const char *mpd_name; /* the PHY's name */ }; #define MII_PHY_DESC(a, b) { MII_OUI_ ## a, MII_MODEL_ ## a ## _ ## b, \ MII_STR_ ## a ## _ ## b } #define MII_PHY_END { 0, 0, NULL } #ifdef _KERNEL #define PHY_READ(p, r) \ MIIBUS_READREG((p)->mii_dev, (p)->mii_phy, (r)) #define PHY_WRITE(p, r, v) \ MIIBUS_WRITEREG((p)->mii_dev, (p)->mii_phy, (r), (v)) #define PHY_SERVICE(p, d, o) \ (*(p)->mii_funcs->pf_service)((p), (d), (o)) #define PHY_STATUS(p) \ (*(p)->mii_funcs->pf_status)(p) #define PHY_RESET(p) \ (*(p)->mii_funcs->pf_reset)(p) enum miibus_device_ivars { MIIBUS_IVAR_FLAGS }; /* * Simplified accessors for miibus */ #define MIIBUS_ACCESSOR(var, ivar, type) \ __BUS_ACCESSOR(miibus, var, MIIBUS, ivar, type) MIIBUS_ACCESSOR(flags, FLAGS, u_int) extern devclass_t miibus_devclass; extern driver_t miibus_driver; int mii_attach(device_t, device_t *, if_t, ifm_change_cb_t, ifm_stat_cb_t, int, int, int, int); int mii_mediachg(struct mii_data *); void mii_tick(struct mii_data *); void mii_pollstat(struct mii_data *); void mii_phy_add_media(struct mii_softc *); int mii_phy_auto(struct mii_softc *); int mii_phy_detach(device_t dev); u_int mii_phy_flowstatus(struct mii_softc *); void mii_phy_reset(struct mii_softc *); void mii_phy_setmedia(struct mii_softc *sc); void mii_phy_update(struct mii_softc *, int); int mii_phy_tick(struct mii_softc *); int mii_phy_mac_match(struct mii_softc *, const char *); int mii_dev_mac_match(device_t, const char *); void *mii_phy_mac_softc(struct mii_softc *); void *mii_dev_mac_softc(device_t); const struct mii_phydesc * mii_phy_match(const struct mii_attach_args *ma, const struct mii_phydesc *mpd); const struct mii_phydesc * mii_phy_match_gen(const struct mii_attach_args *ma, const struct mii_phydesc *mpd, size_t endlen); int mii_phy_dev_probe(device_t dev, const struct mii_phydesc *mpd, int mrv); void mii_phy_dev_attach(device_t dev, u_int flags, const struct mii_phy_funcs *mpf, int add_media); void ukphy_status(struct mii_softc *); u_int mii_oui(u_int, u_int); #define MII_OUI(id1, id2) mii_oui(id1, id2) #define MII_MODEL(id2) (((id2) & IDR2_MODEL) >> 4) #define MII_REV(id2) ((id2) & IDR2_REV) #endif /* _KERNEL */ #endif /* _DEV_MII_MIIVAR_H_ */