svn commit: r305444 - in head/sys/dev: bhnd bhnd/bcma bhnd/bhndb bhnd/cores/pmu bhnd/siba bwn

Landon J. Fuller landonf at FreeBSD.org
Mon Sep 5 22:11:48 UTC 2016


Author: landonf
Date: Mon Sep  5 22:11:46 2016
New Revision: 305444
URL: https://svnweb.freebsd.org/changeset/base/305444

Log:
  bhnd(4): Implement backplane interrupt handling.
  
  This adds bhnd(4) bus-level support for querying backplane interrupt vector
  routing, and delegating machine/bridge-specific interrupt handling to the
  concrete bhnd(4) driver implementation.
  
  On bhndb(4) bridged PCI devices, we provide the PCI/MSI interrupt directly
  to attached cores.
  
  On MIPS devices, we report a backplane interrupt count of 0, effectively
  disabling the bus-level interrupt assignment. This allows mips/broadcom
  to temporarily continue using hard-coded MIPS IRQs until bhnd_mips PIC
  support is implemented.
  
  Reviewed by:	mizhka
  Approved by:	adrian (mentor, implicit)

Modified:
  head/sys/dev/bhnd/bcma/bcma.c
  head/sys/dev/bhnd/bcma/bcma_dmp.h
  head/sys/dev/bhnd/bcma/bcmavar.h
  head/sys/dev/bhnd/bhnd.c
  head/sys/dev/bhnd/bhnd.h
  head/sys/dev/bhnd/bhnd_bus_if.m
  head/sys/dev/bhnd/bhnd_nexus.c
  head/sys/dev/bhnd/bhndb/bhnd_bhndb.c
  head/sys/dev/bhnd/bhndb/bhndb.c
  head/sys/dev/bhnd/bhndb/bhndb_pci.c
  head/sys/dev/bhnd/bhndb/bhndb_pcivar.h
  head/sys/dev/bhnd/cores/pmu/bhnd_pmu_subr.c
  head/sys/dev/bhnd/siba/siba.c
  head/sys/dev/bhnd/siba/siba_bhndb.c
  head/sys/dev/bhnd/siba/sibareg.h
  head/sys/dev/bhnd/siba/sibavar.h
  head/sys/dev/bwn/bwn_mac.c

Modified: head/sys/dev/bhnd/bcma/bcma.c
==============================================================================
--- head/sys/dev/bhnd/bcma/bcma.c	Mon Sep  5 21:55:27 2016	(r305443)
+++ head/sys/dev/bhnd/bcma/bcma.c	Mon Sep  5 22:11:46 2016	(r305444)
@@ -41,8 +41,11 @@ __FBSDID("$FreeBSD$");
 
 #include "bcmavar.h"
 
+#include "bcma_dmp.h"
+
 #include "bcma_eromreg.h"
 #include "bcma_eromvar.h"
+
 #include <dev/bhnd/bhnd_core.h>
 
 /* RID used when allocating EROM table */
@@ -434,6 +437,70 @@ bcma_get_region_addr(device_t dev, devic
 	return (ENOENT);
 }
 
