Module Name: src Committed By: martin Date: Tue Aug 6 16:10:17 UTC 2019
Modified Files: src/sys/dev/pci [netbsd-8]: if_et.c if_etreg.h Log Message: Pull up the following revisions, requested by msaitoh in ticket #1329: sys/dev/pci/if_etreg.h 1.2-1.3 sys/dev/pci/if_et.c 1.23,1.25 and 1.26 via patch Make et(4) work: - Add missing ifioctl_common() for SIOCSIFFLAGS to make if_flags controllable. - Enabling TX/RX in et_init() will always fail when cable is not plugged in. If this happens, we delay TX/RX enablement until link is up. - Modify flow control stuff a little. It still doesn't work. - Avoid undefined behavior when reset the chip. - Code cleanup. To generate a diff of this commit: cvs rdiff -u -r1.14.8.2 -r1.14.8.3 src/sys/dev/pci/if_et.c cvs rdiff -u -r1.1 -r1.1.54.1 src/sys/dev/pci/if_etreg.h Please note that diffs are not public domain; they are subject to the copyright notices on the relevant files.
Modified files: Index: src/sys/dev/pci/if_et.c diff -u src/sys/dev/pci/if_et.c:1.14.8.2 src/sys/dev/pci/if_et.c:1.14.8.3 --- src/sys/dev/pci/if_et.c:1.14.8.2 Mon May 13 12:40:13 2019 +++ src/sys/dev/pci/if_et.c Tue Aug 6 16:10:17 2019 @@ -1,5 +1,5 @@ -/* $NetBSD: if_et.c,v 1.14.8.2 2019/05/13 12:40:13 martin Exp $ */ -/* $OpenBSD: if_et.c,v 1.11 2008/06/08 06:18:07 jsg Exp $ */ +/* $NetBSD: if_et.c,v 1.14.8.3 2019/08/06 16:10:17 martin Exp $ */ +/* $OpenBSD: if_et.c,v 1.12 2008/07/11 09:29:02 kevlo $ */ /* * Copyright (c) 2007 The DragonFly Project. All rights reserved. * @@ -37,7 +37,7 @@ */ #include <sys/cdefs.h> -__KERNEL_RCSID(0, "$NetBSD: if_et.c,v 1.14.8.2 2019/05/13 12:40:13 martin Exp $"); +__KERNEL_RCSID(0, "$NetBSD: if_et.c,v 1.14.8.3 2019/08/06 16:10:17 martin Exp $"); #include "opt_inet.h" #include "vlan.h" @@ -83,17 +83,19 @@ __KERNEL_RCSID(0, "$NetBSD: if_et.c,v 1. int et_match(device_t, cfdata_t, void *); void et_attach(device_t, device_t, void *); -int et_detach(device_t, int flags); +int et_detach(device_t, int); int et_shutdown(device_t); int et_miibus_readreg(device_t, int, int); void et_miibus_writereg(device_t, int, int, int); void et_miibus_statchg(struct ifnet *); -int et_init(struct ifnet *ifp); +int et_init(struct ifnet *); int et_ioctl(struct ifnet *, u_long, void *); void et_start(struct ifnet *); void et_watchdog(struct ifnet *); +static int et_ifmedia_upd(struct ifnet *); +static void et_ifmedia_sts(struct ifnet *, struct ifmediareq *); int et_intr(void *); void et_enable_intrs(struct et_softc *, uint32_t); @@ -131,7 +133,6 @@ int et_start_rxdma(struct et_softc *); int et_start_txdma(struct et_softc *); int et_stop_rxdma(struct et_softc *); int et_stop_txdma(struct et_softc *); -int et_enable_txrx(struct et_softc *); void et_reset(struct et_softc *); int et_bus_config(struct et_softc *); void et_get_eaddr(struct et_softc *, uint8_t[]); @@ -189,6 +190,8 @@ et_attach(device_t parent, device_t self pci_intr_handle_t ih; const char *intrstr; struct ifnet *ifp = &sc->sc_ethercom.ec_if; + struct mii_data * const mii = &sc->sc_miibus; + uint32_t pmcfg; pcireg_t memtype; int error; char intrbuf[PCI_INTRSTR_LEN]; @@ -232,6 +235,9 @@ et_attach(device_t parent, device_t self sc->sc_pct = pa->pa_pc; sc->sc_pcitag = pa->pa_tag; + if (pa->pa_id == PCI_PRODUCT_LUCENT_ET1301) + sc->sc_flags |= ET_FLAG_FASTETHER; + error = et_bus_config(sc); if (error) goto fail; @@ -241,8 +247,11 @@ et_attach(device_t parent, device_t self aprint_normal_dev(self, "Ethernet address %s\n", ether_sprintf(sc->sc_enaddr)); - CSR_WRITE_4(sc, ET_PM, - ET_PM_SYSCLK_GATE | ET_PM_TXCLK_GATE | ET_PM_RXCLK_GATE); + /* Take PHY out of COMA and enable clocks. */ + pmcfg = ET_PM_SYSCLK_GATE | ET_PM_TXCLK_GATE | ET_PM_RXCLK_GATE; + if ((sc->sc_flags & ET_FLAG_FASTETHER) == 0) + pmcfg |= EM_PM_GIGEPHY_ENB; + CSR_WRITE_4(sc, ET_PM, pmcfg); et_reset(sc); @@ -265,23 +274,21 @@ et_attach(device_t parent, device_t self et_chip_attach(sc); - sc->sc_miibus.mii_ifp = ifp; - sc->sc_miibus.mii_readreg = et_miibus_readreg; - sc->sc_miibus.mii_writereg = et_miibus_writereg; - sc->sc_miibus.mii_statchg = et_miibus_statchg; - - sc->sc_ethercom.ec_mii = &sc->sc_miibus; - ifmedia_init(&sc->sc_miibus.mii_media, 0, ether_mediachange, - ether_mediastatus); - mii_attach(self, &sc->sc_miibus, 0xffffffff, MII_PHY_ANY, - MII_OFFSET_ANY, 0); - if (LIST_FIRST(&sc->sc_miibus.mii_phys) == NULL) { + mii->mii_ifp = ifp; + mii->mii_readreg = et_miibus_readreg; + mii->mii_writereg = et_miibus_writereg; + mii->mii_statchg = et_miibus_statchg; + + sc->sc_ethercom.ec_mii = mii; + ifmedia_init(&mii->mii_media, 0, et_ifmedia_upd, et_ifmedia_sts); + mii_attach(self, mii, 0xffffffff, MII_PHY_ANY, MII_OFFSET_ANY, 0); + if (LIST_FIRST(&mii->mii_phys) == NULL) { aprint_error_dev(self, "no PHY found!\n"); - ifmedia_add(&sc->sc_miibus.mii_media, IFM_ETHER | IFM_MANUAL, + ifmedia_add(&mii->mii_media, IFM_ETHER | IFM_MANUAL, 0, NULL); - ifmedia_set(&sc->sc_miibus.mii_media, IFM_ETHER | IFM_MANUAL); + ifmedia_set(&mii->mii_media, IFM_ETHER | IFM_MANUAL); } else - ifmedia_set(&sc->sc_miibus.mii_media, IFM_ETHER | IFM_AUTO); + ifmedia_set(&mii->mii_media, IFM_ETHER | IFM_AUTO); if_attach(ifp); if_deferred_start_init(ifp, NULL); @@ -443,31 +450,117 @@ et_miibus_statchg(struct ifnet *ifp) { struct et_softc *sc = ifp->if_softc; struct mii_data *mii = &sc->sc_miibus; - uint32_t cfg2, ctrl; + uint32_t cfg1, cfg2, ctrl; + int i; + + sc->sc_flags &= ~ET_FLAG_LINK; + if ((mii->mii_media_status & (IFM_ACTIVE | IFM_AVALID)) == + (IFM_ACTIVE | IFM_AVALID)) { + switch (IFM_SUBTYPE(mii->mii_media_active)) { + case IFM_10_T: + case IFM_100_TX: + sc->sc_flags |= ET_FLAG_LINK; + break; + case IFM_1000_T: + if ((sc->sc_flags & ET_FLAG_FASTETHER) == 0) + sc->sc_flags |= ET_FLAG_LINK; + break; + } + } + /* XXX Stop TX/RX MAC? */ + if ((sc->sc_flags & ET_FLAG_LINK) == 0) + return; + + /* Program MACs with resolved speed/duplex/flow-control. */ + ctrl = CSR_READ_4(sc, ET_MAC_CTRL); + ctrl &= ~(ET_MAC_CTRL_GHDX | ET_MAC_CTRL_MODE_MII); + cfg1 = CSR_READ_4(sc, ET_MAC_CFG1); + cfg1 &= ~(ET_MAC_CFG1_TXFLOW | ET_MAC_CFG1_RXFLOW | + ET_MAC_CFG1_LOOPBACK); cfg2 = CSR_READ_4(sc, ET_MAC_CFG2); cfg2 &= ~(ET_MAC_CFG2_MODE_MII | ET_MAC_CFG2_MODE_GMII | - ET_MAC_CFG2_FDX | ET_MAC_CFG2_BIGFRM); + ET_MAC_CFG2_FDX | ET_MAC_CFG2_BIGFRM); cfg2 |= ET_MAC_CFG2_LENCHK | ET_MAC_CFG2_CRC | ET_MAC_CFG2_PADCRC | - __SHIFTIN(7, ET_MAC_CFG2_PREAMBLE_LEN); + __SHIFTIN(7, ET_MAC_CFG2_PREAMBLE_LEN); - ctrl = CSR_READ_4(sc, ET_MAC_CTRL); - ctrl &= ~(ET_MAC_CTRL_GHDX | ET_MAC_CTRL_MODE_MII); - if (IFM_SUBTYPE(mii->mii_media_active) == IFM_1000_T) { + if (IFM_SUBTYPE(mii->mii_media_active) == IFM_1000_T) cfg2 |= ET_MAC_CFG2_MODE_GMII; - } else { + else { cfg2 |= ET_MAC_CFG2_MODE_MII; ctrl |= ET_MAC_CTRL_MODE_MII; } - if ((mii->mii_media_active & IFM_FDX) != 0) + if (IFM_OPTIONS(mii->mii_media_active) & IFM_FDX) { cfg2 |= ET_MAC_CFG2_FDX; - else + /* + * Controller lacks automatic TX pause frame + * generation so it should be handled by driver. + * Even though driver can send pause frame with + * arbitrary pause time, controller does not + * provide a way that tells how many free RX + * buffers are available in controller. This + * limitation makes it hard to generate XON frame + * in time on driver side so don't enable TX flow + * control. + */ +#ifdef notyet + if (IFM_OPTIONS(mii->mii_media_active) & IFM_ETH_TXPAUSE) + cfg1 |= ET_MAC_CFG1_TXFLOW; +#endif + if (IFM_OPTIONS(mii->mii_media_active) & IFM_ETH_RXPAUSE) + cfg1 |= ET_MAC_CFG1_RXFLOW; + } else ctrl |= ET_MAC_CTRL_GHDX; CSR_WRITE_4(sc, ET_MAC_CTRL, ctrl); CSR_WRITE_4(sc, ET_MAC_CFG2, cfg2); + cfg1 |= ET_MAC_CFG1_TXEN | ET_MAC_CFG1_RXEN; + CSR_WRITE_4(sc, ET_MAC_CFG1, cfg1); + +#define NRETRY 100 + + for (i = 0; i < NRETRY; ++i) { + cfg1 = CSR_READ_4(sc, ET_MAC_CFG1); + if ((cfg1 & (ET_MAC_CFG1_SYNC_TXEN | ET_MAC_CFG1_SYNC_RXEN)) == + (ET_MAC_CFG1_SYNC_TXEN | ET_MAC_CFG1_SYNC_RXEN)) + break; + + DELAY(10); + } + /* Note: Timeout always happens when cable is not plugged in. */ + + sc->sc_flags |= ET_FLAG_TXRX_ENABLED; + +#undef NRETRY +} + +static int +et_ifmedia_upd(struct ifnet *ifp) +{ + struct et_softc *sc; + struct mii_data *mii; + struct mii_softc *miisc; + + sc = ifp->if_softc; + mii = &sc->sc_miibus; + LIST_FOREACH(miisc, &mii->mii_phys, mii_list) + PHY_RESET(miisc); + return (mii_mediachg(mii)); +} + +static void +et_ifmedia_sts(struct ifnet *ifp, struct ifmediareq *ifmr) +{ + struct et_softc *sc; + struct mii_data *mii; + + sc = ifp->if_softc; + mii = &sc->sc_miibus; + mii_pollstat(mii); + ifmr->ifm_active = mii->mii_media_active; + ifmr->ifm_status = mii->mii_media_status; } void @@ -490,6 +583,7 @@ et_stop(struct et_softc *sc) sc->sc_tx = 0; sc->sc_tx_intr = 0; + sc->sc_flags &= ~ET_FLAG_TXRX_ENABLED; ifp->if_timer = 0; ifp->if_flags &= ~(IFF_RUNNING | IFF_OACTIVE); @@ -588,6 +682,7 @@ et_get_eaddr(struct et_softc *sc, uint8_ void et_reset(struct et_softc *sc) { + CSR_WRITE_4(sc, ET_MAC_CFG1, ET_MAC_CFG1_RST_TXFUNC | ET_MAC_CFG1_RST_RXFUNC | ET_MAC_CFG1_RST_TXMC | ET_MAC_CFG1_RST_RXMC | @@ -731,7 +826,7 @@ et_dma_free(struct et_softc *sc) * Destroy RX stat ring DMA stuffs */ et_dma_mem_destroy(sc, rxst_ring->rsr_stat, rxst_ring->rsr_dmap); - + /* * Destroy RX status DMA stuffs */ @@ -974,6 +1069,7 @@ et_init(struct ifnet *ifp) s = splnet(); et_stop(sc); + et_reset(sc); for (i = 0; i < ET_RX_NRING; ++i) { sc->sc_rx_data[i].rbd_bufsize = et_bufsize[i].bufsize; @@ -992,10 +1088,6 @@ et_init(struct ifnet *ifp) if (error) goto back; - error = et_enable_txrx(sc); - if (error) - goto back; - error = et_start_rxdma(sc); if (error) goto back; @@ -1004,6 +1096,7 @@ et_init(struct ifnet *ifp) if (error) goto back; + /* Enable interrupts. */ et_enable_intrs(sc, ET_INTRS); callout_schedule(&sc->sc_tick, hz); @@ -1012,6 +1105,9 @@ et_init(struct ifnet *ifp) ifp->if_flags |= IFF_RUNNING; ifp->if_flags &= ~IFF_OACTIVE; + + sc->sc_flags &= ~ET_FLAG_LINK; + et_ifmedia_upd(ifp); back: if (error) et_stop(sc); @@ -1032,6 +1128,8 @@ et_ioctl(struct ifnet *ifp, u_long cmd, switch (cmd) { case SIOCSIFFLAGS: + if ((error = ifioctl_common(ifp, cmd, data)) != 0) + break; if (ifp->if_flags & IFF_UP) { /* * If only the PROMISC or ALLMULTI flag changes, then @@ -1064,7 +1162,6 @@ et_ioctl(struct ifnet *ifp, u_long cmd, error = 0; } break; - } splx(s); @@ -1080,7 +1177,9 @@ et_start(struct ifnet *ifp) int trans; struct mbuf *m; - if ((ifp->if_flags & (IFF_RUNNING | IFF_OACTIVE)) != IFF_RUNNING) + if (((ifp->if_flags & (IFF_RUNNING | IFF_OACTIVE)) != IFF_RUNNING) || + ((sc->sc_flags & (ET_FLAG_LINK | ET_FLAG_TXRX_ENABLED)) != + (ET_FLAG_LINK | ET_FLAG_TXRX_ENABLED))) return; trans = 0; @@ -1125,6 +1224,7 @@ et_watchdog(struct ifnet *ifp) int et_stop_rxdma(struct et_softc *sc) { + CSR_WRITE_4(sc, ET_RXDMA_CTRL, ET_RXDMA_CTRL_HALT | ET_RXDMA_CTRL_RING1_ENABLE); @@ -1139,6 +1239,7 @@ et_stop_rxdma(struct et_softc *sc) int et_stop_txdma(struct et_softc *sc) { + CSR_WRITE_4(sc, ET_TXDMA_CTRL, ET_TXDMA_CTRL_HALT | ET_TXDMA_CTRL_SINGLE_EPKT); return 0; @@ -1221,7 +1322,7 @@ et_setmulti(struct et_softc *sc) uint32_t *hp, h; for (i = 0; i < ETHER_ADDR_LEN; i++) { - addr[i] &= enm->enm_addrlo[i]; + addr[i] &= enm->enm_addrlo[i]; } h = ether_crc32_be(LLADDR((struct sockaddr_dl *)addr), @@ -1606,6 +1707,7 @@ et_init_rxmac(struct et_softc *sc) void et_init_txmac(struct et_softc *sc) { + /* Disable TX MAC and FC(?) */ CSR_WRITE_4(sc, ET_TXMAC_CTRL, ET_TXMAC_CTRL_FC_DISABLE); @@ -1643,45 +1745,9 @@ et_start_rxdma(struct et_softc *sc) int et_start_txdma(struct et_softc *sc) { - CSR_WRITE_4(sc, ET_TXDMA_CTRL, ET_TXDMA_CTRL_SINGLE_EPKT); - return 0; -} - -int -et_enable_txrx(struct et_softc *sc) -{ - struct ifnet *ifp = &sc->sc_ethercom.ec_if; - uint32_t val; - int i, rc = 0; - - val = CSR_READ_4(sc, ET_MAC_CFG1); - val |= ET_MAC_CFG1_TXEN | ET_MAC_CFG1_RXEN; - val &= ~(ET_MAC_CFG1_TXFLOW | ET_MAC_CFG1_RXFLOW | - ET_MAC_CFG1_LOOPBACK); - CSR_WRITE_4(sc, ET_MAC_CFG1, val); - - if ((rc = ether_mediachange(ifp)) != 0) - goto out; -#define NRETRY 100 - - for (i = 0; i < NRETRY; ++i) { - val = CSR_READ_4(sc, ET_MAC_CFG1); - if ((val & (ET_MAC_CFG1_SYNC_TXEN | ET_MAC_CFG1_SYNC_RXEN)) == - (ET_MAC_CFG1_SYNC_TXEN | ET_MAC_CFG1_SYNC_RXEN)) - break; - - DELAY(10); - } - if (i == NRETRY) { - aprint_error_dev(sc->sc_dev, "can't enable RX/TX\n"); - return ETIMEDOUT; - } - -#undef NRETRY + CSR_WRITE_4(sc, ET_TXDMA_CTRL, ET_TXDMA_CTRL_SINGLE_EPKT); return 0; -out: - return rc; } void @@ -1693,6 +1759,9 @@ et_rxeof(struct et_softc *sc) uint32_t rxs_stat_ring; int rxst_wrap, rxst_index; + if ((sc->sc_flags & ET_FLAG_TXRX_ENABLED) == 0) + return; + bus_dmamap_sync(sc->sc_dmat, rxsd->rxsd_dmap, 0, rxsd->rxsd_dmap->dm_mapsize, BUS_DMASYNC_POSTREAD); bus_dmamap_sync(sc->sc_dmat, rxst_ring->rsr_dmap, 0, @@ -1902,7 +1971,6 @@ et_encap(struct et_softc *sc, struct mbu bus_dmamap_sync(sc->sc_dmat, tx_ring->tr_dmap, 0, tx_ring->tr_dmap->dm_mapsize, BUS_DMASYNC_PREWRITE); - tx_ready_pos = __SHIFTIN(tx_ring->tr_ready_index, ET_TX_READY_POS_INDEX); @@ -1928,6 +1996,9 @@ et_txeof(struct et_softc *sc) uint32_t tx_done; int end, wrap; + if ((sc->sc_flags & ET_FLAG_TXRX_ENABLED) == 0) + return; + if (tbd->tbd_used == 0) return; Index: src/sys/dev/pci/if_etreg.h diff -u src/sys/dev/pci/if_etreg.h:1.1 src/sys/dev/pci/if_etreg.h:1.1.54.1 --- src/sys/dev/pci/if_etreg.h:1.1 Sat Nov 13 00:47:25 2010 +++ src/sys/dev/pci/if_etreg.h Tue Aug 6 16:10:17 2019 @@ -1,4 +1,4 @@ -/* $NetBSD: if_etreg.h,v 1.1 2010/11/13 00:47:25 jnemeth Exp $ */ +/* $NetBSD: if_etreg.h,v 1.1.54.1 2019/08/06 16:10:17 martin Exp $ */ /* $OpenBSD: if_etreg.h,v 1.3 2008/06/08 06:18:07 jsg Exp $ */ /* @@ -92,6 +92,7 @@ #define ET_RXQ_END 0x000c #define ET_PM 0x0010 +#define EM_PM_GIGEPHY_ENB (1 << 0) #define ET_PM_SYSCLK_GATE (1 << 3) #define ET_PM_TXCLK_GATE (1 << 4) #define ET_PM_RXCLK_GATE (1 << 5) @@ -235,7 +236,7 @@ #define ET_MAC_CFG1_RST_TXMC (1 << 18) #define ET_MAC_CFG1_RST_RXMC (1 << 19) #define ET_MAC_CFG1_SIM_RST (1 << 30) -#define ET_MAC_CFG1_SOFT_RST (1 << 31) +#define ET_MAC_CFG1_SOFT_RST __BIT(31) #define ET_MAC_CFG2 0x5004 #define ET_MAC_CFG2_FDX (1 << 0) @@ -487,6 +488,7 @@ struct et_softc { struct ethercom sc_ethercom; uint8_t sc_enaddr[ETHER_ADDR_LEN]; int sc_if_flags; + uint32_t sc_flags; /* ET_FLAG_ */ int sc_mem_rid; struct resource *sc_mem_res; @@ -528,4 +530,8 @@ struct et_softc { uint32_t sc_timer; }; +#define ET_FLAG_FASTETHER 0x0004 +#define ET_FLAG_TXRX_ENABLED 0x0100 +#define ET_FLAG_LINK 0x8000 + #endif /* !_IF_ETREG_H */