cpufreq: interactive: Fix null pointer dereference in interactive governor
For the sync_freq feature currently we check pcpu->policy->cur frequency
for each online cpu. But for a CPU that isn't using interactive governor
or for an offline CPU, pcpu->policy can be null or an invalid value.
This patch tries to avoid that scenario by using pcpu->target_freq
instead of policy->cur to get the frequency of an online CPU.
Kernel crash without this patch:
[ 20.132373] Unable to handle kernel NULL pointer dereference at virtual address 00000028
[ 20.132375] pgd = c34f34c0
[ 20.132377] pgd = ef6f2440
[ 20.132383] [00000028] *pgd=00000000
[ 20.132385]
[ 20.132388] [00000028] *pgd=2e98f003, *pmd=00000000
[ 20.132390] Internal error: Oops: 205 [#1] PREEMPT SMP ARM
[ 20.132394] Modules linked in:
[ 20.132398] CPU: 0 PID: 1560 Comm: chown Tainted: G W 3.10.0-perf-gb12057b-00001-ga2c6c16-dirty #7
[ 20.132401] task: ef9af300 ti: ee49c000 task.ti: ee49c000
[ 20.132411] PC is at cpufreq_interactive_timer+0x10c/0x650
[ 20.132415] LR is at cpufreq_interactive_timer+0x128/0x650
<snip>
[ 20.133002] [<c07eb204>] (cpufreq_interactive_timer+0x10c/0x650) from [<c02804d8>] (call_timer_fn+0x80/0x198)
[ 20.133012] [<c02804d8>] (call_timer_fn+0x80/0x198) from [<c0280acc>] (run_timer_softirq+0x1f8/0x270)
[ 20.133019] [<c0280acc>] (run_timer_softirq+0x1f8/0x270) from [<c0279e20>] (__do_softirq+0x12c/0x2d4)
[ 20.133025] [<c0279e20>] (__do_softirq+0x12c/0x2d4) from [<c027a2d4>] (irq_exit+0x74/0xc8)
[ 20.133034] [<c027a2d4>] (irq_exit+0x74/0xc8) from [<c0206a00>] (handle_IRQ+0x68/0x8c)
[ 20.133041] [<c0206a00>] (handle_IRQ+0x68/0x8c) from [<c02004b8>] (gic_handle_irq+0x3c/0x60)
[ 20.133051] [<c02004b8>] (gic_handle_irq+0x3c/0x60) from [<c0ac6900>] (__irq_svc+0x40/0x70)
<snip>
Change-Id: Ie834f5d383de4d41e0fe6fbd40c8b0a0c05d82f5
Signed-off-by: Vijay Ganti <viganti@codeaurora.org>
diff --git a/drivers/cpufreq/cpufreq_interactive.c b/drivers/cpufreq/cpufreq_interactive.c
index 45a41eb..e96d577 100644
--- a/drivers/cpufreq/cpufreq_interactive.c
+++ b/drivers/cpufreq/cpufreq_interactive.c
@@ -445,7 +445,7 @@
continue;
max_load = max(max_load, picpu->prev_load);
- max_freq = max(max_freq, picpu->policy->cur);
+ max_freq = max(max_freq, picpu->target_freq);
}
if (max_freq > up_threshold_any_cpu_freq &&
@@ -1283,6 +1283,7 @@
pcpu = &per_cpu(cpuinfo, j);
down_write(&pcpu->enable_sem);
pcpu->governor_enabled = 0;
+ pcpu->target_freq = 0;
del_timer_sync(&pcpu->cpu_timer);
del_timer_sync(&pcpu->cpu_slack_timer);
up_write(&pcpu->enable_sem);