diff options
28 files changed, 602 insertions, 150 deletions
diff --git a/arch/ia64/kernel/setup.c b/arch/ia64/kernel/setup.c index 4fc2e9569bb2..d86669bcdfb2 100644 --- a/arch/ia64/kernel/setup.c +++ b/arch/ia64/kernel/setup.c | |||
| @@ -1063,6 +1063,7 @@ check_bugs (void) | |||
| 1063 | static int __init run_dmi_scan(void) | 1063 | static int __init run_dmi_scan(void) |
| 1064 | { | 1064 | { |
| 1065 | dmi_scan_machine(); | 1065 | dmi_scan_machine(); |
| 1066 | dmi_memdev_walk(); | ||
| 1066 | dmi_set_dump_stack_arch_desc(); | 1067 | dmi_set_dump_stack_arch_desc(); |
| 1067 | return 0; | 1068 | return 0; |
| 1068 | } | 1069 | } |
diff --git a/arch/x86/include/asm/mce.h b/arch/x86/include/asm/mce.h index cbe6b9e404ce..c696a8687567 100644 --- a/arch/x86/include/asm/mce.h +++ b/arch/x86/include/asm/mce.h | |||
| @@ -16,6 +16,7 @@ | |||
| 16 | #define MCG_EXT_CNT_SHIFT 16 | 16 | #define MCG_EXT_CNT_SHIFT 16 |
| 17 | #define MCG_EXT_CNT(c) (((c) & MCG_EXT_CNT_MASK) >> MCG_EXT_CNT_SHIFT) | 17 | #define MCG_EXT_CNT(c) (((c) & MCG_EXT_CNT_MASK) >> MCG_EXT_CNT_SHIFT) |
| 18 | #define MCG_SER_P (1ULL<<24) /* MCA recovery/new status bits */ | 18 | #define MCG_SER_P (1ULL<<24) /* MCA recovery/new status bits */ |
| 19 | #define MCG_ELOG_P (1ULL<<26) /* Extended error log supported */ | ||
| 19 | 20 | ||
| 20 | /* MCG_STATUS register defines */ | 21 | /* MCG_STATUS register defines */ |
| 21 | #define MCG_STATUS_RIPV (1ULL<<0) /* restart ip valid */ | 22 | #define MCG_STATUS_RIPV (1ULL<<0) /* restart ip valid */ |
diff --git a/arch/x86/kernel/cpu/mcheck/mce-apei.c b/arch/x86/kernel/cpu/mcheck/mce-apei.c index cd8b166a1735..de8b60a53f69 100644 --- a/arch/x86/kernel/cpu/mcheck/mce-apei.c +++ b/arch/x86/kernel/cpu/mcheck/mce-apei.c | |||
| @@ -42,8 +42,7 @@ void apei_mce_report_mem_error(int corrected, struct cper_sec_mem_err *mem_err) | |||
| 42 | struct mce m; | 42 | struct mce m; |
| 43 | 43 | ||
| 44 | /* Only corrected MC is reported */ | 44 | /* Only corrected MC is reported */ |
| 45 | if (!corrected || !(mem_err->validation_bits & | 45 | if (!corrected || !(mem_err->validation_bits & CPER_MEM_VALID_PA)) |
| 46 | CPER_MEM_VALID_PHYSICAL_ADDRESS)) | ||
| 47 | return; | 46 | return; |
| 48 | 47 | ||
| 49 | mce_setup(&m); | 48 | mce_setup(&m); |
diff --git a/arch/x86/kernel/setup.c b/arch/x86/kernel/setup.c index f0de6294b955..918d489fa53d 100644 --- a/arch/x86/kernel/setup.c +++ b/arch/x86/kernel/setup.c | |||
| @@ -993,6 +993,7 @@ void __init setup_arch(char **cmdline_p) | |||
| 993 | efi_init(); | 993 | efi_init(); |
| 994 | 994 | ||
| 995 | dmi_scan_machine(); | 995 | dmi_scan_machine(); |
| 996 | dmi_memdev_walk(); | ||
| 996 | dmi_set_dump_stack_arch_desc(); | 997 | dmi_set_dump_stack_arch_desc(); |
| 997 | 998 | ||
| 998 | /* | 999 | /* |
diff --git a/drivers/acpi/Kconfig b/drivers/acpi/Kconfig index 6efe2ac6902f..e11faae81ed9 100644 --- a/drivers/acpi/Kconfig +++ b/drivers/acpi/Kconfig | |||
| @@ -372,4 +372,25 @@ config ACPI_BGRT | |||
| 372 | 372 | ||
| 373 | source "drivers/acpi/apei/Kconfig" | 373 | source "drivers/acpi/apei/Kconfig" |
| 374 | 374 | ||
| 375 | config ACPI_EXTLOG | ||
| 376 | tristate "Extended Error Log support" | ||
| 377 | depends on X86_MCE && X86_LOCAL_APIC | ||
| 378 | select EFI | ||
| 379 | select UEFI_CPER | ||
| 380 | default n | ||
| 381 | help | ||
| 382 | Certain usages such as Predictive Failure Analysis (PFA) require | ||
| 383 | more information about the error than what can be described in | ||
| 384 | processor machine check banks. Most server processors log | ||
| 385 | additional information about the error in processor uncore | ||
| 386 | registers. Since the addresses and layout of these registers vary | ||
| 387 | widely from one processor to another, system software cannot | ||
| 388 | readily make use of them. To complicate matters further, some of | ||
| 389 | the additional error information cannot be constructed without | ||
| 390 | detailed knowledge about platform topology. | ||
| 391 | |||
| 392 | Enhanced MCA Logging allows firmware to provide additional error | ||
| 393 | information to system software, synchronous with MCE or CMCI. This | ||
| 394 | driver adds support for that functionality. | ||
| 395 | |||
| 375 | endif # ACPI | 396 | endif # ACPI |
diff --git a/drivers/acpi/Makefile b/drivers/acpi/Makefile index cdaf68b58b00..bce34afadcd0 100644 --- a/drivers/acpi/Makefile +++ b/drivers/acpi/Makefile | |||
| @@ -82,3 +82,5 @@ processor-$(CONFIG_CPU_FREQ) += processor_perflib.o | |||
| 82 | obj-$(CONFIG_ACPI_PROCESSOR_AGGREGATOR) += acpi_pad.o | 82 | obj-$(CONFIG_ACPI_PROCESSOR_AGGREGATOR) += acpi_pad.o |
| 83 | 83 | ||
| 84 | obj-$(CONFIG_ACPI_APEI) += apei/ | 84 | obj-$(CONFIG_ACPI_APEI) += apei/ |
| 85 | |||
| 86 | obj-$(CONFIG_ACPI_EXTLOG) += acpi_extlog.o | ||
diff --git a/drivers/acpi/acpi_extlog.c b/drivers/acpi/acpi_extlog.c new file mode 100644 index 000000000000..a6869e110ce5 --- /dev/null +++ b/drivers/acpi/acpi_extlog.c | |||
| @@ -0,0 +1,327 @@ | |||
| 1 | /* | ||
| 2 | * Extended Error Log driver | ||
| 3 | * | ||
| 4 | * Copyright (C) 2013 Intel Corp. | ||
| 5 | * Author: Chen, Gong <gong.chen@intel.com> | ||
| 6 | * | ||
| 7 | * This file is licensed under GPLv2. | ||
| 8 | */ | ||
| 9 | |||
| 10 | #include <linux/module.h> | ||
| 11 | #include <linux/acpi.h> | ||
| 12 | #include <acpi/acpi_bus.h> | ||
| 13 | #include <linux/cper.h> | ||
| 14 | #include <linux/ratelimit.h> | ||
| 15 | #include <asm/cpu.h> | ||
| 16 | #include <asm/mce.h> | ||
| 17 | |||
| 18 | #include "apei/apei-internal.h" | ||
| 19 | |||
| 20 | #define EXT_ELOG_ENTRY_MASK GENMASK_ULL(51, 0) /* elog entry address mask */ | ||
| 21 | |||
| 22 | #define EXTLOG_DSM_REV 0x0 | ||
| 23 | #define EXTLOG_FN_QUERY 0x0 | ||
| 24 | #define EXTLOG_FN_ADDR 0x1 | ||
| 25 | |||
| 26 | #define FLAG_OS_OPTIN BIT(0) | ||
| 27 | #define EXTLOG_QUERY_L1_EXIST BIT(1) | ||
| 28 | #define ELOG_ENTRY_VALID (1ULL<<63) | ||
| 29 | #define ELOG_ENTRY_LEN 0x1000 | ||
| 30 | |||
| 31 | #define EMCA_BUG \ | ||
| 32 | "Can not request iomem region <0x%016llx-0x%016llx> - eMCA disabled\n" | ||
| 33 | |||
| 34 | struct extlog_l1_head { | ||
| 35 | u32 ver; /* Header Version */ | ||
| 36 | u32 hdr_len; /* Header Length */ | ||
| 37 | u64 total_len; /* entire L1 Directory length including this header */ | ||
| 38 | u64 elog_base; /* MCA Error Log Directory base address */ | ||
| 39 | u64 elog_len; /* MCA Error Log Directory length */ | ||
| 40 | u32 flags; /* bit 0 - OS/VMM Opt-in */ | ||
| 41 | u8 rev0[12]; | ||
| 42 | u32 entries; /* Valid L1 Directory entries per logical processor */ | ||
| 43 | u8 rev1[12]; | ||
| 44 | }; | ||
| 45 | |||
| 46 | static u8 extlog_dsm_uuid[] = "663E35AF-CC10-41A4-88EA-5470AF055295"; | ||
| 47 | |||
| 48 | /* L1 table related physical address */ | ||
| 49 | static u64 elog_base; | ||
| 50 | static size_t elog_size; | ||
| 51 | static u64 l1_dirbase; | ||
| 52 | static size_t l1_size; | ||
| 53 | |||
| 54 | /* L1 table related virtual address */ | ||
| 55 | static void __iomem *extlog_l1_addr; | ||
| 56 | static void __iomem *elog_addr; | ||
| 57 | |||
| 58 | static void *elog_buf; | ||
| 59 | |||
| 60 | static u64 *l1_entry_base; | ||
| 61 | static u32 l1_percpu_entry; | ||
| 62 | |||
| 63 | #define ELOG_IDX(cpu, bank) \ | ||
| 64 | (cpu_physical_id(cpu) * l1_percpu_entry + (bank)) | ||
| 65 | |||
| 66 | #define ELOG_ENTRY_DATA(idx) \ | ||
| 67 | (*(l1_entry_base + (idx))) | ||
| 68 | |||
| 69 | #define ELOG_ENTRY_ADDR(phyaddr) \ | ||
| 70 | (phyaddr - elog_base + (u8 *)elog_addr) | ||
| 71 | |||
| 72 | static struct acpi_generic_status *extlog_elog_entry_check(int cpu, int bank) | ||
| 73 | { | ||
| 74 | int idx; | ||
| 75 | u64 data; | ||
| 76 | struct acpi_generic_status *estatus; | ||
| 77 | |||
| 78 | WARN_ON(cpu < 0); | ||
| 79 | idx = ELOG_IDX(cpu, bank); | ||
| 80 | data = ELOG_ENTRY_DATA(idx); | ||
| 81 | if ((data & ELOG_ENTRY_VALID) == 0) | ||
| 82 | return NULL; | ||
| 83 | |||
| 84 | data &= EXT_ELOG_ENTRY_MASK; | ||
| 85 | estatus = (struct acpi_generic_status *)ELOG_ENTRY_ADDR(data); | ||
| 86 | |||
| 87 | /* if no valid data in elog entry, just return */ | ||
| 88 | if (estatus->block_status == 0) | ||
| 89 | return NULL; | ||
| 90 | |||
| 91 | return estatus; | ||
| 92 | } | ||
| 93 | |||
| 94 | static void __print_extlog_rcd(const char *pfx, | ||
| 95 | struct acpi_generic_status *estatus, int cpu) | ||
| 96 | { | ||
| 97 | static atomic_t seqno; | ||
| 98 | unsigned int curr_seqno; | ||
| 99 | char pfx_seq[64]; | ||
| 100 | |||
| 101 | if (!pfx) { | ||
| 102 | if (estatus->error_severity <= CPER_SEV_CORRECTED) | ||
| 103 | pfx = KERN_INFO; | ||
| 104 | else | ||
| 105 | pfx = KERN_ERR; | ||
| 106 | } | ||
| 107 | curr_seqno = atomic_inc_return(&seqno); | ||
| 108 | snprintf(pfx_seq, sizeof(pfx_seq), "%s{%u}", pfx, curr_seqno); | ||
| 109 | printk("%s""Hardware error detected on CPU%d\n", pfx_seq, cpu); | ||
| 110 | cper_estatus_print(pfx_seq, estatus); | ||
| 111 | } | ||
| 112 | |||
| 113 | static int print_extlog_rcd(const char *pfx, | ||
| 114 | struct acpi_generic_status *estatus, int cpu) | ||
| 115 | { | ||
| 116 | /* Not more than 2 messages every 5 seconds */ | ||
| 117 | static DEFINE_RATELIMIT_STATE(ratelimit_corrected, 5*HZ, 2); | ||
| 118 | static DEFINE_RATELIMIT_STATE(ratelimit_uncorrected, 5*HZ, 2); | ||
| 119 | struct ratelimit_state *ratelimit; | ||
| 120 | |||
| 121 | if (estatus->error_severity == CPER_SEV_CORRECTED || | ||
| 122 | (estatus->error_severity == CPER_SEV_INFORMATIONAL)) | ||
| 123 | ratelimit = &ratelimit_corrected; | ||
| 124 | else | ||
| 125 | ratelimit = &ratelimit_uncorrected; | ||
| 126 | if (__ratelimit(ratelimit)) { | ||
| 127 | __print_extlog_rcd(pfx, estatus, cpu); | ||
| 128 | return 0; | ||
| 129 | } | ||
| 130 | |||
| 131 | return 1; | ||
| 132 | } | ||
| 133 | |||
| 134 | static int extlog_print(struct notifier_block *nb, unsigned long val, | ||
| 135 | void *data) | ||
| 136 | { | ||
| 137 | struct mce *mce = (struct mce *)data; | ||
| 138 | int bank = mce->bank; | ||
| 139 | int cpu = mce->extcpu; | ||
| 140 | struct acpi_generic_status *estatus; | ||
| 141 | int rc; | ||
| 142 | |||
| 143 | estatus = extlog_elog_entry_check(cpu, bank); | ||
| 144 | if (estatus == NULL) | ||
| 145 | return NOTIFY_DONE; | ||
| 146 | |||
| 147 | memcpy(elog_buf, (void *)estatus, ELOG_ENTRY_LEN); | ||
| 148 | /* clear record status to enable BIOS to update it again */ | ||
| 149 | estatus->block_status = 0; | ||
| 150 | |||
| 151 | rc = print_extlog_rcd(NULL, (struct acpi_generic_status *)elog_buf, cpu); | ||
| 152 | |||
| 153 | return NOTIFY_DONE; | ||
| 154 | } | ||
| 155 | |||
| 156 | static int extlog_get_dsm(acpi_handle handle, int rev, int func, u64 *ret) | ||
| 157 | { | ||
| 158 | struct acpi_buffer buf = {ACPI_ALLOCATE_BUFFER, NULL}; | ||
| 159 | struct acpi_object_list input; | ||
| 160 | union acpi_object params[4], *obj; | ||
| 161 | u8 uuid[16]; | ||
| 162 | int i; | ||
| 163 | |||
| 164 | acpi_str_to_uuid(extlog_dsm_uuid, uuid); | ||
| 165 | input.count = 4; | ||
| 166 | input.pointer = params; | ||
| 167 | params[0].type = ACPI_TYPE_BUFFER; | ||
| 168 | params[0].buffer.length = 16; | ||
| 169 | params[0].buffer.pointer = uuid; | ||
| 170 | params[1].type = ACPI_TYPE_INTEGER; | ||
| 171 | params[1].integer.value = rev; | ||
| 172 | params[2].type = ACPI_TYPE_INTEGER; | ||
| 173 | params[2].integer.value = func; | ||
| 174 | params[3].type = ACPI_TYPE_PACKAGE; | ||
| 175 | params[3].package.count = 0; | ||
| 176 | params[3].package.elements = NULL; | ||
| 177 | |||
| 178 | if (ACPI_FAILURE(acpi_evaluate_object(handle, "_DSM", &input, &buf))) | ||
| 179 | return -1; | ||
| 180 | |||
| 181 | *ret = 0; | ||
| 182 | obj = (union acpi_object *)buf.pointer; | ||
| 183 | if (obj->type == ACPI_TYPE_INTEGER) { | ||
| 184 | *ret = obj->integer.value; | ||
| 185 | } else if (obj->type == ACPI_TYPE_BUFFER) { | ||
| 186 | if (obj->buffer.length <= 8) { | ||
| 187 | for (i = 0; i < obj->buffer.length; i++) | ||
| 188 | *ret |= (obj->buffer.pointer[i] << (i * 8)); | ||
| 189 | } | ||
| 190 | } | ||
| 191 | kfree(buf.pointer); | ||
| 192 | |||
| 193 | return 0; | ||
| 194 | } | ||
| 195 | |||
| 196 | static bool extlog_get_l1addr(void) | ||
| 197 | { | ||
| 198 | acpi_handle handle; | ||
| 199 | u64 ret; | ||
| 200 | |||
| 201 | if (ACPI_FAILURE(acpi_get_handle(NULL, "\\_SB", &handle))) | ||
| 202 | return false; | ||
| 203 | |||
| 204 | if (extlog_get_dsm(handle, EXTLOG_DSM_REV, EXTLOG_FN_QUERY, &ret) || | ||
| 205 | !(ret & EXTLOG_QUERY_L1_EXIST)) | ||
| 206 | return false; | ||
| 207 | |||
| 208 | if (extlog_get_dsm(handle, EXTLOG_DSM_REV, EXTLOG_FN_ADDR, &ret)) | ||
| 209 | return false; | ||
| 210 | |||
| 211 | l1_dirbase = ret; | ||
| 212 | /* Spec says L1 directory must be 4K aligned, bail out if it isn't */ | ||
| 213 | if (l1_dirbase & ((1 << 12) - 1)) { | ||
| 214 | pr_warn(FW_BUG "L1 Directory is invalid at physical %llx\n", | ||
| 215 | l1_dirbase); | ||
| 216 | return false; | ||
| 217 | } | ||
| 218 | |||
| 219 | return true; | ||
| 220 | } | ||
| 221 | static struct notifier_block extlog_mce_dec = { | ||
| 222 | .notifier_call = extlog_print, | ||
| 223 | }; | ||
| 224 | |||
| 225 | static int __init extlog_init(void) | ||
| 226 | { | ||
| 227 | struct extlog_l1_head *l1_head; | ||
| 228 | void __iomem *extlog_l1_hdr; | ||
| 229 | size_t l1_hdr_size; | ||
| 230 | struct resource *r; | ||
| 231 | u64 cap; | ||
| 232 | int rc; | ||
| 233 | |||
| 234 | rc = -ENODEV; | ||
| 235 | |||
| 236 | rdmsrl(MSR_IA32_MCG_CAP, cap); | ||
| 237 | if (!(cap & MCG_ELOG_P)) | ||
| 238 | return rc; | ||
| 239 | |||
| 240 | if (!extlog_get_l1addr()) | ||
| 241 | return rc; | ||
| 242 | |||
| 243 | rc = -EINVAL; | ||
| 244 | /* get L1 header to fetch necessary information */ | ||
| 245 | l1_hdr_size = sizeof(struct extlog_l1_head); | ||
| 246 | r = request_mem_region(l1_dirbase, l1_hdr_size, "L1 DIR HDR"); | ||
| 247 | if (!r) { | ||
| 248 | pr_warn(FW_BUG EMCA_BUG, | ||
| 249 | (unsigned long long)l1_dirbase, | ||
| 250 | (unsigned long long)l1_dirbase + l1_hdr_size); | ||
| 251 | goto err; | ||
| 252 | } | ||
| 253 | |||
| 254 | extlog_l1_hdr = acpi_os_map_memory(l1_dirbase, l1_hdr_size); | ||
| 255 | l1_head = (struct extlog_l1_head *)extlog_l1_hdr; | ||
| 256 | l1_size = l1_head->total_len; | ||
| 257 | l1_percpu_entry = l1_head->entries; | ||
| 258 | elog_base = l1_head->elog_base; | ||
| 259 | elog_size = l1_head->elog_len; | ||
| 260 | acpi_os_unmap_memory(extlog_l1_hdr, l1_hdr_size); | ||
| 261 | release_mem_region(l1_dirbase, l1_hdr_size); | ||
| 262 | |||
| 263 | /* remap L1 header again based on completed information */ | ||
| 264 | r = request_mem_region(l1_dirbase, l1_size, "L1 Table"); | ||
| 265 | if (!r) { | ||
| 266 | pr_warn(FW_BUG EMCA_BUG, | ||
| 267 | (unsigned long long)l1_dirbase, | ||
| 268 | (unsigned long long)l1_dirbase + l1_size); | ||
| 269 | goto err; | ||
| 270 | } | ||
| 271 | extlog_l1_addr = acpi_os_map_memory(l1_dirbase, l1_size); | ||
| 272 | l1_entry_base = (u64 *)((u8 *)extlog_l1_addr + l1_hdr_size); | ||
| 273 | |||
| 274 | /* remap elog table */ | ||
| 275 | r = request_mem_region(elog_base, elog_size, "Elog Table"); | ||
| 276 | if (!r) { | ||
| 277 | pr_warn(FW_BUG EMCA_BUG, | ||
| 278 | (unsigned long long)elog_base, | ||
| 279 | (unsigned long long)elog_base + elog_size); | ||
| 280 | goto err_release_l1_dir; | ||
| 281 | } | ||
| 282 | elog_addr = acpi_os_map_memory(elog_base, elog_size); | ||
| 283 | |||
| 284 | rc = -ENOMEM; | ||
| 285 | /* allocate buffer to save elog record */ | ||
| 286 | elog_buf = kmalloc(ELOG_ENTRY_LEN, GFP_KERNEL); | ||
| 287 | if (elog_buf == NULL) | ||
| 288 | goto err_release_elog; | ||
| 289 | |||
| 290 | mce_register_decode_chain(&extlog_mce_dec); | ||
| 291 | /* enable OS to be involved to take over management from BIOS */ | ||
| 292 | ((struct extlog_l1_head *)extlog_l1_addr)->flags |= FLAG_OS_OPTIN; | ||
| 293 | |||
| 294 | return 0; | ||
| 295 | |||
| 296 | err_release_elog: | ||
| 297 | if (elog_addr) | ||
| 298 | acpi_os_unmap_memory(elog_addr, elog_size); | ||
| 299 | release_mem_region(elog_base, elog_size); | ||
| 300 | err_release_l1_dir: | ||
| 301 | if (extlog_l1_addr) | ||
| 302 | acpi_os_unmap_memory(extlog_l1_addr, l1_size); | ||
| 303 | release_mem_region(l1_dirbase, l1_size); | ||
| 304 | err: | ||
| 305 | pr_warn(FW_BUG "Extended error log disabled because of problems parsing f/w tables\n"); | ||
| 306 | return rc; | ||
| 307 | } | ||
| 308 | |||
| 309 | static void __exit extlog_exit(void) | ||
| 310 | { | ||
| 311 | mce_unregister_decode_chain(&extlog_mce_dec); | ||
| 312 | ((struct extlog_l1_head *)extlog_l1_addr)->flags &= ~FLAG_OS_OPTIN; | ||
| 313 | if (extlog_l1_addr) | ||
| 314 | acpi_os_unmap_memory(extlog_l1_addr, l1_size); | ||
| 315 | if (elog_addr) | ||
| 316 | acpi_os_unmap_memory(elog_addr, elog_size); | ||
| 317 | release_mem_region(elog_base, elog_size); | ||
| 318 | release_mem_region(l1_dirbase, l1_size); | ||
| 319 | kfree(elog_buf); | ||
| 320 | } | ||
| 321 | |||
| 322 | module_init(extlog_init); | ||
| 323 | module_exit(extlog_exit); | ||
| 324 | |||
| 325 | MODULE_AUTHOR("Chen, Gong <gong.chen@intel.com>"); | ||
| 326 | MODULE_DESCRIPTION("Extended MCA Error Log Driver"); | ||
| 327 | MODULE_LICENSE("GPL"); | ||
diff --git a/drivers/acpi/apei/Kconfig b/drivers/acpi/apei/Kconfig index f0c1ce95a0ec..786294bb682c 100644 --- a/drivers/acpi/apei/Kconfig +++ b/drivers/acpi/apei/Kconfig | |||
| @@ -2,6 +2,8 @@ config ACPI_APEI | |||
| 2 | bool "ACPI Platform Error Interface (APEI)" | 2 | bool "ACPI Platform Error Interface (APEI)" |
| 3 | select MISC_FILESYSTEMS | 3 | select MISC_FILESYSTEMS |
| 4 | select PSTORE | 4 | select PSTORE |
| 5 | select EFI | ||
| 6 | select UEFI_CPER | ||
| 5 | depends on X86 | 7 | depends on X86 |
| 6 | help | 8 | help |
| 7 | APEI allows to report errors (for example from the chipset) | 9 | APEI allows to report errors (for example from the chipset) |
diff --git a/drivers/acpi/apei/Makefile b/drivers/acpi/apei/Makefile index d1d1bc0a4ee1..5d575a955940 100644 --- a/drivers/acpi/apei/Makefile +++ b/drivers/acpi/apei/Makefile | |||
| @@ -3,4 +3,4 @@ obj-$(CONFIG_ACPI_APEI_GHES) += ghes.o | |||
| 3 | obj-$(CONFIG_ACPI_APEI_EINJ) += einj.o | 3 | obj-$(CONFIG_ACPI_APEI_EINJ) += einj.o |
| 4 | obj-$(CONFIG_ACPI_APEI_ERST_DEBUG) += erst-dbg.o | 4 | obj-$(CONFIG_ACPI_APEI_ERST_DEBUG) += erst-dbg.o |
| 5 | 5 | ||
| 6 | apei-y := apei-base.o hest.o cper.o erst.o | 6 | apei-y := apei-base.o hest.o erst.o |
diff --git a/drivers/acpi/apei/apei-internal.h b/drivers/acpi/apei/apei-internal.h index f220d642136e..21ba34a73883 100644 --- a/drivers/acpi/apei/apei-internal.h +++ b/drivers/acpi/apei/apei-internal.h | |||
| @@ -122,11 +122,11 @@ struct dentry; | |||
| 122 | struct dentry *apei_get_debugfs_dir(void); | 122 | struct dentry *apei_get_debugfs_dir(void); |
| 123 | 123 | ||
| 124 | #define apei_estatus_for_each_section(estatus, section) \ | 124 | #define apei_estatus_for_each_section(estatus, section) \ |
| 125 | for (section = (struct acpi_hest_generic_data *)(estatus + 1); \ | 125 | for (section = (struct acpi_generic_data *)(estatus + 1); \ |
| 126 | (void *)section - (void *)estatus < estatus->data_length; \ | 126 | (void *)section - (void *)estatus < estatus->data_length; \ |
| 127 | section = (void *)(section+1) + section->error_data_length) | 127 | section = (void *)(section+1) + section->error_data_length) |
| 128 | 128 | ||
| 129 | static inline u32 apei_estatus_len(struct acpi_hest_generic_status *estatus) | 129 | static inline u32 cper_estatus_len(struct acpi_generic_status *estatus) |
| 130 | { | 130 | { |
| 131 | if (estatus->raw_data_length) | 131 | if (estatus->raw_data_length) |
| 132 | return estatus->raw_data_offset + \ | 132 | return estatus->raw_data_offset + \ |
| @@ -135,10 +135,10 @@ static inline u32 apei_estatus_len(struct acpi_hest_generic_status *estatus) | |||
| 135 | return sizeof(*estatus) + estatus->data_length; | 135 | return sizeof(*estatus) + estatus->data_length; |
| 136 | } | 136 | } |
| 137 | 137 | ||
| 138 | void apei_estatus_print(const char *pfx, | 138 | void cper_estatus_print(const char *pfx, |
| 139 | const struct acpi_hest_generic_status *estatus); | 139 | const struct acpi_generic_status *estatus); |
| 140 | int apei_estatus_check_header(const struct acpi_hest_generic_status *estatus); | 140 | int cper_estatus_check_header(const struct acpi_generic_status *estatus); |
| 141 | int apei_estatus_check(const struct acpi_hest_generic_status *estatus); | 141 | int cper_estatus_check(const struct acpi_generic_status *estatus); |
| 142 | 142 | ||
| 143 | int apei_osc_setup(void); | 143 | int apei_osc_setup(void); |
| 144 | #endif | 144 | #endif |
diff --git a/drivers/acpi/apei/ghes.c b/drivers/acpi/apei/ghes.c index 8ec37bbdd699..a30bc313787b 100644 --- a/drivers/acpi/apei/ghes.c +++ b/drivers/acpi/apei/ghes.c | |||
| @@ -75,13 +75,13 @@ | |||
| 75 | #define GHES_ESTATUS_CACHE_LEN(estatus_len) \ | 75 | #define GHES_ESTATUS_CACHE_LEN(estatus_len) \ |
| 76 | (sizeof(struct ghes_estatus_cache) + (estatus_len)) | 76 | (sizeof(struct ghes_estatus_cache) + (estatus_len)) |
| 77 | #define GHES_ESTATUS_FROM_CACHE(estatus_cache) \ | 77 | #define GHES_ESTATUS_FROM_CACHE(estatus_cache) \ |
| 78 | ((struct acpi_hest_generic_status *) \ | 78 | ((struct acpi_generic_status *) \ |
| 79 | ((struct ghes_estatus_cache *)(estatus_cache) + 1)) | 79 | ((struct ghes_estatus_cache *)(estatus_cache) + 1)) |
| 80 | 80 | ||
| 81 | #define GHES_ESTATUS_NODE_LEN(estatus_len) \ | 81 | #define GHES_ESTATUS_NODE_LEN(estatus_len) \ |
| 82 | (sizeof(struct ghes_estatus_node) + (estatus_len)) | 82 | (sizeof(struct ghes_estatus_node) + (estatus_len)) |
| 83 | #define GHES_ESTATUS_FROM_NODE(estatus_node) \ | 83 | #define GHES_ESTATUS_FROM_NODE(estatus_node) \ |
| 84 | ((struct acpi_hest_generic_status *) \ | 84 | ((struct acpi_generic_status *) \ |
| 85 | ((struct ghes_estatus_node *)(estatus_node) + 1)) | 85 | ((struct ghes_estatus_node *)(estatus_node) + 1)) |
| 86 | 86 | ||
| 87 | bool ghes_disable; | 87 | bool ghes_disable; |
| @@ -378,17 +378,17 @@ static int ghes_read_estatus(struct ghes *ghes, int silent) | |||
| 378 | ghes->flags |= GHES_TO_CLEAR; | 378 | ghes->flags |= GHES_TO_CLEAR; |
| 379 | 379 | ||
| 380 | rc = -EIO; | 380 | rc = -EIO; |
| 381 | len = apei_estatus_len(ghes->estatus); | 381 | len = cper_estatus_len(ghes->estatus); |
| 382 | if (len < sizeof(*ghes->estatus)) | 382 | if (len < sizeof(*ghes->estatus)) |
| 383 | goto err_read_block; | 383 | goto err_read_block; |
| 384 | if (len > ghes->generic->error_block_length) | 384 | if (len > ghes->generic->error_block_length) |
| 385 | goto err_read_block; | 385 | goto err_read_block; |
| 386 | if (apei_estatus_check_header(ghes->estatus)) | 386 | if (cper_estatus_check_header(ghes->estatus)) |
| 387 | goto err_read_block; | 387 | goto err_read_block; |
| 388 | ghes_copy_tofrom_phys(ghes->estatus + 1, | 388 | ghes_copy_tofrom_phys(ghes->estatus + 1, |
| 389 | buf_paddr + sizeof(*ghes->estatus), | 389 | buf_paddr + sizeof(*ghes->estatus), |
| 390 | len - sizeof(*ghes->estatus), 1); | 390 | len - sizeof(*ghes->estatus), 1); |
| 391 | if (apei_estatus_check(ghes->estatus)) | 391 | if (cper_estatus_check(ghes->estatus)) |
| 392 | goto err_read_block; | 392 | goto err_read_block; |
| 393 | rc = 0; | 393 | rc = 0; |
| 394 | 394 | ||
| @@ -409,7 +409,7 @@ static void ghes_clear_estatus(struct ghes *ghes) | |||
| 409 | ghes->flags &= ~GHES_TO_CLEAR; | 409 | ghes->flags &= ~GHES_TO_CLEAR; |
| 410 | } | 410 | } |
| 411 | 411 | ||
| 412 | static void ghes_handle_memory_failure(struct acpi_hest_generic_data *gdata, int sev) | 412 | static void ghes_handle_memory_failure(struct acpi_generic_data *gdata, int sev) |
| 413 | { | 413 | { |
| 414 | #ifdef CONFIG_ACPI_APEI_MEMORY_FAILURE | 414 | #ifdef CONFIG_ACPI_APEI_MEMORY_FAILURE |
| 415 | unsigned long pfn; | 415 | unsigned long pfn; |
| @@ -419,7 +419,7 @@ static void ghes_handle_memory_failure(struct acpi_hest_generic_data *gdata, int | |||
| 419 | 419 | ||
| 420 | if (sec_sev == GHES_SEV_CORRECTED && | 420 | if (sec_sev == GHES_SEV_CORRECTED && |
| 421 | (gdata->flags & CPER_SEC_ERROR_THRESHOLD_EXCEEDED) && | 421 | (gdata->flags & CPER_SEC_ERROR_THRESHOLD_EXCEEDED) && |
| 422 | (mem_err->validation_bits & CPER_MEM_VALID_PHYSICAL_ADDRESS)) { | 422 | (mem_err->validation_bits & CPER_MEM_VALID_PA)) { |
| 423 | pfn = mem_err->physical_addr >> PAGE_SHIFT; | 423 | pfn = mem_err->physical_addr >> PAGE_SHIFT; |
| 424 | if (pfn_valid(pfn)) | 424 | if (pfn_valid(pfn)) |
| 425 | memory_failure_queue(pfn, 0, MF_SOFT_OFFLINE); | 425 | memory_failure_queue(pfn, 0, MF_SOFT_OFFLINE); |
| @@ -430,7 +430,7 @@ static void ghes_handle_memory_failure(struct acpi_hest_generic_data *gdata, int | |||
| 430 | } | 430 | } |
| 431 | if (sev == GHES_SEV_RECOVERABLE && | 431 | if (sev == GHES_SEV_RECOVERABLE && |
| 432 | sec_sev == GHES_SEV_RECOVERABLE && | 432 | sec_sev == GHES_SEV_RECOVERABLE && |
| 433 | mem_err->validation_bits & CPER_MEM_VALID_PHYSICAL_ADDRESS) { | 433 | mem_err->validation_bits & CPER_MEM_VALID_PA) { |
| 434 | pfn = mem_err->physical_addr >> PAGE_SHIFT; | 434 | pfn = mem_err->physical_addr >> PAGE_SHIFT; |
| 435 | memory_failure_queue(pfn, 0, 0); | 435 | memory_failure_queue(pfn, 0, 0); |
| 436 | } | 436 | } |
| @@ -438,10 +438,10 @@ static void ghes_handle_memory_failure(struct acpi_hest_generic_data *gdata, int | |||
| 438 | } | 438 | } |
| 439 | 439 | ||
| 440 | static void ghes_do_proc(struct ghes *ghes, | 440 | static void ghes_do_proc(struct ghes *ghes, |
| 441 | const struct acpi_hest_generic_status *estatus) | 441 | const struct acpi_generic_status *estatus) |
| 442 | { | 442 | { |
| 443 | int sev, sec_sev; | 443 | int sev, sec_sev; |
| 444 | struct acpi_hest_generic_data *gdata; | 444 | struct acpi_generic_data *gdata; |
| 445 | 445 | ||
| 446 | sev = ghes_severity(estatus->error_severity); | 446 | sev = ghes_severity(estatus->error_severity); |
| 447 | apei_estatus_for_each_section(estatus, gdata) { | 447 | apei_estatus_for_each_section(estatus, gdata) { |
| @@ -496,7 +496,7 @@ static void ghes_do_proc(struct ghes *ghes, | |||
| 496 | 496 | ||
| 497 | static void __ghes_print_estatus(const char *pfx, | 497 | static void __ghes_print_estatus(const char *pfx, |
| 498 | const struct acpi_hest_generic *generic, | 498 | const struct acpi_hest_generic *generic, |
| 499 | const struct acpi_hest_generic_status *estatus) | 499 | const struct acpi_generic_status *estatus) |
| 500 | { | 500 | { |
| 501 | static atomic_t seqno; | 501 | static atomic_t seqno; |
| 502 | unsigned int curr_seqno; | 502 | unsigned int curr_seqno; |
| @@ -513,12 +513,12 @@ static void __ghes_print_estatus(const char *pfx, | |||
| 513 | snprintf(pfx_seq, sizeof(pfx_seq), "%s{%u}" HW_ERR, pfx, curr_seqno); | 513 | snprintf(pfx_seq, sizeof(pfx_seq), "%s{%u}" HW_ERR, pfx, curr_seqno); |
| 514 | printk("%s""Hardware error from APEI Generic Hardware Error Source: %d\n", | 514 | printk("%s""Hardware error from APEI Generic Hardware Error Source: %d\n", |
| 515 | pfx_seq, generic->header.source_id); | 515 | pfx_seq, generic->header.source_id); |
| 516 | apei_estatus_print(pfx_seq, estatus); | 516 | cper_estatus_print(pfx_seq, estatus); |
| 517 | } | 517 | } |
| 518 | 518 | ||
| 519 | static int ghes_print_estatus(const char *pfx, | 519 | static int ghes_print_estatus(const char *pfx, |
| 520 | const struct acpi_hest_generic *generic, | 520 | const struct acpi_hest_generic *generic, |
| 521 | const struct acpi_hest_generic_status *estatus) | 521 | const struct acpi_generic_status *estatus) |
| 522 | { | 522 | { |
| 523 | /* Not more than 2 messages every 5 seconds */ | 523 | /* Not more than 2 messages every 5 seconds */ |
| 524 | static DEFINE_RATELIMIT_STATE(ratelimit_corrected, 5*HZ, 2); | 524 | static DEFINE_RATELIMIT_STATE(ratelimit_corrected, 5*HZ, 2); |
| @@ -540,15 +540,15 @@ static int ghes_print_estatus(const char *pfx, | |||
| 540 | * GHES error status reporting throttle, to report more kinds of | 540 | * GHES error status reporting throttle, to report more kinds of |
| 541 | * errors, instead of just most frequently occurred errors. | 541 | * errors, instead of just most frequently occurred errors. |
| 542 | */ | 542 | */ |
| 543 | static int ghes_estatus_cached(struct acpi_hest_generic_status *estatus) | 543 | static int ghes_estatus_cached(struct acpi_generic_status *estatus) |
| 544 | { | 544 | { |
| 545 | u32 len; | 545 | u32 len; |
| 546 | int i, cached = 0; | 546 | int i, cached = 0; |
| 547 | unsigned long long now; | 547 | unsigned long long now; |
| 548 | struct ghes_estatus_cache *cache; | 548 | struct ghes_estatus_cache *cache; |
| 549 | struct acpi_hest_generic_status *cache_estatus; | 549 | struct acpi_generic_status *cache_estatus; |
| 550 | 550 | ||
| 551 | len = apei_estatus_len(estatus); | 551 | len = cper_estatus_len(estatus); |
| 552 | rcu_read_lock(); | 552 | rcu_read_lock(); |
| 553 | for (i = 0; i < GHES_ESTATUS_CACHES_SIZE; i++) { | 553 | for (i = 0; i < GHES_ESTATUS_CACHES_SIZE; i++) { |
| 554 | cache = rcu_dereference(ghes_estatus_caches[i]); | 554 | cache = rcu_dereference(ghes_estatus_caches[i]); |
| @@ -571,19 +571,19 @@ static int ghes_estatus_cached(struct acpi_hest_generic_status *estatus) | |||
| 571 | 571 | ||
| 572 | static struct ghes_estatus_cache *ghes_estatus_cache_alloc( | 572 | static struct ghes_estatus_cache *ghes_estatus_cache_alloc( |
| 573 | struct acpi_hest_generic *generic, | 573 | struct acpi_hest_generic *generic, |
| 574 | struct acpi_hest_generic_status *estatus) | 574 | struct acpi_generic_status *estatus) |
| 575 | { | 575 | { |
| 576 | int alloced; | 576 | int alloced; |
| 577 | u32 len, cache_len; | 577 | u32 len, cache_len; |
| 578 | struct ghes_estatus_cache *cache; | 578 | struct ghes_estatus_cache *cache; |
| 579 | struct acpi_hest_generic_status *cache_estatus; | 579 | struct acpi_generic_status *cache_estatus; |
| 580 | 580 | ||
| 581 | alloced = atomic_add_return(1, &ghes_estatus_cache_alloced); | 581 | alloced = atomic_add_return(1, &ghes_estatus_cache_alloced); |
| 582 | if (alloced > GHES_ESTATUS_CACHE_ALLOCED_MAX) { | 582 | if (alloced > GHES_ESTATUS_CACHE_ALLOCED_MAX) { |
| 583 | atomic_dec(&ghes_estatus_cache_alloced); | 583 | atomic_dec(&ghes_estatus_cache_alloced); |
| 584 | return NULL; | 584 | return NULL; |
| 585 | } | 585 | } |
| 586 | len = apei_estatus_len(estatus); | 586 | len = cper_estatus_len(estatus); |
| 587 | cache_len = GHES_ESTATUS_CACHE_LEN(len); | 587 | cache_len = GHES_ESTATUS_CACHE_LEN(len); |
| 588 | cache = (void *)gen_pool_alloc(ghes_estatus_pool, cache_len); | 588 | cache = (void *)gen_pool_alloc(ghes_estatus_pool, cache_len); |
| 589 | if (!cache) { | 589 | if (!cache) { |
| @@ -603,7 +603,7 @@ static void ghes_estatus_cache_free(struct ghes_estatus_cache *cache) | |||
| 603 | { | 603 | { |
| 604 | u32 len; | 604 | u32 len; |
| 605 | 605 | ||
| 606 | len = apei_estatus_len(GHES_ESTATUS_FROM_CACHE(cache)); | 606 | len = cper_estatus_len(GHES_ESTATUS_FROM_CACHE(cache)); |
| 607 | len = GHES_ESTATUS_CACHE_LEN(len); | 607 | len = GHES_ESTATUS_CACHE_LEN(len); |
| 608 | gen_pool_free(ghes_estatus_pool, (unsigned long)cache, len); | 608 | gen_pool_free(ghes_estatus_pool, (unsigned long)cache, len); |
| 609 | atomic_dec(&ghes_estatus_cache_alloced); | 609 | atomic_dec(&ghes_estatus_cache_alloced); |
| @@ -619,7 +619,7 @@ static void ghes_estatus_cache_rcu_free(struct rcu_head *head) | |||
| 619 | 619 | ||
| 620 | static void ghes_estatus_cache_add( | 620 | static void ghes_estatus_cache_add( |
| 621 | struct acpi_hest_generic *generic, | 621 | struct acpi_hest_generic *generic, |
| 622 | struct acpi_hest_generic_status *estatus) | 622 | struct acpi_generic_status *estatus) |
| 623 | { | 623 | { |
| 624 | int i, slot = -1, count; | 624 | int i, slot = -1, count; |
| 625 | unsigned long long now, duration, period, max_period = 0; | 625 | unsigned long long now, duration, period, max_period = 0; |
| @@ -751,7 +751,7 @@ static void ghes_proc_in_irq(struct irq_work *irq_work) | |||
| 751 | struct llist_node *llnode, *next; | 751 | struct llist_node *llnode, *next; |
| 752 | struct ghes_estatus_node *estatus_node; | 752 | struct ghes_estatus_node *estatus_node; |
| 753 | struct acpi_hest_generic *generic; | 753 | struct acpi_hest_generic *generic; |
| 754 | struct acpi_hest_generic_status *estatus; | 754 | struct acpi_generic_status *estatus; |
| 755 | u32 len, node_len; | 755 | u32 len, node_len; |
| 756 | 756 | ||
| 757 | llnode = llist_del_all(&ghes_estatus_llist); | 757 | llnode = llist_del_all(&ghes_estatus_llist); |
| @@ -765,7 +765,7 @@ static void ghes_proc_in_irq(struct irq_work *irq_work) | |||
| 765 | estatus_node = llist_entry(llnode, struct ghes_estatus_node, | 765 | estatus_node = llist_entry(llnode, struct ghes_estatus_node, |
| 766 | llnode); | 766 | llnode); |
| 767 | estatus = GHES_ESTATUS_FROM_NODE(estatus_node); | 767 | estatus = GHES_ESTATUS_FROM_NODE(estatus_node); |
| 768 | len = apei_estatus_len(estatus); | 768 | len = cper_estatus_len(estatus); |
| 769 | node_len = GHES_ESTATUS_NODE_LEN(len); | 769 | node_len = GHES_ESTATUS_NODE_LEN(len); |
| 770 | ghes_do_proc(estatus_node->ghes, estatus); | 770 | ghes_do_proc(estatus_node->ghes, estatus); |
| 771 | if (!ghes_estatus_cached(estatus)) { | 771 | if (!ghes_estatus_cached(estatus)) { |
| @@ -784,7 +784,7 @@ static void ghes_print_queued_estatus(void) | |||
| 784 | struct llist_node *llnode; | 784 | struct llist_node *llnode; |
| 785 | struct ghes_estatus_node *estatus_node; | 785 | struct ghes_estatus_node *estatus_node; |
| 786 | struct acpi_hest_generic *generic; | 786 | struct acpi_hest_generic *generic; |
| 787 | struct acpi_hest_generic_status *estatus; | 787 | struct acpi_generic_status *estatus; |
| 788 | u32 len, node_len; | 788 | u32 len, node_len; |
| 789 | 789 | ||
| 790 | llnode = llist_del_all(&ghes_estatus_llist); | 790 | llnode = llist_del_all(&ghes_estatus_llist); |
| @@ -797,7 +797,7 @@ static void ghes_print_queued_estatus(void) | |||
| 797 | estatus_node = llist_entry(llnode, struct ghes_estatus_node, | 797 | estatus_node = llist_entry(llnode, struct ghes_estatus_node, |
| 798 | llnode); | 798 | llnode); |
| 799 | estatus = GHES_ESTATUS_FROM_NODE(estatus_node); | 799 | estatus = GHES_ESTATUS_FROM_NODE(estatus_node); |
| 800 | len = apei_estatus_len(estatus); | 800 | len = cper_estatus_len(estatus); |
| 801 | node_len = GHES_ESTATUS_NODE_LEN(len); | 801 | node_len = GHES_ESTATUS_NODE_LEN(len); |
| 802 | generic = estatus_node->generic; | 802 | generic = estatus_node->generic; |
| 803 | ghes_print_estatus(NULL, generic, estatus); | 803 | ghes_print_estatus(NULL, generic, estatus); |
| @@ -843,7 +843,7 @@ static int ghes_notify_nmi(unsigned int cmd, struct pt_regs *regs) | |||
| 843 | #ifdef CONFIG_ARCH_HAVE_NMI_SAFE_CMPXCHG | 843 | #ifdef CONFIG_ARCH_HAVE_NMI_SAFE_CMPXCHG |
| 844 | u32 len, node_len; | 844 | u32 len, node_len; |
| 845 | struct ghes_estatus_node *estatus_node; | 845 | struct ghes_estatus_node *estatus_node; |
| 846 | struct acpi_hest_generic_status *estatus; | 846 | struct acpi_generic_status *estatus; |
| 847 | #endif | 847 | #endif |
| 848 | if (!(ghes->flags & GHES_TO_CLEAR)) | 848 | if (!(ghes->flags & GHES_TO_CLEAR)) |
| 849 | continue; | 849 | continue; |
| @@ -851,7 +851,7 @@ static int ghes_notify_nmi(unsigned int cmd, struct pt_regs *regs) | |||
| 851 | if (ghes_estatus_cached(ghes->estatus)) | 851 | if (ghes_estatus_cached(ghes->estatus)) |
| 852 | goto next; | 852 | goto next; |
| 853 | /* Save estatus for further processing in IRQ context */ | 853 | /* Save estatus for further processing in IRQ context */ |
| 854 | len = apei_estatus_len(ghes->estatus); | 854 | len = cper_estatus_len(ghes->estatus); |
| 855 | node_len = GHES_ESTATUS_NODE_LEN(len); | 855 | node_len = GHES_ESTATUS_NODE_LEN(len); |
| 856 | estatus_node = (void *)gen_pool_alloc(ghes_estatus_pool, | 856 | estatus_node = (void *)gen_pool_alloc(ghes_estatus_pool, |
| 857 | node_len); | 857 | node_len); |
| @@ -923,7 +923,7 @@ static int ghes_probe(struct platform_device *ghes_dev) | |||
| 923 | 923 | ||
| 924 | rc = -EIO; | 924 | rc = -EIO; |
| 925 | if (generic->error_block_length < | 925 | if (generic->error_block_length < |
| 926 | sizeof(struct acpi_hest_generic_status)) { | 926 | sizeof(struct acpi_generic_status)) { |
| 927 | pr_warning(FW_BUG GHES_PFX "Invalid error block length: %u for generic hardware error source: %d\n", | 927 | pr_warning(FW_BUG GHES_PFX "Invalid error block length: %u for generic hardware error source: %d\n", |
| 928 | generic->error_block_length, | 928 | generic->error_block_length, |
| 929 | generic->header.source_id); | 929 | generic->header.source_id); |
diff --git a/drivers/acpi/bus.c b/drivers/acpi/bus.c index b587ec8257b2..e1bd9a181117 100644 --- a/drivers/acpi/bus.c +++ b/drivers/acpi/bus.c | |||
| @@ -174,7 +174,7 @@ static void acpi_print_osc_error(acpi_handle handle, | |||
| 174 | printk("\n"); | 174 | printk("\n"); |
| 175 | } | 175 | } |
| 176 | 176 | ||
| 177 | static acpi_status acpi_str_to_uuid(char *str, u8 *uuid) | 177 | acpi_status acpi_str_to_uuid(char *str, u8 *uuid) |
| 178 | { | 178 | { |
| 179 | int i; | 179 | int i; |
| 180 | static int opc_map_to_uuid[16] = {6, 4, 2, 0, 11, 9, 16, 14, 19, 21, | 180 | static int opc_map_to_uuid[16] = {6, 4, 2, 0, 11, 9, 16, 14, 19, 21, |
| @@ -195,6 +195,7 @@ static acpi_status acpi_str_to_uuid(char *str, u8 *uuid) | |||
| 195 | } | 195 | } |
| 196 | return AE_OK; | 196 | return AE_OK; |
| 197 | } | 197 | } |
| 198 | EXPORT_SYMBOL_GPL(acpi_str_to_uuid); | ||
| 198 | 199 | ||
| 199 | acpi_status acpi_run_osc(acpi_handle handle, struct acpi_osc_context *context) | 200 | acpi_status acpi_run_osc(acpi_handle handle, struct acpi_osc_context *context) |
| 200 | { | 201 | { |
diff --git a/drivers/edac/amd64_edac.c b/drivers/edac/amd64_edac.c index 3c9e4e98c651..b53d0de17e15 100644 --- a/drivers/edac/amd64_edac.c +++ b/drivers/edac/amd64_edac.c | |||
| @@ -339,8 +339,8 @@ static void get_cs_base_and_mask(struct amd64_pvt *pvt, int csrow, u8 dct, | |||
| 339 | if (pvt->fam == 0xf && pvt->ext_model < K8_REV_F) { | 339 | if (pvt->fam == 0xf && pvt->ext_model < K8_REV_F) { |
| 340 | csbase = pvt->csels[dct].csbases[csrow]; | 340 | csbase = pvt->csels[dct].csbases[csrow]; |
| 341 | csmask = pvt->csels[dct].csmasks[csrow]; | 341 | csmask = pvt->csels[dct].csmasks[csrow]; |
| 342 | base_bits = GENMASK(21, 31) | GENMASK(9, 15); | 342 | base_bits = GENMASK_ULL(31, 21) | GENMASK_ULL(15, 9); |
| 343 | mask_bits = GENMASK(21, 29) | GENMASK(9, 15); | 343 | mask_bits = GENMASK_ULL(29, 21) | GENMASK_ULL(15, 9); |
| 344 | addr_shift = 4; | 344 | addr_shift = 4; |
| 345 | 345 | ||
| 346 | /* | 346 | /* |
| @@ -352,16 +352,16 @@ static void get_cs_base_and_mask(struct amd64_pvt *pvt, int csrow, u8 dct, | |||
| 352 | csbase = pvt->csels[dct].csbases[csrow]; | 352 | csbase = pvt->csels[dct].csbases[csrow]; |
| 353 | csmask = pvt->csels[dct].csmasks[csrow >> 1]; | 353 | csmask = pvt->csels[dct].csmasks[csrow >> 1]; |
| 354 | 354 | ||
| 355 | *base = (csbase & GENMASK(5, 15)) << 6; | 355 | *base = (csbase & GENMASK_ULL(15, 5)) << 6; |
| 356 | *base |= (csbase & GENMASK(19, 30)) << 8; | 356 | *base |= (csbase & GENMASK_ULL(30, 19)) << 8; |
| 357 | 357 | ||
| 358 | *mask = ~0ULL; | 358 | *mask = ~0ULL; |
| 359 | /* poke holes for the csmask */ | 359 | /* poke holes for the csmask */ |
| 360 | *mask &= ~((GENMASK(5, 15) << 6) | | 360 | *mask &= ~((GENMASK_ULL(15, 5) << 6) | |
| 361 | (GENMASK(19, 30) << 8)); | 361 | (GENMASK_ULL(30, 19) << 8)); |
| 362 | 362 | ||
| 363 | *mask |= (csmask & GENMASK(5, 15)) << 6; | 363 | *mask |= (csmask & GENMASK_ULL(15, 5)) << 6; |
| 364 | *mask |= (csmask & GENMASK(19, 30)) << 8; | 364 | *mask |= (csmask & GENMASK_ULL(30, 19)) << 8; |
| 365 | 365 | ||
| 366 | return; | 366 | return; |
| 367 | } else { | 367 | } else { |
| @@ -370,9 +370,11 @@ static void get_cs_base_and_mask(struct amd64_pvt *pvt, int csrow, u8 dct, | |||
| 370 | addr_shift = 8; | 370 | addr_shift = 8; |
| 371 | 371 | ||
| 372 | if (pvt->fam == 0x15) | 372 | if (pvt->fam == 0x15) |
| 373 | base_bits = mask_bits = GENMASK(19,30) | GENMASK(5,13); | 373 | base_bits = mask_bits = |
| 374 | GENMASK_ULL(30,19) | GENMASK_ULL(13,5); | ||
| 374 | else | 375 | else |
| 375 | base_bits = mask_bits = GENMASK(19,28) | GENMASK(5,13); | 376 | base_bits = mask_bits = |
| 377 | GENMASK_ULL(28,19) | GENMASK_ULL(13,5); | ||
| 376 | } | 378 | } |
| 377 | 379 | ||
| 378 | *base = (csbase & base_bits) << addr_shift; | 380 | *base = (csbase & base_bits) << addr_shift; |
| @@ -561,7 +563,7 @@ static u64 sys_addr_to_dram_addr(struct mem_ctl_info *mci, u64 sys_addr) | |||
| 561 | * section 3.4.2 of AMD publication 24592: AMD x86-64 Architecture | 563 | * section 3.4.2 of AMD publication 24592: AMD x86-64 Architecture |
| 562 | * Programmer's Manual Volume 1 Application Programming. | 564 | * Programmer's Manual Volume 1 Application Programming. |
| 563 | */ | 565 | */ |
| 564 | dram_addr = (sys_addr & GENMASK(0, 39)) - dram_base; | 566 | dram_addr = (sys_addr & GENMASK_ULL(39, 0)) - dram_base; |
| 565 | 567 | ||
| 566 | edac_dbg(2, "using DRAM Base register to translate SysAddr 0x%lx to DramAddr 0x%lx\n", | 568 | edac_dbg(2, "using DRAM Base register to translate SysAddr 0x%lx to DramAddr 0x%lx\n", |
| 567 | (unsigned long)sys_addr, (unsigned long)dram_addr); | 569 | (unsigned long)sys_addr, (unsigned long)dram_addr); |
| @@ -597,7 +599,7 @@ static u64 dram_addr_to_input_addr(struct mem_ctl_info *mci, u64 dram_addr) | |||
| 597 | * concerning translating a DramAddr to an InputAddr. | 599 | * concerning translating a DramAddr to an InputAddr. |
| 598 | */ | 600 | */ |
| 599 | intlv_shift = num_node_interleave_bits(dram_intlv_en(pvt, 0)); | 601 | intlv_shift = num_node_interleave_bits(dram_intlv_en(pvt, 0)); |
| 600 | input_addr = ((dram_addr >> intlv_shift) & GENMASK(12, 35)) + | 602 | input_addr = ((dram_addr >> intlv_shift) & GENMASK_ULL(35, 12)) + |
| 601 | (dram_addr & 0xfff); | 603 | (dram_addr & 0xfff); |
| 602 | 604 | ||
| 603 | edac_dbg(2, " Intlv Shift=%d DramAddr=0x%lx maps to InputAddr=0x%lx\n", | 605 | edac_dbg(2, " Intlv Shift=%d DramAddr=0x%lx maps to InputAddr=0x%lx\n", |
| @@ -849,7 +851,7 @@ static u64 get_error_address(struct amd64_pvt *pvt, struct mce *m) | |||
| 849 | end_bit = 39; | 851 | end_bit = 39; |
| 850 | } | 852 | } |
| 851 | 853 | ||
| 852 | addr = m->addr & GENMASK(start_bit, end_bit); | 854 | addr = m->addr & GENMASK_ULL(end_bit, start_bit); |
| 853 | 855 | ||
| 854 | /* | 856 | /* |
| 855 | * Erratum 637 workaround | 857 | * Erratum 637 workaround |
| @@ -861,7 +863,7 @@ static u64 get_error_address(struct amd64_pvt *pvt, struct mce *m) | |||
| 861 | u16 mce_nid; | 863 | u16 mce_nid; |
| 862 | u8 intlv_en; | 864 | u8 intlv_en; |
| 863 | 865 | ||
| 864 | if ((addr & GENMASK(24, 47)) >> 24 != 0x00fdf7) | 866 | if ((addr & GENMASK_ULL(47, 24)) >> 24 != 0x00fdf7) |
| 865 | return addr; | 867 | return addr; |
| 866 | 868 | ||
| 867 | mce_nid = amd_get_nb_id(m->extcpu); | 869 | mce_nid = amd_get_nb_id(m->extcpu); |
| @@ -871,7 +873,7 @@ static u64 get_error_address(struct amd64_pvt *pvt, struct mce *m) | |||
| 871 | intlv_en = tmp >> 21 & 0x7; | 873 | intlv_en = tmp >> 21 & 0x7; |
| 872 | 874 | ||
| 873 | /* add [47:27] + 3 trailing bits */ | 875 | /* add [47:27] + 3 trailing bits */ |
| 874 | cc6_base = (tmp & GENMASK(0, 20)) << 3; | 876 | cc6_base = (tmp & GENMASK_ULL(20, 0)) << 3; |
| 875 | 877 | ||
| 876 | /* reverse and add DramIntlvEn */ | 878 | /* reverse and add DramIntlvEn */ |
| 877 | cc6_base |= intlv_en ^ 0x7; | 879 | cc6_base |= intlv_en ^ 0x7; |
| @@ -880,18 +882,18 @@ static u64 get_error_address(struct amd64_pvt *pvt, struct mce *m) | |||
| 880 | cc6_base <<= 24; | 882 | cc6_base <<= 24; |
| 881 | 883 | ||
| 882 | if (!intlv_en) | 884 | if (!intlv_en) |
| 883 | return cc6_base | (addr & GENMASK(0, 23)); | 885 | return cc6_base | (addr & GENMASK_ULL(23, 0)); |
| 884 | 886 | ||
| 885 | amd64_read_pci_cfg(pvt->F1, DRAM_LOCAL_NODE_BASE, &tmp); | 887 | amd64_read_pci_cfg(pvt->F1, DRAM_LOCAL_NODE_BASE, &tmp); |
| 886 | 888 | ||
| 887 | /* faster log2 */ | 889 | /* faster log2 */ |
| 888 | tmp_addr = (addr & GENMASK(12, 23)) << __fls(intlv_en + 1); | 890 | tmp_addr = (addr & GENMASK_ULL(23, 12)) << __fls(intlv_en + 1); |
| 889 | 891 | ||
| 890 | /* OR DramIntlvSel into bits [14:12] */ | 892 | /* OR DramIntlvSel into bits [14:12] */ |
| 891 | tmp_addr |= (tmp & GENMASK(21, 23)) >> 9; | 893 | tmp_addr |= (tmp & GENMASK_ULL(23, 21)) >> 9; |
| 892 | 894 | ||
| 893 | /* add remaining [11:0] bits from original MC4_ADDR */ | 895 | /* add remaining [11:0] bits from original MC4_ADDR */ |
| 894 | tmp_addr |= addr & GENMASK(0, 11); | 896 | tmp_addr |= addr & GENMASK_ULL(11, 0); |
| 895 | 897 | ||
| 896 | return cc6_base | tmp_addr; | 898 | return cc6_base | tmp_addr; |
| 897 | } | 899 | } |
| @@ -952,12 +954,12 @@ static void read_dram_base_limit_regs(struct amd64_pvt *pvt, unsigned range) | |||
| 952 | 954 | ||
| 953 | amd64_read_pci_cfg(f1, DRAM_LOCAL_NODE_LIM, &llim); | 955 | amd64_read_pci_cfg(f1, DRAM_LOCAL_NODE_LIM, &llim); |
| 954 | 956 | ||
| 955 | pvt->ranges[range].lim.lo &= GENMASK(0, 15); | 957 | pvt->ranges[range].lim.lo &= GENMASK_ULL(15, 0); |
| 956 | 958 | ||
| 957 | /* {[39:27],111b} */ | 959 | /* {[39:27],111b} */ |
| 958 | pvt->ranges[range].lim.lo |= ((llim & 0x1fff) << 3 | 0x7) << 16; | 960 | pvt->ranges[range].lim.lo |= ((llim & 0x1fff) << 3 | 0x7) << 16; |
| 959 | 961 | ||
| 960 | pvt->ranges[range].lim.hi &= GENMASK(0, 7); | 962 | pvt->ranges[range].lim.hi &= GENMASK_ULL(7, 0); |
| 961 | 963 | ||
| 962 | /* [47:40] */ | 964 | /* [47:40] */ |
| 963 | pvt->ranges[range].lim.hi |= llim >> 13; | 965 | pvt->ranges[range].lim.hi |= llim >> 13; |
| @@ -1330,7 +1332,7 @@ static u64 f1x_get_norm_dct_addr(struct amd64_pvt *pvt, u8 range, | |||
| 1330 | chan_off = dram_base; | 1332 | chan_off = dram_base; |
| 1331 | } | 1333 | } |
| 1332 | 1334 | ||
| 1333 | return (sys_addr & GENMASK(6,47)) - (chan_off & GENMASK(23,47)); | 1335 | return (sys_addr & GENMASK_ULL(47,6)) - (chan_off & GENMASK_ULL(47,23)); |
| 1334 | } | 1336 | } |
| 1335 | 1337 | ||
| 1336 | /* | 1338 | /* |
diff --git a/drivers/edac/amd64_edac.h b/drivers/edac/amd64_edac.h index d2443cfa0698..6dc1fcc25afb 100644 --- a/drivers/edac/amd64_edac.h +++ b/drivers/edac/amd64_edac.h | |||
| @@ -160,14 +160,6 @@ | |||
| 160 | #define OFF false | 160 | #define OFF false |
| 161 | 161 | ||
| 162 | /* | 162 | /* |
| 163 | * Create a contiguous bitmask starting at bit position @lo and ending at | ||
| 164 | * position @hi. For example | ||
| 165 | * | ||
| 166 | * GENMASK(21, 39) gives us the 64bit vector 0x000000ffffe00000. | ||
| 167 | */ | ||
| 168 | #define GENMASK(lo, hi) (((1ULL << ((hi) - (lo) + 1)) - 1) << (lo)) | ||
| 169 | |||
| 170 | /* | ||
| 171 | * PCI-defined configuration space registers | 163 | * PCI-defined configuration space registers |
| 172 | */ | 164 | */ |
| 173 | #define PCI_DEVICE_ID_AMD_15H_M30H_NB_F1 0x141b | 165 | #define PCI_DEVICE_ID_AMD_15H_M30H_NB_F1 0x141b |
diff --git a/drivers/edac/ghes_edac.c b/drivers/edac/ghes_edac.c index bb534670ec02..d5a98a45c062 100644 --- a/drivers/edac/ghes_edac.c +++ b/drivers/edac/ghes_edac.c | |||
| @@ -297,15 +297,14 @@ void ghes_edac_report_mem_error(struct ghes *ghes, int sev, | |||
| 297 | } | 297 | } |
| 298 | 298 | ||
| 299 | /* Error address */ | 299 | /* Error address */ |
| 300 | if (mem_err->validation_bits & CPER_MEM_VALID_PHYSICAL_ADDRESS) { | 300 | if (mem_err->validation_bits & CPER_MEM_VALID_PA) { |
| 301 | e->page_frame_number = mem_err->physical_addr >> PAGE_SHIFT; | 301 | e->page_frame_number = mem_err->physical_addr >> PAGE_SHIFT; |
| 302 | e->offset_in_page = mem_err->physical_addr & ~PAGE_MASK; | 302 | e->offset_in_page = mem_err->physical_addr & ~PAGE_MASK; |
| 303 | } | 303 | } |
| 304 | 304 | ||
| 305 | /* Error grain */ | 305 | /* Error grain */ |
| 306 | if (mem_err->validation_bits & CPER_MEM_VALID_PHYSICAL_ADDRESS_MASK) { | 306 | if (mem_err->validation_bits & CPER_MEM_VALID_PA_MASK) |
| 307 | e->grain = ~(mem_err->physical_addr_mask & ~PAGE_MASK); | 307 | e->grain = ~(mem_err->physical_addr_mask & ~PAGE_MASK); |
| 308 | } | ||
| 309 | 308 | ||
| 310 | /* Memory error location, mapped on e->location */ | 309 | /* Memory error location, mapped on e->location */ |
| 311 | p = e->location; | 310 | p = e->location; |
| @@ -315,6 +314,8 @@ void ghes_edac_report_mem_error(struct ghes *ghes, int sev, | |||
| 315 | p += sprintf(p, "card:%d ", mem_err->card); | 314 | p += sprintf(p, "card:%d ", mem_err->card); |
| 316 | if (mem_err->validation_bits & CPER_MEM_VALID_MODULE) | 315 | if (mem_err->validation_bits & CPER_MEM_VALID_MODULE) |
| 317 | p += sprintf(p, "module:%d ", mem_err->module); | 316 | p += sprintf(p, "module:%d ", mem_err->module); |
| 317 | if (mem_err->validation_bits & CPER_MEM_VALID_RANK_NUMBER) | ||
| 318 | p += sprintf(p, "rank:%d ", mem_err->rank); | ||
| 318 | if (mem_err->validation_bits & CPER_MEM_VALID_BANK) | 319 | if (mem_err->validation_bits & CPER_MEM_VALID_BANK) |
| 319 | p += sprintf(p, "bank:%d ", mem_err->bank); | 320 | p += sprintf(p, "bank:%d ", mem_err->bank); |
| 320 | if (mem_err->validation_bits & CPER_MEM_VALID_ROW) | 321 | if (mem_err->validation_bits & CPER_MEM_VALID_ROW) |
| @@ -323,6 +324,15 @@ void ghes_edac_report_mem_error(struct ghes *ghes, int sev, | |||
| 323 | p += sprintf(p, "col:%d ", mem_err->column); | 324 | p += sprintf(p, "col:%d ", mem_err->column); |
| 324 | if (mem_err->validation_bits & CPER_MEM_VALID_BIT_POSITION) | 325 | if (mem_err->validation_bits & CPER_MEM_VALID_BIT_POSITION) |
| 325 | p += sprintf(p, "bit_pos:%d ", mem_err->bit_pos); | 326 | p += sprintf(p, "bit_pos:%d ", mem_err->bit_pos); |
| 327 | if (mem_err->validation_bits & CPER_MEM_VALID_MODULE_HANDLE) { | ||
| 328 | const char *bank = NULL, *device = NULL; | ||
| 329 | dmi_memdev_name(mem_err->mem_dev_handle, &bank, &device); | ||
| 330 | if (bank != NULL && device != NULL) | ||
| 331 | p += sprintf(p, "DIMM location:%s %s ", bank, device); | ||
| 332 | else | ||
| 333 | p += sprintf(p, "DIMM DMI handle: 0x%.4x ", | ||
| 334 | mem_err->mem_dev_handle); | ||
| 335 | } | ||
| 326 | if (p > e->location) | 336 | if (p > e->location) |
| 327 | *(p - 1) = '\0'; | 337 | *(p - 1) = '\0'; |
| 328 | 338 | ||
diff --git a/drivers/edac/sb_edac.c b/drivers/edac/sb_edac.c index e04462b60756..88f60c5fecbc 100644 --- a/drivers/edac/sb_edac.c +++ b/drivers/edac/sb_edac.c | |||
| @@ -50,7 +50,7 @@ static int probed; | |||
| 50 | * Get a bit field at register value <v>, from bit <lo> to bit <hi> | 50 | * Get a bit field at register value <v>, from bit <lo> to bit <hi> |
| 51 | */ | 51 | */ |
| 52 | #define GET_BITFIELD(v, lo, hi) \ | 52 | #define GET_BITFIELD(v, lo, hi) \ |
| 53 | (((v) & ((1ULL << ((hi) - (lo) + 1)) - 1) << (lo)) >> (lo)) | 53 | (((v) & GENMASK_ULL(hi, lo)) >> (lo)) |
| 54 | 54 | ||
| 55 | /* | 55 | /* |
| 56 | * sbridge Memory Controller Registers | 56 | * sbridge Memory Controller Registers |
diff --git a/drivers/firmware/dmi_scan.c b/drivers/firmware/dmi_scan.c index fa0affb699b4..c7e81ff8f3ef 100644 --- a/drivers/firmware/dmi_scan.c +++ b/drivers/firmware/dmi_scan.c | |||
| @@ -8,6 +8,7 @@ | |||
| 8 | #include <linux/bootmem.h> | 8 | #include <linux/bootmem.h> |
| 9 | #include <linux/random.h> | 9 | #include <linux/random.h> |
| 10 | #include <asm/dmi.h> | 10 | #include <asm/dmi.h> |
| 11 | #include <asm/unaligned.h> | ||
| 11 | 12 | ||
| 12 | /* | 13 | /* |
| 13 | * DMI stands for "Desktop Management Interface". It is part | 14 | * DMI stands for "Desktop Management Interface". It is part |
| @@ -25,6 +26,13 @@ static int dmi_initialized; | |||
| 25 | /* DMI system identification string used during boot */ | 26 | /* DMI system identification string used during boot */ |
| 26 | static char dmi_ids_string[128] __initdata; | 27 | static char dmi_ids_string[128] __initdata; |
| 27 | 28 | ||
| 29 | static struct dmi_memdev_info { | ||
| 30 | const char *device; | ||
| 31 | const char *bank; | ||
| 32 | u16 handle; | ||
| 33 | } *dmi_memdev; | ||
| 34 | static int dmi_memdev_nr; | ||
| 35 | |||
| 28 | static const char * __init dmi_string_nosave(const struct dmi_header *dm, u8 s) | 36 | static const char * __init dmi_string_nosave(const struct dmi_header *dm, u8 s) |
| 29 | { | 37 | { |
| 30 | const u8 *bp = ((u8 *) dm) + dm->length; | 38 | const u8 *bp = ((u8 *) dm) + dm->length; |
| @@ -322,6 +330,42 @@ static void __init dmi_save_extended_devices(const struct dmi_header *dm) | |||
| 322 | dmi_save_one_device(*d & 0x7f, dmi_string_nosave(dm, *(d - 1))); | 330 | dmi_save_one_device(*d & 0x7f, dmi_string_nosave(dm, *(d - 1))); |
| 323 | } | 331 | } |
| 324 | 332 | ||
| 333 | static void __init count_mem_devices(const struct dmi_header *dm, void *v) | ||
| 334 | { | ||
| 335 | if (dm->type != DMI_ENTRY_MEM_DEVICE) | ||
| 336 | return; | ||
| 337 | dmi_memdev_nr++; | ||
| 338 | } | ||
| 339 | |||
| 340 | static void __init save_mem_devices(const struct dmi_header *dm, void *v) | ||
| 341 | { | ||
| 342 | const char *d = (const char *)dm; | ||
| 343 | static int nr; | ||
| 344 | |||
| 345 | if (dm->type != DMI_ENTRY_MEM_DEVICE) | ||
| 346 | return; | ||
| 347 | if (nr >= dmi_memdev_nr) { | ||
| 348 | pr_warn(FW_BUG "Too many DIMM entries in SMBIOS table\n"); | ||
| 349 | return; | ||
| 350 | } | ||
| 351 | dmi_memdev[nr].handle = get_unaligned(&dm->handle); | ||
| 352 | dmi_memdev[nr].device = dmi_string(dm, d[0x10]); | ||
| 353 | dmi_memdev[nr].bank = dmi_string(dm, d[0x11]); | ||
| 354 | nr++; | ||
| 355 | } | ||
| 356 | |||
| 357 | void __init dmi_memdev_walk(void) | ||
| 358 | { | ||
| 359 | if (!dmi_available) | ||
| 360 | return; | ||
| 361 | |||
| 362 | if (dmi_walk_early(count_mem_devices) == 0 && dmi_memdev_nr) { | ||
| 363 | dmi_memdev = dmi_alloc(sizeof(*dmi_memdev) * dmi_memdev_nr); | ||
| 364 | if (dmi_memdev) | ||
| 365 | dmi_walk_early(save_mem_devices); | ||
| 366 | } | ||
| 367 | } | ||
| 368 | |||
| 325 | /* | 369 | /* |
| 326 | * Process a DMI table entry. Right now all we care about are the BIOS | 370 | * Process a DMI table entry. Right now all we care about are the BIOS |
| 327 | * and machine entries. For 2.5 we should pull the smbus controller info | 371 | * and machine entries. For 2.5 we should pull the smbus controller info |
| @@ -815,3 +859,20 @@ bool dmi_match(enum dmi_field f, const char *str) | |||
| 815 | return !strcmp(info, str); | 859 | return !strcmp(info, str); |
| 816 | } | 860 | } |
| 817 | EXPORT_SYMBOL_GPL(dmi_match); | 861 | EXPORT_SYMBOL_GPL(dmi_match); |
| 862 | |||
| 863 | void dmi_memdev_name(u16 handle, const char **bank, const char **device) | ||
| 864 | { | ||
| 865 | int n; | ||
| 866 | |||
| 867 | if (dmi_memdev == NULL) | ||
| 868 | return; | ||
| 869 | |||
| 870 | for (n = 0; n < dmi_memdev_nr; n++) { | ||
| 871 | if (handle == dmi_memdev[n].handle) { | ||
| 872 | *bank = dmi_memdev[n].bank; | ||
| 873 | *device = dmi_memdev[n].device; | ||
| 874 | break; | ||
| 875 | } | ||
| 876 | } | ||
| 877 | } | ||
| 878 | EXPORT_SYMBOL_GPL(dmi_memdev_name); | ||
diff --git a/drivers/firmware/efi/Kconfig b/drivers/firmware/efi/Kconfig index b0fc7c79dfbb..3150aa4874e8 100644 --- a/drivers/firmware/efi/Kconfig +++ b/drivers/firmware/efi/Kconfig | |||
| @@ -36,4 +36,7 @@ config EFI_VARS_PSTORE_DEFAULT_DISABLE | |||
| 36 | backend for pstore by default. This setting can be overridden | 36 | backend for pstore by default. This setting can be overridden |
| 37 | using the efivars module's pstore_disable parameter. | 37 | using the efivars module's pstore_disable parameter. |
| 38 | 38 | ||
| 39 | config UEFI_CPER | ||
| 40 | def_bool n | ||
| 41 | |||
| 39 | endmenu | 42 | endmenu |
diff --git a/drivers/firmware/efi/Makefile b/drivers/firmware/efi/Makefile index 99245ab5a79c..9ba156d3c775 100644 --- a/drivers/firmware/efi/Makefile +++ b/drivers/firmware/efi/Makefile | |||
| @@ -4,3 +4,4 @@ | |||
| 4 | obj-y += efi.o vars.o | 4 | obj-y += efi.o vars.o |
| 5 | obj-$(CONFIG_EFI_VARS) += efivars.o | 5 | obj-$(CONFIG_EFI_VARS) += efivars.o |
| 6 | obj-$(CONFIG_EFI_VARS_PSTORE) += efi-pstore.o | 6 | obj-$(CONFIG_EFI_VARS_PSTORE) += efi-pstore.o |
| 7 | obj-$(CONFIG_UEFI_CPER) += cper.o | ||
diff --git a/drivers/acpi/apei/cper.c b/drivers/firmware/efi/cper.c index 33dc6a004802..1491dd4f08f9 100644 --- a/drivers/acpi/apei/cper.c +++ b/drivers/firmware/efi/cper.c | |||
| @@ -5,10 +5,10 @@ | |||
| 5 | * Author: Huang Ying <ying.huang@intel.com> | 5 | * Author: Huang Ying <ying.huang@intel.com> |
| 6 | * | 6 | * |
| 7 | * CPER is the format used to describe platform hardware error by | 7 | * CPER is the format used to describe platform hardware error by |
| 8 | * various APEI tables, such as ERST, BERT and HEST etc. | 8 | * various tables, such as ERST, BERT and HEST etc. |
| 9 | * | 9 | * |
| 10 | * For more information about CPER, please refer to Appendix N of UEFI | 10 | * For more information about CPER, please refer to Appendix N of UEFI |
| 11 | * Specification version 2.3. | 11 | * Specification version 2.4. |
| 12 | * | 12 | * |
| 13 | * This program is free software; you can redistribute it and/or | 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 | 14 | * modify it under the terms of the GNU General Public License version |
| @@ -28,10 +28,12 @@ | |||
| 28 | #include <linux/module.h> | 28 | #include <linux/module.h> |
| 29 | #include <linux/time.h> | 29 | #include <linux/time.h> |
| 30 | #include <linux/cper.h> | 30 | #include <linux/cper.h> |
| 31 | #include <linux/dmi.h> | ||
| 31 | #include <linux/acpi.h> | 32 | #include <linux/acpi.h> |
| 32 | #include <linux/pci.h> | 33 | #include <linux/pci.h> |
| 33 | #include <linux/aer.h> | 34 | #include <linux/aer.h> |
| 34 | 35 | ||
| 36 | #define INDENT_SP " " | ||
| 35 | /* | 37 | /* |
| 36 | * CPER record ID need to be unique even after reboot, because record | 38 | * CPER record ID need to be unique even after reboot, because record |
| 37 | * ID is used as index for ERST storage, while CPER records from | 39 | * ID is used as index for ERST storage, while CPER records from |
| @@ -73,7 +75,7 @@ static const char *cper_severity_str(unsigned int severity) | |||
| 73 | * printed, with @pfx is printed at the beginning of each line. | 75 | * printed, with @pfx is printed at the beginning of each line. |
| 74 | */ | 76 | */ |
| 75 | void cper_print_bits(const char *pfx, unsigned int bits, | 77 | void cper_print_bits(const char *pfx, unsigned int bits, |
| 76 | const char *strs[], unsigned int strs_size) | 78 | const char * const strs[], unsigned int strs_size) |
| 77 | { | 79 | { |
| 78 | int i, len = 0; | 80 | int i, len = 0; |
| 79 | const char *str; | 81 | const char *str; |
| @@ -98,32 +100,32 @@ void cper_print_bits(const char *pfx, unsigned int bits, | |||
| 98 | printk("%s\n", buf); | 100 | printk("%s\n", buf); |
| 99 | } | 101 | } |
| 100 | 102 | ||
| 101 | static const char *cper_proc_type_strs[] = { | 103 | static const char * const cper_proc_type_strs[] = { |
| 102 | "IA32/X64", | 104 | "IA32/X64", |
| 103 | "IA64", | 105 | "IA64", |
| 104 | }; | 106 | }; |
| 105 | 107 | ||
| 106 | static const char *cper_proc_isa_strs[] = { | 108 | static const char * const cper_proc_isa_strs[] = { |
| 107 | "IA32", | 109 | "IA32", |
| 108 | "IA64", | 110 | "IA64", |
| 109 | "X64", | 111 | "X64", |
| 110 | }; | 112 | }; |
| 111 | 113 | ||
| 112 | static const char *cper_proc_error_type_strs[] = { | 114 | static const char * const cper_proc_error_type_strs[] = { |
| 113 | "cache error", | 115 | "cache error", |
| 114 | "TLB error", | 116 | "TLB error", |
| 115 | "bus error", | 117 | "bus error", |
| 116 | "micro-architectural error", | 118 | "micro-architectural error", |
| 117 | }; | 119 | }; |
| 118 | 120 | ||
| 119 | static const char *cper_proc_op_strs[] = { | 121 | static const char * const cper_proc_op_strs[] = { |
| 120 | "unknown or generic", | 122 | "unknown or generic", |
| 121 | "data read", | 123 | "data read", |
| 122 | "data write", | 124 | "data write", |
| 123 | "instruction execution", | 125 | "instruction execution", |
| 124 | }; | 126 | }; |
| 125 | 127 | ||
| 126 | static const char *cper_proc_flag_strs[] = { | 128 | static const char * const cper_proc_flag_strs[] = { |
| 127 | "restartable", | 129 | "restartable", |
| 128 | "precise IP", | 130 | "precise IP", |
| 129 | "overflow", | 131 | "overflow", |
| @@ -191,46 +193,58 @@ static const char *cper_mem_err_type_strs[] = { | |||
| 191 | "memory sparing", | 193 | "memory sparing", |
| 192 | "scrub corrected error", | 194 | "scrub corrected error", |
| 193 | "scrub uncorrected error", | 195 | "scrub uncorrected error", |
| 196 | "physical memory map-out event", | ||
| 194 | }; | 197 | }; |
| 195 | 198 | ||
| 196 | static void cper_print_mem(const char *pfx, const struct cper_sec_mem_err *mem) | 199 | static void cper_print_mem(const char *pfx, const struct cper_sec_mem_err *mem) |
| 197 | { | 200 | { |
| 198 | if (mem->validation_bits & CPER_MEM_VALID_ERROR_STATUS) | 201 | if (mem->validation_bits & CPER_MEM_VALID_ERROR_STATUS) |
| 199 | printk("%s""error_status: 0x%016llx\n", pfx, mem->error_status); | 202 | printk("%s""error_status: 0x%016llx\n", pfx, mem->error_status); |
| 200 | if (mem->validation_bits & CPER_MEM_VALID_PHYSICAL_ADDRESS) | 203 | if (mem->validation_bits & CPER_MEM_VALID_PA) |
| 201 | printk("%s""physical_address: 0x%016llx\n", | 204 | printk("%s""physical_address: 0x%016llx\n", |
| 202 | pfx, mem->physical_addr); | 205 | pfx, mem->physical_addr); |
| 203 | if (mem->validation_bits & CPER_MEM_VALID_PHYSICAL_ADDRESS_MASK) | 206 | if (mem->validation_bits & CPER_MEM_VALID_PA_MASK) |
| 204 | printk("%s""physical_address_mask: 0x%016llx\n", | 207 | printk("%s""physical_address_mask: 0x%016llx\n", |
| 205 | pfx, mem->physical_addr_mask); | 208 | pfx, mem->physical_addr_mask); |
| 206 | if (mem->validation_bits & CPER_MEM_VALID_NODE) | 209 | if (mem->validation_bits & CPER_MEM_VALID_NODE) |
| 207 | printk("%s""node: %d\n", pfx, mem->node); | 210 | pr_debug("node: %d\n", mem->node); |
| 208 | if (mem->validation_bits & CPER_MEM_VALID_CARD) | 211 | if (mem->validation_bits & CPER_MEM_VALID_CARD) |
| 209 | printk("%s""card: %d\n", pfx, mem->card); | 212 | pr_debug("card: %d\n", mem->card); |
| 210 | if (mem->validation_bits & CPER_MEM_VALID_MODULE) | 213 | if (mem->validation_bits & CPER_MEM_VALID_MODULE) |
| 211 | printk("%s""module: %d\n", pfx, mem->module); | 214 | pr_debug("module: %d\n", mem->module); |
| 215 | if (mem->validation_bits & CPER_MEM_VALID_RANK_NUMBER) | ||
| 216 | pr_debug("rank: %d\n", mem->rank); | ||
| 212 | if (mem->validation_bits & CPER_MEM_VALID_BANK) | 217 | if (mem->validation_bits & CPER_MEM_VALID_BANK) |
| 213 | printk("%s""bank: %d\n", pfx, mem->bank); | 218 | pr_debug("bank: %d\n", mem->bank); |
| 214 | if (mem->validation_bits & CPER_MEM_VALID_DEVICE) | 219 | if (mem->validation_bits & CPER_MEM_VALID_DEVICE) |
| 215 | printk("%s""device: %d\n", pfx, mem->device); | 220 | pr_debug("device: %d\n", mem->device); |
| 216 | if (mem->validation_bits & CPER_MEM_VALID_ROW) | 221 | if (mem->validation_bits & CPER_MEM_VALID_ROW) |
| 217 | printk("%s""row: %d\n", pfx, mem->row); | 222 | pr_debug("row: %d\n", mem->row); |
| 218 | if (mem->validation_bits & CPER_MEM_VALID_COLUMN) | 223 | if (mem->validation_bits & CPER_MEM_VALID_COLUMN) |
| 219 | printk("%s""column: %d\n", pfx, mem->column); | 224 | pr_debug("column: %d\n", mem->column); |
| 220 | if (mem->validation_bits & CPER_MEM_VALID_BIT_POSITION) | 225 | if (mem->validation_bits & CPER_MEM_VALID_BIT_POSITION) |
| 221 | printk("%s""bit_position: %d\n", pfx, mem->bit_pos); | 226 | pr_debug("bit_position: %d\n", mem->bit_pos); |
| 222 | if (mem->validation_bits & CPER_MEM_VALID_REQUESTOR_ID) | 227 | if (mem->validation_bits & CPER_MEM_VALID_REQUESTOR_ID) |
| 223 | printk("%s""requestor_id: 0x%016llx\n", pfx, mem->requestor_id); | 228 | pr_debug("requestor_id: 0x%016llx\n", mem->requestor_id); |
| 224 | if (mem->validation_bits & CPER_MEM_VALID_RESPONDER_ID) | 229 | if (mem->validation_bits & CPER_MEM_VALID_RESPONDER_ID) |
| 225 | printk("%s""responder_id: 0x%016llx\n", pfx, mem->responder_id); | 230 | pr_debug("responder_id: 0x%016llx\n", mem->responder_id); |
| 226 | if (mem->validation_bits & CPER_MEM_VALID_TARGET_ID) | 231 | if (mem->validation_bits & CPER_MEM_VALID_TARGET_ID) |
| 227 | printk("%s""target_id: 0x%016llx\n", pfx, mem->target_id); | 232 | pr_debug("target_id: 0x%016llx\n", mem->target_id); |
| 228 | if (mem->validation_bits & CPER_MEM_VALID_ERROR_TYPE) { | 233 | if (mem->validation_bits & CPER_MEM_VALID_ERROR_TYPE) { |
| 229 | u8 etype = mem->error_type; | 234 | u8 etype = mem->error_type; |
| 230 | printk("%s""error_type: %d, %s\n", pfx, etype, | 235 | printk("%s""error_type: %d, %s\n", pfx, etype, |
| 231 | etype < ARRAY_SIZE(cper_mem_err_type_strs) ? | 236 | etype < ARRAY_SIZE(cper_mem_err_type_strs) ? |
| 232 | cper_mem_err_type_strs[etype] : "unknown"); | 237 | cper_mem_err_type_strs[etype] : "unknown"); |
| 233 | } | 238 | } |
| 239 | if (mem->validation_bits & CPER_MEM_VALID_MODULE_HANDLE) { | ||
| 240 | const char *bank = NULL, *device = NULL; | ||
| 241 | dmi_memdev_name(mem->mem_dev_handle, &bank, &device); | ||
| 242 | if (bank != NULL && device != NULL) | ||
| 243 | printk("%s""DIMM location: %s %s", pfx, bank, device); | ||
| 244 | else | ||
| 245 | printk("%s""DIMM DMI handle: 0x%.4x", | ||
| 246 | pfx, mem->mem_dev_handle); | ||
| 247 | } | ||
| 234 | } | 248 | } |
| 235 | 249 | ||
| 236 | static const char *cper_pcie_port_type_strs[] = { | 250 | static const char *cper_pcie_port_type_strs[] = { |
| @@ -248,7 +262,7 @@ static const char *cper_pcie_port_type_strs[] = { | |||
| 248 | }; | 262 | }; |
| 249 | 263 | ||
| 250 | static void cper_print_pcie(const char *pfx, const struct cper_sec_pcie *pcie, | 264 | static void cper_print_pcie(const char *pfx, const struct cper_sec_pcie *pcie, |
| 251 | const struct acpi_hest_generic_data *gdata) | 265 | const struct acpi_generic_data *gdata) |
| 252 | { | 266 | { |
| 253 | if (pcie->validation_bits & CPER_PCIE_VALID_PORT_TYPE) | 267 | if (pcie->validation_bits & CPER_PCIE_VALID_PORT_TYPE) |
| 254 | printk("%s""port_type: %d, %s\n", pfx, pcie->port_type, | 268 | printk("%s""port_type: %d, %s\n", pfx, pcie->port_type, |
| @@ -283,55 +297,45 @@ static void cper_print_pcie(const char *pfx, const struct cper_sec_pcie *pcie, | |||
| 283 | pfx, pcie->bridge.secondary_status, pcie->bridge.control); | 297 | pfx, pcie->bridge.secondary_status, pcie->bridge.control); |
| 284 | } | 298 | } |
| 285 | 299 | ||
| 286 | static const char *apei_estatus_section_flag_strs[] = { | 300 | static void cper_estatus_print_section( |
| 287 | "primary", | 301 | const char *pfx, const struct acpi_generic_data *gdata, int sec_no) |
| 288 | "containment warning", | ||
| 289 | "reset", | ||
| 290 | "threshold exceeded", | ||
| 291 | "resource not accessible", | ||
| 292 | "latent error", | ||
| 293 | }; | ||
| 294 | |||
| 295 | static void apei_estatus_print_section( | ||
| 296 | const char *pfx, const struct acpi_hest_generic_data *gdata, int sec_no) | ||
| 297 | { | 302 | { |
| 298 | uuid_le *sec_type = (uuid_le *)gdata->section_type; | 303 | uuid_le *sec_type = (uuid_le *)gdata->section_type; |
| 299 | __u16 severity; | 304 | __u16 severity; |
| 305 | char newpfx[64]; | ||
| 300 | 306 | ||
| 301 | severity = gdata->error_severity; | 307 | severity = gdata->error_severity; |
| 302 | printk("%s""section: %d, severity: %d, %s\n", pfx, sec_no, severity, | 308 | printk("%s""Error %d, type: %s\n", pfx, sec_no, |
| 303 | cper_severity_str(severity)); | 309 | cper_severity_str(severity)); |
| 304 | printk("%s""flags: 0x%02x\n", pfx, gdata->flags); | ||
| 305 | cper_print_bits(pfx, gdata->flags, apei_estatus_section_flag_strs, | ||
| 306 | ARRAY_SIZE(apei_estatus_section_flag_strs)); | ||
| 307 | if (gdata->validation_bits & CPER_SEC_VALID_FRU_ID) | 310 | if (gdata->validation_bits & CPER_SEC_VALID_FRU_ID) |
| 308 | printk("%s""fru_id: %pUl\n", pfx, (uuid_le *)gdata->fru_id); | 311 | printk("%s""fru_id: %pUl\n", pfx, (uuid_le *)gdata->fru_id); |
| 309 | if (gdata->validation_bits & CPER_SEC_VALID_FRU_TEXT) | 312 | if (gdata->validation_bits & CPER_SEC_VALID_FRU_TEXT) |
| 310 | printk("%s""fru_text: %.20s\n", pfx, gdata->fru_text); | 313 | printk("%s""fru_text: %.20s\n", pfx, gdata->fru_text); |
| 311 | 314 | ||
| 315 | snprintf(newpfx, sizeof(newpfx), "%s%s", pfx, INDENT_SP); | ||
| 312 | if (!uuid_le_cmp(*sec_type, CPER_SEC_PROC_GENERIC)) { | 316 | if (!uuid_le_cmp(*sec_type, CPER_SEC_PROC_GENERIC)) { |
| 313 | struct cper_sec_proc_generic *proc_err = (void *)(gdata + 1); | 317 | struct cper_sec_proc_generic *proc_err = (void *)(gdata + 1); |
| 314 | printk("%s""section_type: general processor error\n", pfx); | 318 | printk("%s""section_type: general processor error\n", newpfx); |
| 315 | if (gdata->error_data_length >= sizeof(*proc_err)) | 319 | if (gdata->error_data_length >= sizeof(*proc_err)) |
| 316 | cper_print_proc_generic(pfx, proc_err); | 320 | cper_print_proc_generic(newpfx, proc_err); |
| 317 | else | 321 | else |
| 318 | goto err_section_too_small; | 322 | goto err_section_too_small; |
| 319 | } else if (!uuid_le_cmp(*sec_type, CPER_SEC_PLATFORM_MEM)) { | 323 | } else if (!uuid_le_cmp(*sec_type, CPER_SEC_PLATFORM_MEM)) { |
| 320 | struct cper_sec_mem_err *mem_err = (void *)(gdata + 1); | 324 | struct cper_sec_mem_err *mem_err = (void *)(gdata + 1); |
| 321 | printk("%s""section_type: memory error\n", pfx); | 325 | printk("%s""section_type: memory error\n", newpfx); |
| 322 | if (gdata->error_data_length >= sizeof(*mem_err)) | 326 | if (gdata->error_data_length >= sizeof(*mem_err)) |
| 323 | cper_print_mem(pfx, mem_err); | 327 | cper_print_mem(newpfx, mem_err); |
| 324 | else | 328 | else |
| 325 | goto err_section_too_small; | 329 | goto err_section_too_small; |
| 326 | } else if (!uuid_le_cmp(*sec_type, CPER_SEC_PCIE)) { | 330 | } else if (!uuid_le_cmp(*sec_type, CPER_SEC_PCIE)) { |
| 327 | struct cper_sec_pcie *pcie = (void *)(gdata + 1); | 331 | struct cper_sec_pcie *pcie = (void *)(gdata + 1); |
| 328 | printk("%s""section_type: PCIe error\n", pfx); | 332 | printk("%s""section_type: PCIe error\n", newpfx); |
| 329 | if (gdata->error_data_length >= sizeof(*pcie)) | 333 | if (gdata->error_data_length >= sizeof(*pcie)) |
| 330 | cper_print_pcie(pfx, pcie, gdata); | 334 | cper_print_pcie(newpfx, pcie, gdata); |
| 331 | else | 335 | else |
| 332 | goto err_section_too_small; | 336 | goto err_section_too_small; |
| 333 | } else | 337 | } else |
| 334 | printk("%s""section type: unknown, %pUl\n", pfx, sec_type); | 338 | printk("%s""section type: unknown, %pUl\n", newpfx, sec_type); |
| 335 | 339 | ||
| 336 | return; | 340 | return; |
| 337 | 341 | ||
| @@ -339,34 +343,38 @@ err_section_too_small: | |||
| 339 | pr_err(FW_WARN "error section length is too small\n"); | 343 | pr_err(FW_WARN "error section length is too small\n"); |
| 340 | } | 344 | } |
| 341 | 345 | ||
| 342 | void apei_estatus_print(const char *pfx, | 346 | void cper_estatus_print(const char *pfx, |
| 343 | const struct acpi_hest_generic_status *estatus) | 347 | const struct acpi_generic_status *estatus) |
| 344 | { | 348 | { |
| 345 | struct acpi_hest_generic_data *gdata; | 349 | struct acpi_generic_data *gdata; |
| 346 | unsigned int data_len, gedata_len; | 350 | unsigned int data_len, gedata_len; |
| 347 | int sec_no = 0; | 351 | int sec_no = 0; |
| 352 | char newpfx[64]; | ||
| 348 | __u16 severity; | 353 | __u16 severity; |
| 349 | 354 | ||
| 350 | printk("%s""APEI generic hardware error status\n", pfx); | ||
| 351 | severity = estatus->error_severity; | 355 | severity = estatus->error_severity; |
| 352 | printk("%s""severity: %d, %s\n", pfx, severity, | 356 | if (severity == CPER_SEV_CORRECTED) |
| 353 | cper_severity_str(severity)); | 357 | printk("%s%s\n", pfx, |
| 358 | "It has been corrected by h/w " | ||
| 359 | "and requires no further action"); | ||
| 360 | printk("%s""event severity: %s\n", pfx, cper_severity_str(severity)); | ||
| 354 | data_len = estatus->data_length; | 361 | data_len = estatus->data_length; |
| 355 | gdata = (struct acpi_hest_generic_data *)(estatus + 1); | 362 | gdata = (struct acpi_generic_data *)(estatus + 1); |
| 356 | while (data_len > sizeof(*gdata)) { | 363 | snprintf(newpfx, sizeof(newpfx), "%s%s", pfx, INDENT_SP); |
| 364 | while (data_len >= sizeof(*gdata)) { | ||
| 357 | gedata_len = gdata->error_data_length; | 365 | gedata_len = gdata->error_data_length; |
| 358 | apei_estatus_print_section(pfx, gdata, sec_no); | 366 | cper_estatus_print_section(newpfx, gdata, sec_no); |
| 359 | data_len -= gedata_len + sizeof(*gdata); | 367 | data_len -= gedata_len + sizeof(*gdata); |
| 360 | gdata = (void *)(gdata + 1) + gedata_len; | 368 | gdata = (void *)(gdata + 1) + gedata_len; |
| 361 | sec_no++; | 369 | sec_no++; |
| 362 | } | 370 | } |
| 363 | } | 371 | } |
| 364 | EXPORT_SYMBOL_GPL(apei_estatus_print); | 372 | EXPORT_SYMBOL_GPL(cper_estatus_print); |
| 365 | 373 | ||
| 366 | int apei_estatus_check_header(const struct acpi_hest_generic_status *estatus) | 374 | int cper_estatus_check_header(const struct acpi_generic_status *estatus) |
| 367 | { | 375 | { |
| 368 | if (estatus->data_length && | 376 | if (estatus->data_length && |
| 369 | estatus->data_length < sizeof(struct acpi_hest_generic_data)) | 377 | estatus->data_length < sizeof(struct acpi_generic_data)) |
| 370 | return -EINVAL; | 378 | return -EINVAL; |
| 371 | if (estatus->raw_data_length && | 379 | if (estatus->raw_data_length && |
| 372 | estatus->raw_data_offset < sizeof(*estatus) + estatus->data_length) | 380 | estatus->raw_data_offset < sizeof(*estatus) + estatus->data_length) |
| @@ -374,19 +382,19 @@ int apei_estatus_check_header(const struct acpi_hest_generic_status *estatus) | |||
| 374 | 382 | ||
| 375 | return 0; | 383 | return 0; |
| 376 | } | 384 | } |
| 377 | EXPORT_SYMBOL_GPL(apei_estatus_check_header); | 385 | EXPORT_SYMBOL_GPL(cper_estatus_check_header); |
| 378 | 386 | ||
| 379 | int apei_estatus_check(const struct acpi_hest_generic_status *estatus) | 387 | int cper_estatus_check(const struct acpi_generic_status *estatus) |
| 380 | { | 388 | { |
| 381 | struct acpi_hest_generic_data *gdata; | 389 | struct acpi_generic_data *gdata; |
| 382 | unsigned int data_len, gedata_len; | 390 | unsigned int data_len, gedata_len; |
| 383 | int rc; | 391 | int rc; |
| 384 | 392 | ||
| 385 | rc = apei_estatus_check_header(estatus); | 393 | rc = cper_estatus_check_header(estatus); |
| 386 | if (rc) | 394 | if (rc) |
| 387 | return rc; | 395 | return rc; |
| 388 | data_len = estatus->data_length; | 396 | data_len = estatus->data_length; |
| 389 | gdata = (struct acpi_hest_generic_data *)(estatus + 1); | 397 | gdata = (struct acpi_generic_data *)(estatus + 1); |
| 390 | while (data_len >= sizeof(*gdata)) { | 398 | while (data_len >= sizeof(*gdata)) { |
| 391 | gedata_len = gdata->error_data_length; | 399 | gedata_len = gdata->error_data_length; |
| 392 | if (gedata_len > data_len - sizeof(*gdata)) | 400 | if (gedata_len > data_len - sizeof(*gdata)) |
| @@ -399,4 +407,4 @@ int apei_estatus_check(const struct acpi_hest_generic_status *estatus) | |||
| 399 | 407 | ||
| 400 | return 0; | 408 | return 0; |
| 401 | } | 409 | } |
| 402 | EXPORT_SYMBOL_GPL(apei_estatus_check); | 410 | EXPORT_SYMBOL_GPL(cper_estatus_check); |
diff --git a/drivers/video/sis/init.c b/drivers/video/sis/init.c index f082ae55c0c9..4f26bc28e60b 100644 --- a/drivers/video/sis/init.c +++ b/drivers/video/sis/init.c | |||
| @@ -3320,9 +3320,8 @@ SiSSetMode(struct SiS_Private *SiS_Pr, unsigned short ModeNo) | |||
| 3320 | } | 3320 | } |
| 3321 | 3321 | ||
| 3322 | #ifndef GETBITSTR | 3322 | #ifndef GETBITSTR |
| 3323 | #define BITMASK(h,l) (((unsigned)(1U << ((h)-(l)+1))-1)<<(l)) | 3323 | #define GENBITSMASK(mask) GENMASK(1?mask,0?mask) |
| 3324 | #define GENMASK(mask) BITMASK(1?mask,0?mask) | 3324 | #define GETBITS(var,mask) (((var) & GENBITSMASK(mask)) >> (0?mask)) |
| 3325 | #define GETBITS(var,mask) (((var) & GENMASK(mask)) >> (0?mask)) | ||
| 3326 | #define GETBITSTR(val,from,to) ((GETBITS(val,from)) << (0?to)) | 3325 | #define GETBITSTR(val,from,to) ((GETBITS(val,from)) << (0?to)) |
| 3327 | #endif | 3326 | #endif |
| 3328 | 3327 | ||
diff --git a/include/acpi/actbl1.h b/include/acpi/actbl1.h index 0bd750ebeb49..556c83ee6b42 100644 --- a/include/acpi/actbl1.h +++ b/include/acpi/actbl1.h | |||
| @@ -596,7 +596,7 @@ struct acpi_hest_generic { | |||
| 596 | 596 | ||
| 597 | /* Generic Error Status block */ | 597 | /* Generic Error Status block */ |
| 598 | 598 | ||
| 599 | struct acpi_hest_generic_status { | 599 | struct acpi_generic_status { |
| 600 | u32 block_status; | 600 | u32 block_status; |
| 601 | u32 raw_data_offset; | 601 | u32 raw_data_offset; |
| 602 | u32 raw_data_length; | 602 | u32 raw_data_length; |
| @@ -606,15 +606,15 @@ struct acpi_hest_generic_status { | |||
| 606 | 606 | ||
| 607 | /* Values for block_status flags above */ | 607 | /* Values for block_status flags above */ |
| 608 | 608 | ||
| 609 | #define ACPI_HEST_UNCORRECTABLE (1) | 609 | #define ACPI_GEN_ERR_UC BIT(0) |
| 610 | #define ACPI_HEST_CORRECTABLE (1<<1) | 610 | #define ACPI_GEN_ERR_CE BIT(1) |
| 611 | #define ACPI_HEST_MULTIPLE_UNCORRECTABLE (1<<2) | 611 | #define ACPI_GEN_ERR_MULTI_UC BIT(2) |
| 612 | #define ACPI_HEST_MULTIPLE_CORRECTABLE (1<<3) | 612 | #define ACPI_GEN_ERR_MULTI_CE BIT(3) |
| 613 | #define ACPI_HEST_ERROR_ENTRY_COUNT (0xFF<<4) /* 8 bits, error count */ | 613 | #define ACPI_GEN_ERR_COUNT_SHIFT (0xFF<<4) /* 8 bits, error count */ |
| 614 | 614 | ||
| 615 | /* Generic Error Data entry */ | 615 | /* Generic Error Data entry */ |
| 616 | 616 | ||
| 617 | struct acpi_hest_generic_data { | 617 | struct acpi_generic_data { |
| 618 | u8 section_type[16]; | 618 | u8 section_type[16]; |
| 619 | u32 error_severity; | 619 | u32 error_severity; |
| 620 | u16 revision; | 620 | u16 revision; |
diff --git a/include/acpi/ghes.h b/include/acpi/ghes.h index 720446cb243e..dfd60d0bfd27 100644 --- a/include/acpi/ghes.h +++ b/include/acpi/ghes.h | |||
| @@ -14,7 +14,7 @@ | |||
| 14 | 14 | ||
| 15 | struct ghes { | 15 | struct ghes { |
| 16 | struct acpi_hest_generic *generic; | 16 | struct acpi_hest_generic *generic; |
| 17 | struct acpi_hest_generic_status *estatus; | 17 | struct acpi_generic_status *estatus; |
| 18 | u64 buffer_paddr; | 18 | u64 buffer_paddr; |
| 19 | unsigned long flags; | 19 | unsigned long flags; |
| 20 | union { | 20 | union { |
diff --git a/include/linux/acpi.h b/include/linux/acpi.h index a5db4aeefa36..c30bac8503bc 100644 --- a/include/linux/acpi.h +++ b/include/linux/acpi.h | |||
| @@ -311,6 +311,7 @@ struct acpi_osc_context { | |||
| 311 | #define OSC_INVALID_REVISION_ERROR 8 | 311 | #define OSC_INVALID_REVISION_ERROR 8 |
| 312 | #define OSC_CAPABILITIES_MASK_ERROR 16 | 312 | #define OSC_CAPABILITIES_MASK_ERROR 16 |
| 313 | 313 | ||
| 314 | acpi_status acpi_str_to_uuid(char *str, u8 *uuid); | ||
| 314 | acpi_status acpi_run_osc(acpi_handle handle, struct acpi_osc_context *context); | 315 | acpi_status acpi_run_osc(acpi_handle handle, struct acpi_osc_context *context); |
| 315 | 316 | ||
| 316 | /* platform-wide _OSC bits */ | 317 | /* platform-wide _OSC bits */ |
diff --git a/include/linux/bitops.h b/include/linux/bitops.h index a3b6b82108b9..bd0c4598d03b 100644 --- a/include/linux/bitops.h +++ b/include/linux/bitops.h | |||
| @@ -10,6 +10,14 @@ | |||
| 10 | #define BITS_TO_LONGS(nr) DIV_ROUND_UP(nr, BITS_PER_BYTE * sizeof(long)) | 10 | #define BITS_TO_LONGS(nr) DIV_ROUND_UP(nr, BITS_PER_BYTE * sizeof(long)) |
| 11 | #endif | 11 | #endif |
| 12 | 12 | ||
| 13 | /* | ||
| 14 | * Create a contiguous bitmask starting at bit position @l and ending at | ||
| 15 | * position @h. For example | ||
| 16 | * GENMASK_ULL(39, 21) gives us the 64bit vector 0x000000ffffe00000. | ||
| 17 | */ | ||
| 18 | #define GENMASK(h, l) (((U32_C(1) << ((h) - (l) + 1)) - 1) << (l)) | ||
| 19 | #define GENMASK_ULL(h, l) (((U64_C(1) << ((h) - (l) + 1)) - 1) << (l)) | ||
| 20 | |||
| 13 | extern unsigned int __sw_hweight8(unsigned int w); | 21 | extern unsigned int __sw_hweight8(unsigned int w); |
| 14 | extern unsigned int __sw_hweight16(unsigned int w); | 22 | extern unsigned int __sw_hweight16(unsigned int w); |
| 15 | extern unsigned int __sw_hweight32(unsigned int w); | 23 | extern unsigned int __sw_hweight32(unsigned int w); |
diff --git a/include/linux/cper.h b/include/linux/cper.h index c23049496531..2fc0ec3d89cc 100644 --- a/include/linux/cper.h +++ b/include/linux/cper.h | |||
| @@ -218,8 +218,8 @@ enum { | |||
| 218 | #define CPER_PROC_VALID_IP 0x1000 | 218 | #define CPER_PROC_VALID_IP 0x1000 |
| 219 | 219 | ||
| 220 | #define CPER_MEM_VALID_ERROR_STATUS 0x0001 | 220 | #define CPER_MEM_VALID_ERROR_STATUS 0x0001 |
| 221 | #define CPER_MEM_VALID_PHYSICAL_ADDRESS 0x0002 | 221 | #define CPER_MEM_VALID_PA 0x0002 |
| 222 | #define CPER_MEM_VALID_PHYSICAL_ADDRESS_MASK 0x0004 | 222 | #define CPER_MEM_VALID_PA_MASK 0x0004 |
| 223 | #define CPER_MEM_VALID_NODE 0x0008 | 223 | #define CPER_MEM_VALID_NODE 0x0008 |
| 224 | #define CPER_MEM_VALID_CARD 0x0010 | 224 | #define CPER_MEM_VALID_CARD 0x0010 |
| 225 | #define CPER_MEM_VALID_MODULE 0x0020 | 225 | #define CPER_MEM_VALID_MODULE 0x0020 |
| @@ -232,6 +232,9 @@ enum { | |||
| 232 | #define CPER_MEM_VALID_RESPONDER_ID 0x1000 | 232 | #define CPER_MEM_VALID_RESPONDER_ID 0x1000 |
| 233 | #define CPER_MEM_VALID_TARGET_ID 0x2000 | 233 | #define CPER_MEM_VALID_TARGET_ID 0x2000 |
| 234 | #define CPER_MEM_VALID_ERROR_TYPE 0x4000 | 234 | #define CPER_MEM_VALID_ERROR_TYPE 0x4000 |
| 235 | #define CPER_MEM_VALID_RANK_NUMBER 0x8000 | ||
| 236 | #define CPER_MEM_VALID_CARD_HANDLE 0x10000 | ||
| 237 | #define CPER_MEM_VALID_MODULE_HANDLE 0x20000 | ||
| 235 | 238 | ||
| 236 | #define CPER_PCIE_VALID_PORT_TYPE 0x0001 | 239 | #define CPER_PCIE_VALID_PORT_TYPE 0x0001 |
| 237 | #define CPER_PCIE_VALID_VERSION 0x0002 | 240 | #define CPER_PCIE_VALID_VERSION 0x0002 |
| @@ -347,6 +350,10 @@ struct cper_sec_mem_err { | |||
| 347 | __u64 responder_id; | 350 | __u64 responder_id; |
| 348 | __u64 target_id; | 351 | __u64 target_id; |
| 349 | __u8 error_type; | 352 | __u8 error_type; |
| 353 | __u8 reserved; | ||
| 354 | __u16 rank; | ||
| 355 | __u16 mem_array_handle; /* card handle in UEFI 2.4 */ | ||
| 356 | __u16 mem_dev_handle; /* module handle in UEFI 2.4 */ | ||
| 350 | }; | 357 | }; |
| 351 | 358 | ||
| 352 | struct cper_sec_pcie { | 359 | struct cper_sec_pcie { |
| @@ -389,6 +396,6 @@ struct cper_sec_pcie { | |||
| 389 | 396 | ||
| 390 | u64 cper_next_record_id(void); | 397 | u64 cper_next_record_id(void); |
| 391 | void cper_print_bits(const char *prefix, unsigned int bits, | 398 | void cper_print_bits(const char *prefix, unsigned int bits, |
| 392 | const char *strs[], unsigned int strs_size); | 399 | const char * const strs[], unsigned int strs_size); |
| 393 | 400 | ||
| 394 | #endif | 401 | #endif |
diff --git a/include/linux/dmi.h b/include/linux/dmi.h index b6eb7a05d58e..f820f0a336c9 100644 --- a/include/linux/dmi.h +++ b/include/linux/dmi.h | |||
| @@ -99,6 +99,7 @@ extern const char * dmi_get_system_info(int field); | |||
| 99 | extern const struct dmi_device * dmi_find_device(int type, const char *name, | 99 | extern const struct dmi_device * dmi_find_device(int type, const char *name, |
| 100 | const struct dmi_device *from); | 100 | const struct dmi_device *from); |
| 101 | extern void dmi_scan_machine(void); | 101 | extern void dmi_scan_machine(void); |
| 102 | extern void dmi_memdev_walk(void); | ||
| 102 | extern void dmi_set_dump_stack_arch_desc(void); | 103 | extern void dmi_set_dump_stack_arch_desc(void); |
| 103 | extern bool dmi_get_date(int field, int *yearp, int *monthp, int *dayp); | 104 | extern bool dmi_get_date(int field, int *yearp, int *monthp, int *dayp); |
| 104 | extern int dmi_name_in_vendors(const char *str); | 105 | extern int dmi_name_in_vendors(const char *str); |
| @@ -107,6 +108,7 @@ extern int dmi_available; | |||
| 107 | extern int dmi_walk(void (*decode)(const struct dmi_header *, void *), | 108 | extern int dmi_walk(void (*decode)(const struct dmi_header *, void *), |
| 108 | void *private_data); | 109 | void *private_data); |
| 109 | extern bool dmi_match(enum dmi_field f, const char *str); | 110 | extern bool dmi_match(enum dmi_field f, const char *str); |
| 111 | extern void dmi_memdev_name(u16 handle, const char **bank, const char **device); | ||
| 110 | 112 | ||
| 111 | #else | 113 | #else |
| 112 | 114 | ||
| @@ -115,6 +117,7 @@ static inline const char * dmi_get_system_info(int field) { return NULL; } | |||
| 115 | static inline const struct dmi_device * dmi_find_device(int type, const char *name, | 117 | static inline const struct dmi_device * dmi_find_device(int type, const char *name, |
| 116 | const struct dmi_device *from) { return NULL; } | 118 | const struct dmi_device *from) { return NULL; } |
| 117 | static inline void dmi_scan_machine(void) { return; } | 119 | static inline void dmi_scan_machine(void) { return; } |
| 120 | static inline void dmi_memdev_walk(void) { } | ||
| 118 | static inline void dmi_set_dump_stack_arch_desc(void) { } | 121 | static inline void dmi_set_dump_stack_arch_desc(void) { } |
| 119 | static inline bool dmi_get_date(int field, int *yearp, int *monthp, int *dayp) | 122 | static inline bool dmi_get_date(int field, int *yearp, int *monthp, int *dayp) |
| 120 | { | 123 | { |
| @@ -133,6 +136,8 @@ static inline int dmi_walk(void (*decode)(const struct dmi_header *, void *), | |||
| 133 | void *private_data) { return -1; } | 136 | void *private_data) { return -1; } |
| 134 | static inline bool dmi_match(enum dmi_field f, const char *str) | 137 | static inline bool dmi_match(enum dmi_field f, const char *str) |
| 135 | { return false; } | 138 | { return false; } |
| 139 | static inline void dmi_memdev_name(u16 handle, const char **bank, | ||
| 140 | const char **device) { } | ||
| 136 | static inline const struct dmi_system_id * | 141 | static inline const struct dmi_system_id * |
| 137 | dmi_first_match(const struct dmi_system_id *list) { return NULL; } | 142 | dmi_first_match(const struct dmi_system_id *list) { return NULL; } |
| 138 | 143 | ||
diff --git a/include/linux/edac.h b/include/linux/edac.h index 5c6d7fbaf89e..dbdffe8d4469 100644 --- a/include/linux/edac.h +++ b/include/linux/edac.h | |||
| @@ -51,7 +51,7 @@ static inline void opstate_init(void) | |||
| 51 | #define EDAC_MC_LABEL_LEN 31 | 51 | #define EDAC_MC_LABEL_LEN 31 |
| 52 | 52 | ||
| 53 | /* Maximum size of the location string */ | 53 | /* Maximum size of the location string */ |
| 54 | #define LOCATION_SIZE 80 | 54 | #define LOCATION_SIZE 256 |
| 55 | 55 | ||
| 56 | /* Defines the maximum number of labels that can be reported */ | 56 | /* Defines the maximum number of labels that can be reported */ |
| 57 | #define EDAC_MAX_LABELS 8 | 57 | #define EDAC_MAX_LABELS 8 |
