]> CyberLeo.Net >> Repos - FreeBSD/FreeBSD.git/blob - sys/x86/acpica/acpi_wakeup.c
9539 Make zvol operations use _by_dnode routines
[FreeBSD/FreeBSD.git] / sys / x86 / acpica / acpi_wakeup.c
1 /*-
2  * SPDX-License-Identifier: BSD-2-Clause-FreeBSD
3  *
4  * Copyright (c) 2001 Takanori Watanabe <takawata@jp.freebsd.org>
5  * Copyright (c) 2001-2012 Mitsuru IWASAKI <iwasaki@jp.freebsd.org>
6  * Copyright (c) 2003 Peter Wemm
7  * Copyright (c) 2008-2012 Jung-uk Kim <jkim@FreeBSD.org>
8  * All rights reserved.
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 AUTHOR AND CONTRIBUTORS ``AS IS'' AND
20  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
21  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
22  * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
23  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
24  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
25  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
26  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
27  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
28  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
29  * SUCH DAMAGE.
30  */
31
32 #include <sys/cdefs.h>
33 __FBSDID("$FreeBSD$");
34
35 #if defined(__amd64__)
36 #define DEV_APIC
37 #else
38 #include "opt_apic.h"
39 #endif
40
41 #include <sys/param.h>
42 #include <sys/bus.h>
43 #include <sys/eventhandler.h>
44 #include <sys/kernel.h>
45 #include <sys/malloc.h>
46 #include <sys/memrange.h>
47 #include <sys/smp.h>
48 #include <sys/systm.h>
49 #include <sys/cons.h>
50
51 #include <vm/vm.h>
52 #include <vm/pmap.h>
53
54 #include <machine/clock.h>
55 #include <machine/cpu.h>
56 #include <machine/intr_machdep.h>
57 #include <x86/mca.h>
58 #include <machine/pcb.h>
59 #include <machine/specialreg.h>
60 #include <machine/md_var.h>
61
62 #ifdef DEV_APIC
63 #include <x86/apicreg.h>
64 #include <x86/apicvar.h>
65 #endif
66 #ifdef SMP
67 #include <machine/smp.h>
68 #include <machine/vmparam.h>
69 #endif
70
71 #include <contrib/dev/acpica/include/acpi.h>
72
73 #include <dev/acpica/acpivar.h>
74
75 #include "acpi_wakecode.h"
76 #include "acpi_wakedata.h"
77
78 /* Make sure the code is less than a page and leave room for the stack. */
79 CTASSERT(sizeof(wakecode) < PAGE_SIZE - 1024);
80
81 extern int              acpi_resume_beep;
82 extern int              acpi_reset_video;
83 extern int              acpi_susp_bounce;
84
85 #ifdef SMP
86 extern struct susppcb   **susppcbs;
87 static cpuset_t         suspcpus;
88 #else
89 static struct susppcb   **susppcbs;
90 #endif
91
92 static void             *acpi_alloc_wakeup_handler(void **);
93 static void             acpi_stop_beep(void *);
94
95 #ifdef SMP
96 static int              acpi_wakeup_ap(struct acpi_softc *, int);
97 static void             acpi_wakeup_cpus(struct acpi_softc *);
98 #endif
99
100 #ifdef __amd64__
101 #define ACPI_WAKEPAGES  4
102 #else
103 #define ACPI_WAKEPAGES  1
104 #endif
105
106 #define WAKECODE_FIXUP(offset, type, val)       do {    \
107         type    *addr;                                  \
108         addr = (type *)(sc->acpi_wakeaddr + (offset));  \
109         *addr = val;                                    \
110 } while (0)
111
112 static void
113 acpi_stop_beep(void *arg)
114 {
115
116         if (acpi_resume_beep != 0)
117                 timer_spkr_release();
118 }
119
120 #ifdef SMP
121 static int
122 acpi_wakeup_ap(struct acpi_softc *sc, int cpu)
123 {
124         struct pcb *pcb;
125         int             vector = (sc->acpi_wakephys >> 12) & 0xff;
126         int             apic_id = cpu_apic_ids[cpu];
127         int             ms;
128
129         pcb = &susppcbs[cpu]->sp_pcb;
130         WAKECODE_FIXUP(wakeup_pcb, struct pcb *, pcb);
131         WAKECODE_FIXUP(wakeup_gdt, uint16_t, pcb->pcb_gdt.rd_limit);
132         WAKECODE_FIXUP(wakeup_gdt + 2, uint64_t, pcb->pcb_gdt.rd_base);
133
134         ipi_startup(apic_id, vector);
135
136         /* Wait up to 5 seconds for it to resume. */
137         for (ms = 0; ms < 5000; ms++) {
138                 if (!CPU_ISSET(cpu, &suspended_cpus))
139                         return (1);     /* return SUCCESS */
140                 DELAY(1000);
141         }
142         return (0);             /* return FAILURE */
143 }
144
145 #define WARMBOOT_TARGET         0
146 #ifdef __amd64__
147 #define WARMBOOT_OFF            (KERNBASE + 0x0467)
148 #define WARMBOOT_SEG            (KERNBASE + 0x0469)
149 #else /* __i386__ */
150 #define WARMBOOT_OFF            (PMAP_MAP_LOW + 0x0467)
151 #define WARMBOOT_SEG            (PMAP_MAP_LOW + 0x0469)
152 #endif
153
154 #define CMOS_REG                (0x70)
155 #define CMOS_DATA               (0x71)
156 #define BIOS_RESET              (0x0f)
157 #define BIOS_WARM               (0x0a)
158
159 static void
160 acpi_wakeup_cpus(struct acpi_softc *sc)
161 {
162         uint32_t        mpbioswarmvec;
163         int             cpu;
164         u_char          mpbiosreason;
165
166         /* save the current value of the warm-start vector */
167         mpbioswarmvec = *((uint32_t *)WARMBOOT_OFF);
168         outb(CMOS_REG, BIOS_RESET);
169         mpbiosreason = inb(CMOS_DATA);
170
171         /* setup a vector to our boot code */
172         *((volatile u_short *)WARMBOOT_OFF) = WARMBOOT_TARGET;
173         *((volatile u_short *)WARMBOOT_SEG) = sc->acpi_wakephys >> 4;
174         outb(CMOS_REG, BIOS_RESET);
175         outb(CMOS_DATA, BIOS_WARM);     /* 'warm-start' */
176
177         /* Wake up each AP. */
178         for (cpu = 1; cpu < mp_ncpus; cpu++) {
179                 if (!CPU_ISSET(cpu, &suspcpus))
180                         continue;
181                 if (acpi_wakeup_ap(sc, cpu) == 0) {
182                         /* restore the warmstart vector */
183                         *(uint32_t *)WARMBOOT_OFF = mpbioswarmvec;
184                         panic("acpi_wakeup: failed to resume AP #%d (PHY #%d)",
185                             cpu, cpu_apic_ids[cpu]);
186                 }
187         }
188
189 #ifdef __i386__
190         /*
191          * Remove the identity mapping of low memory for all CPUs and sync
192          * the TLB for the BSP.  The APs are now spinning in
193          * cpususpend_handler() and we will release them soon.  Then each
194          * will invalidate its TLB.
195          */
196         PTD[KPTDI] = 0;
197         invltlb_glob();
198 #endif
199
200         /* restore the warmstart vector */
201         *(uint32_t *)WARMBOOT_OFF = mpbioswarmvec;
202
203         outb(CMOS_REG, BIOS_RESET);
204         outb(CMOS_DATA, mpbiosreason);
205 }
206 #endif
207
208 int
209 acpi_sleep_machdep(struct acpi_softc *sc, int state)
210 {
211         ACPI_STATUS     status;
212         struct pcb      *pcb;
213 #ifdef __amd64__
214         struct pcpu *pc;
215         int i;
216 #endif
217
218         if (sc->acpi_wakeaddr == 0ul)
219                 return (-1);    /* couldn't alloc wake memory */
220
221 #ifdef SMP
222         suspcpus = all_cpus;
223         CPU_CLR(PCPU_GET(cpuid), &suspcpus);
224 #endif
225
226         if (acpi_resume_beep != 0)
227                 timer_spkr_acquire();
228
229         AcpiSetFirmwareWakingVector(sc->acpi_wakephys, 0);
230
231         intr_suspend();
232
233         pcb = &susppcbs[0]->sp_pcb;
234         if (savectx(pcb)) {
235 #ifdef __amd64__
236                 fpususpend(susppcbs[0]->sp_fpususpend);
237 #else
238                 npxsuspend(susppcbs[0]->sp_fpususpend);
239 #endif
240 #ifdef SMP
241                 if (!CPU_EMPTY(&suspcpus) && suspend_cpus(suspcpus) == 0) {
242                         device_printf(sc->acpi_dev, "Failed to suspend APs\n");
243                         return (0);     /* couldn't sleep */
244                 }
245 #endif
246 #ifdef __amd64__
247                 hw_ibrs_active = 0;
248                 hw_ssb_active = 0;
249                 cpu_stdext_feature3 = 0;
250                 CPU_FOREACH(i) {
251                         pc = pcpu_find(i);
252                         pc->pc_ibpb_set = 0;
253                 }
254 #endif
255
256                 WAKECODE_FIXUP(resume_beep, uint8_t, (acpi_resume_beep != 0));
257                 WAKECODE_FIXUP(reset_video, uint8_t, (acpi_reset_video != 0));
258
259 #ifdef __amd64__
260                 WAKECODE_FIXUP(wakeup_efer, uint64_t, rdmsr(MSR_EFER) &
261                     ~(EFER_LMA));
262 #else
263                 WAKECODE_FIXUP(wakeup_cr4, register_t, pcb->pcb_cr4);
264 #endif
265                 WAKECODE_FIXUP(wakeup_pcb, struct pcb *, pcb);
266                 WAKECODE_FIXUP(wakeup_gdt, uint16_t, pcb->pcb_gdt.rd_limit);
267                 WAKECODE_FIXUP(wakeup_gdt + 2, uint64_t, pcb->pcb_gdt.rd_base);
268
269 #ifdef __i386__
270                 /*
271                  * Map some low memory with virt == phys for ACPI wakecode
272                  * to use to jump to high memory after enabling paging. This
273                  * is the same as for similar jump in locore, except the
274                  * jump is a single instruction, and we know its address
275                  * more precisely so only need a single PTD, and we have to
276                  * be careful to use the kernel map (PTD[0] is for curthread
277                  * which may be a user thread in deprecated APIs).
278                  */
279                 PTD[KPTDI] = PTD[LOWPTDI];
280 #endif
281
282                 /* Call ACPICA to enter the desired sleep state */
283                 if (state == ACPI_STATE_S4 && sc->acpi_s4bios)
284                         status = AcpiEnterSleepStateS4bios();
285                 else
286                         status = AcpiEnterSleepState(state);
287                 if (ACPI_FAILURE(status)) {
288                         device_printf(sc->acpi_dev,
289                             "AcpiEnterSleepState failed - %s\n",
290                             AcpiFormatException(status));
291                         return (0);     /* couldn't sleep */
292                 }
293
294                 if (acpi_susp_bounce)
295                         resumectx(pcb);
296
297                 for (;;)
298                         ia32_pause();
299         } else {
300                 /*
301                  * Re-initialize console hardware as soon as possibe.
302                  * No console output (e.g. printf) is allowed before
303                  * this point.
304                  */
305                 cnresume();
306 #ifdef __amd64__
307                 fpuresume(susppcbs[0]->sp_fpususpend);
308 #else
309                 npxresume(susppcbs[0]->sp_fpususpend);
310 #endif
311         }
312
313         return (1);     /* wakeup successfully */
314 }
315
316 int
317 acpi_wakeup_machdep(struct acpi_softc *sc, int state, int sleep_result,
318     int intr_enabled)
319 {
320
321         if (sleep_result == -1)
322                 return (sleep_result);
323
324         if (!intr_enabled) {
325                 /* Wakeup MD procedures in interrupt disabled context */
326                 if (sleep_result == 1) {
327                         pmap_init_pat();
328                         initializecpu();
329                         PCPU_SET(switchtime, 0);
330                         PCPU_SET(switchticks, ticks);
331 #ifdef DEV_APIC
332                         lapic_xapic_mode();
333 #endif
334 #ifdef SMP
335                         if (!CPU_EMPTY(&suspcpus))
336                                 acpi_wakeup_cpus(sc);
337 #endif
338                 }
339
340 #ifdef SMP
341                 if (!CPU_EMPTY(&suspcpus))
342                         resume_cpus(suspcpus);
343 #endif
344                 mca_resume();
345 #ifdef __amd64__
346                 if (vmm_resume_p != NULL)
347                         vmm_resume_p();
348 #endif
349                 intr_resume(/*suspend_cancelled*/false);
350
351                 AcpiSetFirmwareWakingVector(0, 0);
352         } else {
353                 /* Wakeup MD procedures in interrupt enabled context */
354                 if (sleep_result == 1 && mem_range_softc.mr_op != NULL &&
355                     mem_range_softc.mr_op->reinit != NULL)
356                         mem_range_softc.mr_op->reinit(&mem_range_softc);
357         }
358
359         return (sleep_result);
360 }
361
362 static void *
363 acpi_alloc_wakeup_handler(void *wakepages[ACPI_WAKEPAGES])
364 {
365         int             i;
366
367         memset(wakepages, 0, ACPI_WAKEPAGES * sizeof(*wakepages));
368
369         /*
370          * Specify the region for our wakeup code.  We want it in the low 1 MB
371          * region, excluding real mode IVT (0-0x3ff), BDA (0x400-0x4ff), EBDA
372          * (less than 128KB, below 0xa0000, must be excluded by SMAP and DSDT),
373          * and ROM area (0xa0000 and above).  The temporary page tables must be
374          * page-aligned.
375          */
376         for (i = 0; i < ACPI_WAKEPAGES; i++) {
377                 wakepages[i] = contigmalloc(PAGE_SIZE, M_DEVBUF, M_NOWAIT,
378                     0x500, 0xa0000, PAGE_SIZE, 0ul);
379                 if (wakepages[i] == NULL) {
380                         printf("%s: can't alloc wake memory\n", __func__);
381                         goto freepages;
382                 }
383         }
384         if (EVENTHANDLER_REGISTER(power_resume, acpi_stop_beep, NULL,
385             EVENTHANDLER_PRI_LAST) == NULL) {
386                 printf("%s: can't register event handler\n", __func__);
387                 goto freepages;
388         }
389         susppcbs = malloc(mp_ncpus * sizeof(*susppcbs), M_DEVBUF, M_WAITOK);
390         for (i = 0; i < mp_ncpus; i++) {
391                 susppcbs[i] = malloc(sizeof(**susppcbs), M_DEVBUF, M_WAITOK);
392                 susppcbs[i]->sp_fpususpend = alloc_fpusave(M_WAITOK);
393         }
394
395         return (wakepages);
396
397 freepages:
398         for (i = 0; i < ACPI_WAKEPAGES; i++)
399                 if (wakepages[i] != NULL)
400                         contigfree(wakepages[i], PAGE_SIZE, M_DEVBUF);
401         return (NULL);
402 }
403
404 void
405 acpi_install_wakeup_handler(struct acpi_softc *sc)
406 {
407         static void     *wakeaddr;
408         void            *wakepages[ACPI_WAKEPAGES];
409 #ifdef __amd64__
410         uint64_t        *pt4, *pt3, *pt2;
411         vm_paddr_t      pt4pa, pt3pa, pt2pa;
412         int             i;
413 #endif
414
415         if (wakeaddr != NULL)
416                 return;
417
418         if (acpi_alloc_wakeup_handler(wakepages) == NULL)
419                 return;
420
421         wakeaddr = wakepages[0];
422         sc->acpi_wakeaddr = (vm_offset_t)wakeaddr;
423         sc->acpi_wakephys = vtophys(wakeaddr);
424
425 #ifdef __amd64__
426         pt4 = wakepages[1];
427         pt3 = wakepages[2];
428         pt2 = wakepages[3];
429         pt4pa = vtophys(pt4);
430         pt3pa = vtophys(pt3);
431         pt2pa = vtophys(pt2);
432 #endif
433
434         bcopy(wakecode, (void *)sc->acpi_wakeaddr, sizeof(wakecode));
435
436         /* Patch GDT base address, ljmp targets. */
437         WAKECODE_FIXUP((bootgdtdesc + 2), uint32_t,
438             sc->acpi_wakephys + bootgdt);
439         WAKECODE_FIXUP((wakeup_sw32 + 2), uint32_t,
440             sc->acpi_wakephys + wakeup_32);
441 #ifdef __amd64__
442         WAKECODE_FIXUP((wakeup_sw64 + 1), uint32_t,
443             sc->acpi_wakephys + wakeup_64);
444         WAKECODE_FIXUP(wakeup_pagetables, uint32_t, pt4pa);
445 #endif
446
447         /* Save pointers to some global data. */
448         WAKECODE_FIXUP(wakeup_ret, void *, resumectx);
449 #ifndef __amd64__
450 #if defined(PAE) || defined(PAE_TABLES)
451         WAKECODE_FIXUP(wakeup_cr3, register_t, vtophys(kernel_pmap->pm_pdpt));
452 #else
453         WAKECODE_FIXUP(wakeup_cr3, register_t, vtophys(kernel_pmap->pm_pdir));
454 #endif
455
456 #else /* __amd64__ */
457         /* Create the initial 1GB replicated page tables */
458         for (i = 0; i < 512; i++) {
459                 /*
460                  * Each slot of the level 4 pages points
461                  * to the same level 3 page
462                  */
463                 pt4[i] = (uint64_t)pt3pa;
464                 pt4[i] |= PG_V | PG_RW | PG_U;
465
466                 /*
467                  * Each slot of the level 3 pages points
468                  * to the same level 2 page
469                  */
470                 pt3[i] = (uint64_t)pt2pa;
471                 pt3[i] |= PG_V | PG_RW | PG_U;
472
473                 /* The level 2 page slots are mapped with 2MB pages for 1GB. */
474                 pt2[i] = i * (2 * 1024 * 1024);
475                 pt2[i] |= PG_V | PG_RW | PG_PS | PG_U;
476         }
477 #endif /* !__amd64__ */
478
479         if (bootverbose)
480                 device_printf(sc->acpi_dev, "wakeup code va %#jx pa %#jx\n",
481                     (uintmax_t)sc->acpi_wakeaddr, (uintmax_t)sc->acpi_wakephys);
482 }