summaryrefslogtreecommitdiffstats
path: root/sys/dev/bge/if_bge.c
diff options
context:
space:
mode:
authoryongari <yongari@FreeBSD.org>2012-03-12 02:09:47 +0000
committeryongari <yongari@FreeBSD.org>2012-03-12 02:09:47 +0000
commit7f8cecc5034ff015e741c094176b2b792cc135d2 (patch)
tree38bb6bfc86a109bb0b3bf011b271a89f98ce04ed /sys/dev/bge/if_bge.c
parent2bb441e96ed88fc503ae6e6581f99bd02249caa3 (diff)
downloadFreeBSD-src-7f8cecc5034ff015e741c094176b2b792cc135d2.zip
FreeBSD-src-7f8cecc5034ff015e741c094176b2b792cc135d2.tar.gz
Add workaround for PCI-X BCM5704 controller that live behind
AMD-8131 PCI-X bridge. The bridge seems to reorder write access to mailbox registers such that it caused watchdog timeouts by out-of-order TX completions. Tested by: Michael L. Squires <mikes <> siralan dot org > Reviewed by: jhb
Diffstat (limited to 'sys/dev/bge/if_bge.c')
-rw-r--r--sys/dev/bge/if_bge.c70
1 files changed, 67 insertions, 3 deletions
diff --git a/sys/dev/bge/if_bge.c b/sys/dev/bge/if_bge.c
index de8bd9b..1a0d20c 100644
--- a/sys/dev/bge/if_bge.c
+++ b/sys/dev/bge/if_bge.c
@@ -380,6 +380,8 @@ static void bge_dma_free(struct bge_softc *);
static int bge_dma_ring_alloc(struct bge_softc *, bus_size_t, bus_size_t,
bus_dma_tag_t *, uint8_t **, bus_dmamap_t *, bus_addr_t *, const char *);
+static int bge_mbox_reorder(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[]);
@@ -635,6 +637,8 @@ bge_writembx(struct bge_softc *sc, int off, int val)
off += BGE_LPMBX_IRQ0_HI - BGE_MBX_IRQ0_HI;
CSR_WRITE_4(sc, off, val);
+ if ((sc->bge_flags & BGE_FLAG_MBOX_REORDER) != 0)
+ CSR_READ_4(sc, off);
}
/*
@@ -2584,10 +2588,10 @@ bge_dma_alloc(struct bge_softc *sc)
* XXX
* watchdog timeout issue was observed on BCM5704 which
* lives behind PCI-X bridge(e.g AMD 8131 PCI-X bridge).
- * Limiting DMA address space to 32bits seems to address
- * it.
+ * Both limiting DMA address space to 32bits and flushing
+ * mailbox write seem to address the issue.
*/
- if (sc->bge_flags & BGE_FLAG_PCIX)
+ if (sc->bge_pcixcap != 0)
lowaddr = BUS_SPACE_MAXADDR_32BIT;
}
error = bus_dma_tag_create(bus_get_dma_tag(sc->bge_dev), 1, 0, lowaddr,
@@ -2750,6 +2754,56 @@ bge_can_use_msi(struct bge_softc *sc)
}
static int
+bge_mbox_reorder(struct bge_softc *sc)
+{
+ /* Lists of PCI bridges that are known to reorder mailbox writes. */
+ static const struct mbox_reorder {
+ const uint16_t vendor;
+ const uint16_t device;
+ const char *desc;
+ } const mbox_reorder_lists[] = {
+ { 0x1022, 0x7450, "AMD-8131 PCI-X Bridge" },
+ };
+ devclass_t pci, pcib;
+ device_t bus, dev;
+ int count, i;
+
+ count = sizeof(mbox_reorder_lists) / sizeof(mbox_reorder_lists[0]);
+ pci = devclass_find("pci");
+ pcib = devclass_find("pcib");
+ dev = sc->bge_dev;
+ bus = device_get_parent(dev);
+ for (;;) {
+ dev = device_get_parent(bus);
+ bus = device_get_parent(dev);
+ device_printf(sc->bge_dev, "dev : %s%d, bus : %s%d\n",
+ device_get_name(dev), device_get_unit(dev),
+ device_get_name(bus), device_get_unit(bus));
+ if (device_get_devclass(dev) != pcib)
+ break;
+ for (i = 0; i < count; i++) {
+ device_printf(sc->bge_dev,
+ "probing dev : %s%d, vendor : 0x%04x "
+ "device : 0x%04x\n",
+ device_get_name(dev), device_get_unit(dev),
+ pci_get_vendor(dev), pci_get_device(dev));
+ if (pci_get_vendor(dev) ==
+ mbox_reorder_lists[i].vendor &&
+ pci_get_device(dev) ==
+ mbox_reorder_lists[i].device) {
+ device_printf(sc->bge_dev,
+ "enabling MBOX workaround for %s\n",
+ mbox_reorder_lists[i].desc);
+ return (1);
+ }
+ }
+ if (device_get_devclass(bus) != pci)
+ break;
+ }
+ return (0);
+}
+
+static int
bge_attach(device_t dev)
{
struct ifnet *ifp;
@@ -3069,6 +3123,16 @@ bge_attach(device_t dev)
if (BGE_IS_5714_FAMILY(sc) && (sc->bge_flags & BGE_FLAG_PCIX))
sc->bge_flags |= BGE_FLAG_40BIT_BUG;
/*
+ * Some PCI-X bridges are known to trigger write reordering to
+ * the mailbox registers. Typical phenomena is watchdog timeouts
+ * caused by out-of-order TX completions. Enable workaround for
+ * PCI-X devices that live behind these bridges.
+ * Note, PCI-X controllers can run in PCI mode so we can't use
+ * BGE_FLAG_PCIX flag to detect PCI-X controllers.
+ */
+ if (sc->bge_pcixcap != 0 && bge_mbox_reorder(sc) != 0)
+ sc->bge_flags |= BGE_FLAG_MBOX_REORDER;
+ /*
* Allocate the interrupt, using MSI if possible. These devices
* support 8 MSI messages, but only the first one is used in
* normal operation.
OpenPOWER on IntegriCloud