--- vrfc
+++ v8
@@ -1,237 +1,231 @@
-The VAS hardware requires kernel to setup a "fault window" to which
-the hardware will paste a CRB in case of address translation faults.
-
-Create a fault window (which is basically a special receive window)
-and a kernel thread that processes the CRBs that arrive at the fault
-window. A follow-on patch will implement IRQ handling and the
-interrupt handler will wake up the fault thread.
-
-The fault window and thread will be used when we support user-space
-access to the VAS/NX hardware. For now the fault window thread simply
-dumps/logs the CRB and the fault isolation registers. Including these
-in this RFC patchset for review/comments.
+Define interfaces (wrappers) to the 'copy' and 'paste' instructions
+(which are new in PowerISA 3.0). These are intended to be used to
+by NX driver(s) to submit Coprocessor Request Blocks (CRBs) to the
+NX hardware engines.
Signed-off-by: Sukadev Bhattiprolu <sukadev@linux.vnet.ibm.com>
+
---
- drivers/misc/vas/vas-internal.h | 1 +
- drivers/misc/vas/vas.c | 157 +++++++++++++++++++++++++++++++++++++++-
- 2 files changed, 157 insertions(+), 1 deletion(-)
-
-diff --git a/drivers/misc/vas/vas-internal.h b/drivers/misc/vas/vas-internal.h
-index a58ffb2..e3ceb74 100644
---- a/drivers/misc/vas/vas-internal.h
-+++ b/drivers/misc/vas/vas-internal.h
-@@ -366,6 +366,7 @@ extern int vas_initialized;
-
- extern int vas_window_reset(struct vas_instance *vinst, int winid);
- extern struct vas_instance *find_vas_instance(int node, int chip);
-+extern void vas_wakeup_fault_win_thread(void);
+Changelog[v8]:
+ - [Michael Ellerman] Drop vas_initialized() check; cleanup asm code,
+ reuse existing macros, fix old references; add cr0 to clobbers
+
+Changelog[v4]
+ - Export symbols
+Changelog[v3]
+ - Map raw CR value from paste instruction into an error code.
+
+Conflicts:
+ arch/powerpc/platforms/powernv/vas.h
+---
+ MAINTAINERS | 1 +
+ arch/powerpc/include/asm/ppc-opcode.h | 2 ++
+ arch/powerpc/include/asm/vas.h | 12 ++++++++
+ arch/powerpc/platforms/powernv/copy-paste.h | 46 ++++++++++++++++++++++++++++
+ arch/powerpc/platforms/powernv/vas-window.c | 47 +++++++++++++++++++++++++++++
+ arch/powerpc/platforms/powernv/vas.h | 18 +++++++++--
+ 6 files changed, 124 insertions(+), 2 deletions(-)
+ create mode 100644 arch/powerpc/platforms/powernv/copy-paste.h
+
+diff --git a/MAINTAINERS b/MAINTAINERS
+index ec68732..624c67a 100644
+--- a/MAINTAINERS
++++ b/MAINTAINERS
+@@ -6442,6 +6442,7 @@ M: Sukadev Bhattiprolu
+ L: linuxppc-dev@lists.ozlabs.org
+ S: Supported
+ F: arch/powerpc/platforms/powernv/vas*
++F: arch/powerpc/platforms/powernv/copy-paste.h
+ F: arch/powerpc/include/asm/vas.h
+ F: arch/powerpc/include/uapi/asm/vas.h
+
+diff --git a/arch/powerpc/include/asm/ppc-opcode.h b/arch/powerpc/include/asm/ppc-opcode.h
+index fa9ebae..749336d 100644
+--- a/arch/powerpc/include/asm/ppc-opcode.h
++++ b/arch/powerpc/include/asm/ppc-opcode.h
+@@ -414,6 +414,8 @@
+ ___PPC_RB(b))
+ #define PPC_MSGCLRP(b) stringify_in_c(.long PPC_INST_MSGCLRP | \
+ ___PPC_RB(b))
++#define PPC_PASTE(a, b) stringify_in_c(.long PPC_INST_PASTE | \
++ ___PPC_RA(a) | ___PPC_RB(b))
+ #define PPC_POPCNTB(a, s) stringify_in_c(.long PPC_INST_POPCNTB | \
+ __PPC_RA(a) | __PPC_RS(s))
+ #define PPC_POPCNTD(a, s) stringify_in_c(.long PPC_INST_POPCNTD | \
+diff --git a/arch/powerpc/include/asm/vas.h b/arch/powerpc/include/asm/vas.h
+index efbdde5..dfc97f5 100644
+--- a/arch/powerpc/include/asm/vas.h
++++ b/arch/powerpc/include/asm/vas.h
+@@ -145,4 +145,16 @@ struct vas_window *vas_tx_win_open(int vasid, enum vas_cop_type cop,
+ */
+ int vas_win_close(struct vas_window *win);
+
++/*
++ * Copy the co-processor request block (CRB) @crb into the local L2 cache.
++ */
++extern int vas_copy_crb(void *crb, int offset);
++
++/*
++ * Paste a previously copied CRB (see vas_copy_crb()) from the L2 cache to
++ * the hardware address associated with the window @win. @re is expected/
++ * assumed to be true for NX windows.
++ */
++extern int vas_paste_crb(struct vas_window *win, int offset, bool re);
++
+ #endif /* _MISC_VAS_H */
+diff --git a/arch/powerpc/platforms/powernv/copy-paste.h b/arch/powerpc/platforms/powernv/copy-paste.h
+new file mode 100644
+index 0000000..c9a5036
+--- /dev/null
++++ b/arch/powerpc/platforms/powernv/copy-paste.h
+@@ -0,0 +1,46 @@
++/*
++ * Copyright 2016-17 IBM Corp.
++ *
++ * This program is free software; you can redistribute it and/or
++ * modify it under the terms of the GNU General Public License
++ * as published by the Free Software Foundation; either version
++ * 2 of the License, or (at your option) any later version.
++ */
++#include <asm/ppc-opcode.h>
++
++#define CR0_SHIFT 28
++#define CR0_MASK 0xF
++/*
++ * Copy/paste instructions:
++ *
++ * copy RA,RB
++ * Copy contents of address (RA) + effective_address(RB)
++ * to internal copy-buffer.
++ *
++ * paste RA,RB
++ * Paste contents of internal copy-buffer to the address
++ * (RA) + effective_address(RB)
++ */
++static inline int vas_copy(void *crb, int offset)
++{
++ asm volatile(PPC_COPY(%0, %1)";"
++ :
++ : "b" (offset), "b" (crb)
++ : "memory");
++
++ return 0;
++}
++
++static inline int vas_paste(void *paste_address, int offset)
++{
++ u32 cr;
++
++ cr = 0;
++ asm volatile(PPC_PASTE(%1, %2)";"
++ "mfocrf %0, 0x80;"
++ : "=r" (cr)
++ : "b" (offset), "b" (paste_address)
++ : "memory", "cr0");
++
++ return (cr >> CR0_SHIFT) & CR0_MASK;
++}
+diff --git a/arch/powerpc/platforms/powernv/vas-window.c b/arch/powerpc/platforms/powernv/vas-window.c
+index cd12e44..b02f26d 100644
+--- a/arch/powerpc/platforms/powernv/vas-window.c
++++ b/arch/powerpc/platforms/powernv/vas-window.c
+@@ -18,6 +18,7 @@
+ #include <linux/cred.h>
+
+ #include "vas.h"
++#include "copy-paste.h"
/*
- * VREG(x):
-diff --git a/drivers/misc/vas/vas.c b/drivers/misc/vas/vas.c
-index 785e7a1..448d7f9 100644
---- a/drivers/misc/vas/vas.c
-+++ b/drivers/misc/vas/vas.c
-@@ -12,15 +12,29 @@
- #include <linux/export.h>
- #include <linux/types.h>
- #include <linux/slab.h>
-+#include <linux/kthread.h>
- #include <linux/io.h>
- #include <asm/vas.h>
- #include "vas-internal.h"
- #include <asm/opal-api.h>
- #include <asm/opal.h>
-
-+#define VAS_FAULT_WIN_FIFO_SIZE (64 << 10)
-+#define VAS_FAULT_WIN_WCREDS 64
-+
- int vas_initialized;
- struct vas_instance *vas_instances;
-
-+struct fault_win_thread_arg {
-+ int notified;
-+ wait_queue_head_t wq;
-+ void *rx_fifo;
-+ int rx_fifo_size;
-+} fwta;
-+
-+struct task_struct *fwt_thr; /* Fault window thread */
-+struct vas_window *fault_win;
-+
- /*
- * Read the Fault Isolation Registers (FIR) from skiboot into @fir.
- */
-@@ -56,6 +70,135 @@ void vas_print_regs(int chip)
- }
+ * Compute the paste address region for the window @window using the
+@@ -997,6 +998,52 @@ struct vas_window *vas_tx_win_open(int vasid, enum vas_cop_type cop,
}
-
-+void vas_wakeup_fault_win_thread(void)
-+{
-+ fwta.notified = 1;
-+ wake_up(&fwta.wq);
-+}
-+
-+/*
-+ * Process a CRB that we receive on the fault window.
-+ *
-+ * TODO: Since we only support in-kernel compression requests for now,
-+ * we should not get a fault. If we do, dump the CRB and the FIR
-+ * and return - VAS may enter a checkstop :-(
-+ */
-+static void process_fault_crb(struct fault_win_thread_arg *fwt)
-+{
-+ u64 buf[16];
-+
-+ /* TODO: Dump FIRs for all chips for now. We should detect the
-+ * current chip id and dump only for that chip?
+ EXPORT_SYMBOL_GPL(vas_tx_win_open);
+
++int vas_copy_crb(void *crb, int offset)
++{
++ return vas_copy(crb, offset);
++}
++EXPORT_SYMBOL_GPL(vas_copy_crb);
++
++#define RMA_LSMP_REPORT_ENABLE PPC_BIT(53)
++int vas_paste_crb(struct vas_window *txwin, int offset, bool re)
++{
++ int rc;
++ void *addr;
++ uint64_t val;
++
++ /*
++ * Only NX windows are supported for now and hardware assumes
++ * report-enable flag is set for NX windows. Ensure software
++ * complies too.
+ */
-+ vas_print_regs(-1);
-+
-+ memcpy(buf, fwt->rx_fifo, sizeof(buf));
-+ memset(fwt->rx_fifo, 0, sizeof(buf));
-+ pr_debug("VAS: FaultWin Rx-fifo: 0x%llx 0x%llx 0x%llx 0x%llx\n",
-+ buf[0], buf[1], buf[2], buf[3]);
-+}
-+
-+static int fault_win_thread(void *arg)
-+{
-+ struct fault_win_thread_arg *fwta = arg;
-+
-+ do {
-+ if (signal_pending(current))
-+ flush_signals(current);
-+
-+ fwta->notified = 0;
-+ wait_event_interruptible(fwta->wq, fwta->notified ||
-+ kthread_should_stop());
-+
-+ process_fault_crb(fwta);
-+
-+ } while (!kthread_should_stop());
-+
-+ return 0;
-+}
-+
-+static int create_fault_win(void)
-+{
-+ char *name = "VAS-FaultWin-Thread";
-+ struct vas_rx_win_attr attr;
-+
-+ init_waitqueue_head(&fwta.wq);
-+ fwta.notified = 0;
-+ fwta.rx_fifo_size = VAS_FAULT_WIN_FIFO_SIZE;
-+ fwta.rx_fifo = kmalloc(fwta.rx_fifo_size, GFP_KERNEL);
-+ if (!fwta.rx_fifo) {
-+ pr_err("VAS: Unable to alloc %d bytes for rx_fifo\n",
-+ fwta.rx_fifo_size);
-+ return -1;
++ WARN_ON_ONCE(txwin->nx_win && !re);
++
++ addr = txwin->paste_kaddr;
++ if (re) {
++ /*
++ * Set the REPORT_ENABLE bit (equivalent to writing
++ * to 1K offset of the paste address)
++ */
++ val = SET_FIELD(RMA_LSMP_REPORT_ENABLE, 0ULL, 1);
++ addr += val;
+ }
+
+ /*
-+ * Create a worker thread that processes the fault CRBs.
++ * Map the raw CR value from vas_paste() to an error code (there
++ * is just pass or fail for now though).
+ */
-+ fwt_thr = kthread_create_on_node(fault_win_thread, &fwta, 0, name, 0);
-+ if (IS_ERR(fwt_thr))
-+ goto free_mem;
-+
-+ memset(&attr, 0, sizeof(attr));
-+ attr.rx_fifo_size = fwta.rx_fifo_size;
-+ attr.rx_fifo = fwta.rx_fifo;
-+
-+ attr.wcreds_max = VAS_FAULT_WIN_WCREDS;
-+ attr.tc_mode = VAS_THRESH_DISABLED;
-+ attr.pin_win = true;
-+ attr.tx_win_ord_mode = true;
-+ attr.rx_win_ord_mode = true;
-+ attr.fault_win = true;
-+
-+ /*
-+ * 3.1.4.32: Local Notification Control Register. notify_disable is
-+ * true and interrupt disable is false for Fault windows
-+ */
-+ attr.notify_disable = true;
-+
-+ attr.lnotify_lpid = 0;
-+ attr.lnotify_pid = task_pid_nr(fwt_thr);
-+ attr.lnotify_tid = task_pid_nr(fwt_thr);
-+
-+ fault_win = vas_rx_win_open(0, 0, VAS_COP_TYPE_FAULT, &attr);
-+ if (IS_ERR(fault_win)) {
-+ pr_err("VAS: Error %ld opening fault window\n",
-+ PTR_ERR(fault_win));
-+ goto stop_thread;
-+ }
-+
-+ /*
-+ * Wakeup fault thread after fault rx window is opened.
-+ */
-+ wake_up_process(fwt_thr);
-+
-+ pr_err("VAS: Created fault window, %d, LPID/PID/TID [%d/%d/%d]\n",
-+ fault_win->winid, attr.lnotify_lpid, attr.lnotify_pid,
-+ attr.lnotify_tid);
-+
-+ return 0;
-+
-+stop_thread:
-+ kthread_stop(fwt_thr);
-+
-+free_mem:
-+ kfree(attr.rx_fifo);
-+ return -1;
-+}
-+
-+static void destroy_fault_win(void)
-+{
-+ if (vas_win_close(fault_win) < 0)
-+ pr_err("VAS: error closing fault window\n");
-+
-+ /*
-+ * TODO: fault_win_thread() does not exit unless stopped
-+ * but check if there can be any race here.
-+ */
-+ kthread_stop(fwt_thr);
-+ kfree(fwta.rx_fifo);
-+ pr_err("VAS: Fault thread stopped\n");
-+}
-
- static void init_vas_chip(struct vas_instance *vinst)
++ rc = vas_paste(addr, offset);
++ if (rc == 2)
++ rc = 0;
++ else
++ rc = -EINVAL;
++
++ print_fifo_msg_count(txwin);
++
++ return rc;
++}
++EXPORT_SYMBOL_GPL(vas_paste_crb);
++
+ static void poll_window_busy_state(struct vas_window *window)
{
-@@ -93,7 +236,7 @@ static void init_vas_instance(int node, int chip)
-
- int vas_init(void)
+ int busy;
+diff --git a/arch/powerpc/platforms/powernv/vas.h b/arch/powerpc/platforms/powernv/vas.h
+index d3e4f55..38dee5d 100644
+--- a/arch/powerpc/platforms/powernv/vas.h
++++ b/arch/powerpc/platforms/powernv/vas.h
+@@ -398,11 +398,11 @@ extern struct vas_instance *find_vas_instance(int vasid);
+ #ifdef vas_debug
+ static inline void dump_rx_win_attr(struct vas_rx_win_attr *attr)
{
-- int n, c;
-+ int n, c, rc;
-
- vas_instances = kmalloc_array(VAS_MAX_NODES * VAS_MAX_CHIPS_PER_NODE,
- sizeof(struct vas_instance), GFP_KERNEL);
-@@ -110,12 +253,24 @@ int vas_init(void)
-
- vas_initialized = 1;
-
-+ /*
-+ * Create fault handler thread and window.
-+ */
-+ rc = create_fault_win();
-+ if (rc < 0)
-+ goto cleanup;
-+
- return 0;
-+
-+cleanup:
-+ kfree(vas_instances);
-+ return rc;
+- pr_err("VAS: fault %d, notify %d, intr %d early %d\n",
++ pr_err("fault %d, notify %d, intr %d early %d\n",
+ attr->fault_win, attr->notify_disable,
+ attr->intr_disable, attr->notify_early);
+
+- pr_err("VAS: rx_fifo_size %d, max value %d\n",
++ pr_err("rx_fifo_size %d, max value %d\n",
+ attr->rx_fifo_size, VAS_RX_FIFO_SIZE_MAX);
}
- void vas_exit(void)
- {
- vas_initialized = 0;
-+ destroy_fault_win();
- kfree(vas_instances);
+@@ -450,4 +450,18 @@ static inline u64 read_hvwc_reg(struct vas_window *win,
+ return in_be64(win->hvwc_map+reg);
}
++#ifdef vas_debug
++
++static void print_fifo_msg_count(struct vas_window *txwin)
++{
++ uint64_t read_hvwc_reg(struct vas_window *w, char *n, uint64_t o);
++ pr_devel("Winid %d, Msg count %llu\n", txwin->winid,
++ (uint64_t)read_hvwc_reg(txwin, VREG(LRFIFO_PUSH)));
++}
++#else /* vas_debug */
++
++#define print_fifo_msg_count(window)
++
++#endif /* vas_debug */
++
+ #endif /* _VAS_H */
--
-1.8.3.1
+2.7.4