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