--- ./sys/dev/bge/if_bge.c.70	2008-03-01 15:03:15.000000000 +0100
+++ ./sys/dev/bge/if_bge.c	2008-03-01 15:00:22.000000000 +0100
@@ -195,6 +195,8 @@
 	{ BCOM_VENDORID,	BCOM_DEVICEID_BCM5901 },
 	{ BCOM_VENDORID,	BCOM_DEVICEID_BCM5901A2 },
 	{ BCOM_VENDORID,	BCOM_DEVICEID_BCM5903M },
+	{ BCOM_VENDORID,	BCOM_DEVICEID_BCM5906 },
+	{ BCOM_VENDORID,	BCOM_DEVICEID_BCM5906M },
 
 	{ SK_VENDORID,		SK_DEVICEID_ALTIMA },
 
@@ -271,6 +273,8 @@
 	{ BGE_CHIPID_BCM5787_A0,	"BCM5754/5787 A0" }, 
 	{ BGE_CHIPID_BCM5787_A1,	"BCM5754/5787 A1" },
 	{ BGE_CHIPID_BCM5787_A2,	"BCM5754/5787 A2" },
+	{ BGE_CHIPID_BCM5906_A1,	"BCM5906 A1" },
+	{ BGE_CHIPID_BCM5906_A2,	"BCM5906 A2" },
 
 	{ 0, NULL }
 };
@@ -293,6 +297,7 @@
 	{ BGE_ASICREV_BCM5755,		"unknown BCM5755" },
 	/* 5754 and 5787 share the same ASIC ID */
 	{ BGE_ASICREV_BCM5787,		"unknown BCM5754/5787" },
+	{ BGE_ASICREV_BCM5906,		"unknown BCM5906" },
 
 	{ 0, NULL }
 };
@@ -305,6 +310,9 @@
 
 const struct bge_revision * bge_lookup_rev(uint32_t);
 const struct bge_vendor * bge_lookup_vendor(uint16_t);
+
+typedef int	(*bge_eaddr_fcn_t)(struct bge_softc *, uint8_t[]);
+
 static int bge_probe(device_t);
 static int bge_attach(device_t);
 static int bge_detach(device_t);
@@ -315,6 +323,11 @@
 static int bge_dma_alloc(device_t);
 static void bge_dma_free(struct bge_softc *);
 
+static int bge_get_eaddr_mem(struct bge_softc *, uint8_t[]);
+static int bge_get_eaddr_nvram(struct bge_softc *, uint8_t[]);
+static int bge_get_eaddr_eeprom(struct bge_softc *, uint8_t[]);
+static int bge_get_eaddr(struct bge_softc *, uint8_t[]);
+
 static void bge_txeof(struct bge_softc *);
 static void bge_rxeof(struct bge_softc *);
 
@@ -337,6 +350,9 @@
 static int bge_ifmedia_upd(struct ifnet *);
 static void bge_ifmedia_sts(struct ifnet *, struct ifmediareq *);
 
+static uint8_t bge_nvram_getbyte(struct bge_softc *, int, uint8_t *);
+static int bge_read_nvram(struct bge_softc *, caddr_t, int, int);
+
 static uint8_t bge_eeprom_getbyte(struct bge_softc *, int, uint8_t *);
 static int bge_read_eeprom(struct bge_softc *, caddr_t, int, int);
 
@@ -359,6 +375,7 @@
 static int bge_has_eeprom(struct bge_softc *);
 static uint32_t bge_readmem_ind(struct bge_softc *, int);
 static void bge_writemem_ind(struct bge_softc *, int, int);
+static void bge_writembx(struct bge_softc *, int, int);
 #ifdef notdef
 static uint32_t bge_readreg_ind(struct bge_softc *, int);
 #endif
@@ -474,6 +491,10 @@
 			return (0);
 	}
 #endif
+
+	if (sc->bge_asicrev == BGE_ASICREV_BCM5906)
+		return (0);
+
 	return (1);
 }
 
@@ -533,6 +554,15 @@
 	CSR_WRITE_4(sc, off, val);
 }
 
+static void
+bge_writembx(struct bge_softc *sc, int off, int val)
+{
+	if (sc->bge_asicrev == BGE_ASICREV_BCM5906)
+		off += BGE_LPMBX_IRQ0_HI - BGE_MBX_IRQ0_HI;
+
+	CSR_WRITE_4(sc, off, val);
+}
+
 /*
  * Map a single buffer address.
  */
@@ -555,6 +585,78 @@
 	ctx->bge_busaddr = segs->ds_addr;
 }
 
