Index: dev/pci/if_em.c
===================================================================
RCS file: /u/open/cvs/src/sys/dev/pci/if_em.c,v
retrieving revision 1.7
diff -u -r1.7 if_em.c
--- dev/pci/if_em.c	27 Feb 2003 16:31:09 -0000	1.7
+++ dev/pci/if_em.c	14 Jul 2004 21:32:07 -0000
@@ -1,39 +1,38 @@
 /**************************************************************************
 
-Copyright (c) 2001-2002 Intel Corporation
+Copyright (c) 2001-2003, Intel Corporation
 All rights reserved.
 
-Redistribution and use in source and binary forms of the Software, with or
-without modification, are permitted provided that the following conditions
-are met:
-
- 1. Redistributions of source code of the Software may retain the above
-    copyright notice, this list of conditions and the following disclaimer.
-
- 2. Redistributions in binary form of the Software may reproduce the above
-    copyright notice, this list of conditions and the following disclaimer
-    in the documentation and/or other materials provided with the
-    distribution.
+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 shall be used to endorse or promote products derived from
-    this Software without specific prior written permission.
+    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 INTEL OR ITS 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.
+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.
 
 ***************************************************************************/
 
-/*$FreeBSD$*/
+/*$FreeBSD: if_em.c,v 1.26 2003/06/05 17:51:37 pdeuskar Exp $*/
+/* $OpenBSD: if_em.c,v 1.9 2003/06/13 19:21:21 henric Exp $ */
 
 #include "bpfilter.h"
 #include "vlan.h"
@@ -76,23 +75,29 @@
 
 #include <dev/pci/if_em.h>
 
+#ifdef DEBUG
+#define EM_KASSERT(exp,msg)        do { if (!(exp)) panic msg; } while (0)
+#else
+#define EM_KASSERT(exp,msg)
+#endif
+
 /*********************************************************************
- *  Set this to one to display debug statistics                                                   
+ *  Set this to one to display debug statistics
  *********************************************************************/
 int             em_display_debug_stats = 0;
 
 /*********************************************************************
  *  Linked list of board private structures for all NICs found
  *********************************************************************/
-#if 0
-struct em_softc *em_em_softc_list = NULL;
-#endif
+
+struct em_softc *em_adapter_list = NULL;
+
 
 /*********************************************************************
  *  Driver version
  *********************************************************************/
 
-char em_driver_version[] = "1.3.14";
+char em_driver_version[] = "1.6.6";
 
 
 /*********************************************************************
@@ -105,17 +110,23 @@
 	{ PCI_VENDOR_INTEL, PCI_PRODUCT_INTEL_82544EI },
 	{ PCI_VENDOR_INTEL, PCI_PRODUCT_INTEL_82544EI_SC },
 	{ PCI_VENDOR_INTEL, PCI_PRODUCT_INTEL_82544GC },
-	{ PCI_VENDOR_INTEL, PCI_PRODUCT_INTEL_82544GC_LX },
+	{ PCI_VENDOR_INTEL, PCI_PRODUCT_INTEL_82544GC_LOM },
 	{ PCI_VENDOR_INTEL, PCI_PRODUCT_INTEL_82540EM },
 	{ PCI_VENDOR_INTEL, PCI_PRODUCT_INTEL_82545EM },
 	{ PCI_VENDOR_INTEL, PCI_PRODUCT_INTEL_82546EB },
 	{ PCI_VENDOR_INTEL, PCI_PRODUCT_INTEL_82545EM_SC },
 	{ PCI_VENDOR_INTEL, PCI_PRODUCT_INTEL_82546EB_SC },
-	{ PCI_VENDOR_INTEL, PCI_PRODUCT_INTEL_82545EM_LX },
+	{ PCI_VENDOR_INTEL, PCI_PRODUCT_INTEL_82541EI },
+	{ PCI_VENDOR_INTEL, PCI_PRODUCT_INTEL_82540EM_LOM },
+	{ PCI_VENDOR_INTEL, PCI_PRODUCT_INTEL_82540EP_LOM },
+	{ PCI_VENDOR_INTEL, PCI_PRODUCT_INTEL_82540EP },
+	{ PCI_VENDOR_INTEL, PCI_PRODUCT_INTEL_82541EP },
+	{ PCI_VENDOR_INTEL, PCI_PRODUCT_INTEL_82547EI },
+	{ PCI_VENDOR_INTEL, PCI_PRODUCT_INTEL_82540EP_LP }
 };
 
 /*********************************************************************
- *  Function prototypes            
+ *  Function prototypes
  *********************************************************************/
 int  em_probe(struct device *, void *, void *);
 void em_attach(struct device *, struct device *, void *);
@@ -126,7 +137,7 @@
 #endif
 int  em_intr(void *);
 void em_start(struct ifnet *);
-int  em_ioctl(struct ifnet *, IOCTL_CMD_TYPE, caddr_t);
+int  em_ioctl(struct ifnet *, u_long, caddr_t);
 void em_watchdog(struct ifnet *);
 void em_init(void *);
 void em_stop(void *);
@@ -150,33 +161,36 @@
 void em_clean_transmit_interrupts(struct em_softc *);
 int  em_allocate_receive_structures(struct em_softc *);
 int  em_allocate_transmit_structures(struct em_softc *);
-void em_process_receive_interrupts(struct em_softc *);
+void em_process_receive_interrupts(struct em_softc *, int);
 void em_receive_checksum(struct em_softc *, 
-				     struct em_rx_desc * rx_desc,
+				     struct em_rx_desc *,
 				     struct mbuf *);
-#if 0
 void em_transmit_checksum_setup(struct em_softc *,
 					    struct mbuf *,
-					    struct em_tx_buffer *,
 					    u_int32_t *,
 					    u_int32_t *);
-#endif /* 0 */
 void em_set_promisc(struct em_softc *);
 void em_disable_promisc(struct em_softc *);
 void em_set_multi(struct em_softc *);
 void em_print_hw_stats(struct em_softc *);
 void em_print_link_status(struct em_softc *);
-int  em_get_buf(struct em_rx_buffer *, struct em_softc *,
+int  em_get_buf(int i, struct em_softc *,
 			    struct mbuf *);
-void em_enable_vlans(struct em_softc *em_softc);
-
-
-int em_malloc_dma(struct em_softc *sc, struct em_dmamap *emm,
-			 bus_size_t size);
-void em_free_dma(struct em_softc *sc, struct em_dmamap *emm);
+void em_enable_vlans(struct em_softc *);
+int  em_encap(struct em_softc *, struct mbuf *);
+void em_smartspeed(struct em_softc *);
+int  em_82547_fifo_workaround(struct em_softc *, int);
+void em_82547_update_fifo_head(struct em_softc *, int);
+int  em_82547_tx_fifo_reset(struct em_softc *);
+void em_82547_move_tail(void *);
+int  em_dma_malloc(struct em_softc *, bus_size_t,
+    struct em_dma_alloc *, int);
+void em_dma_free(struct em_softc *, struct em_dma_alloc *);
+void em_print_debug_info(struct em_softc *);
+int  em_is_valid_ether_addr(u_int8_t *);
 
 /*********************************************************************
- *  FreeBSD Device Interface Entry Points                    
+ *  FreeBSD Device Interface Entry Points		     
  *********************************************************************/
 
 struct cfattach em_ca = {
@@ -212,123 +226,183 @@
  *  This routine identifies the type of hardware, allocates all resources 
  *  and initializes the hardware.     
  *  
+ *  return 0 on success, positive on failure
  *********************************************************************/
 
 void 
 em_attach(struct device *parent, struct device *self, void *aux)
 {
-        struct pci_attach_args *pa = aux;
+	struct pci_attach_args *pa = aux;
 #if 0
 	pci_chipset_tag_t pc = pa->pa_pc;
 #endif
 	struct em_softc *sc = (struct em_softc *)self;
-	int             s;
-	int             tsize, rsize;
+	int		s;
+	int		tsize, rsize;
+	int		error = 0;
 
 	INIT_DEBUGOUT("em_attach: begin");
 	s = splimp();
 
+#ifdef __FreeBSD__
+	/* Allocate, clear, and link in our sc structure */
+	if (!(sc = device_get_softc(dev))) {
+		printf("em: sc structure allocation failed\n");
+		splx(s);
+		return(ENOMEM);
+	}
+	bzero(sc, sizeof(struct em_softc ));
+	sc->dev = dev;
+	sc->osdep.dev = dev;
+	sc->sc_dv.dv_xname = device_get_unit(dev);
+#endif /* __FreeBSD__ */
+
 	sc->osdep.em_pa = *pa;
 
-	timeout_set(&sc->em_timeout, em_local_timer, sc);
+	if (em_adapter_list != NULL)
+		em_adapter_list->prev = sc;
+	sc->next = em_adapter_list;
+	em_adapter_list = sc;
+
+#ifdef __FreeBSD__
+	/* SYSCTL stuff */
+	sysctl_ctx_init(&sc->sysctl_ctx);
+	sc->sysctl_tree = SYSCTL_ADD_NODE(&sc->sysctl_ctx,
+					       SYSCTL_STATIC_CHILDREN(_hw),
+					       OID_AUTO,
+					       device_get_nameunit(dev),
+					       CTLFLAG_RD,
+					       0, "");
+	if (sc->sysctl_tree == NULL) {
+		error = EIO;
+		goto err_sysctl;
+	}
+
+	SYSCTL_ADD_PROC(&sc->sysctl_ctx,
+			SYSCTL_CHILDREN(sc->sysctl_tree),
+			OID_AUTO, "debug_info", CTLTYPE_INT|CTLFLAG_RW,
+			(void *)sc, 0,
+			em_sysctl_debug_info, "I", "Debug Information");
+
+	SYSCTL_ADD_PROC(&sc->sysctl_ctx,
+			SYSCTL_CHILDREN(sc->sysctl_tree),
+			OID_AUTO, "stats", CTLTYPE_INT|CTLFLAG_RW,
+			(void *)sc, 0,
+			em_sysctl_stats, "I", "Statistics");
+
+	callout_handle_init(&sc->timer_handle);
+	callout_handle_init(&sc->tx_fifo_timer_handle);
+#endif /* __FreeBSD__ */
+
+	timeout_set(&sc->timer_handle, em_local_timer, sc);
+	timeout_set(&sc->tx_fifo_timer_handle, em_82547_move_tail, sc);
 
 	/* Determine hardware revision */
 	em_identify_hardware(sc);
 
 	/* Parameters (to be read from user) */
-	sc->num_tx_desc = MAX_TXD;
-	sc->num_rx_desc = MAX_RXD;
-	sc->tx_int_delay = TIDV;
-	sc->rx_int_delay = RIDV;
+	sc->num_tx_desc = EM_MAX_TXD;
+	sc->num_rx_desc = EM_MAX_RXD;
+	sc->tx_int_delay = EM_TIDV;
+	sc->tx_abs_int_delay = EM_TADV;
+	sc->rx_int_delay = EM_RDTR;
+	sc->rx_abs_int_delay = EM_RADV;
 	sc->hw.autoneg = DO_AUTO_NEG;
 	sc->hw.wait_autoneg_complete = WAIT_FOR_AUTO_NEG_DEFAULT;
 	sc->hw.autoneg_advertised = AUTONEG_ADV_DEFAULT;
 	sc->hw.tbi_compatibility_en = TRUE;
 	sc->rx_buffer_len = EM_RXBUFFER_2048;
 
+	/*
+	 * These parameters control the automatic generation(Tx) and
+	 * response(Rx) to Ethernet PAUSE frames.
+	 */
 	sc->hw.fc_high_water = FC_DEFAULT_HI_THRESH;
 	sc->hw.fc_low_water  = FC_DEFAULT_LO_THRESH;
 	sc->hw.fc_pause_time = FC_DEFAULT_TX_TIMER;
 	sc->hw.fc_send_xon   = TRUE;
 	sc->hw.fc = em_fc_full;
 
-	/* Set the max frame size assuming standard ethernet sized frames */   
+	sc->hw.phy_init_script = 1;
+
+	/*
+	 * Set the max frame size assuming standard ethernet
+	 * sized frames
+	 */
 	sc->hw.max_frame_size = 
-	ETHERMTU + ETHER_HDR_LEN + ETHER_CRC_LEN;
+	    ETHERMTU + ETHER_HDR_LEN + ETHER_CRC_LEN;
 
 	sc->hw.min_frame_size = 
-	MINIMUM_ETHERNET_PACKET_SIZE + ETHER_CRC_LEN;
+	    MINIMUM_ETHERNET_PACKET_SIZE + ETHER_CRC_LEN;
+
+	/*
+	 * This controls when hardware reports transmit completion
+	 * status.
+	 */
+	sc->hw.report_tx_early = 1;
 
-	/* This controls when hardware reports transmit completion status. */
-	if ((EM_REPORT_TX_EARLY == 0) || (EM_REPORT_TX_EARLY == 1)) {
-		sc->hw.report_tx_early = EM_REPORT_TX_EARLY;
-	} else {
-		if (sc->hw.mac_type < em_82543) {
-			sc->hw.report_tx_early = 0;
-		} else {
-			sc->hw.report_tx_early = 1;
-		}
-	}
 
 	if (em_allocate_pci_resources(sc)) {
 		printf("%s: Allocation of PCI resources failed\n", 
 		       sc->sc_dv.dv_xname);
-		em_free_pci_resources(sc);
-		splx(s);
-		return;
+		error = ENXIO;
+		goto err_pci;
 	}
 
+
+	/* Initialize eeprom parameters */
+	em_init_eeprom_params(&sc->hw);
+
 	tsize = EM_ROUNDUP(sc->num_tx_desc *
 			   sizeof(struct em_tx_desc), 4096);
 
 	/* Allocate Transmit Descriptor ring */
-	if(em_malloc_dma(sc, &sc->osdep.em_tx, tsize)) {
-		printf("%s: Unable to allocate TxDescriptor memory\n", 
+	if (em_dma_malloc(sc, tsize, &sc->txdma, BUS_DMA_NOWAIT)) {
+		printf("%s: Unable to allocate tx_desc memory\n", 
 		       sc->sc_dv.dv_xname);
-		em_free_pci_resources(sc);
-		splx(s);
-		return;
+		error = ENOMEM;
+		goto err_tx_desc;
 	}
-
-	sc->tx_desc_base = (struct em_tx_desc *)sc->osdep.em_tx.emm_kva;
+	sc->tx_desc_base = (struct em_tx_desc *)sc->txdma.dma_vaddr;
 
 	rsize = EM_ROUNDUP(sc->num_rx_desc *
 			   sizeof(struct em_rx_desc), 4096);
 
 	/* Allocate Receive Descriptor ring */
-	if(em_malloc_dma(sc, &sc->osdep.em_rx, rsize)) {
+	if (em_dma_malloc(sc, rsize, &sc->rxdma, BUS_DMA_NOWAIT)) {
 		printf("%s: Unable to allocate rx_desc memory\n", 
 		       sc->sc_dv.dv_xname);
-		em_free_pci_resources(sc);
-		em_free_dma(sc, &sc->osdep.em_tx);
-		splx(s);
-		return;
+		error = ENOMEM;
+		goto err_rx_desc;
 	}
-
-	sc->rx_desc_base = (struct em_rx_desc *)sc->osdep.em_rx.emm_kva;
+	sc->rx_desc_base = (struct em_rx_desc *) sc->rxdma.dma_vaddr;
 
 	/* Initialize the hardware */
 	if (em_hardware_init(sc)) {
 		printf("%s: Unable to initialize the hardware\n",
 		       sc->sc_dv.dv_xname);
-		em_free_pci_resources(sc);
-		em_free_dma(sc, &sc->osdep.em_tx);
-		em_free_dma(sc, &sc->osdep.em_rx);
-		splx(s);
-		return;
+		error = EIO;
+		goto err_hw_init;
 	}
 
 	/* Copy the permanent MAC address out of the EEPROM */
 	if (em_read_mac_addr(&sc->hw) < 0) {
 		printf("%s: EEPROM read error while reading mac address\n",
 		       sc->sc_dv.dv_xname);
-		return;
+		error = EIO;
+		goto err_mac_addr;
+	}
+
+	if (!em_is_valid_ether_addr(sc->hw.mac_addr)) {
+		printf("%s: Invalid mac address\n", sc->sc_dv.dv_xname);
+		error = EIO;
+		goto err_mac_addr;
 	}
 
-	memcpy((char *)&sc->arpcom.ac_enaddr, sc->hw.mac_addr,
-	       ETH_LENGTH_OF_ADDRESS);
+	bcopy(sc->hw.mac_addr, sc->interface_data.ac_enaddr,
+	      ETHER_ADDR_LEN);
 
-	printf(", address: %s\n", ether_sprintf(sc->arpcom.ac_enaddr));
+	printf(", address: %s\n", ether_sprintf(sc->interface_data.ac_enaddr));
 
 	/* Setup OS specific network interface */
 	em_setup_interface(sc);
@@ -347,55 +421,73 @@
 
 	INIT_DEBUGOUT("em_attach: end");
 	splx(s);
+	return;
+
+err_mac_addr:
+err_hw_init:
+	em_dma_free(sc, &sc->rxdma);
+err_rx_desc:
+	em_dma_free(sc, &sc->txdma);
+err_tx_desc:
+err_pci:
+	em_free_pci_resources(sc);
+#ifdef __FreeBSD__
+	sysctl_ctx_free(&sc->sysctl_ctx);
+#endif /* __FreeBSD__ */
+/*err_sysctl:*/
+	splx(s);
+	return;
+
 }
 
 /*********************************************************************
  *  Device removal routine
  *
  *  The detach entry point is called when the driver is being removed.
- *  This routine stops the em_softc and deallocates all the resources
+ *  This routine stops the adapter and deallocates all the resources
  *  that were allocated for driver operation.
  *  
  *  return 0 on success, positive on failure
  *********************************************************************/
-#if 0
+#ifdef __FreeBSD__
 int
 em_detach(void* arg)
 {
 	struct em_softc *sc = arg;
-	struct ifnet   *ifp = &sc->arpcom.ac_if;
-	int             s;
+	struct ifnet   *ifp = &sc->interface_data.ac_if;
+	int		s;
 
 	INIT_DEBUGOUT("em_detach: begin");
 	s = splimp();
 
 	em_stop(sc);
 	em_phy_hw_reset(&sc->hw);
-	if_detach(ifp);
-	ether_ifdetach(ifp);
+#if __FreeBSD_version < 500000
+	ether_ifdetach(&sc->interface_data.ac_if, ETHER_BPF_SUPPORTED);
+#else
+	ether_ifdetach(&sc->interface_data.ac_if);
+#endif
 	em_free_pci_resources(sc);
 
 	/* Free Transmit Descriptor ring */
 	if (sc->tx_desc_base) {
-		em_free_dma(sc, &sc->osdep.em_tx);
+		em_dma_free(sc, &sc->txdma);
 		sc->tx_desc_base = NULL;
 	}
 
 	/* Free Receive Descriptor ring */
 	if (sc->rx_desc_base) {
-		em_free_dma(sc, &sc->osdep.em_rx);
+		em_dma_free(sc, &sc->rxdma);
 		sc->rx_desc_base = NULL;
 	}
 
-#if 0
-	/* Remove from the em_softc list */
-	if (em_em_softc_list == sc)
-		em_em_softc_list = sc->next;
+	/* Remove from the adapter list */
+	if (em_adapter_list == sc)
+		em_adapter_list = sc->next;
 	if (sc->next != NULL)
 		sc->next->prev = sc->prev;
 	if (sc->prev != NULL)
 		sc->prev->next = sc->next;
-#endif /* 0 */
 
 	ifp->if_flags &= ~(IFF_RUNNING | IFF_OACTIVE);
 	ifp->if_timer = 0;
@@ -404,6 +496,12 @@
 	return(0);
 }
 
+/*********************************************************************
+ *
+ *  Shutdown entry point
+ *
+ **********************************************************************/
+
 int
 em_shutdown(void* arg)
 {
@@ -412,7 +510,7 @@
 	return(0);
 }
 
-#endif /* 0 */
+#endif /* __FreeBSD__ */
 
 /*********************************************************************
  *  Transmit entry point
@@ -427,156 +525,38 @@
 void
 em_start(struct ifnet *ifp)
 {
-	int             i, s;
+	int		s;
 	struct mbuf    *m_head;
-	u_int32_t       txd_upper; 
-	u_int32_t       txd_lower;
-	struct em_tx_buffer   *tx_buffer;
-	struct em_tx_desc *current_tx_desc = NULL;
-	struct em_softc * sc = ifp->if_softc;
+	struct em_softc *sc = ifp->if_softc;
 
 	if (!sc->link_active)
 		return;
 
-	s = splimp();      
-
-	for(;;) {
-#if NVLAN > 0
-		struct ifvlan *ifv = NULL;
-#endif
+	s = splimp();	   
 
+	for (;;) {
 		IFQ_POLL(&ifp->if_snd, m_head);
 
 		if (m_head == NULL) break;
 
-		if (sc->num_tx_desc_avail <= TX_CLEANUP_THRESHOLD)
-			em_clean_transmit_interrupts(sc);
-
-		if (sc->num_tx_desc_avail <= TX_CLEANUP_THRESHOLD) {
+		if (em_encap(sc, m_head)) {
 			ifp->if_flags |= IFF_OACTIVE;
-			sc->no_tx_desc_avail++;
 			break;
 		}
 
-		tx_buffer =  SIMPLEQ_FIRST(&sc->free_tx_buffer_list);
-		if (!tx_buffer) {
-			sc->no_tx_buffer_avail1++;
-			/* 
-			 * OK so we should not get here but I've seen
-			 * it so let us try to clean up and then try
-			 * to get a tx_buffer again and only break if
-			 * we still don't get one.
-			 */
-			em_clean_transmit_interrupts(sc);
-			tx_buffer = SIMPLEQ_FIRST(&sc->free_tx_buffer_list);
-			if (!tx_buffer) {
-				ifp->if_flags |= IFF_OACTIVE;
-				sc->no_tx_buffer_avail2++;
-				break;
-			}
-		}
-
 		IFQ_DEQUEUE(&ifp->if_snd, m_head);
 
-		SIMPLEQ_REMOVE_HEAD(&sc->free_tx_buffer_list, tx_buffer,
-				    em_tx_entry);
-
-		tx_buffer->num_tx_desc_used = 0;
-		tx_buffer->m_head = m_head;
-#if 0
-		if (ifp->if_hwassist > 0) {
-			em_transmit_checksum_setup(sc,  m_head, tx_buffer, 
-						   &txd_upper, &txd_lower);
-		} else {
-#endif
-			txd_upper = 0;
-			txd_lower = 0;
-#if 0
-		}
-#endif
-
-#if NVLAN > 0
-		/* Find out if we are in vlan mode */
-		if ((m_head->m_flags & (M_PROTO1|M_PKTHDR)) == 
-		    (M_PROTO1|M_PKTHDR) &&
-		    m_head->m_pkthdr.rcvif != NULL &&
-		    m_head->m_pkthdr.rcvif->if_type == IFT_L2VLAN)
-			ifv = m_head->m_pkthdr.rcvif->if_softc;
-#endif
-
-		if (bus_dmamap_load_mbuf(sc->osdep.em_pa.pa_dmat,
-					 tx_buffer->dmamap,
-					 m_head, BUS_DMA_NOWAIT))
-			return;
-
-		for (i = 0; i < tx_buffer->dmamap->dm_nsegs; i++) {
-			bus_addr_t addr= tx_buffer->dmamap->dm_segs[i].ds_addr;
-			bus_size_t len = tx_buffer->dmamap->dm_segs[i].ds_len;
-
-			current_tx_desc = sc->next_avail_tx_desc;
-			current_tx_desc->buffer_addr = htole64(addr);
-
-			current_tx_desc->lower.data = htole32(txd_lower | len);
-			current_tx_desc->upper.data = htole32(txd_upper);
-
-			if (current_tx_desc == sc->last_tx_desc)
-				sc->next_avail_tx_desc =
-				sc->first_tx_desc;
-			else
-				sc->next_avail_tx_desc++;
-
-			sc->num_tx_desc_avail--;
-			tx_buffer->num_tx_desc_used++;
-		}
-
-		/* Put this tx_buffer at the end in the "in use" list */
-		SIMPLEQ_INSERT_TAIL(&sc->used_tx_buffer_list, tx_buffer, 
-				   em_tx_entry);
-
-#if NVLAN > 0
-		if (ifv != NULL) {
-			/* Tell hardware to add tag */
-			current_tx_desc->lower.data |=
-				htole32(E1000_TXD_CMD_VLE);
-
-			/* Set the vlan id */
-			current_tx_desc->upper.fields.special =
-				htole16(ifv->ifv_tag);
-		}
-#endif
-
-		/* 
-		 * Last Descriptor of Packet needs End Of Packet
-		 * (EOP), Report Status (RS) and append Ethernet CRC
-		 * (IFCS) bits set.
-		 */
-		current_tx_desc->lower.data |=
-			htole32(sc->txd_cmd|E1000_TXD_CMD_EOP);
-
 #if NBPFILTER > 0
-		/*
-		 * If there's a BPF listener, bounce a copy of this frame
-		 * to him.
-		 */
+		/* Send a copy of the frame to the BPF listener */
 		if (ifp->if_bpf)
 			bpf_mtap(ifp->if_bpf, m_head);
 #endif
 
-		/* 
-		 * Advance the Transmit Descriptor Tail (Tdt), this
-		 * tells the E1000 that this frame is available to
-		 * transmit.
-		 */
-		E1000_WRITE_REG(&sc->hw, TDT, 
-				(((_BSD_PTRDIFF_T_) sc->next_avail_tx_desc -
-				  (_BSD_PTRDIFF_T_) sc->first_tx_desc) >> 4));
-	} /* end of while loop */
+		/* Set timeout in case hardware has problems transmitting */
+		ifp->if_timer = EM_TX_TIMEOUT;
 
+	}	
 	splx(s);
-
-	/* Set timeout in case chip has problems transmitting */
-	ifp->if_timer = EM_TX_TIMEOUT;
-
 	return;
 }
 
@@ -590,36 +570,41 @@
  **********************************************************************/
 
 int
-em_ioctl(struct ifnet *ifp, IOCTL_CMD_TYPE command, caddr_t data)
+em_ioctl(struct ifnet *ifp, u_long command, caddr_t data)
 {
-	int             s, error = 0;
+	int		s, error = 0;
 	struct ifreq   *ifr = (struct ifreq *) data;
 	struct ifaddr  *ifa = (struct ifaddr *)data;
 	struct em_softc * sc = ifp->if_softc;
 
 	s = splimp();
 
-        if ((error = ether_ioctl(ifp, &sc->arpcom, command, data)) > 0) {
-                splx(s);
-                return (error);
-        }
+	if ((error = ether_ioctl(ifp, &sc->interface_data, command, data)) > 0) {
+		splx(s);
+		return (error);
+	}
 
 	switch (command) {
 	case SIOCSIFADDR:
+#ifdef __FreeBSD__
+	case SIOCGIFADDR:
+		IOCTL_DEBUGOUT("ioctl rcv'd: SIOCxIFADDR (Get/Set Interface Addr)");
+		ether_ioctl(ifp, command, data);
+		break;
+#endif /* __FreeBSD__ */
 		IOCTL_DEBUGOUT("ioctl rcv'd: SIOCSIFADDR (Set Interface "
 			       "Addr)");
 		ifp->if_flags |= IFF_UP;
-                switch (ifa->ifa_addr->sa_family) {
+		em_init(sc);
+		switch (ifa->ifa_addr->sa_family) {
 #ifdef INET
-                case AF_INET:
-                        em_init(sc);
-                        arp_ifinit(&sc->arpcom, ifa);
-                        break;
+		case AF_INET:
+			arp_ifinit(&sc->interface_data, ifa);
+			break;
 #endif /* INET */
-                default:
-                        em_init(sc);
-                        break;
-                }
+		default:
+			break;
+		}
 		break;
 	case SIOCSIFMTU:
 		IOCTL_DEBUGOUT("ioctl rcv'd: SIOCSIFMTU (Set Interface MTU)");
@@ -633,17 +618,13 @@
 		}
 		break;
 	case SIOCSIFFLAGS:
-		IOCTL_DEBUGOUT("ioctl rcv'd: SIOCSIFFLAGS (Set Interface "
-			       "Flags)");
+		IOCTL_DEBUGOUT("ioctl rcv'd: SIOCSIFFLAGS (Set Interface Flags)");
 		if (ifp->if_flags & IFF_UP) {
-			if (ifp->if_flags & IFF_RUNNING &&
-			    ifp->if_flags & IFF_PROMISC) {
-				em_set_promisc(sc);
-			} else if (ifp->if_flags & IFF_RUNNING &&
-				   !(ifp->if_flags & IFF_PROMISC)) {
-				em_disable_promisc(sc);
-			} else
+			if (!(ifp->if_flags & IFF_RUNNING))
 				em_init(sc);
+
+			em_disable_promisc(sc);
+			em_set_promisc(sc);
 		} else {
 			if (ifp->if_flags & IFF_RUNNING) {
 				em_stop(sc);
@@ -653,38 +634,31 @@
 	case SIOCADDMULTI:
 	case SIOCDELMULTI:
 		IOCTL_DEBUGOUT("ioctl rcv'd: SIOC(ADD|DEL)MULTI");
-#if 0
-		if (ifp->if_flags & IFF_RUNNING) {
-			em_disable_intr(sc);
-			em_set_multi(sc);
-			if (sc->hw.mac_type == em_82542_rev2_0)
-				em_initialize_receive_unit(sc);
-			em_enable_intr(sc);
-		}
-		break;
-#endif /* 0 */
-                error = (command == SIOCADDMULTI)
-                        ? ether_addmulti(ifr, &sc->arpcom)
-                        : ether_delmulti(ifr, &sc->arpcom);
+		error = (command == SIOCADDMULTI)
+			? ether_addmulti(ifr, &sc->interface_data)
+			: ether_delmulti(ifr, &sc->interface_data);
 
-                if (error == ENETRESET) {
-                        if (ifp->if_flags & IFF_RUNNING) {
+		if (error == ENETRESET) {
+			if (ifp->if_flags & IFF_RUNNING) {
 				em_disable_intr(sc);
 				em_set_multi(sc);
-				if (sc->hw.mac_type == em_82542_rev2_0)
+				if (sc->hw.mac_type == em_82542_rev2_0) {
 					em_initialize_receive_unit(sc);
-				em_enable_intr(sc);
+				}
+#ifdef DEVICE_POLLING
+				if (!(ifp->if_ipending & IFF_POLLING))
+#endif
+					em_enable_intr(sc);
 			}
-                        error = 0;
-                }
+			error = 0;
+		}
 		break;
 	case SIOCSIFMEDIA:
 	case SIOCGIFMEDIA:
-		IOCTL_DEBUGOUT("ioctl rcv'd: SIOCxIFMEDIA (Get/Set Interface "
-			       "Media)");
+		IOCTL_DEBUGOUT("ioctl rcv'd: SIOCxIFMEDIA (Get/Set Interface Media)");
 		error = ifmedia_ioctl(ifp, ifr, &sc->media, command);
 		break;
-#if 0
+#ifdef __FreeBSD__
 	case SIOCSIFCAP:
 		IOCTL_DEBUGOUT("ioctl rcv'd: SIOCSIFCAP (Set Capabilities)");
 		mask = ifr->ifr_reqcap ^ ifp->if_capenable;
@@ -697,10 +671,9 @@
 				em_init(sc);
 		}
 		break;
-#endif /* 0 */
+#endif /* __FreeBSD__ */
 	default:
-		IOCTL_DEBUGOUT1("ioctl received: UNKNOWN (0x%d)\n",
-				(int)command);
+		IOCTL_DEBUGOUT1("ioctl received: UNKNOWN (0x%d)\n", (int)command);
 		error = EINVAL;
 	}
 
@@ -708,116 +681,6 @@
 	return(error);
 }
 
-void
-em_set_promisc(struct em_softc * sc)
-{
-
-	u_int32_t       reg_rctl;
-	struct ifnet   *ifp = &sc->arpcom.ac_if;
-
-	reg_rctl = E1000_READ_REG(&sc->hw, RCTL);
-
-	if (ifp->if_flags & IFF_PROMISC) {
-		reg_rctl |= (E1000_RCTL_UPE | E1000_RCTL_MPE);
-		E1000_WRITE_REG(&sc->hw, RCTL, reg_rctl);
-	} else if (ifp->if_flags & IFF_ALLMULTI) {
-		reg_rctl |= E1000_RCTL_MPE;
-		reg_rctl &= ~E1000_RCTL_UPE;
-		E1000_WRITE_REG(&sc->hw, RCTL, reg_rctl);
-	}
-
-	return;
-}
-
-void
-em_disable_promisc(struct em_softc * sc)
-{
-	u_int32_t       reg_rctl;
-
-	reg_rctl = E1000_READ_REG(&sc->hw, RCTL);
-
-	reg_rctl &=  (~E1000_RCTL_UPE);
-	reg_rctl &=  (~E1000_RCTL_MPE);
-	E1000_WRITE_REG(&sc->hw, RCTL, reg_rctl);
-
-	return;
-}
-
-
-/*********************************************************************
- *  Multicast Update
- *
- *  This routine is called whenever multicast address list is updated.
- *
- **********************************************************************/
-
-void
-em_set_multi(struct em_softc * sc)
-{
-	u_int32_t reg_rctl = 0;
-	u_int8_t  mta[MAX_NUM_MULTICAST_ADDRESSES * ETH_LENGTH_OF_ADDRESS];
-	u_int16_t pci_cmd_word;
-#if 0
-	struct ifmultiaddr  *ifma;
-#endif
-	int mcnt = 0;
-        struct pci_attach_args *pa = &sc->osdep.em_pa;
-#if 0
-	struct ifnet   *ifp = &sc->arpcom.ac_if;
-#endif
-
-	IOCTL_DEBUGOUT("em_set_multi: begin");
-
-	if (sc->hw.mac_type == em_82542_rev2_0) {
-		reg_rctl = E1000_READ_REG(&sc->hw, RCTL);
-		if (sc->hw.pci_cmd_word & CMD_MEM_WRT_INVALIDATE) {
-			pci_cmd_word = sc->hw.pci_cmd_word & 
-				       ~CMD_MEM_WRT_INVALIDATE;
-			pci_conf_write(pa->pa_pc, pa->pa_tag,
-				       PCI_COMMAND_STATUS_REG, pci_cmd_word);
-		}
-		reg_rctl |= E1000_RCTL_RST;
-		E1000_WRITE_REG(&sc->hw, RCTL, reg_rctl);
-		msec_delay(5);
-	}
-
-#if 0
-#if __FreeBSD_version < 500000 
-	LIST_FOREACH(ifma, &ifp->if_multiaddrs, ifma_link) {
-#else
-	TAILQ_FOREACH(ifma, &ifp->if_multiaddrs, ifma_link) {
-#endif
-		if (ifma->ifma_addr->sa_family != AF_LINK)
-			continue;
-
-		bcopy(LLADDR((struct sockaddr_dl *)ifma->ifma_addr),
-		      &mta[mcnt*ETH_LENGTH_OF_ADDRESS], ETH_LENGTH_OF_ADDRESS);
-		mcnt++;
-	}
-#endif /* 0 */
-
-	if (mcnt > MAX_NUM_MULTICAST_ADDRESSES) {
-		reg_rctl = E1000_READ_REG(&sc->hw, RCTL);
-		reg_rctl |= E1000_RCTL_MPE;
-		E1000_WRITE_REG(&sc->hw, RCTL, reg_rctl);
-	} else
-		em_mc_addr_list_update(&sc->hw, mta, mcnt, 0);
-
-	if (sc->hw.mac_type == em_82542_rev2_0) {
-		reg_rctl = E1000_READ_REG(&sc->hw, RCTL);
-		reg_rctl &= ~E1000_RCTL_RST;
-		E1000_WRITE_REG(&sc->hw, RCTL, reg_rctl);
-		msec_delay(5);
-		if (sc->hw.pci_cmd_word & CMD_MEM_WRT_INVALIDATE) {
-			pci_conf_write(pa->pa_pc, pa->pa_tag,
-				       PCI_COMMAND_STATUS_REG, 
-				       sc->hw.pci_cmd_word);
-		}
-	}
-
-	return;
-}
-
 /*********************************************************************
  *  Watchdog entry point
  *
@@ -851,85 +714,35 @@
 }
 
 /*********************************************************************
- *  Timer routine
+ *  Init entry point
  *
- *  This routine checks for link status and updates statistics.
+ *  This routine is used in two ways. It is used by the stack as
+ *  init entry point in network interface structure. It is also used
+ *  by the driver as a hw/sw initialization routine to get to a 
+ *  consistent state.
  *
+ *  return 0 on success, positive on failure
  **********************************************************************/
 
 void
-em_local_timer(void *arg)
+em_init(void *arg)
 {
-	int s;
+	int		s;
 	struct ifnet   *ifp;
 	struct em_softc * sc = arg;
-	ifp = &sc->arpcom.ac_if;
 
-	s = splimp();
+	INIT_DEBUGOUT("em_init: begin");
 
-	em_check_for_link(&sc->hw);
-	em_print_link_status(sc);
-	em_update_stats_counters(sc);   
-	if (em_display_debug_stats && ifp->if_flags & IFF_RUNNING) {
-		em_print_hw_stats(sc);
-	}
-	timeout_add(&sc->em_timeout, 2*hz);
+	s = splimp();
 
-	splx(s);
-	return;
-}
+	em_stop(sc);
 
-void
-em_print_link_status(struct em_softc * sc)
-{
-	if (E1000_READ_REG(&sc->hw, STATUS) & E1000_STATUS_LU) {
-		if (sc->link_active == 0) {
-			em_get_speed_and_duplex(&sc->hw, 
-						&sc->link_speed, 
-						&sc->link_duplex);
-			sc->link_active = 1;
-		}
-	} else {
-		if (sc->link_active == 1) {
-			sc->link_speed = 0;
-			sc->link_duplex = 0;
-			sc->link_active = 0;
-		}
-	}
-
-	return;
-}
-
-/*********************************************************************
- *  Init entry point
- *
- *  This routine is used in two ways. It is used by the stack as
- *  init entry point in network interface structure. It is also used
- *  by the driver as a hw/sw initialization routine to get to a 
- *  consistent state.
- *
- *  return 0 on success, positive on failure
- **********************************************************************/
-
-void
-em_init(void *arg)
-{
-	int             s;
-	struct ifnet   *ifp;
-	struct em_softc * sc= arg;
-
-	INIT_DEBUGOUT("em_init: begin");
-
-	s = splimp();
-
-	em_stop(sc);
-
-	/* Initialize the hardware */
-	if (em_hardware_init(sc)) {
-		printf("%s: Unable to initialize the hardware\n", 
-		       sc->sc_dv.dv_xname);
-		splx(s);
-		return;
+	/* Initialize the hardware */
+	if (em_hardware_init(sc)) {
+		printf("%s: Unable to initialize the hardware\n", 
+		       sc->sc_dv.dv_xname);
+		splx(s);
+		return;
 	}
 
 	em_enable_vlans(sc);
@@ -957,101 +770,125 @@
 	}
 	em_initialize_receive_unit(sc);
 
-	ifp = &sc->arpcom.ac_if;
+	ifp = &sc->interface_data.ac_if;
 	ifp->if_flags |= IFF_RUNNING;
 	ifp->if_flags &= ~IFF_OACTIVE;
 
-#if 0
+#ifdef __FreeBSD__
 	if (sc->hw.mac_type >= em_82543) {
 		if (ifp->if_capenable & IFCAP_TXCSUM)
 			ifp->if_hwassist = EM_CHECKSUM_FEATURES;
 		else
 			ifp->if_hwassist = 0;
 	}
-#endif /* 0 */
+#endif /* __FreeBSD__ */
 
-	timeout_add(&sc->em_timeout, 2*hz);
+	timeout_add(&sc->timer_handle, 2*hz);
 	em_clear_hw_cntrs(&sc->hw);
-	em_enable_intr(sc);
+#ifdef DEVICE_POLLING
+        /*
+         * Only enable interrupts if we are not polling, make sure
+         * they are off otherwise.
+         */
+        if (ifp->if_ipending & IFF_POLLING)
+                em_disable_intr(sc);
+        else
+#endif /* DEVICE_POLLING */
+		em_enable_intr(sc);
 
 	splx(s);
 	return;
 }
 
 
-/*********************************************************************
- *
- *  This routine disables all traffic on the em_softc by issuing a
- *  global reset on the MAC and deallocates TX/RX buffers. 
- *
- **********************************************************************/
+#ifdef DEVICE_POLLING
+static poll_handler_t em_poll;
 
-void
-em_stop(void *arg)
+static void
+em_poll(struct ifnet *ifp, enum poll_cmd cmd, int count)
 {
-	struct ifnet   *ifp;
-	struct em_softc * sc = arg;
-	ifp = &sc->arpcom.ac_if;
+	struct em_softc *sc = ifp->if_softc;
+	u_int32_t reg_icr;
 
-	INIT_DEBUGOUT("em_stop: begin\n");
-	em_disable_intr(sc);
-	em_reset_hw(&sc->hw);
-	timeout_del(&sc->em_timeout);
-	em_free_transmit_structures(sc);
-	em_free_receive_structures(sc);
-
-
-	/* Tell the stack that the interface is no longer active */
-	ifp->if_flags &= ~(IFF_RUNNING | IFF_OACTIVE);
+	if (cmd == POLL_DEREGISTER) {	    /* final call, enable interrupts */
+		em_enable_intr(sc);
+		return;
+	}
+	if (cmd == POLL_AND_CHECK_STATUS) {
+		reg_icr = E1000_READ_REG(&sc->hw, ICR);
+		if (reg_icr & (E1000_ICR_RXSEQ | E1000_ICR_LSC)) {
+			untimeout(em_local_timer, sc, sc->timer_handle);
+			sc->hw.get_link_status = 1;
+			em_check_for_link(&sc->hw);
+			em_print_link_status(sc);
+			sc->timer_handle = timeout(em_local_timer, sc, 2*hz);
+		}
+	}
+	if (ifp->if_flags & IFF_RUNNING) {
+		em_process_receive_interrupts(sc, count);
+		em_clean_transmit_interrupts(sc);
+	}
 
-	return;
+	if (ifp->if_flags & IFF_RUNNING && ifp->if_snd.ifq_head != NULL)
+		em_start(ifp);
 }
+#endif /* DEVICE_POLLING */
 
 /*********************************************************************
  *
  *  Interrupt Service routine
  *
  **********************************************************************/
-
 int 
 em_intr(void *arg)
 {
-	u_int32_t       loop_cnt = EM_MAX_INTR;
-	u_int32_t       reg_icr;
-	struct ifnet    *ifp;
-	struct em_softc *sc= arg;
+	u_int32_t	loop_cnt = EM_MAX_INTR;
+	u_int32_t	reg_icr;
+	struct ifnet	*ifp;
+	struct em_softc *sc = arg;
 
-	ifp = &sc->arpcom.ac_if;
+	ifp = &sc->interface_data.ac_if;
 
-	em_disable_intr(sc);
-	while (loop_cnt > 0 && 
-	       (reg_icr = E1000_READ_REG(&sc->hw, ICR)) != 0) {
+#ifdef DEVICE_POLLING
+	if (ifp->if_ipending & IFF_POLLING)
+		return;
 
-		/* Link status change */
-		if (reg_icr & (E1000_ICR_RXSEQ | E1000_ICR_LSC)) {
-			timeout_del(&sc->em_timeout);
-			sc->hw.get_link_status = 1;
-			em_check_for_link(&sc->hw);
-			em_print_link_status(sc);
-			timeout_add(&sc->em_timeout, 2*hz); 
-		}
+	if (ether_poll_register(em_poll, ifp)) {
+		em_disable_intr(sc);
+		em_poll(ifp, 0, 1);
+		return;
+	}
+#endif /* DEVICE_POLLING */
+	reg_icr = E1000_READ_REG(&sc->hw, ICR);
+	if (!reg_icr) {
+		return (0);
+	}
+
+	/* Link status change */
+	if (reg_icr & (E1000_ICR_RXSEQ | E1000_ICR_LSC)) {
+		timeout_del(&sc->timer_handle);
+		sc->hw.get_link_status = 1;
+		em_check_for_link(&sc->hw);
+		em_print_link_status(sc);
+		timeout_add(&sc->timer_handle, 2*hz); 
+	}
 
+	while (loop_cnt > 0) {
 		if (ifp->if_flags & IFF_RUNNING) {
-			em_process_receive_interrupts(sc);
+			em_process_receive_interrupts(sc, -1);
 			em_clean_transmit_interrupts(sc);
 		}
 		loop_cnt--;
 	}
 
-	em_enable_intr(sc);
-
 	if (ifp->if_flags & IFF_RUNNING && IFQ_IS_EMPTY(&ifp->if_snd) == 0)
 		em_start(ifp);
 
-	return (EM_MAX_INTR != loop_cnt);
+	return (1);
 }
 
 
+
 /*********************************************************************
  *
  *  Media Ioctl callback
@@ -1125,7 +962,7 @@
 em_media_change(struct ifnet *ifp)
 {
 	struct em_softc * sc = ifp->if_softc;
-	struct ifmedia  *ifm = &sc->media;
+	struct ifmedia	*ifm = &sc->media;
 
 	INIT_DEBUGOUT("em_media_change: begin");
 
@@ -1166,7 +1003,466 @@
 
 	return(0);
 }
-/* Section end: Other registered entry points */
+
+#ifdef __FreeBSD__
+void
+em_tx_cb(void *arg, bus_dma_segment_t *seg, int nsegs, bus_size_t mapsize, int error)
+{
+	struct em_q *q = arg;
+
+	if (error)
+		return;
+	EM_KASSERT(nsegs <= EM_MAX_SCATTER,
+		("Too many DMA segments returned when mapping tx packet"));
+	q->nsegs = nsegs;
+	bcopy(seg, q->segs, nsegs * sizeof(seg[0]));
+}
+#endif /* __FreeBSD__ */
+
+#define EM_FIFO_HDR		 0x10
+#define EM_82547_PKT_THRESH	 0x3e0
+#define EM_82547_TX_FIFO_SIZE	 0x2800
+#define EM_82547_TX_FIFO_BEGIN	 0xf00
+/*********************************************************************
+ *
+ *  This routine maps the mbufs to tx descriptors.
+ *
+ *  return 0 on success, positive on failure
+ **********************************************************************/
+int
+em_encap(struct em_softc *sc, struct mbuf *m_head)
+{
+	u_int32_t	txd_upper;
+	u_int32_t	txd_lower;
+	int		i, j, error;
+#if NVLAN > 0
+	struct ifvlan *ifv = NULL;
+#endif
+	struct em_q	q;
+
+	struct em_buffer   *tx_buffer = NULL;
+	struct em_tx_desc *current_tx_desc = NULL;
+	/*struct ifnet	 *ifp = &sc->interface_data.ac_if;*/
+
+	/*
+	 * Force a cleanup if number of TX descriptors
+	 * available hits the threshold
+	 */
+	if (sc->num_tx_desc_avail <= EM_TX_CLEANUP_THRESHOLD) {
+		em_clean_transmit_interrupts(sc);
+		if (sc->num_tx_desc_avail <= EM_TX_CLEANUP_THRESHOLD) {
+			sc->no_tx_desc_avail1++;
+			return (ENOBUFS);
+		}
+	}
+
+	/*
+	 * Map the packet for DMA.
+	 */
+	if (bus_dmamap_create(sc->txtag, MCLBYTES, 32, 0, 0, BUS_DMA_NOWAIT,
+	    &q.map)) {
+		sc->no_tx_map_avail++;
+		return (ENOMEM);
+	}
+	error = bus_dmamap_load_mbuf(sc->txtag, q.map,
+				     m_head, BUS_DMA_NOWAIT);
+	if (error != 0) {
+		sc->no_tx_dma_setup++;
+		bus_dmamap_destroy(sc->txtag, q.map);
+		return (error);
+	}
+	EM_KASSERT(q.map->dm_nsegs!= 0, ("em_encap: empty packet"));
+
+	if (q.map->dm_nsegs > sc->num_tx_desc_avail) {
+		sc->no_tx_desc_avail2++;
+		bus_dmamap_destroy(sc->txtag, q.map);
+		return (ENOBUFS);
+	}
+
+
+#ifdef __FreeBSD__
+	if (ifp->if_hwassist > 0) {
+		em_transmit_checksum_setup(sc,	m_head,
+					   &txd_upper, &txd_lower);
+	} else
+#endif /* __FreeBSD__ */
+		txd_upper = txd_lower = 0;
+
+
+	/* Find out if we are in vlan mode */
+#if NVLAN > 0
+	if ((m_head->m_flags & (M_PROTO1|M_PKTHDR)) == (M_PROTO1|M_PKTHDR) &&
+	    m_head->m_pkthdr.rcvif != NULL &&
+	    m_head->m_pkthdr.rcvif->if_type == IFT_L2VLAN)
+		ifv = m_head->m_pkthdr.rcvif->if_softc;
+#endif
+
+	i = sc->next_avail_tx_desc;
+	for (j = 0; j < q.map->dm_nsegs; j++) {
+		tx_buffer = &sc->tx_buffer_area[i];
+		current_tx_desc = &sc->tx_desc_base[i];
+
+		current_tx_desc->buffer_addr = htole64(q.map->dm_segs[j].ds_addr);
+		current_tx_desc->lower.data = htole32(
+		    sc->txd_cmd | txd_lower | q.map->dm_segs[j].ds_len);
+		current_tx_desc->upper.data = htole32(txd_upper);
+
+		if (++i == sc->num_tx_desc)
+			i = 0;
+		
+		tx_buffer->m_head = NULL;
+	}
+
+	sc->num_tx_desc_avail -= q.map->dm_nsegs;
+	sc->next_avail_tx_desc = i;
+
+#if NVLAN > 0
+	if (ifv != NULL) {
+		/* Set the vlan id */
+		current_tx_desc->upper.fields.special = htole16(ifv->ifv_tag);
+
+		/* Tell hardware to add tag */
+		current_tx_desc->lower.data |= htole32(E1000_TXD_CMD_VLE);
+	}
+#endif
+
+	tx_buffer->m_head = m_head;
+	tx_buffer->map = q.map;
+	bus_dmamap_sync(sc->txtag, q.map, 0, q.map->dm_mapsize,
+	    BUS_DMASYNC_PREWRITE);
+
+	/* 
+	 * Last Descriptor of Packet needs End Of Packet (EOP) 
+	 */
+	current_tx_desc->lower.data |= htole32(E1000_TXD_CMD_EOP);
+
+	/* 
+	 * Advance the Transmit Descriptor Tail (Tdt), this tells the E1000
+	 * that this frame is available to transmit.
+	 */
+	if (sc->hw.mac_type == em_82547 &&
+	    sc->link_duplex == HALF_DUPLEX) {
+		em_82547_move_tail(sc);
+	} else {
+		E1000_WRITE_REG(&sc->hw, TDT, i);
+		if (sc->hw.mac_type == em_82547) {
+			em_82547_update_fifo_head(sc, m_head->m_pkthdr.len);
+		}
+	}
+
+	return (0);
+}
+
+/*********************************************************************
+ *
+ * 82547 workaround to avoid controller hang in half-duplex environment.
+ * The workaround is to avoid queuing a large packet that would span
+ * the internal Tx FIFO ring boundary. We need to reset the FIFO pointers
+ * in this case. We do that only when FIFO is queiced.
+ *
+ **********************************************************************/
+void
+em_82547_move_tail(void *arg)
+{
+	int s;
+	struct em_softc *sc = arg;
+	uint16_t hw_tdt;
+	uint16_t sw_tdt;
+	struct em_tx_desc *tx_desc;
+	uint16_t length = 0;
+	boolean_t eop = 0;
+
+	s = splimp();
+	hw_tdt = E1000_READ_REG(&sc->hw, TDT);
+	sw_tdt = sc->next_avail_tx_desc;
+
+	while (hw_tdt != sw_tdt) {
+		tx_desc = &sc->tx_desc_base[hw_tdt];
+		length += tx_desc->lower.flags.length;
+		eop = tx_desc->lower.data & E1000_TXD_CMD_EOP;
+		if(++hw_tdt == sc->num_tx_desc)
+			hw_tdt = 0;
+
+		if(eop) {
+			if (em_82547_fifo_workaround(sc, length)) {
+				sc->tx_fifo_wrk++;
+				timeout_add(&sc->tx_fifo_timer_handle, 1);
+				splx(s);
+				return;
+			}
+			else {
+				E1000_WRITE_REG(&sc->hw, TDT, hw_tdt);
+				em_82547_update_fifo_head(sc, length);
+				length = 0;
+			}
+		}
+	}
+	splx(s);
+	return;
+}
+
+int
+em_82547_fifo_workaround(struct em_softc *sc, int len)
+{
+	int fifo_space, fifo_pkt_len;
+
+	fifo_pkt_len = EM_ROUNDUP(len + EM_FIFO_HDR, EM_FIFO_HDR);
+
+	if (sc->link_duplex == HALF_DUPLEX) {
+		fifo_space = EM_82547_TX_FIFO_SIZE - sc->tx_fifo_head;
+
+		if (fifo_pkt_len >= (EM_82547_PKT_THRESH + fifo_space)) {
+			if (em_82547_tx_fifo_reset(sc)) {
+				return(0);
+			}
+			else {
+				return(1);
+			}
+		}
+	}
+
+	return(0);
+}
+
+void
+em_82547_update_fifo_head(struct em_softc *sc, int len)
+{
+	int fifo_pkt_len = EM_ROUNDUP(len + EM_FIFO_HDR, EM_FIFO_HDR);
+
+	/* tx_fifo_head is always 16 byte aligned */
+	sc->tx_fifo_head += fifo_pkt_len;
+	if (sc->tx_fifo_head >= EM_82547_TX_FIFO_SIZE) {
+		sc->tx_fifo_head -= EM_82547_TX_FIFO_SIZE;
+	}
+
+	return;
+}
+
+
+int
+em_82547_tx_fifo_reset(struct em_softc *sc)
+{
+	uint32_t tctl;
+
+	if ( (E1000_READ_REG(&sc->hw, TDT) ==
+	      E1000_READ_REG(&sc->hw, TDH)) &&
+	     (E1000_READ_REG(&sc->hw, TDFT) ==
+	      E1000_READ_REG(&sc->hw, TDFH)) &&
+	     (E1000_READ_REG(&sc->hw, TDFTS) ==
+	      E1000_READ_REG(&sc->hw, TDFHS)) &&
+	     (E1000_READ_REG(&sc->hw, TDFPC) == 0)) {
+
+		/* Disable TX unit */
+		tctl = E1000_READ_REG(&sc->hw, TCTL);
+		E1000_WRITE_REG(&sc->hw, TCTL, tctl & ~E1000_TCTL_EN);
+
+		/* Reset FIFO pointers */
+		E1000_WRITE_REG(&sc->hw, TDFT, EM_82547_TX_FIFO_BEGIN);
+		E1000_WRITE_REG(&sc->hw, TDFH, EM_82547_TX_FIFO_BEGIN);
+		E1000_WRITE_REG(&sc->hw, TDFTS, EM_82547_TX_FIFO_BEGIN);
+		E1000_WRITE_REG(&sc->hw, TDFHS, EM_82547_TX_FIFO_BEGIN);
+
+		/* Re-enable TX unit */
+		E1000_WRITE_REG(&sc->hw, TCTL, tctl);
+		E1000_WRITE_FLUSH(&sc->hw);
+
+		sc->tx_fifo_head = 0;
+		sc->tx_fifo_reset++;
+
+		return(TRUE);
+	}
+	else {
+		return(FALSE);
+	}
+}
+
+void
+em_set_promisc(struct em_softc * sc)
+{
+
+	u_int32_t	reg_rctl;
+	struct ifnet   *ifp = &sc->interface_data.ac_if;
+
+	reg_rctl = E1000_READ_REG(&sc->hw, RCTL);
+
+	if (ifp->if_flags & IFF_PROMISC) {
+		reg_rctl |= (E1000_RCTL_UPE | E1000_RCTL_MPE);
+		E1000_WRITE_REG(&sc->hw, RCTL, reg_rctl);
+	} else if (ifp->if_flags & IFF_ALLMULTI) {
+		reg_rctl |= E1000_RCTL_MPE;
+		reg_rctl &= ~E1000_RCTL_UPE;
+		E1000_WRITE_REG(&sc->hw, RCTL, reg_rctl);
+	}
+
+	return;
+}
+
+void
+em_disable_promisc(struct em_softc * sc)
+{
+	u_int32_t	reg_rctl;
+
+	reg_rctl = E1000_READ_REG(&sc->hw, RCTL);
+
+	reg_rctl &=  (~E1000_RCTL_UPE);
+	reg_rctl &=  (~E1000_RCTL_MPE);
+	E1000_WRITE_REG(&sc->hw, RCTL, reg_rctl);
+
+	return;
+}
+
+
+/*********************************************************************
+ *  Multicast Update
+ *
+ *  This routine is called whenever multicast address list is updated.
+ *
+ **********************************************************************/
+
+void
+em_set_multi(struct em_softc * sc)
+{
+	u_int32_t reg_rctl = 0;
+	u_int8_t  mta[MAX_NUM_MULTICAST_ADDRESSES * ETH_LENGTH_OF_ADDRESS];
+#ifdef __FreeBSD__
+	struct ifmultiaddr  *ifma;
+#endif
+	int mcnt = 0;
+#ifdef __FreeBSD__
+	struct ifnet   *ifp = &sc->interface_data.ac_if;
+#endif
+
+	IOCTL_DEBUGOUT("em_set_multi: begin");
+
+	if (sc->hw.mac_type == em_82542_rev2_0) {
+		reg_rctl = E1000_READ_REG(&sc->hw, RCTL);
+		if (sc->hw.pci_cmd_word & CMD_MEM_WRT_INVALIDATE) {
+			em_pci_clear_mwi(&sc->hw);
+		}
+		reg_rctl |= E1000_RCTL_RST;
+		E1000_WRITE_REG(&sc->hw, RCTL, reg_rctl);
+		msec_delay(5);
+	}
+
+#ifdef __FreeBSD__
+#if __FreeBSD_version < 500000 
+	LIST_FOREACH(ifma, &ifp->if_multiaddrs, ifma_link) {
+#else
+	TAILQ_FOREACH(ifma, &ifp->if_multiaddrs, ifma_link) {
+#endif
+		if (ifma->ifma_addr->sa_family != AF_LINK)
+			continue;
+
+		if (mcnt == MAX_NUM_MULTICAST_ADDRESSES) break;
+
+		bcopy(LLADDR((struct sockaddr_dl *)ifma->ifma_addr),
+		      &mta[mcnt*ETH_LENGTH_OF_ADDRESS], ETH_LENGTH_OF_ADDRESS);
+		mcnt++;
+	}
+#endif /* __FreeBSD__ */
+
+	if (mcnt >= MAX_NUM_MULTICAST_ADDRESSES) {
+		reg_rctl = E1000_READ_REG(&sc->hw, RCTL);
+		reg_rctl |= E1000_RCTL_MPE;
+		E1000_WRITE_REG(&sc->hw, RCTL, reg_rctl);
+	} else
+		em_mc_addr_list_update(&sc->hw, mta, mcnt, 0);
+
+	if (sc->hw.mac_type == em_82542_rev2_0) {
+		reg_rctl = E1000_READ_REG(&sc->hw, RCTL);
+		reg_rctl &= ~E1000_RCTL_RST;
+		E1000_WRITE_REG(&sc->hw, RCTL, reg_rctl);
+		msec_delay(5);
+		if (sc->hw.pci_cmd_word & CMD_MEM_WRT_INVALIDATE) {
+			em_pci_set_mwi(&sc->hw);
+		}
+	}
+
+	return;
+}
+
+
+/*********************************************************************
+ *  Timer routine
+ *
+ *  This routine checks for link status and updates statistics.
+ *
+ **********************************************************************/
+
+void
+em_local_timer(void *arg)
+{
+	int s;
+	struct ifnet   *ifp;
+	struct em_softc * sc = arg;
+	ifp = &sc->interface_data.ac_if;
+
+	s = splimp();
+
+	em_check_for_link(&sc->hw);
+	em_print_link_status(sc);
+	em_update_stats_counters(sc);	
+	if (em_display_debug_stats && ifp->if_flags & IFF_RUNNING) {
+		em_print_hw_stats(sc);
+	}
+	em_smartspeed(sc);
+
+	timeout_add(&sc->timer_handle, 2*hz);
+
+	splx(s);
+	return;
+}
+
+void
+em_print_link_status(struct em_softc * sc)
+{
+	if (E1000_READ_REG(&sc->hw, STATUS) & E1000_STATUS_LU) {
+		if (sc->link_active == 0) {
+			em_get_speed_and_duplex(&sc->hw, 
+						&sc->link_speed, 
+						&sc->link_duplex);
+			sc->link_active = 1;
+			sc->smartspeed = 0;
+		}
+	} else {
+		if (sc->link_active == 1) {
+			sc->link_speed = 0;
+			sc->link_duplex = 0;
+			sc->link_active = 0;
+		}
+	}
+
+	return;
+}
+
+/*********************************************************************
+ *
+ *  This routine disables all traffic on the sc by issuing a
+ *  global reset on the MAC and deallocates TX/RX buffers. 
+ *
+ **********************************************************************/
+
+void
+em_stop(void *arg)
+{
+	struct ifnet   *ifp;
+	struct em_softc * sc = arg;
+	ifp = &sc->interface_data.ac_if;
+
+	INIT_DEBUGOUT("em_stop: begin\n");
+	em_disable_intr(sc);
+	em_reset_hw(&sc->hw);
+	timeout_del(&sc->timer_handle);
+	timeout_del(&sc->tx_fifo_timer_handle);
+	em_free_transmit_structures(sc);
+	em_free_receive_structures(sc);
+
+
+	/* Tell the stack that the interface is no longer active */
+	ifp->if_flags &= ~(IFF_RUNNING | IFF_OACTIVE);
+
+	return;
+}
 
 
 /*********************************************************************
@@ -1185,7 +1481,7 @@
 					    PCI_COMMAND_STATUS_REG);
 	if (!((sc->hw.pci_cmd_word & PCI_COMMAND_MASTER_ENABLE) &&
 	      (sc->hw.pci_cmd_word & PCI_COMMAND_MEM_ENABLE))) {
-		printf("%s: Memory Access and/or Bus Master bits not set!\n", 
+		printf("%s: Memory Access and/or Bus Master bits were not set!\n", 
 		       sc->sc_dv.dv_xname);
 		sc->hw.pci_cmd_word |= 
 		(PCI_COMMAND_MASTER_ENABLE | PCI_COMMAND_MEM_ENABLE);
@@ -1199,78 +1495,40 @@
 
 	reg = pci_conf_read(pa->pa_pc, pa->pa_tag, PCI_CLASS_REG);
 	sc->hw.revision_id = PCI_REVISION(reg);
-
-	reg = pci_conf_read(pa->pa_pc, pa->pa_tag, PCI_SUBSYS_ID_REG);
-
-	sc->hw.subsystem_vendor_id = PCI_VENDOR(reg);
-	sc->hw.subsystem_id = PCI_PRODUCT(reg);
-
-	/* Set MacType, etc. based on this PCI info */
-	switch (sc->hw.device_id) {
-	case E1000_DEV_ID_82542:
-		sc->hw.mac_type = (sc->hw.revision_id == 3) ?
-				       em_82542_rev2_1 : em_82542_rev2_0;
-		break;
-	case E1000_DEV_ID_82543GC_FIBER:
-	case E1000_DEV_ID_82543GC_COPPER:
-		sc->hw.mac_type = em_82543;
-		break;
-	case E1000_DEV_ID_82544EI_FIBER:
-	case E1000_DEV_ID_82544EI_COPPER:
-	case E1000_DEV_ID_82544GC_COPPER:
-	case E1000_DEV_ID_82544GC_LOM:
-		sc->hw.mac_type = em_82544;
-		break;
-	case E1000_DEV_ID_82540EM:
-		sc->hw.mac_type = em_82540;
-		break;
-	case E1000_DEV_ID_82545EM_FIBER:
-	case E1000_DEV_ID_82545EM_COPPER:
-		sc->hw.mac_type = em_82545;
-		break;
-	case E1000_DEV_ID_82546EB_FIBER:
-	case E1000_DEV_ID_82546EB_COPPER:
-		sc->hw.mac_type = em_82546;
-		break;
-	default:
-		INIT_DEBUGOUT1("Unknown device id 0x%x", sc->hw.device_id);
-	}
+
+	reg = pci_conf_read(pa->pa_pc, pa->pa_tag, PCI_SUBSYS_ID_REG);
+
+	sc->hw.subsystem_vendor_id = PCI_VENDOR(reg);
+	sc->hw.subsystem_id = PCI_PRODUCT(reg);
+
+	/* Identify the MAC */
+	if (em_set_mac_type(&sc->hw))
+		printf("%s: Unknown MAC Type\n", sc->sc_dv.dv_xname);
+
 	return;
 }
 
 int
 em_allocate_pci_resources(struct em_softc * sc)
 {
-	int             i, val, rid;
-	pci_intr_handle_t       ih;
-	const char              *intrstr = NULL;
+	int		i, val, rid;
+	pci_intr_handle_t	ih;
+	const char		*intrstr = NULL;
 	struct pci_attach_args *pa = &sc->osdep.em_pa;
-	pci_chipset_tag_t       pc = pa->pa_pc;
+	pci_chipset_tag_t	pc = pa->pa_pc;
 
 	val = pci_conf_read(pa->pa_pc, pa->pa_tag, EM_MMBA);
 	if (PCI_MAPREG_TYPE(val) != PCI_MAPREG_TYPE_MEM) {
 		printf(": mmba isn't memory");
 		return (ENXIO);
-        }
-        if (pci_mapreg_map(pa, EM_MMBA, PCI_MAPREG_MEM_TYPE(val), 0,
-	    &sc->osdep.em_btag, &sc->osdep.em_bhandle,
+	}
+	if (pci_mapreg_map(pa, EM_MMBA, PCI_MAPREG_MEM_TYPE(val), 0,
+	    &sc->osdep.mem_bus_space_tag, &sc->osdep.mem_bus_space_handle,
 	    &sc->osdep.em_membase, &sc->osdep.em_memsize, 0)) {
 		printf(": can't find mem space");
 		return (ENXIO);
 	}
 
-#if 0
-        if (pci_mapreg_map(pa, EM_MMBA, PCI_MAPREG_MEM_TYPE_32BIT, 0,
-	    &sc->osdep.em_btag, &sc->osdep.em_bhandle, &sc->osdep.em_membase,
-	    &sc->osdep.em_memsize, 0) &&
-       	    pci_mapreg_map(pa, EM_MMBA, PCI_MAPREG_MEM_TYPE_64BIT, 0,
-    	    &sc->osdep.em_btag, &sc->osdep.em_bhandle, &sc->osdep.em_membase,
-	    	&sc->osdep.em_memsize, 0)) {
-                printf(": can't find mem space");
-                return (ENXIO);
-        }
-#endif /* 0 */
-
 	if (sc->hw.mac_type > em_82543) {
 		/* Figure our where our IO BAR is ? */
 		rid = EM_MMBA;
@@ -1282,32 +1540,32 @@
 			}
 			rid += 4;
 		}
-        	if (pci_mapreg_map(pa, rid, PCI_MAPREG_TYPE_IO, 0,
+		if (pci_mapreg_map(pa, rid, PCI_MAPREG_TYPE_IO, 0,
 				   &sc->osdep.em_iobtag,
 				   &sc->osdep.em_iobhandle,
 				   &sc->osdep.em_iobase,
 				   &sc->osdep.em_iosize, 0)) {
-                	printf(": can't find io space");
-                	return (ENXIO);
-        	}
+			printf(": can't find io space");
+			return (ENXIO);
+		}
 	}
 
-        if (pci_intr_map(pa, &ih)) {
-                printf(": couldn't map interrupt\n");
-                return (ENXIO);
-        }
+	if (pci_intr_map(pa, &ih)) {
+		printf(": couldn't map interrupt\n");
+		return (ENXIO);
+	}
 
-        intrstr = pci_intr_string(pc, ih);
-        sc->sc_intrhand = pci_intr_establish(pc, ih, IPL_NET, em_intr, sc,
-                                              sc->sc_dv.dv_xname);
-        if (sc->sc_intrhand == NULL) {
-                printf(": couldn't establish interrupt");
-                if (intrstr != NULL)
-                        printf(" at %s", intrstr);
-                printf("\n");
+	intrstr = pci_intr_string(pc, ih);
+	sc->sc_intrhand = pci_intr_establish(pc, ih, IPL_NET, em_intr, sc,
+					      sc->sc_dv.dv_xname);
+	if (sc->sc_intrhand == NULL) {
+		printf(": couldn't establish interrupt");
+		if (intrstr != NULL)
+			printf(" at %s", intrstr);
+		printf("\n");
 		return (ENXIO);
-        }
-        printf(": %s", intrstr);
+	}
+	printf(": %s", intrstr);
 		
 	sc->hw.back = &sc->osdep;
 
@@ -1318,7 +1576,7 @@
 em_free_pci_resources(struct em_softc* sc)
 {
 	struct pci_attach_args *pa = &sc->osdep.em_pa;
-	pci_chipset_tag_t       pc = pa->pa_pc;
+	pci_chipset_tag_t	pc = pa->pa_pc;
 
 	if(sc->sc_intrhand)
 		pci_intr_disestablish(pc, sc->sc_intrhand);
@@ -1330,7 +1588,7 @@
 	sc->osdep.em_iobase = 0;
 
 	if(sc->osdep.em_membase)
-		bus_space_unmap(sc->osdep.em_btag, sc->osdep.em_bhandle,
+		bus_space_unmap(sc->osdep.mem_bus_space_tag, sc->osdep.mem_bus_space_handle,
 				sc->osdep.em_memsize);
 	sc->osdep.em_membase = 0;
 
@@ -1350,6 +1608,9 @@
 	/* Issue a global reset */
 	em_reset_hw(&sc->hw);
 
+	/* When hardware is reset, fifo_head is also reset */
+	sc->tx_fifo_head = 0;
+
 	/* Make sure we have a good EEPROM before we read from it */
 	if (em_validate_eeprom_checksum(&sc->hw) < 0) {
 		printf("%s: The EEPROM Checksum Is Not Valid\n",
@@ -1398,12 +1659,12 @@
 	struct ifnet   *ifp;
 	INIT_DEBUGOUT("em_setup_interface: begin");
 
-	ifp = &sc->arpcom.ac_if;
+	ifp = &sc->interface_data.ac_if;
 	ifp->if_mtu = ETHERMTU;
 	ifp->if_output = ether_output;
 	ifp->if_baudrate = 1000000000;
-#if 0
-	ifp->if_init =  em_init;
+#ifdef __FreeBSD__
+	ifp->if_init =	em_init;
 #endif
 	ifp->if_softc = sc;
 	ifp->if_flags = IFF_BROADCAST | IFF_SIMPLEX | IFF_MULTICAST;
@@ -1413,18 +1674,26 @@
 	IFQ_SET_MAXLEN(&ifp->if_snd, sc->num_tx_desc - 1);
 	IFQ_SET_READY(&ifp->if_snd);
 
-	bcopy(sc->sc_dv.dv_xname, ifp->if_xname, IFNAMSIZ);
+	strlcpy(ifp->if_xname, sc->sc_dv.dv_xname, IFNAMSIZ);
 	
-
-#if 0
+#ifdef __FreeBSD__
 	if (sc->hw.mac_type >= em_82543) {
 		ifp->if_capabilities = IFCAP_HWCSUM;
 		ifp->if_capenable = ifp->if_capabilities;
 	}
-#endif /* 0 */
+
+	/*
+	 * Tell the upper layer(s) we support long frames.
+	 */
+	ifp->if_data.ifi_hdrlen = sizeof(struct ehter_vlan_header);
+#if __FreeBSD_version >= 500000
+	ifp->if_capabilities |= IFCAP_VLAN_HWTAGGING | IFCAP_VLAN_MTU;
+#endif
+#endif /* __FreeBSD__ */
+
 
 	/* 
-	 * Specify the media types supported by this em_softc and register
+	 * Specify the media types supported by this adapter and register
 	 * callbacks to update media and link information
 	 */
 	ifmedia_init(&sc->media, IFM_IMASK, em_media_change,
@@ -1458,6 +1727,175 @@
 
 /*********************************************************************
  *
+ *  Workaround for SmartSpeed on 82541 and 82547 controllers
+ *
+ **********************************************************************/	
+void
+em_smartspeed(struct em_softc *sc)
+{
+	uint16_t phy_tmp;
+ 
+	if(sc->link_active || (sc->hw.phy_type != em_phy_igp) || 
+	   !sc->hw.autoneg || !(sc->hw.autoneg_advertised & ADVERTISE_1000_FULL))
+		return;
+
+	if(sc->smartspeed == 0) {
+		/* If Master/Slave config fault is asserted twice,
+		 * we assume back-to-back */
+		em_read_phy_reg(&sc->hw, PHY_1000T_STATUS, &phy_tmp);
+		if(!(phy_tmp & SR_1000T_MS_CONFIG_FAULT)) return;
+		em_read_phy_reg(&sc->hw, PHY_1000T_STATUS, &phy_tmp);
+		if(phy_tmp & SR_1000T_MS_CONFIG_FAULT) {
+			em_read_phy_reg(&sc->hw, PHY_1000T_CTRL,
+					&phy_tmp);
+			if(phy_tmp & CR_1000T_MS_ENABLE) {
+				phy_tmp &= ~CR_1000T_MS_ENABLE;
+				em_write_phy_reg(&sc->hw,
+						    PHY_1000T_CTRL, phy_tmp);
+				sc->smartspeed++;
+				if(sc->hw.autoneg &&
+				   !em_phy_setup_autoneg(&sc->hw) &&
+				   !em_read_phy_reg(&sc->hw, PHY_CTRL,
+						       &phy_tmp)) {
+					phy_tmp |= (MII_CR_AUTO_NEG_EN |  
+						    MII_CR_RESTART_AUTO_NEG);
+					em_write_phy_reg(&sc->hw,
+							 PHY_CTRL, phy_tmp);
+				}
+			}
+		}
+		return;
+	} else if(sc->smartspeed == EM_SMARTSPEED_DOWNSHIFT) {
+		/* If still no link, perhaps using 2/3 pair cable */
+		em_read_phy_reg(&sc->hw, PHY_1000T_CTRL, &phy_tmp);
+		phy_tmp |= CR_1000T_MS_ENABLE;
+		em_write_phy_reg(&sc->hw, PHY_1000T_CTRL, phy_tmp);
+		if(sc->hw.autoneg &&
+		   !em_phy_setup_autoneg(&sc->hw) &&
+		   !em_read_phy_reg(&sc->hw, PHY_CTRL, &phy_tmp)) {
+			phy_tmp |= (MII_CR_AUTO_NEG_EN |
+				    MII_CR_RESTART_AUTO_NEG);
+			em_write_phy_reg(&sc->hw, PHY_CTRL, phy_tmp);
+		}
+	}
+	/* Restart process after EM_SMARTSPEED_MAX iterations */
+	if(sc->smartspeed++ == EM_SMARTSPEED_MAX)
+		sc->smartspeed = 0;
+
+	return;
+}
+
+
+/*
+ * Manage DMA'able memory.
+ */
+
+#ifdef __FreeBSD__
+void
+em_dmamap_cb(void *arg, bus_dma_segment_t *segs, int nseg, int error)
+{ 
+	if (error)
+		return;
+	*(bus_addr_t*) arg = segs->ds_addr;
+	return;
+}
+#endif /* __FreeBSD__ */
+
+int
+em_dma_malloc(struct em_softc *sc, bus_size_t size,
+	struct em_dma_alloc *dma, int mapflags)
+{
+	int r;
+
+#ifdef __FreeBSD__
+	r = bus_dma_tag_create(NULL,			/* parent */
+			       PAGE_SIZE, 0,		/* alignment, bounds */
+			       BUS_SPACE_MAXADDR,	/* lowaddr */
+			       BUS_SPACE_MAXADDR,	/* highaddr */
+			       NULL, NULL,		/* filter, filterarg */
+			       size,			/* maxsize */
+			       1,			/* nsegments */
+			       size,			/* maxsegsize */
+			       BUS_DMA_ALLOCNOW,	/* flags */
+			       &dma->dma_tag);
+	if (r != 0) {
+		printf("%s: em_dma_malloc: bus_dma_tag_create failed; "
+			"error %u\n", sc->sc_dv.dv_xname, r);
+		goto fail_0;
+	}
+
+	r = bus_dmamap_create(dma->dma_tag, BUS_DMA_NOWAIT, &dma->dma_map);
+#endif /* __FreeBSD__ */
+	dma->dma_tag = sc->osdep.em_pa.pa_dmat;
+	r = bus_dmamap_create(dma->dma_tag, size, 1,
+	    size, 0, BUS_DMA_NOWAIT, &dma->dma_map);
+
+	if (r != 0) {
+		printf("%s: em_dma_malloc: bus_dmamap_create failed; "
+			"error %u\n", sc->sc_dv.dv_xname, r);
+		goto fail_0;
+	}
+
+	r = bus_dmamem_alloc(dma->dma_tag, size, PAGE_SIZE, 0, &dma->dma_seg,
+	    1, &dma->dma_nseg, BUS_DMA_NOWAIT);
+	if (r != 0) {
+		printf("%s: em_dma_malloc: bus_dmammem_alloc failed; "
+			"size %ju, error %d\n", sc->sc_dv.dv_xname,
+			size, r);
+		goto fail_1;
+	}
+
+	r = bus_dmamem_map(dma->dma_tag, &dma->dma_seg, dma->dma_nseg, size,
+	    &dma->dma_vaddr, BUS_DMA_NOWAIT);
+	if (r != 0) {
+		printf("%s: em_dma_malloc: bus_dmammem_map failed; "
+			"size %ju, error %d\n", sc->sc_dv.dv_xname,
+			size, r);
+		goto fail_2;
+	}
+
+	r = bus_dmamap_load(sc->osdep.em_pa.pa_dmat, dma->dma_map,
+			    dma->dma_vaddr,
+			    size,
+			    NULL,
+			    mapflags | BUS_DMA_NOWAIT);
+	if (r != 0) {
+		printf("%s: em_dma_malloc: bus_dmamap_load failed; "
+			"error %u\n", sc->sc_dv.dv_xname, r);
+		goto fail_3;
+	}
+
+	dma->dma_size = size;
+	return (0);
+
+/* fail_4: */
+	bus_dmamap_unload(dma->dma_tag, dma->dma_map);
+fail_3:
+	bus_dmamem_unmap(dma->dma_tag, dma->dma_vaddr, size);
+fail_2:
+	bus_dmamem_free(dma->dma_tag, &dma->dma_seg, dma->dma_nseg);
+fail_1:
+	bus_dmamap_destroy(dma->dma_tag, dma->dma_map);
+	/* bus_dma_tag_destroy(dma->dma_tag); */
+fail_0:
+	dma->dma_map = NULL;
+	/* dma->dma_tag = NULL; */
+	return (r);
+}
+
+void
+em_dma_free(struct em_softc *sc, struct em_dma_alloc *dma)
+{
+	bus_dmamap_unload(dma->dma_tag, dma->dma_map);
+	bus_dmamem_unmap(dma->dma_tag, dma->dma_vaddr, dma->dma_size);
+	bus_dmamem_free(dma->dma_tag, &dma->dma_seg, dma->dma_nseg);
+	bus_dmamap_destroy(dma->dma_tag, dma->dma_map);
+	/* bus_dma_tag_destroy(dma->dma_tag); */
+}
+
+
+/*********************************************************************
+ *
  *  Allocate memory for tx_buffer structures. The tx_buffer stores all 
  *  the information needed to transmit a packet on the wire. 
  *
@@ -1466,7 +1904,7 @@
 em_allocate_transmit_structures(struct em_softc * sc)
 {
 	if (!(sc->tx_buffer_area =
-	      (struct em_tx_buffer *) malloc(sizeof(struct em_tx_buffer) *
+	      (struct em_buffer *) malloc(sizeof(struct em_buffer) *
 					     sc->num_tx_desc, M_DEVBUF,
 					     M_NOWAIT))) {
 		printf("%s: Unable to allocate tx_buffer memory\n", 
@@ -1475,7 +1913,7 @@
 	}
 
 	bzero(sc->tx_buffer_area,
-	      sizeof(struct em_tx_buffer) * sc->num_tx_desc);
+	      sizeof(struct em_buffer) * sc->num_tx_desc);
 
 	return 0;
 }
@@ -1488,39 +1926,35 @@
 int
 em_setup_transmit_structures(struct em_softc* sc)
 {
-	struct em_tx_buffer   *tx_buffer;
-	int             i;
-
-	if (em_allocate_transmit_structures(sc))
-		return ENOMEM;
-
-	sc->first_tx_desc = sc->tx_desc_base;
-	sc->last_tx_desc =
-	sc->first_tx_desc + (sc->num_tx_desc - 1);
-
-
-	SIMPLEQ_INIT(&sc->free_tx_buffer_list);
-	SIMPLEQ_INIT(&sc->used_tx_buffer_list);
+#ifdef __FreeBSD__
+	/*
+	 * Setup DMA descriptor areas.
+	 */
+	if (bus_dma_tag_create(NULL,	/* parent */
+		    PAGE_SIZE, 0,	/* alignment, bounds */
+		    BUS_SPACE_MAXADDR,       /* lowaddr */
+		    BUS_SPACE_MAXADDR,       /* highaddr */
+		    NULL, NULL,              /* filter, filterarg */
+		    MCLBYTES * 8,            /* maxsize */
+		    EM_MAX_SCATTER,          /* nsegments */
+		    MCLBYTES * 8,            /* maxsegsize */
+		    BUS_DMA_ALLOCNOW,        /* flags */
+		    &sc->txtag)) {
+		printf("%s: Unable to allocate TX DMA tag\n", sc->sc_dv.dv_xname);
+		return (ENOMEM);
+	}
 
-	tx_buffer = sc->tx_buffer_area;
+#endif /* __FreeBSD__ */
+	sc->txtag = sc->osdep.em_pa.pa_dmat;
 
-	/* Setup the linked list of the tx_buffer's */
-	for (i = 0; i < sc->num_tx_desc; i++, tx_buffer++) {
-		bzero((void *) tx_buffer, sizeof(struct em_tx_buffer));
-		if (bus_dmamap_create(sc->osdep.em_pa.pa_dmat, MCLBYTES, 32,
-				      MCLBYTES, 0, BUS_DMA_NOWAIT,
-				      &tx_buffer->dmamap))
-			return ENOBUFS;
-		SIMPLEQ_INSERT_TAIL(&sc->free_tx_buffer_list, 
-				   tx_buffer, em_tx_entry);
-	}
+	if (em_allocate_transmit_structures(sc))
+		return (ENOMEM);
 
-	bzero((void *) sc->first_tx_desc,
+	bzero((void *) sc->tx_desc_base,
 	      (sizeof(struct em_tx_desc)) * sc->num_tx_desc);
 
-	/* Setup TX descriptor pointers */
-	sc->next_avail_tx_desc = sc->first_tx_desc;
-	sc->oldest_used_tx_desc = sc->first_tx_desc;
+	sc->next_avail_tx_desc = 0;
+	sc->oldest_used_tx_desc = 0;
 
 	/* Set number of descriptors available */
 	sc->num_tx_desc_avail = sc->num_tx_desc;
@@ -1528,7 +1962,7 @@
 	/* Set checksum context */
 	sc->active_checksum_context = OFFLOAD_NONE;
 
-	return 0;
+	return (0);
 }
 
 /*********************************************************************
@@ -1539,13 +1973,14 @@
 void
 em_initialize_transmit_unit(struct em_softc * sc)
 {
-	u_int32_t       reg_tctl;
-	u_int32_t       reg_tipg = 0;
+	u_int32_t	reg_tctl;
+	u_int32_t	reg_tipg = 0;
+	u_int64_t	bus_addr;
 
 	/* Setup the Base and Length of the Tx Descriptor Ring */
-	E1000_WRITE_REG(&sc->hw, TDBAL,
-			sc->osdep.em_tx.emm_dmamap->dm_segs[0].ds_addr);
-	E1000_WRITE_REG(&sc->hw, TDBAH, 0);
+	bus_addr = sc->txdma.dma_map->dm_segs[0].ds_addr;
+	E1000_WRITE_REG(&sc->hw, TDBAL, (u_int32_t)bus_addr);
+	E1000_WRITE_REG(&sc->hw, TDBAH, (u_int32_t)(bus_addr >> 32));
 	E1000_WRITE_REG(&sc->hw, TDLEN, 
 			sc->num_tx_desc *
 			sizeof(struct em_tx_desc));
@@ -1559,21 +1994,8 @@
 		     E1000_READ_REG(&sc->hw, TDBAL),
 		     E1000_READ_REG(&sc->hw, TDLEN));
 
-
 	/* Set the default values for the Tx Inter Packet Gap timer */
 	switch (sc->hw.mac_type) {
-	case em_82543:
-	case em_82544:
-	case em_82540:
-	case em_82545:
-	case em_82546:
-		if (sc->hw.media_type == em_media_type_fiber)
-			reg_tipg = DEFAULT_82543_TIPG_IPGT_FIBER;
-		else
-			reg_tipg = DEFAULT_82543_TIPG_IPGT_COPPER;
-		reg_tipg |= DEFAULT_82543_TIPG_IPGR1 << E1000_TIPG_IPGR1_SHIFT;
-		reg_tipg |= DEFAULT_82543_TIPG_IPGR2 << E1000_TIPG_IPGR2_SHIFT;
-		break;
 	case em_82542_rev2_0:
 	case em_82542_rev2_1:
 		reg_tipg = DEFAULT_82542_TIPG_IPGT;
@@ -1581,10 +2003,18 @@
 		reg_tipg |= DEFAULT_82542_TIPG_IPGR2 << E1000_TIPG_IPGR2_SHIFT;
 		break;
 	default:
-		printf("%s: Invalid mac type detected\n", sc->sc_dv.dv_xname);
+		if (sc->hw.media_type == em_media_type_fiber)
+			reg_tipg = DEFAULT_82543_TIPG_IPGT_FIBER;
+		else
+			reg_tipg = DEFAULT_82543_TIPG_IPGT_COPPER;
+			reg_tipg |= DEFAULT_82543_TIPG_IPGR1 << E1000_TIPG_IPGR1_SHIFT;
+			reg_tipg |= DEFAULT_82543_TIPG_IPGR2 << E1000_TIPG_IPGR2_SHIFT;
 	}
+
 	E1000_WRITE_REG(&sc->hw, TIPG, reg_tipg);
 	E1000_WRITE_REG(&sc->hw, TIDV, sc->tx_int_delay);
+	if(sc->hw.mac_type >= em_82540)
+		E1000_WRITE_REG(&sc->hw, TADV, sc->tx_abs_int_delay);
 
 	/* Program the Transmit Control Register */
 	reg_tctl = E1000_TCTL_PSP | E1000_TCTL_EN |
@@ -1597,16 +2027,11 @@
 	E1000_WRITE_REG(&sc->hw, TCTL, reg_tctl);
 
 	/* Setup Transmit Descriptor Settings for this adapter */   
-	sc->txd_cmd = E1000_TXD_CMD_IFCS;
+	sc->txd_cmd = E1000_TXD_CMD_IFCS | E1000_TXD_CMD_RS;
 
 	if (sc->tx_int_delay > 0)
 		sc->txd_cmd |= E1000_TXD_CMD_IDE;
 
-	if (sc->hw.report_tx_early == 1)
-		sc->txd_cmd |= E1000_TXD_CMD_RS;
-	else
-		sc->txd_cmd |= E1000_TXD_CMD_RPS;
-
 	return;
 }
 
@@ -1618,28 +2043,32 @@
 void
 em_free_transmit_structures(struct em_softc* sc)
 {
-	struct em_tx_buffer   *tx_buffer;
-	int             i;
+	struct em_buffer   *tx_buffer;
+	int		i;
 
 	INIT_DEBUGOUT("free_transmit_structures: begin");
 
 	if (sc->tx_buffer_area != NULL) {
 		tx_buffer = sc->tx_buffer_area;
 		for (i = 0; i < sc->num_tx_desc; i++, tx_buffer++) {
-			if (tx_buffer->m_head != NULL)
+			if (tx_buffer->m_head != NULL) {
+				bus_dmamap_unload(sc->txtag, tx_buffer->map);
+				bus_dmamap_destroy(sc->txtag, tx_buffer->map);
 				m_freem(tx_buffer->m_head);
+			}
 			tx_buffer->m_head = NULL;
-
-			bus_dmamap_unload(sc->osdep.em_pa.pa_dmat,
-			    tx_buffer->dmamap);
-			bus_dmamap_destroy(sc->osdep.em_pa.pa_dmat,
-			    tx_buffer->dmamap);
 		}
 	}
 	if (sc->tx_buffer_area != NULL) {
 		free(sc->tx_buffer_area, M_DEVBUF);
 		sc->tx_buffer_area = NULL;
 	}
+	if (sc->txtag != NULL) {
+#ifdef __FreeBSD__
+		bus_dma_tag_destroy(sc->txtag);
+#endif
+		sc->txtag = NULL;
+	}
 	return;
 }
 
@@ -1650,16 +2079,17 @@
  *  context only if the protocol type changes.
  *
  **********************************************************************/
-#if 0
+#ifdef __FreeBSD__
 void
 em_transmit_checksum_setup(struct em_softc * sc,
 			   struct mbuf *mp,
-			   struct em_tx_buffer *tx_buffer,
 			   u_int32_t *txd_upper,
 			   u_int32_t *txd_lower) 
 {
 	struct em_context_desc *TXD;
-	struct em_tx_desc * current_tx_desc;
+	struct em_buffer *tx_buffer;
+	int curr_txd;
+
 	if (mp->m_pkthdr.csum_flags) {
 
 		if (mp->m_pkthdr.csum_flags & CSUM_TCP) {
@@ -1691,18 +2121,19 @@
 	/* If we reach this point, the checksum offload context
 	 * needs to be reset.
 	 */
-	current_tx_desc = sc->next_avail_tx_desc;
-	TXD = (struct em_context_desc *)current_tx_desc;
+	curr_txd = sc->next_avail_tx_desc;
+	tx_buffer = &sc->tx_buffer_area[curr_txd];
+	TXD = (struct em_context_desc *) &sc->tx_desc_base[curr_txd];
 
 	TXD->lower_setup.ip_fields.ipcss = ETHER_HDR_LEN;
 	TXD->lower_setup.ip_fields.ipcso = 
 	ETHER_HDR_LEN + offsetof(struct ip, ip_sum);
 	TXD->lower_setup.ip_fields.ipcse = 
-	ETHER_HDR_LEN + sizeof(struct ip) - 1;
+	    htole16(ETHER_HDR_LEN + sizeof(struct ip) - 1);
 
 	TXD->upper_setup.tcp_fields.tucss = 
 	ETHER_HDR_LEN + sizeof(struct ip);
-	TXD->upper_setup.tcp_fields.tucse = 0;
+	TXD->upper_setup.tcp_fields.tucse = htole16(0);
 
 	if (sc->active_checksum_context == OFFLOAD_TCP_IP) {
 		TXD->upper_setup.tcp_fields.tucso = 
@@ -1714,21 +2145,93 @@
 		offsetof(struct udphdr, uh_sum);
 	}
 
-	TXD->tcp_seg_setup.data = 0;
-	TXD->cmd_and_length = E1000_TXD_CMD_DEXT;
+	TXD->tcp_seg_setup.data = htole32(0);
+	TXD->cmd_and_length = htole32(sc->txd_cmd | E1000_TXD_CMD_DEXT);
 
-	if (current_tx_desc == sc->last_tx_desc)
-		sc->next_avail_tx_desc = sc->first_tx_desc;
-	else
-		sc->next_avail_tx_desc++;
+	tx_buffer->m_head = NULL;
+
+	if (++curr_txd == sc->num_tx_desc)
+		curr_txd = 0;
 
 	sc->num_tx_desc_avail--;
+	sc->next_avail_tx_desc = curr_txd;
 
-	tx_buffer->num_tx_desc_used++;
 	return;
 }
-#endif /* 0 */
+#endif /* __FreeBSD__ */
+
+/**********************************************************************
+ *
+ *  Examine each tx_buffer in the used queue. If the hardware is done
+ *  processing the packet then free associated resources. The
+ *  tx_buffer is put back on the free queue. 
+ *
+ **********************************************************************/
+void
+em_clean_transmit_interrupts(struct em_softc* sc)
+{
+	int s;
+	int i, num_avail;
+	struct em_buffer *tx_buffer;
+	struct em_tx_desc   *tx_desc;
+	struct ifnet   *ifp = &sc->interface_data.ac_if;
+
+	if (sc->num_tx_desc_avail == sc->num_tx_desc)
+		return;
+
+	s = splimp();
+#ifdef DBG_STATS
+	sc->clean_tx_interrupts++;
+#endif
+	num_avail = sc->num_tx_desc_avail;
+	i = sc->oldest_used_tx_desc;
+
+	tx_buffer = &sc->tx_buffer_area[i];
+	tx_desc = &sc->tx_desc_base[i];
+
+	while(tx_desc->upper.fields.status & E1000_TXD_STAT_DD) {
+
+		tx_desc->upper.data = 0;
+		num_avail++;
+
+		if (tx_buffer->m_head) {
+			ifp->if_opackets++;
+			bus_dmamap_sync(sc->txtag, tx_buffer->map,
+			    0, tx_buffer->map->dm_mapsize,
+			    BUS_DMASYNC_POSTWRITE);
+			bus_dmamap_unload(sc->txtag, tx_buffer->map);
+			bus_dmamap_destroy(sc->txtag, tx_buffer->map);
 
+			m_freem(tx_buffer->m_head);
+			tx_buffer->m_head = NULL;
+		}
+
+		if (++i == sc->num_tx_desc)
+			i = 0;
+
+		tx_buffer = &sc->tx_buffer_area[i];
+		tx_desc = &sc->tx_desc_base[i];
+	}
+
+	sc->oldest_used_tx_desc = i;
+
+	/*
+	 * If we have enough room, clear IFF_OACTIVE to tell the stack
+	 * that it is OK to send packets.
+	 * If there are no pending descriptors, clear the timeout. Otherwise,
+	 * if some descriptors have been freed, restart the timeout.
+	 */
+	if (num_avail > EM_TX_CLEANUP_THRESHOLD) {
+		ifp->if_flags &= ~IFF_OACTIVE;
+		if (num_avail == sc->num_tx_desc)
+			ifp->if_timer = 0;
+		else if (num_avail == sc->num_tx_desc_avail)
+			ifp->if_timer = EM_TX_TIMEOUT;
+	}
+	sc->num_tx_desc_avail = num_avail;
+	splx(s);
+	return;
+}
 
 /*********************************************************************
  *
@@ -1736,45 +2239,56 @@
  *
  **********************************************************************/
 int
-em_get_buf(struct em_rx_buffer *rx_buffer, struct em_softc *sc,
-	   struct mbuf *mp)
+em_get_buf(int i, struct em_softc *sc,
+    struct mbuf *nmp)
 {
-	struct mbuf    *nmp;
+	struct mbuf    *mp = nmp;
+	struct em_buffer *rx_buffer;
 	struct ifnet   *ifp;
+	int error;
 
-	ifp = &sc->arpcom.ac_if;
+	ifp = &sc->interface_data.ac_if;
 
 	if (mp == NULL) {
-		MGETHDR(nmp, M_DONTWAIT, MT_DATA);
-		if (nmp == NULL) {
+		MGETHDR(mp, M_DONTWAIT, MT_DATA);
+		if (mp == NULL) {
 			sc->mbuf_alloc_failed++;
 			return(ENOBUFS);
 		}
-		MCLGET(nmp, M_DONTWAIT);
-		if ((nmp->m_flags & M_EXT) == 0) {
-			m_freem(nmp);
+		MCLGET(mp, M_DONTWAIT);
+		if ((mp->m_flags & M_EXT) == 0) {
+			m_freem(mp);
 			sc->mbuf_cluster_failed++;
 			return(ENOBUFS);
 		}
-		nmp->m_len = nmp->m_pkthdr.len = MCLBYTES;
+		mp->m_len = mp->m_pkthdr.len = MCLBYTES;
 	} else {
-		nmp = mp;
-		nmp->m_len = nmp->m_pkthdr.len = MCLBYTES;
-		nmp->m_data = nmp->m_ext.ext_buf;
-		nmp->m_next = NULL;
-	}
-
-	if (bus_dmamap_load_mbuf(sc->osdep.em_pa.pa_dmat,
-				 rx_buffer->dmamap,
-				 nmp, BUS_DMA_NOWAIT))
-		return(ENOBUFS);
-
-	if (ifp->if_mtu <= ETHERMTU)
-		m_adj(nmp, ETHER_ALIGN);
-
-	rx_buffer->m_head = nmp;
-	rx_buffer->buffer_addr = 
-		rx_buffer->dmamap->dm_segs[0].ds_addr + ETHER_ALIGN;
+		mp->m_len = mp->m_pkthdr.len = MCLBYTES;
+		mp->m_data = mp->m_ext.ext_buf;
+		mp->m_next = NULL;
+	}
+
+	if (ifp->if_mtu <= ETHERMTU) {
+		m_adj(mp, ETHER_ALIGN);
+	}
+
+	rx_buffer = &sc->rx_buffer_area[i];
+
+	/*
+	 * Using memory from the mbuf cluster pool, invoke the
+	 * bus_dma machinery to arrange the memory mapping.
+	 */
+	error = bus_dmamap_load(sc->rxtag, rx_buffer->map,
+	    mtod(mp, void *), mp->m_len, NULL,
+	    0);
+	if (error) {
+		m_free(mp);
+		return(error);
+	}
+	rx_buffer->m_head = mp;
+	sc->rx_desc_base[i].buffer_addr = htole64(rx_buffer->map->dm_segs[0].ds_addr);
+	bus_dmamap_sync(sc->rxtag, rx_buffer->map, 0,
+	    rx_buffer->map->dm_mapsize, BUS_DMASYNC_PREREAD);
 
 	return(0);
 }
@@ -1790,11 +2304,11 @@
 int
 em_allocate_receive_structures(struct em_softc* sc)
 {
-	int             i;
-	struct em_rx_buffer   *rx_buffer;
+	int		i, error;
+	struct em_buffer *rx_buffer;
 
 	if (!(sc->rx_buffer_area =
-	      (struct em_rx_buffer *) malloc(sizeof(struct em_rx_buffer) *
+	      (struct em_buffer *) malloc(sizeof(struct em_buffer) *
 					     sc->num_rx_desc, M_DEVBUF,
 					     M_NOWAIT))) {
 		printf("%s: Unable to allocate rx_buffer memory\n", 
@@ -1803,24 +2317,59 @@
 	}
 
 	bzero(sc->rx_buffer_area,
-	      sizeof(struct em_rx_buffer) * sc->num_rx_desc);
-
-	for (i = 0, rx_buffer = sc->rx_buffer_area;
-	    i < sc->num_rx_desc; i++, rx_buffer++) {
+	      sizeof(struct em_buffer) * sc->num_rx_desc);
 
-		if (bus_dmamap_create(sc->osdep.em_pa.pa_dmat,
-				      MCLBYTES, 1, MCLBYTES, 0,
-				      BUS_DMA_NOWAIT,
-				      &rx_buffer->dmamap))
-			return ENOBUFS;
-
-		if (em_get_buf(rx_buffer, sc, NULL) == ENOBUFS) {
-			rx_buffer->m_head = NULL;
-			return(ENOBUFS);
+#ifdef __FreeBSD__
+	error = bus_dma_tag_create(NULL,                /* parent */
+				PAGE_SIZE, 0,            /* alignment, bounds */
+				BUS_SPACE_MAXADDR,       /* lowaddr */
+				BUS_SPACE_MAXADDR,       /* highaddr */
+				NULL, NULL,              /* filter, filterarg */
+				MCLBYTES,                /* maxsize */
+				1,                       /* nsegments */
+				MCLBYTES,                /* maxsegsize */
+				BUS_DMA_ALLOCNOW,        /* flags */
+				&sc->rxtag);
+	if (error != 0) {
+		printf("%s: em_allocate_receive_structures: "
+			"bus_dma_tag_create failed; error %u\n",
+			sc->sc_dv.dv_xname, error);
+		goto fail_0;
+	}
+#endif /* __FreeBSD__ */
+	sc->rxtag = sc->osdep.em_pa.pa_dmat;
+
+	rx_buffer = sc->rx_buffer_area;
+	for (i = 0; i < sc->num_rx_desc; i++, rx_buffer++) {
+		error = bus_dmamap_create(sc->rxtag, MCLBYTES, 1,
+					MCLBYTES, 0, BUS_DMA_NOWAIT,
+					&rx_buffer->map);
+		if (error != 0) {
+			printf("%s: em_allocate_receive_structures: "
+			    "bus_dmamap_create failed; error %u\n",
+			    sc->sc_dv.dv_xname, error);
+			goto fail_1;
 		}
 	}
 
-	return(0);
+	for (i = 0; i < sc->num_rx_desc; i++) {
+		error = em_get_buf(i, sc, NULL);
+		if (error != 0) {
+			sc->rx_buffer_area[i].m_head = NULL;
+			sc->rx_desc_base[i].buffer_addr = 0;
+			return(error);
+                }
+        }
+
+        return(0);
+
+fail_1:
+	/* bus_dma_tag_destroy(sc->rxtag); */
+/* fail_0: */
+	sc->rxtag = NULL;
+	free(sc->rx_buffer_area, M_DEVBUF);
+	sc->rx_buffer_area = NULL;
+	return (error);
 }
 
 /*********************************************************************
@@ -1831,42 +2380,14 @@
 int
 em_setup_receive_structures(struct em_softc * sc)
 {
-	struct em_rx_buffer   *rx_buffer;
-	struct em_rx_desc     *rx_desc;
-	int             i;
+	bzero((void *) sc->rx_desc_base,
+	    (sizeof(struct em_rx_desc)) * sc->num_rx_desc);
 
 	if (em_allocate_receive_structures(sc))
 		return ENOMEM;
 
-	SIMPLEQ_INIT(&sc->rx_buffer_list);
-
-	sc->first_rx_desc =
-	(struct em_rx_desc *) sc->rx_desc_base;
-	sc->last_rx_desc =
-	sc->first_rx_desc + (sc->num_rx_desc - 1);
-
-	rx_buffer = (struct em_rx_buffer *) sc->rx_buffer_area;
-
-	bzero((void *) sc->first_rx_desc,
-	      (sizeof(struct em_rx_desc)) * sc->num_rx_desc);
-
-	/* Build a linked list of rx_buffer's */
-	for (i = 0, rx_desc = sc->first_rx_desc;
-	    i < sc->num_rx_desc;
-	    i++, rx_buffer++, rx_desc++) {
-		if (rx_buffer->m_head == NULL)
-			printf("%s: Receive buffer memory not allocated", 
-			       sc->sc_dv.dv_xname);
-		else {
-			rx_desc->buffer_addr = htole64(rx_buffer->buffer_addr);
-			SIMPLEQ_INSERT_TAIL(&sc->rx_buffer_list, 
-					   rx_buffer, em_rx_entry);
-		}
-	}
-
 	/* Setup our descriptor pointers */
-	sc->next_rx_desc_to_check = sc->first_rx_desc;
-
+	sc->next_rx_desc_to_check = 0;
 	return(0);
 }
 
@@ -1878,36 +2399,42 @@
 void
 em_initialize_receive_unit(struct em_softc * sc)
 {
-	u_int32_t       reg_rctl;
-#if 0
-	u_int32_t       reg_rxcsum;
+	u_int32_t	reg_rctl;
+#ifdef __FreeBSD__
+	u_int32_t	reg_rxcsum;
 #endif
-	struct ifnet    *ifp;
+	struct ifnet	*ifp;
+	u_int64_t	bus_addr;
 
-	ifp = &sc->arpcom.ac_if;
+	ifp = &sc->interface_data.ac_if;
 
-	/*
-	 * Make sure receives are disabled while setting up the
-	 * descriptor ring
-	 */
+	/* Make sure receives are disabled while setting up the descriptor ring */
 	E1000_WRITE_REG(&sc->hw, RCTL, 0);
 
 	/* Set the Receive Delay Timer Register */
 	E1000_WRITE_REG(&sc->hw, RDTR, 
 			sc->rx_int_delay | E1000_RDT_FPDB);
 
+	if(sc->hw.mac_type >= em_82540) {
+		E1000_WRITE_REG(&sc->hw, RADV, sc->rx_abs_int_delay);
+
+		/* Set the interrupt throttling rate.  Value is calculated
+		 * as DEFAULT_ITR = 1/(MAX_INTS_PER_SEC * 256ns) */
+#define MAX_INTS_PER_SEC	8000
+#define DEFAULT_ITR		1000000000/(MAX_INTS_PER_SEC * 256)
+		E1000_WRITE_REG(&sc->hw, ITR, DEFAULT_ITR);
+	}
+
 	/* Setup the Base and Length of the Rx Descriptor Ring */
-	E1000_WRITE_REG(&sc->hw, RDBAL, 
-			sc->osdep.em_rx.emm_dmamap->dm_segs[0].ds_addr);
-	E1000_WRITE_REG(&sc->hw, RDBAH, 0);
+	bus_addr = sc->rxdma.dma_map->dm_segs[0].ds_addr;
+	E1000_WRITE_REG(&sc->hw, RDBAL, (u_int32_t)bus_addr);
+	E1000_WRITE_REG(&sc->hw, RDBAH, (u_int32_t)(bus_addr >> 32));
 	E1000_WRITE_REG(&sc->hw, RDLEN, sc->num_rx_desc *
 			sizeof(struct em_rx_desc));
 
 	/* Setup the HW Rx Head and Tail Descriptor Pointers */
 	E1000_WRITE_REG(&sc->hw, RDH, 0);
-	E1000_WRITE_REG(&sc->hw, RDT,
-			(((_BSD_PTRDIFF_T_) sc->last_rx_desc -
-			  (_BSD_PTRDIFF_T_) sc->first_rx_desc) >> 4));
+	E1000_WRITE_REG(&sc->hw, RDT, sc->num_rx_desc - 1);
 
 	/* Setup the Receive Control Register */
 	reg_rctl = E1000_RCTL_EN | E1000_RCTL_BAM | E1000_RCTL_LBM_NO |
@@ -1925,7 +2452,7 @@
 		break;
 	case EM_RXBUFFER_4096:
 		reg_rctl |= E1000_RCTL_SZ_4096|E1000_RCTL_BSEX|E1000_RCTL_LPE;
-		break;            
+		break;		  
 	case EM_RXBUFFER_8192:
 		reg_rctl |= E1000_RCTL_SZ_8192|E1000_RCTL_BSEX|E1000_RCTL_LPE;
 		break;
@@ -1937,7 +2464,7 @@
 	if (ifp->if_mtu > ETHERMTU)
 		reg_rctl |= E1000_RCTL_LPE;
 
-#if 0
+#ifdef __FreeBSD__
 	/* Enable 82543 Receive Checksum Offload for TCP and UDP */
 	if ((sc->hw.mac_type >= em_82543) && 
 	    (ifp->if_capenable & IFCAP_RXCSUM)) {
@@ -1945,7 +2472,7 @@
 		reg_rxcsum |= (E1000_RXCSUM_IPOFL | E1000_RXCSUM_TUOFL);
 		E1000_WRITE_REG(&sc->hw, RXCSUM, reg_rxcsum);
 	}
-#endif /* 0 */
+#endif /* __FreeBSD__ */
 
 	/* Enable Receives */
 	E1000_WRITE_REG(&sc->hw, RCTL, reg_rctl);
@@ -1961,28 +2488,31 @@
 void
 em_free_receive_structures(struct em_softc * sc)
 {
-	struct em_rx_buffer   *rx_buffer;
-	int             i;
+	struct em_buffer   *rx_buffer;
+	int		i;
 
 	INIT_DEBUGOUT("free_receive_structures: begin");
 
 	if (sc->rx_buffer_area != NULL) {
 		rx_buffer = sc->rx_buffer_area;
 		for (i = 0; i < sc->num_rx_desc; i++, rx_buffer++) {
+			if (rx_buffer->map != NULL) {
+				bus_dmamap_unload(sc->rxtag, rx_buffer->map);
+				bus_dmamap_destroy(sc->rxtag, rx_buffer->map);
+			}
 			if (rx_buffer->m_head != NULL)
 				m_freem(rx_buffer->m_head);
 			rx_buffer->m_head = NULL;
-
-			bus_dmamap_unload(sc->osdep.em_pa.pa_dmat,
-			    rx_buffer->dmamap);
-			bus_dmamap_destroy(sc->osdep.em_pa.pa_dmat,
-			    rx_buffer->dmamap);
 		}
 	}
 	if (sc->rx_buffer_area != NULL) {
 		free(sc->rx_buffer_area, M_DEVBUF);
 		sc->rx_buffer_area = NULL;
 	}
+	if (sc->rxtag != NULL) {
+		/* bus_dma_tag_destroy(sc->rxtag); */
+		sc->rxtag = NULL;
+	}
 	return;
 }
 
@@ -1992,26 +2522,27 @@
  *  the mbufs in the descriptor and sends data which has been
  *  dma'ed into host memory to upper layer.
  *
+ *  We loop at most count times if count is > 0, or until done if
+ *  count < 0.
+ *
  *********************************************************************/
 void
-em_process_receive_interrupts(struct em_softc* sc)
+em_process_receive_interrupts(struct em_softc* sc, int count)
 {
-	struct mbuf         *mp;
-	struct ifnet        *ifp;
+	struct ifnet	    *ifp;
+	struct mbuf	    *mp;
 	struct ether_header *eh;
-	u_int16_t           len;
-	u_int8_t            last_byte;
-	u_int8_t            accept_frame = 0;
-	u_int8_t            eop = 0;
-	u_int32_t           pkt_len = 0;
+	u_int8_t	    accept_frame = 0;
+	u_int8_t	    eop = 0;
+	u_int16_t	    len, desc_len;
+	int		    i;
 
 	/* Pointer to the receive descriptor being examined. */
 	struct em_rx_desc   *current_desc;
-	struct em_rx_desc   *last_desc_processed;
-	struct em_rx_buffer *rx_buffer;
 
-	ifp = &sc->arpcom.ac_if;
-	current_desc = sc->next_rx_desc_to_check;
+	ifp = &sc->interface_data.ac_if;
+	i = sc->next_rx_desc_to_check;
+	current_desc = &sc->rx_desc_base[i];
 
 	if (!((current_desc->status) & E1000_RXD_STAT_DD)) {
 #ifdef DBG_STATS
@@ -2020,58 +2551,55 @@
 		return;
 	}
 
-	while (current_desc->status & E1000_RXD_STAT_DD) {
+	while ((current_desc->status & E1000_RXD_STAT_DD) && (count != 0)) {
 
-		/* Get a pointer to the actual receive buffer */
-		rx_buffer = SIMPLEQ_FIRST(&sc->rx_buffer_list);
-
-		if (rx_buffer == NULL) {
-			printf("%s: Found null rx_buffer\n",
-			       sc->sc_dv.dv_xname);
-			return;
-		}
+		mp = sc->rx_buffer_area[i].m_head;
+		bus_dmamap_sync(sc->rxtag, sc->rx_buffer_area[i].map,
+		    0, sc->rx_buffer_area[i].map->dm_mapsize,
+		    BUS_DMASYNC_POSTREAD);
+		bus_dmamap_unload(sc->rxtag, sc->rx_buffer_area[i].map);
 
-		mp = rx_buffer->m_head;      
 		accept_frame = 1;
-
+		desc_len = letoh16(current_desc->length);
 		if (current_desc->status & E1000_RXD_STAT_EOP) {
+			count--;
 			eop = 1;
-			len = letoh16(current_desc->length) - ETHER_CRC_LEN;
+			len = desc_len - ETHER_CRC_LEN;
 		} else {
 			eop = 0;
-			len = letoh16(current_desc->length);
+			len = desc_len;
 		}
 
 		if (current_desc->errors & E1000_RXD_ERR_FRAME_ERR_MASK) {
+			u_int8_t last_byte;
+			u_int32_t pkt_len = desc_len;
 
-			/* Compute packet length for tbi_accept macro */
-			pkt_len = letoh16(current_desc->length);
-			if (sc->fmp != NULL) {
+			if (sc->fmp != NULL)
 				pkt_len += sc->fmp->m_pkthdr.len; 
-			}
 
-			last_byte = *(mtod(rx_buffer->m_head,caddr_t) + 
-				      letoh16(current_desc->length) - 1);
+			last_byte = *(mtod(mp, caddr_t) + desc_len - 1);
 
-			if (TBI_ACCEPT(&sc->hw, current_desc->status, 
-				       current_desc->errors, 
+			if (TBI_ACCEPT(&sc->hw, current_desc->status,
+				       current_desc->errors,
 				       pkt_len, last_byte)) {
 				em_tbi_adjust_stats(&sc->hw, 
 						    &sc->stats, 
 						    pkt_len, 
 						    sc->hw.mac_addr);
 				len--;
-			} else {
+			}
+			else {
 				accept_frame = 0;
 			}
 		}
 
 		if (accept_frame) {
 
-			if (em_get_buf(rx_buffer, sc, NULL) == ENOBUFS) {
+			if (em_get_buf(i, sc, NULL) == ENOBUFS) {
 				sc->dropped_pkts++;
-				em_get_buf(rx_buffer, sc, mp);
-				if (sc->fmp != NULL) m_freem(sc->fmp);
+				em_get_buf(i, sc, mp);
+				if (sc->fmp != NULL)
+					m_freem(sc->fmp);
 				sc->fmp = NULL;
 				sc->lmp = NULL;
 				break;
@@ -2094,6 +2622,8 @@
 
 			if (eop) {
 				sc->fmp->m_pkthdr.rcvif = ifp;
+				ifp->if_ipackets++;
+
 #if NBPFILTER > 0
 				/*
 				 * Handle BPF listeners. Let the BPF
@@ -2103,19 +2633,19 @@
 					bpf_mtap(ifp->if_bpf, sc->fmp);
 #endif
 
-
 				eh = mtod(sc->fmp, struct ether_header *);
-
 				/* Remove ethernet header from mbuf */
 				m_adj(sc->fmp, sizeof(struct ether_header));
-				em_receive_checksum(sc, current_desc, 
-						    sc->fmp);
-#if 0
+				em_receive_checksum(sc, current_desc,
+						sc->fmp);
+
+#ifdef __FreeBSD__
 				if (current_desc->status & E1000_RXD_STAT_VP)
 					VLAN_INPUT_TAG(eh, sc->fmp, 
-					     letoh16(current_desc->special));
+					    (letoh16(current_desc->special) &
+					    E1000_RXD_SPC_VLAN_MASK));
 				else
-#endif /* 0 */
+#endif /* __FreeBSD__ */
 					ether_input(ifp, eh, sc->fmp);
 
 				sc->fmp = NULL;
@@ -2123,8 +2653,9 @@
 			}
 		} else {
 			sc->dropped_pkts++;
-			em_get_buf(rx_buffer, sc, mp);
-			if (sc->fmp != NULL) m_freem(sc->fmp);
+			em_get_buf(i, sc, mp);
+			if (sc->fmp != NULL)
+				m_freem(sc->fmp);
 			sc->fmp = NULL;
 			sc->lmp = NULL;
 		}
@@ -2132,34 +2663,17 @@
 		/* Zero out the receive descriptors status  */
 		current_desc->status = 0;
 
-		if (rx_buffer->m_head != NULL) {
-			current_desc->buffer_addr =
-				htole64(rx_buffer->buffer_addr);
-		}
-
-		/* Advance our pointers to the next descriptor
-		 * (checking for wrap). */
-		if (current_desc == sc->last_rx_desc)
-			sc->next_rx_desc_to_check = sc->first_rx_desc;
-		else
-			((sc)->next_rx_desc_to_check)++;
+		/* Advance the E1000's Receive Queue #0	 "Tail Pointer". */
+		E1000_WRITE_REG(&sc->hw, RDT, i);
 
-		last_desc_processed = current_desc;
-		current_desc = sc->next_rx_desc_to_check;
-		/* 
-		 * Put the buffer that we just indicated back at the
-		 * end of our list
-		 */
-		SIMPLEQ_REMOVE_HEAD(&sc->rx_buffer_list, rx_buffer,
-				    em_rx_entry);
-		SIMPLEQ_INSERT_TAIL(&sc->rx_buffer_list, 
-				   rx_buffer, em_rx_entry);
-
-		/* Advance the E1000's Receive Queue #0  "Tail Pointer". */
-		E1000_WRITE_REG(&sc->hw, RDT, 
-				(((u_long) last_desc_processed -
-				  (u_long) sc->first_rx_desc) >> 4));
+		/* Advance our pointers to the next descriptor */
+		if (++i == sc->num_rx_desc) {
+			i = 0;
+			current_desc = sc->rx_desc_base;
+		} else
+			current_desc++;
 	}
+	sc->next_rx_desc_to_check = i;
 	return;
 }
 
@@ -2175,7 +2689,7 @@
 		    struct em_rx_desc *rx_desc,
 		    struct mbuf *mp)
 {
-#if 0
+#ifdef __FreeBSD__
 	/* 82543 or newer only */
 	if ((sc->hw.mac_type < em_82543) ||
 	    /* Ignore Checksum bit is set */
@@ -2197,7 +2711,7 @@
 	}
 
 	if (rx_desc->status & E1000_RXD_STAT_TCPCS) {
-		/* Did it pass? */        
+		/* Did it pass? */	  
 		if (!(rx_desc->errors & E1000_RXD_ERR_TCPE)) {
 			mp->m_pkthdr.csum_flags |= 
 			(CSUM_DATA_VALID | CSUM_PSEUDO_HDR);
@@ -2206,7 +2720,7 @@
 	}
 
 	return;
-#endif /* 0 */
+#endif /* __FreeBSD__ */
 }
 
 
@@ -2214,7 +2728,7 @@
 {
 	uint32_t ctrl;
 
-	E1000_WRITE_REG(&sc->hw, VET, QTAG_TYPE);
+	E1000_WRITE_REG(&sc->hw, VET, ETHERTYPE_8021Q);
 
 	ctrl = E1000_READ_REG(&sc->hw, CTRL);
 	ctrl |= E1000_CTRL_VME; 
@@ -2238,47 +2752,76 @@
 	return;
 }
 
-void em_write_pci_cfg(struct em_hw *hw,
+int
+em_is_valid_ether_addr(u_int8_t *addr)
+{
+	const char zero_addr[6] = { 0, 0, 0, 0, 0, 0 };
+
+	if ((addr[0] & 1) || (!bcmp(addr, zero_addr, ETHER_ADDR_LEN))) {
+		return (FALSE);
+	}
+
+	return(TRUE);
+}
+
+void
+em_write_pci_cfg(struct em_hw *hw,
 		      uint32_t reg,
 		      uint16_t *value)
 {
-        struct pci_attach_args *pa = &((struct em_osdep *)hw->back)->em_pa;
+	struct pci_attach_args *pa = &((struct em_osdep *)hw->back)->em_pa;
 	pci_chipset_tag_t pc = pa->pa_pc;
+	/* Should we do read/mask/write...?  16 vs 32 bit!!! */
 	pci_conf_write(pc, pa->pa_tag, reg, *value);
 }
 
-void em_read_pci_cfg(struct em_hw *hw, uint32_t reg,
+void
+em_read_pci_cfg(struct em_hw *hw, uint32_t reg,
 		     uint16_t *value)
 {
-        struct pci_attach_args *pa = &((struct em_osdep *)hw->back)->em_pa;
+	struct pci_attach_args *pa = &((struct em_osdep *)hw->back)->em_pa;
 	pci_chipset_tag_t pc = pa->pa_pc;
 	*value = pci_conf_read(pc, pa->pa_tag, reg);
 	return;
 }
 
-uint32_t em_io_read(struct em_hw *hw, uint32_t port)
+void
+em_pci_set_mwi(struct em_hw *hw)
 {
-#if 0
-	return(inl(port));
-#endif
-	return bus_space_read_4(
-                ((struct em_osdep *)(hw)->back)->em_iobtag,
-		((struct em_osdep *)(hw)->back)->em_iobhandle,
-		port);
+	struct pci_attach_args *pa = &((struct em_osdep *)hw->back)->em_pa;
+	pci_chipset_tag_t pc = pa->pa_pc;
+	/* Should we do read/mask/write...?  16 vs 32 bit!!! */
+	pci_conf_write(pc, pa->pa_tag, PCI_COMMAND_STATUS_REG,
+		(hw->pci_cmd_word | CMD_MEM_WRT_INVALIDATE));
+
 }
 
-void em_io_write(struct em_hw *hw, uint32_t port, uint32_t value)
+void
+em_pci_clear_mwi(struct em_hw *hw)
 {
-#if 0
-	outl(port, value);
-#endif
-	bus_space_write_4(
-			((struct em_osdep *)(hw)->back)->em_iobtag,
-			((struct em_osdep *)(hw)->back)->em_iobhandle,
-			port,
+	struct pci_attach_args *pa = &((struct em_osdep *)hw->back)->em_pa;
+	pci_chipset_tag_t pc = pa->pa_pc;
+	/* Should we do read/mask/write...?  16 vs 32 bit!!! */
+	pci_conf_write(pc, pa->pa_tag, PCI_COMMAND_STATUS_REG,
+		(hw->pci_cmd_word & ~CMD_MEM_WRT_INVALIDATE));
+
+}
+
+uint32_t
+em_io_read(struct em_hw *hw, uint32_t port)
+{
+	return bus_space_read_4(((struct em_osdep *)(hw)->back)->em_iobtag,
+		((struct em_osdep *)(hw)->back)->em_iobhandle, port);
+}
+
+void
+em_io_write(struct em_hw *hw, uint32_t port, uint32_t value)
+{
+	bus_space_write_4(((struct em_osdep *)(hw)->back)->em_iobtag,
+			((struct em_osdep *)(hw)->back)->em_iobhandle, port,
 			value);
 	return;
-} 
+}
 
 /**********************************************************************
  *
@@ -2295,6 +2838,7 @@
 	sc->stats.mpc += E1000_READ_REG(&sc->hw, MPC);
 	sc->stats.scc += E1000_READ_REG(&sc->hw, SCC);
 	sc->stats.ecol += E1000_READ_REG(&sc->hw, ECOL);
+
 	sc->stats.mcc += E1000_READ_REG(&sc->hw, MCC);
 	sc->stats.latecol += E1000_READ_REG(&sc->hw, LATECOL);
 	sc->stats.colc += E1000_READ_REG(&sc->hw, COLC);
@@ -2361,11 +2905,9 @@
 		sc->stats.tsctfc += 
 		E1000_READ_REG(&sc->hw, TSCTFC);
 	}
-	ifp = &sc->arpcom.ac_if;
+	ifp = &sc->interface_data.ac_if;
 
 	/* Fill out the OS statistics structure */
-	ifp->if_ipackets = sc->stats.gprc;
-	ifp->if_opackets = sc->stats.gptc;
 	ifp->if_ibytes = sc->stats.gorcl;
 	ifp->if_obytes = sc->stats.gotcl;
 	ifp->if_imcasts = sc->stats.mprc;
@@ -2394,200 +2936,126 @@
  *
  **********************************************************************/
 void
-em_print_hw_stats(struct em_softc *sc)
+em_print_debug_info(struct em_softc *sc)
 {
+	const char * const unit = sc->sc_dv.dv_xname;
+
 #ifdef DBG_STATS
-	printf("%s: Packets not Avail = %ld\n", sc->sc_dv.dv_xname, 
+	printf("%s: Packets not Avail = %ld\n", unit, 
 	       sc->no_pkts_avail);
-	printf("%s: CleanTxInterrupts = %ld\n", sc->sc_dv.dv_xname, 
+	printf("%s: CleanTxInterrupts = %ld\n", unit,
 	       sc->clean_tx_interrupts);
 #endif
+	printf("%s: fifo workaround = %lld, fifo_reset = %lld\n", unit,
+		(long long)sc->tx_fifo_wrk,
+		(long long)sc->tx_fifo_reset);
+	printf("%s: hw tdh = %d, hw tdt = %d\n", unit,
+		E1000_READ_REG(&sc->hw, TDH),
+		E1000_READ_REG(&sc->hw, TDT));
+	printf("%s: Num Tx Descriptors avail = %ld\n", unit,
+	       sc->num_tx_desc_avail);
+	printf("%s: Tx Descriptors not avail1 = %ld\n", unit,
+	       sc->no_tx_desc_avail1);
+	printf("%s: Tx Descriptors not avail2 = %ld\n", unit,
+	       sc->no_tx_desc_avail2);
+	printf("%s: Std mbuf failed = %ld\n", unit,
+		sc->mbuf_alloc_failed);
+	printf("%s: Std mbuf cluster failed = %ld\n", unit,
+		sc->mbuf_cluster_failed);
+	printf("%s: Driver dropped packets = %ld\n", unit,
+	       sc->dropped_pkts);
+
+	return;
+}
 
-	printf("%s: Tx Descriptors not Avail = %ld\n", sc->sc_dv.dv_xname, 
-	       sc->no_tx_desc_avail);
-	printf("%s: Tx Buffer not avail1 = %ld\n", sc->sc_dv.dv_xname, 
-	       sc->no_tx_buffer_avail1);
-	printf("%s: Tx Buffer not avail2 = %ld\n", sc->sc_dv.dv_xname, 
-	       sc->no_tx_buffer_avail2);
-	printf("%s: Std Mbuf Failed = %ld\n",sc->sc_dv.dv_xname, 
-	       sc->mbuf_alloc_failed);
-	printf("%s: Std Cluster Failed = %ld\n",sc->sc_dv.dv_xname, 
-	       sc->mbuf_cluster_failed);
+void
+em_print_hw_stats(struct em_softc *sc)
+{
+	const char * const unit = sc->sc_dv.dv_xname;
 
-	printf("%s: Symbol errors = %lld\n", sc->sc_dv.dv_xname, 
+	printf("%s: Excessive collisions = %lld\n", unit,
+		(long long)sc->stats.ecol);
+	printf("%s: Symbol errors = %lld\n", unit,
 	       (long long)sc->stats.symerrs);
-	printf("%s: Sequence errors = %lld\n", sc->sc_dv.dv_xname, 
+	printf("%s: Sequence errors = %lld\n", unit,
 	       (long long)sc->stats.sec);
-	printf("%s: Defer count = %lld\n", sc->sc_dv.dv_xname, 
+	printf("%s: Defer count = %lld\n", unit,
 	       (long long)sc->stats.dc);
 
-	printf("%s: Missed Packets = %lld\n", sc->sc_dv.dv_xname, 
+	printf("%s: Missed Packets = %lld\n", unit,
 	       (long long)sc->stats.mpc);
-	printf("%s: Receive No Buffers = %lld\n", sc->sc_dv.dv_xname, 
+	printf("%s: Receive No Buffers = %lld\n", unit,
 	       (long long)sc->stats.rnbc);
-	printf("%s: Receive length errors = %lld\n", sc->sc_dv.dv_xname, 
+	printf("%s: Receive length errors = %lld\n", unit,
 	       (long long)sc->stats.rlec);
-	printf("%s: Receive errors = %lld\n", sc->sc_dv.dv_xname, 
+	printf("%s: Receive errors = %lld\n", unit,
 	       (long long)sc->stats.rxerrc);
-	printf("%s: Crc errors = %lld\n", sc->sc_dv.dv_xname, 
+	printf("%s: Crc errors = %lld\n", unit,
 	       (long long)sc->stats.crcerrs);
-	printf("%s: Alignment errors = %lld\n", sc->sc_dv.dv_xname, 
+	printf("%s: Alignment errors = %lld\n", unit,
 	       (long long)sc->stats.algnerrc);
-	printf("%s: Carrier extension errors = %lld\n", sc->sc_dv.dv_xname,
+	printf("%s: Carrier extension errors = %lld\n", unit,
 	       (long long)sc->stats.cexterr);
-	printf("%s: Driver dropped packets = %ld\n", sc->sc_dv.dv_xname, 
-	       sc->dropped_pkts);
 
-	printf("%s: XON Rcvd = %lld\n", sc->sc_dv.dv_xname, 
+	printf("%s: XON Rcvd = %lld\n", unit,
 	       (long long)sc->stats.xonrxc);
-	printf("%s: XON Xmtd = %lld\n", sc->sc_dv.dv_xname, 
+	printf("%s: XON Xmtd = %lld\n", unit,
 	       (long long)sc->stats.xontxc);
-	printf("%s: XOFF Rcvd = %lld\n", sc->sc_dv.dv_xname, 
+	printf("%s: XOFF Rcvd = %lld\n", unit,
 	       (long long)sc->stats.xoffrxc);
-	printf("%s: XOFF Xmtd = %lld\n", sc->sc_dv.dv_xname, 
+	printf("%s: XOFF Xmtd = %lld\n", unit,
 	       (long long)sc->stats.xofftxc);
 
-	printf("%s: Good Packets Rcvd = %lld\n", sc->sc_dv.dv_xname,
+	printf("%s: Good Packets Rcvd = %lld\n", unit,
 	       (long long)sc->stats.gprc);
-	printf("%s: Good Packets Xmtd = %lld\n", sc->sc_dv.dv_xname,
+	printf("%s: Good Packets Xmtd = %lld\n", unit,
 	       (long long)sc->stats.gptc);
-}
 
+	return;
+}
 
-/**********************************************************************
- *
- *  Examine each tx_buffer in the used queue. If the hardware is done
- *  processing the packet then free associated resources. The
- *  tx_buffer is put back on the free queue. 
- *
- **********************************************************************/
-void
-em_clean_transmit_interrupts(struct em_softc* sc)
+#ifdef __FreeBSD__
+int
+em_sysctl_debug_info(SYSCTL_HANDLER_ARGS)
 {
-	struct em_tx_buffer *tx_buffer;
-	struct em_tx_desc   *tx_desc;
-	int             s;
-	struct ifnet   *ifp;
-
-	s = splimp();
-#ifdef DBG_STATS
-	sc->clean_tx_interrupts++;
-#endif
+	int error;
+	int result;
+	struct em_softc *sc;
 
-	for (tx_buffer = SIMPLEQ_FIRST(&sc->used_tx_buffer_list);
-	    tx_buffer; 
-	    tx_buffer = SIMPLEQ_FIRST(&sc->used_tx_buffer_list)) {
-
-		/* 
-		 * Get hold of the next descriptor that the em will
-		 * report status back to (this will be the last
-		 * descriptor of a given tx_buffer). We only want to
-		 * free the tx_buffer (and it resources) if the driver
-		 * is done with ALL of the descriptors.  If the driver
-		 * is done with the last one then it is done with all
-		 * of them.
-		 */
-
-		tx_desc = sc->oldest_used_tx_desc +
-			  (tx_buffer->num_tx_desc_used - 1);
-
-		/* Check for wrap case */
-		if (tx_desc > sc->last_tx_desc)
-			tx_desc -= sc->num_tx_desc;
-
-
-		/* 
-		 * If the descriptor done bit is set free tx_buffer
-		 * and associated resources
-		 */
-		if (tx_desc->upper.fields.status & E1000_TXD_STAT_DD) {
-
-			SIMPLEQ_REMOVE_HEAD(&sc->used_tx_buffer_list, 
-					   tx_buffer,
-					   em_tx_entry);
-
-			if ((tx_desc == sc->last_tx_desc))
-				sc->oldest_used_tx_desc =
-				sc->first_tx_desc;
-			else
-				sc->oldest_used_tx_desc = (tx_desc + 1);
-
-			/* Make available the descriptors that were
-			 * previously used */
-			sc->num_tx_desc_avail +=
-			tx_buffer->num_tx_desc_used;
-
-			tx_buffer->num_tx_desc_used = 0;
-
-			if (tx_buffer->m_head) {
-				m_freem(tx_buffer->m_head);
-				tx_buffer->m_head = NULL;
-			}
-			/* Return this "Software packet" back to the
-			 * "free" list */
-			SIMPLEQ_INSERT_TAIL(&sc->free_tx_buffer_list, 
-					   tx_buffer, em_tx_entry);
-		} else {
-			/* 
-			 * Found a tx_buffer that the em is not done
-			 * with then there is no reason to check the
-			 * rest of the queue.
-			 */
-			break;
-		}
-	}		      /* end for each tx_buffer */
+	result = -1;
+	error = sysctl_handle_int(oidp, &result, 0, req);
 
-	ifp = &sc->arpcom.ac_if;
+	if (error || !req->newptr)
+		return (error);
 
-	/* Tell the stack that it is OK to send packets */
-	if (sc->num_tx_desc_avail > TX_CLEANUP_THRESHOLD) {
-		ifp->if_timer = 0;
-		ifp->if_flags &= ~IFF_OACTIVE;
+	if (result == 1) {
+		sc = (struct em_softc *)arg1;
+		em_print_debug_info(sc);
 	}
-	splx(s);
-	return;
+
+	return error;
 }
 
-int em_malloc_dma(struct em_softc *sc, struct em_dmamap *emm,
-			 bus_size_t size)
+
+int
+em_sysctl_stats(SYSCTL_HANDLER_ARGS)
 {
-	bus_dma_tag_t	dma_tag = sc->osdep.em_pa.pa_dmat;
+	int error;
+	int result;
+	struct em_softc *sc;
 
-	emm->emm_size = size;
+	result = -1;
+	error = sysctl_handle_int(oidp, &result, 0, req);
 
-        if (bus_dmamem_alloc(dma_tag, size, PAGE_SIZE, 0, &emm->emm_seg, 1,
-			     &emm->emm_rseg, BUS_DMA_NOWAIT)) {
-		goto fail0;
-        }
-        if (bus_dmamem_map(dma_tag, &emm->emm_seg, emm->emm_rseg, size,
-			   &emm->emm_kva, BUS_DMA_NOWAIT)) {
-		goto fail1;
-        }
-        if (bus_dmamap_create(dma_tag, size, 1, size, 0, BUS_DMA_NOWAIT,
-			      &emm->emm_dmamap)) {
-		goto fail2;
-        }
-        if (bus_dmamap_load(dma_tag, emm->emm_dmamap, emm->emm_kva, size,
-			    NULL, BUS_DMA_NOWAIT)) {
-		goto fail3;
-        }
-       	 
-	return 0;
+	if (error || !req->newptr)
+		return (error);
 
- fail3:
-	bus_dmamap_destroy(dma_tag, emm->emm_dmamap);
- fail2:
-	bus_dmamem_unmap(dma_tag, emm->emm_kva, size);
- fail1:
-	bus_dmamem_free(dma_tag, &emm->emm_seg, emm->emm_rseg);
- fail0:
-	return (ENOBUFS);
-}
-
-void em_free_dma(struct em_softc *sc, struct em_dmamap *emm)
-{
-	bus_dmamap_unload(sc->osdep.em_pa.pa_dmat, emm->emm_dmamap);
-	bus_dmamap_destroy(sc->osdep.em_pa.pa_dmat, emm->emm_dmamap);
-	bus_dmamem_unmap(sc->osdep.em_pa.pa_dmat, emm->emm_kva, emm->emm_size);
-	bus_dmamem_free(sc->osdep.em_pa.pa_dmat, &emm->emm_seg, emm->emm_rseg);
+	if (result == 1) {
+		sc = (struct em_softc *)arg1;
+		em_print_hw_stats(sc);
+	}
+
+	return error;
 }
+#endif /* __FreeBSD__ */
+
Index: dev/pci/if_em.h
===================================================================
RCS file: /u/open/cvs/src/sys/dev/pci/if_em.h,v
retrieving revision 1.1
diff -u -r1.1 if_em.h
--- dev/pci/if_em.h	24 Sep 2002 18:56:02 -0000	1.1
+++ dev/pci/if_em.h	14 Jul 2004 21:32:07 -0000
@@ -1,39 +1,38 @@
 /**************************************************************************
 
-Copyright (c) 2001-2002 Intel Corporation
+Copyright (c) 2001-2003, Intel Corporation
 All rights reserved.
 
-Redistribution and use in source and binary forms of the Software, with or
-without modification, are permitted provided that the following conditions
-are met:
-
- 1. Redistributions of source code of the Software may retain the above
-    copyright notice, this list of conditions and the following disclaimer.
-
- 2. Redistributions in binary form of the Software may reproduce the above
-    copyright notice, this list of conditions and the following disclaimer
-    in the documentation and/or other materials provided with the
-    distribution.
+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 shall be used to endorse or promote products derived from
-    this Software without specific prior written permission.
+    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 INTEL OR ITS 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.
+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.
 
 ***************************************************************************/
 
-/*$FreeBSD$*/
+/*$FreeBSD: if_em.h,v 1.16 2003/06/05 17:51:38 pdeuskar Exp $*/
+/* $OpenBSD: if_em.h,v 1.2 2003/06/13 19:21:21 henric Exp $ */
 
 #ifndef _EM_H_DEFINED_
 #define _EM_H_DEFINED_
@@ -41,35 +40,149 @@
 #include <dev/pci/if_em_hw.h>
 
 /* Tunables */
-#define MAX_TXD                         256
-#define MAX_RXD                         256
-#define TX_CLEANUP_THRESHOLD            MAX_TXD / 8
-#define TIDV                            128     
-#define RIDV                            28      
-#define DO_AUTO_NEG                     1       
-#define WAIT_FOR_AUTO_NEG_DEFAULT       1       
-#define AUTONEG_ADV_DEFAULT             (ADVERTISE_10_HALF |	\
-					 ADVERTISE_10_FULL |	\
-                                         ADVERTISE_100_HALF |	\
-					 ADVERTISE_100_FULL |	\
-                                         ADVERTISE_1000_FULL)
-#define EM_REPORT_TX_EARLY              2
-#define EM_CHECKSUM_FEATURES            (CSUM_TCP | CSUM_UDP)
+
+/*
+ * TxDescriptors
+ * Valid Range: 80-256 for 82542 and 82543-based adapters
+ *              80-4096 for others
+ * Default Value: 256
+ *   This value is the number of transmit descriptors allocated by the driver.
+ *   Increasing this value allows the driver to queue more transmits. Each
+ *   descriptor is 16 bytes.
+ */
+#define EM_MAX_TXD                      256
+
+/*
+ * RxDescriptors
+ * Valid Range: 80-256 for 82542 and 82543-based adapters
+ *              80-4096 for others
+ * Default Value: 256
+ *   This value is the number of receive descriptors allocated by the driver.
+ *   Increasing this value allows the driver to buffer more incoming packets.
+ *   Each descriptor is 16 bytes.  A receive buffer is also allocated for each
+ *   descriptor. The maximum MTU size is 16110.
+ *
+ */
+#define EM_MAX_RXD                      256
+
+/*
+ * TxIntDelay
+ * Valid Range: 0-65535 (0=off)
+ * Default Value: 64
+ *   This value delays the generation of transmit interrupts in units of
+ *   1.024 microseconds. Transmit interrupt reduction can improve CPU
+ *   efficiency if properly tuned for specific network traffic. If the
+ *   system is reporting dropped transmits, this value may be set too high
+ *   causing the driver to run out of available transmit descriptors.
+ */
+#define EM_TIDV                         64
+
+/*
+ * TxAbsIntDelay (Not valid for 82542 and 82543)
+ * Valid Range: 0-65535 (0=off)
+ * Default Value: 64
+ *   This value, in units of 1.024 microseconds, limits the delay in which a
+ *   transmit interrupt is generated. Useful only if TxIntDelay is non-zero,
+ *   this value ensures that an interrupt is generated after the initial
+ *   packet is sent on the wire within the set amount of time.  Proper tuning,
+ *   along with TxIntDelay, may improve traffic throughput in specific
+ *   network conditions.
+ */
+#define EM_TADV                         64
+
+/*
+ * RxIntDelay
+ * Valid Range: 0-65535 (0=off)
+ * Default Value: 0
+ *   This value delays the generation of receive interrupts in units of 1.024
+ *   microseconds.  Receive interrupt reduction can improve CPU efficiency if
+ *   properly tuned for specific network traffic. Increasing this value adds
+ *   extra latency to frame reception and can end up decreasing the throughput
+ *   of TCP traffic. If the system is reporting dropped receives, this value
+ *   may be set too high, causing the driver to run out of available receive
+ *   descriptors.
+ *
+ *   CAUTION: When setting RxIntDelay to a value other than 0, adapters
+ *            may hang (stop transmitting) under certain network conditions.
+ *            If this occurs a WATCHDOG message is logged in the system event log.
+ *            In addition, the controller is automatically reset, restoring the
+ *            network connection. To eliminate the potential for the hang
+ *            ensure that RxIntDelay is set to 0.
+ */
+#define EM_RDTR                         0
+
+/*
+ * RxAbsIntDelay (Not valid for 82542 and 82543)
+ * Valid Range: 0-65535 (0=off)
+ * Default Value: 64
+ *   This value, in units of 1.024 microseconds, limits the delay in which a
+ *   receive interrupt is generated. Useful only if RxIntDelay is non-zero,
+ *   this value ensures that an interrupt is generated after the initial
+ *   packet is received within the set amount of time.  Proper tuning,
+ *   along with RxIntDelay, may improve traffic throughput in specific network
+ *   conditions.
+ */
+#define EM_RADV                         64
+
+
+/*
+ * This parameter controls the maximum no of times the driver will loop
+ * in the isr.
+ *           Minimum Value = 1
+ */
 #define EM_MAX_INTR                     3
+
+/*
+ * Inform the stack about transmit checksum offload capabilities.
+ */
+#define EM_CHECKSUM_FEATURES            (CSUM_TCP | CSUM_UDP)
+
+/*
+ * This parameter controls the duration of transmit watchdog timer.
+ */
 #define EM_TX_TIMEOUT                   5    /* set to 5 seconds */
 
+/*
+ * This parameter controls when the driver calls the routine to reclaim
+ * transmit descriptors.
+ */
+#define EM_TX_CLEANUP_THRESHOLD         EM_MAX_TXD / 8
+
+/*
+ * This parameter controls whether or not autonegotation is enabled.
+ *              0 - Disable autonegotiation
+ *              1 - Enable  autonegotiation
+ */
+#define DO_AUTO_NEG                     1
+
+/*
+ * This parameter control whether or not the driver will wait for
+ * autonegotiation to complete.
+ *              1 - Wait for autonegotiation to complete
+ *              0 - Don't wait for autonegotiation to complete
+ */
+#define WAIT_FOR_AUTO_NEG_DEFAULT       0
+
+
+/* Tunables -- End */
+
+#define AUTONEG_ADV_DEFAULT      (ADVERTISE_10_HALF | ADVERTISE_10_FULL | \
+                                  ADVERTISE_100_HALF | ADVERTISE_100_FULL | \
+                                  ADVERTISE_1000_FULL)
 
 #define EM_VENDOR_ID                    0x8086
 #define EM_MMBA                         0x0010 /* Mem base address */
 #define EM_ROUNDUP(size, unit) (((size) + (unit) - 1) & ~((unit) - 1))
+
 #define EM_JUMBO_PBA                    0x00000028
 #define EM_DEFAULT_PBA                  0x00000030
+#define EM_SMARTSPEED_DOWNSHIFT         3
+#define EM_SMARTSPEED_MAX               15
+
 
-#define IOCTL_CMD_TYPE                  u_long
 #define MAX_NUM_MULTICAST_ADDRESSES     128
 #define PCI_ANY_ID                      (~0U)
 #define ETHER_ALIGN                     2
-#define QTAG_TYPE                       0x8100
 
 /* Defines for printing debug information */
 #define DEBUG_INIT  0
@@ -93,23 +206,58 @@
 #define EM_RXBUFFER_8192        8192
 #define EM_RXBUFFER_16384      16384
 
-struct em_tx_buffer {
-	SIMPLEQ_ENTRY(em_tx_buffer) em_tx_entry;
-	struct mbuf    *m_head;
-	bus_dmamap_t	dmamap;
-	u_int32_t       num_tx_desc_used;
-};
+#define EM_MAX_SCATTER            64
 
+#ifdef __FreeBSD__
+#ifdef __alpha__
+       #undef vtophys
+       #define vtophys(va)     alpha_XXX_dmamap((vm_offset_t)(va))
+#endif /* __alpha__ */
+#endif /* __FreeBSD__ */
 
 /* ******************************************************************************
- * This structure stores information about the 2k aligned receive buffer
- * into which the E1000 DMA's frames. 
+ * vendor_info_array
+ *
+ * This array contains the list of Subvendor/Subdevice IDs on which the driver
+ * should load.
+ *
  * ******************************************************************************/
-struct em_rx_buffer {
-	SIMPLEQ_ENTRY(em_rx_buffer) em_rx_entry;
-	struct mbuf    *m_head;
-	bus_dmamap_t	dmamap;
-	u_int64_t	buffer_addr;
+#ifdef __FreeBSD__
+typedef struct _em_vendor_info_t {
+        unsigned int vendor_id;
+        unsigned int device_id;
+        unsigned int subvendor_id;
+        unsigned int subdevice_id;
+        unsigned int index;
+} em_vendor_info_t;
+#endif /* __FreeBSD__ */
+
+
+struct em_buffer {
+        struct mbuf    *m_head;
+	bus_dmamap_t	map;		/* bus_dma map for packet */
+};
+
+struct em_q {
+	bus_dmamap_t       map;         /* bus_dma map for packet */
+#ifdef __FreeBSD__
+	int                nsegs;       /* # of segments/descriptors */
+	bus_dma_segment_t  segs[EM_MAX_SCATTER];
+#endif /* __FreeBSD__ */
+};
+
+/*
+ * Bus dma allocation structure used by
+ * em_dma_malloc and em_dma_free.
+ */
+struct em_dma_alloc {
+	bus_addr_t              dma_paddr;
+	caddr_t                 dma_vaddr;
+	bus_dma_tag_t           dma_tag;
+	bus_dmamap_t            dma_map;
+	bus_dma_segment_t       dma_seg;
+	bus_size_t              dma_size;
+	int                     dma_nseg;
 };
 
 typedef enum _XSUM_CONTEXT_T {
@@ -121,68 +269,92 @@
 /* Our adapter structure */
 struct em_softc {
 	struct device	sc_dv;
-	struct arpcom	arpcom;         /* interface info */
+	struct arpcom	interface_data;
+	struct em_softc *next;
+	struct em_softc *prev;
 	struct em_hw    hw;
 
 	/* FreeBSD operating-system-specific structures */
 	struct em_osdep osdep;
 
 	int             io_rid;
-	void                    *sc_intrhand;
+	void           *sc_intrhand;
 	struct ifmedia  media;
-	struct timeout	em_timeout;
+
+	struct timeout	em_intr_enable;
+	struct timeout	timer_handle;
+	struct timeout	tx_fifo_timer_handle;
 
 	/* Info about the board itself */
 	u_int32_t       part_num;
 	u_int8_t        link_active;
 	u_int16_t       link_speed;
 	u_int16_t       link_duplex;
+	u_int32_t       smartspeed;
 	u_int32_t       tx_int_delay;
+	u_int32_t	tx_abs_int_delay;
 	u_int32_t       rx_int_delay;
+	u_int32_t	rx_abs_int_delay;
 
 	XSUM_CONTEXT_T  active_checksum_context;
 
-	/* Transmit definitions */
-	struct em_tx_desc *first_tx_desc;
-	struct em_tx_desc *last_tx_desc;
-	struct em_tx_desc *next_avail_tx_desc;
-	struct em_tx_desc *oldest_used_tx_desc;
-	struct em_tx_desc *tx_desc_base;
-	volatile u_int16_t num_tx_desc_avail;
-	u_int16_t       num_tx_desc;
-	u_int32_t       txd_cmd;
-	struct em_tx_buffer   *tx_buffer_area;
-	SIMPLEQ_HEAD(__em_tx_buffer_free, em_tx_buffer)  free_tx_buffer_list;
-	SIMPLEQ_HEAD(__em_tx_buffer_used, em_tx_buffer)  used_tx_buffer_list;
-
-	/* Receive definitions */
-	struct em_rx_desc *first_rx_desc;
-	struct em_rx_desc *last_rx_desc;
-	struct em_rx_desc *next_rx_desc_to_check;
-	struct em_rx_desc *rx_desc_base;
-	u_int16_t       num_rx_desc;
-	u_int32_t       rx_buffer_len;
-	struct em_rx_buffer   *rx_buffer_area;
-	SIMPLEQ_HEAD(__em_rx_buffer, em_rx_buffer)  rx_buffer_list;
+        /*
+         * Transmit definitions
+         *
+         * We have an array of num_tx_desc descriptors (handled
+         * by the controller) paired with an array of tx_buffers
+         * (at tx_buffer_area).
+         * The index of the next available descriptor is next_avail_tx_desc.
+         * The number of remaining tx_desc is num_tx_desc_avail.
+         */
+	struct em_dma_alloc	txdma;		/* bus_dma glue for tx desc */
+	struct em_tx_desc	*tx_desc_base;
+	u_int32_t		next_avail_tx_desc;
+	u_int32_t		oldest_used_tx_desc;
+	volatile u_int16_t	num_tx_desc_avail;
+	u_int16_t		num_tx_desc;
+	u_int32_t		txd_cmd;
+	struct em_buffer	*tx_buffer_area;
+	bus_dma_tag_t		txtag;		/* dma tag for tx */
+
+        /*
+         * Receive definitions
+         *
+         * we have an array of num_rx_desc rx_desc (handled by the
+         * controller), and paired with an array of rx_buffers
+         * (at rx_buffer_area).
+         * The next pair to check on receive is at offset next_rx_desc_to_check
+         */
+	struct em_dma_alloc	rxdma;		/* bus_dma glue for rx desc */
+	struct em_rx_desc	*rx_desc_base;
+	u_int32_t		next_rx_desc_to_check;
+	u_int16_t		num_rx_desc;
+	u_int32_t		rx_buffer_len;
+	struct em_buffer	*rx_buffer_area;
+	bus_dma_tag_t		rxtag;
 
 	/* Jumbo frame */
-	struct mbuf     *fmp;
-	struct mbuf     *lmp;
+	struct mbuf        *fmp;
+	struct mbuf        *lmp;
+
+	u_int16_t          tx_fifo_head;
 
 	/* Misc stats maintained by the driver */
 	unsigned long   dropped_pkts;
 	unsigned long   mbuf_alloc_failed;
 	unsigned long   mbuf_cluster_failed;
-	unsigned long   xmit_pullup;
-	unsigned long   no_tx_desc_avail;
-	unsigned long   no_tx_buffer_avail1;
-	unsigned long   no_tx_buffer_avail2;
+	unsigned long   no_tx_desc_avail1;
+	unsigned long   no_tx_desc_avail2;
+	unsigned long   no_tx_map_avail;
+        unsigned long   no_tx_dma_setup;
+	u_int64_t       tx_fifo_reset;
+	u_int64_t       tx_fifo_wrk;
+
 #ifdef DBG_STATS
 	unsigned long   no_pkts_avail;
 	unsigned long   clean_tx_interrupts;
 
 #endif
-
 	struct em_hw_stats stats;
 };
 
Index: dev/pci/if_em_hw.c
===================================================================
RCS file: /u/open/cvs/src/sys/dev/pci/if_em_hw.c,v
retrieving revision 1.1
diff -u -r1.1 if_em_hw.c
--- dev/pci/if_em_hw.c	24 Sep 2002 18:56:02 -0000	1.1
+++ dev/pci/if_em_hw.c	14 Jul 2004 21:32:07 -0000
@@ -1,39 +1,38 @@
-/**************************************************************************
+/*******************************************************************************
 
-Copyright (c) 2001-2002 Intel Corporation
-All rights reserved.
+  Copyright (c) 2001-2003, 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.
 
-Redistribution and use in source and binary forms of the Software, with or
-without modification, are permitted provided that the following conditions
-are met:
-
- 1. Redistributions of source code of the Software may retain the above
-    copyright notice, this list of conditions and the following disclaimer.
-
- 2. Redistributions in binary form of the Software may 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 shall 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 INTEL OR ITS 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.
+*******************************************************************************/
 
-***************************************************************************/
-
-/*$FreeBSD$*/
+/*$FreeBSD: if_em_hw.c,v 1.9 2003/06/05 17:51:38 pdeuskar Exp $*/
+/* $OpenBSD: if_em_hw.c,v 1.2 2003/06/13 19:21:21 henric Exp $ */
 /* if_em_hw.c
  * Shared functions for accessing and configuring the MAC
  */
@@ -79,6 +78,8 @@
 
 #include <dev/pci/if_em_hw.h>
 
+static int32_t em_set_phy_type(struct em_hw *hw);
+static void em_phy_init_script(struct em_hw *hw);
 static int32_t em_setup_fiber_link(struct em_hw *hw);
 static int32_t em_setup_copper_link(struct em_hw *hw);
 static int32_t em_phy_force_speed_duplex(struct em_hw *hw);
@@ -89,14 +90,165 @@
 static void em_shift_out_mdi_bits(struct em_hw *hw, uint32_t data, uint16_t count);
 static uint16_t em_shift_in_mdi_bits(struct em_hw *hw);
 static int32_t em_phy_reset_dsp(struct em_hw *hw);
+static int32_t em_write_eeprom_spi(struct em_hw *hw, uint16_t offset,
+                                      uint16_t words, uint16_t *data);
+static int32_t em_write_eeprom_microwire(struct em_hw *hw,
+                                            uint16_t offset, uint16_t words,
+                                            uint16_t *data);
+static int32_t em_spi_eeprom_ready(struct em_hw *hw);
 static void em_raise_ee_clk(struct em_hw *hw, uint32_t *eecd);
 static void em_lower_ee_clk(struct em_hw *hw, uint32_t *eecd);
 static void em_shift_out_ee_bits(struct em_hw *hw, uint16_t data, uint16_t count);
-static uint16_t em_shift_in_ee_bits(struct em_hw *hw);
-static void em_setup_eeprom(struct em_hw *hw);
+static uint16_t em_shift_in_ee_bits(struct em_hw *hw, uint16_t count);
+static int32_t em_acquire_eeprom(struct em_hw *hw);
+static void em_release_eeprom(struct em_hw *hw);
 static void em_standby_eeprom(struct em_hw *hw);
 static int32_t em_id_led_init(struct em_hw * hw);
 
+
+
+/******************************************************************************
+ * Set the phy type member in the hw struct.
+ *
+ * hw - Struct containing variables accessed by shared code
+ *****************************************************************************/
+int32_t
+em_set_phy_type(struct em_hw *hw)
+{
+    DEBUGFUNC("em_set_phy_type");
+
+    switch(hw->phy_id) {
+    case M88E1000_E_PHY_ID:
+    case M88E1000_I_PHY_ID:
+    case M88E1011_I_PHY_ID:
+        hw->phy_type = em_phy_m88;
+        break;
+    case IGP01E1000_I_PHY_ID:
+        hw->phy_type = em_phy_igp;
+        break;
+    default:
+        /* Should never have loaded on this device */
+        hw->phy_type = em_phy_undefined;
+        return -E1000_ERR_PHY_TYPE;
+    }
+
+    return E1000_SUCCESS;
+}
+
+/******************************************************************************
+ * IGP phy init script - initializes the GbE PHY
+ *
+ * hw - Struct containing variables accessed by shared code
+ *****************************************************************************/
+static void
+em_phy_init_script(struct em_hw *hw)
+{
+    DEBUGFUNC("em_phy_init_script");
+
+    if(hw->phy_init_script) {
+        msec_delay(10);
+
+        em_write_phy_reg(hw,IGP01E1000_PHY_PAGE_SELECT,0x0000);
+        em_write_phy_reg(hw,0x0000,0x0140);
+
+        msec_delay(5);
+        em_write_phy_reg(hw,IGP01E1000_PHY_PAGE_SELECT,0x1F95);
+        em_write_phy_reg(hw,0x0015,0x0001);
+
+        em_write_phy_reg(hw,IGP01E1000_PHY_PAGE_SELECT,0x1F71);
+        em_write_phy_reg(hw,0x0011,0xBD21);
+
+        em_write_phy_reg(hw,IGP01E1000_PHY_PAGE_SELECT,0x1F79);
+        em_write_phy_reg(hw,0x0019,0x0018);
+
+        em_write_phy_reg(hw,IGP01E1000_PHY_PAGE_SELECT,0x1F30);
+        em_write_phy_reg(hw,0x0010,0x1600);
+
+        em_write_phy_reg(hw,IGP01E1000_PHY_PAGE_SELECT,0x1F31);
+        em_write_phy_reg(hw,0x0011,0x0014);
+
+        em_write_phy_reg(hw,IGP01E1000_PHY_PAGE_SELECT,0x1F32);
+        em_write_phy_reg(hw,0x0012,0x161C);
+
+        em_write_phy_reg(hw,IGP01E1000_PHY_PAGE_SELECT,0x1F94);
+        em_write_phy_reg(hw,0x0014,0x0003);
+
+        em_write_phy_reg(hw,IGP01E1000_PHY_PAGE_SELECT,0x1F96);
+        em_write_phy_reg(hw,0x0016,0x003F);
+
+        em_write_phy_reg(hw,IGP01E1000_PHY_PAGE_SELECT,0x2010);
+        em_write_phy_reg(hw,0x0010,0x0008);
+
+        em_write_phy_reg(hw,IGP01E1000_PHY_PAGE_SELECT,0x0000);
+        em_write_phy_reg(hw,0x0000,0x3300);
+    }
+}
+
+/******************************************************************************
+ * Set the mac type member in the hw struct.
+ *
+ * hw - Struct containing variables accessed by shared code
+ *****************************************************************************/
+int32_t
+em_set_mac_type(struct em_hw *hw)
+{
+    DEBUGFUNC("em_set_mac_type");
+
+    switch (hw->device_id) {
+    case E1000_DEV_ID_82542:
+        switch (hw->revision_id) {
+        case E1000_82542_2_0_REV_ID:
+            hw->mac_type = em_82542_rev2_0;
+            break;
+        case E1000_82542_2_1_REV_ID:
+            hw->mac_type = em_82542_rev2_1;
+            break;
+        default:
+            /* Invalid 82542 revision ID */
+            return -E1000_ERR_MAC_TYPE;
+        }
+        break;
+    case E1000_DEV_ID_82543GC_FIBER:
+    case E1000_DEV_ID_82543GC_COPPER:
+        hw->mac_type = em_82543;
+        break;
+    case E1000_DEV_ID_82544EI_COPPER:
+    case E1000_DEV_ID_82544EI_FIBER:
+    case E1000_DEV_ID_82544GC_COPPER:
+    case E1000_DEV_ID_82544GC_LOM:
+        hw->mac_type = em_82544;
+        break;
+    case E1000_DEV_ID_82540EM:
+    case E1000_DEV_ID_82540EM_LOM:
+    case E1000_DEV_ID_82540EP:
+    case E1000_DEV_ID_82540EP_LOM:
+    case E1000_DEV_ID_82540EP_LP:
+        hw->mac_type = em_82540;
+        break;
+    case E1000_DEV_ID_82545EM_COPPER:
+    case E1000_DEV_ID_82545EM_FIBER:
+        hw->mac_type = em_82545;
+        break;
+    case E1000_DEV_ID_82546EB_COPPER:
+    case E1000_DEV_ID_82546EB_FIBER:
+    case E1000_DEV_ID_82546EB_QUAD_COPPER:
+        hw->mac_type = em_82546;
+        break;
+    case E1000_DEV_ID_82541EI:
+    case E1000_DEV_ID_82541EP:
+        hw->mac_type = em_82541;
+        break;
+    case E1000_DEV_ID_82547EI:
+        hw->mac_type = em_82547;
+        break;
+    default:
+        /* Should never have loaded on this device */
+        return -E1000_ERR_MAC_TYPE;
+    }
+
+
+    return E1000_SUCCESS;
+}
 /******************************************************************************
  * Reset the transmit and receive units; mask and clear all interrupts.
  *
@@ -109,17 +261,14 @@
     uint32_t ctrl_ext;
     uint32_t icr;
     uint32_t manc;
-    uint16_t pci_cmd_word;
+    uint32_t led_ctrl;
 
     DEBUGFUNC("em_reset_hw");
-    
+
     /* For 82542 (rev 2.0), disable MWI before issuing a device reset */
     if(hw->mac_type == em_82542_rev2_0) {
-        if(hw->pci_cmd_word & CMD_MEM_WRT_INVALIDATE) {
-            DEBUGOUT("Disabling MWI on 82542 rev 2.0\n");
-            pci_cmd_word = hw->pci_cmd_word & ~CMD_MEM_WRT_INVALIDATE;
-            em_write_pci_cfg(hw, PCI_COMMAND_REGISTER, &pci_cmd_word);
-        }
+        DEBUGOUT("Disabling MWI on 82542 rev 2.0\n");
+        em_pci_clear_mwi(hw);
     }
 
     /* Clear interrupt mask to stop board from generating interrupts */
@@ -132,13 +281,14 @@
      */
     E1000_WRITE_REG(hw, RCTL, 0);
     E1000_WRITE_REG(hw, TCTL, E1000_TCTL_PSP);
+    E1000_WRITE_FLUSH(hw);
 
     /* The tbi_compatibility_on Flag must be cleared when Rctl is cleared. */
     hw->tbi_compatibility_on = FALSE;
 
     /* Delay to allow any outstanding PCI transactions to complete before
      * resetting the device
-     */ 
+     */
     msec_delay(10);
 
     /* Issue a global reset to the MAC.  This will reset the chip's
@@ -149,10 +299,26 @@
     DEBUGOUT("Issuing a global reset to MAC\n");
     ctrl = E1000_READ_REG(hw, CTRL);
 
-    if(hw->mac_type > em_82543)
-        E1000_WRITE_REG_IO(hw, CTRL, (ctrl | E1000_CTRL_RST));
-    else
-        E1000_WRITE_REG(hw, CTRL, (ctrl | E1000_CTRL_RST));
+    /* Must reset the PHY before resetting the MAC */
+    if((hw->mac_type == em_82541) || (hw->mac_type == em_82547)) {
+        E1000_WRITE_REG_IO(hw, CTRL, (ctrl | E1000_CTRL_PHY_RST));
+	msec_delay(5);
+    }
+
+    switch(hw->mac_type) {
+        case em_82544:
+        case em_82540:
+        case em_82545:
+        case em_82546:
+        case em_82541:
+            /* These controllers can't ack the 64-bit write when issuing the
+             * reset, so use IO-mapping as a workaround to issue the reset */
+            E1000_WRITE_REG_IO(hw, CTRL, (ctrl | E1000_CTRL_RST));
+            break;
+        default:
+            E1000_WRITE_REG(hw, CTRL, (ctrl | E1000_CTRL_RST));
+            break;
+    }
 
     /* Force a reload from the EEPROM if necessary */
     if(hw->mac_type < em_82540) {
@@ -161,17 +327,28 @@
         ctrl_ext = E1000_READ_REG(hw, CTRL_EXT);
         ctrl_ext |= E1000_CTRL_EXT_EE_RST;
         E1000_WRITE_REG(hw, CTRL_EXT, ctrl_ext);
+        E1000_WRITE_FLUSH(hw);
         /* Wait for EEPROM reload */
         msec_delay(2);
     } else {
         /* Wait for EEPROM reload (it happens automatically) */
-        msec_delay(4);
+        msec_delay(5);
         /* Dissable HW ARPs on ASF enabled adapters */
         manc = E1000_READ_REG(hw, MANC);
         manc &= ~(E1000_MANC_ARP_EN);
         E1000_WRITE_REG(hw, MANC, manc);
     }
-    
+
+    if((hw->mac_type == em_82541) || (hw->mac_type == em_82547)) {
+        em_phy_init_script(hw);
+
+        /* Configure activity LED after PHY reset */
+        led_ctrl = E1000_READ_REG(hw, LEDCTL);
+        led_ctrl &= IGP_ACTIVITY_LED_MASK;
+        led_ctrl |= (IGP_ACTIVITY_LED_ENABLE | IGP_LED3_MODE);
+        E1000_WRITE_REG(hw, LEDCTL, led_ctrl);
+    }
+
     /* Clear interrupt mask to stop board from generating interrupts */
     DEBUGOUT("Masking off all interrupts\n");
     E1000_WRITE_REG(hw, IMC, 0xffffffff);
@@ -182,7 +359,7 @@
     /* If MWI was previously enabled, reenable it. */
     if(hw->mac_type == em_82542_rev2_0) {
         if(hw->pci_cmd_word & CMD_MEM_WRT_INVALIDATE)
-            em_write_pci_cfg(hw, PCI_COMMAND_REGISTER, &hw->pci_cmd_word);
+            em_pci_set_mwi(hw);
     }
 }
 
@@ -190,8 +367,8 @@
  * Performs basic configuration of the adapter.
  *
  * hw - Struct containing variables accessed by shared code
- * 
- * Assumes that the controller has previously been reset and is in a 
+ *
+ * Assumes that the controller has previously been reset and is in a
  * post-reset uninitialized state. Initializes the receive address registers,
  * multicast table, and VLAN filter table. Calls routines to setup link
  * configuration and flow control settings. Clears all on-chip counters. Leaves
@@ -203,7 +380,6 @@
     uint32_t ctrl, status;
     uint32_t i;
     int32_t ret_val;
-    uint16_t pci_cmd_word;
     uint16_t pcix_cmd_word;
     uint16_t pcix_stat_hi_word;
     uint16_t cmd_mmrbc;
@@ -217,7 +393,7 @@
         DEBUGOUT("Error Initializing Identification LED\n");
         return ret_val;
     }
-    
+
     /* Set the Media Type and exit with error if it is not valid. */
     if(hw->mac_type != em_82543) {
         /* tbi_compatibility is only valid on 82543 */
@@ -246,12 +422,10 @@
 
     /* For 82542 (rev 2.0), disable MWI and put the receiver into reset */
     if(hw->mac_type == em_82542_rev2_0) {
-        if(hw->pci_cmd_word & CMD_MEM_WRT_INVALIDATE) {
-            DEBUGOUT("Disabling MWI on 82542 rev 2.0\n");
-            pci_cmd_word = hw->pci_cmd_word & ~CMD_MEM_WRT_INVALIDATE;
-            em_write_pci_cfg(hw, PCI_COMMAND_REGISTER, &pci_cmd_word);
-        }
+        DEBUGOUT("Disabling MWI on 82542 rev 2.0\n");
+        em_pci_clear_mwi(hw);
         E1000_WRITE_REG(hw, RCTL, E1000_RCTL_RST);
+        E1000_WRITE_FLUSH(hw);
         msec_delay(5);
     }
 
@@ -263,9 +437,10 @@
     /* For 82542 (rev 2.0), take the receiver out of reset and enable MWI */
     if(hw->mac_type == em_82542_rev2_0) {
         E1000_WRITE_REG(hw, RCTL, 0);
+        E1000_WRITE_FLUSH(hw);
         msec_delay(1);
         if(hw->pci_cmd_word & CMD_MEM_WRT_INVALIDATE)
-            em_write_pci_cfg(hw, PCI_COMMAND_REGISTER, &hw->pci_cmd_word);
+            em_pci_set_mwi(hw);
     }
 
     /* Zero out the Multicast HASH table */
@@ -290,6 +465,8 @@
             PCIX_COMMAND_MMRBC_SHIFT;
         stat_mmrbc = (pcix_stat_hi_word & PCIX_STATUS_HI_MMRBC_MASK) >>
             PCIX_STATUS_HI_MMRBC_SHIFT;
+        if(stat_mmrbc == PCIX_STATUS_HI_MMRBC_4K)
+            stat_mmrbc = PCIX_STATUS_HI_MMRBC_2K;
         if(cmd_mmrbc > stat_mmrbc) {
             pcix_cmd_word &= ~PCIX_COMMAND_MMRBC_MASK;
             pcix_cmd_word |= stat_mmrbc << PCIX_COMMAND_MMRBC_SHIFT;
@@ -300,6 +477,13 @@
     /* Call a subroutine to configure the link and setup flow control. */
     ret_val = em_setup_link(hw);
 
+    /* Set the transmit descriptor write-back policy */
+    if(hw->mac_type > em_82544) {
+        ctrl = E1000_READ_REG(hw, TXDCTL);
+        ctrl = (ctrl & ~E1000_TXDCTL_WTHRESH) | E1000_TXDCTL_FULL_TX_DESC_WB;
+        E1000_WRITE_REG(hw, TXDCTL, ctrl);
+    }
+
     /* Clear all of the statistics registers (clear on read).  It is
      * important that we do this after we have tried to establish link
      * because the symbol error count will increment wildly if there
@@ -312,13 +496,13 @@
 
 /******************************************************************************
  * Configures flow control and link settings.
- * 
+ *
  * hw - Struct containing variables accessed by shared code
- * 
+ *
  * Determines which flow control settings to use. Calls the apropriate media-
  * specific link configuration function. Configures the flow control settings.
  * Assuming the adapter has a valid link partner, a valid link should be
- * established. Assumes the hardware has previously been reset and the 
+ * established. Assumes the hardware has previously been reset and the
  * transmitter and receiver are not enabled.
  *****************************************************************************/
 int32_t
@@ -338,7 +522,7 @@
      * control setting, then the variable hw->fc will
      * be initialized based on a value in the EEPROM.
      */
-    if(em_read_eeprom(hw, EEPROM_INIT_CONTROL2_REG, &eeprom_data) < 0) {
+    if(em_read_eeprom(hw, EEPROM_INIT_CONTROL2_REG, 1, &eeprom_data) < 0) {
         DEBUGOUT("EEPROM Read Error\n");
         return -E1000_ERR_EEPROM;
     }
@@ -346,7 +530,7 @@
     if(hw->fc == em_fc_default) {
         if((eeprom_data & EEPROM_WORD0F_PAUSE_MASK) == 0)
             hw->fc = em_fc_none;
-        else if((eeprom_data & EEPROM_WORD0F_PAUSE_MASK) == 
+        else if((eeprom_data & EEPROM_WORD0F_PAUSE_MASK) ==
                 EEPROM_WORD0F_ASM_DIR)
             hw->fc = em_fc_tx_pause;
         else
@@ -375,7 +559,7 @@
      * or em_phy_setup() is called.
      */
     if(hw->mac_type == em_82543) {
-        ctrl_ext = ((eeprom_data & EEPROM_WORD0F_SWPDIO_EXT) << 
+        ctrl_ext = ((eeprom_data & EEPROM_WORD0F_SWPDIO_EXT) <<
                     SWDPIO__EXT_SHIFT);
         E1000_WRITE_REG(hw, CTRL_EXT, ctrl_ext);
     }
@@ -401,7 +585,7 @@
      * these registers will be set to a default threshold that may be
      * adjusted later by the driver's runtime code.  However, if the
      * ability to transmit pause frames in not enabled, then these
-     * registers will be set to 0. 
+     * registers will be set to 0.
      */
     if(!(hw->fc & em_fc_tx_pause)) {
         E1000_WRITE_REG(hw, FCRTL, 0);
@@ -425,13 +609,12 @@
  * Sets up link for a fiber based adapter
  *
  * hw - Struct containing variables accessed by shared code
- * ctrl - Current value of the device control register
  *
  * Manipulates Physical Coding Sublayer functions in order to configure
  * link. Assumes the hardware has been previously reset and the transmitter
  * and receiver are not enabled.
  *****************************************************************************/
-static int32_t 
+static int32_t
 em_setup_fiber_link(struct em_hw *hw)
 {
     uint32_t ctrl;
@@ -443,29 +626,29 @@
 
     DEBUGFUNC("em_setup_fiber_link");
 
-    /* On adapters with a MAC newer that 82544, SW Defineable pin 1 will be 
-     * set when the optics detect a signal. On older adapters, it will be 
+    /* On adapters with a MAC newer that 82544, SW Defineable pin 1 will be
+     * set when the optics detect a signal. On older adapters, it will be
      * cleared when there is a signal
      */
     ctrl = E1000_READ_REG(hw, CTRL);
     if(hw->mac_type > em_82544) signal = E1000_CTRL_SWDPIN1;
     else signal = 0;
-   
+
     /* Take the link out of reset */
     ctrl &= ~(E1000_CTRL_LRST);
-    
+
     em_config_collision_dist(hw);
 
     /* Check for a software override of the flow control settings, and setup
      * the device accordingly.  If auto-negotiation is enabled, then software
      * will have to set the "PAUSE" bits to the correct value in the Tranmsit
      * Config Word Register (TXCW) and re-start auto-negotiation.  However, if
-     * auto-negotiation is disabled, then software will have to manually 
+     * auto-negotiation is disabled, then software will have to manually
      * configure the two flow control enable bits in the CTRL register.
      *
      * The possible values of the "fc" parameter are:
      *      0:  Flow control is completely disabled
-     *      1:  Rx flow control is enabled (we can receive pause frames, but 
+     *      1:  Rx flow control is enabled (we can receive pause frames, but
      *          not send pause frames).
      *      2:  Tx flow control is enabled (we can send pause frames but we do
      *          not support receiving pause frames).
@@ -477,8 +660,8 @@
         txcw = (E1000_TXCW_ANE | E1000_TXCW_FD);
         break;
     case em_fc_rx_pause:
-        /* RX Flow control is enabled and TX Flow control is disabled by a 
-         * software over-ride. Since there really isn't a way to advertise 
+        /* RX Flow control is enabled and TX Flow control is disabled by a
+         * software over-ride. Since there really isn't a way to advertise
          * that we are capable of RX Pause ONLY, we will advertise that we
          * support both symmetric and asymmetric RX PAUSE. Later, we will
          *  disable the adapter's ability to send PAUSE frames.
@@ -486,7 +669,7 @@
         txcw = (E1000_TXCW_ANE | E1000_TXCW_FD | E1000_TXCW_PAUSE_MASK);
         break;
     case em_fc_tx_pause:
-        /* TX Flow control is enabled, and RX Flow control is disabled, by a 
+        /* TX Flow control is enabled, and RX Flow control is disabled, by a
          * software over-ride.
          */
         txcw = (E1000_TXCW_ANE | E1000_TXCW_FD | E1000_TXCW_ASM_DIR);
@@ -511,13 +694,14 @@
 
     E1000_WRITE_REG(hw, TXCW, txcw);
     E1000_WRITE_REG(hw, CTRL, ctrl);
+    E1000_WRITE_FLUSH(hw);
 
     hw->txcw = txcw;
     msec_delay(1);
 
     /* If we have a signal (the cable is plugged in) then poll for a "Link-Up"
-     * indication in the Device Status Register.  Time-out if a link isn't 
-     * seen in 500 milliseconds seconds (Auto-negotiation should complete in 
+     * indication in the Device Status Register.  Time-out if a link isn't
+     * seen in 500 milliseconds seconds (Auto-negotiation should complete in
      * less than 500 milliseconds even if the other end is doing it in SW).
      */
     if((E1000_READ_REG(hw, CTRL) & E1000_CTRL_SWDPIN1) == signal) {
@@ -528,7 +712,7 @@
             if(status & E1000_STATUS_LU) break;
         }
         if(i == (LINK_UP_TIMEOUT / 10)) {
-            /* AutoNeg failed to achieve a link, so we'll call 
+            /* AutoNeg failed to achieve a link, so we'll call
              * em_check_for_link. This routine will force the link up if we
              * detect a signal. This will allow us to communicate with
              * non-autonegotiating link partners.
@@ -555,12 +739,12 @@
 * Detects which PHY is present and the speed and duplex
 *
 * hw - Struct containing variables accessed by shared code
-* ctrl - current value of the device control register
 ******************************************************************************/
-static int32_t 
+static int32_t
 em_setup_copper_link(struct em_hw *hw)
 {
     uint32_t ctrl;
+    uint32_t led_ctrl;
     int32_t ret_val;
     uint16_t i;
     uint16_t phy_data;
@@ -590,77 +774,146 @@
     }
     DEBUGOUT1("Phy ID = %x \n", hw->phy_id);
 
-    /* Enable CRS on TX. This must be set for half-duplex operation. */
-    if(em_read_phy_reg(hw, M88E1000_PHY_SPEC_CTRL, &phy_data) < 0) {
-        DEBUGOUT("PHY Read Error\n");
-        return -E1000_ERR_PHY;
-    }
-    phy_data |= M88E1000_PSCR_ASSERT_CRS_ON_TX;
+    if (hw->phy_type == em_phy_igp) {
 
-    /* Options:
-     *   MDI/MDI-X = 0 (default)
-     *   0 - Auto for all speeds
-     *   1 - MDI mode
-     *   2 - MDI-X mode
-     *   3 - Auto for 1000Base-T only (MDI-X for 10/100Base-T modes)
-     */
-    phy_data &= ~M88E1000_PSCR_AUTO_X_MODE;
+        ret_val = em_phy_reset(hw);
+        if(ret_val < 0) {
+            DEBUGOUT("Error Resetting the PHY\n");
+            return ret_val;
+        }
 
-    switch (hw->mdix) {
-    case 1:
-        phy_data |= M88E1000_PSCR_MDI_MANUAL_MODE;
-        break;
-    case 2:
-        phy_data |= M88E1000_PSCR_MDIX_MANUAL_MODE;
-        break;
-    case 3:
-        phy_data |= M88E1000_PSCR_AUTO_X_1000T;
-        break;
-    case 0:
-    default:
-        phy_data |= M88E1000_PSCR_AUTO_X_MODE;
-        break;
-    }
+        /* Wait 10ms for MAC to configure PHY from eeprom settings */
+        msec_delay(15);
 
-    /* Options:
-     *   disable_polarity_correction = 0 (default)
-     *       Automatic Correction for Reversed Cable Polarity
-     *   0 - Disabled
-     *   1 - Enabled
-     */
-    phy_data &= ~M88E1000_PSCR_POLARITY_REVERSAL;
-    if(hw->disable_polarity_correction == 1)
-        phy_data |= M88E1000_PSCR_POLARITY_REVERSAL;
-    if(em_write_phy_reg(hw, M88E1000_PHY_SPEC_CTRL, phy_data) < 0) {
-        DEBUGOUT("PHY Write Error\n");
-        return -E1000_ERR_PHY;
-    }
+        if(em_write_phy_reg(hw, IGP01E1000_PHY_PAGE_SELECT, 0x0000) < 0) {
+            DEBUGOUT("PHY Write Error\n");
+            return -E1000_ERR_PHY;
+        }
 
-    /* Force TX_CLK in the Extended PHY Specific Control Register
-     * to 25MHz clock.
-     */
-    if(em_read_phy_reg(hw, M88E1000_EXT_PHY_SPEC_CTRL, &phy_data) < 0) {
-        DEBUGOUT("PHY Read Error\n");
-        return -E1000_ERR_PHY;
-    }
-    phy_data |= M88E1000_EPSCR_TX_CLK_25;
-    /* Configure Master and Slave downshift values */
-    phy_data &= ~(M88E1000_EPSCR_MASTER_DOWNSHIFT_MASK |
-                  M88E1000_EPSCR_SLAVE_DOWNSHIFT_MASK);
-    phy_data |= (M88E1000_EPSCR_MASTER_DOWNSHIFT_1X |
-                 M88E1000_EPSCR_SLAVE_DOWNSHIFT_1X);
-    if(em_write_phy_reg(hw, M88E1000_EXT_PHY_SPEC_CTRL, phy_data) < 0) {
-        DEBUGOUT("PHY Write Error\n");
-        return -E1000_ERR_PHY;
-    }
+        /* Configure activity LED after PHY reset */
+        led_ctrl = E1000_READ_REG(hw, LEDCTL);
+        led_ctrl &= IGP_ACTIVITY_LED_MASK;
+        led_ctrl |= (IGP_ACTIVITY_LED_ENABLE | IGP_LED3_MODE);
+        E1000_WRITE_REG(hw, LEDCTL, led_ctrl);
+
+        if(hw->autoneg_advertised == ADVERTISE_1000_FULL) {
+            /* Disable SmartSpeed */
+            if(em_read_phy_reg(hw, IGP01E1000_PHY_PORT_CONFIG,
+                                  &phy_data) < 0) {
+                DEBUGOUT("PHY Read Error\n");
+                return -E1000_ERR_PHY;
+            }
+            phy_data &= ~IGP01E1000_PSCFR_SMART_SPEED;
+            if(em_write_phy_reg(hw, IGP01E1000_PHY_PORT_CONFIG,
+                                   phy_data) < 0) {
+                DEBUGOUT("PHY Write Error\n");
+                return -E1000_ERR_PHY;
+            }
+            /* Set auto Master/Slave resolution process */
+            if(em_read_phy_reg(hw, PHY_1000T_CTRL, &phy_data) < 0) {
+                DEBUGOUT("PHY Read Error\n");
+                return -E1000_ERR_PHY;
+            }
+            phy_data &= ~CR_1000T_MS_ENABLE;
+            if(em_write_phy_reg(hw, PHY_1000T_CTRL, phy_data) < 0) {
+                DEBUGOUT("PHY Write Error\n");
+                return -E1000_ERR_PHY;
+            }
+        }
 
-    /* SW Reset the PHY so all changes take effect */
-    ret_val = em_phy_reset(hw);
-    if(ret_val < 0) {
-        DEBUGOUT("Error Resetting the PHY\n");
-        return ret_val;
+        if(em_read_phy_reg(hw, IGP01E1000_PHY_PORT_CTRL, &phy_data) < 0) {
+            DEBUGOUT("PHY Read Error\n");
+            return -E1000_ERR_PHY;
+        }
+
+        /* Force MDI for IGP PHY */
+        phy_data &= ~(IGP01E1000_PSCR_AUTO_MDIX |
+                      IGP01E1000_PSCR_FORCE_MDI_MDIX);
+
+        hw->mdix = 1;
+
+        if(em_write_phy_reg(hw, IGP01E1000_PHY_PORT_CTRL, phy_data) < 0) {
+            DEBUGOUT("PHY Write Error\n");
+            return -E1000_ERR_PHY;
+        }
+
+    } else {
+        /* Enable CRS on TX. This must be set for half-duplex operation. */
+        if(em_read_phy_reg(hw, M88E1000_PHY_SPEC_CTRL, &phy_data) < 0) {
+            DEBUGOUT("PHY Read Error\n");
+            return -E1000_ERR_PHY;
+        }
+        phy_data |= M88E1000_PSCR_ASSERT_CRS_ON_TX;
+
+        /* Options:
+         *   MDI/MDI-X = 0 (default)
+         *   0 - Auto for all speeds
+         *   1 - MDI mode
+         *   2 - MDI-X mode
+         *   3 - Auto for 1000Base-T only (MDI-X for 10/100Base-T modes)
+         */
+        phy_data &= ~M88E1000_PSCR_AUTO_X_MODE;
+
+        switch (hw->mdix) {
+        case 1:
+            phy_data |= M88E1000_PSCR_MDI_MANUAL_MODE;
+            break;
+        case 2:
+            phy_data |= M88E1000_PSCR_MDIX_MANUAL_MODE;
+            break;
+        case 3:
+            phy_data |= M88E1000_PSCR_AUTO_X_1000T;
+            break;
+        case 0:
+        default:
+            phy_data |= M88E1000_PSCR_AUTO_X_MODE;
+            break;
+        }
+
+        /* Options:
+         *   disable_polarity_correction = 0 (default)
+         *       Automatic Correction for Reversed Cable Polarity
+         *   0 - Disabled
+         *   1 - Enabled
+         */
+        phy_data &= ~M88E1000_PSCR_POLARITY_REVERSAL;
+        if(hw->disable_polarity_correction == 1)
+            phy_data |= M88E1000_PSCR_POLARITY_REVERSAL;
+        if(em_write_phy_reg(hw, M88E1000_PHY_SPEC_CTRL, phy_data) < 0) {
+            DEBUGOUT("PHY Write Error\n");
+            return -E1000_ERR_PHY;
+        }
+
+        /* Force TX_CLK in the Extended PHY Specific Control Register
+         * to 25MHz clock.
+         */
+        if(em_read_phy_reg(hw, M88E1000_EXT_PHY_SPEC_CTRL, &phy_data) < 0) {
+            DEBUGOUT("PHY Read Error\n");
+            return -E1000_ERR_PHY;
+        }
+        phy_data |= M88E1000_EPSCR_TX_CLK_25;
+
+        if (hw->phy_revision < M88E1011_I_REV_4) {
+            /* Configure Master and Slave downshift values */
+            phy_data &= ~(M88E1000_EPSCR_MASTER_DOWNSHIFT_MASK |
+                          M88E1000_EPSCR_SLAVE_DOWNSHIFT_MASK);
+            phy_data |= (M88E1000_EPSCR_MASTER_DOWNSHIFT_1X |
+                         M88E1000_EPSCR_SLAVE_DOWNSHIFT_1X);
+            if(em_write_phy_reg(hw, M88E1000_EXT_PHY_SPEC_CTRL,
+                                   phy_data) < 0) {
+                DEBUGOUT("PHY Write Error\n");
+                return -E1000_ERR_PHY;
+            }
+        }
+
+        /* SW Reset the PHY so all changes take effect */
+        ret_val = em_phy_reset(hw);
+        if(ret_val < 0) {
+            DEBUGOUT("Error Resetting the PHY\n");
+            return ret_val;
+        }
     }
-    
+
     /* Options:
      *   autoneg = 1 (default)
      *      PHY will advertise value(s) parsed from
@@ -719,6 +972,7 @@
                 return ret_val;
             }
         }
+        hw->get_link_status = TRUE;
     } else {
         DEBUGOUT("Forcing speed and duplex\n");
         ret_val = em_phy_force_speed_duplex(hw);
@@ -997,24 +1251,43 @@
     /* Write the configured values back to the Device Control Reg. */
     E1000_WRITE_REG(hw, CTRL, ctrl);
 
-    /* Write the MII Control Register with the new PHY configuration. */
-    if(em_read_phy_reg(hw, M88E1000_PHY_SPEC_CTRL, &phy_data) < 0) {
-        DEBUGOUT("PHY Read Error\n");
-        return -E1000_ERR_PHY;
-    }
+    if (hw->phy_type == em_phy_m88) {
+        if(em_read_phy_reg(hw, M88E1000_PHY_SPEC_CTRL, &phy_data) < 0) {
+            DEBUGOUT("PHY Read Error\n");
+            return -E1000_ERR_PHY;
+        }
 
-    /* Clear Auto-Crossover to force MDI manually. M88E1000 requires MDI
-     * forced whenever speed are duplex are forced.
-     */
-    phy_data &= ~M88E1000_PSCR_AUTO_X_MODE;
-    if(em_write_phy_reg(hw, M88E1000_PHY_SPEC_CTRL, phy_data) < 0) {
-        DEBUGOUT("PHY Write Error\n");
-        return -E1000_ERR_PHY;
+        /* Clear Auto-Crossover to force MDI manually. M88E1000 requires MDI
+         * forced whenever speed are duplex are forced.
+         */
+        phy_data &= ~M88E1000_PSCR_AUTO_X_MODE;
+        if(em_write_phy_reg(hw, M88E1000_PHY_SPEC_CTRL, phy_data) < 0) {
+            DEBUGOUT("PHY Write Error\n");
+            return -E1000_ERR_PHY;
+        }
+        DEBUGOUT1("M88E1000 PSCR: %x \n", phy_data);
+
+        /* Need to reset the PHY or these changes will be ignored */
+        mii_ctrl_reg |= MII_CR_RESET;
+    } else {
+        /* Clear Auto-Crossover to force MDI manually.  IGP requires MDI
+         * forced whenever speed or duplex are forced.
+         */
+        if(em_read_phy_reg(hw, IGP01E1000_PHY_PORT_CTRL, &phy_data) < 0) {
+            DEBUGOUT("PHY Read Error\n");
+            return -E1000_ERR_PHY;
+        }
+
+        phy_data &= ~IGP01E1000_PSCR_AUTO_MDIX;
+        phy_data &= ~IGP01E1000_PSCR_FORCE_MDI_MDIX;
+
+        if(em_write_phy_reg(hw, IGP01E1000_PHY_PORT_CTRL, phy_data) < 0) {
+            DEBUGOUT("PHY Write Error\n");
+            return -E1000_ERR_PHY;
+        }
     }
-    DEBUGOUT1("M88E1000 PSCR: %x \n", phy_data);
-    
-    /* Need to reset the PHY or these changes will be ignored */
-    mii_ctrl_reg |= MII_CR_RESET;
+
+    /* Write back the modified PHY MII control register. */
     if(em_write_phy_reg(hw, PHY_CTRL, mii_ctrl_reg) < 0) {
         DEBUGOUT("PHY Write Error\n");
         return -E1000_ERR_PHY;
@@ -1051,7 +1324,7 @@
         }
         if(i == 0) { /* We didn't get link */
             /* Reset the DSP and wait again for link. */
-            
+
             ret_val = em_phy_reset_dsp(hw);
             if(ret_val < 0) {
                 DEBUGOUT("Error Resetting PHY DSP\n");
@@ -1075,32 +1348,34 @@
             }
         }
     }
-    
-    /* Because we reset the PHY above, we need to re-force TX_CLK in the
-     * Extended PHY Specific Control Register to 25MHz clock.  This value
-     * defaults back to a 2.5MHz clock when the PHY is reset.
-     */
-    if(em_read_phy_reg(hw, M88E1000_EXT_PHY_SPEC_CTRL, &phy_data) < 0) {
-        DEBUGOUT("PHY Read Error\n");
-        return -E1000_ERR_PHY;
-    }
-    phy_data |= M88E1000_EPSCR_TX_CLK_25;
-    if(em_write_phy_reg(hw, M88E1000_EXT_PHY_SPEC_CTRL, phy_data) < 0) {
-        DEBUGOUT("PHY Write Error\n");
-        return -E1000_ERR_PHY;
-    }
 
-    /* In addition, because of the s/w reset above, we need to enable CRS on
-     * TX.  This must be set for both full and half duplex operation.
-     */
-    if(em_read_phy_reg(hw, M88E1000_PHY_SPEC_CTRL, &phy_data) < 0) {
-        DEBUGOUT("PHY Read Error\n");
-        return -E1000_ERR_PHY;
-    }
-    phy_data |= M88E1000_PSCR_ASSERT_CRS_ON_TX;
-    if(em_write_phy_reg(hw, M88E1000_PHY_SPEC_CTRL, phy_data) < 0) {
-        DEBUGOUT("PHY Write Error\n");
-        return -E1000_ERR_PHY;
+    if (hw->phy_type == em_phy_m88) {
+        /* Because we reset the PHY above, we need to re-force TX_CLK in the
+         * Extended PHY Specific Control Register to 25MHz clock.  This value
+         * defaults back to a 2.5MHz clock when the PHY is reset.
+         */
+        if(em_read_phy_reg(hw, M88E1000_EXT_PHY_SPEC_CTRL, &phy_data) < 0) {
+            DEBUGOUT("PHY Read Error\n");
+            return -E1000_ERR_PHY;
+        }
+        phy_data |= M88E1000_EPSCR_TX_CLK_25;
+        if(em_write_phy_reg(hw, M88E1000_EXT_PHY_SPEC_CTRL, phy_data) < 0) {
+            DEBUGOUT("PHY Write Error\n");
+            return -E1000_ERR_PHY;
+        }
+
+        /* In addition, because of the s/w reset above, we need to enable CRS on
+         * TX.  This must be set for both full and half duplex operation.
+         */
+        if(em_read_phy_reg(hw, M88E1000_PHY_SPEC_CTRL, &phy_data) < 0) {
+            DEBUGOUT("PHY Read Error\n");
+            return -E1000_ERR_PHY;
+        }
+        phy_data |= M88E1000_PSCR_ASSERT_CRS_ON_TX;
+        if(em_write_phy_reg(hw, M88E1000_PHY_SPEC_CTRL, phy_data) < 0) {
+            DEBUGOUT("PHY Write Error\n");
+            return -E1000_ERR_PHY;
+        }
     }
     return 0;
 }
@@ -1118,12 +1393,15 @@
 {
     uint32_t tctl;
 
+    DEBUGFUNC("em_config_collision_dist");
+
     tctl = E1000_READ_REG(hw, TCTL);
 
     tctl &= ~E1000_TCTL_COLD;
     tctl |= E1000_COLLISION_DISTANCE << E1000_COLD_SHIFT;
 
     E1000_WRITE_REG(hw, TCTL, tctl);
+    E1000_WRITE_FLUSH(hw);
 }
 
 /******************************************************************************
@@ -1153,22 +1431,43 @@
     /* Set up duplex in the Device Control and Transmit Control
      * registers depending on negotiated values.
      */
-    if(em_read_phy_reg(hw, M88E1000_PHY_SPEC_STATUS, &phy_data) < 0) {
-        DEBUGOUT("PHY Read Error\n");
-        return -E1000_ERR_PHY;
-    }
-    if(phy_data & M88E1000_PSSR_DPLX) ctrl |= E1000_CTRL_FD;
-    else ctrl &= ~E1000_CTRL_FD;
+    if (hw->phy_type == em_phy_igp) {
+        if(em_read_phy_reg(hw, IGP01E1000_PHY_PORT_STATUS, &phy_data) < 0) {
+            DEBUGOUT("PHY Read Error\n");
+            return -E1000_ERR_PHY;
+        }
+        if(phy_data & IGP01E1000_PSSR_FULL_DUPLEX) ctrl |= E1000_CTRL_FD;
+        else ctrl &= ~E1000_CTRL_FD;
 
-    em_config_collision_dist(hw);
+        em_config_collision_dist(hw);
 
-    /* Set up speed in the Device Control register depending on
-     * negotiated values.
-     */
-    if((phy_data & M88E1000_PSSR_SPEED) == M88E1000_PSSR_1000MBS)
-        ctrl |= E1000_CTRL_SPD_1000;
-    else if((phy_data & M88E1000_PSSR_SPEED) == M88E1000_PSSR_100MBS)
-        ctrl |= E1000_CTRL_SPD_100;
+        /* Set up speed in the Device Control register depending on
+         * negotiated values.
+         */
+        if((phy_data & IGP01E1000_PSSR_SPEED_MASK) ==
+           IGP01E1000_PSSR_SPEED_1000MBPS)
+            ctrl |= E1000_CTRL_SPD_1000;
+        else if((phy_data & IGP01E1000_PSSR_SPEED_MASK) ==
+                IGP01E1000_PSSR_SPEED_100MBPS)
+            ctrl |= E1000_CTRL_SPD_100;
+    } else {
+        if(em_read_phy_reg(hw, M88E1000_PHY_SPEC_STATUS, &phy_data) < 0) {
+            DEBUGOUT("PHY Read Error\n");
+            return -E1000_ERR_PHY;
+        }
+        if(phy_data & M88E1000_PSSR_DPLX) ctrl |= E1000_CTRL_FD;
+        else ctrl &= ~E1000_CTRL_FD;
+
+        em_config_collision_dist(hw);
+
+        /* Set up speed in the Device Control register depending on
+         * negotiated values.
+         */
+        if((phy_data & M88E1000_PSSR_SPEED) == M88E1000_PSSR_1000MBS)
+            ctrl |= E1000_CTRL_SPD_1000;
+        else if((phy_data & M88E1000_PSSR_SPEED) == M88E1000_PSSR_100MBS)
+            ctrl |= E1000_CTRL_SPD_100;
+    }
     /* Write the configured values back to the Device Control Reg. */
     E1000_WRITE_REG(hw, CTRL, ctrl);
     return 0;
@@ -1176,7 +1475,7 @@
 
 /******************************************************************************
  * Forces the MAC's flow control settings.
- * 
+ *
  * hw - Struct containing variables accessed by shared code
  *
  * Sets the TFCE and RFCE bits in the device control register to reflect
@@ -1243,7 +1542,7 @@
 
 /******************************************************************************
  * Configures flow control settings after link is established
- * 
+ *
  * hw - Struct containing variables accessed by shared code
  *
  * Should be called immediately after a valid link has been established.
@@ -1465,9 +1764,9 @@
     uint16_t lp_capability;
 
     DEBUGFUNC("em_check_for_link");
-    
-    /* On adapters with a MAC newer that 82544, SW Defineable pin 1 will be 
-     * set when the optics detect a signal. On older adapters, it will be 
+
+    /* On adapters with a MAC newer that 82544, SW Defineable pin 1 will be
+     * set when the optics detect a signal. On older adapters, it will be
      * cleared when there is a signal
      */
     if(hw->mac_type > em_82544) signal = E1000_CTRL_SWDPIN1;
@@ -1500,6 +1799,10 @@
 
         if(phy_data & MII_SR_LINK_STATUS) {
             hw->get_link_status = FALSE;
+            /* Check if there was DownShift, must be checked immediately after
+             * link-up */
+            em_check_downshift(hw);
+
         } else {
             /* No link detected */
             return 0;
@@ -1528,7 +1831,7 @@
             }
         }
 
-        /* Configure Flow Control now that Auto-Neg has completed. First, we 
+        /* Configure Flow Control now that Auto-Neg has completed. First, we
          * need to restore the desired flow control settings because we may
          * have had to re-autoneg with a different link partner.
          */
@@ -1557,7 +1860,7 @@
                                 NWAY_LPAR_100TX_HD_CAPS |
                                 NWAY_LPAR_100TX_FD_CAPS |
                                 NWAY_LPAR_100T4_CAPS)) {
-                /* If our link partner advertises anything in addition to 
+                /* If our link partner advertises anything in addition to
                  * gigabit, we do not need to enable TBI compatibility.
                  */
                 if(hw->tbi_compatibility_on) {
@@ -1721,6 +2024,7 @@
      * bit), and then delay 2 microseconds.
      */
     E1000_WRITE_REG(hw, CTRL, (*ctrl | E1000_CTRL_MDC));
+    E1000_WRITE_FLUSH(hw);
     usec_delay(2);
 }
 
@@ -1738,6 +2042,7 @@
      * bit), and then delay 2 microseconds.
      */
     E1000_WRITE_REG(hw, CTRL, (*ctrl & ~E1000_CTRL_MDC));
+    E1000_WRITE_FLUSH(hw);
     usec_delay(2);
 }
 
@@ -1759,7 +2064,7 @@
     uint32_t mask;
 
     /* We need to shift "count" number of bits out to the PHY. So, the value
-     * in the "data" parameter will be shifted out to the PHY one bit at a 
+     * in the "data" parameter will be shifted out to the PHY one bit at a
      * time. In order to do this, "data" must be broken down into bits.
      */
     mask = 0x01;
@@ -1780,6 +2085,7 @@
         else ctrl &= ~E1000_CTRL_MDIO;
 
         E1000_WRITE_REG(hw, CTRL, ctrl);
+        E1000_WRITE_FLUSH(hw);
 
         usec_delay(2);
 
@@ -1788,9 +2094,6 @@
 
         mask = mask >> 1;
     }
-
-    /* Clear the data bit just before leaving this routine. */
-    ctrl &= ~E1000_CTRL_MDIO;
 }
 
 /******************************************************************************
@@ -1798,7 +2101,7 @@
 *
 * hw - Struct containing variables accessed by shared code
 *
-* Bits are shifted in in MSB to LSB order. 
+* Bits are shifted in in MSB to LSB order.
 ******************************************************************************/
 static uint16_t
 em_shift_in_mdi_bits(struct em_hw *hw)
@@ -1813,7 +2116,7 @@
      * These two bits are ignored by us and thrown away. Bits are "shifted in"
      * by raising the input to the Management Data Clock (setting the MDC bit),
      * and then reading the value of the MDIO bit.
-     */ 
+     */
     ctrl = E1000_READ_REG(hw, CTRL);
 
     /* Clear MDIO_DIR (SWDPIO1) to indicate this bit is to be used as input. */
@@ -1821,6 +2124,7 @@
     ctrl &= ~E1000_CTRL_MDIO;
 
     E1000_WRITE_REG(hw, CTRL, ctrl);
+    E1000_WRITE_FLUSH(hw);
 
     /* Raise and Lower the clock before reading in the data. This accounts for
      * the turnaround bits. The first clock occurred when we clocked out the
@@ -1841,9 +2145,6 @@
     em_raise_mdi_clk(hw, &ctrl);
     em_lower_mdi_clk(hw, &ctrl);
 
-    /* Clear the MDIO bit just before leaving this routine. */
-    ctrl &= ~E1000_CTRL_MDIO;
-
     return data;
 }
 
@@ -1875,7 +2176,7 @@
          * PHY to retrieve the desired data.
          */
         mdic = ((reg_addr << E1000_MDIC_REG_SHIFT) |
-                (phy_addr << E1000_MDIC_PHY_SHIFT) | 
+                (phy_addr << E1000_MDIC_PHY_SHIFT) |
                 (E1000_MDIC_OP_READ));
 
         E1000_WRITE_REG(hw, MDIC, mdic);
@@ -1913,7 +2214,7 @@
          * READ operation is performed.  These two bits are thrown away
          * followed by a shift in of 16 bits which contains the desired data.
          */
-        mdic = ((reg_addr) | (phy_addr << 5) | 
+        mdic = ((reg_addr) | (phy_addr << 5) |
                 (PHY_OP_READ << 10) | (PHY_SOF << 12));
 
         em_shift_out_mdi_bits(hw, mdic, 14);
@@ -1957,7 +2258,7 @@
          */
         mdic = (((uint32_t) phy_data) |
                 (reg_addr << E1000_MDIC_REG_SHIFT) |
-                (phy_addr << E1000_MDIC_PHY_SHIFT) | 
+                (phy_addr << E1000_MDIC_PHY_SHIFT) |
                 (E1000_MDIC_OP_WRITE));
 
         E1000_WRITE_REG(hw, MDIC, mdic);
@@ -1975,12 +2276,12 @@
     } else {
         /* We'll need to use the SW defined pins to shift the write command
          * out to the PHY. We first send a preamble to the PHY to signal the
-         * beginning of the MII instruction.  This is done by sending 32 
+         * beginning of the MII instruction.  This is done by sending 32
          * consecutive "1" bits.
          */
         em_shift_out_mdi_bits(hw, PHY_PREAMBLE, PHY_PREAMBLE_SIZE);
 
-        /* Now combine the remaining required fields that will indicate a 
+        /* Now combine the remaining required fields that will indicate a
          * write operation. We use this method instead of calling the
          * em_shift_out_mdi_bits routine for each field in the command. The
          * format of a MII write instruction is as follows:
@@ -1993,6 +2294,7 @@
 
         em_shift_out_mdi_bits(hw, mdic, 32);
     }
+
     return 0;
 }
 
@@ -2004,8 +2306,8 @@
 void
 em_phy_hw_reset(struct em_hw *hw)
 {
-    uint32_t ctrl;
-    uint32_t ctrl_ext;
+    uint32_t ctrl, ctrl_ext;
+    uint32_t led_ctrl;
 
     DEBUGFUNC("em_phy_hw_reset");
 
@@ -2017,8 +2319,10 @@
          */
         ctrl = E1000_READ_REG(hw, CTRL);
         E1000_WRITE_REG(hw, CTRL, ctrl | E1000_CTRL_PHY_RST);
+        E1000_WRITE_FLUSH(hw);
         msec_delay(10);
         E1000_WRITE_REG(hw, CTRL, ctrl);
+        E1000_WRITE_FLUSH(hw);
     } else {
         /* Read the Extended Device Control Register, assert the PHY_RESET_DIR
          * bit to put the PHY into reset. Then, take it out of reset.
@@ -2027,11 +2331,26 @@
         ctrl_ext |= E1000_CTRL_EXT_SDP4_DIR;
         ctrl_ext &= ~E1000_CTRL_EXT_SDP4_DATA;
         E1000_WRITE_REG(hw, CTRL_EXT, ctrl_ext);
+        E1000_WRITE_FLUSH(hw);
         msec_delay(10);
         ctrl_ext |= E1000_CTRL_EXT_SDP4_DATA;
         E1000_WRITE_REG(hw, CTRL_EXT, ctrl_ext);
+        E1000_WRITE_FLUSH(hw);
     }
     usec_delay(150);
+
+    if((hw->mac_type == em_82541) || (hw->mac_type == em_82547)) {
+        if(em_write_phy_reg(hw, IGP01E1000_PHY_PAGE_SELECT, 0x0000) < 0) {
+            DEBUGOUT("PHY Write Error\n");
+            return;
+        }
+
+        /* Configure activity LED after PHY reset */
+        led_ctrl = E1000_READ_REG(hw, LEDCTL);
+        led_ctrl &= IGP_ACTIVITY_LED_MASK;
+        led_ctrl |= (IGP_ACTIVITY_LED_ENABLE | IGP_LED3_MODE);
+        E1000_WRITE_REG(hw, LEDCTL, led_ctrl);
+    }
 }
 
 /******************************************************************************
@@ -2058,6 +2377,9 @@
         return -E1000_ERR_PHY;
     }
     usec_delay(1);
+    if (hw->phy_type == em_phy_igp) {
+        em_phy_init_script(hw);
+    }
     return 0;
 }
 
@@ -2071,6 +2393,7 @@
 {
     uint16_t phy_id_high, phy_id_low;
     boolean_t match = FALSE;
+    int32_t phy_init_status;
 
     DEBUGFUNC("em_detect_gig_phy");
 
@@ -2080,13 +2403,14 @@
         return -E1000_ERR_PHY;
     }
     hw->phy_id = (uint32_t) (phy_id_high << 16);
-    usec_delay(2);
+    usec_delay(20);
     if(em_read_phy_reg(hw, PHY_ID2, &phy_id_low) < 0) {
         DEBUGOUT("PHY Read Error\n");
         return -E1000_ERR_PHY;
     }
     hw->phy_id |= (uint32_t) (phy_id_low & PHY_REVISION_MASK);
-    
+    hw->phy_revision = (uint32_t) phy_id_low & ~PHY_REVISION_MASK;
+
     switch(hw->mac_type) {
     case em_82543:
         if(hw->phy_id == M88E1000_E_PHY_ID) match = TRUE;
@@ -2099,11 +2423,17 @@
     case em_82546:
         if(hw->phy_id == M88E1011_I_PHY_ID) match = TRUE;
         break;
+    case em_82541:
+    case em_82547:
+        if(hw->phy_id == IGP01E1000_I_PHY_ID) match = TRUE;
+        break;
     default:
         DEBUGOUT1("Invalid MAC type %d\n", hw->mac_type);
         return -E1000_ERR_CONFIG;
     }
-    if(match) {
+    phy_init_status = em_set_phy_type(hw);
+
+    if ((match) && (phy_init_status == E1000_SUCCESS)) {
         DEBUGOUT1("PHY ID 0x%X detected\n", hw->phy_id);
         return 0;
     }
@@ -2121,7 +2451,7 @@
 {
     int32_t ret_val = -E1000_ERR_PHY;
     DEBUGFUNC("em_phy_reset_dsp");
-    
+
     do {
         if(em_write_phy_reg(hw, 29, 0x001d) < 0) break;
         if(em_write_phy_reg(hw, 30, 0x00c1) < 0) break;
@@ -2134,6 +2464,133 @@
 }
 
 /******************************************************************************
+* Get PHY information from various PHY registers for igp PHY only.
+*
+* hw - Struct containing variables accessed by shared code
+* phy_info - PHY information structure
+******************************************************************************/
+int32_t
+em_phy_igp_get_info(struct em_hw *hw, struct em_phy_info *phy_info)
+{
+    uint16_t phy_data, polarity, min_length, max_length, average;
+
+    DEBUGFUNC("em_phy_igp_get_info");
+
+    /* The downshift status is checked only once, after link is established,
+     * and it stored in the hw->speed_downgraded parameter. */
+    phy_info->downshift = hw->speed_downgraded;
+
+    /* IGP01E1000 does not need to support it. */
+    phy_info->extended_10bt_distance = em_10bt_ext_dist_enable_normal;
+
+    /* IGP01E1000 always correct polarity reversal */
+    phy_info->polarity_correction = em_polarity_reversal_enabled;
+
+    /* Check polarity status */
+    if(em_check_polarity(hw, &polarity) < 0)
+        return -E1000_ERR_PHY;
+
+    phy_info->cable_polarity = polarity;
+
+    if(em_read_phy_reg(hw, IGP01E1000_PHY_PORT_STATUS, &phy_data) < 0)
+        return -E1000_ERR_PHY;
+
+    phy_info->mdix_mode = (phy_data & IGP01E1000_PSSR_MDIX) >>
+                          IGP01E1000_PSSR_MDIX_SHIFT;
+
+    if((phy_data & IGP01E1000_PSSR_SPEED_MASK) ==
+       IGP01E1000_PSSR_SPEED_1000MBPS) {
+        /* Local/Remote Receiver Information are only valid at 1000 Mbps */
+        if(em_read_phy_reg(hw, PHY_1000T_STATUS, &phy_data) < 0)
+            return -E1000_ERR_PHY;
+
+        phy_info->local_rx = (phy_data & SR_1000T_LOCAL_RX_STATUS) >>
+                             SR_1000T_LOCAL_RX_STATUS_SHIFT;
+        phy_info->remote_rx = (phy_data & SR_1000T_REMOTE_RX_STATUS) >>
+                              SR_1000T_REMOTE_RX_STATUS_SHIFT;
+
+        /* Get cable length */
+        if(em_get_cable_length(hw, &min_length, &max_length) < 0)
+            return -E1000_ERR_PHY;
+
+        /* transalte to old method */
+        average = (max_length + min_length) / 2;
+
+        if(average <= em_igp_cable_length_50)
+            phy_info->cable_length = em_cable_length_50;
+        else if(average <= em_igp_cable_length_80)
+            phy_info->cable_length = em_cable_length_50_80;
+        else if(average <= em_igp_cable_length_110)
+            phy_info->cable_length = em_cable_length_80_110;
+        else if(average <= em_igp_cable_length_140)
+            phy_info->cable_length = em_cable_length_110_140;
+        else
+            phy_info->cable_length = em_cable_length_140;
+    }
+
+    return E1000_SUCCESS;
+}
+
+/******************************************************************************
+* Get PHY information from various PHY registers fot m88 PHY only.
+*
+* hw - Struct containing variables accessed by shared code
+* phy_info - PHY information structure
+******************************************************************************/
+int32_t
+em_phy_m88_get_info(struct em_hw *hw, struct em_phy_info *phy_info)
+{
+    uint16_t phy_data, polarity;
+
+    DEBUGFUNC("em_phy_m88_get_info");
+
+    /* The downshift status is checked only once, after link is established,
+     * and it stored in the hw->speed_downgraded parameter. */
+    phy_info->downshift = hw->speed_downgraded;
+
+    if(em_read_phy_reg(hw, M88E1000_PHY_SPEC_CTRL, &phy_data) < 0)
+        return -E1000_ERR_PHY;
+
+    phy_info->extended_10bt_distance =
+        (phy_data & M88E1000_PSCR_10BT_EXT_DIST_ENABLE) >>
+        M88E1000_PSCR_10BT_EXT_DIST_ENABLE_SHIFT;
+    phy_info->polarity_correction =
+        (phy_data & M88E1000_PSCR_POLARITY_REVERSAL) >>
+        M88E1000_PSCR_POLARITY_REVERSAL_SHIFT;
+
+    /* Check polarity status */
+    if(em_check_polarity(hw, &polarity) < 0)
+        return -E1000_ERR_PHY;
+
+    phy_info->cable_polarity = polarity;
+
+    if(em_read_phy_reg(hw, M88E1000_PHY_SPEC_STATUS, &phy_data) < 0)
+        return -E1000_ERR_PHY;
+
+    phy_info->mdix_mode = (phy_data & M88E1000_PSSR_MDIX) >>
+                          M88E1000_PSSR_MDIX_SHIFT;
+
+    if(phy_data & M88E1000_PSSR_1000MBS) {
+        /* Cable Length Estimation and Local/Remote Receiver Informatoion
+         * are only valid at 1000 Mbps
+         */
+        phy_info->cable_length = ((phy_data & M88E1000_PSSR_CABLE_LENGTH) >>
+                                  M88E1000_PSSR_CABLE_LENGTH_SHIFT);
+
+        if(em_read_phy_reg(hw, PHY_1000T_STATUS, &phy_data) < 0)
+            return -E1000_ERR_PHY;
+
+        phy_info->local_rx = (phy_data & SR_1000T_LOCAL_RX_STATUS) >>
+                             SR_1000T_LOCAL_RX_STATUS_SHIFT;
+
+        phy_info->remote_rx = (phy_data & SR_1000T_REMOTE_RX_STATUS) >>
+                              SR_1000T_REMOTE_RX_STATUS_SHIFT;
+    }
+
+    return E1000_SUCCESS;
+}
+
+/******************************************************************************
 * Get PHY information from various PHY registers
 *
 * hw - Struct containing variables accessed by shared code
@@ -2143,7 +2600,6 @@
 em_phy_get_info(struct em_hw *hw,
                    struct em_phy_info *phy_info)
 {
-    int32_t ret_val = -E1000_ERR_PHY;
     uint16_t phy_data;
 
     DEBUGFUNC("em_phy_get_info");
@@ -2151,6 +2607,7 @@
     phy_info->cable_length = em_cable_length_undefined;
     phy_info->extended_10bt_distance = em_10bt_ext_dist_enable_undefined;
     phy_info->cable_polarity = em_rev_polarity_undefined;
+    phy_info->downshift = em_downshift_undefined;
     phy_info->polarity_correction = em_polarity_reversal_undefined;
     phy_info->mdix_mode = em_auto_x_mode_undefined;
     phy_info->local_rx = em_1000t_rx_status_undefined;
@@ -2161,47 +2618,23 @@
         return -E1000_ERR_CONFIG;
     }
 
-    do {
-        if(em_read_phy_reg(hw, PHY_STATUS, &phy_data) < 0) break;
-        if(em_read_phy_reg(hw, PHY_STATUS, &phy_data) < 0) break;
-        if((phy_data & MII_SR_LINK_STATUS) != MII_SR_LINK_STATUS) {
-            DEBUGOUT("PHY info is only valid if link is up\n");
-            return -E1000_ERR_CONFIG;
-        }
-
-        if(em_read_phy_reg(hw, M88E1000_PHY_SPEC_CTRL, &phy_data) < 0)
-            break;
-        phy_info->extended_10bt_distance =
-            (phy_data & M88E1000_PSCR_10BT_EXT_DIST_ENABLE) >>
-            M88E1000_PSCR_10BT_EXT_DIST_ENABLE_SHIFT;
-        phy_info->polarity_correction =
-            (phy_data & M88E1000_PSCR_POLARITY_REVERSAL) >>
-            M88E1000_PSCR_POLARITY_REVERSAL_SHIFT;
-
-        if(em_read_phy_reg(hw, M88E1000_PHY_SPEC_STATUS, &phy_data) < 0)
-            break;
-        phy_info->cable_polarity = (phy_data & M88E1000_PSSR_REV_POLARITY) >>
-            M88E1000_PSSR_REV_POLARITY_SHIFT;
-        phy_info->mdix_mode = (phy_data & M88E1000_PSSR_MDIX) >>
-            M88E1000_PSSR_MDIX_SHIFT;
-        if(phy_data & M88E1000_PSSR_1000MBS) {
-            /* Cable Length Estimation and Local/Remote Receiver Informatoion
-             * are only valid at 1000 Mbps
-             */
-            phy_info->cable_length = ((phy_data & M88E1000_PSSR_CABLE_LENGTH) >>
-                                      M88E1000_PSSR_CABLE_LENGTH_SHIFT);
-            if(em_read_phy_reg(hw, PHY_1000T_STATUS, &phy_data) < 0) 
-                break;
-            phy_info->local_rx = (phy_data & SR_1000T_LOCAL_RX_STATUS) >>
-                SR_1000T_LOCAL_RX_STATUS_SHIFT;
-            phy_info->remote_rx = (phy_data & SR_1000T_REMOTE_RX_STATUS) >>
-                SR_1000T_REMOTE_RX_STATUS_SHIFT;
-        }
-        ret_val = 0;
-    } while(0);
+    if(em_read_phy_reg(hw, PHY_STATUS, &phy_data) < 0) {
+        DEBUGOUT("PHY Read Error\n");
+        return -E1000_ERR_PHY;
+    }
+    if(em_read_phy_reg(hw, PHY_STATUS, &phy_data) < 0) {
+        DEBUGOUT("PHY Read Error\n");
+        return -E1000_ERR_PHY;
+    }
+    if((phy_data & MII_SR_LINK_STATUS) != MII_SR_LINK_STATUS) {
+        DEBUGOUT("PHY info is only valid if link is up\n");
+        return -E1000_ERR_CONFIG;
+    }
 
-    if(ret_val < 0) DEBUGOUT("PHY Read Error\n");
-    return ret_val;
+    if (hw->phy_type == em_phy_igp)
+        return em_phy_igp_get_info(hw, phy_info);
+    else
+        return em_phy_m88_get_info(hw, phy_info);
 }
 
 int32_t
@@ -2217,6 +2650,109 @@
     return 0;
 }
 
+
+/******************************************************************************
+ * Sets up eeprom variables in the hw struct.  Must be called after mac_type
+ * is configured.
+ *
+ * hw - Struct containing variables accessed by shared code
+ *****************************************************************************/
+void
+em_init_eeprom_params(struct em_hw *hw)
+{
+    struct em_eeprom_info *eeprom = &hw->eeprom;
+    uint32_t eecd = E1000_READ_REG(hw, EECD);
+    uint16_t eeprom_size;
+
+    DEBUGFUNC("em_init_eeprom_params");
+
+    switch (hw->mac_type) {
+    case em_82542_rev2_0:
+    case em_82542_rev2_1:
+    case em_82543:
+    case em_82544:
+        eeprom->type = em_eeprom_microwire;
+        eeprom->word_size = 64;
+        eeprom->opcode_bits = 3;
+        eeprom->address_bits = 6;
+        eeprom->delay_usec = 50;
+        break;
+    case em_82540:
+    case em_82545:
+    case em_82546:
+        eeprom->type = em_eeprom_microwire;
+        eeprom->opcode_bits = 3;
+        eeprom->delay_usec = 50;
+        if(eecd & E1000_EECD_SIZE) {
+            eeprom->word_size = 256;
+            eeprom->address_bits = 8;
+        } else {
+            eeprom->word_size = 64;
+            eeprom->address_bits = 6;
+        }
+        break;
+    case em_82541:
+    case em_82547:
+    default:
+        if (eecd & E1000_EECD_TYPE) {
+            eeprom->type = em_eeprom_spi;
+            eeprom->opcode_bits = 8;
+            eeprom->delay_usec = 1;
+            if (eecd & E1000_EECD_ADDR_BITS) {
+                eeprom->page_size = 32;
+                eeprom->address_bits = 16;
+            } else {
+                eeprom->page_size = 8;
+                eeprom->address_bits = 8;
+            }
+        } else {
+            eeprom->type = em_eeprom_microwire;
+            eeprom->opcode_bits = 3;
+            eeprom->delay_usec = 50;
+            if (eecd & E1000_EECD_ADDR_BITS) {
+                eeprom->word_size = 256;
+                eeprom->address_bits = 8;
+            } else {
+                eeprom->word_size = 64;
+                eeprom->address_bits = 6;
+            }
+        }
+        break;
+    }
+
+    if (eeprom->type == em_eeprom_spi) {
+        eeprom->word_size = 64;
+        if (em_read_eeprom(hw, EEPROM_CFG, 1, &eeprom_size) == 0) {
+            eeprom_size &= EEPROM_SIZE_MASK;
+
+            switch (eeprom_size) {
+                case EEPROM_SIZE_16KB:
+                    eeprom->word_size = 8192;
+                    break;
+                case EEPROM_SIZE_8KB:
+                    eeprom->word_size = 4096;
+                    break;
+                case EEPROM_SIZE_4KB:
+                    eeprom->word_size = 2048;
+                    break;
+                case EEPROM_SIZE_2KB:
+                    eeprom->word_size = 1024;
+                    break;
+                case EEPROM_SIZE_1KB:
+                    eeprom->word_size = 512;
+                    break;
+                case EEPROM_SIZE_512B:
+                    eeprom->word_size = 256;
+                    break;
+                case EEPROM_SIZE_128B:
+                default:
+                    eeprom->word_size = 64;
+                    break;
+            }
+        }
+    }
+}
+
 /******************************************************************************
  * Raises the EEPROM's clock input.
  *
@@ -2228,29 +2764,31 @@
                    uint32_t *eecd)
 {
     /* Raise the clock input to the EEPROM (by setting the SK bit), and then
-     * wait 50 microseconds.
+     * wait <delay> microseconds.
      */
     *eecd = *eecd | E1000_EECD_SK;
     E1000_WRITE_REG(hw, EECD, *eecd);
-    usec_delay(50);
+    E1000_WRITE_FLUSH(hw);
+    usec_delay(hw->eeprom.delay_usec);
 }
 
 /******************************************************************************
  * Lowers the EEPROM's clock input.
  *
- * hw - Struct containing variables accessed by shared code 
+ * hw - Struct containing variables accessed by shared code
  * eecd - EECD's current value
  *****************************************************************************/
 static void
 em_lower_ee_clk(struct em_hw *hw,
                    uint32_t *eecd)
 {
-    /* Lower the clock input to the EEPROM (by clearing the SK bit), and then 
-     * wait 50 microseconds. 
+    /* Lower the clock input to the EEPROM (by clearing the SK bit), and then
+     * wait 50 microseconds.
      */
     *eecd = *eecd & ~E1000_EECD_SK;
     E1000_WRITE_REG(hw, EECD, *eecd);
-    usec_delay(50);
+    E1000_WRITE_FLUSH(hw);
+    usec_delay(hw->eeprom.delay_usec);
 }
 
 /******************************************************************************
@@ -2265,16 +2803,21 @@
                         uint16_t data,
                         uint16_t count)
 {
+    struct em_eeprom_info *eeprom = &hw->eeprom;
     uint32_t eecd;
     uint32_t mask;
 
     /* We need to shift "count" bits out to the EEPROM. So, value in the
      * "data" parameter will be shifted out to the EEPROM one bit at a time.
-     * In order to do this, "data" must be broken down into bits. 
+     * In order to do this, "data" must be broken down into bits.
      */
     mask = 0x01 << (count - 1);
     eecd = E1000_READ_REG(hw, EECD);
-    eecd &= ~(E1000_EECD_DO | E1000_EECD_DI);
+    if (eeprom->type == em_eeprom_microwire) {
+        eecd &= ~E1000_EECD_DO;
+    } else if (eeprom->type == em_eeprom_spi) {
+        eecd |= E1000_EECD_DO;
+    }
     do {
         /* A "1" is shifted out to the EEPROM by setting bit "DI" to a "1",
          * and then raising and then lowering the clock (the SK bit controls
@@ -2287,8 +2830,9 @@
             eecd |= E1000_EECD_DI;
 
         E1000_WRITE_REG(hw, EECD, eecd);
+        E1000_WRITE_FLUSH(hw);
 
-        usec_delay(50);
+        usec_delay(eeprom->delay_usec);
 
         em_raise_ee_clk(hw, &eecd);
         em_lower_ee_clk(hw, &eecd);
@@ -2308,17 +2852,17 @@
  * hw - Struct containing variables accessed by shared code
  *****************************************************************************/
 static uint16_t
-em_shift_in_ee_bits(struct em_hw *hw)
+em_shift_in_ee_bits(struct em_hw *hw, uint16_t count)
 {
     uint32_t eecd;
     uint32_t i;
     uint16_t data;
 
-    /* In order to read a register from the EEPROM, we need to shift 16 bits 
-     * in from the EEPROM. Bits are "shifted in" by raising the clock input to
-     * the EEPROM (setting the SK bit), and then reading the value of the "DO"
-     * bit.  During this "shifting in" process the "DI" bit should always be 
-     * clear..
+    /* In order to read a register from the EEPROM, we need to shift 'count'
+     * bits in from the EEPROM. Bits are "shifted in" by raising the clock
+     * input to the EEPROM (setting the SK bit), and then reading the value of
+     * the "DO" bit.  During this "shifting in" process the "DI" bit should
+     * always be clear.
      */
 
     eecd = E1000_READ_REG(hw, EECD);
@@ -2326,7 +2870,7 @@
     eecd &= ~(E1000_EECD_DO | E1000_EECD_DI);
     data = 0;
 
-    for(i = 0; i < 16; i++) {
+    for(i = 0; i < count; i++) {
         data = data << 1;
         em_raise_ee_clk(hw, &eecd);
 
@@ -2347,98 +2891,196 @@
  *
  * hw - Struct containing variables accessed by shared code
  *
- * Lowers EEPROM clock. Clears input pin. Sets the chip select pin. This 
+ * Lowers EEPROM clock. Clears input pin. Sets the chip select pin. This
  * function should be called before issuing a command to the EEPROM.
  *****************************************************************************/
-static void
-em_setup_eeprom(struct em_hw *hw)
+static int32_t
+em_acquire_eeprom(struct em_hw *hw)
 {
-    uint32_t eecd;
+    struct em_eeprom_info *eeprom = &hw->eeprom;
+    uint32_t eecd, i=0;
+
+    DEBUGFUNC("em_acquire_eeprom");
 
     eecd = E1000_READ_REG(hw, EECD);
 
-    /* Clear SK and DI */
-    eecd &= ~(E1000_EECD_SK | E1000_EECD_DI);
-    E1000_WRITE_REG(hw, EECD, eecd);
+    /* Request EEPROM Access */
+    if(hw->mac_type > em_82544) {
+        eecd |= E1000_EECD_REQ;
+        E1000_WRITE_REG(hw, EECD, eecd);
+        eecd = E1000_READ_REG(hw, EECD);
+        while((!(eecd & E1000_EECD_GNT)) &&
+              (i < E1000_EEPROM_GRANT_ATTEMPTS)) {
+            i++;
+            usec_delay(5);
+            eecd = E1000_READ_REG(hw, EECD);
+        }
+        if(!(eecd & E1000_EECD_GNT)) {
+            eecd &= ~E1000_EECD_REQ;
+            E1000_WRITE_REG(hw, EECD, eecd);
+            DEBUGOUT("Could not acquire EEPROM grant\n");
+            return -E1000_ERR_EEPROM;
+        }
+    }
 
-    /* Set CS */
-    eecd |= E1000_EECD_CS;
-    E1000_WRITE_REG(hw, EECD, eecd);
+    /* Setup EEPROM for Read/Write */
+
+    if (eeprom->type == em_eeprom_microwire) {
+        /* Clear SK and DI */
+        eecd &= ~(E1000_EECD_DI | E1000_EECD_SK);
+        E1000_WRITE_REG(hw, EECD, eecd);
+
+        /* Set CS */
+        eecd |= E1000_EECD_CS;
+        E1000_WRITE_REG(hw, EECD, eecd);
+    } else if (eeprom->type == em_eeprom_spi) {
+        /* Clear SK and CS */
+        eecd &= ~(E1000_EECD_CS | E1000_EECD_SK);
+        E1000_WRITE_REG(hw, EECD, eecd);
+        usec_delay(1);
+    }
+
+    return E1000_SUCCESS;
 }
 
 /******************************************************************************
  * Returns EEPROM to a "standby" state
- * 
+ *
  * hw - Struct containing variables accessed by shared code
  *****************************************************************************/
 static void
 em_standby_eeprom(struct em_hw *hw)
 {
+    struct em_eeprom_info *eeprom = &hw->eeprom;
     uint32_t eecd;
 
     eecd = E1000_READ_REG(hw, EECD);
 
-    /* Deselct EEPROM */
-    eecd &= ~(E1000_EECD_CS | E1000_EECD_SK);
-    E1000_WRITE_REG(hw, EECD, eecd);
-    usec_delay(50);
+    if(eeprom->type == em_eeprom_microwire) {
+        eecd &= ~(E1000_EECD_CS | E1000_EECD_SK);
+        E1000_WRITE_REG(hw, EECD, eecd);
+        E1000_WRITE_FLUSH(hw);
+        usec_delay(eeprom->delay_usec);
 
-    /* Clock high */
-    eecd |= E1000_EECD_SK;
-    E1000_WRITE_REG(hw, EECD, eecd);
-    usec_delay(50);
+        /* Clock high */
+        eecd |= E1000_EECD_SK;
+        E1000_WRITE_REG(hw, EECD, eecd);
+        E1000_WRITE_FLUSH(hw);
+        usec_delay(eeprom->delay_usec);
 
-    /* Select EEPROM */
-    eecd |= E1000_EECD_CS;
-    E1000_WRITE_REG(hw, EECD, eecd);
-    usec_delay(50);
+        /* Select EEPROM */
+        eecd |= E1000_EECD_CS;
+        E1000_WRITE_REG(hw, EECD, eecd);
+        E1000_WRITE_FLUSH(hw);
+        usec_delay(eeprom->delay_usec);
 
-    /* Clock low */
-    eecd &= ~E1000_EECD_SK;
-    E1000_WRITE_REG(hw, EECD, eecd);
-    usec_delay(50);
+        /* Clock low */
+        eecd &= ~E1000_EECD_SK;
+        E1000_WRITE_REG(hw, EECD, eecd);
+        E1000_WRITE_FLUSH(hw);
+        usec_delay(eeprom->delay_usec);
+    } else if(eeprom->type == em_eeprom_spi) {
+        /* Toggle CS to flush commands */
+        eecd |= E1000_EECD_CS;
+        E1000_WRITE_REG(hw, EECD, eecd);
+        E1000_WRITE_FLUSH(hw);
+        usec_delay(eeprom->delay_usec);
+        eecd &= ~E1000_EECD_CS;
+        E1000_WRITE_REG(hw, EECD, eecd);
+        E1000_WRITE_FLUSH(hw);
+        usec_delay(eeprom->delay_usec);
+    }
 }
 
 /******************************************************************************
- * Raises then lowers the EEPROM's clock pin
+ * Terminates a command by inverting the EEPROM's chip select pin
  *
  * hw - Struct containing variables accessed by shared code
  *****************************************************************************/
 static void
-em_clock_eeprom(struct em_hw *hw)
+em_release_eeprom(struct em_hw *hw)
 {
     uint32_t eecd;
 
-    eecd = E1000_READ_REG(hw, EECD);
+    DEBUGFUNC("em_release_eeprom");
+
+    eecd = E1000_READ_REG(hw, EECD);
+
+    if (hw->eeprom.type == em_eeprom_spi) {
+        eecd |= E1000_EECD_CS;  /* Pull CS high */
+        eecd &= ~E1000_EECD_SK; /* Lower SCK */
+
+        E1000_WRITE_REG(hw, EECD, eecd);
 
-    /* Rising edge of clock */
-    eecd |= E1000_EECD_SK;
-    E1000_WRITE_REG(hw, EECD, eecd);
-    usec_delay(50);
+        usec_delay(hw->eeprom.delay_usec);
+    } else if(hw->eeprom.type == em_eeprom_microwire) {
+        /* cleanup eeprom */
 
-    /* Falling edge of clock */
-    eecd &= ~E1000_EECD_SK;
-    E1000_WRITE_REG(hw, EECD, eecd);
-    usec_delay(50);
+        /* CS on Microwire is active-high */
+        eecd &= ~(E1000_EECD_CS | E1000_EECD_DI);
+
+        E1000_WRITE_REG(hw, EECD, eecd);
+
+        /* Rising edge of clock */
+        eecd |= E1000_EECD_SK;
+        E1000_WRITE_REG(hw, EECD, eecd);
+        E1000_WRITE_FLUSH(hw);
+        usec_delay(hw->eeprom.delay_usec);
+
+        /* Falling edge of clock */
+        eecd &= ~E1000_EECD_SK;
+        E1000_WRITE_REG(hw, EECD, eecd);
+        E1000_WRITE_FLUSH(hw);
+        usec_delay(hw->eeprom.delay_usec);
+    }
+
+    /* Stop requesting EEPROM access */
+    if(hw->mac_type > em_82544) {
+        eecd &= ~E1000_EECD_REQ;
+        E1000_WRITE_REG(hw, EECD, eecd);
+    }
 }
 
 /******************************************************************************
- * Terminates a command by lowering the EEPROM's chip select pin
+ * Reads a 16 bit word from the EEPROM.
  *
  * hw - Struct containing variables accessed by shared code
  *****************************************************************************/
-static void
-em_cleanup_eeprom(struct em_hw *hw)
+int32_t
+em_spi_eeprom_ready(struct em_hw *hw)
 {
-    uint32_t eecd;
+    uint16_t retry_count = 0;
+    uint8_t spi_stat_reg;
 
-    eecd = E1000_READ_REG(hw, EECD);
+    DEBUGFUNC("em_spi_eeprom_ready");
+
+    /* Read "Status Register" repeatedly until the LSB is cleared.  The
+     * EEPROM will signal that the command has been completed by clearing
+     * bit 0 of the internal status register.  If it's not cleared within
+     * 5 milliseconds, then error out.
+     */
+    retry_count = 0;
+    do {
+        em_shift_out_ee_bits(hw, EEPROM_RDSR_OPCODE_SPI,
+                                hw->eeprom.opcode_bits);
+        spi_stat_reg = (uint8_t)em_shift_in_ee_bits(hw, 8);
+        if (!(spi_stat_reg & EEPROM_STATUS_RDY_SPI))
+            break;
 
-    eecd &= ~(E1000_EECD_CS | E1000_EECD_DI);
+        usec_delay(5);
+        retry_count += 5;
 
-    E1000_WRITE_REG(hw, EECD, eecd);
+    } while(retry_count < EEPROM_MAX_RETRY_SPI);
+
+    /* ATMEL SPI write time could vary from 0-20mSec on 3.3V devices (and
+     * only 0-5mSec on 5V devices)
+     */
+    if(retry_count >= EEPROM_MAX_RETRY_SPI) {
+        DEBUGOUT("SPI EEPROM Status error\n");
+        return -E1000_ERR_EEPROM;
+    }
 
-    em_clock_eeprom(hw);
+    return E1000_SUCCESS;
 }
 
 /******************************************************************************
@@ -2446,71 +3088,76 @@
  *
  * hw - Struct containing variables accessed by shared code
  * offset - offset of  word in the EEPROM to read
- * data - word read from the EEPROM 
+ * data - word read from the EEPROM
+ * words - number of words to read
  *****************************************************************************/
 int32_t
 em_read_eeprom(struct em_hw *hw,
                   uint16_t offset,
+                  uint16_t words,
                   uint16_t *data)
 {
-    uint32_t eecd;
+    struct em_eeprom_info *eeprom = &hw->eeprom;
     uint32_t i = 0;
-    boolean_t large_eeprom = FALSE;
 
     DEBUGFUNC("em_read_eeprom");
 
-    /* Request EEPROM Access */
-    if(hw->mac_type > em_82544) {
-        eecd = E1000_READ_REG(hw, EECD);
-        if(eecd & E1000_EECD_SIZE) large_eeprom = TRUE;
-        eecd |= E1000_EECD_REQ;
-        E1000_WRITE_REG(hw, EECD, eecd);
-        eecd = E1000_READ_REG(hw, EECD);
-        while((!(eecd & E1000_EECD_GNT)) && (i < 100)) {
-            i++;
-            usec_delay(5);
-            eecd = E1000_READ_REG(hw, EECD);
-        }
-        if(!(eecd & E1000_EECD_GNT)) {
-            eecd &= ~E1000_EECD_REQ;
-            E1000_WRITE_REG(hw, EECD, eecd);
-            DEBUGOUT("Could not acquire EEPROM grant\n");
-            return -E1000_ERR_EEPROM;
-        }
+    /* A check for invalid values:  offset too large, too many words, and not
+     * enough words.
+     */
+    if((offset > eeprom->word_size) || (words > eeprom->word_size - offset) ||
+       (words == 0)) {
+        DEBUGOUT("\"words\" parameter out of bounds\n");
+        return -E1000_ERR_EEPROM;
     }
 
-    /*  Prepare the EEPROM for reading  */
-    em_setup_eeprom(hw);
+    /* Prepare the EEPROM for reading  */
+    if (em_acquire_eeprom(hw) != E1000_SUCCESS)
+        return -E1000_ERR_EEPROM;
 
-    /*  Send the READ command (opcode + addr)  */
-    em_shift_out_ee_bits(hw, EEPROM_READ_OPCODE, 3);
-    if(large_eeprom) {
-        /* If we have a 256 word EEPROM, there are 8 address bits */
-        em_shift_out_ee_bits(hw, offset, 8);
-    } else {
-        /* If we have a 64 word EEPROM, there are 6 address bits */
-        em_shift_out_ee_bits(hw, offset, 6);
-    }
+    if(eeprom->type == em_eeprom_spi) {
+        uint8_t read_opcode = EEPROM_READ_OPCODE_SPI;
 
-    /* Read the data */
-    *data = em_shift_in_ee_bits(hw);
+        if(em_spi_eeprom_ready(hw)) return -E1000_ERR_EEPROM;
 
-    /* End this read operation */
-    em_standby_eeprom(hw);
+        em_standby_eeprom(hw);
 
-    /* Stop requesting EEPROM access */
-    if(hw->mac_type > em_82544) {
-        eecd = E1000_READ_REG(hw, EECD);
-        eecd &= ~E1000_EECD_REQ;
-        E1000_WRITE_REG(hw, EECD, eecd);
+        /* Some SPI eeproms use the 8th address bit embedded in the opcode */
+        if((eeprom->address_bits == 8) && (offset >= 128))
+            read_opcode |= EEPROM_A8_OPCODE_SPI;
+
+        /* Send the READ command (opcode + addr)  */
+        em_shift_out_ee_bits(hw, read_opcode, eeprom->opcode_bits);
+        em_shift_out_ee_bits(hw, (uint16_t)(offset*2), eeprom->address_bits);
+    }
+    else if(eeprom->type == em_eeprom_microwire) {
+        /* Send the READ command (opcode + addr)  */
+        em_shift_out_ee_bits(hw, EEPROM_READ_OPCODE_MICROWIRE,
+                                eeprom->opcode_bits);
+        em_shift_out_ee_bits(hw, offset, eeprom->address_bits);
+    }
+
+    /* Read the data.  The address of the eeprom internally increments with
+     * each word (microwire) or byte (spi) being read, saving on the overhead
+     * of eeprom setup and tear-down.  The address counter will roll over if
+     * reading beyond the size of the eeprom, thus allowing the entire memory
+     * to be read starting from any offset. */
+    for (i = 0; i < words; i++) {
+        uint16_t word_in = em_shift_in_ee_bits(hw, 16);
+        if (eeprom->type == em_eeprom_spi)
+            word_in = (word_in >> 8) | (word_in << 8);
+        data[i] = word_in;
     }
 
+    /* End this read operation */
+    em_release_eeprom(hw);
+
     return 0;
 }
 
 /******************************************************************************
  * Verifies that the EEPROM has a valid checksum
- * 
+ *
  * hw - Struct containing variables accessed by shared code
  *
  * Reads the first 64 16 bit words of the EEPROM and sums the values read.
@@ -2526,7 +3173,7 @@
     DEBUGFUNC("em_validate_eeprom_checksum");
 
     for(i = 0; i < (EEPROM_CHECKSUM_REG + 1); i++) {
-        if(em_read_eeprom(hw, i, &eeprom_data) < 0) {
+        if(em_read_eeprom(hw, i, 1, &eeprom_data) < 0) {
             DEBUGOUT("EEPROM Read Error\n");
             return -E1000_ERR_EEPROM;
         }
@@ -2536,7 +3183,7 @@
     if(checksum == (uint16_t) EEPROM_SUM) {
         return 0;
     } else {
-        DEBUGOUT("EEPROM Checksum Invalid\n");    
+        DEBUGOUT("EEPROM Checksum Invalid\n");
         return -E1000_ERR_EEPROM;
     }
 }
@@ -2558,14 +3205,14 @@
     DEBUGFUNC("em_update_eeprom_checksum");
 
     for(i = 0; i < EEPROM_CHECKSUM_REG; i++) {
-        if(em_read_eeprom(hw, i, &eeprom_data) < 0) {
+        if(em_read_eeprom(hw, i, 1, &eeprom_data) < 0) {
             DEBUGOUT("EEPROM Read Error\n");
             return -E1000_ERR_EEPROM;
         }
         checksum += eeprom_data;
     }
     checksum = (uint16_t) EEPROM_SUM - checksum;
-    if(em_write_eeprom(hw, EEPROM_CHECKSUM_REG, checksum) < 0) {
+    if(em_write_eeprom(hw, EEPROM_CHECKSUM_REG, 1, &checksum) < 0) {
         DEBUGOUT("EEPROM Write Error\n");
         return -E1000_ERR_EEPROM;
     }
@@ -2573,118 +3220,201 @@
 }
 
 /******************************************************************************
- * Writes a 16 bit word to a given offset in the EEPROM.
+ * Parent function for writing words to the different EEPROM types.
  *
  * hw - Struct containing variables accessed by shared code
  * offset - offset within the EEPROM to be written to
- * data - 16 bit word to be writen to the EEPROM
+ * words - number of words to write
+ * data - 16 bit word to be written to the EEPROM
  *
- * If em_update_eeprom_checksum is not called after this function, the 
+ * If em_update_eeprom_checksum is not called after this function, the
  * EEPROM will most likely contain an invalid checksum.
  *****************************************************************************/
 int32_t
 em_write_eeprom(struct em_hw *hw,
                    uint16_t offset,
-                   uint16_t data)
+                   uint16_t words,
+                   uint16_t *data)
 {
-    uint32_t eecd;
-    uint32_t i = 0;
+    struct em_eeprom_info *eeprom = &hw->eeprom;
     int32_t status = 0;
-    boolean_t large_eeprom = FALSE;
 
     DEBUGFUNC("em_write_eeprom");
 
-    /* Request EEPROM Access */
-    if(hw->mac_type > em_82544) {
-        eecd = E1000_READ_REG(hw, EECD);
-        if(eecd & E1000_EECD_SIZE) large_eeprom = TRUE;
-        eecd |= E1000_EECD_REQ;
-        E1000_WRITE_REG(hw, EECD, eecd);
-        eecd = E1000_READ_REG(hw, EECD);
-        while((!(eecd & E1000_EECD_GNT)) && (i < 100)) {
-            i++;
-            usec_delay(5);
-            eecd = E1000_READ_REG(hw, EECD);
-        }
-        if(!(eecd & E1000_EECD_GNT)) {
-            eecd &= ~E1000_EECD_REQ;
-            E1000_WRITE_REG(hw, EECD, eecd);
-            DEBUGOUT("Could not acquire EEPROM grant\n");
-            return -E1000_ERR_EEPROM;
-        }
+    /* A check for invalid values:  offset too large, too many words, and not
+     * enough words.
+     */
+    if((offset > eeprom->word_size) || (words > eeprom->word_size - offset) ||
+       (words == 0)) {
+        DEBUGOUT("\"words\" parameter out of bounds\n");
+        return -E1000_ERR_EEPROM;
     }
 
     /* Prepare the EEPROM for writing  */
-    em_setup_eeprom(hw);
+    if (em_acquire_eeprom(hw) != E1000_SUCCESS)
+        return -E1000_ERR_EEPROM;
 
-    /* Send the 9-bit (or 11-bit on large EEPROM) EWEN (write enable) command
-     * to the EEPROM (5-bit opcode plus 4/6-bit dummy). This puts the EEPROM
-     * into write/erase mode. 
-     */
-    em_shift_out_ee_bits(hw, EEPROM_EWEN_OPCODE, 5);
-    if(large_eeprom) 
-        em_shift_out_ee_bits(hw, 0, 6);
+    if(eeprom->type == em_eeprom_microwire)
+        status = em_write_eeprom_microwire(hw, offset, words, data);
     else
-        em_shift_out_ee_bits(hw, 0, 4);
+        status = em_write_eeprom_spi(hw, offset, words, data);
 
-    /* Prepare the EEPROM */
-    em_standby_eeprom(hw);
+    /* Done with writing */
+    em_release_eeprom(hw);
 
-    /* Send the Write command (3-bit opcode + addr) */
-    em_shift_out_ee_bits(hw, EEPROM_WRITE_OPCODE, 3);
-    if(large_eeprom) 
-        /* If we have a 256 word EEPROM, there are 8 address bits */
-        em_shift_out_ee_bits(hw, offset, 8);
-    else
-        /* If we have a 64 word EEPROM, there are 6 address bits */
-        em_shift_out_ee_bits(hw, offset, 6);
+    return status;
+}
+
+/******************************************************************************
+ * Writes a 16 bit word to a given offset in an SPI EEPROM.
+ *
+ * hw - Struct containing variables accessed by shared code
+ * offset - offset within the EEPROM to be written to
+ * words - number of words to write
+ * data - pointer to array of 8 bit words to be written to the EEPROM
+ *
+ *****************************************************************************/
+int32_t
+em_write_eeprom_spi(struct em_hw *hw,
+                       uint16_t offset,
+                       uint16_t words,
+                       uint16_t *data)
+{
+    struct em_eeprom_info *eeprom = &hw->eeprom;
+    uint16_t widx = 0;
 
-    /* Send the data */
-    em_shift_out_ee_bits(hw, data, 16);
+    DEBUGFUNC("em_write_eeprom_spi");
 
-    /* Toggle the CS line.  This in effect tells to EEPROM to actually execute 
-     * the command in question.
-     */
-    em_standby_eeprom(hw);
+    while (widx < words) {
+        uint8_t write_opcode = EEPROM_WRITE_OPCODE_SPI;
 
-    /* Now read DO repeatedly until is high (equal to '1').  The EEEPROM will
-     * signal that the command has been completed by raising the DO signal.
-     * If DO does not go high in 10 milliseconds, then error out.
-     */
-    for(i = 0; i < 200; i++) {
-        eecd = E1000_READ_REG(hw, EECD);
-        if(eecd & E1000_EECD_DO) break;
-        usec_delay(50);
-    }
-    if(i == 200) {
-        DEBUGOUT("EEPROM Write did not complete\n");
-        status = -E1000_ERR_EEPROM;
+        if(em_spi_eeprom_ready(hw)) return -E1000_ERR_EEPROM;
+
+        em_standby_eeprom(hw);
+
+        /*  Send the WRITE ENABLE command (8 bit opcode )  */
+        em_shift_out_ee_bits(hw, EEPROM_WREN_OPCODE_SPI,
+                                    eeprom->opcode_bits);
+
+        em_standby_eeprom(hw);
+
+        /* Some SPI eeproms use the 8th address bit embedded in the opcode */
+        if((eeprom->address_bits == 8) && (offset >= 128))
+            write_opcode |= EEPROM_A8_OPCODE_SPI;
+
+        /* Send the Write command (8-bit opcode + addr) */
+        em_shift_out_ee_bits(hw, write_opcode, eeprom->opcode_bits);
+
+        em_shift_out_ee_bits(hw, (uint16_t)((offset + widx)*2),
+                                eeprom->address_bits);
+
+        /* Send the data */
+
+        /* Loop to allow for up to whole page write (32 bytes) of eeprom */
+        while (widx < words) {
+            uint16_t word_out = data[widx];
+            word_out = (word_out >> 8) | (word_out << 8);
+            em_shift_out_ee_bits(hw, word_out, 16);
+            widx++;
+
+            /* Some larger eeprom sizes are capable of a 32-byte PAGE WRITE
+             * operation, while the smaller eeproms are capable of an 8-byte
+             * PAGE WRITE operation.  Break the inner loop to pass new address
+             */
+            if((((offset + widx)*2) % eeprom->page_size) == 0) {
+                em_standby_eeprom(hw);
+                break;
+            }
+        }
     }
 
-    /* Recover from write */
+    return E1000_SUCCESS;
+}
+
+/******************************************************************************
+ * Writes a 16 bit word to a given offset in a Microwire EEPROM.
+ *
+ * hw - Struct containing variables accessed by shared code
+ * offset - offset within the EEPROM to be written to
+ * words - number of words to write
+ * data - pointer to array of 16 bit words to be written to the EEPROM
+ *
+ *****************************************************************************/
+int32_t
+em_write_eeprom_microwire(struct em_hw *hw,
+                             uint16_t offset,
+                             uint16_t words,
+                             uint16_t *data)
+{
+    struct em_eeprom_info *eeprom = &hw->eeprom;
+    uint32_t eecd;
+    uint16_t words_written = 0;
+    uint16_t i = 0;
+
+    DEBUGFUNC("em_write_eeprom_microwire");
+
+    /* Send the write enable command to the EEPROM (3-bit opcode plus
+     * 6/8-bit dummy address beginning with 11).  It's less work to include
+     * the 11 of the dummy address as part of the opcode than it is to shift
+     * it over the correct number of bits for the address.  This puts the
+     * EEPROM into write/erase mode.
+     */
+    em_shift_out_ee_bits(hw, EEPROM_EWEN_OPCODE_MICROWIRE,
+                            (uint16_t)(eeprom->opcode_bits + 2));
+
+    em_shift_out_ee_bits(hw, 0, (uint16_t)(eeprom->address_bits - 2));
+
+    /* Prepare the EEPROM */
     em_standby_eeprom(hw);
 
-    /* Send the 9-bit (or 11-bit on large EEPROM) EWDS (write disable) command
-     * to the EEPROM (5-bit opcode plus 4/6-bit dummy). This takes the EEPROM
-     * out of write/erase mode.
-     */
-    em_shift_out_ee_bits(hw, EEPROM_EWDS_OPCODE, 5);
-    if(large_eeprom) 
-        em_shift_out_ee_bits(hw, 0, 6);
-    else
-        em_shift_out_ee_bits(hw, 0, 4);
+    while (words_written < words) {
+        /* Send the Write command (3-bit opcode + addr) */
+        em_shift_out_ee_bits(hw, EEPROM_WRITE_OPCODE_MICROWIRE,
+                                eeprom->opcode_bits);
 
-    /* Done with writing */
-    em_cleanup_eeprom(hw);
+        em_shift_out_ee_bits(hw, (uint16_t)(offset + words_written),
+                                eeprom->address_bits);
 
-    /* Stop requesting EEPROM access */
-    if(hw->mac_type > em_82544) {
-        eecd = E1000_READ_REG(hw, EECD);
-        eecd &= ~E1000_EECD_REQ;
-        E1000_WRITE_REG(hw, EECD, eecd);
+        /* Send the data */
+        em_shift_out_ee_bits(hw, data[words_written], 16);
+
+        /* Toggle the CS line.  This in effect tells the EEPROM to execute
+         * the previous command.
+         */
+        em_standby_eeprom(hw);
+
+        /* Read DO repeatedly until it is high (equal to '1').  The EEPROM will
+         * signal that the command has been completed by raising the DO signal.
+         * If DO does not go high in 10 milliseconds, then error out.
+         */
+        for(i = 0; i < 200; i++) {
+            eecd = E1000_READ_REG(hw, EECD);
+            if(eecd & E1000_EECD_DO) break;
+            usec_delay(50);
+        }
+        if(i == 200) {
+            DEBUGOUT("EEPROM Write did not complete\n");
+            return -E1000_ERR_EEPROM;
+        }
+
+        /* Recover from write */
+        em_standby_eeprom(hw);
+
+        words_written++;
     }
 
-    return status;
+    /* Send the write disable command to the EEPROM (3-bit opcode plus
+     * 6/8-bit dummy address beginning with 10).  It's less work to include
+     * the 10 of the dummy address as part of the opcode than it is to shift
+     * it over the correct number of bits for the address.  This takes the
+     * EEPROM out of write/erase mode.
+     */
+    em_shift_out_ee_bits(hw, EEPROM_EWDS_OPCODE_MICROWIRE,
+                            (uint16_t)(eeprom->opcode_bits + 2));
+
+    em_shift_out_ee_bits(hw, 0, (uint16_t)(eeprom->address_bits - 2));
+
+    return 0;
 }
 
 /******************************************************************************
@@ -2703,7 +3433,7 @@
     DEBUGFUNC("em_read_part_num");
 
     /* Get word 0 from EEPROM */
-    if(em_read_eeprom(hw, offset, &eeprom_data) < 0) {
+    if(em_read_eeprom(hw, offset, 1, &eeprom_data) < 0) {
         DEBUGOUT("EEPROM Read Error\n");
         return -E1000_ERR_EEPROM;
     }
@@ -2711,7 +3441,7 @@
     *part_num = (uint32_t) (eeprom_data << 16);
 
     /* Get word 1 from EEPROM */
-    if(em_read_eeprom(hw, ++offset, &eeprom_data) < 0) {
+    if(em_read_eeprom(hw, ++offset, 1, &eeprom_data) < 0) {
         DEBUGOUT("EEPROM Read Error\n");
         return -E1000_ERR_EEPROM;
     }
@@ -2737,7 +3467,7 @@
 
     for(i = 0; i < NODE_ADDRESS_SIZE; i += 2) {
         offset = i >> 1;
-        if(em_read_eeprom(hw, offset, &eeprom_data) < 0) {
+        if(em_read_eeprom(hw, offset, 1, &eeprom_data) < 0) {
             DEBUGOUT("EEPROM Read Error\n");
             return -E1000_ERR_EEPROM;
         }
@@ -2759,7 +3489,7 @@
 /******************************************************************************
  * Initializes receive address filters.
  *
- * hw - Struct containing variables accessed by shared code 
+ * hw - Struct containing variables accessed by shared code
  *
  * Places the MAC address in receive address register 0 and clears the rest
  * of the receive addresss registers. Clears the multicast table. Assumes
@@ -2804,7 +3534,7 @@
  *
  * The given list replaces any existing list. Clears the last 15 receive
  * address registers and the multicast table. Uses receive address registers
- * for the first 15 multicast addresses, and hashes the rest into the 
+ * for the first 15 multicast addresses, and hashes the rest into the
  * multicast table.
  *****************************************************************************/
 void
@@ -2853,7 +3583,7 @@
         DEBUGOUT1(" Hash value = 0x%03X\n", hash_value);
 
         /* Place this multicast address in the RAR if there is room, *
-         * else put it in the MTA            
+         * else put it in the MTA
          */
         if(rar_used_count < E1000_RAR_ENTRIES) {
             em_rar_set(hw,
@@ -2871,7 +3601,7 @@
  * Hashes an address to determine its location in the multicast table
  *
  * hw - Struct containing variables accessed by shared code
- * mc_addr - the multicast address to hash 
+ * mc_addr - the multicast address to hash
  *****************************************************************************/
 uint32_t
 em_hash_mc_addr(struct em_hw *hw,
@@ -2880,7 +3610,7 @@
     uint32_t hash_value = 0;
 
     /* The portion of the address that is used for the hash table is
-     * determined by the mc_filter_type setting.  
+     * determined by the mc_filter_type setting.
      */
     switch (hw->mc_filter_type) {
     /* [0] [1] [2] [3] [4] [5]
@@ -2923,12 +3653,12 @@
     uint32_t mta;
     uint32_t temp;
 
-    /* The MTA is a register array of 128 32-bit registers.  
-     * It is treated like an array of 4096 bits.  We want to set 
+    /* The MTA is a register array of 128 32-bit registers.
+     * It is treated like an array of 4096 bits.  We want to set
      * bit BitArray[hash_value]. So we figure out what register
      * the bit is in, read it, OR in the new bit, then write
-     * back the new value.  The register is determined by the 
-     * upper 7 bits of the hash value and the bit within that 
+     * back the new value.  The register is determined by the
+     * upper 7 bits of the hash value and the bit within that
      * register are determined by the lower 5 bits of the value.
      */
     hash_reg = (hash_value >> 5) & 0x7F;
@@ -2966,7 +3696,7 @@
     uint32_t rar_low, rar_high;
 
     /* HW expects these in little endian so we reverse the byte order
-     * from network order (big endian) to little endian              
+     * from network order (big endian) to little endian
      */
     rar_low = ((uint32_t) addr[0] |
                ((uint32_t) addr[1] << 8) |
@@ -3024,24 +3754,24 @@
     const uint32_t ledctl_off = E1000_LEDCTL_MODE_LED_OFF;
     uint16_t eeprom_data, i, temp;
     const uint16_t led_mask = 0x0F;
-        
+
     DEBUGFUNC("em_id_led_init");
-    
+
     if(hw->mac_type < em_82540) {
         /* Nothing to do */
         return 0;
     }
-    
+
     ledctl = E1000_READ_REG(hw, LEDCTL);
     hw->ledctl_default = ledctl;
     hw->ledctl_mode1 = hw->ledctl_default;
     hw->ledctl_mode2 = hw->ledctl_default;
-        
-    if(em_read_eeprom(hw, EEPROM_ID_LED_SETTINGS, &eeprom_data) < 0) {
+
+    if(em_read_eeprom(hw, EEPROM_ID_LED_SETTINGS, 1, &eeprom_data) < 0) {
         DEBUGOUT("EEPROM Read Error\n");
         return -E1000_ERR_EEPROM;
     }
-    if((eeprom_data== ID_LED_RESERVED_0000) || 
+    if((eeprom_data== ID_LED_RESERVED_0000) ||
        (eeprom_data == ID_LED_RESERVED_FFFF)) eeprom_data = ID_LED_DEFAULT;
     for(i = 0; i < 4; i++) {
         temp = (eeprom_data >> (i << 2)) & led_mask;
@@ -3092,9 +3822,9 @@
 em_setup_led(struct em_hw *hw)
 {
     uint32_t ledctl;
- 
+
     DEBUGFUNC("em_setup_led");
-   
+
     switch(hw->device_id) {
     case E1000_DEV_ID_82542:
     case E1000_DEV_ID_82543GC_FIBER:
@@ -3112,15 +3842,22 @@
         hw->ledctl_default = ledctl;
         /* Turn off LED0 */
         ledctl &= ~(E1000_LEDCTL_LED0_IVRT |
-                    E1000_LEDCTL_LED0_BLINK | 
+                    E1000_LEDCTL_LED0_BLINK |
                     E1000_LEDCTL_LED0_MODE_MASK);
         ledctl |= (E1000_LEDCTL_MODE_LED_OFF << E1000_LEDCTL_LED0_MODE_SHIFT);
         E1000_WRITE_REG(hw, LEDCTL, ledctl);
         break;
+    case E1000_DEV_ID_82540EP:
+    case E1000_DEV_ID_82540EP_LOM:
+    case E1000_DEV_ID_82540EP_LP:
     case E1000_DEV_ID_82540EM:
     case E1000_DEV_ID_82540EM_LOM:
     case E1000_DEV_ID_82545EM_COPPER:
     case E1000_DEV_ID_82546EB_COPPER:
+    case E1000_DEV_ID_82546EB_QUAD_COPPER:
+    case E1000_DEV_ID_82541EI:
+    case E1000_DEV_ID_82541EP:
+    case E1000_DEV_ID_82547EI:
         E1000_WRITE_REG(hw, LEDCTL, hw->ledctl_mode1);
         break;
     default:
@@ -3150,12 +3887,19 @@
     case E1000_DEV_ID_82544GC_LOM:
         /* No cleanup necessary */
         break;
+    case E1000_DEV_ID_82540EP:
+    case E1000_DEV_ID_82540EP_LOM:
+    case E1000_DEV_ID_82540EP_LP:
     case E1000_DEV_ID_82540EM:
     case E1000_DEV_ID_82540EM_LOM:
     case E1000_DEV_ID_82545EM_COPPER:
     case E1000_DEV_ID_82545EM_FIBER:
     case E1000_DEV_ID_82546EB_COPPER:
     case E1000_DEV_ID_82546EB_FIBER:
+    case E1000_DEV_ID_82546EB_QUAD_COPPER:
+    case E1000_DEV_ID_82541EI:
+    case E1000_DEV_ID_82541EP:
+    case E1000_DEV_ID_82547EI:
         /* Restore LEDCTL settings */
         E1000_WRITE_REG(hw, LEDCTL, hw->ledctl_default);
         break;
@@ -3165,7 +3909,7 @@
     }
     return 0;
 }
-    
+
 /******************************************************************************
  * Turns on the software controllable LED
  *
@@ -3200,10 +3944,17 @@
         ctrl |= E1000_CTRL_SWDPIO0;
         E1000_WRITE_REG(hw, CTRL, ctrl);
         break;
+    case E1000_DEV_ID_82540EP:
+    case E1000_DEV_ID_82540EP_LOM:
+    case E1000_DEV_ID_82540EP_LP:
     case E1000_DEV_ID_82540EM:
     case E1000_DEV_ID_82540EM_LOM:
     case E1000_DEV_ID_82545EM_COPPER:
     case E1000_DEV_ID_82546EB_COPPER:
+    case E1000_DEV_ID_82546EB_QUAD_COPPER:
+    case E1000_DEV_ID_82541EI:
+    case E1000_DEV_ID_82541EP:
+    case E1000_DEV_ID_82547EI:
         E1000_WRITE_REG(hw, LEDCTL, hw->ledctl_mode2);
         break;
     default:
@@ -3247,10 +3998,17 @@
         ctrl |= E1000_CTRL_SWDPIO0;
         E1000_WRITE_REG(hw, CTRL, ctrl);
         break;
+    case E1000_DEV_ID_82540EP:
+    case E1000_DEV_ID_82540EP_LOM:
+    case E1000_DEV_ID_82540EP_LP:
     case E1000_DEV_ID_82540EM:
     case E1000_DEV_ID_82540EM_LOM:
     case E1000_DEV_ID_82545EM_COPPER:
     case E1000_DEV_ID_82546EB_COPPER:
+    case E1000_DEV_ID_82546EB_QUAD_COPPER:
+    case E1000_DEV_ID_82541EI:
+    case E1000_DEV_ID_82541EP:
+    case E1000_DEV_ID_82547EI:
         E1000_WRITE_REG(hw, LEDCTL, hw->ledctl_mode1);
         break;
     default:
@@ -3261,7 +4019,7 @@
 }
 
 /******************************************************************************
- * Clears all hardware statistics counters. 
+ * Clears all hardware statistics counters.
  *
  * hw - Struct containing variables accessed by shared code
  *****************************************************************************/
@@ -3380,7 +4138,7 @@
     DEBUGFUNC("em_update_adaptive");
 
     if(hw->adaptive_ifs) {
-        if((hw->collision_delta * hw->ifs_ratio) > 
+        if((hw->collision_delta * hw->ifs_ratio) >
            hw->tx_packet_delta) {
             if(hw->tx_packet_delta > MIN_NUM_XMITS) {
                 hw->in_ifs_mode = TRUE;
@@ -3393,7 +4151,7 @@
                 }
             }
         } else {
-            if((hw->in_ifs_mode == TRUE) && 
+            if((hw->in_ifs_mode == TRUE) &&
                (hw->tx_packet_delta <= MIN_NUM_XMITS)) {
                 hw->current_ifs_val = 0;
                 hw->in_ifs_mode = FALSE;
@@ -3407,7 +4165,7 @@
 
 /******************************************************************************
  * Adjusts the statistic counters when a frame is accepted by TBI_ACCEPT
- * 
+ *
  * hw - Struct containing variables accessed by shared code
  * frame_len - The length of the frame in question
  * mac_addr - The Ethernet destination address of the frame in question
@@ -3435,16 +4193,16 @@
     carry_bit = 0x80000000 & stats->gorcl;
     stats->gorcl += frame_len;
     /* If the high bit of Gorcl (the low 32 bits of the Good Octets
-     * Received Count) was one before the addition, 
-     * AND it is zero after, then we lost the carry out, 
+     * Received Count) was one before the addition,
+     * AND it is zero after, then we lost the carry out,
      * need to add one to Gorch (Good Octets Received Count High).
-     * This could be simplified if all environments supported 
+     * This could be simplified if all environments supported
      * 64-bit integers.
      */
     if(carry_bit && ((stats->gorcl & 0x80000000) == 0))
         stats->gorch++;
     /* Is this a broadcast or multicast?  Check broadcast first,
-     * since the test for a multicast frame will test positive on 
+     * since the test for a multicast frame will test positive on
      * a broadcast frame.
      */
     if((mac_addr[0] == (uint8_t) 0xff) && (mac_addr[1] == (uint8_t) 0xff))
@@ -3505,7 +4263,11 @@
     status = E1000_READ_REG(hw, STATUS);
     hw->bus_type = (status & E1000_STATUS_PCIX_MODE) ?
                    em_bus_type_pcix : em_bus_type_pci;
-    if(hw->bus_type == em_bus_type_pci) {
+
+    if(hw->device_id == E1000_DEV_ID_82546EB_QUAD_COPPER) {
+        hw->bus_speed = (hw->bus_type == em_bus_type_pci) ?
+                        em_bus_speed_66 : em_bus_speed_120;
+    } else if(hw->bus_type == em_bus_type_pci) {
         hw->bus_speed = (status & E1000_STATUS_PCI66) ?
                         em_bus_speed_66 : em_bus_speed_33;
     } else {
@@ -3563,5 +4325,223 @@
 
     em_io_write(hw, io_addr, offset);
     em_io_write(hw, io_data, value);
+}
+
+
+/******************************************************************************
+ * Estimates the cable length.
+ *
+ * hw - Struct containing variables accessed by shared code
+ * min_length - The estimated minimum length
+ * max_length - The estimated maximum length
+ *
+ * returns: E1000_SUCCESS / -E1000_ERR_XXX
+ *
+ * This function always returns a ranged length (minimum & maximum).
+ * So for M88 phy's, this function interprets the one value returned from the
+ * register to the minimum and maximum range.
+ * For IGP phy's, the function calculates the range by the AGC registers.
+ *****************************************************************************/
+int32_t
+em_get_cable_length(struct em_hw *hw, uint16_t *min_length,
+                       uint16_t *max_length)
+{
+    uint16_t agc_value = 0;
+    uint16_t cur_agc, min_agc = IGP01E1000_AGC_LENGTH_TABLE_SIZE;
+    uint16_t i, phy_data;
+
+    DEBUGFUNC("em_get_cable_length");
+
+    *min_length = *max_length = 0;
+
+    /* Use old method for Phy older than IGP */
+    if(hw->phy_type == em_phy_m88) {
+        if(em_read_phy_reg(hw, M88E1000_PHY_SPEC_STATUS, &phy_data) < 0)
+            return -E1000_ERR_PHY;
+
+        /* Convert the enum value to ranged values */
+        switch((phy_data & M88E1000_PSSR_CABLE_LENGTH) >>
+               M88E1000_PSSR_CABLE_LENGTH_SHIFT) {
+        case em_cable_length_50:
+            *min_length = 0;
+            *max_length = em_igp_cable_length_50;
+            break;
+        case em_cable_length_50_80:
+            *min_length = em_igp_cable_length_50;
+            *max_length = em_igp_cable_length_80;
+            break;
+        case em_cable_length_80_110:
+            *min_length = em_igp_cable_length_80;
+            *max_length = em_igp_cable_length_110;
+            break;
+        case em_cable_length_110_140:
+            *min_length = em_igp_cable_length_110;
+            *max_length = em_igp_cable_length_140;
+            break;
+        case em_cable_length_140:
+            *min_length = em_igp_cable_length_140;
+            *max_length = em_igp_cable_length_170;
+            break;
+        default:
+            return -E1000_ERR_PHY;
+            break;
+        }
+    } else if(hw->phy_type == em_phy_igp) { /* For IGP PHY */
+        uint16_t agc_reg_array[IGP01E1000_PHY_AGC_NUM] = {IGP01E1000_PHY_AGC_A,
+                                                          IGP01E1000_PHY_AGC_B,
+                                                          IGP01E1000_PHY_AGC_C,
+                                                          IGP01E1000_PHY_AGC_D};
+        /* Read the AGC registers for all channels */
+        for(i = 0; i < IGP01E1000_PHY_AGC_NUM; i++) {
+            if(em_write_phy_reg(hw, IGP01E1000_PHY_PAGE_SELECT,
+                                   agc_reg_array[i]) != E1000_SUCCESS)
+                return -E1000_ERR_PHY;
+            if(em_read_phy_reg(hw, agc_reg_array[i] &
+                                  IGP01E1000_PHY_PAGE_SELECT, &phy_data) !=
+                                  E1000_SUCCESS)
+                return -E1000_ERR_PHY;
+
+            cur_agc = phy_data >> IGP01E1000_AGC_LENGTH_SHIFT;
+
+            /* Array bound check. */
+            if((cur_agc >= IGP01E1000_AGC_LENGTH_TABLE_SIZE - 1) ||
+               (cur_agc == 0))
+                return -E1000_ERR_PHY;
+
+            agc_value += cur_agc;
+
+            /* Update minimal AGC value. */
+            if(min_agc > cur_agc)
+                min_agc = cur_agc;
+        }
+
+        /* Return to page 0 */
+        if(em_write_phy_reg(hw, IGP01E1000_PHY_PAGE_SELECT, 0x0) !=
+           E1000_SUCCESS)
+            return -E1000_ERR_PHY;
+
+        /* Remove the minimal AGC result for length < 50m */
+        if(agc_value < IGP01E1000_PHY_AGC_NUM * em_igp_cable_length_50) {
+            agc_value -= min_agc;
+
+            /* Get the average length of the remaining 3 channels */
+            agc_value /= (IGP01E1000_PHY_AGC_NUM - 1);
+        } else {
+            /* Get the average length of all the 4 channels. */
+            agc_value /= IGP01E1000_PHY_AGC_NUM;
+        }
+
+        /* Set the range of the calculated length. */
+        *min_length = ((em_igp_cable_length_table[agc_value] -
+                       IGP01E1000_AGC_RANGE) > 0) ?
+                       (em_igp_cable_length_table[agc_value] -
+                       IGP01E1000_AGC_RANGE) : 0;
+        *max_length = em_igp_cable_length_table[agc_value] +
+                      IGP01E1000_AGC_RANGE;
+    }
+
+    return E1000_SUCCESS;
+}
+
+/******************************************************************************
+ * Check the cable polarity
+ *
+ * hw - Struct containing variables accessed by shared code
+ * polarity - output parameter : 0 - Polarity is not reversed
+ *                               1 - Polarity is reversed.
+ *
+ * returns: E1000_SUCCESS / -E1000_ERR_XXX
+ *
+ * For phy's older then IGP, this function simply reads the polarity bit in the
+ * Phy Status register.  For IGP phy's, this bit is valid only if link speed is
+ * 10 Mbps.  If the link speed is 100 Mbps there is no polarity so this bit will
+ * return 0.  If the link speed is 1000 Mbps the polarity status is in the
+ * IGP01E1000_PHY_PCS_INIT_REG.
+ *****************************************************************************/
+int32_t
+em_check_polarity(struct em_hw *hw, uint16_t *polarity)
+{
+    uint16_t phy_data;
+
+    DEBUGFUNC("em_check_polarity");
+
+    if(hw->phy_type == em_phy_m88) {
+        /* return the Polarity bit in the Status register. */
+        if(em_read_phy_reg(hw, M88E1000_PHY_SPEC_STATUS, &phy_data) < 0)
+            return -E1000_ERR_PHY;
+        *polarity = (phy_data & M88E1000_PSSR_REV_POLARITY) >>
+                    M88E1000_PSSR_REV_POLARITY_SHIFT;
+    } else if(hw->phy_type == em_phy_igp) {
+        /* Read the Status register to check the speed */
+        if(em_read_phy_reg(hw, IGP01E1000_PHY_PORT_STATUS, &phy_data) < 0)
+            return -E1000_ERR_PHY;
+
+        /* If speed is 1000 Mbps, must read the IGP01E1000_PHY_PCS_INIT_REG to
+         * find the polarity status */
+        if((phy_data & IGP01E1000_PSSR_SPEED_MASK) ==
+           IGP01E1000_PSSR_SPEED_1000MBPS) {
+
+            /* Read the GIG initialization PCS register (0x00B4) */
+            if(em_write_phy_reg(hw, IGP01E1000_PHY_PAGE_SELECT,
+                                   IGP01E1000_PHY_PCS_INIT_REG) < 0)
+                return -E1000_ERR_PHY;
+
+            if(em_read_phy_reg(hw, IGP01E1000_PHY_PCS_INIT_REG &
+                                  IGP01E1000_PHY_PAGE_SELECT, &phy_data) < 0)
+                return -E1000_ERR_PHY;
+
+            /* Return to page 0 */
+            if(em_write_phy_reg(hw, IGP01E1000_PHY_PAGE_SELECT, 0x0) !=
+               E1000_SUCCESS)
+                return -E1000_ERR_PHY;
+
+            /* Check the polarity bits */
+            *polarity = (phy_data & IGP01E1000_PHY_POLARITY_MASK) ? 1 : 0;
+        } else {
+            /* For 10 Mbps, read the polarity bit in the status register. (for
+             * 100 Mbps this bit is always 0) */
+            *polarity = phy_data & IGP01E1000_PSSR_POLARITY_REVERSED;
+        }
+    }
+    return E1000_SUCCESS;
+}
+
+/******************************************************************************
+ * Check if Downshift occured
+ *
+ * hw - Struct containing variables accessed by shared code
+ * downshift - output parameter : 0 - No Downshift ocured.
+ *                                1 - Downshift ocured.
+ *
+ * returns: E1000_SUCCESS / -E1000_ERR_XXX
+ *
+ * For phy's older then IGP, this function reads the Downshift bit in the Phy
+ * Specific Status register.  For IGP phy's, it reads the Downgrade bit in the
+ * Link Health register.  In IGP this bit is latched high, so the driver must
+ * read it immediately after link is established.
+ *****************************************************************************/
+int32_t
+em_check_downshift(struct em_hw *hw)
+{
+    uint16_t phy_data;
+
+    DEBUGFUNC("em_check_downshift");
+
+    if(hw->phy_type == em_phy_igp) {
+        if(em_read_phy_reg(hw, IGP01E1000_PHY_LINK_HEALTH, &phy_data) < 0) {
+            DEBUGOUT("PHY Read Error\n");
+            return -E1000_ERR_PHY;
+        }
+        hw->speed_downgraded = (phy_data & IGP01E1000_PLHR_SS_DOWNGRADE) ? 1 : 0;
+    }
+    else if(hw->phy_type == em_phy_m88) {
+        if(em_read_phy_reg(hw, M88E1000_PHY_SPEC_STATUS, &phy_data) < 0) {
+            DEBUGOUT("PHY Read Error\n");
+            return -E1000_ERR_PHY;
+        }
+        hw->speed_downgraded = (phy_data & M88E1000_PSSR_DOWNSHIFT) >>
+                                M88E1000_PSSR_DOWNSHIFT_SHIFT;
+    }
+    return E1000_SUCCESS;
 }
 
Index: dev/pci/if_em_hw.h
===================================================================
RCS file: /u/open/cvs/src/sys/dev/pci/if_em_hw.h,v
retrieving revision 1.2
diff -u -r1.2 if_em_hw.h
--- dev/pci/if_em_hw.h	11 Feb 2003 19:20:27 -0000	1.2
+++ dev/pci/if_em_hw.h	14 Jul 2004 21:32:07 -0000
@@ -1,39 +1,38 @@
-/**************************************************************************
+/*******************************************************************************
 
-Copyright (c) 2001-2002 Intel Corporation
-All rights reserved.
+  Copyright (c) 2001-2003, Intel Corporation
+  All rights reserved.
 
-Redistribution and use in source and binary forms of the Software, with or
-without modification, are permitted provided that the following conditions
-are met:
-
- 1. Redistributions of source code of the Software may retain the above
-    copyright notice, this list of conditions and the following disclaimer.
-
- 2. Redistributions in binary form of the Software may 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 shall 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 INTEL OR ITS 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.
+  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.
 
-/*$FreeBSD$*/
+*******************************************************************************/
+
+/*$FreeBSD: if_em_hw.h,v 1.10 2003/06/05 17:51:38 pdeuskar Exp $*/
+/* $OpenBSD: if_em_hw.h,v 1.3 2003/06/13 19:21:21 henric Exp $ */
 /* if_em_hw.h
  * Structures, enums, and macros for the MAC
  */
@@ -50,16 +49,26 @@
 /* Enumerated types specific to the e1000 hardware */
 /* Media Access Controlers */
 typedef enum {
-    em_82542_rev2_0 = 0,
+    em_undefined = 0,
+    em_82542_rev2_0,
     em_82542_rev2_1,
     em_82543,
     em_82544,
     em_82540,
     em_82545,
     em_82546,
+    em_82541,
+    em_82547,
     em_num_macs
 } em_mac_type;
 
+typedef enum {
+    em_eeprom_uninitialized = 0,
+    em_eeprom_spi,
+    em_eeprom_microwire,
+    em_num_eeprom_types
+} em_eeprom_type;
+
 /* Media Types */
 typedef enum {
     em_media_type_copper = 0,
@@ -96,6 +105,7 @@
     em_bus_speed_33,
     em_bus_speed_66,
     em_bus_speed_100,
+    em_bus_speed_120,
     em_bus_speed_133,
     em_bus_speed_reserved
 } em_bus_speed;
@@ -118,6 +128,27 @@
 } em_cable_length;
 
 typedef enum {
+    em_igp_cable_length_10  = 10,
+    em_igp_cable_length_20  = 20,
+    em_igp_cable_length_30  = 30,
+    em_igp_cable_length_40  = 40,
+    em_igp_cable_length_50  = 50,
+    em_igp_cable_length_60  = 60,
+    em_igp_cable_length_70  = 70,
+    em_igp_cable_length_80  = 80,
+    em_igp_cable_length_90  = 90,
+    em_igp_cable_length_100 = 100,
+    em_igp_cable_length_110 = 110,
+    em_igp_cable_length_120 = 120,
+    em_igp_cable_length_130 = 130,
+    em_igp_cable_length_140 = 140,
+    em_igp_cable_length_150 = 150,
+    em_igp_cable_length_160 = 160,
+    em_igp_cable_length_170 = 170,
+    em_igp_cable_length_180 = 180
+} em_igp_cable_length;
+
+typedef enum {
     em_10bt_ext_dist_enable_normal = 0,
     em_10bt_ext_dist_enable_lower,
     em_10bt_ext_dist_enable_undefined = 0xFF
@@ -130,6 +161,12 @@
 } em_rev_polarity;
 
 typedef enum {
+    em_downshift_normal = 0,
+    em_downshift_activated,
+    em_downshift_undefined = 0xFF
+} em_downshift;
+
+typedef enum {
     em_polarity_reversal_enabled = 0,
     em_polarity_reversal_disabled,
     em_polarity_reversal_undefined = 0xFF
@@ -149,10 +186,17 @@
     em_1000t_rx_status_undefined = 0xFF
 } em_1000t_rx_status;
 
+typedef enum {
+    em_phy_m88 = 0,
+    em_phy_igp,
+    em_phy_undefined = 0xFF
+} em_phy_type;
+
 struct em_phy_info {
     em_cable_length cable_length;
     em_10bt_ext_dist_enable extended_10bt_distance;
     em_rev_polarity cable_polarity;
+    em_downshift downshift;
     em_polarity_reversal polarity_correction;
     em_auto_x_mode mdix_mode;
     em_1000t_rx_status local_rx;
@@ -164,19 +208,31 @@
     uint32_t receive_errors;
 };
 
+struct em_eeprom_info {
+    em_eeprom_type type;
+    uint16_t word_size;
+    uint16_t opcode_bits;
+    uint16_t address_bits;
+    uint16_t delay_usec;
+    uint16_t page_size;
+};
+
 
 
 /* Error Codes */
-#define E1000_SUCCESS    0
-#define E1000_ERR_EEPROM 1
-#define E1000_ERR_PHY    2
-#define E1000_ERR_CONFIG 3
-#define E1000_ERR_PARAM  4
+#define E1000_SUCCESS      0
+#define E1000_ERR_EEPROM   1
+#define E1000_ERR_PHY      2
+#define E1000_ERR_CONFIG   3
+#define E1000_ERR_PARAM    4
+#define E1000_ERR_MAC_TYPE 5
+#define E1000_ERR_PHY_TYPE 6
 
 /* Function prototypes */
 /* Initialization */
 void em_reset_hw(struct em_hw *hw);
 int32_t em_init_hw(struct em_hw *hw);
+int32_t em_set_mac_type(struct em_hw *hw);
 
 /* Link Configuration */
 int32_t em_setup_link(struct em_hw *hw);
@@ -194,13 +250,19 @@
 int32_t em_phy_reset(struct em_hw *hw);
 int32_t em_detect_gig_phy(struct em_hw *hw);
 int32_t em_phy_get_info(struct em_hw *hw, struct em_phy_info *phy_info);
+int32_t em_phy_m88_get_info(struct em_hw *hw, struct em_phy_info *phy_info);
+int32_t em_phy_igp_get_info(struct em_hw *hw, struct em_phy_info *phy_info);
+int32_t em_get_cable_length(struct em_hw *hw, uint16_t *min_length, uint16_t *max_length);
+int32_t em_check_polarity(struct em_hw *hw, uint16_t *polarity);
+int32_t em_check_downshift(struct em_hw *hw);
 int32_t em_validate_mdi_setting(struct em_hw *hw);
 
 /* EEPROM Functions */
-int32_t em_read_eeprom(struct em_hw *hw, uint16_t reg, uint16_t *data);
+void em_init_eeprom_params(struct em_hw *hw);
+int32_t em_read_eeprom(struct em_hw *hw, uint16_t reg, uint16_t words, uint16_t *data);
 int32_t em_validate_eeprom_checksum(struct em_hw *hw);
 int32_t em_update_eeprom_checksum(struct em_hw *hw);
-int32_t em_write_eeprom(struct em_hw *hw, uint16_t reg, uint16_t data);
+int32_t em_write_eeprom(struct em_hw *hw, uint16_t reg, uint16_t words, uint16_t *data);
 int32_t em_read_part_num(struct em_hw *hw, uint32_t * part_num);
 int32_t em_read_mac_addr(struct em_hw * hw);
 
@@ -227,6 +289,8 @@
 void em_update_adaptive(struct em_hw *hw);
 void em_tbi_adjust_stats(struct em_hw *hw, struct em_hw_stats *stats, uint32_t frame_len, uint8_t * mac_addr);
 void em_get_bus_info(struct em_hw *hw);
+void em_pci_set_mwi(struct em_hw *hw);
+void em_pci_clear_mwi(struct em_hw *hw);
 void em_read_pci_cfg(struct em_hw *hw, uint32_t reg, uint16_t * value);
 void em_write_pci_cfg(struct em_hw *hw, uint32_t reg, uint16_t * value);
 /* Port I/O is only supported on 82544 and newer */
@@ -234,26 +298,34 @@
 uint32_t em_read_reg_io(struct em_hw *hw, uint32_t offset);
 void em_io_write(struct em_hw *hw, uint32_t port, uint32_t value);
 void em_write_reg_io(struct em_hw *hw, uint32_t offset, uint32_t value);
+
 #define E1000_READ_REG_IO(a, reg) \
     em_read_reg_io((a), E1000_##reg)
 #define E1000_WRITE_REG_IO(a, reg, val) \
     em_write_reg_io((a), E1000_##reg, val)
 
 /* PCI Device IDs */
-#define E1000_DEV_ID_82542          0x1000
-#define E1000_DEV_ID_82543GC_FIBER  0x1001
-#define E1000_DEV_ID_82543GC_COPPER 0x1004
-#define E1000_DEV_ID_82544EI_COPPER 0x1008
-#define E1000_DEV_ID_82544EI_FIBER  0x1009
-#define E1000_DEV_ID_82544GC_COPPER 0x100C
-#define E1000_DEV_ID_82544GC_LOM    0x100D
-#define E1000_DEV_ID_82540EM        0x100E
-#define E1000_DEV_ID_82540EM_LOM    0x1015
-#define E1000_DEV_ID_82545EM_COPPER 0x100F
-#define E1000_DEV_ID_82545EM_FIBER  0x1011
-#define E1000_DEV_ID_82546EB_COPPER 0x1010
-#define E1000_DEV_ID_82546EB_FIBER  0x1012
-#define NUM_DEV_IDS 13
+#define E1000_DEV_ID_82542               0x1000
+#define E1000_DEV_ID_82543GC_FIBER       0x1001
+#define E1000_DEV_ID_82543GC_COPPER      0x1004
+#define E1000_DEV_ID_82544EI_COPPER      0x1008
+#define E1000_DEV_ID_82544EI_FIBER       0x1009
+#define E1000_DEV_ID_82544GC_COPPER      0x100C
+#define E1000_DEV_ID_82544GC_LOM         0x100D
+#define E1000_DEV_ID_82540EM             0x100E
+#define E1000_DEV_ID_82540EM_LOM         0x1015
+#define E1000_DEV_ID_82540EP_LOM         0x1016
+#define E1000_DEV_ID_82540EP             0x1017
+#define E1000_DEV_ID_82540EP_LP          0x101E
+#define E1000_DEV_ID_82545EM_COPPER      0x100F
+#define E1000_DEV_ID_82545EM_FIBER       0x1011
+#define E1000_DEV_ID_82546EB_COPPER      0x1010
+#define E1000_DEV_ID_82546EB_FIBER       0x1012
+#define E1000_DEV_ID_82546EB_QUAD_COPPER 0x101D
+#define E1000_DEV_ID_82541EI             0x1013
+#define E1000_DEV_ID_82541EP             0x1018
+#define E1000_DEV_ID_82547EI             0x1019
+#define NUM_DEV_IDS 20
 
 #define NODE_ADDRESS_SIZE 6
 #define ETH_LENGTH_OF_ADDRESS 6
@@ -270,7 +342,7 @@
 #define HALF_DUPLEX 1
 #define FULL_DUPLEX 2
 
-/* The sizes (in bytes) of a ethernet packet */
+/* The sizes (in bytes) of an ethernet packet */
 #define ENET_HEADER_SIZE             14
 #define MAXIMUM_ETHERNET_FRAME_SIZE  1518 /* With FCS */
 #define MINIMUM_ETHERNET_FRAME_SIZE  64   /* With FCS */
@@ -298,7 +370,7 @@
 /* This defines the bits that are set in the Interrupt Mask
  * Set/Read Register.  Each bit is documented below:
  *   o RXDMT0 = Receive Descriptor Minimum Threshold hit (ring 0)
- *   o RXSEQ  = Receive Sequence Error 
+ *   o RXSEQ  = Receive Sequence Error
  */
 #define POLL_IMS_ENABLE_MASK ( \
     E1000_IMS_RXDMT0 |         \
@@ -322,9 +394,9 @@
 /* The number of high/low register pairs in the RAR. The RAR (Receive Address
  * Registers) holds the directed and multicast addresses that we monitor. We
  * reserve one of these spots for our directed address, allowing us room for
- * E1000_RAR_ENTRIES - 1 multicast addresses. 
+ * E1000_RAR_ENTRIES - 1 multicast addresses.
  */
-#define E1000_RAR_ENTRIES 16
+#define E1000_RAR_ENTRIES 15
 
 #define MIN_NUMBER_OF_DESCRIPTORS 8
 #define MAX_NUMBER_OF_DESCRIPTORS 0xFFF8
@@ -523,7 +595,7 @@
 /* Register Set. (82543, 82544)
  *
  * Registers are defined to be 32 bits and  should be accessed as 32 bit values.
- * These registers are physically located on the NIC, but are mapped into the 
+ * These registers are physically located on the NIC, but are mapped into the
  * host memory address space.
  *
  * RW - register is both readable and writable
@@ -537,6 +609,7 @@
 #define E1000_EECD     0x00010  /* EEPROM/Flash Control - RW */
 #define E1000_EERD     0x00014  /* EEPROM Read - RW */
 #define E1000_CTRL_EXT 0x00018  /* Extended Device Control - RW */
+#define E1000_FLA      0x0001C  /* Flash Access - RW */
 #define E1000_MDIC     0x00020  /* MDI Control - RW */
 #define E1000_FCAL     0x00028  /* Flow Control Address Low - RW */
 #define E1000_FCAH     0x0002C  /* Flow Control Address High -RW */
@@ -569,6 +642,11 @@
 #define E1000_RADV     0x0282C  /* RX Interrupt Absolute Delay Timer - RW */
 #define E1000_RSRPD    0x02C00  /* RX Small Packet Detect - RW */
 #define E1000_TXDMAC   0x03000  /* TX DMA Control - RW */
+#define E1000_TDFH     0x03410  /* TX Data FIFO Head - RW */
+#define E1000_TDFT     0x03418  /* TX Data FIFO Tail - RW */
+#define E1000_TDFHS    0x03420  /* TX Data FIFO Head Saved - RW */
+#define E1000_TDFTS    0x03428  /* TX Data FIFO Tail Saved - RW */
+#define E1000_TDFPC    0x03430  /* TX Data FIFO Packet Count - RW */
 #define E1000_TDBAL    0x03800  /* TX Descriptor Base Address Low - RW */
 #define E1000_TDBAH    0x03804  /* TX Descriptor Base Address High - RW */
 #define E1000_TDLEN    0x03808  /* TX Descriptor Length - RW */
@@ -660,10 +738,12 @@
  * the registers function in the same manner.
  */
 #define E1000_82542_CTRL     E1000_CTRL
+#define E1000_82542_CTRL_DUP E1000_CTRL_DUP
 #define E1000_82542_STATUS   E1000_STATUS
 #define E1000_82542_EECD     E1000_EECD
 #define E1000_82542_EERD     E1000_EERD
 #define E1000_82542_CTRL_EXT E1000_CTRL_EXT
+#define E1000_82542_FLA      E1000_FLA
 #define E1000_82542_MDIC     E1000_MDIC
 #define E1000_82542_FCAL     E1000_FCAL
 #define E1000_82542_FCAH     E1000_FCAH
@@ -705,6 +785,9 @@
 #define E1000_82542_RADV     E1000_RADV
 #define E1000_82542_RSRPD    E1000_RSRPD
 #define E1000_82542_TXDMAC   E1000_TXDMAC
+#define E1000_82542_TDFHS    E1000_TDFHS
+#define E1000_82542_TDFTS    E1000_TDFTS
+#define E1000_82542_TDFPC    E1000_TDFPC
 #define E1000_82542_TXDCTL   E1000_TXDCTL
 #define E1000_82542_TADV     E1000_TADV
 #define E1000_82542_TSPMT    E1000_TSPMT
@@ -777,6 +860,8 @@
 #define E1000_82542_WUPL     E1000_WUPL
 #define E1000_82542_WUPM     E1000_WUPM
 #define E1000_82542_FFLT     E1000_FFLT
+#define E1000_82542_TDFH     0x08010
+#define E1000_82542_TDFT     0x08018
 #define E1000_82542_FFMT     E1000_FFMT
 #define E1000_82542_FFVT     E1000_FFVT
 
@@ -846,14 +931,18 @@
 struct em_hw {
     uint8_t *hw_addr;
     em_mac_type mac_type;
+    em_phy_type phy_type;
+    uint32_t phy_init_script;
     em_media_type media_type;
     void *back;
     em_fc_type fc;
     em_bus_speed bus_speed;
     em_bus_width bus_width;
     em_bus_type bus_type;
+    struct em_eeprom_info eeprom;
     uint32_t io_base;
     uint32_t phy_id;
+    uint32_t phy_revision;
     uint32_t phy_addr;
     uint32_t original_fc;
     uint32_t txcw;
@@ -890,6 +979,7 @@
     uint8_t mac_addr[NODE_ADDRESS_SIZE];
     uint8_t perm_mac_addr[NODE_ADDRESS_SIZE];
     boolean_t disable_polarity_correction;
+    boolean_t speed_downgraded;
     boolean_t get_link_status;
     boolean_t tbi_compatibility_en;
     boolean_t tbi_compatibility_on;
@@ -951,7 +1041,7 @@
 #define E1000_STATUS_SPEED_1000 0x00000080      /* Speed 1000Mb/s */
 #define E1000_STATUS_ASDV       0x00000300      /* Auto speed detect value */
 #define E1000_STATUS_MTXCKOK    0x00000400      /* MTX clock running OK */
-#define E1000_STATUS_PCI66      0x00000800      /* In 66MHz slot */
+#define E1000_STATUS_PCI66      0x00000800      /* In 66Mhz slot */
 #define E1000_STATUS_BUS64      0x00001000      /* In 64 bit slot */
 #define E1000_STATUS_PCIX_MODE  0x00002000      /* PCI-X mode */
 #define E1000_STATUS_PCIX_SPEED 0x0000C000      /* PCI-X bus speed */
@@ -966,14 +1056,20 @@
 #define E1000_EECD_CS        0x00000002 /* EEPROM Chip Select */
 #define E1000_EECD_DI        0x00000004 /* EEPROM Data In */
 #define E1000_EECD_DO        0x00000008 /* EEPROM Data Out */
-#define E1000_EECD_FWE_MASK  0x00000030 
+#define E1000_EECD_FWE_MASK  0x00000030
 #define E1000_EECD_FWE_DIS   0x00000010 /* Disable FLASH writes */
 #define E1000_EECD_FWE_EN    0x00000020 /* Enable FLASH writes */
 #define E1000_EECD_FWE_SHIFT 4
-#define E1000_EECD_SIZE      0x00000200 /* EEPROM Size (0=64 word 1=256 word) */
 #define E1000_EECD_REQ       0x00000040 /* EEPROM Access Request */
 #define E1000_EECD_GNT       0x00000080 /* EEPROM Access Grant */
 #define E1000_EECD_PRES      0x00000100 /* EEPROM Present */
+#define E1000_EECD_SIZE      0x00000200 /* EEPROM Size (0=64 word 1=256 word) */
+#define E1000_EECD_ADDR_BITS 0x00000400 /* EEPROM Addressing bits based on type
+					 * (0-small, 1-large) */
+#define E1000_EECD_TYPE      0x00002000 /* EEPROM Type (1-SPI, 0-Microwire) */
+#ifndef E1000_EEPROM_GRANT_ATTEMPTS
+#define E1000_EEPROM_GRANT_ATTEMPTS 1000 /* EEPROM # attempts to gain grant */
+#endif
 
 /* EEPROM Read */
 #define E1000_EERD_START      0x00000001 /* Start Read */
@@ -983,8 +1079,15 @@
 #define E1000_EERD_DATA_SHIFT 16
 #define E1000_EERD_DATA_MASK  0xFFFF0000 /* Read Data */
 
+/* SPI EEPROM Status Register */
+#define EEPROM_STATUS_RDY_SPI  0x01
+#define EEPROM_STATUS_WEN_SPI  0x02
+#define EEPROM_STATUS_BP0_SPI  0x04
+#define EEPROM_STATUS_BP1_SPI  0x08
+#define EEPROM_STATUS_WPEN_SPI 0x80
+
 /* Extended Device Control */
-#define E1000_CTRL_EXT_GPI0_EN   0x00000001 /* Maps SDP4 to GPI0 */ 
+#define E1000_CTRL_EXT_GPI0_EN   0x00000001 /* Maps SDP4 to GPI0 */
 #define E1000_CTRL_EXT_GPI1_EN   0x00000002 /* Maps SDP5 to GPI1 */
 #define E1000_CTRL_EXT_PHYINT_EN E1000_CTRL_EXT_GPI1_EN
 #define E1000_CTRL_EXT_GPI2_EN   0x00000004 /* Maps SDP6 to GPI2 */
@@ -1191,6 +1294,7 @@
 #define E1000_TXDCTL_WTHRESH 0x00FF0000 /* TXDCTL Writeback Threshold */
 #define E1000_TXDCTL_GRAN    0x01000000 /* TXDCTL Granularity */
 #define E1000_TXDCTL_LWTHRESH 0xFE000000 /* TXDCTL Low Threshold */
+#define E1000_TXDCTL_FULL_TX_DESC_WB 0x01010000 /* GRAN=1, WTHRESH=1 */
 
 /* Transmit Configuration Word */
 #define E1000_TXCW_FD         0x00000020        /* TXCW full duplex */
@@ -1237,6 +1341,7 @@
 #define E1000_WUC_PME_EN     0x00000002 /* PME Enable */
 #define E1000_WUC_PME_STATUS 0x00000004 /* PME Status */
 #define E1000_WUC_APMPME     0x00000008 /* Assert PME on APM Wakeup */
+#define E1000_WUC_SPM        0x80000000 /* Enable SPM */
 
 /* Wake Up Filter Control */
 #define E1000_WUFC_LNKC 0x00000001 /* Link Status Change Wakeup Enable */
@@ -1280,7 +1385,7 @@
 #define E1000_MANC_IPV6_EN       0x00000800 /* Enable IPv6 */
 #define E1000_MANC_SNAP_EN       0x00001000 /* Accept LLC/SNAP */
 #define E1000_MANC_ARP_EN        0x00002000 /* Enable ARP Request Filtering */
-#define E1000_MANC_NEIGHBOR_EN   0x00004000 /* Enable Neighbor Discovery 
+#define E1000_MANC_NEIGHBOR_EN   0x00004000 /* Enable Neighbor Discovery
                                              * Filtering */
 #define E1000_MANC_TCO_RESET     0x00010000 /* TCO Reset Occurred */
 #define E1000_MANC_RCV_TCO_EN    0x00020000 /* Receive TCO Packets Enabled */
@@ -1300,18 +1405,40 @@
 
 #define E1000_MDALIGN          4096
 
-/* EEPROM Commands */
-#define EEPROM_READ_OPCODE  0x6  /* EERPOM read opcode */
-#define EEPROM_WRITE_OPCODE 0x5  /* EERPOM write opcode */
-#define EEPROM_ERASE_OPCODE 0x7  /* EERPOM erase opcode */
-#define EEPROM_EWEN_OPCODE  0x13 /* EERPOM erase/write enable */
-#define EEPROM_EWDS_OPCODE  0x10 /* EERPOM erast/write disable */
+/* EEPROM Commands - Microwire */
+#define EEPROM_READ_OPCODE_MICROWIRE  0x6  /* EEPROM read opcode */
+#define EEPROM_WRITE_OPCODE_MICROWIRE 0x5  /* EEPROM write opcode */
+#define EEPROM_ERASE_OPCODE_MICROWIRE 0x7  /* EEPROM erase opcode */
+#define EEPROM_EWEN_OPCODE_MICROWIRE  0x13 /* EEPROM erase/write enable */
+#define EEPROM_EWDS_OPCODE_MICROWIRE  0x10 /* EEPROM erast/write disable */
+
+/* EEPROM Commands - SPI */
+#define EEPROM_MAX_RETRY_SPI    5000 /* Max wait of 5ms, for RDY signal */
+#define EEPROM_READ_OPCODE_SPI  0x3  /* EEPROM read opcode */
+#define EEPROM_WRITE_OPCODE_SPI 0x2  /* EEPROM write opcode */
+#define EEPROM_A8_OPCODE_SPI    0x8  /* opcode bit-3 = address bit-8 */
+#define EEPROM_WREN_OPCODE_SPI  0x6  /* EEPROM set Write Enable latch */
+#define EEPROM_WRDI_OPCODE_SPI  0x4  /* EEPROM reset Write Enable latch */
+#define EEPROM_RDSR_OPCODE_SPI  0x5  /* EEPROM read Status register */
+#define EEPROM_WRSR_OPCODE_SPI  0x1  /* EEPROM write Status register */
+
+/* EEPROM Size definitions */
+#define EEPROM_SIZE_16KB        0x1800
+#define EEPROM_SIZE_8KB         0x1400
+#define EEPROM_SIZE_4KB         0x1000
+#define EEPROM_SIZE_2KB         0x0C00
+#define EEPROM_SIZE_1KB         0x0800
+#define EEPROM_SIZE_512B        0x0400
+#define EEPROM_SIZE_128B        0x0000
+#define EEPROM_SIZE_MASK        0x1C00
+
 
 /* EEPROM Word Offsets */
 #define EEPROM_COMPAT              0x0003
 #define EEPROM_ID_LED_SETTINGS     0x0004
 #define EEPROM_INIT_CONTROL1_REG   0x000A
 #define EEPROM_INIT_CONTROL2_REG   0x000F
+#define EEPROM_CFG                 0x0012
 #define EEPROM_FLASH_VERSION       0x0032
 #define EEPROM_CHECKSUM_REG        0x003F
 
@@ -1332,9 +1459,10 @@
 #define ID_LED_OFF1_ON2      0x8
 #define ID_LED_OFF1_OFF2     0x9
 
-/* Mask bits for fields in Word 0x03 of the EEPROM */
-#define EEPROM_COMPAT_SERVER 0x0400
-#define EEPROM_COMPAT_CLIENT 0x0200
+#define IGP_ACTIVITY_LED_MASK   0xFFFFF0FF
+#define IGP_ACTIVITY_LED_ENABLE 0x0300
+#define IGP_LED3_MODE           0x07000000
+
 
 /* Mask bits for fields in Word 0x0a of the EEPROM */
 #define EEPROM_WORD0A_ILOS   0x0010
@@ -1366,7 +1494,6 @@
 #define E1000_COLLISION_DISTANCE        64
 #define E1000_FDX_COLLISION_DISTANCE    E1000_COLLISION_DISTANCE
 #define E1000_HDX_COLLISION_DISTANCE    E1000_COLLISION_DISTANCE
-#define E1000_GB_HDX_COLLISION_DISTANCE 512
 #define E1000_COLD_SHIFT                12
 
 /* The number of Transmit and Receive Descriptors must be a multiple of 8 */
@@ -1407,7 +1534,9 @@
 
 /* PBA constants */
 #define E1000_PBA_16K 0x0010    /* 16KB, default TX allocation */
+#define E1000_PBA_22K 0x0016
 #define E1000_PBA_24K 0x0018
+#define E1000_PBA_30K 0x001E
 #define E1000_PBA_40K 0x0028
 #define E1000_PBA_48K 0x0030    /* 48KB, default RX allocation */
 
@@ -1430,30 +1559,32 @@
 #define PCIX_COMMAND_MMRBC_SHIFT     0x2
 #define PCIX_STATUS_HI_MMRBC_MASK    0x0060
 #define PCIX_STATUS_HI_MMRBC_SHIFT   0x5
+#define PCIX_STATUS_HI_MMRBC_4K      0x3
+#define PCIX_STATUS_HI_MMRBC_2K      0x2
 
 
 /* The number of bits that we need to shift right to move the "pause"
  * bits from the EEPROM (bits 13:12) to the "pause" (bits 8:7) field
- * in the TXCW register 
+ * in the TXCW register
  */
 #define PAUSE_SHIFT 5
 
 /* The number of bits that we need to shift left to move the "SWDPIO"
  * bits from the EEPROM (bits 8:5) to the "SWDPIO" (bits 25:22) field
- * in the CTRL register 
+ * in the CTRL register
  */
 #define SWDPIO_SHIFT 17
 
 /* The number of bits that we need to shift left to move the "SWDPIO_EXT"
  * bits from the EEPROM word F (bits 7:4) to the bits 11:8 of The
  * Extended CTRL register.
- * in the CTRL register 
+ * in the CTRL register
  */
 #define SWDPIO__EXT_SHIFT 4
 
 /* The number of bits that we need to shift left to move the "ILOS"
  * bit from the EEPROM (bit 4) to the "ILOS" (bit 7) field
- * in the CTRL register 
+ * in the CTRL register
  */
 #define ILOS_SHIFT  3
 
@@ -1471,7 +1602,7 @@
 /* TBI_ACCEPT macro definition:
  *
  * This macro requires:
- *      adapter = a pointer to struct em_hw 
+ *      adapter = a pointer to struct em_hw
  *      status = the 8 bit status field of the RX descriptor with EOP set
  *      error = the 8 bit error field of the RX descriptor with EOP set
  *      length = the sum of all the length fields of the RX descriptors that
@@ -1480,14 +1611,14 @@
  *      max_frame_length = the maximum frame length we want to accept.
  *      min_frame_length = the minimum frame length we want to accept.
  *
- * This macro is a conditional that should be used in the interrupt 
+ * This macro is a conditional that should be used in the interrupt
  * handler's Rx processing routine when RxErrors have been detected.
  *
  * Typical use:
  *  ...
  *  if (TBI_ACCEPT) {
  *      accept_frame = TRUE;
- *      em_tbi_adjust_stats(adapter, MacAddress);
+ *      em_tbi_adjust_stats(sc, MacAddress);
  *      frame_length--;
  *  } else {
  *      accept_frame = FALSE;
@@ -1495,15 +1626,15 @@
  *  ...
  */
 
-#define TBI_ACCEPT(adapter, status, errors, length, last_byte) \
-    ((adapter)->tbi_compatibility_on && \
+#define TBI_ACCEPT(sc, status, errors, length, last_byte) \
+    ((sc)->tbi_compatibility_on && \
      (((errors) & E1000_RXD_ERR_FRAME_ERR_MASK) == E1000_RXD_ERR_CE) && \
      ((last_byte) == CARRIER_EXTENSION) && \
      (((status) & E1000_RXD_STAT_VP) ? \
-          (((length) > ((adapter)->min_frame_size - VLAN_TAG_SIZE)) && \
-           ((length) <= ((adapter)->max_frame_size + 1))) : \
-          (((length) > (adapter)->min_frame_size) && \
-           ((length) <= ((adapter)->max_frame_size + VLAN_TAG_SIZE + 1)))))
+          (((length) > ((sc)->min_frame_size - VLAN_TAG_SIZE)) && \
+           ((length) <= ((sc)->max_frame_size + 1))) : \
+          (((length) > (sc)->min_frame_size) && \
+           ((length) <= ((sc)->max_frame_size + VLAN_TAG_SIZE + 1)))))
 
 
 /* Structures, enums, and macros for the PHY */
@@ -1543,6 +1674,29 @@
 #define M88E1000_EXT_PHY_SPEC_CTRL 0x14  /* Extended PHY Specific Control */
 #define M88E1000_RX_ERR_CNTR       0x15  /* Receive Error Counter */
 
+/* IGP01E1000 Specific Registers */
+#define IGP01E1000_PHY_PORT_CONFIG 0x10 /* PHY Specific Port Config Register */
+#define IGP01E1000_PHY_PORT_STATUS 0x11 /* PHY Specific Status Register */
+#define IGP01E1000_PHY_PORT_CTRL   0x12 /* PHY Specific Control Register */
+#define IGP01E1000_PHY_LINK_HEALTH 0x13 /* PHY Link Health Register */
+#define IGP01E1000_GMII_FIFO       0x14 /* GMII FIFO Register */
+#define IGP01E1000_PHY_CHANNEL_QUALITY 0x15 /* PHY Channel Quality Register */
+#define IGP01E1000_PHY_PAGE_SELECT     0x1F /* PHY Page Select Core Register */
+
+/* IGP01E1000 AGC Registers - stores the cable length values*/
+#define IGP01E1000_PHY_AGC_A        0x1172
+#define IGP01E1000_PHY_AGC_B        0x1272
+#define IGP01E1000_PHY_AGC_C        0x1472
+#define IGP01E1000_PHY_AGC_D        0x1872
+
+/* Number of AGC registers */
+#define IGP01E1000_PHY_AGC_NUM     4
+
+/* IGP01E1000 PCS Initialization register - stores the polarity status when
+ * speed = 1000 Mbps. */
+#define IGP01E1000_PHY_PCS_INIT_REG  0x00B4
+
+
 #define MAX_PHY_REG_ADDRESS 0x1F        /* 5 bit address bus (0-0x1F) */
 
 /* PHY Control Register */
@@ -1604,7 +1758,7 @@
 #define NWAY_ER_PAGE_RXD          0x0002 /* LP is 10T   Half Duplex Capable */
 #define NWAY_ER_NEXT_PAGE_CAPS    0x0004 /* LP is 10T   Full Duplex Capable */
 #define NWAY_ER_LP_NEXT_PAGE_CAPS 0x0008 /* LP is 100TX Half Duplex Capable */
-#define NWAY_ER_PAR_DETECT_FAULT  0x0100 /* LP is 100TX Full Duplex Capable */
+#define NWAY_ER_PAR_DETECT_FAULT  0x0010 /* LP is 100TX Full Duplex Capable */
 
 /* Next Page TX Register */
 #define NPTX_MSG_CODE_FIELD 0x0001 /* NP msg code or unformatted data */
@@ -1615,7 +1769,7 @@
                                     * 0 = cannot comply with msg
                                     */
 #define NPTX_MSG_PAGE       0x2000 /* formatted(1)/unformatted(0) pg */
-#define NPTX_NEXT_PAGE      0x8000 /* 1 = addition NP will follow 
+#define NPTX_NEXT_PAGE      0x8000 /* 1 = addition NP will follow
                                     * 0 = sending last NP
                                     */
 
@@ -1624,13 +1778,13 @@
 #define LP_RNPR_TOGGLE         0x0800 /* Toggles between exchanges
                                        * of different NP
                                        */
-#define LP_RNPR_ACKNOWLDGE2    0x1000 /* 1 = will comply with msg 
+#define LP_RNPR_ACKNOWLDGE2    0x1000 /* 1 = will comply with msg
                                        * 0 = cannot comply with msg
                                        */
 #define LP_RNPR_MSG_PAGE       0x2000  /* formatted(1)/unformatted(0) pg */
 #define LP_RNPR_ACKNOWLDGE     0x4000  /* 1 = ACK / 0 = NO ACK */
 #define LP_RNPR_NEXT_PAGE      0x8000  /* 1 = addition NP will follow
-                                        * 0 = sending last NP 
+                                        * 0 = sending last NP
                                         */
 
 /* 1000BASE-T Control Register */
@@ -1677,20 +1831,20 @@
 #define M88E1000_PSCR_JABBER_DISABLE    0x0001 /* 1=Jabber Function disabled */
 #define M88E1000_PSCR_POLARITY_REVERSAL 0x0002 /* 1=Polarity Reversal enabled */
 #define M88E1000_PSCR_SQE_TEST          0x0004 /* 1=SQE Test enabled */
-#define M88E1000_PSCR_CLK125_DISABLE    0x0010 /* 1=CLK125 low, 
+#define M88E1000_PSCR_CLK125_DISABLE    0x0010 /* 1=CLK125 low,
                                                 * 0=CLK125 toggling
                                                 */
 #define M88E1000_PSCR_MDI_MANUAL_MODE  0x0000  /* MDI Crossover Mode bits 6:5 */
                                                /* Manual MDI configuration */
 #define M88E1000_PSCR_MDIX_MANUAL_MODE 0x0020  /* Manual MDIX configuration */
 #define M88E1000_PSCR_AUTO_X_1000T     0x0040  /* 1000BASE-T: Auto crossover,
-                                                *  100BASE-TX/10BASE-T: 
+                                                *  100BASE-TX/10BASE-T:
                                                 *  MDI Mode
                                                 */
-#define M88E1000_PSCR_AUTO_X_MODE      0x0060  /* Auto crossover enabled 
-                                                * all speeds. 
+#define M88E1000_PSCR_AUTO_X_MODE      0x0060  /* Auto crossover enabled
+                                                * all speeds.
                                                 */
-#define M88E1000_PSCR_10BT_EXT_DIST_ENABLE 0x0080 
+#define M88E1000_PSCR_10BT_EXT_DIST_ENABLE 0x0080
                                         /* 1=Enable Extended 10BASE-T distance
                                          * (Lower 10BASE-T RX Threshold)
                                          * 0=Normal 10BASE-T RX Threshold */
@@ -1708,6 +1862,7 @@
 /* M88E1000 PHY Specific Status Register */
 #define M88E1000_PSSR_JABBER             0x0001 /* 1=Jabber */
 #define M88E1000_PSSR_REV_POLARITY       0x0002 /* 1=Polarity reversed */
+#define M88E1000_PSSR_DOWNSHIFT          0x0020 /* 1=Downshifted */
 #define M88E1000_PSSR_MDIX               0x0040 /* 1=MDIX; 0=MDI */
 #define M88E1000_PSSR_CABLE_LENGTH       0x0380 /* 0=<50M;1=50-80M;2=80-110M;
                                             * 3=110-140M;4=>140M */
@@ -1721,6 +1876,7 @@
 #define M88E1000_PSSR_1000MBS            0x8000 /* 10=1000Mbs */
 
 #define M88E1000_PSSR_REV_POLARITY_SHIFT 1
+#define M88E1000_PSSR_DOWNSHIFT_SHIFT    5
 #define M88E1000_PSSR_MDIX_SHIFT         6
 #define M88E1000_PSSR_CABLE_LENGTH_SHIFT 7
 
@@ -1729,12 +1885,12 @@
 #define M88E1000_EPSCR_DOWN_NO_IDLE   0x8000 /* 1=Lost lock detect enabled.
                                               * Will assert lost lock and bring
                                               * link down if idle not seen
-                                              * within 1ms in 1000BASE-T 
+                                              * within 1ms in 1000BASE-T
                                               */
 /* Number of times we will attempt to autonegotiate before downshifting if we
  * are the master */
 #define M88E1000_EPSCR_MASTER_DOWNSHIFT_MASK 0x0C00
-#define M88E1000_EPSCR_MASTER_DOWNSHIFT_1X   0x0000    
+#define M88E1000_EPSCR_MASTER_DOWNSHIFT_1X   0x0000
 #define M88E1000_EPSCR_MASTER_DOWNSHIFT_2X   0x0400
 #define M88E1000_EPSCR_MASTER_DOWNSHIFT_3X   0x0800
 #define M88E1000_EPSCR_MASTER_DOWNSHIFT_4X   0x0C00
@@ -1749,12 +1905,96 @@
 #define M88E1000_EPSCR_TX_CLK_25      0x0070 /* 25  MHz TX_CLK */
 #define M88E1000_EPSCR_TX_CLK_0       0x0000 /* NO  TX_CLK */
 
+
+/* IGP01E1000 Specific Port Config Register - R/W */
+#define IGP01E1000_PSCFR_AUTO_MDIX_PAR_DETECT  0x0010
+#define IGP01E1000_PSCFR_PRE_EN                0x0020
+#define IGP01E1000_PSCFR_SMART_SPEED           0x0080
+#define IGP01E1000_PSCFR_DISABLE_TPLOOPBACK    0x0100
+#define IGP01E1000_PSCFR_DISABLE_JABBER        0x0400
+#define IGP01E1000_PSCFR_DISABLE_TRANSMIT      0x2000
+
+/* IGP01E1000 Specific Port Status Register - R/O */
+#define IGP01E1000_PSSR_AUTONEG_FAILED         0x0001 /* RO LH SC */
+#define IGP01E1000_PSSR_POLARITY_REVERSED      0x0002
+#define IGP01E1000_PSSR_CABLE_LENGTH           0x007C
+#define IGP01E1000_PSSR_FULL_DUPLEX            0x0200
+#define IGP01E1000_PSSR_LINK_UP                0x0400
+#define IGP01E1000_PSSR_MDIX                   0x0800
+#define IGP01E1000_PSSR_SPEED_MASK             0xC000 /* speed bits mask */
+#define IGP01E1000_PSSR_SPEED_10MBPS           0x4000
+#define IGP01E1000_PSSR_SPEED_100MBPS          0x8000
+#define IGP01E1000_PSSR_SPEED_1000MBPS         0xC000
+#define IGP01E1000_PSSR_CABLE_LENGTH_SHIFT     0x0002 /* shift right 2 */
+#define IGP01E1000_PSSR_MDIX_SHIFT             0x000B /* shift right 11 */
+
+/* IGP01E1000 Specific Port Control Register - R/W */
+#define IGP01E1000_PSCR_TP_LOOPBACK            0x0001
+#define IGP01E1000_PSCR_CORRECT_NC_SCMBLR      0x0200
+#define IGP01E1000_PSCR_TEN_CRS_SELECT         0x0400
+#define IGP01E1000_PSCR_FLIP_CHIP              0x0800
+#define IGP01E1000_PSCR_AUTO_MDIX              0x1000
+#define IGP01E1000_PSCR_FORCE_MDI_MDIX         0x2000 /* 0-MDI, 1-MDIX */
+
+/* IGP01E1000 Specific Port Link Health Register */
+#define IGP01E1000_PLHR_SS_DOWNGRADE           0x8000
+#define IGP01E1000_PLHR_GIG_SCRAMBLER_ERROR    0x4000
+#define IGP01E1000_PLHR_GIG_REM_RCVR_NOK       0x0800 /* LH */
+#define IGP01E1000_PLHR_IDLE_ERROR_CNT_OFLOW   0x0400 /* LH */
+#define IGP01E1000_PLHR_DATA_ERR_1             0x0200 /* LH */
+#define IGP01E1000_PLHR_DATA_ERR_0             0x0100
+#define IGP01E1000_PLHR_AUTONEG_FAULT          0x0010
+#define IGP01E1000_PLHR_AUTONEG_ACTIVE         0x0008
+#define IGP01E1000_PLHR_VALID_CHANNEL_D        0x0004
+#define IGP01E1000_PLHR_VALID_CHANNEL_C        0x0002
+#define IGP01E1000_PLHR_VALID_CHANNEL_B        0x0001
+#define IGP01E1000_PLHR_VALID_CHANNEL_A        0x0000
+
+/* IGP01E1000 Channel Quality Register */
+#define IGP01E1000_MSE_CHANNEL_D        0x000F
+#define IGP01E1000_MSE_CHANNEL_C        0x00F0
+#define IGP01E1000_MSE_CHANNEL_B        0x0F00
+#define IGP01E1000_MSE_CHANNEL_A        0xF000
+
+/* IGP01E1000 AGC Registers */
+
+#define IGP01E1000_AGC_LENGTH_SHIFT 7         /* Coarse - 13:11, Fine - 10:7 */
+
+/* 7 bits (3 Coarse + 4 Fine) --> 128 optional values */
+#define IGP01E1000_AGC_LENGTH_TABLE_SIZE 128
+
+/* The precision of the length is +/- 10 meters */
+#define IGP01E1000_AGC_RANGE    10
+
+/* IGP cable length table */
+static const
+uint16_t em_igp_cable_length_table[IGP01E1000_AGC_LENGTH_TABLE_SIZE] =
+    { 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5,
+      5, 10, 10, 10, 10, 10, 10, 10, 20, 20, 20, 20, 20, 25, 25, 25,
+      25, 25, 25, 25, 30, 30, 30, 30, 40, 40, 40, 40, 40, 40, 40, 40,
+      40, 50, 50, 50, 50, 50, 50, 50, 60, 60, 60, 60, 60, 60, 60, 60,
+      60, 70, 70, 70, 70, 70, 70, 80, 80, 80, 80, 80, 80, 90, 90, 90,
+      90, 90, 90, 90, 90, 90, 100, 100, 100, 100, 100, 100, 100, 100, 100, 100,
+      100, 100, 100, 100, 110, 110, 110, 110, 110, 110, 110, 110, 110, 110, 110, 110,
+      110, 110, 110, 110, 110, 110, 120, 120, 120, 120, 120, 120, 120, 120, 120, 120};
+
+/* IGP01E1000 PCS Initialization register */
+/* bits 3:6 in the PCS registers stores the channels polarity */
+#define IGP01E1000_PHY_POLARITY_MASK    0x0078
+
+/* IGP01E1000 GMII FIFO Register */
+#define IGP01E1000_GMII_FLEX_SPD               0x10 /* Enable flexible speed
+                                                     * on Link-Up */
+#define IGP01E1000_GMII_SPD                    0x20 /* Enable SPD */
+
 /* Bit definitions for valid PHY IDs. */
 #define M88E1000_E_PHY_ID  0x01410C50
 #define M88E1000_I_PHY_ID  0x01410C30
 #define M88E1011_I_PHY_ID  0x01410C20
+#define IGP01E1000_I_PHY_ID  0x02A80380
 #define M88E1000_12_PHY_ID M88E1000_E_PHY_ID
 #define M88E1000_14_PHY_ID M88E1000_E_PHY_ID
+#define M88E1011_I_REV_4   0x04
 
 /* Miscellaneous PHY bit definitions. */
 #define PHY_PREAMBLE        0xFFFFFFFF
Index: dev/pci/if_em_osdep.h
===================================================================
RCS file: /u/open/cvs/src/sys/dev/pci/if_em_osdep.h,v
retrieving revision 1.1
diff -u -r1.1 if_em_osdep.h
--- dev/pci/if_em_osdep.h	24 Sep 2002 18:56:02 -0000	1.1
+++ dev/pci/if_em_osdep.h	14 Jul 2004 21:32:07 -0000
@@ -1,42 +1,41 @@
 /**************************************************************************
 
-Copyright (c) 2001-2002 Intel Corporation
+Copyright (c) 2001-2003, Intel Corporation
 All rights reserved.
 
-Redistribution and use in source and binary forms of the Software, with or
-without modification, are permitted provided that the following conditions
-are met:
-
- 1. Redistributions of source code of the Software may retain the above
-    copyright notice, this list of conditions and the following disclaimer.
-
- 2. Redistributions in binary form of the Software may reproduce the above
-    copyright notice, this list of conditions and the following disclaimer
-    in the documentation and/or other materials provided with the
-    distribution.
+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 shall be used to endorse or promote products derived from
-    this Software without specific prior written permission.
+    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 INTEL OR ITS 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.
+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.
 
 ***************************************************************************/
 
-/*$FreeBSD$*/
+/*$FreeBSD: if_em_osdep.h,v 1.11 2003/05/02 21:17:08 pdeuskar Exp $*/
+/* $OpenBSD: if_em_osdep.h,v 1.2 2003/06/13 19:21:21 henric Exp $ */
 
-#ifndef _OPENBSD_OS_H_
-#define _OPENBSD_OS_H_
+#ifndef _EM_OPENBSD_OS_H_
+#define _EM_OPENBSD_OS_H_
 
 #define ASSERT(x) if(!(x)) panic("EM: x")
 
@@ -65,26 +64,14 @@
 #define CMD_MEM_WRT_INVALIDATE          0x0010  /* BIT_4 */
 #define PCI_COMMAND_REGISTER            PCI_COMMAND_STATUS_REG 
 
-struct em_dmamap
-{
-        bus_size_t              emm_size;
-        caddr_t                 emm_ptr, emm_kva;
-        bus_dma_segment_t       emm_seg;
-        bus_dmamap_t            emm_dmamap;
-        int                     emm_rseg;
-};
-
 struct em_osdep
 {
+	bus_space_tag_t    mem_bus_space_tag;
+	bus_space_handle_t mem_bus_space_handle;
 	struct device     *dev;
 
-	struct em_dmamap   em_rx;
-	struct em_dmamap   em_tx;
-
 	struct pci_attach_args em_pa;
 
-	bus_space_handle_t      em_bhandle;
-        bus_space_tag_t         em_btag;
         bus_size_t              em_memsize;
         bus_addr_t              em_membase;
 
@@ -92,40 +79,35 @@
         bus_space_tag_t         em_iobtag;
         bus_size_t              em_iosize;
         bus_addr_t              em_iobase;
-
 };
 
-#define E1000_READ_REG(hw, reg) \
-   bus_space_read_4( \
-		((struct em_osdep *)(hw)->back)->em_btag, \
-		((struct em_osdep *)(hw)->back)->em_bhandle, \
-		((hw)->mac_type >= em_82543) ? \
-			E1000_##reg : E1000_82542_##reg)
-
-#define E1000_WRITE_REG(hw, reg, value) \
-   bus_space_write_4( \
-		((struct em_osdep *)(hw)->back)->em_btag, \
-		((struct em_osdep *)(hw)->back)->em_bhandle, \
-		((hw)->mac_type >= em_82543) ? \
-                     	E1000_##reg : E1000_82542_##reg, \
-		value)
-
-#define E1000_READ_REG_ARRAY(sc, reg, offset) \
-   bus_space_read_4( \
-		((struct em_osdep *)(hw)->back)->em_btag, \
-		((struct em_osdep *)(hw)->back)->em_bhandle, \
-		((hw)->mac_type >= em_82543) ? \
-			(E1000_##reg       + ((offset) << 2)) : \
-			(E1000_82542_##reg + ((offset) << 2)) )
-
-#define E1000_WRITE_REG_ARRAY(sc, reg, offset, value) \
-      bus_space_write_4( \
-		((struct em_osdep *)(hw)->back)->em_btag, \
-		((struct em_osdep *)(hw)->back)->em_bhandle, \
-		((hw)->mac_type >= em_82543) ? \
-			(E1000_##reg       + ((offset) << 2)) : \
-			(E1000_82542_##reg + ((offset) << 2)), \
-		value)
+#define E1000_WRITE_FLUSH(a) E1000_READ_REG(a, STATUS)
+
+#define E1000_READ_REG(a, reg) 						\
+   bus_space_read_4( ((struct em_osdep *)(a)->back)->mem_bus_space_tag,	\
+	((struct em_osdep *)(a)->back)->mem_bus_space_handle,		\
+	((a)->mac_type >= em_82543) ? E1000_##reg : E1000_82542_##reg)
+
+#define E1000_WRITE_REG(a, reg, value)					\
+   bus_space_write_4( ((struct em_osdep *)(a)->back)->mem_bus_space_tag, \
+	((struct em_osdep *)(a)->back)->mem_bus_space_handle,		\
+	((a)->mac_type >= em_82543) ? E1000_##reg : E1000_82542_##reg,	\
+	value)
+
+#define E1000_READ_REG_ARRAY(a, reg, offset)				\
+   bus_space_read_4( ((struct em_osdep *)(a)->back)->mem_bus_space_tag,	\
+		     ((struct em_osdep *)(a)->back)->mem_bus_space_handle, \
+		     ((a)->mac_type >= em_82543) ?			\
+				(E1000_##reg	   + ((offset) << 2)) :	\
+				(E1000_82542_##reg + ((offset) << 2)) ) 
+
+#define E1000_WRITE_REG_ARRAY(a, reg, offset, value)			\
+    bus_space_write_4( ((struct em_osdep *)(a)->back)->mem_bus_space_tag, \
+	((struct em_osdep *)(a)->back)->mem_bus_space_handle,		\
+	((a)->mac_type >= em_82543) ?					\
+		(E1000_##reg	   + ((offset) << 2)) :			\
+		(E1000_82542_##reg + ((offset) << 2)),			\
+	value)
 
-#endif  /* _OPENBSD_OS_H_ */
+#endif  /* _EM_OPENBSD_OS_H_ */
 
Index: dev/pci/pcidevs
===================================================================
RCS file: /u/open/cvs/src/sys/dev/pci/pcidevs,v
retrieving revision 1.609.2.3
diff -u -r1.609.2.3 pcidevs
--- dev/pci/pcidevs	13 Jun 2003 18:52:10 -0000	1.609.2.3
+++ dev/pci/pcidevs	14 Jul 2004 21:32:07 -0000
@@ -1377,15 +1377,21 @@
 product INTEL 82543GC_SC	0x1001	PRO/1000F (PWLA8490SX)
 product INTEL 82543GC		0x1004	PRO/1000T (PWLA8490T)
 product INTEL 82544EI		0x1008	PRO/1000XT (PWLA8490XT)
-product INTEL 82544EI_SC	0x1009	PRO/1000XS (PWLA8490XF)
+product INTEL 82544EI_SC	0x1009	PRO/1000XF (PWLA8490XF)
 product INTEL 82544GC		0x100c	PRO/1000T (PWLA8390T)
-product INTEL 82544GC_LX	0x100d	PRO/1000XTL (PWLA8490XTL)
+product INTEL 82544GC_LOM	0x100d	PRO/1000T LOM
 product INTEL 82540EM		0x100e	PRO/1000MT (PWLA8390MT)
 product INTEL 82545EM		0x100f	PRO/1000MT (PWLA8490MT)
 product INTEL 82546EB		0x1010	PRO/1000MT (PWLA8492MT)
 product INTEL 82545EM_SC	0x1011	PRO/1000MF (PWLA8490MF)
 product INTEL 82546EB_SC	0x1012	PRO/1000MF (PWLA8492MF)
-product INTEL 82545EM_LX	0x1015	PRO/1000MF (PWLA8490LX)
+product INTEL 82541EI		0x1013	PRO/1000 (82541EI)
+product INTEL 82540EM_LOM	0x1015	PRO/1000MT (LOM)
+product INTEL 82540EP_LOM	0x1016	PRO/1000 (82540EP LOM)
+product INTEL 82540EP		0x1017	PRO/1000 (82540EP)
+product INTEL 82541EP		0x1018	PRO/1000 (82541EP)
+product INTEL 82547EI		0x1019	PRO/1000 (82547EI)
+product INTEL 82540EP_LP	0x101e	PRO/1000 (82540EP LP)
 product INTEL 82559		0x1030	82559
 product INTEL PRO_100_VE_0	0x1031	PRO/100 VE
 product INTEL PRO_100_VE_1	0x1032	PRO/100 VE
Index: dev/pci/pcidevs.h
===================================================================
RCS file: /u/open/cvs/src/sys/dev/pci/pcidevs.h,v
retrieving revision 1.610
diff -u -r1.610 pcidevs.h
--- dev/pci/pcidevs.h	19 Mar 2003 21:28:50 -0000	1.610
+++ dev/pci/pcidevs.h	14 Jul 2004 21:32:07 -0000
@@ -1382,15 +1382,22 @@
 #define	PCI_PRODUCT_INTEL_82543GC_SC	0x1001		/* PRO/1000F (PWLA8490SX) */
 #define	PCI_PRODUCT_INTEL_82543GC	0x1004		/* PRO/1000T (PWLA8490T) */
 #define	PCI_PRODUCT_INTEL_82544EI	0x1008		/* PRO/1000XT (PWLA8490XT) */
-#define	PCI_PRODUCT_INTEL_82544EI_SC	0x1009		/* PRO/1000XS (PWLA8490XF) */
+#define	PCI_PRODUCT_INTEL_82544EI_SC	0x1009		/* PRO/1000XF (PWLA8490XF) */
 #define	PCI_PRODUCT_INTEL_82544GC	0x100c		/* PRO/1000T (PWLA8390T) */
-#define	PCI_PRODUCT_INTEL_82544GC_LX	0x100d		/* PRO/1000XTL (PWLA8490XTL) */
+#define	PCI_PRODUCT_INTEL_82544GC_LOM	0x100d		/* PRO/1000T LOM */
 #define	PCI_PRODUCT_INTEL_82540EM	0x100e		/* PRO/1000MT (PWLA8390MT) */
 #define	PCI_PRODUCT_INTEL_82545EM	0x100f		/* PRO/1000MT (PWLA8490MT) */
 #define	PCI_PRODUCT_INTEL_82546EB	0x1010		/* PRO/1000MT (PWLA8492MT) */
 #define	PCI_PRODUCT_INTEL_82545EM_SC	0x1011		/* PRO/1000MF (PWLA8490MF) */
 #define	PCI_PRODUCT_INTEL_82546EB_SC	0x1012		/* PRO/1000MF (PWLA8492MF) */
 #define	PCI_PRODUCT_INTEL_82545EM_LX	0x1015		/* PRO/1000MF (PWLA8490LX) */
+#define	PCI_PRODUCT_INTEL_82541EI	0x1013		/* PRO/1000 (82541EI) */
+#define	PCI_PRODUCT_INTEL_82540EM_LOM	0x1015		/* PRO/1000MT (LOM) */
+#define	PCI_PRODUCT_INTEL_82540EP_LOM	0x1016		/* PRO/1000 (82540EP LOM) */
+#define	PCI_PRODUCT_INTEL_82540EP	0x1017		/* PRO/1000 (82540EP) */
+#define	PCI_PRODUCT_INTEL_82541EP	0x1018		/* PRO/1000 (82541EP) */
+#define	PCI_PRODUCT_INTEL_82547EI	0x1019		/* PRO/1000 (82547EI) */
+#define	PCI_PRODUCT_INTEL_82540EP_LP	0x101e		/* PRO/1000 (82540EP LP) */
 #define	PCI_PRODUCT_INTEL_82559	0x1030		/* 82559 */
 #define	PCI_PRODUCT_INTEL_PRO_100_VE_0	0x1031		/* PRO/100 VE */
 #define	PCI_PRODUCT_INTEL_PRO_100_VE_1	0x1032		/* PRO/100 VE */
Index: dev/pci/pcidevs_data.h
===================================================================
RCS file: /u/open/cvs/src/sys/dev/pci/pcidevs_data.h,v
retrieving revision 1.610
diff -u -r1.610 pcidevs_data.h
--- dev/pci/pcidevs_data.h	19 Mar 2003 21:28:50 -0000	1.610
+++ dev/pci/pcidevs_data.h	14 Jul 2004 21:32:07 -0000
@@ -2452,19 +2452,39 @@
 	},
 	{
 	    PCI_VENDOR_INTEL, PCI_PRODUCT_INTEL_82544EI_SC,
-	    "PRO/1000XS (PWLA8490XF)",
+	    "PRO/1000XF (PWLA8490XF)",
 	},
 	{
 	    PCI_VENDOR_INTEL, PCI_PRODUCT_INTEL_82544GC,
 	    "PRO/1000T (PWLA8390T)",
 	},
 	{
-	    PCI_VENDOR_INTEL, PCI_PRODUCT_INTEL_82544GC_LX,
-	    "PRO/1000XTL (PWLA8490XTL)",
+	    PCI_VENDOR_INTEL, PCI_PRODUCT_INTEL_82544GC_LOM,
+	    "PRO/1000T LOM",
 	},
 	{
 	    PCI_VENDOR_INTEL, PCI_PRODUCT_INTEL_82540EM,
 	    "PRO/1000MT (PWLA8390MT)",
+	},
+	{
+	    PCI_VENDOR_INTEL, PCI_PRODUCT_INTEL_82540EM_LOM,
+	    "PRO/1000MT (LOM)",
+	},
+	{
+	    PCI_VENDOR_INTEL, PCI_PRODUCT_INTEL_82540EP_LOM,
+	    "PRO/1000 (82540EP LOM)",
+	},
+	{
+	    PCI_VENDOR_INTEL, PCI_PRODUCT_INTEL_82540EP,
+	    "PRO/1000 (82540EP)",
+	},
+	{
+	    PCI_VENDOR_INTEL, PCI_PRODUCT_INTEL_82541EP,
+	    "PRO/1000 (82541EP)",
+ 	},
+ 	{
+ 	    PCI_VENDOR_INTEL, PCI_PRODUCT_INTEL_82547EI,
+	    "PRO/1000 (82547EI)",
 	},
 	{
 	    PCI_VENDOR_INTEL, PCI_PRODUCT_INTEL_82545EM,
