ia64/linux-2.6.18-xen.hg

view drivers/acpi/button.c @ 897:329ea0ccb344

balloon: try harder to balloon up under memory pressure.

Currently if the balloon driver is unable to increase the guest's
reservation it assumes the failure was due to reaching its full
allocation, gives up on the ballooning operation and records the limit
it reached as the "hard limit". The driver will not try again until
the target is set again (even to the same value).

However it is possible that ballooning has in fact failed due to
memory pressure in the host and therefore it is desirable to keep
attempting to reach the target in case memory becomes available. The
most likely scenario is that some guests are ballooning down while
others are ballooning up and therefore there is temporary memory
pressure while things stabilise. You would not expect a well behaved
toolstack to ask a domain to balloon to more than its allocation nor
would you expect it to deliberately over-commit memory by setting
balloon targets which exceed the total host memory.

This patch drops the concept of a hard limit and causes the balloon
driver to retry increasing the reservation on a timer in the same
manner as when decreasing the reservation.

Also if we partially succeed in increasing the reservation
(i.e. receive less pages than we asked for) then we may as well keep
those pages rather than returning them to Xen.

Signed-off-by: Ian Campbell <ian.campbell@citrix.com>
author Keir Fraser <keir.fraser@citrix.com>
date Fri Jun 05 14:01:20 2009 +0100 (2009-06-05)
parents 831230e53067
children
line source
1 /*
2 * acpi_button.c - ACPI Button Driver ($Revision: 30 $)
3 *
4 * Copyright (C) 2001, 2002 Andy Grover <andrew.grover@intel.com>
5 * Copyright (C) 2001, 2002 Paul Diefenbaugh <paul.s.diefenbaugh@intel.com>
6 *
7 * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
8 *
9 * This program is free software; you can redistribute it and/or modify
10 * it under the terms of the GNU General Public License as published by
11 * the Free Software Foundation; either version 2 of the License, or (at
12 * your option) any later version.
13 *
14 * This program is distributed in the hope that it will be useful, but
15 * WITHOUT ANY WARRANTY; without even the implied warranty of
16 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
17 * General Public License for more details.
18 *
19 * You should have received a copy of the GNU General Public License along
20 * with this program; if not, write to the Free Software Foundation, Inc.,
21 * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA.
22 *
23 * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
24 */
26 #include <linux/kernel.h>
27 #include <linux/module.h>
28 #include <linux/init.h>
29 #include <linux/types.h>
30 #include <linux/proc_fs.h>
31 #include <linux/seq_file.h>
32 #include <acpi/acpi_bus.h>
33 #include <acpi/acpi_drivers.h>
35 #define ACPI_BUTTON_COMPONENT 0x00080000
36 #define ACPI_BUTTON_DRIVER_NAME "ACPI Button Driver"
37 #define ACPI_BUTTON_CLASS "button"
38 #define ACPI_BUTTON_FILE_INFO "info"
39 #define ACPI_BUTTON_FILE_STATE "state"
40 #define ACPI_BUTTON_TYPE_UNKNOWN 0x00
41 #define ACPI_BUTTON_NOTIFY_STATUS 0x80
43 #define ACPI_BUTTON_SUBCLASS_POWER "power"
44 #define ACPI_BUTTON_HID_POWER "PNP0C0C"
45 #define ACPI_BUTTON_DEVICE_NAME_POWER "Power Button (CM)"
46 #define ACPI_BUTTON_DEVICE_NAME_POWERF "Power Button (FF)"
47 #define ACPI_BUTTON_TYPE_POWER 0x01
48 #define ACPI_BUTTON_TYPE_POWERF 0x02
50 #define ACPI_BUTTON_SUBCLASS_SLEEP "sleep"
51 #define ACPI_BUTTON_HID_SLEEP "PNP0C0E"
52 #define ACPI_BUTTON_DEVICE_NAME_SLEEP "Sleep Button (CM)"
53 #define ACPI_BUTTON_DEVICE_NAME_SLEEPF "Sleep Button (FF)"
54 #define ACPI_BUTTON_TYPE_SLEEP 0x03
55 #define ACPI_BUTTON_TYPE_SLEEPF 0x04
57 #define ACPI_BUTTON_SUBCLASS_LID "lid"
58 #define ACPI_BUTTON_HID_LID "PNP0C0D"
59 #define ACPI_BUTTON_DEVICE_NAME_LID "Lid Switch"
60 #define ACPI_BUTTON_TYPE_LID 0x05
62 #define _COMPONENT ACPI_BUTTON_COMPONENT
63 ACPI_MODULE_NAME("acpi_button")
65 MODULE_AUTHOR("Paul Diefenbaugh");
66 MODULE_DESCRIPTION(ACPI_BUTTON_DRIVER_NAME);
67 MODULE_LICENSE("GPL");
69 static int acpi_button_add(struct acpi_device *device);
70 static int acpi_button_remove(struct acpi_device *device, int type);
71 static int acpi_button_info_open_fs(struct inode *inode, struct file *file);
72 static int acpi_button_state_open_fs(struct inode *inode, struct file *file);
74 static struct acpi_driver acpi_button_driver = {
75 .name = ACPI_BUTTON_DRIVER_NAME,
76 .class = ACPI_BUTTON_CLASS,
77 .ids = "ACPI_FPB,ACPI_FSB,PNP0C0D,PNP0C0C,PNP0C0E",
78 .ops = {
79 .add = acpi_button_add,
80 .remove = acpi_button_remove,
81 },
82 };
84 struct acpi_button {
85 struct acpi_device *device; /* Fixed button kludge */
86 u8 type;
87 unsigned long pushed;
88 };
90 static const struct file_operations acpi_button_info_fops = {
91 .open = acpi_button_info_open_fs,
92 .read = seq_read,
93 .llseek = seq_lseek,
94 .release = single_release,
95 };
97 static const struct file_operations acpi_button_state_fops = {
98 .open = acpi_button_state_open_fs,
99 .read = seq_read,
100 .llseek = seq_lseek,
101 .release = single_release,
102 };
104 /* --------------------------------------------------------------------------
105 FS Interface (/proc)
106 -------------------------------------------------------------------------- */
108 static struct proc_dir_entry *acpi_button_dir;
110 static int acpi_button_info_seq_show(struct seq_file *seq, void *offset)
111 {
112 struct acpi_button *button = (struct acpi_button *)seq->private;
115 if (!button || !button->device)
116 return 0;
118 seq_printf(seq, "type: %s\n",
119 acpi_device_name(button->device));
121 return 0;
122 }
124 static int acpi_button_info_open_fs(struct inode *inode, struct file *file)
125 {
126 return single_open(file, acpi_button_info_seq_show, PDE(inode)->data);
127 }
129 static int acpi_button_state_seq_show(struct seq_file *seq, void *offset)
130 {
131 struct acpi_button *button = (struct acpi_button *)seq->private;
132 acpi_status status;
133 unsigned long state;
136 if (!button || !button->device)
137 return 0;
139 status = acpi_evaluate_integer(button->device->handle, "_LID", NULL, &state);
140 if (ACPI_FAILURE(status)) {
141 seq_printf(seq, "state: unsupported\n");
142 } else {
143 seq_printf(seq, "state: %s\n",
144 (state ? "open" : "closed"));
145 }
147 return 0;
148 }
150 static int acpi_button_state_open_fs(struct inode *inode, struct file *file)
151 {
152 return single_open(file, acpi_button_state_seq_show, PDE(inode)->data);
153 }
155 static struct proc_dir_entry *acpi_power_dir;
156 static struct proc_dir_entry *acpi_sleep_dir;
157 static struct proc_dir_entry *acpi_lid_dir;
159 static int acpi_button_add_fs(struct acpi_device *device)
160 {
161 struct proc_dir_entry *entry = NULL;
162 struct acpi_button *button = NULL;
165 if (!device || !acpi_driver_data(device))
166 return -EINVAL;
168 button = acpi_driver_data(device);
170 switch (button->type) {
171 case ACPI_BUTTON_TYPE_POWER:
172 case ACPI_BUTTON_TYPE_POWERF:
173 if (!acpi_power_dir)
174 acpi_power_dir = proc_mkdir(ACPI_BUTTON_SUBCLASS_POWER,
175 acpi_button_dir);
176 entry = acpi_power_dir;
177 break;
178 case ACPI_BUTTON_TYPE_SLEEP:
179 case ACPI_BUTTON_TYPE_SLEEPF:
180 if (!acpi_sleep_dir)
181 acpi_sleep_dir = proc_mkdir(ACPI_BUTTON_SUBCLASS_SLEEP,
182 acpi_button_dir);
183 entry = acpi_sleep_dir;
184 break;
185 case ACPI_BUTTON_TYPE_LID:
186 if (!acpi_lid_dir)
187 acpi_lid_dir = proc_mkdir(ACPI_BUTTON_SUBCLASS_LID,
188 acpi_button_dir);
189 entry = acpi_lid_dir;
190 break;
191 }
193 if (!entry)
194 return -ENODEV;
195 entry->owner = THIS_MODULE;
197 acpi_device_dir(device) = proc_mkdir(acpi_device_bid(device), entry);
198 if (!acpi_device_dir(device))
199 return -ENODEV;
200 acpi_device_dir(device)->owner = THIS_MODULE;
202 /* 'info' [R] */
203 entry = create_proc_entry(ACPI_BUTTON_FILE_INFO,
204 S_IRUGO, acpi_device_dir(device));
205 if (!entry)
206 return -ENODEV;
207 else {
208 entry->proc_fops = &acpi_button_info_fops;
209 entry->data = acpi_driver_data(device);
210 entry->owner = THIS_MODULE;
211 }
213 /* show lid state [R] */
214 if (button->type == ACPI_BUTTON_TYPE_LID) {
215 entry = create_proc_entry(ACPI_BUTTON_FILE_STATE,
216 S_IRUGO, acpi_device_dir(device));
217 if (!entry)
218 return -ENODEV;
219 else {
220 entry->proc_fops = &acpi_button_state_fops;
221 entry->data = acpi_driver_data(device);
222 entry->owner = THIS_MODULE;
223 }
224 }
226 return 0;
227 }
229 static int acpi_button_remove_fs(struct acpi_device *device)
230 {
231 struct acpi_button *button = NULL;
234 button = acpi_driver_data(device);
235 if (acpi_device_dir(device)) {
236 if (button->type == ACPI_BUTTON_TYPE_LID)
237 remove_proc_entry(ACPI_BUTTON_FILE_STATE,
238 acpi_device_dir(device));
239 remove_proc_entry(ACPI_BUTTON_FILE_INFO,
240 acpi_device_dir(device));
242 remove_proc_entry(acpi_device_bid(device),
243 acpi_device_dir(device)->parent);
244 acpi_device_dir(device) = NULL;
245 }
247 return 0;
248 }
250 /* --------------------------------------------------------------------------
251 Driver Interface
252 -------------------------------------------------------------------------- */
254 static void acpi_button_notify(acpi_handle handle, u32 event, void *data)
255 {
256 struct acpi_button *button = (struct acpi_button *)data;
259 if (!button || !button->device)
260 return;
262 switch (event) {
263 case ACPI_BUTTON_NOTIFY_STATUS:
264 acpi_bus_generate_event(button->device, event,
265 ++button->pushed);
266 break;
267 default:
268 ACPI_DEBUG_PRINT((ACPI_DB_INFO,
269 "Unsupported event [0x%x]\n", event));
270 break;
271 }
273 return;
274 }
276 static acpi_status acpi_button_notify_fixed(void *data)
277 {
278 struct acpi_button *button = (struct acpi_button *)data;
281 if (!button)
282 return AE_BAD_PARAMETER;
284 acpi_button_notify(button->device->handle, ACPI_BUTTON_NOTIFY_STATUS, button);
286 return AE_OK;
287 }
289 static int acpi_button_add(struct acpi_device *device)
290 {
291 int result = 0;
292 acpi_status status = AE_OK;
293 struct acpi_button *button = NULL;
296 if (!device)
297 return -EINVAL;
299 button = kmalloc(sizeof(struct acpi_button), GFP_KERNEL);
300 if (!button)
301 return -ENOMEM;
302 memset(button, 0, sizeof(struct acpi_button));
304 button->device = device;
305 acpi_driver_data(device) = button;
307 /*
308 * Determine the button type (via hid), as fixed-feature buttons
309 * need to be handled a bit differently than generic-space.
310 */
311 if (!strcmp(acpi_device_hid(device), ACPI_BUTTON_HID_POWER)) {
312 button->type = ACPI_BUTTON_TYPE_POWER;
313 strcpy(acpi_device_name(device), ACPI_BUTTON_DEVICE_NAME_POWER);
314 sprintf(acpi_device_class(device), "%s/%s",
315 ACPI_BUTTON_CLASS, ACPI_BUTTON_SUBCLASS_POWER);
316 } else if (!strcmp(acpi_device_hid(device), ACPI_BUTTON_HID_POWERF)) {
317 button->type = ACPI_BUTTON_TYPE_POWERF;
318 strcpy(acpi_device_name(device),
319 ACPI_BUTTON_DEVICE_NAME_POWERF);
320 sprintf(acpi_device_class(device), "%s/%s",
321 ACPI_BUTTON_CLASS, ACPI_BUTTON_SUBCLASS_POWER);
322 } else if (!strcmp(acpi_device_hid(device), ACPI_BUTTON_HID_SLEEP)) {
323 button->type = ACPI_BUTTON_TYPE_SLEEP;
324 strcpy(acpi_device_name(device), ACPI_BUTTON_DEVICE_NAME_SLEEP);
325 sprintf(acpi_device_class(device), "%s/%s",
326 ACPI_BUTTON_CLASS, ACPI_BUTTON_SUBCLASS_SLEEP);
327 } else if (!strcmp(acpi_device_hid(device), ACPI_BUTTON_HID_SLEEPF)) {
328 button->type = ACPI_BUTTON_TYPE_SLEEPF;
329 strcpy(acpi_device_name(device),
330 ACPI_BUTTON_DEVICE_NAME_SLEEPF);
331 sprintf(acpi_device_class(device), "%s/%s",
332 ACPI_BUTTON_CLASS, ACPI_BUTTON_SUBCLASS_SLEEP);
333 } else if (!strcmp(acpi_device_hid(device), ACPI_BUTTON_HID_LID)) {
334 button->type = ACPI_BUTTON_TYPE_LID;
335 strcpy(acpi_device_name(device), ACPI_BUTTON_DEVICE_NAME_LID);
336 sprintf(acpi_device_class(device), "%s/%s",
337 ACPI_BUTTON_CLASS, ACPI_BUTTON_SUBCLASS_LID);
338 } else {
339 printk(KERN_ERR PREFIX "Unsupported hid [%s]\n",
340 acpi_device_hid(device));
341 result = -ENODEV;
342 goto end;
343 }
345 result = acpi_button_add_fs(device);
346 if (result)
347 goto end;
349 switch (button->type) {
350 case ACPI_BUTTON_TYPE_POWERF:
351 status =
352 acpi_install_fixed_event_handler(ACPI_EVENT_POWER_BUTTON,
353 acpi_button_notify_fixed,
354 button);
355 break;
356 case ACPI_BUTTON_TYPE_SLEEPF:
357 status =
358 acpi_install_fixed_event_handler(ACPI_EVENT_SLEEP_BUTTON,
359 acpi_button_notify_fixed,
360 button);
361 break;
362 default:
363 status = acpi_install_notify_handler(device->handle,
364 ACPI_DEVICE_NOTIFY,
365 acpi_button_notify,
366 button);
367 break;
368 }
370 if (ACPI_FAILURE(status)) {
371 result = -ENODEV;
372 goto end;
373 }
375 if (device->wakeup.flags.valid) {
376 /* Button's GPE is run-wake GPE */
377 acpi_set_gpe_type(device->wakeup.gpe_device,
378 device->wakeup.gpe_number,
379 ACPI_GPE_TYPE_WAKE_RUN);
380 acpi_enable_gpe(device->wakeup.gpe_device,
381 device->wakeup.gpe_number, ACPI_NOT_ISR);
382 device->wakeup.state.enabled = 1;
383 }
385 printk(KERN_INFO PREFIX "%s [%s]\n",
386 acpi_device_name(device), acpi_device_bid(device));
388 end:
389 if (result) {
390 acpi_button_remove_fs(device);
391 kfree(button);
392 }
394 return result;
395 }
397 static int acpi_button_remove(struct acpi_device *device, int type)
398 {
399 acpi_status status = 0;
400 struct acpi_button *button = NULL;
403 if (!device || !acpi_driver_data(device))
404 return -EINVAL;
406 button = acpi_driver_data(device);
408 /* Unregister for device notifications. */
409 switch (button->type) {
410 case ACPI_BUTTON_TYPE_POWERF:
411 status =
412 acpi_remove_fixed_event_handler(ACPI_EVENT_POWER_BUTTON,
413 acpi_button_notify_fixed);
414 break;
415 case ACPI_BUTTON_TYPE_SLEEPF:
416 status =
417 acpi_remove_fixed_event_handler(ACPI_EVENT_SLEEP_BUTTON,
418 acpi_button_notify_fixed);
419 break;
420 default:
421 status = acpi_remove_notify_handler(device->handle,
422 ACPI_DEVICE_NOTIFY,
423 acpi_button_notify);
424 break;
425 }
427 acpi_button_remove_fs(device);
429 kfree(button);
431 return 0;
432 }
434 static int __init acpi_button_init(void)
435 {
436 int result = 0;
439 acpi_button_dir = proc_mkdir(ACPI_BUTTON_CLASS, acpi_root_dir);
440 if (!acpi_button_dir)
441 return -ENODEV;
442 acpi_button_dir->owner = THIS_MODULE;
443 result = acpi_bus_register_driver(&acpi_button_driver);
444 if (result < 0) {
445 remove_proc_entry(ACPI_BUTTON_CLASS, acpi_root_dir);
446 return -ENODEV;
447 }
449 return 0;
450 }
452 static void __exit acpi_button_exit(void)
453 {
455 acpi_bus_unregister_driver(&acpi_button_driver);
457 if (acpi_power_dir)
458 remove_proc_entry(ACPI_BUTTON_SUBCLASS_POWER, acpi_button_dir);
459 if (acpi_sleep_dir)
460 remove_proc_entry(ACPI_BUTTON_SUBCLASS_SLEEP, acpi_button_dir);
461 if (acpi_lid_dir)
462 remove_proc_entry(ACPI_BUTTON_SUBCLASS_LID, acpi_button_dir);
463 remove_proc_entry(ACPI_BUTTON_CLASS, acpi_root_dir);
465 return;
466 }
468 module_init(acpi_button_init);
469 module_exit(acpi_button_exit);