+static uint8_t
+bge_nvram_getbyte(struct bge_softc *sc, int addr, uint8_t *dest)
+{
+	uint32_t access, byte = 0;
+	int i;
+
+	/* Lock. */
+	CSR_WRITE_4(sc, BGE_NVRAM_SWARB, BGE_NVRAMSWARB_SET1);
+	for (i = 0; i < 8000; i++) {
+		if (CSR_READ_4(sc, BGE_NVRAM_SWARB) & BGE_NVRAMSWARB_GNT1)
+			break;
+		DELAY(20);
+	}
+	if (i == 8000)
+		return (1);
+
+	/* Enable access. */
+	access = CSR_READ_4(sc, BGE_NVRAM_ACCESS);
+	CSR_WRITE_4(sc, BGE_NVRAM_ACCESS, access | BGE_NVRAMACC_ENABLE);
+
+	CSR_WRITE_4(sc, BGE_NVRAM_ADDR, addr & 0xfffffffc);
+	CSR_WRITE_4(sc, BGE_NVRAM_CMD, BGE_NVRAM_READCMD);
+	for (i = 0; i < BGE_TIMEOUT * 10; i++) {
+		DELAY(10);
+		if (CSR_READ_4(sc, BGE_NVRAM_CMD) & BGE_NVRAMCMD_DONE) {
+			DELAY(10);
+			break;
+		}
+	}
+
+	if (i == BGE_TIMEOUT * 10) {
+		if_printf(sc->bge_ifp, "nvram read timed out\n");
+		return (1);
+	}
+
+	/* Get result. */
+	byte = CSR_READ_4(sc, BGE_NVRAM_RDDATA);
+
+	*dest = (bswap32(byte) >> ((addr % 4) * 8)) & 0xFF;
+
+	/* Disable access. */
+	CSR_WRITE_4(sc, BGE_NVRAM_ACCESS, access);
+
+	/* Unlock. */
+	CSR_WRITE_4(sc, BGE_NVRAM_SWARB, BGE_NVRAMSWARB_CLR1);
+	CSR_READ_4(sc, BGE_NVRAM_SWARB);
+
+	return (0);
+}
+
+/*
+ * Read a sequence of bytes from NVRAM.
+ */
+static int
+bge_read_nvram(struct bge_softc *sc, caddr_t dest, int off, int cnt)
+{
+	int err = 0, i;
+	uint8_t byte = 0;
+
+	if (sc->bge_asicrev != BGE_ASICREV_BCM5906)
+		return (1);
+
+	for (i = 0; i < cnt; i++) {
+		err = bge_nvram_getbyte(sc, off + i, &byte);
+		if (err)
+			break;
+		*(dest + i) = byte;
+	}
+
+	return (err ? 1 : 0);
+}
+
 /*
  * Read a byte of data stored in the EEPROM at address 'addr.' The
  * BCM570x supports both the traditional bitbang interface and an
@@ -659,11 +761,13 @@
 	}
 
 	if (i == BGE_TIMEOUT) {
-		device_printf(sc->bge_dev, "PHY read timed out\n");
+		device_printf(sc->bge_dev, "PHY read timed out "
+			  "(phy %d, reg %d, val 0x%08x)\n", phy, reg, val);
 		val = 0;
 		goto done;
 	}
 
+	DELAY(5);
 	val = CSR_READ_4(sc, BGE_MI_COMM);
 
 done:
@@ -687,6 +791,10 @@
 
 	sc = device_get_softc(dev);
 
+	if (sc->bge_asicrev == BGE_ASICREV_BCM5906 &&
+	    (reg == BRGPHY_MII_1000CTL || reg == BRGPHY_MII_AUXCTL))
+		return(0);
+
 	/* Reading with autopolling on may trigger PCI errors */
 	autopoll = CSR_READ_4(sc, BGE_MI_MODE);
 	if (autopoll & BGE_MIMODE_AUTOPOLL) {
@@ -699,12 +807,17 @@
 
 	for (i = 0; i < BGE_TIMEOUT; i++) {
 		DELAY(10);
-		if (!(CSR_READ_4(sc, BGE_MI_COMM) & BGE_MICOMM_BUSY))
+		if (!(CSR_READ_4(sc, BGE_MI_COMM) & BGE_MICOMM_BUSY)) {
+			DELAY(5);
+			CSR_READ_4(sc, BGE_MI_COMM); /* dummy read */
 			break;
+		}
 	}
 
 	if (i == BGE_TIMEOUT) {
-		device_printf(sc->bge_dev, "PHY write timed out\n");
+		device_printf(sc->bge_dev,
+			  "PHY write timed out (phy %d, reg %d, val %d)\n",
+			  phy, reg, val);
 		return (0);
 	}
 
@@ -887,7 +1000,7 @@
 	    BUS_DMASYNC_PREREAD | BUS_DMASYNC_PREWRITE);
 
 	sc->bge_std = i - 1;
-	CSR_WRITE_4(sc, BGE_MBX_RX_STD_PROD_LO, sc->bge_std);
+	bge_writembx(sc, BGE_MBX_RX_STD_PROD_LO, sc->bge_std);
 
 	return (0);
 }
@@ -934,7 +1047,7 @@
 				    BGE_RCB_FLAG_USE_EXT_RX_BD);
 	CSR_WRITE_4(sc, BGE_RX_JUMBO_RCB_MAXLEN_FLAGS, rcb->bge_maxlen_flags);
 
-	CSR_WRITE_4(sc, BGE_MBX_RX_JUMBO_PROD_LO, sc->bge_jumbo);
+	bge_writembx(sc, BGE_MBX_RX_JUMBO_PROD_LO, sc->bge_jumbo);
 
 	return (0);
 }
@@ -990,17 +1103,17 @@
 
 	/* Initialize transmit producer index for host-memory send ring. */
 	sc->bge_tx_prodidx = 0;
-	CSR_WRITE_4(sc, BGE_MBX_TX_HOST_PROD0_LO, sc->bge_tx_prodidx);
+	bge_writembx(sc, BGE_MBX_TX_HOST_PROD0_LO, sc->bge_tx_prodidx);
 
 	/* 5700 b2 errata */
 	if (sc->bge_chiprev == BGE_CHIPREV_5700_BX)
-		CSR_WRITE_4(sc, BGE_MBX_TX_HOST_PROD0_LO, sc->bge_tx_prodidx);
+		bge_writembx(sc, BGE_MBX_TX_HOST_PROD0_LO, sc->bge_tx_prodidx);
 
 	/* NIC-memory send ring not used; initialize to zero. */
-	CSR_WRITE_4(sc, BGE_MBX_TX_NIC_PROD0_LO, 0);
+	bge_writembx(sc, BGE_MBX_TX_NIC_PROD0_LO, 0);
 	/* 5700 b2 errata */
 	if (sc->bge_chiprev == BGE_CHIPREV_5700_BX)
-		CSR_WRITE_4(sc, BGE_MBX_TX_NIC_PROD0_LO, 0);
+		bge_writembx(sc, BGE_MBX_TX_NIC_PROD0_LO, 0);
 
 	return (0);
 }
@@ -1271,6 +1384,15 @@
 	/* Set the timer prescaler (always 66Mhz) */
 	CSR_WRITE_4(sc, BGE_MISC_CFG, BGE_32BITTIME_66MHZ);
 
+	if (sc->bge_asicrev == BGE_ASICREV_BCM5906) {
+		DELAY(40);	/* XXX */
+
+		/* Put PHY into ready state */
+		BGE_CLRBIT(sc, BGE_MISC_CFG, BGE_MISCCFG_EPHY_IDDQ);
+		CSR_READ_4(sc, BGE_MISC_CFG); /* Flush */
+		DELAY(40);
+	}
+
 	return (0);
 }
 
@@ -1307,15 +1429,21 @@
 		CSR_WRITE_4(sc, BGE_BMAN_DMA_DESCPOOL_LEN, 0x2000);
 	}
 
+
 	/* Configure mbuf pool watermarks */
-	if (BGE_IS_5705_PLUS(sc)) {
-		CSR_WRITE_4(sc, BGE_BMAN_MBUFPOOL_READDMA_LOWAT, 0x0);
-		CSR_WRITE_4(sc, BGE_BMAN_MBUFPOOL_MACRX_LOWAT, 0x10);
-	} else {
+	if (!BGE_IS_5705_PLUS(sc)) {
 		CSR_WRITE_4(sc, BGE_BMAN_MBUFPOOL_READDMA_LOWAT, 0x50);
 		CSR_WRITE_4(sc, BGE_BMAN_MBUFPOOL_MACRX_LOWAT, 0x20);
+		CSR_WRITE_4(sc, BGE_BMAN_MBUFPOOL_HIWAT, 0x60);
+	} else if (sc->bge_asicrev == BGE_ASICREV_BCM5906) {
+		CSR_WRITE_4(sc, BGE_BMAN_MBUFPOOL_READDMA_LOWAT, 0x0);
+		CSR_WRITE_4(sc, BGE_BMAN_MBUFPOOL_MACRX_LOWAT, 0x04);
+		CSR_WRITE_4(sc, BGE_BMAN_MBUFPOOL_HIWAT, 0x10);
+	} else {
+		CSR_WRITE_4(sc, BGE_BMAN_MBUFPOOL_READDMA_LOWAT, 0x0);
+		CSR_WRITE_4(sc, BGE_BMAN_MBUFPOOL_MACRX_LOWAT, 0x10);
+		CSR_WRITE_4(sc, BGE_BMAN_MBUFPOOL_HIWAT, 0x60);
 	}
-	CSR_WRITE_4(sc, BGE_BMAN_MBUFPOOL_HIWAT, 0x60);
 
 	/* Configure DMA resource watermarks */
 	CSR_WRITE_4(sc, BGE_BMAN_DMA_DESCPOOL_LOWAT, 5);
@@ -1462,15 +1590,15 @@
 		    BGE_RCB_MAXLEN_FLAGS(sc->bge_return_ring_cnt,
 		    BGE_RCB_FLAG_RING_DISABLED));
 		RCB_WRITE_4(sc, vrcb, bge_nicaddr, 0);
-		CSR_WRITE_4(sc, BGE_MBX_RX_CONS0_LO +
+		bge_writembx(sc, BGE_MBX_RX_CONS0_LO +
 		    (i * (sizeof(uint64_t))), 0);
 		vrcb += sizeof(struct bge_rcb);
 	}
 
 	/* Initialize RX ring indexes */
