diff --git a/sys/dev/xen/bus/xenpv.c b/sys/dev/xen/bus/xenpv.c --- a/sys/dev/xen/bus/xenpv.c +++ b/sys/dev/xen/bus/xenpv.c @@ -65,6 +65,16 @@ #define LOW_MEM_LIMIT 0 #endif +/* + * Memory ranges available for creating external mappings (foreign or grant + * pages for example). + */ +static struct rman unpopulated_mem = { + .rm_end = ~0, + .rm_type = RMAN_ARRAY, + .rm_descr = "Xen scratch memory", +}; + static void xenpv_identify(driver_t *driver, device_t parent) { @@ -91,10 +101,25 @@ return (BUS_PROBE_NOWILDCARD); } +/* Dummy init for arches that don't have a specific implementation. */ +int __weak_symbol +xen_arch_init_physmem(device_t dev, struct rman *mem) +{ + + return (0); +} + static int xenpv_attach(device_t dev) { - int error; + int error = rman_init(&unpopulated_mem); + + if (error != 0) + return (error); + + error = xen_arch_init_physmem(dev, &unpopulated_mem); + if (error != 0) + return (error); /* * Let our child drivers identify any child devices that they @@ -110,6 +135,14 @@ return (error); } +static int +release_unpopulated_mem(device_t dev, struct resource *res) +{ + + return (rman_is_region_manager(res, &unpopulated_mem) ? + rman_release_resource(res) : bus_release_resource(dev, res)); +} + static struct resource * xenpv_alloc_physmem(device_t dev, device_t child, int *res_id, size_t size) { @@ -117,17 +150,48 @@ vm_paddr_t phys_addr; void *virt_addr; int error; + const unsigned int flags = RF_ACTIVE | RF_UNMAPPED | + RF_ALIGNMENT_LOG2(PAGE_SHIFT); + + KASSERT((size & PAGE_MASK) == 0, ("unaligned size requested")); + size = round_page(size); + + /* Attempt to allocate from arch resource manager. */ + res = rman_reserve_resource(&unpopulated_mem, 0, ~0, size, flags, + child); + if (res != NULL) { + rman_set_rid(res, *res_id); + rman_set_type(res, SYS_RES_MEMORY); + } else { + static bool warned = false; - res = bus_alloc_resource(child, SYS_RES_MEMORY, res_id, LOW_MEM_LIMIT, - ~0, size, RF_ACTIVE | RF_UNMAPPED); - if (res == NULL) + /* Fallback to generic MMIO allocator. */ + if (__predict_false(!warned)) { + warned = true; + device_printf(dev, + "unable to allocate from arch specific routine, " + "fall back to unused memory areas\n"); + } + res = bus_alloc_resource(child, SYS_RES_MEMORY, res_id, + LOW_MEM_LIMIT, ~0, size, flags); + } + + if (res == NULL) { + device_printf(dev, + "failed to allocate Xen unpopulated memory\n"); return (NULL); + } phys_addr = rman_get_start(res); error = vm_phys_fictitious_reg_range(phys_addr, phys_addr + size, VM_MEMATTR_XEN); if (error) { - bus_release_resource(child, SYS_RES_MEMORY, *res_id, res); + int error = release_unpopulated_mem(child, res); + + if (error != 0) + device_printf(dev, "failed to release resource: %d\n", + error); + return (NULL); } virt_addr = pmap_mapdev_attr(phys_addr, size, VM_MEMATTR_XEN); @@ -150,7 +214,8 @@ pmap_unmapdev(virt_addr, size); vm_phys_fictitious_unreg_range(phys_addr, phys_addr + size); - return (bus_release_resource(child, SYS_RES_MEMORY, res_id, res)); + + return (release_unpopulated_mem(child, res)); } static device_method_t xenpv_methods[] = { diff --git a/sys/xen/xen-os.h b/sys/xen/xen-os.h --- a/sys/xen/xen-os.h +++ b/sys/xen/xen-os.h @@ -39,6 +39,8 @@ #include #ifndef __ASSEMBLY__ +#include + #include #include @@ -158,6 +160,9 @@ */ void xen_emergency_print(const char *str, size_t size); +/* Arch-specific helper to init scratch mapping space. */ +int xen_arch_init_physmem(device_t dev, struct rman *mem); + #ifndef xen_mb #define xen_mb() mb() #endif