diff options
author | Mark Kettenis <kettenis@cvs.openbsd.org> | 2015-06-04 18:01:45 +0000 |
---|---|---|
committer | Mark Kettenis <kettenis@cvs.openbsd.org> | 2015-06-04 18:01:45 +0000 |
commit | 8e9fa9b73fd950ca43c9118cb5b0d0be01e26018 (patch) | |
tree | a4017fbdb8b445189f40024480d687d685eff07b | |
parent | 6c7d781e52ac0eb4dd4862927bfa25d26178dc31 (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.c | 6 | ||||
-rw-r--r-- | 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 <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 */ |