-	CSR_WRITE_4(sc, BGE_MBX_RX_STD_PROD_LO, 0);
-	CSR_WRITE_4(sc, BGE_MBX_RX_JUMBO_PROD_LO, 0);
-	CSR_WRITE_4(sc, BGE_MBX_RX_MINI_PROD_LO, 0);
+	bge_writembx(sc, BGE_MBX_RX_STD_PROD_LO, 0);
+	bge_writembx(sc, BGE_MBX_RX_JUMBO_PROD_LO, 0);
+	bge_writembx(sc, BGE_MBX_RX_MINI_PROD_LO, 0);
 
 	/*
 	 * Set up RX return ring 0
@@ -2230,7 +2358,6 @@
 	struct ifnet *ifp;
 	struct bge_softc *sc;
 	uint32_t hwcfg = 0;
-	uint32_t mac_tmp = 0;
 	u_char eaddr[ETHER_ADDR_LEN];
 	int error, reg, rid, trys;
 
@@ -2283,6 +2410,7 @@
 	case BGE_ASICREV_BCM5752:
 	case BGE_ASICREV_BCM5755:
 	case BGE_ASICREV_BCM5787:
+	case BGE_ASICREV_BCM5906:
 		sc->bge_flags |= BGE_FLAG_575X_PLUS;
 		/* FALLTHRU */
 	case BGE_ASICREV_BCM5705:
@@ -2304,7 +2432,7 @@
 		if (sc->bge_asicrev == BGE_ASICREV_BCM5755 ||
 		    sc->bge_asicrev == BGE_ASICREV_BCM5787)
 			sc->bge_flags |= BGE_FLAG_JITTER_BUG;
-		else
+		else if (sc->bge_asicrev != BGE_ASICREV_BCM5906)
 			sc->bge_flags |= BGE_FLAG_BER_BUG;
 	}
 
@@ -2415,22 +2543,14 @@
 	}
 
 #ifdef __sparc64__
