Page Menu
Home
FreeBSD
Search
Configure Global Search
Log In
Files
F148993201
D6471.1789341885.diff
No One
Temporary
Actions
View File
Edit File
Delete File
View Transforms
Subscribe
Flag For Later
Award Token
Size
78 KB
Referenced Files
None
Subscribers
None
D6471.1789341885.diff
View Options
Index: sys/conf/files
===================================================================
--- sys/conf/files
+++ sys/conf/files
@@ -1139,6 +1139,7 @@
dev/bhnd/bcma/bcma_subr.c optional bhndbus | bcma
dev/bhnd/cores/chipc/chipc.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
@@ -1147,6 +1148,7 @@
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
Index: sys/dev/bhnd/bhnd_subr.c
===================================================================
--- sys/dev/bhnd/bhnd_subr.c
+++ sys/dev/bhnd/bhnd_subr.c
@@ -1020,15 +1020,11 @@
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 */
Index: sys/dev/bhnd/bhndb/bhndb_pci_sprom.c
===================================================================
--- sys/dev/bhnd/bhndb/bhndb_pci_sprom.c
+++ sys/dev/bhnd/bhndb/bhndb_pci_sprom.c
@@ -53,29 +53,15 @@
#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 @@
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);
Index: sys/dev/bhnd/cores/chipc/bhnd_chipc_if.m
===================================================================
--- sys/dev/bhnd/cores/chipc/bhnd_chipc_if.m
+++ sys/dev/bhnd/cores/chipc/bhnd_chipc_if.m
@@ -63,3 +63,25 @@
uint32_t value;
uint32_t mask;
}
+
+/**
+ * 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;
+}
Index: sys/dev/bhnd/cores/chipc/bhnd_sprom_chipc.c
===================================================================
--- /dev/null
+++ sys/dev/bhnd/cores/chipc/bhnd_sprom_chipc.c
@@ -0,0 +1,101 @@
+/*-
+ * Copyright (c) 2015-2016 Landon Fuller <landon@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);
Index: sys/dev/bhnd/cores/chipc/chipc.c
===================================================================
--- sys/dev/bhnd/cores/chipc/chipc.c
+++ sys/dev/bhnd/cores/chipc/chipc.c
@@ -1,5 +1,6 @@
/*-
- * Copyright (c) 2015 Landon Fuller <landon@landonf.org>
+ * Copyright (c) 2015-2016 Landon Fuller <landon@landonf.org>
+ * Copyright (c) 2016 Michael Zhilin <mizhka@gmail.com>
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
@@ -42,8 +43,11 @@
#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,13 @@
#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"
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[];
@@ -114,6 +112,36 @@
BHND_CHIP_QUIRK_END
};
+static struct chipc_region *chipc_alloc_region(struct chipc_softc *sc,
+ bhnd_port_type type, u_int port,
+ u_int region);
+static void chipc_free_region(struct chipc_softc *sc,
+ struct chipc_region *cr);
+static struct chipc_region *chipc_find_region(struct chipc_softc *sc,
+ rman_res_t start, rman_res_t end);
+static struct chipc_region *chipc_find_region_by_rid(struct chipc_softc *sc,
+ int rid);
+
+int chipc_retain_region(struct chipc_softc *sc,
+ struct chipc_region *cr, int flags);
+int chipc_release_region(struct chipc_softc *sc,
+ struct chipc_region *cr, int flags);
+
+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_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);
+
+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);
+
/* quirk and capability flag convenience macros */
#define CHIPC_QUIRK(_sc, _name) \
((_sc)->quirks & CHIPC_QUIRK_ ## _name)
@@ -127,12 +155,6 @@
#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)
{
@@ -146,6 +168,128 @@
return (BUS_PROBE_DEFAULT);
}
+/* 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++) {
+ error = chipc_rman_init_regions(sc, types[i], port);
+ if (error) {
+ device_printf(sc->dev,
+ "region init failed for %s%u: %d\n",
+ bhnd_port_type_name(types[i]), port,
+ error);
+
+ goto failed;
+ }
+ }
+ }
+
+ return (0);
+
+failed:
+ chipc_free_rman(sc);
+ return (error);
+}
+
+/* Free memory management state */
+static void
+chipc_free_rman(struct chipc_softc *sc)
+{
+ struct chipc_region *cr, *cr_next;
+
+ STAILQ_FOREACH_SAFE(cr, &sc->mem_regions, cr_link, cr_next)
+ chipc_free_region(sc, cr);
+
+ rman_fini(&sc->mem_rman);
+}
+
+/**
+ * Return the rman instance for a given resource @p type, if any.
+ *
+ * @param sc The chipc device state.
+ * @param type The resource type (e.g. SYS_RES_MEMORY, SYS_RES_IRQ, ...)
+ */
+static struct rman *
+chipc_get_rman(struct chipc_softc *sc, int type)
+{
+ switch (type) {
+ case SYS_RES_MEMORY:
+ return (&sc->mem_rman);
+
+ case SYS_RES_IRQ:
+ /* IRQs can be used with RF_SHAREABLE, so we don't perform
+ * any local proxying of resource requests. */
+ return (NULL);
+
+ default:
+ return (NULL);
+ };
+}
+
static int
chipc_attach(device_t dev)
{
@@ -159,16 +303,33 @@
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);
@@ -185,7 +346,7 @@
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);
@@ -194,35 +355,24 @@
sc->caps = bhnd_bus_read_4(sc->core, CHIPC_CAPABILITIES);
sc->cst = bhnd_bus_read_4(sc->core, CHIPC_CHIPST);
- /* Identify NVRAM source */
+ /* Identify NVRAM source and add child device. */
sc->nvram_src = chipc_nvram_identify(sc);
+ if ((error = chipc_nvram_attach(sc)))
+ goto failed;
- /* 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;
-
- case BHND_NVRAM_SRC_NFLASH:
- // TODO (requires access to NFLASH hardware)
- device_printf(sc->dev, "NVRAM-NFLASH unsupported\n");
- break;
-
- case BHND_NVRAM_SRC_SPROM:
- if ((error = chipc_sprom_init(sc)))
- goto cleanup;
- break;
-
- 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 +381,15 @@
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);
@@ -244,57 +400,767 @@
static int
chipc_suspend(device_t dev)
{
- return (0);
+ 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);
+}
+
/**
- * Initialize local SPROM shadow, if required.
+ * Allocate and initialize new region record.
*
- * @param sc chipc driver state.
+ * @param sc Driver instance state.
+ * @param type The port type to query.
+ * @param port The port number to query.
+ * @param region The region number to query.
*/
-static int
-chipc_sprom_init(struct chipc_softc *sc)
+static struct chipc_region *
+chipc_alloc_region(struct chipc_softc *sc, bhnd_port_type type,
+ u_int port, u_int region)
{
- int error;
+ struct chipc_region *cr;
+ int error;
- KASSERT(sc->nvram_src == BHND_NVRAM_SRC_SPROM,
- ("non-SPROM source (%u)\n", sc->nvram_src));
+ /* Don't bother allocating a chipc_region if init will fail */
+ if (!bhnd_is_region_valid(sc->dev, type, port, region))
+ return (NULL);
- /* Enable access to the SPROM */
- CHIPC_LOCK(sc);
- if ((error = chipc_enable_sprom_pins(sc)))
- goto failed;
+ /* Allocate and initialize region info */
+ cr = malloc(sizeof(*cr), M_BHND, M_NOWAIT);
+ if (cr == NULL)
+ return (NULL);
- /* 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);
+ cr->cr_port_type = type;
+ cr->cr_port_num = port;
+ cr->cr_region_num = region;
+ cr->cr_res = NULL;
+ cr->cr_refs = 0;
+ cr->cr_act_refs = 0;
- chipc_disable_sprom_pins(sc);
+ error = bhnd_get_region_addr(sc->dev, type, port, region, &cr->cr_addr,
+ &cr->cr_count);
+ if (error) {
+ device_printf(sc->dev,
+ "fetching chipc region address failed: %d\n", error);
goto failed;
}
- /* Drop access to the SPROM lines */
- if ((error = chipc_disable_sprom_pins(sc))) {
- bhnd_sprom_fini(&sc->sprom);
- goto failed;
+ cr->cr_end = cr->cr_addr + cr->cr_count - 1;
+
+ /* Note that not all regions have an assigned rid, in which case
+ * this will return -1 */
+ cr->cr_rid = bhnd_get_port_rid(sc->dev, type, port, region);
+ return (cr);
+
+failed:
+ device_printf(sc->dev, "chipc region alloc failed for %s%u.%u\n",
+ bhnd_port_type_name(type), port, region);
+ free(cr, M_BHND);
+ return (NULL);
+}
+
+/**
+ * Deallocate the given region record and its associated resource, if any.
+ *
+ * @param sc Driver instance state.
+ * @param cr Region record to be deallocated.
+ */
+static void
+chipc_free_region(struct chipc_softc *sc, struct chipc_region *cr)
+{
+ KASSERT(cr->cr_refs == 0,
+ ("chipc %s%u.%u region has %u active references",
+ bhnd_port_type_name(cr->cr_port_type), cr->cr_port_num,
+ cr->cr_region_num, cr->cr_refs));
+
+ if (cr->cr_res != NULL) {
+ bhnd_release_resource(sc->dev, SYS_RES_MEMORY, cr->cr_rid,
+ cr->cr_res);
}
- CHIPC_UNLOCK(sc);
+ free(cr, M_BHND);
+}
+
+/**
+ * Locate the region mapping the given range, if any. Returns NULL if no
+ * valid region is found.
+ *
+ * @param sc Driver instance state.
+ * @param start start of address range.
+ * @param end end of address range.
+ */
+static struct chipc_region *
+chipc_find_region(struct chipc_softc *sc, rman_res_t start, rman_res_t end)
+{
+ struct chipc_region *cr;
+
+ if (start > end)
+ return (NULL);
+
+ STAILQ_FOREACH(cr, &sc->mem_regions, cr_link) {
+ if (start < cr->cr_addr || end > cr->cr_end)
+ continue;
+
+ /* Found */
+ return (cr);
+ }
+
+ /* Not found */
+ return (NULL);
+}
+
+/**
+ * Locate a region mapping by its bhnd-assigned resource id (as returned by
+ * bhnd_get_port_rid).
+ *
+ * @param sc Driver instance state.
+ * @param rid Resource ID to query for.
+ */
+static struct chipc_region *
+chipc_find_region_by_rid(struct chipc_softc *sc, int rid)
+{
+ struct chipc_region *cr;
+ int port_rid;
+
+ STAILQ_FOREACH(cr, &sc->mem_regions, cr_link) {
+ port_rid = bhnd_get_port_rid(sc->dev, cr->cr_port_type,
+ cr->cr_port_num, cr->cr_region_num);
+ if (port_rid == -1 || port_rid != rid)
+ continue;
+
+ /* Found */
+ return (cr);
+ }
+
+ /* Not found */
+ return (NULL);
+}
+
+/* Retain a reference to the region, allocating/activating if necessary */
+int
+chipc_retain_region(struct chipc_softc *sc, struct chipc_region *cr, int flags)
+{
+ int error;
+
+ KASSERT(!(flags &~ (RF_ACTIVE|RF_ALLOCATED)), ("unsupported flags"));
+
+ CHIPC_LOCK(sc);
+
+ /* Handle allocation */
+ if (flags & RF_ALLOCATED) {
+ /* If this is the first reference, allocate the resource */
+ if (cr->cr_refs == 0) {
+ KASSERT(cr->cr_res == NULL,
+ ("non-NULL resource has refcount"));
+
+ cr->cr_res = bhnd_alloc_resource(sc->dev,
+ SYS_RES_MEMORY, &cr->cr_rid, cr->cr_addr,
+ cr->cr_end, cr->cr_count, 0);
+
+ if (cr->cr_res == NULL) {
+ CHIPC_UNLOCK(sc);
+ return (ENXIO);
+ }
+ }
+
+ /* Increment allocation refcount */
+ cr->cr_refs++;
+ }
+
+
+ /* Handle activation */
+ if (flags & RF_ACTIVE) {
+ KASSERT(cr->cr_refs > 0,
+ ("cannot activate unallocated resource"));
+
+ /* If this is the first reference, activate the resource */
+ if (cr->cr_act_refs == 0) {
+ error = bhnd_activate_resource(sc->dev, SYS_RES_MEMORY,
+ cr->cr_rid, cr->cr_res);
+ if (error) {
+ /* Drop any allocation reference acquired
+ * above */
+ CHIPC_UNLOCK(sc);
+ chipc_release_region(sc, cr,
+ flags &~ RF_ACTIVE);
+ return (error);
+ }
+ }
+
+ /* Increment activation refcount */
+ cr->cr_act_refs++;
+ }
+
+ CHIPC_UNLOCK(sc);
return (0);
+}
-failed:
+int
+chipc_release_region(struct chipc_softc *sc, struct chipc_region *cr,
+ int flags)
+{
+ int error;
+
+ CHIPC_LOCK(sc);
+ error = 0;
+
+ if (flags & RF_ACTIVE) {
+ KASSERT(cr->cr_act_refs > 0, ("RF_ACTIVE over-released"));
+ KASSERT(cr->cr_act_refs <= cr->cr_refs,
+ ("RF_ALLOCATED released with RF_ACTIVE held"));
+
+ /* If this is the last reference, deactivate the resource */
+ if (cr->cr_act_refs == 1) {
+ error = bhnd_deactivate_resource(sc->dev,
+ SYS_RES_MEMORY, cr->cr_rid, cr->cr_res);
+ if (error)
+ goto done;
+ }
+
+ /* Drop our activation refcount */
+ cr->cr_act_refs--;
+ }
+
+ if (flags & RF_ALLOCATED) {
+ KASSERT(cr->cr_refs > 0, ("overrelease of refs"));
+
+ /* If this is the last reference, release the resource */
+ if (cr->cr_refs == 1) {
+ error = bhnd_release_resource(sc->dev,
+ SYS_RES_MEMORY, cr->cr_rid, cr->cr_res);
+ if (error)
+ goto done;
+
+ cr->cr_res = NULL;
+ cr->cr_rid = -1;
+ }
+
+ /* Drop our allocation refcount */
+ cr->cr_refs--;
+ }
+
+done:
CHIPC_UNLOCK(sc);
return (error);
}
+static struct resource *
+chipc_alloc_resource(device_t dev, device_t child, int type,
+ int *rid, rman_res_t start, rman_res_t end, rman_res_t count, u_int flags)
+{
+ struct chipc_softc *sc;
+ struct chipc_region *cr;
+ struct resource_list_entry *rle;
+ struct resource *rv;
+ struct rman *rm;
+ int error;
+ bool passthrough, isdefault;
+
+ sc = device_get_softc(dev);
+ passthrough = (device_get_parent(child) != dev);
+ isdefault = RMAN_IS_DEFAULT_RANGE(start, end);
+ rle = NULL;
+
+ /* Fetch the resource manager, delegate request if necessary */
+ rm = chipc_get_rman(sc, type);
+ if (rm == NULL) {
+ /* Requested resource type is delegated to our parent */
+ rv = bus_generic_rl_alloc_resource(dev, child, type, rid,
+ start, end, count, flags);
+ return (rv);
+ }
+
+ /* Populate defaults */
+ if (!passthrough && isdefault) {
+ /* Fetch the resource list entry. */
+ rle = resource_list_find(BUS_GET_RESOURCE_LIST(dev, child),
+ type, *rid);
+ if (rle == NULL) {
+ device_printf(dev,
+ "default resource %#x type %d for child %s "
+ "not found\n", *rid, type,
+ device_get_nameunit(child));
+ return (NULL);
+ }
+
+ if (rle->res != NULL) {
+ device_printf(dev,
+ "resource entry %#x type %d for child %s is busy\n",
+ *rid, type, device_get_nameunit(child));
+
+ return (NULL);
+ }
+
+ start = rle->start;
+ end = rle->end;
+ count = ulmax(count, rle->count);
+ }
+
+ /* Locate a mapping region */
+ if ((cr = chipc_find_region(sc, start, end)) == NULL) {
+ device_printf(dev,
+ "no mapping region found for %#x type %d for "
+ "child %s\n",
+ *rid, type, device_get_nameunit(child));
+
+ return (NULL);
+ }
+
+ /* Try to retain a region reference */
+ if ((error = chipc_retain_region(sc, cr, RF_ALLOCATED))) {
+ CHIPC_UNLOCK(sc);
+ return (NULL);
+ }
+
+ /* Make our rman reservation */
+ rv = rman_reserve_resource(rm, start, end, count, flags & ~RF_ACTIVE,
+ child);
+ if (rv == NULL) {
+ chipc_release_region(sc, cr, RF_ALLOCATED);
+ return (NULL);
+ }
+
+ rman_set_rid(rv, *rid);
+
+ /* Activate */
+ if (flags & RF_ACTIVE) {
+ error = bus_activate_resource(child, type, *rid, rv);
+ if (error) {
+ device_printf(dev,
+ "failed to activate entry %#x type %d for "
+ "child %s: %d\n",
+ *rid, type, device_get_nameunit(child), error);
+
+ chipc_release_region(sc, cr, RF_ALLOCATED);
+ rman_release_resource(rv);
+
+ return (NULL);
+ }
+ }
+
+ /* Update child's resource list entry */
+ if (rle != NULL) {
+ rle->res = rv;
+ rle->start = rman_get_start(rv);
+ rle->end = rman_get_end(rv);
+ rle->count = rman_get_size(rv);
+ }
+
+ return (rv);
+}
+
+static int
+chipc_release_resource(device_t dev, device_t child, int type, int rid,
+ struct resource *r)
+{
+ struct chipc_softc *sc;
+ struct chipc_region *cr;
+ struct rman *rm;
+ int error;
+
+ sc = device_get_softc(dev);
+
+ /* Handled by parent bus? */
+ rm = chipc_get_rman(sc, type);
+ if (rm == NULL || !rman_is_region_manager(r, rm)) {
+ return (bus_generic_rl_release_resource(dev, child, type, rid,
+ r));
+ }
+
+ /* Locate the mapping region */
+ cr = chipc_find_region(sc, rman_get_start(r), rman_get_end(r));
+ if (cr == NULL)
+ return (EINVAL);
+
+ /* Deactivate resources */
+ if (rman_get_flags(r) & RF_ACTIVE) {
+ error = BUS_DEACTIVATE_RESOURCE(dev, child, type, rid, r);
+ if (error)
+ return (error);
+ }
+
+ if ((error = rman_release_resource(r)))
+ return (error);
+
+ /* Drop allocation reference */
+ chipc_release_region(sc, cr, RF_ALLOCATED);
+
+ return (0);
+}
+
+static int
+chipc_adjust_resource(device_t dev, device_t child, int type,
+ struct resource *r, rman_res_t start, rman_res_t end)
+{
+ struct chipc_softc *sc;
+ struct chipc_region *cr;
+ struct rman *rm;
+
+ sc = device_get_softc(dev);
+
+ /* Handled by parent bus? */
+ rm = chipc_get_rman(sc, type);
+ if (rm == NULL || !rman_is_region_manager(r, rm)) {
+ return (bus_generic_adjust_resource(dev, child, type, r, start,
+ end));
+ }
+
+ /* The range is limited to the existing region mapping */
+ cr = chipc_find_region(sc, rman_get_start(r), rman_get_end(r));
+ if (cr == NULL)
+ return (EINVAL);
+
+ if (end <= start)
+ return (EINVAL);
+
+ if (start < cr->cr_addr || end > cr->cr_end)
+ return (EINVAL);
+
+ /* Range falls within the existing region */
+ return (rman_adjust_resource(r, start, end));
+}
+
+/**
+ * Initialize child resource @p r with a virtual address, tag, and handle
+ * copied from @p parent, adjusted to contain only the range defined by
+ * @p offsize and @p size.
+ *
+ * @param r The register to be initialized.
+ * @param parent The parent bus resource that fully contains the subregion.
+ * @param offset The subregion offset within @p parent.
+ * @param size The subregion size.
+ */
+static int
+chipc_init_child_resource(struct resource *r,
+ struct resource *parent, bhnd_size_t offset, bhnd_size_t size)
+{
+ bus_space_handle_t bh, child_bh;
+ bus_space_tag_t bt;
+ uintptr_t vaddr;
+ int error;
+
+ /* Fetch the parent resource's bus values */
+ vaddr = (uintptr_t) rman_get_virtual(parent);
+ bt = rman_get_bustag(parent);
+ bh = rman_get_bushandle(parent);
+
+ /* Configure child resource with offset-adjusted values */
+ vaddr += offset;
+ error = bus_space_subregion(bt, bh, offset, size, &child_bh);
+ if (error)
+ return (error);
+
+ rman_set_virtual(r, (void *) vaddr);
+ rman_set_bustag(r, bt);
+ rman_set_bushandle(r, child_bh);
+
+ return (0);
+}
+
+/**
+ * Retain an RF_ACTIVE reference to the region mapping @p r, and
+ * configure @p r with its subregion values.
+ *
+ * @param sc Driver instance state.
+ * @param child Requesting child device.
+ * @param type resource type of @p r.
+ * @param rid resource id of @p r
+ * @param r resource to be activated.
+ * @param req_direct If true, failure to allocate a direct bhnd resource
+ * will be treated as an error. If false, the resource will not be marked
+ * as RF_ACTIVE if bhnd direct resource allocation fails.
+ */
+static int
+chipc_try_activate_resource(struct chipc_softc *sc, device_t child, int type,
+ int rid, struct resource *r, bool req_direct)
+{
+ struct rman *rm;
+ struct chipc_region *cr;
+ bhnd_size_t cr_offset;
+ rman_res_t r_start, r_end, r_size;
+ int error;
+
+ rm = chipc_get_rman(sc, type);
+ if (rm == NULL || !rman_is_region_manager(r, rm))
+ return (EINVAL);
+
+ r_start = rman_get_start(r);
+ r_end = rman_get_end(r);
+ r_size = rman_get_size(r);
+
+ /* Find the corresponding chipc region */
+ cr = chipc_find_region(sc, r_start, r_end);
+ if (cr == NULL)
+ return (EINVAL);
+
+ /* Calculate subregion offset within the chipc region */
+ cr_offset = r_start - cr->cr_addr;
+
+ /* Retain (and activate, if necessary) the chipc region */
+ if ((error = chipc_retain_region(sc, cr, RF_ACTIVE)))
+ return (error);
+
+ /* Configure child resource with its subregion values. */
+ if (cr->cr_res->direct) {
+ error = chipc_init_child_resource(r, cr->cr_res->res,
+ cr_offset, r_size);
+ if (error)
+ goto cleanup;
+
+ /* Mark active */
+ if ((error = rman_activate_resource(r)))
+ goto cleanup;
+ } else if (req_direct) {
+ error = ENOMEM;
+ goto cleanup;
+ }
+
+ return (0);
+
+cleanup:
+ chipc_release_region(sc, cr, RF_ACTIVE);
+ return (error);
+}
+
+static int
+chipc_activate_bhnd_resource(device_t dev, device_t child, int type,
+ int rid, struct bhnd_resource *r)
+{
+ struct chipc_softc *sc;
+ struct rman *rm;
+ int error;
+
+ sc = device_get_softc(dev);
+
+ /* Delegate non-locally managed resources to parent */
+ rm = chipc_get_rman(sc, type);
+ if (rm == NULL || !rman_is_region_manager(r->res, rm)) {
+ return (bhnd_bus_generic_activate_resource(dev, child, type,
+ rid, r));
+ }
+
+ /* Try activating the chipc region resource */
+ error = chipc_try_activate_resource(sc, child, type, rid, r->res,
+ false);
+ if (error)
+ return (error);
+
+ /* Mark the child resource as direct according to the returned resource
+ * state */
+ if (rman_get_flags(r->res) & RF_ACTIVE)
+ r->direct = true;
+
+ return (0);
+}
+
+static int
+chipc_activate_resource(device_t dev, device_t child, int type, int rid,
+ struct resource *r)
+{
+ struct chipc_softc *sc;
+ struct rman *rm;
+
+ sc = device_get_softc(dev);
+
+ /* Delegate non-locally managed resources to parent */
+ rm = chipc_get_rman(sc, type);
+ if (rm == NULL || !rman_is_region_manager(r, rm)) {
+ return (bus_generic_activate_resource(dev, child, type, rid,
+ r));
+ }
+
+ /* Try activating the chipc region-based resource */
+ return (chipc_try_activate_resource(sc, child, type, rid, r, true));
+}
+
+/**
+ * Default bhndb(4) implementation of BUS_DEACTIVATE_RESOURCE().
+ */
+static int
+chipc_deactivate_resource(device_t dev, device_t child, int type,
+ int rid, struct resource *r)
+{
+ struct chipc_softc *sc;
+ struct chipc_region *cr;
+ struct rman *rm;
+ int error;
+
+ sc = device_get_softc(dev);
+
+ /* Handled by parent bus? */
+ rm = chipc_get_rman(sc, type);
+ if (rm == NULL || !rman_is_region_manager(r, rm)) {
+ return (bus_generic_deactivate_resource(dev, child, type, rid,
+ r));
+ }
+
+ /* Find the corresponding chipc region */
+ cr = chipc_find_region(sc, rman_get_start(r), rman_get_end(r));
+ if (cr == NULL)
+ return (EINVAL);
+
+ /* Mark inactive */
+ if ((error = rman_deactivate_resource(r)))
+ return (error);
+
+ /* Drop associated RF_ACTIVE reference */
+ chipc_release_region(sc, cr, RF_ACTIVE);
+
+ return (0);
+}
+
+/**
+ * If supported, add an appropriate NVRAM child device.
+ */
+static int
+chipc_nvram_attach(struct chipc_softc *sc)
+{
+ device_t nvram_dev;
+ rman_res_t start;
+ int error;
+
+ switch (sc->nvram_src) {
+ case BHND_NVRAM_SRC_OTP:
+ 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);
+
+ case BHND_NVRAM_SRC_NFLASH:
+ // TODO (requires access to NFLASH hardware)
+ device_printf(sc->dev, "NVRAM-NFLASH unsupported\n");
+ return (0);
+
+ case BHND_NVRAM_SRC_UNKNOWN:
+ /* Handled externally */
+ return (0);
+
+ default:
+ device_printf(sc->dev, "invalid nvram source: %u\n",
+ sc->nvram_src);
+ return (ENXIO);
+ }
+}
+
/**
* Determine the NVRAM data source for this device.
*
@@ -338,6 +1204,57 @@
return (BHND_NVRAM_SRC_UNKNOWN);
}
+/**
+ * Examine bus state and make a best effort determination of whether it's
+ * likely safe to enable the muxed SPROM pins.
+ *
+ * On devices that do not use SPROM pin muxing, always returns true.
+ *
+ * @param sc chipc driver state.
+ */
+static bool
+chipc_should_enable_sprom(struct chipc_softc *sc)
+{
+ device_t *devs;
+ device_t hostb;
+ device_t parent;
+ int devcount;
+ int error;
+ bool result;
+
+ mtx_assert(&Giant, MA_OWNED); /* for newbus */
+
+ /* Nothing to do? */
+ if (!CHIPC_QUIRK(sc, MUX_SPROM))
+ return (true);
+
+ parent = device_get_parent(sc->dev);
+ hostb = bhnd_find_hostb_device(parent);
+
+ if ((error = device_get_children(parent, &devs, &devcount)))
+ return (false);
+
+ /* Reject any active devices other than ChipCommon, or the
+ * host bridge (if any). */
+ result = true;
+ for (int i = 0; i < devcount; i++) {
+ if (devs[i] == hostb || devs[i] == sc->dev)
+ continue;
+
+ if (!device_is_attached(devs[i]))
+ continue;
+
+ if (device_is_suspended(devs[i]))
+ continue;
+
+ /* Active device; assume SPROM is busy */
+ result = false;
+ break;
+ }
+
+ free(devs, M_TEMP);
+ return (result);
+}
/**
* If required by this device, enable access to the SPROM.
@@ -345,16 +1262,34 @@
* @param sc chipc driver state.
*/
static int
-chipc_enable_sprom_pins(struct chipc_softc *sc)
+chipc_enable_sprom_pins(device_t dev)
{
- uint32_t cctrl;
-
- CHIPC_LOCK_ASSERT(sc, MA_OWNED);
+ struct chipc_softc *sc;
+ uint32_t cctrl;
+ int error;
+
+ sc = device_get_softc(dev);
/* Nothing to do? */
if (!CHIPC_QUIRK(sc, MUX_SPROM))
return (0);
+ /* Make sure we're holding Giant for newbus */
+ mtx_lock(&Giant);
+ CHIPC_LOCK(sc);
+
+ /* Already enabled? */
+ if (sc->sprom_refcnt >= 1) {
+ error = 0;
+ goto finished;
+ }
+
+ /* Check whether bus is busy */
+ if (!chipc_should_enable_sprom(sc)) {
+ error = EBUSY;
+ goto finished;
+ }
+
cctrl = bhnd_bus_read_4(sc->core, CHIPC_CHIPCTRL);
/* 4331 devices */
@@ -368,7 +1303,8 @@
cctrl &= ~CHIPC_CCTRL4331_EXTPA_EN2;
bhnd_bus_write_4(sc->core, CHIPC_CHIPCTRL, cctrl);
- return (0);
+ error = 0;
+ goto finished;
}
/* 4360 devices */
@@ -378,7 +1314,17 @@
/* Refuse to proceed on unsupported devices with muxed SPROM pins */
device_printf(sc->dev, "muxed sprom lines on unrecognized device\n");
- return (ENXIO);
+ error = ENXIO;
+
+finished:
+ /* Bump the reference count */
+ if (error == 0)
+ sc->sprom_refcnt++;
+
+ CHIPC_UNLOCK(sc);
+ mtx_unlock(&Giant);
+
+ return (error);
}
/**
@@ -387,16 +1333,25 @@
*
* @param sc chipc driver state.
*/
-static int
-chipc_disable_sprom_pins(struct chipc_softc *sc)
+static void
+chipc_disable_sprom_pins(device_t dev)
{
- uint32_t cctrl;
+ struct chipc_softc *sc;
+ uint32_t cctrl;
- CHIPC_LOCK_ASSERT(sc, MA_OWNED);
+ sc = device_get_softc(dev);
/* Nothing to do? */
if (!CHIPC_QUIRK(sc, MUX_SPROM))
- return (0);
+ return;
+
+ CHIPC_LOCK(sc);
+
+ /* Check reference count, skip disable if in-use. */
+ KASSERT(sc->sprom_refcnt > 0, ("sprom refcnt overrelease"));
+ sc->sprom_refcnt--;
+ if (sc->sprom_refcnt > 0)
+ goto finished;
cctrl = bhnd_bus_read_4(sc->core, CHIPC_CHIPCTRL);
@@ -411,17 +1366,16 @@
cctrl |= CHIPC_CCTRL4331_EXTPA_EN2;
bhnd_bus_write_4(sc->core, CHIPC_CHIPCTRL, cctrl);
- return (0);
+ goto finished;
}
/* 4360 devices */
if (CHIPC_QUIRK(sc, 4360_FEM_MUX_SPROM)) {
/* Unimplemented */
}
-
- /* Refuse to proceed on unsupported devices with muxed SPROM pins */
- device_printf(sc->dev, "muxed sprom lines on unrecognized device\n");
- return (ENXIO);
+
+finished:
+ CHIPC_UNLOCK(sc);
}
static bhnd_nvram_src_t
@@ -431,64 +1385,6 @@
return (sc->nvram_src);
}
-static int
-chipc_nvram_getvar(device_t dev, const char *name, void *buf, size_t *len)
-{
- struct chipc_softc *sc;
- int error;
-
- sc = device_get_softc(dev);
-
- switch (sc->nvram_src) {
- case BHND_NVRAM_SRC_SPROM:
- CHIPC_LOCK(sc);
- error = bhnd_sprom_getvar(&sc->sprom, name, buf, len);
- CHIPC_UNLOCK(sc);
- return (error);
-
- case BHND_NVRAM_SRC_OTP:
- case BHND_NVRAM_SRC_NFLASH:
- /* Currently unsupported */
- return (ENXIO);
-
- case BHND_NVRAM_SRC_UNKNOWN:
- return (ENODEV);
- }
-
- /* Unknown NVRAM source */
- return (ENODEV);
-}
-
-static int
-chipc_nvram_setvar(device_t dev, const char *name, const void *buf,
- size_t len)
-{
- struct chipc_softc *sc;
- int error;
-
- sc = device_get_softc(dev);
-
- switch (sc->nvram_src) {
- case BHND_NVRAM_SRC_SPROM:
- CHIPC_LOCK(sc);
- error = bhnd_sprom_setvar(&sc->sprom, name, buf, len);
- CHIPC_UNLOCK(sc);
- return (error);
-
- case BHND_NVRAM_SRC_OTP:
- case BHND_NVRAM_SRC_NFLASH:
- /* Currently unsupported */
- return (ENXIO);
-
- case BHND_NVRAM_SRC_UNKNOWN:
- default:
- return (ENODEV);
- }
-
- /* Unknown NVRAM source */
- return (ENODEV);
-}
-
static void
chipc_write_chipctrl(device_t dev, uint32_t value, uint32_t mask)
{
@@ -513,14 +1409,40 @@
DEVMETHOD(device_detach, chipc_detach),
DEVMETHOD(device_suspend, chipc_suspend),
DEVMETHOD(device_resume, chipc_resume),
-
+
+ /* Bus interface */
+ DEVMETHOD(bus_probe_nomatch, chipc_probe_nomatch),
+ DEVMETHOD(bus_print_child, chipc_print_child),
+ DEVMETHOD(bus_child_pnpinfo_str, chipc_child_pnpinfo_str),
+ DEVMETHOD(bus_child_location_str, chipc_child_location_str),
+
+ DEVMETHOD(bus_add_child, chipc_add_child),
+ DEVMETHOD(bus_child_deleted, chipc_child_deleted),
+
+ DEVMETHOD(bus_set_resource, bus_generic_rl_set_resource),
+ DEVMETHOD(bus_get_resource, bus_generic_rl_get_resource),
+ DEVMETHOD(bus_delete_resource, bus_generic_rl_delete_resource),
+ DEVMETHOD(bus_alloc_resource, chipc_alloc_resource),
+ DEVMETHOD(bus_release_resource, chipc_release_resource),
+ DEVMETHOD(bus_adjust_resource, chipc_adjust_resource),
+ DEVMETHOD(bus_activate_resource, chipc_activate_resource),
+ DEVMETHOD(bus_deactivate_resource, chipc_deactivate_resource),
+ DEVMETHOD(bus_get_resource_list, chipc_get_resource_list),
+
+ DEVMETHOD(bus_setup_intr, bus_generic_setup_intr),
+ DEVMETHOD(bus_teardown_intr, bus_generic_teardown_intr),
+ DEVMETHOD(bus_config_intr, bus_generic_config_intr),
+ DEVMETHOD(bus_bind_intr, bus_generic_bind_intr),
+ DEVMETHOD(bus_describe_intr, bus_generic_describe_intr),
+
+ /* BHND bus inteface */
+ DEVMETHOD(bhnd_bus_activate_resource, chipc_activate_bhnd_resource),
+
/* ChipCommon interface */
DEVMETHOD(bhnd_chipc_nvram_src, chipc_nvram_src),
DEVMETHOD(bhnd_chipc_write_chipctrl, chipc_write_chipctrl),
-
- /* NVRAM interface */
- DEVMETHOD(bhnd_nvram_getvar, chipc_nvram_getvar),
- DEVMETHOD(bhnd_nvram_setvar, chipc_nvram_setvar),
+ DEVMETHOD(bhnd_chipc_enable_sprom, chipc_enable_sprom_pins),
+ DEVMETHOD(bhnd_chipc_disable_sprom, chipc_disable_sprom_pins),
DEVMETHOD_END
};
Index: sys/dev/bhnd/cores/chipc/chipcreg.h
===================================================================
--- sys/dev/bhnd/cores/chipc/chipcreg.h
+++ sys/dev/bhnd/cores/chipc/chipcreg.h
@@ -1,5 +1,5 @@
/*-
- * Copyright (c) 2015 Landon Fuller <landon@landonf.org>
+ * Copyright (c) 2015-2016 Landon Fuller <landon@landonf.org>
* Copyright (c) 2010 Broadcom Corporation
* All rights reserved.
*
@@ -25,9 +25,11 @@
#ifndef _BHND_CORES_CHIPC_CHIPCREG_H_
#define _BHND_CORES_CHIPC_CHIPCREG_H_
-#define CHIPC_CHIPID_SIZE 0x100 /**< size of the register block
- containing the chip
- identification registers. */
+#define CHIPC_CHIPID_SIZE 0x100 /**< size of the register block
+ containing the chip
+ identification registers
+ required during bus
+ enumeration */
/** Evaluates to true if the given ChipCommon core revision provides
* the core count via the chip identification register. */
@@ -37,54 +39,173 @@
((_entry & CHIPC_ ## _attr ## _MASK) >> CHIPC_ ## _attr ## _SHIFT)
-#define CHIPC_ID 0x0
+#define CHIPC_ID 0x00
#define CHIPC_CAPABILITIES 0x04
-#define CHIPC_OTPST 0x10
-#define CHIPC_CHIPCTRL 0x28 /**< chip control */
-#define CHIPC_CHIPST 0x2c /**< chip status */
+#define CHIPC_CORECTRL 0x08 /* rev >= 1 */
+#define CHIPC_BIST 0x0C
+
+#define CHIPC_OTPST 0x10 /**< otp status */
+#define CHIPC_OTPCTRL 0x14 /**< otp control */
+#define CHIPC_OTPPROG 0x18
+#define CHIPC_OTPLAYOUT 0x1C /**< otp layout */
+
+#define CHIPC_INTST 0x20 /**< interrupt status */
+#define CHIPC_INTM 0x24 /**< interrupt mask */
+
+#define CHIPC_CHIPCTRL 0x28 /**< chip control (rev >= 11) */
+#define CHIPC_CHIPST 0x2C /**< chip status (rev >= 11) */
+
#define CHIPC_JTAGCMD 0x30
#define CHIPC_JTAGIR 0x34
#define CHIPC_JTAGDR 0x38
#define CHIPC_JTAGCTRL 0x3c
-#define CHIPC_GPIOPU 0x58
-#define CHIPC_GPIOPD 0x5c
+
+#define CHIPC_SFLASHCTRL 0x40
+#define CHIPC_SFLASHADDR 0x44
+#define CHIPC_SFLASHDATA 0x48
+
+/* siba backplane configuration broadcast (siba-only) */
+#define CHIPC_SBBCAST_ADDR 0x50
+#define CHIPC_SBBCAST_DATA 0x54
+
+#define CHIPC_GPIOPU 0x58 /**< pull-up mask (rev >= 20) */
+#define CHIPC_GPIOPD 0x5C /**< pull down mask (rev >= 20) */
#define CHIPC_GPIOIN 0x60
#define CHIPC_GPIOOUT 0x64
#define CHIPC_GPIOOUTEN 0x68
-#define CHIPC_GPIOCTRL 0x6c
+#define CHIPC_GPIOCTRL 0x6C
#define CHIPC_GPIOPOL 0x70
-#define CHIPC_GPIOINTM 0x74
-#define CHIPC_WATCHDOG 0x80
+#define CHIPC_GPIOINTM 0x74 /**< gpio interrupt mask */
+
+#define CHIPC_GPIOEVENT 0x78 /**< gpio event (rev >= 11) */
+#define CHIPC_GPIOEVENT_INTM 0x7C /**< gpio event interrupt mask (rev >= 11) */
+
+#define CHIPC_WATCHDOG 0x80 /**< watchdog timer */
+
+#define CHIPC_GPIOEVENT_INTPOLARITY 0x84 /**< gpio even interrupt polarity (rev >= 11) */
+
+#define CHIPC_GPIOTIMERVAL 0x88 /**< gpio-based LED duty cycle (rev >= 16) */
+#define CHIPC_GPIOTIMEROUTMASK 0x8C
+
+/* clock control block */
#define CHIPC_CLKC_N 0x90
-#define CHIPC_CLKC_M0 0x94
-#define CHIPC_CLKC_M1 0x98
-#define CHIPC_CLKC_M2 0x9c
-#define CHIPC_CLKC_M3 0xa0
-#define CHIPC_CLKDIV 0xa4
-#define CHIPC_SYS_CLK_CTL 0xc0
-#define CHIPC_EROMPTR 0xfc /**< 32-bit EROM base address
+#define CHIPC_CLKC_SB 0x94 /* m0 (backplane) */
+#define CHIPC_CLKC_PCI 0x98 /* m1 */
+#define CHIPC_CLKC_M2 0x9C /* mii/uart/mipsref */
+#define CHIPC_CLKC_M3 0xA0 /* cpu */
+#define CHIPC_CLKDIV 0xA4 /* rev >= 3 */
+#define CHIPC_GPIODEBUGSEL 0xA8 /* rev >= 28 */
+#define CHIPC_CAPABILITIES_EXT 0xAC
+
+/* pll delay (registers rev >= 4) */
+#define CHIPC_PLL_ON_DELAY 0xB0
+#define CHIPC_PLL_FREFSEL_DELAY 0xB4
+#define CHIPC_PLL_SLOWCLK_CTL 0xB8 /* revs 6-9 */
+
+/* "instaclock" registers */
+#define CHIPC_SYS_CLK_CTL 0xC0 /* rev >= 10 */
+#define CHIPC_SYS_CLKSTATESTRETCH 0xC4 /* rev >= 10 */
+
+/* indirect backplane access (rev >= 10) */
+#define CHIPC_BP_ADDRLOW 0xD0
+#define CHIPC_BP_ADDRHIGH 0xD4
+#define CHIPC_BP_DATA 0xD8
+#define CHIPC_BP_INDACCESS 0xE0
+
+/* SPI/I2C (rev >= 37) */
+#define CHIPC_GSIO_CTRL 0xE4
+#define CHIPC_GSIO_ADDR 0xE8
+#define CHIPC_GSIO_DATA 0xEC
+
+/* More clock dividers (corerev >= 32) */
+#define CHIPC_CLKDIV2 0xF0
+
+#define CHIPC_EROMPTR 0xFC /**< 32-bit EROM base address
* on BCMA devices */
+
+/* ExtBus control registers (rev >= 3) */
+#define CHIPC_PCMCIA_CFG 0x100
+#define CHIPC_PCMCIA_MEMWAIT 0x104
+#define CHIPC_PCMCIA_ATTRWAIT 0x108
+#define CHIPC_PCMCIA_IOWAIT 0x10C
+#define CHIPC_IDE_CFG 0x110
+#define CHIPC_IDE_MEMWAIT 0x114
+#define CHIPC_IDE_ATTRWAIT 0x118
+#define CHIPC_IDE_IOWAIT 0x11C
+#define CHIPC_PROG_CFG 0x120
+#define CHIPC_PROG_WAITCOUNT 0x124
+#define CHIPC_FLASH_CFG 0x128
+#define CHIPC_FLASH_WAITCOUNT 0x12C
+#define CHIPC_SECI_CFG 0x130
+#define CHIPC_SECI_ST 0x134
+#define CHIPC_SECI_STM 0x138
+#define CHIPC_SECI_RXNBC 0x13C
+
+/* Enhanced Coexistence Interface (ECI) registers (rev 21-34) */
+#define CHIPC_ECI_OUTPUT 0x140
+#define CHIPC_ECI_CTRL 0x144
+#define CHIPC_ECI_INPUTLO 0x148
+#define CHIPC_ECI_INPUTMI 0x14C
+#define CHIPC_ECI_INPUTHI 0x150
+#define CHIPC_ECI_INPUTINTPOLARITYLO 0x154
+#define CHIPC_ECI_INPUTINTPOLARITYMI 0x158
+#define CHIPC_ECI_INPUTINTPOLARITYHI 0x15C
+#define CHIPC_ECI_INTMASKLO 0x160
+#define CHIPC_ECI_INTMASKMI 0x164
+#define CHIPC_ECI_INTMASKHI 0x168
+#define CHIPC_ECI_EVENTLO 0x16C
+#define CHIPC_ECI_EVENTMI 0x170
+#define CHIPC_ECI_EVENTHI 0x174
+#define CHIPC_ECI_EVENTMASKLO 0x178
+#define CHIPC_ECI_EVENTMASKMI 0x17C
+#define CHIPC_ECI_EVENTMASKHI 0x180
+
+#define CHIPC_FLASHSTRCFG 0x18C /**< BCM4706 NAND flash config */
+
#define CHIPC_SPROM_CTRL 0x190 /**< SPROM interface (rev >= 32) */
#define CHIPC_SPROM_ADDR 0x194
#define CHIPC_SPROM_DATA 0x198
-#define CHIPC_CLK_CTL_ST SI_CLK_CTL_ST
-#define CHIPC_PMU_CTL 0x600
+
+/* Clock control and hardware workarounds (corerev >= 20) */
+#define CHIPC_CLK_CTL_ST 0x1E0
+#define CHIPC_SPROM_HWWAR 0x19
+
+#define CHIPC_UART0 0x300
+#define CHIPC_UART1 0x400
+
+/* PMU registers (rev >= 20) */
+#define CHIPC_PMU_CTRL 0x600
#define CHIPC_PMU_CAP 0x604
#define CHIPC_PMU_ST 0x608
#define CHIPC_PMU_RES_STATE 0x60c
+#define CHIPC_PMU_RES_PENDING 0x610
#define CHIPC_PMU_TIMER 0x614
#define CHIPC_PMU_MIN_RES_MASK 0x618
#define CHIPC_PMU_MAX_RES_MASK 0x61c
+#define CHIPC_PMU_RES_TABLE_SEL 0x620
+#define CHIPC_PMU_RES_DEP_MASK 0x624
+#define CHIPC_PMU_RES_UPDN_TIMER 0x628
+#define CHIPC_PMU_RES_TIMER 0x62C
+#define CHIPC_PMU_CLKSTRETCH 0x630
+#define CHIPC_PMU_WATCHDOG 0x634
+#define CHIPC_PMU_GPIOSEL 0x638 /* pmu rev >= 1 ? */
+#define CHIPC_PMU_GPIOEN 0x63C /* pmu rev >= 1 ? */
+#define CHIPC_PMU_RES_REQ_TIMER_SEL 0x640
+#define CHIPC_PMU_RES_REQ_TIMER 0x644
+#define CHIPC_PMU_RES_REQ_MASK 0x648
#define CHIPC_CHIPCTL_ADDR 0x650
#define CHIPC_CHIPCTL_DATA 0x654
#define CHIPC_PMU_REG_CONTROL_ADDR 0x658
#define CHIPC_PMU_REG_CONTROL_DATA 0x65C
#define CHIPC_PMU_PLL_CONTROL_ADDR 0x660
#define CHIPC_PMU_PLL_CONTROL_DATA 0x664
+#define CHIPC_PMU_STRAPOPT 0x668 /* chipc rev >= 28 */
+#define CHIPC_PMU_XTALFREQ 0x66C /* pmu rev >= 10 */
+
#define CHIPC_SPROM_OTP 0x800 /* SPROM/OTP address space */
+#define CHIPC_SPROM_OTP_SIZE 0x400
/** chipid */
-#define CHIPC_ID 0x0 /**< identification register */
#define CHIPC_ID_CHIP_MASK 0x0000FFFF /**< chip id */
#define CHIPC_ID_CHIP_SHIFT 0
#define CHIPC_ID_REV_MASK 0x000F0000 /**< chip revision */
Index: sys/dev/bhnd/cores/chipc/chipcvar.h
===================================================================
--- sys/dev/bhnd/cores/chipc/chipcvar.h
+++ sys/dev/bhnd/cores/chipc/chipcvar.h
@@ -39,9 +39,6 @@
DECLARE_CLASS(bhnd_chipc);
extern devclass_t bhnd_chipc_devclass;
-#define CHIPC_MAX_RES 1
-#define CHIPC_MAX_RSPEC (CHIPC_MAX_RES+1)
-
/*
* ChipCommon device quirks / features
*/
@@ -107,13 +104,44 @@
CHIPC_QUIRK_4360_FEM_MUX_SPROM = (1<<5) | CHIPC_QUIRK_MUX_SPROM
};
+/**
+ * chipc child device info.
+ */
+struct chipc_devinfo {
+ struct resource_list resources; /**< child resources */
+};
+
+/**
+ * chipc SYS_RES_MEMORY region allocation record.
+ */
+struct chipc_region {
+ bhnd_port_type cr_port_type; /**< bhnd port type */
+ u_int cr_port_num; /**< bhnd port number */
+ u_int cr_region_num; /**< bhnd region number */
+
+ bhnd_addr_t cr_addr; /**< region base address */
+ bhnd_addr_t cr_end; /**< region end address */
+ bhnd_size_t cr_count; /**< region count */
+ int cr_rid; /**< rid, or -1 if no rid
+ * is allocated by the bus for
+ * this region */
+
+ struct bhnd_resource *cr_res; /**< bus resource, or NULL */
+ u_int cr_refs; /**< RF_ALLOCATED refcount */
+ u_int cr_act_refs; /**< RF_ACTIVE refcount */
+
+ STAILQ_ENTRY(chipc_region) cr_link;
+};
+
+/**
+ * chipc driver instance state.
+ */
struct chipc_softc {
device_t dev;
- struct resource_spec rspec[CHIPC_MAX_RSPEC];
- struct bhnd_resource *res[CHIPC_MAX_RES];
-
struct bhnd_resource *core; /**< core registers. */
+ struct chipc_region *core_region; /**< region containing core registers */
+
struct bhnd_chipid ccid; /**< chip identification */
uint32_t quirks; /**< CHIPC_QUIRK_* quirk flags */
uint32_t caps; /**< CHIPC_CAP_* capability register flags */
@@ -123,6 +151,11 @@
struct mtx mtx; /**< state mutex. */
struct bhnd_sprom sprom; /**< OTP/SPROM shadow, if any */
+ size_t sprom_refcnt; /**< SPROM hardware refcount */
+
+ struct rman mem_rman; /**< port memory manager */
+
+ STAILQ_HEAD(, chipc_region) mem_regions;/**< memory allocation records */
};
#define CHIPC_LOCK_INIT(sc) \
@@ -133,4 +166,4 @@
#define CHIPC_LOCK_ASSERT(sc, what) mtx_assert(&(sc)->mtx, what)
#define CHIPC_LOCK_DESTROY(sc) mtx_destroy(&(sc)->mtx)
-#endif /* _BHND_CORES_CHIPC_CHIPCVAR_H_ */
\ No newline at end of file
+#endif /* _BHND_CORES_CHIPC_CHIPCVAR_H_ */
Index: sys/dev/bhnd/nvram/bhnd_sprom.c
===================================================================
--- sys/dev/bhnd/nvram/bhnd_sprom.c
+++ sys/dev/bhnd/nvram/bhnd_sprom.c
@@ -1,5 +1,5 @@
/*-
- * Copyright (c) 2015 Landon Fuller <landon@landonf.org>
+ * Copyright (c) 2015-2016 Landon Fuller <landon@landonf.org>
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
@@ -30,539 +30,180 @@
#include <sys/cdefs.h>
__FBSDID("$FreeBSD$");
+/*
+ * BHND SPROM driver.
+ *
+ * Abstract driver for memory-mapped SPROM devices.
+ */
+
#include <sys/param.h>
+#include <sys/kernel.h>
#include <sys/bus.h>
-#include <sys/endian.h>
-#include <sys/rman.h>
+#include <sys/limits.h>
+#include <sys/malloc.h>
+#include <sys/module.h>
#include <sys/systm.h>
#include <machine/bus.h>
+#include <sys/rman.h>
#include <machine/resource.h>
-#include <dev/bhnd/bhndvar.h>
+#include <dev/bhnd/bhnd.h>
-#include "nvramvar.h"
+#include "bhnd_nvram_if.h"
-#include "bhnd_spromreg.h"
#include "bhnd_spromvar.h"
-/*
- * BHND SPROM Parsing
- *
- * Provides identification and parsing of BHND SPROM data.
- */
-
-static int sprom_direct_read(struct bhnd_sprom *sc, size_t offset,
- void *buf, size_t nbytes, uint8_t *crc);
-static int sprom_extend_shadow(struct bhnd_sprom *sc, size_t image_size,
- uint8_t *crc);
-static int sprom_populate_shadow(struct bhnd_sprom *sc);
-
-static int sprom_var_defn(struct bhnd_sprom *sc, const char *name,
- const struct bhnd_nvram_var **var,
- const struct bhnd_sprom_var **sprom, size_t *size);
-
-/* SPROM revision is always located at the second-to-last byte */
-#define SPROM_REV(_sc) SPROM_READ_1((_sc), (_sc)->sp_size - 2)
-
-/* SPROM CRC is always located at the last byte */
-#define SPROM_CRC_OFF(_sc) SPROM_CRC_LEN(_sc)
-
-/* SPROM CRC covers all but the final CRC byte */
-#define SPROM_CRC_LEN(_sc) ((_sc)->sp_size - 1)
-
-/* SPROM shadow I/O (with byte-order translation) */
-#define SPROM_READ_1(_sc, _off) SPROM_READ_ENC_1(_sc, _off)
-#define SPROM_READ_2(_sc, _off) le16toh(SPROM_READ_ENC_2(_sc, _off))
-#define SPROM_READ_4(_sc, _off) le32toh(SPROM_READ_ENC_4(_sc, _off))
-
-#define SPROM_WRITE_1(_sc, _off, _v) SPROM_WRITE_ENC_1(_sc, _off, (_v))
-#define SPROM_WRITE_2(_sc, _off, _v) SPROM_WRITE_ENC_2(_sc, _off, \
- htole16(_v))
-#define SPROM_WRITE_4(_sc, _off, _v) SPROM_WRITE_ENC_4(_sc, _off, \
- htole32(_v))
-
-/* SPROM shadow I/O (without byte-order translation) */
-#define SPROM_READ_ENC_1(_sc, _off) (*(uint8_t *)((_sc)->sp_shadow + _off))
-#define SPROM_READ_ENC_2(_sc, _off) (*(uint16_t *)((_sc)->sp_shadow + _off))
-#define SPROM_READ_ENC_4(_sc, _off) (*(uint32_t *)((_sc)->sp_shadow + _off))
-
-#define SPROM_WRITE_ENC_1(_sc, _off, _v) \
- *((uint8_t *)((_sc)->sp_shadow + _off)) = (_v)
-#define SPROM_WRITE_ENC_2(_sc, _off, _v) \
- *((uint16_t *)((_sc)->sp_shadow + _off)) = (_v)
-#define SPROM_WRITE_ENC_4(_sc, _off, _v) \
- *((uint32_t *)((_sc)->sp_shadow + _off)) = (_v)
-
-/* Call @p _next macro with the C type, widened (signed or unsigned) C
- * type, and width associated with @p _dtype */
-#define SPROM_SWITCH_TYPE(_dtype, _next, ...) \
-do { \
- switch (_dtype) { \
- case BHND_NVRAM_DT_UINT8: \
- _next (uint8_t, uint32_t, 1, \
- ## __VA_ARGS__); \
- break; \
- case BHND_NVRAM_DT_UINT16: \
- _next (uint16_t, uint32_t, 2, \
- ## __VA_ARGS__); \
- break; \
- case BHND_NVRAM_DT_UINT32: \
- _next (uint32_t, uint32_t, 4, \
- ## __VA_ARGS__); \
- break; \
- case BHND_NVRAM_DT_INT8: \
- _next (int8_t, int32_t, 1, \
- ## __VA_ARGS__); \
- break; \
- case BHND_NVRAM_DT_INT16: \
- _next (int16_t, int32_t, 2, \
- ## __VA_ARGS__); \
- break; \
- case BHND_NVRAM_DT_INT32: \
- _next (int32_t, int32_t, 4, \
- ## __VA_ARGS__); \
- break; \
- case BHND_NVRAM_DT_CHAR: \
- _next (uint8_t, uint32_t, 1, \
- ## __VA_ARGS__); \
- break; \
- } \
-} while (0)
-
-/*
- * Table of supported SPROM image formats, sorted by image size, ascending.
- */
-#define SPROM_FMT(_sz, _revmin, _revmax, _sig) \
- { SPROM_SZ_ ## _sz, _revmin, _revmax, \
- SPROM_SIG_ ## _sig ## _OFF, \
- SPROM_SIG_ ## _sig }
-
-static const struct sprom_fmt {
- size_t size;
- uint8_t rev_min;
- uint8_t rev_max;
- size_t sig_offset;
- uint16_t sig_req;
-} sprom_fmts[] = {
- SPROM_FMT(R1_3, 1, 3, NONE),
- SPROM_FMT(R4_8_9, 4, 4, R4),
- SPROM_FMT(R4_8_9, 8, 9, R8_9),
- SPROM_FMT(R10, 10, 10, R10),
- SPROM_FMT(R11, 11, 11, R11)
-};
+#define SPROM_LOCK_INIT(sc) \
+ mtx_init(&(sc)->mtx, device_get_nameunit((sc)->dev), \
+ "BHND 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)
/**
- * Identify the SPROM format at @p offset within @p r, verify the CRC,
- * and allocate a local shadow copy of the SPROM data.
- *
- * After successful initialization, @p r will not be accessed; any pin
- * configuration required for SPROM access may be reset.
- *
- * @param[out] sprom On success, will be initialized with shadow of the SPROM
- * data.
- * @param r An active resource mapping the SPROM data.
- * @param offset Offset of the SPROM data within @p resource.
+ * Default bhnd sprom driver implementation of DEVICE_PROBE().
*/
int
-bhnd_sprom_init(struct bhnd_sprom *sprom, struct bhnd_resource *r,
- bus_size_t offset)
+bhnd_sprom_probe(device_t dev)
{
- bus_size_t res_size;
- int error;
-
- sprom->dev = rman_get_device(r->res);
- sprom->sp_res = r;
- sprom->sp_res_off = offset;
-
- /* Determine maximum possible SPROM image size */
- res_size = rman_get_size(r->res);
- if (offset >= res_size)
- return (EINVAL);
+ /* Quiet by default */
+ if (!bootverbose)
+ device_quiet(dev);
+ device_set_desc(dev, "Broadcom SPROM/OTP");
- sprom->sp_size_max = MIN(res_size - offset, SPROM_SZ_MAX);
-
- /* Allocate and populate SPROM shadow */
- sprom->sp_size = 0;
- sprom->sp_capacity = sprom->sp_size_max;
- sprom->sp_shadow = malloc(sprom->sp_capacity, M_BHND, M_NOWAIT);
- if (sprom->sp_shadow == NULL)
- return (ENOMEM);
-
- /* Read and identify SPROM image */
- if ((error = sprom_populate_shadow(sprom)))
- return (error);
-
- return (0);
+ /* Refuse wildcard attachments */
+ return (BUS_PROBE_NOWILDCARD);
}
/**
- * Release all resources held by @p sprom.
+ * Default bhnd sprom driver implementation of DEVICE_ATTACH().
*
- * @param sprom A SPROM instance previously initialized via bhnd_sprom_init().
- */
-void
-bhnd_sprom_fini(struct bhnd_sprom *sprom)
-{
- free(sprom->sp_shadow, M_BHND);
-}
-
-/* Perform a read using a SPROM offset descriptor, safely widening the
- * result to its 32-bit representation before assigning it to @p _dest. */
-#define SPROM_GETVAR_READ(_type, _widen, _width, _sc, _off, _dest) \
-do { \
- _type _v = (_type)SPROM_READ_ ## _width(_sc, _off->offset); \
- if (_off->shift > 0) { \
- _v >>= _off->shift; \
- } else if (off->shift < 0) { \
- _v <<= -_off->shift; \
- } \
- _dest = ((uint32_t) (_widen) _v) & _off->mask; \
-} while(0)
-
-/* Emit a value read using a SPROM offset descriptor, narrowing the
- * result output representation and, if necessary, OR'ing it with the
- * previously read value from @p _buf. */
-#define SPROM_GETVAR_WRITE(_type, _widen, _width, _off, _src, _buf) \
-do { \
- _type _v = (_type) (_widen) _src; \
- if (_off->cont) \
- _v |= *((_type *)_buf); \
- *((_type *)_buf) = _v; \
-} while(0)
-
-/**
- * Read a SPROM variable, performing conversion to host byte order.
- *
- * @param sc The SPROM parser state.
- * @param name The SPROM variable name.
- * @param[out] buf On success, the requested value will be written
- * to this buffer. This argment may be NULL if
- * the value is not desired.
- * @param[in,out] len The capacity of @p buf. On success, will be set
- * to the actual size of the requested value.
- *
- * @retval 0 success
- * @retval ENOENT The requested variable was not found.
- * @retval ENOMEM If @p buf is non-NULL and a buffer of @p len is too
- * small to hold the requested value.
- * @retval non-zero If reading @p name otherwise fails, a regular unix
- * error code will be returned.
+ * Assumes sprom is mapped via YS_RES_MEMORY resource with RID 0.
*/
int
-bhnd_sprom_getvar(struct bhnd_sprom *sc, const char *name, void *buf,
- size_t *len)
+bhnd_sprom_attach(device_t dev)
{
- const struct bhnd_nvram_var *nv;
- const struct bhnd_sprom_var *sv;
- size_t all1_offs;
- size_t req_size;
+ struct bhnd_sprom_softc *sc;
int error;
-
- if ((error = sprom_var_defn(sc, name, &nv, &sv, &req_size)))
- return (error);
-
- /* Provide required size */
- if (buf == NULL) {
- *len = req_size;
- return (0);
+
+ 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);
}
- /* Check (and update) target buffer len */
- if (*len < req_size)
- return (ENOMEM);
- else
- *len = req_size;
-
- /* Read data */
- all1_offs = 0;
- for (size_t i = 0; i < sv->num_offsets; i++) {
- const struct bhnd_sprom_offset *off;
- uint32_t val;
-
- off = &sv->offsets[i];
- KASSERT(!off->cont || i > 0, ("cont marked on first offset"));
-
- /* If not a continuation, advance the output buffer */
- if (i > 0 && !off->cont) {
- buf = ((uint8_t *)buf) +
- bhnd_nvram_type_width(sv->offsets[i-1].type);
- }
-
- /* Read the value, widening to a common uint32
- * representation */
- SPROM_SWITCH_TYPE(off->type, SPROM_GETVAR_READ, sc, off, val);
-
- /* If IGNALL1, record whether value has all bits set. */
- if (nv->flags & BHND_NVRAM_VF_IGNALL1) {
- uint32_t all1;
-
- all1 = off->mask;
- if (off->shift > 0)
- all1 >>= off->shift;
- else if (off->shift < 0)
- all1 <<= -off->shift;
-
- if ((val & all1) == all1)
- all1_offs++;
- }
-
- /* Write the value, narrowing to the appropriate output
- * width. */
- SPROM_SWITCH_TYPE(nv->type, SPROM_GETVAR_WRITE, off, val, buf);
+ /* Initialize SPROM shadow */
+ if ((error = bhnd_sprom_init(&sc->shadow, sc->sprom_res, 0))) {
+ device_printf(dev, "unrecognized SPROM format\n");
+ goto failed;
}
- /* Should value should be treated as uninitialized? */
- if (nv->flags & BHND_NVRAM_VF_IGNALL1 && all1_offs == sv->num_offsets)
- return (ENOENT);
+ /* Initialize mutex */
+ SPROM_LOCK_INIT(sc);
return (0);
+
+failed:
+ bhnd_release_resource(dev, SYS_RES_MEMORY, sc->sprom_rid,
+ sc->sprom_res);
+ return (error);
}
-/* Perform a read of a variable offset from _src, safely widening the result
- * to its 32-bit representation before assigning it to @p
- * _dest. */
-#define SPROM_SETVAR_READ(_type, _widen, _width, _off, _src, _dest) \
-do { \
- _type _v = *(const _type *)_src; \
- if (_off->shift > 0) { \
- _v <<= _off->shift; \
- } else if (off->shift < 0) { \
- _v >>= -_off->shift; \
- } \
- _dest = ((uint32_t) (_widen) _v) & _off->mask; \
-} while(0)
-
-
-/* Emit a value read using a SPROM offset descriptor, narrowing the
- * result output representation and, if necessary, OR'ing it with the
- * previously read value from @p _buf. */
-#define SPROM_SETVAR_WRITE(_type, _widen, _width, _sc, _off, _src) \
-do { \
- _type _v = (_type) (_widen) _src; \
- if (_off->cont) \
- _v |= SPROM_READ_ ## _width(_sc, _off->offset); \
- SPROM_WRITE_ ## _width(_sc, _off->offset, _v); \
-} while(0)
-
/**
- * Set a local value for a SPROM variable, performing conversion to SPROM byte
- * order.
- *
- * The new value will be written to the backing SPROM shadow.
- *
- * @param sc The SPROM parser state.
- * @param name The SPROM variable name.
- * @param[out] buf The new value.
- * @param[in,out] len The size of @p buf.
- *
- * @retval 0 success
- * @retval ENOENT The requested variable was not found.
- * @retval EINVAL If @p len does not match the expected variable size.
+ * Default bhnd sprom driver implementation of DEVICE_DETACH().
*/
int
-bhnd_sprom_setvar(struct bhnd_sprom *sc, const char *name, const void *buf,
- size_t len)
+bhnd_sprom_resume(device_t dev)
{
- const struct bhnd_nvram_var *nv;
- const struct bhnd_sprom_var *sv;
- size_t req_size;
- int error;
- uint8_t crc;
-
- if ((error = sprom_var_defn(sc, name, &nv, &sv, &req_size)))
- return (error);
-
- /* Provide required size */
- if (len != req_size)
- return (EINVAL);
-
- /* Write data */
- for (size_t i = 0; i < sv->num_offsets; i++) {
- const struct bhnd_sprom_offset *off;
- uint32_t val;
-
- off = &sv->offsets[i];
- KASSERT(!off->cont || i > 0, ("cont marked on first offset"));
-
- /* If not a continuation, advance the input pointer */
- if (i > 0 && !off->cont) {
- buf = ((const uint8_t *)buf) +
- bhnd_nvram_type_width(sv->offsets[i-1].type);
- }
-
- /* Read the value, widening to a common uint32
- * representation */
- SPROM_SWITCH_TYPE(nv->type, SPROM_SETVAR_READ, off, buf, val);
-
- /* Write the value, narrowing to the appropriate output
- * width. */
- SPROM_SWITCH_TYPE(off->type, SPROM_SETVAR_WRITE, sc, off, val);
- }
-
- /* Update CRC */
- crc = ~bhnd_nvram_crc8(sc->sp_shadow, SPROM_CRC_LEN(sc),
- BHND_NVRAM_CRC8_INITIAL);
- SPROM_WRITE_1(sc, SPROM_CRC_OFF(sc), crc);
-
return (0);
}
-/* Read and identify the SPROM image by incrementally performing
- * read + CRC of all supported image formats */
-static int
-sprom_populate_shadow(struct bhnd_sprom *sc)
+/**
+ * Default bhnd sprom driver implementation of DEVICE_DETACH().
+ */
+int
+bhnd_sprom_suspend(device_t dev)
{
- const struct sprom_fmt *fmt;
- int error;
- uint16_t sig;
- uint8_t srom_rev;
- uint8_t crc;
-
- crc = BHND_NVRAM_CRC8_INITIAL;
-
- /* Identify the SPROM revision (and populate the SPROM shadow) */
- for (size_t i = 0; i < nitems(sprom_fmts); i++) {
- fmt = &sprom_fmts[i];
-
- /* Read image data and check CRC */
- if ((error = sprom_extend_shadow(sc, fmt->size, &crc)))
- return (error);
-
- /* Skip on invalid CRC */
- if (crc != BHND_NVRAM_CRC8_VALID)
- continue;
-
- /* Fetch SROM revision */
- srom_rev = SPROM_REV(sc);
-
- /* Early sromrev 1 devices (specifically some BCM440x enet
- * cards) are reported to have been incorrectly programmed
- * with a revision of 0x10. */
- if (fmt->size == SPROM_SZ_R1_3 && srom_rev == 0x10)
- srom_rev = 0x1;
-
- /* Verify revision range */
- if (srom_rev < fmt->rev_min || srom_rev > fmt->rev_max)
- continue;
-
- /* Verify signature (if any) */
- sig = SPROM_SIG_NONE;
- if (fmt->sig_offset != SPROM_SIG_NONE_OFF)
- sig = SPROM_READ_2(sc, fmt->sig_offset);
-
- if (sig != fmt->sig_req) {
- device_printf(sc->dev,
- "invalid sprom %hhu signature: 0x%hx "
- "(expected 0x%hx)\n",
- srom_rev, sig, fmt->sig_req);
- return (EINVAL);
- }
-
- /* Identified */
- sc->sp_rev = srom_rev;
- return (0);
- }
-
- /* identification failed */
- device_printf(sc->dev, "unrecognized sprom format\n");
- return (EINVAL);
+ return (0);
}
-/*
- * Extend the shadowed SPROM buffer to image_size, reading any required
- * data from the backing SPROM resource and updating the CRC.
+/**
+ * Default bhnd sprom driver implementation of DEVICE_DETACH().
*/
-static int
-sprom_extend_shadow(struct bhnd_sprom *sc, size_t image_size,
- uint8_t *crc)
+int
+bhnd_sprom_detach(device_t dev)
{
- int error;
-
- KASSERT(image_size >= sc->sp_size, (("shadow truncation unsupported")));
-
- /* Verify the request fits within our shadow buffer */
- if (image_size > sc->sp_capacity)
- return (ENOSPC);
-
- /* Skip no-op requests */
- if (sc->sp_size == image_size)
- return (0);
+ struct bhnd_sprom_softc *sc;
+
+ sc = device_get_softc(dev);
- /* Populate the extended range */
- error = sprom_direct_read(sc, sc->sp_size, sc->sp_shadow + sc->sp_size,
- image_size - sc->sp_size, crc);
- if (error)
- return (error);
+ bhnd_release_resource(dev, SYS_RES_MEMORY, sc->sprom_rid,
+ sc->sprom_res);
+ bhnd_sprom_fini(&sc->shadow);
+ SPROM_LOCK_DESTROY(sc);
- sc->sp_size = image_size;
return (0);
}
/**
- * Read nbytes at the given offset from the backing SPROM resource, and
- * update the CRC.
+ * Default bhnd sprom driver implementation of BHND_NVRAM_GETVAR().
*/
static int
-sprom_direct_read(struct bhnd_sprom *sc, size_t offset, void *buf,
- size_t nbytes, uint8_t *crc)
+bhnd_sprom_getvar_meth(device_t dev, const char *name, void *buf, size_t *len)
{
- bus_size_t res_offset;
- uint16_t *p;
-
- KASSERT(nbytes % sizeof(uint16_t) == 0, ("unaligned sprom size"));
- KASSERT(offset % sizeof(uint16_t) == 0, ("unaligned sprom offset"));
-
- /* Check for read overrun */
- if (offset >= sc->sp_size_max || sc->sp_size_max - offset < nbytes) {
- device_printf(sc->dev, "requested SPROM read would overrun\n");
- return (EINVAL);
- }
+ struct bhnd_sprom_softc *sc;
+ int error;
- /* Perform read and update CRC */
- p = (uint16_t *)buf;
- res_offset = sc->sp_res_off + offset;
+ sc = device_get_softc(dev);
- bhnd_bus_read_region_stream_2(sc->sp_res, res_offset, p, nbytes);
- *crc = bhnd_nvram_crc8(p, nbytes, *crc);
+ SPROM_LOCK(sc);
+ error = bhnd_sprom_getvar(&sc->shadow, name, buf, len);
+ SPROM_UNLOCK(sc);
- return (0);
+ return (error);
}
-
/**
- * Locate the variable and SPROM revision-specific definitions
- * for variable with @p name.
+ * Default bhnd sprom driver implementation of BHND_NVRAM_SETVAR().
*/
static int
-sprom_var_defn(struct bhnd_sprom *sc, const char *name,
- const struct bhnd_nvram_var **var,
- const struct bhnd_sprom_var **sprom,
- size_t *size)
+bhnd_sprom_setvar_meth(device_t dev, const char *name, const void *buf,
+ size_t len)
{
- /* Find variable definition */
- *var = bhnd_nvram_var_defn(name);
- if (*var == NULL)
- return (ENOENT);
-
- /* Find revision-specific SPROM definition */
- for (size_t i = 0; i < (*var)->num_sp_descs; i++) {
- const struct bhnd_sprom_var *sp = &(*var)->sprom_descs[i];
-
- if (sc->sp_rev < sp->compat.first)
- continue;
-
- if (sc->sp_rev > sp->compat.last)
- continue;
-
- /* Found */
- *sprom = sp;
-
- /* Calculate size in bytes */
- *size = bhnd_nvram_type_width((*var)->type) * sp->num_offsets;
- return (0);
- }
+ struct bhnd_sprom_softc *sc;
+ int error;
+
+ sc = device_get_softc(dev);
- /* Not supported by this SPROM revision */
- return (ENOENT);
+ SPROM_LOCK(sc);
+ error = bhnd_sprom_setvar(&sc->shadow, name, buf, len);
+ SPROM_UNLOCK(sc);
+
+ return (error);
}
+
+static device_method_t bhnd_sprom_methods[] = {
+ /* Device interface */
+ DEVMETHOD(device_probe, bhnd_sprom_probe),
+ DEVMETHOD(device_attach, bhnd_sprom_attach),
+ DEVMETHOD(device_resume, bhnd_sprom_resume),
+ DEVMETHOD(device_suspend, bhnd_sprom_suspend),
+ DEVMETHOD(device_detach, bhnd_sprom_detach),
+
+ /* NVRAM interface */
+ DEVMETHOD(bhnd_nvram_getvar, bhnd_sprom_getvar_meth),
+ DEVMETHOD(bhnd_nvram_setvar, bhnd_sprom_setvar_meth),
+
+ DEVMETHOD_END
+};
+
+DEFINE_CLASS_0(bhnd_nvram, bhnd_sprom_driver, bhnd_sprom_methods, sizeof(struct bhnd_sprom_softc));
+MODULE_VERSION(bhnd_sprom, 1);
Index: sys/dev/bhnd/nvram/bhnd_sprom_subr.c
===================================================================
--- sys/dev/bhnd/nvram/bhnd_sprom_subr.c
+++ sys/dev/bhnd/nvram/bhnd_sprom_subr.c
@@ -47,9 +47,9 @@
#include "bhnd_spromvar.h"
/*
- * BHND SPROM Parsing
+ * BHND SPROM Parser
*
- * Provides identification and parsing of BHND SPROM data.
+ * Provides identification, decoding, and encoding of BHND SPROM data.
*/
static int sprom_direct_read(struct bhnd_sprom *sc, size_t offset,
Index: sys/dev/bhnd/nvram/bhnd_spromvar.h
===================================================================
--- sys/dev/bhnd/nvram/bhnd_spromvar.h
+++ sys/dev/bhnd/nvram/bhnd_spromvar.h
@@ -29,9 +29,31 @@
* $FreeBSD$
*/
-#ifndef _BHND_NVRAM_BHND_SPROM_H_
-#define _BHND_NVRAM_BHND_SPROM_H_
+#ifndef _BHND_NVRAM_BHND_SPROMVAR_H_
+#define _BHND_NVRAM_BHND_SPROMVAR_H_
+#include <dev/bhnd/bhnd.h>
+
+DECLARE_CLASS(bhnd_sprom_driver);
+struct bhnd_sprom;
+
+int bhnd_sprom_probe(device_t dev);
+int bhnd_sprom_attach(device_t dev);
+int bhnd_sprom_resume(device_t dev);
+int bhnd_sprom_suspend(device_t dev);
+int bhnd_sprom_detach(device_t dev);
+
+int bhnd_sprom_init(struct bhnd_sprom *sprom, struct bhnd_resource *r,
+ bus_size_t offset);
+void bhnd_sprom_fini(struct bhnd_sprom *sprom);
+int bhnd_sprom_getvar(struct bhnd_sprom *sc, const char *name, void *buf,
+ size_t *len);
+int bhnd_sprom_setvar(struct bhnd_sprom *sc, const char *name,
+ const void *buf, size_t len);
+
+/**
+ * bhnd sprom parser instance state.
+ */
struct bhnd_sprom {
device_t dev; /**< sprom parent device */
@@ -46,13 +68,17 @@
size_t sp_capacity; /**< shadow buffer capacity */
};
-int bhnd_sprom_init(struct bhnd_sprom *sprom, struct bhnd_resource *r,
- bus_size_t offset);
-void bhnd_sprom_fini(struct bhnd_sprom *sprom);
-int bhnd_sprom_getvar(struct bhnd_sprom *sc, const char *name, void *buf,
- size_t *len);
-int bhnd_sprom_setvar(struct bhnd_sprom *sc, const char *name,
- const void *buf, size_t len);
+/**
+ * bhnd_sprom driver instance state. Must be first member of all subclass
+ * softc structures.
+ */
+struct bhnd_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 */
+};
-#endif /* _BHND_NVRAM_BHND_SPROM_H_ */
+#endif /* _BHND_NVRAM_BHND_SPROMVAR_H_ */
Index: sys/dev/bhnd/siba/siba.c
===================================================================
--- sys/dev/bhnd/siba/siba.c
+++ sys/dev/bhnd/siba/siba.c
@@ -409,7 +409,7 @@
continue;
*addr = addrspace->sa_base;
- *size = addrspace->sa_size;
+ *size = addrspace->sa_size - addrspace->sa_bus_reserved;
return (0);
}
Index: sys/dev/bhnd/siba/siba_subr.c
===================================================================
--- sys/dev/bhnd/siba/siba_subr.c
+++ sys/dev/bhnd/siba/siba_subr.c
@@ -243,11 +243,16 @@
{
struct siba_addrspace *sa;
struct siba_port *port;
+ rman_res_t r_size;
/* Verify that base + size will not overflow */
if (UINT32_MAX - size < base)
return (ERANGE);
+ /* Verify that size - bus_reserved will not underflow */
+ if (size < bus_reserved)
+ return (ERANGE);
+
/* Must not be 0-length */
if (size == 0)
return (EINVAL);
@@ -266,11 +271,12 @@
sa->sa_size = size;
sa->sa_sid = sid;
sa->sa_region_num = region_num;
-
+ sa->sa_bus_reserved = bus_reserved;
+
/* Populate the resource list */
- size -= bus_reserved;
+ r_size = size - bus_reserved;
sa->sa_rid = resource_list_add_next(&dinfo->resources, SYS_RES_MEMORY,
- base, base + size - 1, size);
+ base, base + r_size - 1, r_size);
/* Append to target port */
STAILQ_INSERT_TAIL(&port->sp_addrs, sa, sa_link);
Index: sys/dev/bhnd/siba/sibavar.h
===================================================================
--- sys/dev/bhnd/siba/sibavar.h
+++ sys/dev/bhnd/siba/sibavar.h
@@ -97,6 +97,8 @@
u_int sa_region_num; /**< bhnd region id */
uint8_t sa_sid; /**< siba-assigned address space ID */
int sa_rid; /**< bus resource id */
+ uint32_t sa_bus_reserved;/**< number of bytes at high end of
+ * address space reserved for the bus */
STAILQ_ENTRY(siba_addrspace) sa_link;
};
Index: sys/modules/bhnd/Makefile
===================================================================
--- sys/modules/bhnd/Makefile
+++ sys/modules/bhnd/Makefile
@@ -5,7 +5,8 @@
KMOD= bhnd
SRCS= bhnd.c bhnd_subr.c \
- bhnd_sprom.c nvram_subr.c \
+ bhnd_sprom.c bhnd_sprom_subr.c \
+ nvram_subr.c \
bhnd_nvram_map.h bhnd_nvram_map_data.h
SRCS+= bhnd_bus_if.c bhnd_bus_if.h \
Index: sys/modules/bhnd/cores/bhnd_chipc/Makefile
===================================================================
--- sys/modules/bhnd/cores/bhnd_chipc/Makefile
+++ sys/modules/bhnd/cores/bhnd_chipc/Makefile
@@ -3,7 +3,8 @@
.PATH: ${.CURDIR}/../../../../dev/bhnd/cores/chipc
KMOD= bhnd_chipc
-SRCS= chipc.c
+SRCS= chipc.c \
+ bhnd_sprom_chipc.c
SRCS+= device_if.h bus_if.h bhnd_bus_if.h \
bhnd_chipc_if.h bhnd_nvram_if.h
File Metadata
Details
Attached
Mime Type
text/plain
Expires
Sun, Sep 13, 11:24 PM (6 h, 43 m)
Storage Engine
blob
Storage Format
Raw Data
Storage Handle
29604257
Default Alt Text
D6471.1789341885.diff (78 KB)
Attached To
Mode
D6471: Implement pass-through resource management for ChipCommon
Attached
Detach File
Event Timeline
Log In to Comment