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