xref: /openbmc/linux/drivers/acpi/apei/erst.c (revision 980533b0)
1 /*
2  * APEI Error Record Serialization Table support
3  *
4  * ERST is a way provided by APEI to save and retrieve hardware error
5  * infomation 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  * Copyright 2010 Intel Corp.
11  *   Author: Huang Ying <ying.huang@intel.com>
12  *
13  * This program is free software; you can redistribute it and/or
14  * modify it under the terms of the GNU General Public License version
15  * 2 as published by the Free Software Foundation.
16  *
17  * This program is distributed in the hope that it will be useful,
18  * but WITHOUT ANY WARRANTY; without even the implied warranty of
19  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
20  * GNU General Public License for more details.
21  *
22  * You should have received a copy of the GNU General Public License
23  * along with this program; if not, write to the Free Software
24  * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
25  */
26 
27 #include <linux/kernel.h>
28 #include <linux/module.h>
29 #include <linux/init.h>
30 #include <linux/delay.h>
31 #include <linux/io.h>
32 #include <linux/acpi.h>
33 #include <linux/uaccess.h>
34 #include <linux/cper.h>
35 #include <linux/nmi.h>
36 #include <acpi/apei.h>
37 
38 #include "apei-internal.h"
39 
40 #define ERST_PFX "ERST: "
41 
42 /* ERST command status */
43 #define ERST_STATUS_SUCCESS			0x0
44 #define ERST_STATUS_NOT_ENOUGH_SPACE		0x1
45 #define ERST_STATUS_HARDWARE_NOT_AVAILABLE	0x2
46 #define ERST_STATUS_FAILED			0x3
47 #define ERST_STATUS_RECORD_STORE_EMPTY		0x4
48 #define ERST_STATUS_RECORD_NOT_FOUND		0x5
49 
50 #define ERST_TAB_ENTRY(tab)						\
51 	((struct acpi_whea_header *)((char *)(tab) +			\
52 				     sizeof(struct acpi_table_erst)))
53 
54 #define SPIN_UNIT		100			/* 100ns */
55 /* Firmware should respond within 1 miliseconds */
56 #define FIRMWARE_TIMEOUT	(1 * NSEC_PER_MSEC)
57 #define FIRMWARE_MAX_STALL	50			/* 50us */
58 
59 int erst_disable;
60 EXPORT_SYMBOL_GPL(erst_disable);
61 
62 static struct acpi_table_erst *erst_tab;
63 
64 /* ERST Error Log Address Range atrributes */
65 #define ERST_RANGE_RESERVED	0x0001
66 #define ERST_RANGE_NVRAM	0x0002
67 #define ERST_RANGE_SLOW		0x0004
68 
69 /*
70  * ERST Error Log Address Range, used as buffer for reading/writing
71  * error records.
72  */
73 static struct erst_erange {
74 	u64 base;
75 	u64 size;
76 	void __iomem *vaddr;
77 	u32 attr;
78 } erst_erange;
79 
80 /*
81  * Prevent ERST interpreter to run simultaneously, because the
82  * corresponding firmware implementation may not work properly when
83  * invoked simultaneously.
84  *
85  * It is used to provide exclusive accessing for ERST Error Log
86  * Address Range too.
87  */
88 static DEFINE_SPINLOCK(erst_lock);
89 
90 static inline int erst_errno(int command_status)
91 {
92 	switch (command_status) {
93 	case ERST_STATUS_SUCCESS:
94 		return 0;
95 	case ERST_STATUS_HARDWARE_NOT_AVAILABLE:
96 		return -ENODEV;
97 	case ERST_STATUS_NOT_ENOUGH_SPACE:
98 		return -ENOSPC;
99 	case ERST_STATUS_RECORD_STORE_EMPTY:
100 	case ERST_STATUS_RECORD_NOT_FOUND:
101 		return -ENOENT;
102 	default:
103 		return -EINVAL;
104 	}
105 }
106 
107 static int erst_timedout(u64 *t, u64 spin_unit)
108 {
109 	if ((s64)*t < spin_unit) {
110 		pr_warning(FW_WARN ERST_PFX
111 			   "Firmware does not respond in time\n");
112 		return 1;
113 	}
114 	*t -= spin_unit;
115 	ndelay(spin_unit);
116 	touch_nmi_watchdog();
117 	return 0;
118 }
119 
120 static int erst_exec_load_var1(struct apei_exec_context *ctx,
121 			       struct acpi_whea_header *entry)
122 {
123 	return __apei_exec_read_register(entry, &ctx->var1);
124 }
125 
126 static int erst_exec_load_var2(struct apei_exec_context *ctx,
127 			       struct acpi_whea_header *entry)
128 {
129 	return __apei_exec_read_register(entry, &ctx->var2);
130 }
131 
132 static int erst_exec_store_var1(struct apei_exec_context *ctx,
133 				struct acpi_whea_header *entry)
134 {
135 	return __apei_exec_write_register(entry, ctx->var1);
136 }
137 
138 static int erst_exec_add(struct apei_exec_context *ctx,
139 			 struct acpi_whea_header *entry)
140 {
141 	ctx->var1 += ctx->var2;
142 	return 0;
143 }
144 
145 static int erst_exec_subtract(struct apei_exec_context *ctx,
146 			      struct acpi_whea_header *entry)
147 {
148 	ctx->var1 -= ctx->var2;
149 	return 0;
150 }
151 
152 static int erst_exec_add_value(struct apei_exec_context *ctx,
153 			       struct acpi_whea_header *entry)
154 {
155 	int rc;
156 	u64 val;
157 
158 	rc = __apei_exec_read_register(entry, &val);
159 	if (rc)
160 		return rc;
161 	val += ctx->value;
162 	rc = __apei_exec_write_register(entry, val);
163 	return rc;
164 }
165 
166 static int erst_exec_subtract_value(struct apei_exec_context *ctx,
167 				    struct acpi_whea_header *entry)
168 {
169 	int rc;
170 	u64 val;
171 
172 	rc = __apei_exec_read_register(entry, &val);
173 	if (rc)
174 		return rc;
175 	val -= ctx->value;
176 	rc = __apei_exec_write_register(entry, val);
177 	return rc;
178 }
179 
180 static int erst_exec_stall(struct apei_exec_context *ctx,
181 			   struct acpi_whea_header *entry)
182 {
183 	u64 stall_time;
184 
185 	if (ctx->value > FIRMWARE_MAX_STALL) {
186 		if (!in_nmi())
187 			pr_warning(FW_WARN ERST_PFX
188 			"Too long stall time for stall instruction: %llx.\n",
189 				   ctx->value);
190 		stall_time = FIRMWARE_MAX_STALL;
191 	} else
192 		stall_time = ctx->value;
193 	udelay(stall_time);
194 	return 0;
195 }
196 
197 static int erst_exec_stall_while_true(struct apei_exec_context *ctx,
198 				      struct acpi_whea_header *entry)
199 {
200 	int rc;
201 	u64 val;
202 	u64 timeout = FIRMWARE_TIMEOUT;
203 	u64 stall_time;
204 
205 	if (ctx->var1 > FIRMWARE_MAX_STALL) {
206 		if (!in_nmi())
207 			pr_warning(FW_WARN ERST_PFX
208 		"Too long stall time for stall while true instruction: %llx.\n",
209 				   ctx->var1);
210 		stall_time = FIRMWARE_MAX_STALL;
211 	} else
212 		stall_time = ctx->var1;
213 
214 	for (;;) {
215 		rc = __apei_exec_read_register(entry, &val);
216 		if (rc)
217 			return rc;
218 		if (val != ctx->value)
219 			break;
220 		if (erst_timedout(&timeout, stall_time * NSEC_PER_USEC))
221 			return -EIO;
222 	}
223 	return 0;
224 }
225 
226 static int erst_exec_skip_next_instruction_if_true(
227 	struct apei_exec_context *ctx,
228 	struct acpi_whea_header *entry)
229 {
230 	int rc;
231 	u64 val;
232 
233 	rc = __apei_exec_read_register(entry, &val);
234 	if (rc)
235 		return rc;
236 	if (val == ctx->value) {
237 		ctx->ip += 2;
238 		return APEI_EXEC_SET_IP;
239 	}
240 
241 	return 0;
242 }
243 
244 static int erst_exec_goto(struct apei_exec_context *ctx,
245 			  struct acpi_whea_header *entry)
246 {
247 	ctx->ip = ctx->value;
248 	return APEI_EXEC_SET_IP;
249 }
250 
251 static int erst_exec_set_src_address_base(struct apei_exec_context *ctx,
252 					  struct acpi_whea_header *entry)
253 {
254 	return __apei_exec_read_register(entry, &ctx->src_base);
255 }
256 
257 static int erst_exec_set_dst_address_base(struct apei_exec_context *ctx,
258 					  struct acpi_whea_header *entry)
259 {
260 	return __apei_exec_read_register(entry, &ctx->dst_base);
261 }
262 
263 static int erst_exec_move_data(struct apei_exec_context *ctx,
264 			       struct acpi_whea_header *entry)
265 {
266 	int rc;
267 	u64 offset;
268 
269 	rc = __apei_exec_read_register(entry, &offset);
270 	if (rc)
271 		return rc;
272 	memmove((void *)ctx->dst_base + offset,
273 		(void *)ctx->src_base + offset,
274 		ctx->var2);
275 
276 	return 0;
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 
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 
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 static ssize_t __erst_get_record_count(void)
387 {
388 	struct apei_exec_context ctx;
389 	int rc;
390 
391 	erst_exec_ctx_init(&ctx);
392 	rc = apei_exec_run(&ctx, ACPI_ERST_GET_RECORD_COUNT);
393 	if (rc)
394 		return rc;
395 	return apei_exec_ctx_get_output(&ctx);
396 }
397 
398 ssize_t erst_get_record_count(void)
399 {
400 	ssize_t count;
401 	unsigned long flags;
402 
403 	if (erst_disable)
404 		return -ENODEV;
405 
406 	spin_lock_irqsave(&erst_lock, flags);
407 	count = __erst_get_record_count();
408 	spin_unlock_irqrestore(&erst_lock, flags);
409 
410 	return count;
411 }
412 EXPORT_SYMBOL_GPL(erst_get_record_count);
413 
414 static int __erst_get_next_record_id(u64 *record_id)
415 {
416 	struct apei_exec_context ctx;
417 	int rc;
418 
419 	erst_exec_ctx_init(&ctx);
420 	rc = apei_exec_run(&ctx, ACPI_ERST_GET_RECORD_ID);
421 	if (rc)
422 		return rc;
423 	*record_id = apei_exec_ctx_get_output(&ctx);
424 
425 	return 0;
426 }
427 
428 /*
429  * Get the record ID of an existing error record on the persistent
430  * storage. If there is no error record on the persistent storage, the
431  * returned record_id is APEI_ERST_INVALID_RECORD_ID.
432  */
433 int erst_get_next_record_id(u64 *record_id)
434 {
435 	int rc;
436 	unsigned long flags;
437 
438 	if (erst_disable)
439 		return -ENODEV;
440 
441 	spin_lock_irqsave(&erst_lock, flags);
442 	rc = __erst_get_next_record_id(record_id);
443 	spin_unlock_irqrestore(&erst_lock, flags);
444 
445 	return rc;
446 }
447 EXPORT_SYMBOL_GPL(erst_get_next_record_id);
448 
449 static int __erst_write_to_storage(u64 offset)
450 {
451 	struct apei_exec_context ctx;
452 	u64 timeout = FIRMWARE_TIMEOUT;
453 	u64 val;
454 	int rc;
455 
456 	erst_exec_ctx_init(&ctx);
457 	rc = apei_exec_run(&ctx, ACPI_ERST_BEGIN_WRITE);
458 	if (rc)
459 		return rc;
460 	apei_exec_ctx_set_input(&ctx, offset);
461 	rc = apei_exec_run(&ctx, ACPI_ERST_SET_RECORD_OFFSET);
462 	if (rc)
463 		return rc;
464 	rc = apei_exec_run(&ctx, ACPI_ERST_EXECUTE_OPERATION);
465 	if (rc)
466 		return rc;
467 	for (;;) {
468 		rc = apei_exec_run(&ctx, ACPI_ERST_CHECK_BUSY_STATUS);
469 		if (rc)
470 			return rc;
471 		val = apei_exec_ctx_get_output(&ctx);
472 		if (!val)
473 			break;
474 		if (erst_timedout(&timeout, SPIN_UNIT))
475 			return -EIO;
476 	}
477 	rc = apei_exec_run(&ctx, ACPI_ERST_GET_COMMAND_STATUS);
478 	if (rc)
479 		return rc;
480 	val = apei_exec_ctx_get_output(&ctx);
481 	rc = apei_exec_run(&ctx, ACPI_ERST_END);
482 	if (rc)
483 		return rc;
484 
485 	return erst_errno(val);
486 }
487 
488 static int __erst_read_from_storage(u64 record_id, u64 offset)
489 {
490 	struct apei_exec_context ctx;
491 	u64 timeout = FIRMWARE_TIMEOUT;
492 	u64 val;
493 	int rc;
494 
495 	erst_exec_ctx_init(&ctx);
496 	rc = apei_exec_run(&ctx, ACPI_ERST_BEGIN_READ);
497 	if (rc)
498 		return rc;
499 	apei_exec_ctx_set_input(&ctx, offset);
500 	rc = apei_exec_run(&ctx, ACPI_ERST_SET_RECORD_OFFSET);
501 	if (rc)
502 		return rc;
503 	apei_exec_ctx_set_input(&ctx, record_id);
504 	rc = apei_exec_run(&ctx, ACPI_ERST_SET_RECORD_ID);
505 	if (rc)
506 		return rc;
507 	rc = apei_exec_run(&ctx, ACPI_ERST_EXECUTE_OPERATION);
508 	if (rc)
509 		return rc;
510 	for (;;) {
511 		rc = apei_exec_run(&ctx, ACPI_ERST_CHECK_BUSY_STATUS);
512 		if (rc)
513 			return rc;
514 		val = apei_exec_ctx_get_output(&ctx);
515 		if (!val)
516 			break;
517 		if (erst_timedout(&timeout, SPIN_UNIT))
518 			return -EIO;
519 	};
520 	rc = apei_exec_run(&ctx, ACPI_ERST_GET_COMMAND_STATUS);
521 	if (rc)
522 		return rc;
523 	val = apei_exec_ctx_get_output(&ctx);
524 	rc = apei_exec_run(&ctx, ACPI_ERST_END);
525 	if (rc)
526 		return rc;
527 
528 	return erst_errno(val);
529 }
530 
531 static int __erst_clear_from_storage(u64 record_id)
532 {
533 	struct apei_exec_context ctx;
534 	u64 timeout = FIRMWARE_TIMEOUT;
535 	u64 val;
536 	int rc;
537 
538 	erst_exec_ctx_init(&ctx);
539 	rc = apei_exec_run(&ctx, ACPI_ERST_BEGIN_CLEAR);
540 	if (rc)
541 		return rc;
542 	apei_exec_ctx_set_input(&ctx, record_id);
543 	rc = apei_exec_run(&ctx, ACPI_ERST_SET_RECORD_ID);
544 	if (rc)
545 		return rc;
546 	rc = apei_exec_run(&ctx, ACPI_ERST_EXECUTE_OPERATION);
547 	if (rc)
548 		return rc;
549 	for (;;) {
550 		rc = apei_exec_run(&ctx, ACPI_ERST_CHECK_BUSY_STATUS);
551 		if (rc)
552 			return rc;
553 		val = apei_exec_ctx_get_output(&ctx);
554 		if (!val)
555 			break;
556 		if (erst_timedout(&timeout, SPIN_UNIT))
557 			return -EIO;
558 	}
559 	rc = apei_exec_run(&ctx, ACPI_ERST_GET_COMMAND_STATUS);
560 	if (rc)
561 		return rc;
562 	val = apei_exec_ctx_get_output(&ctx);
563 	rc = apei_exec_run(&ctx, ACPI_ERST_END);
564 	if (rc)
565 		return rc;
566 
567 	return erst_errno(val);
568 }
569 
570 /* NVRAM ERST Error Log Address Range is not supported yet */
571 static void pr_unimpl_nvram(void)
572 {
573 	if (printk_ratelimit())
574 		pr_warning(ERST_PFX
575 		"NVRAM ERST Log Address Range is not implemented yet\n");
576 }
577 
578 static int __erst_write_to_nvram(const struct cper_record_header *record)
579 {
580 	/* do not print message, because printk is not safe for NMI */
581 	return -ENOSYS;
582 }
583 
584 static int __erst_read_to_erange_from_nvram(u64 record_id, u64 *offset)
585 {
586 	pr_unimpl_nvram();
587 	return -ENOSYS;
588 }
589 
590 static int __erst_clear_from_nvram(u64 record_id)
591 {
592 	pr_unimpl_nvram();
593 	return -ENOSYS;
594 }
595 
596 int erst_write(const struct cper_record_header *record)
597 {
598 	int rc;
599 	unsigned long flags;
600 	struct cper_record_header *rcd_erange;
601 
602 	if (erst_disable)
603 		return -ENODEV;
604 
605 	if (memcmp(record->signature, CPER_SIG_RECORD, CPER_SIG_SIZE))
606 		return -EINVAL;
607 
608 	if (erst_erange.attr & ERST_RANGE_NVRAM) {
609 		if (!spin_trylock_irqsave(&erst_lock, flags))
610 			return -EBUSY;
611 		rc = __erst_write_to_nvram(record);
612 		spin_unlock_irqrestore(&erst_lock, flags);
613 		return rc;
614 	}
615 
616 	if (record->record_length > erst_erange.size)
617 		return -EINVAL;
618 
619 	if (!spin_trylock_irqsave(&erst_lock, flags))
620 		return -EBUSY;
621 	memcpy(erst_erange.vaddr, record, record->record_length);
622 	rcd_erange = erst_erange.vaddr;
623 	/* signature for serialization system */
624 	memcpy(&rcd_erange->persistence_information, "ER", 2);
625 
626 	rc = __erst_write_to_storage(0);
627 	spin_unlock_irqrestore(&erst_lock, flags);
628 
629 	return rc;
630 }
631 EXPORT_SYMBOL_GPL(erst_write);
632 
633 static int __erst_read_to_erange(u64 record_id, u64 *offset)
634 {
635 	int rc;
636 
637 	if (erst_erange.attr & ERST_RANGE_NVRAM)
638 		return __erst_read_to_erange_from_nvram(
639 			record_id, offset);
640 
641 	rc = __erst_read_from_storage(record_id, 0);
642 	if (rc)
643 		return rc;
644 	*offset = 0;
645 
646 	return 0;
647 }
648 
649 static ssize_t __erst_read(u64 record_id, struct cper_record_header *record,
650 			   size_t buflen)
651 {
652 	int rc;
653 	u64 offset, len = 0;
654 	struct cper_record_header *rcd_tmp;
655 
656 	rc = __erst_read_to_erange(record_id, &offset);
657 	if (rc)
658 		return rc;
659 	rcd_tmp = erst_erange.vaddr + offset;
660 	len = rcd_tmp->record_length;
661 	if (len <= buflen)
662 		memcpy(record, rcd_tmp, len);
663 
664 	return len;
665 }
666 
667 /*
668  * If return value > buflen, the buffer size is not big enough,
669  * else if return value < 0, something goes wrong,
670  * else everything is OK, and return value is record length
671  */
672 ssize_t erst_read(u64 record_id, struct cper_record_header *record,
673 		  size_t buflen)
674 {
675 	ssize_t len;
676 	unsigned long flags;
677 
678 	if (erst_disable)
679 		return -ENODEV;
680 
681 	spin_lock_irqsave(&erst_lock, flags);
682 	len = __erst_read(record_id, record, buflen);
683 	spin_unlock_irqrestore(&erst_lock, flags);
684 	return len;
685 }
686 EXPORT_SYMBOL_GPL(erst_read);
687 
688 /*
689  * If return value > buflen, the buffer size is not big enough,
690  * else if return value = 0, there is no more record to read,
691  * else if return value < 0, something goes wrong,
692  * else everything is OK, and return value is record length
693  */
694 ssize_t erst_read_next(struct cper_record_header *record, size_t buflen)
695 {
696 	int rc;
697 	ssize_t len;
698 	unsigned long flags;
699 	u64 record_id;
700 
701 	if (erst_disable)
702 		return -ENODEV;
703 
704 	spin_lock_irqsave(&erst_lock, flags);
705 	rc = __erst_get_next_record_id(&record_id);
706 	if (rc) {
707 		spin_unlock_irqrestore(&erst_lock, flags);
708 		return rc;
709 	}
710 	/* no more record */
711 	if (record_id == APEI_ERST_INVALID_RECORD_ID) {
712 		spin_unlock_irqrestore(&erst_lock, flags);
713 		return 0;
714 	}
715 
716 	len = __erst_read(record_id, record, buflen);
717 	spin_unlock_irqrestore(&erst_lock, flags);
718 
719 	return len;
720 }
721 EXPORT_SYMBOL_GPL(erst_read_next);
722 
723 int erst_clear(u64 record_id)
724 {
725 	int rc;
726 	unsigned long flags;
727 
728 	if (erst_disable)
729 		return -ENODEV;
730 
731 	spin_lock_irqsave(&erst_lock, flags);
732 	if (erst_erange.attr & ERST_RANGE_NVRAM)
733 		rc = __erst_clear_from_nvram(record_id);
734 	else
735 		rc = __erst_clear_from_storage(record_id);
736 	spin_unlock_irqrestore(&erst_lock, flags);
737 
738 	return rc;
739 }
740 EXPORT_SYMBOL_GPL(erst_clear);
741 
742 static int __init setup_erst_disable(char *str)
743 {
744 	erst_disable = 1;
745 	return 0;
746 }
747 
748 __setup("erst_disable", setup_erst_disable);
749 
750 static int erst_check_table(struct acpi_table_erst *erst_tab)
751 {
752 	if (erst_tab->header_length != sizeof(struct acpi_table_erst))
753 		return -EINVAL;
754 	if (erst_tab->header.length < sizeof(struct acpi_table_erst))
755 		return -EINVAL;
756 	if (erst_tab->entries !=
757 	    (erst_tab->header.length - sizeof(struct acpi_table_erst)) /
758 	    sizeof(struct acpi_erst_entry))
759 		return -EINVAL;
760 
761 	return 0;
762 }
763 
764 static int __init erst_init(void)
765 {
766 	int rc = 0;
767 	acpi_status status;
768 	struct apei_exec_context ctx;
769 	struct apei_resources erst_resources;
770 	struct resource *r;
771 
772 	if (acpi_disabled)
773 		goto err;
774 
775 	if (erst_disable) {
776 		pr_info(ERST_PFX
777 	"Error Record Serialization Table (ERST) support is disabled.\n");
778 		goto err;
779 	}
780 
781 	status = acpi_get_table(ACPI_SIG_ERST, 0,
782 				(struct acpi_table_header **)&erst_tab);
783 	if (status == AE_NOT_FOUND) {
784 		pr_info(ERST_PFX "Table is not found!\n");
785 		goto err;
786 	} else if (ACPI_FAILURE(status)) {
787 		const char *msg = acpi_format_exception(status);
788 		pr_err(ERST_PFX "Failed to get table, %s\n", msg);
789 		rc = -EINVAL;
790 		goto err;
791 	}
792 
793 	rc = erst_check_table(erst_tab);
794 	if (rc) {
795 		pr_err(FW_BUG ERST_PFX "ERST table is invalid\n");
796 		goto err;
797 	}
798 
799 	apei_resources_init(&erst_resources);
800 	erst_exec_ctx_init(&ctx);
801 	rc = apei_exec_collect_resources(&ctx, &erst_resources);
802 	if (rc)
803 		goto err_fini;
804 	rc = apei_resources_request(&erst_resources, "APEI ERST");
805 	if (rc)
806 		goto err_fini;
807 	rc = apei_exec_pre_map_gars(&ctx);
808 	if (rc)
809 		goto err_release;
810 	rc = erst_get_erange(&erst_erange);
811 	if (rc) {
812 		if (rc == -ENODEV)
813 			pr_info(ERST_PFX
814 	"The corresponding hardware device or firmware implementation "
815 	"is not available.\n");
816 		else
817 			pr_err(ERST_PFX
818 			       "Failed to get Error Log Address Range.\n");
819 		goto err_unmap_reg;
820 	}
821 
822 	r = request_mem_region(erst_erange.base, erst_erange.size, "APEI ERST");
823 	if (!r) {
824 		pr_err(ERST_PFX
825 		"Can not request iomem region <0x%16llx-0x%16llx> for ERST.\n",
826 		(unsigned long long)erst_erange.base,
827 		(unsigned long long)erst_erange.base + erst_erange.size);
828 		rc = -EIO;
829 		goto err_unmap_reg;
830 	}
831 	rc = -ENOMEM;
832 	erst_erange.vaddr = ioremap_cache(erst_erange.base,
833 					  erst_erange.size);
834 	if (!erst_erange.vaddr)
835 		goto err_release_erange;
836 
837 	pr_info(ERST_PFX
838 	"Error Record Serialization Table (ERST) support is initialized.\n");
839 
840 	return 0;
841 
842 err_release_erange:
843 	release_mem_region(erst_erange.base, erst_erange.size);
844 err_unmap_reg:
845 	apei_exec_post_unmap_gars(&ctx);
846 err_release:
847 	apei_resources_release(&erst_resources);
848 err_fini:
849 	apei_resources_fini(&erst_resources);
850 err:
851 	erst_disable = 1;
852 	return rc;
853 }
854 
855 device_initcall(erst_init);
856