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> 42ae3078d9SRoger 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 52d745c852SEd Schouten static MALLOC_DEFINE(M_BALLOON, "Balloon", "Xen Balloon Driver"); 5312678024SDoug Rabson 5470046ce6SJustin T. Gibbs /* Convert from KB (as fetched from xenstore) to number of PAGES */ 5570046ce6SJustin T. Gibbs #define KB_TO_PAGE_SHIFT (PAGE_SHIFT - 10) 5689e0f4d2SKip Macy 5770046ce6SJustin T. Gibbs struct mtx balloon_mutex; 5889e0f4d2SKip Macy 5912678024SDoug Rabson /* We increase/decrease in batches which fit in a page */ 602f9ec994SRoger Pau Monné static xen_pfn_t frame_list[PAGE_SIZE / sizeof(xen_pfn_t)]; 6112678024SDoug Rabson 6212678024SDoug Rabson struct balloon_stats { 6389e0f4d2SKip Macy /* We aim for 'current allocation' == 'target allocation'. */ 6412678024SDoug Rabson unsigned long current_pages; 6512678024SDoug Rabson unsigned long target_pages; 6689e0f4d2SKip Macy /* We may hit the hard limit in Xen. If we do then we remember it. */ 6712678024SDoug Rabson unsigned long hard_limit; 6889e0f4d2SKip Macy /* 6912678024SDoug Rabson * Drivers may alter the memory reservation independently, but they 7012678024SDoug Rabson * must inform the balloon driver so we avoid hitting the hard limit. 7189e0f4d2SKip Macy */ 7212678024SDoug Rabson unsigned long driver_pages; 7312678024SDoug Rabson /* Number of pages in high- and low-memory balloons. */ 7412678024SDoug Rabson unsigned long balloon_low; 7512678024SDoug Rabson unsigned long balloon_high; 7612678024SDoug Rabson }; 7712678024SDoug Rabson 7812678024SDoug Rabson static struct balloon_stats balloon_stats; 7912678024SDoug Rabson #define bs balloon_stats 8012678024SDoug Rabson 8112678024SDoug Rabson SYSCTL_DECL(_dev_xen); 826472ac3dSEd Schouten static SYSCTL_NODE(_dev_xen, OID_AUTO, balloon, CTLFLAG_RD, NULL, "Balloon"); 8312678024SDoug Rabson SYSCTL_ULONG(_dev_xen_balloon, OID_AUTO, current, CTLFLAG_RD, 8412678024SDoug Rabson &bs.current_pages, 0, "Current allocation"); 8512678024SDoug Rabson SYSCTL_ULONG(_dev_xen_balloon, OID_AUTO, target, CTLFLAG_RD, 8612678024SDoug Rabson &bs.target_pages, 0, "Target allocation"); 8712678024SDoug Rabson SYSCTL_ULONG(_dev_xen_balloon, OID_AUTO, driver_pages, CTLFLAG_RD, 8812678024SDoug Rabson &bs.driver_pages, 0, "Driver pages"); 8912678024SDoug Rabson SYSCTL_ULONG(_dev_xen_balloon, OID_AUTO, hard_limit, CTLFLAG_RD, 9012678024SDoug Rabson &bs.hard_limit, 0, "Xen hard limit"); 9112678024SDoug Rabson SYSCTL_ULONG(_dev_xen_balloon, OID_AUTO, low_mem, CTLFLAG_RD, 9212678024SDoug Rabson &bs.balloon_low, 0, "Low-mem balloon"); 9312678024SDoug Rabson SYSCTL_ULONG(_dev_xen_balloon, OID_AUTO, high_mem, CTLFLAG_RD, 9412678024SDoug Rabson &bs.balloon_high, 0, "High-mem balloon"); 9589e0f4d2SKip Macy 9689e0f4d2SKip Macy /* List of ballooned pages, threaded through the mem_map array. */ 9768e58ea7SRoger Pau Monné static TAILQ_HEAD(,vm_page) ballooned_pages; 9889e0f4d2SKip Macy 9989e0f4d2SKip Macy /* Main work function, always executed in process context. */ 10089e0f4d2SKip Macy static void balloon_process(void *unused); 10189e0f4d2SKip Macy 10289e0f4d2SKip Macy #define IPRINTK(fmt, args...) \ 10389e0f4d2SKip Macy printk(KERN_INFO "xen_mem: " fmt, ##args) 10489e0f4d2SKip Macy #define WPRINTK(fmt, args...) \ 10589e0f4d2SKip Macy printk(KERN_WARNING "xen_mem: " fmt, ##args) 10689e0f4d2SKip Macy 10789e0f4d2SKip Macy static unsigned long 10889e0f4d2SKip Macy current_target(void) 10989e0f4d2SKip Macy { 11012678024SDoug Rabson unsigned long target = min(bs.target_pages, bs.hard_limit); 11112678024SDoug Rabson if (target > (bs.current_pages + bs.balloon_low + bs.balloon_high)) 11212678024SDoug Rabson target = bs.current_pages + bs.balloon_low + bs.balloon_high; 11370046ce6SJustin T. Gibbs return (target); 11489e0f4d2SKip Macy } 11589e0f4d2SKip Macy 11612678024SDoug Rabson static unsigned long 11712678024SDoug Rabson minimum_target(void) 11812678024SDoug Rabson { 11912678024SDoug Rabson unsigned long min_pages, curr_pages = current_target(); 12012678024SDoug Rabson 12112678024SDoug Rabson #define MB2PAGES(mb) ((mb) << (20 - PAGE_SHIFT)) 12270046ce6SJustin T. Gibbs /* 12370046ce6SJustin T. Gibbs * Simple continuous piecewiese linear function: 12412678024SDoug Rabson * max MiB -> min MiB gradient 12512678024SDoug Rabson * 0 0 12612678024SDoug Rabson * 16 16 12712678024SDoug Rabson * 32 24 12812678024SDoug Rabson * 128 72 (1/2) 12912678024SDoug Rabson * 512 168 (1/4) 13012678024SDoug Rabson * 2048 360 (1/8) 13112678024SDoug Rabson * 8192 552 (1/32) 13212678024SDoug Rabson * 32768 1320 13312678024SDoug Rabson * 131072 4392 13412678024SDoug Rabson */ 135ed95805eSJohn Baldwin if (realmem < MB2PAGES(128)) 136ed95805eSJohn Baldwin min_pages = MB2PAGES(8) + (realmem >> 1); 137ed95805eSJohn Baldwin else if (realmem < MB2PAGES(512)) 138ed95805eSJohn Baldwin min_pages = MB2PAGES(40) + (realmem >> 2); 139ed95805eSJohn Baldwin else if (realmem < MB2PAGES(2048)) 140ed95805eSJohn Baldwin min_pages = MB2PAGES(104) + (realmem >> 3); 14112678024SDoug Rabson else 142ed95805eSJohn Baldwin min_pages = MB2PAGES(296) + (realmem >> 5); 14312678024SDoug Rabson #undef MB2PAGES 14412678024SDoug Rabson 14512678024SDoug Rabson /* Don't enforce growth */ 14670046ce6SJustin T. Gibbs return (min(min_pages, curr_pages)); 14712678024SDoug Rabson } 14812678024SDoug Rabson 14989e0f4d2SKip Macy static int 15089e0f4d2SKip Macy increase_reservation(unsigned long nr_pages) 15189e0f4d2SKip Macy { 1522f9ec994SRoger Pau Monné unsigned long i; 15312678024SDoug Rabson vm_page_t page; 15489e0f4d2SKip Macy long rc; 15589e0f4d2SKip Macy struct xen_memory_reservation reservation = { 15689e0f4d2SKip Macy .address_bits = 0, 15789e0f4d2SKip Macy .extent_order = 0, 15889e0f4d2SKip Macy .domid = DOMID_SELF 15989e0f4d2SKip Macy }; 16089e0f4d2SKip Macy 16170046ce6SJustin T. Gibbs mtx_assert(&balloon_mutex, MA_OWNED); 16289e0f4d2SKip Macy 16370046ce6SJustin T. Gibbs if (nr_pages > nitems(frame_list)) 16470046ce6SJustin T. Gibbs nr_pages = nitems(frame_list); 16589e0f4d2SKip Macy 16668e58ea7SRoger Pau Monné for (page = TAILQ_FIRST(&ballooned_pages), i = 0; 16768e58ea7SRoger Pau Monné i < nr_pages; i++, page = TAILQ_NEXT(page, plinks.q)) { 16868e58ea7SRoger Pau Monné KASSERT(page != NULL, ("ballooned_pages list corrupt")); 16912678024SDoug Rabson frame_list[i] = (VM_PAGE_TO_PHYS(page) >> PAGE_SHIFT); 17012678024SDoug Rabson } 17189e0f4d2SKip Macy 17212678024SDoug Rabson set_xen_guest_handle(reservation.extent_start, frame_list); 17389e0f4d2SKip Macy reservation.nr_extents = nr_pages; 17489e0f4d2SKip Macy rc = HYPERVISOR_memory_op( 17512678024SDoug Rabson XENMEM_populate_physmap, &reservation); 17689e0f4d2SKip Macy if (rc < nr_pages) { 17712678024SDoug Rabson if (rc > 0) { 17889e0f4d2SKip Macy int ret; 17912678024SDoug Rabson 18089e0f4d2SKip Macy /* We hit the Xen hard limit: reprobe. */ 18189e0f4d2SKip Macy reservation.nr_extents = rc; 18289e0f4d2SKip Macy ret = HYPERVISOR_memory_op(XENMEM_decrease_reservation, 18389e0f4d2SKip Macy &reservation); 18412678024SDoug Rabson KASSERT(ret == rc, ("HYPERVISOR_memory_op failed")); 18512678024SDoug Rabson } 18612678024SDoug Rabson if (rc >= 0) 18712678024SDoug Rabson bs.hard_limit = (bs.current_pages + rc - 18812678024SDoug Rabson bs.driver_pages); 18989e0f4d2SKip Macy goto out; 19089e0f4d2SKip Macy } 19189e0f4d2SKip Macy 19289e0f4d2SKip Macy for (i = 0; i < nr_pages; i++) { 19368e58ea7SRoger Pau Monné page = TAILQ_FIRST(&ballooned_pages); 19468e58ea7SRoger Pau Monné KASSERT(page != NULL, ("Unable to get ballooned page")); 19568e58ea7SRoger Pau Monné TAILQ_REMOVE(&ballooned_pages, page, plinks.q); 19668e58ea7SRoger Pau Monné bs.balloon_low--; 19789e0f4d2SKip Macy 198ed95805eSJohn Baldwin KASSERT(xen_feature(XENFEAT_auto_translated_physmap), 19912678024SDoug Rabson ("auto translated physmap but mapping is valid")); 20089e0f4d2SKip Macy 20189e0f4d2SKip Macy vm_page_free(page); 20289e0f4d2SKip Macy } 20389e0f4d2SKip Macy 20412678024SDoug Rabson bs.current_pages += nr_pages; 20589e0f4d2SKip Macy 20689e0f4d2SKip Macy out: 20770046ce6SJustin T. Gibbs return (0); 20889e0f4d2SKip Macy } 20989e0f4d2SKip Macy 21089e0f4d2SKip Macy static int 21189e0f4d2SKip Macy decrease_reservation(unsigned long nr_pages) 21289e0f4d2SKip Macy { 2132f9ec994SRoger Pau Monné unsigned long i; 21412678024SDoug Rabson vm_page_t page; 21589e0f4d2SKip Macy int need_sleep = 0; 21689e0f4d2SKip Macy int ret; 21789e0f4d2SKip Macy struct xen_memory_reservation reservation = { 21889e0f4d2SKip Macy .address_bits = 0, 21989e0f4d2SKip Macy .extent_order = 0, 22089e0f4d2SKip Macy .domid = DOMID_SELF 22189e0f4d2SKip Macy }; 22289e0f4d2SKip Macy 22370046ce6SJustin T. Gibbs mtx_assert(&balloon_mutex, MA_OWNED); 22470046ce6SJustin T. Gibbs 22570046ce6SJustin T. Gibbs if (nr_pages > nitems(frame_list)) 22670046ce6SJustin T. Gibbs nr_pages = nitems(frame_list); 22789e0f4d2SKip Macy 22889e0f4d2SKip Macy for (i = 0; i < nr_pages; i++) { 229703dec68SAlan Cox if ((page = vm_page_alloc(NULL, 0, 23089e0f4d2SKip Macy VM_ALLOC_NORMAL | VM_ALLOC_NOOBJ | 23168e58ea7SRoger Pau Monné VM_ALLOC_ZERO)) == NULL) { 23289e0f4d2SKip Macy nr_pages = i; 23389e0f4d2SKip Macy need_sleep = 1; 23489e0f4d2SKip Macy break; 23589e0f4d2SKip Macy } 23612678024SDoug Rabson 23768e58ea7SRoger Pau Monné if ((page->flags & PG_ZERO) == 0) { 23868e58ea7SRoger Pau Monné /* 23968e58ea7SRoger Pau Monné * Zero the page, or else we might be leaking 24068e58ea7SRoger Pau Monné * important data to other domains on the same 24168e58ea7SRoger Pau Monné * host. Xen doesn't scrub ballooned out memory 24268e58ea7SRoger Pau Monné * pages, the guest is in charge of making 24368e58ea7SRoger Pau Monné * sure that no information is leaked. 24468e58ea7SRoger Pau Monné */ 24568e58ea7SRoger Pau Monné pmap_zero_page(page); 24668e58ea7SRoger Pau Monné } 24768e58ea7SRoger Pau Monné 2482f9ec994SRoger Pau Monné frame_list[i] = (VM_PAGE_TO_PHYS(page) >> PAGE_SHIFT); 24912678024SDoug Rabson 25068e58ea7SRoger Pau Monné TAILQ_INSERT_HEAD(&ballooned_pages, page, plinks.q); 25168e58ea7SRoger Pau Monné bs.balloon_low++; 25289e0f4d2SKip Macy } 25389e0f4d2SKip Macy 25412678024SDoug Rabson set_xen_guest_handle(reservation.extent_start, frame_list); 25589e0f4d2SKip Macy reservation.nr_extents = nr_pages; 25689e0f4d2SKip Macy ret = HYPERVISOR_memory_op(XENMEM_decrease_reservation, &reservation); 25712678024SDoug Rabson KASSERT(ret == nr_pages, ("HYPERVISOR_memory_op failed")); 25889e0f4d2SKip Macy 25912678024SDoug Rabson bs.current_pages -= nr_pages; 26089e0f4d2SKip Macy 26112678024SDoug Rabson return (need_sleep); 26289e0f4d2SKip Macy } 26389e0f4d2SKip Macy 26489e0f4d2SKip Macy /* 26589e0f4d2SKip Macy * We avoid multiple worker processes conflicting via the balloon mutex. 26689e0f4d2SKip Macy * We may of course race updates of the target counts (which are protected 26789e0f4d2SKip Macy * by the balloon lock), or with changes to the Xen hard limit, but we will 26889e0f4d2SKip Macy * recover from these in time. 26989e0f4d2SKip Macy */ 27089e0f4d2SKip Macy static void 27189e0f4d2SKip Macy balloon_process(void *unused) 27289e0f4d2SKip Macy { 27389e0f4d2SKip Macy int need_sleep = 0; 27489e0f4d2SKip Macy long credit; 27589e0f4d2SKip Macy 27612678024SDoug Rabson mtx_lock(&balloon_mutex); 27789e0f4d2SKip Macy for (;;) { 278c4f9a105SAlexander Motin int sleep_time; 279c4f9a105SAlexander Motin 28089e0f4d2SKip Macy do { 28112678024SDoug Rabson credit = current_target() - bs.current_pages; 28289e0f4d2SKip Macy if (credit > 0) 28389e0f4d2SKip Macy need_sleep = (increase_reservation(credit) != 0); 28489e0f4d2SKip Macy if (credit < 0) 28589e0f4d2SKip Macy need_sleep = (decrease_reservation(-credit) != 0); 28689e0f4d2SKip Macy 28789e0f4d2SKip Macy } while ((credit != 0) && !need_sleep); 28889e0f4d2SKip Macy 28989e0f4d2SKip Macy /* Schedule more work if there is some still to be done. */ 29012678024SDoug Rabson if (current_target() != bs.current_pages) 291c4f9a105SAlexander Motin sleep_time = hz; 292c4f9a105SAlexander Motin else 293c4f9a105SAlexander Motin sleep_time = 0; 29489e0f4d2SKip Macy 295c4f9a105SAlexander Motin msleep(balloon_process, &balloon_mutex, 0, "balloon", 296c4f9a105SAlexander Motin sleep_time); 29789e0f4d2SKip Macy } 29812678024SDoug Rabson mtx_unlock(&balloon_mutex); 29989e0f4d2SKip Macy } 30089e0f4d2SKip Macy 30189e0f4d2SKip Macy /* Resets the Xen limit, sets new target, and kicks off processing. */ 30289e0f4d2SKip Macy static void 30389e0f4d2SKip Macy set_new_target(unsigned long target) 30489e0f4d2SKip Macy { 30589e0f4d2SKip Macy /* No need for lock. Not read-modify-write updates. */ 30612678024SDoug Rabson bs.hard_limit = ~0UL; 30712678024SDoug Rabson bs.target_pages = max(target, minimum_target()); 30889e0f4d2SKip Macy wakeup(balloon_process); 30989e0f4d2SKip Macy } 31089e0f4d2SKip Macy 311ff662b5cSJustin T. Gibbs static struct xs_watch target_watch = 31289e0f4d2SKip Macy { 31389e0f4d2SKip Macy .node = "memory/target" 31489e0f4d2SKip Macy }; 31589e0f4d2SKip Macy 31689e0f4d2SKip Macy /* React to a change in the target key */ 31789e0f4d2SKip Macy static void 318ff662b5cSJustin T. Gibbs watch_target(struct xs_watch *watch, 31989e0f4d2SKip Macy const char **vec, unsigned int len) 32089e0f4d2SKip Macy { 32189e0f4d2SKip Macy unsigned long long new_target; 32289e0f4d2SKip Macy int err; 32389e0f4d2SKip Macy 324ff662b5cSJustin T. Gibbs err = xs_scanf(XST_NIL, "memory", "target", NULL, 32512678024SDoug Rabson "%llu", &new_target); 32612678024SDoug Rabson if (err) { 32789e0f4d2SKip Macy /* This is ok (for domain0 at least) - so just return */ 32889e0f4d2SKip Macy return; 32989e0f4d2SKip Macy } 33089e0f4d2SKip Macy 33170046ce6SJustin T. Gibbs /* 33270046ce6SJustin T. Gibbs * The given memory/target value is in KiB, so it needs converting to 33370046ce6SJustin T. Gibbs * pages. PAGE_SHIFT converts bytes to pages, hence PAGE_SHIFT - 10. 33489e0f4d2SKip Macy */ 33570046ce6SJustin T. Gibbs set_new_target(new_target >> KB_TO_PAGE_SHIFT); 33689e0f4d2SKip Macy } 33789e0f4d2SKip Macy 338ae3078d9SRoger Pau Monné /*------------------ Private Device Attachment Functions --------------------*/ 339ae3078d9SRoger Pau Monné /** 340ae3078d9SRoger Pau Monné * \brief Identify instances of this device type in the system. 341ae3078d9SRoger Pau Monné * 342ae3078d9SRoger Pau Monné * \param driver The driver performing this identify action. 343ae3078d9SRoger Pau Monné * \param parent The NewBus parent device for any devices this method adds. 344ae3078d9SRoger Pau Monné */ 34589e0f4d2SKip Macy static void 346ae3078d9SRoger Pau Monné xenballoon_identify(driver_t *driver __unused, device_t parent) 347ae3078d9SRoger Pau Monné { 348ae3078d9SRoger Pau Monné /* 349ae3078d9SRoger Pau Monné * A single device instance for our driver is always present 350ae3078d9SRoger Pau Monné * in a system operating under Xen. 351ae3078d9SRoger Pau Monné */ 352ae3078d9SRoger Pau Monné BUS_ADD_CHILD(parent, 0, driver->name, 0); 353ae3078d9SRoger Pau Monné } 354ae3078d9SRoger Pau Monné 355ae3078d9SRoger Pau Monné /** 356*453130d9SPedro F. Giffuni * \brief Probe for the existence of the Xen Balloon device 357ae3078d9SRoger Pau Monné * 358ae3078d9SRoger Pau Monné * \param dev NewBus device_t for this Xen control instance. 359ae3078d9SRoger Pau Monné * 360ae3078d9SRoger Pau Monné * \return Always returns 0 indicating success. 361ae3078d9SRoger Pau Monné */ 362ae3078d9SRoger Pau Monné static int 363ae3078d9SRoger Pau Monné xenballoon_probe(device_t dev) 364ae3078d9SRoger Pau Monné { 365ae3078d9SRoger Pau Monné 366ae3078d9SRoger Pau Monné device_set_desc(dev, "Xen Balloon Device"); 367ae3078d9SRoger Pau Monné return (0); 368ae3078d9SRoger Pau Monné } 369ae3078d9SRoger Pau Monné 370ae3078d9SRoger Pau Monné /** 371ae3078d9SRoger Pau Monné * \brief Attach the Xen Balloon device. 372ae3078d9SRoger Pau Monné * 373ae3078d9SRoger Pau Monné * \param dev NewBus device_t for this Xen control instance. 374ae3078d9SRoger Pau Monné * 375ae3078d9SRoger Pau Monné * \return On success, 0. Otherwise an errno value indicating the 376ae3078d9SRoger Pau Monné * type of failure. 377ae3078d9SRoger Pau Monné */ 378ae3078d9SRoger Pau Monné static int 379ae3078d9SRoger Pau Monné xenballoon_attach(device_t dev) 38089e0f4d2SKip Macy { 38189e0f4d2SKip Macy int err; 38289e0f4d2SKip Macy 38312678024SDoug Rabson mtx_init(&balloon_mutex, "balloon_mutex", NULL, MTX_DEF); 38489e0f4d2SKip Macy 38522c16332SRoger Pau Monné bs.current_pages = xen_pv_domain() ? 38622c16332SRoger Pau Monné HYPERVISOR_start_info->nr_pages : realmem; 38712678024SDoug Rabson bs.target_pages = bs.current_pages; 38812678024SDoug Rabson bs.balloon_low = 0; 38912678024SDoug Rabson bs.balloon_high = 0; 39012678024SDoug Rabson bs.driver_pages = 0UL; 39112678024SDoug Rabson bs.hard_limit = ~0UL; 39289e0f4d2SKip Macy 39312678024SDoug Rabson kproc_create(balloon_process, NULL, NULL, 0, 0, "balloon"); 39489e0f4d2SKip Macy 39589e0f4d2SKip Macy target_watch.callback = watch_target; 39689e0f4d2SKip Macy 397ae3078d9SRoger Pau Monné err = xs_register_watch(&target_watch); 398ae3078d9SRoger Pau Monné if (err) 399ae3078d9SRoger Pau Monné device_printf(dev, 400ae3078d9SRoger Pau Monné "xenballon: failed to set balloon watcher\n"); 40112678024SDoug Rabson 402ae3078d9SRoger Pau Monné return (err); 40389e0f4d2SKip Macy } 404ae3078d9SRoger Pau Monné 405ae3078d9SRoger Pau Monné /*-------------------- Private Device Attachment Data -----------------------*/ 406ae3078d9SRoger Pau Monné static device_method_t xenballoon_methods[] = { 407ae3078d9SRoger Pau Monné /* Device interface */ 408ae3078d9SRoger Pau Monné DEVMETHOD(device_identify, xenballoon_identify), 409ae3078d9SRoger Pau Monné DEVMETHOD(device_probe, xenballoon_probe), 410ae3078d9SRoger Pau Monné DEVMETHOD(device_attach, xenballoon_attach), 411ae3078d9SRoger Pau Monné 412ae3078d9SRoger Pau Monné DEVMETHOD_END 413ae3078d9SRoger Pau Monné }; 414ae3078d9SRoger Pau Monné 415ae3078d9SRoger Pau Monné DEFINE_CLASS_0(xenballoon, xenballoon_driver, xenballoon_methods, 0); 416ae3078d9SRoger Pau Monné devclass_t xenballoon_devclass; 417ae3078d9SRoger Pau Monné 418ae3078d9SRoger Pau Monné DRIVER_MODULE(xenballoon, xenstore, xenballoon_driver, xenballoon_devclass, 419ae3078d9SRoger Pau Monné NULL, NULL); 420