1 /* $NetBSD: acpi_wakeup.c,v 1.49 2017/09/23 10:38:59 maxv 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 /*- 33 * Copyright (c) 2001 Takanori Watanabe <takawata@jp.freebsd.org> 34 * Copyright (c) 2001 Mitsuru IWASAKI <iwasaki@jp.freebsd.org> 35 * All rights reserved. 36 * 37 * Redistribution and use in source and binary forms, with or without 38 * modification, are permitted provided that the following conditions 39 * are met: 40 * 1. Redistributions of source code must retain the above copyright 41 * notice, this list of conditions and the following disclaimer. 42 * 2. Redistributions in binary form must reproduce the above copyright 43 * notice, this list of conditions and the following disclaimer in the 44 * documentation and/or other materials provided with the distribution. 45 * 46 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 47 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 48 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 49 * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 50 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 51 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 52 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 53 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 54 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 55 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 56 * SUCH DAMAGE. 57 * 58 * FreeBSD: src/sys/i386/acpica/acpi_wakeup.c,v 1.9 2002/01/10 03:26:46 wes Exp 59 */ 60 61 #include <sys/cdefs.h> 62 __KERNEL_RCSID(0, "$NetBSD: acpi_wakeup.c,v 1.49 2017/09/23 10:38:59 maxv Exp $"); 63 64 #include <sys/param.h> 65 #include <sys/systm.h> 66 #include <sys/kernel.h> 67 #include <sys/bus.h> 68 #include <sys/cpu.h> 69 #include <sys/kcpuset.h> 70 #include <sys/sysctl.h> 71 72 #include <uvm/uvm_extern.h> 73 #include <uvm/uvm_page.h> 74 75 #ifdef __i386__ 76 #include "opt_mtrr.h" 77 #endif 78 #include "ioapic.h" 79 #include "lapic.h" 80 81 #if NLAPIC > 0 82 #include <machine/i82489var.h> 83 #endif 84 #if NIOAPIC > 0 85 #include <machine/i82093var.h> 86 #endif 87 #include <machine/i8259.h> 88 89 #include "acpica.h" 90 91 #include <dev/ic/i8253reg.h> 92 #include <dev/acpi/acpica.h> 93 #include <dev/acpi/acpivar.h> 94 #define ACPI_MACHDEP_PRIVATE 95 #include <machine/acpi_machdep.h> 96 #include <machine/cpu.h> 97 #include <machine/mtrr.h> 98 99 #include <x86/cpuvar.h> 100 #include <x86/x86/tsc.h> 101 #include <x86/fpu.h> 102 103 #include "opt_vga.h" 104 105 #include "acpi_wakecode.h" 106 107 /* Address is also hard-coded in acpi_wakecode.S */ 108 static paddr_t acpi_wakeup_paddr = 3 * PAGE_SIZE; 109 static vaddr_t acpi_wakeup_vaddr; 110 111 int acpi_md_vbios_reset = 0; /* Referenced by dev/pci/vga_pci.c */ 112 int acpi_md_vesa_modenum = 0; /* Referenced by arch/x86/x86/genfb_machdep.c */ 113 static int acpi_md_beep_on_reset = 0; 114 115 static int acpi_md_s4bios(void); 116 static int sysctl_md_acpi_vbios_reset(SYSCTLFN_ARGS); 117 static int sysctl_md_acpi_beep_on_reset(SYSCTLFN_ARGS); 118 119 /* Implemented in acpi_wakeup_low.S. */ 120 int acpi_md_sleep_prepare(int); 121 int acpi_md_sleep_exit(int); 122 123 /* Referenced by acpi_wakeup_low.S. */ 124 void acpi_md_sleep_enter(int); 125 126 #ifdef MULTIPROCESSOR 127 /* Referenced in ipifuncs.c. */ 128 void acpi_cpu_sleep(struct cpu_info *); 129 #endif 130 131 static void 132 acpi_md_sleep_patch(struct cpu_info *ci) 133 { 134 #define WAKECODE_FIXUP(offset, type, val) do { \ 135 type *addr; \ 136 addr = (type *)(acpi_wakeup_vaddr + offset); \ 137 *addr = val; \ 138 } while (0) 139 140 paddr_t tmp_pdir; 141 142 tmp_pdir = pmap_init_tmp_pgtbl(acpi_wakeup_paddr); 143 144 memcpy((void *)acpi_wakeup_vaddr, wakecode, sizeof(wakecode)); 145 146 if (CPU_IS_PRIMARY(ci)) { 147 WAKECODE_FIXUP(WAKEUP_vesa_modenum, uint16_t, acpi_md_vesa_modenum); 148 WAKECODE_FIXUP(WAKEUP_vbios_reset, uint8_t, acpi_md_vbios_reset); 149 WAKECODE_FIXUP(WAKEUP_beep_on_reset, uint8_t, acpi_md_beep_on_reset); 150 } else { 151 WAKECODE_FIXUP(WAKEUP_vesa_modenum, uint16_t, 0); 152 WAKECODE_FIXUP(WAKEUP_vbios_reset, uint8_t, 0); 153 WAKECODE_FIXUP(WAKEUP_beep_on_reset, uint8_t, 0); 154 } 155 156 #ifdef __i386__ 157 WAKECODE_FIXUP(WAKEUP_r_cr4, uint32_t, ci->ci_suspend_cr4); 158 #endif 159 WAKECODE_FIXUP(WAKEUP_efer, uint32_t, ci->ci_suspend_efer); 160 WAKECODE_FIXUP(WAKEUP_curcpu, void *, ci); 161 #ifdef __i386__ 162 WAKECODE_FIXUP(WAKEUP_r_cr3, uint32_t, tmp_pdir); 163 #else 164 WAKECODE_FIXUP(WAKEUP_r_cr3, uint64_t, tmp_pdir); 165 #endif 166 WAKECODE_FIXUP(WAKEUP_restorecpu, void *, acpi_md_sleep_exit); 167 #undef WAKECODE_FIXUP 168 } 169 170 static int 171 acpi_md_s4bios(void) 172 { 173 ACPI_TABLE_FACS *facs; 174 ACPI_STATUS rv; 175 176 rv = AcpiGetTable(ACPI_SIG_FACS, 0, (ACPI_TABLE_HEADER **)&facs); 177 178 if (ACPI_FAILURE(rv) || facs == NULL) 179 return 0; 180 181 if ((facs->Flags & ACPI_FACS_S4_BIOS_PRESENT) == 0) 182 return 0; 183 184 return 1; 185 } 186 187 void 188 acpi_md_sleep_enter(int state) 189 { 190 static int s4bios = -1; 191 struct cpu_info *ci; 192 ACPI_STATUS rv; 193 194 ci = curcpu(); 195 196 #ifdef MULTIPROCESSOR 197 if (!CPU_IS_PRIMARY(ci)) { 198 atomic_and_32(&ci->ci_flags, ~CPUF_RUNNING); 199 kcpuset_atomic_clear(kcpuset_running, cpu_index(ci)); 200 201 ACPI_FLUSH_CPU_CACHE(); 202 203 for (;;) 204 x86_hlt(); 205 } 206 #endif 207 208 acpi_md_sleep_patch(ci); 209 210 ACPI_FLUSH_CPU_CACHE(); 211 212 switch (state) { 213 214 case ACPI_STATE_S4: 215 216 if (s4bios < 0) 217 s4bios = acpi_md_s4bios(); 218 219 if (s4bios == 0) { 220 aprint_error("acpi0: S4 not supported\n"); 221 return; 222 } 223 224 rv = AcpiEnterSleepStateS4bios(); 225 break; 226 227 default: 228 rv = AcpiEnterSleepState(state); 229 break; 230 } 231 232 if (ACPI_FAILURE(rv)) { 233 aprint_error("acpi0: failed to enter S%d\n", state); 234 return; 235 } 236 237 for (;;) 238 x86_hlt(); 239 } 240 241 #ifdef MULTIPROCESSOR 242 void 243 acpi_cpu_sleep(struct cpu_info *ci) 244 { 245 uint64_t xcr0 = 0; 246 int s; 247 248 KASSERT(!CPU_IS_PRIMARY(ci)); 249 KASSERT(ci == curcpu()); 250 251 s = splhigh(); 252 fpusave_cpu(true); 253 x86_disable_intr(); 254 255 /* 256 * XXX also need to save the PMCs, the dbregs, and probably a few 257 * MSRs too. 258 */ 259 if (rcr4() & CR4_OSXSAVE) 260 xcr0 = rdxcr(0); 261 262 /* Go get some sleep */ 263 if (acpi_md_sleep_prepare(-1)) 264 goto out; 265 266 /* 267 * Sleeping and having bad nightmares about what could go wrong 268 * when waking up. 269 */ 270 271 /* We just woke up (cpuN), execution is resumed here */ 272 cpu_init_msrs(ci, false); 273 fpuinit(ci); 274 if (rcr4() & CR4_OSXSAVE) 275 wrxcr(0, xcr0); 276 pat_init(ci); 277 x86_errata(); 278 #if NLAPIC > 0 279 lapic_enable(); 280 lapic_set_lvt(); 281 lapic_initclocks(); 282 #endif 283 284 atomic_or_32(&ci->ci_flags, CPUF_RUNNING); 285 kcpuset_atomic_set(kcpuset_running, cpu_index(ci)); 286 tsc_sync_ap(ci); 287 288 out: 289 x86_enable_intr(); 290 splx(s); 291 } 292 #endif 293 294 int 295 acpi_md_sleep(int state) 296 { 297 uint64_t xcr0 = 0; 298 int s, ret = 0; 299 #ifdef MULTIPROCESSOR 300 struct cpu_info *ci; 301 CPU_INFO_ITERATOR cii; 302 cpuid_t cid; 303 #endif 304 305 KASSERT(acpi_wakeup_paddr != 0); 306 KASSERT(sizeof(wakecode) <= PAGE_SIZE); 307 308 if (!CPU_IS_PRIMARY(curcpu())) { 309 printf("acpi0: WARNING: ignoring sleep from secondary CPU\n"); 310 return -1; 311 } 312 313 AcpiSetFirmwareWakingVector(acpi_wakeup_paddr, acpi_wakeup_paddr); 314 315 s = splhigh(); 316 fpusave_cpu(true); 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 /* 329 * XXX also need to save the PMCs, the dbregs, and probably a few 330 * MSRs too. 331 */ 332 if (rcr4() & CR4_OSXSAVE) 333 xcr0 = rdxcr(0); 334 335 /* Go get some sleep */ 336 if (acpi_md_sleep_prepare(state)) 337 goto out; 338 339 /* 340 * Sleeping and having bad nightmares about what could go wrong 341 * when waking up. 342 */ 343 344 /* We just woke up (cpu0), execution is resumed here */ 345 cpu_init_msrs(&cpu_info_primary, false); 346 fpuinit(&cpu_info_primary); 347 if (rcr4() & CR4_OSXSAVE) 348 wrxcr(0, xcr0); 349 pat_init(&cpu_info_primary); 350 x86_errata(); 351 i8259_reinit(); 352 #if NLAPIC > 0 353 lapic_enable(); 354 lapic_set_lvt(); 355 lapic_initclocks(); 356 #endif 357 #if NIOAPIC > 0 358 ioapic_reenable(); 359 #endif 360 361 initrtclock(TIMER_FREQ); 362 inittodr(time_second); 363 364 /* 365 * The BIOS should always re-enable the SCI upon 366 * resume from the S3 state. The following is a 367 * workaround for systems that fail to do this. 368 */ 369 (void)AcpiWriteBitRegister(ACPI_BITREG_SCI_ENABLE, 1); 370 371 /* 372 * Clear fixed events (see e.g. ACPI 3.0, p. 62). 373 * Also prevent GPEs from misfiring by disabling 374 * all GPEs before interrupts are enabled. The 375 * AcpiLeaveSleepState() function will enable 376 * and handle the general purpose events later. 377 */ 378 (void)AcpiClearEvent(ACPI_EVENT_PMTIMER); 379 (void)AcpiClearEvent(ACPI_EVENT_GLOBAL); 380 (void)AcpiClearEvent(ACPI_EVENT_POWER_BUTTON); 381 (void)AcpiClearEvent(ACPI_EVENT_SLEEP_BUTTON); 382 (void)AcpiClearEvent(ACPI_EVENT_RTC); 383 (void)AcpiHwDisableAllGpes(); 384 385 acpi_pci_link_resume(); 386 387 out: 388 389 #ifdef MULTIPROCESSOR 390 /* Wake up the secondary CPUs */ 391 for (CPU_INFO_FOREACH(cii, ci)) { 392 if (CPU_IS_PRIMARY(ci)) 393 continue; 394 acpi_md_sleep_patch(ci); 395 396 CPU_STARTUP(ci, acpi_wakeup_paddr); 397 CPU_START_CLEANUP(ci); 398 399 while ((ci->ci_flags & CPUF_RUNNING) == 0) 400 x86_pause(); 401 402 tsc_sync_bp(ci); 403 } 404 #endif 405 406 x86_enable_intr(); 407 splx(s); 408 409 #ifdef MTRR 410 if (mtrr_funcs != NULL) 411 mtrr_commit(); 412 #endif 413 414 return (ret); 415 } 416 417 void 418 acpi_md_sleep_init(void) 419 { 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"); 425 426 pmap_kenter_pa(acpi_wakeup_vaddr, acpi_wakeup_paddr, 427 VM_PROT_READ | VM_PROT_WRITE, 0); 428 pmap_update(pmap_kernel()); 429 } 430 431 SYSCTL_SETUP(sysctl_md_acpi_setup, "ACPI x86 sysctl setup") 432 { 433 const struct sysctlnode *rnode; 434 int err; 435 436 err = sysctl_createv(clog, 0, NULL, &rnode, 437 CTLFLAG_PERMANENT, CTLTYPE_NODE, "acpi", NULL, 438 NULL, 0, NULL, 0, CTL_HW, CTL_CREATE, CTL_EOL); 439 440 if (err != 0) 441 return; 442 443 err = sysctl_createv(clog, 0, &rnode, &rnode, 444 CTLFLAG_PERMANENT, CTLTYPE_NODE, 445 "sleep", SYSCTL_DESCR("ACPI sleep"), 446 NULL, 0, NULL, 0, CTL_CREATE, CTL_EOL); 447 448 if (err != 0) 449 return; 450 451 (void)sysctl_createv(NULL, 0, &rnode, NULL, 452 CTLFLAG_READWRITE, CTLTYPE_BOOL, "beep", 453 NULL, sysctl_md_acpi_beep_on_reset, 454 0, NULL, 0, CTL_CREATE, CTL_EOL); 455 456 (void)sysctl_createv(NULL, 0, &rnode, NULL, 457 CTLFLAG_READWRITE, CTLTYPE_INT, "vbios", 458 NULL, sysctl_md_acpi_vbios_reset, 459 0, NULL, 0, CTL_CREATE, CTL_EOL); 460 } 461 462 static int 463 sysctl_md_acpi_vbios_reset(SYSCTLFN_ARGS) 464 { 465 int error, t; 466 struct sysctlnode node; 467 468 node = *rnode; 469 t = acpi_md_vbios_reset; 470 node.sysctl_data = &t; 471 error = sysctl_lookup(SYSCTLFN_CALL(&node)); 472 if (error || newp == NULL) 473 return error; 474 475 if (t < 0 || t > 2) 476 return EINVAL; 477 478 #ifndef VGA_POST 479 if (t == 2) { 480 aprint_error("WARNING: hw.acpi.sleep.vbios=2 " 481 "unsupported (no option VGA_POST in kernel config)\n"); 482 return EINVAL; 483 } 484 #endif 485 486 acpi_md_vbios_reset = t; 487 488 return 0; 489 } 490 491 static int 492 sysctl_md_acpi_beep_on_reset(SYSCTLFN_ARGS) 493 { 494 int error, t; 495 struct sysctlnode node; 496 497 node = *rnode; 498 t = acpi_md_beep_on_reset; 499 node.sysctl_data = &t; 500 error = sysctl_lookup(SYSCTLFN_CALL(&node)); 501 if (error || newp == NULL) 502 return error; 503 504 if (t < 0 || t > 1) 505 return EINVAL; 506 507 acpi_md_beep_on_reset = t; 508 509 return 0; 510 } 511