aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/acpi/apei
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/acpi/apei')
-rw-r--r--drivers/acpi/apei/Kconfig9
-rw-r--r--drivers/acpi/apei/apei-internal.h2
-rw-r--r--drivers/acpi/apei/cper.c321
-rw-r--r--drivers/acpi/apei/einj.c10
-rw-r--r--drivers/acpi/apei/erst-dbg.c25
-rw-r--r--drivers/acpi/apei/erst.c424
-rw-r--r--drivers/acpi/apei/ghes.c433
-rw-r--r--drivers/acpi/apei/hest.c48
8 files changed, 1102 insertions, 170 deletions
diff --git a/drivers/acpi/apei/Kconfig b/drivers/acpi/apei/Kconfig
index fca34ccfd294..f739a70b1c70 100644
--- a/drivers/acpi/apei/Kconfig
+++ b/drivers/acpi/apei/Kconfig
@@ -1,5 +1,7 @@
1config ACPI_APEI 1config ACPI_APEI
2 bool "ACPI Platform Error Interface (APEI)" 2 bool "ACPI Platform Error Interface (APEI)"
3 select MISC_FILESYSTEMS
4 select PSTORE
3 depends on X86 5 depends on X86
4 help 6 help
5 APEI allows to report errors (for example from the chipset) 7 APEI allows to report errors (for example from the chipset)
@@ -21,6 +23,13 @@ config ACPI_APEI_GHES
21 by firmware to produce more valuable hardware error 23 by firmware to produce more valuable hardware error
22 information for Linux. 24 information for Linux.
23 25
26config ACPI_APEI_PCIEAER
27 bool "APEI PCIe AER logging/recovering support"
28 depends on ACPI_APEI && PCIEAER
29 help
30 PCIe AER errors may be reported via APEI firmware first mode.
31 Turn on this option to enable the corresponding support.
32
24config ACPI_APEI_EINJ 33config ACPI_APEI_EINJ
25 tristate "APEI Error INJection (EINJ)" 34 tristate "APEI Error INJection (EINJ)"
26 depends on ACPI_APEI && DEBUG_FS 35 depends on ACPI_APEI && DEBUG_FS
diff --git a/drivers/acpi/apei/apei-internal.h b/drivers/acpi/apei/apei-internal.h
index 18df1e940276..ef0581f2094d 100644
--- a/drivers/acpi/apei/apei-internal.h
+++ b/drivers/acpi/apei/apei-internal.h
@@ -109,6 +109,8 @@ static inline u32 apei_estatus_len(struct acpi_hest_generic_status *estatus)
109 return sizeof(*estatus) + estatus->data_length; 109 return sizeof(*estatus) + estatus->data_length;
110} 110}
111 111
112void apei_estatus_print(const char *pfx,
113 const struct acpi_hest_generic_status *estatus);
112int apei_estatus_check_header(const struct acpi_hest_generic_status *estatus); 114int apei_estatus_check_header(const struct acpi_hest_generic_status *estatus);
113int apei_estatus_check(const struct acpi_hest_generic_status *estatus); 115int apei_estatus_check(const struct acpi_hest_generic_status *estatus);
114#endif 116#endif
diff --git a/drivers/acpi/apei/cper.c b/drivers/acpi/apei/cper.c
index f4cf2fc4c8c1..5d4189464d63 100644
--- a/drivers/acpi/apei/cper.c
+++ b/drivers/acpi/apei/cper.c
@@ -29,6 +29,7 @@
29#include <linux/time.h> 29#include <linux/time.h>
30#include <linux/cper.h> 30#include <linux/cper.h>
31#include <linux/acpi.h> 31#include <linux/acpi.h>
32#include <linux/aer.h>
32 33
33/* 34/*
34 * CPER record ID need to be unique even after reboot, because record 35 * CPER record ID need to be unique even after reboot, because record
@@ -46,6 +47,326 @@ u64 cper_next_record_id(void)
46} 47}
47EXPORT_SYMBOL_GPL(cper_next_record_id); 48EXPORT_SYMBOL_GPL(cper_next_record_id);
48 49
50static const char *cper_severity_strs[] = {
51 "recoverable",
52 "fatal",
53 "corrected",
54 "info",
55};
56
57static const char *cper_severity_str(unsigned int severity)
58{
59 return severity < ARRAY_SIZE(cper_severity_strs) ?
60 cper_severity_strs[severity] : "unknown";
61}
62
63/*
64 * cper_print_bits - print strings for set bits
65 * @pfx: prefix for each line, including log level and prefix string
66 * @bits: bit mask
67 * @strs: string array, indexed by bit position
68 * @strs_size: size of the string array: @strs
69 *
70 * For each set bit in @bits, print the corresponding string in @strs.
71 * If the output length is longer than 80, multiple line will be
72 * printed, with @pfx is printed at the beginning of each line.
73 */
74void cper_print_bits(const char *pfx, unsigned int bits,
75 const char *strs[], unsigned int strs_size)
76{
77 int i, len = 0;
78 const char *str;
79 char buf[84];
80
81 for (i = 0; i < strs_size; i++) {
82 if (!(bits & (1U << i)))
83 continue;
84 str = strs[i];
85 if (!str)
86 continue;
87 if (len && len + strlen(str) + 2 > 80) {
88 printk("%s\n", buf);
89 len = 0;
90 }
91 if (!len)
92 len = snprintf(buf, sizeof(buf), "%s%s", pfx, str);
93 else
94 len += snprintf(buf+len, sizeof(buf)-len, ", %s", str);
95 }
96 if (len)
97 printk("%s\n", buf);
98}
99
100static const char *cper_proc_type_strs[] = {
101 "IA32/X64",
102 "IA64",
103};
104
105static const char *cper_proc_isa_strs[] = {
106 "IA32",
107 "IA64",
108 "X64",
109};
110
111static const char *cper_proc_error_type_strs[] = {
112 "cache error",
113 "TLB error",
114 "bus error",
115 "micro-architectural error",
116};
117
118static const char *cper_proc_op_strs[] = {
119 "unknown or generic",
120 "data read",
121 "data write",
122 "instruction execution",
123};
124
125static const char *cper_proc_flag_strs[] = {
126 "restartable",
127 "precise IP",
128 "overflow",
129 "corrected",
130};
131
132static void cper_print_proc_generic(const char *pfx,
133 const struct cper_sec_proc_generic *proc)
134{
135 if (proc->validation_bits & CPER_PROC_VALID_TYPE)
136 printk("%s""processor_type: %d, %s\n", pfx, proc->proc_type,
137 proc->proc_type < ARRAY_SIZE(cper_proc_type_strs) ?
138 cper_proc_type_strs[proc->proc_type] : "unknown");
139 if (proc->validation_bits & CPER_PROC_VALID_ISA)
140 printk("%s""processor_isa: %d, %s\n", pfx, proc->proc_isa,
141 proc->proc_isa < ARRAY_SIZE(cper_proc_isa_strs) ?
142 cper_proc_isa_strs[proc->proc_isa] : "unknown");
143 if (proc->validation_bits & CPER_PROC_VALID_ERROR_TYPE) {
144 printk("%s""error_type: 0x%02x\n", pfx, proc->proc_error_type);
145 cper_print_bits(pfx, proc->proc_error_type,
146 cper_proc_error_type_strs,
147 ARRAY_SIZE(cper_proc_error_type_strs));
148 }
149 if (proc->validation_bits & CPER_PROC_VALID_OPERATION)
150 printk("%s""operation: %d, %s\n", pfx, proc->operation,
151 proc->operation < ARRAY_SIZE(cper_proc_op_strs) ?
152 cper_proc_op_strs[proc->operation] : "unknown");
153 if (proc->validation_bits & CPER_PROC_VALID_FLAGS) {
154 printk("%s""flags: 0x%02x\n", pfx, proc->flags);
155 cper_print_bits(pfx, proc->flags, cper_proc_flag_strs,
156 ARRAY_SIZE(cper_proc_flag_strs));
157 }
158 if (proc->validation_bits & CPER_PROC_VALID_LEVEL)
159 printk("%s""level: %d\n", pfx, proc->level);
160 if (proc->validation_bits & CPER_PROC_VALID_VERSION)
161 printk("%s""version_info: 0x%016llx\n", pfx, proc->cpu_version);
162 if (proc->validation_bits & CPER_PROC_VALID_ID)
163 printk("%s""processor_id: 0x%016llx\n", pfx, proc->proc_id);
164 if (proc->validation_bits & CPER_PROC_VALID_TARGET_ADDRESS)
165 printk("%s""target_address: 0x%016llx\n",
166 pfx, proc->target_addr);
167 if (proc->validation_bits & CPER_PROC_VALID_REQUESTOR_ID)
168 printk("%s""requestor_id: 0x%016llx\n",
169 pfx, proc->requestor_id);
170 if (proc->validation_bits & CPER_PROC_VALID_RESPONDER_ID)
171 printk("%s""responder_id: 0x%016llx\n",
172 pfx, proc->responder_id);
173 if (proc->validation_bits & CPER_PROC_VALID_IP)
174 printk("%s""IP: 0x%016llx\n", pfx, proc->ip);
175}
176
177static const char *cper_mem_err_type_strs[] = {
178 "unknown",
179 "no error",
180 "single-bit ECC",
181 "multi-bit ECC",
182 "single-symbol chipkill ECC",
183 "multi-symbol chipkill ECC",
184 "master abort",
185 "target abort",
186 "parity error",
187 "watchdog timeout",
188 "invalid address",
189 "mirror Broken",
190 "memory sparing",
191 "scrub corrected error",
192 "scrub uncorrected error",
193};
194
195static void cper_print_mem(const char *pfx, const struct cper_sec_mem_err *mem)
196{
197 if (mem->validation_bits & CPER_MEM_VALID_ERROR_STATUS)
198 printk("%s""error_status: 0x%016llx\n", pfx, mem->error_status);
199 if (mem->validation_bits & CPER_MEM_VALID_PHYSICAL_ADDRESS)
200 printk("%s""physical_address: 0x%016llx\n",
201 pfx, mem->physical_addr);
202 if (mem->validation_bits & CPER_MEM_VALID_PHYSICAL_ADDRESS_MASK)
203 printk("%s""physical_address_mask: 0x%016llx\n",
204 pfx, mem->physical_addr_mask);
205 if (mem->validation_bits & CPER_MEM_VALID_NODE)
206 printk("%s""node: %d\n", pfx, mem->node);
207 if (mem->validation_bits & CPER_MEM_VALID_CARD)
208 printk("%s""card: %d\n", pfx, mem->card);
209 if (mem->validation_bits & CPER_MEM_VALID_MODULE)
210 printk("%s""module: %d\n", pfx, mem->module);
211 if (mem->validation_bits & CPER_MEM_VALID_BANK)
212 printk("%s""bank: %d\n", pfx, mem->bank);
213 if (mem->validation_bits & CPER_MEM_VALID_DEVICE)
214 printk("%s""device: %d\n", pfx, mem->device);
215 if (mem->validation_bits & CPER_MEM_VALID_ROW)
216 printk("%s""row: %d\n", pfx, mem->row);
217 if (mem->validation_bits & CPER_MEM_VALID_COLUMN)
218 printk("%s""column: %d\n", pfx, mem->column);
219 if (mem->validation_bits & CPER_MEM_VALID_BIT_POSITION)
220 printk("%s""bit_position: %d\n", pfx, mem->bit_pos);
221 if (mem->validation_bits & CPER_MEM_VALID_REQUESTOR_ID)
222 printk("%s""requestor_id: 0x%016llx\n", pfx, mem->requestor_id);
223 if (mem->validation_bits & CPER_MEM_VALID_RESPONDER_ID)
224 printk("%s""responder_id: 0x%016llx\n", pfx, mem->responder_id);
225 if (mem->validation_bits & CPER_MEM_VALID_TARGET_ID)
226 printk("%s""target_id: 0x%016llx\n", pfx, mem->target_id);
227 if (mem->validation_bits & CPER_MEM_VALID_ERROR_TYPE) {
228 u8 etype = mem->error_type;
229 printk("%s""error_type: %d, %s\n", pfx, etype,
230 etype < ARRAY_SIZE(cper_mem_err_type_strs) ?
231 cper_mem_err_type_strs[etype] : "unknown");
232 }
233}
234
235static const char *cper_pcie_port_type_strs[] = {
236 "PCIe end point",
237 "legacy PCI end point",
238 "unknown",
239 "unknown",
240 "root port",
241 "upstream switch port",
242 "downstream switch port",
243 "PCIe to PCI/PCI-X bridge",
244 "PCI/PCI-X to PCIe bridge",
245 "root complex integrated endpoint device",
246 "root complex event collector",
247};
248
249static void cper_print_pcie(const char *pfx, const struct cper_sec_pcie *pcie,
250 const struct acpi_hest_generic_data *gdata)
251{
252 if (pcie->validation_bits & CPER_PCIE_VALID_PORT_TYPE)
253 printk("%s""port_type: %d, %s\n", pfx, pcie->port_type,
254 pcie->port_type < ARRAY_SIZE(cper_pcie_port_type_strs) ?
255 cper_pcie_port_type_strs[pcie->port_type] : "unknown");
256 if (pcie->validation_bits & CPER_PCIE_VALID_VERSION)
257 printk("%s""version: %d.%d\n", pfx,
258 pcie->version.major, pcie->version.minor);
259 if (pcie->validation_bits & CPER_PCIE_VALID_COMMAND_STATUS)
260 printk("%s""command: 0x%04x, status: 0x%04x\n", pfx,
261 pcie->command, pcie->status);
262 if (pcie->validation_bits & CPER_PCIE_VALID_DEVICE_ID) {
263 const __u8 *p;
264 printk("%s""device_id: %04x:%02x:%02x.%x\n", pfx,
265 pcie->device_id.segment, pcie->device_id.bus,
266 pcie->device_id.device, pcie->device_id.function);
267 printk("%s""slot: %d\n", pfx,
268 pcie->device_id.slot >> CPER_PCIE_SLOT_SHIFT);
269 printk("%s""secondary_bus: 0x%02x\n", pfx,
270 pcie->device_id.secondary_bus);
271 printk("%s""vendor_id: 0x%04x, device_id: 0x%04x\n", pfx,
272 pcie->device_id.vendor_id, pcie->device_id.device_id);
273 p = pcie->device_id.class_code;
274 printk("%s""class_code: %02x%02x%02x\n", pfx, p[0], p[1], p[2]);
275 }
276 if (pcie->validation_bits & CPER_PCIE_VALID_SERIAL_NUMBER)
277 printk("%s""serial number: 0x%04x, 0x%04x\n", pfx,
278 pcie->serial_number.lower, pcie->serial_number.upper);
279 if (pcie->validation_bits & CPER_PCIE_VALID_BRIDGE_CONTROL_STATUS)
280 printk(
281 "%s""bridge: secondary_status: 0x%04x, control: 0x%04x\n",
282 pfx, pcie->bridge.secondary_status, pcie->bridge.control);
283#ifdef CONFIG_ACPI_APEI_PCIEAER
284 if (pcie->validation_bits & CPER_PCIE_VALID_AER_INFO) {
285 struct aer_capability_regs *aer_regs = (void *)pcie->aer_info;
286 cper_print_aer(pfx, gdata->error_severity, aer_regs);
287 }
288#endif
289}
290
291static const char *apei_estatus_section_flag_strs[] = {
292 "primary",
293 "containment warning",
294 "reset",
295 "threshold exceeded",
296 "resource not accessible",
297 "latent error",
298};
299
300static void apei_estatus_print_section(
301 const char *pfx, const struct acpi_hest_generic_data *gdata, int sec_no)
302{
303 uuid_le *sec_type = (uuid_le *)gdata->section_type;
304 __u16 severity;
305
306 severity = gdata->error_severity;
307 printk("%s""section: %d, severity: %d, %s\n", pfx, sec_no, severity,
308 cper_severity_str(severity));
309 printk("%s""flags: 0x%02x\n", pfx, gdata->flags);
310 cper_print_bits(pfx, gdata->flags, apei_estatus_section_flag_strs,
311 ARRAY_SIZE(apei_estatus_section_flag_strs));
312 if (gdata->validation_bits & CPER_SEC_VALID_FRU_ID)
313 printk("%s""fru_id: %pUl\n", pfx, (uuid_le *)gdata->fru_id);
314 if (gdata->validation_bits & CPER_SEC_VALID_FRU_TEXT)
315 printk("%s""fru_text: %.20s\n", pfx, gdata->fru_text);
316
317 if (!uuid_le_cmp(*sec_type, CPER_SEC_PROC_GENERIC)) {
318 struct cper_sec_proc_generic *proc_err = (void *)(gdata + 1);
319 printk("%s""section_type: general processor error\n", pfx);
320 if (gdata->error_data_length >= sizeof(*proc_err))
321 cper_print_proc_generic(pfx, proc_err);
322 else
323 goto err_section_too_small;
324 } else if (!uuid_le_cmp(*sec_type, CPER_SEC_PLATFORM_MEM)) {
325 struct cper_sec_mem_err *mem_err = (void *)(gdata + 1);
326 printk("%s""section_type: memory error\n", pfx);
327 if (gdata->error_data_length >= sizeof(*mem_err))
328 cper_print_mem(pfx, mem_err);
329 else
330 goto err_section_too_small;
331 } else if (!uuid_le_cmp(*sec_type, CPER_SEC_PCIE)) {
332 struct cper_sec_pcie *pcie = (void *)(gdata + 1);
333 printk("%s""section_type: PCIe error\n", pfx);
334 if (gdata->error_data_length >= sizeof(*pcie))
335 cper_print_pcie(pfx, pcie, gdata);
336 else
337 goto err_section_too_small;
338 } else
339 printk("%s""section type: unknown, %pUl\n", pfx, sec_type);
340
341 return;
342
343err_section_too_small:
344 pr_err(FW_WARN "error section length is too small\n");
345}
346
347void apei_estatus_print(const char *pfx,
348 const struct acpi_hest_generic_status *estatus)
349{
350 struct acpi_hest_generic_data *gdata;
351 unsigned int data_len, gedata_len;
352 int sec_no = 0;
353 __u16 severity;
354
355 printk("%s""APEI generic hardware error status\n", pfx);
356 severity = estatus->error_severity;
357 printk("%s""severity: %d, %s\n", pfx, severity,
358 cper_severity_str(severity));
359 data_len = estatus->data_length;
360 gdata = (struct acpi_hest_generic_data *)(estatus + 1);
361 while (data_len > sizeof(*gdata)) {
362 gedata_len = gdata->error_data_length;
363 apei_estatus_print_section(pfx, gdata, sec_no);
364 data_len -= gedata_len + sizeof(*gdata);
365 sec_no++;
366 }
367}
368EXPORT_SYMBOL_GPL(apei_estatus_print);
369
49int apei_estatus_check_header(const struct acpi_hest_generic_status *estatus) 370int apei_estatus_check_header(const struct acpi_hest_generic_status *estatus)
50{ 371{
51 if (estatus->data_length && 372 if (estatus->data_length &&
diff --git a/drivers/acpi/apei/einj.c b/drivers/acpi/apei/einj.c
index cf29df69380b..f74b2ea11f21 100644
--- a/drivers/acpi/apei/einj.c
+++ b/drivers/acpi/apei/einj.c
@@ -39,7 +39,7 @@
39#define EINJ_PFX "EINJ: " 39#define EINJ_PFX "EINJ: "
40 40
41#define SPIN_UNIT 100 /* 100ns */ 41#define SPIN_UNIT 100 /* 100ns */
42/* Firmware should respond within 1 miliseconds */ 42/* Firmware should respond within 1 milliseconds */
43#define FIRMWARE_TIMEOUT (1 * NSEC_PER_MSEC) 43#define FIRMWARE_TIMEOUT (1 * NSEC_PER_MSEC)
44 44
45/* 45/*
@@ -101,6 +101,14 @@ static DEFINE_MUTEX(einj_mutex);
101 101
102static struct einj_parameter *einj_param; 102static struct einj_parameter *einj_param;
103 103
104#ifndef writeq
105static inline void writeq(__u64 val, volatile void __iomem *addr)
106{
107 writel(val, addr);
108 writel(val >> 32, addr+4);
109}
110#endif
111
104static void einj_exec_ctx_init(struct apei_exec_context *ctx) 112static void einj_exec_ctx_init(struct apei_exec_context *ctx)
105{ 113{
106 apei_exec_ctx_init(ctx, einj_ins_type, ARRAY_SIZE(einj_ins_type), 114 apei_exec_ctx_init(ctx, einj_ins_type, ARRAY_SIZE(einj_ins_type),
diff --git a/drivers/acpi/apei/erst-dbg.c b/drivers/acpi/apei/erst-dbg.c
index da1228a9a544..a4cfb64c86a1 100644
--- a/drivers/acpi/apei/erst-dbg.c
+++ b/drivers/acpi/apei/erst-dbg.c
@@ -43,12 +43,27 @@ static DEFINE_MUTEX(erst_dbg_mutex);
43 43
44static int erst_dbg_open(struct inode *inode, struct file *file) 44static int erst_dbg_open(struct inode *inode, struct file *file)
45{ 45{
46 int rc, *pos;
47
46 if (erst_disable) 48 if (erst_disable)
47 return -ENODEV; 49 return -ENODEV;
48 50
51 pos = (int *)&file->private_data;
52
53 rc = erst_get_record_id_begin(pos);
54 if (rc)
55 return rc;
56
49 return nonseekable_open(inode, file); 57 return nonseekable_open(inode, file);
50} 58}
51 59
60static int erst_dbg_release(struct inode *inode, struct file *file)
61{
62 erst_get_record_id_end();
63
64 return 0;
65}
66
52static long erst_dbg_ioctl(struct file *f, unsigned int cmd, unsigned long arg) 67static long erst_dbg_ioctl(struct file *f, unsigned int cmd, unsigned long arg)
53{ 68{
54 int rc; 69 int rc;
@@ -79,18 +94,20 @@ static long erst_dbg_ioctl(struct file *f, unsigned int cmd, unsigned long arg)
79static ssize_t erst_dbg_read(struct file *filp, char __user *ubuf, 94static ssize_t erst_dbg_read(struct file *filp, char __user *ubuf,
80 size_t usize, loff_t *off) 95 size_t usize, loff_t *off)
81{ 96{
82 int rc; 97 int rc, *pos;
83 ssize_t len = 0; 98 ssize_t len = 0;
84 u64 id; 99 u64 id;
85 100
86 if (*off != 0) 101 if (*off)
87 return -EINVAL; 102 return -EINVAL;
88 103
89 if (mutex_lock_interruptible(&erst_dbg_mutex) != 0) 104 if (mutex_lock_interruptible(&erst_dbg_mutex) != 0)
90 return -EINTR; 105 return -EINTR;
91 106
107 pos = (int *)&filp->private_data;
108
92retry_next: 109retry_next:
93 rc = erst_get_next_record_id(&id); 110 rc = erst_get_record_id_next(pos, &id);
94 if (rc) 111 if (rc)
95 goto out; 112 goto out;
96 /* no more record */ 113 /* no more record */
@@ -181,9 +198,11 @@ out:
181static const struct file_operations erst_dbg_ops = { 198static const struct file_operations erst_dbg_ops = {
182 .owner = THIS_MODULE, 199 .owner = THIS_MODULE,
183 .open = erst_dbg_open, 200 .open = erst_dbg_open,
201 .release = erst_dbg_release,
184 .read = erst_dbg_read, 202 .read = erst_dbg_read,
185 .write = erst_dbg_write, 203 .write = erst_dbg_write,
186 .unlocked_ioctl = erst_dbg_ioctl, 204 .unlocked_ioctl = erst_dbg_ioctl,
205 .llseek = no_llseek,
187}; 206};
188 207
189static struct miscdevice erst_dbg_dev = { 208static struct miscdevice erst_dbg_dev = {
diff --git a/drivers/acpi/apei/erst.c b/drivers/acpi/apei/erst.c
index 1211c03149e8..e6cef8e1b534 100644
--- a/drivers/acpi/apei/erst.c
+++ b/drivers/acpi/apei/erst.c
@@ -34,6 +34,7 @@
34#include <linux/cper.h> 34#include <linux/cper.h>
35#include <linux/nmi.h> 35#include <linux/nmi.h>
36#include <linux/hardirq.h> 36#include <linux/hardirq.h>
37#include <linux/pstore.h>
37#include <acpi/apei.h> 38#include <acpi/apei.h>
38 39
39#include "apei-internal.h" 40#include "apei-internal.h"
@@ -53,7 +54,7 @@
53 sizeof(struct acpi_table_erst))) 54 sizeof(struct acpi_table_erst)))
54 55
55#define SPIN_UNIT 100 /* 100ns */ 56#define SPIN_UNIT 100 /* 100ns */
56/* Firmware should respond within 1 miliseconds */ 57/* Firmware should respond within 1 milliseconds */
57#define FIRMWARE_TIMEOUT (1 * NSEC_PER_MSEC) 58#define FIRMWARE_TIMEOUT (1 * NSEC_PER_MSEC)
58#define FIRMWARE_MAX_STALL 50 /* 50us */ 59#define FIRMWARE_MAX_STALL 50 /* 50us */
59 60
@@ -86,7 +87,7 @@ static struct erst_erange {
86 * It is used to provide exclusive accessing for ERST Error Log 87 * It is used to provide exclusive accessing for ERST Error Log
87 * Address Range too. 88 * Address Range too.
88 */ 89 */
89static DEFINE_SPINLOCK(erst_lock); 90static DEFINE_RAW_SPINLOCK(erst_lock);
90 91
91static inline int erst_errno(int command_status) 92static inline int erst_errno(int command_status)
92{ 93{
@@ -421,14 +422,30 @@ ssize_t erst_get_record_count(void)
421 if (erst_disable) 422 if (erst_disable)
422 return -ENODEV; 423 return -ENODEV;
423 424
424 spin_lock_irqsave(&erst_lock, flags); 425 raw_spin_lock_irqsave(&erst_lock, flags);
425 count = __erst_get_record_count(); 426 count = __erst_get_record_count();
426 spin_unlock_irqrestore(&erst_lock, flags); 427 raw_spin_unlock_irqrestore(&erst_lock, flags);
427 428
428 return count; 429 return count;
429} 430}
430EXPORT_SYMBOL_GPL(erst_get_record_count); 431EXPORT_SYMBOL_GPL(erst_get_record_count);
431 432
433#define ERST_RECORD_ID_CACHE_SIZE_MIN 16
434#define ERST_RECORD_ID_CACHE_SIZE_MAX 1024
435
436struct erst_record_id_cache {
437 struct mutex lock;
438 u64 *entries;
439 int len;
440 int size;
441 int refcount;
442};
443
444static struct erst_record_id_cache erst_record_id_cache = {
445 .lock = __MUTEX_INITIALIZER(erst_record_id_cache.lock),
446 .refcount = 0,
447};
448
432static int __erst_get_next_record_id(u64 *record_id) 449static int __erst_get_next_record_id(u64 *record_id)
433{ 450{
434 struct apei_exec_context ctx; 451 struct apei_exec_context ctx;
@@ -443,26 +460,179 @@ static int __erst_get_next_record_id(u64 *record_id)
443 return 0; 460 return 0;
444} 461}
445 462
463int erst_get_record_id_begin(int *pos)
464{
465 int rc;
466
467 if (erst_disable)
468 return -ENODEV;
469
470 rc = mutex_lock_interruptible(&erst_record_id_cache.lock);
471 if (rc)
472 return rc;
473 erst_record_id_cache.refcount++;
474 mutex_unlock(&erst_record_id_cache.lock);
475
476 *pos = 0;
477
478 return 0;
479}
480EXPORT_SYMBOL_GPL(erst_get_record_id_begin);
481
482/* erst_record_id_cache.lock must be held by caller */
483static int __erst_record_id_cache_add_one(void)
484{
485 u64 id, prev_id, first_id;
486 int i, rc;
487 u64 *entries;
488 unsigned long flags;
489
490 id = prev_id = first_id = APEI_ERST_INVALID_RECORD_ID;
491retry:
492 raw_spin_lock_irqsave(&erst_lock, flags);
493 rc = __erst_get_next_record_id(&id);
494 raw_spin_unlock_irqrestore(&erst_lock, flags);
495 if (rc == -ENOENT)
496 return 0;
497 if (rc)
498 return rc;
499 if (id == APEI_ERST_INVALID_RECORD_ID)
500 return 0;
501 /* can not skip current ID, or loop back to first ID */
502 if (id == prev_id || id == first_id)
503 return 0;
504 if (first_id == APEI_ERST_INVALID_RECORD_ID)
505 first_id = id;
506 prev_id = id;
507
508 entries = erst_record_id_cache.entries;
509 for (i = 0; i < erst_record_id_cache.len; i++) {
510 if (entries[i] == id)
511 break;
512 }
513 /* record id already in cache, try next */
514 if (i < erst_record_id_cache.len)
515 goto retry;
516 if (erst_record_id_cache.len >= erst_record_id_cache.size) {
517 int new_size, alloc_size;
518 u64 *new_entries;
519
520 new_size = erst_record_id_cache.size * 2;
521 new_size = clamp_val(new_size, ERST_RECORD_ID_CACHE_SIZE_MIN,
522 ERST_RECORD_ID_CACHE_SIZE_MAX);
523 if (new_size <= erst_record_id_cache.size) {
524 if (printk_ratelimit())
525 pr_warning(FW_WARN ERST_PFX
526 "too many record ID!\n");
527 return 0;
528 }
529 alloc_size = new_size * sizeof(entries[0]);
530 if (alloc_size < PAGE_SIZE)
531 new_entries = kmalloc(alloc_size, GFP_KERNEL);
532 else
533 new_entries = vmalloc(alloc_size);
534 if (!new_entries)
535 return -ENOMEM;
536 memcpy(new_entries, entries,
537 erst_record_id_cache.len * sizeof(entries[0]));
538 if (erst_record_id_cache.size < PAGE_SIZE)
539 kfree(entries);
540 else
541 vfree(entries);
542 erst_record_id_cache.entries = entries = new_entries;
543 erst_record_id_cache.size = new_size;
544 }
545 entries[i] = id;
546 erst_record_id_cache.len++;
547
548 return 1;
549}
550
446/* 551/*
447 * Get the record ID of an existing error record on the persistent 552 * Get the record ID of an existing error record on the persistent
448 * storage. If there is no error record on the persistent storage, the 553 * storage. If there is no error record on the persistent storage, the
449 * returned record_id is APEI_ERST_INVALID_RECORD_ID. 554 * returned record_id is APEI_ERST_INVALID_RECORD_ID.
450 */ 555 */
451int erst_get_next_record_id(u64 *record_id) 556int erst_get_record_id_next(int *pos, u64 *record_id)
452{ 557{
453 int rc; 558 int rc = 0;
454 unsigned long flags; 559 u64 *entries;
455 560
456 if (erst_disable) 561 if (erst_disable)
457 return -ENODEV; 562 return -ENODEV;
458 563
459 spin_lock_irqsave(&erst_lock, flags); 564 /* must be enclosed by erst_get_record_id_begin/end */
460 rc = __erst_get_next_record_id(record_id); 565 BUG_ON(!erst_record_id_cache.refcount);
461 spin_unlock_irqrestore(&erst_lock, flags); 566 BUG_ON(*pos < 0 || *pos > erst_record_id_cache.len);
567
568 mutex_lock(&erst_record_id_cache.lock);
569 entries = erst_record_id_cache.entries;
570 for (; *pos < erst_record_id_cache.len; (*pos)++)
571 if (entries[*pos] != APEI_ERST_INVALID_RECORD_ID)
572 break;
573 /* found next record id in cache */
574 if (*pos < erst_record_id_cache.len) {
575 *record_id = entries[*pos];
576 (*pos)++;
577 goto out_unlock;
578 }
579
580 /* Try to add one more record ID to cache */
581 rc = __erst_record_id_cache_add_one();
582 if (rc < 0)
583 goto out_unlock;
584 /* successfully add one new ID */
585 if (rc == 1) {
586 *record_id = erst_record_id_cache.entries[*pos];
587 (*pos)++;
588 rc = 0;
589 } else {
590 *pos = -1;
591 *record_id = APEI_ERST_INVALID_RECORD_ID;
592 }
593out_unlock:
594 mutex_unlock(&erst_record_id_cache.lock);
462 595
463 return rc; 596 return rc;
464} 597}
465EXPORT_SYMBOL_GPL(erst_get_next_record_id); 598EXPORT_SYMBOL_GPL(erst_get_record_id_next);
599
600/* erst_record_id_cache.lock must be held by caller */
601static void __erst_record_id_cache_compact(void)
602{
603 int i, wpos = 0;
604 u64 *entries;
605
606 if (erst_record_id_cache.refcount)
607 return;
608
609 entries = erst_record_id_cache.entries;
610 for (i = 0; i < erst_record_id_cache.len; i++) {
611 if (entries[i] == APEI_ERST_INVALID_RECORD_ID)
612 continue;
613 if (wpos != i)
614 memcpy(&entries[wpos], &entries[i], sizeof(entries[i]));
615 wpos++;
616 }
617 erst_record_id_cache.len = wpos;
618}
619
620void erst_get_record_id_end(void)
621{
622 /*
623 * erst_disable != 0 should be detected by invoker via the
624 * return value of erst_get_record_id_begin/next, so this
625 * function should not be called for erst_disable != 0.
626 */
627 BUG_ON(erst_disable);
628
629 mutex_lock(&erst_record_id_cache.lock);
630 erst_record_id_cache.refcount--;
631 BUG_ON(erst_record_id_cache.refcount < 0);
632 __erst_record_id_cache_compact();
633 mutex_unlock(&erst_record_id_cache.lock);
634}
635EXPORT_SYMBOL_GPL(erst_get_record_id_end);
466 636
467static int __erst_write_to_storage(u64 offset) 637static int __erst_write_to_storage(u64 offset)
468{ 638{
@@ -624,17 +794,17 @@ int erst_write(const struct cper_record_header *record)
624 return -EINVAL; 794 return -EINVAL;
625 795
626 if (erst_erange.attr & ERST_RANGE_NVRAM) { 796 if (erst_erange.attr & ERST_RANGE_NVRAM) {
627 if (!spin_trylock_irqsave(&erst_lock, flags)) 797 if (!raw_spin_trylock_irqsave(&erst_lock, flags))
628 return -EBUSY; 798 return -EBUSY;
629 rc = __erst_write_to_nvram(record); 799 rc = __erst_write_to_nvram(record);
630 spin_unlock_irqrestore(&erst_lock, flags); 800 raw_spin_unlock_irqrestore(&erst_lock, flags);
631 return rc; 801 return rc;
632 } 802 }
633 803
634 if (record->record_length > erst_erange.size) 804 if (record->record_length > erst_erange.size)
635 return -EINVAL; 805 return -EINVAL;
636 806
637 if (!spin_trylock_irqsave(&erst_lock, flags)) 807 if (!raw_spin_trylock_irqsave(&erst_lock, flags))
638 return -EBUSY; 808 return -EBUSY;
639 memcpy(erst_erange.vaddr, record, record->record_length); 809 memcpy(erst_erange.vaddr, record, record->record_length);
640 rcd_erange = erst_erange.vaddr; 810 rcd_erange = erst_erange.vaddr;
@@ -642,7 +812,7 @@ int erst_write(const struct cper_record_header *record)
642 memcpy(&rcd_erange->persistence_information, "ER", 2); 812 memcpy(&rcd_erange->persistence_information, "ER", 2);
643 813
644 rc = __erst_write_to_storage(0); 814 rc = __erst_write_to_storage(0);
645 spin_unlock_irqrestore(&erst_lock, flags); 815 raw_spin_unlock_irqrestore(&erst_lock, flags);
646 816
647 return rc; 817 return rc;
648} 818}
@@ -696,63 +866,41 @@ ssize_t erst_read(u64 record_id, struct cper_record_header *record,
696 if (erst_disable) 866 if (erst_disable)
697 return -ENODEV; 867 return -ENODEV;
698 868
699 spin_lock_irqsave(&erst_lock, flags); 869 raw_spin_lock_irqsave(&erst_lock, flags);
700 len = __erst_read(record_id, record, buflen); 870 len = __erst_read(record_id, record, buflen);
701 spin_unlock_irqrestore(&erst_lock, flags); 871 raw_spin_unlock_irqrestore(&erst_lock, flags);
702 return len; 872 return len;
703} 873}
704EXPORT_SYMBOL_GPL(erst_read); 874EXPORT_SYMBOL_GPL(erst_read);
705 875
706/*
707 * If return value > buflen, the buffer size is not big enough,
708 * else if return value = 0, there is no more record to read,
709 * else if return value < 0, something goes wrong,
710 * else everything is OK, and return value is record length
711 */
712ssize_t erst_read_next(struct cper_record_header *record, size_t buflen)
713{
714 int rc;
715 ssize_t len;
716 unsigned long flags;
717 u64 record_id;
718
719 if (erst_disable)
720 return -ENODEV;
721
722 spin_lock_irqsave(&erst_lock, flags);
723 rc = __erst_get_next_record_id(&record_id);
724 if (rc) {
725 spin_unlock_irqrestore(&erst_lock, flags);
726 return rc;
727 }
728 /* no more record */
729 if (record_id == APEI_ERST_INVALID_RECORD_ID) {
730 spin_unlock_irqrestore(&erst_lock, flags);
731 return 0;
732 }
733
734 len = __erst_read(record_id, record, buflen);
735 spin_unlock_irqrestore(&erst_lock, flags);
736
737 return len;
738}
739EXPORT_SYMBOL_GPL(erst_read_next);
740
741int erst_clear(u64 record_id) 876int erst_clear(u64 record_id)
742{ 877{
743 int rc; 878 int rc, i;
744 unsigned long flags; 879 unsigned long flags;
880 u64 *entries;
745 881
746 if (erst_disable) 882 if (erst_disable)
747 return -ENODEV; 883 return -ENODEV;
748 884
749 spin_lock_irqsave(&erst_lock, flags); 885 rc = mutex_lock_interruptible(&erst_record_id_cache.lock);
886 if (rc)
887 return rc;
888 raw_spin_lock_irqsave(&erst_lock, flags);
750 if (erst_erange.attr & ERST_RANGE_NVRAM) 889 if (erst_erange.attr & ERST_RANGE_NVRAM)
751 rc = __erst_clear_from_nvram(record_id); 890 rc = __erst_clear_from_nvram(record_id);
752 else 891 else
753 rc = __erst_clear_from_storage(record_id); 892 rc = __erst_clear_from_storage(record_id);
754 spin_unlock_irqrestore(&erst_lock, flags); 893 raw_spin_unlock_irqrestore(&erst_lock, flags);
755 894 if (rc)
895 goto out;
896 entries = erst_record_id_cache.entries;
897 for (i = 0; i < erst_record_id_cache.len; i++) {
898 if (entries[i] == record_id)
899 entries[i] = APEI_ERST_INVALID_RECORD_ID;
900 }
901 __erst_record_id_cache_compact();
902out:
903 mutex_unlock(&erst_record_id_cache.lock);
756 return rc; 904 return rc;
757} 905}
758EXPORT_SYMBOL_GPL(erst_clear); 906EXPORT_SYMBOL_GPL(erst_clear);
@@ -781,6 +929,157 @@ static int erst_check_table(struct acpi_table_erst *erst_tab)
781 return 0; 929 return 0;
782} 930}
783 931
932static int erst_open_pstore(struct pstore_info *psi);
933static int erst_close_pstore(struct pstore_info *psi);
934static ssize_t erst_reader(u64 *id, enum pstore_type_id *type,
935 struct timespec *time);
936static u64 erst_writer(enum pstore_type_id type, size_t size);
937
938static struct pstore_info erst_info = {
939 .owner = THIS_MODULE,
940 .name = "erst",
941 .open = erst_open_pstore,
942 .close = erst_close_pstore,
943 .read = erst_reader,
944 .write = erst_writer,
945 .erase = erst_clear
946};
947
948#define CPER_CREATOR_PSTORE \
949 UUID_LE(0x75a574e3, 0x5052, 0x4b29, 0x8a, 0x8e, 0xbe, 0x2c, \
950 0x64, 0x90, 0xb8, 0x9d)
951#define CPER_SECTION_TYPE_DMESG \
952 UUID_LE(0xc197e04e, 0xd545, 0x4a70, 0x9c, 0x17, 0xa5, 0x54, \
953 0x94, 0x19, 0xeb, 0x12)
954#define CPER_SECTION_TYPE_MCE \
955 UUID_LE(0xfe08ffbe, 0x95e4, 0x4be7, 0xbc, 0x73, 0x40, 0x96, \
956 0x04, 0x4a, 0x38, 0xfc)
957
958struct cper_pstore_record {
959 struct cper_record_header hdr;
960 struct cper_section_descriptor sec_hdr;
961 char data[];
962} __packed;
963
964static int reader_pos;
965
966static int erst_open_pstore(struct pstore_info *psi)
967{
968 int rc;
969
970 if (erst_disable)
971 return -ENODEV;
972
973 rc = erst_get_record_id_begin(&reader_pos);
974
975 return rc;
976}
977
978static int erst_close_pstore(struct pstore_info *psi)
979{
980 erst_get_record_id_end();
981
982 return 0;
983}
984
985static ssize_t erst_reader(u64 *id, enum pstore_type_id *type,
986 struct timespec *time)
987{
988 int rc;
989 ssize_t len = 0;
990 u64 record_id;
991 struct cper_pstore_record *rcd = (struct cper_pstore_record *)
992 (erst_info.buf - sizeof(*rcd));
993
994 if (erst_disable)
995 return -ENODEV;
996
997skip:
998 rc = erst_get_record_id_next(&reader_pos, &record_id);
999 if (rc)
1000 goto out;
1001
1002 /* no more record */
1003 if (record_id == APEI_ERST_INVALID_RECORD_ID) {
1004 rc = -1;
1005 goto out;
1006 }
1007
1008 len = erst_read(record_id, &rcd->hdr, sizeof(*rcd) +
1009 erst_info.bufsize);
1010 /* The record may be cleared by others, try read next record */
1011 if (len == -ENOENT)
1012 goto skip;
1013 else if (len < 0) {
1014 rc = -1;
1015 goto out;
1016 }
1017 if (uuid_le_cmp(rcd->hdr.creator_id, CPER_CREATOR_PSTORE) != 0)
1018 goto skip;
1019
1020 *id = record_id;
1021 if (uuid_le_cmp(rcd->sec_hdr.section_type,
1022 CPER_SECTION_TYPE_DMESG) == 0)
1023 *type = PSTORE_TYPE_DMESG;
1024 else if (uuid_le_cmp(rcd->sec_hdr.section_type,
1025 CPER_SECTION_TYPE_MCE) == 0)
1026 *type = PSTORE_TYPE_MCE;
1027 else
1028 *type = PSTORE_TYPE_UNKNOWN;
1029
1030 if (rcd->hdr.validation_bits & CPER_VALID_TIMESTAMP)
1031 time->tv_sec = rcd->hdr.timestamp;
1032 else
1033 time->tv_sec = 0;
1034 time->tv_nsec = 0;
1035
1036out:
1037 return (rc < 0) ? rc : (len - sizeof(*rcd));
1038}
1039
1040static u64 erst_writer(enum pstore_type_id type, size_t size)
1041{
1042 struct cper_pstore_record *rcd = (struct cper_pstore_record *)
1043 (erst_info.buf - sizeof(*rcd));
1044
1045 memset(rcd, 0, sizeof(*rcd));
1046 memcpy(rcd->hdr.signature, CPER_SIG_RECORD, CPER_SIG_SIZE);
1047 rcd->hdr.revision = CPER_RECORD_REV;
1048 rcd->hdr.signature_end = CPER_SIG_END;
1049 rcd->hdr.section_count = 1;
1050 rcd->hdr.error_severity = CPER_SEV_FATAL;
1051 /* timestamp valid. platform_id, partition_id are invalid */
1052 rcd->hdr.validation_bits = CPER_VALID_TIMESTAMP;
1053 rcd->hdr.timestamp = get_seconds();
1054 rcd->hdr.record_length = sizeof(*rcd) + size;
1055 rcd->hdr.creator_id = CPER_CREATOR_PSTORE;
1056 rcd->hdr.notification_type = CPER_NOTIFY_MCE;
1057 rcd->hdr.record_id = cper_next_record_id();
1058 rcd->hdr.flags = CPER_HW_ERROR_FLAGS_PREVERR;
1059
1060 rcd->sec_hdr.section_offset = sizeof(*rcd);
1061 rcd->sec_hdr.section_length = size;
1062 rcd->sec_hdr.revision = CPER_SEC_REV;
1063 /* fru_id and fru_text is invalid */
1064 rcd->sec_hdr.validation_bits = 0;
1065 rcd->sec_hdr.flags = CPER_SEC_PRIMARY;
1066 switch (type) {
1067 case PSTORE_TYPE_DMESG:
1068 rcd->sec_hdr.section_type = CPER_SECTION_TYPE_DMESG;
1069 break;
1070 case PSTORE_TYPE_MCE:
1071 rcd->sec_hdr.section_type = CPER_SECTION_TYPE_MCE;
1072 break;
1073 default:
1074 return -EINVAL;
1075 }
1076 rcd->sec_hdr.section_severity = CPER_SEV_FATAL;
1077
1078 erst_write(&rcd->hdr);
1079
1080 return rcd->hdr.record_id;
1081}
1082
784static int __init erst_init(void) 1083static int __init erst_init(void)
785{ 1084{
786 int rc = 0; 1085 int rc = 0;
@@ -788,6 +1087,7 @@ static int __init erst_init(void)
788 struct apei_exec_context ctx; 1087 struct apei_exec_context ctx;
789 struct apei_resources erst_resources; 1088 struct apei_resources erst_resources;
790 struct resource *r; 1089 struct resource *r;
1090 char *buf;
791 1091
792 if (acpi_disabled) 1092 if (acpi_disabled)
793 goto err; 1093 goto err;
@@ -854,6 +1154,18 @@ static int __init erst_init(void)
854 if (!erst_erange.vaddr) 1154 if (!erst_erange.vaddr)
855 goto err_release_erange; 1155 goto err_release_erange;
856 1156
1157 buf = kmalloc(erst_erange.size, GFP_KERNEL);
1158 mutex_init(&erst_info.buf_mutex);
1159 if (buf) {
1160 erst_info.buf = buf + sizeof(struct cper_pstore_record);
1161 erst_info.bufsize = erst_erange.size -
1162 sizeof(struct cper_pstore_record);
1163 if (pstore_register(&erst_info)) {
1164 pr_info(ERST_PFX "Could not register with persistent store\n");
1165 kfree(buf);
1166 }
1167 }
1168
857 pr_info(ERST_PFX 1169 pr_info(ERST_PFX
858 "Error Record Serialization Table (ERST) support is initialized.\n"); 1170 "Error Record Serialization Table (ERST) support is initialized.\n");
859 1171
diff --git a/drivers/acpi/apei/ghes.c b/drivers/acpi/apei/ghes.c
index 0d505e59214d..f703b2881153 100644
--- a/drivers/acpi/apei/ghes.c
+++ b/drivers/acpi/apei/ghes.c
@@ -12,10 +12,6 @@
12 * For more information about Generic Hardware Error Source, please 12 * For more information about Generic Hardware Error Source, please
13 * refer to ACPI Specification version 4.0, section 17.3.2.6 13 * refer to ACPI Specification version 4.0, section 17.3.2.6
14 * 14 *
15 * Now, only SCI notification type and memory errors are
16 * supported. More notification type and hardware error type will be
17 * added later.
18 *
19 * Copyright 2010 Intel Corp. 15 * Copyright 2010 Intel Corp.
20 * Author: Huang Ying <ying.huang@intel.com> 16 * Author: Huang Ying <ying.huang@intel.com>
21 * 17 *
@@ -39,14 +35,18 @@
39#include <linux/acpi.h> 35#include <linux/acpi.h>
40#include <linux/io.h> 36#include <linux/io.h>
41#include <linux/interrupt.h> 37#include <linux/interrupt.h>
38#include <linux/timer.h>
42#include <linux/cper.h> 39#include <linux/cper.h>
43#include <linux/kdebug.h> 40#include <linux/kdebug.h>
44#include <linux/platform_device.h> 41#include <linux/platform_device.h>
45#include <linux/mutex.h> 42#include <linux/mutex.h>
43#include <linux/ratelimit.h>
44#include <linux/vmalloc.h>
46#include <acpi/apei.h> 45#include <acpi/apei.h>
47#include <acpi/atomicio.h> 46#include <acpi/atomicio.h>
48#include <acpi/hed.h> 47#include <acpi/hed.h>
49#include <asm/mce.h> 48#include <asm/mce.h>
49#include <asm/tlbflush.h>
50 50
51#include "apei-internal.h" 51#include "apei-internal.h"
52 52
@@ -55,42 +55,131 @@
55#define GHES_ESTATUS_MAX_SIZE 65536 55#define GHES_ESTATUS_MAX_SIZE 65536
56 56
57/* 57/*
58 * One struct ghes is created for each generic hardware error 58 * One struct ghes is created for each generic hardware error source.
59 * source.
60 *
61 * It provides the context for APEI hardware error timer/IRQ/SCI/NMI 59 * It provides the context for APEI hardware error timer/IRQ/SCI/NMI
62 * handler. Handler for one generic hardware error source is only 60 * handler.
63 * triggered after the previous one is done. So handler can uses
64 * struct ghes without locking.
65 * 61 *
66 * estatus: memory buffer for error status block, allocated during 62 * estatus: memory buffer for error status block, allocated during
67 * HEST parsing. 63 * HEST parsing.
68 */ 64 */
69#define GHES_TO_CLEAR 0x0001 65#define GHES_TO_CLEAR 0x0001
66#define GHES_EXITING 0x0002
70 67
71struct ghes { 68struct ghes {
72 struct acpi_hest_generic *generic; 69 struct acpi_hest_generic *generic;
73 struct acpi_hest_generic_status *estatus; 70 struct acpi_hest_generic_status *estatus;
74 struct list_head list;
75 u64 buffer_paddr; 71 u64 buffer_paddr;
76 unsigned long flags; 72 unsigned long flags;
73 union {
74 struct list_head list;
75 struct timer_list timer;
76 unsigned int irq;
77 };
77}; 78};
78 79
80static int ghes_panic_timeout __read_mostly = 30;
81
79/* 82/*
80 * Error source lists, one list for each notification method. The 83 * All error sources notified with SCI shares one notifier function,
81 * members in lists are struct ghes. 84 * so they need to be linked and checked one by one. This is applied
85 * to NMI too.
82 * 86 *
83 * The list members are only added in HEST parsing and deleted during 87 * RCU is used for these lists, so ghes_list_mutex is only used for
84 * module_exit, that is, single-threaded. So no lock is needed for 88 * list changing, not for traversing.
85 * that.
86 *
87 * But the mutual exclusion is needed between members adding/deleting
88 * and timer/IRQ/SCI/NMI handler, which may traverse the list. RCU is
89 * used for that.
90 */ 89 */
91static LIST_HEAD(ghes_sci); 90static LIST_HEAD(ghes_sci);
91static LIST_HEAD(ghes_nmi);
92static DEFINE_MUTEX(ghes_list_mutex); 92static DEFINE_MUTEX(ghes_list_mutex);
93 93
94/*
95 * NMI may be triggered on any CPU, so ghes_nmi_lock is used for
96 * mutual exclusion.
97 */
98static DEFINE_RAW_SPINLOCK(ghes_nmi_lock);
99
100/*
101 * Because the memory area used to transfer hardware error information
102 * from BIOS to Linux can be determined only in NMI, IRQ or timer
103 * handler, but general ioremap can not be used in atomic context, so
104 * a special version of atomic ioremap is implemented for that.
105 */
106
107/*
108 * Two virtual pages are used, one for NMI context, the other for
109 * IRQ/PROCESS context
110 */
111#define GHES_IOREMAP_PAGES 2
112#define GHES_IOREMAP_NMI_PAGE(base) (base)
113#define GHES_IOREMAP_IRQ_PAGE(base) ((base) + PAGE_SIZE)
114
115/* virtual memory area for atomic ioremap */
116static struct vm_struct *ghes_ioremap_area;
117/*
118 * These 2 spinlock is used to prevent atomic ioremap virtual memory
119 * area from being mapped simultaneously.
120 */
121static DEFINE_RAW_SPINLOCK(ghes_ioremap_lock_nmi);
122static DEFINE_SPINLOCK(ghes_ioremap_lock_irq);
123
124static int ghes_ioremap_init(void)
125{
126 ghes_ioremap_area = __get_vm_area(PAGE_SIZE * GHES_IOREMAP_PAGES,
127 VM_IOREMAP, VMALLOC_START, VMALLOC_END);
128 if (!ghes_ioremap_area) {
129 pr_err(GHES_PFX "Failed to allocate virtual memory area for atomic ioremap.\n");
130 return -ENOMEM;
131 }
132
133 return 0;
134}
135
136static void ghes_ioremap_exit(void)
137{
138 free_vm_area(ghes_ioremap_area);
139}
140
141static void __iomem *ghes_ioremap_pfn_nmi(u64 pfn)
142{
143 unsigned long vaddr;
144
145 vaddr = (unsigned long)GHES_IOREMAP_NMI_PAGE(ghes_ioremap_area->addr);
146 ioremap_page_range(vaddr, vaddr + PAGE_SIZE,
147 pfn << PAGE_SHIFT, PAGE_KERNEL);
148
149 return (void __iomem *)vaddr;
150}
151
152static void __iomem *ghes_ioremap_pfn_irq(u64 pfn)
153{
154 unsigned long vaddr;
155
156 vaddr = (unsigned long)GHES_IOREMAP_IRQ_PAGE(ghes_ioremap_area->addr);
157 ioremap_page_range(vaddr, vaddr + PAGE_SIZE,
158 pfn << PAGE_SHIFT, PAGE_KERNEL);
159
160 return (void __iomem *)vaddr;
161}
162
163static void ghes_iounmap_nmi(void __iomem *vaddr_ptr)
164{
165 unsigned long vaddr = (unsigned long __force)vaddr_ptr;
166 void *base = ghes_ioremap_area->addr;
167
168 BUG_ON(vaddr != (unsigned long)GHES_IOREMAP_NMI_PAGE(base));
169 unmap_kernel_range_noflush(vaddr, PAGE_SIZE);
170 __flush_tlb_one(vaddr);
171}
172
173static void ghes_iounmap_irq(void __iomem *vaddr_ptr)
174{
175 unsigned long vaddr = (unsigned long __force)vaddr_ptr;
176 void *base = ghes_ioremap_area->addr;
177
178 BUG_ON(vaddr != (unsigned long)GHES_IOREMAP_IRQ_PAGE(base));
179 unmap_kernel_range_noflush(vaddr, PAGE_SIZE);
180 __flush_tlb_one(vaddr);
181}
182
94static struct ghes *ghes_new(struct acpi_hest_generic *generic) 183static struct ghes *ghes_new(struct acpi_hest_generic *generic)
95{ 184{
96 struct ghes *ghes; 185 struct ghes *ghes;
@@ -101,7 +190,6 @@ static struct ghes *ghes_new(struct acpi_hest_generic *generic)
101 if (!ghes) 190 if (!ghes)
102 return ERR_PTR(-ENOMEM); 191 return ERR_PTR(-ENOMEM);
103 ghes->generic = generic; 192 ghes->generic = generic;
104 INIT_LIST_HEAD(&ghes->list);
105 rc = acpi_pre_map_gar(&generic->error_status_address); 193 rc = acpi_pre_map_gar(&generic->error_status_address);
106 if (rc) 194 if (rc)
107 goto err_free; 195 goto err_free;
@@ -153,27 +241,46 @@ static inline int ghes_severity(int severity)
153 case CPER_SEV_FATAL: 241 case CPER_SEV_FATAL:
154 return GHES_SEV_PANIC; 242 return GHES_SEV_PANIC;
155 default: 243 default:
156 /* Unkown, go panic */ 244 /* Unknown, go panic */
157 return GHES_SEV_PANIC; 245 return GHES_SEV_PANIC;
158 } 246 }
159} 247}
160 248
161/* SCI handler run in work queue, so ioremap can be used here */ 249static void ghes_copy_tofrom_phys(void *buffer, u64 paddr, u32 len,
162static int ghes_copy_tofrom_phys(void *buffer, u64 paddr, u32 len, 250 int from_phys)
163 int from_phys)
164{ 251{
165 void *vaddr; 252 void __iomem *vaddr;
166 253 unsigned long flags = 0;
167 vaddr = ioremap_cache(paddr, len); 254 int in_nmi = in_nmi();
168 if (!vaddr) 255 u64 offset;
169 return -ENOMEM; 256 u32 trunk;
170 if (from_phys) 257
171 memcpy(buffer, vaddr, len); 258 while (len > 0) {
172 else 259 offset = paddr - (paddr & PAGE_MASK);
173 memcpy(vaddr, buffer, len); 260 if (in_nmi) {
174 iounmap(vaddr); 261 raw_spin_lock(&ghes_ioremap_lock_nmi);
175 262 vaddr = ghes_ioremap_pfn_nmi(paddr >> PAGE_SHIFT);
176 return 0; 263 } else {
264 spin_lock_irqsave(&ghes_ioremap_lock_irq, flags);
265 vaddr = ghes_ioremap_pfn_irq(paddr >> PAGE_SHIFT);
266 }
267 trunk = PAGE_SIZE - offset;
268 trunk = min(trunk, len);
269 if (from_phys)
270 memcpy_fromio(buffer, vaddr + offset, trunk);
271 else
272 memcpy_toio(vaddr + offset, buffer, trunk);
273 len -= trunk;
274 paddr += trunk;
275 buffer += trunk;
276 if (in_nmi) {
277 ghes_iounmap_nmi(vaddr);
278 raw_spin_unlock(&ghes_ioremap_lock_nmi);
279 } else {
280 ghes_iounmap_irq(vaddr);
281 spin_unlock_irqrestore(&ghes_ioremap_lock_irq, flags);
282 }
283 }
177} 284}
178 285
179static int ghes_read_estatus(struct ghes *ghes, int silent) 286static int ghes_read_estatus(struct ghes *ghes, int silent)
@@ -194,10 +301,8 @@ static int ghes_read_estatus(struct ghes *ghes, int silent)
194 if (!buf_paddr) 301 if (!buf_paddr)
195 return -ENOENT; 302 return -ENOENT;
196 303
197 rc = ghes_copy_tofrom_phys(ghes->estatus, buf_paddr, 304 ghes_copy_tofrom_phys(ghes->estatus, buf_paddr,
198 sizeof(*ghes->estatus), 1); 305 sizeof(*ghes->estatus), 1);
199 if (rc)
200 return rc;
201 if (!ghes->estatus->block_status) 306 if (!ghes->estatus->block_status)
202 return -ENOENT; 307 return -ENOENT;
203 308
@@ -212,17 +317,15 @@ static int ghes_read_estatus(struct ghes *ghes, int silent)
212 goto err_read_block; 317 goto err_read_block;
213 if (apei_estatus_check_header(ghes->estatus)) 318 if (apei_estatus_check_header(ghes->estatus))
214 goto err_read_block; 319 goto err_read_block;
215 rc = ghes_copy_tofrom_phys(ghes->estatus + 1, 320 ghes_copy_tofrom_phys(ghes->estatus + 1,
216 buf_paddr + sizeof(*ghes->estatus), 321 buf_paddr + sizeof(*ghes->estatus),
217 len - sizeof(*ghes->estatus), 1); 322 len - sizeof(*ghes->estatus), 1);
218 if (rc)
219 return rc;
220 if (apei_estatus_check(ghes->estatus)) 323 if (apei_estatus_check(ghes->estatus))
221 goto err_read_block; 324 goto err_read_block;
222 rc = 0; 325 rc = 0;
223 326
224err_read_block: 327err_read_block:
225 if (rc && !silent) 328 if (rc && !silent && printk_ratelimit())
226 pr_warning(FW_WARN GHES_PFX 329 pr_warning(FW_WARN GHES_PFX
227 "Failed to read error status block!\n"); 330 "Failed to read error status block!\n");
228 return rc; 331 return rc;
@@ -255,11 +358,26 @@ static void ghes_do_proc(struct ghes *ghes)
255 } 358 }
256#endif 359#endif
257 } 360 }
361}
258 362
259 if (!processed && printk_ratelimit()) 363static void ghes_print_estatus(const char *pfx, struct ghes *ghes)
260 pr_warning(GHES_PFX 364{
261 "Unknown error record from generic hardware error source: %d\n", 365 /* Not more than 2 messages every 5 seconds */
262 ghes->generic->header.source_id); 366 static DEFINE_RATELIMIT_STATE(ratelimit, 5*HZ, 2);
367
368 if (pfx == NULL) {
369 if (ghes_severity(ghes->estatus->error_severity) <=
370 GHES_SEV_CORRECTED)
371 pfx = KERN_WARNING HW_ERR;
372 else
373 pfx = KERN_ERR HW_ERR;
374 }
375 if (__ratelimit(&ratelimit)) {
376 printk(
377 "%s""Hardware error from APEI Generic Hardware Error Source: %d\n",
378 pfx, ghes->generic->header.source_id);
379 apei_estatus_print(pfx, ghes->estatus);
380 }
263} 381}
264 382
265static int ghes_proc(struct ghes *ghes) 383static int ghes_proc(struct ghes *ghes)
@@ -269,6 +387,7 @@ static int ghes_proc(struct ghes *ghes)
269 rc = ghes_read_estatus(ghes, 0); 387 rc = ghes_read_estatus(ghes, 0);
270 if (rc) 388 if (rc)
271 goto out; 389 goto out;
390 ghes_print_estatus(NULL, ghes);
272 ghes_do_proc(ghes); 391 ghes_do_proc(ghes);
273 392
274out: 393out:
@@ -276,6 +395,42 @@ out:
276 return 0; 395 return 0;
277} 396}
278 397
398static void ghes_add_timer(struct ghes *ghes)
399{
400 struct acpi_hest_generic *g = ghes->generic;
401 unsigned long expire;
402
403 if (!g->notify.poll_interval) {
404 pr_warning(FW_WARN GHES_PFX "Poll interval is 0 for generic hardware error source: %d, disabled.\n",
405 g->header.source_id);
406 return;
407 }
408 expire = jiffies + msecs_to_jiffies(g->notify.poll_interval);
409 ghes->timer.expires = round_jiffies_relative(expire);
410 add_timer(&ghes->timer);
411}
412
413static void ghes_poll_func(unsigned long data)
414{
415 struct ghes *ghes = (void *)data;
416
417 ghes_proc(ghes);
418 if (!(ghes->flags & GHES_EXITING))
419 ghes_add_timer(ghes);
420}
421
422static irqreturn_t ghes_irq_func(int irq, void *data)
423{
424 struct ghes *ghes = data;
425 int rc;
426
427 rc = ghes_proc(ghes);
428 if (rc)
429 return IRQ_NONE;
430
431 return IRQ_HANDLED;
432}
433
279static int ghes_notify_sci(struct notifier_block *this, 434static int ghes_notify_sci(struct notifier_block *this,
280 unsigned long event, void *data) 435 unsigned long event, void *data)
281{ 436{
@@ -292,10 +447,63 @@ static int ghes_notify_sci(struct notifier_block *this,
292 return ret; 447 return ret;
293} 448}
294 449
450static int ghes_notify_nmi(struct notifier_block *this,
451 unsigned long cmd, void *data)
452{
453 struct ghes *ghes, *ghes_global = NULL;
454 int sev, sev_global = -1;
455 int ret = NOTIFY_DONE;
456
457 if (cmd != DIE_NMI)
458 return ret;
459
460 raw_spin_lock(&ghes_nmi_lock);
461 list_for_each_entry_rcu(ghes, &ghes_nmi, list) {
462 if (ghes_read_estatus(ghes, 1)) {
463 ghes_clear_estatus(ghes);
464 continue;
465 }
466 sev = ghes_severity(ghes->estatus->error_severity);
467 if (sev > sev_global) {
468 sev_global = sev;
469 ghes_global = ghes;
470 }
471 ret = NOTIFY_STOP;
472 }
473
474 if (ret == NOTIFY_DONE)
475 goto out;
476
477 if (sev_global >= GHES_SEV_PANIC) {
478 oops_begin();
479 ghes_print_estatus(KERN_EMERG HW_ERR, ghes_global);
480 /* reboot to log the error! */
481 if (panic_timeout == 0)
482 panic_timeout = ghes_panic_timeout;
483 panic("Fatal hardware error!");
484 }
485
486 list_for_each_entry_rcu(ghes, &ghes_nmi, list) {
487 if (!(ghes->flags & GHES_TO_CLEAR))
488 continue;
489 /* Do not print estatus because printk is not NMI safe */
490 ghes_do_proc(ghes);
491 ghes_clear_estatus(ghes);
492 }
493
494out:
495 raw_spin_unlock(&ghes_nmi_lock);
496 return ret;
497}
498
295static struct notifier_block ghes_notifier_sci = { 499static struct notifier_block ghes_notifier_sci = {
296 .notifier_call = ghes_notify_sci, 500 .notifier_call = ghes_notify_sci,
297}; 501};
298 502
503static struct notifier_block ghes_notifier_nmi = {
504 .notifier_call = ghes_notify_nmi,
505};
506
299static int __devinit ghes_probe(struct platform_device *ghes_dev) 507static int __devinit ghes_probe(struct platform_device *ghes_dev)
300{ 508{
301 struct acpi_hest_generic *generic; 509 struct acpi_hest_generic *generic;
@@ -306,18 +514,27 @@ static int __devinit ghes_probe(struct platform_device *ghes_dev)
306 if (!generic->enabled) 514 if (!generic->enabled)
307 return -ENODEV; 515 return -ENODEV;
308 516
309 if (generic->error_block_length < 517 switch (generic->notify.type) {
310 sizeof(struct acpi_hest_generic_status)) { 518 case ACPI_HEST_NOTIFY_POLLED:
311 pr_warning(FW_BUG GHES_PFX 519 case ACPI_HEST_NOTIFY_EXTERNAL:
312"Invalid error block length: %u for generic hardware error source: %d\n", 520 case ACPI_HEST_NOTIFY_SCI:
313 generic->error_block_length, 521 case ACPI_HEST_NOTIFY_NMI:
522 break;
523 case ACPI_HEST_NOTIFY_LOCAL:
524 pr_warning(GHES_PFX "Generic hardware error source: %d notified via local interrupt is not supported!\n",
314 generic->header.source_id); 525 generic->header.source_id);
315 goto err; 526 goto err;
527 default:
528 pr_warning(FW_WARN GHES_PFX "Unknown notification type: %u for generic hardware error source: %d\n",
529 generic->notify.type, generic->header.source_id);
530 goto err;
316 } 531 }
317 if (generic->records_to_preallocate == 0) { 532
318 pr_warning(FW_BUG GHES_PFX 533 rc = -EIO;
319"Invalid records to preallocate: %u for generic hardware error source: %d\n", 534 if (generic->error_block_length <
320 generic->records_to_preallocate, 535 sizeof(struct acpi_hest_generic_status)) {
536 pr_warning(FW_BUG GHES_PFX "Invalid error block length: %u for generic hardware error source: %d\n",
537 generic->error_block_length,
321 generic->header.source_id); 538 generic->header.source_id);
322 goto err; 539 goto err;
323 } 540 }
@@ -327,38 +544,43 @@ static int __devinit ghes_probe(struct platform_device *ghes_dev)
327 ghes = NULL; 544 ghes = NULL;
328 goto err; 545 goto err;
329 } 546 }
330 if (generic->notify.type == ACPI_HEST_NOTIFY_SCI) { 547 switch (generic->notify.type) {
548 case ACPI_HEST_NOTIFY_POLLED:
549 ghes->timer.function = ghes_poll_func;
550 ghes->timer.data = (unsigned long)ghes;
551 init_timer_deferrable(&ghes->timer);
552 ghes_add_timer(ghes);
553 break;
554 case ACPI_HEST_NOTIFY_EXTERNAL:
555 /* External interrupt vector is GSI */
556 if (acpi_gsi_to_irq(generic->notify.vector, &ghes->irq)) {
557 pr_err(GHES_PFX "Failed to map GSI to IRQ for generic hardware error source: %d\n",
558 generic->header.source_id);
559 goto err;
560 }
561 if (request_irq(ghes->irq, ghes_irq_func,
562 0, "GHES IRQ", ghes)) {
563 pr_err(GHES_PFX "Failed to register IRQ for generic hardware error source: %d\n",
564 generic->header.source_id);
565 goto err;
566 }
567 break;
568 case ACPI_HEST_NOTIFY_SCI:
331 mutex_lock(&ghes_list_mutex); 569 mutex_lock(&ghes_list_mutex);
332 if (list_empty(&ghes_sci)) 570 if (list_empty(&ghes_sci))
333 register_acpi_hed_notifier(&ghes_notifier_sci); 571 register_acpi_hed_notifier(&ghes_notifier_sci);
334 list_add_rcu(&ghes->list, &ghes_sci); 572 list_add_rcu(&ghes->list, &ghes_sci);
335 mutex_unlock(&ghes_list_mutex); 573 mutex_unlock(&ghes_list_mutex);
336 } else { 574 break;
337 unsigned char *notify = NULL; 575 case ACPI_HEST_NOTIFY_NMI:
338 576 mutex_lock(&ghes_list_mutex);
339 switch (generic->notify.type) { 577 if (list_empty(&ghes_nmi))
340 case ACPI_HEST_NOTIFY_POLLED: 578 register_die_notifier(&ghes_notifier_nmi);
341 notify = "POLL"; 579 list_add_rcu(&ghes->list, &ghes_nmi);
342 break; 580 mutex_unlock(&ghes_list_mutex);
343 case ACPI_HEST_NOTIFY_EXTERNAL: 581 break;
344 case ACPI_HEST_NOTIFY_LOCAL: 582 default:
345 notify = "IRQ"; 583 BUG();
346 break;
347 case ACPI_HEST_NOTIFY_NMI:
348 notify = "NMI";
349 break;
350 }
351 if (notify) {
352 pr_warning(GHES_PFX
353"Generic hardware error source: %d notified via %s is not supported!\n",
354 generic->header.source_id, notify);
355 } else {
356 pr_warning(FW_WARN GHES_PFX
357"Unknown notification type: %u for generic hardware error source: %d\n",
358 generic->notify.type, generic->header.source_id);
359 }
360 rc = -ENODEV;
361 goto err;
362 } 584 }
363 platform_set_drvdata(ghes_dev, ghes); 585 platform_set_drvdata(ghes_dev, ghes);
364 586
@@ -379,7 +601,14 @@ static int __devexit ghes_remove(struct platform_device *ghes_dev)
379 ghes = platform_get_drvdata(ghes_dev); 601 ghes = platform_get_drvdata(ghes_dev);
380 generic = ghes->generic; 602 generic = ghes->generic;
381 603
604 ghes->flags |= GHES_EXITING;
382 switch (generic->notify.type) { 605 switch (generic->notify.type) {
606 case ACPI_HEST_NOTIFY_POLLED:
607 del_timer_sync(&ghes->timer);
608 break;
609 case ACPI_HEST_NOTIFY_EXTERNAL:
610 free_irq(ghes->irq, ghes);
611 break;
383 case ACPI_HEST_NOTIFY_SCI: 612 case ACPI_HEST_NOTIFY_SCI:
384 mutex_lock(&ghes_list_mutex); 613 mutex_lock(&ghes_list_mutex);
385 list_del_rcu(&ghes->list); 614 list_del_rcu(&ghes->list);
@@ -387,12 +616,23 @@ static int __devexit ghes_remove(struct platform_device *ghes_dev)
387 unregister_acpi_hed_notifier(&ghes_notifier_sci); 616 unregister_acpi_hed_notifier(&ghes_notifier_sci);
388 mutex_unlock(&ghes_list_mutex); 617 mutex_unlock(&ghes_list_mutex);
389 break; 618 break;
619 case ACPI_HEST_NOTIFY_NMI:
620 mutex_lock(&ghes_list_mutex);
621 list_del_rcu(&ghes->list);
622 if (list_empty(&ghes_nmi))
623 unregister_die_notifier(&ghes_notifier_nmi);
624 mutex_unlock(&ghes_list_mutex);
625 /*
626 * To synchronize with NMI handler, ghes can only be
627 * freed after NMI handler finishes.
628 */
629 synchronize_rcu();
630 break;
390 default: 631 default:
391 BUG(); 632 BUG();
392 break; 633 break;
393 } 634 }
394 635
395 synchronize_rcu();
396 ghes_fini(ghes); 636 ghes_fini(ghes);
397 kfree(ghes); 637 kfree(ghes);
398 638
@@ -412,6 +652,8 @@ static struct platform_driver ghes_platform_driver = {
412 652
413static int __init ghes_init(void) 653static int __init ghes_init(void)
414{ 654{
655 int rc;
656
415 if (acpi_disabled) 657 if (acpi_disabled)
416 return -ENODEV; 658 return -ENODEV;
417 659
@@ -420,12 +662,25 @@ static int __init ghes_init(void)
420 return -EINVAL; 662 return -EINVAL;
421 } 663 }
422 664
423 return platform_driver_register(&ghes_platform_driver); 665 rc = ghes_ioremap_init();
666 if (rc)
667 goto err;
668
669 rc = platform_driver_register(&ghes_platform_driver);
670 if (rc)
671 goto err_ioremap_exit;
672
673 return 0;
674err_ioremap_exit:
675 ghes_ioremap_exit();
676err:
677 return rc;
424} 678}
425 679
426static void __exit ghes_exit(void) 680static void __exit ghes_exit(void)
427{ 681{
428 platform_driver_unregister(&ghes_platform_driver); 682 platform_driver_unregister(&ghes_platform_driver);
683 ghes_ioremap_exit();
429} 684}
430 685
431module_init(ghes_init); 686module_init(ghes_init);
diff --git a/drivers/acpi/apei/hest.c b/drivers/acpi/apei/hest.c
index 1a3508a7fe03..181bc2f7bb74 100644
--- a/drivers/acpi/apei/hest.c
+++ b/drivers/acpi/apei/hest.c
@@ -46,9 +46,9 @@ EXPORT_SYMBOL_GPL(hest_disable);
46 46
47/* HEST table parsing */ 47/* HEST table parsing */
48 48
49static struct acpi_table_hest *hest_tab; 49static struct acpi_table_hest *__read_mostly hest_tab;
50 50
51static int hest_esrc_len_tab[ACPI_HEST_TYPE_RESERVED] = { 51static const int hest_esrc_len_tab[ACPI_HEST_TYPE_RESERVED] = {
52 [ACPI_HEST_TYPE_IA32_CHECK] = -1, /* need further calculation */ 52 [ACPI_HEST_TYPE_IA32_CHECK] = -1, /* need further calculation */
53 [ACPI_HEST_TYPE_IA32_CORRECTED_CHECK] = -1, 53 [ACPI_HEST_TYPE_IA32_CORRECTED_CHECK] = -1,
54 [ACPI_HEST_TYPE_IA32_NMI] = sizeof(struct acpi_hest_ia_nmi), 54 [ACPI_HEST_TYPE_IA32_NMI] = sizeof(struct acpi_hest_ia_nmi),
@@ -126,7 +126,7 @@ struct ghes_arr {
126 unsigned int count; 126 unsigned int count;
127}; 127};
128 128
129static int hest_parse_ghes_count(struct acpi_hest_header *hest_hdr, void *data) 129static int __init hest_parse_ghes_count(struct acpi_hest_header *hest_hdr, void *data)
130{ 130{
131 int *count = data; 131 int *count = data;
132 132
@@ -135,17 +135,27 @@ static int hest_parse_ghes_count(struct acpi_hest_header *hest_hdr, void *data)
135 return 0; 135 return 0;
136} 136}
137 137
138static int hest_parse_ghes(struct acpi_hest_header *hest_hdr, void *data) 138static int __init hest_parse_ghes(struct acpi_hest_header *hest_hdr, void *data)
139{ 139{
140 struct platform_device *ghes_dev; 140 struct platform_device *ghes_dev;
141 struct ghes_arr *ghes_arr = data; 141 struct ghes_arr *ghes_arr = data;
142 int rc; 142 int rc, i;
143 143
144 if (hest_hdr->type != ACPI_HEST_TYPE_GENERIC_ERROR) 144 if (hest_hdr->type != ACPI_HEST_TYPE_GENERIC_ERROR)
145 return 0; 145 return 0;
146 146
147 if (!((struct acpi_hest_generic *)hest_hdr)->enabled) 147 if (!((struct acpi_hest_generic *)hest_hdr)->enabled)
148 return 0; 148 return 0;
149 for (i = 0; i < ghes_arr->count; i++) {
150 struct acpi_hest_header *hdr;
151 ghes_dev = ghes_arr->ghes_devs[i];
152 hdr = *(struct acpi_hest_header **)ghes_dev->dev.platform_data;
153 if (hdr->source_id == hest_hdr->source_id) {
154 pr_warning(FW_WARN HEST_PFX "Duplicated hardware error source ID: %d.\n",
155 hdr->source_id);
156 return -EIO;
157 }
158 }
149 ghes_dev = platform_device_alloc("GHES", hest_hdr->source_id); 159 ghes_dev = platform_device_alloc("GHES", hest_hdr->source_id);
150 if (!ghes_dev) 160 if (!ghes_dev)
151 return -ENOMEM; 161 return -ENOMEM;
@@ -165,7 +175,7 @@ err:
165 return rc; 175 return rc;
166} 176}
167 177
168static int hest_ghes_dev_register(unsigned int ghes_count) 178static int __init hest_ghes_dev_register(unsigned int ghes_count)
169{ 179{
170 int rc, i; 180 int rc, i;
171 struct ghes_arr ghes_arr; 181 struct ghes_arr ghes_arr;
@@ -195,24 +205,24 @@ static int __init setup_hest_disable(char *str)
195 205
196__setup("hest_disable", setup_hest_disable); 206__setup("hest_disable", setup_hest_disable);
197 207
198static int __init hest_init(void) 208void __init acpi_hest_init(void)
199{ 209{
200 acpi_status status; 210 acpi_status status;
201 int rc = -ENODEV; 211 int rc = -ENODEV;
202 unsigned int ghes_count = 0; 212 unsigned int ghes_count = 0;
203 213
204 if (acpi_disabled)
205 goto err;
206
207 if (hest_disable) { 214 if (hest_disable) {
208 pr_info(HEST_PFX "HEST tabling parsing is disabled.\n"); 215 pr_info(HEST_PFX "Table parsing disabled.\n");
209 goto err; 216 return;
210 } 217 }
211 218
219 if (acpi_disabled)
220 goto err;
221
212 status = acpi_get_table(ACPI_SIG_HEST, 0, 222 status = acpi_get_table(ACPI_SIG_HEST, 0,
213 (struct acpi_table_header **)&hest_tab); 223 (struct acpi_table_header **)&hest_tab);
214 if (status == AE_NOT_FOUND) { 224 if (status == AE_NOT_FOUND) {
215 pr_info(HEST_PFX "Table is not found!\n"); 225 pr_info(HEST_PFX "Table not found.\n");
216 goto err; 226 goto err;
217 } else if (ACPI_FAILURE(status)) { 227 } else if (ACPI_FAILURE(status)) {
218 const char *msg = acpi_format_exception(status); 228 const char *msg = acpi_format_exception(status);
@@ -226,15 +236,11 @@ static int __init hest_init(void)
226 goto err; 236 goto err;
227 237
228 rc = hest_ghes_dev_register(ghes_count); 238 rc = hest_ghes_dev_register(ghes_count);
229 if (rc) 239 if (!rc) {
230 goto err; 240 pr_info(HEST_PFX "Table parsing has been initialized.\n");
231 241 return;
232 pr_info(HEST_PFX "HEST table parsing is initialized.\n"); 242 }
233 243
234 return 0;
235err: 244err:
236 hest_disable = 1; 245 hest_disable = 1;
237 return rc;
238} 246}
239
240subsys_initcall(hest_init);