xref: /freebsd/sys/dev/acpica/acpi_apei.c (revision 5ac01ce026aa871e24065f931b5b5c36024c96f9)
1 /*-
2  * SPDX-License-Identifier: BSD-2-Clause-FreeBSD
3  *
4  * Copyright (c) 2020 Alexander Motin <mav@FreeBSD.org>
5  *
6  * Redistribution and use in source and binary forms, with or without
7  * modification, are permitted provided that the following conditions
8  * are met:
9  * 1. Redistributions of source code must retain the above copyright
10  *    notice, this list of conditions and the following disclaimer.
11  * 2. Redistributions in binary form must reproduce the above copyright
12  *    notice, this list of conditions and the following disclaimer in the
13  *    documentation and/or other materials provided with the distribution.
14  *
15  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
16  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
17  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
18  * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
19  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
20  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
21  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
22  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
23  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
24  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
25  * SUCH DAMAGE.
26  */
27 
28 #include <sys/cdefs.h>
29 __FBSDID("$FreeBSD$");
30 
31 #include "opt_acpi.h"
32 
33 #include <sys/param.h>
34 #include <sys/systm.h>
35 #include <sys/bus.h>
36 #include <sys/callout.h>
37 #include <sys/interrupt.h>
38 #include <sys/kernel.h>
39 #include <sys/malloc.h>
40 #include <sys/module.h>
41 #include <sys/queue.h>
42 #include <sys/rman.h>
43 #include <vm/vm.h>
44 #include <vm/pmap.h>
45 
46 #include <contrib/dev/acpica/include/acpi.h>
47 #include <contrib/dev/acpica/include/accommon.h>
48 #include <contrib/dev/acpica/include/aclocal.h>
49 #include <contrib/dev/acpica/include/actables.h>
50 
51 #include <dev/acpica/acpivar.h>
52 #include <dev/pci/pcireg.h>
53 #include <dev/pci/pcivar.h>
54 
55 struct apei_ge {
56 	union {
57 		ACPI_HEST_GENERIC v1;
58 		ACPI_HEST_GENERIC_V2 v2;
59 	};
60 	int		 res_type;
61 	int		 res_rid;
62 	struct resource	*res;
63 	int		 res2_type;
64 	int		 res2_rid;
65 	struct resource	*res2;
66 	uint8_t		*buf, *copybuf;
67 	TAILQ_ENTRY(apei_ge) link;
68 	struct callout	 poll;
69 	void		*swi_ih;
70 } *apei_nmi_ge;
71 
72 struct apei_softc {
73 	ACPI_TABLE_HEST *hest;
74 	TAILQ_HEAD(, apei_ge) ges;
75 };
76 
77 struct apei_mem_error {
78 	uint64_t	ValidationBits;
79 	uint64_t	ErrorStatus;
80 	uint64_t	PhysicalAddress;
81 	uint64_t	PhysicalAddressMask;
82 	uint16_t	Node;
83 	uint16_t	Card;
84 	uint16_t	Module;
85 	uint16_t	Bank;
86 	uint16_t	Device;
87 	uint16_t	Row;
88 	uint16_t	Column;
89 	uint16_t	BitPosition;
90 	uint64_t	RequesterID;
91 	uint64_t	ResponderID;
92 	uint64_t	TargetID;
93 	uint8_t		MemoryErrorType;
94 	uint8_t		Extended;
95 	uint16_t	RankNumber;
96 	uint16_t	CardHandle;
97 	uint16_t	ModuleHandle;
98 };
99 
100 struct apei_pcie_error {
101 	uint64_t	ValidationBits;
102 	uint32_t	PortType;
103 	uint32_t	Version;
104 	uint32_t	CommandStatus;
105 	uint32_t	Reserved;
106 	uint8_t		DeviceID[16];
107 	uint8_t		DeviceSerialNumber[8];
108 	uint8_t		BridgeControlStatus[4];
109 	uint8_t		CapabilityStructure[60];
110 	uint8_t		AERInfo[96];
111 };
112 
113 #ifdef __i386__
114 static __inline uint64_t
115 apei_bus_read_8(struct resource *res, bus_size_t offset)
116 {
117 	return (bus_read_4(res, offset) |
118 	    ((uint64_t)bus_read_4(res, offset + 4)) << 32);
119 }
120 static __inline void
121 apei_bus_write_8(struct resource *res, bus_size_t offset, uint64_t val)
122 {
123 	bus_write_4(res, offset, val);
124 	bus_write_4(res, offset + 4, val >> 32);
125 }
126 #define	READ8(r, o)	apei_bus_read_8((r), (o))
127 #define	WRITE8(r, o, v)	apei_bus_write_8((r), (o), (v))
128 #else
129 #define	READ8(r, o)	bus_read_8((r), (o))
130 #define	WRITE8(r, o, v)	bus_write_8((r), (o), (v))
131 #endif
132 
133 int apei_nmi_handler(void);
134 
135 static const char *
136 apei_severity(uint32_t s)
137 {
138 	switch (s) {
139 	case ACPI_HEST_GEN_ERROR_RECOVERABLE:
140 	    return ("Recoverable");
141 	case ACPI_HEST_GEN_ERROR_FATAL:
142 	    return ("Fatal");
143 	case ACPI_HEST_GEN_ERROR_CORRECTED:
144 	    return ("Corrected");
145 	case ACPI_HEST_GEN_ERROR_NONE:
146 	    return ("Informational");
147 	}
148 	return ("???");
149 }
150 
151 static int
152 apei_mem_handler(ACPI_HEST_GENERIC_DATA *ged)
153 {
154 	struct apei_mem_error *p = (struct apei_mem_error *)(ged + 1);
155 
156 	printf("APEI %s Memory Error:\n", apei_severity(ged->ErrorSeverity));
157 	if (p->ValidationBits & 0x01)
158 		printf(" Error Status: 0x%jx\n", p->ErrorStatus);
159 	if (p->ValidationBits & 0x02)
160 		printf(" Physical Address: 0x%jx\n", p->PhysicalAddress);
161 	if (p->ValidationBits & 0x04)
162 		printf(" Physical Address Mask: 0x%jx\n", p->PhysicalAddressMask);
163 	if (p->ValidationBits & 0x08)
164 		printf(" Node: %u\n", p->Node);
165 	if (p->ValidationBits & 0x10)
166 		printf(" Card: %u\n", p->Card);
167 	if (p->ValidationBits & 0x20)
168 		printf(" Module: %u\n", p->Module);
169 	if (p->ValidationBits & 0x40)
170 		printf(" Bank: %u\n", p->Bank);
171 	if (p->ValidationBits & 0x80)
172 		printf(" Device: %u\n", p->Device);
173 	if (p->ValidationBits & 0x100)
174 		printf(" Row: %u\n", p->Row);
175 	if (p->ValidationBits & 0x200)
176 		printf(" Column: %u\n", p->Column);
177 	if (p->ValidationBits & 0x400)
178 		printf(" Bit Position: %u\n", p->BitPosition);
179 	if (p->ValidationBits & 0x800)
180 		printf(" Requester ID: 0x%jx\n", p->RequesterID);
181 	if (p->ValidationBits & 0x1000)
182 		printf(" Responder ID: 0x%jx\n", p->ResponderID);
183 	if (p->ValidationBits & 0x2000)
184 		printf(" Target ID: 0x%jx\n", p->TargetID);
185 	if (p->ValidationBits & 0x4000)
186 		printf(" Memory Error Type: %u\n", p->MemoryErrorType);
187 	if (p->ValidationBits & 0x8000)
188 		printf(" Rank Number: %u\n", p->RankNumber);
189 	if (p->ValidationBits & 0x10000)
190 		printf(" Card Handle: 0x%x\n", p->CardHandle);
191 	if (p->ValidationBits & 0x20000)
192 		printf(" Module Handle: 0x%x\n", p->ModuleHandle);
193 	if (p->ValidationBits & 0x40000)
194 		printf(" Extended Row: %u\n",
195 		    (uint32_t)(p->Extended & 0x3) << 16 | p->Row);
196 	if (p->ValidationBits & 0x80000)
197 		printf(" Bank Group: %u\n", p->Bank >> 8);
198 	if (p->ValidationBits & 0x100000)
199 		printf(" Bank Address: %u\n", p->Bank & 0xff);
200 	if (p->ValidationBits & 0x200000)
201 		printf(" Chip Identification: %u\n", (p->Extended >> 5) & 0x7);
202 
203 	return (0);
204 }
205 
206 static int
207 apei_pcie_handler(ACPI_HEST_GENERIC_DATA *ged)
208 {
209 	struct apei_pcie_error *p = (struct apei_pcie_error *)(ged + 1);
210 	device_t dev;
211 	int h = 0, off, sev;
212 
213 	if ((p->ValidationBits & 0x8) == 0x8) {
214 		mtx_lock(&Giant);
215 		dev = pci_find_dbsf((uint32_t)p->DeviceID[10] << 8 |
216 		    p->DeviceID[9], p->DeviceID[11], p->DeviceID[8],
217 		    p->DeviceID[7]);
218 		if (dev != NULL) {
219 			switch (ged->ErrorSeverity) {
220 			case ACPI_HEST_GEN_ERROR_FATAL:
221 				sev = PCIEM_STA_FATAL_ERROR;
222 				break;
223 			case ACPI_HEST_GEN_ERROR_RECOVERABLE:
224 				sev = PCIEM_STA_NON_FATAL_ERROR;
225 				break;
226 			default:
227 				sev = PCIEM_STA_CORRECTABLE_ERROR;
228 				break;
229 			}
230 			pcie_apei_error(dev, sev,
231 			    (p->ValidationBits & 0x80) ? p->AERInfo : NULL);
232 			h = 1;
233 		}
234 		mtx_unlock(&Giant);
235 	}
236 	if (h)
237 		return (h);
238 
239 	printf("APEI %s PCIe Error:\n", apei_severity(ged->ErrorSeverity));
240 	if (p->ValidationBits & 0x01)
241 		printf(" Port Type: %u\n", p->PortType);
242 	if (p->ValidationBits & 0x02)
243 		printf(" Version: %x\n", p->Version);
244 	if (p->ValidationBits & 0x04)
245 		printf(" Command Status: 0x%08x\n", p->CommandStatus);
246 	if (p->ValidationBits & 0x08) {
247 		printf(" DeviceID:");
248 		for (off = 0; off < sizeof(p->DeviceID); off++)
249 			printf(" %02x", p->DeviceID[off]);
250 		printf("\n");
251 	}
252 	if (p->ValidationBits & 0x10) {
253 		printf(" Device Serial Number:");
254 		for (off = 0; off < sizeof(p->DeviceSerialNumber); off++)
255 			printf(" %02x", p->DeviceSerialNumber[off]);
256 		printf("\n");
257 	}
258 	if (p->ValidationBits & 0x20) {
259 		printf(" Bridge Control Status:");
260 		for (off = 0; off < sizeof(p->BridgeControlStatus); off++)
261 			printf(" %02x", p->BridgeControlStatus[off]);
262 		printf("\n");
263 	}
264 	if (p->ValidationBits & 0x40) {
265 		printf(" Capability Structure:\n");
266 		for (off = 0; off < sizeof(p->CapabilityStructure); off++) {
267 			printf(" %02x", p->CapabilityStructure[off]);
268 			if ((off % 16) == 15 ||
269 			    off + 1 == sizeof(p->CapabilityStructure))
270 				printf("\n");
271 		}
272 	}
273 	if (p->ValidationBits & 0x80) {
274 		printf(" AER Info:\n");
275 		for (off = 0; off < sizeof(p->AERInfo); off++) {
276 			printf(" %02x", p->AERInfo[off]);
277 			if ((off % 16) == 15 || off + 1 == sizeof(p->AERInfo))
278 				printf("\n");
279 		}
280 	}
281 	return (h);
282 }
283 
284 static void
285 apei_ged_handler(ACPI_HEST_GENERIC_DATA *ged)
286 {
287 	ACPI_HEST_GENERIC_DATA_V300 *ged3 = (ACPI_HEST_GENERIC_DATA_V300 *)ged;
288 	/* A5BC1114-6F64-4EDE-B863-3E83ED7C83B1 */
289 	static uint8_t mem_uuid[ACPI_UUID_LENGTH] = {
290 		0x14, 0x11, 0xBC, 0xA5, 0x64, 0x6F, 0xDE, 0x4E,
291 		0xB8, 0x63, 0x3E, 0x83, 0xED, 0x7C, 0x83, 0xB1
292 	};
293 	/* D995E954-BBC1-430F-AD91-B44DCB3C6F35 */
294 	static uint8_t pcie_uuid[ACPI_UUID_LENGTH] = {
295 		0x54, 0xE9, 0x95, 0xD9, 0xC1, 0xBB, 0x0F, 0x43,
296 		0xAD, 0x91, 0xB4, 0x4D, 0xCB, 0x3C, 0x6F, 0x35
297 	};
298 	uint8_t *t;
299 	int h = 0, off;
300 
301 	if (memcmp(mem_uuid, ged->SectionType, ACPI_UUID_LENGTH) == 0) {
302 		h = apei_mem_handler(ged);
303 	} else if (memcmp(pcie_uuid, ged->SectionType, ACPI_UUID_LENGTH) == 0) {
304 		h = apei_pcie_handler(ged);
305 	} else {
306 		t = ged->SectionType;
307 		printf("APEI %s Error %02x%02x%02x%02x-%02x%02x-"
308 		    "%02x%02x-%02x%02x-%02x%02x%02x%02x%02x%02x:\n",
309 		    apei_severity(ged->ErrorSeverity),
310 		    t[3], t[2], t[1], t[0], t[5], t[4], t[7], t[6],
311 		    t[8], t[9], t[10], t[11], t[12], t[13], t[14], t[15]);
312 		printf(" Error Data:\n");
313 		t = (uint8_t *)(ged + 1);
314 		for (off = 0; off < ged->ErrorDataLength; off++) {
315 			printf(" %02x", t[off]);
316 			if ((off % 16) == 15 || off + 1 == ged->ErrorDataLength)
317 				printf("\n");
318 		}
319 	}
320 	if (h)
321 		return;
322 
323 	printf(" Flags: 0x%x\n", ged->Flags);
324 	if (ged->ValidationBits & ACPI_HEST_GEN_VALID_FRU_ID) {
325 		t = ged->FruId;
326 		printf(" FRU Id: %02x%02x%02x%02x-%02x%02x-%02x%02x-"
327 		    "%02x%02x-%02x%02x%02x%02x%02x%02x\n",
328 		    t[3], t[2], t[1], t[0], t[5], t[4], t[7], t[6],
329 		    t[8], t[9], t[10], t[11], t[12], t[13], t[14], t[15]);
330 	}
331 	if (ged->ValidationBits & ACPI_HEST_GEN_VALID_FRU_STRING)
332 		printf(" FRU Text: %.20s", ged->FruText);
333 	if (ged->Revision == 0x300 &&
334 	    ged->ValidationBits & ACPI_HEST_GEN_VALID_TIMESTAMP)
335 		printf(" Timestamp: %016jx", ged3->TimeStamp);
336 }
337 
338 static int
339 apei_ge_handler(struct apei_ge *ge, bool copy)
340 {
341 	uint8_t *buf = copy ? ge->copybuf : ge->buf;
342 	ACPI_HEST_GENERIC_STATUS *ges = (ACPI_HEST_GENERIC_STATUS *)buf;
343 	ACPI_HEST_GENERIC_DATA *ged;
344 	uint32_t sev;
345 	int i, c, off;
346 
347 	if (ges->BlockStatus == 0)
348 		return (0);
349 
350 	c = (ges->BlockStatus >> 4) & 0x3ff;
351 	sev = ges->ErrorSeverity;
352 
353 	/* Process error entries. */
354 	for (off = i = 0; i < c && off + sizeof(*ged) <= ges->DataLength; i++) {
355 		ged = (ACPI_HEST_GENERIC_DATA *)&buf[sizeof(*ges) + off];
356 		apei_ged_handler(ged);
357 		off += sizeof(*ged) + ged->ErrorDataLength;
358 	}
359 
360 	/* Acknowledge the error has been processed. */
361 	ges->BlockStatus = 0;
362 	if (!copy && ge->v1.Header.Type == ACPI_HEST_TYPE_GENERIC_ERROR_V2) {
363 		uint64_t val = READ8(ge->res2, 0);
364 		val &= ge->v2.ReadAckPreserve;
365 		val |= ge->v2.ReadAckWrite;
366 		WRITE8(ge->res2, 0, val);
367 	}
368 
369 	/* If ACPI told the error is fatal -- make it so. */
370 	if (sev == ACPI_HEST_GEN_ERROR_FATAL)
371 		panic("APEI Fatal Hardware Error!");
372 
373 	return (1);
374 }
375 
376 static void
377 apei_nmi_swi(void *arg)
378 {
379 	struct apei_ge *ge = arg;
380 
381 	apei_ge_handler(ge, true);
382 }
383 
384 int
385 apei_nmi_handler(void)
386 {
387 	struct apei_ge *ge = apei_nmi_ge;
388 	ACPI_HEST_GENERIC_STATUS *ges, *gesc;
389 
390 	if (ge == NULL)
391 		return (0);
392 
393 	ges = (ACPI_HEST_GENERIC_STATUS *)ge->buf;
394 	if (ges->BlockStatus == 0)
395 		return (0);
396 
397 	/* If ACPI told the error is fatal -- make it so. */
398 	if (ges->ErrorSeverity == ACPI_HEST_GEN_ERROR_FATAL)
399 		panic("APEI Fatal Hardware Error!");
400 
401 	/* Copy the buffer for later processing. */
402 	gesc = (ACPI_HEST_GENERIC_STATUS *)ge->copybuf;
403 	if (gesc->BlockStatus == 0)
404 		memcpy(ge->copybuf, ge->buf, ge->v1.ErrorBlockLength);
405 
406 	/* Acknowledge the error has been processed. */
407 	ges->BlockStatus = 0;
408 	if (ge->v1.Header.Type == ACPI_HEST_TYPE_GENERIC_ERROR_V2) {
409 		uint64_t val = READ8(ge->res2, 0);
410 		val &= ge->v2.ReadAckPreserve;
411 		val |= ge->v2.ReadAckWrite;
412 		WRITE8(ge->res2, 0, val);
413 	}
414 
415 	/* Schedule SWI for real handling. */
416 	swi_sched(ge->swi_ih, SWI_FROMNMI);
417 
418 	return (1);
419 }
420 
421 static void
422 apei_callout_handler(void *context)
423 {
424 	struct apei_ge *ge = context;
425 
426 	apei_ge_handler(ge, false);
427 	callout_schedule(&ge->poll, ge->v1.Notify.PollInterval * hz / 1000);
428 }
429 
430 static void
431 apei_notify_handler(ACPI_HANDLE h, UINT32 notify, void *context)
432 {
433 	device_t dev = context;
434 	struct apei_softc *sc = device_get_softc(dev);
435 	struct apei_ge *ge;
436 
437 	TAILQ_FOREACH(ge, &sc->ges, link) {
438 		if (ge->v1.Notify.Type == ACPI_HEST_NOTIFY_SCI ||
439 		    ge->v1.Notify.Type == ACPI_HEST_NOTIFY_GPIO ||
440 		    ge->v1.Notify.Type == ACPI_HEST_NOTIFY_GSIV)
441 			apei_ge_handler(ge, false);
442 	}
443 }
444 
445 static int
446 hest_parse_structure(struct apei_softc *sc, void *addr, int remaining)
447 {
448 	ACPI_HEST_HEADER *hdr = addr;
449 	struct apei_ge *ge;
450 
451 	if (remaining < (int)sizeof(ACPI_HEST_HEADER))
452 		return (-1);
453 
454 	switch (hdr->Type) {
455 	case ACPI_HEST_TYPE_IA32_CHECK: {
456 		ACPI_HEST_IA_MACHINE_CHECK *s = addr;
457 		return (sizeof(*s) + s->NumHardwareBanks *
458 		    sizeof(ACPI_HEST_IA_ERROR_BANK));
459 	}
460 	case ACPI_HEST_TYPE_IA32_CORRECTED_CHECK: {
461 		ACPI_HEST_IA_CORRECTED *s = addr;
462 		return (sizeof(*s) + s->NumHardwareBanks *
463 		    sizeof(ACPI_HEST_IA_ERROR_BANK));
464 	}
465 	case ACPI_HEST_TYPE_IA32_NMI: {
466 		ACPI_HEST_IA_NMI *s = addr;
467 		return (sizeof(*s));
468 	}
469 	case ACPI_HEST_TYPE_AER_ROOT_PORT: {
470 		ACPI_HEST_AER_ROOT *s = addr;
471 		return (sizeof(*s));
472 	}
473 	case ACPI_HEST_TYPE_AER_ENDPOINT: {
474 		ACPI_HEST_AER *s = addr;
475 		return (sizeof(*s));
476 	}
477 	case ACPI_HEST_TYPE_AER_BRIDGE: {
478 		ACPI_HEST_AER_BRIDGE *s = addr;
479 		return (sizeof(*s));
480 	}
481 	case ACPI_HEST_TYPE_GENERIC_ERROR: {
482 		ACPI_HEST_GENERIC *s = addr;
483 		ge = malloc(sizeof(*ge), M_DEVBUF, M_WAITOK | M_ZERO);
484 		ge->v1 = *s;
485 		TAILQ_INSERT_TAIL(&sc->ges, ge, link);
486 		return (sizeof(*s));
487 	}
488 	case ACPI_HEST_TYPE_GENERIC_ERROR_V2: {
489 		ACPI_HEST_GENERIC_V2 *s = addr;
490 		ge = malloc(sizeof(*ge), M_DEVBUF, M_WAITOK | M_ZERO);
491 		ge->v2 = *s;
492 		TAILQ_INSERT_TAIL(&sc->ges, ge, link);
493 		return (sizeof(*s));
494 	}
495 	case ACPI_HEST_TYPE_IA32_DEFERRED_CHECK: {
496 		ACPI_HEST_IA_DEFERRED_CHECK *s = addr;
497 		return (sizeof(*s) + s->NumHardwareBanks *
498 		    sizeof(ACPI_HEST_IA_ERROR_BANK));
499 	}
500 	default:
501 		return (-1);
502 	}
503 }
504 
505 static void
506 hest_parse_table(struct apei_softc *sc)
507 {
508 	ACPI_TABLE_HEST *hest = sc->hest;
509 	char *cp;
510 	int remaining, consumed;
511 
512 	remaining = hest->Header.Length - sizeof(ACPI_TABLE_HEST);
513 	while (remaining > 0) {
514 		cp = (char *)hest + hest->Header.Length - remaining;
515 		consumed = hest_parse_structure(sc, cp, remaining);
516 		if (consumed <= 0)
517 			break;
518 		else
519 			remaining -= consumed;
520 	}
521 }
522 
523 static char *apei_ids[] = { "PNP0C33", NULL };
524 static devclass_t apei_devclass;
525 
526 static ACPI_STATUS
527 apei_find(ACPI_HANDLE handle, UINT32 level, void *context,
528     void **status)
529 {
530 	int *found = (int *)status;
531 	char **ids;
532 
533 	for (ids = apei_ids; *ids != NULL; ids++) {
534 		if (acpi_MatchHid(handle, *ids)) {
535 			*found = 1;
536 			break;
537 		}
538 	}
539 	return (AE_OK);
540 }
541 
542 static void
543 apei_identify(driver_t *driver, device_t parent)
544 {
545 	device_t	child;
546 	int		found;
547 
548 	if (acpi_disabled("apei"))
549 		return;
550 	if (acpi_find_table(ACPI_SIG_HEST) == 0)
551 		return;
552 	/* Only one APEI device can exist. */
553 	if (devclass_get_device(apei_devclass, 0))
554 		return;
555 	/* Search for ACPI error device to be used. */
556 	found = 0;
557 	AcpiWalkNamespace(ACPI_TYPE_DEVICE, ACPI_ROOT_OBJECT,
558 	    100, apei_find, NULL, NULL, (void *)&found);
559 	if (found)
560 		return;
561 	/* If not found - create a fake one. */
562 	child = BUS_ADD_CHILD(parent, 2, "apei", 0);
563 	if (child == NULL)
564 		printf("%s: can't add child\n", __func__);
565 }
566 
567 static int
568 apei_probe(device_t dev)
569 {
570 	int rv;
571 
572 	if (acpi_disabled("apei"))
573 		return (ENXIO);
574 	if (acpi_find_table(ACPI_SIG_HEST) == 0)
575 		return (ENXIO);
576 	if (acpi_get_handle(dev) != NULL)
577 		rv = ACPI_ID_PROBE(device_get_parent(dev), dev, apei_ids, NULL);
578 	else
579 		rv = 0;
580 	if (rv <= 0)
581 		device_set_desc(dev, "Platform Error Interface");
582 	return (rv);
583 }
584 
585 static int
586 apei_attach(device_t dev)
587 {
588 	struct apei_softc *sc = device_get_softc(dev);
589 	struct apei_ge *ge;
590 	ACPI_STATUS status;
591 	int rid;
592 
593 	TAILQ_INIT(&sc->ges);
594 
595 	/* Search and parse HEST table. */
596 	status = AcpiGetTable(ACPI_SIG_HEST, 0, (ACPI_TABLE_HEADER **)&sc->hest);
597 	if (ACPI_FAILURE(status))
598 		return (ENXIO);
599 	hest_parse_table(sc);
600 	AcpiPutTable((ACPI_TABLE_HEADER *)sc->hest);
601 
602 	rid = 0;
603 	TAILQ_FOREACH(ge, &sc->ges, link) {
604 		ge->res_rid = rid++;
605 		acpi_bus_alloc_gas(dev, &ge->res_type, &ge->res_rid,
606 		    &ge->v1.ErrorStatusAddress, &ge->res, 0);
607 		if (ge->v1.Header.Type == ACPI_HEST_TYPE_GENERIC_ERROR_V2) {
608 			ge->res2_rid = rid++;
609 			acpi_bus_alloc_gas(dev, &ge->res2_type, &ge->res2_rid,
610 			    &ge->v2.ReadAckRegister, &ge->res2, 0);
611 		}
612 		ge->buf = pmap_mapdev_attr(READ8(ge->res, 0),
613 		    ge->v1.ErrorBlockLength, VM_MEMATTR_WRITE_COMBINING);
614 		if (ge->v1.Notify.Type == ACPI_HEST_NOTIFY_POLLED) {
615 			callout_init(&ge->poll, 1);
616 			callout_reset(&ge->poll,
617 			    ge->v1.Notify.PollInterval * hz / 1000,
618 			    apei_callout_handler, ge);
619 		} else if (ge->v1.Notify.Type == ACPI_HEST_NOTIFY_NMI) {
620 			ge->copybuf = malloc(ge->v1.ErrorBlockLength,
621 			    M_DEVBUF, M_WAITOK | M_ZERO);
622 			swi_add(&clk_intr_event, "apei", apei_nmi_swi, ge,
623 			    SWI_CLOCK, INTR_MPSAFE, &ge->swi_ih);
624 			apei_nmi_ge = ge;
625 			apei_nmi = apei_nmi_handler;
626 		}
627 	}
628 
629 	if (acpi_get_handle(dev) != NULL) {
630 		AcpiInstallNotifyHandler(acpi_get_handle(dev),
631 		    ACPI_DEVICE_NOTIFY, apei_notify_handler, dev);
632 	}
633 	return (0);
634 }
635 
636 static int
637 apei_detach(device_t dev)
638 {
639 	struct apei_softc *sc = device_get_softc(dev);
640 	struct apei_ge *ge;
641 
642 	apei_nmi = NULL;
643 	apei_nmi_ge = NULL;
644 	if (acpi_get_handle(dev) != NULL) {
645 		AcpiRemoveNotifyHandler(acpi_get_handle(dev),
646 		    ACPI_DEVICE_NOTIFY, apei_notify_handler);
647 	}
648 
649 	while ((ge = TAILQ_FIRST(&sc->ges)) != NULL) {
650 		TAILQ_REMOVE(&sc->ges, ge, link);
651 		bus_release_resource(dev, ge->res_type, ge->res_rid, ge->res);
652 		if (ge->res2) {
653 			bus_release_resource(dev, ge->res2_type,
654 			    ge->res2_rid, ge->res2);
655 		}
656 		if (ge->v1.Notify.Type == ACPI_HEST_NOTIFY_POLLED) {
657 			callout_drain(&ge->poll);
658 		} else if (ge->v1.Notify.Type == ACPI_HEST_NOTIFY_NMI) {
659 			swi_remove(&ge->swi_ih);
660 			free(ge->copybuf, M_DEVBUF);
661 		}
662 		pmap_unmapdev((vm_offset_t)ge->buf, ge->v1.ErrorBlockLength);
663 		free(ge, M_DEVBUF);
664 	}
665 	return (0);
666 }
667 
668 static device_method_t apei_methods[] = {
669 	/* Device interface */
670 	DEVMETHOD(device_identify, apei_identify),
671 	DEVMETHOD(device_probe, apei_probe),
672 	DEVMETHOD(device_attach, apei_attach),
673 	DEVMETHOD(device_detach, apei_detach),
674 	DEVMETHOD_END
675 };
676 
677 static driver_t	apei_driver = {
678 	"apei",
679 	apei_methods,
680 	sizeof(struct apei_softc),
681 };
682 
683 DRIVER_MODULE(apei, acpi, apei_driver, apei_devclass, 0, 0);
684 MODULE_DEPEND(apei, acpi, 1, 1, 1);
685