18645f4e83cdd2f22d526276b320dac631be8940
[linux-2.6.git] / drivers / acpi / apei / erst.c
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 <linux/hardirq.h>
37 #include <acpi/apei.h>
38
39 #include "apei-internal.h"
40
41 #define ERST_PFX "ERST: "
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               100                     /* 100ns */
56 /* Firmware should respond within 1 miliseconds */
57 #define FIRMWARE_TIMEOUT        (1 * NSEC_PER_MSEC)
58 #define FIRMWARE_MAX_STALL      50                      /* 50us */
59
60 int erst_disable;
61 EXPORT_SYMBOL_GPL(erst_disable);
62
63 static struct acpi_table_erst *erst_tab;
64
65 /* ERST Error Log Address Range atrributes */
66 #define ERST_RANGE_RESERVED     0x0001
67 #define ERST_RANGE_NVRAM        0x0002
68 #define ERST_RANGE_SLOW         0x0004
69
70 /*
71  * ERST Error Log Address Range, used as buffer for reading/writing
72  * error records.
73  */
74 static struct erst_erange {
75         u64 base;
76         u64 size;
77         void __iomem *vaddr;
78         u32 attr;
79 } erst_erange;
80
81 /*
82  * Prevent ERST interpreter to run simultaneously, because the
83  * corresponding firmware implementation may not work properly when
84  * invoked simultaneously.
85  *
86  * It is used to provide exclusive accessing for ERST Error Log
87  * Address Range too.
88  */
89 static DEFINE_SPINLOCK(erst_lock);
90
91 static inline int erst_errno(int command_status)
92 {
93         switch (command_status) {
94         case ERST_STATUS_SUCCESS:
95                 return 0;
96         case ERST_STATUS_HARDWARE_NOT_AVAILABLE:
97                 return -ENODEV;
98         case ERST_STATUS_NOT_ENOUGH_SPACE:
99                 return -ENOSPC;
100         case ERST_STATUS_RECORD_STORE_EMPTY:
101         case ERST_STATUS_RECORD_NOT_FOUND:
102                 return -ENOENT;
103         default:
104                 return -EINVAL;
105         }
106 }
107
108 static int erst_timedout(u64 *t, u64 spin_unit)
109 {
110         if ((s64)*t < spin_unit) {
111                 pr_warning(FW_WARN ERST_PFX
112                            "Firmware does not respond in time\n");
113                 return 1;
114         }
115         *t -= spin_unit;
116         ndelay(spin_unit);
117         touch_nmi_watchdog();
118         return 0;
119 }
120
121 static int erst_exec_load_var1(struct apei_exec_context *ctx,
122                                struct acpi_whea_header *entry)
123 {
124         return __apei_exec_read_register(entry, &ctx->var1);
125 }
126
127 static int erst_exec_load_var2(struct apei_exec_context *ctx,
128                                struct acpi_whea_header *entry)
129 {
130         return __apei_exec_read_register(entry, &ctx->var2);
131 }
132
133 static int erst_exec_store_var1(struct apei_exec_context *ctx,
134                                 struct acpi_whea_header *entry)
135 {
136         return __apei_exec_write_register(entry, ctx->var1);
137 }
138
139 static int erst_exec_add(struct apei_exec_context *ctx,
140                          struct acpi_whea_header *entry)
141 {
142         ctx->var1 += ctx->var2;
143         return 0;
144 }
145
146 static int erst_exec_subtract(struct apei_exec_context *ctx,
147                               struct acpi_whea_header *entry)
148 {
149         ctx->var1 -= ctx->var2;
150         return 0;
151 }
152
153 static int erst_exec_add_value(struct apei_exec_context *ctx,
154                                struct acpi_whea_header *entry)
155 {
156         int rc;
157         u64 val;
158
159         rc = __apei_exec_read_register(entry, &val);
160         if (rc)
161                 return rc;
162         val += ctx->value;
163         rc = __apei_exec_write_register(entry, val);
164         return rc;
165 }
166
167 static int erst_exec_subtract_value(struct apei_exec_context *ctx,
168                                     struct acpi_whea_header *entry)
169 {
170         int rc;
171         u64 val;
172
173         rc = __apei_exec_read_register(entry, &val);
174         if (rc)
175                 return rc;
176         val -= ctx->value;
177         rc = __apei_exec_write_register(entry, val);
178         return rc;
179 }
180
181 static int erst_exec_stall(struct apei_exec_context *ctx,
182                            struct acpi_whea_header *entry)
183 {
184         u64 stall_time;
185
186         if (ctx->value > FIRMWARE_MAX_STALL) {
187                 if (!in_nmi())
188                         pr_warning(FW_WARN ERST_PFX
189                         "Too long stall time for stall instruction: %llx.\n",
190                                    ctx->value);
191                 stall_time = FIRMWARE_MAX_STALL;
192         } else
193                 stall_time = ctx->value;
194         udelay(stall_time);
195         return 0;
196 }
197
198 static int erst_exec_stall_while_true(struct apei_exec_context *ctx,
199                                       struct acpi_whea_header *entry)
200 {
201         int rc;
202         u64 val;
203         u64 timeout = FIRMWARE_TIMEOUT;
204         u64 stall_time;
205
206         if (ctx->var1 > FIRMWARE_MAX_STALL) {
207                 if (!in_nmi())
208                         pr_warning(FW_WARN ERST_PFX
209                 "Too long stall time for stall while true instruction: %llx.\n",
210                                    ctx->var1);
211                 stall_time = FIRMWARE_MAX_STALL;
212         } else
213                 stall_time = ctx->var1;
214
215         for (;;) {
216                 rc = __apei_exec_read_register(entry, &val);
217                 if (rc)
218                         return rc;
219                 if (val != ctx->value)
220                         break;
221                 if (erst_timedout(&timeout, stall_time * NSEC_PER_USEC))
222                         return -EIO;
223         }
224         return 0;
225 }
226
227 static int erst_exec_skip_next_instruction_if_true(
228         struct apei_exec_context *ctx,
229         struct acpi_whea_header *entry)
230 {
231         int rc;
232         u64 val;
233
234         rc = __apei_exec_read_register(entry, &val);
235         if (rc)
236                 return rc;
237         if (val == ctx->value) {
238                 ctx->ip += 2;
239                 return APEI_EXEC_SET_IP;
240         }
241
242         return 0;
243 }
244
245 static int erst_exec_goto(struct apei_exec_context *ctx,
246                           struct acpi_whea_header *entry)
247 {
248         ctx->ip = ctx->value;
249         return APEI_EXEC_SET_IP;
250 }
251
252 static int erst_exec_set_src_address_base(struct apei_exec_context *ctx,
253                                           struct acpi_whea_header *entry)
254 {
255         return __apei_exec_read_register(entry, &ctx->src_base);
256 }
257
258 static int erst_exec_set_dst_address_base(struct apei_exec_context *ctx,
259                                           struct acpi_whea_header *entry)
260 {
261         return __apei_exec_read_register(entry, &ctx->dst_base);
262 }
263
264 static int erst_exec_move_data(struct apei_exec_context *ctx,
265                                struct acpi_whea_header *entry)
266 {
267         int rc;
268         u64 offset;
269
270         rc = __apei_exec_read_register(entry, &offset);
271         if (rc)
272                 return rc;
273         memmove((void *)ctx->dst_base + offset,
274                 (void *)ctx->src_base + offset,
275                 ctx->var2);
276
277         return 0;
278 }
279
280 static struct apei_exec_ins_type erst_ins_type[] = {
281         [ACPI_ERST_READ_REGISTER] = {
282                 .flags = APEI_EXEC_INS_ACCESS_REGISTER,
283                 .run = apei_exec_read_register,
284         },
285         [ACPI_ERST_READ_REGISTER_VALUE] = {
286                 .flags = APEI_EXEC_INS_ACCESS_REGISTER,
287                 .run = apei_exec_read_register_value,
288         },
289         [ACPI_ERST_WRITE_REGISTER] = {
290                 .flags = APEI_EXEC_INS_ACCESS_REGISTER,
291                 .run = apei_exec_write_register,
292         },
293         [ACPI_ERST_WRITE_REGISTER_VALUE] = {
294                 .flags = APEI_EXEC_INS_ACCESS_REGISTER,
295                 .run = apei_exec_write_register_value,
296         },
297         [ACPI_ERST_NOOP] = {
298                 .flags = 0,
299                 .run = apei_exec_noop,
300         },
301         [ACPI_ERST_LOAD_VAR1] = {
302                 .flags = APEI_EXEC_INS_ACCESS_REGISTER,
303                 .run = erst_exec_load_var1,
304         },
305         [ACPI_ERST_LOAD_VAR2] = {
306                 .flags = APEI_EXEC_INS_ACCESS_REGISTER,
307                 .run = erst_exec_load_var2,
308         },
309         [ACPI_ERST_STORE_VAR1] = {
310                 .flags = APEI_EXEC_INS_ACCESS_REGISTER,
311                 .run = erst_exec_store_var1,
312         },
313         [ACPI_ERST_ADD] = {
314                 .flags = 0,
315                 .run = erst_exec_add,
316         },
317         [ACPI_ERST_SUBTRACT] = {
318                 .flags = 0,
319                 .run = erst_exec_subtract,
320         },
321         [ACPI_ERST_ADD_VALUE] = {
322                 .flags = APEI_EXEC_INS_ACCESS_REGISTER,
323                 .run = erst_exec_add_value,
324         },
325         [ACPI_ERST_SUBTRACT_VALUE] = {
326                 .flags = APEI_EXEC_INS_ACCESS_REGISTER,
327                 .run = erst_exec_subtract_value,
328         },
329         [ACPI_ERST_STALL] = {
330                 .flags = 0,
331                 .run = erst_exec_stall,
332         },
333         [ACPI_ERST_STALL_WHILE_TRUE] = {
334                 .flags = APEI_EXEC_INS_ACCESS_REGISTER,
335                 .run = erst_exec_stall_while_true,
336         },
337         [ACPI_ERST_SKIP_NEXT_IF_TRUE] = {
338                 .flags = APEI_EXEC_INS_ACCESS_REGISTER,
339                 .run = erst_exec_skip_next_instruction_if_true,
340         },
341         [ACPI_ERST_GOTO] = {
342                 .flags = 0,
343                 .run = erst_exec_goto,
344         },
345         [ACPI_ERST_SET_SRC_ADDRESS_BASE] = {
346                 .flags = APEI_EXEC_INS_ACCESS_REGISTER,
347                 .run = erst_exec_set_src_address_base,
348         },
349         [ACPI_ERST_SET_DST_ADDRESS_BASE] = {
350                 .flags = APEI_EXEC_INS_ACCESS_REGISTER,
351                 .run = erst_exec_set_dst_address_base,
352         },
353         [ACPI_ERST_MOVE_DATA] = {
354                 .flags = APEI_EXEC_INS_ACCESS_REGISTER,
355                 .run = erst_exec_move_data,
356         },
357 };
358
359 static inline void erst_exec_ctx_init(struct apei_exec_context *ctx)
360 {
361         apei_exec_ctx_init(ctx, erst_ins_type, ARRAY_SIZE(erst_ins_type),
362                            ERST_TAB_ENTRY(erst_tab), erst_tab->entries);
363 }
364
365 static int erst_get_erange(struct erst_erange *range)
366 {
367         struct apei_exec_context ctx;
368         int rc;
369
370         erst_exec_ctx_init(&ctx);
371         rc = apei_exec_run(&ctx, ACPI_ERST_GET_ERROR_RANGE);
372         if (rc)
373                 return rc;
374         range->base = apei_exec_ctx_get_output(&ctx);
375         rc = apei_exec_run(&ctx, ACPI_ERST_GET_ERROR_LENGTH);
376         if (rc)
377                 return rc;
378         range->size = apei_exec_ctx_get_output(&ctx);
379         rc = apei_exec_run(&ctx, ACPI_ERST_GET_ERROR_ATTRIBUTES);
380         if (rc)
381                 return rc;
382         range->attr = apei_exec_ctx_get_output(&ctx);
383
384         return 0;
385 }
386
387 static ssize_t __erst_get_record_count(void)
388 {
389         struct apei_exec_context ctx;
390         int rc;
391
392         erst_exec_ctx_init(&ctx);
393         rc = apei_exec_run(&ctx, ACPI_ERST_GET_RECORD_COUNT);
394         if (rc)
395                 return rc;
396         return apei_exec_ctx_get_output(&ctx);
397 }
398
399 ssize_t erst_get_record_count(void)
400 {
401         ssize_t count;
402         unsigned long flags;
403
404         if (erst_disable)
405                 return -ENODEV;
406
407         spin_lock_irqsave(&erst_lock, flags);
408         count = __erst_get_record_count();
409         spin_unlock_irqrestore(&erst_lock, flags);
410
411         return count;
412 }
413 EXPORT_SYMBOL_GPL(erst_get_record_count);
414
415 static int __erst_get_next_record_id(u64 *record_id)
416 {
417         struct apei_exec_context ctx;
418         int rc;
419
420         erst_exec_ctx_init(&ctx);
421         rc = apei_exec_run(&ctx, ACPI_ERST_GET_RECORD_ID);
422         if (rc)
423                 return rc;
424         *record_id = apei_exec_ctx_get_output(&ctx);
425
426         return 0;
427 }
428
429 /*
430  * Get the record ID of an existing error record on the persistent
431  * storage. If there is no error record on the persistent storage, the
432  * returned record_id is APEI_ERST_INVALID_RECORD_ID.
433  */
434 int erst_get_next_record_id(u64 *record_id)
435 {
436         int rc;
437         unsigned long flags;
438
439         if (erst_disable)
440                 return -ENODEV;
441
442         spin_lock_irqsave(&erst_lock, flags);
443         rc = __erst_get_next_record_id(record_id);
444         spin_unlock_irqrestore(&erst_lock, flags);
445
446         return rc;
447 }
448 EXPORT_SYMBOL_GPL(erst_get_next_record_id);
449
450 static int __erst_write_to_storage(u64 offset)
451 {
452         struct apei_exec_context ctx;
453         u64 timeout = FIRMWARE_TIMEOUT;
454         u64 val;
455         int rc;
456
457         erst_exec_ctx_init(&ctx);
458         rc = apei_exec_run(&ctx, ACPI_ERST_BEGIN_WRITE);
459         if (rc)
460                 return rc;
461         apei_exec_ctx_set_input(&ctx, offset);
462         rc = apei_exec_run(&ctx, ACPI_ERST_SET_RECORD_OFFSET);
463         if (rc)
464                 return rc;
465         rc = apei_exec_run(&ctx, ACPI_ERST_EXECUTE_OPERATION);
466         if (rc)
467                 return rc;
468         for (;;) {
469                 rc = apei_exec_run(&ctx, ACPI_ERST_CHECK_BUSY_STATUS);
470                 if (rc)
471                         return rc;
472                 val = apei_exec_ctx_get_output(&ctx);
473                 if (!val)
474                         break;
475                 if (erst_timedout(&timeout, SPIN_UNIT))
476                         return -EIO;
477         }
478         rc = apei_exec_run(&ctx, ACPI_ERST_GET_COMMAND_STATUS);
479         if (rc)
480                 return rc;
481         val = apei_exec_ctx_get_output(&ctx);
482         rc = apei_exec_run(&ctx, ACPI_ERST_END);
483         if (rc)
484                 return rc;
485
486         return erst_errno(val);
487 }
488
489 static int __erst_read_from_storage(u64 record_id, u64 offset)
490 {
491         struct apei_exec_context ctx;
492         u64 timeout = FIRMWARE_TIMEOUT;
493         u64 val;
494         int rc;
495
496         erst_exec_ctx_init(&ctx);
497         rc = apei_exec_run(&ctx, ACPI_ERST_BEGIN_READ);
498         if (rc)
499                 return rc;
500         apei_exec_ctx_set_input(&ctx, offset);
501         rc = apei_exec_run(&ctx, ACPI_ERST_SET_RECORD_OFFSET);
502         if (rc)
503                 return rc;
504         apei_exec_ctx_set_input(&ctx, record_id);
505         rc = apei_exec_run(&ctx, ACPI_ERST_SET_RECORD_ID);
506         if (rc)
507                 return rc;
508         rc = apei_exec_run(&ctx, ACPI_ERST_EXECUTE_OPERATION);
509         if (rc)
510                 return rc;
511         for (;;) {
512                 rc = apei_exec_run(&ctx, ACPI_ERST_CHECK_BUSY_STATUS);
513                 if (rc)
514                         return rc;
515                 val = apei_exec_ctx_get_output(&ctx);
516                 if (!val)
517                         break;
518                 if (erst_timedout(&timeout, SPIN_UNIT))
519                         return -EIO;
520         };
521         rc = apei_exec_run(&ctx, ACPI_ERST_GET_COMMAND_STATUS);
522         if (rc)
523                 return rc;
524         val = apei_exec_ctx_get_output(&ctx);
525         rc = apei_exec_run(&ctx, ACPI_ERST_END);
526         if (rc)
527                 return rc;
528
529         return erst_errno(val);
530 }
531
532 static int __erst_clear_from_storage(u64 record_id)
533 {
534         struct apei_exec_context ctx;
535         u64 timeout = FIRMWARE_TIMEOUT;
536         u64 val;
537         int rc;
538
539         erst_exec_ctx_init(&ctx);
540         rc = apei_exec_run(&ctx, ACPI_ERST_BEGIN_CLEAR);
541         if (rc)
542                 return rc;
543         apei_exec_ctx_set_input(&ctx, record_id);
544         rc = apei_exec_run(&ctx, ACPI_ERST_SET_RECORD_ID);
545         if (rc)
546                 return rc;
547         rc = apei_exec_run(&ctx, ACPI_ERST_EXECUTE_OPERATION);
548         if (rc)
549                 return rc;
550         for (;;) {
551                 rc = apei_exec_run(&ctx, ACPI_ERST_CHECK_BUSY_STATUS);
552                 if (rc)
553                         return rc;
554                 val = apei_exec_ctx_get_output(&ctx);
555                 if (!val)
556                         break;
557                 if (erst_timedout(&timeout, SPIN_UNIT))
558                         return -EIO;
559         }
560         rc = apei_exec_run(&ctx, ACPI_ERST_GET_COMMAND_STATUS);
561         if (rc)
562                 return rc;
563         val = apei_exec_ctx_get_output(&ctx);
564         rc = apei_exec_run(&ctx, ACPI_ERST_END);
565         if (rc)
566                 return rc;
567
568         return erst_errno(val);
569 }
570
571 /* NVRAM ERST Error Log Address Range is not supported yet */
572 static void pr_unimpl_nvram(void)
573 {
574         if (printk_ratelimit())
575                 pr_warning(ERST_PFX
576                 "NVRAM ERST Log Address Range is not implemented yet\n");
577 }
578
579 static int __erst_write_to_nvram(const struct cper_record_header *record)
580 {
581         /* do not print message, because printk is not safe for NMI */
582         return -ENOSYS;
583 }
584
585 static int __erst_read_to_erange_from_nvram(u64 record_id, u64 *offset)
586 {
587         pr_unimpl_nvram();
588         return -ENOSYS;
589 }
590
591 static int __erst_clear_from_nvram(u64 record_id)
592 {
593         pr_unimpl_nvram();
594         return -ENOSYS;
595 }
596
597 int erst_write(const struct cper_record_header *record)
598 {
599         int rc;
600         unsigned long flags;
601         struct cper_record_header *rcd_erange;
602
603         if (erst_disable)
604                 return -ENODEV;
605
606         if (memcmp(record->signature, CPER_SIG_RECORD, CPER_SIG_SIZE))
607                 return -EINVAL;
608
609         if (erst_erange.attr & ERST_RANGE_NVRAM) {
610                 if (!spin_trylock_irqsave(&erst_lock, flags))
611                         return -EBUSY;
612                 rc = __erst_write_to_nvram(record);
613                 spin_unlock_irqrestore(&erst_lock, flags);
614                 return rc;
615         }
616
617         if (record->record_length > erst_erange.size)
618                 return -EINVAL;
619
620         if (!spin_trylock_irqsave(&erst_lock, flags))
621                 return -EBUSY;
622         memcpy(erst_erange.vaddr, record, record->record_length);
623         rcd_erange = erst_erange.vaddr;
624         /* signature for serialization system */
625         memcpy(&rcd_erange->persistence_information, "ER", 2);
626
627         rc = __erst_write_to_storage(0);
628         spin_unlock_irqrestore(&erst_lock, flags);
629
630         return rc;
631 }
632 EXPORT_SYMBOL_GPL(erst_write);
633
634 static int __erst_read_to_erange(u64 record_id, u64 *offset)
635 {
636         int rc;
637
638         if (erst_erange.attr & ERST_RANGE_NVRAM)
639                 return __erst_read_to_erange_from_nvram(
640                         record_id, offset);
641
642         rc = __erst_read_from_storage(record_id, 0);
643         if (rc)
644                 return rc;
645         *offset = 0;
646
647         return 0;
648 }
649
650 static ssize_t __erst_read(u64 record_id, struct cper_record_header *record,
651                            size_t buflen)
652 {
653         int rc;
654         u64 offset, len = 0;
655         struct cper_record_header *rcd_tmp;
656
657         rc = __erst_read_to_erange(record_id, &offset);
658         if (rc)
659                 return rc;
660         rcd_tmp = erst_erange.vaddr + offset;
661         len = rcd_tmp->record_length;
662         if (len <= buflen)
663                 memcpy(record, rcd_tmp, len);
664
665         return len;
666 }
667
668 /*
669  * If return value > buflen, the buffer size is not big enough,
670  * else if return value < 0, something goes wrong,
671  * else everything is OK, and return value is record length
672  */
673 ssize_t erst_read(u64 record_id, struct cper_record_header *record,
674                   size_t buflen)
675 {
676         ssize_t len;
677         unsigned long flags;
678
679         if (erst_disable)
680                 return -ENODEV;
681
682         spin_lock_irqsave(&erst_lock, flags);
683         len = __erst_read(record_id, record, buflen);
684         spin_unlock_irqrestore(&erst_lock, flags);
685         return len;
686 }
687 EXPORT_SYMBOL_GPL(erst_read);
688
689 /*
690  * If return value > buflen, the buffer size is not big enough,
691  * else if return value = 0, there is no more record to read,
692  * else if return value < 0, something goes wrong,
693  * else everything is OK, and return value is record length
694  */
695 ssize_t erst_read_next(struct cper_record_header *record, size_t buflen)
696 {
697         int rc;
698         ssize_t len;
699         unsigned long flags;
700         u64 record_id;
701
702         if (erst_disable)
703                 return -ENODEV;
704
705         spin_lock_irqsave(&erst_lock, flags);
706         rc = __erst_get_next_record_id(&record_id);
707         if (rc) {
708                 spin_unlock_irqrestore(&erst_lock, flags);
709                 return rc;
710         }
711         /* no more record */
712         if (record_id == APEI_ERST_INVALID_RECORD_ID) {
713                 spin_unlock_irqrestore(&erst_lock, flags);
714                 return 0;
715         }
716
717         len = __erst_read(record_id, record, buflen);
718         spin_unlock_irqrestore(&erst_lock, flags);
719
720         return len;
721 }
722 EXPORT_SYMBOL_GPL(erst_read_next);
723
724 int erst_clear(u64 record_id)
725 {
726         int rc;
727         unsigned long flags;
728
729         if (erst_disable)
730                 return -ENODEV;
731
732         spin_lock_irqsave(&erst_lock, flags);
733         if (erst_erange.attr & ERST_RANGE_NVRAM)
734                 rc = __erst_clear_from_nvram(record_id);
735         else
736                 rc = __erst_clear_from_storage(record_id);
737         spin_unlock_irqrestore(&erst_lock, flags);
738
739         return rc;
740 }
741 EXPORT_SYMBOL_GPL(erst_clear);
742
743 static int __init setup_erst_disable(char *str)
744 {
745         erst_disable = 1;
746         return 0;
747 }
748
749 __setup("erst_disable", setup_erst_disable);
750
751 static int erst_check_table(struct acpi_table_erst *erst_tab)
752 {
753         if (erst_tab->header_length != sizeof(struct acpi_table_erst))
754                 return -EINVAL;
755         if (erst_tab->header.length < sizeof(struct acpi_table_erst))
756                 return -EINVAL;
757         if (erst_tab->entries !=
758             (erst_tab->header.length - sizeof(struct acpi_table_erst)) /
759             sizeof(struct acpi_erst_entry))
760                 return -EINVAL;
761
762         return 0;
763 }
764
765 static int __init erst_init(void)
766 {
767         int rc = 0;
768         acpi_status status;
769         struct apei_exec_context ctx;
770         struct apei_resources erst_resources;
771         struct resource *r;
772
773         if (acpi_disabled)
774                 goto err;
775
776         if (erst_disable) {
777                 pr_info(ERST_PFX
778         "Error Record Serialization Table (ERST) support is disabled.\n");
779                 goto err;
780         }
781
782         status = acpi_get_table(ACPI_SIG_ERST, 0,
783                                 (struct acpi_table_header **)&erst_tab);
784         if (status == AE_NOT_FOUND) {
785                 pr_info(ERST_PFX "Table is not found!\n");
786                 goto err;
787         } else if (ACPI_FAILURE(status)) {
788                 const char *msg = acpi_format_exception(status);
789                 pr_err(ERST_PFX "Failed to get table, %s\n", msg);
790                 rc = -EINVAL;
791                 goto err;
792         }
793
794         rc = erst_check_table(erst_tab);
795         if (rc) {
796                 pr_err(FW_BUG ERST_PFX "ERST table is invalid\n");
797                 goto err;
798         }
799
800         apei_resources_init(&erst_resources);
801         erst_exec_ctx_init(&ctx);
802         rc = apei_exec_collect_resources(&ctx, &erst_resources);
803         if (rc)
804                 goto err_fini;
805         rc = apei_resources_request(&erst_resources, "APEI ERST");
806         if (rc)
807                 goto err_fini;
808         rc = apei_exec_pre_map_gars(&ctx);
809         if (rc)
810                 goto err_release;
811         rc = erst_get_erange(&erst_erange);
812         if (rc) {
813                 if (rc == -ENODEV)
814                         pr_info(ERST_PFX
815         "The corresponding hardware device or firmware implementation "
816         "is not available.\n");
817                 else
818                         pr_err(ERST_PFX
819                                "Failed to get Error Log Address Range.\n");
820                 goto err_unmap_reg;
821         }
822
823         r = request_mem_region(erst_erange.base, erst_erange.size, "APEI ERST");
824         if (!r) {
825                 pr_err(ERST_PFX
826                 "Can not request iomem region <0x%16llx-0x%16llx> for ERST.\n",
827                 (unsigned long long)erst_erange.base,
828                 (unsigned long long)erst_erange.base + erst_erange.size);
829                 rc = -EIO;
830                 goto err_unmap_reg;
831         }
832         rc = -ENOMEM;
833         erst_erange.vaddr = ioremap_cache(erst_erange.base,
834                                           erst_erange.size);
835         if (!erst_erange.vaddr)
836                 goto err_release_erange;
837
838         pr_info(ERST_PFX
839         "Error Record Serialization Table (ERST) support is initialized.\n");
840
841         return 0;
842
843 err_release_erange:
844         release_mem_region(erst_erange.base, erst_erange.size);
845 err_unmap_reg:
846         apei_exec_post_unmap_gars(&ctx);
847 err_release:
848         apei_resources_release(&erst_resources);
849 err_fini:
850         apei_resources_fini(&erst_resources);
851 err:
852         erst_disable = 1;
853         return rc;
854 }
855
856 device_initcall(erst_init);