Subject: Re: Intel 82573 support
To: None <lists@yazzy.org>
From: SAITOH Masanobu <masanobu@iij.ad.jp>
List: current-users
Date: 05/08/2006 18:05:48
 > > Hi,
 > >
 > > Is anyone working on the support for the Intel 82573 Ethernet chip?
 > >
 > > Jean-Luc
 > 
 > I began working on it but after I got the nic recognized my time schedule 
 > disallowed futher work on it.
 > However this port of FreeBSD's driver by Dheeraj Reddy worked fine on my 
 > current:
 > http://users.ece.gatech.edu/~dheeraj/netbsd.html
 > 
 > 
 > -- 
 > Marcin M. Jessa
 >  http://www.yazzy.org/

I made a patch for the wm driver.

	o NOT COMPLETED

	o most code was taken from Dheeraj Reddy's driver.

	o At least, an i82573E based machine works.

	o not for -current but for netbsd-3 (sorry)

I'm busy and no time to spend to finish this work. I want someone to
take over my work.

Regards.

----------------------------------------------------------
		SAITOH Masanobu (masanobu@iij.ad.jp
				  msaitoh@netbsd.org)


Index: if_wm.c
===================================================================
RCS file: /cvsroot/src/sys/dev/pci/if_wm.c,v
retrieving revision 1.100.2.4
diff -u -r1.100.2.4 if_wm.c
--- if_wm.c	8 Feb 2006 21:10:28 -0000	1.100.2.4
+++ if_wm.c	8 May 2006 08:44:22 -0000
@@ -213,6 +213,9 @@
 	WM_T_82541_2,			/* i82541 2.0+ */
 	WM_T_82547,			/* i82547 */
 	WM_T_82547_2,			/* i82547 2.0+ */
+	WM_T_82571,
+	WM_T_82572,
+	WM_T_82573,
 } wm_chip_type;
 
 /*
@@ -356,10 +359,12 @@
 #define	WM_F_HAS_MII		0x01	/* has MII */
 #define	WM_F_EEPROM_HANDSHAKE	0x02	/* requires EEPROM handshake */
 #define	WM_F_EEPROM_SPI		0x04	/* EEPROM is SPI */
+#define	WM_F_EEPROM_SEMAPHORE	0x08	/* EEPROM semaphore is required */
 #define	WM_F_IOH_VALID		0x10	/* I/O handle is valid */
 #define	WM_F_BUS64		0x20	/* bus is 64-bit */
 #define	WM_F_PCIX		0x40	/* bus is PCI-X */
 #define	WM_F_CSA		0x80	/* bus is CSA */
+#define	WM_F_PCIE		0x100	/* bus is PCI-Express */
 
 #ifdef WM_EVENT_COUNTERS
 #define	WM_EVCNT_INCR(ev)	(ev)->ev_count++
@@ -494,6 +499,14 @@
 
 static int	wm_match(struct device *, struct cfdata *, void *);
 static void	wm_attach(struct device *, struct device *, void *);
+static int	wm_is_onboard_nvm_eeprom(struct wm_softc *);
+static int32_t	wm_get_auto_rd_done(struct wm_softc *);
+static int32_t	wm_get_hw_eeprom_semaphore(struct wm_softc *);
+static void	wm_put_hw_eeprom_semaphore(struct wm_softc *);
+static void	wm_standby_eeprom(struct wm_softc *);
+static int32_t	wm_read_eeprom_eerd(struct wm_softc *, int32_t, int32_t,
+    uint16_t *);
+static int32_t	wm_poll_eerd_eewr_done(struct wm_softc *, int);
 
 CFATTACH_DECL(wm, sizeof(struct wm_softc),
     wm_match, wm_attach, NULL, NULL);
@@ -604,10 +617,18 @@
 	  "Intel i82546GB Gigabit Ethernet (SERDES)",
 	  WM_T_82546_3,		WMP_F_SERDES },
 #endif
+	{ PCI_VENDOR_INTEL,	PCI_PRODUCT_INTEL_82546GB_PCIE,
+	  "Intel PRO/1000MT (82546GB)",
+	  WM_T_82546_3,		WMP_F_1000T },
+
 	{ PCI_VENDOR_INTEL,	PCI_PRODUCT_INTEL_82541EI,
 	  "Intel i82541EI 1000BASE-T Ethernet",
 	  WM_T_82541,		WMP_F_1000T },
 
+	{ PCI_VENDOR_INTEL,	PCI_PRODUCT_INTEL_82541ER_LOM,
+	  "Intel i82541ER (LOM) 1000BASE-T Ethernet",
+	  WM_T_82541,		WMP_F_1000T },
+
 	{ PCI_VENDOR_INTEL,	PCI_PRODUCT_INTEL_82541EI_MOBILE,
 	  "Intel i82541EI Mobile 1000BASE-T Ethernet",
 	  WM_T_82541,		WMP_F_1000T },
