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 EDAC - Error Detection And Correction
===================================== =====================================
"bluesmoke" was the name for this device driver when it was "out-of-tree" "bluesmoke" was the name for this device driver when it
and maintained at sourceforge.net. When it was pushed into 2.6.16 for the was "out-of-tree" and maintained at sourceforge.net -
first time, it was renamed to 'EDAC'. 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 PURPOSE
------- -------
......
...@@ -3933,9 +3933,8 @@ M: Doug Thompson <dougthompson@xmission.com> ...@@ -3933,9 +3933,8 @@ M: Doug Thompson <dougthompson@xmission.com>
M: Borislav Petkov <bp@alien8.de> M: Borislav Petkov <bp@alien8.de>
M: Mauro Carvalho Chehab <mchehab@osg.samsung.com> M: Mauro Carvalho Chehab <mchehab@osg.samsung.com>
L: linux-edac@vger.kernel.org L: linux-edac@vger.kernel.org
W: bluesmoke.sourceforge.net T: git git://git.kernel.org/pub/scm/linux/kernel/git/bp/bp.git for-next
T: 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
T: git://git.kernel.org/pub/linux/kernel/git/mchehab/linux-edac.git#linux_next
S: Supported S: Supported
F: Documentation/edac.txt F: Documentation/edac.txt
F: drivers/edac/ F: drivers/edac/
...@@ -3945,7 +3944,6 @@ EDAC-AMD64 ...@@ -3945,7 +3944,6 @@ EDAC-AMD64
M: Doug Thompson <dougthompson@xmission.com> M: Doug Thompson <dougthompson@xmission.com>
M: Borislav Petkov <bp@alien8.de> M: Borislav Petkov <bp@alien8.de>
L: linux-edac@vger.kernel.org L: linux-edac@vger.kernel.org
W: bluesmoke.sourceforge.net
S: Maintained S: Maintained
F: drivers/edac/amd64_edac* F: drivers/edac/amd64_edac*
...@@ -3953,7 +3951,6 @@ EDAC-CALXEDA ...@@ -3953,7 +3951,6 @@ EDAC-CALXEDA
M: Doug Thompson <dougthompson@xmission.com> M: Doug Thompson <dougthompson@xmission.com>
M: Robert Richter <rric@kernel.org> M: Robert Richter <rric@kernel.org>
L: linux-edac@vger.kernel.org L: linux-edac@vger.kernel.org
W: bluesmoke.sourceforge.net
S: Maintained S: Maintained
F: drivers/edac/highbank* F: drivers/edac/highbank*
...@@ -3962,7 +3959,6 @@ M: Ralf Baechle <ralf@linux-mips.org> ...@@ -3962,7 +3959,6 @@ M: Ralf Baechle <ralf@linux-mips.org>
M: David Daney <david.daney@cavium.com> M: David Daney <david.daney@cavium.com>
L: linux-edac@vger.kernel.org L: linux-edac@vger.kernel.org
L: linux-mips@linux-mips.org L: linux-mips@linux-mips.org
W: bluesmoke.sourceforge.net
S: Supported S: Supported
F: drivers/edac/octeon_edac* F: drivers/edac/octeon_edac*
...@@ -3970,63 +3966,54 @@ EDAC-E752X ...@@ -3970,63 +3966,54 @@ EDAC-E752X
M: Mark Gross <mark.gross@intel.com> M: Mark Gross <mark.gross@intel.com>
M: Doug Thompson <dougthompson@xmission.com> M: Doug Thompson <dougthompson@xmission.com>
L: linux-edac@vger.kernel.org L: linux-edac@vger.kernel.org
W: bluesmoke.sourceforge.net
S: Maintained S: Maintained
F: drivers/edac/e752x_edac.c F: drivers/edac/e752x_edac.c
EDAC-E7XXX EDAC-E7XXX
M: Doug Thompson <dougthompson@xmission.com> M: Doug Thompson <dougthompson@xmission.com>
L: linux-edac@vger.kernel.org L: linux-edac@vger.kernel.org
W: bluesmoke.sourceforge.net
S: Maintained S: Maintained
F: drivers/edac/e7xxx_edac.c F: drivers/edac/e7xxx_edac.c
EDAC-GHES EDAC-GHES
M: Mauro Carvalho Chehab <mchehab@osg.samsung.com> M: Mauro Carvalho Chehab <mchehab@osg.samsung.com>
L: linux-edac@vger.kernel.org L: linux-edac@vger.kernel.org
W: bluesmoke.sourceforge.net
S: Maintained S: Maintained
F: drivers/edac/ghes_edac.c F: drivers/edac/ghes_edac.c
EDAC-I82443BXGX EDAC-I82443BXGX
M: Tim Small <tim@buttersideup.com> M: Tim Small <tim@buttersideup.com>
L: linux-edac@vger.kernel.org L: linux-edac@vger.kernel.org
W: bluesmoke.sourceforge.net
S: Maintained S: Maintained
F: drivers/edac/i82443bxgx_edac.c F: drivers/edac/i82443bxgx_edac.c
EDAC-I3000 EDAC-I3000
M: Jason Uhlenkott <juhlenko@akamai.com> M: Jason Uhlenkott <juhlenko@akamai.com>
L: linux-edac@vger.kernel.org L: linux-edac@vger.kernel.org
W: bluesmoke.sourceforge.net
S: Maintained S: Maintained
F: drivers/edac/i3000_edac.c F: drivers/edac/i3000_edac.c
EDAC-I5000 EDAC-I5000
M: Doug Thompson <dougthompson@xmission.com> M: Doug Thompson <dougthompson@xmission.com>
L: linux-edac@vger.kernel.org L: linux-edac@vger.kernel.org
W: bluesmoke.sourceforge.net
S: Maintained S: Maintained
F: drivers/edac/i5000_edac.c F: drivers/edac/i5000_edac.c
EDAC-I5400 EDAC-I5400
M: Mauro Carvalho Chehab <mchehab@osg.samsung.com> M: Mauro Carvalho Chehab <mchehab@osg.samsung.com>
L: linux-edac@vger.kernel.org L: linux-edac@vger.kernel.org
W: bluesmoke.sourceforge.net
S: Maintained S: Maintained
F: drivers/edac/i5400_edac.c F: drivers/edac/i5400_edac.c
EDAC-I7300 EDAC-I7300
M: Mauro Carvalho Chehab <mchehab@osg.samsung.com> M: Mauro Carvalho Chehab <mchehab@osg.samsung.com>
L: linux-edac@vger.kernel.org L: linux-edac@vger.kernel.org
W: bluesmoke.sourceforge.net
S: Maintained S: Maintained
F: drivers/edac/i7300_edac.c F: drivers/edac/i7300_edac.c
EDAC-I7CORE EDAC-I7CORE
M: Mauro Carvalho Chehab <mchehab@osg.samsung.com> M: Mauro Carvalho Chehab <mchehab@osg.samsung.com>
L: linux-edac@vger.kernel.org L: linux-edac@vger.kernel.org
W: bluesmoke.sourceforge.net
S: Maintained S: Maintained
F: drivers/edac/i7core_edac.c F: drivers/edac/i7core_edac.c
...@@ -4034,42 +4021,36 @@ EDAC-I82975X ...@@ -4034,42 +4021,36 @@ EDAC-I82975X
M: Ranganathan Desikan <ravi@jetztechnologies.com> M: Ranganathan Desikan <ravi@jetztechnologies.com>
M: "Arvind R." <arvino55@gmail.com> M: "Arvind R." <arvino55@gmail.com>
L: linux-edac@vger.kernel.org L: linux-edac@vger.kernel.org
W: bluesmoke.sourceforge.net
S: Maintained S: Maintained
F: drivers/edac/i82975x_edac.c F: drivers/edac/i82975x_edac.c
EDAC-IE31200 EDAC-IE31200
M: Jason Baron <jbaron@akamai.com> M: Jason Baron <jbaron@akamai.com>
L: linux-edac@vger.kernel.org L: linux-edac@vger.kernel.org
W: bluesmoke.sourceforge.net
S: Maintained S: Maintained
F: drivers/edac/ie31200_edac.c F: drivers/edac/ie31200_edac.c
EDAC-MPC85XX EDAC-MPC85XX
M: Johannes Thumshirn <morbidrsa@gmail.com> M: Johannes Thumshirn <morbidrsa@gmail.com>
L: linux-edac@vger.kernel.org L: linux-edac@vger.kernel.org
W: bluesmoke.sourceforge.net
S: Maintained S: Maintained
F: drivers/edac/mpc85xx_edac.[ch] F: drivers/edac/mpc85xx_edac.[ch]
EDAC-PASEMI EDAC-PASEMI
M: Egor Martovetsky <egor@pasemi.com> M: Egor Martovetsky <egor@pasemi.com>
L: linux-edac@vger.kernel.org L: linux-edac@vger.kernel.org
W: bluesmoke.sourceforge.net
S: Maintained S: Maintained
F: drivers/edac/pasemi_edac.c F: drivers/edac/pasemi_edac.c
EDAC-R82600 EDAC-R82600
M: Tim Small <tim@buttersideup.com> M: Tim Small <tim@buttersideup.com>
L: linux-edac@vger.kernel.org L: linux-edac@vger.kernel.org
W: bluesmoke.sourceforge.net
S: Maintained S: Maintained
F: drivers/edac/r82600_edac.c F: drivers/edac/r82600_edac.c
EDAC-SBRIDGE EDAC-SBRIDGE
M: Mauro Carvalho Chehab <mchehab@osg.samsung.com> M: Mauro Carvalho Chehab <mchehab@osg.samsung.com>
L: linux-edac@vger.kernel.org L: linux-edac@vger.kernel.org
W: bluesmoke.sourceforge.net
S: Maintained S: Maintained
F: drivers/edac/sb_edac.c F: drivers/edac/sb_edac.c
......
...@@ -21,10 +21,12 @@ ...@@ -21,10 +21,12 @@
#include <linux/pci.h> #include <linux/pci.h>
#include <linux/delay.h> #include <linux/delay.h>
#include <linux/string.h> #include <linux/string.h>
#include <linux/fsl/edac.h>
#include <linux/init.h> #include <linux/init.h>
#include <linux/interrupt.h> #include <linux/interrupt.h>
#include <linux/memblock.h> #include <linux/memblock.h>
#include <linux/log2.h> #include <linux/log2.h>
#include <linux/platform_device.h>
#include <linux/slab.h> #include <linux/slab.h>
#include <linux/suspend.h> #include <linux/suspend.h>
#include <linux/syscore_ops.h> #include <linux/syscore_ops.h>
...@@ -1255,6 +1257,25 @@ void fsl_pcibios_fixup_phb(struct pci_controller *phb) ...@@ -1255,6 +1257,25 @@ void fsl_pcibios_fixup_phb(struct pci_controller *phb)
#endif #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) static int fsl_pci_probe(struct platform_device *pdev)
{ {
struct device_node *node; struct device_node *node;
...@@ -1262,8 +1283,13 @@ static int fsl_pci_probe(struct platform_device *pdev) ...@@ -1262,8 +1283,13 @@ static int fsl_pci_probe(struct platform_device *pdev)
node = pdev->dev.of_node; node = pdev->dev.of_node;
ret = fsl_add_bridge(pdev, fsl_pci_primary == 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; return 0;
} }
......
...@@ -130,15 +130,6 @@ void fsl_pci_assign_primary(void); ...@@ -130,15 +130,6 @@ void fsl_pci_assign_primary(void);
static inline void fsl_pci_assign_primary(void) {} static inline void fsl_pci_assign_primary(void) {}
#endif #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 #ifdef CONFIG_FSL_PCI
extern int fsl_pci_mcheck_exception(struct pt_regs *); extern int fsl_pci_mcheck_exception(struct pt_regs *);
#else #else
......
...@@ -10,7 +10,7 @@ obj-$(CONFIG_EDAC) := edac_stub.o ...@@ -10,7 +10,7 @@ obj-$(CONFIG_EDAC) := edac_stub.o
obj-$(CONFIG_EDAC_MM_EDAC) += edac_core.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_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 edac_core-$(CONFIG_EDAC_DEBUG) += debugfs.o
......
...@@ -390,11 +390,9 @@ static void edac_device_workq_function(struct work_struct *work_req) ...@@ -390,11 +390,9 @@ static void edac_device_workq_function(struct work_struct *work_req)
* between integral seconds * between integral seconds
*/ */
if (edac_dev->poll_msec == 1000) if (edac_dev->poll_msec == 1000)
queue_delayed_work(edac_workqueue, &edac_dev->work, edac_queue_work(&edac_dev->work, round_jiffies_relative(edac_dev->delay));
round_jiffies_relative(edac_dev->delay));
else else
queue_delayed_work(edac_workqueue, &edac_dev->work, edac_queue_work(&edac_dev->work, edac_dev->delay);
edac_dev->delay);
} }
/* /*
...@@ -402,8 +400,8 @@ static void edac_device_workq_function(struct work_struct *work_req) ...@@ -402,8 +400,8 @@ static void edac_device_workq_function(struct work_struct *work_req)
* initialize a workq item for this edac_device instance * initialize a workq item for this edac_device instance
* passing in the new delay period in msec * passing in the new delay period in msec
*/ */
void edac_device_workq_setup(struct edac_device_ctl_info *edac_dev, static void edac_device_workq_setup(struct edac_device_ctl_info *edac_dev,
unsigned msec) unsigned msec)
{ {
edac_dbg(0, "\n"); edac_dbg(0, "\n");
...@@ -422,29 +420,23 @@ void edac_device_workq_setup(struct edac_device_ctl_info *edac_dev, ...@@ -422,29 +420,23 @@ void edac_device_workq_setup(struct edac_device_ctl_info *edac_dev,
* to fire together on the 1 second exactly * to fire together on the 1 second exactly
*/ */
if (edac_dev->poll_msec == 1000) if (edac_dev->poll_msec == 1000)
queue_delayed_work(edac_workqueue, &edac_dev->work, edac_queue_work(&edac_dev->work, round_jiffies_relative(edac_dev->delay));
round_jiffies_relative(edac_dev->delay));
else else
queue_delayed_work(edac_workqueue, &edac_dev->work, edac_queue_work(&edac_dev->work, edac_dev->delay);
edac_dev->delay);
} }
/* /*
* edac_device_workq_teardown * edac_device_workq_teardown
* stop the workq processing on this edac_dev * 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) if (!edac_dev->edac_check)
return; return;
status = cancel_delayed_work(&edac_dev->work); edac_dev->op_state = OP_OFFLINE;
if (status == 0) {
/* workq instance might be running, wait for it */ edac_stop_work(&edac_dev->work);
flush_workqueue(edac_workqueue);
}
} }
/* /*
...@@ -457,16 +449,15 @@ void edac_device_workq_teardown(struct edac_device_ctl_info *edac_dev) ...@@ -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, void edac_device_reset_delay_period(struct edac_device_ctl_info *edac_dev,
unsigned long value) unsigned long value)
{ {
/* cancel the current workq request, without the mutex lock */ unsigned long jiffs = msecs_to_jiffies(value);
edac_device_workq_teardown(edac_dev);
/* acquire the mutex before doing the workq setup */ if (value == 1000)
mutex_lock(&device_ctls_mutex); jiffs = round_jiffies_relative(value);
/* restart the workq request, with new delay value */ edac_dev->poll_msec = value;
edac_device_workq_setup(edac_dev, 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) ...@@ -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 */ /* get the /sys/devices/system/edac reference */
edac_subsys = edac_get_sysfs_subsys(); 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 */ /* Point to the 'edac_subsys' this instance 'reports' to */
edac_dev->edac_subsys = edac_subsys; edac_dev->edac_subsys = edac_subsys;
...@@ -256,7 +251,7 @@ int edac_device_register_sysfs_main_kobj(struct edac_device_ctl_info *edac_dev) ...@@ -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)) { if (!try_module_get(edac_dev->owner)) {
err = -ENODEV; err = -ENODEV;
goto err_mod_get; goto err_out;
} }
/* register */ /* register */
...@@ -282,9 +277,6 @@ int edac_device_register_sysfs_main_kobj(struct edac_device_ctl_info *edac_dev) ...@@ -282,9 +277,6 @@ int edac_device_register_sysfs_main_kobj(struct edac_device_ctl_info *edac_dev)
err_kobj_reg: err_kobj_reg:
module_put(edac_dev->owner); module_put(edac_dev->owner);
err_mod_get:
edac_put_sysfs_subsys();
err_out: err_out:
return err; return err;
} }
...@@ -306,7 +298,6 @@ void edac_device_unregister_sysfs_main_kobj(struct edac_device_ctl_info *dev) ...@@ -306,7 +298,6 @@ void edac_device_unregister_sysfs_main_kobj(struct edac_device_ctl_info *dev)
* b) 'kfree' the memory * b) 'kfree' the memory
*/ */
kobject_put(&dev->kobj); kobject_put(&dev->kobj);
edac_put_sysfs_subsys();
} }
/* edac_dev -> instance information */ /* edac_dev -> instance information */
......
...@@ -548,8 +548,7 @@ static void edac_mc_workq_function(struct work_struct *work_req) ...@@ -548,8 +548,7 @@ static void edac_mc_workq_function(struct work_struct *work_req)
mutex_unlock(&mem_ctls_mutex); mutex_unlock(&mem_ctls_mutex);
/* Reschedule */ /* Reschedule */
queue_delayed_work(edac_workqueue, &mci->work, edac_queue_work(&mci->work, msecs_to_jiffies(edac_mc_get_poll_msec()));
msecs_to_jiffies(edac_mc_get_poll_msec()));
} }
/* /*
...@@ -561,8 +560,7 @@ static void edac_mc_workq_function(struct work_struct *work_req) ...@@ -561,8 +560,7 @@ static void edac_mc_workq_function(struct work_struct *work_req)
* *
* called with the mem_ctls_mutex held * called with the mem_ctls_mutex held
*/ */
static void edac_mc_workq_setup(struct mem_ctl_info *mci, unsigned msec, static void edac_mc_workq_setup(struct mem_ctl_info *mci, unsigned msec)
bool init)
{ {
edac_dbg(0, "\n"); edac_dbg(0, "\n");
...@@ -570,10 +568,9 @@ static void edac_mc_workq_setup(struct mem_ctl_info *mci, unsigned msec, ...@@ -570,10 +568,9 @@ static void edac_mc_workq_setup(struct mem_ctl_info *mci, unsigned msec,
if (mci->op_state != OP_RUNNING_POLL) if (mci->op_state != OP_RUNNING_POLL)
return; 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, ...@@ -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) static void edac_mc_workq_teardown(struct mem_ctl_info *mci)
{ {
int status; mci->op_state = OP_OFFLINE;
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");
/* workq instance might be running, wait for it */ edac_stop_work(&mci->work);
flush_workqueue(edac_workqueue);
}
} }
/* /*
...@@ -616,9 +604,8 @@ void edac_mc_reset_delay_period(unsigned long value) ...@@ -616,9 +604,8 @@ void edac_mc_reset_delay_period(unsigned long value)
list_for_each(item, &mc_devices) { list_for_each(item, &mc_devices) {
mci = list_entry(item, struct mem_ctl_info, link); 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); mutex_unlock(&mem_ctls_mutex);
} }
...@@ -789,7 +776,7 @@ int edac_mc_add_mc_with_groups(struct mem_ctl_info *mci, ...@@ -789,7 +776,7 @@ int edac_mc_add_mc_with_groups(struct mem_ctl_info *mci,
/* This instance is NOW RUNNING */ /* This instance is NOW RUNNING */
mci->op_state = OP_RUNNING_POLL; 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 { } else {
mci->op_state = OP_RUNNING_INTERRUPT; mci->op_state = OP_RUNNING_INTERRUPT;
} }
......
...@@ -880,21 +880,26 @@ static struct device_type mci_attr_type = { ...@@ -880,21 +880,26 @@ static struct device_type mci_attr_type = {
int edac_create_sysfs_mci_device(struct mem_ctl_info *mci, int edac_create_sysfs_mci_device(struct mem_ctl_info *mci,
const struct attribute_group **groups) const struct attribute_group **groups)
{ {
char *name;
int i, err; int i, err;
/* /*
* The memory controller needs its own bus, in order to avoid * The memory controller needs its own bus, in order to avoid
* namespace conflicts at /sys/bus/edac. * namespace conflicts at /sys/bus/edac.
*/ */
mci->bus->name = kasprintf(GFP_KERNEL, "mc%d", mci->mc_idx); name = kasprintf(GFP_KERNEL, "mc%d", mci->mc_idx);
if (!mci->bus->name) if (!name)
return -ENOMEM; return -ENOMEM;
mci->bus->name = name;
edac_dbg(0, "creating bus %s\n", mci->bus->name); edac_dbg(0, "creating bus %s\n", mci->bus->name);
err = bus_register(mci->bus); err = bus_register(mci->bus);
if (err < 0) if (err < 0) {
goto fail_free_name; kfree(name);
return err;
}
/* get the /sys/devices/system/edac subsys reference */ /* get the /sys/devices/system/edac subsys reference */
mci->dev.type = &mci_attr_type; mci->dev.type = &mci_attr_type;
...@@ -961,8 +966,8 @@ int edac_create_sysfs_mci_device(struct mem_ctl_info *mci, ...@@ -961,8 +966,8 @@ int edac_create_sysfs_mci_device(struct mem_ctl_info *mci,
device_unregister(&mci->dev); device_unregister(&mci->dev);
fail_unregister_bus: fail_unregister_bus:
bus_unregister(mci->bus); bus_unregister(mci->bus);
fail_free_name: kfree(name);
kfree(mci->bus->name);
return err; return err;
} }
...@@ -993,10 +998,12 @@ void edac_remove_sysfs_mci_device(struct mem_ctl_info *mci) ...@@ -993,10 +998,12 @@ void edac_remove_sysfs_mci_device(struct mem_ctl_info *mci)
void edac_unregister_sysfs(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)); edac_dbg(1, "Unregistering device %s\n", dev_name(&mci->dev));
device_unregister(&mci->dev); device_unregister(&mci->dev);
bus_unregister(mci->bus); bus_unregister(mci->bus);
kfree(mci->bus->name); kfree(name);
} }
static void mc_attr_release(struct device *dev) static void mc_attr_release(struct device *dev)
...@@ -1018,24 +1025,15 @@ static struct device_type mc_attr_type = { ...@@ -1018,24 +1025,15 @@ static struct device_type mc_attr_type = {
*/ */
int __init edac_mc_sysfs_init(void) int __init edac_mc_sysfs_init(void)
{ {
struct bus_type *edac_subsys;
int err; 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); mci_pdev = kzalloc(sizeof(*mci_pdev), GFP_KERNEL);
if (!mci_pdev) { if (!mci_pdev) {
err = -ENOMEM; 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; mci_pdev->type = &mc_attr_type;
device_initialize(mci_pdev); device_initialize(mci_pdev);
dev_set_name(mci_pdev, "mc"); dev_set_name(mci_pdev, "mc");
...@@ -1050,8 +1048,6 @@ int __init edac_mc_sysfs_init(void) ...@@ -1050,8 +1048,6 @@ int __init edac_mc_sysfs_init(void)
out_dev_free: out_dev_free:
kfree(mci_pdev); kfree(mci_pdev);
out_put_sysfs:
edac_put_sysfs_subsys();
out: out:
return err; return err;
} }
...@@ -1059,5 +1055,4 @@ int __init edac_mc_sysfs_init(void) ...@@ -1059,5 +1055,4 @@ int __init edac_mc_sysfs_init(void)
void edac_mc_sysfs_exit(void) void edac_mc_sysfs_exit(void)
{ {
device_unregister(mci_pdev); 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, ...@@ -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"); MODULE_PARM_DESC(edac_debug_level, "EDAC debug level: [0-4], default: 2");
#endif #endif
/* scope is to module level only */
struct workqueue_struct *edac_workqueue;
/* /*
* edac_op_state_to_string() * edac_op_state_to_string()
*/ */
...@@ -66,31 +63,37 @@ char *edac_op_state_to_string(int opstate) ...@@ -66,31 +63,37 @@ char *edac_op_state_to_string(int opstate)
} }
/* /*
* edac_workqueue_setup * sysfs object: /sys/devices/system/edac
* initialize the edac work queue for polling operations * 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"); int err;
if (edac_workqueue == NULL)
return -ENODEV; /* create the /sys/devices/system/edac directory */
else err = subsys_system_register(&edac_subsys, NULL);
return 0; if (err)
printk(KERN_ERR "Error registering toplevel EDAC sysfs dir\n");
return err;
} }
/* static void edac_subsys_exit(void)
* edac_workqueue_teardown
* teardown the edac workqueue
*/
static void edac_workqueue_teardown(void)
{ {
if (edac_workqueue) { bus_unregister(&edac_subsys);
flush_workqueue(edac_workqueue);
destroy_workqueue(edac_workqueue);
edac_workqueue = NULL;
}
} }
/* 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 * edac_init
* module initialization entry point * module initialization entry point
...@@ -101,6 +104,10 @@ static int __init edac_init(void) ...@@ -101,6 +104,10 @@ static int __init edac_init(void)
edac_printk(KERN_INFO, EDAC_MC, EDAC_VERSION "\n"); 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 * Harvest and clear any boot/initialization PCI parity errors
* *
...@@ -129,6 +136,8 @@ static int __init edac_init(void) ...@@ -129,6 +136,8 @@ static int __init edac_init(void)
edac_mc_sysfs_exit(); edac_mc_sysfs_exit();
err_sysfs: err_sysfs:
edac_subsys_exit();
return err; return err;
} }
...@@ -144,6 +153,7 @@ static void __exit edac_exit(void) ...@@ -144,6 +153,7 @@ static void __exit edac_exit(void)
edac_workqueue_teardown(); edac_workqueue_teardown();
edac_mc_sysfs_exit(); edac_mc_sysfs_exit();
edac_debugfs_exit(); edac_debugfs_exit();
edac_subsys_exit();
} }
/* /*
......
...@@ -47,10 +47,12 @@ extern int edac_device_create_sysfs(struct edac_device_ctl_info *edac_dev); ...@@ -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); extern void edac_device_remove_sysfs(struct edac_device_ctl_info *edac_dev);
/* edac core workqueue: single CPU mode */ /* edac core workqueue: single CPU mode */
extern struct workqueue_struct *edac_workqueue; int edac_workqueue_setup(void);
extern void edac_device_workq_setup(struct edac_device_ctl_info *edac_dev, void edac_workqueue_teardown(void);
unsigned msec); bool edac_queue_work(struct delayed_work *work, unsigned long delay);
extern void edac_device_workq_teardown(struct edac_device_ctl_info *edac_dev); 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 extern void edac_device_reset_delay_period(struct edac_device_ctl_info
*edac_dev, unsigned long value); *edac_dev, unsigned long value);
extern void edac_mc_reset_delay_period(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) ...@@ -178,41 +178,6 @@ static void del_edac_pci_from_global_list(struct edac_pci_ctl_info *pci)
INIT_LIST_HEAD(&pci->link); 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() * edac_pci_workq_function()
* *
...@@ -244,7 +209,7 @@ static void edac_pci_workq_function(struct work_struct *work_req) ...@@ -244,7 +209,7 @@ static void edac_pci_workq_function(struct work_struct *work_req)
delay = msecs_to_jiffies(msec); delay = msecs_to_jiffies(msec);
/* Reschedule only if we are in POLL mode */ /* 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); mutex_unlock(&edac_pci_ctls_mutex);
...@@ -264,8 +229,8 @@ static void edac_pci_workq_setup(struct edac_pci_ctl_info *pci, ...@@ -264,8 +229,8 @@ static void edac_pci_workq_setup(struct edac_pci_ctl_info *pci,
edac_dbg(0, "\n"); edac_dbg(0, "\n");
INIT_DELAYED_WORK(&pci->work, edac_pci_workq_function); 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, ...@@ -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 * stop the workq processing on this edac_pci instance
*/ */
static void edac_pci_workq_teardown(struct edac_pci_ctl_info *pci) 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_dbg(0, "\n");
edac_pci_workq_teardown(pci); pci->op_state = OP_OFFLINE;
/* need to lock for the setup */
mutex_lock(&edac_pci_ctls_mutex);
edac_pci_workq_setup(pci, value);
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 * edac_pci_alloc_index: Allocate a unique PCI index number
......
...@@ -331,10 +331,7 @@ static struct kobj_type ktype_edac_pci_main_kobj = { ...@@ -331,10 +331,7 @@ static struct kobj_type ktype_edac_pci_main_kobj = {
}; };
/** /**
* edac_pci_main_kobj_setup() * edac_pci_main_kobj_setup: Setup the sysfs for EDAC PCI attributes.
*
* setup the sysfs for EDAC PCI attributes
* assumes edac_subsys has already been initialized
*/ */
static int edac_pci_main_kobj_setup(void) static int edac_pci_main_kobj_setup(void)
{ {
...@@ -351,11 +348,6 @@ static int edac_pci_main_kobj_setup(void) ...@@ -351,11 +348,6 @@ static int edac_pci_main_kobj_setup(void)
* controls and attributes * controls and attributes
*/ */
edac_subsys = edac_get_sysfs_subsys(); 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 /* Bump the reference count on this module to ensure the
* modules isn't unloaded until we deconstruct the top * modules isn't unloaded until we deconstruct the top
...@@ -364,7 +356,7 @@ static int edac_pci_main_kobj_setup(void) ...@@ -364,7 +356,7 @@ static int edac_pci_main_kobj_setup(void)
if (!try_module_get(THIS_MODULE)) { if (!try_module_get(THIS_MODULE)) {
edac_dbg(1, "try_module_get() failed\n"); edac_dbg(1, "try_module_get() failed\n");
err = -ENODEV; err = -ENODEV;
goto mod_get_fail; goto decrement_count_fail;
} }
edac_pci_top_main_kobj = kzalloc(sizeof(struct kobject), GFP_KERNEL); edac_pci_top_main_kobj = kzalloc(sizeof(struct kobject), GFP_KERNEL);
...@@ -399,9 +391,6 @@ static int edac_pci_main_kobj_setup(void) ...@@ -399,9 +391,6 @@ static int edac_pci_main_kobj_setup(void)
kzalloc_fail: kzalloc_fail:
module_put(THIS_MODULE); module_put(THIS_MODULE);
mod_get_fail:
edac_put_sysfs_subsys();
decrement_count_fail: decrement_count_fail:
/* if are on this error exit, nothing to tear down */ /* if are on this error exit, nothing to tear down */
atomic_dec(&edac_pci_sysfs_refcount); atomic_dec(&edac_pci_sysfs_refcount);
...@@ -426,7 +415,6 @@ static void edac_pci_main_kobj_teardown(void) ...@@ -426,7 +415,6 @@ static void edac_pci_main_kobj_teardown(void)
if (atomic_dec_return(&edac_pci_sysfs_refcount) == 0) { if (atomic_dec_return(&edac_pci_sysfs_refcount) == 0) {
edac_dbg(0, "called kobject_put on main kobj\n"); edac_dbg(0, "called kobject_put on main kobj\n");
kobject_put(edac_pci_top_main_kobj); kobject_put(edac_pci_top_main_kobj);
edac_put_sysfs_subsys();
} }
} }
......
...@@ -26,8 +26,6 @@ EXPORT_SYMBOL_GPL(edac_handlers); ...@@ -26,8 +26,6 @@ EXPORT_SYMBOL_GPL(edac_handlers);
int edac_err_assert = 0; int edac_err_assert = 0;
EXPORT_SYMBOL_GPL(edac_err_assert); EXPORT_SYMBOL_GPL(edac_err_assert);
static atomic_t edac_subsys_valid = ATOMIC_INIT(0);
int edac_report_status = EDAC_REPORTING_ENABLED; int edac_report_status = EDAC_REPORTING_ENABLED;
EXPORT_SYMBOL_GPL(edac_report_status); EXPORT_SYMBOL_GPL(edac_report_status);
...@@ -68,42 +66,3 @@ void edac_atomic_assert_error(void) ...@@ -68,42 +66,3 @@ void edac_atomic_assert_error(void)
edac_err_assert++; edac_err_assert++;
} }
EXPORT_SYMBOL_GPL(edac_atomic_assert_error); 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) ...@@ -575,9 +575,7 @@ static void i5100_check_error(struct mem_ctl_info *mci)
static void i5100_refresh_scrubbing(struct work_struct *work) static void i5100_refresh_scrubbing(struct work_struct *work)
{ {
struct delayed_work *i5100_scrubbing = container_of(work, struct delayed_work *i5100_scrubbing = to_delayed_work(work);
struct delayed_work,
work);
struct i5100_priv *priv = container_of(i5100_scrubbing, struct i5100_priv *priv = container_of(i5100_scrubbing,
struct i5100_priv, struct i5100_priv,
i5100_scrubbing); i5100_scrubbing);
......
...@@ -20,6 +20,7 @@ ...@@ -20,6 +20,7 @@
#include <linux/edac.h> #include <linux/edac.h>
#include <linux/smp.h> #include <linux/smp.h>
#include <linux/gfp.h> #include <linux/gfp.h>
#include <linux/fsl/edac.h>
#include <linux/of_platform.h> #include <linux/of_platform.h>
#include <linux/of_device.h> #include <linux/of_device.h>
...@@ -238,10 +239,12 @@ static irqreturn_t mpc85xx_pci_isr(int irq, void *dev_id) ...@@ -238,10 +239,12 @@ static irqreturn_t mpc85xx_pci_isr(int irq, void *dev_id)
return IRQ_HANDLED; 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 edac_pci_ctl_info *pci;
struct mpc85xx_pci_pdata *pdata; struct mpc85xx_pci_pdata *pdata;
struct mpc85xx_edac_pci_plat_data *plat_data;
struct device_node *of_node;
struct resource r; struct resource r;
int res = 0; int res = 0;
...@@ -266,7 +269,15 @@ int mpc85xx_pci_err_probe(struct platform_device *op) ...@@ -266,7 +269,15 @@ int mpc85xx_pci_err_probe(struct platform_device *op)
pdata->name = "mpc85xx_pci_err"; pdata->name = "mpc85xx_pci_err";
pdata->irq = NO_IRQ; 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; pdata->is_pcie = true;
dev_set_drvdata(&op->dev, pci); dev_set_drvdata(&op->dev, pci);
...@@ -284,7 +295,7 @@ int mpc85xx_pci_err_probe(struct platform_device *op) ...@@ -284,7 +295,7 @@ int mpc85xx_pci_err_probe(struct platform_device *op)
pdata->edac_idx = edac_pci_idx++; 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) { if (res) {
printk(KERN_ERR "%s: Unable to get resource for " printk(KERN_ERR "%s: Unable to get resource for "
"PCI err regs\n", __func__); "PCI err regs\n", __func__);
...@@ -339,7 +350,7 @@ int mpc85xx_pci_err_probe(struct platform_device *op) ...@@ -339,7 +350,7 @@ int mpc85xx_pci_err_probe(struct platform_device *op)
} }
if (edac_op_state == EDAC_OPSTATE_INT) { 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, res = devm_request_irq(&op->dev, pdata->irq,
mpc85xx_pci_isr, mpc85xx_pci_isr,
IRQF_SHARED, IRQF_SHARED,
...@@ -386,8 +397,22 @@ int mpc85xx_pci_err_probe(struct platform_device *op) ...@@ -386,8 +397,22 @@ int mpc85xx_pci_err_probe(struct platform_device *op)
devres_release_group(&op->dev, mpc85xx_pci_err_probe); devres_release_group(&op->dev, mpc85xx_pci_err_probe);
return res; 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 */ #endif /* CONFIG_PCI */
/**************************** L2 Err device ***************************/ /**************************** L2 Err device ***************************/
...@@ -1208,6 +1233,14 @@ static void __init mpc85xx_mc_clear_rfxe(void *data) ...@@ -1208,6 +1233,14 @@ static void __init mpc85xx_mc_clear_rfxe(void *data)
} }
#endif #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) static int __init mpc85xx_mc_init(void)
{ {
int res = 0; int res = 0;
...@@ -1226,13 +1259,9 @@ static int __init mpc85xx_mc_init(void) ...@@ -1226,13 +1259,9 @@ static int __init mpc85xx_mc_init(void)
break; break;
} }
res = platform_driver_register(&mpc85xx_mc_err_driver); res = platform_register_drivers(drivers, ARRAY_SIZE(drivers));
if (res)
printk(KERN_WARNING EDAC_MOD_STR "MC fails to register\n");
res = platform_driver_register(&mpc85xx_l2_err_driver);
if (res) 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 #ifdef CONFIG_FSL_SOC_BOOKE
pvr = mfspr(SPRN_PVR); pvr = mfspr(SPRN_PVR);
...@@ -1270,8 +1299,7 @@ static void __exit mpc85xx_mc_exit(void) ...@@ -1270,8 +1299,7 @@ static void __exit mpc85xx_mc_exit(void)
on_each_cpu(mpc85xx_mc_restore_hid1, NULL, 0); on_each_cpu(mpc85xx_mc_restore_hid1, NULL, 0);
} }
#endif #endif
platform_driver_unregister(&mpc85xx_l2_err_driver); platform_unregister_drivers(drivers, ARRAY_SIZE(drivers));
platform_driver_unregister(&mpc85xx_mc_err_driver);
} }
module_exit(mpc85xx_mc_exit); module_exit(mpc85xx_mc_exit);
......
...@@ -847,6 +847,15 @@ static struct platform_driver mv64x60_mc_err_driver = { ...@@ -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) static int __init mv64x60_edac_init(void)
{ {
int ret = 0; int ret = 0;
...@@ -863,39 +872,13 @@ static int __init mv64x60_edac_init(void) ...@@ -863,39 +872,13 @@ static int __init mv64x60_edac_init(void)
break; break;
} }
ret = platform_driver_register(&mv64x60_mc_err_driver); return platform_register_drivers(drivers, ARRAY_SIZE(drivers));
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;
} }
module_init(mv64x60_edac_init); module_init(mv64x60_edac_init);
static void __exit mv64x60_edac_exit(void) static void __exit mv64x60_edac_exit(void)
{ {
#ifdef CONFIG_PCI platform_unregister_drivers(drivers, ARRAY_SIZE(drivers));
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);
} }
module_exit(mv64x60_edac_exit); 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; ...@@ -28,12 +28,10 @@ struct device;
extern int edac_op_state; extern int edac_op_state;
extern int edac_err_assert; extern int edac_err_assert;
extern atomic_t edac_handlers; extern atomic_t edac_handlers;
extern struct bus_type edac_subsys;
extern int edac_handler_set(void); extern int edac_handler_set(void);
extern void edac_atomic_assert_error(void); extern void edac_atomic_assert_error(void);
extern struct bus_type *edac_get_sysfs_subsys(void); extern struct bus_type *edac_get_sysfs_subsys(void);
extern void edac_put_sysfs_subsys(void);
enum { enum {
EDAC_REPORTING_ENABLED, EDAC_REPORTING_ENABLED,
...@@ -237,8 +235,10 @@ enum mem_type { ...@@ -237,8 +235,10 @@ enum mem_type {
#define MEM_FLAG_FB_DDR2 BIT(MEM_FB_DDR2) #define MEM_FLAG_FB_DDR2 BIT(MEM_FB_DDR2)
#define MEM_FLAG_RDDR2 BIT(MEM_RDDR2) #define MEM_FLAG_RDDR2 BIT(MEM_RDDR2)
#define MEM_FLAG_XDR BIT(MEM_XDR) #define MEM_FLAG_XDR BIT(MEM_XDR)
#define MEM_FLAG_DDR3 BIT(MEM_DDR3) #define MEM_FLAG_DDR3 BIT(MEM_DDR3)
#define MEM_FLAG_RDDR3 BIT(MEM_RDDR3) #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 * 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