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; |