@@ -632,9 +653,50 @@
 	  "Intel i82547EI 1000BASE-T Ethernet",
 	  WM_T_82547,		WMP_F_1000T },
 
+	{ PCI_VENDOR_INTEL,	PCI_PRODUCT_INTEL_82547EI_MOBILE,
+	  "Intel i82547EI Moblie 1000BASE-T Ethernet",
+	  WM_T_82547,		WMP_F_1000T },
+
 	{ PCI_VENDOR_INTEL,	PCI_PRODUCT_INTEL_82547GI,
 	  "Intel i82547GI 1000BASE-T Ethernet",
 	  WM_T_82547_2,		WMP_F_1000T },
+
+	{ PCI_VENDOR_INTEL,	PCI_PRODUCT_INTEL_82571EB_COPPER,
+	  "Intel PRO/1000 PT (82571EB)",
+	  WM_T_82571,		WMP_F_1000T },
+
+	{ PCI_VENDOR_INTEL,	PCI_PRODUCT_INTEL_82571EB_FIBER,
+	  "Intel PRO/1000 PF (82571EB)",
+	  WM_T_82571,		WMP_F_1000X },
+#if 0
+	{ PCI_VENDOR_INTEL,	PCI_PRODUCT_INTEL_82571EB_SERDES,
+	  "Intel PRO/1000 PB (82571EB)",
+	  WM_T_82571,		WMP_F_SERDES },
+#endif
+	{ PCI_VENDOR_INTEL,	PCI_PRODUCT_INTEL_82572EI_COPPER,
+	  "Intel i82572EI 1000baseT Ethernet",
+	  WM_T_82572,		WMP_F_1000T },
+
+	{ PCI_VENDOR_INTEL,	PCI_PRODUCT_INTEL_82572EI_FIBER,
+	  "Intel i82572EI 1000baseX Ethernet",
+	  WM_T_82572,		WMP_F_1000X },
+#if 0
+	{ PCI_VENDOR_INTEL,	PCI_PRODUCT_INTEL_82572EI_SERDES,
+	  "Intel i82572EI Gigabit Ethernet (SERDES)",
+	  WM_T_82572,		WMP_F_SERDES },
+#endif
+	{ PCI_VENDOR_INTEL,	PCI_PRODUCT_INTEL_82573E,
+	  "Intel i82573E",
+	  WM_T_82573,		WMP_F_1000T },
+
+	{ PCI_VENDOR_INTEL,	PCI_PRODUCT_INTEL_82573E_IAMT,
+	  "Intel i82573E",
+	  WM_T_82573,		WMP_F_1000T },
+
+	{ PCI_VENDOR_INTEL,	PCI_PRODUCT_INTEL_82573L,
+	  "Intel i82573L Gigabit Ethernet",
+	  WM_T_82573,		WMP_F_1000T },
+
 	{ 0,			0,
 	  NULL,
 	  0,			0 },
@@ -883,6 +945,23 @@
 		reg = CSR_READ(sc, WMREG_STATUS);
 		if (reg & STATUS_BUS64)
 			sc->sc_flags |= WM_F_BUS64;
+		if (sc->sc_type >= WM_T_82571) {
+			uint32_t reg;
+			int timeout = 800;
+
+			sc->sc_flags |= WM_F_PCIE;
+			/* disable PCI-Express master access */
+			reg = CSR_READ(sc, WMREG_CTRL) | CTRL_GIO_M_DIS;
+			CSR_WRITE(sc, WMREG_CTRL, reg);
+
+			while(timeout) {
+				if(!(CSR_READ(sc, WMREG_STATUS) & STATUS_GIO_MASTER_ENA))
+					break;
+				else
+					delay(100);
+				timeout--;
+			}
+		}
 		if (sc->sc_type >= WM_T_82544 &&
 		    (reg & STATUS_PCIX_MODE) != 0) {
 			pcireg_t pcix_cmd, pcix_sts, bytecnt, maxb;
@@ -933,6 +1012,8 @@
 		if (wmp->wmp_product == PCI_PRODUCT_INTEL_82546EB_QUAD) {
 			sc->sc_bus_speed = (sc->sc_flags & WM_F_PCIX) ? 120
 								      : 66;
+		} else if (sc->sc_flags & WM_F_PCIE) {
+			sc->sc_bus_speed = 2500;
 		} else if (sc->sc_flags & WM_F_PCIX) {
 			switch (reg & STATUS_PCIXSPD_MASK) {
 			case STATUS_PCIXSPD_50_66:
@@ -953,9 +1034,14 @@
 			}
 		} else
 			sc->sc_bus_speed = (reg & STATUS_PCI66) ? 66 : 33;
-		aprint_verbose("%s: %d-bit %dMHz %s bus\n", sc->sc_dev.dv_xname,
-		    (sc->sc_flags & WM_F_BUS64) ? 64 : 32, sc->sc_bus_speed,
-		    (sc->sc_flags & WM_F_PCIX) ? "PCIX" : "PCI");
+		if (sc->sc_flags & WM_F_PCIE) {
+			aprint_verbose("%s: %s bus\n", sc->sc_dev.dv_xname,
+			    "PCI-Express");
+		} else {
+			aprint_verbose("%s: %d-bit %dMHz %s bus\n", sc->sc_dev.dv_xname,
+			    (sc->sc_flags & WM_F_BUS64) ? 64 : 32, sc->sc_bus_speed,
+			    (sc->sc_flags & WM_F_PCIX) ? "PCIX" : "PCI");
+		}
 	}
 
 	/*
@@ -1034,6 +1120,9 @@
 		sc->sc_rxsoft[i].rxs_mbuf = NULL;
 	}
 
+	if (sc->sc_type >= WM_T_82571)
+		sc->sc_flags |= WM_F_EEPROM_SEMAPHORE;
+
 	/*
 	 * Reset the chip to a known state.
 	 */
