Page Menu
Home
FreeBSD
Search
Configure Global Search
Log In
Files
F136976416
D7768.id.diff
No One
Temporary
Actions
View File
Edit File
Delete File
View Transforms
Subscribe
Mute Notifications
Flag For Later
Award Token
Size
121 KB
Referenced Files
None
Subscribers
None
D7768.id.diff
View Options
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, ®) == 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
Details
Attached
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)
Attached To
Mode
D7768: Migrate bhndb(4) to the new bhnd_erom API.
Attached
Detach File
Event Timeline
Log In to Comment