From f3524ec8ed3e8a18683c4a5f9ba2d3db62a136fe Mon Sep 17 00:00:00 2001 From: "Landon J. Fuller" Date: Thu, 29 Mar 2018 19:44:15 +0000 Subject: [PATCH] bhnd(4): include a subset of the ChipCommon capability flags in bhnd_chipid; this provides early access to device capability flags required by bhnd(4) bus and bhndb(4) bridge drivers. --- share/man/man9/bhnd.9 | 16 +++- sys/dev/bhnd/bcma/bcma_erom.c | 17 +--- sys/dev/bhnd/bhnd.h | 22 ++--- sys/dev/bhnd/bhnd_erom.c | 113 ++++++++++++++++++++++ sys/dev/bhnd/bhnd_erom.h | 2 + sys/dev/bhnd/bhnd_eromvar.h | 10 ++ sys/dev/bhnd/bhnd_subr.c | 168 --------------------------------- sys/dev/bhnd/bhndb/bhndb_pci.c | 28 +++++- sys/dev/bhnd/siba/siba_erom.c | 40 ++++++-- 9 files changed, 215 insertions(+), 201 deletions(-) diff --git a/share/man/man9/bhnd.9 b/share/man/man9/bhnd.9 index 5edb3fe905f2..7200e7f7ef20 100644 --- a/share/man/man9/bhnd.9 +++ b/share/man/man9/bhnd.9 @@ -28,7 +28,7 @@ .\" .\" $FreeBSD$ .\" -.Dd January 19, 2018 +.Dd March 26, 2018 .Dt BHND 9 .Os .Sh NAME @@ -1130,6 +1130,10 @@ chip, each of which may require driver workarounds for hardware errata, unpopulated components, etc. .It Fa chip_type The interconnect architecture used by this chip. +.It Fa chip_caps +The +.Nm +capability flags supported by this chip. .It Fa enum_addr The backplane enumeration address. On SSB devices, this will be the base address of the first SSB core. @@ -1156,6 +1160,16 @@ UBUS is not currently supported by .Xr bhnd 4 . .El .Pp +The following +.Fa chip_caps +flags are supported: +.Bl -tag -width ".Dv BHND_CAP_BP64" -offset indent -compact +.It Dv BHND_CAP_BP64 +The backplane supports 64-bit addressing. +.It Dv BHND_CAP_PMU +PMU is present. +.El +.Pp Additional symbolic constants for known .Fa chip_id , .Fa chip_pkg , diff --git a/sys/dev/bhnd/bcma/bcma_erom.c b/sys/dev/bhnd/bcma/bcma_erom.c index 11951c9dc11f..6facbc9a2a37 100644 --- a/sys/dev/bhnd/bcma/bcma_erom.c +++ b/sys/dev/bhnd/bcma/bcma_erom.c @@ -45,7 +45,7 @@ __FBSDID("$FreeBSD$"); #include #include -#include +#include #include "bcma_eromreg.h" #include "bcma_eromvar.h" @@ -168,23 +168,16 @@ static int bcma_erom_probe(bhnd_erom_class_t *cls, struct bhnd_erom_io *eio, const struct bhnd_chipid *hint, struct bhnd_chipid *cid) { - uint32_t idreg, eromptr; + int error; /* Hints aren't supported; all BCMA devices have a ChipCommon * core */ if (hint != NULL) return (EINVAL); - /* Confirm CHIPC_EROMPTR availability */ - idreg = bhnd_erom_io_read(eio, CHIPC_ID, 4); - if (!BHND_CHIPTYPE_HAS_EROM(CHIPC_GET_BITS(idreg, CHIPC_ID_BUS))) - return (ENXIO); - - /* Fetch EROM address */ - eromptr = bhnd_erom_io_read(eio, CHIPC_EROMPTR, 4); - - /* Parse chip identifier */ - *cid = bhnd_parse_chipid(idreg, eromptr); + /* Read and parse chip identification */ + if ((error = bhnd_erom_read_chipid(eio, cid))) + return (error); /* Verify chip type */ switch (cid->chip_type) { diff --git a/sys/dev/bhnd/bhnd.h b/sys/dev/bhnd/bhnd.h index ccdc02a827a1..93e7a304760d 100644 --- a/sys/dev/bhnd/bhnd.h +++ b/sys/dev/bhnd/bhnd.h @@ -219,6 +219,7 @@ struct bhnd_chipid { uint8_t chip_rev; /**< chip revision */ uint8_t chip_pkg; /**< chip package (BHND_PKGID_*) */ uint8_t chip_type; /**< chip type (BHND_CHIPTYPE_*) */ + uint32_t chip_caps; /**< chip capabilities (BHND_CAP_*) */ bhnd_addr_t enum_addr; /**< chip_type-specific enumeration * address; either the siba(4) base @@ -229,6 +230,15 @@ struct bhnd_chipid { * not available. */ }; +/** + * Chip capabilities + */ +enum bhnd_cap { + BHND_CAP_BP64 = (1<<0), /**< Backplane supports 64-bit + * addressing */ + BHND_CAP_PMU = (1<<1), /**< PMU is present */ +}; + /** * A bhnd(4) core descriptor. */ @@ -520,18 +530,6 @@ void bhnd_release_resources(device_t dev, const struct resource_spec *rs, struct bhnd_resource **res); -struct bhnd_chipid bhnd_parse_chipid(uint32_t idreg, - bhnd_addr_t enum_addr); - -int bhnd_chipid_fixed_ncores( - const struct bhnd_chipid *cid, - uint16_t chipc_hwrev, uint8_t *ncores); - -int bhnd_read_chipid(device_t dev, - struct resource_spec *rs, - bus_size_t chipc_offset, - struct bhnd_chipid *result); - void bhnd_set_custom_core_desc(device_t dev, const char *name); void bhnd_set_default_core_desc(device_t dev); diff --git a/sys/dev/bhnd/bhnd_erom.c b/sys/dev/bhnd/bhnd_erom.c index 9eb072cd29df..71e8510d4a5c 100644 --- a/sys/dev/bhnd/bhnd_erom.c +++ b/sys/dev/bhnd/bhnd_erom.c @@ -44,18 +44,26 @@ __FBSDID("$FreeBSD$"); #include #include +#include #include + #include #include +#include + static int bhnd_erom_iores_map(struct bhnd_erom_io *eio, bhnd_addr_t addr, bhnd_size_t size); +static int bhnd_erom_iores_tell(struct bhnd_erom_io *eio, + bhnd_addr_t *addr, bhnd_size_t *size); static uint32_t bhnd_erom_iores_read(struct bhnd_erom_io *eio, bhnd_size_t offset, u_int width); static void bhnd_erom_iores_fini(struct bhnd_erom_io *eio); static int bhnd_erom_iobus_map(struct bhnd_erom_io *eio, bhnd_addr_t addr, bhnd_size_t size); +static int bhnd_erom_iobus_tell(struct bhnd_erom_io *eio, + bhnd_addr_t *addr, bhnd_size_t *size); static uint32_t bhnd_erom_iobus_read(struct bhnd_erom_io *eio, bhnd_size_t offset, u_int width); @@ -248,6 +256,62 @@ bhnd_erom_free(bhnd_erom_t *erom) kobj_delete((kobj_t)erom, M_BHND); } +/** + * Read the chip identification registers mapped by @p eio, popuating @p cid + * with the parsed result + * + * @param eio A bus I/O instance, configured with a mapping + * of the ChipCommon core. + * @param[out] cid On success, the parsed chip identification. + * + * @warning + * On early siba(4) devices, the ChipCommon core does not provide + * a valid CHIPC_ID_NUMCORE field. On these ChipCommon revisions + * (see CHIPC_NCORES_MIN_HWREV()), this function will parse and return + * an invalid `ncores` value. + */ +int +bhnd_erom_read_chipid(struct bhnd_erom_io *eio, struct bhnd_chipid *cid) +{ + bhnd_addr_t cc_addr; + bhnd_size_t cc_size; + uint32_t idreg, cc_caps; + int error; + + /* Fetch ChipCommon address */ + if ((error = bhnd_erom_io_tell(eio, &cc_addr, &cc_size))) + return (error); + + /* Read chip identifier */ + idreg = bhnd_erom_io_read(eio, CHIPC_ID, 4); + + /* Extract the basic chip info */ + cid->chip_id = CHIPC_GET_BITS(idreg, CHIPC_ID_CHIP); + cid->chip_pkg = CHIPC_GET_BITS(idreg, CHIPC_ID_PKG); + cid->chip_rev = CHIPC_GET_BITS(idreg, CHIPC_ID_REV); + cid->chip_type = CHIPC_GET_BITS(idreg, CHIPC_ID_BUS); + cid->ncores = CHIPC_GET_BITS(idreg, CHIPC_ID_NUMCORE); + + /* Populate EROM address */ + if (BHND_CHIPTYPE_HAS_EROM(cid->chip_type)) { + cid->enum_addr = bhnd_erom_io_read(eio, CHIPC_EROMPTR, 4); + } else { + cid->enum_addr = cc_addr; + } + + /* Populate capability flags */ + cc_caps = bhnd_erom_io_read(eio, CHIPC_CAPABILITIES, 4); + cid->chip_caps = 0x0; + + if (cc_caps & CHIPC_CAP_BKPLN64) + cid->chip_caps |= BHND_CAP_BP64; + + if (cc_caps & CHIPC_CAP_PMU) + cid->chip_caps |= BHND_CAP_PMU; + + return (0); +} + /** * Attempt to map @p size bytes at @p addr, replacing any existing @@ -267,6 +331,23 @@ bhnd_erom_io_map(struct bhnd_erom_io *eio, bhnd_addr_t addr, bhnd_size_t size) return (eio->map(eio, addr, size)); } +/** + * Return the address range mapped by @p eio, if any. + * + * @param eio I/O instance state. + * @param[out] addr The address mapped by @p eio. + * @param[out] size The number of bytes mapped at @p addr. + * + * @retval 0 success + * @retval ENXIO if @p eio has no mapping. + */ +int +bhnd_erom_io_tell(struct bhnd_erom_io *eio, bhnd_addr_t *addr, + bhnd_size_t *size) +{ + return (eio->tell(eio, addr, size)); +} + /** * Read a 1, 2, or 4 byte data item from @p eio, at the given @p offset * relative to @p eio's current mapping. @@ -306,6 +387,7 @@ bhnd_erom_iores_new(device_t dev, int rid) iores = malloc(sizeof(*iores), M_BHND, M_WAITOK | M_ZERO); iores->eio.map = bhnd_erom_iores_map; + iores->eio.tell = bhnd_erom_iores_tell; iores->eio.read = bhnd_erom_iores_read; iores->eio.fini = bhnd_erom_iores_fini; @@ -361,6 +443,21 @@ bhnd_erom_iores_map(struct bhnd_erom_io *eio, bhnd_addr_t addr, return (0); } +static int +bhnd_erom_iores_tell(struct bhnd_erom_io *eio, bhnd_addr_t *addr, + bhnd_size_t *size) +{ + struct bhnd_erom_iores *iores = (struct bhnd_erom_iores *)eio; + + if (iores->mapped == NULL) + return (ENXIO); + + *addr = rman_get_start(iores->mapped->res); + *size = rman_get_size(iores->mapped->res); + + return (0); +} + static uint32_t bhnd_erom_iores_read(struct bhnd_erom_io *eio, bhnd_size_t offset, u_int width) { @@ -416,6 +513,7 @@ bhnd_erom_iobus_init(struct bhnd_erom_iobus *iobus, bhnd_addr_t addr, bhnd_size_t size, bus_space_tag_t bst, bus_space_handle_t bsh) { iobus->eio.map = bhnd_erom_iobus_map; + iobus->eio.tell = bhnd_erom_iobus_tell; iobus->eio.read = bhnd_erom_iobus_read; iobus->eio.fini = NULL; @@ -463,6 +561,21 @@ bhnd_erom_iobus_map(struct bhnd_erom_io *eio, bhnd_addr_t addr, return (0); } +static int +bhnd_erom_iobus_tell(struct bhnd_erom_io *eio, bhnd_addr_t *addr, + bhnd_size_t *size) +{ + struct bhnd_erom_iobus *iobus = (struct bhnd_erom_iobus *)eio; + + if (!iobus->mapped) + return (ENXIO); + + *addr = iobus->addr + iobus->offset; + *size = iobus->limit; + + return (0); +} + static uint32_t bhnd_erom_iobus_read(struct bhnd_erom_io *eio, bhnd_size_t offset, u_int width) { diff --git a/sys/dev/bhnd/bhnd_erom.h b/sys/dev/bhnd/bhnd_erom.h index d887f4971784..dcf16a8982ee 100644 --- a/sys/dev/bhnd/bhnd_erom.h +++ b/sys/dev/bhnd/bhnd_erom.h @@ -76,6 +76,8 @@ int bhnd_erom_iobus_init(struct bhnd_erom_iobus *iobus, int bhnd_erom_io_map(struct bhnd_erom_io *eio, bhnd_addr_t addr, bhnd_size_t size); +int bhnd_erom_io_tell(struct bhnd_erom_io *eio, + bhnd_addr_t *addr, bhnd_size_t *size); uint32_t bhnd_erom_io_read(struct bhnd_erom_io *eio, bhnd_size_t offset, u_int width); void bhnd_erom_io_fini(struct bhnd_erom_io *eio); diff --git a/sys/dev/bhnd/bhnd_eromvar.h b/sys/dev/bhnd/bhnd_eromvar.h index c230d1413bc6..a496e404a030 100644 --- a/sys/dev/bhnd/bhnd_eromvar.h +++ b/sys/dev/bhnd/bhnd_eromvar.h @@ -48,6 +48,10 @@ struct bhnd_erom_iobus; typedef int (bhnd_erom_io_map_t)(struct bhnd_erom_io *eio, bhnd_addr_t addr, bhnd_size_t size); +/** @see bhnd_erom_io_tell() */ +typedef int (bhnd_erom_io_tell_t)(struct bhnd_erom_io *eio, + bhnd_addr_t *addr, bhnd_size_t *size); + /** @see bhnd_erom_io_read() */ typedef uint32_t (bhnd_erom_io_read_t)(struct bhnd_erom_io *eio, bhnd_size_t offset, u_int width); @@ -55,11 +59,17 @@ typedef uint32_t (bhnd_erom_io_read_t)(struct bhnd_erom_io *eio, /** @see bhnd_erom_io_fini() */ typedef void (bhnd_erom_io_fini_t)(struct bhnd_erom_io *eio); + +int bhnd_erom_read_chipid(struct bhnd_erom_io *eio, + struct bhnd_chipid *cid); + + /** * Abstract EROM bus I/O support. */ struct bhnd_erom_io { bhnd_erom_io_map_t *map; /**< @see bhnd_erom_io_map() */ + bhnd_erom_io_tell_t *tell; /**< @see bhnd_erom_io_tell() */ bhnd_erom_io_read_t *read; /**< @see bhnd_erom_io_read() */ bhnd_erom_io_fini_t *fini; /**< @see bhnd_erom_io_fini(). May be NULL */ }; diff --git a/sys/dev/bhnd/bhnd_subr.c b/sys/dev/bhnd/bhnd_subr.c index 639153478f73..d8f3b486037c 100644 --- a/sys/dev/bhnd/bhnd_subr.c +++ b/sys/dev/bhnd/bhnd_subr.c @@ -1056,174 +1056,6 @@ bhnd_release_resources(device_t dev, const struct resource_spec *rs, } } -/** - * Parse the CHIPC_ID_* fields from the ChipCommon CHIPC_ID - * register, returning its bhnd_chipid representation. - * - * @param idreg The CHIPC_ID register value. - * @param enum_addr The enumeration address to include in the result. - * - * @warning - * On early siba(4) devices, the ChipCommon core does not provide - * a valid CHIPC_ID_NUMCORE field. On these ChipCommon revisions - * (see CHIPC_NCORES_MIN_HWREV()), this function will parse and return - * an invalid `ncores` value. - */ -struct bhnd_chipid -bhnd_parse_chipid(uint32_t idreg, bhnd_addr_t enum_addr) -{ - struct bhnd_chipid result; - - /* Fetch the basic chip info */ - 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; - - return (result); -} - - -/** - * Determine the correct core count for a chip identification value that - * may contain an invalid core count. - * - * On some early siba(4) devices (see CHIPC_NCORES_MIN_HWREV()), the ChipCommon - * core does not provide a valid CHIPC_ID_NUMCORE field. - * - * @param cid The chip identification to be queried. - * @param chipc_hwrev The hardware revision of the ChipCommon core from which - * @p cid was parsed. - * @param[out] ncores On success, will be set to the correct core count. - * - * @retval 0 If the core count is already correct, or was mapped to a - * a correct value. - * @retval EINVAL If the core count is incorrect, but the chip was not - * recognized. - */ -int -bhnd_chipid_fixed_ncores(const struct bhnd_chipid *cid, uint16_t chipc_hwrev, - uint8_t *ncores) -{ - /* bcma(4), and most siba(4) devices */ - if (CHIPC_NCORES_MIN_HWREV(chipc_hwrev)) { - *ncores = cid->ncores; - return (0); - } - - /* broken siba(4) chipsets */ - switch (cid->chip_id) { - case BHND_CHIPID_BCM4306: - *ncores = 6; - break; - case BHND_CHIPID_BCM4704: - *ncores = 9; - break; - case BHND_CHIPID_BCM5365: - /* - * BCM5365 does support ID_NUMCORE in at least - * some of its revisions, but for unknown - * reasons, Broadcom's drivers always exclude - * the ChipCommon revision (0x5) used by BCM5365 - * from the set of revisions supporting - * ID_NUMCORE, and instead supply a fixed value. - * - * Presumably, at least some of these devices - * shipped with a broken ID_NUMCORE value. - */ - *ncores = 7; - break; - default: - return (EINVAL); - } - - return (0); -} - -/** - * Allocate the resource defined by @p rs via @p dev, use it - * to read the ChipCommon ID register relative to @p chipc_offset, - * then release the resource. - * - * @param dev The device owning @p rs. - * @param rs A resource spec that encompasses the ChipCommon register block. - * @param chipc_offset The offset of the ChipCommon registers within @p rs. - * @param[out] result The chip identification data. - * - * @retval 0 success - * @retval non-zero if the ChipCommon identification data could not be read. - */ -int -bhnd_read_chipid(device_t dev, struct resource_spec *rs, - bus_size_t chipc_offset, struct bhnd_chipid *result) -{ - struct resource *res; - bhnd_addr_t enum_addr; - uint32_t reg; - uint8_t chip_type; - int error, rid, rtype; - - rid = rs->rid; - rtype = rs->type; - error = 0; - - /* Allocate the ChipCommon window resource and fetch the chipid data */ - res = bus_alloc_resource_any(dev, rtype, &rid, RF_ACTIVE); - if (res == NULL) { - device_printf(dev, - "failed to allocate bhnd chipc resource\n"); - return (ENXIO); - } - - /* Fetch the basic chip info */ - reg = bus_read_4(res, chipc_offset + CHIPC_ID); - chip_type = CHIPC_GET_BITS(reg, CHIPC_ID_BUS); - - /* Fetch the EROMPTR */ - if (BHND_CHIPTYPE_HAS_EROM(chip_type)) { - enum_addr = bus_read_4(res, chipc_offset + CHIPC_EROMPTR); - } else if (chip_type == BHND_CHIPTYPE_SIBA) { - /* siba(4) uses the ChipCommon base address as the enumeration - * address */ - enum_addr = BHND_DEFAULT_CHIPC_ADDR; - } else { - device_printf(dev, "unknown chip type %hhu\n", chip_type); - error = ENODEV; - goto cleanup; - } - - *result = bhnd_parse_chipid(reg, enum_addr); - - /* Fix the core count on early siba(4) devices */ - if (chip_type == BHND_CHIPTYPE_SIBA) { - uint32_t idh; - uint16_t chipc_hwrev; - - /* - * We need the ChipCommon revision to determine whether - * the ncore field is valid. - * - * We can safely assume the siba IDHIGH register is mapped - * within the chipc register block. - */ - idh = bus_read_4(res, SB0_REG_ABS(SIBA_CFG0_IDHIGH)); - chipc_hwrev = SIBA_IDH_CORE_REV(idh); - - error = bhnd_chipid_fixed_ncores(result, chipc_hwrev, - &result->ncores); - if (error) - goto cleanup; - } - -cleanup: - /* Clean up */ - bus_release_resource(dev, rtype, rid, res); - return (error); -} - /** * Allocate and return a new per-core PMU clock control/status (clkctl) * instance for @p dev. diff --git a/sys/dev/bhnd/bhndb/bhndb_pci.c b/sys/dev/bhnd/bhndb/bhndb_pci.c index f14b5aea2387..da67c49b9388 100644 --- a/sys/dev/bhnd/bhndb/bhndb_pci.c +++ b/sys/dev/bhnd/bhndb/bhndb_pci.c @@ -125,6 +125,8 @@ static void bhndb_pci_eio_init(struct bhndb_pci_eio *eio, struct bhndb_pci_probe *probe); static int bhndb_pci_eio_map(struct bhnd_erom_io *eio, bhnd_addr_t addr, bhnd_size_t size); +static int bhndb_pci_eio_tell(struct bhnd_erom_io *eio, + bhnd_addr_t *addr, bhnd_size_t *size); static uint32_t bhndb_pci_eio_read(struct bhnd_erom_io *eio, bhnd_size_t offset, u_int width); @@ -144,6 +146,7 @@ static struct bhndb_pci_core bhndb_pci_cores[] = { /* bhndb_pci erom I/O instance state */ struct bhndb_pci_eio { struct bhnd_erom_io eio; + bool mapped; /**< true if a valid mapping exists */ bhnd_addr_t addr; /**< mapped address */ bhnd_size_t size; /**< mapped size */ struct bhndb_pci_probe *probe; /**< borrowed probe reference */ @@ -1667,9 +1670,11 @@ bhndb_pci_eio_init(struct bhndb_pci_eio *pio, struct bhndb_pci_probe *probe) memset(pio, 0, sizeof(*pio)); pio->eio.map = bhndb_pci_eio_map; + pio->eio.tell = bhndb_pci_eio_tell; pio->eio.read = bhndb_pci_eio_read; pio->eio.fini = NULL; + pio->mapped = false; pio->addr = 0; pio->size = 0; pio->probe = probe; @@ -1687,6 +1692,23 @@ bhndb_pci_eio_map(struct bhnd_erom_io *eio, bhnd_addr_t addr, pio->addr = addr; pio->size = size; + pio->mapped = true; + + return (0); +} + +/* bhnd_erom_io_tell() implementation */ +static int +bhndb_pci_eio_tell(struct bhnd_erom_io *eio, bhnd_addr_t *addr, + bhnd_size_t *size) +{ + struct bhndb_pci_eio *pio = (struct bhndb_pci_eio *)eio; + + if (!pio->mapped) + return (ENXIO); + + *addr = pio->addr; + *size = pio->size; return (0); } @@ -1697,12 +1719,16 @@ bhndb_pci_eio_read(struct bhnd_erom_io *eio, bhnd_size_t offset, u_int width) { struct bhndb_pci_eio *pio = (struct bhndb_pci_eio *)eio; + /* Must have a valid mapping */ + if (!pio->mapped) + panic("no active mapping"); + /* The requested subrange must fall within the existing mapped range */ if (offset > pio->size || width > pio->size || pio->size - offset < width) { - return (ENXIO); + panic("invalid offset %#jx", offset); } return (bhndb_pci_probe_read(pio->probe, pio->addr, offset, width)); diff --git a/sys/dev/bhnd/siba/siba_erom.c b/sys/dev/bhnd/siba/siba_erom.c index aa2e554f2e14..08fb68ecdcc6 100644 --- a/sys/dev/bhnd/siba/siba_erom.c +++ b/sys/dev/bhnd/siba/siba_erom.c @@ -42,7 +42,7 @@ __FBSDID("$FreeBSD$"); #include -#include +#include #include @@ -390,7 +390,6 @@ siba_eio_read_chipid(struct siba_erom_io *io, bus_addr_t enum_addr, struct bhnd_chipid *cid) { struct siba_core_id ccid; - uint32_t idreg; int error; /* Identify the chipcommon core */ @@ -409,12 +408,39 @@ siba_eio_read_chipid(struct siba_erom_io *io, bus_addr_t enum_addr, } /* Identify the chipset */ - idreg = siba_eio_read_4(io, 0, CHIPC_ID); - *cid = bhnd_parse_chipid(idreg, enum_addr); + if ((error = bhnd_erom_read_chipid(io->eio, cid))) + return (error); - /* Fix up the core count in-place */ - return (bhnd_chipid_fixed_ncores(cid, ccid.core_info.hwrev, - &cid->ncores)); + /* Do we need to fix up the core count? */ + if (CHIPC_NCORES_MIN_HWREV(ccid.core_info.hwrev)) + return (0); + + switch (cid->chip_id) { + case BHND_CHIPID_BCM4306: + cid->ncores = 6; + break; + case BHND_CHIPID_BCM4704: + cid->ncores = 9; + break; + case BHND_CHIPID_BCM5365: + /* + * BCM5365 does support ID_NUMCORE in at least + * some of its revisions, but for unknown + * reasons, Broadcom's drivers always exclude + * the ChipCommon revision (0x5) used by BCM5365 + * from the set of revisions supporting + * ID_NUMCORE, and instead supply a fixed value. + * + * Presumably, at least some of these devices + * shipped with a broken ID_NUMCORE value. + */ + cid->ncores = 7; + break; + default: + return (EINVAL); + } + + return (0); } static int