@@ -1060,6 +1149,12 @@
 		} else
 			sc->sc_ee_addrbits = (reg & EECD_EE_ABITS) ? 8 : 6;
 	} else {
+		if (sc->sc_type >= WM_T_82571) {
+			int rv;
+			rv = wm_get_auto_rd_done(sc);
+		}
+		if (wm_is_onboard_nvm_eeprom(sc) == 0)
+			printf("XXXXXXXXXXXXXXX FLASH XXXXXXXXXXXXXXX\n");
 		/* Assume everything else is SPI. */
 		reg = CSR_READ(sc, WMREG_EECD);
 		sc->sc_flags |= WM_F_EEPROM_SPI;
@@ -1329,6 +1424,48 @@
 	return;
 }
 
+/*******************************************************************************
+ *
+ * Check for EEPROM Auto Read bit done.
+ *
+ * hw: Struct containing variables accessed by shared code
+ *
+ * returns: - E1000_ERR_RESET if fail to reset MAC
+ *            E1000_SUCCESS at any other case.
+ *
+ ******************************************************************************/
+static int32_t
+wm_get_auto_rd_done(struct wm_softc *sc)
+{
+    int32_t timeout = 1000;
+
+    DPRINTF(WM_DEBUG_GMII, ("wm_get_auto_rd_done"));
+
+    switch (sc->sc_type) {
+    default:
+        delay(5*1000);
+        break;
+    case WM_T_82571:
+    case WM_T_82572:
+    case WM_T_82573:
+        while(timeout) {
+            if (CSR_READ(sc, WMREG_EECD) & EECD_EE_AUTORD)
+		    break;
+            else
+		    delay(1*1000);
+            timeout--;
+        }
+
+        if(!timeout) {
+            DPRINTF(WM_DEBUG_GMII, ("Auto read by HW from EEPROM has not completed.\n"));
+            return -1;
+        }
+        break;
+    }
+
+    return 0;
+}
+
 /*
  * wm_shutdown:
  *
@@ -2459,6 +2596,9 @@
 wm_reset(struct wm_softc *sc)
 {
 	int i;
+#if 0
+	uint32_t reg;
+#endif
 
 	/*
 	 * Allocate on-chip memory according to the MTU size.
@@ -2479,6 +2619,29 @@
 	}
 	CSR_WRITE(sc, WMREG_PBA, sc->sc_pba);
 
+	/* Must acquire the MDIO ownership before MAC reset.
+	 * Ownership defaults to firmware after a reset. */
+	if(sc->sc_type == WM_T_82573) {
+		uint32_t extcnf_ctrl;
+		int timeout = 10;
+
+		extcnf_ctrl = CSR_READ(sc, WMREG_EXTCNF_CTRL);
+		extcnf_ctrl |= EXTCNF_CTRL_MDIO_SW_OWNERSHIP;
+
+		do {
+			CSR_WRITE(sc, WMREG_EXTCNF_CTRL, extcnf_ctrl);
+			extcnf_ctrl = CSR_READ(sc, WMREG_EXTCNF_CTRL);
+
+			if(extcnf_ctrl & EXTCNF_CTRL_MDIO_SW_OWNERSHIP)
+				break;
+			else
+				extcnf_ctrl |= EXTCNF_CTRL_MDIO_SW_OWNERSHIP;
+
+			delay(2*1000);
+			timeout--;
+		} while(timeout);
+	}
+
 	switch (sc->sc_type) {
 	case WM_T_82544:
 	case WM_T_82540:
@@ -2511,20 +2674,41 @@
 
 	default:
 		/* Everything else can safely use the documented method. */
+#if 1
 		CSR_WRITE(sc, WMREG_CTRL, CTRL_RST);
+#else
+		reg = CSR_READ(sc, WMREG_CTRL);
+		CSR_WRITE(sc, WMREG_CTRL, reg | CTRL_RST);
+		printf("new reset");
+#endif
 		break;
 	}
 	delay(10000);
 
