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
This commit is contained in:
Landon J. Fuller 2016-09-03 23:57:17 +00:00
parent cd3912b6be
commit 664a749708
33 changed files with 2050 additions and 1124 deletions

View File

@ -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 bhnd
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
#

View File

@ -45,6 +45,9 @@ __FBSDID("$FreeBSD$");
#include "bcma_eromvar.h"
#include <dev/bhnd/bhnd_core.h>
/* 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, struct bhnd_devinfo *dinfo)
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;
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 resource *erom_res, bus_size_t erom_offse
/* 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),

View File

@ -45,5 +45,6 @@
*/
DECLARE_CLASS(bcma_driver);
DECLARE_CLASS(bcma_erom_parser);
#endif /* _BCMA_BCMA_H_ */

View File

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

File diff suppressed because it is too large Load Diff

View File

@ -33,16 +33,30 @@
#define _BCMA_BCMA_EROMVAR_H_
#include <dev/bhnd/bhnd.h>
#include <dev/bhnd/bhnd_erom.h>
#include "bcmavar.h"
struct bcma_erom;
int bcma_erom_next_corecfg(struct bcma_erom *sc,
struct bcma_corecfg **result);
/**
* EROM read context.
* BCMA EROM per-instance state.
*/
struct bcma_erom {
device_t dev; /**< EROM parent device */
struct bhnd_erom obj;
device_t dev; /**< EROM parent device, or NULL
if none. */
struct bhnd_resource *res; /**< EROM table resource, or
NULL if initialized with
bus space tag and handle */
int rid; /**< EROM table rid, or -1 */
bus_space_tag_t bst; /**< EROM table bus space */
bus_space_handle_t bsh; /**< EROM table bus handle */
bus_size_t start; /**< EROM table offset */
bus_size_t offset; /**< current read offset */
};
@ -76,42 +90,4 @@ struct bcma_erom_sport_region {
bhnd_addr_t size; /**< region size */
};
int bcma_erom_open(struct bcma_erom *erom, struct resource *r,
bus_size_t offset);
int bhnd_erom_bus_space_open(struct bcma_erom *erom, device_t owner,
bus_space_tag_t bst, bus_space_handle_t bsh,
bus_size_t offset);
int bcma_erom_peek32(struct bcma_erom *erom, uint32_t *entry);
bus_size_t bcma_erom_tell(struct bcma_erom *erom);
void bcma_erom_seek(struct bcma_erom *erom, bus_size_t offset);
void bcma_erom_reset(struct bcma_erom *erom);
int bcma_erom_seek_next_core(struct bcma_erom *erom);
int bcma_erom_seek_core_index(struct bcma_erom *erom,
u_int core_index);
int bcma_erom_parse_core(struct bcma_erom *erom,
struct bcma_erom_core *core);
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);
int bcma_erom_parse_mport(struct bcma_erom *erom,
struct bcma_erom_mport *mport);
int bcma_erom_parse_sport_region(struct bcma_erom *erom,
struct bcma_erom_sport_region *region);
void bcma_erom_to_core_info(const struct bcma_erom_core *core,
u_int core_idx, int core_unit, struct bhnd_core_info *info);
int bcma_erom_get_core_info(struct bcma_erom *erom,
struct bhnd_core_info **cores,
u_int *num_cores);
int bcma_erom_parse_corecfg(struct bcma_erom *erom,
struct bcma_corecfg **result);
#endif /* _BCMA_BCMA_EROMVAR_H_ */

View File

