Commit 9054619e authored by John Allen's avatar John Allen Committed by Michael Ellerman

powerpc/pseries: Add pseries hotplug workqueue

In support of PAPR changes to add a new hotplug interrupt, introduce a
hotplug workqueue to avoid processing hotplug events in interrupt context.
We will also take advantage of the queue on PowerVM to ensure hotplug
events initiated from different sources (HMC and PRRN events) are handled
and serialized properly.
Signed-off-by: default avatarJohn Allen <jallen@linux.vnet.ibm.com>
Reviewed-by: default avatarNathan Fontenot <nfont@linux.vnet.ibm.com>
Signed-off-by: default avatarMichael Ellerman <mpe@ellerman.id.au>
parent 8fbaa51d
...@@ -27,6 +27,15 @@ ...@@ -27,6 +27,15 @@
#include <asm/uaccess.h> #include <asm/uaccess.h>
#include <asm/rtas.h> #include <asm/rtas.h>
struct workqueue_struct *pseries_hp_wq;
struct pseries_hp_work {
struct work_struct work;
struct pseries_hp_errorlog *errlog;
struct completion *hp_completion;
int *rc;
};
struct cc_workarea { struct cc_workarea {
__be32 drc_index; __be32 drc_index;
__be32 zero; __be32 zero;
...@@ -368,10 +377,51 @@ static int handle_dlpar_errorlog(struct pseries_hp_errorlog *hp_elog) ...@@ -368,10 +377,51 @@ static int handle_dlpar_errorlog(struct pseries_hp_errorlog *hp_elog)
return rc; return rc;
} }
void pseries_hp_work_fn(struct work_struct *work)
{
struct pseries_hp_work *hp_work =
container_of(work, struct pseries_hp_work, work);
if (hp_work->rc)
*(hp_work->rc) = handle_dlpar_errorlog(hp_work->errlog);
else
handle_dlpar_errorlog(hp_work->errlog);
if (hp_work->hp_completion)
complete(hp_work->hp_completion);
kfree(hp_work->errlog);
kfree((void *)work);
}
void queue_hotplug_event(struct pseries_hp_errorlog *hp_errlog,
struct completion *hotplug_done, int *rc)
{
struct pseries_hp_work *work;
struct pseries_hp_errorlog *hp_errlog_copy;
hp_errlog_copy = kmalloc(sizeof(struct pseries_hp_errorlog),
GFP_KERNEL);
memcpy(hp_errlog_copy, hp_errlog, sizeof(struct pseries_hp_errorlog));
work = kmalloc(sizeof(struct pseries_hp_work), GFP_KERNEL);
if (work) {
INIT_WORK((struct work_struct *)work, pseries_hp_work_fn);
work->errlog = hp_errlog_copy;
work->hp_completion = hotplug_done;
work->rc = rc;
queue_work(pseries_hp_wq, (struct work_struct *)work);
} else {
*rc = -ENOMEM;
complete(hotplug_done);
}
}
static ssize_t dlpar_store(struct class *class, struct class_attribute *attr, static ssize_t dlpar_store(struct class *class, struct class_attribute *attr,
const char *buf, size_t count) const char *buf, size_t count)
{ {
struct pseries_hp_errorlog *hp_elog; struct pseries_hp_errorlog *hp_elog;
struct completion hotplug_done;
const char *arg; const char *arg;
int rc; int rc;
...@@ -450,6 +500,8 @@ static CLASS_ATTR(dlpar, S_IWUSR, NULL, dlpar_store); ...@@ -450,6 +500,8 @@ static CLASS_ATTR(dlpar, S_IWUSR, NULL, dlpar_store);
static int __init pseries_dlpar_init(void) static int __init pseries_dlpar_init(void)
{ {
pseries_hp_wq = alloc_workqueue("pseries hotplug workqueue",
WQ_UNBOUND, 1);
return sysfs_create_file(kernel_kobj, &class_attr_dlpar.attr); return sysfs_create_file(kernel_kobj, &class_attr_dlpar.attr);
} }
machine_device_initcall(pseries, pseries_dlpar_init); machine_device_initcall(pseries, pseries_dlpar_init);
......
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