path: root/drivers
diff options
authorLinus Torvalds <torvalds@linux-foundation.org>2014-02-14 11:05:41 -0800
committerLinus Torvalds <torvalds@linux-foundation.org>2014-02-14 11:05:41 -0800
commit3bd354abe17f2c8aa426ef84b78f14e505f0a920 (patch)
treebdaed9ba35a7b6fdce76ae4086309b644f1afd37 /drivers
parentcbc252566c09ad4ab14a40813d4feac4228571cb (diff)
parentcb6ef42e516cb8948f15e4b70dc03af8020050a2 (diff)
Merge tag 'edac_for_3.14' of git://git.kernel.org/pub/scm/linux/kernel/git/bp/bp
Pull EDAC fixes from Borislav Petkov: "Fix polling timeout setting through sysfs. You're surely wondering why the patches are not based on an rc. Well, Andrew sent you 79040cad3f82 ("drivers/edac/edac_mc_sysfs.c: poll timeout cannot be zero sent you") already (it got in in -rc2) but it is not enough as a fix because for one, setting too low polling intervals (< 1sec) don't make any sense and cause unnecessary polling load on the system. Then, even if we set some interval, we explode with [ 4143.094342] WARNING: CPU: 1 PID: 0 at kernel/workqueue.c:1393 __queue_work+0x1d7/0x340() because the workqueue setup path is used also for the timeout period resetting and we're doing INIT_DELAYED_WORK() on an already active workqueue. Which is total bollocks. So this is taken care of by the second patch. I've CCed stable for those two" * tag 'edac_for_3.14' of git://git.kernel.org/pub/scm/linux/kernel/git/bp/bp: EDAC: Correct workqueue setup path EDAC: Poll timeout cannot be zero, p2
Diffstat (limited to 'drivers')
3 files changed, 15 insertions, 10 deletions
diff --git a/drivers/edac/edac_mc.c b/drivers/edac/edac_mc.c
index e8c9ef03495b..33edd6766344 100644
--- a/drivers/edac/edac_mc.c
+++ b/drivers/edac/edac_mc.c
@@ -559,7 +559,8 @@ 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)
+static void edac_mc_workq_setup(struct mem_ctl_info *mci, unsigned msec,
+ bool init)
edac_dbg(0, "\n");
@@ -567,7 +568,9 @@ static void edac_mc_workq_setup(struct mem_ctl_info *mci, unsigned msec)
if (mci->op_state != OP_RUNNING_POLL)
- INIT_DELAYED_WORK(&mci->work, edac_mc_workq_function);
+ if (init)
+ INIT_DELAYED_WORK(&mci->work, edac_mc_workq_function);
mod_delayed_work(edac_workqueue, &mci->work, msecs_to_jiffies(msec));
@@ -601,7 +604,7 @@ static void edac_mc_workq_teardown(struct mem_ctl_info *mci)
* user space has updated our poll period value, need to
* reset our workq delays
-void edac_mc_reset_delay_period(int value)
+void edac_mc_reset_delay_period(unsigned long value)
struct mem_ctl_info *mci;
struct list_head *item;
@@ -611,7 +614,7 @@ void edac_mc_reset_delay_period(int value)
list_for_each(item, &mc_devices) {
mci = list_entry(item, struct mem_ctl_info, link);
- edac_mc_workq_setup(mci, (unsigned long) value);
+ edac_mc_workq_setup(mci, value, false);
@@ -782,7 +785,7 @@ int edac_mc_add_mc(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());
+ edac_mc_workq_setup(mci, edac_mc_get_poll_msec(), true);
} else {
mci->op_state = OP_RUNNING_INTERRUPT;
diff --git a/drivers/edac/edac_mc_sysfs.c b/drivers/edac/edac_mc_sysfs.c
index 8ec1747b1c39..b335c6ab5efe 100644
--- a/drivers/edac/edac_mc_sysfs.c
+++ b/drivers/edac/edac_mc_sysfs.c
@@ -52,18 +52,20 @@ int edac_mc_get_poll_msec(void)
static int edac_set_poll_msec(const char *val, struct kernel_param *kp)
- long l;
+ unsigned long l;
int ret;
if (!val)
return -EINVAL;
- ret = kstrtol(val, 0, &l);
+ ret = kstrtoul(val, 0, &l);
if (ret)
return ret;
- if (!l || ((int)l != l))
+ if (l < 1000)
return -EINVAL;
- *((int *)kp->arg) = l;
+ *((unsigned long *)kp->arg) = l;
/* notify edac_mc engine to reset the poll period */
diff --git a/drivers/edac/edac_module.h b/drivers/edac/edac_module.h
index 3d139c6e7fe3..f2118bfcf8df 100644
--- a/drivers/edac/edac_module.h
+++ b/drivers/edac/edac_module.h
@@ -52,7 +52,7 @@ extern void edac_device_workq_setup(struct edac_device_ctl_info *edac_dev,
extern void edac_device_workq_teardown(struct edac_device_ctl_info *edac_dev);
extern void edac_device_reset_delay_period(struct edac_device_ctl_info
*edac_dev, unsigned long value);
-extern void edac_mc_reset_delay_period(int value);
+extern void edac_mc_reset_delay_period(unsigned long value);
extern void *edac_align_ptr(void **p, unsigned size, int n_elems);