diff --git a/[refs] b/[refs] index 8944c94499eb..7a746c8b8c89 100644 --- a/[refs] +++ b/[refs] @@ -1,2 +1,2 @@ --- -refs/heads/master: feb29c5175e61d0f1ec2cbcaccdfa55e588780be +refs/heads/master: a25ee9200eef07377e1703697afbb5d81f89e500 diff --git a/trunk/arch/x86/kernel/cpu/mcheck/mce-apei.c b/trunk/arch/x86/kernel/cpu/mcheck/mce-apei.c index 8209472b27a5..745b54f9be89 100644 --- a/trunk/arch/x86/kernel/cpu/mcheck/mce-apei.c +++ b/trunk/arch/x86/kernel/cpu/mcheck/mce-apei.c @@ -80,7 +80,7 @@ int apei_write_mce(struct mce *m) rcd.hdr.revision = CPER_RECORD_REV; rcd.hdr.signature_end = CPER_SIG_END; rcd.hdr.section_count = 1; - rcd.hdr.error_severity = CPER_SEV_FATAL; + rcd.hdr.error_severity = CPER_SER_FATAL; /* timestamp, platform_id, partition_id are all invalid */ rcd.hdr.validation_bits = 0; rcd.hdr.record_length = sizeof(rcd); @@ -96,7 +96,7 @@ int apei_write_mce(struct mce *m) rcd.sec_hdr.validation_bits = 0; rcd.sec_hdr.flags = CPER_SEC_PRIMARY; rcd.sec_hdr.section_type = CPER_SECTION_TYPE_MCE; - rcd.sec_hdr.section_severity = CPER_SEV_FATAL; + rcd.sec_hdr.section_severity = CPER_SER_FATAL; memcpy(&rcd.mce, m, sizeof(*m)); diff --git a/trunk/drivers/acpi/Makefile b/trunk/drivers/acpi/Makefile index 6ee33169e1dc..7891904419fc 100644 --- a/trunk/drivers/acpi/Makefile +++ b/trunk/drivers/acpi/Makefile @@ -39,6 +39,7 @@ acpi-y += pci_root.o pci_link.o pci_irq.o pci_bind.o acpi-y += power.o acpi-y += system.o event.o acpi-$(CONFIG_ACPI_DEBUG) += debug.o +acpi-$(CONFIG_DEBUG_FS) += debugfs.o acpi-$(CONFIG_ACPI_NUMA) += numa.o acpi-$(CONFIG_ACPI_PROCFS_POWER) += cm_sbs.o ifdef CONFIG_ACPI_VIDEO diff --git a/trunk/drivers/acpi/apei/Kconfig b/trunk/drivers/acpi/apei/Kconfig index 907e350f1c7d..f8c668f27b5a 100644 --- a/trunk/drivers/acpi/apei/Kconfig +++ b/trunk/drivers/acpi/apei/Kconfig @@ -28,12 +28,3 @@ config ACPI_APEI_EINJ EINJ provides a hardware error injection mechanism, it is mainly used for debugging and testing the other parts of APEI and some other RAS features. - -config ACPI_APEI_ERST_DEBUG - tristate "APEI Error Record Serialization Table (ERST) Debug Support" - depends on ACPI_APEI - help - ERST is a way provided by APEI to save and retrieve hardware - error infomation to and from a persistent store. Enable this - if you want to debugging and testing the ERST kernel support - and firmware implementation. diff --git a/trunk/drivers/acpi/apei/Makefile b/trunk/drivers/acpi/apei/Makefile index d1d1bc0a4ee1..b13b03a17789 100644 --- a/trunk/drivers/acpi/apei/Makefile +++ b/trunk/drivers/acpi/apei/Makefile @@ -1,6 +1,5 @@ obj-$(CONFIG_ACPI_APEI) += apei.o obj-$(CONFIG_ACPI_APEI_GHES) += ghes.o obj-$(CONFIG_ACPI_APEI_EINJ) += einj.o -obj-$(CONFIG_ACPI_APEI_ERST_DEBUG) += erst-dbg.o apei-y := apei-base.o hest.o cper.o erst.o diff --git a/trunk/drivers/acpi/apei/apei-base.c b/trunk/drivers/acpi/apei/apei-base.c index 73fd0c7487c1..216e1e948ff6 100644 --- a/trunk/drivers/acpi/apei/apei-base.c +++ b/trunk/drivers/acpi/apei/apei-base.c @@ -482,14 +482,14 @@ int apei_resources_request(struct apei_resources *resources, list_for_each_entry(res, &resources->ioport, list) { if (res == res_bak) break; - release_region(res->start, res->end - res->start); + release_mem_region(res->start, res->end - res->start); } res_bak = NULL; err_unmap_iomem: list_for_each_entry(res, &resources->iomem, list) { if (res == res_bak) break; - release_mem_region(res->start, res->end - res->start); + release_region(res->start, res->end - res->start); } return -EINVAL; } diff --git a/trunk/drivers/acpi/apei/erst-dbg.c b/trunk/drivers/acpi/apei/erst-dbg.c deleted file mode 100644 index 5281ddda2777..000000000000 --- a/trunk/drivers/acpi/apei/erst-dbg.c +++ /dev/null @@ -1,207 +0,0 @@ -/* - * APEI Error Record Serialization Table debug support - * - * ERST is a way provided by APEI to save and retrieve hardware error - * infomation to and from a persistent store. This file provide the - * debugging/testing support for ERST kernel support and firmware - * implementation. - * - * Copyright 2010 Intel Corp. - * Author: Huang Ying - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License version - * 2 as published by the Free Software Foundation. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - */ - -#include -#include -#include -#include -#include - -#include "apei-internal.h" - -#define ERST_DBG_PFX "ERST DBG: " - -#define ERST_DBG_RECORD_LEN_MAX 4096 - -static void *erst_dbg_buf; -static unsigned int erst_dbg_buf_len; - -/* Prevent erst_dbg_read/write from being invoked concurrently */ -static DEFINE_MUTEX(erst_dbg_mutex); - -static int erst_dbg_open(struct inode *inode, struct file *file) -{ - if (erst_disable) - return -ENODEV; - - return nonseekable_open(inode, file); -} - -static long erst_dbg_ioctl(struct file *f, unsigned int cmd, unsigned long arg) -{ - int rc; - u64 record_id; - u32 record_count; - - switch (cmd) { - case APEI_ERST_CLEAR_RECORD: - rc = copy_from_user(&record_id, (void __user *)arg, - sizeof(record_id)); - if (rc) - return -EFAULT; - return erst_clear(record_id); - case APEI_ERST_GET_RECORD_COUNT: - rc = erst_get_record_count(); - if (rc < 0) - return rc; - record_count = rc; - rc = put_user(record_count, (u32 __user *)arg); - if (rc) - return rc; - return 0; - default: - return -ENOTTY; - } -} - -static ssize_t erst_dbg_read(struct file *filp, char __user *ubuf, - size_t usize, loff_t *off) -{ - int rc; - ssize_t len = 0; - u64 id; - - if (*off != 0) - return -EINVAL; - - if (mutex_lock_interruptible(&erst_dbg_mutex) != 0) - return -EINTR; - -retry_next: - rc = erst_get_next_record_id(&id); - if (rc) - goto out; - /* no more record */ - if (id == APEI_ERST_INVALID_RECORD_ID) - goto out; -retry: - rc = len = erst_read(id, erst_dbg_buf, erst_dbg_buf_len); - /* The record may be cleared by others, try read next record */ - if (rc == -ENOENT) - goto retry_next; - if (rc < 0) - goto out; - if (len > ERST_DBG_RECORD_LEN_MAX) { - pr_warning(ERST_DBG_PFX - "Record (ID: 0x%llx) length is too long: %zd\n", - id, len); - rc = -EIO; - goto out; - } - if (len > erst_dbg_buf_len) { - kfree(erst_dbg_buf); - rc = -ENOMEM; - erst_dbg_buf = kmalloc(len, GFP_KERNEL); - if (!erst_dbg_buf) - goto out; - erst_dbg_buf_len = len; - goto retry; - } - - rc = -EINVAL; - if (len > usize) - goto out; - - rc = -EFAULT; - if (copy_to_user(ubuf, erst_dbg_buf, len)) - goto out; - rc = 0; -out: - mutex_unlock(&erst_dbg_mutex); - return rc ? rc : len; -} - -static ssize_t erst_dbg_write(struct file *filp, const char __user *ubuf, - size_t usize, loff_t *off) -{ - int rc; - struct cper_record_header *rcd; - - if (!capable(CAP_SYS_ADMIN)) - return -EPERM; - - if (usize > ERST_DBG_RECORD_LEN_MAX) { - pr_err(ERST_DBG_PFX "Too long record to be written\n"); - return -EINVAL; - } - - if (mutex_lock_interruptible(&erst_dbg_mutex)) - return -EINTR; - if (usize > erst_dbg_buf_len) { - kfree(erst_dbg_buf); - rc = -ENOMEM; - erst_dbg_buf = kmalloc(usize, GFP_KERNEL); - if (!erst_dbg_buf) - goto out; - erst_dbg_buf_len = usize; - } - rc = copy_from_user(erst_dbg_buf, ubuf, usize); - if (rc) { - rc = -EFAULT; - goto out; - } - rcd = erst_dbg_buf; - rc = -EINVAL; - if (rcd->record_length != usize) - goto out; - - rc = erst_write(erst_dbg_buf); - -out: - mutex_unlock(&erst_dbg_mutex); - return rc < 0 ? rc : usize; -} - -static const struct file_operations erst_dbg_ops = { - .owner = THIS_MODULE, - .open = erst_dbg_open, - .read = erst_dbg_read, - .write = erst_dbg_write, - .unlocked_ioctl = erst_dbg_ioctl, -}; - -static struct miscdevice erst_dbg_dev = { - .minor = MISC_DYNAMIC_MINOR, - .name = "erst_dbg", - .fops = &erst_dbg_ops, -}; - -static __init int erst_dbg_init(void) -{ - return misc_register(&erst_dbg_dev); -} - -static __exit void erst_dbg_exit(void) -{ - misc_deregister(&erst_dbg_dev); - kfree(erst_dbg_buf); -} - -module_init(erst_dbg_init); -module_exit(erst_dbg_exit); - -MODULE_AUTHOR("Huang Ying"); -MODULE_DESCRIPTION("APEI Error Record Serialization Table debug support"); -MODULE_LICENSE("GPL"); diff --git a/trunk/drivers/acpi/apei/ghes.c b/trunk/drivers/acpi/apei/ghes.c index 385a6059714a..fd0cc016a099 100644 --- a/trunk/drivers/acpi/apei/ghes.c +++ b/trunk/drivers/acpi/apei/ghes.c @@ -41,8 +41,6 @@ #include #include #include -#include -#include #include #include #include @@ -89,7 +87,6 @@ struct ghes { * used for that. */ static LIST_HEAD(ghes_sci); -static DEFINE_MUTEX(ghes_list_mutex); static struct ghes *ghes_new(struct acpi_hest_generic *generic) { @@ -135,26 +132,26 @@ static void ghes_fini(struct ghes *ghes) } enum { - GHES_SEV_NO = 0x0, - GHES_SEV_CORRECTED = 0x1, - GHES_SEV_RECOVERABLE = 0x2, - GHES_SEV_PANIC = 0x3, + GHES_SER_NO = 0x0, + GHES_SER_CORRECTED = 0x1, + GHES_SER_RECOVERABLE = 0x2, + GHES_SER_PANIC = 0x3, }; static inline int ghes_severity(int severity) { switch (severity) { - case CPER_SEV_INFORMATIONAL: - return GHES_SEV_NO; - case CPER_SEV_CORRECTED: - return GHES_SEV_CORRECTED; - case CPER_SEV_RECOVERABLE: - return GHES_SEV_RECOVERABLE; - case CPER_SEV_FATAL: - return GHES_SEV_PANIC; + case CPER_SER_INFORMATIONAL: + return GHES_SER_NO; + case CPER_SER_CORRECTED: + return GHES_SER_CORRECTED; + case CPER_SER_RECOVERABLE: + return GHES_SER_RECOVERABLE; + case CPER_SER_FATAL: + return GHES_SER_PANIC; default: /* Unkown, go panic */ - return GHES_SEV_PANIC; + return GHES_SER_PANIC; } } @@ -240,16 +237,16 @@ static void ghes_clear_estatus(struct ghes *ghes) static void ghes_do_proc(struct ghes *ghes) { - int sev, processed = 0; + int ser, processed = 0; struct acpi_hest_generic_data *gdata; - sev = ghes_severity(ghes->estatus->error_severity); + ser = ghes_severity(ghes->estatus->error_severity); apei_estatus_for_each_section(ghes->estatus, gdata) { #ifdef CONFIG_X86_MCE if (!uuid_le_cmp(*(uuid_le *)gdata->section_type, CPER_SEC_PLATFORM_MEM)) { apei_mce_report_mem_error( - sev == GHES_SEV_CORRECTED, + ser == GHES_SER_CORRECTED, (struct cper_sec_mem_err *)(gdata+1)); processed = 1; } @@ -296,15 +293,18 @@ static struct notifier_block ghes_notifier_sci = { .notifier_call = ghes_notify_sci, }; -static int __devinit ghes_probe(struct platform_device *ghes_dev) +static int hest_ghes_parse(struct acpi_hest_header *hest_hdr, void *data) { struct acpi_hest_generic *generic; struct ghes *ghes = NULL; - int rc = -EINVAL; + int rc = 0; - generic = ghes_dev->dev.platform_data; + if (hest_hdr->type != ACPI_HEST_TYPE_GENERIC_ERROR) + return 0; + + generic = (struct acpi_hest_generic *)hest_hdr; if (!generic->enabled) - return -ENODEV; + return 0; if (generic->error_block_length < sizeof(struct acpi_hest_generic_status)) { @@ -327,91 +327,62 @@ static int __devinit ghes_probe(struct platform_device *ghes_dev) ghes = NULL; goto err; } - if (generic->notify.type == ACPI_HEST_NOTIFY_SCI) { - mutex_lock(&ghes_list_mutex); + switch (generic->notify.type) { + case ACPI_HEST_NOTIFY_POLLED: + pr_warning(GHES_PFX +"Generic hardware error source: %d notified via POLL is not supported!\n", + generic->header.source_id); + break; + case ACPI_HEST_NOTIFY_EXTERNAL: + case ACPI_HEST_NOTIFY_LOCAL: + pr_warning(GHES_PFX +"Generic hardware error source: %d notified via IRQ is not supported!\n", + generic->header.source_id); + break; + case ACPI_HEST_NOTIFY_SCI: if (list_empty(&ghes_sci)) register_acpi_hed_notifier(&ghes_notifier_sci); list_add_rcu(&ghes->list, &ghes_sci); - mutex_unlock(&ghes_list_mutex); - } else { - unsigned char *notify = NULL; - - switch (generic->notify.type) { - case ACPI_HEST_NOTIFY_POLLED: - notify = "POLL"; - break; - case ACPI_HEST_NOTIFY_EXTERNAL: - case ACPI_HEST_NOTIFY_LOCAL: - notify = "IRQ"; - break; - case ACPI_HEST_NOTIFY_NMI: - notify = "NMI"; - break; - } - if (notify) { - pr_warning(GHES_PFX -"Generic hardware error source: %d notified via %s is not supported!\n", - generic->header.source_id, notify); - } else { - pr_warning(FW_WARN GHES_PFX -"Unknown notification type: %u for generic hardware error source: %d\n", - generic->notify.type, generic->header.source_id); - } - rc = -ENODEV; - goto err; + break; + case ACPI_HEST_NOTIFY_NMI: + pr_warning(GHES_PFX +"Generic hardware error source: %d notified via NMI is not supported!\n", + generic->header.source_id); + break; + default: + pr_warning(FW_WARN GHES_PFX + "Unknown notification type: %u for generic hardware error source: %d\n", + generic->notify.type, generic->header.source_id); + break; } - platform_set_drvdata(ghes_dev, ghes); return 0; err: - if (ghes) { + if (ghes) ghes_fini(ghes); - kfree(ghes); - } return rc; } -static int __devexit ghes_remove(struct platform_device *ghes_dev) +static void ghes_cleanup(void) { - struct ghes *ghes; - struct acpi_hest_generic *generic; + struct ghes *ghes, *nghes; - ghes = platform_get_drvdata(ghes_dev); - generic = ghes->generic; - - switch (generic->notify.type) { - case ACPI_HEST_NOTIFY_SCI: - mutex_lock(&ghes_list_mutex); - list_del_rcu(&ghes->list); - if (list_empty(&ghes_sci)) - unregister_acpi_hed_notifier(&ghes_notifier_sci); - mutex_unlock(&ghes_list_mutex); - break; - default: - BUG(); - break; - } + if (!list_empty(&ghes_sci)) + unregister_acpi_hed_notifier(&ghes_notifier_sci); synchronize_rcu(); - ghes_fini(ghes); - kfree(ghes); - - platform_set_drvdata(ghes_dev, NULL); - return 0; + list_for_each_entry_safe(ghes, nghes, &ghes_sci, list) { + list_del(&ghes->list); + ghes_fini(ghes); + kfree(ghes); + } } -static struct platform_driver ghes_platform_driver = { - .driver = { - .name = "GHES", - .owner = THIS_MODULE, - }, - .probe = ghes_probe, - .remove = ghes_remove, -}; - static int __init ghes_init(void) { + int rc; + if (acpi_disabled) return -ENODEV; @@ -420,12 +391,32 @@ static int __init ghes_init(void) return -EINVAL; } - return platform_driver_register(&ghes_platform_driver); + rc = apei_hest_parse(hest_ghes_parse, NULL); + if (rc) { + pr_err(GHES_PFX + "Error during parsing HEST generic hardware error sources.\n"); + goto err_cleanup; + } + + if (list_empty(&ghes_sci)) { + pr_info(GHES_PFX + "No functional generic hardware error sources.\n"); + rc = -ENODEV; + goto err_cleanup; + } + + pr_info(GHES_PFX + "Generic Hardware Error Source support is initialized.\n"); + + return 0; +err_cleanup: + ghes_cleanup(); + return rc; } static void __exit ghes_exit(void) { - platform_driver_unregister(&ghes_platform_driver); + ghes_cleanup(); } module_init(ghes_init); @@ -434,4 +425,3 @@ module_exit(ghes_exit); MODULE_AUTHOR("Huang Ying"); MODULE_DESCRIPTION("APEI Generic Hardware Error Source support"); MODULE_LICENSE("GPL"); -MODULE_ALIAS("platform:GHES"); diff --git a/trunk/drivers/acpi/apei/hest.c b/trunk/drivers/acpi/apei/hest.c index 343168d18266..e7f40d362cb3 100644 --- a/trunk/drivers/acpi/apei/hest.c +++ b/trunk/drivers/acpi/apei/hest.c @@ -34,7 +34,6 @@ #include #include #include -#include #include #include "apei-internal.h" @@ -48,6 +47,11 @@ EXPORT_SYMBOL_GPL(hest_disable); static struct acpi_table_hest *hest_tab; +static int hest_void_parse(struct acpi_hest_header *hest_hdr, void *data) +{ + return 0; +} + static int hest_esrc_len_tab[ACPI_HEST_TYPE_RESERVED] = { [ACPI_HEST_TYPE_IA32_CHECK] = -1, /* need further calculation */ [ACPI_HEST_TYPE_IA32_CORRECTED_CHECK] = -1, @@ -121,69 +125,6 @@ int apei_hest_parse(apei_hest_func_t func, void *data) } EXPORT_SYMBOL_GPL(apei_hest_parse); -struct ghes_arr { - struct platform_device **ghes_devs; - unsigned int count; -}; - -static int hest_parse_ghes_count(struct acpi_hest_header *hest_hdr, void *data) -{ - int *count = data; - - if (hest_hdr->type == ACPI_HEST_TYPE_GENERIC_ERROR) - (*count)++; - return 0; -} - -static int hest_parse_ghes(struct acpi_hest_header *hest_hdr, void *data) -{ - struct acpi_hest_generic *generic; - struct platform_device *ghes_dev; - struct ghes_arr *ghes_arr = data; - int rc; - - if (hest_hdr->type != ACPI_HEST_TYPE_GENERIC_ERROR) - return 0; - generic = (struct acpi_hest_generic *)hest_hdr; - if (!generic->enabled) - return 0; - ghes_dev = platform_device_alloc("GHES", hest_hdr->source_id); - if (!ghes_dev) - return -ENOMEM; - ghes_dev->dev.platform_data = generic; - rc = platform_device_add(ghes_dev); - if (rc) - goto err; - ghes_arr->ghes_devs[ghes_arr->count++] = ghes_dev; - - return 0; -err: - platform_device_put(ghes_dev); - return rc; -} - -static int hest_ghes_dev_register(unsigned int ghes_count) -{ - int rc, i; - struct ghes_arr ghes_arr; - - ghes_arr.count = 0; - ghes_arr.ghes_devs = kmalloc(sizeof(void *) * ghes_count, GFP_KERNEL); - if (!ghes_arr.ghes_devs) - return -ENOMEM; - - rc = apei_hest_parse(hest_parse_ghes, &ghes_arr); - if (rc) - goto err; -out: - kfree(ghes_arr.ghes_devs); - return rc; -err: - for (i = 0; i < ghes_arr.count; i++) - platform_device_unregister(ghes_arr.ghes_devs[i]); - goto out; -} - static int __init setup_hest_disable(char *str) { hest_disable = 1; @@ -196,7 +137,6 @@ static int __init hest_init(void) { acpi_status status; int rc = -ENODEV; - unsigned int ghes_count = 0; if (acpi_disabled) goto err; @@ -218,11 +158,7 @@ static int __init hest_init(void) goto err; } - rc = apei_hest_parse(hest_parse_ghes_count, &ghes_count); - if (rc) - goto err; - - rc = hest_ghes_dev_register(ghes_count); + rc = apei_hest_parse(hest_void_parse, NULL); if (rc) goto err; diff --git a/trunk/drivers/acpi/bus.c b/trunk/drivers/acpi/bus.c index c1d23cd71652..7136f24e3002 100644 --- a/trunk/drivers/acpi/bus.c +++ b/trunk/drivers/acpi/bus.c @@ -1036,6 +1036,7 @@ static int __init acpi_init(void) acpi_power_init(); acpi_system_init(); acpi_debug_init(); + acpi_debugfs_init(); acpi_sleep_proc_init(); acpi_wakeup_device_init(); return result; diff --git a/trunk/drivers/acpi/debug.c b/trunk/drivers/acpi/debug.c index 146135e7a6a1..22476eab2b08 100644 --- a/trunk/drivers/acpi/debug.c +++ b/trunk/drivers/acpi/debug.c @@ -197,80 +197,6 @@ static int param_get_trace_state(char *buffer, struct kernel_param *kp) module_param_call(trace_state, param_set_trace_state, param_get_trace_state, NULL, 0644); -/* -------------------------------------------------------------------------- - DebugFS Interface - -------------------------------------------------------------------------- */ - -static ssize_t cm_write(struct file *file, const char __user *user_buf, - size_t count, loff_t *ppos) -{ - static char *buf; - static int uncopied_bytes; - struct acpi_table_header table; - acpi_status status; - - if (!(*ppos)) { - /* parse the table header to get the table length */ - if (count <= sizeof(struct acpi_table_header)) - return -EINVAL; - if (copy_from_user(&table, user_buf, - sizeof(struct acpi_table_header))) - return -EFAULT; - uncopied_bytes = table.length; - buf = kzalloc(uncopied_bytes, GFP_KERNEL); - if (!buf) - return -ENOMEM; - } - - if (uncopied_bytes < count) { - kfree(buf); - return -EINVAL; - } - - if (copy_from_user(buf + (*ppos), user_buf, count)) { - kfree(buf); - return -EFAULT; - } - - uncopied_bytes -= count; - *ppos += count; - - if (!uncopied_bytes) { - status = acpi_install_method(buf); - kfree(buf); - if (ACPI_FAILURE(status)) - return -EINVAL; - add_taint(TAINT_OVERRIDDEN_ACPI_TABLE); - } - - return count; -} - -static const struct file_operations cm_fops = { - .write = cm_write, -}; - -static int acpi_debugfs_init(void) -{ - struct dentry *acpi_dir, *cm_dentry; - - acpi_dir = debugfs_create_dir("acpi", NULL); - if (!acpi_dir) - goto err; - - cm_dentry = debugfs_create_file("custom_method", S_IWUGO, - acpi_dir, NULL, &cm_fops); - if (!cm_dentry) - goto err; - - return 0; - -err: - if (acpi_dir) - debugfs_remove(acpi_dir); - return -EINVAL; -} - /* -------------------------------------------------------------------------- FS Interface (/proc) -------------------------------------------------------------------------- */ @@ -400,7 +326,6 @@ int __init acpi_procfs_init(void) int __init acpi_debug_init(void) { - acpi_debugfs_init(); acpi_procfs_init(); return 0; } diff --git a/trunk/drivers/acpi/debugfs.c b/trunk/drivers/acpi/debugfs.c new file mode 100644 index 000000000000..abfcf9f6e766 --- /dev/null +++ b/trunk/drivers/acpi/debugfs.c @@ -0,0 +1,85 @@ +/* + * debugfs.c - ACPI debugfs interface to userspace. + */ + +#include +#include +#include +#include +#include +#include + +#define _COMPONENT ACPI_SYSTEM_COMPONENT +ACPI_MODULE_NAME("debugfs"); + +/* /sys/kernel/debug/acpi/custom_method */ + +static ssize_t cm_write(struct file *file, const char __user * user_buf, + size_t count, loff_t *ppos) +{ + static char *buf; + static int uncopied_bytes; + struct acpi_table_header table; + acpi_status status; + + if (!(*ppos)) { + /* parse the table header to get the table length */ + if (count <= sizeof(struct acpi_table_header)) + return -EINVAL; + if (copy_from_user(&table, user_buf, + sizeof(struct acpi_table_header))) + return -EFAULT; + uncopied_bytes = table.length; + buf = kzalloc(uncopied_bytes, GFP_KERNEL); + if (!buf) + return -ENOMEM; + } + + if (uncopied_bytes < count) { + kfree(buf); + return -EINVAL; + } + + if (copy_from_user(buf + (*ppos), user_buf, count)) { + kfree(buf); + return -EFAULT; + } + + uncopied_bytes -= count; + *ppos += count; + + if (!uncopied_bytes) { + status = acpi_install_method(buf); + kfree(buf); + if (ACPI_FAILURE(status)) + return -EINVAL; + add_taint(TAINT_OVERRIDDEN_ACPI_TABLE); + } + + return count; +} + +static const struct file_operations cm_fops = { + .write = cm_write, +}; + +int __init acpi_debugfs_init(void) +{ + struct dentry *acpi_dir, *cm_dentry; + + acpi_dir = debugfs_create_dir("acpi", NULL); + if (!acpi_dir) + goto err; + + cm_dentry = debugfs_create_file("custom_method", S_IWUGO, + acpi_dir, NULL, &cm_fops); + if (!cm_dentry) + goto err; + + return 0; + +err: + if (acpi_dir) + debugfs_remove(acpi_dir); + return -EINVAL; +} diff --git a/trunk/drivers/acpi/internal.h b/trunk/drivers/acpi/internal.h index f8f190ec066e..0650e343867e 100644 --- a/trunk/drivers/acpi/internal.h +++ b/trunk/drivers/acpi/internal.h @@ -30,6 +30,12 @@ int acpi_debug_init(void); static inline int acpi_debug_init(void) { return 0; } #endif +#ifdef CONFIG_DEBUG_FS +int acpi_debugfs_init(void); +#else +static inline int acpi_debugfs_init(void) { return 0; } +#endif + /* -------------------------------------------------------------------------- Power Resource -------------------------------------------------------------------------- */ diff --git a/trunk/drivers/acpi/sleep.c b/trunk/drivers/acpi/sleep.c index e4625f919814..2862c781b372 100644 --- a/trunk/drivers/acpi/sleep.c +++ b/trunk/drivers/acpi/sleep.c @@ -70,10 +70,10 @@ static int acpi_sleep_prepare(u32 acpi_state) } ACPI_FLUSH_CPU_CACHE(); + acpi_enable_wakeup_device_prep(acpi_state); #endif printk(KERN_INFO PREFIX "Preparing to enter system sleep state S%d\n", acpi_state); - acpi_enable_wakeup_devices(acpi_state); acpi_enter_sleep_state_prep(acpi_state); return 0; } @@ -118,16 +118,6 @@ static int acpi_pm_freeze(void) return 0; } -/** - * acpi_pre_suspend - Enable wakeup devices, "freeze" EC and save NVS. - */ -static int acpi_pm_pre_suspend(void) -{ - acpi_pm_freeze(); - suspend_nvs_save(); - return 0; -} - /** * __acpi_pm_prepare - Prepare the platform to enter the target state. * @@ -137,9 +127,11 @@ static int acpi_pm_pre_suspend(void) static int __acpi_pm_prepare(void) { int error = acpi_sleep_prepare(acpi_target_sleep_state); + + suspend_nvs_save(); + if (error) acpi_target_sleep_state = ACPI_STATE_S0; - return error; } @@ -150,8 +142,9 @@ static int __acpi_pm_prepare(void) static int acpi_pm_prepare(void) { int error = __acpi_pm_prepare(); + if (!error) - acpi_pm_pre_suspend(); + acpi_pm_freeze(); return error; } @@ -166,6 +159,7 @@ static void acpi_pm_finish(void) { u32 acpi_state = acpi_target_sleep_state; + suspend_nvs_free(); acpi_ec_unblock_transactions(); if (acpi_state == ACPI_STATE_S0) @@ -173,7 +167,7 @@ static void acpi_pm_finish(void) printk(KERN_INFO PREFIX "Waking up from system sleep state S%d\n", acpi_state); - acpi_disable_wakeup_devices(acpi_state); + acpi_disable_wakeup_device(acpi_state); acpi_leave_sleep_state(acpi_state); /* reset firmware waking vector */ @@ -187,7 +181,6 @@ static void acpi_pm_finish(void) */ static void acpi_pm_end(void) { - suspend_nvs_free(); /* * This is necessary in case acpi_pm_finish() is not called during a * failing transition to a sleep state. @@ -258,6 +251,7 @@ static int acpi_suspend_enter(suspend_state_t pm_state) } local_irq_save(flags); + acpi_enable_wakeup_device(acpi_state); switch (acpi_state) { case ACPI_STATE_S1: barrier(); @@ -303,6 +297,11 @@ static int acpi_suspend_enter(suspend_state_t pm_state) return ACPI_SUCCESS(status) ? 0 : -EFAULT; } +static void acpi_suspend_finish(void) +{ + acpi_pm_finish(); +} + static int acpi_suspend_state_valid(suspend_state_t pm_state) { u32 acpi_state; @@ -324,7 +323,7 @@ static struct platform_suspend_ops acpi_suspend_ops = { .begin = acpi_suspend_begin, .prepare_late = acpi_pm_prepare, .enter = acpi_suspend_enter, - .wake = acpi_pm_finish, + .wake = acpi_suspend_finish, .end = acpi_pm_end, }; @@ -337,9 +336,9 @@ static struct platform_suspend_ops acpi_suspend_ops = { static int acpi_suspend_begin_old(suspend_state_t pm_state) { int error = acpi_suspend_begin(pm_state); + if (!error) error = __acpi_pm_prepare(); - return error; } @@ -350,9 +349,9 @@ static int acpi_suspend_begin_old(suspend_state_t pm_state) static struct platform_suspend_ops acpi_suspend_ops_old = { .valid = acpi_suspend_state_valid, .begin = acpi_suspend_begin_old, - .prepare_late = acpi_pm_pre_suspend, + .prepare_late = acpi_pm_freeze, .enter = acpi_suspend_enter, - .wake = acpi_pm_finish, + .wake = acpi_suspend_finish, .end = acpi_pm_end, .recover = acpi_pm_finish, }; @@ -424,6 +423,16 @@ static int acpi_hibernation_begin(void) return error; } +static int acpi_hibernation_pre_snapshot(void) +{ + int error = acpi_pm_prepare(); + + if (!error) + suspend_nvs_save(); + + return error; +} + static int acpi_hibernation_enter(void) { acpi_status status = AE_OK; @@ -432,6 +441,7 @@ static int acpi_hibernation_enter(void) ACPI_FLUSH_CPU_CACHE(); local_irq_save(flags); + acpi_enable_wakeup_device(ACPI_STATE_S4); /* This shouldn't return. If it returns, we have a problem */ status = acpi_enter_sleep_state(ACPI_STATE_S4); /* Reprogram control registers and execute _BFS */ @@ -471,7 +481,7 @@ static void acpi_pm_thaw(void) static struct platform_hibernation_ops acpi_hibernation_ops = { .begin = acpi_hibernation_begin, .end = acpi_pm_end, - .pre_snapshot = acpi_pm_prepare, + .pre_snapshot = acpi_hibernation_pre_snapshot, .finish = acpi_pm_finish, .prepare = acpi_pm_prepare, .enter = acpi_hibernation_enter, @@ -507,6 +517,13 @@ static int acpi_hibernation_begin_old(void) return error; } +static int acpi_hibernation_pre_snapshot_old(void) +{ + acpi_pm_freeze(); + suspend_nvs_save(); + return 0; +} + /* * The following callbacks are used if the pre-ACPI 2.0 suspend ordering has * been requested. @@ -514,7 +531,7 @@ static int acpi_hibernation_begin_old(void) static struct platform_hibernation_ops acpi_hibernation_ops_old = { .begin = acpi_hibernation_begin_old, .end = acpi_pm_end, - .pre_snapshot = acpi_pm_pre_suspend, + .pre_snapshot = acpi_hibernation_pre_snapshot_old, .prepare = acpi_pm_freeze, .finish = acpi_pm_finish, .enter = acpi_hibernation_enter, @@ -678,6 +695,7 @@ static void acpi_power_off(void) /* acpi_sleep_prepare(ACPI_STATE_S5) should have already been called */ printk(KERN_DEBUG "%s called\n", __func__); local_irq_disable(); + acpi_enable_wakeup_device(ACPI_STATE_S5); acpi_enter_sleep_state(ACPI_STATE_S5); } diff --git a/trunk/drivers/acpi/sleep.h b/trunk/drivers/acpi/sleep.h index d8821805c3bc..25b8bd149284 100644 --- a/trunk/drivers/acpi/sleep.h +++ b/trunk/drivers/acpi/sleep.h @@ -2,8 +2,9 @@ extern u8 sleep_states[]; extern int acpi_suspend(u32 state); -extern void acpi_enable_wakeup_devices(u8 sleep_state); -extern void acpi_disable_wakeup_devices(u8 sleep_state); +extern void acpi_enable_wakeup_device_prep(u8 sleep_state); +extern void acpi_enable_wakeup_device(u8 sleep_state); +extern void acpi_disable_wakeup_device(u8 sleep_state); extern struct list_head acpi_wakeup_device_list; extern struct mutex acpi_device_lock; diff --git a/trunk/drivers/acpi/wakeup.c b/trunk/drivers/acpi/wakeup.c index dc6d1d9112fb..388747a7ef4f 100644 --- a/trunk/drivers/acpi/wakeup.c +++ b/trunk/drivers/acpi/wakeup.c @@ -21,17 +21,45 @@ ACPI_MODULE_NAME("wakeup_devices") /** - * acpi_enable_wakeup_devices - Enable wake-up device GPEs. + * acpi_enable_wakeup_device_prep - Prepare wake-up devices. * @sleep_state: ACPI system sleep state. * - * Enable wakeup device power of devices with the state.enable flag set and set - * the wakeup enable mask bits in the GPE registers that correspond to wakeup - * devices. + * Enable all wake-up devices' power, unless the requested system sleep state is + * too deep. */ -void acpi_enable_wakeup_devices(u8 sleep_state) +void acpi_enable_wakeup_device_prep(u8 sleep_state) { struct list_head *node, *next; + list_for_each_safe(node, next, &acpi_wakeup_device_list) { + struct acpi_device *dev = container_of(node, + struct acpi_device, + wakeup_list); + + if (!dev->wakeup.flags.valid || !dev->wakeup.state.enabled + || (sleep_state > (u32) dev->wakeup.sleep_state)) + continue; + + acpi_enable_wakeup_device_power(dev, sleep_state); + } +} + +/** + * acpi_enable_wakeup_device - Enable wake-up device GPEs. + * @sleep_state: ACPI system sleep state. + * + * Enable all wake-up devices' GPEs, with the assumption that + * acpi_disable_all_gpes() was executed before, so we don't need to disable any + * GPEs here. + */ +void acpi_enable_wakeup_device(u8 sleep_state) +{ + struct list_head *node, *next; + + /* + * Caution: this routine must be invoked when interrupt is disabled + * Refer ACPI2.0: P212 + */ list_for_each_safe(node, next, &acpi_wakeup_device_list) { struct acpi_device *dev = container_of(node, struct acpi_device, wakeup_list); @@ -40,9 +68,6 @@ void acpi_enable_wakeup_devices(u8 sleep_state) || sleep_state > (u32) dev->wakeup.sleep_state) continue; - if (dev->wakeup.state.enabled) - acpi_enable_wakeup_device_power(dev, sleep_state); - /* The wake-up power should have been enabled already. */ acpi_enable_gpe(dev->wakeup.gpe_device, dev->wakeup.gpe_number, ACPI_GPE_TYPE_WAKE); @@ -50,10 +75,13 @@ void acpi_enable_wakeup_devices(u8 sleep_state) } /** - * acpi_disable_wakeup_devices - Disable devices' wakeup capability. + * acpi_disable_wakeup_device - Disable devices' wakeup capability. * @sleep_state: ACPI system sleep state. + * + * This function only affects devices with wakeup.state.enabled set, which means + * that it reverses the changes made by acpi_enable_wakeup_device_prep(). */ -void acpi_disable_wakeup_devices(u8 sleep_state) +void acpi_disable_wakeup_device(u8 sleep_state) { struct list_head *node, *next; diff --git a/trunk/include/linux/cper.h b/trunk/include/linux/cper.h index bf972f81e2a7..4b38f905b705 100644 --- a/trunk/include/linux/cper.h +++ b/trunk/include/linux/cper.h @@ -39,10 +39,10 @@ * Severity difinition for error_severity in struct cper_record_header * and section_severity in struct cper_section_descriptor */ -#define CPER_SEV_RECOVERABLE 0x0 -#define CPER_SEV_FATAL 0x1 -#define CPER_SEV_CORRECTED 0x2 -#define CPER_SEV_INFORMATIONAL 0x3 +#define CPER_SER_RECOVERABLE 0x0 +#define CPER_SER_FATAL 0x1 +#define CPER_SER_CORRECTED 0x2 +#define CPER_SER_INFORMATIONAL 0x3 /* * Validation bits difinition for validation_bits in struct