From be3e4ce734139ed581c3e1064647f49864baa6fe Mon Sep 17 00:00:00 2001 From: kettenis Date: Thu, 4 Jun 2015 18:01:44 +0000 Subject: [PATCH] The (no quite so) new kernel perfpolicy code calls cpu_setperf() from a timeout. Unfortunately the smu(4) CPU voltage slewing code sleeps, which causes a kernel panic. Prevent this by delegating the CPU frequency switching and voltage slewing to a task. ok mpi@ --- sys/arch/macppc/dev/smu.c | 6 +++++- sys/arch/macppc/macppc/cpu.c | 21 +++++++++++++++++---- 2 files changed, 22 insertions(+), 5 deletions(-) diff --git a/sys/arch/macppc/dev/smu.c b/sys/arch/macppc/dev/smu.c index 28e8ac155f3..d811aa29b0c 100644 --- a/sys/arch/macppc/dev/smu.c +++ b/sys/arch/macppc/dev/smu.c @@ -1,4 +1,4 @@ -/* $OpenBSD: smu.c,v 1.26 2014/10/08 16:07:45 deraadt Exp $ */ +/* $OpenBSD: smu.c,v 1.27 2015/06/04 18:01:44 kettenis Exp $ */ /* * Copyright (c) 2005 Mark Kettenis @@ -742,6 +742,8 @@ smu_slew_voltage(u_int freq_scale) struct smu_softc *sc = smu_cd.cd_devs[0]; struct smu_cmd *cmd = (struct smu_cmd *)sc->sc_cmd; + rw_enter_write(&sc->sc_lock); + cmd->cmd = SMU_POWER; cmd->len = 8; memcpy(cmd->data, "VSLEW", 5); @@ -750,4 +752,6 @@ smu_slew_voltage(u_int freq_scale) cmd->data[7] = freq_scale; smu_do_cmd(sc, 250); + + rw_exit_write(&sc->sc_lock); } diff --git a/sys/arch/macppc/macppc/cpu.c b/sys/arch/macppc/macppc/cpu.c index c6b055e5234..db486dcc1bf 100644 --- a/sys/arch/macppc/macppc/cpu.c +++ b/sys/arch/macppc/macppc/cpu.c @@ -1,4 +1,4 @@ -/* $OpenBSD: cpu.c,v 1.81 2015/03/31 16:00:38 mpi Exp $ */ +/* $OpenBSD: cpu.c,v 1.82 2015/06/04 18:01:44 kettenis Exp $ */ /* * Copyright (c) 1997 Per Fogelstrom @@ -37,6 +37,7 @@ #include #include #include +#include #include #include @@ -155,10 +156,13 @@ ppc64_scale_frequency(u_int freq_scale) extern int perflevel; +struct task ppc64_setperf_task; +int ppc64_perflevel; + void -ppc64_setperf(int speed) +ppc64_do_setperf(void *arg) { - if (speed <= 50) { + if (ppc64_perflevel <= 50) { if (ppc_curfreq == ppc_maxfreq / 2) return; @@ -175,6 +179,13 @@ ppc64_setperf(int speed) } } +void +ppc64_setperf(int level) +{ + ppc64_perflevel = level; + task_add(systq, &ppc64_setperf_task); +} + void cpuattach(struct device *parent, struct device *dev, void *aux) { @@ -318,8 +329,10 @@ cpuattach(struct device *parent, struct device *dev, void *aux) } if (OF_getprop(qhandle, "power-mode-data", - &ppc_power_mode_data, sizeof ppc_power_mode_data) >= 8) + &ppc_power_mode_data, sizeof ppc_power_mode_data) >= 8) { + task_set(&ppc64_setperf_task, ppc64_do_setperf, NULL); cpu_setperf = ppc64_setperf; + } } /* power savings mode */ -- 2.20.1