summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorMark Kettenis <kettenis@cvs.openbsd.org>2015-06-04 18:01:45 +0000
committerMark Kettenis <kettenis@cvs.openbsd.org>2015-06-04 18:01:45 +0000
commit8e9fa9b73fd950ca43c9118cb5b0d0be01e26018 (patch)
treea4017fbdb8b445189f40024480d687d685eff07b
parent6c7d781e52ac0eb4dd4862927bfa25d26178dc31 (diff)
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@
-rw-r--r--sys/arch/macppc/dev/smu.c6
-rw-r--r--sys/arch/macppc/macppc/cpu.c21
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 <sys/systm.h>
#include <sys/proc.h>
#include <sys/sysctl.h>
+#include <sys/task.h>
#include <sys/device.h>
#include <dev/rndvar.h>
@@ -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;
@@ -176,6 +180,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)
{
struct confargs *ca = 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 */