diff options
-rw-r--r-- | drivers/edac/edac_mc.c | 64 | ||||
-rw-r--r-- | drivers/edac/edac_mc_sysfs.c | 19 | ||||
-rw-r--r-- | drivers/edac/edac_module.h | 2 |
3 files changed, 62 insertions, 23 deletions
diff --git a/drivers/edac/edac_mc.c b/drivers/edac/edac_mc.c index 4471be362599..063a1bffe38b 100644 --- a/drivers/edac/edac_mc.c +++ b/drivers/edac/edac_mc.c | |||
@@ -214,6 +214,13 @@ void edac_mc_free(struct mem_ctl_info *mci) | |||
214 | } | 214 | } |
215 | EXPORT_SYMBOL_GPL(edac_mc_free); | 215 | EXPORT_SYMBOL_GPL(edac_mc_free); |
216 | 216 | ||
217 | |||
218 | /* | ||
219 | * find_mci_by_dev | ||
220 | * | ||
221 | * scan list of controllers looking for the one that manages | ||
222 | * the 'dev' device | ||
223 | */ | ||
217 | static struct mem_ctl_info *find_mci_by_dev(struct device *dev) | 224 | static struct mem_ctl_info *find_mci_by_dev(struct device *dev) |
218 | { | 225 | { |
219 | struct mem_ctl_info *mci; | 226 | struct mem_ctl_info *mci; |
@@ -268,12 +275,6 @@ static void edac_mc_workq_function(struct work_struct *work_req) | |||
268 | if (edac_mc_assert_error_check_and_clear() && (mci->edac_check != NULL)) | 275 | if (edac_mc_assert_error_check_and_clear() && (mci->edac_check != NULL)) |
269 | mci->edac_check(mci); | 276 | mci->edac_check(mci); |
270 | 277 | ||
271 | /* | ||
272 | * FIXME: temp place holder for PCI checks, | ||
273 | * goes away when we break out PCI | ||
274 | */ | ||
275 | edac_pci_do_parity_check(); | ||
276 | |||
277 | mutex_unlock(&mem_ctls_mutex); | 278 | mutex_unlock(&mem_ctls_mutex); |
278 | 279 | ||
279 | /* Reschedule */ | 280 | /* Reschedule */ |
@@ -314,36 +315,55 @@ static void edac_mc_workq_teardown(struct mem_ctl_info *mci) | |||
314 | { | 315 | { |
315 | int status; | 316 | int status; |
316 | 317 | ||
317 | /* if not running POLL, leave now */ | 318 | status = cancel_delayed_work(&mci->work); |
318 | if (mci->op_state == OP_RUNNING_POLL) { | 319 | if (status == 0) { |
319 | status = cancel_delayed_work(&mci->work); | 320 | debugf0("%s() not canceled, flush the queue\n", |
320 | if (status == 0) { | 321 | __func__); |
321 | debugf0("%s() not canceled, flush the queue\n", | ||
322 | __func__); | ||
323 | 322 | ||
324 | /* workq instance might be running, wait for it */ | 323 | /* workq instance might be running, wait for it */ |
325 | flush_workqueue(edac_workqueue); | 324 | flush_workqueue(edac_workqueue); |
326 | } | ||
327 | } | 325 | } |
328 | } | 326 | } |
329 | 327 | ||
330 | /* | 328 | /* |
331 | * edac_reset_delay_period | 329 | * edac_mc_reset_delay_period(unsigned long value) |
330 | * | ||
331 | * user space has updated our poll period value, need to | ||
332 | * reset our workq delays | ||
332 | */ | 333 | */ |
333 | static void edac_reset_delay_period(struct mem_ctl_info *mci, unsigned long value) | 334 | void edac_mc_reset_delay_period(int value) |
334 | { | 335 | { |
335 | /* cancel the current workq request */ | 336 | struct mem_ctl_info *mci; |
336 | edac_mc_workq_teardown(mci); | 337 | struct list_head *item; |
337 | 338 | ||
338 | /* lock the list of devices for the new setup */ | ||
339 | mutex_lock(&mem_ctls_mutex); | 339 | mutex_lock(&mem_ctls_mutex); |
340 | 340 | ||
341 | /* restart the workq request, with new delay value */ | 341 | /* scan the list and turn off all workq timers, doing so under lock |
342 | edac_mc_workq_setup(mci, value); | 342 | */ |
343 | list_for_each(item, &mc_devices) { | ||
344 | mci = list_entry(item, struct mem_ctl_info, link); | ||
345 | |||
346 | if (mci->op_state == OP_RUNNING_POLL) | ||
347 | cancel_delayed_work(&mci->work); | ||
348 | } | ||
349 | |||
350 | mutex_unlock(&mem_ctls_mutex); | ||
351 | |||
352 | |||
353 | /* re-walk the list, and reset the poll delay */ | ||
354 | mutex_lock(&mem_ctls_mutex); | ||
355 | |||
356 | list_for_each(item, &mc_devices) { | ||
357 | mci = list_entry(item, struct mem_ctl_info, link); | ||
358 | |||
359 | edac_mc_workq_setup(mci, (unsigned long) value); | ||
360 | } | ||
343 | 361 | ||
344 | mutex_unlock(&mem_ctls_mutex); | 362 | mutex_unlock(&mem_ctls_mutex); |
345 | } | 363 | } |
346 | 364 | ||
365 | |||
366 | |||
347 | /* Return 0 on success, 1 on failure. | 367 | /* Return 0 on success, 1 on failure. |
348 | * Before calling this function, caller must | 368 | * Before calling this function, caller must |
349 | * assign a unique value to mci->mc_idx. | 369 | * assign a unique value to mci->mc_idx. |
diff --git a/drivers/edac/edac_mc_sysfs.c b/drivers/edac/edac_mc_sysfs.c index cd090b0677a7..4a0576bd06fc 100644 --- a/drivers/edac/edac_mc_sysfs.c +++ b/drivers/edac/edac_mc_sysfs.c | |||
@@ -122,6 +122,23 @@ static ssize_t memctrl_int_store(void *ptr, const char *buffer, size_t count) | |||
122 | return count; | 122 | return count; |
123 | } | 123 | } |
124 | 124 | ||
125 | /* | ||
126 | * mc poll_msec time value | ||
127 | */ | ||
128 | static ssize_t poll_msec_int_store(void *ptr, const char *buffer, size_t count) | ||
129 | { | ||
130 | int *value = (int *)ptr; | ||
131 | |||
132 | if (isdigit(*buffer)) { | ||
133 | *value = simple_strtoul(buffer, NULL, 0); | ||
134 | |||
135 | /* notify edac_mc engine to reset the poll period */ | ||
136 | edac_mc_reset_delay_period(*value); | ||
137 | } | ||
138 | |||
139 | return count; | ||
140 | } | ||
141 | |||
125 | 142 | ||
126 | /* EDAC sysfs CSROW data structures and methods | 143 | /* EDAC sysfs CSROW data structures and methods |
127 | */ | 144 | */ |
@@ -704,7 +721,7 @@ MEMCTRL_ATTR(edac_mc_log_ce, | |||
704 | S_IRUGO | S_IWUSR, memctrl_int_show, memctrl_int_store); | 721 | S_IRUGO | S_IWUSR, memctrl_int_show, memctrl_int_store); |
705 | 722 | ||
706 | MEMCTRL_ATTR(edac_mc_poll_msec, | 723 | MEMCTRL_ATTR(edac_mc_poll_msec, |
707 | S_IRUGO | S_IWUSR, memctrl_int_show, memctrl_int_store); | 724 | S_IRUGO | S_IWUSR, memctrl_int_show, poll_msec_int_store); |
708 | 725 | ||
709 | /* Base Attributes of the memory ECC object */ | 726 | /* Base Attributes of the memory ECC object */ |
710 | static struct memctrl_dev_attribute *memctrl_attr[] = { | 727 | static struct memctrl_dev_attribute *memctrl_attr[] = { |
diff --git a/drivers/edac/edac_module.h b/drivers/edac/edac_module.h index a2134dfc3cc6..3664ae9ccd63 100644 --- a/drivers/edac/edac_module.h +++ b/drivers/edac/edac_module.h | |||
@@ -52,6 +52,8 @@ extern void edac_device_workq_setup(struct edac_device_ctl_info *edac_dev, | |||
52 | extern void edac_device_workq_teardown(struct edac_device_ctl_info *edac_dev); | 52 | extern void edac_device_workq_teardown(struct edac_device_ctl_info *edac_dev); |
53 | extern void edac_device_reset_delay_period(struct edac_device_ctl_info | 53 | extern void edac_device_reset_delay_period(struct edac_device_ctl_info |
54 | *edac_dev, unsigned long value); | 54 | *edac_dev, unsigned long value); |
55 | extern void edac_mc_reset_delay_period(int value); | ||
56 | |||
55 | extern void *edac_align_ptr(void *ptr, unsigned size); | 57 | extern void *edac_align_ptr(void *ptr, unsigned size); |
56 | 58 | ||
57 | /* | 59 | /* |