Skip site navigation (1)Skip section navigation (2)
Date:      Mon, 12 Mar 2012 02:09:47 +0000 (UTC)
From:      Pyun YongHyeon <yongari@FreeBSD.org>
To:        src-committers@freebsd.org, svn-src-all@freebsd.org, svn-src-head@freebsd.org
Subject:   svn commit: r232848 - head/sys/dev/bge
Message-ID:  <201203120209.q2C29l5e037540@svn.freebsd.org>

next in thread | raw e-mail | index | archive | help
Author: yongari
Date: Mon Mar 12 02:09:47 2012
New Revision: 232848
URL: http://svn.freebsd.org/changeset/base/232848

Log:
  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

Modified:
  head/sys/dev/bge/if_bge.c
  head/sys/dev/bge/if_bgereg.h

Modified: head/sys/dev/bge/if_bge.c
==============================================================================
--- head/sys/dev/bge/if_bge.c	Mon Mar 12 01:23:09 2012	(r232847)
+++ head/sys/dev/bge/if_bge.c	Mon Mar 12 02:09:47 2012	(r232848)
@@ -380,6 +380,8 @@ static void bge_dma_free(struct bge_soft
 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 o
 		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.

Modified: head/sys/dev/bge/if_bgereg.h
==============================================================================
--- head/sys/dev/bge/if_bgereg.h	Mon Mar 12 01:23:09 2012	(r232847)
+++ head/sys/dev/bge/if_bgereg.h	Mon Mar 12 02:09:47 2012	(r232848)
@@ -2818,6 +2818,7 @@ struct bge_softc {
 #define	BGE_FLAG_RX_ALIGNBUG	0x04000000
 #define	BGE_FLAG_SHORT_DMA_BUG	0x08000000
 #define	BGE_FLAG_4K_RDMA_BUG	0x10000000
+#define	BGE_FLAG_MBOX_REORDER	0x20000000
 	uint32_t		bge_phy_flags;
 #define	BGE_PHY_NO_WIRESPEED	0x00000001
 #define	BGE_PHY_ADC_BUG		0x00000002



Want to link to this message? Use this URL: <https://mail-archive.FreeBSD.org/cgi/mid.cgi?201203120209.q2C29l5e037540>