@ -91,28 +91,9 @@ bcma_nexus_probe(device_t dev)
static int
bcma_nexus_attach(device_t dev)
{
struct bcma_nexus_softc *sc;
struct resource *erom_res;
int error;
int rid;
sc = device_get_softc(dev);
/* Map the EROM resource and enumerate the bus. */
rid = 0;
erom_res = bus_alloc_resource(dev, SYS_RES_MEMORY, &rid,
sc->bcma_cid.enum_addr,
sc->bcma_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);
bus_release_resource(dev, SYS_RES_MEMORY, rid, erom_res);
if (error)
if ((error = bcma_add_children(dev)))
return (error);
return (bcma_attach(dev));

View File

@ -63,8 +63,7 @@ int bcma_probe(device_t dev);
int bcma_attach(device_t dev);
int bcma_detach(device_t dev);
int bcma_add_children(device_t bus,
struct resource *erom_res, bus_size_t erom_offset);
int bcma_add_children(device_t bus);
struct bcma_sport_list *bcma_corecfg_get_port_list(struct bcma_corecfg *cfg,
bhnd_port_type type);

View File

@ -428,32 +428,6 @@ bhnd_get_chipid(device_t dev) {
return (BHND_BUS_GET_CHIPID(device_get_parent(dev), dev));
};
/**
* Get a list of all cores discoverable on the bhnd bus.
*
* Enumerates all cores discoverable on @p dev, returning the list in
* @p cores and the count in @p num_cores.
*
* The memory allocated for the list should be freed using
* `free(*cores, M_BHND)`. @p cores and @p num_cores are not changed
* when an error is returned.
*
* @param dev A bhnd bus child device.
* @param[out] cores The table of core descriptors.
* @param[out] num_cores The number of core descriptors in @p cores.
*
* @retval 0 success
* @retval non-zero if an error occurs enumerating @p dev, a regular UNIX
* error code should be returned.
*/
static inline int
bhnd_get_core_table(device_t dev, struct bhnd_core_info **cores,
u_int *num_cores)
{
return (BHND_BUS_GET_CORE_TABLE(device_get_parent(dev), dev, cores,
num_cores));
}
/**
* If supported by the chipset, return the clock source for the given clock.
*

View File

@ -56,13 +56,6 @@ CODE {
panic("bhnd_bus_get_chipid unimplemented");
}
static int
bhnd_bus_null_get_core_table(device_t dev, device_t child,
struct bhnd_core_info **cores, u_int *num_cores)
{
panic("bhnd_bus_get_core_table unimplemented");
}
static bhnd_attach_type
bhnd_bus_null_get_attach_type(device_t dev, device_t child)
{
@ -277,32 +270,6 @@ METHOD const struct bhnd_chipid * get_chipid {
device_t child;
} DEFAULT bhnd_bus_null_get_chipid;
/**
* Get a list of all cores discoverable on @p dev.
*
* Enumerates all cores discoverable on @p dev, returning the list in
* @p cores and the count in @p num_cores.
*
* The memory allocated for the list should be freed using
* `free(*cores, M_BHND)`. @p cores and @p num_cores are not changed
* when an error is returned.
*
* @param dev The bhnd bus device.
* @param child The requesting bhnd bus child.
* @param[out] cores The table of core descriptors.
* @param[out] num_cores The number of core descriptors in @p cores.
*
* @retval 0 success
* @retval non-zero if an error occurs enumerating @p dev, a regular UNIX
* error code should be returned.
*/
METHOD int get_core_table {
device_t dev;
device_t child;
struct bhnd_core_info **cores;
u_int *num_cores;
} DEFAULT bhnd_bus_null_get_core_table;
/**
* Return the BHND attachment type of the parent bus.
*

140
sys/dev/bhnd/bhnd_erom.c Normal file
View File

@ -0,0 +1,140 @@
/*-
* Copyright (c) 2016 Landon Fuller <landonf@FreeBSD.org>
* 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 <sys/cdefs.h>
__FBSDID("$FreeBSD$");
#include <sys/param.h>
#include <sys/kobj.h>
#include <dev/bhnd/bhndvar.h>
#include <dev/bhnd/bhnd_erom.h>
/**
* Allocate and return a new device enumeration table parser.
*
* @param cls The parser class for which an instance will be
* allocated.
* @param parent The parent device from which EROM resources should
* be allocated.
* @param rid The resource ID to be used when allocating EROM
* resources.
* @param enum_addr The base address of the device enumeration table.
*
* @retval non-NULL success
* @retval NULL if an error occured allocating or initializing the
* EROM parser.
*/
bhnd_erom_t *
bhnd_erom_alloc(bhnd_erom_class_t *cls, device_t parent, int rid,
bus_addr_t enum_addr)
{
bhnd_erom_t *erom;
int error;
erom = (bhnd_erom_t *)kobj_create((kobj_class_t)cls, M_BHND,
M_WAITOK|M_ZERO);
if ((error = BHND_EROM_INIT(erom, parent, rid, enum_addr))) {
printf("error initializing %s parser at %#jx with "
"rid %d: %d\n", cls->name, (uintmax_t)enum_addr, rid,
error);
kobj_delete((kobj_t)erom, M_BHND);
return (NULL);
}
return (erom);
}
/**
* Perform static initialization of aa device enumeration table parser using
* the provided bus space tag and handle.
*
* This may be used to initialize a caller-allocated erom instance state
* during early boot, prior to malloc availability.
*
* @param cls The parser class for which an instance will be
* allocated.
* @param erom The erom parser instance to initialize.
* @param esize The total available number of bytes allocated for
* @p erom. If this is less than is required by @p cls,
* ENOMEM will be returned.
* @param bst Bus space tag.
* @param bsh Bus space handle mapping the device enumeration
* space.
*
* @retval 0 success
* @retval ENOMEM if @p esize is smaller than required by @p cls.
* @retval non-zero if an error occurs initializing the EROM parser,
* a regular unix error code will be returned.
*/
int
bhnd_erom_init_static(bhnd_erom_class_t *cls, bhnd_erom_t *erom, size_t esize,
bus_space_tag_t bst, bus_space_handle_t bsh)
{
kobj_class_t kcls;
kcls = (kobj_class_t)cls;
/* Verify allocation size */
if (kcls->size > esize)
return (ENOMEM);
/* Perform instance initialization */
kobj_init_static((kobj_t)erom, kcls);
return (BHND_EROM_INIT_STATIC(erom, bst, bsh));
}
/**
* Release any resources held by a @p erom parser previously
* initialized via bhnd_erom_init_static().
*
* @param erom An erom parser instance previously initialized via
* bhnd_erom_init_static().
*/
void
bhnd_erom_fini_static(bhnd_erom_t *erom)
{
return (BHND_EROM_FINI(erom));
}
/**
* Release all resources held by a @p erom parser previously
* allocated via bhnd_erom_alloc().
*
* @param erom An erom parser instance previously allocated via
* bhnd_erom_alloc().
*/
void
bhnd_erom_free(bhnd_erom_t *erom)
{
BHND_EROM_FINI(erom);
kobj_delete((kobj_t)erom, M_BHND);
}

208
sys/dev/bhnd/bhnd_erom.h Normal file
View File

@ -0,0 +1,208 @@
/*-
* Copyright (c) 2015-2016 Landon Fuller <landonf@FreeBSD.org>
* 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.
*
* $FreeBSD$
*/
#ifndef _BHND_EROM_BHND_EROM_H_
#define _BHND_EROM_BHND_EROM_H_
#include <sys/param.h>
#include <sys/kobj.h>
#include <sys/linker_set.h>
#include <dev/bhnd/bhnd.h>
#include <dev/bhnd/bhnd_erom_types.h>
#include "bhnd_erom_if.h"
bhnd_erom_t *bhnd_erom_alloc(bhnd_erom_class_t *cls,
device_t parent, int rid,
bus_addr_t enum_addr);
int bhnd_erom_init_static(bhnd_erom_class_t *cls,
bhnd_erom_t *erom, size_t esize,
bus_space_tag_t bst,
bus_space_handle_t bsh);
void bhnd_erom_fini_static(bhnd_erom_t *erom);
void bhnd_erom_free(bhnd_erom_t *erom);
/**
* Abstract bhnd_erom instance state. Must be first member of all subclass
* instances.
*/
struct bhnd_erom {
KOBJ_FIELDS;
};
/** Number of additional bytes to reserve for statically allocated
* bhnd_erom instances. */
#define BHND_EROM_STATIC_BYTES 64
/**
* A bhnd_erom instance structure large enough to statically allocate
* any known bhnd_erom subclass.
*
* The maximum size of subclasses is verified statically in
* BHND_EROM_DEFINE_CLASS(), and at runtime in bhnd_erom_init_static().
*/
struct bhnd_erom_static {
struct bhnd_erom obj;
uint8_t idata[BHND_EROM_STATIC_BYTES];
};
/** Registered EROM parser class instances. */
SET_DECLARE(bhnd_erom_class_set, bhnd_erom_class_t);
#define BHND_EROM_DEFINE_CLASS(name, classvar, methods, size) \
DEFINE_CLASS_0(name, classvar, methods, size); \
BHND_EROM_CLASS_DEF(classvar); \
_Static_assert(size <= sizeof(struct bhnd_erom_static), \
"cannot statically allocate instance data; " \
"increase BHND_EROM_STATIC_BYTES");
#define BHND_EROM_CLASS_DEF(classvar) DATA_SET(bhnd_erom_class_set, classvar)
/**
* Probe to see if this device enumeration class supports the bhnd bus
* mapped at the given bus space tag and handle, returning a standard
* newbus device probe result (see BUS_PROBE_*) and the probed
* chip identification.
*
* @param cls The parser class to be probed.
* @param bst Bus space tag.
* @param bsh Bus space handle mapping the EXTIF or ChipCommon core.
* @param paddr The physical address of the core mapped by @p bst and
* @p bsh.
* @param[out] cid On success, the probed chip identifier.
*
* @retval 0 if this is the only possible device enumeration
* parser for the probed bus.
* @retval negative if the probe succeeds, a negative value should be
* returned; the parser returning the lowest value will
* be selected to handle device enumeration.
* @retval ENXIO If the bhnd bus type is not handled by this parser.
* @retval positive if an error occurs during probing, a regular unix error
* code should be returned.
*/
static inline int
bhnd_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)
{
return (BHND_EROM_PROBE_STATIC(cls, bst, bsh, paddr, cid));
}
/**
* Parse all cores descriptors in @p erom, returning the array in @p cores and
* the count in @p num_cores.
*
* The memory allocated for the table must be freed via
* bhnd_erom_free_core_table().
*
* @param erom The erom parser to be queried.
* @param[out] cores The table of parsed core descriptors.
* @param[out] num_cores The number of core records in @p cores.
*
* @retval 0 success
* @retval non-zero if an error occurs, a regular unix error code will
* be returned.
*/
static inline int
bhnd_erom_get_core_table(bhnd_erom_t *erom, struct bhnd_core_info **cores,
u_int *num_cores)
{
return (BHND_EROM_GET_CORE_TABLE(erom, cores, num_cores));
}
/**
* Free any memory allocated in a previous call to BHND_EROM_GET_CORE_TABLE().
*
* @param erom The erom parser instance.
* @param cores A core table allocated by @p erom.
*/
static inline void
bhnd_erom_free_core_table(bhnd_erom_t *erom, struct bhnd_core_info *cores)
{
return (BHND_EROM_FREE_CORE_TABLE(erom, cores));
};
/**
* Locate the first core table entry in @p erom that matches @p desc.
*
* @param erom The erom parser to be queried.
* @param desc A core match descriptor.
* @param[out] core On success, the matching core info record.
*
* @retval 0 success
* @retval ENOENT No core matching @p desc was found.
* @retval non-zero Reading or parsing failed.
*/
static inline int
bhnd_erom_lookup_core(bhnd_erom_t *erom, const struct bhnd_core_match *desc,
struct bhnd_core_info *core)
{
return (BHND_EROM_LOOKUP_CORE(erom, desc, core));
}
/**
* Locate the first core table entry in @p erom that matches @p desc,
* and return the specified port region's base address and size.
*
* If a core matching @p desc is not found, or the requested port region
* is not mapped to the matching core, ENOENT is returned.
*
* @param erom The erom parser to be queried.
* @param desc A core match descriptor.
* @param type The port type to search for.
* @param port The port to search for.
* @param region The port region to search for.
* @param[out] core If not NULL, will be populated with the matched core
* info record on success.
* @param[out] addr On success, the base address of the port region.
* @param[out] size On success, the total size of the port region.
*
* @retval 0 success
* @retval ENOENT No core matching @p desc was found.
* @retval ENOENT No port region matching @p type, @p port, and @p region
* was found.
* @retval non-zero Reading or parsing failed.
*/
static inline int
bhnd_erom_lookup_core_addr(bhnd_erom_t *erom, const struct bhnd_core_match *desc,
bhnd_port_type type, u_int port, u_int region, struct bhnd_core_info *core,
bhnd_addr_t *addr, bhnd_size_t *size)
{
return (BHND_EROM_LOOKUP_CORE_ADDR(erom, desc, type, port, region,
core, addr, size));
};
#endif /* _BHND_EROM_BHND_EROM_H_ */

207
sys/dev/bhnd/bhnd_erom_if.m Normal file
View File

