diff options
| author | Landon J. Fuller <landonf@FreeBSD.org> | 2016-09-04 00:58:19 +0000 |
|---|---|---|
| committer | Landon J. Fuller <landonf@FreeBSD.org> | 2016-09-04 00:58:19 +0000 |
| commit | 111d7cb2e34311625c8fa8791a355e58bf233a06 (patch) | |
| tree | 23cc3ee73bbb5086a3fe7d37728a2a99d72c6606 /sys/dev/bhnd/siba | |
| parent | 3da0f3c9ae77569dee5f771b6ea62a866e51228c (diff) | |
Notes
Diffstat (limited to 'sys/dev/bhnd/siba')
| -rw-r--r-- | sys/dev/bhnd/siba/siba.c | 234 | ||||
| -rw-r--r-- | sys/dev/bhnd/siba/siba_bhndb.c | 47 | ||||
| -rw-r--r-- | sys/dev/bhnd/siba/siba_erom.c | 394 | ||||
| -rw-r--r-- | sys/dev/bhnd/siba/siba_nexus.c | 19 | ||||
| -rw-r--r-- | sys/dev/bhnd/siba/sibavar.h | 9 |
5 files changed, 390 insertions, 313 deletions
diff --git a/sys/dev/bhnd/siba/siba.c b/sys/dev/bhnd/siba/siba.c index cb1d6f520cfd1..552c1571209d7 100644 --- a/sys/dev/bhnd/siba/siba.c +++ b/sys/dev/bhnd/siba/siba.c @@ -44,6 +44,12 @@ __FBSDID("$FreeBSD$"); #include "sibareg.h" #include "sibavar.h" +static bhnd_erom_class_t * +siba_get_erom_class(driver_t *driver) +{ + return (&siba_erom_parser); +} + int siba_probe(device_t dev) { @@ -51,84 +57,29 @@ siba_probe(device_t dev) return (BUS_PROBE_DEFAULT); } +/** + * Default siba(4) bus driver implementation of DEVICE_ATTACH(). + * + * This implementation initializes internal siba(4) state and performs + * bus enumeration, and must be called by subclassing drivers in + * DEVICE_ATTACH() before any other bus methods. + */ 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))) + /* Enumerate children */ + if ((error = siba_add_children(dev))) { + device_delete_children(dev); return (error); - - for (int i = 0; i < ndevs; i++) { - struct siba_addrspace *addrspace; - - 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 */ - 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_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)); + return (0); } int @@ -213,15 +164,6 @@ siba_get_resource_list(device_t dev, device_t 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) { @@ -492,6 +434,64 @@ siba_register_addrspaces(device_t dev, struct siba_devinfo *di, return (0); } +/** + * Map per-core configuration blocks for @p dinfo. + * + * @param dev The siba bus device. + * @param dinfo The device info instance on which to map all per-core + * configuration blocks. + */ +static int +siba_map_cfg_resources(device_t dev, struct siba_devinfo *dinfo) +{ + struct siba_addrspace *addrspace; + rman_res_t r_start, r_count, r_end; + uint8_t num_cfg; + + num_cfg = dinfo->core_id.num_cfg_blocks; + if (num_cfg > SIBA_MAX_CFG) { + device_printf(dev, "config block count %hhu out of range\n", + num_cfg); + return (ENXIO); + } + + /* Fetch the core register address space */ + addrspace = siba_find_addrspace(dinfo, BHND_PORT_DEVICE, 0, 0); + if (addrspace == NULL) { + device_printf(dev, "missing device registers\n"); + return (ENXIO); + } + + /* + * Map the per-core configuration blocks + */ + for (uint8_t i = 0; i < num_cfg; i++) { + /* 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 -= i * SIBA_CFG_SIZE; + + r_count = SIBA_CFG_SIZE; + r_end = r_start + r_count - 1; + + /* Allocate the config resource */ + dinfo->cfg_rid[i] = SIBA_CFG_RID(dinfo, i); + dinfo->cfg[i] = BHND_BUS_ALLOC_RESOURCE(dev, dev, + SYS_RES_MEMORY, &dinfo->cfg_rid[i], r_start, r_end, + r_count, RF_ACTIVE); + + if (dinfo->cfg[i] == NULL) { + device_printf(dev, "failed to allocate SIBA_CFG%hhu\n", + i); + return (ENXIO); + } + } + + return (0); +} + + static struct bhnd_devinfo * siba_alloc_bhnd_dinfo(device_t dev) { @@ -510,73 +510,22 @@ siba_free_bhnd_dinfo(device_t dev, struct bhnd_devinfo *dinfo) * 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) +siba_add_children(device_t dev) { - struct bhnd_chipid ccid; - struct bhnd_core_info *cores; - struct siba_devinfo *dinfo; - struct bhnd_resource *r; - int rid; - int error; + const struct bhnd_chipid *chipid; + struct bhnd_core_info *cores; + struct siba_devinfo *dinfo; + struct bhnd_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 = bhnd_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 = bhnd_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 = bhnd_bus_read_4(r, CHIPC_ID); - ccid = bhnd_parse_chipid(ccreg, SIBA_ENUM_ADDR); - - /* Fix up the core count */ - error = bhnd_chipid_fixed_ncores(&ccid, ccrev, &ccid.ncores); - if (error) { - device_printf(dev, "unable to determine core count for " - "chipset 0x%hx\n", ccid.chip_id); - goto cleanup; - } - chipid = &ccid; - bhnd_release_resource(dev, SYS_RES_MEMORY, rid, r); - } + chipid = BHND_BUS_GET_CHIPID(dev, dev); /* Allocate our temporary core table and enumerate all cores */ cores = malloc(sizeof(*cores) * chipid->ncores, M_BHND, M_NOWAIT); @@ -636,14 +585,19 @@ siba_add_children(device_t dev, const struct bhnd_chipid *chipid) if ((error = siba_register_addrspaces(dev, dinfo, r))) goto cleanup; + /* Release our resource covering the register blocks + * we're about to map */ + bhnd_release_resource(dev, SYS_RES_MEMORY, rid, r); + r = NULL; + + /* Map the core's config blocks */ + if ((error = siba_map_cfg_resources(dev, dinfo))) + goto cleanup; + /* 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 */ - bhnd_release_resource(dev, SYS_RES_MEMORY, rid, r); - r = NULL; /* Issue bus callback for fully initialized child. */ BHND_BUS_CHILD_ADDED(dev, child); @@ -673,7 +627,7 @@ static device_method_t siba_methods[] = { DEVMETHOD(bus_get_resource_list, siba_get_resource_list), /* BHND interface */ - DEVMETHOD(bhnd_bus_find_hostb_device, siba_find_hostb_device), + DEVMETHOD(bhnd_bus_get_erom_class, siba_get_erom_class), DEVMETHOD(bhnd_bus_alloc_devinfo, siba_alloc_bhnd_dinfo), DEVMETHOD(bhnd_bus_free_devinfo, siba_free_bhnd_dinfo), DEVMETHOD(bhnd_bus_reset_core, siba_reset_core), diff --git a/sys/dev/bhnd/siba/siba_bhndb.c b/sys/dev/bhnd/siba/siba_bhndb.c index 6803064e331ca..6ba050420082c 100644 --- a/sys/dev/bhnd/siba/siba_bhndb.c +++ b/sys/dev/bhnd/siba/siba_bhndb.c @@ -101,35 +101,28 @@ siba_bhndb_probe(device_t dev) static int siba_bhndb_attach(device_t dev) { - struct siba_softc *sc; - const struct bhnd_chipid *chipid; - int error; + struct siba_softc *sc; + int error; sc = device_get_softc(dev); - /* Enumerate our children. */ - chipid = BHNDB_GET_CHIPID(device_get_parent(dev), dev); - if ((error = siba_add_children(dev, chipid))) - return (error); - - /* Initialize full bridge configuration */ - error = BHNDB_INIT_FULL_CONFIG(device_get_parent(dev), dev, - bhndb_siba_priority_table); - if (error) - return (error); - - /* Ask our parent bridge to find the corresponding bridge core */ - sc->hostb_dev = BHNDB_FIND_HOSTB_DEVICE(device_get_parent(dev), dev); - - /* Call our superclass' implementation */ + /* Perform initial attach and enumerate our children. */ if ((error = siba_attach(dev))) - return (error); + goto failed; - /* Apply attach/resume work-arounds */ + /* Apply attach/resume workarounds before any child drivers attach */ if ((error = siba_bhndb_wars_hwup(sc))) - return (error); + goto failed; + + /* Delegate remainder to standard bhnd method implementation */ + if ((error = bhnd_generic_attach(dev))) + goto failed; return (0); + +failed: + device_delete_children(dev); + return (error); } static int @@ -222,11 +215,15 @@ static int siba_bhndb_wars_pcie_clear_d11_timeout(struct siba_softc *sc) { struct siba_devinfo *dinfo; + device_t hostb_dev; device_t d11; uint32_t imcfg; /* Only applies when bridged by PCIe */ - if (bhnd_get_class(sc->hostb_dev) != BHND_DEVCLASS_PCIE) + if ((hostb_dev = bhnd_find_hostb_device(sc->dev)) == NULL) + return (ENXIO); + + if (bhnd_get_class(hostb_dev) != BHND_DEVCLASS_PCIE) return (0); /* Only applies if there's a D11 core */ @@ -256,10 +253,14 @@ siba_bhndb_wars_pcie_clear_d11_timeout(struct siba_softc *sc) static int siba_bhndb_wars_hwup(struct siba_softc *sc) { + device_t hostb_dev; uint32_t quirks; int error; - quirks = bhnd_device_quirks(sc->hostb_dev, bridge_devs, + if ((hostb_dev = bhnd_find_hostb_device(sc->dev)) == NULL) + return (ENXIO); + + quirks = bhnd_device_quirks(hostb_dev, bridge_devs, sizeof(bridge_devs[0])); if (quirks & SIBA_QUIRK_PCIE_D11_SB_TIMEOUT) { diff --git a/sys/dev/bhnd/siba/siba_erom.c b/sys/dev/bhnd/siba/siba_erom.c index 821a6d7efad7e..1c85c1ed40b2c 100644 --- a/sys/dev/bhnd/siba/siba_erom.c +++ b/sys/dev/bhnd/siba/siba_erom.c @@ -46,117 +46,110 @@ __FBSDID("$FreeBSD$"); #include "sibavar.h" struct siba_erom; +struct siba_erom_io; -static int siba_erom_init_static(bhnd_erom_t *erom, bus_space_tag_t bst, - bus_space_handle_t bsh); -static void siba_erom_fini(bhnd_erom_t *erom); -static uint32_t siba_erom_read_4(struct siba_erom *sc, u_int core_idx, - bus_size_t offset); -static int siba_erom_read_chipid(struct siba_erom *sc, - bus_addr_t enum_addr, struct bhnd_chipid *cid); +static int siba_eio_init(struct siba_erom_io *io, + device_t parent, struct bhnd_resource *res, + int rid, bus_size_t offset, u_int ncores); -struct siba_erom { - struct bhnd_erom obj; +static int siba_eio_init_static(struct siba_erom_io *io, + bus_space_tag_t bst, bus_space_handle_t bsh, + bus_size_t offset, u_int ncores); + +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_chipid(struct siba_erom_io *io, + bus_addr_t enum_addr, + struct bhnd_chipid *cid); + +/** + * SIBA EROM generic I/O context + */ +struct siba_erom_io { u_int ncores; /**< core count */ + bus_size_t offset; /**< base read offset */ /* resource state */ device_t dev; /**< parent dev to use for resource allocations, - or NULL if initialized with bst/bsh */ - struct bhnd_resource *res; /**< siba bus mapping, or NULL */ - int rid; /**< siba bus maping resource ID */ + or NULL if unavailable. */ + struct bhnd_resource *res; /**< memory resource, or NULL */ + int rid; /**< memory resource ID */ /* bus tag state */ - bus_space_tag_t bst; /**< chipc bus tag */ - bus_space_handle_t bsh; /**< chipc bus handle */ + bus_space_tag_t bst; /**< bus space tag */ + bus_space_handle_t bsh; /**< bus space handle */ +}; + +/** + * SIBA EROM per-instance state. + */ +struct siba_erom { + struct bhnd_erom obj; + struct siba_erom_io io; /**< i/o context */ }; -#define EROM_LOG(sc, fmt, ...) do { \ - if (sc->dev != NULL) { \ - device_printf(sc->dev, "%s: " fmt, __FUNCTION__, \ +#define EROM_LOG(io, fmt, ...) do { \ + if (io->dev != NULL) { \ + device_printf(io->dev, "%s: " fmt, __FUNCTION__, \ ##__VA_ARGS__); \ } else { \ printf("%s: " fmt, __FUNCTION__, ##__VA_ARGS__); \ } \ } while(0) -static uint32_t -siba_erom_read_4(struct siba_erom *sc, u_int core_idx, bus_size_t offset) -{ - bus_size_t core_offset; - - /* Sanity check core index and offset */ - if (core_idx >= sc->ncores) - panic("core index %u out of range (ncores=%u)", core_idx, - sc->ncores); - - if (offset > SIBA_CORE_SIZE - sizeof(uint32_t)) - panic("invalid core offset %#jx", (uintmax_t)offset); - - /* Perform read */ - core_offset = SIBA_CORE_OFFSET(core_idx) + offset; - if (sc->res != NULL) - return (bhnd_bus_read_4(sc->res, core_offset)); - else - return (bus_space_read_4(sc->bst, sc->bsh, core_offset)); -} - -/** Fetch and parse a siba core's identification registers */ -static struct siba_core_id -siba_erom_parse_core_id(struct siba_erom *sc, u_int core_idx, int unit) -{ - uint32_t idhigh, idlow; - - idhigh = siba_erom_read_4(sc, core_idx, SB0_REG_ABS(SIBA_CFG0_IDHIGH)); - idlow = siba_erom_read_4(sc, core_idx, SB0_REG_ABS(SIBA_CFG0_IDLOW)); - - return (siba_parse_core_id(idhigh, idlow, core_idx, unit)); -} - -/** Fetch and parse the chip identification register */ static int -siba_erom_read_chipid(struct siba_erom *sc, bus_addr_t enum_addr, +siba_erom_probe_common(struct siba_erom_io *io, const struct bhnd_chipid *hint, struct bhnd_chipid *cid) { - struct siba_core_id ccid; uint32_t idreg; + int error; - /* Identify the chipcommon core */ - ccid = siba_erom_parse_core_id(sc, 0, 0); - if (ccid.core_info.vendor != BHND_MFGID_BCM || - ccid.core_info.device != BHND_COREID_CC) - { - EROM_LOG(sc, - "first core not chipcommon (vendor=%#hx, core=%#hx)\n", - ccid.core_info.vendor, ccid.core_info.device); - return (ENXIO); - } + /* Try using the provided hint. */ + if (hint != NULL) { + struct siba_core_id sid; - /* Identify the chipset */ - idreg = siba_erom_read_4(sc, 0, CHIPC_ID); - *cid = bhnd_parse_chipid(idreg, enum_addr); + /* Validate bus type */ + if (hint->chip_type != BHND_CHIPTYPE_SIBA) + return (ENXIO); - /* Fix up the core count in-place */ - return (bhnd_chipid_fixed_ncores(cid, ccid.core_info.hwrev, - &cid->ncores)); -} + /* + * Verify the first core's IDHIGH/IDLOW identification. + * + * The core must be a Broadcom core, but must *not* be + * a chipcommon core; those shouldn't be hinted. + * + * The first core on EXTIF-equipped devices varies, but on the + * BCM4710, it's a SDRAM core (0x803). + */ -static int -siba_erom_init_common(struct siba_erom *sc) -{ - struct bhnd_chipid cid; - int error; + sid = siba_eio_read_core_id(io, 0, 0); - /* There's always at least one core */ - sc->ncores = 1; + if (sid.core_info.vendor != BHND_MFGID_BCM) + return (ENXIO); - /* Identify the chipset */ - if ((error = siba_erom_read_chipid(sc, SIBA_ENUM_ADDR, &cid))) - return (error); + if (sid.core_info.device == BHND_COREID_CC) + return (EINVAL); - /* Verify the chip type */ - if (cid.chip_type != BHND_CHIPTYPE_SIBA) - return (ENXIO); + *cid = *hint; + } else { + /* Validate bus type */ + idreg = siba_eio_read_4(io, 0, CHIPC_ID); + if (CHIPC_GET_BITS(idreg, CHIPC_ID_BUS) != BHND_CHIPTYPE_SIBA) + return (ENXIO); + + /* Identify the chipset */ + if ((error = siba_eio_read_chipid(io, SIBA_ENUM_ADDR, cid))) + return (error); + + /* Verify the chip type */ + if (cid->chip_type != BHND_CHIPTYPE_SIBA) + return (ENXIO); + } /* * gcc hack: ensure bhnd_chipid.ncores cannot exceed SIBA_MAX_CORES @@ -165,91 +158,213 @@ siba_erom_init_common(struct siba_erom *sc) * if (cid.ncores > SIBA_MAX_CORES) * return (EINVAL) */ - _Static_assert((2^sizeof(cid.ncores)) <= SIBA_MAX_CORES, + _Static_assert((2^sizeof(cid->ncores)) <= SIBA_MAX_CORES, "ncores could result in over-read of backing resource"); - /* Update our core count */ - sc->ncores = cid.ncores; - return (0); } +/* SIBA implementation of BHND_EROM_PROBE() */ static int -siba_erom_init(bhnd_erom_t *erom, device_t parent, int rid, - bus_addr_t enum_addr) +siba_erom_probe(bhnd_erom_class_t *cls, struct bhnd_resource *res, + bus_size_t offset, const struct bhnd_chipid *hint, + struct bhnd_chipid *cid) { - struct siba_erom *sc = (struct siba_erom *)erom; + struct siba_erom_io io; + int error, rid; - sc->dev = parent; - sc->rid = rid; + rid = rman_get_rid(res->res); - sc->res = bhnd_alloc_resource(sc->dev, SYS_RES_MEMORY, &sc->rid, - enum_addr, enum_addr + SIBA_ENUM_SIZE -1, SIBA_ENUM_SIZE, - RF_ACTIVE|RF_SHAREABLE); - if (sc->res == NULL) - return (ENOMEM); + /* Initialize I/O context, assuming at least 1 core exists. */ + if ((error = siba_eio_init(&io, NULL, res, rid, offset, 1))) + return (error); - return (siba_erom_init_common(sc)); + return (siba_erom_probe_common(&io, hint, cid)); } +/* SIBA implementation of BHND_EROM_PROBE_STATIC() */ static int siba_erom_probe_static(bhnd_erom_class_t *cls, bus_space_tag_t bst, - bus_space_handle_t bsh, bus_addr_t paddr, struct bhnd_chipid *cid) + bus_space_handle_t bsh, bus_addr_t paddr, const struct bhnd_chipid *hint, + struct bhnd_chipid *cid) { - struct siba_erom sc; - uint32_t idreg; - uint8_t chip_type; + struct siba_erom_io io; int error; - idreg = bus_space_read_4(bst, bsh, CHIPC_ID); - chip_type = CHIPC_GET_BITS(idreg, CHIPC_ID_BUS); + /* Initialize I/O context, assuming at least 1 core exists. */ + if ((error = siba_eio_init_static(&io, bst, bsh, 0, 1))) + return (error); - if (chip_type != BHND_CHIPTYPE_SIBA) - return (ENXIO); + return (siba_erom_probe_common(&io, hint, cid)); +} - /* Initialize a static EROM instance that we can use to fetch - * the chip identifier */ - if ((error = siba_erom_init_static((bhnd_erom_t *)&sc, bst, bsh))) - return (error); +/* SIBA implementation of BHND_EROM_INIT() */ +static int +siba_erom_init(bhnd_erom_t *erom, const struct bhnd_chipid *cid, + device_t parent, int rid) +{ + struct siba_erom *sc; + struct bhnd_resource *res; + int error; + + sc = (struct siba_erom *)erom; + + /* Allocate backing resource */ + res = bhnd_alloc_resource(parent, SYS_RES_MEMORY, &rid, + cid->enum_addr, cid->enum_addr + SIBA_ENUM_SIZE -1, SIBA_ENUM_SIZE, + RF_ACTIVE|RF_SHAREABLE); + if (res == NULL) + return (ENOMEM); - /* Try to read the chip ID, clean up the static instance */ - error = siba_erom_read_chipid(&sc, paddr, cid); - siba_erom_fini((bhnd_erom_t *)&sc); + /* Initialize I/O context */ + error = siba_eio_init(&sc->io, parent, res, rid, 0x0, cid->ncores); if (error) - return (error); + bhnd_release_resource(parent, SYS_RES_MEMORY, rid, res); - return (BUS_PROBE_DEFAULT); + return (error); } +/* SIBA implementation of BHND_EROM_INIT_STATIC() */ static int -siba_erom_init_static(bhnd_erom_t *erom, bus_space_tag_t bst, - bus_space_handle_t bsh) +siba_erom_init_static(bhnd_erom_t *erom, const struct bhnd_chipid *cid, + bus_space_tag_t bst, bus_space_handle_t bsh) { - struct siba_erom *sc = (struct siba_erom *)erom; - - sc->dev = NULL; - sc->rid = -1; - sc->res = NULL; - sc->bst = bst; - sc->bsh = bsh; + struct siba_erom *sc; + + sc = (struct siba_erom *)erom; - return (siba_erom_init_common(sc)); + /* Initialize I/O context */ + return (siba_eio_init_static(&sc->io, bst, bsh, 0x0, cid->ncores)); } +/* SIBA implementation of BHND_EROM_FINI() */ static void siba_erom_fini(bhnd_erom_t *erom) { struct siba_erom *sc = (struct siba_erom *)erom; - if (sc->res != NULL) { - bhnd_release_resource(sc->dev, SYS_RES_MEMORY, sc->rid, - sc->res); + if (sc->io.res != NULL) { + bhnd_release_resource(sc->io.dev, SYS_RES_MEMORY, sc->io.rid, + sc->io.res); - sc->res = NULL; - sc->rid = -1; + sc->io.res = NULL; + sc->io.rid = -1; } } +/* Initialize siba_erom resource I/O context */ +static int +siba_eio_init(struct siba_erom_io *io, device_t parent, + struct bhnd_resource *res, int rid, bus_size_t offset, u_int ncores) +{ + io->dev = parent; + io->res = res; + io->rid = rid; + io->offset = offset; + io->ncores = ncores; + + return (0); +} + +/* Initialize siba_erom bus space I/O context */ +static int +siba_eio_init_static(struct siba_erom_io *io, bus_space_tag_t bst, + bus_space_handle_t bsh, bus_size_t offset, u_int ncores) +{ + io->res = NULL; + io->rid = -1; + io->bst = bst; + io->bsh = bsh; + io->offset = offset; + io->ncores = ncores; + + return (0); +} + +/** + * Read a 32-bit value from @p offset relative to the base address of + * the given @p core_idx. + * + * @param io EROM I/O context. + * @param core_idx Core index. + * @param offset Core register offset. + */ +static uint32_t +siba_eio_read_4(struct siba_erom_io *io, u_int core_idx, bus_size_t offset) +{ + bus_size_t core_offset; + + /* Sanity check core index and offset */ + if (core_idx >= io->ncores) + panic("core index %u out of range (ncores=%u)", core_idx, + io->ncores); + + if (offset > SIBA_CORE_SIZE - sizeof(uint32_t)) + panic("invalid core offset %#jx", (uintmax_t)offset); + + /* Perform read */ + core_offset = io->offset + SIBA_CORE_OFFSET(core_idx) + offset; + if (io->res != NULL) + return (bhnd_bus_read_4(io->res, core_offset)); + else + return (bus_space_read_4(io->bst, io->bsh, core_offset)); +} + +/** + * Read and parse identification registers for the given @p core_index. + * + * @param io EROM I/O context. + * @param core_idx The core index. + * @param unit The caller-specified unit number to be included in the return + * value. + */ +static struct siba_core_id +siba_eio_read_core_id(struct siba_erom_io *io, u_int core_idx, int unit) +{ + uint32_t idhigh, idlow; + + 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)); + + return (siba_parse_core_id(idhigh, idlow, core_idx, unit)); +} + +/** + * Read and parse the chip identification register from the ChipCommon core. + * + * @param io EROM I/O context. + * @param enum_addr The physical address mapped by @p io. + * @param cid On success, the parsed chip identifier. + */ +static int +siba_eio_read_chipid(struct siba_erom_io *io, bus_addr_t enum_addr, + struct bhnd_chipid *cid) +{ + struct siba_core_id ccid; + uint32_t idreg; + + /* Identify the chipcommon core */ + ccid = siba_eio_read_core_id(io, 0, 0); + if (ccid.core_info.vendor != BHND_MFGID_BCM || + ccid.core_info.device != BHND_COREID_CC) + { + if (bootverbose) { + EROM_LOG(io, "first core not chipcommon " + "(vendor=%#hx, core=%#hx)\n", ccid.core_info.vendor, + ccid.core_info.device); + } + return (ENXIO); + } + + /* Identify the chipset */ + idreg = siba_eio_read_4(io, 0, CHIPC_ID); + *cid = bhnd_parse_chipid(idreg, enum_addr); + + /* Fix up the core count in-place */ + return (bhnd_chipid_fixed_ncores(cid, ccid.core_info.hwrev, + &cid->ncores)); +} + static int siba_erom_lookup_core(bhnd_erom_t *erom, const struct bhnd_core_match *desc, struct bhnd_core_info *core) @@ -264,12 +379,12 @@ siba_erom_lookup_core(bhnd_erom_t *erom, const struct bhnd_core_match *desc, imatch.m.match.core_unit = 0; /* Locate the first matching core */ - for (u_int i = 0; i < sc->ncores; i++) { + for (u_int i = 0; i < sc->io.ncores; i++) { struct siba_core_id sid; struct bhnd_core_info ci; /* Read the core info */ - sid = siba_erom_parse_core_id(sc, i, 0); + sid = siba_eio_read_core_id(&sc->io, i, 0); ci = sid.core_info; /* Check for initial match */ @@ -278,7 +393,7 @@ 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_erom_parse_core_id(sc, i, 0); + sid = siba_eio_read_core_id(&sc->io, i, 0); /* Bump the unit number? */ if (sid.core_info.vendor == ci.vendor && @@ -319,7 +434,7 @@ siba_erom_lookup_core_addr(bhnd_erom_t *erom, const struct bhnd_core_match *desc return (error); /* Fetch full siba core ident */ - sid = siba_erom_parse_core_id(sc, core.core_idx, core.unit); + sid = siba_eio_read_core_id(&sc->io, core.core_idx, core.unit); /* Is port valid? */ if (!siba_is_port_valid(sid.num_addrspace, type, port)) @@ -343,7 +458,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_erom_read_4(sc, core.core_idx, am_offset); + am = siba_eio_read_4(&sc->io, core.core_idx, am_offset); if ((error = siba_parse_admatch(am, &am_addr, &am_size))) { printf("failed to decode address match register value 0x%x\n", @@ -371,19 +486,19 @@ siba_erom_get_core_table(bhnd_erom_t *erom, struct bhnd_core_info **cores, sc = (struct siba_erom *)erom; /* Allocate our core array */ - out = malloc(sizeof(*out) * sc->ncores, M_BHND, M_NOWAIT); + out = malloc(sizeof(*out) * sc->io.ncores, M_BHND, M_NOWAIT); if (out == NULL) return (ENOMEM); *cores = out; - *num_cores = sc->ncores; + *num_cores = sc->io.ncores; /* Enumerate all cores. */ - for (u_int i = 0; i < sc->ncores; i++) { + for (u_int i = 0; i < sc->io.ncores; i++) { struct siba_core_id sid; /* Read the core info */ - sid = siba_erom_parse_core_id(sc, i, 0); + sid = siba_eio_read_core_id(&sc->io, i, 0); out[i] = sid.core_info; /* Determine unit number */ @@ -405,6 +520,7 @@ siba_erom_free_core_table(bhnd_erom_t *erom, struct bhnd_core_info *cores) } static kobj_method_t siba_erom_methods[] = { + KOBJMETHOD(bhnd_erom_probe, siba_erom_probe), KOBJMETHOD(bhnd_erom_probe_static, siba_erom_probe_static), KOBJMETHOD(bhnd_erom_init, siba_erom_init), KOBJMETHOD(bhnd_erom_init_static, siba_erom_init_static), diff --git a/sys/dev/bhnd/siba/siba_nexus.c b/sys/dev/bhnd/siba/siba_nexus.c index 971999cab88fb..cfd6c5dbe30f6 100644 --- a/sys/dev/bhnd/siba/siba_nexus.c +++ b/sys/dev/bhnd/siba/siba_nexus.c @@ -84,18 +84,21 @@ siba_nexus_probe(device_t dev) static int siba_nexus_attach(device_t dev) { - struct siba_nexus_softc *sc; int error; - sc = device_get_softc(dev); + /* Perform initial attach and enumerate our children. */ + if ((error = siba_attach(dev))) + goto failed; - /* Enumerate the bus. */ - if ((error = siba_add_children(dev, NULL))) { - device_printf(dev, "error %d enumerating children\n", error); - return (error); - } + /* Delegate remainder to standard bhnd method implementation */ + if ((error = bhnd_generic_attach(dev))) + goto failed; + + return (0); - return (siba_attach(dev)); +failed: + device_delete_children(dev); + return (error); } static const struct bhnd_chipid * diff --git a/sys/dev/bhnd/siba/sibavar.h b/sys/dev/bhnd/siba/sibavar.h index 81497312c7e1c..0b2e5bba2113c 100644 --- a/sys/dev/bhnd/siba/sibavar.h +++ b/sys/dev/bhnd/siba/sibavar.h @@ -60,8 +60,7 @@ 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); +int siba_add_children(device_t bus); struct siba_devinfo *siba_alloc_dinfo(device_t dev); int siba_init_dinfo(device_t dev, @@ -100,6 +99,11 @@ int siba_parse_admatch(uint32_t am, uint32_t *addr, #define SIBA_MAX_CFG SIBA_CFG_NUM_2_3 /**< maximum number of supported config register blocks */ +#define SIBA_CFG_RID_BASE 100 /**< base resource ID for SIBA_CFG* register allocations */ +#define SIBA_CFG_RID(_dinfo, _cfg) \ + (SIBA_CFG_RID_BASE + (_cfg) + \ + (_dinfo->core_id.core_info.core_idx * SIBA_MAX_CFG)) + /* Sonics/OCP address space mappings */ #define SIBA_CORE_ADDRSPACE 0 /**< Address space mapping the primary device registers */ @@ -155,7 +159,6 @@ struct siba_devinfo { 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_ */ |
