Module Name: src Committed By: jmcneill Date: Wed Feb 23 02:25:04 UTC 2011
Modified Files: src/sys/dev/pci: if_alc.c if_alcreg.h Log Message: catch up with FreeBSD driver, adds support for AR815x chips To generate a diff of this commit: cvs rdiff -u -r1.1 -r1.2 src/sys/dev/pci/if_alc.c src/sys/dev/pci/if_alcreg.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_alc.c diff -u src/sys/dev/pci/if_alc.c:1.1 src/sys/dev/pci/if_alc.c:1.2 --- src/sys/dev/pci/if_alc.c:1.1 Wed Feb 23 00:35:29 2011 +++ src/sys/dev/pci/if_alc.c Wed Feb 23 02:25:04 2011 @@ -26,7 +26,7 @@ * SUCH DAMAGE. */ -/* Driver for Atheros AR8131/AR8132 PCIe Ethernet. */ +/* Driver for Atheros AR813x/AR815x PCIe Ethernet. */ #ifdef _KERNEL_OPT #include "vlan.h" @@ -79,6 +79,25 @@ #include <dev/pci/if_alcreg.h> +/* + * Devices supported by this driver. + */ +static struct alc_ident alc_ident_table[] = { + { PCI_VENDOR_ATTANSIC, PCI_PRODUCT_ATTANSIC_AR8131, 9 * 1024, + "Atheros AR8131 PCIe Gigabit Ethernet" }, + { PCI_VENDOR_ATTANSIC, PCI_PRODUCT_ATTANSIC_AR8132, 9 * 1024, + "Atheros AR8132 PCIe Fast Ethernet" }, + { PCI_VENDOR_ATTANSIC, PCI_PRODUCT_ATTANSIC_AR8151, 6 * 1024, + "Atheros AR8151 v1.0 PCIe Gigabit Ethernet" }, + { PCI_VENDOR_ATTANSIC, PCI_PRODUCT_ATTANSIC_AR8151_V2, 6 * 1024, + "Atheros AR8151 v2.0 PCIe Gigabit Ethernet" }, + { PCI_VENDOR_ATTANSIC, PCI_PRODUCT_ATTANSIC_AR8152_B, 6 * 1024, + "Atheros AR8152 v1.1 PCIe Fast Ethernet" }, + { PCI_VENDOR_ATTANSIC, PCI_PRODUCT_ATTANSIC_AR8152_B2, 6 * 1024, + "Atheros AR8152 v2.0 PCIe Fast Ethernet" }, + { 0, 0, 0, NULL }, +}; + static int alc_match(device_t, cfdata_t, void *); static void alc_attach(device_t, device_t, void *); static int alc_detach(device_t, int); @@ -90,11 +109,13 @@ static int alc_mediachange(struct ifnet *); static void alc_mediastatus(struct ifnet *, struct ifmediareq *); -static void alc_aspm(struct alc_softc *); +static void alc_aspm(struct alc_softc *, int); static void alc_disable_l0s_l1(struct alc_softc *); static int alc_dma_alloc(struct alc_softc *); static void alc_dma_free(struct alc_softc *); static int alc_encap(struct alc_softc *, struct mbuf **); +static struct alc_ident * + alc_find_ident(struct pci_attach_args *); static void alc_get_macaddr(struct alc_softc *); static void alc_init_cmb(struct alc_softc *); static void alc_init_rr_ring(struct alc_softc *); @@ -228,8 +249,8 @@ 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); } static void @@ -261,44 +282,81 @@ return (error); } +static struct alc_ident * +alc_find_ident(struct pci_attach_args *pa) +{ + struct alc_ident *ident; + uint16_t vendor, devid; + + vendor = PCI_VENDOR(pa->pa_id); + devid = PCI_PRODUCT(pa->pa_id); + for (ident = alc_ident_table; ident->name != NULL; ident++) { + if (vendor == ident->vendorid && devid == ident->deviceid) + return (ident); + } + + return (NULL); +} + static int alc_match(device_t dev, cfdata_t match, void *aux) { struct pci_attach_args *pa = aux; - if (PCI_VENDOR(pa->pa_id) != PCI_VENDOR_ATTANSIC) - return 0; - - switch (PCI_PRODUCT(pa->pa_id)) { - case PCI_PRODUCT_ATTANSIC_AR8131: - case PCI_PRODUCT_ATTANSIC_AR8132: - case PCI_PRODUCT_ATTANSIC_AR8152_B2: - break; - default: - return 0; - } - - return 1; + return alc_find_ident(pa) != NULL; } static 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->alc_ident->deviceid) { + case PCI_PRODUCT_ATTANSIC_AR8131: + case PCI_PRODUCT_ATTANSIC_AR8132: + 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_AR8151: + case PCI_PRODUCT_ATTANSIC_AR8151_V2: + case PCI_PRODUCT_ATTANSIC_AR8152_B: + case PCI_PRODUCT_ATTANSIC_AR8152_B2: + 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--) { @@ -314,11 +372,36 @@ if (alcdebug) printf("%s: EEPROM not found!\n", device_xname(sc->sc_dev)); } - 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->alc_ident->deviceid) { + case PCI_PRODUCT_ATTANSIC_AR8131: + case PCI_PRODUCT_ATTANSIC_AR8132: + 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_AR8151: + case PCI_PRODUCT_ATTANSIC_AR8151_V2: + case PCI_PRODUCT_ATTANSIC_AR8152_B: + case PCI_PRODUCT_ATTANSIC_AR8152_B2: + 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); @@ -363,6 +446,43 @@ CSR_READ_2(sc, ALC_GPHY_CFG); DELAY(10 * 1000); + /* DSP fixup, Vendor magic. */ + if (sc->alc_ident->deviceid == PCI_PRODUCT_ATTANSIC_AR8152_B) { + 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->alc_ident->deviceid == PCI_PRODUCT_ATTANSIC_AR8151 || + sc->alc_ident->deviceid == PCI_PRODUCT_ATTANSIC_AR8151_V2 || + sc->alc_ident->deviceid == PCI_PRODUCT_ATTANSIC_AR8152_B || + sc->alc_ident->deviceid == PCI_PRODUCT_ATTANSIC_AR8152_B2) { + 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->alc_ident->deviceid == PCI_PRODUCT_ATTANSIC_AR8151) { + 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->alc_ident->deviceid == PCI_PRODUCT_ATTANSIC_AR8131 || + sc->alc_ident->deviceid == PCI_PRODUCT_ATTANSIC_AR8132 || + sc->alc_ident->deviceid == PCI_PRODUCT_ATTANSIC_AR8151_V2 || + sc->alc_ident->deviceid == PCI_PRODUCT_ATTANSIC_AR8152_B2) { + 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); @@ -411,35 +531,115 @@ static 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->alc_ident->deviceid) { + case PCI_PRODUCT_ATTANSIC_AR8151: + case PCI_PRODUCT_ATTANSIC_AR8151_V2: + /* + * 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; + } } static 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->alc_ident->deviceid == PCI_PRODUCT_ATTANSIC_AR8152_B && + 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->alc_ident->deviceid == + PCI_PRODUCT_ATTANSIC_AR8152_B) + 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->alc_ident->deviceid) { + case PCI_PRODUCT_ATTANSIC_AR8152_B: + pmcfg |= (7 << + PM_CFG_L1_ENTRY_TIMER_SHIFT); + break; + case PCI_PRODUCT_ATTANSIC_AR8152_B2: + case PCI_PRODUCT_ATTANSIC_AR8151_V2: + 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); } @@ -455,13 +655,15 @@ const char *intrstr; struct ifnet *ifp; pcireg_t memtype; - const char *aspm_state[] = { "L0s/L1", "L0s", "L1", "L0s/l1" }; + const char *aspm_state[] = { "L0s/L1", "L0s", "L1", "L0s/L1" }; uint16_t burst; int base, mii_flags, state, error = 0; uint32_t cap, ctl, val; + sc->alc_ident = alc_find_ident(pa); + aprint_naive("\n"); - aprint_normal(": Attansic/Atheros L1C/L2C Ethernet\n"); + aprint_normal(": %s\n", sc->alc_ident->name); sc->sc_dev = self; sc->sc_dmat = pa->pa_dmat; @@ -517,6 +719,7 @@ 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; @@ -533,6 +736,20 @@ 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->alc_ident->deviceid == PCI_PRODUCT_ATTANSIC_AR8152_B && + 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; @@ -546,13 +763,18 @@ device_xname(sc->sc_dev), 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", device_xname(sc->sc_dev), aspm_state[state], state == 0 ? "disabled" : "enabled"); - if (state != 0) - alc_disable_l0s_l1(sc); + alc_disable_l0s_l1(sc); + } else { + aprint_debug_dev(sc->sc_dev, "no ASPM support\n"); } } @@ -569,18 +791,25 @@ * used in AR8132 can't establish gigabit link even if it * shows the same PHY model/revision number of AR8131. */ - switch (PCI_PRODUCT(pa->pa_id)) { - case PCI_PRODUCT_ATTANSIC_AR8132: + switch (sc->alc_ident->deviceid) { + case PCI_PRODUCT_ATTANSIC_AR8152_B: case PCI_PRODUCT_ATTANSIC_AR8152_B2: - sc->alc_flags |= ALC_FLAG_FASTETHER | ALC_FLAG_JUMBO; + sc->alc_flags |= ALC_FLAG_APS; + /* FALLTHROUGH */ + case PCI_PRODUCT_ATTANSIC_AR8132: + sc->alc_flags |= ALC_FLAG_FASTETHER; break; + case PCI_PRODUCT_ATTANSIC_AR8151: + case PCI_PRODUCT_ATTANSIC_AR8151_V2: + sc->alc_flags |= ALC_FLAG_APS; + /* FALLTHROUGH */ default: - sc->alc_flags |= ALC_FLAG_JUMBO | ALC_FLAG_ASPM_MON; break; } + sc->alc_flags |= ALC_FLAG_JUMBO | ALC_FLAG_ASPM_MON; /* - * 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. @@ -1257,6 +1486,10 @@ 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->alc_ident->deviceid == PCI_PRODUCT_ATTANSIC_AR8151 || + sc->alc_ident->deviceid == PCI_PRODUCT_ATTANSIC_AR8151_V2 || + sc->alc_ident->deviceid == PCI_PRODUCT_ATTANSIC_AR8152_B2) + 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: @@ -1680,8 +1913,8 @@ * 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; } @@ -1789,7 +2022,9 @@ 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) @@ -1840,6 +2075,9 @@ alc_init_cmb(sc); alc_init_smb(sc); + /* Enable all clocks. */ + CSR_WRITE_4(sc, ALC_CLK_GATING_CFG, 0); + /* Reprogram the station address. */ memcpy(eaddr, CLLADDR(ifp->if_sadl), sizeof(eaddr)); CSR_WRITE_4(sc, ALC_PAR0, @@ -1901,6 +2139,18 @@ 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->alc_ident->deviceid == PCI_PRODUCT_ATTANSIC_AR8152_B) { + /* 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); @@ -1910,14 +2160,11 @@ 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) @@ -1958,7 +2205,7 @@ * 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_ident->max_framelen); /* Disable header split(?) */ CSR_WRITE_4(sc, ALC_HDS_CFG, 0); @@ -1985,11 +2232,14 @@ * TSO/checksum offloading. */ CSR_WRITE_4(sc, ALC_TSO_OFFLOAD_THRESH, - (ALC_JUMBO_FRAMELEN >> TSO_OFFLOAD_THRESH_UNIT_SHIFT) & + (sc->alc_ident->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->alc_ident->deviceid == PCI_PRODUCT_ATTANSIC_AR8152_B || + sc->alc_ident->deviceid == PCI_PRODUCT_ATTANSIC_AR8152_B2) + 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); @@ -2006,14 +2256,23 @@ * 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->alc_ident->deviceid == PCI_PRODUCT_ATTANSIC_AR8131 || + sc->alc_ident->deviceid == PCI_PRODUCT_ATTANSIC_AR8132) { + 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->alc_ident->deviceid == PCI_PRODUCT_ATTANSIC_AR8152_B || + sc->alc_ident->deviceid == PCI_PRODUCT_ATTANSIC_AR8151_V2) + 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); @@ -2024,15 +2283,9 @@ 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; @@ -2058,7 +2311,7 @@ * - 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 @@ -2068,6 +2321,10 @@ 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->alc_ident->deviceid == PCI_PRODUCT_ATTANSIC_AR8151 || + sc->alc_ident->deviceid == PCI_PRODUCT_ATTANSIC_AR8151_V2 || + sc->alc_ident->deviceid == PCI_PRODUCT_ATTANSIC_AR8152_B2) + 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 @@ -2171,7 +2428,7 @@ /* Disable Rx/Tx MAC. */ reg = CSR_READ_4(sc, ALC_MAC_CFG); if ((reg & (MAC_CFG_TX_ENB | MAC_CFG_RX_ENB)) != 0) { - reg &= ~MAC_CFG_TX_ENB | MAC_CFG_RX_ENB; + reg &= ~(MAC_CFG_TX_ENB | MAC_CFG_RX_ENB); CSR_WRITE_4(sc, ALC_MAC_CFG, reg); } for (i = ALC_TIMEOUT; i > 0; i--) { @@ -2222,7 +2479,7 @@ } /* Disable TxQ. */ reg = CSR_READ_4(sc, ALC_TXQ_CFG); - if ((reg & TXQ_CFG_ENB) == 0) { + if ((reg & TXQ_CFG_ENB) != 0) { reg &= ~TXQ_CFG_ENB; CSR_WRITE_4(sc, ALC_TXQ_CFG, reg); } Index: src/sys/dev/pci/if_alcreg.h diff -u src/sys/dev/pci/if_alcreg.h:1.1 src/sys/dev/pci/if_alcreg.h:1.2 --- src/sys/dev/pci/if_alcreg.h:1.1 Wed Feb 23 00:35:29 2011 +++ src/sys/dev/pci/if_alcreg.h Wed Feb 23 02:25:04 2011 @@ -33,6 +33,9 @@ #define ALC_PCIR_BAR 0x10 +#define ATHEROS_AR8152_B_V10 0xC0 +#define ATHEROS_AR8152_B_V11 0xC1 + /* 0x0000 - 0x02FF : PCIe configuration space */ #define ALC_PEX_UNC_ERR_SEV 0x10C @@ -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) @@ -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 @@ -974,13 +1007,8 @@ #define ALC_PROC_MAX (ALC_RX_RING_CNT - 1) #define ALC_PROC_DEFAULT (ALC_RX_RING_CNT / 4) -#define ALC_JUMBO_FRAMELEN (9 * 1024) -#define ALC_JUMBO_MTU \ - (ALC_JUMBO_FRAMELEN - sizeof(struct ether_vlan_header) - ETHER_CRC_LEN) -#define ALC_MAX_FRAMELEN (ETHER_MAX_LEN + ETHER_VLAN_ENCAP_LEN) - /* - * The number of bits reserved for MSS in AR8121/AR8132 controllers + * The number of bits reserved for MSS in AR813x/AR815x controllers * are 13 bits. This limits the maximum interface MTU size in TSO * case(8191 + sizeof(struct ip) + sizeof(struct tcphdr)) as upper * stack should not generate TCP segments with MSS greater than the @@ -1099,6 +1127,13 @@ uint64_t tx_mcast_bytes; }; +struct alc_ident { + uint16_t vendorid; + uint16_t deviceid; + uint32_t max_framelen; + const char *name; +}; + /* * Software state per device. */ @@ -1114,9 +1149,10 @@ pcitag_t sc_pcitag; void *sc_irq_handle; - + struct alc_ident *alc_ident; struct mii_data sc_miibus; int alc_rev; + int alc_expcap; int alc_chip_rev; int alc_phyaddr; uint8_t alc_eaddr[ETHER_ADDR_LEN]; @@ -1133,7 +1169,9 @@ #define ALC_FLAG_ASPM_MON 0x0080 #define ALC_FLAG_CMB_BUG 0x0100 #define ALC_FLAG_SMB_BUG 0x0200 -#define ALC_FLAG_DETACH 0x4000 +#define ALC_FLAG_L0S 0x0400 +#define ALC_FLAG_L1S 0x0800 +#define ALC_FLAG_APS 0x1000 #define ALC_FLAG_LINK 0x8000 callout_t sc_tick_ch;