1 /* $NetBSD: acpi_wakeup.c,v 1.34 2013/12/01 01:05:16 christos Exp $ */ 2 3 /*- 4 * Copyright (c) 2002, 2011 The NetBSD Foundation, Inc. 5 * All rights reserved. 6 * 7 * This code is derived from software contributed to The NetBSD Foundation 8 * by Takuya SHIOZAKI. 9 * 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. 18 * 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. 30 */ 31 32 #include <sys/cdefs.h> 33 __KERNEL_RCSID(0, "$NetBSD: acpi_wakeup.c,v 1.34 2013/12/01 01:05:16 christos Exp $"); 34 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. 39 * 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. 48 * 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. 60 * 61 * FreeBSD: src/sys/i386/acpica/acpi_wakeup.c,v 1.9 2002/01/10 03:26:46 wes Exp 62 */ 63 64 #include <sys/cdefs.h> 65 __KERNEL_RCSID(0, "$NetBSD: acpi_wakeup.c,v 1.34 2013/12/01 01:05:16 christos Exp $"); 66 67 #include <sys/param.h> 68 #include <sys/systm.h> 69 #include <sys/kernel.h> 70 #include <sys/bus.h> 71 #include <sys/cpu.h> 72 #include <sys/kcpuset.h> 73 #include <sys/sysctl.h> 74 75 #include <uvm/uvm_extern.h> 76 #include <uvm/uvm_page.h> 77 78 #ifdef __i386__ 79 #include "opt_mtrr.h" 80 #endif 81 #include "ioapic.h" 82 #include "lapic.h" 83 84 #if NLAPIC > 0 85 #include <machine/i82489var.h> 86 #endif 87 #if NIOAPIC > 0 88 #include <machine/i82093var.h> 89 #endif 90 #include <machine/i8259.h> 91 92 #include "acpica.h" 93 94 #include <dev/ic/i8253reg.h> 95 #include <dev/acpi/acpica.h> 96 #include <dev/acpi/acpivar.h> 97 #define ACPI_MACHDEP_PRIVATE 98 #include <machine/acpi_machdep.h> 99 #include <machine/cpu.h> 100 #ifdef __i386__ 101 # include <machine/npx.h> 102 #else 103 # include <machine/fpu.h> 104 #endif 105 #include <machine/mtrr.h> 106 107 #include <x86/cpuvar.h> 108 #include <x86/x86/tsc.h> 109 110 #include "opt_vga.h" 111 112 #include "acpi_wakecode.h" 113 114 /* Address is also hard-coded in acpi_wakecode.S */ 115 static paddr_t acpi_wakeup_paddr = 3 * PAGE_SIZE; 116 static vaddr_t acpi_wakeup_vaddr; 117 118 int acpi_md_vbios_reset = 1; /* Referenced by dev/pci/vga_pci.c */ 119 int acpi_md_vesa_modenum = 0; /* Referenced by arch/x86/x86/genfb_machdep.c */ 120 static int acpi_md_beep_on_reset = 0; 121 122 static int acpi_md_s4bios(void); 123 static int sysctl_md_acpi_vbios_reset(SYSCTLFN_ARGS); 124 static int sysctl_md_acpi_beep_on_reset(SYSCTLFN_ARGS); 125 126 /* Implemented in acpi_wakeup_low.S. */ 127 int acpi_md_sleep_prepare(int); 128 int acpi_md_sleep_exit(int); 129 130 /* Referenced by acpi_wakeup_low.S. */ 131 void acpi_md_sleep_enter(int); 132 133 #ifdef MULTIPROCESSOR 134 /* Referenced in ipifuncs.c. */ 135 void acpi_cpu_sleep(struct cpu_info *); 136 #endif 137 138 static void 139 acpi_md_sleep_patch(struct cpu_info *ci) 140 { 141 #define WAKECODE_FIXUP(offset, type, val) do { \ 142 type *addr; \ 143 addr = (type *)(acpi_wakeup_vaddr + offset); \ 144 *addr = val; \ 145 } while (0) 146 147 #define WAKECODE_BCOPY(offset, type, val) do { \ 148 void **addr; \ 149 addr = (void **)(acpi_wakeup_vaddr + offset); \ 150 memcpy(addr, &(val), sizeof(type)); \ 151 } while (0) 152 153 paddr_t tmp_pdir; 154 155 tmp_pdir = pmap_init_tmp_pgtbl(acpi_wakeup_paddr); 156 157 /* Execute Sleep */ 158 memcpy((void *)acpi_wakeup_vaddr, wakecode, sizeof(wakecode)); 159 160 if (CPU_IS_PRIMARY(ci)) { 161 WAKECODE_FIXUP(WAKEUP_vesa_modenum, uint16_t, acpi_md_vesa_modenum); 162 WAKECODE_FIXUP(WAKEUP_vbios_reset, uint8_t, acpi_md_vbios_reset); 163 WAKECODE_FIXUP(WAKEUP_beep_on_reset, uint8_t, acpi_md_beep_on_reset); 164 } else { 165 WAKECODE_FIXUP(WAKEUP_vesa_modenum, uint16_t, 0); 166 WAKECODE_FIXUP(WAKEUP_vbios_reset, uint8_t, 0); 167 WAKECODE_FIXUP(WAKEUP_beep_on_reset, uint8_t, 0); 168 } 169 170 #ifdef __i386__ 171 WAKECODE_FIXUP(WAKEUP_r_cr4, uint32_t, ci->ci_suspend_cr4); 172 #else 173 WAKECODE_FIXUP(WAKEUP_efer, uint32_t, ci->ci_suspend_efer); 174 #endif 175 176 WAKECODE_FIXUP(WAKEUP_curcpu, void *, ci); 177 #ifdef __i386__ 178 WAKECODE_FIXUP(WAKEUP_r_cr3, uint32_t, tmp_pdir); 179 #else 180 WAKECODE_FIXUP(WAKEUP_r_cr3, uint64_t, tmp_pdir); 181 #endif 182 WAKECODE_FIXUP(WAKEUP_restorecpu, void *, acpi_md_sleep_exit); 183 #undef WAKECODE_FIXUP 184 #undef WAKECODE_BCOPY 185 } 186 187 static int 188 acpi_md_s4bios(void) 189 { 190 ACPI_TABLE_FACS *facs; 191 ACPI_STATUS rv; 192 193 rv = AcpiGetTable(ACPI_SIG_FACS, 0, (ACPI_TABLE_HEADER **)&facs); 194 195 if (ACPI_FAILURE(rv) || facs == NULL) 196 return 0; 197 198 if ((facs->Flags & ACPI_FACS_S4_BIOS_PRESENT) == 0) 199 return 0; 200 201 return 1; 202 } 203 204 void 205 acpi_md_sleep_enter(int state) 206 { 207 static int s4bios = -1; 208 struct cpu_info *ci; 209 ACPI_STATUS rv; 210 211 ci = curcpu(); 212 213 #ifdef MULTIPROCESSOR 214 if (!CPU_IS_PRIMARY(ci)) { 215 atomic_and_32(&ci->ci_flags, ~CPUF_RUNNING); 216 kcpuset_atomic_clear(kcpuset_running, cpu_index(ci)); 217 218 ACPI_FLUSH_CPU_CACHE(); 219 220 for (;;) 221 x86_hlt(); 222 } 223 #endif 224 225 acpi_md_sleep_patch(ci); 226 227 ACPI_FLUSH_CPU_CACHE(); 228 229 switch (state) { 230 231 case ACPI_STATE_S4: 232 233 if (s4bios < 0) 234 s4bios = acpi_md_s4bios(); 235 236 if (s4bios == 0) { 237 aprint_error("acpi0: S4 not supported\n"); 238 return; 239 } 240 241 rv = AcpiEnterSleepStateS4bios(); 242 break; 243 244 default: 245 rv = AcpiEnterSleepState(state); 246 break; 247 } 248 249 if (ACPI_FAILURE(rv)) { 250 aprint_error("acpi0: failed to enter S%d\n", state); 251 return; 252 } 253 254 for (;;) 255 x86_hlt(); 256 } 257 258 #ifdef MULTIPROCESSOR 259 void 260 acpi_cpu_sleep(struct cpu_info *ci) 261 { 262 KASSERT(!CPU_IS_PRIMARY(ci)); 263 KASSERT(ci == curcpu()); 264 265 x86_disable_intr(); 266 267 if (acpi_md_sleep_prepare(-1)) 268 return; 269 270 /* Execute Wakeup */ 271 #ifdef __i386__ 272 npxinit(ci); 273 #else 274 cpu_init_msrs(ci, false); 275 fpuinit(ci); 276 #endif 277 #if NLAPIC > 0 278 lapic_enable(); 279 lapic_set_lvt(); 280 lapic_initclocks(); 281 #endif 282 283 atomic_or_32(&ci->ci_flags, CPUF_RUNNING); 284 kcpuset_atomic_set(kcpuset_running, cpu_index(ci)); 285 tsc_sync_ap(ci); 286 287 x86_enable_intr(); 288 } 289 #endif 290 291 int 292 acpi_md_sleep(int state) 293 { 294 int s, ret = 0; 295 #ifdef MULTIPROCESSOR 296 struct cpu_info *ci; 297 CPU_INFO_ITERATOR cii; 298 cpuid_t cid; 299 #endif 300 301 KASSERT(acpi_wakeup_paddr != 0); 302 KASSERT(sizeof(wakecode) <= PAGE_SIZE); 303 304 if (!CPU_IS_PRIMARY(curcpu())) { 305 printf("acpi0: WARNING: ignoring sleep from secondary CPU\n"); 306 return -1; 307 } 308 309 AcpiSetFirmwareWakingVector(acpi_wakeup_paddr); 310 311 s = splhigh(); 312 #ifdef __i386__ 313 npxsave_cpu(true); 314 #else 315 fpusave_cpu(true); 316 #endif 317 x86_disable_intr(); 318 319 #ifdef MULTIPROCESSOR 320 /* Save and suspend Application Processors. */ 321 x86_broadcast_ipi(X86_IPI_ACPI_CPU_SLEEP); 322 cid = cpu_index(curcpu()); 323 while (kcpuset_isotherset(kcpuset_running, cid)) { 324 delay(1); 325 } 326 #endif 327 328 if (acpi_md_sleep_prepare(state)) 329 goto out; 330 331 /* Execute Wakeup */ 332 #ifdef __i386__ 333 npxinit(&cpu_info_primary); 334 #else 335 cpu_init_msrs(&cpu_info_primary, false); 336 fpuinit(&cpu_info_primary); 337 #endif 338 i8259_reinit(); 339 #if NLAPIC > 0 340 lapic_enable(); 341 lapic_set_lvt(); 342 lapic_initclocks(); 343 #endif 344 #if NIOAPIC > 0 345 ioapic_reenable(); 346 #endif 347 348 initrtclock(TIMER_FREQ); 349 inittodr(time_second); 350 351 /* 352 * The BIOS should always re-enable the SCI upon 353 * resume from the S3 state. The following is a 354 * workaround for systems that fail to do this. 355 */ 356 (void)AcpiWriteBitRegister(ACPI_BITREG_SCI_ENABLE, 1); 357 358 /* 359 * Clear fixed events (see e.g. ACPI 3.0, p. 62). 360 * Also prevent GPEs from misfiring by disabling 361 * all GPEs before interrupts are enabled. The 362 * AcpiLeaveSleepState() function will enable 363 * and handle the general purpose events later. 364 */ 365 (void)AcpiClearEvent(ACPI_EVENT_PMTIMER); 366 (void)AcpiClearEvent(ACPI_EVENT_GLOBAL); 367 (void)AcpiClearEvent(ACPI_EVENT_POWER_BUTTON); 368 (void)AcpiClearEvent(ACPI_EVENT_SLEEP_BUTTON); 369 (void)AcpiClearEvent(ACPI_EVENT_RTC); 370 (void)AcpiHwDisableAllGpes(); 371 372 acpi_pci_link_resume(); 373 374 out: 375 376 #ifdef MULTIPROCESSOR 377 for (CPU_INFO_FOREACH(cii, ci)) { 378 if (CPU_IS_PRIMARY(ci)) 379 continue; 380 acpi_md_sleep_patch(ci); 381 382 CPU_STARTUP(ci, acpi_wakeup_paddr); 383 CPU_START_CLEANUP(ci); 384 385 while ((ci->ci_flags & CPUF_RUNNING) == 0) 386 x86_pause(); 387 388 tsc_sync_bp(ci); 389 } 390 #endif 391 392 x86_enable_intr(); 393 splx(s); 394 395 #ifdef MTRR 396 if (mtrr_funcs != NULL) 397 mtrr_commit(); 398 #endif 399 400 return (ret); 401 } 402 403 void 404 acpi_md_sleep_init(void) 405 { 406 /* Map ACPI wakecode */ 407 acpi_wakeup_vaddr = uvm_km_alloc(kernel_map, PAGE_SIZE, 0, 408 UVM_KMF_VAONLY); 409 if (acpi_wakeup_vaddr == 0) 410 panic("acpi: can't allocate address for wakecode.\n"); 411 412 pmap_kenter_pa(acpi_wakeup_vaddr, acpi_wakeup_paddr, 413 VM_PROT_READ | VM_PROT_WRITE, 0); 414 pmap_update(pmap_kernel()); 415 } 416 417 SYSCTL_SETUP(sysctl_md_acpi_setup, "ACPI x86 sysctl setup") 418 { 419 const struct sysctlnode *rnode; 420 int err; 421 422 err = sysctl_createv(clog, 0, NULL, &rnode, 423 CTLFLAG_PERMANENT, CTLTYPE_NODE, "hw", 424 NULL, NULL, 0, NULL, 0, CTL_HW, CTL_EOL); 425 426 if (err != 0) 427 return; 428 429 err = sysctl_createv(clog, 0, &rnode, &rnode, 430 CTLFLAG_PERMANENT, CTLTYPE_NODE, "acpi", NULL, 431 NULL, 0, NULL, 0, CTL_CREATE, CTL_EOL); 432 433 if (err != 0) 434 return; 435 436 err = sysctl_createv(clog, 0, &rnode, &rnode, 437 CTLFLAG_PERMANENT, CTLTYPE_NODE, 438 "sleep", SYSCTL_DESCR("ACPI sleep"), 439 NULL, 0, NULL, 0, CTL_CREATE, CTL_EOL); 440 441 if (err != 0) 442 return; 443 444 (void)sysctl_createv(NULL, 0, &rnode, NULL, 445 CTLFLAG_READWRITE, CTLTYPE_BOOL, "beep", 446 NULL, sysctl_md_acpi_beep_on_reset, 447 0, NULL, 0, CTL_CREATE, CTL_EOL); 448 449 (void)sysctl_createv(NULL, 0, &rnode, NULL, 450 CTLFLAG_READWRITE, CTLTYPE_INT, "vbios", 451 NULL, sysctl_md_acpi_vbios_reset, 452 0, NULL, 0, CTL_CREATE, CTL_EOL); 453 } 454 455 static int 456 sysctl_md_acpi_vbios_reset(SYSCTLFN_ARGS) 457 { 458 int error, t; 459 struct sysctlnode node; 460 461 node = *rnode; 462 t = acpi_md_vbios_reset; 463 node.sysctl_data = &t; 464 error = sysctl_lookup(SYSCTLFN_CALL(&node)); 465 if (error || newp == NULL) 466 return error; 467 468 if (t < 0 || t > 2) 469 return EINVAL; 470 471 #ifndef VGA_POST 472 if (t == 2) { 473 aprint_error("WARNING: hw.acpi.sleep.vbios=2 " 474 "unsupported (no option VGA_POST in kernel config)\n"); 475 return EINVAL; 476 } 477 #endif 478 479 acpi_md_vbios_reset = t; 480 481 return 0; 482 } 483 484 static int 485 sysctl_md_acpi_beep_on_reset(SYSCTLFN_ARGS) 486 { 487 int error, t; 488 struct sysctlnode node; 489 490 node = *rnode; 491 t = acpi_md_beep_on_reset; 492 node.sysctl_data = &t; 493 error = sysctl_lookup(SYSCTLFN_CALL(&node)); 494 if (error || newp == NULL) 495 return error; 496 497 if (t < 0 || t > 1) 498 return EINVAL; 499 500 acpi_md_beep_on_reset = t; 501 502 return 0; 503 } 504