aboutsummaryrefslogtreecommitdiff
path: root/sys/dev/bge
diff options
context:
space:
mode:
authorJohn Baldwin <jhb@FreeBSD.org>2008-06-27 03:24:54 +0000
committerJohn Baldwin <jhb@FreeBSD.org>2008-06-27 03:24:54 +0000
commite993131e96054daa810005927312af35e06e7350 (patch)
treedae34b15f8e6765b51e0a3c5cdcd4e311124c9fa /sys/dev/bge
parentf1e822e26b988ca7a77647c6275e0663f6827ce1 (diff)
Notes
Diffstat (limited to 'sys/dev/bge')
-rw-r--r--sys/dev/bge/if_bge.c397
-rw-r--r--sys/dev/bge/if_bgereg.h70
2 files changed, 371 insertions, 96 deletions
diff --git a/sys/dev/bge/if_bge.c b/sys/dev/bge/if_bge.c
index b53d771ec777..6af25a2c8abc 100644
--- a/sys/dev/bge/if_bge.c
+++ b/sys/dev/bge/if_bge.c
@@ -196,6 +196,8 @@ static struct bge_type {
{ 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 },
@@ -273,6 +275,8 @@ static const struct bge_revision {
{ 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 }
};
@@ -295,6 +299,7 @@ static const struct bge_revision bge_majorrevs[] = {
{ 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 }
};
@@ -307,6 +312,9 @@ static const struct bge_revision bge_majorrevs[] = {
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);
@@ -317,6 +325,12 @@ static void bge_dma_map_addr(void *, bus_dma_segment_t *, int, int);
static int bge_dma_alloc(device_t);
static void bge_dma_free(struct bge_softc *);
+static int bge_get_eaddr_fw(struct bge_softc *sc, uint8_t ether_addr[]);
+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 *);
@@ -339,6 +353,9 @@ static int bge_ifmedia_upd_locked(struct ifnet *);
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);
@@ -358,9 +375,10 @@ static int bge_init_tx_ring(struct bge_softc *);
static int bge_chipinit(struct bge_softc *);
static int bge_blockinit(struct bge_softc *);
-static int bge_has_eeprom(struct bge_softc *);
+static int bge_has_eaddr(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
@@ -442,7 +460,7 @@ SYSCTL_INT(_hw_bge, OID_AUTO, allow_asf, CTLFLAG_RD, &bge_allow_asf, 0,
#define SPARC64_OFW_SUBVENDOR "subsystem-vendor-id"
static int
-bge_has_eeprom(struct bge_softc *sc)
+bge_has_eaddr(struct bge_softc *sc)
{
#ifdef __sparc64__
char buf[sizeof(SPARC64_BLADE_1500_PATH_BGE)];
@@ -454,7 +472,7 @@ bge_has_eeprom(struct bge_softc *sc)
/*
* The on-board BGEs found in sun4u machines aren't fitted with
* an EEPROM which means that we have to obtain the MAC address
- * via OFW and that some tests will always fail. We distinguish
+ * via OFW and that some tests will always fail. We distinguish
* such BGEs by the subvendor ID, which also has to be obtained
* from OFW instead of the PCI configuration space as the latter
* indicates Broadcom as the subvendor of the netboot interface.
@@ -535,6 +553,15 @@ bge_writemem_direct(struct bge_softc *sc, int off, int val)
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.
*/
@@ -557,6 +584,78 @@ bge_dma_map_addr(void *arg, bus_dma_segment_t *segs, int nseg, int error)
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
@@ -661,11 +760,14 @@ bge_miibus_readreg(device_t dev, int phy, int reg)
}
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:
@@ -689,6 +791,10 @@ bge_miibus_writereg(device_t dev, int phy, int reg, int val)
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) {
@@ -701,12 +807,17 @@ bge_miibus_writereg(device_t dev, int phy, int reg, int val)
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);
}
@@ -889,7 +1000,7 @@ bge_init_rx_ring_std(struct bge_softc *sc)
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);
}
@@ -936,7 +1047,7 @@ bge_init_rx_ring_jumbo(struct bge_softc *sc)
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);
}
@@ -992,17 +1103,17 @@ bge_init_tx_ring(struct bge_softc *sc)
/* 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);
}
@@ -1170,10 +1281,10 @@ bge_chipinit(struct bge_softc *sc)
/*
* Check the 'ROM failed' bit on the RX CPU to see if
* self-tests passed. Skip this check when there's no
- * EEPROM fitted, since in that case it will always
- * fail.
+ * chip containing the Ethernet address fitted, since
+ * in that case it will always fail.
*/
- if ((sc->bge_flags & BGE_FLAG_EEPROM) &&
+ if ((sc->bge_flags & BGE_FLAG_EADDR) &&
CSR_READ_4(sc, BGE_RXCPU_MODE) & BGE_RXCPUMODE_ROMFAIL) {
device_printf(sc->bge_dev, "RX CPU self-diagnostics failed!\n");
return (ENODEV);
@@ -1273,6 +1384,16 @@ bge_chipinit(struct bge_softc *sc)
/* Set the timer prescaler (always 66Mhz) */
CSR_WRITE_4(sc, BGE_MISC_CFG, BGE_32BITTIME_66MHZ);
+ /* XXX: The Linux tg3 driver does this at the start of brgphy_reset. */
+ 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);
}
@@ -1310,14 +1431,19 @@ bge_blockinit(struct bge_softc *sc)
}
/* 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);
@@ -1423,6 +1549,9 @@ bge_blockinit(struct bge_softc *sc)
* requirement of all 575x family chips. The Linux driver sets
* the lower threshold for all 5705 family chips as well, but there
* are reports that it might not need to be so strict.
+ *
+ * XXX Linux does some extra fiddling here for the 5906 parts as
+ * well.
*/
if (BGE_IS_5705_PLUS(sc))
val = 8;
@@ -1464,15 +1593,15 @@ bge_blockinit(struct bge_softc *sc)
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
@@ -2225,7 +2354,6 @@ bge_attach(device_t dev)
{
struct ifnet *ifp;
struct bge_softc *sc;
- uint32_t mac_tmp = 0;
uint32_t hwcfg = 0, misccfg;
u_char eaddr[ETHER_ADDR_LEN];
int error, reg, rid, trys;
@@ -2260,16 +2388,17 @@ bge_attach(device_t dev)
sc->bge_chiprev = BGE_CHIPREV(sc->bge_chipid);
/*
- * Don't enable Ethernet@WireSpeed for the 5700 or the
+ * Don't enable Ethernet@WireSpeed for the 5700, 5906, or the
* 5705 A0 and A1 chips.
*/
if (sc->bge_asicrev != BGE_ASICREV_BCM5700 &&
+ sc->bge_asicrev != BGE_ASICREV_BCM5906 &&
sc->bge_chipid != BGE_CHIPID_BCM5705_A0 &&
sc->bge_chipid != BGE_CHIPID_BCM5705_A1)
sc->bge_flags |= BGE_FLAG_WIRESPEED;
- if (bge_has_eeprom(sc))
- sc->bge_flags |= BGE_FLAG_EEPROM;
+ if (bge_has_eaddr(sc))
+ sc->bge_flags |= BGE_FLAG_EADDR;
/* Save chipset family. */
switch (sc->bge_asicrev) {
@@ -2288,6 +2417,7 @@ bge_attach(device_t dev)
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:
@@ -2310,7 +2440,7 @@ bge_attach(device_t dev)
sc->bge_asicrev == BGE_ASICREV_BCM5787) {
if (sc->bge_chipid != BGE_CHIPID_BCM5722_A0)
sc->bge_flags |= BGE_FLAG_JITTER_BUG;
- } else
+ } else if (sc->bge_asicrev != BGE_ASICREV_BCM5906)
sc->bge_flags |= BGE_FLAG_BER_BUG;
}
@@ -2430,28 +2560,12 @@ bge_attach(device_t dev)
goto fail;
}
-#ifdef __sparc64__
- if ((sc->bge_flags & BGE_FLAG_EEPROM) == 0)
- 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)) {
- device_printf(sc->bge_dev,
- "failed to read station address\n");
- error = ENXIO;
- goto fail;
- }
+ error = bge_get_eaddr(sc, eaddr);
+ if (error) {
+ device_printf(sc->bge_dev,
+ "failed to read station address\n");
+ error = ENXIO;
+ goto fail;
}
/* 5705 limits RX return ring to 512 entries. */
@@ -2523,7 +2637,8 @@ bge_attach(device_t dev)
*/
if (bge_readmem_ind(sc, BGE_SOFTWARE_GENCOMM_SIG) == BGE_MAGIC_NUMBER)
hwcfg = bge_readmem_ind(sc, BGE_SOFTWARE_GENCOMM_NICCFG);
- else if (sc->bge_flags & BGE_FLAG_EEPROM) {
+ else if ((sc->bge_flags & BGE_FLAG_EADDR) &&
+ (sc->bge_asicrev != BGE_ASICREV_BCM5906)) {
if (bge_read_eeprom(sc, (caddr_t)&hwcfg, BGE_EE_HWCFG_OFFSET,
sizeof(hwcfg))) {
device_printf(sc->bge_dev, "failed to read EEPROM\n");
@@ -2698,13 +2813,14 @@ static int
bge_reset(struct bge_softc *sc)
{
device_t dev;
- uint32_t cachesize, command, pcistate, reset;
+ uint32_t cachesize, command, pcistate, reset, val;
void (*write_op)(struct bge_softc *, int, int);
- int i, val = 0;
+ int i;
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
@@ -2760,16 +2876,23 @@ bge_reset(struct bge_softc *sc)
/* Issue global reset */
write_op(sc, BGE_MISC_CFG, reset);
+ if (sc->bge_asicrev == BGE_ASICREV_BCM5906) {
+ val = CSR_READ_4(sc, BGE_VCPU_STATUS);
+ CSR_WRITE_4(sc, BGE_VCPU_STATUS,
+ val | BGE_VCPU_STATUS_DRV_RESET);
+ val = CSR_READ_4(sc, BGE_VCPU_EXT_CTRL);
+ CSR_WRITE_4(sc, BGE_VCPU_EXT_CTRL,
+ val & ~BGE_VCPU_EXT_CTRL_HALT_CPU);
+ }
+
DELAY(1000);
/* XXX: Broadcom Linux driver. */
if (sc->bge_flags & BGE_FLAG_PCIE) {
if (sc->bge_chipid == BGE_CHIPID_BCM5750_A0) {
- uint32_t v;
-
DELAY(500000); /* wait for link training to complete */
- v = pci_read_config(dev, 0xC4, 4);
- pci_write_config(dev, 0xC4, v | (1 << 15), 4);
+ val = pci_read_config(dev, 0xC4, 4);
+ pci_write_config(dev, 0xC4, val | (1 << 15), 4);
}
/*
* Set PCIE max payload size to 128 bytes and clear error
@@ -2788,8 +2911,6 @@ bge_reset(struct bge_softc *sc)
/* Re-enable MSI, if neccesary, and enable the memory arbiter. */
if (BGE_IS_5714_FAMILY(sc)) {
- uint32_t val;
-
/* This chip disables MSI on reset. */
if (sc->bge_flags & BGE_FLAG_MSI) {
val = pci_read_config(dev, BGE_PCI_MSI_CTL, 2);
@@ -2804,21 +2925,35 @@ bge_reset(struct bge_softc *sc)
} 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 chip containing the Ethernet
+ * address 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_EADDR) && 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
@@ -2856,20 +2991,16 @@ bge_reset(struct bge_softc *sc)
*/
if (sc->bge_asicrev == BGE_ASICREV_BCM5704 &&
sc->bge_flags & BGE_FLAG_TBI) {
- uint32_t serdescfg;
-
- serdescfg = CSR_READ_4(sc, BGE_SERDES_CFG);
- serdescfg = (serdescfg & ~0xFFF) | 0x880;
- CSR_WRITE_4(sc, BGE_SERDES_CFG, serdescfg);
+ val = CSR_READ_4(sc, BGE_SERDES_CFG);
+ val = (val & ~0xFFF) | 0x880;
+ CSR_WRITE_4(sc, BGE_SERDES_CFG, val);
}
/* XXX: Broadcom Linux driver. */
if (sc->bge_flags & BGE_FLAG_PCIE &&
sc->bge_chipid != BGE_CHIPID_BCM5750_A0) {
- uint32_t v;
-
- v = CSR_READ_4(sc, 0x7C00);
- CSR_WRITE_4(sc, 0x7C00, v | (1 << 25));
+ val = CSR_READ_4(sc, 0x7C00);
+ CSR_WRITE_4(sc, 0x7C00, val | (1 << 25));
}
DELAY(10000);
@@ -3038,11 +3169,11 @@ bge_rxeof(struct bge_softc *sc)
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.
@@ -3184,7 +3315,7 @@ bge_intr(void *xsc)
* 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.
@@ -3565,10 +3696,10 @@ bge_start_locked(struct ifnet *ifp)
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;
@@ -3695,7 +3826,7 @@ bge_init_locked(struct bge_softc *sc)
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
@@ -3703,7 +3834,7 @@ bge_init_locked(struct bge_softc *sc)
{
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);
@@ -3944,7 +4075,7 @@ bge_ioctl(struct ifnet *ifp, u_long command, caddr_t data)
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 {
@@ -3953,7 +4084,7 @@ bge_ioctl(struct ifnet *ifp, u_long command, caddr_t data)
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);
}
@@ -4078,7 +4209,7 @@ bge_stop(struct bge_softc *sc)
/* 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.
@@ -4574,3 +4705,79 @@ bge_sysctl_mem_read(SYSCTL_HANDLER_ARGS)
return (error);
}
#endif
+
+static int
+bge_get_eaddr_fw(struct bge_softc *sc, uint8_t ether_addr[])
+{
+
+ if (sc->bge_flags & BGE_FLAG_EADDR)
+ return (1);
+
+#ifdef __sparc64__
+ OF_getetheraddr(sc->bge_dev, ether_addr);
+ return (0);
+#endif
+ return (1);
+}
+
+static int
+bge_get_eaddr_mem(struct bge_softc *sc, uint8_t ether_addr[])
+{
+ uint32_t mac_addr;
+
+ 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;
+ return (0);
+ }
+ return (1);
+}
+
+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_asicrev == BGE_ASICREV_BCM5906)
+ 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_fw,
+ 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);
+}
diff --git a/sys/dev/bge/if_bgereg.h b/sys/dev/bge/if_bgereg.h
index 09a28e26d321..4e1980c2012f 100644
--- a/sys/dev/bge/if_bgereg.h
+++ b/sys/dev/bge/if_bgereg.h
@@ -284,6 +284,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)
@@ -300,6 +302,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)
@@ -1439,6 +1442,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
@@ -1685,6 +1699,56 @@
#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
#define BGE_MODECTL_BYTESWAP_NONFRAME 0x00000002
@@ -1715,6 +1779,7 @@
#define BGE_MISCCFG_BOARD_ID 0x0001E000
#define BGE_MISCCFG_BOARD_ID_5788 0x00010000
#define BGE_MISCCFG_BOARD_ID_5788M 0x00018000
+#define BGE_MISCCFG_EPHY_IDDQ 0x00200000
#define BGE_32BITTIME_66MHZ (0x41 << 1)
@@ -2042,6 +2107,8 @@ struct bge_status_block {
#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.
@@ -2095,6 +2162,7 @@ struct bge_status_block {
* 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
@@ -2464,7 +2532,7 @@ struct bge_softc {
#define BGE_FLAG_TBI 0x00000001
#define BGE_FLAG_JUMBO 0x00000002
#define BGE_FLAG_WIRESPEED 0x00000004
-#define BGE_FLAG_EEPROM 0x00000008
+#define BGE_FLAG_EADDR 0x00000008
#define BGE_FLAG_MSI 0x00000100
#define BGE_FLAG_PCIX 0x00000200
#define BGE_FLAG_PCIE 0x00000400