10d17de03SHaren Myneni // SPDX-License-Identifier: GPL-2.0+
20d17de03SHaren Myneni /*
30d17de03SHaren Myneni  * VAS Fault handling.
40d17de03SHaren Myneni  * Copyright 2019, IBM Corporation
50d17de03SHaren Myneni  */
60d17de03SHaren Myneni 
70d17de03SHaren Myneni #define pr_fmt(fmt) "vas: " fmt
80d17de03SHaren Myneni 
90d17de03SHaren Myneni #include <linux/kernel.h>
100d17de03SHaren Myneni #include <linux/types.h>
110d17de03SHaren Myneni #include <linux/slab.h>
120d17de03SHaren Myneni #include <linux/uaccess.h>
130d17de03SHaren Myneni #include <linux/kthread.h>
140d17de03SHaren Myneni #include <asm/icswx.h>
150d17de03SHaren Myneni 
160d17de03SHaren Myneni #include "vas.h"
170d17de03SHaren Myneni 
180d17de03SHaren Myneni /*
190d17de03SHaren Myneni  * The maximum FIFO size for fault window can be 8MB
200d17de03SHaren Myneni  * (VAS_RX_FIFO_SIZE_MAX). Using 4MB FIFO since each VAS
210d17de03SHaren Myneni  * instance will be having fault window.
220d17de03SHaren Myneni  * 8MB FIFO can be used if expects more faults for each VAS
230d17de03SHaren Myneni  * instance.
240d17de03SHaren Myneni  */
250d17de03SHaren Myneni #define VAS_FAULT_WIN_FIFO_SIZE	(4 << 20)
260d17de03SHaren Myneni 
270d17de03SHaren Myneni /*
280d17de03SHaren Myneni  * Fault window is opened per VAS instance. NX pastes fault CRB in fault
290d17de03SHaren Myneni  * FIFO upon page faults.
300d17de03SHaren Myneni  */
310d17de03SHaren Myneni int vas_setup_fault_window(struct vas_instance *vinst)
320d17de03SHaren Myneni {
330d17de03SHaren Myneni 	struct vas_rx_win_attr attr;
340d17de03SHaren Myneni 
350d17de03SHaren Myneni 	vinst->fault_fifo_size = VAS_FAULT_WIN_FIFO_SIZE;
360d17de03SHaren Myneni 	vinst->fault_fifo = kzalloc(vinst->fault_fifo_size, GFP_KERNEL);
370d17de03SHaren Myneni 	if (!vinst->fault_fifo) {
380d17de03SHaren Myneni 		pr_err("Unable to alloc %d bytes for fault_fifo\n",
390d17de03SHaren Myneni 				vinst->fault_fifo_size);
400d17de03SHaren Myneni 		return -ENOMEM;
410d17de03SHaren Myneni 	}
420d17de03SHaren Myneni 
430d17de03SHaren Myneni 	/*
440d17de03SHaren Myneni 	 * Invalidate all CRB entries. NX pastes valid entry for each fault.
450d17de03SHaren Myneni 	 */
460d17de03SHaren Myneni 	memset(vinst->fault_fifo, FIFO_INVALID_ENTRY, vinst->fault_fifo_size);
470d17de03SHaren Myneni 	vas_init_rx_win_attr(&attr, VAS_COP_TYPE_FAULT);
480d17de03SHaren Myneni 
490d17de03SHaren Myneni 	attr.rx_fifo_size = vinst->fault_fifo_size;
500d17de03SHaren Myneni 	attr.rx_fifo = vinst->fault_fifo;
510d17de03SHaren Myneni 
520d17de03SHaren Myneni 	/*
530d17de03SHaren Myneni 	 * Max creds is based on number of CRBs can fit in the FIFO.
540d17de03SHaren Myneni 	 * (fault_fifo_size/CRB_SIZE). If 8MB FIFO is used, max creds
550d17de03SHaren Myneni 	 * will be 0xffff since the receive creds field is 16bits wide.
560d17de03SHaren Myneni 	 */
570d17de03SHaren Myneni 	attr.wcreds_max = vinst->fault_fifo_size / CRB_SIZE;
580d17de03SHaren Myneni 	attr.lnotify_lpid = 0;
590d17de03SHaren Myneni 	attr.lnotify_pid = mfspr(SPRN_PID);
600d17de03SHaren Myneni 	attr.lnotify_tid = mfspr(SPRN_PID);
610d17de03SHaren Myneni 
620d17de03SHaren Myneni 	vinst->fault_win = vas_rx_win_open(vinst->vas_id, VAS_COP_TYPE_FAULT,
630d17de03SHaren Myneni 					&attr);
640d17de03SHaren Myneni 
650d17de03SHaren Myneni 	if (IS_ERR(vinst->fault_win)) {
660d17de03SHaren Myneni 		pr_err("VAS: Error %ld opening FaultWin\n",
670d17de03SHaren Myneni 			PTR_ERR(vinst->fault_win));
680d17de03SHaren Myneni 		kfree(vinst->fault_fifo);
690d17de03SHaren Myneni 		return PTR_ERR(vinst->fault_win);
700d17de03SHaren Myneni 	}
710d17de03SHaren Myneni 
720d17de03SHaren Myneni 	pr_devel("VAS: Created FaultWin %d, LPID/PID/TID [%d/%d/%d]\n",
730d17de03SHaren Myneni 			vinst->fault_win->winid, attr.lnotify_lpid,
740d17de03SHaren Myneni 			attr.lnotify_pid, attr.lnotify_tid);
750d17de03SHaren Myneni 
760d17de03SHaren Myneni 	return 0;
770d17de03SHaren Myneni }
78