Commit 0d17de03 authored by Haren Myneni's avatar Haren Myneni Committed by Michael Ellerman

powerpc/vas: Setup fault window per VAS instance

Setup fault window for each VAS instance. When NX gets a fault on
request buffer, pastes fault CRB in the corresponding fault FIFO and
then raises an interrupt to the OS. The kernel handles this fault
and process faults CRB from this FIFO.
Signed-off-by: default avatarSukadev Bhattiprolu <sukadev@linux.vnet.ibm.com>
Signed-off-by: default avatarHaren Myneni <haren@linux.ibm.com>
Signed-off-by: default avatarMichael Ellerman <mpe@ellerman.id.au>
Link: https://lore.kernel.org/r/1587016846.2275.1053.camel@hbabu-laptop
parent c20e1e29
......@@ -17,7 +17,7 @@ obj-$(CONFIG_MEMORY_FAILURE) += opal-memory-errors.o
obj-$(CONFIG_OPAL_PRD) += opal-prd.o
obj-$(CONFIG_PERF_EVENTS) += opal-imc.o
obj-$(CONFIG_PPC_MEMTRACE) += memtrace.o
obj-$(CONFIG_PPC_VAS) += vas.o vas-window.o vas-debug.o
obj-$(CONFIG_PPC_VAS) += vas.o vas-window.o vas-debug.o vas-fault.o
obj-$(CONFIG_OCXL_BASE) += ocxl.o
obj-$(CONFIG_SCOM_DEBUGFS) += opal-xscom.o
obj-$(CONFIG_PPC_SECURE_BOOT) += opal-secvar.o
// SPDX-License-Identifier: GPL-2.0+
/*
* VAS Fault handling.
* Copyright 2019, IBM Corporation
*/
#define pr_fmt(fmt) "vas: " fmt
#include <linux/kernel.h>
#include <linux/types.h>
#include <linux/slab.h>
#include <linux/uaccess.h>
#include <linux/kthread.h>
#include <asm/icswx.h>
#include "vas.h"
/*
* The maximum FIFO size for fault window can be 8MB
* (VAS_RX_FIFO_SIZE_MAX). Using 4MB FIFO since each VAS
* instance will be having fault window.
* 8MB FIFO can be used if expects more faults for each VAS
* instance.
*/
#define VAS_FAULT_WIN_FIFO_SIZE (4 << 20)
/*
* Fault window is opened per VAS instance. NX pastes fault CRB in fault
* FIFO upon page faults.
*/
int vas_setup_fault_window(struct vas_instance *vinst)
{
struct vas_rx_win_attr attr;
vinst->fault_fifo_size = VAS_FAULT_WIN_FIFO_SIZE;
vinst->fault_fifo = kzalloc(vinst->fault_fifo_size, GFP_KERNEL);
if (!vinst->fault_fifo) {
pr_err("Unable to alloc %d bytes for fault_fifo\n",
vinst->fault_fifo_size);
return -ENOMEM;
}
/*
* Invalidate all CRB entries. NX pastes valid entry for each fault.
*/
memset(vinst->fault_fifo, FIFO_INVALID_ENTRY, vinst->fault_fifo_size);
vas_init_rx_win_attr(&attr, VAS_COP_TYPE_FAULT);
attr.rx_fifo_size = vinst->fault_fifo_size;
attr.rx_fifo = vinst->fault_fifo;
/*
* Max creds is based on number of CRBs can fit in the FIFO.
* (fault_fifo_size/CRB_SIZE). If 8MB FIFO is used, max creds
* will be 0xffff since the receive creds field is 16bits wide.
*/
attr.wcreds_max = vinst->fault_fifo_size / CRB_SIZE;
attr.lnotify_lpid = 0;
attr.lnotify_pid = mfspr(SPRN_PID);
attr.lnotify_tid = mfspr(SPRN_PID);
vinst->fault_win = vas_rx_win_open(vinst->vas_id, VAS_COP_TYPE_FAULT,
&attr);
if (IS_ERR(vinst->fault_win)) {
pr_err("VAS: Error %ld opening FaultWin\n",
PTR_ERR(vinst->fault_win));
kfree(vinst->fault_fifo);
return PTR_ERR(vinst->fault_win);
}
pr_devel("VAS: Created FaultWin %d, LPID/PID/TID [%d/%d/%d]\n",
vinst->fault_win->winid, attr.lnotify_lpid,
attr.lnotify_pid, attr.lnotify_tid);
return 0;
}
......@@ -827,9 +827,9 @@ void vas_init_rx_win_attr(struct vas_rx_win_attr *rxattr, enum vas_cop_type cop)
rxattr->fault_win = true;
rxattr->notify_disable = true;
rxattr->rx_wcred_mode = true;
rxattr->tx_wcred_mode = true;
rxattr->rx_win_ord_mode = true;
rxattr->tx_win_ord_mode = true;
rxattr->rej_no_credit = true;
rxattr->tc_mode = VAS_THRESH_DISABLED;
} else if (cop == VAS_COP_TYPE_FTW) {
rxattr->user_win = true;
rxattr->intr_disable = true;
......
......@@ -24,6 +24,11 @@ static LIST_HEAD(vas_instances);
static DEFINE_PER_CPU(int, cpu_vas_id);
static int vas_irq_fault_window_setup(struct vas_instance *vinst)
{
return vas_setup_fault_window(vinst);
}
static int init_vas_instance(struct platform_device *pdev)
{
struct device_node *dn = pdev->dev.of_node;
......@@ -114,6 +119,21 @@ static int init_vas_instance(struct platform_device *pdev)
list_add(&vinst->node, &vas_instances);
mutex_unlock(&vas_mutex);
/*
* IRQ and fault handling setup is needed only for user space
* send windows.
*/
if (vinst->virq) {
rc = vas_irq_fault_window_setup(vinst);
/*
* Fault window is used only for user space send windows.
* So if vinst->virq is NULL, tx_win_open returns -ENODEV
* for user space.
*/
if (rc)
vinst->virq = 0;
}
vas_instance_init_dbgdir(vinst);
dev_set_drvdata(&pdev->dev, vinst);
......
......@@ -295,6 +295,22 @@ enum vas_notify_after_count {
VAS_NOTIFY_AFTER_2
};
/*
* NX can generate an interrupt for multiple faults and expects kernel
* to process all of them. So read all valid CRB entries until find the
* invalid one. So use pswid which is pasted by NX and ccw[0] (reserved
* bit in BE) to check valid CRB. CCW[0] will not be touched by user
* space. Application gets CRB formt error if it updates this bit.
*
* Invalidate FIFO during allocation and process all entries from last
* successful read until finds invalid pswid and ccw[0] values.
* After reading each CRB entry from fault FIFO, the kernel invalidate
* it by updating pswid with FIFO_INVALID_ENTRY and CCW[0] with
* CCW0_INVALID.
*/
#define FIFO_INVALID_ENTRY 0xffffffff
#define CCW0_INVALID 1
/*
* One per instance of VAS. Each instance will have a separate set of
* receive windows, one per coprocessor type.
......@@ -315,6 +331,10 @@ struct vas_instance {
u64 irq_port;
int virq;
int fault_fifo_size;
void *fault_fifo;
struct vas_window *fault_win; /* Fault window */
struct mutex mutex;
struct vas_window *rxwin[VAS_COP_TYPE_MAX];
struct vas_window *windows[VAS_WINDOWS_PER_CHIP];
......@@ -408,6 +428,7 @@ extern void vas_init_dbgdir(void);
extern void vas_instance_init_dbgdir(struct vas_instance *vinst);
extern void vas_window_init_dbgdir(struct vas_window *win);
extern void vas_window_free_dbgdir(struct vas_window *win);
extern int vas_setup_fault_window(struct vas_instance *vinst);
static inline void vas_log_write(struct vas_window *win, char *name,
void *regptr, u64 val)
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment