Commit 89ed0b76 authored by Haren Myneni's avatar Haren Myneni Committed by Michael Ellerman

powerpc/pseries/vas: Add VAS IRQ primary handler

irq_default_primary_handler() can be used only with IRQF_ONESHOT
flag, but the flag disables IRQ before executing the thread handler
and enables it after the interrupt is handled. But this IRQ disable
sets the VAS IRQ OFF state in the hypervisor. In case if NX faults
during this window, the hypervisor will not deliver the fault
interrupt to the partition and the user space may wait continuously
for the CSB update. So use VAS specific IRQ handler instead of
calling the default primary handler.

Increment pending_faults counter in IRQ handler and the bottom
thread handler will process all faults based on this counter.
In case if the another interrupt is received while the thread is
running, it will be processed using this counter. The synchronization
of top and bottom handlers will be done with IRQTF_RUNTHREAD flag
and will re-enter to bottom half if this flag is set.
Signed-off-by: default avatarHaren Myneni <haren@linux.ibm.com>
Reviewed-by: default avatarFrederic Barrat <fbarrat@linux.ibm.com>
Signed-off-by: default avatarMichael Ellerman <mpe@ellerman.id.au>
Link: https://lore.kernel.org/r/aaad8813b4762a6753cfcd0b605a7574a5192ec7.camel@linux.ibm.com
parent 9abf2313
...@@ -200,16 +200,41 @@ static irqreturn_t pseries_vas_fault_thread_fn(int irq, void *data) ...@@ -200,16 +200,41 @@ static irqreturn_t pseries_vas_fault_thread_fn(int irq, void *data)
struct vas_user_win_ref *tsk_ref; struct vas_user_win_ref *tsk_ref;
int rc; int rc;
rc = h_get_nx_fault(txwin->vas_win.winid, (u64)virt_to_phys(&crb)); while (atomic_read(&txwin->pending_faults)) {
if (!rc) { rc = h_get_nx_fault(txwin->vas_win.winid, (u64)virt_to_phys(&crb));
tsk_ref = &txwin->vas_win.task_ref; if (!rc) {
vas_dump_crb(&crb); tsk_ref = &txwin->vas_win.task_ref;
vas_update_csb(&crb, tsk_ref); vas_dump_crb(&crb);
vas_update_csb(&crb, tsk_ref);
}
atomic_dec(&txwin->pending_faults);
} }
return IRQ_HANDLED; return IRQ_HANDLED;
} }
/*
* irq_default_primary_handler() can be used only with IRQF_ONESHOT
* which disables IRQ before executing the thread handler and enables
* it after. But this disabling interrupt sets the VAS IRQ OFF
* state in the hypervisor. If the NX generates fault interrupt
* during this window, the hypervisor will not deliver this
* interrupt to the LPAR. So use VAS specific IRQ handler instead
* of calling the default primary handler.
*/
static irqreturn_t pseries_vas_irq_handler(int irq, void *data)
{
struct pseries_vas_window *txwin = data;
/*
* The thread hanlder will process this interrupt if it is
* already running.
*/
atomic_inc(&txwin->pending_faults);
return IRQ_WAKE_THREAD;
}
/* /*
* Allocate window and setup IRQ mapping. * Allocate window and setup IRQ mapping.
*/ */
...@@ -240,8 +265,9 @@ static int allocate_setup_window(struct pseries_vas_window *txwin, ...@@ -240,8 +265,9 @@ static int allocate_setup_window(struct pseries_vas_window *txwin,
goto out_irq; goto out_irq;
} }
rc = request_threaded_irq(txwin->fault_virq, NULL, rc = request_threaded_irq(txwin->fault_virq,
pseries_vas_fault_thread_fn, IRQF_ONESHOT, pseries_vas_irq_handler,
pseries_vas_fault_thread_fn, 0,
txwin->name, txwin); txwin->name, txwin);
if (rc) { if (rc) {
pr_err("VAS-Window[%d]: Request IRQ(%u) failed with %d\n", pr_err("VAS-Window[%d]: Request IRQ(%u) failed with %d\n",
......
...@@ -132,6 +132,7 @@ struct pseries_vas_window { ...@@ -132,6 +132,7 @@ struct pseries_vas_window {
u64 flags; u64 flags;
char *name; char *name;
int fault_virq; int fault_virq;
atomic_t pending_faults; /* Number of pending faults */
}; };
int sysfs_add_vas_caps(struct vas_cop_feat_caps *caps); int sysfs_add_vas_caps(struct vas_cop_feat_caps *caps);
......
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