aboutsummaryrefslogtreecommitdiff
path: root/sys/dev
diff options
context:
space:
mode:
Diffstat (limited to 'sys/dev')
-rw-r--r--sys/dev/bhnd/bhndb/bhndb.c194
-rw-r--r--sys/dev/bhnd/bhndb/bhndb_pci.c33
-rw-r--r--sys/dev/bhnd/bhndb/bhndb_private.h7
-rw-r--r--sys/dev/bhnd/bhndb/bhndb_subr.c97
-rw-r--r--sys/dev/bhnd/bhndb/bhndbvar.h15
5 files changed, 254 insertions, 92 deletions
diff --git a/sys/dev/bhnd/bhndb/bhndb.c b/sys/dev/bhnd/bhndb/bhndb.c
index 43580b7a2103..f1fc665d8e09 100644
--- a/sys/dev/bhnd/bhndb/bhndb.c
+++ b/sys/dev/bhnd/bhndb/bhndb.c
@@ -85,8 +85,11 @@ static int bhndb_read_chipid(struct bhndb_softc *sc,
const struct bhndb_hwcfg *cfg,
struct bhnd_chipid *result);
+bhndb_addrspace bhndb_get_addrspace(struct bhndb_softc *sc,
+ device_t child);
+
static struct rman *bhndb_get_rman(struct bhndb_softc *sc,
- int type);
+ device_t child, int type);
static int bhndb_init_child_resource(struct resource *r,
struct resource *parent,
@@ -509,6 +512,7 @@ bhndb_read_chipid(struct bhndb_softc *sc, const struct bhndb_hwcfg *cfg,
int
bhndb_attach(device_t dev, bhnd_devclass_t bridge_devclass)
{
+ struct bhndb_devinfo *dinfo;
struct bhndb_softc *sc;
const struct bhndb_hwcfg *cfg;
int error;
@@ -525,45 +529,30 @@ bhndb_attach(device_t dev, bhnd_devclass_t bridge_devclass)
if ((error = bhndb_read_chipid(sc, cfg, &sc->chipid)))
return (error);
- /* Set up a resource manager for the device's address space. */
- sc->mem_rman.rm_start = 0;
- sc->mem_rman.rm_end = BUS_SPACE_MAXADDR_32BIT;
- sc->mem_rman.rm_type = RMAN_ARRAY;
- sc->mem_rman.rm_descr = "BHND I/O memory addresses";
-
- if ((error = rman_init(&sc->mem_rman))) {
- device_printf(dev, "could not initialize mem_rman\n");
- return (error);
- }
-
- error = rman_manage_region(&sc->mem_rman, 0, BUS_SPACE_MAXADDR_32BIT);
- if (error) {
- device_printf(dev, "could not configure mem_rman\n");
- goto failed;
- }
-
- /* Initialize basic resource allocation state. */
+ /* Populate generic resource allocation state. */
sc->bus_res = bhndb_alloc_resources(dev, sc->parent_dev, cfg);
if (sc->bus_res == NULL) {
- error = ENXIO;
- goto failed;
+ return (ENXIO);
}
/* Attach our bridged bus device */
- sc->bus_dev = device_add_child(dev, devclass_get_name(bhnd_devclass),
+ sc->bus_dev = BUS_ADD_CHILD(dev, 0, devclass_get_name(bhnd_devclass),
-1);
if (sc->bus_dev == NULL) {
error = ENXIO;
goto failed;
}
+ /* Configure address space */
+ dinfo = device_get_ivars(sc->bus_dev);
+ dinfo->addrspace = BHNDB_ADDRSPACE_BRIDGED;
+
+ /* Finish attach */
return (bus_generic_attach(dev));
failed:
BHNDB_LOCK_DESTROY(sc);
- rman_fini(&sc->mem_rman);
-
if (sc->bus_res != NULL)
bhndb_free_resources(sc->bus_res);
@@ -680,7 +669,6 @@ bhndb_generic_detach(device_t dev)
return (error);
/* Clean up our driver state. */
- rman_fini(&sc->mem_rman);
bhndb_free_resources(sc->bus_res);
BHNDB_LOCK_DESTROY(sc);
@@ -826,24 +814,60 @@ bhndb_write_ivar(device_t dev, device_t child, int index,
}
/**
+ * Return the address space for the given @p child device.
+ */
+bhndb_addrspace
+bhndb_get_addrspace(struct bhndb_softc *sc, device_t child)
+{
+ struct bhndb_devinfo *dinfo;
+ device_t imd_dev;
+
+ /* Find the directly attached parent of the requesting device */
+ imd_dev = child;
+ while (imd_dev != NULL && device_get_parent(imd_dev) != sc->dev)
+ imd_dev = device_get_parent(imd_dev);
+
+ if (imd_dev == NULL)
+ panic("bhndb address space request for non-child device %s\n",
+ device_get_nameunit(child));
+
+ dinfo = device_get_ivars(imd_dev);
+ return (dinfo->addrspace);
+}
+
+/**
* Return the rman instance for a given resource @p type, if any.
*
* @param sc The bhndb device state.
+ * @param child The requesting child.
* @param type The resource type (e.g. SYS_RES_MEMORY, SYS_RES_IRQ, ...)
*/
static struct rman *
-bhndb_get_rman(struct bhndb_softc *sc, int type)
-{
- switch (type) {
- case SYS_RES_MEMORY:
- return &sc->mem_rman;
- case SYS_RES_IRQ:
- // TODO
- // return &sc->irq_rman;
- return (NULL);
- default:
- return (NULL);
- };
+bhndb_get_rman(struct bhndb_softc *sc, device_t child, int type)
+{
+ switch (bhndb_get_addrspace(sc, child)) {
+ case BHNDB_ADDRSPACE_NATIVE:
+ switch (type) {
+ case SYS_RES_MEMORY:
+ return (&sc->bus_res->ht_mem_rman);
+ case SYS_RES_IRQ:
+ return (NULL);
+ default:
+ return (NULL);
+ };
+
+ case BHNDB_ADDRSPACE_BRIDGED:
+ switch (type) {
+ case SYS_RES_MEMORY:
+ return (&sc->bus_res->br_mem_rman);
+ case SYS_RES_IRQ:
+ // TODO
+ // return &sc->irq_rman;
+ return (NULL);
+ default:
+ return (NULL);
+ };
+ }
}
/**
@@ -865,6 +889,7 @@ bhndb_add_child(device_t dev, u_int order, const char *name, int unit)
return (NULL);
}
+ dinfo->addrspace = BHNDB_ADDRSPACE_NATIVE;
resource_list_init(&dinfo->resources);
device_set_ivars(child, dinfo);
@@ -1062,7 +1087,7 @@ bhndb_alloc_resource(device_t dev, device_t child, int type,
return (NULL);
/* Fetch the resource manager */
- rm = bhndb_get_rman(sc, type);
+ rm = bhndb_get_rman(sc, child, type);
if (rm == NULL)
return (NULL);
@@ -1080,8 +1105,8 @@ bhndb_alloc_resource(device_t dev, device_t child, int type,
if (error) {
device_printf(dev,
"failed to activate entry %#x type %d for "
- "child %s\n",
- *rid, type, device_get_nameunit(child));
+ "child %s: %d\n",
+ *rid, type, device_get_nameunit(child), error);
rman_release_resource(rv);
@@ -1137,7 +1162,7 @@ bhndb_adjust_resource(device_t dev, device_t child, int type,
error = 0;
/* Fetch resource manager */
- rm = bhndb_get_rman(sc, type);
+ rm = bhndb_get_rman(sc, child, type);
if (rm == NULL)
return (ENXIO);
@@ -1159,7 +1184,8 @@ bhndb_adjust_resource(device_t dev, device_t child, int type,
/**
* Initialize child resource @p r with a virtual address, tag, and handle
- * copied from @p parent, adjusted to contain only the range defined by @p win.
+ * copied from @p parent, adjusted to contain only the range defined by
+ * @p offsize and @p size.
*
* @param r The register to be initialized.
* @param parent The parent bus resource that fully contains the subregion.
@@ -1171,7 +1197,6 @@ static int
bhndb_init_child_resource(struct resource *r,
struct resource *parent, bhnd_size_t offset, bhnd_size_t size)
{
-
bus_space_handle_t bh, child_bh;
bus_space_tag_t bt;
uintptr_t vaddr;
@@ -1335,13 +1360,39 @@ bhndb_try_activate_resource(struct bhndb_softc *sc, device_t child, int type,
if (indirect)
*indirect = false;
+
+ r_start = rman_get_start(r);
+ r_size = rman_get_size(r);
+
+ /* Activate native addrspace resources using the host address space */
+ if (bhndb_get_addrspace(sc, child) == BHNDB_ADDRSPACE_NATIVE) {
+ struct resource *parent;
+
+ /* Find the bridge resource referenced by the child */
+ parent = bhndb_find_resource_range(sc->bus_res, r_start,
+ r_size);
+ if (parent == NULL) {
+ device_printf(sc->dev, "host resource not found "
+ "for 0x%llx-0x%llx\n",
+ (unsigned long long) r_start,
+ (unsigned long long) r_start + r_size - 1);
+ return (ENOENT);
+ }
+
+ /* Initialize child resource with the real bus values */
+ error = bhndb_init_child_resource(r, parent,
+ r_start - rman_get_start(parent), r_size);
+ if (error)
+ return (error);
+
+ /* Try to activate child resource */
+ return (rman_activate_resource(r));
+ }
/* Default to low priority */
dw_priority = BHNDB_PRIORITY_LOW;
/* Look for a bus region matching the resource's address range */
- r_start = rman_get_start(r);
- r_size = rman_get_size(r);
region = bhndb_find_resource_region(sc->bus_res, r_start, r_size);
if (region != NULL)
dw_priority = region->priority;
@@ -1431,7 +1482,7 @@ bhndb_deactivate_resource(device_t dev, device_t child, int type,
sc = device_get_softc(dev);
- if ((rm = bhndb_get_rman(sc, type)) == NULL)
+ if ((rm = bhndb_get_rman(sc, child, type)) == NULL)
return (EINVAL);
/* Mark inactive */
@@ -1439,11 +1490,13 @@ bhndb_deactivate_resource(device_t dev, device_t child, int type,
return (error);
/* Free any dynamic window allocation. */
- BHNDB_LOCK(sc);
- dwa = bhndb_dw_find_resource(sc->bus_res, r);
- if (dwa != NULL)
- bhndb_dw_release(sc->bus_res, dwa, r);
- BHNDB_UNLOCK(sc);
+ if (bhndb_get_addrspace(sc, child) == BHNDB_ADDRSPACE_BRIDGED) {
+ BHNDB_LOCK(sc);
+ dwa = bhndb_dw_find_resource(sc->bus_res, r);
+ if (dwa != NULL)
+ bhndb_dw_release(sc->bus_res, dwa, r);
+ BHNDB_UNLOCK(sc);
+ }
return (0);
}
@@ -1516,9 +1569,13 @@ bhndb_release_bhnd_resource(device_t dev, device_t child,
/**
* Default bhndb(4) implementation of BHND_BUS_ACTIVATE_RESOURCE().
+ *
+ * For BHNDB_ADDRSPACE_NATIVE children, all resources may be assumed to
+ * be actived by the bridge.
*
- * Attempts to activate a static register window, a dynamic register window,
- * or configures @p r as an indirect resource -- in that order.
+ * For BHNDB_ADDRSPACE_BRIDGED children, attempts to activate a static register
+ * window, a dynamic register window, or configures @p r as an indirect
+ * resource -- in that order.
*/
static int
bhndb_activate_bhnd_resource(device_t dev, device_t child,
@@ -1526,7 +1583,6 @@ bhndb_activate_bhnd_resource(device_t dev, device_t child,
{
struct bhndb_softc *sc;
struct bhndb_region *region;
- bhndb_priority_t r_prio;
rman_res_t r_start, r_size;
int error;
bool indirect;
@@ -1539,19 +1595,25 @@ bhndb_activate_bhnd_resource(device_t dev, device_t child,
sc = device_get_softc(dev);
- /* Fetch the address range's resource priority */
r_start = rman_get_start(r->res);
r_size = rman_get_size(r->res);
- r_prio = BHNDB_PRIORITY_NONE;
- region = bhndb_find_resource_region(sc->bus_res, r_start, r_size);
- if (region != NULL)
- r_prio = region->priority;
-
- /* If less than the minimum dynamic window priority, this
- * resource should always be indirect. */
- if (r_prio < sc->bus_res->min_prio)
- return (0);
+ /* Verify bridged address range's resource priority, and skip direct
+ * allocation if the priority is too low. */
+ if (bhndb_get_addrspace(sc, child) == BHNDB_ADDRSPACE_BRIDGED) {
+ bhndb_priority_t r_prio;
+
+ region = bhndb_find_resource_region(sc->bus_res, r_start, r_size);
+ if (region != NULL)
+ r_prio = region->priority;
+ else
+ r_prio = BHNDB_PRIORITY_NONE;
+
+ /* If less than the minimum dynamic window priority, this
+ * resource should always be indirect. */
+ if (r_prio < sc->bus_res->min_prio)
+ return (0);
+ }
/* Attempt direct activation */
error = bhndb_try_activate_resource(sc, child, type, rid, r->res,
@@ -1565,7 +1627,9 @@ bhndb_activate_bhnd_resource(device_t dev, device_t child,
r->direct = false;
}
- if (BHNDB_DEBUG(PRIO)) {
+ if (BHNDB_DEBUG(PRIO) &&
+ bhndb_get_addrspace(sc, child) == BHNDB_ADDRSPACE_BRIDGED)
+ {
device_printf(child, "activated 0x%llx-0x%llx as %s "
"resource\n",
(unsigned long long) r_start,
diff --git a/sys/dev/bhnd/bhndb/bhndb_pci.c b/sys/dev/bhnd/bhndb/bhndb_pci.c
index ac5409af85a0..dd11c1249273 100644
--- a/sys/dev/bhnd/bhndb/bhndb_pci.c
+++ b/sys/dev/bhnd/bhndb/bhndb_pci.c
@@ -375,10 +375,18 @@ bhndb_pci_init_full_config(device_t dev, device_t child,
* access to the PCIe SerDes required by the quirk workarounds.
*/
if (sc->pci_devclass == BHND_DEVCLASS_PCIE) {
- sc->mdio = device_add_child(dev,
+ sc->mdio = BUS_ADD_CHILD(dev, 0,
devclass_get_name(bhnd_mdio_pci_devclass), 0);
if (sc->mdio == NULL)
return (ENXIO);
+
+ error = bus_set_resource(sc->mdio, SYS_RES_MEMORY, 0,
+ rman_get_start(sc->mem_res) + sc->mem_off +
+ BHND_PCIE_MDIO_CTL, sizeof(uint32_t)*2);
+ if (error) {
+ device_printf(dev, "failed to set MDIO resource\n");
+ return (error);
+ }
if ((error = device_probe_and_attach(sc->mdio))) {
device_printf(dev, "failed to attach MDIO device\n");
@@ -1021,25 +1029,6 @@ bhndb_pci_discover_quirks(struct bhndb_pci_softc *sc,
static int
bhndb_mdio_pcie_probe(device_t dev)
{
- struct bhndb_softc *psc;
- device_t parent;
-
- /* Parent must be a bhndb_pcie instance */
- parent = device_get_parent(dev);
- if (device_get_driver(parent) != &bhndb_pci_driver)
- return (ENXIO);
-
- /* Parent must have PCIe-Gen1 hostb device */
- psc = device_get_softc(parent);
- if (psc->hostb_dev == NULL)
- return (ENXIO);
-
- if (bhnd_get_vendor(psc->hostb_dev) != BHND_MFGID_BCM ||
- bhnd_get_device(psc->hostb_dev) != BHND_COREID_PCIE)
- {
- return (ENXIO);
- }
-
device_quiet(dev);
return (BUS_PROBE_NOWILDCARD);
}
@@ -1048,15 +1037,11 @@ static int
bhndb_mdio_pcie_attach(device_t dev)
{
struct bhndb_pci_softc *psc;
-
psc = device_get_softc(device_get_parent(dev));
-
return (bhnd_mdio_pcie_attach(dev,
&psc->bhnd_mem_res, -1,
psc->mem_off + BHND_PCIE_MDIO_CTL,
(psc->quirks & BHNDB_PCIE_QUIRK_SD_C22_EXTADDR) != 0));
-
- return (ENXIO);
}
static device_method_t bhnd_mdio_pcie_methods[] = {
diff --git a/sys/dev/bhnd/bhndb/bhndb_private.h b/sys/dev/bhnd/bhndb/bhndb_private.h
index c5dc2ff6137b..4171b534d104 100644
--- a/sys/dev/bhnd/bhndb/bhndb_private.h
+++ b/sys/dev/bhnd/bhndb/bhndb_private.h
@@ -50,6 +50,10 @@ struct bhndb_dw_alloc;
struct bhndb_region;
struct bhndb_resources;
+struct resource *bhndb_find_resource_range(
+ struct bhndb_resources *br,
+ rman_res_t start, rman_res_t count);
+
struct resource *bhndb_find_regwin_resource(
struct bhndb_resources *br,
const struct bhndb_regwin *win);
@@ -167,6 +171,9 @@ struct bhndb_resources {
device_t parent_dev; /**< parent device */
struct resource_spec *res_spec; /**< parent bus resource specs */
struct resource **res; /**< parent bus resources */
+
+ struct rman ht_mem_rman; /**< host memory manager */
+ struct rman br_mem_rman; /**< bridged memory manager */
STAILQ_HEAD(, bhndb_region) bus_regions; /**< bus region descriptors */
diff --git a/sys/dev/bhnd/bhndb/bhndb_subr.c b/sys/dev/bhnd/bhndb/bhndb_subr.c
index 932b4cc4cae2..f6b003aeba73 100644
--- a/sys/dev/bhnd/bhndb/bhndb_subr.c
+++ b/sys/dev/bhnd/bhndb/bhndb_subr.c
@@ -183,6 +183,39 @@ bhnd_generic_br_resume_child(device_t dev, device_t child)
}
/**
+ * Find a SYS_RES_MEMORY resource containing the given address range.
+ *
+ * @param br The bhndb resource state to search.
+ * @param start The start address of the range to search for.
+ * @param count The size of the range to search for.
+ *
+ * @retval resource the host resource containing the requested range.
+ * @retval NULL if no resource containing the requested range can be found.
+ */
+struct resource *
+bhndb_find_resource_range(struct bhndb_resources *br, rman_res_t start,
+ rman_res_t count)
+{
+ for (u_int i = 0; br->res_spec[i].type != -1; i++) {
+ struct resource *r = br->res[i];
+
+ if (br->res_spec->type != SYS_RES_MEMORY)
+ continue;
+
+ /* Verify range */
+ if (rman_get_start(r) > start)
+ continue;
+
+ if (rman_get_end(r) < (start + count - 1))
+ continue;
+
+ return (r);
+ }
+
+ return (NULL);
+}
+
+/**
* Find the resource containing @p win.
*
* @param br The bhndb resource state to search.
@@ -235,8 +268,11 @@ bhndb_alloc_resources(device_t dev, device_t parent_dev,
u_int rnid;
int error;
bool free_parent_res;
+ bool free_ht_mem, free_br_mem;
free_parent_res = false;
+ free_ht_mem = false;
+ free_br_mem = false;
r = malloc(sizeof(*r), M_BHND, M_NOWAIT|M_ZERO);
if (r == NULL)
@@ -249,6 +285,37 @@ bhndb_alloc_resources(device_t dev, device_t parent_dev,
r->min_prio = BHNDB_PRIORITY_NONE;
STAILQ_INIT(&r->bus_regions);
+ /* Initialize host address space resource manager. */
+ r->ht_mem_rman.rm_start = 0;
+ r->ht_mem_rman.rm_end = ~0;
+ r->ht_mem_rman.rm_type = RMAN_ARRAY;
+ r->ht_mem_rman.rm_descr = "BHNDB host memory";
+ if ((error = rman_init(&r->ht_mem_rman))) {
+ device_printf(r->dev, "could not initialize ht_mem_rman\n");
+ goto failed;
+ }
+ free_ht_mem = true;
+
+
+ /* Initialize resource manager for the bridged address space. */
+ r->br_mem_rman.rm_start = 0;
+ r->br_mem_rman.rm_end = BUS_SPACE_MAXADDR_32BIT;
+ r->br_mem_rman.rm_type = RMAN_ARRAY;
+ r->br_mem_rman.rm_descr = "BHNDB bridged memory";
+
+ if ((error = rman_init(&r->br_mem_rman))) {
+ device_printf(r->dev, "could not initialize br_mem_rman\n");
+ goto failed;
+ }
+ free_br_mem = true;
+
+ error = rman_manage_region(&r->br_mem_rman, 0, BUS_SPACE_MAXADDR_32BIT);
+ if (error) {
+ device_printf(r->dev, "could not configure br_mem_rman\n");
+ goto failed;
+ }
+
+
/* Determine our bridge resource count from the hardware config. */
res_num = 0;
for (size_t i = 0; cfg->resource_specs[i].type != -1; i++)
@@ -284,6 +351,26 @@ bhndb_alloc_resources(device_t dev, device_t parent_dev,
free_parent_res = true;
}
+ /* Add allocated memory resources to our host memory resource manager */
+ for (u_int i = 0; r->res_spec[i].type != -1; i++) {
+ struct resource *res;
+
+ /* skip non-memory resources */
+ if (r->res_spec[i].type != SYS_RES_MEMORY)
+ continue;
+
+ /* add host resource to set of managed regions */
+ res = r->res[i];
+ error = rman_manage_region(&r->ht_mem_rman, rman_get_start(res),
+ rman_get_end(res));
+ if (error) {
+ device_printf(r->dev,
+ "could not register host memory region with "
+ "ht_mem_rman: %d\n", error);
+ goto failed;
+ }
+ }
+
/* Fetch the dynamic regwin count and verify that it does not exceed
* what is representable via our freelist bitmask. */
r->dwa_count = bhndb_regwin_count(cfg->register_windows,
@@ -371,6 +458,12 @@ bhndb_alloc_resources(device_t dev, device_t parent_dev,
failed:
if (free_parent_res)
bus_release_resources(r->parent_dev, r->res_spec, r->res);
+
+ if (free_ht_mem)
+ rman_fini(&r->ht_mem_rman);
+
+ if (free_br_mem)
+ rman_fini(&r->br_mem_rman);
if (r->res != NULL)
free(r->res, M_BHND);
@@ -423,6 +516,10 @@ bhndb_free_resources(struct bhndb_resources *br)
free(region, M_BHND);
}
+ /* Release our resource managers */
+ rman_fini(&br->ht_mem_rman);
+ rman_fini(&br->br_mem_rman);
+
/* Free backing resource state structures */
free(br->res, M_BHND);
free(br->res_spec, M_BHND);
diff --git a/sys/dev/bhnd/bhndb/bhndbvar.h b/sys/dev/bhnd/bhndb/bhndbvar.h
index f993e7ce76d3..6c7010258c02 100644
--- a/sys/dev/bhnd/bhndb/bhndbvar.h
+++ b/sys/dev/bhnd/bhndb/bhndbvar.h
@@ -65,9 +65,20 @@ int bhndb_generic_init_full_config(device_t dev, device_t child,
int bhnd_generic_br_suspend_child(device_t dev, device_t child);
int bhnd_generic_br_resume_child(device_t dev, device_t child);
+/**
+ * bhndb child address space. Children either operate in the bridged
+ * SoC address space, or within the address space mapped to the host
+ * device (e.g. the PCI BAR(s)).
+ */
+typedef enum {
+ BHNDB_ADDRSPACE_BRIDGED, /**< bridged (SoC) address space */
+ BHNDB_ADDRSPACE_NATIVE /**< host address space */
+} bhndb_addrspace;
+
/** bhndb child instance state */
struct bhndb_devinfo {
- struct resource_list resources; /**< child resources. */
+ bhndb_addrspace addrspace; /**< child address space. */
+ struct resource_list resources; /**< child resources. */
};
/**
@@ -85,9 +96,7 @@ struct bhndb_softc {
if the @p bus_dev has not yet
called BHNDB_INIT_FULL_CONFIG() */
- struct rman mem_rman; /**< bridged bus memory manager */
struct mtx sc_mtx; /**< resource lock. */
-
struct bhndb_resources *bus_res; /**< bus resource state */
};