aboutsummaryrefslogtreecommitdiff
path: root/sys/dev/bhnd/siba
diff options
context:
space:
mode:
authorLandon J. Fuller <landonf@FreeBSD.org>2016-09-04 00:58:19 +0000
committerLandon J. Fuller <landonf@FreeBSD.org>2016-09-04 00:58:19 +0000
commit111d7cb2e34311625c8fa8791a355e58bf233a06 (patch)
tree23cc3ee73bbb5086a3fe7d37728a2a99d72c6606 /sys/dev/bhnd/siba
parent3da0f3c9ae77569dee5f771b6ea62a866e51228c (diff)
Notes
Diffstat (limited to 'sys/dev/bhnd/siba')
-rw-r--r--sys/dev/bhnd/siba/siba.c234
-rw-r--r--sys/dev/bhnd/siba/siba_bhndb.c47
-rw-r--r--sys/dev/bhnd/siba/siba_erom.c394
-rw-r--r--sys/dev/bhnd/siba/siba_nexus.c19
-rw-r--r--sys/dev/bhnd/siba/sibavar.h9
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_ */