From 4108b3d96273784f697dd6d8e59ef9203a10a02d Mon Sep 17 00:00:00 2001 From: Len Brown Date: Tue, 16 Dec 2014 01:52:06 -0500 Subject: cpuidle: menu: Better idle duration measurement without using CPUIDLE_FLAG_TIME_INVALID When menu sees CPUIDLE_FLAG_TIME_INVALID, it ignores its timestamps, and assumes that idle lasted as long as the time till next predicted timer expiration. But if an interrupt was seen and serviced before that duration, it would actually be more accurate to use the measured time rather than rounding up to the next predicted timer expiration. And if an interrupt is seen and serviced such that the mesured time exceeds the time till next predicted timer expiration, then truncating to that expiration is the right thing to do -- since we can never stay idle past that timer expiration. So the code can do a better job without checking for CPUIDLE_FLAG_TIME_INVALID. Signed-off-by: Len Brown Acked-by: Daniel Lezcano Reviewed-by: Tuukka Tikkanen Signed-off-by: Rafael J. Wysocki --- drivers/cpuidle/governors/menu.c | 25 ++++++++++--------------- 1 file changed, 10 insertions(+), 15 deletions(-) (limited to 'drivers') diff --git a/drivers/cpuidle/governors/menu.c b/drivers/cpuidle/governors/menu.c index 659d7b0c9eb..40580794e23 100644 --- a/drivers/cpuidle/governors/menu.c +++ b/drivers/cpuidle/governors/menu.c @@ -396,8 +396,8 @@ static void menu_update(struct cpuidle_driver *drv, struct cpuidle_device *dev) * power state and occurrence of the wakeup event. * * If the entered idle state didn't support residency measurements, - * we are basically lost in the dark how much time passed. - * As a compromise, assume we slept for the whole expected time. + * we use them anyway if they are short, and if long, + * truncate to the whole expected time. * * Any measured amount of time will include the exit latency. * Since we are interested in when the wakeup begun, not when it @@ -405,22 +405,17 @@ static void menu_update(struct cpuidle_driver *drv, struct cpuidle_device *dev) * the measured amount of time is less than the exit latency, * assume the state was never reached and the exit latency is 0. */ - if (unlikely(target->flags & CPUIDLE_FLAG_TIME_INVALID)) { - /* Use timer value as is */ - measured_us = data->next_timer_us; - } else { - /* Use measured value */ - measured_us = cpuidle_get_last_residency(dev); + /* measured value */ + measured_us = cpuidle_get_last_residency(dev); - /* Deduct exit latency */ - if (measured_us > target->exit_latency) - measured_us -= target->exit_latency; + /* Deduct exit latency */ + if (measured_us > target->exit_latency) + measured_us -= target->exit_latency; - /* Make sure our coefficients do not exceed unity */ - if (measured_us > data->next_timer_us) - measured_us = data->next_timer_us; - } + /* Make sure our coefficients do not exceed unity */ + if (measured_us > data->next_timer_us) + measured_us = data->next_timer_us; /* Update our correction ratio */ new_factor = data->correction_factor[data->bucket]; -- cgit v1.2.3-70-g09d2 From b73026b9c959600bcd65eeae7a5f7ac00ded886f Mon Sep 17 00:00:00 2001 From: Len Brown Date: Tue, 16 Dec 2014 01:52:07 -0500 Subject: cpuidle: ladder: Better idle duration measurement without using CPUIDLE_FLAG_TIME_INVALID When the ladder governor sees the CPUIDLE_FLAG_TIME_INVALID flag, it unconditionally causes a state promotion by setting last_residency to a number higher than the state's promotion_time: last_residency = last_state->threshold.promotion_time + 1 It does this for fear that cpuidle_get_last_residency() will be in-accurate, because cpuidle_enter_state() invoked a state with CPUIDLE_FLAG_TIME_INVALID. But the only state with CPUIDLE_FLAG_TIME_INVALID is acpi_safe_halt(), which may return well after its actual idle duration because it enables interrupts, so cpuidle_enter_state() also measures interrupt service time. So what? In ladder, a huge invalid last_residency has exactly the same effect as the current code -- it unconditionally causes a state promotion. In the case where the idle residency plus measured interrupt handling time is less than the state's demotion_time -- we should use that timestamp to give ladder a chance to demote, rather than unconditionally promoting. This can be done by simply ignoring the CPUIDLE_FLAG_TIME_INVALID, and using the "invalid" time, as it is either equal to what we are doing today, or better. Signed-off-by: Len Brown Acked-by: Daniel Lezcano Signed-off-by: Rafael J. Wysocki --- drivers/cpuidle/governors/ladder.c | 7 +------ 1 file changed, 1 insertion(+), 6 deletions(-) (limited to 'drivers') diff --git a/drivers/cpuidle/governors/ladder.c b/drivers/cpuidle/governors/ladder.c index 37263d9a105..401c0106ed3 100644 --- a/drivers/cpuidle/governors/ladder.c +++ b/drivers/cpuidle/governors/ladder.c @@ -79,12 +79,7 @@ static int ladder_select_state(struct cpuidle_driver *drv, last_state = &ldev->states[last_idx]; - if (!(drv->states[last_idx].flags & CPUIDLE_FLAG_TIME_INVALID)) { - last_residency = cpuidle_get_last_residency(dev) - \ - drv->states[last_idx].exit_latency; - } - else - last_residency = last_state->threshold.promotion_time + 1; + last_residency = cpuidle_get_last_residency(dev) - drv->states[last_idx].exit_latency; /* consider promotion */ if (last_idx < drv->state_count - 1 && -- cgit v1.2.3-70-g09d2 From 62c4cf97e82cf79446642e599d155884f600cf17 Mon Sep 17 00:00:00 2001 From: Len Brown Date: Tue, 16 Dec 2014 01:52:08 -0500 Subject: cpuidle / ACPI: remove unused CPUIDLE_FLAG_TIME_INVALID CPUIDLE_FLAG_TIME_INVALID is no longer checked by menu or ladder cpuidle governors, so don't bother setting or defining it. It was originally invented to account for the fact that acpi_safe_halt() enables interrupts to invoke HLT. That would allow interrupt service routines to be included in the last_idle duration measurements made in cpuidle_enter_state(), potentially returning a duration much larger than reality. But menu and ladder can gracefully handle erroneously large duration intervals without checking for CPUIDLE_FLAG_TIME_INVALID. Further, if they don't check CPUIDLE_FLAG_TIME_INVALID, they can also benefit from the instances when the duration interval is not erroneously large. Signed-off-by: Len Brown Acked-by: Daniel Lezcano Signed-off-by: Rafael J. Wysocki --- drivers/acpi/processor_idle.c | 2 -- include/linux/cpuidle.h | 3 --- 2 files changed, 5 deletions(-) (limited to 'drivers') diff --git a/drivers/acpi/processor_idle.c b/drivers/acpi/processor_idle.c index 380b4b43f36..7afba40e350 100644 --- a/drivers/acpi/processor_idle.c +++ b/drivers/acpi/processor_idle.c @@ -985,8 +985,6 @@ static int acpi_processor_setup_cpuidle_states(struct acpi_processor *pr) state->flags = 0; switch (cx->type) { case ACPI_STATE_C1: - if (cx->entry_method != ACPI_CSTATE_FFH) - state->flags |= CPUIDLE_FLAG_TIME_INVALID; state->enter = acpi_idle_enter_c1; state->enter_dead = acpi_idle_play_dead; diff --git a/include/linux/cpuidle.h b/include/linux/cpuidle.h index a07e087f54b..ab70f3bc44a 100644 --- a/include/linux/cpuidle.h +++ b/include/linux/cpuidle.h @@ -53,7 +53,6 @@ struct cpuidle_state { }; /* Idle State Flags */ -#define CPUIDLE_FLAG_TIME_INVALID (0x01) /* is residency time measurable? */ #define CPUIDLE_FLAG_COUPLED (0x02) /* state applies to multiple cpus */ #define CPUIDLE_FLAG_TIMER_STOP (0x04) /* timer is stopped on this state */ @@ -89,8 +88,6 @@ DECLARE_PER_CPU(struct cpuidle_device, cpuidle_dev); /** * cpuidle_get_last_residency - retrieves the last state's residency time * @dev: the target CPU - * - * NOTE: this value is invalid if CPUIDLE_FLAG_TIME_INVALID is set */ static inline int cpuidle_get_last_residency(struct cpuidle_device *dev) { -- cgit v1.2.3-70-g09d2 From 7496fcbe8a643097efc061160e1c3b65ee2fa350 Mon Sep 17 00:00:00 2001 From: Amit Daniel Kachhap Date: Mon, 15 Dec 2014 09:08:59 +0530 Subject: PM / Domains: Export of_genpd_get_from_provider function This function looks up a PM domain form the provider. This will be useful to add parent/child domain relationship from the SoC specific code. The caller of the function must make sure that PM domain provider is already registered. Reviewed-by: Ulf Hansson Signed-off-by: Amit Daniel Kachhap Signed-off-by: Rafael J. Wysocki --- drivers/base/power/domain.c | 3 ++- include/linux/pm_domain.h | 8 ++++++++ 2 files changed, 10 insertions(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/base/power/domain.c b/drivers/base/power/domain.c index 5d7b7548873..1bd119efaac 100644 --- a/drivers/base/power/domain.c +++ b/drivers/base/power/domain.c @@ -2108,7 +2108,7 @@ EXPORT_SYMBOL_GPL(of_genpd_del_provider); * Returns a valid pointer to struct generic_pm_domain on success or ERR_PTR() * on failure. */ -static struct generic_pm_domain *of_genpd_get_from_provider( +struct generic_pm_domain *of_genpd_get_from_provider( struct of_phandle_args *genpdspec) { struct generic_pm_domain *genpd = ERR_PTR(-ENOENT); @@ -2128,6 +2128,7 @@ static struct generic_pm_domain *of_genpd_get_from_provider( return genpd; } +EXPORT_SYMBOL_GPL(of_genpd_get_from_provider); /** * genpd_dev_pm_detach - Detach a device from its PM domain. diff --git a/include/linux/pm_domain.h b/include/linux/pm_domain.h index 1dd6c7f6416..ba7ca5468a7 100644 --- a/include/linux/pm_domain.h +++ b/include/linux/pm_domain.h @@ -275,6 +275,8 @@ typedef struct generic_pm_domain *(*genpd_xlate_t)(struct of_phandle_args *args, int __of_genpd_add_provider(struct device_node *np, genpd_xlate_t xlate, void *data); void of_genpd_del_provider(struct device_node *np); +struct generic_pm_domain *of_genpd_get_from_provider( + struct of_phandle_args *genpdspec); struct generic_pm_domain *__of_genpd_xlate_simple( struct of_phandle_args *genpdspec, @@ -292,6 +294,12 @@ static inline int __of_genpd_add_provider(struct device_node *np, } static inline void of_genpd_del_provider(struct device_node *np) {} +static inline struct generic_pm_domain *of_genpd_get_from_provider( + struct of_phandle_args *genpdspec) +{ + return NULL; +} + #define __of_genpd_xlate_simple NULL #define __of_genpd_xlate_onecell NULL -- cgit v1.2.3-70-g09d2 From d72be771c5dbabaf3058ef382f4934aa31c88df2 Mon Sep 17 00:00:00 2001 From: Jacob Pan Date: Tue, 16 Dec 2014 09:52:47 -0800 Subject: powercap / RAPL: add IDs for future Xeon CPUs Enable RAPL driver on Xeon cpu id 0x56. Signed-off-by: Jacob Pan Signed-off-by: Rafael J. Wysocki --- drivers/powercap/intel_rapl.c | 1 + 1 file changed, 1 insertion(+) (limited to 'drivers') diff --git a/drivers/powercap/intel_rapl.c b/drivers/powercap/intel_rapl.c index c71443c4f26..97b5e4ee1ca 100644 --- a/drivers/powercap/intel_rapl.c +++ b/drivers/powercap/intel_rapl.c @@ -1041,6 +1041,7 @@ static const struct x86_cpu_id rapl_ids[] = { RAPL_CPU(0x45, rapl_defaults_core),/* Haswell ULT */ RAPL_CPU(0x4C, rapl_defaults_atom),/* Braswell */ RAPL_CPU(0x4A, rapl_defaults_atom),/* Tangier */ + RAPL_CPU(0x56, rapl_defaults_core),/* Future Xeon */ RAPL_CPU(0x5A, rapl_defaults_atom),/* Annidale */ {} }; -- cgit v1.2.3-70-g09d2 From b02ded246d011d0eb22efc178ee711b636214083 Mon Sep 17 00:00:00 2001 From: Dmitry Torokhov Date: Tue, 16 Dec 2014 15:09:36 -0800 Subject: PM / OPP: add some lockdep annotations Certain OPP APIs need to be called under RCU lock; let's add a few rcu_lockdep_assert() calls to warn about potential misuse. Signed-off-by: Dmitry Torokhov Acked-by: Viresh Kumar Signed-off-by: Rafael J. Wysocki --- drivers/base/power/opp.c | 16 ++++++++++++++++ 1 file changed, 16 insertions(+) (limited to 'drivers') diff --git a/drivers/base/power/opp.c b/drivers/base/power/opp.c index d24dd614a0b..b78c14d30da 100644 --- a/drivers/base/power/opp.c +++ b/drivers/base/power/opp.c @@ -108,6 +108,14 @@ static LIST_HEAD(dev_opp_list); /* Lock to allow exclusive modification to the device and opp lists */ static DEFINE_MUTEX(dev_opp_list_lock); +#define opp_rcu_lockdep_assert() \ +do { \ + rcu_lockdep_assert(rcu_read_lock_held() || \ + lockdep_is_held(&dev_opp_list_lock), \ + "Missing rcu_read_lock() or " \ + "dev_opp_list_lock protection"); \ +} while (0) + /** * find_device_opp() - find device_opp struct using device pointer * @dev: device pointer used to lookup device OPPs @@ -218,6 +226,8 @@ int dev_pm_opp_get_opp_count(struct device *dev) struct dev_pm_opp *temp_opp; int count = 0; + opp_rcu_lockdep_assert(); + dev_opp = find_device_opp(dev); if (IS_ERR(dev_opp)) { int r = PTR_ERR(dev_opp); @@ -267,6 +277,8 @@ struct dev_pm_opp *dev_pm_opp_find_freq_exact(struct device *dev, struct device_opp *dev_opp; struct dev_pm_opp *temp_opp, *opp = ERR_PTR(-ERANGE); + opp_rcu_lockdep_assert(); + dev_opp = find_device_opp(dev); if (IS_ERR(dev_opp)) { int r = PTR_ERR(dev_opp); @@ -313,6 +325,8 @@ struct dev_pm_opp *dev_pm_opp_find_freq_ceil(struct device *dev, struct device_opp *dev_opp; struct dev_pm_opp *temp_opp, *opp = ERR_PTR(-ERANGE); + opp_rcu_lockdep_assert(); + if (!dev || !freq) { dev_err(dev, "%s: Invalid argument freq=%p\n", __func__, freq); return ERR_PTR(-EINVAL); @@ -361,6 +375,8 @@ struct dev_pm_opp *dev_pm_opp_find_freq_floor(struct device *dev, struct device_opp *dev_opp; struct dev_pm_opp *temp_opp, *opp = ERR_PTR(-ERANGE); + opp_rcu_lockdep_assert(); + if (!dev || !freq) { dev_err(dev, "%s: Invalid argument freq=%p\n", __func__, freq); return ERR_PTR(-EINVAL); -- cgit v1.2.3-70-g09d2 From 0fe30da2cb43782ee62d30c00a273d6934e5370e Mon Sep 17 00:00:00 2001 From: Dmitry Torokhov Date: Tue, 16 Dec 2014 15:09:37 -0800 Subject: PM / OPP: fix warning in of_free_opp_table() Not having OPP defined for a device is not a crime, we should not splat warning in this case. Also, it seems that we are ready to accept invalid dev (find_device_opp will return ERR_PTR(-EINVAL) then) so let's not crash in dev_name() in such case. Signed-off-by: Dmitry Torokhov Acked-by: Viresh Kumar Signed-off-by: Rafael J. Wysocki --- drivers/base/power/opp.c | 10 ++++++++-- 1 file changed, 8 insertions(+), 2 deletions(-) (limited to 'drivers') diff --git a/drivers/base/power/opp.c b/drivers/base/power/opp.c index b78c14d30da..aac7abcf74f 100644 --- a/drivers/base/power/opp.c +++ b/drivers/base/power/opp.c @@ -799,9 +799,15 @@ void of_free_opp_table(struct device *dev) /* Check for existing list for 'dev' */ dev_opp = find_device_opp(dev); - if (WARN(IS_ERR(dev_opp), "%s: dev_opp: %ld\n", dev_name(dev), - PTR_ERR(dev_opp))) + if (IS_ERR(dev_opp)) { + int error = PTR_ERR(dev_opp); + if (error != -ENODEV) + WARN(1, "%s: dev_opp: %d\n", + IS_ERR_OR_NULL(dev) ? + "Invalid device" : dev_name(dev), + error); return; + } /* Hold our list modification lock here */ mutex_lock(&dev_opp_list_lock); -- cgit v1.2.3-70-g09d2 From b4718c02f49ab5e1452353f0fae78beabe81467c Mon Sep 17 00:00:00 2001 From: Dmitry Torokhov Date: Tue, 16 Dec 2014 15:09:38 -0800 Subject: PM / OPP: take RCU lock in dev_pm_opp_get_opp_count A lot of callers are missing the fact that dev_pm_opp_get_opp_count needs to be called under RCU lock. Given that RCU locks can safely be nested, instead of providing *_locked() API, let's take RCU lock inside dev_pm_opp_get_opp_count() and leave callers as is. Signed-off-by: Dmitry Torokhov Acked-by: Viresh Kumar Signed-off-by: Rafael J. Wysocki --- drivers/base/power/opp.c | 15 ++++++++------- 1 file changed, 8 insertions(+), 7 deletions(-) (limited to 'drivers') diff --git a/drivers/base/power/opp.c b/drivers/base/power/opp.c index aac7abcf74f..106c6935930 100644 --- a/drivers/base/power/opp.c +++ b/drivers/base/power/opp.c @@ -216,9 +216,7 @@ EXPORT_SYMBOL_GPL(dev_pm_opp_get_freq); * This function returns the number of available opps if there are any, * else returns 0 if none or the corresponding error value. * - * Locking: This function must be called under rcu_read_lock(). This function - * internally references two RCU protected structures: device_opp and opp which - * are safe as long as we are under a common RCU locked section. + * Locking: This function takes rcu_read_lock(). */ int dev_pm_opp_get_opp_count(struct device *dev) { @@ -226,13 +224,14 @@ int dev_pm_opp_get_opp_count(struct device *dev) struct dev_pm_opp *temp_opp; int count = 0; - opp_rcu_lockdep_assert(); + rcu_read_lock(); dev_opp = find_device_opp(dev); if (IS_ERR(dev_opp)) { - int r = PTR_ERR(dev_opp); - dev_err(dev, "%s: device OPP not found (%d)\n", __func__, r); - return r; + count = PTR_ERR(dev_opp); + dev_err(dev, "%s: device OPP not found (%d)\n", + __func__, count); + goto out_unlock; } list_for_each_entry_rcu(temp_opp, &dev_opp->opp_list, node) { @@ -240,6 +239,8 @@ int dev_pm_opp_get_opp_count(struct device *dev) count++; } +out_unlock: + rcu_read_unlock(); return count; } EXPORT_SYMBOL_GPL(dev_pm_opp_get_opp_count); -- cgit v1.2.3-70-g09d2 From 62a041a4f58f32989460e37cb4f9aed5183f357f Mon Sep 17 00:00:00 2001 From: Dmitry Torokhov Date: Tue, 16 Dec 2014 15:09:39 -0800 Subject: cpufreq-dt: defer probing if OPP table is not ready cpufreq-dt driver supports mode when OPP table is provided by platform code and not device tree. However on certain platforms code that fills OPP table may run after cpufreq driver tries to initialize, so let's report -EPROBE_DEFER if we do not find any entires in OPP table for the CPU. Signed-off-by: Dmitry Torokhov Acked-by: Viresh Kumar Signed-off-by: Rafael J. Wysocki --- drivers/cpufreq/cpufreq-dt.c | 11 +++++++++++ 1 file changed, 11 insertions(+) (limited to 'drivers') diff --git a/drivers/cpufreq/cpufreq-dt.c b/drivers/cpufreq/cpufreq-dt.c index 9bc2720628a..538abd50b77 100644 --- a/drivers/cpufreq/cpufreq-dt.c +++ b/drivers/cpufreq/cpufreq-dt.c @@ -211,6 +211,17 @@ static int cpufreq_init(struct cpufreq_policy *policy) /* OPPs might be populated at runtime, don't check for error here */ of_init_opp_table(cpu_dev); + /* + * But we need OPP table to function so if it is not there let's + * give platform code chance to provide it for us. + */ + ret = dev_pm_opp_get_opp_count(cpu_dev); + if (ret <= 0) { + pr_debug("OPP table is not ready, deferring probe\n"); + ret = -EPROBE_DEFER; + goto out_free_opp; + } + priv = kzalloc(sizeof(*priv), GFP_KERNEL); if (!priv) { ret = -ENOMEM; -- cgit v1.2.3-70-g09d2 From cb57720bf79688d64854a0a43565aa52303c1f3f Mon Sep 17 00:00:00 2001 From: Ethan Zhao Date: Thu, 18 Dec 2014 15:28:19 +0900 Subject: cpufreq: fix a NULL pointer dereference in __cpufreq_governor() If ACPI _PPC changed notification happens before governor was initiated while kernel is booting, a NULL pointer dereference will be triggered: BUG: unable to handle kernel NULL pointer dereference at 0000000000000030 IP: [] __cpufreq_governor+0x23/0x1e0 PGD 0 Oops: 0000 [#1] SMP ... ... RIP: 0010:[] [] __cpufreq_governor+0x23/0x1e0 RSP: 0018:ffff881fcfbcfbb8 EFLAGS: 00010286 RAX: 0000000000000000 RBX: ffff881fd11b3980 RCX: ffff88407fc20000 RDX: 0000000000000000 RSI: 0000000000000000 RDI: ffff881fd11b3980 RBP: ffff881fcfbcfbd8 R08: 0000000000000000 R09: 000000000000000f R10: ffffffff818068d0 R11: 0000000000000043 R12: 0000000000000004 R13: 0000000000000000 R14: ffffffff8196cae0 R15: 0000000000000000 FS: 0000000000000000(0000) GS:ffff881fffc00000(0000) knlGS:0000000000000000 CS: 0010 DS: 0000 ES: 0000 CR0: 0000000080050033 CR2: 0000000000000030 CR3: 00000000018ae000 CR4: 00000000000407f0 DR0: 0000000000000000 DR1: 0000000000000000 DR2: 0000000000000000 DR3: 0000000000000000 DR6: 00000000ffff0ff0 DR7: 0000000000000400 Process kworker/0:3 (pid: 750, threadinfo ffff881fcfbce000, task ffff881fcf556400) Stack: ffff881fffc17d00 ffff881fcfbcfc18 ffff881fd11b3980 0000000000000000 ffff881fcfbcfc08 ffffffff81470d08 ffff881fd11b3980 0000000000000007 ffff881fcfbcfc18 ffff881fffc17d00 ffff881fcfbcfd28 ffffffff81472e9a Call Trace: [] __cpufreq_set_policy+0x1b8/0x2e0 [] cpufreq_update_policy+0xca/0x150 [] ? cpufreq_update_policy+0x150/0x150 [] acpi_processor_ppc_has_changed+0x71/0x7b [] acpi_processor_notify+0x55/0x115 [] acpi_device_notify+0x19/0x1b [] acpi_ev_notify_dispatch+0x41/0x5f [] acpi_os_execute_deferred+0x27/0x34 The root cause is a race conditon -- cpufreq core and acpi-cpufreq driver were initiated, but cpufreq_governor wasn't and _PPC changed notification happened, __cpufreq_governor() was called within acpi_os_execute_deferred kernel thread context. To fix this panic issue, add pointer checking code in __cpufreq_governor() before pointer policy->governor is to be dereferenced. Signed-off-by: Ethan Zhao Acked-by: Viresh Kumar Signed-off-by: Rafael J. Wysocki --- drivers/cpufreq/cpufreq.c | 6 ++++++ 1 file changed, 6 insertions(+) (limited to 'drivers') diff --git a/drivers/cpufreq/cpufreq.c b/drivers/cpufreq/cpufreq.c index a09a29c312a..46bed4f81cd 100644 --- a/drivers/cpufreq/cpufreq.c +++ b/drivers/cpufreq/cpufreq.c @@ -2028,6 +2028,12 @@ static int __cpufreq_governor(struct cpufreq_policy *policy, /* Don't start any governor operations if we are entering suspend */ if (cpufreq_suspended) return 0; + /* + * Governor might not be initiated here if ACPI _PPC changed + * notification happened, so check it. + */ + if (!policy->governor) + return -EINVAL; if (policy->governor->max_transition_latency && policy->cpuinfo.transition_latency > -- cgit v1.2.3-70-g09d2 From 7d0b93499f4879ddbc75d594f4ea216ba964f78e Mon Sep 17 00:00:00 2001 From: Aaron Lu Date: Mon, 22 Dec 2014 15:18:05 +0800 Subject: ACPI / video: Add some Samsung models to disable_native_backlight list Several Samsung laptop models (SAMSUNG 870Z5E/880Z5E/680Z5E and SAMSUNG 370R4E/370R4V/370R5E/3570RE/370R5V) do not have a working native backlight control interface so restore their acpi_videoX interface. Link: https://bugzilla.kernel.org/show_bug.cgi?id=84221 Link: https://bugzilla.kernel.org/show_bug.cgi?id=84651 For SAMSUNG 870Z5E/880Z5E/680Z5E: Reported-and-tested-by: Brent Saner Reported-by: Vitaliy Filippov Reported-by: Laszlo KREKACS For SAMSUNG 370R4E/370R4V/370R5E/3570RE/370R5V: Reported-by: Vladimir Perepechin Cc: 3.17+ # 3.17+ Signed-off-by: Aaron Lu Signed-off-by: Rafael J. Wysocki --- drivers/acpi/video.c | 17 +++++++++++++++++ 1 file changed, 17 insertions(+) (limited to 'drivers') diff --git a/drivers/acpi/video.c b/drivers/acpi/video.c index 1eaadff2e19..c72e79d2c5a 100644 --- a/drivers/acpi/video.c +++ b/drivers/acpi/video.c @@ -505,6 +505,23 @@ static struct dmi_system_id video_dmi_table[] __initdata = { DMI_MATCH(DMI_PRODUCT_NAME, "HP ENVY 15 Notebook PC"), }, }, + + { + .callback = video_disable_native_backlight, + .ident = "SAMSUNG 870Z5E/880Z5E/680Z5E", + .matches = { + DMI_MATCH(DMI_SYS_VENDOR, "SAMSUNG ELECTRONICS CO., LTD."), + DMI_MATCH(DMI_PRODUCT_NAME, "870Z5E/880Z5E/680Z5E"), + }, + }, + { + .callback = video_disable_native_backlight, + .ident = "SAMSUNG 370R4E/370R4V/370R5E/3570RE/370R5V", + .matches = { + DMI_MATCH(DMI_SYS_VENDOR, "SAMSUNG ELECTRONICS CO., LTD."), + DMI_MATCH(DMI_PRODUCT_NAME, "370R4E/370R4V/370R5E/3570RE/370R5V"), + }, + }, {} }; -- cgit v1.2.3-70-g09d2