Page MenuHomeFreeBSD

D7768.id.diff
No OneTemporary

D7768.id.diff

Index: head/sys/dev/bhnd/bcma/bcma.c
===================================================================
--- head/sys/dev/bhnd/bcma/bcma.c
+++ head/sys/dev/bhnd/bcma/bcma.c
@@ -48,6 +48,12 @@
/* RID used when allocating EROM table */
#define BCMA_EROM_RID 0
+static bhnd_erom_class_t *
+bcma_get_erom_class(driver_t *driver)
+{
+ return (&bcma_erom_parser);
+}
+
int
bcma_probe(device_t dev)
{
@@ -55,70 +61,25 @@
return (BUS_PROBE_DEFAULT);
}
+/**
+ * Default bcma(4) bus driver implementation of DEVICE_ATTACH().
+ *
+ * This implementation initializes internal bcma(4) state and performs
+ * bus enumeration, and must be called by subclassing drivers in
+ * DEVICE_ATTACH() before any other bus methods.
+ */
int
bcma_attach(device_t dev)
{
- struct bcma_devinfo *dinfo;
- device_t *devs, child;
- int ndevs;
- int error;
+ int error;
-
- if ((error = device_get_children(dev, &devs, &ndevs)))
+ /* Enumerate children */
+ if ((error = bcma_add_children(dev))) {
+ device_delete_children(dev);
return (error);
-
- /*
- * Map our children's agent register block.
- */
- for (int i = 0; i < ndevs; i++) {
- bhnd_addr_t addr;
- bhnd_size_t size;
- rman_res_t r_start, r_count, r_end;
-
- child = devs[i];
- dinfo = device_get_ivars(child);
-
- KASSERT(!device_is_suspended(child),
- ("bcma(4) stateful suspend handling requires that devices "
- "not be suspended before bcma_attach()"));
-
- /* Verify that the agent register block exists and is
- * mappable */
- if (bhnd_get_port_rid(child, BHND_PORT_AGENT, 0, 0) == -1)
- continue;
-
- /* Fetch the address of the agent register block */
- error = bhnd_get_region_addr(child, BHND_PORT_AGENT, 0, 0,
- &addr, &size);
- if (error) {
- device_printf(dev, "failed fetching agent register "
- "block address for core %d\n", i);
- goto cleanup;
- }
-
- /* Allocate the resource */
- r_start = addr;
- r_count = size;
- r_end = r_start + r_count - 1;
-
- dinfo->rid_agent = i + 1;
- dinfo->res_agent = BHND_BUS_ALLOC_RESOURCE(dev, dev,
- SYS_RES_MEMORY, &dinfo->rid_agent, r_start, r_end, r_count,
- RF_ACTIVE);
- if (dinfo->res_agent == NULL) {
- device_printf(dev, "failed allocating agent register "
- "block for core %d\n", i);
- error = ENXIO;
- goto cleanup;
- }
}
-cleanup:
- free(devs, M_BHND);
- if (error)
- return (error);
-
- return (bhnd_generic_attach(dev));
+ return (0);
}
int
@@ -191,15 +152,6 @@
return (&dinfo->resources);
}
-static device_t
-bcma_find_hostb_device(device_t dev)
-{
- struct bcma_softc *sc = device_get_softc(dev);
-
- /* This is set (or not) by the concrete bcma driver subclass. */
- return (sc->hostb_dev);
-}
-
static int
bcma_reset_core(device_t dev, device_t child, uint16_t flags)
{
@@ -516,8 +468,7 @@
corecfg = NULL;
/* Allocate our EROM parser */
- erom = bhnd_erom_alloc(&bcma_erom_parser, bus, BCMA_EROM_RID,
- cid->enum_addr);
+ erom = bhnd_erom_alloc(&bcma_erom_parser, cid, bus, BCMA_EROM_RID);
if (erom == NULL)
return (ENODEV);
@@ -528,17 +479,21 @@
child = BUS_ADD_CHILD(bus, 0, NULL, -1);
if (child == NULL) {
error = ENXIO;
- goto failed;
+ goto cleanup;
}
/* Initialize device ivars */
dinfo = device_get_ivars(child);
if ((error = bcma_init_dinfo(bus, dinfo, corecfg)))
- goto failed;
+ goto cleanup;
/* The dinfo instance now owns the corecfg value */
corecfg = NULL;
+ /* Allocate device's agent registers, if any */
+ if ((error = bcma_dinfo_alloc_agent(bus, child, 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))
@@ -548,16 +503,19 @@
BHND_BUS_CHILD_ADDED(bus, child);
}
- /* Hit EOF parsing cores? */
+ /* EOF while parsing cores is expected */
if (error == ENOENT)
error = 0;
-failed:
+cleanup:
bhnd_erom_free(erom);
if (corecfg != NULL)
bcma_free_corecfg(corecfg);
+ if (error)
+ device_delete_children(bus);
+
return (error);
}
@@ -574,7 +532,7 @@
DEVMETHOD(bus_get_resource_list, bcma_get_resource_list),
/* BHND interface */
- DEVMETHOD(bhnd_bus_find_hostb_device, bcma_find_hostb_device),
+ DEVMETHOD(bhnd_bus_get_erom_class, bcma_get_erom_class),
DEVMETHOD(bhnd_bus_alloc_devinfo, bcma_alloc_bhnd_dinfo),
DEVMETHOD(bhnd_bus_free_devinfo, bcma_free_bhnd_dinfo),
DEVMETHOD(bhnd_bus_reset_core, bcma_reset_core),
Index: head/sys/dev/bhnd/bcma/bcma_bhndb.c
===================================================================
--- head/sys/dev/bhnd/bcma/bcma_bhndb.c
+++ head/sys/dev/bhnd/bcma/bcma_bhndb.c
@@ -72,26 +72,21 @@
static int
bcma_bhndb_attach(device_t dev)
{
- struct bcma_softc *sc;
- int error;
-
- sc = device_get_softc(dev);
+ int error;
- /* Enumerate our children. */
- if ((error = bcma_add_children(dev)))
- return (error);
+ /* Perform initial attach and enumerate our children. */
+ if ((error = bcma_attach(dev)))
+ goto failed;
+
+ /* Delegate remainder to standard bhnd method implementation */
+ if ((error = bhnd_generic_attach(dev)))
+ goto failed;
- /* Initialize full bridge configuration */
- error = BHNDB_INIT_FULL_CONFIG(device_get_parent(dev), dev,
- bhndb_bcma_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);
+ return (0);
- /* Call our superclass' implementation */
- return (bcma_attach(dev));
+failed:
+ device_delete_children(dev);
+ return (error);
}
static int
Index: head/sys/dev/bhnd/bcma/bcma_erom.c
===================================================================
--- head/sys/dev/bhnd/bcma/bcma_erom.c
+++ head/sys/dev/bhnd/bcma/bcma_erom.c
@@ -58,7 +58,13 @@
* marker.
*/
+struct bcma_erom_io;
+
static const char *bcma_erom_entry_type_name (uint8_t entry);
+
+static uint32_t bcma_eio_read4(struct bcma_erom_io *io,
+ bus_size_t offset);
+
static int bcma_erom_read32(struct bcma_erom *erom,
uint32_t *entry);
static int bcma_erom_skip32(struct bcma_erom *erom);
@@ -72,8 +78,10 @@
static int bcma_erom_region_to_port_type(struct bcma_erom *erom,
uint8_t region_type, bhnd_port_type *port_type);
+
static int bcma_erom_peek32(struct bcma_erom *erom,
uint32_t *entry);
+
static bus_size_t bcma_erom_tell(struct bcma_erom *erom);
static void bcma_erom_seek(struct bcma_erom *erom,
bus_size_t offset);
@@ -96,9 +104,33 @@
u_int core_idx, int core_unit,
struct bhnd_core_info *info);
+/**
+ * BCMA EROM generic I/O context
+ */
+struct bcma_erom_io {
+ struct bhnd_resource *res; /**< memory resource, or NULL if initialized
+ with bus space tag and handle */
+ int rid; /**< memory resource id, or -1 */
+
+ bus_space_tag_t bst; /**< bus space tag, if any */
+ bus_space_handle_t bsh; /**< bus space handle, if any */
+
+ bus_size_t start; /**< base read offset */
+};
+
+/**
+ * BCMA EROM per-instance state.
+ */
+struct bcma_erom {
+ struct bhnd_erom obj;
+ device_t dev; /**< parent device, or NULL if none. */
+ struct bcma_erom_io io; /**< I/O context */
+ bus_size_t offset; /**< current read offset */
+};
+
#define EROM_LOG(erom, fmt, ...) do { \
if (erom->dev != NULL) { \
- device_printf(erom->dev, "erom[0x%llx]: " fmt, \
+ device_printf(erom->dev, "erom[0x%llx]: " fmt, \
(unsigned long long) (erom->offset), ##__VA_ARGS__);\
} else { \
printf("erom[0x%llx]: " fmt, \
@@ -106,7 +138,6 @@
} \
} while(0)
-
/** Return the type name for an EROM entry */
static const char *
bcma_erom_entry_type_name (uint8_t entry)
@@ -123,47 +154,112 @@
}
}
+
+/**
+ * Read a 32-bit value from an EROM I/O context.
+ *
+ * @param io EROM I/O context.
+ * @param offset Read offset.
+ */
+static uint32_t
+bcma_eio_read4(struct bcma_erom_io *io, bus_size_t offset)
+{
+ bus_size_t read_off;
+
+ read_off = io->start + offset;
+ if (io->res != NULL)
+ return (bhnd_bus_read_4(io->res, read_off));
+ else
+ return (bus_space_read_4(io->bst, io->bsh, read_off));
+}
+
+/* Initialize bcma_erom resource I/O context */
+static void
+bcma_eio_init(struct bcma_erom_io *io, struct bhnd_resource *res, int rid,
+ bus_size_t offset)
+{
+ io->res = res;
+ io->rid = rid;
+ io->start = offset;
+}
+
+/* Initialize bcma_erom bus space I/O context */
+static void
+bcma_eio_init_static(struct bcma_erom_io *io, bus_space_tag_t bst,
+ bus_space_handle_t bsh, bus_size_t offset)
+{
+ io->res = NULL;
+ io->rid = -1;
+ io->bst = bst;
+ io->bsh = bsh;
+ io->start = offset;
+}
+
+/* BCMA implementation of BHND_EROM_INIT() */
static int
-bcma_erom_init(bhnd_erom_t *erom, device_t parent, int rid, bus_addr_t enum_addr)
+bcma_erom_init(bhnd_erom_t *erom, const struct bhnd_chipid *cid,
+ device_t parent, int rid)
{
- struct bcma_erom *sc = (struct bcma_erom *)erom;
+ struct bcma_erom *sc;
+ struct bhnd_resource *res;
+ sc = (struct bcma_erom *)erom;
sc->dev = parent;
+ sc->offset = 0;
+
+ res = bhnd_alloc_resource(parent, SYS_RES_MEMORY, &rid, cid->enum_addr,
+ cid->enum_addr + BCMA_EROM_TABLE_SIZE - 1, BCMA_EROM_TABLE_SIZE,
+ RF_ACTIVE|RF_SHAREABLE);
- sc->rid = rid;
- sc->res = bhnd_alloc_resource(parent, SYS_RES_MEMORY, &sc->rid,
- enum_addr, enum_addr + BCMA_EROM_TABLE_SIZE - 1,
- BCMA_EROM_TABLE_SIZE, RF_ACTIVE|RF_SHAREABLE);
- if (sc->res == NULL)
+ if (res == NULL)
return (ENOMEM);
-
- sc->start = BCMA_EROM_TABLE_START;
+
+ bcma_eio_init(&sc->io, res, rid, BCMA_EROM_TABLE_START);
+
+ return (0);
+}
+
+/* BCMA implementation of BHND_EROM_INIT_STATIC() */
+static int
+bcma_erom_init_static(bhnd_erom_t *erom, const struct bhnd_chipid *cid,
+ bus_space_tag_t bst, bus_space_handle_t bsh)
+{
+ struct bcma_erom *sc;
+
+ sc = (struct bcma_erom *)erom;
+ sc->dev = NULL;
sc->offset = 0;
+ bcma_eio_init_static(&sc->io, bst, bsh, BCMA_EROM_TABLE_START);
+
return (0);
}
+/* Common implementation of BHND_EROM_PROBE/BHND_EROM_PROBE_STATIC */
static int
-bcma_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)
+bcma_erom_probe_common(struct bcma_erom_io *io, const struct bhnd_chipid *hint,
+ struct bhnd_chipid *cid)
{
- uint32_t idreg, eaddr;
- uint8_t chip_type;
+ uint32_t idreg, eromptr;
- idreg = bus_space_read_4(bst, bsh, CHIPC_ID);
- chip_type = CHIPC_GET_BITS(idreg, CHIPC_ID_BUS);
+ /* Hints aren't supported; all BCMA devices have a ChipCommon
+ * core */
+ if (hint != NULL)
+ return (EINVAL);
- /* Fetch EROM physical address */
- if (!BHND_CHIPTYPE_HAS_EROM(chip_type))
+ /* Confirm CHIPC_EROMPTR availability */
+ idreg = bcma_eio_read4(io, CHIPC_ID);
+ if (!BHND_CHIPTYPE_HAS_EROM(CHIPC_GET_BITS(idreg, CHIPC_ID_BUS)))
return (ENXIO);
- eaddr = bus_space_read_4(bst, bsh, CHIPC_EROMPTR);
+ /* Fetch EROM address */
+ eromptr = bcma_eio_read4(io, CHIPC_EROMPTR);
/* Parse chip identifier */
- *cid = bhnd_parse_chipid(idreg, eaddr);
+ *cid = bhnd_parse_chipid(idreg, eromptr);
/* Verify chip type */
- switch (chip_type) {
+ switch (cid->chip_type) {
case BHND_CHIPTYPE_BCMA:
return (BUS_PROBE_DEFAULT);
@@ -173,37 +269,44 @@
default:
return (ENXIO);
- }
+ }
}
static int
-bcma_erom_init_static(bhnd_erom_t *erom, bus_space_tag_t bst,
- bus_space_handle_t bsh)
+bcma_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 bcma_erom *sc = (struct bcma_erom *)erom;
+ struct bcma_erom_io io;
- sc->dev = NULL;
- sc->rid = -1;
- sc->res = NULL;
- sc->bst = bst;
- sc->bsh = bsh;
- sc->start = BCMA_EROM_TABLE_START;
- sc->offset = 0;
+ bcma_eio_init(&io, res, rman_get_rid(res->res),
+ offset + BCMA_EROM_TABLE_START);
- return (0);
+ return (bcma_erom_probe_common(&io, hint, cid));
}
+static int
+bcma_erom_probe_static(bhnd_erom_class_t *cls, bus_space_tag_t bst,
+ bus_space_handle_t bsh, bus_addr_t paddr, const struct bhnd_chipid *hint,
+ struct bhnd_chipid *cid)
+{
+ struct bcma_erom_io io;
+
+ bcma_eio_init_static(&io, bst, bsh, BCMA_EROM_TABLE_START);
+ return (bcma_erom_probe_common(&io, hint, cid));
+}
+
+
static void
bcma_erom_fini(bhnd_erom_t *erom)
{
struct bcma_erom *sc = (struct bcma_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->dev, SYS_RES_MEMORY, sc->io.rid,
+ sc->io.res);
- sc->res = NULL;
- sc->rid = -1;
+ sc->io.res = NULL;
+ sc->io.rid = -1;
}
}
@@ -484,19 +587,12 @@
static int
bcma_erom_peek32(struct bcma_erom *erom, uint32_t *entry)
{
- bus_size_t off;
-
- if (erom->offset >= BCMA_EROM_TABLE_SIZE) {
+ if (erom->offset >= (BCMA_EROM_TABLE_SIZE - sizeof(uint32_t))) {
EROM_LOG(erom, "BCMA EROM table missing terminating EOF\n");
return (EINVAL);
}
-
- off = erom->start + erom->offset;
- if (erom->res != NULL)
- *entry = bhnd_bus_read_4(erom->res, off);
- else
- *entry = bus_space_read_4(erom->bst, erom->bsh, off);
-
+
+ *entry = bcma_eio_read4(&erom->io, erom->offset);
return (0);
}
@@ -1259,6 +1355,7 @@
}
static kobj_method_t bcma_erom_methods[] = {
+ KOBJMETHOD(bhnd_erom_probe, bcma_erom_probe),
KOBJMETHOD(bhnd_erom_probe_static, bcma_erom_probe_static),
KOBJMETHOD(bhnd_erom_init, bcma_erom_init),
KOBJMETHOD(bhnd_erom_init_static, bcma_erom_init_static),
Index: head/sys/dev/bhnd/bcma/bcma_eromvar.h
===================================================================
--- head/sys/dev/bhnd/bcma/bcma_eromvar.h
+++ head/sys/dev/bhnd/bcma/bcma_eromvar.h
@@ -42,25 +42,6 @@
int bcma_erom_next_corecfg(struct bcma_erom *sc,
struct bcma_corecfg **result);
-/**
- * BCMA EROM per-instance state.
- */
-struct bcma_erom {
- struct bhnd_erom obj;
- device_t dev; /**< EROM parent device, or NULL
- if none. */
- struct bhnd_resource *res; /**< EROM table resource, or
- NULL if initialized with
- bus space tag and handle */
- int rid; /**< EROM table rid, or -1 */
-
- bus_space_tag_t bst; /**< EROM table bus space */
- bus_space_handle_t bsh; /**< EROM table bus handle */
-
- bus_size_t start; /**< EROM table offset */
- bus_size_t offset; /**< current read offset */
-};
-
/** EROM core descriptor. */
struct bcma_erom_core {
uint16_t vendor; /**< core's designer */
Index: head/sys/dev/bhnd/bcma/bcma_nexus.c
===================================================================
--- head/sys/dev/bhnd/bcma/bcma_nexus.c
+++ head/sys/dev/bhnd/bcma/bcma_nexus.c
@@ -93,10 +93,19 @@
{
int error;
- if ((error = bcma_add_children(dev)))
- return (error);
+ /* Perform initial attach and enumerate our children. */
+ if ((error = bcma_attach(dev)))
+ goto failed;
+
+ /* Delegate remainder to standard bhnd method implementation */
+ if ((error = bhnd_generic_attach(dev)))
+ goto failed;
+
+ return (0);
- return (bcma_attach(dev));
+failed:
+ device_delete_children(dev);
+ return (error);
}
static const struct bhnd_chipid *
Index: head/sys/dev/bhnd/bcma/bcma_subr.c
===================================================================
--- head/sys/dev/bhnd/bcma/bcma_subr.c
+++ head/sys/dev/bhnd/bcma/bcma_subr.c
@@ -43,6 +43,10 @@
#include "bcmavar.h"
+/* Return the resource ID for a device's agent register allocation */
+#define BCMA_AGENT_RID(_dinfo) \
+ (BCMA_AGENT_RID_BASE + BCMA_DINFO_COREIDX(_dinfo))
+
/**
* Allocate and initialize new core config structure.
*
@@ -244,6 +248,63 @@
return (0);
}
+
+/**
+ * Allocate the per-core agent register block for a device info structure
+ * previous initialized via bcma_init_dinfo().
+ *
+ * If an agent0.0 region is not defined on @p dinfo, the device info
+ * agent resource is set to NULL and 0 is returned.
+ *
+ * @param bus The requesting bus device.
+ * @param child The bcma child device.
+ * @param dinfo The device info associated with @p child
+ *
+ * @retval 0 success
+ * @retval non-zero resource allocation failed.
+ */
+int
+bcma_dinfo_alloc_agent(device_t bus, device_t child, struct bcma_devinfo *dinfo)
+{
+ bhnd_addr_t addr;
+ bhnd_size_t size;
+ rman_res_t r_start, r_count, r_end;
+ int error;
+
+ KASSERT(dinfo->res_agent == NULL, ("double allocation of agent"));
+
+ /* Verify that the agent register block exists and is
+ * mappable */
+ if (bhnd_get_port_rid(child, BHND_PORT_AGENT, 0, 0) == -1)
+ return (0); /* nothing to do */
+
+ /* Fetch the address of the agent register block */
+ error = bhnd_get_region_addr(child, BHND_PORT_AGENT, 0, 0,
+ &addr, &size);
+ if (error) {
+ device_printf(bus, "failed fetching agent register block "
+ "address for core %u\n", BCMA_DINFO_COREIDX(dinfo));
+ return (error);
+ }
+
+ /* Allocate the resource */
+ r_start = addr;
+ r_count = size;
+ r_end = r_start + r_count - 1;
+
+ dinfo->rid_agent = BCMA_AGENT_RID(dinfo);
+ dinfo->res_agent = BHND_BUS_ALLOC_RESOURCE(bus, bus, SYS_RES_MEMORY,
+ &dinfo->rid_agent, r_start, r_end, r_count, RF_ACTIVE);
+ if (dinfo->res_agent == NULL) {
+ device_printf(bus, "failed allocating agent register block for "
+ "core %u\n", BCMA_DINFO_COREIDX(dinfo));
+ return (ENXIO);
+ }
+
+ return (0);
+}
+
+
/**
* Deallocate the given device info structure and any associated resources.
*
Index: head/sys/dev/bhnd/bcma/bcmavar.h
===================================================================
--- head/sys/dev/bhnd/bcma/bcmavar.h
+++ head/sys/dev/bhnd/bcma/bcmavar.h
@@ -45,6 +45,18 @@
* Internal definitions shared by bcma(4) driver implementations.
*/
+/** Base resource ID for per-core agent register allocations */
+#define BCMA_AGENT_RID_BASE 100
+
+/**
+ * Return the device's core index.
+ *
+ * @param _dinfo The bcma_devinfo instance to query.
+ */
+#define BCMA_DINFO_COREIDX(_dinfo) \
+ ((_dinfo)->corecfg->core_info.core_idx)
+
+
/** BCMA port identifier. */
typedef u_int bcma_pid_t;
#define BCMA_PID_MAX UINT_MAX /**< Maximum bcma_pid_t value */
@@ -72,6 +84,8 @@
int bcma_init_dinfo(device_t bus,
struct bcma_devinfo *dinfo,
struct bcma_corecfg *corecfg);
+int bcma_dinfo_alloc_agent(device_t bus, device_t child,
+ struct bcma_devinfo *dinfo);
void bcma_free_dinfo(device_t bus,
struct bcma_devinfo *dinfo);
@@ -147,7 +161,6 @@
/** BMCA per-instance state */
struct bcma_softc {
struct bhnd_softc bhnd_sc; /**< bhnd state */
- device_t hostb_dev; /**< host bridge core, or NULL */
};
#endif /* _BCMA_BCMAVAR_H_ */
Index: head/sys/dev/bhnd/bhnd.h
===================================================================
--- head/sys/dev/bhnd/bhnd.h
+++ head/sys/dev/bhnd/bhnd.h
@@ -39,6 +39,7 @@
#include "bhnd_ids.h"
#include "bhnd_types.h"
+#include "bhnd_erom_types.h"
#include "bhnd_debug.h"
#include "bhnd_bus_if.h"
#include "bhnd_match.h"
@@ -188,6 +189,12 @@
* is MMIO accessible. */
};
+/** Wrap the active resource @p _r in a bhnd_resource structure */
+#define BHND_DIRECT_RESOURCE(_r) ((struct bhnd_resource) { \
+ .res = (_r), \
+ .direct = true, \
+})
+
/**
* Device quirk table descriptor.
*/
@@ -278,6 +285,13 @@
const struct bhnd_core_info *cores,
u_int num_cores, bhnd_devclass_t class);
+struct bhnd_core_match bhnd_core_get_match_desc(
+ const struct bhnd_core_info *core);
+
+bool bhnd_cores_equal(
+ const struct bhnd_core_info *lhs,
+ const struct bhnd_core_info *rhs);
+
bool bhnd_core_matches(
const struct bhnd_core_info *core,
const struct bhnd_core_match *desc);
@@ -389,7 +403,16 @@
bhnd_attach_type bhnd_bus_generic_get_attach_type(device_t dev,
device_t child);
-
+/**
+ * Return the bhnd(4) bus driver's device enumeration parser class
+ *
+ * @param driver A bhnd bus driver instance.
+ */
+static inline bhnd_erom_class_t *
+bhnd_driver_get_erom_class(driver_t *driver)
+{
+ return (BHND_BUS_GET_EROM_CLASS(driver));
+}
/**
* Return the active host bridge core for the bhnd bus, if any, or NULL if
Index: head/sys/dev/bhnd/bhnd_bus_if.m
===================================================================
--- head/sys/dev/bhnd/bhnd_bus_if.m
+++ head/sys/dev/bhnd/bhnd_bus_if.m
@@ -29,6 +29,7 @@
#include <sys/rman.h>
#include <dev/bhnd/bhnd_types.h>
+#include <dev/bhnd/bhnd_erom_types.h>
INTERFACE bhnd_bus;
@@ -49,7 +50,13 @@
#include <sys/systm.h>
#include <dev/bhnd/bhndvar.h>
-
+
+ static bhnd_erom_class_t *
+ bhnd_bus_null_get_erom_class(driver_t *driver)
+ {
+ return (NULL);
+ }
+
static struct bhnd_chipid *
bhnd_bus_null_get_chipid(device_t dev, device_t child)
{
@@ -152,7 +159,7 @@
static device_t
bhnd_bus_null_find_hostb_device(device_t dev)
{
- panic("bhnd_bus_find_hostb_device unimplemented");
+ return (NULL);
}
static bool
@@ -199,6 +206,15 @@
}
/**
+ * Return the bhnd(4) bus driver's device enumeration parser class.
+ *
+ * @param driver The bhnd bus driver instance.
+ */
+STATICMETHOD bhnd_erom_class_t * get_erom_class {
+ driver_t *driver;
+} DEFAULT bhnd_bus_null_get_erom_class;
+
+/**
* Return the active host bridge core for the bhnd bus, if any.
*
* @param dev The bhnd bus device.
Index: head/sys/dev/bhnd/bhnd_erom.h
===================================================================
--- head/sys/dev/bhnd/bhnd_erom.h
+++ head/sys/dev/bhnd/bhnd_erom.h
@@ -42,11 +42,12 @@
#include "bhnd_erom_if.h"
bhnd_erom_t *bhnd_erom_alloc(bhnd_erom_class_t *cls,
- device_t parent, int rid,
- bus_addr_t enum_addr);
+ const struct bhnd_chipid *cid,
+ device_t parent, int rid);
int bhnd_erom_init_static(bhnd_erom_class_t *cls,
bhnd_erom_t *erom, size_t esize,
+ const struct bhnd_chipid *cid,
bus_space_tag_t bst,
bus_space_handle_t bsh);
@@ -94,15 +95,48 @@
/**
* Probe to see if this device enumeration class supports the bhnd bus
+ * mapped by the given resource, returning a standard newbus device probe
+ * result (see BUS_PROBE_*) and the probed chip identification.
+ *
+ * @param cls The erom class to probe.
+ * @param res A resource mapping the first bus core (EXTIF or
+ * ChipCommon)
+ * @param offset Offset to the first bus core within @p res.
+ * @param hint Identification hint used to identify the device. If
+ * chipset supports standard chip identification registers
+ * within the first core, this parameter should be NULL.
+ * @param[out] cid On success, the probed chip identifier.
+ *
+ * @retval 0 if this is the only possible device enumeration
+ * parser for the probed bus.
+ * @retval negative if the probe succeeds, a negative value should be
+ * returned; the parser returning the highest negative
+ * value will be selected to handle device enumeration.
+ * @retval ENXIO If the bhnd bus type is not handled by this parser.
+ * @retval positive if an error occurs during probing, a regular unix error
+ * code should be returned.
+ */
+static inline int
+bhnd_erom_probe(bhnd_erom_class_t *cls, struct bhnd_resource *res,
+ bus_size_t offset, const struct bhnd_chipid *hint, struct bhnd_chipid *cid)
+{
+ return (BHND_EROM_PROBE(cls, res, offset, hint, cid));
+}
+
+/**
+ * Probe to see if this device enumeration class supports the bhnd bus
* mapped at the given bus space tag and handle, returning a standard
* newbus device probe result (see BUS_PROBE_*) and the probed
* chip identification.
*
- * @param cls The parser class to be probed.
+ * @param cls The erom class to probe.
* @param bst Bus space tag.
* @param bsh Bus space handle mapping the EXTIF or ChipCommon core.
* @param paddr The physical address of the core mapped by @p bst and
* @p bsh.
+ * @param hint Identification hint used to identify the device. If
+ * chipset supports standard chip identification registers
+ * within the first core, this parameter should be NULL.
* @param[out] cid On success, the probed chip identifier.
*
* @retval 0 if this is the only possible device enumeration
@@ -116,9 +150,10 @@
*/
static inline int
bhnd_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)
{
- return (BHND_EROM_PROBE_STATIC(cls, bst, bsh, paddr, cid));
+ return (BHND_EROM_PROBE_STATIC(cls, bst, bsh, paddr, hint, cid));
}
/**
Index: head/sys/dev/bhnd/bhnd_erom.c
===================================================================
--- head/sys/dev/bhnd/bhnd_erom.c
+++ head/sys/dev/bhnd/bhnd_erom.c
@@ -45,15 +45,15 @@
* be allocated.
* @param rid The resource ID to be used when allocating EROM
* resources.
- * @param enum_addr The base address of the device enumeration table.
+ * @param cid The device's chip identifier.
*
* @retval non-NULL success
* @retval NULL if an error occured allocating or initializing the
* EROM parser.
*/
bhnd_erom_t *
-bhnd_erom_alloc(bhnd_erom_class_t *cls, device_t parent, int rid,
- bus_addr_t enum_addr)
+bhnd_erom_alloc(bhnd_erom_class_t *cls, const struct bhnd_chipid *cid,
+ device_t parent, int rid)
{
bhnd_erom_t *erom;
int error;
@@ -61,9 +61,9 @@
erom = (bhnd_erom_t *)kobj_create((kobj_class_t)cls, M_BHND,
M_WAITOK|M_ZERO);
- if ((error = BHND_EROM_INIT(erom, parent, rid, enum_addr))) {
+ if ((error = BHND_EROM_INIT(erom, cid, parent, rid))) {
printf("error initializing %s parser at %#jx with "
- "rid %d: %d\n", cls->name, (uintmax_t)enum_addr, rid,
+ "rid %d: %d\n", cls->name, (uintmax_t)cid->enum_addr, rid,
error);
kobj_delete((kobj_t)erom, M_BHND);
@@ -86,6 +86,7 @@
* @param esize The total available number of bytes allocated for
* @p erom. If this is less than is required by @p cls,
* ENOMEM will be returned.
+ * @param cid The device's chip identifier.
* @param bst Bus space tag.
* @param bsh Bus space handle mapping the device enumeration
* space.
@@ -97,7 +98,7 @@
*/
int
bhnd_erom_init_static(bhnd_erom_class_t *cls, bhnd_erom_t *erom, size_t esize,
- bus_space_tag_t bst, bus_space_handle_t bsh)
+ const struct bhnd_chipid *cid, bus_space_tag_t bst, bus_space_handle_t bsh)
{
kobj_class_t kcls;
@@ -109,7 +110,7 @@
/* Perform instance initialization */
kobj_init_static((kobj_t)erom, kcls);
- return (BHND_EROM_INIT_STATIC(erom, bst, bsh));
+ return (BHND_EROM_INIT_STATIC(erom, cid, bst, bsh));
}
/**
Index: head/sys/dev/bhnd/bhnd_erom_if.m
===================================================================
--- head/sys/dev/bhnd/bhnd_erom_if.m
+++ head/sys/dev/bhnd/bhnd_erom_if.m
@@ -45,15 +45,48 @@
/**
* Probe to see if this device enumeration class supports the bhnd bus
+ * mapped by the given resource, returning a standard newbus device probe
+ * result (see BUS_PROBE_*) and the probed chip identification.
+ *
+ * @param cls The erom class to probe.
+ * @param res A resource mapping the first bus core.
+ * @param offset Offset to the first bus core within @p res.
+ * @param hint Hint used to identify the device. If chipset supports
+ * standard chip identification registers within the first
+ * core, this parameter should be NULL.
+ * @param[out] cid On success, the probed chip identifier.
+ *
+ * @retval 0 if this is the only possible device enumeration
+ * parser for the probed bus.
+ * @retval negative if the probe succeeds, a negative value should be
+ * returned; the parser returning the highest negative
+ * value will be selected to handle device enumeration.
+ * @retval ENXIO If the bhnd bus type is not handled by this parser.
+ * @retval positive if an error occurs during probing, a regular unix error
+ * code should be returned.
+ */
+STATICMETHOD int probe {
+ bhnd_erom_class_t *cls;
+ struct bhnd_resource *res;
+ bus_size_t offset;
+ const struct bhnd_chipid *hint;
+ struct bhnd_chipid *cid;
+};
+
+/**
+ * Probe to see if this device enumeration class supports the bhnd bus
* mapped at the given bus space tag and handle, returning a standard
* newbus device probe result (see BUS_PROBE_*) and the probed
* chip identification.
*
- * @param cls The erom parse class to probe.
+ * @param cls The erom class to probe.
* @param bst Bus space tag.
- * @param bsh Bus space handle mapping the EXTIF or ChipCommon core.
+ * @param bsh Bus space handle mapping the first bus core.
* @param paddr The physical address of the core mapped by @p bst and
* @p bsh.
+ * @param hint Hint used to identify the device. If chipset supports
+ * standard chip identification registers within the first
+ * core, this parameter should be NULL.
* @param[out] cid On success, the probed chip identifier.
*
* @retval 0 if this is the only possible device enumeration
@@ -66,51 +99,54 @@
* code should be returned.
*/
STATICMETHOD int 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;
+ bhnd_erom_class_t *cls;
+ bus_space_tag_t bst;
+ bus_space_handle_t bsh;
+ bus_addr_t paddr;
+ const struct bhnd_chipid *hint;
+ struct bhnd_chipid *cid;
};
/**
* Initialize a device enumeration table parser.
*
* @param erom The erom parser to initialize.
+ * @param cid The device's chip identifier.
* @param parent The parent device from which EROM resources should
* be allocated.
* @param rid The resource id to be used when allocating the
* enumeration table.
- * @param enum_addr The base address of the device enumeration table.
*
* @retval 0 success
* @retval non-zero if an error occurs initializing the EROM parser,
* a regular unix error code will be returned.
*/
METHOD int init {
- bhnd_erom_t *erom;
- device_t parent;
- int rid;
- bus_addr_t enum_addr;
+ bhnd_erom_t *erom;
+ const struct bhnd_chipid *cid;
+ device_t parent;
+ int rid;
};
/**
* Initialize an device enumeration table parser using the provided bus space
* tag and handle.
*
- * @param erom The erom parser to initialize.
- * @param bst Bus space tag.
- * @param bsh bus space handle mapping the full bus enumeration
- * space.
+ * @param erom The erom parser to initialize.
+ * @param cid The device's chip identifier.
+ * @param bst Bus space tag.
+ * @param bsh Bus space handle mapping the full bus enumeration
+ * space.
*
* @retval 0 success
* @retval non-zero if an error occurs initializing the EROM parser,
* a regular unix error code will be returned.
*/
METHOD int init_static {
- bhnd_erom_t *erom;
- bus_space_tag_t bst;
- bus_space_handle_t bsh;
+ bhnd_erom_t *erom;
+ const struct bhnd_chipid *cid;
+ bus_space_tag_t bst;
+ bus_space_handle_t bsh;
};
/**
Index: head/sys/dev/bhnd/bhnd_match.h
===================================================================
--- head/sys/dev/bhnd/bhnd_match.h
+++ head/sys/dev/bhnd/bhnd_match.h
@@ -105,8 +105,9 @@
core_id:1,
core_rev:1,
core_class:1,
+ core_idx:1,
core_unit:1,
- flags_unused:3;
+ flags_unused:2;
} match;
} m;
@@ -114,6 +115,7 @@
uint16_t core_id; /**< required core ID */
struct bhnd_hwrev_match core_rev; /**< matching core revisions. */
bhnd_devclass_t core_class; /**< required bhnd class */
+ u_int core_idx; /**< required core index */
int core_unit; /**< required core unit */
};
@@ -122,6 +124,7 @@
_BHND_COPY_MATCH_FIELD(_src, core_id), \
_BHND_COPY_MATCH_FIELD(_src, core_rev), \
_BHND_COPY_MATCH_FIELD(_src, core_class), \
+ _BHND_COPY_MATCH_FIELD(_src, core_idx), \
_BHND_COPY_MATCH_FIELD(_src, core_unit) \
#define BHND_MATCH_CORE_VENDOR(_v) _BHND_SET_MATCH_FIELD(core_vendor, _v)
@@ -129,6 +132,7 @@
#define BHND_MATCH_CORE_REV(_rev) _BHND_SET_MATCH_FIELD(core_rev, \
BHND_ ## _rev)
#define BHND_MATCH_CORE_CLASS(_cls) _BHND_SET_MATCH_FIELD(core_class, _cls)
+#define BHND_MATCH_CORE_IDX(_idx) _BHND_SET_MATCH_FIELD(core_idx, _idx)
#define BHND_MATCH_CORE_UNIT(_unit) _BHND_SET_MATCH_FIELD(core_unit, _unit)
/**
@@ -255,6 +259,7 @@
core_id:1,
core_rev:1,
core_class:1,
+ core_idx:1,
core_unit:1,
chip_id:1,
chip_rev:1,
@@ -263,7 +268,7 @@
board_type:1,
board_rev:1,
board_srom_rev:1,
- flags_unused:2;
+ flags_unused:1;
} match;
} m;
@@ -271,6 +276,7 @@
uint16_t core_id; /**< required core ID */
struct bhnd_hwrev_match core_rev; /**< matching core revisions. */
bhnd_devclass_t core_class; /**< required bhnd class */
+ u_int core_idx; /**< required core index */
int core_unit; /**< required core unit */
uint16_t chip_id; /**< required chip id */
Index: head/sys/dev/bhnd/bhnd_nexus.c
===================================================================
--- head/sys/dev/bhnd/bhnd_nexus.c
+++ head/sys/dev/bhnd/bhnd_nexus.c
@@ -83,7 +83,7 @@
static bool
bhnd_nexus_is_hw_disabled(device_t dev, device_t child)
{
- return false;
+ return (false);
}
static bhnd_attach_type
Index: head/sys/dev/bhnd/bhnd_subr.c
===================================================================
--- head/sys/dev/bhnd/bhnd_subr.c
+++ head/sys/dev/bhnd/bhnd_subr.c
@@ -485,6 +485,47 @@
return bhnd_match_core(cores, num_cores, &md);
}
+
+/**
+ * Create an equality match descriptor for @p core.
+ *
+ * @param core The core info to be matched on.
+ * @param desc On return, will be populated with a match descriptor for @p core.
+ */
+struct bhnd_core_match
+bhnd_core_get_match_desc(const struct bhnd_core_info *core)
+{
+ return ((struct bhnd_core_match) {
+ BHND_MATCH_CORE_VENDOR(core->vendor),
+ BHND_MATCH_CORE_ID(core->device),
+ BHND_MATCH_CORE_REV(HWREV_EQ(core->hwrev)),
+ BHND_MATCH_CORE_CLASS(bhnd_core_class(core)),
+ BHND_MATCH_CORE_IDX(core->core_idx),
+ BHND_MATCH_CORE_UNIT(core->unit)
+ });
+}
+
+
+/**
+ * Return true if the @p lhs is equal to @p rhs
+ *
+ * @param lhs The first bhnd core descriptor to compare.
+ * @param rhs The second bhnd core descriptor to compare.
+ *
+ * @retval true if @p lhs is equal to @p rhs
+ * @retval false if @p lhs is not equal to @p rhs
+ */
+bool
+bhnd_cores_equal(const struct bhnd_core_info *lhs,
+ const struct bhnd_core_info *rhs)
+{
+ struct bhnd_core_match md;
+
+ /* Use an equality match descriptor to perform the comparison */
+ md = bhnd_core_get_match_desc(rhs);
+ return (bhnd_core_matches(lhs, &md));
+}
+
/**
* Return true if the @p core matches @p desc.
*
@@ -511,6 +552,9 @@
!bhnd_hwrev_matches(core->hwrev, &desc->core_rev))
return (false);
+ if (desc->m.match.core_idx && desc->core_idx != core->core_idx)
+ return (false);
+
if (desc->m.match.core_class &&
desc->core_class != bhnd_core_class(core))
return (false);
Index: head/sys/dev/bhnd/bhndb/bhnd_bhndb.c
===================================================================
--- head/sys/dev/bhnd/bhndb/bhnd_bhndb.c
+++ head/sys/dev/bhnd/bhndb/bhnd_bhndb.c
@@ -66,6 +66,22 @@
return (BHND_ATTACH_ADAPTER);
}
+static device_t
+bhnd_bhndb_find_hostb_device(device_t dev)
+{
+ struct bhnd_core_info core;
+ struct bhnd_core_match md;
+ int error;
+
+ /* Ask the bridge for the hostb core info */
+ if ((error = BHNDB_GET_HOSTB_CORE(device_get_parent(dev), dev, &core)))
+ return (NULL);
+
+ /* Find the corresponding bus device */
+ md = bhnd_core_get_match_desc(&core);
+ return (bhnd_match_child(dev, &md));
+}
+
static bhnd_clksrc
bhnd_bhndb_pwrctl_get_clksrc(device_t dev, device_t child,
bhnd_clock clock)
@@ -96,6 +112,7 @@
static device_method_t bhnd_bhndb_methods[] = {
/* BHND interface */
DEVMETHOD(bhnd_bus_get_attach_type, bhnd_bhndb_get_attach_type),
+ DEVMETHOD(bhnd_bus_find_hostb_device, bhnd_bhndb_find_hostb_device),
DEVMETHOD(bhnd_bus_read_board_info, bhnd_bhndb_read_board_info),
DEVMETHOD(bhnd_bus_pwrctl_get_clksrc, bhnd_bhndb_pwrctl_get_clksrc),
Index: head/sys/dev/bhnd/bhndb/bhndb.c
===================================================================
--- head/sys/dev/bhnd/bhndb/bhndb.c
+++ head/sys/dev/bhnd/bhndb/bhndb.c
@@ -50,6 +50,8 @@
#include <dev/bhnd/bhndvar.h>
#include <dev/bhnd/bhndreg.h>
+#include <dev/bhnd/bhnd_erom.h>
+
#include <dev/bhnd/cores/chipc/chipcreg.h>
#include <dev/bhnd/nvram/bhnd_nvram.h>
@@ -71,24 +73,31 @@
#define BHNDB_DEBUG(_type) (BHNDB_DEBUG_ ## _type & bhndb_debug)
-static bool bhndb_hw_matches(device_t *devlist,
- int num_devs,
- const struct bhndb_hw *hw);
-
-static int bhndb_initialize_region_cfg(
- struct bhndb_softc *sc, device_t *devs,
- int ndevs,
- const struct bhndb_hw_priority *table,
- struct bhndb_resources *r);
+static int bhndb_find_hostb_core(struct bhndb_softc *sc,
+ bhnd_erom_t *erom,
+ struct bhnd_core_info *core);
+
+static bhnd_erom_class_t *bhndb_probe_erom_class(struct bhndb_softc *sc,
+ struct bhnd_chipid *cid);
+
+static int bhndb_init_full_config(struct bhndb_softc *sc,
+ bhnd_erom_class_t *eromcls);
+
+static struct bhnd_core_info *bhndb_get_bridge_core(struct bhndb_softc *sc);
+
+static bool bhndb_hw_matches(struct bhnd_core_info *cores,
+ u_int ncores, const struct bhndb_hw *hw);
+
+static int bhndb_init_region_cfg(struct bhndb_softc *sc,
+ bhnd_erom_t *erom,
+ struct bhndb_resources *r,
+ struct bhnd_core_info *cores, u_int ncores,
+ const struct bhndb_hw_priority *table);
static int bhndb_find_hwspec(struct bhndb_softc *sc,
- device_t *devs, int ndevs,
+ struct bhnd_core_info *cores, u_int ncores,
const struct bhndb_hw **hw);
-static int bhndb_read_chipid(struct bhndb_softc *sc,
- const struct bhndb_hwcfg *cfg,
- struct bhnd_chipid *result);
-
bhndb_addrspace bhndb_get_addrspace(struct bhndb_softc *sc,
device_t child);
@@ -111,6 +120,10 @@
int type, int rid, struct resource *r,
bool *indirect);
+static inline struct bhndb_dw_alloc *bhndb_io_resource(struct bhndb_softc *sc,
+ bus_addr_t addr, bus_size_t size,
+ bus_size_t *offset);
+
/**
* Default bhndb(4) implementation of DEVICE_PROBE().
@@ -183,26 +196,40 @@
}
/**
- * Return true if @p devlist matches the @p hw specification.
+ * Return the bridge core info. Will panic if the bridge core info has not yet
+ * been populated during full bridge configuration.
*
- * @param devlist A device table to match against.
- * @param num_devs The number of devices in @p devlist.
+ * @param sc BHNDB device state.
+ */
+static struct bhnd_core_info *
+bhndb_get_bridge_core(struct bhndb_softc *sc)
+{
+ if (!sc->have_br_core)
+ panic("bridge not yet fully configured; no bridge core!");
+
+ return (&sc->bridge_core);
+}
+
+/**
+ * Return true if @p cores matches the @p hw specification.
+ *
+ * @param cores A device table to match against.
+ * @param ncores The number of cores in @p cores.
* @param hw The hardware description to be matched against.
*/
static bool
-bhndb_hw_matches(device_t *devlist, int num_devs, const struct bhndb_hw *hw)
+bhndb_hw_matches(struct bhnd_core_info *cores, u_int ncores,
+ const struct bhndb_hw *hw)
{
for (u_int i = 0; i < hw->num_hw_reqs; i++) {
const struct bhnd_core_match *match;
- struct bhnd_core_info ci;
bool found;
match = &hw->hw_reqs[i];
found = false;
- for (int d = 0; d < num_devs; d++) {
- ci = bhnd_get_core_info(devlist[d]);
- if (!bhnd_core_matches(&ci, match))
+ for (u_int d = 0; d < ncores; d++) {
+ if (!bhnd_core_matches(&cores[d], match))
continue;
found = true;
@@ -217,20 +244,21 @@
}
/**
- * Initialize the region maps and priority configuration in @p r using
- * the provided priority @p table and the set of devices attached to
- * the bridged @p bus_dev .
+ * Initialize the region maps and priority configuration in @p br using
+ * the priority @p table and the set of cores enumerated by @p erom.
*
* @param sc The bhndb device state.
- * @param devs All devices enumerated on the bridged bhnd bus.
- * @param ndevs The length of @p devs.
+ * @param br The resource state to be configured.
+ * @param erom EROM parser used to enumerate @p cores.
+ * @param cores All cores enumerated on the bridged bhnd bus.
+ * @param ncores The length of @p cores.
* @param table Hardware priority table to be used to determine the relative
* priorities of per-core port resources.
- * @param r The resource state to be configured.
*/
static int
-bhndb_initialize_region_cfg(struct bhndb_softc *sc, device_t *devs, int ndevs,
- const struct bhndb_hw_priority *table, struct bhndb_resources *r)
+bhndb_init_region_cfg(struct bhndb_softc *sc, bhnd_erom_t *erom,
+ struct bhndb_resources *br, struct bhnd_core_info *cores, u_int ncores,
+ const struct bhndb_hw_priority *table)
{
const struct bhndb_hw_priority *hp;
bhnd_addr_t addr;
@@ -247,29 +275,40 @@
/*
* Register bridge regions covering all statically mapped ports.
*/
- for (int i = 0; i < ndevs; i++) {
+ for (u_int i = 0; i < ncores; i++) {
const struct bhndb_regwin *regw;
- device_t child;
+ struct bhnd_core_info *core;
+ struct bhnd_core_match md;
- child = devs[i];
+ core = &cores[i];
+ md = bhnd_core_get_match_desc(core);
- for (regw = r->cfg->register_windows;
+ for (regw = br->cfg->register_windows;
regw->win_type != BHNDB_REGWIN_T_INVALID; regw++)
{
/* Only core windows are supported */
if (regw->win_type != BHNDB_REGWIN_T_CORE)
continue;
- /* Skip non-applicable register windows. */
- if (!bhndb_regwin_matches_device(regw, child))
+ /* Skip non-matching cores. */
+ if (!bhndb_regwin_match_core(regw, core))
continue;
-
- /* Fetch the base address of the mapped port. */
- error = bhnd_get_region_addr(child,
- regw->d.core.port_type, regw->d.core.port,
- regw->d.core.region, &addr, &size);
- if (error)
- return (error);
+
+ /* Fetch the base address of the mapped port */
+ error = bhnd_erom_lookup_core_addr(erom, &md,
+ regw->d.core.port_type,
+ regw->d.core.port,
+ regw->d.core.region,
+ NULL,
+ &addr,
+ &size);
+ if (error) {
+ /* Skip non-applicable register windows */
+ if (error == ENOENT)
+ continue;
+
+ return (error);
+ }
/*
* Always defer to the register window's size.
@@ -290,7 +329,7 @@
* The window priority for a statically mapped
* region is always HIGH.
*/
- error = bhndb_add_resource_region(r, addr, size,
+ error = bhndb_add_resource_region(br, addr, size,
BHNDB_PRIORITY_HIGH, regw);
if (error)
return (error);
@@ -301,22 +340,24 @@
* Perform priority accounting and register bridge regions for all
* ports defined in the priority table
*/
- for (int i = 0; i < ndevs; i++) {
+ for (u_int i = 0; i < ncores; i++) {
struct bhndb_region *region;
- device_t child;
+ struct bhnd_core_info *core;
+ struct bhnd_core_match md;
- child = devs[i];
+ core = &cores[i];
+ md = bhnd_core_get_match_desc(core);
/*
* Skip priority accounting for cores that ...
*/
/* ... do not require bridge resources */
- if (bhnd_is_hw_disabled(child) || !device_is_enabled(child))
+ if (BHNDB_BUS_IS_CORE_DISABLED(sc->parent_dev, sc->dev, core))
continue;
/* ... do not have a priority table entry */
- hp = bhndb_hw_priority_find_device(table, child);
+ hp = bhndb_hw_priority_find_core(table, core);
if (hp == NULL)
continue;
@@ -330,27 +371,26 @@
const struct bhndb_port_priority *pp;
pp = &hp->ports[i];
-
- /* Skip ports not defined on this device */
- if (!bhnd_is_region_valid(child, pp->type, pp->port,
- pp->region))
- {
- continue;
- }
/* Fetch the address+size of the mapped port. */
- error = bhnd_get_region_addr(child, pp->type, pp->port,
- pp->region, &addr, &size);
- if (error)
- return (error);
+ error = bhnd_erom_lookup_core_addr(erom, &md,
+ pp->type, pp->port, pp->region,
+ NULL, &addr, &size);
+ if (error) {
+ /* Skip ports not defined on this device */
+ if (error == ENOENT)
+ continue;
+
+ return (error);
+ }
/* Skip ports with an existing static mapping */
- region = bhndb_find_resource_region(r, addr, size);
+ region = bhndb_find_resource_region(br, addr, size);
if (region != NULL && region->static_regwin != NULL)
continue;
/* Define a dynamic region for this port */
- error = bhndb_add_resource_region(r, addr, size,
+ error = bhndb_add_resource_region(br, addr, size,
pp->priority, NULL);
if (error)
return (error);
@@ -375,17 +415,17 @@
/* Determine the minimum priority at which we'll allocate direct
* register windows from our dynamic pool */
size_t prio_total = prio_low + prio_default + prio_high;
- if (prio_total <= r->dwa_count) {
+ if (prio_total <= br->dwa_count) {
/* low+default+high priority regions get windows */
- r->min_prio = BHNDB_PRIORITY_LOW;
+ br->min_prio = BHNDB_PRIORITY_LOW;
- } else if (prio_default + prio_high <= r->dwa_count) {
+ } else if (prio_default + prio_high <= br->dwa_count) {
/* default+high priority regions get windows */
- r->min_prio = BHNDB_PRIORITY_DEFAULT;
+ br->min_prio = BHNDB_PRIORITY_DEFAULT;
} else {
/* high priority regions get windows */
- r->min_prio = BHNDB_PRIORITY_HIGH;
+ br->min_prio = BHNDB_PRIORITY_HIGH;
}
if (BHNDB_DEBUG(PRIO)) {
@@ -393,10 +433,10 @@
const char *direct_msg, *type_msg;
bhndb_priority_t prio, prio_min;
- prio_min = r->min_prio;
+ prio_min = br->min_prio;
device_printf(sc->dev, "min_prio: %d\n", prio_min);
- STAILQ_FOREACH(region, &r->bus_regions, link) {
+ STAILQ_FOREACH(region, &br->bus_regions, link) {
prio = region->priority;
direct_msg = prio >= prio_min ? "direct" : "indirect";
@@ -418,8 +458,8 @@
* Find a hardware specification for @p dev.
*
* @param sc The bhndb device state.
- * @param devs All devices enumerated on the bridged bhnd bus.
- * @param ndevs The length of @p devs.
+ * @param cores All cores enumerated on the bridged bhnd bus.
+ * @param ncores The length of @p cores.
* @param[out] hw On success, the matched hardware specification.
* with @p dev.
*
@@ -427,15 +467,15 @@
* @retval non-zero if an error occurs fetching device info for comparison.
*/
static int
-bhndb_find_hwspec(struct bhndb_softc *sc, device_t *devs, int ndevs,
- const struct bhndb_hw **hw)
+bhndb_find_hwspec(struct bhndb_softc *sc, struct bhnd_core_info *cores,
+ u_int ncores, const struct bhndb_hw **hw)
{
const struct bhndb_hw *next, *hw_table;
/* Search for the first matching hardware config. */
hw_table = BHNDB_BUS_GET_HARDWARE_TABLE(sc->parent_dev, sc->dev);
for (next = hw_table; next->hw_reqs != NULL; next++) {
- if (!bhndb_hw_matches(devs, ndevs, next))
+ if (!bhndb_hw_matches(cores, ncores, next))
continue;
/* Found */
@@ -447,69 +487,15 @@
}
/**
- * Read the ChipCommon identification data for this device.
- *
- * @param sc bhndb device state.
- * @param cfg The hardware configuration to use when mapping the ChipCommon
- * registers.
- * @param[out] result the chip identification data.
- *
- * @retval 0 success
- * @retval non-zero if the ChipCommon identification data could not be read.
- */
-static int
-bhndb_read_chipid(struct bhndb_softc *sc, const struct bhndb_hwcfg *cfg,
- struct bhnd_chipid *result)
-{
- const struct bhnd_chipid *parent_cid;
- const struct bhndb_regwin *cc_win;
- struct resource_spec rs;
- int error;
-
- /* Let our parent device override the discovery process */
- parent_cid = BHNDB_BUS_GET_CHIPID(sc->parent_dev, sc->dev);
- if (parent_cid != NULL) {
- *result = *parent_cid;
- return (0);
- }
-
- /* Find a register window we can use to map the first CHIPC_CHIPID_SIZE
- * of ChipCommon registers. */
- cc_win = bhndb_regwin_find_best(cfg->register_windows,
- BHND_DEVCLASS_CC, 0, BHND_PORT_DEVICE, 0, 0, CHIPC_CHIPID_SIZE);
- if (cc_win == NULL) {
- device_printf(sc->dev, "no chipcommon register window\n");
- return (0);
- }
-
- /* We can assume a device without a static ChipCommon window uses the
- * default ChipCommon address. */
- if (cc_win->win_type == BHNDB_REGWIN_T_DYN) {
- error = BHNDB_SET_WINDOW_ADDR(sc->dev, cc_win,
- BHND_DEFAULT_CHIPC_ADDR);
-
- if (error) {
- device_printf(sc->dev, "failed to set chipcommon "
- "register window\n");
- return (error);
- }
- }
-
- /* Let the default bhnd implemenation alloc/release the resource and
- * perform the read */
- rs.type = cc_win->res.type;
- rs.rid = cc_win->res.rid;
- rs.flags = RF_ACTIVE;
-
- return (bhnd_read_chipid(sc->parent_dev, &rs, cc_win->win_offset,
- result));
-}
-
-/**
* Helper function that must be called by subclass bhndb(4) drivers
* when implementing DEVICE_ATTACH() before calling any bhnd(4) or bhndb(4)
* APIs on the bridge device.
*
+ * This function will add a bridged bhnd(4) child device with a device order of
+ * BHND_PROBE_BUS. Any subclass bhndb(4) driver may use the BHND_PROBE_*
+ * priority bands to add additional devices that will be attached in
+ * their preferred order relative to the bridged bhnd(4) bus.
+ *
* @param dev The bridge device to attach.
* @param bridge_devclass The device class of the bridging core. This is used
* to automatically detect the bridge core, and to disable additional bridge
@@ -521,6 +507,7 @@
struct bhndb_devinfo *dinfo;
struct bhndb_softc *sc;
const struct bhndb_hwcfg *cfg;
+ bhnd_erom_class_t *eromcls;
int error;
sc = device_get_softc(dev);
@@ -530,30 +517,48 @@
BHNDB_LOCK_INIT(sc);
- /* Read our chip identification data */
- cfg = BHNDB_BUS_GET_GENERIC_HWCFG(sc->parent_dev, sc->dev);
- if ((error = bhndb_read_chipid(sc, cfg, &sc->chipid)))
- return (error);
-
/* Populate generic resource allocation state. */
+ cfg = BHNDB_BUS_GET_GENERIC_HWCFG(sc->parent_dev, sc->dev);
sc->bus_res = bhndb_alloc_resources(dev, sc->parent_dev, cfg);
if (sc->bus_res == NULL) {
return (ENXIO);
}
- /* Attach our bridged bus device */
- sc->bus_dev = BUS_ADD_CHILD(dev, 0, "bhnd", -1);
+ /* Allocate our host resources */
+ if ((error = bhndb_alloc_host_resources(sc->bus_res)))
+ goto failed;
+
+ /* Probe for a usable EROM class for our bridged bhnd(4) bus and
+ * populate our chip identifier. */
+ BHNDB_LOCK(sc);
+ if ((eromcls = bhndb_probe_erom_class(sc, &sc->chipid)) == NULL) {
+ BHNDB_UNLOCK(sc);
+
+ device_printf(sc->dev, "device enumeration unsupported; no "
+ "compatible driver found\n");
+ return (ENXIO);
+ }
+ BHNDB_UNLOCK(sc);
+
+ /* Add our bridged bus device */
+ sc->bus_dev = BUS_ADD_CHILD(dev, BHND_PROBE_BUS, "bhnd", -1);
if (sc->bus_dev == NULL) {
error = ENXIO;
goto failed;
}
- /* Configure address space */
dinfo = device_get_ivars(sc->bus_dev);
dinfo->addrspace = BHNDB_ADDRSPACE_BRIDGED;
- /* Finish attach */
- return (bus_generic_attach(dev));
+ /* Enumerate the bridged device and fully initialize our bridged
+ * resource configuration */
+ if ((error = bhndb_init_full_config(sc, eromcls))) {
+ device_printf(sc->dev, "initializing full bridge "
+ "configuration failed: %d\n", error);
+ goto failed;
+ }
+
+ return (0);
failed:
BHNDB_LOCK_DESTROY(sc);
@@ -564,55 +569,265 @@
return (error);
}
+
/**
- * Default bhndb(4) implementation of BHNDB_INIT_FULL_CONFIG().
+ * Return a borrowed reference to the host resource mapping at least
+ * BHND_DEFAULT_CORE_SIZE bytes at the first bus core, for use with
+ * bhnd_erom_probe().
+ *
+ * This may return a borrowed reference to a bhndb_dw_alloc-managed
+ * resource; any additional resource mapping requests may invalidate this
+ * borrowed reference.
+ *
+ * @param sc BHNDB driver state.
+ * @param[out] offset On success, the offset within the returned resource
+ * at which the first bus core can be found.
*
- * This function provides the default bhndb implementation of
- * BHNDB_INIT_FULL_CONFIG(), and must be called by any subclass driver
- * overriding BHNDB_INIT_FULL_CONFIG().
- *
- * As documented by BHNDB_INIT_FULL_CONFIG, this function performs final
- * bridge configuration based on the hardware information enumerated by the
- * child bus, and will reset all resource allocation state on the bridge.
- *
- * When calling this method:
- * - Any bus resources previously allocated by @p child must be deallocated.
- * - The @p child bus must have performed initial enumeration -- but not
- * probe or attachment -- of its children.
+ * @retval non-NULL success.
+ * @retval NULL If no usable mapping could be found.
*/
-int
-bhndb_generic_init_full_config(device_t dev, device_t child,
- const struct bhndb_hw_priority *hw_prio_table)
+static struct resource *
+bhndb_erom_chipc_resource(struct bhndb_softc *sc, bus_size_t *offset)
{
- struct bhndb_softc *sc;
- const struct bhndb_hw *hw;
- struct bhndb_resources *r;
- device_t *devs;
- device_t hostb;
- int ndevs;
- int error;
+ const struct bhndb_hwcfg *cfg;
+ struct bhndb_dw_alloc *dwa;
+ struct resource *res;
+ const struct bhndb_regwin *win;
- sc = device_get_softc(dev);
- hostb = NULL;
+ BHNDB_LOCK_ASSERT(sc, MA_OWNED);
+
+ cfg = sc->bus_res->cfg;
+
+ /* Find a static register window mapping ChipCommon. */
+ win = bhndb_regwin_find_core(cfg->register_windows, BHND_DEVCLASS_CC,
+ 0, BHND_PORT_DEVICE, 0, 0);
+ if (win != NULL) {
+ if (win->win_size < BHND_DEFAULT_CORE_SIZE) {
+ device_printf(sc->dev,
+ "chipcommon register window too small\n");
+ return (NULL);
+ }
+
+ res = bhndb_find_regwin_resource(sc->bus_res, win);
+ if (res == NULL) {
+ device_printf(sc->dev,
+ "chipcommon register window not allocated\n");
+ return (NULL);
+ }
+
+ *offset = win->win_offset;
+ return (res);
+ }
+
+ /* We'll need to fetch and configure a dynamic window. We can assume a
+ * device without a static ChipCommon mapping uses the default siba(4)
+ * base address. */
+ dwa = bhndb_io_resource(sc, BHND_DEFAULT_CHIPC_ADDR,
+ BHND_DEFAULT_CORE_SIZE, offset);
+ if (dwa != NULL)
+ return (dwa->parent_res);
+
+ device_printf(sc->dev, "unable to map chipcommon registers; no usable "
+ "register window found\n");
+ return (NULL);
+}
+
+/**
+ * Probe all supported EROM classes, returning the best matching class
+ * (or NULL if not found), writing the probed chip identifier to @p cid.
+ *
+ * @param sc BHNDB driver state.
+ * @param cid On success, the bridged chipset's chip identifier.
+ */
+static bhnd_erom_class_t *
+bhndb_probe_erom_class(struct bhndb_softc *sc, struct bhnd_chipid *cid)
+{
+ devclass_t bhndb_devclass;
+ const struct bhnd_chipid *hint;
+ struct resource *res;
+ bus_size_t res_offset;
+ driver_t **drivers;
+ int drv_count;
+ bhnd_erom_class_t *erom_cls;
+ int prio, result;
+
+ BHNDB_LOCK_ASSERT(sc, MA_OWNED);
+
+ erom_cls = NULL;
+ prio = 0;
+
+ /* Let our parent device provide a chipid hint */
+ hint = BHNDB_BUS_GET_CHIPID(sc->parent_dev, sc->dev);
+
+ /* Fetch a borrowed reference to the resource mapping ChipCommon. */
+ res = bhndb_erom_chipc_resource(sc, &res_offset);
+ if (res == NULL)
+ return (NULL);
+
+ /* Fetch all available drivers */
+ bhndb_devclass = device_get_devclass(sc->dev);
+ if (devclass_get_drivers(bhndb_devclass, &drivers, &drv_count) != 0)
+ return (NULL);
+
+ /* Enumerate the drivers looking for the best available EROM class */
+ for (int i = 0; i < drv_count; i++) {
+ struct bhnd_chipid pcid;
+ bhnd_erom_class_t *cls;
+
+ cls = bhnd_driver_get_erom_class(drivers[i]);
+ if (cls == NULL)
+ continue;
+
+ kobj_class_compile(cls);
+
+ /* Probe the bus */
+ result = bhnd_erom_probe(cls, &BHND_DIRECT_RESOURCE(res),
+ res_offset, hint, &pcid);
+
+ /* The parser did not match if an error was returned */
+ if (result > 0)
+ continue;
+
+ /* Check for a new highest priority match */
+ if (erom_cls == NULL || result > prio) {
+ prio = result;
+
+ *cid = pcid;
+ erom_cls = cls;
+ }
+
+ /* Terminate immediately on BUS_PROBE_SPECIFIC */
+ if (result == BUS_PROBE_SPECIFIC)
+ break;
+ }
+
+ return (erom_cls);
+}
+
+/* ascending core index comparison used by bhndb_find_hostb_core() */
+static int
+compare_core_index(const void *lhs, const void *rhs)
+{
+ u_int left = ((const struct bhnd_core_info *)lhs)->core_idx;
+ u_int right = ((const struct bhnd_core_info *)rhs)->core_idx;
+
+ if (left < right)
+ return (-1);
+ else if (left > right)
+ return (1);
+ else
+ return (0);
+}
+
+/**
+ * Search @p erom for the core serving as the bhnd host bridge.
+ *
+ * This function uses a heuristic valid on all known PCI/PCIe/PCMCIA-bridged
+ * bhnd(4) devices to determine the hostb core:
+ *
+ * - The core must have a Broadcom vendor ID.
+ * - The core devclass must match the bridge type.
+ * - The core must be the first device on the bus with the bridged device
+ * class.
+ *
+ * @param sc BHNDB device state.
+ * @param erom The device enumeration table parser to be used to fetch
+ * core info.
+ * @param[out] core If found, the matching core info.
+ *
+ * @retval 0 success
+ * @retval ENOENT not found
+ * @retval non-zero if an error occured fetching core info.
+ */
+static int
+bhndb_find_hostb_core(struct bhndb_softc *sc, bhnd_erom_t *erom,
+ struct bhnd_core_info *core)
+{
+ struct bhnd_core_match md;
+ struct bhnd_core_info *cores;
+ u_int ncores;
+ int error;
- /* Fetch the full set of bhnd-attached cores */
- if ((error = device_get_children(sc->bus_dev, &devs, &ndevs))) {
- device_printf(sc->dev, "unable to get children\n");
+ if ((error = bhnd_erom_get_core_table(erom, &cores, &ncores)))
return (error);
+
+ /* Set up a match descriptor for the required device class. */
+ md = (struct bhnd_core_match) {
+ BHND_MATCH_CORE_CLASS(sc->bridge_class),
+ BHND_MATCH_CORE_UNIT(0)
+ };
+
+ /* Ensure the table is sorted by core index value, ascending;
+ * the host bridge must be the absolute first matching device on the
+ * bus. */
+ qsort(cores, ncores, sizeof(*cores), compare_core_index);
+
+ /* Find the hostb core */
+ error = ENOENT;
+ for (u_int i = 0; i < ncores; i++) {
+ if (bhnd_core_matches(&cores[i], &md)) {
+ /* Found! */
+ *core = cores[i];
+ error = 0;
+ break;
+ }
}
- /* Find our host bridge device */
- hostb = BHNDB_FIND_HOSTB_DEVICE(dev, child);
- if (hostb == NULL) {
+ /* Clean up */
+ bhnd_erom_free_core_table(erom, cores);
+
+ return (error);
+}
+
+/**
+ * Identify the bridged device and perform final bridge resource configuration
+ * based on capabilities of the enumerated device.
+ *
+ * Any bridged resources allocated using the generic brige hardware
+ * configuration must be released prior to calling this function.
+ */
+static int
+bhndb_init_full_config(struct bhndb_softc *sc, bhnd_erom_class_t *eromcls)
+{
+ struct bhnd_core_info *cores;
+ struct bhndb_resources *br;
+ const struct bhndb_hw_priority *hwprio;
+ bhnd_erom_t *erom;
+ const struct bhndb_hw *hw;
+ u_int ncores;
+ int error;
+
+ erom = NULL;
+ cores = NULL;
+ br = NULL;
+
+ /* Allocate EROM parser instance */
+ erom = bhnd_erom_alloc(eromcls, &sc->chipid, sc->bus_dev, 0);
+ if (erom == NULL) {
+ device_printf(sc->dev, "failed to allocate device enumeration "
+ "table parser\n");
+ return (ENXIO);
+ }
+
+ /* Look for our host bridge core */
+ if ((error = bhndb_find_hostb_core(sc, erom, &sc->bridge_core))) {
device_printf(sc->dev, "no host bridge core found\n");
- error = ENODEV;
+ goto cleanup;
+ } else {
+ sc->have_br_core = true;
+ }
+
+ /* Fetch the bridged device's core table */
+ if ((error = bhnd_erom_get_core_table(erom, &cores, &ncores))) {
+ device_printf(sc->dev, "error fetching core table: %d\n",
+ error);
goto cleanup;
}
/* Find our full register window configuration */
- if ((error = bhndb_find_hwspec(sc, devs, ndevs, &hw))) {
+ if ((error = bhndb_find_hwspec(sc, cores, ncores, &hw))) {
device_printf(sc->dev, "unable to identify device, "
- " using generic bridge resource definitions\n");
+ " using generic bridge resource definitions\n");
error = 0;
goto cleanup;
}
@@ -620,34 +835,59 @@
if (bootverbose || BHNDB_DEBUG(PRIO))
device_printf(sc->dev, "%s resource configuration\n", hw->name);
- /* Release existing resource state */
- BHNDB_LOCK(sc);
- bhndb_free_resources(sc->bus_res);
- sc->bus_res = NULL;
- BHNDB_UNLOCK(sc);
-
- /* Allocate new resource state */
- r = bhndb_alloc_resources(dev, sc->parent_dev, hw->cfg);
- if (r == NULL) {
- error = ENXIO;
+ /* Allocate new bridge resource state using the discovered hardware
+ * configuration */
+ br = bhndb_alloc_resources(sc->dev, sc->parent_dev, hw->cfg);
+ if (br == NULL) {
+ device_printf(sc->dev,
+ "failed to allocate new resource state\n");
+ error = ENOMEM;
goto cleanup;
}
- /* Initialize our resource priority configuration */
- error = bhndb_initialize_region_cfg(sc, devs, ndevs, hw_prio_table, r);
+ /* Populate our resource priority configuration */
+ hwprio = BHNDB_BUS_GET_HARDWARE_PRIO(sc->parent_dev, sc->dev);
+ error = bhndb_init_region_cfg(sc, erom, br, cores, ncores, hwprio);
if (error) {
- bhndb_free_resources(r);
+ device_printf(sc->dev, "failed to initialize resource "
+ "priority configuration: %d\n", error);
goto cleanup;
}
- /* Update our bridge state */
- BHNDB_LOCK(sc);
- sc->bus_res = r;
- sc->hostb_dev = hostb;
- BHNDB_UNLOCK(sc);
+ /* The EROM parser holds a reference to the resource state we're
+ * about to invalidate */
+ bhnd_erom_free_core_table(erom, cores);
+ bhnd_erom_free(erom);
+
+ cores = NULL;
+ erom = NULL;
+
+ /* Replace existing resource state */
+ bhndb_free_resources(sc->bus_res);
+ sc->bus_res = br;
+
+ /* Pointer is now owned by sc->bus_res */
+ br = NULL;
+
+ /* Re-allocate host resources */
+ if ((error = bhndb_alloc_host_resources(sc->bus_res))) {
+ device_printf(sc->dev, "failed to reallocate bridge host "
+ "resources: %d\n", error);
+ goto cleanup;
+ }
+
+ return (0);
cleanup:
- free(devs, M_TEMP);
+ if (cores != NULL)
+ bhnd_erom_free_core_table(erom, cores);
+
+ if (erom != NULL)
+ bhnd_erom_free(erom);
+
+ if (br != NULL)
+ bhndb_free_resources(br);
+
return (error);
}
@@ -928,21 +1168,17 @@
/**
- * Default implementation of BHNDB_IS_HW_DISABLED().
+ * Default implementation of BHND_BUS_IS_HW_DISABLED().
*/
static bool
-bhndb_is_hw_disabled(device_t dev, device_t child) {
+bhndb_is_hw_disabled(device_t dev, device_t child)
+{
struct bhndb_softc *sc;
+ struct bhnd_core_info *bridge_core;
struct bhnd_core_info core;
sc = device_get_softc(dev);
- /* Requestor must be attached to the bhnd bus */
- if (device_get_parent(child) != sc->bus_dev) {
- return (BHND_BUS_IS_HW_DISABLED(device_get_parent(dev), child));
- }
-
- /* Fetch core info */
core = bhnd_get_core_info(child);
/* Try to defer to the bhndb bus parent */
@@ -951,78 +1187,27 @@
/* Otherwise, we treat bridge-capable cores as unpopulated if they're
* not the configured host bridge */
+ bridge_core = bhndb_get_bridge_core(sc);
if (BHND_DEVCLASS_SUPPORTS_HOSTB(bhnd_core_class(&core)))
- return (BHNDB_FIND_HOSTB_DEVICE(dev, sc->bus_dev) != child);
+ return (!bhnd_cores_equal(&core, bridge_core));
- /* Otherwise, assume the core is populated */
+ /* Assume the core is populated */
return (false);
}
-/* ascending core index comparison used by bhndb_find_hostb_device() */
-static int
-compare_core_index(const void *lhs, const void *rhs)
-{
- u_int left = bhnd_get_core_index(*(const device_t *) lhs);
- u_int right = bhnd_get_core_index(*(const device_t *) rhs);
-
- if (left < right)
- return (-1);
- else if (left > right)
- return (1);
- else
- return (0);
-}
-
/**
- * Default bhndb(4) implementation of BHND_BUS_FIND_HOSTB_DEVICE().
+ * Default bhndb(4) implementation of BHNDB_GET_HOSTB_CORE().
*
* This function uses a heuristic valid on all known PCI/PCIe/PCMCIA-bridged
- * bhnd(4) devices to determine the hostb core:
- *
- * - The core must have a Broadcom vendor ID.
- * - The core devclass must match the bridge type.
- * - The core must be the first device on the bus with the bridged device
- * class.
- *
- * @param dev The bhndb device
- * @param child The requesting bhnd bus.
+ * bhnd(4) devices.
*/
-static device_t
-bhndb_find_hostb_device(device_t dev, device_t child)
+static int
+bhndb_get_hostb_core(device_t dev, device_t child, struct bhnd_core_info *core)
{
- struct bhndb_softc *sc;
- struct bhnd_device_match md;
- device_t hostb_dev, *devlist;
- int devcnt, error;
-
- sc = device_get_softc(dev);
-
- /* Set up a match descriptor for the required device class. */
- md = (struct bhnd_device_match) {
- BHND_MATCH_CORE_CLASS(sc->bridge_class),
- BHND_MATCH_CORE_UNIT(0)
- };
-
- /* Must be the absolute first matching device on the bus. */
- if ((error = device_get_children(child, &devlist, &devcnt)))
- return (false);
-
- /* Sort by core index value, ascending */
- qsort(devlist, devcnt, sizeof(*devlist), compare_core_index);
-
- /* Find the hostb device */
- hostb_dev = NULL;
- for (int i = 0; i < devcnt; i++) {
- if (bhnd_device_matches(devlist[i], &md)) {
- hostb_dev = devlist[i];
- break;
- }
- }
-
- /* Clean up */
- free(devlist, M_TEMP);
+ struct bhndb_softc *sc = device_get_softc(dev);
- return (hostb_dev);
+ *core = *bhndb_get_bridge_core(sc);
+ return (0);
}
/**
@@ -1681,7 +1866,14 @@
}
/**
- * Find the bridge resource to be used for I/O requests.
+ * Return a borrowed reference to a bridge resource allocation record capable
+ * of handling bus I/O requests of @p size at @p addr.
+ *
+ * This will either return a reference to an existing allocation
+ * record mapping the requested space, or will configure and return a free
+ * allocation record.
+ *
+ * Will panic if a usable record cannot be found.
*
* @param sc Bridge driver state.
* @param addr The I/O target address.
@@ -1961,8 +2153,7 @@
/* BHNDB interface */
DEVMETHOD(bhndb_get_chipid, bhndb_get_chipid),
- DEVMETHOD(bhndb_init_full_config, bhndb_generic_init_full_config),
- DEVMETHOD(bhndb_find_hostb_device, bhndb_find_hostb_device),
+ DEVMETHOD(bhndb_get_hostb_core, bhndb_get_hostb_core),
DEVMETHOD(bhndb_suspend_resource, bhndb_suspend_resource),
DEVMETHOD(bhndb_resume_resource, bhndb_resume_resource),
Index: head/sys/dev/bhnd/bhndb/bhndb_bus_if.m
===================================================================
--- head/sys/dev/bhnd/bhndb/bhndb_bus_if.m
+++ head/sys/dev/bhnd/bhndb/bhndb_bus_if.m
@@ -1,5 +1,5 @@
#-
-# Copyright (c) 2015 Landon Fuller <landon@landonf.org>
+# Copyright (c) 2015-2016 Landon Fuller <landonf@FreeBSD.org>
# All rights reserved.
#
# Redistribution and use in source and binary forms, with or without
@@ -59,6 +59,12 @@
{
panic("bhndb_get_hardware_table unimplemented");
}
+
+ static const struct bhndb_hw_priority *
+ bhndb_null_get_hardware_prio(device_t dev, device_t child)
+ {
+ panic("bhndb_get_hardware_prio unimplemented");
+ }
static bool
bhndb_null_is_core_disabled(device_t dev, device_t child,
@@ -109,6 +115,18 @@
} DEFAULT bhndb_null_get_hardware_table;
/**
+ * Return the hardware priority table to be used when allocating bridge
+ * resources.
+ *
+ * @param dev The parent device.
+ * @param child The attached bhndb device.
+ */
+METHOD const struct bhndb_hw_priority * get_hardware_prio {
+ device_t dev;
+ device_t child;
+} DEFAULT bhndb_null_get_hardware_prio;
+
+/**
* Return true if the hardware required by @p core is unpopulated or
* otherwise unusable.
*
Index: head/sys/dev/bhnd/bhndb/bhndb_if.m
===================================================================
--- head/sys/dev/bhnd/bhndb/bhndb_if.m
+++ head/sys/dev/bhnd/bhndb/bhndb_if.m
@@ -61,18 +61,12 @@
{
panic("bhndb_populate_board_info unimplemented");
}
-
- static int
- bhndb_null_init_full_config(device_t dev, device_t child,
- const struct bhndb_hw_priority *priority_table)
- {
- panic("bhndb_init_full_config unimplemented");
- }
- static device_t
- bhndb_null_find_hostb_device(device_t dev, device_t child)
+ static int
+ bhndb_null_get_hostb_core(device_t dev, device_t child,
+ struct bhnd_core_info *core)
{
- panic("bhndb_find_hostb_device unimplemented");
+ panic("bhndb_get_hostb_core unimplemented");
}
static void
@@ -124,39 +118,23 @@
} DEFAULT bhndb_null_populate_board_info;
/**
- * Perform final bridge hardware configuration after @p child has fully
- * enumerated its children.
+ * Get the host bridge core info for the attached bhnd bus.
*
- * This must be called by any bhndb-attached bus device; this allows the
- * bridge to perform final configuration based on the hardware information
- * enumerated by the child bus.
- *
- * When calling this method:
- * - Any bus resources previously allocated by @p child must be deallocated.
- * - The @p child bus must have performed initial enumeration -- but not
- * probe or attachment -- of its children.
+ * @param dev The bridge device.
+ * @param child The bhnd bus device attached to @p dev.
+ * @param[out] core Will be populated with the host bridge core info, if
+ * found.
*
- * @param dev The bridge device.
- * @param child The bhnd bus device attached to @p dev.
- * @param hw_priority The hardware priority table to be used when determining
- * the bridge resource allocation strategy.
- */
-METHOD int init_full_config {
- device_t dev;
- device_t child;
- const struct bhndb_hw_priority *priority_table;
-} DEFAULT bhndb_null_init_full_config;
-
-/**
- * Locate the active host bridge core for the attached bhnd bus.
- *
- * @param dev The bridge device.
- * @param child The bhnd bus device attached to @p dev.
+ * @retval 0 success
+ * @retval ENOENT No host bridge core found.
+ * @retval non-zero If locating the host bridge core otherwise fails, a
+ * regular UNIX error code should be returned.
*/
-METHOD device_t find_hostb_device {
+METHOD int get_hostb_core {
device_t dev;
device_t child;
-} DEFAULT bhndb_null_find_hostb_device;
+ struct bhnd_core_info *core;
+} DEFAULT bhndb_null_get_hostb_core;
/**
* Mark a resource as 'suspended', gauranteeing to the bridge that no
Index: head/sys/dev/bhnd/bhndb/bhndb_pci.c
===================================================================
--- head/sys/dev/bhnd/bhndb/bhndb_pci.c
+++ head/sys/dev/bhnd/bhndb/bhndb_pci.c
@@ -62,6 +62,8 @@
#include "bhndb_pcivar.h"
#include "bhndb_private.h"
+static int bhndb_pci_add_children(struct bhndb_pci_softc *sc);
+
static int bhndb_enable_pci_clocks(struct bhndb_pci_softc *sc);
static int bhndb_disable_pci_clocks(struct bhndb_pci_softc *sc);
@@ -110,93 +112,119 @@
sc = device_get_softc(dev);
sc->dev = dev;
sc->parent = device_get_parent(dev);
+ sc->set_regwin = bhndb_pci_compat_setregwin;
- /* Enable PCI bus mastering */
- pci_enable_busmaster(sc->parent);
-
- /* Determine our bridge device class */
- sc->pci_devclass = BHND_DEVCLASS_PCI;
if (pci_find_cap(sc->parent, PCIY_EXPRESS, &reg) == 0)
sc->pci_devclass = BHND_DEVCLASS_PCIE;
+ else
+ sc->pci_devclass = BHND_DEVCLASS_PCI;
- /* Enable clocks (if supported by this hardware) */
+ /* Enable clocks (if required by this hardware) */
if ((error = bhndb_enable_pci_clocks(sc)))
- return (error);
-
- /* Use siba(4)-compatible regwin handling until we know
- * what kind of bus is attached */
- sc->set_regwin = bhndb_pci_compat_setregwin;
+ goto cleanup;
- /* Perform full bridge attach. This should call back into our
- * bhndb_pci_init_full_config() implementation once the bridged
- * bhnd(4) bus has been enumerated, but before any devices have been
- * probed or attached. */
+ /* Perform bridge attach, fully initializing the bridge
+ * configuration. */
if ((error = bhndb_attach(dev, sc->pci_devclass)))
- return (error);
+ goto cleanup;
- /* If supported, switch to the faster regwin handling */
+ /* If supported, switch to faster regwin handling */
if (sc->bhndb.chipid.chip_type != BHND_CHIPTYPE_SIBA) {
atomic_store_rel_ptr((volatile void *) &sc->set_regwin,
(uintptr_t) &bhndb_pci_fast_setregwin);
}
+ /* Enable PCI bus mastering */
+ pci_enable_busmaster(sc->parent);
+
+ /* Fix-up power on defaults for SROM-less devices. */
+ bhndb_init_sromless_pci_config(sc);
+
+ /* Add any additional child devices */
+ if ((error = bhndb_pci_add_children(sc)))
+ goto cleanup;
+
+ /* Probe and attach our children */
+ if ((error = bus_generic_attach(dev)))
+ goto cleanup;
+
return (0);
+
+cleanup:
+ device_delete_children(dev);
+ bhndb_disable_pci_clocks(sc);
+ pci_disable_busmaster(sc->parent);
+
+ return (error);
}
static int
-bhndb_pci_init_full_config(device_t dev, device_t child,
- const struct bhndb_hw_priority *hw_prio_table)
+bhndb_pci_detach(device_t dev)
{
struct bhndb_pci_softc *sc;
- device_t nv_dev;
- bus_size_t nv_sz;
int error;
sc = device_get_softc(dev);
- /* Let our parent perform standard initialization first */
- if ((error = bhndb_generic_init_full_config(dev, child, hw_prio_table)))
+ /* Attempt to detach our children */
+ if ((error = bus_generic_detach(dev)))
return (error);
- /* Fix-up power on defaults for SROM-less devices. */
- bhndb_init_sromless_pci_config(sc);
+ /* Perform generic bridge detach */
+ if ((error = bhndb_generic_detach(dev)))
+ return (error);
+
+ /* Disable clocks (if required by this hardware) */
+ if ((error = bhndb_disable_pci_clocks(sc)))
+ return (error);
+
+ /* Disable PCI bus mastering */
+ pci_disable_busmaster(sc->parent);
+
+ return (0);
+}
- /* If SPROM is mapped directly into BAR0, add NVRAM device. */
+static int
+bhndb_pci_add_children(struct bhndb_pci_softc *sc)
+{
+ bus_size_t nv_sz;
+ int error;
+
+ /**
+ * If SPROM is mapped directly into BAR0, add child NVRAM
+ * device.
+ */
nv_sz = bhndb_pci_sprom_size(sc);
if (nv_sz > 0) {
struct bhndb_devinfo *dinfo;
- const char *dname;
+ device_t child;
if (bootverbose) {
- device_printf(dev, "found SPROM (%u bytes)\n",
- (unsigned int) nv_sz);
+ device_printf(sc->dev, "found SPROM (%ju bytes)\n",
+ (uintmax_t)nv_sz);
}
- /* Add sprom device */
- dname = "bhnd_nvram";
- if ((nv_dev = BUS_ADD_CHILD(dev, 0, dname, -1)) == NULL) {
- device_printf(dev, "failed to add sprom device\n");
+ /* Add sprom device, ordered early enough to be available
+ * before the bridged bhnd(4) bus is attached. */
+ child = BUS_ADD_CHILD(sc->dev,
+ BHND_PROBE_ROOT + BHND_PROBE_ORDER_EARLY, "bhnd_nvram", -1);
+ if (child == NULL) {
+ device_printf(sc->dev, "failed to add sprom device\n");
return (ENXIO);
}
/* Initialize device address space and resource covering the
* BAR0 SPROM shadow. */
- dinfo = device_get_ivars(nv_dev);
+ dinfo = device_get_ivars(child);
dinfo->addrspace = BHNDB_ADDRSPACE_NATIVE;
- error = bus_set_resource(nv_dev, SYS_RES_MEMORY, 0,
- bhndb_pci_sprom_addr(sc), nv_sz);
+ error = bus_set_resource(child, SYS_RES_MEMORY, 0,
+ bhndb_pci_sprom_addr(sc), nv_sz);
if (error) {
- device_printf(dev,
+ device_printf(sc->dev,
"failed to register sprom resources\n");
return (error);
}
-
- /* Attach the device */
- if ((error = device_probe_and_attach(nv_dev))) {
- device_printf(dev, "sprom attach failed\n");
- return (error);
- }
}
return (0);
@@ -298,18 +326,27 @@
struct bhndb_resources *bres;
const struct bhndb_hwcfg *cfg;
const struct bhndb_regwin *win;
+ struct bhnd_core_info hostb_core;
struct resource *core_regs;
bus_size_t srom_offset;
u_int pci_cidx, sprom_cidx;
uint16_t val;
+ int error;
bres = sc->bhndb.bus_res;
cfg = bres->cfg;
- if (bhnd_get_vendor(sc->bhndb.hostb_dev) != BHND_MFGID_BCM)
+ /* Find our hostb core */
+ error = BHNDB_GET_HOSTB_CORE(sc->dev, sc->bhndb.bus_dev, &hostb_core);
+ if (error) {
+ device_printf(sc->dev, "no host bridge device found\n");
+ return;
+ }
+
+ if (hostb_core.vendor != BHND_MFGID_BCM)
return;
- switch (bhnd_get_device(sc->bhndb.hostb_dev)) {
+ switch (hostb_core.device) {
case BHND_COREID_PCI:
srom_offset = BHND_PCI_SRSH_PI_OFFSET;
break;
@@ -342,7 +379,7 @@
/* If it doesn't match host bridge's core index, update the index
* value */
- pci_cidx = bhnd_get_core_index(sc->bhndb.hostb_dev);
+ pci_cidx = hostb_core.core_idx;
if (sprom_cidx != pci_cidx) {
val &= ~BHND_PCI_SRSH_PI_MASK;
val |= (pci_cidx << BHND_PCI_SRSH_PI_SHIFT);
@@ -384,28 +421,6 @@
}
static int
-bhndb_pci_detach(device_t dev)
-{
- struct bhndb_pci_softc *sc;
- int error;
-
- sc = device_get_softc(dev);
-
- /* Disable clocks (if supported by this hardware) */
- if ((error = bhndb_disable_pci_clocks(sc)))
- return (error);
-
- /* Perform detach */
- if ((error = bhndb_generic_detach(dev)))
- return (error);
-
- /* Disable PCI bus mastering */
- pci_disable_busmaster(sc->parent);
-
- return (0);
-}
-
-static int
bhndb_pci_set_window_addr(device_t dev, const struct bhndb_regwin *rw,
bhnd_addr_t addr)
{
@@ -678,7 +693,6 @@
DEVMETHOD(bhnd_bus_pwrctl_ungate_clock, bhndb_pci_pwrctl_ungate_clock),
/* BHNDB interface */
- DEVMETHOD(bhndb_init_full_config, bhndb_pci_init_full_config),
DEVMETHOD(bhndb_set_window_addr, bhndb_pci_set_window_addr),
DEVMETHOD(bhndb_populate_board_info, bhndb_pci_populate_board_info),
Index: head/sys/dev/bhnd/bhndb/bhndb_private.h
===================================================================
--- head/sys/dev/bhnd/bhndb/bhndb_private.h
+++ head/sys/dev/bhnd/bhndb/bhndb_private.h
@@ -63,6 +63,9 @@
device_t parent_dev,
const struct bhndb_hwcfg *cfg);
+int bhndb_alloc_host_resources(
+ struct bhndb_resources *br);
+
void bhndb_free_resources(
struct bhndb_resources *br);
@@ -126,13 +129,13 @@
bhnd_port_type port_type, u_int port,
u_int region, bus_size_t min_size);
-bool bhndb_regwin_matches_device(
+bool bhndb_regwin_match_core(
const struct bhndb_regwin *regw,
- device_t dev);
+ struct bhnd_core_info *core);
-const struct bhndb_hw_priority *bhndb_hw_priority_find_device(
+const struct bhndb_hw_priority *bhndb_hw_priority_find_core(
const struct bhndb_hw_priority *table,
- device_t device);
+ struct bhnd_core_info *core);
/**
@@ -175,8 +178,9 @@
const struct bhndb_hwcfg *cfg; /**< hardware configuration */
device_t parent_dev; /**< parent device */
- struct resource_spec *res_spec; /**< parent bus resource specs */
- struct resource **res; /**< parent bus resources */
+ struct resource_spec *res_spec; /**< parent bus resource specs, or NULL if not allocated */
+ struct resource **res; /**< parent bus resources, or NULL if not allocated */
+ bool res_avail; /**< if parent bus resources have been allocated */
struct rman ht_mem_rman; /**< host memory manager */
struct rman br_mem_rman; /**< bridged memory manager */
Index: head/sys/dev/bhnd/bhndb/bhndb_subr.c
===================================================================
--- head/sys/dev/bhnd/bhndb/bhndb_subr.c
+++ head/sys/dev/bhnd/bhndb/bhndb_subr.c
@@ -196,6 +196,8 @@
bhndb_find_resource_range(struct bhndb_resources *br, rman_res_t start,
rman_res_t count)
{
+ KASSERT(br->res_avail, ("no host resources allocated"));
+
for (u_int i = 0; br->res_spec[i].type != -1; i++) {
struct resource *r = br->res[i];
@@ -230,6 +232,8 @@
{
const struct resource_spec *rspecs;
+ KASSERT(br->res_avail, ("no host resources allocated"));
+
rspecs = br->cfg->resource_specs;
for (u_int i = 0; rspecs[i].type != -1; i++) {
if (win->res.type != rspecs[i].type)
@@ -250,11 +254,11 @@
}
/**
- * Allocate and initialize a new resource state structure, allocating
- * bus resources from @p parent_dev according to @p cfg.
+ * Allocate and initialize a new resource state structure.
*
* @param dev The bridge device.
- * @param parent_dev The parent device from which resources will be allocated.
+ * @param parent_dev The parent device from which host resources should be
+ * allocated.
* @param cfg The hardware configuration to be used.
*/
struct bhndb_resources *
@@ -264,13 +268,10 @@
struct bhndb_resources *r;
const struct bhndb_regwin *win;
bus_size_t last_window_size;
- size_t res_num;
int rnid;
int error;
- bool free_parent_res;
bool free_ht_mem, free_br_mem;
- free_parent_res = false;
free_ht_mem = false;
free_br_mem = false;
@@ -315,62 +316,6 @@
goto failed;
}
-
- /* Determine our bridge resource count from the hardware config. */
- res_num = 0;
- for (size_t i = 0; cfg->resource_specs[i].type != -1; i++)
- res_num++;
-
- /* Allocate space for a non-const copy of our resource_spec
- * table; this will be updated with the RIDs assigned by
- * bus_alloc_resources. */
- r->res_spec = malloc(sizeof(r->res_spec[0]) * (res_num + 1), M_BHND,
- M_NOWAIT);
- if (r->res_spec == NULL)
- goto failed;
-
- /* Initialize and terminate the table */
- for (size_t i = 0; i < res_num; i++)
- r->res_spec[i] = cfg->resource_specs[i];
-
- r->res_spec[res_num].type = -1;
-
- /* Allocate space for our resource references */
- r->res = malloc(sizeof(r->res[0]) * res_num, M_BHND, M_NOWAIT);
- if (r->res == NULL)
- goto failed;
-
- /* Allocate resources */
- error = bus_alloc_resources(r->parent_dev, r->res_spec, r->res);
- if (error) {
- device_printf(r->dev,
- "could not allocate bridge resources on %s: %d\n",
- device_get_nameunit(r->parent_dev), error);
- goto failed;
- } else {
- free_parent_res = true;
- }
-
- /* Add allocated memory resources to our host memory resource manager */
- for (u_int i = 0; r->res_spec[i].type != -1; i++) {
- struct resource *res;
-
- /* skip non-memory resources */
- if (r->res_spec[i].type != SYS_RES_MEMORY)
- continue;
-
- /* add host resource to set of managed regions */
- res = r->res[i];
- error = rman_manage_region(&r->ht_mem_rman, rman_get_start(res),
- rman_get_end(res));
- if (error) {
- device_printf(r->dev,
- "could not register host memory region with "
- "ht_mem_rman: %d\n", error);
- goto failed;
- }
- }
-
/* Fetch the dynamic regwin count and verify that it does not exceed
* what is representable via our freelist bitstring. */
r->dwa_count = bhndb_regwin_count(cfg->register_windows,
@@ -432,16 +377,109 @@
dwa->target = 0x0;
LIST_INIT(&dwa->refs);
+ rnid++;
+ }
+
+ return (r);
+
+failed:
+ if (free_ht_mem)
+ rman_fini(&r->ht_mem_rman);
+
+ if (free_br_mem)
+ rman_fini(&r->br_mem_rman);
+
+ if (r->dw_alloc != NULL)
+ free(r->dw_alloc, M_BHND);
+
+ if (r->dwa_freelist != NULL)
+ free(r->dwa_freelist, M_BHND);
+
+ free(r, M_BHND);
+
+ return (NULL);
+}
+
+/**
+ * Allocate host resources required by @p br, and initialize
+ * internal BHNDB_ADDRSPACE_NATIVE resource manager state.
+ *
+ * @param br Resource state.
+ */
+int
+bhndb_alloc_host_resources(struct bhndb_resources *br)
+{
+ size_t res_num;
+ int error;
+
+ KASSERT(!br->res_avail, ("host resources already allocated"));
+
+ /* Determine our bridge resource count from the hardware config. */
+ res_num = 0;
+ for (size_t i = 0; br->cfg->resource_specs[i].type != -1; i++)
+ res_num++;
+
+ /* Allocate space for a non-const copy of our resource_spec
+ * table; this will be updated with the RIDs assigned by
+ * bus_alloc_resources. */
+ br->res_spec = malloc(sizeof(br->res_spec[0]) * (res_num + 1), M_BHND,
+ M_NOWAIT);
+ if (br->res_spec == NULL) {
+ error = ENOMEM;
+ goto failed;
+ }
+
+ /* Initialize and terminate the table */
+ for (size_t i = 0; i < res_num; i++)
+ br->res_spec[i] = br->cfg->resource_specs[i];
+
+ br->res_spec[res_num].type = -1;
+
+ /* Allocate space for our resource references */
+ br->res = malloc(sizeof(br->res[0]) * res_num, M_BHND, M_NOWAIT);
+ if (br->res == NULL) {
+ error = ENOMEM;
+ goto failed;
+ }
+
+ /* Allocate host resources */
+ error = bus_alloc_resources(br->parent_dev, br->res_spec, br->res);
+ if (error) {
+ device_printf(br->dev,
+ "could not allocate bridge resources on %s: %d\n",
+ device_get_nameunit(br->parent_dev), error);
+ goto failed;
+ } else {
+ br->res_avail = true;
+ }
+
+ /* Populate (and validate) parent resource references for all
+ * dynamic windows */
+ for (size_t i = 0; i < br->dwa_count; i++) {
+ struct bhndb_dw_alloc *dwa;
+ const struct bhndb_regwin *win;
+
+ dwa = &br->dw_alloc[i];
+ win = dwa->win;
/* Find and validate corresponding resource. */
- dwa->parent_res = bhndb_find_regwin_resource(r, win);
- if (dwa->parent_res == NULL)
+ dwa->parent_res = bhndb_find_regwin_resource(br, win);
+ if (dwa->parent_res == NULL) {
+ device_printf(br->dev, "no host resource found for %u "
+ "register window with offset %#jx and "
+ "size %#jx\n",
+ win->win_type,
+ (uintmax_t)win->win_offset,
+ (uintmax_t)win->win_size);
+
+ error = ENXIO;
goto failed;
+ }
if (rman_get_size(dwa->parent_res) < win->win_offset +
win->win_size)
{
- device_printf(r->dev, "resource %d too small for "
+ device_printf(br->dev, "resource %d too small for "
"register window with offset %llx and size %llx\n",
rman_get_rid(dwa->parent_res),
(unsigned long long) win->win_offset,
@@ -450,37 +488,41 @@
error = EINVAL;
goto failed;
}
+ }
- rnid++;
+ /* Add allocated memory resources to our host memory resource manager */
+ for (u_int i = 0; br->res_spec[i].type != -1; i++) {
+ struct resource *res;
+
+ /* skip non-memory resources */
+ if (br->res_spec[i].type != SYS_RES_MEMORY)
+ continue;
+
+ /* add host resource to set of managed regions */
+ res = br->res[i];
+ error = rman_manage_region(&br->ht_mem_rman,
+ rman_get_start(res), rman_get_end(res));
+ if (error) {
+ device_printf(br->dev,
+ "could not register host memory region with "
+ "ht_mem_rman: %d\n", error);
+ goto failed;
+ }
}
- return (r);
+ return (0);
failed:
- if (free_parent_res)
- bus_release_resources(r->parent_dev, r->res_spec, r->res);
+ if (br->res_avail)
+ bus_release_resources(br->parent_dev, br->res_spec, br->res);
- if (free_ht_mem)
- rman_fini(&r->ht_mem_rman);
-
- if (free_br_mem)
- rman_fini(&r->br_mem_rman);
+ if (br->res != NULL)
+ free(br->res, M_BHND);
- if (r->res != NULL)
- free(r->res, M_BHND);
+ if (br->res_spec != NULL)
+ free(br->res_spec, M_BHND);
- if (r->res_spec != NULL)
- free(r->res_spec, M_BHND);
-
- if (r->dw_alloc != NULL)
- free(r->dw_alloc, M_BHND);
-
- if (r->dwa_freelist != NULL)
- free(r->dwa_freelist, M_BHND);
-
- free (r, M_BHND);
-
- return (NULL);
+ return (error);
}
/**
@@ -510,7 +552,8 @@
}
/* Release resources allocated through our parent. */
- bus_release_resources(br->parent_dev, br->res_spec, br->res);
+ if (br->res_avail)
+ bus_release_resources(br->parent_dev, br->res_spec, br->res);
/* Clean up resource reservations */
for (size_t i = 0; i < br->dwa_count; i++) {
@@ -533,8 +576,12 @@
rman_fini(&br->br_mem_rman);
/* Free backing resource state structures */
- free(br->res, M_BHND);
- free(br->res_spec, M_BHND);
+ if (br->res != NULL)
+ free(br->res, M_BHND);
+
+ if (br->res_spec != NULL)
+ free(br->res_spec, M_BHND);
+
free(br->dw_alloc, M_BHND);
free(br->dwa_freelist, M_BHND);
}
@@ -988,33 +1035,27 @@
}
/**
- * Return true if @p regw defines a static port register window, and
- * the mapped port is actually defined on @p dev.
+ * Return true if @p regw defines a BHNDB_REGWIN_T_CORE register window
+ * that matches against @p core.
*
* @param regw A register window to match against.
- * @param dev A bhnd(4) bus device.
+ * @param core The bhnd(4) core info to match against @p regw.
*/
bool
-bhndb_regwin_matches_device(const struct bhndb_regwin *regw, device_t dev)
+bhndb_regwin_match_core(const struct bhndb_regwin *regw,
+ struct bhnd_core_info *core)
{
/* Only core windows are supported */
if (regw->win_type != BHNDB_REGWIN_T_CORE)
return (false);
/* Device class must match */
- if (bhnd_get_class(dev) != regw->d.core.class)
+ if (bhnd_core_class(core) != regw->d.core.class)
return (false);
/* Device unit must match */
- if (bhnd_get_core_unit(dev) != regw->d.core.unit)
- return (false);
-
- /* The regwin port/region must be defined. */
- if (!bhnd_is_region_valid(dev, regw->d.core.port_type, regw->d.core.port,
- regw->d.core.region))
- {
+ if (core->unit != regw->d.core.unit)
return (false);
- }
/* Matches */
return (true);
@@ -1022,22 +1063,19 @@
/**
* Search for a core resource priority descriptor in @p table that matches
- * @p device.
+ * @p core.
*
* @param table The table to search.
- * @param device A bhnd(4) bus device.
+ * @param core The core to match against @p table.
*/
const struct bhndb_hw_priority *
-bhndb_hw_priority_find_device(const struct bhndb_hw_priority *table,
- device_t device)
+bhndb_hw_priority_find_core(const struct bhndb_hw_priority *table,
+ struct bhnd_core_info *core)
{
const struct bhndb_hw_priority *hp;
- struct bhnd_core_info ci;
-
- ci = bhnd_get_core_info(device);
for (hp = table; hp->ports != NULL; hp++) {
- if (bhnd_core_matches(&ci, &hp->match))
+ if (bhnd_core_matches(core, &hp->match))
return (hp);
}
Index: head/sys/dev/bhnd/bhndb/bhndbvar.h
===================================================================
--- head/sys/dev/bhnd/bhndb/bhndbvar.h
+++ head/sys/dev/bhnd/bhndb/bhndbvar.h
@@ -89,12 +89,12 @@
device_t dev; /**< bridge device */
struct bhnd_chipid chipid; /**< chip identification */
bhnd_devclass_t bridge_class; /**< bridge core type */
+ struct bhnd_core_info bridge_core; /**< bridge core. not populated until
+ * full bridge config is initialized */
+ bool have_br_core; /**< false if not yet available */
device_t parent_dev; /**< parent device */
device_t bus_dev; /**< child bhnd(4) bus */
- device_t hostb_dev; /**< child host bridge device, or NULL
- if the @p bus_dev has not yet
- called BHNDB_INIT_FULL_CONFIG() */
struct mtx sc_mtx; /**< resource lock. */
struct bhndb_resources *bus_res; /**< bus resource state */
Index: head/sys/dev/bhnd/cores/chipc/chipcreg.h
===================================================================
--- head/sys/dev/bhnd/cores/chipc/chipcreg.h
+++ head/sys/dev/bhnd/cores/chipc/chipcreg.h
@@ -25,12 +25,6 @@
#ifndef _BHND_CORES_CHIPC_CHIPCREG_H_
#define _BHND_CORES_CHIPC_CHIPCREG_H_
-#define CHIPC_CHIPID_SIZE 0x100 /**< size of the register block
- containing the chip
- identification registers
- required during bus
- enumeration */
-
/** Evaluates to true if the given ChipCommon core revision supports
* the CHIPC_CORECTRL register */
#define CHIPC_HWREV_HAS_CORECTRL(hwrev) ((hwrev) >= 1)
Index: head/sys/dev/bhnd/siba/siba.c
===================================================================
--- head/sys/dev/bhnd/siba/siba.c
+++ head/sys/dev/bhnd/siba/siba.c
@@ -44,6 +44,12 @@
#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 @@
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 @@
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 @@
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 @@
* 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 @@
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 @@
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),
Index: head/sys/dev/bhnd/siba/siba_bhndb.c
===================================================================
--- head/sys/dev/bhnd/siba/siba_bhndb.c
+++ head/sys/dev/bhnd/siba/siba_bhndb.c
@@ -101,35 +101,28 @@
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 @@
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 @@
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) {
Index: head/sys/dev/bhnd/siba/siba_erom.c
===================================================================
--- head/sys/dev/bhnd/siba/siba_erom.c
+++ head/sys/dev/bhnd/siba/siba_erom.c
@@ -46,117 +46,110 @@
#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);
-struct siba_erom {
- struct bhnd_erom obj;
+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);
+
+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;
-
- /* 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);
- }
-
- /* Identify the chipset */
- idreg = siba_erom_read_4(sc, 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_init_common(struct siba_erom *sc)
-{
- struct bhnd_chipid cid;
int error;
- /* There's always at least one core */
- sc->ncores = 1;
-
- /* Identify the chipset */
- if ((error = siba_erom_read_chipid(sc, SIBA_ENUM_ADDR, &cid)))
- return (error);
+ /* Try using the provided hint. */
+ if (hint != NULL) {
+ struct siba_core_id sid;
- /* Verify the chip type */
- if (cid.chip_type != BHND_CHIPTYPE_SIBA)
- return (ENXIO);
+ /* Validate bus type */
+ if (hint->chip_type != BHND_CHIPTYPE_SIBA)
+ return (ENXIO);
+
+ /*
+ * 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).
+ */
+
+ sid = siba_eio_read_core_id(io, 0, 0);
+
+ if (sid.core_info.vendor != BHND_MFGID_BCM)
+ return (ENXIO);
+
+ if (sid.core_info.device == BHND_COREID_CC)
+ return (EINVAL);
+
+ *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,89 +158,211 @@
* 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;
- /* 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);
+ /* 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);
+
+ /* 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->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));
- sc->res = NULL;
- sc->rid = -1;
+ 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
@@ -264,12 +379,12 @@
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 @@
/* 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 @@
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 @@
}
/* 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 @@
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 @@
}
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),
Index: head/sys/dev/bhnd/siba/siba_nexus.c
===================================================================
--- head/sys/dev/bhnd/siba/siba_nexus.c
+++ head/sys/dev/bhnd/siba/siba_nexus.c
@@ -84,18 +84,21 @@
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;
+
+ /* Delegate remainder to standard bhnd method implementation */
+ if ((error = bhnd_generic_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);
- }
+ return (0);
- return (siba_attach(dev));
+failed:
+ device_delete_children(dev);
+ return (error);
}
static const struct bhnd_chipid *
Index: head/sys/dev/bhnd/siba/sibavar.h
===================================================================
--- head/sys/dev/bhnd/siba/sibavar.h
+++ head/sys/dev/bhnd/siba/sibavar.h
@@ -60,8 +60,7 @@
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 @@
#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_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_ */
Index: head/sys/dev/bwn/if_bwn_pci.c
===================================================================
--- head/sys/dev/bwn/if_bwn_pci.c
+++ head/sys/dev/bwn/if_bwn_pci.c
@@ -1,5 +1,5 @@
/*-
- * Copyright (c) 2015 Landon Fuller <landon@landonf.org>
+ * Copyright (c) 2015-2016 Landon Fuller <landonf@FreeBSD.org>
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
@@ -42,6 +42,7 @@
#include <dev/pci/pcivar.h>
#include <dev/bhnd/bhndb/bhndb_pcivar.h>
+#include <dev/bhnd/bhndb/bhndb_hwdata.h>
#include <dev/bhnd/bhndb/bhndb_pci_hwdata.h>
#include <dev/bhnd/bhnd_ids.h>
@@ -115,12 +116,14 @@
{
.bridge_hwcfg = &bhndb_pci_siba_generic_hwcfg,
.bridge_hwtable = bhndb_pci_generic_hw_table,
+ .bridge_hwprio = bhndb_siba_priority_table,
.devices = siba_devices
},
/* BCMA devices */
{
.bridge_hwcfg = &bhndb_pci_bcma_generic_hwcfg,
.bridge_hwtable = bhndb_pci_generic_hw_table,
+ .bridge_hwprio = bhndb_bcma_priority_table,
.devices = bcma_devices
},
{ NULL, NULL, NULL }
@@ -234,6 +237,13 @@
return (sc->devcfg->bridge_hwtable);
}
+static const struct bhndb_hw_priority *
+bwn_pci_get_bhndb_hwprio(device_t dev, device_t child)
+{
+ struct bwn_pci_softc *sc = device_get_softc(dev);
+ return (sc->devcfg->bridge_hwprio);
+}
+
static bool
bwn_pci_is_core_disabled(device_t dev, device_t child,
struct bhnd_core_info *core)
@@ -274,6 +284,7 @@
/* BHNDB_BUS Interface */
DEVMETHOD(bhndb_bus_get_generic_hwcfg, bwn_pci_get_generic_hwcfg),
DEVMETHOD(bhndb_bus_get_hardware_table, bwn_pci_get_bhndb_hwtable),
+ DEVMETHOD(bhndb_bus_get_hardware_prio, bwn_pci_get_bhndb_hwprio),
DEVMETHOD(bhndb_bus_is_core_disabled, bwn_pci_is_core_disabled),
DEVMETHOD_END
Index: head/sys/dev/bwn/if_bwn_pcivar.h
===================================================================
--- head/sys/dev/bwn/if_bwn_pcivar.h
+++ head/sys/dev/bwn/if_bwn_pcivar.h
@@ -1,5 +1,5 @@
/*-
- * Copyright (c) 2015 Landon Fuller <landon@landonf.org>
+ * Copyright (c) 2015-2016 Landon Fuller <landonf@FreeBSD.org>
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
@@ -87,7 +87,8 @@
struct bwn_pci_devcfg {
const struct bhndb_hwcfg *bridge_hwcfg;
const struct bhndb_hw *bridge_hwtable;
+ const struct bhndb_hw_priority *bridge_hwprio;
const struct bwn_pci_device *devices;
};
-#endif /* _IF_BWN_PCIVAR_H_ */
\ No newline at end of file
+#endif /* _IF_BWN_PCIVAR_H_ */
Index: head/sys/mips/broadcom/bcm_machdep.c
===================================================================
--- head/sys/mips/broadcom/bcm_machdep.c
+++ head/sys/mips/broadcom/bcm_machdep.c
@@ -219,7 +219,8 @@
kobj_class_compile_static(cls, &kops);
/* Probe the bus address */
- result = bhnd_erom_probe_static(cls, bst, bsh, bus_addr, &pcid);
+ result = bhnd_erom_probe_static(cls, bst, bsh, bus_addr, NULL,
+ &pcid);
/* Drop pointer to stack allocated ops table */
cls->ops = NULL;
@@ -253,7 +254,7 @@
/* ... and initialize the erom parser instance */
bsh = BCM_SOC_BSH(cid->enum_addr, 0);
- error = bhnd_erom_init_static(*erom_cls, erom, esize,
+ error = bhnd_erom_init_static(*erom_cls, erom, esize, cid,
mips_bus_space_generic, bsh);
return (error);
Index: head/sys/modules/bhnd/bhndb/Makefile
===================================================================
--- head/sys/modules/bhnd/bhndb/Makefile
+++ head/sys/modules/bhnd/bhndb/Makefile
@@ -9,6 +9,7 @@
bhndb_if.c bhndb_if.h
SRCS+= bhnd_bus_if.h \
bhnd_chipc_if.h \
+ bhnd_erom_if.h \
bhnd_nvram_if.h
SRCS+= device_if.h bus_if.h pci_if.h

File Metadata

Mime Type
text/plain
Expires
Fri, Nov 21, 9:37 PM (7 h, 49 m)
Storage Engine
blob
Storage Format
Raw Data
Storage Handle
25809152
Default Alt Text
D7768.id.diff (121 KB)

Event Timeline