svn commit: r300548 - in head/sys: conf dev/bhnd dev/bhnd/bhndb dev/bhnd/cores/chipc dev/bhnd/nvram dev/bhnd/siba modules/bhnd modules/bhnd/cores/bhnd_chipc

Adrian Chadd adrian at FreeBSD.org
Tue May 24 01:12:21 UTC 2016


Author: adrian
Date: Tue May 24 01:12:19 2016
New Revision: 300548
URL: https://svnweb.freebsd.org/changeset/base/300548

Log:
  [bhnd] Implement pass-through resource management for ChipCommon.
  
  This patchset adds support to bhnd_chipc for sharing SYS_RES_MEMORY
  resources with its children, allowing us to hang devices off of
  bhnd_chipc that rely on access to a subset of the device register space
  that bhnd_chipc itself must also allocate.
  
  We could avoid most of this heavy lifting if RF_SHAREABLE+SYS_RES_MEMORY
  wasn't limited to use with allocations at the same size/offset.
  
  As a work-around, I implemented something similar to vga_pci.c, which
  implements similar reference counting of of PCI BAR resources for its
  children.
  
  With these changes, chipc will use reference counting of SYS_RES_MEMORY
  allocation/activation requests, to decide when to allocate/activate/
  deactivate/release resources from the parent bhnd(4) bus.
  
  The requesting child device is allocated a new resource from chipc's
  rman, pointing to (possibly a subregion of) the refcounted bhnd resources
  allocated by chipc.
  
  Other resource types are just passed directly to the parent bhnd bus;
  RF_SHAREABLE works just fine with IRQs.
  
  I also lifted the SPROM device code out into a common driver, since this
  now allows me to hang simple subclasses off of a common driver off of both
  bhndb_pci and bhnd_chipc.
  
  Tested:
  
  * (landonf) Tested against BCM4331 and BCM4312, confirmed that SPROM still
    attaches and can be queried.
  
  Submitted by:	Landon Fuller <landonf at landonf.org>
  Reviewed by:	mizkha at gmail.com
  Differential Revision:	https://reviews.freebsd.org/D6471

Added:
  head/sys/dev/bhnd/cores/chipc/bhnd_sprom_chipc.c   (contents, props changed)
  head/sys/dev/bhnd/cores/chipc/chipc_private.h   (contents, props changed)
  head/sys/dev/bhnd/cores/chipc/chipc_subr.c   (contents, props changed)
  head/sys/dev/bhnd/nvram/bhnd_sprom_subr.c
     - copied, changed from r300546, head/sys/dev/bhnd/nvram/bhnd_sprom.c
Modified:
  head/sys/conf/files
  head/sys/dev/bhnd/bhnd_subr.c
  head/sys/dev/bhnd/bhndb/bhndb_pci_sprom.c
  head/sys/dev/bhnd/cores/chipc/bhnd_chipc_if.m
  head/sys/dev/bhnd/cores/chipc/chipc.c
  head/sys/dev/bhnd/cores/chipc/chipc.h
  head/sys/dev/bhnd/cores/chipc/chipcreg.h
  head/sys/dev/bhnd/cores/chipc/chipcvar.h
  head/sys/dev/bhnd/nvram/bhnd_nvram.h
  head/sys/dev/bhnd/nvram/bhnd_sprom.c
  head/sys/dev/bhnd/nvram/bhnd_spromvar.h
  head/sys/dev/bhnd/siba/siba.c
  head/sys/dev/bhnd/siba/siba_subr.c
  head/sys/dev/bhnd/siba/sibavar.h
  head/sys/modules/bhnd/Makefile
  head/sys/modules/bhnd/cores/bhnd_chipc/Makefile

Modified: head/sys/conf/files
==============================================================================
--- head/sys/conf/files	Tue May 24 00:57:11 2016	(r300547)
+++ head/sys/conf/files	Tue May 24 01:12:19 2016	(r300548)
@@ -1139,7 +1139,9 @@ dev/bhnd/bcma/bcma_bhndb.c		optional bhn
 dev/bhnd/bcma/bcma_erom.c		optional bhndbus | bcma
 dev/bhnd/bcma/bcma_subr.c		optional bhndbus | bcma
 dev/bhnd/cores/chipc/chipc.c		optional bhndbus | bhnd
+dev/bhnd/cores/chipc/chipc_subr.c	optional bhndbus | bhnd
 dev/bhnd/cores/chipc/bhnd_chipc_if.m	optional bhndbus | bhnd
+dev/bhnd/cores/chipc/bhnd_sprom_chipc.c	optional bhndbus | bhnd
 dev/bhnd/cores/pci/bhnd_pci.c		optional bhndbus pci | bhnd pci
 dev/bhnd/cores/pci/bhnd_pci_hostb.c	optional bhndbus pci | bhndb pci
 dev/bhnd/cores/pci/bhnd_pcib.c		optional bhnd_pcib bhnd pci
@@ -1148,6 +1150,7 @@ dev/bhnd/cores/pcie2/bhnd_pcie2_hostb.c	
 dev/bhnd/cores/pcie2/bhnd_pcie2b.c	optional bhnd_pcie2b bhnd pci
 dev/bhnd/nvram/bhnd_nvram_if.m		optional bhndbus | bhnd
 dev/bhnd/nvram/bhnd_sprom.c		optional bhndbus | bhnd
+dev/bhnd/nvram/bhnd_sprom_subr.c	optional bhndbus | bhnd
 dev/bhnd/nvram/nvram_subr.c		optional bhndbus | bhnd
 dev/bhnd/siba/siba.c			optional bhndbus | siba
 dev/bhnd/siba/siba_bhndb.c		optional bhndbus | siba bhndb

