189e0f4d2SKip Macy /****************************************************************************** 289e0f4d2SKip Macy * balloon.c 389e0f4d2SKip Macy * 489e0f4d2SKip Macy * Xen balloon driver - enables returning/claiming memory to/from Xen. 589e0f4d2SKip Macy * 689e0f4d2SKip Macy * Copyright (c) 2003, B Dragovic 789e0f4d2SKip Macy * Copyright (c) 2003-2004, M Williamson, K Fraser 889e0f4d2SKip Macy * Copyright (c) 2005 Dan M. Smith, IBM Corporation 989e0f4d2SKip Macy * 1089e0f4d2SKip Macy * This file may be distributed separately from the Linux kernel, or 1189e0f4d2SKip Macy * incorporated into other software packages, subject to the following license: 1289e0f4d2SKip Macy * 1389e0f4d2SKip Macy * Permission is hereby granted, free of charge, to any person obtaining a copy 1489e0f4d2SKip Macy * of this source file (the "Software"), to deal in the Software without 1589e0f4d2SKip Macy * restriction, including without limitation the rights to use, copy, modify, 1689e0f4d2SKip Macy * merge, publish, distribute, sublicense, and/or sell copies of the Software, 1789e0f4d2SKip Macy * and to permit persons to whom the Software is furnished to do so, subject to 1889e0f4d2SKip Macy * the following conditions: 1989e0f4d2SKip Macy * 2089e0f4d2SKip Macy * The above copyright notice and this permission notice shall be included in 2189e0f4d2SKip Macy * all copies or substantial portions of the Software. 2289e0f4d2SKip Macy * 2389e0f4d2SKip Macy * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 2489e0f4d2SKip Macy * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 2589e0f4d2SKip Macy * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 2689e0f4d2SKip Macy * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 2789e0f4d2SKip Macy * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING 2889e0f4d2SKip Macy * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS 2989e0f4d2SKip Macy * IN THE SOFTWARE. 3089e0f4d2SKip Macy */ 3189e0f4d2SKip Macy 3289e0f4d2SKip Macy #include <sys/cdefs.h> 3389e0f4d2SKip Macy __FBSDID("$FreeBSD$"); 3489e0f4d2SKip Macy 3589e0f4d2SKip Macy #include <sys/param.h> 3689e0f4d2SKip Macy #include <sys/lock.h> 3712678024SDoug Rabson #include <sys/kernel.h> 3812678024SDoug Rabson #include <sys/kthread.h> 3912678024SDoug Rabson #include <sys/malloc.h> 4089e0f4d2SKip Macy #include <sys/mutex.h> 4112678024SDoug Rabson #include <sys/sysctl.h> 42*ae3078d9SRoger Pau Monné #include <sys/module.h> 4389e0f4d2SKip Macy 4412678024SDoug Rabson #include <vm/vm.h> 4512678024SDoug Rabson #include <vm/vm_page.h> 4612678024SDoug Rabson 4776acc41fSJustin T. Gibbs #include <xen/xen-os.h> 4876acc41fSJustin T. Gibbs #include <xen/hypervisor.h> 4976acc41fSJustin T. Gibbs #include <xen/features.h> 5076acc41fSJustin T. Gibbs #include <xen/xenstore/xenstorevar.h> 5176acc41fSJustin T. Gibbs 5276acc41fSJustin T. Gibbs #include <machine/xen/xenvar.h> 5376acc41fSJustin T. Gibbs 54d745c852SEd Schouten static MALLOC_DEFINE(M_BALLOON, "Balloon", "Xen Balloon Driver"); 5512678024SDoug Rabson 5670046ce6SJustin T. Gibbs /* Convert from KB (as fetched from xenstore) to number of PAGES */ 5770046ce6SJustin T. Gibbs #define KB_TO_PAGE_SHIFT (PAGE_SHIFT - 10) 5889e0f4d2SKip Macy 5970046ce6SJustin T. Gibbs struct mtx balloon_mutex; 6089e0f4d2SKip Macy 6112678024SDoug Rabson /* We increase/decrease in batches which fit in a page */ 6212678024SDoug Rabson static unsigned long frame_list[PAGE_SIZE / sizeof(unsigned long)]; 6312678024SDoug Rabson 6412678024SDoug Rabson struct balloon_stats { 6589e0f4d2SKip Macy /* We aim for 'current allocation' == 'target allocation'. */ 6612678024SDoug Rabson unsigned long current_pages; 6712678024SDoug Rabson unsigned long target_pages; 6889e0f4d2SKip Macy /* We may hit the hard limit in Xen. If we do then we remember it. */ 6912678024SDoug Rabson unsigned long hard_limit; 7089e0f4d2SKip Macy /* 7112678024SDoug Rabson * Drivers may alter the memory reservation independently, but they 7212678024SDoug Rabson * must inform the balloon driver so we avoid hitting the hard limit. 7389e0f4d2SKip Macy */ 7412678024SDoug Rabson unsigned long driver_pages; 7512678024SDoug Rabson /* Number of pages in high- and low-memory balloons. */ 7612678024SDoug Rabson unsigned long balloon_low; 7712678024SDoug Rabson unsigned long balloon_high; 7812678024SDoug Rabson }; 7912678024SDoug Rabson 8012678024SDoug Rabson static struct balloon_stats balloon_stats; 8112678024SDoug Rabson #define bs balloon_stats 8212678024SDoug Rabson 8312678024SDoug Rabson SYSCTL_DECL(_dev_xen); 846472ac3dSEd Schouten static SYSCTL_NODE(_dev_xen, OID_AUTO, balloon, CTLFLAG_RD, NULL, "Balloon"); 8512678024SDoug Rabson SYSCTL_ULONG(_dev_xen_balloon, OID_AUTO, current, CTLFLAG_RD, 8612678024SDoug Rabson &bs.current_pages, 0, "Current allocation"); 8712678024SDoug Rabson SYSCTL_ULONG(_dev_xen_balloon, OID_AUTO, target, CTLFLAG_RD, 8812678024SDoug Rabson &bs.target_pages, 0, "Target allocation"); 8912678024SDoug Rabson SYSCTL_ULONG(_dev_xen_balloon, OID_AUTO, driver_pages, CTLFLAG_RD, 9012678024SDoug Rabson &bs.driver_pages, 0, "Driver pages"); 9112678024SDoug Rabson SYSCTL_ULONG(_dev_xen_balloon, OID_AUTO, hard_limit, CTLFLAG_RD, 9212678024SDoug Rabson &bs.hard_limit, 0, "Xen hard limit"); 9312678024SDoug Rabson SYSCTL_ULONG(_dev_xen_balloon, OID_AUTO, low_mem, CTLFLAG_RD, 9412678024SDoug Rabson &bs.balloon_low, 0, "Low-mem balloon"); 9512678024SDoug Rabson SYSCTL_ULONG(_dev_xen_balloon, OID_AUTO, high_mem, CTLFLAG_RD, 9612678024SDoug Rabson &bs.balloon_high, 0, "High-mem balloon"); 9789e0f4d2SKip Macy 9889e0f4d2SKip Macy /* List of ballooned pages, threaded through the mem_map array. */ 9968e58ea7SRoger Pau Monné static TAILQ_HEAD(,vm_page) ballooned_pages; 10089e0f4d2SKip Macy 10189e0f4d2SKip Macy /* Main work function, always executed in process context. */ 10289e0f4d2SKip Macy static void balloon_process(void *unused); 10389e0f4d2SKip Macy 10489e0f4d2SKip Macy #define IPRINTK(fmt, args...) \ 10589e0f4d2SKip Macy printk(KERN_INFO "xen_mem: " fmt, ##args) 10689e0f4d2SKip Macy #define WPRINTK(fmt, args...) \ 10789e0f4d2SKip Macy printk(KERN_WARNING "xen_mem: " fmt, ##args) 10889e0f4d2SKip Macy 10989e0f4d2SKip Macy static unsigned long 11089e0f4d2SKip Macy current_target(void) 11189e0f4d2SKip Macy { 11212678024SDoug Rabson unsigned long target = min(bs.target_pages, bs.hard_limit); 11312678024SDoug Rabson if (target > (bs.current_pages + bs.balloon_low + bs.balloon_high)) 11412678024SDoug Rabson target = bs.current_pages + bs.balloon_low + bs.balloon_high; 11570046ce6SJustin T. Gibbs return (target); 11689e0f4d2SKip Macy } 11789e0f4d2SKip Macy 11812678024SDoug Rabson static unsigned long 11912678024SDoug Rabson minimum_target(void) 12012678024SDoug Rabson { 12112678024SDoug Rabson #ifdef XENHVM 12270046ce6SJustin T. Gibbs #define max_pfn realmem 1233e33218dSDoug Rabson #else 1243e33218dSDoug Rabson #define max_pfn HYPERVISOR_shared_info->arch.max_pfn 12512678024SDoug Rabson #endif 12612678024SDoug Rabson unsigned long min_pages, curr_pages = current_target(); 12712678024SDoug Rabson 12812678024SDoug Rabson #define MB2PAGES(mb) ((mb) << (20 - PAGE_SHIFT)) 12970046ce6SJustin T. Gibbs /* 13070046ce6SJustin T. Gibbs * Simple continuous piecewiese linear function: 13112678024SDoug Rabson * max MiB -> min MiB gradient 13212678024SDoug Rabson * 0 0 13312678024SDoug Rabson * 16 16 13412678024SDoug Rabson * 32 24 13512678024SDoug Rabson * 128 72 (1/2) 13612678024SDoug Rabson * 512 168 (1/4) 13712678024SDoug Rabson * 2048 360 (1/8) 13812678024SDoug Rabson * 8192 552 (1/32) 13912678024SDoug Rabson * 32768 1320 14012678024SDoug Rabson * 131072 4392 14112678024SDoug Rabson */ 14212678024SDoug Rabson if (max_pfn < MB2PAGES(128)) 14312678024SDoug Rabson min_pages = MB2PAGES(8) + (max_pfn >> 1); 14412678024SDoug Rabson else if (max_pfn < MB2PAGES(512)) 14512678024SDoug Rabson min_pages = MB2PAGES(40) + (max_pfn >> 2); 14612678024SDoug Rabson else if (max_pfn < MB2PAGES(2048)) 14712678024SDoug Rabson min_pages = MB2PAGES(104) + (max_pfn >> 3); 14812678024SDoug Rabson else 14912678024SDoug Rabson min_pages = MB2PAGES(296) + (max_pfn >> 5); 15012678024SDoug Rabson #undef MB2PAGES 15170046ce6SJustin T. Gibbs #undef max_pfn 15212678024SDoug Rabson 15312678024SDoug Rabson /* Don't enforce growth */ 15470046ce6SJustin T. Gibbs return (min(min_pages, curr_pages)); 15512678024SDoug Rabson } 15612678024SDoug Rabson 15789e0f4d2SKip Macy static int 15889e0f4d2SKip Macy increase_reservation(unsigned long nr_pages) 15989e0f4d2SKip Macy { 16012678024SDoug Rabson unsigned long pfn, i; 16112678024SDoug Rabson vm_page_t page; 16289e0f4d2SKip Macy long rc; 16389e0f4d2SKip Macy struct xen_memory_reservation reservation = { 16489e0f4d2SKip Macy .address_bits = 0, 16589e0f4d2SKip Macy .extent_order = 0, 16689e0f4d2SKip Macy .domid = DOMID_SELF 16789e0f4d2SKip Macy }; 16889e0f4d2SKip Macy 16970046ce6SJustin T. Gibbs mtx_assert(&balloon_mutex, MA_OWNED); 17089e0f4d2SKip Macy 17170046ce6SJustin T. Gibbs if (nr_pages > nitems(frame_list)) 17270046ce6SJustin T. Gibbs nr_pages = nitems(frame_list); 17389e0f4d2SKip Macy 17468e58ea7SRoger Pau Monné for (page = TAILQ_FIRST(&ballooned_pages), i = 0; 17568e58ea7SRoger Pau Monné i < nr_pages; i++, page = TAILQ_NEXT(page, plinks.q)) { 17668e58ea7SRoger Pau Monné KASSERT(page != NULL, ("ballooned_pages list corrupt")); 17712678024SDoug Rabson frame_list[i] = (VM_PAGE_TO_PHYS(page) >> PAGE_SHIFT); 17812678024SDoug Rabson } 17989e0f4d2SKip Macy 18012678024SDoug Rabson set_xen_guest_handle(reservation.extent_start, frame_list); 18189e0f4d2SKip Macy reservation.nr_extents = nr_pages; 18289e0f4d2SKip Macy rc = HYPERVISOR_memory_op( 18312678024SDoug Rabson XENMEM_populate_physmap, &reservation); 18489e0f4d2SKip Macy if (rc < nr_pages) { 18512678024SDoug Rabson if (rc > 0) { 18689e0f4d2SKip Macy int ret; 18712678024SDoug Rabson 18889e0f4d2SKip Macy /* We hit the Xen hard limit: reprobe. */ 18989e0f4d2SKip Macy reservation.nr_extents = rc; 19089e0f4d2SKip Macy ret = HYPERVISOR_memory_op(XENMEM_decrease_reservation, 19189e0f4d2SKip Macy &reservation); 19212678024SDoug Rabson KASSERT(ret == rc, ("HYPERVISOR_memory_op failed")); 19312678024SDoug Rabson } 19412678024SDoug Rabson if (rc >= 0) 19512678024SDoug Rabson bs.hard_limit = (bs.current_pages + rc - 19612678024SDoug Rabson bs.driver_pages); 19789e0f4d2SKip Macy goto out; 19889e0f4d2SKip Macy } 19989e0f4d2SKip Macy 20089e0f4d2SKip Macy for (i = 0; i < nr_pages; i++) { 20168e58ea7SRoger Pau Monné page = TAILQ_FIRST(&ballooned_pages); 20268e58ea7SRoger Pau Monné KASSERT(page != NULL, ("Unable to get ballooned page")); 20368e58ea7SRoger Pau Monné TAILQ_REMOVE(&ballooned_pages, page, plinks.q); 20468e58ea7SRoger Pau Monné bs.balloon_low--; 20589e0f4d2SKip Macy 20689e0f4d2SKip Macy pfn = (VM_PAGE_TO_PHYS(page) >> PAGE_SHIFT); 20712678024SDoug Rabson KASSERT((xen_feature(XENFEAT_auto_translated_physmap) || 20812678024SDoug Rabson !phys_to_machine_mapping_valid(pfn)), 20912678024SDoug Rabson ("auto translated physmap but mapping is valid")); 21089e0f4d2SKip Macy 21112678024SDoug Rabson set_phys_to_machine(pfn, frame_list[i]); 21212678024SDoug Rabson 21389e0f4d2SKip Macy vm_page_free(page); 21489e0f4d2SKip Macy } 21589e0f4d2SKip Macy 21612678024SDoug Rabson bs.current_pages += nr_pages; 21789e0f4d2SKip Macy 21889e0f4d2SKip Macy out: 21970046ce6SJustin T. Gibbs return (0); 22089e0f4d2SKip Macy } 22189e0f4d2SKip Macy 22289e0f4d2SKip Macy static int 22389e0f4d2SKip Macy decrease_reservation(unsigned long nr_pages) 22489e0f4d2SKip Macy { 22512678024SDoug Rabson unsigned long pfn, i; 22612678024SDoug Rabson vm_page_t page; 22789e0f4d2SKip Macy int need_sleep = 0; 22889e0f4d2SKip Macy int ret; 22989e0f4d2SKip Macy struct xen_memory_reservation reservation = { 23089e0f4d2SKip Macy .address_bits = 0, 23189e0f4d2SKip Macy .extent_order = 0, 23289e0f4d2SKip Macy .domid = DOMID_SELF 23389e0f4d2SKip Macy }; 23489e0f4d2SKip Macy 23570046ce6SJustin T. Gibbs mtx_assert(&balloon_mutex, MA_OWNED); 23670046ce6SJustin T. Gibbs 23770046ce6SJustin T. Gibbs if (nr_pages > nitems(frame_list)) 23870046ce6SJustin T. Gibbs nr_pages = nitems(frame_list); 23989e0f4d2SKip Macy 24089e0f4d2SKip Macy for (i = 0; i < nr_pages; i++) { 241703dec68SAlan Cox if ((page = vm_page_alloc(NULL, 0, 24289e0f4d2SKip Macy VM_ALLOC_NORMAL | VM_ALLOC_NOOBJ | 24368e58ea7SRoger Pau Monné VM_ALLOC_ZERO)) == NULL) { 24489e0f4d2SKip Macy nr_pages = i; 24589e0f4d2SKip Macy need_sleep = 1; 24689e0f4d2SKip Macy break; 24789e0f4d2SKip Macy } 24812678024SDoug Rabson 24968e58ea7SRoger Pau Monné if ((page->flags & PG_ZERO) == 0) { 25068e58ea7SRoger Pau Monné /* 25168e58ea7SRoger Pau Monné * Zero the page, or else we might be leaking 25268e58ea7SRoger Pau Monné * important data to other domains on the same 25368e58ea7SRoger Pau Monné * host. Xen doesn't scrub ballooned out memory 25468e58ea7SRoger Pau Monné * pages, the guest is in charge of making 25568e58ea7SRoger Pau Monné * sure that no information is leaked. 25668e58ea7SRoger Pau Monné */ 25768e58ea7SRoger Pau Monné pmap_zero_page(page); 25868e58ea7SRoger Pau Monné } 25968e58ea7SRoger Pau Monné 26089e0f4d2SKip Macy pfn = (VM_PAGE_TO_PHYS(page) >> PAGE_SHIFT); 26112678024SDoug Rabson frame_list[i] = PFNTOMFN(pfn); 26212678024SDoug Rabson 26312678024SDoug Rabson set_phys_to_machine(pfn, INVALID_P2M_ENTRY); 26468e58ea7SRoger Pau Monné TAILQ_INSERT_HEAD(&ballooned_pages, page, plinks.q); 26568e58ea7SRoger Pau Monné bs.balloon_low++; 26689e0f4d2SKip Macy } 26789e0f4d2SKip Macy 26812678024SDoug Rabson set_xen_guest_handle(reservation.extent_start, frame_list); 26989e0f4d2SKip Macy reservation.nr_extents = nr_pages; 27089e0f4d2SKip Macy ret = HYPERVISOR_memory_op(XENMEM_decrease_reservation, &reservation); 27112678024SDoug Rabson KASSERT(ret == nr_pages, ("HYPERVISOR_memory_op failed")); 27289e0f4d2SKip Macy 27312678024SDoug Rabson bs.current_pages -= nr_pages; 27489e0f4d2SKip Macy 27512678024SDoug Rabson return (need_sleep); 27689e0f4d2SKip Macy } 27789e0f4d2SKip Macy 27889e0f4d2SKip Macy /* 27989e0f4d2SKip Macy * We avoid multiple worker processes conflicting via the balloon mutex. 28089e0f4d2SKip Macy * We may of course race updates of the target counts (which are protected 28189e0f4d2SKip Macy * by the balloon lock), or with changes to the Xen hard limit, but we will 28289e0f4d2SKip Macy * recover from these in time. 28389e0f4d2SKip Macy */ 28489e0f4d2SKip Macy static void 28589e0f4d2SKip Macy balloon_process(void *unused) 28689e0f4d2SKip Macy { 28789e0f4d2SKip Macy int need_sleep = 0; 28889e0f4d2SKip Macy long credit; 28989e0f4d2SKip Macy 29012678024SDoug Rabson mtx_lock(&balloon_mutex); 29189e0f4d2SKip Macy for (;;) { 292c4f9a105SAlexander Motin int sleep_time; 293c4f9a105SAlexander Motin 29489e0f4d2SKip Macy do { 29512678024SDoug Rabson credit = current_target() - bs.current_pages; 29689e0f4d2SKip Macy if (credit > 0) 29789e0f4d2SKip Macy need_sleep = (increase_reservation(credit) != 0); 29889e0f4d2SKip Macy if (credit < 0) 29989e0f4d2SKip Macy need_sleep = (decrease_reservation(-credit) != 0); 30089e0f4d2SKip Macy 30189e0f4d2SKip Macy } while ((credit != 0) && !need_sleep); 30289e0f4d2SKip Macy 30389e0f4d2SKip Macy /* Schedule more work if there is some still to be done. */ 30412678024SDoug Rabson if (current_target() != bs.current_pages) 305c4f9a105SAlexander Motin sleep_time = hz; 306c4f9a105SAlexander Motin else 307c4f9a105SAlexander Motin sleep_time = 0; 30889e0f4d2SKip Macy 309c4f9a105SAlexander Motin msleep(balloon_process, &balloon_mutex, 0, "balloon", 310c4f9a105SAlexander Motin sleep_time); 31189e0f4d2SKip Macy } 31212678024SDoug Rabson mtx_unlock(&balloon_mutex); 31389e0f4d2SKip Macy } 31489e0f4d2SKip Macy 31589e0f4d2SKip Macy /* Resets the Xen limit, sets new target, and kicks off processing. */ 31689e0f4d2SKip Macy static void 31789e0f4d2SKip Macy set_new_target(unsigned long target) 31889e0f4d2SKip Macy { 31989e0f4d2SKip Macy /* No need for lock. Not read-modify-write updates. */ 32012678024SDoug Rabson bs.hard_limit = ~0UL; 32112678024SDoug Rabson bs.target_pages = max(target, minimum_target()); 32289e0f4d2SKip Macy wakeup(balloon_process); 32389e0f4d2SKip Macy } 32489e0f4d2SKip Macy 325ff662b5cSJustin T. Gibbs static struct xs_watch target_watch = 32689e0f4d2SKip Macy { 32789e0f4d2SKip Macy .node = "memory/target" 32889e0f4d2SKip Macy }; 32989e0f4d2SKip Macy 33089e0f4d2SKip Macy /* React to a change in the target key */ 33189e0f4d2SKip Macy static void 332ff662b5cSJustin T. Gibbs watch_target(struct xs_watch *watch, 33389e0f4d2SKip Macy const char **vec, unsigned int len) 33489e0f4d2SKip Macy { 33589e0f4d2SKip Macy unsigned long long new_target; 33689e0f4d2SKip Macy int err; 33789e0f4d2SKip Macy 338ff662b5cSJustin T. Gibbs err = xs_scanf(XST_NIL, "memory", "target", NULL, 33912678024SDoug Rabson "%llu", &new_target); 34012678024SDoug Rabson if (err) { 34189e0f4d2SKip Macy /* This is ok (for domain0 at least) - so just return */ 34289e0f4d2SKip Macy return; 34389e0f4d2SKip Macy } 34489e0f4d2SKip Macy 34570046ce6SJustin T. Gibbs /* 34670046ce6SJustin T. Gibbs * The given memory/target value is in KiB, so it needs converting to 34770046ce6SJustin T. Gibbs * pages. PAGE_SHIFT converts bytes to pages, hence PAGE_SHIFT - 10. 34889e0f4d2SKip Macy */ 34970046ce6SJustin T. Gibbs set_new_target(new_target >> KB_TO_PAGE_SHIFT); 35089e0f4d2SKip Macy } 35189e0f4d2SKip Macy 352*ae3078d9SRoger Pau Monné /*------------------ Private Device Attachment Functions --------------------*/ 353*ae3078d9SRoger Pau Monné /** 354*ae3078d9SRoger Pau Monné * \brief Identify instances of this device type in the system. 355*ae3078d9SRoger Pau Monné * 356*ae3078d9SRoger Pau Monné * \param driver The driver performing this identify action. 357*ae3078d9SRoger Pau Monné * \param parent The NewBus parent device for any devices this method adds. 358*ae3078d9SRoger Pau Monné */ 35989e0f4d2SKip Macy static void 360*ae3078d9SRoger Pau Monné xenballoon_identify(driver_t *driver __unused, device_t parent) 361*ae3078d9SRoger Pau Monné { 362*ae3078d9SRoger Pau Monné /* 363*ae3078d9SRoger Pau Monné * A single device instance for our driver is always present 364*ae3078d9SRoger Pau Monné * in a system operating under Xen. 365*ae3078d9SRoger Pau Monné */ 366*ae3078d9SRoger Pau Monné BUS_ADD_CHILD(parent, 0, driver->name, 0); 367*ae3078d9SRoger Pau Monné } 368*ae3078d9SRoger Pau Monné 369*ae3078d9SRoger Pau Monné /** 370*ae3078d9SRoger Pau Monné * \brief Probe for the existance of the Xen Balloon device 371*ae3078d9SRoger Pau Monné * 372*ae3078d9SRoger Pau Monné * \param dev NewBus device_t for this Xen control instance. 373*ae3078d9SRoger Pau Monné * 374*ae3078d9SRoger Pau Monné * \return Always returns 0 indicating success. 375*ae3078d9SRoger Pau Monné */ 376*ae3078d9SRoger Pau Monné static int 377*ae3078d9SRoger Pau Monné xenballoon_probe(device_t dev) 378*ae3078d9SRoger Pau Monné { 379*ae3078d9SRoger Pau Monné 380*ae3078d9SRoger Pau Monné device_set_desc(dev, "Xen Balloon Device"); 381*ae3078d9SRoger Pau Monné return (0); 382*ae3078d9SRoger Pau Monné } 383*ae3078d9SRoger Pau Monné 384*ae3078d9SRoger Pau Monné /** 385*ae3078d9SRoger Pau Monné * \brief Attach the Xen Balloon device. 386*ae3078d9SRoger Pau Monné * 387*ae3078d9SRoger Pau Monné * \param dev NewBus device_t for this Xen control instance. 388*ae3078d9SRoger Pau Monné * 389*ae3078d9SRoger Pau Monné * \return On success, 0. Otherwise an errno value indicating the 390*ae3078d9SRoger Pau Monné * type of failure. 391*ae3078d9SRoger Pau Monné */ 392*ae3078d9SRoger Pau Monné static int 393*ae3078d9SRoger Pau Monné xenballoon_attach(device_t dev) 39489e0f4d2SKip Macy { 39589e0f4d2SKip Macy int err; 39612678024SDoug Rabson #ifndef XENHVM 39712678024SDoug Rabson vm_page_t page; 3983e33218dSDoug Rabson unsigned long pfn; 3993e33218dSDoug Rabson 4003e33218dSDoug Rabson #define max_pfn HYPERVISOR_shared_info->arch.max_pfn 40112678024SDoug Rabson #endif 40289e0f4d2SKip Macy 40312678024SDoug Rabson mtx_init(&balloon_mutex, "balloon_mutex", NULL, MTX_DEF); 40489e0f4d2SKip Macy 40512678024SDoug Rabson #ifndef XENHVM 40612678024SDoug Rabson bs.current_pages = min(xen_start_info->nr_pages, max_pfn); 40712678024SDoug Rabson #else 40870046ce6SJustin T. Gibbs bs.current_pages = realmem; 40912678024SDoug Rabson #endif 41012678024SDoug Rabson bs.target_pages = bs.current_pages; 41112678024SDoug Rabson bs.balloon_low = 0; 41212678024SDoug Rabson bs.balloon_high = 0; 41312678024SDoug Rabson bs.driver_pages = 0UL; 41412678024SDoug Rabson bs.hard_limit = ~0UL; 41589e0f4d2SKip Macy 41612678024SDoug Rabson kproc_create(balloon_process, NULL, NULL, 0, 0, "balloon"); 41789e0f4d2SKip Macy 41812678024SDoug Rabson #ifndef XENHVM 41989e0f4d2SKip Macy /* Initialise the balloon with excess memory space. */ 42089e0f4d2SKip Macy for (pfn = xen_start_info->nr_pages; pfn < max_pfn; pfn++) { 42189e0f4d2SKip Macy page = PHYS_TO_VM_PAGE(pfn << PAGE_SHIFT); 42268e58ea7SRoger Pau Monné TAILQ_INSERT_HEAD(&ballooned_pages, page, plinks.q); 42368e58ea7SRoger Pau Monné bs.balloon_low++; 42489e0f4d2SKip Macy } 4253e33218dSDoug Rabson #undef max_pfn 42612678024SDoug Rabson #endif 42789e0f4d2SKip Macy 42889e0f4d2SKip Macy target_watch.callback = watch_target; 42989e0f4d2SKip Macy 430*ae3078d9SRoger Pau Monné err = xs_register_watch(&target_watch); 431*ae3078d9SRoger Pau Monné if (err) 432*ae3078d9SRoger Pau Monné device_printf(dev, 433*ae3078d9SRoger Pau Monné "xenballon: failed to set balloon watcher\n"); 43412678024SDoug Rabson 435*ae3078d9SRoger Pau Monné return (err); 43689e0f4d2SKip Macy } 437*ae3078d9SRoger Pau Monné 438*ae3078d9SRoger Pau Monné /*-------------------- Private Device Attachment Data -----------------------*/ 439*ae3078d9SRoger Pau Monné static device_method_t xenballoon_methods[] = { 440*ae3078d9SRoger Pau Monné /* Device interface */ 441*ae3078d9SRoger Pau Monné DEVMETHOD(device_identify, xenballoon_identify), 442*ae3078d9SRoger Pau Monné DEVMETHOD(device_probe, xenballoon_probe), 443*ae3078d9SRoger Pau Monné DEVMETHOD(device_attach, xenballoon_attach), 444*ae3078d9SRoger Pau Monné 445*ae3078d9SRoger Pau Monné DEVMETHOD_END 446*ae3078d9SRoger Pau Monné }; 447*ae3078d9SRoger Pau Monné 448*ae3078d9SRoger Pau Monné DEFINE_CLASS_0(xenballoon, xenballoon_driver, xenballoon_methods, 0); 449*ae3078d9SRoger Pau Monné devclass_t xenballoon_devclass; 450*ae3078d9SRoger Pau Monné 451*ae3078d9SRoger Pau Monné DRIVER_MODULE(xenballoon, xenstore, xenballoon_driver, xenballoon_devclass, 452*ae3078d9SRoger Pau Monné NULL, NULL); 453