Skip site navigation (1)Skip section navigation (2)
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>