Migrate bhndb(4) to the new bhnd_erom API.
Adds support for probing and initializing bhndb(4) bridge state using the bhnd_erom API, ensuring that full bridge configuration is available *prior* to actually attaching and enumerating the bhnd(4) child device, allowing us to safely allocate bus-level agent/device resources during bhnd(4) bus enumeration. - Add a bhnd_erom_probe() method usable by bhndb(4). This is an analogue to the existing bhnd_erom_probe_static() method, and allows the bhndb bridge to discover the best available erom parser class prior to newbus probing of its children. - Add support for supplying identification hints when probing erom devices. This is required on early EXTIF-only chipsets, where chip identification registers are not available. - Migrate bhndb over to the new bhnd_erom API, using bhnd_core_info records rather than bridged bhnd(4) device_t references to determine the bridged chipsets' capability/bridge configuration. - The bhndb parent (e.g. if_bwn) is now required to supply a hardware priority table to the bridge. The default table is currently sufficient for our supported devices. - Drop the two-pass attach approach we used for compatibility with bhndb(4) in the bhnd(4) bus drivers, and instead perform bus enumeration immediately, and allocate bridged per-child bus-level resources during that enumeration. Approved by: adrian (mentor) Differential Revision: https://reviews.freebsd.org/D7768
This commit is contained in:
parent
3da0f3c9ae
commit
111d7cb2e3
Notes:
svn2git
2020-12-20 02:59:44 +00:00
svn path=/head/; revision=305371
@ -48,6 +48,12 @@ __FBSDID("$FreeBSD$");
|
||||
/* 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 @@ bcma_probe(device_t dev)
|
||||
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 @@ 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)
|
||||
{
|
||||
@ -516,8 +468,7 @@ bcma_add_children(device_t bus)
|
||||
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 @@ bcma_add_children(device_t bus)
|
||||
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 @@ bcma_add_children(device_t bus)
|
||||
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 @@ 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_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),
|
||||
|
@ -72,26 +72,21 @@ bcma_bhndb_probe(device_t dev)
|
||||
static int
|
||||
bcma_bhndb_attach(device_t dev)
|
||||
{
|
||||
struct bcma_softc *sc;
|
||||
int error;
|
||||
int error;
|
||||
|
||||
sc = device_get_softc(dev);
|
||||
/* Perform initial attach and enumerate our children. */
|
||||
if ((error = bcma_attach(dev)))
|
||||
goto failed;
|
||||
|
||||
/* Enumerate our children. */
|
||||
if ((error = bcma_add_children(dev)))
|
||||
return (error);
|
||||
/* 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);
|
||||
return (0);
|
||||
|
||||
/* 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));
|
||||
failed:
|
||||
device_delete_children(dev);
|
||||
return (error);
|
||||
}
|
||||
|
||||
static int
|
||||
|
@ -58,7 +58,13 @@ __FBSDID("$FreeBSD$");
|
||||
* 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_seek_next(struct bcma_erom *erom,
|
||||
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 @@ static void bcma_erom_to_core_info(const struct bcma_erom_core *core,
|
||||
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 @@ static void bcma_erom_to_core_info(const struct bcma_erom_core *core,
|
||||
} \
|
||||
} 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 @@ bcma_erom_entry_type_name (uint8_t entry)
|
||||
}
|
||||
}
|
||||
|
||||
static int
|
||||
bcma_erom_init(bhnd_erom_t *erom, device_t parent, int rid, bus_addr_t enum_addr)
|
||||
|
||||
/**
|
||||
* 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)
|
||||
{
|
||||
struct bcma_erom *sc = (struct bcma_erom *)erom;
|
||||
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, const struct bhnd_chipid *cid,
|
||||
device_t parent, int rid)
|
||||
{
|
||||
struct bcma_erom *sc;
|
||||
struct bhnd_resource *res;
|
||||
|
||||
sc = (struct bcma_erom *)erom;
|
||||
sc->dev = parent;
|
||||
|
||||
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)
|
||||
return (ENOMEM);
|
||||
|
||||
sc->start = BCMA_EROM_TABLE_START;
|
||||
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);
|
||||
|
||||
if (res == NULL)
|
||||
return (ENOMEM);
|
||||
|
||||
bcma_eio_init(&sc->io, res, rid, BCMA_EROM_TABLE_START);
|
||||
|
||||
return (0);
|
||||
}
|
||||
|
||||
/* BCMA implementation of BHND_EROM_INIT_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_init_static(bhnd_erom_t *erom, const struct bhnd_chipid *cid,
|
||||
bus_space_tag_t bst, bus_space_handle_t bsh)
|
||||
{
|
||||
uint32_t idreg, eaddr;
|
||||
uint8_t chip_type;
|
||||
struct bcma_erom *sc;
|
||||
|
||||
idreg = bus_space_read_4(bst, bsh, CHIPC_ID);
|
||||
chip_type = CHIPC_GET_BITS(idreg, CHIPC_ID_BUS);
|
||||
sc = (struct bcma_erom *)erom;
|
||||
sc->dev = NULL;
|
||||
sc->offset = 0;
|
||||
|
||||
/* Fetch EROM physical address */
|
||||
if (!BHND_CHIPTYPE_HAS_EROM(chip_type))
|
||||
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_common(struct bcma_erom_io *io, const struct bhnd_chipid *hint,
|
||||
struct bhnd_chipid *cid)
|
||||
{
|
||||
uint32_t idreg, eromptr;
|
||||
|
||||
/* Hints aren't supported; all BCMA devices have a ChipCommon
|
||||
* core */
|
||||
if (hint != NULL)
|
||||
return (EINVAL);
|
||||
|
||||
/* 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 @@ bcma_erom_probe_static(bhnd_erom_class_t *cls, bus_space_tag_t bst,
|
||||
|
||||
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 @@ bcma_erom_seek(struct bcma_erom *erom, bus_size_t offset)
|
||||
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 @@ bcma_erom_next_corecfg(struct bcma_erom *erom, struct bcma_corecfg **result)
|
||||
}
|
||||
|
||||
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),
|
||||
|
@ -42,25 +42,6 @@ struct bcma_erom;
|
||||
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 */
|
||||
|
@ -93,10 +93,19 @@ bcma_nexus_attach(device_t dev)
|
||||
{
|
||||
int error;
|
||||
|
||||
if ((error = bcma_add_children(dev)))
|
||||
return (error);
|
||||
/* Perform initial attach and enumerate our children. */
|
||||
if ((error = bcma_attach(dev)))
|
||||
goto failed;
|
||||
|
||||
return (bcma_attach(dev));
|
||||
/* 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 const struct bhnd_chipid *
|
||||
|
@ -43,6 +43,10 @@ __FBSDID("$FreeBSD$");
|
||||
|
||||
#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 @@ bcma_init_dinfo(device_t bus, struct bcma_devinfo *dinfo,
|
||||
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.
|
||||
*
|
||||
|
@ -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 @@ struct bcma_devinfo *bcma_alloc_dinfo(device_t bus);
|
||||
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 @@ 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_ */
|
||||
|
@ -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 @@ struct bhnd_resource {
|
||||
* 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 *bhnd_find_core(
|
||||
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 @@ int bhnd_bus_generic_deactivate_resource (device_t dev,
|
||||
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
|
||||
|
@ -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 @@ CODE {
|
||||
#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 @@ CODE {
|
||||
static device_t
|
||||
bhnd_bus_null_find_hostb_device(device_t dev)
|
||||
{
|
||||
panic("bhnd_bus_find_hostb_device unimplemented");
|
||||
return (NULL);
|
||||
}
|
||||
|
||||
static bool
|
||||
@ -198,6 +205,15 @@ CODE {
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* 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.
|
||||
*
|
||||
|
@ -45,15 +45,15 @@ __FBSDID("$FreeBSD$");
|
||||
* 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 @@ bhnd_erom_alloc(bhnd_erom_class_t *cls, device_t parent, int rid,
|
||||
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 @@ bhnd_erom_alloc(bhnd_erom_class_t *cls, device_t parent, int rid,
|
||||
* @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 @@ bhnd_erom_alloc(bhnd_erom_class_t *cls, device_t parent, int rid,
|
||||
*/
|
||||
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 @@ bhnd_erom_init_static(bhnd_erom_class_t *cls, bhnd_erom_t *erom, size_t esize,
|
||||
|
||||
/* 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));
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -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);
|
||||
|
||||
@ -92,17 +93,50 @@ SET_DECLARE(bhnd_erom_class_set, bhnd_erom_class_t);
|
||||
#define BHND_EROM_CLASS_DEF(classvar) DATA_SET(bhnd_erom_class_set, classvar)
|
||||
|
||||
|
||||
/**
|
||||
* 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 @@ SET_DECLARE(bhnd_erom_class_set, bhnd_erom_class_t);
|
||||
*/
|
||||
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));
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -43,17 +43,50 @@ INTERFACE bhnd_erom;
|
||||
# tables used by bhnd(4) buses.
|
||||
#
|
||||
|
||||
/**
|
||||
* 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 @@ INTERFACE bhnd_erom;
|
||||
* 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;
|
||||
};
|
||||
|
||||
/**
|
||||
|
@ -105,8 +105,9 @@ struct bhnd_core_match {
|
||||
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 @@ struct bhnd_core_match {
|
||||
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 @@ struct bhnd_core_match {
|
||||
_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 @@ struct bhnd_core_match {
|
||||
#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 @@ struct bhnd_device_match {
|
||||
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 @@ struct bhnd_device_match {
|
||||
board_type:1,
|
||||
board_rev:1,
|
||||
board_srom_rev:1,
|
||||
flags_unused:2;
|
||||
flags_unused:1;
|
||||
} match;
|
||||
} m;
|
||||
|
||||
@ -271,6 +276,7 @@ struct bhnd_device_match {
|
||||
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 */
|
||||
|
@ -83,7 +83,7 @@ bhnd_nexus_read_chipid(device_t dev, struct bhnd_chipid *chipid)
|
||||
static bool
|
||||
bhnd_nexus_is_hw_disabled(device_t dev, device_t child)
|
||||
{
|
||||
return false;
|
||||
return (false);
|
||||
}
|
||||
|
||||
static bhnd_attach_type
|
||||
|
@ -485,6 +485,47 @@ bhnd_find_core(const struct bhnd_core_info *cores, u_int num_cores,
|
||||
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_core_matches(const struct bhnd_core_info *core,
|
||||
!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);
|
||||
|
@ -66,6 +66,22 @@ bhnd_bhndb_get_attach_type(device_t dev, device_t child)
|
||||
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 @@ bhnd_bhndb_pwrctl_ungate_clock(device_t dev, device_t child,
|
||||
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),
|
||||
|
@ -50,6 +50,8 @@ __FBSDID("$FreeBSD$");
|
||||
#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 @@ enum {
|
||||
|
||||
#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_find_hostb_core(struct bhndb_softc *sc,
|
||||
bhnd_erom_t *erom,
|
||||
struct bhnd_core_info *core);
|
||||
|
||||
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 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 @@ static int bhndb_try_activate_resource(
|
||||
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 @@ bhndb_child_location_str(device_t dev, device_t child, char *buf,
|
||||
}
|
||||
|
||||
/**
|
||||
* 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 @@ bhndb_hw_matches(device_t *devlist, int num_devs, const struct bhndb_hw *hw)
|
||||
}
|
||||
|
||||
/**
|
||||
* 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 @@ bhndb_initialize_region_cfg(struct bhndb_softc *sc, device_t *devs, int ndevs,
|
||||
/*
|
||||
* 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 @@ bhndb_initialize_region_cfg(struct bhndb_softc *sc, device_t *devs, int ndevs,
|
||||
* 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 @@ bhndb_initialize_region_cfg(struct bhndb_softc *sc, device_t *devs, int ndevs,
|
||||
* 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 @@ bhndb_initialize_region_cfg(struct bhndb_softc *sc, device_t *devs, int ndevs,
|
||||
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 @@ bhndb_initialize_region_cfg(struct bhndb_softc *sc, device_t *devs, int ndevs,
|
||||
/* 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 @@ bhndb_initialize_region_cfg(struct bhndb_softc *sc, device_t *devs, int ndevs,
|
||||
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 @@ bhndb_initialize_region_cfg(struct bhndb_softc *sc, device_t *devs, int ndevs,
|
||||
* 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 @@ bhndb_initialize_region_cfg(struct bhndb_softc *sc, device_t *devs, int ndevs,
|
||||
* @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 */
|
||||
@ -446,70 +486,16 @@ bhndb_find_hwspec(struct bhndb_softc *sc, device_t *devs, int ndevs,
|
||||
return (ENOENT);
|
||||
}
|
||||
|
||||
/**
|
||||
* 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 @@ bhndb_attach(device_t dev, bhnd_devclass_t bridge_devclass)
|
||||
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_attach(device_t dev, bhnd_devclass_t bridge_devclass)
|
||||
|
||||
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 @@ bhndb_attach(device_t dev, bhnd_devclass_t bridge_devclass)
|
||||
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 function provides the default bhndb implementation of
|
||||
* BHNDB_INIT_FULL_CONFIG(), and must be called by any subclass driver
|
||||
* overriding BHNDB_INIT_FULL_CONFIG().
|
||||
* This may return a borrowed reference to a bhndb_dw_alloc-managed
|
||||
* resource; any additional resource mapping requests may invalidate this
|
||||
* borrowed reference.
|
||||
*
|
||||
* 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.
|
||||
* @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.
|
||||
*
|
||||
* 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);
|
||||
|
||||
/* 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");
|
||||
return (error);
|
||||
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;
|
||||
}
|
||||
|
||||
/* Find our host bridge device */
|
||||
hostb = BHNDB_FIND_HOSTB_DEVICE(dev, child);
|
||||
if (hostb == NULL) {
|
||||
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;
|
||||
|
||||
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;
|
||||
}
|
||||
}
|
||||
|
||||
/* 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 @@ bhndb_generic_init_full_config(device_t dev, device_t child,
|
||||
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 @@ bhndb_get_chipid(device_t dev, device_t child)
|
||||
|
||||
|
||||
/**
|
||||
* 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 @@ 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 */
|
||||
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;
|
||||
struct bhndb_softc *sc = device_get_softc(dev);
|
||||
|
||||
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);
|
||||
|
||||
return (hostb_dev);
|
||||
*core = *bhndb_get_bridge_core(sc);
|
||||
return (0);
|
||||
}
|
||||
|
||||
/**
|
||||
@ -1681,7 +1866,14 @@ bhndb_io_resource_slow(struct bhndb_softc *sc, bus_addr_t addr,
|
||||
}
|
||||
|
||||
/**
|
||||
* 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 @@ 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_get_hostb_core, bhndb_get_hostb_core),
|
||||
DEVMETHOD(bhndb_suspend_resource, bhndb_suspend_resource),
|
||||
DEVMETHOD(bhndb_resume_resource, bhndb_resume_resource),
|
||||
|
||||
|
@ -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 @@ CODE {
|
||||
{
|
||||
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,
|
||||
@ -108,6 +114,18 @@ METHOD const struct bhndb_hw * get_hardware_table {
|
||||
device_t child;
|
||||
} 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.
|
||||
|
@ -61,18 +61,12 @@ CODE {
|
||||
{
|
||||
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 @@ METHOD int populate_board_info {
|
||||
} 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.
|
||||
* @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.
|
||||
*
|
||||
* 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 hw_priority The hardware priority table to be used when determining
|
||||
* the bridge resource allocation strategy.
|
||||
* @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 int init_full_config {
|
||||
METHOD int get_hostb_core {
|
||||
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.
|
||||
*/
|
||||
METHOD device_t find_hostb_device {
|
||||
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
|
||||
|
@ -62,6 +62,8 @@ __FBSDID("$FreeBSD$");
|
||||
#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 @@ bhndb_pci_attach(device_t dev)
|
||||
sc = device_get_softc(dev);
|
||||
sc->dev = dev;
|
||||
sc->parent = device_get_parent(dev);
|
||||
|
||||
/* 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;
|
||||
|
||||
/* Enable clocks (if supported 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;
|
||||
|
||||
/* 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. */
|
||||
if ((error = bhndb_attach(dev, sc->pci_devclass)))
|
||||
return (error);
|
||||
if (pci_find_cap(sc->parent, PCIY_EXPRESS, ®) == 0)
|
||||
sc->pci_devclass = BHND_DEVCLASS_PCIE;
|
||||
else
|
||||
sc->pci_devclass = BHND_DEVCLASS_PCI;
|
||||
|
||||
/* If supported, switch to the faster regwin handling */
|
||||
/* Enable clocks (if required by this hardware) */
|
||||
if ((error = bhndb_enable_pci_clocks(sc)))
|
||||
goto cleanup;
|
||||
|
||||
/* Perform bridge attach, fully initializing the bridge
|
||||
* configuration. */
|
||||
if ((error = bhndb_attach(dev, sc->pci_devclass)))
|
||||
goto cleanup;
|
||||
|
||||
/* 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);
|
||||
}
|
||||
|
||||
return (0);
|
||||
}
|
||||
|
||||
static int
|
||||
bhndb_pci_init_full_config(device_t dev, device_t child,
|
||||
const struct bhndb_hw_priority *hw_prio_table)
|
||||
{
|
||||
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)))
|
||||
return (error);
|
||||
/* Enable PCI bus mastering */
|
||||
pci_enable_busmaster(sc->parent);
|
||||
|
||||
/* Fix-up power on defaults for SROM-less devices. */
|
||||
bhndb_init_sromless_pci_config(sc);
|
||||
|
||||
/* If SPROM is mapped directly into BAR0, add NVRAM device. */
|
||||
/* 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_detach(device_t dev)
|
||||
{
|
||||
struct bhndb_pci_softc *sc;
|
||||
int error;
|
||||
|
||||
sc = device_get_softc(dev);
|
||||
|
||||
/* Attempt to detach our children */
|
||||
if ((error = bus_generic_detach(dev)))
|
||||
return (error);
|
||||
|
||||
/* 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);
|
||||
}
|
||||
|
||||
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,
|
||||
|
||||
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 @@ bhndb_init_sromless_pci_config(struct bhndb_pci_softc *sc)
|
||||
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 @@ bhndb_init_sromless_pci_config(struct bhndb_pci_softc *sc)
|
||||
|
||||
/* 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);
|
||||
@ -383,28 +420,6 @@ bhndb_pci_suspend(device_t dev)
|
||||
return (bhndb_generic_suspend(dev));
|
||||
}
|
||||
|
||||
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 @@ static device_method_t bhndb_pci_methods[] = {
|
||||
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),
|
||||
|
||||
|
@ -63,6 +63,9 @@ struct bhndb_resources *bhndb_alloc_resources(device_t dev,
|
||||
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 @@ const struct bhndb_regwin *bhndb_regwin_find_best(
|
||||
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 @@ struct bhndb_resources {
|
||||
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 */
|
||||
|
@ -196,6 +196,8 @@ struct resource *
|
||||
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 @@ bhndb_find_regwin_resource(struct bhndb_resources *br,
|
||||
{
|
||||
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 @@ bhndb_find_regwin_resource(struct bhndb_resources *br,
|
||||
}
|
||||
|
||||
/**
|
||||
* 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 @@ bhndb_alloc_resources(device_t dev, device_t parent_dev,
|
||||
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 @@ bhndb_alloc_resources(device_t dev, device_t parent_dev,
|
||||
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 @@ bhndb_alloc_resources(device_t dev, device_t parent_dev,
|
||||
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 @@ bhndb_alloc_resources(device_t dev, device_t parent_dev,
|
||||
error = EINVAL;
|
||||
goto failed;
|
||||
}
|
||||
|
||||
rnid++;
|
||||
}
|
||||
|
||||
return (r);
|
||||
/* 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 (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 (br->res != NULL)
|
||||
free(br->res, M_BHND);
|
||||
|
||||
if (free_br_mem)
|
||||
rman_fini(&r->br_mem_rman);
|
||||
if (br->res_spec != NULL)
|
||||
free(br->res_spec, M_BHND);
|
||||
|
||||
if (r->res != NULL)
|
||||
free(r->res, 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 @@ bhndb_free_resources(struct bhndb_resources *br)
|
||||
}
|
||||
|
||||
/* 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 @@ bhndb_free_resources(struct bhndb_resources *br)
|
||||
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 @@ bhndb_regwin_find_best(const struct bhndb_regwin *table,
|
||||
}
|
||||
|
||||
/**
|
||||
* 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)
|
||||
if (core->unit != 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))
|
||||
{
|
||||
return (false);
|
||||
}
|
||||
|
||||
/* Matches */
|
||||
return (true);
|
||||
@ -1022,22 +1063,19 @@ bhndb_regwin_matches_device(const struct bhndb_regwin *regw, device_t dev)
|
||||
|
||||
/**
|
||||
* 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);
|
||||
}
|
||||
|
||||
|
@ -89,12 +89,12 @@ struct bhndb_softc {
|
||||
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 */
|
||||
|
@ -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)
|
||||
|
@ -44,6 +44,12 @@ __FBSDID("$FreeBSD$");
|
||||
#include "sibareg.h"
|
||||
#include "sibavar.h"
|
||||
|
||||
static bhnd_erom_class_t *
|
||||
siba_get_erom_class(driver_t *driver)
|
||||
{
|
||||
return (&siba_erom_parser);
|
||||
}
|
||||
|
||||
int
|
||||
siba_probe(device_t dev)
|
||||
{
|
||||
@ -51,84 +57,29 @@ siba_probe(device_t dev)
|
||||
return (BUS_PROBE_DEFAULT);
|
||||
}
|
||||
|
||||
/**
|
||||
* Default siba(4) bus driver implementation of DEVICE_ATTACH().
|
||||
*
|
||||
* This implementation initializes internal siba(4) state and performs
|
||||
* bus enumeration, and must be called by subclassing drivers in
|
||||
* DEVICE_ATTACH() before any other bus methods.
|
||||
*/
|
||||
int
|
||||
siba_attach(device_t dev)
|
||||
{
|
||||
struct siba_devinfo *dinfo;
|
||||
struct siba_softc *sc;
|
||||
device_t *devs;
|
||||
int ndevs;
|
||||
int error;
|
||||
|
||||
|
||||
sc = device_get_softc(dev);
|
||||
sc->dev = dev;
|
||||
|
||||
/* Fetch references to the siba SIBA_CFG* blocks for all
|
||||
* registered devices */
|
||||
if ((error = device_get_children(dev, &devs, &ndevs)))
|
||||
/* Enumerate children */
|
||||
if ((error = siba_add_children(dev))) {
|
||||
device_delete_children(dev);
|
||||
return (error);
|
||||
|
||||
for (int i = 0; i < ndevs; i++) {
|
||||
struct siba_addrspace *addrspace;
|
||||
|
||||
dinfo = device_get_ivars(devs[i]);
|
||||
|
||||
KASSERT(!device_is_suspended(devs[i]),
|
||||
("siba(4) stateful suspend handling requires that devices "
|
||||
"not be suspended before siba_attach()"));
|
||||
|
||||
/* Fetch the core register address space */
|
||||
addrspace = siba_find_addrspace(dinfo, BHND_PORT_DEVICE, 0, 0);
|
||||
if (addrspace == NULL) {
|
||||
device_printf(dev,
|
||||
"missing device registers for core %d\n", i);
|
||||
error = ENXIO;
|
||||
goto cleanup;
|
||||
}
|
||||
|
||||
/*
|
||||
* Map the per-core configuration blocks
|
||||
*/
|
||||
KASSERT(dinfo->core_id.num_cfg_blocks <= SIBA_MAX_CFG,
|
||||
("config block count %u out of range",
|
||||
dinfo->core_id.num_cfg_blocks));
|
||||
|
||||
for (u_int cfgidx = 0; cfgidx < dinfo->core_id.num_cfg_blocks;
|
||||
cfgidx++)
|
||||
{
|
||||
rman_res_t r_start, r_count, r_end;
|
||||
|
||||
/* Determine the config block's address range; configuration
|
||||
* blocks are allocated starting at SIBA_CFG0_OFFSET,
|
||||
* growing downwards. */
|
||||
r_start = addrspace->sa_base + SIBA_CFG0_OFFSET;
|
||||
r_start -= cfgidx * SIBA_CFG_SIZE;
|
||||
|
||||
r_count = SIBA_CFG_SIZE;
|
||||
r_end = r_start + r_count - 1;
|
||||
|
||||
/* Allocate the config resource */
|
||||
dinfo->cfg_rid[cfgidx] = 0;
|
||||
dinfo->cfg[cfgidx] = BHND_BUS_ALLOC_RESOURCE(dev, dev,
|
||||
SYS_RES_MEMORY, &dinfo->cfg_rid[cfgidx], r_start,
|
||||
r_end, r_count, RF_ACTIVE);
|
||||
|
||||
if (dinfo->cfg[cfgidx] == NULL) {
|
||||
device_printf(dev, "failed allocating CFG_%u for "
|
||||
"core %d\n", cfgidx, i);
|
||||
error = ENXIO;
|
||||
goto cleanup;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
cleanup:
|
||||
free(devs, M_BHND);
|
||||
if (error)
|
||||
return (error);
|
||||
|
||||
/* Delegate remainder to standard bhnd method implementation */
|
||||
return (bhnd_generic_attach(dev));
|
||||
return (0);
|
||||
}
|
||||
|
||||
int
|
||||
@ -213,15 +164,6 @@ siba_get_resource_list(device_t dev, device_t child)
|
||||
return (&dinfo->resources);
|
||||
}
|
||||
|
||||
static device_t
|
||||
siba_find_hostb_device(device_t dev)
|
||||
{
|
||||
struct siba_softc *sc = device_get_softc(dev);
|
||||
|
||||
/* This is set (or not) by the concrete siba driver subclass. */
|
||||
return (sc->hostb_dev);
|
||||
}
|
||||
|
||||
static int
|
||||
siba_reset_core(device_t dev, device_t child, uint16_t flags)
|
||||
{
|
||||
@ -492,6 +434,64 @@ siba_register_addrspaces(device_t dev, struct siba_devinfo *di,
|
||||
return (0);
|
||||
}
|
||||
|
||||
/**
|
||||
* Map per-core configuration blocks for @p dinfo.
|
||||
*
|
||||
* @param dev The siba bus device.
|
||||
* @param dinfo The device info instance on which to map all per-core
|
||||
* configuration blocks.
|
||||
*/
|
||||
static int
|
||||
siba_map_cfg_resources(device_t dev, struct siba_devinfo *dinfo)
|
||||
{
|
||||
struct siba_addrspace *addrspace;
|
||||
rman_res_t r_start, r_count, r_end;
|
||||
uint8_t num_cfg;
|
||||
|
||||
num_cfg = dinfo->core_id.num_cfg_blocks;
|
||||
if (num_cfg > SIBA_MAX_CFG) {
|
||||
device_printf(dev, "config block count %hhu out of range\n",
|
||||
num_cfg);
|
||||
return (ENXIO);
|
||||
}
|
||||
|
||||
/* Fetch the core register address space */
|
||||
addrspace = siba_find_addrspace(dinfo, BHND_PORT_DEVICE, 0, 0);
|
||||
if (addrspace == NULL) {
|
||||
device_printf(dev, "missing device registers\n");
|
||||
return (ENXIO);
|
||||
}
|
||||
|
||||
/*
|
||||
* Map the per-core configuration blocks
|
||||
*/
|
||||
for (uint8_t i = 0; i < num_cfg; i++) {
|
||||
/* Determine the config block's address range; configuration
|
||||
* blocks are allocated starting at SIBA_CFG0_OFFSET,
|
||||
* growing downwards. */
|
||||
r_start = addrspace->sa_base + SIBA_CFG0_OFFSET;
|
||||
r_start -= i * SIBA_CFG_SIZE;
|
||||
|
||||
r_count = SIBA_CFG_SIZE;
|
||||
r_end = r_start + r_count - 1;
|
||||
|
||||
/* Allocate the config resource */
|
||||
dinfo->cfg_rid[i] = SIBA_CFG_RID(dinfo, i);
|
||||
dinfo->cfg[i] = BHND_BUS_ALLOC_RESOURCE(dev, dev,
|
||||
SYS_RES_MEMORY, &dinfo->cfg_rid[i], r_start, r_end,
|
||||
r_count, RF_ACTIVE);
|
||||
|
||||
if (dinfo->cfg[i] == NULL) {
|
||||
device_printf(dev, "failed to allocate SIBA_CFG%hhu\n",
|
||||
i);
|
||||
return (ENXIO);
|
||||
}
|
||||
}
|
||||
|
||||
return (0);
|
||||
}
|
||||
|
||||
|
||||
static struct bhnd_devinfo *
|
||||
siba_alloc_bhnd_dinfo(device_t dev)
|
||||
{
|
||||
@ -510,73 +510,22 @@ siba_free_bhnd_dinfo(device_t dev, struct bhnd_devinfo *dinfo)
|
||||
* the bus.
|
||||
*
|
||||
* @param dev The siba bus device.
|
||||
* @param chipid The chip identifier, if the device does not provide a
|
||||
* ChipCommon core. Should o NULL otherwise.
|
||||
*/
|
||||
int
|
||||
siba_add_children(device_t dev, const struct bhnd_chipid *chipid)
|
||||
siba_add_children(device_t dev)
|
||||
{
|
||||
struct bhnd_chipid ccid;
|
||||
struct bhnd_core_info *cores;
|
||||
struct siba_devinfo *dinfo;
|
||||
struct bhnd_resource *r;
|
||||
int rid;
|
||||
int error;
|
||||
const struct bhnd_chipid *chipid;
|
||||
struct bhnd_core_info *cores;
|
||||
struct siba_devinfo *dinfo;
|
||||
struct bhnd_resource *r;
|
||||
int rid;
|
||||
int error;
|
||||
|
||||
dinfo = NULL;
|
||||
cores = NULL;
|
||||
r = NULL;
|
||||
|
||||
/*
|
||||
* Try to determine the number of device cores via the ChipCommon
|
||||
* identification registers.
|
||||
*
|
||||
* A small number of very early devices do not include a ChipCommon
|
||||
* core, in which case our caller must supply the chip identification
|
||||
* information via a non-NULL chipid parameter.
|
||||
*/
|
||||
if (chipid == NULL) {
|
||||
uint32_t idhigh, ccreg;
|
||||
uint16_t vendor, device;
|
||||
uint8_t ccrev;
|
||||
|
||||
/* Map the first core's register block. If the ChipCommon core
|
||||
* exists, it will always be the first core. */
|
||||
rid = 0;
|
||||
r = bhnd_alloc_resource(dev, SYS_RES_MEMORY, &rid,
|
||||
SIBA_CORE_ADDR(0), SIBA_CORE_SIZE,
|
||||
SIBA_CORE_ADDR(0) + SIBA_CORE_SIZE - 1,
|
||||
RF_ACTIVE);
|
||||
|
||||
/* Identify the core */
|
||||
idhigh = bhnd_bus_read_4(r, SB0_REG_ABS(SIBA_CFG0_IDHIGH));
|
||||
vendor = SIBA_REG_GET(idhigh, IDH_VENDOR);
|
||||
device = SIBA_REG_GET(idhigh, IDH_DEVICE);
|
||||
ccrev = SIBA_IDH_CORE_REV(idhigh);
|
||||
|
||||
if (vendor != OCP_VENDOR_BCM || device != BHND_COREID_CC) {
|
||||
device_printf(dev,
|
||||
"cannot identify device: no chipcommon core "
|
||||
"found\n");
|
||||
error = ENXIO;
|
||||
goto cleanup;
|
||||
}
|
||||
|
||||
/* Identify the chipset */
|
||||
ccreg = bhnd_bus_read_4(r, CHIPC_ID);
|
||||
ccid = bhnd_parse_chipid(ccreg, SIBA_ENUM_ADDR);
|
||||
|
||||
/* Fix up the core count */
|
||||
error = bhnd_chipid_fixed_ncores(&ccid, ccrev, &ccid.ncores);
|
||||
if (error) {
|
||||
device_printf(dev, "unable to determine core count for "
|
||||
"chipset 0x%hx\n", ccid.chip_id);
|
||||
goto cleanup;
|
||||
}
|
||||
|
||||
chipid = &ccid;
|
||||
bhnd_release_resource(dev, SYS_RES_MEMORY, rid, r);
|
||||
}
|
||||
chipid = BHND_BUS_GET_CHIPID(dev, dev);
|
||||
|
||||
/* Allocate our temporary core table and enumerate all cores */
|
||||
cores = malloc(sizeof(*cores) * chipid->ncores, M_BHND, M_NOWAIT);
|
||||
@ -636,14 +585,19 @@ siba_add_children(device_t dev, const struct bhnd_chipid *chipid)
|
||||
if ((error = siba_register_addrspaces(dev, dinfo, r)))
|
||||
goto cleanup;
|
||||
|
||||
/* Release our resource covering the register blocks
|
||||
* we're about to map */
|
||||
bhnd_release_resource(dev, SYS_RES_MEMORY, rid, r);
|
||||
r = NULL;
|
||||
|
||||
/* Map the core's config blocks */
|
||||
if ((error = siba_map_cfg_resources(dev, dinfo)))
|
||||
goto cleanup;
|
||||
|
||||
/* If pins are floating or the hardware is otherwise
|
||||
* unpopulated, the device shouldn't be used. */
|
||||
if (bhnd_is_hw_disabled(child))
|
||||
device_disable(child);
|
||||
|
||||
/* Release our resource */
|
||||
bhnd_release_resource(dev, SYS_RES_MEMORY, rid, r);
|
||||
r = NULL;
|
||||
|
||||
/* Issue bus callback for fully initialized child. */
|
||||
BHND_BUS_CHILD_ADDED(dev, child);
|
||||
@ -673,7 +627,7 @@ static device_method_t siba_methods[] = {
|
||||
DEVMETHOD(bus_get_resource_list, siba_get_resource_list),
|
||||
|
||||
/* BHND interface */
|
||||
DEVMETHOD(bhnd_bus_find_hostb_device, siba_find_hostb_device),
|
||||
DEVMETHOD(bhnd_bus_get_erom_class, siba_get_erom_class),
|
||||
DEVMETHOD(bhnd_bus_alloc_devinfo, siba_alloc_bhnd_dinfo),
|
||||
DEVMETHOD(bhnd_bus_free_devinfo, siba_free_bhnd_dinfo),
|
||||
DEVMETHOD(bhnd_bus_reset_core, siba_reset_core),
|
||||
|
@ -101,35 +101,28 @@ siba_bhndb_probe(device_t dev)
|
||||
static int
|
||||
siba_bhndb_attach(device_t dev)
|
||||
{
|
||||
struct siba_softc *sc;
|
||||
const struct bhnd_chipid *chipid;
|
||||
int error;
|
||||
struct siba_softc *sc;
|
||||
int error;
|
||||
|
||||
sc = device_get_softc(dev);
|
||||
|
||||
/* Enumerate our children. */
|
||||
chipid = BHNDB_GET_CHIPID(device_get_parent(dev), dev);
|
||||
if ((error = siba_add_children(dev, chipid)))
|
||||
return (error);
|
||||
|
||||
/* Initialize full bridge configuration */
|
||||
error = BHNDB_INIT_FULL_CONFIG(device_get_parent(dev), dev,
|
||||
bhndb_siba_priority_table);
|
||||
if (error)
|
||||
return (error);
|
||||
|
||||
/* Ask our parent bridge to find the corresponding bridge core */
|
||||
sc->hostb_dev = BHNDB_FIND_HOSTB_DEVICE(device_get_parent(dev), dev);
|
||||
|
||||
/* Call our superclass' implementation */
|
||||
/* Perform initial attach and enumerate our children. */
|
||||
if ((error = siba_attach(dev)))
|
||||
return (error);
|
||||
goto failed;
|
||||
|
||||
/* Apply attach/resume work-arounds */
|
||||
/* Apply attach/resume workarounds before any child drivers attach */
|
||||
if ((error = siba_bhndb_wars_hwup(sc)))
|
||||
return (error);
|
||||
goto failed;
|
||||
|
||||
/* Delegate remainder to standard bhnd method implementation */
|
||||
if ((error = bhnd_generic_attach(dev)))
|
||||
goto failed;
|
||||
|
||||
return (0);
|
||||
|
||||
failed:
|
||||
device_delete_children(dev);
|
||||
return (error);
|
||||
}
|
||||
|
||||
static int
|
||||
@ -222,11 +215,15 @@ static int
|
||||
siba_bhndb_wars_pcie_clear_d11_timeout(struct siba_softc *sc)
|
||||
{
|
||||
struct siba_devinfo *dinfo;
|
||||
device_t hostb_dev;
|
||||
device_t d11;
|
||||
uint32_t imcfg;
|
||||
|
||||
/* Only applies when bridged by PCIe */
|
||||
if (bhnd_get_class(sc->hostb_dev) != BHND_DEVCLASS_PCIE)
|
||||
if ((hostb_dev = bhnd_find_hostb_device(sc->dev)) == NULL)
|
||||
return (ENXIO);
|
||||
|
||||
if (bhnd_get_class(hostb_dev) != BHND_DEVCLASS_PCIE)
|
||||
return (0);
|
||||
|
||||
/* Only applies if there's a D11 core */
|
||||
@ -256,10 +253,14 @@ siba_bhndb_wars_pcie_clear_d11_timeout(struct siba_softc *sc)
|
||||
static int
|
||||
siba_bhndb_wars_hwup(struct siba_softc *sc)
|
||||
{
|
||||
device_t hostb_dev;
|
||||
uint32_t quirks;
|
||||
int error;
|
||||
|
||||
quirks = bhnd_device_quirks(sc->hostb_dev, bridge_devs,
|
||||
if ((hostb_dev = bhnd_find_hostb_device(sc->dev)) == NULL)
|
||||
return (ENXIO);
|
||||
|
||||
quirks = bhnd_device_quirks(hostb_dev, bridge_devs,
|
||||
sizeof(bridge_devs[0]));
|
||||
|
||||
if (quirks & SIBA_QUIRK_PCIE_D11_SB_TIMEOUT) {
|
||||
|
@ -46,117 +46,110 @@ __FBSDID("$FreeBSD$");
|
||||
#include "sibavar.h"
|
||||
|
||||
struct siba_erom;
|
||||
struct siba_erom_io;
|
||||
|
||||
static int siba_erom_init_static(bhnd_erom_t *erom, bus_space_tag_t bst,
|
||||
bus_space_handle_t bsh);
|
||||
static void siba_erom_fini(bhnd_erom_t *erom);
|
||||
|
||||
static uint32_t siba_erom_read_4(struct siba_erom *sc, u_int core_idx,
|
||||
bus_size_t offset);
|
||||
static int siba_erom_read_chipid(struct siba_erom *sc,
|
||||
bus_addr_t enum_addr, struct bhnd_chipid *cid);
|
||||
static int siba_eio_init(struct siba_erom_io *io,
|
||||
device_t parent, struct bhnd_resource *res,
|
||||
int rid, bus_size_t offset, u_int ncores);
|
||||
|
||||
struct siba_erom {
|
||||
struct bhnd_erom obj;
|
||||
static int siba_eio_init_static(struct siba_erom_io *io,
|
||||
bus_space_tag_t bst, bus_space_handle_t bsh,
|
||||
bus_size_t offset, u_int ncores);
|
||||
|
||||
static uint32_t siba_eio_read_4(struct siba_erom_io *io,
|
||||
u_int core_idx, bus_size_t offset);
|
||||
|
||||
static struct siba_core_id siba_eio_read_core_id(struct siba_erom_io *io,
|
||||
u_int core_idx, int unit);
|
||||
|
||||
static int siba_eio_read_chipid(struct siba_erom_io *io,
|
||||
bus_addr_t enum_addr,
|
||||
struct bhnd_chipid *cid);
|
||||
|
||||
/**
|
||||
* SIBA EROM generic I/O context
|
||||
*/
|
||||
struct siba_erom_io {
|
||||
u_int ncores; /**< core count */
|
||||
bus_size_t offset; /**< base read offset */
|
||||
|
||||
/* resource state */
|
||||
device_t dev; /**< parent dev to use for resource allocations,
|
||||
or NULL if initialized with bst/bsh */
|
||||
struct bhnd_resource *res; /**< siba bus mapping, or NULL */
|
||||
int rid; /**< siba bus maping resource ID */
|
||||
or NULL if unavailable. */
|
||||
struct bhnd_resource *res; /**< memory resource, or NULL */
|
||||
int rid; /**< memory resource ID */
|
||||
|
||||
/* bus tag state */
|
||||
bus_space_tag_t bst; /**< chipc bus tag */
|
||||
bus_space_handle_t bsh; /**< chipc bus handle */
|
||||
bus_space_tag_t bst; /**< bus space tag */
|
||||
bus_space_handle_t bsh; /**< bus space handle */
|
||||
};
|
||||
|
||||
#define EROM_LOG(sc, fmt, ...) do { \
|
||||
if (sc->dev != NULL) { \
|
||||
device_printf(sc->dev, "%s: " fmt, __FUNCTION__, \
|
||||
/**
|
||||
* SIBA EROM per-instance state.
|
||||
*/
|
||||
struct siba_erom {
|
||||
struct bhnd_erom obj;
|
||||
struct siba_erom_io io; /**< i/o context */
|
||||
};
|
||||
|
||||
#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;
|
||||
/* Try using the provided hint. */
|
||||
if (hint != NULL) {
|
||||
struct siba_core_id sid;
|
||||
|
||||
/* Identify the chipset */
|
||||
if ((error = siba_erom_read_chipid(sc, SIBA_ENUM_ADDR, &cid)))
|
||||
return (error);
|
||||
/* Validate bus type */
|
||||
if (hint->chip_type != BHND_CHIPTYPE_SIBA)
|
||||
return (ENXIO);
|
||||
|
||||
/* Verify the chip type */
|
||||
if (cid.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,91 +158,213 @@ siba_erom_init_common(struct siba_erom *sc)
|
||||
* if (cid.ncores > SIBA_MAX_CORES)
|
||||
* return (EINVAL)
|
||||
*/
|
||||
_Static_assert((2^sizeof(cid.ncores)) <= SIBA_MAX_CORES,
|
||||
_Static_assert((2^sizeof(cid->ncores)) <= SIBA_MAX_CORES,
|
||||
"ncores could result in over-read of backing resource");
|
||||
|
||||
/* Update our core count */
|
||||
sc->ncores = cid.ncores;
|
||||
|
||||
return (0);
|
||||
}
|
||||
|
||||
/* SIBA implementation of BHND_EROM_PROBE() */
|
||||
static int
|
||||
siba_erom_init(bhnd_erom_t *erom, device_t parent, int rid,
|
||||
bus_addr_t enum_addr)
|
||||
siba_erom_probe(bhnd_erom_class_t *cls, struct bhnd_resource *res,
|
||||
bus_size_t offset, const struct bhnd_chipid *hint,
|
||||
struct bhnd_chipid *cid)
|
||||
{
|
||||
struct siba_erom *sc = (struct siba_erom *)erom;
|
||||
struct siba_erom_io io;
|
||||
int error, rid;
|
||||
|
||||
sc->dev = parent;
|
||||
sc->rid = rid;
|
||||
rid = rman_get_rid(res->res);
|
||||
|
||||
sc->res = bhnd_alloc_resource(sc->dev, SYS_RES_MEMORY, &sc->rid,
|
||||
enum_addr, enum_addr + SIBA_ENUM_SIZE -1, SIBA_ENUM_SIZE,
|
||||
RF_ACTIVE|RF_SHAREABLE);
|
||||
if (sc->res == NULL)
|
||||
return (ENOMEM);
|
||||
/* Initialize I/O context, assuming at least 1 core exists. */
|
||||
if ((error = siba_eio_init(&io, NULL, res, rid, offset, 1)))
|
||||
return (error);
|
||||
|
||||
return (siba_erom_init_common(sc));
|
||||
return (siba_erom_probe_common(&io, hint, cid));
|
||||
}
|
||||
|
||||
/* SIBA implementation of BHND_EROM_PROBE_STATIC() */
|
||||
static int
|
||||
siba_erom_probe_static(bhnd_erom_class_t *cls, bus_space_tag_t bst,
|
||||
bus_space_handle_t bsh, bus_addr_t paddr, struct bhnd_chipid *cid)
|
||||
bus_space_handle_t bsh, bus_addr_t paddr, const struct bhnd_chipid *hint,
|
||||
struct bhnd_chipid *cid)
|
||||
{
|
||||
struct siba_erom sc;
|
||||
uint32_t idreg;
|
||||
uint8_t chip_type;
|
||||
struct siba_erom_io io;
|
||||
int error;
|
||||
|
||||
idreg = bus_space_read_4(bst, bsh, CHIPC_ID);
|
||||
chip_type = CHIPC_GET_BITS(idreg, CHIPC_ID_BUS);
|
||||
|
||||
if (chip_type != BHND_CHIPTYPE_SIBA)
|
||||
return (ENXIO);
|
||||
|
||||
/* 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)))
|
||||
/* Initialize I/O context, assuming at least 1 core exists. */
|
||||
if ((error = siba_eio_init_static(&io, bst, bsh, 0, 1)))
|
||||
return (error);
|
||||
|
||||
/* 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);
|
||||
if (error)
|
||||
return (error);
|
||||
|
||||
return (BUS_PROBE_DEFAULT);
|
||||
return (siba_erom_probe_common(&io, hint, cid));
|
||||
}
|
||||
|
||||
/* SIBA implementation of BHND_EROM_INIT() */
|
||||
static int
|
||||
siba_erom_init_static(bhnd_erom_t *erom, bus_space_tag_t bst,
|
||||
bus_space_handle_t bsh)
|
||||
siba_erom_init(bhnd_erom_t *erom, const struct bhnd_chipid *cid,
|
||||
device_t parent, int rid)
|
||||
{
|
||||
struct siba_erom *sc = (struct siba_erom *)erom;
|
||||
struct siba_erom *sc;
|
||||
struct bhnd_resource *res;
|
||||
int error;
|
||||
|
||||
sc = (struct siba_erom *)erom;
|
||||
|
||||
sc->dev = NULL;
|
||||
sc->rid = -1;
|
||||
sc->res = NULL;
|
||||
sc->bst = bst;
|
||||
sc->bsh = bsh;
|
||||
/* 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);
|
||||
|
||||
return (siba_erom_init_common(sc));
|
||||
/* Initialize I/O context */
|
||||
error = siba_eio_init(&sc->io, parent, res, rid, 0x0, cid->ncores);
|
||||
if (error)
|
||||
bhnd_release_resource(parent, SYS_RES_MEMORY, rid, res);
|
||||
|
||||
return (error);
|
||||
}
|
||||
|
||||
/* SIBA implementation of BHND_EROM_INIT_STATIC() */
|
||||
static int
|
||||
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;
|
||||
|
||||
sc = (struct siba_erom *)erom;
|
||||
|
||||
/* Initialize I/O context */
|
||||
return (siba_eio_init_static(&sc->io, bst, bsh, 0x0, cid->ncores));
|
||||
}
|
||||
|
||||
/* SIBA implementation of BHND_EROM_FINI() */
|
||||
static void
|
||||
siba_erom_fini(bhnd_erom_t *erom)
|
||||
{
|
||||
struct siba_erom *sc = (struct siba_erom *)erom;
|
||||
|
||||
if (sc->res != NULL) {
|
||||
bhnd_release_resource(sc->dev, SYS_RES_MEMORY, sc->rid,
|
||||
sc->res);
|
||||
if (sc->io.res != NULL) {
|
||||
bhnd_release_resource(sc->io.dev, SYS_RES_MEMORY, sc->io.rid,
|
||||
sc->io.res);
|
||||
|
||||
sc->res = NULL;
|
||||
sc->rid = -1;
|
||||
sc->io.res = NULL;
|
||||
sc->io.rid = -1;
|
||||
}
|
||||
}
|
||||
|
||||
/* Initialize siba_erom resource I/O context */
|
||||
static int
|
||||
siba_eio_init(struct siba_erom_io *io, device_t parent,
|
||||
struct bhnd_resource *res, int rid, bus_size_t offset, u_int ncores)
|
||||
{
|
||||
io->dev = parent;
|
||||
io->res = res;
|
||||
io->rid = rid;
|
||||
io->offset = offset;
|
||||
io->ncores = ncores;
|
||||
|
||||
return (0);
|
||||
}
|
||||
|
||||
/* Initialize siba_erom bus space I/O context */
|
||||
static int
|
||||
siba_eio_init_static(struct siba_erom_io *io, bus_space_tag_t bst,
|
||||
bus_space_handle_t bsh, bus_size_t offset, u_int ncores)
|
||||
{
|
||||
io->res = NULL;
|
||||
io->rid = -1;
|
||||
io->bst = bst;
|
||||
io->bsh = bsh;
|
||||
io->offset = offset;
|
||||
io->ncores = ncores;
|
||||
|
||||
return (0);
|
||||
}
|
||||
|
||||
/**
|
||||
* Read a 32-bit value from @p offset relative to the base address of
|
||||
* the given @p core_idx.
|
||||
*
|
||||
* @param io EROM I/O context.
|
||||
* @param core_idx Core index.
|
||||
* @param offset Core register offset.
|
||||
*/
|
||||
static uint32_t
|
||||
siba_eio_read_4(struct siba_erom_io *io, u_int core_idx, bus_size_t offset)
|
||||
{
|
||||
bus_size_t core_offset;
|
||||
|
||||
/* Sanity check core index and offset */
|
||||
if (core_idx >= io->ncores)
|
||||
panic("core index %u out of range (ncores=%u)", core_idx,
|
||||
io->ncores);
|
||||
|
||||
if (offset > SIBA_CORE_SIZE - sizeof(uint32_t))
|
||||
panic("invalid core offset %#jx", (uintmax_t)offset);
|
||||
|
||||
/* Perform read */
|
||||
core_offset = io->offset + SIBA_CORE_OFFSET(core_idx) + offset;
|
||||
if (io->res != NULL)
|
||||
return (bhnd_bus_read_4(io->res, core_offset));
|
||||
else
|
||||
return (bus_space_read_4(io->bst, io->bsh, core_offset));
|
||||
}
|
||||
|
||||
/**
|
||||
* Read and parse identification registers for the given @p core_index.
|
||||
*
|
||||
* @param io EROM I/O context.
|
||||
* @param core_idx The core index.
|
||||
* @param unit The caller-specified unit number to be included in the return
|
||||
* value.
|
||||
*/
|
||||
static struct siba_core_id
|
||||
siba_eio_read_core_id(struct siba_erom_io *io, u_int core_idx, int unit)
|
||||
{
|
||||
uint32_t idhigh, idlow;
|
||||
|
||||
idhigh = siba_eio_read_4(io, core_idx, SB0_REG_ABS(SIBA_CFG0_IDHIGH));
|
||||
idlow = siba_eio_read_4(io, core_idx, SB0_REG_ABS(SIBA_CFG0_IDLOW));
|
||||
|
||||
return (siba_parse_core_id(idhigh, idlow, core_idx, unit));
|
||||
}
|
||||
|
||||
/**
|
||||
* Read and parse the chip identification register from the ChipCommon core.
|
||||
*
|
||||
* @param io EROM I/O context.
|
||||
* @param enum_addr The physical address mapped by @p io.
|
||||
* @param cid On success, the parsed chip identifier.
|
||||
*/
|
||||
static int
|
||||
siba_eio_read_chipid(struct siba_erom_io *io, bus_addr_t enum_addr,
|
||||
struct bhnd_chipid *cid)
|
||||
{
|
||||
struct siba_core_id ccid;
|
||||
uint32_t idreg;
|
||||
|
||||
/* Identify the chipcommon core */
|
||||
ccid = siba_eio_read_core_id(io, 0, 0);
|
||||
if (ccid.core_info.vendor != BHND_MFGID_BCM ||
|
||||
ccid.core_info.device != BHND_COREID_CC)
|
||||
{
|
||||
if (bootverbose) {
|
||||
EROM_LOG(io, "first core not chipcommon "
|
||||
"(vendor=%#hx, core=%#hx)\n", ccid.core_info.vendor,
|
||||
ccid.core_info.device);
|
||||
}
|
||||
return (ENXIO);
|
||||
}
|
||||
|
||||
/* Identify the chipset */
|
||||
idreg = siba_eio_read_4(io, 0, CHIPC_ID);
|
||||
*cid = bhnd_parse_chipid(idreg, enum_addr);
|
||||
|
||||
/* Fix up the core count in-place */
|
||||
return (bhnd_chipid_fixed_ncores(cid, ccid.core_info.hwrev,
|
||||
&cid->ncores));
|
||||
}
|
||||
|
||||
static int
|
||||
siba_erom_lookup_core(bhnd_erom_t *erom, const struct bhnd_core_match *desc,
|
||||
struct bhnd_core_info *core)
|
||||
@ -264,12 +379,12 @@ siba_erom_lookup_core(bhnd_erom_t *erom, const struct bhnd_core_match *desc,
|
||||
imatch.m.match.core_unit = 0;
|
||||
|
||||
/* Locate the first matching core */
|
||||
for (u_int i = 0; i < sc->ncores; i++) {
|
||||
for (u_int i = 0; i < sc->io.ncores; i++) {
|
||||
struct siba_core_id sid;
|
||||
struct bhnd_core_info ci;
|
||||
|
||||
/* Read the core info */
|
||||
sid = siba_erom_parse_core_id(sc, i, 0);
|
||||
sid = siba_eio_read_core_id(&sc->io, i, 0);
|
||||
ci = sid.core_info;
|
||||
|
||||
/* Check for initial match */
|
||||
@ -278,7 +393,7 @@ siba_erom_lookup_core(bhnd_erom_t *erom, const struct bhnd_core_match *desc,
|
||||
|
||||
/* Re-scan preceding cores to determine the unit number. */
|
||||
for (u_int j = 0; j < i; j++) {
|
||||
sid = siba_erom_parse_core_id(sc, i, 0);
|
||||
sid = siba_eio_read_core_id(&sc->io, i, 0);
|
||||
|
||||
/* Bump the unit number? */
|
||||
if (sid.core_info.vendor == ci.vendor &&
|
||||
@ -319,7 +434,7 @@ siba_erom_lookup_core_addr(bhnd_erom_t *erom, const struct bhnd_core_match *desc
|
||||
return (error);
|
||||
|
||||
/* Fetch full siba core ident */
|
||||
sid = siba_erom_parse_core_id(sc, core.core_idx, core.unit);
|
||||
sid = siba_eio_read_core_id(&sc->io, core.core_idx, core.unit);
|
||||
|
||||
/* Is port valid? */
|
||||
if (!siba_is_port_valid(sid.num_addrspace, type, port))
|
||||
@ -343,7 +458,7 @@ siba_erom_lookup_core_addr(bhnd_erom_t *erom, const struct bhnd_core_match *desc
|
||||
}
|
||||
|
||||
/* Read and parse the address match register */
|
||||
am = siba_erom_read_4(sc, core.core_idx, am_offset);
|
||||
am = siba_eio_read_4(&sc->io, core.core_idx, am_offset);
|
||||
|
||||
if ((error = siba_parse_admatch(am, &am_addr, &am_size))) {
|
||||
printf("failed to decode address match register value 0x%x\n",
|
||||
@ -371,19 +486,19 @@ siba_erom_get_core_table(bhnd_erom_t *erom, struct bhnd_core_info **cores,
|
||||
sc = (struct siba_erom *)erom;
|
||||
|
||||
/* Allocate our core array */
|
||||
out = malloc(sizeof(*out) * sc->ncores, M_BHND, M_NOWAIT);
|
||||
out = malloc(sizeof(*out) * sc->io.ncores, M_BHND, M_NOWAIT);
|
||||
if (out == NULL)
|
||||
return (ENOMEM);
|
||||
|
||||
*cores = out;
|
||||
*num_cores = sc->ncores;
|
||||
*num_cores = sc->io.ncores;
|
||||
|
||||
/* Enumerate all cores. */
|
||||
for (u_int i = 0; i < sc->ncores; i++) {
|
||||
for (u_int i = 0; i < sc->io.ncores; i++) {
|
||||
struct siba_core_id sid;
|
||||
|
||||
/* Read the core info */
|
||||
sid = siba_erom_parse_core_id(sc, i, 0);
|
||||
sid = siba_eio_read_core_id(&sc->io, i, 0);
|
||||
out[i] = sid.core_info;
|
||||
|
||||
/* Determine unit number */
|
||||
@ -405,6 +520,7 @@ siba_erom_free_core_table(bhnd_erom_t *erom, struct bhnd_core_info *cores)
|
||||
}
|
||||
|
||||
static kobj_method_t siba_erom_methods[] = {
|
||||
KOBJMETHOD(bhnd_erom_probe, siba_erom_probe),
|
||||
KOBJMETHOD(bhnd_erom_probe_static, siba_erom_probe_static),
|
||||
KOBJMETHOD(bhnd_erom_init, siba_erom_init),
|
||||
KOBJMETHOD(bhnd_erom_init_static, siba_erom_init_static),
|
||||
|
@ -84,18 +84,21 @@ siba_nexus_probe(device_t dev)
|
||||
static int
|
||||
siba_nexus_attach(device_t dev)
|
||||
{
|
||||
struct siba_nexus_softc *sc;
|
||||
int error;
|
||||
|
||||
sc = device_get_softc(dev);
|
||||
/* Perform initial attach and enumerate our children. */
|
||||
if ((error = siba_attach(dev)))
|
||||
goto failed;
|
||||
|
||||
/* Enumerate the bus. */
|
||||
if ((error = siba_add_children(dev, NULL))) {
|
||||
device_printf(dev, "error %d enumerating children\n", error);
|
||||
return (error);
|
||||
}
|
||||
/* Delegate remainder to standard bhnd method implementation */
|
||||
if ((error = bhnd_generic_attach(dev)))
|
||||
goto failed;
|
||||
|
||||
return (siba_attach(dev));
|
||||
return (0);
|
||||
|
||||
failed:
|
||||
device_delete_children(dev);
|
||||
return (error);
|
||||
}
|
||||
|
||||
static const struct bhnd_chipid *
|
||||
|
@ -60,8 +60,7 @@ uint16_t siba_get_bhnd_mfgid(uint16_t ocp_vendor);
|
||||
struct siba_core_id siba_parse_core_id(uint32_t idhigh, uint32_t idlow,
|
||||
u_int core_idx, int unit);
|
||||
|
||||
int siba_add_children(device_t bus,
|
||||
const struct bhnd_chipid *chipid);
|
||||
int siba_add_children(device_t bus);
|
||||
|
||||
struct siba_devinfo *siba_alloc_dinfo(device_t dev);
|
||||
int siba_init_dinfo(device_t dev,
|
||||
@ -100,6 +99,11 @@ int siba_parse_admatch(uint32_t am, uint32_t *addr,
|
||||
#define SIBA_MAX_CFG SIBA_CFG_NUM_2_3 /**< maximum number of supported config
|
||||
register blocks */
|
||||
|
||||
#define SIBA_CFG_RID_BASE 100 /**< base resource ID for SIBA_CFG* register allocations */
|
||||
#define SIBA_CFG_RID(_dinfo, _cfg) \
|
||||
(SIBA_CFG_RID_BASE + (_cfg) + \
|
||||
(_dinfo->core_id.core_info.core_idx * SIBA_MAX_CFG))
|
||||
|
||||
/* Sonics/OCP address space mappings */
|
||||
#define SIBA_CORE_ADDRSPACE 0 /**< Address space mapping the primary
|
||||
device registers */
|
||||
@ -155,7 +159,6 @@ struct siba_devinfo {
|
||||
struct siba_softc {
|
||||
struct bhnd_softc bhnd_sc; /**< bhnd state */
|
||||
device_t dev; /**< siba device */
|
||||
device_t hostb_dev; /**< host bridge core, or NULL */
|
||||
};
|
||||
|
||||
#endif /* _SIBA_SIBAVAR_H_ */
|
||||
|
@ -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 @@ __FBSDID("$FreeBSD$");
|
||||
#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 @@ static const struct bwn_pci_devcfg bwn_pci_devcfgs[] = {
|
||||
{
|
||||
.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 @@ bwn_pci_get_bhndb_hwtable(device_t dev, device_t child)
|
||||
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 @@ static device_method_t bwn_pci_methods[] = {
|
||||
/* 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
|
||||
|
@ -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_device {
|
||||
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_ */
|
||||
#endif /* _IF_BWN_PCIVAR_H_ */
|
||||
|
@ -219,7 +219,8 @@ bcm_erom_probe_and_attach(bhnd_erom_class_t **erom_cls, kobj_ops_t erom_ops,
|
||||
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 @@ bcm_erom_probe_and_attach(bhnd_erom_class_t **erom_cls, kobj_ops_t erom_ops,
|
||||
|
||||
/* ... 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);
|
||||
|
@ -9,6 +9,7 @@ SRCS= bhndb.c bhndb_subr.c bhndb_hwdata.c \
|
||||
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
|
||||
|
Loading…
Reference in New Issue
Block a user