diff options
Diffstat (limited to 'drivers/acpi/osl.c')
-rw-r--r-- | drivers/acpi/osl.c | 162 |
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); | |||
96 | static DEFINE_SPINLOCK(acpi_res_lock); | 96 | static DEFINE_SPINLOCK(acpi_res_lock); |
97 | 97 | ||
98 | #define OSI_STRING_LENGTH_MAX 64 /* arbitrary */ | 98 | #define OSI_STRING_LENGTH_MAX 64 /* arbitrary */ |
99 | static char osi_additional_string[OSI_STRING_LENGTH_MAX]; | 99 | static char osi_setup_string[OSI_STRING_LENGTH_MAX]; |
100 | |||
101 | static 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 | ||
143 | static 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 | |||
141 | static void __init acpi_request_region (struct acpi_generic_address *addr, | 157 | static 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 | ||
548 | acpi_status | 566 | acpi_status |
549 | acpi_os_read_pci_configuration(struct acpi_pci_id * pci_id, u32 reg, | 567 | acpi_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 */ | ||
606 | static 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 | |||
663 | void 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 | |||
673 | static void acpi_os_execute_deferred(struct work_struct *work) | 625 | static 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 | */ |
1014 | int __init acpi_osi_setup(char *str) | 972 | static 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 | |||
992 | int __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 | |||
1298 | acpi_status | ||
1299 | acpi_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 | |||
1317 | static inline int acpi_res_list_add(struct acpi_res_list *res) | 1255 | static 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; |