Module Name:    src
Committed By:   riz
Date:           Sun Jul 14 20:39:13 UTC 2013

Modified Files:
        src/sys/dev/pci [netbsd-6]: if_wm.c if_wmreg.h if_wmvar.h

Log Message:
Apply changes (requested by msaitoh in ticket #907):

sys/dev/pci/if_wm.c                             1.238, 1.244-1.247, 1.249-1.258
sys/dev/pci/if_wmreg.h                          1.50-1.51, 1.53
sys/dev/pci/if_wmvar.h                          1.15-1.16

        Various fixes to wm(4):
        Add I21[0178] support.
        Fix a bug that wm_attach() may fail on some PCH2 or newer system.
        wm_valid_nvm_bank_detect_ich8lan() misunderstood the NVM's bank
        number. Fixes PR#47878.
        Fix a bug that the check of reset complete fails on Intel 8 series
        with "wm_lan_init_done: lan_init_done failed to complete" message.
        The broken code was used for ICH8, 9... and PCH2.
        The wm_linkintr_gmii() function is called from interrupt. That's
        not tick, so call mii_pollstat() instead of mii_tick().
        Add ECC support for the packet buffer. Only 82571 and I21[78] support
        ECC.
        Fix a bug that wrong semaphore is used in wm_gmii_hv_{read,write}reg.
        Change style, add comments, fix some comments, use macros and
        remove trailing whitespaces.
        [msaitoh, ticket #907]


To generate a diff of this commit:
cvs rdiff -u -r1.227.2.8 -r1.227.2.9 src/sys/dev/pci/if_wm.c
cvs rdiff -u -r1.46.2.3 -r1.46.2.4 src/sys/dev/pci/if_wmreg.h
cvs rdiff -u -r1.12.10.2 -r1.12.10.3 src/sys/dev/pci/if_wmvar.h

Please note that diffs are not public domain; they are subject to the
copyright notices on the relevant files.

Modified files:

Index: src/sys/dev/pci/if_wm.c
diff -u src/sys/dev/pci/if_wm.c:1.227.2.8 src/sys/dev/pci/if_wm.c:1.227.2.9
--- src/sys/dev/pci/if_wm.c:1.227.2.8	Mon Feb 18 18:05:29 2013
+++ src/sys/dev/pci/if_wm.c	Sun Jul 14 20:39:13 2013
@@ -1,4 +1,4 @@
-/*	$NetBSD: if_wm.c,v 1.227.2.8 2013/02/18 18:05:29 riz Exp $	*/
+/*	$NetBSD: if_wm.c,v 1.227.2.9 2013/07/14 20:39:13 riz Exp $	*/
 
 /*
  * Copyright (c) 2001, 2002, 2003, 2004 Wasabi Systems, Inc.
@@ -37,32 +37,32 @@
 
 /*******************************************************************************
 
-  Copyright (c) 2001-2005, Intel Corporation 
+  Copyright (c) 2001-2005, Intel Corporation
   All rights reserved.
-  
-  Redistribution and use in source and binary forms, with or without 
+ 
+  Redistribution and use in source and binary forms, with or without
   modification, are permitted provided that the following conditions are met:
-  
-   1. Redistributions of source code must retain the above copyright notice, 
+ 
+   1. Redistributions of source code must retain the above copyright notice,
       this list of conditions and the following disclaimer.
-  
-   2. Redistributions in binary form must reproduce the above copyright 
-      notice, this list of conditions and the following disclaimer in the 
+ 
+   2. Redistributions in binary form must reproduce the above copyright
+      notice, this list of conditions and the following disclaimer in the
       documentation and/or other materials provided with the distribution.
-  
-   3. Neither the name of the Intel Corporation nor the names of its 
-      contributors may be used to endorse or promote products derived from 
+ 
+   3. Neither the name of the Intel Corporation nor the names of its
+      contributors may be used to endorse or promote products derived from
       this software without specific prior written permission.
-  
+ 
   THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
-  AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 
-  IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 
-  ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE 
-  LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 
-  CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 
-  SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 
-  INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 
-  CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 
+  AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+  IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+  ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
+  LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+  CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+  SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+  INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+  CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
   ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
   POSSIBILITY OF SUCH DAMAGE.
 
@@ -76,7 +76,7 @@
  */
 
 #include <sys/cdefs.h>
-__KERNEL_RCSID(0, "$NetBSD: if_wm.c,v 1.227.2.8 2013/02/18 18:05:29 riz Exp $");
+__KERNEL_RCSID(0, "$NetBSD: if_wm.c,v 1.227.2.9 2013/07/14 20:39:13 riz Exp $");
 
 #include <sys/param.h>
 #include <sys/systm.h>
@@ -533,10 +533,8 @@ static void	wm_gmii_reset(struct wm_soft
 
 static int	wm_gmii_i82543_readreg(device_t, int, int);
 static void	wm_gmii_i82543_writereg(device_t, int, int, int);
-
 static int	wm_gmii_i82544_readreg(device_t, int, int);
 static void	wm_gmii_i82544_writereg(device_t, int, int, int);
-
 static int	wm_gmii_i80003_readreg(device_t, int, int);
 static void	wm_gmii_i80003_writereg(device_t, int, int, int);
 static int	wm_gmii_bm_readreg(device_t, int, int);
@@ -1024,6 +1022,41 @@ static const struct wm_product {
 	  "I350 Gigabit Connection",
 	  WM_T_I350,		WMP_F_1000T },
 #endif
+	{ PCI_VENDOR_INTEL,	PCI_PRODUCT_INTEL_I210_T1,
+	  "I210-T1 Ethernet Server Adapter",
+	  WM_T_I210,		WMP_F_1000T },
+	{ PCI_VENDOR_INTEL,	PCI_PRODUCT_INTEL_I210_COPPER_OEM1,
+	  "I210 Ethernet (Copper OEM)",
+	  WM_T_I210,		WMP_F_1000T },
+	{ PCI_VENDOR_INTEL,	PCI_PRODUCT_INTEL_I210_COPPER_IT,
+	  "I210 Ethernet (Copper IT)",
+	  WM_T_I210,		WMP_F_1000T },
+	{ PCI_VENDOR_INTEL,	PCI_PRODUCT_INTEL_I210_FIBER,
+	  "I210 Gigabit Ethernet (Fiber)",
+	  WM_T_I210,		WMP_F_1000X },
+#if 0
+	{ PCI_VENDOR_INTEL,	PCI_PRODUCT_INTEL_I210_SERDES,
+	  "I210 Gigabit Ethernet (SERDES)",
+	  WM_T_I210,		WMP_F_SERDES },
+	{ PCI_VENDOR_INTEL,	PCI_PRODUCT_INTEL_I210_SGMII,
+	  "I210 Gigabit Ethernet (SGMII)",
+	  WM_T_I210,		WMP_F_SERDES },
+#endif
+	{ PCI_VENDOR_INTEL,	PCI_PRODUCT_INTEL_I211_COPPER,
+	  "I211 Ethernet (COPPER)",
+	  WM_T_I211,		WMP_F_1000T },
+	{ PCI_VENDOR_INTEL,	PCI_PRODUCT_INTEL_I217_V,
+	  "I217 V Ethernet Connection",
+	  WM_T_PCH_LPT,		WMP_F_1000T },
+	{ PCI_VENDOR_INTEL,	PCI_PRODUCT_INTEL_I217_LM,
+	  "I217 LM Ethernet Connection",
+	  WM_T_PCH_LPT,		WMP_F_1000T },
+	{ PCI_VENDOR_INTEL,	PCI_PRODUCT_INTEL_I218_V,
+	  "I218 V Ethernet Connection",
+	  WM_T_PCH_LPT,		WMP_F_1000T },
+	{ PCI_VENDOR_INTEL,	PCI_PRODUCT_INTEL_I218_LM,
+	  "I218 LM Ethernet Connection",
+	  WM_T_PCH_LPT,		WMP_F_1000T },
 	{ 0,			0,
 	  NULL,
 	  0,			0 },
@@ -1175,7 +1208,8 @@ wm_attach(device_t parent, device_t self
 
 	if ((sc->sc_type == WM_T_82575) || (sc->sc_type == WM_T_82576)
 	    || (sc->sc_type == WM_T_82580) || (sc->sc_type == WM_T_82580ER)
-	    || (sc->sc_type == WM_T_I350))
+	    || (sc->sc_type == WM_T_I350) || (sc->sc_type == WM_T_I210)
+	    || (sc->sc_type == WM_T_I211))
 		sc->sc_flags |= WM_F_NEWQUEUE;
 
 	/* Set device properties (mactype) */
@@ -1325,7 +1359,8 @@ wm_attach(device_t parent, device_t self
 		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_PCH2)
+		    && (sc->sc_type != WM_T_PCH_LPT)) {
 			sc->sc_flags |= WM_F_EEPROM_SEMAPHORE;
 			/* ICH* and PCH* have no PCIe capability registers */
 			if (pci_get_capability(pa->pa_pc, pa->pa_tag,
@@ -1494,7 +1529,8 @@ wm_attach(device_t parent, device_t self
 	CSR_READ(sc, WMREG_RXERRC);
 
 	/* get PHY control from SMBus to PCIe */
-	if ((sc->sc_type == WM_T_PCH) || (sc->sc_type == WM_T_PCH2))
+	if ((sc->sc_type == WM_T_PCH) || (sc->sc_type == WM_T_PCH2)
+	    || (sc->sc_type == WM_T_PCH_LPT))
 		wm_smbustopci(sc);
 
 	/*
@@ -1514,6 +1550,7 @@ wm_attach(device_t parent, device_t self
 	case WM_T_ICH10:
 	case WM_T_PCH:
 	case WM_T_PCH2:
+	case WM_T_PCH_LPT:
 		if (wm_check_mng_mode(sc) != 0)
 			wm_get_hw_control(sc);
 		break;
@@ -1590,6 +1627,7 @@ wm_attach(device_t parent, device_t self
 	case WM_T_ICH10:
 	case WM_T_PCH:
 	case WM_T_PCH2:
+	case WM_T_PCH_LPT:
 		/* FLASH */
 		sc->sc_flags |= WM_F_EEPROM_FLASH | WM_F_SWFWHW_SYNC;
 		memtype = pci_mapreg_type(pa->pa_pc, pa->pa_tag, WM_ICH8_FLASH);
@@ -1609,6 +1647,11 @@ wm_attach(device_t parent, device_t self
 		sc->sc_ich8_flash_bank_size *= ICH_FLASH_SECTOR_SIZE;
 		sc->sc_ich8_flash_bank_size /= 2 * sizeof(uint16_t);
 		break;
+	case WM_T_I210:
+	case WM_T_I211:
+		sc->sc_flags |= WM_F_EEPROM_FLASH_HW;
+		sc->sc_flags |= WM_F_EEPROM_EERDEEWR | WM_F_SWFW_SYNC;
+		break;
 	default:
 		break;
 	}
@@ -1636,7 +1679,9 @@ wm_attach(device_t parent, device_t self
 
 	if (sc->sc_flags & WM_F_EEPROM_INVALID)
 		aprint_verbose_dev(sc->sc_dev, "No EEPROM\n");
-	else if (sc->sc_flags & WM_F_EEPROM_FLASH) {
+	else if (sc->sc_flags & WM_F_EEPROM_FLASH_HW) {
+		aprint_verbose_dev(sc->sc_dev, "FLASH(HW)\n");
+	} else if (sc->sc_flags & WM_F_EEPROM_FLASH) {
 		aprint_verbose_dev(sc->sc_dev, "FLASH\n");
 	} else {
 		if (sc->sc_flags & WM_F_EEPROM_SPI)
@@ -1731,6 +1776,7 @@ wm_attach(device_t parent, device_t self
 	case WM_T_ICH10:
 	case WM_T_PCH:
 	case WM_T_PCH2:
+	case WM_T_PCH_LPT:
 		/* XXX The funcid should be checked on some devices */
 		apme_mask = WUC_APME;
 		eeprom_data = CSR_READ(sc, WMREG_WUC);
@@ -1833,7 +1879,8 @@ wm_attach(device_t parent, device_t self
 	 */
 	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_82573
+	    || sc->sc_type == WM_T_PCH2 || sc->sc_type == WM_T_PCH_LPT
+	    || 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);
@@ -1850,6 +1897,8 @@ wm_attach(device_t parent, device_t self
 		case WM_T_82580:
 		case WM_T_82580ER:
 		case WM_T_I350:
+		case WM_T_I210:
+		case WM_T_I211:
 			reg = CSR_READ(sc, WMREG_CTRL_EXT);
 			switch (reg & CTRL_EXT_LINK_MODE_MASK) {
 			case CTRL_EXT_LINK_MODE_SGMII:
@@ -1914,10 +1963,13 @@ wm_attach(device_t parent, device_t self
 	case WM_T_82580:
 	case WM_T_82580ER:
 	case WM_T_I350:
+	case WM_T_I210:
+	case WM_T_I211:
 	case WM_T_80003:
 	case WM_T_ICH9:
 	case WM_T_ICH10:
 	case WM_T_PCH2:	/* PCH2 supports 9K frame size */
+	case WM_T_PCH_LPT:
 		/* XXX limited to 9234 */
 		sc->sc_ethercom.ec_capabilities |= ETHERCAP_JUMBO_MTU;
 		break;
@@ -2109,7 +2161,7 @@ wm_detach(device_t self, int flags __unu
 	if_detach(ifp);
 
 
-	/* Unload RX dmamaps and free mbufs */ 
+	/* Unload RX dmamaps and free mbufs */
 	wm_rxdrain(sc);
 
 	/* Free dmamap. It's the same as the end of the wm_attach() function */
@@ -2958,9 +3010,9 @@ wm_nq_tx_offload(struct wm_softc *sc, st
 	sc->sc_nq_txdescs[sc->sc_txnext].nqrx_ctx.nqtxc_vl_len =
 	    htole32(vl_len);
 	sc->sc_nq_txdescs[sc->sc_txnext].nqrx_ctx.nqtxc_sn = 0;
-	sc->sc_nq_txdescs[sc->sc_txnext].nqrx_ctx.nqtxc_cmd = 
+	sc->sc_nq_txdescs[sc->sc_txnext].nqrx_ctx.nqtxc_cmd =
 	    htole32(cmdc);
-	sc->sc_nq_txdescs[sc->sc_txnext].nqrx_ctx.nqtxc_mssidx = 
+	sc->sc_nq_txdescs[sc->sc_txnext].nqrx_ctx.nqtxc_mssidx =
 	    htole32(mssidx);
 	WM_CDTXSYNC(sc, sc->sc_txnext, 1, BUS_DMASYNC_PREWRITE);
 	DPRINTF(WM_DEBUG_TX,
@@ -3161,7 +3213,7 @@ wm_nq_start(struct ifnet *ifp)
 			    htole32(fields);
 			DPRINTF(WM_DEBUG_TX,
 			    ("%s: TX: adv data desc %d 0x%" PRIx64 "\n",
-			    device_xname(sc->sc_dev), nexttx, 
+			    device_xname(sc->sc_dev), nexttx,
 			    (uint64_t)dmamap->dm_segs[0].ds_addr));
 			DPRINTF(WM_DEBUG_TX,
 			    ("\t 0x%08x%08x\n", fields,
@@ -3646,7 +3698,7 @@ wm_rxintr(struct wm_softc *sc)
 
 		/*
 		 * Okay, we have the entire packet now.  The chip is
-		 * configured to include the FCS except I350
+		 * configured to include the FCS except I350 and I21[01]
 		 * (not all chips can be configured to strip it),
 		 * so we need to trim it.
 		 * May need to adjust length of previous mbuf in the
@@ -3654,7 +3706,8 @@ wm_rxintr(struct wm_softc *sc)
 		 * For an eratta, the RCTL_SECRC bit in RCTL register
 		 * is always set in I350, so we don't trim it.
 		 */
-		if (sc->sc_type != WM_T_I350) {
+		if ((sc->sc_type != WM_T_I350) && (sc->sc_type != WM_T_I210)
+		    && (sc->sc_type != WM_T_I211)) {
 			if (m->m_len < ETHER_CRC_LEN) {
 				sc->sc_rxtail->m_len
 				    -= (ETHER_CRC_LEN - m->m_len);
@@ -3767,9 +3820,9 @@ wm_linkintr_gmii(struct wm_softc *sc, ui
 
 	if (icr & ICR_LSC) {
 		DPRINTF(WM_DEBUG_LINK,
-		    ("%s: LINK: LSC -> mii_tick\n",
+		    ("%s: LINK: LSC -> mii_pollstat\n",
 			device_xname(sc->sc_dev)));
-		mii_tick(&sc->sc_mii);
+		mii_pollstat(&sc->sc_mii);
 		if (sc->sc_type == WM_T_82543) {
 			int miistatus, active;
 
@@ -3994,6 +4047,10 @@ wm_reset(struct wm_softc *sc)
 	case WM_T_82580ER:
 		sc->sc_pba = PBA_35K;
 		break;
+	case WM_T_I210:
+	case WM_T_I211:
+		sc->sc_pba = PBA_34K;
+		break;
 	case WM_T_82576:
 		sc->sc_pba = PBA_64K;
 		break;
@@ -4014,6 +4071,7 @@ wm_reset(struct wm_softc *sc)
 		break;
 	case WM_T_PCH:
 	case WM_T_PCH2:
+	case WM_T_PCH_LPT:
 		sc->sc_pba = PBA_26K;
 		break;
 	default:
@@ -4031,7 +4089,8 @@ wm_reset(struct wm_softc *sc)
 		CSR_WRITE(sc, WMREG_CTRL, sc->sc_ctrl);
 
 		while (timeout--) {
-			if ((CSR_READ(sc, WMREG_STATUS) & STATUS_GIO_M_ENA) == 0)
+			if ((CSR_READ(sc, WMREG_STATUS) & STATUS_GIO_M_ENA)
+			    == 0)
 				break;
 			delay(100);
 		}
@@ -4127,6 +4186,7 @@ wm_reset(struct wm_softc *sc)
 	case WM_T_ICH10:
 	case WM_T_PCH:
 	case WM_T_PCH2:
+	case WM_T_PCH_LPT:
 		reg = CSR_READ(sc, WMREG_CTRL) | CTRL_RST;
 		if (wm_check_reset_block(sc) == 0) {
 			/*
@@ -4163,6 +4223,8 @@ wm_reset(struct wm_softc *sc)
 	case WM_T_82580ER:
 	case WM_T_82583:
 	case WM_T_I350:
+	case WM_T_I210:
+	case WM_T_I211:
 	default:
 		/* Everything else can safely use the documented method. */
 		CSR_WRITE(sc, WMREG_CTRL, CSR_READ(sc, WMREG_CTRL) | CTRL_RST);
@@ -4223,16 +4285,18 @@ wm_reset(struct wm_softc *sc)
 	case WM_T_82580:
 	case WM_T_82580ER:
 	case WM_T_I350:
+	case WM_T_I210:
+	case WM_T_I211:
 	case WM_T_80003:
-	case WM_T_ICH8:
-	case WM_T_ICH9:
 		/* check EECD_EE_AUTORD */
 		wm_get_auto_rd_done(sc);
 		break;
+	case WM_T_ICH8:
+	case WM_T_ICH9:
 	case WM_T_ICH10:
 	case WM_T_PCH:
 	case WM_T_PCH2:
-		wm_lan_init_done(sc);
+	case WM_T_PCH_LPT:
 		break;
 	default:
 		panic("%s: unknown type\n", __func__);
@@ -4365,6 +4429,7 @@ wm_init(struct ifnet *ifp)
 	case WM_T_ICH10:
 	case WM_T_PCH:
 	case WM_T_PCH2:
+	case WM_T_PCH_LPT:
 		if (wm_check_mng_mode(sc) != 0)
 			wm_get_hw_control(sc);
 		break;
@@ -4378,7 +4443,8 @@ wm_init(struct ifnet *ifp)
 
 	reg = CSR_READ(sc, WMREG_CTRL_EXT);
 	/* Enable PHY low-power state when MAC is at D3 w/o WoL */
-	if ((sc->sc_type == WM_T_PCH) || (sc->sc_type == WM_T_PCH2))
+	if ((sc->sc_type == WM_T_PCH) || (sc->sc_type == WM_T_PCH2)
+	    || (sc->sc_type == WM_T_PCH_LPT))
 		CSR_WRITE(sc, WMREG_CTRL_EXT, reg | CTRL_EXT_PHYPDEN);
 
 	/* Initialize the transmit descriptor ring. */
@@ -4463,16 +4529,16 @@ wm_init(struct ifnet *ifp)
 		} else {
 			CSR_WRITE(sc, WMREG_RDH, 0);
 			CSR_WRITE(sc, WMREG_RDT, 0);
-			CSR_WRITE(sc, WMREG_RDTR, 375 | RDTR_FPD);	/* ITR/4 */
-			CSR_WRITE(sc, WMREG_RADV, 375);		/* MUST be same */
+			CSR_WRITE(sc, WMREG_RDTR, 375 | RDTR_FPD); /* ITR/4 */
+			CSR_WRITE(sc, WMREG_RADV, 375);	/* MUST be same */
 		}
 	}
 	for (i = 0; i < WM_NRXDESC; i++) {
 		rxs = &sc->sc_rxsoft[i];
 		if (rxs->rxs_mbuf == NULL) {
 			if ((error = wm_add_rxbuf(sc, i)) != 0) {
-				log(LOG_ERR, "%s: unable to allocate or map rx "
-				    "buffer %d, error = %d\n",
+				log(LOG_ERR, "%s: unable to allocate or map "
+				    "rx buffer %d, error = %d\n",
 				    device_xname(sc->sc_dev), i, error);
 				/*
 				 * XXX Should attempt to run with fewer receive
@@ -4514,7 +4580,7 @@ wm_init(struct ifnet *ifp)
 	 */
 	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_PCH2) && (sc->sc_type != WM_T_PCH_LPT)) {
 		CSR_WRITE(sc, WMREG_FCAL, FCAL_CONST);
 		CSR_WRITE(sc, WMREG_FCAH, FCAH_CONST);
 		CSR_WRITE(sc, WMREG_FCT, ETHERTYPE_FLOWCONTROL);
@@ -4547,6 +4613,7 @@ wm_init(struct ifnet *ifp)
 		case WM_T_ICH10:
 		case WM_T_PCH:
 		case WM_T_PCH2:
+		case WM_T_PCH_LPT:
 			/*
 			 * Set the mac to wait the maximum time between each
 			 * iteration and increase the max iterations when
@@ -4611,7 +4678,7 @@ wm_init(struct ifnet *ifp)
 
 	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_PCH2) || (sc->sc_type == WM_T_PCH_LPT)) {
 		reg = CSR_READ(sc, WMREG_KABGTXD);
 		reg |= KABGTXD_BGSQLBIAS;
 		CSR_WRITE(sc, WMREG_KABGTXD, reg);
@@ -4697,7 +4764,7 @@ wm_init(struct ifnet *ifp)
 	 * The I350 has a bug where it always strips the CRC whether
 	 * asked to or not. So ask for stripped CRC here and cope in rxeof
 	 */
-	if (sc->sc_type == WM_T_I350)
+	if ((sc->sc_type == WM_T_I350) || (sc->sc_type == WM_T_I210))
 		sc->sc_rctl |= RCTL_SECRC;
 
 	if (((sc->sc_ethercom.ec_capabilities & ETHERCAP_JUMBO_MTU) != 0)
@@ -4732,6 +4799,26 @@ wm_init(struct ifnet *ifp)
 	/* Set the receive filter. */
 	wm_set_filter(sc);
 
+	/* Enable ECC */
+	switch (sc->sc_type) {
+	case WM_T_82571:
+		reg = CSR_READ(sc, WMREG_PBA_ECC);
+		reg |= PBA_ECC_CORR_EN;
+		CSR_WRITE(sc, WMREG_PBA_ECC, reg);
+		break;
+	case WM_T_PCH_LPT:
+		reg = CSR_READ(sc, WMREG_PBECCSTS);
+		reg |= PBECCSTS_UNCORR_ECC_ENABLE;
+		CSR_WRITE(sc, WMREG_PBECCSTS, reg);
+
+		reg = CSR_READ(sc, WMREG_CTRL);
+		reg |= CTRL_MEHE;
+		CSR_WRITE(sc, WMREG_CTRL, reg);
+		break;
+	default:
+		break;
+	}
+
 	/* On 575 and later set RDT only if RX enabled */
 	if ((sc->sc_flags & WM_F_NEWQUEUE) != 0)
 		for (i = 0; i < WM_NRXDESC; i++)
@@ -4856,6 +4943,8 @@ wm_get_auto_rd_done(struct wm_softc *sc)
 	case WM_T_82580:
 	case WM_T_82580ER:
 	case WM_T_I350:
+	case WM_T_I210:
+	case WM_T_I211:
 	case WM_T_80003:
 	case WM_T_ICH8:
 	case WM_T_ICH9:
@@ -4885,6 +4974,7 @@ wm_lan_init_done(struct wm_softc *sc)
 	case WM_T_ICH10:
 	case WM_T_PCH:
 	case WM_T_PCH2:
+	case WM_T_PCH_LPT:
 		for (i = 0; i < WM_ICH8_LAN_INIT_TIMEOUT; i++) {
 			reg = CSR_READ(sc, WMREG_STATUS);
 			if ((reg & STATUS_LAN_INIT_DONE) != 0)
@@ -4944,6 +5034,8 @@ wm_get_cfg_done(struct wm_softc *sc)
 	case WM_T_82580:
 	case WM_T_82580ER:
 	case WM_T_I350:
+	case WM_T_I210:
+	case WM_T_I211:
 		if (sc->sc_type == WM_T_82571) {
 			/* Only 82571 shares port 0 */
 			mask = EEMNGCTL_CFGDONE_0;
@@ -4964,13 +5056,16 @@ wm_get_cfg_done(struct wm_softc *sc)
 	case WM_T_ICH10:
 	case WM_T_PCH:
 	case WM_T_PCH2:
-		if (sc->sc_type >= WM_T_PCH) {
-			reg = CSR_READ(sc, WMREG_STATUS);
-			if ((reg & STATUS_PHYRA) != 0)
-				CSR_WRITE(sc, WMREG_STATUS,
-				    reg & ~STATUS_PHYRA);
-		}
+	case WM_T_PCH_LPT:
 		delay(10*1000);
+		if (sc->sc_type >= WM_T_ICH10)
+			wm_lan_init_done(sc);
+		else
+			wm_get_auto_rd_done(sc);
+
+		reg = CSR_READ(sc, WMREG_STATUS);
+		if ((reg & STATUS_PHYRA) != 0)
+			CSR_WRITE(sc, WMREG_STATUS, reg & ~STATUS_PHYRA);
 		break;
 	default:
 		panic("%s: %s: unknown type\n", device_xname(sc->sc_dev),
@@ -5153,7 +5248,7 @@ wm_read_eeprom_uwire(struct wm_softc *sc
 			delay(2);
 		}
 		/* XXX: end of workaround */
-		
+	
 		/* Set CHIP SELECT. */
 		reg |= EECD_CS;
 		CSR_WRITE(sc, WMREG_EECD, reg);
@@ -5248,8 +5343,12 @@ wm_read_eeprom_spi(struct wm_softc *sc, 
 	return 0;
 }
 
-#define EEPROM_CHECKSUM		0xBABA
-#define EEPROM_SIZE		0x0040
+#define NVM_CHECKSUM			0xBABA
+#define EEPROM_SIZE			0x0040
+#define NVM_COMPAT			0x0003
+#define NVM_COMPAT_VALID_CHECKSUM	0x0001
+#define NVM_FUTURE_INIT_WORD1			0x0019
+#define NVM_FUTURE_INIT_WORD1_VALID_CHECKSUM	0x0040
 
 /*
  * wm_validate_eeprom_checksum
@@ -5259,21 +5358,36 @@ wm_read_eeprom_spi(struct wm_softc *sc, 
 static int
 wm_validate_eeprom_checksum(struct wm_softc *sc)
 {
-	uint16_t checksum;
+	uint16_t checksum, valid_checksum;
 	uint16_t eeprom_data;
+	uint16_t csum_wordaddr;
 	int i;
 
 	checksum = 0;
 
+	/* Don't check for I211 */
+	if (sc->sc_type == WM_T_I211)
+		return 0;
+
+	if (sc->sc_type == WM_T_PCH_LPT) {
+		csum_wordaddr = NVM_COMPAT;
+		valid_checksum = NVM_COMPAT_VALID_CHECKSUM;
+	} else {
+		csum_wordaddr = NVM_FUTURE_INIT_WORD1;
+		valid_checksum = NVM_FUTURE_INIT_WORD1_VALID_CHECKSUM;
+	}
+
 #ifdef WM_DEBUG
 	/* Dump EEPROM image for debug */
 	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)) {
-		wm_read_eeprom(sc, 0x19, 1, &eeprom_data);
-		if ((eeprom_data & 0x40) == 0) {
-			DPRINTF(WM_DEBUG_NVM,("%s: NVM need to be updated\n",
-				device_xname(sc->sc_dev)));
+	    || (sc->sc_type == WM_T_PCH2) || (sc->sc_type == WM_T_PCH_LPT)) {
+		wm_read_eeprom(sc, csum_wordaddr, 1, &eeprom_data);
+		if ((eeprom_data & valid_checksum) == 0) {
+			DPRINTF(WM_DEBUG_NVM,
+			    ("%s: NVM need to be updated (%04x != %04x)\n",
+				device_xname(sc->sc_dev), eeprom_data,
+				    valid_checksum));
 		}
 	}
 
@@ -5297,8 +5411,12 @@ wm_validate_eeprom_checksum(struct wm_so
 		checksum += eeprom_data;
 	}
 
-	if (checksum != (uint16_t) EEPROM_CHECKSUM)
-		return 1;
+	if (checksum != (uint16_t) NVM_CHECKSUM) {
+#ifdef WM_DEBUG
+		printf("%s: NVM checksum mismatch (%04x != %04x)\n",
+		    device_xname(sc->sc_dev), checksum, NVM_CHECKSUM);
+#endif
+	}
 
 	return 0;
 }
@@ -5321,7 +5439,7 @@ wm_read_eeprom(struct wm_softc *sc, int 
 
 	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_PCH2) || (sc->sc_type == WM_T_PCH_LPT))
 		rv = wm_read_eeprom_ich8(sc, word, wordcnt, data);
 	else if (sc->sc_flags & WM_F_EEPROM_EERDEEWR)
 		rv = wm_read_eeprom_eerd(sc, word, wordcnt, data);
@@ -5438,6 +5556,8 @@ wm_read_mac_addr(struct wm_softc *sc, ui
 	case WM_T_82575:
 	case WM_T_82576:
 	case WM_T_80003:
+	case WM_T_I210:
+	case WM_T_I211:
 		if (wm_check_alt_mac_addr(sc) != 0) {
 			/* reset the offset to LAN0 */
 			offset = EEPROM_OFF_MACADDR;
@@ -5545,7 +5665,7 @@ wm_add_rxbuf(struct wm_softc *sc, int id
 	if ((sc->sc_flags & WM_F_NEWQUEUE) != 0) {
 		if ((sc->sc_rctl & RCTL_EN) != 0)
 			WM_INIT_RXDESC(sc, idx);
-	} else 
+	} else
 		WM_INIT_RXDESC(sc, idx);
 
 	return 0;
@@ -5599,7 +5719,7 @@ wm_mchash(struct wm_softc *sc, const uin
 
 	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_PCH2) || (sc->sc_type == WM_T_PCH_LPT)) {
 		hash = (enaddr[4] >> ich8_lo_shift[sc->sc_mchash_type]) |
 		    (((uint16_t) enaddr[5]) << ich8_hi_shift[sc->sc_mchash_type]);
 		return (hash & 0x3ff);
@@ -5647,7 +5767,8 @@ wm_set_filter(struct wm_softc *sc)
 	if (sc->sc_type == WM_T_ICH8)
 		size = WM_RAL_TABSIZE_ICH8 -1;
 	else if ((sc->sc_type == WM_T_ICH9) || (sc->sc_type == WM_T_ICH10)
-	    || (sc->sc_type == WM_T_PCH) || (sc->sc_type == WM_T_PCH2))
+	    || (sc->sc_type == WM_T_PCH) || (sc->sc_type == WM_T_PCH2)
+	    || (sc->sc_type == WM_T_PCH_LPT))
 		size = WM_RAL_TABSIZE_ICH8;
 	else if (sc->sc_type == WM_T_82575)
 		size = WM_RAL_TABSIZE_82575;
@@ -5663,7 +5784,7 @@ wm_set_filter(struct wm_softc *sc)
 
 	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_PCH2) || (sc->sc_type == WM_T_PCH_LPT))
 		size = WM_ICH8_MC_TABSIZE;
 	else
 		size = WM_MC_TABSIZE;
@@ -5690,7 +5811,8 @@ wm_set_filter(struct wm_softc *sc)
 		reg = (hash >> 5);
 		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_PCH2)
+		    || (sc->sc_type == WM_T_PCH_LPT))
 			reg &= 0x1f;
 		else
 			reg &= 0x7f;
@@ -6033,6 +6155,8 @@ wm_gmii_reset(struct wm_softc *sc)
 	case WM_T_82580:
 	case WM_T_82580ER:
 	case WM_T_I350:
+	case WM_T_I210:
+	case WM_T_I211:
 	case WM_T_80003:
 		rv = wm_get_swfw_semaphore(sc, swfwphysem[sc->sc_funcid]);
 		break;
@@ -6041,6 +6165,7 @@ wm_gmii_reset(struct wm_softc *sc)
 	case WM_T_ICH10:
 	case WM_T_PCH:
 	case WM_T_PCH2:
+	case WM_T_PCH_LPT:
 		rv = wm_get_swfwhw_semaphore(sc);
 		break;
 	default:
@@ -6104,6 +6229,8 @@ wm_gmii_reset(struct wm_softc *sc)
 	case WM_T_82580:
 	case WM_T_82580ER:
 	case WM_T_I350:
+	case WM_T_I210:
+	case WM_T_I211:
 	case WM_T_82583:
 	case WM_T_80003:
 		/* generic reset */
@@ -6125,6 +6252,7 @@ wm_gmii_reset(struct wm_softc *sc)
 	case WM_T_ICH10:
 	case WM_T_PCH:
 	case WM_T_PCH2:
+	case WM_T_PCH_LPT:
 		/* generic reset */
 		CSR_WRITE(sc, WMREG_CTRL, sc->sc_ctrl | CTRL_PHY_RESET);
 		delay(100);
@@ -6152,6 +6280,8 @@ wm_gmii_reset(struct wm_softc *sc)
 	case WM_T_82580:
 	case WM_T_82580ER:
 	case WM_T_I350:
+	case WM_T_I210:
+	case WM_T_I211:
 	case WM_T_80003:
 		wm_put_swfw_semaphore(sc, swfwphysem[sc->sc_funcid]);
 		break;
@@ -6160,6 +6290,7 @@ wm_gmii_reset(struct wm_softc *sc)
 	case WM_T_ICH10:
 	case WM_T_PCH:
 	case WM_T_PCH2:
+	case WM_T_PCH_LPT:
 		wm_put_swfwhw_semaphore(sc);
 		break;
 	default:
@@ -6193,6 +6324,8 @@ wm_gmii_reset(struct wm_softc *sc)
 	case WM_T_82580:
 	case WM_T_82580ER:
 	case WM_T_I350:
+	case WM_T_I210:
+	case WM_T_I211:
 	case WM_T_82583:
 	case WM_T_80003:
 		/* null */
@@ -6206,6 +6339,7 @@ wm_gmii_reset(struct wm_softc *sc)
 	case WM_T_ICH10:
 	case WM_T_PCH:
 	case WM_T_PCH2:
+	case WM_T_PCH_LPT:
 		/* Allow time for h/w to get to a quiescent state afer reset */
 		delay(10*1000);
 
@@ -6229,7 +6363,8 @@ wm_gmii_reset(struct wm_softc *sc)
 		 */
 
 		/* Configure the LCD with the OEM bits in NVM */
-		if ((sc->sc_type == WM_T_PCH) || (sc->sc_type == WM_T_PCH2)) {
+		if ((sc->sc_type == WM_T_PCH) || (sc->sc_type == WM_T_PCH2)
+		    || (sc->sc_type == WM_T_PCH_LPT)) {
 			/*
 			 * Disable LPLU.
 			 * XXX It seems that 82567 has LPLU, too.
@@ -6255,6 +6390,7 @@ static void
 wm_gmii_mediainit(struct wm_softc *sc, pci_product_id_t prodid)
 {
 	struct ifnet *ifp = &sc->sc_ethercom.ec_if;
+	struct mii_data *mii = &sc->sc_mii;
 
 	/* We have MII. */
 	sc->sc_flags |= WM_F_HAS_MII;
@@ -6274,29 +6410,50 @@ wm_gmii_mediainit(struct wm_softc *sc, p
 	CSR_WRITE(sc, WMREG_CTRL, sc->sc_ctrl);
 
 	/* Initialize our media structures and probe the GMII. */
-	sc->sc_mii.mii_ifp = ifp;
+	mii->mii_ifp = ifp;
 
+	/*
+	 * Determine the PHY access method.
+	 *
+	 *  For SGMII, use SGMII specific method.
+	 *
+	 *  For some devices, we can determine the PHY access method
+	 * from sc_type.
+	 *
+	 *  For ICH8 variants, it's difficult to detemine the PHY access
+	 * method by sc_type, so use the PCI product ID for some devices.
+	 * For other ICH8 variants, try to use igp's method. If the PHY
+	 * can't detect, then use bm's method.
+	 */
 	switch (prodid) {
 	case PCI_PRODUCT_INTEL_PCH_M_LM:
 	case PCI_PRODUCT_INTEL_PCH_M_LC:
 		/* 82577 */
 		sc->sc_phytype = WMPHY_82577;
-		sc->sc_mii.mii_readreg = wm_gmii_hv_readreg;
-		sc->sc_mii.mii_writereg = wm_gmii_hv_writereg;
+		mii->mii_readreg = wm_gmii_hv_readreg;
+		mii->mii_writereg = wm_gmii_hv_writereg;
 		break;
 	case PCI_PRODUCT_INTEL_PCH_D_DM:
 	case PCI_PRODUCT_INTEL_PCH_D_DC:
 		/* 82578 */
 		sc->sc_phytype = WMPHY_82578;
-		sc->sc_mii.mii_readreg = wm_gmii_hv_readreg;
-		sc->sc_mii.mii_writereg = wm_gmii_hv_writereg;
+		mii->mii_readreg = wm_gmii_hv_readreg;
+		mii->mii_writereg = wm_gmii_hv_writereg;
 		break;
 	case PCI_PRODUCT_INTEL_PCH2_LV_LM:
 	case PCI_PRODUCT_INTEL_PCH2_LV_V:
-		/* 82578 */
+		/* 82579 */
 		sc->sc_phytype = WMPHY_82579;
-		sc->sc_mii.mii_readreg = wm_gmii_hv_readreg;
-		sc->sc_mii.mii_writereg = wm_gmii_hv_writereg;
+		mii->mii_readreg = wm_gmii_hv_readreg;
+		mii->mii_writereg = wm_gmii_hv_writereg;
+		break;
+	case PCI_PRODUCT_INTEL_I217_LM:
+	case PCI_PRODUCT_INTEL_I217_V:
+	case PCI_PRODUCT_INTEL_I218_LM:
+	case PCI_PRODUCT_INTEL_I218_V:
+		/* I21[78] */
+		mii->mii_readreg = wm_gmii_hv_readreg;
+		mii->mii_writereg = wm_gmii_hv_writereg;
 		break;
 	case PCI_PRODUCT_INTEL_82801I_BM:
 	case PCI_PRODUCT_INTEL_82801J_R_BM_LM:
@@ -6306,40 +6463,44 @@ wm_gmii_mediainit(struct wm_softc *sc, p
 	case PCI_PRODUCT_INTEL_82801J_R_BM_V:
 		/* 82567 */
 		sc->sc_phytype = WMPHY_BM;
-		sc->sc_mii.mii_readreg = wm_gmii_bm_readreg;
-		sc->sc_mii.mii_writereg = wm_gmii_bm_writereg;
+		mii->mii_readreg = wm_gmii_bm_readreg;
+		mii->mii_writereg = wm_gmii_bm_writereg;
 		break;
 	default:
 		if ((sc->sc_flags & WM_F_SGMII) != 0) {
-			sc->sc_mii.mii_readreg = wm_sgmii_readreg;
-			sc->sc_mii.mii_writereg = wm_sgmii_writereg;
+			mii->mii_readreg = wm_sgmii_readreg;
+			mii->mii_writereg = wm_sgmii_writereg;
 		} else if (sc->sc_type >= WM_T_80003) {
-			sc->sc_mii.mii_readreg = wm_gmii_i80003_readreg;
-			sc->sc_mii.mii_writereg = wm_gmii_i80003_writereg;
+			mii->mii_readreg = wm_gmii_i80003_readreg;
+			mii->mii_writereg = wm_gmii_i80003_writereg;
+		} else if (sc->sc_type >= WM_T_I210) {
+			mii->mii_readreg = wm_gmii_i82544_readreg;
+			mii->mii_writereg = wm_gmii_i82544_writereg;
 		} else if (sc->sc_type >= WM_T_82580) {
 			sc->sc_phytype = WMPHY_82580;
-			sc->sc_mii.mii_readreg = wm_gmii_82580_readreg;
-			sc->sc_mii.mii_writereg = wm_gmii_82580_writereg;
+			mii->mii_readreg = wm_gmii_82580_readreg;
+			mii->mii_writereg = wm_gmii_82580_writereg;
 		} else if (sc->sc_type >= WM_T_82544) {
-			sc->sc_mii.mii_readreg = wm_gmii_i82544_readreg;
-			sc->sc_mii.mii_writereg = wm_gmii_i82544_writereg;
+			mii->mii_readreg = wm_gmii_i82544_readreg;
+			mii->mii_writereg = wm_gmii_i82544_writereg;
 		} else {
-			sc->sc_mii.mii_readreg = wm_gmii_i82543_readreg;
-			sc->sc_mii.mii_writereg = wm_gmii_i82543_writereg;
+			mii->mii_readreg = wm_gmii_i82543_readreg;
+			mii->mii_writereg = wm_gmii_i82543_writereg;
 		}
 		break;
 	}
-	sc->sc_mii.mii_statchg = wm_gmii_statchg;
+	mii->mii_statchg = wm_gmii_statchg;
 
 	wm_gmii_reset(sc);
 
 	sc->sc_ethercom.ec_mii = &sc->sc_mii;
-	ifmedia_init(&sc->sc_mii.mii_media, IFM_IMASK, wm_gmii_mediachange,
+	ifmedia_init(&mii->mii_media, IFM_IMASK, wm_gmii_mediachange,
 	    wm_gmii_mediastatus);
 
 	if ((sc->sc_type == WM_T_82575) || (sc->sc_type == WM_T_82576)
 	    || (sc->sc_type == WM_T_82580) || (sc->sc_type == WM_T_82580ER)
-	    || (sc->sc_type == WM_T_I350)) {
+	    || (sc->sc_type == WM_T_I350) || (sc->sc_type == WM_T_I210)
+	    || (sc->sc_type == WM_T_I211)) {
 		if ((sc->sc_flags & WM_F_SGMII) == 0) {
 			/* Attach only one port */
 			mii_attach(sc->sc_dev, &sc->sc_mii, 0xffffffff, 1,
@@ -6368,31 +6529,44 @@ wm_gmii_mediainit(struct wm_softc *sc, p
 		    MII_OFFSET_ANY, MIIF_DOPAUSE);
 	}
 
-	if ((sc->sc_type == WM_T_PCH2) &&
-	    (LIST_FIRST(&sc->sc_mii.mii_phys) == NULL)) {
+	/*
+	 * If the MAC is PCH2 or PCH_LPT and failed to detect MII PHY, call
+	 * wm_set_mdio_slow_mode_hv() for a workaround and retry.
+	 */
+	if (((sc->sc_type == WM_T_PCH2) || (sc->sc_type == WM_T_PCH_LPT)) &&
+	    (LIST_FIRST(&mii->mii_phys) == NULL)) {
 		wm_set_mdio_slow_mode_hv(sc);
 		mii_attach(sc->sc_dev, &sc->sc_mii, 0xffffffff, MII_PHY_ANY,
 		    MII_OFFSET_ANY, MIIF_DOPAUSE);
 	}
-			
-	if (LIST_FIRST(&sc->sc_mii.mii_phys) == NULL) {
+
+	/*
+	 * (For ICH8 variants)
+	 * If PHY detection failed, use BM's r/w function and retry.
+	 */
+	if (LIST_FIRST(&mii->mii_phys) == NULL) {
 		/* if failed, retry with *_bm_* */
-		sc->sc_mii.mii_readreg = wm_gmii_bm_readreg;
-		sc->sc_mii.mii_writereg = wm_gmii_bm_writereg;
+		mii->mii_readreg = wm_gmii_bm_readreg;
+		mii->mii_writereg = wm_gmii_bm_writereg;
 
 		mii_attach(sc->sc_dev, &sc->sc_mii, 0xffffffff, MII_PHY_ANY,
 		    MII_OFFSET_ANY, MIIF_DOPAUSE);
 	}
-	if (LIST_FIRST(&sc->sc_mii.mii_phys) == NULL) {
-		ifmedia_add(&sc->sc_mii.mii_media, IFM_ETHER|IFM_NONE, 0, NULL);
-		ifmedia_set(&sc->sc_mii.mii_media, IFM_ETHER|IFM_NONE);
+
+	if (LIST_FIRST(&mii->mii_phys) == NULL) {
+		/* Any PHY wasn't find */
+		ifmedia_add(&mii->mii_media, IFM_ETHER|IFM_NONE, 0, NULL);
+		ifmedia_set(&mii->mii_media, IFM_ETHER|IFM_NONE);
 		sc->sc_phytype = WMPHY_NONE;
 	} else {
-		/* Check PHY type */
+		/*
+		 * PHY Found!
+		 * Check PHY type.
+		 */
 		uint32_t model;
 		struct mii_softc *child;
 
-		child = LIST_FIRST(&sc->sc_mii.mii_phys);
+		child = LIST_FIRST(&mii->mii_phys);
 		if (device_is_a(child->mii_dev, "igphy")) {
 			struct igphy_softc *isc = (struct igphy_softc *)child;
 
@@ -6401,7 +6575,7 @@ wm_gmii_mediainit(struct wm_softc *sc, p
 				sc->sc_phytype = WMPHY_IGP_3;
 		}
 
-		ifmedia_set(&sc->sc_mii.mii_media, IFM_ETHER | IFM_AUTO);
+		ifmedia_set(&mii->mii_media, IFM_ETHER | IFM_AUTO);
 	}
 }
 
@@ -6745,12 +6919,12 @@ wm_gmii_bm_readreg(device_t self, int ph
 
 	if (reg > BME1000_MAX_MULTI_PAGE_REG) {
 		if (phy == 1)
-			wm_gmii_i82544_writereg(self, phy, 0x1f,
+			wm_gmii_i82544_writereg(self, phy, MII_IGPHY_PAGE_SELECT,
 			    reg);
 		else
-			wm_gmii_i82544_writereg(self, phy, GG82563_PHY_PAGE_SELECT,
+			wm_gmii_i82544_writereg(self, phy,
+			    GG82563_PHY_PAGE_SELECT,
 			    reg >> GG82563_PAGE_SHIFT);
-
 	}
 
 	rv = wm_gmii_i82544_readreg(self, phy, reg & GG82563_MAX_REG_ADDRESS);
@@ -6780,12 +6954,12 @@ wm_gmii_bm_writereg(device_t self, int p
 
 	if (reg > BME1000_MAX_MULTI_PAGE_REG) {
 		if (phy == 1)
-			wm_gmii_i82544_writereg(self, phy, 0x1f,
+			wm_gmii_i82544_writereg(self, phy, MII_IGPHY_PAGE_SELECT,
 			    reg);
 		else
-			wm_gmii_i82544_writereg(self, phy, GG82563_PHY_PAGE_SELECT,
+			wm_gmii_i82544_writereg(self, phy,
+			    GG82563_PHY_PAGE_SELECT,
 			    reg >> GG82563_PAGE_SHIFT);
-
 	}
 
 	wm_gmii_i82544_writereg(self, phy, reg & GG82563_MAX_REG_ADDRESS, val);
@@ -6849,7 +7023,7 @@ wm_gmii_hv_readreg(device_t self, int ph
 	uint16_t val;
 	int rv;
 
-	if (wm_get_swfw_semaphore(sc, SWFW_PHY0_SM)) {
+	if (wm_get_swfwhw_semaphore(sc)) {
 		aprint_error_dev(sc->sc_dev, "%s: failed to get semaphore\n",
 		    __func__);
 		return 0;
@@ -6881,7 +7055,7 @@ wm_gmii_hv_readreg(device_t self, int ph
 	}
 
 	rv = wm_gmii_i82544_readreg(self, phy, regnum & IGPHY_MAXREGADDR);
-	wm_put_swfw_semaphore(sc, SWFW_PHY0_SM);
+	wm_put_swfwhw_semaphore(sc);
 	return rv;
 }
 
@@ -6899,7 +7073,7 @@ wm_gmii_hv_writereg(device_t self, int p
 	uint16_t page = BM_PHY_REG_PAGE(reg);
 	uint16_t regnum = BM_PHY_REG_NUM(reg);
 
-	if (wm_get_swfw_semaphore(sc, SWFW_PHY0_SM)) {
+	if (wm_get_swfwhw_semaphore(sc)) {
 		aprint_error_dev(sc->sc_dev, "%s: failed to get semaphore\n",
 		    __func__);
 		return;
@@ -6936,13 +7110,13 @@ wm_gmii_hv_writereg(device_t self, int p
 	}
 
 	wm_gmii_i82544_writereg(self, phy, regnum & IGPHY_MAXREGADDR, val);
-	wm_put_swfw_semaphore(sc, SWFW_PHY0_SM);
+	wm_put_swfwhw_semaphore(sc);
 }
 
 /*
- * wm_gmii_hv_readreg:	[mii interface function]
+ * wm_sgmii_readreg:	[mii interface function]
  *
- *	Read a PHY register on the kumeran
+ *	Read a PHY register on the SGMII
  * This could be handled by the PHY layer if we didn't have to lock the
  * ressource ...
  */
@@ -6983,9 +7157,9 @@ wm_sgmii_readreg(device_t self, int phy,
 }
 
 /*
- * wm_gmii_hv_writereg:	[mii interface function]
+ * wm_sgmii_writereg:	[mii interface function]
  *
- *	Write a PHY register on the kumeran.
+ *	Write a PHY register on the SGMII.
  * This could be handled by the PHY layer if we didn't have to lock the
  * ressource ...
  */
@@ -7352,31 +7526,42 @@ wm_put_swfwhw_semaphore(struct wm_softc 
 static int
 wm_valid_nvm_bank_detect_ich8lan(struct wm_softc *sc, unsigned int *bank)
 {
+	uint32_t eecd;
 	uint32_t act_offset = ICH_NVM_SIG_WORD * 2 + 1;
 	uint32_t bank1_offset = sc->sc_ich8_flash_bank_size * sizeof(uint16_t);
+	uint8_t sig_byte = 0;
 
-	if ((sc->sc_type != WM_T_ICH10) && (sc->sc_type != WM_T_PCH)) {
-		/* Value of bit 22 corresponds to the flash bank we're on. */
-		*bank = (CSR_READ(sc, WMREG_EECD) & EECD_SEC1VAL) ? 1 : 0;
-	} else {
-		uint8_t bank_high_byte;
-		wm_read_ich8_byte(sc, act_offset, &bank_high_byte);
-		if ((bank_high_byte & 0xc0) == 0x80)
+	switch (sc->sc_type) {
+	case WM_T_ICH8:
+	case WM_T_ICH9:
+		eecd = CSR_READ(sc, WMREG_EECD);
+		if ((eecd & EECD_SEC1VAL_VALMASK) == EECD_SEC1VAL_VALMASK) {
+			*bank = ((eecd & EECD_SEC1VAL) != 0) ? 1 : 0;
+			return 0;
+		}
+		/* FALLTHROUGH */
+	default:
+		/* Default to 0 */
+		*bank = 0;
+
+		/* Check bank 0 */
+		wm_read_ich8_byte(sc, act_offset, &sig_byte);
+		if ((sig_byte & ICH_NVM_VALID_SIG_MASK) == ICH_NVM_SIG_VALUE) {
 			*bank = 0;
-		else {
-			wm_read_ich8_byte(sc, act_offset + bank1_offset,
-			    &bank_high_byte);
-			if ((bank_high_byte & 0xc0) == 0x80)
-				*bank = 1;
-			else {
-				aprint_error_dev(sc->sc_dev,
-				    "EEPROM not present\n");
-				return -1;
-			}
+			return 0;
+		}
+
+		/* Check bank 1 */
+		wm_read_ich8_byte(sc, act_offset + bank1_offset,
+		    &sig_byte);
+		if ((sig_byte & ICH_NVM_VALID_SIG_MASK) == ICH_NVM_SIG_VALUE) {
+			*bank = 1;
+			return 0;
 		}
 	}
 
-	return 0;
+	aprint_error_dev(sc->sc_dev, "EEPROM not present\n");
+	return -1;
 }
 
 /******************************************************************************
@@ -7410,7 +7595,10 @@ wm_read_eeprom_ich8(struct wm_softc *sc,
 		return error;
 	}
 
-	/* Adjust offset appropriately if we're on bank 1 - adjust for word size */
+	/*
+	 * Adjust offset appropriately if we're on bank 1 - adjust for word
+	 * size
+	 */
 	bank_offset = flash_bank * (sc->sc_ich8_flash_bank_size * 2);
 
 	error = wm_get_swfwhw_semaphore(sc);
@@ -7425,8 +7613,8 @@ wm_read_eeprom_ich8(struct wm_softc *sc,
 		act_offset = bank_offset + ((offset + i) * 2);
 		error = wm_read_ich8_word(sc, act_offset, &word);
 		if (error) {
-			aprint_error_dev(sc->sc_dev, "%s: failed to read NVM\n",
-			    __func__);
+			aprint_error_dev(sc->sc_dev,
+			    "%s: failed to read NVM\n", __func__);
 			break;
 		}
 		data[i] = word;
@@ -7671,6 +7859,7 @@ wm_check_mng_mode(struct wm_softc *sc)
 	case WM_T_ICH10:
 	case WM_T_PCH:
 	case WM_T_PCH2:
+	case WM_T_PCH_LPT:
 		rv = wm_check_mng_mode_ich8lan(sc);
 		break;
 	case WM_T_82574:
@@ -7772,6 +7961,7 @@ wm_check_reset_block(struct wm_softc *sc
 	case WM_T_ICH10:
 	case WM_T_PCH:
 	case WM_T_PCH2:
+	case WM_T_PCH_LPT:
 		reg = CSR_READ(sc, WMREG_FWSM);
 		if ((reg & FWSM_RSPCIPHY) != 0)
 			return 0;
@@ -7818,6 +8008,7 @@ wm_get_hw_control(struct wm_softc *sc)
 	case WM_T_ICH10:
 	case WM_T_PCH:
 	case WM_T_PCH2:
+	case WM_T_PCH_LPT:
 		reg = CSR_READ(sc, WMREG_CTRL_EXT);
 		CSR_WRITE(sc, WMREG_CTRL_EXT, reg | CTRL_EXT_DRV_LOAD);
 		break;
@@ -7833,7 +8024,7 @@ wm_release_hw_control(struct wm_softc *s
 
 	if ((sc->sc_flags & WM_F_HAS_MANAGE) == 0)
 		return;
-	
+
 	if (sc->sc_type == WM_T_82573) {
 		reg = CSR_READ(sc, WMREG_SWSM);
 		reg &= ~SWSM_DRV_LOAD;
@@ -7950,7 +8141,7 @@ wm_kmrn_lock_loss_workaround_ich8lan(str
 	reg = CSR_READ(sc, WMREG_PHY_CTRL);
 	reg |= PHY_CTRL_GBE_DIS | PHY_CTRL_NOND0A_GBE_DIS;
 	CSR_WRITE(sc, WMREG_PHY_CTRL, reg);
-	
+
 	/*
 	 * Call gig speed drop workaround on Gig disable before accessing
 	 * any PHY registers.
@@ -8230,7 +8421,7 @@ wm_init_manageability(struct wm_softc *s
 			manc |= MANC_EN_MNG2HOST;
 			manc2h |= MANC2H_PORT_623| MANC2H_PORT_624;
 			CSR_WRITE(sc, WMREG_MANC2H, manc2h);
-			
+		
 		}
 
 		CSR_WRITE(sc, WMREG_MANC, manc);
@@ -8261,7 +8452,7 @@ wm_get_wakeup(struct wm_softc *sc)
 	case WM_T_82583:
 		sc->sc_flags |= WM_F_HAS_AMT;
 		/* FALLTHROUGH */
-	case WM_T_80003: 
+	case WM_T_80003:
 	case WM_T_82541:
 	case WM_T_82547:
 	case WM_T_82571:
@@ -8283,6 +8474,7 @@ wm_get_wakeup(struct wm_softc *sc)
 	case WM_T_ICH10:
 	case WM_T_PCH:
 	case WM_T_PCH2:
+	case WM_T_PCH_LPT:
 		sc->sc_flags |= WM_F_HAS_AMT;
 		sc->sc_flags |= WM_F_ASF_FIRMWARE_PRES;
 		break;
@@ -8358,6 +8550,7 @@ wm_enable_wakeup(struct wm_softc *sc)
 	case WM_T_ICH10:
 	case WM_T_PCH:
 	case WM_T_PCH2:
+	case WM_T_PCH_LPT:
 		/* Disable gig during WOL */
 		reg = CSR_READ(sc, WMREG_PHY_CTRL);
 		reg |= PHY_CTRL_D0A_LPLU | PHY_CTRL_GBE_DIS;

Index: src/sys/dev/pci/if_wmreg.h
diff -u src/sys/dev/pci/if_wmreg.h:1.46.2.3 src/sys/dev/pci/if_wmreg.h:1.46.2.4
--- src/sys/dev/pci/if_wmreg.h:1.46.2.3	Mon Feb 18 18:05:30 2013
+++ src/sys/dev/pci/if_wmreg.h	Sun Jul 14 20:39:13 2013
@@ -1,4 +1,4 @@
-/*	$NetBSD: if_wmreg.h,v 1.46.2.3 2013/02/18 18:05:30 riz Exp $	*/
+/*	$NetBSD: if_wmreg.h,v 1.46.2.4 2013/07/14 20:39:13 riz Exp $	*/
 
 /*
  * Copyright (c) 2001 Wasabi Systems, Inc.
@@ -35,6 +35,39 @@
  * POSSIBILITY OF SUCH DAMAGE.
  */
 
+/******************************************************************************
+
+  Copyright (c) 2001-2012, Intel Corporation 
+  All rights reserved.
+  
+  Redistribution and use in source and binary forms, with or without 
+  modification, are permitted provided that the following conditions are met:
+  
+   1. Redistributions of source code must retain the above copyright notice, 
+      this list of conditions and the following disclaimer.
+  
+   2. Redistributions in binary form must reproduce the above copyright 
+      notice, this list of conditions and the following disclaimer in the 
+      documentation and/or other materials provided with the distribution.
+  
+   3. Neither the name of the Intel Corporation nor the names of its 
+      contributors may be used to endorse or promote products derived from 
+      this software without specific prior written permission.
+  
+  THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+  AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 
+  IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 
+  ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE 
+  LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 
+  CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 
+  SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 
+  INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 
+  CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 
+  ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+  POSSIBILITY OF SUCH DAMAGE.
+
+******************************************************************************/
+
 /*
  * Register description for the Intel i82542 (``Wiseman''),
  * i82543 (``Livengood''), and i82544 (``Cordova'') Gigabit
@@ -200,6 +233,7 @@ struct livengood_tcpip_ctxdesc {
 #define	CTRL_SWDPIO_SHIFT	22
 #define	CTRL_SWDPIO_MASK	0x0f
 #define	CTRL_SWDPIO(x)		(1U << (CTRL_SWDPIO_SHIFT + (x)))
+#define CTRL_MEHE	(1U << 17)	/* Memory Error Handling Enable(I217)*/
 #define	CTRL_RST	(1U << 26)	/* device reset */
 #define	CTRL_RFCE	(1U << 27)	/* Rx flow control enable */
 #define	CTRL_TFCE	(1U << 28)	/* Tx flow control enable */
@@ -255,6 +289,7 @@ struct livengood_tcpip_ctxdesc {
 #define	EECD_EE_TYPE	(1U << 13)	/* EEPROM type
 					   (0 = Microwire, 1 = SPI) */
 #define EECD_SEC1VAL	(1U << 22)	/* Sector One Valid */
+#define EECD_SEC1VAL_VALMASK (EECD_EE_AUTORD | EECD_EE_PRES) /* Valid Mask */
 
 #define	UWIRE_OPC_ERASE	0x04		/* MicroWire "erase" opcode */
 #define	UWIRE_OPC_WRITE	0x05		/* MicroWire "write" opcode */
@@ -683,6 +718,7 @@ struct livengood_tcpip_ctxdesc {
 #define	PBA_26K		0x001a
 #define	PBA_30K		0x001e
 #define	PBA_32K		0x0020
+#define	PBA_34K		0x0022
 #define	PBA_35K		0x0023
 #define	PBA_40K		0x0028
 #define	PBA_48K		0x0030		/* 48K, default Rx allocation */
@@ -690,6 +726,11 @@ struct livengood_tcpip_ctxdesc {
 
 #define	WMREG_PBS	0x1008	/* Packet Buffer Size (ICH) */
 
+#define	WMREG_PBECCSTS	0x100c	/* Packet Buffer ECC Status (PCH_LPT) */
+#define	PBECCSTS_CORR_ERR_CNT_MASK	0x000000ff
+#define	PBECCSTS_UNCORR_ERR_CNT_MASK	0x0000ff00
+#define	PBECCSTS_UNCORR_ECC_ENABLE	0x00010000
+
 #define WMREG_EEMNGCTL	0x1010	/* MNG EEprom Control */
 #define EEMNGCTL_CFGDONE_0 0x040000	/* MNG config cycle done */
 #define EEMNGCTL_CFGDONE_1 0x080000	/*  2nd port */
@@ -708,6 +749,13 @@ struct livengood_tcpip_ctxdesc {
 #define MAX_SGMII_PHY_REG_ADDR	255
 #define I2CCMD_PHY_TIMEOUT	200
 
+#define WMREG_PBA_ECC	0x01100	/* PBA ECC */
+#define PBA_ECC_COUNTER_MASK	0xfff00000 /* ECC counter mask */
+#define PBA_ECC_COUNTER_SHIFT	20	   /* ECC counter shift value */
+#define	PBA_ECC_CORR_EN		0x00000001 /* Enable ECC error correction */
+#define	PBA_ECC_STAT_CLR	0x00000002 /* Clear ECC error counter */
+#define	PBA_ECC_INT_EN		0x00000004 /* Enable ICR bit 5 on ECC error */
+
 #define WMREG_EICS	0x01520  /* Ext. Interrupt Cause Set - WO */
 #define WMREG_EIMS	0x01524  /* Ext. Interrupt Mask Set/Read - RW */
 #define WMREG_EIMC	0x01528  /* Ext. Interrupt Mask Clear - WO */
@@ -963,6 +1011,8 @@ struct livengood_tcpip_ctxdesc {
 
 #define ICH_NVM_SIG_WORD	0x13
 #define ICH_NVM_SIG_MASK	0xc000
+#define ICH_NVM_VALID_SIG_MASK	0xc0
+#define ICH_NVM_SIG_VALUE	0x80
 
 /* for PCI express Capability registers */
 #define	WM_PCI_PCIE_DCSR2_16MS	0x00000005

Index: src/sys/dev/pci/if_wmvar.h
diff -u src/sys/dev/pci/if_wmvar.h:1.12.10.2 src/sys/dev/pci/if_wmvar.h:1.12.10.3
--- src/sys/dev/pci/if_wmvar.h:1.12.10.2	Thu Feb 14 22:08:28 2013
+++ src/sys/dev/pci/if_wmvar.h	Sun Jul 14 20:39:13 2013
@@ -1,4 +1,4 @@
-/*	$NetBSD: if_wmvar.h,v 1.12.10.2 2013/02/14 22:08:28 jdc Exp $	*/
+/*	$NetBSD: if_wmvar.h,v 1.12.10.3 2013/07/14 20:39:13 riz Exp $	*/
 
 /*
  * Copyright (c) 2001, 2002, 2003, 2004 Wasabi Systems, Inc.
@@ -94,6 +94,7 @@
 #define WM_F_HAS_MANAGE		0x00080000
 #define WM_F_WOL		0x00100000
 #define WM_F_EEE		0x00200000  /* Energy Efficiency Ethernet */
+#define	WM_F_EEPROM_FLASH_HW	0x00400000	/* EEPROM is FLASH */
 
 typedef enum {
 	WM_T_unknown		= 0,
@@ -120,12 +121,15 @@ typedef enum {
 	WM_T_82580,			/* i82580 */
 	WM_T_82580ER,			/* i82580ER */
 	WM_T_I350,			/* I350 */
+	WM_T_I210,			/* I210 */
+	WM_T_I211,			/* I211 */
 	WM_T_80003,			/* i80003 */
 	WM_T_ICH8,			/* ICH8 LAN */
 	WM_T_ICH9,			/* ICH9 LAN */
 	WM_T_ICH10,			/* ICH10 LAN */
 	WM_T_PCH,			/* PCH LAN */
 	WM_T_PCH2,			/* PCH2 LAN */
+	WM_T_PCH_LPT,			/* PCH LPT LAN (I21[78]) */
 } wm_chip_type;
 
 typedef enum {

Reply via email to