Module Name: src Committed By: martin Date: Wed Nov 27 11:08:24 UTC 2019
Modified Files: src/sys/dev/pci [netbsd-9]: if_bge.c Log Message: Pull up following revision(s) (requested by msaitoh in ticket #487): sys/dev/pci/if_bge.c: revision 1.340 sys/dev/pci/if_bge.c: revision 1.341 sys/dev/pci/if_bge.c: revision 1.342 sys/dev/pci/if_bge.c: revision 1.336 - Avoid undefined behavior in bge_setmulti(). found by kUBSan. - Avoid undefined behavior when setting the MAC address in bge_init(). found by kUBSan. Fix a bug that SK-9D41 can't detect fiber media. Check the subsystem ID correctly. This bug was added in if_bge.c rev. 1.161. - Use *_FLUSH() more. The main purpose is to wait following delay() correctly. - Add missing DELAY(80) after writing BGE_MI_MODE register. Modify PHY initialization code. This change fix a bug that SK-9D21 doesn't detect MII PHY. - Add error check to bge_miibus_writereg(). - Change return value of bge_miibus_readreg() when a read error occurred. It also add error message using with aprint_debug_dev(). This error occurs on some devices while detecting MII devices. - Move the location of BGE_MI_MODE register's initialization to next to bge_chipinit(). - Set BGE_MAC_MODE before calling ifmedia_init() and/or mii_attach(). - Add retry code for mii_attach() failed. Same as FreeBSD. To generate a diff of this commit: cvs rdiff -u -r1.335 -r1.335.2.1 src/sys/dev/pci/if_bge.c 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_bge.c diff -u src/sys/dev/pci/if_bge.c:1.335 src/sys/dev/pci/if_bge.c:1.335.2.1 --- src/sys/dev/pci/if_bge.c:1.335 Tue Jul 9 08:46:58 2019 +++ src/sys/dev/pci/if_bge.c Wed Nov 27 11:08:24 2019 @@ -1,4 +1,4 @@ -/* $NetBSD: if_bge.c,v 1.335 2019/07/09 08:46:58 msaitoh Exp $ */ +/* $NetBSD: if_bge.c,v 1.335.2.1 2019/11/27 11:08:24 martin Exp $ */ /* * Copyright (c) 2001 Wind River Systems @@ -79,7 +79,7 @@ */ #include <sys/cdefs.h> -__KERNEL_RCSID(0, "$NetBSD: if_bge.c,v 1.335 2019/07/09 08:46:58 msaitoh Exp $"); +__KERNEL_RCSID(0, "$NetBSD: if_bge.c,v 1.335.2.1 2019/11/27 11:08:24 martin Exp $"); #include <sys/param.h> #include <sys/systm.h> @@ -1027,10 +1027,10 @@ bge_eeprom_getbyte(struct bge_softc *sc, * Enable use of auto EEPROM access so we can avoid * having to use the bitbang method. */ - BGE_SETBIT(sc, BGE_MISC_LOCAL_CTL, BGE_MLC_AUTO_EEPROM); + BGE_SETBIT_FLUSH(sc, BGE_MISC_LOCAL_CTL, BGE_MLC_AUTO_EEPROM); /* Reset the EEPROM, load the clock period. */ - CSR_WRITE_4(sc, BGE_EE_ADDR, + CSR_WRITE_4_FLUSH(sc, BGE_EE_ADDR, BGE_EEADDR_RESET | BGE_EEHALFCLK(BGE_HALFCLK_384SCL)); DELAY(20); @@ -1113,9 +1113,11 @@ bge_miibus_readreg(device_t dev, int phy if (i == BGE_TIMEOUT) { aprint_error_dev(sc->bge_dev, "PHY read timed out\n"); rv = ETIMEDOUT; - } else if ((data & BGE_MICOMM_READFAIL) != 0) - rv = -1; - else + } else if ((data & BGE_MICOMM_READFAIL) != 0) { + /* XXX This error occurs on some devices while attaching. */ + aprint_debug_dev(sc->bge_dev, "PHY read I/O error\n"); + rv = EIO; + } else *val = data & BGE_MICOMM_DATA; if (autopoll & BGE_MIMODE_AUTOPOLL) { @@ -1133,7 +1135,8 @@ static int bge_miibus_writereg(device_t dev, int phy, int reg, uint16_t val) { struct bge_softc *sc = device_private(dev); - uint32_t autopoll; + uint32_t data, autopoll; + int rv = 0; int i; if (BGE_ASICREV(sc->bge_chipid) == BGE_ASICREV_BCM5906 && @@ -1156,13 +1159,22 @@ bge_miibus_writereg(device_t dev, int ph for (i = 0; i < BGE_TIMEOUT; i++) { delay(10); - if (!(CSR_READ_4(sc, BGE_MI_COMM) & BGE_MICOMM_BUSY)) { + data = CSR_READ_4(sc, BGE_MI_COMM); + if (!(data & BGE_MICOMM_BUSY)) { delay(5); - CSR_READ_4(sc, BGE_MI_COMM); + data = CSR_READ_4(sc, BGE_MI_COMM); break; } } + if (i == BGE_TIMEOUT) { + aprint_error_dev(sc->bge_dev, "PHY write timed out\n"); + rv = ETIMEDOUT; + } else if ((data & BGE_MICOMM_READFAIL) != 0) { + aprint_error_dev(sc->bge_dev, "PHY write I/O error\n"); + rv = EIO; + } + if (autopoll & BGE_MIMODE_AUTOPOLL) { BGE_STS_SETBIT(sc, BGE_STS_AUTOPOLL); BGE_SETBIT_FLUSH(sc, BGE_MI_MODE, BGE_MIMODE_AUTOPOLL); @@ -1176,7 +1188,7 @@ bge_miibus_writereg(device_t dev, int ph return ETIMEDOUT; } - return 0; + return rv; } static void @@ -1827,7 +1839,7 @@ bge_setmulti(struct bge_softc *sc) /* Just want the 7 least-significant bits. */ h &= 0x7f; - hashes[(h & 0x60) >> 5] |= 1 << (h & 0x1F); + hashes[(h & 0x60) >> 5] |= 1U << (h & 0x1F); ETHER_NEXT_MULTI(step, enm); } ETHER_UNLOCK(ec); @@ -2286,7 +2298,7 @@ bge_chipinit(struct bge_softc *sc) #endif /* Set the timer prescaler (always 66MHz) */ - CSR_WRITE_4(sc, BGE_MISC_CFG, BGE_32BITTIME_66MHZ); + CSR_WRITE_4_FLUSH(sc, BGE_MISC_CFG, BGE_32BITTIME_66MHZ); if (BGE_ASICREV(sc->bge_chipid) == BGE_ASICREV_BCM5906) { DELAY(40); /* XXX */ @@ -3182,14 +3194,14 @@ bge_attach(device_t parent, device_t sel uint32_t command; struct ifnet *ifp; struct mii_data * const mii = &sc->bge_mii; - uint32_t misccfg, mimode; + uint32_t misccfg, mimode, macmode; void * kva; u_char eaddr[ETHER_ADDR_LEN]; pcireg_t memtype, subid, reg; bus_addr_t memaddr; uint32_t pm_ctl; bool no_seeprom; - int capmask; + int capmask, trys; int mii_flags; int map_flags; char intrbuf[PCI_INTRSTR_LEN]; @@ -3433,14 +3445,6 @@ bge_attach(device_t parent, device_t sel BGE_ASICREV(sc->bge_chipid) == BGE_ASICREV_BCM57780) sc->bge_flags |= BGEF_CPMU_PRESENT; - /* Set MI_MODE */ - mimode = BGE_MIMODE_PHYADDR(sc->bge_phy_addr); - if ((sc->bge_flags & BGEF_CPMU_PRESENT) != 0) - mimode |= BGE_MIMODE_500KHZ_CONST; - else - mimode |= BGE_MIMODE_BASE; - CSR_WRITE_4(sc, BGE_MI_MODE, mimode); - /* * When using the BCM5701 in PCI-X mode, data corruption has * been observed in the first few bytes of some received packets. @@ -3636,10 +3640,10 @@ bge_attach(device_t parent, device_t sel * Reset NVRAM before bge_reset(). It's required to acquire NVRAM * lock in bge_reset(). */ - CSR_WRITE_4(sc, BGE_EE_ADDR, + CSR_WRITE_4_FLUSH(sc, BGE_EE_ADDR, BGE_EEADDR_RESET | BGE_EEHALFCLK(BGE_HALFCLK_384SCL)); delay(1000); - BGE_SETBIT(sc, BGE_MISC_LOCAL_CTL, BGE_MLC_AUTO_EEPROM); + BGE_SETBIT_FLUSH(sc, BGE_MISC_LOCAL_CTL, BGE_MLC_AUTO_EEPROM); bge_stop_fw(sc); bge_sig_pre_reset(sc, BGE_RESET_START); @@ -3685,6 +3689,21 @@ bge_attach(device_t parent, device_t sel return; } + if (BGE_ASICREV(sc->bge_chipid) == BGE_ASICREV_BCM5700) { + BGE_SETBIT_FLUSH(sc, BGE_MISC_LOCAL_CTL, + BGE_MLC_MISCIO_OUT1 | BGE_MLC_MISCIO_OUTEN1); + DELAY(100); + } + + /* Set MI_MODE */ + mimode = BGE_MIMODE_PHYADDR(sc->bge_phy_addr); + if ((sc->bge_flags & BGEF_CPMU_PRESENT) != 0) + mimode |= BGE_MIMODE_500KHZ_CONST; + else + mimode |= BGE_MIMODE_BASE; + CSR_WRITE_4_FLUSH(sc, BGE_MI_MODE, mimode); + DELAY(80); + /* * Get station address from the EEPROM. */ @@ -3853,7 +3872,7 @@ bge_attach(device_t parent, device_t sel * by its PCI subsystem ID, as we do below for the SysKonnect SK-9D41. * The SysKonnect SK-9D41 is a 1000baseSX card. */ - if (PCI_PRODUCT(pa->pa_id) == SK_SUBSYSID_9D41 || + if (PCI_PRODUCT(subid) == SK_SUBSYSID_9D41 || (hwcfg & BGE_HWCFG_MEDIA) == BGE_MEDIA_FIBER) { if (BGE_IS_5705_PLUS(sc)) { sc->bge_flags |= BGEF_FIBER_MII; @@ -3871,8 +3890,14 @@ bge_attach(device_t parent, device_t sel prop_dictionary_set_uint32(dict, "phyflags", sc->bge_phy_flags); prop_dictionary_set_uint32(dict, "chipid", sc->bge_chipid); + macmode = CSR_READ_4(sc, BGE_MAC_MODE); + macmode &= ~BGE_MACMODE_PORTMODE; /* Initialize ifmedia structures. */ if (sc->bge_flags & BGEF_FIBER_TBI) { + CSR_WRITE_4_FLUSH(sc, BGE_MAC_MODE, + macmode | BGE_PORTMODE_TBI); + DELAY(40); + sc->ethercom.ec_ifmedia = &sc->bge_ifmedia; ifmedia_init(&sc->bge_ifmedia, IFM_IMASK, bge_ifmedia_upd, bge_ifmedia_sts); @@ -3884,6 +3909,8 @@ bge_attach(device_t parent, device_t sel /* Pretend the user requested this setting */ sc->bge_ifmedia.ifm_media = sc->bge_ifmedia.ifm_cur->ifm_media; } else { + uint16_t phyreg; + int rv; /* * Do transceiver setup and tell the firmware the * driver is down so we can try to get access the @@ -3891,18 +3918,53 @@ bge_attach(device_t parent, device_t sel * if we get a conflict with the ASF firmware accessing * the PHY. */ - BGE_CLRBIT(sc, BGE_MODE_CTL, BGE_MODECTL_STACKUP); - bge_asf_driver_up(sc); + if (sc->bge_flags & BGEF_FIBER_MII) + macmode |= BGE_PORTMODE_GMII; + else + macmode |= BGE_PORTMODE_MII; + CSR_WRITE_4_FLUSH(sc, BGE_MAC_MODE, macmode); + DELAY(40); + /* + * Do transceiver setup and tell the firmware the + * driver is down so we can try to get access the + * probe if ASF is running. Retry a couple of times + * if we get a conflict with the ASF firmware accessing + * the PHY. + */ + trys = 0; + BGE_CLRBIT(sc, BGE_MODE_CTL, BGE_MODECTL_STACKUP); sc->ethercom.ec_mii = mii; ifmedia_init(&mii->mii_media, 0, bge_ifmedia_upd, bge_ifmedia_sts); mii_flags = MIIF_DOPAUSE; if (sc->bge_flags & BGEF_FIBER_MII) mii_flags |= MIIF_HAVEFIBER; +again: + bge_asf_driver_up(sc); + rv = bge_miibus_readreg(sc->bge_dev, sc->bge_phy_addr, + MII_BMCR, &phyreg); + if ((rv != 0) || ((phyreg & BMCR_PDOWN) != 0)) { + int i; + + bge_miibus_writereg(sc->bge_dev, sc->bge_phy_addr, + MII_BMCR, BMCR_RESET); + /* Wait up to 500ms for it to complete. */ + for (i = 0; i < 500; i++) { + bge_miibus_readreg(sc->bge_dev, + sc->bge_phy_addr, MII_BMCR, &phyreg); + if ((phyreg & BMCR_RESET) == 0) + break; + DELAY(1000); + } + } + mii_attach(sc->bge_dev, mii, capmask, sc->bge_phy_addr, MII_OFFSET_ANY, mii_flags); + if (LIST_EMPTY(&mii->mii_phys) && (trys++ < 4)) + goto again; + if (LIST_EMPTY(&mii->mii_phys)) { aprint_error_dev(sc->bge_dev, "no PHY found!\n"); ifmedia_add(&mii->mii_media, IFM_ETHER | IFM_MANUAL, @@ -5530,7 +5592,8 @@ bge_init(struct ifnet *ifp) /* Load our MAC address. */ m = (const uint16_t *)&(CLLADDR(ifp->if_sadl)[0]); CSR_WRITE_4(sc, BGE_MAC_ADDR1_LO, htons(m[0])); - CSR_WRITE_4(sc, BGE_MAC_ADDR1_HI, (htons(m[1]) << 16) | htons(m[2])); + CSR_WRITE_4(sc, BGE_MAC_ADDR1_HI, + ((uint32_t)htons(m[1]) << 16) | htons(m[2])); /* Enable or disable promiscuous mode as needed. */ if (ifp->if_flags & IFF_PROMISC) @@ -5676,10 +5739,10 @@ bge_ifmedia_upd(struct ifnet *ifp) break; case IFM_1000_SX: if ((ifm->ifm_media & IFM_FDX) != 0) { - BGE_CLRBIT(sc, BGE_MAC_MODE, + BGE_CLRBIT_FLUSH(sc, BGE_MAC_MODE, BGE_MACMODE_HALF_DUPLEX); } else { - BGE_SETBIT(sc, BGE_MAC_MODE, + BGE_SETBIT_FLUSH(sc, BGE_MAC_MODE, BGE_MACMODE_HALF_DUPLEX); } DELAY(40); @@ -6077,7 +6140,7 @@ bge_link_upd(struct bge_softc *sc) BGE_STS_SETBIT(sc, BGE_STS_LINK); if (BGE_ASICREV(sc->bge_chipid) == BGE_ASICREV_BCM5704) { - BGE_CLRBIT(sc, BGE_MAC_MODE, + BGE_CLRBIT_FLUSH(sc, BGE_MAC_MODE, BGE_MACMODE_TBI_SEND_CFGS); DELAY(40); }