Power management fixes for v4.13-rc1
- Avoid clearing the PCI PME Enable bit for devices as a result of config space restoration which confuses AML executed afterward and causes wakeup events to be lost on some systems (Rafael Wysocki). - Fix the native PCIe PME interrupts handling in the cases when the PME IRQ is set up as a system wakeup one so that runtime PM remote wakeup works as expected after system resume on systems where that happens (Rafael Wysocki). - Fix the device PM QoS sysfs interface to handle invalid user input correctly instead of using an unititialized variable value as the latency tolerance for the device at hand (Dan Carpenter). - Get rid of one more rounding error from intel_pstate computations (Srinivas Pandruvada). - Fix the schedutil cpufreq governor to prevent it from possibly accessing unititialized data structures from governor callbacks in some cases on systems when multiple CPUs share a single cpufreq policy object (Vikram Mulukutla). - Fix the return values of probe routines in two devfreq drivers (Gustavo Silva). - Constify an attribute_group structure in devfreq (Arvind Yadav). -----BEGIN PGP SIGNATURE----- Version: GnuPG v2 iQIcBAABCAAGBQJZaLe2AAoJEILEb/54YlRxbi8P/jbQkFdtZinL8eR5DNlUt9jn ZzOnPNNJL0xj2dRJ8qpmHYT1PAQQGIhWyiXavbJqLeZeO5f4AFnFa8Uya+oq6UfP rv73RIk+qaogUccdqfa7Y3IcBhuER9q2baSIguLEt4w7+szyiWO+XonK640iTRNz moUcf2MCA9EacvwlmANQbnimB7mvwz4Tupgn6zK6zh2BJEBYlkWRbqXE1Zm6tJXb +jYwKY0W/hsJbLAUfhbz0Iz6FhvE/ix46NTRw33gWyjmmsUSn4KvIF6mq1+RplD9 6Rvka6pilqSIWoy3Wr4irAQkaOA8WecvwKGtmTh6mkfQC8TyNbQEHwD0EBSsht9n G1OHaWLv7m8PKaxmaLMvQEd8gYWmKAF3EZHA6zT2qN+LCPkMKzab/dEhsU/rxuR2 Nda57D5iNsGIETfVws9FBeYKOw64gb6TOQi8bunLPQbg15n4XWuL5IjtgnPwHFcU xkaxE5UbAmSLIDM8drevIQGIgrEsDDCgezvnVBV8vCYwUyBbzuBb+T6jibPMdNDM t0DiF8QwQEGJcxYXEd5FpPamS3rmeKxcf234kzf9lHq0Msq6lMFdhihoJvZJ6rw/ F18ZkAT3ni546CRmknJrUmeg7FjwHsTgJo7K7MArIcHBLhsA59+Bv2Mh+UIH//yT 57c1OquHgPXx1uTULMC3 =G9eQ -----END PGP SIGNATURE----- Merge tag 'pm-fixes-4.13-rc1' of git://git.kernel.org/pub/scm/linux/kernel/git/rafael/linux-pm Pull power management fixes from Rafael Wysocki: "These fix a recently exposed issue in the PCI device wakeup code and one older problem related to PCI device wakeup that has been reported recently, modify one more piece of computations in intel_pstate to get rid of a rounding error, fix a possible race in the schedutil cpufreq governor, fix the device PM QoS sysfs interface to correctly handle invalid user input, fix return values of two probe routines in devfreq drivers and constify an attribute_group structure in devfreq. Specifics: - Avoid clearing the PCI PME Enable bit for devices as a result of config space restoration which confuses AML executed afterward and causes wakeup events to be lost on some systems (Rafael Wysocki). - Fix the native PCIe PME interrupts handling in the cases when the PME IRQ is set up as a system wakeup one so that runtime PM remote wakeup works as expected after system resume on systems where that happens (Rafael Wysocki). - Fix the device PM QoS sysfs interface to handle invalid user input correctly instead of using an unititialized variable value as the latency tolerance for the device at hand (Dan Carpenter). - Get rid of one more rounding error from intel_pstate computations (Srinivas Pandruvada). - Fix the schedutil cpufreq governor to prevent it from possibly accessing unititialized data structures from governor callbacks in some cases on systems when multiple CPUs share a single cpufreq policy object (Vikram Mulukutla). - Fix the return values of probe routines in two devfreq drivers (Gustavo Silva). - Constify an attribute_group structure in devfreq (Arvind Yadav)" * tag 'pm-fixes-4.13-rc1' of git://git.kernel.org/pub/scm/linux/kernel/git/rafael/linux-pm: PCI / PM: Fix native PME handling during system suspend/resume PCI / PM: Restore PME Enable after config space restoration cpufreq: schedutil: Fix sugov_start() versus sugov_update_shared() race PM / QoS: return -EINVAL for bogus strings cpufreq: intel_pstate: Fix ratio setting for min_perf_pct PM / devfreq: constify attribute_group structures. PM / devfreq: tegra: fix error return code in tegra_devfreq_probe() PM / devfreq: rk3399_dmc: fix error return code in rk3399_dmcfreq_probe()
This commit is contained in:
commit
e37720e25d
|
@ -272,6 +272,8 @@ static ssize_t pm_qos_latency_tolerance_store(struct device *dev,
|
|||
value = PM_QOS_LATENCY_TOLERANCE_NO_CONSTRAINT;
|
||||
else if (!strcmp(buf, "any") || !strcmp(buf, "any\n"))
|
||||
value = PM_QOS_LATENCY_ANY;
|
||||
else
|
||||
return -EINVAL;
|
||||
}
|
||||
ret = dev_pm_qos_update_user_latency_tolerance(dev, value);
|
||||
return ret < 0 ? ret : n;
|
||||
|
|
|
@ -572,7 +572,7 @@ static int min_perf_pct_min(void)
|
|||
int turbo_pstate = cpu->pstate.turbo_pstate;
|
||||
|
||||
return turbo_pstate ?
|
||||
DIV_ROUND_UP(cpu->pstate.min_pstate * 100, turbo_pstate) : 0;
|
||||
(cpu->pstate.min_pstate * 100 / turbo_pstate) : 0;
|
||||
}
|
||||
|
||||
static s16 intel_pstate_get_epb(struct cpudata *cpu_data)
|
||||
|
|
|
@ -86,7 +86,7 @@ static struct attribute *dev_entries[] = {
|
|||
&dev_attr_set_freq.attr,
|
||||
NULL,
|
||||
};
|
||||
static struct attribute_group dev_attr_group = {
|
||||
static const struct attribute_group dev_attr_group = {
|
||||
.name = "userspace",
|
||||
.attrs = dev_entries,
|
||||
};
|
||||
|
|
|
@ -336,8 +336,9 @@ static int rk3399_dmcfreq_probe(struct platform_device *pdev)
|
|||
|
||||
irq = platform_get_irq(pdev, 0);
|
||||
if (irq < 0) {
|
||||
dev_err(&pdev->dev, "Cannot get the dmc interrupt resource\n");
|
||||
return -EINVAL;
|
||||
dev_err(&pdev->dev,
|
||||
"Cannot get the dmc interrupt resource: %d\n", irq);
|
||||
return irq;
|
||||
}
|
||||
data = devm_kzalloc(dev, sizeof(struct rk3399_dmcfreq), GFP_KERNEL);
|
||||
if (!data)
|
||||
|
|
|
@ -688,9 +688,9 @@ static int tegra_devfreq_probe(struct platform_device *pdev)
|
|||
}
|
||||
|
||||
irq = platform_get_irq(pdev, 0);
|
||||
if (irq <= 0) {
|
||||
dev_err(&pdev->dev, "Failed to get IRQ\n");
|
||||
return -ENODEV;
|
||||
if (irq < 0) {
|
||||
dev_err(&pdev->dev, "Failed to get IRQ: %d\n", irq);
|
||||
return irq;
|
||||
}
|
||||
|
||||
platform_set_drvdata(pdev, tegra);
|
||||
|
|
|
@ -511,6 +511,7 @@ static int pci_restore_standard_config(struct pci_dev *pci_dev)
|
|||
}
|
||||
|
||||
pci_restore_state(pci_dev);
|
||||
pci_pme_restore(pci_dev);
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
@ -522,6 +523,7 @@ static void pci_pm_default_resume_early(struct pci_dev *pci_dev)
|
|||
{
|
||||
pci_power_up(pci_dev);
|
||||
pci_restore_state(pci_dev);
|
||||
pci_pme_restore(pci_dev);
|
||||
pci_fixup_device(pci_fixup_resume_early, pci_dev);
|
||||
}
|
||||
|
||||
|
|
|
@ -1801,7 +1801,11 @@ static void __pci_pme_active(struct pci_dev *dev, bool enable)
|
|||
pci_write_config_word(dev, dev->pm_cap + PCI_PM_CTRL, pmcsr);
|
||||
}
|
||||
|
||||
static void pci_pme_restore(struct pci_dev *dev)
|
||||
/**
|
||||
* pci_pme_restore - Restore PME configuration after config space restore.
|
||||
* @dev: PCI device to update.
|
||||
*/
|
||||
void pci_pme_restore(struct pci_dev *dev)
|
||||
{
|
||||
u16 pmcsr;
|
||||
|
||||
|
@ -1811,6 +1815,7 @@ static void pci_pme_restore(struct pci_dev *dev)
|
|||
pci_read_config_word(dev, dev->pm_cap + PCI_PM_CTRL, &pmcsr);
|
||||
if (dev->wakeup_prepared) {
|
||||
pmcsr |= PCI_PM_CTRL_PME_ENABLE;
|
||||
pmcsr &= ~PCI_PM_CTRL_PME_STATUS;
|
||||
} else {
|
||||
pmcsr &= ~PCI_PM_CTRL_PME_ENABLE;
|
||||
pmcsr |= PCI_PM_CTRL_PME_STATUS;
|
||||
|
@ -1907,14 +1912,9 @@ int pci_enable_wake(struct pci_dev *dev, pci_power_t state, bool enable)
|
|||
{
|
||||
int ret = 0;
|
||||
|
||||
/*
|
||||
* Don't do the same thing twice in a row for one device, but restore
|
||||
* PME Enable in case it has been updated by config space restoration.
|
||||
*/
|
||||
if (!!enable == !!dev->wakeup_prepared) {
|
||||
pci_pme_restore(dev);
|
||||
/* Don't do the same thing twice in a row for one device. */
|
||||
if (!!enable == !!dev->wakeup_prepared)
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
* According to "PCI System Architecture" 4th ed. by Tom Shanley & Don
|
||||
|
|
|
@ -71,6 +71,7 @@ void pci_power_up(struct pci_dev *dev);
|
|||
void pci_disable_enabled_device(struct pci_dev *dev);
|
||||
int pci_finish_runtime_suspend(struct pci_dev *dev);
|
||||
int __pci_pme_wakeup(struct pci_dev *dev, void *ign);
|
||||
void pci_pme_restore(struct pci_dev *dev);
|
||||
bool pci_dev_keep_suspended(struct pci_dev *dev);
|
||||
void pci_dev_complete_resume(struct pci_dev *pci_dev);
|
||||
void pci_config_pm_runtime_get(struct pci_dev *dev);
|
||||
|
|
|
@ -40,17 +40,11 @@ static int __init pcie_pme_setup(char *str)
|
|||
}
|
||||
__setup("pcie_pme=", pcie_pme_setup);
|
||||
|
||||
enum pme_suspend_level {
|
||||
PME_SUSPEND_NONE = 0,
|
||||
PME_SUSPEND_WAKEUP,
|
||||
PME_SUSPEND_NOIRQ,
|
||||
};
|
||||
|
||||
struct pcie_pme_service_data {
|
||||
spinlock_t lock;
|
||||
struct pcie_device *srv;
|
||||
struct work_struct work;
|
||||
enum pme_suspend_level suspend_level;
|
||||
bool noirq; /* If set, keep the PME interrupt disabled. */
|
||||
};
|
||||
|
||||
/**
|
||||
|
@ -228,7 +222,7 @@ static void pcie_pme_work_fn(struct work_struct *work)
|
|||
spin_lock_irq(&data->lock);
|
||||
|
||||
for (;;) {
|
||||
if (data->suspend_level != PME_SUSPEND_NONE)
|
||||
if (data->noirq)
|
||||
break;
|
||||
|
||||
pcie_capability_read_dword(port, PCI_EXP_RTSTA, &rtsta);
|
||||
|
@ -255,7 +249,7 @@ static void pcie_pme_work_fn(struct work_struct *work)
|
|||
spin_lock_irq(&data->lock);
|
||||
}
|
||||
|
||||
if (data->suspend_level == PME_SUSPEND_NONE)
|
||||
if (!data->noirq)
|
||||
pcie_pme_interrupt_enable(port, true);
|
||||
|
||||
spin_unlock_irq(&data->lock);
|
||||
|
@ -378,7 +372,7 @@ static int pcie_pme_suspend(struct pcie_device *srv)
|
|||
{
|
||||
struct pcie_pme_service_data *data = get_service_data(srv);
|
||||
struct pci_dev *port = srv->port;
|
||||
bool wakeup, wake_irq_enabled = false;
|
||||
bool wakeup;
|
||||
int ret;
|
||||
|
||||
if (device_may_wakeup(&port->dev)) {
|
||||
|
@ -388,19 +382,16 @@ static int pcie_pme_suspend(struct pcie_device *srv)
|
|||
wakeup = pcie_pme_check_wakeup(port->subordinate);
|
||||
up_read(&pci_bus_sem);
|
||||
}
|
||||
spin_lock_irq(&data->lock);
|
||||
if (wakeup) {
|
||||
ret = enable_irq_wake(srv->irq);
|
||||
if (ret == 0) {
|
||||
data->suspend_level = PME_SUSPEND_WAKEUP;
|
||||
wake_irq_enabled = true;
|
||||
}
|
||||
}
|
||||
if (!wake_irq_enabled) {
|
||||
pcie_pme_interrupt_enable(port, false);
|
||||
pcie_clear_root_pme_status(port);
|
||||
data->suspend_level = PME_SUSPEND_NOIRQ;
|
||||
if (!ret)
|
||||
return 0;
|
||||
}
|
||||
|
||||
spin_lock_irq(&data->lock);
|
||||
pcie_pme_interrupt_enable(port, false);
|
||||
pcie_clear_root_pme_status(port);
|
||||
data->noirq = true;
|
||||
spin_unlock_irq(&data->lock);
|
||||
|
||||
synchronize_irq(srv->irq);
|
||||
|
@ -417,15 +408,15 @@ static int pcie_pme_resume(struct pcie_device *srv)
|
|||
struct pcie_pme_service_data *data = get_service_data(srv);
|
||||
|
||||
spin_lock_irq(&data->lock);
|
||||
if (data->suspend_level == PME_SUSPEND_NOIRQ) {
|
||||
if (data->noirq) {
|
||||
struct pci_dev *port = srv->port;
|
||||
|
||||
pcie_clear_root_pme_status(port);
|
||||
pcie_pme_interrupt_enable(port, true);
|
||||
data->noirq = false;
|
||||
} else {
|
||||
disable_irq_wake(srv->irq);
|
||||
}
|
||||
data->suspend_level = PME_SUSPEND_NONE;
|
||||
spin_unlock_irq(&data->lock);
|
||||
|
||||
return 0;
|
||||
|
|
|
@ -610,6 +610,11 @@ static int sugov_start(struct cpufreq_policy *policy)
|
|||
sg_cpu->sg_policy = sg_policy;
|
||||
sg_cpu->flags = SCHED_CPUFREQ_RT;
|
||||
sg_cpu->iowait_boost_max = policy->cpuinfo.max_freq;
|
||||
}
|
||||
|
||||
for_each_cpu(cpu, policy->cpus) {
|
||||
struct sugov_cpu *sg_cpu = &per_cpu(sugov_cpu, cpu);
|
||||
|
||||
cpufreq_add_update_util_hook(cpu, &sg_cpu->update_util,
|
||||
policy_is_shared(policy) ?
|
||||
sugov_update_shared :
|
||||
|
|
Loading…
Reference in New Issue