Author | Tokens | Token Proportion | Commits | Commit Proportion |
---|---|---|---|---|
Roger Pau Monné | 509 | 55.39% | 1 | 14.29% |
Oleksandr Tyshchenko | 260 | 28.29% | 1 | 14.29% |
Dan J Williams | 112 | 12.19% | 3 | 42.86% |
Juergen Gross | 31 | 3.37% | 1 | 14.29% |
Zhen Lei | 7 | 0.76% | 1 | 14.29% |
Total | 919 | 7 |
// SPDX-License-Identifier: GPL-2.0 #include <linux/errno.h> #include <linux/gfp.h> #include <linux/kernel.h> #include <linux/mm.h> #include <linux/memremap.h> #include <linux/slab.h> #include <asm/page.h> #include <xen/balloon.h> #include <xen/page.h> #include <xen/xen.h> 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, *tmp_res = NULL; void *vaddr; unsigned int i, alloc_pages = round_up(nr_pages, PAGES_PER_SECTION); struct range mhp_range; int ret; res = kzalloc(sizeof(*res), GFP_KERNEL); if (!res) return -ENOMEM; res->name = "Xen scratch"; res->flags = IORESOURCE_MEM | IORESOURCE_BUSY; 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; goto err_pgmap; } pgmap->type = MEMORY_DEVICE_GENERIC; pgmap->range = (struct range) { .start = res->start, .end = res->end, }; pgmap->nr_range = 1; pgmap->owner = res; #ifdef CONFIG_XEN_HAVE_PVMMU /* * memremap will build page tables for the new memory so * the p2m must contain invalid entries so the correct * non-present PTEs will be written. * * If a failure occurs, the original (identity) p2m entries * are not restored since this region is now known not to * conflict with any devices. */ if (!xen_feature(XENFEAT_auto_translated_physmap)) { xen_pfn_t pfn = PFN_DOWN(res->start); for (i = 0; i < alloc_pages; i++) { if (!set_phys_to_machine(pfn + i, INVALID_P2M_ENTRY)) { pr_warn("set_phys_to_machine() failed, no memory added\n"); ret = -ENOMEM; goto err_memremap; } } } #endif vaddr = memremap_pages(pgmap, NUMA_NO_NODE); if (IS_ERR(vaddr)) { pr_err("Cannot remap memory range\n"); ret = PTR_ERR(vaddr); goto err_memremap; } for (i = 0; i < alloc_pages; i++) { struct page *pg = virt_to_page(vaddr + PAGE_SIZE * i); pg->zone_device_data = page_list; page_list = pg; list_count++; } return 0; 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); return ret; } /** * xen_alloc_unpopulated_pages - alloc unpopulated pages * @nr_pages: Number of pages * @pages: pages returned * @return 0 on success, error otherwise */ 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); if (ret) goto out; } for (i = 0; i < nr_pages; i++) { struct page *pg = page_list; BUG_ON(!pg); page_list = pg->zone_device_data; list_count--; pages[i] = pg; #ifdef CONFIG_XEN_HAVE_PVMMU if (!xen_feature(XENFEAT_auto_translated_physmap)) { ret = xen_alloc_p2m_entry(page_to_pfn(pg)); if (ret < 0) { unsigned int j; for (j = 0; j <= i; j++) { pages[j]->zone_device_data = page_list; page_list = pages[j]; list_count++; } goto out; } } #endif } out: mutex_unlock(&list_lock); return ret; } EXPORT_SYMBOL(xen_alloc_unpopulated_pages); /** * xen_free_unpopulated_pages - return unpopulated pages * @nr_pages: Number of pages * @pages: pages to return */ 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; page_list = pages[i]; list_count++; } mutex_unlock(&list_lock); } EXPORT_SYMBOL(xen_free_unpopulated_pages); 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);
Information contained on this website is for historical information purposes only and does not indicate or represent copyright ownership.
Created with Cregit http://github.com/cregit/cregit
Version 2.0-RC1