-	if ((sc->bge_flags & BGE_FLAG_EEPROM) == 0)
+	if (((sc->bge_flags & BGE_FLAG_EEPROM) == 0) &&
+	    (sc->bge_asicrev != BGE_ASICREV_BCM5906))
 		OF_getetheraddr(dev, eaddr);
 	else
 #endif
 	{
-		mac_tmp = bge_readmem_ind(sc, 0x0C14);
-		if ((mac_tmp >> 16) == 0x484B) {
-			eaddr[0] = (u_char)(mac_tmp >> 8);
-			eaddr[1] = (u_char)mac_tmp;
-			mac_tmp = bge_readmem_ind(sc, 0x0C18);
-			eaddr[2] = (u_char)(mac_tmp >> 24);
-			eaddr[3] = (u_char)(mac_tmp >> 16);
-			eaddr[4] = (u_char)(mac_tmp >> 8);
-			eaddr[5] = (u_char)mac_tmp;
-		} else if (bge_read_eeprom(sc, eaddr,
-		    BGE_EE_MAC_OFFSET + 2, ETHER_ADDR_LEN)) {
+		error = bge_get_eaddr(sc, eaddr);
+		if (error) {
 			device_printf(sc->bge_dev,
 			    "failed to read station address\n");
 			error = ENXIO;
@@ -2688,7 +2808,8 @@
 
 	dev = sc->bge_dev;
 
-	if (BGE_IS_575X_PLUS(sc) && !BGE_IS_5714_FAMILY(sc)) {
+	if (BGE_IS_575X_PLUS(sc) && !BGE_IS_5714_FAMILY(sc) &&
+	    (sc->bge_asicrev != BGE_ASICREV_BCM5906)) {
 		if (sc->bge_flags & BGE_FLAG_PCIE)
 			write_op = bge_writemem_direct;
 		else
@@ -2744,6 +2865,17 @@
 	/* Issue global reset */
 	write_op(sc, BGE_MISC_CFG, reset);
 
+	if (sc->bge_asicrev == BGE_ASICREV_BCM5906) {
+		uint32_t status, ctrl;
+
+		status = CSR_READ_4(sc, BGE_VCPU_STATUS);
+		CSR_WRITE_4(sc, BGE_VCPU_STATUS,
+		    status | BGE_VCPU_STATUS_DRV_RESET);
+		ctrl = CSR_READ_4(sc, BGE_VCPU_EXT_CTRL);
+		CSR_WRITE_4(sc, BGE_VCPU_EXT_CTRL,
+		    ctrl & ~BGE_VCPU_EXT_CTRL_HALT_CPU);
+	}
+
 	DELAY(1000);
 
 	/* XXX: Broadcom Linux driver. */
@@ -2788,21 +2920,34 @@
 	} else
 		CSR_WRITE_4(sc, BGE_MARB_MODE, BGE_MARBMODE_ENABLE);
 
-	/*
-	 * Poll until we see the 1's complement of the magic number.
-	 * This indicates that the firmware initialization is complete.
-	 * We expect this to fail if no EEPROM is fitted though.
-	 */
-	for (i = 0; i < BGE_TIMEOUT; i++) {
-		DELAY(10);
-		val = bge_readmem_ind(sc, BGE_SOFTWARE_GENCOMM);
-		if (val == ~BGE_MAGIC_NUMBER)
-			break;
-	}
+	if (sc->bge_asicrev == BGE_ASICREV_BCM5906) {
+		for (i = 0; i < BGE_TIMEOUT; i++) {
+			val = CSR_READ_4(sc, BGE_VCPU_STATUS);
+			if (val & BGE_VCPU_STATUS_INIT_DONE)
+				break;
+			DELAY(100);
+		}
+		if (i == BGE_TIMEOUT) {
+			device_printf(sc->bge_dev, "reset timed out\n");
+			return (1);
+		}
+	} else {
+		/*
+		 * Poll until we see the 1's complement of the magic number.
+		 * This indicates that the firmware initialization is complete.
+		 * We expect this to fail if no EEPROM is fitted though.
+		 */
+		for (i = 0; i < BGE_TIMEOUT; i++) {
+			DELAY(10);
+			val = bge_readmem_ind(sc, BGE_SOFTWARE_GENCOMM);
+			if (val == ~BGE_MAGIC_NUMBER)
+				break;
+		}
 
-	if ((sc->bge_flags & BGE_FLAG_EEPROM) && i == BGE_TIMEOUT)
-		device_printf(sc->bge_dev, "firmware handshake timed out, "
-		    "found 0x%08x\n", val);
+		if ((sc->bge_flags & BGE_FLAG_EEPROM) && i == BGE_TIMEOUT)
+			device_printf(sc->bge_dev, "firmware handshake timed out, "
+			    "found 0x%08x\n", val);
+	}
 
 	/*
 	 * XXX Wait for the value of the PCISTATE register to
@@ -3022,11 +3167,11 @@
 		bus_dmamap_sync(sc->bge_cdata.bge_rx_jumbo_ring_tag,
 		    sc->bge_cdata.bge_rx_jumbo_ring_map, BUS_DMASYNC_PREWRITE);
 
-	CSR_WRITE_4(sc, BGE_MBX_RX_CONS0_LO, sc->bge_rx_saved_considx);
+	bge_writembx(sc, BGE_MBX_RX_CONS0_LO, sc->bge_rx_saved_considx);
 	if (stdcnt)
-		CSR_WRITE_4(sc, BGE_MBX_RX_STD_PROD_LO, sc->bge_std);
+		bge_writembx(sc, BGE_MBX_RX_STD_PROD_LO, sc->bge_std);
 	if (jumbocnt)
-		CSR_WRITE_4(sc, BGE_MBX_RX_JUMBO_PROD_LO, sc->bge_jumbo);
+		bge_writembx(sc, BGE_MBX_RX_JUMBO_PROD_LO, sc->bge_jumbo);
 #ifdef notyet
 	/*
 	 * This register wraps very quickly under heavy packet drops.
@@ -3168,7 +3313,7 @@
 	 * the status check).  So toggling would probably be a pessimization
 	 * even with MSI.  It would only be needed for using a task queue.
 	 */
-	CSR_WRITE_4(sc, BGE_MBX_IRQ0_LO, 0);
+	bge_writembx(sc, BGE_MBX_IRQ0_LO, 0);
 
 	/*
 	 * Do the mandatory PCI flush as well as get the link status.
@@ -3545,10 +3690,10 @@
 		return;
 
 	/* Transmit. */
-	CSR_WRITE_4(sc, BGE_MBX_TX_HOST_PROD0_LO, prodidx);
+	bge_writembx(sc, BGE_MBX_TX_HOST_PROD0_LO, prodidx);
 	/* 5700 b2 errata */
 	if (sc->bge_chiprev == BGE_CHIPREV_5700_BX)
-		CSR_WRITE_4(sc, BGE_MBX_TX_HOST_PROD0_LO, prodidx);
+		bge_writembx(sc, BGE_MBX_TX_HOST_PROD0_LO, prodidx);
 
 	sc->bge_tx_prodidx = prodidx;
 
@@ -3675,7 +3820,7 @@
 	if (ifp->if_capenable & IFCAP_POLLING) {
 		BGE_SETBIT(sc, BGE_PCI_MISC_CTL,
 		    BGE_PCIMISCCTL_MASK_PCI_INTR);
-		CSR_WRITE_4(sc, BGE_MBX_IRQ0_LO, 1);
+		bge_writembx(sc, BGE_MBX_IRQ0_LO, 1);
 	} else
 #endif
 
@@ -3683,7 +3828,7 @@
 	{
 	BGE_SETBIT(sc, BGE_PCI_MISC_CTL, BGE_PCIMISCCTL_CLEAR_INTA);
 	BGE_CLRBIT(sc, BGE_PCI_MISC_CTL, BGE_PCIMISCCTL_MASK_PCI_INTR);
-	CSR_WRITE_4(sc, BGE_MBX_IRQ0_LO, 0);
+	bge_writembx(sc, BGE_MBX_IRQ0_LO, 0);
 	}
 	
 	bge_ifmedia_upd_locked(ifp);
@@ -3906,7 +4051,7 @@
 				BGE_LOCK(sc);
 				BGE_SETBIT(sc, BGE_PCI_MISC_CTL,
 				    BGE_PCIMISCCTL_MASK_PCI_INTR);
-				CSR_WRITE_4(sc, BGE_MBX_IRQ0_LO, 1);
+				bge_writembx(sc, BGE_MBX_IRQ0_LO, 1);
 				ifp->if_capenable |= IFCAP_POLLING;
 				BGE_UNLOCK(sc);
 			} else {
@@ -3915,7 +4060,7 @@
 				BGE_LOCK(sc);
 				BGE_CLRBIT(sc, BGE_PCI_MISC_CTL,
 				    BGE_PCIMISCCTL_MASK_PCI_INTR);
-				CSR_WRITE_4(sc, BGE_MBX_IRQ0_LO, 0);
+				bge_writembx(sc, BGE_MBX_IRQ0_LO, 0);
 				ifp->if_capenable &= ~IFCAP_POLLING;
 				BGE_UNLOCK(sc);
 			}
@@ -4040,7 +4185,7 @@
 
 	/* Disable host interrupts. */
 	BGE_SETBIT(sc, BGE_PCI_MISC_CTL, BGE_PCIMISCCTL_MASK_PCI_INTR);
-	CSR_WRITE_4(sc, BGE_MBX_IRQ0_LO, 1);
+	bge_writembx(sc, BGE_MBX_IRQ0_LO, 1);
 
 	/*
 	 * Tell firmware we're shutting down.
@@ -4536,3 +4681,64 @@
 	return (error);
 }
 #endif
+
+static int
+bge_get_eaddr_mem(struct bge_softc *sc, uint8_t ether_addr[])
+{
+	uint32_t mac_addr;
+	int ret = 1;
+
+	mac_addr = bge_readmem_ind(sc, 0x0c14);
+	if ((mac_addr >> 16) == 0x484b) {
+		ether_addr[0] = (uint8_t)(mac_addr >> 8);
+		ether_addr[1] = (uint8_t)mac_addr;
+		mac_addr = bge_readmem_ind(sc, 0x0c18);
+		ether_addr[2] = (uint8_t)(mac_addr >> 24);
+		ether_addr[3] = (uint8_t)(mac_addr >> 16);
+		ether_addr[4] = (uint8_t)(mac_addr >> 8);
+		ether_addr[5] = (uint8_t)mac_addr;
+		ret = 0;
+	}
+	return ret;
+}
+
+static int
+bge_get_eaddr_nvram(struct bge_softc *sc, uint8_t ether_addr[])
+{
+	int mac_offset = BGE_EE_MAC_OFFSET;
+
+	if (sc->bge_asicrev == BGE_ASICREV_BCM5906)
+		mac_offset = BGE_EE_MAC_OFFSET_5906;
+
+	return bge_read_nvram(sc, ether_addr, mac_offset + 2, ETHER_ADDR_LEN);
+}
+
+static int
+bge_get_eaddr_eeprom(struct bge_softc *sc, uint8_t ether_addr[])
+{
+	if (!(sc->bge_flags & BGE_FLAG_EEPROM))
+		return 1;
+
+	return bge_read_eeprom(sc, ether_addr, BGE_EE_MAC_OFFSET + 2,
+			       ETHER_ADDR_LEN);
+}
+
+static int
+bge_get_eaddr(struct bge_softc *sc, uint8_t eaddr[])
+{
+	static const bge_eaddr_fcn_t bge_eaddr_funcs[] = {
+		/* NOTE: Order is critical */
+		bge_get_eaddr_mem,
+		bge_get_eaddr_nvram,
+		bge_get_eaddr_eeprom,
+		NULL
+	};
+	const bge_eaddr_fcn_t *func;
+
+	for (func = bge_eaddr_funcs; *func != NULL; ++func) {
+		if ((*func)(sc, eaddr) == 0)
+			break;
+	}
+	return (*func == NULL ? ENXIO : 0);
+}
+
--- ./sys/dev/bge/if_bgereg.h.orig	2007-05-22 21:22:58.000000000 +0200
+++ ./sys/dev/bge/if_bgereg.h	2008-03-01 14:55:49.000000000 +0100
@@ -283,6 +283,8 @@
 #define	BGE_CHIPID_BCM5787_A0		0xb0000000
 #define	BGE_CHIPID_BCM5787_A1		0xb0010000
 #define	BGE_CHIPID_BCM5787_A2		0xb0020000
+#define	BGE_CHIPID_BCM5906_A1		0xc0010000
+#define	BGE_CHIPID_BCM5906_A2		0xc0020000
 
 /* shorthand one */
 #define	BGE_ASICREV(x)			((x) >> 28)
@@ -299,6 +301,7 @@
 #define	BGE_ASICREV_BCM5755		0x0a
 #define	BGE_ASICREV_BCM5754		0x0b
 #define	BGE_ASICREV_BCM5787		0x0b
+#define	BGE_ASICREV_BCM5906		0x0c
 
 /* chip revisions */
 #define	BGE_CHIPREV(x)			((x) >> 24)
@@ -1438,6 +1441,17 @@
 #define	BGE_RXCPUSTAT_MA_REQ_FIFOOFLOW	0x40000000
 #define	BGE_RXCPUSTAT_BLOCKING_READ	0x80000000
 
+/*
+ * V? CPU registers
+ */
+#define	BGE_VCPU_STATUS			0x5100
+#define	BGE_VCPU_EXT_CTRL		0x6890
+
+#define	BGE_VCPU_STATUS_INIT_DONE	0x04000000
+#define	BGE_VCPU_STATUS_DRV_RESET 	0x08000000
+
+#define	BGE_VCPU_EXT_CTRL_HALT_CPU	0x00400000
+#define	BGE_VCPU_EXT_CTRL_DISABLE_WOL	0x20000000
 
 /*
  * TX CPU registers
@@ -1683,6 +1697,55 @@
 #define	BGE_MDI_CTL			0x6844
 #define	BGE_EE_DELAY			0x6848
 #define	BGE_FASTBOOT_PC			0x6894
+/*
+ * NVRAM Control registers
+ */
+#define	BGE_NVRAM_CMD			0x7000
+#define	BGE_NVRAM_STAT			0x7004
+#define	BGE_NVRAM_WRDATA		0x7008
+#define	BGE_NVRAM_ADDR			0x700c
+#define	BGE_NVRAM_RDDATA		0x7010
+#define	BGE_NVRAM_CFG1			0x7014
+#define	BGE_NVRAM_CFG2			0x7018
+#define	BGE_NVRAM_CFG3			0x701c
+#define	BGE_NVRAM_SWARB			0x7020
+#define	BGE_NVRAM_ACCESS		0x7024
+#define	BGE_NVRAM_WRITE1		0x7028
+
+#define	BGE_NVRAMCMD_RESET		0x00000001
+#define	BGE_NVRAMCMD_DONE		0x00000008
+#define	BGE_NVRAMCMD_START		0x00000010
+#define	BGE_NVRAMCMD_WR			0x00000020 /* 1 = wr, 0 = rd */
+#define	BGE_NVRAMCMD_ERASE		0x00000040
+#define	BGE_NVRAMCMD_FIRST		0x00000080
+#define	BGE_NVRAMCMD_LAST		0x00000100
+
+#define	BGE_NVRAM_READCMD \
+	(BGE_NVRAMCMD_FIRST|BGE_NVRAMCMD_LAST| \
+	BGE_NVRAMCMD_START|BGE_NVRAMCMD_DONE)
+#define	BGE_NVRAM_WRITECMD \
+	(BGE_NVRAMCMD_FIRST|BGE_NVRAMCMD_LAST| \
+	BGE_NVRAMCMD_START|BGE_NVRAMCMD_DONE|BGE_NVRAMCMD_WR)
+
+#define	BGE_NVRAMSWARB_SET0		0x00000001
+#define	BGE_NVRAMSWARB_SET1		0x00000002
+#define	BGE_NVRAMSWARB_SET2		0x00000003
+#define	BGE_NVRAMSWARB_SET3		0x00000004
+#define	BGE_NVRAMSWARB_CLR0		0x00000010
+#define	BGE_NVRAMSWARB_CLR1		0x00000020
+#define	BGE_NVRAMSWARB_CLR2		0x00000040
+#define	BGE_NVRAMSWARB_CLR3		0x00000080
+#define	BGE_NVRAMSWARB_GNT0		0x00000100
+#define	BGE_NVRAMSWARB_GNT1		0x00000200
+#define	BGE_NVRAMSWARB_GNT2		0x00000400
+#define	BGE_NVRAMSWARB_GNT3		0x00000800
+#define	BGE_NVRAMSWARB_REQ0		0x00001000
+#define	BGE_NVRAMSWARB_REQ1		0x00002000
+#define	BGE_NVRAMSWARB_REQ2		0x00004000
+#define	BGE_NVRAMSWARB_REQ3		0x00008000
+
+#define	BGE_NVRAMACC_ENABLE		0x00000001
+#define	BGE_NVRAMACC_WRENABLE		0x00000002
 
 /* Mode control register */
 #define	BGE_MODECTL_INT_SNDCOAL_ONLY	0x00000001
@@ -1711,6 +1774,7 @@
 /* Misc. config register */
 #define	BGE_MISCCFG_RESET_CORE_CLOCKS	0x00000001
 #define	BGE_MISCCFG_TIMER_PRESCALER	0x000000FE
+#define	BGE_MISCCFG_EPHY_IDDQ		0x00200000
 
 #define	BGE_32BITTIME_66MHZ		(0x41 << 1)
 
@@ -2037,6 +2101,8 @@
 #define	BCOM_DEVICEID_BCM5901		0x170D
 #define	BCOM_DEVICEID_BCM5901A2		0x170E
 #define	BCOM_DEVICEID_BCM5903M		0x16FF
+#define	BCOM_DEVICEID_BCM5906		0x1712
+#define	BCOM_DEVICEID_BCM5906M		0x1713
 
 /*
  * Alteon AceNIC PCI vendor/device ID.
@@ -2090,6 +2156,7 @@
  * Offset of MAC address inside EEPROM.
  */
 #define	BGE_EE_MAC_OFFSET		0x7C
+#define	BGE_EE_MAC_OFFSET_5906		0x10
 #define	BGE_EE_HWCFG_OFFSET		0xC8
 
 #define	BGE_HWCFG_VOLTAGE		0x00000003
@@ -2474,6 +2541,7 @@
 #define	BGE_FLAG_BER_BUG	0x02000000
 #define	BGE_FLAG_ADJUST_TRIM	0x04000000
 #define	BGE_FLAG_CRC_BUG	0x08000000
+#define	BGE_FLAG_NO_EEPROM	0x10000000
 	uint32_t		bge_chipid;
 	uint8_t			bge_asicrev;
 	uint8_t			bge_chiprev;
--- ./sys/dev/mii/brgphy.c.70	2008-03-01 14:54:58.000000000 +0100
+++ ./sys/dev/mii/brgphy.c	2008-03-01 14:55:49.000000000 +0100
@@ -131,6 +131,7 @@
 	MII_PHY_DESC(xxBROADCOM_ALT1, BCM5755),
 	MII_PHY_DESC(xxBROADCOM_ALT1, BCM5787),
 	MII_PHY_DESC(xxBROADCOM_ALT1, BCM5708S),
+	MII_PHY_DESC(BROADCOM2, BCM5906),
 	MII_PHY_END
 };
 
