Page Menu
Home
FreeBSD
Search
Configure Global Search
Log In
Files
F152559626
D7769.diff
No One
Temporary
Actions
View File
Edit File
Delete File
View Transforms
Subscribe
Mute Notifications
Flag For Later
Award Token
Size
35 KB
Referenced Files
None
Subscribers
None
D7769.diff
View Options
Index: sys/dev/bhnd/bcma/bcma.c
===================================================================
--- sys/dev/bhnd/bcma/bcma.c
+++ sys/dev/bhnd/bcma/bcma.c
@@ -41,8 +41,11 @@
#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 @@
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 @@
/* 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 @@
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 @@
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
};
Index: sys/dev/bhnd/bcma/bcma_dmp.h
===================================================================
--- sys/dev/bhnd/bcma/bcma_dmp.h
+++ sys/dev/bhnd/bcma/bcma_dmp.h
@@ -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
Index: sys/dev/bhnd/bcma/bcmavar.h
===================================================================
--- sys/dev/bhnd/bcma/bcmavar.h
+++ sys/dev/bhnd/bcma/bcmavar.h
@@ -74,6 +74,9 @@
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);
Index: sys/dev/bhnd/bhnd.h
===================================================================
--- sys/dev/bhnd/bhnd.h
+++ sys/dev/bhnd/bhnd.h
@@ -550,6 +550,45 @@
}
/**
+ * 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
Index: sys/dev/bhnd/bhnd.c
===================================================================
--- sys/dev/bhnd/bhnd.c
+++ sys/dev/bhnd/bhnd.c
@@ -925,9 +925,14 @@
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_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));
Index: sys/dev/bhnd/bhnd_bus_if.m
===================================================================
--- sys/dev/bhnd/bhnd_bus_if.m
+++ sys/dev/bhnd/bhnd_bus_if.m
@@ -1,5 +1,5 @@
#-
-# Copyright (c) 2015 Landon Fuller <landon@landonf.org>
+# Copyright (c) 2015-2016 Landon Fuller <landonf@FreeBSD.org>
# All rights reserved.
#
# Redistribution and use in source and binary forms, with or without
@@ -96,7 +96,26 @@
{
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 @@
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.
*
Index: sys/dev/bhnd/bhnd_nexus.c
===================================================================
--- sys/dev/bhnd/bhnd_nexus.c
+++ sys/dev/bhnd/bhnd_nexus.c
@@ -122,6 +122,13 @@
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 @@
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
};
Index: sys/dev/bhnd/bhndb/bhnd_bhndb.c
===================================================================
--- sys/dev/bhnd/bhndb/bhnd_bhndb.c
+++ sys/dev/bhnd/bhndb/bhnd_bhndb.c
@@ -82,6 +82,13 @@
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)
@@ -114,6 +121,7 @@
DEVMETHOD(bhnd_bus_get_attach_type, bhnd_bhndb_get_attach_type),
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),
Index: sys/dev/bhnd/bhndb/bhndb.c
===================================================================
--- sys/dev/bhnd/bhndb/bhndb.c
+++ sys/dev/bhnd/bhndb/bhndb.c
@@ -986,7 +986,7 @@
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;
@@ -1017,7 +1017,7 @@
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);
@@ -1033,7 +1033,6 @@
rman_get_rid(r), r, NULL));
}
-
/**
* Default bhndb(4) implementation of BUS_READ_IVAR().
*/
@@ -1102,8 +1101,6 @@
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);
@@ -1229,6 +1226,15 @@
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. */
@@ -1259,11 +1265,6 @@
/* 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,
@@ -1306,12 +1307,21 @@
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);
@@ -1348,15 +1358,18 @@
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);
@@ -1563,7 +1576,7 @@
BHNDB_LOCK_ASSERT(sc, MA_NOTOWNED);
- // TODO - IRQs
+ /* Only MMIO resources can be mapped via register windows */
if (type != SYS_RES_MEMORY)
return (ENXIO);
@@ -1674,6 +1687,13 @@
{
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));
}
@@ -1691,8 +1711,13 @@
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)))
@@ -1748,6 +1773,15 @@
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);
@@ -1811,7 +1845,7 @@
("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;
@@ -2049,61 +2083,6 @@
}
/**
- * 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
@@ -2134,11 +2113,11 @@
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),
Index: sys/dev/bhnd/bhndb/bhndb_pci.c
===================================================================
--- sys/dev/bhnd/bhndb/bhndb_pci.c
+++ sys/dev/bhnd/bhndb/bhndb_pci.c
@@ -62,6 +62,7 @@
#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 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 @@
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 @@
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, ®) == 0)
sc->pci_devclass = BHND_DEVCLASS_PCIE;
else
@@ -153,6 +198,9 @@
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 @@
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 @@
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 @@
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),
Index: sys/dev/bhnd/bhndb/bhndb_pcivar.h
===================================================================
--- sys/dev/bhnd/bhndb/bhndb_pcivar.h
+++ sys/dev/bhnd/bhndb/bhndb_pcivar.h
@@ -48,11 +48,19 @@
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 */
};
Index: sys/dev/bhnd/cores/pmu/bhnd_pmu_subr.c
===================================================================
--- sys/dev/bhnd/cores/pmu/bhnd_pmu_subr.c
+++ sys/dev/bhnd/cores/pmu/bhnd_pmu_subr.c
@@ -3395,14 +3395,14 @@
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);
Index: sys/dev/bhnd/siba/siba.c
===================================================================
--- sys/dev/bhnd/siba/siba.c
+++ sys/dev/bhnd/siba/siba.c
@@ -373,6 +373,60 @@
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));
+
+ /* Must be a valid interrupt ID */
+ if (intr >= siba_get_intr_count(dev, child))
+ return (ENXIO);
+
+ /* Fetch sbflag number */
+ dinfo = device_get_ivars(child);
+ tpsflag = bhnd_bus_read_4(dinfo->cfg[0], SIBA_CFG0_TPSFLAG);
+ *ivec = SIBA_REG_GET(tpsflag, TPS_NUM0);
+
+ return (0);
+}
/**
* Register all address space mappings for @p di.
@@ -538,6 +592,7 @@
device_t child;
uint32_t idhigh, idlow;
rman_res_t r_count, r_end, r_start;
+ int nintr;
/* Map the core's register block */
rid = 0;
@@ -594,6 +649,16 @@
if ((error = siba_map_cfg_resources(dev, dinfo)))
goto cleanup;
+ /* Assign interrupts */
+ nintr = bhnd_get_intr_count(child);
+ for (int rid = 0; rid < nintr; rid++) {
+ error = BHND_BUS_ASSIGN_INTR(dev, child, rid);
+ if (error) {
+ device_printf(dev, "failed to assign interrupt "
+ "%d to core %u: %d\n", rid, i, error);
+ }
+ }
+
/* If pins are floating or the hardware is otherwise
* unpopulated, the device shouldn't be used. */
if (bhnd_is_hw_disabled(child))
@@ -639,6 +704,8 @@
DEVMETHOD(bhnd_bus_get_port_rid, siba_get_port_rid),
DEVMETHOD(bhnd_bus_decode_port_rid, siba_decode_port_rid),
DEVMETHOD(bhnd_bus_get_region_addr, siba_get_region_addr),
+ DEVMETHOD(bhnd_bus_get_intr_count, siba_get_intr_count),
+ DEVMETHOD(bhnd_bus_get_core_ivec, siba_get_core_ivec),
DEVMETHOD_END
};
Index: sys/dev/bhnd/siba/siba_bhndb.c
===================================================================
--- sys/dev/bhnd/siba/siba_bhndb.c
+++ sys/dev/bhnd/siba/siba_bhndb.c
@@ -271,7 +271,6 @@
return (0);
}
-
static device_method_t siba_bhndb_methods[] = {
/* Device interface */
DEVMETHOD(device_probe, siba_bhndb_probe),
Index: sys/dev/bhnd/siba/sibareg.h
===================================================================
--- sys/dev/bhnd/siba/sibareg.h
+++ sys/dev/bhnd/siba/sibareg.h
@@ -48,6 +48,7 @@
#define SIBA_ENUM_ADDR BHND_DEFAULT_CHIPC_ADDR /**< enumeration space */
#define SIBA_ENUM_SIZE 0x00100000 /**< size of the enumeration space */
#define SIBA_CORE_SIZE BHND_DEFAULT_CORE_SIZE /**< per-core register block size */
+#define SIBA_CORE_NUM_INTR 1 /**< number of per-core interrupt lines */
#define SIBA_MAX_CORES \
(SIBA_ENUM_SIZE/SIBA_CORE_SIZE) /**< Maximum number of cores */
@@ -119,6 +120,7 @@
/* sbtpsflag */
#define SIBA_TPS_NUM0_MASK 0x3f /* interrupt sbFlag # generated by this core */
+#define SIBA_TPS_NUM0_SHIFT 0
#define SIBA_TPS_F0EN0 0x40 /* interrupt is always sent on the backplane */
/* sbtmerrlog */
Index: sys/dev/bhnd/siba/sibavar.h
===================================================================
--- sys/dev/bhnd/siba/sibavar.h
+++ sys/dev/bhnd/siba/sibavar.h
@@ -54,6 +54,9 @@
int siba_detach(device_t dev);
int siba_resume(device_t dev);
int siba_suspend(device_t dev);
+int siba_get_intr_count(device_t dev, device_t child);
+int siba_get_core_ivec(device_t dev, device_t child,
+ u_int intr, uint32_t *ivec);
uint16_t siba_get_bhnd_mfgid(uint16_t ocp_vendor);
Index: sys/dev/bwn/bwn_mac.c
===================================================================
--- sys/dev/bwn/bwn_mac.c
+++ sys/dev/bwn/bwn_mac.c
@@ -47,16 +47,12 @@
#include "bhnd_nvram_map.h"
-static const struct resource_spec bwn_rspec[] = {
- { SYS_RES_MEMORY, 0, RF_ACTIVE },
- { -1, -1, 0 }
-};
-
-#define RSPEC_LEN (sizeof(bwn_rspec)/sizeof(bwn_rspec[0]))
-
struct bwn_softc {
- struct resource_spec rspec[RSPEC_LEN];
- struct bhnd_resource *res[RSPEC_LEN-1];
+ int mem_rid;
+ struct bhnd_resource *mem_res;
+
+ int intr_rid;
+ struct resource *intr_res;
};
static const struct bwn_device {
@@ -89,28 +85,50 @@
bwn_attach(device_t dev)
{
struct bwn_softc *sc;
- struct bhnd_resource *r;
int error;
sc = device_get_softc(dev);
- memcpy(sc->rspec, bwn_rspec, sizeof(bwn_rspec));
- if ((error = bhnd_alloc_resources(dev, sc->rspec, sc->res)))
- return (error);
+ /* Allocate device resources */
+ sc->mem_rid = 0;
+ sc->mem_res = bhnd_alloc_resource_any(dev, SYS_RES_MEMORY,
+ &sc->mem_rid, RF_ACTIVE);
+ if (sc->mem_res == NULL) {
+ device_printf(dev, "failed to allocate device registers\n");
+ error = ENXIO;
+ goto cleanup;
+ }
- // XXX TODO
- r = sc->res[0];
- device_printf(dev, "got rid=%d res=%p\n", sc->rspec[0].rid, r);
+ sc->intr_rid = 0;
+ sc->intr_res = bus_alloc_resource_any(dev, SYS_RES_IRQ, &sc->intr_rid,
+ RF_ACTIVE|RF_SHAREABLE);
+ if (sc->intr_res == NULL) {
+ device_printf(dev, "failed to allocate device interrupt\n");
+ error = ENXIO;
+ goto cleanup;
+ }
+ // TODO
uint8_t macaddr[6];
error = bhnd_nvram_getvar_array(dev, BHND_NVAR_MACADDR, macaddr,
sizeof(macaddr), BHND_NVRAM_TYPE_UINT8);
if (error)
- return (error);
+ device_printf(dev, "error fetching macaddr: %d\n", error);
+ else
+ device_printf(dev, "got macaddr %6D\n", macaddr, ":");
- device_printf(dev, "got macaddr %6D\n", macaddr, ":");
-
return (0);
+
+cleanup:
+ if (sc->mem_res != NULL)
+ bhnd_release_resource(dev, SYS_RES_MEMORY, sc->mem_rid,
+ sc->mem_res);
+
+ if (sc->intr_res != NULL)
+ bus_release_resource(dev, SYS_RES_IRQ, sc->intr_rid,
+ sc->intr_res);
+
+ return (error);
}
static int
@@ -119,7 +137,9 @@
struct bwn_softc *sc;
sc = device_get_softc(dev);
- bhnd_release_resources(dev, sc->rspec, sc->res);
+
+ bhnd_release_resource(dev, SYS_RES_MEMORY, sc->mem_rid, sc->mem_res);
+ bus_release_resource(dev, SYS_RES_IRQ, sc->intr_rid, sc->intr_res);
return (0);
}
File Metadata
Details
Attached
Mime Type
text/plain
Expires
Thu, Apr 16, 4:47 PM (5 h, 51 m)
Storage Engine
blob
Storage Format
Raw Data
Storage Handle
31559709
Default Alt Text
D7769.diff (35 KB)
Attached To
Mode
D7769: Implement bhnd(4) backplane interrupt handling.
Attached
Detach File
Event Timeline
Log In to Comment