-	for (i = 0; i < 1000; i++) {
-		if ((CSR_READ(sc, WMREG_CTRL) & CTRL_RST) == 0)
+	if (sc->sc_type == WM_T_82573) {
+		uint32_t ctrl_ext;
+		int32_t ret_val;
+
+		delay(10);
+		ctrl_ext = CSR_READ(sc, WMREG_CTRL_EXT);
+		ctrl_ext |= CTRL_EXT_EE_RST;
+		CSR_WRITE(sc, WMREG_CTRL_EXT, ctrl_ext);
+		CSR_WRITE_FLUSH(sc);
+		ret_val = wm_get_auto_rd_done(sc);
+		if(ret_val)
+			/* We don't want to continue accessing MAC registers. */
 			return;
-		delay(20);
-	}
+	} else {
+		for (i = 0; i < 1000; i++) {
+			if ((CSR_READ(sc, WMREG_CTRL) & CTRL_RST) == 0)
+				return;
+			delay(20);
+		}
 
-	if (CSR_READ(sc, WMREG_CTRL) & CTRL_RST)
-		log(LOG_ERR, "%s: reset failed to complete\n",
-		    sc->sc_dev.dv_xname);
+		if (CSR_READ(sc, WMREG_CTRL) & CTRL_RST)
+			log(LOG_ERR, "%s: reset failed to complete\n",
+			    sc->sc_dev.dv_xname);
+	}
 }
 
 /*
@@ -2872,6 +3056,30 @@
 	ifp->if_timer = 0;
 }
 
+/***************************************************************************
+* Description:     Determines if the onboard NVM is FLASH or EEPROM.
+*
+* hw - Struct containing variables accessed by shared code
+****************************************************************************/
+static int
+wm_is_onboard_nvm_eeprom(struct wm_softc *sc)
+{
+    uint32_t eecd = 0;
+
+    if(sc->sc_type == WM_T_82573) {
+	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;
+}
+
 /*
  * wm_acquire_eeprom:
  *
@@ -2883,32 +3091,102 @@
 	uint32_t reg;
 	int x;
 
-	if (sc->sc_flags & WM_F_EEPROM_HANDSHAKE)  {
-		reg = CSR_READ(sc, WMREG_EECD);
+	if (wm_get_hw_eeprom_semaphore(sc))
+		return 1;
 
-		/* Request EEPROM access. */
-		reg |= EECD_EE_REQ;
-		CSR_WRITE(sc, WMREG_EECD, reg);
+	reg = CSR_READ(sc, WMREG_EECD);
 
-		/* ..and wait for it to be granted. */
-		for (x = 0; x < 100; x++) {
-			reg = CSR_READ(sc, WMREG_EECD);
-			if (reg & EECD_EE_GNT)
-				break;
-			delay(5);
-		}
-		if ((reg & EECD_EE_GNT) == 0) {
-			aprint_error("%s: could not acquire EEPROM GNT\n",
-			    sc->sc_dev.dv_xname);
-			reg &= ~EECD_EE_REQ;
+	if (sc->sc_type != WM_T_82573) {
+		if (sc->sc_flags & WM_F_EEPROM_HANDSHAKE)  {
+			/* Request EEPROM access. */
+			reg |= EECD_EE_REQ;
 			CSR_WRITE(sc, WMREG_EECD, reg);
-			return (1);
+
+			/* ..and wait for it to be granted. */
+			for (x = 0; x < 100; x++) {
+				reg = CSR_READ(sc, WMREG_EECD);
+				if (reg & EECD_EE_GNT)
+					break;
+				delay(5);
+			}
+			if ((reg & EECD_EE_GNT) == 0) {
+				aprint_error("%s: could not acquire EEPROM GNT\n",
+				    sc->sc_dev.dv_xname);
+				reg &= ~EECD_EE_REQ;
+				CSR_WRITE(sc, WMREG_EECD, reg);
+				return (1);
+			}
 		}
 	}
 
+	/* Setup EEPROM for Read/Write */
+
+	if (!(sc->sc_flags & WM_F_EEPROM_SPI)) { /* micorwire */
+ 		/* Clear SK and DI */
+		reg &= ~(EECD_DI | EECD_SK);
+		CSR_WRITE(sc, WMREG_EECD, reg);
+
+		/* Set CS */
+		reg |= EECD_CS;
+		CSR_WRITE(sc, WMREG_EECD, reg);
+	} else {
+		/* Clear SK and CS */
+		reg &= ~(EECD_CS | EECD_SK);
+		CSR_WRITE(sc, WMREG_EECD, reg);
+		delay(1);
+	}
+
 	return (0);
 }
 
+/******************************************************************************
+ * Returns EEPROM to a "standby" state
+ *
+ * hw - Struct containing variables accessed by shared code
+ *****************************************************************************/
+static void
+wm_standby_eeprom(struct wm_softc *sc)
+{
+    uint32_t eecd;
+
+    eecd = CSR_READ(sc, WMREG_EECD);
+
+    if (!(sc->sc_flags & WM_F_EEPROM_SPI)) {
+        eecd &= ~(EECD_CS | EECD_SK);
+        CSR_WRITE(sc, WMREG_EECD, eecd);
+        CSR_WRITE_FLUSH(sc);
+        delay(100); /* XXX */
+
+        /* Clock high */
+        eecd |= EECD_SK;
+        CSR_WRITE(sc, WMREG_EECD, eecd);
+        CSR_WRITE_FLUSH(sc);
+        delay(100); /* XXX */
+
+        /* Select EEPROM */
+        eecd |= EECD_CS;
+        CSR_WRITE(sc, WMREG_EECD, eecd);
+        CSR_WRITE_FLUSH(sc);
+        delay(100); /* XXX */
+
+        /* Clock low */
+        eecd &= ~EECD_SK;
+        CSR_WRITE(sc, WMREG_EECD, eecd);
+        CSR_WRITE_FLUSH(sc);
+        delay(100); /* XXX */
+    } else { /* SPI */
+        /* Toggle CS to flush commands */
+        eecd |= EECD_CS;
+        CSR_WRITE(sc, WMREG_EECD, eecd);
+        CSR_WRITE_FLUSH(sc);
+        delay(100); /* XXX */
+        eecd &= ~EECD_CS;
+        CSR_WRITE(sc, WMREG_EECD, eecd);
+        CSR_WRITE_FLUSH(sc);
+        delay(100); /* XXX */
+    }
+}
+
 /*
  * wm_release_eeprom:
  *
@@ -2919,11 +3197,23 @@
 {
 	uint32_t reg;
 
-	if (sc->sc_flags & WM_F_EEPROM_HANDSHAKE) {
+	reg = CSR_READ(sc, WMREG_EECD);
+
+	if (sc->sc_flags & WM_F_EEPROM_SPI) {
+		reg |= EECD_CS; /* Pull CS high */
+		reg &= ~EECD_SK;/* Lower SCK */
+		CSR_WRITE(sc, WMREG_EECD, reg);
+	} else {
+		/* XXX null */
+	}
+
+	if (sc->sc_type & WM_T_82544) {
 		reg = CSR_READ(sc, WMREG_EECD);
 		reg &= ~EECD_EE_REQ;
 		CSR_WRITE(sc, WMREG_EECD, reg);
 	}
