Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

Merge branch 'acpi-apei'

* acpi-apei: (29 commits)
efi: cper: Fix possible out-of-bounds access
ACPI: APEI: Fix possible out-of-bounds access to BERT region
MAINTAINERS: Add James Morse to the list of APEI reviewers
ACPI / APEI: Add support for the SDEI GHES Notification type
firmware: arm_sdei: Add ACPI GHES registration helper
ACPI / APEI: Use separate fixmap pages for arm64 NMI-like notifications
ACPI / APEI: Only use queued estatus entry during in_nmi_queue_one_entry()
ACPI / APEI: Split ghes_read_estatus() to allow a peek at the CPER length
ACPI / APEI: Make GHES estatus header validation more user friendly
ACPI / APEI: Pass ghes and estatus separately to avoid a later copy
ACPI / APEI: Let the notification helper specify the fixmap slot
ACPI / APEI: Move locking to the notification helper
arm64: KVM/mm: Move SEA handling behind a single 'claim' interface
KVM: arm/arm64: Add kvm_ras.h to collect kvm specific RAS plumbing
ACPI / APEI: Switch NOTIFY_SEA to use the estatus queue
ACPI / APEI: Move NOTIFY_SEA between the estatus-queue and NOTIFY_NMI
ACPI / APEI: Don't allow ghes_ack_error() to mask earlier errors
ACPI / APEI: Generalise the estatus queue's notify code
ACPI / APEI: Don't update struct ghes' flags in read/clear estatus
ACPI / APEI: Remove spurious GHES_TO_CLEAR check
...

