diff options
author | Stuart Henderson <sthen@cvs.openbsd.org> | 2011-05-18 14:20:28 +0000 |
---|---|---|
committer | Stuart Henderson <sthen@cvs.openbsd.org> | 2011-05-18 14:20:28 +0000 |
commit | fc24ee0f2627294577142e36286b924e73705adb (patch) | |
tree | 7120e6f9adaf1978ada491b5573ab4929a763a61 | |
parent | be10ce4ae030011141af2f10f7d945efd1ddf7b6 (diff) |
Support additional L2C variants and L1D (AR813x/AR815x chips).
Tested on L1C by Abel Abraham Camarillo Ojeda, thank you.
From FreeBSD via kevlo@, ok jsg@
-rw-r--r-- | share/man/man4/alc.4 | 9 | ||||
-rw-r--r-- | sys/dev/pci/if_alc.c | 443 | ||||
-rw-r--r-- | sys/dev/pci/if_alcreg.h | 56 |
3 files changed, 396 insertions, 112 deletions
diff --git a/share/man/man4/alc.4 b/share/man/man4/alc.4 index b5d550ca6d1..d4d291f1420 100644 --- a/share/man/man4/alc.4 +++ b/share/man/man4/alc.4 @@ -1,4 +1,4 @@ -.\" $OpenBSD: alc.4,v 1.2 2009/08/08 14:12:41 jmc Exp $ +.\" $OpenBSD: alc.4,v 1.3 2011/05/18 14:20:27 sthen Exp $ .\" .\" Copyright (c) 2009 Kevin Lo <kevlo@openbsd.org> .\" @@ -14,12 +14,12 @@ .\" ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF .\" OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. .\" -.Dd $Mdocdate: August 8 2009 $ +.Dd $Mdocdate: May 18 2011 $ .Dt ALC 4 .Os .Sh NAME .Nm alc -.Nd Atheros AR8131/AR8132 10/100/Gigabit Ethernet device +.Nd Atheros AR813x/AR815x 10/100/Gigabit Ethernet device .Sh SYNOPSIS .Cd "alc* at pci?" .Cd "atphy* at mii?" @@ -27,8 +27,7 @@ The .Nm driver provides support for Ethernet interfaces based on the -Atheros AR8131/AR8132 Ethernet chipset, also known as -the Attansic L1C/L2C respectively. +Atheros AR813x/AR815x Ethernet chipset. .Pp The .Nm diff --git a/sys/dev/pci/if_alc.c b/sys/dev/pci/if_alc.c index 6b3576eb9d7..082cc794c8f 100644 --- a/sys/dev/pci/if_alc.c +++ b/sys/dev/pci/if_alc.c @@ -1,4 +1,4 @@ -/* $OpenBSD: if_alc.c,v 1.11 2011/04/05 18:01:21 henning Exp $ */ +/* $OpenBSD: if_alc.c,v 1.12 2011/05/18 14:20:27 sthen Exp $ */ /*- * Copyright (c) 2009, Pyun YongHyeon <yongari@FreeBSD.org> * All rights reserved. @@ -88,7 +88,7 @@ void alc_watchdog(struct ifnet *); int alc_mediachange(struct ifnet *); void alc_mediastatus(struct ifnet *, struct ifmediareq *); -void alc_aspm(struct alc_softc *); +void alc_aspm(struct alc_softc *, int); void alc_disable_l0s_l1(struct alc_softc *); int alc_dma_alloc(struct alc_softc *); void alc_dma_free(struct alc_softc *); @@ -109,7 +109,7 @@ void alc_phy_down(struct alc_softc *); void alc_phy_reset(struct alc_softc *); void alc_reset(struct alc_softc *); void alc_rxeof(struct alc_softc *, struct rx_rdesc *); -int alc_rxintr(struct alc_softc *); +void alc_rxintr(struct alc_softc *); void alc_iff(struct alc_softc *); void alc_rxvlan(struct alc_softc *); void alc_start_queue(struct alc_softc *); @@ -125,7 +125,11 @@ uint32_t alc_dma_burst[] = { 128, 256, 512, 1024, 2048, 4096, 0 }; const struct pci_matchid alc_devices[] = { { PCI_VENDOR_ATTANSIC, PCI_PRODUCT_ATTANSIC_L1C }, - { PCI_VENDOR_ATTANSIC, PCI_PRODUCT_ATTANSIC_L2C } + { PCI_VENDOR_ATTANSIC, PCI_PRODUCT_ATTANSIC_L2C }, + { PCI_VENDOR_ATTANSIC, PCI_PRODUCT_ATTANSIC_L1D }, + { PCI_VENDOR_ATTANSIC, PCI_PRODUCT_ATTANSIC_L1D_1 }, + { PCI_VENDOR_ATTANSIC, PCI_PRODUCT_ATTANSIC_L2C_1 }, + { PCI_VENDOR_ATTANSIC, PCI_PRODUCT_ATTANSIC_L2C_2 } }; struct cfattach alc_ca = { @@ -236,8 +240,8 @@ alc_miibus_statchg(struct device *dev) reg = CSR_READ_4(sc, ALC_MAC_CFG); reg |= MAC_CFG_TX_ENB | MAC_CFG_RX_ENB; CSR_WRITE_4(sc, ALC_MAC_CFG, reg); + alc_aspm(sc, IFM_SUBTYPE(mii->mii_media_active)); } - alc_aspm(sc); } void @@ -280,20 +284,53 @@ void alc_get_macaddr(struct alc_softc *sc) { uint32_t ea[2], opt; - int i; + uint16_t val; + int eeprom, i; + eeprom = 0; opt = CSR_READ_4(sc, ALC_OPT_CFG); - if ((CSR_READ_4(sc, ALC_TWSI_DEBUG) & TWSI_DEBUG_DEV_EXIST) != 0) { + if ((CSR_READ_4(sc, ALC_MASTER_CFG) & MASTER_OTP_SEL) != 0 && + (CSR_READ_4(sc, ALC_TWSI_DEBUG) & TWSI_DEBUG_DEV_EXIST) != 0) { /* * EEPROM found, let TWSI reload EEPROM configuration. * This will set ethernet address of controller. */ - if ((opt & OPT_CFG_CLK_ENB) == 0) { - opt |= OPT_CFG_CLK_ENB; - CSR_WRITE_4(sc, ALC_OPT_CFG, opt); - CSR_READ_4(sc, ALC_OPT_CFG); - DELAY(1000); + eeprom++; + switch (sc->sc_product) { + case PCI_PRODUCT_ATTANSIC_L1C: + case PCI_PRODUCT_ATTANSIC_L2C: + if ((opt & OPT_CFG_CLK_ENB) == 0) { + opt |= OPT_CFG_CLK_ENB; + CSR_WRITE_4(sc, ALC_OPT_CFG, opt); + CSR_READ_4(sc, ALC_OPT_CFG); + DELAY(1000); + } + break; + case PCI_PRODUCT_ATTANSIC_L1D: + case PCI_PRODUCT_ATTANSIC_L1D_1: + case PCI_PRODUCT_ATTANSIC_L2C_1: + case PCI_PRODUCT_ATTANSIC_L2C_2: + alc_miibus_writereg(&sc->sc_dev, sc->alc_phyaddr, + ALC_MII_DBG_ADDR, 0x00); + val = alc_miibus_readreg(&sc->sc_dev, sc->alc_phyaddr, + ALC_MII_DBG_DATA); + alc_miibus_writereg(&sc->sc_dev, sc->alc_phyaddr, + ALC_MII_DBG_DATA, val & 0xFF7F); + alc_miibus_writereg(&sc->sc_dev, sc->alc_phyaddr, + ALC_MII_DBG_ADDR, 0x3B); + val = alc_miibus_readreg(&sc->sc_dev, sc->alc_phyaddr, + ALC_MII_DBG_DATA); + alc_miibus_writereg(&sc->sc_dev, sc->alc_phyaddr, + ALC_MII_DBG_DATA, val | 0x0008); + DELAY(20); + break; } + + CSR_WRITE_4(sc, ALC_LTSSM_ID_CFG, + CSR_READ_4(sc, ALC_LTSSM_ID_CFG) & ~LTSSM_ID_WRO_ENB); + CSR_WRITE_4(sc, ALC_WOL_CFG, 0); + CSR_READ_4(sc, ALC_WOL_CFG); + CSR_WRITE_4(sc, ALC_TWSI_CFG, CSR_READ_4(sc, ALC_TWSI_CFG) | TWSI_CFG_SW_LD_START); for (i = 100; i > 0; i--) { @@ -309,11 +346,36 @@ alc_get_macaddr(struct alc_softc *sc) if (alcdebug) printf("%s: EEPROM not found!\n", sc->sc_dev.dv_xname); } - if ((opt & OPT_CFG_CLK_ENB) != 0) { - opt &= ~OPT_CFG_CLK_ENB; - CSR_WRITE_4(sc, ALC_OPT_CFG, opt); - CSR_READ_4(sc, ALC_OPT_CFG); - DELAY(1000); + if (eeprom != 0) { + switch (sc->sc_product) { + case PCI_PRODUCT_ATTANSIC_L1C: + case PCI_PRODUCT_ATTANSIC_L2C: + if ((opt & OPT_CFG_CLK_ENB) != 0) { + opt &= ~OPT_CFG_CLK_ENB; + CSR_WRITE_4(sc, ALC_OPT_CFG, opt); + CSR_READ_4(sc, ALC_OPT_CFG); + DELAY(1000); + } + break; + case PCI_PRODUCT_ATTANSIC_L1D: + case PCI_PRODUCT_ATTANSIC_L1D_1: + case PCI_PRODUCT_ATTANSIC_L2C_1: + case PCI_PRODUCT_ATTANSIC_L2C_2: + alc_miibus_writereg(&sc->sc_dev, sc->alc_phyaddr, + ALC_MII_DBG_ADDR, 0x00); + val = alc_miibus_readreg(&sc->sc_dev, sc->alc_phyaddr, + ALC_MII_DBG_DATA); + alc_miibus_writereg(&sc->sc_dev, sc->alc_phyaddr, + ALC_MII_DBG_DATA, val | 0x0080); + alc_miibus_writereg(&sc->sc_dev, sc->alc_phyaddr, + ALC_MII_DBG_ADDR, 0x3B); + val = alc_miibus_readreg(&sc->sc_dev, sc->alc_phyaddr, + ALC_MII_DBG_DATA); + alc_miibus_writereg(&sc->sc_dev, sc->alc_phyaddr, + ALC_MII_DBG_DATA, val & 0xFFF7); + DELAY(20); + break; + } } ea[0] = CSR_READ_4(sc, ALC_PAR0); @@ -358,6 +420,43 @@ alc_phy_reset(struct alc_softc *sc) CSR_READ_2(sc, ALC_GPHY_CFG); DELAY(10 * 1000); + /* DSP fixup, Vendor magic. */ + if (sc->sc_product == PCI_PRODUCT_ATTANSIC_L2C_1) { + alc_miibus_writereg(&sc->sc_dev, sc->alc_phyaddr, + ALC_MII_DBG_ADDR, 0x000A); + data = alc_miibus_readreg(&sc->sc_dev, sc->alc_phyaddr, + ALC_MII_DBG_DATA); + alc_miibus_writereg(&sc->sc_dev, sc->alc_phyaddr, + ALC_MII_DBG_DATA, data & 0xDFFF); + } + if (sc->sc_product == PCI_PRODUCT_ATTANSIC_L1D || + sc->sc_product == PCI_PRODUCT_ATTANSIC_L1D_1 || + sc->sc_product == PCI_PRODUCT_ATTANSIC_L2C_1 || + sc->sc_product == PCI_PRODUCT_ATTANSIC_L2C_2) { + alc_miibus_writereg(&sc->sc_dev, sc->alc_phyaddr, + ALC_MII_DBG_ADDR, 0x003B); + data = alc_miibus_readreg(&sc->sc_dev, sc->alc_phyaddr, + ALC_MII_DBG_DATA); + alc_miibus_writereg(&sc->sc_dev, sc->alc_phyaddr, + ALC_MII_DBG_DATA, data & 0xFFF7); + DELAY(20 * 1000); + } + if (sc->sc_product == PCI_PRODUCT_ATTANSIC_L1D) { + alc_miibus_writereg(&sc->sc_dev, sc->alc_phyaddr, + ALC_MII_DBG_ADDR, 0x0029); + alc_miibus_writereg(&sc->sc_dev, sc->alc_phyaddr, + ALC_MII_DBG_DATA, 0x929D); + } + if (sc->sc_product == PCI_PRODUCT_ATTANSIC_L1C || + sc->sc_product == PCI_PRODUCT_ATTANSIC_L2C || + sc->sc_product == PCI_PRODUCT_ATTANSIC_L1D_1 || + sc->sc_product == PCI_PRODUCT_ATTANSIC_L2C_2) { + alc_miibus_writereg(&sc->sc_dev, sc->alc_phyaddr, + ALC_MII_DBG_ADDR, 0x0029); + alc_miibus_writereg(&sc->sc_dev, sc->alc_phyaddr, + ALC_MII_DBG_DATA, 0xB6DD); + } + /* Load DSP codes, vendor magic. */ data = ANA_LOOP_SEL_10BT | ANA_EN_MASK_TB | ANA_EN_10BT_IDLE | ((1 << ANA_INTERVAL_SEL_TIMER_SHIFT) & ANA_INTERVAL_SEL_TIMER_MASK); @@ -406,35 +505,114 @@ alc_phy_reset(struct alc_softc *sc) void alc_phy_down(struct alc_softc *sc) { - - /* Force PHY down. */ - CSR_WRITE_2(sc, ALC_GPHY_CFG, - GPHY_CFG_EXT_RESET | GPHY_CFG_HIB_EN | GPHY_CFG_HIB_PULSE | - GPHY_CFG_SEL_ANA_RESET | GPHY_CFG_PHY_IDDQ | GPHY_CFG_PWDOWN_HW); - DELAY(1000); + switch (sc->sc_product) { + case PCI_PRODUCT_ATTANSIC_L1D: + case PCI_PRODUCT_ATTANSIC_L1D_1: + /* + * GPHY power down caused more problems on AR8151 v2.0. + * When driver is reloaded after GPHY power down, + * accesses to PHY/MAC registers hung the system. Only + * cold boot recovered from it. I'm not sure whether + * AR8151 v1.0 also requires this one though. I don't + * have AR8151 v1.0 controller in hand. + * The only option left is to isolate the PHY and + * initiates power down the PHY which in turn saves + * more power when driver is unloaded. + */ + alc_miibus_writereg(&sc->sc_dev, sc->alc_phyaddr, + MII_BMCR, BMCR_ISO | BMCR_PDOWN); + break; + default: + /* Force PHY down. */ + CSR_WRITE_2(sc, ALC_GPHY_CFG, + GPHY_CFG_EXT_RESET | GPHY_CFG_HIB_EN | GPHY_CFG_HIB_PULSE | + GPHY_CFG_SEL_ANA_RESET | GPHY_CFG_PHY_IDDQ | + GPHY_CFG_PWDOWN_HW); + DELAY(1000); + break; + } } void -alc_aspm(struct alc_softc *sc) +alc_aspm(struct alc_softc *sc, int media) { uint32_t pmcfg; + uint16_t linkcfg; pmcfg = CSR_READ_4(sc, ALC_PM_CFG); + if ((sc->alc_flags & (ALC_FLAG_APS | ALC_FLAG_PCIE)) == + (ALC_FLAG_APS | ALC_FLAG_PCIE)) + linkcfg = CSR_READ_2(sc, sc->alc_expcap + + PCI_PCIE_LCSR); + else + linkcfg = 0; 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_LCKDET_TIMER_DEFAULT << PM_CFG_LCKDET_TIMER_SHIFT); + pmcfg &= ~(PM_CFG_ASPM_L1_ENB | PM_CFG_ASPM_L0S_ENB); + + if ((sc->alc_flags & ALC_FLAG_APS) != 0) { + /* Disable extended sync except AR8152 B v1.0 */ + linkcfg &= ~0x80; + if (sc->sc_product == PCI_PRODUCT_ATTANSIC_L2C_1 && + sc->alc_rev == ATHEROS_AR8152_B_V10) + linkcfg |= 0x80; + CSR_WRITE_2(sc, sc->alc_expcap + PCI_PCIE_LCSR, + linkcfg); + pmcfg &= ~(PM_CFG_EN_BUFS_RX_L0S | PM_CFG_SA_DLY_ENB | + PM_CFG_HOTRST); + pmcfg |= (PM_CFG_L1_ENTRY_TIMER_DEFAULT << + PM_CFG_L1_ENTRY_TIMER_SHIFT); + pmcfg &= ~PM_CFG_PM_REQ_TIMER_MASK; + pmcfg |= (PM_CFG_PM_REQ_TIMER_DEFAULT << + PM_CFG_PM_REQ_TIMER_SHIFT); + pmcfg |= PM_CFG_SERDES_PD_EX_L1 | PM_CFG_PCIE_RECV; + } + 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 ((sc->alc_flags & ALC_FLAG_L0S) != 0) + pmcfg |= PM_CFG_ASPM_L0S_ENB; + if ((sc->alc_flags & ALC_FLAG_L1S) != 0) + pmcfg |= PM_CFG_ASPM_L1_ENB; + if ((sc->alc_flags & ALC_FLAG_APS) != 0) { + if (sc->sc_product == PCI_PRODUCT_ATTANSIC_L2C_1) + pmcfg &= ~PM_CFG_ASPM_L0S_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; + if (media == IFM_100_TX || media == IFM_1000_T) { + pmcfg &= ~PM_CFG_L1_ENTRY_TIMER_MASK; + switch (sc->sc_product) { + case PCI_PRODUCT_ATTANSIC_L2C_1: + pmcfg |= (7 << + PM_CFG_L1_ENTRY_TIMER_SHIFT); + break; + case PCI_PRODUCT_ATTANSIC_L1D_1: + case PCI_PRODUCT_ATTANSIC_L2C_2: + pmcfg |= (4 << + PM_CFG_L1_ENTRY_TIMER_SHIFT); + break; + default: + pmcfg |= (15 << + PM_CFG_L1_ENTRY_TIMER_SHIFT); + break; + } + } + } else { + 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); + } } else { - pmcfg &= ~PM_CFG_SERDES_PLL_L1_ENB; + pmcfg &= ~(PM_CFG_SERDES_BUDS_RX_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 ((sc->alc_flags & ALC_FLAG_L1S) != 0) + pmcfg |= PM_CFG_ASPM_L1_ENB; } CSR_WRITE_4(sc, ALC_PM_CFG, pmcfg); } @@ -450,9 +628,9 @@ alc_attach(struct device *parent, struct device *self, void *aux) const char *intrstr; struct ifnet *ifp; pcireg_t memtype; - char *aspm_state[] = { "L0s/L1", "L0s", "L1", "L0s/l1" }; + char *aspm_state[] = { "L0s/L1", "L0s", "L1", "L0s/L1" }; uint16_t burst; - int base, mii_flags, state, error = 0; + int base, state, error = 0; uint32_t cap, ctl, val; /* @@ -499,6 +677,7 @@ alc_attach(struct device *parent, struct device *self, void *aux) if (pci_get_capability(pc, pa->pa_tag, PCI_CAP_PCIEXPRESS, &base, NULL)) { sc->alc_flags |= ALC_FLAG_PCIE; + sc->alc_expcap = base; burst = pci_conf_read(sc->sc_pct, sc->sc_pcitag, base + PCI_PCIE_DCSR) >> 16; sc->alc_dma_rd_burst = (burst & 0x7000) >> 12; @@ -515,6 +694,20 @@ alc_attach(struct device *parent, struct device *self, void *aux) val = CSR_READ_4(sc, ALC_PEX_UNC_ERR_SEV); val &= ~(PEX_UNC_ERR_SEV_DLP | PEX_UNC_ERR_SEV_FCP); CSR_WRITE_4(sc, ALC_PEX_UNC_ERR_SEV, val); + CSR_WRITE_4(sc, ALC_LTSSM_ID_CFG, + CSR_READ_4(sc, ALC_LTSSM_ID_CFG) & ~LTSSM_ID_WRO_ENB); + CSR_WRITE_4(sc, ALC_PCIE_PHYMISC, + CSR_READ_4(sc, ALC_PCIE_PHYMISC) | + PCIE_PHYMISC_FORCE_RCV_DET); + if (sc->sc_product == PCI_PRODUCT_ATTANSIC_L2C_1 && + sc->alc_rev == ATHEROS_AR8152_B_V10) { + val = CSR_READ_4(sc, ALC_PCIE_PHYMISC2); + val &= ~(PCIE_PHYMISC2_SERDES_CDR_MASK | + PCIE_PHYMISC2_SERDES_TH_MASK); + val |= 3 << PCIE_PHYMISC2_SERDES_CDR_SHIFT; + val |= 3 << PCIE_PHYMISC2_SERDES_TH_SHIFT; + CSR_WRITE_4(sc, ALC_PCIE_PHYMISC2, val); + } /* Disable ASPM L0S and L1. */ cap = pci_conf_read(sc->sc_pct, sc->sc_pcitag, base + PCI_PCIE_LCAP) >> 16; @@ -528,13 +721,16 @@ alc_attach(struct device *parent, struct device *self, void *aux) sc->sc_dev.dv_xname, sc->alc_rcb == DMA_CFG_RCB_64 ? 64 : 128); state = ctl & 0x03; + if (state & 0x01) + sc->alc_flags |= ALC_FLAG_L0S; + if (state & 0x02) + sc->alc_flags |= ALC_FLAG_L1S; if (alcdebug) printf("%s: ASPM %s %s\n", sc->sc_dev.dv_xname, aspm_state[state], state == 0 ? "disabled" : "enabled"); - if (state != 0) - alc_disable_l0s_l1(sc); + alc_disable_l0s_l1(sc); } } @@ -551,12 +747,39 @@ alc_attach(struct device *parent, struct device *self, void *aux) * used in AR8132 can't establish gigabit link even if it * shows the same PHY model/revision number of AR8131. */ - if (PCI_PRODUCT(pa->pa_id) == PCI_PRODUCT_ATTANSIC_L2C) - sc->alc_flags |= ALC_FLAG_FASTETHER | ALC_FLAG_JUMBO; - else - sc->alc_flags |= ALC_FLAG_JUMBO | ALC_FLAG_ASPM_MON; + sc->sc_product = PCI_PRODUCT(pa->pa_id); + switch (sc->sc_product) { + case PCI_PRODUCT_ATTANSIC_L2C_1: + case PCI_PRODUCT_ATTANSIC_L2C_2: + sc->alc_flags |= ALC_FLAG_APS; + /* FALLTHROUGH */ + case PCI_PRODUCT_ATTANSIC_L2C: + sc->alc_flags |= ALC_FLAG_FASTETHER; + break; + case PCI_PRODUCT_ATTANSIC_L1D: + case PCI_PRODUCT_ATTANSIC_L1D_1: + sc->alc_flags |= ALC_FLAG_APS; + /* FALLTHROUGH */ + default: + break; + } + sc->alc_flags |= ALC_FLAG_ASPM_MON | ALC_FLAG_JUMBO; + + switch (sc->sc_product) { + case PCI_PRODUCT_ATTANSIC_L1C: + case PCI_PRODUCT_ATTANSIC_L2C: + sc->alc_max_framelen = 9 * 1024; + break; + case PCI_PRODUCT_ATTANSIC_L1D: + case PCI_PRODUCT_ATTANSIC_L1D_1: + case PCI_PRODUCT_ATTANSIC_L2C_1: + case PCI_PRODUCT_ATTANSIC_L2C_2: + sc->alc_max_framelen = 6 * 1024; + break; + } + /* - * It seems that AR8131/AR8132 has silicon bug for SMB. In + * It seems that AR813x/AR815x has silicon bug for SMB. In * addition, Atheros said that enabling SMB wouldn't improve * performance. However I think it's bad to access lots of * registers to extract MAC statistics. @@ -619,11 +842,8 @@ alc_attach(struct device *parent, struct device *self, void *aux) ifmedia_init(&sc->sc_miibus.mii_media, 0, alc_mediachange, alc_mediastatus); - mii_flags = 0; - if ((sc->alc_flags & ALC_FLAG_JUMBO) != 0) - mii_flags |= MIIF_DOPAUSE; mii_attach(self, &sc->sc_miibus, 0xffffffff, MII_PHY_ANY, - MII_OFFSET_ANY, mii_flags); + MII_OFFSET_ANY, MIIF_DOPAUSE); if (LIST_FIRST(&sc->sc_miibus.mii_phys) == NULL) { printf("%s: no PHY found!\n", sc->sc_dev.dv_xname); @@ -1136,16 +1356,15 @@ alc_start(struct ifnet *ifp) { struct alc_softc *sc = ifp->if_softc; struct mbuf *m_head; - int enq; - - if ((ifp->if_flags & (IFF_RUNNING | IFF_OACTIVE)) != IFF_RUNNING) - return; + int enq = 0; /* Reclaim transmitted frames. */ if (sc->alc_cdata.alc_tx_cnt >= ALC_TX_DESC_HIWAT) alc_txeof(sc); - enq = 0; + if ((ifp->if_flags & (IFF_RUNNING | IFF_OACTIVE)) != IFF_RUNNING) + return; + for (;;) { IFQ_DEQUEUE(&ifp->if_snd, m_head); if (m_head == NULL) @@ -1162,7 +1381,7 @@ alc_start(struct ifnet *ifp) ifp->if_flags |= IFF_OACTIVE; break; } - enq = 1; + enq++; #if NBPFILTER > 0 /* @@ -1174,7 +1393,7 @@ alc_start(struct ifnet *ifp) #endif } - if (enq) { + if (enq > 0) { /* Sync descriptors. */ bus_dmamap_sync(sc->sc_dmat, sc->alc_cdata.alc_tx_ring_map, 0, sc->alc_cdata.alc_tx_ring_map->dm_mapsize, @@ -1274,6 +1493,10 @@ alc_mac_config(struct alc_softc *sc) reg = CSR_READ_4(sc, ALC_MAC_CFG); reg &= ~(MAC_CFG_FULL_DUPLEX | MAC_CFG_TX_FC | MAC_CFG_RX_FC | MAC_CFG_SPEED_MASK); + if (sc->sc_product == PCI_PRODUCT_ATTANSIC_L1D || + sc->sc_product == PCI_PRODUCT_ATTANSIC_L1D_1 || + sc->sc_product == PCI_PRODUCT_ATTANSIC_L2C_2) + reg |= MAC_CFG_HASH_ALG_CRC32 | MAC_CFG_SPEED_MODE_SW; /* Reprogram MAC with resolved speed/duplex. */ switch (IFM_SUBTYPE(mii->mii_media_active)) { case IFM_10_T: @@ -1451,24 +1674,25 @@ alc_intr(void *arg) struct alc_softc *sc = arg; struct ifnet *ifp = &sc->sc_arpcom.ac_if; uint32_t status; + int claimed = 0; status = CSR_READ_4(sc, ALC_INTR_STATUS); if ((status & ALC_INTRS) == 0) return (0); + /* Disable interrupts. */ + CSR_WRITE_4(sc, ALC_INTR_STATUS, INTR_DIS_INT); + + status = CSR_READ_4(sc, ALC_INTR_STATUS); + if ((status & ALC_INTRS) == 0) + goto back; + /* Acknowledge and disable interrupts. */ CSR_WRITE_4(sc, ALC_INTR_STATUS, status | INTR_DIS_INT); if (ifp->if_flags & IFF_RUNNING) { - if (status & INTR_RX_PKT) { - int error; - - error = alc_rxintr(sc); - if (error) { - alc_init(ifp); - return (0); - } - } + if (status & INTR_RX_PKT) + alc_rxintr(sc); if (status & (INTR_DMA_RD_TO_RST | INTR_DMA_WR_TO_RST | INTR_TXQ_TO_RST)) { @@ -1485,14 +1709,17 @@ alc_intr(void *arg) return (0); } - alc_txeof(sc); - if (!IFQ_IS_EMPTY(&ifp->if_snd)) + if (status & INTR_TX_PKT) { + alc_txeof(sc); + if (!IFQ_IS_EMPTY(&ifp->if_snd)) alc_start(ifp); + } } - + claimed = 1; +back: /* Re-enable interrupts. */ CSR_WRITE_4(sc, ALC_INTR_STATUS, 0x7FFFFFFF); - return (1); + return (claimed); } void @@ -1507,7 +1734,7 @@ alc_txeof(struct alc_softc *sc) return; bus_dmamap_sync(sc->sc_dmat, sc->alc_cdata.alc_tx_ring_map, 0, sc->alc_cdata.alc_tx_ring_map->dm_mapsize, - BUS_DMASYNC_POSTREAD); + BUS_DMASYNC_POSTWRITE); if ((sc->alc_flags & ALC_FLAG_CMB_BUG) == 0) { bus_dmamap_sync(sc->sc_dmat, sc->alc_cdata.alc_cmb_map, 0, sc->alc_cdata.alc_cmb_map->dm_mapsize, @@ -1591,7 +1818,7 @@ alc_newbuf(struct alc_softc *sc, struct alc_rxdesc *rxd) return (0); } -int +void alc_rxintr(struct alc_softc *sc) { struct ifnet *ifp = &sc->sc_arpcom.ac_if; @@ -1615,7 +1842,7 @@ alc_rxintr(struct alc_softc *sc) if (alcdebug) printf("%s: unexpected segment count -- " "resetting\n", sc->sc_dev.dv_xname); - return (EIO); + break; } alc_rxeof(sc, rrd); /* Clear Rx return status. */ @@ -1653,8 +1880,6 @@ alc_rxintr(struct alc_softc *sc) CSR_WRITE_4(sc, ALC_MBOX_RD0_PROD_IDX, sc->alc_cdata.alc_rx_cons); } - - return (0); } /* Receive a frame. */ @@ -1686,9 +1911,8 @@ alc_rxeof(struct alc_softc *sc, struct rx_rdesc *rrd) * Force network stack compute checksum for * errored frames. */ - status |= RRD_TCP_UDPCSUM_NOK | RRD_IPCSUM_NOK; - if ((RRD_ERR_CRC | RRD_ERR_ALIGN | RRD_ERR_TRUNC | - RRD_ERR_RUNT) != 0) + if ((status & (RRD_ERR_CRC | RRD_ERR_ALIGN | + RRD_ERR_TRUNC | RRD_ERR_RUNT)) != 0) return; } @@ -1801,7 +2025,9 @@ alc_reset(struct alc_softc *sc) uint32_t reg; int i; - CSR_WRITE_4(sc, ALC_MASTER_CFG, MASTER_RESET); + reg = CSR_READ_4(sc, ALC_MASTER_CFG) & 0xFFFF; + reg |= MASTER_OOB_DIS_OFF | MASTER_RESET; + CSR_WRITE_4(sc, ALC_MASTER_CFG, reg); for (i = ALC_RESET_TIMEOUT; i > 0; i--) { DELAY(10); if ((CSR_READ_4(sc, ALC_MASTER_CFG) & MASTER_RESET) == 0) @@ -1852,6 +2078,9 @@ alc_init(struct ifnet *ifp) alc_init_cmb(sc); alc_init_smb(sc); + /* Enable all clocks. */ + CSR_WRITE_4(sc, ALC_CLK_GATING_CFG, 0); + /* Reprogram the station address. */ bcopy(LLADDR(ifp->if_sadl), eaddr, ETHER_ADDR_LEN); CSR_WRITE_4(sc, ALC_PAR0, @@ -1913,6 +2142,18 @@ alc_init(struct ifnet *ifp) CSR_WRITE_4(sc, ALC_SMB_BASE_ADDR_HI, ALC_ADDR_HI(paddr)); CSR_WRITE_4(sc, ALC_SMB_BASE_ADDR_LO, ALC_ADDR_LO(paddr)); + if (sc->sc_product == PCI_PRODUCT_ATTANSIC_L2C_1) { + /* Reconfigure SRAM - Vendor magic. */ + CSR_WRITE_4(sc, ALC_SRAM_RX_FIFO_LEN, 0x000002A0); + CSR_WRITE_4(sc, ALC_SRAM_TX_FIFO_LEN, 0x00000100); + CSR_WRITE_4(sc, ALC_SRAM_RX_FIFO_ADDR, 0x029F0000); + CSR_WRITE_4(sc, ALC_SRAM_RD0_ADDR, 0x02BF02A0); + CSR_WRITE_4(sc, ALC_SRAM_TX_FIFO_ADDR, 0x03BF02C0); + CSR_WRITE_4(sc, ALC_SRAM_TD_ADDR, 0x03DF03C0); + CSR_WRITE_4(sc, ALC_TXF_WATER_MARK, 0x00000000); + CSR_WRITE_4(sc, ALC_RD_DMA_CFG, 0x00000000); + } + /* Tell hardware that we're ready to load DMA blocks. */ CSR_WRITE_4(sc, ALC_DMA_BLOCK, DMA_BLOCK_LOAD); @@ -1922,14 +2163,11 @@ alc_init(struct ifnet *ifp) reg = ALC_USECS(sc->alc_int_rx_mod) << IM_TIMER_RX_SHIFT; reg |= ALC_USECS(sc->alc_int_tx_mod) << IM_TIMER_TX_SHIFT; CSR_WRITE_4(sc, ALC_IM_TIMER, reg); - reg = CSR_READ_4(sc, ALC_MASTER_CFG); - reg &= ~(MASTER_CHIP_REV_MASK | MASTER_CHIP_ID_MASK); /* * We don't want to automatic interrupt clear as task queue * for the interrupt should know interrupt status. */ - reg &= ~MASTER_INTR_RD_CLR; - reg &= ~(MASTER_IM_RX_TIMER_ENB | MASTER_IM_TX_TIMER_ENB); + reg = MASTER_SA_TIMER_ENB; if (ALC_USECS(sc->alc_int_rx_mod) != 0) reg |= MASTER_IM_RX_TIMER_ENB; if (ALC_USECS(sc->alc_int_tx_mod) != 0) @@ -1970,7 +2208,7 @@ alc_init(struct ifnet *ifp) * Be conservative in what you do, be liberal in what you * accept from others - RFC 793. */ - CSR_WRITE_4(sc, ALC_FRAME_SIZE, ALC_JUMBO_FRAMELEN); + CSR_WRITE_4(sc, ALC_FRAME_SIZE, sc->alc_max_framelen); /* Disable header split(?) */ CSR_WRITE_4(sc, ALC_HDS_CFG, 0); @@ -1997,11 +2235,14 @@ alc_init(struct ifnet *ifp) * TSO/checksum offloading. */ CSR_WRITE_4(sc, ALC_TSO_OFFLOAD_THRESH, - (ALC_JUMBO_FRAMELEN >> TSO_OFFLOAD_THRESH_UNIT_SHIFT) & + (sc->alc_max_framelen >> TSO_OFFLOAD_THRESH_UNIT_SHIFT) & TSO_OFFLOAD_THRESH_MASK); /* Configure TxQ. */ reg = (alc_dma_burst[sc->alc_dma_rd_burst] << TXQ_CFG_TX_FIFO_BURST_SHIFT) & TXQ_CFG_TX_FIFO_BURST_MASK; + if (sc->sc_product == PCI_PRODUCT_ATTANSIC_L2C_1 || + sc->sc_product == PCI_PRODUCT_ATTANSIC_L2C_2) + reg >>= 1; reg |= (TXQ_CFG_TD_BURST_DEFAULT << TXQ_CFG_TD_BURST_SHIFT) & TXQ_CFG_TD_BURST_MASK; CSR_WRITE_4(sc, ALC_TXQ_CFG, reg | TXQ_CFG_ENHANCED_MODE); @@ -2018,14 +2259,22 @@ alc_init(struct ifnet *ifp) * XON : 80% of Rx FIFO * XOFF : 30% of Rx FIFO */ - reg = CSR_READ_4(sc, ALC_SRAM_RX_FIFO_LEN); - rxf_hi = (reg * 8) / 10; - rxf_lo = (reg * 3)/ 10; - CSR_WRITE_4(sc, ALC_RX_FIFO_PAUSE_THRESH, - ((rxf_lo << RX_FIFO_PAUSE_THRESH_LO_SHIFT) & - RX_FIFO_PAUSE_THRESH_LO_MASK) | - ((rxf_hi << RX_FIFO_PAUSE_THRESH_HI_SHIFT) & - RX_FIFO_PAUSE_THRESH_HI_MASK)); + if (sc->sc_product == PCI_PRODUCT_ATTANSIC_L1C || + sc->sc_product == PCI_PRODUCT_ATTANSIC_L2C) { + reg = CSR_READ_4(sc, ALC_SRAM_RX_FIFO_LEN); + rxf_hi = (reg * 8) / 10; + rxf_lo = (reg * 3) / 10; + CSR_WRITE_4(sc, ALC_RX_FIFO_PAUSE_THRESH, + ((rxf_lo << RX_FIFO_PAUSE_THRESH_LO_SHIFT) & + RX_FIFO_PAUSE_THRESH_LO_MASK) | + ((rxf_hi << RX_FIFO_PAUSE_THRESH_HI_SHIFT) & + RX_FIFO_PAUSE_THRESH_HI_MASK)); + } + if (sc->sc_product == PCI_PRODUCT_ATTANSIC_L1D_1 || + sc->sc_product == PCI_PRODUCT_ATTANSIC_L2C_1) + CSR_WRITE_4(sc, ALC_SERDES_LOCK, + CSR_READ_4(sc, ALC_SERDES_LOCK) | SERDES_MAC_CLK_SLOWDOWN | + SERDES_PHY_CLK_SLOWDOWN); /* Disable RSS until I understand L1C/L2C's RSS logic. */ CSR_WRITE_4(sc, ALC_RSS_IDT_TABLE0, 0); @@ -2036,15 +2285,9 @@ alc_init(struct ifnet *ifp) RXQ_CFG_RD_BURST_MASK; reg |= RXQ_CFG_RSS_MODE_DIS; if ((sc->alc_flags & ALC_FLAG_ASPM_MON) != 0) - reg |= RXQ_CFG_ASPM_THROUGHPUT_LIMIT_100M; + reg |= RXQ_CFG_ASPM_THROUGHPUT_LIMIT_1M; CSR_WRITE_4(sc, ALC_RXQ_CFG, reg); - /* Configure Rx DMAW request thresold. */ - CSR_WRITE_4(sc, ALC_RD_DMA_CFG, - ((RD_DMA_CFG_THRESH_DEFAULT << RD_DMA_CFG_THRESH_SHIFT) & - RD_DMA_CFG_THRESH_MASK) | - ((ALC_RD_DMA_CFG_USECS(0) << RD_DMA_CFG_TIMER_SHIFT) & - RD_DMA_CFG_TIMER_MASK)); /* Configure DMA parameters. */ reg = DMA_CFG_OUT_ORDER | DMA_CFG_RD_REQ_PRI; reg |= sc->alc_rcb; @@ -2070,7 +2313,7 @@ alc_init(struct ifnet *ifp) * - Enable CRC generation. * Actual reconfiguration of MAC for resolved speed/duplex * is followed after detection of link establishment. - * AR8131/AR8132 always does checksum computation regardless + * AR813x/AR815x always does checksum computation regardless * of MAC_CFG_RXCSUM_ENB bit. Also the controller is known to * have bug in protocol field in Rx return structure so * these controllers can't handle fragmented frames. Disable @@ -2080,6 +2323,10 @@ alc_init(struct ifnet *ifp) reg = MAC_CFG_TX_CRC_ENB | MAC_CFG_TX_AUTO_PAD | MAC_CFG_FULL_DUPLEX | ((MAC_CFG_PREAMBLE_DEFAULT << MAC_CFG_PREAMBLE_SHIFT) & MAC_CFG_PREAMBLE_MASK); + if (sc->sc_product == PCI_PRODUCT_ATTANSIC_L1D || + sc->sc_product == PCI_PRODUCT_ATTANSIC_L1D_1 || + sc->sc_product == PCI_PRODUCT_ATTANSIC_L2C_2) + reg |= MAC_CFG_HASH_ALG_CRC32 | MAC_CFG_SPEED_MODE_SW; if ((sc->alc_flags & ALC_FLAG_FASTETHER) != 0) reg |= MAC_CFG_SPEED_10_100; else diff --git a/sys/dev/pci/if_alcreg.h b/sys/dev/pci/if_alcreg.h index 3857f240816..67f1d21a374 100644 --- a/sys/dev/pci/if_alcreg.h +++ b/sys/dev/pci/if_alcreg.h @@ -1,4 +1,4 @@ -/* $OpenBSD: if_alcreg.h,v 1.1 2009/08/08 09:31:13 kevlo Exp $ */ +/* $OpenBSD: if_alcreg.h,v 1.2 2011/05/18 14:20:27 sthen Exp $ */ /*- * Copyright (c) 2009, Pyun YongHyeon <yongari@FreeBSD.org> * All rights reserved. @@ -31,7 +31,10 @@ #ifndef _IF_ALCREG_H #define _IF_ALCREG_H -#define ALC_PCIR_BAR 0x10 +#define ALC_PCIR_BAR 0x10 + +#define ATHEROS_AR8152_B_V10 0xC0 +#define ATHEROS_AR8152_B_V11 0xC1 /* 0x0000 - 0x02FF : PCIe configuration space */ @@ -56,6 +59,12 @@ #define ALC_PCIE_PHYMISC 0x1000 #define PCIE_PHYMISC_FORCE_RCV_DET 0x00000004 +#define ALC_PCIE_PHYMISC2 0x1004 +#define PCIE_PHYMISC2_SERDES_CDR_MASK 0x00030000 +#define PCIE_PHYMISC2_SERDES_TH_MASK 0x000C0000 +#define PCIE_PHYMISC2_SERDES_CDR_SHIFT 16 +#define PCIE_PHYMISC2_SERDES_TH_SHIFT 18 + #define ALC_TWSI_DEBUG 0x1108 #define TWSI_DEBUG_DEV_EXIST 0x20000000 @@ -88,7 +97,9 @@ #define PM_CFG_PCIE_RECV 0x00008000 #define PM_CFG_L1_ENTRY_TIMER_MASK 0x000F0000 #define PM_CFG_PM_REQ_TIMER_MASK 0x00F00000 -#define PM_CFG_LCKDET_TIMER_MASK 0x3F000000 +#define PM_CFG_LCKDET_TIMER_MASK 0x0F000000 +#define PM_CFG_EN_BUFS_RX_L0S 0x10000000 +#define PM_CFG_SA_DLY_ENB 0x20000000 #define PM_CFG_MAC_ASPM_CHK 0x40000000 #define PM_CFG_HOTRST 0x80000000 #define PM_CFG_L0S_ENTRY_TIMER_SHIFT 8 @@ -96,10 +107,20 @@ #define PM_CFG_PM_REQ_TIMER_SHIFT 20 #define PM_CFG_LCKDET_TIMER_SHIFT 24 +#define PM_CFG_L0S_ENTRY_TIMER_DEFAULT 6 +#define PM_CFG_L1_ENTRY_TIMER_DEFAULT 1 +#define PM_CFG_LCKDET_TIMER_DEFAULT 12 +#define PM_CFG_PM_REQ_TIMER_DEFAULT 12 + +#define ALC_LTSSM_ID_CFG 0x12FC +#define LTSSM_ID_WRO_ENB 0x00001000 + #define ALC_MASTER_CFG 0x1400 #define MASTER_RESET 0x00000001 +#define MASTER_TEST_MODE_MASK 0x0000000C #define MASTER_BERT_START 0x00000010 -#define MASTER_TEST_MODE_MASK 0x000000C0 +#define MASTER_OOB_DIS_OFF 0x00000040 +#define MASTER_SA_TIMER_ENB 0x00000080 #define MASTER_MTIMER_ENB 0x00000100 #define MASTER_MANUAL_INTR_ENB 0x00000200 #define MASTER_IM_TX_TIMER_ENB 0x00000400 @@ -114,7 +135,7 @@ #define MASTER_CHIP_REV_SHIFT 16 #define MASTER_CHIP_ID_SHIFT 24 -/* Number of ticks per usec for AR8131/AR8132. */ +/* Number of ticks per usec for AR813x/AR815x. */ #define ALC_TICK_USECS 2 #define ALC_USECS(x) ((x) / ALC_TICK_USECS) @@ -136,7 +157,7 @@ * alc(4) does not rely on Tx completion interrupts, so set it * somewhat large value to reduce Tx completion interrupts. */ -#define ALC_IM_TX_TIMER_DEFAULT 50000 /* 50ms */ +#define ALC_IM_TX_TIMER_DEFAULT 1000 /* 1ms */ #define ALC_GPHY_CFG 0x140C /* 16bits */ #define GPHY_CFG_EXT_RESET 0x0001 @@ -212,6 +233,8 @@ #define ALC_SERDES_LOCK 0x1424 #define SERDES_LOCK_DET 0x00000001 #define SERDES_LOCK_DET_ENB 0x00000002 +#define SERDES_MAC_CLK_SLOWDOWN 0x00020000 +#define SERDES_PHY_CLK_SLOWDOWN 0x00040000 #define ALC_MAC_CFG 0x1480 #define MAC_CFG_TX_ENB 0x00000001 @@ -241,6 +264,8 @@ #define MAC_CFG_BCAST 0x04000000 #define MAC_CFG_DBG 0x08000000 #define MAC_CFG_SINGLE_PAUSE_ENB 0x10000000 +#define MAC_CFG_HASH_ALG_CRC32 0x20000000 +#define MAC_CFG_SPEED_MODE_SW 0x40000000 #define MAC_CFG_PREAMBLE_SHIFT 10 #define MAC_CFG_PREAMBLE_DEFAULT 7 @@ -683,11 +708,19 @@ #define HDS_CFG_BACKFILLSIZE_SHIFT 8 #define HDS_CFG_MAX_HDRSIZE_SHIFT 20 -/* AR8131/AR8132 registers for MAC statistics */ +/* AR813x/AR815x registers for MAC statistics */ #define ALC_RX_MIB_BASE 0x1700 #define ALC_TX_MIB_BASE 0x1760 +#define ALC_CLK_GATING_CFG 0x1814 +#define CLK_GATING_DMAW_ENB 0x0001 +#define CLK_GATING_DMAR_ENB 0x0002 +#define CLK_GATING_TXQ_ENB 0x0004 +#define CLK_GATING_RXQ_ENB 0x0008 +#define CLK_GATING_TXMAC_ENB 0x0010 +#define CLK_GATING_RXMAC_ENB 0x0020 + #define ALC_DEBUG_DATA0 0x1900 #define ALC_DEBUG_DATA1 0x1904 @@ -1112,6 +1145,7 @@ struct alc_softc { bus_dma_tag_t sc_dmat; pci_chipset_tag_t sc_pct; pcitag_t sc_pcitag; + pci_vendor_id_t sc_product; void *sc_irq_handle; @@ -1120,19 +1154,23 @@ struct alc_softc { int alc_chip_rev; int alc_phyaddr; uint8_t alc_eaddr[ETHER_ADDR_LEN]; + uint32_t alc_max_framelen; 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 -#define ALC_FLAG_MSI 0x0004 -#define ALC_FLAG_MSIX 0x0008 +#define ALC_FLAG_PM 0x0010 #define ALC_FLAG_FASTETHER 0x0020 #define ALC_FLAG_JUMBO 0x0040 #define ALC_FLAG_ASPM_MON 0x0080 #define ALC_FLAG_CMB_BUG 0x0100 #define ALC_FLAG_SMB_BUG 0x0200 +#define ALC_FLAG_L0S 0x0400 +#define ALC_FLAG_L1S 0x0800 +#define ALC_FLAG_APS 0x1000 #define ALC_FLAG_DETACH 0x4000 #define ALC_FLAG_LINK 0x8000 |