ia64/linux-2.6.18-xen.hg

view drivers/acpi/toshiba_acpi.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 * toshiba_acpi.c - Toshiba Laptop ACPI Extras
3 *
4 *
5 * Copyright (C) 2002-2004 John Belmonte
6 *
7 * This program is free software; you can redistribute it and/or modify
8 * it under the terms of the GNU General Public License as published by
9 * the Free Software Foundation; either version 2 of the License, or
10 * (at your option) any later version.
11 *
12 * This program is distributed in the hope that it will be useful,
13 * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 * GNU General Public License for more details.
16 *
17 * You should have received a copy of the GNU General Public License
18 * along with this program; if not, write to the Free Software
19 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
20 *
21 *
22 * The devolpment page for this driver is located at
23 * http://memebeam.org/toys/ToshibaAcpiDriver.
24 *
25 * Credits:
26 * Jonathan A. Buzzard - Toshiba HCI info, and critical tips on reverse
27 * engineering the Windows drivers
28 * Yasushi Nagato - changes for linux kernel 2.4 -> 2.5
29 * Rob Miller - TV out and hotkeys help
30 *
31 *
32 * TODO
33 *
34 */
36 #define TOSHIBA_ACPI_VERSION "0.18"
37 #define PROC_INTERFACE_VERSION 1
39 #include <linux/kernel.h>
40 #include <linux/module.h>
41 #include <linux/init.h>
42 #include <linux/types.h>
43 #include <linux/proc_fs.h>
44 #include <asm/uaccess.h>
46 #include <acpi/acpi_drivers.h>
48 MODULE_AUTHOR("John Belmonte");
49 MODULE_DESCRIPTION("Toshiba Laptop ACPI Extras Driver");
50 MODULE_LICENSE("GPL");
52 #define MY_LOGPREFIX "toshiba_acpi: "
53 #define MY_ERR KERN_ERR MY_LOGPREFIX
54 #define MY_NOTICE KERN_NOTICE MY_LOGPREFIX
55 #define MY_INFO KERN_INFO MY_LOGPREFIX
57 /* Toshiba ACPI method paths */
58 #define METHOD_LCD_BRIGHTNESS "\\_SB_.PCI0.VGA_.LCD_._BCM"
59 #define METHOD_HCI_1 "\\_SB_.VALD.GHCI"
60 #define METHOD_HCI_2 "\\_SB_.VALZ.GHCI"
61 #define METHOD_VIDEO_OUT "\\_SB_.VALX.DSSX"
63 /* Toshiba HCI interface definitions
64 *
65 * HCI is Toshiba's "Hardware Control Interface" which is supposed to
66 * be uniform across all their models. Ideally we would just call
67 * dedicated ACPI methods instead of using this primitive interface.
68 * However the ACPI methods seem to be incomplete in some areas (for
69 * example they allow setting, but not reading, the LCD brightness value),
70 * so this is still useful.
71 */
73 #define HCI_WORDS 6
75 /* operations */
76 #define HCI_SET 0xff00
77 #define HCI_GET 0xfe00
79 /* return codes */
80 #define HCI_SUCCESS 0x0000
81 #define HCI_FAILURE 0x1000
82 #define HCI_NOT_SUPPORTED 0x8000
83 #define HCI_EMPTY 0x8c00
85 /* registers */
86 #define HCI_FAN 0x0004
87 #define HCI_SYSTEM_EVENT 0x0016
88 #define HCI_VIDEO_OUT 0x001c
89 #define HCI_HOTKEY_EVENT 0x001e
90 #define HCI_LCD_BRIGHTNESS 0x002a
92 /* field definitions */
93 #define HCI_LCD_BRIGHTNESS_BITS 3
94 #define HCI_LCD_BRIGHTNESS_SHIFT (16-HCI_LCD_BRIGHTNESS_BITS)
95 #define HCI_LCD_BRIGHTNESS_LEVELS (1 << HCI_LCD_BRIGHTNESS_BITS)
96 #define HCI_VIDEO_OUT_LCD 0x1
97 #define HCI_VIDEO_OUT_CRT 0x2
98 #define HCI_VIDEO_OUT_TV 0x4
100 /* utility
101 */
103 static __inline__ void _set_bit(u32 * word, u32 mask, int value)
104 {
105 *word = (*word & ~mask) | (mask * value);
106 }
108 /* acpi interface wrappers
109 */
111 static int is_valid_acpi_path(const char *methodName)
112 {
113 acpi_handle handle;
114 acpi_status status;
116 status = acpi_get_handle(NULL, (char *)methodName, &handle);
117 return !ACPI_FAILURE(status);
118 }
120 static int write_acpi_int(const char *methodName, int val)
121 {
122 struct acpi_object_list params;
123 union acpi_object in_objs[1];
124 acpi_status status;
126 params.count = sizeof(in_objs) / sizeof(in_objs[0]);
127 params.pointer = in_objs;
128 in_objs[0].type = ACPI_TYPE_INTEGER;
129 in_objs[0].integer.value = val;
131 status = acpi_evaluate_object(NULL, (char *)methodName, &params, NULL);
132 return (status == AE_OK);
133 }
135 #if 0
136 static int read_acpi_int(const char *methodName, int *pVal)
137 {
138 struct acpi_buffer results;
139 union acpi_object out_objs[1];
140 acpi_status status;
142 results.length = sizeof(out_objs);
143 results.pointer = out_objs;
145 status = acpi_evaluate_object(0, (char *)methodName, 0, &results);
146 *pVal = out_objs[0].integer.value;
148 return (status == AE_OK) && (out_objs[0].type == ACPI_TYPE_INTEGER);
149 }
150 #endif
152 static const char *method_hci /*= 0*/ ;
154 /* Perform a raw HCI call. Here we don't care about input or output buffer
155 * format.
156 */
157 static acpi_status hci_raw(const u32 in[HCI_WORDS], u32 out[HCI_WORDS])
158 {
159 struct acpi_object_list params;
160 union acpi_object in_objs[HCI_WORDS];
161 struct acpi_buffer results;
162 union acpi_object out_objs[HCI_WORDS + 1];
163 acpi_status status;
164 int i;
166 params.count = HCI_WORDS;
167 params.pointer = in_objs;
168 for (i = 0; i < HCI_WORDS; ++i) {
169 in_objs[i].type = ACPI_TYPE_INTEGER;
170 in_objs[i].integer.value = in[i];
171 }
173 results.length = sizeof(out_objs);
174 results.pointer = out_objs;
176 status = acpi_evaluate_object(NULL, (char *)method_hci, &params,
177 &results);
178 if ((status == AE_OK) && (out_objs->package.count <= HCI_WORDS)) {
179 for (i = 0; i < out_objs->package.count; ++i) {
180 out[i] = out_objs->package.elements[i].integer.value;
181 }
182 }
184 return status;
185 }
187 /* common hci tasks (get or set one value)
188 *
189 * In addition to the ACPI status, the HCI system returns a result which
190 * may be useful (such as "not supported").
191 */
193 static acpi_status hci_write1(u32 reg, u32 in1, u32 * result)
194 {
195 u32 in[HCI_WORDS] = { HCI_SET, reg, in1, 0, 0, 0 };
196 u32 out[HCI_WORDS];
197 acpi_status status = hci_raw(in, out);
198 *result = (status == AE_OK) ? out[0] : HCI_FAILURE;
199 return status;
200 }
202 static acpi_status hci_read1(u32 reg, u32 * out1, u32 * result)
203 {
204 u32 in[HCI_WORDS] = { HCI_GET, reg, 0, 0, 0, 0 };
205 u32 out[HCI_WORDS];
206 acpi_status status = hci_raw(in, out);
207 *out1 = out[2];
208 *result = (status == AE_OK) ? out[0] : HCI_FAILURE;
209 return status;
210 }
212 static struct proc_dir_entry *toshiba_proc_dir /*= 0*/ ;
213 static int force_fan;
214 static int last_key_event;
215 static int key_event_valid;
217 typedef struct _ProcItem {
218 const char *name;
219 char *(*read_func) (char *);
220 unsigned long (*write_func) (const char *, unsigned long);
221 } ProcItem;
223 /* proc file handlers
224 */
226 static int
227 dispatch_read(char *page, char **start, off_t off, int count, int *eof,
228 ProcItem * item)
229 {
230 char *p = page;
231 int len;
233 if (off == 0)
234 p = item->read_func(p);
236 /* ISSUE: I don't understand this code */
237 len = (p - page);
238 if (len <= off + count)
239 *eof = 1;
240 *start = page + off;
241 len -= off;
242 if (len > count)
243 len = count;
244 if (len < 0)
245 len = 0;
246 return len;
247 }
249 static int
250 dispatch_write(struct file *file, const char __user * buffer,
251 unsigned long count, ProcItem * item)
252 {
253 int result;
254 char *tmp_buffer;
256 /* Arg buffer points to userspace memory, which can't be accessed
257 * directly. Since we're making a copy, zero-terminate the
258 * destination so that sscanf can be used on it safely.
259 */
260 tmp_buffer = kmalloc(count + 1, GFP_KERNEL);
261 if (!tmp_buffer)
262 return -ENOMEM;
264 if (copy_from_user(tmp_buffer, buffer, count)) {
265 result = -EFAULT;
266 } else {
267 tmp_buffer[count] = 0;
268 result = item->write_func(tmp_buffer, count);
269 }
270 kfree(tmp_buffer);
271 return result;
272 }
274 static char *read_lcd(char *p)
275 {
276 u32 hci_result;
277 u32 value;
279 hci_read1(HCI_LCD_BRIGHTNESS, &value, &hci_result);
280 if (hci_result == HCI_SUCCESS) {
281 value = value >> HCI_LCD_BRIGHTNESS_SHIFT;
282 p += sprintf(p, "brightness: %d\n", value);
283 p += sprintf(p, "brightness_levels: %d\n",
284 HCI_LCD_BRIGHTNESS_LEVELS);
285 } else {
286 printk(MY_ERR "Error reading LCD brightness\n");
287 }
289 return p;
290 }
292 static unsigned long write_lcd(const char *buffer, unsigned long count)
293 {
294 int value;
295 u32 hci_result;
297 if (sscanf(buffer, " brightness : %i", &value) == 1 &&
298 value >= 0 && value < HCI_LCD_BRIGHTNESS_LEVELS) {
299 value = value << HCI_LCD_BRIGHTNESS_SHIFT;
300 hci_write1(HCI_LCD_BRIGHTNESS, value, &hci_result);
301 if (hci_result != HCI_SUCCESS)
302 return -EFAULT;
303 } else {
304 return -EINVAL;
305 }
307 return count;
308 }
310 static char *read_video(char *p)
311 {
312 u32 hci_result;
313 u32 value;
315 hci_read1(HCI_VIDEO_OUT, &value, &hci_result);
316 if (hci_result == HCI_SUCCESS) {
317 int is_lcd = (value & HCI_VIDEO_OUT_LCD) ? 1 : 0;
318 int is_crt = (value & HCI_VIDEO_OUT_CRT) ? 1 : 0;
319 int is_tv = (value & HCI_VIDEO_OUT_TV) ? 1 : 0;
320 p += sprintf(p, "lcd_out: %d\n", is_lcd);
321 p += sprintf(p, "crt_out: %d\n", is_crt);
322 p += sprintf(p, "tv_out: %d\n", is_tv);
323 } else {
324 printk(MY_ERR "Error reading video out status\n");
325 }
327 return p;
328 }
330 static unsigned long write_video(const char *buffer, unsigned long count)
331 {
332 int value;
333 int remain = count;
334 int lcd_out = -1;
335 int crt_out = -1;
336 int tv_out = -1;
337 u32 hci_result;
338 int video_out;
340 /* scan expression. Multiple expressions may be delimited with ;
341 *
342 * NOTE: to keep scanning simple, invalid fields are ignored
343 */
344 while (remain) {
345 if (sscanf(buffer, " lcd_out : %i", &value) == 1)
346 lcd_out = value & 1;
347 else if (sscanf(buffer, " crt_out : %i", &value) == 1)
348 crt_out = value & 1;
349 else if (sscanf(buffer, " tv_out : %i", &value) == 1)
350 tv_out = value & 1;
351 /* advance to one character past the next ; */
352 do {
353 ++buffer;
354 --remain;
355 }
356 while (remain && *(buffer - 1) != ';');
357 }
359 hci_read1(HCI_VIDEO_OUT, &video_out, &hci_result);
360 if (hci_result == HCI_SUCCESS) {
361 int new_video_out = video_out;
362 if (lcd_out != -1)
363 _set_bit(&new_video_out, HCI_VIDEO_OUT_LCD, lcd_out);
364 if (crt_out != -1)
365 _set_bit(&new_video_out, HCI_VIDEO_OUT_CRT, crt_out);
366 if (tv_out != -1)
367 _set_bit(&new_video_out, HCI_VIDEO_OUT_TV, tv_out);
368 /* To avoid unnecessary video disruption, only write the new
369 * video setting if something changed. */
370 if (new_video_out != video_out)
371 write_acpi_int(METHOD_VIDEO_OUT, new_video_out);
372 } else {
373 return -EFAULT;
374 }
376 return count;
377 }
379 static char *read_fan(char *p)
380 {
381 u32 hci_result;
382 u32 value;
384 hci_read1(HCI_FAN, &value, &hci_result);
385 if (hci_result == HCI_SUCCESS) {
386 p += sprintf(p, "running: %d\n", (value > 0));
387 p += sprintf(p, "force_on: %d\n", force_fan);
388 } else {
389 printk(MY_ERR "Error reading fan status\n");
390 }
392 return p;
393 }
395 static unsigned long write_fan(const char *buffer, unsigned long count)
396 {
397 int value;
398 u32 hci_result;
400 if (sscanf(buffer, " force_on : %i", &value) == 1 &&
401 value >= 0 && value <= 1) {
402 hci_write1(HCI_FAN, value, &hci_result);
403 if (hci_result != HCI_SUCCESS)
404 return -EFAULT;
405 else
406 force_fan = value;
407 } else {
408 return -EINVAL;
409 }
411 return count;
412 }
414 static char *read_keys(char *p)
415 {
416 u32 hci_result;
417 u32 value;
419 if (!key_event_valid) {
420 hci_read1(HCI_SYSTEM_EVENT, &value, &hci_result);
421 if (hci_result == HCI_SUCCESS) {
422 key_event_valid = 1;
423 last_key_event = value;
424 } else if (hci_result == HCI_EMPTY) {
425 /* better luck next time */
426 } else if (hci_result == HCI_NOT_SUPPORTED) {
427 /* This is a workaround for an unresolved issue on
428 * some machines where system events sporadically
429 * become disabled. */
430 hci_write1(HCI_SYSTEM_EVENT, 1, &hci_result);
431 printk(MY_NOTICE "Re-enabled hotkeys\n");
432 } else {
433 printk(MY_ERR "Error reading hotkey status\n");
434 goto end;
435 }
436 }
438 p += sprintf(p, "hotkey_ready: %d\n", key_event_valid);
439 p += sprintf(p, "hotkey: 0x%04x\n", last_key_event);
441 end:
442 return p;
443 }
445 static unsigned long write_keys(const char *buffer, unsigned long count)
446 {
447 int value;
449 if (sscanf(buffer, " hotkey_ready : %i", &value) == 1 && value == 0) {
450 key_event_valid = 0;
451 } else {
452 return -EINVAL;
453 }
455 return count;
456 }
458 static char *read_version(char *p)
459 {
460 p += sprintf(p, "driver: %s\n", TOSHIBA_ACPI_VERSION);
461 p += sprintf(p, "proc_interface: %d\n",
462 PROC_INTERFACE_VERSION);
463 return p;
464 }
466 /* proc and module init
467 */
469 #define PROC_TOSHIBA "toshiba"
471 static ProcItem proc_items[] = {
472 {"lcd", read_lcd, write_lcd},
473 {"video", read_video, write_video},
474 {"fan", read_fan, write_fan},
475 {"keys", read_keys, write_keys},
476 {"version", read_version, NULL},
477 {NULL}
478 };
480 static acpi_status __init add_device(void)
481 {
482 struct proc_dir_entry *proc;
483 ProcItem *item;
485 for (item = proc_items; item->name; ++item) {
486 proc = create_proc_read_entry(item->name,
487 S_IFREG | S_IRUGO | S_IWUSR,
488 toshiba_proc_dir,
489 (read_proc_t *) dispatch_read,
490 item);
491 if (proc)
492 proc->owner = THIS_MODULE;
493 if (proc && item->write_func)
494 proc->write_proc = (write_proc_t *) dispatch_write;
495 }
497 return AE_OK;
498 }
500 static acpi_status __exit remove_device(void)
501 {
502 ProcItem *item;
504 for (item = proc_items; item->name; ++item)
505 remove_proc_entry(item->name, toshiba_proc_dir);
506 return AE_OK;
507 }
509 static int __init toshiba_acpi_init(void)
510 {
511 acpi_status status = AE_OK;
512 u32 hci_result;
514 if (acpi_disabled)
515 return -ENODEV;
517 if (!acpi_specific_hotkey_enabled) {
518 printk(MY_INFO "Using generic hotkey driver\n");
519 return -ENODEV;
520 }
521 /* simple device detection: look for HCI method */
522 if (is_valid_acpi_path(METHOD_HCI_1))
523 method_hci = METHOD_HCI_1;
524 else if (is_valid_acpi_path(METHOD_HCI_2))
525 method_hci = METHOD_HCI_2;
526 else
527 return -ENODEV;
529 printk(MY_INFO "Toshiba Laptop ACPI Extras version %s\n",
530 TOSHIBA_ACPI_VERSION);
531 printk(MY_INFO " HCI method: %s\n", method_hci);
533 force_fan = 0;
534 key_event_valid = 0;
536 /* enable event fifo */
537 hci_write1(HCI_SYSTEM_EVENT, 1, &hci_result);
539 toshiba_proc_dir = proc_mkdir(PROC_TOSHIBA, acpi_root_dir);
540 if (!toshiba_proc_dir) {
541 status = AE_ERROR;
542 } else {
543 toshiba_proc_dir->owner = THIS_MODULE;
544 status = add_device();
545 if (ACPI_FAILURE(status))
546 remove_proc_entry(PROC_TOSHIBA, acpi_root_dir);
547 }
549 return (ACPI_SUCCESS(status)) ? 0 : -ENODEV;
550 }
552 static void __exit toshiba_acpi_exit(void)
553 {
554 remove_device();
556 if (toshiba_proc_dir)
557 remove_proc_entry(PROC_TOSHIBA, acpi_root_dir);
559 return;
560 }
562 module_init(toshiba_acpi_init);
563 module_exit(toshiba_acpi_exit);