Messages in this thread Patch in this message | | | From | Borislav Petkov <> | Subject | [PATCH 3/4] x86, RAS: Add a decoded msg buffer | Date | Fri, 2 Mar 2012 15:25:13 +0100 |
| |
From: Borislav Petkov <borislav.petkov@amd.com>
Echoing 1 into /sys/devices/system/ras/agent causes the ras_printk() function to buffer a string describing a hardware error. This is meant for userspace daemons which are running on the system and are going to consume decoded information through the MCE tracepoint.
Signed-off-by: Borislav Petkov <borislav.petkov@amd.com> --- arch/x86/Kconfig | 9 +++ arch/x86/Makefile | 3 + arch/x86/include/asm/ras.h | 15 +++++ arch/x86/ras/Makefile | 1 + arch/x86/ras/ras.c | 145 ++++++++++++++++++++++++++++++++++++++++++++ 5 files changed, 173 insertions(+), 0 deletions(-) create mode 100644 arch/x86/include/asm/ras.h create mode 100644 arch/x86/ras/Makefile create mode 100644 arch/x86/ras/ras.c
diff --git a/arch/x86/Kconfig b/arch/x86/Kconfig index 5bed94e189fa..bda1480241b2 100644 --- a/arch/x86/Kconfig +++ b/arch/x86/Kconfig @@ -657,6 +657,15 @@ config X86_CYCLONE_TIMER def_bool y depends on X86_SUMMIT +config X86_RAS + def_bool y + prompt "X86 RAS features" + ---help--- + A collection of Reliability, Availability and Serviceability + software features which aim to enable hardware error logging + and reporting. Leave it at 'y' unless you really know what + you're doing + source "arch/x86/Kconfig.cpu" config HPET_TIMER diff --git a/arch/x86/Makefile b/arch/x86/Makefile index 209ba1294592..a6b6bb1f308b 100644 --- a/arch/x86/Makefile +++ b/arch/x86/Makefile @@ -146,6 +146,9 @@ drivers-$(CONFIG_OPROFILE) += arch/x86/oprofile/ # suspend and hibernation support drivers-$(CONFIG_PM) += arch/x86/power/ +# RAS support +core-y += arch/x86/ras/ + drivers-$(CONFIG_FB) += arch/x86/video/ #### diff --git a/arch/x86/include/asm/ras.h b/arch/x86/include/asm/ras.h new file mode 100644 index 000000000000..92199af2ab7b --- /dev/null +++ b/arch/x86/include/asm/ras.h @@ -0,0 +1,15 @@ +#ifndef _ASM_X86_RAS_H +#define _ASM_X86_RAS_H + +#define ERR_BUF_SZ 500 + +extern bool ras_agent; + +#define PR_EMERG BIT(0) +#define PR_WARNING BIT(1) +#define PR_CONT BIT(2) + +extern const char *ras_get_decoded_err(void); +extern void ras_printk(unsigned long flags, const char *fmt, ...); + +#endif /* _ASM_X86_RAS_H */ diff --git a/arch/x86/ras/Makefile b/arch/x86/ras/Makefile new file mode 100644 index 000000000000..7a70bb5cd057 --- /dev/null +++ b/arch/x86/ras/Makefile @@ -0,0 +1 @@ +obj-y := ras.o diff --git a/arch/x86/ras/ras.c b/arch/x86/ras/ras.c new file mode 100644 index 000000000000..5edfe30034d3 --- /dev/null +++ b/arch/x86/ras/ras.c @@ -0,0 +1,145 @@ +#include <linux/slab.h> +#include <linux/types.h> +#include <linux/device.h> +#include <linux/kernel.h> +#include <linux/module.h> +#include <asm/ras.h> + +static size_t dec_len; +static char *err_str; + +/* + * If true, userspace has an agent running and eating all the + * tracing data we're sending out so there's no dmesg output + */ +bool ras_agent; +EXPORT_SYMBOL_GPL(ras_agent); + +/* getting the string implies the current buffer is emptied */ +const char *ras_get_decoded_err(void) +{ + dec_len = 0; + return err_str; +} + +void ras_printk(unsigned long flags, const char *fmt, ...) +{ + va_list args; + char *buf; + size_t left; + int i; + + /* add a HW_ERR prefix to a newly started line */ + if (!(flags & PR_CONT)) { + strcpy(err_str + dec_len, HW_ERR); + dec_len += strlen(HW_ERR); + } + + left = ERR_BUF_SZ - dec_len - 1; + buf = err_str + dec_len; + + va_start(args, fmt); + i = vsnprintf(buf, left, fmt, args); + va_end(args); + + if (i >= left) { + pr_err("Error decode buffer truncated.\n"); + dec_len = ERR_BUF_SZ-1; + err_str[dec_len] = '\n'; + } else + dec_len += i; + + if (!ras_agent) { + if (flags & PR_EMERG) + pr_emerg("%s", buf); + if (flags & PR_WARNING) + pr_warning("%s", buf); + else if (flags & PR_CONT) + pr_cont("%s", buf); + + dec_len = 0; + } +} +EXPORT_SYMBOL_GPL(ras_printk); + +struct bus_type ras_subsys = { + .name = "ras", + .dev_name = "ras", +}; + +struct ras_attr { + struct attribute attr; + ssize_t (*show) (struct kobject *kobj, struct ras_attr *attr, char *bf); + ssize_t (*store)(struct kobject *kobj, struct ras_attr *attr, + const char *buf, size_t count); +}; + +#define RAS_ATTR(_name, _mode, _show, _store) \ +static struct ras_attr ras_attr_##_name = __ATTR(_name, _mode, _show, _store) + +static ssize_t ras_agent_show(struct kobject *kobj, + struct ras_attr *attr, + char *buf) +{ + return sprintf(buf, "%.1d\n", ras_agent); +} + +static ssize_t ras_agent_store(struct kobject *kobj, + struct ras_attr *attr, + const char *buf, size_t count) +{ + int ret = 0; + unsigned long value; + + ret = kstrtoul(buf, 10, &value); + if (ret < 0) { + printk(KERN_ERR "Wrong value for ras_agent field.\n"); + return ret; + } + + ras_agent = !!value; + + return count; +} + +RAS_ATTR(agent, 0644, ras_agent_show, ras_agent_store); + +static struct attribute *ras_root_attrs[] = { + &ras_attr_agent.attr, + NULL +}; + +static const struct attribute_group ras_root_attr_group = { + .attrs = ras_root_attrs, +}; + +static const struct attribute_group *ras_root_attr_groups[] = { + &ras_root_attr_group, + NULL, +}; + +static int __init ras_init(void) +{ + int err = 0; + + err = subsys_system_register(&ras_subsys, ras_root_attr_groups); + if (err) { + printk(KERN_ERR "Error registering toplevel RAS sysfs node.\n"); + return err; + } + + /* no freeing of this since it ras.c is compiled-on only */ + err_str = kzalloc(ERR_BUF_SZ, GFP_KERNEL); + if (!err_str) { + err = -ENOMEM; + goto err_alloc; + } + + return 0; + +err_alloc: + bus_unregister(&ras_subsys); + + return err; +} +subsys_initcall(ras_init); -- 1.7.8.rc0
| |