Merge branches 'acpi-pci-pm' and 'acpi-pci-hotplug'
* acpi-pci-pm: PCI / ACPI: Install wakeup notify handlers for all PCI devs with ACPI * acpi-pci-hotplug: ACPIPHP / radeon / nouveau: Fix VGA switcheroo problem related to hotplug ACPI / PCI / hotplug: Avoid warning when _ADR not present
This commit is contained in:
commit
4706515a92
6 changed files with 79 additions and 18 deletions
|
@ -156,6 +156,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)
|
||||||
{
|
{
|
||||||
|
|
|
@ -51,6 +51,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;
|
||||||
|
|
||||||
|
@ -260,9 +261,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;
|
||||||
|
|
||||||
|
@ -338,6 +340,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 {
|
||||||
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)
|
||||||
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)
|
||||||
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;
|
||||||
|
|
|
@ -279,7 +279,9 @@ static acpi_status register_slot(acpi_handle handle, u32 lvl, void *data,
|
||||||
|
|
||||||
status = acpi_evaluate_integer(handle, "_ADR", NULL, &adr);
|
status = acpi_evaluate_integer(handle, "_ADR", NULL, &adr);
|
||||||
if (ACPI_FAILURE(status)) {
|
if (ACPI_FAILURE(status)) {
|
||||||
acpi_handle_warn(handle, "can't evaluate _ADR (%#x)\n", status);
|
if (status != AE_NOT_FOUND)
|
||||||
|
acpi_handle_warn(handle,
|
||||||
|
"can't evaluate _ADR (%#x)\n", status);
|
||||||
return AE_OK;
|
return AE_OK;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -643,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
|
||||||
|
@ -701,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;
|
||||||
|
@ -741,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)
|
||||||
|
|
|
@ -330,29 +330,32 @@ static int acpi_pci_find_device(struct device *dev, acpi_handle *handle)
|
||||||
static void pci_acpi_setup(struct device *dev)
|
static void pci_acpi_setup(struct device *dev)
|
||||||
{
|
{
|
||||||
struct pci_dev *pci_dev = to_pci_dev(dev);
|
struct pci_dev *pci_dev = to_pci_dev(dev);
|
||||||
acpi_handle handle = ACPI_HANDLE(dev);
|
struct acpi_device *adev = ACPI_COMPANION(dev);
|
||||||
struct acpi_device *adev;
|
|
||||||
|
|
||||||
if (acpi_bus_get_device(handle, &adev) || !adev->wakeup.flags.valid)
|
if (!adev)
|
||||||
|
return;
|
||||||
|
|
||||||
|
pci_acpi_add_pm_notifier(adev, pci_dev);
|
||||||
|
if (!adev->wakeup.flags.valid)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
device_set_wakeup_capable(dev, true);
|
device_set_wakeup_capable(dev, true);
|
||||||
acpi_pci_sleep_wake(pci_dev, false);
|
acpi_pci_sleep_wake(pci_dev, false);
|
||||||
|
|
||||||
pci_acpi_add_pm_notifier(adev, pci_dev);
|
|
||||||
if (adev->wakeup.flags.run_wake)
|
if (adev->wakeup.flags.run_wake)
|
||||||
device_set_run_wake(dev, true);
|
device_set_run_wake(dev, true);
|
||||||
}
|
}
|
||||||
|
|
||||||
static void pci_acpi_cleanup(struct device *dev)
|
static void pci_acpi_cleanup(struct device *dev)
|
||||||
{
|
{
|
||||||
acpi_handle handle = ACPI_HANDLE(dev);
|
struct acpi_device *adev = ACPI_COMPANION(dev);
|
||||||
struct acpi_device *adev;
|
|
||||||
|
|
||||||
if (!acpi_bus_get_device(handle, &adev) && adev->wakeup.flags.valid) {
|
if (!adev)
|
||||||
|
return;
|
||||||
|
|
||||||
|
pci_acpi_remove_pm_notifier(adev);
|
||||||
|
if (adev->wakeup.flags.valid) {
|
||||||
device_set_wakeup_capable(dev, false);
|
device_set_wakeup_capable(dev, false);
|
||||||
device_set_run_wake(dev, false);
|
device_set_run_wake(dev, false);
|
||||||
pci_acpi_remove_pm_notifier(adev);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -169,7 +169,8 @@ struct acpi_device_flags {
|
||||||
u32 ejectable:1;
|
u32 ejectable:1;
|
||||||
u32 power_manageable:1;
|
u32 power_manageable:1;
|
||||||
u32 match_driver:1;
|
u32 match_driver:1;
|
||||||
u32 reserved:27;
|
u32 no_hotplug:1;
|
||||||
|
u32 reserved:26;
|
||||||
};
|
};
|
||||||
|
|
||||||
/* File System */
|
/* File System */
|
||||||
|
@ -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 *);
|
||||||
|
|
Loading…
Add table
Reference in a new issue