Index: head/sys/dev/bhnd/bcma/bcma_bhndb.c
===================================================================
--- head/sys/dev/bhnd/bcma/bcma_bhndb.c
+++ head/sys/dev/bhnd/bcma/bcma_bhndb.c
@@ -166,6 +166,20 @@
 	return (0);
 }
 
+static int
+bcma_bhndb_read_board_info(device_t dev, device_t child,
+    struct bhnd_board_info *info)
+{
+	int	error;
+
+	/* Initialize with NVRAM-derived values */
+	if ((error = bhnd_bus_generic_read_board_info(dev, child, info)))
+		return (error);
+
+	/* Let the bridge fill in any additional data */
+	return (BHNDB_POPULATE_BOARD_INFO(device_get_parent(dev), dev, info));
+}
+
 static device_method_t bcma_bhndb_methods[] = {
 	/* Device interface */
 	DEVMETHOD(device_probe,			bcma_bhndb_probe),
@@ -175,6 +189,9 @@
 	DEVMETHOD(bus_suspend_child,		bcma_bhndb_suspend_child),
 	DEVMETHOD(bus_resume_child,		bcma_bhndb_resume_child),
 
+	/* BHND interface */
+	DEVMETHOD(bhnd_bus_read_board_info,	bcma_bhndb_read_board_info),
+
 	DEVMETHOD_END
 };
 
Index: head/sys/dev/bhnd/bhnd.h
===================================================================
--- head/sys/dev/bhnd/bhnd.h
+++ head/sys/dev/bhnd/bhnd.h
@@ -110,6 +110,34 @@
 #undef	BHND_ACCESSOR
 
 /**
+ * A bhnd(4) board descriptor.
+ */
+struct bhnd_board_info {
+	uint16_t	board_vendor;	/**< PCI-SIG vendor ID (even on non-PCI
+					  *  devices).
+					  *
+					  *  On PCI devices, this will generally
+					  *  be the subsystem vendor ID, but the
+					  *  value may be overridden in device
+					  *  NVRAM.
+					  */
+	uint16_t	board_type;	/**< Board type (See BHND_BOARD_*)
+					  *
+					  *  On PCI devices, this will generally
+					  *  be the subsystem device ID, but the
+					  *  value may be overridden in device
+					  *  NVRAM.
+					  */
+	uint16_t	board_rev;	/**< Board revision. */
+	uint8_t		board_srom_rev;	/**< Board SROM format revision */
+
+	uint32_t	board_flags;	/**< Board flags (see BHND_BFL_*) */
+	uint32_t	board_flags2;	/**< Board flags 2 (see BHND_BFL2_*) */
+	uint32_t	board_flags3;	/**< Board flags 3 (see BHND_BFL3_*) */
+};
+
+
+/**
  * Chip Identification
  * 
  * This is read from the ChipCommon ID register; on earlier bhnd(4) devices
@@ -131,23 +159,10 @@
 };
 
 /**
-* A bhnd(4) bus resource.
-* 
-* This provides an abstract interface to per-core resources that may require
-* bus-level remapping of address windows prior to access.
-*/
-struct bhnd_resource {
-	struct resource	*res;		/**< the system resource. */
-	bool		 direct;	/**< false if the resource requires
-					 *   bus window remapping before it
-					 *   is MMIO accessible. */
-};
-
-/**
  * A bhnd(4) core descriptor.
  */
 struct bhnd_core_info {
-	uint16_t	vendor;		/**< vendor */
+	uint16_t	vendor;		/**< JEP-106 vendor (BHND_MFGID_*) */
 	uint16_t	device;		/**< device */
 	uint16_t	hwrev;		/**< hardware revision */
 	u_int		core_idx;	/**< bus-assigned core index */
@@ -165,6 +180,19 @@
 					     to match on any revision. */
 };
 
+/**
+* A bhnd(4) bus resource.
+* 
+* This provides an abstract interface to per-core resources that may require
+* bus-level remapping of address windows prior to access.
+*/
+struct bhnd_resource {
+	struct resource	*res;		/**< the system resource. */
+	bool		 direct;	/**< false if the resource requires
+					 *   bus window remapping before it
+					 *   is MMIO accessible. */
+};
+
 /** 
  * Wildcard hardware revision match descriptor.
  */
@@ -233,31 +261,51 @@
 		.unit = -1			\
 	}
 
-/** A chipset match descriptor. */
+/**
+ * A chipset match descriptor.
+ * 
+ * @warning Matching on board/nvram attributes relies on NVRAM access, and will
+ * fail if a valid NVRAM device cannot be found, or is not yet attached.
+ */
 struct bhnd_chip_match {
 	/** Select fields to be matched */
-	uint8_t
+	uint16_t
 		match_id:1,
 		match_rev:1,
 		match_pkg:1,
-		match_flags_unused:5;
+		match_bvendor:1,
+		match_btype:1,
+		match_brev:1,
+		match_srom_rev:1,
+		match_any:1,
+		match_flags_unused:8;
 
 	uint16_t		chip_id;	/**< required chip id */
 	struct bhnd_hwrev_match	chip_rev;	/**< matching chip revisions */
 	uint8_t			chip_pkg;	/**< required package */
+
+	uint16_t		board_vendor;	/**< required board vendor */
+	uint16_t		board_type;	/**< required board type */
+	struct bhnd_hwrev_match	board_rev;	/**< matching board revisions */
+
+	struct bhnd_hwrev_match	board_srom_rev;	/**< matching board srom revisions */
 };
 
 #define	BHND_CHIP_MATCH_ANY		\
-	{ .match_id = 0, .match_rev = 0, .match_pkg = 0 }
+	{ .match_any = 1 }
 
 #define	BHND_CHIP_MATCH_IS_ANY(_m)	\
-	((_m)->match_id == 0 && (_m)->match_rev == 0 && (_m)->match_pkg == 0)
+	((_m)->match_any == 1)
+
+#define	BHND_CHIP_MATCH_REQ_BOARD_INFO(_m)		\
+	((_m)->match_srom_rev || (_m)->match_bvendor ||	\
+	    (_m)->match_btype || (_m)->match_brev)
 
 /** Set the required chip ID within a bhnd_chip_match instance */
 #define	BHND_CHIP_ID(_cid)		\
 	.match_id = 1, .chip_id = BHND_CHIPID_BCM ## _cid
 
-/** Set the required revision range within a bhnd_chip_match instance */
+/** Set the required chip revision range within a bhnd_chip_match instance */
 #define	BHND_CHIP_REV(_rev)		\
 	.match_rev = 1, .chip_rev = BHND_ ## _rev
 
@@ -265,6 +313,31 @@
 #define	BHND_CHIP_PKG(_pkg)		\
 	.match_pkg = 1, .chip_pkg = BHND_PKGID_BCM ## _pkg
 
+/** Set the required board vendor within a bhnd_chip_match instance */
+#define	BHND_CHIP_BVENDOR(_vend)		\
+	.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
+
+/** Set the required SROM revision range within a bhnd_chip_match instance */
+#define	BHND_CHIP_SROMREV(_rev)		\
+	.match_srom_rev = 1, .board_srom_rev = BHND_ ## _rev
+
+/** Set the required board revision range within a bhnd_chip_match instance */
+#define	BHND_CHIP_BREV(_rev)	\
+	.match_brev = 1, .board_rev = BHND_ ## _rev
+
+/** 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)
+
+/** Set the required board vendor, type, and revision within a bhnd_chip_match
+ *  instance */
+#define	BHND_CHIP_BVTR(_vend, _type, _rev)	\
+	BHND_CHIP_BVT(_vend, _type), BHND_CHIP_BREV(_rev)
+
 /** Set the required chip and package ID within a bhnd_chip_match instance */
 #define	BHND_CHIP_IP(_cid, _pkg)	\
 	BHND_CHIP_ID(_cid), BHND_CHIP_PKG(_pkg)
@@ -314,23 +387,29 @@
 	const struct bhnd_core_match	 core;			/**< core match descriptor */ 
 	const char			*desc;			/**< device description, or NULL. */
 	const struct bhnd_device_quirk	*quirks_table;		/**< quirks table for this device, or NULL */
+	const struct bhnd_chip_quirk	*chip_quirks_table;	/**< chipset-specific quirks for this device, or NULL */
 	uint32_t			 device_flags;		/**< required BHND_DF_* flags */
 };
 
