diff --git a/src/add-ons/kernel/drivers/network/ar81xx/dev/ale/if_ale.c b/src/add-ons/kernel/drivers/network/ar81xx/dev/ale/if_ale.c index bad25df411..a3aab0f1cd 100644 --- a/src/add-ons/kernel/drivers/network/ar81xx/dev/ale/if_ale.c +++ b/src/add-ons/kernel/drivers/network/ar81xx/dev/ale/if_ale.c @@ -28,7 +28,7 @@ /* Driver for Atheros AR8121/AR8113/AR8114 PCIe Ethernet. */ #include -__FBSDID("$FreeBSD: src/sys/dev/ale/if_ale.c,v 1.3 2008/12/03 09:01:12 yongari Exp $"); +__FBSDID("$FreeBSD$"); #include #include @@ -78,9 +78,6 @@ __FBSDID("$FreeBSD: src/sys/dev/ale/if_ale.c,v 1.3 2008/12/03 09:01:12 yongari E /* For more information about Tx checksum offload issues see ale_encap(). */ #define ALE_CSUM_FEATURES (CSUM_TCP | CSUM_UDP) -#ifndef IFCAP_VLAN_HWTSO -#define IFCAP_VLAN_HWTSO 0 -#endif MODULE_DEPEND(ale, pci, 1, 1, 1); MODULE_DEPEND(ale, ether, 1, 1, 1); @@ -211,9 +208,6 @@ ale_miibus_readreg(device_t dev, int phy, int reg) sc = device_get_softc(dev); - if (phy != sc->ale_phyaddr) - return (0); - CSR_WRITE_4(sc, ALE_MDIO, MDIO_OP_EXECUTE | MDIO_OP_READ | MDIO_SUP_PREAMBLE | MDIO_CLK_25_4 | MDIO_REG_ADDR(reg)); for (i = ALE_PHY_TIMEOUT; i > 0; i--) { @@ -240,9 +234,6 @@ ale_miibus_writereg(device_t dev, int phy, int reg, int val) sc = device_get_softc(dev); - if (phy != sc->ale_phyaddr) - return (0); - CSR_WRITE_4(sc, ALE_MDIO, MDIO_OP_EXECUTE | MDIO_OP_WRITE | (val & MDIO_DATA_MASK) << MDIO_DATA_SHIFT | MDIO_SUP_PREAMBLE | MDIO_CLK_25_4 | MDIO_REG_ADDR(reg)); @@ -610,18 +601,28 @@ ale_attach(device_t dev) ifp->if_capenable = ifp->if_capabilities; /* Set up MII bus. */ - if ((error = mii_phy_probe(dev, &sc->ale_miibus, ale_mediachange, - ale_mediastatus)) != 0) { - device_printf(dev, "no PHY found!\n"); + error = mii_attach(dev, &sc->ale_miibus, ifp, ale_mediachange, + ale_mediastatus, BMSR_DEFCAPMASK, sc->ale_phyaddr, MII_OFFSET_ANY, + 0); + if (error != 0) { + device_printf(dev, "attaching PHYs failed\n"); goto fail; } ether_ifattach(ifp, sc->ale_eaddr); /* VLAN capability setup. */ - ifp->if_capabilities |= IFCAP_VLAN_MTU; - ifp->if_capabilities |= IFCAP_VLAN_HWTAGGING | IFCAP_VLAN_HWCSUM; + ifp->if_capabilities |= IFCAP_VLAN_MTU | IFCAP_VLAN_HWTAGGING | + IFCAP_VLAN_HWCSUM | IFCAP_VLAN_HWTSO; ifp->if_capenable = ifp->if_capabilities; + /* + * Even though controllers supported by ale(3) have Rx checksum + * offload bug the workaround for fragmented frames seemed to + * work so far. However it seems Rx checksum offload does not + * work under certain conditions. So disable Rx checksum offload + * until I find more clue about it but allow users to override it. + */ + ifp->if_capenable &= ~IFCAP_RXCSUM; /* Tell the upper layer(s) we support long frames. */ ifp->if_data.ifi_hdrlen = sizeof(struct ether_vlan_header); @@ -1549,20 +1550,11 @@ ale_resume(device_t dev) struct ale_softc *sc; struct ifnet *ifp; int pmc; - uint16_t cmd, pmstat; + uint16_t pmstat; sc = device_get_softc(dev); ALE_LOCK(sc); - /* - * Clear INTx emulation disable for hardwares that - * is set in resume event. From Linux. - */ - cmd = pci_read_config(sc->ale_dev, PCIR_COMMAND, 2); - if ((cmd & 0x0400) != 0) { - cmd &= ~0x0400; - pci_write_config(sc->ale_dev, PCIR_COMMAND, cmd, 2); - } if (pci_find_extcap(sc->ale_dev, PCIY_PMG, &pmc) == 0) { /* Disable PME and clear PME status. */ pmstat = pci_read_config(sc->ale_dev, @@ -1595,7 +1587,7 @@ ale_encap(struct ale_softc *sc, struct mbuf **m_head) struct tcphdr *tcp; bus_dma_segment_t txsegs[ALE_MAXTXSEGS]; bus_dmamap_t map; - uint32_t cflags, ip_off, poff, vtag; + uint32_t cflags, hdrlen, ip_off, poff, vtag; int error, i, nsegs, prod, si; ALE_LOCK_ASSERT(sc); @@ -1687,7 +1679,13 @@ ale_encap(struct ale_softc *sc, struct mbuf **m_head) *m_head = NULL; return (ENOBUFS); } + ip = (struct ip *)(mtod(m, char *) + ip_off); tcp = (struct tcphdr *)(mtod(m, char *) + poff); + m = m_pullup(m, poff + (tcp->th_off << 2)); + if (m == NULL) { + *m_head = NULL; + return (ENOBUFS); + } /* * AR81xx requires IP/TCP header size and offset as * well as TCP pseudo checksum which complicates @@ -1740,15 +1738,21 @@ ale_encap(struct ale_softc *sc, struct mbuf **m_head) } /* Check descriptor overrun. */ - if (sc->ale_cdata.ale_tx_cnt + nsegs >= ALE_TX_RING_CNT - 2) { + if (sc->ale_cdata.ale_tx_cnt + nsegs >= ALE_TX_RING_CNT - 3) { bus_dmamap_unload(sc->ale_cdata.ale_tx_tag, map); return (ENOBUFS); } bus_dmamap_sync(sc->ale_cdata.ale_tx_tag, map, BUS_DMASYNC_PREWRITE); m = *m_head; - /* Configure Tx checksum offload. */ - if ((m->m_pkthdr.csum_flags & ALE_CSUM_FEATURES) != 0) { + if ((m->m_pkthdr.csum_flags & CSUM_TSO) != 0) { + /* Request TSO and set MSS. */ + cflags |= ALE_TD_TSO; + cflags |= ((uint32_t)m->m_pkthdr.tso_segsz << ALE_TD_MSS_SHIFT); + /* Set IP/TCP header size. */ + cflags |= ip->ip_hl << ALE_TD_IPHDR_LEN_SHIFT; + cflags |= tcp->th_off << ALE_TD_TCPHDR_LEN_SHIFT; + } else if ((m->m_pkthdr.csum_flags & ALE_CSUM_FEATURES) != 0) { /* * AR81xx supports Tx custom checksum offload feature * that offloads single 16bit checksum computation. @@ -1779,15 +1783,6 @@ ale_encap(struct ale_softc *sc, struct mbuf **m_head) ALE_TD_CSUM_XSUMOFFSET_SHIFT); } - if ((m->m_pkthdr.csum_flags & CSUM_TSO) != 0) { - /* Request TSO and set MSS. */ - cflags |= ALE_TD_TSO; - cflags |= ((uint32_t)m->m_pkthdr.tso_segsz << ALE_TD_MSS_SHIFT); - /* Set IP/TCP header size. */ - cflags |= ip->ip_hl << ALE_TD_IPHDR_LEN_SHIFT; - cflags |= tcp->th_off << ALE_TD_TCPHDR_LEN_SHIFT; - } - /* Configure VLAN hardware tag insertion. */ if ((m->m_flags & M_VLANTAG) != 0) { vtag = ALE_TX_VLAN_TAG(m->m_pkthdr.ether_vtag); @@ -1795,8 +1790,32 @@ ale_encap(struct ale_softc *sc, struct mbuf **m_head) cflags |= ALE_TD_INSERT_VLAN_TAG; } - desc = NULL; - for (i = 0; i < nsegs; i++) { + i = 0; + if ((m->m_pkthdr.csum_flags & CSUM_TSO) != 0) { + /* + * Make sure the first fragment contains + * only ethernet and IP/TCP header with options. + */ + hdrlen = poff + (tcp->th_off << 2); + desc = &sc->ale_cdata.ale_tx_ring[prod]; + desc->addr = htole64(txsegs[i].ds_addr); + desc->len = htole32(ALE_TX_BYTES(hdrlen) | vtag); + desc->flags = htole32(cflags); + sc->ale_cdata.ale_tx_cnt++; + ALE_DESC_INC(prod, ALE_TX_RING_CNT); + if (m->m_len - hdrlen > 0) { + /* Handle remaining payload of the first fragment. */ + desc = &sc->ale_cdata.ale_tx_ring[prod]; + desc->addr = htole64(txsegs[i].ds_addr + hdrlen); + desc->len = htole32(ALE_TX_BYTES(m->m_len - hdrlen) | + vtag); + desc->flags = htole32(cflags); + sc->ale_cdata.ale_tx_cnt++; + ALE_DESC_INC(prod, ALE_TX_RING_CNT); + } + i = 1; + } + for (; i < nsegs; i++) { desc = &sc->ale_cdata.ale_tx_ring[prod]; desc->addr = htole64(txsegs[i].ds_addr); desc->len = htole32(ALE_TX_BYTES(txsegs[i].ds_len) | vtag); @@ -2003,6 +2022,7 @@ ale_ioctl(struct ifnet *ifp, u_long cmd, caddr_t data) else ifp->if_hwassist &= ~CSUM_TSO; } + #ifdef ENABLE_WOL if ((mask & IFCAP_WOL_MCAST) != 0 && (ifp->if_capabilities & IFCAP_WOL_MCAST) != 0) @@ -2011,28 +2031,19 @@ ale_ioctl(struct ifnet *ifp, u_long cmd, caddr_t data) (ifp->if_capabilities & IFCAP_WOL_MAGIC) != 0) ifp->if_capenable ^= IFCAP_WOL_MAGIC; #endif - if ((mask & IFCAP_VLAN_HWTAGGING) != 0 && - (ifp->if_capabilities & IFCAP_VLAN_HWTAGGING) != 0) { - ifp->if_capenable ^= IFCAP_VLAN_HWTAGGING; - ale_rxvlan(sc); - } if ((mask & IFCAP_VLAN_HWCSUM) != 0 && (ifp->if_capabilities & IFCAP_VLAN_HWCSUM) != 0) ifp->if_capenable ^= IFCAP_VLAN_HWCSUM; if ((mask & IFCAP_VLAN_HWTSO) != 0 && (ifp->if_capabilities & IFCAP_VLAN_HWTSO) != 0) ifp->if_capenable ^= IFCAP_VLAN_HWTSO; - /* - * VLAN hardware tagging is required to do checksum - * offload or TSO on VLAN interface. Checksum offload - * on VLAN interface also requires hardware checksum - * offload of parent interface. - */ - if ((ifp->if_capenable & IFCAP_TXCSUM) == 0) - ifp->if_capenable &= ~IFCAP_VLAN_HWCSUM; - if ((ifp->if_capenable & IFCAP_VLAN_HWTAGGING) == 0) - ifp->if_capenable &= - ~(IFCAP_VLAN_HWTSO | IFCAP_VLAN_HWCSUM); + if ((mask & IFCAP_VLAN_HWTAGGING) != 0 && + (ifp->if_capabilities & IFCAP_VLAN_HWTAGGING) != 0) { + ifp->if_capenable ^= IFCAP_VLAN_HWTAGGING; + if ((ifp->if_capenable & IFCAP_VLAN_HWTAGGING) == 0) + ifp->if_capenable &= ~IFCAP_VLAN_HWTSO; + ale_rxvlan(sc); + } ALE_UNLOCK(sc); VLAN_CAPABILITIES(ifp); break; @@ -3063,15 +3074,15 @@ ale_rxfilter(struct ale_softc *sc) /* Program new filter. */ bzero(mchash, sizeof(mchash)); - IF_ADDR_LOCK(ifp); + if_maddr_rlock(ifp); TAILQ_FOREACH(ifma, &sc->ale_ifp->if_multiaddrs, ifma_link) { if (ifma->ifma_addr->sa_family != AF_LINK) continue; - crc = ether_crc32_le(LLADDR((struct sockaddr_dl *) + crc = ether_crc32_be(LLADDR((struct sockaddr_dl *) ifma->ifma_addr), ETHER_ADDR_LEN); mchash[crc >> 31] |= 1 << ((crc >> 26) & 0x1f); } - IF_ADDR_UNLOCK(ifp); + if_maddr_runlock(ifp); CSR_WRITE_4(sc, ALE_MAR0, mchash[0]); CSR_WRITE_4(sc, ALE_MAR1, mchash[1]); diff --git a/src/add-ons/kernel/drivers/network/ar81xx/dev/ale/if_alereg.h b/src/add-ons/kernel/drivers/network/ar81xx/dev/ale/if_alereg.h index 7df9783aea..896b0abb44 100644 --- a/src/add-ons/kernel/drivers/network/ar81xx/dev/ale/if_alereg.h +++ b/src/add-ons/kernel/drivers/network/ar81xx/dev/ale/if_alereg.h @@ -24,7 +24,7 @@ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMATE. * - * $FreeBSD: src/sys/dev/ale/if_alereg.h,v 1.1.2.1.2.1 2008/11/25 02:59:29 kensmith Exp $ + * $FreeBSD$ */ #ifndef _IF_ALEREG_H diff --git a/src/add-ons/kernel/drivers/network/ar81xx/dev/ale/if_alevar.h b/src/add-ons/kernel/drivers/network/ar81xx/dev/ale/if_alevar.h index 69bfad7c74..aaaf98571c 100644 --- a/src/add-ons/kernel/drivers/network/ar81xx/dev/ale/if_alevar.h +++ b/src/add-ons/kernel/drivers/network/ar81xx/dev/ale/if_alevar.h @@ -24,7 +24,7 @@ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. * - * $FreeBSD: src/sys/dev/ale/if_alevar.h,v 1.1.2.1.2.1 2008/11/25 02:59:29 kensmith Exp $ + * $FreeBSD$ */ #ifndef _IF_ALEVAR_H diff --git a/src/add-ons/kernel/drivers/network/atheros813x/dev/alc/if_alc.c b/src/add-ons/kernel/drivers/network/atheros813x/dev/alc/if_alc.c index a53af779b0..7b23fae6fa 100644 --- a/src/add-ons/kernel/drivers/network/atheros813x/dev/alc/if_alc.c +++ b/src/add-ons/kernel/drivers/network/atheros813x/dev/alc/if_alc.c @@ -25,7 +25,7 @@ * SUCH DAMAGE. */ -/* Driver for Atheros AR8131/AR8132 PCIe Ethernet. */ +/* Driver for Atheros AR813x/AR815x PCIe Ethernet. */ #include __FBSDID("$FreeBSD$"); @@ -84,9 +84,6 @@ __FBSDID("$FreeBSD$"); #else #define ALC_CSUM_FEATURES (CSUM_IP | CSUM_TCP | CSUM_UDP) #endif -#ifndef IFCAP_VLAN_HWTSO -#define IFCAP_VLAN_HWTSO 0 -#endif MODULE_DEPEND(alc, pci, 1, 1, 1); MODULE_DEPEND(alc, ether, 1, 1, 1); @@ -101,18 +98,23 @@ TUNABLE_INT("hw.alc.msix_disable", &msix_disable); /* * Devices supported by this driver. */ -static struct alc_dev { - uint16_t alc_vendorid; - uint16_t alc_deviceid; - const char *alc_name; -} alc_devs[] = { - { VENDORID_ATHEROS, DEVICEID_ATHEROS_AR8131, +static struct alc_ident alc_ident_table[] = { + { VENDORID_ATHEROS, DEVICEID_ATHEROS_AR8131, 9 * 1024, "Atheros AR8131 PCIe Gigabit Ethernet" }, - { VENDORID_ATHEROS, DEVICEID_ATHEROS_AR8132, - "Atheros AR8132 PCIe Fast Ethernet" } + { VENDORID_ATHEROS, DEVICEID_ATHEROS_AR8132, 9 * 1024, + "Atheros AR8132 PCIe Fast Ethernet" }, + { VENDORID_ATHEROS, DEVICEID_ATHEROS_AR8151, 6 * 1024, + "Atheros AR8151 v1.0 PCIe Gigabit Ethernet" }, + { VENDORID_ATHEROS, DEVICEID_ATHEROS_AR8151_V2, 6 * 1024, + "Atheros AR8151 v2.0 PCIe Gigabit Ethernet" }, + { VENDORID_ATHEROS, DEVICEID_ATHEROS_AR8152_B, 6 * 1024, + "Atheros AR8152 v1.1 PCIe Fast Ethernet" }, + { VENDORID_ATHEROS, DEVICEID_ATHEROS_AR8152_B2, 6 * 1024, + "Atheros AR8152 v2.0 PCIe Fast Ethernet" }, + { 0, 0, 0, NULL} }; -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); @@ -121,6 +123,8 @@ static int alc_dma_alloc(struct alc_softc *); static void alc_dma_free(struct alc_softc *); static void alc_dmamap_cb(void *, bus_dma_segment_t *, int, int); static int alc_encap(struct alc_softc *, struct mbuf **); +static struct alc_ident * + alc_find_ident(device_t); #ifndef __NO_STRICT_ALIGNMENT static struct mbuf * alc_fixup_rx(struct ifnet *, struct mbuf *); @@ -231,7 +235,14 @@ alc_miibus_readreg(device_t dev, int phy, int reg) sc = device_get_softc(dev); - if (phy != sc->alc_phyaddr) + /* + * For AR8132 fast ethernet controller, do not report 1000baseT + * capability to mii(4). Even though AR8132 uses the same + * model/revision number of F1 gigabit PHY, the PHY has no + * ability to establish 1000baseT link. + */ + if ((sc->alc_flags & ALC_FLAG_FASTETHER) != 0 && + reg == MII_EXTSR) return (0); CSR_WRITE_4(sc, ALC_MDIO, MDIO_OP_EXECUTE | MDIO_OP_READ | @@ -260,9 +271,6 @@ alc_miibus_writereg(device_t dev, int phy, int reg, int val) sc = device_get_softc(dev); - if (phy != sc->alc_phyaddr) - return (0); - CSR_WRITE_4(sc, ALC_MDIO, MDIO_OP_EXECUTE | MDIO_OP_WRITE | (val & MDIO_DATA_MASK) << MDIO_DATA_SHIFT | MDIO_SUP_PREAMBLE | MDIO_CLK_25_4 | MDIO_REG_ADDR(reg)); @@ -323,8 +331,8 @@ alc_miibus_statchg(device_t 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); } static void @@ -368,23 +376,31 @@ alc_mediachange(struct ifnet *ifp) return (error); } -static int -alc_probe(device_t dev) +static struct alc_ident * +alc_find_ident(device_t dev) { - struct alc_dev *sp; - int i; + struct alc_ident *ident; uint16_t vendor, devid; vendor = pci_get_vendor(dev); devid = pci_get_device(dev); - sp = alc_devs; - for (i = 0; i < sizeof(alc_devs) / sizeof(alc_devs[0]); i++) { - if (vendor == sp->alc_vendorid && - devid == sp->alc_deviceid) { - device_set_desc(dev, sp->alc_name); - return (BUS_PROBE_DEFAULT); - } - sp++; + for (ident = alc_ident_table; ident->name != NULL; ident++) { + if (vendor == ident->vendorid && devid == ident->deviceid) + return (ident); + } + + return (NULL); +} + +static int +alc_probe(device_t dev) +{ + struct alc_ident *ident; + + ident = alc_find_ident(dev); + if (ident != NULL) { + device_set_desc(dev, ident->name); + return (BUS_PROBE_DEFAULT); } return (ENXIO); @@ -394,20 +410,53 @@ 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 DEVICEID_ATHEROS_AR8131: + case DEVICEID_ATHEROS_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 DEVICEID_ATHEROS_AR8151: + case DEVICEID_ATHEROS_AR8151_V2: + case DEVICEID_ATHEROS_AR8152_B: + case DEVICEID_ATHEROS_AR8152_B2: + alc_miibus_writereg(sc->alc_dev, sc->alc_phyaddr, + ALC_MII_DBG_ADDR, 0x00); + val = alc_miibus_readreg(sc->alc_dev, sc->alc_phyaddr, + ALC_MII_DBG_DATA); + alc_miibus_writereg(sc->alc_dev, sc->alc_phyaddr, + ALC_MII_DBG_DATA, val & 0xFF7F); + alc_miibus_writereg(sc->alc_dev, sc->alc_phyaddr, + ALC_MII_DBG_ADDR, 0x3B); + val = alc_miibus_readreg(sc->alc_dev, sc->alc_phyaddr, + ALC_MII_DBG_DATA); + alc_miibus_writereg(sc->alc_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--) { @@ -423,11 +472,36 @@ alc_get_macaddr(struct alc_softc *sc) if (bootverbose) device_printf(sc->alc_dev, "EEPROM not found!\n"); } - 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 DEVICEID_ATHEROS_AR8131: + case DEVICEID_ATHEROS_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 DEVICEID_ATHEROS_AR8151: + case DEVICEID_ATHEROS_AR8151_V2: + case DEVICEID_ATHEROS_AR8152_B: + case DEVICEID_ATHEROS_AR8152_B2: + alc_miibus_writereg(sc->alc_dev, sc->alc_phyaddr, + ALC_MII_DBG_ADDR, 0x00); + val = alc_miibus_readreg(sc->alc_dev, sc->alc_phyaddr, + ALC_MII_DBG_DATA); + alc_miibus_writereg(sc->alc_dev, sc->alc_phyaddr, + ALC_MII_DBG_DATA, val | 0x0080); + alc_miibus_writereg(sc->alc_dev, sc->alc_phyaddr, + ALC_MII_DBG_ADDR, 0x3B); + val = alc_miibus_readreg(sc->alc_dev, sc->alc_phyaddr, + ALC_MII_DBG_DATA); + alc_miibus_writereg(sc->alc_dev, sc->alc_phyaddr, + ALC_MII_DBG_DATA, val & 0xFFF7); + DELAY(20); + break; + } } ea[0] = CSR_READ_4(sc, ALC_PAR0); @@ -472,6 +546,43 @@ alc_phy_reset(struct alc_softc *sc) CSR_READ_2(sc, ALC_GPHY_CFG); DELAY(10 * 1000); + /* DSP fixup, Vendor magic. */ + if (sc->alc_ident->deviceid == DEVICEID_ATHEROS_AR8152_B) { + alc_miibus_writereg(sc->alc_dev, sc->alc_phyaddr, + ALC_MII_DBG_ADDR, 0x000A); + data = alc_miibus_readreg(sc->alc_dev, sc->alc_phyaddr, + ALC_MII_DBG_DATA); + alc_miibus_writereg(sc->alc_dev, sc->alc_phyaddr, + ALC_MII_DBG_DATA, data & 0xDFFF); + } + if (sc->alc_ident->deviceid == DEVICEID_ATHEROS_AR8151 || + sc->alc_ident->deviceid == DEVICEID_ATHEROS_AR8151_V2 || + sc->alc_ident->deviceid == DEVICEID_ATHEROS_AR8152_B || + sc->alc_ident->deviceid == DEVICEID_ATHEROS_AR8152_B2) { + alc_miibus_writereg(sc->alc_dev, sc->alc_phyaddr, + ALC_MII_DBG_ADDR, 0x003B); + data = alc_miibus_readreg(sc->alc_dev, sc->alc_phyaddr, + ALC_MII_DBG_DATA); + alc_miibus_writereg(sc->alc_dev, sc->alc_phyaddr, + ALC_MII_DBG_DATA, data & 0xFFF7); + DELAY(20 * 1000); + } + if (sc->alc_ident->deviceid == DEVICEID_ATHEROS_AR8151) { + alc_miibus_writereg(sc->alc_dev, sc->alc_phyaddr, + ALC_MII_DBG_ADDR, 0x0029); + alc_miibus_writereg(sc->alc_dev, sc->alc_phyaddr, + ALC_MII_DBG_DATA, 0x929D); + } + if (sc->alc_ident->deviceid == DEVICEID_ATHEROS_AR8131 || + sc->alc_ident->deviceid == DEVICEID_ATHEROS_AR8132 || + sc->alc_ident->deviceid == DEVICEID_ATHEROS_AR8151_V2 || + sc->alc_ident->deviceid == DEVICEID_ATHEROS_AR8152_B2) { + alc_miibus_writereg(sc->alc_dev, sc->alc_phyaddr, + ALC_MII_DBG_ADDR, 0x0029); + alc_miibus_writereg(sc->alc_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); @@ -521,36 +632,117 @@ 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 DEVICEID_ATHEROS_AR8151: + case DEVICEID_ATHEROS_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->alc_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; ALC_LOCK_ASSERT(sc); 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 + + PCIR_EXPRESS_LINK_CTL); + 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_SERDES_ENB | PM_CFG_RBER_ENB; + 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 == DEVICEID_ATHEROS_AR8152_B && + sc->alc_rev == ATHEROS_AR8152_B_V10) + linkcfg |= 0x80; + CSR_WRITE_2(sc, sc->alc_expcap + PCIR_EXPRESS_LINK_CTL, + 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 == + DEVICEID_ATHEROS_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 DEVICEID_ATHEROS_AR8152_B: + pmcfg |= (7 << + PM_CFG_L1_ENTRY_TIMER_SHIFT); + break; + case DEVICEID_ATHEROS_AR8152_B2: + case DEVICEID_ATHEROS_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); } @@ -560,9 +752,9 @@ alc_attach(device_t dev) { struct alc_softc *sc; struct ifnet *ifp; - char *aspm_state[] = { "L0s/L1", "L0s", "L1", "L0s/l1" }; + char *aspm_state[] = { "L0s/L1", "L0s", "L1", "L0s/L1" }; uint16_t burst; - int base, error, i, msic, msixc, pmc, state; + int base, error, i, msic, msixc, state; uint32_t cap, ctl, val; error = 0; @@ -573,6 +765,7 @@ alc_attach(device_t dev) MTX_DEF); callout_init_mtx(&sc->alc_tick_ch, &sc->alc_mtx, 0); TASK_INIT(&sc->alc_int_task, 0, alc_int_task, sc); + sc->alc_ident = alc_find_ident(dev); /* Map the device. */ pci_enable_busmaster(dev); @@ -593,6 +786,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; @@ -603,10 +797,28 @@ alc_attach(device_t dev) device_printf(dev, "TLP payload size : %u bytes.\n", alc_dma_burst[sc->alc_dma_wr_burst]); } + if (alc_dma_burst[sc->alc_dma_rd_burst] > 1024) + sc->alc_dma_rd_burst = 3; + if (alc_dma_burst[sc->alc_dma_wr_burst] > 1024) + sc->alc_dma_wr_burst = 3; /* Clear data link and flow-control protocol error. */ 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 == DEVICEID_ATHEROS_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 = CSR_READ_2(sc, base + PCIR_EXPRESS_LINK_CAP); if ((cap & PCIM_LINK_CAP_ASPM) != 0) { @@ -617,12 +829,19 @@ alc_attach(device_t dev) device_printf(dev, "RCB %u bytes\n", 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 (bootverbose) device_printf(sc->alc_dev, "ASPM %s %s\n", aspm_state[state], state == 0 ? "disabled" : "enabled"); - if (state != 0) - alc_disable_l0s_l1(sc); + alc_disable_l0s_l1(sc); + } else { + if (bootverbose) + device_printf(sc->alc_dev, + "no ASPM support\n"); } } @@ -639,12 +858,25 @@ alc_attach(device_t dev) * used in AR8132 can't establish gigabit link even if it * shows the same PHY model/revision number of AR8131. */ - if (pci_get_device(dev) == DEVICEID_ATHEROS_AR8132) - sc->alc_flags |= ALC_FLAG_FASTETHER | ALC_FLAG_JUMBO; - else - sc->alc_flags |= ALC_FLAG_JUMBO | ALC_FLAG_ASPM_MON; + switch (sc->alc_ident->deviceid) { + case DEVICEID_ATHEROS_AR8152_B: + case DEVICEID_ATHEROS_AR8152_B2: + sc->alc_flags |= ALC_FLAG_APS; + /* FALLTHROUGH */ + case DEVICEID_ATHEROS_AR8132: + sc->alc_flags |= ALC_FLAG_FASTETHER; + break; + case DEVICEID_ATHEROS_AR8151: + case DEVICEID_ATHEROS_AR8151_V2: + sc->alc_flags |= ALC_FLAG_APS; + /* FALLTHROUGH */ + default: + break; + } + sc->alc_flags |= ALC_FLAG_ASPM_MON | ALC_FLAG_JUMBO; + /* - * 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. @@ -732,22 +964,27 @@ alc_attach(device_t dev) IFQ_SET_READY(&ifp->if_snd); ifp->if_capabilities = IFCAP_TXCSUM | IFCAP_TSO4; ifp->if_hwassist = ALC_CSUM_FEATURES | CSUM_TSO; - if (pci_find_extcap(dev, PCIY_PMG, &pmc) == 0) + if (pci_find_extcap(dev, PCIY_PMG, &base) == 0) { ifp->if_capabilities |= IFCAP_WOL_MAGIC | IFCAP_WOL_MCAST; + sc->alc_flags |= ALC_FLAG_PM; + sc->alc_pmcap = base; + } ifp->if_capenable = ifp->if_capabilities; /* Set up MII bus. */ - if ((error = mii_phy_probe(dev, &sc->alc_miibus, alc_mediachange, - alc_mediastatus)) != 0) { - device_printf(dev, "no PHY found!\n"); + error = mii_attach(dev, &sc->alc_miibus, ifp, alc_mediachange, + alc_mediastatus, BMSR_DEFCAPMASK, sc->alc_phyaddr, MII_OFFSET_ANY, + MIIF_DOPAUSE); + if (error != 0) { + device_printf(dev, "attaching PHYs failed\n"); goto fail; } ether_ifattach(ifp, sc->alc_eaddr); /* VLAN capability setup. */ - ifp->if_capabilities |= IFCAP_VLAN_MTU; - ifp->if_capabilities |= IFCAP_VLAN_HWTAGGING | IFCAP_VLAN_HWCSUM; + ifp->if_capabilities |= IFCAP_VLAN_MTU | IFCAP_VLAN_HWTAGGING | + IFCAP_VLAN_HWCSUM | IFCAP_VLAN_HWTSO; ifp->if_capenable = ifp->if_capabilities; /* * XXX @@ -1354,7 +1591,7 @@ again: /* * Create Tx buffer parent tag. - * AR8131/AR8132 allows 64bit DMA addressing of Tx/Rx buffers + * AR813x/AR815x allows 64bit DMA addressing of Tx/Rx buffers * so it needs separate parent DMA tag as parent DMA address * space could be restricted to be within 32bit address space * by 4GB boundary crossing. @@ -1662,20 +1899,14 @@ static void alc_setwol(struct alc_softc *sc) { struct ifnet *ifp; - uint32_t cap, reg, pmcs; + uint32_t reg, pmcs; uint16_t pmstat; - int base, pmc; ALC_LOCK_ASSERT(sc); - if (pci_find_extcap(sc->alc_dev, PCIY_EXPRESS, &base) == 0) { - cap = CSR_READ_2(sc, base + PCIR_EXPRESS_LINK_CAP); - if ((cap & PCIM_LINK_CAP_ASPM) != 0) { - cap = CSR_READ_2(sc, base + PCIR_EXPRESS_LINK_CTL); - alc_disable_l0s_l1(sc); - } - } - if (pci_find_extcap(sc->alc_dev, PCIY_PMG, &pmc) != 0) { + alc_disable_l0s_l1(sc); + ifp = sc->alc_ifp; + if ((sc->alc_flags & ALC_FLAG_PM) == 0) { /* Disable WOL. */ CSR_WRITE_4(sc, ALC_WOL_CFG, 0); reg = CSR_READ_4(sc, ALC_PCIE_PHYMISC); @@ -1683,16 +1914,16 @@ alc_setwol(struct alc_softc *sc) CSR_WRITE_4(sc, ALC_PCIE_PHYMISC, reg); /* Force PHY power down. */ alc_phy_down(sc); + CSR_WRITE_4(sc, ALC_MASTER_CFG, + CSR_READ_4(sc, ALC_MASTER_CFG) | MASTER_CLK_SEL_DIS); return; } - ifp = sc->alc_ifp; if ((ifp->if_capenable & IFCAP_WOL) != 0) { if ((sc->alc_flags & ALC_FLAG_FASTETHER) == 0) alc_setlinkspeed(sc); - reg = CSR_READ_4(sc, ALC_MASTER_CFG); - reg &= ~MASTER_CLK_SEL_DIS; - CSR_WRITE_4(sc, ALC_MASTER_CFG, reg); + CSR_WRITE_4(sc, ALC_MASTER_CFG, + CSR_READ_4(sc, ALC_MASTER_CFG) & ~MASTER_CLK_SEL_DIS); } pmcs = 0; @@ -1714,13 +1945,17 @@ alc_setwol(struct alc_softc *sc) if ((ifp->if_capenable & IFCAP_WOL) == 0) { /* WOL disabled, PHY power down. */ alc_phy_down(sc); + CSR_WRITE_4(sc, ALC_MASTER_CFG, + CSR_READ_4(sc, ALC_MASTER_CFG) | MASTER_CLK_SEL_DIS); } /* Request PME. */ - pmstat = pci_read_config(sc->alc_dev, pmc + PCIR_POWER_STATUS, 2); + pmstat = pci_read_config(sc->alc_dev, + sc->alc_pmcap + PCIR_POWER_STATUS, 2); pmstat &= ~(PCIM_PSTAT_PME | PCIM_PSTAT_PMEENABLE); if ((ifp->if_capenable & IFCAP_WOL) != 0) pmstat |= PCIM_PSTAT_PME | PCIM_PSTAT_PMEENABLE; - pci_write_config(sc->alc_dev, pmc + PCIR_POWER_STATUS, pmstat, 2); + pci_write_config(sc->alc_dev, + sc->alc_pmcap + PCIR_POWER_STATUS, pmstat, 2); } static int @@ -1743,20 +1978,19 @@ alc_resume(device_t dev) { struct alc_softc *sc; struct ifnet *ifp; - int pmc; uint16_t pmstat; sc = device_get_softc(dev); ALC_LOCK(sc); - if (pci_find_extcap(sc->alc_dev, PCIY_PMG, &pmc) == 0) { + if ((sc->alc_flags & ALC_FLAG_PM) != 0) { /* Disable PME and clear PME status. */ pmstat = pci_read_config(sc->alc_dev, - pmc + PCIR_POWER_STATUS, 2); + sc->alc_pmcap + PCIR_POWER_STATUS, 2); if ((pmstat & PCIM_PSTAT_PMEENABLE) != 0) { pmstat &= ~PCIM_PSTAT_PMEENABLE; pci_write_config(sc->alc_dev, - pmc + PCIR_POWER_STATUS, pmstat, 2); + sc->alc_pmcap + PCIR_POWER_STATUS, pmstat, 2); } } /* Reset PHY. */ @@ -1794,7 +2028,7 @@ alc_encap(struct alc_softc *sc, struct mbuf **m_head) ip_off = poff = 0; if ((m->m_pkthdr.csum_flags & (ALC_CSUM_FEATURES | CSUM_TSO)) != 0) { /* - * AR8131/AR8132 requires offset of TCP/UDP header in its + * AR813x/AR815x requires offset of TCP/UDP header in its * Tx descriptor to perform Tx checksum offloading. TSO * also requires TCP header offset and modification of * IP/TCP header. This kind of operation takes many CPU @@ -1866,6 +2100,8 @@ alc_encap(struct alc_softc *sc, struct mbuf **m_head) * Reset IP checksum and recompute TCP pseudo * checksum as NDIS specification said. */ + ip = (struct ip *)(mtod(m, char *) + ip_off); + tcp = (struct tcphdr *)(mtod(m, char *) + poff); ip->ip_sum = 0; tcp->th_sum = in_pseudo(ip->ip_src.s_addr, ip->ip_dst.s_addr, htons(IPPROTO_TCP)); @@ -1921,28 +2157,7 @@ alc_encap(struct alc_softc *sc, struct mbuf **m_head) vtag = (vtag << TD_VLAN_SHIFT) & TD_VLAN_MASK; cflags |= TD_INS_VLAN_TAG; } - /* Configure Tx checksum offload. */ - if ((m->m_pkthdr.csum_flags & ALC_CSUM_FEATURES) != 0) { -#ifdef ALC_USE_CUSTOM_CSUM - cflags |= TD_CUSTOM_CSUM; - /* Set checksum start offset. */ - cflags |= ((poff >> 1) << TD_PLOAD_OFFSET_SHIFT) & - TD_PLOAD_OFFSET_MASK; - /* Set checksum insertion position of TCP/UDP. */ - cflags |= (((poff + m->m_pkthdr.csum_data) >> 1) << - TD_CUSTOM_CSUM_OFFSET_SHIFT) & TD_CUSTOM_CSUM_OFFSET_MASK; -#else - if ((m->m_pkthdr.csum_flags & CSUM_IP) != 0) - cflags |= TD_IPCSUM; - if ((m->m_pkthdr.csum_flags & CSUM_TCP) != 0) - cflags |= TD_TCPCSUM; - if ((m->m_pkthdr.csum_flags & CSUM_UDP) != 0) - cflags |= TD_UDPCSUM; - /* Set TCP/UDP header offset. */ - cflags |= (poff << TD_L4HDR_OFFSET_SHIFT) & - TD_L4HDR_OFFSET_MASK; -#endif - } else if ((m->m_pkthdr.csum_flags & CSUM_TSO) != 0) { + if ((m->m_pkthdr.csum_flags & CSUM_TSO) != 0) { /* Request TSO and set MSS. */ cflags |= TD_TSO | TD_TSO_DESCV1; cflags |= ((uint32_t)m->m_pkthdr.tso_segsz << TD_MSS_SHIFT) & @@ -1951,7 +2166,7 @@ alc_encap(struct alc_softc *sc, struct mbuf **m_head) cflags |= (poff << TD_TCPHDR_OFFSET_SHIFT) & TD_TCPHDR_OFFSET_MASK; /* - * AR8131/AR8132 requires the first buffer should + * AR813x/AR815x requires the first buffer should * only hold IP/TCP header data. Payload should * be handled in other descriptors. */ @@ -1974,6 +2189,27 @@ alc_encap(struct alc_softc *sc, struct mbuf **m_head) } /* Handle remaining fragments. */ idx = 1; + } else if ((m->m_pkthdr.csum_flags & ALC_CSUM_FEATURES) != 0) { + /* Configure Tx checksum offload. */ +#ifdef ALC_USE_CUSTOM_CSUM + cflags |= TD_CUSTOM_CSUM; + /* Set checksum start offset. */ + cflags |= ((poff >> 1) << TD_PLOAD_OFFSET_SHIFT) & + TD_PLOAD_OFFSET_MASK; + /* Set checksum insertion position of TCP/UDP. */ + cflags |= (((poff + m->m_pkthdr.csum_data) >> 1) << + TD_CUSTOM_CSUM_OFFSET_SHIFT) & TD_CUSTOM_CSUM_OFFSET_MASK; +#else + if ((m->m_pkthdr.csum_flags & CSUM_IP) != 0) + cflags |= TD_IPCSUM; + if ((m->m_pkthdr.csum_flags & CSUM_TCP) != 0) + cflags |= TD_TCPCSUM; + if ((m->m_pkthdr.csum_flags & CSUM_UDP) != 0) + cflags |= TD_UDPCSUM; + /* Set TCP/UDP header offset. */ + cflags |= (poff << TD_L4HDR_OFFSET_SHIFT) & + TD_L4HDR_OFFSET_MASK; +#endif } for (; idx < nsegs; idx++) { desc = &sc->alc_rdata.alc_tx_ring[prod]; @@ -2111,18 +2347,21 @@ alc_ioctl(struct ifnet *ifp, u_long cmd, caddr_t data) error = 0; switch (cmd) { case SIOCSIFMTU: - if (ifr->ifr_mtu < ETHERMIN || ifr->ifr_mtu > ALC_JUMBO_MTU || + if (ifr->ifr_mtu < ETHERMIN || + ifr->ifr_mtu > (sc->alc_ident->max_framelen - + sizeof(struct ether_vlan_header) - ETHER_CRC_LEN) || ((sc->alc_flags & ALC_FLAG_JUMBO) == 0 && ifr->ifr_mtu > ETHERMTU)) error = EINVAL; else if (ifp->if_mtu != ifr->ifr_mtu) { ALC_LOCK(sc); ifp->if_mtu = ifr->ifr_mtu; - /* AR8131/AR8132 has 13 bits MSS field. */ + /* AR813x/AR815x has 13 bits MSS field. */ if (ifp->if_mtu > ALC_TSO_MTU && (ifp->if_capenable & IFCAP_TSO4) != 0) { ifp->if_capenable &= ~IFCAP_TSO4; ifp->if_hwassist &= ~CSUM_TSO; + VLAN_CAPABILITIES(ifp); } ALC_UNLOCK(sc); } @@ -2168,7 +2407,7 @@ alc_ioctl(struct ifnet *ifp, u_long cmd, caddr_t data) (ifp->if_capabilities & IFCAP_TSO4) != 0) { ifp->if_capenable ^= IFCAP_TSO4; if ((ifp->if_capenable & IFCAP_TSO4) != 0) { - /* AR8131/AR8132 has 13 bits MSS field. */ + /* AR813x/AR815x has 13 bits MSS field. */ if (ifp->if_mtu > ALC_TSO_MTU) { ifp->if_capenable &= ~IFCAP_TSO4; ifp->if_hwassist &= ~CSUM_TSO; @@ -2194,14 +2433,6 @@ alc_ioctl(struct ifnet *ifp, u_long cmd, caddr_t data) if ((mask & IFCAP_VLAN_HWTSO) != 0 && (ifp->if_capabilities & IFCAP_VLAN_HWTSO) != 0) ifp->if_capenable ^= IFCAP_VLAN_HWTSO; - /* - * VLAN hardware tagging is required to do checksum - * offload or TSO on VLAN interface. Checksum offload - * on VLAN interface also requires hardware checksum - * offload of parent interface. - */ - if ((ifp->if_capenable & IFCAP_TXCSUM) == 0) - ifp->if_capenable &= ~IFCAP_VLAN_HWCSUM; if ((ifp->if_capenable & IFCAP_VLAN_HWTAGGING) == 0) ifp->if_capenable &= ~(IFCAP_VLAN_HWTSO | IFCAP_VLAN_HWCSUM); @@ -2228,6 +2459,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->alc_ident->deviceid == DEVICEID_ATHEROS_AR8151 || + sc->alc_ident->deviceid == DEVICEID_ATHEROS_AR8151_V2 || + sc->alc_ident->deviceid == DEVICEID_ATHEROS_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: @@ -2240,12 +2475,10 @@ alc_mac_config(struct alc_softc *sc) } if ((IFM_OPTIONS(mii->mii_media_active) & IFM_FDX) != 0) { reg |= MAC_CFG_FULL_DUPLEX; -#ifdef notyet if ((IFM_OPTIONS(mii->mii_media_active) & IFM_ETH_TXPAUSE) != 0) reg |= MAC_CFG_TX_FC; if ((IFM_OPTIONS(mii->mii_media_active) & IFM_ETH_RXPAUSE) != 0) reg |= MAC_CFG_RX_FC; -#endif } CSR_WRITE_4(sc, ALC_MAC_CFG, reg); } @@ -2729,8 +2962,8 @@ alc_rxeof(struct alc_softc *sc, struct rx_rdesc *rrd) * 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; } @@ -2849,7 +3082,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) @@ -2980,6 +3215,18 @@ alc_init_locked(struct alc_softc *sc) 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 == DEVICEID_ATHEROS_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); @@ -2987,14 +3234,11 @@ alc_init_locked(struct alc_softc *sc) 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) @@ -3006,10 +3250,10 @@ alc_init_locked(struct alc_softc *sc) */ CSR_WRITE_4(sc, ALC_INTR_RETRIG_TIMER, ALC_USECS(0)); /* Configure CMB. */ - CSR_WRITE_4(sc, ALC_CMB_TD_THRESH, 4); - if ((sc->alc_flags & ALC_FLAG_CMB_BUG) == 0) + if ((sc->alc_flags & ALC_FLAG_CMB_BUG) == 0) { + CSR_WRITE_4(sc, ALC_CMB_TD_THRESH, 4); CSR_WRITE_4(sc, ALC_CMB_TX_TIMER, ALC_USECS(5000)); - else + } else CSR_WRITE_4(sc, ALC_CMB_TX_TIMER, ALC_USECS(0)); /* * Hardware can be configured to issue SMB interrupt based @@ -3035,7 +3279,7 @@ alc_init_locked(struct alc_softc *sc) * 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); @@ -3062,11 +3306,14 @@ alc_init_locked(struct alc_softc *sc) * 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 == DEVICEID_ATHEROS_AR8152_B || + sc->alc_ident->deviceid == DEVICEID_ATHEROS_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); @@ -3083,14 +3330,23 @@ alc_init_locked(struct alc_softc *sc) * 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 == DEVICEID_ATHEROS_AR8131 || + sc->alc_ident->deviceid == DEVICEID_ATHEROS_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 == DEVICEID_ATHEROS_AR8152_B || + sc->alc_ident->deviceid == DEVICEID_ATHEROS_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); @@ -3101,15 +3357,9 @@ alc_init_locked(struct alc_softc *sc) 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; @@ -3135,7 +3385,7 @@ alc_init_locked(struct alc_softc *sc) * - 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 @@ -3145,6 +3395,10 @@ alc_init_locked(struct alc_softc *sc) 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 == DEVICEID_ATHEROS_AR8151 || + sc->alc_ident->deviceid == DEVICEID_ATHEROS_AR8151_V2 || + sc->alc_ident->deviceid == DEVICEID_ATHEROS_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 @@ -3246,7 +3500,7 @@ alc_stop_mac(struct alc_softc *sc) /* 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--) { @@ -3466,7 +3720,7 @@ alc_rxfilter(struct alc_softc *sc) TAILQ_FOREACH(ifma, &sc->alc_ifp->if_multiaddrs, ifma_link) { if (ifma->ifma_addr->sa_family != AF_LINK) continue; - crc = ether_crc32_le(LLADDR((struct sockaddr_dl *) + crc = ether_crc32_be(LLADDR((struct sockaddr_dl *) ifma->ifma_addr), ETHER_ADDR_LEN); mchash[crc >> 31] |= 1 << ((crc >> 26) & 0x1f); } diff --git a/src/add-ons/kernel/drivers/network/atheros813x/dev/alc/if_alcreg.h b/src/add-ons/kernel/drivers/network/atheros813x/dev/alc/if_alcreg.h index 21191ab298..f22879835e 100644 --- a/src/add-ons/kernel/drivers/network/atheros813x/dev/alc/if_alcreg.h +++ b/src/add-ons/kernel/drivers/network/atheros813x/dev/alc/if_alcreg.h @@ -36,10 +36,17 @@ #define VENDORID_ATHEROS 0x1969 /* - * Atheros AR8131/AR8132 device ID + * Atheros AR813x/AR815x device ID */ #define DEVICEID_ATHEROS_AR8131 0x1063 /* L1C */ #define DEVICEID_ATHEROS_AR8132 0x1062 /* L2C */ +#define DEVICEID_ATHEROS_AR8151 0x1073 /* L1D V1.0 */ +#define DEVICEID_ATHEROS_AR8151_V2 0x1083 /* L1D V2.0 */ +#define DEVICEID_ATHEROS_AR8152_B 0x2060 /* L2C V1.1 */ +#define DEVICEID_ATHEROS_AR8152_B2 0x2062 /* L2C V2.0 */ + +#define ATHEROS_AR8152_B_V10 0xC0 +#define ATHEROS_AR8152_B_V11 0xC1 /* 0x0000 - 0x02FF : PCIe configuration space */ @@ -64,6 +71,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 @@ -97,6 +110,8 @@ #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_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 @@ -104,10 +119,19 @@ #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 12 +#define PM_CFG_PM_REQ_TIMER_DEFAULT 1 + +#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 @@ -122,7 +146,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) @@ -144,7 +168,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 @@ -220,6 +244,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 @@ -249,6 +275,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 @@ -691,7 +719,7 @@ #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 diff --git a/src/add-ons/kernel/drivers/network/atheros813x/dev/alc/if_alcvar.h b/src/add-ons/kernel/drivers/network/atheros813x/dev/alc/if_alcvar.h index b8f839dbf5..7280ca363e 100644 --- a/src/add-ons/kernel/drivers/network/atheros813x/dev/alc/if_alcvar.h +++ b/src/add-ons/kernel/drivers/network/atheros813x/dev/alc/if_alcvar.h @@ -68,13 +68,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 @@ -192,6 +187,13 @@ struct alc_hw_stats { 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. */ @@ -204,6 +206,7 @@ struct alc_softc { struct resource *alc_irq[ALC_MSI_MESSAGES]; struct resource_spec *alc_irq_spec; void *alc_intrhand[ALC_MSI_MESSAGES]; + struct alc_ident *alc_ident; int alc_rev; int alc_chip_rev; int alc_phyaddr; @@ -211,16 +214,22 @@ struct alc_softc { uint32_t alc_dma_rd_burst; uint32_t alc_dma_wr_burst; uint32_t alc_rcb; + int alc_expcap; + int alc_pmcap; 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 diff --git a/src/add-ons/kernel/drivers/network/attansic_l2/dev/ae/if_ae.c b/src/add-ons/kernel/drivers/network/attansic_l2/dev/ae/if_ae.c index e0e688811e..da5d01094f 100644 --- a/src/add-ons/kernel/drivers/network/attansic_l2/dev/ae/if_ae.c +++ b/src/add-ons/kernel/drivers/network/attansic_l2/dev/ae/if_ae.c @@ -28,7 +28,7 @@ */ #include -__FBSDID("$FreeBSD: src/sys/dev/ae/if_ae.c,v 1.1.2.1.2.1 2008/11/25 02:59:29 kensmith Exp $"); +__FBSDID("$FreeBSD$"); #include #include @@ -105,7 +105,7 @@ static void ae_phy_init(ae_softc_t *sc); static int ae_reset(ae_softc_t *sc); static void ae_init(void *arg); static int ae_init_locked(ae_softc_t *sc); -static unsigned int ae_detach(device_t dev); +static int ae_detach(device_t dev); static int ae_miibus_readreg(device_t dev, int phy, int reg); static int ae_miibus_writereg(device_t dev, int phy, int reg, int val); static void ae_miibus_statchg(device_t dev); @@ -360,13 +360,11 @@ ae_attach(device_t dev) if (error != 0) goto fail; - /* Set default PHY address. */ - sc->phyaddr = AE_PHYADDR_DEFAULT; - ifp = sc->ifp = if_alloc(IFT_ETHER); if (ifp == NULL) { device_printf(dev, "could not allocate ifnet structure.\n"); error = ENXIO; + goto fail; } ifp->if_softc = sc; @@ -377,20 +375,23 @@ ae_attach(device_t dev) ifp->if_init = ae_init; ifp->if_capabilities = IFCAP_VLAN_MTU | IFCAP_VLAN_HWTAGGING; ifp->if_hwassist = 0; - ifp->if_snd.ifq_drv_maxlen = IFQ_MAXLEN; + ifp->if_snd.ifq_drv_maxlen = ifqmaxlen; IFQ_SET_MAXLEN(&ifp->if_snd, ifp->if_snd.ifq_drv_maxlen); IFQ_SET_READY(&ifp->if_snd); - if (pci_find_extcap(dev, PCIY_PMG, &pmc) == 0) + if (pci_find_extcap(dev, PCIY_PMG, &pmc) == 0) { + ifp->if_capabilities |= IFCAP_WOL_MAGIC; sc->flags |= AE_FLAG_PMG; + } ifp->if_capenable = ifp->if_capabilities; /* * Configure and attach MII bus. */ - error = mii_phy_probe(dev, &sc->miibus, ae_mediachange, - ae_mediastatus); + error = mii_attach(dev, &sc->miibus, ifp, ae_mediachange, + ae_mediastatus, BMSR_DEFCAPMASK, AE_PHYADDR_DEFAULT, + MII_OFFSET_ANY, 0); if (error != 0) { - device_printf(dev, "no PHY found.\n"); + device_printf(dev, "attaching PHYs failed\n"); goto fail; } @@ -562,6 +563,8 @@ ae_init_locked(ae_softc_t *sc) AE_LOCK_ASSERT(sc); ifp = sc->ifp; + if ((ifp->if_drv_flags & IFF_DRV_RUNNING) != 0) + return (0); mii = device_get_softc(sc->miibus); ae_stop(sc); @@ -744,7 +747,7 @@ ae_init_locked(ae_softc_t *sc) return (0); } -static unsigned int +static int ae_detach(device_t dev) { struct ae_softc *sc; @@ -808,9 +811,6 @@ ae_miibus_readreg(device_t dev, int phy, int reg) * Locking is done in upper layers. */ - if (phy != sc->phyaddr) - return (0); - val = ((reg << AE_MDIO_REGADDR_SHIFT) & AE_MDIO_REGADDR_MASK) | AE_MDIO_START | AE_MDIO_READ | AE_MDIO_SUP_PREAMBLE | ((AE_MDIO_CLK_25_4 << AE_MDIO_CLK_SHIFT) & AE_MDIO_CLK_MASK); @@ -846,9 +846,6 @@ ae_miibus_writereg(device_t dev, int phy, int reg, int val) * Locking is done in upper layers. */ - if (phy != sc->phyaddr) - return (0); - aereg = ((reg << AE_MDIO_REGADDR_SHIFT) & AE_MDIO_REGADDR_MASK) | AE_MDIO_START | AE_MDIO_SUP_PREAMBLE | ((AE_MDIO_CLK_25_4 << AE_MDIO_CLK_SHIFT) & AE_MDIO_CLK_MASK) | @@ -1045,7 +1042,7 @@ ae_get_reg_eaddr(ae_softc_t *sc, uint32_t *eaddr) if (AE_CHECK_EADDR_VALID(eaddr) != 0) { if (bootverbose) device_printf(sc->dev, - "Ethetnet address registers are invalid.\n"); + "Ethernet address registers are invalid.\n"); return (EINVAL); } return (0); @@ -1107,12 +1104,9 @@ ae_dmamap_cb(void *arg, bus_dma_segment_t *segs, int nsegs, int error) static int ae_alloc_rings(ae_softc_t *sc) { - bus_dma_tag_t bustag; bus_addr_t busaddr; int error; - bustag = bus_get_dma_tag(sc->dev); - /* * Create parent DMA tag. */ @@ -1336,6 +1330,7 @@ ae_pm_init(ae_softc_t *sc) struct ifnet *ifp; uint32_t val; uint16_t pmstat; + struct mii_data *mii; int pmc; AE_LOCK_ASSERT(sc); @@ -1347,7 +1342,40 @@ ae_pm_init(ae_softc_t *sc) return; } - ae_powersave_enable(sc); + /* + * Configure WOL if enabled. + */ + if ((ifp->if_capenable & IFCAP_WOL) != 0) { + mii = device_get_softc(sc->miibus); + mii_pollstat(mii); + if ((mii->mii_media_status & IFM_AVALID) != 0 && + (mii->mii_media_status & IFM_ACTIVE) != 0) { + AE_WRITE_4(sc, AE_WOL_REG, AE_WOL_MAGIC | \ + AE_WOL_MAGIC_PME); + + /* + * Configure MAC. + */ + val = AE_MAC_RX_EN | AE_MAC_CLK_PHY | \ + AE_MAC_TX_CRC_EN | AE_MAC_TX_AUTOPAD | \ + ((AE_HALFBUF_DEFAULT << AE_HALFBUF_SHIFT) & \ + AE_HALFBUF_MASK) | \ + ((AE_MAC_PREAMBLE_DEFAULT << \ + AE_MAC_PREAMBLE_SHIFT) & AE_MAC_PREAMBLE_MASK) | \ + AE_MAC_BCAST_EN | AE_MAC_MCAST_EN; + if ((IFM_OPTIONS(mii->mii_media_active) & \ + IFM_FDX) != 0) + val |= AE_MAC_FULL_DUPLEX; + AE_WRITE_4(sc, AE_MAC_REG, val); + + } else { /* No link. */ + AE_WRITE_4(sc, AE_WOL_REG, AE_WOL_LNKCHG | \ + AE_WOL_LNKCHG_PME); + AE_WRITE_4(sc, AE_MAC_REG, 0); + } + } else { + ae_powersave_enable(sc); + } /* * PCIE hacks. Magic numbers. @@ -1365,6 +1393,8 @@ ae_pm_init(ae_softc_t *sc) pci_find_extcap(sc->dev, PCIY_PMG, &pmc); pmstat = pci_read_config(sc->dev, pmc + PCIR_POWER_STATUS, 2); pmstat &= ~(PCIM_PSTAT_PME | PCIM_PSTAT_PMEENABLE); + if ((ifp->if_capenable & IFCAP_WOL) != 0) + pmstat |= PCIM_PSTAT_PME | PCIM_PSTAT_PMEENABLE; pci_write_config(sc->dev, pmc + PCIR_POWER_STATUS, pmstat, 2); } @@ -1754,7 +1784,10 @@ ae_int_task(void *arg, int pending) if ((ifp->if_drv_flags & IFF_DRV_RUNNING) != 0) { if ((val & (AE_ISR_DMAR_TIMEOUT | AE_ISR_DMAW_TIMEOUT | AE_ISR_PHY_LINKDOWN)) != 0) { + ifp->if_drv_flags &= ~IFF_DRV_RUNNING; ae_init_locked(sc); + AE_UNLOCK(sc); + return; } if ((val & AE_ISR_TX_EVENT) != 0) ae_tx_intr(sc); @@ -1869,8 +1902,8 @@ ae_rxeof(ae_softc_t *sc, ae_rxd_t *rxd) if_printf(ifp, "Rx interrupt occuried.\n"); #endif size = le16toh(rxd->len) - ETHER_CRC_LEN; - if (size < 0) { - if_printf(ifp, "Negative length packet received."); + if (size < (ETHER_MIN_LEN - ETHER_CRC_LEN - ETHER_VLAN_ENCAP_LEN)) { + if_printf(ifp, "Runt frame received."); return (EIO); } @@ -1965,6 +1998,7 @@ ae_watchdog(ae_softc_t *sc) if_printf(ifp, "watchdog timeout - resetting.\n"); ifp->if_oerrors++; + ifp->if_drv_flags &= ~IFF_DRV_RUNNING; ae_init_locked(sc); if (!IFQ_DRV_IS_EMPTY(&ifp->if_snd)) taskqueue_enqueue(sc->tq, &sc->tx_task); @@ -2042,15 +2076,15 @@ ae_rxfilter(ae_softc_t *sc) * Load multicast tables. */ bzero(mchash, sizeof(mchash)); - IF_ADDR_LOCK(ifp); + if_maddr_rlock(ifp); TAILQ_FOREACH(ifma, &ifp->if_multiaddrs, ifma_link) { if (ifma->ifma_addr->sa_family != AF_LINK) continue; - crc = ether_crc32_le(LLADDR((struct sockaddr_dl *) + crc = ether_crc32_be(LLADDR((struct sockaddr_dl *) ifma->ifma_addr), ETHER_ADDR_LEN); mchash[crc >> 31] |= 1 << ((crc >> 26) & 0x1f); } - IF_ADDR_UNLOCK(ifp); + if_maddr_runlock(ifp); AE_WRITE_4(sc, AE_REG_MHT0, mchash[0]); AE_WRITE_4(sc, AE_REG_MHT1, mchash[1]); AE_WRITE_4(sc, AE_MAC_REG, rxcfg); @@ -2075,8 +2109,10 @@ ae_ioctl(struct ifnet *ifp, u_long cmd, caddr_t data) else if (ifp->if_mtu != ifr->ifr_mtu) { AE_LOCK(sc); ifp->if_mtu = ifr->ifr_mtu; - if ((ifp->if_drv_flags & IFF_DRV_RUNNING) != 0) + if ((ifp->if_drv_flags & IFF_DRV_RUNNING) != 0) { + ifp->if_drv_flags &= ~IFF_DRV_RUNNING; ae_init_locked(sc); + } AE_UNLOCK(sc); } break; diff --git a/src/add-ons/kernel/drivers/network/attansic_l2/dev/ae/if_aereg.h b/src/add-ons/kernel/drivers/network/attansic_l2/dev/ae/if_aereg.h index 19481b3401..cc09e0b828 100644 --- a/src/add-ons/kernel/drivers/network/attansic_l2/dev/ae/if_aereg.h +++ b/src/add-ons/kernel/drivers/network/attansic_l2/dev/ae/if_aereg.h @@ -22,7 +22,7 @@ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * - * $FreeBSD: src/sys/dev/ae/if_aereg.h,v 1.1.2.1.2.1 2008/11/25 02:59:29 kensmith Exp $ + * $FreeBSD$ */ /* diff --git a/src/add-ons/kernel/drivers/network/attansic_l2/dev/ae/if_aevar.h b/src/add-ons/kernel/drivers/network/attansic_l2/dev/ae/if_aevar.h index b63253fe83..862340144d 100644 --- a/src/add-ons/kernel/drivers/network/attansic_l2/dev/ae/if_aevar.h +++ b/src/add-ons/kernel/drivers/network/attansic_l2/dev/ae/if_aevar.h @@ -22,7 +22,7 @@ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * - * $FreeBSD: src/sys/dev/ae/if_aevar.h,v 1.1.2.1.2.1 2008/11/25 02:59:29 kensmith Exp $ + * $FreeBSD$ */ #ifndef IF_AEVAR_H @@ -111,7 +111,6 @@ typedef struct ae_softc { struct mtx mtx; - int phyaddr; uint8_t eaddr[ETHER_ADDR_LEN]; uint8_t flags; int if_flags;