diff --git a/sys/arm64/arm64/nexus.c b/sys/arm64/arm64/nexus.c --- a/sys/arm64/arm64/nexus.c +++ b/sys/arm64/arm64/nexus.c @@ -106,6 +106,8 @@ rman_res_t, rman_res_t, rman_res_t, u_int); static int nexus_activate_resource(device_t, device_t, int, int, struct resource *); +static int nexus_map_resource(device_t, device_t, int, struct resource *, + struct resource_map_request *, struct resource_map *); static int nexus_config_intr(device_t dev, int irq, enum intr_trigger trig, enum intr_polarity pol); static struct resource_list *nexus_get_reslist(device_t, device_t); @@ -135,6 +137,7 @@ DEVMETHOD(bus_add_child, nexus_add_child), DEVMETHOD(bus_alloc_resource, nexus_alloc_resource), DEVMETHOD(bus_activate_resource, nexus_activate_resource), + DEVMETHOD(bus_map_resource, nexus_map_resource), DEVMETHOD(bus_config_intr, nexus_config_intr), DEVMETHOD(bus_get_resource_list, nexus_get_reslist), DEVMETHOD(bus_set_resource, nexus_set_resource), @@ -344,10 +347,8 @@ nexus_activate_resource(device_t bus, device_t child, int type, int rid, struct resource *r) { + struct resource_map map; int err; - bus_addr_t paddr; - bus_size_t psize; - bus_space_handle_t vaddr; if ((err = rman_activate_resource(r)) != 0) return (err); @@ -355,18 +356,21 @@ /* * If this is a memory resource, map it into the kernel. */ - if (type == SYS_RES_MEMORY || type == SYS_RES_IOPORT) { - paddr = (bus_addr_t)rman_get_start(r); - psize = (bus_size_t)rman_get_size(r); - err = bus_space_map(&memmap_bus, paddr, psize, 0, &vaddr); - if (err != 0) { - rman_deactivate_resource(r); - return (err); + switch (type) { + case SYS_RES_IOPORT: + case SYS_RES_MEMORY: + if ((rman_get_flags(r) & RF_UNMAPPED) == 0) { + err = nexus_map_resource(bus, child, type, r, NULL, + &map); + if (err != 0) { + rman_deactivate_resource(r); + return (err); + } + + rman_set_mapping(r, &map); } - rman_set_bustag(r, &memmap_bus); - rman_set_virtual(r, (void *)vaddr); - rman_set_bushandle(r, vaddr); - } else if (type == SYS_RES_IRQ) { + break; + case SYS_RES_IRQ: err = intr_activate_irq(child, r); if (err != 0) { rman_deactivate_resource(r); @@ -420,6 +424,51 @@ return (rman_deactivate_resource(r)); } +static int +nexus_map_resource(device_t bus, device_t child, int type, struct resource *r, + struct resource_map_request *argsp, struct resource_map *map) +{ + struct resource_map_request args; + rman_res_t end, length, start; + + /* Resources must be active to be mapped. */ + if ((rman_get_flags(r) & RF_ACTIVE) == 0) + return (ENXIO); + + /* Mappings are only supported on I/O and memory resources. */ + switch (type) { + case SYS_RES_IOPORT: + case SYS_RES_MEMORY: + break; + default: + return (EINVAL); + } + + resource_init_map_request(&args); + if (argsp != NULL) + bcopy(argsp, &args, imin(argsp->size, args.size)); + start = rman_get_start(r) + args.offset; + if (args.length == 0) + length = rman_get_size(r); + else + length = args.length; + end = start + length - 1; + if (start > rman_get_end(r) || start < rman_get_start(r)) + return (EINVAL); + if (end > rman_get_end(r) || end < start) + return (EINVAL); + + map->r_vaddr = pmap_mapdev_attr(start, length, args.memattr); + map->r_bustag = &memmap_bus; + map->r_size = length; + + /* + * The handle is the virtual address. + */ + map->r_bushandle = (bus_space_handle_t)map->r_vaddr; + return (0); +} + #ifdef FDT static device_method_t nexus_fdt_methods[] = { /* Device interface */