From ae2917093fb60bdc1ed3e5757b74801420569a9a Mon Sep 17 00:00:00 2001 From: Abhishek Goel Date: Tue, 5 Feb 2019 04:51:28 -0600 Subject: [PATCH 01/17] tools/power/cpupower: Display boost frequency separately cpufreq driver creates sysfs file "scaling_boost_frequency" for platforms which support boost frequency. Cpupower now prints boost frequencies separately. For few x86 vendors who already have different way to get boost frequency, will continue to use the existing logic. Rest of the platforms will rely on "scaling_boost_frequency" file to display boost frequency. Signed-off-by: Abhishek Goel Signed-off-by: Shuah Khan --- tools/power/cpupower/lib/cpufreq.c | 19 +++++----- tools/power/cpupower/lib/cpufreq.h | 16 ++++----- tools/power/cpupower/utils/cpufreq-info.c | 42 +++++++++++++++++------ 3 files changed, 50 insertions(+), 27 deletions(-) diff --git a/tools/power/cpupower/lib/cpufreq.c b/tools/power/cpupower/lib/cpufreq.c index 0c0f3e3f0d80..80650497fb80 100644 --- a/tools/power/cpupower/lib/cpufreq.c +++ b/tools/power/cpupower/lib/cpufreq.c @@ -333,17 +333,20 @@ void cpufreq_put_available_governors(struct cpufreq_available_governors *any) } -struct cpufreq_available_frequencies -*cpufreq_get_available_frequencies(unsigned int cpu) +struct cpufreq_frequencies +*cpufreq_get_frequencies(const char *type, unsigned int cpu) { - struct cpufreq_available_frequencies *first = NULL; - struct cpufreq_available_frequencies *current = NULL; + struct cpufreq_frequencies *first = NULL; + struct cpufreq_frequencies *current = NULL; char one_value[SYSFS_PATH_MAX]; char linebuf[MAX_LINE_LEN]; + char fname[MAX_LINE_LEN]; unsigned int pos, i; unsigned int len; - len = sysfs_cpufreq_read_file(cpu, "scaling_available_frequencies", + snprintf(fname, MAX_LINE_LEN, "scaling_%s_frequencies", type); + + len = sysfs_cpufreq_read_file(cpu, fname, linebuf, sizeof(linebuf)); if (len == 0) return NULL; @@ -389,9 +392,9 @@ struct cpufreq_available_frequencies return NULL; } -void cpufreq_put_available_frequencies(struct cpufreq_available_frequencies - *any) { - struct cpufreq_available_frequencies *tmp, *next; +void cpufreq_put_frequencies(struct cpufreq_frequencies *any) +{ + struct cpufreq_frequencies *tmp, *next; if (!any) return; diff --git a/tools/power/cpupower/lib/cpufreq.h b/tools/power/cpupower/lib/cpufreq.h index 60beaf5ed2ea..775738269cbf 100644 --- a/tools/power/cpupower/lib/cpufreq.h +++ b/tools/power/cpupower/lib/cpufreq.h @@ -28,10 +28,10 @@ struct cpufreq_available_governors { struct cpufreq_available_governors *first; }; -struct cpufreq_available_frequencies { +struct cpufreq_frequencies { unsigned long frequency; - struct cpufreq_available_frequencies *next; - struct cpufreq_available_frequencies *first; + struct cpufreq_frequencies *next; + struct cpufreq_frequencies *first; }; @@ -129,14 +129,14 @@ void cpufreq_put_available_governors( * * Only present on _some_ ->target() cpufreq drivers. For information purposes * only. Please free allocated memory by calling - * cpufreq_put_available_frequencies after use. + * cpufreq_put_frequencies after use. */ -struct cpufreq_available_frequencies -*cpufreq_get_available_frequencies(unsigned int cpu); +struct cpufreq_frequencies +*cpufreq_get_frequencies(const char *type, unsigned int cpu); -void cpufreq_put_available_frequencies( - struct cpufreq_available_frequencies *first); +void cpufreq_put_frequencies( + struct cpufreq_frequencies *first); /* determine affected CPUs diff --git a/tools/power/cpupower/utils/cpufreq-info.c b/tools/power/cpupower/utils/cpufreq-info.c index c3f39d5128ee..10290b308797 100644 --- a/tools/power/cpupower/utils/cpufreq-info.c +++ b/tools/power/cpupower/utils/cpufreq-info.c @@ -161,19 +161,12 @@ static void print_duration(unsigned long duration) return; } -/* --boost / -b */ - -static int get_boost_mode(unsigned int cpu) +static int get_boost_mode_x86(unsigned int cpu) { int support, active, b_states = 0, ret, pstate_no, i; /* ToDo: Make this more global */ unsigned long pstates[MAX_HW_PSTATES] = {0,}; - if (cpupower_cpu_info.vendor != X86_VENDOR_AMD && - cpupower_cpu_info.vendor != X86_VENDOR_HYGON && - cpupower_cpu_info.vendor != X86_VENDOR_INTEL) - return 0; - ret = cpufreq_has_boost_support(cpu, &support, &active, &b_states); if (ret) { printf(_("Error while evaluating Boost Capabilities" @@ -248,6 +241,33 @@ static int get_boost_mode(unsigned int cpu) return 0; } +/* --boost / -b */ + +static int get_boost_mode(unsigned int cpu) +{ + struct cpufreq_frequencies *freqs; + + if (cpupower_cpu_info.vendor == X86_VENDOR_AMD || + cpupower_cpu_info.vendor == X86_VENDOR_HYGON || + cpupower_cpu_info.vendor == X86_VENDOR_INTEL) + return get_boost_mode_x86(cpu); + + freqs = cpufreq_get_frequencies("boost", cpu); + if (freqs) { + printf(_(" boost frequency steps: ")); + while (freqs->next) { + print_speed(freqs->frequency); + printf(", "); + freqs = freqs->next; + } + print_speed(freqs->frequency); + printf("\n"); + cpufreq_put_frequencies(freqs); + } + + return 0; +} + /* --freq / -f */ static int get_freq_kernel(unsigned int cpu, unsigned int human) @@ -456,7 +476,7 @@ static int get_latency(unsigned int cpu, unsigned int human) static void debug_output_one(unsigned int cpu) { - struct cpufreq_available_frequencies *freqs; + struct cpufreq_frequencies *freqs; get_driver(cpu); get_related_cpus(cpu); @@ -464,7 +484,7 @@ static void debug_output_one(unsigned int cpu) get_latency(cpu, 1); get_hardware_limits(cpu, 1); - freqs = cpufreq_get_available_frequencies(cpu); + freqs = cpufreq_get_frequencies("available", cpu); if (freqs) { printf(_(" available frequency steps: ")); while (freqs->next) { @@ -474,7 +494,7 @@ static void debug_output_one(unsigned int cpu) } print_speed(freqs->frequency); printf("\n"); - cpufreq_put_available_frequencies(freqs); + cpufreq_put_frequencies(freqs); } get_available_governors(cpu); From 814b8797f9863abc2877acf87f6be0f140d00139 Mon Sep 17 00:00:00 2001 From: "Rafael J. Wysocki" Date: Wed, 27 Feb 2019 14:35:50 +0100 Subject: [PATCH 02/17] cpuidle: menu: Avoid overflows when computing variance The variance computation in get_typical_interval() may overflow if the square of the value of diff exceeds the maximum for the int64_t data type value which basically is the case when it is of the order of UINT_MAX. However, data points so far in the future don't matter for idle state selection anyway, so change the initial threshold value in get_typical_interval() to INT_MAX which will cause more "outlying" data points to be discarded without affecting the selection result. Reported-by: Randy Dunlap Signed-off-by: Rafael J. Wysocki --- drivers/cpuidle/governors/menu.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/cpuidle/governors/menu.c b/drivers/cpuidle/governors/menu.c index 61316fc51548..5951604e7d5c 100644 --- a/drivers/cpuidle/governors/menu.c +++ b/drivers/cpuidle/governors/menu.c @@ -186,7 +186,7 @@ static unsigned int get_typical_interval(struct menu_device *data, unsigned int min, max, thresh, avg; uint64_t sum, variance; - thresh = UINT_MAX; /* Discard outliers above this value */ + thresh = INT_MAX; /* Discard outliers above this value */ again: From 5d094fea148dc35e2e5664d297b82494322704cd Mon Sep 17 00:00:00 2001 From: "Rafael J. Wysocki" Date: Tue, 5 Mar 2019 11:44:04 +0100 Subject: [PATCH 03/17] cpufreq: Improve kerneldoc comments for cpufreq_cpu_get/put() Fix the formatting of the cpufreq_cpu_get() and cpufreq_cpu_put() kerneldoc comments and rework them to be somewhat easier to follow. Signed-off-by: Rafael J. Wysocki Acked-by: Viresh Kumar Signed-off-by: Rafael J. Wysocki --- drivers/cpufreq/cpufreq.c | 24 +++++++++--------------- 1 file changed, 9 insertions(+), 15 deletions(-) diff --git a/drivers/cpufreq/cpufreq.c b/drivers/cpufreq/cpufreq.c index 0e626b00053b..e10922709d13 100644 --- a/drivers/cpufreq/cpufreq.c +++ b/drivers/cpufreq/cpufreq.c @@ -206,17 +206,15 @@ unsigned int cpufreq_generic_get(unsigned int cpu) EXPORT_SYMBOL_GPL(cpufreq_generic_get); /** - * cpufreq_cpu_get: returns policy for a cpu and marks it busy. + * cpufreq_cpu_get - Return policy for a CPU and mark it as busy. + * @cpu: CPU to find the policy for. * - * @cpu: cpu to find policy for. + * Call cpufreq_cpu_get_raw() to obtain a cpufreq policy for @cpu and increment + * the kobject reference counter of that policy. Return a valid policy on + * success or NULL on failure. * - * This returns policy for 'cpu', returns NULL if it doesn't exist. - * It also increments the kobject reference count to mark it busy and so would - * require a corresponding call to cpufreq_cpu_put() to decrement it back. - * If corresponding call cpufreq_cpu_put() isn't made, the policy wouldn't be - * freed as that depends on the kobj count. - * - * Return: A valid policy on success, otherwise NULL on failure. + * The policy returned by this function has to be released with the help of + * cpufreq_cpu_put() to balance its kobject reference counter properly. */ struct cpufreq_policy *cpufreq_cpu_get(unsigned int cpu) { @@ -243,12 +241,8 @@ struct cpufreq_policy *cpufreq_cpu_get(unsigned int cpu) EXPORT_SYMBOL_GPL(cpufreq_cpu_get); /** - * cpufreq_cpu_put: Decrements the usage count of a policy - * - * @policy: policy earlier returned by cpufreq_cpu_get(). - * - * This decrements the kobject reference count incremented earlier by calling - * cpufreq_cpu_get(). + * cpufreq_cpu_put - Decrement kobject usage counter for cpufreq policy. + * @policy: cpufreq policy returned by cpufreq_cpu_get(). */ void cpufreq_cpu_put(struct cpufreq_policy *policy) { From 7a5bd1279bce2116af67979bea311a0ccc4b8bb9 Mon Sep 17 00:00:00 2001 From: Joe Perches Date: Mon, 4 Mar 2019 09:14:38 -0800 Subject: [PATCH 04/17] PM: Add and use pr_fmt() Prefix all printk/pr_ messages with "PM: " to make the logging a bit more consistent. Miscellanea: o Convert a few printks to pr_ o Whitespace to align to open parentheses o Remove embedded "PM: " from pr_debugs as pr_fmt adds it Signed-off-by: Joe Perches Reviewed-by: Kees Cook Reviewed-by: Kevin Hilman Signed-off-by: Rafael J. Wysocki --- drivers/base/power/domain.c | 12 +++++++----- drivers/base/power/main.c | 21 +++++++++++---------- drivers/base/power/trace.c | 2 ++ drivers/base/power/wakeup.c | 4 +++- 4 files changed, 23 insertions(+), 16 deletions(-) diff --git a/drivers/base/power/domain.c b/drivers/base/power/domain.c index 2c334c01fc43..764e0f28979e 100644 --- a/drivers/base/power/domain.c +++ b/drivers/base/power/domain.c @@ -6,6 +6,8 @@ * This file is released under the GPLv2. */ +#define pr_fmt(fmt) "PM: " fmt + #include #include #include @@ -1657,8 +1659,8 @@ int pm_genpd_remove_subdomain(struct generic_pm_domain *genpd, genpd_lock_nested(genpd, SINGLE_DEPTH_NESTING); if (!list_empty(&subdomain->master_links) || subdomain->device_count) { - pr_warn("%s: unable to remove subdomain %s\n", genpd->name, - subdomain->name); + pr_warn("%s: unable to remove subdomain %s\n", + genpd->name, subdomain->name); ret = -EBUSY; goto out; } @@ -1767,7 +1769,7 @@ int pm_genpd_init(struct generic_pm_domain *genpd, if (ret) return ret; } else if (!gov) { - pr_warn("%s : no governor for states\n", genpd->name); + pr_warn("%s: no governor for states\n", genpd->name); } device_initialize(&genpd->dev); @@ -2514,7 +2516,7 @@ static int genpd_parse_state(struct genpd_power_state *genpd_state, &entry_latency); if (err) { pr_debug(" * %pOF missing entry-latency-us property\n", - state_node); + state_node); return -EINVAL; } @@ -2522,7 +2524,7 @@ static int genpd_parse_state(struct genpd_power_state *genpd_state, &exit_latency); if (err) { pr_debug(" * %pOF missing exit-latency-us property\n", - state_node); + state_node); return -EINVAL; } diff --git a/drivers/base/power/main.c b/drivers/base/power/main.c index 893ae464bfd6..929bc9d50db7 100644 --- a/drivers/base/power/main.c +++ b/drivers/base/power/main.c @@ -17,6 +17,8 @@ * subsystem list maintains. */ +#define pr_fmt(fmt) "PM: " fmt + #include #include #include @@ -128,7 +130,7 @@ void device_pm_add(struct device *dev) if (device_pm_not_required(dev)) return; - pr_debug("PM: Adding info for %s:%s\n", + pr_debug("Adding info for %s:%s\n", dev->bus ? dev->bus->name : "No Bus", dev_name(dev)); device_pm_check_callbacks(dev); mutex_lock(&dpm_list_mtx); @@ -149,7 +151,7 @@ void device_pm_remove(struct device *dev) if (device_pm_not_required(dev)) return; - pr_debug("PM: Removing info for %s:%s\n", + pr_debug("Removing info for %s:%s\n", dev->bus ? dev->bus->name : "No Bus", dev_name(dev)); complete_all(&dev->power.completion); mutex_lock(&dpm_list_mtx); @@ -168,7 +170,7 @@ void device_pm_remove(struct device *dev) */ void device_pm_move_before(struct device *deva, struct device *devb) { - pr_debug("PM: Moving %s:%s before %s:%s\n", + pr_debug("Moving %s:%s before %s:%s\n", deva->bus ? deva->bus->name : "No Bus", dev_name(deva), devb->bus ? devb->bus->name : "No Bus", dev_name(devb)); /* Delete deva from dpm_list and reinsert before devb. */ @@ -182,7 +184,7 @@ void device_pm_move_before(struct device *deva, struct device *devb) */ void device_pm_move_after(struct device *deva, struct device *devb) { - pr_debug("PM: Moving %s:%s after %s:%s\n", + pr_debug("Moving %s:%s after %s:%s\n", deva->bus ? deva->bus->name : "No Bus", dev_name(deva), devb->bus ? devb->bus->name : "No Bus", dev_name(devb)); /* Delete deva from dpm_list and reinsert after devb. */ @@ -195,7 +197,7 @@ void device_pm_move_after(struct device *deva, struct device *devb) */ void device_pm_move_last(struct device *dev) { - pr_debug("PM: Moving %s:%s to end of list\n", + pr_debug("Moving %s:%s to end of list\n", dev->bus ? dev->bus->name : "No Bus", dev_name(dev)); list_move_tail(&dev->power.entry, &dpm_list); } @@ -418,8 +420,8 @@ static void pm_dev_dbg(struct device *dev, pm_message_t state, const char *info) static void pm_dev_err(struct device *dev, pm_message_t state, const char *info, int error) { - printk(KERN_ERR "PM: Device %s failed to %s%s: error %d\n", - dev_name(dev), pm_verb(state.event), info, error); + pr_err("Device %s failed to %s%s: error %d\n", + dev_name(dev), pm_verb(state.event), info, error); } static void dpm_show_time(ktime_t starttime, pm_message_t state, int error, @@ -2022,8 +2024,7 @@ int dpm_prepare(pm_message_t state) error = 0; continue; } - printk(KERN_INFO "PM: Device %s not prepared " - "for power transition: code %d\n", + pr_info("Device %s not prepared for power transition: code %d\n", dev_name(dev), error); put_device(dev); break; @@ -2062,7 +2063,7 @@ EXPORT_SYMBOL_GPL(dpm_suspend_start); void __suspend_report_result(const char *function, void *fn, int ret) { if (ret) - printk(KERN_ERR "%s(): %pF returns %d\n", function, fn, ret); + pr_err("%s(): %pF returns %d\n", function, fn, ret); } EXPORT_SYMBOL_GPL(__suspend_report_result); diff --git a/drivers/base/power/trace.c b/drivers/base/power/trace.c index b11f47a1e819..2bd9d2c744ca 100644 --- a/drivers/base/power/trace.c +++ b/drivers/base/power/trace.c @@ -7,6 +7,8 @@ * devices may be working. */ +#define pr_fmt(fmt) "PM: " fmt + #include #include #include diff --git a/drivers/base/power/wakeup.c b/drivers/base/power/wakeup.c index f1fee72ed970..d0e77d56c1d9 100644 --- a/drivers/base/power/wakeup.c +++ b/drivers/base/power/wakeup.c @@ -6,6 +6,8 @@ * This file is released under the GPLv2. */ +#define pr_fmt(fmt) "PM: " fmt + #include #include #include @@ -853,7 +855,7 @@ bool pm_wakeup_pending(void) raw_spin_unlock_irqrestore(&events_lock, flags); if (ret) { - pr_debug("PM: Wakeup pending, aborting suspend\n"); + pr_debug("Wakeup pending, aborting suspend\n"); pm_print_active_wakeup_sources(); } From fdc56c073270af2f4d223c96a5fff3048352fc03 Mon Sep 17 00:00:00 2001 From: Ulf Hansson Date: Tue, 5 Mar 2019 13:55:26 +0100 Subject: [PATCH 05/17] PM-runtime: Consolidate code to get active/suspended time In a step to consolidate the code for fetching the PM-runtime active/suspended time for a device, add a common function for that and make the existing pm_runtime_suspended_time() call it. Also add a corresponding pm_runtime_active_time() calling the new common function. Signed-off-by: Ulf Hansson [ rjw: Changelog, function rename ] Signed-off-by: Rafael J. Wysocki --- drivers/base/power/power.h | 1 + drivers/base/power/runtime.c | 14 ++++++++++++-- 2 files changed, 13 insertions(+), 2 deletions(-) diff --git a/drivers/base/power/power.h b/drivers/base/power/power.h index c511def48b48..ec33fbdb919b 100644 --- a/drivers/base/power/power.h +++ b/drivers/base/power/power.h @@ -21,6 +21,7 @@ static inline void pm_runtime_early_init(struct device *dev) extern void pm_runtime_init(struct device *dev); extern void pm_runtime_reinit(struct device *dev); extern void pm_runtime_remove(struct device *dev); +extern u64 pm_runtime_active_time(struct device *dev); #define WAKE_IRQ_DEDICATED_ALLOCATED BIT(0) #define WAKE_IRQ_DEDICATED_MANAGED BIT(1) diff --git a/drivers/base/power/runtime.c b/drivers/base/power/runtime.c index 78937c45278c..32f6bf076bd7 100644 --- a/drivers/base/power/runtime.c +++ b/drivers/base/power/runtime.c @@ -98,7 +98,7 @@ static void __update_runtime_status(struct device *dev, enum rpm_status status) dev->power.runtime_status = status; } -u64 pm_runtime_suspended_time(struct device *dev) +static u64 rpm_get_accounted_time(struct device *dev, bool suspended) { u64 time; unsigned long flags; @@ -106,12 +106,22 @@ u64 pm_runtime_suspended_time(struct device *dev) spin_lock_irqsave(&dev->power.lock, flags); update_pm_runtime_accounting(dev); - time = dev->power.suspended_time; + time = suspended ? dev->power.suspended_time : dev->power.active_time; spin_unlock_irqrestore(&dev->power.lock, flags); return time; } + +u64 pm_runtime_active_time(struct device *dev) +{ + return rpm_get_accounted_time(dev, false); +} + +u64 pm_runtime_suspended_time(struct device *dev) +{ + return rpm_get_accounted_time(dev, true); +} EXPORT_SYMBOL_GPL(pm_runtime_suspended_time); /** From 0996584b3026bed7f38abe02e8535e6a6c474118 Mon Sep 17 00:00:00 2001 From: Ulf Hansson Date: Tue, 5 Mar 2019 13:55:35 +0100 Subject: [PATCH 06/17] PM-runtime: Call pm_runtime_active|suspended_time() from sysfs Avoid the open-coding of the accounted time acquisition in runtime_active|suspend_time_show() and make them call pm_runtime_active|suspended_time() instead. Note that this change also indirectly avoids holding dev->power.lock around the do_div() computation and the sprintf() call which is an additional improvement. Signed-off-by: Ulf Hansson [ rjw: Changelog ] Signed-off-by: Rafael J. Wysocki --- drivers/base/power/runtime.c | 2 +- drivers/base/power/sysfs.c | 12 ++---------- include/linux/pm.h | 1 - 3 files changed, 3 insertions(+), 12 deletions(-) diff --git a/drivers/base/power/runtime.c b/drivers/base/power/runtime.c index 32f6bf076bd7..a2d22e3ecf3a 100644 --- a/drivers/base/power/runtime.c +++ b/drivers/base/power/runtime.c @@ -64,7 +64,7 @@ static int rpm_suspend(struct device *dev, int rpmflags); * runtime_status field is updated, to account the time in the old state * correctly. */ -void update_pm_runtime_accounting(struct device *dev) +static void update_pm_runtime_accounting(struct device *dev) { u64 now, last, delta; diff --git a/drivers/base/power/sysfs.c b/drivers/base/power/sysfs.c index c6bf76124184..1226e441ddfe 100644 --- a/drivers/base/power/sysfs.c +++ b/drivers/base/power/sysfs.c @@ -125,13 +125,9 @@ static ssize_t runtime_active_time_show(struct device *dev, struct device_attribute *attr, char *buf) { int ret; - u64 tmp; - spin_lock_irq(&dev->power.lock); - update_pm_runtime_accounting(dev); - tmp = dev->power.active_time; + u64 tmp = pm_runtime_active_time(dev); do_div(tmp, NSEC_PER_MSEC); ret = sprintf(buf, "%llu\n", tmp); - spin_unlock_irq(&dev->power.lock); return ret; } @@ -141,13 +137,9 @@ static ssize_t runtime_suspended_time_show(struct device *dev, struct device_attribute *attr, char *buf) { int ret; - u64 tmp; - spin_lock_irq(&dev->power.lock); - update_pm_runtime_accounting(dev); - tmp = dev->power.suspended_time; + u64 tmp = pm_runtime_suspended_time(dev); do_div(tmp, NSEC_PER_MSEC); ret = sprintf(buf, "%llu\n", tmp); - spin_unlock_irq(&dev->power.lock); return ret; } diff --git a/include/linux/pm.h b/include/linux/pm.h index 06f7ed893928..66c19a65a514 100644 --- a/include/linux/pm.h +++ b/include/linux/pm.h @@ -643,7 +643,6 @@ struct dev_pm_info { struct dev_pm_qos *qos; }; -extern void update_pm_runtime_accounting(struct device *dev); extern int dev_pm_get_subsys_data(struct device *dev); extern void dev_pm_put_subsys_data(struct device *dev); From 9505b98ccddc454008ca7efff90044e3e857c827 Mon Sep 17 00:00:00 2001 From: Arnd Bergmann Date: Thu, 7 Mar 2019 11:22:41 +0100 Subject: [PATCH 07/17] cpufreq: pxa2xx: remove incorrect __init annotation pxa_cpufreq_init_voltages() is marked __init but usually inlined into the non-__init pxa_cpufreq_init() function. When building with clang, it can stay as a standalone function in a discarded section, and produce this warning: WARNING: vmlinux.o(.text+0x616a00): Section mismatch in reference from the function pxa_cpufreq_init() to the function .init.text:pxa_cpufreq_init_voltages() The function pxa_cpufreq_init() references the function __init pxa_cpufreq_init_voltages(). This is often because pxa_cpufreq_init lacks a __init annotation or the annotation of pxa_cpufreq_init_voltages is wrong. Fixes: 50e77fcd790e ("ARM: pxa: remove __init from cpufreq_driver->init()") Signed-off-by: Arnd Bergmann Acked-by: Viresh Kumar Reviewed-by: Nathan Chancellor Acked-by: Robert Jarzmik Cc: All applicable Signed-off-by: Rafael J. Wysocki --- drivers/cpufreq/pxa2xx-cpufreq.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/drivers/cpufreq/pxa2xx-cpufreq.c b/drivers/cpufreq/pxa2xx-cpufreq.c index 46254e583982..74e0e0c20c46 100644 --- a/drivers/cpufreq/pxa2xx-cpufreq.c +++ b/drivers/cpufreq/pxa2xx-cpufreq.c @@ -143,7 +143,7 @@ static int pxa_cpufreq_change_voltage(const struct pxa_freqs *pxa_freq) return ret; } -static void __init pxa_cpufreq_init_voltages(void) +static void pxa_cpufreq_init_voltages(void) { vcc_core = regulator_get(NULL, "vcc_core"); if (IS_ERR(vcc_core)) { @@ -159,7 +159,7 @@ static int pxa_cpufreq_change_voltage(const struct pxa_freqs *pxa_freq) return 0; } -static void __init pxa_cpufreq_init_voltages(void) { } +static void pxa_cpufreq_init_voltages(void) { } #endif static void find_freq_tables(struct cpufreq_frequency_table **freq_table, From 07a6c71bbd4a85a619069a00d37e7232edf2306e Mon Sep 17 00:00:00 2001 From: Aisheng Dong Date: Wed, 6 Mar 2019 13:25:25 +0000 Subject: [PATCH 08/17] PM / QoS: Fix typo in file description Fix a typo in the file description comment. Signed-off-by: Dong Aisheng Signed-off-by: Rafael J. Wysocki --- drivers/base/power/qos.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/base/power/qos.c b/drivers/base/power/qos.c index 3382542b39b7..f80e402ef778 100644 --- a/drivers/base/power/qos.c +++ b/drivers/base/power/qos.c @@ -22,7 +22,7 @@ * per-device constraint data struct. * * Note about the per-device constraint data struct allocation: - * . The per-device constraints data struct ptr is tored into the device + * . The per-device constraints data struct ptr is stored into the device * dev_pm_info. * . To minimize the data usage by the per-device constraints, the data struct * is only allocated at the first call to dev_pm_qos_add_request. From 55286a29389a1a30fb2ccc83ef9315809946b365 Mon Sep 17 00:00:00 2001 From: Rajendra Nayak Date: Wed, 6 Mar 2019 09:37:26 +0530 Subject: [PATCH 09/17] OPP: Fix handling of multiple power domains We seem to rely on the number of phandles specified in the 'required-opps' property to identify cases where a device is associated with multiple power domains and hence would have multiple virtual devices that have to be dealt with. In cases where we do have devices with multiple power domains but with only one of them being scalable, this logic seems to fail. Instead read the number of power domains from DT to identify such cases. Signed-off-by: Rajendra Nayak Reviewed-by: Stephen Boyd Acked-by: Viresh Kumar Signed-off-by: Rafael J. Wysocki --- drivers/opp/of.c | 16 ++++++++++++++-- 1 file changed, 14 insertions(+), 2 deletions(-) diff --git a/drivers/opp/of.c b/drivers/opp/of.c index 62504b18f198..c10c782d15aa 100644 --- a/drivers/opp/of.c +++ b/drivers/opp/of.c @@ -173,7 +173,7 @@ static void _opp_table_alloc_required_tables(struct opp_table *opp_table, struct opp_table **required_opp_tables; struct device **genpd_virt_devs = NULL; struct device_node *required_np, *np; - int count, i; + int count, count_pd, i; /* Traversing the first OPP node is all we need */ np = of_get_next_available_child(opp_np, NULL); @@ -186,7 +186,19 @@ static void _opp_table_alloc_required_tables(struct opp_table *opp_table, if (!count) goto put_np; - if (count > 1) { + /* + * Check the number of power-domains to know if we need to deal + * with virtual devices. In some cases we have devices with multiple + * power domains but with only one of them being scalable, hence + * 'count' could be 1, but we still have to deal with multiple genpds + * and virtual devices. + */ + count_pd = of_count_phandle_with_args(dev->of_node, "power-domains", + "#power-domain-cells"); + if (!count_pd) + goto put_np; + + if (count_pd > 1) { genpd_virt_devs = kcalloc(count, sizeof(*genpd_virt_devs), GFP_KERNEL); if (!genpd_virt_devs) From 46b7fe94995fd166786a301dbba919046e70e702 Mon Sep 17 00:00:00 2001 From: Aisheng Dong Date: Wed, 6 Mar 2019 13:25:12 +0000 Subject: [PATCH 10/17] PM / Domains: Improve warn for multiple states but no governor It's possible a PM domain defines only one state and it does not need a governor to work. For such case, a warning actually is not necessary. Signed-off-by: Dong Aisheng Reviewed-by: Ulf Hansson Signed-off-by: Rafael J. Wysocki --- drivers/base/power/domain.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/base/power/domain.c b/drivers/base/power/domain.c index 2c334c01fc43..394f9daa3983 100644 --- a/drivers/base/power/domain.c +++ b/drivers/base/power/domain.c @@ -1766,7 +1766,7 @@ int pm_genpd_init(struct generic_pm_domain *genpd, ret = genpd_set_default_power_state(genpd); if (ret) return ret; - } else if (!gov) { + } else if (!gov && genpd->state_count > 1) { pr_warn("%s : no governor for states\n", genpd->name); } From 0cec68a97787db1ca5772f5939ec4db22de78d65 Mon Sep 17 00:00:00 2001 From: Aisheng Dong Date: Wed, 6 Mar 2019 13:25:15 +0000 Subject: [PATCH 11/17] PM / Domains: Return early for all errors in _genpd_power_off() It is strange to only return early for -EBUSY state and left other errors to be still measured execution time. As for error cases, the elapsed_ns computed actually is not quite accurate and meaningful for governor to use. So let's simply return for all error cases. Signed-off-by: Dong Aisheng Reviewed-by: Ulf Hansson Signed-off-by: Rafael J. Wysocki --- drivers/base/power/domain.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/drivers/base/power/domain.c b/drivers/base/power/domain.c index 394f9daa3983..f01257607bf7 100644 --- a/drivers/base/power/domain.c +++ b/drivers/base/power/domain.c @@ -457,19 +457,19 @@ static int _genpd_power_off(struct generic_pm_domain *genpd, bool timed) time_start = ktime_get(); ret = genpd->power_off(genpd); - if (ret == -EBUSY) + if (ret) return ret; elapsed_ns = ktime_to_ns(ktime_sub(ktime_get(), time_start)); if (elapsed_ns <= genpd->states[state_idx].power_off_latency_ns) - return ret; + return 0; genpd->states[state_idx].power_off_latency_ns = elapsed_ns; genpd->max_off_time_changed = true; pr_debug("%s: Power-%s latency exceeded, new value %lld ns\n", genpd->name, "off", elapsed_ns); - return ret; + return 0; } /** From d9dfca7f81246db9a2c28ac1c811fc1085fbd478 Mon Sep 17 00:00:00 2001 From: Aisheng Dong Date: Wed, 6 Mar 2019 13:25:29 +0000 Subject: [PATCH 12/17] PM / domains: Remove one unnecessary blank line Remove one unnecessary blank line Signed-off-by: Dong Aisheng Signed-off-by: Rafael J. Wysocki --- drivers/base/power/domain_governor.c | 1 - 1 file changed, 1 deletion(-) diff --git a/drivers/base/power/domain_governor.c b/drivers/base/power/domain_governor.c index 99896fbf18e4..4d07e38a8247 100644 --- a/drivers/base/power/domain_governor.c +++ b/drivers/base/power/domain_governor.c @@ -128,7 +128,6 @@ static bool __default_power_down_ok(struct dev_pm_domain *pd, off_on_time_ns = genpd->states[state].power_off_latency_ns + genpd->states[state].power_on_latency_ns; - min_off_time_ns = -1; /* * Check if subdomains can be off for enough time. From 1fad17fb1bbcd73159c2b992668a6957ecc5af8a Mon Sep 17 00:00:00 2001 From: Viresh Kumar Date: Fri, 8 Mar 2019 15:23:11 +0530 Subject: [PATCH 13/17] PM / wakeup: Rework wakeup source timer cancellation If wakeup_source_add() is called right after wakeup_source_remove() for the same wakeup source, timer_setup() may be called for a potentially scheduled timer which is incorrect. To avoid that, move the wakeup source timer cancellation from wakeup_source_drop() to wakeup_source_remove(). Moreover, make wakeup_source_remove() clear the timer function after canceling the timer to let wakeup_source_not_registered() treat unregistered wakeup sources in the same way as the ones that have never been registered. Signed-off-by: Viresh Kumar Cc: 4.4+ # 4.4+ [ rjw: Subject, changelog, merged two patches together ] Signed-off-by: Rafael J. Wysocki --- drivers/base/power/wakeup.c | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/drivers/base/power/wakeup.c b/drivers/base/power/wakeup.c index f1fee72ed970..a25d2d82f44d 100644 --- a/drivers/base/power/wakeup.c +++ b/drivers/base/power/wakeup.c @@ -118,7 +118,6 @@ void wakeup_source_drop(struct wakeup_source *ws) if (!ws) return; - del_timer_sync(&ws->timer); __pm_relax(ws); } EXPORT_SYMBOL_GPL(wakeup_source_drop); @@ -205,6 +204,13 @@ void wakeup_source_remove(struct wakeup_source *ws) list_del_rcu(&ws->entry); raw_spin_unlock_irqrestore(&events_lock, flags); synchronize_srcu(&wakeup_srcu); + + del_timer_sync(&ws->timer); + /* + * Clear timer.function to make wakeup_source_not_registered() treat + * this wakeup source as not registered. + */ + ws->timer.function = NULL; } EXPORT_SYMBOL_GPL(wakeup_source_remove); From 623217a0cc45a6c179303b3bbfdc594806a464cc Mon Sep 17 00:00:00 2001 From: "Rafael J. Wysocki" Date: Mon, 11 Mar 2019 12:53:59 +0100 Subject: [PATCH 14/17] PM / wakeup: Drop wakeup_source_drop() After commit d856f39ac1cc ("PM / wakeup: Rework wakeup source timer cancellation") wakeup_source_drop() is a trivial wrapper around __pm_relax() and it has no users except for wakeup_source_destroy() and wakeup_source_trash() which also has no users, so drop it along with the latter and make wakeup_source_destroy() call __pm_relax() directly. Signed-off-by: Rafael J. Wysocki Acked-by: Viresh Kumar --- drivers/base/power/wakeup.c | 18 +----------------- include/linux/pm_wakeup.h | 9 --------- 2 files changed, 1 insertion(+), 26 deletions(-) diff --git a/drivers/base/power/wakeup.c b/drivers/base/power/wakeup.c index a25d2d82f44d..ecbe152d151f 100644 --- a/drivers/base/power/wakeup.c +++ b/drivers/base/power/wakeup.c @@ -106,22 +106,6 @@ struct wakeup_source *wakeup_source_create(const char *name) } EXPORT_SYMBOL_GPL(wakeup_source_create); -/** - * wakeup_source_drop - Prepare a struct wakeup_source object for destruction. - * @ws: Wakeup source to prepare for destruction. - * - * Callers must ensure that __pm_stay_awake() or __pm_wakeup_event() will never - * be run in parallel with this function for the same wakeup source object. - */ -void wakeup_source_drop(struct wakeup_source *ws) -{ - if (!ws) - return; - - __pm_relax(ws); -} -EXPORT_SYMBOL_GPL(wakeup_source_drop); - /* * Record wakeup_source statistics being deleted into a dummy wakeup_source. */ @@ -161,7 +145,7 @@ void wakeup_source_destroy(struct wakeup_source *ws) if (!ws) return; - wakeup_source_drop(ws); + __pm_relax(ws); wakeup_source_record(ws); kfree_const(ws->name); kfree(ws); diff --git a/include/linux/pm_wakeup.h b/include/linux/pm_wakeup.h index 4238dde0aaf0..0ff134d6575a 100644 --- a/include/linux/pm_wakeup.h +++ b/include/linux/pm_wakeup.h @@ -96,7 +96,6 @@ static inline void device_set_wakeup_path(struct device *dev) /* drivers/base/power/wakeup.c */ extern void wakeup_source_prepare(struct wakeup_source *ws, const char *name); extern struct wakeup_source *wakeup_source_create(const char *name); -extern void wakeup_source_drop(struct wakeup_source *ws); extern void wakeup_source_destroy(struct wakeup_source *ws); extern void wakeup_source_add(struct wakeup_source *ws); extern void wakeup_source_remove(struct wakeup_source *ws); @@ -134,8 +133,6 @@ static inline struct wakeup_source *wakeup_source_create(const char *name) return NULL; } -static inline void wakeup_source_drop(struct wakeup_source *ws) {} - static inline void wakeup_source_destroy(struct wakeup_source *ws) {} static inline void wakeup_source_add(struct wakeup_source *ws) {} @@ -204,12 +201,6 @@ static inline void wakeup_source_init(struct wakeup_source *ws, wakeup_source_add(ws); } -static inline void wakeup_source_trash(struct wakeup_source *ws) -{ - wakeup_source_remove(ws); - wakeup_source_drop(ws); -} - static inline void __pm_wakeup_event(struct wakeup_source *ws, unsigned int msec) { return pm_wakeup_ws_event(ws, msec, false); From faef080f6db5320011862f7baf1aa66d0851559f Mon Sep 17 00:00:00 2001 From: Viresh Kumar Date: Tue, 12 Mar 2019 10:27:18 +0530 Subject: [PATCH 15/17] PM / OPP: Update performance state when freq == old_freq At boot up, CPUFreq core performs a sanity check to see if the system is running at a frequency defined in the frequency table of the CPU. If so, we try to find a valid frequency (lowest frequency greater than the currently programmed frequency) from the table and set it. When the call reaches dev_pm_opp_set_rate(), it calls _find_freq_ceil(opp_table, &old_freq) to find the previously configured OPP and this call also updates the old_freq. This eventually sets the old_freq == freq (new target requested by cpufreq core) and we skip updating the performance state in this case. Fix this by also updating the performance state when the old_freq == freq. Fixes: ca1b5d77b1c6 ("OPP: Configure all required OPPs") Cc: v5.0 # v5.0 Reported-by: Niklas Cassel Tested-by: Jorge Ramirez-Ortiz Signed-off-by: Viresh Kumar Signed-off-by: Rafael J. Wysocki --- drivers/opp/core.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/opp/core.c b/drivers/opp/core.c index d7f97167cac3..0420f7e8ad5b 100644 --- a/drivers/opp/core.c +++ b/drivers/opp/core.c @@ -760,7 +760,7 @@ int dev_pm_opp_set_rate(struct device *dev, unsigned long target_freq) old_freq, freq); /* Scaling up? Configure required OPPs before frequency */ - if (freq > old_freq) { + if (freq >= old_freq) { ret = _set_required_opps(dev, opp_table, opp); if (ret) goto put_opp; From 8e3b403954507eb74ad241dc3750443ccc9ee40a Mon Sep 17 00:00:00 2001 From: "Rafael J. Wysocki" Date: Mon, 11 Mar 2019 12:57:25 +0100 Subject: [PATCH 16/17] cpufreq: intel_pstate: Fix up iowait_boost computation After commit b8bd1581aa61 ("cpufreq: intel_pstate: Rework iowait boosting to be less aggressive") the handling of the case when the SCHED_CPUFREQ_IOWAIT flag is set again after a few iterations of intel_pstate_update_util() is a bit inconsistent, because the new value of cpu->iowait_boost may be lower than ONE_EIGHTH_FP if it was set before, but has not dropped down to zero just yet. Fix that up by ensuring that the new value of cpu->iowait_boost will always be at least ONE_EIGHTH_FP then. Fixes: b8bd1581aa61 ("cpufreq: intel_pstate: Rework iowait boosting to be less aggressive") Signed-off-by: Rafael J. Wysocki --- drivers/cpufreq/intel_pstate.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/cpufreq/intel_pstate.c b/drivers/cpufreq/intel_pstate.c index 002f5169d4eb..e22f0dbaebb1 100644 --- a/drivers/cpufreq/intel_pstate.c +++ b/drivers/cpufreq/intel_pstate.c @@ -1762,7 +1762,7 @@ static void intel_pstate_update_util(struct update_util_data *data, u64 time, /* Start over if the CPU may have been idle. */ if (delta_ns > TICK_NSEC) { cpu->iowait_boost = ONE_EIGHTH_FP; - } else if (cpu->iowait_boost) { + } else if (cpu->iowait_boost >= ONE_EIGHTH_FP) { cpu->iowait_boost <<= 1; if (cpu->iowait_boost > int_tofp(1)) cpu->iowait_boost = int_tofp(1); From 22782b3f9bb8ae21c710e2880db21bc729771e92 Mon Sep 17 00:00:00 2001 From: "Rafael J. Wysocki" Date: Tue, 12 Mar 2019 19:13:13 +0100 Subject: [PATCH 17/17] cpuidle: governor: Add new governors to cpuidle_governors again After commit 61cb5758d3c4 ("cpuidle: Add cpuidle.governor= command line parameter") new cpuidle governors are not added to the list of available governors, so governor selection via sysfs doesn't work as expected (even though it is rarely used anyway). Fix that by making cpuidle_register_governor() add new governors to cpuidle_governors again. Fixes: 61cb5758d3c4 ("cpuidle: Add cpuidle.governor= command line parameter") Reported-by: Kees Cook Cc: 5.0+ # 5.0+ Signed-off-by: Rafael J. Wysocki --- drivers/cpuidle/governor.c | 1 + 1 file changed, 1 insertion(+) diff --git a/drivers/cpuidle/governor.c b/drivers/cpuidle/governor.c index bb93e5cf6a4a..9fddf828a76f 100644 --- a/drivers/cpuidle/governor.c +++ b/drivers/cpuidle/governor.c @@ -89,6 +89,7 @@ int cpuidle_register_governor(struct cpuidle_governor *gov) mutex_lock(&cpuidle_lock); if (__cpuidle_find_governor(gov->name) == NULL) { ret = 0; + list_add_tail(&gov->governor_list, &cpuidle_governors); if (!cpuidle_curr_governor || !strncasecmp(param_governor, gov->name, CPUIDLE_NAME_LEN) || (cpuidle_curr_governor->rating < gov->rating &&