Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
freebsd
GitHub Repository: freebsd/freebsd-src
Path: blob/main/sys/dev/acpica/acpi_apei.c
105585 views
1
/*-
2
* SPDX-License-Identifier: BSD-2-Clause
3
*
4
* Copyright (c) 2020 Alexander Motin <[email protected]>
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
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
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 *
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
830