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 <lan...@landonf.org>
+# Copyright (c) 2015-2016 Landon Fuller <land...@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 ***
_______________________________________________
svn-src-all@freebsd.org mailing list
https://lists.freebsd.org/mailman/listinfo/svn-src-all
To unsubscribe, send any mail to "svn-src-all-unsubscr...@freebsd.org"

Reply via email to