mirror of
https://github.com/BobTheBlinker/android_kernel_motorola_sm6375.git
synced 2026-10-28 10:41:38 -04:00
Merge branch 'linux_next' of git://git.kernel.org/pub/scm/linux/kernel/git/mchehab/i7core
* 'linux_next' of git://git.kernel.org/pub/scm/linux/kernel/git/mchehab/i7core: (83 commits) i7core_edac: Better describe the supported devices Add support for Westmere to i7core_edac driver i7core_edac: don't free on success i7core_edac: Add support for X5670 Always call i7core_[ur]dimm_check_mc_ecc_err i7core_edac: fix memory leak of i7core_dev EDAC: add __init to i7core_xeon_pci_fixup i7core_edac: Fix wrong device id for channel 1 devices i7core: add support for Lynnfield alternate address i7core_edac: Add initial support for Lynnfield i7core_edac: do not export static functions edac: fix i7core build edac: i7core_edac produces undefined behaviour on 32bit i7core_edac: Use a more generic approach for probing PCI devices i7core_edac: PCI device is called NONCORE, instead of NOCORE i7core_edac: Fix ringbuffer maxsize i7core_edac: First store, then increment i7core_edac: Better parse "any" addrmask i7core_edac: Use a lockless ringbuffer edac: Create an unique instance for each kobj ...
This commit is contained in:
commit
9a9620db07
13 changed files with 2598 additions and 44 deletions
|
|
@ -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
|
||||
bool
|
||||
|
||||
config EDAC_AMD64
|
||||
tristate "AMD64 (Opteron, Athlon64) K8, F10h, F11h"
|
||||
depends on EDAC_MM_EDAC && K8_NB && X86_64 && PCI && EDAC_DECODE_MCE
|
||||
|
|
@ -166,6 +169,16 @@ config EDAC_I5400
|
|||
Support for error detection and correction the Intel
|
||||
i5400 MCH chipset (Seaburg).
|
||||
|
||||
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 that exists on
|
||||
newer processors like i7 Core, i7 Core Extreme, Xeon 35xx
|
||||
and Xeon 55xx processors.
|
||||
|
||||
config EDAC_I82860
|
||||
tristate "Intel 82860"
|
||||
depends on EDAC_MM_EDAC && PCI && X86_32
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
@ -23,6 +24,7 @@ obj-$(CONFIG_EDAC_CPC925) += cpc925_edac.o
|
|||
obj-$(CONFIG_EDAC_I5000) += i5000_edac.o
|
||||
obj-$(CONFIG_EDAC_I5100) += i5100_edac.o
|
||||
obj-$(CONFIG_EDAC_I5400) += i5400_edac.o
|
||||
obj-$(CONFIG_EDAC_I7CORE) += i7core_edac.o
|
||||
obj-$(CONFIG_EDAC_E7XXX) += e7xxx_edac.o
|
||||
obj-$(CONFIG_EDAC_E752X) += e752x_edac.o
|
||||
obj-$(CONFIG_EDAC_I82443BXGX) += i82443bxgx_edac.o
|
||||
|
|
|
|||
|
|
@ -341,12 +341,30 @@ struct csrow_info {
|
|||
struct channel_info *channels;
|
||||
};
|
||||
|
||||
struct mcidev_sysfs_group {
|
||||
const char *name; /* group name */
|
||||
struct mcidev_sysfs_attribute *mcidev_attr; /* group attributes */
|
||||
};
|
||||
|
||||
struct mcidev_sysfs_group_kobj {
|
||||
struct list_head list; /* list for all instances within a mc */
|
||||
|
||||
struct kobject kobj; /* kobj for the group */
|
||||
|
||||
struct mcidev_sysfs_group *grp; /* group description table */
|
||||
struct mem_ctl_info *mci; /* the parent */
|
||||
};
|
||||
|
||||
/* mcidev_sysfs_attribute structure
|
||||
* used for driver sysfs attributes and in mem_ctl_info
|
||||
* sysfs top level entries
|
||||
*/
|
||||
struct mcidev_sysfs_attribute {
|
||||
struct attribute attr;
|
||||
/* It should use either attr or grp */
|
||||
struct attribute attr;
|
||||
struct mcidev_sysfs_group *grp; /* Points to a group of attributes */
|
||||
|
||||
/* Ops for show/store values at the attribute - not used on group */
|
||||
ssize_t (*show)(struct mem_ctl_info *,char *);
|
||||
ssize_t (*store)(struct mem_ctl_info *, const char *,size_t);
|
||||
};
|
||||
|
|
@ -424,6 +442,9 @@ struct mem_ctl_info {
|
|||
/* edac sysfs device control */
|
||||
struct kobject edac_mci_kobj;
|
||||
|
||||
/* list for all grp instances within a mc */
|
||||
struct list_head grp_kobj_list;
|
||||
|
||||
/* Additional top controller level attributes, but specified
|
||||
* by the low level driver.
|
||||
*
|
||||
|
|
|
|||
|
|
@ -557,6 +557,8 @@ static ssize_t mcidev_show(struct kobject *kobj, struct attribute *attr,
|
|||
struct mem_ctl_info *mem_ctl_info = to_mci(kobj);
|
||||
struct mcidev_sysfs_attribute *mcidev_attr = to_mcidev_attr(attr);
|
||||
|
||||
debugf1("%s() mem_ctl_info %p\n", __func__, mem_ctl_info);
|
||||
|
||||
if (mcidev_attr->show)
|
||||
return mcidev_attr->show(mem_ctl_info, buffer);
|
||||
|
||||
|
|
@ -569,6 +571,8 @@ static ssize_t mcidev_store(struct kobject *kobj, struct attribute *attr,
|
|||
struct mem_ctl_info *mem_ctl_info = to_mci(kobj);
|
||||
struct mcidev_sysfs_attribute *mcidev_attr = to_mcidev_attr(attr);
|
||||
|
||||
debugf1("%s() mem_ctl_info %p\n", __func__, mem_ctl_info);
|
||||
|
||||
if (mcidev_attr->store)
|
||||
return mcidev_attr->store(mem_ctl_info, buffer, count);
|
||||
|
||||
|
|
@ -726,28 +730,118 @@ void edac_mc_unregister_sysfs_main_kobj(struct mem_ctl_info *mci)
|
|||
|
||||
#define EDAC_DEVICE_SYMLINK "device"
|
||||
|
||||
#define grp_to_mci(k) (container_of(k, struct mcidev_sysfs_group_kobj, kobj)->mci)
|
||||
|
||||
/* MCI show/store functions for top most object */
|
||||
static ssize_t inst_grp_show(struct kobject *kobj, struct attribute *attr,
|
||||
char *buffer)
|
||||
{
|
||||
struct mem_ctl_info *mem_ctl_info = grp_to_mci(kobj);
|
||||
struct mcidev_sysfs_attribute *mcidev_attr = to_mcidev_attr(attr);
|
||||
|
||||
debugf1("%s() mem_ctl_info %p\n", __func__, mem_ctl_info);
|
||||
|
||||
if (mcidev_attr->show)
|
||||
return mcidev_attr->show(mem_ctl_info, buffer);
|
||||
|
||||
return -EIO;
|
||||
}
|
||||
|
||||
static ssize_t inst_grp_store(struct kobject *kobj, struct attribute *attr,
|
||||
const char *buffer, size_t count)
|
||||
{
|
||||
struct mem_ctl_info *mem_ctl_info = grp_to_mci(kobj);
|
||||
struct mcidev_sysfs_attribute *mcidev_attr = to_mcidev_attr(attr);
|
||||
|
||||
debugf1("%s() mem_ctl_info %p\n", __func__, mem_ctl_info);
|
||||
|
||||
if (mcidev_attr->store)
|
||||
return mcidev_attr->store(mem_ctl_info, buffer, count);
|
||||
|
||||
return -EIO;
|
||||
}
|
||||
|
||||
/* No memory to release for this kobj */
|
||||
static void edac_inst_grp_release(struct kobject *kobj)
|
||||
{
|
||||
struct mcidev_sysfs_group_kobj *grp;
|
||||
struct mem_ctl_info *mci;
|
||||
|
||||
debugf1("%s()\n", __func__);
|
||||
|
||||
grp = container_of(kobj, struct mcidev_sysfs_group_kobj, kobj);
|
||||
mci = grp->mci;
|
||||
|
||||
kobject_put(&mci->edac_mci_kobj);
|
||||
}
|
||||
|
||||
/* Intermediate show/store table */
|
||||
static struct sysfs_ops inst_grp_ops = {
|
||||
.show = inst_grp_show,
|
||||
.store = inst_grp_store
|
||||
};
|
||||
|
||||
/* the kobj_type instance for a instance group */
|
||||
static struct kobj_type ktype_inst_grp = {
|
||||
.release = edac_inst_grp_release,
|
||||
.sysfs_ops = &inst_grp_ops,
|
||||
};
|
||||
|
||||
|
||||
/*
|
||||
* edac_create_mci_instance_attributes
|
||||
* create MC driver specific attributes at the topmost level
|
||||
* directory of this mci instance.
|
||||
* create MC driver specific attributes bellow an specified kobj
|
||||
* This routine calls itself recursively, in order to create an entire
|
||||
* object tree.
|
||||
*/
|
||||
static int edac_create_mci_instance_attributes(struct mem_ctl_info *mci)
|
||||
static int edac_create_mci_instance_attributes(struct mem_ctl_info *mci,
|
||||
struct mcidev_sysfs_attribute *sysfs_attrib,
|
||||
struct kobject *kobj)
|
||||
{
|
||||
int err;
|
||||
struct mcidev_sysfs_attribute *sysfs_attrib;
|
||||
|
||||
/* point to the start of the array and iterate over it
|
||||
* adding each attribute listed to this mci instance's kobject
|
||||
*/
|
||||
sysfs_attrib = mci->mc_driver_sysfs_attributes;
|
||||
debugf1("%s()\n", __func__);
|
||||
|
||||
while (sysfs_attrib) {
|
||||
if (sysfs_attrib->grp) {
|
||||
struct mcidev_sysfs_group_kobj *grp_kobj;
|
||||
|
||||
grp_kobj = kzalloc(sizeof(*grp_kobj), GFP_KERNEL);
|
||||
if (!grp_kobj)
|
||||
return -ENOMEM;
|
||||
|
||||
list_add_tail(&grp_kobj->list, &mci->grp_kobj_list);
|
||||
|
||||
grp_kobj->grp = sysfs_attrib->grp;
|
||||
grp_kobj->mci = mci;
|
||||
|
||||
debugf0("%s() grp %s, mci %p\n", __func__,
|
||||
sysfs_attrib->grp->name, mci);
|
||||
|
||||
err = kobject_init_and_add(&grp_kobj->kobj,
|
||||
&ktype_inst_grp,
|
||||
&mci->edac_mci_kobj,
|
||||
sysfs_attrib->grp->name);
|
||||
if (err)
|
||||
return err;
|
||||
|
||||
err = edac_create_mci_instance_attributes(mci,
|
||||
grp_kobj->grp->mcidev_attr,
|
||||
&grp_kobj->kobj);
|
||||
|
||||
if (err)
|
||||
return err;
|
||||
} else if (sysfs_attrib->attr.name) {
|
||||
debugf0("%s() file %s\n", __func__,
|
||||
sysfs_attrib->attr.name);
|
||||
|
||||
err = sysfs_create_file(kobj, &sysfs_attrib->attr);
|
||||
} else
|
||||
break;
|
||||
|
||||
while (sysfs_attrib && sysfs_attrib->attr.name) {
|
||||
err = sysfs_create_file(&mci->edac_mci_kobj,
|
||||
(struct attribute*) sysfs_attrib);
|
||||
if (err) {
|
||||
return err;
|
||||
}
|
||||
|
||||
sysfs_attrib++;
|
||||
}
|
||||
|
||||
|
|
@ -759,21 +853,44 @@ static int edac_create_mci_instance_attributes(struct mem_ctl_info *mci)
|
|||
* remove MC driver specific attributes at the topmost level
|
||||
* directory of this mci instance.
|
||||
*/
|
||||
static void edac_remove_mci_instance_attributes(struct mem_ctl_info *mci)
|
||||
static void edac_remove_mci_instance_attributes(struct mem_ctl_info *mci,
|
||||
struct mcidev_sysfs_attribute *sysfs_attrib,
|
||||
struct kobject *kobj, int count)
|
||||
{
|
||||
struct mcidev_sysfs_attribute *sysfs_attrib;
|
||||
struct mcidev_sysfs_group_kobj *grp_kobj, *tmp;
|
||||
|
||||
/* point to the start of the array and iterate over it
|
||||
* adding each attribute listed to this mci instance's kobject
|
||||
debugf1("%s()\n", __func__);
|
||||
|
||||
/*
|
||||
* loop if there are attributes and until we hit a NULL entry
|
||||
* Remove first all the atributes
|
||||
*/
|
||||
sysfs_attrib = mci->mc_driver_sysfs_attributes;
|
||||
|
||||
/* loop if there are attributes and until we hit a NULL entry */
|
||||
while (sysfs_attrib && sysfs_attrib->attr.name) {
|
||||
sysfs_remove_file(&mci->edac_mci_kobj,
|
||||
(struct attribute *) sysfs_attrib);
|
||||
while (sysfs_attrib) {
|
||||
if (sysfs_attrib->grp) {
|
||||
list_for_each_entry(grp_kobj, &mci->grp_kobj_list,
|
||||
list)
|
||||
if (grp_kobj->grp == sysfs_attrib->grp)
|
||||
edac_remove_mci_instance_attributes(mci,
|
||||
grp_kobj->grp->mcidev_attr,
|
||||
&grp_kobj->kobj, count + 1);
|
||||
} else if (sysfs_attrib->attr.name) {
|
||||
debugf0("%s() file %s\n", __func__,
|
||||
sysfs_attrib->attr.name);
|
||||
sysfs_remove_file(kobj, &sysfs_attrib->attr);
|
||||
} else
|
||||
break;
|
||||
sysfs_attrib++;
|
||||
}
|
||||
|
||||
/*
|
||||
* Now that all attributes got removed, it is save to remove all groups
|
||||
*/
|
||||
if (!count)
|
||||
list_for_each_entry_safe(grp_kobj, tmp, &mci->grp_kobj_list,
|
||||
list) {
|
||||
debugf0("%s() grp %s\n", __func__, grp_kobj->grp->name);
|
||||
kobject_put(&grp_kobj->kobj);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
|
@ -794,6 +911,8 @@ int edac_create_sysfs_mci_device(struct mem_ctl_info *mci)
|
|||
|
||||
debugf0("%s() idx=%d\n", __func__, mci->mc_idx);
|
||||
|
||||
INIT_LIST_HEAD(&mci->grp_kobj_list);
|
||||
|
||||
/* create a symlink for the device */
|
||||
err = sysfs_create_link(kobj_mci, &mci->dev->kobj,
|
||||
EDAC_DEVICE_SYMLINK);
|
||||
|
|
@ -806,7 +925,9 @@ int edac_create_sysfs_mci_device(struct mem_ctl_info *mci)
|
|||
* then create them now for the driver.
|
||||
*/
|
||||
if (mci->mc_driver_sysfs_attributes) {
|
||||
err = edac_create_mci_instance_attributes(mci);
|
||||
err = edac_create_mci_instance_attributes(mci,
|
||||
mci->mc_driver_sysfs_attributes,
|
||||
&mci->edac_mci_kobj);
|
||||
if (err) {
|
||||
debugf1("%s() failure to create mci attributes\n",
|
||||
__func__);
|
||||
|
|
@ -841,7 +962,8 @@ fail1:
|
|||
}
|
||||
|
||||
/* remove the mci instance's attributes, if any */
|
||||
edac_remove_mci_instance_attributes(mci);
|
||||
edac_remove_mci_instance_attributes(mci,
|
||||
mci->mc_driver_sysfs_attributes, &mci->edac_mci_kobj, 0);
|
||||
|
||||
/* remove the symlink */
|
||||
sysfs_remove_link(kobj_mci, EDAC_DEVICE_SYMLINK);
|
||||
|
|
@ -875,8 +997,9 @@ void edac_remove_sysfs_mci_device(struct mem_ctl_info *mci)
|
|||
debugf0("%s() remove_mci_instance\n", __func__);
|
||||
|
||||
/* remove this mci instance's attribtes */
|
||||
edac_remove_mci_instance_attributes(mci);
|
||||
|
||||
edac_remove_mci_instance_attributes(mci,
|
||||
mci->mc_driver_sysfs_attributes,
|
||||
&mci->edac_mci_kobj, 0);
|
||||
debugf0("%s() unregister this mci kobj\n", __func__);
|
||||
|
||||
/* unregister this instance's kobject */
|
||||
|
|
|
|||
61
drivers/edac/edac_mce.c
Normal file
61
drivers/edac/edac_mce.c
Normal file
|
|
@ -0,0 +1,61 @@
|
|||
/* 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_parse(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_parse);
|
||||
|
||||
MODULE_LICENSE("GPL");
|
||||
MODULE_AUTHOR("Mauro Carvalho Chehab <[email protected]>");
|
||||
MODULE_AUTHOR("Red Hat Inc. (http://www.redhat.com)");
|
||||
MODULE_DESCRIPTION("EDAC Driver for mcelog captured errors");
|
||||
2078
drivers/edac/i7core_edac.c
Normal file
2078
drivers/edac/i7core_edac.c
Normal file
File diff suppressed because it is too large
Load diff
Loading…
Reference in a new issue