@ -0,0 +1,207 @@
#-
# Copyright (c) 2016 Landon Fuller <landon@landonf.org>
# 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.
# 2. Redistributions in binary form must reproduce the above copyright
# notice, this list of conditions and the following disclaimer in the
# documentation and/or other materials provided with the distribution.
#
# THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
# IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
# OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
# IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
# INDIRECT, INCIDENTAL, 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 DAMAGE.
#
# $FreeBSD$
#include <sys/param.h>
#include <sys/bus.h>
#include <machine/bus.h>
#include <sys/rman.h>
#include <machine/resource.h>
#include <dev/bhnd/bhnd.h>
#include <dev/bhnd/bhnd_erom_types.h>
INTERFACE bhnd_erom;
#
# bhnd(4) device enumeration.
#
# Provides a common parser interface to the incompatible device enumeration
# tables used by bhnd(4) buses.
#
/**
* Probe to see if this device enumeration class supports the bhnd bus
* mapped at the given bus space tag and handle, returning a standard
* newbus device probe result (see BUS_PROBE_*) and the probed
* chip identification.
*
* @param cls The erom parse class to probe.
* @param bst Bus space tag.
* @param bsh Bus space handle mapping the EXTIF or ChipCommon core.
* @param paddr The physical address of the core mapped by @p bst and
* @p bsh.
* @param[out] cid On success, the probed chip identifier.
*
* @retval 0 if this is the only possible device enumeration
* parser for the probed bus.
* @retval negative if the probe succeeds, a negative value should be
* returned; the parser returning the highest negative
* value will be selected to handle device enumeration.
* @retval ENXIO If the bhnd bus type is not handled by this parser.
* @retval positive if an error occurs during probing, a regular unix error
* code should be returned.
*/
STATICMETHOD int 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;
};
/**
* Initialize a device enumeration table parser.
*
* @param erom The erom parser to initialize.
* @param parent The parent device from which EROM resources should
* be allocated.
* @param rid The resource id to be used when allocating the
* enumeration table.
* @param enum_addr The base address of the device enumeration table.
*
* @retval 0 success
* @retval non-zero if an error occurs initializing the EROM parser,
* a regular unix error code will be returned.
*/
METHOD int init {
bhnd_erom_t *erom;
device_t parent;
int rid;
bus_addr_t enum_addr;
};
/**
* Initialize an device enumeration table parser using the provided bus space
* tag and handle.
*
* @param erom The erom parser to initialize.
* @param bst Bus space tag.
* @param bsh bus space handle mapping the full bus enumeration
* space.
*
* @retval 0 success
* @retval non-zero if an error occurs initializing the EROM parser,
* a regular unix error code will be returned.
*/
METHOD int init_static {
bhnd_erom_t *erom;
bus_space_tag_t bst;
bus_space_handle_t bsh;
};
/**
* Release all resources held by @p erom.
*
* @param erom An erom parser instance previously initialized via
* BHND_EROM_INIT() or BHND_EROM_INIT_STATIC().
*/
METHOD void fini {
bhnd_erom_t *erom;
};
/**
* Parse all cores descriptors, returning the array in @p cores and the count
* in @p num_cores.
*
* The memory allocated for the table must be freed via
* BHND_EROM_FREE_CORE_TABLE().
*
* @param erom The erom parser to be queried.
* @param[out] cores The table of parsed core descriptors.
* @param[out] num_cores The number of core records in @p cores.
*
* @retval 0 success
* @retval non-zero if an error occurs, a regular unix error code will
* be returned.
*/
METHOD int get_core_table {
bhnd_erom_t *erom;
struct bhnd_core_info **cores;
u_int *num_cores;
};
/**
* Free any memory allocated in a previous call to BHND_EROM_GET_CORE_TABLE().
*
* @param erom The erom parser instance.
* @param cores A core table allocated by @p erom.
*/
METHOD void free_core_table {
bhnd_erom_t *erom;
struct bhnd_core_info *cores;
};
/**
* Locate the first core table entry in @p erom that matches @p desc.
*
* @param erom The erom parser to be queried.
* @param desc A core match descriptor.
* @param[out] core On success, the matching core info record.
*
* @retval 0 success
* @retval ENOENT No core matching @p desc was found.
* @retval non-zero Reading or parsing failed.
*/
METHOD int lookup_core {
bhnd_erom_t *erom;
const struct bhnd_core_match *desc;
struct bhnd_core_info *core;
};
/**
* Locate the first core table entry in @p erom that matches @p desc,
* and return the specified port region's base address and size.
*
* If a core matching @p desc is not found, or the requested port region
* is not mapped to the matching core, ENOENT is returned.
*
* @param erom The erom parser to be queried.
* @param desc A core match descriptor.
* @param type The port type to search for.
* @param port The port to search for.
* @param region The port region to search for.
* @param[out] core If not NULL, will be populated with the matched core
* info record on success.
* @param[out] addr On success, the base address of the port region.
* @param[out] size On success, the total size of the port region.
*
* @retval 0 success
* @retval ENOENT No core matching @p desc was found.
* @retval ENOENT No port region matching @p type, @p port, and @p region
* was found.
* @retval non-zero Reading or parsing failed.
*/
METHOD int lookup_core_addr {
bhnd_erom_t *erom;
const struct bhnd_core_match *desc;
bhnd_port_type type;
u_int port;
u_int region;
struct bhnd_core_info *core;
bhnd_addr_t *addr;
bhnd_size_t *size;
};

View File

@ -0,0 +1,42 @@
/*-
* Copyright (c) 2016 Landon Fuller <landonf@FreeBSD.org>
* 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.
*
* $FreeBSD$
*/
#ifndef _BHND_EROM_BHND_EROM_TYPES_H_
#define _BHND_EROM_BHND_EROM_TYPES_H_
#include <sys/param.h>
#include <sys/kobj.h>
typedef struct kobj_class bhnd_erom_class_t; /**< bhnd_erom parser class */
typedef struct bhnd_erom bhnd_erom_t; /**< bhnd_erom parser instance */
typedef struct bhnd_erom_static bhnd_erom_static_t; /**< bhnd_erom parser static instance data */
#endif /* _BHND_EROM_BHND_EROM_TYPES_H_ */

View File

