]> CyberLeo.Net >> Repos - FreeBSD/FreeBSD.git/blob - sys/amd64/acpica/acpi_machdep.c
MFV r331708:
[FreeBSD/FreeBSD.git] / sys / amd64 / acpica / acpi_machdep.c
1 /*-
2  * SPDX-License-Identifier: BSD-2-Clause-FreeBSD
3  *
4  * Copyright (c) 2001 Mitsuru IWASAKI
5  * All rights reserved.
6  *
7  * Redistribution and use in source and binary forms, with or without
8  * modification, are permitted provided that the following conditions
9  * are met:
10  * 1. Redistributions of source code must retain the above copyright
11  *    notice, this list of conditions and the following disclaimer.
12  * 2. Redistributions in binary form must reproduce the above copyright
13  *    notice, this list of conditions and the following disclaimer in the
14  *    documentation and/or other materials provided with the distribution.
15  *
16  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
17  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
18  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
19  * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
20  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
21  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
22  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
23  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
24  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
25  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
26  * SUCH DAMAGE.
27  */
28
29 #include <sys/cdefs.h>
30 __FBSDID("$FreeBSD$");
31
32 #include <sys/param.h>
33 #include <sys/bus.h>
34 #include <sys/kernel.h>
35 #include <sys/module.h>
36 #include <sys/sysctl.h>
37
38 #include <vm/vm.h>
39 #include <vm/pmap.h>
40
41 #include <contrib/dev/acpica/include/acpi.h>
42 #include <contrib/dev/acpica/include/accommon.h>
43 #include <contrib/dev/acpica/include/actables.h>
44
45 #include <dev/acpica/acpivar.h>
46
47 #include <machine/nexusvar.h>
48
49 int acpi_resume_beep;
50 SYSCTL_INT(_debug_acpi, OID_AUTO, resume_beep, CTLFLAG_RWTUN,
51     &acpi_resume_beep, 0, "Beep the PC speaker when resuming");
52
53 int acpi_reset_video;
54 TUNABLE_INT("hw.acpi.reset_video", &acpi_reset_video);
55
56 static int intr_model = ACPI_INTR_PIC;
57
58 int
59 acpi_machdep_init(device_t dev)
60 {
61         struct acpi_softc *sc;
62
63         sc = device_get_softc(dev);
64
65         acpi_apm_init(sc);
66         acpi_install_wakeup_handler(sc);
67
68         if (intr_model != ACPI_INTR_PIC)
69                 acpi_SetIntrModel(intr_model);
70
71         SYSCTL_ADD_INT(&sc->acpi_sysctl_ctx,
72             SYSCTL_CHILDREN(sc->acpi_sysctl_tree), OID_AUTO,
73             "reset_video", CTLFLAG_RW, &acpi_reset_video, 0,
74             "Call the VESA reset BIOS vector on the resume path");
75
76         return (0);
77 }
78
79 void
80 acpi_SetDefaultIntrModel(int model)
81 {
82
83         intr_model = model;
84 }
85
86 int
87 acpi_machdep_quirks(int *quirks)
88 {
89
90         return (0);
91 }
92
93 /*
94  * Support for mapping ACPI tables during early boot.  Currently this
95  * uses the crashdump map to map each table.  However, the crashdump
96  * map is created in pmap_bootstrap() right after the direct map, so
97  * we should be able to just use pmap_mapbios() here instead.
98  *
99  * This makes the following assumptions about how we use this KVA:
100  * pages 0 and 1 are used to map in the header of each table found via
101  * the RSDT or XSDT and pages 2 to n are used to map in the RSDT or
102  * XSDT.  This has to use 2 pages for the table headers in case a
103  * header spans a page boundary.
104  *
105  * XXX: We don't ensure the table fits in the available address space
106  * in the crashdump map.
107  */
108
109 /*
110  * Map some memory using the crashdump map.  'offset' is an offset in
111  * pages into the crashdump map to use for the start of the mapping.
112  */
113 static void *
114 table_map(vm_paddr_t pa, int offset, vm_offset_t length)
115 {
116         vm_offset_t va, off;
117         void *data;
118
119         off = pa & PAGE_MASK;
120         length = round_page(length + off);
121         pa = pa & PG_FRAME;
122         va = (vm_offset_t)pmap_kenter_temporary(pa, offset) +
123             (offset * PAGE_SIZE);
124         data = (void *)(va + off);
125         length -= PAGE_SIZE;
126         while (length > 0) {
127                 va += PAGE_SIZE;
128                 pa += PAGE_SIZE;
129                 length -= PAGE_SIZE;
130                 pmap_kenter(va, pa);
131                 invlpg(va);
132         }
133         return (data);
134 }
135
136 /* Unmap memory previously mapped with table_map(). */
137 static void
138 table_unmap(void *data, vm_offset_t length)
139 {
140         vm_offset_t va, off;
141
142         va = (vm_offset_t)data;
143         off = va & PAGE_MASK;
144         length = round_page(length + off);
145         va &= ~PAGE_MASK;
146         while (length > 0) {
147                 pmap_kremove(va);
148                 invlpg(va);
149                 va += PAGE_SIZE;
150                 length -= PAGE_SIZE;
151         }
152 }
153
154 /*
155  * Map a table at a given offset into the crashdump map.  It first
156  * maps the header to determine the table length and then maps the
157  * entire table.
158  */
159 static void *
160 map_table(vm_paddr_t pa, int offset, const char *sig)
161 {
162         ACPI_TABLE_HEADER *header;
163         vm_offset_t length;
164         void *table;
165
166         header = table_map(pa, offset, sizeof(ACPI_TABLE_HEADER));
167         if (strncmp(header->Signature, sig, ACPI_NAME_SIZE) != 0) {
168                 table_unmap(header, sizeof(ACPI_TABLE_HEADER));
169                 return (NULL);
170         }
171         length = header->Length;
172         table_unmap(header, sizeof(ACPI_TABLE_HEADER));
173         table = table_map(pa, offset, length);
174         if (ACPI_FAILURE(AcpiTbChecksum(table, length))) {
175                 if (bootverbose)
176                         printf("ACPI: Failed checksum for table %s\n", sig);
177 #if (ACPI_CHECKSUM_ABORT)
178                 table_unmap(table, length);
179                 return (NULL);
180 #endif
181         }
182         return (table);
183 }
184
185 /*
186  * See if a given ACPI table is the requested table.  Returns the
187  * length of the able if it matches or zero on failure.
188  */
189 static int
190 probe_table(vm_paddr_t address, const char *sig)
191 {
192         ACPI_TABLE_HEADER *table;
193
194         table = table_map(address, 0, sizeof(ACPI_TABLE_HEADER));
195         if (table == NULL) {
196                 if (bootverbose)
197                         printf("ACPI: Failed to map table at 0x%jx\n",
198                             (uintmax_t)address);
199                 return (0);
200         }
201         if (bootverbose)
202                 printf("Table '%.4s' at 0x%jx\n", table->Signature,
203                     (uintmax_t)address);
204
205         if (strncmp(table->Signature, sig, ACPI_NAME_SIZE) != 0) {
206                 table_unmap(table, sizeof(ACPI_TABLE_HEADER));
207                 return (0);
208         }
209         table_unmap(table, sizeof(ACPI_TABLE_HEADER));
210         return (1);
211 }
212
213 /*
214  * Try to map a table at a given physical address previously returned
215  * by acpi_find_table().
216  */
217 void *
218 acpi_map_table(vm_paddr_t pa, const char *sig)
219 {
220
221         return (map_table(pa, 0, sig));
222 }
223
224 /* Unmap a table previously mapped via acpi_map_table(). */
225 void
226 acpi_unmap_table(void *table)
227 {
228         ACPI_TABLE_HEADER *header;
229
230         header = (ACPI_TABLE_HEADER *)table;
231         table_unmap(table, header->Length);
232 }
233
234 /*
235  * Return the physical address of the requested table or zero if one
236  * is not found.
237  */
238 vm_paddr_t
239 acpi_find_table(const char *sig)
240 {
241         ACPI_PHYSICAL_ADDRESS rsdp_ptr;
242         ACPI_TABLE_RSDP *rsdp;
243         ACPI_TABLE_RSDT *rsdt;
244         ACPI_TABLE_XSDT *xsdt;
245         ACPI_TABLE_HEADER *table;
246         vm_paddr_t addr;
247         int i, count;
248
249         if (resource_disabled("acpi", 0))
250                 return (0);
251
252         /*
253          * Map in the RSDP.  Since ACPI uses AcpiOsMapMemory() which in turn
254          * calls pmap_mapbios() to find the RSDP, we assume that we can use
255          * pmap_mapbios() to map the RSDP.
256          */
257         if ((rsdp_ptr = AcpiOsGetRootPointer()) == 0)
258                 return (0);
259         rsdp = pmap_mapbios(rsdp_ptr, sizeof(ACPI_TABLE_RSDP));
260         if (rsdp == NULL) {
261                 if (bootverbose)
262                         printf("ACPI: Failed to map RSDP\n");
263                 return (0);
264         }
265
266         /*
267          * For ACPI >= 2.0, use the XSDT if it is available.
268          * Otherwise, use the RSDT.  We map the XSDT or RSDT at page 2
269          * in the crashdump area.  Pages 0 and 1 are used to map in the
270          * headers of candidate ACPI tables.
271          */
272         addr = 0;
273         if (rsdp->Revision >= 2 && rsdp->XsdtPhysicalAddress != 0) {
274                 /*
275                  * AcpiOsGetRootPointer only verifies the checksum for
276                  * the version 1.0 portion of the RSDP.  Version 2.0 has
277                  * an additional checksum that we verify first.
278                  */
279                 if (AcpiTbChecksum((UINT8 *)rsdp, ACPI_RSDP_XCHECKSUM_LENGTH)) {
280                         if (bootverbose)
281                                 printf("ACPI: RSDP failed extended checksum\n");
282                         return (0);
283                 }
284                 xsdt = map_table(rsdp->XsdtPhysicalAddress, 2, ACPI_SIG_XSDT);
285                 if (xsdt == NULL) {
286                         if (bootverbose)
287                                 printf("ACPI: Failed to map XSDT\n");
288                         return (0);
289                 }
290                 count = (xsdt->Header.Length - sizeof(ACPI_TABLE_HEADER)) /
291                     sizeof(UINT64);
292                 for (i = 0; i < count; i++)
293                         if (probe_table(xsdt->TableOffsetEntry[i], sig)) {
294                                 addr = xsdt->TableOffsetEntry[i];
295                                 break;
296                         }
297                 acpi_unmap_table(xsdt);
298         } else {
299                 rsdt = map_table(rsdp->RsdtPhysicalAddress, 2, ACPI_SIG_RSDT);
300                 if (rsdt == NULL) {
301                         if (bootverbose)
302                                 printf("ACPI: Failed to map RSDT\n");
303                         return (0);
304                 }
305                 count = (rsdt->Header.Length - sizeof(ACPI_TABLE_HEADER)) /
306                     sizeof(UINT32);
307                 for (i = 0; i < count; i++)
308                         if (probe_table(rsdt->TableOffsetEntry[i], sig)) {
309                                 addr = rsdt->TableOffsetEntry[i];
310                                 break;
311                         }
312                 acpi_unmap_table(rsdt);
313         }
314         pmap_unmapbios((vm_offset_t)rsdp, sizeof(ACPI_TABLE_RSDP));
315         if (addr == 0) {
316                 if (bootverbose)
317                         printf("ACPI: No %s table found\n", sig);
318                 return (0);
319         }
320         if (bootverbose)
321                 printf("%s: Found table at 0x%jx\n", sig, (uintmax_t)addr);
322
323         /*
324          * Verify that we can map the full table and that its checksum is
325          * correct, etc.
326          */
327         table = map_table(addr, 0, sig);
328         if (table == NULL)
329                 return (0);
330         acpi_unmap_table(table);
331
332         return (addr);
333 }
334
335 /*
336  * ACPI nexus(4) driver.
337  */
338 static int
339 nexus_acpi_probe(device_t dev)
340 {
341         int error;
342
343         error = acpi_identify();
344         if (error)
345                 return (error);
346
347         return (BUS_PROBE_DEFAULT);
348 }
349
350 static int
351 nexus_acpi_attach(device_t dev)
352 {
353
354         nexus_init_resources();
355         bus_generic_probe(dev);
356         if (BUS_ADD_CHILD(dev, 10, "acpi", 0) == NULL)
357                 panic("failed to add acpi0 device");
358
359         return (bus_generic_attach(dev));
360 }
361
362 static device_method_t nexus_acpi_methods[] = {
363         /* Device interface */
364         DEVMETHOD(device_probe,         nexus_acpi_probe),
365         DEVMETHOD(device_attach,        nexus_acpi_attach),
366
367         { 0, 0 }
368 };
369
370 DEFINE_CLASS_1(nexus, nexus_acpi_driver, nexus_acpi_methods, 1, nexus_driver);
371 static devclass_t nexus_devclass;
372
373 DRIVER_MODULE(nexus_acpi, root, nexus_acpi_driver, nexus_devclass, 0, 0);