diff options
author | Len Brown <len.brown@intel.com> | 2011-03-23 02:34:54 -0400 |
---|---|---|
committer | Len Brown <len.brown@intel.com> | 2011-03-23 02:34:54 -0400 |
commit | 02e2407858fd62053bf60349c0e72cd1c7a4a60e (patch) | |
tree | 0ebdbddc97d3abbc675916010e7771065b70c137 /drivers/acpi/apei | |
parent | 96e1c408ea8a556c5b51e0e7d56bd2afbfbf5fe9 (diff) | |
parent | 6447f55da90b77faec1697d499ed7986bb4f6de6 (diff) |
Merge branch 'linus' into release
Conflicts:
arch/x86/kernel/acpi/sleep.c
Signed-off-by: Len Brown <len.brown@intel.com>
Diffstat (limited to 'drivers/acpi/apei')
-rw-r--r-- | drivers/acpi/apei/Kconfig | 1 | ||||
-rw-r--r-- | drivers/acpi/apei/erst.c | 136 |
2 files changed, 137 insertions, 0 deletions
diff --git a/drivers/acpi/apei/Kconfig b/drivers/acpi/apei/Kconfig index 9ecf6feae830..66a03caa2ad9 100644 --- a/drivers/acpi/apei/Kconfig +++ b/drivers/acpi/apei/Kconfig | |||
@@ -1,5 +1,6 @@ | |||
1 | config ACPI_APEI | 1 | config ACPI_APEI |
2 | bool "ACPI Platform Error Interface (APEI)" | 2 | bool "ACPI Platform Error Interface (APEI)" |
3 | select PSTORE | ||
3 | depends on X86 | 4 | depends on X86 |
4 | help | 5 | help |
5 | APEI allows to report errors (for example from the chipset) | 6 | APEI allows to report errors (for example from the chipset) |
diff --git a/drivers/acpi/apei/erst.c b/drivers/acpi/apei/erst.c index 8ff8c32fef58..d6cb0ff6988e 100644 --- a/drivers/acpi/apei/erst.c +++ b/drivers/acpi/apei/erst.c | |||
@@ -34,6 +34,7 @@ | |||
34 | #include <linux/cper.h> | 34 | #include <linux/cper.h> |
35 | #include <linux/nmi.h> | 35 | #include <linux/nmi.h> |
36 | #include <linux/hardirq.h> | 36 | #include <linux/hardirq.h> |
37 | #include <linux/pstore.h> | ||
37 | #include <acpi/apei.h> | 38 | #include <acpi/apei.h> |
38 | 39 | ||
39 | #include "apei-internal.h" | 40 | #include "apei-internal.h" |
@@ -928,6 +929,128 @@ static int erst_check_table(struct acpi_table_erst *erst_tab) | |||
928 | return 0; | 929 | return 0; |
929 | } | 930 | } |
930 | 931 | ||
932 | static size_t erst_reader(u64 *id, enum pstore_type_id *type, | ||
933 | struct timespec *time); | ||
934 | static u64 erst_writer(enum pstore_type_id type, size_t size); | ||
935 | |||
936 | static struct pstore_info erst_info = { | ||
937 | .owner = THIS_MODULE, | ||
938 | .name = "erst", | ||
939 | .read = erst_reader, | ||
940 | .write = erst_writer, | ||
941 | .erase = erst_clear | ||
942 | }; | ||
943 | |||
944 | #define CPER_CREATOR_PSTORE \ | ||
945 | UUID_LE(0x75a574e3, 0x5052, 0x4b29, 0x8a, 0x8e, 0xbe, 0x2c, \ | ||
946 | 0x64, 0x90, 0xb8, 0x9d) | ||
947 | #define CPER_SECTION_TYPE_DMESG \ | ||
948 | UUID_LE(0xc197e04e, 0xd545, 0x4a70, 0x9c, 0x17, 0xa5, 0x54, \ | ||
949 | 0x94, 0x19, 0xeb, 0x12) | ||
950 | #define CPER_SECTION_TYPE_MCE \ | ||
951 | UUID_LE(0xfe08ffbe, 0x95e4, 0x4be7, 0xbc, 0x73, 0x40, 0x96, \ | ||
952 | 0x04, 0x4a, 0x38, 0xfc) | ||
953 | |||
954 | struct cper_pstore_record { | ||
955 | struct cper_record_header hdr; | ||
956 | struct cper_section_descriptor sec_hdr; | ||
957 | char data[]; | ||
958 | } __packed; | ||
959 | |||
960 | static size_t erst_reader(u64 *id, enum pstore_type_id *type, | ||
961 | struct timespec *time) | ||
962 | { | ||
963 | int rc; | ||
964 | ssize_t len; | ||
965 | unsigned long flags; | ||
966 | u64 record_id; | ||
967 | struct cper_pstore_record *rcd = (struct cper_pstore_record *) | ||
968 | (erst_info.buf - sizeof(*rcd)); | ||
969 | |||
970 | if (erst_disable) | ||
971 | return -ENODEV; | ||
972 | |||
973 | raw_spin_lock_irqsave(&erst_lock, flags); | ||
974 | skip: | ||
975 | rc = __erst_get_next_record_id(&record_id); | ||
976 | if (rc) { | ||
977 | raw_spin_unlock_irqrestore(&erst_lock, flags); | ||
978 | return rc; | ||
979 | } | ||
980 | /* no more record */ | ||
981 | if (record_id == APEI_ERST_INVALID_RECORD_ID) { | ||
982 | raw_spin_unlock_irqrestore(&erst_lock, flags); | ||
983 | return 0; | ||
984 | } | ||
985 | |||
986 | len = __erst_read(record_id, &rcd->hdr, sizeof(*rcd) + | ||
987 | erst_erange.size); | ||
988 | if (uuid_le_cmp(rcd->hdr.creator_id, CPER_CREATOR_PSTORE) != 0) | ||
989 | goto skip; | ||
990 | raw_spin_unlock_irqrestore(&erst_lock, flags); | ||
991 | |||
992 | *id = record_id; | ||
993 | if (uuid_le_cmp(rcd->sec_hdr.section_type, | ||
994 | CPER_SECTION_TYPE_DMESG) == 0) | ||
995 | *type = PSTORE_TYPE_DMESG; | ||
996 | else if (uuid_le_cmp(rcd->sec_hdr.section_type, | ||
997 | CPER_SECTION_TYPE_MCE) == 0) | ||
998 | *type = PSTORE_TYPE_MCE; | ||
999 | else | ||
1000 | *type = PSTORE_TYPE_UNKNOWN; | ||
1001 | |||
1002 | if (rcd->hdr.validation_bits & CPER_VALID_TIMESTAMP) | ||
1003 | time->tv_sec = rcd->hdr.timestamp; | ||
1004 | else | ||
1005 | time->tv_sec = 0; | ||
1006 | time->tv_nsec = 0; | ||
1007 | |||
1008 | return len - sizeof(*rcd); | ||
1009 | } | ||
1010 | |||
1011 | static u64 erst_writer(enum pstore_type_id type, size_t size) | ||
1012 | { | ||
1013 | struct cper_pstore_record *rcd = (struct cper_pstore_record *) | ||
1014 | (erst_info.buf - sizeof(*rcd)); | ||
1015 | |||
1016 | memset(rcd, 0, sizeof(*rcd)); | ||
1017 | memcpy(rcd->hdr.signature, CPER_SIG_RECORD, CPER_SIG_SIZE); | ||
1018 | rcd->hdr.revision = CPER_RECORD_REV; | ||
1019 | rcd->hdr.signature_end = CPER_SIG_END; | ||
1020 | rcd->hdr.section_count = 1; | ||
1021 | rcd->hdr.error_severity = CPER_SEV_FATAL; | ||
1022 | /* timestamp valid. platform_id, partition_id are invalid */ | ||
1023 | rcd->hdr.validation_bits = CPER_VALID_TIMESTAMP; | ||
1024 | rcd->hdr.timestamp = get_seconds(); | ||
1025 | rcd->hdr.record_length = sizeof(*rcd) + size; | ||
1026 | rcd->hdr.creator_id = CPER_CREATOR_PSTORE; | ||
1027 | rcd->hdr.notification_type = CPER_NOTIFY_MCE; | ||
1028 | rcd->hdr.record_id = cper_next_record_id(); | ||
1029 | rcd->hdr.flags = CPER_HW_ERROR_FLAGS_PREVERR; | ||
1030 | |||
1031 | rcd->sec_hdr.section_offset = sizeof(*rcd); | ||
1032 | rcd->sec_hdr.section_length = size; | ||
1033 | rcd->sec_hdr.revision = CPER_SEC_REV; | ||
1034 | /* fru_id and fru_text is invalid */ | ||
1035 | rcd->sec_hdr.validation_bits = 0; | ||
1036 | rcd->sec_hdr.flags = CPER_SEC_PRIMARY; | ||
1037 | switch (type) { | ||
1038 | case PSTORE_TYPE_DMESG: | ||
1039 | rcd->sec_hdr.section_type = CPER_SECTION_TYPE_DMESG; | ||
1040 | break; | ||
1041 | case PSTORE_TYPE_MCE: | ||
1042 | rcd->sec_hdr.section_type = CPER_SECTION_TYPE_MCE; | ||
1043 | break; | ||
1044 | default: | ||
1045 | return -EINVAL; | ||
1046 | } | ||
1047 | rcd->sec_hdr.section_severity = CPER_SEV_FATAL; | ||
1048 | |||
1049 | erst_write(&rcd->hdr); | ||
1050 | |||
1051 | return rcd->hdr.record_id; | ||
1052 | } | ||
1053 | |||
931 | static int __init erst_init(void) | 1054 | static int __init erst_init(void) |
932 | { | 1055 | { |
933 | int rc = 0; | 1056 | int rc = 0; |
@@ -935,6 +1058,7 @@ static int __init erst_init(void) | |||
935 | struct apei_exec_context ctx; | 1058 | struct apei_exec_context ctx; |
936 | struct apei_resources erst_resources; | 1059 | struct apei_resources erst_resources; |
937 | struct resource *r; | 1060 | struct resource *r; |
1061 | char *buf; | ||
938 | 1062 | ||
939 | if (acpi_disabled) | 1063 | if (acpi_disabled) |
940 | goto err; | 1064 | goto err; |
@@ -1001,6 +1125,18 @@ static int __init erst_init(void) | |||
1001 | if (!erst_erange.vaddr) | 1125 | if (!erst_erange.vaddr) |
1002 | goto err_release_erange; | 1126 | goto err_release_erange; |
1003 | 1127 | ||
1128 | buf = kmalloc(erst_erange.size, GFP_KERNEL); | ||
1129 | mutex_init(&erst_info.buf_mutex); | ||
1130 | if (buf) { | ||
1131 | erst_info.buf = buf + sizeof(struct cper_pstore_record); | ||
1132 | erst_info.bufsize = erst_erange.size - | ||
1133 | sizeof(struct cper_pstore_record); | ||
1134 | if (pstore_register(&erst_info)) { | ||
1135 | pr_info(ERST_PFX "Could not register with persistent store\n"); | ||
1136 | kfree(buf); | ||
1137 | } | ||
1138 | } | ||
1139 | |||
1004 | pr_info(ERST_PFX | 1140 | pr_info(ERST_PFX |
1005 | "Error Record Serialization Table (ERST) support is initialized.\n"); | 1141 | "Error Record Serialization Table (ERST) support is initialized.\n"); |
1006 | 1142 | ||