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.c162
1 files changed, 50 insertions, 112 deletions
diff --git a/drivers/acpi/osl.c b/drivers/acpi/osl.c
index 65b25a303b86..d3bed219c442 100644
--- a/drivers/acpi/osl.c
+++ b/drivers/acpi/osl.c
@@ -96,7 +96,9 @@ static LIST_HEAD(resource_list_head);
96static DEFINE_SPINLOCK(acpi_res_lock); 96static DEFINE_SPINLOCK(acpi_res_lock);
97 97
98#define OSI_STRING_LENGTH_MAX 64 /* arbitrary */ 98#define OSI_STRING_LENGTH_MAX 64 /* arbitrary */
99static char osi_additional_string[OSI_STRING_LENGTH_MAX]; 99static char osi_setup_string[OSI_STRING_LENGTH_MAX];
100
101static void __init acpi_osi_setup_late(void);
100 102
101/* 103/*
102 * The story of _OSI(Linux) 104 * The story of _OSI(Linux)
@@ -138,6 +140,20 @@ static struct osi_linux {
138 unsigned int known:1; 140 unsigned int known:1;
139} osi_linux = { 0, 0, 0, 0}; 141} osi_linux = { 0, 0, 0, 0};
140 142
143static u32 acpi_osi_handler(acpi_string interface, u32 supported)
144{
145 if (!strcmp("Linux", interface)) {
146
147 printk(KERN_NOTICE FW_BUG PREFIX
148 "BIOS _OSI(Linux) query %s%s\n",
149 osi_linux.enable ? "honored" : "ignored",
150 osi_linux.cmdline ? " via cmdline" :
151 osi_linux.dmi ? " via DMI" : "");
152 }
153
154 return supported;
155}
156
141static void __init acpi_request_region (struct acpi_generic_address *addr, 157static void __init acpi_request_region (struct acpi_generic_address *addr,
142 unsigned int length, char *desc) 158 unsigned int length, char *desc)
143{ 159{
@@ -198,6 +214,8 @@ acpi_status acpi_os_initialize1(void)
198 BUG_ON(!kacpid_wq); 214 BUG_ON(!kacpid_wq);
199 BUG_ON(!kacpi_notify_wq); 215 BUG_ON(!kacpi_notify_wq);
200 BUG_ON(!kacpi_hotplug_wq); 216 BUG_ON(!kacpi_hotplug_wq);
217 acpi_install_interface_handler(acpi_osi_handler);
218 acpi_osi_setup_late();
201 return AE_OK; 219 return AE_OK;
202} 220}
203 221
@@ -547,9 +565,10 @@ acpi_os_write_memory(acpi_physical_address phys_addr, u32 value, u32 width)
547 565
548acpi_status 566acpi_status
549acpi_os_read_pci_configuration(struct acpi_pci_id * pci_id, u32 reg, 567acpi_os_read_pci_configuration(struct acpi_pci_id * pci_id, u32 reg,
550 u32 *value, u32 width) 568 u64 *value, u32 width)
551{ 569{
552 int result, size; 570 int result, size;
571 u32 value32;
553 572
554 if (!value) 573 if (!value)
555 return AE_BAD_PARAMETER; 574 return AE_BAD_PARAMETER;
@@ -570,7 +589,8 @@ acpi_os_read_pci_configuration(struct acpi_pci_id * pci_id, u32 reg,
570 589
571 result = raw_pci_read(pci_id->segment, pci_id->bus, 590 result = raw_pci_read(pci_id->segment, pci_id->bus,
572 PCI_DEVFN(pci_id->device, pci_id->function), 591 PCI_DEVFN(pci_id->device, pci_id->function),
573 reg, size, value); 592 reg, size, &value32);
593 *value = value32;
574 594
575 return (result ? AE_ERROR : AE_OK); 595 return (result ? AE_ERROR : AE_OK);
576} 596}
@@ -602,74 +622,6 @@ acpi_os_write_pci_configuration(struct acpi_pci_id * pci_id, u32 reg,
602 return (result ? AE_ERROR : AE_OK); 622 return (result ? AE_ERROR : AE_OK);
603} 623}
604 624
605/* TODO: Change code to take advantage of driver model more */
606static void acpi_os_derive_pci_id_2(acpi_handle rhandle, /* upper bound */
607 acpi_handle chandle, /* current node */
608 struct acpi_pci_id **id,
609 int *is_bridge, u8 * bus_number)
610{
611 acpi_handle handle;
612 struct acpi_pci_id *pci_id = *id;
613 acpi_status status;
614 unsigned long long temp;
615 acpi_object_type type;
616
617 acpi_get_parent(chandle, &handle);
618 if (handle != rhandle) {
619 acpi_os_derive_pci_id_2(rhandle, handle, &pci_id, is_bridge,
620 bus_number);
621
622 status = acpi_get_type(handle, &type);
623 if ((ACPI_FAILURE(status)) || (type != ACPI_TYPE_DEVICE))
624 return;
625
626 status = acpi_evaluate_integer(handle, METHOD_NAME__ADR, NULL,
627 &temp);
628 if (ACPI_SUCCESS(status)) {
629 u32 val;
630 pci_id->device = ACPI_HIWORD(ACPI_LODWORD(temp));
631 pci_id->function = ACPI_LOWORD(ACPI_LODWORD(temp));
632
633 if (*is_bridge)
634 pci_id->bus = *bus_number;
635
636 /* any nicer way to get bus number of bridge ? */
637 status =
638 acpi_os_read_pci_configuration(pci_id, 0x0e, &val,
639 8);
640 if (ACPI_SUCCESS(status)
641 && ((val & 0x7f) == 1 || (val & 0x7f) == 2)) {
642 status =
643 acpi_os_read_pci_configuration(pci_id, 0x18,
644 &val, 8);
645 if (!ACPI_SUCCESS(status)) {
646 /* Certainly broken... FIX ME */
647 return;
648 }
649 *is_bridge = 1;
650 pci_id->bus = val;
651 status =
652 acpi_os_read_pci_configuration(pci_id, 0x19,
653 &val, 8);
654 if (ACPI_SUCCESS(status)) {
655 *bus_number = val;
656 }
657 } else
658 *is_bridge = 0;
659 }
660 }
661}
662
663void acpi_os_derive_pci_id(acpi_handle rhandle, /* upper bound */
664 acpi_handle chandle, /* current node */
665 struct acpi_pci_id **id)
666{
667 int is_bridge = 1;
668 u8 bus_number = (*id)->bus;
669
670 acpi_os_derive_pci_id_2(rhandle, chandle, id, &is_bridge, &bus_number);
671}
672
673static void acpi_os_execute_deferred(struct work_struct *work) 625static void acpi_os_execute_deferred(struct work_struct *work)
674{ 626{
675 struct acpi_os_dpc *dpc = container_of(work, struct acpi_os_dpc, work); 627 struct acpi_os_dpc *dpc = container_of(work, struct acpi_os_dpc, work);
@@ -977,6 +929,12 @@ static void __init set_osi_linux(unsigned int enable)
977 printk(KERN_NOTICE PREFIX "%sed _OSI(Linux)\n", 929 printk(KERN_NOTICE PREFIX "%sed _OSI(Linux)\n",
978 enable ? "Add": "Delet"); 930 enable ? "Add": "Delet");
979 } 931 }
932
933 if (osi_linux.enable)
934 acpi_osi_setup("Linux");
935 else
936 acpi_osi_setup("!Linux");
937
980 return; 938 return;
981} 939}
982 940
@@ -1011,21 +969,33 @@ void __init acpi_dmi_osi_linux(int enable, const struct dmi_system_id *d)
1011 * string starting with '!' disables that string 969 * string starting with '!' disables that string
1012 * otherwise string is added to list, augmenting built-in strings 970 * otherwise string is added to list, augmenting built-in strings
1013 */ 971 */
1014int __init acpi_osi_setup(char *str) 972static void __init acpi_osi_setup_late(void)
1015{ 973{
1016 if (str == NULL || *str == '\0') { 974 char *str = osi_setup_string;
1017 printk(KERN_INFO PREFIX "_OSI method disabled\n"); 975
1018 acpi_gbl_create_osi_method = FALSE; 976 if (*str == '\0')
1019 } else if (!strcmp("!Linux", str)) { 977 return;
978
979 if (!strcmp("!Linux", str)) {
1020 acpi_cmdline_osi_linux(0); /* !enable */ 980 acpi_cmdline_osi_linux(0); /* !enable */
1021 } else if (*str == '!') { 981 } else if (*str == '!') {
1022 if (acpi_osi_invalidate(++str) == AE_OK) 982 if (acpi_remove_interface(++str) == AE_OK)
1023 printk(KERN_INFO PREFIX "Deleted _OSI(%s)\n", str); 983 printk(KERN_INFO PREFIX "Deleted _OSI(%s)\n", str);
1024 } else if (!strcmp("Linux", str)) { 984 } else if (!strcmp("Linux", str)) {
1025 acpi_cmdline_osi_linux(1); /* enable */ 985 acpi_cmdline_osi_linux(1); /* enable */
1026 } else if (*osi_additional_string == '\0') { 986 } else {
1027 strncpy(osi_additional_string, str, OSI_STRING_LENGTH_MAX); 987 if (acpi_install_interface(str) == AE_OK)
1028 printk(KERN_INFO PREFIX "Added _OSI(%s)\n", str); 988 printk(KERN_INFO PREFIX "Added _OSI(%s)\n", str);
989 }
990}
991
992int __init acpi_osi_setup(char *str)
993{
994 if (str == NULL || *str == '\0') {
995 printk(KERN_INFO PREFIX "_OSI method disabled\n");
996 acpi_gbl_create_osi_method = FALSE;
997 } else {
998 strncpy(osi_setup_string, str, OSI_STRING_LENGTH_MAX);
1029 } 999 }
1030 1000
1031 return 1; 1001 return 1;
@@ -1282,38 +1252,6 @@ acpi_status acpi_os_release_object(acpi_cache_t * cache, void *object)
1282 return (AE_OK); 1252 return (AE_OK);
1283} 1253}
1284 1254
1285/******************************************************************************
1286 *
1287 * FUNCTION: acpi_os_validate_interface
1288 *
1289 * PARAMETERS: interface - Requested interface to be validated
1290 *
1291 * RETURN: AE_OK if interface is supported, AE_SUPPORT otherwise
1292 *
1293 * DESCRIPTION: Match an interface string to the interfaces supported by the
1294 * host. Strings originate from an AML call to the _OSI method.
1295 *
1296 *****************************************************************************/
1297
1298acpi_status
1299acpi_os_validate_interface (char *interface)
1300{
1301 if (!strncmp(osi_additional_string, interface, OSI_STRING_LENGTH_MAX))
1302 return AE_OK;
1303 if (!strcmp("Linux", interface)) {
1304
1305 printk(KERN_NOTICE PREFIX
1306 "BIOS _OSI(Linux) query %s%s\n",
1307 osi_linux.enable ? "honored" : "ignored",
1308 osi_linux.cmdline ? " via cmdline" :
1309 osi_linux.dmi ? " via DMI" : "");
1310
1311 if (osi_linux.enable)
1312 return AE_OK;
1313 }
1314 return AE_SUPPORT;
1315}
1316
1317static inline int acpi_res_list_add(struct acpi_res_list *res) 1255static inline int acpi_res_list_add(struct acpi_res_list *res)
1318{ 1256{
1319 struct acpi_res_list *res_list_elem; 1257 struct acpi_res_list *res_list_elem;