Please note that diffs are not public domain; they are subject to the copyright notices on the relevant files. =================================================================== RCS file: /ftp/cvs/cvsroot/src/sys/dev/pci/if_wm.c,v rcsdiff: /ftp/cvs/cvsroot/src/sys/dev/pci/if_wm.c,v: warning: Unknown phrases like `commitid ...;' are present. retrieving revision 1.508 retrieving revision 1.508.4.8 diff -u -p -r1.508 -r1.508.4.8 --- src/sys/dev/pci/if_wm.c 2017/04/13 10:37:36 1.508 +++ src/sys/dev/pci/if_wm.c 2017/12/10 09:48:04 1.508.4.8 @@ -1,4 +1,4 @@ -/* $NetBSD: if_wm.c,v 1.508 2017/04/13 10:37:36 knakahara Exp $ */ +/* $NetBSD: if_wm.c,v 1.508.4.8 2017/12/10 09:48:04 snj Exp $ */ /* * Copyright (c) 2001, 2002, 2003, 2004 Wasabi Systems, Inc. @@ -73,7 +73,6 @@ * TODO (in order of importance): * * - Check XXX'ed comments - * - Disable D0 LPLU on 8257[12356], 82580 and I350. * - TX Multi queue improvement (refine queue selection logic) * - Split header buffer for newer descriptors * - EEE (Energy Efficiency Ethernet) @@ -84,7 +83,7 @@ */ #include -__KERNEL_RCSID(0, "$NetBSD: if_wm.c,v 1.508 2017/04/13 10:37:36 knakahara Exp $"); +__KERNEL_RCSID(0, "$NetBSD: if_wm.c,v 1.508.4.8 2017/12/10 09:48:04 snj Exp $"); #ifdef _KERNEL_OPT #include "opt_net_mpsafe.h" @@ -135,6 +134,7 @@ __KERNEL_RCSID(0, "$NetBSD: if_wm.c,v 1. #include #include #include +#include #include #include @@ -442,6 +442,12 @@ struct wm_phyop { int reset_delay_us; }; +struct wm_nvmop { + int (*acquire)(struct wm_softc *); + void (*release)(struct wm_softc *); + int (*read)(struct wm_softc *, int, int, uint16_t *); +}; + /* * Software state per device. */ @@ -564,6 +570,7 @@ struct wm_softc { kmutex_t *sc_ich_nvmmtx; /* ICH/PCH specific NVM mutex */ struct wm_phyop phy; + struct wm_nvmop nvm; }; #define WM_CORE_LOCK(_sc) if ((_sc)->sc_core_lock) mutex_enter((_sc)->sc_core_lock) @@ -679,6 +686,9 @@ static void wm_set_pcie_completion_timeo static void wm_get_auto_rd_done(struct wm_softc *); static void wm_lan_init_done(struct wm_softc *); static void wm_get_cfg_done(struct wm_softc *); +static void wm_phy_post_reset(struct wm_softc *); +static void wm_write_smbus_addr(struct wm_softc *); +static void wm_init_lcd_from_nvm(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_phy(struct wm_softc *); @@ -696,8 +706,8 @@ static int wm_setup_legacy(struct wm_sof static int wm_setup_msix(struct wm_softc *); static int wm_init(struct ifnet *); static int wm_init_locked(struct ifnet *); -static void wm_turnon(struct wm_softc *); -static void wm_turnoff(struct wm_softc *); +static void wm_unset_stopping_flags(struct wm_softc *); +static void wm_set_stopping_flags(struct wm_softc *); static void wm_stop(struct ifnet *, int); static void wm_stop_locked(struct ifnet *, int); static void wm_dump_mbuf_chain(struct wm_softc *, struct mbuf *); @@ -799,10 +809,10 @@ static void wm_gmii_statchg(struct ifnet * These functions are not for accessing MII registers but for accessing * kumeran specific registers. */ -static int wm_kmrn_readreg(struct wm_softc *, int); -static int wm_kmrn_readreg_locked(struct wm_softc *, int); -static void wm_kmrn_writereg(struct wm_softc *, int, int); -static void wm_kmrn_writereg_locked(struct wm_softc *, int, int); +static int wm_kmrn_readreg(struct wm_softc *, int, uint16_t *); +static int wm_kmrn_readreg_locked(struct wm_softc *, int, uint16_t *); +static int wm_kmrn_writereg(struct wm_softc *, int, uint16_t); +static int wm_kmrn_writereg_locked(struct wm_softc *, int, uint16_t); /* SGMII */ static bool wm_sgmii_uses_mdio(struct wm_softc *); static int wm_sgmii_readreg(device_t, int, int); @@ -854,8 +864,6 @@ static int wm_nvm_read_spt(struct wm_sof static int wm_nvm_read_word_invm(struct wm_softc *, uint16_t, uint16_t *); static int wm_nvm_read_invm(struct wm_softc *, int, int, uint16_t *); /* Lock, detecting NVM type, validate checksum and read */ -static int wm_nvm_acquire(struct wm_softc *); -static void wm_nvm_release(struct wm_softc *); 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 *); @@ -869,17 +877,23 @@ static int wm_nvm_read(struct wm_softc * */ static int wm_get_null(struct wm_softc *); static void wm_put_null(struct wm_softc *); +static int wm_get_eecd(struct wm_softc *); +static void wm_put_eecd(struct wm_softc *); static int wm_get_swsm_semaphore(struct wm_softc *); /* 8257[123] */ static void wm_put_swsm_semaphore(struct wm_softc *); static int wm_get_swfw_semaphore(struct wm_softc *, uint16_t); static void wm_put_swfw_semaphore(struct wm_softc *, uint16_t); +static int wm_get_nvm_80003(struct wm_softc *); +static void wm_put_nvm_80003(struct wm_softc *); +static int wm_get_nvm_82571(struct wm_softc *); +static void wm_put_nvm_82571(struct wm_softc *); static int wm_get_phy_82575(struct wm_softc *); static void wm_put_phy_82575(struct wm_softc *); static int wm_get_swfwhw_semaphore(struct wm_softc *); /* For 574/583 */ static void wm_put_swfwhw_semaphore(struct wm_softc *); static int wm_get_swflag_ich8lan(struct wm_softc *); /* For PHY */ static void wm_put_swflag_ich8lan(struct wm_softc *); -static int wm_get_nvm_ich8lan(struct wm_softc *); /* For NVM */ +static int wm_get_nvm_ich8lan(struct wm_softc *); static void wm_put_nvm_ich8lan(struct wm_softc *); static int wm_get_hw_semaphore_82573(struct wm_softc *); static void wm_put_hw_semaphore_82573(struct wm_softc *); @@ -909,7 +923,6 @@ static void wm_igp3_phy_powerdown_workar static void wm_enable_wakeup(struct wm_softc *); /* 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 *); @@ -930,6 +943,7 @@ static bool wm_phy_is_accessible_pchlan( static void wm_toggle_lanphypc_pch_lpt(struct wm_softc *); static int wm_platform_pm_pch_lpt(struct wm_softc *, bool); static void wm_pll_workaround_i210(struct wm_softc *); +static void wm_legacy_irq_quirk_spt(struct wm_softc *); CFATTACH_DECL3_NEW(wm, sizeof(struct wm_softc), wm_match, wm_attach, wm_detach, NULL, NULL, NULL, DVF_DETACH_SHUTDOWN); @@ -1674,6 +1688,7 @@ wm_attach(device_t parent, device_t self prop_data_t ea; prop_number_t pn; uint8_t enaddr[ETHER_ADDR_LEN]; + char buf[256]; uint16_t cfg1, cfg2, swdpin, nvmword; pcireg_t preg, memtype; uint16_t eeprom_data, apme_mask; @@ -1709,8 +1724,8 @@ wm_attach(device_t parent, device_t self sc->sc_type = wmp->wmp_type; /* Set default function pointers */ - sc->phy.acquire = wm_get_null; - sc->phy.release = wm_put_null; + sc->phy.acquire = sc->nvm.acquire = wm_get_null; + sc->phy.release = sc->nvm.release = wm_put_null; sc->phy.reset_delay_us = (sc->sc_type >= WM_T_82571) ? 100 : 10000; if (sc->sc_type < WM_T_82543) { @@ -1838,7 +1853,13 @@ wm_attach(device_t parent, device_t self /* Allocation settings */ max_type = PCI_INTR_TYPE_MSIX; - counts[PCI_INTR_TYPE_MSIX] = sc->sc_nqueues + 1; + /* + * 82583 has a MSI-X capability in the PCI configuration space but + * it doesn't support it. At least the document doesn't say anything + * about MSI-X. + */ + counts[PCI_INTR_TYPE_MSIX] + = (sc->sc_type == WM_T_82583) ? 0 : sc->sc_nqueues + 1; counts[PCI_INTR_TYPE_MSI] = 1; counts[PCI_INTR_TYPE_INTX] = 1; /* overridden by disable flags */ @@ -2035,6 +2056,7 @@ alloc_retry: case WM_T_82543: case WM_T_82544: /* Microwire */ + sc->nvm.read = wm_nvm_read_uwire; sc->sc_nvm_wordsize = 64; sc->sc_nvm_addrbits = 6; break; @@ -2044,6 +2066,7 @@ alloc_retry: case WM_T_82546: case WM_T_82546_3: /* Microwire */ + sc->nvm.read = wm_nvm_read_uwire; reg = CSR_READ(sc, WMREG_EECD); if (reg & EECD_EE_SIZE) { sc->sc_nvm_wordsize = 256; @@ -2053,19 +2076,29 @@ alloc_retry: sc->sc_nvm_addrbits = 6; } sc->sc_flags |= WM_F_LOCK_EECD; + sc->nvm.acquire = wm_get_eecd; + sc->nvm.release = wm_put_eecd; break; case WM_T_82541: case WM_T_82541_2: case WM_T_82547: case WM_T_82547_2: - sc->sc_flags |= WM_F_LOCK_EECD; reg = CSR_READ(sc, WMREG_EECD); + /* + * wm_nvm_set_addrbits_size_eecd() accesses SPI in it only + * on 8254[17], so set flags and functios before calling it. + */ + sc->sc_flags |= WM_F_LOCK_EECD; + sc->nvm.acquire = wm_get_eecd; + sc->nvm.release = wm_put_eecd; if (reg & EECD_EE_TYPE) { /* SPI */ + sc->nvm.read = wm_nvm_read_spi; sc->sc_flags |= WM_F_EEPROM_SPI; wm_nvm_set_addrbits_size_eecd(sc); } else { /* Microwire */ + sc->nvm.read = wm_nvm_read_uwire; if ((reg & EECD_EE_ABITS) != 0) { sc->sc_nvm_wordsize = 256; sc->sc_nvm_addrbits = 8; @@ -2078,25 +2111,30 @@ alloc_retry: case WM_T_82571: case WM_T_82572: /* SPI */ + sc->nvm.read = wm_nvm_read_eerd; + /* Not use WM_F_LOCK_EECD because we use EERD */ sc->sc_flags |= WM_F_EEPROM_SPI; wm_nvm_set_addrbits_size_eecd(sc); - sc->sc_flags |= WM_F_LOCK_EECD | WM_F_LOCK_SWSM; sc->phy.acquire = wm_get_swsm_semaphore; sc->phy.release = wm_put_swsm_semaphore; + sc->nvm.acquire = wm_get_nvm_82571; + sc->nvm.release = wm_put_nvm_82571; break; case WM_T_82573: case WM_T_82574: case WM_T_82583: + sc->nvm.read = wm_nvm_read_eerd; + /* Not use WM_F_LOCK_EECD because we use EERD */ if (sc->sc_type == WM_T_82573) { - sc->sc_flags |= WM_F_LOCK_SWSM; sc->phy.acquire = wm_get_swsm_semaphore; sc->phy.release = wm_put_swsm_semaphore; + sc->nvm.acquire = wm_get_nvm_82571; + sc->nvm.release = wm_put_nvm_82571; } else { - sc->sc_flags |= WM_F_LOCK_EXTCNF; /* Both PHY and NVM use the same semaphore. */ - sc->phy.acquire + sc->phy.acquire = sc->nvm.acquire = wm_get_swfwhw_semaphore; - sc->phy.release + sc->phy.release = sc->nvm.release = wm_put_swfwhw_semaphore; } if (wm_nvm_is_onboard_eeprom(sc) == 0) { @@ -2107,7 +2145,6 @@ alloc_retry: sc->sc_flags |= WM_F_EEPROM_SPI; wm_nvm_set_addrbits_size_eecd(sc); } - sc->sc_flags |= WM_F_EEPROM_EERDEEWR; break; case WM_T_82575: case WM_T_82576: @@ -2118,10 +2155,18 @@ alloc_retry: /* SPI */ sc->sc_flags |= WM_F_EEPROM_SPI; wm_nvm_set_addrbits_size_eecd(sc); - sc->sc_flags |= WM_F_EEPROM_EERDEEWR | WM_F_LOCK_SWFW - | WM_F_LOCK_SWSM; + if((sc->sc_type == WM_T_80003) + || (sc->sc_nvm_wordsize < (1 << 15))) { + sc->nvm.read = wm_nvm_read_eerd; + /* Don't use WM_F_LOCK_EECD because we use EERD */ + } else { + sc->nvm.read = wm_nvm_read_spi; + sc->sc_flags |= WM_F_LOCK_EECD; + } sc->phy.acquire = wm_get_phy_82575; sc->phy.release = wm_put_phy_82575; + sc->nvm.acquire = wm_get_nvm_80003; + sc->nvm.release = wm_put_nvm_80003; break; case WM_T_ICH8: case WM_T_ICH9: @@ -2129,8 +2174,9 @@ alloc_retry: case WM_T_PCH: case WM_T_PCH2: case WM_T_PCH_LPT: + sc->nvm.read = wm_nvm_read_ich8; /* FLASH */ - sc->sc_flags |= WM_F_EEPROM_FLASH | WM_F_LOCK_EXTCNF; + sc->sc_flags |= WM_F_EEPROM_FLASH; sc->sc_nvm_wordsize = 2048; memtype = pci_mapreg_type(pa->pa_pc, pa->pa_tag,WM_ICH8_FLASH); if (pci_mapreg_map(pa, WM_ICH8_FLASH, memtype, 0, @@ -2150,10 +2196,13 @@ alloc_retry: sc->sc_flashreg_offset = 0; sc->phy.acquire = wm_get_swflag_ich8lan; sc->phy.release = wm_put_swflag_ich8lan; + sc->nvm.acquire = wm_get_nvm_ich8lan; + sc->nvm.release = wm_put_nvm_ich8lan; break; case WM_T_PCH_SPT: + sc->nvm.read = wm_nvm_read_spt; /* SPT has no GFPREG; flash registers mapped through BAR0 */ - sc->sc_flags |= WM_F_EEPROM_FLASH | WM_F_LOCK_EXTCNF; + sc->sc_flags |= WM_F_EEPROM_FLASH; sc->sc_flasht = sc->sc_st; sc->sc_flashh = sc->sc_sh; sc->sc_ich8_flash_base = 0; @@ -2167,28 +2216,32 @@ alloc_retry: sc->sc_flashreg_offset = WM_PCH_SPT_FLASHOFFSET; sc->phy.acquire = wm_get_swflag_ich8lan; sc->phy.release = wm_put_swflag_ich8lan; + sc->nvm.acquire = wm_get_nvm_ich8lan; + sc->nvm.release = wm_put_nvm_ich8lan; break; case WM_T_I210: case WM_T_I211: + /* Allow a single clear of the SW semaphore on I210 and newer*/ + sc->sc_flags |= WM_F_WA_I210_CLSEM; if (wm_nvm_get_flash_presence_i210(sc)) { - wm_nvm_set_addrbits_size_eecd(sc); + sc->nvm.read = wm_nvm_read_eerd; + /* Don't use WM_F_LOCK_EECD because we use EERD */ sc->sc_flags |= WM_F_EEPROM_FLASH_HW; - sc->sc_flags |= WM_F_EEPROM_EERDEEWR; + wm_nvm_set_addrbits_size_eecd(sc); } else { - sc->sc_nvm_wordsize = INVM_SIZE; + sc->nvm.read = wm_nvm_read_invm; sc->sc_flags |= WM_F_EEPROM_INVM; + sc->sc_nvm_wordsize = INVM_SIZE; } - sc->sc_flags |= WM_F_LOCK_SWFW | WM_F_LOCK_SWSM; sc->phy.acquire = wm_get_phy_82575; sc->phy.release = wm_put_phy_82575; + sc->nvm.acquire = wm_get_nvm_80003; + sc->nvm.release = wm_put_nvm_80003; break; default: break; } - /* Reset the chip to a known state. */ - wm_reset(sc); - /* Ensure the SMBI bit is clear before first NVM or PHY access */ switch (sc->sc_type) { case WM_T_82571: @@ -2235,9 +2288,6 @@ alloc_retry: sc->sc_flags |= WM_F_EEPROM_INVALID; } - /* Set device properties (macflags) */ - 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"); else { @@ -2261,6 +2311,15 @@ alloc_retry: wm_nvm_version(sc); aprint_verbose("\n"); + /* + * XXX The first call of wm_gmii_setup_phytype. The result might be + * incorrect. + */ + wm_gmii_setup_phytype(sc, 0, 0); + + /* Reset the chip to a known state. */ + wm_reset(sc); + /* Check for I21[01] PLL workaround */ if (sc->sc_type == WM_T_I210) sc->sc_flags |= WM_F_PLL_WA_I210; @@ -2377,10 +2436,6 @@ alloc_retry: /* Check for WM_F_WOL flag after the setting of the EEPROM stuff */ if ((eeprom_data & apme_mask) != 0) sc->sc_flags |= WM_F_WOL; -#ifdef WM_DEBUG - if ((sc->sc_flags & WM_F_WOL) != 0) - printf("WOL\n"); -#endif if ((sc->sc_type == WM_T_82575) || (sc->sc_type == WM_T_82576)) { /* Check NVM for autonegotiation */ @@ -2477,17 +2532,13 @@ alloc_retry: sc->sc_nvm_k1_enabled = 0; } - /* - * Determine if we're TBI,GMII or SGMII mode, and initialize the - * media structures accordingly. - */ + /* Determine if we're GMII, TBI, SERDES or SGMII mode */ 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 || sc->sc_type == WM_T_PCH2 || sc->sc_type == WM_T_PCH_LPT || sc->sc_type == WM_T_PCH_SPT || sc->sc_type == WM_T_82573 || sc->sc_type == WM_T_82574 || sc->sc_type == WM_T_82583) { - /* STATUS_TBIMODE reserved/reused, can't rely on it */ - wm_gmii_mediainit(sc, wmp->wmp_product); + /* Copper only */ } else 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) || (sc->sc_type ==WM_T_I210) @@ -2553,11 +2604,6 @@ alloc_retry: else reg &= ~CTRL_EXT_I2C_ENA; CSR_WRITE(sc, WMREG_CTRL_EXT, reg); - - if (sc->sc_mediatype == WM_MEDIATYPE_COPPER) - wm_gmii_mediainit(sc, wmp->wmp_product); - else - wm_tbi_mediainit(sc); } else if (sc->sc_type < WM_T_82543 || (CSR_READ(sc, WMREG_STATUS) & STATUS_TBIMODE) != 0) { if (sc->sc_mediatype == WM_MEDIATYPE_COPPER) { @@ -2565,15 +2611,24 @@ alloc_retry: "WARNING: TBIMODE set on 1000BASE-T product!\n"); sc->sc_mediatype = WM_MEDIATYPE_FIBER; } - wm_tbi_mediainit(sc); } else { if (sc->sc_mediatype == WM_MEDIATYPE_FIBER) { aprint_error_dev(sc->sc_dev, "WARNING: TBIMODE clear on 1000BASE-X product!\n"); sc->sc_mediatype = WM_MEDIATYPE_COPPER; } - wm_gmii_mediainit(sc, wmp->wmp_product); } + snprintb(buf, sizeof(buf), WM_FLAGS, sc->sc_flags); + aprint_verbose_dev(sc->sc_dev, "%s\n", buf); + + /* Set device properties (macflags) */ + prop_dictionary_set_uint32(dict, "macflags", sc->sc_flags); + + /* Initialize the media structures accordingly. */ + if (sc->sc_mediatype == WM_MEDIATYPE_COPPER) + wm_gmii_mediainit(sc, wmp->wmp_product); + else + wm_tbi_mediainit(sc); /* All others */ ifp = &sc->sc_ethercom.ec_if; xname = device_xname(sc->sc_dev); @@ -2621,11 +2676,12 @@ alloc_retry: case WM_T_82571: case WM_T_82572: case WM_T_82574: + case WM_T_82583: case WM_T_82575: case WM_T_82576: case WM_T_82580: case WM_T_I350: - case WM_T_I354: /* XXXX ok? */ + case WM_T_I354: case WM_T_I210: case WM_T_I211: case WM_T_80003: @@ -2643,7 +2699,6 @@ alloc_retry: break; case WM_T_82542_2_0: case WM_T_82542_2_1: - case WM_T_82583: case WM_T_ICH8: /* No support for jumbo frame */ break; @@ -2990,6 +3045,9 @@ wm_ifflags_cb(struct ethercom *ec) struct wm_softc *sc = ifp->if_softc; int rc = 0; + DPRINTF(WM_DEBUG_INIT, ("%s: %s called\n", + device_xname(sc->sc_dev), __func__)); + WM_CORE_LOCK(sc); int change = ifp->if_flags ^ sc->sc_if_flags; @@ -3204,7 +3262,9 @@ wm_read_mac_addr(struct wm_softc *sc, ui static void wm_set_ral(struct wm_softc *sc, const uint8_t *enaddr, int idx) { - uint32_t ral_lo, ral_hi; + uint32_t ral_lo, ral_hi, addrl, addrh; + uint32_t wlock_mac; + int rv; if (enaddr != NULL) { ral_lo = enaddr[0] | (enaddr[1] << 8) | (enaddr[2] << 16) | @@ -3216,14 +3276,54 @@ wm_set_ral(struct wm_softc *sc, const ui ral_hi = 0; } - if (sc->sc_type >= WM_T_82544) { - CSR_WRITE(sc, WMREG_RAL_LO(WMREG_CORDOVA_RAL_BASE, idx), - ral_lo); - CSR_WRITE(sc, WMREG_RAL_HI(WMREG_CORDOVA_RAL_BASE, idx), - ral_hi); - } else { - CSR_WRITE(sc, WMREG_RAL_LO(WMREG_RAL_BASE, idx), ral_lo); - CSR_WRITE(sc, WMREG_RAL_HI(WMREG_RAL_BASE, idx), ral_hi); + switch (sc->sc_type) { + case WM_T_82542_2_0: + case WM_T_82542_2_1: + case WM_T_82543: + CSR_WRITE(sc, WMREG_RAL(idx), ral_lo); + CSR_WRITE_FLUSH(sc); + CSR_WRITE(sc, WMREG_RAH(idx), ral_hi); + CSR_WRITE_FLUSH(sc); + break; + case WM_T_PCH2: + case WM_T_PCH_LPT: + case WM_T_PCH_SPT: + if (idx == 0) { + CSR_WRITE(sc, WMREG_CORDOVA_RAL(idx), ral_lo); + CSR_WRITE_FLUSH(sc); + CSR_WRITE(sc, WMREG_CORDOVA_RAH(idx), ral_hi); + CSR_WRITE_FLUSH(sc); + return; + } + if (sc->sc_type != WM_T_PCH2) { + wlock_mac = __SHIFTOUT(CSR_READ(sc, WMREG_FWSM), + FWSM_WLOCK_MAC); + addrl = WMREG_SHRAL(idx - 1); + addrh = WMREG_SHRAH(idx - 1); + } else { + wlock_mac = 0; + addrl = WMREG_PCH_LPT_SHRAL(idx - 1); + addrh = WMREG_PCH_LPT_SHRAH(idx - 1); + } + + if ((wlock_mac == 0) || (idx <= wlock_mac)) { + rv = wm_get_swflag_ich8lan(sc); + if (rv != 0) + return; + CSR_WRITE(sc, addrl, ral_lo); + CSR_WRITE_FLUSH(sc); + CSR_WRITE(sc, addrh, ral_hi); + CSR_WRITE_FLUSH(sc); + wm_put_swflag_ich8lan(sc); + } + + break; + default: + CSR_WRITE(sc, WMREG_CORDOVA_RAL(idx), ral_lo); + CSR_WRITE_FLUSH(sc); + CSR_WRITE(sc, WMREG_CORDOVA_RAH(idx), ral_hi); + CSR_WRITE_FLUSH(sc); + break; } } @@ -3342,8 +3442,10 @@ wm_set_filter(struct wm_softc *sc) else size = WM_MC_TABSIZE; /* Clear out the multicast table. */ - for (i = 0; i < size; i++) + for (i = 0; i < size; i++) { CSR_WRITE(sc, mta_reg + (i << 2), 0); + CSR_WRITE_FLUSH(sc); + } ETHER_LOCK(ec); ETHER_FIRST_MULTI(step, ec, enm); @@ -3385,9 +3487,13 @@ wm_set_filter(struct wm_softc *sc) */ bit = CSR_READ(sc, mta_reg + ((reg - 1) << 2)); CSR_WRITE(sc, mta_reg + (reg << 2), hash); + CSR_WRITE_FLUSH(sc); CSR_WRITE(sc, mta_reg + ((reg - 1) << 2), bit); - } else + CSR_WRITE_FLUSH(sc); + } else { CSR_WRITE(sc, mta_reg + (reg << 2), hash); + CSR_WRITE_FLUSH(sc); + } ETHER_NEXT_MULTI(step, enm); } @@ -3609,6 +3715,180 @@ wm_get_cfg_done(struct wm_softc *sc) } } +void +wm_phy_post_reset(struct wm_softc *sc) +{ + uint32_t reg; + + /* This function is only for ICH8 and newer. */ + if (sc->sc_type < WM_T_ICH8) + return; + + if (wm_phy_resetisblocked(sc)) { + /* XXX */ + device_printf(sc->sc_dev, "PHY is blocked\n"); + return; + } + + /* Allow time for h/w to get to quiescent state after reset */ + delay(10*1000); + + /* Perform any necessary post-reset workarounds */ + if (sc->sc_type == WM_T_PCH) + wm_hv_phy_workaround_ich8lan(sc); + if (sc->sc_type == WM_T_PCH2) + wm_lv_phy_workaround_ich8lan(sc); + + /* Clear the host wakeup bit after lcd reset */ + if (sc->sc_type >= WM_T_PCH) { + reg = wm_gmii_hv_readreg(sc->sc_dev, 2, + BM_PORT_GEN_CFG); + reg &= ~BM_WUC_HOST_WU_BIT; + wm_gmii_hv_writereg(sc->sc_dev, 2, + BM_PORT_GEN_CFG, reg); + } + + /* Configure the LCD with the extended configuration region in NVM */ + wm_init_lcd_from_nvm(sc); + + /* Configure the LCD with the OEM bits in NVM */ +} + +/* Only for PCH and newer */ +static void +wm_write_smbus_addr(struct wm_softc *sc) +{ + uint32_t strap, freq; + uint32_t phy_data; + + DPRINTF(WM_DEBUG_INIT, ("%s: %s called\n", + device_xname(sc->sc_dev), __func__)); + + strap = CSR_READ(sc, WMREG_STRAP); + freq = __SHIFTOUT(strap, STRAP_FREQ); + + phy_data = wm_gmii_hv_readreg_locked(sc->sc_dev, 2, HV_SMB_ADDR); + + phy_data &= ~HV_SMB_ADDR_ADDR; + phy_data |= __SHIFTOUT(strap, STRAP_SMBUSADDR); + phy_data |= HV_SMB_ADDR_PEC_EN | HV_SMB_ADDR_VALID; + + if (sc->sc_phytype == WMPHY_I217) { + /* Restore SMBus frequency */ + if (freq --) { + phy_data &= ~(HV_SMB_ADDR_FREQ_LOW + | HV_SMB_ADDR_FREQ_HIGH); + phy_data |= __SHIFTIN((freq & 0x01) != 0, + HV_SMB_ADDR_FREQ_LOW); + phy_data |= __SHIFTIN((freq & 0x02) != 0, + HV_SMB_ADDR_FREQ_HIGH); + } else { + DPRINTF(WM_DEBUG_INIT, + ("%s: %s Unsupported SMB frequency in PHY\n", + device_xname(sc->sc_dev), __func__)); + } + } + + wm_gmii_hv_writereg_locked(sc->sc_dev, 2, HV_SMB_ADDR, phy_data); +} + +void +wm_init_lcd_from_nvm(struct wm_softc *sc) +{ + uint32_t extcnfctr, sw_cfg_mask, cnf_size, word_addr, i, reg; + uint16_t phy_page = 0; + + DPRINTF(WM_DEBUG_INIT, ("%s: %s called\n", + device_xname(sc->sc_dev), __func__)); + + switch (sc->sc_type) { + case WM_T_ICH8: + if ((sc->sc_phytype == WMPHY_UNKNOWN) + || (sc->sc_phytype != WMPHY_IGP_3)) + return; + + if ((sc->sc_pcidevid == PCI_PRODUCT_INTEL_82801H_AMT) + || (sc->sc_pcidevid == PCI_PRODUCT_INTEL_82801H_LAN)) { + sw_cfg_mask = FEXTNVM_SW_CONFIG; + break; + } + /* FALLTHROUGH */ + case WM_T_PCH: + case WM_T_PCH2: + case WM_T_PCH_LPT: + case WM_T_PCH_SPT: + sw_cfg_mask = FEXTNVM_SW_CONFIG_ICH8M; + break; + default: + return; + } + + sc->phy.acquire(sc); + + reg = CSR_READ(sc, WMREG_FEXTNVM); + if ((reg & sw_cfg_mask) == 0) + goto release; + + /* + * Make sure HW does not configure LCD from PHY extended configuration + * before SW configuration + */ + extcnfctr = CSR_READ(sc, WMREG_EXTCNFCTR); + if ((sc->sc_type < WM_T_PCH2) + && ((extcnfctr & EXTCNFCTR_PCIE_WRITE_ENABLE) != 0)) + goto release; + + DPRINTF(WM_DEBUG_INIT, ("%s: %s: Configure LCD by software\n", + device_xname(sc->sc_dev), __func__)); + /* word_addr is in DWORD */ + word_addr = __SHIFTOUT(extcnfctr, EXTCNFCTR_EXT_CNF_POINTER) << 1; + + reg = CSR_READ(sc, WMREG_EXTCNFSIZE); + cnf_size = __SHIFTOUT(reg, EXTCNFSIZE_LENGTH); + + if (((sc->sc_type == WM_T_PCH) + && ((extcnfctr & EXTCNFCTR_OEM_WRITE_ENABLE) == 0)) + || (sc->sc_type > WM_T_PCH)) { + /* + * HW configures the SMBus address and LEDs when the OEM and + * LCD Write Enable bits are set in the NVM. When both NVM bits + * are cleared, SW will configure them instead. + */ + DPRINTF(WM_DEBUG_INIT, ("%s: %s: Configure SMBus and LED\n", + device_xname(sc->sc_dev), __func__)); + wm_write_smbus_addr(sc); + + reg = CSR_READ(sc, WMREG_LEDCTL); + wm_gmii_hv_writereg_locked(sc->sc_dev, 1, HV_LED_CONFIG, reg); + } + + /* Configure LCD from extended configuration region. */ + for (i = 0; i < cnf_size; i++) { + uint16_t reg_data, reg_addr; + + if (wm_nvm_read(sc, (word_addr + i * 2), 1, ®_data) != 0) + goto release; + + if (wm_nvm_read(sc, (word_addr + i * 2 + 1), 1, ®_addr) !=0) + goto release; + + if (reg_addr == MII_IGPHY_PAGE_SELECT) + phy_page = reg_data; + + reg_addr &= IGPHY_MAXREGADDR; + reg_addr |= phy_page; + + sc->phy.release(sc); /* XXX */ + sc->sc_mii.mii_writereg(sc->sc_dev, 1, reg_addr, reg_data); + sc->phy.acquire(sc); /* XXX */ + } + +release: + sc->phy.release(sc); + return; +} + + /* Init hardware bits */ void wm_initialize_hardware_bits(struct wm_softc *sc) @@ -3748,10 +4028,18 @@ wm_initialize_hardware_bits(struct wm_so case WM_T_PCH_LPT: case WM_T_PCH_SPT: /* TARC0 */ - if ((sc->sc_type == WM_T_ICH8) - || (sc->sc_type == WM_T_PCH_SPT)) { + if (sc->sc_type == WM_T_ICH8) { /* Set TARC0 bits 29 and 28 */ tarc0 |= __BITS(29, 28); + } else if (sc->sc_type == WM_T_PCH_SPT) { + tarc0 |= __BIT(29); + /* + * Drop bit 28. From Linux. + * See I218/I219 spec update + * "5. Buffer Overrun While the I219 is + * Processing DMA Transactions" + */ + tarc0 &= ~__BIT(28); } /* Set TARC0 bits 23,24,26,27 */ tarc0 |= __BITS(27, 26) | __BITS(24, 23); @@ -3888,6 +4176,7 @@ wm_reset_phy(struct wm_softc *sc) sc->phy.release(sc); wm_get_cfg_done(sc); + wm_phy_post_reset(sc); } static void @@ -3895,7 +4184,10 @@ wm_flush_desc_rings(struct wm_softc *sc) { pcireg_t preg; uint32_t reg; + struct wm_txqueue *txq; + wiseman_txdesc_t *txd; int nexttx; + uint32_t rctl; /* First, disable MULR fix in FEXTNVM11 */ reg = CSR_READ(sc, WMREG_FEXTNVM11); @@ -3904,66 +4196,64 @@ wm_flush_desc_rings(struct wm_softc *sc) preg = pci_conf_read(sc->sc_pc, sc->sc_pcitag, WM_PCI_DESCRING_STATUS); reg = CSR_READ(sc, WMREG_TDLEN(0)); - if (((preg & DESCRING_STATUS_FLUSH_REQ) != 0) && (reg != 0)) { - struct wm_txqueue *txq; - wiseman_txdesc_t *txd; - - /* TX */ - printf("%s: Need TX flush (reg = %08x, len = %u)\n", - device_xname(sc->sc_dev), preg, reg); - reg = CSR_READ(sc, WMREG_TCTL); - CSR_WRITE(sc, WMREG_TCTL, reg | TCTL_EN); + if (((preg & DESCRING_STATUS_FLUSH_REQ) == 0) || (reg == 0)) + return; - txq = &sc->sc_queue[0].wmq_txq; - nexttx = txq->txq_next; - txd = &txq->txq_descs[nexttx]; - wm_set_dma_addr(&txd->wtx_addr, WM_CDTXADDR(txq, nexttx)); - txd->wtx_cmdlen = htole32(WTX_CMD_IFCS| 512); - txd->wtx_fields.wtxu_status = 0; - txd->wtx_fields.wtxu_options = 0; - txd->wtx_fields.wtxu_vlan = 0; + /* TX */ + printf("%s: Need TX flush (reg = %08x, len = %u)\n", + device_xname(sc->sc_dev), preg, reg); + reg = CSR_READ(sc, WMREG_TCTL); + CSR_WRITE(sc, WMREG_TCTL, reg | TCTL_EN); + + txq = &sc->sc_queue[0].wmq_txq; + nexttx = txq->txq_next; + txd = &txq->txq_descs[nexttx]; + wm_set_dma_addr(&txd->wtx_addr, WM_CDTXADDR(txq, nexttx)); + txd->wtx_cmdlen = htole32(WTX_CMD_IFCS| 512); + txd->wtx_fields.wtxu_status = 0; + txd->wtx_fields.wtxu_options = 0; + txd->wtx_fields.wtxu_vlan = 0; - bus_space_barrier(sc->sc_st, sc->sc_sh, 0, 0, - BUS_SPACE_BARRIER_WRITE); + bus_space_barrier(sc->sc_st, sc->sc_sh, 0, 0, + BUS_SPACE_BARRIER_WRITE); - txq->txq_next = WM_NEXTTX(txq, txq->txq_next); - CSR_WRITE(sc, WMREG_TDT(0), txq->txq_next); - bus_space_barrier(sc->sc_st, sc->sc_sh, 0, 0, - BUS_SPACE_BARRIER_READ | BUS_SPACE_BARRIER_WRITE); - delay(250); - } + txq->txq_next = WM_NEXTTX(txq, txq->txq_next); + CSR_WRITE(sc, WMREG_TDT(0), txq->txq_next); + bus_space_barrier(sc->sc_st, sc->sc_sh, 0, 0, + BUS_SPACE_BARRIER_READ | BUS_SPACE_BARRIER_WRITE); + delay(250); + preg = pci_conf_read(sc->sc_pc, sc->sc_pcitag, WM_PCI_DESCRING_STATUS); - if (preg & DESCRING_STATUS_FLUSH_REQ) { - uint32_t rctl; + if ((preg & DESCRING_STATUS_FLUSH_REQ) == 0) + return; - /* RX */ - printf("%s: Need RX flush (reg = %08x)\n", - device_xname(sc->sc_dev), preg); - rctl = CSR_READ(sc, WMREG_RCTL); - CSR_WRITE(sc, WMREG_RCTL, rctl & ~RCTL_EN); - CSR_WRITE_FLUSH(sc); - delay(150); + /* RX */ + printf("%s: Need RX flush (reg = %08x)\n", + device_xname(sc->sc_dev), preg); + rctl = CSR_READ(sc, WMREG_RCTL); + CSR_WRITE(sc, WMREG_RCTL, rctl & ~RCTL_EN); + CSR_WRITE_FLUSH(sc); + delay(150); - reg = CSR_READ(sc, WMREG_RXDCTL(0)); - /* zero the lower 14 bits (prefetch and host thresholds) */ - reg &= 0xffffc000; - /* - * update thresholds: prefetch threshold to 31, host threshold - * to 1 and make sure the granularity is "descriptors" and not - * "cache lines" - */ - reg |= (0x1f | (1 << 8) | RXDCTL_GRAN); - CSR_WRITE(sc, WMREG_RXDCTL(0), reg); + reg = CSR_READ(sc, WMREG_RXDCTL(0)); + /* zero the lower 14 bits (prefetch and host thresholds) */ + reg &= 0xffffc000; + /* + * update thresholds: prefetch threshold to 31, host threshold + * to 1 and make sure the granularity is "descriptors" and not + * "cache lines" + */ + reg |= (0x1f | (1 << 8) | RXDCTL_GRAN); + CSR_WRITE(sc, WMREG_RXDCTL(0), reg); - /* - * momentarily enable the RX ring for the changes to take - * effect - */ - CSR_WRITE(sc, WMREG_RCTL, rctl | RCTL_EN); - CSR_WRITE_FLUSH(sc); - delay(150); - CSR_WRITE(sc, WMREG_RCTL, rctl & ~RCTL_EN); - } + /* + * momentarily enable the RX ring for the changes to take + * effect + */ + CSR_WRITE(sc, WMREG_RCTL, rctl | RCTL_EN); + CSR_WRITE_FLUSH(sc); + delay(150); + CSR_WRITE(sc, WMREG_RCTL, rctl & ~RCTL_EN); } /* @@ -3977,6 +4267,8 @@ wm_reset(struct wm_softc *sc) int phy_reset = 0; int i, error = 0; uint32_t reg; + uint16_t kmreg; + int rv; DPRINTF(WM_DEBUG_INIT, ("%s: %s called\n", device_xname(sc->sc_dev), __func__)); @@ -4069,6 +4361,9 @@ wm_reset(struct wm_softc *sc) break; delay(100); } + if (timeout == 0) + device_printf(sc->sc_dev, + "failed to disable busmastering\n"); } /* Set the completion timeout for interface */ @@ -4318,6 +4613,9 @@ wm_reset(struct wm_softc *sc) break; } + if (phy_reset != 0) + wm_phy_post_reset(sc); + if ((sc->sc_type == WM_T_82580) || (sc->sc_type == WM_T_I350) || (sc->sc_type == WM_T_I354)) { /* clear global device reset status bit */ @@ -4335,21 +4633,21 @@ wm_reset(struct wm_softc *sc) CSR_WRITE(sc, WMREG_EIAC_82574, 0); } + 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) + || (sc->sc_type == WM_T_PCH2) || (sc->sc_type == WM_T_PCH_LPT) + || (sc->sc_type == WM_T_PCH_SPT)) { + reg = CSR_READ(sc, WMREG_KABGTXD); + reg |= KABGTXD_BGSQLBIAS; + CSR_WRITE(sc, WMREG_KABGTXD, reg); + } + /* reload sc_ctrl */ sc->sc_ctrl = CSR_READ(sc, WMREG_CTRL); if ((sc->sc_type >= WM_T_I350) && (sc->sc_type <= WM_T_I211)) wm_set_eee_i350(sc); - /* Clear the host wakeup bit after lcd reset */ - if (sc->sc_type >= WM_T_PCH) { - reg = wm_gmii_hv_readreg(sc->sc_dev, 2, - BM_PORT_GEN_CFG); - reg &= ~BM_WUC_HOST_WU_BIT; - wm_gmii_hv_writereg(sc->sc_dev, 2, - BM_PORT_GEN_CFG, reg); - } - /* * For PCH, this write will make sure that any noise will be detected * as a CRC error and be dropped rather than show up as a bad packet @@ -4365,6 +4663,21 @@ wm_reset(struct wm_softc *sc) if ((sc->sc_flags & WM_F_PLL_WA_I210) != 0) wm_pll_workaround_i210(sc); + + if (sc->sc_type == WM_T_80003) { + /* default to TRUE to enable the MDIC W/A */ + sc->sc_flags |= WM_F_80003_MDIC_WA; + + rv = wm_kmrn_readreg(sc, + KUMCTRLSTA_OFFSET >> KUMCTRLSTA_OFFSET_SHIFT, &kmreg); + if (rv == 0) { + if ((kmreg & KUMCTRLSTA_OPMODE_MASK) + == KUMCTRLSTA_OPMODE_INBAND_MDIO) + sc->sc_flags &= ~WM_F_80003_MDIC_WA; + else + sc->sc_flags |= WM_F_80003_MDIC_WA; + } + } } /* @@ -4822,7 +5135,7 @@ wm_setup_msix(struct wm_softc *sc) } static void -wm_turnon(struct wm_softc *sc) +wm_unset_stopping_flags(struct wm_softc *sc) { int i; @@ -4848,7 +5161,7 @@ wm_turnon(struct wm_softc *sc) } static void -wm_turnoff(struct wm_softc *sc) +wm_set_stopping_flags(struct wm_softc *sc) { int i; @@ -5036,10 +5349,17 @@ wm_init_locked(struct ifnet *ifp) /* Reset the chip to a known state. */ wm_reset(sc); - /* AMT based hardware can now take control from firmware */ + /* + * AMT based hardware can now take control from firmware + * Do this after reset. + */ if ((sc->sc_flags & WM_F_HAS_AMT) != 0) wm_get_hw_control(sc); + if ((sc->sc_type == WM_T_PCH_SPT) && + pci_intr_type(sc->sc_pc, sc->sc_intrs[0]) == PCI_INTR_TYPE_INTX) + wm_legacy_irq_quirk_spt(sc); + /* Init hardware bits */ wm_initialize_hardware_bits(sc); @@ -5131,7 +5451,7 @@ wm_init_locked(struct ifnet *ifp) wm_set_vlan(sc); if (sc->sc_flags & WM_F_HAS_MII) { - int val; + uint16_t kmreg; switch (sc->sc_type) { case WM_T_80003: @@ -5150,19 +5470,20 @@ wm_init_locked(struct ifnet *ifp) */ wm_kmrn_writereg(sc, KUMCTRLSTA_OFFSET_TIMEOUTS, 0xFFFF); - val = wm_kmrn_readreg(sc, KUMCTRLSTA_OFFSET_INB_PARAM); - val |= 0x3F; - wm_kmrn_writereg(sc, - KUMCTRLSTA_OFFSET_INB_PARAM, val); + wm_kmrn_readreg(sc, KUMCTRLSTA_OFFSET_INB_PARAM, + &kmreg); + kmreg |= 0x3F; + wm_kmrn_writereg(sc, KUMCTRLSTA_OFFSET_INB_PARAM, + kmreg); break; default: break; } if (sc->sc_type == WM_T_80003) { - val = CSR_READ(sc, WMREG_CTRL_EXT); - val &= ~CTRL_EXT_LINK_MODE_MASK; - CSR_WRITE(sc, WMREG_CTRL_EXT, val); + reg = CSR_READ(sc, WMREG_CTRL_EXT); + reg &= ~CTRL_EXT_LINK_MODE_MASK; + CSR_WRITE(sc, WMREG_CTRL_EXT, reg); /* Bypass RX and TX FIFO's */ wm_kmrn_writereg(sc, KUMCTRLSTA_OFFSET_FIFO_CTRL, @@ -5363,15 +5684,6 @@ wm_init_locked(struct ifnet *ifp) } else CSR_WRITE(sc, WMREG_IMS, sc->sc_icr); - 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) - || (sc->sc_type == WM_T_PCH2) || (sc->sc_type == WM_T_PCH_LPT) - || (sc->sc_type == WM_T_PCH_SPT)) { - reg = CSR_READ(sc, WMREG_KABGTXD); - reg |= KABGTXD_BGSQLBIAS; - CSR_WRITE(sc, WMREG_KABGTXD, reg); - } - /* Set up the inter-packet gap. */ CSR_WRITE(sc, WMREG_TIPG, sc->sc_tipg); @@ -5477,9 +5789,6 @@ wm_init_locked(struct ifnet *ifp) } else panic("wm_init: i82542 requires MCLBYTES = 2048"); } - /* Set the receive filter. */ - wm_set_filter(sc); - /* Enable ECC */ switch (sc->sc_type) { case WM_T_82571: @@ -5514,7 +5823,10 @@ wm_init_locked(struct ifnet *ifp) } } - wm_turnon(sc); + /* Set the receive filter. */ + wm_set_filter(sc); + + wm_unset_stopping_flags(sc); /* Start the one second link check clock. */ callout_reset(&sc->sc_tick_ch, hz, wm_tick, sc); @@ -5557,7 +5869,7 @@ wm_stop_locked(struct ifnet *ifp, int di device_xname(sc->sc_dev), __func__)); KASSERT(WM_CORE_LOCKED(sc)); - wm_turnoff(sc); + wm_set_stopping_flags(sc); /* Stop the one second clock. */ callout_stop(&sc->sc_tick_ch); @@ -6745,7 +7057,6 @@ wm_send_common_locked(struct ifnet *ifp, { struct wm_softc *sc = ifp->if_softc; struct mbuf *m0; - struct m_tag *mtag; struct wm_txsoft *txs; bus_dmamap_t dmamap; int error, nexttx, lasttx = -1, ofree, seg, segs_needed, use_tso; @@ -6994,11 +7305,11 @@ wm_send_common_locked(struct ifnet *ifp, * * This is only valid on the last descriptor of the packet. */ - if ((mtag = VLAN_OUTPUT_TAG(&sc->sc_ethercom, m0)) != NULL) { + if (vlan_has_tag(m0)) { txq->txq_descs[lasttx].wtx_cmdlen |= htole32(WTX_CMD_VLE); txq->txq_descs[lasttx].wtx_fields.wtxu_vlan - = htole16(VLAN_TAG_VALUE(mtag) & 0xffff); + = htole16(vlan_get_tag(m0)); } txs->txs_lastdesc = lasttx; @@ -7067,7 +7378,6 @@ wm_nq_tx_offload(struct wm_softc *sc, st struct wm_txsoft *txs, uint32_t *cmdlenp, uint32_t *fieldsp, bool *do_csum) { struct mbuf *m0 = txs->txs_mbuf; - struct m_tag *mtag; uint32_t vl_len, mssidx, cmdc; struct ether_header *eh; int offset, iphl; @@ -7111,8 +7421,8 @@ wm_nq_tx_offload(struct wm_softc *sc, st vl_len |= (iphl << NQTXC_VLLEN_IPLEN_SHIFT); KASSERT((iphl & ~NQTXC_VLLEN_IPLEN_MASK) == 0); - if ((mtag = VLAN_OUTPUT_TAG(&sc->sc_ethercom, m0)) != NULL) { - vl_len |= ((VLAN_TAG_VALUE(mtag) & NQTXC_VLLEN_VLAN_MASK) + if (vlan_has_tag(m0)) { + vl_len |= ((vlan_get_tag(m0) & NQTXC_VLLEN_VLAN_MASK) << NQTXC_VLLEN_VLAN_SHIFT); *cmdlenp |= NQTX_CMD_VLE; } @@ -7350,7 +7660,6 @@ wm_nq_send_common_locked(struct ifnet *i { struct wm_softc *sc = ifp->if_softc; struct mbuf *m0; - struct m_tag *mtag; struct wm_txsoft *txs; bus_dmamap_t dmamap; int error, nexttx, lasttx = -1, seg, segs_needed; @@ -7511,12 +7820,11 @@ wm_nq_send_common_locked(struct ifnet *i htole32(WTX_CMD_IFCS | dmamap->dm_segs[0].ds_len); txq->txq_descs[nexttx].wtx_fields.wtxu_status = 0; txq->txq_descs[nexttx].wtx_fields.wtxu_options = 0; - if ((mtag = VLAN_OUTPUT_TAG(&sc->sc_ethercom, m0)) != - NULL) { + if (vlan_has_tag(m0)) { txq->txq_descs[nexttx].wtx_cmdlen |= htole32(WTX_CMD_VLE); txq->txq_descs[nexttx].wtx_fields.wtxu_vlan = - htole16(VLAN_TAG_VALUE(mtag) & 0xffff); + htole16(vlan_get_tag(m0)); } else { txq->txq_descs[nexttx].wtx_fields.wtxu_vlan =0; } @@ -7930,11 +8238,10 @@ static inline bool wm_rxdesc_input_vlantag(struct wm_rxqueue *rxq, uint32_t status, uint16_t vlantag, struct mbuf *m) { - struct ifnet *ifp = &rxq->rxq_sc->sc_ethercom.ec_if; if (wm_rxdesc_is_set_status(rxq->rxq_sc, status, WRX_ST_VP, EXTRXC_STATUS_VP, NQRXC_STATUS_VP)) { - VLAN_INPUT_TAG(ifp, m, le16toh(vlantag), return false); + vlan_set_tag(m, le16toh(vlantag)); } return true; @@ -8190,10 +8497,22 @@ wm_linkintr_gmii(struct wm_softc *sc, ui uint32_t reg; 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", + if ((status & STATUS_LU) != 0) { + DPRINTF(WM_DEBUG_LINK, ("%s: LINK: LSC -> up %s\n", + device_xname(sc->sc_dev), + (status & STATUS_FD) ? "FDX" : "HDX")); + } else { + DPRINTF(WM_DEBUG_LINK, ("%s: LINK: LSC -> down\n", + device_xname(sc->sc_dev))); + } + if ((sc->sc_type == WM_T_ICH8) && ((status & STATUS_LU) == 0)) + wm_gig_downshift_workaround_ich8lan(sc); + + if ((sc->sc_type == WM_T_ICH8) + && (sc->sc_phytype == WMPHY_IGP_3)) { + wm_kmrn_lock_loss_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) { @@ -8231,9 +8550,6 @@ wm_linkintr_gmii(struct wm_softc *sc, ui sc->sc_ctrl |= CTRL_FD; CSR_WRITE(sc, WMREG_CTRL, sc->sc_ctrl); } - } else if ((sc->sc_type == WM_T_ICH8) - && (sc->sc_phytype == WMPHY_IGP_3)) { - wm_kmrn_lock_loss_workaround_ich8lan(sc); } else if (sc->sc_type == WM_T_PCH) { wm_k1_gig_workaround_hv(sc, ((sc->sc_mii.mii_media_status & IFM_ACTIVE) != 0)); @@ -8469,12 +8785,14 @@ wm_intr_legacy(void *arg) uint32_t icr, rndval = 0; int handled = 0; - DPRINTF(WM_DEBUG_TX, - ("%s: INTx: got intr\n", device_xname(sc->sc_dev))); while (1 /* CONSTCOND */) { icr = CSR_READ(sc, WMREG_ICR); if ((icr & sc->sc_icr) == 0) break; + if (handled == 0) { + DPRINTF(WM_DEBUG_TX, + ("%s: INTx: got intr\n",device_xname(sc->sc_dev))); + } if (rndval == 0) rndval = icr; @@ -8496,6 +8814,11 @@ wm_intr_legacy(void *arg) WM_Q_EVCNT_INCR(rxq, rxintr); } #endif + /* + * wm_rxeof() does *not* call upper layer functions directly, + * as if_percpuq_enqueue() just call softint_schedule(). + * So, we can call wm_rxeof() in interrupt context. + */ wm_rxeof(rxq, UINT_MAX); mutex_exit(rxq->rxq_lock); @@ -8854,6 +9177,8 @@ 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_82583: case WM_T_82575: case WM_T_82576: case WM_T_82580: @@ -8864,10 +9189,6 @@ wm_gmii_reset(struct wm_softc *sc) 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 */ @@ -8879,34 +9200,7 @@ wm_gmii_reset(struct wm_softc *sc) case WM_T_PCH2: case WM_T_PCH_LPT: case WM_T_PCH_SPT: - /* Allow time for h/w to get to a quiescent state afer reset */ - delay(10*1000); - - if (sc->sc_type == WM_T_PCH) - wm_hv_phy_workaround_ich8lan(sc); - - if (sc->sc_type == WM_T_PCH2) - wm_lv_phy_workaround_ich8lan(sc); - - /* Clear the host wakeup bit after lcd reset */ - if (sc->sc_type >= WM_T_PCH) { - reg = wm_gmii_hv_readreg(sc->sc_dev, 2, - BM_PORT_GEN_CFG); - reg &= ~BM_WUC_HOST_WU_BIT; - wm_gmii_hv_writereg(sc->sc_dev, 2, - BM_PORT_GEN_CFG, reg); - } - - /* - * XXX Configure the LCD with th extended configuration region - * in NVM - */ - - /* Disable D0 LPLU. */ - if (sc->sc_type >= WM_T_PCH) /* PCH* */ - wm_lplu_d0_disable_pch(sc); - else - wm_lplu_d0_disable(sc); /* ICH* */ + wm_phy_post_reset(sc); break; default: panic("%s: unknown type\n", __func__); @@ -8943,6 +9237,9 @@ wm_gmii_setup_phytype(struct wm_softc *s mii_readreg_t new_readreg; mii_writereg_t new_writereg; + DPRINTF(WM_DEBUG_INIT, ("%s: %s called\n", + device_xname(sc->sc_dev), __func__)); + if (mii->mii_readreg == NULL) { /* * This is the first call of this function. For ICH and PCH @@ -9243,12 +9540,6 @@ wm_gmii_mediainit(struct wm_softc *sc, p /* Initialize our media structures and probe the GMII. */ mii->mii_ifp = ifp; - /* - * The first call of wm_mii_setup_phytype. The result might be - * incorrect. - */ - wm_gmii_setup_phytype(sc, 0, 0); - mii->mii_statchg = wm_gmii_statchg; /* get PHY control from SMBus to PCIe */ @@ -9341,7 +9632,7 @@ wm_gmii_mediainit(struct wm_softc *sc, p /* * PHY Found! Check PHY type again by the second call of - * wm_mii_setup_phytype. + * wm_gmii_setup_phytype. */ wm_gmii_setup_phytype(sc, child->mii_mpd_oui, child->mii_mpd_model); @@ -9367,6 +9658,9 @@ wm_gmii_mediachange(struct ifnet *ifp) if ((ifp->if_flags & IFF_UP) == 0) return 0; + /* Disable D0 LPLU. */ + wm_lplu_d0_disable(sc); + sc->sc_ctrl &= ~(CTRL_SPEED_MASK | CTRL_FD); sc->sc_ctrl |= CTRL_SLU; if ((IFM_SUBTYPE(ife->ifm_media) == IFM_AUTO) @@ -9393,6 +9687,7 @@ wm_gmii_mediachange(struct ifnet *ifp) } } CSR_WRITE(sc, WMREG_CTRL, sc->sc_ctrl); + CSR_WRITE_FLUSH(sc); if (sc->sc_type <= WM_T_82543) wm_gmii_reset(sc); @@ -9497,9 +9792,9 @@ wm_i82543_mii_recvbits(struct wm_softc * * Read a PHY register on the GMII (i82543 version). */ static int -wm_gmii_i82543_readreg(device_t self, int phy, int reg) +wm_gmii_i82543_readreg(device_t dev, int phy, int reg) { - struct wm_softc *sc = device_private(self); + struct wm_softc *sc = device_private(dev); int rv; wm_i82543_mii_sendbits(sc, 0xffffffffU, 32); @@ -9508,7 +9803,7 @@ wm_gmii_i82543_readreg(device_t self, in rv = wm_i82543_mii_recvbits(sc) & 0xffff; DPRINTF(WM_DEBUG_GMII, ("%s: GMII: read phy %d reg %d -> 0x%04x\n", - device_xname(sc->sc_dev), phy, reg, rv)); + device_xname(dev), phy, reg, rv)); return rv; } @@ -9519,9 +9814,9 @@ wm_gmii_i82543_readreg(device_t self, in * Write a PHY register on the GMII (i82543 version). */ static void -wm_gmii_i82543_writereg(device_t self, int phy, int reg, int val) +wm_gmii_i82543_writereg(device_t dev, int phy, int reg, int val) { - struct wm_softc *sc = device_private(self); + struct wm_softc *sc = device_private(dev); wm_i82543_mii_sendbits(sc, 0xffffffffU, 32); wm_i82543_mii_sendbits(sc, val | (MII_COMMAND_ACK << 16) | @@ -9535,12 +9830,18 @@ wm_gmii_i82543_writereg(device_t self, i * Read a PHY register on the GMII. */ static int -wm_gmii_mdic_readreg(device_t self, int phy, int reg) +wm_gmii_mdic_readreg(device_t dev, int phy, int reg) { - struct wm_softc *sc = device_private(self); + struct wm_softc *sc = device_private(dev); uint32_t mdic = 0; int i, rv; + if (reg > MII_ADDRMASK) { + device_printf(dev, "%s: PHYTYPE = %d, addr 0x%x > 0x1f\n", + __func__, sc->sc_phytype, reg); + reg &= MII_ADDRMASK; + } + CSR_WRITE(sc, WMREG_MDIC, MDIC_OP_READ | MDIC_PHYADD(phy) | MDIC_REGADD(reg)); @@ -9553,12 +9854,12 @@ wm_gmii_mdic_readreg(device_t self, int if ((mdic & MDIC_READY) == 0) { log(LOG_WARNING, "%s: MDIC read timed out: phy %d reg %d\n", - device_xname(sc->sc_dev), phy, reg); + device_xname(dev), phy, reg); rv = 0; } else if (mdic & MDIC_E) { #if 0 /* This is normal if no PHY is present. */ log(LOG_WARNING, "%s: MDIC read error: phy %d reg %d\n", - device_xname(sc->sc_dev), phy, reg); + device_xname(dev), phy, reg); #endif rv = 0; } else { @@ -9576,12 +9877,18 @@ wm_gmii_mdic_readreg(device_t self, int * Write a PHY register on the GMII. */ static void -wm_gmii_mdic_writereg(device_t self, int phy, int reg, int val) +wm_gmii_mdic_writereg(device_t dev, int phy, int reg, int val) { - struct wm_softc *sc = device_private(self); + struct wm_softc *sc = device_private(dev); uint32_t mdic = 0; int i; + if (reg > MII_ADDRMASK) { + device_printf(dev, "%s: PHYTYPE = %d, addr 0x%x > 0x1f\n", + __func__, sc->sc_phytype, reg); + reg &= MII_ADDRMASK; + } + CSR_WRITE(sc, WMREG_MDIC, MDIC_OP_WRITE | MDIC_PHYADD(phy) | MDIC_REGADD(reg) | MDIC_DATA(val)); @@ -9594,10 +9901,10 @@ wm_gmii_mdic_writereg(device_t self, int if ((mdic & MDIC_READY) == 0) log(LOG_WARNING, "%s: MDIC write timed out: phy %d reg %d\n", - device_xname(sc->sc_dev), phy, reg); + device_xname(dev), phy, reg); else if (mdic & MDIC_E) log(LOG_WARNING, "%s: MDIC write error: phy %d reg %d\n", - device_xname(sc->sc_dev), phy, reg); + device_xname(dev), phy, reg); } /* @@ -9606,17 +9913,33 @@ wm_gmii_mdic_writereg(device_t self, int * Read a PHY register on the GMII. */ static int -wm_gmii_i82544_readreg(device_t self, int phy, int reg) +wm_gmii_i82544_readreg(device_t dev, int phy, int reg) { - struct wm_softc *sc = device_private(self); + struct wm_softc *sc = device_private(dev); int rv; if (sc->phy.acquire(sc)) { - aprint_error_dev(sc->sc_dev, "%s: failed to get semaphore\n", - __func__); + device_printf(dev, "%s: failed to get semaphore\n", __func__); return 0; } - rv = wm_gmii_mdic_readreg(self, phy, reg); + + if (reg > BME1000_MAX_MULTI_PAGE_REG) { + switch (sc->sc_phytype) { + case WMPHY_IGP: + case WMPHY_IGP_2: + case WMPHY_IGP_3: + wm_gmii_mdic_writereg(dev, phy, MII_IGPHY_PAGE_SELECT, reg); + break; + default: +#ifdef WM_DEBUG + device_printf(dev, "%s: PHYTYPE = 0x%x, addr = %02x\n", + __func__, sc->sc_phytype, reg); +#endif + break; + } + } + + rv = wm_gmii_mdic_readreg(dev, phy, reg & MII_ADDRMASK); sc->phy.release(sc); return rv; @@ -9628,15 +9951,32 @@ wm_gmii_i82544_readreg(device_t self, in * Write a PHY register on the GMII. */ static void -wm_gmii_i82544_writereg(device_t self, int phy, int reg, int val) +wm_gmii_i82544_writereg(device_t dev, int phy, int reg, int val) { - struct wm_softc *sc = device_private(self); + struct wm_softc *sc = device_private(dev); if (sc->phy.acquire(sc)) { - aprint_error_dev(sc->sc_dev, "%s: failed to get semaphore\n", - __func__); + device_printf(dev, "%s: failed to get semaphore\n", __func__); + return; + } + + if (reg > BME1000_MAX_MULTI_PAGE_REG) { + switch (sc->sc_phytype) { + case WMPHY_IGP: + case WMPHY_IGP_2: + case WMPHY_IGP_3: + wm_gmii_mdic_writereg(dev, phy, MII_IGPHY_PAGE_SELECT, reg); + break; + default: +#ifdef WM_DEBUG + device_printf(dev, "%s: PHYTYPE == 0x%x, addr = %02x", + __func__, sc->sc_phytype, reg); +#endif + break; + } } - wm_gmii_mdic_writereg(self, phy, reg, val); + + wm_gmii_mdic_writereg(dev, phy, reg & MII_ADDRMASK, val); sc->phy.release(sc); } @@ -9648,33 +9988,49 @@ wm_gmii_i82544_writereg(device_t self, i * ressource ... */ static int -wm_gmii_i80003_readreg(device_t self, int phy, int reg) +wm_gmii_i80003_readreg(device_t dev, int phy, int reg) { - struct wm_softc *sc = device_private(self); + struct wm_softc *sc = device_private(dev); + int page_select, temp; int rv; if (phy != 1) /* only one PHY on kumeran bus */ return 0; if (sc->phy.acquire(sc)) { - aprint_error_dev(sc->sc_dev, "%s: failed to get semaphore\n", - __func__); + device_printf(dev, "%s: failed to get semaphore\n", __func__); return 0; } - if ((reg & MII_ADDRMASK) < GG82563_MIN_ALT_REG) { - wm_gmii_mdic_writereg(self, phy, GG82563_PHY_PAGE_SELECT, - reg >> GG82563_PAGE_SHIFT); - } else { - wm_gmii_mdic_writereg(self, phy, GG82563_PHY_PAGE_SELECT_ALT, - reg >> GG82563_PAGE_SHIFT); - } - /* Wait more 200us for a bug of the ready bit in the MDIC register */ - delay(200); - rv = wm_gmii_mdic_readreg(self, phy, reg & MII_ADDRMASK); - delay(200); - sc->phy.release(sc); + if ((reg & MII_ADDRMASK) < GG82563_MIN_ALT_REG) + page_select = GG82563_PHY_PAGE_SELECT; + else { + /* + * Use Alternative Page Select register to access registers + * 30 and 31. + */ + page_select = GG82563_PHY_PAGE_SELECT_ALT; + } + temp = (uint16_t)reg >> GG82563_PAGE_SHIFT; + wm_gmii_mdic_writereg(dev, phy, page_select, temp); + if ((sc->sc_flags & WM_F_80003_MDIC_WA) != 0) { + /* + * Wait more 200us for a bug of the ready bit in the MDIC + * register. + */ + delay(200); + if (wm_gmii_mdic_readreg(dev, phy, page_select) != temp) { + device_printf(dev, "%s failed\n", __func__); + rv = 0; /* XXX */ + goto out; + } + rv = wm_gmii_mdic_readreg(dev, phy, reg & MII_ADDRMASK); + delay(200); + } else + rv = wm_gmii_mdic_readreg(dev, phy, reg & MII_ADDRMASK); +out: + sc->phy.release(sc); return rv; } @@ -9686,31 +10042,46 @@ wm_gmii_i80003_readreg(device_t self, in * ressource ... */ static void -wm_gmii_i80003_writereg(device_t self, int phy, int reg, int val) +wm_gmii_i80003_writereg(device_t dev, int phy, int reg, int val) { - struct wm_softc *sc = device_private(self); + struct wm_softc *sc = device_private(dev); + int page_select, temp; if (phy != 1) /* only one PHY on kumeran bus */ return; if (sc->phy.acquire(sc)) { - aprint_error_dev(sc->sc_dev, "%s: failed to get semaphore\n", - __func__); + device_printf(dev, "%s: failed to get semaphore\n", __func__); return; } - if ((reg & MII_ADDRMASK) < GG82563_MIN_ALT_REG) { - wm_gmii_mdic_writereg(self, phy, GG82563_PHY_PAGE_SELECT, - reg >> GG82563_PAGE_SHIFT); - } else { - wm_gmii_mdic_writereg(self, phy, GG82563_PHY_PAGE_SELECT_ALT, - reg >> GG82563_PAGE_SHIFT); - } - /* Wait more 200us for a bug of the ready bit in the MDIC register */ - delay(200); - wm_gmii_mdic_writereg(self, phy, reg & MII_ADDRMASK, val); - delay(200); + if ((reg & MII_ADDRMASK) < GG82563_MIN_ALT_REG) + page_select = GG82563_PHY_PAGE_SELECT; + else { + /* + * Use Alternative Page Select register to access registers + * 30 and 31. + */ + page_select = GG82563_PHY_PAGE_SELECT_ALT; + } + temp = (uint16_t)reg >> GG82563_PAGE_SHIFT; + wm_gmii_mdic_writereg(dev, phy, page_select, temp); + if ((sc->sc_flags & WM_F_80003_MDIC_WA) != 0) { + /* + * Wait more 200us for a bug of the ready bit in the MDIC + * register. + */ + delay(200); + if (wm_gmii_mdic_readreg(dev, phy, page_select) != temp) { + device_printf(dev, "%s failed\n", __func__); + goto out; + } + wm_gmii_mdic_writereg(dev, phy, reg & MII_ADDRMASK, val); + delay(200); + } else + wm_gmii_mdic_writereg(dev, phy, reg & MII_ADDRMASK, val); +out: sc->phy.release(sc); } @@ -9722,16 +10093,15 @@ wm_gmii_i80003_writereg(device_t self, i * ressource ... */ static int -wm_gmii_bm_readreg(device_t self, int phy, int reg) +wm_gmii_bm_readreg(device_t dev, int phy, int reg) { - struct wm_softc *sc = device_private(self); + struct wm_softc *sc = device_private(dev); uint16_t page = reg >> BME1000_PAGE_SHIFT; uint16_t val; int rv; if (sc->phy.acquire(sc)) { - aprint_error_dev(sc->sc_dev, "%s: failed to get semaphore\n", - __func__); + device_printf(dev, "%s: failed to get semaphore\n", __func__); return 0; } @@ -9740,7 +10110,7 @@ wm_gmii_bm_readreg(device_t self, int ph || (reg == 31)) ? 1 : phy; /* Page 800 works differently than the rest so it has its own func */ if (page == BM_WUC_PAGE) { - wm_access_phy_wakeup_reg_bm(self, reg, &val, 1); + wm_access_phy_wakeup_reg_bm(dev, reg, &val, 1); rv = val; goto release; } @@ -9748,14 +10118,14 @@ wm_gmii_bm_readreg(device_t self, int ph if (reg > BME1000_MAX_MULTI_PAGE_REG) { if ((phy == 1) && (sc->sc_type != WM_T_82574) && (sc->sc_type != WM_T_82583)) - wm_gmii_mdic_writereg(self, phy, + wm_gmii_mdic_writereg(dev, phy, MII_IGPHY_PAGE_SELECT, page << BME1000_PAGE_SHIFT); else - wm_gmii_mdic_writereg(self, phy, + wm_gmii_mdic_writereg(dev, phy, BME1000_PHY_PAGE_SELECT, page); } - rv = wm_gmii_mdic_readreg(self, phy, reg & MII_ADDRMASK); + rv = wm_gmii_mdic_readreg(dev, phy, reg & MII_ADDRMASK); release: sc->phy.release(sc); @@ -9770,14 +10140,13 @@ release: * ressource ... */ static void -wm_gmii_bm_writereg(device_t self, int phy, int reg, int val) +wm_gmii_bm_writereg(device_t dev, int phy, int reg, int val) { - struct wm_softc *sc = device_private(self); + struct wm_softc *sc = device_private(dev); uint16_t page = reg >> BME1000_PAGE_SHIFT; if (sc->phy.acquire(sc)) { - aprint_error_dev(sc->sc_dev, "%s: failed to get semaphore\n", - __func__); + device_printf(dev, "%s: failed to get semaphore\n", __func__); return; } @@ -9789,35 +10158,35 @@ wm_gmii_bm_writereg(device_t self, int p uint16_t tmp; tmp = val; - wm_access_phy_wakeup_reg_bm(self, reg, &tmp, 0); + wm_access_phy_wakeup_reg_bm(dev, reg, &tmp, 0); goto release; } if (reg > BME1000_MAX_MULTI_PAGE_REG) { if ((phy == 1) && (sc->sc_type != WM_T_82574) && (sc->sc_type != WM_T_82583)) - wm_gmii_mdic_writereg(self, phy, + wm_gmii_mdic_writereg(dev, phy, MII_IGPHY_PAGE_SELECT, page << BME1000_PAGE_SHIFT); else - wm_gmii_mdic_writereg(self, phy, + wm_gmii_mdic_writereg(dev, phy, BME1000_PHY_PAGE_SELECT, page); } - wm_gmii_mdic_writereg(self, phy, reg & MII_ADDRMASK, val); + wm_gmii_mdic_writereg(dev, phy, reg & MII_ADDRMASK, val); release: sc->phy.release(sc); } static void -wm_access_phy_wakeup_reg_bm(device_t self, int offset, int16_t *val, int rd) +wm_access_phy_wakeup_reg_bm(device_t dev, int offset, int16_t *val, int rd) { - struct wm_softc *sc = device_private(self); + struct wm_softc *sc = device_private(dev); uint16_t regnum = BM_PHY_REG_NUM(offset); uint16_t wuce, reg; DPRINTF(WM_DEBUG_GMII, ("%s: %s called\n", - device_xname(sc->sc_dev), __func__)); + device_xname(dev), __func__)); /* XXX Gig must be disabled for MDIO accesses to page 800 */ if (sc->sc_type == WM_T_PCH) { /* XXX e1000 driver do nothing... why? */ @@ -9829,18 +10198,18 @@ wm_access_phy_wakeup_reg_bm(device_t sel */ /* Set page 769 */ - wm_gmii_mdic_writereg(self, 1, MII_IGPHY_PAGE_SELECT, + wm_gmii_mdic_writereg(dev, 1, MII_IGPHY_PAGE_SELECT, BM_WUC_ENABLE_PAGE << BME1000_PAGE_SHIFT); /* Read WUCE and save it */ - wuce = wm_gmii_mdic_readreg(self, 1, BM_WUC_ENABLE_REG); + wuce = wm_gmii_mdic_readreg(dev, 1, BM_WUC_ENABLE_REG); reg = wuce | BM_WUC_ENABLE_BIT; reg &= ~(BM_WUC_ME_WU_BIT | BM_WUC_HOST_WU_BIT); - wm_gmii_mdic_writereg(self, 1, BM_WUC_ENABLE_REG, reg); + wm_gmii_mdic_writereg(dev, 1, BM_WUC_ENABLE_REG, reg); /* Select page 800 */ - wm_gmii_mdic_writereg(self, 1, MII_IGPHY_PAGE_SELECT, + wm_gmii_mdic_writereg(dev, 1, MII_IGPHY_PAGE_SELECT, BM_WUC_PAGE << BME1000_PAGE_SHIFT); /* @@ -9849,22 +10218,22 @@ wm_access_phy_wakeup_reg_bm(device_t sel */ /* Write page 800 */ - wm_gmii_mdic_writereg(self, 1, BM_WUC_ADDRESS_OPCODE, regnum); + wm_gmii_mdic_writereg(dev, 1, BM_WUC_ADDRESS_OPCODE, regnum); if (rd) - *val = wm_gmii_mdic_readreg(self, 1, BM_WUC_DATA_OPCODE); + *val = wm_gmii_mdic_readreg(dev, 1, BM_WUC_DATA_OPCODE); else - wm_gmii_mdic_writereg(self, 1, BM_WUC_DATA_OPCODE, *val); + wm_gmii_mdic_writereg(dev, 1, BM_WUC_DATA_OPCODE, *val); /* * 3) Disable PHY wakeup register. * See e1000_disable_phy_wakeup_reg_access_bm(). */ /* Set page 769 */ - wm_gmii_mdic_writereg(self, 1, MII_IGPHY_PAGE_SELECT, + wm_gmii_mdic_writereg(dev, 1, MII_IGPHY_PAGE_SELECT, BM_WUC_ENABLE_PAGE << BME1000_PAGE_SHIFT); - wm_gmii_mdic_writereg(self, 1, BM_WUC_ENABLE_REG, wuce); + wm_gmii_mdic_writereg(dev, 1, BM_WUC_ENABLE_REG, wuce); } /* @@ -9875,26 +10244,25 @@ wm_access_phy_wakeup_reg_bm(device_t sel * ressource ... */ static int -wm_gmii_hv_readreg(device_t self, int phy, int reg) +wm_gmii_hv_readreg(device_t dev, int phy, int reg) { - struct wm_softc *sc = device_private(self); + struct wm_softc *sc = device_private(dev); int rv; DPRINTF(WM_DEBUG_GMII, ("%s: %s called\n", - device_xname(sc->sc_dev), __func__)); + device_xname(dev), __func__)); if (sc->phy.acquire(sc)) { - aprint_error_dev(sc->sc_dev, "%s: failed to get semaphore\n", - __func__); + device_printf(dev, "%s: failed to get semaphore\n", __func__); return 0; } - rv = wm_gmii_hv_readreg_locked(self, phy, reg); + rv = wm_gmii_hv_readreg_locked(dev, phy, reg); sc->phy.release(sc); return rv; } static int -wm_gmii_hv_readreg_locked(device_t self, int phy, int reg) +wm_gmii_hv_readreg_locked(device_t dev, int phy, int reg) { uint16_t page = BM_PHY_REG_PAGE(reg); uint16_t regnum = BM_PHY_REG_NUM(reg); @@ -9905,7 +10273,7 @@ wm_gmii_hv_readreg_locked(device_t self, /* Page 800 works differently than the rest so it has its own func */ if (page == BM_WUC_PAGE) { - wm_access_phy_wakeup_reg_bm(self, reg, &val, 1); + wm_access_phy_wakeup_reg_bm(dev, reg, &val, 1); return val; } @@ -9918,12 +10286,19 @@ wm_gmii_hv_readreg_locked(device_t self, return 0; } + /* + * XXX I21[789] documents say that the SMBus Address register is at + * PHY address 01, Page 0 (not 768), Register 26. + */ + if (page == HV_INTC_FC_PAGE_START) + page = 0; + if (regnum > BME1000_MAX_MULTI_PAGE_REG) { - wm_gmii_mdic_writereg(self, 1, MII_IGPHY_PAGE_SELECT, + wm_gmii_mdic_writereg(dev, 1, MII_IGPHY_PAGE_SELECT, page << BME1000_PAGE_SHIFT); } - rv = wm_gmii_mdic_readreg(self, phy, regnum & MII_ADDRMASK); + rv = wm_gmii_mdic_readreg(dev, phy, regnum & MII_ADDRMASK); return rv; } @@ -9935,27 +10310,26 @@ wm_gmii_hv_readreg_locked(device_t self, * ressource ... */ static void -wm_gmii_hv_writereg(device_t self, int phy, int reg, int val) +wm_gmii_hv_writereg(device_t dev, int phy, int reg, int val) { - struct wm_softc *sc = device_private(self); + struct wm_softc *sc = device_private(dev); DPRINTF(WM_DEBUG_GMII, ("%s: %s called\n", - device_xname(sc->sc_dev), __func__)); + device_xname(dev), __func__)); if (sc->phy.acquire(sc)) { - aprint_error_dev(sc->sc_dev, "%s: failed to get semaphore\n", - __func__); + device_printf(dev, "%s: failed to get semaphore\n", __func__); return; } - wm_gmii_hv_writereg_locked(self, phy, reg, val); + wm_gmii_hv_writereg_locked(dev, phy, reg, val); sc->phy.release(sc); } static void -wm_gmii_hv_writereg_locked(device_t self, int phy, int reg, int val) +wm_gmii_hv_writereg_locked(device_t dev, int phy, int reg, int val) { - struct wm_softc *sc = device_private(self); + struct wm_softc *sc = device_private(dev); uint16_t page = BM_PHY_REG_PAGE(reg); uint16_t regnum = BM_PHY_REG_NUM(reg); @@ -9966,7 +10340,7 @@ wm_gmii_hv_writereg_locked(device_t self uint16_t tmp; tmp = val; - wm_access_phy_wakeup_reg_bm(self, reg, &tmp, 0); + wm_access_phy_wakeup_reg_bm(dev, reg, &tmp, 0); return; } @@ -9981,6 +10355,13 @@ wm_gmii_hv_writereg_locked(device_t self { /* + * XXX I21[789] documents say that the SMBus Address register + * is at PHY address 01, Page 0 (not 768), Register 26. + */ + if (page == HV_INTC_FC_PAGE_START) + page = 0; + + /* * XXX Workaround MDIO accesses being disabled after entering * IEEE Power Down (whenever bit 11 of the PHY control * register is set) @@ -9997,12 +10378,12 @@ wm_gmii_hv_writereg_locked(device_t self } if (regnum > BME1000_MAX_MULTI_PAGE_REG) { - wm_gmii_mdic_writereg(self, 1, MII_IGPHY_PAGE_SELECT, + wm_gmii_mdic_writereg(dev, 1, MII_IGPHY_PAGE_SELECT, page << BME1000_PAGE_SHIFT); } } - wm_gmii_mdic_writereg(self, phy, regnum & MII_ADDRMASK, val); + wm_gmii_mdic_writereg(dev, phy, regnum & MII_ADDRMASK, val); } /* @@ -10013,18 +10394,24 @@ wm_gmii_hv_writereg_locked(device_t self * ressource ... */ static int -wm_gmii_82580_readreg(device_t self, int phy, int reg) +wm_gmii_82580_readreg(device_t dev, int phy, int reg) { - struct wm_softc *sc = device_private(self); + struct wm_softc *sc = device_private(dev); int rv; if (sc->phy.acquire(sc) != 0) { - aprint_error_dev(sc->sc_dev, "%s: failed to get semaphore\n", - __func__); + device_printf(dev, "%s: failed to get semaphore\n", __func__); return 0; } - rv = wm_gmii_mdic_readreg(self, phy, reg); +#ifdef DIAGNOSTIC + if (reg > MII_ADDRMASK) { + device_printf(dev, "%s: PHYTYPE = %d, addr 0x%x > 0x1f\n", + __func__, sc->sc_phytype, reg); + reg &= MII_ADDRMASK; + } +#endif + rv = wm_gmii_mdic_readreg(dev, phy, reg); sc->phy.release(sc); return rv; @@ -10038,17 +10425,23 @@ wm_gmii_82580_readreg(device_t self, int * ressource ... */ static void -wm_gmii_82580_writereg(device_t self, int phy, int reg, int val) +wm_gmii_82580_writereg(device_t dev, int phy, int reg, int val) { - struct wm_softc *sc = device_private(self); + struct wm_softc *sc = device_private(dev); if (sc->phy.acquire(sc) != 0) { - aprint_error_dev(sc->sc_dev, "%s: failed to get semaphore\n", - __func__); + device_printf(dev, "%s: failed to get semaphore\n", __func__); return; } - wm_gmii_mdic_writereg(self, phy, reg, val); +#ifdef DIAGNOSTIC + if (reg > MII_ADDRMASK) { + device_printf(dev, "%s: PHYTYPE = %d, addr 0x%x > 0x1f\n", + __func__, sc->sc_phytype, reg); + reg &= MII_ADDRMASK; + } +#endif + wm_gmii_mdic_writereg(dev, phy, reg, val); sc->phy.release(sc); } @@ -10061,26 +10454,25 @@ wm_gmii_82580_writereg(device_t self, in * ressource ... */ static int -wm_gmii_gs40g_readreg(device_t self, int phy, int reg) +wm_gmii_gs40g_readreg(device_t dev, int phy, int reg) { - struct wm_softc *sc = device_private(self); + struct wm_softc *sc = device_private(dev); int page, offset; int rv; /* Acquire semaphore */ if (sc->phy.acquire(sc)) { - aprint_error_dev(sc->sc_dev, "%s: failed to get semaphore\n", - __func__); + device_printf(dev, "%s: failed to get semaphore\n", __func__); return 0; } /* Page select */ page = reg >> GS40G_PAGE_SHIFT; - wm_gmii_mdic_writereg(self, phy, GS40G_PAGE_SELECT, page); + wm_gmii_mdic_writereg(dev, phy, GS40G_PAGE_SELECT, page); /* Read reg */ offset = reg & GS40G_OFFSET_MASK; - rv = wm_gmii_mdic_readreg(self, phy, offset); + rv = wm_gmii_mdic_readreg(dev, phy, offset); sc->phy.release(sc); return rv; @@ -10094,25 +10486,24 @@ wm_gmii_gs40g_readreg(device_t self, int * ressource ... */ static void -wm_gmii_gs40g_writereg(device_t self, int phy, int reg, int val) +wm_gmii_gs40g_writereg(device_t dev, int phy, int reg, int val) { - struct wm_softc *sc = device_private(self); + struct wm_softc *sc = device_private(dev); int page, offset; /* Acquire semaphore */ if (sc->phy.acquire(sc)) { - aprint_error_dev(sc->sc_dev, "%s: failed to get semaphore\n", - __func__); + device_printf(dev, "%s: failed to get semaphore\n", __func__); return; } /* Page select */ page = reg >> GS40G_PAGE_SHIFT; - wm_gmii_mdic_writereg(self, phy, GS40G_PAGE_SELECT, page); + wm_gmii_mdic_writereg(dev, phy, GS40G_PAGE_SELECT, page); /* Write reg */ offset = reg & GS40G_OFFSET_MASK; - wm_gmii_mdic_writereg(self, phy, offset, val); + wm_gmii_mdic_writereg(dev, phy, offset, val); /* Release semaphore */ sc->phy.release(sc); @@ -10190,7 +10581,7 @@ wm_gmii_statchg(struct ifnet *ifp) * Read a kumeran register */ static int -wm_kmrn_readreg(struct wm_softc *sc, int reg) +wm_kmrn_readreg(struct wm_softc *sc, int reg, uint16_t *val) { int rv; @@ -10199,12 +10590,12 @@ wm_kmrn_readreg(struct wm_softc *sc, int else rv = sc->phy.acquire(sc); if (rv != 0) { - aprint_error_dev(sc->sc_dev, - "%s: failed to get semaphore\n", __func__); - return 0; + device_printf(sc->sc_dev, "%s: failed to get semaphore\n", + __func__); + return rv; } - rv = wm_kmrn_readreg_locked(sc, reg); + rv = wm_kmrn_readreg_locked(sc, reg, val); if (sc->sc_type == WM_T_80003) wm_put_swfw_semaphore(sc, SWFW_MAC_CSR_SM); @@ -10215,9 +10606,8 @@ wm_kmrn_readreg(struct wm_softc *sc, int } static int -wm_kmrn_readreg_locked(struct wm_softc *sc, int reg) +wm_kmrn_readreg_locked(struct wm_softc *sc, int reg, uint16_t *val) { - int rv; CSR_WRITE(sc, WMREG_KUMCTRLSTA, ((reg << KUMCTRLSTA_OFFSET_SHIFT) & KUMCTRLSTA_OFFSET) | @@ -10225,9 +10615,9 @@ wm_kmrn_readreg_locked(struct wm_softc * CSR_WRITE_FLUSH(sc); delay(2); - rv = CSR_READ(sc, WMREG_KUMCTRLSTA) & KUMCTRLSTA_MASK; + *val = CSR_READ(sc, WMREG_KUMCTRLSTA) & KUMCTRLSTA_MASK; - return rv; + return 0; } /* @@ -10235,8 +10625,8 @@ wm_kmrn_readreg_locked(struct wm_softc * * * Write a kumeran register */ -static void -wm_kmrn_writereg(struct wm_softc *sc, int reg, int val) +static int +wm_kmrn_writereg(struct wm_softc *sc, int reg, uint16_t val) { int rv; @@ -10245,26 +10635,29 @@ wm_kmrn_writereg(struct wm_softc *sc, in else rv = sc->phy.acquire(sc); if (rv != 0) { - aprint_error_dev(sc->sc_dev, - "%s: failed to get semaphore\n", __func__); - return; + device_printf(sc->sc_dev, "%s: failed to get semaphore\n", + __func__); + return rv; } - wm_kmrn_writereg_locked(sc, reg, val); + rv = wm_kmrn_writereg_locked(sc, reg, val); if (sc->sc_type == WM_T_80003) wm_put_swfw_semaphore(sc, SWFW_MAC_CSR_SM); else sc->phy.release(sc); + + return rv; } -static void -wm_kmrn_writereg_locked(struct wm_softc *sc, int reg, int val) +static int +wm_kmrn_writereg_locked(struct wm_softc *sc, int reg, uint16_t val) { CSR_WRITE(sc, WMREG_KUMCTRLSTA, - ((reg << KUMCTRLSTA_OFFSET_SHIFT) & KUMCTRLSTA_OFFSET) | - (val & KUMCTRLSTA_MASK)); + ((reg << KUMCTRLSTA_OFFSET_SHIFT) & KUMCTRLSTA_OFFSET) | val); + + return 0; } /* SGMII related */ @@ -10310,15 +10703,14 @@ wm_sgmii_uses_mdio(struct wm_softc *sc) * ressource ... */ static int -wm_sgmii_readreg(device_t self, int phy, int reg) +wm_sgmii_readreg(device_t dev, int phy, int reg) { - struct wm_softc *sc = device_private(self); + struct wm_softc *sc = device_private(dev); uint32_t i2ccmd; int i, rv; if (sc->phy.acquire(sc)) { - aprint_error_dev(sc->sc_dev, "%s: failed to get semaphore\n", - __func__); + device_printf(dev, "%s: failed to get semaphore\n", __func__); return 0; } @@ -10335,9 +10727,9 @@ wm_sgmii_readreg(device_t self, int phy, break; } if ((i2ccmd & I2CCMD_READY) == 0) - aprint_error_dev(sc->sc_dev, "I2CCMD Read did not complete\n"); + device_printf(dev, "I2CCMD Read did not complete\n"); if ((i2ccmd & I2CCMD_ERROR) != 0) - aprint_error_dev(sc->sc_dev, "I2CCMD Error bit set\n"); + device_printf(dev, "I2CCMD Error bit set\n"); rv = ((i2ccmd >> 8) & 0x00ff) | ((i2ccmd << 8) & 0xff00); @@ -10353,16 +10745,15 @@ wm_sgmii_readreg(device_t self, int phy, * ressource ... */ static void -wm_sgmii_writereg(device_t self, int phy, int reg, int val) +wm_sgmii_writereg(device_t dev, int phy, int reg, int val) { - struct wm_softc *sc = device_private(self); + struct wm_softc *sc = device_private(dev); uint32_t i2ccmd; int i; int val_swapped; if (sc->phy.acquire(sc) != 0) { - aprint_error_dev(sc->sc_dev, "%s: failed to get semaphore\n", - __func__); + device_printf(dev, "%s: failed to get semaphore\n", __func__); return; } /* Swap the data bytes for the I2C interface */ @@ -10380,9 +10771,9 @@ wm_sgmii_writereg(device_t self, int phy break; } if ((i2ccmd & I2CCMD_READY) == 0) - aprint_error_dev(sc->sc_dev, "I2CCMD Write did not complete\n"); + device_printf(dev, "I2CCMD Write did not complete\n"); if ((i2ccmd & I2CCMD_ERROR) != 0) - aprint_error_dev(sc->sc_dev, "I2CCMD Error bit set\n"); + device_printf(dev, "I2CCMD Error bit set\n"); sc->phy.release(sc); } @@ -10451,9 +10842,9 @@ do { \ status = CSR_READ(sc, WMREG_STATUS); if (((status & STATUS_2P5_SKU) != 0) && ((status & STATUS_2P5_SKU_OVER) == 0)) { - ADD("2500baseKX-FDX", IFM_2500_SX | IFM_FDX,ANAR_X_FD); + ADD("2500baseKX-FDX", IFM_2500_KX | IFM_FDX,ANAR_X_FD); } else - ADD("1000baseSX-FDX", IFM_1000_SX | IFM_FDX,ANAR_X_FD); + ADD("1000baseKX-FDX", IFM_1000_KX | IFM_FDX,ANAR_X_FD); } else if (sc->sc_type == WM_T_82545) { /* Only 82545 is LX (XXX except SFP) */ ADD("1000baseLX", IFM_1000_LX, ANAR_X_HD); @@ -11144,6 +11535,9 @@ wm_nvm_read_uwire(struct wm_softc *sc, i DPRINTF(WM_DEBUG_NVM, ("%s: %s called\n", device_xname(sc->sc_dev), __func__)); + if (sc->nvm.acquire(sc) != 0) + return -1; + for (i = 0; i < wordcnt; i++) { /* Clear SK and DI. */ reg = CSR_READ(sc, WMREG_EECD) & ~(EECD_SK | EECD_DI); @@ -11189,6 +11583,7 @@ wm_nvm_read_uwire(struct wm_softc *sc, i delay(2); } + sc->nvm.release(sc); return 0; } @@ -11217,7 +11612,10 @@ wm_nvm_set_addrbits_size_eecd(struct wm_ case WM_T_82547_2: /* Set dummy value to access EEPROM */ sc->sc_nvm_wordsize = 64; - wm_nvm_read(sc, NVM_OFF_EEPROM_SIZE, 1, &data); + if (wm_nvm_read(sc, NVM_OFF_EEPROM_SIZE, 1, &data) != 0) { + aprint_error_dev(sc->sc_dev, + "%s: failed to read EEPROM size\n", __func__); + } reg = data; size = __SHIFTOUT(reg, EECD_EE_SIZE_EX_MASK); if (size == 0) @@ -11280,7 +11678,7 @@ wm_nvm_ready_spi(struct wm_softc *sc) } if (usec >= SPI_MAX_RETRIES) { aprint_error_dev(sc->sc_dev,"EEPROM failed to become ready\n"); - return 1; + return -1; } return 0; } @@ -11296,18 +11694,22 @@ wm_nvm_read_spi(struct wm_softc *sc, int uint32_t reg, val; int i; uint8_t opc; + int rv = 0; DPRINTF(WM_DEBUG_NVM, ("%s: %s called\n", device_xname(sc->sc_dev), __func__)); + if (sc->nvm.acquire(sc) != 0) + return -1; + /* Clear SK and CS. */ reg = CSR_READ(sc, WMREG_EECD) & ~(EECD_SK | EECD_CS); CSR_WRITE(sc, WMREG_EECD, reg); CSR_WRITE_FLUSH(sc); delay(2); - if (wm_nvm_ready_spi(sc)) - return 1; + if ((rv = wm_nvm_ready_spi(sc)) != 0) + goto out; /* Toggle CS to flush commands. */ CSR_WRITE(sc, WMREG_EECD, reg | EECD_CS); @@ -11335,7 +11737,9 @@ wm_nvm_read_spi(struct wm_softc *sc, int CSR_WRITE_FLUSH(sc); delay(2); - return 0; +out: + sc->nvm.release(sc); + return rv; } /* Using with EERD */ @@ -11365,23 +11769,28 @@ wm_nvm_read_eerd(struct wm_softc *sc, in uint16_t *data) { int i, eerd = 0; - int error = 0; + int rv = 0; DPRINTF(WM_DEBUG_NVM, ("%s: %s called\n", device_xname(sc->sc_dev), __func__)); + if (sc->nvm.acquire(sc) != 0) + return -1; + for (i = 0; i < wordcnt; i++) { eerd = ((offset + i) << EERD_ADDR_SHIFT) | EERD_START; - CSR_WRITE(sc, WMREG_EERD, eerd); - error = wm_poll_eerd_eewr_done(sc, WMREG_EERD); - if (error != 0) + rv = wm_poll_eerd_eewr_done(sc, WMREG_EERD); + if (rv != 0) { + aprint_error_dev(sc->sc_dev, "EERD polling failed: " + "offset=%d. wordcnt=%d\n", offset, wordcnt); break; - + } data[i] = (CSR_READ(sc, WMREG_EERD) >> EERD_DATA_SHIFT); } - return error; + sc->nvm.release(sc); + return rv; } /* Flash */ @@ -11711,7 +12120,7 @@ wm_read_ich8_dword(struct wm_softc *sc, static int wm_nvm_read_ich8(struct wm_softc *sc, int offset, int words, uint16_t *data) { - int32_t error = 0; + int32_t rv = 0; uint32_t flash_bank = 0; uint32_t act_offset = 0; uint32_t bank_offset = 0; @@ -11721,14 +12130,17 @@ wm_nvm_read_ich8(struct wm_softc *sc, in DPRINTF(WM_DEBUG_NVM, ("%s: %s called\n", device_xname(sc->sc_dev), __func__)); + if (sc->nvm.acquire(sc) != 0) + return -1; + /* * We need to know which is the valid flash bank. In the event * that we didn't allocate eeprom_shadow_ram, we may not be * managing flash_bank. So it cannot be trusted and needs * to be updated with each read. */ - error = wm_nvm_valid_bank_detect_ich8lan(sc, &flash_bank); - if (error) { + rv = wm_nvm_valid_bank_detect_ich8lan(sc, &flash_bank); + if (rv) { DPRINTF(WM_DEBUG_NVM, ("%s: failed to detect NVM bank\n", device_xname(sc->sc_dev))); flash_bank = 0; @@ -11740,18 +12152,11 @@ wm_nvm_read_ich8(struct wm_softc *sc, in */ bank_offset = flash_bank * (sc->sc_ich8_flash_bank_size * 2); - error = wm_get_swfwhw_semaphore(sc); - if (error) { - aprint_error_dev(sc->sc_dev, "%s: failed to get semaphore\n", - __func__); - return error; - } - for (i = 0; i < words; i++) { /* The NVM part needs a byte offset, hence * 2 */ act_offset = bank_offset + ((offset + i) * 2); - error = wm_read_ich8_word(sc, act_offset, &word); - if (error) { + rv = wm_read_ich8_word(sc, act_offset, &word); + if (rv) { aprint_error_dev(sc->sc_dev, "%s: failed to read NVM\n", __func__); break; @@ -11759,8 +12164,8 @@ wm_nvm_read_ich8(struct wm_softc *sc, in data[i] = word; } - wm_put_swfwhw_semaphore(sc); - return error; + sc->nvm.release(sc); + return rv; } /****************************************************************************** @@ -11775,7 +12180,7 @@ wm_nvm_read_ich8(struct wm_softc *sc, in static int wm_nvm_read_spt(struct wm_softc *sc, int offset, int words, uint16_t *data) { - int32_t error = 0; + int32_t rv = 0; uint32_t flash_bank = 0; uint32_t act_offset = 0; uint32_t bank_offset = 0; @@ -11785,14 +12190,17 @@ wm_nvm_read_spt(struct wm_softc *sc, int DPRINTF(WM_DEBUG_NVM, ("%s: %s called\n", device_xname(sc->sc_dev), __func__)); + if (sc->nvm.acquire(sc) != 0) + return -1; + /* * We need to know which is the valid flash bank. In the event * that we didn't allocate eeprom_shadow_ram, we may not be * managing flash_bank. So it cannot be trusted and needs * to be updated with each read. */ - error = wm_nvm_valid_bank_detect_ich8lan(sc, &flash_bank); - if (error) { + rv = wm_nvm_valid_bank_detect_ich8lan(sc, &flash_bank); + if (rv) { DPRINTF(WM_DEBUG_NVM, ("%s: failed to detect NVM bank\n", device_xname(sc->sc_dev))); flash_bank = 0; @@ -11804,19 +12212,12 @@ wm_nvm_read_spt(struct wm_softc *sc, int */ bank_offset = flash_bank * (sc->sc_ich8_flash_bank_size * 2); - error = wm_get_swfwhw_semaphore(sc); - if (error) { - aprint_error_dev(sc->sc_dev, "%s: failed to get semaphore\n", - __func__); - return error; - } - for (i = 0; i < words; i++) { /* The NVM part needs a byte offset, hence * 2 */ act_offset = bank_offset + ((offset + i) * 2); /* but we must read dword aligned, so mask ... */ - error = wm_read_ich8_dword(sc, act_offset & ~0x3, &dword); - if (error) { + rv = wm_read_ich8_dword(sc, act_offset & ~0x3, &dword); + if (rv) { aprint_error_dev(sc->sc_dev, "%s: failed to read NVM\n", __func__); break; @@ -11828,8 +12229,8 @@ wm_nvm_read_spt(struct wm_softc *sc, int data[i] = (uint16_t)((dword >> 16) & 0xFFFF); } - wm_put_swfwhw_semaphore(sc); - return error; + sc->nvm.release(sc); + return rv; } /* iNVM */ @@ -11877,6 +12278,9 @@ wm_nvm_read_invm(struct wm_softc *sc, in DPRINTF(WM_DEBUG_NVM, ("%s: %s called\n", device_xname(sc->sc_dev), __func__)); + if (sc->nvm.acquire(sc) != 0) + return -1; + for (i = 0; i < words; i++) { switch (offset + i) { case NVM_OFF_MACADDR: @@ -11931,131 +12335,39 @@ wm_nvm_read_invm(struct wm_softc *sc, in } } + sc->nvm.release(sc); return rv; } /* Lock, detecting NVM type, validate checksum, version and read */ -/* - * wm_nvm_acquire: - * - * Perform the EEPROM handshake required on some chips. - */ static int -wm_nvm_acquire(struct wm_softc *sc) +wm_nvm_is_onboard_eeprom(struct wm_softc *sc) { - uint32_t reg; - int x; - int ret = 0; + uint32_t eecd = 0; - DPRINTF(WM_DEBUG_NVM, ("%s: %s called\n", - device_xname(sc->sc_dev), __func__)); + if (sc->sc_type == WM_T_82573 || sc->sc_type == WM_T_82574 + || sc->sc_type == WM_T_82583) { + eecd = CSR_READ(sc, WMREG_EECD); - if (sc->sc_type >= WM_T_ICH8) { - ret = wm_get_nvm_ich8lan(sc); - } else if (sc->sc_flags & WM_F_LOCK_EXTCNF) { - ret = wm_get_swfwhw_semaphore(sc); - } else if (sc->sc_flags & WM_F_LOCK_SWFW) { - /* This will also do wm_get_swsm_semaphore() if needed */ - ret = wm_get_swfw_semaphore(sc, SWFW_EEP_SM); - } else if (sc->sc_flags & WM_F_LOCK_SWSM) { - ret = wm_get_swsm_semaphore(sc); - } + /* Isolate bits 15 & 16 */ + eecd = ((eecd >> 15) & 0x03); - if (ret) { - aprint_error_dev(sc->sc_dev, "%s: failed to get semaphore\n", - __func__); - return 1; + /* If both bits are set, device is Flash type */ + if (eecd == 0x03) + return 0; } + return 1; +} - if (sc->sc_flags & WM_F_LOCK_EECD) { - reg = CSR_READ(sc, WMREG_EECD); +static int +wm_nvm_get_flash_presence_i210(struct wm_softc *sc) +{ + uint32_t eec; - /* Request EEPROM access. */ - reg |= EECD_EE_REQ; - CSR_WRITE(sc, WMREG_EECD, reg); - - /* ..and wait for it to be granted. */ - for (x = 0; x < 1000; x++) { - reg = CSR_READ(sc, WMREG_EECD); - if (reg & EECD_EE_GNT) - break; - delay(5); - } - if ((reg & EECD_EE_GNT) == 0) { - aprint_error_dev(sc->sc_dev, - "could not acquire EEPROM GNT\n"); - reg &= ~EECD_EE_REQ; - CSR_WRITE(sc, WMREG_EECD, reg); - if (sc->sc_flags & WM_F_LOCK_EXTCNF) - wm_put_swfwhw_semaphore(sc); - if (sc->sc_flags & WM_F_LOCK_SWFW) - wm_put_swfw_semaphore(sc, SWFW_EEP_SM); - else if (sc->sc_flags & WM_F_LOCK_SWSM) - wm_put_swsm_semaphore(sc); - return 1; - } - } - - return 0; -} - -/* - * wm_nvm_release: - * - * Release the EEPROM mutex. - */ -static void -wm_nvm_release(struct wm_softc *sc) -{ - uint32_t reg; - - DPRINTF(WM_DEBUG_NVM, ("%s: %s called\n", - device_xname(sc->sc_dev), __func__)); - - if (sc->sc_flags & WM_F_LOCK_EECD) { - reg = CSR_READ(sc, WMREG_EECD); - reg &= ~EECD_EE_REQ; - CSR_WRITE(sc, WMREG_EECD, reg); - } - - if (sc->sc_type >= WM_T_ICH8) { - wm_put_nvm_ich8lan(sc); - } else if (sc->sc_flags & WM_F_LOCK_EXTCNF) - wm_put_swfwhw_semaphore(sc); - if (sc->sc_flags & WM_F_LOCK_SWFW) - wm_put_swfw_semaphore(sc, SWFW_EEP_SM); - else if (sc->sc_flags & WM_F_LOCK_SWSM) - wm_put_swsm_semaphore(sc); -} - -static int -wm_nvm_is_onboard_eeprom(struct wm_softc *sc) -{ - uint32_t eecd = 0; - - if (sc->sc_type == WM_T_82573 || sc->sc_type == WM_T_82574 - || sc->sc_type == WM_T_82583) { - eecd = CSR_READ(sc, WMREG_EECD); - - /* Isolate bits 15 & 16 */ - eecd = ((eecd >> 15) & 0x03); - - /* If both bits are set, device is Flash type */ - if (eecd == 0x03) - return 0; - } - return 1; -} - -static int -wm_nvm_get_flash_presence_i210(struct wm_softc *sc) -{ - uint32_t eec; - - eec = CSR_READ(sc, WMREG_EEC); - if ((eec & EEC_FLASH_DETECTED) != 0) - return 1; + eec = CSR_READ(sc, WMREG_EEC); + if ((eec & EEC_FLASH_DETECTED) != 0) + return 1; return 0; } @@ -12164,6 +12476,7 @@ wm_nvm_version(struct wm_softc *sc) bool check_version = false; bool check_optionrom = false; bool have_build = false; + bool have_uid = true; /* * Version format: @@ -12182,7 +12495,16 @@ wm_nvm_version(struct wm_softc *sc) * 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); + + /* + * XXX + * Qemu's e1000e emulation (82574L)'s SPI has only 64 words. + * I've never seen on real 82574 hardware with such small SPI ROM. + */ + if ((sc->sc_nvm_wordsize < NVM_OFF_IMAGE_UID1) + || (wm_nvm_read(sc, NVM_OFF_IMAGE_UID1, 1, &uid1) != 0)) + have_uid = false; + switch (sc->sc_type) { case WM_T_82571: case WM_T_82572: @@ -12200,10 +12522,12 @@ wm_nvm_version(struct wm_softc *sc) break; case WM_T_I211: wm_nvm_version_invm(sc); + have_uid = false; goto printver; case WM_T_I210: if (!wm_nvm_get_flash_presence_i210(sc)) { wm_nvm_version_invm(sc); + have_uid = false; goto printver; } /* FALLTHROUGH */ @@ -12215,8 +12539,8 @@ wm_nvm_version(struct wm_softc *sc) default: return; } - if (check_version) { - wm_nvm_read(sc, NVM_OFF_VERSION, 1, &nvm_data); + if (check_version + && (wm_nvm_read(sc, NVM_OFF_VERSION, 1, &nvm_data) == 0)) { 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; @@ -12238,14 +12562,18 @@ printver: aprint_verbose(".%d", build); } } - if (check_optionrom) { - wm_nvm_read(sc, NVM_OFF_COMB_VER_PTR, 1, &off); + + /* Assume the Option ROM area is at avove NVM_SIZE */ + if ((sc->sc_nvm_wordsize > NVM_SIZE) && check_optionrom + && (wm_nvm_read(sc, NVM_OFF_COMB_VER_PTR, 1, &off) == 0)) { /* Option ROM Version */ if ((off != 0x0000) && (off != 0xffff)) { + int rv; + 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) + rv = wm_nvm_read(sc, off + 1, 1, &uid1); + rv |= wm_nvm_read(sc, off, 1, &uid0); + if ((rv == 0) && (uid0 != 0) && (uid0 != 0xffff) && (uid1 != 0) && (uid1 != 0xffff)) { /* 16bits */ major = uid0 >> 8; @@ -12257,8 +12585,8 @@ printver: } } - wm_nvm_read(sc, NVM_OFF_IMAGE_UID0, 1, &uid0); - aprint_verbose(", Image Unique ID %08x", (uid1 << 16) | uid0); + if (have_uid && (wm_nvm_read(sc, NVM_OFF_IMAGE_UID0, 1, &uid0) == 0)) + aprint_verbose(", Image Unique ID %08x", (uid1 << 16) | uid0); } /* @@ -12275,27 +12603,10 @@ wm_nvm_read(struct wm_softc *sc, int wor device_xname(sc->sc_dev), __func__)); if (sc->sc_flags & WM_F_EEPROM_INVALID) - return 1; - - if (wm_nvm_acquire(sc)) - return 1; - - 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) - || (sc->sc_type == WM_T_PCH2) || (sc->sc_type == WM_T_PCH_LPT)) - rv = wm_nvm_read_ich8(sc, word, wordcnt, data); - else if (sc->sc_type == WM_T_PCH_SPT) - rv = wm_nvm_read_spt(sc, word, wordcnt, data); - else if (sc->sc_flags & WM_F_EEPROM_INVM) - rv = wm_nvm_read_invm(sc, word, wordcnt, data); - else if (sc->sc_flags & WM_F_EEPROM_EERDEEWR) - rv = wm_nvm_read_eerd(sc, word, wordcnt, data); - else if (sc->sc_flags & WM_F_EEPROM_SPI) - rv = wm_nvm_read_spi(sc, word, wordcnt, data); - else - rv = wm_nvm_read_uwire(sc, word, wordcnt, data); + return -1; - wm_nvm_release(sc); + rv = sc->nvm.read(sc, word, wordcnt, data); + return rv; } @@ -12322,6 +12633,94 @@ wm_put_null(struct wm_softc *sc) return; } +static int +wm_get_eecd(struct wm_softc *sc) +{ + uint32_t reg; + int x; + + DPRINTF(WM_DEBUG_LOCK | WM_DEBUG_NVM, ("%s: %s called\n", + device_xname(sc->sc_dev), __func__)); + + reg = CSR_READ(sc, WMREG_EECD); + + /* Request EEPROM access. */ + reg |= EECD_EE_REQ; + CSR_WRITE(sc, WMREG_EECD, reg); + + /* ..and wait for it to be granted. */ + for (x = 0; x < 1000; x++) { + reg = CSR_READ(sc, WMREG_EECD); + if (reg & EECD_EE_GNT) + break; + delay(5); + } + if ((reg & EECD_EE_GNT) == 0) { + aprint_error_dev(sc->sc_dev, + "could not acquire EEPROM GNT\n"); + reg &= ~EECD_EE_REQ; + CSR_WRITE(sc, WMREG_EECD, reg); + return -1; + } + + return 0; +} + +static void +wm_nvm_eec_clock_raise(struct wm_softc *sc, uint32_t *eecd) +{ + + *eecd |= EECD_SK; + CSR_WRITE(sc, WMREG_EECD, *eecd); + CSR_WRITE_FLUSH(sc); + if ((sc->sc_flags & WM_F_EEPROM_SPI) != 0) + delay(1); + else + delay(50); +} + +static void +wm_nvm_eec_clock_lower(struct wm_softc *sc, uint32_t *eecd) +{ + + *eecd &= ~EECD_SK; + CSR_WRITE(sc, WMREG_EECD, *eecd); + CSR_WRITE_FLUSH(sc); + if ((sc->sc_flags & WM_F_EEPROM_SPI) != 0) + delay(1); + else + delay(50); +} + +static void +wm_put_eecd(struct wm_softc *sc) +{ + uint32_t reg; + + DPRINTF(WM_DEBUG_LOCK, ("%s: %s called\n", + device_xname(sc->sc_dev), __func__)); + + /* Stop nvm */ + reg = CSR_READ(sc, WMREG_EECD); + if ((sc->sc_flags & WM_F_EEPROM_SPI) != 0) { + /* Pull CS high */ + reg |= EECD_CS; + wm_nvm_eec_clock_lower(sc, ®); + } else { + /* CS on Microwire is active-high */ + reg &= ~(EECD_CS | EECD_DI); + CSR_WRITE(sc, WMREG_EECD, reg); + wm_nvm_eec_clock_raise(sc, ®); + wm_nvm_eec_clock_lower(sc, ®); + } + + reg = CSR_READ(sc, WMREG_EECD); + reg &= ~EECD_EE_REQ; + CSR_WRITE(sc, WMREG_EECD, reg); + + return; +} + /* * Get hardware semaphore. * Same as e1000_get_hw_semaphore_generic() @@ -12336,6 +12735,7 @@ wm_get_swsm_semaphore(struct wm_softc *s device_xname(sc->sc_dev), __func__)); KASSERT(sc->sc_nvm_wordsize > 0); +retry: /* Get the SW semaphore. */ timeout = sc->sc_nvm_wordsize + 1; while (timeout) { @@ -12349,6 +12749,16 @@ wm_get_swsm_semaphore(struct wm_softc *s } if (timeout == 0) { + if ((sc->sc_flags & WM_F_WA_I210_CLSEM) != 0) { + /* + * In rare circumstances, the SW semaphore may already + * be held unintentionally. Clear the semaphore once + * before giving up. + */ + sc->sc_flags &= ~WM_F_WA_I210_CLSEM; + wm_put_swsm_semaphore(sc); + goto retry; + } aprint_error_dev(sc->sc_dev, "could not acquire SWSM SMBI\n"); return 1; @@ -12398,7 +12808,7 @@ wm_put_swsm_semaphore(struct wm_softc *s /* * Get SW/FW semaphore. - * Same as e1000_acquire_swfw_sync_82575(). + * Same as e1000_acquire_swfw_sync_{80003es2lan,82575}(). */ static int wm_get_swfw_semaphore(struct wm_softc *sc, uint16_t mask) @@ -12406,31 +12816,31 @@ wm_get_swfw_semaphore(struct wm_softc *s uint32_t swfw_sync; uint32_t swmask = mask << SWFW_SOFT_SHIFT; uint32_t fwmask = mask << SWFW_FIRM_SHIFT; - int timeout = 200; + int timeout; DPRINTF(WM_DEBUG_LOCK, ("%s: %s called\n", device_xname(sc->sc_dev), __func__)); - KASSERT((sc->sc_flags & WM_F_LOCK_SWSM) != 0); + + if (sc->sc_type == WM_T_80003) + timeout = 50; + else + timeout = 200; for (timeout = 0; timeout < 200; timeout++) { - if (sc->sc_flags & WM_F_LOCK_SWSM) { - if (wm_get_swsm_semaphore(sc)) { - aprint_error_dev(sc->sc_dev, - "%s: failed to get semaphore\n", - __func__); - return 1; - } + if (wm_get_swsm_semaphore(sc)) { + aprint_error_dev(sc->sc_dev, + "%s: failed to get semaphore\n", + __func__); + return 1; } swfw_sync = CSR_READ(sc, WMREG_SW_FW_SYNC); if ((swfw_sync & (swmask | fwmask)) == 0) { swfw_sync |= swmask; CSR_WRITE(sc, WMREG_SW_FW_SYNC, swfw_sync); - if (sc->sc_flags & WM_F_LOCK_SWSM) - wm_put_swsm_semaphore(sc); + wm_put_swsm_semaphore(sc); return 0; } - if (sc->sc_flags & WM_F_LOCK_SWSM) - wm_put_swsm_semaphore(sc); + wm_put_swsm_semaphore(sc); delay(5000); } printf("%s: failed to get swfw semaphore mask 0x%x swfw 0x%x\n", @@ -12445,17 +12855,103 @@ wm_put_swfw_semaphore(struct wm_softc *s DPRINTF(WM_DEBUG_LOCK, ("%s: %s called\n", device_xname(sc->sc_dev), __func__)); - KASSERT((sc->sc_flags & WM_F_LOCK_SWSM) != 0); - if (sc->sc_flags & WM_F_LOCK_SWSM) { - while (wm_get_swsm_semaphore(sc) != 0) - continue; - } + while (wm_get_swsm_semaphore(sc) != 0) + continue; + swfw_sync = CSR_READ(sc, WMREG_SW_FW_SYNC); swfw_sync &= ~(mask << SWFW_SOFT_SHIFT); CSR_WRITE(sc, WMREG_SW_FW_SYNC, swfw_sync); - if (sc->sc_flags & WM_F_LOCK_SWSM) + + wm_put_swsm_semaphore(sc); +} + +static int +wm_get_nvm_80003(struct wm_softc *sc) +{ + int rv; + + DPRINTF(WM_DEBUG_LOCK | WM_DEBUG_NVM, ("%s: %s called\n", + device_xname(sc->sc_dev), __func__)); + + if ((rv = wm_get_swfw_semaphore(sc, SWFW_EEP_SM)) != 0) { + aprint_error_dev(sc->sc_dev, + "%s: failed to get semaphore(SWFW)\n", + __func__); + return rv; + } + + if (((sc->sc_flags & WM_F_LOCK_EECD) != 0) + && (rv = wm_get_eecd(sc)) != 0) { + aprint_error_dev(sc->sc_dev, + "%s: failed to get semaphore(EECD)\n", + __func__); + wm_put_swfw_semaphore(sc, SWFW_EEP_SM); + return rv; + } + + return 0; +} + +static void +wm_put_nvm_80003(struct wm_softc *sc) +{ + + DPRINTF(WM_DEBUG_LOCK, ("%s: %s called\n", + device_xname(sc->sc_dev), __func__)); + + if ((sc->sc_flags & WM_F_LOCK_EECD) != 0) + wm_put_eecd(sc); + wm_put_swfw_semaphore(sc, SWFW_EEP_SM); +} + +static int +wm_get_nvm_82571(struct wm_softc *sc) +{ + int rv; + + DPRINTF(WM_DEBUG_LOCK, ("%s: %s called\n", + device_xname(sc->sc_dev), __func__)); + + if ((rv = wm_get_swsm_semaphore(sc)) != 0) + return rv; + + switch (sc->sc_type) { + case WM_T_82573: + break; + default: + if ((sc->sc_flags & WM_F_LOCK_EECD) != 0) + rv = wm_get_eecd(sc); + break; + } + + if (rv != 0) { + aprint_error_dev(sc->sc_dev, + "%s: failed to get semaphore\n", + __func__); wm_put_swsm_semaphore(sc); + } + + return rv; +} + +static void +wm_put_nvm_82571(struct wm_softc *sc) +{ + + DPRINTF(WM_DEBUG_LOCK, ("%s: %s called\n", + device_xname(sc->sc_dev), __func__)); + + switch (sc->sc_type) { + case WM_T_82573: + break; + default: + if ((sc->sc_flags & WM_F_LOCK_EECD) != 0) + wm_put_eecd(sc); + break; + } + + wm_put_swsm_semaphore(sc); } static int @@ -13041,18 +13537,6 @@ wm_get_wakeup(struct wm_softc *sc) if (wm_enable_mng_pass_thru(sc) != 0) sc->sc_flags |= WM_F_HAS_MANAGE; -#ifdef WM_DEBUG - printf("\n"); - if ((sc->sc_flags & WM_F_HAS_AMT) != 0) - printf("HAS_AMT,"); - if ((sc->sc_flags & WM_F_ARC_SUBSYS_VALID) != 0) - printf("ARC_SUBSYS_VALID,"); - if ((sc->sc_flags & WM_F_ASF_FIRMWARE_PRES) != 0) - printf("ASF_FIRMWARE_PRES,"); - if ((sc->sc_flags & WM_F_HAS_MANAGE) != 0) - printf("HAS_MANAGE,"); - printf("\n"); -#endif /* * Note that the WOL flags is set after the resetting of the eeprom * stuff @@ -13308,28 +13792,56 @@ wm_enable_wakeup(struct wm_softc *sc) static void wm_lplu_d0_disable(struct wm_softc *sc) { + struct mii_data *mii = &sc->sc_mii; uint32_t reg; DPRINTF(WM_DEBUG_INIT, ("%s: %s called\n", device_xname(sc->sc_dev), __func__)); - 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; - - DPRINTF(WM_DEBUG_INIT, ("%s: %s called\n", - device_xname(sc->sc_dev), __func__)); + if (sc->sc_phytype == WMPHY_IFE) + return; - 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); + switch (sc->sc_type) { + case WM_T_82571: + case WM_T_82572: + case WM_T_82573: + case WM_T_82575: + case WM_T_82576: + reg = mii->mii_readreg(sc->sc_dev, 1, MII_IGPHY_POWER_MGMT); + reg &= ~PMR_D0_LPLU; + mii->mii_writereg(sc->sc_dev, 1, MII_IGPHY_POWER_MGMT, reg); + break; + case WM_T_82580: + case WM_T_I350: + case WM_T_I210: + case WM_T_I211: + reg = CSR_READ(sc, WMREG_PHPM); + reg &= ~PHPM_D0A_LPLU; + CSR_WRITE(sc, WMREG_PHPM, reg); + break; + case WM_T_82574: + case WM_T_82583: + case WM_T_ICH8: + case WM_T_ICH9: + case WM_T_ICH10: + reg = CSR_READ(sc, WMREG_PHY_CTRL); + reg &= ~(PHY_CTRL_GBE_DIS | PHY_CTRL_D0A_LPLU); + CSR_WRITE(sc, WMREG_PHY_CTRL, reg); + CSR_WRITE_FLUSH(sc); + break; + case WM_T_PCH: + case WM_T_PCH2: + case WM_T_PCH_LPT: + case WM_T_PCH_SPT: + reg = wm_gmii_hv_readreg(sc->sc_dev, 1, HV_OEM_BITS); + reg &= ~(HV_OEM_BITS_A1KDIS | HV_OEM_BITS_LPLU); + if (wm_phy_resetisblocked(sc) == false) + reg |= HV_OEM_BITS_ANEGNOW; + wm_gmii_hv_writereg(sc->sc_dev, 1, HV_OEM_BITS, reg); + break; + default: + break; + } } /* EEE */ @@ -13368,31 +13880,32 @@ 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; + struct mii_data *mii = &sc->sc_mii; + uint32_t status = CSR_READ(sc, WMREG_STATUS); + int i; int reg; - miistatus = sc->sc_mii.mii_media_status; + DPRINTF(WM_DEBUG_INIT, ("%s: %s called\n", + device_xname(sc->sc_dev), __func__)); /* If the link is not up, do nothing */ - if ((miistatus & IFM_ACTIVE) == 0) + if ((status & STATUS_LU) == 0) return; - active = sc->sc_mii.mii_media_active; - /* Nothing to do if the link is other than 1Gbps */ - if (IFM_SUBTYPE(active) != IFM_1000_T) + if (__SHIFTOUT(status, STATUS_SPEED) != STATUS_SPEED_1000) return; + reg = CSR_READ(sc, WMREG_PHY_CTRL); for (i = 0; i < 10; i++) { /* 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); + reg = mii->mii_readreg(sc->sc_dev, 1, IGP3_KMRN_DIAG); + reg = mii->mii_readreg(sc->sc_dev, 1, IGP3_KMRN_DIAG); if ((reg & IGP3_KMRN_DIAG_PCS_LOCK_LOSS) == 0) goto out; /* GOOD! */ /* Reset the PHY */ - wm_gmii_reset(sc); + wm_reset_phy(sc); delay(5*1000); } @@ -13409,22 +13922,23 @@ wm_kmrn_lock_loss_workaround_ich8lan(str out: return; -#endif } /* WOL from S5 stops working */ static void wm_gig_downshift_workaround_ich8lan(struct wm_softc *sc) { - uint16_t kmrn_reg; + uint16_t kmreg; /* Only for igp3 */ if (sc->sc_phytype == WMPHY_IGP_3) { - kmrn_reg = wm_kmrn_readreg(sc, KUMCTRLSTA_OFFSET_DIAG); - kmrn_reg |= KUMCTRLSTA_DIAG_NELPBK; - wm_kmrn_writereg(sc, KUMCTRLSTA_OFFSET_DIAG, kmrn_reg); - kmrn_reg &= ~KUMCTRLSTA_DIAG_NELPBK; - wm_kmrn_writereg(sc, KUMCTRLSTA_OFFSET_DIAG, kmrn_reg); + if (wm_kmrn_readreg(sc, KUMCTRLSTA_OFFSET_DIAG, &kmreg) != 0) + return; + kmreg |= KUMCTRLSTA_DIAG_NELPBK; + if (wm_kmrn_writereg(sc, KUMCTRLSTA_OFFSET_DIAG, kmreg) != 0) + return; + kmreg &= ~KUMCTRLSTA_DIAG_NELPBK; + wm_kmrn_writereg(sc, KUMCTRLSTA_OFFSET_DIAG, kmreg); } } @@ -13528,16 +14042,21 @@ static void wm_configure_k1_ich8lan(struct wm_softc *sc, int k1_enable) { uint32_t ctrl, ctrl_ext, tmp; - uint16_t kmrn_reg; + uint16_t kmreg; + int rv; - kmrn_reg = wm_kmrn_readreg_locked(sc, KUMCTRLSTA_OFFSET_K1_CONFIG); + rv = wm_kmrn_readreg_locked(sc, KUMCTRLSTA_OFFSET_K1_CONFIG, &kmreg); + if (rv != 0) + return; if (k1_enable) - kmrn_reg |= KUMCTRLSTA_K1_ENABLE; + kmreg |= KUMCTRLSTA_K1_ENABLE; else - kmrn_reg &= ~KUMCTRLSTA_K1_ENABLE; + kmreg &= ~KUMCTRLSTA_K1_ENABLE; - wm_kmrn_writereg_locked(sc, KUMCTRLSTA_OFFSET_K1_CONFIG, kmrn_reg); + rv = wm_kmrn_writereg_locked(sc, KUMCTRLSTA_OFFSET_K1_CONFIG, kmreg); + if (rv != 0) + return; delay(20); @@ -13556,6 +14075,8 @@ wm_configure_k1_ich8lan(struct wm_softc CSR_WRITE(sc, WMREG_CTRL_EXT, ctrl_ext); CSR_WRITE_FLUSH(sc); delay(20); + + return; } /* special case - for 82575 - need to do manual init ... */ @@ -13715,15 +14236,36 @@ wm_platform_pm_pch_lpt(struct wm_softc * | __SHIFTIN(link, LTRV_SNOOP_REQ) | LTRV_SEND; uint32_t rxa; uint16_t scale = 0, lat_enc = 0; + int32_t obff_hwm = 0; int64_t lat_ns, value; DPRINTF(WM_DEBUG_INIT, ("%s: %s called\n", device_xname(sc->sc_dev), __func__)); if (link) { - pcireg_t preg; uint16_t max_snoop, max_nosnoop, max_ltr_enc; + uint32_t status; + uint16_t speed; + pcireg_t preg; + + status = CSR_READ(sc, WMREG_STATUS); + switch (__SHIFTOUT(status, STATUS_SPEED)) { + case STATUS_SPEED_10: + speed = 10; + break; + case STATUS_SPEED_100: + speed = 100; + break; + case STATUS_SPEED_1000: + speed = 1000; + break; + default: + device_printf(sc->sc_dev, "Unknown speed " + "(status = %08x)\n", status); + return -1; + } + /* Rx Packet Buffer Allocation size (KB) */ rxa = CSR_READ(sc, WMREG_PBA) & PBA_RXA_MASK; /* @@ -13736,31 +14278,12 @@ wm_platform_pm_pch_lpt(struct wm_softc * * 1=2^5ns, 2=2^10ns,...5=2^25ns. */ lat_ns = ((int64_t)rxa * 1024 - - (2 * (int64_t)sc->sc_ethercom.ec_if.if_mtu)) * 8 * 1000; + (2 * ((int64_t)sc->sc_ethercom.ec_if.if_mtu + + ETHER_HDR_LEN))) * 8 * 1000; if (lat_ns < 0) lat_ns = 0; - else { - uint32_t status; - uint16_t speed; - - status = CSR_READ(sc, WMREG_STATUS); - switch (__SHIFTOUT(status, STATUS_SPEED)) { - case STATUS_SPEED_10: - speed = 10; - break; - case STATUS_SPEED_100: - speed = 100; - break; - case STATUS_SPEED_1000: - speed = 1000; - break; - default: - printf("%s: Unknown speed (status = %08x)\n", - device_xname(sc->sc_dev), status); - return -1; - } + else lat_ns /= speed; - } value = lat_ns; while (value > LTRV_VALUE) { @@ -13774,6 +14297,7 @@ wm_platform_pm_pch_lpt(struct wm_softc * } lat_enc = (uint16_t)(__SHIFTIN(scale, LTRV_SCALE) | value); + /* Determine the maximum latency tolerated by the platform */ preg = pci_conf_read(sc->sc_pc, sc->sc_pcitag, WM_PCI_LTR_CAP_LPT); max_snoop = preg & 0xffff; @@ -13783,12 +14307,39 @@ wm_platform_pm_pch_lpt(struct wm_softc * if (lat_enc > max_ltr_enc) { lat_enc = max_ltr_enc; + lat_ns = __SHIFTOUT(lat_enc, PCI_LTR_MAXSNOOPLAT_VAL) + * PCI_LTR_SCALETONS( + __SHIFTOUT(lat_enc, + PCI_LTR_MAXSNOOPLAT_SCALE)); + } + + if (lat_ns) { + lat_ns *= speed * 1000; + lat_ns /= 8; + lat_ns /= 1000000000; + obff_hwm = (int32_t)(rxa - lat_ns); + } + if ((obff_hwm < 0) || (obff_hwm > SVT_OFF_HWM)) { + device_printf(sc->sc_dev, "Invalid high water mark %d" + "(rxa = %d, lat_ns = %d)\n", + obff_hwm, (int32_t)rxa, (int32_t)lat_ns); + return -1; } } /* Snoop and No-Snoop latencies the same */ reg |= lat_enc | __SHIFTIN(lat_enc, LTRV_NONSNOOP); CSR_WRITE(sc, WMREG_LTRV, reg); + /* Set OBFF high water mark */ + reg = CSR_READ(sc, WMREG_SVT) & ~SVT_OFF_HWM; + reg |= obff_hwm; + CSR_WRITE(sc, WMREG_SVT, reg); + + /* Enable OBFF */ + reg = CSR_READ(sc, WMREG_SVCR); + reg |= SVCR_OFF_EN | SVCR_OFF_MASKINT; + CSR_WRITE(sc, WMREG_SVCR, reg); + return 0; } @@ -13866,3 +14417,21 @@ wm_pll_workaround_i210(struct wm_softc * if (wa_done) aprint_verbose_dev(sc->sc_dev, "I210 workaround done\n"); } + +static void +wm_legacy_irq_quirk_spt(struct wm_softc *sc) +{ + uint32_t reg; + + DPRINTF(WM_DEBUG_INIT, ("%s: %s called\n", + device_xname(sc->sc_dev), __func__)); + KASSERT(sc->sc_type == WM_T_PCH_SPT); + + reg = CSR_READ(sc, WMREG_FEXTNVM7); + reg |= FEXTNVM7_SIDE_CLK_UNGATE; + CSR_WRITE(sc, WMREG_FEXTNVM7, reg); + + reg = CSR_READ(sc, WMREG_FEXTNVM9); + reg |= FEXTNVM9_IOSFSB_CLKGATE_DIS | FEXTNVM9_IOSFSB_CLKREQ_DIS; + CSR_WRITE(sc, WMREG_FEXTNVM9, reg); +}