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