Date: Wed, 27 Sep 2017 19:48:34 +0000 (UTC) From: "Landon J. Fuller" <landonf@FreeBSD.org> To: src-committers@freebsd.org, svn-src-all@freebsd.org, svn-src-head@freebsd.org Subject: svn commit: r324071 - in head/sys: dev/bhnd dev/bhnd/bcma dev/bhnd/bhndb dev/bhnd/siba mips/broadcom modules/bhnd/bhndb_pci Message-ID: <201709271948.v8RJmYpD022365@repo.freebsd.org>
next in thread | raw e-mail | index | archive | help
Author: landonf Date: Wed Sep 27 19:48:34 2017 New Revision: 324071 URL: https://svnweb.freebsd.org/changeset/base/324071 Log: bhnd: Add support for supplying bus I/O callbacks when initializing an EROM parser. This allows us to use the EROM parser API in cases where the standard bus space I/O APIs are unsuitable. In particular, this will allow us to parse the device enumeration table directly from bhndb(4) drivers, prior to full attach and configuration of the bridge. Approved by: adrian (mentor) Sponsored by: The FreeBSD Foundation Differential Revision: https://reviews.freebsd.org/D12510 Added: head/sys/dev/bhnd/bhnd_eromvar.h (contents, props changed) Modified: head/sys/dev/bhnd/bcma/bcma.c head/sys/dev/bhnd/bcma/bcma_erom.c head/sys/dev/bhnd/bhnd_erom.c head/sys/dev/bhnd/bhnd_erom.h head/sys/dev/bhnd/bhnd_erom_if.m head/sys/dev/bhnd/bhndb/bhndb.c head/sys/dev/bhnd/bhndb/bhndb_pci.c head/sys/dev/bhnd/bhndb/bhndb_pcivar.h head/sys/dev/bhnd/bhndb/bhndb_private.h head/sys/dev/bhnd/bhndb/bhndb_subr.c head/sys/dev/bhnd/bhndb/bhndbvar.h head/sys/dev/bhnd/bhndreg.h head/sys/dev/bhnd/siba/siba.c head/sys/dev/bhnd/siba/siba_erom.c head/sys/mips/broadcom/bcm_machdep.c head/sys/mips/broadcom/bcm_machdep.h head/sys/modules/bhnd/bhndb_pci/Makefile Modified: head/sys/dev/bhnd/bcma/bcma.c ============================================================================== --- head/sys/dev/bhnd/bcma/bcma.c Wed Sep 27 19:44:23 2017 (r324070) +++ head/sys/dev/bhnd/bcma/bcma.c Wed Sep 27 19:48:34 2017 (r324071) @@ -686,6 +686,7 @@ bcma_add_children(device_t bus) { 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 @@ bcma_add_children(device_t bus) 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; Modified: head/sys/dev/bhnd/bcma/bcma_erom.c ============================================================================== --- head/sys/dev/bhnd/bcma/bcma_erom.c Wed Sep 27 19:44:23 2017 (r324070) +++ head/sys/dev/bhnd/bcma/bcma_erom.c Wed Sep 27 19:48:34 2017 (r324071) @@ -1,7 +1,11 @@ /*- - * Copyright (c) 2015 Landon Fuller <landon@landonf.org> + * Copyright (c) 2015-2017 Landon Fuller <landonf@landonf.org> + * 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 @@ __FBSDID("$FreeBSD$"); * marker. */ -struct bcma_erom_io; - static const char *bcma_erom_entry_type_name (uint8_t entry); -static uint32_t bcma_eio_read4(struct bcma_erom_io *io, - bus_size_t offset); - static int bcma_erom_read32(struct bcma_erom *erom, uint32_t *entry); static int bcma_erom_skip32(struct bcma_erom *erom); @@ -105,37 +104,18 @@ static void bcma_erom_to_core_info(const struct bcma 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 @@ bcma_erom_entry_type_name (uint8_t entry) } } - -/** - * 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 @@ bcma_erom_probe_common(struct bcma_erom_io *io, const } } -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 @@ bcma_erom_peek32(struct bcma_erom *erom, uint32_t *ent 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 @@ bcma_erom_dump(bhnd_erom_t *erom) 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), Modified: head/sys/dev/bhnd/bhnd_erom.c ============================================================================== --- head/sys/dev/bhnd/bhnd_erom.c Wed Sep 27 19:44:23 2017 (r324070) +++ head/sys/dev/bhnd/bhnd_erom.c Wed Sep 27 19:48:34 2017 (r324071) @@ -1,7 +1,11 @@ /*- * Copyright (c) 2016 Landon Fuller <landonf@FreeBSD.org> + * 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 <sys/param.h> +#include <sys/bus.h> #include <sys/kobj.h> + +#include <machine/bus.h> +#include <sys/rman.h> +#include <machine/resource.h> #include <dev/bhnd/bhndvar.h> #include <dev/bhnd/bhnd_erom.h> +#include <dev/bhnd/bhnd_eromvar.h> +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 @@ __FBSDID("$FreeBSD$"); */ 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 @@ bhnd_erom_alloc(bhnd_erom_class_t *cls, const struct b 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 @@ bhnd_erom_alloc(bhnd_erom_class_t *cls, const struct b } /** - * 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 @@ bhnd_erom_alloc(bhnd_erom_class_t *cls, const struct b * @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 @@ bhnd_erom_alloc(bhnd_erom_class_t *cls, const struct b */ 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 @@ bhnd_erom_init_static(bhnd_erom_class_t *cls, bhnd_ero /* 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_free(bhnd_erom_t *erom) { 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); + } } Modified: head/sys/dev/bhnd/bhnd_erom.h ============================================================================== --- head/sys/dev/bhnd/bhnd_erom.h Wed Sep 27 19:44:23 2017 (r324070) +++ head/sys/dev/bhnd/bhnd_erom.h Wed Sep 27 19:48:34 2017 (r324071) @@ -1,7 +1,11 @@ /*- - * Copyright (c) 2015-2016 Landon Fuller <landonf@FreeBSD.org> + * Copyright (c) 2015-2017 Landon Fuller <landonf@FreeBSD.org> + * 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 @@ SET_DECLARE(bhnd_erom_class_set, bhnd_erom_class_t); #define BHND_EROM_CLASS_DEF(classvar) DATA_SET(bhnd_erom_class_set, classvar) - /** * Probe to see if this device enumeration class supports the bhnd bus - * mapped by the given resource, returning a standard newbus device probe - * result (see BUS_PROBE_*) and the probed chip identification. + * 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 @@ SET_DECLARE(bhnd_erom_class_set, bhnd_erom_class_t); * 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)); } /** Modified: head/sys/dev/bhnd/bhnd_erom_if.m ============================================================================== --- head/sys/dev/bhnd/bhnd_erom_if.m Wed Sep 27 19:44:23 2017 (r324070) +++ head/sys/dev/bhnd/bhnd_erom_if.m Wed Sep 27 19:48:34 2017 (r324071) @@ -1,7 +1,11 @@ #- -# Copyright (c) 2016 Landon Fuller <landon@landonf.org> +# Copyright (c) 2016-2017 Landon Fuller <landon@landonf.org> +# 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 @@ INTERFACE bhnd_erom; # tables used by bhnd(4) buses. # -/** - * Probe to see if this device enumeration class supports the bhnd bus - * mapped by the given resource, returning a standard newbus device probe - * result (see BUS_PROBE_*) and the probed chip identification. - * - * @param cls The erom class to probe. - * @param res A resource mapping the first bus core. - * @param offset Offset to the first bus core within @p res. - * @param hint Hint used to identify the device. If chipset supports - * standard chip identification registers within the first - * core, this parameter should be NULL. - * @param[out] cid On success, the probed chip identifier. - * - * @retval 0 if this is the only possible device enumeration - * parser for the probed bus. - * @retval negative if the probe succeeds, a negative value should be - * returned; the parser returning the highest negative - * value will be selected to handle device enumeration. - * @retval ENXIO If the bhnd bus type is not handled by this parser. - * @retval positive if an error occurs during probing, a regular unix error - * code should be returned. - */ -STATICMETHOD int probe { - bhnd_erom_class_t *cls; - struct bhnd_resource *res; - bus_size_t offset; - const struct bhnd_chipid *hint; - struct bhnd_chipid *cid; +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 @@ STATICMETHOD int probe { * @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 @@ STATICMETHOD int probe_static { * * @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 @@ STATICMETHOD int probe_static { METHOD int init { bhnd_erom_t *erom; const struct bhnd_chipid *cid; - device_t parent; - int rid; -}; - *** DIFF OUTPUT TRUNCATED AT 1000 LINES ***
Want to link to this message? Use this URL: <https://mail-archive.FreeBSD.org/cgi/mid.cgi?201709271948.v8RJmYpD022365>