aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--drivers/acpi/blacklist.c381
-rw-r--r--drivers/acpi/bus.c2
-rw-r--r--drivers/acpi/ec.c26
-rw-r--r--drivers/acpi/fan.c40
-rw-r--r--drivers/acpi/osl.c173
-rw-r--r--drivers/acpi/processor_throttling.c4
-rw-r--r--drivers/firmware/dmi-id.c2
-rw-r--r--drivers/firmware/dmi_scan.c8
-rw-r--r--include/acpi/acpi_bus.h3
-rw-r--r--include/linux/acpi.h7
-rw-r--r--include/linux/dmi.h4
11 files changed, 591 insertions, 59 deletions
diff --git a/drivers/acpi/blacklist.c b/drivers/acpi/blacklist.c
index 3ec110ce00c8..8809654d6cc9 100644
--- a/drivers/acpi/blacklist.c
+++ b/drivers/acpi/blacklist.c
@@ -3,6 +3,7 @@
3 * 3 *
4 * Check to see if the given machine has a known bad ACPI BIOS 4 * Check to see if the given machine has a known bad ACPI BIOS
5 * or if the BIOS is too old. 5 * or if the BIOS is too old.
6 * Check given machine against acpi_osi_dmi_table[].
6 * 7 *
7 * Copyright (C) 2004 Len Brown <len.brown@intel.com> 8 * Copyright (C) 2004 Len Brown <len.brown@intel.com>
8 * Copyright (C) 2002 Andy Grover <andrew.grover@intel.com> 9 * Copyright (C) 2002 Andy Grover <andrew.grover@intel.com>
@@ -50,6 +51,8 @@ struct acpi_blacklist_item {
50 u32 is_critical_error; 51 u32 is_critical_error;
51}; 52};
52 53
54static struct dmi_system_id acpi_osi_dmi_table[] __initdata;
55
53/* 56/*
54 * POLICY: If *anything* doesn't work, put it on the blacklist. 57 * POLICY: If *anything* doesn't work, put it on the blacklist.
55 * If they are critical errors, mark it critical, and abort driver load. 58 * If they are critical errors, mark it critical, and abort driver load.
@@ -165,5 +168,383 @@ int __init acpi_blacklisted(void)
165 168
166 blacklisted += blacklist_by_year(); 169 blacklisted += blacklist_by_year();
167 170
171 dmi_check_system(acpi_osi_dmi_table);
172
168 return blacklisted; 173 return blacklisted;
169} 174}
175#ifdef CONFIG_DMI
176static int __init dmi_enable_osi_linux(const struct dmi_system_id *d)
177{
178 acpi_dmi_osi_linux(1, d); /* enable */
179 return 0;
180}
181static int __init dmi_disable_osi_linux(const struct dmi_system_id *d)
182{
183 acpi_dmi_osi_linux(0, d); /* disable */
184 return 0;
185}
186static int __init dmi_unknown_osi_linux(const struct dmi_system_id *d)
187{
188 acpi_dmi_osi_linux(-1, d); /* unknown */
189 return 0;
190}
191
192/*
193 * Most BIOS that invoke OSI(Linux) do nothing with it.
194 * But some cause Linux to break.
195 * Only a couple use it to make Linux run better.
196 *
197 * Thus, Linux should continue to disable OSI(Linux) by default,
198 * should continue to discourage BIOS writers from using it, and
199 * should whitelist the few existing systems that require it.
200 *
201 * If it appears clear a vendor isn't using OSI(Linux)
202 * for anything constructive, blacklist them by name to disable
203 * unnecessary dmesg warnings on all of their products.
204 */
205
206static struct dmi_system_id acpi_osi_dmi_table[] __initdata = {
207 /*
208 * Disable OSI(Linux) warnings on all "Acer, inc."
209 *
210 * _OSI(Linux) disables the latest Windows BIOS code:
211 * DMI_MATCH(DMI_PRODUCT_NAME, "Aspire 5050"),
212 * DMI_MATCH(DMI_PRODUCT_NAME, "Aspire 5580"),
213 * DMI_MATCH(DMI_PRODUCT_NAME, "TravelMate 3010"),
214 * _OSI(Linux) effect unknown:
215 * DMI_MATCH(DMI_PRODUCT_NAME, "Ferrari 5000"),
216 */
217 {
218 .callback = dmi_disable_osi_linux,
219 .ident = "Acer, inc.",
220 .matches = {
221 DMI_MATCH(DMI_SYS_VENDOR, "Acer, inc."),
222 },
223 },
224 /*
225 * Disable OSI(Linux) warnings on all "Acer"
226 *
227 * _OSI(Linux) effect unknown:
228 * DMI_MATCH(DMI_PRODUCT_NAME, "Aspire 5100"),
229 * DMI_MATCH(DMI_PRODUCT_NAME, "Aspire 5610"),
230 * DMI_MATCH(DMI_PRODUCT_NAME, "Aspire 7720Z"),
231 * DMI_MATCH(DMI_PRODUCT_NAME, "TravelMate 5520"),
232 * DMI_MATCH(DMI_PRODUCT_NAME, "TravelMate 6460"),
233 * DMI_MATCH(DMI_PRODUCT_NAME, "TravelMate 7510"),
234 * DMI_MATCH(DMI_PRODUCT_NAME, "Extensa 5220"),
235 */
236 {
237 .callback = dmi_unknown_osi_linux,
238 .ident = "Acer",
239 .matches = {
240 DMI_MATCH(DMI_SYS_VENDOR, "Acer"),
241 },
242 },
243 /*
244 * Disable OSI(Linux) warnings on all "Apple Computer, Inc."
245 *
246 * _OSI(Linux) confirmed to be a NOP:
247 * DMI_MATCH(DMI_PRODUCT_NAME, "MacBook1,1"),
248 * DMI_MATCH(DMI_PRODUCT_NAME, "MacBook2,1"),
249 * DMI_MATCH(DMI_PRODUCT_NAME, "MacBookPro2,2"),
250 * _OSI(Linux) effect unknown:
251 * DMI_MATCH(DMI_PRODUCT_NAME, "MacPro2,1"),
252 * DMI_MATCH(DMI_PRODUCT_NAME, "MacBookPro1,1"),
253 * DMI_MATCH(DMI_PRODUCT_NAME, "MacBookPro3,1"),
254 */
255 {
256 .callback = dmi_disable_osi_linux,
257 .ident = "Apple",
258 .matches = {
259 DMI_MATCH(DMI_SYS_VENDOR, "Apple Computer, Inc."),
260 },
261 },
262 /*
263 * Disable OSI(Linux) warnings on all "BenQ"
264 *
265 * _OSI(Linux) confirmed to be a NOP:
266 * DMI_MATCH(DMI_PRODUCT_NAME, "Joybook S31"),
267 */
268 {
269 .callback = dmi_disable_osi_linux,
270 .ident = "BenQ",
271 .matches = {
272 DMI_MATCH(DMI_SYS_VENDOR, "BenQ"),
273 },
274 },
275 /*
276 * Disable OSI(Linux) warnings on all "Clevo Co."
277 *
278 * _OSI(Linux) confirmed to be a NOP:
279 * DMI_MATCH(DMI_PRODUCT_NAME, "M570RU"),
280 */
281 {
282 .callback = dmi_disable_osi_linux,
283 .ident = "Clevo",
284 .matches = {
285 DMI_MATCH(DMI_SYS_VENDOR, "Clevo Co."),
286 },
287 },
288 /*
289 * Disable OSI(Linux) warnings on all "COMPAL"
290 *
291 * _OSI(Linux) confirmed to be a NOP:
292 * DMI_MATCH(DMI_BOARD_NAME, "HEL8X"),
293 * _OSI(Linux) unknown effect:
294 * DMI_MATCH(DMI_BOARD_NAME, "IFL91"),
295 */
296 {
297 .callback = dmi_unknown_osi_linux,
298 .ident = "Compal",
299 .matches = {
300 DMI_MATCH(DMI_BIOS_VENDOR, "COMPAL"),
301 },
302 },
303 { /* OSI(Linux) touches USB, breaks suspend to disk */
304 .callback = dmi_disable_osi_linux,
305 .ident = "Dell Dimension 5150",
306 .matches = {
307 DMI_MATCH(DMI_SYS_VENDOR, "Dell Inc."),
308 DMI_MATCH(DMI_PRODUCT_NAME, "Dell DM051"),
309 },
310 },
311 { /* OSI(Linux) is a NOP */
312 .callback = dmi_disable_osi_linux,
313 .ident = "Dell",
314 .matches = {
315 DMI_MATCH(DMI_SYS_VENDOR, "Dell Inc."),
316 DMI_MATCH(DMI_PRODUCT_NAME, "Inspiron 1501"),
317 },
318 },
319 { /* OSI(Linux) effect unknown */
320 .callback = dmi_unknown_osi_linux,
321 .ident = "Dell",
322 .matches = {
323 DMI_MATCH(DMI_SYS_VENDOR, "Dell Inc."),
324 DMI_MATCH(DMI_PRODUCT_NAME, "Latitude D830"),
325 },
326 },
327 { /* OSI(Linux) effect unknown */
328 .callback = dmi_unknown_osi_linux,
329 .ident = "Dell",
330 .matches = {
331 DMI_MATCH(DMI_SYS_VENDOR, "Dell Inc."),
332 DMI_MATCH(DMI_PRODUCT_NAME, "OptiPlex GX620"),
333 },
334 },
335 { /* OSI(Linux) effect unknown */
336 .callback = dmi_unknown_osi_linux,
337 .ident = "Dell",
338 .matches = {
339 DMI_MATCH(DMI_SYS_VENDOR, "Dell Inc."),
340 DMI_MATCH(DMI_PRODUCT_NAME, "PowerEdge 1900"),
341 },
342 },
343 { /* OSI(Linux) touches USB */
344 .callback = dmi_disable_osi_linux,
345 .ident = "Dell",
346 .matches = {
347 DMI_MATCH(DMI_SYS_VENDOR, "Dell Inc."),
348 DMI_MATCH(DMI_PRODUCT_NAME, "Precision WorkStation 390"),
349 },
350 },
351 { /* OSI(Linux) is a NOP */
352 .callback = dmi_disable_osi_linux,
353 .ident = "Dell Vostro 1000",
354 .matches = {
355 DMI_MATCH(DMI_SYS_VENDOR, "Dell Inc."),
356 DMI_MATCH(DMI_PRODUCT_NAME, "Vostro 1000"),
357 },
358 },
359 { /* OSI(Linux) effect unknown */
360 .callback = dmi_unknown_osi_linux,
361 .ident = "Dell",
362 .matches = {
363 DMI_MATCH(DMI_SYS_VENDOR, "Dell Inc."),
364 DMI_MATCH(DMI_PRODUCT_NAME, "PowerEdge SC440"),
365 },
366 },
367 { /* OSI(Linux) effect unknown */
368 .callback = dmi_unknown_osi_linux,
369 .ident = "Dialogue Flybook V5",
370 .matches = {
371 DMI_MATCH(DMI_SYS_VENDOR, "Dialogue Technology Corporation"),
372 DMI_MATCH(DMI_PRODUCT_NAME, "Flybook V5"),
373 },
374 },
375 /*
376 * Disable OSI(Linux) warnings on all "FUJITSU SIEMENS"
377 *
378 * _OSI(Linux) disables latest Windows BIOS code:
379 * DMI_MATCH(DMI_PRODUCT_NAME, "AMILO Pa 2510"),
380 * _OSI(Linux) confirmed to be a NOP:
381 * DMI_MATCH(DMI_PRODUCT_NAME, "AMILO Pi 1536"),
382 * DMI_MATCH(DMI_PRODUCT_NAME, "AMILO Pi 1556"),
383 * DMI_MATCH(DMI_PRODUCT_NAME, "AMILO Xi 1546"),
384 * _OSI(Linux) unknown effect:
385 * DMI_MATCH(DMI_PRODUCT_NAME, "Amilo M1425"),
386 * DMI_MATCH(DMI_PRODUCT_NAME, "Amilo Si 1520"),
387 * DMI_MATCH(DMI_PRODUCT_NAME, "ESPRIMO Mobile V5505"),
388 */
389 {
390 .callback = dmi_disable_osi_linux,
391 .ident = "Fujitsu Siemens",
392 .matches = {
393 DMI_MATCH(DMI_SYS_VENDOR, "FUJITSU SIEMENS"),
394 },
395 },
396 /*
397 * Disable OSI(Linux) warnings on all "Hewlett-Packard"
398 *
399 * _OSI(Linux) confirmed to be a NOP:
400 * .ident = "HP Pavilion tx 1000"
401 * DMI_MATCH(DMI_BOARD_NAME, "30BF"),
402 * .ident = "HP Pavilion dv2000"
403 * DMI_MATCH(DMI_BOARD_NAME, "30B5"),
404 * .ident = "HP Pavilion dv5000",
405 * DMI_MATCH(DMI_BOARD_NAME, "30A7"),
406 * .ident = "HP Pavilion dv6300 30BC",
407 * DMI_MATCH(DMI_BOARD_NAME, "30BC"),
408 * .ident = "HP Pavilion dv6000",
409 * DMI_MATCH(DMI_BOARD_NAME, "30B7"),
410 * DMI_MATCH(DMI_BOARD_NAME, "30B8"),
411 * .ident = "HP Pavilion dv9000",
412 * DMI_MATCH(DMI_BOARD_NAME, "30B9"),
413 * .ident = "HP Pavilion dv9500",
414 * DMI_MATCH(DMI_BOARD_NAME, "30CB"),
415 * .ident = "HP/Compaq Presario C500",
416 * DMI_MATCH(DMI_BOARD_NAME, "30C6"),
417 * .ident = "HP/Compaq Presario F500",
418 * DMI_MATCH(DMI_BOARD_NAME, "30D3"),
419 * _OSI(Linux) unknown effect:
420 * .ident = "HP Pavilion dv6500",
421 * DMI_MATCH(DMI_BOARD_NAME, "30D0"),
422 */
423 {
424 .callback = dmi_disable_osi_linux,
425 .ident = "Hewlett-Packard",
426 .matches = {
427 DMI_MATCH(DMI_SYS_VENDOR, "Hewlett-Packard"),
428 },
429 },
430 /*
431 * Lenovo has a mix of systems OSI(Linux) situations
432 * and thus we can not wildcard the vendor.
433 *
434 * _OSI(Linux) helps sound
435 * DMI_MATCH(DMI_PRODUCT_VERSION, "ThinkPad R61"),
436 * DMI_MATCH(DMI_PRODUCT_VERSION, "ThinkPad T61"),
437 * _OSI(Linux) is a NOP:
438 * DMI_MATCH(DMI_PRODUCT_VERSION, "3000 N100"),
439 */
440 {
441 .callback = dmi_enable_osi_linux,
442 .ident = "Lenovo ThinkPad R61",
443 .matches = {
444 DMI_MATCH(DMI_SYS_VENDOR, "LENOVO"),
445 DMI_MATCH(DMI_PRODUCT_VERSION, "ThinkPad R61"),
446 },
447 },
448 {
449 .callback = dmi_enable_osi_linux,
450 .ident = "Lenovo ThinkPad T61",
451 .matches = {
452 DMI_MATCH(DMI_SYS_VENDOR, "LENOVO"),
453 DMI_MATCH(DMI_PRODUCT_VERSION, "ThinkPad T61"),
454 },
455 },
456 {
457 .callback = dmi_unknown_osi_linux,
458 .ident = "Lenovo 3000 V100",
459 .matches = {
460 DMI_MATCH(DMI_SYS_VENDOR, "LENOVO"),
461 DMI_MATCH(DMI_PRODUCT_VERSION, "LENOVO3000 V100"),
462 },
463 },
464 {
465 .callback = dmi_disable_osi_linux,
466 .ident = "Lenovo 3000 N100",
467 .matches = {
468 DMI_MATCH(DMI_SYS_VENDOR, "LENOVO"),
469 DMI_MATCH(DMI_PRODUCT_VERSION, "3000 N100"),
470 },
471 },
472 /*
473 * Disable OSI(Linux) warnings on all "LG Electronics"
474 *
475 * _OSI(Linux) confirmed to be a NOP:
476 * DMI_MATCH(DMI_PRODUCT_NAME, "P1-J150B"),
477 */
478 {
479 .callback = dmi_disable_osi_linux,
480 .ident = "LG",
481 .matches = {
482 DMI_MATCH(DMI_SYS_VENDOR, "LG Electronics"),
483 },
484 },
485 /* NEC - OSI(Linux) effect unknown */
486 {
487 .callback = dmi_unknown_osi_linux,
488 .ident = "NEC VERSA M360",
489 .matches = {
490 DMI_MATCH(DMI_SYS_VENDOR, "NEC Computers SAS"),
491 DMI_MATCH(DMI_PRODUCT_NAME, "NEC VERSA M360"),
492 },
493 },
494 /*
495 * Disable OSI(Linux) warnings on all "Samsung Electronics"
496 *
497 * OSI(Linux) disables PNP0C32 and other BIOS code for Windows:
498 * DMI_MATCH(DMI_PRODUCT_NAME, "R40P/R41P"),
499 * DMI_MATCH(DMI_PRODUCT_NAME, "R59P/R60P/R61P"),
500 */
501 {
502 .callback = dmi_disable_osi_linux,
503 .ident = "Samsung",
504 .matches = {
505 DMI_MATCH(DMI_SYS_VENDOR, "SAMSUNG ELECTRONICS CO., LTD."),
506 },
507 },
508 /*
509 * Disable OSI(Linux) warnings on all "Sony Corporation"
510 *
511 * _OSI(Linux) is a NOP:
512 * DMI_MATCH(DMI_PRODUCT_NAME, "VGN-SZ650N"),
513 * DMI_MATCH(DMI_PRODUCT_NAME, "VGN-SZ38GP_C"),
514 * DMI_MATCH(DMI_PRODUCT_NAME, "VGN-TZ21MN_N"),
515 * _OSI(Linux) unknown effect:
516 * DMI_MATCH(DMI_PRODUCT_NAME, "VGN-FZ11M"),
517 */
518 {
519 .callback = dmi_unknown_osi_linux,
520 .ident = "Sony",
521 .matches = {
522 DMI_MATCH(DMI_SYS_VENDOR, "Sony Corporation"),
523 },
524 },
525 /*
526 * Disable OSI(Linux) warnings on all "TOSHIBA"
527 *
528 * _OSI(Linux) breaks sound (bugzilla 7787):
529 * DMI_MATCH(DMI_PRODUCT_NAME, "Satellite P100"),
530 * DMI_MATCH(DMI_PRODUCT_NAME, "Satellite P105"),
531 * _OSI(Linux) is a NOP:
532 * DMI_MATCH(DMI_PRODUCT_NAME, "Satellite A100"),
533 * DMI_MATCH(DMI_PRODUCT_NAME, "Satellite A210"),
534 * _OSI(Linux) unknown effect:
535 * DMI_MATCH(DMI_PRODUCT_NAME, "Satellite A135"),
536 * DMI_MATCH(DMI_PRODUCT_NAME, "Satellite A200"),
537 * DMI_MATCH(DMI_PRODUCT_NAME, "Satellite P205"),
538 * DMI_MATCH(DMI_PRODUCT_NAME, "Satellite U305"),
539 */
540 {
541 .callback = dmi_disable_osi_linux,
542 .ident = "Toshiba",
543 .matches = {
544 DMI_MATCH(DMI_SYS_VENDOR, "TOSHIBA"),
545 },
546 },
547 {}
548};
549
550#endif /* CONFIG_DMI */
diff --git a/drivers/acpi/bus.c b/drivers/acpi/bus.c
index d7a115c362d1..f4487c38d9f2 100644
--- a/drivers/acpi/bus.c
+++ b/drivers/acpi/bus.c
@@ -200,7 +200,7 @@ int acpi_bus_set_power(acpi_handle handle, int state)
200 * Get device's current power state 200 * Get device's current power state
201 */ 201 */
202 acpi_bus_get_power(device->handle, &device->power.state); 202 acpi_bus_get_power(device->handle, &device->power.state);
203 if (state == device->power.state) { 203 if ((state == device->power.state) && !device->flags.force_power_state) {
204 ACPI_DEBUG_PRINT((ACPI_DB_INFO, "Device is already at D%d\n", 204 ACPI_DEBUG_PRINT((ACPI_DB_INFO, "Device is already at D%d\n",
205 state)); 205 state));
206 return 0; 206 return 0;
diff --git a/drivers/acpi/ec.c b/drivers/acpi/ec.c
index 97dc16155a55..987b967c7467 100644
--- a/drivers/acpi/ec.c
+++ b/drivers/acpi/ec.c
@@ -26,6 +26,9 @@
26 * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ 26 * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
27 */ 27 */
28 28
29/* Uncomment next line to get verbose print outs*/
30/* #define DEBUG */
31
29#include <linux/kernel.h> 32#include <linux/kernel.h>
30#include <linux/module.h> 33#include <linux/module.h>
31#include <linux/init.h> 34#include <linux/init.h>
@@ -47,9 +50,6 @@
47#undef PREFIX 50#undef PREFIX
48#define PREFIX "ACPI: EC: " 51#define PREFIX "ACPI: EC: "
49 52
50/* Uncomment next line to get verbose print outs*/
51/* #define DEBUG */
52
53/* EC status register */ 53/* EC status register */
54#define ACPI_EC_FLAG_OBF 0x01 /* Output buffer full */ 54#define ACPI_EC_FLAG_OBF 0x01 /* Output buffer full */
55#define ACPI_EC_FLAG_IBF 0x02 /* Input buffer full */ 55#define ACPI_EC_FLAG_IBF 0x02 /* Input buffer full */
@@ -82,6 +82,7 @@ enum {
82 EC_FLAGS_ADDRESS, /* Address is being written */ 82 EC_FLAGS_ADDRESS, /* Address is being written */
83 EC_FLAGS_NO_WDATA_GPE, /* Don't expect WDATA GPE event */ 83 EC_FLAGS_NO_WDATA_GPE, /* Don't expect WDATA GPE event */
84 EC_FLAGS_WDATA, /* Data is being written */ 84 EC_FLAGS_WDATA, /* Data is being written */
85 EC_FLAGS_NO_OBF1_GPE, /* Don't expect GPE before read */
85}; 86};
86 87
87static int acpi_ec_remove(struct acpi_device *device, int type); 88static int acpi_ec_remove(struct acpi_device *device, int type);
@@ -138,26 +139,26 @@ static struct acpi_ec {
138static inline u8 acpi_ec_read_status(struct acpi_ec *ec) 139static inline u8 acpi_ec_read_status(struct acpi_ec *ec)
139{ 140{
140 u8 x = inb(ec->command_addr); 141 u8 x = inb(ec->command_addr);
141 pr_debug(PREFIX "---> status = 0x%2x\n", x); 142 pr_debug(PREFIX "---> status = 0x%2.2x\n", x);
142 return x; 143 return x;
143} 144}
144 145
145static inline u8 acpi_ec_read_data(struct acpi_ec *ec) 146static inline u8 acpi_ec_read_data(struct acpi_ec *ec)
146{ 147{
147 u8 x = inb(ec->data_addr); 148 u8 x = inb(ec->data_addr);
148 pr_debug(PREFIX "---> data = 0x%2x\n", x); 149 pr_debug(PREFIX "---> data = 0x%2.2x\n", x);
149 return inb(ec->data_addr); 150 return inb(ec->data_addr);
150} 151}
151 152
152static inline void acpi_ec_write_cmd(struct acpi_ec *ec, u8 command) 153static inline void acpi_ec_write_cmd(struct acpi_ec *ec, u8 command)
153{ 154{
154 pr_debug(PREFIX "<--- command = 0x%2x\n", command); 155 pr_debug(PREFIX "<--- command = 0x%2.2x\n", command);
155 outb(command, ec->command_addr); 156 outb(command, ec->command_addr);
156} 157}
157 158
158static inline void acpi_ec_write_data(struct acpi_ec *ec, u8 data) 159static inline void acpi_ec_write_data(struct acpi_ec *ec, u8 data)
159{ 160{
160 pr_debug(PREFIX "<--- data = 0x%2x\n", data); 161 pr_debug(PREFIX "<--- data = 0x%2.2x\n", data);
161 outb(data, ec->data_addr); 162 outb(data, ec->data_addr);
162} 163}
163 164
@@ -179,6 +180,10 @@ static inline int acpi_ec_check_status(struct acpi_ec *ec, enum ec_event event)
179static int acpi_ec_wait(struct acpi_ec *ec, enum ec_event event, int force_poll) 180static int acpi_ec_wait(struct acpi_ec *ec, enum ec_event event, int force_poll)
180{ 181{
181 int ret = 0; 182 int ret = 0;
183
184 if (unlikely(event == ACPI_EC_EVENT_OBF_1 &&
185 test_bit(EC_FLAGS_NO_OBF1_GPE, &ec->flags)))
186 force_poll = 1;
182 if (unlikely(test_bit(EC_FLAGS_ADDRESS, &ec->flags) && 187 if (unlikely(test_bit(EC_FLAGS_ADDRESS, &ec->flags) &&
183 test_bit(EC_FLAGS_NO_ADDRESS_GPE, &ec->flags))) 188 test_bit(EC_FLAGS_NO_ADDRESS_GPE, &ec->flags)))
184 force_poll = 1; 189 force_poll = 1;
@@ -192,7 +197,12 @@ static int acpi_ec_wait(struct acpi_ec *ec, enum ec_event event, int force_poll)
192 goto end; 197 goto end;
193 clear_bit(EC_FLAGS_WAIT_GPE, &ec->flags); 198 clear_bit(EC_FLAGS_WAIT_GPE, &ec->flags);
194 if (acpi_ec_check_status(ec, event)) { 199 if (acpi_ec_check_status(ec, event)) {
195 if (test_bit(EC_FLAGS_ADDRESS, &ec->flags)) { 200 if (event == ACPI_EC_EVENT_OBF_1) {
201 /* miss OBF_1 GPE, don't expect it */
202 pr_info(PREFIX "missing OBF confirmation, "
203 "don't expect it any longer.\n");
204 set_bit(EC_FLAGS_NO_OBF1_GPE, &ec->flags);
205 } else if (test_bit(EC_FLAGS_ADDRESS, &ec->flags)) {
196 /* miss address GPE, don't expect it anymore */ 206 /* miss address GPE, don't expect it anymore */
197 pr_info(PREFIX "missing address confirmation, " 207 pr_info(PREFIX "missing address confirmation, "
198 "don't expect it any longer.\n"); 208 "don't expect it any longer.\n");
diff --git a/drivers/acpi/fan.c b/drivers/acpi/fan.c
index a5a5532db268..a6e149d692cb 100644
--- a/drivers/acpi/fan.c
+++ b/drivers/acpi/fan.c
@@ -47,6 +47,8 @@ MODULE_LICENSE("GPL");
47 47
48static int acpi_fan_add(struct acpi_device *device); 48static int acpi_fan_add(struct acpi_device *device);
49static int acpi_fan_remove(struct acpi_device *device, int type); 49static int acpi_fan_remove(struct acpi_device *device, int type);
50static int acpi_fan_suspend(struct acpi_device *device, pm_message_t state);
51static int acpi_fan_resume(struct acpi_device *device);
50 52
51static const struct acpi_device_id fan_device_ids[] = { 53static const struct acpi_device_id fan_device_ids[] = {
52 {"PNP0C0B", 0}, 54 {"PNP0C0B", 0},
@@ -61,6 +63,8 @@ static struct acpi_driver acpi_fan_driver = {
61 .ops = { 63 .ops = {
62 .add = acpi_fan_add, 64 .add = acpi_fan_add,
63 .remove = acpi_fan_remove, 65 .remove = acpi_fan_remove,
66 .suspend = acpi_fan_suspend,
67 .resume = acpi_fan_resume,
64 }, 68 },
65}; 69};
66 70
@@ -191,6 +195,10 @@ static int acpi_fan_add(struct acpi_device *device)
191 goto end; 195 goto end;
192 } 196 }
193 197
198 device->flags.force_power_state = 1;
199 acpi_bus_set_power(device->handle, state);
200 device->flags.force_power_state = 0;
201
194 result = acpi_fan_add_fs(device); 202 result = acpi_fan_add_fs(device);
195 if (result) 203 if (result)
196 goto end; 204 goto end;
@@ -216,6 +224,38 @@ static int acpi_fan_remove(struct acpi_device *device, int type)
216 return 0; 224 return 0;
217} 225}
218 226
227static int acpi_fan_suspend(struct acpi_device *device, pm_message_t state)
228{
229 if (!device)
230 return -EINVAL;
231
232 acpi_bus_set_power(device->handle, ACPI_STATE_D0);
233
234 return AE_OK;
235}
236
237static int acpi_fan_resume(struct acpi_device *device)
238{
239 int result = 0;
240 int power_state = 0;
241
242 if (!device)
243 return -EINVAL;
244
245 result = acpi_bus_get_power(device->handle, &power_state);
246 if (result) {
247 ACPI_DEBUG_PRINT((ACPI_DB_ERROR,
248 "Error reading fan power state\n"));
249 return result;
250 }
251
252 device->flags.force_power_state = 1;
253 acpi_bus_set_power(device->handle, power_state);
254 device->flags.force_power_state = 0;
255
256 return result;
257}
258
219static int __init acpi_fan_init(void) 259static int __init acpi_fan_init(void)
220{ 260{
221 int result = 0; 261 int result = 0;
diff --git a/drivers/acpi/osl.c b/drivers/acpi/osl.c
index e3a673a00845..e53fb516f9d4 100644
--- a/drivers/acpi/osl.c
+++ b/drivers/acpi/osl.c
@@ -77,11 +77,55 @@ static struct workqueue_struct *kacpi_notify_wq;
77#define OSI_STRING_LENGTH_MAX 64 /* arbitrary */ 77#define OSI_STRING_LENGTH_MAX 64 /* arbitrary */
78static char osi_additional_string[OSI_STRING_LENGTH_MAX]; 78static char osi_additional_string[OSI_STRING_LENGTH_MAX];
79 79
80static int osi_linux; /* disable _OSI(Linux) by default */ 80/*
81 * "Ode to _OSI(Linux)"
82 *
83 * osi_linux -- Control response to BIOS _OSI(Linux) query.
84 *
85 * As Linux evolves, the features that it supports change.
86 * So an OSI string such as "Linux" is not specific enough
87 * to be useful across multiple versions of Linux. It
88 * doesn't identify any particular feature, interface,
89 * or even any particular version of Linux...
90 *
91 * Unfortunately, Linux-2.6.22 and earlier responded "yes"
92 * to a BIOS _OSI(Linux) query. When
93 * a reference mobile BIOS started using it, its use
94 * started to spread to many vendor platforms.
95 * As it is not supportable, we need to halt that spread.
96 *
97 * Today, most BIOS references to _OSI(Linux) are noise --
98 * they have no functional effect and are just dead code
99 * carried over from the reference BIOS.
100 *
101 * The next most common case is that _OSI(Linux) harms Linux,
102 * usually by causing the BIOS to follow paths that are
103 * not tested during Windows validation.
104 *
105 * Finally, there is a short list of platforms
106 * where OSI(Linux) benefits Linux.
107 *
108 * In Linux-2.6.23, OSI(Linux) is first disabled by default.
109 * DMI is used to disable the dmesg warning about OSI(Linux)
110 * on platforms where it is known to have no effect.
111 * But a dmesg warning remains for systems where
112 * we do not know if OSI(Linux) is good or bad for the system.
113 * DMI is also used to enable OSI(Linux) for the machines
114 * that are known to need it.
115 *
116 * BIOS writers should NOT query _OSI(Linux) on future systems.
117 * It will be ignored by default, and to get Linux to
118 * not ignore it will require a kernel source update to
119 * add a DMI entry, or a boot-time "acpi_osi=Linux" invocation.
120 */
121#define OSI_LINUX_ENABLE 0
81 122
82#ifdef CONFIG_DMI 123struct osi_linux {
83static struct __initdata dmi_system_id acpi_osl_dmi_table[]; 124 unsigned int enable:1;
84#endif 125 unsigned int dmi:1;
126 unsigned int cmdline:1;
127 unsigned int known:1;
128} osi_linux = { OSI_LINUX_ENABLE, 0, 0, 0};
85 129
86static void __init acpi_request_region (struct acpi_generic_address *addr, 130static void __init acpi_request_region (struct acpi_generic_address *addr,
87 unsigned int length, char *desc) 131 unsigned int length, char *desc)
@@ -133,7 +177,6 @@ device_initcall(acpi_reserve_resources);
133 177
134acpi_status __init acpi_os_initialize(void) 178acpi_status __init acpi_os_initialize(void)
135{ 179{
136 dmi_check_system(acpi_osl_dmi_table);
137 return AE_OK; 180 return AE_OK;
138} 181}
139 182
@@ -964,13 +1007,37 @@ static int __init acpi_os_name_setup(char *str)
964 1007
965__setup("acpi_os_name=", acpi_os_name_setup); 1008__setup("acpi_os_name=", acpi_os_name_setup);
966 1009
967static void enable_osi_linux(int enable) { 1010static void __init set_osi_linux(unsigned int enable)
1011{
1012 if (osi_linux.enable != enable) {
1013 osi_linux.enable = enable;
1014 printk(KERN_NOTICE PREFIX "%sed _OSI(Linux)\n",
1015 enable ? "Add": "Delet");
1016 }
1017 return;
1018}
968 1019
969 if (osi_linux != enable) 1020static void __init acpi_cmdline_osi_linux(unsigned int enable)
970 printk(KERN_INFO PREFIX "%sabled _OSI(Linux)\n", 1021{
971 enable ? "En": "Dis"); 1022 osi_linux.cmdline = 1; /* cmdline set the default */
1023 set_osi_linux(enable);
1024
1025 return;
1026}
1027
1028void __init acpi_dmi_osi_linux(int enable, const struct dmi_system_id *d)
1029{
1030 osi_linux.dmi = 1; /* DMI knows that this box asks OSI(Linux) */
1031
1032 printk(KERN_NOTICE PREFIX "DMI detected: %s\n", d->ident);
1033
1034 if (enable == -1)
1035 return;
1036
1037 osi_linux.known = 1; /* DMI knows which OSI(Linux) default needed */
1038
1039 set_osi_linux(enable);
972 1040
973 osi_linux = enable;
974 return; 1041 return;
975} 1042}
976 1043
@@ -987,12 +1054,12 @@ static int __init acpi_osi_setup(char *str)
987 printk(KERN_INFO PREFIX "_OSI method disabled\n"); 1054 printk(KERN_INFO PREFIX "_OSI method disabled\n");
988 acpi_gbl_create_osi_method = FALSE; 1055 acpi_gbl_create_osi_method = FALSE;
989 } else if (!strcmp("!Linux", str)) { 1056 } else if (!strcmp("!Linux", str)) {
990 enable_osi_linux(0); 1057 acpi_cmdline_osi_linux(0); /* !enable */
991 } else if (*str == '!') { 1058 } else if (*str == '!') {
992 if (acpi_osi_invalidate(++str) == AE_OK) 1059 if (acpi_osi_invalidate(++str) == AE_OK)
993 printk(KERN_INFO PREFIX "Deleted _OSI(%s)\n", str); 1060 printk(KERN_INFO PREFIX "Deleted _OSI(%s)\n", str);
994 } else if (!strcmp("Linux", str)) { 1061 } else if (!strcmp("Linux", str)) {
995 enable_osi_linux(1); 1062 acpi_cmdline_osi_linux(1); /* enable */
996 } else if (*osi_additional_string == '\0') { 1063 } else if (*osi_additional_string == '\0') {
997 strncpy(osi_additional_string, str, OSI_STRING_LENGTH_MAX); 1064 strncpy(osi_additional_string, str, OSI_STRING_LENGTH_MAX);
998 printk(KERN_INFO PREFIX "Added _OSI(%s)\n", str); 1065 printk(KERN_INFO PREFIX "Added _OSI(%s)\n", str);
@@ -1141,6 +1208,34 @@ acpi_status acpi_os_release_object(acpi_cache_t * cache, void *object)
1141 return (AE_OK); 1208 return (AE_OK);
1142} 1209}
1143 1210
1211/**
1212 * acpi_dmi_dump - dump DMI slots needed for blacklist entry
1213 *
1214 * Returns 0 on success
1215 */
1216int acpi_dmi_dump(void)
1217{
1218
1219 if (!dmi_available)
1220 return -1;
1221
1222 printk(KERN_NOTICE PREFIX "DMI System Vendor: %s\n",
1223 dmi_get_slot(DMI_SYS_VENDOR));
1224 printk(KERN_NOTICE PREFIX "DMI Product Name: %s\n",
1225 dmi_get_slot(DMI_PRODUCT_NAME));
1226 printk(KERN_NOTICE PREFIX "DMI Product Version: %s\n",
1227 dmi_get_slot(DMI_PRODUCT_VERSION));
1228 printk(KERN_NOTICE PREFIX "DMI Board Name: %s\n",
1229 dmi_get_slot(DMI_BOARD_NAME));
1230 printk(KERN_NOTICE PREFIX "DMI BIOS Vendor: %s\n",
1231 dmi_get_slot(DMI_BIOS_VENDOR));
1232 printk(KERN_NOTICE PREFIX "DMI BIOS Date: %s\n",
1233 dmi_get_slot(DMI_BIOS_DATE));
1234
1235 return 0;
1236}
1237
1238
1144/****************************************************************************** 1239/******************************************************************************
1145 * 1240 *
1146 * FUNCTION: acpi_os_validate_interface 1241 * FUNCTION: acpi_os_validate_interface
@@ -1160,13 +1255,29 @@ acpi_os_validate_interface (char *interface)
1160 if (!strncmp(osi_additional_string, interface, OSI_STRING_LENGTH_MAX)) 1255 if (!strncmp(osi_additional_string, interface, OSI_STRING_LENGTH_MAX))
1161 return AE_OK; 1256 return AE_OK;
1162 if (!strcmp("Linux", interface)) { 1257 if (!strcmp("Linux", interface)) {
1163 printk(KERN_WARNING PREFIX 1258
1164 "System BIOS is requesting _OSI(Linux)\n"); 1259 printk(KERN_NOTICE PREFIX
1165 printk(KERN_WARNING PREFIX 1260 "BIOS _OSI(Linux) query %s%s\n",
1166 "If \"acpi_osi=Linux\" works better,\n" 1261 osi_linux.enable ? "honored" : "ignored",
1167 "Please send dmidecode " 1262 osi_linux.cmdline ? " via cmdline" :
1168 "to linux-acpi@vger.kernel.org\n"); 1263 osi_linux.dmi ? " via DMI" : "");
1169 if(osi_linux) 1264
1265 if (!osi_linux.dmi) {
1266 if (acpi_dmi_dump())
1267 printk(KERN_NOTICE PREFIX
1268 "[please extract dmidecode output]\n");
1269 printk(KERN_NOTICE PREFIX
1270 "Please send DMI info above to "
1271 "linux-acpi@vger.kernel.org\n");
1272 }
1273 if (!osi_linux.known && !osi_linux.cmdline) {
1274 printk(KERN_NOTICE PREFIX
1275 "If \"acpi_osi=%sLinux\" works better, "
1276 "please notify linux-acpi@vger.kernel.org\n",
1277 osi_linux.enable ? "!" : "");
1278 }
1279
1280 if (osi_linux.enable)
1170 return AE_OK; 1281 return AE_OK;
1171 } 1282 }
1172 return AE_SUPPORT; 1283 return AE_SUPPORT;
@@ -1198,28 +1309,4 @@ acpi_os_validate_address (
1198 return AE_OK; 1309 return AE_OK;
1199} 1310}
1200 1311
1201#ifdef CONFIG_DMI
1202static int dmi_osi_linux(const struct dmi_system_id *d)
1203{
1204 printk(KERN_NOTICE "%s detected: enabling _OSI(Linux)\n", d->ident);
1205 enable_osi_linux(1);
1206 return 0;
1207}
1208
1209static struct dmi_system_id acpi_osl_dmi_table[] __initdata = {
1210 /*
1211 * Boxes that need _OSI(Linux)
1212 */
1213 {
1214 .callback = dmi_osi_linux,
1215 .ident = "Intel Napa CRB",
1216 .matches = {
1217 DMI_MATCH(DMI_BOARD_VENDOR, "Intel Corporation"),
1218 DMI_MATCH(DMI_BOARD_NAME, "MPAD-MSAE Customer Reference Boards"),
1219 },
1220 },
1221 {}
1222};
1223#endif /* CONFIG_DMI */
1224
1225#endif 1312#endif
diff --git a/drivers/acpi/processor_throttling.c b/drivers/acpi/processor_throttling.c
index 6742d7bc4777..1685b40abda7 100644
--- a/drivers/acpi/processor_throttling.c
+++ b/drivers/acpi/processor_throttling.c
@@ -775,12 +775,12 @@ int acpi_processor_get_throttling_info(struct acpi_processor *pr)
775 acpi_processor_get_throttling_states(pr) || 775 acpi_processor_get_throttling_states(pr) ||
776 acpi_processor_get_platform_limit(pr)) 776 acpi_processor_get_platform_limit(pr))
777 { 777 {
778 if (acpi_processor_get_fadt_info(pr))
779 return 0;
780 pr->throttling.acpi_processor_get_throttling = 778 pr->throttling.acpi_processor_get_throttling =
781 &acpi_processor_get_throttling_fadt; 779 &acpi_processor_get_throttling_fadt;
782 pr->throttling.acpi_processor_set_throttling = 780 pr->throttling.acpi_processor_set_throttling =
783 &acpi_processor_set_throttling_fadt; 781 &acpi_processor_set_throttling_fadt;
782 if (acpi_processor_get_fadt_info(pr))
783 return 0;
784 } else { 784 } else {
785 pr->throttling.acpi_processor_get_throttling = 785 pr->throttling.acpi_processor_get_throttling =
786 &acpi_processor_get_throttling_ptc; 786 &acpi_processor_get_throttling_ptc;
diff --git a/drivers/firmware/dmi-id.c b/drivers/firmware/dmi-id.c
index bc132d8f79cb..313c99cbdc62 100644
--- a/drivers/firmware/dmi-id.c
+++ b/drivers/firmware/dmi-id.c
@@ -173,8 +173,6 @@ static struct device *dmi_dev;
173 if (dmi_get_system_info(_field)) \ 173 if (dmi_get_system_info(_field)) \
174 sys_dmi_attributes[i++] = &sys_dmi_##_name##_attr.dev_attr.attr; 174 sys_dmi_attributes[i++] = &sys_dmi_##_name##_attr.dev_attr.attr;
175 175
176extern int dmi_available;
177
178/* In a separate function to keep gcc 3.2 happy - do NOT merge this in 176/* In a separate function to keep gcc 3.2 happy - do NOT merge this in
179 dmi_id_init! */ 177 dmi_id_init! */
180static void __init dmi_id_init_attr_table(void) 178static void __init dmi_id_init_attr_table(void)
diff --git a/drivers/firmware/dmi_scan.c b/drivers/firmware/dmi_scan.c
index 0cdadea7a40e..5e596a7e3601 100644
--- a/drivers/firmware/dmi_scan.c
+++ b/drivers/firmware/dmi_scan.c
@@ -470,3 +470,11 @@ int dmi_get_year(int field)
470 return year; 470 return year;
471} 471}
472 472
473/**
474 * dmi_get_slot - return dmi_ident[slot]
475 * @slot: index into dmi_ident[]
476 */
477char *dmi_get_slot(int slot)
478{
479 return(dmi_ident[slot]);
480}
diff --git a/include/acpi/acpi_bus.h b/include/acpi/acpi_bus.h
index 19c3ead2a90b..7b74b60a68a4 100644
--- a/include/acpi/acpi_bus.h
+++ b/include/acpi/acpi_bus.h
@@ -168,7 +168,8 @@ struct acpi_device_flags {
168 u32 power_manageable:1; 168 u32 power_manageable:1;
169 u32 performance_manageable:1; 169 u32 performance_manageable:1;
170 u32 wake_capable:1; /* Wakeup(_PRW) supported? */ 170 u32 wake_capable:1; /* Wakeup(_PRW) supported? */
171 u32 reserved:20; 171 u32 force_power_state:1;
172 u32 reserved:19;
172}; 173};
173 174
174/* File System */ 175/* File System */
diff --git a/include/linux/acpi.h b/include/linux/acpi.h
index e3c16c981e46..63f2e6ed698f 100644
--- a/include/linux/acpi.h
+++ b/include/linux/acpi.h
@@ -40,6 +40,7 @@
40#include <acpi/acpi_drivers.h> 40#include <acpi/acpi_drivers.h>
41#include <acpi/acpi_numa.h> 41#include <acpi/acpi_numa.h>
42#include <asm/acpi.h> 42#include <asm/acpi.h>
43#include <linux/dmi.h>
43 44
44 45
45#ifdef CONFIG_ACPI 46#ifdef CONFIG_ACPI
@@ -192,7 +193,9 @@ extern int ec_transaction(u8 command,
192#endif /*CONFIG_ACPI_EC*/ 193#endif /*CONFIG_ACPI_EC*/
193 194
194extern int acpi_blacklisted(void); 195extern int acpi_blacklisted(void);
195extern void acpi_bios_year(char *s); 196#ifdef CONFIG_DMI
197extern void acpi_dmi_osi_linux(int enable, const struct dmi_system_id *d);
198#endif
196 199
197#ifdef CONFIG_ACPI_NUMA 200#ifdef CONFIG_ACPI_NUMA
198int acpi_get_pxm(acpi_handle handle); 201int acpi_get_pxm(acpi_handle handle);
@@ -226,5 +229,5 @@ static inline int acpi_boot_table_init(void)
226 return 0; 229 return 0;
227} 230}
228 231
229#endif /* CONFIG_ACPI */ 232#endif /* !CONFIG_ACPI */
230#endif /*_LINUX_ACPI_H*/ 233#endif /*_LINUX_ACPI_H*/
diff --git a/include/linux/dmi.h b/include/linux/dmi.h
index 00fc7a9c35ec..5b42a659a308 100644
--- a/include/linux/dmi.h
+++ b/include/linux/dmi.h
@@ -78,6 +78,8 @@ extern const struct dmi_device * dmi_find_device(int type, const char *name,
78extern void dmi_scan_machine(void); 78extern void dmi_scan_machine(void);
79extern int dmi_get_year(int field); 79extern int dmi_get_year(int field);
80extern int dmi_name_in_vendors(const char *str); 80extern int dmi_name_in_vendors(const char *str);
81extern int dmi_available;
82extern char *dmi_get_slot(int slot);
81 83
82#else 84#else
83 85
@@ -87,6 +89,8 @@ static inline const struct dmi_device * dmi_find_device(int type, const char *na
87 const struct dmi_device *from) { return NULL; } 89 const struct dmi_device *from) { return NULL; }
88static inline int dmi_get_year(int year) { return 0; } 90static inline int dmi_get_year(int year) { return 0; }
89static inline int dmi_name_in_vendors(const char *s) { return 0; } 91static inline int dmi_name_in_vendors(const char *s) { return 0; }
92#define dmi_available 0
93static inline char *dmi_get_slot(int slot) { return NULL; }
90 94
91#endif 95#endif
92 96