@ -944,7 +944,7 @@ bhnd_read_chipid(device_t dev, struct resource_spec *rs,
} else if (chip_type == BHND_CHIPTYPE_SIBA) {
/* siba(4) uses the ChipCommon base address as the enumeration
* address */
enum_addr = rman_get_start(res) + chipc_offset;
enum_addr = BHND_DEFAULT_CHIPC_ADDR;
} else {
device_printf(dev, "unknown chip type %hhu\n", chip_type);
error = ENODEV;
@ -1578,19 +1578,41 @@ bhnd_bus_generic_release_resource(device_t dev, device_t child, int type,
/**
* Helper function for implementing BHND_BUS_ACTIVATE_RESOURCE().
*
* This implementation of BHND_BUS_ACTIVATE_RESOURCE() simply calls the
* This implementation of BHND_BUS_ACTIVATE_RESOURCE() first calls the
* BHND_BUS_ACTIVATE_RESOURCE() method of the parent of @p dev.
*
* If this fails, and if @p dev is the direct parent of @p child, standard
* resource activation is attempted via bus_activate_resource(). This enables
* direct use of the bhnd(4) resource APIs on devices that may not be attached
* to a parent bhnd bus or bridge.
*/
int
bhnd_bus_generic_activate_resource(device_t dev, device_t child, int type,
int rid, struct bhnd_resource *r)
{
/* Try to delegate to the parent */
if (device_get_parent(dev) != NULL)
return (BHND_BUS_ACTIVATE_RESOURCE(device_get_parent(dev),
child, type, rid, r));
int error;
bool passthrough;
return (EINVAL);
passthrough = (device_get_parent(child) != dev);
/* Try to delegate to the parent */
if (device_get_parent(dev) != NULL) {
error = BHND_BUS_ACTIVATE_RESOURCE(device_get_parent(dev),
child, type, rid, r);
} else {
error = ENODEV;
}
/* If bhnd(4) activation has failed and we're the child's direct
* parent, try falling back on standard resource activation.
*/
if (error && !passthrough) {
error = bus_activate_resource(child, type, rid, r->res);
if (!error)
r->direct = true;
}
return (error);
};
/**

View File

@ -1328,6 +1328,10 @@ bhndb_retain_dynamic_window(struct bhndb_softc *sc, struct resource *r)
return (NULL);
}
/* Window must be large enough to map the entire resource */
if (dwa->win->win_size < rman_get_size(r))
return (NULL);
/* Set the window target */
error = bhndb_dw_set_addr(sc->dev, sc->bus_res, dwa, rman_get_start(r),
rman_get_size(r));

View File

@ -335,7 +335,7 @@ siba_get_port_count(device_t dev, device_t child, bhnd_port_type type)
type));
dinfo = device_get_ivars(child);
return (siba_addrspace_port_count(dinfo));
return (siba_addrspace_port_count(dinfo->core_id.num_addrspace));
}
static u_int
@ -350,10 +350,11 @@ siba_get_region_count(device_t dev, device_t child, bhnd_port_type type,
type, port));
dinfo = device_get_ivars(child);
if (!siba_is_port_valid(dinfo, type, port))
if (!siba_is_port_valid(dinfo->core_id.num_addrspace, type, port))
return (0);
return (siba_addrspace_region_count(dinfo, port));
return (siba_addrspace_region_count(dinfo->core_id.num_addrspace,
port));
}
static int
@ -441,7 +442,7 @@ siba_get_region_addr(device_t dev, device_t child, bhnd_port_type port_type,
*/
static int
siba_register_addrspaces(device_t dev, struct siba_devinfo *di,
struct resource *r)
struct bhnd_resource *r)
{
struct siba_core_id *cid;
uint32_t addr;
@ -465,7 +466,7 @@ siba_register_addrspaces(device_t dev, struct siba_devinfo *di,
}
/* Fetch the address match register value */
adm = bus_read_4(r, adm_offset);
adm = bhnd_bus_read_4(r, adm_offset);
/* Parse the value */
if ((error = siba_parse_admatch(adm, &addr, &size))) {
@ -504,76 +505,6 @@ siba_free_bhnd_dinfo(device_t dev, struct bhnd_devinfo *dinfo)
siba_free_dinfo(dev, (struct siba_devinfo *)dinfo);
}
static int
siba_get_core_table(device_t dev, device_t child, struct bhnd_core_info **cores,
u_int *num_cores)
{
const struct bhnd_chipid *chipid;
struct bhnd_core_info *table;
struct bhnd_resource *r;
int error;
int rid;
/* Fetch the core count from our chip identification */
chipid = BHND_BUS_GET_CHIPID(dev, dev);
/* Allocate our local core table */
table = malloc(sizeof(*table) * chipid->ncores, M_BHND, M_NOWAIT);
if (table == NULL)
return (ENOMEM);
/* Enumerate all cores. */
for (u_int i = 0; i < chipid->ncores; i++) {
struct siba_core_id cid;
uint32_t idhigh, idlow;
/* Map the core's register block */
rid = 0;
r = bhnd_alloc_resource(dev, SYS_RES_MEMORY, &rid,
SIBA_CORE_ADDR(i), SIBA_CORE_ADDR(i) + SIBA_CORE_SIZE - 1,
SIBA_CORE_SIZE, RF_ACTIVE);
if (r == NULL) {
error = ENXIO;
goto failed;
}
/* Read the core info */
idhigh = bhnd_bus_read_4(r, SB0_REG_ABS(SIBA_CFG0_IDHIGH));
idlow = bhnd_bus_read_4(r, SB0_REG_ABS(SIBA_CFG0_IDLOW));
cid = siba_parse_core_id(idhigh, idlow, i, 0);
table[i] = cid.core_info;
/* Determine unit number */
for (u_int j = 0; j < i; j++) {
if (table[j].vendor == table[i].vendor &&
table[j].device == table[i].device)
table[i].unit++;
}
/* Release our resource */
bhnd_release_resource(dev, SYS_RES_MEMORY, rid, r);
r = NULL;
}
/* Provide the result values (performed last to avoid modifying
* cores/num_cores if enumeration failed). */
*cores = table;
*num_cores = chipid->ncores;
return (0);
failed:
if (table != NULL)
free(table, M_BHND);
if (r != NULL)
bhnd_release_resource(dev, SYS_RES_MEMORY, rid, r);
return (error);
}
/**
* Scan the core table and add all valid discovered cores to
* the bus.
@ -588,7 +519,7 @@ siba_add_children(device_t dev, const struct bhnd_chipid *chipid)
struct bhnd_chipid ccid;
struct bhnd_core_info *cores;
struct siba_devinfo *dinfo;
struct resource *r;
struct bhnd_resource *r;
int rid;
int error;
@ -612,13 +543,13 @@ siba_add_children(device_t dev, const struct bhnd_chipid *chipid)
/* Map the first core's register block. If the ChipCommon core
* exists, it will always be the first core. */
rid = 0;
r = bus_alloc_resource(dev, SYS_RES_MEMORY, &rid,
r = bhnd_alloc_resource(dev, SYS_RES_MEMORY, &rid,
SIBA_CORE_ADDR(0), SIBA_CORE_SIZE,
SIBA_CORE_ADDR(0) + SIBA_CORE_SIZE - 1,
RF_ACTIVE);
/* Identify the core */
idhigh = bus_read_4(r, SB0_REG_ABS(SIBA_CFG0_IDHIGH));
idhigh = bhnd_bus_read_4(r, SB0_REG_ABS(SIBA_CFG0_IDHIGH));
vendor = SIBA_REG_GET(idhigh, IDH_VENDOR);
device = SIBA_REG_GET(idhigh, IDH_DEVICE);
ccrev = SIBA_IDH_CORE_REV(idhigh);
@ -632,7 +563,7 @@ siba_add_children(device_t dev, const struct bhnd_chipid *chipid)
}
/* Identify the chipset */
ccreg = bus_read_4(r, CHIPC_ID);
ccreg = bhnd_bus_read_4(r, CHIPC_ID);
ccid = bhnd_parse_chipid(ccreg, SIBA_ENUM_ADDR);
/* Fix up the core count */
@ -644,7 +575,7 @@ siba_add_children(device_t dev, const struct bhnd_chipid *chipid)
}
chipid = &ccid;
bus_release_resource(dev, SYS_RES_MEMORY, rid, r);
bhnd_release_resource(dev, SYS_RES_MEMORY, rid, r);
}
/* Allocate our temporary core table and enumerate all cores */
@ -664,7 +595,7 @@ siba_add_children(device_t dev, const struct bhnd_chipid *chipid)
r_start = SIBA_CORE_ADDR(i);
r_count = SIBA_CORE_SIZE;
r_end = r_start + SIBA_CORE_SIZE - 1;
r = bus_alloc_resource(dev, SYS_RES_MEMORY, &rid, r_start,
r = bhnd_alloc_resource(dev, SYS_RES_MEMORY, &rid, r_start,
r_end, r_count, RF_ACTIVE);
if (r == NULL) {
error = ENXIO;
@ -679,8 +610,8 @@ siba_add_children(device_t dev, const struct bhnd_chipid *chipid)
}
/* Read the core info */
idhigh = bus_read_4(r, SB0_REG_ABS(SIBA_CFG0_IDHIGH));
idlow = bus_read_4(r, SB0_REG_ABS(SIBA_CFG0_IDLOW));
idhigh = bhnd_bus_read_4(r, SB0_REG_ABS(SIBA_CFG0_IDHIGH));
idlow = bhnd_bus_read_4(r, SB0_REG_ABS(SIBA_CFG0_IDLOW));
cid = siba_parse_core_id(idhigh, idlow, i, 0);
cores[i] = cid.core_info;
@ -711,7 +642,7 @@ siba_add_children(device_t dev, const struct bhnd_chipid *chipid)
device_disable(child);
/* Release our resource */
bus_release_resource(dev, SYS_RES_MEMORY, rid, r);
bhnd_release_resource(dev, SYS_RES_MEMORY, rid, r);
r = NULL;
/* Issue bus callback for fully initialized child. */
@ -723,7 +654,7 @@ siba_add_children(device_t dev, const struct bhnd_chipid *chipid)
free(cores, M_BHND);
if (r != NULL)
bus_release_resource(dev, SYS_RES_MEMORY, rid, r);
bhnd_release_resource(dev, SYS_RES_MEMORY, rid, r);
return (error);
}
@ -743,7 +674,6 @@ static device_method_t siba_methods[] = {
/* BHND interface */
DEVMETHOD(bhnd_bus_find_hostb_device, siba_find_hostb_device),
DEVMETHOD(bhnd_bus_get_core_table, siba_get_core_table),
DEVMETHOD(bhnd_bus_alloc_devinfo, siba_alloc_bhnd_dinfo),
DEVMETHOD(bhnd_bus_free_devinfo, siba_free_bhnd_dinfo),
DEVMETHOD(bhnd_bus_reset_core, siba_reset_core),

View File

@ -45,5 +45,6 @@
*/
DECLARE_CLASS(siba_driver);
DECLARE_CLASS(siba_erom_parser);
#endif /* _SIBA_SIBA_H_ */

View File

@ -0,0 +1,420 @@
/*-
* Copyright (c) 2015-2016 Landon Fuller <landonf@FreeBSD.org>
* 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 <sys/cdefs.h>
__FBSDID("$FreeBSD$");
#include <sys/param.h>
#include <sys/bus.h>
#include <sys/kernel.h>
#include <sys/malloc.h>
#include <sys/module.h>
#include <machine/bus.h>
#include <dev/bhnd/bhnd_erom.h>
#include <dev/bhnd/cores/chipc/chipcreg.h>
#include "sibareg.h"
#include "sibavar.h"
struct siba_erom;
static int siba_erom_init_static(bhnd_erom_t *erom, bus_space_tag_t bst,
bus_space_handle_t bsh);
static void siba_erom_fini(bhnd_erom_t *erom);
static uint32_t siba_erom_read_4(struct siba_erom *sc, u_int core_idx,
bus_size_t offset);
static int siba_erom_read_chipid(struct siba_erom *sc,
bus_addr_t enum_addr, struct bhnd_chipid *cid);
struct siba_erom {
struct bhnd_erom obj;
u_int ncores; /**< core count */
/* resource state */
device_t dev; /**< parent dev to use for resource allocations,
or NULL if initialized with bst/bsh */
struct bhnd_resource *res; /**< siba bus mapping, or NULL */
int rid; /**< siba bus maping resource ID */
/* bus tag state */
bus_space_tag_t bst; /**< chipc bus tag */
bus_space_handle_t bsh; /**< chipc bus handle */
};
#define EROM_LOG(sc, fmt, ...) do { \
if (sc->dev != NULL) { \
device_printf(sc->dev, "%s: " fmt, __FUNCTION__, \
##__VA_ARGS__); \
} else { \
printf("%s: " fmt, __FUNCTION__, ##__VA_ARGS__); \
} \
} while(0)
static uint32_t
siba_erom_read_4(struct siba_erom *sc, u_int core_idx, bus_size_t offset)
{
bus_size_t core_offset;
/* Sanity check core index and offset */
if (core_idx >= sc->ncores)
panic("core index %u out of range (ncores=%u)", core_idx,
sc->ncores);
if (offset > SIBA_CORE_SIZE - sizeof(uint32_t))
panic("invalid core offset %#jx", (uintmax_t)offset);
/* Perform read */
core_offset = SIBA_CORE_OFFSET(core_idx) + offset;
if (sc->res != NULL)
return (bhnd_bus_read_4(sc->res, core_offset));
else
return (bus_space_read_4(sc->bst, sc->bsh, core_offset));
}
/** Fetch and parse a siba core's identification registers */
static struct siba_core_id
siba_erom_parse_core_id(struct siba_erom *sc, u_int core_idx, int unit)
{
uint32_t idhigh, idlow;
idhigh = siba_erom_read_4(sc, core_idx, SB0_REG_ABS(SIBA_CFG0_IDHIGH));
idlow = siba_erom_read_4(sc, core_idx, SB0_REG_ABS(SIBA_CFG0_IDLOW));
return (siba_parse_core_id(idhigh, idlow, core_idx, unit));
}
/** Fetch and parse the chip identification register */
static int
siba_erom_read_chipid(struct siba_erom *sc, bus_addr_t enum_addr,
struct bhnd_chipid *cid)
{
struct siba_core_id ccid;
uint32_t idreg;
/* Identify the chipcommon core */
ccid = siba_erom_parse_core_id(sc, 0, 0);
if (ccid.core_info.vendor != BHND_MFGID_BCM ||
ccid.core_info.device != BHND_COREID_CC)
{
EROM_LOG(sc,
"first core not chipcommon (vendor=%#hx, core=%#hx)\n",
ccid.core_info.vendor, ccid.core_info.device);
return (ENXIO);
}
/* Identify the chipset */
idreg = siba_erom_read_4(sc, 0, CHIPC_ID);
*cid = bhnd_parse_chipid(idreg, enum_addr);
/* Fix up the core count in-place */
return (bhnd_chipid_fixed_ncores(cid, ccid.core_info.hwrev,
&cid->ncores));
}
static int
siba_erom_init_common(struct siba_erom *sc)
{
struct bhnd_chipid cid;
int error;
/* There's always at least one core */
sc->ncores = 1;
/* Identify the chipset */
if ((error = siba_erom_read_chipid(sc, SIBA_ENUM_ADDR, &cid)))
return (error);
/* Verify the chip type */
if (cid.chip_type != BHND_CHIPTYPE_SIBA)
return (ENXIO);
/*
* gcc hack: ensure bhnd_chipid.ncores cannot exceed SIBA_MAX_CORES
* without triggering build failure due to -Wtype-limits
*
* if (cid.ncores > SIBA_MAX_CORES)
* return (EINVAL)
*/
_Static_assert((2^sizeof(cid.ncores)) <= SIBA_MAX_CORES,
"ncores could result in over-read of backing resource");
/* Update our core count */
sc->ncores = cid.ncores;
return (0);
}
static int
siba_erom_init(bhnd_erom_t *erom, device_t parent, int rid,
bus_addr_t enum_addr)
{
struct siba_erom *sc = (struct siba_erom *)erom;
sc->dev = parent;
sc->rid = rid;
sc->res = bhnd_alloc_resource(sc->dev, SYS_RES_MEMORY, &sc->rid,
enum_addr, enum_addr + SIBA_ENUM_SIZE -1, SIBA_ENUM_SIZE,
RF_ACTIVE|RF_SHAREABLE);
if (sc->res == NULL)
return (ENOMEM);
return (siba_erom_init_common(sc));
}
static int
siba_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)
{
struct siba_erom sc;
uint32_t idreg;
uint8_t chip_type;
int error;
idreg = bus_space_read_4(bst, bsh, CHIPC_ID);
chip_type = CHIPC_GET_BITS(idreg, CHIPC_ID_BUS);
if (chip_type != BHND_CHIPTYPE_SIBA)
return (ENXIO);
/* Initialize a static EROM instance that we can use to fetch
* the chip identifier */
if ((error = siba_erom_init_static((bhnd_erom_t *)&sc, bst, bsh)))
return (error);
/* Try to read the chip ID, clean up the static instance */
error = siba_erom_read_chipid(&sc, paddr, cid);
siba_erom_fini((bhnd_erom_t *)&sc);
if (error)
return (error);
return (BUS_PROBE_DEFAULT);
}
static int
siba_erom_init_static(bhnd_erom_t *erom, bus_space_tag_t bst,
bus_space_handle_t bsh)
{
struct siba_erom *sc = (struct siba_erom *)erom;
sc->dev = NULL;
sc->rid = -1;
sc->res = NULL;
sc->bst = bst;
sc->bsh = bsh;
return (siba_erom_init_common(sc));
}
static void
siba_erom_fini(bhnd_erom_t *erom)
{
struct siba_erom *sc = (struct siba_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
siba_erom_lookup_core(bhnd_erom_t *erom, const struct bhnd_core_match *desc,
struct bhnd_core_info *core)
{
struct siba_erom *sc;
struct bhnd_core_match imatch;
sc = (struct siba_erom *)erom;
/* 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 < sc->ncores; i++) {
struct siba_core_id sid;
struct bhnd_core_info ci;
/* Read the core info */
sid = siba_erom_parse_core_id(sc, i, 0);
ci = sid.core_info;
/* Check for initial match */
if (!bhnd_core_matches(&ci, &imatch))
continue;
/* Re-scan preceding cores to determine the unit number. */
for (u_int j = 0; j < i; j++) {
sid = siba_erom_parse_core_id(sc, i, 0);
/* Bump the unit number? */
if (sid.core_info.vendor == ci.vendor &&
sid.core_info.device == ci.device)
ci.unit++;
}
/* Check for full match against now-valid unit number */
if (!bhnd_core_matches(&ci, desc))
continue;
/* Matching core found */
*core = ci;
return (0);
}
/* Not found */
return (ENOENT);
}
static int
siba_erom_lookup_core_addr(bhnd_erom_t *erom, const struct bhnd_core_match *desc,
bhnd_port_type type, u_int port, u_int region, struct bhnd_core_info *info,
bhnd_addr_t *addr, bhnd_size_t *size)
{
struct siba_erom *sc;
struct bhnd_core_info core;
struct siba_core_id sid;
uint32_t am, am_addr, am_size;
u_int am_offset;
u_int addrspace;
int error;
sc = (struct siba_erom *)erom;
/* Locate the requested core */
if ((error = siba_erom_lookup_core(erom, desc, &core)))
return (error);
/* Fetch full siba core ident */
sid = siba_erom_parse_core_id(sc, core.core_idx, core.unit);
/* Is port valid? */
if (!siba_is_port_valid(sid.num_addrspace, type, port))
return (ENOENT);
/* Is region valid? */
if (region >= siba_addrspace_region_count(sid.num_addrspace, port))
return (ENOENT);
/* Map the bhnd port values to a siba addrspace index */
error = siba_addrspace_index(sid.num_addrspace, type, port, region,
&addrspace);
if (error)
return (error);
/* Determine the register offset */
am_offset = siba_admatch_offset(addrspace);
if (am_offset == 0) {
printf("addrspace %u is unsupported", addrspace);
return (ENODEV);
}
/* Read and parse the address match register */
am = siba_erom_read_4(sc, core.core_idx, am_offset);
if ((error = siba_parse_admatch(am, &am_addr, &am_size))) {
printf("failed to decode address match register value 0x%x\n",
am);
return (error);
}
if (info != NULL)
*info = core;
*addr = am_addr;
*size = am_size;
return (0);
}
/* BHND_EROM_GET_CORE_TABLE() */
static int
siba_erom_get_core_table(bhnd_erom_t *erom, struct bhnd_core_info **cores,
u_int *num_cores)
{
struct siba_erom *sc;
struct bhnd_core_info *out;
sc = (struct siba_erom *)erom;
/* Allocate our core array */
out = malloc(sizeof(*out) * sc->ncores, M_BHND, M_NOWAIT);
if (out == NULL)
return (ENOMEM);
*cores = out;
*num_cores = sc->ncores;
/* Enumerate all cores. */
for (u_int i = 0; i < sc->ncores; i++) {
struct siba_core_id sid;
/* Read the core info */
sid = siba_erom_parse_core_id(sc, i, 0);
out[i] = sid.core_info;
/* Determine unit number */
for (u_int j = 0; j < i; j++) {
if (out[j].vendor == out[i].vendor &&
out[j].device == out[i].device)
out[i].unit++;
}
}
return (0);
}
/* BHND_EROM_FREE_CORE_TABLE() */
static void
siba_erom_free_core_table(bhnd_erom_t *erom, struct bhnd_core_info *cores)
{
free(cores, M_BHND);
}
static kobj_method_t siba_erom_methods[] = {
KOBJMETHOD(bhnd_erom_probe_static, siba_erom_probe_static),
KOBJMETHOD(bhnd_erom_init, siba_erom_init),
KOBJMETHOD(bhnd_erom_init_static, siba_erom_init_static),
KOBJMETHOD(bhnd_erom_fini, siba_erom_fini),
KOBJMETHOD(bhnd_erom_get_core_table, siba_erom_get_core_table),
KOBJMETHOD(bhnd_erom_free_core_table, siba_erom_free_core_table),
KOBJMETHOD(bhnd_erom_lookup_core, siba_erom_lookup_core),
KOBJMETHOD(bhnd_erom_lookup_core_addr, siba_erom_lookup_core_addr),
KOBJMETHOD_END
};
BHND_EROM_DEFINE_CLASS(siba_erom, siba_erom_parser, siba_erom_methods, sizeof(struct siba_erom));

View File

@ -184,15 +184,15 @@ siba_addrspace_region(u_int addrspace)
/**
* Return the number of bhnd(4) ports to advertise for the given
* @p dinfo.
* @p num_addrspace.
*
* @param dinfo The device info to query.
* @param num_addrspace The number of siba address spaces.
*/
u_int
siba_addrspace_port_count(struct siba_devinfo *dinfo)
siba_addrspace_port_count(u_int num_addrspace)
{
/* 0, 1, or 2 ports */
return min(dinfo->core_id.num_addrspace, 2);
return min(num_addrspace, 2);
}
/**
@ -203,10 +203,8 @@ siba_addrspace_port_count(struct siba_devinfo *dinfo)
* spaces.
*/
u_int
siba_addrspace_region_count(struct siba_devinfo *dinfo, u_int port)
siba_addrspace_region_count(u_int num_addrspace, u_int port)
{
u_int num_addrspace = dinfo->core_id.num_addrspace;
/* The first address space, if any, is mapped to device0.0 */
if (port == 0)
return (min(num_addrspace, 1));
@ -220,32 +218,33 @@ siba_addrspace_region_count(struct siba_devinfo *dinfo, u_int port)
}
/**
* Return true if @p port is defined on @p dinfo, false otherwise.
* Return true if @p port is defined given an address space count
* of @p num_addrspace, false otherwise.
*
* Refer to the siba_find_addrspace() function for information on siba's
* mapping of bhnd(4) port and region identifiers.
*
* @param dinfo The device info to verify the port against.
* @param num_addrspace The number of address spaces to verify the port against.
* @param type The bhnd(4) port type.
* @param port The bhnd(4) port number.
*/
bool
siba_is_port_valid(struct siba_devinfo *dinfo, bhnd_port_type type, u_int port)
siba_is_port_valid(u_int num_addrspace, bhnd_port_type type, u_int port)
{
/* Only device ports are supported */
if (type != BHND_PORT_DEVICE)
return (false);
/* Verify the index against the port count */
if (siba_addrspace_port_count(dinfo) <= port)
if (siba_addrspace_port_count(num_addrspace) <= port)
return (false);
return (true);
}
/**
* Map an bhnd(4) type/port/region triplet to its associated address space
* entry, if any.
* Map a bhnd(4) type/port/region triplet to its associated address space
* index, if any.
*
* For compatibility with bcma(4), we map address spaces to port/region
* identifiers as follows:
@ -258,6 +257,46 @@ siba_is_port_valid(struct siba_devinfo *dinfo, bhnd_port_type type, u_int port)
*
* The only supported port type is BHND_PORT_DEVICE.
*
* @param num_addrspace The number of available siba address spaces.
* @param type The bhnd(4) port type.
* @param port The bhnd(4) port number.
* @param region The bhnd(4) port region.
* @param addridx On success, the corresponding addrspace index.
*
* @retval 0 success
* @retval ENOENT if the given type/port/region cannot be mapped to a
* siba address space.
*/
int
siba_addrspace_index(u_int num_addrspace, bhnd_port_type type, u_int port,
u_int region, u_int *addridx)
{
u_int idx;
if (!siba_is_port_valid(num_addrspace, type, port))
return (ENOENT);
if (port == 0)
idx = region;
else if (port == 1)
idx = region + 1;
else
return (ENOENT);
if (idx >= num_addrspace)
return (ENOENT);
/* Found */
*addridx = idx;
return (0);
}
/**
* Map an bhnd(4) type/port/region triplet to its associated address space
* entry, if any.
*
* The only supported port type is BHND_PORT_DEVICE.
*
* @param dinfo The device info to search for a matching address space.
* @param type The bhnd(4) port type.
* @param port The bhnd(4) port number.
@ -268,22 +307,18 @@ siba_find_addrspace(struct siba_devinfo *dinfo, bhnd_port_type type, u_int port,
u_int region)
{
u_int addridx;
int error;
if (!siba_is_port_valid(dinfo, type, port))
return (NULL);
if (port == 0)
addridx = region;
else if (port == 1)
addridx = region + 1;
else
return (NULL);
/* Out of range? */
if (addridx >= dinfo->core_id.num_addrspace)
/* Map to addrspace index */
error = siba_addrspace_index(dinfo->core_id.num_addrspace, type, port,
region, &addridx);
if (error)
return (NULL);
/* Found */
if (addridx >= SIBA_MAX_ADDRSPACE)
return (NULL);
return (&dinfo->addrspace[addridx]);
}

