Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 696e409d authored by Mauro Carvalho Chehab's avatar Mauro Carvalho Chehab
Browse files

edac_mce: Add an interface driver to report mce errors via edac



edac_mce module is an interface module that gets mcelog data and
forwards to any registered edac module that expects to receive data via
mce.

Signed-off-by: default avatarMauro Carvalho Chehab <mchehab@redhat.com>
parent 41fcb7fe
Loading
Loading
Loading
Loading
+10 −0
Original line number Diff line number Diff line
@@ -36,6 +36,7 @@
#include <linux/fs.h>
#include <linux/mm.h>
#include <linux/debugfs.h>
#include <linux/edac_mce.h>

#include <asm/processor.h>
#include <asm/hw_irq.h>
@@ -168,6 +169,15 @@ void mce_log(struct mce *mce)
	for (;;) {
		entry = rcu_dereference_check_mce(mcelog.next);
		for (;;) {
			/*
			 * If edac_mce is enabled, it will check the error type
			 * and will process it, if it is a known error.
			 * Otherwise, the error will be sent through mcelog
			 * interface
			 */
			if (edac_mce_parse(mce))
				return;

			/*
			 * When the buffer fills up discard new entries.
			 * Assume that the earlier errors are the more
+7 −1
Original line number Diff line number Diff line
@@ -69,6 +69,9 @@ config EDAC_MM_EDAC
	  occurred so that a particular failing memory module can be
	  replaced.  If unsure, select 'Y'.

config EDAC_MCE
	tristate

config EDAC_AMD64
	tristate "AMD64 (Opteron, Athlon64) K8, F10h, F11h"
	depends on EDAC_MM_EDAC && K8_NB && X86_64 && PCI && EDAC_DECODE_MCE
@@ -169,9 +172,12 @@ config EDAC_I5400
config EDAC_I7CORE
	tristate "Intel i7 Core (Nehalem) processors"
	depends on EDAC_MM_EDAC && PCI && X86
	select EDAC_MCE
	help
	  Support for error detection and correction the Intel
	  i7 Core (Nehalem) Integrated Memory Controller
	  i7 Core (Nehalem) Integrated Memory Controller that exists on
	  newer processors like i7 Core, i7 Core Extreme, Xeon 35xx
	  and Xeon 55xx processors.

config EDAC_I82860
	tristate "Intel 82860"
+1 −0
Original line number Diff line number Diff line
@@ -8,6 +8,7 @@

obj-$(CONFIG_EDAC)			:= edac_stub.o
obj-$(CONFIG_EDAC_MM_EDAC)		+= edac_core.o
obj-$(CONFIG_EDAC_MCE)			+= edac_mce.o

edac_core-objs	:= edac_mc.o edac_device.o edac_mc_sysfs.o edac_pci_sysfs.o
edac_core-objs	+= edac_module.o edac_device_sysfs.o
+58 −0
Original line number Diff line number Diff line
/* Provides edac interface to mcelog events
 *
 * This file may be distributed under the terms of the
 * GNU General Public License version 2.
 *
 * Copyright (c) 2009 by:
 *	 Mauro Carvalho Chehab <mchehab@redhat.com>
 *
 * Red Hat Inc. http://www.redhat.com
 */

#include <linux/module.h>
#include <linux/edac_mce.h>
#include <asm/mce.h>

int edac_mce_enabled;
EXPORT_SYMBOL_GPL(edac_mce_enabled);


/*
 * Extension interface
 */

static LIST_HEAD(edac_mce_list);
static DEFINE_MUTEX(edac_mce_lock);

int edac_mce_register(struct edac_mce *edac_mce)
{
	mutex_lock(&edac_mce_lock);
	list_add_tail(&edac_mce->list, &edac_mce_list);
	mutex_unlock(&edac_mce_lock);
	return 0;
}
EXPORT_SYMBOL(edac_mce_register);

void edac_mce_unregister(struct edac_mce *edac_mce)
{
	mutex_lock(&edac_mce_lock);
	list_del(&edac_mce->list);
	mutex_unlock(&edac_mce_lock);
}
EXPORT_SYMBOL(edac_mce_unregister);



int edac_mce_queue(struct mce *mce)
{
	struct edac_mce *edac_mce;

	list_for_each_entry(edac_mce, &edac_mce_list, list) {
		if (edac_mce->check_error(edac_mce->priv, mce))
			return 1;
	}

	/* Nobody queued the error */
	return 0;
}
EXPORT_SYMBOL_GPL(edac_mce_queue);
+31 −0
Original line number Diff line number Diff line
/* Provides edac interface to mcelog events
 *
 * This file may be distributed under the terms of the
 * GNU General Public License version 2.
 *
 * Copyright (c) 2009 by:
 *	 Mauro Carvalho Chehab <mchehab@redhat.com>
 *
 * Red Hat Inc. http://www.redhat.com
 */

#if defined(CONFIG_EDAC_MCE) || \
			(defined(CONFIG_EDAC_MCE_MODULE) && defined(MODULE))

#include <asm/mce.h>
#include <linux/list.h>

struct edac_mce {
	struct list_head list;

	void *priv;
	int (*check_error)(void *priv, struct mce *mce);
};

int edac_mce_register(struct edac_mce *edac_mce);
void edac_mce_unregister(struct edac_mce *edac_mce);
int edac_mce_parse(struct mce *mce);

#else
#define edac_mce_parse(mce) (0)
#endif