From owner-svn-src-head@freebsd.org Sat Sep 3 23:57:19 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 8C12DBCF7E5; Sat, 3 Sep 2016 23:57:19 +0000 (UTC) (envelope-from landonf@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 2EE33D54; Sat, 3 Sep 2016 23:57:19 +0000 (UTC) (envelope-from landonf@FreeBSD.org) Received: from repo.freebsd.org ([127.0.1.37]) by repo.freebsd.org (8.15.2/8.15.2) with ESMTP id u83NvIB8008196; Sat, 3 Sep 2016 23:57:18 GMT (envelope-from landonf@FreeBSD.org) Received: (from landonf@localhost) by repo.freebsd.org (8.15.2/8.15.2/Submit) id u83NvIxf008190; Sat, 3 Sep 2016 23:57:18 GMT (envelope-from landonf@FreeBSD.org) Message-Id: <201609032357.u83NvIxf008190@repo.freebsd.org> X-Authentication-Warning: repo.freebsd.org: landonf set sender to landonf@FreeBSD.org using -f From: "Landon J. Fuller" Date: Sat, 3 Sep 2016 23:57:18 +0000 (UTC) To: src-committers@freebsd.org, svn-src-all@freebsd.org, svn-src-head@freebsd.org Subject: svn commit: r305366 - in head/sys: conf dev/bhnd dev/bhnd/bcma dev/bhnd/bhndb dev/bhnd/siba mips/broadcom modules/bhnd modules/bhnd/bcma modules/bhnd/bcma_bhndb modules/bhnd/siba modules/bhnd/siba_... 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: Sat, 03 Sep 2016 23:57:19 -0000 Author: landonf Date: Sat Sep 3 23:57:17 2016 New Revision: 305366 URL: https://svnweb.freebsd.org/changeset/base/305366 Log: Implement a generic bhnd(4) device enumeration table API. This defines a new bhnd_erom_if API, providing a common interface to device enumeration on siba(4) and bcma(4) devices, for use both in the bhndb bridge and SoC early boot contexts, and migrates mips/broadcom over to the new API. This also replaces the previous adhoc device enumeration support implemented for mips/broadcom. Migration of bhndb to the new API will be implemented in a follow-up commit. - Defined new bhnd_erom_if interface for bhnd(4) device enumeration, along with bcma(4) and siba(4)-specific implementations. - Fixed a minor bug in bhndb that logged an error when we attempted to map the full siba(4) bus space (18000000-17FFFFFF) in the siba EROM parser. - Reverted use of the resource's start address as the ChipCommon enum_addr in bhnd_read_chipid(). When called from bhndb, this address is found within the host address space, resulting in an invalid bridged enum_addr. - Added support for falling back on standard bus_activate_resource() in bhnd_bus_generic_activate_resource(), enabling allocation of the bhnd_erom's bhnd_resource directly from a nexus-attached bhnd(4) device. - Removed BHND_BUS_GET_CORE_TABLE(); it has been replaced by the erom API. - Added support for statically initializing bhnd_erom instances, for use prior to malloc availability. The statically allocated buffer size is verified both at runtime, and via a compile-time assertion (see BHND_EROM_STATIC_BYTES). - bhnd_erom classes are registered within a module via a linker set, allowing mips/broadcom to probe available EROM parser instances without creating a strong reference to bcma/siba-specific symbols. - Migrated mips/broadcom to bhnd_erom_if, replacing the previous MIPS-specific device enumeration implementation. Approved by: adrian (mentor) Differential Revision: https://reviews.freebsd.org/D7748 Added: head/sys/dev/bhnd/bhnd_erom.c (contents, props changed) head/sys/dev/bhnd/bhnd_erom.h (contents, props changed) head/sys/dev/bhnd/bhnd_erom_if.m (contents, props changed) head/sys/dev/bhnd/bhnd_erom_types.h (contents, props changed) head/sys/dev/bhnd/siba/siba_erom.c (contents, props changed) Deleted: head/sys/mips/broadcom/bcm_bcma.c head/sys/mips/broadcom/bcm_siba.c Modified: head/sys/conf/files head/sys/dev/bhnd/bcma/bcma.c head/sys/dev/bhnd/bcma/bcma.h head/sys/dev/bhnd/bcma/bcma_bhndb.c head/sys/dev/bhnd/bcma/bcma_erom.c head/sys/dev/bhnd/bcma/bcma_eromvar.h head/sys/dev/bhnd/bcma/bcma_nexus.c head/sys/dev/bhnd/bcma/bcmavar.h head/sys/dev/bhnd/bhnd.h head/sys/dev/bhnd/bhnd_bus_if.m head/sys/dev/bhnd/bhnd_subr.c head/sys/dev/bhnd/bhndb/bhndb.c head/sys/dev/bhnd/siba/siba.c head/sys/dev/bhnd/siba/siba.h head/sys/dev/bhnd/siba/siba_subr.c head/sys/dev/bhnd/siba/sibareg.h head/sys/dev/bhnd/siba/sibavar.h head/sys/mips/broadcom/bcm_machdep.c head/sys/mips/broadcom/bcm_machdep.h head/sys/mips/broadcom/bcm_pmu.c head/sys/mips/broadcom/files.broadcom head/sys/modules/bhnd/Makefile head/sys/modules/bhnd/bcma/Makefile head/sys/modules/bhnd/bcma_bhndb/Makefile head/sys/modules/bhnd/siba/Makefile head/sys/modules/bhnd/siba_bhndb/Makefile Modified: head/sys/conf/files ============================================================================== --- head/sys/conf/files Sat Sep 3 23:04:56 2016 (r305365) +++ head/sys/conf/files Sat Sep 3 23:57:17 2016 (r305366) @@ -1140,6 +1140,8 @@ dev/bce/if_bce.c optional bce dev/bfe/if_bfe.c optional bfe dev/bge/if_bge.c optional bge dev/bhnd/bhnd.c optional bhnd +dev/bhnd/bhnd_erom.c optional bhnd +dev/bhnd/bhnd_erom_if.m optional bhnd dev/bhnd/bhnd_nexus.c optional bhnd siba_nexus | \ bhnd bcma_nexus dev/bhnd/bhnd_subr.c optional bhnd @@ -1188,6 +1190,7 @@ dev/bhnd/nvram/bhnd_sprom.c optional bh dev/bhnd/nvram/bhnd_sprom_parser.c optional bhnd dev/bhnd/siba/siba.c optional siba bhnd dev/bhnd/siba/siba_bhndb.c optional siba bhnd bhndb +dev/bhnd/siba/siba_erom.c optional siba bhnd dev/bhnd/siba/siba_nexus.c optional siba_nexus siba bhnd dev/bhnd/siba/siba_subr.c optional siba bhnd # Modified: head/sys/dev/bhnd/bcma/bcma.c ============================================================================== --- head/sys/dev/bhnd/bcma/bcma.c Sat Sep 3 23:04:56 2016 (r305365) +++ head/sys/dev/bhnd/bcma/bcma.c Sat Sep 3 23:57:17 2016 (r305366) @@ -45,6 +45,9 @@ __FBSDID("$FreeBSD$"); #include "bcma_eromvar.h" #include +/* RID used when allocating EROM table */ +#define BCMA_EROM_RID 0 + int bcma_probe(device_t dev) { @@ -492,76 +495,35 @@ bcma_free_bhnd_dinfo(device_t dev, struc bcma_free_dinfo(dev, (struct bcma_devinfo *)dinfo); } - -static int -bcma_get_core_table(device_t dev, device_t child, struct bhnd_core_info **cores, - u_int *num_cores) -{ - struct bcma_softc *sc; - struct bcma_erom erom; - const struct bhnd_chipid *cid; - struct resource *r; - int error; - int rid; - - sc = device_get_softc(dev); - - /* Map the EROM table. */ - cid = BHND_BUS_GET_CHIPID(dev, dev); - rid = 0; - r = bus_alloc_resource(dev, SYS_RES_MEMORY, &rid, cid->enum_addr, - cid->enum_addr + BCMA_EROM_TABLE_SIZE, BCMA_EROM_TABLE_SIZE, - RF_ACTIVE); - if (r == NULL) { - device_printf(dev, "failed to allocate EROM resource\n"); - return (ENXIO); - } - - /* Enumerate all declared cores */ - if ((error = bcma_erom_open(&erom, r, BCMA_EROM_TABLE_START))) - goto cleanup; - - error = bcma_erom_get_core_info(&erom, cores, num_cores); - -cleanup: - bus_release_resource(dev, SYS_RES_MEMORY, rid, r); - return (error); -} - /** - * Scan a device enumeration ROM table, adding all valid discovered cores to + * Scan the device enumeration ROM table, adding all valid discovered cores to * the bus. * * @param bus The bcma bus. - * @param erom_res An active resource mapping the EROM core. - * @param erom_offset Base offset of the EROM core's register mapping. */ int -bcma_add_children(device_t bus, struct resource *erom_res, bus_size_t erom_offset) +bcma_add_children(device_t bus) { - struct bcma_erom erom; - struct bcma_corecfg *corecfg; - struct bcma_devinfo *dinfo; - device_t child; - int error; + bhnd_erom_t *erom; + struct bcma_erom *bcma_erom; + const struct bhnd_chipid *cid; + struct bcma_corecfg *corecfg; + struct bcma_devinfo *dinfo; + device_t child; + int error; + cid = BHND_BUS_GET_CHIPID(bus, bus); corecfg = NULL; - /* Initialize our reader */ - error = bcma_erom_open(&erom, erom_res, erom_offset); - if (error) - return (error); + /* Allocate our EROM parser */ + erom = bhnd_erom_alloc(&bcma_erom_parser, bus, BCMA_EROM_RID, + cid->enum_addr); + if (erom == NULL) + return (ENODEV); /* Add all cores. */ - while (!error) { - /* Parse next core */ - error = bcma_erom_parse_corecfg(&erom, &corecfg); - if (error && error == ENOENT) { - return (0); - } else if (error) { - goto failed; - } - + bcma_erom = (struct bcma_erom *)erom; + while ((error = bcma_erom_next_corecfg(bcma_erom, &corecfg)) == 0) { /* Add the child device */ child = BUS_ADD_CHILD(bus, 0, NULL, -1); if (child == NULL) { @@ -588,9 +550,11 @@ bcma_add_children(device_t bus, struct r /* Hit EOF parsing cores? */ if (error == ENOENT) - return (0); + error = 0; failed: + bhnd_erom_free(erom); + if (corecfg != NULL) bcma_free_corecfg(corecfg); @@ -613,7 +577,6 @@ static device_method_t bcma_methods[] = DEVMETHOD(bhnd_bus_find_hostb_device, bcma_find_hostb_device), DEVMETHOD(bhnd_bus_alloc_devinfo, bcma_alloc_bhnd_dinfo), DEVMETHOD(bhnd_bus_free_devinfo, bcma_free_bhnd_dinfo), - DEVMETHOD(bhnd_bus_get_core_table, bcma_get_core_table), DEVMETHOD(bhnd_bus_reset_core, bcma_reset_core), DEVMETHOD(bhnd_bus_suspend_core, bcma_suspend_core), DEVMETHOD(bhnd_bus_read_config, bcma_read_config), Modified: head/sys/dev/bhnd/bcma/bcma.h ============================================================================== --- head/sys/dev/bhnd/bcma/bcma.h Sat Sep 3 23:04:56 2016 (r305365) +++ head/sys/dev/bhnd/bcma/bcma.h Sat Sep 3 23:57:17 2016 (r305366) @@ -45,5 +45,6 @@ */ DECLARE_CLASS(bcma_driver); +DECLARE_CLASS(bcma_erom_parser); -#endif /* _BCMA_BCMA_H_ */ \ No newline at end of file +#endif /* _BCMA_BCMA_H_ */ Modified: head/sys/dev/bhnd/bcma/bcma_bhndb.c ============================================================================== --- head/sys/dev/bhnd/bcma/bcma_bhndb.c Sat Sep 3 23:04:56 2016 (r305365) +++ head/sys/dev/bhnd/bcma/bcma_bhndb.c Sat Sep 3 23:57:17 2016 (r305366) @@ -73,29 +73,12 @@ static int bcma_bhndb_attach(device_t dev) { struct bcma_softc *sc; - const struct bhnd_chipid *cid; - struct resource *erom_res; int error; - int rid; sc = device_get_softc(dev); - /* Map the EROM resource and enumerate our children. */ - cid = BHNDB_GET_CHIPID(device_get_parent(dev), dev); - rid = 0; - erom_res = bus_alloc_resource(dev, SYS_RES_MEMORY, &rid, cid->enum_addr, - cid->enum_addr + BCMA_EROM_TABLE_SIZE, BCMA_EROM_TABLE_SIZE, - RF_ACTIVE); - if (erom_res == NULL) { - device_printf(dev, "failed to allocate EROM resource\n"); - return (ENXIO); - } - - error = bcma_add_children(dev, erom_res, BCMA_EROM_TABLE_START); - - /* Clean up */ - bus_release_resource(dev, SYS_RES_MEMORY, rid, erom_res); - if (error) + /* Enumerate our children. */ + if ((error = bcma_add_children(dev))) return (error); /* Initialize full bridge configuration */ Modified: head/sys/dev/bhnd/bcma/bcma_erom.c ============================================================================== --- head/sys/dev/bhnd/bcma/bcma_erom.c Sat Sep 3 23:04:56 2016 (r305365) +++ head/sys/dev/bhnd/bcma/bcma_erom.c Sat Sep 3 23:57:17 2016 (r305366) @@ -39,6 +39,8 @@ __FBSDID("$FreeBSD$"); #include #include +#include + #include "bcma_eromreg.h" #include "bcma_eromvar.h" @@ -56,17 +58,43 @@ __FBSDID("$FreeBSD$"); * marker. */ -static const char *erom_entry_type_name (uint8_t entry); -static int erom_read32(struct bcma_erom *erom, uint32_t *entry); -static int erom_skip32(struct bcma_erom *erom); - -static int erom_skip_core(struct bcma_erom *erom); -static int erom_skip_mport(struct bcma_erom *erom); -static int erom_skip_sport_region(struct bcma_erom *erom); - -static int erom_seek_next(struct bcma_erom *erom, uint8_t etype); -static int erom_region_to_port_type(struct bcma_erom *erom, - uint8_t region_type, bhnd_port_type *port_type); +static const char *bcma_erom_entry_type_name (uint8_t entry); +static int bcma_erom_read32(struct bcma_erom *erom, + uint32_t *entry); +static int bcma_erom_skip32(struct bcma_erom *erom); + +static int bcma_erom_skip_core(struct bcma_erom *erom); +static int bcma_erom_skip_mport(struct bcma_erom *erom); +static int bcma_erom_skip_sport_region(struct bcma_erom *erom); + +static int bcma_erom_seek_next(struct bcma_erom *erom, + uint8_t etype); +static int bcma_erom_region_to_port_type(struct bcma_erom *erom, + uint8_t region_type, bhnd_port_type *port_type); + +static int bcma_erom_peek32(struct bcma_erom *erom, + uint32_t *entry); +static bus_size_t bcma_erom_tell(struct bcma_erom *erom); +static void bcma_erom_seek(struct bcma_erom *erom, + bus_size_t offset); +static void bcma_erom_reset(struct bcma_erom *erom); + +static int bcma_erom_seek_matching_core(struct bcma_erom *sc, + const struct bhnd_core_match *desc, + struct bhnd_core_info *core); + +static int bcma_erom_parse_core(struct bcma_erom *erom, + struct bcma_erom_core *core); + +static int bcma_erom_parse_mport(struct bcma_erom *erom, + struct bcma_erom_mport *mport); + +static int bcma_erom_parse_sport_region(struct bcma_erom *erom, + struct bcma_erom_sport_region *region); + +static void bcma_erom_to_core_info(const struct bcma_erom_core *core, + u_int core_idx, int core_unit, + struct bhnd_core_info *info); #define EROM_LOG(erom, fmt, ...) do { \ if (erom->dev != NULL) { \ @@ -78,58 +106,10 @@ static int erom_region_to_port_type(st } \ } while(0) -/** - * Open an EROM table for reading. - * - * @param[out] erom On success, will be populated with a valid EROM - * read state. - * @param r An active resource mapping the EROM core. - * @param offset Offset of the EROM core within @p resource. - * - * @retval 0 success - * @retval non-zero if the erom table could not be opened. - */ -int -bcma_erom_open(struct bcma_erom *erom, struct resource *r, - bus_size_t offset) -{ - return (bhnd_erom_bus_space_open(erom, rman_get_device(r), - rman_get_bustag(r), rman_get_bushandle(r), offset)); - - return (0); -} - -/** - * Open an EROM table for reading using the provided bus space tag and - * handle. - * - * @param[out] erom On success, will be populated with a valid EROM - * read state. - * @param dev The owning device, or NULL if none. - * @param bst EROM table bus space tag. - * @param bsh EROM table bus space handle. - * @param offset Offset of the EROM core from @p resource. - * - * @retval 0 success - * @retval non-zero if the erom table could not be opened. - */ -int -bhnd_erom_bus_space_open(struct bcma_erom *erom, device_t dev, - bus_space_tag_t bst, bus_space_handle_t bsh, bus_size_t offset) -{ - /* Initialize the EROM reader */ - erom->dev = dev; - erom->bst = bst; - erom->bsh = bsh; - erom->start = offset + BCMA_EROM_TABLE_START; - erom->offset = 0; - - return (0); -} /** Return the type name for an EROM entry */ static const char * -erom_entry_type_name (uint8_t entry) +bcma_erom_entry_type_name (uint8_t entry) { switch (BCMA_EROM_GET_ATTR(entry, ENTRY_TYPE)) { case BCMA_EROM_ENTRY_TYPE_CORE: @@ -143,10 +123,340 @@ erom_entry_type_name (uint8_t entry) } } +static int +bcma_erom_init(bhnd_erom_t *erom, device_t parent, int rid, bus_addr_t enum_addr) +{ + struct bcma_erom *sc = (struct bcma_erom *)erom; + + sc->dev = parent; + + sc->rid = rid; + sc->res = bhnd_alloc_resource(parent, SYS_RES_MEMORY, &sc->rid, + enum_addr, enum_addr + BCMA_EROM_TABLE_SIZE - 1, + BCMA_EROM_TABLE_SIZE, RF_ACTIVE|RF_SHAREABLE); + if (sc->res == NULL) + return (ENOMEM); + + sc->start = BCMA_EROM_TABLE_START; + sc->offset = 0; + + return (0); +} + +static int +bcma_erom_probe_static(bhnd_erom_class_t *cls, bus_space_tag_t bst, + bus_space_handle_t bsh, bus_addr_t paddr, struct bhnd_chipid *cid) +{ + uint32_t idreg, eaddr; + uint8_t chip_type; + + idreg = bus_space_read_4(bst, bsh, CHIPC_ID); + chip_type = CHIPC_GET_BITS(idreg, CHIPC_ID_BUS); + + /* Fetch EROM physical address */ + if (!BHND_CHIPTYPE_HAS_EROM(chip_type)) + return (ENXIO); + + eaddr = bus_space_read_4(bst, bsh, CHIPC_EROMPTR); + + /* Parse chip identifier */ + *cid = bhnd_parse_chipid(idreg, eaddr); + + /* Verify chip type */ + switch (chip_type) { + case BHND_CHIPTYPE_BCMA: + return (BUS_PROBE_DEFAULT); + + case BHND_CHIPTYPE_BCMA_ALT: + case BHND_CHIPTYPE_UBUS: + return (BUS_PROBE_GENERIC); + + default: + return (ENXIO); + } +} + +static int +bcma_erom_init_static(bhnd_erom_t *erom, bus_space_tag_t bst, + bus_space_handle_t bsh) +{ + struct bcma_erom *sc = (struct bcma_erom *)erom; + + sc->dev = NULL; + sc->rid = -1; + sc->res = NULL; + sc->bst = bst; + sc->bsh = bsh; + sc->start = BCMA_EROM_TABLE_START; + sc->offset = 0; + + return (0); +} + +static void +bcma_erom_fini(bhnd_erom_t *erom) +{ + struct bcma_erom *sc = (struct bcma_erom *)erom; + + if (sc->res != NULL) { + bhnd_release_resource(sc->dev, SYS_RES_MEMORY, sc->rid, + sc->res); + + sc->res = NULL; + sc->rid = -1; + } +} + +static int +bcma_erom_lookup_core(bhnd_erom_t *erom, const struct bhnd_core_match *desc, + struct bhnd_core_info *core) +{ + struct bcma_erom *sc = (struct bcma_erom *)erom; + + /* Search for the first matching core */ + return (bcma_erom_seek_matching_core(sc, desc, core)); +} + +static int +bcma_erom_lookup_core_addr(bhnd_erom_t *erom, const struct bhnd_core_match *desc, + bhnd_port_type port_type, u_int port_num, u_int region_num, + struct bhnd_core_info *core, bhnd_addr_t *addr, bhnd_size_t *size) +{ + struct bcma_erom *sc; + struct bcma_erom_core ec; + uint32_t entry; + uint8_t region_port, region_type; + bool found; + int error; + + sc = (struct bcma_erom *)erom; + + /* Seek to the first matching core and provide the core info + * to the caller */ + if ((error = bcma_erom_seek_matching_core(sc, desc, core))) + return (error); + + if ((error = bcma_erom_parse_core(sc, &ec))) + return (error); + + /* Skip master ports */ + for (u_long i = 0; i < ec.num_mport; i++) { + if ((error = bcma_erom_skip_mport(sc))) + return (error); + } + + /* Seek to the region block for the given port type */ + found = false; + while (1) { + bhnd_port_type p_type; + uint8_t r_type; + + if ((error = bcma_erom_peek32(sc, &entry))) + return (error); + + if (!BCMA_EROM_ENTRY_IS(entry, REGION)) + return (ENOENT); + + /* Expected region type? */ + r_type = BCMA_EROM_GET_ATTR(entry, REGION_TYPE); + error = bcma_erom_region_to_port_type(sc, r_type, &p_type); + if (error) + return (error); + + if (p_type == port_type) { + found = true; + break; + } + + /* Skip to next entry */ + if ((error = bcma_erom_skip_sport_region(sc))) + return (error); + } + + if (!found) + return (ENOENT); + + /* Found the appropriate port type block; now find the region records + * for the given port number */ + found = false; + for (u_int i = 0; i <= port_num; i++) { + bhnd_port_type p_type; + + if ((error = bcma_erom_peek32(sc, &entry))) + return (error); + + if (!BCMA_EROM_ENTRY_IS(entry, REGION)) + return (ENOENT); + + /* Fetch the type/port of the first region entry */ + region_type = BCMA_EROM_GET_ATTR(entry, REGION_TYPE); + region_port = BCMA_EROM_GET_ATTR(entry, REGION_PORT); + + /* Have we found the region entries for the desired port? */ + if (i == port_num) { + error = bcma_erom_region_to_port_type(sc, region_type, + &p_type); + if (error) + return (error); + + if (p_type == port_type) + found = true; + + break; + } + + /* Otherwise, seek to next block of region records */ + while (1) { + uint8_t next_type, next_port; + + if ((error = bcma_erom_skip_sport_region(sc))) + return (error); + + if ((error = bcma_erom_peek32(sc, &entry))) + return (error); + + if (!BCMA_EROM_ENTRY_IS(entry, REGION)) + return (ENOENT); + + next_type = BCMA_EROM_GET_ATTR(entry, REGION_TYPE); + next_port = BCMA_EROM_GET_ATTR(entry, REGION_PORT); + + if (next_type != region_type || + next_port != region_port) + break; + } + } + + if (!found) + return (ENOENT); + + /* Finally, search for the requested region number */ + for (u_int i = 0; i <= region_num; i++) { + struct bcma_erom_sport_region region; + uint8_t next_port, next_type; + + if ((error = bcma_erom_peek32(sc, &entry))) + return (error); + + if (!BCMA_EROM_ENTRY_IS(entry, REGION)) + return (ENOENT); + + /* Check for the end of the region block */ + next_type = BCMA_EROM_GET_ATTR(entry, REGION_TYPE); + next_port = BCMA_EROM_GET_ATTR(entry, REGION_PORT); + + if (next_type != region_type || + next_port != region_port) + break; + + /* Parse the region */ + if ((error = bcma_erom_parse_sport_region(sc, ®ion))) + return (error); + + /* Is this our target region_num? */ + if (i == region_num) { + /* Found */ + *addr = region.base_addr; + *size = region.size; + return (0); + } + } + + /* Not found */ + return (ENOENT); +}; + +static int +bcma_erom_get_core_table(bhnd_erom_t *erom, struct bhnd_core_info **cores, + u_int *num_cores) +{ + struct bcma_erom *sc; + struct bhnd_core_info *buffer; + bus_size_t initial_offset; + u_int count; + int error; + + sc = (struct bcma_erom *)erom; + + buffer = NULL; + initial_offset = bcma_erom_tell(sc); + + /* Determine the core count */ + bcma_erom_reset(sc); + for (count = 0, error = 0; !error; count++) { + struct bcma_erom_core core; + + /* Seek to the first readable core entry */ + error = bcma_erom_seek_next(sc, BCMA_EROM_ENTRY_TYPE_CORE); + if (error == ENOENT) + break; + else if (error) + goto cleanup; + + /* Read past the core descriptor */ + if ((error = bcma_erom_parse_core(sc, &core))) + goto cleanup; + } + + /* Allocate our output buffer */ + buffer = malloc(sizeof(struct bhnd_core_info) * count, M_BHND, + M_NOWAIT); + if (buffer == NULL) { + error = ENOMEM; + goto cleanup; + } + + /* Parse all core descriptors */ + bcma_erom_reset(sc); + for (u_int i = 0; i < count; i++) { + struct bcma_erom_core core; + int unit; + + /* Parse the core */ + error = bcma_erom_seek_next(sc, BCMA_EROM_ENTRY_TYPE_CORE); + if (error) + goto cleanup; + + error = bcma_erom_parse_core(sc, &core); + if (error) + goto cleanup; + + /* Determine the unit number */ + unit = 0; + for (u_int j = 0; j < i; j++) { + if (buffer[i].vendor == buffer[j].vendor && + buffer[i].device == buffer[j].device) + unit++; + } + + /* Convert to a bhnd info record */ + bcma_erom_to_core_info(&core, i, unit, &buffer[i]); + } + +cleanup: + if (!error) { + *cores = buffer; + *num_cores = count; + } else { + if (buffer != NULL) + free(buffer, M_BHND); + } + + /* Restore the initial position */ + bcma_erom_seek(sc, initial_offset); + return (error); +} + +static void +bcma_erom_free_core_table(bhnd_erom_t *erom, struct bhnd_core_info *cores) +{ + free(cores, M_BHND); +} + /** * Return the current read position. */ -bus_size_t +static bus_size_t bcma_erom_tell(struct bcma_erom *erom) { return (erom->offset); @@ -155,7 +465,7 @@ bcma_erom_tell(struct bcma_erom *erom) /** * Seek to an absolute read position. */ -void +static void bcma_erom_seek(struct bcma_erom *erom, bus_size_t offset) { erom->offset = offset; @@ -171,16 +481,22 @@ bcma_erom_seek(struct bcma_erom *erom, b * @retval ENOENT The end of the EROM table was reached. * @retval non-zero The read could not be completed. */ -int +static int bcma_erom_peek32(struct bcma_erom *erom, uint32_t *entry) { + bus_size_t off; + if (erom->offset >= BCMA_EROM_TABLE_SIZE) { EROM_LOG(erom, "BCMA EROM table missing terminating EOF\n"); return (EINVAL); } - *entry = bus_space_read_4(erom->bst, erom->bsh, - erom->start + erom->offset); + off = erom->start + erom->offset; + if (erom->res != NULL) + *entry = bhnd_bus_read_4(erom->res, off); + else + *entry = bus_space_read_4(erom->bst, erom->bsh, off); + return (0); } @@ -194,7 +510,7 @@ bcma_erom_peek32(struct bcma_erom *erom, * @retval non-zero The read could not be completed. */ static int -erom_read32(struct bcma_erom *erom, uint32_t *entry) +bcma_erom_read32(struct bcma_erom *erom, uint32_t *entry) { int error; @@ -213,11 +529,11 @@ erom_read32(struct bcma_erom *erom, uint * @retval non-zero The read could not be completed. */ static int -erom_skip32(struct bcma_erom *erom) +bcma_erom_skip32(struct bcma_erom *erom) { uint32_t entry; - return erom_read32(erom, &entry); + return bcma_erom_read32(erom, &entry); } /** @@ -229,7 +545,7 @@ erom_skip32(struct bcma_erom *erom) * @retval non-zero The read could not be completed. */ static int -erom_skip_core(struct bcma_erom *erom) +bcma_erom_skip_core(struct bcma_erom *erom) { struct bcma_erom_core core; return (bcma_erom_parse_core(erom, &core)); @@ -244,7 +560,7 @@ erom_skip_core(struct bcma_erom *erom) * @retval non-zero The read could not be completed. */ static int -erom_skip_mport(struct bcma_erom *erom) +bcma_erom_skip_mport(struct bcma_erom *erom) { struct bcma_erom_mport mp; return (bcma_erom_parse_mport(erom, &mp)); @@ -259,7 +575,7 @@ erom_skip_mport(struct bcma_erom *erom) * @retval non-zero The read could not be completed. */ static int -erom_skip_sport_region(struct bcma_erom *erom) +bcma_erom_skip_sport_region(struct bcma_erom *erom) { struct bcma_erom_sport_region r; return (bcma_erom_parse_sport_region(erom, &r)); @@ -276,7 +592,7 @@ erom_skip_sport_region(struct bcma_erom * @retval non-zero Reading or parsing the descriptor failed. */ static int -erom_seek_next(struct bcma_erom *erom, uint8_t etype) +bcma_erom_seek_next(struct bcma_erom *erom, uint8_t etype) { uint32_t entry; int error; @@ -298,19 +614,19 @@ erom_seek_next(struct bcma_erom *erom, u /* Skip non-matching entry types. */ switch (BCMA_EROM_GET_ATTR(entry, ENTRY_TYPE)) { case BCMA_EROM_ENTRY_TYPE_CORE: - if ((error = erom_skip_core(erom))) + if ((error = bcma_erom_skip_core(erom))) return (error); break; case BCMA_EROM_ENTRY_TYPE_MPORT: - if ((error = erom_skip_mport(erom))) + if ((error = bcma_erom_skip_mport(erom))) return (error); break; case BCMA_EROM_ENTRY_TYPE_REGION: - if ((error = erom_skip_sport_region(erom))) + if ((error = bcma_erom_skip_sport_region(erom))) return (error); break; @@ -328,62 +644,100 @@ erom_seek_next(struct bcma_erom *erom, u * * @param erom EROM read state. */ -void +static void bcma_erom_reset(struct bcma_erom *erom) { erom->offset = 0; } /** - * Seek to the next core entry. - * - * @param erom EROM read state. - * @retval 0 success - * @retval ENOENT The end of the EROM table was reached. - * @retval non-zero Reading or parsing failed. - */ -int -bcma_erom_seek_next_core(struct bcma_erom *erom) -{ - return (erom_seek_next(erom, BCMA_EROM_ENTRY_TYPE_CORE)); -} - -/** - * Seek to the requested core entry. + * Seek to the first core entry matching @p desc. * * @param erom EROM read state. - * @param core_index Index of the core to seek to. + * @param desc The core match descriptor. + * @param[out] core On success, the matching core info. If the core info + * is not desired, a NULL pointer may be provided. * @retval 0 success * @retval ENOENT The end of the EROM table was reached before @p index was * found. * @retval non-zero Reading or parsing failed. */ -int -bcma_erom_seek_core_index(struct bcma_erom *erom, u_int core_index) +static int +bcma_erom_seek_matching_core(struct bcma_erom *sc, + const struct bhnd_core_match *desc, struct bhnd_core_info *core) { - int error; + struct bhnd_core_match imatch; + bus_size_t core_offset, next_offset; + int error; - /* Start search at top of EROM */ - bcma_erom_reset(erom); + /* Seek to table start. */ + bcma_erom_reset(sc); - /* Skip core descriptors till we hit the requested entry */ - for (u_int i = 0; i < core_index; i++) { - struct bcma_erom_core core; + /* We can't determine a core's unit number during the initial scan. */ + imatch = *desc; + imatch.m.match.core_unit = 0; + + /* Locate the first matching core */ + for (u_int i = 0; i < UINT_MAX; i++) { + struct bcma_erom_core ec; + struct bhnd_core_info ci; - /* Read past the core descriptor */ - if ((error = bcma_erom_parse_core(erom, &core))) + /* Seek to the next core */ + error = bcma_erom_seek_next(sc, BCMA_EROM_ENTRY_TYPE_CORE); + if (error) return (error); - /* Seek to the next readable core entry */ - error = erom_seek_next(erom, BCMA_EROM_ENTRY_TYPE_CORE); - if (error) + /* Save the core offset */ + core_offset = bcma_erom_tell(sc); + + /* Parse the core */ + if ((error = bcma_erom_parse_core(sc, &ec))) return (error); + + bcma_erom_to_core_info(&ec, i, 0, &ci); + + /* Check for initial match */ + if (!bhnd_core_matches(&ci, &imatch)) + continue; + + /* Re-scan preceding cores to determine the unit number. */ + next_offset = bcma_erom_tell(sc); + bcma_erom_reset(sc); + for (u_int j = 0; j < i; j++) { + /* Parse the core */ + error = bcma_erom_seek_next(sc, + BCMA_EROM_ENTRY_TYPE_CORE); + if (error) + return (error); + + if ((error = bcma_erom_parse_core(sc, &ec))) + return (error); + + /* Bump the unit number? */ + if (ec.vendor == ci.vendor && ec.device == ci.device) + ci.unit++; + } + + /* Check for full match against now-valid unit number */ + if (!bhnd_core_matches(&ci, desc)) { + /* Reposition to allow reading the next core */ + bcma_erom_seek(sc, next_offset); + continue; + } + + /* Found; seek to the core's initial offset and provide + * the core info to the caller */ + bcma_erom_seek(sc, core_offset); + if (core != NULL) + *core = ci; + + return (0); } - return (0); + /* Not found, or a parse error occured */ + return (error); } - /** * Read the next core descriptor from the EROM table. * @@ -394,14 +748,14 @@ bcma_erom_seek_core_index(struct bcma_er * @retval ENOENT The end of the EROM table was reached. * @retval non-zero Reading or parsing the core descriptor failed. */ -int +static int bcma_erom_parse_core(struct bcma_erom *erom, struct bcma_erom_core *core) { uint32_t entry; int error; /* Parse CoreDescA */ - if ((error = erom_read32(erom, &entry))) + if ((error = bcma_erom_read32(erom, &entry))) return (error); /* Handle EOF */ @@ -410,7 +764,7 @@ bcma_erom_parse_core(struct bcma_erom *e if (!BCMA_EROM_ENTRY_IS(entry, CORE)) { EROM_LOG(erom, "Unexpected EROM entry 0x%x (type=%s)\n", - entry, erom_entry_type_name(entry)); + entry, bcma_erom_entry_type_name(entry)); return (EINVAL); } @@ -419,7 +773,7 @@ bcma_erom_parse_core(struct bcma_erom *e core->device = BCMA_EROM_GET_ATTR(entry, COREA_ID); /* Parse CoreDescB */ - if ((error = erom_read32(erom, &entry))) + if ((error = bcma_erom_read32(erom, &entry))) return (error); if (!BCMA_EROM_ENTRY_IS(entry, CORE)) { @@ -436,153 +790,6 @@ bcma_erom_parse_core(struct bcma_erom *e } /** - * Seek to a region record associated with @p core_index. - * - * @param erom EROM read state. - * @param core_index The index of the core record to be searched. - * @param port_type The port type to search for. - * @param port_num The port number to search for. - * @param region_num The region number to search for. - * @retval 0 success - * @retval ENOENT The requested region was not found. - * @retval non-zero Reading or parsing failed. - */ -int -bcma_erom_seek_core_sport_region(struct bcma_erom *erom, u_int core_index, - bhnd_port_type port_type, u_int port_num, u_int region_num) -{ - struct bcma_erom_core core; - uint32_t entry; - uint8_t region_port, region_type; - bool found; - int error; - - if ((error = bcma_erom_seek_core_index(erom, core_index))) - return (error); - - if ((error = bcma_erom_parse_core(erom, &core))) - return (error); - - /* Skip master ports */ - for (u_long i = 0; i < core.num_mport; i++) { - if ((error = erom_skip_mport(erom))) - return (error); - } - - /* Seek to the region block for the given port type */ - found = false; - while (1) { - bhnd_port_type p_type; - uint8_t r_type; - - if ((error = bcma_erom_peek32(erom, &entry))) - return (error); - - if (!BCMA_EROM_ENTRY_IS(entry, REGION)) - return (ENOENT); - - /* Expected region type? */ - r_type = BCMA_EROM_GET_ATTR(entry, REGION_TYPE); - if ((error = erom_region_to_port_type(erom, r_type, &p_type))) - return (error); - - if (p_type == port_type) { - found = true; *** DIFF OUTPUT TRUNCATED AT 1000 LINES ***