+/**
+ * Default bcma(4) bus driver implementation of BHND_BUS_GET_INTR_COUNT().
+ * 
+ * This implementation consults @p child's agent register block,
+ * returning the number of interrupt output lines routed to @p child.
+ */
+int
+bcma_get_intr_count(device_t dev, device_t child)
+{
+	struct bcma_devinfo	*dinfo;
+	uint32_t		 dmpcfg, oobw;
+
+	dinfo = device_get_ivars(child);
+
+	/* Agent block must be mapped */
+	if (dinfo->res_agent == NULL)
+		return (0);
+
+	/* Agent must support OOB */
+	dmpcfg = bhnd_bus_read_4(dinfo->res_agent, BCMA_DMP_CONFIG);
+	if (!BCMA_DMP_GET_FLAG(dmpcfg, BCMA_DMP_CFG_OOB))
+		return (0);
+
+	/* Return OOB width as interrupt count */
+	oobw = bhnd_bus_read_4(dinfo->res_agent,
+	    BCMA_DMP_OOB_OUTWIDTH(BCMA_OOB_BANK_INTR));
+	if (oobw > BCMA_OOB_NUM_SEL) {
+		device_printf(dev, "ignoring invalid OOBOUTWIDTH for core %u: "
+		    "%#x\n", BCMA_DINFO_COREIDX(dinfo), oobw);
+		return (0);
+	}
+	
+	return (oobw);
+}
+
+/**
+ * Default bcma(4) bus driver implementation of BHND_BUS_GET_CORE_IVEC().
+ * 
+ * This implementation consults @p child's agent register block,
+ * returning the interrupt output line routed to @p child, at OOB selector
+ * @p intr.
+ */
+int
+bcma_get_core_ivec(device_t dev, device_t child, u_int intr, uint32_t *ivec)
+{
+	struct bcma_devinfo	*dinfo;
+	uint32_t		 oobsel;
+
+	dinfo = device_get_ivars(child);
+
+	/* Interrupt ID must be valid. */
+	if (intr >= bcma_get_intr_count(dev, child))
+		return (ENXIO);
+
+	/* Fetch OOBSEL busline value */
+	KASSERT(dinfo->res_agent != NULL, ("missing agent registers"));
+	oobsel = bhnd_bus_read_4(dinfo->res_agent, BCMA_DMP_OOBSELOUT(
+	    BCMA_OOB_BANK_INTR, intr));
+	*ivec = (oobsel >> BCMA_DMP_OOBSEL_SHIFT(intr)) &
+	    BCMA_DMP_OOBSEL_BUSLINE_MASK;
+
+	return (0);
+}
+
 static struct bhnd_devinfo *
 bcma_alloc_bhnd_dinfo(device_t dev)
 {
@@ -475,6 +542,8 @@ bcma_add_children(device_t bus)
 	/* Add all cores. */
 	bcma_erom = (struct bcma_erom *)erom;
 	while ((error = bcma_erom_next_corecfg(bcma_erom, &corecfg)) == 0) {
+		int nintr;
+
 		/* Add the child device */
 		child = BUS_ADD_CHILD(bus, 0, NULL, -1);
 		if (child == NULL) {
@@ -494,6 +563,17 @@ bcma_add_children(device_t bus)
 		if ((error = bcma_dinfo_alloc_agent(bus, child, dinfo)))
 			goto cleanup;
 
+		/* Assign interrupts */
+		nintr = bhnd_get_intr_count(child);
+		for (int rid = 0; rid < nintr; rid++) {
+			error = BHND_BUS_ASSIGN_INTR(bus, child, rid);
+			if (error) {
+				device_printf(bus, "failed to assign interrupt "
+				    "%d to core %u: %d\n", rid,
+				    BCMA_DINFO_COREIDX(dinfo), error);
+			}
+		}
+
 		/* If pins are floating or the hardware is otherwise
 		 * unpopulated, the device shouldn't be used. */
 		if (bhnd_is_hw_disabled(child))
@@ -544,6 +624,8 @@ static device_method_t bcma_methods[] = 
 	DEVMETHOD(bhnd_bus_get_port_rid,	bcma_get_port_rid),
 	DEVMETHOD(bhnd_bus_decode_port_rid,	bcma_decode_port_rid),
 	DEVMETHOD(bhnd_bus_get_region_addr,	bcma_get_region_addr),
+	DEVMETHOD(bhnd_bus_get_intr_count,	bcma_get_intr_count),
+	DEVMETHOD(bhnd_bus_get_core_ivec,	bcma_get_core_ivec),
 
 	DEVMETHOD_END
 };

Modified: head/sys/dev/bhnd/bcma/bcma_dmp.h
==============================================================================
--- head/sys/dev/bhnd/bcma/bcma_dmp.h	Mon Sep  5 21:55:27 2016	(r305443)
+++ head/sys/dev/bhnd/bcma/bcma_dmp.h	Mon Sep  5 22:11:46 2016	(r305444)
@@ -37,8 +37,18 @@
  * in the proprietary "NIC-301 Interconnect Device Management (PL368)"
  * errata publication, available to licensees as part of ARM's
  * CoreLink Controllers and Peripherals Engineering Errata.
+ * 
+ * As such, the exact interpretation of these register definitions is
+ * unconfirmed, and may be incorrect.
  */
 
+#define	BCMA_DMP_GET_FLAG(_value, _flag)	\
+	(((_value) & _flag) != 0)
+#define	BCMA_DMP_GET_BITS(_value, _field)	\
+        ((_value & _field ## _MASK) >> _field ## _SHIFT)
+#define	BHND_DMP_SET_BITS(_value, _field)	\
+	(((_value) << _field ## _SHIFT) & _field ## _MASK)
+
 /* Out-of-band Router registers */
 #define	BCMA_OOB_BUSCONFIG	0x020
 #define	BCMA_OOB_STATUSA	0x100
@@ -71,23 +81,36 @@
 #define	BCMA_OOB_ITOPOOBC	0xf38
 #define	BCMA_OOB_ITOPOOBD	0xf3c
 
-/* DMP wrapper registers */
-#define	BCMA_DMP_OOBSELINA30	0x000
-#define	BCMA_DMP_OOBSELINA74	0x004
-#define	BCMA_DMP_OOBSELINB30	0x020
-#define	BCMA_DMP_OOBSELINB74	0x024
-#define	BCMA_DMP_OOBSELINC30	0x040
-#define	BCMA_DMP_OOBSELINC74	0x044
-#define	BCMA_DMP_OOBSELIND30	0x060
-#define	BCMA_DMP_OOBSELIND74	0x064
-#define	BCMA_DMP_OOBSELOUTA30	0x100
-#define	BCMA_DMP_OOBSELOUTA74	0x104
-#define	BCMA_DMP_OOBSELOUTB30	0x120
-#define	BCMA_DMP_OOBSELOUTB74	0x124
-#define	BCMA_DMP_OOBSELOUTC30	0x140
-#define	BCMA_DMP_OOBSELOUTC74	0x144
-#define	BCMA_DMP_OOBSELOUTD30	0x160
-#define	BCMA_DMP_OOBSELOUTD74	0x164
+/* Common definitions */
+#define	BCMA_OOB_NUM_BANKS	4	/**< number of OOB banks (A, B, C, D) */
+#define	BCMA_OOB_NUM_SEL	8	/**< number of OOB selectors per bank */
+#define	BCMA_OOB_NUM_BUSLINES	32	/**< number of bus lines managed by OOB core */
+
+#define	BCMA_OOB_BANKA		0	/**< bank A index */
+#define	BCMA_OOB_BANKB		1	/**< bank B index */
+#define	BCMA_OOB_BANKC		2	/**< bank C index */
+#define	BCMA_OOB_BANKD		3	/**< bank D index */
+
+/** OOB bank used for interrupt lines */
+#define	BCMA_OOB_BANK_INTR	BCMA_OOB_BANKA
+
+/* DMP agent registers */
+#define	BCMA_DMP_OOBSELINA30	0x000	/**< A0-A3 input selectors */
+#define	BCMA_DMP_OOBSELINA74	0x004	/**< A4-A7 input selectors */
+#define	BCMA_DMP_OOBSELINB30	0x020	/**< B0-B3 input selectors */
+#define	BCMA_DMP_OOBSELINB74	0x024	/**< B4-B7 input selectors */
+#define	BCMA_DMP_OOBSELINC30	0x040	/**< C0-C3 input selectors */
+#define	BCMA_DMP_OOBSELINC74	0x044	/**< C4-C7 input selectors */
+#define	BCMA_DMP_OOBSELIND30	0x060	/**< D0-D3 input selectors */
+#define	BCMA_DMP_OOBSELIND74	0x064	/**< D4-D7 input selectors */
+#define	BCMA_DMP_OOBSELOUTA30	0x100	/**< A0-A3 output selectors */
+#define	BCMA_DMP_OOBSELOUTA74	0x104	/**< A4-A7 output selectors */
+#define	BCMA_DMP_OOBSELOUTB30	0x120	/**< B0-B3 output selectors */
+#define	BCMA_DMP_OOBSELOUTB74	0x124	/**< B4-B7 output selectors */
+#define	BCMA_DMP_OOBSELOUTC30	0x140	/**< C0-C3 output selectors */
+#define	BCMA_DMP_OOBSELOUTC74	0x144	/**< C4-C7 output selectors */
+#define	BCMA_DMP_OOBSELOUTD30	0x160	/**< D0-D3 output selectors */
+#define	BCMA_DMP_OOBSELOUTD74	0x164	/**< D4-D7 output selectors */
 #define	BCMA_DMP_OOBSYNCA	0x200
 #define	BCMA_DMP_OOBSELOUTAEN	0x204
 #define	BCMA_DMP_OOBSYNCB	0x220
@@ -109,18 +132,20 @@
 #define	BCMA_DMP_OOBDINWIDTH	0x364
 #define	BCMA_DMP_OOBDOUTWIDTH	0x368
 
-/* The exact interpretation of these bits is unverified; these
- * are our best guesses as to their use */
-#define	BCMA_DMP_OOBSEL_MASK	0xFF		/**< OOBSEL config mask */
-#define	BCMA_DMP_OOBSEL_0_MASK	BCMA_DMP_OOBSEL_MASK
-#define	BCMA_DMP_OOBSEL_1_MASK	BCMA_DMP_OOBSEL_MASK
-#define	BCMA_DMP_OOBSEL_2_MASK	BCMA_DMP_OOBSEL_MASK
-#define	BCMA_DMP_OOBSEL_3_MASK	BCMA_DMP_OOBSEL_MASK
-#define	BCMA_DMP_OOBSEL_0_SHIFT	0		/**< first OOBSEL config */
-#define	BCMA_DMP_OOBSEL_1_SHIFT	8		/**< second OOBSEL config */
-#define	BCMA_DMP_OOBSEL_2_SHIFT	16		/**< third OOBSEL config */
-#define	BCMA_DMP_OOBSEL_3_SHIFT	24		/**< fouth OOBSEL config */
-#define	BCMA_DMP_OOBSEL_EN	(1 << 7)	/**< enable bit */
+#define	BCMA_DMP_OOBSEL(_base, _bank, _sel)	\
+    (_base + (_bank * 8) + (_sel >= 4 ? 4 : 0))
+
+#define	BCMA_DMP_OOBSELIN(_bank, _sel)		\
+	BCMA_DMP_OOBSEL(BCMA_DMP_OOBSELINA30, _bank, _sel)
+
+#define	BCMA_DMP_OOBSELOUT(_bank, _sel)		\
+	BCMA_DMP_OOBSEL(BCMA_DMP_OOBSELOUTA30, _bank, _sel)
+
+#define	BCMA_DMP_OOBSYNC(_bank)		(BCMA_DMP_OOBSYNCA + (_bank * 8))
+#define	BCMA_DMP_OOBSELOUT_EN(_bank)	(BCMA_DMP_OOBSELOUTAEN + (_bank * 8))
+#define	BCMA_DMP_OOB_EXTWIDTH(_bank)	(BCMA_DMP_OOBAEXTWIDTH + (_bank * 12))
+#define	BCMA_DMP_OOB_INWIDTH(_bank)	(BCMA_DMP_OOBAINWIDTH + (_bank * 12))
+#define	BCMA_DMP_OOB_OUTWIDTH(_bank)	(BCMA_DMP_OOBAOUTWIDTH + (_bank * 12))
 
 // This was inherited from Broadcom's aidmp.h header
 // Is it required for any of our use-cases?
@@ -192,6 +217,34 @@
 #define	BCMA_DMP_COMPONENTID2	0xff8
 #define	BCMA_DMP_COMPONENTID3	0xffc
 
+
+/* OOBSEL(IN|OUT) */
+#define	BCMA_DMP_OOBSEL_MASK		0xFF		/**< OOB selector mask */
+#define	BCMA_DMP_OOBSEL_EN		(1<<7)		/**< OOB selector enable bit */
+#define	BCMA_DMP_OOBSEL_SHIFT(_sel)	((_sel % BCMA_OOB_NUM_SEL) * 8)
+#define	BCMA_DMP_OOBSEL_BUSLINE_MASK	0x7F		/**< OOB selector bus line mask */
+#define	BCMA_DMP_OOBSEL_BUSLINE_SHIFT	0
+
+#define	BCMA_DMP_OOBSEL_0_MASK	BCMA_DMP_OOBSEL_MASK
+#define	BCMA_DMP_OOBSEL_1_MASK	BCMA_DMP_OOBSEL_MASK
+#define	BCMA_DMP_OOBSEL_2_MASK	BCMA_DMP_OOBSEL_MASK
+#define	BCMA_DMP_OOBSEL_3_MASK	BCMA_DMP_OOBSEL_MASK
+
+#define	BCMA_DMP_OOBSEL_4_MASK	BCMA_DMP_OOBSEL_MASK
+#define	BCMA_DMP_OOBSEL_5_MASK	BCMA_DMP_OOBSEL_MASK
+#define	BCMA_DMP_OOBSEL_6_MASK	BCMA_DMP_OOBSEL_MASK
+#define	BCMA_DMP_OOBSEL_7_MASK	BCMA_DMP_OOBSEL_MASK
+
+#define	BCMA_DMP_OOBSEL_0_SHIFT	BCMA_DMP_OOBSEL_SHIFT(0)
+#define	BCMA_DMP_OOBSEL_1_SHIFT	BCMA_DMP_OOBSEL_SHIFT(1)
+#define	BCMA_DMP_OOBSEL_2_SHIFT	BCMA_DMP_OOBSEL_SHIFT(2)
+#define	BCMA_DMP_OOBSEL_3_SHIFT	BCMA_DMP_OOBSEL_SHIFT(3)
+
+#define	BCMA_DMP_OOBSEL_4_SHIFT	BCMA_DMP_OOBSEL_0_SHIFT
+#define	BCMA_DMP_OOBSEL_5_SHIFT	BCMA_DMP_OOBSEL_1_SHIFT
+#define	BCMA_DMP_OOBSEL_6_SHIFT	BCMA_DMP_OOBSEL_2_SHIFT
+#define	BCMA_DMP_OOBSEL_7_SHIFT	BCMA_DMP_OOBSEL_3_SHIFT
+
 /* resetctrl */
 #define	BMCA_DMP_RC_RESET	1
 

Modified: head/sys/dev/bhnd/bcma/bcmavar.h
==============================================================================
--- head/sys/dev/bhnd/bcma/bcmavar.h	Mon Sep  5 21:55:27 2016	(r305443)
+++ head/sys/dev/bhnd/bcma/bcmavar.h	Mon Sep  5 22:11:46 2016	(r305444)
@@ -74,6 +74,9 @@ struct bcma_sport;
 int			 bcma_probe(device_t dev);
 int			 bcma_attach(device_t dev);
 int			 bcma_detach(device_t dev);
+int			 bcma_get_intr_count(device_t dev, device_t child);
+int			 bcma_get_core_ivec(device_t dev, device_t child,
+			     u_int intr, uint32_t *ivec);
 
 int			 bcma_add_children(device_t bus);
 

Modified: head/sys/dev/bhnd/bhnd.c
==============================================================================
--- head/sys/dev/bhnd/bhnd.c	Mon Sep  5 21:55:27 2016	(r305443)
+++ head/sys/dev/bhnd/bhnd.c	Mon Sep  5 22:11:46 2016	(r305444)
@@ -925,9 +925,14 @@ bhnd_generic_print_child(device_t dev, d
 	retval += bus_print_child_header(dev, child);
 
 	rl = BUS_GET_RESOURCE_LIST(dev, child);
+	
+	
 	if (rl != NULL) {
 		retval += resource_list_print_type(rl, "mem", SYS_RES_MEMORY,
 		    "%#jx");
+
+		retval += resource_list_print_type(rl, "irq", SYS_RES_IRQ,
+		    "%#jd");
 	}
 
 	retval += printf(" at core %u", bhnd_get_core_index(child));
@@ -974,8 +979,10 @@ bhnd_generic_probe_nomatch(device_t dev,
 		bhnd_get_device_name(child));
 
 	rl = BUS_GET_RESOURCE_LIST(dev, child);
-	if (rl != NULL)
+	if (rl != NULL) {
 		resource_list_print_type(rl, "mem", SYS_RES_MEMORY, "%#jx");
+		resource_list_print_type(rl, "irq", SYS_RES_IRQ, "%#jd");
+	}
 
 	printf(" at core %u (no driver attached)\n",
 	    bhnd_get_core_index(child));

Modified: head/sys/dev/bhnd/bhnd.h
==============================================================================
--- head/sys/dev/bhnd/bhnd.h	Mon Sep  5 21:55:27 2016	(r305443)
+++ head/sys/dev/bhnd/bhnd.h	Mon Sep  5 22:11:46 2016	(r305444)
@@ -550,6 +550,45 @@ bhnd_read_board_info(device_t dev, struc
 }
 
 /**
+ * Return the number of interrupts to be assigned to @p child via
+ * BHND_BUS_ASSIGN_INTR().
+ * 
+ * @param dev A bhnd bus child device.
+ */
+static inline int
+bhnd_get_intr_count(device_t dev)
+{
+	return (BHND_BUS_GET_INTR_COUNT(device_get_parent(dev), dev));
+}
+
+/**
+ * Return the backplane interrupt vector corresponding to @p dev's given
+ * @p intr number.
+ * 
+ * @param dev A bhnd bus child device.
+ * @param intr The interrupt number being queried. This is equivalent to the
+ * bus resource ID for the interrupt.
+ * @param[out] ivec On success, the assigned hardware interrupt vector be
+ * written to this pointer.
+ *
+ * On bcma(4) devices, this returns the OOB bus line assigned to the
+ * interrupt.
+ *
+ * On siba(4) devices, this returns the target OCP slave flag number assigned
+ * to the interrupt.
+ *
+ * @retval 0		success
+ * @retval ENXIO	If @p intr exceeds the number of interrupts available
+ *			to @p child.
+ */
+static inline int
+bhnd_get_core_ivec(device_t dev, u_int intr, uint32_t *ivec)
+{
+	return (BHND_BUS_GET_CORE_IVEC(device_get_parent(dev), dev, intr,
+	    ivec));
+}
+
+/**
  * Allocate and enable per-core PMU request handling for @p child.
  *
  * The region containing the core's PMU register block (if any) must be

Modified: head/sys/dev/bhnd/bhnd_bus_if.m
==============================================================================
--- head/sys/dev/bhnd/bhnd_bus_if.m	Mon Sep  5 21:55:27 2016	(r305443)
+++ head/sys/dev/bhnd/bhnd_bus_if.m	Mon Sep  5 22:11:46 2016	(r305444)
@@ -1,5 +1,5 @@
 #-
-# Copyright (c) 2015 Landon Fuller <landon at landonf.org>
+# Copyright (c) 2015-2016 Landon Fuller <landonf at FreeBSD.org>
 # All rights reserved.
 #
 # Redistribution and use in source and binary forms, with or without
@@ -96,7 +96,26 @@ CODE {
 	{
 		panic("bhnd_bus_read_boardinfo unimplemented");
 	}
-	
+
+	static int
+	bhnd_bus_null_get_intr_count(device_t dev, device_t child)
+	{
+		panic("bhnd_bus_get_intr_count unimplemented");
+	}
+
+	static int
+	bhnd_bus_null_assign_intr(device_t dev, device_t child, int rid)
+	{
+		panic("bhnd_bus_assign_intr unimplemented");
+	}
+
+	static int
+	bhnd_bus_null_get_core_ivec(device_t dev, device_t child, u_int intr,
+	    uint32_t *ivec)
+	{
+		panic("bhnd_bus_get_core_ivec unimplemented");
+	}
+
 	static void
 	bhnd_bus_null_child_added(device_t dev, device_t child)
 	{
@@ -349,6 +368,78 @@ METHOD void free_devinfo {
 	struct bhnd_devinfo *dinfo;
 };
 
+
+/**
+ * Return the number of interrupts to be assigned to @p child via
+ * BHND_BUS_ASSIGN_INTR().
+ * 
+ * @param dev The bhnd bus parent of @p child.
+ * @param child The bhnd device for which a count should be returned.
+ *
+ * @retval 0		If no interrupts should be assigned.
+ * @retval non-zero	The count of interrupt resource IDs to be
+ *			assigned, starting at rid 0.
+ */
+METHOD int get_intr_count {
+	device_t dev;
+	device_t child;
+} DEFAULT bhnd_bus_null_get_intr_count;
+
+/**
+ * Assign an interrupt to @p child via bus_set_resource().
+ *
+ * The default bus implementation of this method should assign backplane
+ * interrupt values to @p child.
+ *
+ * Bridge-attached bus implementations may instead override standard
+ * interconnect IRQ assignment, providing IRQs inherited from the parent bus.
+ *
+ * TODO: Once we can depend on INTRNG, investigate replacing this with a
+ * bridge-level interrupt controller.
+ * 
+ * @param dev The bhnd bus parent of @p child.
+ * @param child The bhnd device to which an interrupt should be assigned.
+ * @param rid The interrupt resource ID to be assigned.
+ *
+ * @retval 0		If an interrupt was assigned.
+ * @retval non-zero	If assigning an interrupt otherwise fails, a regular
+ *			unix error code will be returned.
+ */
+METHOD int assign_intr {
+	device_t dev;
+	device_t child;
+	int rid;
+} DEFAULT bhnd_bus_null_assign_intr;
+
+/**
+ * Return the backplane interrupt vector corresponding to @p child's given
+ * @p intr number.
+ * 
+ * @param dev The bhnd bus parent of @p child.
+ * @param child The bhnd device for which the assigned interrupt vector should
+ * be queried.
+ * @param intr The interrupt number being queried. This is equivalent to the
+ * bus resource ID for the interrupt.
+ * @param[out] ivec On success, the assigned hardware interrupt vector be
+ * written to this pointer.
+ *
+ * On bcma(4) devices, this returns the OOB bus line assigned to the
+ * interrupt.
+ *
+ * On siba(4) devices, this returns the target OCP slave flag number assigned
+ * to the interrupt.
+ *
+ * @retval 0		success
+ * @retval ENXIO	If @p intr exceeds the number of interrupts available
+ *			to @p child.
+ */
+METHOD int get_core_ivec {
+	device_t dev;
+	device_t child;
+	u_int intr;
+	uint32_t *ivec;
+} DEFAULT bhnd_bus_null_get_core_ivec;
+
 /**
  * Notify a bhnd bus that a child was added.
  *

Modified: head/sys/dev/bhnd/bhnd_nexus.c
==============================================================================
--- head/sys/dev/bhnd/bhnd_nexus.c	Mon Sep  5 21:55:27 2016	(r305443)
+++ head/sys/dev/bhnd/bhnd_nexus.c	Mon Sep  5 22:11:46 2016	(r305444)
@@ -122,6 +122,13 @@ bhnd_nexus_deactivate_resource(device_t 
 	return (0);
 }
 
+static int
+bhnd_nexus_get_intr_count(device_t dev, device_t child)
+{
+	// TODO: arch-specific interrupt handling.
+	return (0);
+}
+
 static device_method_t bhnd_nexus_methods[] = {
 	/* bhnd interface */
 	DEVMETHOD(bhnd_bus_activate_resource,	bhnd_nexus_activate_resource),
@@ -129,6 +136,8 @@ static device_method_t bhnd_nexus_method
 	DEVMETHOD(bhnd_bus_is_hw_disabled,	bhnd_nexus_is_hw_disabled),
 	DEVMETHOD(bhnd_bus_get_attach_type,	bhnd_nexus_get_attach_type),
 
+	DEVMETHOD(bhnd_bus_get_intr_count,	bhnd_nexus_get_intr_count),
+
 	DEVMETHOD_END
 };
 

Modified: head/sys/dev/bhnd/bhndb/bhnd_bhndb.c
==============================================================================
--- head/sys/dev/bhnd/bhndb/bhnd_bhndb.c	Mon Sep  5 21:55:27 2016	(r305443)
+++ head/sys/dev/bhnd/bhndb/bhnd_bhndb.c	Mon Sep  5 22:11:46 2016	(r305444)
@@ -93,6 +93,13 @@ bhnd_bhndb_find_hostb_device(device_t de
 	return (bhnd_match_child(dev, &md));
 }
 
+static int
+bhnd_bhndb_assign_intr(device_t dev, device_t child, int rid)
+{
+	/* Delegate to parent bridge */
+	return (BHND_BUS_ASSIGN_INTR(device_get_parent(dev), child, rid));
+}
+
 static bhnd_clksrc
 bhnd_bhndb_pwrctl_get_clksrc(device_t dev, device_t child,
 	bhnd_clock clock)
@@ -126,6 +133,7 @@ static device_method_t bhnd_bhndb_method
 	DEVMETHOD(bhnd_bus_is_hw_disabled,	bhnd_bhndb_is_hw_disabled),
 	DEVMETHOD(bhnd_bus_find_hostb_device,	bhnd_bhndb_find_hostb_device),
 	DEVMETHOD(bhnd_bus_read_board_info,	bhnd_bhndb_read_board_info),
+	DEVMETHOD(bhnd_bus_assign_intr,		bhnd_bhndb_assign_intr),
 
 	DEVMETHOD(bhnd_bus_pwrctl_get_clksrc,	bhnd_bhndb_pwrctl_get_clksrc),
 	DEVMETHOD(bhnd_bus_pwrctl_gate_clock,	bhnd_bhndb_pwrctl_gate_clock),

Modified: head/sys/dev/bhnd/bhndb/bhndb.c
==============================================================================
--- head/sys/dev/bhnd/bhndb/bhndb.c	Mon Sep  5 21:55:27 2016	(r305443)
+++ head/sys/dev/bhnd/bhndb/bhndb.c	Mon Sep  5 22:11:46 2016	(r305444)
@@ -993,7 +993,7 @@ bhndb_suspend_resource(device_t dev, dev
 
 	sc = device_get_softc(dev);
 
-	// TODO: IRQs?
+	/* Non-MMIO resources (e.g. IRQs) are handled solely by our parent */
 	if (type != SYS_RES_MEMORY)
 		return;
 
@@ -1024,7 +1024,7 @@ bhndb_resume_resource(device_t dev, devi
 
 	sc = device_get_softc(dev);
 
-	// TODO: IRQs?
+	/* Non-MMIO resources (e.g. IRQs) are handled solely by our parent */
 	if (type != SYS_RES_MEMORY)
 		return (0);
 
@@ -1040,7 +1040,6 @@ bhndb_resume_resource(device_t dev, devi
 	    rman_get_rid(r), r, NULL));
 }
 
-
 /**
  * Default bhndb(4) implementation of BUS_READ_IVAR().
  */
@@ -1109,8 +1108,6 @@ bhndb_get_rman(struct bhndb_softc *sc, d
 		case SYS_RES_MEMORY:
 			return (&sc->bus_res->br_mem_rman);
 		case SYS_RES_IRQ:
-			// TODO
-			// return &sc->irq_rman;
 			return (NULL);
 		default:
 			return (NULL);
@@ -1233,6 +1230,15 @@ bhndb_alloc_resource(device_t dev, devic
 	isdefault = RMAN_IS_DEFAULT_RANGE(start, end);
 	rle = NULL;
 
+	/* Fetch the resource manager */
+	rm = bhndb_get_rman(sc, child, type);
+	if (rm == NULL) {
+		/* Delegate to our parent device's bus; the requested
+		 * resource type isn't handled locally. */
+		return (BUS_ALLOC_RESOURCE(device_get_parent(sc->parent_dev),
+		    child, type, rid,  start, end, count, flags));
+	}
+
 	/* Populate defaults */
 	if (!passthrough && isdefault) {
 		/* Fetch the resource list entry. */
@@ -1263,11 +1269,6 @@ bhndb_alloc_resource(device_t dev, devic
 	/* Validate resource addresses */
 	if (start > end || count > ((end - start) + 1))
 		return (NULL);
-	
-	/* Fetch the resource manager */
-	rm = bhndb_get_rman(sc, child, type);
-	if (rm == NULL)
-		return (NULL);
 
 	/* Make our reservation */
 	rv = rman_reserve_resource(rm, start, end, count, flags & ~RF_ACTIVE,
@@ -1310,12 +1311,21 @@ static int
 bhndb_release_resource(device_t dev, device_t child, int type, int rid,
     struct resource *r)
 {
+	struct bhndb_softc		*sc;
 	struct resource_list_entry	*rle;
 	bool				 passthrough;
 	int				 error;
-	
+
+	sc = device_get_softc(dev);
 	passthrough = (device_get_parent(child) != dev);
 
+	/* Delegate to our parent device's bus if the requested resource type
+	 * isn't handled locally. */
+	if (bhndb_get_rman(sc, child, type) == NULL) {
+		return (BUS_RELEASE_RESOURCE(device_get_parent(sc->parent_dev),
+		    child, type, rid, r));
+	}
+
 	/* Deactivate resources */
 	if (rman_get_flags(r) & RF_ACTIVE) {
 		error = BUS_DEACTIVATE_RESOURCE(dev, child, type, rid, r);
@@ -1352,15 +1362,18 @@ bhndb_adjust_resource(device_t dev, devi
 	sc = device_get_softc(dev);
 	error = 0;
 
+	/* Delegate to our parent device's bus if the requested resource type
+	 * isn't handled locally. */
+	rm = bhndb_get_rman(sc, child, type);
+	if (rm == NULL) {
+		return (BUS_ADJUST_RESOURCE(device_get_parent(sc->parent_dev),
+		    child, type, r, start, end));
+	}
+
 	/* Verify basic constraints */
 	if (end <= start)
 		return (EINVAL);
 
-	/* Fetch resource manager */
-	rm = bhndb_get_rman(sc, child, type);
-	if (rm == NULL)
-		return (ENXIO);
-
 	if (!rman_is_region_manager(r, rm))
 		return (ENXIO);
 
@@ -1567,7 +1580,7 @@ bhndb_try_activate_resource(struct bhndb
 
 	BHNDB_LOCK_ASSERT(sc, MA_NOTOWNED);
 
-	// TODO - IRQs
+	/* Only MMIO resources can be mapped via register windows */
 	if (type != SYS_RES_MEMORY)
 		return (ENXIO);
 	
@@ -1678,6 +1691,13 @@ bhndb_activate_resource(device_t dev, de
 {
 	struct bhndb_softc *sc = device_get_softc(dev);
 
+	/* Delegate directly to our parent device's bus if the requested
+	 * resource type isn't handled locally. */
+	if (bhndb_get_rman(sc, child, type) == NULL) {
+		return (BUS_ACTIVATE_RESOURCE(device_get_parent(sc->parent_dev),
+		    child, type, rid, r));
+	}
+
 	return (bhndb_try_activate_resource(sc, child, type, rid, r, NULL));
 }
 
@@ -1695,8 +1715,13 @@ bhndb_deactivate_resource(device_t dev, 
 
 	sc = device_get_softc(dev);
 
-	if ((rm = bhndb_get_rman(sc, child, type)) == NULL)
-		return (EINVAL);
+	/* Delegate directly to our parent device's bus if the requested
+	 * resource type isn't handled locally. */
+	rm = bhndb_get_rman(sc, child, type);
+	if (rm == NULL) {
+		return (BUS_DEACTIVATE_RESOURCE(
+		    device_get_parent(sc->parent_dev), child, type, rid, r));
+	}
 
 	/* Mark inactive */
 	if ((error = rman_deactivate_resource(r)))
@@ -1752,6 +1777,15 @@ bhndb_activate_bhnd_resource(device_t de
 
 	sc = device_get_softc(dev);
 
+	/* Delegate directly to BUS_ACTIVATE_RESOURCE() if the requested
+	 * resource type isn't handled locally. */
+	if (bhndb_get_rman(sc, child, type) == NULL) {
+		error = BUS_ACTIVATE_RESOURCE(dev, child, type, rid, r->res);
+		if (error == 0)
+			r->direct = true;
+		return (error);
+	}
+
 	r_start = rman_get_start(r->res);
 	r_size = rman_get_size(r->res);
 
@@ -1815,7 +1849,7 @@ bhndb_deactivate_bhnd_resource(device_t 
 	    ("RF_ACTIVE not set on direct resource"));
 
 	/* Perform deactivation */
-	error = bus_deactivate_resource(child, type, rid, r->res);
+	error = BUS_DEACTIVATE_RESOURCE(dev, child, type, rid, r->res);
 	if (!error)
 		r->direct = false;
 
@@ -2053,61 +2087,6 @@ bhndb_bus_barrier(device_t dev, device_t
 }
 
 /**
- * Default bhndb(4) implementation of BUS_SETUP_INTR().
- */
-static int
-bhndb_setup_intr(device_t dev, device_t child, struct resource *r,
-    int flags, driver_filter_t filter, driver_intr_t handler, void *arg,
-    void **cookiep)
-{
-	// TODO
-	return (EOPNOTSUPP);
-}
-
-/**
- * Default bhndb(4) implementation of BUS_TEARDOWN_INTR().
- */
-static int
-bhndb_teardown_intr(device_t dev, device_t child, struct resource *r,
-    void *cookie)
-{
-	// TODO
-	return (EOPNOTSUPP);
-}
-
-/**
- * Default bhndb(4) implementation of BUS_CONFIG_INTR().
- */
-static int
-bhndb_config_intr(device_t dev, int irq, enum intr_trigger trig,
-    enum intr_polarity pol)
-{
-	// TODO
-	return (EOPNOTSUPP);
-}
-
-/**
- * Default bhndb(4) implementation of BUS_BIND_INTR().
- */
-static int
-bhndb_bind_intr(device_t dev, device_t child, struct resource *r, int cpu)
-{
-	// TODO
-	return (EOPNOTSUPP);
-}
-
-/**
- * Default bhndb(4) implementation of BUS_DESCRIBE_INTR().
- */
-static int
-bhndb_describe_intr(device_t dev, device_t child, struct resource *irq, void *cookie,
-    const char *descr)
-{
-	// TODO
-	return (EOPNOTSUPP);
-}
-
-/**
  * Default bhndb(4) implementation of BUS_GET_DMA_TAG().
  */
 static bus_dma_tag_t
@@ -2138,11 +2117,11 @@ static device_method_t bhndb_methods[] =
 	DEVMETHOD(bus_activate_resource,	bhndb_activate_resource),
 	DEVMETHOD(bus_deactivate_resource,	bhndb_deactivate_resource),
 
-	DEVMETHOD(bus_setup_intr,		bhndb_setup_intr),
-	DEVMETHOD(bus_teardown_intr,		bhndb_teardown_intr),
-	DEVMETHOD(bus_config_intr,		bhndb_config_intr),
-	DEVMETHOD(bus_bind_intr,		bhndb_bind_intr),
-	DEVMETHOD(bus_describe_intr,		bhndb_describe_intr),
+	DEVMETHOD(bus_setup_intr,		bus_generic_setup_intr),
+	DEVMETHOD(bus_teardown_intr,		bus_generic_teardown_intr),
+	DEVMETHOD(bus_config_intr,		bus_generic_config_intr),
+	DEVMETHOD(bus_bind_intr,		bus_generic_bind_intr),
+	DEVMETHOD(bus_describe_intr,		bus_generic_describe_intr),
 
 	DEVMETHOD(bus_get_dma_tag,		bhndb_get_dma_tag),
 

Modified: head/sys/dev/bhnd/bhndb/bhndb_pci.c
==============================================================================
--- head/sys/dev/bhnd/bhndb/bhndb_pci.c	Mon Sep  5 21:55:27 2016	(r305443)
+++ head/sys/dev/bhnd/bhndb/bhndb_pci.c	Mon Sep  5 22:11:46 2016	(r305444)
@@ -62,6 +62,7 @@ __FBSDID("$FreeBSD$");
 #include "bhndb_pcivar.h"
 #include "bhndb_private.h"
 
+static int		bhndb_pci_init_msi(struct bhndb_pci_softc *sc);
 static int		bhndb_pci_add_children(struct bhndb_pci_softc *sc);
 
 static int		bhndb_enable_pci_clocks(struct bhndb_pci_softc *sc);
@@ -78,6 +79,8 @@ static void		bhndb_init_sromless_pci_con
 static bus_addr_t	bhndb_pci_sprom_addr(struct bhndb_pci_softc *sc);
 static bus_size_t	bhndb_pci_sprom_size(struct bhndb_pci_softc *sc);
 
+#define	BHNDB_PCI_MSI_COUNT	1
+
 /** 
  * Default bhndb_pci implementation of device_probe().
  * 
@@ -103,6 +106,33 @@ bhndb_pci_probe(device_t dev)
 	return (BUS_PROBE_DEFAULT);
 }
 
+/* Configure MSI interrupts */
+static int
+bhndb_pci_init_msi(struct bhndb_pci_softc *sc)
+{
+	int error;
+
+	/* Is MSI available? */
+	if (pci_msi_count(sc->parent) < BHNDB_PCI_MSI_COUNT)
+		return (ENXIO);
+
+	/* Allocate expected message count */
+	sc->intr.msi_count = BHNDB_PCI_MSI_COUNT;
+	if ((error = pci_alloc_msi(sc->parent, &sc->intr.msi_count))) {
+		device_printf(sc->dev, "failed to allocate MSI interrupts: "
+		    "%d\n", error);
+		return (error);
+	}
+
+	if (sc->intr.msi_count < BHNDB_PCI_MSI_COUNT)
+		return (ENXIO);
+
+	/* MSI uses resource IDs starting at 1 */
+	sc->intr.intr_rid = 1;
+
+	return (0);
+}
+
 static int
 bhndb_pci_attach(device_t dev)
 {
@@ -114,6 +144,21 @@ bhndb_pci_attach(device_t dev)
 	sc->parent = device_get_parent(dev);
 	sc->set_regwin = bhndb_pci_compat_setregwin;
 
+	/* Enable PCI bus mastering */
+	pci_enable_busmaster(sc->parent);
+
+	/* Set up interrupt handling */
+	if (bhndb_pci_init_msi(sc) == 0) {
+		device_printf(dev, "Using MSI interrupts on %s\n",
+		    device_get_nameunit(sc->parent));
+	} else {
+		device_printf(dev, "Using INTx interrupts on %s\n",
+		    device_get_nameunit(sc->parent));
+		sc->intr.intr_rid = 0;
+	}
+
+	/* Determine our bridge device class */
+	sc->pci_devclass = BHND_DEVCLASS_PCI;
 	if (pci_find_cap(sc->parent, PCIY_EXPRESS, &reg) == 0)
 		sc->pci_devclass = BHND_DEVCLASS_PCIE;
 	else
@@ -153,6 +198,9 @@ bhndb_pci_attach(device_t dev)
 cleanup:
 	device_delete_children(dev);
 	bhndb_disable_pci_clocks(sc);
+	if (sc->intr.msi_count > 0)
+		pci_release_msi(dev);
+
 	pci_disable_busmaster(sc->parent);
 
 	return (error);
@@ -178,6 +226,10 @@ bhndb_pci_detach(device_t dev)
 	if ((error = bhndb_disable_pci_clocks(sc)))
 		return (error);
 
+	/* Release MSI interrupts */
+	if (sc->intr.msi_count > 0)
+		pci_release_msi(dev);
+
 	/* Disable PCI bus mastering */
 	pci_disable_busmaster(sc->parent);
 
@@ -679,6 +731,29 @@ bhndb_pci_pwrctl_ungate_clock(device_t d
 	return (bhndb_enable_pci_clocks(sc));
 }
 
+static int
+bhndb_pci_assign_intr(device_t dev, device_t child, int rid)
+{
+	struct bhndb_pci_softc	*sc;
+	rman_res_t		 start, count;
+	int			 error;
+
+	sc = device_get_softc(dev);
+
+	/* Is the rid valid? */
+	if (rid >= bhnd_get_intr_count(child))
+		return (EINVAL);
+ 
+	/* Fetch our common PCI interrupt's start/count. */
+	error = bus_get_resource(sc->parent, SYS_RES_IRQ, sc->intr.intr_rid,
+	    &start, &count);
+	if (error)
+		return (error);
+
+	/* Add to child's resource list */
+        return (bus_set_resource(child, SYS_RES_IRQ, rid, start, count));
+}
+
 static device_method_t bhndb_pci_methods[] = {
 	/* Device interface */
 	DEVMETHOD(device_probe,			bhndb_pci_probe),
@@ -688,6 +763,8 @@ static device_method_t bhndb_pci_methods
 	DEVMETHOD(device_detach,		bhndb_pci_detach),
 
 	/* BHND interface */
+	DEVMETHOD(bhnd_bus_assign_intr,		bhndb_pci_assign_intr),
+
 	DEVMETHOD(bhnd_bus_pwrctl_get_clksrc,	bhndb_pci_pwrctl_get_clksrc),
 	DEVMETHOD(bhnd_bus_pwrctl_gate_clock,	bhndb_pci_pwrctl_gate_clock),
 	DEVMETHOD(bhnd_bus_pwrctl_ungate_clock,	bhndb_pci_pwrctl_ungate_clock),

Modified: head/sys/dev/bhnd/bhndb/bhndb_pcivar.h
==============================================================================
--- head/sys/dev/bhnd/bhndb/bhndb_pcivar.h	Mon Sep  5 21:55:27 2016	(r305443)
+++ head/sys/dev/bhnd/bhndb/bhndb_pcivar.h	Mon Sep  5 22:11:46 2016	(r305444)
@@ -48,11 +48,19 @@ struct bhndb_pci_softc;
 typedef int (*bhndb_pci_set_regwin_t)(struct bhndb_pci_softc *sc,
 	         const struct bhndb_regwin *rw, bhnd_addr_t addr);
 
+/* bhndb_pci interrupt state */
+struct bhndb_pci_intr {
+	int		msi_count;	/**< MSI count, or 0 */
+	int		intr_rid;	/**< interrupt resource ID.*/
+};
+
 struct bhndb_pci_softc {
 	struct bhndb_softc	bhndb;		/**< parent softc */
 	device_t		dev;		/**< bridge device */
 	device_t		parent;		/**< parent PCI device */
 	bhnd_devclass_t		pci_devclass;	/**< PCI core's devclass */
+	struct bhndb_pci_intr	intr;		/**< PCI interrupt config */
+
 	bhndb_pci_set_regwin_t	set_regwin;	/**< regwin handler */
 };
 

Modified: head/sys/dev/bhnd/cores/pmu/bhnd_pmu_subr.c
==============================================================================
--- head/sys/dev/bhnd/cores/pmu/bhnd_pmu_subr.c	Mon Sep  5 21:55:27 2016	(r305443)
+++ head/sys/dev/bhnd/cores/pmu/bhnd_pmu_subr.c	Mon Sep  5 22:11:46 2016	(r305444)
@@ -3395,14 +3395,14 @@ bhnd_pmu_radio_enable(struct bhnd_pmu_so
 
 		if (enable) {
 			oobsel |= BHND_PMU_SET_BITS(BCMA_DMP_OOBSEL_EN,
-			    BCMA_DMP_OOBSEL_1);
+			    BCMA_DMP_OOBSEL_5);
 			oobsel |= BHND_PMU_SET_BITS(BCMA_DMP_OOBSEL_EN,
-			    BCMA_DMP_OOBSEL_2);
+			    BCMA_DMP_OOBSEL_6);
 		} else {
 			oobsel &= ~BHND_PMU_SET_BITS(BCMA_DMP_OOBSEL_EN,
-			    BCMA_DMP_OOBSEL_1);
+			    BCMA_DMP_OOBSEL_5);
 			oobsel &= ~BHND_PMU_SET_BITS(BCMA_DMP_OOBSEL_EN,
-			    BCMA_DMP_OOBSEL_2);
+			    BCMA_DMP_OOBSEL_6);
 		}
 
 		bhnd_write_config(d11core, BCMA_DMP_OOBSELOUTB74, oobsel, 4);

Modified: head/sys/dev/bhnd/siba/siba.c
==============================================================================
--- head/sys/dev/bhnd/siba/siba.c	Mon Sep  5 21:55:27 2016	(r305443)
+++ head/sys/dev/bhnd/siba/siba.c	Mon Sep  5 22:11:46 2016	(r305444)
@@ -373,6 +373,60 @@ siba_get_region_addr(device_t dev, devic
 	return (0);
 }
 
+/**
+ * Default siba(4) bus driver implementation of BHND_BUS_GET_INTR_COUNT().
+ * 
+ * This implementation consults @p child's configuration block mapping,
+ * returning SIBA_CORE_NUM_INTR if a valid CFG0 block is mapped.
+ */
+int
+siba_get_intr_count(device_t dev, device_t child)
+{
+	struct siba_devinfo *dinfo;
+
+	/* delegate non-bus-attached devices to our parent */
+	if (device_get_parent(child) != dev)
+		return (BHND_BUS_GET_INTR_COUNT(device_get_parent(dev), child));
+
+	dinfo = device_get_ivars(child);
+
+	/* We can get/set interrupt sbflags on any core with a valid cfg0
+	 * block; whether the core actually makes use of it is another matter
+	 * entirely */
+	if (dinfo->cfg[0] == NULL)
+		return (0);
+
+	return (SIBA_CORE_NUM_INTR);
+}
+
+/**
+ * Default siba(4) bus driver implementation of BHND_BUS_GET_CORE_IVEC().
+ * 
+ * This implementation consults @p child's CFG0 register block,
+ * returning the interrupt flag assigned to @p child.
+ */
+int
+siba_get_core_ivec(device_t dev, device_t child, u_int intr, uint32_t *ivec)
+{
+	struct siba_devinfo	*dinfo;
+	uint32_t		 tpsflag;
+
+	/* delegate non-bus-attached devices to our parent */
+	if (device_get_parent(child) != dev)
+		return (BHND_BUS_GET_CORE_IVEC(device_get_parent(dev), child,
+		    intr, ivec));
+

*** DIFF OUTPUT TRUNCATED AT 1000 LINES ***


More information about the svn-src-all mailing list