Modified: head/sys/dev/bhnd/bhnd_subr.c
==============================================================================
--- head/sys/dev/bhnd/bhnd_subr.c	Tue May 24 00:57:11 2016	(r300547)
+++ head/sys/dev/bhnd/bhnd_subr.c	Tue May 24 01:12:19 2016	(r300548)
@@ -797,11 +797,11 @@ bhnd_parse_chipid(uint32_t idreg, bhnd_a
 	struct bhnd_chipid result;
 
 	/* Fetch the basic chip info */
-	result.chip_id = CHIPC_GET_ATTR(idreg, ID_CHIP);
-	result.chip_pkg = CHIPC_GET_ATTR(idreg, ID_PKG);
-	result.chip_rev = CHIPC_GET_ATTR(idreg, ID_REV);
-	result.chip_type = CHIPC_GET_ATTR(idreg, ID_BUS);
-	result.ncores = CHIPC_GET_ATTR(idreg, ID_NUMCORE);
+	result.chip_id = CHIPC_GET_BITS(idreg, CHIPC_ID_CHIP);
+	result.chip_pkg = CHIPC_GET_BITS(idreg, CHIPC_ID_PKG);
+	result.chip_rev = CHIPC_GET_BITS(idreg, CHIPC_ID_REV);
+	result.chip_type = CHIPC_GET_BITS(idreg, CHIPC_ID_BUS);
+	result.ncores = CHIPC_GET_BITS(idreg, CHIPC_ID_NUMCORE);
 
 	result.enum_addr = enum_addr;
 
@@ -1020,15 +1020,11 @@ find_nvram_child(device_t dev)
 	if (device_get_devclass(dev) != bhnd_devclass)
 		return (NULL);
 
-	/* Look for a ChipCommon device */
+	/* Look for a ChipCommon-attached NVRAM device */
 	if ((chipc = bhnd_find_child(dev, BHND_DEVCLASS_CC, -1)) != NULL) {
-		bhnd_nvram_src_t src;
-
-		/* Query the NVRAM source and determine whether it's
-		 * accessible via the ChipCommon device */
-		src = BHND_CHIPC_NVRAM_SRC(chipc);
-		if (BHND_NVRAM_SRC_CC(src))
-			return (chipc);
+		nvram = device_find_child(chipc, "bhnd_nvram", 0);
+		if (nvram != NULL)
+			return (nvram);
 	}
 
 	/* Not found */

Modified: head/sys/dev/bhnd/bhndb/bhndb_pci_sprom.c
==============================================================================
--- head/sys/dev/bhnd/bhndb/bhndb_pci_sprom.c	Tue May 24 00:57:11 2016	(r300547)
+++ head/sys/dev/bhnd/bhndb/bhndb_pci_sprom.c	Tue May 24 01:12:19 2016	(r300548)
@@ -53,29 +53,15 @@ __FBSDID("$FreeBSD$");
 #include <dev/bhnd/nvram/bhnd_spromvar.h>
 
 #include "bhnd_nvram_if.h"
+
 #include "bhndb_pcireg.h"
 #include "bhndb_pcivar.h"
 
-struct bhndb_pci_sprom_softc {
-	device_t		 dev;
-	struct bhnd_resource	*sprom_res;	/**< SPROM resource */
-	int			 sprom_rid;	/**< SPROM RID */
-	struct bhnd_sprom	 shadow;	/**< SPROM shadow */
-	struct mtx		 mtx;		/**< SPROM shadow mutex */
-};
-
-#define	SPROM_LOCK_INIT(sc) \
-	mtx_init(&(sc)->mtx, device_get_nameunit((sc)->dev), \
-	    "BHND PCI SPROM lock", MTX_DEF)
-#define	SPROM_LOCK(sc)			mtx_lock(&(sc)->mtx)
-#define	SPROM_UNLOCK(sc)			mtx_unlock(&(sc)->mtx)
-#define	SPROM_LOCK_ASSERT(sc, what)	mtx_assert(&(sc)->mtx, what)
-#define	SPROM_LOCK_DESTROY(sc)		mtx_destroy(&(sc)->mtx)
-
 static int
 bhndb_pci_sprom_probe(device_t dev)
 {
 	device_t	bridge, bus;
+	int		error;
 
 	/* Our parent must be a PCI-BHND bridge with an attached bhnd bus */
 	bridge = device_get_parent(dev);
@@ -86,125 +72,23 @@ bhndb_pci_sprom_probe(device_t dev)
 	if (bus == NULL)
 		return (ENXIO);
 
-	/* Found */
-	device_set_desc(dev, "PCI-BHNDB SPROM/OTP");
-	if (!bootverbose)
-		device_quiet(dev);
+	/* Defer to default driver implementation */
+	if ((error = bhnd_sprom_probe(dev)) > 0)
+		return (error);
 
-	/* Refuse wildcard attachments */
 	return (BUS_PROBE_NOWILDCARD);
 }
 
-static int
-bhndb_pci_sprom_attach(device_t dev)
-{
-	struct bhndb_pci_sprom_softc	*sc;
-	int				 error;
-	
-	sc = device_get_softc(dev);
-	sc->dev = dev;
-
-	/* Allocate SPROM resource */
-	sc->sprom_rid = 0;
-	sc->sprom_res = bhnd_alloc_resource_any(dev, SYS_RES_MEMORY,
-	    &sc->sprom_rid, RF_ACTIVE);
-	if (sc->sprom_res == NULL) {
-		device_printf(dev, "failed to allocate resources\n");
-		return (ENXIO);
-	}
-
-	/* Initialize SPROM shadow */
-	if ((error = bhnd_sprom_init(&sc->shadow, sc->sprom_res, 0))) {
-		device_printf(dev, "unrecognized SPROM format\n");
-		goto failed;
-	}
-
-	/* Initialize mutex */
-	SPROM_LOCK_INIT(sc);
-
-	return (0);
-	
-failed:
-	bhnd_release_resource(dev, SYS_RES_MEMORY, sc->sprom_rid,
-	    sc->sprom_res);
-	return (error);
-}
-
-static int
-bhndb_pci_sprom_resume(device_t dev)
-{
-	return (0);
-}
-
-static int
-bhndb_pci_sprom_suspend(device_t dev)
-{
-	return (0);
-}
-
-static int
-bhndb_pci_sprom_detach(device_t dev)
-{
-	struct bhndb_pci_sprom_softc	*sc;
-	
-	sc = device_get_softc(dev);
-
-	bhnd_release_resource(dev, SYS_RES_MEMORY, sc->sprom_rid,
-	    sc->sprom_res);
-	bhnd_sprom_fini(&sc->shadow);
-	SPROM_LOCK_DESTROY(sc);
-
-	return (0);
-}
-
-static int
-bhndb_pci_sprom_getvar(device_t dev, const char *name, void *buf, size_t *len)
-{
-	struct bhndb_pci_sprom_softc	*sc;
-	int				 error;
-
-	sc = device_get_softc(dev);
-
-	SPROM_LOCK(sc);
-	error = bhnd_sprom_getvar(&sc->shadow, name, buf, len);
-	SPROM_UNLOCK(sc);
-
-	return (error);
-}
-
-static int
-bhndb_pci_sprom_setvar(device_t dev, const char *name, const void *buf,
-    size_t len)
-{
-	struct bhndb_pci_sprom_softc	*sc;
-	int				 error;
-
-	sc = device_get_softc(dev);
-
-	SPROM_LOCK(sc);
-	error = bhnd_sprom_setvar(&sc->shadow, name, buf, len);
-	SPROM_UNLOCK(sc);
-
-	return (error);
-}
 
 static device_method_t bhndb_pci_sprom_methods[] = {
 	/* Device interface */
 	DEVMETHOD(device_probe,			bhndb_pci_sprom_probe),
-	DEVMETHOD(device_attach,		bhndb_pci_sprom_attach),
-	DEVMETHOD(device_resume,		bhndb_pci_sprom_resume),
-	DEVMETHOD(device_suspend,		bhndb_pci_sprom_suspend),
-	DEVMETHOD(device_detach,		bhndb_pci_sprom_detach),
-
-	/* NVRAM interface */
-	DEVMETHOD(bhnd_nvram_getvar,		bhndb_pci_sprom_getvar),
-	DEVMETHOD(bhnd_nvram_setvar,		bhndb_pci_sprom_setvar),
-
 	DEVMETHOD_END
 };
 
-DEFINE_CLASS_0(bhnd_nvram, bhndb_pci_sprom_driver, bhndb_pci_sprom_methods, sizeof(struct bhndb_pci_sprom_softc));
+DEFINE_CLASS_1(bhnd_nvram, bhndb_pci_sprom_driver, bhndb_pci_sprom_methods, sizeof(struct bhnd_sprom_softc), bhnd_sprom_driver);
 
 DRIVER_MODULE(bhndb_pci_sprom, bhndb, bhndb_pci_sprom_driver, bhnd_nvram_devclass, NULL, NULL);
 MODULE_DEPEND(bhndb_pci_sprom, bhnd, 1, 1, 1);
+MODULE_DEPEND(bhndb_pci_sprom, bhnd_sprom, 1, 1, 1);
 MODULE_VERSION(bhndb_pci_sprom, 1);

Modified: head/sys/dev/bhnd/cores/chipc/bhnd_chipc_if.m
==============================================================================
--- head/sys/dev/bhnd/cores/chipc/bhnd_chipc_if.m	Tue May 24 00:57:11 2016	(r300547)
+++ head/sys/dev/bhnd/cores/chipc/bhnd_chipc_if.m	Tue May 24 01:12:19 2016	(r300548)
@@ -36,6 +36,11 @@ INTERFACE bhnd_chipc;
 # bhnd(4) ChipCommon interface.
 #
 
+HEADER {
+	/* forward declarations */
+	struct chipc_caps;
+}
+
 /**
  * Return the preferred NVRAM data source.
  *
@@ -63,3 +68,35 @@ METHOD void write_chipctrl {
 	uint32_t value;
 	uint32_t mask;
 }
+
+/**
+ * Return a borrowed reference to ChipCommon's capability
+ * table.
+ *
+ * @param dev A bhnd(4) ChipCommon device
+ */
+METHOD struct chipc_caps * get_caps {
+	device_t dev;
+}
+
+/**
+ * Enable hardware access to the SPROM.
+ * 
+ * @param sc chipc driver state.
+ *
+ * @retval 0		success
+ * @retval EBUSY	If enabling the hardware may conflict with
+ *			other active devices.
+ */
+METHOD int enable_sprom {
+	device_t dev;
+}
+
+/**
+ * Release hardware access to the SPROM.
+ * 
+ * @param sc chipc driver state.
+ */
+METHOD void disable_sprom {
+	device_t dev;
+}

Added: head/sys/dev/bhnd/cores/chipc/bhnd_sprom_chipc.c
==============================================================================
--- /dev/null	00:00:00 1970	(empty, because file is newly added)
+++ head/sys/dev/bhnd/cores/chipc/bhnd_sprom_chipc.c	Tue May 24 01:12:19 2016	(r300548)
@@ -0,0 +1,101 @@
+/*-
+ * Copyright (c) 2015-2016 Landon Fuller <landon at landonf.org>
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer,
+ *    without modification.
+ * 2. Redistributions in binary form must reproduce at minimum a disclaimer
+ *    similar to the "NO WARRANTY" disclaimer below ("Disclaimer") and any
+ *    redistribution must be conditioned upon including a substantially
+ *    similar Disclaimer requirement for further binary redistribution.
+ *
+ * NO WARRANTY
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF NONINFRINGEMENT, MERCHANTIBILITY
+ * AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL
+ * THE COPYRIGHT HOLDERS OR CONTRIBUTORS BE LIABLE FOR SPECIAL, EXEMPLARY,
+ * OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER
+ * IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
+ * THE POSSIBILITY OF SUCH DAMAGES.
+ */
+
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD$");
+
+/*
+ * ChipCommon SPROM driver.
+ */
+
+#include <sys/param.h>
+#include <sys/kernel.h>
+#include <sys/bus.h>
+#include <sys/limits.h>
+#include <sys/malloc.h>
+#include <sys/module.h>
+#include <sys/systm.h>
+
+#include <dev/bhnd/bhnd.h>
+#include <dev/bhnd/nvram/bhnd_nvram.h>
+#include <dev/bhnd/nvram/bhnd_spromvar.h>
+
+#include "bhnd_chipc_if.h"
+#include "bhnd_nvram_if.h"
+
+static int
+chipc_sprom_probe(device_t dev)
+{
+	device_t	chipc;
+	int		error;
+
+	chipc = device_get_parent(dev);
+
+	/* Only match on SPROM devices */
+	if (BHND_CHIPC_NVRAM_SRC(chipc) != BHND_NVRAM_SRC_SPROM)
+		return (ENXIO);
+
+	/* Defer to default driver implementation */
+	if ((error = bhnd_sprom_probe(dev)) > 0)
+		return (error);
+
+	return (BUS_PROBE_NOWILDCARD);
+}
+
+static int
+chipc_sprom_attach(device_t dev)
+{
+	device_t	chipc;
+	int		error;
+
+	/* Request that ChipCommon enable access to SPROM hardware before
+	 * delegating attachment (and SPROM parsing) to the common driver */
+	chipc = device_get_parent(dev);
+	if ((error = BHND_CHIPC_ENABLE_SPROM(chipc)))
+		return (error);
+
+	error = bhnd_sprom_attach(dev);
+	BHND_CHIPC_DISABLE_SPROM(chipc);
+	return (error);
+}
+
+static device_method_t chipc_sprom_methods[] = {
+	/* Device interface */
+	DEVMETHOD(device_probe,			chipc_sprom_probe),
+	DEVMETHOD(device_attach,		chipc_sprom_attach),
+	DEVMETHOD_END
+};
+
+DEFINE_CLASS_1(bhnd_nvram, chipc_sprom_driver, chipc_sprom_methods, sizeof(struct bhnd_sprom_softc), bhnd_sprom_driver);
+DRIVER_MODULE(bhnd_chipc_sprom, bhnd_chipc, chipc_sprom_driver, bhnd_nvram_devclass, NULL, NULL);
+
+MODULE_DEPEND(bhnd_chipc_sprom, bhnd, 1, 1, 1);
+MODULE_DEPEND(bhnd_chipc_sprom, bhnd_chipc, 1, 1, 1);
+MODULE_DEPEND(bhnd_chipc_sprom, bhnd_sprom, 1, 1, 1);
+MODULE_VERSION(bhnd_chipc_sprom, 1);

Modified: head/sys/dev/bhnd/cores/chipc/chipc.c
==============================================================================
--- head/sys/dev/bhnd/cores/chipc/chipc.c	Tue May 24 00:57:11 2016	(r300547)
+++ head/sys/dev/bhnd/cores/chipc/chipc.c	Tue May 24 01:12:19 2016	(r300548)
@@ -1,5 +1,6 @@
 /*-
- * Copyright (c) 2015 Landon Fuller <landon at landonf.org>
+ * Copyright (c) 2015-2016 Landon Fuller <landon at landonf.org>
+ * Copyright (c) 2016 Michael Zhilin <mizhka at gmail.com>
  * All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
@@ -42,8 +43,11 @@ __FBSDID("$FreeBSD$");
 
 #include <sys/param.h>
 #include <sys/kernel.h>
+#include <sys/lock.h>
 #include <sys/bus.h>
+#include <sys/malloc.h>
 #include <sys/module.h>
+#include <sys/mutex.h>
 #include <sys/systm.h>
 
 #include <machine/bus.h>
@@ -51,19 +55,14 @@ __FBSDID("$FreeBSD$");
 #include <machine/resource.h>
 
 #include <dev/bhnd/bhnd.h>
-
-#include "bhnd_nvram_if.h"
+#include <dev/bhnd/bhndvar.h>
 
 #include "chipcreg.h"
 #include "chipcvar.h"
+#include "chipc_private.h"
 
 devclass_t bhnd_chipc_devclass;	/**< bhnd(4) chipcommon device class */
 
-static const struct resource_spec chipc_rspec[CHIPC_MAX_RSPEC] = {
-	{ SYS_RES_MEMORY,	0,	RF_ACTIVE },
-	{ -1, -1, 0 }
-};
-
 static struct bhnd_device_quirk chipc_quirks[];
 static struct bhnd_chip_quirk chipc_chip_quirks[];
 
@@ -77,7 +76,10 @@ static const struct bhnd_device chipc_de
 /* Device quirks table */
 static struct bhnd_device_quirk chipc_quirks[] = {
 	{ BHND_HWREV_GTE	(32),	CHIPC_QUIRK_SUPPORTS_SPROM },
-	{ BHND_HWREV_GTE	(35),	CHIPC_QUIRK_SUPPORTS_NFLASH },
+	{ BHND_HWREV_GTE	(35),	CHIPC_QUIRK_SUPPORTS_CAP_EXT },
+	{ BHND_HWREV_EQ		(38),	CHIPC_QUIRK_4706_NFLASH }, /*BCM5357 ?*/
+	{ BHND_HWREV_GTE	(49),	CHIPC_QUIRK_IPX_OTPLAYOUT_SIZE },
+
 	BHND_DEVICE_QUIRK_END
 };
 
@@ -111,15 +113,37 @@ static struct bhnd_chip_quirk chipc_chip
 	{{ BHND_CHIP_IR(43602, HWREV_LTE(2)) },
 		CHIPC_QUIRK_4360_FEM_MUX_SPROM },
 
+	/* BCM4706 */
+	{{ BHND_CHIP_ID(4306) },
+		CHIPC_QUIRK_4706_NFLASH },
+
 	BHND_CHIP_QUIRK_END
 };
 
