Index: sys/amd64/include/vm.h =================================================================== --- sys/amd64/include/vm.h +++ sys/amd64/include/vm.h @@ -41,5 +41,6 @@ #define VM_MEMATTR_WEAK_UNCACHEABLE ((vm_memattr_t)PAT_UNCACHED) #define VM_MEMATTR_DEFAULT VM_MEMATTR_WRITE_BACK +#define VM_MEMATTR_DEVICE_DEFAULT VM_MEMATTR_UNCACHEABLE #endif /* !_MACHINE_VM_H_ */ Index: sys/i386/include/vm.h =================================================================== --- sys/i386/include/vm.h +++ sys/i386/include/vm.h @@ -41,5 +41,6 @@ #define VM_MEMATTR_WEAK_UNCACHEABLE ((vm_memattr_t)PAT_UNCACHED) #define VM_MEMATTR_DEFAULT VM_MEMATTR_WRITE_BACK +#define VM_MEMATTR_DEVICE_DEFAULT VM_MEMATTR_UNCACHEABLE #endif /* !_MACHINE_VM_H_ */ 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,62 @@ struct resource *_r; }; + +/** + * @brief Map a resource + * + * Allocate a mapping for a range of an active resource. The mapping + * is described by a bus space tag and handle. 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 _tag the tag for the mapping + * @param _handle the handle for the mapping + */ +METHOD int map_resource { + device_t _dev; + device_t _child; + int _type; + struct resource *_r; + struct resource_map_request *_args; + bus_space_tag_t *_tag; + bus_space_handle_t *_handle; +}; + + +/** + * @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 _tag the tag of the mapping to release + * @param _handle the handle of the mapping to release + */ +METHOD int unmap_resource { + device_t _dev; + device_t _child; + int _type; + struct resource *_r; + bus_space_tag_t _tag; + bus_space_handle_t _handle; +}; + + /** * @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 @@ -4027,6 +4027,41 @@ } /** + * @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, bus_space_tag_t *tag, + bus_space_handle_t *handle) +{ + /* Propagate up the bus hierarchy until someone handles it. */ + if (dev->parent) + return (BUS_MAP_RESOURCE(dev->parent, child, type, r, args, tag, + handle)); + 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, bus_space_tag_t tag, bus_space_handle_t handle) +{ + /* Propagate up the bus hierarchy until someone handles it. */ + if (dev->parent) + return (BUS_UNMAP_RESOURCE(dev->parent, child, type, r, tag, + handle)); + return (EINVAL); +} + +/** * @brief Helper function for implementing BUS_BIND_INTR(). * * This simple implementation of BUS_BIND_INTR() simply calls the @@ -4342,6 +4377,37 @@ } /** + * @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, bus_space_tag_t *tag, + bus_space_handle_t *handle) +{ + if (dev->parent == NULL) + return (EINVAL); + return (BUS_MAP_RESOURCE(dev->parent, dev, type, r, args, tag, handle)); +} + +/** + * @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, + bus_space_tag_t tag, bus_space_handle_t handle) +{ + if (dev->parent == NULL) + return (EINVAL); + return (BUS_UNMAP_RESOURCE(dev->parent, dev, type, r, tag, handle)); +} + +/** * @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,22 @@ KOBJ_CLASS_FIELDS; }; +/** + * @brief Optional properties of a resource mapping request. + */ +struct resource_map_request { + int size; + rman_res_t offset; + rman_res_t length; + vm_memattr_t memattr; +}; + +#define resource_init_map_request(rmr) do { \ + bzero((rmr), sizeof(*(rmr))); \ + (rmr)->size = sizeof(*(rmr)); \ + (rmr)->memattr = VM_MEMATTR_DEVICE_DEFAULT; \ +} while (0) + /* * Definitions for drivers which need to keep simple lists of resources * for their child devices. @@ -386,6 +402,11 @@ 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, + bus_space_tag_t *tag, + bus_space_handle_t *handle); 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 +440,10 @@ 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, + bus_space_tag_t tag, + bus_space_handle_t handle); int bus_generic_write_ivar(device_t dev, device_t child, int which, uintptr_t value); @@ -447,6 +472,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, + bus_space_tag_t *tag, bus_space_handle_t *handle); +int bus_unmap_resource(device_t dev, int type, struct resource *r, + bus_space_tag_t tag, bus_space_handle_t handle); 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/x86/x86/nexus.c =================================================================== --- sys/x86/x86/nexus.c +++ sys/x86/x86/nexus.c @@ -115,6 +115,14 @@ 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, + bus_space_tag_t *tag, + bus_space_handle_t *handle); +static int nexus_unmap_resource(device_t bus, device_t child, int type, + struct resource *r, bus_space_tag_t tag, + bus_space_handle_t handle); 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 +161,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 +436,86 @@ nexus_activate_resource(device_t bus, device_t child, int type, int rid, struct resource *r) { + bus_space_tag_t tag; + bus_space_handle_t handle; + 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, &tag, &handle); + if (error) { + rman_deactivate_resource(r); + return (error); + } + + rman_set_bustag(r, tag); + rman_set_bushandle(r, handle); + if (type == SYS_RES_MEMORY) { +#ifdef PC98 + /* PC-98: the type of bus_space_handle_t is the structure. */ + vaddr = (void *)handle->bsh_base; +#else + /* IBM-PC: the type of bus_space_handle_t is u_int */ + vaddr = (void *)handle; +#endif + rman_set_virtual(r, vaddr); + } + return (0); +} + +static int +nexus_deactivate_resource(device_t bus, device_t child, int type, int rid, + struct resource *r) +{ + int error; + + error = rman_deactivate_resource(r); + if (error) + return (error); + + if (rman_get_flags(r) & RF_UNMAPPED) + return (0); + + nexus_unmap_resource(bus, child, type, r, rman_get_bustag(r), + rman_get_bushandle(r)); + return (0); +} + +static int +nexus_map_resource(device_t bus, device_t child, int type, struct resource *r, + struct resource_map_request *argsp, bus_space_tag_t *tag, + bus_space_handle_t *handle) +{ + 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 +523,64 @@ 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, handle); if (error) return (error); - rman_set_bushandle(r, bh); #else - rman_set_bushandle(r, rman_get_start(r)); + *handle = start; #endif - rman_set_bustag(r, X86_BUS_SPACE_IO); + *tag = X86_BUS_SPACE_IO; 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, 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); + vaddr = pmap_mapdev_attr(start, size, args.memattr); + *tag = X86_BUS_SPACE_MEM; #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); + (*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); + *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, + bus_space_tag_t tag, bus_space_handle_t handle) { - + void *vaddr; + rman_res_t size; + /* * 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)); +#ifdef PC98 + /* PC-98: the type of bus_space_handle_t is the structure. */ + vaddr = (void *)handle->bsh_base; + size = handle->bsh_sz; +#else + /* IBM-PC: the type of bus_space_handle_t is u_int */ + vaddr = (void *)handle; + /* XXX: size is wrong */ + size = rman_get_size(r) +#endif + pmap_unmapdev((vm_offset_t)vaddr, 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(tag, handle, handle->bsh_sz); } #endif - return (rman_deactivate_resource(r)); + return (0); } static int