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, ®) == 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