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.
This commit is contained in:
Landon J. Fuller 2018-03-29 19:44:15 +00:00
parent 19f74c09b1
commit f3524ec8ed
Notes: svn2git 2020-12-20 02:59:44 +00:00
svn path=/head/; revision=331744
9 changed files with 215 additions and 201 deletions

View file

@ -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 ,

View file

@ -45,7 +45,7 @@ __FBSDID("$FreeBSD$");
#include <machine/bus.h>
#include <machine/resource.h>
#include <dev/bhnd/cores/chipc/chipcreg.h>
#include <dev/bhnd/bhnd_eromvar.h>
#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) {

View file

@ -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);

View file

@ -44,18 +44,26 @@ __FBSDID("$FreeBSD$");
#include <sys/rman.h>
#include <machine/resource.h>
#include <dev/bhnd/bhndreg.h>
#include <dev/bhnd/bhndvar.h>
#include <dev/bhnd/bhnd_erom.h>
#include <dev/bhnd/bhnd_eromvar.h>
#include <dev/bhnd/cores/chipc/chipcreg.h>
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)
{

View file

@ -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);

View file

@ -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 */
};

View file

@ -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.

View file

@ -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));

View file

@ -42,7 +42,7 @@ __FBSDID("$FreeBSD$");
#include <machine/bus.h>
#include <dev/bhnd/bhnd_erom.h>
#include <dev/bhnd/bhnd_eromvar.h>
#include <dev/bhnd/cores/chipc/chipcreg.h>
@ -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