diff options
| -rw-r--r-- | drivers/acpi/bus.c | 10 | ||||
| -rw-r--r-- | drivers/gpu/drm/nouveau/nouveau_acpi.c | 16 | ||||
| -rw-r--r-- | drivers/gpu/drm/radeon/radeon_atpx_handler.c | 16 | ||||
| -rw-r--r-- | drivers/pci/hotplug/acpiphp_glue.c | 26 | ||||
| -rw-r--r-- | include/acpi/acpi_bus.h | 4 |
5 files changed, 64 insertions, 8 deletions
diff --git a/drivers/acpi/bus.c b/drivers/acpi/bus.c index bba9b72e25f8..0710004055c8 100644 --- a/drivers/acpi/bus.c +++ b/drivers/acpi/bus.c | |||
| @@ -156,6 +156,16 @@ int acpi_bus_get_private_data(acpi_handle handle, void **data) | |||
| 156 | } | 156 | } |
| 157 | EXPORT_SYMBOL(acpi_bus_get_private_data); | 157 | EXPORT_SYMBOL(acpi_bus_get_private_data); |
| 158 | 158 | ||
| 159 | void acpi_bus_no_hotplug(acpi_handle handle) | ||
| 160 | { | ||
| 161 | struct acpi_device *adev = NULL; | ||
| 162 | |||
| 163 | acpi_bus_get_device(handle, &adev); | ||
| 164 | if (adev) | ||
| 165 | adev->flags.no_hotplug = true; | ||
| 166 | } | ||
| 167 | EXPORT_SYMBOL_GPL(acpi_bus_no_hotplug); | ||
| 168 | |||
| 159 | static void acpi_print_osc_error(acpi_handle handle, | 169 | static void acpi_print_osc_error(acpi_handle handle, |
| 160 | struct acpi_osc_context *context, char *error) | 170 | struct acpi_osc_context *context, char *error) |
| 161 | { | 171 | { |
diff --git a/drivers/gpu/drm/nouveau/nouveau_acpi.c b/drivers/gpu/drm/nouveau/nouveau_acpi.c index 95c740454049..ba0183fb84f3 100644 --- a/drivers/gpu/drm/nouveau/nouveau_acpi.c +++ b/drivers/gpu/drm/nouveau/nouveau_acpi.c | |||
| @@ -51,6 +51,7 @@ static struct nouveau_dsm_priv { | |||
| 51 | bool dsm_detected; | 51 | bool dsm_detected; |
| 52 | bool optimus_detected; | 52 | bool optimus_detected; |
| 53 | acpi_handle dhandle; | 53 | acpi_handle dhandle; |
| 54 | acpi_handle other_handle; | ||
| 54 | acpi_handle rom_handle; | 55 | acpi_handle rom_handle; |
| 55 | } nouveau_dsm_priv; | 56 | } nouveau_dsm_priv; |
| 56 | 57 | ||
| @@ -260,9 +261,10 @@ static int nouveau_dsm_pci_probe(struct pci_dev *pdev) | |||
| 260 | if (!dhandle) | 261 | if (!dhandle) |
| 261 | return false; | 262 | return false; |
| 262 | 263 | ||
| 263 | if (!acpi_has_method(dhandle, "_DSM")) | 264 | if (!acpi_has_method(dhandle, "_DSM")) { |
| 265 | nouveau_dsm_priv.other_handle = dhandle; | ||
| 264 | return false; | 266 | return false; |
| 265 | 267 | } | |
| 266 | if (nouveau_test_dsm(dhandle, nouveau_dsm, NOUVEAU_DSM_POWER)) | 268 | if (nouveau_test_dsm(dhandle, nouveau_dsm, NOUVEAU_DSM_POWER)) |
| 267 | retval |= NOUVEAU_DSM_HAS_MUX; | 269 | retval |= NOUVEAU_DSM_HAS_MUX; |
| 268 | 270 | ||
| @@ -338,6 +340,16 @@ static bool nouveau_dsm_detect(void) | |||
| 338 | printk(KERN_INFO "VGA switcheroo: detected DSM switching method %s handle\n", | 340 | printk(KERN_INFO "VGA switcheroo: detected DSM switching method %s handle\n", |
| 339 | acpi_method_name); | 341 | acpi_method_name); |
| 340 | nouveau_dsm_priv.dsm_detected = true; | 342 | nouveau_dsm_priv.dsm_detected = true; |
| 343 | /* | ||
| 344 | * On some systems hotplug events are generated for the device | ||
| 345 | * being switched off when _DSM is executed. They cause ACPI | ||
| 346 | * hotplug to trigger and attempt to remove the device from | ||
| 347 | * the system, which causes it to break down. Prevent that from | ||
| 348 | * happening by setting the no_hotplug flag for the involved | ||
| 349 | * ACPI device objects. | ||
| 350 | */ | ||
| 351 | acpi_bus_no_hotplug(nouveau_dsm_priv.dhandle); | ||
| 352 | acpi_bus_no_hotplug(nouveau_dsm_priv.other_handle); | ||
| 341 | ret = true; | 353 | ret = true; |
| 342 | } | 354 | } |
| 343 | 355 | ||
diff --git a/drivers/gpu/drm/radeon/radeon_atpx_handler.c b/drivers/gpu/drm/radeon/radeon_atpx_handler.c index 9d302eaeea15..485848f889f5 100644 --- a/drivers/gpu/drm/radeon/radeon_atpx_handler.c +++ b/drivers/gpu/drm/radeon/radeon_atpx_handler.c | |||
| @@ -33,6 +33,7 @@ static struct radeon_atpx_priv { | |||
| 33 | bool atpx_detected; | 33 | bool atpx_detected; |
| 34 | /* handle for device - and atpx */ | 34 | /* handle for device - and atpx */ |
| 35 | acpi_handle dhandle; | 35 | acpi_handle dhandle; |
| 36 | acpi_handle other_handle; | ||
| 36 | struct radeon_atpx atpx; | 37 | struct radeon_atpx atpx; |
| 37 | } radeon_atpx_priv; | 38 | } radeon_atpx_priv; |
| 38 | 39 | ||
| @@ -451,9 +452,10 @@ static bool radeon_atpx_pci_probe_handle(struct pci_dev *pdev) | |||
| 451 | return false; | 452 | return false; |
| 452 | 453 | ||
| 453 | status = acpi_get_handle(dhandle, "ATPX", &atpx_handle); | 454 | status = acpi_get_handle(dhandle, "ATPX", &atpx_handle); |
| 454 | if (ACPI_FAILURE(status)) | 455 | if (ACPI_FAILURE(status)) { |
| 456 | radeon_atpx_priv.other_handle = dhandle; | ||
| 455 | return false; | 457 | return false; |
| 456 | 458 | } | |
| 457 | radeon_atpx_priv.dhandle = dhandle; | 459 | radeon_atpx_priv.dhandle = dhandle; |
| 458 | radeon_atpx_priv.atpx.handle = atpx_handle; | 460 | radeon_atpx_priv.atpx.handle = atpx_handle; |
| 459 | return true; | 461 | return true; |
| @@ -530,6 +532,16 @@ static bool radeon_atpx_detect(void) | |||
| 530 | printk(KERN_INFO "VGA switcheroo: detected switching method %s handle\n", | 532 | printk(KERN_INFO "VGA switcheroo: detected switching method %s handle\n", |
| 531 | acpi_method_name); | 533 | acpi_method_name); |
| 532 | radeon_atpx_priv.atpx_detected = true; | 534 | radeon_atpx_priv.atpx_detected = true; |
| 535 | /* | ||
| 536 | * On some systems hotplug events are generated for the device | ||
| 537 | * being switched off when ATPX is executed. They cause ACPI | ||
| 538 | * hotplug to trigger and attempt to remove the device from | ||
| 539 | * the system, which causes it to break down. Prevent that from | ||
| 540 | * happening by setting the no_hotplug flag for the involved | ||
| 541 | * ACPI device objects. | ||
| 542 | */ | ||
| 543 | acpi_bus_no_hotplug(radeon_atpx_priv.dhandle); | ||
| 544 | acpi_bus_no_hotplug(radeon_atpx_priv.other_handle); | ||
| 533 | return true; | 545 | return true; |
| 534 | } | 546 | } |
| 535 | return false; | 547 | return false; |
diff --git a/drivers/pci/hotplug/acpiphp_glue.c b/drivers/pci/hotplug/acpiphp_glue.c index 438a4d09958b..e86439283a5d 100644 --- a/drivers/pci/hotplug/acpiphp_glue.c +++ b/drivers/pci/hotplug/acpiphp_glue.c | |||
| @@ -645,6 +645,24 @@ static void disable_slot(struct acpiphp_slot *slot) | |||
| 645 | slot->flags &= (~SLOT_ENABLED); | 645 | slot->flags &= (~SLOT_ENABLED); |
| 646 | } | 646 | } |
| 647 | 647 | ||
| 648 | static bool acpiphp_no_hotplug(acpi_handle handle) | ||
| 649 | { | ||
| 650 | struct acpi_device *adev = NULL; | ||
| 651 | |||
| 652 | acpi_bus_get_device(handle, &adev); | ||
| 653 | return adev && adev->flags.no_hotplug; | ||
| 654 | } | ||
| 655 | |||
| 656 | static bool slot_no_hotplug(struct acpiphp_slot *slot) | ||
| 657 | { | ||
| 658 | struct acpiphp_func *func; | ||
| 659 | |||
| 660 | list_for_each_entry(func, &slot->funcs, sibling) | ||
| 661 | if (acpiphp_no_hotplug(func_to_handle(func))) | ||
| 662 | return true; | ||
| 663 | |||
| 664 | return false; | ||
| 665 | } | ||
| 648 | 666 | ||
| 649 | /** | 667 | /** |
| 650 | * get_slot_status - get ACPI slot status | 668 | * get_slot_status - get ACPI slot status |
| @@ -703,7 +721,8 @@ static void trim_stale_devices(struct pci_dev *dev) | |||
| 703 | unsigned long long sta; | 721 | unsigned long long sta; |
| 704 | 722 | ||
| 705 | status = acpi_evaluate_integer(handle, "_STA", NULL, &sta); | 723 | status = acpi_evaluate_integer(handle, "_STA", NULL, &sta); |
| 706 | alive = ACPI_SUCCESS(status) && sta == ACPI_STA_ALL; | 724 | alive = (ACPI_SUCCESS(status) && sta == ACPI_STA_ALL) |
| 725 | || acpiphp_no_hotplug(handle); | ||
| 707 | } | 726 | } |
| 708 | if (!alive) { | 727 | if (!alive) { |
| 709 | u32 v; | 728 | u32 v; |
| @@ -743,8 +762,9 @@ static void acpiphp_check_bridge(struct acpiphp_bridge *bridge) | |||
| 743 | struct pci_dev *dev, *tmp; | 762 | struct pci_dev *dev, *tmp; |
| 744 | 763 | ||
| 745 | mutex_lock(&slot->crit_sect); | 764 | mutex_lock(&slot->crit_sect); |
| 746 | /* wake up all functions */ | 765 | if (slot_no_hotplug(slot)) { |
| 747 | if (get_slot_status(slot) == ACPI_STA_ALL) { | 766 | ; /* do nothing */ |
| 767 | } else if (get_slot_status(slot) == ACPI_STA_ALL) { | ||
| 748 | /* remove stale devices if any */ | 768 | /* remove stale devices if any */ |
| 749 | list_for_each_entry_safe(dev, tmp, &bus->devices, | 769 | list_for_each_entry_safe(dev, tmp, &bus->devices, |
| 750 | bus_list) | 770 | bus_list) |
diff --git a/include/acpi/acpi_bus.h b/include/acpi/acpi_bus.h index 7b2de026a4f3..ca49ebd231ca 100644 --- a/include/acpi/acpi_bus.h +++ b/include/acpi/acpi_bus.h | |||
| @@ -168,7 +168,8 @@ struct acpi_device_flags { | |||
| 168 | u32 ejectable:1; | 168 | u32 ejectable:1; |
| 169 | u32 power_manageable:1; | 169 | u32 power_manageable:1; |
| 170 | u32 match_driver:1; | 170 | u32 match_driver:1; |
| 171 | u32 reserved:27; | 171 | u32 no_hotplug:1; |
| 172 | u32 reserved:26; | ||
| 172 | }; | 173 | }; |
| 173 | 174 | ||
| 174 | /* File System */ | 175 | /* File System */ |
| @@ -343,6 +344,7 @@ extern struct kobject *acpi_kobj; | |||
| 343 | extern int acpi_bus_generate_netlink_event(const char*, const char*, u8, int); | 344 | extern int acpi_bus_generate_netlink_event(const char*, const char*, u8, int); |
| 344 | void acpi_bus_private_data_handler(acpi_handle, void *); | 345 | void acpi_bus_private_data_handler(acpi_handle, void *); |
| 345 | int acpi_bus_get_private_data(acpi_handle, void **); | 346 | int acpi_bus_get_private_data(acpi_handle, void **); |
| 347 | void acpi_bus_no_hotplug(acpi_handle handle); | ||
| 346 | extern int acpi_notifier_call_chain(struct acpi_device *, u32, u32); | 348 | extern int acpi_notifier_call_chain(struct acpi_device *, u32, u32); |
| 347 | extern int register_acpi_notifier(struct notifier_block *); | 349 | extern int register_acpi_notifier(struct notifier_block *); |
| 348 | extern int unregister_acpi_notifier(struct notifier_block *); | 350 | extern int unregister_acpi_notifier(struct notifier_block *); |