+
+	wm_put_hw_eeprom_semaphore(sc);
 }
 
 /*
@@ -2945,6 +3235,7 @@
 		else
 			reg &= ~EECD_DI;
 		CSR_WRITE(sc, WMREG_EECD, reg);
+		CSR_WRITE_FLUSH(sc);
 		delay(2);
 		CSR_WRITE(sc, WMREG_EECD, reg | EECD_SK);
 		delay(2);
@@ -3018,6 +3309,68 @@
 	return (0);
 }
 
+/******************************************************************************
+ * Reads a 16 bit word from the EEPROM using the EERD register.
+ *
+ * hw - Struct containing variables accessed by shared code
+ * offset - offset of  word in the EEPROM to read
+ * data - word read from the EEPROM
+ * words - number of words to read
+ *****************************************************************************/
+static int32_t
+wm_read_eeprom_eerd(struct wm_softc *sc,
+                  int32_t offset,
+                  int32_t words,
+                  uint16_t *data)
+{
+    uint32_t i, eerd = 0;
+    int32_t error = 0;
+
+    for (i = 0; i < words; i++) {
+        eerd = ((offset+i) << E1000_EEPROM_RW_ADDR_SHIFT) +
+                         E1000_EEPROM_RW_REG_START;
+
+        CSR_WRITE(sc, WMREG_EERD, eerd);
+        error = wm_poll_eerd_eewr_done(sc, E1000_EEPROM_POLL_READ);
+        
+        if(error) {
+            break;
+        }
+        data[i] = (CSR_READ(sc, WMREG_EERD) >> E1000_EEPROM_RW_REG_DATA);
+      
+    }
+    
+    return error;
+}
+
+/******************************************************************************
+ * Polls the status bit (bit 1) of the EERD to determine when the read is done.
+ *
+ * hw - Struct containing variables accessed by shared code
+ *****************************************************************************/
+static int32_t
+wm_poll_eerd_eewr_done(struct wm_softc *sc, int eerd)
+{
+    uint32_t attempts = 100000;
+    uint32_t i, reg = 0;
+    int32_t done = -1;
+
+    for(i = 0; i < attempts; i++) {
+        if(eerd == E1000_EEPROM_POLL_READ)
+            reg = CSR_READ(sc, WMREG_EERD);
+        else 
+            reg = CSR_READ(sc, WMREG_EEWR);
+
+        if(reg & E1000_EEPROM_RW_REG_DONE) {
+            done = 0;
+            break;
+        }
+        delay(5);
+    }
+
+    return done;
+}
+
 /*
  * wm_spi_eeprom_ready:
  *
@@ -3029,7 +3382,7 @@
 	uint32_t val;
 	int usec;
 
-	for (usec = 0; usec < SPI_MAX_RETRIES; delay(5), usec += 5) {
+	for (usec = 0; usec < SPI_MAX_RETRIES; delay(5), wm_standby_eeprom(sc), usec += 5) {
 		wm_eeprom_sendbits(sc, SPI_OPC_RDSR, 8);
 		wm_eeprom_recvbits(sc, &val, 8);
 		if ((val & SPI_SR_RDY) == 0)
@@ -3063,10 +3416,14 @@
 	if (wm_spi_eeprom_ready(sc))
 		return (1);
 
+	wm_standby_eeprom(sc);
+
 	/* Toggle CS to flush commands. */
 	CSR_WRITE(sc, WMREG_EECD, reg | EECD_CS);
