xref: /openbmc/linux/drivers/xen/xen-balloon.c (revision 762f99f4f3cb41a775b5157dd761217beba65873)
1803eb047SDaniel De Graaf /******************************************************************************
2803eb047SDaniel De Graaf  * Xen balloon driver - enables returning/claiming memory to/from Xen.
3803eb047SDaniel De Graaf  *
4803eb047SDaniel De Graaf  * Copyright (c) 2003, B Dragovic
5803eb047SDaniel De Graaf  * Copyright (c) 2003-2004, M Williamson, K Fraser
6803eb047SDaniel De Graaf  * Copyright (c) 2005 Dan M. Smith, IBM Corporation
7803eb047SDaniel De Graaf  *
8803eb047SDaniel De Graaf  * This program is free software; you can redistribute it and/or
9803eb047SDaniel De Graaf  * modify it under the terms of the GNU General Public License version 2
10803eb047SDaniel De Graaf  * as published by the Free Software Foundation; or, when distributed
11803eb047SDaniel De Graaf  * separately from the Linux kernel or incorporated into other
12803eb047SDaniel De Graaf  * software packages, subject to the following license:
13803eb047SDaniel De Graaf  *
14803eb047SDaniel De Graaf  * Permission is hereby granted, free of charge, to any person obtaining a copy
15803eb047SDaniel De Graaf  * of this source file (the "Software"), to deal in the Software without
16803eb047SDaniel De Graaf  * restriction, including without limitation the rights to use, copy, modify,
17803eb047SDaniel De Graaf  * merge, publish, distribute, sublicense, and/or sell copies of the Software,
18803eb047SDaniel De Graaf  * and to permit persons to whom the Software is furnished to do so, subject to
19803eb047SDaniel De Graaf  * the following conditions:
20803eb047SDaniel De Graaf  *
21803eb047SDaniel De Graaf  * The above copyright notice and this permission notice shall be included in
22803eb047SDaniel De Graaf  * all copies or substantial portions of the Software.
23803eb047SDaniel De Graaf  *
24803eb047SDaniel De Graaf  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
25803eb047SDaniel De Graaf  * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
26803eb047SDaniel De Graaf  * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
27803eb047SDaniel De Graaf  * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
28803eb047SDaniel De Graaf  * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
29803eb047SDaniel De Graaf  * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
30803eb047SDaniel De Graaf  * IN THE SOFTWARE.
31803eb047SDaniel De Graaf  */
32803eb047SDaniel De Graaf 
33283c0972SJoe Perches #define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
34283c0972SJoe Perches 
35803eb047SDaniel De Graaf #include <linux/kernel.h>
36106eaa8eSPaul Gortmaker #include <linux/errno.h>
37106eaa8eSPaul Gortmaker #include <linux/mm_types.h>
38106eaa8eSPaul Gortmaker #include <linux/init.h>
39803eb047SDaniel De Graaf #include <linux/capability.h>
401d988ed4SJuergen Gross #include <linux/memory_hotplug.h>
41803eb047SDaniel De Graaf 
42803eb047SDaniel De Graaf #include <xen/xen.h>
43803eb047SDaniel De Graaf #include <xen/interface/xen.h>
44803eb047SDaniel De Graaf #include <xen/balloon.h>
45803eb047SDaniel De Graaf #include <xen/xenbus.h>
46803eb047SDaniel De Graaf #include <xen/features.h>
47803eb047SDaniel De Graaf #include <xen/page.h>
48197ecb38SMarek Marczykowski-Górecki #include <xen/mem-reservation.h>
49803eb047SDaniel De Graaf 
50803eb047SDaniel De Graaf #define PAGES2KB(_p) ((_p)<<(PAGE_SHIFT-10))
51803eb047SDaniel De Graaf 
52803eb047SDaniel De Graaf #define BALLOON_CLASS_NAME "xen_memory"
53803eb047SDaniel De Graaf 
541d988ed4SJuergen Gross #ifdef CONFIG_MEMORY_HOTPLUG
551d988ed4SJuergen Gross u64 xen_saved_max_mem_size = 0;
561d988ed4SJuergen Gross #endif
571d988ed4SJuergen Gross 
5807068021SKay Sievers static struct device balloon_dev;
59803eb047SDaniel De Graaf 
6007068021SKay Sievers static int register_balloon(struct device *dev);
61803eb047SDaniel De Graaf 
62803eb047SDaniel De Graaf /* React to a change in the target key */
watch_target(struct xenbus_watch * watch,const char * path,const char * token)63803eb047SDaniel De Graaf static void watch_target(struct xenbus_watch *watch,
645584ea25SJuergen Gross 			 const char *path, const char *token)
65803eb047SDaniel De Graaf {
665266b8e4SJuergen Gross 	unsigned long long new_target, static_max;
67803eb047SDaniel De Graaf 	int err;
6896edd61dSJuergen Gross 	static bool watch_fired;
6996edd61dSJuergen Gross 	static long target_diff;
70803eb047SDaniel De Graaf 
711d988ed4SJuergen Gross #ifdef CONFIG_MEMORY_HOTPLUG
721d988ed4SJuergen Gross 	/* The balloon driver will take care of adding memory now. */
731d988ed4SJuergen Gross 	if (xen_saved_max_mem_size)
741d988ed4SJuergen Gross 		max_mem_size = xen_saved_max_mem_size;
751d988ed4SJuergen Gross #endif
761d988ed4SJuergen Gross 
77803eb047SDaniel De Graaf 	err = xenbus_scanf(XBT_NIL, "memory", "target", "%llu", &new_target);
78803eb047SDaniel De Graaf 	if (err != 1) {
79803eb047SDaniel De Graaf 		/* This is ok (for domain0 at least) - so just return */
80803eb047SDaniel De Graaf 		return;
81803eb047SDaniel De Graaf 	}
82803eb047SDaniel De Graaf 
83803eb047SDaniel De Graaf 	/* The given memory/target value is in KiB, so it needs converting to
84803eb047SDaniel De Graaf 	 * pages. PAGE_SHIFT converts bytes to pages, hence PAGE_SHIFT - 10.
85803eb047SDaniel De Graaf 	 */
8696edd61dSJuergen Gross 	new_target >>= PAGE_SHIFT - 10;
875266b8e4SJuergen Gross 
885266b8e4SJuergen Gross 	if (!watch_fired) {
895266b8e4SJuergen Gross 		watch_fired = true;
903aa6c19dSBoris Ostrovsky 
913aa6c19dSBoris Ostrovsky 		if ((xenbus_scanf(XBT_NIL, "memory", "static-max",
923aa6c19dSBoris Ostrovsky 				  "%llu", &static_max) == 1) ||
933aa6c19dSBoris Ostrovsky 		    (xenbus_scanf(XBT_NIL, "memory", "memory_static_max",
943aa6c19dSBoris Ostrovsky 				  "%llu", &static_max) == 1))
955266b8e4SJuergen Gross 			static_max >>= PAGE_SHIFT - 10;
963aa6c19dSBoris Ostrovsky 		else
97eda4eabfSJuergen Gross 			static_max = balloon_stats.current_pages;
983aa6c19dSBoris Ostrovsky 
993596924aSRoger Pau Monne 		target_diff = (xen_pv_domain() || xen_initial_domain()) ? 0
1005266b8e4SJuergen Gross 				: static_max - balloon_stats.target_pages;
10196edd61dSJuergen Gross 	}
10296edd61dSJuergen Gross 
1035266b8e4SJuergen Gross 	balloon_set_new_target(new_target - target_diff);
104803eb047SDaniel De Graaf }
1056b71c52eSOlaf Hering static struct xenbus_watch target_watch = {
1066b71c52eSOlaf Hering 	.node = "memory/target",
1076b71c52eSOlaf Hering 	.callback = watch_target,
1086b71c52eSOlaf Hering };
1096b71c52eSOlaf Hering 
110803eb047SDaniel De Graaf 
balloon_init_watcher(struct notifier_block * notifier,unsigned long event,void * data)111803eb047SDaniel De Graaf static int balloon_init_watcher(struct notifier_block *notifier,
112803eb047SDaniel De Graaf 				unsigned long event,
113803eb047SDaniel De Graaf 				void *data)
114803eb047SDaniel De Graaf {
115803eb047SDaniel De Graaf 	int err;
116803eb047SDaniel De Graaf 
117803eb047SDaniel De Graaf 	err = register_xenbus_watch(&target_watch);
118803eb047SDaniel De Graaf 	if (err)
119283c0972SJoe Perches 		pr_err("Failed to set balloon watcher\n");
120803eb047SDaniel De Graaf 
121803eb047SDaniel De Graaf 	return NOTIFY_DONE;
122803eb047SDaniel De Graaf }
123803eb047SDaniel De Graaf 
1246b71c52eSOlaf Hering static struct notifier_block xenstore_notifier = {
1256b71c52eSOlaf Hering 	.notifier_call = balloon_init_watcher,
1266b71c52eSOlaf Hering };
127803eb047SDaniel De Graaf 
xen_balloon_init(void)12896edd61dSJuergen Gross void xen_balloon_init(void)
129803eb047SDaniel De Graaf {
13007068021SKay Sievers 	register_balloon(&balloon_dev);
131803eb047SDaniel De Graaf 
132803eb047SDaniel De Graaf 	register_xenstore_notifier(&xenstore_notifier);
133803eb047SDaniel De Graaf }
13496edd61dSJuergen Gross EXPORT_SYMBOL_GPL(xen_balloon_init);
135803eb047SDaniel De Graaf 
136803eb047SDaniel De Graaf #define BALLOON_SHOW(name, format, args...)				\
137*20600617SYueHaibing 	static ssize_t name##_show(struct device *dev,			\
13807068021SKay Sievers 				   struct device_attribute *attr,	\
139803eb047SDaniel De Graaf 				   char *buf)				\
140803eb047SDaniel De Graaf 	{								\
141803eb047SDaniel De Graaf 		return sprintf(buf, format, ##args);			\
142803eb047SDaniel De Graaf 	}								\
143*20600617SYueHaibing 	static DEVICE_ATTR_RO(name)
144803eb047SDaniel De Graaf 
145803eb047SDaniel De Graaf BALLOON_SHOW(current_kb, "%lu\n", PAGES2KB(balloon_stats.current_pages));
146803eb047SDaniel De Graaf BALLOON_SHOW(low_kb, "%lu\n", PAGES2KB(balloon_stats.balloon_low));
147803eb047SDaniel De Graaf BALLOON_SHOW(high_kb, "%lu\n", PAGES2KB(balloon_stats.balloon_high));
148803eb047SDaniel De Graaf 
14907068021SKay Sievers static DEVICE_ULONG_ATTR(schedule_delay, 0444, balloon_stats.schedule_delay);
15007068021SKay Sievers static DEVICE_ULONG_ATTR(max_schedule_delay, 0644, balloon_stats.max_schedule_delay);
15107068021SKay Sievers static DEVICE_ULONG_ATTR(retry_count, 0444, balloon_stats.retry_count);
15207068021SKay Sievers static DEVICE_ULONG_ATTR(max_retry_count, 0644, balloon_stats.max_retry_count);
153197ecb38SMarek Marczykowski-Górecki static DEVICE_BOOL_ATTR(scrub_pages, 0644, xen_scrub_pages);
154803eb047SDaniel De Graaf 
target_kb_show(struct device * dev,struct device_attribute * attr,char * buf)155*20600617SYueHaibing static ssize_t target_kb_show(struct device *dev, struct device_attribute *attr,
156803eb047SDaniel De Graaf 			      char *buf)
157803eb047SDaniel De Graaf {
158803eb047SDaniel De Graaf 	return sprintf(buf, "%lu\n", PAGES2KB(balloon_stats.target_pages));
159803eb047SDaniel De Graaf }
160803eb047SDaniel De Graaf 
target_kb_store(struct device * dev,struct device_attribute * attr,const char * buf,size_t count)161*20600617SYueHaibing static ssize_t target_kb_store(struct device *dev,
16207068021SKay Sievers 			       struct device_attribute *attr,
163*20600617SYueHaibing 			       const char *buf, size_t count)
164803eb047SDaniel De Graaf {
165803eb047SDaniel De Graaf 	char *endchar;
166803eb047SDaniel De Graaf 	unsigned long long target_bytes;
167803eb047SDaniel De Graaf 
168803eb047SDaniel De Graaf 	if (!capable(CAP_SYS_ADMIN))
169803eb047SDaniel De Graaf 		return -EPERM;
170803eb047SDaniel De Graaf 
171803eb047SDaniel De Graaf 	target_bytes = simple_strtoull(buf, &endchar, 0) * 1024;
172803eb047SDaniel De Graaf 
173803eb047SDaniel De Graaf 	balloon_set_new_target(target_bytes >> PAGE_SHIFT);
174803eb047SDaniel De Graaf 
175803eb047SDaniel De Graaf 	return count;
176803eb047SDaniel De Graaf }
177803eb047SDaniel De Graaf 
178*20600617SYueHaibing static DEVICE_ATTR_RW(target_kb);
179803eb047SDaniel De Graaf 
target_show(struct device * dev,struct device_attribute * attr,char * buf)180*20600617SYueHaibing static ssize_t target_show(struct device *dev, struct device_attribute *attr,
181803eb047SDaniel De Graaf 			   char *buf)
182803eb047SDaniel De Graaf {
183803eb047SDaniel De Graaf 	return sprintf(buf, "%llu\n",
184803eb047SDaniel De Graaf 		       (unsigned long long)balloon_stats.target_pages
185803eb047SDaniel De Graaf 		       << PAGE_SHIFT);
186803eb047SDaniel De Graaf }
187803eb047SDaniel De Graaf 
target_store(struct device * dev,struct device_attribute * attr,const char * buf,size_t count)188*20600617SYueHaibing static ssize_t target_store(struct device *dev,
18907068021SKay Sievers 			    struct device_attribute *attr,
190*20600617SYueHaibing 			    const char *buf, size_t count)
191803eb047SDaniel De Graaf {
192803eb047SDaniel De Graaf 	char *endchar;
193803eb047SDaniel De Graaf 	unsigned long long target_bytes;
194803eb047SDaniel De Graaf 
195803eb047SDaniel De Graaf 	if (!capable(CAP_SYS_ADMIN))
196803eb047SDaniel De Graaf 		return -EPERM;
197803eb047SDaniel De Graaf 
198803eb047SDaniel De Graaf 	target_bytes = memparse(buf, &endchar);
199803eb047SDaniel De Graaf 
200803eb047SDaniel De Graaf 	balloon_set_new_target(target_bytes >> PAGE_SHIFT);
201803eb047SDaniel De Graaf 
202803eb047SDaniel De Graaf 	return count;
203803eb047SDaniel De Graaf }
204803eb047SDaniel De Graaf 
205*20600617SYueHaibing static DEVICE_ATTR_RW(target);
206803eb047SDaniel De Graaf 
207b6a473a7STakashi Iwai static struct attribute *balloon_attrs[] = {
208b6a473a7STakashi Iwai 	&dev_attr_target_kb.attr,
209b6a473a7STakashi Iwai 	&dev_attr_target.attr,
210b6a473a7STakashi Iwai 	&dev_attr_schedule_delay.attr.attr,
211b6a473a7STakashi Iwai 	&dev_attr_max_schedule_delay.attr.attr,
212b6a473a7STakashi Iwai 	&dev_attr_retry_count.attr.attr,
213b6a473a7STakashi Iwai 	&dev_attr_max_retry_count.attr.attr,
214197ecb38SMarek Marczykowski-Górecki 	&dev_attr_scrub_pages.attr.attr,
215b6a473a7STakashi Iwai 	NULL
216b6a473a7STakashi Iwai };
217b6a473a7STakashi Iwai 
218b6a473a7STakashi Iwai static const struct attribute_group balloon_group = {
219b6a473a7STakashi Iwai 	.attrs = balloon_attrs
220803eb047SDaniel De Graaf };
221803eb047SDaniel De Graaf 
222803eb047SDaniel De Graaf static struct attribute *balloon_info_attrs[] = {
22307068021SKay Sievers 	&dev_attr_current_kb.attr,
22407068021SKay Sievers 	&dev_attr_low_kb.attr,
22507068021SKay Sievers 	&dev_attr_high_kb.attr,
226803eb047SDaniel De Graaf 	NULL
227803eb047SDaniel De Graaf };
228803eb047SDaniel De Graaf 
229ead1d014SJan Beulich static const struct attribute_group balloon_info_group = {
230803eb047SDaniel De Graaf 	.name = "info",
231803eb047SDaniel De Graaf 	.attrs = balloon_info_attrs
232803eb047SDaniel De Graaf };
233803eb047SDaniel De Graaf 
234b6a473a7STakashi Iwai static const struct attribute_group *balloon_groups[] = {
235b6a473a7STakashi Iwai 	&balloon_group,
236b6a473a7STakashi Iwai 	&balloon_info_group,
237b6a473a7STakashi Iwai 	NULL
238b6a473a7STakashi Iwai };
239b6a473a7STakashi Iwai 
24007068021SKay Sievers static struct bus_type balloon_subsys = {
24107068021SKay Sievers 	.name = BALLOON_CLASS_NAME,
24207068021SKay Sievers 	.dev_name = BALLOON_CLASS_NAME,
243803eb047SDaniel De Graaf };
244803eb047SDaniel De Graaf 
register_balloon(struct device * dev)24507068021SKay Sievers static int register_balloon(struct device *dev)
246803eb047SDaniel De Graaf {
247b6a473a7STakashi Iwai 	int error;
248803eb047SDaniel De Graaf 
2498ea11f7fSKonrad Rzeszutek Wilk 	error = subsys_system_register(&balloon_subsys, NULL);
250803eb047SDaniel De Graaf 	if (error)
251803eb047SDaniel De Graaf 		return error;
252803eb047SDaniel De Graaf 
25307068021SKay Sievers 	dev->id = 0;
25407068021SKay Sievers 	dev->bus = &balloon_subsys;
255b6a473a7STakashi Iwai 	dev->groups = balloon_groups;
256803eb047SDaniel De Graaf 
25707068021SKay Sievers 	error = device_register(dev);
258803eb047SDaniel De Graaf 	if (error) {
25907068021SKay Sievers 		bus_unregister(&balloon_subsys);
260803eb047SDaniel De Graaf 		return error;
261803eb047SDaniel De Graaf 	}
262803eb047SDaniel De Graaf 
263803eb047SDaniel De Graaf 	return 0;
264803eb047SDaniel De Graaf }
265