diff options
| author | Len Brown <len.brown@intel.com> | 2007-05-30 00:10:38 -0400 |
|---|---|---|
| committer | Len Brown <len.brown@intel.com> | 2007-05-30 00:10:38 -0400 |
| commit | f507654d450d329c81a70eec0096d5dfe67802ec (patch) | |
| tree | bdc34cda973fac170cc90d5b6aa61d27ac558949 | |
| parent | ae00d812436dc968f4a5dea7757b6a94910b6dc4 (diff) | |
ACPI: Make _OSI(Linux) a special case
_OSI("Linux") is like _OS("Linux"), it is ill-defined and
virtually no BIOS vendors test interaction with it.
As a result, it can do more damage than good because
it causes the BIOS to follow un-tested paths.
Recently, several machines have turned up that erroneously
test this string in a way which causes them to _not_ test other
compatibility strings, including the ZI9 and Toshiba.
So it appears that this bad code has made it into
a BIOS vendor's reference BIOS.
Linux has no choice but to stop advertising compatibility
with _OSI string "Linux" - as there are an unbounded
number of possible incompatibilities going forward.
But some BIOSes have already shipped which do use it
for things like conditionally re-enabling video on resume
from S3. (Too bad they didn't do that unconditionally)
Add special case code for _OSI(Linux)
Squawk to dmesg if _OSI(Linux) is requested
Add DMI list both to enable and disable _OSI(Linux)
But for now, keep the default enabled via
#define OSI_LINUX_ENABLED.
http://bugzilla.kernel.org/show_bug.cgi?id=7787
Signed-off-by: Len Brown <len.brown@intel.com>
| -rw-r--r-- | drivers/acpi/osl.c | 91 | ||||
| -rw-r--r-- | drivers/acpi/utilities/uteval.c | 1 |
2 files changed, 91 insertions, 1 deletions
diff --git a/drivers/acpi/osl.c b/drivers/acpi/osl.c index f4760cfa61e1..e349879d9246 100644 --- a/drivers/acpi/osl.c +++ b/drivers/acpi/osl.c | |||
| @@ -33,6 +33,7 @@ | |||
| 33 | #include <linux/interrupt.h> | 33 | #include <linux/interrupt.h> |
| 34 | #include <linux/kmod.h> | 34 | #include <linux/kmod.h> |
| 35 | #include <linux/delay.h> | 35 | #include <linux/delay.h> |
| 36 | #include <linux/dmi.h> | ||
| 36 | #include <linux/workqueue.h> | 37 | #include <linux/workqueue.h> |
| 37 | #include <linux/nmi.h> | 38 | #include <linux/nmi.h> |
| 38 | #include <linux/acpi.h> | 39 | #include <linux/acpi.h> |
| @@ -76,6 +77,18 @@ static struct workqueue_struct *kacpi_notify_wq; | |||
| 76 | #define OSI_STRING_LENGTH_MAX 64 /* arbitrary */ | 77 | #define OSI_STRING_LENGTH_MAX 64 /* arbitrary */ |
| 77 | static char osi_additional_string[OSI_STRING_LENGTH_MAX]; | 78 | static char osi_additional_string[OSI_STRING_LENGTH_MAX]; |
| 78 | 79 | ||
| 80 | #define OSI_LINUX_ENABLED | ||
| 81 | #ifdef OSI_LINUX_ENABLED | ||
| 82 | int osi_linux = 1; /* enable _OSI(Linux) by default */ | ||
| 83 | #else | ||
| 84 | int osi_linux; /* disable _OSI(Linux) by default */ | ||
| 85 | #endif | ||
| 86 | |||
| 87 | |||
| 88 | #ifdef CONFIG_DMI | ||
| 89 | static struct dmi_system_id acpi_osl_dmi_table[]; | ||
| 90 | #endif | ||
| 91 | |||
| 79 | static void __init acpi_request_region (struct acpi_generic_address *addr, | 92 | static void __init acpi_request_region (struct acpi_generic_address *addr, |
| 80 | unsigned int length, char *desc) | 93 | unsigned int length, char *desc) |
| 81 | { | 94 | { |
| @@ -126,6 +139,7 @@ device_initcall(acpi_reserve_resources); | |||
| 126 | 139 | ||
| 127 | acpi_status acpi_os_initialize(void) | 140 | acpi_status acpi_os_initialize(void) |
| 128 | { | 141 | { |
| 142 | dmi_check_system(acpi_osl_dmi_table); | ||
| 129 | return AE_OK; | 143 | return AE_OK; |
| 130 | } | 144 | } |
| 131 | 145 | ||
| @@ -963,6 +977,16 @@ static int __init acpi_os_name_setup(char *str) | |||
| 963 | 977 | ||
| 964 | __setup("acpi_os_name=", acpi_os_name_setup); | 978 | __setup("acpi_os_name=", acpi_os_name_setup); |
| 965 | 979 | ||
| 980 | static void enable_osi_linux(int enable) { | ||
| 981 | |||
| 982 | if (osi_linux != enable) | ||
| 983 | printk(KERN_INFO PREFIX "%sabled _OSI(Linux)\n", | ||
| 984 | enable ? "En": "Dis"); | ||
| 985 | |||
| 986 | osi_linux = enable; | ||
| 987 | return; | ||
| 988 | } | ||
| 989 | |||
| 966 | /* | 990 | /* |
| 967 | * Modify the list of "OS Interfaces" reported to BIOS via _OSI | 991 | * Modify the list of "OS Interfaces" reported to BIOS via _OSI |
| 968 | * | 992 | * |
| @@ -978,6 +1002,10 @@ static int __init acpi_osi_setup(char *str) | |||
| 978 | } else if (*str == '!') { | 1002 | } else if (*str == '!') { |
| 979 | if (acpi_osi_invalidate(++str) == AE_OK) | 1003 | if (acpi_osi_invalidate(++str) == AE_OK) |
| 980 | printk(KERN_INFO PREFIX "Deleted _OSI(%s)\n", str); | 1004 | printk(KERN_INFO PREFIX "Deleted _OSI(%s)\n", str); |
| 1005 | } else if (!strcmp("!Linux", str)) { | ||
| 1006 | enable_osi_linux(0); | ||
| 1007 | } else if (!strcmp("Linux", str)) { | ||
| 1008 | enable_osi_linux(1); | ||
| 981 | } else if (*osi_additional_string == '\0') { | 1009 | } else if (*osi_additional_string == '\0') { |
| 982 | strncpy(osi_additional_string, str, OSI_STRING_LENGTH_MAX); | 1010 | strncpy(osi_additional_string, str, OSI_STRING_LENGTH_MAX); |
| 983 | printk(KERN_INFO PREFIX "Added _OSI(%s)\n", str); | 1011 | printk(KERN_INFO PREFIX "Added _OSI(%s)\n", str); |
| @@ -1152,6 +1180,23 @@ acpi_os_validate_interface (char *interface) | |||
| 1152 | { | 1180 | { |
| 1153 | if (!strncmp(osi_additional_string, interface, OSI_STRING_LENGTH_MAX)) | 1181 | if (!strncmp(osi_additional_string, interface, OSI_STRING_LENGTH_MAX)) |
| 1154 | return AE_OK; | 1182 | return AE_OK; |
| 1183 | if (!strcmp("Linux", interface)) { | ||
| 1184 | printk(KERN_WARNING PREFIX | ||
| 1185 | "System BIOS is requesting _OSI(Linux)\n"); | ||
| 1186 | #ifdef OSI_LINUX_ENABLED | ||
| 1187 | printk(KERN_WARNING PREFIX | ||
| 1188 | "Please test with \"acpi_osi=!Linux\"\n" | ||
| 1189 | "Please send dmidecode " | ||
| 1190 | "to linux-acpi@vger.kernel.org\n"); | ||
| 1191 | #else | ||
| 1192 | printk(KERN_WARNING PREFIX | ||
| 1193 | "If \"acpi_osi=Linux\" works better,\n" | ||
| 1194 | "Please send dmidecode " | ||
| 1195 | "to linux-acpi@vger.kernel.org\n"); | ||
| 1196 | #endif | ||
| 1197 | if(osi_linux) | ||
| 1198 | return AE_OK; | ||
| 1199 | } | ||
| 1155 | return AE_SUPPORT; | 1200 | return AE_SUPPORT; |
| 1156 | } | 1201 | } |
| 1157 | 1202 | ||
| @@ -1181,5 +1226,51 @@ acpi_os_validate_address ( | |||
| 1181 | return AE_OK; | 1226 | return AE_OK; |
| 1182 | } | 1227 | } |
| 1183 | 1228 | ||
| 1229 | #ifdef CONFIG_DMI | ||
| 1230 | #ifdef OSI_LINUX_ENABLED | ||
| 1231 | static int dmi_osi_not_linux(struct dmi_system_id *d) | ||
| 1232 | { | ||
| 1233 | printk(KERN_NOTICE "%s detected: requires not _OSI(Linux)\n", d->ident); | ||
| 1234 | enable_osi_linux(0); | ||
| 1235 | return 0; | ||
| 1236 | } | ||
| 1237 | #else | ||
| 1238 | static int dmi_osi_linux(struct dmi_system_id *d) | ||
| 1239 | { | ||
| 1240 | printk(KERN_NOTICE "%s detected: requires _OSI(Linux)\n", d->ident); | ||
| 1241 | enable_osi_linux(1); | ||
| 1242 | return 0; | ||
| 1243 | } | ||
| 1244 | #endif | ||
| 1245 | |||
| 1246 | static struct dmi_system_id acpi_osl_dmi_table[] = { | ||
| 1247 | #ifdef OSI_LINUX_ENABLED | ||
| 1248 | /* | ||
| 1249 | * Boxes that need NOT _OSI(Linux) | ||
| 1250 | */ | ||
| 1251 | { | ||
| 1252 | .callback = dmi_osi_not_linux, | ||
| 1253 | .ident = "Toshiba Satellite P100", | ||
| 1254 | .matches = { | ||
| 1255 | DMI_MATCH(DMI_BOARD_VENDOR, "TOSHIBA"), | ||
| 1256 | DMI_MATCH(DMI_BOARD_NAME, "Satellite P100"), | ||
| 1257 | }, | ||
| 1258 | }, | ||
| 1259 | #else | ||
| 1260 | /* | ||
| 1261 | * Boxes that need _OSI(Linux) | ||
| 1262 | */ | ||
| 1263 | { | ||
| 1264 | .callback = dmi_osi_linux, | ||
| 1265 | .ident = "Intel Napa CRB", | ||
| 1266 | .matches = { | ||
| 1267 | DMI_MATCH(DMI_BOARD_VENDOR, "Intel Corporation"), | ||
| 1268 | DMI_MATCH(DMI_BOARD_NAME, "MPAD-MSAE Customer Reference Boards"), | ||
| 1269 | }, | ||
| 1270 | }, | ||
| 1271 | #endif | ||
| 1272 | {} | ||
| 1273 | }; | ||
| 1274 | #endif /* CONFIG_DMI */ | ||
| 1184 | 1275 | ||
| 1185 | #endif | 1276 | #endif |
diff --git a/drivers/acpi/utilities/uteval.c b/drivers/acpi/utilities/uteval.c index a10120ad6982..8ec6f8e48138 100644 --- a/drivers/acpi/utilities/uteval.c +++ b/drivers/acpi/utilities/uteval.c | |||
| @@ -62,7 +62,6 @@ acpi_ut_translate_one_cid(union acpi_operand_object *obj_desc, | |||
| 62 | static char *acpi_interfaces_supported[] = { | 62 | static char *acpi_interfaces_supported[] = { |
| 63 | /* Operating System Vendor Strings */ | 63 | /* Operating System Vendor Strings */ |
| 64 | 64 | ||
| 65 | "Linux", | ||
| 66 | "Windows 2000", | 65 | "Windows 2000", |
| 67 | "Windows 2001", | 66 | "Windows 2001", |
| 68 | "Windows 2001 SP0", | 67 | "Windows 2001 SP0", |
