Commit d870a9d5 authored by Linus Torvalds's avatar Linus Torvalds

Merge tag 'edac_for_4.5' of git://git.kernel.org/pub/scm/linux/kernel/git/bp/bp

Pull EDAC updates from Borislav Petkov:

 - hide EDAC workqueue from users (Borislav Petkov)

 - edac_subsys init/teardown cleanup (Borislav Petkov)

 - make mpc85xx-pci-edac a platform device (Scott Wood)

 - sb_edac KNL gen2 support (Jim Snow)

 - other small cleanups all over the place

* tag 'edac_for_4.5' of git://git.kernel.org/pub/scm/linux/kernel/git/bp/bp:
  EDAC, i5100: Use to_delayed_work()
  MAINTAINERS: Fix EDAC repo URLs format
  EDAC, sb_edac: Set fixed DIMM width on Xeon Knights Landing
  EDAC: Rework workqueue handling
  EDAC: Make edac_device workqueue setup/teardown functions static
  EDAC: Remove edac_get_sysfs_subsys() error handling
  EDAC: Unexport and make edac_subsys static
  EDAC: Rip out the edac_subsys reference counting
  EDAC: Robustify workqueues destruction
  EDAC, mc_sysfs: Fix freeing bus' name
  EDAC, mpc85xx: Make mpc85xx-pci-edac a platform device
  EDAC, sb_edac: Add Knights Landing (Xeon Phi gen 2) support
  EDAC, sb_edac: Add support for duplicate device IDs
  EDAC, sb_edac: Virtualize several hard-coded functions
  EDAC, mv64x60: Use platform_register/unregister_drivers()
  EDAC, mpc85xx: Use platform_register/unregister_drivers()
  EDAC: Add DDR4 flag
  EDAC: Remove references to bluesmoke.sourceforge.net
  EDAC, pci: Remove old disabled code
