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
_______________________________________________
svn-src-head@freebsd.org mailing list
http://lists.freebsd.org/mailman/listinfo/svn-src-head
To unsubscribe, send any mail to "svn-src-head-unsubscr...@freebsd.org"

Reply via email to