diff options
Diffstat (limited to 'sys')
-rw-r--r-- | sys/dev/bhnd/siba/siba.c | 205 | ||||
-rw-r--r-- | sys/dev/bhnd/siba/siba_erom.c | 197 | ||||
-rw-r--r-- | sys/dev/bhnd/siba/siba_eromvar.h | 46 | ||||
-rw-r--r-- | sys/dev/bhnd/siba/siba_subr.c | 173 | ||||
-rw-r--r-- | sys/dev/bhnd/siba/sibavar.h | 47 |
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 */ |