1*8fc4e4bbSbouyer /* $NetBSD: acpi_wakeup.c,v 1.57 2023/10/19 14:59:46 bouyer Exp $ */
2870cffb0Sjoerg
3870cffb0Sjoerg /*-
40c794722Srmind * Copyright (c) 2002, 2011 The NetBSD Foundation, Inc.
5870cffb0Sjoerg * All rights reserved.
6870cffb0Sjoerg *
7870cffb0Sjoerg * This code is derived from software contributed to The NetBSD Foundation
8870cffb0Sjoerg * by Takuya SHIOZAKI.
9870cffb0Sjoerg *
10870cffb0Sjoerg * Redistribution and use in source and binary forms, with or without
11870cffb0Sjoerg * modification, are permitted provided that the following conditions
12870cffb0Sjoerg * are met:
13870cffb0Sjoerg * 1. Redistributions of source code must retain the above copyright
14870cffb0Sjoerg * notice, this list of conditions and the following disclaimer.
15870cffb0Sjoerg * 2. Redistributions in binary form must reproduce the above copyright
16870cffb0Sjoerg * notice, this list of conditions and the following disclaimer in the
17870cffb0Sjoerg * documentation and/or other materials provided with the distribution.
18870cffb0Sjoerg *
19870cffb0Sjoerg * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
20870cffb0Sjoerg * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
21870cffb0Sjoerg * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
22870cffb0Sjoerg * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
23870cffb0Sjoerg * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
24870cffb0Sjoerg * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
25870cffb0Sjoerg * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
26870cffb0Sjoerg * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
27870cffb0Sjoerg * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
28870cffb0Sjoerg * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
29870cffb0Sjoerg * POSSIBILITY OF SUCH DAMAGE.
30870cffb0Sjoerg */
31870cffb0Sjoerg
32870cffb0Sjoerg /*-
33870cffb0Sjoerg * Copyright (c) 2001 Takanori Watanabe <takawata@jp.freebsd.org>
34870cffb0Sjoerg * Copyright (c) 2001 Mitsuru IWASAKI <iwasaki@jp.freebsd.org>
35870cffb0Sjoerg * All rights reserved.
36870cffb0Sjoerg *
37870cffb0Sjoerg * Redistribution and use in source and binary forms, with or without
38870cffb0Sjoerg * modification, are permitted provided that the following conditions
39870cffb0Sjoerg * are met:
40870cffb0Sjoerg * 1. Redistributions of source code must retain the above copyright
41870cffb0Sjoerg * notice, this list of conditions and the following disclaimer.
42870cffb0Sjoerg * 2. Redistributions in binary form must reproduce the above copyright
43870cffb0Sjoerg * notice, this list of conditions and the following disclaimer in the
44870cffb0Sjoerg * documentation and/or other materials provided with the distribution.
45870cffb0Sjoerg *
46870cffb0Sjoerg * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
47870cffb0Sjoerg * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
48870cffb0Sjoerg * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
49870cffb0Sjoerg * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
50870cffb0Sjoerg * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
51870cffb0Sjoerg * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
52870cffb0Sjoerg * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
53870cffb0Sjoerg * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
54870cffb0Sjoerg * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
55870cffb0Sjoerg * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
56870cffb0Sjoerg * SUCH DAMAGE.
57870cffb0Sjoerg *
58870cffb0Sjoerg * FreeBSD: src/sys/i386/acpica/acpi_wakeup.c,v 1.9 2002/01/10 03:26:46 wes Exp
59870cffb0Sjoerg */
60870cffb0Sjoerg
610c794722Srmind #include <sys/cdefs.h>
62*8fc4e4bbSbouyer __KERNEL_RCSID(0, "$NetBSD: acpi_wakeup.c,v 1.57 2023/10/19 14:59:46 bouyer Exp $");
630c794722Srmind
64870cffb0Sjoerg #include <sys/param.h>
65870cffb0Sjoerg #include <sys/systm.h>
66870cffb0Sjoerg #include <sys/kernel.h>
67391925c7Sdyoung #include <sys/bus.h>
680c794722Srmind #include <sys/cpu.h>
690c794722Srmind #include <sys/kcpuset.h>
70870cffb0Sjoerg #include <sys/sysctl.h>
71870cffb0Sjoerg
72870cffb0Sjoerg #include <uvm/uvm_extern.h>
73870cffb0Sjoerg
74870cffb0Sjoerg #ifdef __i386__
75870cffb0Sjoerg #include "opt_mtrr.h"
76870cffb0Sjoerg #endif
77870cffb0Sjoerg #include "ioapic.h"
78870cffb0Sjoerg #include "lapic.h"
79870cffb0Sjoerg
80870cffb0Sjoerg #if NLAPIC > 0
81870cffb0Sjoerg #include <machine/i82489var.h>
82870cffb0Sjoerg #endif
83870cffb0Sjoerg #if NIOAPIC > 0
84870cffb0Sjoerg #include <machine/i82093var.h>
85870cffb0Sjoerg #endif
86870cffb0Sjoerg #include <machine/i8259.h>
87870cffb0Sjoerg
88b0fb7abfSjmcneill #include "acpica.h"
89870cffb0Sjoerg
90870cffb0Sjoerg #include <dev/ic/i8253reg.h>
91870cffb0Sjoerg #include <dev/acpi/acpica.h>
92870cffb0Sjoerg #include <dev/acpi/acpivar.h>
93870cffb0Sjoerg #define ACPI_MACHDEP_PRIVATE
94870cffb0Sjoerg #include <machine/acpi_machdep.h>
95870cffb0Sjoerg #include <machine/cpu.h>
96870cffb0Sjoerg #include <machine/mtrr.h>
97870cffb0Sjoerg
98870cffb0Sjoerg #include <x86/cpuvar.h>
997ad644e9Sdrochner #include <x86/x86/tsc.h>
100480bf536Sdsl #include <x86/fpu.h>
10198f1f453Sbouyer #include <arch/x86/include/genfb_machdep.h>
102870cffb0Sjoerg
10312cda298Sjoerg #include "opt_vga.h"
10412cda298Sjoerg
105870cffb0Sjoerg #include "acpi_wakecode.h"
106870cffb0Sjoerg
10777901f27Sriastradh #ifdef XENPV
10877901f27Sriastradh #error acpi_wakeup.c (acpi_md_vesa_modenum) users must be adapted for Xen
109*8fc4e4bbSbouyer #else
110*8fc4e4bbSbouyer int acpi_md_vesa_modenum = 0;
11177901f27Sriastradh #endif
11277901f27Sriastradh
113870cffb0Sjoerg /* Address is also hard-coded in acpi_wakecode.S */
114870cffb0Sjoerg static paddr_t acpi_wakeup_paddr = 3 * PAGE_SIZE;
115870cffb0Sjoerg static vaddr_t acpi_wakeup_vaddr;
116870cffb0Sjoerg
1178843b0cbSjmcneill static int acpi_md_beep_on_reset = 0;
118870cffb0Sjoerg
11918bb71aeSjruoho static int acpi_md_s4bios(void);
120870cffb0Sjoerg static int sysctl_md_acpi_vbios_reset(SYSCTLFN_ARGS);
121870cffb0Sjoerg static int sysctl_md_acpi_beep_on_reset(SYSCTLFN_ARGS);
122870cffb0Sjoerg
123870cffb0Sjoerg /* Implemented in acpi_wakeup_low.S. */
124870cffb0Sjoerg int acpi_md_sleep_prepare(int);
125870cffb0Sjoerg int acpi_md_sleep_exit(int);
12618bb71aeSjruoho
127870cffb0Sjoerg /* Referenced by acpi_wakeup_low.S. */
128870cffb0Sjoerg void acpi_md_sleep_enter(int);
129870cffb0Sjoerg
130870cffb0Sjoerg #ifdef MULTIPROCESSOR
131870cffb0Sjoerg /* Referenced in ipifuncs.c. */
132870cffb0Sjoerg void acpi_cpu_sleep(struct cpu_info *);
133870cffb0Sjoerg #endif
134870cffb0Sjoerg
135870cffb0Sjoerg static void
acpi_md_sleep_patch(struct cpu_info * ci)136870cffb0Sjoerg acpi_md_sleep_patch(struct cpu_info *ci)
137870cffb0Sjoerg {
138870cffb0Sjoerg #define WAKECODE_FIXUP(offset, type, val) do { \
139870cffb0Sjoerg type *addr; \
140870cffb0Sjoerg addr = (type *)(acpi_wakeup_vaddr + offset); \
141870cffb0Sjoerg *addr = val; \
142870cffb0Sjoerg } while (0)
143870cffb0Sjoerg
144870cffb0Sjoerg paddr_t tmp_pdir;
145870cffb0Sjoerg
146870cffb0Sjoerg tmp_pdir = pmap_init_tmp_pgtbl(acpi_wakeup_paddr);
147870cffb0Sjoerg
148e2cb8590Scegger memcpy((void *)acpi_wakeup_vaddr, wakecode, sizeof(wakecode));
149870cffb0Sjoerg
150870cffb0Sjoerg if (CPU_IS_PRIMARY(ci)) {
151b585cf85Sjmcneill WAKECODE_FIXUP(WAKEUP_vesa_modenum, uint16_t, acpi_md_vesa_modenum);
152870cffb0Sjoerg WAKECODE_FIXUP(WAKEUP_vbios_reset, uint8_t, acpi_md_vbios_reset);
153870cffb0Sjoerg WAKECODE_FIXUP(WAKEUP_beep_on_reset, uint8_t, acpi_md_beep_on_reset);
154870cffb0Sjoerg } else {
155b585cf85Sjmcneill WAKECODE_FIXUP(WAKEUP_vesa_modenum, uint16_t, 0);
156870cffb0Sjoerg WAKECODE_FIXUP(WAKEUP_vbios_reset, uint8_t, 0);
157870cffb0Sjoerg WAKECODE_FIXUP(WAKEUP_beep_on_reset, uint8_t, 0);
158870cffb0Sjoerg }
159870cffb0Sjoerg
160870cffb0Sjoerg #ifdef __i386__
161870cffb0Sjoerg WAKECODE_FIXUP(WAKEUP_r_cr4, uint32_t, ci->ci_suspend_cr4);
162870cffb0Sjoerg #endif
163d93fe1fdSmaxv WAKECODE_FIXUP(WAKEUP_efer, uint32_t, ci->ci_suspend_efer);
164870cffb0Sjoerg WAKECODE_FIXUP(WAKEUP_curcpu, void *, ci);
165870cffb0Sjoerg #ifdef __i386__
166870cffb0Sjoerg WAKECODE_FIXUP(WAKEUP_r_cr3, uint32_t, tmp_pdir);
167870cffb0Sjoerg #else
168870cffb0Sjoerg WAKECODE_FIXUP(WAKEUP_r_cr3, uint64_t, tmp_pdir);
169870cffb0Sjoerg #endif
170870cffb0Sjoerg WAKECODE_FIXUP(WAKEUP_restorecpu, void *, acpi_md_sleep_exit);
171870cffb0Sjoerg #undef WAKECODE_FIXUP
172870cffb0Sjoerg }
173870cffb0Sjoerg
17418bb71aeSjruoho static int
acpi_md_s4bios(void)17518bb71aeSjruoho acpi_md_s4bios(void)
176870cffb0Sjoerg {
17718bb71aeSjruoho ACPI_TABLE_FACS *facs;
178c0c31ce9Sjruoho ACPI_STATUS rv;
179870cffb0Sjoerg
18018bb71aeSjruoho rv = AcpiGetTable(ACPI_SIG_FACS, 0, (ACPI_TABLE_HEADER **)&facs);
181870cffb0Sjoerg
18218bb71aeSjruoho if (ACPI_FAILURE(rv) || facs == NULL)
18318bb71aeSjruoho return 0;
1840f58ad7aSjruoho
18518bb71aeSjruoho if ((facs->Flags & ACPI_FACS_S4_BIOS_PRESENT) == 0)
18618bb71aeSjruoho return 0;
187870cffb0Sjoerg
18818bb71aeSjruoho return 1;
189870cffb0Sjoerg }
190870cffb0Sjoerg
191870cffb0Sjoerg void
acpi_md_sleep_enter(int state)192870cffb0Sjoerg acpi_md_sleep_enter(int state)
193870cffb0Sjoerg {
19418bb71aeSjruoho static int s4bios = -1;
195870cffb0Sjoerg struct cpu_info *ci;
19618bb71aeSjruoho ACPI_STATUS rv;
197870cffb0Sjoerg
198870cffb0Sjoerg ci = curcpu();
199870cffb0Sjoerg
200870cffb0Sjoerg #ifdef MULTIPROCESSOR
201870cffb0Sjoerg if (!CPU_IS_PRIMARY(ci)) {
202870cffb0Sjoerg atomic_and_32(&ci->ci_flags, ~CPUF_RUNNING);
2030c794722Srmind kcpuset_atomic_clear(kcpuset_running, cpu_index(ci));
204870cffb0Sjoerg
205870cffb0Sjoerg ACPI_FLUSH_CPU_CACHE();
206870cffb0Sjoerg
207870cffb0Sjoerg for (;;)
208870cffb0Sjoerg x86_hlt();
209870cffb0Sjoerg }
210870cffb0Sjoerg #endif
211870cffb0Sjoerg
212870cffb0Sjoerg acpi_md_sleep_patch(ci);
213870cffb0Sjoerg
214870cffb0Sjoerg ACPI_FLUSH_CPU_CACHE();
215870cffb0Sjoerg
21618bb71aeSjruoho switch (state) {
21718bb71aeSjruoho
21818bb71aeSjruoho case ACPI_STATE_S4:
21918bb71aeSjruoho
22018bb71aeSjruoho if (s4bios < 0)
22118bb71aeSjruoho s4bios = acpi_md_s4bios();
22218bb71aeSjruoho
22318bb71aeSjruoho if (s4bios == 0) {
22418bb71aeSjruoho aprint_error("acpi0: S4 not supported\n");
225870cffb0Sjoerg return;
226870cffb0Sjoerg }
227870cffb0Sjoerg
22818bb71aeSjruoho rv = AcpiEnterSleepStateS4bios();
22918bb71aeSjruoho break;
23018bb71aeSjruoho
23118bb71aeSjruoho default:
23218bb71aeSjruoho rv = AcpiEnterSleepState(state);
23318bb71aeSjruoho break;
23418bb71aeSjruoho }
23518bb71aeSjruoho
23618bb71aeSjruoho if (ACPI_FAILURE(rv)) {
23718bb71aeSjruoho aprint_error("acpi0: failed to enter S%d\n", state);
238870cffb0Sjoerg return;
239870cffb0Sjoerg }
240870cffb0Sjoerg
241870cffb0Sjoerg for (;;)
242870cffb0Sjoerg x86_hlt();
243870cffb0Sjoerg }
244870cffb0Sjoerg
245870cffb0Sjoerg #ifdef MULTIPROCESSOR
246870cffb0Sjoerg void
acpi_cpu_sleep(struct cpu_info * ci)247870cffb0Sjoerg acpi_cpu_sleep(struct cpu_info *ci)
248870cffb0Sjoerg {
24923b50811Smaxv uint64_t xcr0 = 0;
25021053717Smaxv int s;
25121053717Smaxv
252870cffb0Sjoerg KASSERT(!CPU_IS_PRIMARY(ci));
253870cffb0Sjoerg KASSERT(ci == curcpu());
254870cffb0Sjoerg
25521053717Smaxv s = splhigh();
256560337f7Smaxv fpu_save();
257870cffb0Sjoerg x86_disable_intr();
258870cffb0Sjoerg
25923b50811Smaxv /*
26023b50811Smaxv * XXX also need to save the PMCs, the dbregs, and probably a few
26123b50811Smaxv * MSRs too.
26223b50811Smaxv */
26323b50811Smaxv if (rcr4() & CR4_OSXSAVE)
26423b50811Smaxv xcr0 = rdxcr(0);
26523b50811Smaxv
266f54b02d7Smaxv /* Go get some sleep */
267870cffb0Sjoerg if (acpi_md_sleep_prepare(-1))
26821053717Smaxv goto out;
269870cffb0Sjoerg
270f54b02d7Smaxv /*
271f54b02d7Smaxv * Sleeping and having bad nightmares about what could go wrong
272f54b02d7Smaxv * when waking up.
273f54b02d7Smaxv */
274f54b02d7Smaxv
275f54b02d7Smaxv /* We just woke up (cpuN), execution is resumed here */
276870cffb0Sjoerg cpu_init_msrs(ci, false);
27751a0d6b1Sdsl fpuinit(ci);
27823b50811Smaxv if (rcr4() & CR4_OSXSAVE)
27923b50811Smaxv wrxcr(0, xcr0);
280f54b02d7Smaxv pat_init(ci);
2813eef1a86Smaxv x86_errata();
282870cffb0Sjoerg #if NLAPIC > 0
283870cffb0Sjoerg lapic_enable();
284870cffb0Sjoerg lapic_set_lvt();
285570e015dSad lapic_reset();
286870cffb0Sjoerg #endif
287870cffb0Sjoerg
288870cffb0Sjoerg atomic_or_32(&ci->ci_flags, CPUF_RUNNING);
2890c794722Srmind kcpuset_atomic_set(kcpuset_running, cpu_index(ci));
2907ad644e9Sdrochner tsc_sync_ap(ci);
291870cffb0Sjoerg
29221053717Smaxv out:
293870cffb0Sjoerg x86_enable_intr();
29421053717Smaxv splx(s);
295870cffb0Sjoerg }
296870cffb0Sjoerg #endif
297870cffb0Sjoerg
298870cffb0Sjoerg int
acpi_md_sleep(int state)299870cffb0Sjoerg acpi_md_sleep(int state)
300870cffb0Sjoerg {
30123b50811Smaxv uint64_t xcr0 = 0;
30213e32ea2Sjmcneill int s, ret = 0;
303870cffb0Sjoerg #ifdef MULTIPROCESSOR
304870cffb0Sjoerg struct cpu_info *ci;
305870cffb0Sjoerg CPU_INFO_ITERATOR cii;
3060c794722Srmind cpuid_t cid;
307870cffb0Sjoerg #endif
308870cffb0Sjoerg
309870cffb0Sjoerg KASSERT(acpi_wakeup_paddr != 0);
310870cffb0Sjoerg KASSERT(sizeof(wakecode) <= PAGE_SIZE);
311870cffb0Sjoerg
312870cffb0Sjoerg if (!CPU_IS_PRIMARY(curcpu())) {
313870cffb0Sjoerg printf("acpi0: WARNING: ignoring sleep from secondary CPU\n");
314870cffb0Sjoerg return -1;
315870cffb0Sjoerg }
316870cffb0Sjoerg
3172b33f18bSjmcneill AcpiSetFirmwareWakingVector(acpi_wakeup_paddr, 0);
318870cffb0Sjoerg
31913e32ea2Sjmcneill s = splhigh();
320560337f7Smaxv fpu_save();
321870cffb0Sjoerg x86_disable_intr();
322870cffb0Sjoerg
323870cffb0Sjoerg #ifdef MULTIPROCESSOR
3240c794722Srmind /* Save and suspend Application Processors. */
325870cffb0Sjoerg x86_broadcast_ipi(X86_IPI_ACPI_CPU_SLEEP);
3260c794722Srmind cid = cpu_index(curcpu());
327d4db18a6Sjakllsch while (kcpuset_isotherset(kcpuset_running, cid)) {
328870cffb0Sjoerg delay(1);
3290c794722Srmind }
330870cffb0Sjoerg #endif
331870cffb0Sjoerg
33223b50811Smaxv /*
33323b50811Smaxv * XXX also need to save the PMCs, the dbregs, and probably a few
33423b50811Smaxv * MSRs too.
33523b50811Smaxv */
33623b50811Smaxv if (rcr4() & CR4_OSXSAVE)
33723b50811Smaxv xcr0 = rdxcr(0);
33823b50811Smaxv
339f54b02d7Smaxv /* Go get some sleep */
340870cffb0Sjoerg if (acpi_md_sleep_prepare(state))
341870cffb0Sjoerg goto out;
342870cffb0Sjoerg
343f54b02d7Smaxv /*
344f54b02d7Smaxv * Sleeping and having bad nightmares about what could go wrong
345f54b02d7Smaxv * when waking up.
346f54b02d7Smaxv */
347f54b02d7Smaxv
348f54b02d7Smaxv /* We just woke up (cpu0), execution is resumed here */
34965ae8df0Sriastradh tsc_tc_reset();
350870cffb0Sjoerg cpu_init_msrs(&cpu_info_primary, false);
35151a0d6b1Sdsl fpuinit(&cpu_info_primary);
35223b50811Smaxv if (rcr4() & CR4_OSXSAVE)
35323b50811Smaxv wrxcr(0, xcr0);
354f54b02d7Smaxv pat_init(&cpu_info_primary);
3553eef1a86Smaxv x86_errata();
356870cffb0Sjoerg i8259_reinit();
357870cffb0Sjoerg #if NLAPIC > 0
358870cffb0Sjoerg lapic_enable();
359870cffb0Sjoerg lapic_set_lvt();
360570e015dSad lapic_reset();
361870cffb0Sjoerg #endif
362870cffb0Sjoerg #if NIOAPIC > 0
363870cffb0Sjoerg ioapic_reenable();
364870cffb0Sjoerg #endif
365870cffb0Sjoerg
366870cffb0Sjoerg initrtclock(TIMER_FREQ);
367870cffb0Sjoerg inittodr(time_second);
368870cffb0Sjoerg
36955bd26d1Sjruoho /*
3707cfe5d04Sjruoho * The BIOS should always re-enable the SCI upon
3717cfe5d04Sjruoho * resume from the S3 state. The following is a
3727cfe5d04Sjruoho * workaround for systems that fail to do this.
3737cfe5d04Sjruoho */
3747cfe5d04Sjruoho (void)AcpiWriteBitRegister(ACPI_BITREG_SCI_ENABLE, 1);
3757cfe5d04Sjruoho
3767cfe5d04Sjruoho /*
37755bd26d1Sjruoho * Clear fixed events (see e.g. ACPI 3.0, p. 62).
37855bd26d1Sjruoho * Also prevent GPEs from misfiring by disabling
37955bd26d1Sjruoho * all GPEs before interrupts are enabled. The
38055bd26d1Sjruoho * AcpiLeaveSleepState() function will enable
38155bd26d1Sjruoho * and handle the general purpose events later.
38255bd26d1Sjruoho */
38355bd26d1Sjruoho (void)AcpiClearEvent(ACPI_EVENT_PMTIMER);
38455bd26d1Sjruoho (void)AcpiClearEvent(ACPI_EVENT_GLOBAL);
38555bd26d1Sjruoho (void)AcpiClearEvent(ACPI_EVENT_POWER_BUTTON);
38655bd26d1Sjruoho (void)AcpiClearEvent(ACPI_EVENT_SLEEP_BUTTON);
38755bd26d1Sjruoho (void)AcpiClearEvent(ACPI_EVENT_RTC);
38855bd26d1Sjruoho (void)AcpiHwDisableAllGpes();
389870cffb0Sjoerg
390a5be52d4Sjoerg acpi_pci_link_resume();
391a5be52d4Sjoerg
392870cffb0Sjoerg out:
393870cffb0Sjoerg
394870cffb0Sjoerg #ifdef MULTIPROCESSOR
395f54b02d7Smaxv /* Wake up the secondary CPUs */
396870cffb0Sjoerg for (CPU_INFO_FOREACH(cii, ci)) {
397870cffb0Sjoerg if (CPU_IS_PRIMARY(ci))
398870cffb0Sjoerg continue;
399870cffb0Sjoerg acpi_md_sleep_patch(ci);
400870cffb0Sjoerg
401870cffb0Sjoerg CPU_STARTUP(ci, acpi_wakeup_paddr);
402870cffb0Sjoerg CPU_START_CLEANUP(ci);
403870cffb0Sjoerg
404870cffb0Sjoerg while ((ci->ci_flags & CPUF_RUNNING) == 0)
405870cffb0Sjoerg x86_pause();
4067ad644e9Sdrochner
4077ad644e9Sdrochner tsc_sync_bp(ci);
408870cffb0Sjoerg }
409870cffb0Sjoerg #endif
410870cffb0Sjoerg
411870cffb0Sjoerg x86_enable_intr();
41213e32ea2Sjmcneill splx(s);
413870cffb0Sjoerg
414870cffb0Sjoerg #ifdef MTRR
415870cffb0Sjoerg if (mtrr_funcs != NULL)
416870cffb0Sjoerg mtrr_commit();
417870cffb0Sjoerg #endif
418870cffb0Sjoerg
419870cffb0Sjoerg return (ret);
420870cffb0Sjoerg }
421870cffb0Sjoerg
422870cffb0Sjoerg void
acpi_md_sleep_init(void)423870cffb0Sjoerg acpi_md_sleep_init(void)
424870cffb0Sjoerg {
425870cffb0Sjoerg /* Map ACPI wakecode */
426870cffb0Sjoerg acpi_wakeup_vaddr = uvm_km_alloc(kernel_map, PAGE_SIZE, 0,
427870cffb0Sjoerg UVM_KMF_VAONLY);
428870cffb0Sjoerg if (acpi_wakeup_vaddr == 0)
429870cffb0Sjoerg panic("acpi: can't allocate address for wakecode.\n");
430870cffb0Sjoerg
431870cffb0Sjoerg pmap_kenter_pa(acpi_wakeup_vaddr, acpi_wakeup_paddr,
4329480c51bScegger VM_PROT_READ | VM_PROT_WRITE, 0);
433870cffb0Sjoerg pmap_update(pmap_kernel());
434870cffb0Sjoerg }
435870cffb0Sjoerg
4360addcacfSjruoho SYSCTL_SETUP(sysctl_md_acpi_setup, "ACPI x86 sysctl setup")
437870cffb0Sjoerg {
4380addcacfSjruoho const struct sysctlnode *rnode;
439b99cdd8eSjruoho int err;
440870cffb0Sjoerg
441b99cdd8eSjruoho err = sysctl_createv(clog, 0, NULL, &rnode,
442b99cdd8eSjruoho CTLFLAG_PERMANENT, CTLTYPE_NODE, "acpi", NULL,
4434f6fb3bfSpooka NULL, 0, NULL, 0, CTL_HW, CTL_CREATE, CTL_EOL);
444b99cdd8eSjruoho
445b99cdd8eSjruoho if (err != 0)
4460addcacfSjruoho return;
447b99cdd8eSjruoho
448b99cdd8eSjruoho err = sysctl_createv(clog, 0, &rnode, &rnode,
449b99cdd8eSjruoho CTLFLAG_PERMANENT, CTLTYPE_NODE,
450b99cdd8eSjruoho "sleep", SYSCTL_DESCR("ACPI sleep"),
451b99cdd8eSjruoho NULL, 0, NULL, 0, CTL_CREATE, CTL_EOL);
452b99cdd8eSjruoho
453b99cdd8eSjruoho if (err != 0)
4540addcacfSjruoho return;
455b99cdd8eSjruoho
456b99cdd8eSjruoho (void)sysctl_createv(NULL, 0, &rnode, NULL,
457b99cdd8eSjruoho CTLFLAG_READWRITE, CTLTYPE_BOOL, "beep",
458b99cdd8eSjruoho NULL, sysctl_md_acpi_beep_on_reset,
459b99cdd8eSjruoho 0, NULL, 0, CTL_CREATE, CTL_EOL);
460b99cdd8eSjruoho
461b99cdd8eSjruoho (void)sysctl_createv(NULL, 0, &rnode, NULL,
462b99cdd8eSjruoho CTLFLAG_READWRITE, CTLTYPE_INT, "vbios",
463b99cdd8eSjruoho NULL, sysctl_md_acpi_vbios_reset,
464b99cdd8eSjruoho 0, NULL, 0, CTL_CREATE, CTL_EOL);
465870cffb0Sjoerg }
466870cffb0Sjoerg
467870cffb0Sjoerg static int
sysctl_md_acpi_vbios_reset(SYSCTLFN_ARGS)468870cffb0Sjoerg sysctl_md_acpi_vbios_reset(SYSCTLFN_ARGS)
469870cffb0Sjoerg {
470870cffb0Sjoerg int error, t;
471870cffb0Sjoerg struct sysctlnode node;
472870cffb0Sjoerg
473870cffb0Sjoerg node = *rnode;
474870cffb0Sjoerg t = acpi_md_vbios_reset;
475870cffb0Sjoerg node.sysctl_data = &t;
476870cffb0Sjoerg error = sysctl_lookup(SYSCTLFN_CALL(&node));
477870cffb0Sjoerg if (error || newp == NULL)
478870cffb0Sjoerg return error;
479870cffb0Sjoerg
4800b2a6aefSjoerg if (t < 0 || t > 2)
481870cffb0Sjoerg return EINVAL;
482870cffb0Sjoerg
48312cda298Sjoerg #ifndef VGA_POST
484292e598aSjoerg if (t == 2) {
485b99cdd8eSjruoho aprint_error("WARNING: hw.acpi.sleep.vbios=2 "
486292e598aSjoerg "unsupported (no option VGA_POST in kernel config)\n");
48712cda298Sjoerg return EINVAL;
488292e598aSjoerg }
48912cda298Sjoerg #endif
49012cda298Sjoerg
491870cffb0Sjoerg acpi_md_vbios_reset = t;
492870cffb0Sjoerg
493870cffb0Sjoerg return 0;
494870cffb0Sjoerg }
495870cffb0Sjoerg
496870cffb0Sjoerg static int
sysctl_md_acpi_beep_on_reset(SYSCTLFN_ARGS)497870cffb0Sjoerg sysctl_md_acpi_beep_on_reset(SYSCTLFN_ARGS)
498870cffb0Sjoerg {
499870cffb0Sjoerg int error, t;
500870cffb0Sjoerg struct sysctlnode node;
501870cffb0Sjoerg
502870cffb0Sjoerg node = *rnode;
503870cffb0Sjoerg t = acpi_md_beep_on_reset;
504870cffb0Sjoerg node.sysctl_data = &t;
505870cffb0Sjoerg error = sysctl_lookup(SYSCTLFN_CALL(&node));
506870cffb0Sjoerg if (error || newp == NULL)
507870cffb0Sjoerg return error;
508870cffb0Sjoerg
509870cffb0Sjoerg if (t < 0 || t > 1)
510870cffb0Sjoerg return EINVAL;
511870cffb0Sjoerg
512870cffb0Sjoerg acpi_md_beep_on_reset = t;
513870cffb0Sjoerg
514870cffb0Sjoerg return 0;
515870cffb0Sjoerg }
516