xref: /freebsd/sys/dev/acpica/acpi_apei.c (revision 5cd08d9ecf52d37229f4888e38631cb91ce97eb9)
1 /*-
2  * SPDX-License-Identifier: BSD-2-Clause
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 #include "opt_acpi.h"
30 #include "opt_pci.h"
31 
32 #include <sys/param.h>
33 #include <sys/systm.h>
34 #include <sys/bus.h>
35 #include <sys/callout.h>
36 #include <sys/interrupt.h>
37 #include <sys/kernel.h>
38 #include <sys/malloc.h>
39 #include <sys/module.h>
40 #include <sys/queue.h>
41 #include <sys/rman.h>
42 #include <vm/vm.h>
43 #include <vm/pmap.h>
44 
45 #include <contrib/dev/acpica/include/acpi.h>
46 #include <contrib/dev/acpica/include/accommon.h>
47 #include <contrib/dev/acpica/include/aclocal.h>
48 #include <contrib/dev/acpica/include/actables.h>
49 
50 #include <dev/acpica/acpivar.h>
51 #include <dev/pci/pcireg.h>
52 #include <dev/pci/pcivar.h>
53 
54 struct apei_ge {
55 	union {
56 		ACPI_HEST_GENERIC v1;
57 		ACPI_HEST_GENERIC_V2 v2;
58 	};
59 	int		 res_type;
60 	int		 res_rid;
61 	struct resource	*res;
62 	int		 res2_type;
63 	int		 res2_rid;
64 	struct resource	*res2;
65 	uint8_t		*buf, *copybuf;
66 	TAILQ_ENTRY(apei_ge) link;
67 	TAILQ_ENTRY(apei_ge) nlink;
68 };
69 
70 /* NMI */
71 struct apei_nges {
72 	void		*swi_ih;
73 	TAILQ_HEAD(, apei_ge) ges;
74 } *apei_nmi_nges;
75 
76 /* Interrupt */
77 struct apei_iges {
78 	TAILQ_HEAD(, apei_ge) ges;
79 };
80 
81 /* Polling */
82 struct apei_pges {
83 	sbintime_t	 interval;
84 	struct callout	 poll;
85 	TAILQ_HEAD(, apei_ge) ges;
86 };
87 
88 struct apei_softc {
89 	ACPI_TABLE_HEST *hest;
90 	TAILQ_HEAD(, apei_ge) ges;
91 	struct apei_nges nges;
92 	struct apei_iges iges;
93 	struct apei_pges pges[32];
94 };
95 
96 struct apei_mem_error {
97 	uint64_t	ValidationBits;
98 	uint64_t	ErrorStatus;
99 	uint64_t	PhysicalAddress;
100 	uint64_t	PhysicalAddressMask;
101 	uint16_t	Node;
102 	uint16_t	Card;
103 	uint16_t	Module;
104 	uint16_t	Bank;
105 	uint16_t	Device;
106 	uint16_t	Row;
107 	uint16_t	Column;
108 	uint16_t	BitPosition;
109 	uint64_t	RequesterID;
110 	uint64_t	ResponderID;
111 	uint64_t	TargetID;
112 	uint8_t		MemoryErrorType;
113 	uint8_t		Extended;
114 	uint16_t	RankNumber;
115 	uint16_t	CardHandle;
116 	uint16_t	ModuleHandle;
117 };
118 
119 struct apei_pcie_error {
120 	uint64_t	ValidationBits;
121 	uint32_t	PortType;
122 	uint32_t	Version;
123 	uint32_t	CommandStatus;
124 	uint32_t	Reserved;
125 	uint8_t		DeviceID[16];
126 	uint8_t		DeviceSerialNumber[8];
127 	uint8_t		BridgeControlStatus[4];
128 	uint8_t		CapabilityStructure[60];
129 	uint8_t		AERInfo[96];
130 };
131 
132 #ifdef __i386__
133 static __inline uint64_t
apei_bus_read_8(struct resource * res,bus_size_t offset)134 apei_bus_read_8(struct resource *res, bus_size_t offset)
135 {
136 	return (bus_read_4(res, offset) |
137 	    ((uint64_t)bus_read_4(res, offset + 4)) << 32);
138 }
139 static __inline void
apei_bus_write_8(struct resource * res,bus_size_t offset,uint64_t val)140 apei_bus_write_8(struct resource *res, bus_size_t offset, uint64_t val)
141 {
142 	bus_write_4(res, offset, val);
143 	bus_write_4(res, offset + 4, val >> 32);
144 }
145 #define	READ8(r, o)	apei_bus_read_8((r), (o))
146 #define	WRITE8(r, o, v)	apei_bus_write_8((r), (o), (v))
147 #else
148 #define	READ8(r, o)	bus_read_8((r), (o))
149 #define	WRITE8(r, o, v)	bus_write_8((r), (o), (v))
150 #endif
151 
152 #define GED_SIZE(ged)	((ged)->Revision >= 0x300 ? \
153     sizeof(ACPI_HEST_GENERIC_DATA_V300) : sizeof(ACPI_HEST_GENERIC_DATA))
154 #define GED_DATA(ged)	((uint8_t *)(ged) + GED_SIZE(ged))
155 
156 #define PGE_ID(ge)	(fls(MAX(1, (ge)->v1.Notify.PollInterval)) - 1)
157 
158 static struct sysctl_ctx_list apei_sysctl_ctx;
159 static struct sysctl_oid *apei_sysctl_tree;
160 static int log_corrected = 1;
161 
162 int apei_nmi_handler(void);
163 
164 static const char *
apei_severity(uint32_t s)165 apei_severity(uint32_t s)
166 {
167 	switch (s) {
168 	case ACPI_HEST_GEN_ERROR_RECOVERABLE:
169 	    return ("Recoverable");
170 	case ACPI_HEST_GEN_ERROR_FATAL:
171 	    return ("Fatal");
172 	case ACPI_HEST_GEN_ERROR_CORRECTED:
173 	    return ("Corrected");
174 	case ACPI_HEST_GEN_ERROR_NONE:
175 	    return ("Informational");
176 	}
177 	return ("???");
178 }
179 
180 static int
apei_mem_handler(ACPI_HEST_GENERIC_DATA * ged)181 apei_mem_handler(ACPI_HEST_GENERIC_DATA *ged)
182 {
183 	struct apei_mem_error *p = (struct apei_mem_error *)GED_DATA(ged);
184 
185 	if (!log_corrected &&
186 	    (ged->ErrorSeverity == ACPI_HEST_GEN_ERROR_CORRECTED ||
187 	    ged->ErrorSeverity == ACPI_HEST_GEN_ERROR_NONE))
188 		return (1);
189 
190 	printf("APEI %s Memory Error:\n", apei_severity(ged->ErrorSeverity));
191 	if (p->ValidationBits & 0x01)
192 		printf(" Error Status: 0x%jx\n", p->ErrorStatus);
193 	if (p->ValidationBits & 0x02)
194 		printf(" Physical Address: 0x%jx\n", p->PhysicalAddress);
195 	if (p->ValidationBits & 0x04)
196 		printf(" Physical Address Mask: 0x%jx\n", p->PhysicalAddressMask);
197 	if (p->ValidationBits & 0x08)
198 		printf(" Node: %u\n", p->Node);
199 	if (p->ValidationBits & 0x10)
200 		printf(" Card: %u\n", p->Card);
201 	if (p->ValidationBits & 0x20)
202 		printf(" Module: %u\n", p->Module);
203 	if (p->ValidationBits & 0x40)
204 		printf(" Bank: %u\n", p->Bank);
205 	if (p->ValidationBits & 0x80)
206 		printf(" Device: %u\n", p->Device);
207 	if (p->ValidationBits & 0x100)
208 		printf(" Row: %u\n", p->Row);
209 	if (p->ValidationBits & 0x200)
210 		printf(" Column: %u\n", p->Column);
211 	if (p->ValidationBits & 0x400)
212 		printf(" Bit Position: %u\n", p->BitPosition);
213 	if (p->ValidationBits & 0x800)
214 		printf(" Requester ID: 0x%jx\n", p->RequesterID);
215 	if (p->ValidationBits & 0x1000)
216 		printf(" Responder ID: 0x%jx\n", p->ResponderID);
217 	if (p->ValidationBits & 0x2000)
218 		printf(" Target ID: 0x%jx\n", p->TargetID);
219 	if (p->ValidationBits & 0x4000)
220 		printf(" Memory Error Type: %u\n", p->MemoryErrorType);
221 	if (p->ValidationBits & 0x8000)
222 		printf(" Rank Number: %u\n", p->RankNumber);
223 	if (p->ValidationBits & 0x10000)
224 		printf(" Card Handle: 0x%x\n", p->CardHandle);
225 	if (p->ValidationBits & 0x20000)
226 		printf(" Module Handle: 0x%x\n", p->ModuleHandle);
227 	if (p->ValidationBits & 0x40000)
228 		printf(" Extended Row: %u\n",
229 		    (uint32_t)(p->Extended & 0x3) << 16 | p->Row);
230 	if (p->ValidationBits & 0x80000)
231 		printf(" Bank Group: %u\n", p->Bank >> 8);
232 	if (p->ValidationBits & 0x100000)
233 		printf(" Bank Address: %u\n", p->Bank & 0xff);
234 	if (p->ValidationBits & 0x200000)
235 		printf(" Chip Identification: %u\n", (p->Extended >> 5) & 0x7);
236 
237 	return (0);
238 }
239 
240 static int
apei_pcie_handler(ACPI_HEST_GENERIC_DATA * ged)241 apei_pcie_handler(ACPI_HEST_GENERIC_DATA *ged)
242 {
243 	struct apei_pcie_error *p = (struct apei_pcie_error *)GED_DATA(ged);
244 	int off;
245 #ifdef DEV_PCI
246 	device_t dev;
247 	int h = 0, sev;
248 
249 	if ((p->ValidationBits & 0x8) == 0x8) {
250 		mtx_lock(&Giant);
251 		dev = pci_find_dbsf((uint32_t)p->DeviceID[10] << 8 |
252 		    p->DeviceID[9], p->DeviceID[11], p->DeviceID[8],
253 		    p->DeviceID[7]);
254 		if (dev != NULL) {
255 			switch (ged->ErrorSeverity) {
256 			case ACPI_HEST_GEN_ERROR_FATAL:
257 				sev = PCIEM_STA_FATAL_ERROR;
258 				break;
259 			case ACPI_HEST_GEN_ERROR_RECOVERABLE:
260 				sev = PCIEM_STA_NON_FATAL_ERROR;
261 				break;
262 			default:
263 				sev = PCIEM_STA_CORRECTABLE_ERROR;
264 				break;
265 			}
266 			pcie_apei_error(dev, sev,
267 			    (p->ValidationBits & 0x80) ? p->AERInfo : NULL);
268 			h = 1;
269 		}
270 		mtx_unlock(&Giant);
271 	}
272 	if (h)
273 		return (h);
274 #endif
275 
276 	if (!log_corrected &&
277 	    (ged->ErrorSeverity == ACPI_HEST_GEN_ERROR_CORRECTED ||
278 	    ged->ErrorSeverity == ACPI_HEST_GEN_ERROR_NONE))
279 		return (1);
280 
281 	printf("APEI %s PCIe Error:\n", apei_severity(ged->ErrorSeverity));
282 	if (p->ValidationBits & 0x01)
283 		printf(" Port Type: %u\n", p->PortType);
284 	if (p->ValidationBits & 0x02)
285 		printf(" Version: %x\n", p->Version);
286 	if (p->ValidationBits & 0x04)
287 		printf(" Command Status: 0x%08x\n", p->CommandStatus);
288 	if (p->ValidationBits & 0x08) {
289 		printf(" DeviceID:");
290 		for (off = 0; off < sizeof(p->DeviceID); off++)
291 			printf(" %02x", p->DeviceID[off]);
292 		printf("\n");
293 	}
294 	if (p->ValidationBits & 0x10) {
295 		printf(" Device Serial Number:");
296 		for (off = 0; off < sizeof(p->DeviceSerialNumber); off++)
297 			printf(" %02x", p->DeviceSerialNumber[off]);
298 		printf("\n");
299 	}
300 	if (p->ValidationBits & 0x20) {
301 		printf(" Bridge Control Status:");
302 		for (off = 0; off < sizeof(p->BridgeControlStatus); off++)
303 			printf(" %02x", p->BridgeControlStatus[off]);
304 		printf("\n");
305 	}
306 	if (p->ValidationBits & 0x40) {
307 		printf(" Capability Structure:\n");
308 		for (off = 0; off < sizeof(p->CapabilityStructure); off++) {
309 			printf(" %02x", p->CapabilityStructure[off]);
310 			if ((off % 16) == 15 ||
311 			    off + 1 == sizeof(p->CapabilityStructure))
312 				printf("\n");
313 		}
314 	}
315 	if (p->ValidationBits & 0x80) {
316 		printf(" AER Info:\n");
317 		for (off = 0; off < sizeof(p->AERInfo); off++) {
318 			printf(" %02x", p->AERInfo[off]);
319 			if ((off % 16) == 15 || off + 1 == sizeof(p->AERInfo))
320 				printf("\n");
321 		}
322 	}
323 	return (0);
324 }
325 
326 static void
apei_ged_handler(ACPI_HEST_GENERIC_DATA * ged)327 apei_ged_handler(ACPI_HEST_GENERIC_DATA *ged)
328 {
329 	ACPI_HEST_GENERIC_DATA_V300 *ged3 = (ACPI_HEST_GENERIC_DATA_V300 *)ged;
330 	/* A5BC1114-6F64-4EDE-B863-3E83ED7C83B1 */
331 	static uint8_t mem_uuid[ACPI_UUID_LENGTH] = {
332 		0x14, 0x11, 0xBC, 0xA5, 0x64, 0x6F, 0xDE, 0x4E,
333 		0xB8, 0x63, 0x3E, 0x83, 0xED, 0x7C, 0x83, 0xB1
334 	};
335 	/* D995E954-BBC1-430F-AD91-B44DCB3C6F35 */
336 	static uint8_t pcie_uuid[ACPI_UUID_LENGTH] = {
337 		0x54, 0xE9, 0x95, 0xD9, 0xC1, 0xBB, 0x0F, 0x43,
338 		0xAD, 0x91, 0xB4, 0x4D, 0xCB, 0x3C, 0x6F, 0x35
339 	};
340 	uint8_t *t;
341 	int h = 0, off;
342 
343 	if (memcmp(mem_uuid, ged->SectionType, ACPI_UUID_LENGTH) == 0) {
344 		h = apei_mem_handler(ged);
345 	} else if (memcmp(pcie_uuid, ged->SectionType, ACPI_UUID_LENGTH) == 0) {
346 		h = apei_pcie_handler(ged);
347 	} else {
348 		if (!log_corrected &&
349 		    (ged->ErrorSeverity == ACPI_HEST_GEN_ERROR_CORRECTED ||
350 		    ged->ErrorSeverity == ACPI_HEST_GEN_ERROR_NONE))
351 			return;
352 
353 		t = ged->SectionType;
354 		printf("APEI %s Error %02x%02x%02x%02x-%02x%02x-"
355 		    "%02x%02x-%02x%02x-%02x%02x%02x%02x%02x%02x:\n",
356 		    apei_severity(ged->ErrorSeverity),
357 		    t[3], t[2], t[1], t[0], t[5], t[4], t[7], t[6],
358 		    t[8], t[9], t[10], t[11], t[12], t[13], t[14], t[15]);
359 		printf(" Error Data:\n");
360 		t = (uint8_t *)GED_DATA(ged);
361 		for (off = 0; off < ged->ErrorDataLength; off++) {
362 			printf(" %02x", t[off]);
363 			if ((off % 16) == 15 || off + 1 == ged->ErrorDataLength)
364 				printf("\n");
365 		}
366 	}
367 	if (h)
368 		return;
369 
370 	printf(" Flags: 0x%x\n", ged->Flags);
371 	if (ged->ValidationBits & ACPI_HEST_GEN_VALID_FRU_ID) {
372 		t = ged->FruId;
373 		printf(" FRU Id: %02x%02x%02x%02x-%02x%02x-%02x%02x-"
374 		    "%02x%02x-%02x%02x%02x%02x%02x%02x\n",
375 		    t[3], t[2], t[1], t[0], t[5], t[4], t[7], t[6],
376 		    t[8], t[9], t[10], t[11], t[12], t[13], t[14], t[15]);
377 	}
378 	if (ged->ValidationBits & ACPI_HEST_GEN_VALID_FRU_STRING)
379 		printf(" FRU Text: %.20s\n", ged->FruText);
380 	if (ged->Revision >= 0x300 &&
381 	    ged->ValidationBits & ACPI_HEST_GEN_VALID_TIMESTAMP)
382 		printf(" Timestamp: %016jx\n", ged3->TimeStamp);
383 }
384 
385 static int
apei_ge_handler(struct apei_ge * ge,bool copy)386 apei_ge_handler(struct apei_ge *ge, bool copy)
387 {
388 	uint8_t *buf = copy ? ge->copybuf : ge->buf;
389 	ACPI_HEST_GENERIC_STATUS *ges = (ACPI_HEST_GENERIC_STATUS *)buf;
390 	ACPI_HEST_GENERIC_DATA *ged;
391 	size_t off, len;
392 	uint32_t sev;
393 	int i, c;
394 
395 	if (ges == NULL || ges->BlockStatus == 0)
396 		return (0);
397 
398 	c = (ges->BlockStatus >> 4) & 0x3ff;
399 	sev = ges->ErrorSeverity;
400 
401 	/* Process error entries. */
402 	len = MIN(ge->v1.ErrorBlockLength - sizeof(*ges), ges->DataLength);
403 	for (off = i = 0; i < c && off + sizeof(*ged) <= len; i++) {
404 		ged = (ACPI_HEST_GENERIC_DATA *)&buf[sizeof(*ges) + off];
405 		if ((uint64_t)GED_SIZE(ged) + ged->ErrorDataLength > len - off)
406 			break;
407 		apei_ged_handler(ged);
408 		off += GED_SIZE(ged) + ged->ErrorDataLength;
409 	}
410 
411 	/* Acknowledge the error has been processed. */
412 	ges->BlockStatus = 0;
413 	if (!copy && ge->v1.Header.Type == ACPI_HEST_TYPE_GENERIC_ERROR_V2 &&
414 	    ge->res2) {
415 		uint64_t val = READ8(ge->res2, 0);
416 		val &= ge->v2.ReadAckPreserve;
417 		val |= ge->v2.ReadAckWrite;
418 		WRITE8(ge->res2, 0, val);
419 	}
420 
421 	/* If ACPI told the error is fatal -- make it so. */
422 	if (sev == ACPI_HEST_GEN_ERROR_FATAL)
423 		panic("APEI Fatal Hardware Error!");
424 
425 	return (1);
426 }
427 
428 static void
apei_nmi_swi(void * arg)429 apei_nmi_swi(void *arg)
430 {
431 	struct apei_nges *nges = arg;
432 	struct apei_ge *ge;
433 
434 	TAILQ_FOREACH(ge, &nges->ges, nlink)
435 		apei_ge_handler(ge, true);
436 }
437 
438 int
apei_nmi_handler(void)439 apei_nmi_handler(void)
440 {
441 	struct apei_nges *nges = apei_nmi_nges;
442 	struct apei_ge *ge;
443 	ACPI_HEST_GENERIC_STATUS *ges, *gesc;
444 	int handled = 0;
445 
446 	if (nges == NULL)
447 		return (0);
448 
449 	TAILQ_FOREACH(ge, &nges->ges, nlink) {
450 		ges = (ACPI_HEST_GENERIC_STATUS *)ge->buf;
451 		if (ges == NULL || ges->BlockStatus == 0)
452 			continue;
453 
454 		/* If ACPI told the error is fatal -- make it so. */
455 		if (ges->ErrorSeverity == ACPI_HEST_GEN_ERROR_FATAL)
456 			panic("APEI Fatal Hardware Error!");
457 
458 		/* Copy the buffer for later processing. */
459 		gesc = (ACPI_HEST_GENERIC_STATUS *)ge->copybuf;
460 		if (gesc->BlockStatus == 0)
461 			memcpy(ge->copybuf, ge->buf, ge->v1.ErrorBlockLength);
462 
463 		/* Acknowledge the error has been processed. */
464 		ges->BlockStatus = 0;
465 		if (ge->v1.Header.Type == ACPI_HEST_TYPE_GENERIC_ERROR_V2 &&
466 		    ge->res2) {
467 			uint64_t val = READ8(ge->res2, 0);
468 			val &= ge->v2.ReadAckPreserve;
469 			val |= ge->v2.ReadAckWrite;
470 			WRITE8(ge->res2, 0, val);
471 		}
472 		handled = 1;
473 	}
474 
475 	/* Schedule SWI for real handling. */
476 	if (handled)
477 		swi_sched(nges->swi_ih, SWI_FROMNMI);
478 
479 	return (handled);
480 }
481 
482 static void
apei_callout_handler(void * context)483 apei_callout_handler(void *context)
484 {
485 	struct apei_pges *pges = context;
486 	struct apei_ge *ge;
487 
488 	TAILQ_FOREACH(ge, &pges->ges, nlink)
489 		apei_ge_handler(ge, false);
490 	callout_schedule_sbt(&pges->poll, pges->interval, pges->interval, 0);
491 }
492 
493 static void
apei_notify_handler(ACPI_HANDLE h,UINT32 notify,void * context)494 apei_notify_handler(ACPI_HANDLE h, UINT32 notify, void *context)
495 {
496 	device_t dev = context;
497 	struct apei_softc *sc = device_get_softc(dev);
498 	struct apei_ge *ge;
499 
500 	TAILQ_FOREACH(ge, &sc->iges.ges, nlink)
501 		apei_ge_handler(ge, false);
502 }
503 
504 static int
hest_parse_structure(struct apei_softc * sc,void * addr,int remaining)505 hest_parse_structure(struct apei_softc *sc, void *addr, int remaining)
506 {
507 	ACPI_HEST_HEADER *hdr = addr;
508 	struct apei_ge *ge;
509 
510 	if (remaining < (int)sizeof(ACPI_HEST_HEADER))
511 		return (-1);
512 
513 	switch (hdr->Type) {
514 	case ACPI_HEST_TYPE_IA32_CHECK: {
515 		ACPI_HEST_IA_MACHINE_CHECK *s = addr;
516 		return (sizeof(*s) + s->NumHardwareBanks *
517 		    sizeof(ACPI_HEST_IA_ERROR_BANK));
518 	}
519 	case ACPI_HEST_TYPE_IA32_CORRECTED_CHECK: {
520 		ACPI_HEST_IA_CORRECTED *s = addr;
521 		return (sizeof(*s) + s->NumHardwareBanks *
522 		    sizeof(ACPI_HEST_IA_ERROR_BANK));
523 	}
524 	case ACPI_HEST_TYPE_IA32_NMI: {
525 		ACPI_HEST_IA_NMI *s = addr;
526 		return (sizeof(*s));
527 	}
528 	case ACPI_HEST_TYPE_AER_ROOT_PORT: {
529 		ACPI_HEST_AER_ROOT *s = addr;
530 		return (sizeof(*s));
531 	}
532 	case ACPI_HEST_TYPE_AER_ENDPOINT: {
533 		ACPI_HEST_AER *s = addr;
534 		return (sizeof(*s));
535 	}
536 	case ACPI_HEST_TYPE_AER_BRIDGE: {
537 		ACPI_HEST_AER_BRIDGE *s = addr;
538 		return (sizeof(*s));
539 	}
540 	case ACPI_HEST_TYPE_GENERIC_ERROR: {
541 		ACPI_HEST_GENERIC *s = addr;
542 		ge = malloc(sizeof(*ge), M_DEVBUF, M_WAITOK | M_ZERO);
543 		ge->v1 = *s;
544 		TAILQ_INSERT_TAIL(&sc->ges, ge, link);
545 		return (sizeof(*s));
546 	}
547 	case ACPI_HEST_TYPE_GENERIC_ERROR_V2: {
548 		ACPI_HEST_GENERIC_V2 *s = addr;
549 		ge = malloc(sizeof(*ge), M_DEVBUF, M_WAITOK | M_ZERO);
550 		ge->v2 = *s;
551 		TAILQ_INSERT_TAIL(&sc->ges, ge, link);
552 		return (sizeof(*s));
553 	}
554 	case ACPI_HEST_TYPE_IA32_DEFERRED_CHECK: {
555 		ACPI_HEST_IA_DEFERRED_CHECK *s = addr;
556 		return (sizeof(*s) + s->NumHardwareBanks *
557 		    sizeof(ACPI_HEST_IA_ERROR_BANK));
558 	}
559 	default:
560 		return (-1);
561 	}
562 }
563 
564 static void
hest_parse_table(struct apei_softc * sc)565 hest_parse_table(struct apei_softc *sc)
566 {
567 	ACPI_TABLE_HEST *hest = sc->hest;
568 	char *cp;
569 	int remaining, consumed;
570 
571 	remaining = hest->Header.Length - sizeof(ACPI_TABLE_HEST);
572 	while (remaining > 0) {
573 		cp = (char *)hest + hest->Header.Length - remaining;
574 		consumed = hest_parse_structure(sc, cp, remaining);
575 		if (consumed <= 0)
576 			break;
577 		else
578 			remaining -= consumed;
579 	}
580 }
581 
582 static char *apei_ids[] = { "PNP0C33", NULL };
583 
584 static ACPI_STATUS
apei_find(ACPI_HANDLE handle,UINT32 level,void * context,void ** status)585 apei_find(ACPI_HANDLE handle, UINT32 level, void *context,
586     void **status)
587 {
588 	int *found = (int *)status;
589 	char **ids;
590 
591 	for (ids = apei_ids; *ids != NULL; ids++) {
592 		if (acpi_MatchHid(handle, *ids)) {
593 			*found = 1;
594 			break;
595 		}
596 	}
597 	return (AE_OK);
598 }
599 
600 static void
apei_identify(driver_t * driver,device_t parent)601 apei_identify(driver_t *driver, device_t parent)
602 {
603 	device_t	child;
604 	int		found;
605 	ACPI_TABLE_HEADER *hest;
606 	ACPI_STATUS	status;
607 
608 	if (acpi_disabled("apei"))
609 		return;
610 
611 	/* Without HEST table we have nothing to do. */
612 	status = AcpiGetTable(ACPI_SIG_HEST, 0, &hest);
613 	if (ACPI_FAILURE(status))
614 		return;
615 	AcpiPutTable(hest);
616 
617 	/* Only one APEI device can exist. */
618 	if (devclass_get_device(devclass_find("apei"), 0))
619 		return;
620 
621 	/* Search for ACPI error device to be used. */
622 	found = 0;
623 	AcpiWalkNamespace(ACPI_TYPE_DEVICE, ACPI_ROOT_OBJECT,
624 	    100, apei_find, NULL, NULL, (void *)&found);
625 	if (found)
626 		return;
627 
628 	/* If not found - create a fake one. */
629 	child = BUS_ADD_CHILD(parent, 2, "apei", 0);
630 	if (child == NULL)
631 		printf("%s: can't add child\n", __func__);
632 }
633 
634 static int
apei_probe(device_t dev)635 apei_probe(device_t dev)
636 {
637 	ACPI_TABLE_HEADER *hest;
638 	ACPI_STATUS	status;
639 	int rv;
640 
641 	if (acpi_disabled("apei"))
642 		return (ENXIO);
643 
644 	if (acpi_get_handle(dev) != NULL) {
645 		rv = ACPI_ID_PROBE(device_get_parent(dev), dev, apei_ids, NULL);
646 		if (rv > 0)
647 			return (rv);
648 	} else
649 		rv = 0;
650 
651 	/* Without HEST table we have nothing to do. */
652 	status = AcpiGetTable(ACPI_SIG_HEST, 0, &hest);
653 	if (ACPI_FAILURE(status))
654 		return (ENXIO);
655 	AcpiPutTable(hest);
656 
657 	device_set_desc(dev, "ACPI Platform Error Interface");
658 	return (rv);
659 }
660 
661 static int
apei_attach(device_t dev)662 apei_attach(device_t dev)
663 {
664 	struct apei_softc *sc = device_get_softc(dev);
665 	struct acpi_softc *acpi_sc;
666 	struct apei_pges *pges;
667 	struct apei_ge *ge;
668 	ACPI_STATUS status;
669 	int rid;
670 
671 	if (!apei_sysctl_tree) {
672 		/* Install hw.acpi.apei sysctl tree */
673 		acpi_sc = acpi_device_get_parent_softc(dev);
674 		apei_sysctl_tree = SYSCTL_ADD_NODE(&apei_sysctl_ctx,
675 		    SYSCTL_CHILDREN(acpi_sc->acpi_sysctl_tree), OID_AUTO,
676 		    "apei", CTLFLAG_RD | CTLFLAG_MPSAFE, 0,
677 		    "ACPI Platform Error Interface");
678 		SYSCTL_ADD_INT(&apei_sysctl_ctx, SYSCTL_CHILDREN(apei_sysctl_tree),
679 		    OID_AUTO, "log_corrected", CTLFLAG_RWTUN, &log_corrected, 0,
680 		    "Log corrected errors to the console");
681 	}
682 
683 	TAILQ_INIT(&sc->ges);
684 	TAILQ_INIT(&sc->nges.ges);
685 	TAILQ_INIT(&sc->iges.ges);
686 	for (int i = 0; i < nitems(sc->pges); i++) {
687 		pges = &sc->pges[i];
688 		pges->interval = SBT_1MS << i;
689 		callout_init(&pges->poll, 1);
690 		TAILQ_INIT(&pges->ges);
691 	}
692 
693 	/* Search and parse HEST table. */
694 	status = AcpiGetTable(ACPI_SIG_HEST, 0, (ACPI_TABLE_HEADER **)&sc->hest);
695 	if (ACPI_FAILURE(status))
696 		return (ENXIO);
697 	hest_parse_table(sc);
698 	AcpiPutTable((ACPI_TABLE_HEADER *)sc->hest);
699 
700 	rid = 0;
701 	TAILQ_FOREACH(ge, &sc->ges, link) {
702 		ge->res_rid = rid++;
703 		acpi_bus_alloc_gas(dev, &ge->res_type, &ge->res_rid,
704 		    &ge->v1.ErrorStatusAddress, &ge->res, 0);
705 		if (ge->res) {
706 			ge->buf = pmap_mapdev_attr(READ8(ge->res, 0),
707 			    ge->v1.ErrorBlockLength, VM_MEMATTR_WRITE_COMBINING);
708 		} else {
709 			device_printf(dev, "Can't allocate status resource.\n");
710 		}
711 		if (ge->v1.Header.Type == ACPI_HEST_TYPE_GENERIC_ERROR_V2) {
712 			ge->res2_rid = rid++;
713 			acpi_bus_alloc_gas(dev, &ge->res2_type, &ge->res2_rid,
714 			    &ge->v2.ReadAckRegister, &ge->res2, RF_SHAREABLE);
715 			if (ge->res2 == NULL)
716 				device_printf(dev, "Can't allocate ack resource.\n");
717 		}
718 		if (ge->v1.Notify.Type == ACPI_HEST_NOTIFY_POLLED) {
719 			pges = &sc->pges[PGE_ID(ge)];
720 			TAILQ_INSERT_TAIL(&sc->pges[PGE_ID(ge)].ges, ge, nlink);
721 			callout_reset_sbt(&pges->poll, pges->interval, pges->interval,
722 			    apei_callout_handler, pges, 0);
723 		} else if (ge->v1.Notify.Type == ACPI_HEST_NOTIFY_SCI ||
724 		    ge->v1.Notify.Type == ACPI_HEST_NOTIFY_GPIO ||
725 		    ge->v1.Notify.Type == ACPI_HEST_NOTIFY_GSIV) {
726 			TAILQ_INSERT_TAIL(&sc->iges.ges, ge, nlink);
727 		} else if (ge->v1.Notify.Type == ACPI_HEST_NOTIFY_NMI) {
728 			ge->copybuf = malloc(ge->v1.ErrorBlockLength,
729 			    M_DEVBUF, M_WAITOK | M_ZERO);
730 			TAILQ_INSERT_TAIL(&sc->nges.ges, ge, nlink);
731 			if (sc->nges.swi_ih == NULL) {
732 				swi_add(&clk_intr_event, "apei", apei_nmi_swi,
733 				    &sc->nges, SWI_CLOCK, INTR_MPSAFE,
734 				    &sc->nges.swi_ih);
735 				apei_nmi_nges = &sc->nges;
736 				apei_nmi = apei_nmi_handler;
737 			}
738 		}
739 	}
740 
741 	if (acpi_get_handle(dev) != NULL) {
742 		AcpiInstallNotifyHandler(acpi_get_handle(dev),
743 		    ACPI_DEVICE_NOTIFY, apei_notify_handler, dev);
744 	}
745 	return (0);
746 }
747 
748 static int
apei_detach(device_t dev)749 apei_detach(device_t dev)
750 {
751 	struct apei_softc *sc = device_get_softc(dev);
752 	struct apei_ge *ge;
753 
754 	apei_nmi = NULL;
755 	apei_nmi_nges = NULL;
756 	if (sc->nges.swi_ih != NULL) {
757 		swi_remove(&sc->nges.swi_ih);
758 		sc->nges.swi_ih = NULL;
759 	}
760 	if (acpi_get_handle(dev) != NULL) {
761 		AcpiRemoveNotifyHandler(acpi_get_handle(dev),
762 		    ACPI_DEVICE_NOTIFY, apei_notify_handler);
763 	}
764 	for (int i = 0; i < nitems(sc->pges); i++)
765 		callout_drain(&sc->pges[i].poll);
766 
767 	while ((ge = TAILQ_FIRST(&sc->ges)) != NULL) {
768 		TAILQ_REMOVE(&sc->ges, ge, link);
769 		if (ge->res) {
770 			bus_release_resource(dev, ge->res_type,
771 			    ge->res_rid, ge->res);
772 		}
773 		if (ge->res2) {
774 			bus_release_resource(dev, ge->res2_type,
775 			    ge->res2_rid, ge->res2);
776 		}
777 		if (ge->v1.Notify.Type == ACPI_HEST_NOTIFY_POLLED) {
778 			TAILQ_REMOVE(&sc->pges[PGE_ID(ge)].ges, ge, nlink);
779 		} else if (ge->v1.Notify.Type == ACPI_HEST_NOTIFY_SCI ||
780 		    ge->v1.Notify.Type == ACPI_HEST_NOTIFY_GPIO ||
781 		    ge->v1.Notify.Type == ACPI_HEST_NOTIFY_GSIV) {
782 			TAILQ_REMOVE(&sc->iges.ges, ge, nlink);
783 		} else if (ge->v1.Notify.Type == ACPI_HEST_NOTIFY_NMI) {
784 			TAILQ_REMOVE(&sc->nges.ges, ge, nlink);
785 			free(ge->copybuf, M_DEVBUF);
786 		}
787 		if (ge->buf) {
788 			pmap_unmapdev(ge->buf, ge->v1.ErrorBlockLength);
789 		}
790 		free(ge, M_DEVBUF);
791 	}
792 	return (0);
793 }
794 
795 static device_method_t apei_methods[] = {
796 	/* Device interface */
797 	DEVMETHOD(device_identify, apei_identify),
798 	DEVMETHOD(device_probe, apei_probe),
799 	DEVMETHOD(device_attach, apei_attach),
800 	DEVMETHOD(device_detach, apei_detach),
801 	DEVMETHOD_END
802 };
803 
804 static driver_t	apei_driver = {
805 	"apei",
806 	apei_methods,
807 	sizeof(struct apei_softc),
808 };
809 
810 static int
apei_modevent(struct module * mod __unused,int evt,void * cookie __unused)811 apei_modevent(struct module *mod __unused, int evt, void *cookie __unused)
812 {
813 	int err = 0;
814 
815 	switch (evt) {
816 	case MOD_LOAD:
817 		sysctl_ctx_init(&apei_sysctl_ctx);
818 		break;
819 	case MOD_UNLOAD:
820 		sysctl_ctx_free(&apei_sysctl_ctx);
821 		break;
822 	default:
823 		err = EINVAL;
824 	}
825 	return (err);
826 }
827 
828 DRIVER_MODULE(apei, acpi, apei_driver, apei_modevent, 0);
829 MODULE_DEPEND(apei, acpi, 1, 1, 1);
830