Commit c4cf3b45 authored by Borislav Petkov's avatar Borislav Petkov

EDAC: Rework workqueue handling

Hide the EDAC workqueue pointer in a separate compilation unit and add
accessors for the workqueue manipulations needed.

Remove edac_pci_reset_delay_period() which wasn't used by anything. It
seems it got added without a user with

  91b99041 ("drivers/edac: updated PCI monitoring")
Signed-off-by: default avatarBorislav Petkov <bp@suse.de>
parent e136fa01
...@@ -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);
} }
/* /*
...@@ -422,11 +420,9 @@ static void edac_device_workq_setup(struct edac_device_ctl_info *edac_dev, ...@@ -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 * 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);
} }
/* /*
...@@ -440,8 +436,7 @@ static void edac_device_workq_teardown(struct edac_device_ctl_info *edac_dev) ...@@ -440,8 +436,7 @@ static void edac_device_workq_teardown(struct edac_device_ctl_info *edac_dev)
edac_dev->op_state = OP_OFFLINE; edac_dev->op_state = OP_OFFLINE;
cancel_delayed_work_sync(&edac_dev->work); edac_stop_work(&edac_dev->work);
flush_workqueue(edac_workqueue);
} }
/* /*
...@@ -454,16 +449,15 @@ static void edac_device_workq_teardown(struct edac_device_ctl_info *edac_dev) ...@@ -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, 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);
} }
/* /*
......
...@@ -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));
} }
/* /*
...@@ -588,8 +585,7 @@ static void edac_mc_workq_teardown(struct mem_ctl_info *mci) ...@@ -588,8 +585,7 @@ static void edac_mc_workq_teardown(struct mem_ctl_info *mci)
{ {
mci->op_state = OP_OFFLINE; mci->op_state = OP_OFFLINE;
cancel_delayed_work_sync(&mci->work); edac_stop_work(&mci->work);
flush_workqueue(edac_workqueue);
} }
/* /*
...@@ -608,9 +604,8 @@ void edac_mc_reset_delay_period(unsigned long value) ...@@ -608,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);
} }
...@@ -781,7 +776,7 @@ int edac_mc_add_mc_with_groups(struct mem_ctl_info *mci, ...@@ -781,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;
} }
......
...@@ -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()
*/ */
...@@ -65,32 +62,6 @@ char *edac_op_state_to_string(int opstate) ...@@ -65,32 +62,6 @@ char *edac_op_state_to_string(int opstate)
return "UNKNOWN"; 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 * sysfs object: /sys/devices/system/edac
* need to export to other files * need to export to other files
......
...@@ -47,7 +47,12 @@ extern int edac_device_create_sysfs(struct edac_device_ctl_info *edac_dev); ...@@ -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); 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);
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 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);
......
...@@ -209,7 +209,7 @@ static void edac_pci_workq_function(struct work_struct *work_req) ...@@ -209,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);
...@@ -229,8 +229,8 @@ static void edac_pci_workq_setup(struct edac_pci_ctl_info *pci, ...@@ -229,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()));
} }
/* /*
...@@ -243,32 +243,8 @@ static void edac_pci_workq_teardown(struct edac_pci_ctl_info *pci) ...@@ -243,32 +243,8 @@ static void edac_pci_workq_teardown(struct edac_pci_ctl_info *pci)
pci->op_state = OP_OFFLINE; pci->op_state = OP_OFFLINE;
cancel_delayed_work_sync(&pci->work); edac_stop_work(&pci->work);
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);
mutex_unlock(&edac_pci_ctls_mutex);
} }
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
......
#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;
}
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