summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--sys/dev/bhnd/siba/siba.c111
-rw-r--r--sys/dev/bhnd/siba/siba_subr.c220
-rw-r--r--sys/dev/bhnd/siba/sibareg.h5
-rw-r--r--sys/dev/bhnd/siba/sibavar.h61
4 files changed, 189 insertions, 208 deletions
diff --git a/sys/dev/bhnd/siba/siba.c b/sys/dev/bhnd/siba/siba.c
index bd3af18..bbd751d 100644
--- a/sys/dev/bhnd/siba/siba.c
+++ b/sys/dev/bhnd/siba/siba.c
@@ -70,7 +70,6 @@ siba_attach(device_t dev)
for (int i = 0; i < ndevs; i++) {
struct siba_addrspace *addrspace;
- struct siba_port *port;
dinfo = device_get_ivars(devs[i]);
@@ -79,14 +78,10 @@ siba_attach(device_t dev)
"not be suspended before siba_attach()"));
/* Fetch the core register address space */
- port = siba_dinfo_get_port(dinfo, BHND_PORT_DEVICE, 0);
- if (port == NULL) {
- error = ENXIO;
- goto cleanup;
- }
-
- addrspace = siba_find_port_addrspace(port, SIBA_ADDRSPACE_CORE);
+ addrspace = siba_find_addrspace(dinfo, BHND_PORT_DEVICE, 0, 0);
if (addrspace == NULL) {
+ device_printf(dev,
+ "missing device registers for core %d\n", i);
error = ENXIO;
goto cleanup;
}
@@ -94,7 +89,7 @@ siba_attach(device_t dev)
/*
* Map the per-core configuration blocks
*/
- KASSERT(dinfo->core_id.num_cfg_blocks <= SIBA_CFG_NUM_MAX,
+ KASSERT(dinfo->core_id.num_cfg_blocks <= SIBA_MAX_CFG,
("config block count %u out of range",
dinfo->core_id.num_cfg_blocks));
@@ -285,32 +280,25 @@ siba_get_port_count(device_t dev, device_t child, bhnd_port_type type)
type));
dinfo = device_get_ivars(child);
-
- /* We advertise exactly one port of any type */
- if (siba_dinfo_get_port(dinfo, type, 0) != NULL)
- return (1);
-
- return (0);
+ return (siba_addrspace_port_count(dinfo));
}
static u_int
siba_get_region_count(device_t dev, device_t child, bhnd_port_type type,
- u_int port_num)
+ u_int port)
{
struct siba_devinfo *dinfo;
- struct siba_port *port;
/* delegate non-bus-attached devices to our parent */
if (device_get_parent(child) != dev)
return (BHND_BUS_GET_REGION_COUNT(device_get_parent(dev), child,
- type, port_num));
+ type, port));
dinfo = device_get_ivars(child);
- port = siba_dinfo_get_port(dinfo, type, port_num);
- if (port == NULL)
+ if (!siba_is_port_valid(dinfo, type, port))
return (0);
- return (port->sp_num_addrs);
+ return (siba_addrspace_region_count(dinfo, port));
}
static int
@@ -318,7 +306,6 @@ siba_get_port_rid(device_t dev, device_t child, bhnd_port_type port_type,
u_int port_num, u_int region_num)
{
struct siba_devinfo *dinfo;
- struct siba_port *port;
struct siba_addrspace *addrspace;
/* delegate non-bus-attached devices to our parent */
@@ -327,17 +314,11 @@ siba_get_port_rid(device_t dev, device_t child, bhnd_port_type port_type,
port_type, port_num, region_num));
dinfo = device_get_ivars(child);
- port = siba_dinfo_get_port(dinfo, port_type, port_num);
- if (port == NULL)
+ addrspace = siba_find_addrspace(dinfo, port_type, port_num, region_num);
+ if (addrspace == NULL)
return (-1);
- STAILQ_FOREACH(addrspace, &port->sp_addrs, sa_link) {
- if (addrspace->sa_region_num == region_num)
- return (addrspace->sa_rid);
- }
-
- /* not found */
- return (-1);
+ return (addrspace->sa_rid);
}
static int
@@ -345,8 +326,6 @@ siba_decode_port_rid(device_t dev, device_t child, int type, int rid,
bhnd_port_type *port_type, u_int *port_num, u_int *region_num)
{
struct siba_devinfo *dinfo;
- struct siba_port *port;
- struct siba_addrspace *addrspace;
/* delegate non-bus-attached devices to our parent */
if (device_get_parent(child) != dev)
@@ -359,29 +338,17 @@ siba_decode_port_rid(device_t dev, device_t child, int type, int rid,
if (type != SYS_RES_MEMORY)
return (EINVAL);
- /* Starting with the most likely device list, search all three port
- * lists */
- bhnd_port_type types[] = {
- BHND_PORT_DEVICE,
- BHND_PORT_AGENT,
- BHND_PORT_BRIDGE
- };
-
- for (int i = 0; i < nitems(types); i++) {
- port = siba_dinfo_get_port(dinfo, types[i], 0);
- if (port == NULL)
+ for (int i = 0; i < dinfo->core_id.num_addrspace; i++) {
+ if (dinfo->addrspace[i].sa_rid != rid)
continue;
-
- STAILQ_FOREACH(addrspace, &port->sp_addrs, sa_link) {
- if (addrspace->sa_rid != rid)
- continue;
-
- *port_type = port->sp_type;
- *port_num = port->sp_num;
- *region_num = addrspace->sa_region_num;
- }
+
+ *port_type = BHND_PORT_DEVICE;
+ *port_num = siba_addrspace_port(i);
+ *region_num = siba_addrspace_region(i);
+ return (0);
}
+ /* Not found */
return (ENOENT);
}
@@ -390,7 +357,6 @@ siba_get_region_addr(device_t dev, device_t child, bhnd_port_type port_type,
u_int port_num, u_int region_num, bhnd_addr_t *addr, bhnd_size_t *size)
{
struct siba_devinfo *dinfo;
- struct siba_port *port;
struct siba_addrspace *addrspace;
/* delegate non-bus-attached devices to our parent */
@@ -400,20 +366,13 @@ siba_get_region_addr(device_t dev, device_t child, bhnd_port_type port_type,
}
dinfo = device_get_ivars(child);
- port = siba_dinfo_get_port(dinfo, port_type, port_num);
- if (port == NULL)
+ addrspace = siba_find_addrspace(dinfo, port_type, port_num, region_num);
+ if (addrspace == NULL)
return (ENOENT);
- STAILQ_FOREACH(addrspace, &port->sp_addrs, sa_link) {
- if (addrspace->sa_region_num != region_num)
- continue;
-
- *addr = addrspace->sa_base;
- *size = addrspace->sa_size - addrspace->sa_bus_reserved;
- return (0);
- }
-
- return (ENOENT);
+ *addr = addrspace->sa_base;
+ *size = addrspace->sa_size - addrspace->sa_bus_reserved;
+ return (0);
}
@@ -432,26 +391,21 @@ siba_register_addrspaces(device_t dev, struct siba_devinfo *di,
struct siba_core_id *cid;
uint32_t addr;
uint32_t size;
- u_int region_num;
int error;
cid = &di->core_id;
- /* Region numbers must be assigned in order, but our siba address
- * space IDs may be sparsely allocated; thus, we track
- * the region index separately. */
- region_num = 0;
/* Register the device address space entries */
- for (uint8_t sid = 0; sid < di->core_id.num_addrspace; sid++) {
+ for (uint8_t i = 0; i < di->core_id.num_addrspace; i++) {
uint32_t adm;
u_int adm_offset;
uint32_t bus_reserved;
/* Determine the register offset */
- adm_offset = siba_admatch_offset(sid);
+ adm_offset = siba_admatch_offset(i);
if (adm_offset == 0) {
- device_printf(dev, "addrspace %hhu is unsupported", sid);
+ device_printf(dev, "addrspace %hhu is unsupported", i);
return (ENODEV);
}
@@ -469,17 +423,14 @@ siba_register_addrspaces(device_t dev, struct siba_devinfo *di,
* reserve the Sonics configuration register blocks for the
* use of our bus. */
bus_reserved = 0;
- if (sid == SIBA_ADDRSPACE_CORE)
+ if (i == SIBA_CORE_ADDRSPACE)
bus_reserved = cid->num_cfg_blocks * SIBA_CFG_SIZE;
/* Append the region info */
- error = siba_append_dinfo_region(di, BHND_PORT_DEVICE, 0,
- region_num, sid, addr, size, bus_reserved);
+ error = siba_append_dinfo_region(di, i, addr, size,
+ bus_reserved);
if (error)
return (error);
-
-
- region_num++;
}
return (0);
diff --git a/sys/dev/bhnd/siba/siba_subr.c b/sys/dev/bhnd/siba/siba_subr.c
index 27b3f0d..44052df 100644
--- a/sys/dev/bhnd/siba/siba_subr.c
+++ b/sys/dev/bhnd/siba/siba_subr.c
@@ -106,35 +106,6 @@ siba_parse_core_id(uint32_t idhigh, uint32_t idlow, u_int core_idx, int unit)
}
/**
- * Initialize new port descriptor.
- *
- * @param port_num Port number.
- * @param port_type Port type.
- */
-static void
-siba_init_port(struct siba_port *port, bhnd_port_type port_type, u_int port_num)
-{
- port->sp_num = port_num;
- port->sp_type = port_type;
- port->sp_num_addrs = 0;
- STAILQ_INIT(&port->sp_addrs);
-}
-
-/**
- * Deallocate all resources associated with the given port descriptor.
- *
- * @param port Port descriptor to be deallocated.
- */
-static void
-siba_release_port(struct siba_port *port) {
- struct siba_addrspace *as, *as_next;
-
- STAILQ_FOREACH_SAFE(as, &port->sp_addrs, sa_link, as_next) {
- free(as, M_BHND);
- }
-}
-
-/**
* Allocate and initialize new device info structure, copying the
* provided core id.
*
@@ -157,76 +128,153 @@ siba_alloc_dinfo(device_t bus, const struct siba_core_id *core_id)
dinfo->cfg_rid[i] = -1;
}
- siba_init_port(&dinfo->device_port, BHND_PORT_DEVICE, 0);
resource_list_init(&dinfo->resources);
return dinfo;
}
/**
- * Return the @p dinfo port instance for @p type, or NULL.
+ * Map an addrspace index to its corresponding bhnd(4) port number.
*
- * @param dinfo The siba device info.
- * @param type The requested port type.
+ * @param addrspace Address space index.
+ */
+u_int
+siba_addrspace_port(u_int addrspace)
+{
+ /* The first addrspace is always mapped to device0; the remainder
+ * are mapped to device1 */
+ if (addrspace == 0)
+ return (0);
+ else
+ return (1);
+}
+
+/**
+ * Map an addrspace index to its corresponding bhnd(4) region number.
*
- * @retval siba_port If @p port_type and @p port_num are defined on @p dinfo.
- * @retval NULL If the requested port is not defined on @p dinfo.
+ * @param addrspace Address space index.
*/
-struct siba_port *
-siba_dinfo_get_port(struct siba_devinfo *dinfo, bhnd_port_type port_type,
- u_int port_num)
+u_int
+siba_addrspace_region(u_int addrspace)
{
- /* We only define a single port for any given type. */
- if (port_num != 0)
- return (NULL);
+ /* The first addrspace is always mapped to device0.0; the remainder
+ * are mapped to device1.0 + (n - 1) */
+ if (addrspace == 0)
+ return (0);
+ else
+ return (addrspace - 1);
+}
- switch (port_type) {
- case BHND_PORT_DEVICE:
- return (&dinfo->device_port);
- case BHND_PORT_BRIDGE:
- return (NULL);
- case BHND_PORT_AGENT:
- return (NULL);
- default:
- printf("%s: unknown port_type (%d)\n",
- __func__,
- port_type);
- return (NULL);
- }
+/**
+ * Return the number of bhnd(4) ports to advertise for the given
+ * @p dinfo.
+ *
+ * @param dinfo The device info to query.
+ */
+u_int
+siba_addrspace_port_count(struct siba_devinfo *dinfo)
+{
+ /* 0, 1, or 2 ports */
+ return min(dinfo->core_id.num_addrspace, 2);
}
+/**
+ * Return the number of bhnd(4) regions to advertise on @p port
+ * given the provided @p num_addrspace address space count.
+ *
+ * @param num_addrspace The number of core-mapped siba(4) Sonics/OCP address
+ * spaces.
+ */
+u_int
+siba_addrspace_region_count(struct siba_devinfo *dinfo, 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));
+
+ /* All remaining address spaces are mapped to device0.(n - 1) */
+ if (port == 1 && num_addrspace >= 2)
+ return (num_addrspace - 1);
+
+ /* No region mapping */
+ return (0);
+}
/**
- * Find an address space with @p sid on @p port.
+ * Return true if @p port is defined on @p dinfo, false otherwise.
+ *
+ * Refer to the siba_find_addrspace() function for information on siba's
+ * mapping of bhnd(4) port and region identifiers.
*
- * @param port The port to search for a matching address space.
- * @param sid The siba-assigned address space ID to search for.
+ * @param dinfo The device info to verify the port against.
+ * @param type The bhnd(4) port type.
+ * @param port The bhnd(4) port number.
*/
-struct siba_addrspace *
-siba_find_port_addrspace(struct siba_port *port, uint8_t sid)
+bool
+siba_is_port_valid(struct siba_devinfo *dinfo, bhnd_port_type type, u_int port)
{
- struct siba_addrspace *addrspace;
+ /* Only device ports are supported */
+ if (type != BHND_PORT_DEVICE)
+ return (false);
- STAILQ_FOREACH(addrspace, &port->sp_addrs, sa_link) {
- if (addrspace->sa_sid == sid)
- return (addrspace);
- }
+ /* Verify the index against the port count */
+ if (siba_addrspace_port_count(dinfo) <= port)
+ return (false);
- /* not found */
- return (NULL);
+ return (true);
}
/**
- * Append a new address space entry to @p port_num of type @p port_type
- * in @p dinfo.
+ * Map an bhnd(4) type/port/region triplet to its associated address space
+ * entry, if any.
+ *
+ * For compatibility with bcma(4), we map address spaces to port/region
+ * identifiers as follows:
+ *
+ * [port] [addrspace]
+ * device0.0 0
+ * device1.0 1
+ * device1.1 2
+ * device1.2 3
+ *
+ * The only supported port type is BHND_PORT_DEVICE.
*
- * The range will also be registered in @p dinfo resource list.
+ * @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.
+ * @param region The bhnd(4) port region.
+ */
+struct siba_addrspace *
+siba_find_addrspace(struct siba_devinfo *dinfo, bhnd_port_type type, u_int port,
+ u_int region)
+{
+ u_int addridx;
+
+ 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)
+ return (NULL);
+
+ /* Found */
+ return (&dinfo->addrspace[addridx]);
+}
+
+/**
+ * Append an address space entry to @p dinfo.
*
* @param dinfo The device info entry to update.
- * @param port_type The port type.
- * @param port_num The port number.
- * @param region_num The region index number.
- * @param sid The siba-assigned core-unique address space identifier.
+ * @param addridx The address space index.
* @param base The mapping's base address.
* @param size The mapping size.
* @param bus_reserved Number of bytes to reserve in @p size for bus use
@@ -237,12 +285,10 @@ siba_find_port_addrspace(struct siba_port *port, uint8_t sid)
* @retval non-zero An error occurred appending the entry.
*/
int
-siba_append_dinfo_region(struct siba_devinfo *dinfo, bhnd_port_type port_type,
- u_int port_num, u_int region_num, uint8_t sid, uint32_t base, uint32_t size,
- uint32_t bus_reserved)
+siba_append_dinfo_region(struct siba_devinfo *dinfo, uint8_t addridx,
+ uint32_t base, uint32_t size, uint32_t bus_reserved)
{
struct siba_addrspace *sa;
- struct siba_port *port;
rman_res_t r_size;
/* Verify that base + size will not overflow */
@@ -257,20 +303,14 @@ siba_append_dinfo_region(struct siba_devinfo *dinfo, bhnd_port_type port_type,
if (size == 0)
return (EINVAL);
- /* Determine target port */
- port = siba_dinfo_get_port(dinfo, port_type, port_num);
- if (port == NULL)
+ /* Must not exceed addrspace array size */
+ if (addridx >= nitems(dinfo->addrspace))
return (EINVAL);
- /* Allocate new addrspace entry */
- sa = malloc(sizeof(*sa), M_BHND, M_NOWAIT|M_ZERO);
- if (sa == NULL)
- return (ENOMEM);
-
+ /* Initialize new addrspace entry */
+ sa = &dinfo->addrspace[addridx];
sa->sa_base = base;
sa->sa_size = size;
- sa->sa_sid = sid;
- sa->sa_region_num = region_num;
sa->sa_bus_reserved = bus_reserved;
/* Populate the resource list */
@@ -278,10 +318,6 @@ siba_append_dinfo_region(struct siba_devinfo *dinfo, bhnd_port_type port_type,
sa->sa_rid = resource_list_add_next(&dinfo->resources, SYS_RES_MEMORY,
base, base + (r_size - 1), r_size);
- /* Append to target port */
- STAILQ_INSERT_TAIL(&port->sp_addrs, sa, sa_link);
- port->sp_num_addrs++;
-
return (0);
}
@@ -294,8 +330,6 @@ siba_append_dinfo_region(struct siba_devinfo *dinfo, bhnd_port_type port_type,
void
siba_free_dinfo(device_t dev, struct siba_devinfo *dinfo)
{
- siba_release_port(&dinfo->device_port);
-
resource_list_free(&dinfo->resources);
/* Free all mapped configuration blocks */
diff --git a/sys/dev/bhnd/siba/sibareg.h b/sys/dev/bhnd/siba/sibareg.h
index c1a2e26..be49d34 100644
--- a/sys/dev/bhnd/siba/sibareg.h
+++ b/sys/dev/bhnd/siba/sibareg.h
@@ -51,9 +51,6 @@
#define SIBA_MAX_CORES \
(SIBA_ENUM_SIZE/SIBA_CORE_SIZE) /**< Maximum number of cores */
-#define SIBA_ADDRSPACE_CORE 0 /**< address space identifier of the
- core enumeration block. */
-
/**< Evaluates to the bus address of the @p idx core register block */
#define SIBA_CORE_ADDR(idx) \
(SIBA_ENUM_ADDR + ((idx) * SIBA_CORE_SIZE))
@@ -175,7 +172,7 @@
#define SIBA_IMCH_BEM_MASK 0xc0 /* bus error mode */
#define SIBA_IMCH_BEM_SHIFT 6
-/* sbadmatch0 */
+/* sbadmatch0-4 */
#define SIBA_AM_TYPE_MASK 0x3 /* address type */
#define SIBA_AM_TYPE_SHIFT 0x0
#define SIBA_AM_AD64 0x4 /* reserved */
diff --git a/sys/dev/bhnd/siba/sibavar.h b/sys/dev/bhnd/siba/sibavar.h
index 2c9f14c..4f36586 100644
--- a/sys/dev/bhnd/siba/sibavar.h
+++ b/sys/dev/bhnd/siba/sibavar.h
@@ -47,7 +47,6 @@
struct siba_addrspace;
struct siba_devinfo;
-struct siba_port;
struct siba_core_id;
int siba_probe(device_t dev);
@@ -69,47 +68,53 @@ struct siba_devinfo *siba_alloc_dinfo(device_t dev,
void siba_free_dinfo(device_t dev,
struct siba_devinfo *dinfo);
-struct siba_port *siba_dinfo_get_port(struct siba_devinfo *dinfo,
- bhnd_port_type port_type, u_int port_num);
+u_int siba_addrspace_port_count(struct siba_devinfo *dinfo);
+u_int siba_addrspace_region_count(struct siba_devinfo *dinfo,
+ u_int port);
-struct siba_addrspace *siba_find_port_addrspace(struct siba_port *port,
- uint8_t sid);
+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,
+ bhnd_port_type type, u_int port);
+
+struct siba_addrspace *siba_find_addrspace(struct siba_devinfo *dinfo,
+ bhnd_port_type type, u_int port, u_int region);
int siba_append_dinfo_region(struct siba_devinfo *dinfo,
- bhnd_port_type port_type, u_int port_num,
- u_int region_num, uint8_t sid, uint32_t base,
- uint32_t size, uint32_t bus_reserved);
+ uint8_t sid, uint32_t base, uint32_t size,
+ uint32_t bus_reserved);
u_int siba_admatch_offset(uint8_t addrspace);
int siba_parse_admatch(uint32_t am, uint32_t *addr,
uint32_t *size);
+
/* Sonics configuration register blocks */
#define SIBA_CFG_NUM_2_2 1 /**< sonics <= 2.2 maps SIBA_CFG0. */
#define SIBA_CFG_NUM_2_3 2 /**< sonics <= 2.3 maps SIBA_CFG0 and SIBA_CFG1 */
-#define SIBA_CFG_NUM_MAX SIBA_CFG_NUM_2_3 /**< maximum number of supported config
+#define SIBA_MAX_CFG SIBA_CFG_NUM_2_3 /**< maximum number of supported config
register blocks */
+/* Sonics/OCP address space mappings */
+#define SIBA_CORE_ADDRSPACE 0 /**< Address space mapping the primary
+ device registers */
+
+#define SIBA_MAX_ADDRSPACE 4 /**< Maximum number of Sonics/OCP
+ * address space mappings for a
+ * single core. */
+
+/* bhnd(4) (port,region) representation of siba address space mappings */
+#define SIBA_MAX_PORT 2 /**< maximum number of advertised
+ * bhnd(4) ports */
+
/** siba(4) address space descriptor */
struct siba_addrspace {
uint32_t sa_base; /**< base address */
uint32_t sa_size; /**< size */
- u_int sa_region_num; /**< bhnd region id */
- uint8_t sa_sid; /**< siba-assigned address space ID */
int sa_rid; /**< bus resource id */
uint32_t sa_bus_reserved;/**< number of bytes at high end of
* address space reserved for the bus */
-
- STAILQ_ENTRY(siba_addrspace) sa_link;
-};
-
-/** siba(4) port descriptor */
-struct siba_port {
- bhnd_port_type sp_type; /**< port type */
- u_int sp_num; /**< port number */
- u_int sp_num_addrs; /**< number of address space mappings */
-
- STAILQ_HEAD(, siba_addrspace) sp_addrs; /**< address spaces mapped to this port */
};
/**
@@ -133,16 +138,10 @@ struct siba_core_id {
struct siba_devinfo {
struct resource_list resources; /**< per-core memory regions. */
struct siba_core_id core_id; /**< core identification info */
+ struct siba_addrspace addrspace[SIBA_MAX_ADDRSPACE]; /**< memory map descriptors */
- struct siba_port device_port; /**< device port holding ownership
- * of all siba address space
- * entries for this core. */
-
- /** SIBA_CFG* register blocks */
- struct bhnd_resource *cfg[SIBA_CFG_NUM_MAX];
-
- /** SIBA_CFG* resource IDs */
- int cfg_rid[SIBA_CFG_NUM_MAX];
+ struct bhnd_resource *cfg[SIBA_MAX_CFG]; /**< SIBA_CFG_* registers */
+ int cfg_rid[SIBA_MAX_CFG]; /**< SIBA_CFG_* resource IDs */
};
OpenPOWER on IntegriCloud