summaryrefslogtreecommitdiffstats
path: root/sys
diff options
context:
space:
mode:
authorscottl <scottl@FreeBSD.org>2006-12-12 05:11:12 +0000
committerscottl <scottl@FreeBSD.org>2006-12-12 05:11:12 +0000
commitfec8d2cf34e67f0b3928b1d0e160fa9cda4ab1fc (patch)
tree874ac79112ff4b01d6c87a72ccda9b5dce100244 /sys
parentc75a3f1632f68021e1f0c1f2ff7b596324d1e55c (diff)
downloadFreeBSD-src-fec8d2cf34e67f0b3928b1d0e160fa9cda4ab1fc.zip
FreeBSD-src-fec8d2cf34e67f0b3928b1d0e160fa9cda4ab1fc.tar.gz
Fix support for certain 575x/578x chips. This consists of the following:
- Use the appropriate register writing method when reseting the chip - Program the descriptor DMA engine correctly. - More reliably detect certain chips and their features. Also add some low-level debugging tools to help future work on this driver. Submitted by: David Christenson (proof of concept changes) Sponsored by: www.UIA.net
Diffstat (limited to 'sys')
-rw-r--r--sys/dev/bge/if_bge.c298
-rw-r--r--sys/dev/bge/if_bgereg.h11
2 files changed, 274 insertions, 35 deletions
diff --git a/sys/dev/bge/if_bge.c b/sys/dev/bge/if_bge.c
index a861b3b..e7ec011 100644
--- a/sys/dev/bge/if_bge.c
+++ b/sys/dev/bge/if_bge.c
@@ -256,6 +256,10 @@ static const struct bge_revision {
{ BGE_CHIPID_BCM5714_B3, "BCM5714 B3" },
{ BGE_CHIPID_BCM5715_A0, "BCM5715 A0" },
{ BGE_CHIPID_BCM5715_A1, "BCM5715 A1" },
+ /* 5784 and 5787 share the same ASIC ID */
+ { BGE_CHIPID_BCM5787_A0, "BCM5754/5787 A0" },
+ { BGE_CHIPID_BCM5787_A1, "BCM5754/5787 A1" },
+ { BGE_CHIPID_BCM5787_A2, "BCM5754/5787 A2" },
{ 0, NULL }
};
@@ -276,7 +280,8 @@ static const struct bge_revision bge_majorrevs[] = {
{ BGE_ASICREV_BCM5780, "unknown BCM5780" },
{ BGE_ASICREV_BCM5714, "unknown BCM5714" },
{ BGE_ASICREV_BCM5755, "unknown BCM5755" },
- { BGE_ASICREV_BCM5787, "unknown BCM5787" },
+ /* 5784 and 5787 share the same ASIC ID */
+ { BGE_ASICREV_BCM5787, "unknown BCM5754/5787" },
{ 0, NULL }
};
@@ -345,6 +350,7 @@ static void bge_writemem_ind(struct bge_softc *, int, int);
static uint32_t bge_readreg_ind(struct bge_softc *, int);
#endif
static void bge_writereg_ind(struct bge_softc *, int, int);
+static void bge_writemem_direct(struct bge_softc *, int, int) __unused;
static int bge_miibus_readreg(device_t, int, int);
static int bge_miibus_writereg(device_t, int, int, int);
@@ -361,6 +367,18 @@ static void bge_sig_pre_reset(struct bge_softc *, int);
static int bge_reset(struct bge_softc *);
static void bge_link_upd(struct bge_softc *);
+/*
+ * The BGE_REGISTER_DEBUG option is only for low-level debugging. It may
+ * leak information to untrusted users. It is also known to cause alignment
+ * traps on certain architectures.
+ */
+#ifdef BGE_REGISTER_DEBUG
+static int bge_sysctl_debug_info(SYSCTL_HANDLER_ARGS);
+static int bge_sysctl_reg_read(SYSCTL_HANDLER_ARGS);
+static int bge_sysctl_mem_read(SYSCTL_HANDLER_ARGS);
+#endif
+static void bge_add_sysctls(struct bge_softc *);
+
static device_method_t bge_methods[] = {
/* Device interface */
DEVMETHOD(device_probe, bge_probe),
@@ -409,11 +427,14 @@ static uint32_t
bge_readmem_ind(struct bge_softc *sc, int off)
{
device_t dev;
+ uint32_t val;
dev = sc->bge_dev;
pci_write_config(dev, BGE_PCI_MEMWIN_BASEADDR, off, 4);
- return (pci_read_config(dev, BGE_PCI_MEMWIN_DATA, 4));
+ val = pci_read_config(dev, BGE_PCI_MEMWIN_DATA, 4);
+ pci_write_config(dev, BGE_PCI_MEMWIN_BASEADDR, 0, 4);
+ return (val);
}
static void
@@ -425,6 +446,7 @@ bge_writemem_ind(struct bge_softc *sc, int off, int val)
pci_write_config(dev, BGE_PCI_MEMWIN_BASEADDR, off, 4);
pci_write_config(dev, BGE_PCI_MEMWIN_DATA, val, 4);
+ pci_write_config(dev, BGE_PCI_MEMWIN_BASEADDR, 0, 4);
}
#ifdef notdef
@@ -451,6 +473,12 @@ bge_writereg_ind(struct bge_softc *sc, int off, int val)
pci_write_config(dev, BGE_PCI_REG_DATA, val, 4);
}
+static void
+bge_writemem_direct(struct bge_softc *sc, int off, int val)
+{
+ CSR_WRITE_4(sc, off, val);
+}
+
/*
* Map a single buffer address.
*/
@@ -1193,6 +1221,7 @@ bge_blockinit(struct bge_softc *sc)
struct bge_rcb *rcb;
bus_size_t vrcb;
bge_hostaddr taddr;
+ uint32_t val;
int i;
/*
@@ -1330,7 +1359,12 @@ bge_blockinit(struct bge_softc *sc)
* values are 1/8th the number of descriptors allocated to
* each ring.
*/
- CSR_WRITE_4(sc, BGE_RBDI_STD_REPL_THRESH, BGE_STD_RX_RING_CNT/8);
+ if (sc->bge_flags & BGE_FLAG_5705_PLUS)
+ val = 8;
+ else
+ val = BGE_STD_RX_RING_CNT / 8;
+
+ CSR_WRITE_4(sc, BGE_RBDI_STD_REPL_THRESH, val);
CSR_WRITE_4(sc, BGE_RBDI_JUMBO_REPL_THRESH, BGE_JUMBO_RX_RING_CNT/8);
/*
@@ -1500,9 +1534,16 @@ bge_blockinit(struct bge_softc *sc)
if (!(BGE_IS_5705_PLUS(sc)))
CSR_WRITE_4(sc, BGE_DMAC_MODE, BGE_DMACMODE_ENABLE);
+
+ val = BGE_WDMAMODE_ENABLE|BGE_WDMAMODE_ALL_ATTNS;
+
+ /* Enable host coalescing bug fix. */
+ if (sc->bge_asicrev == BGE_ASICREV_BCM5755 ||
+ sc->bge_asicrev == BGE_ASICREV_BCM5787)
+ val |= (1 << 29);
+
/* Turn on write DMA state machine */
- CSR_WRITE_4(sc, BGE_WDMA_MODE,
- BGE_WDMAMODE_ENABLE|BGE_WDMAMODE_ALL_ATTNS);
+ CSR_WRITE_4(sc, BGE_WDMA_MODE, val);
/* Turn on read DMA state machine */
CSR_WRITE_4(sc, BGE_RDMA_MODE,
@@ -2071,7 +2112,7 @@ bge_attach(device_t dev)
uint32_t mac_tmp = 0;
u_char eaddr[6];
int error = 0, rid;
- int trys;
+ int trys, reg;
sc = device_get_softc(dev);
sc->bge_dev = dev;
@@ -2143,27 +2184,37 @@ bge_attach(device_t dev)
break;
}
- /*
- * XXX: Broadcom Linux driver. Not in specs or eratta.
- * PCI-Express?
- */
- if (BGE_IS_5705_PLUS(sc)) {
- uint32_t v;
-
- v = pci_read_config(dev, BGE_PCI_MSI_CAPID, 4);
- if (((v >> 8) & 0xff) == BGE_PCIE_CAPID_REG) {
- v = pci_read_config(dev, BGE_PCIE_CAPID_REG, 4);
- if ((v & 0xff) == BGE_PCIE_CAPID)
- sc->bge_flags |= BGE_FLAG_PCIE;
- }
+ /*
+ * Check if this is a PCI-X or PCI Express device.
+ */
+#if __FreeBSD_version > 700010
+ if (pci_find_extcap(dev, PCIY_EXPRESS, &reg) == 0) {
+ /*
+ * Found a PCI Express capabilities register, this
+ * must be a PCI Express device.
+ */
+ if (reg != 0)
+ sc->bge_flags |= BGE_FLAG_PCIE;
+ } else if (pci_find_extcap(dev, PCIY_PCIX, &reg) == 0) {
+ if (reg != 0)
+ sc->bge_flags |= BGE_FLAG_PCIX;
}
-
- /*
- * PCI-X ?
- */
- if ((pci_read_config(sc->bge_dev, BGE_PCI_PCISTATE, 4) &
- BGE_PCISTATE_PCI_BUSMODE) == 0)
- sc->bge_flags |= BGE_FLAG_PCIX;
+
+#else
+ if (sc->bge_flags & BGE_FLAG_5705_PLUS) {
+ reg = pci_read_config(dev, BGE_PCIE_CAPID_REG, 4);
+ if ((reg & 0xff) == BGE_PCIE_CAPID)
+ sc->bge_flags |= BGE_FLAG_PCIE;
+ } else {
+ /*
+ * Check if the device is in PCI-X Mode.
+ * (This bit is not valid on PCI Express controllers.)
+ */
+ if ((pci_read_config(sc->bge_dev, BGE_PCI_PCISTATE, 4) &
+ BGE_PCISTATE_PCI_BUSMODE) == 0)
+ sc->bge_flags |= BGE_FLAG_PCIX;
+ }
+#endif
/* Try to reset the chip. */
if (bge_reset(sc)) {
@@ -2244,8 +2295,8 @@ bge_attach(device_t dev)
sc->bge_stat_ticks = BGE_TICKS_PER_SEC;
sc->bge_rx_coal_ticks = 150;
sc->bge_tx_coal_ticks = 150;
- sc->bge_rx_max_coal_bds = 64;
- sc->bge_tx_max_coal_bds = 128;
+ sc->bge_rx_max_coal_bds = 10;
+ sc->bge_tx_max_coal_bds = 10;
/* Set up ifnet structure */
ifp = sc->bge_ifp = if_alloc(IFT_ETHER);
@@ -2384,6 +2435,8 @@ again:
device_printf(sc->bge_dev, "couldn't set up irq\n");
}
+ bge_add_sysctls(sc);
+
fail:
return (error);
}
@@ -2458,10 +2511,19 @@ bge_reset(struct bge_softc *sc)
{
device_t dev;
uint32_t cachesize, command, pcistate, reset;
+ void (*write_op)(struct bge_softc *, int, int);
int i, val = 0;
dev = sc->bge_dev;
+ if (BGE_IS_5705_PLUS(sc) && !BGE_IS_5714_FAMILY(sc))
+ if (sc->bge_flags & BGE_FLAG_PCIE)
+ write_op = bge_writemem_direct;
+ else
+ write_op = bge_writemem_ind;
+ else
+ write_op = bge_writereg_ind;
+
/* Save some important PCI state. */
cachesize = pci_read_config(dev, BGE_PCI_CACHESZ, 4);
command = pci_read_config(dev, BGE_PCI_CMD, 4);
@@ -2471,6 +2533,23 @@ bge_reset(struct bge_softc *sc)
BGE_PCIMISCCTL_INDIRECT_ACCESS|BGE_PCIMISCCTL_MASK_PCI_INTR|
BGE_HIF_SWAP_OPTIONS|BGE_PCIMISCCTL_PCISTATE_RW, 4);
+ /* Disable fastboot on controllers that support it. */
+ if (sc->bge_asicrev == BGE_ASICREV_BCM5752 ||
+ sc->bge_asicrev == BGE_ASICREV_BCM5755 ||
+ sc->bge_asicrev == BGE_ASICREV_BCM5787) {
+ if (bootverbose)
+ device_printf(sc->bge_dev, "%s: Disabling fastboot\n",
+ __FUNCTION__);
+ CSR_WRITE_4(sc, BGE_FASTBOOT_PC, 0x0);
+ }
+
+ /*
+ * Write the magic number to SRAM at offset 0xB50.
+ * When firmware finishes its initialization it will
+ * write ~BGE_MAGIC_NUMBER to the same location.
+ */
+ bge_writemem_ind(sc, BGE_SOFTWARE_GENCOMM, BGE_MAGIC_NUMBER);
+
reset = BGE_MISCCFG_RESET_CORE_CLOCKS|(65<<1);
/* XXX: Broadcom Linux driver. */
@@ -2490,8 +2569,15 @@ bge_reset(struct bge_softc *sc)
*/
bge_writemem_ind(sc, BGE_SOFTWARE_GENCOMM, BGE_MAGIC_NUMBER);
+ /*
+ * Set GPHY Power Down Override to leave GPHY
+ * powered up in D0 uninitialized.
+ */
+ if (sc->bge_flags & BGE_FLAG_5705_PLUS)
+ reset |= 0x04000000;
+
/* Issue global reset */
- bge_writereg_ind(sc, BGE_MISC_CFG, reset);
+ write_op(sc, BGE_MISC_CFG, reset);
DELAY(1000);
@@ -2504,7 +2590,7 @@ bge_reset(struct bge_softc *sc)
v = pci_read_config(dev, 0xc4, 4);
pci_write_config(dev, 0xc4, v | (1<<15), 4);
}
- /* Set PCIE max payload size and clear error status. */
+ /* Set PCIE max payload size to 128 bytes and clear error status. */
pci_write_config(dev, 0xd8, 0xf5000, 4);
}
@@ -2514,7 +2600,7 @@ bge_reset(struct bge_softc *sc)
BGE_HIF_SWAP_OPTIONS|BGE_PCIMISCCTL_PCISTATE_RW, 4);
pci_write_config(dev, BGE_PCI_CACHESZ, cachesize, 4);
pci_write_config(dev, BGE_PCI_CMD, command, 4);
- bge_writereg_ind(sc, BGE_MISC_CFG, (65 << 1));
+ write_op(sc, BGE_MISC_CFG, (65 << 1));
/* Enable memory arbiter. */
if (BGE_IS_5714_FAMILY(sc)) {
@@ -2526,8 +2612,7 @@ bge_reset(struct bge_softc *sc)
CSR_WRITE_4(sc, BGE_MARB_MODE, BGE_MARBMODE_ENABLE);
/*
- * Poll the value location we just wrote until
- * we see the 1's complement of the magic number.
+ * Poll until we see the 1's complement of the magic number.
* This indicates that the firmware initialization
* is complete.
*/
@@ -2539,8 +2624,8 @@ bge_reset(struct bge_softc *sc)
}
if (i == BGE_TIMEOUT) {
- device_printf(sc->bge_dev, "firmware handshake timed out\n");
- return(0);
+ device_printf(sc->bge_dev, "firmware handshake timed out! "
+ "found 0x%08X\n", val);
}
/*
@@ -2557,6 +2642,11 @@ bge_reset(struct bge_softc *sc)
DELAY(10);
}
+ if (sc->bge_flags & BGE_FLAG_PCIE) {
+ reset = bge_readmem_ind(sc, 0x7c00);
+ bge_writemem_ind(sc, 0x7c00, reset | (1 << 25));
+ }
+
/* Fix up byte swapping. */
CSR_WRITE_4(sc, BGE_MODE_CTL, BGE_DMA_SWAP_OPTIONS|
BGE_MODECTL_BYTESWAP_DATA);
@@ -3947,3 +4037,141 @@ bge_link_upd(struct bge_softc *sc)
BGE_MACSTAT_CFG_CHANGED|BGE_MACSTAT_MI_COMPLETE|
BGE_MACSTAT_LINK_CHANGED);
}
+
+static void
+bge_add_sysctls(struct bge_softc *sc)
+{
+ struct sysctl_ctx_list *ctx;
+ struct sysctl_oid_list *children;
+
+ ctx = device_get_sysctl_ctx(sc->bge_dev);
+ children = SYSCTL_CHILDREN(device_get_sysctl_tree(sc->bge_dev));
+
+#ifdef BGE_REGISTER_DEBUG
+ SYSCTL_ADD_PROC(ctx, children, OID_AUTO, "debug_info",
+ CTLTYPE_INT | CTLFLAG_RW, sc, 0, bge_sysctl_debug_info, "I",
+ "Debug Information");
+
+ SYSCTL_ADD_PROC(ctx, children, OID_AUTO, "reg_read",
+ CTLTYPE_INT | CTLFLAG_RW, sc, 0, bge_sysctl_reg_read, "I",
+ "Register Read");
+
+ SYSCTL_ADD_PROC(ctx, children, OID_AUTO, "mem_read",
+ CTLTYPE_INT | CTLFLAG_RW, sc, 0, bge_sysctl_mem_read, "I",
+ "Memory Read");
+
+ SYSCTL_ADD_ULONG(ctx, children, OID_AUTO, "stat_IfHcInOctets",
+ CTLFLAG_RD,
+ &sc->bge_ldata.bge_stats->rxstats.ifHCInOctets.bge_addr_lo,
+ "Bytes received");
+
+ SYSCTL_ADD_ULONG(ctx, children, OID_AUTO, "stat_IfHcOutOctets",
+ CTLFLAG_RD,
+ &sc->bge_ldata.bge_stats->txstats.ifHCOutOctets.bge_addr_lo,
+ "Bytes received");
+#endif
+}
+
+#ifdef BGE_REGISTER_DEBUG
+static int
+bge_sysctl_debug_info(SYSCTL_HANDLER_ARGS)
+{
+ struct bge_softc *sc;
+ uint16_t *sbdata;
+ int error;
+ int result;
+ int i, j;
+
+ result = -1;
+ error = sysctl_handle_int(oidp, &result, 0, req);
+ if (error || (req->newptr == NULL))
+ return (error);
+
+ if (result == 1) {
+ sc = (struct bge_softc *)arg1;
+
+ sbdata = (uint16_t *)sc->bge_ldata.bge_status_block;
+ printf("Status Block:\n");
+ for (i = 0x0; i < (BGE_STATUS_BLK_SZ / 4); ) {
+ printf("%06x:", i);
+ for (j = 0; j < 8; j++) {
+ printf(" %04x", sbdata[i]);
+ i += 4;
+ }
+ printf("\n");
+ }
+
+ printf("Registers:\n");
+ for (i = 0x800; i < 0xa00; ) {
+ printf("%06x:", i);
+ for (j = 0; j < 8; j++) {
+ printf(" %08x", CSR_READ_4(sc, i));
+ i += 4;
+ }
+ printf("\n");
+ }
+
+ printf("Hardware Flags:\n");
+ if (sc->bge_flags & BGE_FLAG_575X_PLUS)
+ printf(" - 575X Plus\n");
+ if (sc->bge_flags & BGE_FLAG_5705_PLUS)
+ printf(" - 5705 Plus\n");
+ if (sc->bge_flags & BGE_FLAG_JUMBO)
+ printf(" - Supports Jumbo Frames\n");
+ if (sc->bge_flags & BGE_FLAG_PCIX)
+ printf(" - PCI-X Bus\n");
+ if (sc->bge_flags & BGE_FLAG_PCIE)
+ printf(" - PCI Express Bus\n");
+ if (sc->bge_flags & BGE_FLAG_NO3LED)
+ printf(" - No 3 LEDs\n");
+ if (sc->bge_flags & BGE_FLAG_RX_ALIGNBUG)
+ printf(" - RX Alignment Bug\n");
+ }
+
+ return (error);
+}
+
+static int
+bge_sysctl_reg_read(SYSCTL_HANDLER_ARGS)
+{
+ struct bge_softc *sc;
+ int error;
+ uint16_t result;
+ uint32_t val;
+
+ result = -1;
+ error = sysctl_handle_int(oidp, &result, 0, req);
+ if (error || (req->newptr == NULL))
+ return (error);
+
+ if (result < 0x8000) {
+ sc = (struct bge_softc *)arg1;
+ val = CSR_READ_4(sc, result);
+ printf("reg 0x%06X = 0x%08X\n", result, val);
+ }
+
+ return (error);
+}
+
+static int
+bge_sysctl_mem_read(SYSCTL_HANDLER_ARGS)
+{
+ struct bge_softc *sc;
+ int error;
+ uint16_t result;
+ uint32_t val;
+
+ result = -1;
+ error = sysctl_handle_int(oidp, &result, 0, req);
+ if (error || (req->newptr == NULL))
+ return (error);
+
+ if (result < 0x8000) {
+ sc = (struct bge_softc *)arg1;
+ val = bge_readmem_ind(sc, result);
+ printf("mem 0x%06X = 0x%08X\n", result, val);
+ }
+
+ return (error);
+}
+#endif
diff --git a/sys/dev/bge/if_bgereg.h b/sys/dev/bge/if_bgereg.h
index f96b0fd..82ac370 100644
--- a/sys/dev/bge/if_bgereg.h
+++ b/sys/dev/bge/if_bgereg.h
@@ -271,6 +271,15 @@
#define BGE_CHIPID_BCM5714_B3 0x80030000
#define BGE_CHIPID_BCM5715_A0 0x90000000
#define BGE_CHIPID_BCM5715_A1 0x90010000
+#define BGE_CHIPID_BCM5755_A0 0xa0000000
+#define BGE_CHIPID_BCM5755_A1 0xa0010000
+#define BGE_CHIPID_BCM5755_A2 0xa0020000
+#define BGE_CHIPID_BCM5754_A0 0xb0000000
+#define BGE_CHIPID_BCM5754_A1 0xb0010000
+#define BGE_CHIPID_BCM5754_A2 0xb0020000
+#define BGE_CHIPID_BCM5787_A0 0xb0000000
+#define BGE_CHIPID_BCM5787_A1 0xb0010000
+#define BGE_CHIPID_BCM5787_A2 0xb0020000
/* shorthand one */
#define BGE_ASICREV(x) ((x) >> 28)
@@ -285,6 +294,7 @@
#define BGE_ASICREV_BCM5780 0x08
#define BGE_ASICREV_BCM5714 0x09
#define BGE_ASICREV_BCM5755 0x0a
+#define BGE_ASICREV_BCM5754 0x0b
#define BGE_ASICREV_BCM5787 0x0b
/* chip revisions */
@@ -1661,6 +1671,7 @@
#define BGE_EE_CTL 0x6840
#define BGE_MDI_CTL 0x6844
#define BGE_EE_DELAY 0x6848
+#define BGE_FASTBOOT_PC 0x6894
/* Mode control register */
#define BGE_MODECTL_INT_SNDCOAL_ONLY 0x00000001
OpenPOWER on IntegriCloud