Author: landonf
Date: Tue Nov 21 23:15:20 2017
New Revision: 326079
URL: https://svnweb.freebsd.org/changeset/base/326079

Log:
  bhnd(4): implement MIPS and PCI(e) interrupt support
  
  On BHND MIPS SoCs, this replaces the use of hard-coded MIPS IRQ#s in the
  common bhnd(4) core drivers; we now register an INTRNG child PIC that
  handles routing of backplane interrupt vectors via the MIPS core.
  
  On BHND PCI devices, backplane interrupt vectors are now routed to the
  PCI/PCIe host bridge core when bus_setup_intr() is called, where they are
  dispatched by the PCI core via a host interrupt (e.g. INTx/MSI).
  
  The bhndb(4) bridge driver tracks registered interrupt handlers for the
  bridged bhnd(4) devices and manages backplane interrupt routing, while
  delegating actual bus interrupt setup/teardown to the parent bus on behalf
  of the bridged cores.
  
  Approved by:  adrian (mentor, implicit)
  Sponsored by: The FreeBSD Foundation
  Differential Revision:        https://reviews.freebsd.org/D12518

Added:
  head/sys/mips/broadcom/bcm_mips.c   (contents, props changed)
  head/sys/mips/broadcom/bcm_mipsvar.h   (contents, props changed)
Modified:
  head/sys/dev/bhnd/bcma/bcma.c
  head/sys/dev/bhnd/bcma/bcma_subr.c
  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_ids.h
  head/sys/dev/bhnd/bhnd_match.h
  head/sys/dev/bhnd/bhnd_subr.c
  head/sys/dev/bhnd/bhndb/bhnd_bhndb.c
  head/sys/dev/bhnd/bhndb/bhndb.c
  head/sys/dev/bhnd/bhndb/bhndb_if.m
  head/sys/dev/bhnd/bhndb/bhndb_pci.c
  head/sys/dev/bhnd/bhndb/bhndb_pcireg.h
  head/sys/dev/bhnd/bhndb/bhndb_pcivar.h
  head/sys/dev/bhnd/bhndb/bhndb_private.h
  head/sys/dev/bhnd/bhndb/bhndb_subr.c
  head/sys/dev/bhnd/bhndb/bhndbvar.h
  head/sys/dev/bhnd/bhndvar.h
  head/sys/dev/bhnd/cores/chipc/chipc.c
  head/sys/dev/bhnd/cores/chipc/chipc_private.h
  head/sys/dev/bhnd/cores/chipc/chipc_subr.c
  head/sys/dev/bhnd/cores/chipc/chipcvar.h
  head/sys/dev/bhnd/cores/pci/bhnd_pci_hostb.c
  head/sys/dev/bhnd/cores/usb/bhnd_usb.c
  head/sys/dev/bhnd/cores/usb/bhnd_usbvar.h
  head/sys/dev/bhnd/siba/siba.c
  head/sys/dev/bhnd/siba/siba_bhndb.c
  head/sys/dev/bhnd/siba/siba_erom.c
  head/sys/dev/bhnd/siba/siba_subr.c
  head/sys/dev/bhnd/siba/sibareg.h
  head/sys/dev/bhnd/siba/sibavar.h
  head/sys/mips/broadcom/bcm_bmips.c
  head/sys/mips/broadcom/bcm_machdep.c
  head/sys/mips/broadcom/bcm_machdep.h
  head/sys/mips/broadcom/bcm_mips74k.c
  head/sys/mips/broadcom/bcm_mips74kreg.h
  head/sys/mips/broadcom/bcma_nexus.c
  head/sys/mips/broadcom/bhnd_nexus.c
  head/sys/mips/broadcom/files.broadcom
  head/sys/mips/broadcom/siba_nexus.c
  head/sys/mips/include/intr.h
  head/sys/mips/mips/mips_pic.c

Modified: head/sys/dev/bhnd/bcma/bcma.c
==============================================================================
--- head/sys/dev/bhnd/bcma/bcma.c       Tue Nov 21 22:06:49 2017        
(r326078)
+++ head/sys/dev/bhnd/bcma/bcma.c       Tue Nov 21 23:15:20 2017        
(r326079)
@@ -1,7 +1,11 @@
 /*-
- * Copyright (c) 2015 Landon Fuller <lan...@landonf.org>
+ * Copyright (c) 2015-2016 Landon Fuller <lan...@landonf.org>
+ * Copyright (c) 2017 The FreeBSD Foundation
  * All rights reserved.
  *
+ * Portions of this software were developed by Landon Fuller
+ * under sponsorship from the FreeBSD Foundation.
+ *
  * Redistribution and use in source and binary forms, with or without
  * modification, are permitted provided that the following conditions
  * are met:
@@ -124,7 +128,7 @@ bcma_child_deleted(device_t dev, device_t child)
 
        /* Free bcma device info */
        if ((dinfo = device_get_ivars(child)) != NULL)
