Author: adrian
Date: Tue May 17 06:52:53 2016
New Revision: 300015
URL: https://svnweb.freebsd.org/changeset/base/300015

Log:
  [bhnd] Finish bhnd(4) PCI/PCIe-G1 hostb support.
  
  Now that we've got access to SPROM and can access board identification,
  this implements all known remaining hardware work-arounds for the bhnd(4)
  PCI and PCIe-G1 cores operating endpoint mode.
  
  Additionally, this adds an initial set of skeleton PCIe-G2 hostb and pcib
  drivers, required by fullmac and newer softmac devices.
  
  Submitted by: Landon Fuller <land...@landonf.org>
  Differential Revision:        https://reviews.freebsd.org/D6377

Added:
  head/sys/dev/bhnd/cores/pcie2/
  head/sys/dev/bhnd/cores/pcie2/bhnd_pcie2.c   (contents, props changed)
  head/sys/dev/bhnd/cores/pcie2/bhnd_pcie2_hostb.c   (contents, props changed)
  head/sys/dev/bhnd/cores/pcie2/bhnd_pcie2_hostbvar.h   (contents, props 
changed)
  head/sys/dev/bhnd/cores/pcie2/bhnd_pcie2_reg.h   (contents, props changed)
  head/sys/dev/bhnd/cores/pcie2/bhnd_pcie2_var.h   (contents, props changed)
  head/sys/dev/bhnd/cores/pcie2/bhnd_pcie2b.c   (contents, props changed)
  head/sys/dev/bhnd/cores/pcie2/bhnd_pcie2b_var.h   (contents, props changed)
Modified:
  head/sys/conf/files
  head/sys/dev/bhnd/bhnd.h
  head/sys/dev/bhnd/bhnd_ids.h
  head/sys/dev/bhnd/bhnd_subr.c
  head/sys/dev/bhnd/bhndb/bhndb_pci.c
  head/sys/dev/bhnd/bhndb/bhndb_pcireg.h
  head/sys/dev/bhnd/cores/chipc/bhnd_chipc_if.m
  head/sys/dev/bhnd/cores/chipc/chipc.c
  head/sys/dev/bhnd/cores/pci/bhnd_pci.c
  head/sys/dev/bhnd/cores/pci/bhnd_pci_hostb.c
  head/sys/dev/bhnd/cores/pci/bhnd_pci_hostbvar.h
  head/sys/dev/bhnd/cores/pci/bhnd_pcib.c
  head/sys/dev/bhnd/cores/pci/bhnd_pcireg.h
  head/sys/dev/bhnd/siba/siba.c
  head/sys/dev/bhnd/siba/siba_bhndb.c
  head/sys/dev/bhnd/siba/sibavar.h
  head/sys/modules/bhnd/cores/bhnd_pci/Makefile
  head/sys/modules/bhnd/cores/bhnd_pci_hostb/Makefile
  head/sys/modules/bhnd/cores/bhnd_pcib/Makefile

Modified: head/sys/conf/files
==============================================================================
--- head/sys/conf/files Tue May 17 06:45:25 2016        (r300014)
+++ head/sys/conf/files Tue May 17 06:52:53 2016        (r300015)
@@ -1142,6 +1142,9 @@ dev/bhnd/cores/chipc/bhnd_chipc_if.m      opt
 dev/bhnd/cores/pci/bhnd_pci.c          optional bhndbus pci | bhnd pci
 dev/bhnd/cores/pci/bhnd_pci_hostb.c    optional bhndbus pci | bhndb pci
 dev/bhnd/cores/pci/bhnd_pcib.c         optional bhnd_pcib bhnd pci
+dev/bhnd/cores/pcie2/bhnd_pcie2.c      optional bhndbus pci | bhnd pci
+dev/bhnd/cores/pcie2/bhnd_pcie2_hostb.c        optional bhndbus pci | bhndb pci
+dev/bhnd/cores/pcie2/bhnd_pcie2b.c     optional bhnd_pcie2b bhnd pci
 dev/bhnd/nvram/bhnd_nvram_if.m         optional bhndbus | bhnd
 dev/bhnd/nvram/bhnd_sprom.c            optional bhndbus | bhnd
 dev/bhnd/nvram/nvram_subr.c            optional bhndbus | bhnd

