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 #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/bhndb/bhndb_subr.c =================================================================== --- sys/dev/bhnd/bhndb/bhndb_subr.c +++ sys/dev/bhnd/bhndb/bhndb_subr.c @@ -263,6 +263,7 @@ struct bhndb_resources *r; const struct bhndb_regwin *win; bus_size_t last_window_size; + char *rdescr; size_t res_num; u_int rnid; int error; @@ -283,12 +284,24 @@ r->cfg = cfg; r->min_prio = BHNDB_PRIORITY_NONE; STAILQ_INIT(&r->bus_regions); - + + /* Initialize rman descriptions */ + r->ht_mem_rman.rm_descr = NULL; + r->br_mem_rman.rm_descr = NULL; + + asprintf(&rdescr, M_BHND, "%s host memory", device_get_nameunit(dev)); + if ((r->ht_mem_rman.rm_descr = rdescr) == NULL) + goto failed; + + asprintf(&rdescr, M_BHND, "%s bridged memory", + device_get_nameunit(dev)); + if ((r->br_mem_rman.rm_descr = rdescr) == NULL) + goto failed; + /* Initialize host address space resource manager. */ r->ht_mem_rman.rm_start = 0; r->ht_mem_rman.rm_end = ~0; r->ht_mem_rman.rm_type = RMAN_ARRAY; - r->ht_mem_rman.rm_descr = "BHNDB host memory"; if ((error = rman_init(&r->ht_mem_rman))) { device_printf(r->dev, "could not initialize ht_mem_rman\n"); goto failed; @@ -300,8 +313,6 @@ r->br_mem_rman.rm_start = 0; r->br_mem_rman.rm_end = BUS_SPACE_MAXADDR_32BIT; r->br_mem_rman.rm_type = RMAN_ARRAY; - r->br_mem_rman.rm_descr = "BHNDB bridged memory"; - if ((error = rman_init(&r->br_mem_rman))) { device_printf(r->dev, "could not initialize br_mem_rman\n"); goto failed; @@ -458,6 +469,12 @@ if (free_parent_res) bus_release_resources(r->parent_dev, r->res_spec, r->res); + if (r->ht_mem_rman.rm_descr != NULL) + free((void *)r->ht_mem_rman.rm_descr, M_BHND); + + if (r->br_mem_rman.rm_descr != NULL) + free((void *)r->br_mem_rman.rm_descr, M_BHND); + if (free_ht_mem) rman_fini(&r->ht_mem_rman); @@ -515,6 +532,10 @@ free(region, M_BHND); } + /* Free our allocated resource manager descriptions */ + free((void *)br->ht_mem_rman.rm_descr, M_BHND); + free((void *)br->br_mem_rman.rm_descr, M_BHND); + /* Release our resource managers */ rman_fini(&br->ht_mem_rman); rman_fini(&br->br_mem_rman); 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 + * 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 +__FBSDID("$FreeBSD$"); + +/* + * ChipCommon SPROM driver. + */ + +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include + +#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,5 @@ /*- - * Copyright (c) 2015 Landon Fuller + * Copyright (c) 2015-2016 Landon Fuller * All rights reserved. * * Redistribution and use in source and binary forms, with or without @@ -42,8 +42,11 @@ #include #include +#include #include +#include #include +#include #include #include @@ -52,8 +55,6 @@ #include -#include "bhnd_nvram_if.h" - #include "chipcreg.h" #include "chipcvar.h" @@ -114,6 +115,11 @@ BHND_CHIP_QUIRK_END }; +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 +133,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) { @@ -159,7 +159,8 @@ sc->dev = dev; sc->quirks = bhnd_device_quirks(dev, chipc_devices, sizeof(chipc_devices[0])); - + sc->sprom_refcnt = 0; + CHIPC_LOCK_INIT(sc); /* Allocate bus resources */ @@ -168,7 +169,18 @@ return (error); sc->core = sc->res[0]; - + + /* Map just the primary ChipCommon register block, leaving the + * remainder for our children */ + error = bus_adjust_resource(dev, SYS_RES_MEMORY, sc->core->res, + rman_get_start(sc->core->res), + rman_get_start(sc->core->res) + CHIPC_CHIPID_SIZE - 1); + if (error) { + device_printf(dev, "failed to resize register block: %d\n", + error); + goto cleanup; + } + /* Fetch our chipset identification data */ ccid_reg = bhnd_bus_read_4(sc->core, CHIPC_ID); chip_type = CHIPC_GET_ATTR(ccid_reg, ID_BUS); @@ -194,30 +206,14 @@ 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 cleanup; - /* 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 cleanup; return (0); @@ -231,6 +227,10 @@ chipc_detach(device_t dev) { struct chipc_softc *sc; + int error; + + if ((error = bus_generic_detach(dev))) + return (error); sc = device_get_softc(dev); bhnd_release_resources(dev, sc->rspec, sc->res); @@ -244,55 +244,162 @@ 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); } -/** - * Initialize local SPROM shadow, if required. - * - * @param sc chipc driver state. - */ static int -chipc_sprom_init(struct chipc_softc *sc) +chipc_child_location_str(device_t dev, device_t child, char *buf, + size_t buflen) { - int error; + if (buflen == 0) + return (EOVERFLOW); - KASSERT(sc->nvram_src == BHND_NVRAM_SRC_SPROM, - ("non-SPROM source (%u)\n", sc->nvram_src)); + *buf = '\0'; + return (ENXIO); +} - /* Enable access to the SPROM */ - CHIPC_LOCK(sc); - if ((error = chipc_enable_sprom_pins(sc))) - goto failed; +static device_t +chipc_add_child(device_t dev, u_int order, const char *name, int unit) +{ + struct chipc_devinfo *dinfo; + device_t child; - /* 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); + child = device_add_child_ordered(dev, order, name, unit); + if (child == NULL) + return (NULL); - chipc_disable_sprom_pins(sc); - goto failed; + dinfo = malloc(sizeof(struct chipc_devinfo), M_DEVBUF, M_NOWAIT); + if (dinfo == NULL) { + device_delete_child(dev, child); + return (NULL); } - /* Drop access to the SPROM lines */ - if ((error = chipc_disable_sprom_pins(sc))) { - bhnd_sprom_fini(&sc->sprom); - goto failed; + 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_DEVBUF); } - CHIPC_UNLOCK(sc); - return (0); + device_set_ivars(child, NULL); +} -failed: - CHIPC_UNLOCK(sc); - return (error); +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); +} + +/** + * 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); + } } /** @@ -338,6 +445,57 @@ return (BHND_NVRAM_SRC_UNKNOWN); } +/** + * Eexamine 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 +503,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 +544,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 +555,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 +574,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 +607,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 +626,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 +650,38 @@ 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, bus_generic_rl_alloc_resource), + DEVMETHOD(bus_release_resource, bus_generic_rl_release_resource), + DEVMETHOD(bus_adjust_resource, bus_generic_adjust_resource), + DEVMETHOD(bus_release_resource, bus_generic_rl_release_resource), + DEVMETHOD(bus_activate_resource, bus_generic_activate_resource), + DEVMETHOD(bus_deactivate_resource, bus_generic_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), + /* 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 @@ -25,10 +25,6 @@ #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. */ - /** Evaluates to true if the given ChipCommon core revision provides * the core count via the chip identification register. */ #define CHIPC_NCORES_MIN_HWREV(hwrev) ((hwrev) == 4 || (hwrev) >= 6) @@ -64,6 +60,10 @@ #define CHIPC_SYS_CLK_CTL 0xc0 #define CHIPC_EROMPTR 0xfc /**< 32-bit EROM base address * on BCMA devices */ +#define CHIPC_CHIPID_SIZE 0x100 /**< size of the register block + containing the chip + identification registers. */ + #define CHIPC_SPROM_CTRL 0x190 /**< SPROM interface (rev >= 32) */ #define CHIPC_SPROM_ADDR 0x194 #define CHIPC_SPROM_DATA 0x198 @@ -82,6 +82,7 @@ #define CHIPC_PMU_PLL_CONTROL_ADDR 0x660 #define CHIPC_PMU_PLL_CONTROL_DATA 0x664 #define CHIPC_SPROM_OTP 0x800 /* SPROM/OTP address space */ +#define CHIPC_SPROM_OTP_SIZE 0x400 /** chipid */ #define CHIPC_ID 0x0 /**< identification register */ Index: sys/dev/bhnd/cores/chipc/chipcvar.h =================================================================== --- sys/dev/bhnd/cores/chipc/chipcvar.h +++ sys/dev/bhnd/cores/chipc/chipcvar.h @@ -107,6 +107,16 @@ 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 driver instance state. + */ struct chipc_softc { device_t dev; @@ -123,6 +133,7 @@ struct mtx mtx; /**< state mutex. */ struct bhnd_sprom sprom; /**< OTP/SPROM shadow, if any */ + size_t sprom_refcnt; /**< SPROM hardware refcount */ }; #define CHIPC_LOCK_INIT(sc) \ @@ -133,4 +144,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 + * Copyright (c) 2015-2016 Landon Fuller * All rights reserved. * * Redistribution and use in source and binary forms, with or without @@ -30,539 +30,180 @@ #include __FBSDID("$FreeBSD$"); +/* + * BHND SPROM driver. + * + * Abstract driver for memory-mapped SPROM devices. + */ + #include +#include #include -#include -#include +#include +#include +#include #include #include +#include #include -#include +#include -#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 + +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/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