Index: head/sys/dev/bhnd/siba/siba.c =================================================================== --- head/sys/dev/bhnd/siba/siba.c (revision 301971) +++ head/sys/dev/bhnd/siba/siba.c (revision 301972) @@ -1,697 +1,648 @@ /*- * Copyright (c) 2015 Landon Fuller * 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, * without modification. * 2. Redistributions in binary form must reproduce at minimum a disclaimer * similar to the "NO WARRANTY" disclaimer below ("Disclaimer") and any * redistribution must be conditioned upon including a substantially * similar Disclaimer requirement for further binary redistribution. * * NO WARRANTY * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT * LIMITED TO, THE IMPLIED WARRANTIES OF NONINFRINGEMENT, MERCHANTIBILITY * AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL * THE COPYRIGHT HOLDERS OR CONTRIBUTORS BE LIABLE FOR 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 DAMAGES. */ #include __FBSDID("$FreeBSD$"); #include #include #include #include #include #include #include #include #include "sibareg.h" #include "sibavar.h" int siba_probe(device_t dev) { device_set_desc(dev, "SIBA BHND bus"); return (BUS_PROBE_DEFAULT); } int siba_attach(device_t dev) { struct siba_devinfo *dinfo; struct siba_softc *sc; device_t *devs; int ndevs; int error; sc = device_get_softc(dev); sc->dev = dev; /* Fetch references to the siba SIBA_CFG* blocks for all * registered devices */ if ((error = device_get_children(dev, &devs, &ndevs))) return (error); for (int i = 0; i < ndevs; i++) { struct siba_addrspace *addrspace; - struct siba_port *port; dinfo = device_get_ivars(devs[i]); KASSERT(!device_is_suspended(devs[i]), ("siba(4) stateful suspend handling requires that devices " "not be suspended before siba_attach()")); /* Fetch the core register address space */ - port = siba_dinfo_get_port(dinfo, BHND_PORT_DEVICE, 0); - if (port == NULL) { - error = ENXIO; - goto cleanup; - } - - addrspace = siba_find_port_addrspace(port, SIBA_ADDRSPACE_CORE); + addrspace = siba_find_addrspace(dinfo, BHND_PORT_DEVICE, 0, 0); if (addrspace == NULL) { + device_printf(dev, + "missing device registers for core %d\n", i); error = ENXIO; goto cleanup; } /* * Map the per-core configuration blocks */ - KASSERT(dinfo->core_id.num_cfg_blocks <= SIBA_CFG_NUM_MAX, + KASSERT(dinfo->core_id.num_cfg_blocks <= SIBA_MAX_CFG, ("config block count %u out of range", dinfo->core_id.num_cfg_blocks)); for (u_int cfgidx = 0; cfgidx < dinfo->core_id.num_cfg_blocks; cfgidx++) { rman_res_t r_start, r_count, r_end; /* Determine the config block's address range; configuration * blocks are allocated starting at SIBA_CFG0_OFFSET, * growing downwards. */ r_start = addrspace->sa_base + SIBA_CFG0_OFFSET; r_start -= cfgidx * SIBA_CFG_SIZE; r_count = SIBA_CFG_SIZE; r_end = r_start + r_count - 1; /* Allocate the config resource */ dinfo->cfg_rid[cfgidx] = 0; dinfo->cfg[cfgidx] = BHND_BUS_ALLOC_RESOURCE(dev, dev, SYS_RES_MEMORY, &dinfo->cfg_rid[cfgidx], r_start, r_end, r_count, RF_ACTIVE); if (dinfo->cfg[cfgidx] == NULL) { device_printf(dev, "failed allocating CFG_%u for " "core %d\n", cfgidx, i); error = ENXIO; goto cleanup; } } } cleanup: free(devs, M_BHND); if (error) return (error); /* Delegate remainder to standard bhnd method implementation */ return (bhnd_generic_attach(dev)); } int siba_detach(device_t dev) { return (bhnd_generic_detach(dev)); } int siba_resume(device_t dev) { return (bhnd_generic_resume(dev)); } int siba_suspend(device_t dev) { return (bhnd_generic_suspend(dev)); } static int siba_read_ivar(device_t dev, device_t child, int index, uintptr_t *result) { const struct siba_devinfo *dinfo; const struct bhnd_core_info *cfg; dinfo = device_get_ivars(child); cfg = &dinfo->core_id.core_info; switch (index) { case BHND_IVAR_VENDOR: *result = cfg->vendor; return (0); case BHND_IVAR_DEVICE: *result = cfg->device; return (0); case BHND_IVAR_HWREV: *result = cfg->hwrev; return (0); case BHND_IVAR_DEVICE_CLASS: *result = bhnd_core_class(cfg); return (0); case BHND_IVAR_VENDOR_NAME: *result = (uintptr_t) bhnd_vendor_name(cfg->vendor); return (0); case BHND_IVAR_DEVICE_NAME: *result = (uintptr_t) bhnd_core_name(cfg); return (0); case BHND_IVAR_CORE_INDEX: *result = cfg->core_idx; return (0); case BHND_IVAR_CORE_UNIT: *result = cfg->unit; return (0); default: return (ENOENT); } } static int siba_write_ivar(device_t dev, device_t child, int index, uintptr_t value) { switch (index) { case BHND_IVAR_VENDOR: case BHND_IVAR_DEVICE: case BHND_IVAR_HWREV: case BHND_IVAR_DEVICE_CLASS: case BHND_IVAR_VENDOR_NAME: case BHND_IVAR_DEVICE_NAME: case BHND_IVAR_CORE_INDEX: case BHND_IVAR_CORE_UNIT: return (EINVAL); default: return (ENOENT); } } static void siba_child_deleted(device_t dev, device_t child) { struct siba_devinfo *dinfo = device_get_ivars(child); if (dinfo != NULL) siba_free_dinfo(dev, dinfo); } static struct resource_list * siba_get_resource_list(device_t dev, device_t child) { struct siba_devinfo *dinfo = device_get_ivars(child); return (&dinfo->resources); } static device_t siba_find_hostb_device(device_t dev) { struct siba_softc *sc = device_get_softc(dev); /* This is set (or not) by the concrete siba driver subclass. */ return (sc->hostb_dev); } static int siba_reset_core(device_t dev, device_t child, uint16_t flags) { struct siba_devinfo *dinfo; if (device_get_parent(child) != dev) BHND_BUS_RESET_CORE(device_get_parent(dev), child, flags); dinfo = device_get_ivars(child); /* Can't reset the core without access to the CFG0 registers */ if (dinfo->cfg[0] == NULL) return (ENODEV); // TODO - perform reset return (ENXIO); } static int siba_suspend_core(device_t dev, device_t child) { struct siba_devinfo *dinfo; if (device_get_parent(child) != dev) BHND_BUS_SUSPEND_CORE(device_get_parent(dev), child); dinfo = device_get_ivars(child); /* Can't suspend the core without access to the CFG0 registers */ if (dinfo->cfg[0] == NULL) return (ENODEV); // TODO - perform suspend return (ENXIO); } static u_int siba_get_port_count(device_t dev, device_t child, bhnd_port_type type) { struct siba_devinfo *dinfo; /* delegate non-bus-attached devices to our parent */ if (device_get_parent(child) != dev) return (BHND_BUS_GET_PORT_COUNT(device_get_parent(dev), child, type)); dinfo = device_get_ivars(child); - - /* We advertise exactly one port of any type */ - if (siba_dinfo_get_port(dinfo, type, 0) != NULL) - return (1); - - return (0); + return (siba_addrspace_port_count(dinfo)); } static u_int siba_get_region_count(device_t dev, device_t child, bhnd_port_type type, - u_int port_num) + u_int port) { struct siba_devinfo *dinfo; - struct siba_port *port; /* delegate non-bus-attached devices to our parent */ if (device_get_parent(child) != dev) return (BHND_BUS_GET_REGION_COUNT(device_get_parent(dev), child, - type, port_num)); + type, port)); dinfo = device_get_ivars(child); - port = siba_dinfo_get_port(dinfo, type, port_num); - if (port == NULL) + if (!siba_is_port_valid(dinfo, type, port)) return (0); - return (port->sp_num_addrs); + return (siba_addrspace_region_count(dinfo, port)); } static int siba_get_port_rid(device_t dev, device_t child, bhnd_port_type port_type, u_int port_num, u_int region_num) { struct siba_devinfo *dinfo; - struct siba_port *port; struct siba_addrspace *addrspace; /* delegate non-bus-attached devices to our parent */ if (device_get_parent(child) != dev) return (BHND_BUS_GET_PORT_RID(device_get_parent(dev), child, port_type, port_num, region_num)); dinfo = device_get_ivars(child); - port = siba_dinfo_get_port(dinfo, port_type, port_num); - if (port == NULL) + addrspace = siba_find_addrspace(dinfo, port_type, port_num, region_num); + if (addrspace == NULL) return (-1); - STAILQ_FOREACH(addrspace, &port->sp_addrs, sa_link) { - if (addrspace->sa_region_num == region_num) - return (addrspace->sa_rid); - } - - /* not found */ - return (-1); + return (addrspace->sa_rid); } static int siba_decode_port_rid(device_t dev, device_t child, int type, int rid, bhnd_port_type *port_type, u_int *port_num, u_int *region_num) { struct siba_devinfo *dinfo; - struct siba_port *port; - struct siba_addrspace *addrspace; /* delegate non-bus-attached devices to our parent */ if (device_get_parent(child) != dev) return (BHND_BUS_DECODE_PORT_RID(device_get_parent(dev), child, type, rid, port_type, port_num, region_num)); dinfo = device_get_ivars(child); /* Ports are always memory mapped */ if (type != SYS_RES_MEMORY) return (EINVAL); - /* Starting with the most likely device list, search all three port - * lists */ - bhnd_port_type types[] = { - BHND_PORT_DEVICE, - BHND_PORT_AGENT, - BHND_PORT_BRIDGE - }; - - for (int i = 0; i < nitems(types); i++) { - port = siba_dinfo_get_port(dinfo, types[i], 0); - if (port == NULL) + for (int i = 0; i < dinfo->core_id.num_addrspace; i++) { + if (dinfo->addrspace[i].sa_rid != rid) continue; - - STAILQ_FOREACH(addrspace, &port->sp_addrs, sa_link) { - if (addrspace->sa_rid != rid) - continue; - *port_type = port->sp_type; - *port_num = port->sp_num; - *region_num = addrspace->sa_region_num; - } + *port_type = BHND_PORT_DEVICE; + *port_num = siba_addrspace_port(i); + *region_num = siba_addrspace_region(i); + return (0); } + /* Not found */ return (ENOENT); } static int siba_get_region_addr(device_t dev, device_t child, bhnd_port_type port_type, u_int port_num, u_int region_num, bhnd_addr_t *addr, bhnd_size_t *size) { struct siba_devinfo *dinfo; - struct siba_port *port; struct siba_addrspace *addrspace; /* delegate non-bus-attached devices to our parent */ if (device_get_parent(child) != dev) { return (BHND_BUS_GET_REGION_ADDR(device_get_parent(dev), child, port_type, port_num, region_num, addr, size)); } dinfo = device_get_ivars(child); - port = siba_dinfo_get_port(dinfo, port_type, port_num); - if (port == NULL) + addrspace = siba_find_addrspace(dinfo, port_type, port_num, region_num); + if (addrspace == NULL) return (ENOENT); - STAILQ_FOREACH(addrspace, &port->sp_addrs, sa_link) { - if (addrspace->sa_region_num != region_num) - continue; - - *addr = addrspace->sa_base; - *size = addrspace->sa_size - addrspace->sa_bus_reserved; - return (0); - } - - return (ENOENT); + *addr = addrspace->sa_base; + *size = addrspace->sa_size - addrspace->sa_bus_reserved; + 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 resource *r) { struct siba_core_id *cid; uint32_t addr; uint32_t size; - u_int region_num; int error; cid = &di->core_id; - /* Region numbers must be assigned in order, but our siba address - * space IDs may be sparsely allocated; thus, we track - * the region index separately. */ - region_num = 0; /* Register the device address space entries */ - for (uint8_t sid = 0; sid < di->core_id.num_addrspace; sid++) { + 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(sid); + adm_offset = siba_admatch_offset(i); if (adm_offset == 0) { - device_printf(dev, "addrspace %hhu is unsupported", sid); + device_printf(dev, "addrspace %hhu is unsupported", i); return (ENODEV); } /* Fetch the address match register value */ adm = 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 (sid == SIBA_ADDRSPACE_CORE) + if (i == SIBA_CORE_ADDRSPACE) bus_reserved = cid->num_cfg_blocks * SIBA_CFG_SIZE; /* Append the region info */ - error = siba_append_dinfo_region(di, BHND_PORT_DEVICE, 0, - region_num, sid, addr, size, bus_reserved); + error = siba_append_dinfo_region(di, i, addr, size, + bus_reserved); if (error) return (error); - - - region_num++; } return (0); } /** * Scan the core table and add all valid discovered cores to * the bus. * * @param dev The siba bus device. * @param chipid The chip identifier, if the device does not provide a * ChipCommon core. Should o NULL otherwise. */ int siba_add_children(device_t dev, const struct bhnd_chipid *chipid) { struct bhnd_chipid ccid; struct bhnd_core_info *cores; struct siba_devinfo *dinfo; struct resource *r; int rid; int error; dinfo = NULL; cores = NULL; r = NULL; /* * Try to determine the number of device cores via the ChipCommon * identification registers. * * A small number of very early devices do not include a ChipCommon * core, in which case our caller must supply the chip identification * information via a non-NULL chipid parameter. */ if (chipid == NULL) { uint32_t idhigh, ccreg; uint16_t vendor, device; uint8_t ccrev; /* Map the first core's register block. If the ChipCommon core * exists, it will always be the first core. */ rid = 0; r = bus_alloc_resource(dev, SYS_RES_MEMORY, &rid, SIBA_CORE_ADDR(0), SIBA_CORE_SIZE, SIBA_CORE_ADDR(0) + SIBA_CORE_SIZE - 1, RF_ACTIVE); /* Identify the core */ idhigh = bus_read_4(r, SB0_REG_ABS(SIBA_CFG0_IDHIGH)); vendor = SIBA_REG_GET(idhigh, IDH_VENDOR); device = SIBA_REG_GET(idhigh, IDH_DEVICE); ccrev = SIBA_IDH_CORE_REV(idhigh); if (vendor != OCP_VENDOR_BCM || device != BHND_COREID_CC) { device_printf(dev, "cannot identify device: no chipcommon core " "found\n"); error = ENXIO; goto cleanup; } /* Identify the chipset */ ccreg = bus_read_4(r, CHIPC_ID); ccid = bhnd_parse_chipid(ccreg, SIBA_ENUM_ADDR); if (!CHIPC_NCORES_MIN_HWREV(ccrev)) { switch (ccid.chip_id) { case BHND_CHIPID_BCM4306: ccid.ncores = 6; break; case BHND_CHIPID_BCM4704: ccid.ncores = 9; break; case BHND_CHIPID_BCM5365: /* * BCM5365 does support ID_NUMCORE in at least * some of its revisions, but for unknown * reasons, Broadcom's drivers always exclude * the ChipCommon revision (0x5) used by BCM5365 * from the set of revisions supporting * ID_NUMCORE, and instead supply a fixed value. * * Presumably, at least some of these devices * shipped with a broken ID_NUMCORE value. */ ccid.ncores = 7; break; default: device_printf(dev, "unable to determine core " "count for unrecognized chipset 0x%hx\n", ccid.chip_id); error = ENXIO; goto cleanup; } } chipid = &ccid; bus_release_resource(dev, SYS_RES_MEMORY, rid, r); } /* Allocate our temporary core table and enumerate all cores */ cores = malloc(sizeof(*cores) * chipid->ncores, M_BHND, M_NOWAIT); if (cores == NULL) return (ENOMEM); /* Add all cores. */ for (u_int i = 0; i < chipid->ncores; i++) { struct siba_core_id cid; 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 = bus_alloc_resource(dev, SYS_RES_MEMORY, &rid, r_start, r_end, r_count, RF_ACTIVE); if (r == NULL) { error = ENXIO; goto cleanup; } /* Read the core info */ idhigh = bus_read_4(r, SB0_REG_ABS(SIBA_CFG0_IDHIGH)); idlow = bus_read_4(r, SB0_REG_ABS(SIBA_CFG0_IDLOW)); cid = siba_parse_core_id(idhigh, idlow, i, 0); cores[i] = cid.core_info; /* Determine unit number */ for (u_int j = 0; j < i; j++) { if (cores[j].vendor == cores[i].vendor && cores[j].device == cores[i].device) cores[i].unit++; } /* Allocate per-device bus info */ dinfo = siba_alloc_dinfo(dev, &cid); if (dinfo == NULL) { error = ENXIO; goto cleanup; } /* Register the core's address space(s). */ if ((error = siba_register_addrspaces(dev, dinfo, r))) goto cleanup; /* Add the child device */ child = device_add_child(dev, NULL, -1); if (child == NULL) { error = ENXIO; goto cleanup; } /* The child device now owns the dinfo pointer */ device_set_ivars(child, dinfo); dinfo = 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); /* Release our resource */ bus_release_resource(dev, SYS_RES_MEMORY, rid, r); r = NULL; } cleanup: if (cores != NULL) free(cores, M_BHND); if (dinfo != NULL) siba_free_dinfo(dev, dinfo); if (r != NULL) bus_release_resource(dev, SYS_RES_MEMORY, rid, r); return (error); } static device_method_t siba_methods[] = { /* Device interface */ DEVMETHOD(device_probe, siba_probe), DEVMETHOD(device_attach, siba_attach), DEVMETHOD(device_detach, siba_detach), DEVMETHOD(device_resume, siba_resume), DEVMETHOD(device_suspend, siba_suspend), /* Bus interface */ DEVMETHOD(bus_child_deleted, siba_child_deleted), DEVMETHOD(bus_read_ivar, siba_read_ivar), DEVMETHOD(bus_write_ivar, siba_write_ivar), DEVMETHOD(bus_get_resource_list, siba_get_resource_list), /* BHND interface */ DEVMETHOD(bhnd_bus_find_hostb_device, siba_find_hostb_device), DEVMETHOD(bhnd_bus_reset_core, siba_reset_core), DEVMETHOD(bhnd_bus_suspend_core, siba_suspend_core), DEVMETHOD(bhnd_bus_get_port_count, siba_get_port_count), DEVMETHOD(bhnd_bus_get_region_count, siba_get_region_count), DEVMETHOD(bhnd_bus_get_port_rid, siba_get_port_rid), DEVMETHOD(bhnd_bus_decode_port_rid, siba_decode_port_rid), DEVMETHOD(bhnd_bus_get_region_addr, siba_get_region_addr), DEVMETHOD_END }; DEFINE_CLASS_1(bhnd, siba_driver, siba_methods, sizeof(struct siba_softc), bhnd_driver); MODULE_VERSION(siba, 1); MODULE_DEPEND(siba, bhnd, 1, 1, 1); Index: head/sys/dev/bhnd/siba/siba_subr.c =================================================================== --- head/sys/dev/bhnd/siba/siba_subr.c (revision 301971) +++ head/sys/dev/bhnd/siba/siba_subr.c (revision 301972) @@ -1,383 +1,417 @@ /*- * Copyright (c) 2015 Landon Fuller * 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, * without modification. * 2. Redistributions in binary form must reproduce at minimum a disclaimer * similar to the "NO WARRANTY" disclaimer below ("Disclaimer") and any * redistribution must be conditioned upon including a substantially * similar Disclaimer requirement for further binary redistribution. * * NO WARRANTY * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT * LIMITED TO, THE IMPLIED WARRANTIES OF NONINFRINGEMENT, MERCHANTIBILITY * AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL * THE COPYRIGHT HOLDERS OR CONTRIBUTORS BE LIABLE FOR 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 DAMAGES. */ #include __FBSDID("$FreeBSD$"); #include #include #include #include #include #include #include #include #include "sibareg.h" #include "sibavar.h" /** * Map a siba(4) OCP vendor code to its corresponding JEDEC JEP-106 vendor * code. * * @param ocp_vendor An OCP vendor code. * @return The BHND_MFGID constant corresponding to @p ocp_vendor, or * BHND_MFGID_INVALID if the OCP vendor is unknown. */ uint16_t siba_get_bhnd_mfgid(uint16_t ocp_vendor) { switch (ocp_vendor) { case OCP_VENDOR_BCM: return (BHND_MFGID_BCM); default: return (BHND_MFGID_INVALID); } } /** * 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 }; } /** - * Initialize new port descriptor. - * - * @param port_num Port number. - * @param port_type Port type. - */ -static void -siba_init_port(struct siba_port *port, bhnd_port_type port_type, u_int port_num) -{ - port->sp_num = port_num; - port->sp_type = port_type; - port->sp_num_addrs = 0; - STAILQ_INIT(&port->sp_addrs); -} - -/** - * Deallocate all resources associated with the given port descriptor. - * - * @param port Port descriptor to be deallocated. - */ -static void -siba_release_port(struct siba_port *port) { - struct siba_addrspace *as, *as_next; - - STAILQ_FOREACH_SAFE(as, &port->sp_addrs, sa_link, as_next) { - free(as, M_BHND); - } -} - -/** * Allocate and initialize new device info structure, copying the * provided core id. * * @param dev The requesting bus device. * @param core Device core info. */ struct siba_devinfo * siba_alloc_dinfo(device_t bus, const struct siba_core_id *core_id) { struct siba_devinfo *dinfo; dinfo = malloc(sizeof(struct siba_devinfo), M_BHND, M_NOWAIT); if (dinfo == NULL) return NULL; dinfo->core_id = *core_id; for (u_int i = 0; i < nitems(dinfo->cfg); i++) { dinfo->cfg[i] = NULL; dinfo->cfg_rid[i] = -1; } - siba_init_port(&dinfo->device_port, BHND_PORT_DEVICE, 0); resource_list_init(&dinfo->resources); return dinfo; } /** - * Return the @p dinfo port instance for @p type, or NULL. + * Map an addrspace index to its corresponding bhnd(4) port number. * - * @param dinfo The siba device info. - * @param type The requested port type. + * @param addrspace Address space index. + */ +u_int +siba_addrspace_port(u_int addrspace) +{ + /* The first addrspace is always mapped to device0; the remainder + * are mapped to device1 */ + if (addrspace == 0) + return (0); + else + return (1); +} + +/** + * Map an addrspace index to its corresponding bhnd(4) region number. * - * @retval siba_port If @p port_type and @p port_num are defined on @p dinfo. - * @retval NULL If the requested port is not defined on @p dinfo. + * @param addrspace Address space index. */ -struct siba_port * -siba_dinfo_get_port(struct siba_devinfo *dinfo, bhnd_port_type port_type, - u_int port_num) +u_int +siba_addrspace_region(u_int addrspace) { - /* We only define a single port for any given type. */ - if (port_num != 0) - return (NULL); + /* The first addrspace is always mapped to device0.0; the remainder + * are mapped to device1.0 + (n - 1) */ + if (addrspace == 0) + return (0); + else + return (addrspace - 1); +} - switch (port_type) { - case BHND_PORT_DEVICE: - return (&dinfo->device_port); - case BHND_PORT_BRIDGE: - return (NULL); - case BHND_PORT_AGENT: - return (NULL); - default: - printf("%s: unknown port_type (%d)\n", - __func__, - port_type); - return (NULL); - } +/** + * Return the number of bhnd(4) ports to advertise for the given + * @p dinfo. + * + * @param dinfo The device info to query. + */ +u_int +siba_addrspace_port_count(struct siba_devinfo *dinfo) +{ + /* 0, 1, or 2 ports */ + return min(dinfo->core_id.num_addrspace, 2); } +/** + * Return the number of bhnd(4) regions to advertise on @p port + * given the provided @p num_addrspace address space count. + * + * @param num_addrspace The number of core-mapped siba(4) Sonics/OCP address + * spaces. + */ +u_int +siba_addrspace_region_count(struct siba_devinfo *dinfo, u_int port) +{ + u_int num_addrspace = dinfo->core_id.num_addrspace; + /* The first address space, if any, is mapped to device0.0 */ + if (port == 0) + return (min(num_addrspace, 1)); + + /* All remaining address spaces are mapped to device0.(n - 1) */ + if (port == 1 && num_addrspace >= 2) + return (num_addrspace - 1); + + /* No region mapping */ + return (0); +} + /** - * Find an address space with @p sid on @p port. + * Return true if @p port is defined on @p dinfo, false otherwise. + * + * Refer to the siba_find_addrspace() function for information on siba's + * mapping of bhnd(4) port and region identifiers. * - * @param port The port to search for a matching address space. - * @param sid The siba-assigned address space ID to search for. + * @param dinfo The device info to verify the port against. + * @param type The bhnd(4) port type. + * @param port The bhnd(4) port number. */ -struct siba_addrspace * -siba_find_port_addrspace(struct siba_port *port, uint8_t sid) +bool +siba_is_port_valid(struct siba_devinfo *dinfo, bhnd_port_type type, u_int port) { - struct siba_addrspace *addrspace; + /* Only device ports are supported */ + if (type != BHND_PORT_DEVICE) + return (false); - STAILQ_FOREACH(addrspace, &port->sp_addrs, sa_link) { - if (addrspace->sa_sid == sid) - return (addrspace); - } + /* Verify the index against the port count */ + if (siba_addrspace_port_count(dinfo) <= port) + return (false); - /* not found */ - return (NULL); + return (true); } /** - * Append a new address space entry to @p port_num of type @p port_type - * in @p dinfo. + * Map an bhnd(4) type/port/region triplet to its associated address space + * entry, if any. * - * The range will also be registered in @p dinfo resource list. + * For compatibility with bcma(4), we map address spaces to port/region + * identifiers as follows: * + * [port] [addrspace] + * device0.0 0 + * device1.0 1 + * device1.1 2 + * device1.2 3 + * + * The only supported port type is BHND_PORT_DEVICE. + * + * @param dinfo The device info to search for a matching address space. + * @param type The bhnd(4) port type. + * @param port The bhnd(4) port number. + * @param region The bhnd(4) port region. + */ +struct siba_addrspace * +siba_find_addrspace(struct siba_devinfo *dinfo, bhnd_port_type type, u_int port, + u_int region) +{ + u_int addridx; + + if (!siba_is_port_valid(dinfo, type, port)) + return (NULL); + + if (port == 0) + addridx = region; + else if (port == 1) + addridx = region + 1; + else + return (NULL); + + /* Out of range? */ + if (addridx >= dinfo->core_id.num_addrspace) + return (NULL); + + /* Found */ + return (&dinfo->addrspace[addridx]); +} + +/** + * Append an address space entry to @p dinfo. + * * @param dinfo The device info entry to update. - * @param port_type The port type. - * @param port_num The port number. - * @param region_num The region index number. - * @param sid The siba-assigned core-unique address space identifier. + * @param addridx The address space index. * @param base The mapping's base address. * @param size The mapping size. * @param bus_reserved Number of bytes to reserve in @p size for bus use * when registering the resource list entry. This is used to reserve bus * access to the core's SIBA_CFG* register blocks. * * @retval 0 success * @retval non-zero An error occurred appending the entry. */ int -siba_append_dinfo_region(struct siba_devinfo *dinfo, bhnd_port_type port_type, - u_int port_num, u_int region_num, uint8_t sid, uint32_t base, uint32_t size, - uint32_t bus_reserved) +siba_append_dinfo_region(struct siba_devinfo *dinfo, uint8_t addridx, + uint32_t base, uint32_t size, uint32_t bus_reserved) { struct siba_addrspace *sa; - struct siba_port *port; rman_res_t r_size; /* Verify that base + size will not overflow */ if (size > 0 && UINT32_MAX - (size - 1) < base) return (ERANGE); /* Verify that size - bus_reserved will not underflow */ if (size < bus_reserved) return (ERANGE); /* Must not be 0-length */ if (size == 0) return (EINVAL); - /* Determine target port */ - port = siba_dinfo_get_port(dinfo, port_type, port_num); - if (port == NULL) + /* Must not exceed addrspace array size */ + if (addridx >= nitems(dinfo->addrspace)) return (EINVAL); - /* Allocate new addrspace entry */ - sa = malloc(sizeof(*sa), M_BHND, M_NOWAIT|M_ZERO); - if (sa == NULL) - return (ENOMEM); - + /* Initialize new addrspace entry */ + sa = &dinfo->addrspace[addridx]; sa->sa_base = base; sa->sa_size = size; - sa->sa_sid = sid; - sa->sa_region_num = region_num; sa->sa_bus_reserved = bus_reserved; /* Populate the resource list */ r_size = size - bus_reserved; sa->sa_rid = resource_list_add_next(&dinfo->resources, SYS_RES_MEMORY, base, base + (r_size - 1), r_size); - /* Append to target port */ - STAILQ_INSERT_TAIL(&port->sp_addrs, sa, sa_link); - port->sp_num_addrs++; - return (0); } /** * Deallocate the given device info structure and any associated resources. * * @param dev The requesting bus device. * @param dinfo Device info to be deallocated. */ void siba_free_dinfo(device_t dev, struct siba_devinfo *dinfo) { - siba_release_port(&dinfo->device_port); - resource_list_free(&dinfo->resources); /* Free all mapped configuration blocks */ for (u_int i = 0; i < nitems(dinfo->cfg); i++) { if (dinfo->cfg[i] == NULL) continue; bhnd_release_resource(dev, SYS_RES_MEMORY, dinfo->cfg_rid[i], dinfo->cfg[i]); dinfo->cfg[i] = NULL; dinfo->cfg_rid[i] = -1; } free(dinfo, M_BHND); } /** * Return the core-enumeration-relative offset for the @p addrspace * SIBA_R0_ADMATCH* register. * * @param addrspace The address space index. * * @retval non-zero success * @retval 0 the given @p addrspace index is not supported. */ u_int siba_admatch_offset(uint8_t addrspace) { switch (addrspace) { case 0: return SB0_REG_ABS(SIBA_CFG0_ADMATCH0); case 1: return SB0_REG_ABS(SIBA_CFG0_ADMATCH1); case 2: return SB0_REG_ABS(SIBA_CFG0_ADMATCH2); case 3: return SB0_REG_ABS(SIBA_CFG0_ADMATCH3); default: return (0); } } /** * Parse a SIBA_R0_ADMATCH* register. * * @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. * * @retval 0 success * @retval non-zero a parse error occurred. */ int siba_parse_admatch(uint32_t am, uint32_t *addr, uint32_t *size) { 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); break; case 1: *addr = am & SIBA_AM_BASE1_MASK; *size = 1 << (SIBA_REG_GET(am, AM_ADINT1) + 1); break; case 2: *addr = am & SIBA_AM_BASE2_MASK; *size = 1 << (SIBA_REG_GET(am, AM_ADINT2) + 1); break; default: return (EINVAL); } return (0); } Index: head/sys/dev/bhnd/siba/sibareg.h =================================================================== --- head/sys/dev/bhnd/siba/sibareg.h (revision 301971) +++ head/sys/dev/bhnd/siba/sibareg.h (revision 301972) @@ -1,266 +1,263 @@ /*- * Copyright (c) 2015 Landon Fuller * Copyright (c) 2010 Broadcom Corporation * * This file was derived from the sbconfig.h header distributed with * Broadcom's initial brcm80211 Linux driver release, as * contributed to the Linux staging repository. * * Permission to use, copy, modify, and/or distribute this software for any * purpose with or without fee is hereby granted, provided that the above * copyright notice and this permission notice appear in all copies. * * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY * SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION * OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN * CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. * * $FreeBSD$ */ #ifndef _BHND_SIBA_SIBAREG_ #define _BHND_SIBA_SIBAREG_ #include /* * Broadcom SIBA Configuration Space Registers. * * Backplane configuration registers common to siba(4) core register * blocks. */ /** * Extract a config attribute by applying _MASK and _SHIFT defines. * * @param _reg The register value containing the desired attribute * @param _attr The BCMA EROM attribute name (e.g. ENTRY_ISVALID), to be * concatenated with the `SB` prefix and `_MASK`/`_SHIFT` suffixes. */ #define SIBA_REG_GET(_entry, _attr) \ ((_entry & SIBA_ ## _attr ## _MASK) \ >> SIBA_ ## _attr ## _SHIFT) #define SIBA_ENUM_ADDR BHND_DEFAULT_CHIPC_ADDR /**< enumeration space */ #define SIBA_ENUM_SIZE 0x00100000 /**< size of the enumeration space */ #define SIBA_CORE_SIZE BHND_DEFAULT_CORE_SIZE /**< per-core register block size */ #define SIBA_MAX_CORES \ (SIBA_ENUM_SIZE/SIBA_CORE_SIZE) /**< Maximum number of cores */ -#define SIBA_ADDRSPACE_CORE 0 /**< address space identifier of the - core enumeration block. */ - /**< Evaluates to the bus address of the @p idx core register block */ #define SIBA_CORE_ADDR(idx) \ (SIBA_ENUM_ADDR + ((idx) * SIBA_CORE_SIZE)) /* * Sonics configuration registers are mapped to each core's enumeration * space, at the end of the 4kb device register block, in reverse * order: * * [0x0000-0x0dff] core registers * [0x0e00-0x0eff] SIBA_R1 registers (sonics >= 2.3) * [0x0f00-0x0fff] SIBA_R0 registers */ #define SIBA_CFG0_OFFSET 0xf00 /**< first configuration block */ #define SIBA_CFG1_OFFSET 0xe00 /**< second configuration block (sonics >= 2.3) */ #define SIBA_CFG_SIZE 0x100 /**< cfg register block size */ /* Return the SIBA_CORE_ADDR-relative offset for a SIBA_CFG* register. */ #define SB0_REG_ABS(off) ((off) + SIBA_CFG0_OFFSET) #define SB1_REG_ABS(off) ((off) + SIBA_CFG1_OFFSET) /* SIBA_CFG0 registers */ #define SIBA_CFG0_IPSFLAG 0x08 /**< initiator port ocp slave flag */ #define SIBA_CFG0_TPSFLAG 0x18 /**< target port ocp slave flag */ #define SIBA_CFG0_TMERRLOGA 0x48 /**< sonics >= 2.3 */ #define SIBA_CFG0_TMERRLOG 0x50 /**< sonics >= 2.3 */ #define SIBA_CFG0_ADMATCH3 0x60 /**< address match3 */ #define SIBA_CFG0_ADMATCH2 0x68 /**< address match2 */ #define SIBA_CFG0_ADMATCH1 0x70 /**< address match1 */ #define SIBA_CFG0_IMSTATE 0x90 /**< initiator agent state */ #define SIBA_CFG0_INTVEC 0x94 /**< interrupt mask */ #define SIBA_CFG0_TMSTATELOW 0x98 /**< target state */ #define SIBA_CFG0_TMSTATEHIGH 0x9c /**< target state */ #define SIBA_CFG0_BWA0 0xa0 /**< bandwidth allocation table0 */ #define SIBA_CFG0_IMCONFIGLOW 0xa8 /**< initiator configuration */ #define SIBA_CFG0_IMCONFIGHIGH 0xac /**< initiator configuration */ #define SIBA_CFG0_ADMATCH0 0xb0 /**< address match0 */ #define SIBA_CFG0_TMCONFIGLOW 0xb8 /**< target configuration */ #define SIBA_CFG0_TMCONFIGHIGH 0xbc /**< target configuration */ #define SIBA_CFG0_BCONFIG 0xc0 /**< broadcast configuration */ #define SIBA_CFG0_BSTATE 0xc8 /**< broadcast state */ #define SIBA_CFG0_ACTCNFG 0xd8 /**< activate configuration */ #define SIBA_CFG0_FLAGST 0xe8 /**< current sbflags */ #define SIBA_CFG0_IDLOW 0xf8 /**< identification */ #define SIBA_CFG0_IDHIGH 0xfc /**< identification */ /* SIBA_CFG1 registers (sonics >= 2.3) */ #define SIBA_CFG1_IMERRLOGA 0xa8 /**< (sonics >= 2.3) */ #define SIBA_CFG1_IMERRLOG 0xb0 /**< sbtmerrlog (sonics >= 2.3) */ #define SIBA_CFG1_TMPORTCONNID0 0xd8 /**< sonics >= 2.3 */ #define SIBA_CFG1_TMPORTLOCK0 0xf8 /**< sonics >= 2.3 */ /* sbipsflag */ #define SIBA_IPS_INT1_MASK 0x3f /* which sbflags get routed to mips interrupt 1 */ #define SIBA_IPS_INT1_SHIFT 0 #define SIBA_IPS_INT2_MASK 0x3f00 /* which sbflags get routed to mips interrupt 2 */ #define SIBA_IPS_INT2_SHIFT 8 #define SIBA_IPS_INT3_MASK 0x3f0000 /* which sbflags get routed to mips interrupt 3 */ #define SIBA_IPS_INT3_SHIFT 16 #define SIBA_IPS_INT4_MASK 0x3f000000 /* which sbflags get routed to mips interrupt 4 */ #define SIBA_IPS_INT4_SHIFT 24 /* sbtpsflag */ #define SIBA_TPS_NUM0_MASK 0x3f /* interrupt sbFlag # generated by this core */ #define SIBA_TPS_F0EN0 0x40 /* interrupt is always sent on the backplane */ /* sbtmerrlog */ #define SIBA_TMEL_CM 0x00000007 /* command */ #define SIBA_TMEL_CI 0x0000ff00 /* connection id */ #define SIBA_TMEL_EC 0x0f000000 /* error code */ #define SIBA_TMEL_ME 0x80000000 /* multiple error */ /* sbimstate */ #define SIBA_IM_PC 0xf /* pipecount */ #define SIBA_IM_AP_MASK 0x30 /* arbitration policy */ #define SIBA_IM_AP_BOTH 0x00 /* use both timeslaces and token */ #define SIBA_IM_AP_TS 0x10 /* use timesliaces only */ #define SIBA_IM_AP_TK 0x20 /* use token only */ #define SIBA_IM_AP_RSV 0x30 /* reserved */ #define SIBA_IM_IBE 0x20000 /* inbanderror */ #define SIBA_IM_TO 0x40000 /* timeout */ #define SIBA_IM_BY 0x01800000 /* busy (sonics >= 2.3) */ #define SIBA_IM_RJ 0x02000000 /* reject (sonics >= 2.3) */ /* sbtmstatelow */ #define SIBA_TML_RESET 0x0001 /* reset */ #define SIBA_TML_REJ_MASK 0x0006 /* reject field */ #define SIBA_TML_REJ 0x0002 /* reject */ #define SIBA_TML_TMPREJ 0x0004 /* temporary reject, for error recovery */ #define SIBA_TML_SICF_SHIFT 16 /* Shift to locate the SI control flags in sbtml */ /* sbtmstatehigh */ #define SIBA_TMH_SERR 0x0001 /* serror */ #define SIBA_TMH_INT 0x0002 /* interrupt */ #define SIBA_TMH_BUSY 0x0004 /* busy */ #define SIBA_TMH_TO 0x0020 /* timeout (sonics >= 2.3) */ #define SIBA_TMH_SISF_SHIFT 16 /* Shift to locate the SI status flags in sbtmh */ /* sbbwa0 */ #define SIBA_BWA_TAB0_MASK 0xffff /* lookup table 0 */ #define SIBA_BWA_TAB1_MASK 0xffff /* lookup table 1 */ #define SIBA_BWA_TAB1_SHIFT 16 /* sbimconfiglow */ #define SIBA_IMCL_STO_MASK 0x7 /* service timeout */ #define SIBA_IMCL_RTO_MASK 0x70 /* request timeout */ #define SIBA_IMCL_RTO_SHIFT 4 #define SIBA_IMCL_CID_MASK 0xff0000 /* connection id */ #define SIBA_IMCL_CID_SHIFT 16 /* sbimconfighigh */ #define SIBA_IMCH_IEM_MASK 0xc /* inband error mode */ #define SIBA_IMCH_TEM_MASK 0x30 /* timeout error mode */ #define SIBA_IMCH_TEM_SHIFT 4 #define SIBA_IMCH_BEM_MASK 0xc0 /* bus error mode */ #define SIBA_IMCH_BEM_SHIFT 6 -/* sbadmatch0 */ +/* sbadmatch0-4 */ #define SIBA_AM_TYPE_MASK 0x3 /* address type */ #define SIBA_AM_TYPE_SHIFT 0x0 #define SIBA_AM_AD64 0x4 /* reserved */ #define SIBA_AM_ADINT0_MASK 0xf8 /* type0 size */ #define SIBA_AM_ADINT0_SHIFT 3 #define SIBA_AM_ADINT1_MASK 0x1f8 /* type1 size */ #define SIBA_AM_ADINT1_SHIFT 3 #define SIBA_AM_ADINT2_MASK 0x1f8 /* type2 size */ #define SIBA_AM_ADINT2_SHIFT 3 #define SIBA_AM_ADEN 0x400 /* enable */ #define SIBA_AM_ADNEG 0x800 /* negative decode */ #define SIBA_AM_BASE0_MASK 0xffffff00 /* type0 base address */ #define SIBA_AM_BASE0_SHIFT 8 #define SIBA_AM_BASE1_MASK 0xfffff000 /* type1 base address for the core */ #define SIBA_AM_BASE1_SHIFT 12 #define SIBA_AM_BASE2_MASK 0xffff0000 /* type2 base address for the core */ #define SIBA_AM_BASE2_SHIFT 16 /* sbtmconfiglow */ #define SIBA_TMCL_CD_MASK 0xff /* clock divide */ #define SIBA_TMCL_CO_MASK 0xf800 /* clock offset */ #define SIBA_TMCL_CO_SHIFT 11 #define SIBA_TMCL_IF_MASK 0xfc0000 /* interrupt flags */ #define SIBA_TMCL_IF_SHIFT 18 #define SIBA_TMCL_IM_MASK 0x3000000 /* interrupt mode */ #define SIBA_TMCL_IM_SHIFT 24 /* sbtmconfighigh */ #define SIBA_TMCH_BM_MASK 0x3 /* busy mode */ #define SIBA_TMCH_RM_MASK 0x3 /* retry mode */ #define SIBA_TMCH_RM_SHIFT 2 #define SIBA_TMCH_SM_MASK 0x30 /* stop mode */ #define SIBA_TMCH_SM_SHIFT 4 #define SIBA_TMCH_EM_MASK 0x300 /* sb error mode */ #define SIBA_TMCH_EM_SHIFT 8 #define SIBA_TMCH_IM_MASK 0xc00 /* int mode */ #define SIBA_TMCH_IM_SHIFT 10 /* sbbconfig */ #define SIBA_BC_LAT_MASK 0x3 /* sb latency */ #define SIBA_BC_MAX0_MASK 0xf0000 /* maxccntr0 */ #define SIBA_BC_MAX0_SHIFT 16 #define SIBA_BC_MAX1_MASK 0xf00000 /* maxccntr1 */ #define SIBA_BC_MAX1_SHIFT 20 /* sbbstate */ #define SIBA_BS_SRD 0x1 /* st reg disable */ #define SIBA_BS_HRD 0x2 /* hold reg disable */ /* sbidlow */ #define SIBA_IDL_CS_MASK 0x3 /* config space */ #define SIBA_IDL_CS_SHIFT 0 #define SIBA_IDL_NRADDR_MASK 0x38 /* # address ranges supported */ #define SIBA_IDL_NRADDR_SHIFT 3 #define SIBA_IDL_SYNCH 0x40 /* sync */ #define SIBA_IDL_INIT 0x80 /* initiator */ #define SIBA_IDL_MINLAT_MASK 0xf00 /* minimum backplane latency */ #define SIBA_IDL_MINLAT_SHIFT 8 #define SIBA_IDL_MAXLAT_MASK 0xf000 /* maximum backplane latency */ #define SIBA_IDL_MAXLAT_SHIFT 12 #define SIBA_IDL_FIRST_MASK 0x10000 /* this initiator is first */ #define SIBA_IDL_FIRST_SHIFT 16 #define SIBA_IDL_CW_MASK 0xc0000 /* cycle counter width */ #define SIBA_IDL_CW_SHIFT 18 #define SIBA_IDL_TP_MASK 0xf00000 /* target ports */ #define SIBA_IDL_TP_SHIFT 20 #define SIBA_IDL_IP_MASK 0xf000000 /* initiator ports */ #define SIBA_IDL_IP_SHIFT 24 #define SIBA_IDL_SBREV_MASK 0xf0000000 /* sonics backplane revision code */ #define SIBA_IDL_SBREV_SHIFT 28 #define SIBA_IDL_SBREV_2_2 0x0 /* version 2.2 or earlier */ #define SIBA_IDL_SBREV_2_3 0x1 /* version 2.3 */ /* sbidhigh */ #define SIBA_IDH_RC_MASK 0x000f /* revision code */ #define SIBA_IDH_RCE_MASK 0x7000 /* revision code extension field */ #define SIBA_IDH_RCE_SHIFT 8 #define SIBA_IDH_DEVICE_MASK 0x8ff0 /* core code */ #define SIBA_IDH_DEVICE_SHIFT 4 #define SIBA_IDH_VENDOR_MASK 0xffff0000 /* vendor code */ #define SIBA_IDH_VENDOR_SHIFT 16 #define SIBA_IDH_CORE_REV(sbidh) \ (SIBA_REG_GET((sbidh), IDH_RCE) | ((sbidh) & SIBA_IDH_RC_MASK)) #define SIBA_COMMIT 0xfd8 /* update buffered registers value */ #endif /* _BHND_SIBA_SIBAREG_ */ Index: head/sys/dev/bhnd/siba/sibavar.h =================================================================== --- head/sys/dev/bhnd/siba/sibavar.h (revision 301971) +++ head/sys/dev/bhnd/siba/sibavar.h (revision 301972) @@ -1,156 +1,155 @@ /*- * Copyright (c) 2015 Landon Fuller * 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, * without modification. * 2. Redistributions in binary form must reproduce at minimum a disclaimer * similar to the "NO WARRANTY" disclaimer below ("Disclaimer") and any * redistribution must be conditioned upon including a substantially * similar Disclaimer requirement for further binary redistribution. * * NO WARRANTY * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT * LIMITED TO, THE IMPLIED WARRANTIES OF NONINFRINGEMENT, MERCHANTIBILITY * AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL * THE COPYRIGHT HOLDERS OR CONTRIBUTORS BE LIABLE FOR 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 DAMAGES. * * $FreeBSD$ */ #ifndef _SIBA_SIBAVAR_H_ #define _SIBA_SIBAVAR_H_ #include #include #include #include #include #include "siba.h" /* * Internal definitions shared by siba(4) driver implementations. */ struct siba_addrspace; struct siba_devinfo; -struct siba_port; struct siba_core_id; int siba_probe(device_t dev); int siba_attach(device_t dev); int siba_detach(device_t dev); int siba_resume(device_t dev); int siba_suspend(device_t dev); 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, const struct bhnd_chipid *chipid); struct siba_devinfo *siba_alloc_dinfo(device_t dev, const struct siba_core_id *core_id); void siba_free_dinfo(device_t dev, struct siba_devinfo *dinfo); -struct siba_port *siba_dinfo_get_port(struct siba_devinfo *dinfo, - bhnd_port_type port_type, u_int port_num); +u_int siba_addrspace_port_count(struct siba_devinfo *dinfo); +u_int siba_addrspace_region_count(struct siba_devinfo *dinfo, + u_int port); -struct siba_addrspace *siba_find_port_addrspace(struct siba_port *port, - uint8_t sid); +u_int siba_addrspace_port(u_int addrspace); +u_int siba_addrspace_region(u_int addrspace); +bool siba_is_port_valid(struct siba_devinfo *dinfo, + bhnd_port_type type, u_int port); + +struct siba_addrspace *siba_find_addrspace(struct siba_devinfo *dinfo, + bhnd_port_type type, u_int port, u_int region); + int siba_append_dinfo_region(struct siba_devinfo *dinfo, - bhnd_port_type port_type, u_int port_num, - u_int region_num, uint8_t sid, uint32_t base, - uint32_t size, uint32_t bus_reserved); + 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); + /* Sonics configuration register blocks */ #define SIBA_CFG_NUM_2_2 1 /**< sonics <= 2.2 maps SIBA_CFG0. */ #define SIBA_CFG_NUM_2_3 2 /**< sonics <= 2.3 maps SIBA_CFG0 and SIBA_CFG1 */ -#define SIBA_CFG_NUM_MAX SIBA_CFG_NUM_2_3 /**< maximum number of supported config +#define SIBA_MAX_CFG SIBA_CFG_NUM_2_3 /**< maximum number of supported config register blocks */ +/* Sonics/OCP address space mappings */ +#define SIBA_CORE_ADDRSPACE 0 /**< Address space mapping the primary + device registers */ + +#define SIBA_MAX_ADDRSPACE 4 /**< Maximum number of Sonics/OCP + * address space mappings for a + * single core. */ + +/* bhnd(4) (port,region) representation of siba address space mappings */ +#define SIBA_MAX_PORT 2 /**< maximum number of advertised + * bhnd(4) ports */ + /** siba(4) address space descriptor */ struct siba_addrspace { uint32_t sa_base; /**< base address */ uint32_t sa_size; /**< size */ - u_int sa_region_num; /**< bhnd region id */ - uint8_t sa_sid; /**< siba-assigned address space ID */ int sa_rid; /**< bus resource id */ uint32_t sa_bus_reserved;/**< number of bytes at high end of * address space reserved for the bus */ - - STAILQ_ENTRY(siba_addrspace) sa_link; }; -/** siba(4) port descriptor */ -struct siba_port { - bhnd_port_type sp_type; /**< port type */ - u_int sp_num; /**< port number */ - u_int sp_num_addrs; /**< number of address space mappings */ - - STAILQ_HEAD(, siba_addrspace) sp_addrs; /**< address spaces mapped to this port */ -}; - /** * 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 */ }; /** * siba(4) per-device info */ struct siba_devinfo { struct resource_list resources; /**< per-core memory regions. */ struct siba_core_id core_id; /**< core identification info */ + struct siba_addrspace addrspace[SIBA_MAX_ADDRSPACE]; /**< memory map descriptors */ - struct siba_port device_port; /**< device port holding ownership - * of all siba address space - * entries for this core. */ - - /** SIBA_CFG* register blocks */ - struct bhnd_resource *cfg[SIBA_CFG_NUM_MAX]; - - /** SIBA_CFG* resource IDs */ - int cfg_rid[SIBA_CFG_NUM_MAX]; + struct bhnd_resource *cfg[SIBA_MAX_CFG]; /**< SIBA_CFG_* registers */ + int cfg_rid[SIBA_MAX_CFG]; /**< SIBA_CFG_* resource IDs */ }; /** siba(4) per-instance state */ struct siba_softc { struct bhnd_softc bhnd_sc; /**< bhnd state */ device_t dev; /**< siba device */ device_t hostb_dev; /**< host bridge core, or NULL */ }; #endif /* _SIBA_SIBAVAR_H_ */