forked from Minki/linux
ACPI and power management fixes and new device IDs for 3.13-rc7
- VGA switcheroo was broken for some users as a result of the ACPI-based PCI hotplug (ACPIPHP) changes in 3.12, because some previously ignored hotplug events started to be handled. The fix causes them to be ignored again. - There are two more issues related to cpufreq's suspend/resume handling changes from the 3.12 cycle addressed by Viresh Kumar's fixes. - intel_pstate triggers a divide error in a timer function if the P-state information it needs is missing during initialization. This leads to kernel panics on nested KVM clients and is fixed by failing the initialization cleanly in those cases. - PCI initalization code changes during the 3.9 cycle uncovered BIOS issues related to ACPI wakeup notifications (some BIOSes send them for devices that aren't supposed to support ACPI wakeup). Work around them by installing an ACPI wakeup notify handler for all PCI devices with ACPI support. - The Calxeda cpuilde driver's probe function is tagged as __init, which is incorrect and causes a section mismatch to occur during build. Fix from Andre Przywara removes the __init tag from there. - During the 3.12 cycle ACPIPHP started to print warnings about missing _ADR for devices that legitimately don't have it. Fix from Toshi Kani makes it only print the warnings where they make sense. / -----BEGIN PGP SIGNATURE----- Version: GnuPG v2.0.19 (GNU/Linux) iQIcBAABCAAGBQJSxrJgAAoJEILEb/54YlRxRPkP/ifzrrVhdzqXIEy44b93JeDx oSmZW6yTO51GZlDx2bjt6CGJcIUDC4ExYV6S2tB44/DL19CYdIxi7oBaXtUvzGRs oZ6B1wfvKOIxZ0RQguaGd1uerQU304CGwUXu/jpRZ/UuZZFKq5Uts6O3bilGzCfR Y+MUH+qECwdBXaFHUISdWFsa3lxj0U0kglszh+DsxwS4gy/pLbCu5fKLgHLuNNQC hhEEToQ6uF4o8hbkGJvgUPo3V3aUSXObgvJh4ntP09YE1AEJScLB4wKmqL0zN8Qj pbBf1WC5OpGXv8zGM9ErrY64YaKA36uhJvOi6RtBGLbG+pYM6E6IM9zNf4Ku+T79 JNEulpq27aEx2JghNSgMFYQZEOGTH+q24iXZdZlOIvqWpMymATlqP/gAQQIpg3VC OIIdocMFRsbgwFXf41uyUqs458fg5xREz5k6geWZeyriM45wFShR+JnMopQWc5OB a3sbcWUShFBL1T0pqYR4SDLDvH4NdEP2NKO2jlqMXUewLXsVRRt/42etGoe0rI3C cMWPQq7z0GNN+NboUviqwHdxUKqONWGt+pd/3u8FI/Y1IlXEeXQYGawhSu81uCpT 5gLaKDkwOrCSwOw68Msuod0Cce6TnoTowi6hP2aAEu8mDJwQY+toqA3+CPoO8nty DdhZjP1afEgsVVyjErX4 =LXh0 -----END PGP SIGNATURE----- Merge tag 'pm+acpi-3.13-rc7' of git://git.kernel.org/pub/scm/linux/kernel/git/rafael/linux-pm Pull ACPI and PM fixes and new device IDs from Rafael Wysocki: "These commits, except for one, are regression fixes and the remaining one fixes a divide error leading to a kernel panic. The majority of the regressions fixed here were introduced during the 3.12 cycle, one of them is from this cycle and one is older. Specifics: - VGA switcheroo was broken for some users as a result of the ACPI-based PCI hotplug (ACPIPHP) changes in 3.12, because some previously ignored hotplug events started to be handled. The fix causes them to be ignored again. - There are two more issues related to cpufreq's suspend/resume handling changes from the 3.12 cycle addressed by Viresh Kumar's fixes. - intel_pstate triggers a divide error in a timer function if the P-state information it needs is missing during initialization. This leads to kernel panics on nested KVM clients and is fixed by failing the initialization cleanly in those cases. - PCI initalization code changes during the 3.9 cycle uncovered BIOS issues related to ACPI wakeup notifications (some BIOSes send them for devices that aren't supposed to support ACPI wakeup). Work around them by installing an ACPI wakeup notify handler for all PCI devices with ACPI support. - The Calxeda cpuilde driver's probe function is tagged as __init, which is incorrect and causes a section mismatch to occur during build. Fix from Andre Przywara removes the __init tag from there. - During the 3.12 cycle ACPIPHP started to print warnings about missing _ADR for devices that legitimately don't have it. Fix from Toshi Kani makes it only print the warnings where they make sense" * tag 'pm+acpi-3.13-rc7' of git://git.kernel.org/pub/scm/linux/kernel/git/rafael/linux-pm: ACPIPHP / radeon / nouveau: Fix VGA switcheroo problem related to hotplug intel_pstate: Fail initialization if P-state information is missing ARM/cpuidle: remove __init tag from Calxeda cpuidle probe function PCI / ACPI: Install wakeup notify handlers for all PCI devs with ACPI cpufreq: preserve user_policy across suspend/resume cpufreq: Clean up after a failing light-weight initialization ACPI / PCI / hotplug: Avoid warning when _ADR not present
This commit is contained in:
commit
23e8e5901d
@ -156,6 +156,16 @@ int acpi_bus_get_private_data(acpi_handle handle, void **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,
|
||||
struct acpi_osc_context *context, char *error)
|
||||
{
|
||||
|
@ -839,9 +839,6 @@ static void cpufreq_init_policy(struct cpufreq_policy *policy)
|
||||
|
||||
/* set default policy */
|
||||
ret = cpufreq_set_policy(policy, &new_policy);
|
||||
policy->user_policy.policy = policy->policy;
|
||||
policy->user_policy.governor = policy->governor;
|
||||
|
||||
if (ret) {
|
||||
pr_debug("setting policy failed\n");
|
||||
if (cpufreq_driver->exit)
|
||||
@ -1016,15 +1013,17 @@ static int __cpufreq_add_dev(struct device *dev, struct subsys_interface *sif,
|
||||
read_unlock_irqrestore(&cpufreq_driver_lock, flags);
|
||||
#endif
|
||||
|
||||
if (frozen)
|
||||
/* Restore the saved policy when doing light-weight init */
|
||||
policy = cpufreq_policy_restore(cpu);
|
||||
else
|
||||
/*
|
||||
* Restore the saved policy when doing light-weight init and fall back
|
||||
* to the full init if that fails.
|
||||
*/
|
||||
policy = frozen ? cpufreq_policy_restore(cpu) : NULL;
|
||||
if (!policy) {
|
||||
frozen = false;
|
||||
policy = cpufreq_policy_alloc();
|
||||
|
||||
if (!policy)
|
||||
goto nomem_out;
|
||||
|
||||
if (!policy)
|
||||
goto nomem_out;
|
||||
}
|
||||
|
||||
/*
|
||||
* In the resume path, since we restore a saved policy, the assignment
|
||||
@ -1069,8 +1068,10 @@ static int __cpufreq_add_dev(struct device *dev, struct subsys_interface *sif,
|
||||
*/
|
||||
cpumask_and(policy->cpus, policy->cpus, cpu_online_mask);
|
||||
|
||||
policy->user_policy.min = policy->min;
|
||||
policy->user_policy.max = policy->max;
|
||||
if (!frozen) {
|
||||
policy->user_policy.min = policy->min;
|
||||
policy->user_policy.max = policy->max;
|
||||
}
|
||||
|
||||
blocking_notifier_call_chain(&cpufreq_policy_notifier_list,
|
||||
CPUFREQ_START, policy);
|
||||
@ -1101,6 +1102,11 @@ static int __cpufreq_add_dev(struct device *dev, struct subsys_interface *sif,
|
||||
|
||||
cpufreq_init_policy(policy);
|
||||
|
||||
if (!frozen) {
|
||||
policy->user_policy.policy = policy->policy;
|
||||
policy->user_policy.governor = policy->governor;
|
||||
}
|
||||
|
||||
kobject_uevent(&policy->kobj, KOBJ_ADD);
|
||||
up_read(&cpufreq_rwsem);
|
||||
|
||||
@ -1118,8 +1124,11 @@ err_get_freq:
|
||||
if (cpufreq_driver->exit)
|
||||
cpufreq_driver->exit(policy);
|
||||
err_set_policy_cpu:
|
||||
if (frozen)
|
||||
if (frozen) {
|
||||
/* Do not leave stale fallback data behind. */
|
||||
per_cpu(cpufreq_cpu_data_fallback, cpu) = NULL;
|
||||
cpufreq_policy_put_kobj(policy);
|
||||
}
|
||||
cpufreq_policy_free(policy);
|
||||
|
||||
nomem_out:
|
||||
|
@ -614,6 +614,11 @@ static int intel_pstate_init_cpu(unsigned int cpunum)
|
||||
cpu = all_cpu_data[cpunum];
|
||||
|
||||
intel_pstate_get_cpu_pstates(cpu);
|
||||
if (!cpu->pstate.current_pstate) {
|
||||
all_cpu_data[cpunum] = NULL;
|
||||
kfree(cpu);
|
||||
return -ENODATA;
|
||||
}
|
||||
|
||||
cpu->cpu = cpunum;
|
||||
|
||||
|
@ -65,7 +65,7 @@ static struct cpuidle_driver calxeda_idle_driver = {
|
||||
.state_count = 2,
|
||||
};
|
||||
|
||||
static int __init calxeda_cpuidle_probe(struct platform_device *pdev)
|
||||
static int calxeda_cpuidle_probe(struct platform_device *pdev)
|
||||
{
|
||||
return cpuidle_register(&calxeda_idle_driver, NULL);
|
||||
}
|
||||
|
@ -51,6 +51,7 @@ static struct nouveau_dsm_priv {
|
||||
bool dsm_detected;
|
||||
bool optimus_detected;
|
||||
acpi_handle dhandle;
|
||||
acpi_handle other_handle;
|
||||
acpi_handle rom_handle;
|
||||
} nouveau_dsm_priv;
|
||||
|
||||
@ -260,9 +261,10 @@ static int nouveau_dsm_pci_probe(struct pci_dev *pdev)
|
||||
if (!dhandle)
|
||||
return false;
|
||||
|
||||
if (!acpi_has_method(dhandle, "_DSM"))
|
||||
if (!acpi_has_method(dhandle, "_DSM")) {
|
||||
nouveau_dsm_priv.other_handle = dhandle;
|
||||
return false;
|
||||
|
||||
}
|
||||
if (nouveau_test_dsm(dhandle, nouveau_dsm, NOUVEAU_DSM_POWER))
|
||||
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",
|
||||
acpi_method_name);
|
||||
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;
|
||||
}
|
||||
|
||||
|
@ -33,6 +33,7 @@ static struct radeon_atpx_priv {
|
||||
bool atpx_detected;
|
||||
/* handle for device - and atpx */
|
||||
acpi_handle dhandle;
|
||||
acpi_handle other_handle;
|
||||
struct radeon_atpx atpx;
|
||||
} radeon_atpx_priv;
|
||||
|
||||
@ -451,9 +452,10 @@ static bool radeon_atpx_pci_probe_handle(struct pci_dev *pdev)
|
||||
return false;
|
||||
|
||||
status = acpi_get_handle(dhandle, "ATPX", &atpx_handle);
|
||||
if (ACPI_FAILURE(status))
|
||||
if (ACPI_FAILURE(status)) {
|
||||
radeon_atpx_priv.other_handle = dhandle;
|
||||
return false;
|
||||
|
||||
}
|
||||
radeon_atpx_priv.dhandle = dhandle;
|
||||
radeon_atpx_priv.atpx.handle = atpx_handle;
|
||||
return true;
|
||||
@ -530,6 +532,16 @@ static bool radeon_atpx_detect(void)
|
||||
printk(KERN_INFO "VGA switcheroo: detected switching method %s handle\n",
|
||||
acpi_method_name);
|
||||
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 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);
|
||||
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;
|
||||
}
|
||||
|
||||
@ -643,6 +645,24 @@ static void disable_slot(struct acpiphp_slot *slot)
|
||||
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
|
||||
@ -701,7 +721,8 @@ static void trim_stale_devices(struct pci_dev *dev)
|
||||
unsigned long long 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) {
|
||||
u32 v;
|
||||
@ -741,8 +762,9 @@ static void acpiphp_check_bridge(struct acpiphp_bridge *bridge)
|
||||
struct pci_dev *dev, *tmp;
|
||||
|
||||
mutex_lock(&slot->crit_sect);
|
||||
/* wake up all functions */
|
||||
if (get_slot_status(slot) == ACPI_STA_ALL) {
|
||||
if (slot_no_hotplug(slot)) {
|
||||
; /* do nothing */
|
||||
} else if (get_slot_status(slot) == ACPI_STA_ALL) {
|
||||
/* remove stale devices if any */
|
||||
list_for_each_entry_safe(dev, tmp, &bus->devices,
|
||||
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)
|
||||
{
|
||||
struct pci_dev *pci_dev = to_pci_dev(dev);
|
||||
acpi_handle handle = ACPI_HANDLE(dev);
|
||||
struct acpi_device *adev;
|
||||
struct acpi_device *adev = ACPI_COMPANION(dev);
|
||||
|
||||
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;
|
||||
|
||||
device_set_wakeup_capable(dev, true);
|
||||
acpi_pci_sleep_wake(pci_dev, false);
|
||||
|
||||
pci_acpi_add_pm_notifier(adev, pci_dev);
|
||||
if (adev->wakeup.flags.run_wake)
|
||||
device_set_run_wake(dev, true);
|
||||
}
|
||||
|
||||
static void pci_acpi_cleanup(struct device *dev)
|
||||
{
|
||||
acpi_handle handle = ACPI_HANDLE(dev);
|
||||
struct acpi_device *adev;
|
||||
struct acpi_device *adev = ACPI_COMPANION(dev);
|
||||
|
||||
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_run_wake(dev, false);
|
||||
pci_acpi_remove_pm_notifier(adev);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -169,7 +169,8 @@ struct acpi_device_flags {
|
||||
u32 ejectable:1;
|
||||
u32 power_manageable:1;
|
||||
u32 match_driver:1;
|
||||
u32 reserved:27;
|
||||
u32 no_hotplug:1;
|
||||
u32 reserved:26;
|
||||
};
|
||||
|
||||
/* File System */
|
||||
@ -344,6 +345,7 @@ extern struct kobject *acpi_kobj;
|
||||
extern int acpi_bus_generate_netlink_event(const char*, const char*, u8, int);
|
||||
void acpi_bus_private_data_handler(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 register_acpi_notifier(struct notifier_block *);
|
||||
extern int unregister_acpi_notifier(struct notifier_block *);
|
||||
|
Loading…
Reference in New Issue
Block a user