Modified: head/sys/dev/bhnd/bhnd.h
==============================================================================
--- head/sys/dev/bhnd/bhnd.h    Tue May 17 06:45:25 2016        (r300014)
+++ head/sys/dev/bhnd/bhnd.h    Tue May 17 06:52:53 2016        (r300015)
@@ -318,8 +318,8 @@ struct bhnd_chip_match {
        .match_bvendor = 1, .board_vendor = _vend
 
 /** Set the required board type within a bhnd_chip_match instance */
-#define        BHND_CHIP_BT(_btype)            \
-       .match_btype = 1, .board_type = BHND_BOARD_BCM ## _btype
+#define        BHND_CHIP_BTYPE(_btype)         \
+       .match_btype = 1, .board_type = BHND_BOARD_ ## _btype
 
 /** Set the required SROM revision range within a bhnd_chip_match instance */
 #define        BHND_CHIP_SROMREV(_rev)         \
@@ -331,7 +331,7 @@ struct bhnd_chip_match {
 
 /** Set the required board vendor and type within a bhnd_chip_match instance */
 #define        BHND_CHIP_BVT(_vend, _type)     \
-       BHND_CHIP_BVEND(_vend), BHND_CHIP_BTYPE(_type)
+       BHND_CHIP_BVENDOR(_vend), BHND_CHIP_BTYPE(_type)
 
 /** Set the required board vendor, type, and revision within a bhnd_chip_match
  *  instance */
@@ -429,6 +429,9 @@ device_t                     bhnd_match_child(device_t de
 device_t                        bhnd_find_child(device_t dev,
                                     bhnd_devclass_t class, int unit);
 
+device_t                        bhnd_find_bridge_root(device_t dev,
+                                    devclass_t bus_class);
+
 const struct bhnd_core_info    *bhnd_match_core(
                                     const struct bhnd_core_info *cores,
                                     u_int num_cores,

Modified: head/sys/dev/bhnd/bhnd_ids.h
==============================================================================
--- head/sys/dev/bhnd/bhnd_ids.h        Tue May 17 06:45:25 2016        
(r300014)
+++ head/sys/dev/bhnd/bhnd_ids.h        Tue May 17 06:52:53 2016        
(r300015)
@@ -26,8 +26,6 @@
 #ifndef _BHND_BHND_IDS_H_
 #define _BHND_BHND_IDS_H_
 
-
-
 /*
  * JEDEC JEP-106 Core Vendor IDs
  * 
@@ -851,12 +849,12 @@
 #define        BHND_BOARD_BU4785               0x0478
 
 /* 4321 boards */
-#define        BHND_BOARD_BU4321               0x046b
-#define        BHND_BOARD_BU4321E              0x047c
-#define        BHND_BOARD_MP4321               0x046c
-#define        BHND_BOARD_CB2_4321             0x046d
-#define        BHND_BOARD_CB2_4321_AG          0x0066
-#define        BHND_BOARD_MC4321               0x046e
+#define        BHND_BOARD_BCM4321BU            0x046b
+#define        BHND_BOARD_BCM4321BUE           0x047c
+#define        BHND_BOARD_BCM4321MP            0x046c
+#define        BHND_BOARD_BCM4321CB2           0x046d
+#define        BHND_BOARD_BCM4321CB2_AG        0x0066
+#define        BHND_BOARD_BCM4321MC            0x046e
 
 /* 4328 boards */
 #define        BHND_BOARD_BU4328               0x0481

Modified: head/sys/dev/bhnd/bhnd_subr.c
==============================================================================
--- head/sys/dev/bhnd/bhnd_subr.c       Tue May 17 06:45:25 2016        
(r300014)
+++ head/sys/dev/bhnd/bhnd_subr.c       Tue May 17 06:52:53 2016        
(r300015)
@@ -350,6 +350,56 @@ done:
 }
 
 /**
+ * Walk up the bhnd device hierarchy to locate the root device
+ * to which the bhndb bridge is attached.
+ * 
+ * This can be used from within bhnd host bridge drivers to locate the
+ * actual upstream host device.
+ * 
+ * @param dev A bhnd device.
+ * @param bus_class The expected bus (e.g. "pci") to which the bridge root
+ * should be attached.
+ * 
+ * @retval device_t if a matching parent device is found.
+ * @retval NULL @p dev is not attached via a bhndb bus
+ * @retval NULL no parent device is attached via @p bus_class.
+ */
+device_t
+bhnd_find_bridge_root(device_t dev, devclass_t bus_class)
+{
+       devclass_t      bhndb_class;
+       device_t        parent;
+
+       KASSERT(device_get_devclass(device_get_parent(dev)) == bhnd_devclass,
+          ("%s not a bhnd device", device_get_nameunit(dev)));
+
+       bhndb_class = devclass_find("bhndb");
+
+       /* Walk the device tree until we hit a bridge */
+       parent = dev;
+       while ((parent = device_get_parent(parent)) != NULL) {
+               if (device_get_devclass(parent) == bhndb_class)
+                       break;
+       }
+
+       /* No bridge? */
+       if (parent == NULL)
+               return (NULL);
+
+       /* Search for a parent attached to the expected bus class */
+       while ((parent = device_get_parent(parent)) != NULL) {
+               device_t bus;
+
+               bus = device_get_parent(parent);
+               if (bus != NULL && device_get_devclass(bus) == bus_class)
+                       return (parent);
+       }
+
+       /* Not found */
+       return (NULL);
+}
+
+/**
  * Find the first core in @p cores that matches @p desc.
  * 
  * @param cores The table to search.

Modified: head/sys/dev/bhnd/bhndb/bhndb_pci.c
==============================================================================
--- head/sys/dev/bhnd/bhndb/bhndb_pci.c Tue May 17 06:45:25 2016        
(r300014)
+++ head/sys/dev/bhnd/bhndb/bhndb_pci.c Tue May 17 06:52:53 2016        
(r300015)
@@ -37,9 +37,10 @@ __FBSDID("$FreeBSD$");
  * bus (e.g. bcma or siba) via a Broadcom PCI core configured in end-point
  * mode.
  * 
- * This driver handles all host-level PCI interactions with a PCI/PCIe bridge
- * core operating in endpoint mode. On the bridged bhnd bus, the PCI core
- * device will be managed by a bhnd_pci_hostb driver.
+ * This driver handles all initial generic host-level PCI interactions with a
+ * PCI/PCIe bridge core operating in endpoint mode. Once the bridged bhnd(4)
+ * bus has been enumerated, this driver works in tandem with a core-specific
+ * bhnd_pci_hostb driver to manage the PCI core.
  */
 
 #include <sys/param.h>
@@ -482,6 +483,35 @@ bhndb_pci_populate_board_info(device_t d
 
        sc = device_get_softc(dev);
 
+       /* 
+        * On a subset of Apple BCM4360 modules, always prefer the
+        * PCI subdevice to the SPROM-supplied boardtype.
+        * 
+        * TODO:
+        * 
+        * Broadcom's own drivers implement this override, and then later use
+        * the remapped BCM4360 board type to determine the required
+        * board-specific workarounds.
+        * 
+        * Without access to this hardware, it's unclear why this mapping
+        * is done, and we must do the same. If we can survey the hardware
+        * in question, it may be possible to replace this behavior with
+        * explicit references to the SPROM-supplied boardtype(s) in our
+        * quirk definitions.
+        */
+       if (pci_get_subvendor(sc->parent) == PCI_VENDOR_APPLE) {
+               switch (info->board_type) {
+               case BHND_BOARD_BCM94360X29C:
+               case BHND_BOARD_BCM94360X29CP2:
+               case BHND_BOARD_BCM94360X51:
+               case BHND_BOARD_BCM94360X51P2:
+                       info->board_type = 0;   /* allow override below */
+                       break;
+               default:
+                       break;
+               }
+       }
+
        /* If NVRAM did not supply vendor/type info, provide the PCI
         * subvendor/subdevice values. */
        if (info->board_vendor == 0)
@@ -560,10 +590,6 @@ bhndb_disable_pci_clocks(struct bhndb_pc
        if (sc->pci_devclass != BHND_DEVCLASS_PCI)
                return (0);
 
-       // TODO: Check board flags for BFL2_XTALBUFOUTEN?
-       // TODO: Check PCI core revision?
-       // TODO: Switch to 'slow' clock?
-
        /* Fetch current config */
        gpio_out = pci_read_config(sc->parent, BHNDB_PCI_GPIO_OUT, 4);
        gpio_en = pci_read_config(sc->parent, BHNDB_PCI_GPIO_OUTEN, 4);
@@ -601,6 +627,7 @@ DEFINE_CLASS_1(bhndb, bhndb_pci_driver, 
 
 MODULE_VERSION(bhndb_pci, 1);
 MODULE_DEPEND(bhndb_pci, bhnd_pci_hostb, 1, 1, 1);
+MODULE_DEPEND(bhndb_pci, bhnd_pcie2_hostb, 1, 1, 1);
 MODULE_DEPEND(bhndb_pci, pci, 1, 1, 1);
 MODULE_DEPEND(bhndb_pci, bhndb, 1, 1, 1);
 MODULE_DEPEND(bhndb_pci, bhnd, 1, 1, 1);

Modified: head/sys/dev/bhnd/bhndb/bhndb_pcireg.h
==============================================================================
--- head/sys/dev/bhnd/bhndb/bhndb_pcireg.h      Tue May 17 06:45:25 2016        
(r300014)
+++ head/sys/dev/bhnd/bhndb/bhndb_pcireg.h      Tue May 17 06:52:53 2016        
(r300015)
@@ -29,13 +29,13 @@
  * 
  * = MAJOR CORE REVISIONS =
  * 
- * There have been four revisions to the BAR0/BAR1 memory mappings used
+ * There have been four revisions to the BAR0 memory mappings used
  * in BHND PCI/PCIE bridge cores:
  * 
  * == PCI_V0 ==
  * Applies to:
  * -  PCI (cid=0x804, revision <= 12)
- * BAR size: 8KB
+ * BAR0 size: 8KB
  * Address Map:
  *     [offset+  size] type    description
  *     [0x0000+0x1000] dynamic mapped backplane address space (window 0).
@@ -46,7 +46,7 @@
  * Applies to:
  * -  PCI (cid=0x804, revision >= 13)
  * -  PCIE (cid=0x820) with ChipCommon (revision <= 31)
- * BAR size: 16KB
+ * BAR0 size: 16KB
  * Address Map:
  *     [offset+  size] type    description
  *     [0x0000+0x1000] dynamic mapped backplane address space (window 0).
@@ -57,7 +57,7 @@
  * == PCI_V2 ==
  * Applies to:
  * - PCIE (cid=0x820) with ChipCommon (revision >= 32)
- * BAR size: 16KB
+ * BAR0 size: 16KB
  * Address Map:
  *     [offset+  size] type    description
  *     [0x0000+0x1000] dynamic mapped backplane address space (window 0).
@@ -68,7 +68,7 @@
  * == PCI_V3 ==
  * Applies to:
  * - PCIE Gen 2 (cid=0x83c)
- * BAR size: 32KB?
+ * BAR0 size: 32KB
  * Address Map:
  *     [offset+  size] type    description
  *     [0x0000+0x1000] dynamic mapped backplane address space (window 0).
@@ -76,6 +76,12 @@
  *     [0x2000+0x1000] fixed   pci/pcie core registers
  *     [0x3000+0x1000] fixed   chipcommon core registers
  *     [???]
+ * BAR1 size: varies
+ * Address Map:
+ *     [offset+  size] type    description
+ *     [0x0000+0x????] fixed   ARM tightly-coupled memory (TCM).
+ *                             While fullmac chipsets provided a fixed
+ *                             4KB mapping, newer devices will vary.
  * 
  * = MINOR CORE REVISIONS =
  * 
@@ -86,28 +92,6 @@
  * == PCI/PCIE Cores Revision >= 14 ==
  * - Mapped the clock CSR into the PCI config space. Refer to
  *   BHND_PCI_CLK_CTL_ST
- * 
- * = Hardware Bugs =
- * == BAR1 ==
- * 
- * The BHND PCI(e) cores hypothetically support an additional memory mapping
- * of the backplane address space via BAR1, but this appears to be subject
- * to a hardware bug in which BAR1 is initially configured with a 4 byte
- * length.
- * 
- * A work-around for this bug may be possible by writing to the PCI core's
- * BAR1 config register (0x4e0), but this requires further research -- I've
- * found three sources for information on the BAR1 PCI core configuration that
- * may be relevant:
- *     - The QLogix NetXTreme 10GB PCIe NIC seems to use the same PCIE
- *       core IP block as is used in other BHND devices. The bxe(4) driver
- *       contains example initialization code and register constants
- *       that may apply (e.g. GRC_BAR2_CONFIG/PCI_CONFIG_2_BAR2_SIZE).
- *     - The publicly available Broadcom BCM440X data sheet (440X-PG02-R)
- *       appears to (partially) document a Broadcom PCI(e) core that has a
- *       seemingly compatible programming model.
- *     - The Android bcmdhd driver sources include a possible work-around
- *       implementation (writing to 0x4e0) in dhd_pcie.c
  */
 
 /* Common PCI/PCIE Config Registers */
@@ -181,12 +165,11 @@
 #define        BHNDB_PCI_V2_BAR0_CCREGS_OFFSET 0x3000  /* bar0 + 12K accesses 
chipc core registers */
 #define        BHNDB_PCI_V2_BAR0_CCREGS_SIZE   0x1000
 
-/* PCI_V3 */
+/* PCI_V3 (PCIe-G2) */
 #define        BHNDB_PCI_V3_BAR0_WIN0_CONTROL  0x80    /* backplane address 
space accessed by BAR0/WIN0 */
-#define        BHNDB_PCI_V3_BAR1_WIN0_CONTROL  0x84    /* backplane address 
space accessed by BAR1/WIN0. */
 #define BHNDB_PCI_V3_BAR0_WIN1_CONTROL 0x70    /* backplane address space 
accessed by BAR0/WIN1 */
 
-#define        BHNDB_PCI_V3_BAR0_SIZE          0x8000  /* 32KB BAR0 (?) */
+#define        BHNDB_PCI_V3_BAR0_SIZE          0x8000  /* 32KB BAR0 */
 #define        BHNDB_PCI_V3_BAR0_WIN0_OFFSET   0x0     /* bar0 + 0x0 accesses 
configurable 4K region of backplane address space */
 #define        BHNDB_PCI_V3_BAR0_WIN0_SIZE     0x1000
 #define        BHNDB_PCI_V3_BAR0_WIN1_OFFSET   0x1000  /* bar0 + 4K accesses 
second 4K window */

Modified: head/sys/dev/bhnd/cores/chipc/bhnd_chipc_if.m
==============================================================================
--- head/sys/dev/bhnd/cores/chipc/bhnd_chipc_if.m       Tue May 17 06:45:25 
2016        (r300014)
+++ head/sys/dev/bhnd/cores/chipc/bhnd_chipc_if.m       Tue May 17 06:52:53 
2016        (r300015)
@@ -43,4 +43,23 @@ INTERFACE bhnd_chipc;
  */
 METHOD bhnd_nvram_src_t nvram_src {
        device_t dev;
-}
\ No newline at end of file
+}
+
+/**
+ * Write @p value with @p mask directly to the chipctrl register.
+ *
+ * @param dev A bhnd(4) ChipCommon device.
+ * @param value The value to write.
+ * @param mask The mask of bits to be written from @p value.
+ *
+ * Drivers should only use function for functionality that is not
+ * available via another bhnd_chipc() function.
+ *
+ * Currently, the only known valid use-case is in implementing a hardware
+ * work-around for the BCM4321 PCIe rev7 core revision.
+ */
+METHOD void write_chipctrl {
+       device_t dev;
+       uint32_t value;
+       uint32_t mask;
+}

Modified: head/sys/dev/bhnd/cores/chipc/chipc.c
==============================================================================
--- head/sys/dev/bhnd/cores/chipc/chipc.c       Tue May 17 06:45:25 2016        
(r300014)
+++ head/sys/dev/bhnd/cores/chipc/chipc.c       Tue May 17 06:52:53 2016        
(r300015)
@@ -489,20 +489,38 @@ chipc_nvram_setvar(device_t dev, const c
        return (ENODEV);
 }
 
+static void
+chipc_write_chipctrl(device_t dev, uint32_t value, uint32_t mask)
+{
+       struct chipc_softc      *sc;
+       uint32_t                 cctrl;
+
+       sc = device_get_softc(dev);
+
+       CHIPC_LOCK(sc);
+
+       cctrl = bhnd_bus_read_4(sc->core, CHIPC_CHIPCTRL);
+       cctrl = (cctrl & ~mask) | (value | mask);
+       bhnd_bus_write_4(sc->core, CHIPC_CHIPCTRL, cctrl);
+
+       CHIPC_UNLOCK(sc);
+}
+
 static device_method_t chipc_methods[] = {
        /* Device interface */
-       DEVMETHOD(device_probe,         chipc_probe),
-       DEVMETHOD(device_attach,        chipc_attach),
-       DEVMETHOD(device_detach,        chipc_detach),
-       DEVMETHOD(device_suspend,       chipc_suspend),
-       DEVMETHOD(device_resume,        chipc_resume),
+       DEVMETHOD(device_probe,                 chipc_probe),
+       DEVMETHOD(device_attach,                chipc_attach),
+       DEVMETHOD(device_detach,                chipc_detach),
+       DEVMETHOD(device_suspend,               chipc_suspend),
+       DEVMETHOD(device_resume,                chipc_resume),
        
        /* ChipCommon interface */
-       DEVMETHOD(bhnd_chipc_nvram_src, chipc_nvram_src),
+       DEVMETHOD(bhnd_chipc_nvram_src,         chipc_nvram_src),
+       DEVMETHOD(bhnd_chipc_write_chipctrl,    chipc_write_chipctrl),
 
        /* NVRAM interface */
-       DEVMETHOD(bhnd_nvram_getvar,    chipc_nvram_getvar),
-       DEVMETHOD(bhnd_nvram_setvar,    chipc_nvram_setvar),
+       DEVMETHOD(bhnd_nvram_getvar,            chipc_nvram_getvar),
+       DEVMETHOD(bhnd_nvram_setvar,            chipc_nvram_setvar),
 
        DEVMETHOD_END
 };

Modified: head/sys/dev/bhnd/cores/pci/bhnd_pci.c
==============================================================================
--- head/sys/dev/bhnd/cores/pci/bhnd_pci.c      Tue May 17 06:45:25 2016        
(r300014)
+++ head/sys/dev/bhnd/cores/pci/bhnd_pci.c      Tue May 17 06:52:53 2016        
(r300015)
@@ -429,8 +429,7 @@ bhnd_pcie_mdio_read_ext(struct bhnd_pci_
     int reg)
 {
        uint32_t        cmd;
-       uint16_t        blk, val;
-       uint8_t         blk_reg;
+       uint16_t        val;
        int             error;
 
        if (devaddr == MDIO_DEVADDR_NONE)
@@ -438,27 +437,23 @@ bhnd_pcie_mdio_read_ext(struct bhnd_pci_
 
        /* Extended register access is only supported for the SerDes device,
         * using the non-standard C22 extended address mechanism */
-       if (!(sc->quirks & BHND_PCI_QUIRK_SD_C22_EXTADDR))
+       if (!(sc->quirks & BHND_PCI_QUIRK_SD_C22_EXTADDR) ||
+           phy != BHND_PCIE_PHYADDR_SD)
+       {
                return (~0U);   
-       if (phy != BHND_PCIE_PHYADDR_SD || devaddr != BHND_PCIE_DEVAD_SD)
-               return (~0U);
+       }
 
        /* Enable MDIO access */
        BHND_PCI_LOCK(sc);
        bhnd_pcie_mdio_enable(sc);
 
-       /* Determine the block and register values */
-       blk = (reg & BHND_PCIE_SD_ADDREXT_BLK_MASK);
-       blk_reg = (reg & BHND_PCIE_SD_ADDREXT_REG_MASK);
-
        /* Write the block address to the address extension register */
-       cmd = BHND_PCIE_MDIODATA_ADDR(phy, BHND_PCIE_SD_ADDREXT) |
-           (blk & BHND_PCIE_MDIODATA_DATA_MASK);
+       cmd = BHND_PCIE_MDIODATA_ADDR(phy, BHND_PCIE_SD_ADDREXT) | devaddr;
        if ((error = bhnd_pcie_mdio_cmd_write(sc, cmd)))
                goto cleanup;
 
        /* Issue the read */
-       cmd = BHND_PCIE_MDIODATA_ADDR(phy, blk_reg);
+       cmd = BHND_PCIE_MDIODATA_ADDR(phy, reg);
        error = bhnd_pcie_mdio_cmd_read(sc, cmd, &val);
 
 cleanup:
@@ -476,8 +471,6 @@ bhnd_pcie_mdio_write_ext(struct bhnd_pci
     int reg, int val)
 {      
        uint32_t        cmd;
-       uint16_t        blk;
-       uint8_t         blk_reg;
        int             error;
 
        if (devaddr == MDIO_DEVADDR_NONE)
@@ -485,27 +478,23 @@ bhnd_pcie_mdio_write_ext(struct bhnd_pci
 
        /* Extended register access is only supported for the SerDes device,
         * using the non-standard C22 extended address mechanism */
-       if (!(sc->quirks & BHND_PCI_QUIRK_SD_C22_EXTADDR))
+       if (!(sc->quirks & BHND_PCI_QUIRK_SD_C22_EXTADDR) ||
+           phy != BHND_PCIE_PHYADDR_SD)
+       {
                return (~0U);   
-       if (phy != BHND_PCIE_PHYADDR_SD || devaddr != BHND_PCIE_DEVAD_SD)
-               return (~0U);
+       }
 
        /* Enable MDIO access */
        BHND_PCI_LOCK(sc);
        bhnd_pcie_mdio_enable(sc);
 
-       /* Determine the block and register values */
-       blk = (reg & BHND_PCIE_SD_ADDREXT_BLK_MASK);
-       blk_reg = (reg & BHND_PCIE_SD_ADDREXT_REG_MASK);
-
        /* Write the block address to the address extension register */
-       cmd = BHND_PCIE_MDIODATA_ADDR(phy, BHND_PCIE_SD_ADDREXT) |
-           (blk & BHND_PCIE_MDIODATA_DATA_MASK);
+       cmd = BHND_PCIE_MDIODATA_ADDR(phy, BHND_PCIE_SD_ADDREXT) | devaddr;
        if ((error = bhnd_pcie_mdio_cmd_write(sc, cmd)))
                goto cleanup;
 
        /* Issue the write */
-       cmd = BHND_PCIE_MDIODATA_ADDR(phy, blk_reg) |
+       cmd = BHND_PCIE_MDIODATA_ADDR(phy, reg) |
            (val & BHND_PCIE_MDIODATA_DATA_MASK);
        error = bhnd_pcie_mdio_cmd_write(sc, cmd);
 

Modified: head/sys/dev/bhnd/cores/pci/bhnd_pci_hostb.c
==============================================================================
--- head/sys/dev/bhnd/cores/pci/bhnd_pci_hostb.c        Tue May 17 06:45:25 
2016        (r300014)
+++ head/sys/dev/bhnd/cores/pci/bhnd_pci_hostb.c        Tue May 17 06:52:53 
2016        (r300015)
@@ -56,28 +56,43 @@ __FBSDID("$FreeBSD$");
 
 #include <dev/bhnd/bhnd.h>
 
-#include "bhnd_pcireg.h"
-#include "bhnd_pci_hostbvar.h"
+#include <dev/pci/pcireg.h>
+#include <dev/pci/pcivar.h>
 
-#define        BHND_PCI_ASSERT_QUIRK(_sc, _name)       \
-    KASSERT((_sc)->quirks & (_name), ("quirk " __STRING(_name) " not set"))
+#include <dev/bhnd/cores/chipc/chipc.h>
+#include <dev/bhnd/cores/chipc/chipcreg.h>
 
-#define        BHND_PCI_DEV(_core, _quirks, _chip_quirks)              \
-       BHND_DEVICE(_core, "", _quirks, _chip_quirks, BHND_DF_HOSTB)
+#include "bhnd_pcireg.h"
+#include "bhnd_pci_hostbvar.h"
 
 static const struct bhnd_device_quirk bhnd_pci_quirks[];
 static const struct bhnd_device_quirk bhnd_pcie_quirks[];
+static const struct bhnd_chip_quirk bhnd_pci_chip_quirks[];
 static const struct bhnd_chip_quirk bhnd_pcie_chip_quirks[];
 
+/* Device driver work-around variations */
+typedef enum {
+       BHND_PCI_WAR_ATTACH,    /**< apply attach workarounds */
+       BHND_PCI_WAR_RESUME,    /**< apply resume workarounds */
+       BHND_PCI_WAR_SUSPEND,   /**< apply suspend workarounds */
+       BHND_PCI_WAR_DETACH     /**< apply detach workarounds */
+} bhnd_pci_war_state;
+
 static int     bhnd_pci_wars_early_once(struct bhnd_pcihb_softc *sc);
-static int     bhnd_pci_wars_hwup(struct bhnd_pcihb_softc *sc);
-static int     bhnd_pci_wars_hwdown(struct bhnd_pcihb_softc *sc);
+static int     bhnd_pci_wars_hwup(struct bhnd_pcihb_softc *sc,
+                   bhnd_pci_war_state state);
+static int     bhnd_pci_wars_hwdown(struct bhnd_pcihb_softc *sc,
+                   bhnd_pci_war_state state);
 
 /*
  * device/quirk tables
  */
+
+#define        BHND_PCI_DEV(_core, _quirks, _chip_quirks)              \
+       BHND_DEVICE(_core, "", _quirks, _chip_quirks, BHND_DF_HOSTB)
+
 static const struct bhnd_device bhnd_pci_devs[] = {
-       BHND_PCI_DEV(PCI,       bhnd_pci_quirks,        NULL),
+       BHND_PCI_DEV(PCI,       bhnd_pci_quirks,        bhnd_pci_chip_quirks),
        BHND_PCI_DEV(PCIE,      bhnd_pcie_quirks,       bhnd_pcie_chip_quirks),
        BHND_DEVICE_END
 };
@@ -89,12 +104,22 @@ static const struct bhnd_device_quirk bh
        BHND_DEVICE_QUIRK_END
 };
 
+static const struct bhnd_chip_quirk bhnd_pci_chip_quirks[] = {
+       /* BCM4321CB2 boards that require 960ns latency timer override */
+       {{ BHND_CHIP_BTYPE(BCM4321CB2) },
+               BHND_PCI_QUIRK_960NS_LATTIM_OVR },
+       {{ BHND_CHIP_BTYPE(BCM4321CB2_AG) },
+               BHND_PCI_QUIRK_960NS_LATTIM_OVR },
+
+       BHND_CHIP_QUIRK_END
+};
+
 static const struct bhnd_device_quirk bhnd_pcie_quirks[] = {
        { BHND_HWREV_EQ         (0),    BHND_PCIE_QUIRK_SDR9_L0s_HANG },
-       { BHND_HWREV_RANGE      (0, 1), BHND_PCIE_QUIRK_UR_STATUS_FIX },
+       { BHND_HWREV_RANGE      (0,1),  BHND_PCIE_QUIRK_UR_STATUS_FIX },
        { BHND_HWREV_EQ         (1),    BHND_PCIE_QUIRK_PCIPM_REQEN },
 
-       { BHND_HWREV_RANGE      (3, 5), BHND_PCIE_QUIRK_ASPM_OVR |
+       { BHND_HWREV_RANGE      (3,5),  BHND_PCIE_QUIRK_ASPM_OVR |
                                        BHND_PCIE_QUIRK_SDR9_POLARITY |
                                        BHND_PCIE_QUIRK_SDR9_NO_FREQRETRY },
 
@@ -102,37 +127,50 @@ static const struct bhnd_device_quirk bh
        { BHND_HWREV_GTE        (6),    BHND_PCIE_QUIRK_SPROM_L23_PCI_RESET },
        { BHND_HWREV_EQ         (7),    BHND_PCIE_QUIRK_SERDES_NOPLLDOWN },
        { BHND_HWREV_GTE        (8),    BHND_PCIE_QUIRK_L1_TIMER_PERF },
-       { BHND_HWREV_GTE        (10),   BHND_PCIE_QUIRK_SD_C22_EXTADDR },
+
+       { BHND_HWREV_LTE        (17),   BHND_PCIE_QUIRK_MAX_MRRS_128 },
+
        BHND_DEVICE_QUIRK_END
 };
 
 static const struct bhnd_chip_quirk bhnd_pcie_chip_quirks[] = {
        /* Apple boards on which BHND_BFL2_PCIEWAR_OVR should be assumed
         * to be set. */
-       {{ BHND_CHIP_BVENDOR            (PCI_VENDOR_APPLE),
-          BHND_CHIP_SROMREV            (HWREV_EQ(4)),
-          BHND_CHIP_BREV               (HWREV_LTE(0x71)) },
-          BHND_PCIE_QUIRK_BFL2_PCIEWAR_EN },
+       {{ BHND_CHIP_BVENDOR    (PCI_VENDOR_APPLE),
+          BHND_CHIP_SROMREV    (HWREV_EQ(4)),
+          BHND_CHIP_BREV       (HWREV_LTE(0x71)) },
+               BHND_PCIE_QUIRK_BFL2_PCIEWAR_EN         },
+
+       /* Apple BCM4322 boards that require 700mV SerDes TX drive strength. */
+       {{ BHND_CHIP_BVT        (PCI_VENDOR_APPLE,      BCM94322X9)     },
+               BHND_PCIE_QUIRK_SERDES_TXDRV_700MV      },
+
+       /* Apple BCM4331 board-specific quirks */
+#define        BHND_APPLE_4331_QUIRK(_board, ...)                              
\
+       {{ BHND_CHIP_ID         (4331),                                 \
+          BHND_CHIP_BVT        (PCI_VENDOR_APPLE,      _board), },     \
+               __VA_ARGS__ }
+
+       BHND_APPLE_4331_QUIRK(BCM94331X19,
+           BHND_PCIE_QUIRK_SERDES_TXDRV_MAX|BHND_PCIE_QUIRK_DEFAULT_MRRS_512),
+
+       BHND_APPLE_4331_QUIRK(BCM94331X28,
+           BHND_PCIE_QUIRK_SERDES_TXDRV_MAX|BHND_PCIE_QUIRK_DEFAULT_MRRS_512),
+       BHND_APPLE_4331_QUIRK(BCM94331X28B, BHND_PCIE_QUIRK_DEFAULT_MRRS_512),
+         
+       BHND_APPLE_4331_QUIRK(BCM94331X29B,
+           BHND_PCIE_QUIRK_SERDES_TXDRV_MAX|BHND_PCIE_QUIRK_DEFAULT_MRRS_512),
+
+       BHND_APPLE_4331_QUIRK(BCM94331X19C,
+           BHND_PCIE_QUIRK_SERDES_TXDRV_MAX|BHND_PCIE_QUIRK_DEFAULT_MRRS_512),
+           
+       BHND_APPLE_4331_QUIRK(BCM94331X29D, BHND_PCIE_QUIRK_DEFAULT_MRRS_512),
+       BHND_APPLE_4331_QUIRK(BCM94331X33, BHND_PCIE_QUIRK_DEFAULT_MRRS_512),
+#undef BHND_APPLE_4331_QUIRK
 
        BHND_CHIP_QUIRK_END
 };
 
-// Quirk handling TODO
-// WARs for the following are not yet implemented:
-// - BHND_PCIE_QUIRK_ASPM_OVR
-// - BHND_PCIE_QUIRK_BFL2_PCIEWAR_EN
-// - BHND_PCIE_QUIRK_SERDES_NOPLLDOWN
-// Quirks (and WARs) for the following are not yet defined:
-// - Power savings via MDIO BLK1/PWR_MGMT3 on PCIe hwrev 15-20, 21-22
-// - WOWL PME enable/disable
-// - 4360 PCIe SerDes Tx amplitude/deemphasis (vendor Apple, boards
-//   BCM94360X51P2, BCM94360X51A).
-// - PCI latency timer (boards CB2_4321_BOARD, CB2_4321_AG_BOARD)
-// - Max SerDes TX drive strength (vendor Apple, pcie >= rev10,
-//   board BCM94322X9)
-// - 700mV SerDes TX drive strength (chipid BCM4331, boards BCM94331X19,
-//   BCM94331X28, BCM94331X29B, BCM94331X19C)
-
 #define        BHND_PCI_SOFTC(_sc)     (&((_sc)->common))
 
 #define        BHND_PCI_READ_2(_sc, _reg)              \
@@ -159,6 +197,13 @@ static const struct bhnd_chip_quirk bhnd
 #define        BHND_PCI_MDIO_WRITE(_sc, _phy, _reg, _val)              \
        bhnd_pcie_mdio_write(BHND_PCI_SOFTC(_sc), (_phy), (_reg), (_val))
 
+#define        BHND_PCI_MDIO_READ_EXT(_sc, _phy, _devaddr, _reg)               
\
+       bhnd_pcie_mdio_read_ext(BHND_PCI_SOFTC(_sc), (_phy), (_devaddr), (_reg))
+
+#define        BHND_PCI_MDIO_WRITE_EXT(_sc, _phy, _devaddr, _reg, _val)        
\
+       bhnd_pcie_mdio_write_ext(BHND_PCI_SOFTC(_sc), (_phy),           \
+           (_devaddr), (_reg), (_val))
+
 #define        BPCI_REG_SET(_regv, _attr, _val)        \
        BHND_PCI_REG_SET((_regv), BHND_ ## _attr, (_val))
 
@@ -180,26 +225,34 @@ bhnd_pci_hostb_attach(device_t dev)
        int                      error;
 
        sc = device_get_softc(dev);
+       sc->dev = dev;
        sc->quirks = bhnd_device_quirks(dev, bhnd_pci_devs,
            sizeof(bhnd_pci_devs[0]));
 
+       /* Find the host PCI bridge device */
+       sc->pci_dev = bhnd_find_bridge_root(dev, devclass_find("pci"));
+       if (sc->pci_dev == NULL) {
+               device_printf(dev, "parent pci bridge device not found\n");
+               return (ENXIO);
+       }
+
+       /* Common setup */
        if ((error = bhnd_pci_generic_attach(dev)))
                return (error);
 
        /* Apply early single-shot work-arounds */
-       if ((error = bhnd_pci_wars_early_once(sc))) {
-               bhnd_pci_generic_detach(dev);
-               return (error);
-       }
+       if ((error = bhnd_pci_wars_early_once(sc)))
+               goto failed;
 
        /* Apply attach/resume work-arounds */
-       if ((error = bhnd_pci_wars_hwup(sc))) {
-               bhnd_pci_generic_detach(dev);
-               return (error);
-       }
-
+       if ((error = bhnd_pci_wars_hwup(sc, BHND_PCI_WAR_ATTACH)))
+               goto failed;
 
        return (0);
+       
+failed:
+       bhnd_pci_generic_detach(dev);
+       return (error);
 }
 
 static int
@@ -211,7 +264,7 @@ bhnd_pci_hostb_detach(device_t dev)
        sc = device_get_softc(dev);
 
        /* Apply suspend/detach work-arounds */
-       if ((error = bhnd_pci_wars_hwdown(sc)))
+       if ((error = bhnd_pci_wars_hwdown(sc, BHND_PCI_WAR_DETACH)))
                return (error);
 
        return (bhnd_pci_generic_detach(dev));
@@ -226,7 +279,7 @@ bhnd_pci_hostb_suspend(device_t dev)
        sc = device_get_softc(dev);
 
        /* Apply suspend/detach work-arounds */
-       if ((error = bhnd_pci_wars_hwdown(sc)))
+       if ((error = bhnd_pci_wars_hwdown(sc, BHND_PCI_WAR_SUSPEND)))
                return (error);
 
        return (bhnd_pci_generic_suspend(dev));
@@ -244,7 +297,7 @@ bhnd_pci_hostb_resume(device_t dev)
                return (error);
 
        /* Apply attach/resume work-arounds */
-       if ((error = bhnd_pci_wars_hwup(sc))) {
+       if ((error = bhnd_pci_wars_hwup(sc, BHND_PCI_WAR_RESUME))) {
                bhnd_pci_generic_detach(dev);
                return (error);
        }
@@ -263,6 +316,36 @@ bhnd_pci_hostb_resume(device_t dev)
 static int
 bhnd_pci_wars_early_once(struct bhnd_pcihb_softc *sc)
 {
+       int error;
+
+       /* Set PCI latency timer */
+       if (sc->quirks & BHND_PCI_QUIRK_960NS_LATTIM_OVR) {
+               pci_write_config(sc->pci_dev, PCIR_LATTIMER, 0x20 /* 960ns */,
+                   1); 
+       }
+
+       /* Determine whether ASPM/CLKREQ should be forced on, or forced off. */
+       if (sc->quirks & BHND_PCIE_QUIRK_ASPM_OVR) {
+               struct bhnd_board_info  board;
+               bool                    aspm_en;
+
+               /* Fetch board info */
+               if ((error = bhnd_read_board_info(sc->dev, &board)))
+                       return (error);
+               
+               /* Check board flags */
+               aspm_en = true;
+               if (board.board_flags2 & BHND_BFL2_PCIEWAR_OVR)
+                       aspm_en = false;
+
+               /* Early Apple devices did not (but should have) set
+                * BHND_BFL2_PCIEWAR_OVR in SPROM. */
+               if (sc->quirks & BHND_PCIE_QUIRK_BFL2_PCIEWAR_EN)
+                       aspm_en = false;
+
+               sc->aspm_quirk_override.aspm_en = aspm_en;
+       }
+
        /* Determine correct polarity by observing the attach-time PCIe PHY
         * link status. This is used later to reset/force the SerDes
         * polarity */
@@ -270,12 +353,23 @@ bhnd_pci_wars_early_once(struct bhnd_pci
                uint32_t st;
                bool inv;
 
-
                st = BHND_PCI_PROTO_READ_4(sc, BHND_PCIE_PLP_STATUSREG);
                inv = ((st & BHND_PCIE_PLP_POLARITY_INV) != 0);
                sc->sdr9_quirk_polarity.inv = inv;
        }
 
+       /* Override maximum read request size */
+       if (bhnd_get_class(sc->dev) == BHND_DEVCLASS_PCIE) {
+               int     msize;
+
+               msize = 128; /* compatible with all PCIe-G1 core revisions */
+               if (sc->quirks & BHND_PCIE_QUIRK_DEFAULT_MRRS_512)
+                       msize = 512;
+
+               if (pci_set_max_read_req(sc->pci_dev, msize) == 0)
+                       panic("set mrrs on non-PCIe device");
+       }
+
        return (0);
 }
 
@@ -284,7 +378,7 @@ bhnd_pci_wars_early_once(struct bhnd_pci
  * of the bridge device.
  */
 static int
-bhnd_pci_wars_hwup(struct bhnd_pcihb_softc *sc)
+bhnd_pci_wars_hwup(struct bhnd_pcihb_softc *sc, bhnd_pci_war_state state)
 {
        /* Note that the order here matters; these work-arounds
         * should not be re-ordered without careful review of their
@@ -407,6 +501,47 @@ bhnd_pci_wars_hwup(struct bhnd_pcihb_sof
                BHND_PCI_PROTO_WRITE_4(sc, BHND_PCIE_DLLP_PMTHRESHREG, pmt);
        }
 
+       /* Override ASPM/ECPM settings in SPROM shadow and PCIER_LINK_CTL */
+       if (sc->quirks & BHND_PCIE_QUIRK_ASPM_OVR) {
+               bus_size_t      reg;
+               uint16_t        cfg;
+
+               /* Set ASPM L1/L0s flags in SPROM shadow */
+               reg = BHND_PCIE_SPROM_SHADOW + BHND_PCIE_SRSH_ASPM_OFFSET;
+               cfg = BHND_PCI_READ_2(sc, reg);
+
+               if (sc->aspm_quirk_override.aspm_en)
+                       cfg |= BHND_PCIE_SRSH_ASPM_ENB;
+               else
+                       cfg &= ~BHND_PCIE_SRSH_ASPM_ENB;
+               
+               BHND_PCI_WRITE_2(sc, reg, cfg);
+
+
+               /* Set ASPM/ECPM (CLKREQ) flags in PCIe link control register */
+               cfg = pcie_read_config(sc->pci_dev, PCIER_LINK_CTL, 2);
+
+               if (sc->aspm_quirk_override.aspm_en)
+                       cfg |= PCIEM_LINK_CTL_ASPMC;
+               else
+                       cfg &= ~PCIEM_LINK_CTL_ASPMC;
+
+               cfg &= ~PCIEM_LINK_CTL_ECPM;            /* CLKREQ# */
+
+               pcie_write_config(sc->pci_dev, PCIER_LINK_CTL, cfg, 2); 
+
+               /* Set CLKREQ (ECPM) flags in SPROM shadow */
+               reg = BHND_PCIE_SPROM_SHADOW + BHND_PCIE_SRSH_CLKREQ_OFFSET_R5;
+               cfg = BHND_PCI_READ_2(sc, reg);
+               
+               if (sc->aspm_quirk_override.aspm_en)
+                       cfg |= BHND_PCIE_SRSH_CLKREQ_ENB;
+               else
+                       cfg &= ~BHND_PCIE_SRSH_CLKREQ_ENB;
+
+               BHND_PCI_WRITE_2(sc, reg, cfg);
+       }
+
        /* Enable L23READY_EXIT_NOPRST if not already set in SPROM. */
        if (sc->quirks & BHND_PCIE_QUIRK_SPROM_L23_PCI_RESET) {
                bus_size_t      reg;
@@ -423,6 +558,54 @@ bhnd_pci_wars_hwup(struct bhnd_pcihb_sof
                }
        }
 
+       /* Disable SerDes PLL down */
+       if (sc->quirks & BHND_PCIE_QUIRK_SERDES_NOPLLDOWN) {
+               device_t        bhnd, chipc;
+               bus_size_t      reg;
+               
+               bhnd = device_get_parent(sc->dev);
+               chipc = bhnd_find_child(bhnd, BHND_DEVCLASS_CC, 0);
+               KASSERT(chipc != NULL, ("missing chipcommon device"));
+
+               /* Write SerDes PLL disable flag to the ChipCommon core */
+               BHND_CHIPC_WRITE_CHIPCTRL(chipc, CHIPCTRL_4321_PLL_DOWN,
+                   CHIPCTRL_4321_PLL_DOWN);
+
+               /* Clear SPROM shadow backdoor register */
+               reg = BHND_PCIE_SPROM_SHADOW + BHND_PCIE_SRSH_BD_OFFSET;
+               BHND_PCI_WRITE_2(sc, reg, 0);
+       }
+
+       /* Adjust TX drive strength and pre-emphasis coefficient */
+       if (sc->quirks & BHND_PCIE_QUIRK_SERDES_TXDRV_ADJUST) {
+               uint16_t txdrv;
+
+               /* Fetch current TX driver parameters */
+               txdrv = BHND_PCI_MDIO_READ_EXT(sc, BHND_PCIE_PHYADDR_SD,
+                   BHND_PCIE_SD_REGS_TX0, BHND_PCIE_SD_TX_DRIVER);
+
+               /* Set 700mV drive strength */
+               if (sc->quirks & BHND_PCIE_QUIRK_SERDES_TXDRV_700MV) {
+                       txdrv = BPCI_REG_SET(txdrv, PCIE_SD_TX_DRIVER_P2_COEFF,
+                           BHND_PCIE_APPLE_TX_P2_COEFF_700MV);
+
+                       txdrv = BPCI_REG_SET(txdrv, PCIE_SD_TX_DRIVER_IDRIVER,
+                           BHND_PCIE_APPLE_TX_IDRIVER_700MV);
+               }
+
+               /* ... or, set max drive strength */
+               if (sc->quirks & BHND_PCIE_QUIRK_SERDES_TXDRV_MAX) {
+                       txdrv = BPCI_REG_SET(txdrv, PCIE_SD_TX_DRIVER_P2_COEFF,
+                           BHND_PCIE_APPLE_TX_P2_COEFF_MAX);
+                       
+                       txdrv = BPCI_REG_SET(txdrv, PCIE_SD_TX_DRIVER_IDRIVER,
+                           BHND_PCIE_APPLE_TX_IDRIVER_MAX);
+               }
+
+               BHND_PCI_MDIO_WRITE_EXT(sc, BHND_PCIE_PHYADDR_SD,
+                   BHND_PCIE_SD_REGS_TX0, BHND_PCIE_SD_TX_DRIVER, txdrv);
+       }
+
        return (0);
 }
 
@@ -431,8 +614,8 @@ bhnd_pci_wars_hwup(struct bhnd_pcihb_sof
  * of the bridge device.
  */
 static int
-bhnd_pci_wars_hwdown(struct bhnd_pcihb_softc *sc)
-{      
+bhnd_pci_wars_hwdown(struct bhnd_pcihb_softc *sc, bhnd_pci_war_state state)
+{
        /* Reduce L1 timer for better power savings.
         * TODO: We could enable/disable this on demand for better power
         * savings if we tie this to HT clock request handling */
@@ -443,6 +626,19 @@ bhnd_pci_wars_hwdown(struct bhnd_pcihb_s
                BHND_PCI_PROTO_WRITE_4(sc, BHND_PCIE_DLLP_PMTHRESHREG, pmt);
        }
 
+       /* Enable CLKREQ (ECPM). If suspending, also disable ASPM L1 entry */
+       if (sc->quirks & BHND_PCIE_QUIRK_ASPM_OVR) {
+               uint16_t        lcreg;
+
+               lcreg = pcie_read_config(sc->pci_dev, PCIER_LINK_CTL, 2);
+
+               lcreg |= PCIEM_LINK_CTL_ECPM;   /* CLKREQ# */
+               if (state == BHND_PCI_WAR_SUSPEND)
+                       lcreg &= ~PCIEM_LINK_CTL_ASPMC_L1;
+
+               pcie_write_config(sc->pci_dev, PCIER_LINK_CTL, lcreg, 2);
+       }
+
        return (0);
 }
 
@@ -456,10 +652,9 @@ static device_method_t bhnd_pci_hostb_me
        DEVMETHOD_END
 };
 
-DEFINE_CLASS_1(bhnd_pci_hostb, bhnd_pci_hostb_driver, bhnd_pci_hostb_methods, 
+DEFINE_CLASS_1(bhnd_hostb, bhnd_pci_hostb_driver, bhnd_pci_hostb_methods, 
     sizeof(struct bhnd_pcihb_softc), bhnd_pci_driver);
-
-DRIVER_MODULE(bhnd_hostb, bhnd, bhnd_pci_hostb_driver, bhnd_hostb_devclass, 0, 
0);
+DRIVER_MODULE(bhnd_pci_hostb, bhnd, bhnd_pci_hostb_driver, 
bhnd_hostb_devclass, 0, 0);
 
 MODULE_VERSION(bhnd_pci_hostb, 1);
 MODULE_DEPEND(bhnd_pci_hostb, bhnd, 1, 1, 1);

Modified: head/sys/dev/bhnd/cores/pci/bhnd_pci_hostbvar.h
==============================================================================
--- head/sys/dev/bhnd/cores/pci/bhnd_pci_hostbvar.h     Tue May 17 06:45:25 
2016        (r300014)
+++ head/sys/dev/bhnd/cores/pci/bhnd_pci_hostbvar.h     Tue May 17 06:52:53 
2016        (r300015)
@@ -43,7 +43,7 @@
 
 DECLARE_CLASS(bhnd_pci_hostb_driver);
 
-/* 
+/**
  * PCI/PCIe-Gen1 endpoint-mode device quirks
  */
 enum {
@@ -56,7 +56,6 @@ enum {
         */
        BHND_PCI_QUIRK_SBTOPCI2_PREF_BURST      = (1<<1),
 
-
        /**
         * SBTOPCI_RC_READMULTI must be set on the SSB_PCICORE_SBTOPCI2
         * register.
@@ -74,18 +73,24 @@ enum {
        BHND_PCI_QUIRK_CLKRUN_DSBL              = (1<<3),
 
        /**
+        * On PCI-attached BCM4321CB* boards, the PCI latency timer must be set
+        * to 960ns on initial attach.
+        */
+       BHND_PCI_QUIRK_960NS_LATTIM_OVR         = (1<<4),
+
+       /**
         * TLP workaround for unmatched address handling is required.
         * 
         * This TLP workaround will enable setting of the PCIe UR status bit
         * on memory access to an unmatched address.
         */
-       BHND_PCIE_QUIRK_UR_STATUS_FIX           = (1<<4),
+       BHND_PCIE_QUIRK_UR_STATUS_FIX           = (1<<5),
 
        /**
         * PCI-PM power management must be explicitly enabled via
         * the data link control register.
         */
-       BHND_PCIE_QUIRK_PCIPM_REQEN             = (1<<5),
+       BHND_PCIE_QUIRK_PCIPM_REQEN             = (1<<6),
 
        /**
         * Fix L0s to L0 exit transition on SerDes <= rev9 devices.
@@ -98,46 +103,50 @@ enum {
         * filters must be tweaked to ensure the CDR has fully stabilized
         * before asserting receive sequencer completion.
         */
-       BHND_PCIE_QUIRK_SDR9_L0s_HANG           = (1<<6),
+       BHND_PCIE_QUIRK_SDR9_L0s_HANG           = (1<<7),
 
        /**
         * The idle time for entering L1 low-power state must be
         * explicitly set (to 114ns) to fix slow L1->L0 transition issues.
         */
-       BHND_PCIE_QUIRK_L1_IDLE_THRESH          = (1<<7),
+       BHND_PCIE_QUIRK_L1_IDLE_THRESH          = (1<<8),
        
        /**
         * The ASPM L1 entry timer should be extended for better performance,
         * and restored for better power savings.
         */
-       BHND_PCIE_QUIRK_L1_TIMER_PERF           = (1<<8),
+       BHND_PCIE_QUIRK_L1_TIMER_PERF           = (1<<9),
 
        /**
         * ASPM and ECPM settings must be overridden manually.
+        * Applies to 4311B0/4321B1 chipset revisions.
         * 
         * The override behavior is controlled by the BHND_BFL2_PCIEWAR_OVR
-        * flag. If this flag is set, ASPM/CLKREQ should be overridden as

*** DIFF OUTPUT TRUNCATED AT 1000 LINES ***
_______________________________________________
svn-src-head@freebsd.org mailing list
https://lists.freebsd.org/mailman/listinfo/svn-src-head
To unsubscribe, send any mail to "svn-src-head-unsubscr...@freebsd.org"

Reply via email to