-               bcma_free_dinfo(dev, dinfo);
+               bcma_free_dinfo(dev, child, dinfo);
 
        device_set_ivars(child, NULL);
 }
@@ -613,66 +617,46 @@ bcma_get_region_addr(device_t dev, device_t child, bhn
 
 /**
  * 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
+u_int
 bcma_get_intr_count(device_t dev, device_t child)
 {
-       struct bcma_devinfo     *dinfo;
-       uint32_t                 dmpcfg, oobw;
+       struct bcma_devinfo *dinfo;
 
-       dinfo = device_get_ivars(child);
+       /* 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));
 
-       /* 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);
+       dinfo = device_get_ivars(child);
+       return (dinfo->num_intrs);
 }
 
 /**
- * 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.
+ * Default bcma(4) bus driver implementation of BHND_BUS_GET_INTR_IVEC().
  */
 int
-bcma_get_core_ivec(device_t dev, device_t child, u_int intr, uint32_t *ivec)
+bcma_get_intr_ivec(device_t dev, device_t child, u_int intr, u_int *ivec)
 {
        struct bcma_devinfo     *dinfo;
-       uint32_t                 oobsel;
+       struct bcma_intr        *desc;
 
+       /* delegate non-bus-attached devices to our parent */
+       if (device_get_parent(child) != dev) {
+               return (BHND_BUS_GET_INTR_IVEC(device_get_parent(dev), child,
+                   intr, ivec));
+       }
+
        dinfo = device_get_ivars(child);
 
-       /* Interrupt ID must be valid. */
-       if (intr >= bcma_get_intr_count(dev, child))
-               return (ENXIO);
+       STAILQ_FOREACH(desc, &dinfo->intrs, i_link) {
+               if (desc->i_sel == intr) {
+                       *ivec = desc->i_busline;
+                       return (0);
+               }
+       }
 
-       /* 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);
+       /* Not found */
+       return (ENXIO);
 }
 
 /**
@@ -707,8 +691,6 @@ 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) {
@@ -718,27 +700,12 @@ bcma_add_children(device_t bus)
 
                /* Initialize device ivars */
                dinfo = device_get_ivars(child);
-               if ((error = bcma_init_dinfo(bus, dinfo, corecfg)))
+               if ((error = bcma_init_dinfo(bus, child, dinfo, corecfg)))
                        goto cleanup;
 
                /* The dinfo instance now owns the corecfg value */
                corecfg = NULL;
 
-               /* Allocate device's agent registers, if any */
-               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))
@@ -794,7 +761,7 @@ static device_method_t bcma_methods[] = {
        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(bhnd_bus_get_intr_ivec,       bcma_get_intr_ivec),
 
        DEVMETHOD_END
 };

Modified: head/sys/dev/bhnd/bcma/bcma_subr.c
==============================================================================
--- head/sys/dev/bhnd/bcma/bcma_subr.c  Tue Nov 21 22:06:49 2017        
(r326078)
+++ head/sys/dev/bhnd/bcma/bcma_subr.c  Tue Nov 21 23:15:20 2017        
(r326079)
@@ -1,7 +1,11 @@
 /*-
- * Copyright (c) 2015 Landon Fuller <lan...@landonf.org>
+ * Copyright (c) 2015-2016 Landon Fuller <lan...@landonf.org>
+ * Copyright (c) 2017 The FreeBSD Foundation
  * All rights reserved.
  *
+ * Portions of this software were developed by Landon Fuller
+ * under sponsorship from the FreeBSD Foundation.
+ *
  * Redistribution and use in source and binary forms, with or without
  * modification, are permitted provided that the following conditions
  * are met:
@@ -154,7 +158,7 @@ bcma_corecfg_get_port_list(struct bcma_corecfg *cfg, b
  * @param ports The set of ports to be enumerated
  */
 static void
