1*4882a593Smuzhiyun // SPDX-License-Identifier: GPL-2.0-only
2*4882a593Smuzhiyun /*
3*4882a593Smuzhiyun * APEI Generic Hardware Error Source support
4*4882a593Smuzhiyun *
5*4882a593Smuzhiyun * Generic Hardware Error Source provides a way to report platform
6*4882a593Smuzhiyun * hardware errors (such as that from chipset). It works in so called
7*4882a593Smuzhiyun * "Firmware First" mode, that is, hardware errors are reported to
8*4882a593Smuzhiyun * firmware firstly, then reported to Linux by firmware. This way,
9*4882a593Smuzhiyun * some non-standard hardware error registers or non-standard hardware
10*4882a593Smuzhiyun * link can be checked by firmware to produce more hardware error
11*4882a593Smuzhiyun * information for Linux.
12*4882a593Smuzhiyun *
13*4882a593Smuzhiyun * For more information about Generic Hardware Error Source, please
14*4882a593Smuzhiyun * refer to ACPI Specification version 4.0, section 17.3.2.6
15*4882a593Smuzhiyun *
16*4882a593Smuzhiyun * Copyright 2010,2011 Intel Corp.
17*4882a593Smuzhiyun * Author: Huang Ying <ying.huang@intel.com>
18*4882a593Smuzhiyun */
19*4882a593Smuzhiyun
20*4882a593Smuzhiyun #include <linux/arm_sdei.h>
21*4882a593Smuzhiyun #include <linux/kernel.h>
22*4882a593Smuzhiyun #include <linux/moduleparam.h>
23*4882a593Smuzhiyun #include <linux/init.h>
24*4882a593Smuzhiyun #include <linux/acpi.h>
25*4882a593Smuzhiyun #include <linux/io.h>
26*4882a593Smuzhiyun #include <linux/interrupt.h>
27*4882a593Smuzhiyun #include <linux/timer.h>
28*4882a593Smuzhiyun #include <linux/cper.h>
29*4882a593Smuzhiyun #include <linux/platform_device.h>
30*4882a593Smuzhiyun #include <linux/mutex.h>
31*4882a593Smuzhiyun #include <linux/ratelimit.h>
32*4882a593Smuzhiyun #include <linux/vmalloc.h>
33*4882a593Smuzhiyun #include <linux/irq_work.h>
34*4882a593Smuzhiyun #include <linux/llist.h>
35*4882a593Smuzhiyun #include <linux/genalloc.h>
36*4882a593Smuzhiyun #include <linux/pci.h>
37*4882a593Smuzhiyun #include <linux/pfn.h>
38*4882a593Smuzhiyun #include <linux/aer.h>
39*4882a593Smuzhiyun #include <linux/nmi.h>
40*4882a593Smuzhiyun #include <linux/sched/clock.h>
41*4882a593Smuzhiyun #include <linux/uuid.h>
42*4882a593Smuzhiyun #include <linux/ras.h>
43*4882a593Smuzhiyun #include <linux/task_work.h>
44*4882a593Smuzhiyun
45*4882a593Smuzhiyun #include <acpi/actbl1.h>
46*4882a593Smuzhiyun #include <acpi/ghes.h>
47*4882a593Smuzhiyun #include <acpi/apei.h>
48*4882a593Smuzhiyun #include <asm/fixmap.h>
49*4882a593Smuzhiyun #include <asm/tlbflush.h>
50*4882a593Smuzhiyun #include <ras/ras_event.h>
51*4882a593Smuzhiyun
52*4882a593Smuzhiyun #include "apei-internal.h"
53*4882a593Smuzhiyun
54*4882a593Smuzhiyun #define GHES_PFX "GHES: "
55*4882a593Smuzhiyun
56*4882a593Smuzhiyun #define GHES_ESTATUS_MAX_SIZE 65536
57*4882a593Smuzhiyun #define GHES_ESOURCE_PREALLOC_MAX_SIZE 65536
58*4882a593Smuzhiyun
59*4882a593Smuzhiyun #define GHES_ESTATUS_POOL_MIN_ALLOC_ORDER 3
60*4882a593Smuzhiyun
61*4882a593Smuzhiyun /* This is just an estimation for memory pool allocation */
62*4882a593Smuzhiyun #define GHES_ESTATUS_CACHE_AVG_SIZE 512
63*4882a593Smuzhiyun
64*4882a593Smuzhiyun #define GHES_ESTATUS_CACHES_SIZE 4
65*4882a593Smuzhiyun
66*4882a593Smuzhiyun #define GHES_ESTATUS_IN_CACHE_MAX_NSEC 10000000000ULL
67*4882a593Smuzhiyun /* Prevent too many caches are allocated because of RCU */
68*4882a593Smuzhiyun #define GHES_ESTATUS_CACHE_ALLOCED_MAX (GHES_ESTATUS_CACHES_SIZE * 3 / 2)
69*4882a593Smuzhiyun
70*4882a593Smuzhiyun #define GHES_ESTATUS_CACHE_LEN(estatus_len) \
71*4882a593Smuzhiyun (sizeof(struct ghes_estatus_cache) + (estatus_len))
72*4882a593Smuzhiyun #define GHES_ESTATUS_FROM_CACHE(estatus_cache) \
73*4882a593Smuzhiyun ((struct acpi_hest_generic_status *) \
74*4882a593Smuzhiyun ((struct ghes_estatus_cache *)(estatus_cache) + 1))
75*4882a593Smuzhiyun
76*4882a593Smuzhiyun #define GHES_ESTATUS_NODE_LEN(estatus_len) \
77*4882a593Smuzhiyun (sizeof(struct ghes_estatus_node) + (estatus_len))
78*4882a593Smuzhiyun #define GHES_ESTATUS_FROM_NODE(estatus_node) \
79*4882a593Smuzhiyun ((struct acpi_hest_generic_status *) \
80*4882a593Smuzhiyun ((struct ghes_estatus_node *)(estatus_node) + 1))
81*4882a593Smuzhiyun
82*4882a593Smuzhiyun #define GHES_VENDOR_ENTRY_LEN(gdata_len) \
83*4882a593Smuzhiyun (sizeof(struct ghes_vendor_record_entry) + (gdata_len))
84*4882a593Smuzhiyun #define GHES_GDATA_FROM_VENDOR_ENTRY(vendor_entry) \
85*4882a593Smuzhiyun ((struct acpi_hest_generic_data *) \
86*4882a593Smuzhiyun ((struct ghes_vendor_record_entry *)(vendor_entry) + 1))
87*4882a593Smuzhiyun
88*4882a593Smuzhiyun /*
89*4882a593Smuzhiyun * NMI-like notifications vary by architecture, before the compiler can prune
90*4882a593Smuzhiyun * unused static functions it needs a value for these enums.
91*4882a593Smuzhiyun */
92*4882a593Smuzhiyun #ifndef CONFIG_ARM_SDE_INTERFACE
93*4882a593Smuzhiyun #define FIX_APEI_GHES_SDEI_NORMAL __end_of_fixed_addresses
94*4882a593Smuzhiyun #define FIX_APEI_GHES_SDEI_CRITICAL __end_of_fixed_addresses
95*4882a593Smuzhiyun #endif
96*4882a593Smuzhiyun
is_hest_type_generic_v2(struct ghes * ghes)97*4882a593Smuzhiyun static inline bool is_hest_type_generic_v2(struct ghes *ghes)
98*4882a593Smuzhiyun {
99*4882a593Smuzhiyun return ghes->generic->header.type == ACPI_HEST_TYPE_GENERIC_ERROR_V2;
100*4882a593Smuzhiyun }
101*4882a593Smuzhiyun
102*4882a593Smuzhiyun /*
103*4882a593Smuzhiyun * This driver isn't really modular, however for the time being,
104*4882a593Smuzhiyun * continuing to use module_param is the easiest way to remain
105*4882a593Smuzhiyun * compatible with existing boot arg use cases.
106*4882a593Smuzhiyun */
107*4882a593Smuzhiyun bool ghes_disable;
108*4882a593Smuzhiyun module_param_named(disable, ghes_disable, bool, 0);
109*4882a593Smuzhiyun
110*4882a593Smuzhiyun /*
111*4882a593Smuzhiyun * All error sources notified with HED (Hardware Error Device) share a
112*4882a593Smuzhiyun * single notifier callback, so they need to be linked and checked one
113*4882a593Smuzhiyun * by one. This holds true for NMI too.
114*4882a593Smuzhiyun *
115*4882a593Smuzhiyun * RCU is used for these lists, so ghes_list_mutex is only used for
116*4882a593Smuzhiyun * list changing, not for traversing.
117*4882a593Smuzhiyun */
118*4882a593Smuzhiyun static LIST_HEAD(ghes_hed);
119*4882a593Smuzhiyun static DEFINE_MUTEX(ghes_list_mutex);
120*4882a593Smuzhiyun
121*4882a593Smuzhiyun /*
122*4882a593Smuzhiyun * Because the memory area used to transfer hardware error information
123*4882a593Smuzhiyun * from BIOS to Linux can be determined only in NMI, IRQ or timer
124*4882a593Smuzhiyun * handler, but general ioremap can not be used in atomic context, so
125*4882a593Smuzhiyun * the fixmap is used instead.
126*4882a593Smuzhiyun *
127*4882a593Smuzhiyun * This spinlock is used to prevent the fixmap entry from being used
128*4882a593Smuzhiyun * simultaneously.
129*4882a593Smuzhiyun */
130*4882a593Smuzhiyun static DEFINE_SPINLOCK(ghes_notify_lock_irq);
131*4882a593Smuzhiyun
132*4882a593Smuzhiyun struct ghes_vendor_record_entry {
133*4882a593Smuzhiyun struct work_struct work;
134*4882a593Smuzhiyun int error_severity;
135*4882a593Smuzhiyun char vendor_record[];
136*4882a593Smuzhiyun };
137*4882a593Smuzhiyun
138*4882a593Smuzhiyun static struct gen_pool *ghes_estatus_pool;
139*4882a593Smuzhiyun static unsigned long ghes_estatus_pool_size_request;
140*4882a593Smuzhiyun
141*4882a593Smuzhiyun static struct ghes_estatus_cache *ghes_estatus_caches[GHES_ESTATUS_CACHES_SIZE];
142*4882a593Smuzhiyun static atomic_t ghes_estatus_cache_alloced;
143*4882a593Smuzhiyun
144*4882a593Smuzhiyun static int ghes_panic_timeout __read_mostly = 30;
145*4882a593Smuzhiyun
ghes_map(u64 pfn,enum fixed_addresses fixmap_idx)146*4882a593Smuzhiyun static void __iomem *ghes_map(u64 pfn, enum fixed_addresses fixmap_idx)
147*4882a593Smuzhiyun {
148*4882a593Smuzhiyun phys_addr_t paddr;
149*4882a593Smuzhiyun pgprot_t prot;
150*4882a593Smuzhiyun
151*4882a593Smuzhiyun paddr = PFN_PHYS(pfn);
152*4882a593Smuzhiyun prot = arch_apei_get_mem_attribute(paddr);
153*4882a593Smuzhiyun __set_fixmap(fixmap_idx, paddr, prot);
154*4882a593Smuzhiyun
155*4882a593Smuzhiyun return (void __iomem *) __fix_to_virt(fixmap_idx);
156*4882a593Smuzhiyun }
157*4882a593Smuzhiyun
ghes_unmap(void __iomem * vaddr,enum fixed_addresses fixmap_idx)158*4882a593Smuzhiyun static void ghes_unmap(void __iomem *vaddr, enum fixed_addresses fixmap_idx)
159*4882a593Smuzhiyun {
160*4882a593Smuzhiyun int _idx = virt_to_fix((unsigned long)vaddr);
161*4882a593Smuzhiyun
162*4882a593Smuzhiyun WARN_ON_ONCE(fixmap_idx != _idx);
163*4882a593Smuzhiyun clear_fixmap(fixmap_idx);
164*4882a593Smuzhiyun }
165*4882a593Smuzhiyun
ghes_estatus_pool_init(unsigned int num_ghes)166*4882a593Smuzhiyun int ghes_estatus_pool_init(unsigned int num_ghes)
167*4882a593Smuzhiyun {
168*4882a593Smuzhiyun unsigned long addr, len;
169*4882a593Smuzhiyun int rc;
170*4882a593Smuzhiyun
171*4882a593Smuzhiyun ghes_estatus_pool = gen_pool_create(GHES_ESTATUS_POOL_MIN_ALLOC_ORDER, -1);
172*4882a593Smuzhiyun if (!ghes_estatus_pool)
173*4882a593Smuzhiyun return -ENOMEM;
174*4882a593Smuzhiyun
175*4882a593Smuzhiyun len = GHES_ESTATUS_CACHE_AVG_SIZE * GHES_ESTATUS_CACHE_ALLOCED_MAX;
176*4882a593Smuzhiyun len += (num_ghes * GHES_ESOURCE_PREALLOC_MAX_SIZE);
177*4882a593Smuzhiyun
178*4882a593Smuzhiyun ghes_estatus_pool_size_request = PAGE_ALIGN(len);
179*4882a593Smuzhiyun addr = (unsigned long)vmalloc(PAGE_ALIGN(len));
180*4882a593Smuzhiyun if (!addr)
181*4882a593Smuzhiyun goto err_pool_alloc;
182*4882a593Smuzhiyun
183*4882a593Smuzhiyun rc = gen_pool_add(ghes_estatus_pool, addr, PAGE_ALIGN(len), -1);
184*4882a593Smuzhiyun if (rc)
185*4882a593Smuzhiyun goto err_pool_add;
186*4882a593Smuzhiyun
187*4882a593Smuzhiyun return 0;
188*4882a593Smuzhiyun
189*4882a593Smuzhiyun err_pool_add:
190*4882a593Smuzhiyun vfree((void *)addr);
191*4882a593Smuzhiyun
192*4882a593Smuzhiyun err_pool_alloc:
193*4882a593Smuzhiyun gen_pool_destroy(ghes_estatus_pool);
194*4882a593Smuzhiyun
195*4882a593Smuzhiyun return -ENOMEM;
196*4882a593Smuzhiyun }
197*4882a593Smuzhiyun
map_gen_v2(struct ghes * ghes)198*4882a593Smuzhiyun static int map_gen_v2(struct ghes *ghes)
199*4882a593Smuzhiyun {
200*4882a593Smuzhiyun return apei_map_generic_address(&ghes->generic_v2->read_ack_register);
201*4882a593Smuzhiyun }
202*4882a593Smuzhiyun
unmap_gen_v2(struct ghes * ghes)203*4882a593Smuzhiyun static void unmap_gen_v2(struct ghes *ghes)
204*4882a593Smuzhiyun {
205*4882a593Smuzhiyun apei_unmap_generic_address(&ghes->generic_v2->read_ack_register);
206*4882a593Smuzhiyun }
207*4882a593Smuzhiyun
ghes_ack_error(struct acpi_hest_generic_v2 * gv2)208*4882a593Smuzhiyun static void ghes_ack_error(struct acpi_hest_generic_v2 *gv2)
209*4882a593Smuzhiyun {
210*4882a593Smuzhiyun int rc;
211*4882a593Smuzhiyun u64 val = 0;
212*4882a593Smuzhiyun
213*4882a593Smuzhiyun rc = apei_read(&val, &gv2->read_ack_register);
214*4882a593Smuzhiyun if (rc)
215*4882a593Smuzhiyun return;
216*4882a593Smuzhiyun
217*4882a593Smuzhiyun val &= gv2->read_ack_preserve << gv2->read_ack_register.bit_offset;
218*4882a593Smuzhiyun val |= gv2->read_ack_write << gv2->read_ack_register.bit_offset;
219*4882a593Smuzhiyun
220*4882a593Smuzhiyun apei_write(val, &gv2->read_ack_register);
221*4882a593Smuzhiyun }
222*4882a593Smuzhiyun
ghes_new(struct acpi_hest_generic * generic)223*4882a593Smuzhiyun static struct ghes *ghes_new(struct acpi_hest_generic *generic)
224*4882a593Smuzhiyun {
225*4882a593Smuzhiyun struct ghes *ghes;
226*4882a593Smuzhiyun unsigned int error_block_length;
227*4882a593Smuzhiyun int rc;
228*4882a593Smuzhiyun
229*4882a593Smuzhiyun ghes = kzalloc(sizeof(*ghes), GFP_KERNEL);
230*4882a593Smuzhiyun if (!ghes)
231*4882a593Smuzhiyun return ERR_PTR(-ENOMEM);
232*4882a593Smuzhiyun
233*4882a593Smuzhiyun ghes->generic = generic;
234*4882a593Smuzhiyun if (is_hest_type_generic_v2(ghes)) {
235*4882a593Smuzhiyun rc = map_gen_v2(ghes);
236*4882a593Smuzhiyun if (rc)
237*4882a593Smuzhiyun goto err_free;
238*4882a593Smuzhiyun }
239*4882a593Smuzhiyun
240*4882a593Smuzhiyun rc = apei_map_generic_address(&generic->error_status_address);
241*4882a593Smuzhiyun if (rc)
242*4882a593Smuzhiyun goto err_unmap_read_ack_addr;
243*4882a593Smuzhiyun error_block_length = generic->error_block_length;
244*4882a593Smuzhiyun if (error_block_length > GHES_ESTATUS_MAX_SIZE) {
245*4882a593Smuzhiyun pr_warn(FW_WARN GHES_PFX
246*4882a593Smuzhiyun "Error status block length is too long: %u for "
247*4882a593Smuzhiyun "generic hardware error source: %d.\n",
248*4882a593Smuzhiyun error_block_length, generic->header.source_id);
249*4882a593Smuzhiyun error_block_length = GHES_ESTATUS_MAX_SIZE;
250*4882a593Smuzhiyun }
251*4882a593Smuzhiyun ghes->estatus = kmalloc(error_block_length, GFP_KERNEL);
252*4882a593Smuzhiyun if (!ghes->estatus) {
253*4882a593Smuzhiyun rc = -ENOMEM;
254*4882a593Smuzhiyun goto err_unmap_status_addr;
255*4882a593Smuzhiyun }
256*4882a593Smuzhiyun
257*4882a593Smuzhiyun return ghes;
258*4882a593Smuzhiyun
259*4882a593Smuzhiyun err_unmap_status_addr:
260*4882a593Smuzhiyun apei_unmap_generic_address(&generic->error_status_address);
261*4882a593Smuzhiyun err_unmap_read_ack_addr:
262*4882a593Smuzhiyun if (is_hest_type_generic_v2(ghes))
263*4882a593Smuzhiyun unmap_gen_v2(ghes);
264*4882a593Smuzhiyun err_free:
265*4882a593Smuzhiyun kfree(ghes);
266*4882a593Smuzhiyun return ERR_PTR(rc);
267*4882a593Smuzhiyun }
268*4882a593Smuzhiyun
ghes_fini(struct ghes * ghes)269*4882a593Smuzhiyun static void ghes_fini(struct ghes *ghes)
270*4882a593Smuzhiyun {
271*4882a593Smuzhiyun kfree(ghes->estatus);
272*4882a593Smuzhiyun apei_unmap_generic_address(&ghes->generic->error_status_address);
273*4882a593Smuzhiyun if (is_hest_type_generic_v2(ghes))
274*4882a593Smuzhiyun unmap_gen_v2(ghes);
275*4882a593Smuzhiyun }
276*4882a593Smuzhiyun
ghes_severity(int severity)277*4882a593Smuzhiyun static inline int ghes_severity(int severity)
278*4882a593Smuzhiyun {
279*4882a593Smuzhiyun switch (severity) {
280*4882a593Smuzhiyun case CPER_SEV_INFORMATIONAL:
281*4882a593Smuzhiyun return GHES_SEV_NO;
282*4882a593Smuzhiyun case CPER_SEV_CORRECTED:
283*4882a593Smuzhiyun return GHES_SEV_CORRECTED;
284*4882a593Smuzhiyun case CPER_SEV_RECOVERABLE:
285*4882a593Smuzhiyun return GHES_SEV_RECOVERABLE;
286*4882a593Smuzhiyun case CPER_SEV_FATAL:
287*4882a593Smuzhiyun return GHES_SEV_PANIC;
288*4882a593Smuzhiyun default:
289*4882a593Smuzhiyun /* Unknown, go panic */
290*4882a593Smuzhiyun return GHES_SEV_PANIC;
291*4882a593Smuzhiyun }
292*4882a593Smuzhiyun }
293*4882a593Smuzhiyun
ghes_copy_tofrom_phys(void * buffer,u64 paddr,u32 len,int from_phys,enum fixed_addresses fixmap_idx)294*4882a593Smuzhiyun static void ghes_copy_tofrom_phys(void *buffer, u64 paddr, u32 len,
295*4882a593Smuzhiyun int from_phys,
296*4882a593Smuzhiyun enum fixed_addresses fixmap_idx)
297*4882a593Smuzhiyun {
298*4882a593Smuzhiyun void __iomem *vaddr;
299*4882a593Smuzhiyun u64 offset;
300*4882a593Smuzhiyun u32 trunk;
301*4882a593Smuzhiyun
302*4882a593Smuzhiyun while (len > 0) {
303*4882a593Smuzhiyun offset = paddr - (paddr & PAGE_MASK);
304*4882a593Smuzhiyun vaddr = ghes_map(PHYS_PFN(paddr), fixmap_idx);
305*4882a593Smuzhiyun trunk = PAGE_SIZE - offset;
306*4882a593Smuzhiyun trunk = min(trunk, len);
307*4882a593Smuzhiyun if (from_phys)
308*4882a593Smuzhiyun memcpy_fromio(buffer, vaddr + offset, trunk);
309*4882a593Smuzhiyun else
310*4882a593Smuzhiyun memcpy_toio(vaddr + offset, buffer, trunk);
311*4882a593Smuzhiyun len -= trunk;
312*4882a593Smuzhiyun paddr += trunk;
313*4882a593Smuzhiyun buffer += trunk;
314*4882a593Smuzhiyun ghes_unmap(vaddr, fixmap_idx);
315*4882a593Smuzhiyun }
316*4882a593Smuzhiyun }
317*4882a593Smuzhiyun
318*4882a593Smuzhiyun /* Check the top-level record header has an appropriate size. */
__ghes_check_estatus(struct ghes * ghes,struct acpi_hest_generic_status * estatus)319*4882a593Smuzhiyun static int __ghes_check_estatus(struct ghes *ghes,
320*4882a593Smuzhiyun struct acpi_hest_generic_status *estatus)
321*4882a593Smuzhiyun {
322*4882a593Smuzhiyun u32 len = cper_estatus_len(estatus);
323*4882a593Smuzhiyun
324*4882a593Smuzhiyun if (len < sizeof(*estatus)) {
325*4882a593Smuzhiyun pr_warn_ratelimited(FW_WARN GHES_PFX "Truncated error status block!\n");
326*4882a593Smuzhiyun return -EIO;
327*4882a593Smuzhiyun }
328*4882a593Smuzhiyun
329*4882a593Smuzhiyun if (len > ghes->generic->error_block_length) {
330*4882a593Smuzhiyun pr_warn_ratelimited(FW_WARN GHES_PFX "Invalid error status block length!\n");
331*4882a593Smuzhiyun return -EIO;
332*4882a593Smuzhiyun }
333*4882a593Smuzhiyun
334*4882a593Smuzhiyun if (cper_estatus_check_header(estatus)) {
335*4882a593Smuzhiyun pr_warn_ratelimited(FW_WARN GHES_PFX "Invalid CPER header!\n");
336*4882a593Smuzhiyun return -EIO;
337*4882a593Smuzhiyun }
338*4882a593Smuzhiyun
339*4882a593Smuzhiyun return 0;
340*4882a593Smuzhiyun }
341*4882a593Smuzhiyun
342*4882a593Smuzhiyun /* Read the CPER block, returning its address, and header in estatus. */
__ghes_peek_estatus(struct ghes * ghes,struct acpi_hest_generic_status * estatus,u64 * buf_paddr,enum fixed_addresses fixmap_idx)343*4882a593Smuzhiyun static int __ghes_peek_estatus(struct ghes *ghes,
344*4882a593Smuzhiyun struct acpi_hest_generic_status *estatus,
345*4882a593Smuzhiyun u64 *buf_paddr, enum fixed_addresses fixmap_idx)
346*4882a593Smuzhiyun {
347*4882a593Smuzhiyun struct acpi_hest_generic *g = ghes->generic;
348*4882a593Smuzhiyun int rc;
349*4882a593Smuzhiyun
350*4882a593Smuzhiyun rc = apei_read(buf_paddr, &g->error_status_address);
351*4882a593Smuzhiyun if (rc) {
352*4882a593Smuzhiyun *buf_paddr = 0;
353*4882a593Smuzhiyun pr_warn_ratelimited(FW_WARN GHES_PFX
354*4882a593Smuzhiyun "Failed to read error status block address for hardware error source: %d.\n",
355*4882a593Smuzhiyun g->header.source_id);
356*4882a593Smuzhiyun return -EIO;
357*4882a593Smuzhiyun }
358*4882a593Smuzhiyun if (!*buf_paddr)
359*4882a593Smuzhiyun return -ENOENT;
360*4882a593Smuzhiyun
361*4882a593Smuzhiyun ghes_copy_tofrom_phys(estatus, *buf_paddr, sizeof(*estatus), 1,
362*4882a593Smuzhiyun fixmap_idx);
363*4882a593Smuzhiyun if (!estatus->block_status) {
364*4882a593Smuzhiyun *buf_paddr = 0;
365*4882a593Smuzhiyun return -ENOENT;
366*4882a593Smuzhiyun }
367*4882a593Smuzhiyun
368*4882a593Smuzhiyun return 0;
369*4882a593Smuzhiyun }
370*4882a593Smuzhiyun
__ghes_read_estatus(struct acpi_hest_generic_status * estatus,u64 buf_paddr,enum fixed_addresses fixmap_idx,size_t buf_len)371*4882a593Smuzhiyun static int __ghes_read_estatus(struct acpi_hest_generic_status *estatus,
372*4882a593Smuzhiyun u64 buf_paddr, enum fixed_addresses fixmap_idx,
373*4882a593Smuzhiyun size_t buf_len)
374*4882a593Smuzhiyun {
375*4882a593Smuzhiyun ghes_copy_tofrom_phys(estatus, buf_paddr, buf_len, 1, fixmap_idx);
376*4882a593Smuzhiyun if (cper_estatus_check(estatus)) {
377*4882a593Smuzhiyun pr_warn_ratelimited(FW_WARN GHES_PFX
378*4882a593Smuzhiyun "Failed to read error status block!\n");
379*4882a593Smuzhiyun return -EIO;
380*4882a593Smuzhiyun }
381*4882a593Smuzhiyun
382*4882a593Smuzhiyun return 0;
383*4882a593Smuzhiyun }
384*4882a593Smuzhiyun
ghes_read_estatus(struct ghes * ghes,struct acpi_hest_generic_status * estatus,u64 * buf_paddr,enum fixed_addresses fixmap_idx)385*4882a593Smuzhiyun static int ghes_read_estatus(struct ghes *ghes,
386*4882a593Smuzhiyun struct acpi_hest_generic_status *estatus,
387*4882a593Smuzhiyun u64 *buf_paddr, enum fixed_addresses fixmap_idx)
388*4882a593Smuzhiyun {
389*4882a593Smuzhiyun int rc;
390*4882a593Smuzhiyun
391*4882a593Smuzhiyun rc = __ghes_peek_estatus(ghes, estatus, buf_paddr, fixmap_idx);
392*4882a593Smuzhiyun if (rc)
393*4882a593Smuzhiyun return rc;
394*4882a593Smuzhiyun
395*4882a593Smuzhiyun rc = __ghes_check_estatus(ghes, estatus);
396*4882a593Smuzhiyun if (rc)
397*4882a593Smuzhiyun return rc;
398*4882a593Smuzhiyun
399*4882a593Smuzhiyun return __ghes_read_estatus(estatus, *buf_paddr, fixmap_idx,
400*4882a593Smuzhiyun cper_estatus_len(estatus));
401*4882a593Smuzhiyun }
402*4882a593Smuzhiyun
ghes_clear_estatus(struct ghes * ghes,struct acpi_hest_generic_status * estatus,u64 buf_paddr,enum fixed_addresses fixmap_idx)403*4882a593Smuzhiyun static void ghes_clear_estatus(struct ghes *ghes,
404*4882a593Smuzhiyun struct acpi_hest_generic_status *estatus,
405*4882a593Smuzhiyun u64 buf_paddr, enum fixed_addresses fixmap_idx)
406*4882a593Smuzhiyun {
407*4882a593Smuzhiyun estatus->block_status = 0;
408*4882a593Smuzhiyun
409*4882a593Smuzhiyun if (!buf_paddr)
410*4882a593Smuzhiyun return;
411*4882a593Smuzhiyun
412*4882a593Smuzhiyun ghes_copy_tofrom_phys(estatus, buf_paddr,
413*4882a593Smuzhiyun sizeof(estatus->block_status), 0,
414*4882a593Smuzhiyun fixmap_idx);
415*4882a593Smuzhiyun
416*4882a593Smuzhiyun /*
417*4882a593Smuzhiyun * GHESv2 type HEST entries introduce support for error acknowledgment,
418*4882a593Smuzhiyun * so only acknowledge the error if this support is present.
419*4882a593Smuzhiyun */
420*4882a593Smuzhiyun if (is_hest_type_generic_v2(ghes))
421*4882a593Smuzhiyun ghes_ack_error(ghes->generic_v2);
422*4882a593Smuzhiyun }
423*4882a593Smuzhiyun
424*4882a593Smuzhiyun /*
425*4882a593Smuzhiyun * Called as task_work before returning to user-space.
426*4882a593Smuzhiyun * Ensure any queued work has been done before we return to the context that
427*4882a593Smuzhiyun * triggered the notification.
428*4882a593Smuzhiyun */
ghes_kick_task_work(struct callback_head * head)429*4882a593Smuzhiyun static void ghes_kick_task_work(struct callback_head *head)
430*4882a593Smuzhiyun {
431*4882a593Smuzhiyun struct acpi_hest_generic_status *estatus;
432*4882a593Smuzhiyun struct ghes_estatus_node *estatus_node;
433*4882a593Smuzhiyun u32 node_len;
434*4882a593Smuzhiyun
435*4882a593Smuzhiyun estatus_node = container_of(head, struct ghes_estatus_node, task_work);
436*4882a593Smuzhiyun if (IS_ENABLED(CONFIG_ACPI_APEI_MEMORY_FAILURE))
437*4882a593Smuzhiyun memory_failure_queue_kick(estatus_node->task_work_cpu);
438*4882a593Smuzhiyun
439*4882a593Smuzhiyun estatus = GHES_ESTATUS_FROM_NODE(estatus_node);
440*4882a593Smuzhiyun node_len = GHES_ESTATUS_NODE_LEN(cper_estatus_len(estatus));
441*4882a593Smuzhiyun gen_pool_free(ghes_estatus_pool, (unsigned long)estatus_node, node_len);
442*4882a593Smuzhiyun }
443*4882a593Smuzhiyun
ghes_do_memory_failure(u64 physical_addr,int flags)444*4882a593Smuzhiyun static bool ghes_do_memory_failure(u64 physical_addr, int flags)
445*4882a593Smuzhiyun {
446*4882a593Smuzhiyun unsigned long pfn;
447*4882a593Smuzhiyun
448*4882a593Smuzhiyun if (!IS_ENABLED(CONFIG_ACPI_APEI_MEMORY_FAILURE))
449*4882a593Smuzhiyun return false;
450*4882a593Smuzhiyun
451*4882a593Smuzhiyun pfn = PHYS_PFN(physical_addr);
452*4882a593Smuzhiyun if (!pfn_valid(pfn)) {
453*4882a593Smuzhiyun pr_warn_ratelimited(FW_WARN GHES_PFX
454*4882a593Smuzhiyun "Invalid address in generic error data: %#llx\n",
455*4882a593Smuzhiyun physical_addr);
456*4882a593Smuzhiyun return false;
457*4882a593Smuzhiyun }
458*4882a593Smuzhiyun
459*4882a593Smuzhiyun memory_failure_queue(pfn, flags);
460*4882a593Smuzhiyun return true;
461*4882a593Smuzhiyun }
462*4882a593Smuzhiyun
ghes_handle_memory_failure(struct acpi_hest_generic_data * gdata,int sev)463*4882a593Smuzhiyun static bool ghes_handle_memory_failure(struct acpi_hest_generic_data *gdata,
464*4882a593Smuzhiyun int sev)
465*4882a593Smuzhiyun {
466*4882a593Smuzhiyun int flags = -1;
467*4882a593Smuzhiyun int sec_sev = ghes_severity(gdata->error_severity);
468*4882a593Smuzhiyun struct cper_sec_mem_err *mem_err = acpi_hest_get_payload(gdata);
469*4882a593Smuzhiyun
470*4882a593Smuzhiyun if (!(mem_err->validation_bits & CPER_MEM_VALID_PA))
471*4882a593Smuzhiyun return false;
472*4882a593Smuzhiyun
473*4882a593Smuzhiyun /* iff following two events can be handled properly by now */
474*4882a593Smuzhiyun if (sec_sev == GHES_SEV_CORRECTED &&
475*4882a593Smuzhiyun (gdata->flags & CPER_SEC_ERROR_THRESHOLD_EXCEEDED))
476*4882a593Smuzhiyun flags = MF_SOFT_OFFLINE;
477*4882a593Smuzhiyun if (sev == GHES_SEV_RECOVERABLE && sec_sev == GHES_SEV_RECOVERABLE)
478*4882a593Smuzhiyun flags = 0;
479*4882a593Smuzhiyun
480*4882a593Smuzhiyun if (flags != -1)
481*4882a593Smuzhiyun return ghes_do_memory_failure(mem_err->physical_addr, flags);
482*4882a593Smuzhiyun
483*4882a593Smuzhiyun return false;
484*4882a593Smuzhiyun }
485*4882a593Smuzhiyun
ghes_handle_arm_hw_error(struct acpi_hest_generic_data * gdata,int sev)486*4882a593Smuzhiyun static bool ghes_handle_arm_hw_error(struct acpi_hest_generic_data *gdata, int sev)
487*4882a593Smuzhiyun {
488*4882a593Smuzhiyun struct cper_sec_proc_arm *err = acpi_hest_get_payload(gdata);
489*4882a593Smuzhiyun bool queued = false;
490*4882a593Smuzhiyun int sec_sev, i;
491*4882a593Smuzhiyun char *p;
492*4882a593Smuzhiyun
493*4882a593Smuzhiyun log_arm_hw_error(err);
494*4882a593Smuzhiyun
495*4882a593Smuzhiyun sec_sev = ghes_severity(gdata->error_severity);
496*4882a593Smuzhiyun if (sev != GHES_SEV_RECOVERABLE || sec_sev != GHES_SEV_RECOVERABLE)
497*4882a593Smuzhiyun return false;
498*4882a593Smuzhiyun
499*4882a593Smuzhiyun p = (char *)(err + 1);
500*4882a593Smuzhiyun for (i = 0; i < err->err_info_num; i++) {
501*4882a593Smuzhiyun struct cper_arm_err_info *err_info = (struct cper_arm_err_info *)p;
502*4882a593Smuzhiyun bool is_cache = (err_info->type == CPER_ARM_CACHE_ERROR);
503*4882a593Smuzhiyun bool has_pa = (err_info->validation_bits & CPER_ARM_INFO_VALID_PHYSICAL_ADDR);
504*4882a593Smuzhiyun const char *error_type = "unknown error";
505*4882a593Smuzhiyun
506*4882a593Smuzhiyun /*
507*4882a593Smuzhiyun * The field (err_info->error_info & BIT(26)) is fixed to set to
508*4882a593Smuzhiyun * 1 in some old firmware of HiSilicon Kunpeng920. We assume that
509*4882a593Smuzhiyun * firmware won't mix corrected errors in an uncorrected section,
510*4882a593Smuzhiyun * and don't filter out 'corrected' error here.
511*4882a593Smuzhiyun */
512*4882a593Smuzhiyun if (is_cache && has_pa) {
513*4882a593Smuzhiyun queued = ghes_do_memory_failure(err_info->physical_fault_addr, 0);
514*4882a593Smuzhiyun p += err_info->length;
515*4882a593Smuzhiyun continue;
516*4882a593Smuzhiyun }
517*4882a593Smuzhiyun
518*4882a593Smuzhiyun if (err_info->type < ARRAY_SIZE(cper_proc_error_type_strs))
519*4882a593Smuzhiyun error_type = cper_proc_error_type_strs[err_info->type];
520*4882a593Smuzhiyun
521*4882a593Smuzhiyun pr_warn_ratelimited(FW_WARN GHES_PFX
522*4882a593Smuzhiyun "Unhandled processor error type: %s\n",
523*4882a593Smuzhiyun error_type);
524*4882a593Smuzhiyun p += err_info->length;
525*4882a593Smuzhiyun }
526*4882a593Smuzhiyun
527*4882a593Smuzhiyun return queued;
528*4882a593Smuzhiyun }
529*4882a593Smuzhiyun
530*4882a593Smuzhiyun /*
531*4882a593Smuzhiyun * PCIe AER errors need to be sent to the AER driver for reporting and
532*4882a593Smuzhiyun * recovery. The GHES severities map to the following AER severities and
533*4882a593Smuzhiyun * require the following handling:
534*4882a593Smuzhiyun *
535*4882a593Smuzhiyun * GHES_SEV_CORRECTABLE -> AER_CORRECTABLE
536*4882a593Smuzhiyun * These need to be reported by the AER driver but no recovery is
537*4882a593Smuzhiyun * necessary.
538*4882a593Smuzhiyun * GHES_SEV_RECOVERABLE -> AER_NONFATAL
539*4882a593Smuzhiyun * GHES_SEV_RECOVERABLE && CPER_SEC_RESET -> AER_FATAL
540*4882a593Smuzhiyun * These both need to be reported and recovered from by the AER driver.
541*4882a593Smuzhiyun * GHES_SEV_PANIC does not make it to this handling since the kernel must
542*4882a593Smuzhiyun * panic.
543*4882a593Smuzhiyun */
ghes_handle_aer(struct acpi_hest_generic_data * gdata)544*4882a593Smuzhiyun static void ghes_handle_aer(struct acpi_hest_generic_data *gdata)
545*4882a593Smuzhiyun {
546*4882a593Smuzhiyun #ifdef CONFIG_ACPI_APEI_PCIEAER
547*4882a593Smuzhiyun struct cper_sec_pcie *pcie_err = acpi_hest_get_payload(gdata);
548*4882a593Smuzhiyun
549*4882a593Smuzhiyun if (pcie_err->validation_bits & CPER_PCIE_VALID_DEVICE_ID &&
550*4882a593Smuzhiyun pcie_err->validation_bits & CPER_PCIE_VALID_AER_INFO) {
551*4882a593Smuzhiyun unsigned int devfn;
552*4882a593Smuzhiyun int aer_severity;
553*4882a593Smuzhiyun
554*4882a593Smuzhiyun devfn = PCI_DEVFN(pcie_err->device_id.device,
555*4882a593Smuzhiyun pcie_err->device_id.function);
556*4882a593Smuzhiyun aer_severity = cper_severity_to_aer(gdata->error_severity);
557*4882a593Smuzhiyun
558*4882a593Smuzhiyun /*
559*4882a593Smuzhiyun * If firmware reset the component to contain
560*4882a593Smuzhiyun * the error, we must reinitialize it before
561*4882a593Smuzhiyun * use, so treat it as a fatal AER error.
562*4882a593Smuzhiyun */
563*4882a593Smuzhiyun if (gdata->flags & CPER_SEC_RESET)
564*4882a593Smuzhiyun aer_severity = AER_FATAL;
565*4882a593Smuzhiyun
566*4882a593Smuzhiyun aer_recover_queue(pcie_err->device_id.segment,
567*4882a593Smuzhiyun pcie_err->device_id.bus,
568*4882a593Smuzhiyun devfn, aer_severity,
569*4882a593Smuzhiyun (struct aer_capability_regs *)
570*4882a593Smuzhiyun pcie_err->aer_info);
571*4882a593Smuzhiyun }
572*4882a593Smuzhiyun #endif
573*4882a593Smuzhiyun }
574*4882a593Smuzhiyun
575*4882a593Smuzhiyun static BLOCKING_NOTIFIER_HEAD(vendor_record_notify_list);
576*4882a593Smuzhiyun
ghes_register_vendor_record_notifier(struct notifier_block * nb)577*4882a593Smuzhiyun int ghes_register_vendor_record_notifier(struct notifier_block *nb)
578*4882a593Smuzhiyun {
579*4882a593Smuzhiyun return blocking_notifier_chain_register(&vendor_record_notify_list, nb);
580*4882a593Smuzhiyun }
581*4882a593Smuzhiyun EXPORT_SYMBOL_GPL(ghes_register_vendor_record_notifier);
582*4882a593Smuzhiyun
ghes_unregister_vendor_record_notifier(struct notifier_block * nb)583*4882a593Smuzhiyun void ghes_unregister_vendor_record_notifier(struct notifier_block *nb)
584*4882a593Smuzhiyun {
585*4882a593Smuzhiyun blocking_notifier_chain_unregister(&vendor_record_notify_list, nb);
586*4882a593Smuzhiyun }
587*4882a593Smuzhiyun EXPORT_SYMBOL_GPL(ghes_unregister_vendor_record_notifier);
588*4882a593Smuzhiyun
ghes_vendor_record_work_func(struct work_struct * work)589*4882a593Smuzhiyun static void ghes_vendor_record_work_func(struct work_struct *work)
590*4882a593Smuzhiyun {
591*4882a593Smuzhiyun struct ghes_vendor_record_entry *entry;
592*4882a593Smuzhiyun struct acpi_hest_generic_data *gdata;
593*4882a593Smuzhiyun u32 len;
594*4882a593Smuzhiyun
595*4882a593Smuzhiyun entry = container_of(work, struct ghes_vendor_record_entry, work);
596*4882a593Smuzhiyun gdata = GHES_GDATA_FROM_VENDOR_ENTRY(entry);
597*4882a593Smuzhiyun
598*4882a593Smuzhiyun blocking_notifier_call_chain(&vendor_record_notify_list,
599*4882a593Smuzhiyun entry->error_severity, gdata);
600*4882a593Smuzhiyun
601*4882a593Smuzhiyun len = GHES_VENDOR_ENTRY_LEN(acpi_hest_get_record_size(gdata));
602*4882a593Smuzhiyun gen_pool_free(ghes_estatus_pool, (unsigned long)entry, len);
603*4882a593Smuzhiyun }
604*4882a593Smuzhiyun
ghes_defer_non_standard_event(struct acpi_hest_generic_data * gdata,int sev)605*4882a593Smuzhiyun static void ghes_defer_non_standard_event(struct acpi_hest_generic_data *gdata,
606*4882a593Smuzhiyun int sev)
607*4882a593Smuzhiyun {
608*4882a593Smuzhiyun struct acpi_hest_generic_data *copied_gdata;
609*4882a593Smuzhiyun struct ghes_vendor_record_entry *entry;
610*4882a593Smuzhiyun u32 len;
611*4882a593Smuzhiyun
612*4882a593Smuzhiyun len = GHES_VENDOR_ENTRY_LEN(acpi_hest_get_record_size(gdata));
613*4882a593Smuzhiyun entry = (void *)gen_pool_alloc(ghes_estatus_pool, len);
614*4882a593Smuzhiyun if (!entry)
615*4882a593Smuzhiyun return;
616*4882a593Smuzhiyun
617*4882a593Smuzhiyun copied_gdata = GHES_GDATA_FROM_VENDOR_ENTRY(entry);
618*4882a593Smuzhiyun memcpy(copied_gdata, gdata, acpi_hest_get_record_size(gdata));
619*4882a593Smuzhiyun entry->error_severity = sev;
620*4882a593Smuzhiyun
621*4882a593Smuzhiyun INIT_WORK(&entry->work, ghes_vendor_record_work_func);
622*4882a593Smuzhiyun schedule_work(&entry->work);
623*4882a593Smuzhiyun }
624*4882a593Smuzhiyun
ghes_do_proc(struct ghes * ghes,const struct acpi_hest_generic_status * estatus)625*4882a593Smuzhiyun static bool ghes_do_proc(struct ghes *ghes,
626*4882a593Smuzhiyun const struct acpi_hest_generic_status *estatus)
627*4882a593Smuzhiyun {
628*4882a593Smuzhiyun int sev, sec_sev;
629*4882a593Smuzhiyun struct acpi_hest_generic_data *gdata;
630*4882a593Smuzhiyun guid_t *sec_type;
631*4882a593Smuzhiyun const guid_t *fru_id = &guid_null;
632*4882a593Smuzhiyun char *fru_text = "";
633*4882a593Smuzhiyun bool queued = false;
634*4882a593Smuzhiyun
635*4882a593Smuzhiyun sev = ghes_severity(estatus->error_severity);
636*4882a593Smuzhiyun apei_estatus_for_each_section(estatus, gdata) {
637*4882a593Smuzhiyun sec_type = (guid_t *)gdata->section_type;
638*4882a593Smuzhiyun sec_sev = ghes_severity(gdata->error_severity);
639*4882a593Smuzhiyun if (gdata->validation_bits & CPER_SEC_VALID_FRU_ID)
640*4882a593Smuzhiyun fru_id = (guid_t *)gdata->fru_id;
641*4882a593Smuzhiyun
642*4882a593Smuzhiyun if (gdata->validation_bits & CPER_SEC_VALID_FRU_TEXT)
643*4882a593Smuzhiyun fru_text = gdata->fru_text;
644*4882a593Smuzhiyun
645*4882a593Smuzhiyun if (guid_equal(sec_type, &CPER_SEC_PLATFORM_MEM)) {
646*4882a593Smuzhiyun struct cper_sec_mem_err *mem_err = acpi_hest_get_payload(gdata);
647*4882a593Smuzhiyun
648*4882a593Smuzhiyun ghes_edac_report_mem_error(sev, mem_err);
649*4882a593Smuzhiyun
650*4882a593Smuzhiyun arch_apei_report_mem_error(sev, mem_err);
651*4882a593Smuzhiyun queued = ghes_handle_memory_failure(gdata, sev);
652*4882a593Smuzhiyun }
653*4882a593Smuzhiyun else if (guid_equal(sec_type, &CPER_SEC_PCIE)) {
654*4882a593Smuzhiyun ghes_handle_aer(gdata);
655*4882a593Smuzhiyun }
656*4882a593Smuzhiyun else if (guid_equal(sec_type, &CPER_SEC_PROC_ARM)) {
657*4882a593Smuzhiyun queued = ghes_handle_arm_hw_error(gdata, sev);
658*4882a593Smuzhiyun } else {
659*4882a593Smuzhiyun void *err = acpi_hest_get_payload(gdata);
660*4882a593Smuzhiyun
661*4882a593Smuzhiyun ghes_defer_non_standard_event(gdata, sev);
662*4882a593Smuzhiyun log_non_standard_event(sec_type, fru_id, fru_text,
663*4882a593Smuzhiyun sec_sev, err,
664*4882a593Smuzhiyun gdata->error_data_length);
665*4882a593Smuzhiyun }
666*4882a593Smuzhiyun }
667*4882a593Smuzhiyun
668*4882a593Smuzhiyun return queued;
669*4882a593Smuzhiyun }
670*4882a593Smuzhiyun
__ghes_print_estatus(const char * pfx,const struct acpi_hest_generic * generic,const struct acpi_hest_generic_status * estatus)671*4882a593Smuzhiyun static void __ghes_print_estatus(const char *pfx,
672*4882a593Smuzhiyun const struct acpi_hest_generic *generic,
673*4882a593Smuzhiyun const struct acpi_hest_generic_status *estatus)
674*4882a593Smuzhiyun {
675*4882a593Smuzhiyun static atomic_t seqno;
676*4882a593Smuzhiyun unsigned int curr_seqno;
677*4882a593Smuzhiyun char pfx_seq[64];
678*4882a593Smuzhiyun
679*4882a593Smuzhiyun if (pfx == NULL) {
680*4882a593Smuzhiyun if (ghes_severity(estatus->error_severity) <=
681*4882a593Smuzhiyun GHES_SEV_CORRECTED)
682*4882a593Smuzhiyun pfx = KERN_WARNING;
683*4882a593Smuzhiyun else
684*4882a593Smuzhiyun pfx = KERN_ERR;
685*4882a593Smuzhiyun }
686*4882a593Smuzhiyun curr_seqno = atomic_inc_return(&seqno);
687*4882a593Smuzhiyun snprintf(pfx_seq, sizeof(pfx_seq), "%s{%u}" HW_ERR, pfx, curr_seqno);
688*4882a593Smuzhiyun printk("%s""Hardware error from APEI Generic Hardware Error Source: %d\n",
689*4882a593Smuzhiyun pfx_seq, generic->header.source_id);
690*4882a593Smuzhiyun cper_estatus_print(pfx_seq, estatus);
691*4882a593Smuzhiyun }
692*4882a593Smuzhiyun
ghes_print_estatus(const char * pfx,const struct acpi_hest_generic * generic,const struct acpi_hest_generic_status * estatus)693*4882a593Smuzhiyun static int ghes_print_estatus(const char *pfx,
694*4882a593Smuzhiyun const struct acpi_hest_generic *generic,
695*4882a593Smuzhiyun const struct acpi_hest_generic_status *estatus)
696*4882a593Smuzhiyun {
697*4882a593Smuzhiyun /* Not more than 2 messages every 5 seconds */
698*4882a593Smuzhiyun static DEFINE_RATELIMIT_STATE(ratelimit_corrected, 5*HZ, 2);
699*4882a593Smuzhiyun static DEFINE_RATELIMIT_STATE(ratelimit_uncorrected, 5*HZ, 2);
700*4882a593Smuzhiyun struct ratelimit_state *ratelimit;
701*4882a593Smuzhiyun
702*4882a593Smuzhiyun if (ghes_severity(estatus->error_severity) <= GHES_SEV_CORRECTED)
703*4882a593Smuzhiyun ratelimit = &ratelimit_corrected;
704*4882a593Smuzhiyun else
705*4882a593Smuzhiyun ratelimit = &ratelimit_uncorrected;
706*4882a593Smuzhiyun if (__ratelimit(ratelimit)) {
707*4882a593Smuzhiyun __ghes_print_estatus(pfx, generic, estatus);
708*4882a593Smuzhiyun return 1;
709*4882a593Smuzhiyun }
710*4882a593Smuzhiyun return 0;
711*4882a593Smuzhiyun }
712*4882a593Smuzhiyun
713*4882a593Smuzhiyun /*
714*4882a593Smuzhiyun * GHES error status reporting throttle, to report more kinds of
715*4882a593Smuzhiyun * errors, instead of just most frequently occurred errors.
716*4882a593Smuzhiyun */
ghes_estatus_cached(struct acpi_hest_generic_status * estatus)717*4882a593Smuzhiyun static int ghes_estatus_cached(struct acpi_hest_generic_status *estatus)
718*4882a593Smuzhiyun {
719*4882a593Smuzhiyun u32 len;
720*4882a593Smuzhiyun int i, cached = 0;
721*4882a593Smuzhiyun unsigned long long now;
722*4882a593Smuzhiyun struct ghes_estatus_cache *cache;
723*4882a593Smuzhiyun struct acpi_hest_generic_status *cache_estatus;
724*4882a593Smuzhiyun
725*4882a593Smuzhiyun len = cper_estatus_len(estatus);
726*4882a593Smuzhiyun rcu_read_lock();
727*4882a593Smuzhiyun for (i = 0; i < GHES_ESTATUS_CACHES_SIZE; i++) {
728*4882a593Smuzhiyun cache = rcu_dereference(ghes_estatus_caches[i]);
729*4882a593Smuzhiyun if (cache == NULL)
730*4882a593Smuzhiyun continue;
731*4882a593Smuzhiyun if (len != cache->estatus_len)
732*4882a593Smuzhiyun continue;
733*4882a593Smuzhiyun cache_estatus = GHES_ESTATUS_FROM_CACHE(cache);
734*4882a593Smuzhiyun if (memcmp(estatus, cache_estatus, len))
735*4882a593Smuzhiyun continue;
736*4882a593Smuzhiyun atomic_inc(&cache->count);
737*4882a593Smuzhiyun now = sched_clock();
738*4882a593Smuzhiyun if (now - cache->time_in < GHES_ESTATUS_IN_CACHE_MAX_NSEC)
739*4882a593Smuzhiyun cached = 1;
740*4882a593Smuzhiyun break;
741*4882a593Smuzhiyun }
742*4882a593Smuzhiyun rcu_read_unlock();
743*4882a593Smuzhiyun return cached;
744*4882a593Smuzhiyun }
745*4882a593Smuzhiyun
ghes_estatus_cache_alloc(struct acpi_hest_generic * generic,struct acpi_hest_generic_status * estatus)746*4882a593Smuzhiyun static struct ghes_estatus_cache *ghes_estatus_cache_alloc(
747*4882a593Smuzhiyun struct acpi_hest_generic *generic,
748*4882a593Smuzhiyun struct acpi_hest_generic_status *estatus)
749*4882a593Smuzhiyun {
750*4882a593Smuzhiyun int alloced;
751*4882a593Smuzhiyun u32 len, cache_len;
752*4882a593Smuzhiyun struct ghes_estatus_cache *cache;
753*4882a593Smuzhiyun struct acpi_hest_generic_status *cache_estatus;
754*4882a593Smuzhiyun
755*4882a593Smuzhiyun alloced = atomic_add_return(1, &ghes_estatus_cache_alloced);
756*4882a593Smuzhiyun if (alloced > GHES_ESTATUS_CACHE_ALLOCED_MAX) {
757*4882a593Smuzhiyun atomic_dec(&ghes_estatus_cache_alloced);
758*4882a593Smuzhiyun return NULL;
759*4882a593Smuzhiyun }
760*4882a593Smuzhiyun len = cper_estatus_len(estatus);
761*4882a593Smuzhiyun cache_len = GHES_ESTATUS_CACHE_LEN(len);
762*4882a593Smuzhiyun cache = (void *)gen_pool_alloc(ghes_estatus_pool, cache_len);
763*4882a593Smuzhiyun if (!cache) {
764*4882a593Smuzhiyun atomic_dec(&ghes_estatus_cache_alloced);
765*4882a593Smuzhiyun return NULL;
766*4882a593Smuzhiyun }
767*4882a593Smuzhiyun cache_estatus = GHES_ESTATUS_FROM_CACHE(cache);
768*4882a593Smuzhiyun memcpy(cache_estatus, estatus, len);
769*4882a593Smuzhiyun cache->estatus_len = len;
770*4882a593Smuzhiyun atomic_set(&cache->count, 0);
771*4882a593Smuzhiyun cache->generic = generic;
772*4882a593Smuzhiyun cache->time_in = sched_clock();
773*4882a593Smuzhiyun return cache;
774*4882a593Smuzhiyun }
775*4882a593Smuzhiyun
ghes_estatus_cache_free(struct ghes_estatus_cache * cache)776*4882a593Smuzhiyun static void ghes_estatus_cache_free(struct ghes_estatus_cache *cache)
777*4882a593Smuzhiyun {
778*4882a593Smuzhiyun u32 len;
779*4882a593Smuzhiyun
780*4882a593Smuzhiyun len = cper_estatus_len(GHES_ESTATUS_FROM_CACHE(cache));
781*4882a593Smuzhiyun len = GHES_ESTATUS_CACHE_LEN(len);
782*4882a593Smuzhiyun gen_pool_free(ghes_estatus_pool, (unsigned long)cache, len);
783*4882a593Smuzhiyun atomic_dec(&ghes_estatus_cache_alloced);
784*4882a593Smuzhiyun }
785*4882a593Smuzhiyun
ghes_estatus_cache_rcu_free(struct rcu_head * head)786*4882a593Smuzhiyun static void ghes_estatus_cache_rcu_free(struct rcu_head *head)
787*4882a593Smuzhiyun {
788*4882a593Smuzhiyun struct ghes_estatus_cache *cache;
789*4882a593Smuzhiyun
790*4882a593Smuzhiyun cache = container_of(head, struct ghes_estatus_cache, rcu);
791*4882a593Smuzhiyun ghes_estatus_cache_free(cache);
792*4882a593Smuzhiyun }
793*4882a593Smuzhiyun
ghes_estatus_cache_add(struct acpi_hest_generic * generic,struct acpi_hest_generic_status * estatus)794*4882a593Smuzhiyun static void ghes_estatus_cache_add(
795*4882a593Smuzhiyun struct acpi_hest_generic *generic,
796*4882a593Smuzhiyun struct acpi_hest_generic_status *estatus)
797*4882a593Smuzhiyun {
798*4882a593Smuzhiyun int i, slot = -1, count;
799*4882a593Smuzhiyun unsigned long long now, duration, period, max_period = 0;
800*4882a593Smuzhiyun struct ghes_estatus_cache *cache, *slot_cache = NULL, *new_cache;
801*4882a593Smuzhiyun
802*4882a593Smuzhiyun new_cache = ghes_estatus_cache_alloc(generic, estatus);
803*4882a593Smuzhiyun if (new_cache == NULL)
804*4882a593Smuzhiyun return;
805*4882a593Smuzhiyun rcu_read_lock();
806*4882a593Smuzhiyun now = sched_clock();
807*4882a593Smuzhiyun for (i = 0; i < GHES_ESTATUS_CACHES_SIZE; i++) {
808*4882a593Smuzhiyun cache = rcu_dereference(ghes_estatus_caches[i]);
809*4882a593Smuzhiyun if (cache == NULL) {
810*4882a593Smuzhiyun slot = i;
811*4882a593Smuzhiyun slot_cache = NULL;
812*4882a593Smuzhiyun break;
813*4882a593Smuzhiyun }
814*4882a593Smuzhiyun duration = now - cache->time_in;
815*4882a593Smuzhiyun if (duration >= GHES_ESTATUS_IN_CACHE_MAX_NSEC) {
816*4882a593Smuzhiyun slot = i;
817*4882a593Smuzhiyun slot_cache = cache;
818*4882a593Smuzhiyun break;
819*4882a593Smuzhiyun }
820*4882a593Smuzhiyun count = atomic_read(&cache->count);
821*4882a593Smuzhiyun period = duration;
822*4882a593Smuzhiyun do_div(period, (count + 1));
823*4882a593Smuzhiyun if (period > max_period) {
824*4882a593Smuzhiyun max_period = period;
825*4882a593Smuzhiyun slot = i;
826*4882a593Smuzhiyun slot_cache = cache;
827*4882a593Smuzhiyun }
828*4882a593Smuzhiyun }
829*4882a593Smuzhiyun /* new_cache must be put into array after its contents are written */
830*4882a593Smuzhiyun smp_wmb();
831*4882a593Smuzhiyun if (slot != -1 && cmpxchg(ghes_estatus_caches + slot,
832*4882a593Smuzhiyun slot_cache, new_cache) == slot_cache) {
833*4882a593Smuzhiyun if (slot_cache)
834*4882a593Smuzhiyun call_rcu(&slot_cache->rcu, ghes_estatus_cache_rcu_free);
835*4882a593Smuzhiyun } else
836*4882a593Smuzhiyun ghes_estatus_cache_free(new_cache);
837*4882a593Smuzhiyun rcu_read_unlock();
838*4882a593Smuzhiyun }
839*4882a593Smuzhiyun
__ghes_panic(struct ghes * ghes,struct acpi_hest_generic_status * estatus,u64 buf_paddr,enum fixed_addresses fixmap_idx)840*4882a593Smuzhiyun static void __ghes_panic(struct ghes *ghes,
841*4882a593Smuzhiyun struct acpi_hest_generic_status *estatus,
842*4882a593Smuzhiyun u64 buf_paddr, enum fixed_addresses fixmap_idx)
843*4882a593Smuzhiyun {
844*4882a593Smuzhiyun __ghes_print_estatus(KERN_EMERG, ghes->generic, estatus);
845*4882a593Smuzhiyun
846*4882a593Smuzhiyun ghes_clear_estatus(ghes, estatus, buf_paddr, fixmap_idx);
847*4882a593Smuzhiyun
848*4882a593Smuzhiyun /* reboot to log the error! */
849*4882a593Smuzhiyun if (!panic_timeout)
850*4882a593Smuzhiyun panic_timeout = ghes_panic_timeout;
851*4882a593Smuzhiyun panic("Fatal hardware error!");
852*4882a593Smuzhiyun }
853*4882a593Smuzhiyun
ghes_proc(struct ghes * ghes)854*4882a593Smuzhiyun static int ghes_proc(struct ghes *ghes)
855*4882a593Smuzhiyun {
856*4882a593Smuzhiyun struct acpi_hest_generic_status *estatus = ghes->estatus;
857*4882a593Smuzhiyun u64 buf_paddr;
858*4882a593Smuzhiyun int rc;
859*4882a593Smuzhiyun
860*4882a593Smuzhiyun rc = ghes_read_estatus(ghes, estatus, &buf_paddr, FIX_APEI_GHES_IRQ);
861*4882a593Smuzhiyun if (rc)
862*4882a593Smuzhiyun goto out;
863*4882a593Smuzhiyun
864*4882a593Smuzhiyun if (ghes_severity(estatus->error_severity) >= GHES_SEV_PANIC)
865*4882a593Smuzhiyun __ghes_panic(ghes, estatus, buf_paddr, FIX_APEI_GHES_IRQ);
866*4882a593Smuzhiyun
867*4882a593Smuzhiyun if (!ghes_estatus_cached(estatus)) {
868*4882a593Smuzhiyun if (ghes_print_estatus(NULL, ghes->generic, estatus))
869*4882a593Smuzhiyun ghes_estatus_cache_add(ghes->generic, estatus);
870*4882a593Smuzhiyun }
871*4882a593Smuzhiyun ghes_do_proc(ghes, estatus);
872*4882a593Smuzhiyun
873*4882a593Smuzhiyun out:
874*4882a593Smuzhiyun ghes_clear_estatus(ghes, estatus, buf_paddr, FIX_APEI_GHES_IRQ);
875*4882a593Smuzhiyun
876*4882a593Smuzhiyun return rc;
877*4882a593Smuzhiyun }
878*4882a593Smuzhiyun
ghes_add_timer(struct ghes * ghes)879*4882a593Smuzhiyun static void ghes_add_timer(struct ghes *ghes)
880*4882a593Smuzhiyun {
881*4882a593Smuzhiyun struct acpi_hest_generic *g = ghes->generic;
882*4882a593Smuzhiyun unsigned long expire;
883*4882a593Smuzhiyun
884*4882a593Smuzhiyun if (!g->notify.poll_interval) {
885*4882a593Smuzhiyun pr_warn(FW_WARN GHES_PFX "Poll interval is 0 for generic hardware error source: %d, disabled.\n",
886*4882a593Smuzhiyun g->header.source_id);
887*4882a593Smuzhiyun return;
888*4882a593Smuzhiyun }
889*4882a593Smuzhiyun expire = jiffies + msecs_to_jiffies(g->notify.poll_interval);
890*4882a593Smuzhiyun ghes->timer.expires = round_jiffies_relative(expire);
891*4882a593Smuzhiyun add_timer(&ghes->timer);
892*4882a593Smuzhiyun }
893*4882a593Smuzhiyun
ghes_poll_func(struct timer_list * t)894*4882a593Smuzhiyun static void ghes_poll_func(struct timer_list *t)
895*4882a593Smuzhiyun {
896*4882a593Smuzhiyun struct ghes *ghes = from_timer(ghes, t, timer);
897*4882a593Smuzhiyun unsigned long flags;
898*4882a593Smuzhiyun
899*4882a593Smuzhiyun spin_lock_irqsave(&ghes_notify_lock_irq, flags);
900*4882a593Smuzhiyun ghes_proc(ghes);
901*4882a593Smuzhiyun spin_unlock_irqrestore(&ghes_notify_lock_irq, flags);
902*4882a593Smuzhiyun if (!(ghes->flags & GHES_EXITING))
903*4882a593Smuzhiyun ghes_add_timer(ghes);
904*4882a593Smuzhiyun }
905*4882a593Smuzhiyun
ghes_irq_func(int irq,void * data)906*4882a593Smuzhiyun static irqreturn_t ghes_irq_func(int irq, void *data)
907*4882a593Smuzhiyun {
908*4882a593Smuzhiyun struct ghes *ghes = data;
909*4882a593Smuzhiyun unsigned long flags;
910*4882a593Smuzhiyun int rc;
911*4882a593Smuzhiyun
912*4882a593Smuzhiyun spin_lock_irqsave(&ghes_notify_lock_irq, flags);
913*4882a593Smuzhiyun rc = ghes_proc(ghes);
914*4882a593Smuzhiyun spin_unlock_irqrestore(&ghes_notify_lock_irq, flags);
915*4882a593Smuzhiyun if (rc)
916*4882a593Smuzhiyun return IRQ_NONE;
917*4882a593Smuzhiyun
918*4882a593Smuzhiyun return IRQ_HANDLED;
919*4882a593Smuzhiyun }
920*4882a593Smuzhiyun
ghes_notify_hed(struct notifier_block * this,unsigned long event,void * data)921*4882a593Smuzhiyun static int ghes_notify_hed(struct notifier_block *this, unsigned long event,
922*4882a593Smuzhiyun void *data)
923*4882a593Smuzhiyun {
924*4882a593Smuzhiyun struct ghes *ghes;
925*4882a593Smuzhiyun unsigned long flags;
926*4882a593Smuzhiyun int ret = NOTIFY_DONE;
927*4882a593Smuzhiyun
928*4882a593Smuzhiyun spin_lock_irqsave(&ghes_notify_lock_irq, flags);
929*4882a593Smuzhiyun rcu_read_lock();
930*4882a593Smuzhiyun list_for_each_entry_rcu(ghes, &ghes_hed, list) {
931*4882a593Smuzhiyun if (!ghes_proc(ghes))
932*4882a593Smuzhiyun ret = NOTIFY_OK;
933*4882a593Smuzhiyun }
934*4882a593Smuzhiyun rcu_read_unlock();
935*4882a593Smuzhiyun spin_unlock_irqrestore(&ghes_notify_lock_irq, flags);
936*4882a593Smuzhiyun
937*4882a593Smuzhiyun return ret;
938*4882a593Smuzhiyun }
939*4882a593Smuzhiyun
940*4882a593Smuzhiyun static struct notifier_block ghes_notifier_hed = {
941*4882a593Smuzhiyun .notifier_call = ghes_notify_hed,
942*4882a593Smuzhiyun };
943*4882a593Smuzhiyun
944*4882a593Smuzhiyun /*
945*4882a593Smuzhiyun * Handlers for CPER records may not be NMI safe. For example,
946*4882a593Smuzhiyun * memory_failure_queue() takes spinlocks and calls schedule_work_on().
947*4882a593Smuzhiyun * In any NMI-like handler, memory from ghes_estatus_pool is used to save
948*4882a593Smuzhiyun * estatus, and added to the ghes_estatus_llist. irq_work_queue() causes
949*4882a593Smuzhiyun * ghes_proc_in_irq() to run in IRQ context where each estatus in
950*4882a593Smuzhiyun * ghes_estatus_llist is processed.
951*4882a593Smuzhiyun *
952*4882a593Smuzhiyun * Memory from the ghes_estatus_pool is also used with the ghes_estatus_cache
953*4882a593Smuzhiyun * to suppress frequent messages.
954*4882a593Smuzhiyun */
955*4882a593Smuzhiyun static struct llist_head ghes_estatus_llist;
956*4882a593Smuzhiyun static struct irq_work ghes_proc_irq_work;
957*4882a593Smuzhiyun
ghes_proc_in_irq(struct irq_work * irq_work)958*4882a593Smuzhiyun static void ghes_proc_in_irq(struct irq_work *irq_work)
959*4882a593Smuzhiyun {
960*4882a593Smuzhiyun struct llist_node *llnode, *next;
961*4882a593Smuzhiyun struct ghes_estatus_node *estatus_node;
962*4882a593Smuzhiyun struct acpi_hest_generic *generic;
963*4882a593Smuzhiyun struct acpi_hest_generic_status *estatus;
964*4882a593Smuzhiyun bool task_work_pending;
965*4882a593Smuzhiyun u32 len, node_len;
966*4882a593Smuzhiyun int ret;
967*4882a593Smuzhiyun
968*4882a593Smuzhiyun llnode = llist_del_all(&ghes_estatus_llist);
969*4882a593Smuzhiyun /*
970*4882a593Smuzhiyun * Because the time order of estatus in list is reversed,
971*4882a593Smuzhiyun * revert it back to proper order.
972*4882a593Smuzhiyun */
973*4882a593Smuzhiyun llnode = llist_reverse_order(llnode);
974*4882a593Smuzhiyun while (llnode) {
975*4882a593Smuzhiyun next = llnode->next;
976*4882a593Smuzhiyun estatus_node = llist_entry(llnode, struct ghes_estatus_node,
977*4882a593Smuzhiyun llnode);
978*4882a593Smuzhiyun estatus = GHES_ESTATUS_FROM_NODE(estatus_node);
979*4882a593Smuzhiyun len = cper_estatus_len(estatus);
980*4882a593Smuzhiyun node_len = GHES_ESTATUS_NODE_LEN(len);
981*4882a593Smuzhiyun task_work_pending = ghes_do_proc(estatus_node->ghes, estatus);
982*4882a593Smuzhiyun if (!ghes_estatus_cached(estatus)) {
983*4882a593Smuzhiyun generic = estatus_node->generic;
984*4882a593Smuzhiyun if (ghes_print_estatus(NULL, generic, estatus))
985*4882a593Smuzhiyun ghes_estatus_cache_add(generic, estatus);
986*4882a593Smuzhiyun }
987*4882a593Smuzhiyun
988*4882a593Smuzhiyun if (task_work_pending && current->mm) {
989*4882a593Smuzhiyun estatus_node->task_work.func = ghes_kick_task_work;
990*4882a593Smuzhiyun estatus_node->task_work_cpu = smp_processor_id();
991*4882a593Smuzhiyun ret = task_work_add(current, &estatus_node->task_work,
992*4882a593Smuzhiyun TWA_RESUME);
993*4882a593Smuzhiyun if (ret)
994*4882a593Smuzhiyun estatus_node->task_work.func = NULL;
995*4882a593Smuzhiyun }
996*4882a593Smuzhiyun
997*4882a593Smuzhiyun if (!estatus_node->task_work.func)
998*4882a593Smuzhiyun gen_pool_free(ghes_estatus_pool,
999*4882a593Smuzhiyun (unsigned long)estatus_node, node_len);
1000*4882a593Smuzhiyun
1001*4882a593Smuzhiyun llnode = next;
1002*4882a593Smuzhiyun }
1003*4882a593Smuzhiyun }
1004*4882a593Smuzhiyun
ghes_print_queued_estatus(void)1005*4882a593Smuzhiyun static void ghes_print_queued_estatus(void)
1006*4882a593Smuzhiyun {
1007*4882a593Smuzhiyun struct llist_node *llnode;
1008*4882a593Smuzhiyun struct ghes_estatus_node *estatus_node;
1009*4882a593Smuzhiyun struct acpi_hest_generic *generic;
1010*4882a593Smuzhiyun struct acpi_hest_generic_status *estatus;
1011*4882a593Smuzhiyun
1012*4882a593Smuzhiyun llnode = llist_del_all(&ghes_estatus_llist);
1013*4882a593Smuzhiyun /*
1014*4882a593Smuzhiyun * Because the time order of estatus in list is reversed,
1015*4882a593Smuzhiyun * revert it back to proper order.
1016*4882a593Smuzhiyun */
1017*4882a593Smuzhiyun llnode = llist_reverse_order(llnode);
1018*4882a593Smuzhiyun while (llnode) {
1019*4882a593Smuzhiyun estatus_node = llist_entry(llnode, struct ghes_estatus_node,
1020*4882a593Smuzhiyun llnode);
1021*4882a593Smuzhiyun estatus = GHES_ESTATUS_FROM_NODE(estatus_node);
1022*4882a593Smuzhiyun generic = estatus_node->generic;
1023*4882a593Smuzhiyun ghes_print_estatus(NULL, generic, estatus);
1024*4882a593Smuzhiyun llnode = llnode->next;
1025*4882a593Smuzhiyun }
1026*4882a593Smuzhiyun }
1027*4882a593Smuzhiyun
ghes_in_nmi_queue_one_entry(struct ghes * ghes,enum fixed_addresses fixmap_idx)1028*4882a593Smuzhiyun static int ghes_in_nmi_queue_one_entry(struct ghes *ghes,
1029*4882a593Smuzhiyun enum fixed_addresses fixmap_idx)
1030*4882a593Smuzhiyun {
1031*4882a593Smuzhiyun struct acpi_hest_generic_status *estatus, tmp_header;
1032*4882a593Smuzhiyun struct ghes_estatus_node *estatus_node;
1033*4882a593Smuzhiyun u32 len, node_len;
1034*4882a593Smuzhiyun u64 buf_paddr;
1035*4882a593Smuzhiyun int sev, rc;
1036*4882a593Smuzhiyun
1037*4882a593Smuzhiyun if (!IS_ENABLED(CONFIG_ARCH_HAVE_NMI_SAFE_CMPXCHG))
1038*4882a593Smuzhiyun return -EOPNOTSUPP;
1039*4882a593Smuzhiyun
1040*4882a593Smuzhiyun rc = __ghes_peek_estatus(ghes, &tmp_header, &buf_paddr, fixmap_idx);
1041*4882a593Smuzhiyun if (rc) {
1042*4882a593Smuzhiyun ghes_clear_estatus(ghes, &tmp_header, buf_paddr, fixmap_idx);
1043*4882a593Smuzhiyun return rc;
1044*4882a593Smuzhiyun }
1045*4882a593Smuzhiyun
1046*4882a593Smuzhiyun rc = __ghes_check_estatus(ghes, &tmp_header);
1047*4882a593Smuzhiyun if (rc) {
1048*4882a593Smuzhiyun ghes_clear_estatus(ghes, &tmp_header, buf_paddr, fixmap_idx);
1049*4882a593Smuzhiyun return rc;
1050*4882a593Smuzhiyun }
1051*4882a593Smuzhiyun
1052*4882a593Smuzhiyun len = cper_estatus_len(&tmp_header);
1053*4882a593Smuzhiyun node_len = GHES_ESTATUS_NODE_LEN(len);
1054*4882a593Smuzhiyun estatus_node = (void *)gen_pool_alloc(ghes_estatus_pool, node_len);
1055*4882a593Smuzhiyun if (!estatus_node)
1056*4882a593Smuzhiyun return -ENOMEM;
1057*4882a593Smuzhiyun
1058*4882a593Smuzhiyun estatus_node->ghes = ghes;
1059*4882a593Smuzhiyun estatus_node->generic = ghes->generic;
1060*4882a593Smuzhiyun estatus_node->task_work.func = NULL;
1061*4882a593Smuzhiyun estatus = GHES_ESTATUS_FROM_NODE(estatus_node);
1062*4882a593Smuzhiyun
1063*4882a593Smuzhiyun if (__ghes_read_estatus(estatus, buf_paddr, fixmap_idx, len)) {
1064*4882a593Smuzhiyun ghes_clear_estatus(ghes, estatus, buf_paddr, fixmap_idx);
1065*4882a593Smuzhiyun rc = -ENOENT;
1066*4882a593Smuzhiyun goto no_work;
1067*4882a593Smuzhiyun }
1068*4882a593Smuzhiyun
1069*4882a593Smuzhiyun sev = ghes_severity(estatus->error_severity);
1070*4882a593Smuzhiyun if (sev >= GHES_SEV_PANIC) {
1071*4882a593Smuzhiyun ghes_print_queued_estatus();
1072*4882a593Smuzhiyun __ghes_panic(ghes, estatus, buf_paddr, fixmap_idx);
1073*4882a593Smuzhiyun }
1074*4882a593Smuzhiyun
1075*4882a593Smuzhiyun ghes_clear_estatus(ghes, &tmp_header, buf_paddr, fixmap_idx);
1076*4882a593Smuzhiyun
1077*4882a593Smuzhiyun /* This error has been reported before, don't process it again. */
1078*4882a593Smuzhiyun if (ghes_estatus_cached(estatus))
1079*4882a593Smuzhiyun goto no_work;
1080*4882a593Smuzhiyun
1081*4882a593Smuzhiyun llist_add(&estatus_node->llnode, &ghes_estatus_llist);
1082*4882a593Smuzhiyun
1083*4882a593Smuzhiyun return rc;
1084*4882a593Smuzhiyun
1085*4882a593Smuzhiyun no_work:
1086*4882a593Smuzhiyun gen_pool_free(ghes_estatus_pool, (unsigned long)estatus_node,
1087*4882a593Smuzhiyun node_len);
1088*4882a593Smuzhiyun
1089*4882a593Smuzhiyun return rc;
1090*4882a593Smuzhiyun }
1091*4882a593Smuzhiyun
ghes_in_nmi_spool_from_list(struct list_head * rcu_list,enum fixed_addresses fixmap_idx)1092*4882a593Smuzhiyun static int ghes_in_nmi_spool_from_list(struct list_head *rcu_list,
1093*4882a593Smuzhiyun enum fixed_addresses fixmap_idx)
1094*4882a593Smuzhiyun {
1095*4882a593Smuzhiyun int ret = -ENOENT;
1096*4882a593Smuzhiyun struct ghes *ghes;
1097*4882a593Smuzhiyun
1098*4882a593Smuzhiyun rcu_read_lock();
1099*4882a593Smuzhiyun list_for_each_entry_rcu(ghes, rcu_list, list) {
1100*4882a593Smuzhiyun if (!ghes_in_nmi_queue_one_entry(ghes, fixmap_idx))
1101*4882a593Smuzhiyun ret = 0;
1102*4882a593Smuzhiyun }
1103*4882a593Smuzhiyun rcu_read_unlock();
1104*4882a593Smuzhiyun
1105*4882a593Smuzhiyun if (IS_ENABLED(CONFIG_ARCH_HAVE_NMI_SAFE_CMPXCHG) && !ret)
1106*4882a593Smuzhiyun irq_work_queue(&ghes_proc_irq_work);
1107*4882a593Smuzhiyun
1108*4882a593Smuzhiyun return ret;
1109*4882a593Smuzhiyun }
1110*4882a593Smuzhiyun
1111*4882a593Smuzhiyun #ifdef CONFIG_ACPI_APEI_SEA
1112*4882a593Smuzhiyun static LIST_HEAD(ghes_sea);
1113*4882a593Smuzhiyun
1114*4882a593Smuzhiyun /*
1115*4882a593Smuzhiyun * Return 0 only if one of the SEA error sources successfully reported an error
1116*4882a593Smuzhiyun * record sent from the firmware.
1117*4882a593Smuzhiyun */
ghes_notify_sea(void)1118*4882a593Smuzhiyun int ghes_notify_sea(void)
1119*4882a593Smuzhiyun {
1120*4882a593Smuzhiyun static DEFINE_RAW_SPINLOCK(ghes_notify_lock_sea);
1121*4882a593Smuzhiyun int rv;
1122*4882a593Smuzhiyun
1123*4882a593Smuzhiyun raw_spin_lock(&ghes_notify_lock_sea);
1124*4882a593Smuzhiyun rv = ghes_in_nmi_spool_from_list(&ghes_sea, FIX_APEI_GHES_SEA);
1125*4882a593Smuzhiyun raw_spin_unlock(&ghes_notify_lock_sea);
1126*4882a593Smuzhiyun
1127*4882a593Smuzhiyun return rv;
1128*4882a593Smuzhiyun }
1129*4882a593Smuzhiyun
ghes_sea_add(struct ghes * ghes)1130*4882a593Smuzhiyun static void ghes_sea_add(struct ghes *ghes)
1131*4882a593Smuzhiyun {
1132*4882a593Smuzhiyun mutex_lock(&ghes_list_mutex);
1133*4882a593Smuzhiyun list_add_rcu(&ghes->list, &ghes_sea);
1134*4882a593Smuzhiyun mutex_unlock(&ghes_list_mutex);
1135*4882a593Smuzhiyun }
1136*4882a593Smuzhiyun
ghes_sea_remove(struct ghes * ghes)1137*4882a593Smuzhiyun static void ghes_sea_remove(struct ghes *ghes)
1138*4882a593Smuzhiyun {
1139*4882a593Smuzhiyun mutex_lock(&ghes_list_mutex);
1140*4882a593Smuzhiyun list_del_rcu(&ghes->list);
1141*4882a593Smuzhiyun mutex_unlock(&ghes_list_mutex);
1142*4882a593Smuzhiyun synchronize_rcu();
1143*4882a593Smuzhiyun }
1144*4882a593Smuzhiyun #else /* CONFIG_ACPI_APEI_SEA */
ghes_sea_add(struct ghes * ghes)1145*4882a593Smuzhiyun static inline void ghes_sea_add(struct ghes *ghes) { }
ghes_sea_remove(struct ghes * ghes)1146*4882a593Smuzhiyun static inline void ghes_sea_remove(struct ghes *ghes) { }
1147*4882a593Smuzhiyun #endif /* CONFIG_ACPI_APEI_SEA */
1148*4882a593Smuzhiyun
1149*4882a593Smuzhiyun #ifdef CONFIG_HAVE_ACPI_APEI_NMI
1150*4882a593Smuzhiyun /*
1151*4882a593Smuzhiyun * NMI may be triggered on any CPU, so ghes_in_nmi is used for
1152*4882a593Smuzhiyun * having only one concurrent reader.
1153*4882a593Smuzhiyun */
1154*4882a593Smuzhiyun static atomic_t ghes_in_nmi = ATOMIC_INIT(0);
1155*4882a593Smuzhiyun
1156*4882a593Smuzhiyun static LIST_HEAD(ghes_nmi);
1157*4882a593Smuzhiyun
ghes_notify_nmi(unsigned int cmd,struct pt_regs * regs)1158*4882a593Smuzhiyun static int ghes_notify_nmi(unsigned int cmd, struct pt_regs *regs)
1159*4882a593Smuzhiyun {
1160*4882a593Smuzhiyun static DEFINE_RAW_SPINLOCK(ghes_notify_lock_nmi);
1161*4882a593Smuzhiyun int ret = NMI_DONE;
1162*4882a593Smuzhiyun
1163*4882a593Smuzhiyun if (!atomic_add_unless(&ghes_in_nmi, 1, 1))
1164*4882a593Smuzhiyun return ret;
1165*4882a593Smuzhiyun
1166*4882a593Smuzhiyun raw_spin_lock(&ghes_notify_lock_nmi);
1167*4882a593Smuzhiyun if (!ghes_in_nmi_spool_from_list(&ghes_nmi, FIX_APEI_GHES_NMI))
1168*4882a593Smuzhiyun ret = NMI_HANDLED;
1169*4882a593Smuzhiyun raw_spin_unlock(&ghes_notify_lock_nmi);
1170*4882a593Smuzhiyun
1171*4882a593Smuzhiyun atomic_dec(&ghes_in_nmi);
1172*4882a593Smuzhiyun return ret;
1173*4882a593Smuzhiyun }
1174*4882a593Smuzhiyun
ghes_nmi_add(struct ghes * ghes)1175*4882a593Smuzhiyun static void ghes_nmi_add(struct ghes *ghes)
1176*4882a593Smuzhiyun {
1177*4882a593Smuzhiyun mutex_lock(&ghes_list_mutex);
1178*4882a593Smuzhiyun if (list_empty(&ghes_nmi))
1179*4882a593Smuzhiyun register_nmi_handler(NMI_LOCAL, ghes_notify_nmi, 0, "ghes");
1180*4882a593Smuzhiyun list_add_rcu(&ghes->list, &ghes_nmi);
1181*4882a593Smuzhiyun mutex_unlock(&ghes_list_mutex);
1182*4882a593Smuzhiyun }
1183*4882a593Smuzhiyun
ghes_nmi_remove(struct ghes * ghes)1184*4882a593Smuzhiyun static void ghes_nmi_remove(struct ghes *ghes)
1185*4882a593Smuzhiyun {
1186*4882a593Smuzhiyun mutex_lock(&ghes_list_mutex);
1187*4882a593Smuzhiyun list_del_rcu(&ghes->list);
1188*4882a593Smuzhiyun if (list_empty(&ghes_nmi))
1189*4882a593Smuzhiyun unregister_nmi_handler(NMI_LOCAL, "ghes");
1190*4882a593Smuzhiyun mutex_unlock(&ghes_list_mutex);
1191*4882a593Smuzhiyun /*
1192*4882a593Smuzhiyun * To synchronize with NMI handler, ghes can only be
1193*4882a593Smuzhiyun * freed after NMI handler finishes.
1194*4882a593Smuzhiyun */
1195*4882a593Smuzhiyun synchronize_rcu();
1196*4882a593Smuzhiyun }
1197*4882a593Smuzhiyun #else /* CONFIG_HAVE_ACPI_APEI_NMI */
ghes_nmi_add(struct ghes * ghes)1198*4882a593Smuzhiyun static inline void ghes_nmi_add(struct ghes *ghes) { }
ghes_nmi_remove(struct ghes * ghes)1199*4882a593Smuzhiyun static inline void ghes_nmi_remove(struct ghes *ghes) { }
1200*4882a593Smuzhiyun #endif /* CONFIG_HAVE_ACPI_APEI_NMI */
1201*4882a593Smuzhiyun
ghes_nmi_init_cxt(void)1202*4882a593Smuzhiyun static void ghes_nmi_init_cxt(void)
1203*4882a593Smuzhiyun {
1204*4882a593Smuzhiyun init_irq_work(&ghes_proc_irq_work, ghes_proc_in_irq);
1205*4882a593Smuzhiyun }
1206*4882a593Smuzhiyun
__ghes_sdei_callback(struct ghes * ghes,enum fixed_addresses fixmap_idx)1207*4882a593Smuzhiyun static int __ghes_sdei_callback(struct ghes *ghes,
1208*4882a593Smuzhiyun enum fixed_addresses fixmap_idx)
1209*4882a593Smuzhiyun {
1210*4882a593Smuzhiyun if (!ghes_in_nmi_queue_one_entry(ghes, fixmap_idx)) {
1211*4882a593Smuzhiyun irq_work_queue(&ghes_proc_irq_work);
1212*4882a593Smuzhiyun
1213*4882a593Smuzhiyun return 0;
1214*4882a593Smuzhiyun }
1215*4882a593Smuzhiyun
1216*4882a593Smuzhiyun return -ENOENT;
1217*4882a593Smuzhiyun }
1218*4882a593Smuzhiyun
ghes_sdei_normal_callback(u32 event_num,struct pt_regs * regs,void * arg)1219*4882a593Smuzhiyun static int ghes_sdei_normal_callback(u32 event_num, struct pt_regs *regs,
1220*4882a593Smuzhiyun void *arg)
1221*4882a593Smuzhiyun {
1222*4882a593Smuzhiyun static DEFINE_RAW_SPINLOCK(ghes_notify_lock_sdei_normal);
1223*4882a593Smuzhiyun struct ghes *ghes = arg;
1224*4882a593Smuzhiyun int err;
1225*4882a593Smuzhiyun
1226*4882a593Smuzhiyun raw_spin_lock(&ghes_notify_lock_sdei_normal);
1227*4882a593Smuzhiyun err = __ghes_sdei_callback(ghes, FIX_APEI_GHES_SDEI_NORMAL);
1228*4882a593Smuzhiyun raw_spin_unlock(&ghes_notify_lock_sdei_normal);
1229*4882a593Smuzhiyun
1230*4882a593Smuzhiyun return err;
1231*4882a593Smuzhiyun }
1232*4882a593Smuzhiyun
ghes_sdei_critical_callback(u32 event_num,struct pt_regs * regs,void * arg)1233*4882a593Smuzhiyun static int ghes_sdei_critical_callback(u32 event_num, struct pt_regs *regs,
1234*4882a593Smuzhiyun void *arg)
1235*4882a593Smuzhiyun {
1236*4882a593Smuzhiyun static DEFINE_RAW_SPINLOCK(ghes_notify_lock_sdei_critical);
1237*4882a593Smuzhiyun struct ghes *ghes = arg;
1238*4882a593Smuzhiyun int err;
1239*4882a593Smuzhiyun
1240*4882a593Smuzhiyun raw_spin_lock(&ghes_notify_lock_sdei_critical);
1241*4882a593Smuzhiyun err = __ghes_sdei_callback(ghes, FIX_APEI_GHES_SDEI_CRITICAL);
1242*4882a593Smuzhiyun raw_spin_unlock(&ghes_notify_lock_sdei_critical);
1243*4882a593Smuzhiyun
1244*4882a593Smuzhiyun return err;
1245*4882a593Smuzhiyun }
1246*4882a593Smuzhiyun
apei_sdei_register_ghes(struct ghes * ghes)1247*4882a593Smuzhiyun static int apei_sdei_register_ghes(struct ghes *ghes)
1248*4882a593Smuzhiyun {
1249*4882a593Smuzhiyun if (!IS_ENABLED(CONFIG_ARM_SDE_INTERFACE))
1250*4882a593Smuzhiyun return -EOPNOTSUPP;
1251*4882a593Smuzhiyun
1252*4882a593Smuzhiyun return sdei_register_ghes(ghes, ghes_sdei_normal_callback,
1253*4882a593Smuzhiyun ghes_sdei_critical_callback);
1254*4882a593Smuzhiyun }
1255*4882a593Smuzhiyun
apei_sdei_unregister_ghes(struct ghes * ghes)1256*4882a593Smuzhiyun static int apei_sdei_unregister_ghes(struct ghes *ghes)
1257*4882a593Smuzhiyun {
1258*4882a593Smuzhiyun if (!IS_ENABLED(CONFIG_ARM_SDE_INTERFACE))
1259*4882a593Smuzhiyun return -EOPNOTSUPP;
1260*4882a593Smuzhiyun
1261*4882a593Smuzhiyun return sdei_unregister_ghes(ghes);
1262*4882a593Smuzhiyun }
1263*4882a593Smuzhiyun
ghes_probe(struct platform_device * ghes_dev)1264*4882a593Smuzhiyun static int ghes_probe(struct platform_device *ghes_dev)
1265*4882a593Smuzhiyun {
1266*4882a593Smuzhiyun struct acpi_hest_generic *generic;
1267*4882a593Smuzhiyun struct ghes *ghes = NULL;
1268*4882a593Smuzhiyun unsigned long flags;
1269*4882a593Smuzhiyun
1270*4882a593Smuzhiyun int rc = -EINVAL;
1271*4882a593Smuzhiyun
1272*4882a593Smuzhiyun generic = *(struct acpi_hest_generic **)ghes_dev->dev.platform_data;
1273*4882a593Smuzhiyun if (!generic->enabled)
1274*4882a593Smuzhiyun return -ENODEV;
1275*4882a593Smuzhiyun
1276*4882a593Smuzhiyun switch (generic->notify.type) {
1277*4882a593Smuzhiyun case ACPI_HEST_NOTIFY_POLLED:
1278*4882a593Smuzhiyun case ACPI_HEST_NOTIFY_EXTERNAL:
1279*4882a593Smuzhiyun case ACPI_HEST_NOTIFY_SCI:
1280*4882a593Smuzhiyun case ACPI_HEST_NOTIFY_GSIV:
1281*4882a593Smuzhiyun case ACPI_HEST_NOTIFY_GPIO:
1282*4882a593Smuzhiyun break;
1283*4882a593Smuzhiyun
1284*4882a593Smuzhiyun case ACPI_HEST_NOTIFY_SEA:
1285*4882a593Smuzhiyun if (!IS_ENABLED(CONFIG_ACPI_APEI_SEA)) {
1286*4882a593Smuzhiyun pr_warn(GHES_PFX "Generic hardware error source: %d notified via SEA is not supported\n",
1287*4882a593Smuzhiyun generic->header.source_id);
1288*4882a593Smuzhiyun rc = -ENOTSUPP;
1289*4882a593Smuzhiyun goto err;
1290*4882a593Smuzhiyun }
1291*4882a593Smuzhiyun break;
1292*4882a593Smuzhiyun case ACPI_HEST_NOTIFY_NMI:
1293*4882a593Smuzhiyun if (!IS_ENABLED(CONFIG_HAVE_ACPI_APEI_NMI)) {
1294*4882a593Smuzhiyun pr_warn(GHES_PFX "Generic hardware error source: %d notified via NMI interrupt is not supported!\n",
1295*4882a593Smuzhiyun generic->header.source_id);
1296*4882a593Smuzhiyun goto err;
1297*4882a593Smuzhiyun }
1298*4882a593Smuzhiyun break;
1299*4882a593Smuzhiyun case ACPI_HEST_NOTIFY_SOFTWARE_DELEGATED:
1300*4882a593Smuzhiyun if (!IS_ENABLED(CONFIG_ARM_SDE_INTERFACE)) {
1301*4882a593Smuzhiyun pr_warn(GHES_PFX "Generic hardware error source: %d notified via SDE Interface is not supported!\n",
1302*4882a593Smuzhiyun generic->header.source_id);
1303*4882a593Smuzhiyun goto err;
1304*4882a593Smuzhiyun }
1305*4882a593Smuzhiyun break;
1306*4882a593Smuzhiyun case ACPI_HEST_NOTIFY_LOCAL:
1307*4882a593Smuzhiyun pr_warn(GHES_PFX "Generic hardware error source: %d notified via local interrupt is not supported!\n",
1308*4882a593Smuzhiyun generic->header.source_id);
1309*4882a593Smuzhiyun goto err;
1310*4882a593Smuzhiyun default:
1311*4882a593Smuzhiyun pr_warn(FW_WARN GHES_PFX "Unknown notification type: %u for generic hardware error source: %d\n",
1312*4882a593Smuzhiyun generic->notify.type, generic->header.source_id);
1313*4882a593Smuzhiyun goto err;
1314*4882a593Smuzhiyun }
1315*4882a593Smuzhiyun
1316*4882a593Smuzhiyun rc = -EIO;
1317*4882a593Smuzhiyun if (generic->error_block_length <
1318*4882a593Smuzhiyun sizeof(struct acpi_hest_generic_status)) {
1319*4882a593Smuzhiyun pr_warn(FW_BUG GHES_PFX "Invalid error block length: %u for generic hardware error source: %d\n",
1320*4882a593Smuzhiyun generic->error_block_length, generic->header.source_id);
1321*4882a593Smuzhiyun goto err;
1322*4882a593Smuzhiyun }
1323*4882a593Smuzhiyun ghes = ghes_new(generic);
1324*4882a593Smuzhiyun if (IS_ERR(ghes)) {
1325*4882a593Smuzhiyun rc = PTR_ERR(ghes);
1326*4882a593Smuzhiyun ghes = NULL;
1327*4882a593Smuzhiyun goto err;
1328*4882a593Smuzhiyun }
1329*4882a593Smuzhiyun
1330*4882a593Smuzhiyun switch (generic->notify.type) {
1331*4882a593Smuzhiyun case ACPI_HEST_NOTIFY_POLLED:
1332*4882a593Smuzhiyun timer_setup(&ghes->timer, ghes_poll_func, 0);
1333*4882a593Smuzhiyun ghes_add_timer(ghes);
1334*4882a593Smuzhiyun break;
1335*4882a593Smuzhiyun case ACPI_HEST_NOTIFY_EXTERNAL:
1336*4882a593Smuzhiyun /* External interrupt vector is GSI */
1337*4882a593Smuzhiyun rc = acpi_gsi_to_irq(generic->notify.vector, &ghes->irq);
1338*4882a593Smuzhiyun if (rc) {
1339*4882a593Smuzhiyun pr_err(GHES_PFX "Failed to map GSI to IRQ for generic hardware error source: %d\n",
1340*4882a593Smuzhiyun generic->header.source_id);
1341*4882a593Smuzhiyun goto err;
1342*4882a593Smuzhiyun }
1343*4882a593Smuzhiyun rc = request_irq(ghes->irq, ghes_irq_func, IRQF_SHARED,
1344*4882a593Smuzhiyun "GHES IRQ", ghes);
1345*4882a593Smuzhiyun if (rc) {
1346*4882a593Smuzhiyun pr_err(GHES_PFX "Failed to register IRQ for generic hardware error source: %d\n",
1347*4882a593Smuzhiyun generic->header.source_id);
1348*4882a593Smuzhiyun goto err;
1349*4882a593Smuzhiyun }
1350*4882a593Smuzhiyun break;
1351*4882a593Smuzhiyun
1352*4882a593Smuzhiyun case ACPI_HEST_NOTIFY_SCI:
1353*4882a593Smuzhiyun case ACPI_HEST_NOTIFY_GSIV:
1354*4882a593Smuzhiyun case ACPI_HEST_NOTIFY_GPIO:
1355*4882a593Smuzhiyun mutex_lock(&ghes_list_mutex);
1356*4882a593Smuzhiyun if (list_empty(&ghes_hed))
1357*4882a593Smuzhiyun register_acpi_hed_notifier(&ghes_notifier_hed);
1358*4882a593Smuzhiyun list_add_rcu(&ghes->list, &ghes_hed);
1359*4882a593Smuzhiyun mutex_unlock(&ghes_list_mutex);
1360*4882a593Smuzhiyun break;
1361*4882a593Smuzhiyun
1362*4882a593Smuzhiyun case ACPI_HEST_NOTIFY_SEA:
1363*4882a593Smuzhiyun ghes_sea_add(ghes);
1364*4882a593Smuzhiyun break;
1365*4882a593Smuzhiyun case ACPI_HEST_NOTIFY_NMI:
1366*4882a593Smuzhiyun ghes_nmi_add(ghes);
1367*4882a593Smuzhiyun break;
1368*4882a593Smuzhiyun case ACPI_HEST_NOTIFY_SOFTWARE_DELEGATED:
1369*4882a593Smuzhiyun rc = apei_sdei_register_ghes(ghes);
1370*4882a593Smuzhiyun if (rc)
1371*4882a593Smuzhiyun goto err;
1372*4882a593Smuzhiyun break;
1373*4882a593Smuzhiyun default:
1374*4882a593Smuzhiyun BUG();
1375*4882a593Smuzhiyun }
1376*4882a593Smuzhiyun
1377*4882a593Smuzhiyun platform_set_drvdata(ghes_dev, ghes);
1378*4882a593Smuzhiyun
1379*4882a593Smuzhiyun ghes_edac_register(ghes, &ghes_dev->dev);
1380*4882a593Smuzhiyun
1381*4882a593Smuzhiyun /* Handle any pending errors right away */
1382*4882a593Smuzhiyun spin_lock_irqsave(&ghes_notify_lock_irq, flags);
1383*4882a593Smuzhiyun ghes_proc(ghes);
1384*4882a593Smuzhiyun spin_unlock_irqrestore(&ghes_notify_lock_irq, flags);
1385*4882a593Smuzhiyun
1386*4882a593Smuzhiyun return 0;
1387*4882a593Smuzhiyun
1388*4882a593Smuzhiyun err:
1389*4882a593Smuzhiyun if (ghes) {
1390*4882a593Smuzhiyun ghes_fini(ghes);
1391*4882a593Smuzhiyun kfree(ghes);
1392*4882a593Smuzhiyun }
1393*4882a593Smuzhiyun return rc;
1394*4882a593Smuzhiyun }
1395*4882a593Smuzhiyun
ghes_remove(struct platform_device * ghes_dev)1396*4882a593Smuzhiyun static int ghes_remove(struct platform_device *ghes_dev)
1397*4882a593Smuzhiyun {
1398*4882a593Smuzhiyun int rc;
1399*4882a593Smuzhiyun struct ghes *ghes;
1400*4882a593Smuzhiyun struct acpi_hest_generic *generic;
1401*4882a593Smuzhiyun
1402*4882a593Smuzhiyun ghes = platform_get_drvdata(ghes_dev);
1403*4882a593Smuzhiyun generic = ghes->generic;
1404*4882a593Smuzhiyun
1405*4882a593Smuzhiyun ghes->flags |= GHES_EXITING;
1406*4882a593Smuzhiyun switch (generic->notify.type) {
1407*4882a593Smuzhiyun case ACPI_HEST_NOTIFY_POLLED:
1408*4882a593Smuzhiyun del_timer_sync(&ghes->timer);
1409*4882a593Smuzhiyun break;
1410*4882a593Smuzhiyun case ACPI_HEST_NOTIFY_EXTERNAL:
1411*4882a593Smuzhiyun free_irq(ghes->irq, ghes);
1412*4882a593Smuzhiyun break;
1413*4882a593Smuzhiyun
1414*4882a593Smuzhiyun case ACPI_HEST_NOTIFY_SCI:
1415*4882a593Smuzhiyun case ACPI_HEST_NOTIFY_GSIV:
1416*4882a593Smuzhiyun case ACPI_HEST_NOTIFY_GPIO:
1417*4882a593Smuzhiyun mutex_lock(&ghes_list_mutex);
1418*4882a593Smuzhiyun list_del_rcu(&ghes->list);
1419*4882a593Smuzhiyun if (list_empty(&ghes_hed))
1420*4882a593Smuzhiyun unregister_acpi_hed_notifier(&ghes_notifier_hed);
1421*4882a593Smuzhiyun mutex_unlock(&ghes_list_mutex);
1422*4882a593Smuzhiyun synchronize_rcu();
1423*4882a593Smuzhiyun break;
1424*4882a593Smuzhiyun
1425*4882a593Smuzhiyun case ACPI_HEST_NOTIFY_SEA:
1426*4882a593Smuzhiyun ghes_sea_remove(ghes);
1427*4882a593Smuzhiyun break;
1428*4882a593Smuzhiyun case ACPI_HEST_NOTIFY_NMI:
1429*4882a593Smuzhiyun ghes_nmi_remove(ghes);
1430*4882a593Smuzhiyun break;
1431*4882a593Smuzhiyun case ACPI_HEST_NOTIFY_SOFTWARE_DELEGATED:
1432*4882a593Smuzhiyun rc = apei_sdei_unregister_ghes(ghes);
1433*4882a593Smuzhiyun if (rc)
1434*4882a593Smuzhiyun return rc;
1435*4882a593Smuzhiyun break;
1436*4882a593Smuzhiyun default:
1437*4882a593Smuzhiyun BUG();
1438*4882a593Smuzhiyun break;
1439*4882a593Smuzhiyun }
1440*4882a593Smuzhiyun
1441*4882a593Smuzhiyun ghes_fini(ghes);
1442*4882a593Smuzhiyun
1443*4882a593Smuzhiyun ghes_edac_unregister(ghes);
1444*4882a593Smuzhiyun
1445*4882a593Smuzhiyun kfree(ghes);
1446*4882a593Smuzhiyun
1447*4882a593Smuzhiyun platform_set_drvdata(ghes_dev, NULL);
1448*4882a593Smuzhiyun
1449*4882a593Smuzhiyun return 0;
1450*4882a593Smuzhiyun }
1451*4882a593Smuzhiyun
1452*4882a593Smuzhiyun static struct platform_driver ghes_platform_driver = {
1453*4882a593Smuzhiyun .driver = {
1454*4882a593Smuzhiyun .name = "GHES",
1455*4882a593Smuzhiyun },
1456*4882a593Smuzhiyun .probe = ghes_probe,
1457*4882a593Smuzhiyun .remove = ghes_remove,
1458*4882a593Smuzhiyun };
1459*4882a593Smuzhiyun
ghes_init(void)1460*4882a593Smuzhiyun static int __init ghes_init(void)
1461*4882a593Smuzhiyun {
1462*4882a593Smuzhiyun int rc;
1463*4882a593Smuzhiyun
1464*4882a593Smuzhiyun if (acpi_disabled)
1465*4882a593Smuzhiyun return -ENODEV;
1466*4882a593Smuzhiyun
1467*4882a593Smuzhiyun switch (hest_disable) {
1468*4882a593Smuzhiyun case HEST_NOT_FOUND:
1469*4882a593Smuzhiyun return -ENODEV;
1470*4882a593Smuzhiyun case HEST_DISABLED:
1471*4882a593Smuzhiyun pr_info(GHES_PFX "HEST is not enabled!\n");
1472*4882a593Smuzhiyun return -EINVAL;
1473*4882a593Smuzhiyun default:
1474*4882a593Smuzhiyun break;
1475*4882a593Smuzhiyun }
1476*4882a593Smuzhiyun
1477*4882a593Smuzhiyun if (ghes_disable) {
1478*4882a593Smuzhiyun pr_info(GHES_PFX "GHES is not enabled!\n");
1479*4882a593Smuzhiyun return -EINVAL;
1480*4882a593Smuzhiyun }
1481*4882a593Smuzhiyun
1482*4882a593Smuzhiyun ghes_nmi_init_cxt();
1483*4882a593Smuzhiyun
1484*4882a593Smuzhiyun rc = platform_driver_register(&ghes_platform_driver);
1485*4882a593Smuzhiyun if (rc)
1486*4882a593Smuzhiyun goto err;
1487*4882a593Smuzhiyun
1488*4882a593Smuzhiyun rc = apei_osc_setup();
1489*4882a593Smuzhiyun if (rc == 0 && osc_sb_apei_support_acked)
1490*4882a593Smuzhiyun pr_info(GHES_PFX "APEI firmware first mode is enabled by APEI bit and WHEA _OSC.\n");
1491*4882a593Smuzhiyun else if (rc == 0 && !osc_sb_apei_support_acked)
1492*4882a593Smuzhiyun pr_info(GHES_PFX "APEI firmware first mode is enabled by WHEA _OSC.\n");
1493*4882a593Smuzhiyun else if (rc && osc_sb_apei_support_acked)
1494*4882a593Smuzhiyun pr_info(GHES_PFX "APEI firmware first mode is enabled by APEI bit.\n");
1495*4882a593Smuzhiyun else
1496*4882a593Smuzhiyun pr_info(GHES_PFX "Failed to enable APEI firmware first mode.\n");
1497*4882a593Smuzhiyun
1498*4882a593Smuzhiyun return 0;
1499*4882a593Smuzhiyun err:
1500*4882a593Smuzhiyun return rc;
1501*4882a593Smuzhiyun }
1502*4882a593Smuzhiyun device_initcall(ghes_init);
1503