svn commit: r329180 - head/sys/dev/bhnd/siba

Landon J. Fuller landonf at FreeBSD.org
Mon Feb 12 19:36:28 UTC 2018


Author: landonf
Date: Mon Feb 12 19:36:26 2018
New Revision: 329180
URL: https://svnweb.freebsd.org/changeset/base/329180

Log:
  siba(4): Ignore disabled per-core address match entries.
  
  Previously, the address regions described by disabled admatch entries would
  be treated as being mapped to the given core; while incorrect, this was
  essentially harmless given that the entries describe unused address space
  on the few affected devices.
  
  We now perform parsing of per-core admatch registers and interrupt flags in
  siba_erom, correctly skip any disabled admatch entries, and use the
  siba_erom API in siba_add_children() to perform enumeration of attached
  cores.

Added:
  head/sys/dev/bhnd/siba/siba_eromvar.h   (contents, props changed)
Modified:
  head/sys/dev/bhnd/siba/siba.c
  head/sys/dev/bhnd/siba/siba_erom.c
  head/sys/dev/bhnd/siba/siba_subr.c
  head/sys/dev/bhnd/siba/sibavar.h

Modified: head/sys/dev/bhnd/siba/siba.c
==============================================================================
--- head/sys/dev/bhnd/siba/siba.c	Mon Feb 12 19:08:17 2018	(r329179)
+++ head/sys/dev/bhnd/siba/siba.c	Mon Feb 12 19:36:26 2018	(r329180)
@@ -47,9 +47,14 @@ __FBSDID("$FreeBSD$");
 #include <dev/bhnd/cores/chipc/chipc.h>
 #include <dev/bhnd/cores/chipc/pwrctl/bhnd_pwrctl.h>
 
+#include "siba_eromvar.h"
+
 #include "sibareg.h"
 #include "sibavar.h"
 
