Index: sys/kern/bus_if.m =================================================================== --- sys/kern/bus_if.m +++ sys/kern/bus_if.m @@ -274,8 +274,9 @@ * @brief Activate a resource * * Activate a resource previously allocated with - * BUS_ALLOC_RESOURCE(). This may for instance map a memory region - * into the kernel's virtual address space. + * BUS_ALLOC_RESOURCE(). This may enable decoding of this resource in a + * device for instance. It will also establish a mapping for the resource + * unless RF_UNMAPPED was set when allocating the resource. * * @param _dev the parent device of @p _child * @param _child the device which allocated the resource @@ -291,12 +292,58 @@ struct resource *_r; }; + +/** + * @brief Map a resource + * + * Allocate a mapping for a range of an active resource. The mapping + * is described by a struct resource_map object. This may for instance + * map a memory region into the kernel's virtual address space. + * + * @param _dev the parent device of @p _child + * @param _child the device which allocated the resource + * @param _type the type of resource + * @param _r the resource to map + * @param _args optional attributes of the mapping + * @param _map the mapping + */ +METHOD int map_resource { + device_t _dev; + device_t _child; + int _type; + struct resource *_r; + struct resource_map_request *_args; + struct resource_map *_map; +} DEFAULT bus_generic_map_resource; + + +/** + * @brief Unmap a resource + * + * Release a mapping previously allocated with + * BUS_MAP_RESOURCE(). This may for instance unmap a memory region + * from the kernel's virtual address space. + * + * @param _dev the parent device of @p _child + * @param _child the device which allocated the resource + * @param _type the type of resource + * @param _r the resource + * @param _map the mapping to release + */ +METHOD int unmap_resource { + device_t _dev; + device_t _child; + int _type; + struct resource *_r; + struct resource_map *_map; +} DEFAULT bus_generic_unmap_resource; + + /** * @brief Deactivate a resource * * Deactivate a resource previously allocated with - * BUS_ALLOC_RESOURCE(). This may for instance unmap a memory region - * from the kernel's virtual address space. + * BUS_ALLOC_RESOURCE(). * * @param _dev the parent device of @p _child * @param _child the device which allocated the resource Index: sys/kern/subr_bus.c =================================================================== --- sys/kern/subr_bus.c +++ sys/kern/subr_bus.c @@ -3017,6 +3017,15 @@ * Some useful method implementations to make life easier for bus drivers. */ +void +resource_init_map_request_impl(struct resource_map_request *args, size_t sz) +{ + + bzero(args, sz); + args->size = sz; + args->memattr = VM_MEMATTR_UNCACHEABLE; +} + /** * @brief Initialise a resource list. * @@ -4027,6 +4036,40 @@ } /** + * @brief Helper function for implementing BUS_MAP_RESOURCE(). + * + * This simple implementation of BUS_MAP_RESOURCE() simply calls the + * BUS_MAP_RESOURCE() method of the parent of @p dev. + */ +int +bus_generic_map_resource(device_t dev, device_t child, int type, + struct resource *r, struct resource_map_request *args, + struct resource_map *map) +{ + /* Propagate up the bus hierarchy until someone handles it. */ + if (dev->parent) + return (BUS_MAP_RESOURCE(dev->parent, child, type, r, args, + map)); + return (EINVAL); +} + +/** + * @brief Helper function for implementing BUS_UNMAP_RESOURCE(). + * + * This simple implementation of BUS_UNMAP_RESOURCE() simply calls the + * BUS_UNMAP_RESOURCE() method of the parent of @p dev. + */ +int +bus_generic_unmap_resource(device_t dev, device_t child, int type, + struct resource *r, struct resource_map *map) +{ + /* Propagate up the bus hierarchy until someone handles it. */ + if (dev->parent) + return (BUS_UNMAP_RESOURCE(dev->parent, child, type, r, map)); + return (EINVAL); +} + +/** * @brief Helper function for implementing BUS_BIND_INTR(). * * This simple implementation of BUS_BIND_INTR() simply calls the @@ -4342,6 +4385,36 @@ } /** + * @brief Wrapper function for BUS_MAP_RESOURCE(). + * + * This function simply calls the BUS_MAP_RESOURCE() method of the + * parent of @p dev. + */ +int +bus_map_resource(device_t dev, int type, struct resource *r, + struct resource_map_request *args, struct resource_map *map) +{ + if (dev->parent == NULL) + return (EINVAL); + return (BUS_MAP_RESOURCE(dev->parent, dev, type, r, args, map)); +} + +/** + * @brief Wrapper function for BUS_UNMAP_RESOURCE(). + * + * This function simply calls the BUS_UNMAP_RESOURCE() method of the + * parent of @p dev. + */ +int +bus_unmap_resource(device_t dev, int type, struct resource *r, + struct resource_map *map) +{ + if (dev->parent == NULL) + return (EINVAL); + return (BUS_UNMAP_RESOURCE(dev->parent, dev, type, r, map)); +} + +/** * @brief Wrapper function for BUS_RELEASE_RESOURCE(). * * This function simply calls the BUS_RELEASE_RESOURCE() method of the Index: sys/sys/bus.h =================================================================== --- sys/sys/bus.h +++ sys/sys/bus.h @@ -277,6 +277,31 @@ KOBJ_CLASS_FIELDS; }; +/** + * @brief A resource mapping. + */ +struct resource_map { + bus_space_tag_t r_bustag; + bus_space_handle_t r_bushandle; + bus_size_t r_size; + void *r_vaddr; +}; + +/** + * @brief Optional properties of a resource mapping request. + */ +struct resource_map_request { + size_t size; + rman_res_t offset; + rman_res_t length; + vm_memattr_t memattr; +}; + +void resource_init_map_request_impl(struct resource_map_request *_args, + size_t _sz); +#define resource_init_map_request(rmr) \ + resource_init_map_request_impl((rmr), sizeof(*(rmr))) + /* * Definitions for drivers which need to keep simple lists of resources * for their child devices. @@ -386,6 +411,10 @@ int bus_generic_get_domain(device_t dev, device_t child, int *domain); struct resource_list * bus_generic_get_resource_list (device_t, device_t); +int bus_generic_map_resource(device_t dev, device_t child, int type, + struct resource *r, + struct resource_map_request *args, + struct resource_map *map); void bus_generic_new_pass(device_t dev); int bus_print_child_header(device_t dev, device_t child); int bus_print_child_domain(device_t dev, device_t child); @@ -419,6 +448,9 @@ int bus_generic_suspend_child(device_t dev, device_t child); int bus_generic_teardown_intr(device_t dev, device_t child, struct resource *irq, void *cookie); +int bus_generic_unmap_resource(device_t dev, device_t child, int type, + struct resource *r, + struct resource_map *map); int bus_generic_write_ivar(device_t dev, device_t child, int which, uintptr_t value); @@ -447,6 +479,11 @@ struct resource *r); int bus_deactivate_resource(device_t dev, int type, int rid, struct resource *r); +int bus_map_resource(device_t dev, int type, struct resource *r, + struct resource_map_request *args, + struct resource_map *map); +int bus_unmap_resource(device_t dev, int type, struct resource *r, + struct resource_map *map); bus_dma_tag_t bus_get_dma_tag(device_t dev); int bus_get_domain(device_t dev, int *domain); int bus_release_resource(device_t dev, int type, int rid, Index: sys/sys/rman.h =================================================================== --- sys/sys/rman.h +++ sys/sys/rman.h @@ -47,6 +47,7 @@ #define RF_FIRSTSHARE 0x0020 /* first in sharing list */ #define RF_PREFETCHABLE 0x0040 /* resource is prefetchable */ #define RF_OPTIONAL 0x0080 /* for bus_alloc_resources() */ +#define RF_UNMAPPED 0x0100 /* don't map resource when activating */ #define RF_ALIGNMENT_SHIFT 10 /* alignment size bit starts bit 10 */ #define RF_ALIGNMENT_MASK (0x003F << RF_ALIGNMENT_SHIFT) Index: sys/vm/vm.h =================================================================== --- sys/vm/vm.h +++ sys/vm/vm.h @@ -109,8 +109,9 @@ typedef int boolean_t; /* - * The exact set of memory attributes is machine dependent. However, every - * machine is required to define VM_MEMATTR_DEFAULT. + * The exact set of memory attributes is machine dependent. However, + * every machine is required to define VM_MEMATTR_DEFAULT and + * VM_MEMATTR_UNCACHEABLE. */ typedef char vm_memattr_t; /* memory attribute codes */ Index: sys/x86/x86/nexus.c =================================================================== --- sys/x86/x86/nexus.c +++ sys/x86/x86/nexus.c @@ -115,6 +115,12 @@ struct resource *); static int nexus_deactivate_resource(device_t, device_t, int, int, struct resource *); +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); +static int nexus_unmap_resource(device_t bus, device_t child, int type, + struct resource *r, struct resource_map *map); static int nexus_release_resource(device_t, device_t, int, int, struct resource *); static int nexus_setup_intr(device_t, device_t, struct resource *, int flags, @@ -153,6 +159,8 @@ DEVMETHOD(bus_release_resource, nexus_release_resource), DEVMETHOD(bus_activate_resource, nexus_activate_resource), DEVMETHOD(bus_deactivate_resource, nexus_deactivate_resource), + DEVMETHOD(bus_map_resource, nexus_map_resource), + DEVMETHOD(bus_unmap_resource, nexus_unmap_resource), DEVMETHOD(bus_setup_intr, nexus_setup_intr), DEVMETHOD(bus_teardown_intr, nexus_teardown_intr), #ifdef SMP @@ -426,12 +434,79 @@ nexus_activate_resource(device_t bus, device_t child, int type, int rid, struct resource *r) { + struct resource_map map; + int error; + void *vaddr; + + error = rman_activate_resource(r); + if (error != 0) + return (error); + + if (rman_get_flags(r) & RF_UNMAPPED) + return (0); + + error = nexus_map_resource(bus, child, type, r, NULL, &map); + if (error) { + rman_deactivate_resource(r); + return (error); + } + + rman_set_bustag(r, map->r_tag); + rman_set_bushandle(r, map->r_handle); + rman_set_virtual(r, map->r_vaddr); + return (0); +} + +static int +nexus_deactivate_resource(device_t bus, device_t child, int type, int rid, + struct resource *r) +{ + struct resource_map map; + int error; + + error = rman_deactivate_resource(r); + if (error) + return (error); + + if (rman_get_flags(r) & RF_UNMAPPED) + return (0); + + map.r_tag = rman_get_bustag(r); + map.r_handle = rman_get_bushandle(r); + map.r_size = rman_get_size(r); + map.r_vaddr = rman_get_virtual(r); + nexus_unmap_resource(bus, child, type, r, &map); + return (0); +} + +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 start, size; #ifdef PC98 - bus_space_handle_t bh; int error; #endif void *vaddr; + /* Resources must be active to be mapped. */ + if (!(rman_get_flags(r) & RF_ACTIVE)) + return (ENXIO); + + 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.size == 0) + size = rman_get_size(r); + else + size = args.size; + if (start > rman_get_end(r) || start < rman_get_start(r)) + return (EINVAL); + if (start + size > rman_get_end(r) || start + size < start) + return (EINVAL); + /* * If this is a memory resource, map it into the kernel. */ @@ -439,58 +514,59 @@ case SYS_RES_IOPORT: #ifdef PC98 error = i386_bus_space_handle_alloc(X86_BUS_SPACE_IO, - rman_get_start(r), rman_get_size(r), &bh); + start, size, &map->r_handle); if (error) return (error); - rman_set_bushandle(r, bh); #else - rman_set_bushandle(r, rman_get_start(r)); + map->r_handle = start; #endif - rman_set_bustag(r, X86_BUS_SPACE_IO); + map->r_tag = X86_BUS_SPACE_IO; + map->r_size = size; + map->r_vaddr = NULL; break; case SYS_RES_MEMORY: #ifdef PC98 error = i386_bus_space_handle_alloc(X86_BUS_SPACE_MEM, - rman_get_start(r), rman_get_size(r), &bh); + start, size, &map->r_handle); if (error) return (error); #endif - vaddr = pmap_mapdev(rman_get_start(r), rman_get_size(r)); - rman_set_virtual(r, vaddr); - rman_set_bustag(r, X86_BUS_SPACE_MEM); + map->r_vaddr = pmap_mapdev_attr(start, size, args.memattr); + map->r_tag = X86_BUS_SPACE_MEM; + map->r_size = size; + + /* + * PC-98 stores the virtual address as a member of the + * structure in the handle. On plain x86, the handle is + * the virtual address. + */ #ifdef PC98 - /* PC-98: the type of bus_space_handle_t is the structure. */ - bh->bsh_base = (bus_addr_t) vaddr; - rman_set_bushandle(r, bh); + map->r_handle->bsh_base = (bus_addr_t)vaddr; #else - /* IBM-PC: the type of bus_space_handle_t is u_int */ - rman_set_bushandle(r, (bus_space_handle_t) vaddr); + map->r_handle = (bus_space_handle_t)vaddr; #endif + break; } - return (rman_activate_resource(r)); + return (0); } static int -nexus_deactivate_resource(device_t bus, device_t child, int type, int rid, - struct resource *r) +nexus_unmap_resource(device_t bus, device_t child, int type, struct resource *r, + struct resource_map *map) { - + /* * If this is a memory resource, unmap it. */ - if (type == SYS_RES_MEMORY) { - pmap_unmapdev((vm_offset_t)rman_get_virtual(r), - rman_get_size(r)); - } + if (type == SYS_RES_MEMORY) + pmap_unmapdev((vm_offset_t)map->r_vaddr, map->r_size); #ifdef PC98 if (type == SYS_RES_MEMORY || type == SYS_RES_IOPORT) { - bus_space_handle_t bh; - - bh = rman_get_bushandle(r); - i386_bus_space_handle_free(rman_get_bustag(r), bh, bh->bsh_sz); + i386_bus_space_handle_free(map->r_tag, map->r_handle, + map->r_handle->bsh_sz); } #endif - return (rman_deactivate_resource(r)); + return (0); } static int