parents 2634bf25 1cac5503
EDAC - Error Detection And Correction
=====================================
"bluesmoke" was the name for this device driver when it was "out-of-tree"
and maintained at sourceforge.net. When it was pushed into 2.6.16 for the
first time, it was renamed to 'EDAC'.
"bluesmoke" was the name for this device driver when it
was "out-of-tree" and maintained at sourceforge.net -
bluesmoke.sourceforge.net. That site is mostly archaic now and can be
used only for historical purposes.
When the subsystem was pushed into 2.6.16 for the first time, it was
renamed to 'EDAC'.
PURPOSE
-------
......
......@@ -3933,9 +3933,8 @@ M: Doug Thompson <dougthompson@xmission.com>
M: Borislav Petkov <bp@alien8.de>
M: Mauro Carvalho Chehab <mchehab@osg.samsung.com>
L: linux-edac@vger.kernel.org
W: bluesmoke.sourceforge.net
T: git://git.kernel.org/pub/scm/linux/kernel/git/bp/bp.git#for-next
T: git://git.kernel.org/pub/linux/kernel/git/mchehab/linux-edac.git#linux_next
T: git git://git.kernel.org/pub/scm/linux/kernel/git/bp/bp.git for-next
T: git git://git.kernel.org/pub/scm/linux/kernel/git/mchehab/linux-edac.git linux_next
S: Supported
F: Documentation/edac.txt
F: drivers/edac/
......@@ -3945,7 +3944,6 @@ EDAC-AMD64
M: Doug Thompson <dougthompson@xmission.com>
M: Borislav Petkov <bp@alien8.de>
L: linux-edac@vger.kernel.org
W: bluesmoke.sourceforge.net
S: Maintained
F: drivers/edac/amd64_edac*
......@@ -3953,7 +3951,6 @@ EDAC-CALXEDA
M: Doug Thompson <dougthompson@xmission.com>
M: Robert Richter <rric@kernel.org>
L: linux-edac@vger.kernel.org
W: bluesmoke.sourceforge.net
S: Maintained
F: drivers/edac/highbank*
......@@ -3962,7 +3959,6 @@ M: Ralf Baechle <ralf@linux-mips.org>
M: David Daney <david.daney@cavium.com>
L: linux-edac@vger.kernel.org
L: linux-mips@linux-mips.org
W: bluesmoke.sourceforge.net
S: Supported
F: drivers/edac/octeon_edac*
......@@ -3970,63 +3966,54 @@ EDAC-E752X
M: Mark Gross <mark.gross@intel.com>
M: Doug Thompson <dougthompson@xmission.com>
L: linux-edac@vger.kernel.org
W: bluesmoke.sourceforge.net
S: Maintained
F: drivers/edac/e752x_edac.c
EDAC-E7XXX
M: Doug Thompson <dougthompson@xmission.com>
L: linux-edac@vger.kernel.org
W: bluesmoke.sourceforge.net
S: Maintained
F: drivers/edac/e7xxx_edac.c
EDAC-GHES
M: Mauro Carvalho Chehab <mchehab@osg.samsung.com>
L: linux-edac@vger.kernel.org
W: bluesmoke.sourceforge.net
S: Maintained
F: drivers/edac/ghes_edac.c
EDAC-I82443BXGX
M: Tim Small <tim@buttersideup.com>
L: linux-edac@vger.kernel.org
W: bluesmoke.sourceforge.net
S: Maintained
F: drivers/edac/i82443bxgx_edac.c
EDAC-I3000
M: Jason Uhlenkott <juhlenko@akamai.com>
L: linux-edac@vger.kernel.org
W: bluesmoke.sourceforge.net
S: Maintained
F: drivers/edac/i3000_edac.c
EDAC-I5000
M: Doug Thompson <dougthompson@xmission.com>
L: linux-edac@vger.kernel.org
W: bluesmoke.sourceforge.net
S: Maintained
F: drivers/edac/i5000_edac.c
EDAC-I5400
M: Mauro Carvalho Chehab <mchehab@osg.samsung.com>
L: linux-edac@vger.kernel.org
W: bluesmoke.sourceforge.net
S: Maintained
F: drivers/edac/i5400_edac.c
EDAC-I7300
M: Mauro Carvalho Chehab <mchehab@osg.samsung.com>
L: linux-edac@vger.kernel.org
W: bluesmoke.sourceforge.net
S: Maintained
F: drivers/edac/i7300_edac.c
EDAC-I7CORE
M: Mauro Carvalho Chehab <mchehab@osg.samsung.com>
L: linux-edac@vger.kernel.org
W: bluesmoke.sourceforge.net
S: Maintained
F: drivers/edac/i7core_edac.c
......@@ -4034,42 +4021,36 @@ EDAC-I82975X
M: Ranganathan Desikan <ravi@jetztechnologies.com>
M: "Arvind R." <arvino55@gmail.com>
L: linux-edac@vger.kernel.org
W: bluesmoke.sourceforge.net
S: Maintained
F: drivers/edac/i82975x_edac.c
EDAC-IE31200
M: Jason Baron <jbaron@akamai.com>
L: linux-edac@vger.kernel.org
W: bluesmoke.sourceforge.net
S: Maintained
F: drivers/edac/ie31200_edac.c
EDAC-MPC85XX
M: Johannes Thumshirn <morbidrsa@gmail.com>
L: linux-edac@vger.kernel.org
W: bluesmoke.sourceforge.net
S: Maintained
F: drivers/edac/mpc85xx_edac.[ch]
EDAC-PASEMI
M: Egor Martovetsky <egor@pasemi.com>
L: linux-edac@vger.kernel.org
W: bluesmoke.sourceforge.net
S: Maintained
F: drivers/edac/pasemi_edac.c
EDAC-R82600
M: Tim Small <tim@buttersideup.com>
L: linux-edac@vger.kernel.org
W: bluesmoke.sourceforge.net
S: Maintained
F: drivers/edac/r82600_edac.c
EDAC-SBRIDGE
M: Mauro Carvalho Chehab <mchehab@osg.samsung.com>
L: linux-edac@vger.kernel.org
W: bluesmoke.sourceforge.net
S: Maintained
F: drivers/edac/sb_edac.c
......
......@@ -21,10 +21,12 @@
#include <linux/pci.h>
#include <linux/delay.h>
#include <linux/string.h>
#include <linux/fsl/edac.h>
#include <linux/init.h>
#include <linux/interrupt.h>
#include <linux/memblock.h>
#include <linux/log2.h>
#include <linux/platform_device.h>
#include <linux/slab.h>
#include <linux/suspend.h>
#include <linux/syscore_ops.h>
......@@ -1255,6 +1257,25 @@ void fsl_pcibios_fixup_phb(struct pci_controller *phb)
#endif
}
static int add_err_dev(struct platform_device *pdev)
{
struct platform_device *errdev;
struct mpc85xx_edac_pci_plat_data pd = {
.of_node = pdev->dev.of_node
};
errdev = platform_device_register_resndata(&pdev->dev,
"mpc85xx-pci-edac",
PLATFORM_DEVID_AUTO,
pdev->resource,
pdev->num_resources,
&pd, sizeof(pd));
if (IS_ERR(errdev))
return PTR_ERR(errdev);
return 0;
}
static int fsl_pci_probe(struct platform_device *pdev)
{
struct device_node *node;
......@@ -1262,8 +1283,13 @@ static int fsl_pci_probe(struct platform_device *pdev)
node = pdev->dev.of_node;
ret = fsl_add_bridge(pdev, fsl_pci_primary == node);
if (ret)
return ret;
mpc85xx_pci_err_probe(pdev);
ret = add_err_dev(pdev);
if (ret)
dev_err(&pdev->dev, "couldn't register error device: %d\n",
ret);
return 0;
}
......
......@@ -130,15 +130,6 @@ void fsl_pci_assign_primary(void);
static inline void fsl_pci_assign_primary(void) {}
#endif
#ifdef CONFIG_EDAC_MPC85XX
int mpc85xx_pci_err_probe(struct platform_device *op);
#else
static inline int mpc85xx_pci_err_probe(struct platform_device *op)
{
return -ENOTSUPP;
}
#endif
#ifdef CONFIG_FSL_PCI
extern int fsl_pci_mcheck_exception(struct pt_regs *);
#else
......
......@@ -10,7 +10,7 @@ obj-$(CONFIG_EDAC) := edac_stub.o
obj-$(CONFIG_EDAC_MM_EDAC) += edac_core.o
edac_core-y := edac_mc.o edac_device.o edac_mc_sysfs.o
edac_core-y += edac_module.o edac_device_sysfs.o
edac_core-y += edac_module.o edac_device_sysfs.o wq.o
edac_core-$(CONFIG_EDAC_DEBUG) += debugfs.o
......
......@@ -390,11 +390,9 @@ static void edac_device_workq_function(struct work_struct *work_req)
* between integral seconds
*/
if (edac_dev->poll_msec == 1000)
queue_delayed_work(edac_workqueue, &edac_dev->work,
round_jiffies_relative(edac_dev->delay));
edac_queue_work(&edac_dev->work, round_jiffies_relative(edac_dev->delay));
else
queue_delayed_work(edac_workqueue, &edac_dev->work,
edac_dev->delay);
edac_queue_work(&edac_dev->work, edac_dev->delay);
}
/*
......@@ -402,8 +400,8 @@ static void edac_device_workq_function(struct work_struct *work_req)
* initialize a workq item for this edac_device instance
* passing in the new delay period in msec
*/
void edac_device_workq_setup(struct edac_device_ctl_info *edac_dev,
unsigned msec)
static void edac_device_workq_setup(struct edac_device_ctl_info *edac_dev,
unsigned msec)
{
edac_dbg(0, "\n");
......@@ -422,29 +420,23 @@ void edac_device_workq_setup(struct edac_device_ctl_info *edac_dev,
* to fire together on the 1 second exactly
*/
if (edac_dev->poll_msec == 1000)
queue_delayed_work(edac_workqueue, &edac_dev->work,
round_jiffies_relative(edac_dev->delay));
edac_queue_work(&edac_dev->work, round_jiffies_relative(edac_dev->delay));
else
queue_delayed_work(edac_workqueue, &edac_dev->work,
edac_dev->delay);
edac_queue_work(&edac_dev->work, edac_dev->delay);
}
/*
* edac_device_workq_teardown
* stop the workq processing on this edac_dev
*/
void edac_device_workq_teardown(struct edac_device_ctl_info *edac_dev)
static void edac_device_workq_teardown(struct edac_device_ctl_info *edac_dev)
{
int status;
if (!edac_dev->edac_check)
return;
status = cancel_delayed_work(&edac_dev->work);
if (status == 0) {
/* workq instance might be running, wait for it */
flush_workqueue(edac_workqueue);
}
edac_dev->op_state = OP_OFFLINE;
edac_stop_work(&edac_dev->work);
}
/*
......@@ -457,16 +449,15 @@ void edac_device_workq_teardown(struct edac_device_ctl_info *edac_dev)
void edac_device_reset_delay_period(struct edac_device_ctl_info *edac_dev,
unsigned long value)
{
/* cancel the current workq request, without the mutex lock */
edac_device_workq_teardown(edac_dev);
unsigned long jiffs = msecs_to_jiffies(value);
/* acquire the mutex before doing the workq setup */
mutex_lock(&device_ctls_mutex);
if (value == 1000)
jiffs = round_jiffies_relative(value);
/* restart the workq request, with new delay value */
edac_device_workq_setup(edac_dev, value);
edac_dev->poll_msec = value;
edac_dev->delay = jiffs;
mutex_unlock(&device_ctls_mutex);
edac_mod_work(&edac_dev->work, jiffs);
}
/*
......
......@@ -237,11 +237,6 @@ int edac_device_register_sysfs_main_kobj(struct edac_device_ctl_info *edac_dev)
/* get the /sys/devices/system/edac reference */
edac_subsys = edac_get_sysfs_subsys();
if (edac_subsys == NULL) {
edac_dbg(1, "no edac_subsys error\n");
err = -ENODEV;
goto err_out;
}
/* Point to the 'edac_subsys' this instance 'reports' to */
edac_dev->edac_subsys = edac_subsys;
......@@ -256,7 +251,7 @@ int edac_device_register_sysfs_main_kobj(struct edac_device_ctl_info *edac_dev)
if (!try_module_get(edac_dev->owner)) {
err = -ENODEV;
goto err_mod_get;
goto err_out;
}
/* register */
......@@ -282,9 +277,6 @@ int edac_device_register_sysfs_main_kobj(struct edac_device_ctl_info *edac_dev)
err_kobj_reg:
module_put(edac_dev->owner);
err_mod_get:
edac_put_sysfs_subsys();
err_out:
return err;
}
......@@ -306,7 +298,6 @@ void edac_device_unregister_sysfs_main_kobj(struct edac_device_ctl_info *dev)
* b) 'kfree' the memory
*/
kobject_put(&dev->kobj);
edac_put_sysfs_subsys();
}
/* edac_dev -> instance information */
......
......@@ -548,8 +548,7 @@ static void edac_mc_workq_function(struct work_struct *work_req)
mutex_unlock(&mem_ctls_mutex);
/* Reschedule */
queue_delayed_work(edac_workqueue, &mci->work,
msecs_to_jiffies(edac_mc_get_poll_msec()));
edac_queue_work(&mci->work, msecs_to_jiffies(edac_mc_get_poll_msec()));
}
/*
......@@ -561,8 +560,7 @@ static void edac_mc_workq_function(struct work_struct *work_req)
*
* called with the mem_ctls_mutex held
*/
static void edac_mc_workq_setup(struct mem_ctl_info *mci, unsigned msec,
bool init)
static void edac_mc_workq_setup(struct mem_ctl_info *mci, unsigned msec)
{
edac_dbg(0, "\n");
......@@ -570,10 +568,9 @@ static void edac_mc_workq_setup(struct mem_ctl_info *mci, unsigned msec,
if (mci->op_state != OP_RUNNING_POLL)
return;
if (init)
INIT_DELAYED_WORK(&mci->work, edac_mc_workq_function);
INIT_DELAYED_WORK(&mci->work, edac_mc_workq_function);
mod_delayed_work(edac_workqueue, &mci->work, msecs_to_jiffies(msec));
edac_queue_work(&mci->work, msecs_to_jiffies(msec));
}
/*
......@@ -586,18 +583,9 @@ static void edac_mc_workq_setup(struct mem_ctl_info *mci, unsigned msec,
*/
static void edac_mc_workq_teardown(struct mem_ctl_info *mci)
{
int status;
if (mci->op_state != OP_RUNNING_POLL)
return;
status = cancel_delayed_work(&mci->work);
if (status == 0) {
edac_dbg(0, "not canceled, flush the queue\n");
mci->op_state = OP_OFFLINE;
/* workq instance might be running, wait for it */
flush_workqueue(edac_workqueue);
}
edac_stop_work(&mci->work);
}
/*
......@@ -616,9 +604,8 @@ void edac_mc_reset_delay_period(unsigned long value)
list_for_each(item, &mc_devices) {
mci = list_entry(item, struct mem_ctl_info, link);
edac_mc_workq_setup(mci, value, false);
edac_mod_work(&mci->work, value);
}
mutex_unlock(&mem_ctls_mutex);
}
......@@ -789,7 +776,7 @@ int edac_mc_add_mc_with_groups(struct mem_ctl_info *mci,
/* This instance is NOW RUNNING */
mci->op_state = OP_RUNNING_POLL;
edac_mc_workq_setup(mci, edac_mc_get_poll_msec(), true);
edac_mc_workq_setup(mci, edac_mc_get_poll_msec());
} else {
mci->op_state = OP_RUNNING_INTERRUPT;
}
......
......@@ -880,21 +880,26 @@ static struct device_type mci_attr_type = {
int edac_create_sysfs_mci_device(struct mem_ctl_info *mci,
const struct attribute_group **groups)
{
char *name;
int i, err;
/*
* The memory controller needs its own bus, in order to avoid
* namespace conflicts at /sys/bus/edac.
*/
mci->bus->name = kasprintf(GFP_KERNEL, "mc%d", mci->mc_idx);
if (!mci->bus->name)
name = kasprintf(GFP_KERNEL, "mc%d", mci->mc_idx);
if (!name)
return -ENOMEM;
mci->bus->name = name;
edac_dbg(0, "creating bus %s\n", mci->bus->name);
err = bus_register(mci->bus);
if (err < 0)
goto fail_free_name;
if (err < 0) {
kfree(name);
return err;
}
/* get the /sys/devices/system/edac subsys reference */
mci->dev.type = &mci_attr_type;
......@@ -961,8 +966,8 @@ int edac_create_sysfs_mci_device(struct mem_ctl_info *mci,
device_unregister(&mci->dev);
fail_unregister_bus:
bus_unregister(mci->bus);
fail_free_name:
kfree(mci->bus->name);
kfree(name);
return err;
}
......@@ -993,10 +998,12 @@ void edac_remove_sysfs_mci_device(struct mem_ctl_info *mci)
void edac_unregister_sysfs(struct mem_ctl_info *mci)
{
const char *name = mci->bus->name;
edac_dbg(1, "Unregistering device %s\n", dev_name(&mci->dev));
device_unregister(&mci->dev);
bus_unregister(mci->bus);
kfree(mci->bus->name);
kfree(name);
}
static void mc_attr_release(struct device *dev)
......@@ -1018,24 +1025,15 @@ static struct device_type mc_attr_type = {
*/
int __init edac_mc_sysfs_init(void)
{
struct bus_type *edac_subsys;
int err;
/* get the /sys/devices/system/edac subsys reference */
edac_subsys = edac_get_sysfs_subsys();
if (edac_subsys == NULL) {
edac_dbg(1, "no edac_subsys\n");
err = -EINVAL;
goto out;
}
mci_pdev = kzalloc(sizeof(*mci_pdev), GFP_KERNEL);
if (!mci_pdev) {
err = -ENOMEM;
goto out_put_sysfs;
goto out;
}
mci_pdev->bus = edac_subsys;
mci_pdev->bus = edac_get_sysfs_subsys();
mci_pdev->type = &mc_attr_type;
device_initialize(mci_pdev);
dev_set_name(mci_pdev, "mc");
......@@ -1050,8 +1048,6 @@ int __init edac_mc_sysfs_init(void)
out_dev_free:
kfree(mci_pdev);
out_put_sysfs:
edac_put_sysfs_subsys();
out:
return err;
}
......@@ -1059,5 +1055,4 @@ int __init edac_mc_sysfs_init(void)
void edac_mc_sysfs_exit(void)
{
device_unregister(mci_pdev);
edac_put_sysfs_subsys();
}
......@@ -43,9 +43,6 @@ module_param_call(edac_debug_level, edac_set_debug_level, param_get_int,
MODULE_PARM_DESC(edac_debug_level, "EDAC debug level: [0-4], default: 2");
#endif
/* scope is to module level only */
struct workqueue_struct *edac_workqueue;
/*
* edac_op_state_to_string()
*/
......@@ -66,31 +63,37 @@ char *edac_op_state_to_string(int opstate)
}
/*
* edac_workqueue_setup
* initialize the edac work queue for polling operations
* sysfs object: /sys/devices/system/edac
* need to export to other files
*/
static int edac_workqueue_setup(void)
static struct bus_type edac_subsys = {
.name = "edac",
.dev_name = "edac",
};
static int edac_subsys_init(void)
{
edac_workqueue = create_singlethread_workqueue("edac-poller");
if (edac_workqueue == NULL)
return -ENODEV;
else
return 0;
int err;
/* create the /sys/devices/system/edac directory */
err = subsys_system_register(&edac_subsys, NULL);
if (err)
printk(KERN_ERR "Error registering toplevel EDAC sysfs dir\n");
return err;
}
/*
* edac_workqueue_teardown
* teardown the edac workqueue
*/
static void edac_workqueue_teardown(void)
static void edac_subsys_exit(void)
{
if (edac_workqueue) {
flush_workqueue(edac_workqueue);
destroy_workqueue(edac_workqueue);
edac_workqueue = NULL;
}
bus_unregister(&edac_subsys);
}
/* return pointer to the 'edac' node in sysfs */
struct bus_type *edac_get_sysfs_subsys(void)
{
return &edac_subsys;
}
EXPORT_SYMBOL_GPL(edac_get_sysfs_subsys);
/*
* edac_init
* module initialization entry point
......@@ -101,6 +104,10 @@ static int __init edac_init(void)
edac_printk(KERN_INFO, EDAC_MC, EDAC_VERSION "\n");
err = edac_subsys_init();
if (err)
return err;
/*
* Harvest and clear any boot/initialization PCI parity errors
*
......@@ -129,6 +136,8 @@ static int __init edac_init(void)
edac_mc_sysfs_exit();
err_sysfs:
edac_subsys_exit();
return err;
}
......@@ -144,6 +153,7 @@ static void __exit edac_exit(void)
edac_workqueue_teardown();
edac_mc_sysfs_exit();
edac_debugfs_exit();
edac_subsys_exit();
}
/*
......
......@@ -47,10 +47,12 @@ extern int edac_device_create_sysfs(struct edac_device_ctl_info *edac_dev);
extern void edac_device_remove_sysfs(struct edac_device_ctl_info *edac_dev);
/* edac core workqueue: single CPU mode */
extern struct workqueue_struct *edac_workqueue;
extern void edac_device_workq_setup(struct edac_device_ctl_info *edac_dev,
unsigned msec);
extern void edac_device_workq_teardown(struct edac_device_ctl_info *edac_dev);
int edac_workqueue_setup(void);
void edac_workqueue_teardown(void);
bool edac_queue_work(struct delayed_work *work, unsigned long delay);
bool edac_stop_work(struct delayed_work *work);
bool edac_mod_work(struct delayed_work *work, unsigned long delay);
extern void edac_device_reset_delay_period(struct edac_device_ctl_info
*edac_dev, unsigned long value);
extern void edac_mc_reset_delay_period(unsigned long value);
......
......@@ -178,41 +178,6 @@ static void del_edac_pci_from_global_list(struct edac_pci_ctl_info *pci)
INIT_LIST_HEAD(&pci->link);
}
#if 0
/* Older code, but might use in the future */
/*
* edac_pci_find()
* Search for an edac_pci_ctl_info structure whose index is 'idx'
*
* If found, return a pointer to the structure
* Else return NULL.
*
* Caller must hold pci_ctls_mutex.
*/
struct edac_pci_ctl_info *edac_pci_find(int idx)
{
struct list_head *item;
struct edac_pci_ctl_info *pci;
/* Iterage over list, looking for exact match of ID */
list_for_each(item, &edac_pci_list) {
pci = list_entry(item, struct edac_pci_ctl_info, link);
if (pci->pci_idx >= idx) {
if (pci->pci_idx == idx)
return pci;
/* not on list, so terminate early */
break;
}
}
return NULL;
}
EXPORT_SYMBOL_GPL(edac_pci_find);
#endif
/*
* edac_pci_workq_function()
*
......@@ -244,7 +209,7 @@ static void edac_pci_workq_function(struct work_struct *work_req)
delay = msecs_to_jiffies(msec);
/* Reschedule only if we are in POLL mode */
queue_delayed_work(edac_workqueue, &pci->work, delay);
edac_queue_work(&pci->work, delay);
}
mutex_unlock(&edac_pci_ctls_mutex);
......@@ -264,8 +229,8 @@ static void edac_pci_workq_setup(struct edac_pci_ctl_info *pci,
edac_dbg(0, "\n");
INIT_DELAYED_WORK(&pci->work, edac_pci_workq_function);
queue_delayed_work(edac_workqueue, &pci->work,
msecs_to_jiffies(edac_pci_get_poll_msec()));
edac_queue_work(&pci->work, msecs_to_jiffies(edac_pci_get_poll_msec()));
}
/*
......@@ -273,38 +238,13 @@ static void edac_pci_workq_setup(struct edac_pci_ctl_info *pci,
* stop the workq processing on this edac_pci instance
*/
static void edac_pci_workq_teardown(struct edac_pci_ctl_info *pci)
{
int status;
edac_dbg(0, "\n");
status = cancel_delayed_work(&pci->work);
if (status == 0)
flush_workqueue(edac_workqueue);
}
/*
* edac_pci_reset_delay_period
*
* called with a new period value for the workq period
* a) stop current workq timer
* b) restart workq timer with new value
*/
void edac_pci_reset_delay_period(struct edac_pci_ctl_info *pci,
unsigned long value)
{
edac_dbg(0, "\n");
edac_pci_workq_teardown(pci);
/* need to lock for the setup */
mutex_lock(&edac_pci_ctls_mutex);
edac_pci_workq_setup(pci, value);
pci->op_state = OP_OFFLINE;
mutex_unlock(&edac_pci_ctls_mutex);
edac_stop_work(&pci->work);
}
EXPORT_SYMBOL_GPL(edac_pci_reset_delay_period);
/*
* edac_pci_alloc_index: Allocate a unique PCI index number
......
......@@ -331,10 +331,7 @@ static struct kobj_type ktype_edac_pci_main_kobj = {
};
/**
* edac_pci_main_kobj_setup()
*
* setup the sysfs for EDAC PCI attributes
* assumes edac_subsys has already been initialized
* edac_pci_main_kobj_setup: Setup the sysfs for EDAC PCI attributes.
*/
static int edac_pci_main_kobj_setup(void)
{
......@@ -351,11 +348,6 @@ static int edac_pci_main_kobj_setup(void)
* controls and attributes
*/
edac_subsys = edac_get_sysfs_subsys();
if (edac_subsys == NULL) {
edac_dbg(1, "no edac_subsys\n");
err = -ENODEV;
goto decrement_count_fail;
}
/* Bump the reference count on this module to ensure the
* modules isn't unloaded until we deconstruct the top
......@@ -364,7 +356,7 @@ static int edac_pci_main_kobj_setup(void)
if (!try_module_get(THIS_MODULE)) {
edac_dbg(1, "try_module_get() failed\n");
err = -ENODEV;
goto mod_get_fail;
goto decrement_count_fail;
}
edac_pci_top_main_kobj = kzalloc(sizeof(struct kobject), GFP_KERNEL);
......@@ -399,9 +391,6 @@ static int edac_pci_main_kobj_setup(void)
kzalloc_fail:
module_put(THIS_MODULE);
mod_get_fail:
edac_put_sysfs_subsys();
decrement_count_fail:
/* if are on this error exit, nothing to tear down */
atomic_dec(&edac_pci_sysfs_refcount);
......@@ -426,7 +415,6 @@ static void edac_pci_main_kobj_teardown(void)
if (atomic_dec_return(&edac_pci_sysfs_refcount) == 0) {
edac_dbg(0, "called kobject_put on main kobj\n");
kobject_put(edac_pci_top_main_kobj);
edac_put_sysfs_subsys();
}
}
......
......@@ -26,8 +26,6 @@ EXPORT_SYMBOL_GPL(edac_handlers);
int edac_err_assert = 0;
EXPORT_SYMBOL_GPL(edac_err_assert);
static atomic_t edac_subsys_valid = ATOMIC_INIT(0);
int edac_report_status = EDAC_REPORTING_ENABLED;
EXPORT_SYMBOL_GPL(edac_report_status);
......@@ -68,42 +66,3 @@ void edac_atomic_assert_error(void)
edac_err_assert++;
}
EXPORT_SYMBOL_GPL(edac_atomic_assert_error);
/*
* sysfs object: /sys/devices/system/edac
* need to export to other files
*/
struct bus_type edac_subsys = {
.name = "edac",
.dev_name = "edac",
};
EXPORT_SYMBOL_GPL(edac_subsys);
/* return pointer to the 'edac' node in sysfs */
struct bus_type *edac_get_sysfs_subsys(void)
{
int err = 0;
if (atomic_read(&edac_subsys_valid))
goto out;
/* create the /sys/devices/system/edac directory */
err = subsys_system_register(&edac_subsys, NULL);
if (err) {
printk(KERN_ERR "Error registering toplevel EDAC sysfs dir\n");
return NULL;
}
out:
atomic_inc(&edac_subsys_valid);
return &edac_subsys;
}
EXPORT_SYMBOL_GPL(edac_get_sysfs_subsys);
void edac_put_sysfs_subsys(void)
{
/* last user unregisters it */
if (atomic_dec_and_test(&edac_subsys_valid))
bus_unregister(&edac_subsys);
}
EXPORT_SYMBOL_GPL(edac_put_sysfs_subsys);
......@@ -575,9 +575,7 @@ static void i5100_check_error(struct mem_ctl_info *mci)
static void i5100_refresh_scrubbing(struct work_struct *work)
{
struct delayed_work *i5100_scrubbing = container_of(work,
struct delayed_work,
work);
struct delayed_work *i5100_scrubbing = to_delayed_work(work);
struct i5100_priv *priv = container_of(i5100_scrubbing,
struct i5100_priv,
i5100_scrubbing);
......
......@@ -20,6 +20,7 @@
#include <linux/edac.h>
#include <linux/smp.h>
#include <linux/gfp.h>
#include <linux/fsl/edac.h>
#include <linux/of_platform.h>
#include <linux/of_device.h>
......@@ -238,10 +239,12 @@ static irqreturn_t mpc85xx_pci_isr(int irq, void *dev_id)
return IRQ_HANDLED;
}
int mpc85xx_pci_err_probe(struct platform_device *op)
static int mpc85xx_pci_err_probe(struct platform_device *op)
{
struct edac_pci_ctl_info *pci;
struct mpc85xx_pci_pdata *pdata;
struct mpc85xx_edac_pci_plat_data *plat_data;
struct device_node *of_node;
struct resource r;
int res = 0;
......@@ -266,7 +269,15 @@ int mpc85xx_pci_err_probe(struct platform_device *op)
pdata->name = "mpc85xx_pci_err";
pdata->irq = NO_IRQ;
if (mpc85xx_pcie_find_capability(op->dev.of_node) > 0)
plat_data = op->dev.platform_data;
if (!plat_data) {
dev_err(&op->dev, "no platform data");
res = -ENXIO;
goto err;
}
of_node = plat_data->of_node;
if (mpc85xx_pcie_find_capability(of_node) > 0)
pdata->is_pcie = true;
dev_set_drvdata(&op->dev, pci);
......@@ -284,7 +295,7 @@ int mpc85xx_pci_err_probe(struct platform_device *op)
pdata->edac_idx = edac_pci_idx++;
res = of_address_to_resource(op->dev.of_node, 0, &r);
res = of_address_to_resource(of_node, 0, &r);
if (res) {
printk(KERN_ERR "%s: Unable to get resource for "
"PCI err regs\n", __func__);
......@@ -339,7 +350,7 @@ int mpc85xx_pci_err_probe(struct platform_device *op)
}
if (edac_op_state == EDAC_OPSTATE_INT) {
pdata->irq = irq_of_parse_and_map(op->dev.of_node, 0);
pdata->irq = irq_of_parse_and_map(of_node, 0);
res = devm_request_irq(&op->dev, pdata->irq,
mpc85xx_pci_isr,
IRQF_SHARED,
......@@ -386,8 +397,22 @@ int mpc85xx_pci_err_probe(struct platform_device *op)
devres_release_group(&op->dev, mpc85xx_pci_err_probe);
return res;
}
EXPORT_SYMBOL(mpc85xx_pci_err_probe);
static const struct platform_device_id mpc85xx_pci_err_match[] = {
{
.name = "mpc85xx-pci-edac"
},
{}
};
static struct platform_driver mpc85xx_pci_err_driver = {
.probe = mpc85xx_pci_err_probe,
.id_table = mpc85xx_pci_err_match,
.driver = {
.name = "mpc85xx_pci_err",
.suppress_bind_attrs = true,
},
};
#endif /* CONFIG_PCI */
/**************************** L2 Err device ***************************/
......@@ -1208,6 +1233,14 @@ static void __init mpc85xx_mc_clear_rfxe(void *data)
}
#endif
static struct platform_driver * const drivers[] = {
&mpc85xx_mc_err_driver,
&mpc85xx_l2_err_driver,
#ifdef CONFIG_PCI
&mpc85xx_pci_err_driver,
#endif
};
static int __init mpc85xx_mc_init(void)
{
int res = 0;
......@@ -1226,13 +1259,9 @@ static int __init mpc85xx_mc_init(void)
break;
}
res = platform_driver_register(&mpc85xx_mc_err_driver);
if (res)
printk(KERN_WARNING EDAC_MOD_STR "MC fails to register\n");
res = platform_driver_register(&mpc85xx_l2_err_driver);
res = platform_register_drivers(drivers, ARRAY_SIZE(drivers));
if (res)
printk(KERN_WARNING EDAC_MOD_STR "L2 fails to register\n");
printk(KERN_WARNING EDAC_MOD_STR "drivers fail to register\n");
#ifdef CONFIG_FSL_SOC_BOOKE
pvr = mfspr(SPRN_PVR);
......@@ -1270,8 +1299,7 @@ static void __exit mpc85xx_mc_exit(void)
on_each_cpu(mpc85xx_mc_restore_hid1, NULL, 0);
}
#endif
platform_driver_unregister(&mpc85xx_l2_err_driver);
platform_driver_unregister(&mpc85xx_mc_err_driver);
platform_unregister_drivers(drivers, ARRAY_SIZE(drivers));
}
module_exit(mpc85xx_mc_exit);
......
......@@ -847,6 +847,15 @@ static struct platform_driver mv64x60_mc_err_driver = {
}
};
static struct platform_driver * const drivers[] = {
&mv64x60_mc_err_driver,
&mv64x60_cpu_err_driver,
&mv64x60_sram_err_driver,
#ifdef CONFIG_PCI
&mv64x60_pci_err_driver,
#endif
};
static int __init mv64x60_edac_init(void)
{
int ret = 0;
......@@ -863,39 +872,13 @@ static int __init mv64x60_edac_init(void)
break;
}
ret = platform_driver_register(&mv64x60_mc_err_driver);
if (ret)
printk(KERN_WARNING EDAC_MOD_STR "MC err failed to register\n");
ret = platform_driver_register(&mv64x60_cpu_err_driver);
if (ret)
printk(KERN_WARNING EDAC_MOD_STR
"CPU err failed to register\n");
ret = platform_driver_register(&mv64x60_sram_err_driver);
if (ret)
printk(KERN_WARNING EDAC_MOD_STR
"SRAM err failed to register\n");
#ifdef CONFIG_PCI
ret = platform_driver_register(&mv64x60_pci_err_driver);
if (ret)
printk(KERN_WARNING EDAC_MOD_STR
"PCI err failed to register\n");
#endif
return ret;
return platform_register_drivers(drivers, ARRAY_SIZE(drivers));
}
module_init(mv64x60_edac_init);
static void __exit mv64x60_edac_exit(void)
{
#ifdef CONFIG_PCI
platform_driver_unregister(&mv64x60_pci_err_driver);
#endif
platform_driver_unregister(&mv64x60_sram_err_driver);
platform_driver_unregister(&mv64x60_cpu_err_driver);
platform_driver_unregister(&mv64x60_mc_err_driver);
platform_unregister_drivers(drivers, ARRAY_SIZE(drivers));
}
module_exit(mv64x60_edac_exit);
......
This diff is collapsed.
#include "edac_module.h"
static struct workqueue_struct *wq;
bool edac_queue_work(struct delayed_work *work, unsigned long delay)
{
return queue_delayed_work(wq, work, delay);
}
EXPORT_SYMBOL_GPL(edac_queue_work);
bool edac_mod_work(struct delayed_work *work, unsigned long delay)
{
return mod_delayed_work(wq, work, delay);
}
EXPORT_SYMBOL_GPL(edac_mod_work);
bool edac_stop_work(struct delayed_work *work)
{
bool ret;
ret = cancel_delayed_work_sync(work);
flush_workqueue(wq);
return ret;
}
EXPORT_SYMBOL_GPL(edac_stop_work);
int edac_workqueue_setup(void)
{
wq = create_singlethread_workqueue("edac-poller");
if (!wq)
return -ENODEV;
else
return 0;
}
void edac_workqueue_teardown(void)
{
flush_workqueue(wq);
destroy_workqueue(wq);
wq = NULL;
}
......@@ -28,12 +28,10 @@ struct device;
extern int edac_op_state;
extern int edac_err_assert;
extern atomic_t edac_handlers;
extern struct bus_type edac_subsys;
extern int edac_handler_set(void);
extern void edac_atomic_assert_error(void);
extern struct bus_type *edac_get_sysfs_subsys(void);
extern void edac_put_sysfs_subsys(void);
enum {
EDAC_REPORTING_ENABLED,
......@@ -237,8 +235,10 @@ enum mem_type {
#define MEM_FLAG_FB_DDR2 BIT(MEM_FB_DDR2)
#define MEM_FLAG_RDDR2 BIT(MEM_RDDR2)
#define MEM_FLAG_XDR BIT(MEM_XDR)
#define MEM_FLAG_DDR3 BIT(MEM_DDR3)
#define MEM_FLAG_RDDR3 BIT(MEM_RDDR3)
#define MEM_FLAG_DDR3 BIT(MEM_DDR3)
#define MEM_FLAG_RDDR3 BIT(MEM_RDDR3)
#define MEM_FLAG_DDR4 BIT(MEM_DDR4)
#define MEM_FLAG_RDDR4 BIT(MEM_RDDR4)
/**
* enum edac-type - Error Detection and Correction capabilities and mode
......
#ifndef FSL_EDAC_H
#define FSL_EDAC_H
struct mpc85xx_edac_pci_plat_data {
struct device_node *of_node;
};
#endif
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment