aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/acpi
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/acpi')
-rw-r--r--drivers/acpi/apei/Kconfig9
-rw-r--r--drivers/acpi/apei/Makefile1
-rw-r--r--drivers/acpi/apei/apei-base.c4
-rw-r--r--drivers/acpi/apei/erst-dbg.c207
-rw-r--r--drivers/acpi/apei/ghes.c172
-rw-r--r--drivers/acpi/apei/hest.c76
-rw-r--r--drivers/acpi/sleep.c60
-rw-r--r--drivers/acpi/sleep.h5
-rw-r--r--drivers/acpi/wakeup.c48
9 files changed, 413 insertions, 169 deletions
diff --git a/drivers/acpi/apei/Kconfig b/drivers/acpi/apei/Kconfig
index f8c668f27b5..907e350f1c7 100644
--- a/drivers/acpi/apei/Kconfig
+++ b/drivers/acpi/apei/Kconfig
@@ -28,3 +28,12 @@ config ACPI_APEI_EINJ
28 EINJ provides a hardware error injection mechanism, it is 28 EINJ provides a hardware error injection mechanism, it is
29 mainly used for debugging and testing the other parts of 29 mainly used for debugging and testing the other parts of
30 APEI and some other RAS features. 30 APEI and some other RAS features.
31
32config ACPI_APEI_ERST_DEBUG
33 tristate "APEI Error Record Serialization Table (ERST) Debug Support"
34 depends on ACPI_APEI
35 help
36 ERST is a way provided by APEI to save and retrieve hardware
37 error infomation to and from a persistent store. Enable this
38 if you want to debugging and testing the ERST kernel support
39 and firmware implementation.
diff --git a/drivers/acpi/apei/Makefile b/drivers/acpi/apei/Makefile
index b13b03a1778..d1d1bc0a4ee 100644
--- a/drivers/acpi/apei/Makefile
+++ b/drivers/acpi/apei/Makefile
@@ -1,5 +1,6 @@
1obj-$(CONFIG_ACPI_APEI) += apei.o 1obj-$(CONFIG_ACPI_APEI) += apei.o
2obj-$(CONFIG_ACPI_APEI_GHES) += ghes.o 2obj-$(CONFIG_ACPI_APEI_GHES) += ghes.o
3obj-$(CONFIG_ACPI_APEI_EINJ) += einj.o 3obj-$(CONFIG_ACPI_APEI_EINJ) += einj.o
4obj-$(CONFIG_ACPI_APEI_ERST_DEBUG) += erst-dbg.o
4 5
5apei-y := apei-base.o hest.o cper.o erst.o 6apei-y := apei-base.o hest.o cper.o erst.o
diff --git a/drivers/acpi/apei/apei-base.c b/drivers/acpi/apei/apei-base.c
index 216e1e948ff..73fd0c7487c 100644
--- a/drivers/acpi/apei/apei-base.c
+++ b/drivers/acpi/apei/apei-base.c
@@ -482,14 +482,14 @@ err_unmap_ioport:
482 list_for_each_entry(res, &resources->ioport, list) { 482 list_for_each_entry(res, &resources->ioport, list) {
483 if (res == res_bak) 483 if (res == res_bak)
484 break; 484 break;
485 release_mem_region(res->start, res->end - res->start); 485 release_region(res->start, res->end - res->start);
486 } 486 }
487 res_bak = NULL; 487 res_bak = NULL;
488err_unmap_iomem: 488err_unmap_iomem:
489 list_for_each_entry(res, &resources->iomem, list) { 489 list_for_each_entry(res, &resources->iomem, list) {
490 if (res == res_bak) 490 if (res == res_bak)
491 break; 491 break;
492 release_region(res->start, res->end - res->start); 492 release_mem_region(res->start, res->end - res->start);
493 } 493 }
494 return -EINVAL; 494 return -EINVAL;
495} 495}
diff --git a/drivers/acpi/apei/erst-dbg.c b/drivers/acpi/apei/erst-dbg.c
new file mode 100644
index 00000000000..5281ddda277
--- /dev/null
+++ b/drivers/acpi/apei/erst-dbg.c
@@ -0,0 +1,207 @@
1/*
2 * APEI Error Record Serialization Table debug support
3 *
4 * ERST is a way provided by APEI to save and retrieve hardware error
5 * infomation to and from a persistent store. This file provide the
6 * debugging/testing support for ERST kernel support and firmware
7 * implementation.
8 *
9 * Copyright 2010 Intel Corp.
10 * Author: Huang Ying <ying.huang@intel.com>
11 *
12 * This program is free software; you can redistribute it and/or
13 * modify it under the terms of the GNU General Public License version
14 * 2 as published by the Free Software Foundation.
15 *
16 * This program is distributed in the hope that it will be useful,
17 * but WITHOUT ANY WARRANTY; without even the implied warranty of
18 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
19 * GNU General Public License for more details.
20 *
21 * You should have received a copy of the GNU General Public License
22 * along with this program; if not, write to the Free Software
23 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
24 */
25
26#include <linux/kernel.h>
27#include <linux/module.h>
28#include <linux/uaccess.h>
29#include <acpi/apei.h>
30#include <linux/miscdevice.h>
31
32#include "apei-internal.h"
33
34#define ERST_DBG_PFX "ERST DBG: "
35
36#define ERST_DBG_RECORD_LEN_MAX 4096
37
38static void *erst_dbg_buf;
39static unsigned int erst_dbg_buf_len;
40
41/* Prevent erst_dbg_read/write from being invoked concurrently */
42static DEFINE_MUTEX(erst_dbg_mutex);
43
44static int erst_dbg_open(struct inode *inode, struct file *file)
45{
46 if (erst_disable)
47 return -ENODEV;
48
49 return nonseekable_open(inode, file);
50}
51
52static long erst_dbg_ioctl(struct file *f, unsigned int cmd, unsigned long arg)
53{
54 int rc;
55 u64 record_id;
56 u32 record_count;
57
58 switch (cmd) {
59 case APEI_ERST_CLEAR_RECORD:
60 rc = copy_from_user(&record_id, (void __user *)arg,
61 sizeof(record_id));
62 if (rc)
63 return -EFAULT;
64 return erst_clear(record_id);
65 case APEI_ERST_GET_RECORD_COUNT:
66 rc = erst_get_record_count();
67 if (rc < 0)
68 return rc;
69 record_count = rc;
70 rc = put_user(record_count, (u32 __user *)arg);
71 if (rc)
72 return rc;
73 return 0;
74 default:
75 return -ENOTTY;
76 }
77}
78
79static ssize_t erst_dbg_read(struct file *filp, char __user *ubuf,
80 size_t usize, loff_t *off)
81{
82 int rc;
83 ssize_t len = 0;
84 u64 id;
85
86 if (*off != 0)
87 return -EINVAL;
88
89 if (mutex_lock_interruptible(&erst_dbg_mutex) != 0)
90 return -EINTR;
91
92retry_next:
93 rc = erst_get_next_record_id(&id);
94 if (rc)
95 goto out;
96 /* no more record */
97 if (id == APEI_ERST_INVALID_RECORD_ID)
98 goto out;
99retry:
100 rc = len = erst_read(id, erst_dbg_buf, erst_dbg_buf_len);
101 /* The record may be cleared by others, try read next record */
102 if (rc == -ENOENT)
103 goto retry_next;
104 if (rc < 0)
105 goto out;
106 if (len > ERST_DBG_RECORD_LEN_MAX) {
107 pr_warning(ERST_DBG_PFX
108 "Record (ID: 0x%llx) length is too long: %zd\n",
109 id, len);
110 rc = -EIO;
111 goto out;
112 }
113 if (len > erst_dbg_buf_len) {
114 kfree(erst_dbg_buf);
115 rc = -ENOMEM;
116 erst_dbg_buf = kmalloc(len, GFP_KERNEL);
117 if (!erst_dbg_buf)
118 goto out;
119 erst_dbg_buf_len = len;
120 goto retry;
121 }
122
123 rc = -EINVAL;
124 if (len > usize)
125 goto out;
126
127 rc = -EFAULT;
128 if (copy_to_user(ubuf, erst_dbg_buf, len))
129 goto out;
130 rc = 0;
131out:
132 mutex_unlock(&erst_dbg_mutex);
133 return rc ? rc : len;
134}
135
136static ssize_t erst_dbg_write(struct file *filp, const char __user *ubuf,
137 size_t usize, loff_t *off)
138{
139 int rc;
140 struct cper_record_header *rcd;
141
142 if (!capable(CAP_SYS_ADMIN))
143 return -EPERM;
144
145 if (usize > ERST_DBG_RECORD_LEN_MAX) {
146 pr_err(ERST_DBG_PFX "Too long record to be written\n");
147 return -EINVAL;
148 }
149
150 if (mutex_lock_interruptible(&erst_dbg_mutex))
151 return -EINTR;
152 if (usize > erst_dbg_buf_len) {
153 kfree(erst_dbg_buf);
154 rc = -ENOMEM;
155 erst_dbg_buf = kmalloc(usize, GFP_KERNEL);
156 if (!erst_dbg_buf)
157 goto out;
158 erst_dbg_buf_len = usize;
159 }
160 rc = copy_from_user(erst_dbg_buf, ubuf, usize);
161 if (rc) {
162 rc = -EFAULT;
163 goto out;
164 }
165 rcd = erst_dbg_buf;
166 rc = -EINVAL;
167 if (rcd->record_length != usize)
168 goto out;
169
170 rc = erst_write(erst_dbg_buf);
171
172out:
173 mutex_unlock(&erst_dbg_mutex);
174 return rc < 0 ? rc : usize;
175}
176
177static const struct file_operations erst_dbg_ops = {
178 .owner = THIS_MODULE,
179 .open = erst_dbg_open,
180 .read = erst_dbg_read,
181 .write = erst_dbg_write,
182 .unlocked_ioctl = erst_dbg_ioctl,
183};
184
185static struct miscdevice erst_dbg_dev = {
186 .minor = MISC_DYNAMIC_MINOR,
187 .name = "erst_dbg",
188 .fops = &erst_dbg_ops,
189};
190
191static __init int erst_dbg_init(void)
192{
193 return misc_register(&erst_dbg_dev);
194}
195
196static __exit void erst_dbg_exit(void)
197{
198 misc_deregister(&erst_dbg_dev);
199 kfree(erst_dbg_buf);
200}
201
202module_init(erst_dbg_init);
203module_exit(erst_dbg_exit);
204
205MODULE_AUTHOR("Huang Ying");
206MODULE_DESCRIPTION("APEI Error Record Serialization Table debug support");
207MODULE_LICENSE("GPL");
diff --git a/drivers/acpi/apei/ghes.c b/drivers/acpi/apei/ghes.c
index fd0cc016a09..385a6059714 100644
--- a/drivers/acpi/apei/ghes.c
+++ b/drivers/acpi/apei/ghes.c
@@ -41,6 +41,8 @@
41#include <linux/interrupt.h> 41#include <linux/interrupt.h>
42#include <linux/cper.h> 42#include <linux/cper.h>
43#include <linux/kdebug.h> 43#include <linux/kdebug.h>
44#include <linux/platform_device.h>
45#include <linux/mutex.h>
44#include <acpi/apei.h> 46#include <acpi/apei.h>
45#include <acpi/atomicio.h> 47#include <acpi/atomicio.h>
46#include <acpi/hed.h> 48#include <acpi/hed.h>
@@ -87,6 +89,7 @@ struct ghes {
87 * used for that. 89 * used for that.
88 */ 90 */
89static LIST_HEAD(ghes_sci); 91static LIST_HEAD(ghes_sci);
92static DEFINE_MUTEX(ghes_list_mutex);
90 93
91static struct ghes *ghes_new(struct acpi_hest_generic *generic) 94static struct ghes *ghes_new(struct acpi_hest_generic *generic)
92{ 95{
@@ -132,26 +135,26 @@ static void ghes_fini(struct ghes *ghes)
132} 135}
133 136
134enum { 137enum {
135 GHES_SER_NO = 0x0, 138 GHES_SEV_NO = 0x0,
136 GHES_SER_CORRECTED = 0x1, 139 GHES_SEV_CORRECTED = 0x1,
137 GHES_SER_RECOVERABLE = 0x2, 140 GHES_SEV_RECOVERABLE = 0x2,
138 GHES_SER_PANIC = 0x3, 141 GHES_SEV_PANIC = 0x3,
139}; 142};
140 143
141static inline int ghes_severity(int severity) 144static inline int ghes_severity(int severity)
142{ 145{
143 switch (severity) { 146 switch (severity) {
144 case CPER_SER_INFORMATIONAL: 147 case CPER_SEV_INFORMATIONAL:
145 return GHES_SER_NO; 148 return GHES_SEV_NO;
146 case CPER_SER_CORRECTED: 149 case CPER_SEV_CORRECTED:
147 return GHES_SER_CORRECTED; 150 return GHES_SEV_CORRECTED;
148 case CPER_SER_RECOVERABLE: 151 case CPER_SEV_RECOVERABLE:
149 return GHES_SER_RECOVERABLE; 152 return GHES_SEV_RECOVERABLE;
150 case CPER_SER_FATAL: 153 case CPER_SEV_FATAL:
151 return GHES_SER_PANIC; 154 return GHES_SEV_PANIC;
152 default: 155 default:
153 /* Unkown, go panic */ 156 /* Unkown, go panic */
154 return GHES_SER_PANIC; 157 return GHES_SEV_PANIC;
155 } 158 }
156} 159}
157 160
@@ -237,16 +240,16 @@ static void ghes_clear_estatus(struct ghes *ghes)
237 240
238static void ghes_do_proc(struct ghes *ghes) 241static void ghes_do_proc(struct ghes *ghes)
239{ 242{
240 int ser, processed = 0; 243 int sev, processed = 0;
241 struct acpi_hest_generic_data *gdata; 244 struct acpi_hest_generic_data *gdata;
242 245
243 ser = ghes_severity(ghes->estatus->error_severity); 246 sev = ghes_severity(ghes->estatus->error_severity);
244 apei_estatus_for_each_section(ghes->estatus, gdata) { 247 apei_estatus_for_each_section(ghes->estatus, gdata) {
245#ifdef CONFIG_X86_MCE 248#ifdef CONFIG_X86_MCE
246 if (!uuid_le_cmp(*(uuid_le *)gdata->section_type, 249 if (!uuid_le_cmp(*(uuid_le *)gdata->section_type,
247 CPER_SEC_PLATFORM_MEM)) { 250 CPER_SEC_PLATFORM_MEM)) {
248 apei_mce_report_mem_error( 251 apei_mce_report_mem_error(
249 ser == GHES_SER_CORRECTED, 252 sev == GHES_SEV_CORRECTED,
250 (struct cper_sec_mem_err *)(gdata+1)); 253 (struct cper_sec_mem_err *)(gdata+1));
251 processed = 1; 254 processed = 1;
252 } 255 }
@@ -293,18 +296,15 @@ static struct notifier_block ghes_notifier_sci = {
293 .notifier_call = ghes_notify_sci, 296 .notifier_call = ghes_notify_sci,
294}; 297};
295 298
296static int hest_ghes_parse(struct acpi_hest_header *hest_hdr, void *data) 299static int __devinit ghes_probe(struct platform_device *ghes_dev)
297{ 300{
298 struct acpi_hest_generic *generic; 301 struct acpi_hest_generic *generic;
299 struct ghes *ghes = NULL; 302 struct ghes *ghes = NULL;
300 int rc = 0; 303 int rc = -EINVAL;
301 304
302 if (hest_hdr->type != ACPI_HEST_TYPE_GENERIC_ERROR) 305 generic = ghes_dev->dev.platform_data;
303 return 0;
304
305 generic = (struct acpi_hest_generic *)hest_hdr;
306 if (!generic->enabled) 306 if (!generic->enabled)
307 return 0; 307 return -ENODEV;
308 308
309 if (generic->error_block_length < 309 if (generic->error_block_length <
310 sizeof(struct acpi_hest_generic_status)) { 310 sizeof(struct acpi_hest_generic_status)) {
@@ -327,62 +327,91 @@ static int hest_ghes_parse(struct acpi_hest_header *hest_hdr, void *data)
327 ghes = NULL; 327 ghes = NULL;
328 goto err; 328 goto err;
329 } 329 }
330 switch (generic->notify.type) { 330 if (generic->notify.type == ACPI_HEST_NOTIFY_SCI) {
331 case ACPI_HEST_NOTIFY_POLLED: 331 mutex_lock(&ghes_list_mutex);
332 pr_warning(GHES_PFX
333"Generic hardware error source: %d notified via POLL is not supported!\n",
334 generic->header.source_id);
335 break;
336 case ACPI_HEST_NOTIFY_EXTERNAL:
337 case ACPI_HEST_NOTIFY_LOCAL:
338 pr_warning(GHES_PFX
339"Generic hardware error source: %d notified via IRQ is not supported!\n",
340 generic->header.source_id);
341 break;
342 case ACPI_HEST_NOTIFY_SCI:
343 if (list_empty(&ghes_sci)) 332 if (list_empty(&ghes_sci))
344 register_acpi_hed_notifier(&ghes_notifier_sci); 333 register_acpi_hed_notifier(&ghes_notifier_sci);
345 list_add_rcu(&ghes->list, &ghes_sci); 334 list_add_rcu(&ghes->list, &ghes_sci);
346 break; 335 mutex_unlock(&ghes_list_mutex);
347 case ACPI_HEST_NOTIFY_NMI: 336 } else {
348 pr_warning(GHES_PFX 337 unsigned char *notify = NULL;
349"Generic hardware error source: %d notified via NMI is not supported!\n", 338
350 generic->header.source_id); 339 switch (generic->notify.type) {
351 break; 340 case ACPI_HEST_NOTIFY_POLLED:
352 default: 341 notify = "POLL";
353 pr_warning(FW_WARN GHES_PFX 342 break;
354 "Unknown notification type: %u for generic hardware error source: %d\n", 343 case ACPI_HEST_NOTIFY_EXTERNAL:
355 generic->notify.type, generic->header.source_id); 344 case ACPI_HEST_NOTIFY_LOCAL:
356 break; 345 notify = "IRQ";
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;
357 } 362 }
363 platform_set_drvdata(ghes_dev, ghes);
358 364
359 return 0; 365 return 0;
360err: 366err:
361 if (ghes) 367 if (ghes) {
362 ghes_fini(ghes); 368 ghes_fini(ghes);
369 kfree(ghes);
370 }
363 return rc; 371 return rc;
364} 372}
365 373
366static void ghes_cleanup(void) 374static int __devexit ghes_remove(struct platform_device *ghes_dev)
367{ 375{
368 struct ghes *ghes, *nghes; 376 struct ghes *ghes;
377 struct acpi_hest_generic *generic;
369 378
370 if (!list_empty(&ghes_sci)) 379 ghes = platform_get_drvdata(ghes_dev);
371 unregister_acpi_hed_notifier(&ghes_notifier_sci); 380 generic = ghes->generic;
381
382 switch (generic->notify.type) {
383 case ACPI_HEST_NOTIFY_SCI:
384 mutex_lock(&ghes_list_mutex);
385 list_del_rcu(&ghes->list);
386 if (list_empty(&ghes_sci))
387 unregister_acpi_hed_notifier(&ghes_notifier_sci);
388 mutex_unlock(&ghes_list_mutex);
389 break;
390 default:
391 BUG();
392 break;
393 }
372 394
373 synchronize_rcu(); 395 synchronize_rcu();
396 ghes_fini(ghes);
397 kfree(ghes);
374 398
375 list_for_each_entry_safe(ghes, nghes, &ghes_sci, list) { 399 platform_set_drvdata(ghes_dev, NULL);
376 list_del(&ghes->list); 400
377 ghes_fini(ghes); 401 return 0;
378 kfree(ghes);
379 }
380} 402}
381 403
404static struct platform_driver ghes_platform_driver = {
405 .driver = {
406 .name = "GHES",
407 .owner = THIS_MODULE,
408 },
409 .probe = ghes_probe,
410 .remove = ghes_remove,
411};
412
382static int __init ghes_init(void) 413static int __init ghes_init(void)
383{ 414{
384 int rc;
385
386 if (acpi_disabled) 415 if (acpi_disabled)
387 return -ENODEV; 416 return -ENODEV;
388 417
@@ -391,32 +420,12 @@ static int __init ghes_init(void)
391 return -EINVAL; 420 return -EINVAL;
392 } 421 }
393 422
394 rc = apei_hest_parse(hest_ghes_parse, NULL); 423 return platform_driver_register(&ghes_platform_driver);
395 if (rc) {
396 pr_err(GHES_PFX
397 "Error during parsing HEST generic hardware error sources.\n");
398 goto err_cleanup;
399 }
400
401 if (list_empty(&ghes_sci)) {
402 pr_info(GHES_PFX
403 "No functional generic hardware error sources.\n");
404 rc = -ENODEV;
405 goto err_cleanup;
406 }
407
408 pr_info(GHES_PFX
409 "Generic Hardware Error Source support is initialized.\n");
410
411 return 0;
412err_cleanup:
413 ghes_cleanup();
414 return rc;
415} 424}
416 425
417static void __exit ghes_exit(void) 426static void __exit ghes_exit(void)
418{ 427{
419 ghes_cleanup(); 428 platform_driver_unregister(&ghes_platform_driver);
420} 429}
421 430
422module_init(ghes_init); 431module_init(ghes_init);
@@ -425,3 +434,4 @@ module_exit(ghes_exit);
425MODULE_AUTHOR("Huang Ying"); 434MODULE_AUTHOR("Huang Ying");
426MODULE_DESCRIPTION("APEI Generic Hardware Error Source support"); 435MODULE_DESCRIPTION("APEI Generic Hardware Error Source support");
427MODULE_LICENSE("GPL"); 436MODULE_LICENSE("GPL");
437MODULE_ALIAS("platform:GHES");
diff --git a/drivers/acpi/apei/hest.c b/drivers/acpi/apei/hest.c
index e7f40d362cb..343168d1826 100644
--- a/drivers/acpi/apei/hest.c
+++ b/drivers/acpi/apei/hest.c
@@ -34,6 +34,7 @@
34#include <linux/kdebug.h> 34#include <linux/kdebug.h>
35#include <linux/highmem.h> 35#include <linux/highmem.h>
36#include <linux/io.h> 36#include <linux/io.h>
37#include <linux/platform_device.h>
37#include <acpi/apei.h> 38#include <acpi/apei.h>
38 39
39#include "apei-internal.h" 40#include "apei-internal.h"
@@ -47,11 +48,6 @@ EXPORT_SYMBOL_GPL(hest_disable);
47 48
48static struct acpi_table_hest *hest_tab; 49static struct acpi_table_hest *hest_tab;
49 50
50static int hest_void_parse(struct acpi_hest_header *hest_hdr, void *data)
51{
52 return 0;
53}
54
55static int hest_esrc_len_tab[ACPI_HEST_TYPE_RESERVED] = { 51static int hest_esrc_len_tab[ACPI_HEST_TYPE_RESERVED] = {
56 [ACPI_HEST_TYPE_IA32_CHECK] = -1, /* need further calculation */ 52 [ACPI_HEST_TYPE_IA32_CHECK] = -1, /* need further calculation */
57 [ACPI_HEST_TYPE_IA32_CORRECTED_CHECK] = -1, 53 [ACPI_HEST_TYPE_IA32_CORRECTED_CHECK] = -1,
@@ -125,6 +121,69 @@ int apei_hest_parse(apei_hest_func_t func, void *data)
125} 121}
126EXPORT_SYMBOL_GPL(apei_hest_parse); 122EXPORT_SYMBOL_GPL(apei_hest_parse);
127 123
124struct ghes_arr {
125 struct platform_device **ghes_devs;
126 unsigned int count;
127};
128
129static int hest_parse_ghes_count(struct acpi_hest_header *hest_hdr, void *data)
130{
131 int *count = data;
132
133 if (hest_hdr->type == ACPI_HEST_TYPE_GENERIC_ERROR)
134 (*count)++;
135 return 0;
136}
137
138static int hest_parse_ghes(struct acpi_hest_header *hest_hdr, void *data)
139{
140 struct acpi_hest_generic *generic;
141 struct platform_device *ghes_dev;
142 struct ghes_arr *ghes_arr = data;
143 int rc;
144
145 if (hest_hdr->type != ACPI_HEST_TYPE_GENERIC_ERROR)
146 return 0;
147 generic = (struct acpi_hest_generic *)hest_hdr;
148 if (!generic->enabled)
149 return 0;
150 ghes_dev = platform_device_alloc("GHES", hest_hdr->source_id);
151 if (!ghes_dev)
152 return -ENOMEM;
153 ghes_dev->dev.platform_data = generic;
154 rc = platform_device_add(ghes_dev);
155 if (rc)
156 goto err;
157 ghes_arr->ghes_devs[ghes_arr->count++] = ghes_dev;
158
159 return 0;
160err:
161 platform_device_put(ghes_dev);
162 return rc;
163}
164
165static int hest_ghes_dev_register(unsigned int ghes_count)
166{
167 int rc, i;
168 struct ghes_arr ghes_arr;
169
170 ghes_arr.count = 0;
171 ghes_arr.ghes_devs = kmalloc(sizeof(void *) * ghes_count, GFP_KERNEL);
172 if (!ghes_arr.ghes_devs)
173 return -ENOMEM;
174
175 rc = apei_hest_parse(hest_parse_ghes, &ghes_arr);
176 if (rc)
177 goto err;
178out:
179 kfree(ghes_arr.ghes_devs);
180 return rc;
181err:
182 for (i = 0; i < ghes_arr.count; i++)
183 platform_device_unregister(ghes_arr.ghes_devs[i]);
184 goto out;
185}
186
128static int __init setup_hest_disable(char *str) 187static int __init setup_hest_disable(char *str)
129{ 188{
130 hest_disable = 1; 189 hest_disable = 1;
@@ -137,6 +196,7 @@ static int __init hest_init(void)
137{ 196{
138 acpi_status status; 197 acpi_status status;
139 int rc = -ENODEV; 198 int rc = -ENODEV;
199 unsigned int ghes_count = 0;
140 200
141 if (acpi_disabled) 201 if (acpi_disabled)
142 goto err; 202 goto err;
@@ -158,7 +218,11 @@ static int __init hest_init(void)
158 goto err; 218 goto err;
159 } 219 }
160 220
161 rc = apei_hest_parse(hest_void_parse, NULL); 221 rc = apei_hest_parse(hest_parse_ghes_count, &ghes_count);
222 if (rc)
223 goto err;
224
225 rc = hest_ghes_dev_register(ghes_count);
162 if (rc) 226 if (rc)
163 goto err; 227 goto err;
164 228
diff --git a/drivers/acpi/sleep.c b/drivers/acpi/sleep.c
index 2862c781b37..e4625f91981 100644
--- a/drivers/acpi/sleep.c
+++ b/drivers/acpi/sleep.c
@@ -70,10 +70,10 @@ static int acpi_sleep_prepare(u32 acpi_state)
70 70
71 } 71 }
72 ACPI_FLUSH_CPU_CACHE(); 72 ACPI_FLUSH_CPU_CACHE();
73 acpi_enable_wakeup_device_prep(acpi_state);
74#endif 73#endif
75 printk(KERN_INFO PREFIX "Preparing to enter system sleep state S%d\n", 74 printk(KERN_INFO PREFIX "Preparing to enter system sleep state S%d\n",
76 acpi_state); 75 acpi_state);
76 acpi_enable_wakeup_devices(acpi_state);
77 acpi_enter_sleep_state_prep(acpi_state); 77 acpi_enter_sleep_state_prep(acpi_state);
78 return 0; 78 return 0;
79} 79}
@@ -119,6 +119,16 @@ static int acpi_pm_freeze(void)
119} 119}
120 120
121/** 121/**
122 * acpi_pre_suspend - Enable wakeup devices, "freeze" EC and save NVS.
123 */
124static int acpi_pm_pre_suspend(void)
125{
126 acpi_pm_freeze();
127 suspend_nvs_save();
128 return 0;
129}
130
131/**
122 * __acpi_pm_prepare - Prepare the platform to enter the target state. 132 * __acpi_pm_prepare - Prepare the platform to enter the target state.
123 * 133 *
124 * If necessary, set the firmware waking vector and do arch-specific 134 * If necessary, set the firmware waking vector and do arch-specific
@@ -127,11 +137,9 @@ static int acpi_pm_freeze(void)
127static int __acpi_pm_prepare(void) 137static int __acpi_pm_prepare(void)
128{ 138{
129 int error = acpi_sleep_prepare(acpi_target_sleep_state); 139 int error = acpi_sleep_prepare(acpi_target_sleep_state);
130
131 suspend_nvs_save();
132
133 if (error) 140 if (error)
134 acpi_target_sleep_state = ACPI_STATE_S0; 141 acpi_target_sleep_state = ACPI_STATE_S0;
142
135 return error; 143 return error;
136} 144}
137 145
@@ -142,9 +150,8 @@ static int __acpi_pm_prepare(void)
142static int acpi_pm_prepare(void) 150static int acpi_pm_prepare(void)
143{ 151{
144 int error = __acpi_pm_prepare(); 152 int error = __acpi_pm_prepare();
145
146 if (!error) 153 if (!error)
147 acpi_pm_freeze(); 154 acpi_pm_pre_suspend();
148 155
149 return error; 156 return error;
150} 157}
@@ -159,7 +166,6 @@ static void acpi_pm_finish(void)
159{ 166{
160 u32 acpi_state = acpi_target_sleep_state; 167 u32 acpi_state = acpi_target_sleep_state;
161 168
162 suspend_nvs_free();
163 acpi_ec_unblock_transactions(); 169 acpi_ec_unblock_transactions();
164 170
165 if (acpi_state == ACPI_STATE_S0) 171 if (acpi_state == ACPI_STATE_S0)
@@ -167,7 +173,7 @@ static void acpi_pm_finish(void)
167 173
168 printk(KERN_INFO PREFIX "Waking up from system sleep state S%d\n", 174 printk(KERN_INFO PREFIX "Waking up from system sleep state S%d\n",
169 acpi_state); 175 acpi_state);
170 acpi_disable_wakeup_device(acpi_state); 176 acpi_disable_wakeup_devices(acpi_state);
171 acpi_leave_sleep_state(acpi_state); 177 acpi_leave_sleep_state(acpi_state);
172 178
173 /* reset firmware waking vector */ 179 /* reset firmware waking vector */
@@ -181,6 +187,7 @@ static void acpi_pm_finish(void)
181 */ 187 */
182static void acpi_pm_end(void) 188static void acpi_pm_end(void)
183{ 189{
190 suspend_nvs_free();
184 /* 191 /*
185 * This is necessary in case acpi_pm_finish() is not called during a 192 * This is necessary in case acpi_pm_finish() is not called during a
186 * failing transition to a sleep state. 193 * failing transition to a sleep state.
@@ -251,7 +258,6 @@ static int acpi_suspend_enter(suspend_state_t pm_state)
251 } 258 }
252 259
253 local_irq_save(flags); 260 local_irq_save(flags);
254 acpi_enable_wakeup_device(acpi_state);
255 switch (acpi_state) { 261 switch (acpi_state) {
256 case ACPI_STATE_S1: 262 case ACPI_STATE_S1:
257 barrier(); 263 barrier();
@@ -297,11 +303,6 @@ static int acpi_suspend_enter(suspend_state_t pm_state)
297 return ACPI_SUCCESS(status) ? 0 : -EFAULT; 303 return ACPI_SUCCESS(status) ? 0 : -EFAULT;
298} 304}
299 305
300static void acpi_suspend_finish(void)
301{
302 acpi_pm_finish();
303}
304
305static int acpi_suspend_state_valid(suspend_state_t pm_state) 306static int acpi_suspend_state_valid(suspend_state_t pm_state)
306{ 307{
307 u32 acpi_state; 308 u32 acpi_state;
@@ -323,7 +324,7 @@ static struct platform_suspend_ops acpi_suspend_ops = {
323 .begin = acpi_suspend_begin, 324 .begin = acpi_suspend_begin,
324 .prepare_late = acpi_pm_prepare, 325 .prepare_late = acpi_pm_prepare,
325 .enter = acpi_suspend_enter, 326 .enter = acpi_suspend_enter,
326 .wake = acpi_suspend_finish, 327 .wake = acpi_pm_finish,
327 .end = acpi_pm_end, 328 .end = acpi_pm_end,
328}; 329};
329 330
@@ -336,9 +337,9 @@ static struct platform_suspend_ops acpi_suspend_ops = {
336static int acpi_suspend_begin_old(suspend_state_t pm_state) 337static int acpi_suspend_begin_old(suspend_state_t pm_state)
337{ 338{
338 int error = acpi_suspend_begin(pm_state); 339 int error = acpi_suspend_begin(pm_state);
339
340 if (!error) 340 if (!error)
341 error = __acpi_pm_prepare(); 341 error = __acpi_pm_prepare();
342
342 return error; 343 return error;
343} 344}
344 345
@@ -349,9 +350,9 @@ static int acpi_suspend_begin_old(suspend_state_t pm_state)
349static struct platform_suspend_ops acpi_suspend_ops_old = { 350static struct platform_suspend_ops acpi_suspend_ops_old = {
350 .valid = acpi_suspend_state_valid, 351 .valid = acpi_suspend_state_valid,
351 .begin = acpi_suspend_begin_old, 352 .begin = acpi_suspend_begin_old,
352 .prepare_late = acpi_pm_freeze, 353 .prepare_late = acpi_pm_pre_suspend,
353 .enter = acpi_suspend_enter, 354 .enter = acpi_suspend_enter,
354 .wake = acpi_suspend_finish, 355 .wake = acpi_pm_finish,
355 .end = acpi_pm_end, 356 .end = acpi_pm_end,
356 .recover = acpi_pm_finish, 357 .recover = acpi_pm_finish,
357}; 358};
@@ -423,16 +424,6 @@ static int acpi_hibernation_begin(void)
423 return error; 424 return error;
424} 425}
425 426
426static int acpi_hibernation_pre_snapshot(void)
427{
428 int error = acpi_pm_prepare();
429
430 if (!error)
431 suspend_nvs_save();
432
433 return error;
434}
435
436static int acpi_hibernation_enter(void) 427static int acpi_hibernation_enter(void)
437{ 428{
438 acpi_status status = AE_OK; 429 acpi_status status = AE_OK;
@@ -441,7 +432,6 @@ static int acpi_hibernation_enter(void)
441 ACPI_FLUSH_CPU_CACHE(); 432 ACPI_FLUSH_CPU_CACHE();
442 433
443 local_irq_save(flags); 434 local_irq_save(flags);
444 acpi_enable_wakeup_device(ACPI_STATE_S4);
445 /* This shouldn't return. If it returns, we have a problem */ 435 /* This shouldn't return. If it returns, we have a problem */
446 status = acpi_enter_sleep_state(ACPI_STATE_S4); 436 status = acpi_enter_sleep_state(ACPI_STATE_S4);
447 /* Reprogram control registers and execute _BFS */ 437 /* Reprogram control registers and execute _BFS */
@@ -481,7 +471,7 @@ static void acpi_pm_thaw(void)
481static struct platform_hibernation_ops acpi_hibernation_ops = { 471static struct platform_hibernation_ops acpi_hibernation_ops = {
482 .begin = acpi_hibernation_begin, 472 .begin = acpi_hibernation_begin,
483 .end = acpi_pm_end, 473 .end = acpi_pm_end,
484 .pre_snapshot = acpi_hibernation_pre_snapshot, 474 .pre_snapshot = acpi_pm_prepare,
485 .finish = acpi_pm_finish, 475 .finish = acpi_pm_finish,
486 .prepare = acpi_pm_prepare, 476 .prepare = acpi_pm_prepare,
487 .enter = acpi_hibernation_enter, 477 .enter = acpi_hibernation_enter,
@@ -517,13 +507,6 @@ static int acpi_hibernation_begin_old(void)
517 return error; 507 return error;
518} 508}
519 509
520static int acpi_hibernation_pre_snapshot_old(void)
521{
522 acpi_pm_freeze();
523 suspend_nvs_save();
524 return 0;
525}
526
527/* 510/*
528 * The following callbacks are used if the pre-ACPI 2.0 suspend ordering has 511 * The following callbacks are used if the pre-ACPI 2.0 suspend ordering has
529 * been requested. 512 * been requested.
@@ -531,7 +514,7 @@ static int acpi_hibernation_pre_snapshot_old(void)
531static struct platform_hibernation_ops acpi_hibernation_ops_old = { 514static struct platform_hibernation_ops acpi_hibernation_ops_old = {
532 .begin = acpi_hibernation_begin_old, 515 .begin = acpi_hibernation_begin_old,
533 .end = acpi_pm_end, 516 .end = acpi_pm_end,
534 .pre_snapshot = acpi_hibernation_pre_snapshot_old, 517 .pre_snapshot = acpi_pm_pre_suspend,
535 .prepare = acpi_pm_freeze, 518 .prepare = acpi_pm_freeze,
536 .finish = acpi_pm_finish, 519 .finish = acpi_pm_finish,
537 .enter = acpi_hibernation_enter, 520 .enter = acpi_hibernation_enter,
@@ -695,7 +678,6 @@ static void acpi_power_off(void)
695 /* acpi_sleep_prepare(ACPI_STATE_S5) should have already been called */ 678 /* acpi_sleep_prepare(ACPI_STATE_S5) should have already been called */
696 printk(KERN_DEBUG "%s called\n", __func__); 679 printk(KERN_DEBUG "%s called\n", __func__);
697 local_irq_disable(); 680 local_irq_disable();
698 acpi_enable_wakeup_device(ACPI_STATE_S5);
699 acpi_enter_sleep_state(ACPI_STATE_S5); 681 acpi_enter_sleep_state(ACPI_STATE_S5);
700} 682}
701 683
diff --git a/drivers/acpi/sleep.h b/drivers/acpi/sleep.h
index 25b8bd14928..d8821805c3b 100644
--- a/drivers/acpi/sleep.h
+++ b/drivers/acpi/sleep.h
@@ -2,9 +2,8 @@
2extern u8 sleep_states[]; 2extern u8 sleep_states[];
3extern int acpi_suspend(u32 state); 3extern int acpi_suspend(u32 state);
4 4
5extern void acpi_enable_wakeup_device_prep(u8 sleep_state); 5extern void acpi_enable_wakeup_devices(u8 sleep_state);
6extern void acpi_enable_wakeup_device(u8 sleep_state); 6extern void acpi_disable_wakeup_devices(u8 sleep_state);
7extern void acpi_disable_wakeup_device(u8 sleep_state);
8 7
9extern struct list_head acpi_wakeup_device_list; 8extern struct list_head acpi_wakeup_device_list;
10extern struct mutex acpi_device_lock; 9extern struct mutex acpi_device_lock;
diff --git a/drivers/acpi/wakeup.c b/drivers/acpi/wakeup.c
index 388747a7ef4..dc6d1d9112f 100644
--- a/drivers/acpi/wakeup.c
+++ b/drivers/acpi/wakeup.c
@@ -21,46 +21,18 @@
21ACPI_MODULE_NAME("wakeup_devices") 21ACPI_MODULE_NAME("wakeup_devices")
22 22
23/** 23/**
24 * acpi_enable_wakeup_device_prep - Prepare wake-up devices. 24 * acpi_enable_wakeup_devices - Enable wake-up device GPEs.
25 * @sleep_state: ACPI system sleep state. 25 * @sleep_state: ACPI system sleep state.
26 * 26 *
27 * Enable all wake-up devices' power, unless the requested system sleep state is 27 * Enable wakeup device power of devices with the state.enable flag set and set
28 * too deep. 28 * the wakeup enable mask bits in the GPE registers that correspond to wakeup
29 * devices.
29 */ 30 */
30void acpi_enable_wakeup_device_prep(u8 sleep_state) 31void acpi_enable_wakeup_devices(u8 sleep_state)
31{ 32{
32 struct list_head *node, *next; 33 struct list_head *node, *next;
33 34
34 list_for_each_safe(node, next, &acpi_wakeup_device_list) { 35 list_for_each_safe(node, next, &acpi_wakeup_device_list) {
35 struct acpi_device *dev = container_of(node,
36 struct acpi_device,
37 wakeup_list);
38
39 if (!dev->wakeup.flags.valid || !dev->wakeup.state.enabled
40 || (sleep_state > (u32) dev->wakeup.sleep_state))
41 continue;
42
43 acpi_enable_wakeup_device_power(dev, sleep_state);
44 }
45}
46
47/**
48 * acpi_enable_wakeup_device - Enable wake-up device GPEs.
49 * @sleep_state: ACPI system sleep state.
50 *
51 * Enable all wake-up devices' GPEs, with the assumption that
52 * acpi_disable_all_gpes() was executed before, so we don't need to disable any
53 * GPEs here.
54 */
55void acpi_enable_wakeup_device(u8 sleep_state)
56{
57 struct list_head *node, *next;
58
59 /*
60 * Caution: this routine must be invoked when interrupt is disabled
61 * Refer ACPI2.0: P212
62 */
63 list_for_each_safe(node, next, &acpi_wakeup_device_list) {
64 struct acpi_device *dev = 36 struct acpi_device *dev =
65 container_of(node, struct acpi_device, wakeup_list); 37 container_of(node, struct acpi_device, wakeup_list);
66 38
@@ -68,6 +40,9 @@ void acpi_enable_wakeup_device(u8 sleep_state)
68 || sleep_state > (u32) dev->wakeup.sleep_state) 40 || sleep_state > (u32) dev->wakeup.sleep_state)
69 continue; 41 continue;
70 42
43 if (dev->wakeup.state.enabled)
44 acpi_enable_wakeup_device_power(dev, sleep_state);
45
71 /* The wake-up power should have been enabled already. */ 46 /* The wake-up power should have been enabled already. */
72 acpi_enable_gpe(dev->wakeup.gpe_device, dev->wakeup.gpe_number, 47 acpi_enable_gpe(dev->wakeup.gpe_device, dev->wakeup.gpe_number,
73 ACPI_GPE_TYPE_WAKE); 48 ACPI_GPE_TYPE_WAKE);
@@ -75,13 +50,10 @@ void acpi_enable_wakeup_device(u8 sleep_state)
75} 50}
76 51
77/** 52/**
78 * acpi_disable_wakeup_device - Disable devices' wakeup capability. 53 * acpi_disable_wakeup_devices - Disable devices' wakeup capability.
79 * @sleep_state: ACPI system sleep state. 54 * @sleep_state: ACPI system sleep state.
80 *
81 * This function only affects devices with wakeup.state.enabled set, which means
82 * that it reverses the changes made by acpi_enable_wakeup_device_prep().
83 */ 55 */
84void acpi_disable_wakeup_device(u8 sleep_state) 56void acpi_disable_wakeup_devices(u8 sleep_state)
85{ 57{
86 struct list_head *node, *next; 58 struct list_head *node, *next;
87 59