-#define	_BHND_DEVICE(_vendor, _device, _desc, _quirks, _flags, ...)	\
-	{ BHND_CORE_MATCH(BHND_MFGID_ ## _vendor, BHND_COREID_ ## _device, \
-	    BHND_HWREV_ANY), _desc, _quirks, _flags }
-
-#define	BHND_MIPS_DEVICE(_device, _desc, _quirks, ...)	\
-	_BHND_DEVICE(MIPS, _device, _desc, _quirks, ## __VA_ARGS__, 0)
-
-#define	BHND_ARM_DEVICE(_device, _desc, _quirks, ...)	\
-	_BHND_DEVICE(ARM, _device, _desc, _quirks, ## __VA_ARGS__, 0)
+#define	_BHND_DEVICE(_vendor, _device, _desc, _quirks, _chip_quirks,	\
+     _flags, ...)							\
+	{ BHND_CORE_MATCH(BHND_MFGID_ ## _vendor,			\
+	    BHND_COREID_ ## _device, BHND_HWREV_ANY), _desc, _quirks,	\
+	    _chip_quirks, _flags }
+
+#define	BHND_MIPS_DEVICE(_device, _desc, _quirks, _chip_quirks, ...)	\
+	_BHND_DEVICE(MIPS, _device, _desc, _quirks, _chip_quirks,	\
+	    ## __VA_ARGS__, 0)
+
+#define	BHND_ARM_DEVICE(_device, _desc, _quirks, _chip_quirks, ...)	\
+	_BHND_DEVICE(ARM, _device, _desc, _quirks, _chip_quirks,	\
+	    ## __VA_ARGS__, 0)
+
+#define	BHND_DEVICE(_device, _desc, _quirks, _chip_quirks, ...)		\
+	_BHND_DEVICE(BCM, _device, _desc, _quirks, _chip_quirks,	\
+	    ## __VA_ARGS__, 0)
 
-#define	BHND_DEVICE(_device, _desc, _quirks, ...)	\
-	_BHND_DEVICE(BCM, _device, _desc, _quirks, ## __VA_ARGS__, 0)
-
-#define	BHND_DEVICE_END			{ BHND_CORE_MATCH_ANY, NULL, NULL, 0 }
+#define	BHND_DEVICE_END	{ BHND_CORE_MATCH_ANY, NULL, NULL, NULL, 0 }
 
 const char			*bhnd_vendor_name(uint16_t vendor);
 const char			*bhnd_port_type_name(bhnd_port_type port_type);
@@ -365,6 +444,7 @@
 
 bool				 bhnd_chip_matches(
 				     const struct bhnd_chipid *chipid,
+				     const struct bhnd_board_info *binfo,
 				     const struct bhnd_chip_match *desc);
 
 bool				 bhnd_hwrev_matches(uint16_t hwrev,
@@ -418,6 +498,12 @@
 				     void *buf, size_t *size);
 const struct bhnd_chipid	*bhnd_bus_generic_get_chipid(device_t dev,
 				     device_t child);
+int				 bhnd_bus_generic_read_board_info(device_t dev,
+				     device_t child,
+				     struct bhnd_board_info *info);
+int				 bhnd_bus_generic_get_nvram_var(device_t dev,
+				    device_t child, const char *name,
+				    void *buf, size_t *size);
 struct bhnd_resource		*bhnd_bus_generic_alloc_resource (device_t dev,
 				     device_t child, int type, int *rid,
 				     rman_res_t start, rman_res_t end,
@@ -472,6 +558,28 @@
 };
 
 /**
+ * Attempt to read the BHND board identification from the bhnd bus.
+ *
+ * This relies on NVRAM access, and will fail if a valid NVRAM device cannot
+ * be found, or is not yet attached.
+ *
+ * @param dev The parent of @p child.
+ * @param child The bhnd device requesting board info.
+ * @param[out] info On success, will be populated with the bhnd(4) device's
+ * board information.
+ *
+ * @retval 0 success
+ * @retval ENODEV	No valid NVRAM source could be found.
+ * @retval non-zero	If reading @p name otherwise fails, a regular unix
+ *			error code will be returned.
+ */
+static inline int
+bhnd_read_board_info(device_t dev, struct bhnd_board_info *info)
+{
+	return (BHND_BUS_READ_BOARD_INFO(device_get_parent(dev), dev, info));
+}
+
+/**
  * Determine an NVRAM variable's expected size.
  *
  * @param 	dev	A bhnd bus child device.
@@ -480,6 +588,7 @@
  *
  * @retval 0		success
  * @retval ENOENT	The requested variable was not found.
+ * @retval ENODEV	No valid NVRAM source could be found.
  * @retval non-zero	If reading @p name otherwise fails, a regular unix
  *			error code will be returned.
  */
@@ -502,6 +611,7 @@
  * @retval 0		success
  * @retval ENOENT	The requested variable was not found.
  * @retval EINVAL	If @p len does not match the actual variable size.
+ * @retval ENODEV	No valid NVRAM source could be found.
  * @retval non-zero	If reading @p name otherwise fails, a regular unix
  *			error code will be returned.
  */
Index: head/sys/dev/bhnd/bhnd.c
===================================================================
--- head/sys/dev/bhnd/bhnd.c
+++ head/sys/dev/bhnd/bhnd.c
@@ -58,11 +58,6 @@
 #include <sys/rman.h>
 #include <machine/resource.h>
 
-#include "nvram/bhnd_nvram.h"
-
-#include "bhnd_chipc_if.h"
-#include "bhnd_nvram_if.h"
-
 #include "bhnd.h"
 #include "bhndvar.h"
 
@@ -85,8 +80,6 @@
 	{ BHND_MFGID_INVALID,	BHND_COREID_INVALID,		false	}
 };
 
-static device_t	find_nvram_child(device_t dev);
-
 static int	compare_ascending_probe_order(const void *lhs,
 		    const void *rhs);
 static int	compare_descending_probe_order(const void *lhs,
@@ -314,7 +307,9 @@
 {
 	switch (bhnd_get_class(child)) {
 	case BHND_DEVCLASS_CC:
-		return (BHND_PROBE_BUS + BHND_PROBE_ORDER_FIRST);
+		/* Must be early enough to provide NVRAM access to the
+		 * host bridge */
+		return (BHND_PROBE_ROOT + BHND_PROBE_ORDER_FIRST);
 
 	case BHND_DEVCLASS_CC_B:
 		/* fall through */
@@ -381,68 +376,6 @@
 }
 
 /**
- * Find an NVRAM child device on @p dev, if any.
- * 
- * @retval device_t An NVRAM device.
- * @retval NULL If no NVRAM device is found.
- */
-static device_t
-find_nvram_child(device_t dev)
-{
-	device_t	chipc, nvram;
-
-	/* Look for a directly-attached NVRAM child */
-	nvram = device_find_child(dev, "bhnd_nvram", 0);
-	if (nvram != NULL)
-		return (nvram);
-
-	/* Remaining checks are only applicable when searching a bhnd(4)
-	 * bus. */
-	if (device_get_devclass(dev) != bhnd_devclass)
-		return (NULL);
-
-	/* Look for a ChipCommon device */
-	if ((chipc = bhnd_find_child(dev, BHND_DEVCLASS_CC, -1)) != NULL) {
-		bhnd_nvram_src_t src;
-
-		/* Query the NVRAM source and determine whether it's
-		 * accessible via the ChipCommon device */
-		src = BHND_CHIPC_NVRAM_SRC(chipc);
-		if (BHND_NVRAM_SRC_CC(src))
-			return (chipc);
-	}
-
-	/* Not found */
-	return (NULL);
-}
-
-/**
- * Default bhnd(4) bus driver implementation of BHND_BUS_GET_NVRAM_VAR().
- * 
- * This implementation searches @p dev for a usable NVRAM child device:
- * - The first child device implementing the bhnd_nvram devclass is
- *   returned, otherwise
- * - If @p dev is a bhnd(4) bus, a ChipCommon core that advertises an
- *   attached NVRAM source.
- * 
- * If no usable child device is found on @p dev, the request is delegated to
- * the BHND_BUS_GET_NVRAM_VAR() method on the parent of @p dev.
- */
-static int
-bhnd_generic_get_nvram_var(device_t dev, device_t child, const char *name,
-    void *buf, size_t *size)
-{
-	device_t nvram;
-
-	/* Try to find an NVRAM device applicable to @p child */
-	if ((nvram = find_nvram_child(dev)) == NULL)
-		return (BHND_BUS_GET_NVRAM_VAR(device_get_parent(dev), child,
-		    name, buf, size));
-
-	return BHND_NVRAM_GETVAR(nvram, name, buf, size);
-}
-
-/**
  * Default bhnd(4) bus driver implementation of BUS_PRINT_CHILD().
  * 
  * This implementation requests the device's struct resource_list via
@@ -693,7 +626,7 @@
 	DEVMETHOD(bhnd_bus_get_probe_order,	bhnd_generic_get_probe_order),
 	DEVMETHOD(bhnd_bus_is_region_valid,	bhnd_generic_is_region_valid),
 	DEVMETHOD(bhnd_bus_is_hw_disabled,	bhnd_bus_generic_is_hw_disabled),
-	DEVMETHOD(bhnd_bus_get_nvram_var,	bhnd_generic_get_nvram_var),
+	DEVMETHOD(bhnd_bus_get_nvram_var,	bhnd_bus_generic_get_nvram_var),
 	DEVMETHOD(bhnd_bus_read_1,		bhnd_read_1),
 	DEVMETHOD(bhnd_bus_read_2,		bhnd_read_2),
 	DEVMETHOD(bhnd_bus_read_4,		bhnd_read_4),
Index: head/sys/dev/bhnd/bhnd_bus_if.m
===================================================================
--- head/sys/dev/bhnd/bhnd_bus_if.m
+++ head/sys/dev/bhnd/bhnd_bus_if.m
@@ -38,10 +38,10 @@
 
 HEADER {
 	/* forward declarations */
+	struct bhnd_board_info;
 	struct bhnd_core_info;
 	struct bhnd_chipid;
 	struct bhnd_resource;
-	struct bhnd_bus_ctx;
 }
 
 CODE {
@@ -54,7 +54,14 @@
 	{
 		panic("bhnd_bus_get_chipid unimplemented");
 	}
-	
+
+	static int
+	bhnd_bus_null_read_board_info(device_t dev, device_t child,
+	    struct bhnd_board_info *info)
+	{
+		panic("bhnd_bus_read_boardinfo unimplemented");
+	}
+
 	static device_t
 	bhnd_bus_null_find_hostb_device(device_t dev)
 	{
@@ -99,7 +106,7 @@
 	bhnd_bus_null_get_nvram_var(device_t dev, device_t child,
 	    const char *name, void *buf, size_t *size)
 	{
-		return (ENOENT);
+		return (ENODEV);
 	}
 
 }
@@ -177,6 +184,28 @@
 } DEFAULT bhnd_bus_null_get_chipid;
 
 /**
+ * Attempt to read the BHND board identification from the parent bus.
+ *
+ * This relies on NVRAM access, and will fail if a valid NVRAM device cannot
+ * be found, or is not yet attached.
+ *
+ * @param dev The parent of @p child.
+ * @param child The bhnd device requesting board info.
+ * @param[out] info On success, will be populated with the bhnd(4) device's
+ * board information.
+ *
+ * @retval 0 success
+ * @retval ENODEV	No valid NVRAM source could be found.
+ * @retval non-zero	If reading @p name otherwise fails, a regular unix
+ *			error code will be returned.
+ */
+METHOD int read_board_info {
+	device_t dev;
+	device_t child;
+	struct bhnd_board_info *info;
+} DEFAULT bhnd_bus_null_read_board_info;
+
+/**
  * Reset the device's hardware core.
  *
  * @param dev The parent of @p child.
@@ -400,6 +429,7 @@
  * @retval ENOENT	The requested variable was not found.
  * @retval ENOMEM	If @p buf is non-NULL and a buffer of @p size is too
  *			small to hold the requested value.
+ * @retval ENODEV	No valid NVRAM source could be found.
  * @retval non-zero	If reading @p name otherwise fails, a regular unix
  *			error code will be returned.
  */
Index: head/sys/dev/bhnd/bhnd_ids.h
===================================================================
--- head/sys/dev/bhnd/bhnd_ids.h
+++ head/sys/dev/bhnd/bhnd_ids.h
@@ -1,10 +1,12 @@
 /*-
- * Copyright (C) 1999-2013, Broadcom Corporation
+ * Copyright (c) 2015-2016 Landon Fuller <landon@landonf.org>
+ * Copyright (c) 1999-2015, Broadcom Corporation
  * 
  * This file is derived from the bcmdevs.h header contributed by Broadcom 
- * to Android's bcmdhd driver module, and the hndsoc.h header distributed with
- * with Broadcom's initial brcm80211 Linux driver release, as contributed to 
- * the Linux staging repository. 
+ * to Android's bcmdhd driver module, later revisions of bcmdevs.h distributed
+ * with the dd-wrt project, and the hndsoc.h header distributed with Broadcom's
+ * initial brcm80211 Linux driver release as contributed to the Linux staging
+ * repository.
  * 
  * Permission to use, copy, modify, and/or distribute this software for any
  * purpose with or without fee is hereby granted, provided that the above
@@ -18,8 +20,6 @@
  * OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN
  * CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
  *
- * $Id: bcmdevs.h 387183 2013-02-24 07:42:07Z $
- * 
  * $FreeBSD$
  */
 
@@ -669,22 +669,22 @@
 
 
 /* board specific GPIO assignment, gpio 0-3 are also customer-configurable led */
-#define	BHND_BOARD_GPIO_BTC3W_IN	0x850	/* bit 4 is RF_ACTIVE, bit 6 is STATUS, bit 11 is PRI */
-#define	BHND_BOARD_GPIO_BTC3W_OUT	0x020	/* bit 5 is TX_CONF */
-#define	BHND_BOARD_GPIO_BTCMOD_IN	0x010	/* bit 4 is the alternate BT Coexistence Input */
-#define	BHND_BOARD_GPIO_BTCMOD_OUT	0x020	/* bit 5 is the alternate BT Coexistence Out */
-#define	BHND_BOARD_GPIO_BTC_IN		0x080	/* bit 7 is BT Coexistence Input */
-#define	BHND_BOARD_GPIO_BTC_OUT		0x100	/* bit 8 is BT Coexistence Out */
-#define	BHND_BOARD_GPIO_PACTRL		0x200	/* bit 9 controls the PA on new 4306 boards */
-#define	BHND_BOARD_GPIO_12		0x1000	/* gpio 12 */
-#define	BHND_BOARD_GPIO_13		0x2000	/* gpio 13 */
-#define	BHND_BOARD_GPIO_BTC4_IN		0x0800	/* gpio 11, coex4, in */
-#define	BHND_BOARD_GPIO_BTC4_BT		0x2000	/* gpio 12, coex4, bt active */
-#define	BHND_BOARD_GPIO_BTC4_STAT	0x4000	/* gpio 14, coex4, status */
-#define	BHND_BOARD_GPIO_BTC4_WLAN	0x8000	/* gpio 15, coex4, wlan active */
-#define	BHND_BOARD_GPIO_1_WLAN_PWR	0x02	/* throttle WLAN power on X21 board */
-#define	BHND_BOARD_GPIO_3_WLAN_PWR	0x08	/* throttle WLAN power on X28 board */
-#define	BHND_BOARD_GPIO_4_WLAN_PWR	0x10	/* throttle WLAN power on X19 board */
+#define	BHND_GPIO_BOARD_BTC3W_IN	0x850	/* bit 4 is RF_ACTIVE, bit 6 is STATUS, bit 11 is PRI */
+#define	BHND_GPIO_BOARD_BTC3W_OUT	0x020	/* bit 5 is TX_CONF */
+#define	BHND_GPIO_BOARD_BTCMOD_IN	0x010	/* bit 4 is the alternate BT Coexistence Input */
+#define	BHND_GPIO_BOARD_BTCMOD_OUT	0x020	/* bit 5 is the alternate BT Coexistence Out */
+#define	BHND_GPIO_BOARD_BTC_IN		0x080	/* bit 7 is BT Coexistence Input */
+#define	BHND_GPIO_BOARD_BTC_OUT		0x100	/* bit 8 is BT Coexistence Out */
+#define	BHND_GPIO_BOARD_PACTRL		0x200	/* bit 9 controls the PA on new 4306 boards */
+#define	BHND_GPIO_BOARD_12		0x1000	/* gpio 12 */
+#define	BHND_GPIO_BOARD_13		0x2000	/* gpio 13 */
+#define	BHND_GPIO_BOARD_BTC4_IN		0x0800	/* gpio 11, coex4, in */
+#define	BHND_GPIO_BOARD_BTC4_BT		0x2000	/* gpio 12, coex4, bt active */
+#define	BHND_GPIO_BOARD_BTC4_STAT	0x4000	/* gpio 14, coex4, status */
+#define	BHND_GPIO_BOARD_BTC4_WLAN	0x8000	/* gpio 15, coex4, wlan active */
+#define	BHND_GPIO_BOARD_1_WLAN_PWR	0x02	/* throttle WLAN power on X21 board */
+#define	BHND_GPIO_BOARD_3_WLAN_PWR	0x08	/* throttle WLAN power on X28 board */
+#define	BHND_GPIO_BOARD_4_WLAN_PWR	0x10	/* throttle WLAN power on X19 board */
 
 #define	BHND_GPIO_BTC4W_OUT_4312	0x010	/* bit 4 is BT_IODISABLE */
 #define	BHND_GPIO_BTC4W_OUT_43224	0x020	/* bit 5 is BT_IODISABLE */
@@ -700,11 +700,385 @@
 #define	BHND_CHIPC_MIN_SLOW_CLK		32	/* us Slow clock period */
 #define	BHND_CHIPC_XTAL_ON_DELAY	1000	/* us crystal power-on delay */
 
+/* Board Types */
+#define	BHND_BOARD_BU4710		0x0400
+#define	BHND_BOARD_VSIM4710		0x0401
+#define	BHND_BOARD_QT4710		0x0402
+
+#define	BHND_BOARD_BU4309		0x040a
+#define	BHND_BOARD_BCM94309CB		0x040b
+#define	BHND_BOARD_BCM94309MP		0x040c
+#define	BHND_BOARD_BCM4309AP		0x040d
+
+#define	BHND_BOARD_BCM94302MP		0x040e
+
+#define	BHND_BOARD_BU4306		0x0416
+#define	BHND_BOARD_BCM94306CB		0x0417
+#define	BHND_BOARD_BCM94306MP		0x0418
+
+#define	BHND_BOARD_BCM94710D		0x041a
+#define	BHND_BOARD_BCM94710R1		0x041b
+#define	BHND_BOARD_BCM94710R4		0x041c
+#define	BHND_BOARD_BCM94710AP		0x041d
+
+#define	BHND_BOARD_BU2050		0x041f
+
+
+#define	BHND_BOARD_BCM94309G		0x0421
+
+#define	BHND_BOARD_BU4704		0x0423
+#define	BHND_BOARD_BU4702		0x0424
+
+#define	BHND_BOARD_BCM94306PC		0x0425		/* pcmcia 3.3v 4306 card */
+
+
+#define	BHND_BOARD_BCM94702MN		0x0428
+
+/* BCM4702 1U CompactPCI Board */
+#define	BHND_BOARD_BCM94702CPCI		0x0429
+
+/* BCM4702 with BCM95380 VLAN Router */
+#define	BHND_BOARD_BCM95380RR		0x042a
+
+/* cb4306 with SiGe PA */
+#define	BHND_BOARD_BCM94306CBSG		0x042b
+
+/* cb4306 with SiGe PA */
+#define	BHND_BOARD_PCSG94306		0x042d
+
+/* bu4704 with sdram */
+#define	BHND_BOARD_BU4704SD		0x042e
+
+/* Dual 11a/11g Router */
+#define	BHND_BOARD_BCM94704AGR		0x042f
+
+/* 11a-only minipci */
+#define	BHND_BOARD_BCM94308MP		0x0430
+
+
+
+#define	BHND_BOARD_BU4712		0x0444
+#define	BHND_BOARD_BU4712SD		0x045d
+#define	BHND_BOARD_BU4712L		0x045f
+
+/* BCM4712 boards */
+#define	BHND_BOARD_BCM94712AP		0x0445
+#define	BHND_BOARD_BCM94712P		0x0446
+
+/* BCM4318 boards */
+#define	BHND_BOARD_BU4318		0x0447
+#define	BHND_BOARD_CB4318		0x0448
+#define	BHND_BOARD_MPG4318		0x0449
+#define	BHND_BOARD_MP4318		0x044a
+#define	BHND_BOARD_SD4318		0x044b
+
+/* BCM4313 boards */
+#define	BHND_BOARD_BCM94313BU		0x050f
+#define	BHND_BOARD_BCM94313HM		0x0510
+#define	BHND_BOARD_BCM94313EPA		0x0511
+#define	BHND_BOARD_BCM94313HMG		0x051C
+
+/* BCM63XX boards */
+#define	BHND_BOARD_BCM96338		0x6338
+#define	BHND_BOARD_BCM96348		0x6348
+#define	BHND_BOARD_BCM96358		0x6358
+#define	BHND_BOARD_BCM96368		0x6368
+
+/* Another mp4306 with SiGe */
+#define	BHND_BOARD_BCM94306P		0x044c
+
+/* mp4303 */
+#define	BHND_BOARD_BCM94303MP		0x044e
+
+/* mpsgh4306 */
+#define	BHND_BOARD_BCM94306MPSGH	0x044f
+
+/* BRCM 4306 w/ Front End Modules */
+#define	BHND_BOARD_BCM94306MPM		0x0450
+#define	BHND_BOARD_BCM94306MPL		0x0453
+
+/* 4712agr */
+#define	BHND_BOARD_BCM94712AGR		0x0451
+
+/* pcmcia 4303 */
+#define	BHND_BOARD_PC4303		0x0454
+
+/* 5350K */
+#define	BHND_BOARD_BCM95350K		0x0455
+
+/* 5350R */
+#define	BHND_BOARD_BCM95350R		0x0456
+
+/* 4306mplna */
+#define	BHND_BOARD_BCM94306MPLNA	0x0457
+
+/* 4320 boards */
+#define	BHND_BOARD_BU4320		0x0458
+#define	BHND_BOARD_BU4320S		0x0459
+#define	BHND_BOARD_BCM94320PH		0x045a
+
+/* 4306mph */
+#define	BHND_BOARD_BCM94306MPH		0x045b
+
+/* 4306pciv */
+#define	BHND_BOARD_BCM94306PCIV		0x045c
+
+#define	BHND_BOARD_BU4712SD		0x045d
+
+#define	BHND_BOARD_BCM94320PFLSH	0x045e
+
+#define	BHND_BOARD_BU4712L		0x045f
+#define	BHND_BOARD_BCM94712LGR		0x0460
+#define	BHND_BOARD_BCM94320R		0x0461
+
+#define	BHND_BOARD_BU5352		0x0462
+
+#define	BHND_BOARD_BCM94318MPGH		0x0463
+
+#define	BHND_BOARD_BU4311		0x0464
+#define	BHND_BOARD_BCM94311MC		0x0465
+#define	BHND_BOARD_BCM94311MCAG		0x0466
+
+#define	BHND_BOARD_BCM95352GR		0x0467
+
+/* bcm95351agr */
+#define	BHND_BOARD_BCM95351AGR		0x0470
+
+/* bcm94704mpcb */
+#define	BHND_BOARD_BCM94704MPCB		0x0472
+
+/* 4785 boards */
+#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
+
+/* 4328 boards */
+#define	BHND_BOARD_BU4328		0x0481
+#define	BHND_BOARD_BCM4328SDG		0x0482
+#define	BHND_BOARD_BCM4328SDAG		0x0483
+#define	BHND_BOARD_BCM4328UG		0x0484
+#define	BHND_BOARD_BCM4328UAG		0x0485
+#define	BHND_BOARD_BCM4328PC		0x0486
+#define	BHND_BOARD_BCM4328CF		0x0487
+
+/* 4325 boards */
+#define	BHND_BOARD_BCM94325DEVBU	0x0490
+#define	BHND_BOARD_BCM94325BGABU	0x0491
+
+#define	BHND_BOARD_BCM94325SDGWB	0x0492
+
+#define	BHND_BOARD_BCM94325SDGMDL	0x04aa
+#define	BHND_BOARD_BCM94325SDGMDL2	0x04c6
+#define	BHND_BOARD_BCM94325SDGMDL3	0x04c9
+
+#define	BHND_BOARD_BCM94325SDABGWBA	0x04e1
+
+/* 4322 boards */
+#define	BHND_BOARD_BCM94322MC		0x04a4
+#define	BHND_BOARD_BCM94322USB		0x04a8	/* dualband */
+#define	BHND_BOARD_BCM94322HM		0x04b0
+#define	BHND_BOARD_BCM94322USB2D	0x04bf	/* single band discrete front end */
+
+/* 4312 boards */
+#define	BHND_BOARD_BCM4312MCGSG		0x04b5
+
+/* 4315 boards */
+#define	BHND_BOARD_BCM94315DEVBU	0x04c2
+#define	BHND_BOARD_BCM94315USBGP	0x04c7
+#define	BHND_BOARD_BCM94315BGABU	0x04ca
+#define	BHND_BOARD_BCM94315USBGP41	0x04cb
+
+/* 4319 boards */
+#define	BHND_BOARD_BCM94319DEVBU	0X04e5
+#define	BHND_BOARD_BCM94319USB		0X04e6
+#define	BHND_BOARD_BCM94319SD		0X04e7
+
+/* 4716 boards */
+#define	BHND_BOARD_BCM94716NR2		0x04cd
+
+/* 4319 boards */
+#define	BHND_BOARD_BCM94319DEVBU	0X04e5
+#define	BHND_BOARD_BCM94319USBNP4L	0X04e6
+#define	BHND_BOARD_BCM94319WLUSBN4L	0X04e7
+#define	BHND_BOARD_BCM94319SDG		0X04ea
+#define	BHND_BOARD_BCM94319LCUSBSDN4L	0X04eb
+#define	BHND_BOARD_BCM94319USBB		0x04ee
+#define	BHND_BOARD_BCM94319LCSDN4L	0X0507
+#define	BHND_BOARD_BCM94319LSUSBN4L	0X0508
+#define	BHND_BOARD_BCM94319SDNA4L	0X0517
+#define	BHND_BOARD_BCM94319SDELNA4L	0X0518
+#define	BHND_BOARD_BCM94319SDELNA6L	0X0539
+#define	BHND_BOARD_BCM94319ARCADYAN	0X0546
+#define	BHND_BOARD_BCM94319WINDSOR	0x0561
+#define	BHND_BOARD_BCM94319MLAP		0x0562
+#define	BHND_BOARD_BCM94319SDNA		0x058b
+#define	BHND_BOARD_BCM94319BHEMU3	0x0563
+#define	BHND_BOARD_BCM94319SDHMB	0x058c
+#define	BHND_BOARD_BCM94319SDBREF	0x05a1
+#define	BHND_BOARD_BCM94319USBSDB	0x05a2
+
+/* 4329 boards */
+#define	BHND_BOARD_BCM94329AGB		0X04b9
+#define	BHND_BOARD_BCM94329TDKMDL1	0X04ba
+#define	BHND_BOARD_BCM94329TDKMDL11	0X04fc
+#define	BHND_BOARD_BCM94329OLYMPICN18	0X04fd
+#define	BHND_BOARD_BCM94329OLYMPICN90	0X04fe
+#define	BHND_BOARD_BCM94329OLYMPICN90U	0X050c
+#define	BHND_BOARD_BCM94329OLYMPICN90M	0X050b
+#define	BHND_BOARD_BCM94329AGBF		0X04ff
+#define	BHND_BOARD_BCM94329OLYMPICX17	0X0504
+#define	BHND_BOARD_BCM94329OLYMPICX17M	0X050a
+#define	BHND_BOARD_BCM94329OLYMPICX17U	0X0509
+#define	BHND_BOARD_BCM94329OLYMPICUNO	0X0564
+#define	BHND_BOARD_BCM94329MOTOROLA	0X0565
+#define	BHND_BOARD_BCM94329OLYMPICLOCO	0X0568
+
+/* 4336 SDIO board types */
+#define	BHND_BOARD_BCM94336SD_WLBGABU	0x0511
+#define	BHND_BOARD_BCM94336SD_WLBGAREF	0x0519
+#define	BHND_BOARD_BCM94336SDGP		0x0538
+#define	BHND_BOARD_BCM94336SDG		0x0519
+#define	BHND_BOARD_BCM94336SDGN		0x0538
+#define	BHND_BOARD_BCM94336SDGFC	0x056B
+
+/* 4330 SDIO board types */
+#define	BHND_BOARD_BCM94330SDG		0x0528
+#define	BHND_BOARD_BCM94330SD_FCBGABU	0x052e
+#define	BHND_BOARD_BCM94330SD_WLBGABU	0x052f
+#define	BHND_BOARD_BCM94330SD_FCBGA	0x0530
+#define	BHND_BOARD_BCM94330FCSDAGB	0x0532
+#define	BHND_BOARD_BCM94330OLYMPICAMG	0x0549
+#define	BHND_BOARD_BCM94330OLYMPICAMGEPA	0x054F
+#define	BHND_BOARD_BCM94330OLYMPICUNO3	0x0551
+#define	BHND_BOARD_BCM94330WLSDAGB	0x0547
+#define	BHND_BOARD_BCM94330CSPSDAGBB	0x054A
+
+/* 43224 boards */
+#define	BHND_BOARD_BCM943224X21		0x056e
+#define	BHND_BOARD_BCM943224X21_FCC	0x00d1
+#define	BHND_BOARD_BCM943224X21B	0x00e9
+#define	BHND_BOARD_BCM943224M93		0x008b
+#define	BHND_BOARD_BCM943224M93A	0x0090
+#define	BHND_BOARD_BCM943224X16		0x0093
+#define	BHND_BOARD_BCM94322X9		0x008d
+#define	BHND_BOARD_BCM94322M35e		0x008e
+
+/* 43228 Boards */
+#define	BHND_BOARD_BCM943228BU8		0x0540
+#define	BHND_BOARD_BCM943228BU9		0x0541
+#define	BHND_BOARD_BCM943228BU		0x0542
+#define	BHND_BOARD_BCM943227HM4L	0x0543
+#define	BHND_BOARD_BCM943227HMB		0x0544
+#define	BHND_BOARD_BCM943228HM4L	0x0545
+#define	BHND_BOARD_BCM943228SD		0x0573
+
+/* 43239 Boards */
+#define	BHND_BOARD_BCM943239MOD		0x05ac
+#define	BHND_BOARD_BCM943239REF		0x05aa
+
+/* 4331 boards */
+#define	BHND_BOARD_BCM94331X19		0x00D6	/* X19B */
+#define	BHND_BOARD_BCM94331X28		0x00E4	/* X28 */
+#define	BHND_BOARD_BCM94331X28B		0x010E	/* X28B */
+#define	BHND_BOARD_BCM94331PCIEBT3Ax	BCM94331X28
+#define	BHND_BOARD_BCM94331X12_2G	0x00EC	/* X12 2G */
+#define	BHND_BOARD_BCM94331X12_5G	0x00ED	/* X12 5G */
+#define	BHND_BOARD_BCM94331X29B		0x00EF	/* X29B */
+#define	BHND_BOARD_BCM94331X29D		0x010F	/* X29D */
+#define	BHND_BOARD_BCM94331CSAX		BCM94331X29B
+#define	BHND_BOARD_BCM94331X19C		0x00F5	/* X19C */
+#define	BHND_BOARD_BCM94331X33		0x00F4	/* X33 */
+#define	BHND_BOARD_BCM94331BU		0x0523
+#define	BHND_BOARD_BCM94331S9BU		0x0524
+#define	BHND_BOARD_BCM94331MC		0x0525
+#define	BHND_BOARD_BCM94331MCI		0x0526
+#define	BHND_BOARD_BCM94331PCIEBT4	0x0527
+#define	BHND_BOARD_BCM94331HM		0x0574
+#define	BHND_BOARD_BCM94331PCIEDUAL	0x059B
+#define	BHND_BOARD_BCM94331MCH5		0x05A9
+#define	BHND_BOARD_BCM94331CS		0x05C6
+#define	BHND_BOARD_BCM94331CD		0x05DA
+
+/* 4314 Boards */
+#define	BHND_BOARD_BCM94314BU		0x05b1
+
+/* 53572 Boards */
+#define	BHND_BOARD_BCM953572BU		0x058D
+#define	BHND_BOARD_BCM953572NR2		0x058E
+#define	BHND_BOARD_BCM947188NR2		0x058F
+#define	BHND_BOARD_BCM953572SDRNR2	0x0590
+
+/* 43236 boards */
+#define	BHND_BOARD_BCM943236OLYMPICSULLEY	0x594
+#define	BHND_BOARD_BCM943236PREPROTOBLU2O3	0x5b9
+#define	BHND_BOARD_BCM943236USBELNA		0x5f8
+
+/* 4314 Boards */
+#define	BHND_BOARD_BCM94314BUSDIO	0x05c8
+#define	BHND_BOARD_BCM94314BGABU	0x05c9
+#define	BHND_BOARD_BCM94314HMEPA	0x05ca
+#define	BHND_BOARD_BCM94314HMEPABK	0x05cb
+#define	BHND_BOARD_BCM94314SUHMEPA	0x05cc
+#define	BHND_BOARD_BCM94314SUHM		0x05cd
+#define	BHND_BOARD_BCM94314HM		0x05d1
+
+/* 4334 Boards */
+#define	BHND_BOARD_BCM94334FCAGBI	0x05df
+#define	BHND_BOARD_BCM94334WLAGBI	0x05dd
+
+/* 4335 Boards */
+#define	BHND_BOARD_BCM94335X52		0x0114
+
+/* 4345 Boards */
+#define	BHND_BOARD_BCM94345		0x0687
+
+/* 4360 Boards */
+#define	BHND_BOARD_BCM94360X52C		0X0117
+#define	BHND_BOARD_BCM94360X52D		0X0137
+#define	BHND_BOARD_BCM94360X29C		0X0112
+#define	BHND_BOARD_BCM94360X29CP2	0X0134
+#define	BHND_BOARD_BCM94360X51		0x0111
+#define	BHND_BOARD_BCM94360X51P2	0x0129
+#define	BHND_BOARD_BCM94360X51A		0x0135
+#define	BHND_BOARD_BCM94360X51B		0x0136
+#define	BHND_BOARD_BCM94360CS		0x061B
+#define	BHND_BOARD_BCM94360J28_D11AC2G	0x0c00
+#define	BHND_BOARD_BCM94360J28_D11AC5G	0x0c01
+#define	BHND_BOARD_BCM94360USBH5_D11AC5G	0x06aa
+
+/* 4350 Boards */
+#define	BHND_BOARD_BCM94350X52B		0X0116
+#define	BHND_BOARD_BCM94350X14		0X0131
+
+/* 43217 Boards */
+#define	BHND_BOARD_BCM943217BU		0x05d5
+#define	BHND_BOARD_BCM943217HM2L	0x05d6
+#define	BHND_BOARD_BCM943217HMITR2L	0x05d7
+
+/* 43142 Boards */
+#define	BHND_BOARD_BCM943142HM		0x05e0
+
 /* 43341 Boards */
-#define	BCM943341WLABGS_SSID	0x062d
+#define	BHND_BOARD_BCM943341WLABGS	0x062d
 
 /* 43342 Boards */
-#define	BCM943342FCAGBI_SSID	0x0641
+#define	BHND_BOARD_BCM943342FCAGBI	0x0641
+
+/* 43602 Boards, unclear yet what boards will be created. */
+#define	BHND_BOARD_BCM943602RSVD1	0x06a5
+#define	BHND_BOARD_BCM943602RSVD2	0x06a6
+#define	BHND_BOARD_BCM943602X87		0X0133
+#define	BHND_BOARD_BCM943602X238	0X0132
+
+/* 4354 board types */
+#define	BHND_BOARD_BCM94354WLSAGBI	0x06db
+#define	BHND_BOARD_BCM94354Z		0x0707
 
 /* # of GPIO pins */
 #define	BHND_BCM43XX_GPIO_NUMPINS	32
Index: head/sys/dev/bhnd/bhnd_subr.c
===================================================================
--- head/sys/dev/bhnd/bhnd_subr.c
+++ head/sys/dev/bhnd/bhnd_subr.c
@@ -41,9 +41,18 @@
 
 #include <dev/bhnd/cores/chipc/chipcreg.h>
 
+#include "nvram/bhnd_nvram.h"
+
+#include "bhnd_chipc_if.h"
+
+#include "bhnd_nvram_if.h"
+#include "bhnd_nvram_map.h"
+
 #include "bhndreg.h"
 #include "bhndvar.h"
 
+static device_t		find_nvram_child(device_t dev);
+
 /* BHND core device description table. */
 static const struct bhnd_core_desc {
 	uint16_t	 vendor;
@@ -427,6 +436,7 @@
  * Return true if the @p chip matches @p desc.
  * 
  * @param chip A bhnd chip identifier.
+ * @param board The bhnd board info, or NULL if unavailable.
  * @param desc A match descriptor to compare against @p chip.
  * 
  * @retval true if @p chip matches @p match
@@ -434,8 +444,19 @@
  */
 bool
 bhnd_chip_matches(const struct bhnd_chipid *chip,
+    const struct bhnd_board_info *board,
     const struct bhnd_chip_match *desc)
 {
+	/* Explicit wildcard match */
+	if (desc->match_any)
+		return (true);
+
+	/* If board_info is missing, but required, we cannot match. */
+	if (BHND_CHIP_MATCH_REQ_BOARD_INFO(desc) && board == NULL)
+		return (false);
+
+
+	/* Chip matching */
 	if (desc->match_id && chip->chip_id != desc->chip_id)
 		return (false);
 
@@ -446,6 +467,23 @@
 	    !bhnd_hwrev_matches(chip->chip_rev, &desc->chip_rev))
 		return (false);
 
+
+	/* Board info matching */
+	if (desc->match_srom_rev &&
+	    !bhnd_hwrev_matches(board->board_srom_rev, &desc->board_srom_rev))
+		return (false);
+
+	if (desc->match_bvendor && board->board_vendor != desc->board_vendor)
+		return (false);
+
+	if (desc->match_btype && board->board_type != desc->board_type)
+		return (false);
+
+	if (desc->match_brev &&
+	    !bhnd_hwrev_matches(board->board_rev, &desc->board_rev))
+		return (false);
+
+
 	return (true);
 }
 
@@ -547,15 +585,43 @@
 uint32_t
 bhnd_chip_quirks(device_t dev, const struct bhnd_chip_quirk *table)
 {
+	struct bhnd_board_info		 bi, *board;
 	const struct bhnd_chipid	*cid;
 	const struct bhnd_chip_quirk	*qent;
 	uint32_t			 quirks;
-	
+	int				 error;
+	bool				 need_boardinfo;
+
 	cid = bhnd_get_chipid(dev);
 	quirks = 0;
+	need_boardinfo = 0;
+	board = NULL;
 
+	/* Determine whether quirk matching requires board_info; we want to
+	 * avoid fetching board_info for early devices (e.g. ChipCommon)
+	 * that are brought up prior to NVRAM being readable. */
 	for (qent = table; !BHND_CHIP_QUIRK_IS_END(qent); qent++) {
-		if (bhnd_chip_matches(cid, &qent->chip))
+		if (!BHND_CHIP_MATCH_REQ_BOARD_INFO(&qent->chip))
+			continue;
+
+		need_boardinfo = true;
+		break;
+	}
+
+	/* If required, fetch board info */
+	if (need_boardinfo) {
+		error = bhnd_read_board_info(dev, &bi);
+		if (!error) {
+			board = &bi;
+		} else {
+			device_printf(dev, "failed to read required board info "
+			    "during quirk matching: %d\n", error);
+		}
+	}
+
+	/* Apply all matching quirk flags */
+	for (qent = table; !BHND_CHIP_QUIRK_IS_END(qent); qent++) {
+		if (bhnd_chip_matches(cid, board, &qent->chip))
 			quirks |= qent->quirks;
 	}
 
@@ -590,16 +656,18 @@
 		return (0);
 	}
 
-	/* Quirks aren't a mandatory field */
-	if ((qtable = dent->quirks_table) == NULL)
-		return (0);
-
-	/* Collect matching quirk entries */
-	for (qent = qtable; !BHND_DEVICE_QUIRK_IS_END(qent); qent++) {
-		if (bhnd_hwrev_matches(hwrev, &qent->hwrev))
-			quirks |= qent->quirks;
+	/* Collect matching device quirk entries */
+	if ((qtable = dent->quirks_table) != NULL) {
+		for (qent = qtable; !BHND_DEVICE_QUIRK_IS_END(qent); qent++) {
+			if (bhnd_hwrev_matches(hwrev, &qent->hwrev))
+				quirks |= qent->quirks;
+		}
 	}
 
+	/* Collect matching chip quirk entries */
+	if (dent->chip_quirks_table != NULL)
+		quirks |= bhnd_chip_quirks(dev, dent->chip_quirks_table);
+
 	return (quirks);
 }
 
@@ -824,6 +892,130 @@
 	panic("missing BHND_BUS_GET_CHIPID()");
 }
 
+/* nvram board_info population macros for bhnd_bus_generic_read_board_info() */
+#define	BHND_GV(_dest, _name)	\
+	bhnd_nvram_getvar(child, BHND_NVAR_ ## _name, &_dest, sizeof(_dest))
+
+#define	REQ_BHND_GV(_dest, _name)		do {			\
+	if ((error = BHND_GV(_dest, _name))) {				\
+		device_printf(dev,					\
+		    "error reading " __STRING(_name) ": %d\n", error);	\
+		return (error);						\
+	}								\
+} while(0)
+
+#define	OPT_BHND_GV(_dest, _name, _default)	do {			\
+	if ((error = BHND_GV(_dest, _name))) {				\
+		if (error != ENOENT) {					\
+			device_printf(dev,				\
+			    "error reading "				\
+			       __STRING(_name) ": %d\n", error);	\
+			return (error);					\
+		}							\
+		_dest = _default;					\
+	}								\
+} while(0)
+
+/**
+ * Helper function for implementing BHND_BUS_READ_BOARDINFO().
+ * 
+ * This implementation populates @p info with information from NVRAM,
+ * defaulting board_vendor and board_type fields to 0 if the
+ * requested variables cannot be found.
+ * 
+ * This behavior is correct for most SoCs, but must be overridden on
+ * bridged (PCI, PCMCIA, etc) devices to produce a complete bhnd_board_info
+ * result.
+ */
+int
+bhnd_bus_generic_read_board_info(device_t dev, device_t child,
+    struct bhnd_board_info *info)
+{
+	int	error;
+
+	OPT_BHND_GV(info->board_vendor,	BOARDVENDOR,	0);
+	OPT_BHND_GV(info->board_type,	BOARDTYPE,	0);	/* srom >= 2 */
+	REQ_BHND_GV(info->board_rev,	BOARDREV);
+	REQ_BHND_GV(info->board_srom_rev,SROMREV);
+	REQ_BHND_GV(info->board_flags,	BOARDFLAGS);
+	OPT_BHND_GV(info->board_flags2,	BOARDFLAGS2,	0);	/* srom >= 4 */
+	OPT_BHND_GV(info->board_flags3,	BOARDFLAGS3,	0);	/* srom >= 11 */
+
+	return (0);
+}
+
+#undef	BHND_GV
+#undef	BHND_GV_REQ
+#undef	BHND_GV_OPT
+
+
+/**
+ * Find an NVRAM child device on @p dev, if any.
+ * 
+ * @retval device_t An NVRAM device.
+ * @retval NULL If no NVRAM device is found.
+ */
+static device_t
+find_nvram_child(device_t dev)
+{
+	device_t	chipc, nvram;
+
+	/* Look for a directly-attached NVRAM child */
+	nvram = device_find_child(dev, "bhnd_nvram", 0);
+	if (nvram != NULL)
+		return (nvram);
+
+	/* Remaining checks are only applicable when searching a bhnd(4)
+	 * bus. */
+	if (device_get_devclass(dev) != bhnd_devclass)
+		return (NULL);
+
+	/* Look for a ChipCommon device */
+	if ((chipc = bhnd_find_child(dev, BHND_DEVCLASS_CC, -1)) != NULL) {
+		bhnd_nvram_src_t src;
+
+		/* Query the NVRAM source and determine whether it's
+		 * accessible via the ChipCommon device */
+		src = BHND_CHIPC_NVRAM_SRC(chipc);
+		if (BHND_NVRAM_SRC_CC(src))
+			return (chipc);
+	}
+
+	/* Not found */
+	return (NULL);
+}
+
+/**
+ * Helper function for implementing BHND_BUS_GET_NVRAM_VAR().
+ * 
+ * This implementation searches @p dev for a usable NVRAM child device:
+ * - The first child device implementing the bhnd_nvram devclass is
+ *   returned, otherwise
+ * - If @p dev is a bhnd(4) bus, a ChipCommon core that advertises an
+ *   attached NVRAM source.
+ * 
+ * If no usable child device is found on @p dev, the request is delegated to
+ * the BHND_BUS_GET_NVRAM_VAR() method on the parent of @p dev.
+ */
+int
+bhnd_bus_generic_get_nvram_var(device_t dev, device_t child, const char *name,
+    void *buf, size_t *size)
+{
+	device_t	nvram;
+	device_t	parent;
+
+	/* Try to find an NVRAM device applicable to @p child */
+	if ((nvram = find_nvram_child(dev)) != NULL)
+		return BHND_NVRAM_GETVAR(nvram, name, buf, size);
+
+	/* Try to delegate to parent */
+	if ((parent = device_get_parent(dev)) == NULL)
+		return (ENODEV);
+
+	return (BHND_BUS_GET_NVRAM_VAR(device_get_parent(dev), child,
+	    name, buf, size));
+}
+
 /**
  * Helper function for implementing BHND_BUS_ALLOC_RESOURCE().
  * 
Index: head/sys/dev/bhnd/bhndb/bhndb.c
===================================================================
--- head/sys/dev/bhnd/bhndb/bhndb.c
+++ head/sys/dev/bhnd/bhndb/bhndb.c
@@ -1714,26 +1714,6 @@
 	return (dwa);
 }
 
-/**
- * Default bhndb(4) implementation of BHND_BUS_GET_NVRAM_VAR().
- */
-static int
-bhndb_get_nvram_var(device_t dev, device_t child, const char *name,
-    void *buf, size_t *size)
-{
-	device_t nvram;
-
-	/* Look for a directly-attached NVRAM child */
-	nvram = device_find_child(dev, devclass_get_name(bhnd_nvram_devclass),
-	    0);
-	if (nvram != NULL)
-		return (BHND_NVRAM_GETVAR(nvram, name, buf, size));
-
-	/* Otherwise, delegate to our parent */
-	return (BHND_BUS_GET_NVRAM_VAR(device_get_parent(dev), child,
-	    name, buf, size));
-}
-
 /*
  * BHND_BUS_(READ|WRITE_* implementations
  */
@@ -1961,7 +1941,7 @@
 	DEVMETHOD(bhnd_bus_get_chipid,		bhndb_get_chipid),
 	DEVMETHOD(bhnd_bus_activate_resource,	bhndb_activate_bhnd_resource),
 	DEVMETHOD(bhnd_bus_deactivate_resource,	bhndb_deactivate_bhnd_resource),
-	DEVMETHOD(bhnd_bus_get_nvram_var,	bhndb_get_nvram_var),
+	DEVMETHOD(bhnd_bus_get_nvram_var,	bhnd_bus_generic_get_nvram_var),
 	DEVMETHOD(bhnd_bus_read_1,		bhndb_bus_read_1),
 	DEVMETHOD(bhnd_bus_read_2,		bhndb_bus_read_2),
 	DEVMETHOD(bhnd_bus_read_4,		bhndb_bus_read_4),
Index: head/sys/dev/bhnd/bhndb/bhndb_if.m
===================================================================
--- head/sys/dev/bhnd/bhndb/bhndb_if.m
+++ head/sys/dev/bhnd/bhndb/bhndb_if.m
@@ -56,6 +56,13 @@
 	}
 
 	static int
+	bhndb_null_populate_board_info(device_t dev, device_t child,
+	    struct bhnd_board_info *info)
+	{
+		panic("bhndb_populate_board_info unimplemented");
+	}
+
+	static int
 	bhndb_null_init_full_config(device_t dev, device_t child,
 	    const struct bhndb_hw_priority *priority_table)
 	{
@@ -102,6 +109,21 @@
 } DEFAULT bhndb_null_get_chipid;
 
 /**
+ * Populate @p info with board info known only to the bridge,
+ * deferring to any existing initialized fields in @p info.
+ *
+ * @param dev The parent device of @p child.
+ * @param child The bhndb-attached device.
+ * @param[in,out] info A board info structure previously initialized with any
+ * information available from NVRAM.
+ */
+METHOD int populate_board_info {
+	device_t dev;
+	device_t child;
+	struct bhnd_board_info *info;
+} DEFAULT bhndb_null_populate_board_info;
+
+/**
  * Perform final bridge hardware configuration after @p child has fully
  * enumerated its children.
  *
Index: head/sys/dev/bhnd/bhndb/bhndb_pci.c
===================================================================
--- head/sys/dev/bhnd/bhndb/bhndb_pci.c
+++ head/sys/dev/bhnd/bhndb/bhndb_pci.c
@@ -474,6 +474,25 @@
 	return (0);
 }
 
+static int
+bhndb_pci_populate_board_info(device_t dev, device_t child,
+    struct bhnd_board_info *info)
+{
+	struct bhndb_pci_softc	*sc;
+
+	sc = device_get_softc(dev);
+
+	/* If NVRAM did not supply vendor/type info, provide the PCI
+	 * subvendor/subdevice values. */
+	if (info->board_vendor == 0)
+		info->board_vendor = pci_get_subvendor(sc->parent);
+
+	if (info->board_type == 0)
+		info->board_type = pci_get_subdevice(sc->parent);
+
+	return (0);
+}
+
 /**
  * Enable externally managed clocks, if required.
  * 
@@ -572,6 +591,7 @@
 	/* BHNDB interface */
 	DEVMETHOD(bhndb_init_full_config,	bhndb_pci_init_full_config),
 	DEVMETHOD(bhndb_set_window_addr,	bhndb_pci_set_window_addr),
+	DEVMETHOD(bhndb_populate_board_info,	bhndb_pci_populate_board_info),
 
 	DEVMETHOD_END
 };
Index: head/sys/dev/bhnd/cores/chipc/chipc.c
===================================================================
--- head/sys/dev/bhnd/cores/chipc/chipc.c
+++ head/sys/dev/bhnd/cores/chipc/chipc.c
@@ -65,10 +65,11 @@
 };
 
 static struct bhnd_device_quirk chipc_quirks[];