View File

@ -51,9 +51,11 @@
#define SIBA_MAX_CORES \
(SIBA_ENUM_SIZE/SIBA_CORE_SIZE) /**< Maximum number of cores */
/**< Evaluates to the bus address of the @p idx core register block */
#define SIBA_CORE_ADDR(idx) \
(SIBA_ENUM_ADDR + ((idx) * SIBA_CORE_SIZE))
/** Evaluates to the bus address offset of the @p idx core register block */
#define SIBA_CORE_OFFSET(idx) ((idx) * SIBA_CORE_SIZE)
/** Evaluates to the bus address of the @p idx core register block */
#define SIBA_CORE_ADDR(idx) (SIBA_ENUM_ADDR + SIBA_CORE_OFFSET(idx))
/*
* Sonics configuration registers are mapped to each core's enumeration

View File

@ -70,14 +70,16 @@ int siba_init_dinfo(device_t dev,
void siba_free_dinfo(device_t dev,
struct siba_devinfo *dinfo);
u_int siba_addrspace_port_count(struct siba_devinfo *dinfo);
u_int siba_addrspace_region_count(struct siba_devinfo *dinfo,
u_int siba_addrspace_port_count(u_int num_addrspace);
u_int siba_addrspace_region_count(u_int num_addrspace,
u_int port);
u_int siba_addrspace_port(u_int addrspace);
u_int siba_addrspace_region(u_int addrspace);
bool siba_is_port_valid(struct siba_devinfo *dinfo,
int siba_addrspace_index(u_int num_addrspace,
bhnd_port_type type, u_int port, u_int region,
u_int *addridx);
bool siba_is_port_valid(u_int num_addrspace,
bhnd_port_type type, u_int port);
struct siba_addrspace *siba_find_addrspace(struct siba_devinfo *dinfo,

View File

@ -1,100 +0,0 @@
/*-
* Copyright (c) 2016 Landon Fuller <landonf@FreeBSD.org>
*
* 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.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
*
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, 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 DAMAGE.
*/
#include <sys/cdefs.h>
__FBSDID("$FreeBSD$");
#include <sys/types.h>
#include <machine/bus.h>
#include <dev/bhnd/bhnd.h>
#include <dev/bhnd/bcma/bcma_eromvar.h>
#include "bcm_machdep.h"
#define BCMFC_ERR(fmt, ...) printf("%s: " fmt, __FUNCTION__, ##__VA_ARGS__)
int
bcm_find_core_bcma(struct bhnd_chipid *chipid, bhnd_devclass_t devclass,
int unit, struct bhnd_core_info *info, uintptr_t *addr)
{
struct bcma_erom erom;
struct bcma_erom_core core;
struct bcma_erom_sport_region region;
bhnd_devclass_t core_class;
int error;
error = bhnd_erom_bus_space_open(&erom, NULL, mips_bus_space_generic,
(bus_space_handle_t) BCM_SOC_ADDR(chipid->enum_addr, 0), 0);
if (error) {
BCMFC_ERR("erom open failed: %d\n", error);
return (error);
}
for (u_long core_index = 0; core_index < ULONG_MAX; core_index++) {
/* Fetch next core record */
if ((error = bcma_erom_seek_next_core(&erom)))
return (error);
if ((error = bcma_erom_parse_core(&erom, &core))) {
BCMFC_ERR("core parse failed: %d\n", error);
return (error);
}
/* Check for match */
core_class = bhnd_find_core_class(core.vendor,
core.device);
if (core_class != devclass)
continue;
/* Provide the basic core info */
if (info != NULL)
bcma_erom_to_core_info(&core, core_index, 0, info);
/* Provide the core's device0.0 port address */
error = bcma_erom_seek_core_sport_region(&erom, core_index,
BHND_PORT_DEVICE, 0, 0);
if (error) {
BCMFC_ERR("sport not found: %d\n", error);
return (error);
}
if ((error = bcma_erom_parse_sport_region(&erom, &region))) {
BCMFC_ERR("sport parse failed: %d\n", error);
return (error);
}
if (addr != NULL)
*addr = region.base_addr;
return (0);
}
/* Not found */
return (ENOENT);
}