@@ -186,6 +187,7 @@
 	/* Handle any special cases based on the PHY ID */
 	switch (bsc->mii_oui) {
 	case MII_OUI_BROADCOM: 
+	case MII_OUI_BROADCOM2: 
 		break;
 	case MII_OUI_xxBROADCOM:
 		switch (bsc->mii_model) {
@@ -226,12 +228,14 @@
 		bce_sc = ifp->if_softc;
 	}
 
-	/* Todo: Need to add additional controllers such as 5906 & 5787F */
+	/* Todo: Need to add additional controllers such as 5787F */
 	/* The 590x chips are 10/100 only. */
 	if (bge_sc &&
 	    pci_get_vendor(bge_sc->bge_dev) == BCOM_VENDORID &&
 	    (pci_get_device(bge_sc->bge_dev) == BCOM_DEVICEID_BCM5901 ||
-	    pci_get_device(bge_sc->bge_dev) == BCOM_DEVICEID_BCM5901A2)) {
+	     pci_get_device(bge_sc->bge_dev) == BCOM_DEVICEID_BCM5901A2 ||
+	     pci_get_device(bge_sc->bge_dev) == BCOM_DEVICEID_BCM5906 ||
+	     pci_get_device(bge_sc->bge_dev) == BCOM_DEVICEID_BCM5906M)) {
 		fast_ether = 1;
 		sc->mii_anegticks = MII_ANEGTICKS;
 	}
