xref: /freebsd/sys/amd64/acpica/acpi_machdep.c (revision 0957b409a90fd597c1e9124cbaf3edd2b488f4ac)
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);
374