View File

@ -96,15 +96,15 @@ __FBSDID("$FreeBSD$");
#define BCM_TRACE(_fmt, ...)
#endif
static int bcm_find_core(struct bhnd_chipid *chipid,
bhnd_devclass_t devclass, int unit,
struct bhnd_core_info *info, uintptr_t *addr);
static int bcm_init_platform_data(struct bcm_platform *pdata);
static int bcm_init_platform_data(struct bcm_platform *bp);
/* Allow bus-specific implementations to override bcm_find_core_(bcma|siba)
* symbols, if included in the kernel build */
__weak_reference(bcm_find_core_default, bcm_find_core_bcma);
__weak_reference(bcm_find_core_default, bcm_find_core_siba);
static int bcm_find_core(struct bcm_platform *bp, uint16_t vendor,
uint16_t device, int unit, struct bhnd_core_info *info,
uintptr_t *addr);
static int bcm_erom_probe_and_attach(bhnd_erom_class_t **erom_cls,
kobj_ops_t erom_ops, bhnd_erom_t *erom, size_t esize,
struct bhnd_chipid *cid);
extern int *edata;
extern int *end;
@ -121,128 +121,213 @@ bcm_get_platform(void)
return (&bcm_platform_data);
}
/* Default (no-op) bcm_find_core() implementation. */
int
bcm_find_core_default(struct bhnd_chipid *chipid, bhnd_devclass_t devclass,
int unit, struct bhnd_core_info *info, uintptr_t *addr)
static bus_addr_t
bcm_get_bus_addr(void)
{
return (ENODEV);
long maddr;
if (resource_long_value("bhnd", 0, "maddr", &maddr) == 0)
return ((u_long)maddr);
return (BHND_DEFAULT_CHIPC_ADDR);
}
/**
* Search @p chipid's enumeration table for a core with @p devclass and
* @p unit.
* Search the device enumeration table for a core matching @p vendor,
* @p device, and @p unit.
*
* @param chipid Chip identification data, including the address
* of the enumeration table to be searched.
* @param devclass Search for a core matching this device class.
* @param bp Platform state containing a valid EROM parser.
* @param vendor The core's required vendor.
* @param device The core's required device id.
* @param unit The core's required unit number.
* @param[out] info On success, will be populated with the core
* @param[out] info If non-NULL, will be populated with the core
* info.
* @param[out] addr If non-NULL, will be populated with the core's
* physical register address.
*/
static int
bcm_find_core(struct bhnd_chipid *chipid, bhnd_devclass_t devclass, int unit,
struct bhnd_core_info *info, uintptr_t *addr)
bcm_find_core(struct bcm_platform *bp, uint16_t vendor, uint16_t device,
int unit, struct bhnd_core_info *info, uintptr_t *addr)
{
switch (chipid->chip_type) {
case BHND_CHIPTYPE_SIBA:
return (bcm_find_core_siba(chipid, devclass, unit, info, addr));
struct bhnd_core_match md;
bhnd_addr_t b_addr;
bhnd_size_t b_size;
int error;
md = (struct bhnd_core_match) {
BHND_MATCH_CORE_VENDOR(vendor),
BHND_MATCH_CORE_ID(BHND_COREID_CC),
BHND_MATCH_CORE_UNIT(0)
};
/* Fetch core info */
error = bhnd_erom_lookup_core_addr(&bp->erom.obj, &md, BHND_PORT_DEVICE,
0, 0, info, &b_addr, &b_size);
if (error)
return (error);
if (addr != NULL && b_addr > UINTPTR_MAX) {
BCM_ERR("core address %#jx overflows native address width\n",
(uintmax_t)b_addr);
return (ERANGE);
}
if (addr != NULL)
*addr = b_addr;
return (0);
}
/**
* Probe and attach a bhnd_erom parser instance for the bhnd bus.
*
* @param[out] erom_cls The probed EROM class.
* @param[out] erom_ops The storage to be used when compiling
* @p erom_cls.
* @param[out] erom The storage to be used when initializing the
* static instance of @p erom_cls.
* @param esize The total available number of bytes allocated
* for @p erom. If this is less than is required
* by @p erom_cls ENOMEM will be returned.
* @param[out] cid On success, the probed chip identification.
*/
static int
bcm_erom_probe_and_attach(bhnd_erom_class_t **erom_cls, kobj_ops_t erom_ops,
bhnd_erom_t *erom, size_t esize, struct bhnd_chipid *cid)
{
bhnd_erom_class_t **clsp;
bus_space_tag_t bst;
bus_space_handle_t bsh;
bus_addr_t bus_addr;
int error, prio, result;
bus_addr = bcm_get_bus_addr();
*erom_cls = NULL;
prio = 0;
bst = mips_bus_space_generic;
bsh = BCM_SOC_BSH(bus_addr, 0);
SET_FOREACH(clsp, bhnd_erom_class_set) {
struct bhnd_chipid pcid;
bhnd_erom_class_t *cls;
struct kobj_ops kops;
cls = *clsp;
/* Compile the class' ops table */
kobj_class_compile_static(cls, &kops);
/* Probe the bus address */
result = bhnd_erom_probe_static(cls, bst, bsh, bus_addr, &pcid);
/* Drop pointer to stack allocated ops table */
cls->ops = NULL;
/* The parser did not match if an error was returned */
if (result > 0)
continue;
/* Check for a new highest priority match */
if (*erom_cls == NULL || result > prio) {
prio = result;
*cid = pcid;
*erom_cls = cls;
}
/* Terminate immediately on BUS_PROBE_SPECIFIC */
if (result == BUS_PROBE_SPECIFIC)
break;
default:
if (!BHND_CHIPTYPE_HAS_EROM(chipid->chip_type)) {
printf("%s: unsupported chip type: %d\n", __FUNCTION__,
chipid->chip_type);
return (ENXIO);
}
return (bcm_find_core_bcma(chipid, devclass, unit, info, addr));
/* Valid EROM class probed? */
if (*erom_cls == NULL) {
BCM_ERR("no erom parser found for root bus at %#jx\n",
(uintmax_t)bus_addr);
return (ENOENT);
}
/* Using the provided storage, recompile the erom class ... */
kobj_class_compile_static(*erom_cls, erom_ops);
/* ... and initialize the erom parser instance */
bsh = BCM_SOC_BSH(cid->enum_addr, 0);
error = bhnd_erom_init_static(*erom_cls, erom, esize,
mips_bus_space_generic, bsh);
return (error);
}
/**
* Populate platform configuration data.
*/
static int
bcm_init_platform_data(struct bcm_platform *pdata)
bcm_init_platform_data(struct bcm_platform *bp)
{
uint32_t reg;
bhnd_addr_t enum_addr;
long maddr;
uint8_t chip_type;
bool aob, pmu;
int error;
/* Fetch CFE console handle (if any). Must be initialized before
* any calls to printf/early_putc. */
#ifdef CFE
if ((pdata->cfe_console = cfe_getstdhandle(CFE_STDHANDLE_CONSOLE)) < 0)
pdata->cfe_console = -1;
if ((bp->cfe_console = cfe_getstdhandle(CFE_STDHANDLE_CONSOLE)) < 0)
bp->cfe_console = -1;
#endif
/* Fetch bhnd/chipc address */
if (resource_long_value("bhnd", 0, "maddr", &maddr) == 0)
pdata->cc_addr = (u_long)maddr;
else
pdata->cc_addr = BHND_DEFAULT_CHIPC_ADDR;
/* Read chip identifier from ChipCommon */
reg = BCM_SOC_READ_4(pdata->cc_addr, CHIPC_ID);
chip_type = CHIPC_GET_BITS(reg, CHIPC_ID_BUS);
if (BHND_CHIPTYPE_HAS_EROM(chip_type))
enum_addr = BCM_SOC_READ_4(pdata->cc_addr, CHIPC_EROMPTR);
else
enum_addr = pdata->cc_addr;
pdata->id = bhnd_parse_chipid(reg, enum_addr);
/* Fetch chipc core info and capabilities */
pdata->cc_caps = BCM_SOC_READ_4(pdata->cc_addr, CHIPC_CAPABILITIES);
error = bcm_find_core(&pdata->id, BHND_DEVCLASS_CC, 0, &pdata->cc_id,
NULL);
/* Probe and attach device table provider, populating our
* chip identification */
error = bcm_erom_probe_and_attach(&bp->erom_impl, &bp->erom_ops,
&bp->erom.obj, sizeof(bp->erom), &bp->cid);
if (error) {
printf("%s: error locating chipc core: %d", __FUNCTION__,
error);
BCM_ERR("error attaching erom parser: %d\n", error);
return (error);
}
if (CHIPC_HWREV_HAS_CAP_EXT(pdata->cc_id.hwrev)) {
pdata->cc_caps_ext = BCM_SOC_READ_4(pdata->cc_addr,
CHIPC_CAPABILITIES_EXT);
} else {
pdata->cc_caps_ext = 0x0;
/* Fetch chipcommon core info */
error = bcm_find_core(bp, BHND_MFGID_BCM, BHND_COREID_CC, 0, &bp->cc_id,
&bp->cc_addr);
if (error) {
BCM_ERR("error locating chipc core: %d\n", error);
return (error);
}
/* Fetch chipc capability flags */
bp->cc_caps = BCM_SOC_READ_4(bp->cc_addr, CHIPC_CAPABILITIES);
bp->cc_caps_ext = 0x0;
if (CHIPC_HWREV_HAS_CAP_EXT(bp->cc_id.hwrev))
bp->cc_caps_ext = BCM_CHIPC_READ_4(bp, CHIPC_CAPABILITIES_EXT);
/* Fetch PMU info */
pmu = CHIPC_GET_FLAG(pdata->cc_caps, CHIPC_CAP_PMU);
aob = CHIPC_GET_FLAG(pdata->cc_caps_ext, CHIPC_CAP2_AOB);
pmu = CHIPC_GET_FLAG(bp->cc_caps, CHIPC_CAP_PMU);
aob = CHIPC_GET_FLAG(bp->cc_caps_ext, CHIPC_CAP2_AOB);
if (pmu && aob) {
/* PMU block mapped to a PMU core on the Always-on-Bus (aob) */
error = bcm_find_core(&pdata->id, BHND_DEVCLASS_PMU, 0,
&pdata->pmu_id, &pdata->pmu_addr);
error = bcm_find_core(bp, BHND_MFGID_BCM, BHND_COREID_PMU, 0,
&bp->pmu_id, &bp->pmu_addr);
if (error) {
printf("%s: error locating pmu core: %d", __FUNCTION__,
error);
BCM_ERR("error locating pmu core: %d\n", error);
return (error);
}
} else if (pmu) {
/* PMU block mapped to chipc */
pdata->pmu_addr = pdata->cc_addr;
pdata->pmu_id = pdata->cc_id;
bp->pmu_addr = bp->cc_addr;
bp->pmu_id = bp->cc_id;
} else {
/* No PMU */
pdata->pmu_addr = 0x0;
memset(&pdata->pmu_id, 0, sizeof(pdata->pmu_id));
bp->pmu_addr = 0x0;
memset(&bp->pmu_id, 0, sizeof(bp->pmu_id));
}
/* Initialize PMU query state */
if (pmu) {
error = bhnd_pmu_query_init(&pdata->pmu, NULL, pdata->id,
&bcm_pmu_soc_io, pdata);
error = bhnd_pmu_query_init(&bp->pmu, NULL, bp->cid,
&bcm_pmu_soc_io, bp);
if (error) {
printf("%s: bhnd_pmu_query_init() failed: %d\n",
__FUNCTION__, error);
BCM_ERR("bhnd_pmu_query_init() failed: %d\n", error);
return (error);
}
}
@ -346,7 +431,7 @@ platform_reset(void)
bcm4785war = false;
/* Handle BCM4785-specific behavior */
if (bp->id.chip_id == BHND_CHIPID_BCM4785) {
if (bp->cid.chip_id == BHND_CHIPID_BCM4785) {
bcm4785war = true;
/* Switch to async mode */

View File

@ -36,16 +36,14 @@
#include <machine/cpuregs.h>
#include <dev/bhnd/bhnd.h>
#include <dev/bhnd/bhnd_erom.h>
#include <dev/bhnd/cores/pmu/bhnd_pmuvar.h>
extern const struct bhnd_pmu_io bcm_pmu_soc_io;
typedef int (bcm_bus_find_core)(struct bhnd_chipid *chipid,
bhnd_devclass_t devclass, int unit, struct bhnd_core_info *info,
uintptr_t *addr);
struct bcm_platform {
struct bhnd_chipid id; /**< chip id */
struct bhnd_chipid cid; /**< chip id */
struct bhnd_core_info cc_id; /**< chipc core info */
uintptr_t cc_addr; /**< chipc core phys address */
uint32_t cc_caps; /**< chipc capabilities */
@ -60,6 +58,13 @@ struct bcm_platform {
struct bhnd_pmu_query pmu; /**< PMU query instance */
bhnd_erom_class_t *erom_impl; /**< erom parser class */
struct kobj_ops erom_ops; /**< compiled kobj opcache */
union {
bhnd_erom_static_t data;
bhnd_erom_t obj;
} erom;
#ifdef CFE
int cfe_console; /**< Console handle, or -1 */
#endif
@ -74,9 +79,11 @@ uint64_t bcm_get_ilpfreq(struct bcm_platform *bp);
u_int bcm_get_uart_rclk(struct bcm_platform *bp);
bcm_bus_find_core bcm_find_core_default;
bcm_bus_find_core bcm_find_core_bcma;
bcm_bus_find_core bcm_find_core_siba;
#define BCM_ERR(fmt, ...) \
printf("%s: " fmt, __FUNCTION__, ##__VA_ARGS__)
#define BCM_SOC_BSH(_addr, _offset) \
((bus_space_handle_t)BCM_SOC_ADDR((_addr), (_offset)))
#define BCM_SOC_ADDR(_addr, _offset) \
MIPS_PHYS_TO_KSEG1((_addr) + (_offset))

View File

@ -239,14 +239,14 @@ bcm_get_cpufreq(struct bcm_platform *bp)
* PWRCTL support
*/
pll_type = CHIPC_GET_BITS(bp->cc_caps, CHIPC_CAP_PLL);
mreg = bhnd_pwrctl_cpu_clkreg_m(&bp->id, pll_type, &fixed_hz);
mreg = bhnd_pwrctl_cpu_clkreg_m(&bp->cid, pll_type, &fixed_hz);
if (mreg == 0)
return (fixed_hz);
n = BCM_CHIPC_READ_4(bp, CHIPC_CLKC_N);
m = BCM_CHIPC_READ_4(bp, mreg);
return (bhnd_pwrctl_cpu_clock_rate(&bp->id, pll_type, n, m));
return (bhnd_pwrctl_cpu_clock_rate(&bp->cid, pll_type, n, m));
}
@ -267,14 +267,14 @@ bcm_get_sifreq(struct bcm_platform *bp)
* PWRCTL support
*/
pll_type = CHIPC_GET_BITS(bp->cc_caps, CHIPC_CAP_PLL);
mreg = bhnd_pwrctl_si_clkreg_m(&bp->id, pll_type, &fixed_hz);
mreg = bhnd_pwrctl_si_clkreg_m(&bp->cid, pll_type, &fixed_hz);
if (mreg == 0)
return (fixed_hz);
n = BCM_CHIPC_READ_4(bp, CHIPC_CLKC_N);
m = BCM_CHIPC_READ_4(bp, mreg);
return (bhnd_pwrctl_si_clock_rate(&bp->id, pll_type, n, m));
return (bhnd_pwrctl_si_clock_rate(&bp->cid, pll_type, n, m));
}

View File

@ -1,64 +0,0 @@
/*-
* Copyright (c) 2016 Landon Fuller <landonf@FreeBSD.org>
*
* 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.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
*
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, 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 DAMAGE.
*/
#include <sys/cdefs.h>
__FBSDID("$FreeBSD$");
#include <dev/bhnd/bhnd.h>
#include <dev/bhnd/bhndreg.h>
#include <dev/bhnd/siba/sibareg.h>
#include <dev/bhnd/siba/sibavar.h>
#include "bcm_machdep.h"
int
bcm_find_core_siba(struct bhnd_chipid *chipid, bhnd_devclass_t devclass,
int unit, struct bhnd_core_info *info, uintptr_t *addr)
{
struct siba_core_id scid;
uintptr_t cc_addr;
uint32_t idhigh, idlow;
/* No other cores are required during early boot on siba(4) devices */
if (devclass != BHND_DEVCLASS_CC || unit != 0)
return (ENOENT);
cc_addr = chipid->enum_addr;
idhigh = BCM_SOC_READ_4(cc_addr, SB0_REG_ABS(SIBA_CFG0_IDHIGH));
idlow = BCM_SOC_READ_4(cc_addr, SB0_REG_ABS(SIBA_CFG0_IDHIGH));
scid = siba_parse_core_id(idhigh, idlow, 0, 0);
if (info != NULL)
*info = scid.core_info;
if (addr != NULL)
*addr = cc_addr;
return (0);
}

View File

@ -4,10 +4,8 @@
# for USB 1.1 OHCI, Ethernet and IPSEC cores
# which are believed to be devices we have drivers for
# which just need to be tweaked for attachment to an BHND system bus.
mips/broadcom/bcm_bcma.c optional bcma_nexus bcma
mips/broadcom/bcm_machdep.c standard
mips/broadcom/bcm_pmu.c standard
mips/broadcom/bcm_siba.c optional siba_nexus siba
mips/mips/tick.c standard
mips/mips/mips_pic.c standard
kern/subr_intr.c standard

View File

@ -10,6 +10,9 @@ KMOD= bhnd
SRCS= bhnd.c bhnd_subr.c
SRCS+= bhnd_bus_if.c bhnd_bus_if.h
SRCS+= bhnd_erom.c
SRCS+= bhnd_erom_if.c bhnd_erom_if.h
# ChipCommon
SRCS+= chipc.c chipc_subr.c
SRCS+= bhnd_sprom_chipc.c \

View File

@ -5,6 +5,7 @@
KMOD= bcma
SRCS= bcma.c bcma_subr.c bcma_erom.c
SRCS+= device_if.h bus_if.h bhnd_bus_if.h
SRCS+= device_if.h bus_if.h
SRCS+= bhnd_bus_if.h bhnd_erom_if.h
.include <bsd.kmod.mk>

View File

@ -5,7 +5,8 @@
KMOD= bcma_bhndb
SRCS= bcma_bhndb.c
SRCS+= bhnd_bus_if.h bhndb_bus_if.h bhndb_if.h
SRCS+= bhnd_bus_if.h bhnd_erom_if.h
SRCS+= bhndb_bus_if.h bhndb_if.h
SRCS+= device_if.h bus_if.h
.include <bsd.kmod.mk>

View File

@ -3,8 +3,10 @@
.PATH: ${.CURDIR}/../../../dev/bhnd/siba
KMOD= siba
SRCS= siba.c siba_subr.c
SRCS= siba.c siba_subr.c \
siba_erom.c
SRCS+= device_if.h bus_if.h bhnd_bus_if.h
SRCS+= device_if.h bus_if.h
SRCS+= bhnd_bus_if.h bhnd_erom_if.h
.include <bsd.kmod.mk>

View File

@ -5,7 +5,8 @@
KMOD= siba_bhndb
SRCS= siba_bhndb.c
SRCS+= bhnd_bus_if.h bhndb_bus_if.h bhndb_if.h
SRCS+= bhnd_bus_if.h bhnd_erom_if.h
SRCS+= bhndb_bus_if.h bhndb_if.h
SRCS+= device_if.h bus_if.h
.include <bsd.kmod.mk>