Expand PMF_FN_* macros.
[netbsd-mini2440.git] / sys / arch / x86 / acpi / acpi_wakeup.c
blob4c2f5a90b577298e18976676e31ff06cd923687c
1 /* $NetBSD: acpi_wakeup.c,v 1.19 2009/10/26 19:16:58 cegger Exp $ */
3 /*-
4 * Copyright (c) 2002 The NetBSD Foundation, Inc.
5 * All rights reserved.
7 * This code is derived from software contributed to The NetBSD Foundation
8 * by Takuya SHIOZAKI.
10 * Redistribution and use in source and binary forms, with or without
11 * modification, are permitted provided that the following conditions
12 * are met:
13 * 1. Redistributions of source code must retain the above copyright
14 * notice, this list of conditions and the following disclaimer.
15 * 2. Redistributions in binary form must reproduce the above copyright
16 * notice, this list of conditions and the following disclaimer in the
17 * documentation and/or other materials provided with the distribution.
19 * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
20 * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
21 * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
22 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
23 * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
24 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
25 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
26 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
27 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
28 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
29 * POSSIBILITY OF SUCH DAMAGE.
32 #include <sys/cdefs.h>
33 __KERNEL_RCSID(0, "$NetBSD: acpi_wakeup.c,v 1.19 2009/10/26 19:16:58 cegger Exp $");
35 /*-
36 * Copyright (c) 2001 Takanori Watanabe <takawata@jp.freebsd.org>
37 * Copyright (c) 2001 Mitsuru IWASAKI <iwasaki@jp.freebsd.org>
38 * All rights reserved.
40 * Redistribution and use in source and binary forms, with or without
41 * modification, are permitted provided that the following conditions
42 * are met:
43 * 1. Redistributions of source code must retain the above copyright
44 * notice, this list of conditions and the following disclaimer.
45 * 2. Redistributions in binary form must reproduce the above copyright
46 * notice, this list of conditions and the following disclaimer in the
47 * documentation and/or other materials provided with the distribution.
49 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
50 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
51 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
52 * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
53 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
54 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
55 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
56 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
57 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
58 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
59 * SUCH DAMAGE.
61 * FreeBSD: src/sys/i386/acpica/acpi_wakeup.c,v 1.9 2002/01/10 03:26:46 wes Exp
64 #include <sys/param.h>
65 #include <sys/systm.h>
66 #include <sys/kernel.h>
67 #include <machine/bus.h>
68 #include <sys/proc.h>
69 #include <sys/sysctl.h>
71 #include <uvm/uvm_extern.h>
72 #include <uvm/uvm_page.h>
74 #ifdef __i386__
75 #include "opt_mtrr.h"
76 #endif
77 #include "ioapic.h"
78 #include "lapic.h"
80 #if NLAPIC > 0
81 #include <machine/i82489var.h>
82 #endif
83 #if NIOAPIC > 0
84 #include <machine/i82093var.h>
85 #endif
86 #include <machine/i8259.h>
88 #include "acpica.h"
90 #include <dev/ic/i8253reg.h>
91 #include <dev/acpi/acpica.h>
92 #include <dev/acpi/acpivar.h>
93 #define ACPI_MACHDEP_PRIVATE
94 #include <machine/acpi_machdep.h>
95 #include <machine/cpu.h>
96 #ifdef __i386__
97 # include <machine/npx.h>
98 #else
99 # include <machine/fpu.h>
100 #endif
101 #include <machine/mtrr.h>
103 #include <x86/cpuvar.h>
104 #include <x86/x86/tsc.h>
106 #include "opt_vga.h"
108 #include "acpi_wakecode.h"
110 /* Address is also hard-coded in acpi_wakecode.S */
111 static paddr_t acpi_wakeup_paddr = 3 * PAGE_SIZE;
112 static vaddr_t acpi_wakeup_vaddr;
114 static int acpi_md_node = CTL_EOL;
115 int acpi_md_vbios_reset = 1; /* Referenced by dev/pci/vga_pci.c */
116 int acpi_md_vesa_modenum = 0; /* Referenced by arch/x86/x86/genfb_machdep.c */
117 static int acpi_md_beep_on_reset = 0;
119 static int sysctl_md_acpi_vbios_reset(SYSCTLFN_ARGS);
120 static int sysctl_md_acpi_beep_on_reset(SYSCTLFN_ARGS);
122 /* Implemented in acpi_wakeup_low.S. */
123 int acpi_md_sleep_prepare(int);
124 int acpi_md_sleep_exit(int);
125 /* Referenced by acpi_wakeup_low.S. */
126 void acpi_md_sleep_enter(int);
128 #ifdef MULTIPROCESSOR
129 /* Referenced in ipifuncs.c. */
130 void acpi_cpu_sleep(struct cpu_info *);
131 #endif
133 static void
134 acpi_md_sleep_patch(struct cpu_info *ci)
136 #define WAKECODE_FIXUP(offset, type, val) do { \
137 type *addr; \
138 addr = (type *)(acpi_wakeup_vaddr + offset); \
139 *addr = val; \
140 } while (0)
142 #define WAKECODE_BCOPY(offset, type, val) do { \
143 void **addr; \
144 addr = (void **)(acpi_wakeup_vaddr + offset); \
145 memcpy(addr, &(val), sizeof(type)); \
146 } while (0)
148 paddr_t tmp_pdir;
150 tmp_pdir = pmap_init_tmp_pgtbl(acpi_wakeup_paddr);
152 /* Execute Sleep */
153 memcpy((void *)acpi_wakeup_vaddr, wakecode, sizeof(wakecode));
155 if (CPU_IS_PRIMARY(ci)) {
156 WAKECODE_FIXUP(WAKEUP_vesa_modenum, uint16_t, acpi_md_vesa_modenum);
157 WAKECODE_FIXUP(WAKEUP_vbios_reset, uint8_t, acpi_md_vbios_reset);
158 WAKECODE_FIXUP(WAKEUP_beep_on_reset, uint8_t, acpi_md_beep_on_reset);
159 } else {
160 WAKECODE_FIXUP(WAKEUP_vesa_modenum, uint16_t, 0);
161 WAKECODE_FIXUP(WAKEUP_vbios_reset, uint8_t, 0);
162 WAKECODE_FIXUP(WAKEUP_beep_on_reset, uint8_t, 0);
165 #ifdef __i386__
166 WAKECODE_FIXUP(WAKEUP_r_cr4, uint32_t, ci->ci_suspend_cr4);
167 #else
168 WAKECODE_FIXUP(WAKEUP_efer, uint32_t, ci->ci_suspend_efer);
169 #endif
171 WAKECODE_FIXUP(WAKEUP_curcpu, void *, ci);
172 #ifdef __i386__
173 WAKECODE_FIXUP(WAKEUP_r_cr3, uint32_t, tmp_pdir);
174 #else
175 WAKECODE_FIXUP(WAKEUP_r_cr3, uint64_t, tmp_pdir);
176 #endif
177 WAKECODE_FIXUP(WAKEUP_restorecpu, void *, acpi_md_sleep_exit);
178 #undef WAKECODE_FIXUP
179 #undef WAKECODE_BCOPY
183 * S4 sleep using S4BIOS support, from FreeBSD.
185 * FreeBSD: src/sys/dev/acpica/acpica_support.c,v 1.4 2002/03/12 09:45:17 dfr Exp
188 static ACPI_STATUS
189 enter_s4_with_bios(void)
191 ACPI_OBJECT_LIST ArgList;
192 ACPI_OBJECT Arg;
193 UINT32 ret;
194 ACPI_STATUS status;
196 /* run the _PTS and _GTS methods */
198 ACPI_MEMSET(&ArgList, 0, sizeof(ArgList));
199 ArgList.Count = 1;
200 ArgList.Pointer = &Arg;
202 ACPI_MEMSET(&Arg, 0, sizeof(Arg));
203 Arg.Type = ACPI_TYPE_INTEGER;
204 Arg.Integer.Value = ACPI_STATE_S4;
206 AcpiEvaluateObject(NULL, "\\_PTS", &ArgList, NULL);
207 AcpiEvaluateObject(NULL, "\\_GTS", &ArgList, NULL);
209 /* clear wake status */
211 AcpiWriteBitRegister(ACPI_BITREG_WAKE_STATUS, 1);
213 AcpiHwDisableAllGpes();
214 AcpiHwEnableAllWakeupGpes();
216 /* flush caches */
218 ACPI_FLUSH_CPU_CACHE();
221 * write the value to command port and wait until we enter sleep state
223 do {
224 AcpiOsStall(1000000);
225 AcpiOsWritePort(AcpiGbl_FADT.SmiCommand,
226 AcpiGbl_FADT.S4BiosRequest, 8);
227 status = AcpiReadBitRegister(ACPI_BITREG_WAKE_STATUS, &ret);
228 if (ACPI_FAILURE(status))
229 break;
230 } while (!ret);
232 AcpiHwDisableAllGpes();
233 AcpiHwEnableAllRuntimeGpes();
235 return (AE_OK);
238 void
239 acpi_md_sleep_enter(int state)
241 ACPI_STATUS status;
242 struct cpu_info *ci;
244 ci = curcpu();
246 #ifdef MULTIPROCESSOR
247 if (!CPU_IS_PRIMARY(ci)) {
248 atomic_and_32(&ci->ci_flags, ~CPUF_RUNNING);
249 atomic_and_32(&cpus_running, ~ci->ci_cpumask);
251 ACPI_FLUSH_CPU_CACHE();
253 for (;;)
254 x86_hlt();
256 #endif
258 acpi_md_sleep_patch(ci);
260 ACPI_FLUSH_CPU_CACHE();
262 if (state == ACPI_STATE_S4) {
263 ACPI_TABLE_FACS *facs;
264 status = AcpiGetTable(ACPI_SIG_FACS, 0, (ACPI_TABLE_HEADER **)&facs);
265 if (ACPI_FAILURE(status)) {
266 printf("acpi: S4BIOS not supported: cannot load FACS\n");
267 return;
269 if (facs == NULL ||
270 (facs->Flags & ACPI_FACS_S4_BIOS_PRESENT) == 0) {
271 printf("acpi: S4BIOS not supported: not present");
272 return;
274 status = enter_s4_with_bios();
275 } else {
276 status = AcpiEnterSleepState(state);
279 if (ACPI_FAILURE(status)) {
280 printf("acpi: AcpiEnterSleepState failed: %s\n",
281 AcpiFormatException(status));
282 return;
285 for (;;)
286 x86_hlt();
289 #ifdef MULTIPROCESSOR
290 void
291 acpi_cpu_sleep(struct cpu_info *ci)
293 KASSERT(!CPU_IS_PRIMARY(ci));
294 KASSERT(ci == curcpu());
296 x86_disable_intr();
298 if (acpi_md_sleep_prepare(-1))
299 return;
301 /* Execute Wakeup */
302 #ifdef __i386__
303 npxinit(ci);
304 #else
305 cpu_init_msrs(ci, false);
306 fpuinit(ci);
307 #endif
308 #if NLAPIC > 0
309 lapic_enable();
310 lapic_set_lvt();
311 lapic_initclocks();
312 #endif
314 atomic_or_32(&ci->ci_flags, CPUF_RUNNING);
315 atomic_or_32(&cpus_running, ci->ci_cpumask);
316 tsc_sync_ap(ci);
318 x86_enable_intr();
320 #endif
323 acpi_md_sleep(int state)
325 int s, ret = 0;
326 #ifdef MULTIPROCESSOR
327 struct cpu_info *ci;
328 CPU_INFO_ITERATOR cii;
329 #endif
331 KASSERT(acpi_wakeup_paddr != 0);
332 KASSERT(sizeof(wakecode) <= PAGE_SIZE);
334 if (!CPU_IS_PRIMARY(curcpu())) {
335 printf("acpi0: WARNING: ignoring sleep from secondary CPU\n");
336 return -1;
339 AcpiSetFirmwareWakingVector(acpi_wakeup_paddr);
341 s = splhigh();
342 #ifdef __i386__
343 npxsave_cpu(true);
344 #else
345 fpusave_cpu(true);
346 #endif
347 x86_disable_intr();
349 #ifdef MULTIPROCESSOR
350 /* Save and suspend Application Processors */
351 x86_broadcast_ipi(X86_IPI_ACPI_CPU_SLEEP);
352 while (cpus_running != curcpu()->ci_cpumask)
353 delay(1);
354 #endif
356 if (acpi_md_sleep_prepare(state))
357 goto out;
359 /* Execute Wakeup */
360 #ifdef __i386__
361 npxinit(&cpu_info_primary);
362 #else
363 cpu_init_msrs(&cpu_info_primary, false);
364 fpuinit(&cpu_info_primary);
365 #endif
366 i8259_reinit();
367 #if NLAPIC > 0
368 lapic_enable();
369 lapic_set_lvt();
370 lapic_initclocks();
371 #endif
372 #if NIOAPIC > 0
373 ioapic_reenable();
374 #endif
376 initrtclock(TIMER_FREQ);
377 inittodr(time_second);
379 AcpiClearEvent(ACPI_EVENT_PMTIMER);
380 AcpiClearEvent(ACPI_EVENT_GLOBAL);
381 AcpiClearEvent(ACPI_EVENT_POWER_BUTTON);
382 AcpiClearEvent(ACPI_EVENT_SLEEP_BUTTON);
383 AcpiClearEvent(ACPI_EVENT_RTC);
384 AcpiHwDisableAllGpes ();
386 acpi_pci_link_resume();
388 out:
390 #ifdef MULTIPROCESSOR
391 for (CPU_INFO_FOREACH(cii, ci)) {
392 if (CPU_IS_PRIMARY(ci))
393 continue;
394 acpi_md_sleep_patch(ci);
396 CPU_STARTUP(ci, acpi_wakeup_paddr);
397 CPU_START_CLEANUP(ci);
399 while ((ci->ci_flags & CPUF_RUNNING) == 0)
400 x86_pause();
402 tsc_sync_bp(ci);
404 #endif
406 x86_enable_intr();
407 splx(s);
409 #ifdef MTRR
410 if (mtrr_funcs != NULL)
411 mtrr_commit();
412 #endif
414 return (ret);
417 void
418 acpi_md_sleep_init(void)
420 /* Map ACPI wakecode */
421 acpi_wakeup_vaddr = uvm_km_alloc(kernel_map, PAGE_SIZE, 0,
422 UVM_KMF_VAONLY);
423 if (acpi_wakeup_vaddr == 0)
424 panic("acpi: can't allocate address for wakecode.\n");
426 pmap_kenter_pa(acpi_wakeup_vaddr, acpi_wakeup_paddr,
427 VM_PROT_READ | VM_PROT_WRITE, 0);
428 pmap_update(pmap_kernel());
431 SYSCTL_SETUP(sysctl_md_acpi_setup, "acpi x86 sysctl setup")
433 const struct sysctlnode *node;
434 const struct sysctlnode *ssnode;
436 if (sysctl_createv(NULL, 0, NULL, &node, CTLFLAG_PERMANENT,
437 CTLTYPE_NODE, "machdep", NULL, NULL, 0, NULL, 0, CTL_MACHDEP,
438 CTL_EOL) != 0)
439 return;
440 if (sysctl_createv(NULL, 0, &node, &ssnode, CTLFLAG_READWRITE,
441 CTLTYPE_INT, "acpi_vbios_reset", NULL, sysctl_md_acpi_vbios_reset,
442 0, NULL, 0, CTL_CREATE, CTL_EOL) != 0)
443 return;
444 if (sysctl_createv(NULL, 0, &node, &ssnode, CTLFLAG_READWRITE,
445 CTLTYPE_INT, "acpi_beep_on_reset", NULL, sysctl_md_acpi_beep_on_reset,
446 0, NULL, 0, CTL_CREATE, CTL_EOL) != 0)
447 return;
449 acpi_md_node = node->sysctl_num;
452 static int
453 sysctl_md_acpi_vbios_reset(SYSCTLFN_ARGS)
455 int error, t;
456 struct sysctlnode node;
458 node = *rnode;
459 t = acpi_md_vbios_reset;
460 node.sysctl_data = &t;
461 error = sysctl_lookup(SYSCTLFN_CALL(&node));
462 if (error || newp == NULL)
463 return error;
465 if (t < 0 || t > 2)
466 return EINVAL;
468 #ifndef VGA_POST
469 if (t == 2) {
470 aprint_error("WARNING: machdep.acpi_vbios_reset=2 "
471 "unsupported (no option VGA_POST in kernel config)\n");
472 return EINVAL;
474 #endif
476 acpi_md_vbios_reset = t;
478 return 0;
481 static int
482 sysctl_md_acpi_beep_on_reset(SYSCTLFN_ARGS)
484 int error, t;
485 struct sysctlnode node;
487 node = *rnode;
488 t = acpi_md_beep_on_reset;
489 node.sysctl_data = &t;
490 error = sysctl_lookup(SYSCTLFN_CALL(&node));
491 if (error || newp == NULL)
492 return error;
494 if (t < 0 || t > 1)
495 return EINVAL;
497 acpi_md_beep_on_reset = t;
499 return 0;