[PATCH 06/14] powerpc/vas: Setup fault handler per VAS instance

Haren Myneni haren at linux.vnet.ibm.com
Wed Nov 27 12:08:20 AEDT 2019


Fault handler is created as kernel thread for each VAS instance and
invoked whenever NX generates page fault. This thread reads CRBs
from fault FIFO and process them.

Signed-off-by: Sukadev Bhattiprolu <sukadev at linux.vnet.ibm.com>
Signed-off-by: Haren Myneni <haren at us.ibm.com>
---
 arch/powerpc/platforms/powernv/vas-fault.c | 54 ++++++++++++++++++++++++++++++
 arch/powerpc/platforms/powernv/vas.c       |  7 ++++
 arch/powerpc/platforms/powernv/vas.h       |  6 ++++
 3 files changed, 67 insertions(+)

diff --git a/arch/powerpc/platforms/powernv/vas-fault.c b/arch/powerpc/platforms/powernv/vas-fault.c
index a5e63a5..c6c105c 100644
--- a/arch/powerpc/platforms/powernv/vas-fault.c
+++ b/arch/powerpc/platforms/powernv/vas-fault.c
@@ -11,6 +11,7 @@
 #include <linux/slab.h>
 #include <linux/uaccess.h>
 #include <linux/kthread.h>
+#include <linux/sched/signal.h>
 #include <asm/icswx.h>
 
 #include "vas.h"
@@ -24,6 +25,54 @@
  */
 #define VAS_FAULT_WIN_FIFO_SIZE	(4 << 20)
 
+struct task_struct *fault_handler;
+
+void vas_wakeup_fault_handler(int virq, void *arg)
+{
+	struct vas_instance *vinst = arg;
+
+	atomic_inc(&vinst->pending_fault);
+	wake_up(&vinst->fault_wq);
+}
+
+/*
+ * Fault handler thread for each VAS instance and process fault CRBs.
+ */
+static int fault_handler_func(void *arg)
+{
+	struct vas_instance *vinst = (struct vas_instance *)arg;
+
+	do {
+		if (signal_pending(current))
+			flush_signals(current);
+
+		wait_event_interruptible(vinst->fault_wq,
+					atomic_read(&vinst->pending_fault) ||
+					kthread_should_stop());
+
+		if (kthread_should_stop())
+			break;
+
+		atomic_dec(&vinst->pending_fault);
+	} while (!kthread_should_stop());
+
+	return 0;
+}
+
+/*
+ * Create a thread that processes the fault CRBs.
+ */
+int vas_setup_fault_handler(struct vas_instance *vinst)
+{
+	vinst->fault_handler = kthread_run(fault_handler_func, (void *)vinst,
+					"vas-fault-%u", vinst->vas_id);
+
+	if (IS_ERR(vinst->fault_handler))
+		return PTR_ERR(vinst->fault_handler);
+
+	return 0;
+}
+
 /*
  * Fault window is opened per VAS instance. NX pastes fault CRB in fault
  * FIFO upon page faults.
@@ -102,4 +151,9 @@ int vas_cleanup_fault_window(struct vas_instance *vinst)
 
 	return rc;
 }
+
+void vas_cleanup_fault_handler(struct vas_instance *vinst)
+{
+	kthread_stop(vinst->fault_handler);
+}
 #endif
diff --git a/arch/powerpc/platforms/powernv/vas.c b/arch/powerpc/platforms/powernv/vas.c
index dd0e06c..db2aca4 100644
--- a/arch/powerpc/platforms/powernv/vas.c
+++ b/arch/powerpc/platforms/powernv/vas.c
@@ -30,6 +30,7 @@ static irqreturn_t vas_irq_handler(int virq, void *data)
 	struct vas_instance *vinst = data;
 
 	pr_devel("VAS %d: virq %d\n", vinst->vas_id, virq);
+	vas_wakeup_fault_handler(virq, data);
 
 	return IRQ_HANDLED;
 }
@@ -54,6 +55,10 @@ static void vas_irq_fault_handle_setup(struct vas_instance *vinst)
 	 * for user space.
 	 */
 	rc = vas_setup_fault_window(vinst);
+
+	if (!rc)
+		rc = vas_setup_fault_handler(vinst);
+
 	if (rc) {
 		free_irq(vinst->virq, vinst);
 		vinst->virq = 0;
@@ -129,6 +134,8 @@ static int init_vas_instance(struct platform_device *pdev)
 		}
 	}
 
+	init_waitqueue_head(&vinst->fault_wq);
+
 	pr_devel("Initialized instance [%s, %d] paste_base 0x%llx paste_win_id_shift 0x%llx IRQ %d Port 0x%llx\n",
 			pdev->name, vasid, vinst->paste_base_addr,
 			vinst->paste_win_id_shift, vinst->virq,
diff --git a/arch/powerpc/platforms/powernv/vas.h b/arch/powerpc/platforms/powernv/vas.h
index e23fd69..ee284b3 100644
--- a/arch/powerpc/platforms/powernv/vas.h
+++ b/arch/powerpc/platforms/powernv/vas.h
@@ -317,6 +317,9 @@ struct vas_instance {
 	int virq;
 	int fault_fifo_size;
 	void *fault_fifo;
+	atomic_t pending_fault;
+	wait_queue_head_t fault_wq;
+	struct task_struct *fault_handler;
 	struct vas_window *fault_win; /* Fault window */
 
 	struct mutex mutex;
@@ -414,6 +417,9 @@ struct vas_winctx {
 extern void vas_window_free_dbgdir(struct vas_window *win);
 extern int vas_setup_fault_window(struct vas_instance *vinst);
 extern int vas_cleanup_fault_window(struct vas_instance *vinst);
+extern void vas_wakeup_fault_handler(int virq, void *arg);
+extern int vas_setup_fault_handler(struct vas_instance *vinst);
+extern void vas_cleanup_fault_handler(struct vas_instance *vinst);
 
 static inline void vas_log_write(struct vas_window *win, char *name,
 			void *regptr, u64 val)
-- 
1.8.3.1





More information about the Linuxppc-dev mailing list