+	CSR_WRITE_FLUSH(sc);
 	delay(2);
 	CSR_WRITE(sc, WMREG_EECD, reg);
+	CSR_WRITE_FLUSH(sc);
 	delay(2);
 
 	opc = SPI_OPC_READ;
@@ -3099,8 +3456,21 @@
 {
 	int rv;
 
-	if (wm_acquire_eeprom(sc))
-		return (1);
+	if ((wm_is_onboard_nvm_eeprom(sc) == 1) ||
+	    (sc->sc_type != WM_T_82573))
+		if (wm_acquire_eeprom(sc)) {
+			return (1);
+		}
+
+	if (sc->sc_type == WM_T_82573) {
+		int32_t rv;
+
+		rv = wm_read_eeprom_eerd(sc, word, wordcnt, data);
+		if ((wm_is_onboard_nvm_eeprom(sc) == 1) ||
+		    (sc->sc_type != WM_T_82573))
+			wm_release_eeprom(sc);
+		return rv;
+	}
 
 	if (sc->sc_flags & WM_F_EEPROM_SPI)
 		rv = wm_read_eeprom_spi(sc, word, wordcnt, data);
@@ -3853,3 +4223,73 @@
 	CSR_WRITE(sc, (sc->sc_type < WM_T_82543) ? WMREG_OLD_FCRTL
 						 : WMREG_FCRTL, sc->sc_fcrtl);
 }
+
+/***************************************************************************
+ *
+ * Using the combination of SMBI and SWESMBI semaphore bits when resetting
+ * adapter or Eeprom access.
+ *
+ * hw: Struct containing variables accessed by shared code
+ *
+ * returns: - E1000_ERR_EEPROM if fail to access EEPROM.
+ *            E1000_SUCCESS at any other case.
+ *
+ ***************************************************************************/
+static int32_t
+wm_get_hw_eeprom_semaphore(struct wm_softc *sc)
+{
+    int32_t timeout;
+    uint32_t swsm;
+
+    DPRINTF(WM_DEBUG_GMII, ("wm_get_hw_eeprom_semaphore"));
+
+    if((sc->sc_flags & WM_F_EEPROM_SEMAPHORE) == 0)
+        return 0;
+
+    /* Get the FW semaphore. */
+    timeout = 1000 + 1; /* XXX */
+    while(timeout) {
+        swsm = CSR_READ(sc, WMREG_SWSM);
+        swsm |= SWSM_SWESMBI;
+        CSR_WRITE(sc, WMREG_SWSM, swsm);
+        /* if we managed to set the bit we got the semaphore. */
+        swsm = CSR_READ(sc, WMREG_SWSM);
+        if(swsm & SWSM_SWESMBI)
+            break;
+
+        delay(50);
+        timeout--;
+    }
+
+    if(!timeout) {
+        /* Release semaphores */
+        wm_put_hw_eeprom_semaphore(sc);
+        DPRINTF(WM_DEBUG_GMII, ("Driver can't access the Eeprom - SWESMBI bit is set.\n"));
+        return 1;
+    }
+
+    return 0;
+}
+
+/***************************************************************************
+ * This function clears HW semaphore bits.
+ *
+ * hw: Struct containing variables accessed by shared code
+ *
+ * returns: - None.
+ *
+ ***************************************************************************/
+static void
+wm_put_hw_eeprom_semaphore(struct wm_softc *sc)
+{
+    uint32_t swsm;
+
+    DPRINTF(WM_DEBUG_GMII, ("wm_put_hw_eeprom_semaphore"));
+
+    if((sc->sc_flags & WM_F_EEPROM_SEMAPHORE) == 0)
+	    return;
+
+    swsm = CSR_READ(sc, WMREG_SWSM);
+        swsm &= ~(SWSM_SWESMBI);
+    CSR_WRITE(sc, WMREG_SWSM, swsm);
+}
Index: if_wmreg.h
===================================================================
RCS file: /cvsroot/src/sys/dev/pci/if_wmreg.h,v
retrieving revision 1.14.4.1
diff -u -r1.14.4.1 if_wmreg.h
--- if_wmreg.h	28 Aug 2005 09:49:37 -0000	1.14.4.1
+++ if_wmreg.h	8 May 2006 08:44:22 -0000
@@ -174,6 +174,7 @@
 #define	CTRL_FD		(1U << 0)	/* full duplex */
 #define	CTRL_BEM	(1U << 1)	/* big-endian mode */
 #define	CTRL_PRIOR	(1U << 2)	/* 0 = receive, 1 = fair */
