From 72368d122c7479aa6e14fbbd334717b8a0c157a6 Mon Sep 17 00:00:00 2001 From: Rafael J. Wysocki Date: Fri, 27 Dec 2013 01:07:11 +0100 Subject: cpufreq: Clean up after a failing light-weight initialization If cpufreq_policy_restore() returns NULL during system resume, __cpufreq_add_dev() should just fall back to the full initialization instead of returning an error, because that may actually make things work. Moreover, it should not leave stale fallback data behind after it has failed to restore a previously existing policy. This change is based on Viresh Kumar's work. Fixes: 5302c3fb2e62 ("cpufreq: Perform light-weight init/teardown during suspend/resume") Reported-by: Bjørn Mork Signed-off-by: Rafael J. Wysocki Acked-by: Viresh Kumar Cc: 3.12+ # 3.12+ --- drivers/cpufreq/cpufreq.c | 23 ++++++++++++++--------- 1 file changed, 14 insertions(+), 9 deletions(-) (limited to 'drivers') diff --git a/drivers/cpufreq/cpufreq.c b/drivers/cpufreq/cpufreq.c index 16d7b4ac94be..f13a663d1da5 100644 --- a/drivers/cpufreq/cpufreq.c +++ b/drivers/cpufreq/cpufreq.c @@ -1016,15 +1016,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 @@ -1118,8 +1120,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: -- cgit v1.2.3 From 08fd8c1cf0a99abf34e09a8b99b74872e0d73a23 Mon Sep 17 00:00:00 2001 From: Viresh Kumar Date: Tue, 24 Dec 2013 07:11:01 +0530 Subject: cpufreq: preserve user_policy across suspend/resume Prevent __cpufreq_add_dev() from overwriting the existing values of user_policy.{min|max|policy|governor} with defaults during resume from system suspend. Fixes: 5302c3fb2e62 ("cpufreq: Perform light-weight init/teardown during suspend/resume") Reported-by: Bjørn Mork Signed-off-by: Viresh Kumar Cc: 3.12+ # 3.12+ [rjw: Changelog] Signed-off-by: Rafael J. Wysocki --- drivers/cpufreq/cpufreq.c | 14 +++++++++----- 1 file changed, 9 insertions(+), 5 deletions(-) (limited to 'drivers') diff --git a/drivers/cpufreq/cpufreq.c b/drivers/cpufreq/cpufreq.c index f13a663d1da5..8d19f7c06010 100644 --- a/drivers/cpufreq/cpufreq.c +++ b/drivers/cpufreq/cpufreq.c @@ -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) @@ -1071,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); @@ -1103,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); -- cgit v1.2.3 From 5781532ebecd9e0b7b5fc25d78030bdec635f4ac Mon Sep 17 00:00:00 2001 From: Andre Przywara Date: Fri, 13 Dec 2013 21:49:19 +0100 Subject: ARM/cpuidle: remove __init tag from Calxeda cpuidle probe function Commit 60a66e370007e8535b7a561353b07b37deaf35ba changed the Calxeda cpuidle driver to a platform driver, copying the __init tag from the _init() to the newly used _probe() function. However, "probe should not be __init." (Rob said ;-) Remove the __init tag to fix a section mismatch in the Calxeda cpuidle driver. Signed-off-by: Andre Przywara Signed-off-by: Daniel Lezcano --- drivers/cpuidle/cpuidle-calxeda.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/cpuidle/cpuidle-calxeda.c b/drivers/cpuidle/cpuidle-calxeda.c index 36795639df0d..6e51114057d0 100644 --- a/drivers/cpuidle/cpuidle-calxeda.c +++ b/drivers/cpuidle/cpuidle-calxeda.c @@ -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); } -- cgit v1.2.3 From 98a947abdd54e5de909bebadfced1696ccad30cf Mon Sep 17 00:00:00 2001 From: Rafael J. Wysocki Date: Tue, 31 Dec 2013 13:37:46 +0100 Subject: intel_pstate: Fail initialization if P-state information is missing If pstate.current_pstate is 0 after the initial intel_pstate_get_cpu_pstates(), this means that we were unable to obtain any useful P-state information and there is no reason to continue, so free memory and return an error in that case. This fixes the following divide error occuring in a nested KVM guest: Intel P-state driver initializing. Intel pstate controlling: cpu 0 cpufreq: __cpufreq_add_dev: ->get() failed divide error: 0000 [#1] SMP Modules linked in: CPU: 0 PID: 1 Comm: swapper/0 Not tainted 3.13.0-0.rc4.git5.1.fc21.x86_64 #1 Hardware name: Bochs Bochs, BIOS Bochs 01/01/2011 task: ffff88001ea20000 ti: ffff88001e9bc000 task.ti: ffff88001e9bc000 RIP: 0010:[] [] intel_pstate_timer_func+0x11d/0x2b0 RSP: 0000:ffff88001ee03e18 EFLAGS: 00010246 RAX: 0000000000000000 RBX: ffff88001a454348 RCX: 0000000000006100 RDX: 0000000000000000 RSI: 0000000000000000 RDI: 0000000000000000 RBP: ffff88001ee03e38 R08: 0000000000000000 R09: 0000000000000000 R10: ffff88001ea20000 R11: 0000000000000000 R12: 00000c0a1ea20000 R13: 1ea200001ea20000 R14: ffffffff815c5400 R15: ffff88001a454348 FS: 0000000000000000(0000) GS:ffff88001ee00000(0000) knlGS:0000000000000000 CS: 0010 DS: 0000 ES: 0000 CR0: 000000008005003b CR2: 0000000000000000 CR3: 0000000001c0c000 CR4: 00000000000006f0 Stack: fffffffb1a454390 ffffffff821a4500 ffff88001a454390 0000000000000100 ffff88001ee03ea8 ffffffff81083e9a ffffffff81083e15 ffffffff82d5ed40 ffffffff8258cc60 0000000000000000 ffffffff81ac39de 0000000000000000 Call Trace: [] call_timer_fn+0x8a/0x310 [] ? call_timer_fn+0x5/0x310 [] ? pid_param_set+0x130/0x130 [] run_timer_softirq+0x234/0x380 [] __do_softirq+0x104/0x430 [] irq_exit+0xcd/0xe0 [] smp_apic_timer_interrupt+0x45/0x60 [] apic_timer_interrupt+0x72/0x80 [] ? vprintk_emit+0x1dd/0x5e0 [] printk+0x67/0x69 [] __cpufreq_add_dev.isra.13+0x883/0x8d0 [] cpufreq_add_dev+0x10/0x20 [] subsys_interface_register+0xb1/0xf0 [] cpufreq_register_driver+0x9f/0x210 [] intel_pstate_init+0x27d/0x3be [] ? mutex_unlock+0xe/0x10 [] ? cpufreq_gov_dbs_init+0x12/0x12 [] do_one_initcall+0xfa/0x1b0 [] ? parse_args+0x225/0x3f0 [] kernel_init_freeable+0x1fc/0x287 [] ? do_early_param+0x88/0x88 [] ? rest_init+0x150/0x150 [] kernel_init+0xe/0x130 [] ret_from_fork+0x7c/0xb0 [] ? rest_init+0x150/0x150 Code: c1 e0 05 48 63 bc 03 10 01 00 00 48 63 83 d0 00 00 00 48 63 d6 48 c1 e2 08 c1 e1 08 4c 63 c2 48 c1 e0 08 48 98 48 c1 e0 08 48 99 <49> f7 f8 48 98 48 0f af f8 48 c1 ff 08 29 f9 89 ca c1 fa 1f 89 RIP [] intel_pstate_timer_func+0x11d/0x2b0 RSP ---[ end trace f166110ed22cc37a ]--- Kernel panic - not syncing: Fatal exception in interrupt Reported-and-tested-by: Kashyap Chamarthy Cc: Josh Boyer Signed-off-by: Rafael J. Wysocki Cc: All applicable --- drivers/cpufreq/intel_pstate.c | 5 +++++ 1 file changed, 5 insertions(+) (limited to 'drivers') diff --git a/drivers/cpufreq/intel_pstate.c b/drivers/cpufreq/intel_pstate.c index 5f1cbae36961..f9d561e198ab 100644 --- a/drivers/cpufreq/intel_pstate.c +++ b/drivers/cpufreq/intel_pstate.c @@ -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; -- cgit v1.2.3