xref: /freebsd/sys/i386/acpica/acpi_machdep.c (revision 06c3fb27)
1 /*-
2  * SPDX-License-Identifier: BSD-2-Clause
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/param.h>
30 #include <sys/bus.h>
31 #include <sys/kernel.h>
32 #include <sys/module.h>
33 #include <sys/sysctl.h>
34 
35 #include <vm/vm.h>
36 #include <vm/pmap.h>
37 
38 #include <contrib/dev/acpica/include/acpi.h>
39 #include <contrib/dev/acpica/include/accommon.h>
40 #include <contrib/dev/acpica/include/actables.h>
41 
42 #include <dev/acpica/acpivar.h>
43 
44 #include <machine/nexusvar.h>
45 
46 uint32_t acpi_resume_beep;
47 SYSCTL_UINT(_debug_acpi, OID_AUTO, resume_beep, CTLFLAG_RWTUN, &acpi_resume_beep,
48     0, "Beep the PC speaker when resuming");
49 
50 uint32_t acpi_reset_video;
51 TUNABLE_INT("hw.acpi.reset_video", &acpi_reset_video);
52 
53 static int intr_model = ACPI_INTR_PIC;
54 
55 int
56 acpi_machdep_init(device_t dev)
57 {
58 	struct acpi_softc *sc;
59 
60 	sc = device_get_softc(dev);
61 
62 	acpi_apm_init(sc);
63 	acpi_install_wakeup_handler(sc);
64 
65 	if (intr_model == ACPI_INTR_PIC)
66 		BUS_CONFIG_INTR(dev, AcpiGbl_FADT.SciInterrupt,
67 		    INTR_TRIGGER_LEVEL, INTR_POLARITY_LOW);
68 	else
69 		acpi_SetIntrModel(intr_model);
70 
71 	SYSCTL_ADD_UINT(&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 /* Check BIOS date.  If 1998 or older, disable ACPI. */
87 int
88 acpi_machdep_quirks(int *quirks)
89 {
90 	char *va;
91 	int year;
92 
93 	/* BIOS address 0xffff5 contains the date in the format mm/dd/yy. */
94 	va = pmap_mapbios(0xffff0, 16);
95 	sscanf(va + 11, "%2d", &year);
96 	pmap_unmapbios(va, 16);
97 
98 	/*
99 	 * Date must be >= 1/1/1999 or we don't trust ACPI.  Note that this
100 	 * check must be changed by my 114th birthday.
101 	 */
102 	if (year > 90 && year < 99)
103 		*quirks = ACPI_Q_BROKEN;
104 
105 	return (0);
106 }
107 
108 /*
109  * Map a table.  First map the header to determine the table length and then map
110  * the entire table.
111  */
112 static void *
113 map_table(vm_paddr_t pa, const char *sig)
114 {
115 	ACPI_TABLE_HEADER *header;
116 	vm_size_t length;
117 	void *table;
118 
119 	header = pmap_mapbios(pa, sizeof(ACPI_TABLE_HEADER));
120 	if (strncmp(header->Signature, sig, ACPI_NAMESEG_SIZE) != 0) {
121 		pmap_unmapbios(header, sizeof(ACPI_TABLE_HEADER));
122 		return (NULL);
123 	}
124 	length = header->Length;
125 	pmap_unmapbios(header, sizeof(ACPI_TABLE_HEADER));
126 	table = pmap_mapbios(pa, length);
127 	if (ACPI_FAILURE(AcpiUtChecksum(table, length))) {
128 		if (bootverbose)
129 			printf("ACPI: Failed checksum for table %s\n", sig);
130 #if (ACPI_CHECKSUM_ABORT)
131 		pmap_unmapbios(table, length);
132 		return (NULL);
133 #endif
134 	}
135 	return (table);
136 }
137 
138 /*
139  * See if a given ACPI table is the requested table.  Returns the
140  * length of the table if it matches or zero on failure.
141  */
142 static int
143 probe_table(vm_paddr_t address, const char *sig)
144 {
145 	ACPI_TABLE_HEADER *table;
146 	int ret;
147 
148 	table = pmap_mapbios(address, sizeof(ACPI_TABLE_HEADER));
149 	ret = strncmp(table->Signature, sig, ACPI_NAMESEG_SIZE) == 0;
150 	pmap_unmapbios(table, sizeof(ACPI_TABLE_HEADER));
151 	return (ret);
152 }
153 
154 /*
155  * Try to map a table at a given physical address previously returned
156  * by acpi_find_table().
157  */
158 void *
159 acpi_map_table(vm_paddr_t pa, const char *sig)
160 {
161 
162 	return (map_table(pa, sig));
163 }
164 
165 /* Unmap a table previously mapped via acpi_map_table(). */
166 void
167 acpi_unmap_table(void *table)
168 {
169 	ACPI_TABLE_HEADER *header;
170 
171 	header = (ACPI_TABLE_HEADER *)table;
172 	pmap_unmapbios(table, header->Length);
173 }
174 
175 /*
176  * Return the physical address of the requested table or zero if one
177  * is not found.
178  */
179 vm_paddr_t
180 acpi_find_table(const char *sig)
181 {
182 	ACPI_PHYSICAL_ADDRESS rsdp_ptr;
183 	ACPI_TABLE_RSDP *rsdp;
184 	ACPI_TABLE_RSDT *rsdt;
185 	ACPI_TABLE_XSDT *xsdt;
186 	ACPI_TABLE_HEADER *table;
187 	vm_paddr_t addr;
188 	int i, count;
189 
190 	if (resource_disabled("acpi", 0))
191 		return (0);
192 
193 	/*
194 	 * Map in the RSDP.  Since ACPI uses AcpiOsMapMemory() which in turn
195 	 * calls pmap_mapbios() to find the RSDP, we assume that we can use
196 	 * pmap_mapbios() to map the RSDP.
197 	 */
198 	if ((rsdp_ptr = AcpiOsGetRootPointer()) == 0)
199 		return (0);
200 	rsdp = pmap_mapbios(rsdp_ptr, sizeof(ACPI_TABLE_RSDP));
201 	if (rsdp == NULL) {
202 		if (bootverbose)
203 			printf("ACPI: Failed to map RSDP\n");
204 		return (0);
205 	}
206 
207 	/*
208 	 * For ACPI >= 2.0, use the XSDT if it is available.
209 	 * Otherwise, use the RSDT.
210 	 */
211 	addr = 0;
212 	if (rsdp->Revision >= 2 && rsdp->XsdtPhysicalAddress != 0) {
213 		/*
214 		 * AcpiOsGetRootPointer only verifies the checksum for
215 		 * the version 1.0 portion of the RSDP.  Version 2.0 has
216 		 * an additional checksum that we verify first.
217 		 */
218 		if (AcpiUtChecksum((UINT8 *)rsdp, ACPI_RSDP_XCHECKSUM_LENGTH)) {
219 			if (bootverbose)
220 				printf("ACPI: RSDP failed extended checksum\n");
221 			return (0);
222 		}
223 		xsdt = map_table(rsdp->XsdtPhysicalAddress, ACPI_SIG_XSDT);
224 		if (xsdt == NULL) {
225 			if (bootverbose)
226 				printf("ACPI: Failed to map XSDT\n");
227 			return (0);
228 		}
229 		count = (xsdt->Header.Length - sizeof(ACPI_TABLE_HEADER)) /
230 		    sizeof(UINT64);
231 		for (i = 0; i < count; i++)
232 			if (probe_table(xsdt->TableOffsetEntry[i], sig)) {
233 				addr = xsdt->TableOffsetEntry[i];
234 				break;
235 			}
236 		acpi_unmap_table(xsdt);
237 	} else {
238 		rsdt = map_table(rsdp->RsdtPhysicalAddress, ACPI_SIG_RSDT);
239 		if (rsdt == NULL) {
240 			if (bootverbose)
241 				printf("ACPI: Failed to map RSDT\n");
242 			return (0);
243 		}
244 		count = (rsdt->Header.Length - sizeof(ACPI_TABLE_HEADER)) /
245 		    sizeof(UINT32);
246 		for (i = 0; i < count; i++)
247 			if (probe_table(rsdt->TableOffsetEntry[i], sig)) {
248 				addr = rsdt->TableOffsetEntry[i];
249 				break;
250 			}
251 		acpi_unmap_table(rsdt);
252 	}
253 	pmap_unmapbios(rsdp, sizeof(ACPI_TABLE_RSDP));
254 	if (addr == 0)
255 		return (0);
256 
257 	/*
258 	 * Verify that we can map the full table and that its checksum is
259 	 * correct, etc.
260 	 */
261 	table = map_table(addr, sig);
262 	if (table == NULL)
263 		return (0);
264 	acpi_unmap_table(table);
265 
266 	return (addr);
267 }
268 
269 /*
270  * ACPI nexus(4) driver.
271  */
272 static int
273 nexus_acpi_probe(device_t dev)
274 {
275 	int error;
276 
277 	error = acpi_identify();
278 	if (error)
279 		return (error);
280 	device_quiet(dev);
281 	return (BUS_PROBE_DEFAULT);
282 }
283 
284 static int
285 nexus_acpi_attach(device_t dev)
286 {
287 
288 	nexus_init_resources();
289 	bus_generic_probe(dev);
290 	if (BUS_ADD_CHILD(dev, 10, "acpi", 0) == NULL)
291 		panic("failed to add acpi0 device");
292 
293 	return (bus_generic_attach(dev));
294 }
295 
296 static device_method_t nexus_acpi_methods[] = {
297 	/* Device interface */
298 	DEVMETHOD(device_probe,		nexus_acpi_probe),
299 	DEVMETHOD(device_attach,	nexus_acpi_attach),
300 	{ 0, 0 }
301 };
302 
303 DEFINE_CLASS_1(nexus, nexus_acpi_driver, nexus_acpi_methods, 1, nexus_driver);
304 
305 DRIVER_MODULE(nexus_acpi, root, nexus_acpi_driver, 0, 0);
306