diff options
author | landonf <landonf@FreeBSD.org> | 2016-06-16 20:04:33 +0000 |
---|---|---|
committer | landonf <landonf@FreeBSD.org> | 2016-06-16 20:04:33 +0000 |
commit | 0f15c82878790de14c05ebe2779f1020b21679e2 (patch) | |
tree | 6171bb991c52e73ab5b779a8002b5107fe216ce2 | |
parent | 4bf2fbdedfe29fb1df05246dee777d76520d5dad (diff) | |
download | FreeBSD-src-0f15c82878790de14c05ebe2779f1020b21679e2.zip FreeBSD-src-0f15c82878790de14c05ebe2779f1020b21679e2.tar.gz |
siba(4): Adopt bcma-compatible mapping of bhnd(4) port/region identifiers.
Maps Sonics/OCP per-core address spaces to bcma(4)-compatible port/region
identifiers.
This permits the use of common address map identifiers in bhnd device
drivers, independent of the underlying interconnect type.
Approved by: re (gjb), adrian (mentor)
Differential Revision: https://reviews.freebsd.org/D6850
-rw-r--r-- | sys/dev/bhnd/siba/siba.c | 111 | ||||
-rw-r--r-- | sys/dev/bhnd/siba/siba_subr.c | 220 | ||||
-rw-r--r-- | sys/dev/bhnd/siba/sibareg.h | 5 | ||||
-rw-r--r-- | sys/dev/bhnd/siba/sibavar.h | 61 |
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 */ }; |