aboutsummaryrefslogtreecommitdiff
path: root/sys/dev/bhnd
diff options
context:
space:
mode:
authorLandon J. Fuller <landonf@FreeBSD.org>2018-02-12 19:36:26 +0000
committerLandon J. Fuller <landonf@FreeBSD.org>2018-02-12 19:36:26 +0000
commit7c7c726bca778fa6f49c9ed6ce681c3b281bcdd8 (patch)
tree7543abf579ddfc49a2840a9e260d3571bbe68e60 /sys/dev/bhnd
parent21b8a7a6cad1a4ecb217f4b830088cbcf36b92ac (diff)
downloadsrc-7c7c726bca778fa6f49c9ed6ce681c3b281bcdd8.tar.gz
src-7c7c726bca778fa6f49c9ed6ce681c3b281bcdd8.zip
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.
Notes
Notes: svn path=/head/; revision=329180
Diffstat (limited to 'sys/dev/bhnd')
-rw-r--r--sys/dev/bhnd/siba/siba.c205
-rw-r--r--sys/dev/bhnd/siba/siba_erom.c197
-rw-r--r--sys/dev/bhnd/siba/siba_eromvar.h46
-rw-r--r--sys/dev/bhnd/siba/siba_subr.c173
-rw-r--r--sys/dev/bhnd/siba/sibavar.h47
5 files changed, 388 insertions, 280 deletions
diff --git a/sys/dev/bhnd/siba/siba.c b/sys/dev/bhnd/siba/siba.c
index 984399f00abd..c9696f0e45b2 100644
--- a/sys/dev/bhnd/siba/siba.c
+++ b/sys/dev/bhnd/siba/siba.c
@@ -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 type, int rid,
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,117 +1166,10 @@ siba_get_intr_ivec(device_t dev, device_t child, u_int intr, u_int *ivec)
dinfo = device_get_ivars(child);
- KASSERT(dinfo->intr_en, ("core does not have an interrupt assigned"));
- *ivec = dinfo->intr.flag;
- return (0);
-}
-
-/**
- * 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);
- }
-
- 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);
+ KASSERT(dinfo->core_id.intr_en,
+ ("core does not have an interrupt assigned"));
+ *ivec = dinfo->core_id.intr_flag;
return (0);
}
@@ -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,39 +1315,13 @@ 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;
- 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++;
- }
+ if ((error = siba_erom_get_core_id(siba_erom, i, &cores[i])))
+ goto failed;
/* Add the child device */
child = BUS_ADD_CHILD(dev, 0, NULL, -1);
@@ -1460,30 +1338,22 @@ siba_add_children(device_t dev)
goto failed;
}
- if ((error = siba_init_dinfo(dev, 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)))
+ if ((error = siba_init_dinfo(dev, child, dinfo, &cores[i])))
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);
}
diff --git a/sys/dev/bhnd/siba/siba_erom.c b/sys/dev/bhnd/siba/siba_erom.c
index 57b2f79e833b..aa2e554f2e14 100644
--- a/sys/dev/bhnd/siba/siba_erom.c
+++ b/sys/dev/bhnd/siba/siba_erom.c
@@ -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_erom_io *eio,
* 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,16 +231,151 @@ siba_eio_read_4(struct siba_erom_io *io, u_int core_idx, bus_size_t offset)
* @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));
+
+ 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++;
+ }
- return (siba_parse_core_id(idhigh, idlow, core_idx, unit));
+ *result = sid;
+ return (0);
}
/**
@@ -252,9 +391,12 @@ siba_eio_read_chipid(struct siba_erom_io *io, bus_addr_t enum_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 bhnd_core_match *desc,
{
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 bhnd_core_match *desc,
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 bhnd_core_match *desc,
/* 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 struct bhnd_core_match *desc
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 struct bhnd_core_match *desc
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 struct bhnd_core_match *desc
/* 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 struct bhnd_core_match *desc
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 bhnd_core_info **cores,
{
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 bhnd_core_info **cores,
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);
}
}
diff --git a/sys/dev/bhnd/siba/siba_eromvar.h b/sys/dev/bhnd/siba/siba_eromvar.h
new file mode 100644
index 000000000000..fa0f60011a02
--- /dev/null
+++ b/sys/dev/bhnd/siba/siba_eromvar.h
@@ -0,0 +1,46 @@
+/*-
+ * SPDX-License-Identifier: BSD-2-Clause-FreeBSD
+ *
+ * Copyright (c) 2018 Landon Fuller <landonf@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_ */
diff --git a/sys/dev/bhnd/siba/siba_subr.c b/sys/dev/bhnd/siba/siba_subr.c
index 9a854abd14c6..536f683b483f 100644
--- a/sys/dev/bhnd/siba/siba_subr.c
+++ b/sys/dev/bhnd/siba/siba_subr.c
@@ -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,7 +102,11 @@ 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,10 +124,77 @@ 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);
}
@@ -238,7 +274,7 @@ siba_port_count(struct siba_core_id *core_id, bhnd_port_type port_type)
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, bhnd_port_type port_type,
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, bhnd_port_type port_type,
* 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_port_type type, u_int port,
* 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, bhnd_port_type port_type,
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_port_type type, u_int port,
* @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 siba_devinfo *dinfo)
}
/* 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;
-
- /* Negative encoding is not supported. This is not used on any
- * currently known devices*/
- if (am & SIBA_AM_ADNEG)
- return (EINVAL);
+ u_int am_type;
/* 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);
diff --git a/sys/dev/bhnd/siba/sibavar.h b/sys/dev/bhnd/siba/sibavar.h
index 4d60edd42a7c..650ad799406b 100644
--- a/sys/dev/bhnd/siba/sibavar.h
+++ b/sys/dev/bhnd/siba/sibavar.h
@@ -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_devinfo *dinfo,
struct siba_cfg_block *siba_find_cfg_block(struct siba_devinfo *dinfo,
bhnd_port_type type, u_int port, u_int region);
-int siba_append_dinfo_region(struct siba_devinfo *dinfo,
- uint8_t sid, uint32_t base, uint32_t size,
- uint32_t bus_reserved);
-
u_int siba_admatch_offset(uint8_t addrspace);
-int siba_parse_admatch(uint32_t am, uint32_t *addr,
- uint32_t *size);
+int siba_parse_admatch(uint32_t am,
+ struct siba_admatch *admatch);
void siba_write_target_state(device_t dev,
struct siba_devinfo *dinfo, bus_size_t reg,
@@ -148,6 +143,14 @@ int siba_wait_target_state(device_t dev,
#define SIBA_MAX_PORT 2 /**< maximum number of advertised
* bhnd(4) ports */
+/** siba(4) address match descriptor */
+struct siba_admatch {
+ uint32_t am_base; /**< base address. */
+ uint32_t am_size; /**< size. */
+ bool am_negative; /**< if true, negative matching is performed. */
+ bool am_enabled; /**< if true, matching on this entry is enabled. */
+};
+
/** siba(4) address space descriptor */
struct siba_addrspace {
uint32_t sa_base; /**< base address */
@@ -166,7 +169,6 @@ struct siba_cfg_block {
/** siba(4) backplane interrupt flag descriptor */
struct siba_intr {
- u_int flag; /**< backplane flag # */
bool mapped; /**< if an irq has been mapped */
int rid; /**< bus resource id, or -1 if unassigned */
rman_res_t irq; /**< the mapped bus irq, if any */
@@ -176,15 +178,17 @@ struct siba_intr {
* siba(4) per-core identification info.
*/
struct siba_core_id {
- struct bhnd_core_info core_info; /**< standard bhnd(4) core info */
- uint16_t sonics_vendor; /**< OCP vendor identifier used to generate
- * the JEDEC-106 bhnd(4) vendor identifier. */
- uint8_t sonics_rev; /**< sonics backplane revision code */
- uint8_t num_addrspace; /**< number of address ranges mapped to
- this core. */
- uint8_t num_cfg_blocks; /**< number of Sonics configuration register
- blocks mapped to the core's enumeration
- space */
+ struct bhnd_core_info core_info; /**< standard bhnd(4) core info */
+ uint16_t sonics_vendor; /**< OCP vendor identifier used to generate
+ * the JEDEC-106 bhnd(4) vendor identifier. */
+ uint8_t sonics_rev; /**< sonics backplane revision code */
+ bool intr_en; /**< if backplane interrupt distribution is enabled for this core */
+ u_int intr_flag; /**< backplane interrupt flag # */
+ struct siba_admatch admatch[SIBA_MAX_ADDRSPACE]; /**< active address match descriptors defined by this core. */
+ uint8_t num_admatch; /**< number of address match descriptors. */
+ uint8_t num_cfg_blocks; /**< number of Sonics configuration register
+ blocks mapped to the core's enumeration
+ space */
};
/**
@@ -205,8 +209,7 @@ struct siba_devinfo {
struct siba_core_id core_id; /**< core identification info */
struct siba_addrspace addrspace[SIBA_MAX_ADDRSPACE]; /**< memory map descriptors */
struct siba_cfg_block cfg[SIBA_MAX_CFG]; /**< config block descriptors */
- struct siba_intr intr; /**< interrupt flag descriptor, if any */
- bool intr_en; /**< if true, core has an assigned interrupt flag */
+ struct siba_intr intr; /**< interrupt flag mapping, if any */
struct bhnd_resource *cfg_res[SIBA_MAX_CFG]; /**< bus-mapped config block registers */
int cfg_rid[SIBA_MAX_CFG]; /**< bus-mapped config block resource IDs */