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 <lan...@landonf.org>
+ * Copyright (c) 2015-2017 Landon Fuller <land...@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 <land...@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 <land...@freebsd.org>
+ * Copyright (c) 2015-2017 Landon Fuller <land...@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 <lan...@landonf.org>
+# Copyright (c) 2016-2017 Landon Fuller <lan...@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 ***
_______________________________________________
svn-src-head@freebsd.org mailing list
https://lists.freebsd.org/mailman/listinfo/svn-src-head
To unsubscribe, send any mail to "svn-src-head-unsubscr...@freebsd.org"

Reply via email to