Merge tag 'pm-fixes-4.13-rc1' of git://git.kernel.org/pub/scm/linux/kernel/git/rafael...
authorLinus Torvalds <torvalds@linux-foundation.org>
Sat, 15 Jul 2017 05:24:25 +0000 (22:24 -0700)
committerLinus Torvalds <torvalds@linux-foundation.org>
Sat, 15 Jul 2017 05:24:25 +0000 (22:24 -0700)
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()

drivers/base/power/sysfs.c
drivers/cpufreq/intel_pstate.c
drivers/devfreq/governor_userspace.c
drivers/devfreq/rk3399_dmc.c
drivers/devfreq/tegra-devfreq.c
drivers/pci/pci-driver.c
drivers/pci/pci.c
drivers/pci/pci.h
drivers/pci/pcie/pme.c
kernel/sched/cpufreq_schedutil.c

index 185a52581cfae3294f92bcb94a7de5277bbec751..156ab57bca7715238571165b14e23d54ebbbd23a 100644 (file)
@@ -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;
index d6f323560da39f87d1219a158aabfaf35ceea07d..b7fb8b7c980dc5d2eb2001e4790910cb5b399514 100644 (file)
@@ -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)
index 176976068bcd1552d0a625ea47ebdf72812b4c6b..77028c27593c635d821fab28eea57c0084a89346 100644 (file)
@@ -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,
 };
index 40a2499730fcb4cc635dfb9a0de2b9d50ea47869..1b89ebbad02c0a3d546587b74ea32aef11df1884 100644 (file)
@@ -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)
index 214fff96fa4a6c23d92b71eb1528348e2025afb8..ae712159246fbe2b66895d56f05da9d75fdcd00d 100644 (file)
@@ -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);
index 607f677f48d21f7b7f1b938ec39c11034c4dac17..d51e8738f9c23687e9d88860e57d5197d8cf70e1 100644 (file)
@@ -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);
 }
 
index d88edf5c563b6f07a709c917204b0a77f54ab1f3..af0cc3456dc1b48b1325c06c5edd2ca8cc22a640 100644 (file)
@@ -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
index 03e3d0285aea0423c9732c85bc378bb23daab3df..22e061738c6f4f91049959953783f1e82da192f7 100644 (file)
@@ -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);
index 80e58d25006d04b86e6efe82f581db80c81fe85c..fafdb165dd2ed663779f77bc59b3da3fb32af5c4 100644 (file)
@@ -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;
index 076a2e31951ccbb538e8004a85cf1f247818d57e..29a397067ffa0f7c818990f3defe1a4bdd437708 100644 (file)
@@ -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 :