linux/drivers/acpi/apei/erst.c
<<
>>
Prefs
   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 * 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 milliseconds */
  57#define FIRMWARE_TIMEOUT        (1 * NSEC_PER_MSEC)
  58#define FIRMWARE_MAX_STALL      50                      /* 50us */
  59
  60int erst_disable;
  61EXPORT_SYMBOL_GPL(erst_disable);
  62
  63static 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 */
  74static 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 */
  89static DEFINE_RAW_SPINLOCK(erst_lock);
  90
  91static 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
 108static 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
 121static 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
 127static 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
 133static 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
 139static 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
 146static 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
 153static 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
 167static 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
 181static 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
 198static 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
 227static 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
 245static 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
 252static 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
 258static 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
 264static int erst_exec_move_data(struct apei_exec_context *ctx,
 265                               struct acpi_whea_header *entry)
 266{
 267        int rc;
 268        u64 offset;
 269        void *src, *dst;
 270
 271        /* ioremap does not work in interrupt context */
 272        if (in_interrupt()) {
 273                pr_warning(ERST_PFX
 274                           "MOVE_DATA can not be used in interrupt context");
 275                return -EBUSY;
 276        }
 277
 278        rc = __apei_exec_read_register(entry, &offset);
 279        if (rc)
 280                return rc;
 281
 282        src = ioremap(ctx->src_base + offset, ctx->var2);
 283        if (!src)
 284                return -ENOMEM;
 285        dst = ioremap(ctx->dst_base + offset, ctx->var2);
 286        if (!dst)
 287                return -ENOMEM;
 288
 289        memmove(dst, src, ctx->var2);
 290
 291        iounmap(src);
 292        iounmap(dst);
 293
 294        return 0;
 295}
 296
 297static struct apei_exec_ins_type erst_ins_type[] = {
 298        [ACPI_ERST_READ_REGISTER] = {
 299                .flags = APEI_EXEC_INS_ACCESS_REGISTER,
 300                .run = apei_exec_read_register,
 301        },
 302        [ACPI_ERST_READ_REGISTER_VALUE] = {
 303                .flags = APEI_EXEC_INS_ACCESS_REGISTER,
 304                .run = apei_exec_read_register_value,
 305        },
 306        [ACPI_ERST_WRITE_REGISTER] = {
 307                .flags = APEI_EXEC_INS_ACCESS_REGISTER,
 308                .run = apei_exec_write_register,
 309        },
 310        [ACPI_ERST_WRITE_REGISTER_VALUE] = {
 311                .flags = APEI_EXEC_INS_ACCESS_REGISTER,
 312                .run = apei_exec_write_register_value,
 313        },
 314        [ACPI_ERST_NOOP] = {
 315                .flags = 0,
 316                .run = apei_exec_noop,
 317        },
 318        [ACPI_ERST_LOAD_VAR1] = {
 319                .flags = APEI_EXEC_INS_ACCESS_REGISTER,
 320                .run = erst_exec_load_var1,
 321        },
 322        [ACPI_ERST_LOAD_VAR2] = {
 323                .flags = APEI_EXEC_INS_ACCESS_REGISTER,
 324                .run = erst_exec_load_var2,
 325        },
 326        [ACPI_ERST_STORE_VAR1] = {
 327                .flags = APEI_EXEC_INS_ACCESS_REGISTER,
 328                .run = erst_exec_store_var1,
 329        },
 330        [ACPI_ERST_ADD] = {
 331                .flags = 0,
 332                .run = erst_exec_add,
 333        },
 334        [ACPI_ERST_SUBTRACT] = {
 335                .flags = 0,
 336                .run = erst_exec_subtract,
 337        },
 338        [ACPI_ERST_ADD_VALUE] = {
 339                .flags = APEI_EXEC_INS_ACCESS_REGISTER,
 340                .run = erst_exec_add_value,
 341        },
 342        [ACPI_ERST_SUBTRACT_VALUE] = {
 343                .flags = APEI_EXEC_INS_ACCESS_REGISTER,
 344                .run = erst_exec_subtract_value,
 345        },
 346        [ACPI_ERST_STALL] = {
 347                .flags = 0,
 348                .run = erst_exec_stall,
 349        },
 350        [ACPI_ERST_STALL_WHILE_TRUE] = {
 351                .flags = APEI_EXEC_INS_ACCESS_REGISTER,
 352                .run = erst_exec_stall_while_true,
 353        },
 354        [ACPI_ERST_SKIP_NEXT_IF_TRUE] = {
 355                .flags = APEI_EXEC_INS_ACCESS_REGISTER,
 356                .run = erst_exec_skip_next_instruction_if_true,
 357        },
 358        [ACPI_ERST_GOTO] = {
 359                .flags = 0,
 360                .run = erst_exec_goto,
 361        },
 362        [ACPI_ERST_SET_SRC_ADDRESS_BASE] = {
 363                .flags = APEI_EXEC_INS_ACCESS_REGISTER,
 364                .run = erst_exec_set_src_address_base,
 365        },
 366        [ACPI_ERST_SET_DST_ADDRESS_BASE] = {
 367                .flags = APEI_EXEC_INS_ACCESS_REGISTER,
 368                .run = erst_exec_set_dst_address_base,
 369        },
 370        [ACPI_ERST_MOVE_DATA] = {
 371                .flags = APEI_EXEC_INS_ACCESS_REGISTER,
 372                .run = erst_exec_move_data,
 373        },
 374};
 375
 376static inline void erst_exec_ctx_init(struct apei_exec_context *ctx)
 377{
 378        apei_exec_ctx_init(ctx, erst_ins_type, ARRAY_SIZE(erst_ins_type),
 379                           ERST_TAB_ENTRY(erst_tab), erst_tab->entries);
 380}
 381
 382static int erst_get_erange(struct erst_erange *range)
 383{
 384        struct apei_exec_context ctx;
 385        int rc;
 386
 387        erst_exec_ctx_init(&ctx);
 388        rc = apei_exec_run(&ctx, ACPI_ERST_GET_ERROR_RANGE);
 389        if (rc)
 390                return rc;
 391        range->base = apei_exec_ctx_get_output(&ctx);
 392        rc = apei_exec_run(&ctx, ACPI_ERST_GET_ERROR_LENGTH);
 393        if (rc)
 394                return rc;
 395        range->size = apei_exec_ctx_get_output(&ctx);
 396        rc = apei_exec_run(&ctx, ACPI_ERST_GET_ERROR_ATTRIBUTES);
 397        if (rc)
 398                return rc;
 399        range->attr = apei_exec_ctx_get_output(&ctx);
 400
 401        return 0;
 402}
 403
 404static ssize_t __erst_get_record_count(void)
 405{
 406        struct apei_exec_context ctx;
 407        int rc;
 408
 409        erst_exec_ctx_init(&ctx);
 410        rc = apei_exec_run(&ctx, ACPI_ERST_GET_RECORD_COUNT);
 411        if (rc)
 412                return rc;
 413        return apei_exec_ctx_get_output(&ctx);
 414}
 415
 416ssize_t erst_get_record_count(void)
 417{
 418        ssize_t count;
 419        unsigned long flags;
 420
 421        if (erst_disable)
 422                return -ENODEV;
 423
 424        raw_spin_lock_irqsave(&erst_lock, flags);
 425        count = __erst_get_record_count();
 426        raw_spin_unlock_irqrestore(&erst_lock, flags);
 427
 428        return count;
 429}
 430EXPORT_SYMBOL_GPL(erst_get_record_count);
 431
 432static int __erst_get_next_record_id(u64 *record_id)
 433{
 434        struct apei_exec_context ctx;
 435        int rc;
 436
 437        erst_exec_ctx_init(&ctx);
 438        rc = apei_exec_run(&ctx, ACPI_ERST_GET_RECORD_ID);
 439        if (rc)
 440                return rc;
 441        *record_id = apei_exec_ctx_get_output(&ctx);
 442
 443        return 0;
 444}
 445
 446/*
 447 * Get the record ID of an existing error record on the persistent
 448 * storage. If there is no error record on the persistent storage, the
 449 * returned record_id is APEI_ERST_INVALID_RECORD_ID.
 450 */
 451int erst_get_next_record_id(u64 *record_id)
 452{
 453        int rc;
 454        unsigned long flags;
 455
 456        if (erst_disable)
 457                return -ENODEV;
 458
 459        raw_spin_lock_irqsave(&erst_lock, flags);
 460        rc = __erst_get_next_record_id(record_id);
 461        raw_spin_unlock_irqrestore(&erst_lock, flags);
 462
 463        return rc;
 464}
 465EXPORT_SYMBOL_GPL(erst_get_next_record_id);
 466
 467static int __erst_write_to_storage(u64 offset)
 468{
 469        struct apei_exec_context ctx;
 470        u64 timeout = FIRMWARE_TIMEOUT;
 471        u64 val;
 472        int rc;
 473
 474        erst_exec_ctx_init(&ctx);
 475        rc = apei_exec_run(&ctx, ACPI_ERST_BEGIN_WRITE);
 476        if (rc)
 477                return rc;
 478        apei_exec_ctx_set_input(&ctx, offset);
 479        rc = apei_exec_run(&ctx, ACPI_ERST_SET_RECORD_OFFSET);
 480        if (rc)
 481                return rc;
 482        rc = apei_exec_run(&ctx, ACPI_ERST_EXECUTE_OPERATION);
 483        if (rc)
 484                return rc;
 485        for (;;) {
 486                rc = apei_exec_run(&ctx, ACPI_ERST_CHECK_BUSY_STATUS);
 487                if (rc)
 488                        return rc;
 489                val = apei_exec_ctx_get_output(&ctx);
 490                if (!val)
 491                        break;
 492                if (erst_timedout(&timeout, SPIN_UNIT))
 493                        return -EIO;
 494        }
 495        rc = apei_exec_run(&ctx, ACPI_ERST_GET_COMMAND_STATUS);
 496        if (rc)
 497                return rc;
 498        val = apei_exec_ctx_get_output(&ctx);
 499        rc = apei_exec_run(&ctx, ACPI_ERST_END);
 500        if (rc)
 501                return rc;
 502
 503        return erst_errno(val);
 504}
 505
 506static int __erst_read_from_storage(u64 record_id, u64 offset)
 507{
 508        struct apei_exec_context ctx;
 509        u64 timeout = FIRMWARE_TIMEOUT;
 510        u64 val;
 511        int rc;
 512
 513        erst_exec_ctx_init(&ctx);
 514        rc = apei_exec_run(&ctx, ACPI_ERST_BEGIN_READ);
 515        if (rc)
 516                return rc;
 517        apei_exec_ctx_set_input(&ctx, offset);
 518        rc = apei_exec_run(&ctx, ACPI_ERST_SET_RECORD_OFFSET);
 519        if (rc)
 520                return rc;
 521        apei_exec_ctx_set_input(&ctx, record_id);
 522        rc = apei_exec_run(&ctx, ACPI_ERST_SET_RECORD_ID);
 523        if (rc)
 524                return rc;
 525        rc = apei_exec_run(&ctx, ACPI_ERST_EXECUTE_OPERATION);
 526        if (rc)
 527                return rc;
 528        for (;;) {
 529                rc = apei_exec_run(&ctx, ACPI_ERST_CHECK_BUSY_STATUS);
 530                if (rc)
 531                        return rc;
 532                val = apei_exec_ctx_get_output(&ctx);
 533                if (!val)
 534                        break;
 535                if (erst_timedout(&timeout, SPIN_UNIT))
 536                        return -EIO;
 537        };
 538        rc = apei_exec_run(&ctx, ACPI_ERST_GET_COMMAND_STATUS);
 539        if (rc)
 540                return rc;
 541        val = apei_exec_ctx_get_output(&ctx);
 542        rc = apei_exec_run(&ctx, ACPI_ERST_END);
 543        if (rc)
 544                return rc;
 545
 546        return erst_errno(val);
 547}
 548
 549static int __erst_clear_from_storage(u64 record_id)
 550{
 551        struct apei_exec_context ctx;
 552        u64 timeout = FIRMWARE_TIMEOUT;
 553        u64 val;
 554        int rc;
 555
 556        erst_exec_ctx_init(&ctx);
 557        rc = apei_exec_run(&ctx, ACPI_ERST_BEGIN_CLEAR);
 558        if (rc)
 559                return rc;
 560        apei_exec_ctx_set_input(&ctx, record_id);
 561        rc = apei_exec_run(&ctx, ACPI_ERST_SET_RECORD_ID);
 562        if (rc)
 563                return rc;
 564        rc = apei_exec_run(&ctx, ACPI_ERST_EXECUTE_OPERATION);
 565        if (rc)
 566                return rc;
 567        for (;;) {
 568                rc = apei_exec_run(&ctx, ACPI_ERST_CHECK_BUSY_STATUS);
 569                if (rc)
 570                        return rc;
 571                val = apei_exec_ctx_get_output(&ctx);
 572                if (!val)
 573                        break;
 574                if (erst_timedout(&timeout, SPIN_UNIT))
 575                        return -EIO;
 576        }
 577        rc = apei_exec_run(&ctx, ACPI_ERST_GET_COMMAND_STATUS);
 578        if (rc)
 579                return rc;
 580        val = apei_exec_ctx_get_output(&ctx);
 581        rc = apei_exec_run(&ctx, ACPI_ERST_END);
 582        if (rc)
 583                return rc;
 584
 585        return erst_errno(val);
 586}
 587
 588/* NVRAM ERST Error Log Address Range is not supported yet */
 589static void pr_unimpl_nvram(void)
 590{
 591        if (printk_ratelimit())
 592                pr_warning(ERST_PFX
 593                "NVRAM ERST Log Address Range is not implemented yet\n");
 594}
 595
 596static int __erst_write_to_nvram(const struct cper_record_header *record)
 597{
 598        /* do not print message, because printk is not safe for NMI */
 599        return -ENOSYS;
 600}
 601
 602static int __erst_read_to_erange_from_nvram(u64 record_id, u64 *offset)
 603{
 604        pr_unimpl_nvram();
 605        return -ENOSYS;
 606}
 607
 608static int __erst_clear_from_nvram(u64 record_id)
 609{
 610        pr_unimpl_nvram();
 611        return -ENOSYS;
 612}
 613
 614int erst_write(const struct cper_record_header *record)
 615{
 616        int rc;
 617        unsigned long flags;
 618        struct cper_record_header *rcd_erange;
 619
 620        if (erst_disable)
 621                return -ENODEV;
 622
 623        if (memcmp(record->signature, CPER_SIG_RECORD, CPER_SIG_SIZE))
 624                return -EINVAL;
 625
 626        if (erst_erange.attr & ERST_RANGE_NVRAM) {
 627                if (!raw_spin_trylock_irqsave(&erst_lock, flags))
 628                        return -EBUSY;
 629                rc = __erst_write_to_nvram(record);
 630                raw_spin_unlock_irqrestore(&erst_lock, flags);
 631                return rc;
 632        }
 633
 634        if (record->record_length > erst_erange.size)
 635                return -EINVAL;
 636
 637        if (!raw_spin_trylock_irqsave(&erst_lock, flags))
 638                return -EBUSY;
 639        memcpy(erst_erange.vaddr, record, record->record_length);
 640        rcd_erange = erst_erange.vaddr;
 641        /* signature for serialization system */
 642        memcpy(&rcd_erange->persistence_information, "ER", 2);
 643
 644        rc = __erst_write_to_storage(0);
 645        raw_spin_unlock_irqrestore(&erst_lock, flags);
 646
 647        return rc;
 648}
 649EXPORT_SYMBOL_GPL(erst_write);
 650
 651static int __erst_read_to_erange(u64 record_id, u64 *offset)
 652{
 653        int rc;
 654
 655        if (erst_erange.attr & ERST_RANGE_NVRAM)
 656                return __erst_read_to_erange_from_nvram(
 657                        record_id, offset);
 658
 659        rc = __erst_read_from_storage(record_id, 0);
 660        if (rc)
 661                return rc;
 662        *offset = 0;
 663
 664        return 0;
 665}
 666
 667static ssize_t __erst_read(u64 record_id, struct cper_record_header *record,
 668                           size_t buflen)
 669{
 670        int rc;
 671        u64 offset, len = 0;
 672        struct cper_record_header *rcd_tmp;
 673
 674        rc = __erst_read_to_erange(record_id, &offset);
 675        if (rc)
 676                return rc;
 677        rcd_tmp = erst_erange.vaddr + offset;
 678        len = rcd_tmp->record_length;
 679        if (len <= buflen)
 680                memcpy(record, rcd_tmp, len);
 681
 682        return len;
 683}
 684
 685/*
 686 * If return value > buflen, the buffer size is not big enough,
 687 * else if return value < 0, something goes wrong,
 688 * else everything is OK, and return value is record length
 689 */
 690ssize_t erst_read(u64 record_id, struct cper_record_header *record,
 691                  size_t buflen)
 692{
 693        ssize_t len;
 694        unsigned long flags;
 695
 696        if (erst_disable)
 697                return -ENODEV;
 698
 699        raw_spin_lock_irqsave(&erst_lock, flags);
 700        len = __erst_read(record_id, record, buflen);
 701        raw_spin_unlock_irqrestore(&erst_lock, flags);
 702        return len;
 703}
 704EXPORT_SYMBOL_GPL(erst_read);
 705
 706/*
 707 * If return value > buflen, the buffer size is not big enough,
 708 * else if return value = 0, there is no more record to read,
 709 * else if return value < 0, something goes wrong,
 710 * else everything is OK, and return value is record length
 711 */
 712ssize_t erst_read_next(struct cper_record_header *record, size_t buflen)
 713{
 714        int rc;
 715        ssize_t len;
 716        unsigned long flags;
 717        u64 record_id;
 718
 719        if (erst_disable)
 720                return -ENODEV;
 721
 722        raw_spin_lock_irqsave(&erst_lock, flags);
 723        rc = __erst_get_next_record_id(&record_id);
 724        if (rc) {
 725                raw_spin_unlock_irqrestore(&erst_lock, flags);
 726                return rc;
 727        }
 728        /* no more record */
 729        if (record_id == APEI_ERST_INVALID_RECORD_ID) {
 730                raw_spin_unlock_irqrestore(&erst_lock, flags);
 731                return 0;
 732        }
 733
 734        len = __erst_read(record_id, record, buflen);
 735        raw_spin_unlock_irqrestore(&erst_lock, flags);
 736
 737        return len;
 738}
 739EXPORT_SYMBOL_GPL(erst_read_next);
 740
 741int erst_clear(u64 record_id)
 742{
 743        int rc;
 744        unsigned long flags;
 745
 746        if (erst_disable)
 747                return -ENODEV;
 748
 749        raw_spin_lock_irqsave(&erst_lock, flags);
 750        if (erst_erange.attr & ERST_RANGE_NVRAM)
 751                rc = __erst_clear_from_nvram(record_id);
 752        else
 753                rc = __erst_clear_from_storage(record_id);
 754        raw_spin_unlock_irqrestore(&erst_lock, flags);
 755
 756        return rc;
 757}
 758EXPORT_SYMBOL_GPL(erst_clear);
 759
 760static int __init setup_erst_disable(char *str)
 761{
 762        erst_disable = 1;
 763        return 0;
 764}
 765
 766__setup("erst_disable", setup_erst_disable);
 767
 768static int erst_check_table(struct acpi_table_erst *erst_tab)
 769{
 770        if ((erst_tab->header_length !=
 771             (sizeof(struct acpi_table_erst) - sizeof(erst_tab->header)))
 772            && (erst_tab->header_length != sizeof(struct acpi_table_einj)))
 773                return -EINVAL;
 774        if (erst_tab->header.length < sizeof(struct acpi_table_erst))
 775                return -EINVAL;
 776        if (erst_tab->entries !=
 777            (erst_tab->header.length - sizeof(struct acpi_table_erst)) /
 778            sizeof(struct acpi_erst_entry))
 779                return -EINVAL;
 780
 781        return 0;
 782}
 783
 784static int __init erst_init(void)
 785{
 786        int rc = 0;
 787        acpi_status status;
 788        struct apei_exec_context ctx;
 789        struct apei_resources erst_resources;
 790        struct resource *r;
 791
 792        if (acpi_disabled)
 793                goto err;
 794
 795        if (erst_disable) {
 796                pr_info(ERST_PFX
 797        "Error Record Serialization Table (ERST) support is disabled.\n");
 798                goto err;
 799        }
 800
 801        status = acpi_get_table(ACPI_SIG_ERST, 0,
 802                                (struct acpi_table_header **)&erst_tab);
 803        if (status == AE_NOT_FOUND) {
 804                pr_info(ERST_PFX "Table is not found!\n");
 805                goto err;
 806        } else if (ACPI_FAILURE(status)) {
 807                const char *msg = acpi_format_exception(status);
 808                pr_err(ERST_PFX "Failed to get table, %s\n", msg);
 809                rc = -EINVAL;
 810                goto err;
 811        }
 812
 813        rc = erst_check_table(erst_tab);
 814        if (rc) {
 815                pr_err(FW_BUG ERST_PFX "ERST table is invalid\n");
 816                goto err;
 817        }
 818
 819        apei_resources_init(&erst_resources);
 820        erst_exec_ctx_init(&ctx);
 821        rc = apei_exec_collect_resources(&ctx, &erst_resources);
 822        if (rc)
 823                goto err_fini;
 824        rc = apei_resources_request(&erst_resources, "APEI ERST");
 825        if (rc)
 826                goto err_fini;
 827        rc = apei_exec_pre_map_gars(&ctx);
 828        if (rc)
 829                goto err_release;
 830        rc = erst_get_erange(&erst_erange);
 831        if (rc) {
 832                if (rc == -ENODEV)
 833                        pr_info(ERST_PFX
 834        "The corresponding hardware device or firmware implementation "
 835        "is not available.\n");
 836                else
 837                        pr_err(ERST_PFX
 838                               "Failed to get Error Log Address Range.\n");
 839                goto err_unmap_reg;
 840        }
 841
 842        r = request_mem_region(erst_erange.base, erst_erange.size, "APEI ERST");
 843        if (!r) {
 844                pr_err(ERST_PFX
 845                "Can not request iomem region <0x%16llx-0x%16llx> for ERST.\n",
 846                (unsigned long long)erst_erange.base,
 847                (unsigned long long)erst_erange.base + erst_erange.size);
 848                rc = -EIO;
 849                goto err_unmap_reg;
 850        }
 851        rc = -ENOMEM;
 852        erst_erange.vaddr = ioremap_cache(erst_erange.base,
 853                                          erst_erange.size);
 854        if (!erst_erange.vaddr)
 855                goto err_release_erange;
 856
 857        pr_info(ERST_PFX
 858        "Error Record Serialization Table (ERST) support is initialized.\n");
 859
 860        return 0;
 861
 862err_release_erange:
 863        release_mem_region(erst_erange.base, erst_erange.size);
 864err_unmap_reg:
 865        apei_exec_post_unmap_gars(&ctx);
 866err_release:
 867        apei_resources_release(&erst_resources);
 868err_fini:
 869        apei_resources_fini(&erst_resources);
 870err:
 871        erst_disable = 1;
 872        return rc;
 873}
 874
 875device_initcall(erst_init);
 876