[RFC PATCH 07/13] powerpc/vas: Update CSB and notify process for fault CRBs
Haren Myneni
haren at linux.vnet.ibm.com
Sat Oct 19 16:57:16 AEDT 2019
For each fault CRB, update fault address in CRB (fault_storage_addr)
and translation error status in CSB. If the actual fault is in CSB,
send signal to process with SIGSEGV. Process can send new request by
touching the fault address.
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 | 115 +++++++++++++++++++++++++++++
arch/powerpc/platforms/powernv/vas.h | 5 ++
2 files changed, 120 insertions(+)
diff --git a/arch/powerpc/platforms/powernv/vas-fault.c b/arch/powerpc/platforms/powernv/vas-fault.c
index 02b5c10..7aacce9 100644
--- a/arch/powerpc/platforms/powernv/vas-fault.c
+++ b/arch/powerpc/platforms/powernv/vas-fault.c
@@ -40,6 +40,120 @@ void vas_wakeup_fault_handler(int virq, void *arg)
}
/*
+ * Check if the fault occurred in the CSB itself. Return true if so, false
+ */
+static bool fault_in_csb(struct coprocessor_request_block *crb)
+{
+ u64 fault_addr, csb_start, csb_end;
+
+ fault_addr = crb_nx_fault_addr(crb);
+ csb_start = crb_csb_addr(crb);
+ csb_end = csb_start + sizeof(struct coprocessor_status_block);
+
+ if (fault_addr >= csb_start && fault_addr < csb_end) {
+ pr_err("CSB Fault: csb start/end 0x%llx/0x%llx, addr 0x%llx\n",
+ csb_start, csb_end, fault_addr);
+ return true;
+ }
+
+ return false;
+}
+
+static void notify_process(pid_t pid, u64 fault_addr)
+{
+ int rc;
+ struct kernel_siginfo info;
+
+ memset(&info, 0, sizeof(info));
+
+ info.si_signo = SIGSEGV;
+ info.si_errno = 0;
+ info.si_code = 0;
+
+ info.si_addr = (void *)fault_addr;
+ rcu_read_lock();
+ rc = kill_pid_info(SIGSEGV, &info, find_vpid(pid));
+ rcu_read_unlock();
+
+ pr_devel("%s(): pid %d kill_proc_info() rc %d\n", __func__, pid, rc);
+}
+
+/*
+ * Update the CSB to indicate a translation error.
+ *
+ * If the fault is in the CSB address itself or if we are unable to
+ * update the CSB, send a signal to the process, because we have no
+ * other way of notifying the user process.
+ *
+ * Remaining settings in the CSB are based on wait_for_csb() of
+ * NX-GZIP.
+*/
+static void update_csb(int pid, struct coprocessor_request_block *crb)
+{
+ int rc;
+ void __user *csb_addr;
+ struct task_struct *tsk;
+ struct coprocessor_status_block csb;
+
+ if (fault_in_csb(crb))
+ goto notify;
+
+ csb_addr = (void *)__be64_to_cpu(crb->csb_addr);
+
+ csb.cc = CSB_CC_TRANSLATION;
+ csb.ce = CSB_CE_TERMINATION;
+ csb.cs = 0;
+ csb.count = 0;
+
+ /*
+ * Returns the fault address in CPU format since it is passed with
+ * signal. But if the user space expects BE format, need changes.
+ * i.e either kernel (here) or user should convert to CPU format.
+ * Not both!
+ */
+ csb.address = crb_nx_fault_addr(crb);
+ csb.flags = CSB_V;
+
+ rcu_read_lock();
+ tsk = find_task_by_vpid(pid);
+ if (!tsk) {
+ /*
+ * vas_win_close() waits for any pending CRBs and pending
+ * send window credits. In case of this fault CRB, the send
+ * credit is not yet returned. So we should NOT end up with a
+ * non-existent task for this fault CRB.
+ */
+ WARN_ON_ONCE(!tsk);
+ rcu_read_unlock();
+ return;
+ }
+
+ if (tsk->flags & PF_EXITING) {
+ rcu_read_unlock();
+ return;
+ }
+
+ get_task_struct(tsk);
+ rcu_read_unlock();
+
+ use_mm(tsk->mm);
+ rc = copy_to_user(csb_addr, &csb, sizeof(csb));
+ unuse_mm(tsk->mm);
+ put_task_struct(tsk);
+
+ if (rc) {
+ pr_err("CSB: Error updating CSB address 0x%p signalling\n",
+ csb_addr);
+ goto notify;
+ }
+
+ return;
+
+notify:
+ notify_process(pid, crb_nx_fault_addr(crb));
+}
+
+/*
* Process CRBs that we receive on the fault window.
*/
static void process_fault_crbs(struct vas_instance *vinst)
@@ -116,6 +230,7 @@ static void process_fault_crbs(struct vas_instance *vinst)
return;
}
+ update_csb(vas_window_pid(window), crb);
} while (true);
}
diff --git a/arch/powerpc/platforms/powernv/vas.h b/arch/powerpc/platforms/powernv/vas.h
index eb929c7..be1aefa 100644
--- a/arch/powerpc/platforms/powernv/vas.h
+++ b/arch/powerpc/platforms/powernv/vas.h
@@ -424,6 +424,11 @@ struct vas_winctx {
extern struct vas_window *vas_pswid_to_window(struct vas_instance *vinst,
uint32_t pswid);
+static inline int vas_window_pid(struct vas_window *window)
+{
+ return window->pid;
+}
+
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