From owner-svn-src-head@freebsd.org Tue May 24 01:12:21 2016 Return-Path: Delivered-To: svn-src-head@mailman.ysv.freebsd.org Received: from mx1.freebsd.org (mx1.freebsd.org [IPv6:2001:1900:2254:206a::19:1]) by mailman.ysv.freebsd.org (Postfix) with ESMTP id 7F823B4860C; Tue, 24 May 2016 01:12:21 +0000 (UTC) (envelope-from adrian@FreeBSD.org) Received: from repo.freebsd.org (repo.freebsd.org [IPv6:2610:1c1:1:6068::e6a:0]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (Client did not present a certificate) by mx1.freebsd.org (Postfix) with ESMTPS id 1E8791BF5; Tue, 24 May 2016 01:12:21 +0000 (UTC) (envelope-from adrian@FreeBSD.org) Received: from repo.freebsd.org ([127.0.1.37]) by repo.freebsd.org (8.15.2/8.15.2) with ESMTP id u4O1CKtP063658; Tue, 24 May 2016 01:12:20 GMT (envelope-from adrian@FreeBSD.org) Received: (from adrian@localhost) by repo.freebsd.org (8.15.2/8.15.2/Submit) id u4O1CJOt063645; Tue, 24 May 2016 01:12:19 GMT (envelope-from adrian@FreeBSD.org) Message-Id: <201605240112.u4O1CJOt063645@repo.freebsd.org> X-Authentication-Warning: repo.freebsd.org: adrian set sender to adrian@FreeBSD.org using -f From: Adrian Chadd Date: Tue, 24 May 2016 01:12:19 +0000 (UTC) To: src-committers@freebsd.org, svn-src-all@freebsd.org, svn-src-head@freebsd.org Subject: svn commit: r300548 - in head/sys: conf dev/bhnd dev/bhnd/bhndb dev/bhnd/cores/chipc dev/bhnd/nvram dev/bhnd/siba modules/bhnd modules/bhnd/cores/bhnd_chipc X-SVN-Group: head MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit X-BeenThere: svn-src-head@freebsd.org X-Mailman-Version: 2.1.22 Precedence: list List-Id: SVN commit messages for the src tree for head/-current List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , X-List-Received-Date: Tue, 24 May 2016 01:12:21 -0000 Author: adrian Date: Tue May 24 01:12:19 2016 New Revision: 300548 URL: https://svnweb.freebsd.org/changeset/base/300548 Log: [bhnd] Implement pass-through resource management for ChipCommon. This patchset adds support to bhnd_chipc for sharing SYS_RES_MEMORY resources with its children, allowing us to hang devices off of bhnd_chipc that rely on access to a subset of the device register space that bhnd_chipc itself must also allocate. We could avoid most of this heavy lifting if RF_SHAREABLE+SYS_RES_MEMORY wasn't limited to use with allocations at the same size/offset. As a work-around, I implemented something similar to vga_pci.c, which implements similar reference counting of of PCI BAR resources for its children. With these changes, chipc will use reference counting of SYS_RES_MEMORY allocation/activation requests, to decide when to allocate/activate/ deactivate/release resources from the parent bhnd(4) bus. The requesting child device is allocated a new resource from chipc's rman, pointing to (possibly a subregion of) the refcounted bhnd resources allocated by chipc. Other resource types are just passed directly to the parent bhnd bus; RF_SHAREABLE works just fine with IRQs. I also lifted the SPROM device code out into a common driver, since this now allows me to hang simple subclasses off of a common driver off of both bhndb_pci and bhnd_chipc. Tested: * (landonf) Tested against BCM4331 and BCM4312, confirmed that SPROM still attaches and can be queried. Submitted by: Landon Fuller Reviewed by: mizkha@gmail.com Differential Revision: https://reviews.freebsd.org/D6471 Added: head/sys/dev/bhnd/cores/chipc/bhnd_sprom_chipc.c (contents, props changed) head/sys/dev/bhnd/cores/chipc/chipc_private.h (contents, props changed) head/sys/dev/bhnd/cores/chipc/chipc_subr.c (contents, props changed) head/sys/dev/bhnd/nvram/bhnd_sprom_subr.c - copied, changed from r300546, head/sys/dev/bhnd/nvram/bhnd_sprom.c Modified: head/sys/conf/files head/sys/dev/bhnd/bhnd_subr.c head/sys/dev/bhnd/bhndb/bhndb_pci_sprom.c head/sys/dev/bhnd/cores/chipc/bhnd_chipc_if.m head/sys/dev/bhnd/cores/chipc/chipc.c head/sys/dev/bhnd/cores/chipc/chipc.h head/sys/dev/bhnd/cores/chipc/chipcreg.h head/sys/dev/bhnd/cores/chipc/chipcvar.h head/sys/dev/bhnd/nvram/bhnd_nvram.h head/sys/dev/bhnd/nvram/bhnd_sprom.c head/sys/dev/bhnd/nvram/bhnd_spromvar.h head/sys/dev/bhnd/siba/siba.c head/sys/dev/bhnd/siba/siba_subr.c head/sys/dev/bhnd/siba/sibavar.h head/sys/modules/bhnd/Makefile head/sys/modules/bhnd/cores/bhnd_chipc/Makefile Modified: head/sys/conf/files ============================================================================== --- head/sys/conf/files Tue May 24 00:57:11 2016 (r300547) +++ head/sys/conf/files Tue May 24 01:12:19 2016 (r300548) @@ -1139,7 +1139,9 @@ dev/bhnd/bcma/bcma_bhndb.c optional bhn dev/bhnd/bcma/bcma_erom.c optional bhndbus | bcma dev/bhnd/bcma/bcma_subr.c optional bhndbus | bcma dev/bhnd/cores/chipc/chipc.c optional bhndbus | bhnd +dev/bhnd/cores/chipc/chipc_subr.c optional bhndbus | bhnd dev/bhnd/cores/chipc/bhnd_chipc_if.m optional bhndbus | bhnd +dev/bhnd/cores/chipc/bhnd_sprom_chipc.c optional bhndbus | bhnd dev/bhnd/cores/pci/bhnd_pci.c optional bhndbus pci | bhnd pci dev/bhnd/cores/pci/bhnd_pci_hostb.c optional bhndbus pci | bhndb pci dev/bhnd/cores/pci/bhnd_pcib.c optional bhnd_pcib bhnd pci @@ -1148,6 +1150,7 @@ dev/bhnd/cores/pcie2/bhnd_pcie2_hostb.c dev/bhnd/cores/pcie2/bhnd_pcie2b.c optional bhnd_pcie2b bhnd pci dev/bhnd/nvram/bhnd_nvram_if.m optional bhndbus | bhnd dev/bhnd/nvram/bhnd_sprom.c optional bhndbus | bhnd +dev/bhnd/nvram/bhnd_sprom_subr.c optional bhndbus | bhnd dev/bhnd/nvram/nvram_subr.c optional bhndbus | bhnd dev/bhnd/siba/siba.c optional bhndbus | siba dev/bhnd/siba/siba_bhndb.c optional bhndbus | siba bhndb Modified: head/sys/dev/bhnd/bhnd_subr.c ============================================================================== --- head/sys/dev/bhnd/bhnd_subr.c Tue May 24 00:57:11 2016 (r300547) +++ head/sys/dev/bhnd/bhnd_subr.c Tue May 24 01:12:19 2016 (r300548) @@ -797,11 +797,11 @@ bhnd_parse_chipid(uint32_t idreg, bhnd_a struct bhnd_chipid result; /* Fetch the basic chip info */ - result.chip_id = CHIPC_GET_ATTR(idreg, ID_CHIP); - result.chip_pkg = CHIPC_GET_ATTR(idreg, ID_PKG); - result.chip_rev = CHIPC_GET_ATTR(idreg, ID_REV); - result.chip_type = CHIPC_GET_ATTR(idreg, ID_BUS); - result.ncores = CHIPC_GET_ATTR(idreg, ID_NUMCORE); + result.chip_id = CHIPC_GET_BITS(idreg, CHIPC_ID_CHIP); + result.chip_pkg = CHIPC_GET_BITS(idreg, CHIPC_ID_PKG); + result.chip_rev = CHIPC_GET_BITS(idreg, CHIPC_ID_REV); + result.chip_type = CHIPC_GET_BITS(idreg, CHIPC_ID_BUS); + result.ncores = CHIPC_GET_BITS(idreg, CHIPC_ID_NUMCORE); result.enum_addr = enum_addr; @@ -1020,15 +1020,11 @@ find_nvram_child(device_t dev) if (device_get_devclass(dev) != bhnd_devclass) return (NULL); - /* Look for a ChipCommon device */ + /* Look for a ChipCommon-attached NVRAM device */ if ((chipc = bhnd_find_child(dev, BHND_DEVCLASS_CC, -1)) != NULL) { - bhnd_nvram_src_t src; - - /* Query the NVRAM source and determine whether it's - * accessible via the ChipCommon device */ - src = BHND_CHIPC_NVRAM_SRC(chipc); - if (BHND_NVRAM_SRC_CC(src)) - return (chipc); + nvram = device_find_child(chipc, "bhnd_nvram", 0); + if (nvram != NULL) + return (nvram); } /* Not found */ Modified: head/sys/dev/bhnd/bhndb/bhndb_pci_sprom.c ============================================================================== --- head/sys/dev/bhnd/bhndb/bhndb_pci_sprom.c Tue May 24 00:57:11 2016 (r300547) +++ head/sys/dev/bhnd/bhndb/bhndb_pci_sprom.c Tue May 24 01:12:19 2016 (r300548) @@ -53,29 +53,15 @@ __FBSDID("$FreeBSD$"); #include #include "bhnd_nvram_if.h" + #include "bhndb_pcireg.h" #include "bhndb_pcivar.h" -struct bhndb_pci_sprom_softc { - device_t dev; - struct bhnd_resource *sprom_res; /**< SPROM resource */ - int sprom_rid; /**< SPROM RID */ - struct bhnd_sprom shadow; /**< SPROM shadow */ - struct mtx mtx; /**< SPROM shadow mutex */ -}; - -#define SPROM_LOCK_INIT(sc) \ - mtx_init(&(sc)->mtx, device_get_nameunit((sc)->dev), \ - "BHND PCI SPROM lock", MTX_DEF) -#define SPROM_LOCK(sc) mtx_lock(&(sc)->mtx) -#define SPROM_UNLOCK(sc) mtx_unlock(&(sc)->mtx) -#define SPROM_LOCK_ASSERT(sc, what) mtx_assert(&(sc)->mtx, what) -#define SPROM_LOCK_DESTROY(sc) mtx_destroy(&(sc)->mtx) - static int bhndb_pci_sprom_probe(device_t dev) { device_t bridge, bus; + int error; /* Our parent must be a PCI-BHND bridge with an attached bhnd bus */ bridge = device_get_parent(dev); @@ -86,125 +72,23 @@ bhndb_pci_sprom_probe(device_t dev) if (bus == NULL) return (ENXIO); - /* Found */ - device_set_desc(dev, "PCI-BHNDB SPROM/OTP"); - if (!bootverbose) - device_quiet(dev); + /* Defer to default driver implementation */ + if ((error = bhnd_sprom_probe(dev)) > 0) + return (error); - /* Refuse wildcard attachments */ return (BUS_PROBE_NOWILDCARD); } -static int -bhndb_pci_sprom_attach(device_t dev) -{ - struct bhndb_pci_sprom_softc *sc; - int error; - - sc = device_get_softc(dev); - sc->dev = dev; - - /* Allocate SPROM resource */ - sc->sprom_rid = 0; - sc->sprom_res = bhnd_alloc_resource_any(dev, SYS_RES_MEMORY, - &sc->sprom_rid, RF_ACTIVE); - if (sc->sprom_res == NULL) { - device_printf(dev, "failed to allocate resources\n"); - return (ENXIO); - } - - /* Initialize SPROM shadow */ - if ((error = bhnd_sprom_init(&sc->shadow, sc->sprom_res, 0))) { - device_printf(dev, "unrecognized SPROM format\n"); - goto failed; - } - - /* Initialize mutex */ - SPROM_LOCK_INIT(sc); - - return (0); - -failed: - bhnd_release_resource(dev, SYS_RES_MEMORY, sc->sprom_rid, - sc->sprom_res); - return (error); -} - -static int -bhndb_pci_sprom_resume(device_t dev) -{ - return (0); -} - -static int -bhndb_pci_sprom_suspend(device_t dev) -{ - return (0); -} - -static int -bhndb_pci_sprom_detach(device_t dev) -{ - struct bhndb_pci_sprom_softc *sc; - - sc = device_get_softc(dev); - - bhnd_release_resource(dev, SYS_RES_MEMORY, sc->sprom_rid, - sc->sprom_res); - bhnd_sprom_fini(&sc->shadow); - SPROM_LOCK_DESTROY(sc); - - return (0); -} - -static int -bhndb_pci_sprom_getvar(device_t dev, const char *name, void *buf, size_t *len) -{ - struct bhndb_pci_sprom_softc *sc; - int error; - - sc = device_get_softc(dev); - - SPROM_LOCK(sc); - error = bhnd_sprom_getvar(&sc->shadow, name, buf, len); - SPROM_UNLOCK(sc); - - return (error); -} - -static int -bhndb_pci_sprom_setvar(device_t dev, const char *name, const void *buf, - size_t len) -{ - struct bhndb_pci_sprom_softc *sc; - int error; - - sc = device_get_softc(dev); - - SPROM_LOCK(sc); - error = bhnd_sprom_setvar(&sc->shadow, name, buf, len); - SPROM_UNLOCK(sc); - - return (error); -} static device_method_t bhndb_pci_sprom_methods[] = { /* Device interface */ DEVMETHOD(device_probe, bhndb_pci_sprom_probe), - DEVMETHOD(device_attach, bhndb_pci_sprom_attach), - DEVMETHOD(device_resume, bhndb_pci_sprom_resume), - DEVMETHOD(device_suspend, bhndb_pci_sprom_suspend), - DEVMETHOD(device_detach, bhndb_pci_sprom_detach), - - /* NVRAM interface */ - DEVMETHOD(bhnd_nvram_getvar, bhndb_pci_sprom_getvar), - DEVMETHOD(bhnd_nvram_setvar, bhndb_pci_sprom_setvar), - DEVMETHOD_END }; -DEFINE_CLASS_0(bhnd_nvram, bhndb_pci_sprom_driver, bhndb_pci_sprom_methods, sizeof(struct bhndb_pci_sprom_softc)); +DEFINE_CLASS_1(bhnd_nvram, bhndb_pci_sprom_driver, bhndb_pci_sprom_methods, sizeof(struct bhnd_sprom_softc), bhnd_sprom_driver); DRIVER_MODULE(bhndb_pci_sprom, bhndb, bhndb_pci_sprom_driver, bhnd_nvram_devclass, NULL, NULL); MODULE_DEPEND(bhndb_pci_sprom, bhnd, 1, 1, 1); +MODULE_DEPEND(bhndb_pci_sprom, bhnd_sprom, 1, 1, 1); MODULE_VERSION(bhndb_pci_sprom, 1); Modified: head/sys/dev/bhnd/cores/chipc/bhnd_chipc_if.m ============================================================================== --- head/sys/dev/bhnd/cores/chipc/bhnd_chipc_if.m Tue May 24 00:57:11 2016 (r300547) +++ head/sys/dev/bhnd/cores/chipc/bhnd_chipc_if.m Tue May 24 01:12:19 2016 (r300548) @@ -36,6 +36,11 @@ INTERFACE bhnd_chipc; # bhnd(4) ChipCommon interface. # +HEADER { + /* forward declarations */ + struct chipc_caps; +} + /** * Return the preferred NVRAM data source. * @@ -63,3 +68,35 @@ METHOD void write_chipctrl { uint32_t value; uint32_t mask; } + +/** + * Return a borrowed reference to ChipCommon's capability + * table. + * + * @param dev A bhnd(4) ChipCommon device + */ +METHOD struct chipc_caps * get_caps { + device_t dev; +} + +/** + * Enable hardware access to the SPROM. + * + * @param sc chipc driver state. + * + * @retval 0 success + * @retval EBUSY If enabling the hardware may conflict with + * other active devices. + */ +METHOD int enable_sprom { + device_t dev; +} + +/** + * Release hardware access to the SPROM. + * + * @param sc chipc driver state. + */ +METHOD void disable_sprom { + device_t dev; +} Added: head/sys/dev/bhnd/cores/chipc/bhnd_sprom_chipc.c ============================================================================== --- /dev/null 00:00:00 1970 (empty, because file is newly added) +++ head/sys/dev/bhnd/cores/chipc/bhnd_sprom_chipc.c Tue May 24 01:12:19 2016 (r300548) @@ -0,0 +1,101 @@ +/*- + * Copyright (c) 2015-2016 Landon Fuller + * 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); Modified: head/sys/dev/bhnd/cores/chipc/chipc.c ============================================================================== --- head/sys/dev/bhnd/cores/chipc/chipc.c Tue May 24 00:57:11 2016 (r300547) +++ head/sys/dev/bhnd/cores/chipc/chipc.c Tue May 24 01:12:19 2016 (r300548) @@ -1,5 +1,6 @@ /*- - * Copyright (c) 2015 Landon Fuller + * Copyright (c) 2015-2016 Landon Fuller + * Copyright (c) 2016 Michael Zhilin * All rights reserved. * * Redistribution and use in source and binary forms, with or without @@ -42,8 +43,11 @@ __FBSDID("$FreeBSD$"); #include #include +#include #include +#include #include +#include #include #include @@ -51,19 +55,14 @@ __FBSDID("$FreeBSD$"); #include #include - -#include "bhnd_nvram_if.h" +#include #include "chipcreg.h" #include "chipcvar.h" +#include "chipc_private.h" devclass_t bhnd_chipc_devclass; /**< bhnd(4) chipcommon device class */ -static const struct resource_spec chipc_rspec[CHIPC_MAX_RSPEC] = { - { SYS_RES_MEMORY, 0, RF_ACTIVE }, - { -1, -1, 0 } -}; - static struct bhnd_device_quirk chipc_quirks[]; static struct bhnd_chip_quirk chipc_chip_quirks[]; @@ -77,7 +76,10 @@ static const struct bhnd_device chipc_de /* Device quirks table */ static struct bhnd_device_quirk chipc_quirks[] = { { BHND_HWREV_GTE (32), CHIPC_QUIRK_SUPPORTS_SPROM }, - { BHND_HWREV_GTE (35), CHIPC_QUIRK_SUPPORTS_NFLASH }, + { BHND_HWREV_GTE (35), CHIPC_QUIRK_SUPPORTS_CAP_EXT }, + { BHND_HWREV_EQ (38), CHIPC_QUIRK_4706_NFLASH }, /*BCM5357 ?*/ + { BHND_HWREV_GTE (49), CHIPC_QUIRK_IPX_OTPLAYOUT_SIZE }, + BHND_DEVICE_QUIRK_END }; @@ -111,15 +113,37 @@ static struct bhnd_chip_quirk chipc_chip {{ BHND_CHIP_IR(43602, HWREV_LTE(2)) }, CHIPC_QUIRK_4360_FEM_MUX_SPROM }, + /* BCM4706 */ + {{ BHND_CHIP_ID(4306) }, + CHIPC_QUIRK_4706_NFLASH }, + BHND_CHIP_QUIRK_END }; +static int chipc_try_activate_resource( + struct chipc_softc *sc, device_t child, + int type, int rid, struct resource *r, + bool req_direct); + +static int chipc_read_caps(struct chipc_softc *sc, + struct chipc_caps *caps); + +static int chipc_nvram_attach(struct chipc_softc *sc); +static bhnd_nvram_src_t chipc_nvram_identify(struct chipc_softc *sc); +static bool chipc_should_enable_sprom( + struct chipc_softc *sc); + +static int chipc_init_rman(struct chipc_softc *sc); +static void chipc_free_rman(struct chipc_softc *sc); +static struct rman *chipc_get_rman(struct chipc_softc *sc, + int type); + /* quirk and capability flag convenience macros */ #define CHIPC_QUIRK(_sc, _name) \ ((_sc)->quirks & CHIPC_QUIRK_ ## _name) #define CHIPC_CAP(_sc, _name) \ - ((_sc)->caps & CHIPC_ ## _name) + ((_sc)->caps._name) #define CHIPC_ASSERT_QUIRK(_sc, name) \ KASSERT(CHIPC_QUIRK((_sc), name), ("quirk " __STRING(_name) " not set")) @@ -127,12 +151,6 @@ static struct bhnd_chip_quirk chipc_chip #define CHIPC_ASSERT_CAP(_sc, name) \ KASSERT(CHIPC_CAP((_sc), name), ("capability " __STRING(_name) " not set")) -static bhnd_nvram_src_t chipc_nvram_identify(struct chipc_softc *sc); -static int chipc_sprom_init(struct chipc_softc *); -static int chipc_enable_sprom_pins(struct chipc_softc *); -static int chipc_disable_sprom_pins(struct chipc_softc *); - - static int chipc_probe(device_t dev) { @@ -159,19 +177,36 @@ chipc_attach(device_t dev) sc->dev = dev; sc->quirks = bhnd_device_quirks(dev, chipc_devices, sizeof(chipc_devices[0])); - + sc->sprom_refcnt = 0; + CHIPC_LOCK_INIT(sc); + STAILQ_INIT(&sc->mem_regions); - /* Allocate bus resources */ - memcpy(sc->rspec, chipc_rspec, sizeof(sc->rspec)); - if ((error = bhnd_alloc_resources(dev, sc->rspec, sc->res))) - return (error); + /* Set up resource management */ + if ((error = chipc_init_rman(sc))) { + device_printf(sc->dev, + "failed to initialize chipc resource state: %d\n", error); + goto failed; + } + + /* Allocate the region containing our core registers */ + if ((sc->core_region = chipc_find_region_by_rid(sc, 0)) == NULL) { + error = ENXIO; + goto failed; + } + + error = chipc_retain_region(sc, sc->core_region, + RF_ALLOCATED|RF_ACTIVE); + if (error) { + sc->core_region = NULL; + goto failed; + } else { + sc->core = sc->core_region->cr_res; + } - sc->core = sc->res[0]; - /* Fetch our chipset identification data */ ccid_reg = bhnd_bus_read_4(sc->core, CHIPC_ID); - chip_type = CHIPC_GET_ATTR(ccid_reg, ID_BUS); + chip_type = CHIPC_GET_BITS(ccid_reg, CHIPC_ID_BUS); switch (chip_type) { case BHND_CHIPTYPE_SIBA: @@ -185,44 +220,36 @@ chipc_attach(device_t dev) default: device_printf(dev, "unsupported chip type %hhu\n", chip_type); error = ENODEV; - goto cleanup; + goto failed; } sc->ccid = bhnd_parse_chipid(ccid_reg, enum_addr); - /* Fetch capability and status register values */ - sc->caps = bhnd_bus_read_4(sc->core, CHIPC_CAPABILITIES); - sc->cst = bhnd_bus_read_4(sc->core, CHIPC_CHIPST); - - /* Identify NVRAM source */ - sc->nvram_src = chipc_nvram_identify(sc); - - /* Read NVRAM data */ - switch (sc->nvram_src) { - case BHND_NVRAM_SRC_OTP: - // TODO (requires access to OTP hardware) - device_printf(sc->dev, "NVRAM-OTP unsupported\n"); - break; + /* Fetch and parse capability register(s) */ + if ((error = chipc_read_caps(sc, &sc->caps))) + goto failed; - case BHND_NVRAM_SRC_NFLASH: - // TODO (requires access to NFLASH hardware) - device_printf(sc->dev, "NVRAM-NFLASH unsupported\n"); - break; + if (bootverbose) + chipc_print_caps(sc->dev, &sc->caps); - case BHND_NVRAM_SRC_SPROM: - if ((error = chipc_sprom_init(sc))) - goto cleanup; - break; + /* Identify NVRAM source and add child device. */ + sc->nvram_src = chipc_nvram_identify(sc); + if ((error = chipc_nvram_attach(sc))) + goto failed; - case BHND_NVRAM_SRC_UNKNOWN: - /* Handled externally */ - break; - } + /* Standard bus probe */ + if ((error = bus_generic_attach(dev))) + goto failed; return (0); -cleanup: - bhnd_release_resources(dev, sc->rspec, sc->res); +failed: + if (sc->core_region != NULL) { + chipc_release_region(sc, sc->core_region, + RF_ALLOCATED|RF_ACTIVE); + } + + chipc_free_rman(sc); CHIPC_LOCK_DESTROY(sc); return (error); } @@ -231,9 +258,15 @@ static int chipc_detach(device_t dev) { struct chipc_softc *sc; + int error; sc = device_get_softc(dev); - bhnd_release_resources(dev, sc->rspec, sc->res); + + if ((error = bus_generic_detach(dev))) + return (error); + + chipc_release_region(sc, sc->core_region, RF_ALLOCATED|RF_ACTIVE); + chipc_free_rman(sc); bhnd_sprom_fini(&sc->sprom); CHIPC_LOCK_DESTROY(sc); @@ -241,58 +274,131 @@ chipc_detach(device_t dev) return (0); } +/* Read and parse chipc capabilities */ static int -chipc_suspend(device_t dev) +chipc_read_caps(struct chipc_softc *sc, struct chipc_caps *caps) { - return (0); -} + uint32_t cap_reg; + uint32_t cap_ext_reg; + uint32_t regval; + + /* Fetch cap registers */ + cap_reg = bhnd_bus_read_4(sc->core, CHIPC_CAPABILITIES); + cap_ext_reg = 0; + if (CHIPC_QUIRK(sc, SUPPORTS_CAP_EXT)) + cap_ext_reg = bhnd_bus_read_4(sc->core, CHIPC_CAPABILITIES_EXT); + + /* Extract values */ + caps->num_uarts = CHIPC_GET_BITS(cap_reg, CHIPC_CAP_NUM_UART); + caps->mipseb = CHIPC_GET_FLAG(cap_reg, CHIPC_CAP_MIPSEB); + caps->uart_gpio = CHIPC_GET_FLAG(cap_reg, CHIPC_CAP_UARTGPIO); + caps->uart_clock = CHIPC_GET_BITS(cap_reg, CHIPC_CAP_UCLKSEL); + + caps->extbus_type = CHIPC_GET_BITS(cap_reg, CHIPC_CAP_EXTBUS); + caps->power_control = CHIPC_GET_FLAG(cap_reg, CHIPC_CAP_PWR_CTL); + caps->jtag_master = CHIPC_GET_FLAG(cap_reg, CHIPC_CAP_JTAGP); + + caps->pll_type = CHIPC_GET_BITS(cap_reg, CHIPC_CAP_PLL); + caps->backplane_64 = CHIPC_GET_FLAG(cap_reg, CHIPC_CAP_BKPLN64); + caps->boot_rom = CHIPC_GET_FLAG(cap_reg, CHIPC_CAP_ROM); + caps->pmu = CHIPC_GET_FLAG(cap_reg, CHIPC_CAP_PMU); + caps->eci = CHIPC_GET_FLAG(cap_reg, CHIPC_CAP_ECI); + caps->sprom = CHIPC_GET_FLAG(cap_reg, CHIPC_CAP_SPROM); + caps->otp_size = CHIPC_GET_BITS(cap_reg, CHIPC_CAP_OTP_SIZE); + + caps->seci = CHIPC_GET_FLAG(cap_ext_reg, CHIPC_CAP2_SECI); + caps->gsio = CHIPC_GET_FLAG(cap_ext_reg, CHIPC_CAP2_GSIO); + caps->aob = CHIPC_GET_FLAG(cap_ext_reg, CHIPC_CAP2_AOB); + + /* Fetch OTP size for later IPX controller revisions */ + if (CHIPC_QUIRK(sc, IPX_OTPLAYOUT_SIZE)) { + regval = bhnd_bus_read_4(sc->core, CHIPC_OTPLAYOUT); + caps->otp_size = CHIPC_GET_BITS(regval, CHIPC_OTPL_SIZE); + } + + /* Determine flash type and paramters */ + caps->cfi_width = 0; + + switch (CHIPC_GET_BITS(cap_reg, CHIPC_CAP_FLASH)) { + case CHIPC_CAP_SFLASH_ST: + caps->flash_type = CHIPC_SFLASH_ST; + break; + case CHIPC_CAP_SFLASH_AT: + caps->flash_type = CHIPC_SFLASH_AT; + break; + case CHIPC_CAP_NFLASH: + caps->flash_type = CHIPC_NFLASH; + break; + case CHIPC_CAP_PFLASH: + caps->flash_type = CHIPC_PFLASH_CFI; + + /* determine cfi width */ + regval = bhnd_bus_read_4(sc->core, CHIPC_FLASH_CFG); + if (CHIPC_GET_FLAG(regval, CHIPC_FLASH_CFG_DS)) + caps->cfi_width = 2; + else + caps->cfi_width = 1; + + break; + case CHIPC_CAP_FLASH_NONE: + caps->flash_type = CHIPC_FLASH_NONE; + break; + + } + + /* Handle 4706_NFLASH fallback */ + if (CHIPC_QUIRK(sc, 4706_NFLASH) && + CHIPC_GET_FLAG(cap_reg, CHIPC_CAP_4706_NFLASH)) + { + caps->flash_type = CHIPC_NFLASH_4706; + } -static int -chipc_resume(device_t dev) -{ return (0); } /** - * Initialize local SPROM shadow, if required. - * - * @param sc chipc driver state. + * If supported, add an appropriate NVRAM child device. */ static int -chipc_sprom_init(struct chipc_softc *sc) +chipc_nvram_attach(struct chipc_softc *sc) { - int error; + device_t nvram_dev; + rman_res_t start; + int error; - KASSERT(sc->nvram_src == BHND_NVRAM_SRC_SPROM, - ("non-SPROM source (%u)\n", sc->nvram_src)); + switch (sc->nvram_src) { + case BHND_NVRAM_SRC_OTP: + // TODO OTP support + device_printf(sc->dev, "OTP nvram source unsupported\n"); + return (0); - /* Enable access to the SPROM */ - CHIPC_LOCK(sc); - if ((error = chipc_enable_sprom_pins(sc))) - goto failed; + case BHND_NVRAM_SRC_SPROM: + /* Add OTP/SPROM device */ + nvram_dev = BUS_ADD_CHILD(sc->dev, 0, "bhnd_nvram", -1); + if (nvram_dev == NULL) { + device_printf(sc->dev, "failed to add NVRAM device\n"); + return (ENXIO); + } + + start = rman_get_start(sc->core->res) + CHIPC_SPROM_OTP; + error = bus_set_resource(nvram_dev, SYS_RES_MEMORY, 0, start, + CHIPC_SPROM_OTP_SIZE); + return (error); - /* Initialize SPROM parser */ - error = bhnd_sprom_init(&sc->sprom, sc->core, CHIPC_SPROM_OTP); - if (error) { - device_printf(sc->dev, "SPROM identification failed: %d\n", - error); + case BHND_NVRAM_SRC_FLASH: + // TODO flash support + device_printf(sc->dev, "flash nvram source unsupported\n"); + return (0); - chipc_disable_sprom_pins(sc); - goto failed; - } + case BHND_NVRAM_SRC_UNKNOWN: + /* Handled externally */ + return (0); - /* Drop access to the SPROM lines */ - if ((error = chipc_disable_sprom_pins(sc))) { - bhnd_sprom_fini(&sc->sprom); - goto failed; + default: + device_printf(sc->dev, "invalid nvram source: %u\n", + sc->nvram_src); + return (ENXIO); } - CHIPC_UNLOCK(sc); - - return (0); - -failed: - CHIPC_UNLOCK(sc); - return (error); } /** @@ -317,27 +423,645 @@ chipc_nvram_identify(struct chipc_softc * We check for hardware presence in order of precedence. For example, * SPROM is is always used in preference to internal OTP if found. */ - if (CHIPC_CAP(sc, CAP_SPROM)) { + if (CHIPC_CAP(sc, sprom)) { srom_ctrl = bhnd_bus_read_4(sc->core, CHIPC_SPROM_CTRL); if (srom_ctrl & CHIPC_SRC_PRESENT) return (BHND_NVRAM_SRC_SPROM); } /* Check for OTP */ - if (CHIPC_CAP(sc, CAP_OTP_SIZE)) + if (CHIPC_CAP(sc, otp_size) != 0) return (BHND_NVRAM_SRC_OTP); - /* - * Finally, Northstar chipsets (and possibly other chipsets?) support - * external NAND flash. - */ - if (CHIPC_QUIRK(sc, SUPPORTS_NFLASH) && CHIPC_CAP(sc, CAP_NFLASH)) - return (BHND_NVRAM_SRC_NFLASH); + /* Check for flash */ + if (CHIPC_CAP(sc, flash_type) != CHIPC_FLASH_NONE) + return (BHND_NVRAM_SRC_FLASH); /* No NVRAM hardware capability declared */ return (BHND_NVRAM_SRC_UNKNOWN); } +static int +chipc_suspend(device_t dev) +{ + return (bus_generic_suspend(dev)); +} + +static int +chipc_resume(device_t dev) +{ + return (bus_generic_resume(dev)); +} + +static void +chipc_probe_nomatch(device_t dev, device_t child) +{ + struct resource_list *rl; + const char *name; + + name = device_get_name(child); + if (name == NULL) + name = "unknown device"; + + device_printf(dev, "<%s> at", name); + + rl = BUS_GET_RESOURCE_LIST(dev, child); + if (rl != NULL) { + resource_list_print_type(rl, "mem", SYS_RES_MEMORY, "%#jx"); + resource_list_print_type(rl, "irq", SYS_RES_IRQ, "%jd"); + } + + printf(" (no driver attached)\n"); +} + +static int +chipc_print_child(device_t dev, device_t child) +{ + struct resource_list *rl; + int retval = 0; + + retval += bus_print_child_header(dev, child); + + rl = BUS_GET_RESOURCE_LIST(dev, child); + if (rl != NULL) { + retval += resource_list_print_type(rl, "mem", SYS_RES_MEMORY, + "%#jx"); + retval += resource_list_print_type(rl, "irq", SYS_RES_IRQ, + "%jd"); + } + + retval += bus_print_child_domain(dev, child); + retval += bus_print_child_footer(dev, child); + + return (retval); +} + +static int +chipc_child_pnpinfo_str(device_t dev, device_t child, char *buf, + size_t buflen) +{ + if (buflen == 0) + return (EOVERFLOW); + + *buf = '\0'; + return (0); +} + +static int +chipc_child_location_str(device_t dev, device_t child, char *buf, + size_t buflen) +{ + if (buflen == 0) + return (EOVERFLOW); + + *buf = '\0'; + return (ENXIO); +} + +static device_t +chipc_add_child(device_t dev, u_int order, const char *name, int unit) +{ + struct chipc_devinfo *dinfo; + device_t child; + + child = device_add_child_ordered(dev, order, name, unit); + if (child == NULL) + return (NULL); + + dinfo = malloc(sizeof(struct chipc_devinfo), M_BHND, M_NOWAIT); + if (dinfo == NULL) { + device_delete_child(dev, child); + return (NULL); + } + + resource_list_init(&dinfo->resources); + + device_set_ivars(child, dinfo); + + return (child); +} + +static void +chipc_child_deleted(device_t dev, device_t child) +{ + struct chipc_devinfo *dinfo = device_get_ivars(child); + + if (dinfo != NULL) { + resource_list_free(&dinfo->resources); + free(dinfo, M_BHND); + } + + device_set_ivars(child, NULL); +} + +static struct resource_list * +chipc_get_resource_list(device_t dev, device_t child) +{ + struct chipc_devinfo *dinfo = device_get_ivars(child); + return (&dinfo->resources); +} + + +/* Allocate region records for the given port, and add the port's memory + * range to the mem_rman */ +static int +chipc_rman_init_regions (struct chipc_softc *sc, bhnd_port_type type, + u_int port) +{ + struct chipc_region *cr; + rman_res_t start, end; + u_int num_regions; + int error; + + num_regions = bhnd_get_region_count(sc->dev, port, port); + for (u_int region = 0; region < num_regions; region++) { + /* Allocate new region record */ + cr = chipc_alloc_region(sc, type, port, region); + if (cr == NULL) + return (ENODEV); + + /* Can't manage regions that cannot be allocated */ + if (cr->cr_rid < 0) { + BHND_DEBUG_DEV(sc->dev, "no rid for chipc region " + "%s%u.%u", bhnd_port_type_name(type), port, region); + chipc_free_region(sc, cr); + continue; + } + + /* Add to rman's managed range */ + start = cr->cr_addr; + end = cr->cr_end; + if ((error = rman_manage_region(&sc->mem_rman, start, end))) { + chipc_free_region(sc, cr); + return (error); + } + + /* Add to region list */ + STAILQ_INSERT_TAIL(&sc->mem_regions, cr, cr_link); + } + + return (0); +} + +/* Initialize memory state for all chipc port regions */ +static int +chipc_init_rman(struct chipc_softc *sc) +{ + u_int num_ports; + int error; + + /* Port types for which we'll register chipc_region mappings */ + bhnd_port_type types[] = { + BHND_PORT_DEVICE + }; + + /* Initialize resource manager */ + sc->mem_rman.rm_start = 0; + sc->mem_rman.rm_end = BUS_SPACE_MAXADDR; + sc->mem_rman.rm_type = RMAN_ARRAY; + sc->mem_rman.rm_descr = "ChipCommon Device Memory"; + if ((error = rman_init(&sc->mem_rman))) { + device_printf(sc->dev, "could not initialize mem_rman: %d\n", + error); + return (error); + } + + /* Populate per-port-region state */ + for (u_int i = 0; i < nitems(types); i++) { + num_ports = bhnd_get_port_count(sc->dev, types[i]); + for (u_int port = 0; port < num_ports; port++) { *** DIFF OUTPUT TRUNCATED AT 1000 LINES ***