Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
torvalds
GitHub Repository: torvalds/linux
Path: blob/master/drivers/acpi/apei/erst.c
26285 views
1
// SPDX-License-Identifier: GPL-2.0-only
2
/*
3
* APEI Error Record Serialization Table support
4
*
5
* ERST is a way provided by APEI to save and retrieve hardware error
6
* information to and from a persistent store.
7
*
8
* For more information about ERST, please refer to ACPI Specification
9
* version 4.0, section 17.4.
10
*
11
* Copyright 2010 Intel Corp.
12
* Author: Huang Ying <[email protected]>
13
*/
14
15
#include <linux/kernel.h>
16
#include <linux/module.h>
17
#include <linux/init.h>
18
#include <linux/delay.h>
19
#include <linux/io.h>
20
#include <linux/acpi.h>
21
#include <linux/uaccess.h>
22
#include <linux/cper.h>
23
#include <linux/nmi.h>
24
#include <linux/hardirq.h>
25
#include <linux/pstore.h>
26
#include <linux/vmalloc.h>
27
#include <linux/mm.h> /* kvfree() */
28
#include <acpi/apei.h>
29
30
#include "apei-internal.h"
31
32
#undef pr_fmt
33
#define pr_fmt(fmt) "ERST: " fmt
34
35
/* ERST command status */
36
#define ERST_STATUS_SUCCESS 0x0
37
#define ERST_STATUS_NOT_ENOUGH_SPACE 0x1
38
#define ERST_STATUS_HARDWARE_NOT_AVAILABLE 0x2
39
#define ERST_STATUS_FAILED 0x3
40
#define ERST_STATUS_RECORD_STORE_EMPTY 0x4
41
#define ERST_STATUS_RECORD_NOT_FOUND 0x5
42
43
#define ERST_TAB_ENTRY(tab) \
44
((struct acpi_whea_header *)((char *)(tab) + \
45
sizeof(struct acpi_table_erst)))
46
47
#define SPIN_UNIT 100 /* 100ns */
48
/* Firmware should respond within 1 milliseconds */
49
#define FIRMWARE_TIMEOUT (1 * NSEC_PER_MSEC)
50
#define FIRMWARE_MAX_STALL 50 /* 50us */
51
52
int erst_disable;
53
EXPORT_SYMBOL_GPL(erst_disable);
54
55
static struct acpi_table_erst *erst_tab;
56
57
/* ERST Error Log Address Range attributes */
58
#define ERST_RANGE_RESERVED 0x0001
59
#define ERST_RANGE_NVRAM 0x0002
60
#define ERST_RANGE_SLOW 0x0004
61
62
/* ERST Exec max timings */
63
#define ERST_EXEC_TIMING_MAX_MASK 0xFFFFFFFF00000000
64
#define ERST_EXEC_TIMING_MAX_SHIFT 32
65
66
/*
67
* ERST Error Log Address Range, used as buffer for reading/writing
68
* error records.
69
*/
70
static struct erst_erange {
71
u64 base;
72
u64 size;
73
void __iomem *vaddr;
74
u32 attr;
75
u64 timings;
76
} erst_erange;
77
78
/*
79
* Prevent ERST interpreter to run simultaneously, because the
80
* corresponding firmware implementation may not work properly when
81
* invoked simultaneously.
82
*
83
* It is used to provide exclusive accessing for ERST Error Log
84
* Address Range too.
85
*/
86
static DEFINE_RAW_SPINLOCK(erst_lock);
87
88
static inline int erst_errno(int command_status)
89
{
90
switch (command_status) {
91
case ERST_STATUS_SUCCESS:
92
return 0;
93
case ERST_STATUS_HARDWARE_NOT_AVAILABLE:
94
return -ENODEV;
95
case ERST_STATUS_NOT_ENOUGH_SPACE:
96
return -ENOSPC;
97
case ERST_STATUS_RECORD_STORE_EMPTY:
98
case ERST_STATUS_RECORD_NOT_FOUND:
99
return -ENOENT;
100
default:
101
return -EINVAL;
102
}
103
}
104
105
static inline u64 erst_get_timeout(void)
106
{
107
u64 timeout = FIRMWARE_TIMEOUT;
108
109
if (erst_erange.attr & ERST_RANGE_SLOW) {
110
timeout = ((erst_erange.timings & ERST_EXEC_TIMING_MAX_MASK) >>
111
ERST_EXEC_TIMING_MAX_SHIFT) * NSEC_PER_MSEC;
112
if (timeout < FIRMWARE_TIMEOUT)
113
timeout = FIRMWARE_TIMEOUT;
114
}
115
return timeout;
116
}
117
118
static int erst_timedout(u64 *t, u64 spin_unit)
119
{
120
if ((s64)*t < spin_unit) {
121
pr_warn(FW_WARN "Firmware does not respond in time.\n");
122
return 1;
123
}
124
*t -= spin_unit;
125
ndelay(spin_unit);
126
touch_nmi_watchdog();
127
return 0;
128
}
129
130
static int erst_exec_load_var1(struct apei_exec_context *ctx,
131
struct acpi_whea_header *entry)
132
{
133
return __apei_exec_read_register(entry, &ctx->var1);
134
}
135
136
static int erst_exec_load_var2(struct apei_exec_context *ctx,
137
struct acpi_whea_header *entry)
138
{
139
return __apei_exec_read_register(entry, &ctx->var2);
140
}
141
142
static int erst_exec_store_var1(struct apei_exec_context *ctx,
143
struct acpi_whea_header *entry)
144
{
145
return __apei_exec_write_register(entry, ctx->var1);
146
}
147
148
static int erst_exec_add(struct apei_exec_context *ctx,
149
struct acpi_whea_header *entry)
150
{
151
ctx->var1 += ctx->var2;
152
return 0;
153
}
154
155
static int erst_exec_subtract(struct apei_exec_context *ctx,
156
struct acpi_whea_header *entry)
157
{
158
ctx->var1 -= ctx->var2;
159
return 0;
160
}
161
162
static int erst_exec_add_value(struct apei_exec_context *ctx,
163
struct acpi_whea_header *entry)
164
{
165
int rc;
166
u64 val;
167
168
rc = __apei_exec_read_register(entry, &val);
169
if (rc)
170
return rc;
171
val += ctx->value;
172
rc = __apei_exec_write_register(entry, val);
173
return rc;
174
}
175
176
static int erst_exec_subtract_value(struct apei_exec_context *ctx,
177
struct acpi_whea_header *entry)
178
{
179
int rc;
180
u64 val;
181
182
rc = __apei_exec_read_register(entry, &val);
183
if (rc)
184
return rc;
185
val -= ctx->value;
186
rc = __apei_exec_write_register(entry, val);
187
return rc;
188
}
189
190
static int erst_exec_stall(struct apei_exec_context *ctx,
191
struct acpi_whea_header *entry)
192
{
193
u64 stall_time;
194
195
if (ctx->value > FIRMWARE_MAX_STALL) {
196
if (!in_nmi())
197
pr_warn(FW_WARN
198
"Too long stall time for stall instruction: 0x%llx.\n",
199
ctx->value);
200
stall_time = FIRMWARE_MAX_STALL;
201
} else
202
stall_time = ctx->value;
203
udelay(stall_time);
204
return 0;
205
}
206
207
static int erst_exec_stall_while_true(struct apei_exec_context *ctx,
208
struct acpi_whea_header *entry)
209
{
210
int rc;
211
u64 val;
212
u64 timeout;
213
u64 stall_time;
214
215
timeout = erst_get_timeout();
216
217
if (ctx->var1 > FIRMWARE_MAX_STALL) {
218
if (!in_nmi())
219
pr_warn(FW_WARN
220
"Too long stall time for stall while true instruction: 0x%llx.\n",
221
ctx->var1);
222
stall_time = FIRMWARE_MAX_STALL;
223
} else
224
stall_time = ctx->var1;
225
226
for (;;) {
227
rc = __apei_exec_read_register(entry, &val);
228
if (rc)
229
return rc;
230
if (val != ctx->value)
231
break;
232
if (erst_timedout(&timeout, stall_time * NSEC_PER_USEC))
233
return -EIO;
234
}
235
return 0;
236
}
237
238
static int erst_exec_skip_next_instruction_if_true(
239
struct apei_exec_context *ctx,
240
struct acpi_whea_header *entry)
241
{
242
int rc;
243
u64 val;
244
245
rc = __apei_exec_read_register(entry, &val);
246
if (rc)
247
return rc;
248
if (val == ctx->value) {
249
ctx->ip += 2;
250
return APEI_EXEC_SET_IP;
251
}
252
253
return 0;
254
}
255
256
static int erst_exec_goto(struct apei_exec_context *ctx,
257
struct acpi_whea_header *entry)
258
{
259
ctx->ip = ctx->value;
260
return APEI_EXEC_SET_IP;
261
}
262
263
static int erst_exec_set_src_address_base(struct apei_exec_context *ctx,
264
struct acpi_whea_header *entry)
265
{
266
return __apei_exec_read_register(entry, &ctx->src_base);
267
}
268
269
static int erst_exec_set_dst_address_base(struct apei_exec_context *ctx,
270
struct acpi_whea_header *entry)
271
{
272
return __apei_exec_read_register(entry, &ctx->dst_base);
273
}
274
275
static int erst_exec_move_data(struct apei_exec_context *ctx,
276
struct acpi_whea_header *entry)
277
{
278
int rc;
279
u64 offset;
280
void *src, *dst;
281
282
/* ioremap does not work in interrupt context */
283
if (in_interrupt()) {
284
pr_warn("MOVE_DATA can not be used in interrupt context.\n");
285
return -EBUSY;
286
}
287
288
rc = __apei_exec_read_register(entry, &offset);
289
if (rc)
290
return rc;
291
292
src = ioremap(ctx->src_base + offset, ctx->var2);
293
if (!src)
294
return -ENOMEM;
295
dst = ioremap(ctx->dst_base + offset, ctx->var2);
296
if (!dst) {
297
iounmap(src);
298
return -ENOMEM;
299
}
300
301
memmove(dst, src, ctx->var2);
302
303
iounmap(src);
304
iounmap(dst);
305
306
return 0;
307
}
308
309
static struct apei_exec_ins_type erst_ins_type[] = {
310
[ACPI_ERST_READ_REGISTER] = {
311
.flags = APEI_EXEC_INS_ACCESS_REGISTER,
312
.run = apei_exec_read_register,
313
},
314
[ACPI_ERST_READ_REGISTER_VALUE] = {
315
.flags = APEI_EXEC_INS_ACCESS_REGISTER,
316
.run = apei_exec_read_register_value,
317
},
318
[ACPI_ERST_WRITE_REGISTER] = {
319
.flags = APEI_EXEC_INS_ACCESS_REGISTER,
320
.run = apei_exec_write_register,
321
},
322
[ACPI_ERST_WRITE_REGISTER_VALUE] = {
323
.flags = APEI_EXEC_INS_ACCESS_REGISTER,
324
.run = apei_exec_write_register_value,
325
},
326
[ACPI_ERST_NOOP] = {
327
.flags = 0,
328
.run = apei_exec_noop,
329
},
330
[ACPI_ERST_LOAD_VAR1] = {
331
.flags = APEI_EXEC_INS_ACCESS_REGISTER,
332
.run = erst_exec_load_var1,
333
},
334
[ACPI_ERST_LOAD_VAR2] = {
335
.flags = APEI_EXEC_INS_ACCESS_REGISTER,
336
.run = erst_exec_load_var2,
337
},
338
[ACPI_ERST_STORE_VAR1] = {
339
.flags = APEI_EXEC_INS_ACCESS_REGISTER,
340
.run = erst_exec_store_var1,
341
},
342
[ACPI_ERST_ADD] = {
343
.flags = 0,
344
.run = erst_exec_add,
345
},
346
[ACPI_ERST_SUBTRACT] = {
347
.flags = 0,
348
.run = erst_exec_subtract,
349
},
350
[ACPI_ERST_ADD_VALUE] = {
351
.flags = APEI_EXEC_INS_ACCESS_REGISTER,
352
.run = erst_exec_add_value,
353
},
354
[ACPI_ERST_SUBTRACT_VALUE] = {
355
.flags = APEI_EXEC_INS_ACCESS_REGISTER,
356
.run = erst_exec_subtract_value,
357
},
358
[ACPI_ERST_STALL] = {
359
.flags = 0,
360
.run = erst_exec_stall,
361
},
362
[ACPI_ERST_STALL_WHILE_TRUE] = {
363
.flags = APEI_EXEC_INS_ACCESS_REGISTER,
364
.run = erst_exec_stall_while_true,
365
},
366
[ACPI_ERST_SKIP_NEXT_IF_TRUE] = {
367
.flags = APEI_EXEC_INS_ACCESS_REGISTER,
368
.run = erst_exec_skip_next_instruction_if_true,
369
},
370
[ACPI_ERST_GOTO] = {
371
.flags = 0,
372
.run = erst_exec_goto,
373
},
374
[ACPI_ERST_SET_SRC_ADDRESS_BASE] = {
375
.flags = APEI_EXEC_INS_ACCESS_REGISTER,
376
.run = erst_exec_set_src_address_base,
377
},
378
[ACPI_ERST_SET_DST_ADDRESS_BASE] = {
379
.flags = APEI_EXEC_INS_ACCESS_REGISTER,
380
.run = erst_exec_set_dst_address_base,
381
},
382
[ACPI_ERST_MOVE_DATA] = {
383
.flags = APEI_EXEC_INS_ACCESS_REGISTER,
384
.run = erst_exec_move_data,
385
},
386
};
387
388
static inline void erst_exec_ctx_init(struct apei_exec_context *ctx)
389
{
390
apei_exec_ctx_init(ctx, erst_ins_type, ARRAY_SIZE(erst_ins_type),
391
ERST_TAB_ENTRY(erst_tab), erst_tab->entries);
392
}
393
394
static int erst_get_erange(struct erst_erange *range)
395
{
396
struct apei_exec_context ctx;
397
int rc;
398
399
erst_exec_ctx_init(&ctx);
400
rc = apei_exec_run(&ctx, ACPI_ERST_GET_ERROR_RANGE);
401
if (rc)
402
return rc;
403
range->base = apei_exec_ctx_get_output(&ctx);
404
rc = apei_exec_run(&ctx, ACPI_ERST_GET_ERROR_LENGTH);
405
if (rc)
406
return rc;
407
range->size = apei_exec_ctx_get_output(&ctx);
408
rc = apei_exec_run(&ctx, ACPI_ERST_GET_ERROR_ATTRIBUTES);
409
if (rc)
410
return rc;
411
range->attr = apei_exec_ctx_get_output(&ctx);
412
rc = apei_exec_run(&ctx, ACPI_ERST_EXECUTE_TIMINGS);
413
if (rc == 0)
414
range->timings = apei_exec_ctx_get_output(&ctx);
415
else if (rc == -ENOENT)
416
range->timings = 0;
417
else
418
return rc;
419
420
return 0;
421
}
422
423
static ssize_t __erst_get_record_count(void)
424
{
425
struct apei_exec_context ctx;
426
int rc;
427
428
erst_exec_ctx_init(&ctx);
429
rc = apei_exec_run(&ctx, ACPI_ERST_GET_RECORD_COUNT);
430
if (rc)
431
return rc;
432
return apei_exec_ctx_get_output(&ctx);
433
}
434
435
ssize_t erst_get_record_count(void)
436
{
437
ssize_t count;
438
unsigned long flags;
439
440
if (erst_disable)
441
return -ENODEV;
442
443
raw_spin_lock_irqsave(&erst_lock, flags);
444
count = __erst_get_record_count();
445
raw_spin_unlock_irqrestore(&erst_lock, flags);
446
447
return count;
448
}
449
EXPORT_SYMBOL_GPL(erst_get_record_count);
450
451
#define ERST_RECORD_ID_CACHE_SIZE_MIN 16
452
#define ERST_RECORD_ID_CACHE_SIZE_MAX 1024
453
454
struct erst_record_id_cache {
455
struct mutex lock;
456
u64 *entries;
457
int len;
458
int size;
459
int refcount;
460
};
461
462
static struct erst_record_id_cache erst_record_id_cache = {
463
.lock = __MUTEX_INITIALIZER(erst_record_id_cache.lock),
464
.refcount = 0,
465
};
466
467
static int __erst_get_next_record_id(u64 *record_id)
468
{
469
struct apei_exec_context ctx;
470
int rc;
471
472
erst_exec_ctx_init(&ctx);
473
rc = apei_exec_run(&ctx, ACPI_ERST_GET_RECORD_ID);
474
if (rc)
475
return rc;
476
*record_id = apei_exec_ctx_get_output(&ctx);
477
478
return 0;
479
}
480
481
int erst_get_record_id_begin(int *pos)
482
{
483
int rc;
484
485
if (erst_disable)
486
return -ENODEV;
487
488
rc = mutex_lock_interruptible(&erst_record_id_cache.lock);
489
if (rc)
490
return rc;
491
erst_record_id_cache.refcount++;
492
mutex_unlock(&erst_record_id_cache.lock);
493
494
*pos = 0;
495
496
return 0;
497
}
498
EXPORT_SYMBOL_GPL(erst_get_record_id_begin);
499
500
/* erst_record_id_cache.lock must be held by caller */
501
static int __erst_record_id_cache_add_one(void)
502
{
503
u64 id, prev_id, first_id;
504
int i, rc;
505
u64 *entries;
506
unsigned long flags;
507
508
id = prev_id = first_id = APEI_ERST_INVALID_RECORD_ID;
509
retry:
510
raw_spin_lock_irqsave(&erst_lock, flags);
511
rc = __erst_get_next_record_id(&id);
512
raw_spin_unlock_irqrestore(&erst_lock, flags);
513
if (rc == -ENOENT)
514
return 0;
515
if (rc)
516
return rc;
517
if (id == APEI_ERST_INVALID_RECORD_ID)
518
return 0;
519
/* can not skip current ID, or loop back to first ID */
520
if (id == prev_id || id == first_id)
521
return 0;
522
if (first_id == APEI_ERST_INVALID_RECORD_ID)
523
first_id = id;
524
prev_id = id;
525
526
entries = erst_record_id_cache.entries;
527
for (i = 0; i < erst_record_id_cache.len; i++) {
528
if (entries[i] == id)
529
break;
530
}
531
/* record id already in cache, try next */
532
if (i < erst_record_id_cache.len)
533
goto retry;
534
if (erst_record_id_cache.len >= erst_record_id_cache.size) {
535
int new_size;
536
u64 *new_entries;
537
538
new_size = erst_record_id_cache.size * 2;
539
new_size = clamp_val(new_size, ERST_RECORD_ID_CACHE_SIZE_MIN,
540
ERST_RECORD_ID_CACHE_SIZE_MAX);
541
if (new_size <= erst_record_id_cache.size) {
542
if (printk_ratelimit())
543
pr_warn(FW_WARN "too many record IDs!\n");
544
return 0;
545
}
546
new_entries = kvmalloc_array(new_size, sizeof(entries[0]),
547
GFP_KERNEL);
548
if (!new_entries)
549
return -ENOMEM;
550
memcpy(new_entries, entries,
551
erst_record_id_cache.len * sizeof(entries[0]));
552
kvfree(entries);
553
erst_record_id_cache.entries = entries = new_entries;
554
erst_record_id_cache.size = new_size;
555
}
556
entries[i] = id;
557
erst_record_id_cache.len++;
558
559
return 1;
560
}
561
562
/*
563
* Get the record ID of an existing error record on the persistent
564
* storage. If there is no error record on the persistent storage, the
565
* returned record_id is APEI_ERST_INVALID_RECORD_ID.
566
*/
567
int erst_get_record_id_next(int *pos, u64 *record_id)
568
{
569
int rc = 0;
570
u64 *entries;
571
572
if (erst_disable)
573
return -ENODEV;
574
575
/* must be enclosed by erst_get_record_id_begin/end */
576
BUG_ON(!erst_record_id_cache.refcount);
577
BUG_ON(*pos < 0 || *pos > erst_record_id_cache.len);
578
579
mutex_lock(&erst_record_id_cache.lock);
580
entries = erst_record_id_cache.entries;
581
for (; *pos < erst_record_id_cache.len; (*pos)++)
582
if (entries[*pos] != APEI_ERST_INVALID_RECORD_ID)
583
break;
584
/* found next record id in cache */
585
if (*pos < erst_record_id_cache.len) {
586
*record_id = entries[*pos];
587
(*pos)++;
588
goto out_unlock;
589
}
590
591
/* Try to add one more record ID to cache */
592
rc = __erst_record_id_cache_add_one();
593
if (rc < 0)
594
goto out_unlock;
595
/* successfully add one new ID */
596
if (rc == 1) {
597
*record_id = erst_record_id_cache.entries[*pos];
598
(*pos)++;
599
rc = 0;
600
} else {
601
*pos = -1;
602
*record_id = APEI_ERST_INVALID_RECORD_ID;
603
}
604
out_unlock:
605
mutex_unlock(&erst_record_id_cache.lock);
606
607
return rc;
608
}
609
EXPORT_SYMBOL_GPL(erst_get_record_id_next);
610
611
/* erst_record_id_cache.lock must be held by caller */
612
static void __erst_record_id_cache_compact(void)
613
{
614
int i, wpos = 0;
615
u64 *entries;
616
617
if (erst_record_id_cache.refcount)
618
return;
619
620
entries = erst_record_id_cache.entries;
621
for (i = 0; i < erst_record_id_cache.len; i++) {
622
if (entries[i] == APEI_ERST_INVALID_RECORD_ID)
623
continue;
624
if (wpos != i)
625
entries[wpos] = entries[i];
626
wpos++;
627
}
628
erst_record_id_cache.len = wpos;
629
}
630
631
void erst_get_record_id_end(void)
632
{
633
/*
634
* erst_disable != 0 should be detected by invoker via the
635
* return value of erst_get_record_id_begin/next, so this
636
* function should not be called for erst_disable != 0.
637
*/
638
BUG_ON(erst_disable);
639
640
mutex_lock(&erst_record_id_cache.lock);
641
erst_record_id_cache.refcount--;
642
BUG_ON(erst_record_id_cache.refcount < 0);
643
__erst_record_id_cache_compact();
644
mutex_unlock(&erst_record_id_cache.lock);
645
}
646
EXPORT_SYMBOL_GPL(erst_get_record_id_end);
647
648
static int __erst_write_to_storage(u64 offset)
649
{
650
struct apei_exec_context ctx;
651
u64 timeout;
652
u64 val;
653
int rc;
654
655
timeout = erst_get_timeout();
656
657
erst_exec_ctx_init(&ctx);
658
rc = apei_exec_run_optional(&ctx, ACPI_ERST_BEGIN_WRITE);
659
if (rc)
660
return rc;
661
apei_exec_ctx_set_input(&ctx, offset);
662
rc = apei_exec_run(&ctx, ACPI_ERST_SET_RECORD_OFFSET);
663
if (rc)
664
return rc;
665
rc = apei_exec_run(&ctx, ACPI_ERST_EXECUTE_OPERATION);
666
if (rc)
667
return rc;
668
for (;;) {
669
rc = apei_exec_run(&ctx, ACPI_ERST_CHECK_BUSY_STATUS);
670
if (rc)
671
return rc;
672
val = apei_exec_ctx_get_output(&ctx);
673
if (!val)
674
break;
675
if (erst_timedout(&timeout, SPIN_UNIT))
676
return -EIO;
677
}
678
rc = apei_exec_run(&ctx, ACPI_ERST_GET_COMMAND_STATUS);
679
if (rc)
680
return rc;
681
val = apei_exec_ctx_get_output(&ctx);
682
rc = apei_exec_run_optional(&ctx, ACPI_ERST_END);
683
if (rc)
684
return rc;
685
686
return erst_errno(val);
687
}
688
689
static int __erst_read_from_storage(u64 record_id, u64 offset)
690
{
691
struct apei_exec_context ctx;
692
u64 timeout;
693
u64 val;
694
int rc;
695
696
timeout = erst_get_timeout();
697
698
erst_exec_ctx_init(&ctx);
699
rc = apei_exec_run_optional(&ctx, ACPI_ERST_BEGIN_READ);
700
if (rc)
701
return rc;
702
apei_exec_ctx_set_input(&ctx, offset);
703
rc = apei_exec_run(&ctx, ACPI_ERST_SET_RECORD_OFFSET);
704
if (rc)
705
return rc;
706
apei_exec_ctx_set_input(&ctx, record_id);
707
rc = apei_exec_run(&ctx, ACPI_ERST_SET_RECORD_ID);
708
if (rc)
709
return rc;
710
rc = apei_exec_run(&ctx, ACPI_ERST_EXECUTE_OPERATION);
711
if (rc)
712
return rc;
713
for (;;) {
714
rc = apei_exec_run(&ctx, ACPI_ERST_CHECK_BUSY_STATUS);
715
if (rc)
716
return rc;
717
val = apei_exec_ctx_get_output(&ctx);
718
if (!val)
719
break;
720
if (erst_timedout(&timeout, SPIN_UNIT))
721
return -EIO;
722
}
723
rc = apei_exec_run(&ctx, ACPI_ERST_GET_COMMAND_STATUS);
724
if (rc)
725
return rc;
726
val = apei_exec_ctx_get_output(&ctx);
727
rc = apei_exec_run_optional(&ctx, ACPI_ERST_END);
728
if (rc)
729
return rc;
730
731
return erst_errno(val);
732
}
733
734
static int __erst_clear_from_storage(u64 record_id)
735
{
736
struct apei_exec_context ctx;
737
u64 timeout;
738
u64 val;
739
int rc;
740
741
timeout = erst_get_timeout();
742
743
erst_exec_ctx_init(&ctx);
744
rc = apei_exec_run_optional(&ctx, ACPI_ERST_BEGIN_CLEAR);
745
if (rc)
746
return rc;
747
apei_exec_ctx_set_input(&ctx, record_id);
748
rc = apei_exec_run(&ctx, ACPI_ERST_SET_RECORD_ID);
749
if (rc)
750
return rc;
751
rc = apei_exec_run(&ctx, ACPI_ERST_EXECUTE_OPERATION);
752
if (rc)
753
return rc;
754
for (;;) {
755
rc = apei_exec_run(&ctx, ACPI_ERST_CHECK_BUSY_STATUS);
756
if (rc)
757
return rc;
758
val = apei_exec_ctx_get_output(&ctx);
759
if (!val)
760
break;
761
if (erst_timedout(&timeout, SPIN_UNIT))
762
return -EIO;
763
}
764
rc = apei_exec_run(&ctx, ACPI_ERST_GET_COMMAND_STATUS);
765
if (rc)
766
return rc;
767
val = apei_exec_ctx_get_output(&ctx);
768
rc = apei_exec_run_optional(&ctx, ACPI_ERST_END);
769
if (rc)
770
return rc;
771
772
return erst_errno(val);
773
}
774
775
/* NVRAM ERST Error Log Address Range is not supported yet */
776
static void pr_unimpl_nvram(void)
777
{
778
if (printk_ratelimit())
779
pr_warn("NVRAM ERST Log Address Range not implemented yet.\n");
780
}
781
782
static int __erst_write_to_nvram(const struct cper_record_header *record)
783
{
784
/* do not print message, because printk is not safe for NMI */
785
return -ENOSYS;
786
}
787
788
static int __erst_read_to_erange_from_nvram(u64 record_id, u64 *offset)
789
{
790
pr_unimpl_nvram();
791
return -ENOSYS;
792
}
793
794
static int __erst_clear_from_nvram(u64 record_id)
795
{
796
pr_unimpl_nvram();
797
return -ENOSYS;
798
}
799
800
int erst_write(const struct cper_record_header *record)
801
{
802
int rc;
803
unsigned long flags;
804
struct cper_record_header *rcd_erange;
805
806
if (erst_disable)
807
return -ENODEV;
808
809
if (memcmp(record->signature, CPER_SIG_RECORD, CPER_SIG_SIZE))
810
return -EINVAL;
811
812
if (erst_erange.attr & ERST_RANGE_NVRAM) {
813
if (!raw_spin_trylock_irqsave(&erst_lock, flags))
814
return -EBUSY;
815
rc = __erst_write_to_nvram(record);
816
raw_spin_unlock_irqrestore(&erst_lock, flags);
817
return rc;
818
}
819
820
if (record->record_length > erst_erange.size)
821
return -EINVAL;
822
823
if (!raw_spin_trylock_irqsave(&erst_lock, flags))
824
return -EBUSY;
825
memcpy(erst_erange.vaddr, record, record->record_length);
826
rcd_erange = erst_erange.vaddr;
827
/* signature for serialization system */
828
memcpy(&rcd_erange->persistence_information, "ER", 2);
829
830
rc = __erst_write_to_storage(0);
831
raw_spin_unlock_irqrestore(&erst_lock, flags);
832
833
return rc;
834
}
835
EXPORT_SYMBOL_GPL(erst_write);
836
837
static int __erst_read_to_erange(u64 record_id, u64 *offset)
838
{
839
int rc;
840
841
if (erst_erange.attr & ERST_RANGE_NVRAM)
842
return __erst_read_to_erange_from_nvram(
843
record_id, offset);
844
845
rc = __erst_read_from_storage(record_id, 0);
846
if (rc)
847
return rc;
848
*offset = 0;
849
850
return 0;
851
}
852
853
static ssize_t __erst_read(u64 record_id, struct cper_record_header *record,
854
size_t buflen)
855
{
856
int rc;
857
u64 offset, len = 0;
858
struct cper_record_header *rcd_tmp;
859
860
rc = __erst_read_to_erange(record_id, &offset);
861
if (rc)
862
return rc;
863
rcd_tmp = erst_erange.vaddr + offset;
864
len = rcd_tmp->record_length;
865
if (len <= buflen)
866
memcpy(record, rcd_tmp, len);
867
868
return len;
869
}
870
871
/*
872
* If return value > buflen, the buffer size is not big enough,
873
* else if return value < 0, something goes wrong,
874
* else everything is OK, and return value is record length
875
*/
876
ssize_t erst_read(u64 record_id, struct cper_record_header *record,
877
size_t buflen)
878
{
879
ssize_t len;
880
unsigned long flags;
881
882
if (erst_disable)
883
return -ENODEV;
884
885
raw_spin_lock_irqsave(&erst_lock, flags);
886
len = __erst_read(record_id, record, buflen);
887
raw_spin_unlock_irqrestore(&erst_lock, flags);
888
return len;
889
}
890
EXPORT_SYMBOL_GPL(erst_read);
891
892
static void erst_clear_cache(u64 record_id)
893
{
894
int i;
895
u64 *entries;
896
897
mutex_lock(&erst_record_id_cache.lock);
898
899
entries = erst_record_id_cache.entries;
900
for (i = 0; i < erst_record_id_cache.len; i++) {
901
if (entries[i] == record_id)
902
entries[i] = APEI_ERST_INVALID_RECORD_ID;
903
}
904
__erst_record_id_cache_compact();
905
906
mutex_unlock(&erst_record_id_cache.lock);
907
}
908
909
ssize_t erst_read_record(u64 record_id, struct cper_record_header *record,
910
size_t buflen, size_t recordlen, const guid_t *creatorid)
911
{
912
ssize_t len;
913
914
/*
915
* if creatorid is NULL, read any record for erst-dbg module
916
*/
917
if (creatorid == NULL) {
918
len = erst_read(record_id, record, buflen);
919
if (len == -ENOENT)
920
erst_clear_cache(record_id);
921
922
return len;
923
}
924
925
len = erst_read(record_id, record, buflen);
926
/*
927
* if erst_read return value is -ENOENT skip to next record_id,
928
* and clear the record_id cache.
929
*/
930
if (len == -ENOENT) {
931
erst_clear_cache(record_id);
932
goto out;
933
}
934
935
if (len < 0)
936
goto out;
937
938
/*
939
* if erst_read return value is less than record head length,
940
* consider it as -EIO, and clear the record_id cache.
941
*/
942
if (len < recordlen) {
943
len = -EIO;
944
erst_clear_cache(record_id);
945
goto out;
946
}
947
948
/*
949
* if creatorid is not wanted, consider it as not found,
950
* for skipping to next record_id.
951
*/
952
if (!guid_equal(&record->creator_id, creatorid))
953
len = -ENOENT;
954
955
out:
956
return len;
957
}
958
EXPORT_SYMBOL_GPL(erst_read_record);
959
960
int erst_clear(u64 record_id)
961
{
962
int rc, i;
963
unsigned long flags;
964
u64 *entries;
965
966
if (erst_disable)
967
return -ENODEV;
968
969
rc = mutex_lock_interruptible(&erst_record_id_cache.lock);
970
if (rc)
971
return rc;
972
raw_spin_lock_irqsave(&erst_lock, flags);
973
if (erst_erange.attr & ERST_RANGE_NVRAM)
974
rc = __erst_clear_from_nvram(record_id);
975
else
976
rc = __erst_clear_from_storage(record_id);
977
raw_spin_unlock_irqrestore(&erst_lock, flags);
978
if (rc)
979
goto out;
980
entries = erst_record_id_cache.entries;
981
for (i = 0; i < erst_record_id_cache.len; i++) {
982
if (entries[i] == record_id)
983
entries[i] = APEI_ERST_INVALID_RECORD_ID;
984
}
985
__erst_record_id_cache_compact();
986
out:
987
mutex_unlock(&erst_record_id_cache.lock);
988
return rc;
989
}
990
EXPORT_SYMBOL_GPL(erst_clear);
991
992
static int __init setup_erst_disable(char *str)
993
{
994
erst_disable = 1;
995
return 1;
996
}
997
998
__setup("erst_disable", setup_erst_disable);
999
1000
static int erst_check_table(struct acpi_table_erst *erst_tab)
1001
{
1002
if ((erst_tab->header_length !=
1003
(sizeof(struct acpi_table_erst) - sizeof(erst_tab->header)))
1004
&& (erst_tab->header_length != sizeof(struct acpi_table_erst)))
1005
return -EINVAL;
1006
if (erst_tab->header.length < sizeof(struct acpi_table_erst))
1007
return -EINVAL;
1008
if (erst_tab->entries !=
1009
(erst_tab->header.length - sizeof(struct acpi_table_erst)) /
1010
sizeof(struct acpi_erst_entry))
1011
return -EINVAL;
1012
1013
return 0;
1014
}
1015
1016
static int erst_open_pstore(struct pstore_info *psi);
1017
static int erst_close_pstore(struct pstore_info *psi);
1018
static ssize_t erst_reader(struct pstore_record *record);
1019
static int erst_writer(struct pstore_record *record);
1020
static int erst_clearer(struct pstore_record *record);
1021
1022
static struct pstore_info erst_info = {
1023
.owner = THIS_MODULE,
1024
.name = "erst",
1025
.flags = PSTORE_FLAGS_DMESG,
1026
.open = erst_open_pstore,
1027
.close = erst_close_pstore,
1028
.read = erst_reader,
1029
.write = erst_writer,
1030
.erase = erst_clearer
1031
};
1032
1033
#define CPER_CREATOR_PSTORE \
1034
GUID_INIT(0x75a574e3, 0x5052, 0x4b29, 0x8a, 0x8e, 0xbe, 0x2c, \
1035
0x64, 0x90, 0xb8, 0x9d)
1036
#define CPER_SECTION_TYPE_DMESG \
1037
GUID_INIT(0xc197e04e, 0xd545, 0x4a70, 0x9c, 0x17, 0xa5, 0x54, \
1038
0x94, 0x19, 0xeb, 0x12)
1039
#define CPER_SECTION_TYPE_DMESG_Z \
1040
GUID_INIT(0x4f118707, 0x04dd, 0x4055, 0xb5, 0xdd, 0x95, 0x6d, \
1041
0x34, 0xdd, 0xfa, 0xc6)
1042
#define CPER_SECTION_TYPE_MCE \
1043
GUID_INIT(0xfe08ffbe, 0x95e4, 0x4be7, 0xbc, 0x73, 0x40, 0x96, \
1044
0x04, 0x4a, 0x38, 0xfc)
1045
1046
struct cper_pstore_record {
1047
struct cper_record_header hdr;
1048
struct cper_section_descriptor sec_hdr;
1049
char data[];
1050
} __packed;
1051
1052
static int reader_pos;
1053
1054
static int erst_open_pstore(struct pstore_info *psi)
1055
{
1056
if (erst_disable)
1057
return -ENODEV;
1058
1059
return erst_get_record_id_begin(&reader_pos);
1060
}
1061
1062
static int erst_close_pstore(struct pstore_info *psi)
1063
{
1064
erst_get_record_id_end();
1065
1066
return 0;
1067
}
1068
1069
static ssize_t erst_reader(struct pstore_record *record)
1070
{
1071
int rc;
1072
ssize_t len = 0;
1073
u64 record_id;
1074
struct cper_pstore_record *rcd;
1075
size_t rcd_len = sizeof(*rcd) + erst_info.bufsize;
1076
1077
if (erst_disable)
1078
return -ENODEV;
1079
1080
rcd = kmalloc(rcd_len, GFP_KERNEL);
1081
if (!rcd) {
1082
rc = -ENOMEM;
1083
goto out;
1084
}
1085
skip:
1086
rc = erst_get_record_id_next(&reader_pos, &record_id);
1087
if (rc)
1088
goto out;
1089
1090
/* no more record */
1091
if (record_id == APEI_ERST_INVALID_RECORD_ID) {
1092
rc = -EINVAL;
1093
goto out;
1094
}
1095
1096
len = erst_read_record(record_id, &rcd->hdr, rcd_len, sizeof(*rcd),
1097
&CPER_CREATOR_PSTORE);
1098
/* The record may be cleared by others, try read next record */
1099
if (len == -ENOENT)
1100
goto skip;
1101
else if (len < 0)
1102
goto out;
1103
1104
record->buf = kmalloc(len, GFP_KERNEL);
1105
if (record->buf == NULL) {
1106
rc = -ENOMEM;
1107
goto out;
1108
}
1109
memcpy(record->buf, rcd->data, len - sizeof(*rcd));
1110
record->id = record_id;
1111
record->compressed = false;
1112
record->ecc_notice_size = 0;
1113
if (guid_equal(&rcd->sec_hdr.section_type, &CPER_SECTION_TYPE_DMESG_Z)) {
1114
record->type = PSTORE_TYPE_DMESG;
1115
record->compressed = true;
1116
} else if (guid_equal(&rcd->sec_hdr.section_type, &CPER_SECTION_TYPE_DMESG))
1117
record->type = PSTORE_TYPE_DMESG;
1118
else if (guid_equal(&rcd->sec_hdr.section_type, &CPER_SECTION_TYPE_MCE))
1119
record->type = PSTORE_TYPE_MCE;
1120
else
1121
record->type = PSTORE_TYPE_MAX;
1122
1123
if (rcd->hdr.validation_bits & CPER_VALID_TIMESTAMP)
1124
record->time.tv_sec = rcd->hdr.timestamp;
1125
else
1126
record->time.tv_sec = 0;
1127
record->time.tv_nsec = 0;
1128
1129
out:
1130
kfree(rcd);
1131
return (rc < 0) ? rc : (len - sizeof(*rcd));
1132
}
1133
1134
static int erst_writer(struct pstore_record *record)
1135
{
1136
struct cper_pstore_record *rcd = (struct cper_pstore_record *)
1137
(erst_info.buf - sizeof(*rcd));
1138
int ret;
1139
1140
memset(rcd, 0, sizeof(*rcd));
1141
memcpy(rcd->hdr.signature, CPER_SIG_RECORD, CPER_SIG_SIZE);
1142
rcd->hdr.revision = CPER_RECORD_REV;
1143
rcd->hdr.signature_end = CPER_SIG_END;
1144
rcd->hdr.section_count = 1;
1145
rcd->hdr.error_severity = CPER_SEV_FATAL;
1146
/* timestamp valid. platform_id, partition_id are invalid */
1147
rcd->hdr.validation_bits = CPER_VALID_TIMESTAMP;
1148
rcd->hdr.timestamp = ktime_get_real_seconds();
1149
rcd->hdr.record_length = sizeof(*rcd) + record->size;
1150
rcd->hdr.creator_id = CPER_CREATOR_PSTORE;
1151
rcd->hdr.notification_type = CPER_NOTIFY_MCE;
1152
rcd->hdr.record_id = cper_next_record_id();
1153
rcd->hdr.flags = CPER_HW_ERROR_FLAGS_PREVERR;
1154
1155
rcd->sec_hdr.section_offset = sizeof(*rcd);
1156
rcd->sec_hdr.section_length = record->size;
1157
rcd->sec_hdr.revision = CPER_SEC_REV;
1158
/* fru_id and fru_text is invalid */
1159
rcd->sec_hdr.validation_bits = 0;
1160
rcd->sec_hdr.flags = CPER_SEC_PRIMARY;
1161
switch (record->type) {
1162
case PSTORE_TYPE_DMESG:
1163
if (record->compressed)
1164
rcd->sec_hdr.section_type = CPER_SECTION_TYPE_DMESG_Z;
1165
else
1166
rcd->sec_hdr.section_type = CPER_SECTION_TYPE_DMESG;
1167
break;
1168
case PSTORE_TYPE_MCE:
1169
rcd->sec_hdr.section_type = CPER_SECTION_TYPE_MCE;
1170
break;
1171
default:
1172
return -EINVAL;
1173
}
1174
rcd->sec_hdr.section_severity = CPER_SEV_FATAL;
1175
1176
ret = erst_write(&rcd->hdr);
1177
record->id = rcd->hdr.record_id;
1178
1179
return ret;
1180
}
1181
1182
static int erst_clearer(struct pstore_record *record)
1183
{
1184
return erst_clear(record->id);
1185
}
1186
1187
static int __init erst_init(void)
1188
{
1189
int rc = 0;
1190
acpi_status status;
1191
struct apei_exec_context ctx;
1192
struct apei_resources erst_resources;
1193
struct resource *r;
1194
char *buf;
1195
1196
if (acpi_disabled)
1197
goto err;
1198
1199
if (erst_disable) {
1200
pr_info(
1201
"Error Record Serialization Table (ERST) support is disabled.\n");
1202
goto err;
1203
}
1204
1205
status = acpi_get_table(ACPI_SIG_ERST, 0,
1206
(struct acpi_table_header **)&erst_tab);
1207
if (status == AE_NOT_FOUND)
1208
goto err;
1209
else if (ACPI_FAILURE(status)) {
1210
const char *msg = acpi_format_exception(status);
1211
pr_err("Failed to get table, %s\n", msg);
1212
rc = -EINVAL;
1213
goto err;
1214
}
1215
1216
rc = erst_check_table(erst_tab);
1217
if (rc) {
1218
pr_err(FW_BUG "ERST table is invalid.\n");
1219
goto err_put_erst_tab;
1220
}
1221
1222
apei_resources_init(&erst_resources);
1223
erst_exec_ctx_init(&ctx);
1224
rc = apei_exec_collect_resources(&ctx, &erst_resources);
1225
if (rc)
1226
goto err_fini;
1227
rc = apei_resources_request(&erst_resources, "APEI ERST");
1228
if (rc)
1229
goto err_fini;
1230
rc = apei_exec_pre_map_gars(&ctx);
1231
if (rc)
1232
goto err_release;
1233
rc = erst_get_erange(&erst_erange);
1234
if (rc) {
1235
if (rc == -ENODEV)
1236
pr_info(
1237
"The corresponding hardware device or firmware implementation "
1238
"is not available.\n");
1239
else
1240
pr_err("Failed to get Error Log Address Range.\n");
1241
goto err_unmap_reg;
1242
}
1243
1244
r = request_mem_region(erst_erange.base, erst_erange.size, "APEI ERST");
1245
if (!r) {
1246
pr_err("Can not request [mem %#010llx-%#010llx] for ERST.\n",
1247
(unsigned long long)erst_erange.base,
1248
(unsigned long long)erst_erange.base + erst_erange.size - 1);
1249
rc = -EIO;
1250
goto err_unmap_reg;
1251
}
1252
rc = -ENOMEM;
1253
erst_erange.vaddr = ioremap_cache(erst_erange.base,
1254
erst_erange.size);
1255
if (!erst_erange.vaddr)
1256
goto err_release_erange;
1257
1258
pr_info(
1259
"Error Record Serialization Table (ERST) support is initialized.\n");
1260
1261
buf = kmalloc(erst_erange.size, GFP_KERNEL);
1262
if (buf) {
1263
erst_info.buf = buf + sizeof(struct cper_pstore_record);
1264
erst_info.bufsize = erst_erange.size -
1265
sizeof(struct cper_pstore_record);
1266
rc = pstore_register(&erst_info);
1267
if (rc) {
1268
if (rc != -EPERM)
1269
pr_info(
1270
"Could not register with persistent store.\n");
1271
erst_info.buf = NULL;
1272
erst_info.bufsize = 0;
1273
kfree(buf);
1274
}
1275
} else
1276
pr_err(
1277
"Failed to allocate %lld bytes for persistent store error log.\n",
1278
erst_erange.size);
1279
1280
/* Cleanup ERST Resources */
1281
apei_resources_fini(&erst_resources);
1282
1283
return 0;
1284
1285
err_release_erange:
1286
release_mem_region(erst_erange.base, erst_erange.size);
1287
err_unmap_reg:
1288
apei_exec_post_unmap_gars(&ctx);
1289
err_release:
1290
apei_resources_release(&erst_resources);
1291
err_fini:
1292
apei_resources_fini(&erst_resources);
1293
err_put_erst_tab:
1294
acpi_put_table((struct acpi_table_header *)erst_tab);
1295
err:
1296
erst_disable = 1;
1297
return rc;
1298
}
1299
1300
device_initcall(erst_init);
1301
1302