forked from Minki/linux
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: John Allen <jallen@linux.vnet.ibm.com> Reviewed-by: Nathan Fontenot <nfont@linux.vnet.ibm.com> Signed-off-by: Michael Ellerman <mpe@ellerman.id.au>
This commit is contained in:
parent
8fbaa51d43
commit
9054619ef5
@ -27,6 +27,15 @@
|
||||
#include <asm/uaccess.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 {
|
||||
__be32 drc_index;
|
||||
__be32 zero;
|
||||
@ -368,10 +377,51 @@ static int handle_dlpar_errorlog(struct pseries_hp_errorlog *hp_elog)
|
||||
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,
|
||||
const char *buf, size_t count)
|
||||
{
|
||||
struct pseries_hp_errorlog *hp_elog;
|
||||
struct completion hotplug_done;
|
||||
const char *arg;
|
||||
int rc;
|
||||
|
||||
@ -450,6 +500,8 @@ static CLASS_ATTR(dlpar, S_IWUSR, NULL, dlpar_store);
|
||||
|
||||
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);
|
||||
}
|
||||
machine_device_initcall(pseries, pseries_dlpar_init);
|
||||
|
Loading…
Reference in New Issue
Block a user