aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/acpi/osl.c
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/acpi/osl.c')
-rw-r--r--drivers/acpi/osl.c223
1 files changed, 144 insertions, 79 deletions
diff --git a/drivers/acpi/osl.c b/drivers/acpi/osl.c
index 82525d9cccb0..0c41db3075a5 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 123static struct 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
@@ -207,8 +250,12 @@ acpi_physical_address __init acpi_os_get_root_pointer(void)
207 "System description tables not found\n"); 250 "System description tables not found\n");
208 return 0; 251 return 0;
209 } 252 }
210 } else 253 } else {
211 return acpi_find_rsdp(); 254 acpi_physical_address pa = 0;
255
256 acpi_find_root_pointer(&pa);
257 return pa;
258 }
212} 259}
213 260
214void __iomem *__init_refok 261void __iomem *__init_refok
@@ -619,25 +666,6 @@ static void acpi_os_execute_deferred(struct work_struct *work)
619 dpc->function(dpc->context); 666 dpc->function(dpc->context);
620 kfree(dpc); 667 kfree(dpc);
621 668
622 /* Yield cpu to notify thread */
623 cond_resched();
624
625 return;
626}
627
628static void acpi_os_execute_notify(struct work_struct *work)
629{
630 struct acpi_os_dpc *dpc = container_of(work, struct acpi_os_dpc, work);
631
632 if (!dpc) {
633 printk(KERN_ERR PREFIX "Invalid (NULL) context\n");
634 return;
635 }
636
637 dpc->function(dpc->context);
638
639 kfree(dpc);
640
641 return; 669 return;
642} 670}
643 671
@@ -661,7 +689,7 @@ acpi_status acpi_os_execute(acpi_execute_type type,
661{ 689{
662 acpi_status status = AE_OK; 690 acpi_status status = AE_OK;
663 struct acpi_os_dpc *dpc; 691 struct acpi_os_dpc *dpc;
664 692 struct workqueue_struct *queue;
665 ACPI_DEBUG_PRINT((ACPI_DB_EXEC, 693 ACPI_DEBUG_PRINT((ACPI_DB_EXEC,
666 "Scheduling function [%p(%p)] for deferred execution.\n", 694 "Scheduling function [%p(%p)] for deferred execution.\n",
667 function, context)); 695 function, context));
@@ -685,20 +713,13 @@ acpi_status acpi_os_execute(acpi_execute_type type,
685 dpc->function = function; 713 dpc->function = function;
686 dpc->context = context; 714 dpc->context = context;
687 715
688 if (type == OSL_NOTIFY_HANDLER) { 716 INIT_WORK(&dpc->work, acpi_os_execute_deferred);
689 INIT_WORK(&dpc->work, acpi_os_execute_notify); 717 queue = (type == OSL_NOTIFY_HANDLER) ? kacpi_notify_wq : kacpid_wq;
690 if (!queue_work(kacpi_notify_wq, &dpc->work)) { 718 if (!queue_work(queue, &dpc->work)) {
691 status = AE_ERROR; 719 ACPI_DEBUG_PRINT((ACPI_DB_ERROR,
692 kfree(dpc); 720 "Call to queue_work() failed.\n"));
693 } 721 status = AE_ERROR;
694 } else { 722 kfree(dpc);
695 INIT_WORK(&dpc->work, acpi_os_execute_deferred);
696 if (!queue_work(kacpid_wq, &dpc->work)) {
697 ACPI_DEBUG_PRINT((ACPI_DB_ERROR,
698 "Call to queue_work() failed.\n"));
699 status = AE_ERROR;
700 kfree(dpc);
701 }
702 } 723 }
703 return_ACPI_STATUS(status); 724 return_ACPI_STATUS(status);
704} 725}
@@ -965,13 +986,37 @@ static int __init acpi_os_name_setup(char *str)
965 986
966__setup("acpi_os_name=", acpi_os_name_setup); 987__setup("acpi_os_name=", acpi_os_name_setup);
967 988
968static void enable_osi_linux(int enable) { 989static void __init set_osi_linux(unsigned int enable)
990{
991 if (osi_linux.enable != enable) {
992 osi_linux.enable = enable;
993 printk(KERN_NOTICE PREFIX "%sed _OSI(Linux)\n",
994 enable ? "Add": "Delet");
995 }
996 return;
997}
998
999static void __init acpi_cmdline_osi_linux(unsigned int enable)
1000{
1001 osi_linux.cmdline = 1; /* cmdline set the default */
1002 set_osi_linux(enable);
1003
1004 return;
1005}
1006
1007void __init acpi_dmi_osi_linux(int enable, const struct dmi_system_id *d)
1008{
1009 osi_linux.dmi = 1; /* DMI knows that this box asks OSI(Linux) */
1010
1011 printk(KERN_NOTICE PREFIX "DMI detected: %s\n", d->ident);
1012
1013 if (enable == -1)
1014 return;
1015
1016 osi_linux.known = 1; /* DMI knows which OSI(Linux) default needed */
969 1017
970 if (osi_linux != enable) 1018 set_osi_linux(enable);
971 printk(KERN_INFO PREFIX "%sabled _OSI(Linux)\n",
972 enable ? "En": "Dis");
973 1019
974 osi_linux = enable;
975 return; 1020 return;
976} 1021}
977 1022
@@ -988,12 +1033,12 @@ static int __init acpi_osi_setup(char *str)
988 printk(KERN_INFO PREFIX "_OSI method disabled\n"); 1033 printk(KERN_INFO PREFIX "_OSI method disabled\n");
989 acpi_gbl_create_osi_method = FALSE; 1034 acpi_gbl_create_osi_method = FALSE;
990 } else if (!strcmp("!Linux", str)) { 1035 } else if (!strcmp("!Linux", str)) {
991 enable_osi_linux(0); 1036 acpi_cmdline_osi_linux(0); /* !enable */
992 } else if (*str == '!') { 1037 } else if (*str == '!') {
993 if (acpi_osi_invalidate(++str) == AE_OK) 1038 if (acpi_osi_invalidate(++str) == AE_OK)
994 printk(KERN_INFO PREFIX "Deleted _OSI(%s)\n", str); 1039 printk(KERN_INFO PREFIX "Deleted _OSI(%s)\n", str);
995 } else if (!strcmp("Linux", str)) { 1040 } else if (!strcmp("Linux", str)) {
996 enable_osi_linux(1); 1041 acpi_cmdline_osi_linux(1); /* enable */
997 } else if (*osi_additional_string == '\0') { 1042 } else if (*osi_additional_string == '\0') {
998 strncpy(osi_additional_string, str, OSI_STRING_LENGTH_MAX); 1043 strncpy(osi_additional_string, str, OSI_STRING_LENGTH_MAX);
999 printk(KERN_INFO PREFIX "Added _OSI(%s)\n", str); 1044 printk(KERN_INFO PREFIX "Added _OSI(%s)\n", str);
@@ -1142,6 +1187,34 @@ acpi_status acpi_os_release_object(acpi_cache_t * cache, void *object)
1142 return (AE_OK); 1187 return (AE_OK);
1143} 1188}
1144 1189
1190/**
1191 * acpi_dmi_dump - dump DMI slots needed for blacklist entry
1192 *
1193 * Returns 0 on success
1194 */
1195static int acpi_dmi_dump(void)
1196{
1197
1198 if (!dmi_available)
1199 return -1;
1200
1201 printk(KERN_NOTICE PREFIX "DMI System Vendor: %s\n",
1202 dmi_get_system_info(DMI_SYS_VENDOR));
1203 printk(KERN_NOTICE PREFIX "DMI Product Name: %s\n",
1204 dmi_get_system_info(DMI_PRODUCT_NAME));
1205 printk(KERN_NOTICE PREFIX "DMI Product Version: %s\n",
1206 dmi_get_system_info(DMI_PRODUCT_VERSION));
1207 printk(KERN_NOTICE PREFIX "DMI Board Name: %s\n",
1208 dmi_get_system_info(DMI_BOARD_NAME));
1209 printk(KERN_NOTICE PREFIX "DMI BIOS Vendor: %s\n",
1210 dmi_get_system_info(DMI_BIOS_VENDOR));
1211 printk(KERN_NOTICE PREFIX "DMI BIOS Date: %s\n",
1212 dmi_get_system_info(DMI_BIOS_DATE));
1213
1214 return 0;
1215}
1216
1217
1145/****************************************************************************** 1218/******************************************************************************
1146 * 1219 *
1147 * FUNCTION: acpi_os_validate_interface 1220 * FUNCTION: acpi_os_validate_interface
@@ -1161,13 +1234,29 @@ acpi_os_validate_interface (char *interface)
1161 if (!strncmp(osi_additional_string, interface, OSI_STRING_LENGTH_MAX)) 1234 if (!strncmp(osi_additional_string, interface, OSI_STRING_LENGTH_MAX))
1162 return AE_OK; 1235 return AE_OK;
1163 if (!strcmp("Linux", interface)) { 1236 if (!strcmp("Linux", interface)) {
1164 printk(KERN_WARNING PREFIX 1237
1165 "System BIOS is requesting _OSI(Linux)\n"); 1238 printk(KERN_NOTICE PREFIX
1166 printk(KERN_WARNING PREFIX 1239 "BIOS _OSI(Linux) query %s%s\n",
1167 "If \"acpi_osi=Linux\" works better,\n" 1240 osi_linux.enable ? "honored" : "ignored",
1168 "Please send dmidecode " 1241 osi_linux.cmdline ? " via cmdline" :
1169 "to linux-acpi@vger.kernel.org\n"); 1242 osi_linux.dmi ? " via DMI" : "");
1170 if(osi_linux) 1243
1244 if (!osi_linux.dmi) {
1245 if (acpi_dmi_dump())
1246 printk(KERN_NOTICE PREFIX
1247 "[please extract dmidecode output]\n");
1248 printk(KERN_NOTICE PREFIX
1249 "Please send DMI info above to "
1250 "linux-acpi@vger.kernel.org\n");
1251 }
1252 if (!osi_linux.known && !osi_linux.cmdline) {
1253 printk(KERN_NOTICE PREFIX
1254 "If \"acpi_osi=%sLinux\" works better, "
1255 "please notify linux-acpi@vger.kernel.org\n",
1256 osi_linux.enable ? "!" : "");
1257 }
1258
1259 if (osi_linux.enable)
1171 return AE_OK; 1260 return AE_OK;
1172 } 1261 }
1173 return AE_SUPPORT; 1262 return AE_SUPPORT;
@@ -1199,28 +1288,4 @@ acpi_os_validate_address (
1199 return AE_OK; 1288 return AE_OK;
1200} 1289}
1201 1290
1202#ifdef CONFIG_DMI
1203static int dmi_osi_linux(const struct dmi_system_id *d)
1204{
1205 printk(KERN_NOTICE "%s detected: enabling _OSI(Linux)\n", d->ident);
1206 enable_osi_linux(1);
1207 return 0;
1208}
1209
1210static struct dmi_system_id acpi_osl_dmi_table[] __initdata = {
1211 /*
1212 * Boxes that need _OSI(Linux)
1213 */
1214 {
1215 .callback = dmi_osi_linux,
1216 .ident = "Intel Napa CRB",
1217 .matches = {
1218 DMI_MATCH(DMI_BOARD_VENDOR, "Intel Corporation"),
1219 DMI_MATCH(DMI_BOARD_NAME, "MPAD-MSAE Customer Reference Boards"),
1220 },
1221 },
1222 {}
1223};
1224#endif /* CONFIG_DMI */
1225
1226#endif 1291#endif