+/* RID used when allocating EROM resources */
+#define	SIBA_EROM_RID	0
+
 static bhnd_erom_class_t *
 siba_get_erom_class(driver_t *driver)
 {
@@ -1057,7 +1062,7 @@ siba_decode_port_rid(device_t dev, device_t child, int
 		return (EINVAL);
 
 	/* Look for a matching addrspace entry */
-	for (u_int i = 0; i < dinfo->core_id.num_addrspace; i++) {
+	for (u_int i = 0; i < dinfo->core_id.num_admatch; i++) {
 		if (dinfo->addrspace[i].sa_rid != rid)
 			continue;
 
@@ -1131,7 +1136,7 @@ siba_get_intr_count(device_t dev, device_t child)
 		return (BHND_BUS_GET_INTR_COUNT(device_get_parent(dev), child));
 
 	dinfo = device_get_ivars(child);
-	if (!dinfo->intr_en) {
+	if (!dinfo->core_id.intr_en) {
 		/* No interrupts */
 		return (0);
 	} else {
@@ -1161,121 +1166,14 @@ siba_get_intr_ivec(device_t dev, device_t child, u_int
 
 	dinfo = device_get_ivars(child);
 
-	KASSERT(dinfo->intr_en, ("core does not have an interrupt assigned"));
-	*ivec = dinfo->intr.flag;
-	return (0);
-}
+	KASSERT(dinfo->core_id.intr_en,
+	    ("core does not have an interrupt assigned"));
 
-/**
- * Register all address space mappings for @p di.
- *
- * @param dev The siba bus device.
- * @param di The device info instance on which to register all address
- * space entries.
- * @param r A resource mapping the enumeration table block for @p di.
- */
-static int
-siba_register_addrspaces(device_t dev, struct siba_devinfo *di,
-    struct bhnd_resource *r)
-{
-	struct siba_core_id	*cid;
-	uint32_t		 addr;
-	uint32_t		 size;
-	int			 error;
-
-	cid = &di->core_id;
-
-
-	/* Register the device address space entries */
-	for (uint8_t i = 0; i < di->core_id.num_addrspace; i++) {
-		uint32_t	adm;
-		u_int		adm_offset;
-		uint32_t	bus_reserved;
-
-		/* Determine the register offset */
-		adm_offset = siba_admatch_offset(i);
-		if (adm_offset == 0) {
-		    device_printf(dev, "addrspace %hhu is unsupported", i);
-		    return (ENODEV);
-		}
-
-		/* Fetch the address match register value */
-		adm = bhnd_bus_read_4(r, adm_offset);
-
-		/* Parse the value */
-		if ((error = siba_parse_admatch(adm, &addr, &size))) {
-			device_printf(dev, "failed to decode address "
-			    " match register value 0x%x\n", adm);
-			return (error);
-		}
-
-		/* If this is the device's core/enumeration addrespace,
-		 * reserve the Sonics configuration register blocks for the
-		 * use of our bus. */
-		bus_reserved = 0;
-		if (i == SIBA_CORE_ADDRSPACE)
-			bus_reserved = cid->num_cfg_blocks * SIBA_CFG_SIZE;
-
-		/* Append the region info */
-		error = siba_append_dinfo_region(di, i, addr, size,
-		    bus_reserved);
-		if (error)
-			return (error);
-	}
-
+	*ivec = dinfo->core_id.intr_flag;
 	return (0);
 }
 
-
 /**
- * Register all interrupt descriptors for @p dinfo. Must be called after
- * configuration blocks have been mapped.
- *
- * @param dev The siba bus device.
- * @param child The siba child device.
- * @param dinfo The device info instance on which to register all interrupt
- * descriptor entries.
- * @param r A resource mapping the enumeration table block for @p di.
- */
-static int
-siba_register_interrupts(device_t dev, device_t child,
-    struct siba_devinfo *dinfo, struct bhnd_resource *r)
-{
-	uint32_t	tpsflag;
-	int		error;
-
-	/* Is backplane interrupt distribution enabled for this core? */
-	tpsflag = bhnd_bus_read_4(r, SB0_REG_ABS(SIBA_CFG0_TPSFLAG));
-	if ((tpsflag & SIBA_TPS_F0EN0) == 0) {
-		dinfo->intr_en = false;
-		return (0);
-	}
-
-	/* Have one interrupt */
-	dinfo->intr_en = true;
-	dinfo->intr.flag = SIBA_REG_GET(tpsflag, TPS_NUM0);
-	dinfo->intr.mapped = false;
-	dinfo->intr.irq = 0;
-	dinfo->intr.rid = -1;
-
-	/* Map the interrupt */
-	error = BHND_BUS_MAP_INTR(dev, child, 0 /* single intr is always 0 */,
-	    &dinfo->intr.irq);
-	if (error) {
-		device_printf(dev, "failed mapping interrupt line for core %u: "
-		    "%d\n", dinfo->core_id.core_info.core_idx, error);
-		return (error);
-	}
-	dinfo->intr.mapped = true;
-
-	/* Update the resource list */
-	dinfo->intr.rid = resource_list_add_next(&dinfo->resources, SYS_RES_IRQ,
-	    dinfo->intr.irq, dinfo->intr.irq, 1);
-
-	return (0);
-}
-
-/**
  * Map per-core configuration blocks for @p dinfo.
  *
  * @param dev The siba bus device.
@@ -1386,21 +1284,27 @@ siba_child_deleted(device_t dev, device_t child)
 int
 siba_add_children(device_t dev)
 {
-	const struct bhnd_chipid	*chipid;
+	bhnd_erom_t			*erom;
+	struct siba_erom		*siba_erom;
+	struct bhnd_erom_io		*eio;
+	const struct bhnd_chipid	*cid;
 	struct siba_core_id		*cores;
-	struct bhnd_resource		*r;
 	device_t			*children;
-	int				 rid;
 	int				 error;
 
-	cores = NULL;
-	r = NULL;
+	cid = BHND_BUS_GET_CHIPID(dev, dev);
 
-	chipid = BHND_BUS_GET_CHIPID(dev, dev);
+	/* Allocate our EROM parser */
+	eio = bhnd_erom_iores_new(dev, SIBA_EROM_RID);
+	erom = bhnd_erom_alloc(&siba_erom_parser, cid, eio);
+	if (erom == NULL) {
+		bhnd_erom_io_fini(eio);
+		return (ENODEV);
+	}
 
 	/* Allocate our temporary core and device table */
-	cores = malloc(sizeof(*cores) * chipid->ncores, M_BHND, M_WAITOK);
-	children = malloc(sizeof(*children) * chipid->ncores, M_BHND,
+	cores = malloc(sizeof(*cores) * cid->ncores, M_BHND, M_WAITOK);
+	children = malloc(sizeof(*children) * cid->ncores, M_BHND,
 	    M_WAITOK | M_ZERO);
 
 	/*
@@ -1411,40 +1315,14 @@ siba_add_children(device_t dev)
 	 * defer mapping of the per-core siba(4) config blocks until all cores
 	 * have been enumerated and otherwise configured.
 	 */
-	for (u_int i = 0; i < chipid->ncores; i++) {
+	siba_erom = (struct siba_erom *)erom;
+	for (u_int i = 0; i < cid->ncores; i++) {
 		struct siba_devinfo	*dinfo;
 		device_t		 child;
-		uint32_t		 idhigh, idlow;
-		rman_res_t		 r_count, r_end, r_start;
 
-		/* Map the core's register block */
-		rid = 0;
-		r_start = SIBA_CORE_ADDR(i);
-		r_count = SIBA_CORE_SIZE;
-		r_end = r_start + SIBA_CORE_SIZE - 1;
-		r = bhnd_alloc_resource(dev, SYS_RES_MEMORY, &rid, r_start,
-		    r_end, r_count, RF_ACTIVE);
-		if (r == NULL) {
-			error = ENXIO;
+		if ((error = siba_erom_get_core_id(siba_erom, i, &cores[i])))
 			goto failed;
-		}
 
-		/* Read the core info */
-		idhigh = bhnd_bus_read_4(r, SB0_REG_ABS(SIBA_CFG0_IDHIGH));
-		idlow = bhnd_bus_read_4(r, SB0_REG_ABS(SIBA_CFG0_IDLOW));
-
-		cores[i] = siba_parse_core_id(idhigh, idlow, i, 0);
-
-		/* Determine and set unit number */
-		for (u_int j = 0; j < i; j++) {
-			struct bhnd_core_info *cur = &cores[i].core_info;
-			struct bhnd_core_info *prev = &cores[j].core_info;
-
-			if (prev->vendor == cur->vendor &&
-			    prev->device == cur->device)
-				cur->unit++;
-		}
-
 		/* Add the child device */
 		child = BUS_ADD_CHILD(dev, 0, NULL, -1);
 		if (child == NULL) {
@@ -1460,30 +1338,22 @@ siba_add_children(device_t dev)
 			goto failed;
 		}
 
-		if ((error = siba_init_dinfo(dev, dinfo, &cores[i])))
+		if ((error = siba_init_dinfo(dev, child, dinfo, &cores[i])))
 			goto failed;
 
-		/* Register the core's address space(s). */
-		if ((error = siba_register_addrspaces(dev, dinfo, r)))
-			goto failed;
-
-		/* Register the core's interrupts */
-		if ((error = siba_register_interrupts(dev, child, dinfo, r)))
-			goto failed;
-
-		/* Unmap the core's register block */
-		bhnd_release_resource(dev, SYS_RES_MEMORY, rid, r);
-		r = NULL;
-
 		/* If pins are floating or the hardware is otherwise
 		 * unpopulated, the device shouldn't be used. */
 		if (bhnd_is_hw_disabled(child))
 			device_disable(child);
 	}
 
+	/* Free EROM (and any bridge register windows it might hold) */
+	bhnd_erom_free(erom);
+	erom = NULL;
+
 	/* Map all valid core's config register blocks and perform interrupt
 	 * assignment */
-	for (u_int i = 0; i < chipid->ncores; i++) {
+	for (u_int i = 0; i < cid->ncores; i++) {
 		struct siba_devinfo	*dinfo;
 		device_t		 child;
 
@@ -1509,7 +1379,7 @@ siba_add_children(device_t dev)
 	return (0);
 
 failed:
-	for (u_int i = 0; i < chipid->ncores; i++) {
+	for (u_int i = 0; i < cid->ncores; i++) {
 		if (children[i] == NULL)
 			continue;
 
@@ -1518,9 +1388,8 @@ failed:
 
 	free(cores, M_BHND);
 	free(children, M_BHND);
-
-	if (r != NULL)
-		bhnd_release_resource(dev, SYS_RES_MEMORY, rid, r);
+	if (erom != NULL)
+		bhnd_erom_free(erom);
 
 	return (error);
 }

Modified: head/sys/dev/bhnd/siba/siba_erom.c
==============================================================================
--- head/sys/dev/bhnd/siba/siba_erom.c	Mon Feb 12 19:08:17 2018	(r329179)
+++ head/sys/dev/bhnd/siba/siba_erom.c	Mon Feb 12 19:36:26 2018	(r329180)
@@ -49,6 +49,8 @@ __FBSDID("$FreeBSD$");
 #include "sibareg.h"
 #include "sibavar.h"
 
+#include "siba_eromvar.h"
+
 struct siba_erom;
 struct siba_erom_io;
 
@@ -59,8 +61,9 @@ static int			siba_eio_init(struct siba_erom_io *io,
 static uint32_t			siba_eio_read_4(struct siba_erom_io *io,
 				    u_int core_idx, bus_size_t offset);
 
-static struct siba_core_id	siba_eio_read_core_id(struct siba_erom_io *io,
-				    u_int core_idx, int unit);
+static int			siba_eio_read_core_id(struct siba_erom_io *io,
+				    u_int core_idx, int unit,
+				    struct siba_core_id *sid);
 
 static int			siba_eio_read_chipid(struct siba_erom_io *io,
 				    bus_addr_t enum_addr,
@@ -118,7 +121,8 @@ siba_erom_probe(bhnd_erom_class_t *cls, struct bhnd_er
 		 * BCM4710, it's a SDRAM core (0x803).
 		 */
 
-		sid = siba_eio_read_core_id(&io, 0, 0);
+		if ((error = siba_eio_read_core_id(&io, 0, 0, &sid)))
+			return (error);
 
 		if (sid.core_info.vendor != BHND_MFGID_BCM)
 			return (ENXIO);
@@ -227,19 +231,154 @@ siba_eio_read_4(struct siba_erom_io *io, u_int core_id
  * @param core_idx The core index.
  * @param unit The caller-specified unit number to be included in the return
  * value.
+ * @param[out] sid On success, the parsed siba core id.
+ * 
+ * @retval 0		success
+ * @retval non-zero     if reading or parsing the identification registers
+ *			otherwise fails, a regular unix error code will be
+ *			returned.
  */
-static struct siba_core_id
-siba_eio_read_core_id(struct siba_erom_io *io, u_int core_idx, int unit)
+static int
+siba_eio_read_core_id(struct siba_erom_io *io, u_int core_idx, int unit,
+    struct siba_core_id *sid)
 {
-	uint32_t idhigh, idlow;
+	struct siba_admatch	admatch[SIBA_MAX_ADDRSPACE];
+	uint32_t		idhigh, idlow;
+	uint32_t		tpsflag;
+	uint16_t		ocp_vendor;
+	uint8_t			sonics_rev;
+	uint8_t			num_admatch;
+	uint8_t			num_admatch_en;
+	uint8_t			num_cfg;
+	bool			intr_en;
+	u_int			intr_flag;
+	int			error;
 
 	idhigh = siba_eio_read_4(io, core_idx, SB0_REG_ABS(SIBA_CFG0_IDHIGH));
 	idlow = siba_eio_read_4(io, core_idx, SB0_REG_ABS(SIBA_CFG0_IDLOW));
+	tpsflag = siba_eio_read_4(io, core_idx, SB0_REG_ABS(SIBA_CFG0_TPSFLAG));
 
-	return (siba_parse_core_id(idhigh, idlow, core_idx, unit));
+	ocp_vendor = SIBA_REG_GET(idhigh, IDH_VENDOR);
+	sonics_rev = SIBA_REG_GET(idlow, IDL_SBREV);
+	num_admatch = SIBA_REG_GET(idlow, IDL_NRADDR) + 1 /* + enum block */;
+	if (num_admatch > nitems(admatch)) {
+		printf("core%u: invalid admatch count %hhu\n", core_idx,
+		    num_admatch);
+		return (EINVAL);
+	}
+
+	/* Determine backplane interrupt distribution configuration */
+	intr_en = ((tpsflag & SIBA_TPS_F0EN0) != 0);
+	intr_flag = SIBA_REG_GET(tpsflag, TPS_NUM0);
+
+	/* Determine the number of sonics config register blocks */
+	num_cfg = SIBA_CFG_NUM_2_2;
+	if (sonics_rev >= SIBA_IDL_SBREV_2_3)
+		num_cfg = SIBA_CFG_NUM_2_3;
+
+	/* Parse all admatch descriptors */
+	num_admatch_en = 0;
+	for (uint8_t i = 0; i < num_admatch; i++) {
+		uint32_t	am_value;
+		u_int		am_offset;
+
+		KASSERT(i < nitems(admatch), ("invalid admatch index"));
+
+		/* Determine the register offset */
+		am_offset = siba_admatch_offset(i);
+		if (am_offset == 0) {
+			printf("core%u: addrspace %hhu is unsupported",
+			    core_idx, i);
+			return (ENODEV);
+		}
+
+		/* Read and parse the address match register */
+		am_value = siba_eio_read_4(io, core_idx, am_offset);
+		error = siba_parse_admatch(am_value, &admatch[num_admatch_en]);
+		if (error) {
+			printf("core%u: failed to decode admatch[%hhu] "
+			    "register value 0x%x\n", core_idx, i, am_value);
+			return (error);
+		}
+
+		/* Skip disabled entries */
+		if (!admatch[num_admatch_en].am_enabled)
+			continue;
+
+		/* Reject unsupported negative matches. These are not used on
+		 * any known devices */
+		if (admatch[num_admatch_en].am_negative) {
+			printf("core%u: unsupported negative admatch[%hhu] "
+			    "value 0x%x\n", core_idx, i, am_value);
+			return (ENXIO);
+		}
+
+		num_admatch_en++;
+	}
+
+	/* Populate the result */
+	*sid = (struct siba_core_id) {
+		.core_info	= {
+			.vendor	= siba_get_bhnd_mfgid(ocp_vendor),
+			.device	= SIBA_REG_GET(idhigh, IDH_DEVICE),
+			.hwrev	= SIBA_IDH_CORE_REV(idhigh),
+			.core_idx = core_idx,
+			.unit	= unit
+		},
+		.sonics_vendor	= ocp_vendor,
+		.sonics_rev	= sonics_rev,
+		.intr_en	= intr_en,
+		.intr_flag	= intr_flag,
+		.num_admatch	= num_admatch_en,
+		.num_cfg_blocks	= num_cfg
+	};
+	memcpy(sid->admatch, admatch, num_admatch_en * sizeof(admatch[0]));
+
+	return (0);
 }
 
 /**
+ * Read and parse the SSB identification registers for the given @p core_index,
+ * returning the siba(4) core identification in @p sid.
+ * 
+ * @param sc A siba EROM instance.
+ * @param core_idx The index of the core to be identified.
+ * @param[out] result On success, the parsed siba core id.
+ * 
+ * @retval 0		success
+ * @retval non-zero     if reading or parsing the identification registers
+ *			otherwise fails, a regular unix error code will be
+ *			returned.
+ */
+int
+siba_erom_get_core_id(struct siba_erom *sc, u_int core_idx,
+    struct siba_core_id *result)
+{
+	struct siba_core_id	sid;
+	int			error;
+
+	/* Fetch the core info, assuming a unit number of 0 */
+	if ((error = siba_eio_read_core_id(&sc->io, core_idx, 0, &sid)))
+		return (error);
+
+	/* Scan preceding cores to determine the real unit number. */
+	for (u_int i = 0; i < core_idx; i++) {
+		struct siba_core_id prev;
+
+		if ((error = siba_eio_read_core_id(&sc->io, i, 0, &prev)))
+			return (error);
+
+		/* Bump the unit number? */
+		if (sid.core_info.vendor == prev.core_info.vendor &&
+		    sid.core_info.device == prev.core_info.device)
+			sid.core_info.unit++;
+	}
+
+	*result = sid;
+	return (0);
+}
+
+/**
  * Read and parse the chip identification register from the ChipCommon core.
  * 
  * @param io EROM I/O context.
@@ -252,9 +391,12 @@ siba_eio_read_chipid(struct siba_erom_io *io, bus_addr
 {
 	struct siba_core_id	ccid;
 	uint32_t		idreg;
+	int			error;
 
 	/* Identify the chipcommon core */
-	ccid = siba_eio_read_core_id(io, 0, 0);
+	if ((error = siba_eio_read_core_id(io, 0, 0, &ccid)))
+		return (error);
+
 	if (ccid.core_info.vendor != BHND_MFGID_BCM ||
 	    ccid.core_info.device != BHND_COREID_CC)
 	{
@@ -281,6 +423,7 @@ siba_erom_lookup_core(bhnd_erom_t *erom, const struct 
 {
 	struct siba_erom	*sc;
 	struct bhnd_core_match	 imatch;
+	int			 error;
 
 	sc = (struct siba_erom *)erom;
 
@@ -294,7 +437,9 @@ siba_erom_lookup_core(bhnd_erom_t *erom, const struct 
 		struct bhnd_core_info	ci;
 
 		/* Read the core info */
-		sid = siba_eio_read_core_id(&sc->io, i, 0);
+		if ((error = siba_eio_read_core_id(&sc->io, i, 0, &sid)))
+			return (error);
+
 		ci = sid.core_info;
 
 		/* Check for initial match */
@@ -303,7 +448,9 @@ siba_erom_lookup_core(bhnd_erom_t *erom, const struct 
 
 		/* Re-scan preceding cores to determine the unit number. */
 		for (u_int j = 0; j < i; j++) {
-			sid = siba_eio_read_core_id(&sc->io, j, 0);
+			error = siba_eio_read_core_id(&sc->io, j, 0, &sid);
+			if (error)
+				return (error);
 
 			/* Bump the unit number? */
 			if (sid.core_info.vendor == ci.vendor &&
@@ -332,7 +479,8 @@ siba_erom_lookup_core_addr(bhnd_erom_t *erom, const st
 	struct siba_erom	*sc;
 	struct bhnd_core_info	 core;
 	struct siba_core_id	 sid;
-	uint32_t		 am, am_addr, am_size;
+	struct siba_admatch	 admatch;
+	uint32_t		 am;
 	u_int			 am_offset;
 	u_int			 addrspace, cfg;
 	
@@ -345,7 +493,9 @@ siba_erom_lookup_core_addr(bhnd_erom_t *erom, const st
 		return (error);
 
 	/* Fetch full siba core ident */
-	sid = siba_eio_read_core_id(&sc->io, core.core_idx, core.unit);
+	error = siba_eio_read_core_id(&sc->io, core.core_idx, core.unit, &sid);
+	if (error)
+		return (error);
 
 	/* Is port valid? */
 	if (!siba_is_port_valid(&sid, type, port))
@@ -419,7 +569,7 @@ siba_erom_lookup_core_addr(bhnd_erom_t *erom, const st
 	/* Read and parse the address match register */
 	am = siba_eio_read_4(&sc->io, core.core_idx, am_offset);
 
-	if ((error = siba_parse_admatch(am, &am_addr, &am_size))) {
+	if ((error = siba_parse_admatch(am, &admatch))) {
 		printf("failed to decode address match register value 0x%x\n",
 		    am);
 		return (error);
@@ -428,8 +578,8 @@ siba_erom_lookup_core_addr(bhnd_erom_t *erom, const st
 	if (info != NULL)
 		*info = core;
 
-	*addr = am_addr;
-	*size = am_size;
+	*addr = admatch.am_base;
+	*size = admatch.am_size;
 
 	return (0);
 }
@@ -441,6 +591,7 @@ siba_erom_get_core_table(bhnd_erom_t *erom, struct bhn
 {
 	struct siba_erom	*sc;
 	struct bhnd_core_info	*out;
+	int			 error;
 
 	sc = (struct siba_erom *)erom;
 
@@ -457,7 +608,9 @@ siba_erom_get_core_table(bhnd_erom_t *erom, struct bhn
 		struct siba_core_id sid;
 
 		/* Read the core info */
-		sid = siba_eio_read_core_id(&sc->io, i, 0);
+		if ((error = siba_eio_read_core_id(&sc->io, i, 0, &sid)))
+			return (error);
+
 		out[i] = sid.core_info;
 
 		/* Determine unit number */
@@ -508,8 +661,9 @@ siba_erom_dump(bhnd_erom_t *erom)
 		printf("\tnraddr\t0x%04x\n", nraddr);
 
 		for (size_t addrspace = 0; addrspace < nraddr; addrspace++) {
-			uint32_t	am, am_addr, am_size;
-			u_int		am_offset;
+			struct siba_admatch	admatch;
+			uint32_t		am;
+			u_int			am_offset;
 
 			/* Determine the register offset */
 			am_offset = siba_admatch_offset(addrspace);
@@ -521,16 +675,15 @@ siba_erom_dump(bhnd_erom_t *erom)
 			
 			/* Read and parse the address match register */
 			am = siba_eio_read_4(&sc->io, i, am_offset);
-			error = siba_parse_admatch(am, &am_addr, &am_size);
-			if (error) {
+			if ((error = siba_parse_admatch(am, &admatch))) {
 				printf("failed to decode address match "
 				    "register value 0x%x\n", am);
 				continue;
 			}
 
 			printf("\taddrspace %zu\n", addrspace);
-			printf("\t\taddr: 0x%08x\n", am_addr);
-			printf("\t\tsize: 0x%08x\n", am_size);
+			printf("\t\taddr: 0x%08x\n", admatch.am_base);
+			printf("\t\tsize: 0x%08x\n", admatch.am_size);
 		}
 	}
 

Added: head/sys/dev/bhnd/siba/siba_eromvar.h
==============================================================================
--- /dev/null	00:00:00 1970	(empty, because file is newly added)
+++ head/sys/dev/bhnd/siba/siba_eromvar.h	Mon Feb 12 19:36:26 2018	(r329180)
@@ -0,0 +1,46 @@
+/*-
+ * SPDX-License-Identifier: BSD-2-Clause-FreeBSD
+ *
+ * Copyright (c) 2018 Landon Fuller <landonf at FreeBSD.org>
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ * 
+ * $FreeBSD$
+ */
+
+#ifndef	_SIBA_SIBA_EROMVAR_H_
+#define	_SIBA_SIBA_EROMVAR_H_
+
+#include <dev/bhnd/bhnd.h>
+#include <dev/bhnd/bhnd_erom.h>
+
+#include "sibavar.h"
+
+struct siba_erom;
+
+#define	SIBA_EROM_
+
+int	siba_erom_get_core_id(struct siba_erom *sc, u_int core_idx,
+	    struct siba_core_id *result);
+
+#endif /* _SIBA_SIBA_EROMVAR_H_ */

Modified: head/sys/dev/bhnd/siba/siba_subr.c
==============================================================================
--- head/sys/dev/bhnd/siba/siba_subr.c	Mon Feb 12 19:08:17 2018	(r329179)
+++ head/sys/dev/bhnd/siba/siba_subr.c	Mon Feb 12 19:36:26 2018	(r329180)
@@ -48,6 +48,12 @@ __FBSDID("$FreeBSD$");
 #include "sibareg.h"
 #include "sibavar.h"
 
+static int	siba_register_interrupts(device_t dev, device_t child,
+		    struct siba_devinfo *dinfo);
+static int	siba_append_dinfo_region(struct siba_devinfo *dinfo,
+		     uint8_t addridx, uint32_t base, uint32_t size,
+		     uint32_t bus_reserved);
+
 /**
  * Map a siba(4) OCP vendor code to its corresponding JEDEC JEP-106 vendor
  * code.
@@ -68,48 +74,6 @@ siba_get_bhnd_mfgid(uint16_t ocp_vendor)
 }
 
 /**
- * Parse the SIBA_IDH_* fields from the per-core identification
- * registers, returning a siba_core_id representation.
- * 
- * @param idhigh The SIBA_R0_IDHIGH register.
- * @param idlow The SIBA_R0_IDLOW register. 
- * @param core_id The core id (index) to include in the result.
- * @param unit The unit number to include in the result.
- */
-struct siba_core_id	 
-siba_parse_core_id(uint32_t idhigh, uint32_t idlow, u_int core_idx, int unit)
-{
-
-	uint16_t	ocp_vendor;
-	uint8_t		sonics_rev;
-	uint8_t		num_addrspace;
-	uint8_t		num_cfg;
-
-	ocp_vendor = SIBA_REG_GET(idhigh, IDH_VENDOR);
-	sonics_rev = SIBA_REG_GET(idlow, IDL_SBREV);
-	num_addrspace = SIBA_REG_GET(idlow, IDL_NRADDR) + 1 /* + enum block */;
-
-	/* Determine the number of sonics config register blocks */
-	num_cfg = SIBA_CFG_NUM_2_2;
-	if (sonics_rev >= SIBA_IDL_SBREV_2_3)
-		num_cfg = SIBA_CFG_NUM_2_3;
-
-	return (struct siba_core_id) {
-		.core_info	= {
-			.vendor	= siba_get_bhnd_mfgid(ocp_vendor),
-			.device	= SIBA_REG_GET(idhigh, IDH_DEVICE),
-			.hwrev	= SIBA_IDH_CORE_REV(idhigh),
-			.core_idx = core_idx,
-			.unit	= unit
-		},
-		.sonics_vendor	= ocp_vendor,
-		.sonics_rev	= sonics_rev,
-		.num_addrspace	= num_addrspace,
-		.num_cfg_blocks	= num_cfg
-	};	
-}
-
-/**
  * Allocate and return a new empty device info structure.
  * 
  * @param bus The requesting bus device.
@@ -138,8 +102,12 @@ siba_alloc_dinfo(device_t bus)
 	resource_list_init(&dinfo->resources);
 
 	dinfo->pmu_state = SIBA_PMU_NONE;
-	dinfo->intr_en = false;
 
+	dinfo->intr = (struct siba_intr) {
+		.mapped = false,
+		.rid = -1
+	};
+
 	return dinfo;
 }
 
@@ -148,6 +116,7 @@ siba_alloc_dinfo(device_t bus)
  * siba_alloc_dinfo, copying the provided core id.
  * 
  * @param dev The requesting bus device.
+ * @param child The siba child device.
  * @param dinfo The device info instance.
  * @param core Device core info.
  * 
@@ -155,14 +124,81 @@ siba_alloc_dinfo(device_t bus)
  * @retval non-zero initialization failed.
  */
 int
-siba_init_dinfo(device_t dev, struct siba_devinfo *dinfo,
+siba_init_dinfo(device_t dev, device_t child, struct siba_devinfo *dinfo,
     const struct siba_core_id *core_id)
 {
+	int error;
+
 	dinfo->core_id = *core_id;
+
+	/* Register all address space mappings */
+	for (uint8_t i = 0; i < core_id->num_admatch; i++) {
+		uint32_t bus_reserved;
+
+		/* If this is the device's core/enumeration addrespace,
+		 * reserve the Sonics configuration register blocks for the
+		 * use of our bus. */
+		bus_reserved = 0;
+		if (i == SIBA_CORE_ADDRSPACE)
+			bus_reserved = core_id->num_cfg_blocks * SIBA_CFG_SIZE;
+
+		/* Append the region info */
+		error = siba_append_dinfo_region(dinfo, i,
+		    core_id->admatch[i].am_base, core_id->admatch[i].am_size,
+		    bus_reserved);
+		if (error)
+			return (error);
+	}
+
+	/* Register all interrupt(s) */
+	if ((error = siba_register_interrupts(dev, child, dinfo)))
+		return (error);
+
 	return (0);
 }
 
+
 /**
+ * Register and map all interrupts for @p dinfo.
+ *
+ * @param dev The siba bus device.
+ * @param child The siba child device.
+ * @param dinfo The device info instance on which to register all interrupt
+ * entries.
+ */
+static int
+siba_register_interrupts(device_t dev, device_t child,
+     struct siba_devinfo *dinfo)
+{
+	int error;
+
+	/* Is backplane interrupt distribution enabled for this core? */
+	if (!dinfo->core_id.intr_en)
+		return (0);
+
+	/* Have one interrupt */
+	dinfo->intr.mapped = false;
+	dinfo->intr.irq = 0;
+	dinfo->intr.rid = -1;
+
+	/* Map the interrupt */
+	error = BHND_BUS_MAP_INTR(dev, child, 0 /* single intr is always 0 */,
+	    &dinfo->intr.irq);
+	if (error) {
+		device_printf(dev, "failed mapping interrupt line for core %u: "
+		    "%d\n", dinfo->core_id.core_info.core_idx, error);
+		return (error);
+	}
+	dinfo->intr.mapped = true;
+
+	/* Update the resource list */
+	dinfo->intr.rid = resource_list_add_next(&dinfo->resources, SYS_RES_IRQ,
+	    dinfo->intr.irq, dinfo->intr.irq, 1);
+
+	return (0);
+}
+
+/**
  * Map an addrspace index to its corresponding bhnd(4) BHND_PORT_DEVICE port
  * number.
  * 
@@ -238,7 +274,7 @@ siba_port_count(struct siba_core_id *core_id, bhnd_por
 	switch (port_type) {
 	case BHND_PORT_DEVICE:
 		/* 0, 1, or 2 ports */
-		return (min(core_id->num_addrspace, 2));
+		return (min(core_id->num_admatch, 2));
 
 	case BHND_PORT_AGENT:
 		/* One agent port maps all configuration blocks */
@@ -292,11 +328,11 @@ siba_port_region_count(struct siba_core_id *core_id, b
 	case BHND_PORT_DEVICE:
 		/* The first address space, if any, is mapped to device0.0 */
 		if (port == 0)
-			return (min(core_id->num_addrspace, 1));
+			return (min(core_id->num_admatch, 1));
 
 		/* All remaining address spaces are mapped to device0.(n - 1) */
-		if (port == 1 && core_id->num_addrspace >= 2)
-			return (core_id->num_addrspace - 1);
+		if (port == 1 && core_id->num_admatch >= 2)
+			return (core_id->num_admatch - 1);
 
 		break;
 
@@ -327,7 +363,6 @@ siba_port_region_count(struct siba_core_id *core_id, b
  * 	agent0.0	0
  * 	agent0.1	1
  * 
- * @param num_addrspace The number of available siba address spaces.
  * @param port_type The bhnd(4) port type.
  * @param port The bhnd(4) port number.
  * @param region The bhnd(4) port region.
@@ -394,7 +429,7 @@ siba_find_cfg_block(struct siba_devinfo *dinfo, bhnd_p
  * For compatibility with bcma(4), we map address spaces to port/region
  * identifiers as follows:
  * 
- * 	[port]		[addrspace]
+ * 	[port.region]	[admatch index]
  * 	device0.0	0
  * 	device1.0	1
  * 	device1.1	2
@@ -431,7 +466,7 @@ siba_addrspace_index(struct siba_core_id *core_id, bhn
 	else
 		return (ENOENT);
 
-	if (idx >= core_id->num_addrspace)
+	if (idx >= core_id->num_admatch)
 		return (ENOENT);
 
 	/* Found */
@@ -484,7 +519,7 @@ siba_find_addrspace(struct siba_devinfo *dinfo, bhnd_p
  * @retval 0 success
  * @retval non-zero An error occurred appending the entry.
  */
-int
+static int
 siba_append_dinfo_region(struct siba_devinfo *dinfo, uint8_t addridx,
     uint32_t base, uint32_t size, uint32_t bus_reserved)
 {
@@ -546,7 +581,7 @@ siba_free_dinfo(device_t dev, device_t child, struct s
 	}
 
 	/* Unmap the core's interrupt */
-	if (dinfo->intr_en && dinfo->intr.mapped) {
+	if (dinfo->core_id.intr_en && dinfo->intr.mapped) {
 		BHND_BUS_UNMAP_INTR(dev, child, dinfo->intr.irq);
 		dinfo->intr.mapped = false;
 	}
@@ -585,36 +620,38 @@ siba_admatch_offset(uint8_t addrspace)
  * 
  * @param addrspace The address space index.
  * @param am The address match register value to be parsed.
- * @param[out] addr The parsed address.
- * @param[out] size The parsed size.
+ * @param[out] admatch The parsed address match descriptor
  * 
  * @retval 0 success
  * @retval non-zero a parse error occurred.
  */
 int
-siba_parse_admatch(uint32_t am, uint32_t *addr, uint32_t *size)
+siba_parse_admatch(uint32_t am, struct siba_admatch *admatch)
 {
-	u_int		am_type;
+	u_int am_type;
 	
-	/* Negative encoding is not supported. This is not used on any
-	 * currently known devices*/
-	if (am & SIBA_AM_ADNEG)
-		return (EINVAL);
-	
 	/* Extract the base address and size */
 	am_type = SIBA_REG_GET(am, AM_TYPE);
 	switch (am_type) {
 	case 0:
-		*addr = am & SIBA_AM_BASE0_MASK;
-		*size = 1 << (SIBA_REG_GET(am, AM_ADINT0) + 1);
+		/* Type 0 entries are always enabled, and do not support
+		 * negative matching */
+		admatch->am_base = am & SIBA_AM_BASE0_MASK;
+		admatch->am_size = 1 << (SIBA_REG_GET(am, AM_ADINT0) + 1);
+		admatch->am_enabled = true;
+		admatch->am_negative = false;
 		break;
 	case 1:
-		*addr = am & SIBA_AM_BASE1_MASK;
-		*size = 1 << (SIBA_REG_GET(am, AM_ADINT1) + 1);
+		admatch->am_base = am & SIBA_AM_BASE1_MASK;
+		admatch->am_size = 1 << (SIBA_REG_GET(am, AM_ADINT1) + 1);
+		admatch->am_enabled = ((am & SIBA_AM_ADEN) != 0);
+		admatch->am_negative = ((am & SIBA_AM_ADNEG) != 0);
 		break;
 	case 2:
-		*addr = am & SIBA_AM_BASE2_MASK;
-		*size = 1 << (SIBA_REG_GET(am, AM_ADINT2) + 1);
+		admatch->am_base = am & SIBA_AM_BASE2_MASK;
+		admatch->am_size = 1 << (SIBA_REG_GET(am, AM_ADINT2) + 1);
+		admatch->am_enabled = ((am & SIBA_AM_ADEN) != 0);
+		admatch->am_negative = ((am & SIBA_AM_ADNEG) != 0);
 		break;
 	default:
 		return (EINVAL);

Modified: head/sys/dev/bhnd/siba/sibavar.h
==============================================================================
--- head/sys/dev/bhnd/siba/sibavar.h	Mon Feb 12 19:08:17 2018	(r329179)
+++ head/sys/dev/bhnd/siba/sibavar.h	Mon Feb 12 19:36:26 2018	(r329180)
@@ -37,6 +37,7 @@
 #define _SIBA_SIBAVAR_H_
 
 #include <sys/param.h>
+#include <sys/bitstring.h>
 #include <sys/bus.h>
 #include <sys/limits.h>
 #include <sys/lock.h>
@@ -52,6 +53,7 @@
  */
 
 struct siba_addrspace;
+struct siba_admatch;
 struct siba_cfg_block;
 struct siba_devinfo;
 struct siba_core_id;
@@ -68,13 +70,10 @@ int			 siba_get_intr_ivec(device_t dev, device_t child
 
 uint16_t		 siba_get_bhnd_mfgid(uint16_t ocp_vendor);
 
-struct siba_core_id	 siba_parse_core_id(uint32_t idhigh, uint32_t idlow,
-			     u_int core_idx, int unit);
-
 int			 siba_add_children(device_t bus);
 
 struct siba_devinfo	*siba_alloc_dinfo(device_t dev);
-int			 siba_init_dinfo(device_t dev,
+int			 siba_init_dinfo(device_t dev, device_t child,
 			     struct siba_devinfo *dinfo,
 			     const struct siba_core_id *core_id);
 void			 siba_free_dinfo(device_t dev, device_t child,
@@ -109,13 +108,9 @@ struct siba_addrspace	*siba_find_addrspace(struct siba

*** DIFF OUTPUT TRUNCATED AT 1000 LINES ***


More information about the svn-src-all mailing list