/*
* edac_mc kernel module
* (C) 2005, 2006 Linux Networx (http://lnxi.com)
* This file may be distributed under the terms of the
* GNU General Public License.
*
* Written by Thayne Harbaugh
* Based on work by Dan Hollis <goemon at anime dot net> and others.
* http://www.anime.net/~goemon/linux-ecc/
*
* Modified by Dave Peterson and Doug Thompson
*
*/
#include <linux/module.h>
#include <linux/proc_fs.h>
#include <linux/kernel.h>
#include <linux/types.h>
#include <linux/smp.h>
#include <linux/init.h>
#include <linux/sysctl.h>
#include <linux/highmem.h>
#include <linux/timer.h>
#include <linux/slab.h>
#include <linux/jiffies.h>
#include <linux/spinlock.h>
#include <linux/list.h>
#include <linux/ctype.h>
#include <linux/edac.h>
#include <linux/bitops.h>
#include <linux/uaccess.h>
#include <asm/page.h>
#include "edac_mc.h"
#include "edac_module.h"
#include <ras/ras_event.h>
#ifdef CONFIG_EDAC_ATOMIC_SCRUB
#include <asm/edac.h>
#else
#define edac_atomic_scrub(va, size) do { } while (0)
#endif
int edac_op_state = EDAC_OPSTATE_INVAL;
EXPORT_SYMBOL_GPL(edac_op_state);
static int edac_report = EDAC_REPORTING_ENABLED;
/* lock to memory controller's control array */
static DEFINE_MUTEX(mem_ctls_mutex);
static LIST_HEAD(mc_devices);
/*
* Used to lock EDAC MC to just one module, avoiding two drivers e. g.
* apei/ghes and i7core_edac to be used at the same time.
*/
static const char *edac_mc_owner;
int edac_get_report_status(void)
{
return edac_report;
}
EXPORT_SYMBOL_GPL(edac_get_report_status);
void edac_set_report_status(int new)
{
if (new == EDAC_REPORTING_ENABLED ||
new == EDAC_REPORTING_DISABLED ||
new == EDAC_REPORTING_FORCE)
edac_report = new;
}
EXPORT_SYMBOL_GPL(edac_set_report_status);
static int edac_report_set(const char *str, const struct kernel_param *kp)
{
if (!str)
return -EINVAL;
if (!strncmp(str, "on", 2))
edac_report = EDAC_REPORTING_ENABLED;
else if (!strncmp(str, "off", 3))
edac_report = EDAC_REPORTING_DISABLED;
else if (!strncmp(str, "force", 5))
edac_report = EDAC_REPORTING_FORCE;
return 0;
}
static int edac_report_get(char *buffer, const struct kernel_param *kp)
{
int ret = 0;
switch (edac_report) {
case EDAC_REPORTING_ENABLED:
ret = sprintf(buffer, "on");
break;
case EDAC_REPORTING_DISABLED:
ret = sprintf(buffer, "off");
break;
case EDAC_REPORTING_FORCE:
ret = sprintf(buffer, "force");
break;
default:
ret = -EINVAL;
break;
}
return ret;
}
static const struct kernel_param_ops edac_report_ops = {
.set = edac_report_set,
.get = edac_report_get,
};
module_param_cb(edac_report, &edac_report_ops, &edac_report, 0644);
unsigned edac_dimm_info_location(struct dimm_info *dimm, char *buf,
unsigned len)
{
struct mem_ctl_info *mci = dimm->mci;
int i, n, count = 0;
char *p = buf;
for (i = 0; i < mci->n_layers; i++) {
n = snprintf(p, len, "%s %d ",
edac_layer_name[mci->layers[i].type],
dimm->location[i]);
p += n;
len -= n<