Commit d1badf8d authored by Rafael J. Wysocki's avatar Rafael J. Wysocki

Merge branch 'acpi-pci-hotplug' into acpi-hotplug

Conflicts:
	include/acpi/acpi_bus.h
parents caa73ea1 f244d8b6
...@@ -149,6 +149,16 @@ int acpi_bus_get_private_data(acpi_handle handle, void **data) ...@@ -149,6 +149,16 @@ int acpi_bus_get_private_data(acpi_handle handle, void **data)
} }
EXPORT_SYMBOL(acpi_bus_get_private_data); EXPORT_SYMBOL(acpi_bus_get_private_data);
void acpi_bus_no_hotplug(acpi_handle handle)
{
struct acpi_device *adev = NULL;
acpi_bus_get_device(handle, &adev);
if (adev)
adev->flags.no_hotplug = true;
}
EXPORT_SYMBOL_GPL(acpi_bus_no_hotplug);
static void acpi_print_osc_error(acpi_handle handle, static void acpi_print_osc_error(acpi_handle handle,
struct acpi_osc_context *context, char *error) struct acpi_osc_context *context, char *error)
{ {
......
...@@ -46,6 +46,7 @@ static struct nouveau_dsm_priv { ...@@ -46,6 +46,7 @@ static struct nouveau_dsm_priv {
bool dsm_detected; bool dsm_detected;
bool optimus_detected; bool optimus_detected;
acpi_handle dhandle; acpi_handle dhandle;
acpi_handle other_handle;
acpi_handle rom_handle; acpi_handle rom_handle;
} nouveau_dsm_priv; } nouveau_dsm_priv;
...@@ -255,9 +256,10 @@ static int nouveau_dsm_pci_probe(struct pci_dev *pdev) ...@@ -255,9 +256,10 @@ static int nouveau_dsm_pci_probe(struct pci_dev *pdev)
if (!dhandle) if (!dhandle)
return false; return false;
if (!acpi_has_method(dhandle, "_DSM")) if (!acpi_has_method(dhandle, "_DSM")) {
nouveau_dsm_priv.other_handle = dhandle;
return false; return false;
}
if (nouveau_test_dsm(dhandle, nouveau_dsm, NOUVEAU_DSM_POWER)) if (nouveau_test_dsm(dhandle, nouveau_dsm, NOUVEAU_DSM_POWER))
retval |= NOUVEAU_DSM_HAS_MUX; retval |= NOUVEAU_DSM_HAS_MUX;
...@@ -333,6 +335,16 @@ static bool nouveau_dsm_detect(void) ...@@ -333,6 +335,16 @@ static bool nouveau_dsm_detect(void)
printk(KERN_INFO "VGA switcheroo: detected DSM switching method %s handle\n", printk(KERN_INFO "VGA switcheroo: detected DSM switching method %s handle\n",
acpi_method_name); acpi_method_name);
nouveau_dsm_priv.dsm_detected = true; nouveau_dsm_priv.dsm_detected = true;
/*
* On some systems hotplug events are generated for the device
* being switched off when _DSM is executed. They cause ACPI
* hotplug to trigger and attempt to remove the device from
* the system, which causes it to break down. Prevent that from
* happening by setting the no_hotplug flag for the involved
* ACPI device objects.
*/
acpi_bus_no_hotplug(nouveau_dsm_priv.dhandle);
acpi_bus_no_hotplug(nouveau_dsm_priv.other_handle);
ret = true; ret = true;
} }
......
...@@ -33,6 +33,7 @@ static struct radeon_atpx_priv { ...@@ -33,6 +33,7 @@ static struct radeon_atpx_priv {
bool atpx_detected; bool atpx_detected;
/* handle for device - and atpx */ /* handle for device - and atpx */
acpi_handle dhandle; acpi_handle dhandle;
acpi_handle other_handle;
struct radeon_atpx atpx; struct radeon_atpx atpx;
} radeon_atpx_priv; } radeon_atpx_priv;
...@@ -451,9 +452,10 @@ static bool radeon_atpx_pci_probe_handle(struct pci_dev *pdev) ...@@ -451,9 +452,10 @@ static bool radeon_atpx_pci_probe_handle(struct pci_dev *pdev)
return false; return false;
status = acpi_get_handle(dhandle, "ATPX", &atpx_handle); status = acpi_get_handle(dhandle, "ATPX", &atpx_handle);
if (ACPI_FAILURE(status)) if (ACPI_FAILURE(status)) {
radeon_atpx_priv.other_handle = dhandle;
return false; return false;
}
radeon_atpx_priv.dhandle = dhandle; radeon_atpx_priv.dhandle = dhandle;
radeon_atpx_priv.atpx.handle = atpx_handle; radeon_atpx_priv.atpx.handle = atpx_handle;
return true; return true;
...@@ -530,6 +532,16 @@ static bool radeon_atpx_detect(void) ...@@ -530,6 +532,16 @@ static bool radeon_atpx_detect(void)
printk(KERN_INFO "VGA switcheroo: detected switching method %s handle\n", printk(KERN_INFO "VGA switcheroo: detected switching method %s handle\n",
acpi_method_name); acpi_method_name);
radeon_atpx_priv.atpx_detected = true; radeon_atpx_priv.atpx_detected = true;
/*
* On some systems hotplug events are generated for the device
* being switched off when ATPX is executed. They cause ACPI
* hotplug to trigger and attempt to remove the device from
* the system, which causes it to break down. Prevent that from
* happening by setting the no_hotplug flag for the involved
* ACPI device objects.
*/
acpi_bus_no_hotplug(radeon_atpx_priv.dhandle);
acpi_bus_no_hotplug(radeon_atpx_priv.other_handle);
return true; return true;
} }
return false; return false;
......
...@@ -645,6 +645,24 @@ static void disable_slot(struct acpiphp_slot *slot) ...@@ -645,6 +645,24 @@ static void disable_slot(struct acpiphp_slot *slot)
slot->flags &= (~SLOT_ENABLED); slot->flags &= (~SLOT_ENABLED);
} }
static bool acpiphp_no_hotplug(acpi_handle handle)
{
struct acpi_device *adev = NULL;
acpi_bus_get_device(handle, &adev);
return adev && adev->flags.no_hotplug;
}
static bool slot_no_hotplug(struct acpiphp_slot *slot)
{
struct acpiphp_func *func;
list_for_each_entry(func, &slot->funcs, sibling)
if (acpiphp_no_hotplug(func_to_handle(func)))
return true;
return false;
}
/** /**
* get_slot_status - get ACPI slot status * get_slot_status - get ACPI slot status
...@@ -703,7 +721,8 @@ static void trim_stale_devices(struct pci_dev *dev) ...@@ -703,7 +721,8 @@ static void trim_stale_devices(struct pci_dev *dev)
unsigned long long sta; unsigned long long sta;
status = acpi_evaluate_integer(handle, "_STA", NULL, &sta); status = acpi_evaluate_integer(handle, "_STA", NULL, &sta);
alive = ACPI_SUCCESS(status) && sta == ACPI_STA_ALL; alive = (ACPI_SUCCESS(status) && sta == ACPI_STA_ALL)
|| acpiphp_no_hotplug(handle);
} }
if (!alive) { if (!alive) {
u32 v; u32 v;
...@@ -743,8 +762,9 @@ static void acpiphp_check_bridge(struct acpiphp_bridge *bridge) ...@@ -743,8 +762,9 @@ static void acpiphp_check_bridge(struct acpiphp_bridge *bridge)
struct pci_dev *dev, *tmp; struct pci_dev *dev, *tmp;
mutex_lock(&slot->crit_sect); mutex_lock(&slot->crit_sect);
/* wake up all functions */ if (slot_no_hotplug(slot)) {
if (get_slot_status(slot) == ACPI_STA_ALL) { ; /* do nothing */
} else if (get_slot_status(slot) == ACPI_STA_ALL) {
/* remove stale devices if any */ /* remove stale devices if any */
list_for_each_entry_safe(dev, tmp, &bus->devices, list_for_each_entry_safe(dev, tmp, &bus->devices,
bus_list) bus_list)
......
...@@ -163,7 +163,8 @@ struct acpi_device_flags { ...@@ -163,7 +163,8 @@ struct acpi_device_flags {
u32 match_driver:1; u32 match_driver:1;
u32 initialized:1; u32 initialized:1;
u32 visited:1; u32 visited:1;
u32 reserved:25; u32 no_hotplug:1;
u32 reserved:24;
}; };
/* File System */ /* File System */
...@@ -344,6 +345,7 @@ extern struct kobject *acpi_kobj; ...@@ -344,6 +345,7 @@ extern struct kobject *acpi_kobj;
extern int acpi_bus_generate_netlink_event(const char*, const char*, u8, int); extern int acpi_bus_generate_netlink_event(const char*, const char*, u8, int);
void acpi_bus_private_data_handler(acpi_handle, void *); void acpi_bus_private_data_handler(acpi_handle, void *);
int acpi_bus_get_private_data(acpi_handle, void **); int acpi_bus_get_private_data(acpi_handle, void **);
void acpi_bus_no_hotplug(acpi_handle handle);
extern int acpi_notifier_call_chain(struct acpi_device *, u32, u32); extern int acpi_notifier_call_chain(struct acpi_device *, u32, u32);
extern int register_acpi_notifier(struct notifier_block *); extern int register_acpi_notifier(struct notifier_block *);
extern int unregister_acpi_notifier(struct notifier_block *); extern int unregister_acpi_notifier(struct notifier_block *);
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment