diff --git a/drivers/edac/Makefile b/drivers/edac/Makefile index dbf53e08bdd1..be163e20fe56 100644 --- a/drivers/edac/Makefile +++ b/drivers/edac/Makefile @@ -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 diff --git a/drivers/edac/edac_device.c b/drivers/edac/edac_device.c index 455a64b67521..a97900333e2d 100644 --- a/drivers/edac/edac_device.c +++ b/drivers/edac/edac_device.c @@ -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); } /* @@ -422,11 +420,9 @@ static 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); } /* @@ -440,8 +436,7 @@ static void edac_device_workq_teardown(struct edac_device_ctl_info *edac_dev) edac_dev->op_state = OP_OFFLINE; - cancel_delayed_work_sync(&edac_dev->work); - flush_workqueue(edac_workqueue); + edac_stop_work(&edac_dev->work); } /* @@ -454,16 +449,15 @@ static 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); } /* diff --git a/drivers/edac/edac_mc.c b/drivers/edac/edac_mc.c index 1b2c2187b347..8adfc167c2e3 100644 --- a/drivers/edac/edac_mc.c +++ b/drivers/edac/edac_mc.c @@ -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)); } /* @@ -588,8 +585,7 @@ static void edac_mc_workq_teardown(struct mem_ctl_info *mci) { mci->op_state = OP_OFFLINE; - cancel_delayed_work_sync(&mci->work); - flush_workqueue(edac_workqueue); + edac_stop_work(&mci->work); } /* @@ -608,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); } @@ -781,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; } diff --git a/drivers/edac/edac_module.c b/drivers/edac/edac_module.c index 2b53680a687d..5f8543be995a 100644 --- a/drivers/edac/edac_module.c +++ b/drivers/edac/edac_module.c @@ -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() */ @@ -65,32 +62,6 @@ char *edac_op_state_to_string(int opstate) return "UNKNOWN"; } -/* - * edac_workqueue_setup - * initialize the edac work queue for polling operations - */ -static int edac_workqueue_setup(void) -{ - edac_workqueue = create_singlethread_workqueue("edac-poller"); - if (edac_workqueue == NULL) - return -ENODEV; - else - return 0; -} - -/* - * edac_workqueue_teardown - * teardown the edac workqueue - */ -static void edac_workqueue_teardown(void) -{ - if (edac_workqueue) { - flush_workqueue(edac_workqueue); - destroy_workqueue(edac_workqueue); - edac_workqueue = NULL; - } -} - /* * sysfs object: /sys/devices/system/edac * need to export to other files diff --git a/drivers/edac/edac_module.h b/drivers/edac/edac_module.h index 7388abfbf10b..cfaacb99c973 100644 --- a/drivers/edac/edac_module.h +++ b/drivers/edac/edac_module.h @@ -47,7 +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; +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); diff --git a/drivers/edac/edac_pci.c b/drivers/edac/edac_pci.c index d8b083190695..99685388d3fb 100644 --- a/drivers/edac/edac_pci.c +++ b/drivers/edac/edac_pci.c @@ -209,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); @@ -229,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())); } /* @@ -243,33 +243,9 @@ static void edac_pci_workq_teardown(struct edac_pci_ctl_info *pci) pci->op_state = OP_OFFLINE; - cancel_delayed_work_sync(&pci->work); - flush_workqueue(edac_workqueue); + edac_stop_work(&pci->work); } -/* - * 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); - - mutex_unlock(&edac_pci_ctls_mutex); -} -EXPORT_SYMBOL_GPL(edac_pci_reset_delay_period); - /* * edac_pci_alloc_index: Allocate a unique PCI index number * diff --git a/drivers/edac/wq.c b/drivers/edac/wq.c new file mode 100644 index 000000000000..1b8c07e44fd8 --- /dev/null +++ b/drivers/edac/wq.c @@ -0,0 +1,42 @@ +#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; +}