svn commit: r326079 - in head/sys: dev/bhnd dev/bhnd/bcma dev/bhnd/bhndb dev/bhnd/cores/chipc dev/bhnd/cores/pci dev/bhnd/cores/usb dev/bhnd/siba mips/broadcom mips/include mips/mips
Landon J. Fuller
landonf at FreeBSD.org
Tue Nov 21 23:15:22 UTC 2017
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 <landon at landonf.org>
+ * Copyright (c) 2015-2016 Landon Fuller <landon at 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 <landon at landonf.org>
+ * Copyright (c) 2015-2016 Landon Fuller <landon at 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 <landon at landonf.org>
+ * Copyright (c) 2015-2016 Landon Fuller <landon at 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 ***
More information about the svn-src-all
mailing list