Module Name: src Committed By: msaitoh Date: Mon Nov 25 05:35:26 UTC 2019
Modified Files: src/sys/dev/pci: if_bge.c Log Message: 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.341 -r1.342 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.341 src/sys/dev/pci/if_bge.c:1.342 --- src/sys/dev/pci/if_bge.c:1.341 Mon Nov 25 05:18:59 2019 +++ src/sys/dev/pci/if_bge.c Mon Nov 25 05:35:26 2019 @@ -1,4 +1,4 @@ -/* $NetBSD: if_bge.c,v 1.341 2019/11/25 05:18:59 msaitoh Exp $ */ +/* $NetBSD: if_bge.c,v 1.342 2019/11/25 05:35:26 msaitoh Exp $ */ /* * Copyright (c) 2001 Wind River Systems @@ -79,7 +79,7 @@ */ #include <sys/cdefs.h> -__KERNEL_RCSID(0, "$NetBSD: if_bge.c,v 1.341 2019/11/25 05:18:59 msaitoh Exp $"); +__KERNEL_RCSID(0, "$NetBSD: if_bge.c,v 1.342 2019/11/25 05:35:26 msaitoh Exp $"); #include <sys/param.h> #include <sys/systm.h> @@ -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 @@ -3176,14 +3188,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]; @@ -3427,15 +3439,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); - DELAY(80); - /* * When using the BCM5701 in PCI-X mode, data corruption has * been observed in the first few bytes of some received packets. @@ -3680,6 +3683,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. */ @@ -3866,8 +3884,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); @@ -3879,6 +3903,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 @@ -3886,18 +3912,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,