summaryrefslogtreecommitdiffstats
path: root/sys/kern/subr_power.c
diff options
context:
space:
mode:
authorimp <imp@FreeBSD.org>2005-11-09 07:32:01 +0000
committerimp <imp@FreeBSD.org>2005-11-09 07:32:01 +0000
commita528ef30b2f1868c6b5fe3d8c3ce6caf9d618ca2 (patch)
tree613ab6d4b6601530f1affc19d2f0746b85523daf /sys/kern/subr_power.c
parent2f1cffe2641cec84c19eb4a381d6e0c8d0fc567c (diff)
downloadFreeBSD-src-a528ef30b2f1868c6b5fe3d8c3ce6caf9d618ca2.zip
FreeBSD-src-a528ef30b2f1868c6b5fe3d8c3ce6caf9d618ca2.tar.gz
Kick off the suspend sequence from the keyboard in a SWI rather than
in the hardware interrupt context (even if it is likely just an ithread). We don't document that suspend/resume routines are run from such a context and some of the things that happen in those routines aren't interrupt safe. Since there's no real need to run from that context, this restores assumptions that suspend routines have made. This fixes Thierry Herbelot's 'Trying to sleep while sleeping is prohibited' problem.
Diffstat (limited to 'sys/kern/subr_power.c')
-rw-r--r--sys/kern/subr_power.c15
1 files changed, 13 insertions, 2 deletions
diff --git a/sys/kern/subr_power.c b/sys/kern/subr_power.c
index 7d69765..f1485e6 100644
--- a/sys/kern/subr_power.c
+++ b/sys/kern/subr_power.c
@@ -32,10 +32,20 @@ __FBSDID("$FreeBSD$");
#include <sys/proc.h>
#include <sys/power.h>
+#include <sys/taskqueue.h>
static u_int power_pm_type = POWER_PM_TYPE_NONE;
static power_pm_fn_t power_pm_fn = NULL;
static void *power_pm_arg = NULL;
+static struct task power_pm_task;
+
+static void
+power_pm_deferred_fn(void *arg, int pending)
+{
+ int state = (int)arg;
+
+ power_pm_fn(POWER_CMD_SUSPEND, power_pm_arg, state);
+}
int
power_pm_register(u_int pm_type, power_pm_fn_t pm_fn, void *pm_arg)
@@ -48,6 +58,7 @@ power_pm_register(u_int pm_type, power_pm_fn_t pm_fn, void *pm_arg)
power_pm_fn = pm_fn;
power_pm_arg = pm_arg;
error = 0;
+ TASK_INIT(&power_pm_task, 0, power_pm_deferred_fn, NULL);
} else {
error = ENXIO;
}
@@ -72,8 +83,8 @@ power_pm_suspend(int state)
state != POWER_SLEEP_STATE_SUSPEND &&
state != POWER_SLEEP_STATE_HIBERNATE)
return;
-
- power_pm_fn(POWER_CMD_SUSPEND, power_pm_arg, state);
+ power_pm_task.ta_context = (void *)state;
+ taskqueue_enqueue(taskqueue_swi, &power_pm_task);
}
/*
OpenPOWER on IntegriCloud