xref: /freebsd/sys/amd64/acpica/acpi_machdep.c (revision fdafd315)
1f86214b6SMitsuru IWASAKI /*-
24d846d26SWarner Losh  * SPDX-License-Identifier: BSD-2-Clause
3c49761ddSPedro F. Giffuni  *
4f86214b6SMitsuru IWASAKI  * Copyright (c) 2001 Mitsuru IWASAKI
5f86214b6SMitsuru IWASAKI  * All rights reserved.
6f86214b6SMitsuru IWASAKI  *
7f86214b6SMitsuru IWASAKI  * Redistribution and use in source and binary forms, with or without
8f86214b6SMitsuru IWASAKI  * modification, are permitted provided that the following conditions
9f86214b6SMitsuru IWASAKI  * are met:
10f86214b6SMitsuru IWASAKI  * 1. Redistributions of source code must retain the above copyright
11f86214b6SMitsuru IWASAKI  *    notice, this list of conditions and the following disclaimer.
12f86214b6SMitsuru IWASAKI  * 2. Redistributions in binary form must reproduce the above copyright
13f86214b6SMitsuru IWASAKI  *    notice, this list of conditions and the following disclaimer in the
14f86214b6SMitsuru IWASAKI  *    documentation and/or other materials provided with the distribution.
15f86214b6SMitsuru IWASAKI  *
16f86214b6SMitsuru IWASAKI  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
17f86214b6SMitsuru IWASAKI  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
18f86214b6SMitsuru IWASAKI  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
19f86214b6SMitsuru IWASAKI  * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
20f86214b6SMitsuru IWASAKI  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
21f86214b6SMitsuru IWASAKI  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
22f86214b6SMitsuru IWASAKI  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
23f86214b6SMitsuru IWASAKI  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
24f86214b6SMitsuru IWASAKI  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
25f86214b6SMitsuru IWASAKI  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
26f86214b6SMitsuru IWASAKI  * SUCH DAMAGE.
27f86214b6SMitsuru IWASAKI  */
28f86214b6SMitsuru IWASAKI 
29f86214b6SMitsuru IWASAKI #include <sys/param.h>
30f86214b6SMitsuru IWASAKI #include <sys/bus.h>
315217af30SJohn Baldwin #include <sys/kernel.h>
325217af30SJohn Baldwin #include <sys/module.h>
33c66d2b38SJung-uk Kim #include <sys/sysctl.h>
34a7e2341eSJung-uk Kim 
35d95e7f5aSJohn Baldwin #include <vm/vm.h>
36d95e7f5aSJohn Baldwin #include <vm/pmap.h>
37f86214b6SMitsuru IWASAKI 
38129d3046SJung-uk Kim #include <contrib/dev/acpica/include/acpi.h>
39d95e7f5aSJohn Baldwin #include <contrib/dev/acpica/include/accommon.h>
40d95e7f5aSJohn Baldwin #include <contrib/dev/acpica/include/actables.h>
41129d3046SJung-uk Kim 
42f86214b6SMitsuru IWASAKI #include <dev/acpica/acpivar.h>
43f86214b6SMitsuru IWASAKI 
445217af30SJohn Baldwin #include <machine/nexusvar.h>
455217af30SJohn Baldwin 
46d2b227cdSJung-uk Kim int acpi_resume_beep;
47af3b2549SHans Petter Selasky SYSCTL_INT(_debug_acpi, OID_AUTO, resume_beep, CTLFLAG_RWTUN,
48af3b2549SHans Petter Selasky     &acpi_resume_beep, 0, "Beep the PC speaker when resuming");
49d2b227cdSJung-uk Kim 
50d2b227cdSJung-uk Kim int acpi_reset_video;
51c66d2b38SJung-uk Kim TUNABLE_INT("hw.acpi.reset_video", &acpi_reset_video);
52c66d2b38SJung-uk Kim 
538848ad86SPeter Wemm static int intr_model = ACPI_INTR_PIC;
548848ad86SPeter Wemm 
55f86214b6SMitsuru IWASAKI int
acpi_machdep_init(device_t dev)56f86214b6SMitsuru IWASAKI acpi_machdep_init(device_t dev)
57f86214b6SMitsuru IWASAKI {
58f86214b6SMitsuru IWASAKI 	struct acpi_softc *sc;
59f86214b6SMitsuru IWASAKI 
6093a88474SJung-uk Kim 	sc = device_get_softc(dev);
61c66d2b38SJung-uk Kim 
6293a88474SJung-uk Kim 	acpi_apm_init(sc);
630ef8c0cbSJung-uk Kim 	acpi_install_wakeup_handler(sc);
64f86214b6SMitsuru IWASAKI 
658848ad86SPeter Wemm 	if (intr_model != ACPI_INTR_PIC)
668848ad86SPeter Wemm 		acpi_SetIntrModel(intr_model);
678848ad86SPeter Wemm 
68fbbb13f9SMatthew D Fleming 	SYSCTL_ADD_INT(&sc->acpi_sysctl_ctx,
69c66d2b38SJung-uk Kim 	    SYSCTL_CHILDREN(sc->acpi_sysctl_tree), OID_AUTO,
70c66d2b38SJung-uk Kim 	    "reset_video", CTLFLAG_RW, &acpi_reset_video, 0,
71c66d2b38SJung-uk Kim 	    "Call the VESA reset BIOS vector on the resume path");
72c66d2b38SJung-uk Kim 
73f86214b6SMitsuru IWASAKI 	return (0);
74f86214b6SMitsuru IWASAKI }
758848ad86SPeter Wemm 
768848ad86SPeter Wemm void
acpi_SetDefaultIntrModel(int model)778848ad86SPeter Wemm acpi_SetDefaultIntrModel(int model)
788848ad86SPeter Wemm {
798848ad86SPeter Wemm 
808848ad86SPeter Wemm 	intr_model = model;
818848ad86SPeter Wemm }
821a26ea7fSNate Lawson 
831a26ea7fSNate Lawson int
acpi_machdep_quirks(int * quirks)841a26ea7fSNate Lawson acpi_machdep_quirks(int *quirks)
851a26ea7fSNate Lawson {
867c2bf852SJung-uk Kim 
871a26ea7fSNate Lawson 	return (0);
881a26ea7fSNate Lawson }
8931ad3b88SNate Lawson 
905217af30SJohn Baldwin /*
9172c7f24cSMark Johnston  * Map a table.  First map the header to determine the table length and then map
9272c7f24cSMark Johnston  * the entire table.
93d95e7f5aSJohn Baldwin  */
94d95e7f5aSJohn Baldwin static void *
map_table(vm_paddr_t pa,const char * sig)9572c7f24cSMark Johnston map_table(vm_paddr_t pa, const char *sig)
96d95e7f5aSJohn Baldwin {
97d95e7f5aSJohn Baldwin 	ACPI_TABLE_HEADER *header;
9852fba9a9SJessica Clarke 	vm_size_t length;
99d95e7f5aSJohn Baldwin 	void *table;
100d95e7f5aSJohn Baldwin 
10172c7f24cSMark Johnston 	header = pmap_mapbios(pa, sizeof(ACPI_TABLE_HEADER));
102278f0de6SJung-uk Kim 	if (strncmp(header->Signature, sig, ACPI_NAMESEG_SIZE) != 0) {
1037ae99f80SJohn Baldwin 		pmap_unmapbios(header, sizeof(ACPI_TABLE_HEADER));
104d95e7f5aSJohn Baldwin 		return (NULL);
105d95e7f5aSJohn Baldwin 	}
106d95e7f5aSJohn Baldwin 	length = header->Length;
1077ae99f80SJohn Baldwin 	pmap_unmapbios(header, sizeof(ACPI_TABLE_HEADER));
10872c7f24cSMark Johnston 	table = pmap_mapbios(pa, length);
10919ee8335SJung-uk Kim 	if (ACPI_FAILURE(AcpiUtChecksum(table, length))) {
110d95e7f5aSJohn Baldwin 		if (bootverbose)
111d95e7f5aSJohn Baldwin 			printf("ACPI: Failed checksum for table %s\n", sig);
11242c93b8dSJohn Baldwin #if (ACPI_CHECKSUM_ABORT)
1137ae99f80SJohn Baldwin 		pmap_unmapbios(table, length);
114d95e7f5aSJohn Baldwin 		return (NULL);
11542c93b8dSJohn Baldwin #endif
116d95e7f5aSJohn Baldwin 	}
117d95e7f5aSJohn Baldwin 	return (table);
118d95e7f5aSJohn Baldwin }
119d95e7f5aSJohn Baldwin 
120d95e7f5aSJohn Baldwin /*
121d95e7f5aSJohn Baldwin  * See if a given ACPI table is the requested table.  Returns the
12243909748SJessica Clarke  * length of the table if it matches or zero on failure.
123d95e7f5aSJohn Baldwin  */
124d95e7f5aSJohn Baldwin static int
probe_table(vm_paddr_t address,const char * sig)125d95e7f5aSJohn Baldwin probe_table(vm_paddr_t address, const char *sig)
126d95e7f5aSJohn Baldwin {
127d95e7f5aSJohn Baldwin 	ACPI_TABLE_HEADER *table;
12872c7f24cSMark Johnston 	int ret;
129d95e7f5aSJohn Baldwin 
13072c7f24cSMark Johnston 	table = pmap_mapbios(address, sizeof(ACPI_TABLE_HEADER));
13172c7f24cSMark Johnston 	ret = strncmp(table->Signature, sig, ACPI_NAMESEG_SIZE) == 0;
1327ae99f80SJohn Baldwin 	pmap_unmapbios(table, sizeof(ACPI_TABLE_HEADER));
13372c7f24cSMark Johnston 	return (ret);
134d95e7f5aSJohn Baldwin }
135d95e7f5aSJohn Baldwin 
136d95e7f5aSJohn Baldwin /*
137d95e7f5aSJohn Baldwin  * Try to map a table at a given physical address previously returned
138d95e7f5aSJohn Baldwin  * by acpi_find_table().
139d95e7f5aSJohn Baldwin  */
140d95e7f5aSJohn Baldwin void *
acpi_map_table(vm_paddr_t pa,const char * sig)141d95e7f5aSJohn Baldwin acpi_map_table(vm_paddr_t pa, const char *sig)
142d95e7f5aSJohn Baldwin {
143d95e7f5aSJohn Baldwin 
14472c7f24cSMark Johnston 	return (map_table(pa, sig));
145d95e7f5aSJohn Baldwin }
146d95e7f5aSJohn Baldwin 
147d95e7f5aSJohn Baldwin /* Unmap a table previously mapped via acpi_map_table(). */
148d95e7f5aSJohn Baldwin void
acpi_unmap_table(void * table)149d95e7f5aSJohn Baldwin acpi_unmap_table(void *table)
150d95e7f5aSJohn Baldwin {
151d95e7f5aSJohn Baldwin 	ACPI_TABLE_HEADER *header;
152d95e7f5aSJohn Baldwin 
153d95e7f5aSJohn Baldwin 	header = (ACPI_TABLE_HEADER *)table;
1547ae99f80SJohn Baldwin 	pmap_unmapbios(table, header->Length);
155d95e7f5aSJohn Baldwin }
156d95e7f5aSJohn Baldwin 
157d95e7f5aSJohn Baldwin /*
158d95e7f5aSJohn Baldwin  * Return the physical address of the requested table or zero if one
159d95e7f5aSJohn Baldwin  * is not found.
160d95e7f5aSJohn Baldwin  */
161d95e7f5aSJohn Baldwin vm_paddr_t
acpi_find_table(const char * sig)162d95e7f5aSJohn Baldwin acpi_find_table(const char *sig)
163d95e7f5aSJohn Baldwin {
164d95e7f5aSJohn Baldwin 	ACPI_PHYSICAL_ADDRESS rsdp_ptr;
165d95e7f5aSJohn Baldwin 	ACPI_TABLE_RSDP *rsdp;
166d95e7f5aSJohn Baldwin 	ACPI_TABLE_RSDT *rsdt;
167d95e7f5aSJohn Baldwin 	ACPI_TABLE_XSDT *xsdt;
168d95e7f5aSJohn Baldwin 	ACPI_TABLE_HEADER *table;
169d95e7f5aSJohn Baldwin 	vm_paddr_t addr;
170d95e7f5aSJohn Baldwin 	int i, count;
171d95e7f5aSJohn Baldwin 
172d95e7f5aSJohn Baldwin 	if (resource_disabled("acpi", 0))
173d95e7f5aSJohn Baldwin 		return (0);
174d95e7f5aSJohn Baldwin 
175d95e7f5aSJohn Baldwin 	/*
176d95e7f5aSJohn Baldwin 	 * Map in the RSDP.  Since ACPI uses AcpiOsMapMemory() which in turn
177d95e7f5aSJohn Baldwin 	 * calls pmap_mapbios() to find the RSDP, we assume that we can use
178d95e7f5aSJohn Baldwin 	 * pmap_mapbios() to map the RSDP.
179d95e7f5aSJohn Baldwin 	 */
180d95e7f5aSJohn Baldwin 	if ((rsdp_ptr = AcpiOsGetRootPointer()) == 0)
181d95e7f5aSJohn Baldwin 		return (0);
182d95e7f5aSJohn Baldwin 	rsdp = pmap_mapbios(rsdp_ptr, sizeof(ACPI_TABLE_RSDP));
183d95e7f5aSJohn Baldwin 	if (rsdp == NULL) {
184d95e7f5aSJohn Baldwin 		printf("ACPI: Failed to map RSDP\n");
185d95e7f5aSJohn Baldwin 		return (0);
186d95e7f5aSJohn Baldwin 	}
187d95e7f5aSJohn Baldwin 
188d95e7f5aSJohn Baldwin 	/*
189d95e7f5aSJohn Baldwin 	 * For ACPI >= 2.0, use the XSDT if it is available.
19072c7f24cSMark Johnston 	 * Otherwise, use the RSDT.
191d95e7f5aSJohn Baldwin 	 */
192d95e7f5aSJohn Baldwin 	addr = 0;
193d95e7f5aSJohn Baldwin 	if (rsdp->Revision >= 2 && rsdp->XsdtPhysicalAddress != 0) {
194d95e7f5aSJohn Baldwin 		/*
195d95e7f5aSJohn Baldwin 		 * AcpiOsGetRootPointer only verifies the checksum for
196d95e7f5aSJohn Baldwin 		 * the version 1.0 portion of the RSDP.  Version 2.0 has
197d95e7f5aSJohn Baldwin 		 * an additional checksum that we verify first.
198d95e7f5aSJohn Baldwin 		 */
19919ee8335SJung-uk Kim 		if (AcpiUtChecksum((UINT8 *)rsdp, ACPI_RSDP_XCHECKSUM_LENGTH)) {
200d95e7f5aSJohn Baldwin 			printf("ACPI: RSDP failed extended checksum\n");
2017ae99f80SJohn Baldwin 			pmap_unmapbios(rsdp, sizeof(ACPI_TABLE_RSDP));
202d95e7f5aSJohn Baldwin 			return (0);
203d95e7f5aSJohn Baldwin 		}
20472c7f24cSMark Johnston 		xsdt = map_table(rsdp->XsdtPhysicalAddress, ACPI_SIG_XSDT);
205d95e7f5aSJohn Baldwin 		if (xsdt == NULL) {
206d95e7f5aSJohn Baldwin 			printf("ACPI: Failed to map XSDT\n");
2077ae99f80SJohn Baldwin 			pmap_unmapbios(rsdp, sizeof(ACPI_TABLE_RSDP));
208d95e7f5aSJohn Baldwin 			return (0);
209d95e7f5aSJohn Baldwin 		}
210d95e7f5aSJohn Baldwin 		count = (xsdt->Header.Length - sizeof(ACPI_TABLE_HEADER)) /
211d95e7f5aSJohn Baldwin 		    sizeof(UINT64);
212d95e7f5aSJohn Baldwin 		for (i = 0; i < count; i++)
213d95e7f5aSJohn Baldwin 			if (probe_table(xsdt->TableOffsetEntry[i], sig)) {
214d95e7f5aSJohn Baldwin 				addr = xsdt->TableOffsetEntry[i];
215d95e7f5aSJohn Baldwin 				break;
216d95e7f5aSJohn Baldwin 			}
217d95e7f5aSJohn Baldwin 		acpi_unmap_table(xsdt);
218d95e7f5aSJohn Baldwin 	} else {
21972c7f24cSMark Johnston 		rsdt = map_table(rsdp->RsdtPhysicalAddress, ACPI_SIG_RSDT);
220d95e7f5aSJohn Baldwin 		if (rsdt == NULL) {
221d95e7f5aSJohn Baldwin 			printf("ACPI: Failed to map RSDT\n");
2227ae99f80SJohn Baldwin 			pmap_unmapbios(rsdp, sizeof(ACPI_TABLE_RSDP));
223d95e7f5aSJohn Baldwin 			return (0);
224d95e7f5aSJohn Baldwin 		}
225d95e7f5aSJohn Baldwin 		count = (rsdt->Header.Length - sizeof(ACPI_TABLE_HEADER)) /
226d95e7f5aSJohn Baldwin 		    sizeof(UINT32);
227d95e7f5aSJohn Baldwin 		for (i = 0; i < count; i++)
228d95e7f5aSJohn Baldwin 			if (probe_table(rsdt->TableOffsetEntry[i], sig)) {
229d95e7f5aSJohn Baldwin 				addr = rsdt->TableOffsetEntry[i];
230d95e7f5aSJohn Baldwin 				break;
231d95e7f5aSJohn Baldwin 			}
232d95e7f5aSJohn Baldwin 		acpi_unmap_table(rsdt);
233d95e7f5aSJohn Baldwin 	}
2347ae99f80SJohn Baldwin 	pmap_unmapbios(rsdp, sizeof(ACPI_TABLE_RSDP));
2358f6355b5SAlexander Motin 	if (addr == 0)
236d95e7f5aSJohn Baldwin 		return (0);
237d95e7f5aSJohn Baldwin 
238d95e7f5aSJohn Baldwin 	/*
239d95e7f5aSJohn Baldwin 	 * Verify that we can map the full table and that its checksum is
240d95e7f5aSJohn Baldwin 	 * correct, etc.
241d95e7f5aSJohn Baldwin 	 */
24272c7f24cSMark Johnston 	table = map_table(addr, sig);
243d95e7f5aSJohn Baldwin 	if (table == NULL)
244d95e7f5aSJohn Baldwin 		return (0);
245d95e7f5aSJohn Baldwin 	acpi_unmap_table(table);
246d95e7f5aSJohn Baldwin 
247d95e7f5aSJohn Baldwin 	return (addr);
248d95e7f5aSJohn Baldwin }
249d95e7f5aSJohn Baldwin 
250d95e7f5aSJohn Baldwin /*
2515217af30SJohn Baldwin  * ACPI nexus(4) driver.
2525217af30SJohn Baldwin  */
2535217af30SJohn Baldwin static int
nexus_acpi_probe(device_t dev)2545217af30SJohn Baldwin nexus_acpi_probe(device_t dev)
2555217af30SJohn Baldwin {
2565217af30SJohn Baldwin 	int error;
2575217af30SJohn Baldwin 
2585217af30SJohn Baldwin 	error = acpi_identify();
2595217af30SJohn Baldwin 	if (error)
2605217af30SJohn Baldwin 		return (error);
261732b69c9SMark Johnston 	device_quiet(dev);
2625217af30SJohn Baldwin 	return (BUS_PROBE_DEFAULT);
2635217af30SJohn Baldwin }
2645217af30SJohn Baldwin 
2655217af30SJohn Baldwin static int
nexus_acpi_attach(device_t dev)2665217af30SJohn Baldwin nexus_acpi_attach(device_t dev)
2675217af30SJohn Baldwin {
2685217af30SJohn Baldwin 
2695217af30SJohn Baldwin 	nexus_init_resources();
2705217af30SJohn Baldwin 	bus_generic_probe(dev);
2710ef8c0cbSJung-uk Kim 	if (BUS_ADD_CHILD(dev, 10, "acpi", 0) == NULL)
2725217af30SJohn Baldwin 		panic("failed to add acpi0 device");
2735217af30SJohn Baldwin 
2740ef8c0cbSJung-uk Kim 	return (bus_generic_attach(dev));
2755217af30SJohn Baldwin }
2765217af30SJohn Baldwin 
2775217af30SJohn Baldwin static device_method_t nexus_acpi_methods[] = {
2785217af30SJohn Baldwin 	/* Device interface */
2795217af30SJohn Baldwin 	DEVMETHOD(device_probe,		nexus_acpi_probe),
2805217af30SJohn Baldwin 	DEVMETHOD(device_attach,	nexus_acpi_attach),
2815217af30SJohn Baldwin 	{ 0, 0 }
2825217af30SJohn Baldwin };
2835217af30SJohn Baldwin 
2845217af30SJohn Baldwin DEFINE_CLASS_1(nexus, nexus_acpi_driver, nexus_acpi_methods, 1, nexus_driver);
2855217af30SJohn Baldwin 
286badcc74fSJohn Baldwin DRIVER_MODULE(nexus_acpi, root, nexus_acpi_driver, 0, 0);
287