+#define	CTRL_GIO_M_DIS	(1U << 2)	/* 1 = disable master access */
 #define	CTRL_LRST	(1U << 3)	/* link reset */
 #define	CTRL_ASDE	(1U << 5)	/* auto speed detect enable */
 #define	CTRL_SLU	(1U << 6)	/* set link up */
@@ -222,6 +223,7 @@
 #define	STATUS_PCIXSPD_66_100  STATUS_PCIXSPD(1)
 #define	STATUS_PCIXSPD_100_133 STATUS_PCIXSPD(2)
 #define	STATUS_PCIXSPD_MASK    STATUS_PCIXSPD(3)
+#define	STATUS_GIO_MASTER_ENA (1U << 19)	/* PCI-e master enable */
 
 #define	WMREG_EECD	0x0010	/* EEPROM Control Register */
 #define	EECD_SK		(1U << 0)	/* clock */
@@ -236,11 +238,14 @@
 #define	EECD_EE_PRES	(1U << 8)	/* EEPROM present */
 #define	EECD_EE_SIZE	(1U << 9)	/* EEPROM size
 					   (0 = 64 word, 1 = 256 word) */
+#define EECD_EE_AUTORD	(1U << 9)	/* EEPROM Auto Read done */
 #define	EECD_EE_ABITS	(1U << 10)	/* EEPROM address bits
 					   (based on type) */
 #define	EECD_EE_TYPE	(1U << 13)	/* EEPROM type
 					   (0 = Microwire, 1 = SPI) */
 
+#define WMREG_EERD	0x0014
+
 #define	UWIRE_OPC_ERASE	0x04		/* MicroWire "erase" opcode */
 #define	UWIRE_OPC_WRITE	0x05		/* MicroWire "write" opcode */
 #define	UWIRE_OPC_READ	0x06		/* MicroWire "read" opcode */
@@ -545,6 +550,18 @@
 
 #define	WMREG_AIT	0x0458	/* Adaptive IFS Throttle */
 
+#define WMREG_EXTCNF_CTRL  0x0F00  /* Extended Configuration Control */
+
+/* Extended Configuration Control and Size */
+#define EXTCNF_CTRL_PCIE_WRITE_ENABLE 0x00000001
+#define EXTCNF_CTRL_PHY_WRITE_ENABLE  0x00000002
+#define EXTCNF_CTRL_D_UD_ENABLE       0x00000004
+#define EXTCNF_CTRL_D_UD_LATENCY      0x00000008
+#define EXTCNF_CTRL_D_UD_OWNER        0x00000010
+#define EXTCNF_CTRL_MDIO_SW_OWNERSHIP 0x00000020
+#define EXTCNF_CTRL_MDIO_HW_OWNERSHIP 0x00000040
+#define EXTCNF_CTRL_EXT_CNF_POINTER   0x1FFF0000
+
 #define	WMREG_VFTA	0x0600
 
 #define	WM_MC_TABSIZE	128
@@ -560,6 +577,8 @@
 #define	PBA_40K		0x0028
 #define	PBA_48K		0x0030		/* 48K, default Rx allocation */
 
+#define WMREG_EEWR	0x102c
+
 #define	WMREG_TXDMAC	0x3000	/* Transfer DMA Control */
 #define	TXDMAC_DPP	(1U << 0)	/* disable packet prefetch */
 
@@ -578,3 +597,16 @@
 #define	WMREG_XOFFRXC	0x4050	/* XOFF Rx Count - R/clr */
 #define	WMREG_XOFFTXC	0x4054	/* XOFF Tx Count - R/clr */
 #define	WMREG_FCRUC	0x4058	/* Flow Control Rx Unsupported Count - R/clr */
