diff options
author | Mark Kettenis <kettenis@cvs.openbsd.org> | 2010-04-07 06:33:07 +0000 |
---|---|---|
committer | Mark Kettenis <kettenis@cvs.openbsd.org> | 2010-04-07 06:33:07 +0000 |
commit | e364404469d7df746d6ea478fd0f30e477dd7b78 (patch) | |
tree | 5c9df2f558ad3ad0783f363c744645614d483293 /sys | |
parent | fd68c6363abe0cbf58a199c00f9e3f8878d0e47d (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.c | 56 | ||||
-rw-r--r-- | sys/arch/amd64/amd64/cpu.c | 10 | ||||
-rw-r--r-- | sys/arch/amd64/amd64/ipifuncs.c | 3 | ||||
-rw-r--r-- | sys/arch/i386/i386/acpi_machdep.c | 49 | ||||
-rw-r--r-- | sys/arch/i386/i386/ipifuncs.c | 3 | ||||
-rw-r--r-- | sys/dev/acpi/acpi.c | 22 | ||||
-rw-r--r-- | sys/dev/acpi/acpivar.h | 3 |
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); |