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