Index: head/sys/dev/bhnd/bcma/bcma.c =================================================================== --- head/sys/dev/bhnd/bcma/bcma.c +++ head/sys/dev/bhnd/bcma/bcma.c @@ -686,6 +686,7 @@ { bhnd_erom_t *erom; struct bcma_erom *bcma_erom; + struct bhnd_erom_io *eio; const struct bhnd_chipid *cid; struct bcma_corecfg *corecfg; struct bcma_devinfo *dinfo; @@ -696,9 +697,12 @@ corecfg = NULL; /* Allocate our EROM parser */ - erom = bhnd_erom_alloc(&bcma_erom_parser, cid, bus, BCMA_EROM_RID); - if (erom == NULL) + eio = bhnd_erom_iores_new(bus, BCMA_EROM_RID); + erom = bhnd_erom_alloc(&bcma_erom_parser, cid, eio); + if (erom == NULL) { + bhnd_erom_io_fini(eio); return (ENODEV); + } /* Add all cores. */ bcma_erom = (struct bcma_erom *)erom; Index: head/sys/dev/bhnd/bcma/bcma_erom.c =================================================================== --- head/sys/dev/bhnd/bcma/bcma_erom.c +++ head/sys/dev/bhnd/bcma/bcma_erom.c @@ -1,7 +1,11 @@ /*- - * Copyright (c) 2015 Landon Fuller + * Copyright (c) 2015-2017 Landon Fuller + * Copyright (c) 2017 The FreeBSD Foundation * All rights reserved. * + * Portions of this software were developed by Landon Fuller + * under sponsorship from the FreeBSD Foundation. + * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: @@ -58,13 +62,8 @@ * 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); @@ -105,37 +104,18 @@ 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 */ + struct bhnd_erom obj; + device_t dev; /**< parent device, or NULL if none. */ + struct bhnd_erom_io *eio; /**< bus I/O callbacks */ + bhnd_size_t offset; /**< current read offset */ }; -#define EROM_LOG(erom, fmt, ...) do { \ - if (erom->dev != NULL) { \ - device_printf(erom->dev, "erom[0x%llx]: " fmt, \ - (unsigned long long) (erom->offset), ##__VA_ARGS__);\ - } else { \ - printf("erom[0x%llx]: " fmt, \ - (unsigned long long) (erom->offset), ##__VA_ARGS__);\ - } \ +#define EROM_LOG(erom, fmt, ...) do { \ + printf("%s erom[0x%llx]: " fmt, __FUNCTION__, \ + (unsigned long long)(erom->offset), ##__VA_ARGS__); \ } while(0) /** Return the type name for an EROM entry */ @@ -154,106 +134,52 @@ } } - -/** - * Read a 32-bit value from an EROM I/O context. - * - * @param io EROM I/O context. - * @param offset Read offset. - */ -static uint32_t -bcma_eio_read4(struct bcma_erom_io *io, bus_size_t offset) -{ - bus_size_t read_off; - - read_off = io->start + offset; - if (io->res != NULL) - return (bhnd_bus_read_4(io->res, read_off)); - else - return (bus_space_read_4(io->bst, io->bsh, read_off)); -} - -/* Initialize bcma_erom resource I/O context */ -static void -bcma_eio_init(struct bcma_erom_io *io, struct bhnd_resource *res, int rid, - bus_size_t offset) -{ - io->res = res; - io->rid = rid; - io->start = offset; -} - -/* Initialize bcma_erom bus space I/O context */ -static void -bcma_eio_init_static(struct bcma_erom_io *io, bus_space_tag_t bst, - bus_space_handle_t bsh, bus_size_t offset) -{ - io->res = NULL; - io->rid = -1; - io->bst = bst; - io->bsh = bsh; - io->start = offset; -} - /* BCMA implementation of BHND_EROM_INIT() */ static int bcma_erom_init(bhnd_erom_t *erom, const struct bhnd_chipid *cid, - device_t parent, int rid) + struct bhnd_erom_io *eio) { struct bcma_erom *sc; - struct bhnd_resource *res; + bhnd_addr_t table_addr; + int error; sc = (struct bcma_erom *)erom; - sc->dev = parent; + sc->eio = eio; 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); + /* Determine erom table address */ + if (BHND_ADDR_MAX - BCMA_EROM_TABLE_START < cid->enum_addr) + return (ENXIO); /* would overflow */ - if (res == NULL) - return (ENOMEM); + table_addr = cid->enum_addr + BCMA_EROM_TABLE_START; - bcma_eio_init(&sc->io, res, rid, BCMA_EROM_TABLE_START); + /* Try to map the erom table */ + error = bhnd_erom_io_map(sc->eio, table_addr, BCMA_EROM_TABLE_SIZE); + if (error) + return (error); return (0); } -/* BCMA implementation of BHND_EROM_INIT_STATIC() */ +/* BCMA implementation of BHND_EROM_PROBE() */ static int -bcma_erom_init_static(bhnd_erom_t *erom, const struct bhnd_chipid *cid, - bus_space_tag_t bst, bus_space_handle_t bsh) +bcma_erom_probe(bhnd_erom_class_t *cls, struct bhnd_erom_io *eio, + const struct bhnd_chipid *hint, struct bhnd_chipid *cid) { - struct bcma_erom *sc; + uint32_t idreg, eromptr; - sc = (struct bcma_erom *)erom; - sc->dev = NULL; - sc->offset = 0; - - bcma_eio_init_static(&sc->io, bst, bsh, BCMA_EROM_TABLE_START); - - return (0); -} - -/* Common implementation of BHND_EROM_PROBE/BHND_EROM_PROBE_STATIC */ -static int -bcma_erom_probe_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); + /* Confirm CHIPC_EROMPTR availability */ + idreg = bhnd_erom_io_read(eio, CHIPC_ID, 4); if (!BHND_CHIPTYPE_HAS_EROM(CHIPC_GET_BITS(idreg, CHIPC_ID_BUS))) return (ENXIO); /* Fetch EROM address */ - eromptr = bcma_eio_read4(io, CHIPC_EROMPTR); + eromptr = bhnd_erom_io_read(eio, CHIPC_EROMPTR, 4); /* Parse chip identifier */ *cid = bhnd_parse_chipid(idreg, eromptr); @@ -272,42 +198,12 @@ } } -static int -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_io io; - - bcma_eio_init(&io, res, rman_get_rid(res->res), - offset + BCMA_EROM_TABLE_START); - - 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->io.res != NULL) { - bhnd_release_resource(sc->dev, SYS_RES_MEMORY, sc->io.rid, - sc->io.res); - - sc->io.res = NULL; - sc->io.rid = -1; - } + bhnd_erom_io_fini(sc->eio); } static int @@ -591,8 +487,8 @@ EROM_LOG(erom, "BCMA EROM table missing terminating EOF\n"); return (EINVAL); } - - *entry = bcma_eio_read4(&erom->io, erom->offset); + + *entry = bhnd_erom_io_read(erom->eio, erom->offset, 4); return (0); } @@ -1520,9 +1416,7 @@ static kobj_method_t bcma_erom_methods[] = { KOBJMETHOD(bhnd_erom_probe, bcma_erom_probe), - KOBJMETHOD(bhnd_erom_probe_static, bcma_erom_probe_static), KOBJMETHOD(bhnd_erom_init, bcma_erom_init), - KOBJMETHOD(bhnd_erom_init_static, bcma_erom_init_static), KOBJMETHOD(bhnd_erom_fini, bcma_erom_fini), KOBJMETHOD(bhnd_erom_get_core_table, bcma_erom_get_core_table), KOBJMETHOD(bhnd_erom_free_core_table, bcma_erom_free_core_table), Index: head/sys/dev/bhnd/bhnd_erom.h =================================================================== --- head/sys/dev/bhnd/bhnd_erom.h +++ head/sys/dev/bhnd/bhnd_erom.h @@ -1,7 +1,11 @@ /*- - * Copyright (c) 2015-2016 Landon Fuller + * Copyright (c) 2015-2017 Landon Fuller + * Copyright (c) 2017 The FreeBSD Foundation * All rights reserved. * + * Portions of this software were developed by Landon Fuller + * under sponsorship from the FreeBSD Foundation. + * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: @@ -41,20 +45,39 @@ #include "bhnd_erom_if.h" -bhnd_erom_t *bhnd_erom_alloc(bhnd_erom_class_t *cls, - const struct bhnd_chipid *cid, - device_t parent, int rid); +/* forward declarations */ +struct bhnd_erom_io; +struct bhnd_erom_iobus; -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); +bhnd_erom_class_t *bhnd_erom_probe_driver_classes(devclass_t bus_devclass, + struct bhnd_erom_io *eio, + const struct bhnd_chipid *hint, + struct bhnd_chipid *cid); -void bhnd_erom_fini_static(bhnd_erom_t *erom); +bhnd_erom_t *bhnd_erom_alloc(bhnd_erom_class_t *cls, + const struct bhnd_chipid *cid, + struct bhnd_erom_io *eio); -void bhnd_erom_free(bhnd_erom_t *erom); +int bhnd_erom_init_static(bhnd_erom_class_t *cls, + bhnd_erom_t *erom, size_t esize, + const struct bhnd_chipid *cid, + struct bhnd_erom_io *eio); +void bhnd_erom_fini_static(bhnd_erom_t *erom); + +void bhnd_erom_free(bhnd_erom_t *erom); + +struct bhnd_erom_io *bhnd_erom_iores_new(device_t dev, int rid); +int bhnd_erom_iobus_init(struct bhnd_erom_iobus *iobus, + bhnd_addr_t addr, bhnd_size_t size, + bus_space_tag_t bst, bus_space_handle_t bsh); + +int bhnd_erom_io_map(struct bhnd_erom_io *eio, + bhnd_addr_t addr, bhnd_size_t size); +uint32_t bhnd_erom_io_read(struct bhnd_erom_io *eio, + bhnd_size_t offset, u_int width); +void bhnd_erom_io_fini(struct bhnd_erom_io *eio); + /** * Abstract bhnd_erom instance state. Must be first member of all subclass * instances. @@ -92,19 +115,18 @@ #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. + * mapped by @p eio, 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 eio A bus I/O instance, configured with a mapping of the + * first bus core. + * @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 @@ -117,43 +139,10 @@ * 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) +bhnd_erom_probe(bhnd_erom_class_t *cls, struct bhnd_erom_io *eio, + 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 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 - * parser for the probed bus. - * @retval negative if the probe succeeds, a negative value should be - * returned; the parser returning the lowest 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_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) -{ - return (BHND_EROM_PROBE_STATIC(cls, bst, bsh, paddr, hint, cid)); + return (BHND_EROM_PROBE(cls, eio, hint, cid)); } /** Index: head/sys/dev/bhnd/bhnd_erom.c =================================================================== --- head/sys/dev/bhnd/bhnd_erom.c +++ head/sys/dev/bhnd/bhnd_erom.c @@ -1,7 +1,11 @@ /*- * Copyright (c) 2016 Landon Fuller + * Copyright (c) 2017 The FreeBSD Foundation * All rights reserved. * + * Portions of this software were developed by Landon Fuller + * under sponsorship from the FreeBSD Foundation. + * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: @@ -31,20 +35,124 @@ __FBSDID("$FreeBSD$"); #include +#include #include + +#include +#include +#include #include #include +#include +static int bhnd_erom_iores_map(struct bhnd_erom_io *eio, bhnd_addr_t addr, + bhnd_size_t size); +static uint32_t bhnd_erom_iores_read(struct bhnd_erom_io *eio, + bhnd_size_t offset, u_int width); +static void bhnd_erom_iores_fini(struct bhnd_erom_io *eio); + +static int bhnd_erom_iobus_map(struct bhnd_erom_io *eio, bhnd_addr_t addr, + bhnd_size_t size); +static uint32_t bhnd_erom_iobus_read(struct bhnd_erom_io *eio, + bhnd_size_t offset, u_int width); + /** + * An implementation of bhnd_erom_io that manages mappings via + * bhnd_alloc_resource() and bhnd_release_resource(). + */ +struct bhnd_erom_iores { + struct bhnd_erom_io eio; + device_t owner; /**< device from which we'll allocate resources */ + int owner_rid; /**< rid to use when allocating new mappings */ + struct bhnd_resource *mapped; /**< current mapping, or NULL */ + int mapped_rid; /**< resource ID of current mapping, or -1 */ +}; + +/** + * Fetch the device enumeration parser class from all bhnd(4)-compatible drivers + * registered for @p bus_devclass, probe @p eio for supporting parser classes, + * and return the best available supporting enumeration parser class. + * + * @param bus_devclass The bus device class to be queried for + * bhnd(4)-compatible drivers. + * @param eio An erom bus I/O instance, configured with a + * mapping of the first bus core. + * @param hint Identification hint used to identify the device. + * If the 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 non-NULL on success, the best available EROM class. + * @retval NULL if no erom class returned a successful probe result for + * @p eio. + */ +bhnd_erom_class_t * +bhnd_erom_probe_driver_classes(devclass_t bus_devclass, + struct bhnd_erom_io *eio, const struct bhnd_chipid *hint, + struct bhnd_chipid *cid) +{ + driver_t **drivers; + int drv_count; + bhnd_erom_class_t *erom_cls; + int error, prio, result; + + erom_cls = NULL; + prio = 0; + + /* Fetch all available drivers */ + error = devclass_get_drivers(bus_devclass, &drivers, &drv_count); + if (error) { + printf("error fetching bhnd(4) drivers for %s: %d\n", + devclass_get_name(bus_devclass), error); + 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; + + /* The default implementation of BHND_BUS_GET_EROM_CLASS() + * returns NULL if unimplemented; this should always be safe + * to call on arbitrary drivers */ + cls = bhnd_driver_get_erom_class(drivers[i]); + if (cls == NULL) + continue; + + kobj_class_compile(cls); + + /* Probe the bus */ + result = bhnd_erom_probe(cls, eio, hint, &pcid); + + /* The parser did not match if an error was returned */ + if (result > 0) + continue; + + /* Check for a new highest priority match */ + if (erom_cls == NULL || result > prio) { + prio = result; + + *cid = pcid; + erom_cls = cls; + } + + /* Terminate immediately on BUS_PROBE_SPECIFIC */ + if (result == BUS_PROBE_SPECIFIC) + break; + } + + return (erom_cls); +} + +/** * Allocate and return a new device enumeration table parser. * * @param cls The parser class for which an instance will be * allocated. - * @param parent The parent device from which EROM resources should - * be allocated. - * @param rid The resource ID to be used when allocating EROM - * resources. + * @param eio The bus I/O callbacks to use when reading the device + * enumeration table. * @param cid The device's chip identifier. * * @retval non-NULL success @@ -53,7 +161,7 @@ */ bhnd_erom_t * bhnd_erom_alloc(bhnd_erom_class_t *cls, const struct bhnd_chipid *cid, - device_t parent, int rid) + struct bhnd_erom_io *eio) { bhnd_erom_t *erom; int error; @@ -61,10 +169,9 @@ erom = (bhnd_erom_t *)kobj_create((kobj_class_t)cls, M_BHND, M_WAITOK|M_ZERO); - 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)cid->enum_addr, rid, - error); + if ((error = BHND_EROM_INIT(erom, cid, eio))) { + printf("error initializing %s parser at %#jx: %d\n", cls->name, + (uintmax_t)cid->enum_addr, error); kobj_delete((kobj_t)erom, M_BHND); return (NULL); @@ -74,8 +181,7 @@ } /** - * Perform static initialization of aa device enumeration table parser using - * the provided bus space tag and handle. + * Perform static initialization of a device enumeration table parser. * * This may be used to initialize a caller-allocated erom instance state * during early boot, prior to malloc availability. @@ -87,9 +193,8 @@ * @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. + * @param eio The bus I/O callbacks to use when reading the device + * enumeration table. * * @retval 0 success * @retval ENOMEM if @p esize is smaller than required by @p cls. @@ -98,7 +203,7 @@ */ 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) + const struct bhnd_chipid *cid, struct bhnd_erom_io *eio) { kobj_class_t kcls; @@ -110,7 +215,7 @@ /* Perform instance initialization */ kobj_init_static((kobj_t)erom, kcls); - return (BHND_EROM_INIT_STATIC(erom, cid, bst, bsh)); + return (BHND_EROM_INIT(erom, cid, eio)); } /** @@ -138,4 +243,244 @@ { BHND_EROM_FINI(erom); kobj_delete((kobj_t)erom, M_BHND); +} + + +/** + * Attempt to map @p size bytes at @p addr, replacing any existing + * @p eio mapping. + * + * @param eio I/O instance state. + * @param addr The address to be mapped. + * @param size The number of bytes to be mapped at @p addr. + * + * @retval 0 success + * @retval non-zero if mapping @p addr otherwise fails, a regular + * unix error code should be returned. + */ +int +bhnd_erom_io_map(struct bhnd_erom_io *eio, bhnd_addr_t addr, bhnd_size_t size) +{ + return (eio->map(eio, addr, size)); +} + +/** + * Read a 1, 2, or 4 byte data item from @p eio, at the given @p offset + * relative to @p eio's current mapping. + * + * @param eio erom I/O callbacks + * @param offset read offset. + * @param width item width (1, 2, or 4 bytes). + */ +uint32_t +bhnd_erom_io_read(struct bhnd_erom_io *eio, bhnd_size_t offset, u_int width) +{ + return (eio->read(eio, offset, width)); +} + +/** + * Free all resources held by @p eio. + */ +void +bhnd_erom_io_fini(struct bhnd_erom_io *eio) +{ + if (eio->fini != NULL) + return (eio->fini(eio)); +} + +/** + * Allocate, initialize, and return a new I/O instance that will perform + * mapping by allocating SYS_RES_MEMORY resources from @p dev using @p rid. + * + * @param dev The device to pass to bhnd_alloc_resource() and + * bhnd_release_resource() functions. + * @param rid The resource ID to be used when allocating memory resources. + */ +struct bhnd_erom_io * +bhnd_erom_iores_new(device_t dev, int rid) +{ + struct bhnd_erom_iores *iores; + + iores = malloc(sizeof(*iores), M_BHND, M_WAITOK | M_ZERO); + iores->eio.map = bhnd_erom_iores_map; + iores->eio.read = bhnd_erom_iores_read; + iores->eio.fini = bhnd_erom_iores_fini; + + iores->owner = dev; + iores->owner_rid = rid; + iores->mapped = NULL; + iores->mapped_rid = -1; + + return (&iores->eio); +} + +static int +bhnd_erom_iores_map(struct bhnd_erom_io *eio, bhnd_addr_t addr, + bhnd_size_t size) +{ + struct bhnd_erom_iores *iores; + + iores = (struct bhnd_erom_iores *)eio; + + /* Sanity check the addr/size */ + if (size == 0) + return (EINVAL); + + if (BHND_ADDR_MAX - size < addr) + return (EINVAL); /* would overflow */ + + /* Check for an existing mapping */ + if (iores->mapped) { + /* If already mapped, nothing else to do */ + if (rman_get_start(iores->mapped->res) == addr && + rman_get_size(iores->mapped->res) == size) + { + return (0); + } + + /* Otherwise, we need to drop the existing mapping */ + bhnd_release_resource(iores->owner, SYS_RES_MEMORY, + iores->mapped_rid, iores->mapped); + iores->mapped = NULL; + iores->mapped_rid = -1; + } + + /* Try to allocate the new mapping */ + iores->mapped_rid = iores->owner_rid; + iores->mapped = bhnd_alloc_resource(iores->owner, SYS_RES_MEMORY, + &iores->mapped_rid, addr, addr+size-1, size, + RF_ACTIVE|RF_SHAREABLE); + if (iores->mapped == NULL) { + iores->mapped_rid = -1; + return (ENXIO); + } + + return (0); +} + +static uint32_t +bhnd_erom_iores_read(struct bhnd_erom_io *eio, bhnd_size_t offset, u_int width) +{ + struct bhnd_erom_iores *iores = (struct bhnd_erom_iores *)eio; + + if (iores->mapped == NULL) + panic("read with invalid mapping"); + + switch (width) { + case 1: + return (bhnd_bus_read_1(iores->mapped, offset)); + case 2: + return (bhnd_bus_read_2(iores->mapped, offset)); + case 4: + return (bhnd_bus_read_4(iores->mapped, offset)); + default: + panic("invalid width %u", width); + } +} + +static void +bhnd_erom_iores_fini(struct bhnd_erom_io *eio) +{ + struct bhnd_erom_iores *iores = (struct bhnd_erom_iores *)eio; + + /* Release any mapping */ + if (iores->mapped) { + bhnd_release_resource(iores->owner, SYS_RES_MEMORY, + iores->mapped_rid, iores->mapped); + iores->mapped = NULL; + iores->mapped_rid = -1; + } + + free(eio, M_BHND); +} + +/** + * Initialize an I/O instance that will perform mapping directly from the + * given bus space tag and handle. + * + * @param addr The base address mapped by @p bsh. + * @param size The total size mapped by @p bsh. + * @param bst Bus space tag for @p bsh. + * @param bsh Bus space handle mapping the full bus enumeration space. + * + * @retval 0 success + * @retval non-zero if initializing @p iobus otherwise fails, a regular + * unix error code will be returned. + */ +int +bhnd_erom_iobus_init(struct bhnd_erom_iobus *iobus, bhnd_addr_t addr, + bhnd_size_t size, bus_space_tag_t bst, bus_space_handle_t bsh) +{ + iobus->eio.map = bhnd_erom_iobus_map; + iobus->eio.read = bhnd_erom_iobus_read; + iobus->eio.fini = NULL; + + iobus->addr = addr; + iobus->size = size; + iobus->bst = bst; + iobus->bsh = bsh; + iobus->mapped = false; + + return (0); +} + +static int +bhnd_erom_iobus_map(struct bhnd_erom_io *eio, bhnd_addr_t addr, + bhnd_size_t size) +{ + struct bhnd_erom_iobus *iobus = (struct bhnd_erom_iobus *)eio; + + /* Sanity check the addr/size */ + if (size == 0) + return (EINVAL); + + /* addr+size must not overflow */ + if (BHND_ADDR_MAX - size < addr) + return (EINVAL); + + /* addr/size must fit within our bus tag's mapping */ + if (addr < iobus->addr || size > iobus->size) + return (ENXIO); + + if (iobus->size - (addr - iobus->addr) < size) + return (ENXIO); + + /* The new addr offset and size must be representible as a bus_size_t */ + if ((addr - iobus->addr) > BUS_SPACE_MAXSIZE) + return (ENXIO); + + if (size > BUS_SPACE_MAXSIZE) + return (ENXIO); + + iobus->offset = addr - iobus->addr; + iobus->limit = size; + iobus->mapped = true; + + return (0); +} + +static uint32_t +bhnd_erom_iobus_read(struct bhnd_erom_io *eio, bhnd_size_t offset, u_int width) +{ + struct bhnd_erom_iobus *iobus = (struct bhnd_erom_iobus *)eio; + + if (!iobus->mapped) + panic("no active mapping"); + + if (iobus->limit < width || iobus->limit - width < offset) + panic("invalid offset %#jx", offset); + + switch (width) { + case 1: + return (bus_space_read_1(iobus->bst, iobus->bsh, + iobus->offset + offset)); + case 2: + return (bus_space_read_2(iobus->bst, iobus->bsh, + iobus->offset + offset)); + case 4: + return (bus_space_read_4(iobus->bst, iobus->bsh, + iobus->offset + offset)); + default: + panic("invalid width %u", width); + } } Index: head/sys/dev/bhnd/bhnd_erom_if.m =================================================================== --- head/sys/dev/bhnd/bhnd_erom_if.m +++ head/sys/dev/bhnd/bhnd_erom_if.m @@ -1,7 +1,11 @@ #- -# Copyright (c) 2016 Landon Fuller +# Copyright (c) 2016-2017 Landon Fuller +# Copyright (c) 2017 The FreeBSD Foundation # All rights reserved. # +# Portions of this software were developed by Landon Fuller +# under sponsorship from the FreeBSD Foundation. +# # Redistribution and use in source and binary forms, with or without # modification, are permitted provided that the following conditions # are met: @@ -43,51 +47,25 @@ # 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; +HEADER { + /* forward declarations */ + struct bhnd_erom_io; }; /** - * 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. + * Probe to see if this device enumeration class supports the bhnd bus at + * @p addr, returning a standard newbus device probe result (see BUS_PROBE_*) + * and the probed chip identification. * - * @param cls The erom class to probe. - * @param bst Bus space tag. - * @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. + * @param cls The erom class to probe. + * @param eio A bus I/O instance, configured with a mapping of + * the first bus core. + * @param base_addr Address of the first bus core. + * @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. @@ -98,11 +76,9 @@ * @retval positive if an error occurs during probing, a regular unix error * code should be returned. */ -STATICMETHOD int probe_static { +STATICMETHOD int probe { bhnd_erom_class_t *cls; - bus_space_tag_t bst; - bus_space_handle_t bsh; - bus_addr_t paddr; + struct bhnd_erom_io *eio; const struct bhnd_chipid *hint; struct bhnd_chipid *cid; }; @@ -112,11 +88,9 @@ * * @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 eio The bus I/O instance to use when reading the device + * enumeration table. On success, the erom parser assumes + * ownership of this instance. * @retval 0 success * @retval non-zero if an error occurs initializing the EROM parser, * a regular unix error code will be returned. @@ -124,29 +98,7 @@ METHOD int init { 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 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; - const struct bhnd_chipid *cid; - bus_space_tag_t bst; - bus_space_handle_t bsh; + struct bhnd_erom_io *eio; }; /** Index: head/sys/dev/bhnd/bhnd_eromvar.h =================================================================== --- head/sys/dev/bhnd/bhnd_eromvar.h +++ head/sys/dev/bhnd/bhnd_eromvar.h @@ -0,0 +1,79 @@ +/*- + * Copyright (c) 2017 The FreeBSD Foundation + * All rights reserved. + * + * This software was developed by Landon Fuller under sponsorship from + * the FreeBSD Foundation. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer, + * without modification. + * 2. Redistributions in binary form must reproduce at minimum a disclaimer + * similar to the "NO WARRANTY" disclaimer below ("Disclaimer") and any + * redistribution must be conditioned upon including a substantially + * similar Disclaimer requirement for further binary redistribution. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF NONINFRINGEMENT, MERCHANTIBILITY + * AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL + * THE COPYRIGHT HOLDERS OR CONTRIBUTORS BE LIABLE FOR SPECIAL, EXEMPLARY, + * OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER + * IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF + * THE POSSIBILITY OF SUCH DAMAGES. + * + * $FreeBSD$ + */ + +#ifndef _BHND_EROM_BHND_EROMVAR_H_ +#define _BHND_EROM_BHND_EROMVAR_H_ + +#include + +#include "bhnd_erom.h" + +/* forward declarations */ +struct bhnd_erom_io; +struct bhnd_erom_iobus; + +/** @see bhnd_erom_io_map() */ +typedef int (bhnd_erom_io_map_t)(struct bhnd_erom_io *eio, + bhnd_addr_t addr, bhnd_size_t size); + +/** @see bhnd_erom_io_read() */ +typedef uint32_t (bhnd_erom_io_read_t)(struct bhnd_erom_io *eio, + bhnd_size_t offset, u_int width); + +/** @see bhnd_erom_io_fini() */ +typedef void (bhnd_erom_io_fini_t)(struct bhnd_erom_io *eio); + +/** + * Abstract EROM bus I/O support. + */ +struct bhnd_erom_io { + bhnd_erom_io_map_t *map; /**< @see bhnd_erom_io_map() */ + bhnd_erom_io_read_t *read; /**< @see bhnd_erom_io_read() */ + bhnd_erom_io_fini_t *fini; /**< @see bhnd_erom_io_fini(). May be NULL */ +}; + +/** + * EROM bus handle/tag I/O instance state. + */ +struct bhnd_erom_iobus { + struct bhnd_erom_io eio; + bhnd_addr_t addr; /**< the address of @p bsh */ + bhnd_size_t size; /**< the size of @p bsh */ + bus_space_tag_t bst; /**< bus space tag */ + bus_space_handle_t bsh; /**< bus space handle mapping the full enumeration space */ + bool mapped; /**< if a mapping is active */ + bus_size_t offset; /**< the current mapped offset within bsh */ + bus_size_t limit; /**< the current mapped size relative to offset */ +}; + +#endif /* _BHND_EROM_BHND_EROMVAR_H_ */ Index: head/sys/dev/bhnd/bhndb/bhndb.c =================================================================== --- head/sys/dev/bhnd/bhndb/bhndb.c +++ head/sys/dev/bhnd/bhndb/bhndb.c @@ -77,18 +77,6 @@ #define BHNDB_DEBUG(_type) (BHNDB_DEBUG_ ## _type & bhndb_debug) -static int bhndb_find_hostb_core(struct bhndb_softc *sc, - bhnd_erom_t *erom, - struct bhnd_core_info *core); - -static bhnd_erom_class_t *bhndb_probe_erom_class(struct bhndb_softc *sc, - struct bhnd_chipid *cid); - -static int bhndb_init_full_config(struct bhndb_softc *sc, - bhnd_erom_class_t *eromcls); - -static struct bhnd_core_info *bhndb_get_bridge_core(struct bhndb_softc *sc); - static bool bhndb_hw_matches(struct bhndb_softc *sc, struct bhnd_core_info *cores, u_int ncores, const struct bhndb_hw *hw); @@ -201,21 +189,6 @@ } /** - * Return the bridge core info. Will panic if the bridge core info has not yet - * been populated during full bridge configuration. - * - * @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 sc BHNDB device state. @@ -507,52 +480,67 @@ * 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 - * cores (e.g. PCMCIA on a PCIe device). + * @param dev The bridge device to attach. + * @param cid The bridged device's chip identification. + * @param cores The bridged device's core table. + * @param ncores The number of cores in @p cores. + * @param bridge_core Core info for the bhnd(4) core serving as the host + * bridge. + * @param erom_class An erom parser class that may be used to parse + * the bridged device's device enumeration table. */ int -bhndb_attach(device_t dev, bhnd_devclass_t bridge_devclass) +bhndb_attach(device_t dev, struct bhnd_chipid *cid, + struct bhnd_core_info *cores, u_int ncores, + struct bhnd_core_info *bridge_core, bhnd_erom_class_t *erom_class) { struct bhndb_devinfo *dinfo; struct bhndb_softc *sc; - const struct bhndb_hwcfg *cfg; - bhnd_erom_class_t *eromcls; + const struct bhndb_hw *hw; + const struct bhndb_hwcfg *hwcfg; + const struct bhndb_hw_priority *hwprio; + struct bhnd_erom_io *eio; + bhnd_erom_t *erom; int error; sc = device_get_softc(dev); sc->dev = dev; sc->parent_dev = device_get_parent(dev); - sc->bridge_class = bridge_devclass; + sc->bridge_core = *bridge_core; + sc->chipid = *cid; if ((error = bhnd_service_registry_init(&sc->services))) return (error); BHNDB_LOCK_INIT(sc); - - /* 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) - goto failed; - /* Allocate our host resources */ - if ((error = bhndb_alloc_host_resources(sc->bus_res))) - goto failed; + erom = NULL; - /* 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); + /* Find a matching bridge hardware configuration */ + if ((error = bhndb_find_hwspec(sc, cores, ncores, &hw))) { + device_printf(sc->dev, "unable to identify device, " + " using generic bridge resource definitions\n"); - device_printf(sc->dev, "device enumeration unsupported; no " - "compatible driver found\n"); - return (ENXIO); + hwcfg = BHNDB_BUS_GET_GENERIC_HWCFG(sc->parent_dev, dev); + hw = NULL; + } else { + hwcfg = hw->cfg; } - BHNDB_UNLOCK(sc); + if (hw != NULL && (bootverbose || BHNDB_DEBUG(PRIO))) { + device_printf(sc->dev, "%s resource configuration\n", hw->name); + } + + /* Allocate bridge resource state using the discovered hardware + * configuration */ + sc->bus_res = bhndb_alloc_resources(sc->dev, sc->parent_dev, hwcfg); + if (sc->bus_res == NULL) { + device_printf(sc->dev, "failed to allocate bridge resource " + "state\n"); + error = ENOMEM; + goto failed; + } + /* Add our bridged bus device */ sc->bus_dev = BUS_ADD_CHILD(dev, BHND_PROBE_BUS, "bhnd", -1); if (sc->bus_dev == NULL) { @@ -563,345 +551,41 @@ dinfo = device_get_ivars(sc->bus_dev); dinfo->addrspace = BHNDB_ADDRSPACE_BRIDGED; - /* 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); + /* We can now use bhndb to perform bridging of SYS_RES_MEMORY resources; + * we use this to instantiate an erom parser instance */ + eio = bhnd_erom_iores_new(sc->bus_dev, 0); + if ((erom = bhnd_erom_alloc(erom_class, cid, eio)) == NULL) { + bhnd_erom_io_fini(eio); + error = ENXIO; goto failed; } - return (0); - -failed: - BHNDB_LOCK_DESTROY(sc); - - if (sc->bus_res != NULL) - bhndb_free_resources(sc->bus_res); - - bhnd_service_registry_fini(&sc->services); - - return (error); -} - - -/** - * Return a borrowed reference to the host resource mapping at least - * BHND_DEFAULT_CORE_SIZE bytes at the first bus core, for use with - * bhnd_erom_probe(). - * - * This may return a borrowed reference to a bhndb_dw_alloc-managed - * resource; any additional resource mapping requests may invalidate this - * borrowed reference. - * - * @param sc BHNDB driver state. - * @param[out] offset On success, the offset within the returned resource - * at which the first bus core can be found. - * - * @retval non-NULL success. - * @retval NULL If no usable mapping could be found. - */ -static struct resource * -bhndb_erom_chipc_resource(struct bhndb_softc *sc, bus_size_t *offset) -{ - const struct bhndb_hwcfg *cfg; - struct bhndb_dw_alloc *dwa; - struct resource *res; - const struct bhndb_regwin *win; - - BHNDB_LOCK_ASSERT(sc, MA_OWNED); - - cfg = sc->bus_res->cfg; - - /* Find a static register window mapping ChipCommon. */ - win = bhndb_regwin_find_core(cfg->register_windows, BHND_DEVCLASS_CC, - 0, BHND_PORT_DEVICE, 0, 0); - if (win != NULL) { - if (win->win_size < BHND_DEFAULT_CORE_SIZE) { - device_printf(sc->dev, - "chipcommon register window too small\n"); - return (NULL); - } - - res = bhndb_find_regwin_resource(sc->bus_res, win); - if (res == NULL) { - device_printf(sc->dev, - "chipcommon register window not allocated\n"); - return (NULL); - } - - *offset = win->win_offset; - return (res); - } - - /* We'll need to fetch and configure a dynamic window. We can assume a - * device without a static ChipCommon mapping uses the default siba(4) - * base address. */ - dwa = bhndb_io_resource(sc, BHND_DEFAULT_CHIPC_ADDR, - BHND_DEFAULT_CORE_SIZE, offset); - if (dwa != NULL) - return (dwa->parent_res); - - device_printf(sc->dev, "unable to map chipcommon registers; no usable " - "register window found\n"); - return (NULL); -} - -/** - * Probe all supported EROM classes, returning the best matching class - * (or NULL if not found), writing the probed chip identifier to @p cid. - * - * @param sc BHNDB driver state. - * @param cid On success, the bridged chipset's chip identifier. - */ -static bhnd_erom_class_t * -bhndb_probe_erom_class(struct bhndb_softc *sc, struct bhnd_chipid *cid) -{ - devclass_t bhndb_devclass; - const struct bhnd_chipid *hint; - struct resource *res; - bus_size_t res_offset; - driver_t **drivers; - int drv_count; - bhnd_erom_class_t *erom_cls; - int prio, result; - - BHNDB_LOCK_ASSERT(sc, MA_OWNED); - - erom_cls = NULL; - prio = 0; - - /* Let our parent device provide a chipid hint */ - hint = BHNDB_BUS_GET_CHIPID(sc->parent_dev, sc->dev); - - /* Fetch a borrowed reference to the resource mapping ChipCommon. */ - res = bhndb_erom_chipc_resource(sc, &res_offset); - if (res == NULL) - return (NULL); - - /* Fetch all available drivers */ - bhndb_devclass = device_get_devclass(sc->dev); - if (devclass_get_drivers(bhndb_devclass, &drivers, &drv_count) != 0) - return (NULL); - - /* Enumerate the drivers looking for the best available EROM class */ - for (int i = 0; i < drv_count; i++) { - struct bhnd_chipid pcid; - bhnd_erom_class_t *cls; - - cls = bhnd_driver_get_erom_class(drivers[i]); - if (cls == NULL) - continue; - - kobj_class_compile(cls); - - /* Probe the bus */ - result = bhnd_erom_probe(cls, &BHND_DIRECT_RESOURCE(res), - res_offset, hint, &pcid); - - /* The parser did not match if an error was returned */ - if (result > 0) - continue; - - /* Check for a new highest priority match */ - if (erom_cls == NULL || result > prio) { - prio = result; - - *cid = pcid; - erom_cls = cls; - } - - /* Terminate immediately on BUS_PROBE_SPECIFIC */ - if (result == BUS_PROBE_SPECIFIC) - break; - } - - return (erom_cls); -} - -/* ascending core index comparison used by bhndb_find_hostb_core() */ -static int -compare_core_index(const void *lhs, const void *rhs) -{ - u_int left = ((const struct bhnd_core_info *)lhs)->core_idx; - u_int right = ((const struct bhnd_core_info *)rhs)->core_idx; - - if (left < right) - return (-1); - else if (left > right) - return (1); - else - return (0); -} - -/** - * Search @p erom for the core serving as the bhnd host bridge. - * - * This function uses a heuristic valid on all known PCI/PCIe/PCMCIA-bridged - * bhnd(4) devices to determine the hostb core: - * - * - The core must have a Broadcom vendor ID. - * - The core devclass must match the bridge type. - * - The core must be the first device on the bus with the bridged device - * class. - * - * @param sc BHNDB device state. - * @param erom The device enumeration table parser to be used to fetch - * core info. - * @param[out] core If found, the matching core info. - * - * @retval 0 success - * @retval ENOENT not found - * @retval non-zero if an error occured fetching core info. - */ -static int -bhndb_find_hostb_core(struct bhndb_softc *sc, bhnd_erom_t *erom, - struct bhnd_core_info *core) -{ - struct bhnd_core_match md; - struct bhnd_core_info *cores; - u_int ncores; - int error; - - 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"); - 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, cores, ncores, &hw))) { - device_printf(sc->dev, "unable to identify device, " - " using generic bridge resource definitions\n"); - error = 0; - goto cleanup; - } - - if (bootverbose || BHNDB_DEBUG(PRIO)) - device_printf(sc->dev, "%s resource configuration\n", hw->name); - - /* 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; - } - /* 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); + error = bhndb_init_region_cfg(sc, erom, sc->bus_res, cores, ncores, + hwprio); if (error) { device_printf(sc->dev, "failed to initialize resource " "priority configuration: %d\n", error); - goto cleanup; + goto failed; } - /* The EROM parser holds a reference to the resource state we're - * about to invalidate */ - bhnd_erom_free_core_table(erom, cores); + /* Free our erom instance */ 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: - if (cores != NULL) - bhnd_erom_free_core_table(erom, cores); +failed: + BHNDB_LOCK_DESTROY(sc); + if (sc->bus_res != NULL) + bhndb_free_resources(sc->bus_res); + if (erom != NULL) bhnd_erom_free(erom); - if (br != NULL) - bhndb_free_resources(br); + bhnd_service_registry_fini(&sc->services); return (error); } @@ -1190,7 +874,6 @@ struct bhnd_core_info *core) { struct bhndb_softc *sc; - struct bhnd_core_info *bridge_core; sc = device_get_softc(dev); @@ -1200,9 +883,8 @@ /* 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 (!bhnd_cores_equal(core, bridge_core)); + return (!bhnd_cores_equal(core, &sc->bridge_core)); /* Assume the core is populated */ return (false); @@ -1219,7 +901,7 @@ { struct bhndb_softc *sc = device_get_softc(dev); - *core = *bhndb_get_bridge_core(sc); + *core = sc->bridge_core; return (0); } @@ -1498,7 +1180,7 @@ r_size = rman_get_size(r); /* Find the corresponding bridge resource */ - bridge_res = bhndb_find_regwin_resource(sc->bus_res, win); + bridge_res = bhndb_host_resource_for_regwin(sc->bus_res->res, win); if (bridge_res == NULL) return (ENXIO); @@ -1618,8 +1300,8 @@ struct resource *parent; /* Find the bridge resource referenced by the child */ - parent = bhndb_find_resource_range(sc->bus_res, r_start, - r_size); + parent = bhndb_host_resource_for_range(sc->bus_res->res, + type, r_start, r_size); if (parent == NULL) { device_printf(sc->dev, "host resource not found " "for 0x%llx-0x%llx\n", Index: head/sys/dev/bhnd/bhndb/bhndb_pci.c =================================================================== --- head/sys/dev/bhnd/bhndb/bhndb_pci.c +++ head/sys/dev/bhnd/bhndb/bhndb_pci.c @@ -1,7 +1,11 @@ /*- * Copyright (c) 2015-2016 Landon Fuller + * Copyright (c) 2017 The FreeBSD Foundation * All rights reserved. * + * Portions of this software were developed by Landon Fuller + * under sponsorship from the FreeBSD Foundation. + * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: @@ -55,23 +59,36 @@ #include #include +#include +#include +#include + #include #include "bhndb_pcireg.h" #include "bhndb_pcivar.h" #include "bhndb_private.h" +struct bhndb_pci_eio; + static int bhndb_pci_init_msi(struct bhndb_pci_softc *sc); +static int bhndb_pci_read_core_table(device_t dev, + struct bhnd_chipid *chipid, + struct bhnd_core_info **cores, u_int *ncores, + bhnd_erom_class_t **eromcls); 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); +static bool bhndb_is_pcie_attached(device_t dev); -static int bhndb_pci_compat_setregwin(struct bhndb_pci_softc *, +static int bhndb_enable_pci_clocks(device_t dev); +static int bhndb_disable_pci_clocks(device_t dev); + +static int bhndb_pci_compat_setregwin(device_t dev, + device_t pci_dev, const struct bhndb_regwin *, + bhnd_addr_t); +static int bhndb_pci_fast_setregwin(device_t dev, device_t pci_dev, const struct bhndb_regwin *, bhnd_addr_t); -static int bhndb_pci_fast_setregwin(struct bhndb_pci_softc *, - const struct bhndb_regwin *, bhnd_addr_t); static void bhndb_init_sromless_pci_config( struct bhndb_pci_softc *sc); @@ -79,8 +96,30 @@ static bus_addr_t bhndb_pci_sprom_addr(struct bhndb_pci_softc *sc); static bus_size_t bhndb_pci_sprom_size(struct bhndb_pci_softc *sc); +static int bhndb_pci_eio_init(struct bhndb_pci_eio *pio, + device_t dev, device_t pci_dev, + struct bhndb_host_resources *hr); +static int bhndb_pci_eio_map(struct bhnd_erom_io *eio, + bhnd_addr_t addr, bhnd_size_t size); +static uint32_t bhndb_pci_eio_read(struct bhnd_erom_io *eio, + bhnd_size_t offset, u_int width); + #define BHNDB_PCI_MSI_COUNT 1 +/* bhndb_pci erom I/O implementation */ +struct bhndb_pci_eio { + struct bhnd_erom_io eio; + device_t dev; /**< bridge device */ + device_t pci_dev; /**< parent PCI device */ + struct bhndb_host_resources *hr; /**< borrowed reference to host resources */ + const struct bhndb_regwin *win; /**< mapped register window, or NULL */ + struct resource *res; /**< resource containing the register window, or NULL if no window mapped */ + bhnd_addr_t res_target; /**< current target address (if mapped) */ + bool mapped; /**< true if a valid mapping exists, false otherwise */ + bhnd_addr_t addr; /**< mapped address */ + bhnd_size_t size; /**< mapped size */ +}; + /** * Default bhndb_pci implementation of device_probe(). * @@ -137,17 +176,23 @@ bhndb_pci_attach(device_t dev) { struct bhndb_pci_softc *sc; + struct bhnd_chipid cid; + struct bhnd_core_info *cores, hostb_core; + bhnd_erom_class_t *erom_class; + u_int ncores; int error, reg; sc = device_get_softc(dev); sc->dev = dev; sc->parent = device_get_parent(dev); - sc->set_regwin = bhndb_pci_compat_setregwin; + sc->set_regwin = NULL; + cores = NULL; + /* Enable PCI bus mastering */ pci_enable_busmaster(sc->parent); - /* Set up interrupt handling */ + /* Set up PCI interrupt handling */ if (bhndb_pci_init_msi(sc) == 0) { device_printf(dev, "Using MSI interrupts on %s\n", device_get_nameunit(sc->parent)); @@ -165,23 +210,33 @@ sc->pci_devclass = BHND_DEVCLASS_PCI; /* Enable clocks (if required by this hardware) */ - if ((error = bhndb_enable_pci_clocks(sc))) + if ((error = bhndb_enable_pci_clocks(sc->dev))) goto cleanup; - /* Perform bridge attach, fully initializing the bridge - * configuration. */ - if ((error = bhndb_attach(dev, sc->pci_devclass))) + /* Identify the chip and enumerate the bridged cores */ + error = bhndb_pci_read_core_table(dev, &cid, &cores, &ncores, + &erom_class); + if (error) 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); + /* Select the appropriate register window handler */ + if (cid.chip_type == BHND_CHIPTYPE_SIBA) { + sc->set_regwin = bhndb_pci_compat_setregwin; + } else { + sc->set_regwin = bhndb_pci_fast_setregwin; } - /* Enable PCI bus mastering */ - pci_enable_busmaster(sc->parent); + /* Determine our host bridge core */ + error = bhndb_find_hostb_core(cores, ncores, sc->pci_devclass, + &hostb_core); + if (error) + goto cleanup; + /* Perform bridge attach */ + error = bhndb_attach(dev, &cid, cores, ncores, &hostb_core, erom_class); + if (error) + goto cleanup; + /* Fix-up power on defaults for SROM-less devices. */ bhndb_init_sromless_pci_config(sc); @@ -193,14 +248,20 @@ if ((error = bus_generic_attach(dev))) goto cleanup; + free(cores, M_BHND); + return (0); cleanup: device_delete_children(dev); - bhndb_disable_pci_clocks(sc); + bhndb_disable_pci_clocks(sc->dev); + if (sc->intr.msi_count > 0) pci_release_msi(dev); + if (cores != NULL) + free(cores, M_BHND); + pci_disable_busmaster(sc->parent); return (error); @@ -223,7 +284,7 @@ return (error); /* Disable clocks (if required by this hardware) */ - if ((error = bhndb_disable_pci_clocks(sc))) + if ((error = bhndb_disable_pci_clocks(sc->dev))) return (error); /* Release MSI interrupts */ @@ -236,7 +297,125 @@ return (0); } +/** + * Use the generic PCI bridge hardware configuration to enumerate the bridged + * bhnd(4) bus' core table. + * + * @note This function may be safely called prior to device attach, (e.g. + * from DEVICE_PROBE). + * @note This function requires exclusive ownership over allocating and + * configuring host bridge resources, and should only be called prior to + * completion of device attach and full configuration of the bridge. + * + * @param dev The bhndb_pci bridge device. + * @param[out] chipid On success, the parsed chip identification. + * @param[out] cores On success, the enumerated core table. The + * caller is responsible for freeing this table via + * bhndb_pci_free_core_table(). + * @param[out] ncores On success, the number of cores found in + * @p cores. + * @param[out] eromcls On success, a pointer to the erom class used to + * parse the device enumeration table. This + * argument may be NULL if the class is not + * desired. + * + * @retval 0 success + * @retval non-zero if enumerating the bridged bhnd(4) bus fails, a regular + * unix error code will be returned. + */ static int +bhndb_pci_read_core_table(device_t dev, struct bhnd_chipid *chipid, + struct bhnd_core_info **cores, u_int *ncores, + bhnd_erom_class_t **eromcls) +{ + const struct bhndb_hwcfg *cfg; + struct bhndb_host_resources *hr; + struct bhndb_pci_eio pio; + struct bhnd_core_info *erom_cores; + const struct bhnd_chipid *hint; + struct bhnd_chipid cid; + bhnd_erom_class_t *erom_class; + bhnd_erom_t *erom; + device_t parent_dev; + u_int erom_ncores; + int error; + + parent_dev = device_get_parent(dev); + erom = NULL; + erom_cores = NULL; + + /* Fetch our chipid hint (if any) and generic hardware configuration */ + cfg = BHNDB_BUS_GET_GENERIC_HWCFG(parent_dev, dev); + hint = BHNDB_BUS_GET_CHIPID(parent_dev, dev); + + /* Allocate our host resources */ + if ((error = bhndb_alloc_host_resources(parent_dev, cfg, &hr))) + return (error); + + /* Initialize our erom I/O state */ + if ((error = bhndb_pci_eio_init(&pio, dev, parent_dev, hr))) + goto failed; + + /* Map the first bus core from our bridged bhnd(4) bus */ + error = bhndb_pci_eio_map(&pio.eio, BHND_DEFAULT_CHIPC_ADDR, + BHND_DEFAULT_CORE_SIZE); + if (error) + goto failed; + + /* Probe for a usable EROM class, and read the chip identifier */ + erom_class = bhnd_erom_probe_driver_classes(device_get_devclass(dev), + &pio.eio, hint, &cid); + if (erom_class == NULL) { + device_printf(dev, "device enumeration unsupported; no " + "compatible driver found\n"); + + error = ENXIO; + goto failed; + } + + /* Allocate EROM parser */ + if ((erom = bhnd_erom_alloc(erom_class, &cid, &pio.eio)) == NULL) { + device_printf(dev, "failed to allocate device enumeration " + "table parser\n"); + error = ENXIO; + goto failed; + } + + /* Read the full core table */ + error = bhnd_erom_get_core_table(erom, &erom_cores, &erom_ncores); + if (error) { + device_printf(dev, "error fetching core table: %d\n", error); + goto failed; + } + + /* Provide the results to our caller */ + *cores = malloc(sizeof(erom_cores[0]) * erom_ncores, M_BHND, M_WAITOK); + memcpy(*cores, erom_cores, sizeof(erom_cores[0]) * erom_ncores); + *ncores = erom_ncores; + + *chipid = cid; + if (eromcls != NULL) + *eromcls = erom_class; + + /* Clean up */ + bhnd_erom_free_core_table(erom, erom_cores); + bhnd_erom_free(erom); + bhndb_release_host_resources(hr); + + return (0); + +failed: + if (erom_cores != NULL) + bhnd_erom_free_core_table(erom, erom_cores); + + if (erom != NULL) + bhnd_erom_free(erom); + + bhndb_release_host_resources(hr); + return (error); +} + +static int bhndb_pci_add_children(struct bhndb_pci_softc *sc) { bus_size_t nv_sz; @@ -309,7 +488,7 @@ KASSERT(sprom_win != NULL, ("requested sprom address on PCI_V2+")); /* Fetch the associated resource */ - r = bhndb_find_regwin_resource(sc->bhndb.bus_res, sprom_win); + r = bhndb_host_resource_for_regwin(sc->bhndb.bus_res->res, sprom_win); KASSERT(r != NULL, ("missing resource for sprom window\n")); return (rman_get_start(r) + sprom_win->win_offset); @@ -419,7 +598,7 @@ } /* Fetch the resource containing the register window */ - core_regs = bhndb_find_regwin_resource(bres, win); + core_regs = bhndb_host_resource_for_regwin(bres->res, win); if (core_regs == NULL) { device_printf(sc->dev, "missing PCI core register resource\n"); return; @@ -449,7 +628,7 @@ sc = device_get_softc(dev); /* Enable clocks (if supported by this hardware) */ - if ((error = bhndb_enable_pci_clocks(sc))) + if ((error = bhndb_enable_pci_clocks(sc->dev))) return (error); /* Perform resume */ @@ -465,7 +644,7 @@ sc = device_get_softc(dev); /* Disable clocks (if supported by this hardware) */ - if ((error = bhndb_disable_pci_clocks(sc))) + if ((error = bhndb_disable_pci_clocks(sc->dev))) return (error); /* Perform suspend */ @@ -477,7 +656,7 @@ bhnd_addr_t addr) { struct bhndb_pci_softc *sc = device_get_softc(dev); - return (sc->set_regwin(sc, rw, addr)); + return (sc->set_regwin(sc->dev, sc->parent, rw, addr)); } /** @@ -491,7 +670,7 @@ * validating the register, there's no harm in performing the verification. */ static int -bhndb_pci_compat_setregwin(struct bhndb_pci_softc *sc, +bhndb_pci_compat_setregwin(device_t dev, device_t pci_dev, const struct bhndb_regwin *rw, bhnd_addr_t addr) { int error; @@ -502,10 +681,10 @@ reg = rw->d.dyn.cfg_offset; for (u_int i = 0; i < BHNDB_PCI_BARCTRL_WRITE_RETRY; i++) { - if ((error = bhndb_pci_fast_setregwin(sc, rw, addr))) + if ((error = bhndb_pci_fast_setregwin(dev, pci_dev, rw, addr))) return (error); - if (pci_read_config(sc->parent, reg, 4) == addr) + if (pci_read_config(pci_dev, reg, 4) == addr) return (0); DELAY(10); @@ -519,7 +698,7 @@ * A bcma(4)-only bhndb_set_window_addr implementation. */ static int -bhndb_pci_fast_setregwin(struct bhndb_pci_softc *sc, +bhndb_pci_fast_setregwin(device_t dev, device_t pci_dev, const struct bhndb_regwin *rw, bhnd_addr_t addr) { /* The PCI bridge core only supports 32-bit addressing, regardless @@ -533,7 +712,7 @@ if (addr % rw->win_size != 0) return (EINVAL); - pci_write_config(sc->parent, rw->d.dyn.cfg_offset, addr, 4); + pci_write_config(pci_dev, rw->d.dyn.cfg_offset, addr, 4); break; default: return (ENODEV); @@ -591,6 +770,23 @@ } /** + * Return true if the bridge device @p bhndb is attached via PCIe, + * false otherwise. + * + * @param dev The bhndb bridge device + */ +static bool +bhndb_is_pcie_attached(device_t dev) +{ + int reg; + + if (pci_find_cap(device_get_parent(dev), PCIY_EXPRESS, ®) == 0) + return (true); + + return (false); +} + +/** * Enable externally managed clocks, if required. * * Some PCI chipsets (BCM4306, possibly others) chips do not support @@ -598,77 +794,89 @@ * attach/resume by directly adjusting GPIO registers exposed in the * PCI config space, and correspondingly, explicitly shutdown at * detach/suspend. - * - * @param sc Bridge driver state. + * + * @note This function may be safely called prior to device attach, (e.g. + * from DEVICE_PROBE). + * + * @param dev The bhndb bridge device */ static int -bhndb_enable_pci_clocks(struct bhndb_pci_softc *sc) +bhndb_enable_pci_clocks(device_t dev) { + device_t pci_dev; uint32_t gpio_in, gpio_out, gpio_en; uint32_t gpio_flags; uint16_t pci_status; + pci_dev = device_get_parent(dev); + /* Only supported and required on PCI devices */ - if (sc->pci_devclass != BHND_DEVCLASS_PCI) + if (!bhndb_is_pcie_attached(dev)) return (0); /* Read state of XTAL pin */ - gpio_in = pci_read_config(sc->parent, BHNDB_PCI_GPIO_IN, 4); + gpio_in = pci_read_config(pci_dev, BHNDB_PCI_GPIO_IN, 4); if (gpio_in & BHNDB_PCI_GPIO_XTAL_ON) return (0); /* already enabled */ /* Fetch current config */ - gpio_out = pci_read_config(sc->parent, BHNDB_PCI_GPIO_OUT, 4); - gpio_en = pci_read_config(sc->parent, BHNDB_PCI_GPIO_OUTEN, 4); + gpio_out = pci_read_config(pci_dev, BHNDB_PCI_GPIO_OUT, 4); + gpio_en = pci_read_config(pci_dev, BHNDB_PCI_GPIO_OUTEN, 4); /* Set PLL_OFF/XTAL_ON pins to HIGH and enable both pins */ gpio_flags = (BHNDB_PCI_GPIO_PLL_OFF|BHNDB_PCI_GPIO_XTAL_ON); gpio_out |= gpio_flags; gpio_en |= gpio_flags; - pci_write_config(sc->parent, BHNDB_PCI_GPIO_OUT, gpio_out, 4); - pci_write_config(sc->parent, BHNDB_PCI_GPIO_OUTEN, gpio_en, 4); + pci_write_config(pci_dev, BHNDB_PCI_GPIO_OUT, gpio_out, 4); + pci_write_config(pci_dev, BHNDB_PCI_GPIO_OUTEN, gpio_en, 4); DELAY(1000); /* Reset PLL_OFF */ gpio_out &= ~BHNDB_PCI_GPIO_PLL_OFF; - pci_write_config(sc->parent, BHNDB_PCI_GPIO_OUT, gpio_out, 4); + pci_write_config(pci_dev, BHNDB_PCI_GPIO_OUT, gpio_out, 4); DELAY(5000); /* Clear any PCI 'sent target-abort' flag. */ - pci_status = pci_read_config(sc->parent, PCIR_STATUS, 2); + pci_status = pci_read_config(pci_dev, PCIR_STATUS, 2); pci_status &= ~PCIM_STATUS_STABORT; - pci_write_config(sc->parent, PCIR_STATUS, pci_status, 2); + pci_write_config(pci_dev, PCIR_STATUS, pci_status, 2); return (0); } /** * Disable externally managed clocks, if required. - * - * @param sc Bridge driver state. + * + * This function may be safely called prior to device attach, (e.g. + * from DEVICE_PROBE). + * + * @param dev The bhndb bridge device */ static int -bhndb_disable_pci_clocks(struct bhndb_pci_softc *sc) +bhndb_disable_pci_clocks(device_t dev) { + device_t pci_dev; uint32_t gpio_out, gpio_en; + pci_dev = device_get_parent(dev); + /* Only supported and required on PCI devices */ - if (sc->pci_devclass != BHND_DEVCLASS_PCI) + if (bhndb_is_pcie_attached(dev)) return (0); /* Fetch current config */ - gpio_out = pci_read_config(sc->parent, BHNDB_PCI_GPIO_OUT, 4); - gpio_en = pci_read_config(sc->parent, BHNDB_PCI_GPIO_OUTEN, 4); + gpio_out = pci_read_config(pci_dev, BHNDB_PCI_GPIO_OUT, 4); + gpio_en = pci_read_config(pci_dev, BHNDB_PCI_GPIO_OUTEN, 4); /* Set PLL_OFF to HIGH, XTAL_ON to LOW. */ gpio_out &= ~BHNDB_PCI_GPIO_XTAL_ON; gpio_out |= BHNDB_PCI_GPIO_PLL_OFF; - pci_write_config(sc->parent, BHNDB_PCI_GPIO_OUT, gpio_out, 4); + pci_write_config(pci_dev, BHNDB_PCI_GPIO_OUT, gpio_out, 4); /* Enable both output pins */ gpio_en |= (BHNDB_PCI_GPIO_PLL_OFF|BHNDB_PCI_GPIO_XTAL_ON); - pci_write_config(sc->parent, BHNDB_PCI_GPIO_OUTEN, gpio_en, 4); + pci_write_config(pci_dev, BHNDB_PCI_GPIO_OUTEN, gpio_en, 4); return (0); } @@ -683,7 +891,7 @@ sc = device_get_softc(dev); /* Only supported on PCI devices */ - if (sc->pci_devclass != BHND_DEVCLASS_PCI) + if (bhndb_is_pcie_attached(sc->dev)) return (ENODEV); /* Only ILP is supported */ @@ -704,14 +912,14 @@ struct bhndb_pci_softc *sc = device_get_softc(dev); /* Only supported on PCI devices */ - if (sc->pci_devclass != BHND_DEVCLASS_PCI) + if (bhndb_is_pcie_attached(sc->dev)) return (ENODEV); /* Only HT is supported */ if (clock != BHND_CLOCK_HT) return (ENXIO); - return (bhndb_disable_pci_clocks(sc)); + return (bhndb_disable_pci_clocks(sc->dev)); } static int @@ -721,14 +929,14 @@ struct bhndb_pci_softc *sc = device_get_softc(dev); /* Only supported on PCI devices */ - if (sc->pci_devclass != BHND_DEVCLASS_PCI) + if (bhndb_is_pcie_attached(sc->dev)) return (ENODEV); /* Only HT is supported */ if (clock != BHND_CLOCK_HT) return (ENXIO); - return (bhndb_enable_pci_clocks(sc)); + return (bhndb_enable_pci_clocks(sc->dev)); } static int @@ -752,6 +960,191 @@ /* Add to child's resource list */ return (bus_set_resource(child, SYS_RES_IRQ, rid, start, count)); +} + +/** + * Initialize a new bhndb PCI bridge EROM I/O instance. This EROM I/O + * implementation supports mapping of the device enumeration table via the + * @p hr host resources. + * + * @param pio The instance to be initialized. + * @param dev The bridge device. + * @param pci_dev The bridge's parent PCI device. + * @param hr The host resources to be used to map the device + * enumeration table. + */ +static int +bhndb_pci_eio_init(struct bhndb_pci_eio *pio, device_t dev, device_t pci_dev, + struct bhndb_host_resources *hr) +{ + memset(&pio->eio, sizeof(pio->eio), 0); + pio->eio.map = bhndb_pci_eio_map; + pio->eio.read = bhndb_pci_eio_read; + pio->eio.fini = NULL; + + pio->dev = dev; + pio->pci_dev = pci_dev; + pio->hr = hr; + pio->win = NULL; + pio->res = NULL; + + return (0); +} + +/** + * Attempt to adjust the dynamic register window backing @p pio to permit + * reading @p size bytes at @p addr. + * + * If @p addr or @p size fall outside the existing mapped range, or if + * @p pio is not backed by a dynamic register window, ENXIO will be returned. + * + * @param pio The bhndb PCI erom I/O state to be modified. + * @param addr The address to be include + */ +static int +bhndb_pci_eio_adjust_mapping(struct bhndb_pci_eio *pio, bhnd_addr_t addr, + bhnd_size_t size) +{ + bhnd_addr_t target; + bhnd_size_t offset; + int error; + + + KASSERT(pio->win != NULL, ("missing register window")); + KASSERT(pio->res != NULL, ("missing regwin resource")); + KASSERT(pio->win->win_type == BHNDB_REGWIN_T_DYN, + ("unexpected window type %d", pio->win->win_type)); + + /* The requested subrange must fall within the total mapped range */ + if (addr < pio->addr || (addr - pio->addr) > pio->size || + size > pio->size || (addr - pio->addr) - pio->size < size) + { + return (ENXIO); + } + + /* Do we already have a useable mapping? */ + if (addr >= pio->res_target && + addr <= pio->res_target + pio->win->win_size && + (pio->res_target + pio->win->win_size) - addr >= size) + { + return (0); + } + + /* Page-align the target address */ + offset = addr % pio->win->win_size; + target = addr - offset; + + /* Configure the register window */ + error = bhndb_pci_compat_setregwin(pio->dev, pio->pci_dev, pio->win, + target); + if (error) { + device_printf(pio->dev, "failed to configure dynamic register " + "window: %d\n", error); + return (error); + } + + pio->res_target = target; + return (0); +} + +/* bhnd_erom_io_map() implementation */ +static int +bhndb_pci_eio_map(struct bhnd_erom_io *eio, bhnd_addr_t addr, + bhnd_size_t size) +{ + struct bhndb_pci_eio *pio; + const struct bhndb_regwin *regwin; + struct resource *r; + bhnd_addr_t target; + bhnd_size_t offset; + int error; + + pio = (struct bhndb_pci_eio *)eio; + + /* Locate a useable dynamic register window */ + regwin = bhndb_regwin_find_type(pio->hr->cfg->register_windows, + BHNDB_REGWIN_T_DYN, MIN(size, BHND_DEFAULT_CORE_SIZE)); + if (regwin == NULL) { + device_printf(pio->dev, "unable to map %#jx+%#jx; no " + "usable dynamic register window found\n", addr, size); + return (ENXIO); + } + + /* Locate the host resource mapping our register window */ + if ((r = bhndb_host_resource_for_regwin(pio->hr, regwin)) == NULL) { + device_printf(pio->dev, "unable to map %#jx+%#jx; no " + "usable register resource found\n", addr, size); + return (ENXIO); + } + + /* Page-align the target address */ + offset = addr % regwin->win_size; + target = addr - offset; + + /* Configure the register window */ + error = bhndb_pci_compat_setregwin(pio->dev, pio->pci_dev, regwin, + target); + if (error) { + device_printf(pio->dev, "failed to configure dynamic register " + "window: %d\n", error); + return (error); + } + + /* Update our mapping state */ + pio->win = regwin; + pio->res = r; + pio->addr = addr; + pio->size = size; + pio->res_target = target; + + return (0); +} + +/* bhnd_erom_io_read() implementation */ +static uint32_t +bhndb_pci_eio_read(struct bhnd_erom_io *eio, bhnd_size_t offset, u_int width) +{ + struct bhndb_pci_eio *pio; + bhnd_addr_t addr; + bus_size_t res_offset; + int error; + + pio = (struct bhndb_pci_eio *)eio; + + /* Calculate absolute address */ + if (BHND_SIZE_MAX - offset < pio->addr) { + device_printf(pio->dev, "invalid offset %#jx+%#jx\n", pio->addr, + offset); + return (UINT32_MAX); + } + + addr = pio->addr + offset; + + /* Adjust the mapping for our read */ + if ((error = bhndb_pci_eio_adjust_mapping(pio, addr, width))) { + device_printf(pio->dev, "failed to adjust register mapping: " + "%d\n", error); + return (UINT32_MAX); + } + + KASSERT(pio->res_target <= addr, ("invalid mapping (%#jx vs. %#jx)", + pio->res_target, addr)); + + /* Determine the actual read offset within our register window + * resource */ + res_offset = (addr - pio->res_target) + pio->win->win_offset; + + /* Perform our read */ + switch (width) { + case 1: + return (bus_read_1(pio->res, res_offset)); + case 2: + return (bus_read_2(pio->res, res_offset)); + case 4: + return (bus_read_4(pio->res, res_offset)); + default: + panic("unsupported width: %u", width); + } } static device_method_t bhndb_pci_methods[] = { Index: head/sys/dev/bhnd/bhndb/bhndb_pcivar.h =================================================================== --- head/sys/dev/bhnd/bhndb/bhndb_pcivar.h +++ head/sys/dev/bhnd/bhndb/bhndb_pcivar.h @@ -45,7 +45,7 @@ /* * An interconnect-specific function implementing BHNDB_SET_WINDOW_ADDR */ -typedef int (*bhndb_pci_set_regwin_t)(struct bhndb_pci_softc *sc, +typedef int (*bhndb_pci_set_regwin_t)(device_t dev, device_t pci_dev, const struct bhndb_regwin *rw, bhnd_addr_t addr); /* bhndb_pci interrupt state */ Index: head/sys/dev/bhnd/bhndb/bhndb_private.h =================================================================== --- head/sys/dev/bhnd/bhndb/bhndb_private.h +++ head/sys/dev/bhnd/bhndb/bhndb_private.h @@ -1,7 +1,10 @@ /*- - * Copyright (c) 2015 Landon Fuller + * Copyright (c) 2015-2016 Landon Fuller * All rights reserved. * + * Portions of this software were developed by Landon Fuller + * under sponsorship from the FreeBSD Foundation. + * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: @@ -51,21 +54,10 @@ struct bhndb_region; struct bhndb_resources; -struct resource *bhndb_find_resource_range( - struct bhndb_resources *br, - rman_res_t start, rman_res_t count); - -struct resource *bhndb_find_regwin_resource( - struct bhndb_resources *br, - const struct bhndb_regwin *win); - 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); @@ -107,32 +99,6 @@ struct bhndb_dw_alloc *dwa, bus_addr_t addr, bus_size_t size); -size_t bhndb_regwin_count( - const struct bhndb_regwin *table, - bhndb_regwin_type_t type); - -const struct bhndb_regwin *bhndb_regwin_find_type( - const struct bhndb_regwin *table, - bhndb_regwin_type_t type, - bus_size_t min_size); - -const struct bhndb_regwin *bhndb_regwin_find_core( - const struct bhndb_regwin *table, - bhnd_devclass_t class, int unit, - bhnd_port_type port_type, u_int port, - u_int region); - - -const struct bhndb_regwin *bhndb_regwin_find_best( - const struct bhndb_regwin *table, - bhnd_devclass_t class, int unit, - bhnd_port_type port_type, u_int port, - u_int region, bus_size_t min_size); - -bool bhndb_regwin_match_core( - const struct bhndb_regwin *regw, - struct bhnd_core_info *core); - const struct bhndb_hw_priority *bhndb_hw_priority_find_core( const struct bhndb_hw_priority *table, struct bhnd_core_info *core); @@ -177,10 +143,7 @@ device_t dev; /**< bridge device */ const struct bhndb_hwcfg *cfg; /**< hardware configuration */ - device_t parent_dev; /**< parent device */ - 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 bhndb_host_resources *res; /**< host resources, or NULL if not allocated */ struct rman ht_mem_rman; /**< host memory manager */ struct rman br_mem_rman; /**< bridged memory manager */ Index: head/sys/dev/bhnd/bhndb/bhndb_subr.c =================================================================== --- head/sys/dev/bhnd/bhndb/bhndb_subr.c +++ head/sys/dev/bhnd/bhndb/bhndb_subr.c @@ -1,7 +1,11 @@ /*- - * Copyright (c) 2015 Landon Fuller + * Copyright (c) 2015-2016 Landon Fuller + * Copyright (c) 2017 The FreeBSD Foundation * All rights reserved. * + * Portions of this software were developed by Landon Fuller + * under sponsorship from the FreeBSD Foundation. + * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: @@ -183,9 +187,10 @@ } /** - * Find a SYS_RES_MEMORY resource containing the given address range. + * Find a host resource of @p type that maps the given range. * - * @param br The bhndb resource state to search. + * @param hr The resource state to search. + * @param type The resource type to search for (see SYS_RES_*). * @param start The start address of the range to search for. * @param count The size of the range to search for. * @@ -193,15 +198,13 @@ * @retval NULL if no resource containing the requested range can be found. */ struct resource * -bhndb_find_resource_range(struct bhndb_resources *br, rman_res_t start, - rman_res_t count) +bhndb_host_resource_for_range(struct bhndb_host_resources *hr, int type, + rman_res_t start, rman_res_t count) { - KASSERT(br->res_avail, ("no host resources allocated")); + for (u_int i = 0; hr->resource_specs[i].type != -1; i++) { + struct resource *r = hr->resources[i]; - for (u_int i = 0; br->res_spec[i].type != -1; i++) { - struct resource *r = br->res[i]; - - if (br->res_spec->type != SYS_RES_MEMORY) + if (hr->resource_specs[i].type != type) continue; /* Verify range */ @@ -218,23 +221,21 @@ } /** - * Find the resource containing @p win. + * Find a host resource of that matches the given register window definition. * - * @param br The bhndb resource state to search. - * @param win A register window. + * @param hr The resource state to search. + * @param win A register window definition. * - * @retval resource the resource containing @p win. - * @retval NULL if no resource containing @p win can be found. + * @retval resource the host resource corresponding to @p win. + * @retval NULL if no resource corresponding to @p win can be found. */ struct resource * -bhndb_find_regwin_resource(struct bhndb_resources *br, +bhndb_host_resource_for_regwin(struct bhndb_host_resources *hr, const struct bhndb_regwin *win) { const struct resource_spec *rspecs; - KASSERT(br->res_avail, ("no host resources allocated")); - - rspecs = br->cfg->resource_specs; + rspecs = hr->resource_specs; for (u_int i = 0; rspecs[i].type != -1; i++) { if (win->res.type != rspecs[i].type) continue; @@ -243,12 +244,11 @@ continue; /* Found declared resource */ - return (br->res[i]); + return (hr->resources[i]); } - device_printf(br->dev, - "missing regwin resource spec (type=%d, rid=%d)\n", - win->res.type, win->res.rid); + device_printf(hr->owner, "missing regwin resource spec " + "(type=%d, rid=%d)\n", win->res.type, win->res.rid); return (NULL); } @@ -281,8 +281,8 @@ /* Basic initialization */ r->dev = dev; - r->parent_dev = parent_dev; r->cfg = cfg; + r->res = NULL; r->min_prio = BHNDB_PRIORITY_NONE; STAILQ_INIT(&r->bus_regions); @@ -380,92 +380,28 @@ 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); + error = bhndb_alloc_host_resources(parent_dev, r->cfg, &r->res); if (error) { - device_printf(br->dev, - "could not allocate bridge resources on %s: %d\n", - device_get_nameunit(br->parent_dev), error); + device_printf(r->dev, + "could not allocate host resources on %s: %d\n", + device_get_nameunit(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++) { + for (size_t i = 0; i < r->dwa_count; i++) { struct bhndb_dw_alloc *dwa; const struct bhndb_regwin *win; - dwa = &br->dw_alloc[i]; + dwa = &r->dw_alloc[i]; win = dwa->win; /* Find and validate corresponding resource. */ - dwa->parent_res = bhndb_find_regwin_resource(br, win); + dwa->parent_res = bhndb_host_resource_for_regwin(r->res, win); if (dwa->parent_res == NULL) { - device_printf(br->dev, "no host resource found for %u " + device_printf(r->dev, "no host resource found for %u " "register window with offset %#jx and " "size %#jx\n", win->win_type, @@ -479,7 +415,7 @@ if (rman_get_size(dwa->parent_res) < win->win_offset + win->win_size) { - device_printf(br->dev, "resource %d too small for " + device_printf(r->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, @@ -491,38 +427,46 @@ } /* Add allocated memory resources to our host memory resource manager */ - for (u_int i = 0; br->res_spec[i].type != -1; i++) { + for (u_int i = 0; r->res->resource_specs[i].type != -1; i++) { struct resource *res; /* skip non-memory resources */ - if (br->res_spec[i].type != SYS_RES_MEMORY) + if (r->res->resource_specs[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, + res = r->res->resources[i]; + error = rman_manage_region(&r->ht_mem_rman, rman_get_start(res), rman_get_end(res)); if (error) { - device_printf(br->dev, + device_printf(r->dev, "could not register host memory region with " "ht_mem_rman: %d\n", error); goto failed; } } - return (0); + return (r); failed: - if (br->res_avail) - bus_release_resources(br->parent_dev, br->res_spec, br->res); - - if (br->res != NULL) - free(br->res, M_BHND); + if (free_ht_mem) + rman_fini(&r->ht_mem_rman); - if (br->res_spec != NULL) - free(br->res_spec, M_BHND); + if (free_br_mem) + rman_fini(&r->br_mem_rman); - return (error); + if (r->dw_alloc != NULL) + free(r->dw_alloc, M_BHND); + + if (r->dwa_freelist != NULL) + free(r->dwa_freelist, M_BHND); + + if (r->res != NULL) + bhndb_release_host_resources(r->res); + + free(r, M_BHND); + + return (NULL); } /** @@ -551,9 +495,9 @@ } } - /* Release resources allocated through our parent. */ - if (br->res_avail) - bus_release_resources(br->parent_dev, br->res_spec, br->res); + /* Release host resources allocated through our parent. */ + if (br->res != NULL) + bhndb_release_host_resources(br->res); /* Clean up resource reservations */ for (size_t i = 0; i < br->dwa_count; i++) { @@ -575,15 +519,151 @@ rman_fini(&br->ht_mem_rman); rman_fini(&br->br_mem_rman); - /* Free backing resource state structures */ - 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); +} + +/** + * Allocate host bus resources defined by @p hwcfg. + * + * On success, the caller assumes ownership of the allocated host resources, + * which must be freed via bhndb_release_host_resources(). + * + * @param dev The device to be used when allocating resources + * (e.g. via bus_alloc_resources()). + * @param hwcfg The hardware configuration defining the host + * resources to be allocated + * @param[out] resources On success, the allocated host resources. + */ +int +bhndb_alloc_host_resources(device_t dev, const struct bhndb_hwcfg *hwcfg, + struct bhndb_host_resources **resources) +{ + struct bhndb_host_resources *hr; + size_t nres; + int error; + + hr = malloc(sizeof(*hr), M_BHND, M_WAITOK); + hr->owner = dev; + hr->cfg = hwcfg; + hr->resource_specs = NULL; + hr->resources = NULL; + + /* Determine our bridge resource count from the hardware config. */ + nres = 0; + for (size_t i = 0; hwcfg->resource_specs[i].type != -1; i++) + nres++; + + /* Allocate space for a non-const copy of our resource_spec + * table; this will be updated with the RIDs assigned by + * bus_alloc_resources. */ + hr->resource_specs = malloc(sizeof(hr->resource_specs[0]) * (nres + 1), + M_BHND, M_WAITOK); + + /* Initialize and terminate the table */ + for (size_t i = 0; i < nres; i++) + hr->resource_specs[i] = hwcfg->resource_specs[i]; + + hr->resource_specs[nres].type = -1; + + /* Allocate space for our resource references */ + hr->resources = malloc(sizeof(hr->resources[0]) * nres, M_BHND, + M_WAITOK); + + /* Allocate host resources */ + error = bus_alloc_resources(hr->owner, hr->resource_specs, + hr->resources); + if (error) { + device_printf(dev, "could not allocate bridge resources via " + "%s: %d\n", device_get_nameunit(dev), error); + goto failed; + } + + *resources = hr; + return (0); + +failed: + if (hr->resource_specs != NULL) + free(hr->resource_specs, M_BHND); + + if (hr->resources != NULL) + free(hr->resources, M_BHND); + + free(hr, M_BHND); + + return (error); +} + +/** + * Deallocate a set of bridge host resources. + * + * @param hr The resources to be freed. + */ +void +bhndb_release_host_resources(struct bhndb_host_resources *hr) +{ + bus_release_resources(hr->owner, hr->resource_specs, hr->resources); + + free(hr->resources, M_BHND); + free(hr->resource_specs, M_BHND); + free(hr, M_BHND); +} + + +/** + * Search @p cores 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 cores The core table to search. + * @param ncores The number of cores in @p cores. + * @param bridge_devclass The expected device class of the bridge core. + * @param[out] core If found, the matching host bridge core info. + * + * @retval 0 success + * @retval ENOENT not found + */ +int +bhndb_find_hostb_core(struct bhnd_core_info *cores, u_int ncores, + bhnd_devclass_t bridge_devclass, struct bhnd_core_info *core) +{ + struct bhnd_core_match md; + struct bhnd_core_info *match; + u_int match_core_idx; + + /* Set up a match descriptor for the required device class. */ + md = (struct bhnd_core_match) { + BHND_MATCH_CORE_CLASS(bridge_devclass), + BHND_MATCH_CORE_UNIT(0) + }; + + /* Find the matching core with the lowest core index */ + match = NULL; + match_core_idx = UINT_MAX; + + for (u_int i = 0; i < ncores; i++) { + if (!bhnd_core_matches(&cores[i], &md)) + continue; + + /* Lower core indices take precedence */ + if (match != NULL && match_core_idx < match->core_idx) + continue; + + match = &cores[i]; + match_core_idx = match->core_idx; + } + + if (match == NULL) + return (ENOENT); + + *core = *match; + return (0); } /** Index: head/sys/dev/bhnd/bhndb/bhndbvar.h =================================================================== --- head/sys/dev/bhnd/bhndb/bhndbvar.h +++ head/sys/dev/bhnd/bhndb/bhndbvar.h @@ -56,19 +56,70 @@ DECLARE_CLASS(bhndb_driver); struct bhndb_resources; +struct bhndb_host_resources; -int bhndb_attach(device_t dev, bhnd_devclass_t bridge_devclass); +int bhndb_attach(device_t dev, + struct bhnd_chipid *cid, + struct bhnd_core_info *cores, u_int ncores, + struct bhnd_core_info *bridge_core, + bhnd_erom_class_t *erom_class); -int bhndb_generic_probe(device_t dev); -int bhndb_generic_detach(device_t dev); -int bhndb_generic_suspend(device_t dev); -int bhndb_generic_resume(device_t dev); -int bhndb_generic_init_full_config(device_t dev, device_t child, - const struct bhndb_hw_priority *hw_prio_table); +int bhndb_generic_probe(device_t dev); +int bhndb_generic_detach(device_t dev); +int bhndb_generic_suspend(device_t dev); +int bhndb_generic_resume(device_t dev); +int bhndb_generic_init_full_config(device_t dev, + device_t child, + const struct bhndb_hw_priority *hw_prio_table); -int bhnd_generic_br_suspend_child(device_t dev, device_t child); -int bhnd_generic_br_resume_child(device_t dev, device_t child); +int bhnd_generic_br_suspend_child(device_t dev, + device_t child); +int bhnd_generic_br_resume_child(device_t dev, + device_t child); +int bhndb_find_hostb_core( + struct bhnd_core_info *cores, u_int ncores, + bhnd_devclass_t bridge_devclass, + struct bhnd_core_info *core); + +int bhndb_alloc_host_resources(device_t dev, + const struct bhndb_hwcfg *hwcfg, + struct bhndb_host_resources **resources); +void bhndb_release_host_resources( + struct bhndb_host_resources *resources); +struct resource *bhndb_host_resource_for_range( + struct bhndb_host_resources *resources, + int type, rman_res_t start, + rman_res_t count); +struct resource *bhndb_host_resource_for_regwin( + struct bhndb_host_resources *resources, + const struct bhndb_regwin *win); + +size_t bhndb_regwin_count( + const struct bhndb_regwin *table, + bhndb_regwin_type_t type); + +const struct bhndb_regwin *bhndb_regwin_find_type( + const struct bhndb_regwin *table, + bhndb_regwin_type_t type, + bus_size_t min_size); + +const struct bhndb_regwin *bhndb_regwin_find_core( + const struct bhndb_regwin *table, + bhnd_devclass_t class, int unit, + bhnd_port_type port_type, u_int port, + u_int region); + +const struct bhndb_regwin *bhndb_regwin_find_best( + const struct bhndb_regwin *table, + bhnd_devclass_t class, int unit, + bhnd_port_type port_type, u_int port, + u_int region, bus_size_t min_size); + +bool bhndb_regwin_match_core( + const struct bhndb_regwin *regw, + struct bhnd_core_info *core); + /** * bhndb child address space. Children either operate in the bridged * SoC address space, or within the address space mapped to the host @@ -86,16 +137,23 @@ }; /** + * Host resources allocated for a bridge hardware configuration. + */ +struct bhndb_host_resources { + device_t owner; /**< device owning the allocated resources */ + const struct bhndb_hwcfg *cfg; /**< bridge hardware configuration */ + struct resource_spec *resource_specs; /**< resource specification table */ + struct resource **resources; /**< allocated resource table */ +}; + +/** * bhndb driver instance state. Must be first member of all subclass * softc structures. */ 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 */ + struct bhnd_core_info bridge_core; /**< bridge core info */ device_t parent_dev; /**< parent device */ device_t bus_dev; /**< child bhnd(4) bus */ Index: head/sys/dev/bhnd/bhndreg.h =================================================================== --- head/sys/dev/bhnd/bhndreg.h +++ head/sys/dev/bhnd/bhndreg.h @@ -34,9 +34,9 @@ /** * The default address at which the ChipCommon core is mapped on all siba(4) - * devices, and most bcma(4) devices. + * devices, and most (all?) bcma(4) devices. */ -#define BHND_DEFAULT_CHIPC_ADDR 0x18000000 +#define BHND_DEFAULT_CHIPC_ADDR 0x18000000 /** * The standard size of a primary BHND_PORT_DEVICE or BHND_PORT_AGENT @@ -44,5 +44,9 @@ */ #define BHND_DEFAULT_CORE_SIZE 0x1000 +/** + * The standard size of the siba(4) and bcma(4) enumeration space. + */ +#define BHND_DEFAULT_ENUM_SIZE 0x00100000 #endif /* _BHND_BHNDREG_H_ */ \ No newline at end of file Index: head/sys/dev/bhnd/siba/siba.c =================================================================== --- head/sys/dev/bhnd/siba/siba.c +++ head/sys/dev/bhnd/siba/siba.c @@ -820,30 +820,34 @@ siba_add_children(device_t dev) { const struct bhnd_chipid *chipid; - struct bhnd_core_info *cores; - struct siba_devinfo *dinfo; + struct siba_core_id *cores; struct bhnd_resource *r; + device_t *children; int rid; int error; - dinfo = NULL; cores = NULL; r = NULL; 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); - if (cores == NULL) - return (ENOMEM); + /* Allocate our temporary core and device table */ + cores = malloc(sizeof(*cores) * chipid->ncores, M_BHND, M_WAITOK); + children = malloc(sizeof(*children) * chipid->ncores, M_BHND, + M_WAITOK | M_ZERO); - /* Add all cores. */ + /* + * Add child devices for all discovered cores. + * + * On bridged devices, we'll exhaust our available register windows if + * we map config blocks on unpopulated/disabled cores. To avoid this, we + * defer mapping of the per-core siba(4) config blocks until all cores + * have been enumerated and otherwise configured. + */ for (u_int i = 0; i < chipid->ncores; i++) { - struct siba_core_id cid; - device_t child; + struct siba_devinfo *dinfo; uint32_t idhigh, idlow; rman_res_t r_count, r_end, r_start; - int nintr; /* Map the core's register block */ rid = 0; @@ -854,51 +858,73 @@ r_end, r_count, RF_ACTIVE); if (r == NULL) { error = ENXIO; - goto cleanup; + goto failed; } - /* Add the child device */ - child = BUS_ADD_CHILD(dev, 0, NULL, -1); - if (child == NULL) { - error = ENXIO; - goto cleanup; - } - /* Read the core info */ idhigh = bhnd_bus_read_4(r, SB0_REG_ABS(SIBA_CFG0_IDHIGH)); idlow = bhnd_bus_read_4(r, SB0_REG_ABS(SIBA_CFG0_IDLOW)); - cid = siba_parse_core_id(idhigh, idlow, i, 0); - cores[i] = cid.core_info; + cores[i] = siba_parse_core_id(idhigh, idlow, i, 0); - /* Determine unit number */ + /* Determine and set unit number */ for (u_int j = 0; j < i; j++) { - if (cores[j].vendor == cores[i].vendor && - cores[j].device == cores[i].device) - cores[i].unit++; + struct bhnd_core_info *cur = &cores[i].core_info; + struct bhnd_core_info *prev = &cores[j].core_info; + + if (prev->vendor == cur->vendor && + prev->device == cur->device) + cur->unit++; } + /* Add the child device */ + children[i] = BUS_ADD_CHILD(dev, 0, NULL, -1); + if (children[i] == NULL) { + error = ENXIO; + goto failed; + } + /* Initialize per-device bus info */ - if ((dinfo = device_get_ivars(child)) == NULL) { + if ((dinfo = device_get_ivars(children[i])) == NULL) { error = ENXIO; - goto cleanup; + goto failed; } - if ((error = siba_init_dinfo(dev, dinfo, &cid))) - goto cleanup; + if ((error = siba_init_dinfo(dev, dinfo, &cores[i]))) + goto failed; /* Register the core's address space(s). */ if ((error = siba_register_addrspaces(dev, dinfo, r))) - goto cleanup; + goto failed; - /* Release our resource covering the register blocks - * we're about to map */ + /* Unmap the core's register block */ bhnd_release_resource(dev, SYS_RES_MEMORY, rid, r); r = NULL; + /* If pins are floating or the hardware is otherwise + * unpopulated, the device shouldn't be used. */ + if (bhnd_is_hw_disabled(children[i])) + device_disable(children[i]); + } + + /* Map all valid core's config register blocks and perform interrupt + * assignment */ + for (u_int i = 0; i < chipid->ncores; i++) { + struct siba_devinfo *dinfo; + device_t child; + int nintr; + + child = children[i]; + + /* Skip if core is disabled */ + if (bhnd_is_hw_disabled(child)) + continue; + + dinfo = device_get_ivars(child); + /* Map the core's config blocks */ if ((error = siba_map_cfg_resources(dev, dinfo))) - goto cleanup; + goto failed; /* Assign interrupts */ nintr = bhnd_get_intr_count(child); @@ -910,18 +936,25 @@ } } - /* 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); - /* Issue bus callback for fully initialized child. */ BHND_BUS_CHILD_ADDED(dev, child); } - -cleanup: - if (cores != NULL) - free(cores, M_BHND); + + free(cores, M_BHND); + free(children, M_BHND); + + return (0); + +failed: + for (u_int i = 0; i < chipid->ncores; i++) { + if (children[i] == NULL) + continue; + + device_delete_child(dev, children[i]); + } + + free(cores, M_BHND); + free(children, M_BHND); if (r != NULL) bhnd_release_resource(dev, SYS_RES_MEMORY, rid, r); Index: head/sys/dev/bhnd/siba/siba_erom.c =================================================================== --- head/sys/dev/bhnd/siba/siba_erom.c +++ head/sys/dev/bhnd/siba/siba_erom.c @@ -1,7 +1,11 @@ /*- * Copyright (c) 2015-2016 Landon Fuller + * Copyright (c) 2017 The FreeBSD Foundation * All rights reserved. * + * Portions of this software were developed by Landon Fuller + * under sponsorship from the FreeBSD Foundation. + * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: @@ -50,13 +54,8 @@ 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 bhnd_erom_io *eio, u_int ncores); -static int siba_eio_init_static(struct siba_erom_io *io, - bus_space_tag_t bst, bus_space_handle_t bsh, - bus_size_t offset, u_int ncores); - static uint32_t siba_eio_read_4(struct siba_erom_io *io, u_int core_idx, bus_size_t offset); @@ -71,18 +70,9 @@ * SIBA EROM generic I/O context */ struct siba_erom_io { + struct bhnd_erom_io *eio; /**< erom I/O callbacks */ + bhnd_addr_t base_addr; /**< address of first core */ 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 unavailable. */ - struct bhnd_resource *res; /**< memory resource, or NULL */ - int rid; /**< memory resource ID */ - - /* bus tag state */ - bus_space_tag_t bst; /**< bus space tag */ - bus_space_handle_t bsh; /**< bus space handle */ }; /** @@ -93,22 +83,23 @@ 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__); \ - } \ +#define EROM_LOG(io, fmt, ...) do { \ + printf("%s: " fmt, __FUNCTION__, ##__VA_ARGS__); \ } while(0) +/* SIBA implementation of BHND_EROM_PROBE() */ static int -siba_erom_probe_common(struct siba_erom_io *io, const struct bhnd_chipid *hint, - struct bhnd_chipid *cid) +siba_erom_probe(bhnd_erom_class_t *cls, struct bhnd_erom_io *eio, + const struct bhnd_chipid *hint, struct bhnd_chipid *cid) { + struct siba_erom_io io; uint32_t idreg; int error; + /* Initialize I/O context, assuming at least the first core is mapped */ + if ((error = siba_eio_init(&io, eio, 1))) + return (error); + /* Try using the provided hint. */ if (hint != NULL) { struct siba_core_id sid; @@ -127,7 +118,7 @@ * BCM4710, it's a SDRAM core (0x803). */ - sid = siba_eio_read_core_id(io, 0, 0); + sid = siba_eio_read_core_id(&io, 0, 0); if (sid.core_info.vendor != BHND_MFGID_BCM) return (ENXIO); @@ -138,12 +129,12 @@ *cid = *hint; } else { /* Validate bus type */ - idreg = siba_eio_read_4(io, 0, CHIPC_ID); + 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))) + if ((error = siba_eio_read_chipid(&io, SIBA_ENUM_ADDR, cid))) return (error); /* Verify the chip type */ @@ -164,123 +155,47 @@ return (0); } -/* SIBA implementation of BHND_EROM_PROBE() */ -static int -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_io io; - int error, rid; - - rid = rman_get_rid(res->res); - - /* 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_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, const struct bhnd_chipid *hint, - struct bhnd_chipid *cid) -{ - struct siba_erom_io io; - int error; - - /* Initialize I/O context, assuming at least 1 core exists. */ - if ((error = siba_eio_init_static(&io, bst, bsh, 0, 1))) - return (error); - - return (siba_erom_probe_common(&io, hint, cid)); -} - /* SIBA implementation of BHND_EROM_INIT() */ static int siba_erom_init(bhnd_erom_t *erom, const struct bhnd_chipid *cid, - device_t parent, int rid) + struct bhnd_erom_io *eio) { struct siba_erom *sc; - struct bhnd_resource *res; int error; - + sc = (struct siba_erom *)erom; - /* Allocate backing resource */ - res = bhnd_alloc_resource(parent, SYS_RES_MEMORY, &rid, - cid->enum_addr, cid->enum_addr + SIBA_ENUM_SIZE -1, SIBA_ENUM_SIZE, - RF_ACTIVE|RF_SHAREABLE); - if (res == NULL) - return (ENOMEM); + /* Attempt to map the full core enumeration space */ + error = bhnd_erom_io_map(eio, cid->enum_addr, + cid->ncores * SIBA_CORE_SIZE); + if (error) { + printf("%s: failed to map %u cores: %d\n", __FUNCTION__, + cid->ncores, error); + return (error); + } /* 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); + return (siba_eio_init(&sc->io, eio, cid->ncores)); } -/* 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->io.res != NULL) { - bhnd_release_resource(sc->io.dev, SYS_RES_MEMORY, sc->io.rid, - sc->io.res); - - sc->io.res = NULL; - sc->io.rid = -1; - } + bhnd_erom_io_fini(sc->io.eio); } /* 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) +siba_eio_init(struct siba_erom_io *io, struct bhnd_erom_io *eio, u_int ncores) { - io->dev = parent; - io->res = res; - io->rid = rid; - io->offset = offset; + io->eio = eio; 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. @@ -292,8 +207,6 @@ 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, @@ -303,11 +216,8 @@ 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)); + return (bhnd_erom_io_read(io->eio, SIBA_CORE_OFFSET(core_idx) + offset, + 4)); } /** @@ -393,7 +303,7 @@ /* Re-scan preceding cores to determine the unit number. */ for (u_int j = 0; j < i; j++) { - sid = siba_eio_read_core_id(&sc->io, i, 0); + sid = siba_eio_read_core_id(&sc->io, j, 0); /* Bump the unit number? */ if (sid.core_info.vendor == ci.vendor && @@ -580,9 +490,7 @@ static kobj_method_t siba_erom_methods[] = { KOBJMETHOD(bhnd_erom_probe, siba_erom_probe), - KOBJMETHOD(bhnd_erom_probe_static, siba_erom_probe_static), KOBJMETHOD(bhnd_erom_init, siba_erom_init), - KOBJMETHOD(bhnd_erom_init_static, siba_erom_init_static), KOBJMETHOD(bhnd_erom_fini, siba_erom_fini), KOBJMETHOD(bhnd_erom_get_core_table, siba_erom_get_core_table), KOBJMETHOD(bhnd_erom_free_core_table, siba_erom_free_core_table), Index: head/sys/mips/broadcom/bcm_machdep.h =================================================================== --- head/sys/mips/broadcom/bcm_machdep.h +++ head/sys/mips/broadcom/bcm_machdep.h @@ -40,7 +40,7 @@ #include #include -#include +#include #include @@ -66,6 +66,7 @@ bhnd_erom_class_t *erom_impl; /**< erom parser class */ struct kobj_ops erom_ops; /**< compiled kobj opcache */ + struct bhnd_erom_iobus erom_io; /**< erom I/O callbacks */ union { bhnd_erom_static_t data; bhnd_erom_t obj; Index: head/sys/mips/broadcom/bcm_machdep.c =================================================================== --- head/sys/mips/broadcom/bcm_machdep.c +++ head/sys/mips/broadcom/bcm_machdep.c @@ -77,6 +77,7 @@ #include #include +#include #include @@ -108,7 +109,7 @@ static int bcm_erom_probe_and_attach(bhnd_erom_class_t **erom_cls, kobj_ops_t erom_ops, bhnd_erom_t *erom, size_t esize, - struct bhnd_chipid *cid); + struct bhnd_erom_io *eio, struct bhnd_chipid *cid); extern int *edata; extern int *end; @@ -149,6 +150,17 @@ return (BHND_DEFAULT_CHIPC_ADDR); } +static bus_size_t +bcm_get_bus_size(void) +{ + long msize; + + if (resource_long_value("bhnd", 0, "msize", &msize) == 0) + return ((u_long)msize); + + return (BHND_DEFAULT_ENUM_SIZE); +} + /** * Search the device enumeration table for a core matching @p descs, * @@ -242,25 +254,31 @@ * @param esize The total available number of bytes allocated * for @p erom. If this is less than is required * by @p erom_cls ENOMEM will be returned. + * @param eio EROM I/O callbacks to be used. * @param[out] cid On success, the probed chip identification. */ static int bcm_erom_probe_and_attach(bhnd_erom_class_t **erom_cls, kobj_ops_t erom_ops, - bhnd_erom_t *erom, size_t esize, struct bhnd_chipid *cid) + bhnd_erom_t *erom, size_t esize, struct bhnd_erom_io *eio, + struct bhnd_chipid *cid) { bhnd_erom_class_t **clsp; - bus_space_tag_t bst; - bus_space_handle_t bsh; bus_addr_t bus_addr; int error, prio, result; - bus_addr = bcm_get_bus_addr(); *erom_cls = NULL; prio = 0; - bst = mips_bus_space_generic; - bsh = BCM_SOC_BSH(bus_addr, 0); + /* Map our first bus core for the erom probe */ + bus_addr = bcm_get_bus_addr(); + if ((error = bhnd_erom_io_map(eio, bus_addr, BHND_DEFAULT_CORE_SIZE))) { + BCM_ERR("failed to map first core at %#jx+%#jx: %d\n", + (uintmax_t)bus_addr, (uintmax_t)BHND_DEFAULT_CORE_SIZE, + error); + return (error); + } + SET_FOREACH(clsp, bhnd_erom_class_set) { struct bhnd_chipid pcid; bhnd_erom_class_t *cls; @@ -272,8 +290,7 @@ kobj_class_compile_static(cls, &kops); /* Probe the bus address */ - result = bhnd_erom_probe_static(cls, bst, bsh, bus_addr, NULL, - &pcid); + result = bhnd_erom_probe(cls, eio, NULL, &pcid); /* Drop pointer to stack allocated ops table */ cls->ops = NULL; @@ -299,6 +316,7 @@ if (*erom_cls == NULL) { BCM_ERR("no erom parser found for root bus at %#jx\n", (uintmax_t)bus_addr); + return (ENOENT); } @@ -306,9 +324,7 @@ kobj_class_compile_static(*erom_cls, 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, cid, - mips_bus_space_generic, bsh); + error = bhnd_erom_init_static(*erom_cls, erom, esize, cid, eio); return (error); } @@ -319,9 +335,15 @@ static int bcm_init_platform_data(struct bcm_platform *bp) { - bool aob, pmu; - int error; + bus_addr_t bus_addr, bus_size; + bus_space_tag_t erom_bst; + bus_space_handle_t erom_bsh; + bool aob, pmu; + int error; + bus_addr = bcm_get_bus_addr(); + bus_size = bcm_get_bus_size(); + #ifdef CFE /* Fetch CFE console handle (if any). Must be initialized before * any calls to printf/early_putc. */ @@ -339,10 +361,21 @@ /* Probe and attach device table provider, populating our * chip identification */ + erom_bst = mips_bus_space_generic; + erom_bsh = BCM_SOC_BSH(bus_addr, 0); + + error = bhnd_erom_iobus_init(&bp->erom_io, bus_addr, bus_size, erom_bst, + erom_bsh); + if (error) { + BCM_ERR("failed to initialize erom I/O callbacks: %d\n", error); + return (error); + } + error = bcm_erom_probe_and_attach(&bp->erom_impl, &bp->erom_ops, - &bp->erom.obj, sizeof(bp->erom), &bp->cid); + &bp->erom.obj, sizeof(bp->erom), &bp->erom_io.eio, &bp->cid); if (error) { BCM_ERR("error attaching erom parser: %d\n", error); + bhnd_erom_io_fini(&bp->erom_io.eio); return (error); } Index: head/sys/modules/bhnd/bhndb_pci/Makefile =================================================================== --- head/sys/modules/bhnd/bhndb_pci/Makefile +++ head/sys/modules/bhnd/bhndb_pci/Makefile @@ -6,6 +6,7 @@ SRCS= bhndb_pci.c bhndb_pci_hwdata.c \ bhndb_pci_sprom.c SRCS+= bhnd_bus_if.h bhndb_bus_if.h bhndb_if.h +SRCS+= bhnd_erom_if.h SRCS+= bhnd_nvram_if.h SRCS+= device_if.h bus_if.h pci_if.h