xref: /freebsd/sys/dev/xen/balloon/balloon.c (revision ae3078d9e4fcd093550ac45c54cc45b816d38e55)
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