+598 -375
+1
MAINTAINERS
··· 331 331 M: "Rafael J. Wysocki" <rjw@rjwysocki.net> 332 332 M: Len Brown <lenb@kernel.org> 333 333 L: linux-acpi@vger.kernel.org 334 + R: James Morse <james.morse@arm.com> 334 335 R: Tony Luck <tony.luck@intel.com> 335 336 R: Borislav Petkov <bp@alien8.de> 336 337 F: drivers/acpi/apei/
+14
arch/arm/include/asm/kvm_ras.h
··· 1 + /* SPDX-License-Identifier: GPL-2.0 */ 2 + /* Copyright (C) 2018 - Arm Ltd */ 3 + 4 + #ifndef __ARM_KVM_RAS_H__ 5 + #define __ARM_KVM_RAS_H__ 6 + 7 + #include <linux/types.h> 8 + 9 + static inline int kvm_handle_guest_sea(phys_addr_t addr, unsigned int esr) 10 + { 11 + return -1; 12 + } 13 + 14 + #endif /* __ARM_KVM_RAS_H__ */
-5
arch/arm/include/asm/system_misc.h
··· 38 38 39 39 extern unsigned int user_debug; 40 40 41 - static inline int handle_guest_sea(phys_addr_t addr, unsigned int esr) 42 - { 43 - return -1; 44 - } 45 - 46 41 #endif /* !__ASSEMBLY__ */ 47 42 48 43 #endif /* __ASM_ARM_SYSTEM_MISC_H */
+3 -1
arch/arm64/include/asm/acpi.h
··· 18 18 19 19 #include <asm/cputype.h> 20 20 #include <asm/io.h> 21 + #include <asm/ptrace.h> 21 22 #include <asm/smp_plat.h> 22 23 #include <asm/tlbflush.h> 23 24 ··· 111 110 112 111 static inline void arch_fix_phys_package_id(int num, u32 slot) { } 113 112 void __init acpi_init_cpus(void); 114 - 113 + int apei_claim_sea(struct pt_regs *regs); 115 114 #else 116 115 static inline void acpi_init_cpus(void) { } 116 + static inline int apei_claim_sea(struct pt_regs *regs) { return -ENOENT; } 117 117 #endif /* CONFIG_ACPI */ 118 118 119 119 #ifdef CONFIG_ARM64_ACPI_PARKING_PROTOCOL
+1
arch/arm64/include/asm/daifflags.h
··· 20 20 21 21 #define DAIF_PROCCTX 0 22 22 #define DAIF_PROCCTX_NOIRQ PSR_I_BIT 23 + #define DAIF_ERRCTX (PSR_I_BIT | PSR_A_BIT) 23 24 24 25 /* mask/save/unmask/restore all exceptions, including interrupts. */ 25 26 static inline void local_daif_mask(void)
+5 -1
arch/arm64/include/asm/fixmap.h
··· 55 55 #ifdef CONFIG_ACPI_APEI_GHES 56 56 /* Used for GHES mapping from assorted contexts */ 57 57 FIX_APEI_GHES_IRQ, 58 - FIX_APEI_GHES_NMI, 58 + FIX_APEI_GHES_SEA, 59 + #ifdef CONFIG_ARM_SDE_INTERFACE 60 + FIX_APEI_GHES_SDEI_NORMAL, 61 + FIX_APEI_GHES_SDEI_CRITICAL, 62 + #endif 59 63 #endif /* CONFIG_ACPI_APEI_GHES */ 60 64 61 65 #ifdef CONFIG_UNMAP_KERNEL_AT_EL0
+25
arch/arm64/include/asm/kvm_ras.h
··· 1 + /* SPDX-License-Identifier: GPL-2.0 */ 2 + /* Copyright (C) 2018 - Arm Ltd */ 3 + 4 + #ifndef __ARM64_KVM_RAS_H__ 5 + #define __ARM64_KVM_RAS_H__ 6 + 7 + #include <linux/acpi.h> 8 + #include <linux/errno.h> 9 + #include <linux/types.h> 10 + 11 + #include <asm/acpi.h> 12 + 13 + /* 14 + * Was this synchronous external abort a RAS notification? 15 + * Returns '0' for errors handled by some RAS subsystem, or -ENOENT. 16 + */ 17 + static inline int kvm_handle_guest_sea(phys_addr_t addr, unsigned int esr) 18 + { 19 + /* apei_claim_sea(NULL) expects to mask interrupts itself */ 20 + lockdep_assert_irqs_enabled(); 21 + 22 + return apei_claim_sea(NULL); 23 + } 24 + 25 + #endif /* __ARM64_KVM_RAS_H__ */
-2
arch/arm64/include/asm/system_misc.h
··· 46 46 47 47 extern void (*arm_pm_restart)(enum reboot_mode reboot_mode, const char *cmd); 48 48 49 - int handle_guest_sea(phys_addr_t addr, unsigned int esr); 50 - 51 49 #endif /* __ASSEMBLY__ */ 52 50 53 51 #endif /* __ASM_SYSTEM_MISC_H */
+31
arch/arm64/kernel/acpi.c
··· 27 27 #include <linux/smp.h> 28 28 #include <linux/serial_core.h> 29 29 30 + #include <acpi/ghes.h> 30 31 #include <asm/cputype.h> 31 32 #include <asm/cpu_ops.h> 33 + #include <asm/daifflags.h> 32 34 #include <asm/pgtable.h> 33 35 #include <asm/smp_plat.h> 34 36 ··· 257 255 if (attr & EFI_MEMORY_WC) 258 256 return __pgprot(PROT_NORMAL_NC); 259 257 return __pgprot(PROT_DEVICE_nGnRnE); 258 + } 259 + 260 + /* 261 + * Claim Synchronous External Aborts as a firmware first notification. 262 + * 263 + * Used by KVM and the arch do_sea handler. 264 + * @regs may be NULL when called from process context. 265 + */ 266 + int apei_claim_sea(struct pt_regs *regs) 267 + { 268 + int err = -ENOENT; 269 + unsigned long current_flags; 270 + 271 + if (!IS_ENABLED(CONFIG_ACPI_APEI_GHES)) 272 + return err; 273 + 274 + current_flags = arch_local_save_flags(); 275 + 276 + /* 277 + * SEA can interrupt SError, mask it and describe this as an NMI so 278 + * that APEI defers the handling. 279 + */ 280 + local_daif_restore(DAIF_ERRCTX); 281 + nmi_enter(); 282 + err = ghes_notify_sea(); 283 + nmi_exit(); 284 + local_daif_restore(current_flags); 285 + 286 + return err; 260 287 }
+5 -19
arch/arm64/mm/fault.c
··· 18 18 * along with this program. If not, see <http://www.gnu.org/licenses/>. 19 19 */ 20 20 21 + #include <linux/acpi.h> 21 22 #include <linux/extable.h> 22 23 #include <linux/signal.h> 23 24 #include <linux/mm.h> ··· 34 33 #include <linux/preempt.h> 35 34 #include <linux/hugetlb.h> 36 35 36 + #include <asm/acpi.h> 37 37 #include <asm/bug.h> 38 38 #include <asm/cmpxchg.h> 39 39 #include <asm/cpufeature.h> ··· 48 46 #include <asm/pgtable.h> 49 47 #include <asm/tlbflush.h> 50 48 #include <asm/traps.h> 51 - 52 - #include <acpi/ghes.h> 53 49 54 50 struct fault_info { 55 51 int (*fn)(unsigned long addr, unsigned int esr, ··· 643 643 inf = esr_to_fault_info(esr); 644 644 645 645 /* 646 - * Synchronous aborts may interrupt code which had interrupts masked. 647 - * Before calling out into the wider kernel tell the interested 648 - * subsystems. 646 + * Return value ignored as we rely on signal merging. 647 + * Future patches will make this more robust. 649 648 */ 650 - if (IS_ENABLED(CONFIG_ACPI_APEI_SEA)) { 651 - if (interrupts_enabled(regs)) 652 - nmi_enter(); 653 - 654 - ghes_notify_sea(); 655 - 656 - if (interrupts_enabled(regs)) 657 - nmi_exit(); 658 - } 649 + apei_claim_sea(regs); 659 650 660 651 if (esr & ESR_ELx_FnV) 661 652 siaddr = NULL; ··· 723 732 { do_bad, SIGKILL, SI_KERNEL, "page domain fault" }, 724 733 { do_bad, SIGKILL, SI_KERNEL, "unknown 63" }, 725 734 }; 726 - 727 - int handle_guest_sea(phys_addr_t addr, unsigned int esr) 728 - { 729 - return ghes_notify_sea(); 730 - } 731 735 732 736 asmlinkage void __exception do_mem_abort(unsigned long addr, unsigned int esr, 733 737 struct pt_regs *regs)
+1 -11
drivers/acpi/apei/Kconfig
··· 41 41 Turn on this option to enable the corresponding support. 42 42 43 43 config ACPI_APEI_SEA 44 - bool "APEI Synchronous External Abort logging/recovering support" 44 + bool 45 45 depends on ARM64 && ACPI_APEI_GHES 46 46 default y 47 - help 48 - This option should be enabled if the system supports 49 - firmware first handling of SEA (Synchronous External Abort). 50 - SEA happens with certain faults of data abort or instruction 51 - abort synchronous exceptions on ARMv8 systems. If a system 52 - supports firmware first handling of SEA, the platform analyzes 53 - and handles hardware error notifications from SEA, and it may then 54 - form a HW error record for the OS to parse and handle. This 55 - option allows the OS to look for such hardware error record, and 56 - take appropriate action. 57 47 58 48 config ACPI_APEI_MEMORY_FAILURE 59 49 bool "APEI memory error recovering support"
+10 -13
drivers/acpi/apei/bert.c
··· 42 42 int remain = region_len; 43 43 u32 estatus_len; 44 44 45 - if (!estatus->block_status) 46 - return; 47 - 48 - while (remain > sizeof(struct acpi_bert_region)) { 49 - if (cper_estatus_check(estatus)) { 50 - pr_err(FW_BUG "Invalid error record.\n"); 51 - return; 52 - } 53 - 45 + while (remain >= sizeof(struct acpi_bert_region)) { 54 46 estatus_len = cper_estatus_len(estatus); 55 47 if (remain < estatus_len) { 56 48 pr_err(FW_BUG "Truncated status block (length: %u).\n", 57 49 estatus_len); 50 + return; 51 + } 52 + 53 + /* No more error records. */ 54 + if (!estatus->block_status) 55 + return; 56 + 57 + if (cper_estatus_check(estatus)) { 58 + pr_err(FW_BUG "Invalid error record.\n"); 58 59 return; 59 60 } 60 61 ··· 71 70 estatus->block_status = 0; 72 71 73 72 estatus = (void *)estatus + estatus_len; 74 - /* No more error records. */ 75 - if (!estatus->block_status) 76 - return; 77 - 78 73 remain -= estatus_len; 79 74 } 80 75 }
+7 -8
drivers/acpi/apei/einj.c
··· 644 644 return 0; 645 645 } 646 646 647 - DEFINE_SIMPLE_ATTRIBUTE(error_type_fops, error_type_get, 648 - error_type_set, "0x%llx\n"); 647 + DEFINE_DEBUGFS_ATTRIBUTE(error_type_fops, error_type_get, error_type_set, 648 + "0x%llx\n"); 649 649 650 650 static int error_inject_set(void *data, u64 val) 651 651 { ··· 656 656 error_param3, error_param4); 657 657 } 658 658 659 - DEFINE_SIMPLE_ATTRIBUTE(error_inject_fops, NULL, 660 - error_inject_set, "%llu\n"); 659 + DEFINE_DEBUGFS_ATTRIBUTE(error_inject_fops, NULL, error_inject_set, "%llu\n"); 661 660 662 661 static int einj_check_table(struct acpi_table_einj *einj_tab) 663 662 { ··· 708 709 709 710 debugfs_create_file("available_error_type", S_IRUSR, einj_debug_dir, 710 711 NULL, &available_error_type_fops); 711 - debugfs_create_file("error_type", S_IRUSR | S_IWUSR, einj_debug_dir, 712 - NULL, &error_type_fops); 713 - debugfs_create_file("error_inject", S_IWUSR, einj_debug_dir, 714 - NULL, &error_inject_fops); 712 + debugfs_create_file_unsafe("error_type", 0600, einj_debug_dir, 713 + NULL, &error_type_fops); 714 + debugfs_create_file_unsafe("error_inject", 0200, einj_debug_dir, 715 + NULL, &error_inject_fops); 715 716 716 717 apei_resources_init(&einj_resources); 717 718 einj_exec_ctx_init(&ctx);
+12 -15
drivers/acpi/apei/erst.c
··· 938 938 }; 939 939 940 940 #define CPER_CREATOR_PSTORE \ 941 - UUID_LE(0x75a574e3, 0x5052, 0x4b29, 0x8a, 0x8e, 0xbe, 0x2c, \ 942 - 0x64, 0x90, 0xb8, 0x9d) 941 + GUID_INIT(0x75a574e3, 0x5052, 0x4b29, 0x8a, 0x8e, 0xbe, 0x2c, \ 942 + 0x64, 0x90, 0xb8, 0x9d) 943 943 #define CPER_SECTION_TYPE_DMESG \ 944 - UUID_LE(0xc197e04e, 0xd545, 0x4a70, 0x9c, 0x17, 0xa5, 0x54, \ 945 - 0x94, 0x19, 0xeb, 0x12) 944 + GUID_INIT(0xc197e04e, 0xd545, 0x4a70, 0x9c, 0x17, 0xa5, 0x54, \ 945 + 0x94, 0x19, 0xeb, 0x12) 946 946 #define CPER_SECTION_TYPE_DMESG_Z \ 947 - UUID_LE(0x4f118707, 0x04dd, 0x4055, 0xb5, 0xdd, 0x95, 0x6d, \ 948 - 0x34, 0xdd, 0xfa, 0xc6) 947 + GUID_INIT(0x4f118707, 0x04dd, 0x4055, 0xb5, 0xdd, 0x95, 0x6d, \ 948 + 0x34, 0xdd, 0xfa, 0xc6) 949 949 #define CPER_SECTION_TYPE_MCE \ 950 - UUID_LE(0xfe08ffbe, 0x95e4, 0x4be7, 0xbc, 0x73, 0x40, 0x96, \ 951 - 0x04, 0x4a, 0x38, 0xfc) 950 + GUID_INIT(0xfe08ffbe, 0x95e4, 0x4be7, 0xbc, 0x73, 0x40, 0x96, \ 951 + 0x04, 0x4a, 0x38, 0xfc) 952 952 953 953 struct cper_pstore_record { 954 954 struct cper_record_header hdr; ··· 1012 1012 rc = -EIO; 1013 1013 goto out; 1014 1014 } 1015 - if (uuid_le_cmp(rcd->hdr.creator_id, CPER_CREATOR_PSTORE) != 0) 1015 + if (!guid_equal(&rcd->hdr.creator_id, &CPER_CREATOR_PSTORE)) 1016 1016 goto skip; 1017 1017 1018 1018 record->buf = kmalloc(len, GFP_KERNEL); ··· 1024 1024 record->id = record_id; 1025 1025 record->compressed = false; 1026 1026 record->ecc_notice_size = 0; 1027 - if (uuid_le_cmp(rcd->sec_hdr.section_type, 1028 - CPER_SECTION_TYPE_DMESG_Z) == 0) { 1027 + if (guid_equal(&rcd->sec_hdr.section_type, &CPER_SECTION_TYPE_DMESG_Z)) { 1029 1028 record->type = PSTORE_TYPE_DMESG; 1030 1029 record->compressed = true; 1031 - } else if (uuid_le_cmp(rcd->sec_hdr.section_type, 1032 - CPER_SECTION_TYPE_DMESG) == 0) 1030 + } else if (guid_equal(&rcd->sec_hdr.section_type, &CPER_SECTION_TYPE_DMESG)) 1033 1031 record->type = PSTORE_TYPE_DMESG; 1034 - else if (uuid_le_cmp(rcd->sec_hdr.section_type, 1035 - CPER_SECTION_TYPE_MCE) == 0) 1032 + else if (guid_equal(&rcd->sec_hdr.section_type, &CPER_SECTION_TYPE_MCE)) 1036 1033 record->type = PSTORE_TYPE_MCE; 1037 1034 else 1038 1035 record->type = PSTORE_TYPE_MAX;
+378 -291
drivers/acpi/apei/ghes.c
··· 25 25 * GNU General Public License for more details. 26 26 */ 27 27 28 + #include <linux/arm_sdei.h> 28 29 #include <linux/kernel.h> 29 30 #include <linux/moduleparam.h> 30 31 #include <linux/init.h> ··· 34 33 #include <linux/interrupt.h> 35 34 #include <linux/timer.h> 36 35 #include <linux/cper.h> 37 - #include <linux/kdebug.h> 38 36 #include <linux/platform_device.h> 39 37 #include <linux/mutex.h> 40 38 #include <linux/ratelimit.h> ··· 42 42 #include <linux/llist.h> 43 43 #include <linux/genalloc.h> 44 44 #include <linux/pci.h> 45 + #include <linux/pfn.h> 45 46 #include <linux/aer.h> 46 47 #include <linux/nmi.h> 47 48 #include <linux/sched/clock.h> ··· 86 85 ((struct acpi_hest_generic_status *) \ 87 86 ((struct ghes_estatus_node *)(estatus_node) + 1)) 88 87 88 + /* 89 + * NMI-like notifications vary by architecture, before the compiler can prune 90 + * unused static functions it needs a value for these enums. 91 + */ 92 + #ifndef CONFIG_ARM_SDE_INTERFACE 93 + #define FIX_APEI_GHES_SDEI_NORMAL __end_of_fixed_addresses 94 + #define FIX_APEI_GHES_SDEI_CRITICAL __end_of_fixed_addresses 95 + #endif 96 + 89 97 static inline bool is_hest_type_generic_v2(struct ghes *ghes) 90 98 { 91 99 return ghes->generic->header.type == ACPI_HEST_TYPE_GENERIC_ERROR_V2; ··· 125 115 * handler, but general ioremap can not be used in atomic context, so 126 116 * the fixmap is used instead. 127 117 * 128 - * These 2 spinlocks are used to prevent the fixmap entries from being used 118 + * This spinlock is used to prevent the fixmap entry from being used 129 119 * simultaneously. 130 120 */ 131 - static DEFINE_RAW_SPINLOCK(ghes_ioremap_lock_nmi); 132 - static DEFINE_SPINLOCK(ghes_ioremap_lock_irq); 121 + static DEFINE_SPINLOCK(ghes_notify_lock_irq); 133 122 134 123 static struct gen_pool *ghes_estatus_pool; 135 124 static unsigned long ghes_estatus_pool_size_request; ··· 138 129 139 130 static int ghes_panic_timeout __read_mostly = 30; 140 131 141 - static void __iomem *ghes_ioremap_pfn_nmi(u64 pfn) 132 + static void __iomem *ghes_map(u64 pfn, enum fixed_addresses fixmap_idx) 142 133 { 143 134 phys_addr_t paddr; 144 135 pgprot_t prot; 145 136 146 - paddr = pfn << PAGE_SHIFT; 137 + paddr = PFN_PHYS(pfn); 147 138 prot = arch_apei_get_mem_attribute(paddr); 148 - __set_fixmap(FIX_APEI_GHES_NMI, paddr, prot); 139 + __set_fixmap(fixmap_idx, paddr, prot); 149 140 150 - return (void __iomem *) fix_to_virt(FIX_APEI_GHES_NMI); 141 + return (void __iomem *) __fix_to_virt(fixmap_idx); 151 142 } 152 143 153 - static void __iomem *ghes_ioremap_pfn_irq(u64 pfn) 144 + static void ghes_unmap(void __iomem *vaddr, enum fixed_addresses fixmap_idx) 154 145 { 155 - phys_addr_t paddr; 156 - pgprot_t prot; 146 + int _idx = virt_to_fix((unsigned long)vaddr); 157 147 158 - paddr = pfn << PAGE_SHIFT; 159 - prot = arch_apei_get_mem_attribute(paddr); 160 - __set_fixmap(FIX_APEI_GHES_IRQ, paddr, prot); 161 - 162 - return (void __iomem *) fix_to_virt(FIX_APEI_GHES_IRQ); 148 + WARN_ON_ONCE(fixmap_idx != _idx); 149 + clear_fixmap(fixmap_idx); 163 150 } 164 151 165 - static void ghes_iounmap_nmi(void) 152 + int ghes_estatus_pool_init(int num_ghes) 166 153 { 167 - clear_fixmap(FIX_APEI_GHES_NMI); 168 - } 154 + unsigned long addr, len; 169 155 170 - static void ghes_iounmap_irq(void) 171 - { 172 - clear_fixmap(FIX_APEI_GHES_IRQ); 173 - } 174 - 175 - static int ghes_estatus_pool_init(void) 176 - { 177 156 ghes_estatus_pool = gen_pool_create(GHES_ESTATUS_POOL_MIN_ALLOC_ORDER, -1); 178 157 if (!ghes_estatus_pool) 179 158 return -ENOMEM; 180 - return 0; 181 - } 182 159 183 - static void ghes_estatus_pool_free_chunk_page(struct gen_pool *pool, 184 - struct gen_pool_chunk *chunk, 185 - void *data) 186 - { 187 - free_page(chunk->start_addr); 188 - } 160 + len = GHES_ESTATUS_CACHE_AVG_SIZE * GHES_ESTATUS_CACHE_ALLOCED_MAX; 161 + len += (num_ghes * GHES_ESOURCE_PREALLOC_MAX_SIZE); 189 162 190 - static void ghes_estatus_pool_exit(void) 191 - { 192 - gen_pool_for_each_chunk(ghes_estatus_pool, 193 - ghes_estatus_pool_free_chunk_page, NULL); 194 - gen_pool_destroy(ghes_estatus_pool); 195 - } 163 + ghes_estatus_pool_size_request = PAGE_ALIGN(len); 164 + addr = (unsigned long)vmalloc(PAGE_ALIGN(len)); 165 + if (!addr) 166 + return -ENOMEM; 196 167 197 - static int ghes_estatus_pool_expand(unsigned long len) 198 - { 199 - unsigned long i, pages, size, addr; 200 - int ret; 168 + /* 169 + * New allocation must be visible in all pgd before it can be found by 170 + * an NMI allocating from the pool. 171 + */ 172 + vmalloc_sync_all(); 201 173 202 - ghes_estatus_pool_size_request += PAGE_ALIGN(len); 203 - size = gen_pool_size(ghes_estatus_pool); 204 - if (size >= ghes_estatus_pool_size_request) 205 - return 0; 206 - pages = (ghes_estatus_pool_size_request - size) / PAGE_SIZE; 207 - for (i = 0; i < pages; i++) { 208 - addr = __get_free_page(GFP_KERNEL); 209 - if (!addr) 210 - return -ENOMEM; 211 - ret = gen_pool_add(ghes_estatus_pool, addr, PAGE_SIZE, -1); 212 - if (ret) 213 - return ret; 214 - } 215 - 216 - return 0; 174 + return gen_pool_add(ghes_estatus_pool, addr, PAGE_ALIGN(len), -1); 217 175 } 218 176 219 177 static int map_gen_v2(struct ghes *ghes) ··· 191 215 static void unmap_gen_v2(struct ghes *ghes) 192 216 { 193 217 apei_unmap_generic_address(&ghes->generic_v2->read_ack_register); 218 + } 219 + 220 + static void ghes_ack_error(struct acpi_hest_generic_v2 *gv2) 221 + { 222 + int rc; 223 + u64 val = 0; 224 + 225 + rc = apei_read(&val, &gv2->read_ack_register); 226 + if (rc) 227 + return; 228 + 229 + val &= gv2->read_ack_preserve << gv2->read_ack_register.bit_offset; 230 + val |= gv2->read_ack_write << gv2->read_ack_register.bit_offset; 231 + 232 + apei_write(val, &gv2->read_ack_register); 194 233 } 195 234 196 235 static struct ghes *ghes_new(struct acpi_hest_generic *generic) ··· 280 289 } 281 290 282 291 static void ghes_copy_tofrom_phys(void *buffer, u64 paddr, u32 len, 283 - int from_phys) 292 + int from_phys, 293 + enum fixed_addresses fixmap_idx) 284 294 { 285 295 void __iomem *vaddr; 286 - unsigned long flags = 0; 287 - int in_nmi = in_nmi(); 288 296 u64 offset; 289 297 u32 trunk; 290 298 291 299 while (len > 0) { 292 300 offset = paddr - (paddr & PAGE_MASK); 293 - if (in_nmi) { 294 - raw_spin_lock(&ghes_ioremap_lock_nmi); 295 - vaddr = ghes_ioremap_pfn_nmi(paddr >> PAGE_SHIFT); 296 - } else { 297 - spin_lock_irqsave(&ghes_ioremap_lock_irq, flags); 298 - vaddr = ghes_ioremap_pfn_irq(paddr >> PAGE_SHIFT); 299 - } 301 + vaddr = ghes_map(PHYS_PFN(paddr), fixmap_idx); 300 302 trunk = PAGE_SIZE - offset; 301 303 trunk = min(trunk, len); 302 304 if (from_phys) ··· 299 315 len -= trunk; 300 316 paddr += trunk; 301 317 buffer += trunk; 302 - if (in_nmi) { 303 - ghes_iounmap_nmi(); 304 - raw_spin_unlock(&ghes_ioremap_lock_nmi); 305 - } else { 306 - ghes_iounmap_irq(); 307 - spin_unlock_irqrestore(&ghes_ioremap_lock_irq, flags); 308 - } 318 + ghes_unmap(vaddr, fixmap_idx); 309 319 } 310 320 } 311 321 312 - static int ghes_read_estatus(struct ghes *ghes, int silent) 322 + /* Check the top-level record header has an appropriate size. */ 323 + static int __ghes_check_estatus(struct ghes *ghes, 324 + struct acpi_hest_generic_status *estatus) 325 + { 326 + u32 len = cper_estatus_len(estatus); 327 + 328 + if (len < sizeof(*estatus)) { 329 + pr_warn_ratelimited(FW_WARN GHES_PFX "Truncated error status block!\n"); 330 + return -EIO; 331 + } 332 + 333 + if (len > ghes->generic->error_block_length) { 334 + pr_warn_ratelimited(FW_WARN GHES_PFX "Invalid error status block length!\n"); 335 + return -EIO; 336 + } 337 + 338 + if (cper_estatus_check_header(estatus)) { 339 + pr_warn_ratelimited(FW_WARN GHES_PFX "Invalid CPER header!\n"); 340 + return -EIO; 341 + } 342 + 343 + return 0; 344 + } 345 + 346 + /* Read the CPER block, returning its address, and header in estatus. */ 347 + static int __ghes_peek_estatus(struct ghes *ghes, 348 + struct acpi_hest_generic_status *estatus, 349 + u64 *buf_paddr, enum fixed_addresses fixmap_idx) 313 350 { 314 351 struct acpi_hest_generic *g = ghes->generic; 315 - u64 buf_paddr; 316 - u32 len; 317 352 int rc; 318 353 319 - rc = apei_read(&buf_paddr, &g->error_status_address); 354 + rc = apei_read(buf_paddr, &g->error_status_address); 320 355 if (rc) { 321 - if (!silent && printk_ratelimit()) 322 - pr_warning(FW_WARN GHES_PFX 356 + *buf_paddr = 0; 357 + pr_warn_ratelimited(FW_WARN GHES_PFX 323 358 "Failed to read error status block address for hardware error source: %d.\n", 324 359 g->header.source_id); 325 360 return -EIO; 326 361 } 327 - if (!buf_paddr) 362 + if (!*buf_paddr) 328 363 return -ENOENT; 329 364 330 - ghes_copy_tofrom_phys(ghes->estatus, buf_paddr, 331 - sizeof(*ghes->estatus), 1); 332 - if (!ghes->estatus->block_status) 365 + ghes_copy_tofrom_phys(estatus, *buf_paddr, sizeof(*estatus), 1, 366 + fixmap_idx); 367 + if (!estatus->block_status) { 368 + *buf_paddr = 0; 333 369 return -ENOENT; 370 + } 334 371 335 - ghes->buffer_paddr = buf_paddr; 336 - ghes->flags |= GHES_TO_CLEAR; 337 - 338 - rc = -EIO; 339 - len = cper_estatus_len(ghes->estatus); 340 - if (len < sizeof(*ghes->estatus)) 341 - goto err_read_block; 342 - if (len > ghes->generic->error_block_length) 343 - goto err_read_block; 344 - if (cper_estatus_check_header(ghes->estatus)) 345 - goto err_read_block; 346 - ghes_copy_tofrom_phys(ghes->estatus + 1, 347 - buf_paddr + sizeof(*ghes->estatus), 348 - len - sizeof(*ghes->estatus), 1); 349 - if (cper_estatus_check(ghes->estatus)) 350 - goto err_read_block; 351 - rc = 0; 352 - 353 - err_read_block: 354 - if (rc && !silent && printk_ratelimit()) 355 - pr_warning(FW_WARN GHES_PFX 356 - "Failed to read error status block!\n"); 357 - return rc; 372 + return __ghes_check_estatus(ghes, estatus); 358 373 } 359 374 360 - static void ghes_clear_estatus(struct ghes *ghes) 375 + static int __ghes_read_estatus(struct acpi_hest_generic_status *estatus, 376 + u64 buf_paddr, enum fixed_addresses fixmap_idx, 377 + size_t buf_len) 361 378 { 362 - ghes->estatus->block_status = 0; 363 - if (!(ghes->flags & GHES_TO_CLEAR)) 379 + ghes_copy_tofrom_phys(estatus, buf_paddr, buf_len, 1, fixmap_idx); 380 + if (cper_estatus_check(estatus)) { 381 + pr_warn_ratelimited(FW_WARN GHES_PFX 382 + "Failed to read error status block!\n"); 383 + return -EIO; 384 + } 385 + 386 + return 0; 387 + } 388 + 389 + static int ghes_read_estatus(struct ghes *ghes, 390 + struct acpi_hest_generic_status *estatus, 391 + u64 *buf_paddr, enum fixed_addresses fixmap_idx) 392 + { 393 + int rc; 394 + 395 + rc = __ghes_peek_estatus(ghes, estatus, buf_paddr, fixmap_idx); 396 + if (rc) 397 + return rc; 398 + 399 + rc = __ghes_check_estatus(ghes, estatus); 400 + if (rc) 401 + return rc; 402 + 403 + return __ghes_read_estatus(estatus, *buf_paddr, fixmap_idx, 404 + cper_estatus_len(estatus)); 405 + } 406 + 407 + static void ghes_clear_estatus(struct ghes *ghes, 408 + struct acpi_hest_generic_status *estatus, 409 + u64 buf_paddr, enum fixed_addresses fixmap_idx) 410 + { 411 + estatus->block_status = 0; 412 + 413 + if (!buf_paddr) 364 414 return; 365 - ghes_copy_tofrom_phys(ghes->estatus, ghes->buffer_paddr, 366 - sizeof(ghes->estatus->block_status), 0); 367 - ghes->flags &= ~GHES_TO_CLEAR; 415 + 416 + ghes_copy_tofrom_phys(estatus, buf_paddr, 417 + sizeof(estatus->block_status), 0, 418 + fixmap_idx); 419 + 420 + /* 421 + * GHESv2 type HEST entries introduce support for error acknowledgment, 422 + * so only acknowledge the error if this support is present. 423 + */ 424 + if (is_hest_type_generic_v2(ghes)) 425 + ghes_ack_error(ghes->generic_v2); 368 426 } 369 427 370 428 static void ghes_handle_memory_failure(struct acpi_hest_generic_data *gdata, int sev) ··· 698 672 rcu_read_unlock(); 699 673 } 700 674 701 - static int ghes_ack_error(struct acpi_hest_generic_v2 *gv2) 675 + static void __ghes_panic(struct ghes *ghes, 676 + struct acpi_hest_generic_status *estatus, 677 + u64 buf_paddr, enum fixed_addresses fixmap_idx) 702 678 { 703 - int rc; 704 - u64 val = 0; 679 + __ghes_print_estatus(KERN_EMERG, ghes->generic, estatus); 705 680 706 - rc = apei_read(&val, &gv2->read_ack_register); 707 - if (rc) 708 - return rc; 709 - 710 - val &= gv2->read_ack_preserve << gv2->read_ack_register.bit_offset; 711 - val |= gv2->read_ack_write << gv2->read_ack_register.bit_offset; 712 - 713 - return apei_write(val, &gv2->read_ack_register); 714 - } 715 - 716 - static void __ghes_panic(struct ghes *ghes) 717 - { 718 - __ghes_print_estatus(KERN_EMERG, ghes->generic, ghes->estatus); 719 - 720 - ghes_clear_estatus(ghes); 681 + ghes_clear_estatus(ghes, estatus, buf_paddr, fixmap_idx); 721 682 722 683 /* reboot to log the error! */ 723 684 if (!panic_timeout) ··· 714 701 715 702 static int ghes_proc(struct ghes *ghes) 716 703 { 704 + struct acpi_hest_generic_status *estatus = ghes->estatus; 705 + u64 buf_paddr; 717 706 int rc; 718 707 719 - rc = ghes_read_estatus(ghes, 0); 708 + rc = ghes_read_estatus(ghes, estatus, &buf_paddr, FIX_APEI_GHES_IRQ); 720 709 if (rc) 721 710 goto out; 722 711 723 - if (ghes_severity(ghes->estatus->error_severity) >= GHES_SEV_PANIC) { 724 - __ghes_panic(ghes); 725 - } 712 + if (ghes_severity(estatus->error_severity) >= GHES_SEV_PANIC) 713 + __ghes_panic(ghes, estatus, buf_paddr, FIX_APEI_GHES_IRQ); 726 714 727 - if (!ghes_estatus_cached(ghes->estatus)) { 728 - if (ghes_print_estatus(NULL, ghes->generic, ghes->estatus)) 729 - ghes_estatus_cache_add(ghes->generic, ghes->estatus); 715 + if (!ghes_estatus_cached(estatus)) { 716 + if (ghes_print_estatus(NULL, ghes->generic, estatus)) 717 + ghes_estatus_cache_add(ghes->generic, estatus); 730 718 } 731 - ghes_do_proc(ghes, ghes->estatus); 719 + ghes_do_proc(ghes, estatus); 732 720 733 721 out: 734 - ghes_clear_estatus(ghes); 735 - 736 - if (rc == -ENOENT) 737 - return rc; 738 - 739 - /* 740 - * GHESv2 type HEST entries introduce support for error acknowledgment, 741 - * so only acknowledge the error if this support is present. 742 - */ 743 - if (is_hest_type_generic_v2(ghes)) 744 - return ghes_ack_error(ghes->generic_v2); 722 + ghes_clear_estatus(ghes, estatus, buf_paddr, FIX_APEI_GHES_IRQ); 745 723 746 724 return rc; 747 725 } ··· 755 751 static void ghes_poll_func(struct timer_list *t) 756 752 { 757 753 struct ghes *ghes = from_timer(ghes, t, timer); 754 + unsigned long flags; 758 755 756 + spin_lock_irqsave(&ghes_notify_lock_irq, flags); 759 757 ghes_proc(ghes); 758 + spin_unlock_irqrestore(&ghes_notify_lock_irq, flags); 760 759 if (!(ghes->flags & GHES_EXITING)) 761 760 ghes_add_timer(ghes); 762 761 } ··· 767 760 static irqreturn_t ghes_irq_func(int irq, void *data) 768 761 { 769 762 struct ghes *ghes = data; 763 + unsigned long flags; 770 764 int rc; 771 765 766 + spin_lock_irqsave(&ghes_notify_lock_irq, flags); 772 767 rc = ghes_proc(ghes); 768 + spin_unlock_irqrestore(&ghes_notify_lock_irq, flags); 773 769 if (rc) 774 770 return IRQ_NONE; 775 771 ··· 783 773 void *data) 784 774 { 785 775 struct ghes *ghes; 776 + unsigned long flags; 786 777 int ret = NOTIFY_DONE; 787 778 779 + spin_lock_irqsave(&ghes_notify_lock_irq, flags); 788 780 rcu_read_lock(); 789 781 list_for_each_entry_rcu(ghes, &ghes_hed, list) { 790 782 if (!ghes_proc(ghes)) 791 783 ret = NOTIFY_OK; 792 784 } 793 785 rcu_read_unlock(); 786 + spin_unlock_irqrestore(&ghes_notify_lock_irq, flags); 794 787 795 788 return ret; 796 789 } ··· 802 789 .notifier_call = ghes_notify_hed, 803 790 }; 804 791 805 - #ifdef CONFIG_ACPI_APEI_SEA 806 - static LIST_HEAD(ghes_sea); 807 - 808 792 /* 809 - * Return 0 only if one of the SEA error sources successfully reported an error 810 - * record sent from the firmware. 811 - */ 812 - int ghes_notify_sea(void) 813 - { 814 - struct ghes *ghes; 815 - int ret = -ENOENT; 816 - 817 - rcu_read_lock(); 818 - list_for_each_entry_rcu(ghes, &ghes_sea, list) { 819 - if (!ghes_proc(ghes)) 820 - ret = 0; 821 - } 822 - rcu_read_unlock(); 823 - return ret; 824 - } 825 - 826 - static void ghes_sea_add(struct ghes *ghes) 827 - { 828 - mutex_lock(&ghes_list_mutex); 829 - list_add_rcu(&ghes->list, &ghes_sea); 830 - mutex_unlock(&ghes_list_mutex); 831 - } 832 - 833 - static void ghes_sea_remove(struct ghes *ghes) 834 - { 835 - mutex_lock(&ghes_list_mutex); 836 - list_del_rcu(&ghes->list); 837 - mutex_unlock(&ghes_list_mutex); 838 - synchronize_rcu(); 839 - } 840 - #else /* CONFIG_ACPI_APEI_SEA */ 841 - static inline void ghes_sea_add(struct ghes *ghes) { } 842 - static inline void ghes_sea_remove(struct ghes *ghes) { } 843 - #endif /* CONFIG_ACPI_APEI_SEA */ 844 - 845 - #ifdef CONFIG_HAVE_ACPI_APEI_NMI 846 - /* 847 - * printk is not safe in NMI context. So in NMI handler, we allocate 848 - * required memory from lock-less memory allocator 849 - * (ghes_estatus_pool), save estatus into it, put them into lock-less 850 - * list (ghes_estatus_llist), then delay printk into IRQ context via 851 - * irq_work (ghes_proc_irq_work). ghes_estatus_size_request record 852 - * required pool size by all NMI error source. 793 + * Handlers for CPER records may not be NMI safe. For example, 794 + * memory_failure_queue() takes spinlocks and calls schedule_work_on(). 795 + * In any NMI-like handler, memory from ghes_estatus_pool is used to save 796 + * estatus, and added to the ghes_estatus_llist. irq_work_queue() causes 797 + * ghes_proc_in_irq() to run in IRQ context where each estatus in 798 + * ghes_estatus_llist is processed. 799 + * 800 + * Memory from the ghes_estatus_pool is also used with the ghes_estatus_cache 801 + * to suppress frequent messages. 853 802 */ 854 803 static struct llist_head ghes_estatus_llist; 855 804 static struct irq_work ghes_proc_irq_work; 856 - 857 - /* 858 - * NMI may be triggered on any CPU, so ghes_in_nmi is used for 859 - * having only one concurrent reader. 860 - */ 861 - static atomic_t ghes_in_nmi = ATOMIC_INIT(0); 862 - 863 - static LIST_HEAD(ghes_nmi); 864 805 865 806 static void ghes_proc_in_irq(struct irq_work *irq_work) 866 807 { ··· 872 905 } 873 906 } 874 907 875 - /* Save estatus for further processing in IRQ context */ 876 - static void __process_error(struct ghes *ghes) 908 + static int ghes_in_nmi_queue_one_entry(struct ghes *ghes, 909 + enum fixed_addresses fixmap_idx) 877 910 { 878 - #ifdef CONFIG_ARCH_HAVE_NMI_SAFE_CMPXCHG 879 - u32 len, node_len; 911 + struct acpi_hest_generic_status *estatus, tmp_header; 880 912 struct ghes_estatus_node *estatus_node; 881 - struct acpi_hest_generic_status *estatus; 913 + u32 len, node_len; 914 + u64 buf_paddr; 915 + int sev, rc; 882 916 883 - if (ghes_estatus_cached(ghes->estatus)) 884 - return; 917 + if (!IS_ENABLED(CONFIG_ARCH_HAVE_NMI_SAFE_CMPXCHG)) 918 + return -EOPNOTSUPP; 885 919 886 - len = cper_estatus_len(ghes->estatus); 920 + rc = __ghes_peek_estatus(ghes, &tmp_header, &buf_paddr, fixmap_idx); 921 + if (rc) { 922 + ghes_clear_estatus(ghes, &tmp_header, buf_paddr, fixmap_idx); 923 + return rc; 924 + } 925 + 926 + rc = __ghes_check_estatus(ghes, &tmp_header); 927 + if (rc) { 928 + ghes_clear_estatus(ghes, &tmp_header, buf_paddr, fixmap_idx); 929 + return rc; 930 + } 931 + 932 + len = cper_estatus_len(&tmp_header); 887 933 node_len = GHES_ESTATUS_NODE_LEN(len); 888 - 889 934 estatus_node = (void *)gen_pool_alloc(ghes_estatus_pool, node_len); 890 935 if (!estatus_node) 891 - return; 936 + return -ENOMEM; 892 937 893 938 estatus_node->ghes = ghes; 894 939 estatus_node->generic = ghes->generic; 895 940 estatus = GHES_ESTATUS_FROM_NODE(estatus_node); 896 - memcpy(estatus, ghes->estatus, len); 941 + 942 + if (__ghes_read_estatus(estatus, buf_paddr, fixmap_idx, len)) { 943 + ghes_clear_estatus(ghes, estatus, buf_paddr, fixmap_idx); 944 + rc = -ENOENT; 945 + goto no_work; 946 + } 947 + 948 + sev = ghes_severity(estatus->error_severity); 949 + if (sev >= GHES_SEV_PANIC) { 950 + ghes_print_queued_estatus(); 951 + __ghes_panic(ghes, estatus, buf_paddr, fixmap_idx); 952 + } 953 + 954 + ghes_clear_estatus(ghes, &tmp_header, buf_paddr, fixmap_idx); 955 + 956 + /* This error has been reported before, don't process it again. */ 957 + if (ghes_estatus_cached(estatus)) 958 + goto no_work; 959 + 897 960 llist_add(&estatus_node->llnode, &ghes_estatus_llist); 898 - #endif 961 + 962 + return rc; 963 + 964 + no_work: 965 + gen_pool_free(ghes_estatus_pool, (unsigned long)estatus_node, 966 + node_len); 967 + 968 + return rc; 899 969 } 970 + 971 + static int ghes_in_nmi_spool_from_list(struct list_head *rcu_list, 972 + enum fixed_addresses fixmap_idx) 973 + { 974 + int ret = -ENOENT; 975 + struct ghes *ghes; 976 + 977 + rcu_read_lock(); 978 + list_for_each_entry_rcu(ghes, rcu_list, list) { 979 + if (!ghes_in_nmi_queue_one_entry(ghes, fixmap_idx)) 980 + ret = 0; 981 + } 982 + rcu_read_unlock(); 983 + 984 + if (IS_ENABLED(CONFIG_ARCH_HAVE_NMI_SAFE_CMPXCHG) && !ret) 985 + irq_work_queue(&ghes_proc_irq_work); 986 + 987 + return ret; 988 + } 989 + 990 + #ifdef CONFIG_ACPI_APEI_SEA 991 + static LIST_HEAD(ghes_sea); 992 + 993 + /* 994 + * Return 0 only if one of the SEA error sources successfully reported an error 995 + * record sent from the firmware. 996 + */ 997 + int ghes_notify_sea(void) 998 + { 999 + static DEFINE_RAW_SPINLOCK(ghes_notify_lock_sea); 1000 + int rv; 1001 + 1002 + raw_spin_lock(&ghes_notify_lock_sea); 1003 + rv = ghes_in_nmi_spool_from_list(&ghes_sea, FIX_APEI_GHES_SEA); 1004 + raw_spin_unlock(&ghes_notify_lock_sea); 1005 + 1006 + return rv; 1007 + } 1008 + 1009 + static void ghes_sea_add(struct ghes *ghes) 1010 + { 1011 + mutex_lock(&ghes_list_mutex); 1012 + list_add_rcu(&ghes->list, &ghes_sea); 1013 + mutex_unlock(&ghes_list_mutex); 1014 + } 1015 + 1016 + static void ghes_sea_remove(struct ghes *ghes) 1017 + { 1018 + mutex_lock(&ghes_list_mutex); 1019 + list_del_rcu(&ghes->list); 1020 + mutex_unlock(&ghes_list_mutex); 1021 + synchronize_rcu(); 1022 + } 1023 + #else /* CONFIG_ACPI_APEI_SEA */ 1024 + static inline void ghes_sea_add(struct ghes *ghes) { } 1025 + static inline void ghes_sea_remove(struct ghes *ghes) { } 1026 + #endif /* CONFIG_ACPI_APEI_SEA */ 1027 + 1028 + #ifdef CONFIG_HAVE_ACPI_APEI_NMI 1029 + /* 1030 + * NMI may be triggered on any CPU, so ghes_in_nmi is used for 1031 + * having only one concurrent reader. 1032 + */ 1033 + static atomic_t ghes_in_nmi = ATOMIC_INIT(0); 1034 + 1035 + static LIST_HEAD(ghes_nmi); 900 1036 901 1037 static int ghes_notify_nmi(unsigned int cmd, struct pt_regs *regs) 902 1038 { 903 - struct ghes *ghes; 904 - int sev, ret = NMI_DONE; 1039 + static DEFINE_RAW_SPINLOCK(ghes_notify_lock_nmi); 1040 + int ret = NMI_DONE; 905 1041 906 1042 if (!atomic_add_unless(&ghes_in_nmi, 1, 1)) 907 1043 return ret; 908 1044 909 - list_for_each_entry_rcu(ghes, &ghes_nmi, list) { 910 - if (ghes_read_estatus(ghes, 1)) { 911 - ghes_clear_estatus(ghes); 912 - continue; 913 - } else { 914 - ret = NMI_HANDLED; 915 - } 1045 + raw_spin_lock(&ghes_notify_lock_nmi); 1046 + if (!ghes_in_nmi_spool_from_list(&ghes_nmi, FIX_APEI_GHES_NMI)) 1047 + ret = NMI_HANDLED; 1048 + raw_spin_unlock(&ghes_notify_lock_nmi); 916 1049 917 - sev = ghes_severity(ghes->estatus->error_severity); 918 - if (sev >= GHES_SEV_PANIC) { 919 - oops_begin(); 920 - ghes_print_queued_estatus(); 921 - __ghes_panic(ghes); 922 - } 923 - 924 - if (!(ghes->flags & GHES_TO_CLEAR)) 925 - continue; 926 - 927 - __process_error(ghes); 928 - ghes_clear_estatus(ghes); 929 - } 930 - 931 - #ifdef CONFIG_ARCH_HAVE_NMI_SAFE_CMPXCHG 932 - if (ret == NMI_HANDLED) 933 - irq_work_queue(&ghes_proc_irq_work); 934 - #endif 935 1050 atomic_dec(&ghes_in_nmi); 936 1051 return ret; 937 1052 } 938 1053 939 - static unsigned long ghes_esource_prealloc_size( 940 - const struct acpi_hest_generic *generic) 941 - { 942 - unsigned long block_length, prealloc_records, prealloc_size; 943 - 944 - block_length = min_t(unsigned long, generic->error_block_length, 945 - GHES_ESTATUS_MAX_SIZE); 946 - prealloc_records = max_t(unsigned long, 947 - generic->records_to_preallocate, 1); 948 - prealloc_size = min_t(unsigned long, block_length * prealloc_records, 949 - GHES_ESOURCE_PREALLOC_MAX_SIZE); 950 - 951 - return prealloc_size; 952 - } 953 - 954 - static void ghes_estatus_pool_shrink(unsigned long len) 955 - { 956 - ghes_estatus_pool_size_request -= PAGE_ALIGN(len); 957 - } 958 - 959 1054 static void ghes_nmi_add(struct ghes *ghes) 960 1055 { 961 - unsigned long len; 962 - 963 - len = ghes_esource_prealloc_size(ghes->generic); 964 - ghes_estatus_pool_expand(len); 965 1056 mutex_lock(&ghes_list_mutex); 966 1057 if (list_empty(&ghes_nmi)) 967 1058 register_nmi_handler(NMI_LOCAL, ghes_notify_nmi, 0, "ghes"); ··· 1029 1004 1030 1005 static void ghes_nmi_remove(struct ghes *ghes) 1031 1006 { 1032 - unsigned long len; 1033 - 1034 1007 mutex_lock(&ghes_list_mutex); 1035 1008 list_del_rcu(&ghes->list); 1036 1009 if (list_empty(&ghes_nmi)) ··· 1039 1016 * freed after NMI handler finishes. 1040 1017 */ 1041 1018 synchronize_rcu(); 1042 - len = ghes_esource_prealloc_size(ghes->generic); 1043 - ghes_estatus_pool_shrink(len); 1044 1019 } 1020 + #else /* CONFIG_HAVE_ACPI_APEI_NMI */ 1021 + static inline void ghes_nmi_add(struct ghes *ghes) { } 1022 + static inline void ghes_nmi_remove(struct ghes *ghes) { } 1023 + #endif /* CONFIG_HAVE_ACPI_APEI_NMI */ 1045 1024 1046 1025 static void ghes_nmi_init_cxt(void) 1047 1026 { 1048 1027 init_irq_work(&ghes_proc_irq_work, ghes_proc_in_irq); 1049 1028 } 1050 - #else /* CONFIG_HAVE_ACPI_APEI_NMI */ 1051 - static inline void ghes_nmi_add(struct ghes *ghes) { } 1052 - static inline void ghes_nmi_remove(struct ghes *ghes) { } 1053 - static inline void ghes_nmi_init_cxt(void) { } 1054 - #endif /* CONFIG_HAVE_ACPI_APEI_NMI */ 1029 + 1030 + static int __ghes_sdei_callback(struct ghes *ghes, 1031 + enum fixed_addresses fixmap_idx) 1032 + { 1033 + if (!ghes_in_nmi_queue_one_entry(ghes, fixmap_idx)) { 1034 + irq_work_queue(&ghes_proc_irq_work); 1035 + 1036 + return 0; 1037 + } 1038 + 1039 + return -ENOENT; 1040 + } 1041 + 1042 + static int ghes_sdei_normal_callback(u32 event_num, struct pt_regs *regs, 1043 + void *arg) 1044 + { 1045 + static DEFINE_RAW_SPINLOCK(ghes_notify_lock_sdei_normal); 1046 + struct ghes *ghes = arg; 1047 + int err; 1048 + 1049 + raw_spin_lock(&ghes_notify_lock_sdei_normal); 1050 + err = __ghes_sdei_callback(ghes, FIX_APEI_GHES_SDEI_NORMAL); 1051 + raw_spin_unlock(&ghes_notify_lock_sdei_normal); 1052 + 1053 + return err; 1054 + } 1055 + 1056 + static int ghes_sdei_critical_callback(u32 event_num, struct pt_regs *regs, 1057 + void *arg) 1058 + { 1059 + static DEFINE_RAW_SPINLOCK(ghes_notify_lock_sdei_critical); 1060 + struct ghes *ghes = arg; 1061 + int err; 1062 + 1063 + raw_spin_lock(&ghes_notify_lock_sdei_critical); 1064 + err = __ghes_sdei_callback(ghes, FIX_APEI_GHES_SDEI_CRITICAL); 1065 + raw_spin_unlock(&ghes_notify_lock_sdei_critical); 1066 + 1067 + return err; 1068 + } 1069 + 1070 + static int apei_sdei_register_ghes(struct ghes *ghes) 1071 + { 1072 + if (!IS_ENABLED(CONFIG_ARM_SDE_INTERFACE)) 1073 + return -EOPNOTSUPP; 1074 + 1075 + return sdei_register_ghes(ghes, ghes_sdei_normal_callback, 1076 + ghes_sdei_critical_callback); 1077 + } 1078 + 1079 + static int apei_sdei_unregister_ghes(struct ghes *ghes) 1080 + { 1081 + if (!IS_ENABLED(CONFIG_ARM_SDE_INTERFACE)) 1082 + return -EOPNOTSUPP; 1083 + 1084 + return sdei_unregister_ghes(ghes); 1085 + } 1055 1086 1056 1087 static int ghes_probe(struct platform_device *ghes_dev) 1057 1088 { 1058 1089 struct acpi_hest_generic *generic; 1059 1090 struct ghes *ghes = NULL; 1091 + unsigned long flags; 1060 1092 1061 1093 int rc = -EINVAL; 1062 1094 ··· 1138 1060 case ACPI_HEST_NOTIFY_NMI: 1139 1061 if (!IS_ENABLED(CONFIG_HAVE_ACPI_APEI_NMI)) { 1140 1062 pr_warn(GHES_PFX "Generic hardware error source: %d notified via NMI interrupt is not supported!\n", 1063 + generic->header.source_id); 1064 + goto err; 1065 + } 1066 + break; 1067 + case ACPI_HEST_NOTIFY_SOFTWARE_DELEGATED: 1068 + if (!IS_ENABLED(CONFIG_ARM_SDE_INTERFACE)) { 1069 + pr_warn(GHES_PFX "Generic hardware error source: %d notified via SDE Interface is not supported!\n", 1141 1070 generic->header.source_id); 1142 1071 goto err; 1143 1072 } ··· 1212 1127 case ACPI_HEST_NOTIFY_NMI: 1213 1128 ghes_nmi_add(ghes); 1214 1129 break; 1130 + case ACPI_HEST_NOTIFY_SOFTWARE_DELEGATED: 1131 + rc = apei_sdei_register_ghes(ghes); 1132 + if (rc) 1133 + goto err; 1134 + break; 1215 1135 default: 1216 1136 BUG(); 1217 1137 } ··· 1226 1136 ghes_edac_register(ghes, &ghes_dev->dev); 1227 1137 1228 1138 /* Handle any pending errors right away */ 1139 + spin_lock_irqsave(&ghes_notify_lock_irq, flags); 1229 1140 ghes_proc(ghes); 1141 + spin_unlock_irqrestore(&ghes_notify_lock_irq, flags); 1230 1142 1231 1143 return 0; 1232 1144 ··· 1242 1150 1243 1151 static int ghes_remove(struct platform_device *ghes_dev) 1244 1152 { 1153 + int rc; 1245 1154 struct ghes *ghes; 1246 1155 struct acpi_hest_generic *generic; 1247 1156 ··· 1274 1181 break; 1275 1182 case ACPI_HEST_NOTIFY_NMI: 1276 1183 ghes_nmi_remove(ghes); 1184 + break; 1185 + case ACPI_HEST_NOTIFY_SOFTWARE_DELEGATED: 1186 + rc = apei_sdei_unregister_ghes(ghes); 1187 + if (rc) 1188 + return rc; 1277 1189 break; 1278 1190 default: 1279 1191 BUG(); ··· 1328 1230 1329 1231 ghes_nmi_init_cxt(); 1330 1232 1331 - rc = ghes_estatus_pool_init(); 1332 - if (rc) 1333 - goto err; 1334 - 1335 - rc = ghes_estatus_pool_expand(GHES_ESTATUS_CACHE_AVG_SIZE * 1336 - GHES_ESTATUS_CACHE_ALLOCED_MAX); 1337 - if (rc) 1338 - goto err_pool_exit; 1339 - 1340 1233 rc = platform_driver_register(&ghes_platform_driver); 1341 1234 if (rc) 1342 - goto err_pool_exit; 1235 + goto err; 1343 1236 1344 1237 rc = apei_osc_setup(); 1345 1238 if (rc == 0 && osc_sb_apei_support_acked) ··· 1343 1254 pr_info(GHES_PFX "Failed to enable APEI firmware first mode.\n"); 1344 1255 1345 1256 return 0; 1346 - err_pool_exit: 1347 - ghes_estatus_pool_exit(); 1348 1257 err: 1349 1258 return rc; 1350 1259 }
+15 -1
drivers/acpi/apei/hest.c
··· 32 32 #include <linux/io.h> 33 33 #include <linux/platform_device.h> 34 34 #include <acpi/apei.h> 35 + #include <acpi/ghes.h> 35 36 36 37 #include "apei-internal.h" 37 38 ··· 54 53 [ACPI_HEST_TYPE_AER_BRIDGE] = sizeof(struct acpi_hest_aer_bridge), 55 54 [ACPI_HEST_TYPE_GENERIC_ERROR] = sizeof(struct acpi_hest_generic), 56 55 [ACPI_HEST_TYPE_GENERIC_ERROR_V2] = sizeof(struct acpi_hest_generic_v2), 56 + [ACPI_HEST_TYPE_IA32_DEFERRED_CHECK] = -1, 57 57 }; 58 58 59 59 static int hest_esrc_len(struct acpi_hest_header *hest_hdr) ··· 75 73 } else if (hest_type == ACPI_HEST_TYPE_IA32_CHECK) { 76 74 struct acpi_hest_ia_machine_check *mc; 77 75 mc = (struct acpi_hest_ia_machine_check *)hest_hdr; 76 + len = sizeof(*mc) + mc->num_hardware_banks * 77 + sizeof(struct acpi_hest_ia_error_bank); 78 + } else if (hest_type == ACPI_HEST_TYPE_IA32_DEFERRED_CHECK) { 79 + struct acpi_hest_ia_deferred_check *mc; 80 + mc = (struct acpi_hest_ia_deferred_check *)hest_hdr; 78 81 len = sizeof(*mc) + mc->num_hardware_banks * 79 82 sizeof(struct acpi_hest_ia_error_bank); 80 83 } ··· 210 203 rc = apei_hest_parse(hest_parse_ghes, &ghes_arr); 211 204 if (rc) 212 205 goto err; 206 + 207 + rc = ghes_estatus_pool_init(ghes_count); 208 + if (rc) 209 + goto err; 210 + 213 211 out: 214 212 kfree(ghes_arr.ghes_devs); 215 213 return rc; ··· 263 251 rc = apei_hest_parse(hest_parse_ghes_count, &ghes_count); 264 252 if (rc) 265 253 goto err; 266 - rc = hest_ghes_dev_register(ghes_count); 254 + 255 + if (ghes_count) 256 + rc = hest_ghes_dev_register(ghes_count); 267 257 if (rc) 268 258 goto err; 269 259 }
+68
drivers/firmware/arm_sdei.c
··· 2 2 // Copyright (C) 2017 Arm Ltd. 3 3 #define pr_fmt(fmt) "sdei: " fmt 4 4 5 + #include <acpi/ghes.h> 5 6 #include <linux/acpi.h> 6 7 #include <linux/arm_sdei.h> 7 8 #include <linux/arm-smccc.h> ··· 886 885 unsigned long arg4, struct arm_smccc_res *res) 887 886 { 888 887 arm_smccc_hvc(function_id, arg0, arg1, arg2, arg3, arg4, 0, 0, res); 888 + } 889 + 890 + int sdei_register_ghes(struct ghes *ghes, sdei_event_callback *normal_cb, 891 + sdei_event_callback *critical_cb) 892 + { 893 + int err; 894 + u64 result; 895 + u32 event_num; 896 + sdei_event_callback *cb; 897 + 898 + if (!IS_ENABLED(CONFIG_ACPI_APEI_GHES)) 899 + return -EOPNOTSUPP; 900 + 901 + event_num = ghes->generic->notify.vector; 902 + if (event_num == 0) { 903 + /* 904 + * Event 0 is reserved by the specification for 905 + * SDEI_EVENT_SIGNAL. 906 + */ 907 + return -EINVAL; 908 + } 909 + 910 + err = sdei_api_event_get_info(event_num, SDEI_EVENT_INFO_EV_PRIORITY, 911 + &result); 912 + if (err) 913 + return err; 914 + 915 + if (result == SDEI_EVENT_PRIORITY_CRITICAL) 916 + cb = critical_cb; 917 + else 918 + cb = normal_cb; 919 + 920 + err = sdei_event_register(event_num, cb, ghes); 921 + if (!err) 922 + err = sdei_event_enable(event_num); 923 + 924 + return err; 925 + } 926 + 927 + int sdei_unregister_ghes(struct ghes *ghes) 928 + { 929 + int i; 930 + int err; 931 + u32 event_num = ghes->generic->notify.vector; 932 + 933 + might_sleep(); 934 + 935 + if (!IS_ENABLED(CONFIG_ACPI_APEI_GHES)) 936 + return -EOPNOTSUPP; 937 + 938 + /* 939 + * The event may be running on another CPU. Disable it 940 + * to stop new events, then try to unregister a few times. 941 + */ 942 + err = sdei_event_disable(event_num); 943 + if (err) 944 + return err; 945 + 946 + for (i = 0; i < 3; i++) { 947 + err = sdei_event_unregister(event_num); 948 + if (err != -EINPROGRESS) 949 + break; 950 + 951 + schedule(); 952 + } 953 + 954 + return err; 889 955 } 890 956 891 957 static int sdei_get_conduit(struct platform_device *pdev)
+9 -4
drivers/firmware/efi/cper.c
··· 546 546 int cper_estatus_check(const struct acpi_hest_generic_status *estatus) 547 547 { 548 548 struct acpi_hest_generic_data *gdata; 549 - unsigned int data_len, gedata_len; 549 + unsigned int data_len, record_size; 550 550 int rc; 551 551 552 552 rc = cper_estatus_check_header(estatus); 553 553 if (rc) 554 554 return rc; 555 + 555 556 data_len = estatus->data_length; 556 557 557 558 apei_estatus_for_each_section(estatus, gdata) { 558 - gedata_len = acpi_hest_get_error_length(gdata); 559 - if (gedata_len > data_len - acpi_hest_get_size(gdata)) 559 + if (sizeof(struct acpi_hest_generic_data) > data_len) 560 560 return -EINVAL; 561 - data_len -= acpi_hest_get_record_size(gdata); 561 + 562 + record_size = acpi_hest_get_record_size(gdata); 563 + if (record_size > data_len) 564 + return -EINVAL; 565 + 566 + data_len -= record_size; 562 567 } 563 568 if (data_len) 564 569 return -EINVAL;
+2 -2
include/acpi/ghes.h
··· 13 13 * estatus: memory buffer for error status block, allocated during 14 14 * HEST parsing. 15 15 */ 16 - #define GHES_TO_CLEAR 0x0001 17 16 #define GHES_EXITING 0x0002 18 17 19 18 struct ghes { ··· 21 22 struct acpi_hest_generic_v2 *generic_v2; 22 23 }; 23 24 struct acpi_hest_generic_status *estatus; 24 - u64 buffer_paddr; 25 25 unsigned long flags; 26 26 union { 27 27 struct list_head list; ··· 49 51 GHES_SEV_RECOVERABLE = 0x2, 50 52 GHES_SEV_PANIC = 0x3, 51 53 }; 54 + 55 + int ghes_estatus_pool_init(int num_ghes); 52 56 53 57 /* From drivers/edac/ghes_edac.c */ 54 58
+9
include/linux/arm_sdei.h
··· 11 11 CONDUIT_HVC, 12 12 }; 13 13 14 + #include <acpi/ghes.h> 15 + 16 + #ifdef CONFIG_ARM_SDE_INTERFACE 14 17 #include <asm/sdei.h> 18 + #endif 15 19 16 20 /* Arch code should override this to set the entry point from firmware... */ 17 21 #ifndef sdei_arch_get_entry_point ··· 42 38 43 39 int sdei_event_enable(u32 event_num); 44 40 int sdei_event_disable(u32 event_num); 41 + 42 + /* GHES register/unregister helpers */ 43 + int sdei_register_ghes(struct ghes *ghes, sdei_event_callback *normal_cb, 44 + sdei_event_callback *critical_cb); 45 + int sdei_unregister_ghes(struct ghes *ghes); 45 46 46 47 #ifdef CONFIG_ARM_SDE_INTERFACE 47 48 /* For use by arch code when CPU hotplug notifiers are not appropriate. */
+2 -2
virt/kvm/arm/mmu.c
··· 27 27 #include <asm/kvm_arm.h> 28 28 #include <asm/kvm_mmu.h> 29 29 #include <asm/kvm_mmio.h> 30 + #include <asm/kvm_ras.h> 30 31 #include <asm/kvm_asm.h> 31 32 #include <asm/kvm_emulate.h> 32 33 #include <asm/virt.h> 33 - #include <asm/system_misc.h> 34 34 35 35 #include "trace.h" 36 36 ··· 1906 1906 * For RAS the host kernel may handle this abort. 1907 1907 * There is no need to pass the error into the guest. 1908 1908 */ 1909 - if (!handle_guest_sea(fault_ipa, kvm_vcpu_get_hsr(vcpu))) 1909 + if (!kvm_handle_guest_sea(fault_ipa, kvm_vcpu_get_hsr(vcpu))) 1910 1910 return 1; 1911 1911 1912 1912 if (unlikely(!is_iabt)) {