[bhnd] Replace is_hostb_device() with a more general find_hostb_device()

This allows bus children to query for the host bridge device, rather
than having to iterate over all attached devices.

Submitted by:	Landon Fuller <landonf@landonf.org>
Differential Revision:	https://reviews.freebsd.org/D6193
This commit is contained in:
Adrian Chadd 2016-05-08 17:52:12 +00:00
parent 7206c4fc60
commit d935257080
12 changed files with 86 additions and 75 deletions

View File

@ -194,6 +194,14 @@ bcma_get_resource_list(device_t dev, device_t child)
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)
@ -471,6 +479,7 @@ static device_method_t bcma_methods[] = {
DEVMETHOD(bus_get_resource_list, bcma_get_resource_list),
/* BHND interface */
DEVMETHOD(bhnd_bus_find_hostb_device, bcma_find_hostb_device),
DEVMETHOD(bhnd_bus_reset_core, bcma_reset_core),
DEVMETHOD(bhnd_bus_suspend_core, bcma_suspend_core),
DEVMETHOD(bhnd_bus_get_port_count, bcma_get_port_count),

View File

@ -65,14 +65,16 @@ bcma_bhndb_probe(device_t dev)
static int
bcma_bhndb_attach(device_t dev)
{
struct bcma_softc *sc;
const struct bhnd_chipid *cid;
struct resource *erom_res;
int error;
int rid;
cid = BHNDB_GET_CHIPID(device_get_parent(dev), dev);
sc = device_get_softc(dev);
/* Map the EROM resource and enumerate our children. */
cid = BHNDB_GET_CHIPID(device_get_parent(dev), dev);
rid = 0;
erom_res = bus_alloc_resource(dev, SYS_RES_MEMORY, &rid, cid->enum_addr,
cid->enum_addr + BCMA_EROM_TABLE_SIZE, BCMA_EROM_TABLE_SIZE,
@ -95,6 +97,9 @@ bcma_bhndb_attach(device_t dev)
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 */
return (bcma_attach(dev));
}

View File

@ -144,6 +144,7 @@ struct bcma_devinfo {
/** 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_ */

View File

@ -347,7 +347,7 @@ bhnd_generic_get_probe_order(device_t dev, device_t child)
case BHND_DEVCLASS_EROM:
case BHND_DEVCLASS_OTHER:
case BHND_DEVCLASS_INVALID:
if (bhnd_is_hostb_device(child))
if (bhnd_find_hostb_device(dev) == child)
return (BHND_PROBE_ROOT + BHND_PROBE_ORDER_EARLY);
return (BHND_PROBE_DEFAULT);
@ -676,7 +676,6 @@ static device_method_t bhnd_methods[] = {
DEVMETHOD(bhnd_bus_get_chipid, bhnd_bus_generic_get_chipid),
DEVMETHOD(bhnd_bus_get_probe_order, bhnd_generic_get_probe_order),
DEVMETHOD(bhnd_bus_is_region_valid, bhnd_generic_is_region_valid),
DEVMETHOD(bhnd_bus_is_hostb_device, bhnd_bus_generic_is_hostb_device),
DEVMETHOD(bhnd_bus_is_hw_disabled, bhnd_bus_generic_is_hw_disabled),
DEVMETHOD(bhnd_bus_read_nvram_var, bhnd_generic_read_nvram_var),
DEVMETHOD(bhnd_bus_read_1, bhnd_read_1),

View File

@ -335,8 +335,6 @@ void bhnd_set_custom_core_desc(device_t dev,
void bhnd_set_default_core_desc(device_t dev);
bool bhnd_bus_generic_is_hostb_device(device_t dev,
device_t child);
bool bhnd_bus_generic_is_hw_disabled(device_t dev,
device_t child);
bool bhnd_bus_generic_is_region_valid(device_t dev,
@ -364,14 +362,14 @@ int bhnd_bus_generic_deactivate_resource (device_t dev,
/**
* Return true if @p dev is serving as a host bridge for its parent bhnd
* bus.
* Return the active host bridge core for the bhnd bus, if any, or NULL if
* not found.
*
* @param dev A bhnd bus child device.
* @param dev A bhnd bus device.
*/
static inline bool
bhnd_is_hostb_device(device_t dev) {
return (BHND_BUS_IS_HOSTB_DEVICE(device_get_parent(dev), dev));
static inline device_t
bhnd_find_hostb_device(device_t dev) {
return (BHND_BUS_FIND_HOSTB_DEVICE(dev));
}
/**

View File

@ -55,10 +55,10 @@ CODE {
panic("bhnd_bus_get_chipid unimplemented");
}
static bool
bhnd_bus_null_is_hostb_device(device_t dev, device_t child)
static device_t
bhnd_bus_null_find_hostb_device(device_t dev)
{
panic("bhnd_bus_is_hostb_device unimplemented");
panic("bhnd_bus_find_hostb_device unimplemented");
}
static bool
@ -105,19 +105,16 @@ CODE {
}
/**
* Returns true if @p child is serving as a host bridge for the bhnd
* bus.
* Return the active host bridge core for the bhnd bus, if any.
*
* The default implementation will walk the parent device tree until
* the root node is hit, returning false.
* @param dev The bhnd bus device.
*
* @param dev The device whose child is being examined.
* @param child The child device.
* @retval device_t if a hostb device exists
* @retval NULL if no hostb device is found.
*/
METHOD bool is_hostb_device {
METHOD device_t find_hostb_device {
device_t dev;
device_t child;
} DEFAULT bhnd_bus_null_is_hostb_device;
} DEFAULT bhnd_bus_null_find_hostb_device;
/**
* Return true if the hardware components required by @p child are unpopulated

View File

@ -486,7 +486,11 @@ const struct bhnd_device *
bhnd_device_lookup(device_t dev, const struct bhnd_device *table,
size_t entry_size)
{
const struct bhnd_device *entry;
const struct bhnd_device *entry;
device_t hostb, parent;
parent = device_get_parent(dev);
hostb = bhnd_find_hostb_device(parent);
for (entry = table; entry->desc != NULL; entry =
(const struct bhnd_device *) ((const char *) entry + entry_size))
@ -496,8 +500,8 @@ bhnd_device_lookup(device_t dev, const struct bhnd_device *table,
continue;
/* match device flags */
if (entry->device_flags & BHND_DF_HOSTB) {
if (!bhnd_is_hostb_device(dev))
if (entry->device_flags & BHND_DF_HOSTB) {
if (dev != hostb)
continue;
}
@ -737,24 +741,6 @@ bhnd_set_default_core_desc(device_t dev)
bhnd_set_custom_core_desc(dev, bhnd_get_device_name(dev));
}
/**
* Helper function for implementing BHND_BUS_IS_HOSTB_DEVICE().
*
* If a parent device is available, this implementation delegates the
* request to the BHND_BUS_IS_HOSTB_DEVICE() method on the parent of @p dev.
*
* If no parent device is available (i.e. on a the bus root), false
* is returned.
*/
bool
bhnd_bus_generic_is_hostb_device(device_t dev, device_t child) {
if (device_get_parent(dev) != NULL)
return (BHND_BUS_IS_HOSTB_DEVICE(device_get_parent(dev),
child));
return (false);
}
/**
* Helper function for implementing BHND_BUS_IS_HW_DISABLED().
*

View File

@ -589,18 +589,12 @@ bhndb_generic_init_full_config(device_t dev, device_t child,
sc = device_get_softc(dev);
hostb = NULL;
/* Fetch the full set of attached devices */
/* Fetch the full set of bhnd-attached cores */
if ((error = device_get_children(sc->bus_dev, &devs, &ndevs)))
return (error);
/* Find our host bridge device */
for (int i = 0; i < ndevs; i++) {
if (bhnd_is_hostb_device(devs[i])) {
hostb = devs[i];
break;
}
}
hostb = BHNDB_FIND_HOSTB_DEVICE(dev, child);
if (hostb == NULL) {
device_printf(sc->dev, "no host bridge core found\n");
error = ENODEV;
@ -950,13 +944,13 @@ bhndb_is_hw_disabled(device_t dev, device_t child) {
/* Otherwise, we treat bridge-capable cores as unpopulated if they're
* not the configured host bridge */
if (BHND_DEVCLASS_SUPPORTS_HOSTB(bhnd_core_class(&core)))
return (!BHND_BUS_IS_HOSTB_DEVICE(dev, child));
return (BHNDB_FIND_HOSTB_DEVICE(dev, sc->bus_dev) != child);
/* Otherwise, assume the core is populated */
return (false);
}
/* ascending core index comparison used by bhndb_is_hostb_device() */
/* ascending core index comparison used by bhndb_find_hostb_device() */
static int
compare_core_index(const void *lhs, const void *rhs)
{
@ -972,7 +966,7 @@ compare_core_index(const void *lhs, const void *rhs)
}
/**
* Default bhndb(4) implementation of BHND_BUS_IS_HOSTB_DEVICE().
* Default bhndb(4) implementation of BHND_BUS_FIND_HOSTB_DEVICE().
*
* This function uses a heuristic valid on all known PCI/PCIe/PCMCIA-bridged
* bhnd(4) devices to determine the hostb core:
@ -982,27 +976,19 @@ compare_core_index(const void *lhs, const void *rhs)
* - The core must be the first device on the bus with the bridged device
* class.
*
* @param sc The bridge device state.
* @param cores The table of bridge-enumerated cores.
* @param num_cores The length of @p cores.
* @param core The core to check.
* @param dev The bhndb device
* @param child The requesting bhnd bus.
*/
static bool
bhndb_is_hostb_device(device_t dev, device_t child)
static device_t
bhndb_find_hostb_device(device_t dev, device_t child)
{
struct bhndb_softc *sc;
struct bhnd_core_match md;
device_t hostb_dev, *devlist;
int devcnt, error;
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_HOSTB_DEVICE(device_get_parent(dev),
child));
/* Determine required device class and set up a match descriptor. */
md = (struct bhnd_core_match) {
.vendor = BHND_MFGID_BCM,
@ -1011,19 +997,15 @@ bhndb_is_hostb_device(device_t dev, device_t child)
.class = sc->bridge_class,
.unit = 0
};
/* Pre-screen the device before searching over the full device list. */
if (!bhnd_device_matches(child, &md))
return (false);
/* Must be the absolute first matching device on the bus. */
if ((error = device_get_children(sc->bus_dev, &devlist, &devcnt)))
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 actual hostb device */
/* Find the hostb device */
hostb_dev = NULL;
for (int i = 0; i < devcnt; i++) {
if (bhnd_device_matches(devlist[i], &md)) {
@ -1035,7 +1017,7 @@ bhndb_is_hostb_device(device_t dev, device_t child)
/* Clean up */
free(devlist, M_TEMP);
return (child == hostb_dev);
return (hostb_dev);
}
/**
@ -1922,12 +1904,12 @@ static device_method_t bhndb_methods[] = {
/* 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_suspend_resource, bhndb_suspend_resource),
DEVMETHOD(bhndb_resume_resource, bhndb_resume_resource),
/* BHND interface */
DEVMETHOD(bhnd_bus_is_hw_disabled, bhndb_is_hw_disabled),
DEVMETHOD(bhnd_bus_is_hostb_device, bhndb_is_hostb_device),
DEVMETHOD(bhnd_bus_get_chipid, bhndb_get_chipid),
DEVMETHOD(bhnd_bus_activate_resource, bhndb_activate_bhnd_resource),
DEVMETHOD(bhnd_bus_deactivate_resource, bhndb_deactivate_bhnd_resource),

View File

@ -62,6 +62,12 @@ CODE {
panic("bhndb_init_full_config unimplemented");
}
static device_t
bhndb_null_find_hostb_device(device_t dev, device_t child)
{
panic("bhndb_find_hostb_device unimplemented");
}
static void
bhndb_null_suspend_resource(device_t dev, device_t child, int type,
struct resource *r)
@ -119,6 +125,17 @@ METHOD int init_full_config {
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.
*/
METHOD device_t find_hostb_device {
device_t dev;
device_t child;
} DEFAULT bhndb_null_find_hostb_device;
/**
* Mark a resource as 'suspended', gauranteeing to the bridge that no
* further use of the resource will be made until BHNDB_RESUME_RESOURCE()

View File

@ -216,6 +216,15 @@ siba_get_resource_list(device_t dev, device_t child)
return (&dinfo->resources);
}
static device_t
siba_find_hostb_device(device_t dev)
{
struct siba_softc *sc = device_get_softc(dev);
/* This is set (or not) by the concrete siba driver subclass. */
return (sc->hostb_dev);
}
static int
siba_reset_core(device_t dev, device_t child, uint16_t flags)
{
@ -662,6 +671,7 @@ static device_method_t siba_methods[] = {
DEVMETHOD(bus_get_resource_list, siba_get_resource_list),
/* BHND interface */
DEVMETHOD(bhnd_bus_find_hostb_device, siba_find_hostb_device),
DEVMETHOD(bhnd_bus_reset_core, siba_reset_core),
DEVMETHOD(bhnd_bus_suspend_core, siba_suspend_core),
DEVMETHOD(bhnd_bus_get_port_count, siba_get_port_count),

View File

@ -73,9 +73,12 @@ siba_bhndb_probe(device_t dev)
static int
siba_bhndb_attach(device_t dev)
{
struct siba_softc *sc;
const struct bhnd_chipid *chipid;
int error;
sc = device_get_softc(dev);
/* Enumerate our children. */
chipid = BHNDB_GET_CHIPID(device_get_parent(dev), dev);
if ((error = siba_add_children(dev, chipid)))
@ -87,6 +90,9 @@ siba_bhndb_attach(device_t dev)
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 */
return (siba_attach(dev));
}

View File

@ -145,6 +145,7 @@ struct siba_devinfo {
/** siba(4) per-instance state */
struct siba_softc {
struct bhnd_softc bhnd_sc; /**< bhnd state */
device_t hostb_dev; /**< host bridge core, or NULL */
};
#endif /* _SIBA_SIBAVAR_H_ */