diff options
author | landonf <landonf@FreeBSD.org> | 2016-06-04 19:31:06 +0000 |
---|---|---|
committer | landonf <landonf@FreeBSD.org> | 2016-06-04 19:31:06 +0000 |
commit | 05a96f91516b68de58945e078d1b08834517db86 (patch) | |
tree | 9945ad132f35c47ec7b89498af667c639ecfd8cf /sys/dev/bhnd/cores/chipc/chipc.c | |
parent | 09864b3ba8f32d9521c64080dcd867e8c5936560 (diff) | |
download | FreeBSD-src-05a96f91516b68de58945e078d1b08834517db86.zip FreeBSD-src-05a96f91516b68de58945e078d1b08834517db86.tar.gz |
Fix several MIPS/BCM-blocking bugs in bhnd(4) chipc
- Correct IRQ lines for UART (to fix IRQ lookup in future)
- Check device unit in resource assignment during chipc_add_child
- If chipc hint->size is RM_MAX_END, resource end should be same as window end
- Clear reference from resource list entry to resource in case of resource release
- Add CHIPC_GET_CAPS implementation
- Correct chipc flash constants (to be unshifted)
- Default implementation of get_attach_type should iterate over device tree
- Add default implementation for BHND_CHIPC_GET_CAPS usable by chipc grandchildren
Submitted by: Michael Zhilin <mizhka@gmail.com>
Approved by: adrian (mentor)
Differential Revision: https://reviews.freebsd.org/D6584
Diffstat (limited to 'sys/dev/bhnd/cores/chipc/chipc.c')
-rw-r--r-- | sys/dev/bhnd/cores/chipc/chipc.c | 77 |
1 files changed, 64 insertions, 13 deletions
diff --git a/sys/dev/bhnd/cores/chipc/chipc.c b/sys/dev/bhnd/cores/chipc/chipc.c index 6fce0da..c4c7df1 100644 --- a/sys/dev/bhnd/cores/chipc/chipc.c +++ b/sys/dev/bhnd/cores/chipc/chipc.c @@ -110,12 +110,13 @@ static const struct chipc_hint { u_int region; } chipc_hints[] = { // FIXME: cfg/spi port1.1 mapping on siba(4) SoCs + // FIXME: IRQ shouldn't be hardcoded /* device unit type rid base size port,region */ { "bhnd_nvram", 0, SYS_RES_MEMORY, 0, CHIPC_SPROM_OTP, CHIPC_SPROM_OTP_SIZE, 0,0 }, { "uart", 0, SYS_RES_MEMORY, 0, CHIPC_UART0_BASE, CHIPC_UART_SIZE, 0,0 }, - { "uart", 0, SYS_RES_IRQ, 0, 0, RM_MAX_END }, + { "uart", 0, SYS_RES_IRQ, 0, 2, 1 }, { "uart", 1, SYS_RES_MEMORY, 0, CHIPC_UART1_BASE, CHIPC_UART_SIZE, 0,0 }, - { "uart", 1, SYS_RES_IRQ, 0, 0, RM_MAX_END }, + { "uart", 1, SYS_RES_IRQ, 0, 2, 1 }, { "spi", 0, SYS_RES_MEMORY, 0, 0, RM_MAX_END, 1,1 }, { "spi", 0, SYS_RES_MEMORY, 1, CHIPC_SFLASH_BASE, CHIPC_SFLASH_SIZE, 0,0 }, { "cfi", 0, SYS_RES_MEMORY, 0, 0, RM_MAX_END, 1,1}, @@ -480,12 +481,30 @@ chipc_add_child(device_t dev, u_int order, const char *name, int unit) struct chipc_devinfo *dinfo; const struct chipc_hint *hint; device_t child; + devclass_t child_dc; int error; + int busrel_unit; child = device_add_child_ordered(dev, order, name, unit); if (child == NULL) return (NULL); + /* system-wide device unit */ + unit = device_get_unit(child); + child_dc = device_get_devclass(child); + + busrel_unit = 0; + for (int i = 0; i < unit; i++) { + device_t tmp; + + tmp = devclass_get_device(child_dc, i); + if (tmp != NULL && (device_get_parent(tmp) == dev)) + busrel_unit++; + } + + /* bus-wide device unit (override unit for further hint matching) */ + unit = busrel_unit; + dinfo = malloc(sizeof(struct chipc_devinfo), M_BHND, M_NOWAIT); if (dinfo == NULL) { device_delete_child(dev, child); @@ -504,9 +523,14 @@ chipc_add_child(device_t dev, u_int order, const char *name, int unit) bhnd_addr_t region_addr; bhnd_size_t region_size; + /* Check device name */ if (strcmp(hint->name, name) != 0) continue; + /* Check device unit */ + if (hint->unit >= 0 && unit != hint->unit) + continue; + switch (hint->type) { case SYS_RES_IRQ: /* Add child resource */ @@ -535,8 +559,9 @@ chipc_add_child(device_t dev, u_int order, const char *name, int unit) /* Verify requested range is mappable */ if (hint->base > region_size || - hint->size > region_size || - region_size - hint->base < hint->size ) + (hint->size != RM_MAX_END && + (hint->size > region_size || + region_size - hint->base < hint->size ))) { device_printf(dev, "%s%u.%u region cannot map requested range " @@ -546,9 +571,17 @@ chipc_add_child(device_t dev, u_int order, const char *name, int unit) hint->size); } - /* Add child resource */ - error = bus_set_resource(child, hint->type, - hint->rid, region_addr + hint->base, hint->size); + /* + * Add child resource. If hint doesn't define the end + * of resource window (RX_MAX_END), use end of region. + */ + + error = bus_set_resource(child, + hint->type, + hint->rid, region_addr + hint->base, + (hint->size == RM_MAX_END) ? + region_size - hint->base : + hint->size); if (error) { device_printf(dev, "bus_set_resource() failed for %s: %d\n", @@ -754,8 +787,10 @@ chipc_alloc_resource(device_t dev, device_t child, int type, if (rle->res != NULL) { device_printf(dev, - "resource entry %#x type %d for child %s is busy\n", - *rid, type, device_get_nameunit(child)); + "resource entry %#x type %d for child %s is busy " + "[%d]\n", + *rid, type, device_get_nameunit(child), + rman_get_flags(rle->res)); return (NULL); } @@ -821,10 +856,11 @@ static int chipc_release_resource(device_t dev, device_t child, int type, int rid, struct resource *r) { - struct chipc_softc *sc; - struct chipc_region *cr; - struct rman *rm; - int error; + struct chipc_softc *sc; + struct chipc_region *cr; + struct rman *rm; + struct resource_list_entry *rle; + int error; sc = device_get_softc(dev); @@ -853,6 +889,11 @@ chipc_release_resource(device_t dev, device_t child, int type, int rid, /* Drop allocation reference */ chipc_release_region(sc, cr, RF_ALLOCATED); + /* Clear reference from the resource list entry if exists */ + rle = resource_list_find(BUS_GET_RESOURCE_LIST(dev, child), type, rid); + if (rle != NULL) + rle->res = NULL; + return (0); } @@ -1238,6 +1279,15 @@ chipc_write_chipctrl(device_t dev, uint32_t value, uint32_t mask) CHIPC_UNLOCK(sc); } +static struct chipc_caps * +chipc_get_caps(device_t dev) +{ + struct chipc_softc *sc; + + sc = device_get_softc(dev); + return (&sc->caps); +} + static device_method_t chipc_methods[] = { /* Device interface */ DEVMETHOD(device_probe, chipc_probe), @@ -1279,6 +1329,7 @@ static device_method_t chipc_methods[] = { DEVMETHOD(bhnd_chipc_write_chipctrl, chipc_write_chipctrl), DEVMETHOD(bhnd_chipc_enable_sprom, chipc_enable_sprom_pins), DEVMETHOD(bhnd_chipc_disable_sprom, chipc_disable_sprom_pins), + DEVMETHOD(bhnd_chipc_get_caps, chipc_get_caps), DEVMETHOD_END }; |