summaryrefslogtreecommitdiff
path: root/sys
diff options
context:
space:
mode:
authorMark Kettenis <kettenis@cvs.openbsd.org>2010-04-07 06:33:07 +0000
committerMark Kettenis <kettenis@cvs.openbsd.org>2010-04-07 06:33:07 +0000
commite364404469d7df746d6ea478fd0f30e477dd7b78 (patch)
tree5c9df2f558ad3ad0783f363c744645614d483293 /sys
parentfd68c6363abe0cbf58a199c00f9e3f8878d0e47d (diff)
Make suspend/resume work on MP machines (running an MP kernel). Joint work
from mlarkin@ and me, with some amd64 fixes thrown in by deraadt@ ok marco@, deraadt@, pirofti@, mlarkin@
Diffstat (limited to 'sys')
-rw-r--r--sys/arch/amd64/amd64/acpi_machdep.c56
-rw-r--r--sys/arch/amd64/amd64/cpu.c10
-rw-r--r--sys/arch/amd64/amd64/ipifuncs.c3
-rw-r--r--sys/arch/i386/i386/acpi_machdep.c49
-rw-r--r--sys/arch/i386/i386/ipifuncs.c3
-rw-r--r--sys/dev/acpi/acpi.c22
-rw-r--r--sys/dev/acpi/acpivar.h3
7 files changed, 129 insertions, 17 deletions
diff --git a/sys/arch/amd64/amd64/acpi_machdep.c b/sys/arch/amd64/amd64/acpi_machdep.c
index d5323d15cb5..bfba94bb8ec 100644
--- a/sys/arch/amd64/amd64/acpi_machdep.c
+++ b/sys/arch/amd64/amd64/acpi_machdep.c
@@ -1,4 +1,4 @@
-/* $OpenBSD: acpi_machdep.c,v 1.33 2010/02/23 21:54:53 kettenis Exp $ */
+/* $OpenBSD: acpi_machdep.c,v 1.34 2010/04/07 06:33:06 kettenis Exp $ */
/*
* Copyright (c) 2005 Thorsten Lockert <tholo@sigmasoft.com>
*
@@ -21,6 +21,7 @@
#include <sys/device.h>
#include <sys/malloc.h>
#include <sys/memrange.h>
+#include <sys/user.h>
#include <uvm/uvm_extern.h>
@@ -28,7 +29,9 @@
#include <machine/biosvar.h>
#include <machine/isa_machdep.h>
+#include <machine/cpu.h>
#include <machine/cpufunc.h>
+#include <machine/cpuvar.h>
#include <dev/isa/isareg.h>
#include <dev/acpi/acpireg.h>
@@ -224,9 +227,13 @@ acpi_sleep_machdep(struct acpi_softc *sc, int state)
/* Copy the current cpu registers into a safe place for resume. */
if (acpi_savecpu()) {
fpusave_cpu(curcpu(), 1);
+#ifdef MULTIPROCESSOR
+ x86_broadcast_ipi(X86_IPI_FLUSH_FPU);
+ x86_broadcast_ipi(X86_IPI_HALT);
+#endif
wbinvd();
- if (acpi_enter_sleep_state(sc, state) != 0)
- panic("%s: acpi_enter_sleep_state failed", DEVNAME(sc));
+ acpi_enter_sleep_state(sc, state);
+ panic("%s: acpi_enter_sleep_state failed", DEVNAME(sc));
}
#if 0
/* Temporarily disabled for debugging purposes */
@@ -260,4 +267,47 @@ acpi_sleep_machdep(struct acpi_softc *sc, int state)
return (0);
}
+void cpu_start_secondary(struct cpu_info *ci);
+
+void
+acpi_resume_machdep(void)
+{
+#ifdef MULTIPROCESSOR
+ struct cpu_info *ci;
+ struct proc *p;
+ struct pcb *pcb;
+ struct trapframe *tf;
+ struct switchframe *sf;
+ int i;
+
+ /* XXX refactor with matching code in cpu.c */
+
+ for (i = 0; i < MAXCPUS; i++) {
+ ci = cpu_info[i];
+ if (ci == NULL)
+ continue;
+ if (ci->ci_idle_pcb == NULL)
+ continue;
+ if (ci->ci_flags & (CPUF_BSP|CPUF_SP|CPUF_PRIMARY))
+ continue;
+ KASSERT((ci->ci_flags & CPUF_RUNNING) == 0);
+
+ p = ci->ci_schedstate.spc_idleproc;
+ pcb = &p->p_addr->u_pcb;
+
+ tf = (struct trapframe *)pcb->pcb_tss.tss_rsp0 - 1;
+ sf = (struct switchframe *)tf - 1;
+ sf->sf_r12 = (u_int64_t)sched_idle;
+ sf->sf_r13 = (u_int64_t)ci;
+ sf->sf_rip = (u_int64_t)proc_trampoline;
+ pcb->pcb_rsp = (u_int64_t)sf;
+ pcb->pcb_rbp = 0;
+
+ ci->ci_flags &= ~CPUF_PRESENT;
+ cpu_start_secondary(ci);
+ }
+
+ cpu_boot_secondary_processors();
+#endif /* MULTIPROCESSOR */
+}
#endif /* ! SMALL_KERNEL */
diff --git a/sys/arch/amd64/amd64/cpu.c b/sys/arch/amd64/amd64/cpu.c
index 75a1ffaba82..2a67d8f4474 100644
--- a/sys/arch/amd64/amd64/cpu.c
+++ b/sys/arch/amd64/amd64/cpu.c
@@ -1,4 +1,4 @@
-/* $OpenBSD: cpu.c,v 1.29 2010/04/01 19:47:59 kettenis Exp $ */
+/* $OpenBSD: cpu.c,v 1.30 2010/04/07 06:33:06 kettenis Exp $ */
/* $NetBSD: cpu.c,v 1.1 2003/04/26 18:39:26 fvdl Exp $ */
/*-
@@ -145,9 +145,9 @@ u_int32_t cpus_attached = 0;
struct cpu_info *cpu_info[MAXCPUS] = { &cpu_info_primary };
void cpu_hatch(void *);
-static void cpu_boot_secondary(struct cpu_info *ci);
-static void cpu_start_secondary(struct cpu_info *ci);
-static void cpu_copy_trampoline(void);
+void cpu_boot_secondary(struct cpu_info *ci);
+void cpu_start_secondary(struct cpu_info *ci);
+void cpu_copy_trampoline(void);
/*
* Runs once per boot once multiprocessor goo has been detected and
@@ -548,7 +548,7 @@ cpu_debug_dump(void)
}
#endif
-static void
+void
cpu_copy_trampoline(void)
{
/*
diff --git a/sys/arch/amd64/amd64/ipifuncs.c b/sys/arch/amd64/amd64/ipifuncs.c
index abe50ba74cb..d8615ef350b 100644
--- a/sys/arch/amd64/amd64/ipifuncs.c
+++ b/sys/arch/amd64/amd64/ipifuncs.c
@@ -1,4 +1,4 @@
-/* $OpenBSD: ipifuncs.c,v 1.10 2009/11/29 17:11:30 kettenis Exp $ */
+/* $OpenBSD: ipifuncs.c,v 1.11 2010/04/07 06:33:06 kettenis Exp $ */
/* $NetBSD: ipifuncs.c,v 1.1 2003/04/26 18:39:28 fvdl Exp $ */
/*-
@@ -99,6 +99,7 @@ x86_64_ipi_halt(struct cpu_info *ci)
{
disable_intr();
ci->ci_flags &= ~CPUF_RUNNING;
+ wbinvd();
for(;;) {
__asm __volatile("hlt");
diff --git a/sys/arch/i386/i386/acpi_machdep.c b/sys/arch/i386/i386/acpi_machdep.c
index 5b4fdb640cb..23d0e882de4 100644
--- a/sys/arch/i386/i386/acpi_machdep.c
+++ b/sys/arch/i386/i386/acpi_machdep.c
@@ -1,4 +1,4 @@
-/* $OpenBSD: acpi_machdep.c,v 1.28 2010/02/23 21:54:53 kettenis Exp $ */
+/* $OpenBSD: acpi_machdep.c,v 1.29 2010/04/07 06:33:06 kettenis Exp $ */
/*
* Copyright (c) 2005 Thorsten Lockert <tholo@sigmasoft.com>
*
@@ -21,6 +21,7 @@
#include <sys/device.h>
#include <sys/malloc.h>
#include <sys/memrange.h>
+#include <sys/user.h>
#include <uvm/uvm_extern.h>
@@ -29,7 +30,9 @@
#include <machine/acpiapm.h>
#include <i386/isa/isa_machdep.h>
+#include <machine/cpu.h>
#include <machine/cpufunc.h>
+#include <machine/cpuvar.h>
#include <machine/npx.h>
#include <dev/isa/isareg.h>
@@ -242,6 +245,10 @@ acpi_sleep_machdep(struct acpi_softc *sc, int state)
/* Copy the current cpu registers into a safe place for resume. */
if (acpi_savecpu()) {
npxsave_cpu(curcpu(), 1);
+#ifdef MULTIPROCESSOR
+ i386_broadcast_ipi(I386_IPI_FLUSH_FPU);
+ i386_broadcast_ipi(I386_IPI_HALT);
+#endif
wbinvd();
acpi_enter_sleep_state(sc, state);
panic("%s: acpi_enter_sleep_state failed", DEVNAME(sc));
@@ -288,4 +295,44 @@ acpi_sleep_machdep(struct acpi_softc *sc, int state)
return (0);
}
+void
+acpi_resume_machdep(void)
+{
+#ifdef MULTIPROCESSOR
+ struct cpu_info *ci;
+ struct proc *p;
+ struct pcb *pcb;
+ struct trapframe *tf;
+ struct switchframe *sf;
+ int i;
+
+ /* XXX refactor with matching code in cpu.c */
+
+ for (i = 0; i < MAXCPUS; i++) {
+ ci = cpu_info[i];
+ if (ci == NULL)
+ continue;
+ if (ci->ci_idle_pcb == NULL)
+ continue;
+ if (ci->ci_flags & (CPUF_BSP|CPUF_SP|CPUF_PRIMARY))
+ continue;
+ KASSERT((ci->ci_flags & CPUF_RUNNING) == 0);
+
+ p = ci->ci_schedstate.spc_idleproc;
+ pcb = &p->p_addr->u_pcb;
+
+ tf = (struct trapframe *)pcb->pcb_tss.tss_esp0 - 1;
+ sf = (struct switchframe *)tf - 1;
+ sf->sf_esi = (int)sched_idle;
+ sf->sf_ebx = (int)ci;
+ sf->sf_eip = (int)proc_trampoline;
+ pcb->pcb_esp = (int)sf;
+
+ ci->ci_idepth = 0;
+ }
+
+ cpu_boot_secondary_processors();
+#endif /* MULTIPROCESSOR */
+}
+
#endif /* ! SMALL_KERNEL */
diff --git a/sys/arch/i386/i386/ipifuncs.c b/sys/arch/i386/i386/ipifuncs.c
index f0facf0b339..76c4df59186 100644
--- a/sys/arch/i386/i386/ipifuncs.c
+++ b/sys/arch/i386/i386/ipifuncs.c
@@ -1,4 +1,4 @@
-/* $OpenBSD: ipifuncs.c,v 1.15 2010/04/01 19:48:50 kettenis Exp $ */
+/* $OpenBSD: ipifuncs.c,v 1.16 2010/04/07 06:33:06 kettenis Exp $ */
/* $NetBSD: ipifuncs.c,v 1.1.2.3 2000/06/26 02:04:06 sommerfeld Exp $ */
/*-
@@ -102,6 +102,7 @@ i386_ipi_halt(struct cpu_info *ci)
{
disable_intr();
ci->ci_flags &= ~CPUF_RUNNING;
+ wbinvd();
for(;;) {
asm volatile("hlt");
diff --git a/sys/dev/acpi/acpi.c b/sys/dev/acpi/acpi.c
index 15c83596401..b66e45732b3 100644
--- a/sys/dev/acpi/acpi.c
+++ b/sys/dev/acpi/acpi.c
@@ -1,4 +1,4 @@
-/* $OpenBSD: acpi.c,v 1.155 2010/03/31 19:21:19 kettenis Exp $ */
+/* $OpenBSD: acpi.c,v 1.156 2010/04/07 06:33:06 kettenis Exp $ */
/*
* Copyright (c) 2005 Thorsten Lockert <tholo@sigmasoft.com>
* Copyright (c) 2005 Jordan Hargrave <jordan@openbsd.org>
@@ -27,6 +27,7 @@
#include <sys/proc.h>
#include <sys/kthread.h>
#include <sys/workq.h>
+#include <sys/sched.h>
#include <machine/conf.h>
#include <machine/cpufunc.h>
@@ -1837,10 +1838,6 @@ acpi_sleep_state(struct acpi_softc *sc, int state)
{
int ret;
-#ifdef MULTIPROCESSOR
- if (ncpus > 1) /* cannot suspend MP yet */
- return (0);
-#endif
switch (state) {
case ACPI_STATE_S0:
return (0);
@@ -1956,6 +1953,8 @@ acpi_resume(struct acpi_softc *sc, int state)
enable_intr();
splx(acpi_saved_spl);
+ acpi_resume_machdep();
+
sc->sc_state = ACPI_STATE_S0;
if (sc->sc_tts) {
env.v_integer = sc->sc_state;
@@ -1971,6 +1970,10 @@ acpi_resume(struct acpi_softc *sc, int state)
aml_evalnode(sc, sc->sc_sst, 1, &env, NULL);
}
+#ifdef MULTIPROCESSOR
+ sched_start_secondary_cpus();
+#endif
+
acpi_record_event(sc, APM_NORMAL_RESUME);
#if NWSDISPLAY > 0
@@ -2018,6 +2021,10 @@ acpi_handle_suspend_failure(struct acpi_softc *sc)
env.v_integer = ACPI_SST_WORKING;
aml_evalnode(sc, sc->sc_sst, 1, &env, NULL);
}
+
+#ifdef MULTIPROCESSOR
+ sched_start_secondary_cpus();
+#endif
}
int
@@ -2035,6 +2042,11 @@ acpi_prepare_sleep_state(struct acpi_softc *sc, int state)
return (ENXIO);
}
+#ifdef MULTIPROCESSOR
+ sched_stop_secondary_cpus();
+ KASSERT(CPU_IS_PRIMARY(curcpu()));
+#endif
+
memset(&env, 0, sizeof(env));
env.type = AML_OBJTYPE_INTEGER;
env.v_integer = state;
diff --git a/sys/dev/acpi/acpivar.h b/sys/dev/acpi/acpivar.h
index 32dca939a39..af31e3240cc 100644
--- a/sys/dev/acpi/acpivar.h
+++ b/sys/dev/acpi/acpivar.h
@@ -1,4 +1,4 @@
-/* $OpenBSD: acpivar.h,v 1.56 2010/03/31 19:21:19 kettenis Exp $ */
+/* $OpenBSD: acpivar.h,v 1.57 2010/04/07 06:33:06 kettenis Exp $ */
/*
* Copyright (c) 2005 Thorsten Lockert <tholo@sigmasoft.com>
*
@@ -294,6 +294,7 @@ int acpi_sleep_state(struct acpi_softc *, int);
int acpi_prepare_sleep_state(struct acpi_softc *, int);
int acpi_enter_sleep_state(struct acpi_softc *, int);
int acpi_sleep_machdep(struct acpi_softc *, int);
+void acpi_resume_machdep(void);
void acpi_sleep_walk(struct acpi_softc *, int);