+static int			 chipc_try_activate_resource(
+				    struct chipc_softc *sc, device_t child,
+				    int type, int rid, struct resource *r,
+				    bool req_direct);
+
+static int			 chipc_read_caps(struct chipc_softc *sc,
+				     struct chipc_caps *caps);
+
+static int			 chipc_nvram_attach(struct chipc_softc *sc);
+static bhnd_nvram_src_t		 chipc_nvram_identify(struct chipc_softc *sc);
+static bool			 chipc_should_enable_sprom(
+				     struct chipc_softc *sc);
+
+static int			 chipc_init_rman(struct chipc_softc *sc);
+static void			 chipc_free_rman(struct chipc_softc *sc);
+static struct rman		*chipc_get_rman(struct chipc_softc *sc,
+				     int type);
+
 /* quirk and capability flag convenience macros */
 #define	CHIPC_QUIRK(_sc, _name)	\
     ((_sc)->quirks & CHIPC_QUIRK_ ## _name)
     
 #define CHIPC_CAP(_sc, _name)	\
-    ((_sc)->caps & CHIPC_ ## _name)
+    ((_sc)->caps._name)
 
 #define	CHIPC_ASSERT_QUIRK(_sc, name)	\
     KASSERT(CHIPC_QUIRK((_sc), name), ("quirk " __STRING(_name) " not set"))
@@ -127,12 +151,6 @@ static struct bhnd_chip_quirk chipc_chip
 #define	CHIPC_ASSERT_CAP(_sc, name)	\
     KASSERT(CHIPC_CAP((_sc), name), ("capability " __STRING(_name) " not set"))
 
-static bhnd_nvram_src_t	chipc_nvram_identify(struct chipc_softc *sc);
-static int		chipc_sprom_init(struct chipc_softc *);
-static int		chipc_enable_sprom_pins(struct chipc_softc *);
-static int		chipc_disable_sprom_pins(struct chipc_softc *);
-
-
 static int
 chipc_probe(device_t dev)
 {
@@ -159,19 +177,36 @@ chipc_attach(device_t dev)
 	sc->dev = dev;
 	sc->quirks = bhnd_device_quirks(dev, chipc_devices,
 	    sizeof(chipc_devices[0]));
-	
+	sc->sprom_refcnt = 0;
+
 	CHIPC_LOCK_INIT(sc);
+	STAILQ_INIT(&sc->mem_regions);
 
-	/* Allocate bus resources */
-	memcpy(sc->rspec, chipc_rspec, sizeof(sc->rspec));
-	if ((error = bhnd_alloc_resources(dev, sc->rspec, sc->res)))
-		return (error);
+	/* Set up resource management */
+	if ((error = chipc_init_rman(sc))) {
+		device_printf(sc->dev,
+		    "failed to initialize chipc resource state: %d\n", error);
+		goto failed;
+	}
+
+	/* Allocate the region containing our core registers */
+	if ((sc->core_region = chipc_find_region_by_rid(sc, 0)) == NULL) {
+		error = ENXIO;
+		goto failed;
+	}
+
+	error = chipc_retain_region(sc, sc->core_region,
+	    RF_ALLOCATED|RF_ACTIVE);
+	if (error) {
+		sc->core_region = NULL;
+		goto failed;
+	} else {
+		sc->core = sc->core_region->cr_res;
+	}
 
-	sc->core = sc->res[0];
-	
 	/* Fetch our chipset identification data */
 	ccid_reg = bhnd_bus_read_4(sc->core, CHIPC_ID);
-	chip_type = CHIPC_GET_ATTR(ccid_reg, ID_BUS);
+	chip_type = CHIPC_GET_BITS(ccid_reg, CHIPC_ID_BUS);
 
 	switch (chip_type) {
 	case BHND_CHIPTYPE_SIBA:
@@ -185,44 +220,36 @@ chipc_attach(device_t dev)
 	default:
 		device_printf(dev, "unsupported chip type %hhu\n", chip_type);
 		error = ENODEV;
-		goto cleanup;
+		goto failed;
 	}
 
 	sc->ccid = bhnd_parse_chipid(ccid_reg, enum_addr);
 
-	/* Fetch capability and status register values */
-	sc->caps = bhnd_bus_read_4(sc->core, CHIPC_CAPABILITIES);
-	sc->cst = bhnd_bus_read_4(sc->core, CHIPC_CHIPST);
-
-	/* Identify NVRAM source */
-	sc->nvram_src = chipc_nvram_identify(sc);
-
-	/* Read NVRAM data */
-	switch (sc->nvram_src) {
-	case BHND_NVRAM_SRC_OTP:
-		// TODO (requires access to OTP hardware)
-		device_printf(sc->dev, "NVRAM-OTP unsupported\n");
-		break;
+	/* Fetch and parse capability register(s) */
+	if ((error = chipc_read_caps(sc, &sc->caps)))
+		goto failed;
 
-	case BHND_NVRAM_SRC_NFLASH:
-		// TODO (requires access to NFLASH hardware)
-		device_printf(sc->dev, "NVRAM-NFLASH unsupported\n");
-		break;
+	if (bootverbose)
+		chipc_print_caps(sc->dev, &sc->caps);
 
-	case BHND_NVRAM_SRC_SPROM:
-		if ((error = chipc_sprom_init(sc)))
-			goto cleanup;
-		break;
+	/* Identify NVRAM source and add child device. */
+	sc->nvram_src = chipc_nvram_identify(sc);
+	if ((error = chipc_nvram_attach(sc)))
+		goto failed;
 
-	case BHND_NVRAM_SRC_UNKNOWN:
-		/* Handled externally */
-		break;
-	}
+	/* Standard bus probe */
+	if ((error = bus_generic_attach(dev)))
+		goto failed;
 
 	return (0);
 	
-cleanup:
-	bhnd_release_resources(dev, sc->rspec, sc->res);
+failed:
+	if (sc->core_region != NULL) {
+		chipc_release_region(sc, sc->core_region,
+		    RF_ALLOCATED|RF_ACTIVE);
+	}
+
+	chipc_free_rman(sc);
 	CHIPC_LOCK_DESTROY(sc);
 	return (error);
 }
@@ -231,9 +258,15 @@ static int
 chipc_detach(device_t dev)
 {
 	struct chipc_softc	*sc;
+	int			 error;
 
 	sc = device_get_softc(dev);
-	bhnd_release_resources(dev, sc->rspec, sc->res);
+
+	if ((error = bus_generic_detach(dev)))
+		return (error);
+
+	chipc_release_region(sc, sc->core_region, RF_ALLOCATED|RF_ACTIVE);
+	chipc_free_rman(sc);
 	bhnd_sprom_fini(&sc->sprom);
 
 	CHIPC_LOCK_DESTROY(sc);
@@ -241,58 +274,131 @@ chipc_detach(device_t dev)
 	return (0);
 }
 
+/* Read and parse chipc capabilities */
 static int
-chipc_suspend(device_t dev)
+chipc_read_caps(struct chipc_softc *sc, struct chipc_caps *caps)
 {
-	return (0);
-}
+	uint32_t	cap_reg;
+	uint32_t	cap_ext_reg;
+	uint32_t	regval;
+
+	/* Fetch cap registers */
+	cap_reg = bhnd_bus_read_4(sc->core, CHIPC_CAPABILITIES);
+	cap_ext_reg = 0;
+	if (CHIPC_QUIRK(sc, SUPPORTS_CAP_EXT))
+		cap_ext_reg = bhnd_bus_read_4(sc->core, CHIPC_CAPABILITIES_EXT);
+
+	/* Extract values */
+	caps->num_uarts		= CHIPC_GET_BITS(cap_reg, CHIPC_CAP_NUM_UART);
+	caps->mipseb		= CHIPC_GET_FLAG(cap_reg, CHIPC_CAP_MIPSEB);
+	caps->uart_gpio		= CHIPC_GET_FLAG(cap_reg, CHIPC_CAP_UARTGPIO);
+	caps->uart_clock	= CHIPC_GET_BITS(cap_reg, CHIPC_CAP_UCLKSEL);
+
+	caps->extbus_type	= CHIPC_GET_BITS(cap_reg, CHIPC_CAP_EXTBUS);
+	caps->power_control	= CHIPC_GET_FLAG(cap_reg, CHIPC_CAP_PWR_CTL);
+	caps->jtag_master	= CHIPC_GET_FLAG(cap_reg, CHIPC_CAP_JTAGP);
+
+	caps->pll_type		= CHIPC_GET_BITS(cap_reg, CHIPC_CAP_PLL);
+	caps->backplane_64	= CHIPC_GET_FLAG(cap_reg, CHIPC_CAP_BKPLN64);
+	caps->boot_rom		= CHIPC_GET_FLAG(cap_reg, CHIPC_CAP_ROM);
+	caps->pmu		= CHIPC_GET_FLAG(cap_reg, CHIPC_CAP_PMU);
+	caps->eci		= CHIPC_GET_FLAG(cap_reg, CHIPC_CAP_ECI);
+	caps->sprom		= CHIPC_GET_FLAG(cap_reg, CHIPC_CAP_SPROM);
+	caps->otp_size		= CHIPC_GET_BITS(cap_reg, CHIPC_CAP_OTP_SIZE);
+
+	caps->seci		= CHIPC_GET_FLAG(cap_ext_reg, CHIPC_CAP2_SECI);
+	caps->gsio		= CHIPC_GET_FLAG(cap_ext_reg, CHIPC_CAP2_GSIO);
+	caps->aob		= CHIPC_GET_FLAG(cap_ext_reg, CHIPC_CAP2_AOB);
+
+	/* Fetch OTP size for later IPX controller revisions */
+	if (CHIPC_QUIRK(sc, IPX_OTPLAYOUT_SIZE)) {
+		regval = bhnd_bus_read_4(sc->core, CHIPC_OTPLAYOUT);
+		caps->otp_size = CHIPC_GET_BITS(regval, CHIPC_OTPL_SIZE);
+	}
+
+	/* Determine flash type and paramters */
+	caps->cfi_width = 0;
+
+	switch (CHIPC_GET_BITS(cap_reg, CHIPC_CAP_FLASH)) {
+	case CHIPC_CAP_SFLASH_ST:
+		caps->flash_type = CHIPC_SFLASH_ST;
+		break;
+	case CHIPC_CAP_SFLASH_AT:
+		caps->flash_type = CHIPC_SFLASH_AT;
+		break;
+	case CHIPC_CAP_NFLASH:
+		caps->flash_type = CHIPC_NFLASH;
+		break;
+	case CHIPC_CAP_PFLASH:
+		caps->flash_type = CHIPC_PFLASH_CFI;
+
+		/* determine cfi width */
+		regval = bhnd_bus_read_4(sc->core, CHIPC_FLASH_CFG);
+		if (CHIPC_GET_FLAG(regval, CHIPC_FLASH_CFG_DS))
+			caps->cfi_width = 2;
+		else
+			caps->cfi_width = 1;
+
+		break;
+	case CHIPC_CAP_FLASH_NONE:
+		caps->flash_type = CHIPC_FLASH_NONE;
+		break;
+			
+	}
+
+	/* Handle 4706_NFLASH fallback */
+	if (CHIPC_QUIRK(sc, 4706_NFLASH) &&
+	    CHIPC_GET_FLAG(cap_reg, CHIPC_CAP_4706_NFLASH))
+	{
+		caps->flash_type = CHIPC_NFLASH_4706;
+	}
 
-static int
-chipc_resume(device_t dev)
-{
 	return (0);
 }
 
 /**
- * Initialize local SPROM shadow, if required.
- * 
- * @param sc chipc driver state.
+ * If supported, add an appropriate NVRAM child device.
  */
 static int
-chipc_sprom_init(struct chipc_softc *sc)
+chipc_nvram_attach(struct chipc_softc *sc)
 {
-	int	error;
+	device_t	 nvram_dev;
+	rman_res_t	 start;
+	int		 error;
 
-	KASSERT(sc->nvram_src == BHND_NVRAM_SRC_SPROM,
-	    ("non-SPROM source (%u)\n", sc->nvram_src));
+	switch (sc->nvram_src) {
+	case BHND_NVRAM_SRC_OTP:
+		// TODO OTP support
+		device_printf(sc->dev, "OTP nvram source unsupported\n");
+		return (0);
 
-	/* Enable access to the SPROM */
-	CHIPC_LOCK(sc);
-	if ((error = chipc_enable_sprom_pins(sc)))
-		goto failed;
+	case BHND_NVRAM_SRC_SPROM:
+		/* Add OTP/SPROM device */
+		nvram_dev = BUS_ADD_CHILD(sc->dev, 0, "bhnd_nvram", -1);
+		if (nvram_dev == NULL) {
+			device_printf(sc->dev, "failed to add NVRAM device\n");
+			return (ENXIO);
+		}
+
+		start = rman_get_start(sc->core->res) + CHIPC_SPROM_OTP;
+		error = bus_set_resource(nvram_dev, SYS_RES_MEMORY, 0, start,
+		    CHIPC_SPROM_OTP_SIZE);
+		return (error);
 
-	/* Initialize SPROM parser */
-	error = bhnd_sprom_init(&sc->sprom, sc->core, CHIPC_SPROM_OTP);
-	if (error) {
-		device_printf(sc->dev, "SPROM identification failed: %d\n",
-			error);
+	case BHND_NVRAM_SRC_FLASH:
+		// TODO flash support
+		device_printf(sc->dev, "flash nvram source unsupported\n");
+		return (0);
 
-		chipc_disable_sprom_pins(sc);
-		goto failed;
-	}
+	case BHND_NVRAM_SRC_UNKNOWN:
+		/* Handled externally */
+		return (0);
 
-	/* Drop access to the SPROM lines */
-	if ((error = chipc_disable_sprom_pins(sc))) {
-		bhnd_sprom_fini(&sc->sprom);
-		goto failed;
+	default:
+		device_printf(sc->dev, "invalid nvram source: %u\n",
+		     sc->nvram_src);
+		return (ENXIO);
 	}
-	CHIPC_UNLOCK(sc);
-
-	return (0);
-
-failed:
-	CHIPC_UNLOCK(sc);
-	return (error);
 }
 
 /**
@@ -317,27 +423,645 @@ chipc_nvram_identify(struct chipc_softc 
 	 * We check for hardware presence in order of precedence. For example,
 	 * SPROM is is always used in preference to internal OTP if found.
 	 */
-	if (CHIPC_CAP(sc, CAP_SPROM)) {
+	if (CHIPC_CAP(sc, sprom)) {
 		srom_ctrl = bhnd_bus_read_4(sc->core, CHIPC_SPROM_CTRL);
 		if (srom_ctrl & CHIPC_SRC_PRESENT)
 			return (BHND_NVRAM_SRC_SPROM);
 	}
 
 	/* Check for OTP */
-	if (CHIPC_CAP(sc, CAP_OTP_SIZE))
+	if (CHIPC_CAP(sc, otp_size) != 0)
 		return (BHND_NVRAM_SRC_OTP);
 
-	/*
-	 * Finally, Northstar chipsets (and possibly other chipsets?) support
-	 * external NAND flash. 
-	 */
-	if (CHIPC_QUIRK(sc, SUPPORTS_NFLASH) && CHIPC_CAP(sc, CAP_NFLASH))
-		return (BHND_NVRAM_SRC_NFLASH);
+	/* Check for flash */
+	if (CHIPC_CAP(sc, flash_type) != CHIPC_FLASH_NONE)
+		return (BHND_NVRAM_SRC_FLASH);
 
 	/* No NVRAM hardware capability declared */
 	return (BHND_NVRAM_SRC_UNKNOWN);
 }
 
+static int
+chipc_suspend(device_t dev)
+{
+	return (bus_generic_suspend(dev));
+}
+
+static int
+chipc_resume(device_t dev)
+{
+	return (bus_generic_resume(dev));
+}
+
+static void
+chipc_probe_nomatch(device_t dev, device_t child)
+{
+	struct resource_list	*rl;
+	const char		*name;
+
+	name = device_get_name(child);
+	if (name == NULL)
+		name = "unknown device";
+
+	device_printf(dev, "<%s> at", name);
+
+	rl = BUS_GET_RESOURCE_LIST(dev, child);
+	if (rl != NULL) {
+		resource_list_print_type(rl, "mem", SYS_RES_MEMORY, "%#jx");
+		resource_list_print_type(rl, "irq", SYS_RES_IRQ, "%jd");
+	}
+
+	printf(" (no driver attached)\n");
+}
+
+static int
+chipc_print_child(device_t dev, device_t child)
+{
+	struct resource_list	*rl;
+	int			 retval = 0;
+
+	retval += bus_print_child_header(dev, child);
+
+	rl = BUS_GET_RESOURCE_LIST(dev, child);
+	if (rl != NULL) {
+		retval += resource_list_print_type(rl, "mem", SYS_RES_MEMORY,
+		    "%#jx");
+		retval += resource_list_print_type(rl, "irq", SYS_RES_IRQ,
+		    "%jd");
+	}
+
+	retval += bus_print_child_domain(dev, child);
+	retval += bus_print_child_footer(dev, child);
+
+	return (retval);
+}
+
+static int
+chipc_child_pnpinfo_str(device_t dev, device_t child, char *buf,
+    size_t buflen)
+{
+	if (buflen == 0)
+		return (EOVERFLOW);
+
+	*buf = '\0';
+	return (0);
+}
+
+static int
+chipc_child_location_str(device_t dev, device_t child, char *buf,
+    size_t buflen)
+{
+	if (buflen == 0)
+		return (EOVERFLOW);
+
+	*buf = '\0';
+	return (ENXIO);
+}
+
+static device_t
+chipc_add_child(device_t dev, u_int order, const char *name, int unit)
+{
+	struct chipc_devinfo	*dinfo;
+	device_t		 child;
+
+	child = device_add_child_ordered(dev, order, name, unit);
+	if (child == NULL)
+		return (NULL);
+
+	dinfo = malloc(sizeof(struct chipc_devinfo), M_BHND, M_NOWAIT);
+	if (dinfo == NULL) {
+		device_delete_child(dev, child);
+		return (NULL);
+	}
+
+	resource_list_init(&dinfo->resources);
+
+	device_set_ivars(child, dinfo);
+
+	return (child);
+}
+
+static void
+chipc_child_deleted(device_t dev, device_t child)
+{
+	struct chipc_devinfo *dinfo = device_get_ivars(child);
+
+	if (dinfo != NULL) {
+		resource_list_free(&dinfo->resources);
+		free(dinfo, M_BHND);
+	}
+
+	device_set_ivars(child, NULL);
+}
+
+static struct resource_list *
+chipc_get_resource_list(device_t dev, device_t child)
+{
+	struct chipc_devinfo *dinfo = device_get_ivars(child);
+	return (&dinfo->resources);
+}
+
+
+/* Allocate region records for the given port, and add the port's memory
+ * range to the mem_rman */
+static int
+chipc_rman_init_regions (struct chipc_softc *sc, bhnd_port_type type,
+    u_int port)
+{
+	struct	chipc_region	*cr;
+	rman_res_t		 start, end;
+	u_int			 num_regions;
+	int			 error;
+
+	num_regions = bhnd_get_region_count(sc->dev, port, port);
+	for (u_int region = 0; region < num_regions; region++) {
+		/* Allocate new region record */
+		cr = chipc_alloc_region(sc, type, port, region);
+		if (cr == NULL)
+			return (ENODEV);
+
+		/* Can't manage regions that cannot be allocated */
+		if (cr->cr_rid < 0) {
+			BHND_DEBUG_DEV(sc->dev, "no rid for chipc region "
+			    "%s%u.%u", bhnd_port_type_name(type), port, region);
+			chipc_free_region(sc, cr);
+			continue;
+		}
+
+		/* Add to rman's managed range */
+		start = cr->cr_addr;
+		end = cr->cr_end;
+		if ((error = rman_manage_region(&sc->mem_rman, start, end))) {
+			chipc_free_region(sc, cr);
+			return (error);
+		}
+
+		/* Add to region list */
+		STAILQ_INSERT_TAIL(&sc->mem_regions, cr, cr_link);
+	}
+
+	return (0);
+}
+
+/* Initialize memory state for all chipc port regions */
+static int
+chipc_init_rman(struct chipc_softc *sc)
+{
+	u_int	num_ports;
+	int	error;
+
+	/* Port types for which we'll register chipc_region mappings */
+	bhnd_port_type types[] = {
+	    BHND_PORT_DEVICE
+	};
+
+	/* Initialize resource manager */
+	sc->mem_rman.rm_start = 0;
+	sc->mem_rman.rm_end = BUS_SPACE_MAXADDR;
+	sc->mem_rman.rm_type = RMAN_ARRAY;
+	sc->mem_rman.rm_descr = "ChipCommon Device Memory";
+	if ((error = rman_init(&sc->mem_rman))) {
+		device_printf(sc->dev, "could not initialize mem_rman: %d\n",
+		    error);
+		return (error);
+	}
+
+	/* Populate per-port-region state */
+	for (u_int i = 0; i < nitems(types); i++) {
+		num_ports = bhnd_get_port_count(sc->dev, types[i]);
+		for (u_int port = 0; port < num_ports; port++) {

*** DIFF OUTPUT TRUNCATED AT 1000 LINES ***


More information about the svn-src-all mailing list