1 /*
2 * APEI Error Record Serialization Table support
3 *
4 * ERST is a way provided by APEI to save and retrieve hardware error
5 * information to and from a persistent store.
6 *
7 * For more information about ERST, please refer to ACPI Specification
8 * version 4.0, section 17.4.
9 *
10 * This feature is ported from linux acpi tree
11 * Copyright 2010 Intel Corp.
12 * Author: Huang Ying <ying.huang@intel.com>
13 * Ported by: Liu, Jinsong <jinsong.liu@intel.com>
14 *
15 * This program is free software; you can redistribute it and/or
16 * modify it under the terms of the GNU General Public License version
17 * 2 as published by the Free Software Foundation.
18 *
19 * This program is distributed in the hope that it will be useful,
20 * but WITHOUT ANY WARRANTY; without even the implied warranty of
21 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
22 * GNU General Public License for more details.
23 *
24 * You should have received a copy of the GNU General Public License
25 * along with this program; If not, see <http://www.gnu.org/licenses/>.
26 */
27
28 #include <xen/kernel.h>
29 #include <xen/errno.h>
30 #include <xen/delay.h>
31 #include <xen/init.h>
32 #include <xen/string.h>
33 #include <xen/types.h>
34 #include <xen/spinlock.h>
35 #include <xen/cper.h>
36 #include <asm/fixmap.h>
37 #include <asm/io.h>
38 #include <acpi/acpi.h>
39 #include <acpi/apei.h>
40
41 #include "apei-internal.h"
42
43 /* ERST command status */
44 #define ERST_STATUS_SUCCESS 0x0
45 #define ERST_STATUS_NOT_ENOUGH_SPACE 0x1
46 #define ERST_STATUS_HARDWARE_NOT_AVAILABLE 0x2
47 #define ERST_STATUS_FAILED 0x3
48 #define ERST_STATUS_RECORD_STORE_EMPTY 0x4
49 #define ERST_STATUS_RECORD_NOT_FOUND 0x5
50
51 #define ERST_TAB_ENTRY(tab) \
52 ((struct acpi_whea_header *)((char *)(tab) + \
53 sizeof(struct acpi_table_erst)))
54
55 #define SPIN_UNIT 1 /* 1us */
56 /* Firmware should respond within 1 miliseconds */
57 #define FIRMWARE_TIMEOUT (1 * 1000)
58 #define FIRMWARE_MAX_STALL 50 /* 50us */
59
60 static struct acpi_table_erst *__read_mostly erst_tab;
61 static bool_t __read_mostly erst_enabled;
62
63 /* ERST Error Log Address Range atrributes */
64 #define ERST_RANGE_RESERVED 0x0001
65 #define ERST_RANGE_NVRAM 0x0002
66 #define ERST_RANGE_SLOW 0x0004
67
68 /*
69 * ERST Error Log Address Range, used as buffer for reading/writing
70 * error records.
71 */
72 static struct erst_erange {
73 u64 base;
74 u64 size;
75 void __iomem *vaddr;
76 u32 attr;
77 } erst_erange;
78
79 /*
80 * Prevent ERST interpreter to run simultaneously, because the
81 * corresponding firmware implementation may not work properly when
82 * invoked simultaneously.
83 *
84 * It is used to provide exclusive accessing for ERST Error Log
85 * Address Range too.
86 */
87 static DEFINE_SPINLOCK(erst_lock);
88
erst_errno(int command_status)89 static inline int erst_errno(int command_status)
90 {
91 switch (command_status) {
92 case ERST_STATUS_SUCCESS:
93 return 0;
94 case ERST_STATUS_HARDWARE_NOT_AVAILABLE:
95 return -ENODEV;
96 case ERST_STATUS_NOT_ENOUGH_SPACE:
97 return -ENOSPC;
98 case ERST_STATUS_RECORD_STORE_EMPTY:
99 case ERST_STATUS_RECORD_NOT_FOUND:
100 return -ENOENT;
101 default:
102 return -EINVAL;
103 }
104 }
105
erst_timedout(u64 * t,u64 spin_unit)106 static int erst_timedout(u64 *t, u64 spin_unit)
107 {
108 if ((s64)*t < spin_unit) {
109 printk(XENLOG_WARNING "Firmware does not respond in time\n");
110 return 1;
111 }
112 *t -= spin_unit;
113 udelay(spin_unit);
114 return 0;
115 }
116
erst_exec_load_var1(struct apei_exec_context * ctx,struct acpi_whea_header * entry)117 static int erst_exec_load_var1(struct apei_exec_context *ctx,
118 struct acpi_whea_header *entry)
119 {
120 return __apei_exec_read_register(entry, &ctx->var1);
121 }
122
erst_exec_load_var2(struct apei_exec_context * ctx,struct acpi_whea_header * entry)123 static int erst_exec_load_var2(struct apei_exec_context *ctx,
124 struct acpi_whea_header *entry)
125 {
126 return __apei_exec_read_register(entry, &ctx->var2);
127 }
128
erst_exec_store_var1(struct apei_exec_context * ctx,struct acpi_whea_header * entry)129 static int erst_exec_store_var1(struct apei_exec_context *ctx,
130 struct acpi_whea_header *entry)
131 {
132 return __apei_exec_write_register(entry, ctx->var1);
133 }
134
erst_exec_add(struct apei_exec_context * ctx,struct acpi_whea_header * entry)135 static int erst_exec_add(struct apei_exec_context *ctx,
136 struct acpi_whea_header *entry)
137 {
138 ctx->var1 += ctx->var2;
139 return 0;
140 }
141
erst_exec_subtract(struct apei_exec_context * ctx,struct acpi_whea_header * entry)142 static int erst_exec_subtract(struct apei_exec_context *ctx,
143 struct acpi_whea_header *entry)
144 {
145 ctx->var1 -= ctx->var2;
146 return 0;
147 }
148
erst_exec_add_value(struct apei_exec_context * ctx,struct acpi_whea_header * entry)149 static int erst_exec_add_value(struct apei_exec_context *ctx,
150 struct acpi_whea_header *entry)
151 {
152 int rc;
153 u64 val;
154
155 rc = __apei_exec_read_register(entry, &val);
156 if (rc)
157 return rc;
158 val += ctx->value;
159 rc = __apei_exec_write_register(entry, val);
160 return rc;
161 }
162
erst_exec_subtract_value(struct apei_exec_context * ctx,struct acpi_whea_header * entry)163 static int erst_exec_subtract_value(struct apei_exec_context *ctx,
164 struct acpi_whea_header *entry)
165 {
166 int rc;
167 u64 val;
168
169 rc = __apei_exec_read_register(entry, &val);
170 if (rc)
171 return rc;
172 val -= ctx->value;
173 rc = __apei_exec_write_register(entry, val);
174 return rc;
175 }
176
erst_exec_stall(struct apei_exec_context * ctx,struct acpi_whea_header * entry)177 static int erst_exec_stall(struct apei_exec_context *ctx,
178 struct acpi_whea_header *entry)
179 {
180 udelay((ctx->var1 > FIRMWARE_MAX_STALL) ?
181 FIRMWARE_MAX_STALL :
182 ctx->var1);
183 return 0;
184 }
185
erst_exec_stall_while_true(struct apei_exec_context * ctx,struct acpi_whea_header * entry)186 static int erst_exec_stall_while_true(struct apei_exec_context *ctx,
187 struct acpi_whea_header *entry)
188 {
189 int rc;
190 u64 val;
191 u64 timeout = FIRMWARE_TIMEOUT;
192 u64 stall_time = (ctx->var1 > FIRMWARE_MAX_STALL) ?
193 FIRMWARE_MAX_STALL :
194 ctx->var1;
195
196 for (;;) {
197 rc = __apei_exec_read_register(entry, &val);
198 if (rc)
199 return rc;
200 if (val != ctx->value)
201 break;
202 if (erst_timedout(&timeout, stall_time))
203 return -EIO;
204 }
205 return 0;
206 }
207
erst_exec_skip_next_instruction_if_true(struct apei_exec_context * ctx,struct acpi_whea_header * entry)208 static int erst_exec_skip_next_instruction_if_true(
209 struct apei_exec_context *ctx,
210 struct acpi_whea_header *entry)
211 {
212 int rc;
213 u64 val;
214
215 rc = __apei_exec_read_register(entry, &val);
216 if (rc)
217 return rc;
218 if (val == ctx->value) {
219 ctx->ip += 2;
220 return APEI_EXEC_SET_IP;
221 }
222
223 return 0;
224 }
225
erst_exec_goto(struct apei_exec_context * ctx,struct acpi_whea_header * entry)226 static int erst_exec_goto(struct apei_exec_context *ctx,
227 struct acpi_whea_header *entry)
228 {
229 ctx->ip = ctx->value;
230 return APEI_EXEC_SET_IP;
231 }
232
erst_exec_set_src_address_base(struct apei_exec_context * ctx,struct acpi_whea_header * entry)233 static int erst_exec_set_src_address_base(struct apei_exec_context *ctx,
234 struct acpi_whea_header *entry)
235 {
236 return __apei_exec_read_register(entry, &ctx->src_base);
237 }
238
erst_exec_set_dst_address_base(struct apei_exec_context * ctx,struct acpi_whea_header * entry)239 static int erst_exec_set_dst_address_base(struct apei_exec_context *ctx,
240 struct acpi_whea_header *entry)
241 {
242 return __apei_exec_read_register(entry, &ctx->dst_base);
243 }
244
erst_exec_move_data(struct apei_exec_context * ctx,struct acpi_whea_header * entry)245 static int erst_exec_move_data(struct apei_exec_context *ctx,
246 struct acpi_whea_header *entry)
247 {
248 int rc;
249 u64 offset;
250 void *src, *dst;
251
252 /* ioremap does not work in interrupt context */
253 if (in_irq()) {
254 printk(KERN_WARNING
255 "MOVE_DATA cannot be used in interrupt context\n");
256 return -EBUSY;
257 }
258
259 rc = __apei_exec_read_register(entry, &offset);
260 if (rc)
261 return rc;
262
263 src = ioremap(ctx->src_base + offset, ctx->var2);
264 if (!src)
265 return -ENOMEM;
266
267 dst = ioremap(ctx->dst_base + offset, ctx->var2);
268 if (dst) {
269 memmove(dst, src, ctx->var2);
270 iounmap(dst);
271 } else
272 rc = -ENOMEM;
273
274 iounmap(src);
275
276 return rc;
277 }
278
279 static struct apei_exec_ins_type erst_ins_type[] = {
280 [ACPI_ERST_READ_REGISTER] = {
281 .flags = APEI_EXEC_INS_ACCESS_REGISTER,
282 .run = apei_exec_read_register,
283 },
284 [ACPI_ERST_READ_REGISTER_VALUE] = {
285 .flags = APEI_EXEC_INS_ACCESS_REGISTER,
286 .run = apei_exec_read_register_value,
287 },
288 [ACPI_ERST_WRITE_REGISTER] = {
289 .flags = APEI_EXEC_INS_ACCESS_REGISTER,
290 .run = apei_exec_write_register,
291 },
292 [ACPI_ERST_WRITE_REGISTER_VALUE] = {
293 .flags = APEI_EXEC_INS_ACCESS_REGISTER,
294 .run = apei_exec_write_register_value,
295 },
296 [ACPI_ERST_NOOP] = {
297 .flags = 0,
298 .run = apei_exec_noop,
299 },
300 [ACPI_ERST_LOAD_VAR1] = {
301 .flags = APEI_EXEC_INS_ACCESS_REGISTER,
302 .run = erst_exec_load_var1,
303 },
304 [ACPI_ERST_LOAD_VAR2] = {
305 .flags = APEI_EXEC_INS_ACCESS_REGISTER,
306 .run = erst_exec_load_var2,
307 },
308 [ACPI_ERST_STORE_VAR1] = {
309 .flags = APEI_EXEC_INS_ACCESS_REGISTER,
310 .run = erst_exec_store_var1,
311 },
312 [ACPI_ERST_ADD] = {
313 .flags = 0,
314 .run = erst_exec_add,
315 },
316 [ACPI_ERST_SUBTRACT] = {
317 .flags = 0,
318 .run = erst_exec_subtract,
319 },
320 [ACPI_ERST_ADD_VALUE] = {
321 .flags = APEI_EXEC_INS_ACCESS_REGISTER,
322 .run = erst_exec_add_value,
323 },
324 [ACPI_ERST_SUBTRACT_VALUE] = {
325 .flags = APEI_EXEC_INS_ACCESS_REGISTER,
326 .run = erst_exec_subtract_value,
327 },
328 [ACPI_ERST_STALL] = {
329 .flags = 0,
330 .run = erst_exec_stall,
331 },
332 [ACPI_ERST_STALL_WHILE_TRUE] = {
333 .flags = APEI_EXEC_INS_ACCESS_REGISTER,
334 .run = erst_exec_stall_while_true,
335 },
336 [ACPI_ERST_SKIP_NEXT_IF_TRUE] = {
337 .flags = APEI_EXEC_INS_ACCESS_REGISTER,
338 .run = erst_exec_skip_next_instruction_if_true,
339 },
340 [ACPI_ERST_GOTO] = {
341 .flags = 0,
342 .run = erst_exec_goto,
343 },
344 [ACPI_ERST_SET_SRC_ADDRESS_BASE] = {
345 .flags = APEI_EXEC_INS_ACCESS_REGISTER,
346 .run = erst_exec_set_src_address_base,
347 },
348 [ACPI_ERST_SET_DST_ADDRESS_BASE] = {
349 .flags = APEI_EXEC_INS_ACCESS_REGISTER,
350 .run = erst_exec_set_dst_address_base,
351 },
352 [ACPI_ERST_MOVE_DATA] = {
353 .flags = APEI_EXEC_INS_ACCESS_REGISTER,
354 .run = erst_exec_move_data,
355 },
356 };
357
erst_exec_ctx_init(struct apei_exec_context * ctx)358 static inline void erst_exec_ctx_init(struct apei_exec_context *ctx)
359 {
360 apei_exec_ctx_init(ctx, erst_ins_type, ARRAY_SIZE(erst_ins_type),
361 ERST_TAB_ENTRY(erst_tab), erst_tab->entries);
362 }
363
erst_get_erange(struct erst_erange * range)364 static int erst_get_erange(struct erst_erange *range)
365 {
366 struct apei_exec_context ctx;
367 int rc;
368
369 erst_exec_ctx_init(&ctx);
370 rc = apei_exec_run(&ctx, ACPI_ERST_GET_ERROR_RANGE);
371 if (rc)
372 return rc;
373 range->base = apei_exec_ctx_get_output(&ctx);
374 rc = apei_exec_run(&ctx, ACPI_ERST_GET_ERROR_LENGTH);
375 if (rc)
376 return rc;
377 range->size = apei_exec_ctx_get_output(&ctx);
378 rc = apei_exec_run(&ctx, ACPI_ERST_GET_ERROR_ATTRIBUTES);
379 if (rc)
380 return rc;
381 range->attr = apei_exec_ctx_get_output(&ctx);
382
383 return 0;
384 }
385
386 #ifndef NDEBUG /* currently dead code */
387
__erst_get_record_count(void)388 static ssize_t __erst_get_record_count(void)
389 {
390 struct apei_exec_context ctx;
391 int rc;
392 u64 output;
393 ssize_t count;
394
395 erst_exec_ctx_init(&ctx);
396 rc = apei_exec_run(&ctx, ACPI_ERST_GET_RECORD_COUNT);
397 if (rc)
398 return rc;
399 count = output = apei_exec_ctx_get_output(&ctx);
400 return count >= 0 && count == output ? count : -ERANGE;
401 }
402
erst_get_record_count(void)403 ssize_t erst_get_record_count(void)
404 {
405 ssize_t count;
406 unsigned long flags;
407
408 if (!erst_enabled)
409 return -ENODEV;
410
411 spin_lock_irqsave(&erst_lock, flags);
412 count = __erst_get_record_count();
413 spin_unlock_irqrestore(&erst_lock, flags);
414
415 return count;
416 }
417
__erst_get_next_record_id(u64 * record_id)418 static int __erst_get_next_record_id(u64 *record_id)
419 {
420 struct apei_exec_context ctx;
421 int rc;
422
423 erst_exec_ctx_init(&ctx);
424 rc = apei_exec_run(&ctx, ACPI_ERST_GET_RECORD_ID);
425 if (rc)
426 return rc;
427 *record_id = apei_exec_ctx_get_output(&ctx);
428
429 return 0;
430 }
431
432 /*
433 * Get the record ID of an existing error record on the persistent
434 * storage. If there is no error record on the persistent storage, the
435 * returned record_id is APEI_ERST_INVALID_RECORD_ID.
436 */
erst_get_next_record_id(u64 * record_id)437 int erst_get_next_record_id(u64 *record_id)
438 {
439 int rc;
440 unsigned long flags;
441
442 if (!erst_enabled)
443 return -ENODEV;
444
445 spin_lock_irqsave(&erst_lock, flags);
446 rc = __erst_get_next_record_id(record_id);
447 spin_unlock_irqrestore(&erst_lock, flags);
448
449 return rc;
450 }
451
452 #endif /* currently dead code */
453
__erst_write_to_storage(u64 offset)454 static int __erst_write_to_storage(u64 offset)
455 {
456 struct apei_exec_context ctx;
457 u64 timeout = FIRMWARE_TIMEOUT;
458 u64 val;
459 int rc;
460
461 erst_exec_ctx_init(&ctx);
462 rc = apei_exec_run(&ctx, ACPI_ERST_BEGIN_WRITE);
463 if (rc)
464 return rc;
465 apei_exec_ctx_set_input(&ctx, offset);
466 rc = apei_exec_run(&ctx, ACPI_ERST_SET_RECORD_OFFSET);
467 if (rc)
468 return rc;
469 rc = apei_exec_run(&ctx, ACPI_ERST_EXECUTE_OPERATION);
470 if (rc)
471 return rc;
472 for (;;) {
473 rc = apei_exec_run(&ctx, ACPI_ERST_CHECK_BUSY_STATUS);
474 if (rc)
475 return rc;
476 val = apei_exec_ctx_get_output(&ctx);
477 if (!val)
478 break;
479 if (erst_timedout(&timeout, SPIN_UNIT))
480 return -EIO;
481 }
482 rc = apei_exec_run(&ctx, ACPI_ERST_GET_COMMAND_STATUS);
483 if (rc)
484 return rc;
485 val = apei_exec_ctx_get_output(&ctx);
486 rc = apei_exec_run(&ctx, ACPI_ERST_END);
487 if (rc)
488 return rc;
489
490 return erst_errno(val);
491 }
492
493 #ifndef NDEBUG /* currently dead code */
494
__erst_read_from_storage(u64 record_id,u64 offset)495 static int __erst_read_from_storage(u64 record_id, u64 offset)
496 {
497 struct apei_exec_context ctx;
498 u64 timeout = FIRMWARE_TIMEOUT;
499 u64 val;
500 int rc;
501
502 erst_exec_ctx_init(&ctx);
503 rc = apei_exec_run(&ctx, ACPI_ERST_BEGIN_READ);
504 if (rc)
505 return rc;
506 apei_exec_ctx_set_input(&ctx, offset);
507 rc = apei_exec_run(&ctx, ACPI_ERST_SET_RECORD_OFFSET);
508 if (rc)
509 return rc;
510 apei_exec_ctx_set_input(&ctx, record_id);
511 rc = apei_exec_run(&ctx, ACPI_ERST_SET_RECORD_ID);
512 if (rc)
513 return rc;
514 rc = apei_exec_run(&ctx, ACPI_ERST_EXECUTE_OPERATION);
515 if (rc)
516 return rc;
517 for (;;) {
518 rc = apei_exec_run(&ctx, ACPI_ERST_CHECK_BUSY_STATUS);
519 if (rc)
520 return rc;
521 val = apei_exec_ctx_get_output(&ctx);
522 if (!val)
523 break;
524 if (erst_timedout(&timeout, SPIN_UNIT))
525 return -EIO;
526 };
527 rc = apei_exec_run(&ctx, ACPI_ERST_GET_COMMAND_STATUS);
528 if (rc)
529 return rc;
530 val = apei_exec_ctx_get_output(&ctx);
531 rc = apei_exec_run(&ctx, ACPI_ERST_END);
532 if (rc)
533 return rc;
534
535 return erst_errno(val);
536 }
537
__erst_clear_from_storage(u64 record_id)538 static int __erst_clear_from_storage(u64 record_id)
539 {
540 struct apei_exec_context ctx;
541 u64 timeout = FIRMWARE_TIMEOUT;
542 u64 val;
543 int rc;
544
545 erst_exec_ctx_init(&ctx);
546 rc = apei_exec_run(&ctx, ACPI_ERST_BEGIN_CLEAR);
547 if (rc)
548 return rc;
549 apei_exec_ctx_set_input(&ctx, record_id);
550 rc = apei_exec_run(&ctx, ACPI_ERST_SET_RECORD_ID);
551 if (rc)
552 return rc;
553 rc = apei_exec_run(&ctx, ACPI_ERST_EXECUTE_OPERATION);
554 if (rc)
555 return rc;
556 for (;;) {
557 rc = apei_exec_run(&ctx, ACPI_ERST_CHECK_BUSY_STATUS);
558 if (rc)
559 return rc;
560 val = apei_exec_ctx_get_output(&ctx);
561 if (!val)
562 break;
563 if (erst_timedout(&timeout, SPIN_UNIT))
564 return -EIO;
565 }
566 rc = apei_exec_run(&ctx, ACPI_ERST_GET_COMMAND_STATUS);
567 if (rc)
568 return rc;
569 val = apei_exec_ctx_get_output(&ctx);
570 rc = apei_exec_run(&ctx, ACPI_ERST_END);
571 if (rc)
572 return rc;
573
574 return erst_errno(val);
575 }
576
577 #endif /* currently dead code */
578
579 /* NVRAM ERST Error Log Address Range is not supported yet */
__erst_write_to_nvram(const struct cper_record_header * record)580 static int __erst_write_to_nvram(const struct cper_record_header *record)
581 {
582 /* do not print message, because printk is not safe for NMI */
583 return -ENOSYS;
584 }
585
586 #ifndef NDEBUG /* currently dead code */
587
__erst_read_to_erange_from_nvram(u64 record_id,u64 * offset)588 static int __erst_read_to_erange_from_nvram(u64 record_id, u64 *offset)
589 {
590 printk(KERN_WARNING
591 "NVRAM ERST Log Address Range is not implemented yet\n");
592 return -ENOSYS;
593 }
594
__erst_clear_from_nvram(u64 record_id)595 static int __erst_clear_from_nvram(u64 record_id)
596 {
597 printk(KERN_WARNING
598 "NVRAM ERST Log Address Range is not implemented yet\n");
599 return -ENOSYS;
600 }
601
602 #endif /* currently dead code */
603
erst_write(const struct cper_record_header * record)604 int erst_write(const struct cper_record_header *record)
605 {
606 int rc;
607 unsigned long flags;
608 struct cper_record_header *rcd_erange;
609
610 if (!record)
611 return -EINVAL;
612
613 if (!erst_enabled)
614 return -ENODEV;
615
616 if (memcmp(record->signature, CPER_SIG_RECORD, CPER_SIG_SIZE))
617 return -EINVAL;
618
619 if (erst_erange.attr & ERST_RANGE_NVRAM) {
620 if (!spin_trylock_irqsave(&erst_lock, flags))
621 return -EBUSY;
622 rc = __erst_write_to_nvram(record);
623 spin_unlock_irqrestore(&erst_lock, flags);
624 return rc;
625 }
626
627 if (record->record_length > erst_erange.size)
628 return -EINVAL;
629
630 if (!spin_trylock_irqsave(&erst_lock, flags))
631 return -EBUSY;
632 memcpy(erst_erange.vaddr, record, record->record_length);
633 rcd_erange = erst_erange.vaddr;
634 /* signature for serialization system */
635 memcpy(&rcd_erange->persistence_information, "ER", 2);
636
637 rc = __erst_write_to_storage(0);
638 spin_unlock_irqrestore(&erst_lock, flags);
639
640 return rc;
641 }
642
643 #ifndef NDEBUG /* currently dead code */
644
__erst_read_to_erange(u64 record_id,u64 * offset)645 static int __erst_read_to_erange(u64 record_id, u64 *offset)
646 {
647 int rc;
648
649 if (erst_erange.attr & ERST_RANGE_NVRAM)
650 return __erst_read_to_erange_from_nvram(
651 record_id, offset);
652
653 rc = __erst_read_from_storage(record_id, 0);
654 if (rc)
655 return rc;
656 *offset = 0;
657
658 return 0;
659 }
660
__erst_read(u64 record_id,struct cper_record_header * record,size_t buflen)661 static ssize_t __erst_read(u64 record_id, struct cper_record_header *record,
662 size_t buflen)
663 {
664 int rc;
665 u64 offset;
666 ssize_t len;
667 struct cper_record_header *rcd_tmp;
668
669 rc = __erst_read_to_erange(record_id, &offset);
670 if (rc)
671 return rc;
672 rcd_tmp = erst_erange.vaddr + offset;
673 if (rcd_tmp->record_length > buflen)
674 return -ENOBUFS;
675 len = rcd_tmp->record_length;
676 if (len < 0)
677 return -ERANGE;
678 memcpy(record, rcd_tmp, len);
679
680 return len;
681 }
682
683 /*
684 * If return value > buflen, the buffer size is not big enough,
685 * else if return value < 0, something goes wrong,
686 * else everything is OK, and return value is record length
687 */
erst_read(u64 record_id,struct cper_record_header * record,size_t buflen)688 ssize_t erst_read(u64 record_id, struct cper_record_header *record,
689 size_t buflen)
690 {
691 ssize_t len;
692 unsigned long flags;
693
694 if (!erst_enabled)
695 return -ENODEV;
696
697 spin_lock_irqsave(&erst_lock, flags);
698 len = __erst_read(record_id, record, buflen);
699 spin_unlock_irqrestore(&erst_lock, flags);
700 return len;
701 }
702
703 /*
704 * If return value > buflen, the buffer size is not big enough,
705 * else if return value = 0, there is no more record to read,
706 * else if return value < 0, something goes wrong,
707 * else everything is OK, and return value is record length
708 */
erst_read_next(struct cper_record_header * record,size_t buflen)709 ssize_t erst_read_next(struct cper_record_header *record, size_t buflen)
710 {
711 int rc;
712 ssize_t len;
713 unsigned long flags;
714 u64 record_id;
715
716 if (!erst_enabled)
717 return -ENODEV;
718
719 spin_lock_irqsave(&erst_lock, flags);
720 rc = __erst_get_next_record_id(&record_id);
721 if (rc) {
722 spin_unlock_irqrestore(&erst_lock, flags);
723 return rc;
724 }
725 /* no more record */
726 if (record_id == APEI_ERST_INVALID_RECORD_ID) {
727 spin_unlock_irqrestore(&erst_lock, flags);
728 return 0;
729 }
730
731 len = __erst_read(record_id, record, buflen);
732 spin_unlock_irqrestore(&erst_lock, flags);
733
734 return len;
735 }
736
erst_clear(u64 record_id)737 int erst_clear(u64 record_id)
738 {
739 int rc;
740 unsigned long flags;
741
742 if (!erst_enabled)
743 return -ENODEV;
744
745 spin_lock_irqsave(&erst_lock, flags);
746 if (erst_erange.attr & ERST_RANGE_NVRAM)
747 rc = __erst_clear_from_nvram(record_id);
748 else
749 rc = __erst_clear_from_storage(record_id);
750 spin_unlock_irqrestore(&erst_lock, flags);
751
752 return rc;
753 }
754
755 #endif /* currently dead code */
756
erst_check_table(struct acpi_table_erst * erst_tab)757 static int __init erst_check_table(struct acpi_table_erst *erst_tab)
758 {
759 if (erst_tab->header.length < sizeof(*erst_tab))
760 return -EINVAL;
761
762 switch (erst_tab->header_length) {
763 case sizeof(*erst_tab) - sizeof(erst_tab->header):
764 /*
765 * While invalid per specification, there are (early?) systems
766 * indicating the full header size here, so accept that value too.
767 */
768 case sizeof(*erst_tab):
769 break;
770 default:
771 return -EINVAL;
772 }
773
774 if (erst_tab->entries !=
775 (erst_tab->header.length - sizeof(*erst_tab)) /
776 sizeof(struct acpi_erst_entry))
777 return -EINVAL;
778
779 return 0;
780 }
781
erst_init(void)782 int __init erst_init(void)
783 {
784 int rc = 0;
785 acpi_status status;
786 acpi_physical_address erst_addr;
787 acpi_native_uint erst_len;
788 struct apei_exec_context ctx;
789
790 if (acpi_disabled)
791 return -ENODEV;
792
793 status = acpi_get_table_phys(ACPI_SIG_ERST, 0, &erst_addr, &erst_len);
794 if (status == AE_NOT_FOUND)
795 return -ENODEV;
796
797 if (ACPI_FAILURE(status)) {
798 const char *msg = acpi_format_exception(status);
799 printk(KERN_WARNING "Failed to get ERST table: %s\n", msg);
800 return -EINVAL;
801 }
802 map_pages_to_xen((unsigned long)__va(erst_addr), maddr_to_mfn(erst_addr),
803 PFN_UP(erst_addr + erst_len) - PFN_DOWN(erst_addr),
804 PAGE_HYPERVISOR);
805 erst_tab = __va(erst_addr);
806
807 rc = erst_check_table(erst_tab);
808 if (rc) {
809 printk(KERN_ERR "ERST table is invalid\n");
810 return rc;
811 }
812
813 erst_exec_ctx_init(&ctx);
814 rc = apei_exec_pre_map_gars(&ctx);
815 if (rc)
816 return rc;
817
818 rc = erst_get_erange(&erst_erange);
819 if (rc) {
820 if (rc == -ENODEV)
821 printk(KERN_INFO
822 "The corresponding hardware device or firmware "
823 "implementation is not available.\n");
824 else
825 printk(KERN_ERR
826 "Failed to get Error Log Address Range.\n");
827 goto err_unmap_reg;
828 }
829
830 erst_erange.vaddr = apei_pre_map(erst_erange.base, erst_erange.size);
831 if (!erst_erange.vaddr) {
832 rc = -ENOMEM;
833 goto err_unmap_reg;
834 }
835
836 printk(KERN_INFO "Xen ERST support is initialized.\n");
837 erst_enabled = 1;
838
839 return 0;
840
841 err_unmap_reg:
842 apei_exec_post_unmap_gars(&ctx);
843 return rc;
844 }
845