Index: sys/dev/alc/if_alcvar.h =================================================================== --- sys/dev/alc/if_alcvar.h (revision 210298) +++ sys/dev/alc/if_alcvar.h (working copy) @@ -211,6 +211,7 @@ struct alc_softc { uint32_t alc_dma_rd_burst; uint32_t alc_dma_wr_burst; uint32_t alc_rcb; + int alc_expcap; int alc_flags; #define ALC_FLAG_PCIE 0x0001 #define ALC_FLAG_PCIX 0x0002 Index: sys/dev/alc/if_alc.c =================================================================== --- sys/dev/alc/if_alc.c (revision 210298) +++ sys/dev/alc/if_alc.c (working copy) @@ -109,7 +109,7 @@ static struct alc_dev { "Atheros AR8132 PCIe Fast Ethernet" } }; -static void alc_aspm(struct alc_softc *); +static void alc_aspm(struct alc_softc *, int); static int alc_attach(device_t); static int alc_check_boundary(struct alc_softc *); static int alc_detach(device_t); @@ -331,7 +331,7 @@ alc_miibus_statchg(device_t dev) reg |= MAC_CFG_TX_ENB | MAC_CFG_RX_ENB; CSR_WRITE_4(sc, ALC_MAC_CFG, reg); } - alc_aspm(sc); + alc_aspm(sc, IFM_SUBTYPE(mii->mii_media_active)); } static void @@ -536,28 +536,53 @@ alc_phy_down(struct alc_softc *sc) } static void -alc_aspm(struct alc_softc *sc) +alc_aspm(struct alc_softc *sc, int media) { uint32_t pmcfg; + uint16_t linkcfg; + int val; ALC_LOCK_ASSERT(sc); pmcfg = CSR_READ_4(sc, ALC_PM_CFG); + linkcfg = CSR_READ_2(sc, sc->alc_expcap + PCIR_EXPRESS_LINK_CTL); pmcfg &= ~PM_CFG_SERDES_PD_EX_L1; - pmcfg |= PM_CFG_SERDES_BUDS_RX_L1_ENB; - pmcfg |= PM_CFG_SERDES_L1_ENB; - pmcfg &= ~PM_CFG_L1_ENTRY_TIMER_MASK; + pmcfg &= ~(PM_CFG_L1_ENTRY_TIMER_MASK | PM_CFG_LCKDET_TIMER_MASK); pmcfg |= PM_CFG_MAC_ASPM_CHK; + pmcfg |= PM_CFG_SERDES_ENB | PM_CFG_RBER_ENB; + pmcfg &= ~(PM_CFG_ASPM_L1_ENB | PM_CFG_ASPM_L0S_ENB); if ((sc->alc_flags & ALC_FLAG_LINK) != 0) { - pmcfg |= PM_CFG_SERDES_PLL_L1_ENB; - pmcfg &= ~PM_CFG_CLK_SWH_L1; - pmcfg &= ~PM_CFG_ASPM_L1_ENB; - pmcfg &= ~PM_CFG_ASPM_L0S_ENB; + if (linkcfg & 0x0001) + pmcfg |= PM_CFG_ASPM_L0S_ENB; + if (linkcfg & 0x0002) + pmcfg |= PM_CFG_ASPM_L1_ENB; + pmcfg |= PM_CFG_SERDES_L1_ENB | PM_CFG_SERDES_PLL_L1_ENB | + PM_CFG_SERDES_BUDS_RX_L1_ENB; + pmcfg &= ~(PM_CFG_CLK_SWH_L1 | PM_CFG_ASPM_L1_ENB | + PM_CFG_ASPM_L0S_ENB); + /* XXX Another magic from vendor. */ + alc_miibus_writereg(sc->alc_dev, sc->alc_phyaddr, + ALC_MII_DBG_ADDR, MII_ANA_CFG41); + switch (media) { + case IFM_10_T: + val = 0xB6DD; + break; + case IFM_100_TX: + val = 0xB2DD; + break; + case IFM_1000_T: + default: + val = 0x96DD; + } + alc_miibus_writereg(sc->alc_dev, sc->alc_phyaddr, + ALC_MII_DBG_DATA, val); } else { - pmcfg &= ~PM_CFG_SERDES_PLL_L1_ENB; + pmcfg &= ~PM_CFG_SERDES_BUDS_RX_L1_ENB; + pmcfg &= ~(PM_CFG_SERDES_L1_ENB | PM_CFG_SERDES_L1_ENB | + PM_CFG_SERDES_PLL_L1_ENB); pmcfg |= PM_CFG_CLK_SWH_L1; - pmcfg &= ~PM_CFG_ASPM_L1_ENB; - pmcfg &= ~PM_CFG_ASPM_L0S_ENB; + if (linkcfg & 0x0002) + pmcfg |= PM_CFG_ASPM_L1_ENB; } CSR_WRITE_4(sc, ALC_PM_CFG, pmcfg); } @@ -600,6 +625,7 @@ alc_attach(device_t dev) sc->alc_rcb = DMA_CFG_RCB_64; if (pci_find_extcap(dev, PCIY_EXPRESS, &base) == 0) { sc->alc_flags |= ALC_FLAG_PCIE; + sc->alc_expcap = base; burst = CSR_READ_2(sc, base + PCIR_EXPRESS_DEVICE_CTL); sc->alc_dma_rd_burst = (burst & PCIM_EXP_CTL_MAX_READ_REQUEST) >> 12;