Module Name: src Committed By: snj Date: Fri Feb 26 22:08:17 UTC 2016
Modified Files: src/sys/dev/mii [netbsd-7]: igphy.c ukphy.c src/sys/dev/pci [netbsd-7]: if_wm.c if_wmreg.h if_wmvar.h Log Message: Pull up following revision(s) (requested by msaitoh in ticket #1102): sys/dev/mii/igphy.c: 1.25 sys/dev/mii/ukphy.c: 1.48 sys/dev/pci/if_wm.c: revisions 1.308, 1.318, 1.320, 1.324-1.332, 1.334, 1.336, 1.343-1.344, 1.347-1.348, 1.350, 1.376-1.382, 1.386-1.389 via patch sys/dev/pci/if_wmreg.h: revisions 1.68-1.70, 1.73-1.77, 1.79-1.80, 1.82, 1.86-1.88 via patch sys/dev/pci/if_wmvar.h: revisions 1.22-1.23, 1.25-1.30 via patch Sync wm(4) as of if_wm.c rev 1.389 except MSI/MSI-X, multiqueue and NET_MPSAFE: - Add C2000 KX and 2.5G support. - Set ICH9 and ICH10's PBA size to 14K if the RX buffer size is more than 4096. Almost the same as other OSes. - For 82576 and newer devices, the PBA register is deleted. Don't write PBA for those chips. Also change the calculation of RX packet buffer size in new way. - Fix a lot of bugs to make 82575 and newer SERDES based systems work. - Print NVM image version and option ROM version. - Add workaround for I210 Errata 25 and I211 Errata 10 (PLL bug). This workaround is required if the NVM image version < 3.25. - Fix a bug that wm_detach() didn't unmap the FHASH's area. Now "drvct -d wm0" -> "drvctl -r pci0" works on ICH* and PCH*. - Add workaround for 82574 Errata 25 and 82583 Errata 12 "Dropped RX packets" and for 82573 (unknown). Set GCR_L1_ACT_WITHOUT_L0S_RX bit. The NVM Image version 2.1.4 and newer have this workaround. - Check PHY type correctly. This change is required to use igphy(4) device correctly. - Disable LPLU (Low Power Link Up) on D0 state on 82574, 82583 and ICH* too. - Call wm_get_hw_control() correctly. This change fixes a bug that some AMT based systems doesn't linkup at 1000BaseT. The problem was observed on HP Compaq dc7700. A lot of fixes have been done for wm(4) and igphy(4), so now PR#44893 should be fixed. - Call wm_get_wakeup(sc) before checking WM_F_HAS_AMT. It's required to check the existence of AMT correctly. - Fix a problem that wm_gate_hw_phy_config_ich8lan() isn't called in wm_reset() on PCH2. - Clear WMREG_WUC in wm_reset() if the chip >= 82544. This might fix the behavior on suspend/resume. - Fix logic of wm_check_reset_block() on ICH* and PCH*. This change might fix a problem that PHY's read/write functions can't get semaphore. - On ICH8, call wm_gig_downshift_workaround_ich8lan() when link changed down. - Drop PHY_CTRL_GBE_DIS explicitly in wm_lplu_d0_disable() in case BIOS sets this bit. - Fix two bugs in wm_kmrn_lock_loss_workaround_ich8lan(). Now the function checks the status correctly but it causes linkdown up to 10 times, so it's disabled for the time being. - PR/50527: David Binderman: Fix impossible code. Odd offsets need special treatment. - Fix RAL table's size of PCH2 and PCH_LPT. - PCH_LPT (and newer device) is required to check FWSM_WLOCK_MAC bit to determine the range of the RAL. - Use sc->sc_itr instead of hard-coded number. - Rename wm_tbi_check_link() to wm_tbi_tick() because this function acts as mii_tick(). - ACK Accelerate Disable in the RFCTL register is not bit 13 but 12. No binary change because this definition has not used yet. - Add ACK data Disable bit's definition (not used yet). - PHY_CTRL_GBE_DIS is not bit 4 but bit 6. This change has no any effect by default because WM_WOL is not defined yet and m_kmrn_lock_loss_workaround_ich8lan() is broken. - Fix wm_check_mng_mode_ich8lan(). This function is used only when WM_WOL is defined and it's disabled by default. - Rename wm_check_reset_block() to wm_phy_resetisblocked() and make it returns bool. No functional change. - Reorder function definitions and macro definitions. No functional change. - Fix comment. Add comment. Update comment. - KNF. To generate a diff of this commit: cvs rdiff -u -r1.23 -r1.23.2.1 src/sys/dev/mii/igphy.c cvs rdiff -u -r1.46 -r1.46.8.1 src/sys/dev/mii/ukphy.c cvs rdiff -u -r1.289.2.8 -r1.289.2.9 src/sys/dev/pci/if_wm.c cvs rdiff -u -r1.60.2.4 -r1.60.2.5 src/sys/dev/pci/if_wmreg.h cvs rdiff -u -r1.19.2.3 -r1.19.2.4 src/sys/dev/pci/if_wmvar.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/mii/igphy.c diff -u src/sys/dev/mii/igphy.c:1.23 src/sys/dev/mii/igphy.c:1.23.2.1 --- src/sys/dev/mii/igphy.c:1.23 Mon Jun 16 16:48:16 2014 +++ src/sys/dev/mii/igphy.c Fri Feb 26 22:08:17 2016 @@ -1,4 +1,4 @@ -/* $NetBSD: igphy.c,v 1.23 2014/06/16 16:48:16 msaitoh Exp $ */ +/* $NetBSD: igphy.c,v 1.23.2.1 2016/02/26 22:08:17 snj Exp $ */ /* * The Intel copyright applies to the analog register setup, and the @@ -70,7 +70,7 @@ */ #include <sys/cdefs.h> -__KERNEL_RCSID(0, "$NetBSD: igphy.c,v 1.23 2014/06/16 16:48:16 msaitoh Exp $"); +__KERNEL_RCSID(0, "$NetBSD: igphy.c,v 1.23.2.1 2016/02/26 22:08:17 snj Exp $"); #include "opt_mii.h" @@ -154,6 +154,9 @@ igphyattach(device_t parent, device_t se sc->mii_dev = self; sc->mii_inst = mii->mii_instance; sc->mii_phy = ma->mii_phyno; + sc->mii_mpd_oui = MII_OUI(ma->mii_id1, ma->mii_id2); + sc->mii_mpd_model = MII_MODEL(ma->mii_id2); + sc->mii_mpd_rev = MII_REV(ma->mii_id2); sc->mii_funcs = &igphy_funcs; sc->mii_pdata = mii; sc->mii_flags = ma->mii_flags; Index: src/sys/dev/mii/ukphy.c diff -u src/sys/dev/mii/ukphy.c:1.46 src/sys/dev/mii/ukphy.c:1.46.8.1 --- src/sys/dev/mii/ukphy.c:1.46 Tue Jun 11 16:18:48 2013 +++ src/sys/dev/mii/ukphy.c Fri Feb 26 22:08:17 2016 @@ -1,4 +1,4 @@ -/* $NetBSD: ukphy.c,v 1.46 2013/06/11 16:18:48 msaitoh Exp $ */ +/* $NetBSD: ukphy.c,v 1.46.8.1 2016/02/26 22:08:17 snj Exp $ */ /*- * Copyright (c) 1998, 1999, 2000 The NetBSD Foundation, Inc. @@ -59,7 +59,7 @@ */ #include <sys/cdefs.h> -__KERNEL_RCSID(0, "$NetBSD: ukphy.c,v 1.46 2013/06/11 16:18:48 msaitoh Exp $"); +__KERNEL_RCSID(0, "$NetBSD: ukphy.c,v 1.46.8.1 2016/02/26 22:08:17 snj Exp $"); #include "opt_mii.h" @@ -121,6 +121,9 @@ ukphyattach(device_t parent, device_t se sc->mii_dev = self; sc->mii_inst = mii->mii_instance; sc->mii_phy = ma->mii_phyno; + sc->mii_mpd_oui = MII_OUI(ma->mii_id1, ma->mii_id2); + sc->mii_mpd_model = MII_MODEL(ma->mii_id2); + sc->mii_mpd_rev = MII_REV(ma->mii_id2); sc->mii_funcs = &ukphy_funcs; sc->mii_pdata = mii; sc->mii_flags = ma->mii_flags; Index: src/sys/dev/pci/if_wm.c diff -u src/sys/dev/pci/if_wm.c:1.289.2.8 src/sys/dev/pci/if_wm.c:1.289.2.9 --- src/sys/dev/pci/if_wm.c:1.289.2.8 Wed Jun 10 16:43:51 2015 +++ src/sys/dev/pci/if_wm.c Fri Feb 26 22:08:17 2016 @@ -1,4 +1,4 @@ -/* $NetBSD: if_wm.c,v 1.289.2.8 2015/06/10 16:43:51 snj Exp $ */ +/* $NetBSD: if_wm.c,v 1.289.2.9 2016/02/26 22:08:17 snj Exp $ */ /* * Copyright (c) 2001, 2002, 2003, 2004 Wasabi Systems, Inc. @@ -75,13 +75,16 @@ * - Check XXX'ed comments * - EEE (Energy Efficiency Ethernet) * - MSI/MSI-X + * - Multi queue + * - Image Unique ID + * - Disable D0 LPLU on 8257[12356], 82580 and I350. * - Virtual Function * - Set LED correctly (based on contents in EEPROM) * - Rework how parameters are loaded from the EEPROM. */ #include <sys/cdefs.h> -__KERNEL_RCSID(0, "$NetBSD: if_wm.c,v 1.289.2.8 2015/06/10 16:43:51 snj Exp $"); +__KERNEL_RCSID(0, "$NetBSD: if_wm.c,v 1.289.2.9 2016/02/26 22:08:17 snj Exp $"); #include <sys/param.h> #include <sys/systm.h> @@ -249,6 +252,10 @@ static uint16_t swfwphysem[] = { SWFW_PHY3_SM }; +static const uint32_t wm_82580_rxpbs_table[] = { + 36, 72, 144, 1, 2, 4, 8, 16, 35, 70, 140 +}; + /* * Software state per device. */ @@ -262,6 +269,7 @@ struct wm_softc { bus_size_t sc_ios; /* I/O space size */ bus_space_tag_t sc_flasht; /* flash registers space tag */ bus_space_handle_t sc_flashh; /* flash registers space handle */ + bus_size_t sc_flashs; /* flash registers space size */ bus_dma_tag_t sc_dmat; /* bus DMA tag */ struct ethercom sc_ethercom; /* ethernet common data */ @@ -291,8 +299,11 @@ struct wm_softc { callout_t sc_tick_ch; /* tick callout */ bool sc_stopping; + int sc_nvm_ver_major; + int sc_nvm_ver_minor; + int sc_nvm_ver_build; int sc_nvm_addrbits; /* NVM address bits */ - unsigned int sc_nvm_wordsize; /* NVM word size */ + unsigned int sc_nvm_wordsize; /* NVM word size */ int sc_ich8_flash_base; int sc_ich8_flash_bank_size; int sc_nvm_k1_enabled; @@ -334,7 +345,7 @@ struct wm_softc { struct evcnt sc_ev_txtsopain; /* painful header manip. for TSO */ struct evcnt sc_ev_txseg[WM_NTXSEGS]; /* Tx packets w/ N segments */ - struct evcnt sc_ev_txdrop; /* Tx packets dropped (too many segs) */ + struct evcnt sc_ev_txdrop; /* Tx packets dropped(too many segs) */ struct evcnt sc_ev_tu; /* Tx underrun */ @@ -384,8 +395,8 @@ struct wm_softc { uint32_t sc_pba; /* prototype PBA register */ int sc_tbi_linkup; /* TBI link status */ - int sc_tbi_anegticks; /* autonegotiation ticks */ - int sc_tbi_ticks; /* tbi ticks */ + int sc_tbi_serdes_anegticks; /* autonegotiation ticks */ + int sc_tbi_serdes_ticks; /* tbi ticks */ int sc_mchash_type; /* multicast filter offset */ @@ -518,7 +529,7 @@ do { \ __rxd->wrx_status = 0; \ __rxd->wrx_errors = 0; \ __rxd->wrx_special = 0; \ - WM_CDRXSYNC((sc), (x), BUS_DMASYNC_PREREAD|BUS_DMASYNC_PREWRITE); \ + WM_CDRXSYNC((sc), (x), BUS_DMASYNC_PREREAD | BUS_DMASYNC_PREWRITE); \ \ CSR_WRITE((sc), (sc)->sc_rdt_reg, (x)); \ } while (/*CONSTCOND*/0) @@ -562,6 +573,7 @@ static void wm_get_auto_rd_done(struct w static void wm_lan_init_done(struct wm_softc *); static void wm_get_cfg_done(struct wm_softc *); static void wm_initialize_hardware_bits(struct wm_softc *); +static uint32_t wm_rxpbs_adjust_82580(uint32_t); static void wm_reset(struct wm_softc *); static int wm_add_rxbuf(struct wm_softc *, int); static void wm_rxdrain(struct wm_softc *); @@ -586,6 +598,7 @@ static void wm_txintr(struct wm_softc *) static void wm_rxintr(struct wm_softc *); static void wm_linkintr_gmii(struct wm_softc *, uint32_t); static void wm_linkintr_tbi(struct wm_softc *, uint32_t); +static void wm_linkintr_serdes(struct wm_softc *, uint32_t); static void wm_linkintr(struct wm_softc *, uint32_t); static int wm_intr(void *); @@ -593,12 +606,14 @@ static int wm_intr(void *); * Media related. * GMII, SGMII, TBI, SERDES and SFP. */ +/* Common */ +static void wm_tbi_serdes_set_linkled(struct wm_softc *); /* GMII related */ static void wm_gmii_reset(struct wm_softc *); static int wm_get_phy_id_82575(struct wm_softc *); static void wm_gmii_mediainit(struct wm_softc *, pci_product_id_t); -static void wm_gmii_mediastatus(struct ifnet *, struct ifmediareq *); static int wm_gmii_mediachange(struct ifnet *); +static void wm_gmii_mediastatus(struct ifnet *, struct ifmediareq *); static void wm_i82543_mii_sendbits(struct wm_softc *, uint32_t, int); static uint32_t wm_i82543_mii_recvbits(struct wm_softc *); static int wm_gmii_i82543_readreg(device_t, int, int); @@ -614,6 +629,8 @@ static int wm_gmii_hv_readreg(device_t, static void wm_gmii_hv_writereg(device_t, int, int, int); static int wm_gmii_82580_readreg(device_t, int, int); static void wm_gmii_82580_writereg(device_t, int, int, int); +static int wm_gmii_gs40g_readreg(device_t, int, int); +static void wm_gmii_gs40g_writereg(device_t, int, int, int); static void wm_gmii_statchg(struct ifnet *); static int wm_kmrn_readreg(struct wm_softc *, int); static void wm_kmrn_writereg(struct wm_softc *, int, int); @@ -622,12 +639,16 @@ static bool wm_sgmii_uses_mdio(struct wm static int wm_sgmii_readreg(device_t, int, int); static void wm_sgmii_writereg(device_t, int, int, int); /* TBI related */ -static int wm_check_for_link(struct wm_softc *); static void wm_tbi_mediainit(struct wm_softc *); -static void wm_tbi_mediastatus(struct ifnet *, struct ifmediareq *); static int wm_tbi_mediachange(struct ifnet *); -static void wm_tbi_set_linkled(struct wm_softc *); -static void wm_tbi_check_link(struct wm_softc *); +static void wm_tbi_mediastatus(struct ifnet *, struct ifmediareq *); +static int wm_check_for_link(struct wm_softc *); +static void wm_tbi_tick(struct wm_softc *); +/* SERDES related */ +static void wm_serdes_power_up_link_82575(struct wm_softc *); +static int wm_serdes_mediachange(struct ifnet *); +static void wm_serdes_mediastatus(struct ifnet *, struct ifmediareq *); +static void wm_serdes_tick(struct wm_softc *); /* SFP related */ static int wm_sfp_read_data_byte(struct wm_softc *, uint16_t, uint8_t *); static uint32_t wm_sfp_get_media_type(struct wm_softc *); @@ -667,6 +688,8 @@ static void wm_nvm_release(struct wm_sof static int wm_nvm_is_onboard_eeprom(struct wm_softc *); static int wm_nvm_get_flash_presence_i210(struct wm_softc *); static int wm_nvm_validate_checksum(struct wm_softc *); +static void wm_nvm_version_invm(struct wm_softc *); +static void wm_nvm_version(struct wm_softc *); static int wm_nvm_read(struct wm_softc *, int, int, uint16_t *); /* @@ -686,12 +709,14 @@ static void wm_put_hw_semaphore_82573(st * Management mode and power management related subroutines. * BMC, AMT, suspend/resume and EEE. */ +#ifdef WM_WOL static int wm_check_mng_mode(struct wm_softc *); static int wm_check_mng_mode_ich8lan(struct wm_softc *); static int wm_check_mng_mode_82574(struct wm_softc *); static int wm_check_mng_mode_generic(struct wm_softc *); +#endif static int wm_enable_mng_pass_thru(struct wm_softc *); -static int wm_check_reset_block(struct wm_softc *); +static bool wm_phy_resetisblocked(struct wm_softc *); static void wm_get_hw_control(struct wm_softc *); static void wm_release_hw_control(struct wm_softc *); static void wm_gate_hw_phy_config_ich8lan(struct wm_softc *, int); @@ -704,6 +729,9 @@ static void wm_enable_phy_wakeup(struct static void wm_igp3_phy_powerdown_workaround_ich8lan(struct wm_softc *); static void wm_enable_wakeup(struct wm_softc *); #endif +/* LPLU (Low Power Link Up) */ +static void wm_lplu_d0_disable(struct wm_softc *); +static void wm_lplu_d0_disable_pch(struct wm_softc *); /* EEE */ static void wm_set_eee_i350(struct wm_softc *); @@ -719,6 +747,8 @@ static void wm_k1_gig_workaround_hv(stru static void wm_set_mdio_slow_mode_hv(struct wm_softc *); static void wm_configure_k1_ich8lan(struct wm_softc *, int); static void wm_reset_init_script_82575(struct wm_softc *); +static void wm_reset_mdicnfg_82580(struct wm_softc *); +static void wm_pll_workaround_i210(struct wm_softc *); CFATTACH_DECL3_NEW(wm, sizeof(struct wm_softc), wm_match, wm_attach, wm_detach, NULL, NULL, NULL, DVF_DETACH_SHUTDOWN); @@ -1168,9 +1198,18 @@ static const struct wm_product { "I350 Gigabit Connection", WM_T_I350, WMP_F_COPPER }, + { PCI_VENDOR_INTEL, PCI_PRODUCT_INTEL_C2000_1000KX, + "I354 Gigabit Ethernet (KX)", + WM_T_I354, WMP_F_SERDES }, + { PCI_VENDOR_INTEL, PCI_PRODUCT_INTEL_C2000_SGMII, - "I354 Gigabit Connection", + "I354 Gigabit Ethernet (SGMII)", + WM_T_I354, WMP_F_COPPER }, + + { PCI_VENDOR_INTEL, PCI_PRODUCT_INTEL_C2000_25GBE, + "I354 Gigabit Ethernet (2.5G)", WM_T_I354, WMP_F_COPPER }, + { PCI_VENDOR_INTEL, PCI_PRODUCT_INTEL_I210_T1, "I210-T1 Ethernet Server Adapter", WM_T_I210, WMP_F_COPPER }, @@ -1348,7 +1387,7 @@ wm_attach(device_t parent, device_t self prop_data_t ea; prop_number_t pn; uint8_t enaddr[ETHER_ADDR_LEN]; - uint16_t cfg1, cfg2, swdpin, io3; + uint16_t cfg1, cfg2, swdpin, nvmword; pcireg_t preg, memtype; uint16_t eeprom_data, apme_mask; bool force_clear_smbi; @@ -1378,7 +1417,7 @@ wm_attach(device_t parent, device_t self sc->sc_dmat = pa->pa_dmat; sc->sc_pcidevid = PCI_PRODUCT(pa->pa_id); - sc->sc_rev = PCI_REVISION(pci_conf_read(pc, pa->pa_tag, PCI_CLASS_REG)); + sc->sc_rev = PCI_REVISION(pci_conf_read(pc, pa->pa_tag,PCI_CLASS_REG)); pci_aprint_devinfo_fancy(pa, "Ethernet controller", wmp->wmp_name, 1); sc->sc_type = wmp->wmp_type; @@ -1580,11 +1619,9 @@ wm_attach(device_t parent, device_t self pcix_sts = pci_conf_read(pa->pa_pc, pa->pa_tag, sc->sc_pcixe_capoff + PCIX_STATUS); - bytecnt = - (pcix_cmd & PCIX_CMD_BYTECNT_MASK) >> + bytecnt = (pcix_cmd & PCIX_CMD_BYTECNT_MASK) >> PCIX_CMD_BYTECNT_SHIFT; - maxb = - (pcix_sts & PCIX_STATUS_MAXB_MASK) >> + maxb = (pcix_sts & PCIX_STATUS_MAXB_MASK) >> PCIX_STATUS_MAXB_SHIFT; if (bytecnt > maxb) { aprint_verbose_dev(sc->sc_dev, @@ -1808,20 +1845,19 @@ wm_attach(device_t parent, device_t self /* FLASH */ sc->sc_flags |= WM_F_EEPROM_FLASH | WM_F_LOCK_EXTCNF; sc->sc_nvm_wordsize = 2048; - memtype = pci_mapreg_type(pa->pa_pc, pa->pa_tag, WM_ICH8_FLASH); + memtype = pci_mapreg_type(pa->pa_pc, pa->pa_tag,WM_ICH8_FLASH); if (pci_mapreg_map(pa, WM_ICH8_FLASH, memtype, 0, - &sc->sc_flasht, &sc->sc_flashh, NULL, NULL)) { + &sc->sc_flasht, &sc->sc_flashh, NULL, &sc->sc_flashs)) { aprint_error_dev(sc->sc_dev, "can't map FLASH registers\n"); goto fail_5; } reg = ICH8_FLASH_READ32(sc, ICH_FLASH_GFPREG); sc->sc_ich8_flash_base = (reg & ICH_GFPREG_BASE_MASK) * - ICH_FLASH_SECTOR_SIZE; + ICH_FLASH_SECTOR_SIZE; sc->sc_ich8_flash_bank_size = ((reg >> 16) & ICH_GFPREG_BASE_MASK) + 1; - sc->sc_ich8_flash_bank_size -= - (reg & ICH_GFPREG_BASE_MASK); + sc->sc_ich8_flash_bank_size -= (reg & ICH_GFPREG_BASE_MASK); sc->sc_ich8_flash_bank_size *= ICH_FLASH_SECTOR_SIZE; sc->sc_ich8_flash_bank_size /= 2 * sizeof(uint16_t); break; @@ -1834,7 +1870,7 @@ wm_attach(device_t parent, device_t self } else { sc->sc_nvm_wordsize = INVM_SIZE; sc->sc_flags |= WM_F_EEPROM_INVM; - sc->sc_flags |= WM_F_EEPROM_EERDEEWR | WM_F_LOCK_SWFW; + sc->sc_flags |= WM_F_LOCK_SWFW; } break; default: @@ -1891,26 +1927,46 @@ wm_attach(device_t parent, device_t self prop_dictionary_set_uint32(dict, "macflags", sc->sc_flags); if (sc->sc_flags & WM_F_EEPROM_INVALID) - aprint_verbose_dev(sc->sc_dev, "No EEPROM\n"); + aprint_verbose_dev(sc->sc_dev, "No EEPROM"); else { aprint_verbose_dev(sc->sc_dev, "%u words ", sc->sc_nvm_wordsize); if (sc->sc_flags & WM_F_EEPROM_INVM) - aprint_verbose("iNVM\n"); + aprint_verbose("iNVM"); else if (sc->sc_flags & WM_F_EEPROM_FLASH_HW) - aprint_verbose("FLASH(HW)\n"); + aprint_verbose("FLASH(HW)"); else if (sc->sc_flags & WM_F_EEPROM_FLASH) - aprint_verbose("FLASH\n"); + aprint_verbose("FLASH"); else { if (sc->sc_flags & WM_F_EEPROM_SPI) eetype = "SPI"; else eetype = "MicroWire"; - aprint_verbose("(%d address bits) %s EEPROM\n", + aprint_verbose("(%d address bits) %s EEPROM", sc->sc_nvm_addrbits, eetype); } } + wm_nvm_version(sc); + aprint_verbose("\n"); + + /* Check for I21[01] PLL workaround */ + if (sc->sc_type == WM_T_I210) + sc->sc_flags |= WM_F_PLL_WA_I210; + if ((sc->sc_type == WM_T_I210) && wm_nvm_get_flash_presence_i210(sc)) { + /* NVM image release 3.25 has a workaround */ + if ((sc->sc_nvm_ver_major < 3) + || ((sc->sc_nvm_ver_major == 3) + && (sc->sc_nvm_ver_minor < 25))) { + aprint_verbose_dev(sc->sc_dev, + "ROM image version %d.%d is older than 3.25\n", + sc->sc_nvm_ver_major, sc->sc_nvm_ver_minor); + sc->sc_flags |= WM_F_PLL_WA_I210; + } + } + if ((sc->sc_flags & WM_F_PLL_WA_I210) != 0) + wm_pll_workaround_i210(sc); + wm_get_wakeup(sc); switch (sc->sc_type) { case WM_T_82571: case WM_T_82572: @@ -1924,13 +1980,14 @@ wm_attach(device_t parent, device_t self case WM_T_PCH: case WM_T_PCH2: case WM_T_PCH_LPT: - if (wm_check_mng_mode(sc) != 0) + /* Non-AMT based hardware can now take control from firmware */ + if ((sc->sc_flags & WM_F_HAS_AMT) == 0) wm_get_hw_control(sc); break; default: break; } - wm_get_wakeup(sc); + /* * Read the Ethernet address from the EEPROM, if not first found * in device properties. @@ -2028,6 +2085,14 @@ wm_attach(device_t parent, device_t self printf("WOL\n"); #endif + if ((sc->sc_type == WM_T_82575) || (sc->sc_type == WM_T_82576)) { + /* Check NVM for autonegotiation */ + if (wm_nvm_read(sc, NVM_OFF_COMPAT, 1, &nvmword) == 0) { + if ((nvmword & NVM_COMPAT_SERDES_FORCE_MODE) != 0) + sc->sc_flags |= WM_F_PCS_DIS_AUTONEGO; + } + } + /* * XXX need special handling for some multiple port cards * to disable a paticular port. @@ -2049,17 +2114,34 @@ wm_attach(device_t parent, device_t self if (cfg1 & NVM_CFG1_ILOS) sc->sc_ctrl |= CTRL_ILOS; - if (sc->sc_type >= WM_T_82544) { - sc->sc_ctrl |= - ((swdpin >> NVM_SWDPIN_SWDPIO_SHIFT) & 0xf) << - CTRL_SWDPIO_SHIFT; - sc->sc_ctrl |= - ((swdpin >> NVM_SWDPIN_SWDPIN_SHIFT) & 0xf) << - CTRL_SWDPINS_SHIFT; - } else { - sc->sc_ctrl |= - ((cfg1 >> NVM_CFG1_SWDPIO_SHIFT) & 0xf) << - CTRL_SWDPIO_SHIFT; + + /* + * XXX + * This code isn't correct because pin 2 and 3 are located + * in different position on newer chips. Check all datasheet. + * + * Until resolve this problem, check if a chip < 82580 + */ + if (sc->sc_type <= WM_T_82580) { + if (sc->sc_type >= WM_T_82544) { + sc->sc_ctrl |= + ((swdpin >> NVM_SWDPIN_SWDPIO_SHIFT) & 0xf) << + CTRL_SWDPIO_SHIFT; + sc->sc_ctrl |= + ((swdpin >> NVM_SWDPIN_SWDPIN_SHIFT) & 0xf) << + CTRL_SWDPINS_SHIFT; + } else { + sc->sc_ctrl |= + ((cfg1 >> NVM_CFG1_SWDPIO_SHIFT) & 0xf) << + CTRL_SWDPIO_SHIFT; + } + } + + /* XXX For other than 82580? */ + if (sc->sc_type == WM_T_82580) { + wm_nvm_read(sc, NVM_OFF_CFG3_PORTA, 1, &nvmword); + if (nvmword & __BIT(13)) + sc->sc_ctrl |= CTRL_ILOS; } #if 0 @@ -2237,8 +2319,8 @@ wm_attach(device_t parent, device_t self switch (sc->sc_type) { case WM_T_82573: /* XXX limited to 9234 if ASPM is disabled */ - wm_nvm_read(sc, NVM_OFF_INIT_3GIO_3, 1, &io3); - if ((io3 & NVM_3GIO_3_ASPM_MASK) != 0) + wm_nvm_read(sc, NVM_OFF_INIT_3GIO_3, 1, &nvmword); + if ((nvmword & NVM_3GIO_3_ASPM_MASK) != 0) sc->sc_ethercom.ec_capabilities |= ETHERCAP_JUMBO_MTU; break; case WM_T_82571: @@ -2502,11 +2584,14 @@ wm_detach(device_t self, int flags __unu bus_space_unmap(sc->sc_st, sc->sc_sh, sc->sc_ss); sc->sc_ss = 0; } - if (sc->sc_ios) { bus_space_unmap(sc->sc_iot, sc->sc_ioh, sc->sc_ios); sc->sc_ios = 0; } + if (sc->sc_flashs) { + bus_space_unmap(sc->sc_flasht, sc->sc_flashh, sc->sc_flashs); + sc->sc_flashs = 0; + } if (sc->sc_tx_lock) mutex_obj_free(sc->sc_tx_lock); @@ -2637,8 +2722,11 @@ wm_tick(void *arg) if (sc->sc_flags & WM_F_HAS_MII) mii_tick(&sc->sc_mii); + else if ((sc->sc_type >= WM_T_82575) + && (sc->sc_mediatype == WM_MEDIATYPE_SERDES)) + wm_serdes_tick(sc); else - wm_tbi_check_link(sc); + wm_tbi_tick(sc); out: WM_TX_UNLOCK(sc); @@ -2663,7 +2751,7 @@ wm_ifflags_cb(struct ethercom *ec) if (change != 0) sc->sc_if_flags = ifp->if_flags; - if ((change & ~(IFF_CANTCHANGE|IFF_DEBUG)) != 0) { + if ((change & ~(IFF_CANTCHANGE | IFF_DEBUG)) != 0) { rc = ENETRESET; goto out; } @@ -2934,7 +3022,7 @@ wm_set_filter(struct wm_softc *sc) struct ether_multistep step; bus_addr_t mta_reg; uint32_t hash, reg, bit; - int i, size; + int i, size, max; if (sc->sc_type >= WM_T_82544) mta_reg = WMREG_CORDOVA_MTA; @@ -2957,9 +3045,12 @@ wm_set_filter(struct wm_softc *sc) if (sc->sc_type == WM_T_ICH8) size = WM_RAL_TABSIZE_ICH8 -1; else if ((sc->sc_type == WM_T_ICH9) || (sc->sc_type == WM_T_ICH10) - || (sc->sc_type == WM_T_PCH) || (sc->sc_type == WM_T_PCH2) - || (sc->sc_type == WM_T_PCH_LPT)) + || (sc->sc_type == WM_T_PCH)) size = WM_RAL_TABSIZE_ICH8; + else if (sc->sc_type == WM_T_PCH2) + size = WM_RAL_TABSIZE_PCH2; + else if (sc->sc_type == WM_T_PCH_LPT) + size = WM_RAL_TABSIZE_PCH_LPT; else if (sc->sc_type == WM_T_82575) size = WM_RAL_TABSIZE_82575; else if ((sc->sc_type == WM_T_82576) || (sc->sc_type == WM_T_82580)) @@ -2969,8 +3060,28 @@ wm_set_filter(struct wm_softc *sc) else size = WM_RAL_TABSIZE; wm_set_ral(sc, CLLADDR(ifp->if_sadl), 0); - for (i = 1; i < size; i++) - wm_set_ral(sc, NULL, i); + + if (sc->sc_type == WM_T_PCH_LPT) { + i = __SHIFTOUT(CSR_READ(sc, WMREG_FWSM), FWSM_WLOCK_MAC); + switch (i) { + case 0: + /* We can use all entries */ + max = size; + break; + case 1: + /* Only RAR[0] */ + max = 1; + break; + default: + /* available SHRA + RAR[0] */ + max = i + 1; + } + } else + max = size; + for (i = 1; i < size; i++) { + if (i < max) + wm_set_ral(sc, NULL, i); + } if ((sc->sc_type == WM_T_ICH8) || (sc->sc_type == WM_T_ICH9) || (sc->sc_type == WM_T_ICH10) || (sc->sc_type == WM_T_PCH) @@ -3011,8 +3122,12 @@ wm_set_filter(struct wm_softc *sc) hash = CSR_READ(sc, mta_reg + (reg << 2)); hash |= 1U << bit; - /* XXX Hardware bug?? */ - if (sc->sc_type == WM_T_82544 && (reg & 0xe) == 1) { + if (sc->sc_type == WM_T_82544 && (reg & 1) != 0) { + /* + * 82544 Errata 9: Certain register cannot be written + * with particular alignments in PCI-X bus operation + * (FCAH, MTA and VFTA). + */ bit = CSR_READ(sc, mta_reg + ((reg - 1) << 2)); CSR_WRITE(sc, mta_reg + (reg << 2), hash); CSR_WRITE(sc, mta_reg + ((reg - 1) << 2), bit); @@ -3231,7 +3346,7 @@ void wm_initialize_hardware_bits(struct wm_softc *sc) { uint32_t tarc0, tarc1, reg; - + /* For 82571 variant, 80003 and ICHs */ if (((sc->sc_type >= WM_T_82571) && (sc->sc_type <= WM_T_82583)) || (sc->sc_type >= WM_T_80003)) { @@ -3306,6 +3421,17 @@ wm_initialize_hardware_bits(struct wm_so CSR_WRITE(sc, WMREG_CTRL, sc->sc_ctrl); /* PCIe Control Register */ + /* + * 82573 Errata (unknown). + * + * 82574 Errata 25 and 82583 Errata 12 + * "Dropped Rx Packets": + * NVM Image Version 2.1.4 and newer has no this bug. + */ + reg = CSR_READ(sc, WMREG_GCR); + reg |= GCR_L1_ACT_WITHOUT_L0S_RX; + CSR_WRITE(sc, WMREG_GCR, reg); + if ((sc->sc_type == WM_T_82574) || (sc->sc_type == WM_T_82583)) { /* @@ -3420,6 +3546,17 @@ wm_initialize_hardware_bits(struct wm_so } } +static uint32_t +wm_rxpbs_adjust_82580(uint32_t val) +{ + uint32_t rv = 0; + + if (val < __arraycount(wm_82580_rxpbs_table)) + rv = wm_82580_rxpbs_table[val]; + + return rv; +} + /* * wm_reset: * @@ -3451,21 +3588,9 @@ wm_reset(struct wm_softc *sc) case WM_T_82571: case WM_T_82572: case WM_T_82575: /* XXX need special handing for jumbo frames */ - case WM_T_I350: - case WM_T_I354: case WM_T_80003: sc->sc_pba = PBA_32K; break; - case WM_T_82580: - sc->sc_pba = PBA_35K; - break; - case WM_T_I210: - case WM_T_I211: - sc->sc_pba = PBA_34K; - break; - case WM_T_82576: - sc->sc_pba = PBA_64K; - break; case WM_T_82573: sc->sc_pba = PBA_12K; break; @@ -3473,6 +3598,19 @@ wm_reset(struct wm_softc *sc) case WM_T_82583: sc->sc_pba = PBA_20K; break; + case WM_T_82576: + sc->sc_pba = CSR_READ(sc, WMREG_RXPBS); + sc->sc_pba &= RXPBS_SIZE_MASK_82576; + break; + case WM_T_82580: + case WM_T_I350: + case WM_T_I354: + sc->sc_pba = wm_rxpbs_adjust_82580(CSR_READ(sc, WMREG_RXPBS)); + break; + case WM_T_I210: + case WM_T_I211: + sc->sc_pba = PBA_34K; + break; case WM_T_ICH8: /* Workaround for a bit corruption issue in FIFO memory */ sc->sc_pba = PBA_8K; @@ -3480,7 +3618,8 @@ wm_reset(struct wm_softc *sc) break; case WM_T_ICH9: case WM_T_ICH10: - sc->sc_pba = PBA_10K; + sc->sc_pba = sc->sc_ethercom.ec_if.if_mtu > 4096 ? + PBA_14K : PBA_10K; break; case WM_T_PCH: case WM_T_PCH2: @@ -3492,7 +3631,13 @@ wm_reset(struct wm_softc *sc) PBA_40K : PBA_48K; break; } - CSR_WRITE(sc, WMREG_PBA, sc->sc_pba); + /* + * Only old or non-multiqueue devices have the PBA register + * XXX Need special handling for 82575. + */ + if (((sc->sc_flags & WM_F_NEWQUEUE) == 0) + || (sc->sc_type == WM_T_82575)) + CSR_WRITE(sc, WMREG_PBA, sc->sc_pba); /* Prevent the PCI-E bus from sticking */ if (sc->sc_flags & WM_F_PCIE) { @@ -3593,17 +3738,16 @@ wm_reset(struct wm_softc *sc) case WM_T_PCH2: case WM_T_PCH_LPT: reg = CSR_READ(sc, WMREG_CTRL) | CTRL_RST; - if (wm_check_reset_block(sc) == 0) { + if (wm_phy_resetisblocked(sc) == false) { /* * Gate automatic PHY configuration by hardware on * non-managed 82579 */ if ((sc->sc_type == WM_T_PCH2) && ((CSR_READ(sc, WMREG_FWSM) & FWSM_FW_VALID) - != 0)) + == 0)) wm_gate_hw_phy_config_ich8lan(sc, 1); - reg |= CTRL_PHY_RESET; phy_reset = 1; } @@ -3731,9 +3875,7 @@ wm_reset(struct wm_softc *sc) switch (sc->sc_type) { case WM_T_82575: case WM_T_82576: -#if 0 /* XXX */ case WM_T_82580: -#endif case WM_T_I350: case WM_T_I354: case WM_T_ICH8: @@ -3741,11 +3883,7 @@ wm_reset(struct wm_softc *sc) if ((CSR_READ(sc, WMREG_EECD) & EECD_EE_PRES) == 0) { /* Not found */ sc->sc_flags |= WM_F_EEPROM_INVALID; - if ((sc->sc_type == WM_T_82575) - || (sc->sc_type == WM_T_82576) - || (sc->sc_type == WM_T_82580) - || (sc->sc_type == WM_T_I350) - || (sc->sc_type == WM_T_I354)) + if (sc->sc_type == WM_T_82575) wm_reset_init_script_82575(sc); } break; @@ -3780,10 +3918,13 @@ wm_reset(struct wm_softc *sc) if (sc->sc_type == WM_T_PCH) CSR_WRITE(sc, WMREG_CRC_OFFSET, 0x65656565); - if ((sc->sc_flags & WM_F_NEWQUEUE) != 0) + if (sc->sc_type >= WM_T_82544) CSR_WRITE(sc, WMREG_WUC, 0); - /* XXX need special handling for 82580 */ + wm_reset_mdicnfg_82580(sc); + + if ((sc->sc_flags & WM_F_PLL_WA_I210) != 0) + wm_pll_workaround_i210(sc); } /* @@ -3817,7 +3958,7 @@ wm_add_rxbuf(struct wm_softc *sc, int id m->m_len = m->m_pkthdr.len = m->m_ext.ext_size; error = bus_dmamap_load_mbuf(sc->sc_dmat, rxs->rxs_dmamap, m, - BUS_DMA_READ|BUS_DMA_NOWAIT); + BUS_DMA_READ | BUS_DMA_NOWAIT); if (error) { /* XXX XXX XXX */ aprint_error_dev(sc->sc_dev, @@ -3931,7 +4072,8 @@ wm_init_locked(struct ifnet *ifp) case WM_T_PCH: case WM_T_PCH2: case WM_T_PCH_LPT: - if (wm_check_mng_mode(sc) != 0) + /* AMT based hardware can now take control from firmware */ + if ((sc->sc_flags & WM_F_HAS_AMT) != 0) wm_get_hw_control(sc); break; default: @@ -3948,7 +4090,7 @@ wm_init_locked(struct ifnet *ifp) /* Initialize the transmit descriptor ring. */ memset(sc->sc_txdescs, 0, WM_TXDESCSIZE(sc)); WM_CDTXSYNC(sc, 0, WM_NTXDESC(sc), - BUS_DMASYNC_PREREAD|BUS_DMASYNC_PREWRITE); + BUS_DMASYNC_PREREAD | BUS_DMASYNC_PREWRITE); sc->sc_txfree = WM_NTXDESC(sc); sc->sc_txnext = 0; @@ -4027,8 +4169,10 @@ wm_init_locked(struct ifnet *ifp) } else { CSR_WRITE(sc, WMREG_RDH, 0); CSR_WRITE(sc, WMREG_RDT, 0); - CSR_WRITE(sc, WMREG_RDTR, 375 | RDTR_FPD); /* ITR/4 */ - CSR_WRITE(sc, WMREG_RADV, 375); /* MUST be same */ + /* ITR/4 */ + CSR_WRITE(sc, WMREG_RDTR, (sc->sc_itr / 4) | RDTR_FPD); + /* MUST be same */ + CSR_WRITE(sc, WMREG_RADV, sc->sc_itr); } } for (i = 0; i < WM_NRXDESC; i++) { @@ -4120,8 +4264,7 @@ wm_init_locked(struct ifnet *ifp) */ wm_kmrn_writereg(sc, KUMCTRLSTA_OFFSET_TIMEOUTS, 0xFFFF); - val = wm_kmrn_readreg(sc, - KUMCTRLSTA_OFFSET_INB_PARAM); + val = wm_kmrn_readreg(sc, KUMCTRLSTA_OFFSET_INB_PARAM); val |= 0x3F; wm_kmrn_writereg(sc, KUMCTRLSTA_OFFSET_INB_PARAM, val); @@ -4452,7 +4595,7 @@ wm_tx_offload(struct wm_softc *sc, struc } if ((m0->m_pkthdr.csum_flags & - (M_CSUM_TSOv4|M_CSUM_UDPv4|M_CSUM_TCPv4)) != 0) { + (M_CSUM_TSOv4 | M_CSUM_UDPv4 | M_CSUM_TCPv4)) != 0) { iphl = M_CSUM_DATA_IPv4_IPHL(m0->m_pkthdr.csum_data); } else { iphl = M_CSUM_DATA_IPv6_HL(m0->m_pkthdr.csum_data); @@ -4555,7 +4698,7 @@ wm_tx_offload(struct wm_softc *sc, struc ipcs = WTX_TCPIP_IPCSS(offset) | WTX_TCPIP_IPCSO(offset + offsetof(struct ip, ip_sum)) | WTX_TCPIP_IPCSE(ipcse); - if (m0->m_pkthdr.csum_flags & (M_CSUM_IPv4|M_CSUM_TSOv4)) { + if (m0->m_pkthdr.csum_flags & (M_CSUM_IPv4 | M_CSUM_TSOv4)) { WM_EVCNT_INCR(&sc->sc_ev_txipsum); fields |= WTX_IXSM; } @@ -4563,7 +4706,7 @@ wm_tx_offload(struct wm_softc *sc, struc offset += iphl; if (m0->m_pkthdr.csum_flags & - (M_CSUM_TCPv4|M_CSUM_UDPv4|M_CSUM_TSOv4)) { + (M_CSUM_TCPv4 | M_CSUM_UDPv4 | M_CSUM_TSOv4)) { WM_EVCNT_INCR(&sc->sc_ev_txtusum); fields |= WTX_TXSM; tucs = WTX_TCPIP_TUCSS(offset) | @@ -4571,7 +4714,7 @@ wm_tx_offload(struct wm_softc *sc, struc M_CSUM_DATA_IPv4_OFFSET(m0->m_pkthdr.csum_data)) | WTX_TCPIP_TUCSE(0) /* rest of packet */; } else if ((m0->m_pkthdr.csum_flags & - (M_CSUM_TCPv6|M_CSUM_UDPv6|M_CSUM_TSOv6)) != 0) { + (M_CSUM_TCPv6 | M_CSUM_UDPv6 | M_CSUM_TSOv6)) != 0) { WM_EVCNT_INCR(&sc->sc_ev_txtusum6); fields |= WTX_TXSM; tucs = WTX_TCPIP_TUCSS(offset) | @@ -4751,7 +4894,7 @@ wm_start_locked(struct ifnet *ifp) KASSERT(WM_TX_LOCKED(sc)); - if ((ifp->if_flags & (IFF_RUNNING|IFF_OACTIVE)) != IFF_RUNNING) + if ((ifp->if_flags & (IFF_RUNNING | IFF_OACTIVE)) != IFF_RUNNING) return; /* Remember the previous number of free descriptors. */ @@ -4903,9 +5046,9 @@ wm_start_locked(struct ifnet *ifp) /* Set up offload parameters for this packet. */ if (m0->m_pkthdr.csum_flags & - (M_CSUM_TSOv4|M_CSUM_TSOv6| - M_CSUM_IPv4|M_CSUM_TCPv4|M_CSUM_UDPv4| - M_CSUM_TCPv6|M_CSUM_UDPv6)) { + (M_CSUM_TSOv4 | M_CSUM_TSOv6 | + M_CSUM_IPv4 | M_CSUM_TCPv4 | M_CSUM_UDPv4 | + M_CSUM_TCPv6 | M_CSUM_UDPv6)) { if (wm_tx_offload(sc, txs, &cksumcmd, &cksumfields) != 0) { /* Error message already displayed. */ @@ -4939,21 +5082,19 @@ wm_start_locked(struct ifnet *ifp) * write-backs in TSO mode. Append a * 4-byte sentinel descriptor. */ - if (use_tso && - seg == dmamap->dm_nsegs - 1 && + if (use_tso && seg == dmamap->dm_nsegs - 1 && curlen > 8) curlen -= 4; wm_set_dma_addr( - &sc->sc_txdescs[nexttx].wtx_addr, - curaddr); - sc->sc_txdescs[nexttx].wtx_cmdlen = - htole32(cksumcmd | curlen); - sc->sc_txdescs[nexttx].wtx_fields.wtxu_status = - 0; - sc->sc_txdescs[nexttx].wtx_fields.wtxu_options = - cksumfields; - sc->sc_txdescs[nexttx].wtx_fields.wtxu_vlan = 0; + &sc->sc_txdescs[nexttx].wtx_addr, curaddr); + sc->sc_txdescs[nexttx].wtx_cmdlen + = htole32(cksumcmd | curlen); + sc->sc_txdescs[nexttx].wtx_fields.wtxu_status + = 0; + sc->sc_txdescs[nexttx].wtx_fields.wtxu_options + = cksumfields; + sc->sc_txdescs[nexttx].wtx_fields.wtxu_vlan =0; lasttx = nexttx; DPRINTF(WM_DEBUG_TX, @@ -4996,7 +5137,7 @@ wm_start_locked(struct ifnet *ifp) /* Sync the descriptors we're using. */ WM_CDTXSYNC(sc, sc->sc_txnext, txs->txs_ndesc, - BUS_DMASYNC_PREREAD|BUS_DMASYNC_PREWRITE); + BUS_DMASYNC_PREREAD | BUS_DMASYNC_PREWRITE); /* Give the packet to the chip. */ CSR_WRITE(sc, sc->sc_tdt_reg, nexttx); @@ -5022,7 +5163,8 @@ wm_start_locked(struct ifnet *ifp) if (m0 != NULL) { ifp->if_flags |= IFF_OACTIVE; WM_EVCNT_INCR(&sc->sc_ev_txdrop); - DPRINTF(WM_DEBUG_TX, ("%s: TX: error after IFQ_DEQUEUE\n", __func__)); + DPRINTF(WM_DEBUG_TX, ("%s: TX: error after IFQ_DEQUEUE\n", + __func__)); m_freem(m0); } @@ -5084,7 +5226,7 @@ wm_nq_tx_offload(struct wm_softc *sc, st KASSERT((offset & ~NQTXC_VLLEN_MACLEN_MASK) == 0); if ((m0->m_pkthdr.csum_flags & - (M_CSUM_TSOv4|M_CSUM_UDPv4|M_CSUM_TCPv4|M_CSUM_IPv4)) != 0) { + (M_CSUM_TSOv4 | M_CSUM_UDPv4 | M_CSUM_TCPv4 | M_CSUM_IPv4)) != 0) { iphl = M_CSUM_DATA_IPv4_IPHL(m0->m_pkthdr.csum_data); } else { iphl = M_CSUM_DATA_IPv6_HL(m0->m_pkthdr.csum_data); @@ -5264,7 +5406,7 @@ wm_nq_start_locked(struct ifnet *ifp) KASSERT(WM_TX_LOCKED(sc)); - if ((ifp->if_flags & (IFF_RUNNING|IFF_OACTIVE)) != IFF_RUNNING) + if ((ifp->if_flags & (IFF_RUNNING | IFF_OACTIVE)) != IFF_RUNNING) return; sent = false; @@ -5310,7 +5452,7 @@ wm_nq_start_locked(struct ifnet *ifp) * buffer. */ error = bus_dmamap_load_mbuf(sc->sc_dmat, dmamap, m0, - BUS_DMA_WRITE|BUS_DMA_NOWAIT); + BUS_DMA_WRITE | BUS_DMA_NOWAIT); if (error) { if (error == EFBIG) { WM_EVCNT_INCR(&sc->sc_ev_txdrop); @@ -5379,9 +5521,9 @@ wm_nq_start_locked(struct ifnet *ifp) /* Set up offload parameters for this packet. */ uint32_t cmdlen, fields, dcmdlen; if (m0->m_pkthdr.csum_flags & - (M_CSUM_TSOv4|M_CSUM_TSOv6| - M_CSUM_IPv4|M_CSUM_TCPv4|M_CSUM_UDPv4| - M_CSUM_TCPv6|M_CSUM_UDPv6)) { + (M_CSUM_TSOv4 | M_CSUM_TSOv6 | + M_CSUM_IPv4 | M_CSUM_TCPv4 | M_CSUM_UDPv4 | + M_CSUM_TCPv6 | M_CSUM_UDPv6)) { if (wm_nq_tx_offload(sc, txs, &cmdlen, &fields, &do_csum) != 0) { /* Error message already displayed. */ @@ -5416,7 +5558,7 @@ wm_nq_start_locked(struct ifnet *ifp) sc->sc_txdescs[nexttx].wtx_fields.wtxu_vlan = htole16(VLAN_TAG_VALUE(mtag) & 0xffff); } else { - sc->sc_txdescs[nexttx].wtx_fields.wtxu_vlan = 0; + sc->sc_txdescs[nexttx].wtx_fields.wtxu_vlan =0; } dcmdlen = 0; } else { @@ -5483,7 +5625,7 @@ wm_nq_start_locked(struct ifnet *ifp) /* Sync the descriptors we're using. */ WM_CDTXSYNC(sc, sc->sc_txnext, txs->txs_ndesc, - BUS_DMASYNC_PREREAD|BUS_DMASYNC_PREWRITE); + BUS_DMASYNC_PREREAD | BUS_DMASYNC_PREWRITE); /* Give the packet to the chip. */ CSR_WRITE(sc, sc->sc_tdt_reg, nexttx); @@ -5510,7 +5652,8 @@ wm_nq_start_locked(struct ifnet *ifp) if (m0 != NULL) { ifp->if_flags |= IFF_OACTIVE; WM_EVCNT_INCR(&sc->sc_ev_txdrop); - DPRINTF(WM_DEBUG_TX, ("%s: TX: error after IFQ_DEQUEUE\n", __func__)); + DPRINTF(WM_DEBUG_TX, ("%s: TX: error after IFQ_DEQUEUE\n", + __func__)); m_freem(m0); } @@ -5553,11 +5696,11 @@ wm_txintr(struct wm_softc *sc) i = WM_NEXTTXS(sc, i), sc->sc_txsfree++) { txs = &sc->sc_txsoft[i]; - DPRINTF(WM_DEBUG_TX, - ("%s: TX: checking job %d\n", device_xname(sc->sc_dev), i)); + DPRINTF(WM_DEBUG_TX, ("%s: TX: checking job %d\n", + device_xname(sc->sc_dev), i)); WM_CDTXSYNC(sc, txs->txs_firstdesc, txs->txs_ndesc, - BUS_DMASYNC_POSTREAD|BUS_DMASYNC_POSTWRITE); + BUS_DMASYNC_POSTREAD | BUS_DMASYNC_POSTWRITE); status = sc->sc_txdescs[txs->txs_lastdesc].wtx_fields.wtxu_status; @@ -5583,7 +5726,7 @@ wm_txintr(struct wm_softc *sc) WM_EVCNT_INCR(&sc->sc_ev_tu); #endif /* WM_EVENT_COUNTERS */ - if (status & (WTX_ST_EC|WTX_ST_LC)) { + if (status & (WTX_ST_EC | WTX_ST_LC)) { ifp->if_oerrors++; if (status & WTX_ST_LC) log(LOG_WARNING, "%s: late collision\n", @@ -5773,9 +5916,7 @@ wm_rxintr(struct wm_softc *sc) */ /* XXXX should check for i350 and i354 */ if ((status & WRX_ST_VP) != 0) { - VLAN_INPUT_TAG(ifp, m, - le16toh(vlantag), - continue); + VLAN_INPUT_TAG(ifp, m, le16toh(vlantag), continue); } /* Set up checksum info for this packet. */ @@ -5841,8 +5982,12 @@ wm_linkintr_gmii(struct wm_softc *sc, ui __func__)); if (icr & ICR_LSC) { - DPRINTF(WM_DEBUG_LINK, - ("%s: LINK: LSC -> mii_pollstat\n", + uint32_t status = CSR_READ(sc, WMREG_STATUS); + + if ((sc->sc_type == WM_T_ICH8) && ((status & STATUS_LU) == 0)) + wm_gig_downshift_workaround_ich8lan(sc); + + DPRINTF(WM_DEBUG_LINK, ("%s: LINK: LSC -> mii_pollstat\n", device_xname(sc->sc_dev))); mii_pollstat(&sc->sc_mii); if (sc->sc_type == WM_T_82543) { @@ -5873,8 +6018,7 @@ wm_linkintr_gmii(struct wm_softc *sc, ui * fiber? * Shoud not enter here. */ - printf("unknown media (%x)\n", - active); + printf("unknown media (%x)\n", active); break; } if (active & IFM_FDX) @@ -5907,8 +6051,7 @@ wm_linkintr_gmii(struct wm_softc *sc, ui } } } else if (icr & ICR_RXSEQ) { - DPRINTF(WM_DEBUG_LINK, - ("%s: LINK Receive sequence error\n", + DPRINTF(WM_DEBUG_LINK, ("%s: LINK Receive sequence error\n", device_xname(sc->sc_dev))); } } @@ -5958,7 +6101,8 @@ wm_linkintr_tbi(struct wm_softc *sc, uin device_xname(sc->sc_dev))); sc->sc_tbi_linkup = 0; } - wm_tbi_set_linkled(sc); + /* Update LED */ + wm_tbi_serdes_set_linkled(sc); } else if (icr & ICR_RXSEQ) { DPRINTF(WM_DEBUG_LINK, ("%s: LINK: Receive sequence error\n", @@ -5967,6 +6111,76 @@ wm_linkintr_tbi(struct wm_softc *sc, uin } /* + * wm_linkintr_serdes: + * + * Helper; handle link interrupts for TBI mode. + */ +static void +wm_linkintr_serdes(struct wm_softc *sc, uint32_t icr) +{ + struct mii_data *mii = &sc->sc_mii; + struct ifmedia_entry *ife = sc->sc_mii.mii_media.ifm_cur; + uint32_t pcs_adv, pcs_lpab, reg; + + DPRINTF(WM_DEBUG_LINK, ("%s: %s:\n", device_xname(sc->sc_dev), + __func__)); + + if (icr & ICR_LSC) { + /* Check PCS */ + reg = CSR_READ(sc, WMREG_PCS_LSTS); + if ((reg & PCS_LSTS_LINKOK) != 0) { + mii->mii_media_status |= IFM_ACTIVE; + sc->sc_tbi_linkup = 1; + } else { + mii->mii_media_status |= IFM_NONE; + sc->sc_tbi_linkup = 0; + wm_tbi_serdes_set_linkled(sc); + return; + } + mii->mii_media_active |= IFM_1000_SX; + if ((reg & PCS_LSTS_FDX) != 0) + mii->mii_media_active |= IFM_FDX; + else + mii->mii_media_active |= IFM_HDX; + if (IFM_SUBTYPE(ife->ifm_media) == IFM_AUTO) { + /* Check flow */ + reg = CSR_READ(sc, WMREG_PCS_LSTS); + if ((reg & PCS_LSTS_AN_COMP) == 0) { + DPRINTF(WM_DEBUG_LINK, + ("XXX LINKOK but not ACOMP\n")); + return; + } + pcs_adv = CSR_READ(sc, WMREG_PCS_ANADV); + pcs_lpab = CSR_READ(sc, WMREG_PCS_LPAB); + DPRINTF(WM_DEBUG_LINK, + ("XXX AN result %08x, %08x\n", pcs_adv, pcs_lpab)); + if ((pcs_adv & TXCW_SYM_PAUSE) + && (pcs_lpab & TXCW_SYM_PAUSE)) { + mii->mii_media_active |= IFM_FLOW + | IFM_ETH_TXPAUSE | IFM_ETH_RXPAUSE; + } else if (((pcs_adv & TXCW_SYM_PAUSE) == 0) + && (pcs_adv & TXCW_ASYM_PAUSE) + && (pcs_lpab & TXCW_SYM_PAUSE) + && (pcs_lpab & TXCW_ASYM_PAUSE)) + mii->mii_media_active |= IFM_FLOW + | IFM_ETH_TXPAUSE; + else if ((pcs_adv & TXCW_SYM_PAUSE) + && (pcs_adv & TXCW_ASYM_PAUSE) + && ((pcs_lpab & TXCW_SYM_PAUSE) == 0) + && (pcs_lpab & TXCW_ASYM_PAUSE)) + mii->mii_media_active |= IFM_FLOW + | IFM_ETH_RXPAUSE; + } + /* Update LED */ + wm_tbi_serdes_set_linkled(sc); + } else { + DPRINTF(WM_DEBUG_LINK, + ("%s: LINK: Receive sequence error\n", + device_xname(sc->sc_dev))); + } +} + +/* * wm_linkintr: * * Helper; handle link interrupts. @@ -5977,6 +6191,9 @@ wm_linkintr(struct wm_softc *sc, uint32_ if (sc->sc_flags & WM_F_HAS_MII) wm_linkintr_gmii(sc, icr); + else if ((sc->sc_mediatype == WM_MEDIATYPE_SERDES) + && (sc->sc_type >= WM_T_82575)) + wm_linkintr_serdes(sc, icr); else wm_linkintr_tbi(sc, icr); } @@ -6010,11 +6227,11 @@ wm_intr(void *arg) handled = 1; #if defined(WM_DEBUG) || defined(WM_EVENT_COUNTERS) - if (icr & (ICR_RXDMT0|ICR_RXT0)) { + if (icr & (ICR_RXDMT0 | ICR_RXT0)) { DPRINTF(WM_DEBUG_RX, ("%s: RX: got Rx intr 0x%08x\n", device_xname(sc->sc_dev), - icr & (ICR_RXDMT0|ICR_RXT0))); + icr & (ICR_RXDMT0 | ICR_RXT0))); WM_EVCNT_INCR(&sc->sc_ev_rxintr); } #endif @@ -6033,7 +6250,7 @@ wm_intr(void *arg) #endif wm_txintr(sc); - if (icr & (ICR_LSC|ICR_RXSEQ)) { + if (icr & (ICR_LSC | ICR_RXSEQ)) { WM_EVCNT_INCR(&sc->sc_ev_linkintr); wm_linkintr(sc, icr); } @@ -6061,6 +6278,28 @@ wm_intr(void *arg) * GMII, SGMII, TBI (and SERDES) */ +/* Common */ + +/* + * wm_tbi_serdes_set_linkled: + * + * Update the link LED on TBI and SERDES devices. + */ +static void +wm_tbi_serdes_set_linkled(struct wm_softc *sc) +{ + + if (sc->sc_tbi_linkup) + sc->sc_ctrl |= CTRL_SWDPIN(0); + else + sc->sc_ctrl &= ~CTRL_SWDPIN(0); + + /* 82540 or newer devices are active low */ + sc->sc_ctrl ^= (sc->sc_type >= WM_T_82540) ? CTRL_SWDPIN(0) : 0; + + CSR_WRITE(sc, WMREG_CTRL, sc->sc_ctrl); +} + /* GMII related */ /* @@ -6258,7 +6497,6 @@ wm_gmii_reset(struct wm_softc *sc) case WM_T_82571: case WM_T_82572: case WM_T_82573: - case WM_T_82574: case WM_T_82575: case WM_T_82576: case WM_T_82580: @@ -6266,10 +6504,13 @@ wm_gmii_reset(struct wm_softc *sc) case WM_T_I354: case WM_T_I210: case WM_T_I211: - case WM_T_82583: case WM_T_80003: /* null */ break; + case WM_T_82574: + case WM_T_82583: + wm_lplu_d0_disable(sc); + break; case WM_T_82541: case WM_T_82547: /* XXX Configure actively LED after PHY reset */ @@ -6302,18 +6543,11 @@ wm_gmii_reset(struct wm_softc *sc) * in NVM */ - /* Configure the LCD with the OEM bits in NVM */ - if ((sc->sc_type == WM_T_PCH) || (sc->sc_type == WM_T_PCH2) - || (sc->sc_type == WM_T_PCH_LPT)) { - /* - * Disable LPLU. - * XXX It seems that 82567 has LPLU, too. - */ - reg = wm_gmii_hv_readreg(sc->sc_dev, 1, HV_OEM_BITS); - reg &= ~(HV_OEM_BITS_A1KDIS| HV_OEM_BITS_LPLU); - reg |= HV_OEM_BITS_ANEGNOW; - wm_gmii_hv_writereg(sc->sc_dev, 1, HV_OEM_BITS, reg); - } + /* Disable D0 LPLU. */ + if (sc->sc_type >= WM_T_PCH) /* PCH* */ + wm_lplu_d0_disable_pch(sc); + else + wm_lplu_d0_disable(sc); /* ICH* */ break; default: panic("%s: unknown type\n", __func__); @@ -6445,19 +6679,24 @@ wm_gmii_mediainit(struct wm_softc *sc, p default: if (((sc->sc_flags & WM_F_SGMII) != 0) && !wm_sgmii_uses_mdio(sc)){ + /* SGMII */ mii->mii_readreg = wm_sgmii_readreg; mii->mii_writereg = wm_sgmii_writereg; } else if (sc->sc_type >= WM_T_80003) { + /* 80003 */ mii->mii_readreg = wm_gmii_i80003_readreg; mii->mii_writereg = wm_gmii_i80003_writereg; } else if (sc->sc_type >= WM_T_I210) { - mii->mii_readreg = wm_gmii_i82544_readreg; - mii->mii_writereg = wm_gmii_i82544_writereg; + /* I210 and I211 */ + mii->mii_readreg = wm_gmii_gs40g_readreg; + mii->mii_writereg = wm_gmii_gs40g_writereg; } else if (sc->sc_type >= WM_T_82580) { + /* 82580, I350 and I354 */ sc->sc_phytype = WMPHY_82580; mii->mii_readreg = wm_gmii_82580_readreg; mii->mii_writereg = wm_gmii_82580_writereg; } else if (sc->sc_type >= WM_T_82544) { + /* 82544, 0, [56], [17], 8257[1234] and 82583 */ mii->mii_readreg = wm_gmii_i82544_readreg; mii->mii_writereg = wm_gmii_i82544_writereg; } else { @@ -6546,8 +6785,8 @@ wm_gmii_mediainit(struct wm_softc *sc, p if (LIST_FIRST(&mii->mii_phys) == NULL) { /* Any PHY wasn't find */ - ifmedia_add(&mii->mii_media, IFM_ETHER|IFM_NONE, 0, NULL); - ifmedia_set(&mii->mii_media, IFM_ETHER|IFM_NONE); + ifmedia_add(&mii->mii_media, IFM_ETHER | IFM_NONE, 0, NULL); + ifmedia_set(&mii->mii_media, IFM_ETHER | IFM_NONE); sc->sc_phytype = WMPHY_NONE; } else { /* @@ -6558,34 +6797,15 @@ wm_gmii_mediainit(struct wm_softc *sc, p struct mii_softc *child; child = LIST_FIRST(&mii->mii_phys); - if (device_is_a(child->mii_dev, "igphy")) { - struct igphy_softc *isc = (struct igphy_softc *)child; - - model = isc->sc_mii.mii_mpd_model; - if (model == MII_MODEL_yyINTEL_I82566) - sc->sc_phytype = WMPHY_IGP_3; - } + model = child->mii_mpd_model; + if (model == MII_MODEL_yyINTEL_I82566) + sc->sc_phytype = WMPHY_IGP_3; ifmedia_set(&mii->mii_media, IFM_ETHER | IFM_AUTO); } } /* - * wm_gmii_mediastatus: [ifmedia interface function] - * - * Get the current interface media status on a 1000BASE-T device. - */ -static void -wm_gmii_mediastatus(struct ifnet *ifp, struct ifmediareq *ifmr) -{ - struct wm_softc *sc = ifp->if_softc; - - ether_mediastatus(ifp, ifmr); - ifmr->ifm_active = (ifmr->ifm_active & ~IFM_ETH_FMASK) - | sc->sc_flowflags; -} - -/* * wm_gmii_mediachange: [ifmedia interface function] * * Set hardware to newly-selected media on a 1000BASE-T device. @@ -6634,6 +6854,21 @@ wm_gmii_mediachange(struct ifnet *ifp) return rc; } +/* + * wm_gmii_mediastatus: [ifmedia interface function] + * + * Get the current interface media status on a 1000BASE-T device. + */ +static void +wm_gmii_mediastatus(struct ifnet *ifp, struct ifmediareq *ifmr) +{ + struct wm_softc *sc = ifp->if_softc; + + ether_mediastatus(ifp, ifmr); + ifmr->ifm_active = (ifmr->ifm_active & ~IFM_ETH_FMASK) + | sc->sc_flowflags; +} + #define MDI_IO CTRL_SWDPIN(2) #define MDI_DIR CTRL_SWDPIO(2) /* host -> PHY */ #define MDI_CLK CTRL_SWDPIN(3) @@ -6644,7 +6879,7 @@ wm_i82543_mii_sendbits(struct wm_softc * uint32_t i, v; v = CSR_READ(sc, WMREG_CTRL); - v &= ~(MDI_IO|MDI_CLK|(CTRL_SWDPIO_MASK << CTRL_SWDPIO_SHIFT)); + v &= ~(MDI_IO | MDI_CLK | (CTRL_SWDPIO_MASK << CTRL_SWDPIO_SHIFT)); v |= MDI_DIR | CTRL_SWDPIO(3); for (i = 1 << (nbits - 1); i != 0; i >>= 1) { @@ -6670,7 +6905,7 @@ wm_i82543_mii_recvbits(struct wm_softc * uint32_t v, i, data = 0; v = CSR_READ(sc, WMREG_CTRL); - v &= ~(MDI_IO|MDI_CLK|(CTRL_SWDPIO_MASK << CTRL_SWDPIO_SHIFT)); + v &= ~(MDI_IO | MDI_CLK | (CTRL_SWDPIO_MASK << CTRL_SWDPIO_SHIFT)); v |= CTRL_SWDPIO(3); CSR_WRITE(sc, WMREG_CTRL, v); @@ -6725,8 +6960,7 @@ wm_gmii_i82543_readreg(device_t self, in (MII_COMMAND_READ << 10) | (MII_COMMAND_START << 12), 14); rv = wm_i82543_mii_recvbits(sc) & 0xffff; - DPRINTF(WM_DEBUG_GMII, - ("%s: GMII: read phy %d reg %d -> 0x%04x\n", + DPRINTF(WM_DEBUG_GMII, ("%s: GMII: read phy %d reg %d -> 0x%04x\n", device_xname(sc->sc_dev), phy, reg, rv)); return rv; @@ -6920,8 +7154,8 @@ wm_gmii_bm_readreg(device_t self, int ph if (reg > BME1000_MAX_MULTI_PAGE_REG) { if (phy == 1) - wm_gmii_i82544_writereg(self, phy, MII_IGPHY_PAGE_SELECT, - reg); + wm_gmii_i82544_writereg(self, phy, + MII_IGPHY_PAGE_SELECT, reg); else wm_gmii_i82544_writereg(self, phy, GG82563_PHY_PAGE_SELECT, @@ -6955,8 +7189,8 @@ wm_gmii_bm_writereg(device_t self, int p if (reg > BME1000_MAX_MULTI_PAGE_REG) { if (phy == 1) - wm_gmii_i82544_writereg(self, phy, MII_IGPHY_PAGE_SELECT, - reg); + wm_gmii_i82544_writereg(self, phy, + MII_IGPHY_PAGE_SELECT, reg); else wm_gmii_i82544_writereg(self, phy, GG82563_PHY_PAGE_SELECT, @@ -7167,6 +7401,75 @@ wm_gmii_82580_writereg(device_t self, in } /* + * wm_gmii_gs40g_readreg: [mii interface function] + * + * Read a PHY register on the I2100 and I211. + * This could be handled by the PHY layer if we didn't have to lock the + * ressource ... + */ +static int +wm_gmii_gs40g_readreg(device_t self, int phy, int reg) +{ + struct wm_softc *sc = device_private(self); + int sem; + int page, offset; + int rv; + + /* Acquire semaphore */ + sem = swfwphysem[sc->sc_funcid]; + if (wm_get_swfw_semaphore(sc, sem)) { + aprint_error_dev(sc->sc_dev, "%s: failed to get semaphore\n", + __func__); + return 0; + } + + /* Page select */ + page = reg >> GS40G_PAGE_SHIFT; + wm_gmii_i82544_writereg(self, phy, GS40G_PAGE_SELECT, page); + + /* Read reg */ + offset = reg & GS40G_OFFSET_MASK; + rv = wm_gmii_i82544_readreg(self, phy, offset); + + wm_put_swfw_semaphore(sc, sem); + return rv; +} + +/* + * wm_gmii_gs40g_writereg: [mii interface function] + * + * Write a PHY register on the I210 and I211. + * This could be handled by the PHY layer if we didn't have to lock the + * ressource ... + */ +static void +wm_gmii_gs40g_writereg(device_t self, int phy, int reg, int val) +{ + struct wm_softc *sc = device_private(self); + int sem; + int page, offset; + + /* Acquire semaphore */ + sem = swfwphysem[sc->sc_funcid]; + if (wm_get_swfw_semaphore(sc, sem)) { + aprint_error_dev(sc->sc_dev, "%s: failed to get semaphore\n", + __func__); + return; + } + + /* Page select */ + page = reg >> GS40G_PAGE_SHIFT; + wm_gmii_i82544_writereg(self, phy, GS40G_PAGE_SELECT, page); + + /* Write reg */ + offset = reg & GS40G_OFFSET_MASK; + wm_gmii_i82544_writereg(self, phy, offset, val); + + /* Release semaphore */ + wm_put_swfw_semaphore(sc, sem); +} + +/* * wm_gmii_statchg: [mii interface function] * * Callback from MII layer when media changes. @@ -7425,106 +7728,35 @@ wm_sgmii_writereg(device_t self, int phy /* TBI related */ -/* XXX Currently TBI only */ -static int -wm_check_for_link(struct wm_softc *sc) +/* + * wm_tbi_mediainit: + * + * Initialize media for use on 1000BASE-X devices. + */ +static void +wm_tbi_mediainit(struct wm_softc *sc) { - struct ifmedia_entry *ife = sc->sc_mii.mii_media.ifm_cur; - uint32_t rxcw; - uint32_t ctrl; - uint32_t status; - uint32_t sig; + struct ifnet *ifp = &sc->sc_ethercom.ec_if; + const char *sep = ""; - if (sc->sc_mediatype == WM_MEDIATYPE_SERDES) { - sc->sc_tbi_linkup = 1; - return 0; - } + if (sc->sc_type < WM_T_82543) + sc->sc_tipg = TIPG_WM_DFLT; + else + sc->sc_tipg = TIPG_LG_DFLT; - rxcw = CSR_READ(sc, WMREG_RXCW); - ctrl = CSR_READ(sc, WMREG_CTRL); - status = CSR_READ(sc, WMREG_STATUS); - - sig = (sc->sc_type > WM_T_82544) ? CTRL_SWDPIN(1) : 0; - - DPRINTF(WM_DEBUG_LINK, ("%s: %s: sig = %d, status_lu = %d, rxcw_c = %d\n", - device_xname(sc->sc_dev), __func__, - ((ctrl & CTRL_SWDPIN(1)) == sig), - ((status & STATUS_LU) != 0), - ((rxcw & RXCW_C) != 0) - )); - - /* - * SWDPIN LU RXCW - * 0 0 0 - * 0 0 1 (should not happen) - * 0 1 0 (should not happen) - * 0 1 1 (should not happen) - * 1 0 0 Disable autonego and force linkup - * 1 0 1 got /C/ but not linkup yet - * 1 1 0 (linkup) - * 1 1 1 If IFM_AUTO, back to autonego - * - */ - if (((ctrl & CTRL_SWDPIN(1)) == sig) - && ((status & STATUS_LU) == 0) - && ((rxcw & RXCW_C) == 0)) { - DPRINTF(WM_DEBUG_LINK, ("%s: force linkup and fullduplex\n", - __func__)); - sc->sc_tbi_linkup = 0; - /* Disable auto-negotiation in the TXCW register */ - CSR_WRITE(sc, WMREG_TXCW, (sc->sc_txcw & ~TXCW_ANE)); - - /* - * Force link-up and also force full-duplex. - * - * NOTE: CTRL was updated TFCE and RFCE automatically, - * so we should update sc->sc_ctrl - */ - sc->sc_ctrl = ctrl | CTRL_SLU | CTRL_FD; - CSR_WRITE(sc, WMREG_CTRL, sc->sc_ctrl); - } else if (((status & STATUS_LU) != 0) - && ((rxcw & RXCW_C) != 0) - && (IFM_SUBTYPE(ife->ifm_media) == IFM_AUTO)) { - sc->sc_tbi_linkup = 1; - DPRINTF(WM_DEBUG_LINK, ("%s: go back to autonego\n", - __func__)); - CSR_WRITE(sc, WMREG_TXCW, sc->sc_txcw); - CSR_WRITE(sc, WMREG_CTRL, (ctrl & ~CTRL_SLU)); - } else if (((ctrl & CTRL_SWDPIN(1)) == sig) - && ((rxcw & RXCW_C) != 0)) { - DPRINTF(WM_DEBUG_LINK, ("/C/")); - } else { - DPRINTF(WM_DEBUG_LINK, ("%s: %x,%x,%x\n", __func__, rxcw, ctrl, - status)); - } - - return 0; -} - -/* - * wm_tbi_mediainit: - * - * Initialize media for use on 1000BASE-X devices. - */ -static void -wm_tbi_mediainit(struct wm_softc *sc) -{ - struct ifnet *ifp = &sc->sc_ethercom.ec_if; - const char *sep = ""; - - if (sc->sc_type < WM_T_82543) - sc->sc_tipg = TIPG_WM_DFLT; - else - sc->sc_tipg = TIPG_LG_DFLT; - - sc->sc_tbi_anegticks = 5; + sc->sc_tbi_serdes_anegticks = 5; /* Initialize our media structures */ sc->sc_mii.mii_ifp = ifp; - sc->sc_ethercom.ec_mii = &sc->sc_mii; - ifmedia_init(&sc->sc_mii.mii_media, IFM_IMASK, wm_tbi_mediachange, - wm_tbi_mediastatus); + + if ((sc->sc_type >= WM_T_82575) + && (sc->sc_mediatype == WM_MEDIATYPE_SERDES)) + ifmedia_init(&sc->sc_mii.mii_media, IFM_IMASK, + wm_serdes_mediachange, wm_serdes_mediastatus); + else + ifmedia_init(&sc->sc_mii.mii_media, IFM_IMASK, + wm_tbi_mediachange, wm_tbi_mediastatus); /* * SWD Pins: @@ -7533,7 +7765,11 @@ wm_tbi_mediainit(struct wm_softc *sc) * 1 = Loss Of Signal (input) */ sc->sc_ctrl |= CTRL_SWDPIO(0); - sc->sc_ctrl &= ~CTRL_SWDPIO(1); + + /* XXX Perhaps this is only for TBI */ + if (sc->sc_mediatype != WM_MEDIATYPE_SERDES) + sc->sc_ctrl &= ~CTRL_SWDPIO(1); + if (sc->sc_mediatype == WM_MEDIATYPE_SERDES) sc->sc_ctrl &= ~CTRL_LRST; @@ -7542,7 +7778,7 @@ wm_tbi_mediainit(struct wm_softc *sc) #define ADD(ss, mm, dd) \ do { \ aprint_normal("%s%s", sep, ss); \ - ifmedia_add(&sc->sc_mii.mii_media, IFM_ETHER|(mm), (dd), NULL); \ + ifmedia_add(&sc->sc_mii.mii_media, IFM_ETHER | (mm), (dd), NULL); \ sep = ", "; \ } while (/*CONSTCOND*/0) @@ -7551,12 +7787,12 @@ do { \ /* Only 82545 is LX */ if (sc->sc_type == WM_T_82545) { ADD("1000baseLX", IFM_1000_LX, ANAR_X_HD); - ADD("1000baseLX-FDX", IFM_1000_LX|IFM_FDX, ANAR_X_FD); + ADD("1000baseLX-FDX", IFM_1000_LX | IFM_FDX, ANAR_X_FD); } else { ADD("1000baseSX", IFM_1000_SX, ANAR_X_HD); - ADD("1000baseSX-FDX", IFM_1000_SX|IFM_FDX, ANAR_X_FD); + ADD("1000baseSX-FDX", IFM_1000_SX | IFM_FDX, ANAR_X_FD); } - ADD("auto", IFM_AUTO, ANAR_X_FD|ANAR_X_HD); + ADD("auto", IFM_AUTO, ANAR_X_FD | ANAR_X_HD); aprint_normal("\n"); #undef ADD @@ -7565,43 +7801,6 @@ do { \ } /* - * wm_tbi_mediastatus: [ifmedia interface function] - * - * Get the current interface media status on a 1000BASE-X device. - */ -static void -wm_tbi_mediastatus(struct ifnet *ifp, struct ifmediareq *ifmr) -{ - struct wm_softc *sc = ifp->if_softc; - uint32_t ctrl, status; - - ifmr->ifm_status = IFM_AVALID; - ifmr->ifm_active = IFM_ETHER; - - status = CSR_READ(sc, WMREG_STATUS); - if ((status & STATUS_LU) == 0) { - ifmr->ifm_active |= IFM_NONE; - return; - } - - ifmr->ifm_status |= IFM_ACTIVE; - /* Only 82545 is LX */ - if (sc->sc_type == WM_T_82545) - ifmr->ifm_active |= IFM_1000_LX; - else - ifmr->ifm_active |= IFM_1000_SX; - if (CSR_READ(sc, WMREG_STATUS) & STATUS_FD) - ifmr->ifm_active |= IFM_FDX; - else - ifmr->ifm_active |= IFM_HDX; - ctrl = CSR_READ(sc, WMREG_CTRL); - if (ctrl & CTRL_RFCE) - ifmr->ifm_active |= IFM_FLOW | IFM_ETH_RXPAUSE; - if (ctrl & CTRL_TFCE) - ifmr->ifm_active |= IFM_FLOW | IFM_ETH_TXPAUSE; -} - -/* * wm_tbi_mediachange: [ifmedia interface function] * * Set hardware to newly-selected media on a 1000BASE-X device. @@ -7614,15 +7813,16 @@ wm_tbi_mediachange(struct ifnet *ifp) uint32_t status; int i; - if (sc->sc_mediatype == WM_MEDIATYPE_SERDES) - return 0; + if (sc->sc_mediatype == WM_MEDIATYPE_SERDES) { + /* XXX need some work for >= 82571 and < 82575 */ + if (sc->sc_type < WM_T_82575) + return 0; + } if ((sc->sc_type == WM_T_82571) || (sc->sc_type == WM_T_82572) || (sc->sc_type >= WM_T_82575)) CSR_WRITE(sc, WMREG_SCTL, SCTL_DISABLE_SERDES_LOOPBACK); - /* XXX power_up_serdes_link_82575() */ - sc->sc_ctrl &= ~CTRL_LRST; sc->sc_txcw = TXCW_ANE; if (IFM_SUBTYPE(ife->ifm_media) == IFM_AUTO) @@ -7706,49 +7906,141 @@ wm_tbi_mediachange(struct ifnet *ifp) sc->sc_tbi_linkup = 0; } - wm_tbi_set_linkled(sc); + wm_tbi_serdes_set_linkled(sc); return 0; } /* - * wm_tbi_set_linkled: + * wm_tbi_mediastatus: [ifmedia interface function] * - * Update the link LED on 1000BASE-X devices. + * Get the current interface media status on a 1000BASE-X device. */ static void -wm_tbi_set_linkled(struct wm_softc *sc) +wm_tbi_mediastatus(struct ifnet *ifp, struct ifmediareq *ifmr) { + struct wm_softc *sc = ifp->if_softc; + uint32_t ctrl, status; - if (sc->sc_tbi_linkup) - sc->sc_ctrl |= CTRL_SWDPIN(0); + ifmr->ifm_status = IFM_AVALID; + ifmr->ifm_active = IFM_ETHER; + + status = CSR_READ(sc, WMREG_STATUS); + if ((status & STATUS_LU) == 0) { + ifmr->ifm_active |= IFM_NONE; + return; + } + + ifmr->ifm_status |= IFM_ACTIVE; + /* Only 82545 is LX */ + if (sc->sc_type == WM_T_82545) + ifmr->ifm_active |= IFM_1000_LX; else - sc->sc_ctrl &= ~CTRL_SWDPIN(0); + ifmr->ifm_active |= IFM_1000_SX; + if (CSR_READ(sc, WMREG_STATUS) & STATUS_FD) + ifmr->ifm_active |= IFM_FDX; + else + ifmr->ifm_active |= IFM_HDX; + ctrl = CSR_READ(sc, WMREG_CTRL); + if (ctrl & CTRL_RFCE) + ifmr->ifm_active |= IFM_FLOW | IFM_ETH_RXPAUSE; + if (ctrl & CTRL_TFCE) + ifmr->ifm_active |= IFM_FLOW | IFM_ETH_TXPAUSE; +} - /* 82540 or newer devices are active low */ - sc->sc_ctrl ^= (sc->sc_type >= WM_T_82540) ? CTRL_SWDPIN(0) : 0; +/* XXX TBI only */ +static int +wm_check_for_link(struct wm_softc *sc) +{ + struct ifmedia_entry *ife = sc->sc_mii.mii_media.ifm_cur; + uint32_t rxcw; + uint32_t ctrl; + uint32_t status; + uint32_t sig; - CSR_WRITE(sc, WMREG_CTRL, sc->sc_ctrl); + if (sc->sc_mediatype == WM_MEDIATYPE_SERDES) { + /* XXX need some work for >= 82571 */ + if (sc->sc_type >= WM_T_82571) { + sc->sc_tbi_linkup = 1; + return 0; + } + } + + rxcw = CSR_READ(sc, WMREG_RXCW); + ctrl = CSR_READ(sc, WMREG_CTRL); + status = CSR_READ(sc, WMREG_STATUS); + + sig = (sc->sc_type > WM_T_82544) ? CTRL_SWDPIN(1) : 0; + + DPRINTF(WM_DEBUG_LINK, + ("%s: %s: sig = %d, status_lu = %d, rxcw_c = %d\n", + device_xname(sc->sc_dev), __func__, + ((ctrl & CTRL_SWDPIN(1)) == sig), + ((status & STATUS_LU) != 0), ((rxcw & RXCW_C) != 0))); + + /* + * SWDPIN LU RXCW + * 0 0 0 + * 0 0 1 (should not happen) + * 0 1 0 (should not happen) + * 0 1 1 (should not happen) + * 1 0 0 Disable autonego and force linkup + * 1 0 1 got /C/ but not linkup yet + * 1 1 0 (linkup) + * 1 1 1 If IFM_AUTO, back to autonego + * + */ + if (((ctrl & CTRL_SWDPIN(1)) == sig) + && ((status & STATUS_LU) == 0) + && ((rxcw & RXCW_C) == 0)) { + DPRINTF(WM_DEBUG_LINK, ("%s: force linkup and fullduplex\n", + __func__)); + sc->sc_tbi_linkup = 0; + /* Disable auto-negotiation in the TXCW register */ + CSR_WRITE(sc, WMREG_TXCW, (sc->sc_txcw & ~TXCW_ANE)); + + /* + * Force link-up and also force full-duplex. + * + * NOTE: CTRL was updated TFCE and RFCE automatically, + * so we should update sc->sc_ctrl + */ + sc->sc_ctrl = ctrl | CTRL_SLU | CTRL_FD; + CSR_WRITE(sc, WMREG_CTRL, sc->sc_ctrl); + } else if (((status & STATUS_LU) != 0) + && ((rxcw & RXCW_C) != 0) + && (IFM_SUBTYPE(ife->ifm_media) == IFM_AUTO)) { + sc->sc_tbi_linkup = 1; + DPRINTF(WM_DEBUG_LINK, ("%s: go back to autonego\n", + __func__)); + CSR_WRITE(sc, WMREG_TXCW, sc->sc_txcw); + CSR_WRITE(sc, WMREG_CTRL, (ctrl & ~CTRL_SLU)); + } else if (((ctrl & CTRL_SWDPIN(1)) == sig) + && ((rxcw & RXCW_C) != 0)) { + DPRINTF(WM_DEBUG_LINK, ("/C/")); + } else { + DPRINTF(WM_DEBUG_LINK, ("%s: %x,%x,%x\n", __func__, rxcw, ctrl, + status)); + } + + return 0; } /* - * wm_tbi_check_link: + * wm_tbi_tick: * - * Check the link on 1000BASE-X devices. + * Check the link on TBI devices. + * This function acts as mii_tick(). */ static void -wm_tbi_check_link(struct wm_softc *sc) +wm_tbi_tick(struct wm_softc *sc) { - struct ifmedia_entry *ife = sc->sc_mii.mii_media.ifm_cur; + struct mii_data *mii = &sc->sc_mii; + struct ifmedia_entry *ife = mii->mii_media.ifm_cur; uint32_t status; KASSERT(WM_TX_LOCKED(sc)); - if (sc->sc_mediatype == WM_MEDIATYPE_SERDES) { - sc->sc_tbi_linkup = 1; - return; - } - status = CSR_READ(sc, WMREG_STATUS); /* XXX is this needed? */ @@ -7767,36 +8059,227 @@ wm_tbi_check_link(struct wm_softc *sc) device_xname(sc->sc_dev), (status & STATUS_FD) ? "FDX" : "HDX")); sc->sc_tbi_linkup = 1; + sc->sc_tbi_serdes_ticks = 0; } - if ((sc->sc_ethercom.ec_if.if_flags & IFF_UP) - && ((status & STATUS_LU) == 0)) { + if ((sc->sc_ethercom.ec_if.if_flags & IFF_UP) == 0) + goto setled; + + if ((status & STATUS_LU) == 0) { sc->sc_tbi_linkup = 0; - if (IFM_SUBTYPE(ife->ifm_media) == IFM_AUTO) { - /* If the timer expired, retry autonegotiation */ - if (++sc->sc_tbi_ticks >= sc->sc_tbi_anegticks) { - DPRINTF(WM_DEBUG_LINK, ("EXPIRE\n")); - sc->sc_tbi_ticks = 0; - /* - * Reset the link, and let autonegotiation do - * its thing - */ - sc->sc_ctrl |= CTRL_LRST; - CSR_WRITE(sc, WMREG_CTRL, sc->sc_ctrl); - CSR_WRITE_FLUSH(sc); - delay(1000); - sc->sc_ctrl &= ~CTRL_LRST; - CSR_WRITE(sc, WMREG_CTRL, sc->sc_ctrl); - CSR_WRITE_FLUSH(sc); - delay(1000); - CSR_WRITE(sc, WMREG_TXCW, - sc->sc_txcw & ~TXCW_ANE); - CSR_WRITE(sc, WMREG_TXCW, sc->sc_txcw); - } + /* If the timer expired, retry autonegotiation */ + if ((IFM_SUBTYPE(ife->ifm_media) == IFM_AUTO) + && (++sc->sc_tbi_serdes_ticks + >= sc->sc_tbi_serdes_anegticks)) { + DPRINTF(WM_DEBUG_LINK, ("EXPIRE\n")); + sc->sc_tbi_serdes_ticks = 0; + /* + * Reset the link, and let autonegotiation do + * its thing + */ + sc->sc_ctrl |= CTRL_LRST; + CSR_WRITE(sc, WMREG_CTRL, sc->sc_ctrl); + CSR_WRITE_FLUSH(sc); + delay(1000); + sc->sc_ctrl &= ~CTRL_LRST; + CSR_WRITE(sc, WMREG_CTRL, sc->sc_ctrl); + CSR_WRITE_FLUSH(sc); + delay(1000); + CSR_WRITE(sc, WMREG_TXCW, + sc->sc_txcw & ~TXCW_ANE); + CSR_WRITE(sc, WMREG_TXCW, sc->sc_txcw); + } + } + +setled: + wm_tbi_serdes_set_linkled(sc); +} + +/* SERDES related */ +static void +wm_serdes_power_up_link_82575(struct wm_softc *sc) +{ + uint32_t reg; + + if ((sc->sc_mediatype != WM_MEDIATYPE_SERDES) + && ((sc->sc_flags & WM_F_SGMII) == 0)) + return; + + reg = CSR_READ(sc, WMREG_PCS_CFG); + reg |= PCS_CFG_PCS_EN; + CSR_WRITE(sc, WMREG_PCS_CFG, reg); + + reg = CSR_READ(sc, WMREG_CTRL_EXT); + reg &= ~CTRL_EXT_SWDPIN(3); + CSR_WRITE(sc, WMREG_CTRL_EXT, reg); + CSR_WRITE_FLUSH(sc); +} + +static int +wm_serdes_mediachange(struct ifnet *ifp) +{ + struct wm_softc *sc = ifp->if_softc; + bool pcs_autoneg = true; /* XXX */ + uint32_t ctrl_ext, pcs_lctl, reg; + + /* XXX Currently, this function is not called on 8257[12] */ + if ((sc->sc_type == WM_T_82571) || (sc->sc_type == WM_T_82572) + || (sc->sc_type >= WM_T_82575)) + CSR_WRITE(sc, WMREG_SCTL, SCTL_DISABLE_SERDES_LOOPBACK); + + wm_serdes_power_up_link_82575(sc); + + sc->sc_ctrl |= CTRL_SLU; + + if ((sc->sc_type == WM_T_82575) || (sc->sc_type == WM_T_82576)) + sc->sc_ctrl |= CTRL_SWDPIN(0) | CTRL_SWDPIN(1); + + ctrl_ext = CSR_READ(sc, WMREG_CTRL_EXT); + pcs_lctl = CSR_READ(sc, WMREG_PCS_LCTL); + switch (ctrl_ext & CTRL_EXT_LINK_MODE_MASK) { + case CTRL_EXT_LINK_MODE_SGMII: + pcs_autoneg = true; + pcs_lctl &= ~PCS_LCTL_AN_TIMEOUT; + break; + case CTRL_EXT_LINK_MODE_1000KX: + pcs_autoneg = false; + /* FALLTHROUGH */ + default: + if ((sc->sc_type == WM_T_82575) + || (sc->sc_type == WM_T_82576)) { + if ((sc->sc_flags & WM_F_PCS_DIS_AUTONEGO) != 0) + pcs_autoneg = false; + } + sc->sc_ctrl |= CTRL_SPEED_1000 | CTRL_FRCSPD | CTRL_FD + | CTRL_FRCFDX; + pcs_lctl |= PCS_LCTL_FSV_1000 | PCS_LCTL_FDV_FULL; + } + CSR_WRITE(sc, WMREG_CTRL, sc->sc_ctrl); + + if (pcs_autoneg) { + pcs_lctl |= PCS_LCTL_AN_ENABLE | PCS_LCTL_AN_RESTART; + pcs_lctl &= ~PCS_LCTL_FORCE_FC; + + reg = CSR_READ(sc, WMREG_PCS_ANADV); + reg &= ~(TXCW_ASYM_PAUSE | TXCW_SYM_PAUSE); + reg |= TXCW_ASYM_PAUSE | TXCW_SYM_PAUSE; + CSR_WRITE(sc, WMREG_PCS_ANADV, reg); + } else + pcs_lctl |= PCS_LCTL_FSD | PCS_LCTL_FORCE_FC; + + CSR_WRITE(sc, WMREG_PCS_LCTL, pcs_lctl); + + + return 0; +} + +static void +wm_serdes_mediastatus(struct ifnet *ifp, struct ifmediareq *ifmr) +{ + struct wm_softc *sc = ifp->if_softc; + struct mii_data *mii = &sc->sc_mii; + struct ifmedia_entry *ife = sc->sc_mii.mii_media.ifm_cur; + uint32_t pcs_adv, pcs_lpab, reg; + + ifmr->ifm_status = IFM_AVALID; + ifmr->ifm_active = IFM_ETHER; + + /* Check PCS */ + reg = CSR_READ(sc, WMREG_PCS_LSTS); + if ((reg & PCS_LSTS_LINKOK) == 0) { + ifmr->ifm_active |= IFM_NONE; + sc->sc_tbi_linkup = 0; + goto setled; + } + + sc->sc_tbi_linkup = 1; + ifmr->ifm_status |= IFM_ACTIVE; + ifmr->ifm_active |= IFM_1000_SX; /* XXX */ + if ((reg & PCS_LSTS_FDX) != 0) + ifmr->ifm_active |= IFM_FDX; + else + ifmr->ifm_active |= IFM_HDX; + mii->mii_media_active &= ~IFM_ETH_FMASK; + if (IFM_SUBTYPE(ife->ifm_media) == IFM_AUTO) { + /* Check flow */ + reg = CSR_READ(sc, WMREG_PCS_LSTS); + if ((reg & PCS_LSTS_AN_COMP) == 0) { + DPRINTF(WM_DEBUG_LINK, ("XXX LINKOK but not ACOMP\n")); + goto setled; + } + pcs_adv = CSR_READ(sc, WMREG_PCS_ANADV); + pcs_lpab = CSR_READ(sc, WMREG_PCS_LPAB); + DPRINTF(WM_DEBUG_LINK, + ("XXX AN result(2) %08x, %08x\n", pcs_adv, pcs_lpab)); + if ((pcs_adv & TXCW_SYM_PAUSE) + && (pcs_lpab & TXCW_SYM_PAUSE)) { + mii->mii_media_active |= IFM_FLOW + | IFM_ETH_TXPAUSE | IFM_ETH_RXPAUSE; + } else if (((pcs_adv & TXCW_SYM_PAUSE) == 0) + && (pcs_adv & TXCW_ASYM_PAUSE) + && (pcs_lpab & TXCW_SYM_PAUSE) + && (pcs_lpab & TXCW_ASYM_PAUSE)) { + mii->mii_media_active |= IFM_FLOW + | IFM_ETH_TXPAUSE; + } else if ((pcs_adv & TXCW_SYM_PAUSE) + && (pcs_adv & TXCW_ASYM_PAUSE) + && ((pcs_lpab & TXCW_SYM_PAUSE) == 0) + && (pcs_lpab & TXCW_ASYM_PAUSE)) { + mii->mii_media_active |= IFM_FLOW + | IFM_ETH_RXPAUSE; + } else { + } + } + ifmr->ifm_active = (ifmr->ifm_active & ~IFM_ETH_FMASK) + | (mii->mii_media_active & IFM_ETH_FMASK); +setled: + wm_tbi_serdes_set_linkled(sc); +} + +/* + * wm_serdes_tick: + * + * Check the link on serdes devices. + */ +static void +wm_serdes_tick(struct wm_softc *sc) +{ + struct ifnet *ifp = &sc->sc_ethercom.ec_if; + struct mii_data *mii = &sc->sc_mii; + struct ifmedia_entry *ife = mii->mii_media.ifm_cur; + uint32_t reg; + + KASSERT(WM_TX_LOCKED(sc)); + + mii->mii_media_status = IFM_AVALID; + mii->mii_media_active = IFM_ETHER; + + /* Check PCS */ + reg = CSR_READ(sc, WMREG_PCS_LSTS); + if ((reg & PCS_LSTS_LINKOK) != 0) { + mii->mii_media_status |= IFM_ACTIVE; + sc->sc_tbi_linkup = 1; + sc->sc_tbi_serdes_ticks = 0; + mii->mii_media_active |= IFM_1000_SX; /* XXX */ + if ((reg & PCS_LSTS_FDX) != 0) + mii->mii_media_active |= IFM_FDX; + else + mii->mii_media_active |= IFM_HDX; + } else { + mii->mii_media_status |= IFM_NONE; + sc->sc_tbi_linkup = 0; + /* If the timer expired, retry autonegotiation */ + if ((IFM_SUBTYPE(ife->ifm_media) == IFM_AUTO) + && (++sc->sc_tbi_serdes_ticks + >= sc->sc_tbi_serdes_anegticks)) { + DPRINTF(WM_DEBUG_LINK, ("EXPIRE\n")); + sc->sc_tbi_serdes_ticks = 0; + /* XXX */ + wm_serdes_mediachange(ifp); } } - wm_tbi_set_linkled(sc); + wm_tbi_serdes_set_linkled(sc); } /* SFP related */ @@ -7984,7 +8467,7 @@ wm_nvm_read_uwire(struct wm_softc *sc, i delay(2); } /* XXX: end of workaround */ - + /* Set CHIP SELECT. */ reg |= EECD_CS; CSR_WRITE(sc, WMREG_EECD, reg); @@ -8095,7 +8578,7 @@ wm_nvm_ready_spi(struct wm_softc *sc) break; } if (usec >= SPI_MAX_RETRIES) { - aprint_error_dev(sc->sc_dev, "EEPROM failed to become ready\n"); + aprint_error_dev(sc->sc_dev,"EEPROM failed to become ready\n"); return 1; } return 0; @@ -8534,7 +9017,7 @@ wm_nvm_read_word_invm(struct wm_softc *s uint8_t record_type, word_address; for (i = 0; i < INVM_SIZE; i++) { - invm_dword = CSR_READ(sc, E1000_INVM_DATA_REG(i)); + invm_dword = CSR_READ(sc, WM_INVM_DATA_REG(i)); /* Get record type */ record_type = INVM_DWORD_TO_RECORD_TYPE(invm_dword); if (record_type == INVM_UNINITIALIZED_STRUCTURE) @@ -8619,7 +9102,7 @@ wm_nvm_read_invm(struct wm_softc *sc, in return rv; } -/* Lock, detecting NVM type, validate checksum and read */ +/* Lock, detecting NVM type, validate checksum, version and read */ /* * wm_nvm_acquire: @@ -8816,6 +9299,133 @@ wm_nvm_validate_checksum(struct wm_softc return 0; } +static void +wm_nvm_version_invm(struct wm_softc *sc) +{ + uint32_t dword; + + /* + * Linux's code to decode version is very strange, so we don't + * obey that algorithm and just use word 61 as the document. + * Perhaps it's not perfect though... + * + * Example: + * + * Word61: 00800030 -> Version 0.6 (I211 spec update notes about 0.6) + */ + dword = CSR_READ(sc, WM_INVM_DATA_REG(61)); + dword = __SHIFTOUT(dword, INVM_VER_1); + sc->sc_nvm_ver_major = __SHIFTOUT(dword, INVM_MAJOR); + sc->sc_nvm_ver_minor = __SHIFTOUT(dword, INVM_MINOR); +} + +static void +wm_nvm_version(struct wm_softc *sc) +{ + uint16_t major, minor, build, patch; + uint16_t uid0, uid1; + uint16_t nvm_data; + uint16_t off; + bool check_version = false; + bool check_optionrom = false; + bool have_build = false; + + /* + * Version format: + * + * XYYZ + * X0YZ + * X0YY + * + * Example: + * + * 82571 0x50a2 5.10.2? (the spec update notes about 5.6-5.10) + * 82571 0x50a6 5.10.6? + * 82572 0x506a 5.6.10? + * 82572EI 0x5069 5.6.9? + * 82574L 0x1080 1.8.0? (the spec update notes about 2.1.4) + * 0x2013 2.1.3? + * 82583 0x10a0 1.10.0? (document says it's default vaule) + */ + wm_nvm_read(sc, NVM_OFF_IMAGE_UID1, 1, &uid1); + switch (sc->sc_type) { + case WM_T_82571: + case WM_T_82572: + case WM_T_82574: + case WM_T_82583: + check_version = true; + check_optionrom = true; + have_build = true; + break; + case WM_T_82575: + case WM_T_82576: + case WM_T_82580: + if ((uid1 & NVM_MAJOR_MASK) != NVM_UID_VALID) + check_version = true; + break; + case WM_T_I211: + wm_nvm_version_invm(sc); + goto printver; + case WM_T_I210: + if (!wm_nvm_get_flash_presence_i210(sc)) { + wm_nvm_version_invm(sc); + goto printver; + } + /* FALLTHROUGH */ + case WM_T_I350: + case WM_T_I354: + check_version = true; + check_optionrom = true; + break; + default: + return; + } + if (check_version) { + wm_nvm_read(sc, NVM_OFF_VERSION, 1, &nvm_data); + major = (nvm_data & NVM_MAJOR_MASK) >> NVM_MAJOR_SHIFT; + if (have_build || ((nvm_data & 0x0f00) != 0x0000)) { + minor = (nvm_data & NVM_MINOR_MASK) >> NVM_MINOR_SHIFT; + build = nvm_data & NVM_BUILD_MASK; + have_build = true; + } else + minor = nvm_data & 0x00ff; + + /* Decimal */ + minor = (minor / 16) * 10 + (minor % 16); + sc->sc_nvm_ver_major = major; + sc->sc_nvm_ver_minor = minor; + +printver: + aprint_verbose(", version %d.%d", sc->sc_nvm_ver_major, + sc->sc_nvm_ver_minor); + if (have_build) { + sc->sc_nvm_ver_build = build; + aprint_verbose(".%d", build); + } + } + if (check_optionrom) { + wm_nvm_read(sc, NVM_OFF_COMB_VER_PTR, 1, &off); + /* Option ROM Version */ + if ((off != 0x0000) && (off != 0xffff)) { + off += NVM_COMBO_VER_OFF; + wm_nvm_read(sc, off + 1, 1, &uid1); + wm_nvm_read(sc, off, 1, &uid0); + if ((uid0 != 0) && (uid0 != 0xffff) + && (uid1 != 0) && (uid1 != 0xffff)) { + /* 16bits */ + major = uid0 >> 8; + build = (uid0 << 8) | (uid1 >> 8); + patch = uid1 & 0x00ff; + aprint_verbose(", option ROM Version %d.%d.%d", + major, build, patch); + } + } + } + + wm_nvm_read(sc, NVM_OFF_IMAGE_UID0, 1, &uid0); + aprint_verbose(", Image Unique ID %08x", (uid1 << 16) | uid0); +} + /* * wm_nvm_read: * @@ -8896,7 +9506,8 @@ wm_get_swsm_semaphore(struct wm_softc *s } if (timeout == 0) { - aprint_error_dev(sc->sc_dev, "could not acquire SWSM SWESMBI\n"); + aprint_error_dev(sc->sc_dev, + "could not acquire SWSM SWESMBI\n"); /* Release semaphores */ wm_put_swsm_semaphore(sc); return 1; @@ -8972,11 +9583,11 @@ wm_get_swfwhw_semaphore(struct wm_softc for (timeout = 0; timeout < 200; timeout++) { ext_ctrl = CSR_READ(sc, WMREG_EXTCNFCTR); - ext_ctrl |= E1000_EXTCNF_CTRL_SWFLAG; + ext_ctrl |= EXTCNFCTR_MDIO_SW_OWNERSHIP; CSR_WRITE(sc, WMREG_EXTCNFCTR, ext_ctrl); ext_ctrl = CSR_READ(sc, WMREG_EXTCNFCTR); - if (ext_ctrl & E1000_EXTCNF_CTRL_SWFLAG) + if (ext_ctrl & EXTCNFCTR_MDIO_SW_OWNERSHIP) return 0; delay(5000); } @@ -8989,8 +9600,9 @@ static void wm_put_swfwhw_semaphore(struct wm_softc *sc) { uint32_t ext_ctrl; + ext_ctrl = CSR_READ(sc, WMREG_EXTCNFCTR); - ext_ctrl &= ~E1000_EXTCNF_CTRL_SWFLAG; + ext_ctrl &= ~EXTCNFCTR_MDIO_SW_OWNERSHIP; CSR_WRITE(sc, WMREG_EXTCNFCTR, ext_ctrl); } @@ -9036,6 +9648,7 @@ wm_put_hw_semaphore_82573(struct wm_soft * BMC, AMT, suspend/resume and EEE. */ +#ifdef WM_WOL static int wm_check_mng_mode(struct wm_softc *sc) { @@ -9076,7 +9689,8 @@ wm_check_mng_mode_ich8lan(struct wm_soft fwsm = CSR_READ(sc, WMREG_FWSM); - if ((fwsm & FWSM_MODE_MASK) == (MNG_ICH_IAMT_MODE << FWSM_MODE_SHIFT)) + if (((fwsm & FWSM_FW_VALID) != 0) + && (__SHIFTOUT(fwsm, FWSM_MODE) == MNG_ICH_IAMT_MODE)) return 1; return 0; @@ -9102,11 +9716,12 @@ wm_check_mng_mode_generic(struct wm_soft fwsm = CSR_READ(sc, WMREG_FWSM); - if ((fwsm & FWSM_MODE_MASK) == (MNG_IAMT_MODE << FWSM_MODE_SHIFT)) + if (__SHIFTOUT(fwsm, FWSM_MODE) == MNG_IAMT_MODE) return 1; return 0; } +#endif /* WM_WOL */ static int wm_enable_mng_pass_thru(struct wm_softc *sc) @@ -9127,8 +9742,7 @@ wm_enable_mng_pass_thru(struct wm_softc fwsm = CSR_READ(sc, WMREG_FWSM); factps = CSR_READ(sc, WMREG_FACTPS); if (((factps & FACTPS_MNGCG) == 0) - && ((fwsm & FWSM_MODE_MASK) - == (MNG_ICH_IAMT_MODE << FWSM_MODE_SHIFT))) + && (__SHIFTOUT(fwsm, FWSM_MODE) == MNG_ICH_IAMT_MODE)) return 1; } else if ((sc->sc_type == WM_T_82574) || (sc->sc_type == WM_T_82583)){ uint16_t data; @@ -9148,10 +9762,12 @@ wm_enable_mng_pass_thru(struct wm_softc return 0; } -static int -wm_check_reset_block(struct wm_softc *sc) +static bool +wm_phy_resetisblocked(struct wm_softc *sc) { + bool blocked = false; uint32_t reg; + int i = 0; switch (sc->sc_type) { case WM_T_ICH8: @@ -9160,11 +9776,16 @@ wm_check_reset_block(struct wm_softc *sc case WM_T_PCH: case WM_T_PCH2: case WM_T_PCH_LPT: - reg = CSR_READ(sc, WMREG_FWSM); - if ((reg & FWSM_RSPCIPHY) != 0) - return 0; - else - return -1; + do { + reg = CSR_READ(sc, WMREG_FWSM); + if ((reg & FWSM_RSPCIPHY) == 0) { + blocked = true; + delay(10*1000); + continue; + } + blocked = false; + } while (blocked && (i++ < 10)); + return blocked; break; case WM_T_82571: case WM_T_82572: @@ -9174,16 +9795,16 @@ wm_check_reset_block(struct wm_softc *sc case WM_T_80003: reg = CSR_READ(sc, WMREG_MANC); if ((reg & MANC_BLK_PHY_RST_ON_IDE) != 0) - return -1; + return true; else - return 0; + return false; break; default: /* no problem */ break; } - return 0; + return false; } static void @@ -9255,7 +9876,7 @@ wm_smbustopci(struct wm_softc *sc) fwsm = CSR_READ(sc, WMREG_FWSM); if (((fwsm & FWSM_FW_VALID) == 0) - && ((wm_check_reset_block(sc) == 0))) { + && ((wm_phy_resetisblocked(sc) == false))) { sc->sc_ctrl |= CTRL_LANPHYPC_OVERRIDE; sc->sc_ctrl &= ~CTRL_LANPHYPC_VALUE; CSR_WRITE(sc, WMREG_CTRL, sc->sc_ctrl); @@ -9291,7 +9912,6 @@ wm_init_manageability(struct wm_softc *s manc |= MANC_EN_MNG2HOST; manc2h |= MANC2H_PORT_623| MANC2H_PORT_624; CSR_WRITE(sc, WMREG_MANC2H, manc2h); - } CSR_WRITE(sc, WMREG_MANC, manc); @@ -9334,7 +9954,7 @@ wm_get_wakeup(struct wm_softc *sc) case WM_T_82580: case WM_T_I350: case WM_T_I354: - if ((CSR_READ(sc, WMREG_FWSM) & FWSM_MODE_MASK) != 0) + if ((CSR_READ(sc, WMREG_FWSM) & FWSM_MODE) != 0) sc->sc_flags |= WM_F_ARC_SUBSYS_VALID; sc->sc_flags |= WM_F_ASF_FIRMWARE_PRES; break; @@ -9519,6 +10139,29 @@ wm_enable_wakeup(struct wm_softc *sc) } #endif /* WM_WOL */ +/* LPLU */ + +static void +wm_lplu_d0_disable(struct wm_softc *sc) +{ + uint32_t reg; + + reg = CSR_READ(sc, WMREG_PHY_CTRL); + reg &= ~(PHY_CTRL_GBE_DIS | PHY_CTRL_D0A_LPLU); + CSR_WRITE(sc, WMREG_PHY_CTRL, reg); +} + +static void +wm_lplu_d0_disable_pch(struct wm_softc *sc) +{ + uint32_t reg; + + reg = wm_gmii_hv_readreg(sc->sc_dev, 1, HV_OEM_BITS); + reg &= ~(HV_OEM_BITS_A1KDIS | HV_OEM_BITS_LPLU); + reg |= HV_OEM_BITS_ANEGNOW; + wm_gmii_hv_writereg(sc->sc_dev, 1, HV_OEM_BITS, reg); +} + /* EEE */ static void @@ -9555,13 +10198,14 @@ wm_set_eee_i350(struct wm_softc *sc) static void wm_kmrn_lock_loss_workaround_ich8lan(struct wm_softc *sc) { +#if 0 int miistatus, active, i; int reg; miistatus = sc->sc_mii.mii_media_status; /* If the link is not up, do nothing */ - if ((miistatus & IFM_ACTIVE) != 0) + if ((miistatus & IFM_ACTIVE) == 0) return; active = sc->sc_mii.mii_media_active; @@ -9574,7 +10218,7 @@ wm_kmrn_lock_loss_workaround_ich8lan(str /* read twice */ reg = wm_gmii_i80003_readreg(sc->sc_dev, 1, IGP3_KMRN_DIAG); reg = wm_gmii_i80003_readreg(sc->sc_dev, 1, IGP3_KMRN_DIAG); - if ((reg & IGP3_KMRN_DIAG_PCS_LOCK_LOSS) != 0) + if ((reg & IGP3_KMRN_DIAG_PCS_LOCK_LOSS) == 0) goto out; /* GOOD! */ /* Reset the PHY */ @@ -9595,6 +10239,7 @@ wm_kmrn_lock_loss_workaround_ich8lan(str out: return; +#endif } /* WOL from S5 stops working */ @@ -9757,3 +10402,104 @@ wm_reset_init_script_82575(struct wm_sof wm_82575_write_8bit_ctlr_reg(sc, WMREG_SCCTL, 0x14, 0x00); wm_82575_write_8bit_ctlr_reg(sc, WMREG_SCCTL, 0x10, 0x00); } + +static void +wm_reset_mdicnfg_82580(struct wm_softc *sc) +{ + uint32_t reg; + uint16_t nvmword; + int rv; + + if ((sc->sc_flags & WM_F_SGMII) == 0) + return; + + rv = wm_nvm_read(sc, NVM_OFF_LAN_FUNC_82580(sc->sc_funcid) + + NVM_OFF_CFG3_PORTA, 1, &nvmword); + if (rv != 0) { + aprint_error_dev(sc->sc_dev, "%s: failed to read NVM\n", + __func__); + return; + } + + reg = CSR_READ(sc, WMREG_MDICNFG); + if (nvmword & NVM_CFG3_PORTA_EXT_MDIO) + reg |= MDICNFG_DEST; + if (nvmword & NVM_CFG3_PORTA_COM_MDIO) + reg |= MDICNFG_COM_MDIO; + CSR_WRITE(sc, WMREG_MDICNFG, reg); +} + +/* + * I210 Errata 25 and I211 Errata 10 + * Slow System Clock. + */ +static void +wm_pll_workaround_i210(struct wm_softc *sc) +{ + uint32_t mdicnfg, wuc; + uint32_t reg; + pcireg_t pcireg; + uint32_t pmreg; + uint16_t nvmword, tmp_nvmword; + int phyval; + bool wa_done = false; + int i; + + /* Save WUC and MDICNFG registers */ + wuc = CSR_READ(sc, WMREG_WUC); + mdicnfg = CSR_READ(sc, WMREG_MDICNFG); + + reg = mdicnfg & ~MDICNFG_DEST; + CSR_WRITE(sc, WMREG_MDICNFG, reg); + + if (wm_nvm_read(sc, INVM_AUTOLOAD, 1, &nvmword) != 0) + nvmword = INVM_DEFAULT_AL; + tmp_nvmword = nvmword | INVM_PLL_WO_VAL; + + /* Get Power Management cap offset */ + if (pci_get_capability(sc->sc_pc, sc->sc_pcitag, PCI_CAP_PWRMGMT, + &pmreg, NULL) == 0) + return; + for (i = 0; i < WM_MAX_PLL_TRIES; i++) { + phyval = wm_gmii_gs40g_readreg(sc->sc_dev, 1, + GS40G_PHY_PLL_FREQ_PAGE | GS40G_PHY_PLL_FREQ_REG); + + if ((phyval & GS40G_PHY_PLL_UNCONF) != GS40G_PHY_PLL_UNCONF) { + break; /* OK */ + } + + wa_done = true; + /* Directly reset the internal PHY */ + reg = CSR_READ(sc, WMREG_CTRL); + CSR_WRITE(sc, WMREG_CTRL, reg | CTRL_PHY_RESET); + + reg = CSR_READ(sc, WMREG_CTRL_EXT); + reg |= CTRL_EXT_PHYPDEN | CTRL_EXT_SDLPE; + CSR_WRITE(sc, WMREG_CTRL_EXT, reg); + + CSR_WRITE(sc, WMREG_WUC, 0); + reg = (INVM_AUTOLOAD << 4) | (tmp_nvmword << 16); + CSR_WRITE(sc, WMREG_EEARBC_I210, reg); + + pcireg = pci_conf_read(sc->sc_pc, sc->sc_pcitag, + pmreg + PCI_PMCSR); + pcireg |= PCI_PMCSR_STATE_D3; + pci_conf_write(sc->sc_pc, sc->sc_pcitag, + pmreg + PCI_PMCSR, pcireg); + delay(1000); + pcireg &= ~PCI_PMCSR_STATE_D3; + pci_conf_write(sc->sc_pc, sc->sc_pcitag, + pmreg + PCI_PMCSR, pcireg); + + reg = (INVM_AUTOLOAD << 4) | (nvmword << 16); + CSR_WRITE(sc, WMREG_EEARBC_I210, reg); + + /* Restore WUC register */ + CSR_WRITE(sc, WMREG_WUC, wuc); + } + + /* Restore MDICNFG setting */ + CSR_WRITE(sc, WMREG_MDICNFG, mdicnfg); + if (wa_done) + aprint_verbose_dev(sc->sc_dev, "I210 workaround done\n"); +} Index: src/sys/dev/pci/if_wmreg.h diff -u src/sys/dev/pci/if_wmreg.h:1.60.2.4 src/sys/dev/pci/if_wmreg.h:1.60.2.5 --- src/sys/dev/pci/if_wmreg.h:1.60.2.4 Wed Jun 10 16:43:51 2015 +++ src/sys/dev/pci/if_wmreg.h Fri Feb 26 22:08:17 2016 @@ -1,4 +1,4 @@ -/* $NetBSD: if_wmreg.h,v 1.60.2.4 2015/06/10 16:43:51 snj Exp $ */ +/* $NetBSD: if_wmreg.h,v 1.60.2.5 2016/02/26 22:08:17 snj Exp $ */ /* * Copyright (c) 2001 Wasabi Systems, Inc. @@ -315,7 +315,9 @@ struct livengood_tcpip_ctxdesc { #define CTRL_EXT_SPD_BYPS (1U << 15) /* speed select bypass */ #define CTRL_EXT_IPS1 (1U << 16) /* invert power state bit 1 */ #define CTRL_EXT_RO_DIS (1U << 17) /* relaxed ordering disabled */ -#define CTRL_EXT_DMA_DYN_CLK (1U << 19) /* DMA Dymamic Gating Enable */ +#define CTRL_EXT_SDLPE (1U << 18) /* SerDes Low Power Enable */ +#define CTRL_EXT_DMA_DYN_CLK (1U << 19) /* DMA Dynamic Gating Enable */ +#define CTRL_EXT_PHYPDEN __BIT(20) #define CTRL_EXT_LINK_MODE_MASK 0x00C00000 #define CTRL_EXT_LINK_MODE_GMII 0x00000000 #define CTRL_EXT_LINK_MODE_KMRN 0x00000000 @@ -324,7 +326,6 @@ struct livengood_tcpip_ctxdesc { #define CTRL_EXT_LINK_MODE_PCIX_SERDES 0x00800000 #define CTRL_EXT_LINK_MODE_TBI 0x00C00000 #define CTRL_EXT_LINK_MODE_PCIE_SERDES 0x00C00000 -#define CTRL_EXT_PHYPDEN 0x00100000 #define CTRL_EXT_I2C_ENA 0x02000000 /* I2C enable */ #define CTRL_EXT_DRV_LOAD 0x10000000 @@ -414,6 +415,8 @@ struct livengood_tcpip_ctxdesc { #define WM_RAL_TABSIZE 15 /* RAL size for old devices */ #define WM_RAL_TABSIZE_ICH8 7 /* RAL size for ICH* and PCH* */ +#define WM_RAL_TABSIZE_PCH2 5 /* RAL size for PCH2 */ +#define WM_RAL_TABSIZE_PCH_LPT 12 /* RAL size for PCH_LPT */ #define WM_RAL_TABSIZE_82575 16 /* RAL size for 82575 */ #define WM_RAL_TABSIZE_82576 24 /* RAL size for 82576 and 82580 */ #define WM_RAL_TABSIZE_I350 32 /* RAL size for I350 */ @@ -656,14 +659,13 @@ struct livengood_tcpip_ctxdesc { #define EXTCNFCTR_MDIO_HW_OWNERSHIP 0x00000040 #define EXTCNFCTR_GATE_PHY_CFG 0x00000080 #define EXTCNFCTR_EXT_CNF_POINTER 0x0FFF0000 -#define E1000_EXTCNF_CTRL_SWFLAG EXTCNFCTR_MDIO_SW_OWNERSHIP #define WMREG_PHY_CTRL 0x0f10 /* PHY control */ #define PHY_CTRL_SPD_EN (1 << 0) #define PHY_CTRL_D0A_LPLU (1 << 1) #define PHY_CTRL_NOND0A_LPLU (1 << 2) #define PHY_CTRL_NOND0A_GBE_DIS (1 << 3) -#define PHY_CTRL_GBE_DIS (1 << 4) +#define PHY_CTRL_GBE_DIS (1 << 6) #define WMREG_PBA 0x1000 /* Packet Buffer Allocation */ #define PBA_BYTE_SHIFT 10 /* KB -> bytes */ @@ -671,6 +673,7 @@ struct livengood_tcpip_ctxdesc { #define PBA_8K 0x0008 #define PBA_10K 0x000a #define PBA_12K 0x000c +#define PBA_14K 0x000e #define PBA_16K 0x0010 /* 16K, default Tx allocation */ #define PBA_20K 0x0014 #define PBA_22K 0x0016 @@ -740,6 +743,9 @@ struct livengood_tcpip_ctxdesc { #define WMREG_EITR(x) (0x01680 + (0x4 * (x))) #define EITR_ITR_INT_MASK 0x0000ffff +#define WMREG_RXPBS 0x2404 /* Rx Packet Buffer Size */ +#define RXPBS_SIZE_MASK_82576 0x0000007F + #define WMREG_RDFH 0x2410 /* Receive Data FIFO Head */ #define WMREG_RDFT 0x2418 /* Receive Data FIFO Tail */ #define WMREG_RDFHS 0x2420 /* Receive Data FIFO Head Saved */ @@ -797,6 +803,28 @@ struct livengood_tcpip_ctxdesc { #define WMREG_TLPIC 0x4148 /* EEE Tx LPI Count */ #define WMREG_RLPIC 0x414c /* EEE Rx LPI Count */ +#define WMREG_PCS_CFG 0x4200 /* PCS Configuration */ +#define PCS_CFG_PCS_EN __BIT(3) + +#define WMREG_PCS_LCTL 0x4208 /* PCS Link Control */ +#define PCS_LCTL_FSV_1000 __BIT(2) /* AN Timeout Enable */ +#define PCS_LCTL_FDV_FULL __BIT(3) /* AN Timeout Enable */ +#define PCS_LCTL_FSD __BIT(4) /* AN Timeout Enable */ +#define PCS_LCTL_FORCE_FC __BIT(7) /* AN Timeout Enable */ +#define PCS_LCTL_AN_ENABLE __BIT(16) /* AN Timeout Enable */ +#define PCS_LCTL_AN_RESTART __BIT(17) /* AN Timeout Enable */ +#define PCS_LCTL_AN_TIMEOUT __BIT(18) /* AN Timeout Enable */ + +#define WMREG_PCS_LSTS 0x420c /* PCS Link Status */ +#define PCS_LSTS_LINKOK __BIT(0) +#define PCS_LSTS_SPEED_100 __BIT(1) +#define PCS_LSTS_SPEED_1000 __BIT(2) +#define PCS_LSTS_FDX __BIT(3) +#define PCS_LSTS_AN_COMP __BIT(16) + +#define WMREG_PCS_ANADV 0x4218 /* AN Advertsement */ +#define WMREG_PCS_LPAB 0x421c /* Link Partnet Ability */ + #define WMREG_RXCSUM 0x5000 /* Receive Checksum register */ #define RXCSUM_PCSS 0x000000ff /* Packet Checksum Start */ #define RXCSUM_IPOFL (1U << 8) /* IP checksum offload */ @@ -808,7 +836,8 @@ struct livengood_tcpip_ctxdesc { #define WMREG_RFCTL 0x5008 /* Receive Filter Control */ #define WMREG_RFCTL_NFSWDIS __BIT(6) /* NFS Write Disable */ #define WMREG_RFCTL_NFSRDIS __BIT(7) /* NFS Read Disable */ -#define WMREG_RFCTL_ACKDIS __BIT(13) /* ACK Accelerate Disable */ +#define WMREG_RFCTL_ACKDIS __BIT(12) /* ACK Accelerate Disable */ +#define WMREG_RFCTL_ACKD_DIS __BIT(13) /* ACK data Disable */ #define WMREG_RFCTL_IPV6EXDIS __BIT(16) /* IPv6 Extension Header Disable */ #define WMREG_RFCTL_NEWIPV6EXDIS __BIT(17) /* New IPv6 Extension Header */ @@ -836,7 +865,7 @@ struct livengood_tcpip_ctxdesc { #define MANC_EN_MAC_ADDR_FILTER 0x00100000 #define MANC_EN_MNG2HOST 0x00200000 -#define WMREG_MANC2H 0x5860 /* Manaegment Control To Host - RW */ +#define WMREG_MANC2H 0x5860 /* Management Control To Host - RW */ #define MANC2H_PORT_623 (1 << 5) #define MANC2H_PORT_624 (1 << 6) @@ -851,6 +880,7 @@ struct livengood_tcpip_ctxdesc { #define GCR_CMPL_TMOUT_10MS 0x00001000 #define GCR_CMPL_TMOUT_RESEND 0x00010000 #define GCR_CAP_VER2 0x00040000 +#define GCR_L1_ACT_WITHOUT_L0S_RX 0x08000000 #define WMREG_FACTPS 0x5b30 /* Function Active and Power State to MNG */ #define FACTPS_MNGCG 0x20000000 @@ -867,12 +897,12 @@ struct livengood_tcpip_ctxdesc { #define SWSM_DRV_LOAD 0x00000008 /* Driver Loaded Bit */ #define WMREG_FWSM 0x5b54 /* FW Semaphore */ -#define FWSM_MODE_MASK 0xe -#define FWSM_MODE_SHIFT 0x1 +#define FWSM_MODE __BITS(1, 3) #define MNG_ICH_IAMT_MODE 0x2 /* PT mode? */ #define MNG_IAMT_MODE 0x3 -#define FWSM_RSPCIPHY 0x00000040 /* Reset PHY on PCI reset */ -#define FWSM_FW_VALID 0x00008000 /* FW established a valid mode */ +#define FWSM_RSPCIPHY __BIT(6) /* Reset PHY on PCI reset */ +#define FWSM_WLOCK_MAC __BITS(7, 9) /* Reset PHY on PCI reset */ +#define FWSM_FW_VALID __BIT(15) /* FW established a valid mode */ #define WMREG_SWSM2 0x5b58 /* SW Semaphore 2 */ #define SWSM2_LOCK 0x00000002 /* Secondary driver semaphore bit */ @@ -895,6 +925,7 @@ struct livengood_tcpip_ctxdesc { #define EEC_FLASH_DETECTED (1U << 19) /* FLASH */ #define EEC_FLUPD (1U << 23) /* Update FLASH */ +#define WMREG_EEARBC_I210 0x12024 /* * NVM related values. @@ -928,6 +959,7 @@ struct livengood_tcpip_ctxdesc { #define NVM_OFF_MACADDR2 0x0002 /* MAC address offset 2 */ #define NVM_OFF_COMPAT 0x0003 #define NVM_OFF_ID_LED_SETTINGS 0x0004 +#define NVM_OFF_VERSION 0x0005 #define NVM_OFF_CFG1 0x000a /* config word 1 */ #define NVM_OFF_CFG2 0x000f /* config word 2 */ #define NVM_OFF_EEPROM_SIZE 0x0012 /* NVM SIZE */ @@ -941,6 +973,9 @@ struct livengood_tcpip_ctxdesc { #define NVM_OFF_SWDPIN 0x0020 /* SWD Pins (Cordova) */ #define NVM_OFF_CFG3_PORTA 0x0024 /* config word 3 */ #define NVM_OFF_ALT_MAC_ADDR_PTR 0x0037 /* to the alternative MAC addresses */ +#define NVM_OFF_COMB_VER_PTR 0x003d +#define NVM_OFF_IMAGE_UID0 0x0042 +#define NVM_OFF_IMAGE_UID1 0x0043 #define NVM_COMPAT_VALID_CHECKSUM 0x0001 @@ -980,6 +1015,8 @@ struct livengood_tcpip_ctxdesc { #define NVM_CFG2_MNGM_NCSI 1 #define NVM_CFG2_MNGM_PT 2 +#define NVM_COMPAT_SERDES_FORCE_MODE __BIT(14) /* Don't use autonego */ + #define NVM_FUTURE_INIT_WORD1_VALID_CHECKSUM 0x0040 #define NVM_K1_CONFIG_ENABLE 0x01 @@ -991,6 +1028,8 @@ struct livengood_tcpip_ctxdesc { #define NVM_3GIO_3_ASPM_MASK (0x3 << 2) /* Active State PM Support */ #define NVM_CFG3_APME (1U << 10) +#define NVM_CFG3_PORTA_EXT_MDIO (1U << 2) /* External MDIO Interface */ +#define NVM_CFG3_PORTA_COM_MDIO (1U << 3) /* MDIO Interface is shared */ #define NVM_OFF_MACADDR_82571(x) (3 * (x)) @@ -1000,8 +1039,17 @@ struct livengood_tcpip_ctxdesc { */ #define NVM_OFF_LAN_FUNC_82580(x) ((x) ? (0x40 + (0x40 * (x))) : 0) +#define NVM_COMBO_VER_OFF 0x0083 + +#define NVM_MAJOR_MASK 0xf000 +#define NVM_MAJOR_SHIFT 12 +#define NVM_MINOR_MASK 0x0ff0 +#define NVM_MINOR_SHIFT 4 +#define NVM_BUILD_MASK 0x000f +#define NVM_UID_VALID 0x8000 + /* iNVM Registers for i21[01] */ -#define E1000_INVM_DATA_REG(reg) (0x12120 + 4*(reg)) +#define WM_INVM_DATA_REG(reg) (0x12120 + 4*(reg)) #define INVM_SIZE 64 /* Number of INVM Data Registers */ /* iNVM default vaule */ @@ -1020,11 +1068,22 @@ struct livengood_tcpip_ctxdesc { #define INVM_CSR_AUTOLOAD_STRUCTURE 0x2 #define INVM_PHY_REGISTER_AUTOLOAD_STRUCTURE 0x3 #define INVM_RSA_KEY_SHA256_STRUCTURE 0x4 -#define INVM_INVALIDATED_STRUCTURE 0x5 +#define INVM_INVALIDATED_STRUCTURE 0xf #define INVM_RSA_KEY_SHA256_DATA_SIZE_IN_DWORDS 8 #define INVM_CSR_AUTOLOAD_DATA_SIZE_IN_DWORDS 1 +#define INVM_DEFAULT_AL 0x202f +#define INVM_AUTOLOAD 0x0a +#define INVM_PLL_WO_VAL 0x0010 + +/* Version and Image Type field */ +#define INVM_VER_1 __BITS(12,3) +#define INVM_VER_2 __BITS(22,13) +#define INVM_IMGTYPE __BITS(28,23) +#define INVM_MINOR __BITS(3,0) +#define INVM_MAJOR __BITS(9,4) + /* Word definitions for ID LED Settings */ #define ID_LED_RESERVED_FFFF 0xFFFF @@ -1098,6 +1157,13 @@ struct livengood_tcpip_ctxdesc { #define SFF_SFP_ETH_FLAGS_1000T 0x08 #define SFF_SFP_ETH_FLAGS_100FX 0x10 +/* I21[01] PHY related definitions */ +#define GS40G_PAGE_SELECT 0x16 +#define GS40G_PAGE_SHIFT 16 +#define GS40G_OFFSET_MASK 0xffff +#define GS40G_PHY_PLL_FREQ_PAGE 0xfc0000 +#define GS40G_PHY_PLL_FREQ_REG 0x000e +#define GS40G_PHY_PLL_UNCONF 0xff /* advanced TX descriptor for 82575 and newer */ typedef union nq_txdesc { Index: src/sys/dev/pci/if_wmvar.h diff -u src/sys/dev/pci/if_wmvar.h:1.19.2.3 src/sys/dev/pci/if_wmvar.h:1.19.2.4 --- src/sys/dev/pci/if_wmvar.h:1.19.2.3 Tue May 19 05:09:02 2015 +++ src/sys/dev/pci/if_wmvar.h Fri Feb 26 22:08:17 2016 @@ -1,4 +1,4 @@ -/* $NetBSD: if_wmvar.h,v 1.19.2.3 2015/05/19 05:09:02 snj Exp $ */ +/* $NetBSD: if_wmvar.h,v 1.19.2.4 2016/02/26 22:08:17 snj Exp $ */ /* * Copyright (c) 2001, 2002, 2003, 2004 Wasabi Systems, Inc. @@ -95,8 +95,25 @@ #define WM_F_HAS_MANAGE 0x00100000 #define WM_F_WOL 0x00200000 #define WM_F_EEE 0x00400000 /* Energy Efficiency Ethernet */ -#define WM_F_ATTACHED 0x00800000 /* attach() fininsed successfully */ +#define WM_F_ATTACHED 0x00800000 /* attach() finished successfully */ #define WM_F_EEPROM_INVM 0x01000000 /* NVM is iNVM */ +#define WM_F_PCS_DIS_AUTONEGO 0x02000000 /* PCS Disable Autonego */ +#define WM_F_PLL_WA_I210 0x04000000 /* I21[01] PLL workaround */ + +/* + * Variations of Intel gigabit Ethernet controller: + * + * +-- 82542 + * | +-- 82543 - 82544 + * | | +-- 82540 - 82545 - 82546 + * | | | +-- 82541 - 82547 + * | | | | +---------- 82571 - 82572 - 82573 - 82574 - 82583 + * | | | | | +--------- 82575 - 82576 - 82580 - I350 - I354 - I210 - I211 + * | | | | | | +-- 80003 + * | | | | | | | +-- ICH8 - ICH9 - ICH10 - PCH - PCH2 - PCH_LPT + * | | | | | | | | + * -+--+--+--+--+--+--+--+-----------------------------------------------> + */ typedef enum { WM_T_unknown = 0, @@ -126,12 +143,12 @@ typedef enum { WM_T_I210, /* I210 */ WM_T_I211, /* I211 */ WM_T_80003, /* i80003 */ - WM_T_ICH8, /* ICH8 LAN */ + WM_T_ICH8, /* ICH8 (I/O Controller Hub) LAN */ WM_T_ICH9, /* ICH9 LAN */ WM_T_ICH10, /* ICH10 LAN */ - WM_T_PCH, /* PCH LAN */ + WM_T_PCH, /* PCH (Platform Controller Hub) LAN */ WM_T_PCH2, /* PCH2 LAN */ - WM_T_PCH_LPT, /* PCH LPT LAN (I21[78]) */ + WM_T_PCH_LPT, /* PCH "Lynx Point" LAN (I217, I218) */ } wm_chip_type; typedef enum { @@ -155,5 +172,6 @@ typedef enum { #define WM_PHY_CFG_TIMEOUT 100 #define WM_ICH8_LAN_INIT_TIMEOUT 1500 #define WM_MDIO_OWNERSHIP_TIMEOUT 10 +#define WM_MAX_PLL_TRIES 5 #endif /* _DEV_PCI_IF_WMVAR_H_ */