diff options
author | Len Brown <len.brown@intel.com> | 2008-01-23 20:50:56 -0500 |
---|---|---|
committer | Len Brown <len.brown@intel.com> | 2008-01-23 21:26:15 -0500 |
commit | d4b7dc499daae909e62dc260b95cd618f2970ded (patch) | |
tree | d24816be9d0830724e35f322c515dc8db38d4a2e | |
parent | 7ce95ce5c6dbbc3f70933f04537860ffd9dbe17e (diff) |
ACPI: make _OSI(Linux) console messages smarter
If BIOS invokes _OSI(Linux), the kernel response
depends on what the ACPI DMI list knows about the system,
and that is reflectd in dmesg:
1) System unknown to DMI:
ACPI: BIOS _OSI(Linux) query ignored
ACPI: DMI System Vendor: LENOVO
ACPI: DMI Product Name: 7661W1P
ACPI: DMI Product Version: ThinkPad T61
ACPI: DMI Board Name: 7661W1P
ACPI: DMI BIOS Vendor: LENOVO
ACPI: DMI BIOS Date: 10/18/2007
ACPI: Please send DMI info above to linux-acpi@vger.kernel.org
ACPI: If "acpi_osi=Linux" works better, please notify linux-acpi@vger.kernel.org
2) System known to DMI, but effect of OSI(Linux) unknown:
ACPI: DMI detected: Lenovo ThinkPad T61
...
ACPI: BIOS _OSI(Linux) query ignored via DMI
ACPI: If "acpi_osi=Linux" works better, please notify linux-acpi@vger.kernel.org
3) System known to DMI, which disables _OSI(Linux):
ACPI: DMI detected: Lenovo ThinkPad T61
...
ACPI: BIOS _OSI(Linux) query ignored via DMI
4) System known to DMI, which enable _OSI(Linux):
ACPI: DMI detected: Lenovo ThinkPad T61
ACPI: Added _OSI(Linux)
...
ACPI: BIOS _OSI(Linux) query honored via DMI
cmdline overrides take precidence over the built-in
default and the DMI prescribed default.
cmdline "acpi_osi=Linux" results in:
ACPI: BIOS _OSI(Linux) query honored via cmdline
Signed-off-by: Len Brown <len.brown@intel.com>
-rw-r--r-- | drivers/acpi/blacklist.c | 11 | ||||
-rw-r--r-- | drivers/acpi/osl.c | 122 | ||||
-rw-r--r-- | include/linux/acpi.h | 7 |
3 files changed, 118 insertions, 22 deletions
diff --git a/drivers/acpi/blacklist.c b/drivers/acpi/blacklist.c index 3ec110ce00c8..018fc16c44ce 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 | ||
54 | static 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,13 @@ 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 | ||
176 | static struct dmi_system_id acpi_osi_dmi_table[] __initdata = { | ||
177 | {} | ||
178 | }; | ||
179 | |||
180 | #endif /* CONFIG_DMI */ | ||
diff --git a/drivers/acpi/osl.c b/drivers/acpi/osl.c index 15f095ea795e..e53fb516f9d4 100644 --- a/drivers/acpi/osl.c +++ b/drivers/acpi/osl.c | |||
@@ -77,7 +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 */ |
78 | static char osi_additional_string[OSI_STRING_LENGTH_MAX]; | 78 | static char osi_additional_string[OSI_STRING_LENGTH_MAX]; |
79 | 79 | ||
80 | static 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 | ||
122 | |||
123 | struct osi_linux { | ||
124 | unsigned int enable:1; | ||
125 | unsigned int dmi:1; | ||
126 | unsigned int cmdline:1; | ||
127 | unsigned int known:1; | ||
128 | } osi_linux = { OSI_LINUX_ENABLE, 0, 0, 0}; | ||
81 | 129 | ||
82 | static void __init acpi_request_region (struct acpi_generic_address *addr, | 130 | static void __init acpi_request_region (struct acpi_generic_address *addr, |
83 | unsigned int length, char *desc) | 131 | unsigned int length, char *desc) |
@@ -959,13 +1007,37 @@ static int __init acpi_os_name_setup(char *str) | |||
959 | 1007 | ||
960 | __setup("acpi_os_name=", acpi_os_name_setup); | 1008 | __setup("acpi_os_name=", acpi_os_name_setup); |
961 | 1009 | ||
962 | static void enable_osi_linux(int enable) { | 1010 | static 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 | } | ||
1019 | |||
1020 | static void __init acpi_cmdline_osi_linux(unsigned int enable) | ||
1021 | { | ||
1022 | osi_linux.cmdline = 1; /* cmdline set the default */ | ||
1023 | set_osi_linux(enable); | ||
1024 | |||
1025 | return; | ||
1026 | } | ||
1027 | |||
1028 | void __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 */ | ||
963 | 1038 | ||
964 | if (osi_linux != enable) | 1039 | set_osi_linux(enable); |
965 | printk(KERN_INFO PREFIX "%sabled _OSI(Linux)\n", | ||
966 | enable ? "En": "Dis"); | ||
967 | 1040 | ||
968 | osi_linux = enable; | ||
969 | return; | 1041 | return; |
970 | } | 1042 | } |
971 | 1043 | ||
@@ -982,12 +1054,12 @@ static int __init acpi_osi_setup(char *str) | |||
982 | printk(KERN_INFO PREFIX "_OSI method disabled\n"); | 1054 | printk(KERN_INFO PREFIX "_OSI method disabled\n"); |
983 | acpi_gbl_create_osi_method = FALSE; | 1055 | acpi_gbl_create_osi_method = FALSE; |
984 | } else if (!strcmp("!Linux", str)) { | 1056 | } else if (!strcmp("!Linux", str)) { |
985 | enable_osi_linux(0); | 1057 | acpi_cmdline_osi_linux(0); /* !enable */ |
986 | } else if (*str == '!') { | 1058 | } else if (*str == '!') { |
987 | if (acpi_osi_invalidate(++str) == AE_OK) | 1059 | if (acpi_osi_invalidate(++str) == AE_OK) |
988 | printk(KERN_INFO PREFIX "Deleted _OSI(%s)\n", str); | 1060 | printk(KERN_INFO PREFIX "Deleted _OSI(%s)\n", str); |
989 | } else if (!strcmp("Linux", str)) { | 1061 | } else if (!strcmp("Linux", str)) { |
990 | enable_osi_linux(1); | 1062 | acpi_cmdline_osi_linux(1); /* enable */ |
991 | } else if (*osi_additional_string == '\0') { | 1063 | } else if (*osi_additional_string == '\0') { |
992 | strncpy(osi_additional_string, str, OSI_STRING_LENGTH_MAX); | 1064 | strncpy(osi_additional_string, str, OSI_STRING_LENGTH_MAX); |
993 | printk(KERN_INFO PREFIX "Added _OSI(%s)\n", str); | 1065 | printk(KERN_INFO PREFIX "Added _OSI(%s)\n", str); |
@@ -1183,19 +1255,29 @@ acpi_os_validate_interface (char *interface) | |||
1183 | if (!strncmp(osi_additional_string, interface, OSI_STRING_LENGTH_MAX)) | 1255 | if (!strncmp(osi_additional_string, interface, OSI_STRING_LENGTH_MAX)) |
1184 | return AE_OK; | 1256 | return AE_OK; |
1185 | if (!strcmp("Linux", interface)) { | 1257 | if (!strcmp("Linux", interface)) { |
1186 | printk(KERN_WARNING PREFIX | 1258 | |
1187 | "System BIOS is requesting _OSI(Linux)\n"); | ||
1188 | if (acpi_dmi_dump()) | ||
1189 | printk(KERN_NOTICE PREFIX | ||
1190 | "[please extract dmidecode output]\n"); | ||
1191 | printk(KERN_NOTICE PREFIX | ||
1192 | "Please send DMI info above to " | ||
1193 | "linux-acpi@vger.kernel.org\n"); | ||
1194 | printk(KERN_NOTICE PREFIX | 1259 | printk(KERN_NOTICE PREFIX |
1195 | "If \"acpi_osi=%sLinux\" works better, " | 1260 | "BIOS _OSI(Linux) query %s%s\n", |
1196 | "please notify linux-acpi@vger.kernel.org\n", | 1261 | osi_linux.enable ? "honored" : "ignored", |
1197 | osi_linux ? "!" : ""); | 1262 | osi_linux.cmdline ? " via cmdline" : |
1198 | if(osi_linux) | 1263 | osi_linux.dmi ? " via DMI" : ""); |
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) | ||
1199 | return AE_OK; | 1281 | return AE_OK; |
1200 | } | 1282 | } |
1201 | return AE_SUPPORT; | 1283 | return AE_SUPPORT; |
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 | ||
194 | extern int acpi_blacklisted(void); | 195 | extern int acpi_blacklisted(void); |
195 | extern void acpi_bios_year(char *s); | 196 | #ifdef CONFIG_DMI |
197 | extern 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 |
198 | int acpi_get_pxm(acpi_handle handle); | 201 | int 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*/ |