svn commit: r324071 - in head/sys: dev/bhnd dev/bhnd/bcma dev/bhnd/bhndb dev/bhnd/siba mips/broadcom modules/bhnd/bhndb_pci
Landon J. Fuller
landonf at FreeBSD.org
Wed Sep 27 19:48:36 UTC 2017
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 at landonf.org>
+ * Copyright (c) 2015-2017 Landon Fuller <landonf at 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 at 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 at FreeBSD.org>
+ * Copyright (c) 2015-2017 Landon Fuller <landonf at 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 at landonf.org>
+# Copyright (c) 2016-2017 Landon Fuller <landon at 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 ***
More information about the svn-src-all
mailing list