@@ -930,6 +934,11 @@
 			    PHY_READ(sc, BRGPHY_MII_PHY_EXTCTL) &
 			    ~BRGPHY_PHY_EXTCTL_3_LED);
 		}
+
+		/* Adjust output voltage (From Linux driver) */
+		if (bge_sc->bge_asicrev == BGE_ASICREV_BCM5906)
+			PHY_WRITE(sc, BRGPHY_MII_EPHY_PTEST, 0x12);
+
 	/* Handle any bce (NetXtreme II) workarounds. */
 	} else if (bce_sc) {
 
--- ./sys/dev/mii/brgphyreg.h.70	2008-03-01 14:55:05.000000000 +0100
+++ ./sys/dev/mii/brgphyreg.h	2008-03-01 14:55:49.000000000 +0100
@@ -161,6 +161,7 @@
 #define	BRGPHY_MII_DSP_RW_PORT	0x15	/* DSP coefficient r/w port */
 
 #define	BRGPHY_MII_DSP_ADDR_REG	0x17	/* DSP coefficient addr register */
+#define BRGPHY_MII_EPHY_PTEST	0x17	/* 5906 PHY register */
 
 #define	BRGPHY_DSP_TAP_NUMBER_MASK		0x00
 #define	BRGPHY_DSP_AGC_A			0x00
--- ./sys/dev/mii/miidevs.orig	2007-11-05 02:42:02.000000000 +0100
+++ ./sys/dev/mii/miidevs	2008-03-01 14:55:49.000000000 +0100
@@ -52,6 +52,7 @@
 oui ALTIMA			0x0010a9	Altima Communications
 oui AMD				0x00001a	Advanced Micro Devices
 oui BROADCOM			0x001018	Broadcom Corporation
+oui BROADCOM2			0x000af7	Broadcom Corporation
 oui CICADA			0x0003F1	Cicada Semiconductor
 oui DAVICOM			0x00606e	Davicom Semiconductor
 oui ICPLUS			0x0090c3	IC Plus Corp.
@@ -135,6 +136,7 @@
 model xxBROADCOM_ALT1 BCM5755	0x000c BCM5755 10/100/1000baseTX PHY
 model xxBROADCOM_ALT1 BCM5787	0x000e BCM5787 10/100/1000baseTX PHY
 model xxBROADCOM_ALT1 BCM5708S	0x0015 BCM5708S 1000/2500BaseSX PHY
+model BROADCOM2 BCM5906		0x0004 BCM5906 10/100baseTX PHY
 
 /* Cicada Semiconductor PHYs (now owned by Vitesse?) */
 model CICADA CS8201		0x0001 Cicada CS8201 10/100/1000TX PHY