-bcma_dinfo_init_resource_info(device_t bus, struct bcma_devinfo *dinfo,
+bcma_dinfo_init_port_resource_info(device_t bus, struct bcma_devinfo *dinfo,
     struct bcma_sport_list *ports)
 {
        struct bcma_map         *map;
@@ -193,7 +197,127 @@ bcma_dinfo_init_resource_info(device_t bus, struct bcm
 }
 
 
+
 /**
+ * Allocate the per-core agent register block for a device info structure.
+ * 
+ * If an agent0.0 region is not defined on @p dinfo, the device info
+ * agent resource is set to NULL and 0 is returned.
+ * 
+ * @param bus The requesting bus device.
+ * @param child The bcma child device.
+ * @param dinfo The device info associated with @p child
+ * 
+ * @retval 0 success
+ * @retval non-zero resource allocation failed.
+ */
+static int
+bcma_dinfo_init_agent(device_t bus, device_t child, struct bcma_devinfo *dinfo)
+{
+       bhnd_addr_t     addr;
+       bhnd_size_t     size;
+       rman_res_t      r_start, r_count, r_end;
+       int             error;
+
+       KASSERT(dinfo->res_agent == NULL, ("double allocation of agent"));
+
+       /* Verify that the agent register block exists and is
+        * mappable */
+       if (bhnd_get_port_rid(child, BHND_PORT_AGENT, 0, 0) == -1)
+               return (0);     /* nothing to do */
+
+       /* Fetch the address of the agent register block */
+       error = bhnd_get_region_addr(child, BHND_PORT_AGENT, 0, 0,
+           &addr, &size);
+       if (error) {
+               device_printf(bus, "failed fetching agent register block "
+                   "address for core %u\n", BCMA_DINFO_COREIDX(dinfo));
+               return (error);
+       }
+
+       /* Allocate the resource */
+       r_start = addr;
+       r_count = size;
+       r_end = r_start + r_count - 1;
+
+       dinfo->rid_agent = BCMA_AGENT_RID(dinfo);
+       dinfo->res_agent = BHND_BUS_ALLOC_RESOURCE(bus, bus, SYS_RES_MEMORY,
+           &dinfo->rid_agent, r_start, r_end, r_count, RF_ACTIVE|RF_SHAREABLE);
+       if (dinfo->res_agent == NULL) {
+               device_printf(bus, "failed allocating agent register block for "
+                   "core %u\n", BCMA_DINFO_COREIDX(dinfo));
+               return (ENXIO);
+       }
+
+       return (0);
+}
+
+/**
+ * Populate the list of interrupts for a device info structure
+ * previously initialized via bcma_dinfo_alloc_agent().
+ * 
+ * If an agent0.0 region is not mapped on @p dinfo, the OOB interrupt bank is
+ * assumed to be unavailable and 0 is returned.
+ * 
+ * @param bus The requesting bus device.
+ * @param dinfo The device info instance to be initialized.
+ */
+static int
+bcma_dinfo_init_intrs(device_t bus, device_t child,
+    struct bcma_devinfo *dinfo)
+{
+       uint32_t dmpcfg, oobw;
+
+       /* 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);
+
+       /* Fetch width of the OOB interrupt bank */
+       oobw = bhnd_bus_read_4(dinfo->res_agent,
+            BCMA_DMP_OOB_OUTWIDTH(BCMA_OOB_BANK_INTR));
+       if (oobw > BCMA_OOB_NUM_SEL) {
+               device_printf(bus, "ignoring invalid OOBOUTWIDTH for core %u: "
+                   "%#x\n", BCMA_DINFO_COREIDX(dinfo), oobw);
+               return (0);
+       }
+
+       /* Fetch OOBSEL busline values and populate list of interrupt
+        * descriptors */
+       for (uint32_t sel = 0; sel < oobw; sel++) {
+               struct bcma_intr        *intr;
+               uint32_t                 selout;
+               uint8_t                  line;
+
+               if (dinfo->num_intrs == UINT_MAX)
+                       return (ENOMEM);
+       
+               selout = bhnd_bus_read_4(dinfo->res_agent, BCMA_DMP_OOBSELOUT(
+                   BCMA_OOB_BANK_INTR, sel));
+
+               line = (selout >> BCMA_DMP_OOBSEL_SHIFT(sel)) &
+                   BCMA_DMP_OOBSEL_BUSLINE_MASK;
+
+               intr = bcma_alloc_intr(BCMA_OOB_BANK_INTR, sel, line);
+               if (intr == NULL) {
+                       device_printf(bus, "failed allocating interrupt "
+                           "descriptor %#x for core %u\n", sel,
+                           BCMA_DINFO_COREIDX(dinfo));
+                       return (ENOMEM);
+               }
+
+               STAILQ_INSERT_HEAD(&dinfo->intrs, intr, i_link);
+               dinfo->num_intrs++;
+       }
+
+       return (0);
+}
+
+/**
  * Allocate and return a new empty device info structure.
  * 
  * @param bus The requesting bus device.
@@ -213,6 +337,9 @@ bcma_alloc_dinfo(device_t bus)
        dinfo->res_agent = NULL;
        dinfo->rid_agent = -1;
 
+       STAILQ_INIT(&dinfo->intrs);
+       dinfo->num_intrs = 0;
+
        resource_list_init(&dinfo->resources);
 
        return (dinfo);
@@ -224,7 +351,8 @@ bcma_alloc_dinfo(device_t bus)
  * configuration.
  * 
  * @param bus The requesting bus device.
- * @param dinfo The device info instance.
+ * @param child The bcma child device.
+ * @param dinfo The device info associated with @p child
  * @param corecfg Device core configuration; ownership of this value
  * will be assumed by @p dinfo.
  * 
@@ -232,9 +360,12 @@ bcma_alloc_dinfo(device_t bus)
  * @retval non-zero initialization failed.
  */
 int
-bcma_init_dinfo(device_t bus, struct bcma_devinfo *dinfo,
+bcma_init_dinfo(device_t bus, device_t child, struct bcma_devinfo *dinfo,
     struct bcma_corecfg *corecfg)
 {
+       struct bcma_intr        *intr;
+       int                      error;
+
        KASSERT(dinfo->corecfg == NULL, ("dinfo previously initialized"));
 
        /* Save core configuration value */
@@ -242,71 +373,52 @@ bcma_init_dinfo(device_t bus, struct bcma_devinfo *din
 
        /* The device ports must always be initialized first to ensure that
         * rid 0 maps to the first device port */
-       bcma_dinfo_init_resource_info(bus, dinfo, &corecfg->dev_ports);
+       bcma_dinfo_init_port_resource_info(bus, dinfo, &corecfg->dev_ports);
+       bcma_dinfo_init_port_resource_info(bus, dinfo, &corecfg->bridge_ports);
+       bcma_dinfo_init_port_resource_info(bus, dinfo, &corecfg->wrapper_ports);
 
-       bcma_dinfo_init_resource_info(bus, dinfo, &corecfg->bridge_ports);
-       bcma_dinfo_init_resource_info(bus, dinfo, &corecfg->wrapper_ports);
+       /* Now that we've defined the port resources, we can map the device's
+        * agent registers (if any) */
+       if ((error = bcma_dinfo_init_agent(bus, child, dinfo)))
+               goto failed;
 
-       return (0);
-}
+       /* With agent registers mapped, we can populate the device's interrupt
+        * descriptors */
+       if ((error = bcma_dinfo_init_intrs(bus, child, dinfo)))
+               goto failed;
 
+       /* Finally, map the interrupt descriptors */
+       STAILQ_FOREACH(intr, &dinfo->intrs, i_link) {
+               /* Already mapped? */
+               if (intr->i_mapped)
+                       continue;
 
-/**
- * Allocate the per-core agent register block for a device info structure
- * previous initialized via bcma_init_dinfo().
- * 
- * If an agent0.0 region is not defined on @p dinfo, the device info
- * agent resource is set to NULL and 0 is returned.
- * 
- * @param bus The requesting bus device.
- * @param child The bcma child device.
- * @param dinfo The device info associated with @p child
- * 
- * @retval 0 success
- * @retval non-zero resource allocation failed.
- */
-int
-bcma_dinfo_alloc_agent(device_t bus, device_t child, struct bcma_devinfo 
*dinfo)
-{
-       bhnd_addr_t     addr;
-       bhnd_size_t     size;
-       rman_res_t      r_start, r_count, r_end;
-       int             error;
+               /* Map the interrupt */
+               error = BHND_BUS_MAP_INTR(bus, child, intr->i_sel,
+                   &intr->i_irq);
+               if (error) {
+                       device_printf(bus, "failed mapping interrupt line %u "
+                           "for core %u: %d\n", intr->i_sel,
+                           BCMA_DINFO_COREIDX(dinfo), error);
+                       goto failed;
+               }
 
-       KASSERT(dinfo->res_agent == NULL, ("double allocation of agent"));
+               intr->i_mapped = true;
        
-       /* Verify that the agent register block exists and is
-        * mappable */
-       if (bhnd_get_port_rid(child, BHND_PORT_AGENT, 0, 0) == -1)
-               return (0);     /* nothing to do */
-
-       /* Fetch the address of the agent register block */
-       error = bhnd_get_region_addr(child, BHND_PORT_AGENT, 0, 0,
-           &addr, &size);
-       if (error) {
-               device_printf(bus, "failed fetching agent register block "
-                   "address for core %u\n", BCMA_DINFO_COREIDX(dinfo));
-               return (error);
+               /* Add to resource list */
+               intr->i_rid = resource_list_add_next(&dinfo->resources,
+                   SYS_RES_IRQ, intr->i_irq, intr->i_irq, 1);
        }
 
-       /* Allocate the resource */
-       r_start = addr;
-       r_count = size;
-       r_end = r_start + r_count - 1;
+       return (0);
 
-       dinfo->rid_agent = BCMA_AGENT_RID(dinfo);
-       dinfo->res_agent = BHND_BUS_ALLOC_RESOURCE(bus, bus, SYS_RES_MEMORY,
-           &dinfo->rid_agent, r_start, r_end, r_count, RF_ACTIVE);
-       if (dinfo->res_agent == NULL) {
-               device_printf(bus, "failed allocating agent register block for "
-                   "core %u\n", BCMA_DINFO_COREIDX(dinfo));
-               return (ENXIO);
-       }
+failed:
+       /* Owned by the caller on failure */
+       dinfo->corecfg = NULL;
 
-       return (0);
+       return (error);
 }
 
-
 /**
  * Deallocate the given device info structure and any associated resources.
  * 
@@ -314,8 +426,10 @@ bcma_dinfo_alloc_agent(device_t bus, device_t child, s
  * @param dinfo Device info to be deallocated.
  */
 void
-bcma_free_dinfo(device_t bus, struct bcma_devinfo *dinfo)
+bcma_free_dinfo(device_t bus, device_t child, struct bcma_devinfo *dinfo)
 {
+       struct bcma_intr *intr, *inext;
+
        resource_list_free(&dinfo->resources);
 
        if (dinfo->corecfg != NULL)
@@ -327,9 +441,69 @@ bcma_free_dinfo(device_t bus, struct bcma_devinfo *din
                    dinfo->res_agent);
        }
 
+       /* Clean up interrupt descriptors */
+       STAILQ_FOREACH_SAFE(intr, &dinfo->intrs, i_link, inext) {
+               STAILQ_REMOVE(&dinfo->intrs, intr, bcma_intr, i_link);
+
+               /* Release our IRQ mapping */
+               if (intr->i_mapped) {
+                       BHND_BUS_UNMAP_INTR(bus, child, intr->i_irq);
+                       intr->i_mapped = false;
+               }
+
+               bcma_free_intr(intr);
+       }
+
        free(dinfo, M_BHND);
 }
 
+
+/**
+ * Allocate and initialize a new interrupt descriptor.
+ * 
+ * @param bank OOB bank.
+ * @param sel OOB selector.
+ * @param line OOB bus line.
+ */
+struct bcma_intr *
+bcma_alloc_intr(uint8_t bank, uint8_t sel, uint8_t line)
+{
+       struct bcma_intr *intr;
+
+       if (bank >= BCMA_OOB_NUM_BANKS)
+               return (NULL);
+
+       if (sel >= BCMA_OOB_NUM_SEL)
+               return (NULL);
+
+       if (line >= BCMA_OOB_NUM_BUSLINES)
+               return (NULL);
+
+       intr = malloc(sizeof(*intr), M_BHND, M_NOWAIT);
+       if (intr == NULL)
+               return (NULL);
+
+       intr->i_bank = bank;
+       intr->i_sel = sel;
+       intr->i_busline = line;
+       intr->i_mapped = false;
+       intr->i_irq = 0;
+
+       return (intr);
+}
+
+/**
+ * Deallocate all resources associated with the given interrupt descriptor.
+ * 
+ * @param intr Interrupt descriptor to be deallocated.
+ */
+void
+bcma_free_intr(struct bcma_intr *intr)
+{
+       KASSERT(!intr->i_mapped, ("interrupt %u still mapped", intr->i_sel));
+
+       free(intr, M_BHND);
+}
 
 /**
  * Allocate and initialize new slave port descriptor.

Modified: head/sys/dev/bhnd/bcma/bcmavar.h
==============================================================================
--- head/sys/dev/bhnd/bcma/bcmavar.h    Tue Nov 21 22:06:49 2017        
(r326078)
+++ head/sys/dev/bhnd/bcma/bcmavar.h    Tue Nov 21 23:15:20 2017        
(r326079)
@@ -1,7 +1,11 @@
 /*-
- * Copyright (c) 2015 Landon Fuller <lan...@landonf.org>
+ * Copyright (c) 2015-2016 Landon Fuller <lan...@landonf.org>
+ * Copyright (c) 2017 The FreeBSD Foundation
  * All rights reserved.
  *
+ * Portions of this software were developed by Landon Fuller
+ * under sponsorship from the FreeBSD Foundation.
+ *
  * Redistribution and use in source and binary forms, with or without
  * modification, are permitted provided that the following conditions
  * are met:
@@ -67,6 +71,7 @@ typedef u_int         bcma_rmid_t;
 
 struct bcma_devinfo;
 struct bcma_corecfg;
+struct bcma_intr;
 struct bcma_map;
 struct bcma_mport;
 struct bcma_sport;
@@ -74,8 +79,8 @@ 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                   bcma_get_intr_count(device_t dev, device_t child);
+int                     bcma_get_intr_ivec(device_t dev, device_t child,
                             u_int intr, uint32_t *ivec);
 
 int                     bcma_add_children(device_t bus);
@@ -84,18 +89,20 @@ struct bcma_sport_list      *bcma_corecfg_get_port_list(str
                             bhnd_port_type type);
 
 struct bcma_devinfo    *bcma_alloc_dinfo(device_t bus);
-int                     bcma_init_dinfo(device_t bus,
+int                     bcma_init_dinfo(device_t bus, device_t child,
                             struct bcma_devinfo *dinfo,
                             struct bcma_corecfg *corecfg);
-int                     bcma_dinfo_alloc_agent(device_t bus, device_t child,
+void                    bcma_free_dinfo(device_t bus, device_t child,
                             struct bcma_devinfo *dinfo);
-void                    bcma_free_dinfo(device_t bus,
-                            struct bcma_devinfo *dinfo);
 
 struct bcma_corecfg    *bcma_alloc_corecfg(u_int core_index, int core_unit,
                             uint16_t vendor, uint16_t device, uint8_t hwrev);
 void                    bcma_free_corecfg(struct bcma_corecfg *corecfg);
 
+struct bcma_intr       *bcma_alloc_intr(uint8_t bank, uint8_t sel,
+                            uint8_t line);
+void                    bcma_free_intr(struct bcma_intr *intr);
+
 struct bcma_sport      *bcma_alloc_sport(bcma_pid_t port_num, bhnd_port_type 
port_type);
 void                    bcma_free_sport(struct bcma_sport *sport);
 
@@ -121,6 +128,18 @@ struct bcma_map {
        STAILQ_ENTRY(bcma_map) m_link;
 };
 
+/** BCMA interrupt descriptor */
+struct bcma_intr {
+       uint8_t         i_bank;         /**< OOB bank (see BCMA_OOB_BANK[A-D]) 
*/
+       uint8_t         i_sel;          /**< OOB selector (0-7) */
+       uint8_t         i_busline;      /**< OOB bus line assigned to this 
selector */
+       bool            i_mapped;       /**< if an irq has been mapped for this 
selector */
+       int             i_rid;          /**< bus resource id, or -1 */
+       rman_res_t      i_irq;          /**< the mapped bus irq, if any */
+
+       STAILQ_ENTRY(bcma_intr) i_link;
+};
+
 /** BCMA slave port descriptor */
 struct bcma_sport {
        bcma_pid_t      sp_num;         /**< slave port number (core-unique) */
@@ -131,8 +150,9 @@ struct bcma_sport {
        STAILQ_ENTRY(bcma_sport) sp_link;
 };
 
-STAILQ_HEAD(bcma_mport_list, bcma_mport);
-STAILQ_HEAD(bcma_sport_list, bcma_sport);
+STAILQ_HEAD(bcma_mport_list,   bcma_mport);
+STAILQ_HEAD(bcma_intr_list,    bcma_intr);
+STAILQ_HEAD(bcma_sport_list,   bcma_sport);
 
 /** BCMA IP core/block configuration */
 struct bcma_corecfg {
@@ -161,6 +181,9 @@ struct bcma_devinfo {
        struct bhnd_resource            *res_agent;     /**< Agent (wrapper) 
resource, or NULL. Not
                                                          *  all bcma(4) cores 
have or require an agent. */
        int                              rid_agent;     /**< Agent resource ID, 
or -1 */
+
+       u_int                            num_intrs;     /**< number of 
interrupt descriptors. */
+       struct bcma_intr_list            intrs;         /**< interrupt 
descriptors */
 
        struct bhnd_core_pmu_info       *pmu_info;      /**< Bus-managed PMU 
state, or NULL */
 };

Modified: head/sys/dev/bhnd/bhnd.c
==============================================================================
--- head/sys/dev/bhnd/bhnd.c    Tue Nov 21 22:06:49 2017        (r326078)
+++ head/sys/dev/bhnd/bhnd.c    Tue Nov 21 23:15:20 2017        (r326079)
@@ -814,6 +814,22 @@ bhnd_generic_resume_child(device_t dev, device_t child
        return bus_generic_resume_child(dev, child);
 }
 
+
+/**
+ * Default bhnd(4) bus driver implementation of BUS_SETUP_INTR().
+ *
+ * This implementation of BUS_SETUP_INTR() will delegate interrupt setup
+ * to the parent of @p dev, if any.
+ */
+int
+bhnd_generic_setup_intr(device_t dev, device_t child, struct resource *irq,
+    int flags, driver_filter_t *filter, driver_intr_t *intr, void *arg,
+    void **cookiep)
+{
+       return (bus_generic_setup_intr(dev, child, irq, flags, filter, intr,
+           arg, cookiep));
+}
+
 /*
  * Delegate all indirect I/O to the parent device. When inherited by
  * non-bridged bus implementations, resources will never be marked as
@@ -917,7 +933,7 @@ static device_method_t bhnd_methods[] = {
        DEVMETHOD(bus_activate_resource,        bus_generic_activate_resource),
        DEVMETHOD(bus_deactivate_resource,      
bus_generic_deactivate_resource),
 
-       DEVMETHOD(bus_setup_intr,               bus_generic_setup_intr),
+       DEVMETHOD(bus_setup_intr,               bhnd_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),

Modified: head/sys/dev/bhnd/bhnd.h
==============================================================================
--- head/sys/dev/bhnd/bhnd.h    Tue Nov 21 22:06:49 2017        (r326078)
+++ head/sys/dev/bhnd/bhnd.h    Tue Nov 21 23:15:20 2017        (r326079)
@@ -250,10 +250,10 @@ struct bhnd_device_quirk {
        {{ BHND_MATCH_CORE_REV(_rev) }, (_flags) }
 
 #define        BHND_CHIP_QUIRK(_chip, _rev, _flags)    \
-       {{ BHND_CHIP_IR(BCM ## _chip, _rev) }, (_flags) }
+       {{ BHND_MATCH_CHIP_IR(BCM ## _chip, _rev) }, (_flags) }
 
 #define        BHND_PKG_QUIRK(_chip, _pkg, _flags)     \
-       {{ BHND_CHIP_IP(BCM ## _chip, BCM ## _chip ## _pkg) }, (_flags) }
+       {{ BHND_MATCH_CHIP_IP(BCM ## _chip, BCM ## _chip ## _pkg) }, (_flags) }
 
 #define        BHND_BOARD_QUIRK(_board, _flags)        \
        {{ BHND_MATCH_BOARD_TYPE(_board) },     \
@@ -528,8 +528,8 @@ int                          
bhnd_bus_generic_activate_resource (device_t d
 int                             bhnd_bus_generic_deactivate_resource (device_t 
dev,
                                     device_t child, int type, int rid,
                                     struct bhnd_resource *r);
-bhnd_attach_type                bhnd_bus_generic_get_attach_type(device_t dev,
-                                    device_t child);
+uintptr_t                       bhnd_bus_generic_get_intr_domain(device_t dev,
+                                    device_t child, bool self);
 
 /**
  * Return the bhnd(4) bus driver's device enumeration parser class
@@ -865,25 +865,22 @@ bhnd_read_board_info(device_t dev, struct bhnd_board_i
 }
 
 /**
- * Return the number of interrupts to be assigned to @p child via
- * BHND_BUS_ASSIGN_INTR().
+ * Return the number of interrupt lines assigned to @p dev.
  * 
  * @param dev A bhnd bus child device.
  */
-static inline int
+static inline u_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.
+ * Get the backplane interrupt vector of the @p intr line attached to @p dev.
  * 
  * @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
+ * @param intr The index of the interrupt line being queried.
+ * @param[out] ivec On success, the assigned hardware interrupt vector will be
  * written to this pointer.
  *
  * On bcma(4) devices, this returns the OOB bus line assigned to the
@@ -893,14 +890,48 @@ bhnd_get_intr_count(device_t dev)
  * to the interrupt.
  *
  * @retval 0           success
- * @retval ENXIO       If @p intr exceeds the number of interrupts available
- *                     to @p child.
+ * @retval ENXIO       If @p intr exceeds the number of interrupt lines
+ *                     assigned to @p child.
  */
 static inline int
-bhnd_get_core_ivec(device_t dev, u_int intr, uint32_t *ivec)
+bhnd_get_intr_ivec(device_t dev, u_int intr, u_int *ivec)
 {
-       return (BHND_BUS_GET_CORE_IVEC(device_get_parent(dev), dev, intr,
+       return (BHND_BUS_GET_INTR_IVEC(device_get_parent(dev), dev, intr,
            ivec));
+}
+
+/**
+ * Map the given @p intr to an IRQ number; until unmapped, this IRQ may be used
+ * to allocate a resource of type SYS_RES_IRQ.
+ * 
+ * On success, the caller assumes ownership of the interrupt mapping, and
+ * is responsible for releasing the mapping via bhnd_unmap_intr().
+ * 
+ * @param dev The requesting device.
+ * @param intr The interrupt being mapped.
+ * @param[out] irq On success, the bus interrupt value mapped for @p intr.
+ *
+ * @retval 0           If an interrupt was assigned.
+ * @retval non-zero    If mapping an interrupt otherwise fails, a regular
+ *                     unix error code will be returned.
+ */
+static inline int
+bhnd_map_intr(device_t dev, u_int intr, rman_res_t *irq)
+{
+       return (BHND_BUS_MAP_INTR(device_get_parent(dev), dev, intr, irq));
+}
+
+/**
+ * Unmap an bus interrupt previously mapped via bhnd_map_intr().
+ * 
+ * @param dev The requesting device.
+ * @param intr The interrupt number being unmapped. This is equivalent to the
+ * bus resource ID for the interrupt.
+ */
+static inline void
+bhnd_unmap_intr(device_t dev, rman_res_t irq)
+{
+       return (BHND_BUS_UNMAP_INTR(device_get_parent(dev), dev, irq));
 }
 
 /**

Modified: head/sys/dev/bhnd/bhnd_bus_if.m
==============================================================================
--- head/sys/dev/bhnd/bhnd_bus_if.m     Tue Nov 21 22:06:49 2017        
(r326078)
+++ head/sys/dev/bhnd/bhnd_bus_if.m     Tue Nov 21 23:15:20 2017        
(r326079)
@@ -141,25 +141,6 @@ 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)
        {
@@ -243,7 +224,40 @@ CODE {
                panic("bhnd_bus_get_probe_order unimplemented");
        }
 
+       static uintptr_t
+       bhnd_bus_null_get_intr_domain(device_t dev, device_t child, bool self)
+       {
+               /* Unsupported */
+               return (0);
+       }
+
+       static u_int
+       bhnd_bus_null_get_intr_count(device_t dev, device_t child)
+       {
+               return (0);
+       }
+
        static int
+       bhnd_bus_null_get_intr_ivec(device_t dev, device_t child, u_int intr,
+           u_int *ivec)
+       {
+               panic("bhnd_bus_get_intr_ivec unimplemented");
+       }
+       
+       static int
+       bhnd_bus_null_map_intr(device_t dev, device_t child, u_int intr,
+           rman_res_t *irq)
+       {
+           panic("bhnd_bus_map_intr unimplemented");
+       }
+
+       static int
+       bhnd_bus_null_unmap_intr(device_t dev, device_t child, rman_res_t irq)
+       {
+           panic("bhnd_bus_unmap_intr unimplemented");
+       }
+
+       static int
        bhnd_bus_null_get_port_rid(device_t dev, device_t child,
            bhnd_port_type port_type, u_int port, u_int region)
        {
@@ -488,77 +502,6 @@ METHOD int read_board_info {
 } DEFAULT bhnd_bus_null_read_board_info;
 
 /**
- * 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.
  *
  * This method must be called by concrete bhnd(4) driver impementations
@@ -996,6 +939,106 @@ METHOD int deactivate_resource {
        int rid;
         struct bhnd_resource *r;
 } DEFAULT bhnd_bus_generic_deactivate_resource;
+
+/**
+ * Return the interrupt domain.
+ *
+ * This globally unique value may be used as the interrupt controller 'xref'
+ * on targets that support INTRNG.
+ *
+ * @param dev The device whose child is being examined.
+ * @param child The child device.
+ * @parem self If true, return @p child's interrupt domain, rather than the
+ * domain in which @p child resides.
+ *
+ * On Non-OFW targets, this should either return:
+ *   - The pointer address of a device that can uniquely identify @p child's
+ *     interrupt domain (e.g., the bhnd bus' device_t address), or
+ *   - 0 if unsupported by the bus.
+ *
+ * On OFW (including FDT) targets, this should return the @p child's iparent
+ * property's xref if @p self is false, the child's own node xref value if
+ * @p self is true, or 0 if no interrupt parent is found.
+ */
+METHOD uintptr_t get_intr_domain {
+       device_t dev;
+       device_t child;
+       bool self;
+} DEFAULT bhnd_bus_null_get_intr_domain;
+ 
+/**
+ * Return the number of interrupt lines assigned to @p child.
+ * 
+ * @param dev The bhnd device whose child is being examined.
+ * @param child The child device.
+ */
+METHOD u_int get_intr_count {
+       device_t dev;
+       device_t child;
+} DEFAULT bhnd_bus_null_get_intr_count;
+
+/**
+ * Get the backplane interrupt vector of the @p intr line attached to @p child.
+ * 
+ * @param dev The device whose child is being examined.
+ * @param child The child device.
+ * @param intr The index of the interrupt line being queried.
+ * @param[out] ivec On success, the assigned hardware interrupt vector will 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 interrupt lines
+ *                     assigned to @p child.
+ */
+METHOD int get_intr_ivec {
+       device_t dev;
+       device_t child;
+       u_int intr;
+       u_int *ivec;
+} DEFAULT bhnd_bus_null_get_intr_ivec;
+
+/**
+ * Map the given @p intr to an IRQ number; until unmapped, this IRQ may be used
+ * to allocate a resource of type SYS_RES_IRQ.
+ * 
+ * On success, the caller assumes ownership of the interrupt mapping, and

*** 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