[RFC PATCH 07/13] powerpc/vas: Update CSB and notify process for fault CRBs
From: Haren Myneni <hidden>
Date: 2019-10-19 06:06:26
Subsystem:
linux for powerpc (32-bit and 64-bit), the rest · Maintainers:
Madhavan Srinivasan, Linus Torvalds
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 <redacted> Signed-off-by: Haren Myneni <haren@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