+static struct bhnd_chip_quirk chipc_chip_quirks[];
 
 /* Supported device identifiers */
 static const struct bhnd_device chipc_devices[] = {
-	BHND_DEVICE(CC, "CC", chipc_quirks),
+	BHND_DEVICE(CC, "CC", chipc_quirks, chipc_chip_quirks),
 	BHND_DEVICE_END
 };
 
@@ -158,7 +159,6 @@
 	sc->dev = dev;
 	sc->quirks = bhnd_device_quirks(dev, chipc_devices,
 	    sizeof(chipc_devices[0]));
-	sc->quirks |= bhnd_chip_quirks(dev, chipc_chip_quirks);
 	
 	CHIPC_LOCK_INIT(sc);
 
Index: head/sys/dev/bhnd/cores/pci/bhnd_pci.c
===================================================================
--- head/sys/dev/bhnd/cores/pci/bhnd_pci.c
+++ head/sys/dev/bhnd/cores/pci/bhnd_pci.c
@@ -68,8 +68,8 @@
 
 #define	BHND_PCI_QUIRKS		bhnd_pci_quirks
 #define	BHND_PCIE_QUIRKS	bhnd_pcie_quirks
-#define	BHND_PCI_DEV(_core, _desc, ...)				\
-	{ BHND_DEVICE(_core, _desc, BHND_ ## _core ## _QUIRKS,	\
+#define	BHND_PCI_DEV(_core, _desc, ...)					\
+	{ BHND_DEVICE(_core, _desc, BHND_ ## _core ## _QUIRKS, NULL,	\
 	    ## __VA_ARGS__), BHND_PCI_REGFMT_ ## _core }
 
 static const struct bhnd_pci_device {
Index: head/sys/dev/bhnd/cores/pci/bhnd_pci_hostb.c
===================================================================
--- head/sys/dev/bhnd/cores/pci/bhnd_pci_hostb.c
+++ head/sys/dev/bhnd/cores/pci/bhnd_pci_hostb.c
@@ -62,11 +62,12 @@
 #define	BHND_PCI_ASSERT_QUIRK(_sc, _name)	\
     KASSERT((_sc)->quirks & (_name), ("quirk " __STRING(_name) " not set"))
 
-#define	BHND_PCI_DEV(_core, _quirks)				\
-	BHND_DEVICE(_core, "", _quirks, BHND_DF_HOSTB)
+#define	BHND_PCI_DEV(_core, _quirks, _chip_quirks)		\
+	BHND_DEVICE(_core, "", _quirks, _chip_quirks, BHND_DF_HOSTB)
 
 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_pcie_chip_quirks[];
 
 static int	bhnd_pci_wars_early_once(struct bhnd_pcihb_softc *sc);
 static int	bhnd_pci_wars_hwup(struct bhnd_pcihb_softc *sc);
@@ -76,8 +77,8 @@
  * device/quirk tables
  */
 static const struct bhnd_device bhnd_pci_devs[] = {
-	BHND_PCI_DEV(PCI,	bhnd_pci_quirks),
-	BHND_PCI_DEV(PCIE,	bhnd_pcie_quirks),
+	BHND_PCI_DEV(PCI,	bhnd_pci_quirks,	NULL),
+	BHND_PCI_DEV(PCIE,	bhnd_pcie_quirks,	bhnd_pcie_chip_quirks),
 	BHND_DEVICE_END
 };
 
@@ -105,9 +106,21 @@
 	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_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
Index: head/sys/dev/bhnd/cores/pci/bhnd_pci_hostbvar.h
===================================================================
--- head/sys/dev/bhnd/cores/pci/bhnd_pci_hostbvar.h
+++ head/sys/dev/bhnd/cores/pci/bhnd_pci_hostbvar.h
@@ -131,20 +131,27 @@
 	 *   clear ASPM L1 in the PCIER_LINK_CTL register.
 	 */
 	BHND_PCIE_QUIRK_ASPM_OVR		= (1<<9),
-	
+
+	/**
+	 * A subset of Apple devices did not set the BHND_BFL2_PCIEWAR_OVR
+	 * flag in SPROM; on these devices, the BHND_BFL2_PCIEWAR_OVR flag
+	 * should always be treated as if set.
+	 */
+	BHND_PCIE_QUIRK_BFL2_PCIEWAR_EN		= (1<<10),
+
 	/**
 	 * Fix SerDes polarity on SerDes <= rev9 devices.
 	 *
 	 * The SerDes polarity must be saved at device attachment, and
 	 * restored on suspend/resume.
 	 */
-	BHND_PCIE_QUIRK_SDR9_POLARITY		= (1<<10),
+	BHND_PCIE_QUIRK_SDR9_POLARITY		= (1<<11),
 
 	/**
 	 * SerDes PLL down flag must be manually disabled (by ChipCommon) on
 	 * resume.
 	 */
-	BHND_PCIE_QUIRK_SERDES_NOPLLDOWN	= (1<<11),
+	BHND_PCIE_QUIRK_SERDES_NOPLLDOWN	= (1<<12),
 
         /**
 	 * On attach and resume, consult the SPROM to determine whether
@@ -152,7 +159,7 @@
 	 *
 	 * If L23READY_EXIT_NOPRST is not already set in the SPROM, set it
 	 */
-	BHND_PCIE_QUIRK_SPROM_L23_PCI_RESET	= (1<<12),
+	BHND_PCIE_QUIRK_SPROM_L23_PCI_RESET	= (1<<13),
 	
 	/**
 	 * The PCIe SerDes supports non-standard extended MDIO register access.
@@ -160,7 +167,7 @@
 	 * The PCIe SerDes supports access to extended MDIO registers via
 	 * a non-standard Clause 22 address extension mechanism.
 	 */
-	BHND_PCIE_QUIRK_SD_C22_EXTADDR		= (1<<13),
+	BHND_PCIE_QUIRK_SD_C22_EXTADDR		= (1<<14),
 	
 	/**
 	 * The PCIe SerDes PLL must be configured to not retry the startup
@@ -168,7 +175,7 @@
 	 * 
 	 * The issue this workaround resolves has not be determined.
 	 */
-	BHND_PCIE_QUIRK_SDR9_NO_FREQRETRY	= (1<<14),
+	BHND_PCIE_QUIRK_SDR9_NO_FREQRETRY	= (1<<15),
 };
 
 /**
Index: head/sys/dev/bhnd/nvram/nvram_map
===================================================================
--- head/sys/dev/bhnd/nvram/nvram_map
+++ head/sys/dev/bhnd/nvram/nvram_map
@@ -30,6 +30,60 @@
 # available ISC-licensed CIS and SROM code and associated headers.
 #
 
+# Board Info
+#
+
+u16 boardvendor	{}			# PCI vendor ID (SoC NVRAM-only)
+u16 subvid	{ srom >= 2	0x6 }	# PCI subvendor ID
+u16 devid	{ srom >= 8	0x60 }	# PCI device ID 
+
+u32 boardflags {
+	srom 1		u16 0x72
+	srom 2		u16 0x72 | u16 0x38 (<<16)
+	srom 3		u16 0x72 | u16 0x7A (<<16)
+	srom 4		0x44
+	srom 5-7	0x4A
+	srom >= 8	0x84
+}
+u32 boardflags2 {
+	srom 4		0x48
+	srom 5-7	0x4E
+	srom >= 8	0x88
+}
+u32 boardflags3 {
+	srom >= 11	0x8C
+}
+
+# Board serial number, independent of mac addr
+u16 boardnum {
+	srom 1-2	0x4C
+	srom 3		0x4E
+	srom 4		0x50
+	srom 5-7	0x56
+	srom 8-10	0x90
+	srom >= 11	0x94
+}
+
+# Board revision
+u16 boardrev {
+	srom 1-3	u8 0x5D
+	srom 4-7	0x42
+	srom >= 8	0x82
+}
+
+# Board type
+u16 boardtype {
+	srom >= 2	0x4
+}
+
+# SROM revision
+u8 sromrev {
+	srom 1-3	0x74
+	srom 4-9	0x1B6
+	srom 10		0x1CA
+	srom 11		0x1D2
+}
+
 # Antennas available
 u8 aa2g {
 	srom 1-3	0x5C (&0x30, >>4)
@@ -184,46 +238,6 @@
 	srom >= 11	0xA7
 }
 
-# board flags
-u32 boardflags {
-	srom 1		u16 0x72
-	srom 2		u16 0x72 | u16 0x38 (<<16)
-	srom 3		u16 0x72 | u16 0x7A (<<16)
-	srom 4		0x44
-	srom 5-7	0x4A
-	srom >= 8	0x84
-}
-u32 boardflags2 {
-	srom 4		0x48
-	srom 5-7	0x4E
-	srom >= 8	0x88
-}
-u32 boardflags3 {
-	srom >= 11	0x8C
-}
-
-# board serial number, independent of mac addr
-u16 boardnum {
-	srom 1-2	0x4C
-	srom 3		0x4E
-	srom 4		0x50
-	srom 5-7	0x56
-	srom 8-10	0x90
-	srom >= 11	0x94
-}
-
-# One byte board revision
-u16 boardrev {
-	srom 1-3	u8 0x5D
-	srom 4-7	0x42
-	srom >= 8	0x82
-}
-
-# 2 bytes; boardtype
-u16 boardtype {
-	srom >= 2	0x4
-}
-
 # Default country code (sromrev == 1)
 u8 cc {
 	srom 1		0x5C (&0xF)
@@ -274,11 +288,6 @@
 	srom >= 11	u8 0xA8
 }
 
-# PCI device id
-private u16 devid {
-	srom >= 8	u16 0x60
-}
-
 u8 elna2g {
 	srom 8-10	0xBB
 }
@@ -1269,10 +1278,6 @@
 	srom >= 11	0x1BA
 }
 
-u16 subvid {
-	srom >= 2	0x6
-}
-
 u32[5] swctrlmap_2g {
 	srom 10	u32[4] 0x1B8, u16 0x1C8
 }
Index: head/sys/dev/bhnd/siba/siba_bhndb.c
===================================================================
--- head/sys/dev/bhnd/siba/siba_bhndb.c
+++ head/sys/dev/bhnd/siba/siba_bhndb.c
@@ -166,6 +166,20 @@
 	return (0);
 }
 
+static int
+siba_bhndb_read_board_info(device_t dev, device_t child,
+    struct bhnd_board_info *info)
+{
+	int	error;
+
+	/* Initialize with NVRAM-derived values */
+	if ((error = bhnd_bus_generic_read_board_info(dev, child, info)))
+		return (error);
+
+	/* Let the bridge fill in any additional data */
+	return (BHNDB_POPULATE_BOARD_INFO(device_get_parent(dev), dev, info));
+}
+
 static device_method_t siba_bhndb_methods[] = {
 	/* Device interface */
 	DEVMETHOD(device_probe,			siba_bhndb_probe),
@@ -175,6 +189,9 @@
 	DEVMETHOD(bus_suspend_child,		siba_bhndb_suspend_child),
 	DEVMETHOD(bus_resume_child,		siba_bhndb_resume_child),
 
+	/* BHND interface */
+	DEVMETHOD(bhnd_bus_read_board_info,	siba_bhndb_read_board_info),
+
 	DEVMETHOD_END
 };