+
+#define WMREG_SWSM      0x5B50 /* SW Semaphore */
+/* SW Semaphore Register */
+#define SWSM_SMBI         0x00000001 /* Driver Semaphore bit */
+#define SWSM_SWESMBI      0x00000002 /* FW Semaphore bit */
+#define SWSM_WMNG         0x00000004 /* Wake MNG Clock */
+#define SWSM_DRV_LOAD     0x00000008 /* Driver Loaded Bit */
+
+#define E1000_EEPROM_RW_REG_DONE   2    /* Offset to READ/WRITE done bit */
+#define E1000_EEPROM_RW_REG_START  1    /* First bit for telling part to start operation */
+#define E1000_EEPROM_RW_ADDR_SHIFT 2    /* Shift to the address bits */
+#define E1000_EEPROM_POLL_READ     0    /* Flag for polling for read complete */
+#define E1000_EEPROM_RW_REG_DATA   16   /* Offset to data in EEPROM read/write registers */
Index: pcidevs
===================================================================
RCS file: /cvsroot/src/sys/dev/pci/pcidevs,v
retrieving revision 1.701.2.28
diff -u -r1.701.2.28 pcidevs
--- pcidevs	8 Apr 2006 23:29:19 -0000	1.701.2.28
+++ pcidevs	8 May 2006 08:44:23 -0000
@@ -1687,11 +1687,13 @@
 product INTEL 82545EM_FIBER	0x1011	i82545EM 1000baseX Ethernet
 product INTEL 82546EB_FIBER	0x1012	i82546EB 1000baseX Ethernet
 product INTEL 82541EI		0x1013	i82541EI Gigabit Ethernet
+product INTEL 82541ER_LOM       0x1014  i82541ER (LOM) Gigabit Ethernet
 product INTEL 82540EM_LOM	0x1015	i82540EM (LOM) Gigabit Ethernet
 product INTEL 82540EP_LOM	0x1016	i82540EP (LOM) Gigabit Ethernet
 product INTEL 82540EP		0x1017	i82540EP Gigabit Ethernet
 product INTEL 82541EI_MOBILE	0x1018	i82541EI Mobile Gigabit Ethernet
 product INTEL 82547EI		0x1019	i82547EI Gigabit Ethernet
+product INTEL 82547EI_MOBILE    0x101a  i82547EI Mobile GigE
 product INTEL 82546EB_QUAD	0x101d	i82546EB 1000baseT Ethernet
 product INTEL 82540EP_LP	0x101e	i82540EP Gigabit Ethernet
 product INTEL 82545GM_COPPER	0x1026	i82545GM 1000baseT Ethernet
@@ -1717,6 +1719,9 @@
 product INTEL PRO_100_VM_6	0x1050	PRO/100 VM Network Controller with 82562ET/EZ PHY
 product INTEL 82801EB_LAN	0x1051	82801EB/ER 10/100 Ethernet
 product INTEL PRO_100_M		0x1059	PRO/100 M Network Controller
+product INTEL 82571EB_COPPER    0x105E  PRO/1000 PT (82571EB)
+product INTEL 82571EB_FIBER     0x105F  PRO/1000 PF (82571EB)
+product INTEL 82571EB_SERDES    0x1060  PRO/1000 PB (82571EB)
 product INTEL 82801FB_LAN	0x1064	82801FB 10/100 Ethernet
 product INTEL 82547GI		0x1075	i82547GI Gigabit Ethernet
 product INTEL 82541GI		0x1076	i82541GI Gigabit Ethernet
@@ -1726,6 +1731,14 @@
 product INTEL 82546GB_FIBER	0x107a	i82546GB 1000baseX Ethernet
 product INTEL 82546GB_SERDES	0x107b	i82546GB Gigabit Ethernet (SERDES)
 product INTEL 82541PI		0x107c  i82541PI Gigabit Ethernet
+product INTEL 82572EI_COPPER	0x107d  i82572EI 1000baseT Ethernet
+product INTEL 82572EI_FIBER	0x107e  i82572EI 1000baseX Ethernet
+product INTEL 82572EI_SERDES	0x107f  i82572EI Gigabit Ethernet (SERDES)
+product INTEL 82546GB_PCIE      0x108A  PRO/1000MT (82546GB)
+product INTEL 82573E		0x108b  i82573E Gigabit Ethernet
+product INTEL 82573E_IAMT	0x108c  i82573E Gigabit Ethernet
+product INTEL 82573L		0x109a  i82573L Gigabit Ethernet
+product INTEL 82546GB_QUAD_COPPER 0x1099  PRO/1000MT QP (82546GB)
 product INTEL 82815_DC100_HUB	0x1100	82815 Hub
 product INTEL 82815_DC100_AGP	0x1101	82815 AGP
 product INTEL 82815_DC100_GRAPH	0x1102	82815 Graphics