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