Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
freebsd
GitHub Repository: freebsd/freebsd-src
Path: blob/main/sys/dev/acpica/acpi_apei.c
39507 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
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
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
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 *
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
831