diff options
Diffstat (limited to 'drivers/xen/unpopulated-alloc.c')
| -rw-r--r-- | drivers/xen/unpopulated-alloc.c | 87 | 
1 files changed, 82 insertions, 5 deletions
| diff --git a/drivers/xen/unpopulated-alloc.c b/drivers/xen/unpopulated-alloc.c index 87e6b7db892f..a8b41057c382 100644 --- a/drivers/xen/unpopulated-alloc.c +++ b/drivers/xen/unpopulated-alloc.c @@ -8,6 +8,7 @@  #include <asm/page.h> +#include <xen/balloon.h>  #include <xen/page.h>  #include <xen/xen.h> @@ -15,13 +16,29 @@ static DEFINE_MUTEX(list_lock);  static struct page *page_list;  static unsigned int list_count; +static struct resource *target_resource; + +/* + * If arch is not happy with system "iomem_resource" being used for + * the region allocation it can provide it's own view by creating specific + * Xen resource with unused regions of guest physical address space provided + * by the hypervisor. + */ +int __weak __init arch_xen_unpopulated_init(struct resource **res) +{ +	*res = &iomem_resource; + +	return 0; +} +  static int fill_list(unsigned int nr_pages)  {  	struct dev_pagemap *pgmap; -	struct resource *res; +	struct resource *res, *tmp_res = NULL;  	void *vaddr;  	unsigned int i, alloc_pages = round_up(nr_pages, PAGES_PER_SECTION); -	int ret = -ENOMEM; +	struct range mhp_range; +	int ret;  	res = kzalloc(sizeof(*res), GFP_KERNEL);  	if (!res) @@ -30,14 +47,40 @@ static int fill_list(unsigned int nr_pages)  	res->name = "Xen scratch";  	res->flags = IORESOURCE_MEM | IORESOURCE_BUSY; -	ret = allocate_resource(&iomem_resource, res, -				alloc_pages * PAGE_SIZE, 0, -1, +	mhp_range = mhp_get_pluggable_range(true); + +	ret = allocate_resource(target_resource, res, +				alloc_pages * PAGE_SIZE, mhp_range.start, mhp_range.end,  				PAGES_PER_SECTION * PAGE_SIZE, NULL, NULL);  	if (ret < 0) {  		pr_err("Cannot allocate new IOMEM resource\n");  		goto err_resource;  	} +	/* +	 * Reserve the region previously allocated from Xen resource to avoid +	 * re-using it by someone else. +	 */ +	if (target_resource != &iomem_resource) { +		tmp_res = kzalloc(sizeof(*tmp_res), GFP_KERNEL); +		if (!tmp_res) { +			ret = -ENOMEM; +			goto err_insert; +		} + +		tmp_res->name = res->name; +		tmp_res->start = res->start; +		tmp_res->end = res->end; +		tmp_res->flags = res->flags; + +		ret = request_resource(&iomem_resource, tmp_res); +		if (ret < 0) { +			pr_err("Cannot request resource %pR (%d)\n", tmp_res, ret); +			kfree(tmp_res); +			goto err_insert; +		} +	} +  	pgmap = kzalloc(sizeof(*pgmap), GFP_KERNEL);  	if (!pgmap) {  		ret = -ENOMEM; @@ -85,7 +128,6 @@ static int fill_list(unsigned int nr_pages)  	for (i = 0; i < alloc_pages; i++) {  		struct page *pg = virt_to_page(vaddr + PAGE_SIZE * i); -		BUG_ON(!virt_addr_valid(vaddr + PAGE_SIZE * i));  		pg->zone_device_data = page_list;  		page_list = pg;  		list_count++; @@ -96,6 +138,11 @@ static int fill_list(unsigned int nr_pages)  err_memremap:  	kfree(pgmap);  err_pgmap: +	if (tmp_res) { +		release_resource(tmp_res); +		kfree(tmp_res); +	} +err_insert:  	release_resource(res);  err_resource:  	kfree(res); @@ -113,6 +160,14 @@ int xen_alloc_unpopulated_pages(unsigned int nr_pages, struct page **pages)  	unsigned int i;  	int ret = 0; +	/* +	 * Fallback to default behavior if we do not have any suitable resource +	 * to allocate required region from and as the result we won't be able to +	 * construct pages. +	 */ +	if (!target_resource) +		return xen_alloc_ballooned_pages(nr_pages, pages); +  	mutex_lock(&list_lock);  	if (list_count < nr_pages) {  		ret = fill_list(nr_pages - list_count); @@ -160,6 +215,11 @@ void xen_free_unpopulated_pages(unsigned int nr_pages, struct page **pages)  {  	unsigned int i; +	if (!target_resource) { +		xen_free_ballooned_pages(nr_pages, pages); +		return; +	} +  	mutex_lock(&list_lock);  	for (i = 0; i < nr_pages; i++) {  		pages[i]->zone_device_data = page_list; @@ -202,3 +262,20 @@ static int __init init(void)  }  subsys_initcall(init);  #endif + +static int __init unpopulated_init(void) +{ +	int ret; + +	if (!xen_domain()) +		return -ENODEV; + +	ret = arch_xen_unpopulated_init(&target_resource); +	if (ret) { +		pr_err("xen:unpopulated: Cannot initialize target resource\n"); +		target_resource = NULL; +	} + +	return ret; +} +early_initcall(unpopulated_init); |