* [RFC PATCH 01/11] VAS: Define macros and register fields
2016-11-11 17:02 [RFC PATCH 00/11] Enable VAS Sukadev Bhattiprolu
@ 2016-11-11 17:02 ` Sukadev Bhattiprolu
2016-11-11 17:02 ` [RFC PATCH 02/11] VAS: Define vas_dev_init() and vas_dev_exit() Sukadev Bhattiprolu
` (9 subsequent siblings)
10 siblings, 0 replies; 12+ messages in thread
From: Sukadev Bhattiprolu @ 2016-11-11 17:02 UTC (permalink / raw)
To: Michael Ellerman
Cc: Benjamin Herrenschmidt, michael.neuling, stewart, hbabu,
linuxppc-dev
Define macros for the VAS hardware registers and bit-fields as well
as couple of data structures needed by the VAS driver.
Signed-off-by: Sukadev Bhattiprolu <sukadev@linux.vnet.ibm.com>
---
MAINTAINERS | 6 +
arch/powerpc/include/asm/vas.h | 40 +++++
drivers/misc/vas/vas-internal.h | 365 ++++++++++++++++++++++++++++++++++++++++
3 files changed, 411 insertions(+)
create mode 100644 arch/powerpc/include/asm/vas.h
create mode 100644 drivers/misc/vas/vas-internal.h
diff --git a/MAINTAINERS b/MAINTAINERS
index 644ff65..3ef8d4d 100644
--- a/MAINTAINERS
+++ b/MAINTAINERS
@@ -12410,6 +12410,12 @@ S: Maintained
F: Documentation/fb/uvesafb.txt
F: drivers/video/fbdev/uvesafb.*
+VAS (IBM Virtual Accelerator Switchboard) DRIVER
+M: Sukadev Bhattiprolu <sukadev@linux.vnet.ibm.com>
+L: linuxppc-dev@lists.ozlabs.org
+S: Supported
+F: drivers/misc/vas/*
+
VF610 NAND DRIVER
M: Stefan Agner <stefan@agner.ch>
L: linux-mtd@lists.infradead.org
diff --git a/arch/powerpc/include/asm/vas.h b/arch/powerpc/include/asm/vas.h
new file mode 100644
index 0000000..1c10437
--- /dev/null
+++ b/arch/powerpc/include/asm/vas.h
@@ -0,0 +1,40 @@
+/*
+ * Copyright 2016 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.
+ */
+
+#ifndef VAS_H
+#define VAS_H
+
+#define VAS_RX_FIFO_SIZE_MAX (8 << 20) /* 8MB */
+/*
+ * Co-processor Engine type.
+ */
+enum vas_cop_type {
+ VAS_COP_TYPE_FAULT,
+ VAS_COP_TYPE_842,
+ VAS_COP_TYPE_842_HIPRI,
+ VAS_COP_TYPE_GZIP,
+ VAS_COP_TYPE_GZIP_HIPRI,
+ VAS_COP_TYPE_MAX,
+};
+
+/*
+ * Threshold Control Mode: Have paste operation fail if the number of
+ * requests in receive FIFO exceeds a threshold.
+ *
+ * NOTE: No special error code yet if paste is rejected because of these
+ * limits. So users can't distinguish between this and other errors.
+ */
+enum vas_thresh_ctl {
+ VAS_THRESH_DISABLED,
+ VAS_THRESH_FIFO_GT_HALF_FULL,
+ VAS_THRESH_FIFO_GT_QTR_FULL,
+ VAS_THRESH_FIFO_GT_EIGHTH_FULL,
+};
+
+#endif
diff --git a/drivers/misc/vas/vas-internal.h b/drivers/misc/vas/vas-internal.h
new file mode 100644
index 0000000..f91fd66
--- /dev/null
+++ b/drivers/misc/vas/vas-internal.h
@@ -0,0 +1,365 @@
+/*
+ * Copyright 2016 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.
+ */
+
+#ifndef VAS_INTERNAL_H
+#define VAS_INTERNAL_H
+#include <linux/atomic.h>
+#include <linux/idr.h>
+#include <asm/vas.h>
+
+/*
+ * HVWC and UWC BAR.
+ *
+ * A Power node can have (upto?) 8 Power chips.
+ *
+ * There is one instance of VAS in each Power chip. Each instance of VAS
+ * has 64K windows, which can be used to send/receive messages from
+ * software threads and coprocessors.
+ *
+ * Each window is described by two types of window contexts:
+ *
+ * Hypervisor Window Context (HVWC) of size VAS_HVWC_SIZE bytes
+ * OS/User Window Context (UWC) of size VAS_UWC_SIZE bytes.
+ *
+ * A window context can be viewed as a set of 64-bit registers. The settings
+ * of these registers control/determine the behavior of the VAS hardware
+ * when messages are sent/received through the window.
+ *
+ * Each Power chip i.e each instance of VAS, is assigned two distinct ranges
+ * (one for each type of context) of Power-bus addresses (aka Base Address
+ * Region or BAR) which can be used to access the window contexts in that
+ * instance of VAS.
+ *
+ * From the Power9 MMIO Ranges Spreadsheet:
+ *
+ * The HVWC BAR is of size 0x40000000000 and for chip 0, the HVWC BAR begins
+ * at 0x6019000000000ULL, for chip 1 at 0x0006059000000000 etc.
+ *
+ * i.e the HVWC for each of the 64K windows on chip 0 can be accessed at the
+ * address 0x6019000000000ULL, and HVWC for the 64K windows on chip 1 can be
+ * accessed at the address 0x0006059000000000 and so on.
+ *
+ * Similarly, the UWC BAR is also of size 0x40000000000 and for chip 0,
+ * begins at 0x0006019100000000, for chip 1 at 0x0006059100000000 etc.
+ *
+ * Following macros describe the HVWC and UWC BARs for chip 0. The BARs for
+ * the other chips are computed in get_hvwc_mmio_bar() / get_uwc_mmio_bar().
+ */
+#define VAS_HVWC_MMIO_BAR_BASE 0x0006019100000000ULL
+#define VAS_HVWC_MMIO_BAR_SIZE 0x40000000000
+
+#define VAS_UWC_MMIO_BAR_BASE 0x0006019000000000ULL
+#define VAS_UWC_MMIO_BAR_SIZE 0x40000000000
+
+/*
+ * Hypervisor and OS/USer Window Context sizes
+ */
+#define VAS_HVWC_SIZE 512
+#define VAS_UWC_SIZE PAGE_SIZE
+
+/*
+ * TODO: Get nodes and chip info from device tree.
+ */
+#define VAS_MAX_NODES 1
+#define VAS_MAX_CHIPS_PER_NODE 1
+
+/* Initial per-process credits. We may need to tweak these later */
+#define VAS_WCREDS_MIN 16
+#define VAS_WCREDS_MAX 64
+#define VAS_WCREDS_DEFAULT 64
+
+/*
+ * TODO:
+ * - Hardcoded for Power9 but should get from device tree (must
+ * sync with Skiboot!)
+ * - Increase number of windows to 64K after initial development
+ */
+#define VAS_MAX_WINDOWS_PER_CHIP 64
+
+#ifdef CONFIG_PPC_4K_PAGES
+# error "TODO: Compute RMA/Paste-address for 4K pages."
+#else
+#ifndef CONFIG_PPC_64K_PAGES
+# error "Unexpected Page size."
+#endif
+#endif
+
+/*
+ * TODO: Copied from nx-842.h. Move to a common header
+ */
+/* Get/Set bit fields */
+#define MASK_LSH(m) (__builtin_ffsl(m) - 1)
+
+/* Sigh. nx-842 and skiboot have the parameters in opposite order */
+#define GET_FIELD(m, v) (((v) & (m)) >> MASK_LSH(m))
+#define SET_FIELD(m, v, val) \
+ (((v) & ~(m)) | ((((typeof(v))(val)) << MASK_LSH(m)) & (m)))
+
+/*
+ * VAS Window Context Register Offsets and bitmasks.
+ * See Section 3.1.4 of VAS Work book
+ */
+#define VAS_LPID_OFFSET 0x010
+#define VAS_LPID PPC_BITMASK(0, 11)
+
+#define VAS_PID_OFFSET 0x018
+#define VAS_PID_ID PPC_BITMASK(0, 19)
+
+#define VAS_XLATE_MSR_OFFSET 0x020
+#define VAS_XLATE_MSR_DR PPC_BIT(0)
+#define VAS_XLATE_MSR_TA PPC_BIT(1)
+#define VAS_XLATE_MSR_PR PPC_BIT(2)
+#define VAS_XLATE_MSR_US PPC_BIT(3)
+#define VAS_XLATE_MSR_HV PPC_BIT(4)
+#define VAS_XLATE_MSR_SF PPC_BIT(5)
+#define VAS_XLATE_MSR_UV PPC_BIT(6)
+
+#define VAS_XLATE_LPCR_OFFSET 0x028
+#define VAS_XLATE_LPCR_PAGE_SIZE PPC_BITMASK(0, 2)
+#define VAS_XLATE_LPCR_ISL PPC_BIT(3)
+#define VAS_XLATE_LPCR_TC PPC_BIT(4)
+#define VAS_XLATE_LPCR_SC PPC_BIT(5)
+
+#define VAS_XLATE_CTL_OFFSET 0x030
+#define VAS_XLATE_MODE PPC_BITMASK(0, 1)
+
+#define VAS_AMR_OFFSET 0x040
+#define VAS_AMR PPC_BITMASK(0, 63)
+
+#define VAS_SEIDR_OFFSET 0x048
+#define VAS_SEIDR PPC_BITMASK(0, 63)
+
+#define VAS_FAULT_TX_WIN_OFFSET 0x050
+#define VAS_FAULT_TX_WIN PPC_BITMASK(48, 63)
+
+#define VAS_OSU_INTR_SRC_RA_OFFSET 0x060
+#define VAS_OSU_INTR_SRC_RA PPC_BITMASK(8, 63)
+
+#define VAS_HV_INTR_SRC_RA_OFFSET 0x070
+#define VAS_HV_INTR_SRC_RA PPC_BITMASK(8, 63)
+
+#define VAS_PSWID_OFFSET 0x078
+#define VAS_PSWID_EA_HANDLE PPC_BITMASK(0, 31)
+
+#define VAS_SPARE1_OFFSET 0x080
+#define VAS_SPARE2_OFFSET 0x088
+#define VAS_SPARE3_OFFSET 0x090
+#define VAS_SPARE4_OFFSET 0x130
+#define VAS_SPARE5_OFFSET 0x160
+#define VAS_SPARE6_OFFSET 0x188
+
+#define VAS_LFIFO_BAR_OFFSET 0x0A0
+#define VAS_LFIFO_BAR PPC_BITMASK(8, 53)
+#define VAS_PAGE_MIGRATION_SELECT PPC_BITMASK(54, 56)
+
+#define VAS_LDATA_STAMP_CTL_OFFSET 0x0A8
+#define VAS_LDATA_STAMP PPC_BITMASK(0, 1)
+#define VAS_XTRA_WRITE PPC_BIT(2)
+
+#define VAS_LDMA_CACHE_CTL_OFFSET 0x0B0
+#define VAS_LDMA_TYPE PPC_BITMASK(0, 1)
+
+#define VAS_LRFIFO_PUSH_OFFSET 0x0B8
+#define VAS_LRFIFO_PUSH PPC_BITMASK(0, 15)
+
+#define VAS_CURR_MSG_COUNT_OFFSET 0x0C0
+#define VAS_CURR_MSG_COUNT PPC_BITMASK(0, 7)
+
+#define VAS_LNOTIFY_AFTER_COUNT_OFFSET 0x0C8
+#define VAS_LNOTIFY_AFTER_COUNT PPC_BITMASK(0, 7)
+
+#define VAS_LRX_WCRED_OFFSET 0x0E0
+#define VAS_LRX_WCRED PPC_BITMASK(0, 15)
+
+#define VAS_LRX_WCRED_ADDER_OFFSET 0x190
+#define VAS_LRX_WCRED_ADDER PPC_BITMASK(0, 15)
+
+#define VAS_TX_WCRED_OFFSET 0x0F0
+#define VAS_TX_WCRED PPC_BITMASK(4, 15)
+
+#define VAS_TX_WCRED_ADDER_OFFSET 0x1A0
+#define VAS_TX_WCRED_ADDER PPC_BITMASK(4, 15)
+
+#define VAS_LFIFO_SIZE_OFFSET 0x100
+#define VAS_LFIFO_SIZE PPC_BITMASK(0, 3)
+
+#define VAS_WINCTL_OFFSET 0x108
+#define VAS_WINCTL_OPEN PPC_BIT(0)
+#define VAS_WINCTL_REJ_NO_CREDIT PPC_BIT(1)
+#define VAS_WINCTL_PIN PPC_BIT(2)
+#define VAS_WINCTL_TX_WCRED_MODE PPC_BIT(3)
+#define VAS_WINCTL_RX_WCRED_MODE PPC_BIT(4)
+#define VAS_WINCTL_TXWIN_ORD_MODE PPC_BIT(5)
+#define VAS_WINCTL_RXWIN_ORD_MODE PPC_BIT(6)
+#define VAS_WINCTL_RSVD_TXBUF PPC_BIT(7)
+#define VAS_WINCTL_THRESH_CTL PPC_BITMASK(8, 9)
+#define VAS_WINCTL_FAULT_WIN PPC_BIT(10)
+#define VAS_WINCTL_NX_WIN PPC_BIT(11)
+
+#define VAS_WIN_STATUS_OFFSET 0x110
+#define VAS_WIN_BUSY PPC_BIT(1)
+
+#define VAS_WIN_CTX_CACHING_CTL_OFFSET 0x118
+#define VAS_CASTOUT_REQ PPC_BIT(0)
+#define VAS_PUSH_TO_MEM PPC_BIT(1)
+#define VAS_WIN_CACHE_STATUS PPC_BIT(4)
+
+#define VAS_TX_RSVD_BUF_COUNT_OFFSET 0x120
+#define VAS_RXVD_BUF_COUNT PPC_BITMASK(58, 63)
+
+#define VAS_LRFIFO_WIN_PTR_OFFSET 0x128
+#define VAS_LRX_WIN_ID PPC_BITMASK(0, 15)
+
+/*
+ * Local Notification Control Register controls what happens in _response_
+ * to a paste command and hence applies only to receive windows.
+ */
+#define VAS_LNOTIFY_CTL_OFFSET 0x138
+#define VAS_NOTIFY_DISABLE PPC_BIT(0)
+#define VAS_INTR_DISABLE PPC_BIT(1)
+#define VAS_NOTIFY_EARLY PPC_BIT(2)
+#define VAS_NOTIFY_OSU_INTR PPC_BIT(3)
+
+#define VAS_LNOTIFY_PID_OFFSET 0x140
+#define VAS_LNOTIFY_PID PPC_BITMASK(0, 19)
+
+#define VAS_LNOTIFY_LPID_OFFSET 0x148
+#define VAS_LNOTIFY_LPID PPC_BITMASK(0, 11)
+
+#define VAS_LNOTIFY_TID_OFFSET 0x150
+#define VAS_LNOTIFY_TID PPC_BITMASK(0, 15)
+
+#define VAS_LNOTIFY_SCOPE_OFFSET 0x158
+#define VAS_LNOTIFY_MIN_SCOPE PPC_BITMASK(0, 1)
+#define VAS_LNOTIFY_MAX_SCOPE PPC_BITMASK(2, 3)
+
+#define VAS_NX_UTIL_OFFSET 0x1B0
+#define VAS_NX_UTIL PPC_BITMASK(0, 63)
+
+/* SE: Side effects */
+#define VAS_NX_UTIL_SE_OFFSET 0x1B8
+#define VAS_NX_UTIL_SE PPC_BITMASK(0, 63)
+
+#define VAS_NX_UTIL_ADDER_OFFSET 0x180
+#define VAS_NX_UTIL_ADDER PPC_BITMASK(32, 63)
+
+/*
+ * Local Notify Scope Control Register. (Receive windows only).
+ */
+enum vas_notify_scope {
+ VAS_SCOPE_LOCAL,
+ VAS_SCOPE_GROUP,
+ VAS_SCOPE_VECTORED_GROUP,
+ VAS_SCOPE_UNUSED,
+};
+
+/*
+ * Local DMA Cache Control Register (Receive windows only).
+ */
+enum vas_dma_type {
+ VAS_DMA_TYPE_INJECT,
+ VAS_DMA_TYPE_WRITE,
+};
+
+/*
+ * Local Notify Scope Control Register. (Receive windows only).
+ * Not applicable to NX receive windows.
+ */
+enum vas_notify_after_count {
+ VAS_NOTIFY_AFTER_256 = 0,
+ VAS_NOTIFY_NONE,
+ VAS_NOTIFY_AFTER_2
+};
+
+/*
+ * One per instance of VAS (i.e one per chip).
+ * Each instance will have a separate set of receive windows, one per
+ * coprocessor type.
+ */
+struct vas_instance {
+ int node;
+ int chip;
+ struct ida ida;
+ struct mutex mutex;
+ struct vas_window *rxwin[VAS_COP_TYPE_MAX];
+};
+
+/*
+ * In-kernel data structure for a VAS window. One per window.
+ */
+struct vas_window {
+ /* Fields common to Send and receive windows */
+ struct vas_instance *vinst;
+ int winid;
+ bool txwin; /* True if send window */
+ bool nx_win; /* True if NX window */
+ void *hvwc_map; /* HV window context */
+ void *uwc_map; /* OS/User window context */
+
+ /* Fields applicable only to send windows */
+ void *paste_kaddr;
+ char *paste_addr_name;
+ struct vas_window *rxwin;
+
+ /* Feilds applicable only to receive windows */
+ enum vas_cop_type cop;
+ atomic_t num_txwins;
+
+ int32_t hwirq;
+ uint64_t irq_port;
+};
+
+/*
+ * A VAS Window context is a 512-byte area in the hardware that contains
+ * a set of 64-bit registers. Individual bit-fields in these registers
+ * determine the configuration/operation of the hardware. struct vas_winctx
+ * is a container for the register fields in the window context.
+ * One per window.
+ */
+struct vas_winctx {
+ void *rx_fifo;
+ int rx_fifo_size;
+ int wcreds_max;
+ int rsvd_txbuf_count;
+
+ bool user_win;
+ bool nx_win;
+ bool fault_win;
+ bool rsvd_txbuf_enable;
+ bool pin_win;
+ bool rej_no_credit;
+ bool tx_wcred_mode;
+ bool rx_wcred_mode;
+ bool tx_win_ord_mode;
+ bool rx_win_ord_mode;
+ bool data_stamp;
+ bool xtra_write;
+ bool notify_disable;
+ bool intr_disable;
+ bool notify_early;
+ bool notify_os_intr_reg;
+
+ int lpid;
+ int pid;
+ int lnotify_lpid;
+ int lnotify_pid;
+ int lnotify_tid;
+ int pswid;
+ int rx_win_id;
+ int fault_win_id;
+ uint64_t irq_port;
+
+ enum vas_dma_type dma_type;
+ enum vas_thresh_ctl tc_mode;
+ enum vas_notify_scope min_scope;
+ enum vas_notify_scope max_scope;
+ enum vas_notify_after_count notify_after_count;
+};
+
+#endif
--
1.8.3.1
^ permalink raw reply related [flat|nested] 12+ messages in thread
* [RFC PATCH 02/11] VAS: Define vas_dev_init() and vas_dev_exit()
2016-11-11 17:02 [RFC PATCH 00/11] Enable VAS Sukadev Bhattiprolu
2016-11-11 17:02 ` [RFC PATCH 01/11] VAS: Define macros and register fields Sukadev Bhattiprolu
@ 2016-11-11 17:02 ` Sukadev Bhattiprolu
2016-11-11 17:02 ` [RFC PATCH 03/11] VAS: Define helpers for access MMIO regions Sukadev Bhattiprolu
` (8 subsequent siblings)
10 siblings, 0 replies; 12+ messages in thread
From: Sukadev Bhattiprolu @ 2016-11-11 17:02 UTC (permalink / raw)
To: Michael Ellerman
Cc: Benjamin Herrenschmidt, michael.neuling, stewart, hbabu,
linuxppc-dev
Define functions to initialize/terminate the VAS device driver.
These functions will configure the hardware in a follow on patch.
Signed-off-by: Sukadev Bhattiprolu <sukadev@linux.vnet.ibm.com>
---
drivers/misc/Kconfig | 1 +
drivers/misc/Makefile | 1 +
drivers/misc/vas/Kconfig | 19 +++++++
drivers/misc/vas/Makefile | 3 ++
drivers/misc/vas/vas-internal.h | 5 ++
drivers/misc/vas/vas-window.c | 19 +++++++
drivers/misc/vas/vas.c | 113 ++++++++++++++++++++++++++++++++++++++++
7 files changed, 161 insertions(+)
create mode 100644 drivers/misc/vas/Kconfig
create mode 100644 drivers/misc/vas/Makefile
create mode 100644 drivers/misc/vas/vas-window.c
create mode 100644 drivers/misc/vas/vas.c
diff --git a/drivers/misc/Kconfig b/drivers/misc/Kconfig
index d002528..d9a8cf0 100644
--- a/drivers/misc/Kconfig
+++ b/drivers/misc/Kconfig
@@ -806,4 +806,5 @@ source "drivers/misc/mic/Kconfig"
source "drivers/misc/genwqe/Kconfig"
source "drivers/misc/echo/Kconfig"
source "drivers/misc/cxl/Kconfig"
+source "drivers/misc/vas/Kconfig"
endmenu
diff --git a/drivers/misc/Makefile b/drivers/misc/Makefile
index fb32516..aa5947b 100644
--- a/drivers/misc/Makefile
+++ b/drivers/misc/Makefile
@@ -55,6 +55,7 @@ obj-$(CONFIG_GENWQE) += genwqe/
obj-$(CONFIG_ECHO) += echo/
obj-$(CONFIG_VEXPRESS_SYSCFG) += vexpress-syscfg.o
obj-$(CONFIG_CXL_BASE) += cxl/
+obj-$(CONFIG_VAS) += vas/
obj-$(CONFIG_PANEL) += panel.o
lkdtm-$(CONFIG_LKDTM) += lkdtm_core.o
diff --git a/drivers/misc/vas/Kconfig b/drivers/misc/vas/Kconfig
new file mode 100644
index 0000000..f02b887
--- /dev/null
+++ b/drivers/misc/vas/Kconfig
@@ -0,0 +1,19 @@
+#
+# IBM Virtual Accelarator Switchboard (VAS) compatible devices
+#depends on PPC_POWERNV && PCI_MSI && EEH
+#
+
+config VAS
+ tristate "Support for IBM Virtual Accelerator Switchboard (VAS)"
+ default n
+ help
+ Select this option to enable driver support for IBM Virtual
+ Accelerator Switchboard (VAS).
+ VAS allows accelerators in co processors like NX-842 to be
+ directly available to a user process. This driver enables
+ userspace programs to access these accelerators via
+ /dev/vas/vas-nxM.N devices.
+
+ VAS adapters are found in POWER9 based systems.
+
+ If unsure, say N.
diff --git a/drivers/misc/vas/Makefile b/drivers/misc/vas/Makefile
new file mode 100644
index 0000000..7dd7139
--- /dev/null
+++ b/drivers/misc/vas/Makefile
@@ -0,0 +1,3 @@
+ccflags-y := $(call cc-disable-warning, unused-const-variable)
+ccflags-$(CONFIG_PPC_WERROR) += -Werror
+obj-$(CONFIG_VAS) += vas.o vas-window.o
diff --git a/drivers/misc/vas/vas-internal.h b/drivers/misc/vas/vas-internal.h
index f91fd66..282513b 100644
--- a/drivers/misc/vas/vas-internal.h
+++ b/drivers/misc/vas/vas-internal.h
@@ -362,4 +362,9 @@ struct vas_winctx {
enum vas_notify_after_count notify_after_count;
};
+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);
+
#endif
diff --git a/drivers/misc/vas/vas-window.c b/drivers/misc/vas/vas-window.c
new file mode 100644
index 0000000..468f3bf
--- /dev/null
+++ b/drivers/misc/vas/vas-window.c
@@ -0,0 +1,19 @@
+/*
+ * Copyright 2016 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 <linux/types.h>
+#include <linux/mutex.h>
+#include <asm/vas.h>
+#include "vas-internal.h"
+
+/* stub for now */
+int vas_window_reset(struct vas_instance *vinst, int winid)
+{
+ return 0;
+}
diff --git a/drivers/misc/vas/vas.c b/drivers/misc/vas/vas.c
new file mode 100644
index 0000000..51f9c70
--- /dev/null
+++ b/drivers/misc/vas/vas.c
@@ -0,0 +1,113 @@
+/*
+ * Copyright 2016 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 <linux/module.h>
+#include <linux/kernel.h>
+#include <linux/export.h>
+#include <linux/types.h>
+#include <linux/slab.h>
+#include <linux/io.h>
+#include <asm/vas.h>
+#include "vas-internal.h"
+
+int vas_initialized;
+struct vas_instance *vas_instances;
+
+static void init_vas_chip(struct vas_instance *vinst)
+{
+ int i;
+
+ for (i = 0; i < VAS_MAX_WINDOWS_PER_CHIP; i++)
+ vas_window_reset(vinst, i);
+}
+
+/*
+ * Although this is read/used multiple times, it is written to only
+ * during initialization.
+ */
+struct vas_instance *find_vas_instance(int node, int chip)
+{
+ int i = node * VAS_MAX_CHIPS_PER_NODE + chip;
+
+ return &vas_instances[i];
+}
+
+static void init_vas_instance(int node, int chip)
+{
+ struct vas_instance *vinst;
+
+ vinst = find_vas_instance(node, chip);
+
+ ida_init(&vinst->ida);
+
+ vinst->node = node;
+ vinst->chip = chip;
+ mutex_init(&vinst->mutex);
+
+ init_vas_chip(vinst);
+}
+
+int vas_init(void)
+{
+ int n, c;
+
+ vas_instances = kmalloc_array(VAS_MAX_NODES * VAS_MAX_CHIPS_PER_NODE,
+ sizeof(struct vas_instance), GFP_KERNEL);
+ if (!vas_instances)
+ return -ENOMEM;
+
+ /*
+ * TODO: Get node-id and chip id from device tree?
+ */
+ for (n = 0; n < VAS_MAX_NODES; n++) {
+ for (c = 0; c < VAS_MAX_CHIPS_PER_NODE; c++)
+ init_vas_instance(n, c);
+ }
+
+ vas_initialized = 1;
+
+ return 0;
+}
+
+void vas_exit(void)
+{
+ vas_initialized = 0;
+ kfree(vas_instances);
+}
+
+/*
+ * We will have a device driver for user space access to VAS.
+ * But for now this is just a wrapper to vas_init()
+ */
+int __init vas_dev_init(void)
+{
+ int rc;
+
+ rc = vas_init();
+ if (rc)
+ return rc;
+
+ vas_initialized = 1;
+
+ pr_err("VAS: initialized\n");
+
+ return 0;
+}
+
+void __init vas_dev_exit(void)
+{
+ pr_err("VAS: exiting\n");
+ vas_exit();
+}
+
+module_init(vas_dev_init);
+module_exit(vas_dev_exit);
+MODULE_DESCRIPTION("IBM Virtual Accelerator Switchboard");
+MODULE_AUTHOR("Sukadev Bhattiprolu <sukadev@linux.vnet.ibm.com>");
+MODULE_LICENSE("GPL");
--
1.8.3.1
^ permalink raw reply related [flat|nested] 12+ messages in thread
* [RFC PATCH 03/11] VAS: Define helpers for access MMIO regions
2016-11-11 17:02 [RFC PATCH 00/11] Enable VAS Sukadev Bhattiprolu
2016-11-11 17:02 ` [RFC PATCH 01/11] VAS: Define macros and register fields Sukadev Bhattiprolu
2016-11-11 17:02 ` [RFC PATCH 02/11] VAS: Define vas_dev_init() and vas_dev_exit() Sukadev Bhattiprolu
@ 2016-11-11 17:02 ` Sukadev Bhattiprolu
2016-11-11 17:02 ` [RFC PATCH 04/11] VAS: Define helpers to init window context Sukadev Bhattiprolu
` (7 subsequent siblings)
10 siblings, 0 replies; 12+ messages in thread
From: Sukadev Bhattiprolu @ 2016-11-11 17:02 UTC (permalink / raw)
To: Michael Ellerman
Cc: Benjamin Herrenschmidt, michael.neuling, stewart, hbabu,
linuxppc-dev
Define some helper functions to access the MMIO regions. We use these
in a follow-on patches to read/write VAS hardware registers. These
helpers are also used to later issue 'paste' instructions to submit
requests to the NX hardware engines.
Signed-off-by: Sukadev Bhattiprolu <sukadev@linux.vnet.ibm.com>
---
drivers/misc/vas/vas-window.c | 182 ++++++++++++++++++++++++++++++++++++++++++
1 file changed, 182 insertions(+)
diff --git a/drivers/misc/vas/vas-window.c b/drivers/misc/vas/vas-window.c
index 468f3bf..2c220a3 100644
--- a/drivers/misc/vas/vas-window.c
+++ b/drivers/misc/vas/vas-window.c
@@ -9,9 +9,191 @@
#include <linux/types.h>
#include <linux/mutex.h>
+#include <linux/slab.h>
+#include <linux/io.h>
#include <asm/vas.h>
#include "vas-internal.h"
+/*
+ * Using the node, chip and window id for the send winow identified by
+ * @window, compute and return the Power Bus address to which a sender
+ * could issue a paste instruction for this window.
+ *
+ * Refer to Tables 1.1 through 1.4 in Section 1.3.3.1 (Send Message w/Paste
+ * Commands (cl_rma_w)) of VAS P9 Workbook for the PowerBus Address usage
+ * in VAS.
+ *
+ * With 64K mode and Large SMP Mode the bits are used as follows:
+ *
+ * Bits Values Comments
+ * --------------------------------------
+ * 0:7 0b 0000_0000 Reserved
+ * 8:12 0b 0000_1 System id/Foreign Index 0:4
+ * 13:14 0b 00 Foreign Index 5:6
+ *
+ * 15:18 0 throuh 15 Node id (0 through 15)
+ * 19:21 0 through 7 Chip id (0 throuh 7)
+ * 22:23 0b 00 Unused, Foreign index 7:8
+ *
+ * 24:31 0b 0000_0000 RPN 0:7, Reserved
+ * 32:47 0 through 64K Send Window Id
+ * 48:51 0b 0000 Spare
+ *
+ * 52 0b 0 Reserved
+ * 53 0b 1 Report Enable (Set to 1 for NX).
+ * 54 0b 0 Reserved
+ *
+ * 55:56 0b 00 Snoop Bus
+ * 57:63 0b 0000_000 Reserved
+ *
+ * Except for a few bits, the small SMP mode computation is similar.
+ *
+ * TODO: Detect and compute address for small SMP mode.
+ *
+ * Example: For Node 0, Chip 0, Window id 4, Report Enable 1:
+ *
+ * Byte0 Byte1 Byte2 Byte3 Byte4 Byte5 Byte6 Byte7
+ * 00000000 00001000 00000000 00000000 00000000 00000100 00000100 00000000
+ * | | |
+ * +-------+-------+ v
+ * | Report Enable
+ * v
+ * Window id 4
+ *
+ * Thus, the paste address is 0x00080000_00040400.
+ */
+#define RMA_LSMP_64K_SYS_ID PPC_BITMASK(8, 12)
+#define RMA_LSMP_64K_NODE_ID PPC_BITMASK(15, 18)
+#define RMA_LSMP_64K_CHIP_ID PPC_BITMASK(19, 21)
+#define RMA_LSMP_64K_TX_WIN_ID PPC_BITMASK(32, 47)
+#define RMA_LSMP_REPORT_ENABLE PPC_BIT(53)
+
+uint64_t compute_paste_address(struct vas_window *window, int *size)
+{
+ int node, chip, winid;
+ uint64_t val = 0ULL;
+
+ node = window->vinst->node;
+ chip = window->vinst->chip;
+ winid = window->winid;
+
+ *size = PAGE_SIZE;
+
+ val = SET_FIELD(RMA_LSMP_64K_SYS_ID, val, 1);
+ val = SET_FIELD(RMA_LSMP_64K_NODE_ID, val, node);
+ val = SET_FIELD(RMA_LSMP_64K_CHIP_ID, val, chip);
+ val = SET_FIELD(RMA_LSMP_64K_TX_WIN_ID, val, winid);
+ val = SET_FIELD(RMA_LSMP_REPORT_ENABLE, val, 1);
+ pr_debug("%swin #%d: Paste address 0x%llx\n",
+ window->txwin ? "Tx" : "Rx", winid, val);
+ return val;
+}
+
+static void get_hvwc_mmio_bar(struct vas_window *window,
+ uint64_t *start, int *len)
+{
+ uint64_t pbaddr;
+ int instance;
+
+ instance = window->vinst->node * 8 + window->vinst->chip;
+ pbaddr = VAS_HVWC_MMIO_BAR_BASE + instance * VAS_HVWC_MMIO_BAR_SIZE;
+
+ *start = pbaddr + window->winid * VAS_HVWC_SIZE;
+ *len = VAS_HVWC_SIZE;
+}
+
+static void get_uwc_mmio_bar(struct vas_window *window,
+ uint64_t *start, int *len)
+{
+ uint64_t pbaddr;
+ int instance;
+
+ instance = window->vinst->node * 8 + window->vinst->chip;
+ pbaddr = VAS_UWC_MMIO_BAR_BASE + instance * VAS_UWC_MMIO_BAR_SIZE;
+
+ *start = pbaddr + window->winid * VAS_UWC_SIZE;
+ *len = VAS_UWC_SIZE;
+}
+
+static void *map_mmio_region(char *name, uint64_t start, int len)
+{
+ void *map;
+
+ if (!request_mem_region(start, len, name)) {
+ pr_devel("%s(): request_mem_region(0x%llx, %d) failed\n",
+ __func__, start, len);
+ return NULL;
+ }
+
+ map = __ioremap(start, len, pgprot_val(pgprot_cached(__pgprot(0))));
+ if (!map) {
+ pr_devel("%s(): ioremap(0x%llx, %d) failed\n", __func__, start,
+ len);
+ return NULL;
+ }
+
+ return map;
+}
+
+/*
+ * Unmap the MMIO regions for a window.
+ */
+void unmap_wc_mmio_bars(struct vas_window *window)
+{
+ int len;
+ uint64_t busaddr_start;
+
+ if (window->paste_kaddr) {
+ iounmap(window->paste_kaddr);
+ busaddr_start = compute_paste_address(window, &len);
+ pr_debug("Releasing pbaddr region [0x%llx, %d]\n",
+ busaddr_start, len);
+ release_mem_region((phys_addr_t)busaddr_start, len);
+ }
+
+ if (window->hvwc_map) {
+ iounmap(window->hvwc_map);
+ get_hvwc_mmio_bar(window, &busaddr_start, &len);
+ release_mem_region((phys_addr_t)busaddr_start, len);
+ }
+
+ if (window->uwc_map) {
+ iounmap(window->uwc_map);
+ get_uwc_mmio_bar(window, &busaddr_start, &len);
+ release_mem_region((phys_addr_t)busaddr_start, len);
+ }
+}
+
+/*
+ * Find the Hypervisor Window Context (HVWC) MMIO Base Address Region and the
+ * OS/User Window Context (UWC) MMIO Base Address Region for the given window.
+ * Map these bus addresses and save the mapped kernel addresses in @window.
+ */
+int map_wc_mmio_bars(struct vas_window *window)
+{
+ int len;
+ uint64_t start;
+
+ window->hvwc_map = window->uwc_map = NULL;
+
+ get_hvwc_mmio_bar(window, &start, &len);
+ window->hvwc_map = map_mmio_region("HVWCM_Window", start, len);
+
+ pr_debug("Win #%d: Map hvwc 0x%p -> [0x%llx,%d]\n", window->winid,
+ window->hvwc_map, start, len);
+
+ get_uwc_mmio_bar(window, &start, &len);
+ window->uwc_map = map_mmio_region("UWCM_Window", start, len);
+
+ pr_debug("Win #%d: Map uvwc 0x%p -> [0x%llx,%d]\n", window->winid,
+ window->uwc_map, start, len);
+
+ if (!window->hvwc_map || !window->uwc_map)
+ return -1;
+
+ return 0;
+}
+
/* stub for now */
int vas_window_reset(struct vas_instance *vinst, int winid)
{
--
1.8.3.1
^ permalink raw reply related [flat|nested] 12+ messages in thread
* [RFC PATCH 04/11] VAS: Define helpers to init window context
2016-11-11 17:02 [RFC PATCH 00/11] Enable VAS Sukadev Bhattiprolu
` (2 preceding siblings ...)
2016-11-11 17:02 ` [RFC PATCH 03/11] VAS: Define helpers for access MMIO regions Sukadev Bhattiprolu
@ 2016-11-11 17:02 ` Sukadev Bhattiprolu
2016-11-11 17:02 ` [RFC PATCH 05/11] VAS: Define helpers to alloc/free windows Sukadev Bhattiprolu
` (6 subsequent siblings)
10 siblings, 0 replies; 12+ messages in thread
From: Sukadev Bhattiprolu @ 2016-11-11 17:02 UTC (permalink / raw)
To: Michael Ellerman
Cc: Benjamin Herrenschmidt, michael.neuling, stewart, hbabu,
linuxppc-dev
Define helpers to initialize window context registers of the VAS
hardware. These will be used in follow-on patches when opening/closing
VAS windows.
Signed-off-by: Sukadev Bhattiprolu <sukadev@linux.vnet.ibm.com>
---
drivers/misc/vas/vas-internal.h | 55 +++++++
drivers/misc/vas/vas-window.c | 330 ++++++++++++++++++++++++++++++++++++++++
2 files changed, 385 insertions(+)
diff --git a/drivers/misc/vas/vas-internal.h b/drivers/misc/vas/vas-internal.h
index 282513b..953b7bb 100644
--- a/drivers/misc/vas/vas-internal.h
+++ b/drivers/misc/vas/vas-internal.h
@@ -367,4 +367,59 @@ 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);
+/*
+ * VREG(x):
+ * Expand a register's short name (eg: LPID) into two parameters:
+ * - the register's short name in string form ("LPID"), and
+ * - the name of the macro (eg: VAS_LPID_OFFSET), defining the
+ * register's offset in the window context
+ */
+#define VREG_SFX(n, s) __stringify(n), VAS_##n##s
+#define VREG(r) VREG_SFX(r, _OFFSET)
+
+#ifndef vas_debug
+static inline void vas_log_write(struct vas_window *win, char *name,
+ void *regptr, uint64_t val)
+{
+ if (val)
+ pr_err("%swin #%d: %s reg %p, val 0x%llx\n",
+ win->txwin ? "Tx" : "Rx", win->winid, name,
+ regptr, val);
+}
+
+#else /* vas_debug */
+
+#define vas_log_write(win, name, reg, val)
+
+#endif /* vas_debug */
+
+
+static inline void write_uwc_reg(struct vas_window *win, char *name,
+ int32_t reg, uint64_t val)
+{
+ void *regptr;
+
+ regptr = win->uwc_map + reg;
+ vas_log_write(win, name, regptr, val);
+
+ out_be64(regptr, val);
+}
+
+static inline void write_hvwc_reg(struct vas_window *win, char *name,
+ int32_t reg, uint64_t val)
+{
+ void *regptr;
+
+ regptr = win->hvwc_map + reg;
+ vas_log_write(win, name, regptr, val);
+
+ out_be64(regptr, val);
+}
+
+static inline uint64_t read_hvwc_reg(struct vas_window *win,
+ char *name __maybe_unused, int32_t reg)
+{
+ return in_be64(win->hvwc_map+reg);
+}
+
#endif
diff --git a/drivers/misc/vas/vas-window.c b/drivers/misc/vas/vas-window.c
index 2c220a3..797b4ebd 100644
--- a/drivers/misc/vas/vas-window.c
+++ b/drivers/misc/vas/vas-window.c
@@ -14,6 +14,8 @@
#include <asm/vas.h>
#include "vas-internal.h"
+static int fault_winid;
+
/*
* Using the node, chip and window id for the send winow identified by
* @window, compute and return the Power Bus address to which a sender
@@ -194,6 +196,334 @@ int map_wc_mmio_bars(struct vas_window *window)
return 0;
}
+/*
+ * Reset all valid registers in the HV and OS/User Window Contexts for
+ * the window identified by @window.
+ *
+ * NOTE: We cannot really use a for loop to reset window context. Not all
+ * offsets in a window context are valid registers and the valid
+ * registers are not sequential. And, we can only write to offsets
+ * with valid registers (or is that only in Simics?).
+ */
+void reset_window_regs(struct vas_window *window)
+{
+ write_hvwc_reg(window, VREG(LPID), 0ULL);
+ write_hvwc_reg(window, VREG(PID), 0ULL);
+ write_hvwc_reg(window, VREG(XLATE_MSR), 0ULL);
+ write_hvwc_reg(window, VREG(XLATE_LPCR), 0ULL);
+ write_hvwc_reg(window, VREG(XLATE_CTL), 0ULL);
+ write_hvwc_reg(window, VREG(AMR), 0ULL);
+ write_hvwc_reg(window, VREG(SEIDR), 0ULL);
+ write_hvwc_reg(window, VREG(FAULT_TX_WIN), 0ULL);
+ write_hvwc_reg(window, VREG(OSU_INTR_SRC_RA), 0ULL);
+ write_hvwc_reg(window, VREG(HV_INTR_SRC_RA), 0ULL);
+ write_hvwc_reg(window, VREG(PSWID), 0ULL);
+ write_hvwc_reg(window, VREG(SPARE1), 0ULL);
+ write_hvwc_reg(window, VREG(SPARE2), 0ULL);
+ write_hvwc_reg(window, VREG(SPARE3), 0ULL);
+ write_hvwc_reg(window, VREG(SPARE4), 0ULL);
+ write_hvwc_reg(window, VREG(SPARE5), 0ULL);
+ write_hvwc_reg(window, VREG(SPARE6), 0ULL);
+ write_hvwc_reg(window, VREG(LFIFO_BAR), 0ULL);
+ write_hvwc_reg(window, VREG(LDATA_STAMP_CTL), 0ULL);
+ write_hvwc_reg(window, VREG(LDMA_CACHE_CTL), 0ULL);
+ write_hvwc_reg(window, VREG(LRFIFO_PUSH), 0ULL);
+ write_hvwc_reg(window, VREG(CURR_MSG_COUNT), 0ULL);
+ write_hvwc_reg(window, VREG(LNOTIFY_AFTER_COUNT), 0ULL);
+ write_hvwc_reg(window, VREG(LRX_WCRED), 0ULL);
+ write_hvwc_reg(window, VREG(LRX_WCRED_ADDER), 0ULL);
+ write_hvwc_reg(window, VREG(TX_WCRED), 0ULL);
+ write_hvwc_reg(window, VREG(TX_WCRED_ADDER), 0ULL);
+ write_hvwc_reg(window, VREG(LFIFO_SIZE), 0ULL);
+ write_hvwc_reg(window, VREG(WINCTL), 0ULL);
+ write_hvwc_reg(window, VREG(WIN_STATUS), 0ULL);
+ write_hvwc_reg(window, VREG(WIN_CTX_CACHING_CTL), 0ULL);
+ write_hvwc_reg(window, VREG(TX_RSVD_BUF_COUNT), 0ULL);
+ write_hvwc_reg(window, VREG(LRFIFO_WIN_PTR), 0ULL);
+ write_hvwc_reg(window, VREG(LNOTIFY_CTL), 0ULL);
+ write_hvwc_reg(window, VREG(LNOTIFY_PID), 0ULL);
+ write_hvwc_reg(window, VREG(LNOTIFY_LPID), 0ULL);
+ write_hvwc_reg(window, VREG(LNOTIFY_TID), 0ULL);
+ write_hvwc_reg(window, VREG(LNOTIFY_SCOPE), 0ULL);
+ write_hvwc_reg(window, VREG(NX_UTIL), 0ULL);
+ write_hvwc_reg(window, VREG(NX_UTIL_SE), 0ULL);
+ write_hvwc_reg(window, VREG(NX_UTIL_ADDER), 0ULL);
+
+ /*
+ * TODO: The Send and receive window credit adder registers are
+ * also accessible from HVWC and have been initialized above.
+ * We probably don't need to initialize from the OS/User
+ * Window Context? Initialize anyway for now.
+ */
+ write_uwc_reg(window, VREG(TX_WCRED_ADDER), 0ULL);
+ write_uwc_reg(window, VREG(LRX_WCRED_ADDER), 0ULL);
+}
+
+/*
+ * Initialize window context registers related to Address Translation.
+ * These registers are common to send/receive windows although they
+ * differ for user/kernel windows. As we resolve the TODOs we may
+ * want to add fields to vas_winctx and move the intialization to
+ * init_vas_winctx_regs().
+ */
+static void init_xlate_regs(struct vas_window *window, bool user_win)
+{
+ uint64_t lpcr, msr, val;
+
+ reset_window_regs(window);
+
+ msr = mfmsr();
+ WARN_ON_ONCE(!(msr & MSR_SF));
+ val = 0ULL;
+ if (user_win) {
+ val = SET_FIELD(VAS_XLATE_MSR_DR, val, true);
+ val = SET_FIELD(VAS_XLATE_MSR_TA, val, false);
+ val = SET_FIELD(VAS_XLATE_MSR_PR, val, true);
+ val = SET_FIELD(VAS_XLATE_MSR_US, val, false);
+ val = SET_FIELD(VAS_XLATE_MSR_HV, val, true);
+ val = SET_FIELD(VAS_XLATE_MSR_SF, val, true);
+ val = SET_FIELD(VAS_XLATE_MSR_UV, val, false);
+ } else {
+ val = SET_FIELD(VAS_XLATE_MSR_DR, val, false);
+ val = SET_FIELD(VAS_XLATE_MSR_TA, val, false);
+ val = SET_FIELD(VAS_XLATE_MSR_PR, val, msr & MSR_PR);
+ val = SET_FIELD(VAS_XLATE_MSR_US, val, false);
+ val = SET_FIELD(VAS_XLATE_MSR_HV, val, true);
+ val = SET_FIELD(VAS_XLATE_MSR_SF, val, true);
+ val = SET_FIELD(VAS_XLATE_MSR_UV, val, false);
+ }
+ write_hvwc_reg(window, VREG(XLATE_MSR), val);
+
+ lpcr = mfspr(SPRN_LPCR);
+ val = 0ULL;
+ /*
+ * NOTE: From Section 5.7.6.1 Segment Lookaside Buffer of the
+ * Power ISA, v2.07, Page size encoding is 0 = 4KB, 5 = 64KB.
+ *
+ * NOTE: From Section 1.3.1, Address Translation Context of the
+ * Nest MMU Workbook, LPCR_SC should be 0 for Power9.
+ */
+ val = SET_FIELD(VAS_XLATE_LPCR_PAGE_SIZE, val, 5);
+ val = SET_FIELD(VAS_XLATE_LPCR_ISL, val, lpcr & LPCR_ISL);
+ val = SET_FIELD(VAS_XLATE_LPCR_TC, val, lpcr & LPCR_TC);
+ val = SET_FIELD(VAS_XLATE_LPCR_SC, val, 0);
+ write_hvwc_reg(window, VREG(XLATE_LPCR), val);
+
+ /*
+ * Section 1.3.1 (Address translation Context) of NMMU workbook.
+ * 0b00 Hashed Page Table mode
+ * 0b01 Reserved
+ * 0b10 Radix on HPT - not supported in P9
+ * 0b11 Radix on Radix (only mode supported in Linux on P9).
+ */
+ val = 0ULL;
+ val = SET_FIELD(VAS_XLATE_MODE, val, 0x11);
+ write_hvwc_reg(window, VREG(XLATE_CTL), val);
+
+ /*
+ * TODO: Can we mfspr(AMR) even for user windows?
+ */
+ val = 0ULL;
+ val = SET_FIELD(VAS_AMR, val, mfspr(SPRN_AMR));
+ write_hvwc_reg(window, VREG(AMR), val);
+
+ /*
+ * TODO: Assuming Secure Executable ID Register (SEIDR) is only used
+ * in the ultravisor mode. Since MSR(UV) is 0 for now, set SEIDR
+ * to 0 as well, although we should 'mfspr(SEIDR)' at some point.
+ */
+ val = 0ULL;
+ val = SET_FIELD(VAS_SEIDR, val, 0);
+ write_hvwc_reg(window, VREG(SEIDR), val);
+}
+
+/*
+ * Initialize Reserved Send Buffer Count for the send window. It involves
+ * writing to the register, reading it back to confirm that the hardware
+ * has enough buffers to reserve. See section 1.3.1.2.1 of VAS workbook.
+ *
+ * Since we can only make a best-effort attempt to fulfill the request,
+ * we don't return any errors if we cannot.
+ *
+ * TODO: Reserved (aka dedicated) send buffers are not supported yet.
+ */
+static void init_rsvd_tx_buf_count(struct vas_window *txwin,
+ struct vas_winctx *winctx)
+{
+ write_hvwc_reg(txwin, VREG(TX_RSVD_BUF_COUNT), 0ULL);
+}
+
+/*
+ * Compute the log2() of the FIFO size expressed as kilobytes. It is intended
+ * to be used to initialize the Local FIFO Size Register defined in Section
+ * 3.14.25 of the VAS Workbook.
+ */
+static int map_fifo_size_to_reg(int fifo_size)
+{
+ int kb;
+ int map;
+
+ kb = fifo_size / 1024;
+ if (!kb)
+ kb = 1;
+
+ map = -1;
+ while (kb) {
+ kb >>= 1;
+ map++;
+ }
+
+ return map;
+}
+
+/*
+ * init_winctx_regs()
+ * Initialize window context registers for a receive window.
+ * Except for caching control and marking window open, the registers
+ * are initialized in the order listed in Section 3.1.4 (Window Context
+ * Cache Register Details) of the VAS workbook although they don't need
+ * to be.
+ *
+ * Design note: For NX receive windows, NX allocates the FIFO buffer in OPAL
+ * (so that it can get a large contiguous area) and passes that buffer
+ * to kernel via device tree. We now write that buffer address to the
+ * FIFO BAR. Would it make sense to do this all in OPAL? i.e have OPAL
+ * write the per-chip RX FIFO addresses to the windows during boot-up
+ * as a one-time task? That could work for NX but what about other
+ * receivers? Let the receivers tell us the rx-fifo buffers for now.
+ */
+int init_winctx_regs(struct vas_window *window, struct vas_winctx *winctx)
+{
+ uint64_t val;
+ int fifo_size;
+
+ val = 0ULL;
+ val = SET_FIELD(VAS_LPID, val, winctx->lpid);
+ write_hvwc_reg(window, VREG(LPID), val);
+
+ val = 0ULL;
+ val = SET_FIELD(VAS_PID_ID, val, winctx->pid);
+ write_hvwc_reg(window, VREG(PID), val);
+
+ init_xlate_regs(window, false);
+
+ val = 0ULL;
+ val = SET_FIELD(VAS_FAULT_TX_WIN, val, fault_winid);
+ write_hvwc_reg(window, VREG(FAULT_TX_WIN), val);
+
+ /* In PowerNV, interrupts go to HV. */
+ write_hvwc_reg(window, VREG(OSU_INTR_SRC_RA), 0ULL);
+
+ val = 0ULL;
+ val = SET_FIELD(VAS_HV_INTR_SRC_RA, val, window->irq_port);
+ write_hvwc_reg(window, VREG(HV_INTR_SRC_RA), val);
+
+ val = 0ULL;
+ val = SET_FIELD(VAS_PSWID_EA_HANDLE, val, winctx->pswid);
+ write_hvwc_reg(window, VREG(PSWID), val);
+
+ write_hvwc_reg(window, VREG(SPARE1), 0ULL);
+ write_hvwc_reg(window, VREG(SPARE2), 0ULL);
+ write_hvwc_reg(window, VREG(SPARE3), 0ULL);
+
+ /* See also: Design note in function header */
+ val = 0ULL;
+ val = SET_FIELD(VAS_LFIFO_BAR, val, __pa(winctx->rx_fifo));
+ val = SET_FIELD(VAS_PAGE_MIGRATION_SELECT, val, 0);
+ write_hvwc_reg(window, VREG(LFIFO_BAR), val);
+
+ val = 0ULL;
+ val = SET_FIELD(VAS_LDATA_STAMP, val, winctx->data_stamp);
+ write_hvwc_reg(window, VREG(LDATA_STAMP_CTL), val);
+
+ val = 0ULL;
+ val = SET_FIELD(VAS_LDMA_TYPE, val, winctx->dma_type);
+ write_hvwc_reg(window, VREG(LDMA_CACHE_CTL), val);
+
+ write_hvwc_reg(window, VREG(LRFIFO_PUSH), 0ULL);
+ write_hvwc_reg(window, VREG(CURR_MSG_COUNT), 0ULL);
+ write_hvwc_reg(window, VREG(LNOTIFY_AFTER_COUNT), 0ULL);
+
+ val = 0ULL;
+ val = SET_FIELD(VAS_LRX_WCRED, val, winctx->wcreds_max);
+ write_hvwc_reg(window, VREG(LRX_WCRED), val);
+
+ write_hvwc_reg(window, VREG(LRX_WCRED_ADDER), 0ULL);
+ write_hvwc_reg(window, VREG(TX_WCRED), 0ULL);
+ write_hvwc_reg(window, VREG(TX_WCRED_ADDER), 0ULL);
+
+ val = 0ULL;
+ fifo_size = winctx->rx_fifo_size;
+ val = SET_FIELD(VAS_LFIFO_SIZE, val, map_fifo_size_to_reg(fifo_size));
+ write_hvwc_reg(window, VREG(LFIFO_SIZE), val);
+
+ /* Update window control and caching control registers last so
+ * we mark the window open only after fully initializing it and
+ * pushing context to cache.
+ */
+
+ write_hvwc_reg(window, VREG(WIN_STATUS), 0ULL);
+
+ init_rsvd_tx_buf_count(window, winctx);
+
+ /* for a send window, point to the matching receive window */
+ val = 0ULL;
+ val = SET_FIELD(VAS_LRX_WIN_ID, val, winctx->rx_win_id);
+ write_hvwc_reg(window, VREG(LRFIFO_WIN_PTR), val);
+
+ write_hvwc_reg(window, VREG(SPARE4), 0ULL);
+
+ val = 0ULL;
+ val = SET_FIELD(VAS_NOTIFY_DISABLE, val, winctx->notify_disable);
+ val = SET_FIELD(VAS_INTR_DISABLE, val, winctx->intr_disable);
+ val = SET_FIELD(VAS_NOTIFY_EARLY, val, winctx->notify_early);
+ val = SET_FIELD(VAS_NOTIFY_OSU_INTR, val, winctx->notify_os_intr_reg);
+ write_hvwc_reg(window, VREG(LNOTIFY_CTL), val);
+
+ val = 0ULL;
+ val = SET_FIELD(VAS_LNOTIFY_PID, val, winctx->lnotify_pid);
+ write_hvwc_reg(window, VREG(LNOTIFY_PID), val);
+
+ val = 0ULL;
+ val = SET_FIELD(VAS_LNOTIFY_LPID, val, winctx->lnotify_lpid);
+ write_hvwc_reg(window, VREG(LNOTIFY_LPID), val);
+
+ val = 0ULL;
+ val = SET_FIELD(VAS_LNOTIFY_TID, val, winctx->lnotify_tid);
+ write_hvwc_reg(window, VREG(LNOTIFY_TID), val);
+
+ val = 0ULL;
+ val = SET_FIELD(VAS_LNOTIFY_MIN_SCOPE, val, winctx->min_scope);
+ val = SET_FIELD(VAS_LNOTIFY_MAX_SCOPE, val, winctx->max_scope);
+ write_hvwc_reg(window, VREG(LNOTIFY_SCOPE), val);
+
+ write_hvwc_reg(window, VREG(SPARE5), 0ULL);
+ write_hvwc_reg(window, VREG(NX_UTIL), 0ULL);
+ write_hvwc_reg(window, VREG(NX_UTIL_SE), 0ULL);
+ write_hvwc_reg(window, VREG(NX_UTIL_ADDER), 0ULL);
+ write_hvwc_reg(window, VREG(SPARE6), 0ULL);
+
+ /* Finally, push window context to memory and... */
+ val = 0ULL;
+ val = SET_FIELD(VAS_PUSH_TO_MEM, val, 1);
+ write_hvwc_reg(window, VREG(WIN_CTX_CACHING_CTL), val);
+
+ /* ... mark the window open for business */
+ val = 0ULL;
+ val = SET_FIELD(VAS_WINCTL_REJ_NO_CREDIT, val, winctx->rej_no_credit);
+ val = SET_FIELD(VAS_WINCTL_PIN, val, winctx->pin_win);
+ val = SET_FIELD(VAS_WINCTL_TX_WCRED_MODE, val, winctx->tx_wcred_mode);
+ val = SET_FIELD(VAS_WINCTL_RX_WCRED_MODE, val, winctx->rx_wcred_mode);
+ val = SET_FIELD(VAS_WINCTL_TXWIN_ORD_MODE, val, winctx->tx_win_ord_mode);
+ val = SET_FIELD(VAS_WINCTL_RXWIN_ORD_MODE, val, winctx->rx_win_ord_mode);
+ val = SET_FIELD(VAS_WINCTL_FAULT_WIN, val, winctx->fault_win);
+ val = SET_FIELD(VAS_WINCTL_NX_WIN, val, winctx->nx_win);
+ val = SET_FIELD(VAS_WINCTL_OPEN, val, 1);
+ write_hvwc_reg(window, VREG(WINCTL), val);
+
+ return 0;
+}
+
/* stub for now */
int vas_window_reset(struct vas_instance *vinst, int winid)
{
--
1.8.3.1
^ permalink raw reply related [flat|nested] 12+ messages in thread
* [RFC PATCH 05/11] VAS: Define helpers to alloc/free windows
2016-11-11 17:02 [RFC PATCH 00/11] Enable VAS Sukadev Bhattiprolu
` (3 preceding siblings ...)
2016-11-11 17:02 ` [RFC PATCH 04/11] VAS: Define helpers to init window context Sukadev Bhattiprolu
@ 2016-11-11 17:02 ` Sukadev Bhattiprolu
2016-11-11 17:02 ` [RFC PATCH 06/11] VAS: Define vas_rx_win_open() and vas_win_close() Sukadev Bhattiprolu
` (5 subsequent siblings)
10 siblings, 0 replies; 12+ messages in thread
From: Sukadev Bhattiprolu @ 2016-11-11 17:02 UTC (permalink / raw)
To: Michael Ellerman
Cc: Benjamin Herrenschmidt, michael.neuling, stewart, hbabu,
linuxppc-dev
Define helpers to allocate/free VAS window objects. These will
be used in follow-on patches when opening/closing windows.
Signed-off-by: Sukadev Bhattiprolu <sukadev@linux.vnet.ibm.com>
---
drivers/misc/vas/vas-window.c | 74 ++++++++++++++++++++++++++++++++++++++++++-
1 file changed, 73 insertions(+), 1 deletion(-)
diff --git a/drivers/misc/vas/vas-window.c b/drivers/misc/vas/vas-window.c
index 797b4ebd..056cfe9 100644
--- a/drivers/misc/vas/vas-window.c
+++ b/drivers/misc/vas/vas-window.c
@@ -524,8 +524,80 @@ int init_winctx_regs(struct vas_window *window, struct vas_winctx *winctx)
return 0;
}
-/* stub for now */
+DEFINE_SPINLOCK(vas_ida_lock);
+
+void vas_release_window_id(struct ida *ida, int winid)
+{
+ spin_lock(&vas_ida_lock);
+ ida_remove(ida, winid);
+ spin_unlock(&vas_ida_lock);
+}
+
+int vas_assign_window_id(struct ida *ida)
+{
+ int rc, winid;
+
+ rc = ida_pre_get(ida, GFP_KERNEL);
+ if (!rc)
+ return -1;
+
+ spin_lock(&vas_ida_lock);
+ rc = ida_get_new_above(ida, 1, &winid);
+ spin_unlock(&vas_ida_lock);
+
+ if (rc)
+ return rc;
+
+ if (winid > VAS_MAX_WINDOWS_PER_CHIP) {
+ pr_err("VAS: Too many (%d) open windows\n", winid);
+ vas_release_window_id(ida, winid);
+ return -EAGAIN;
+ }
+
+ return winid;
+}
+
+static void vas_window_free(struct vas_window *window)
+{
+ unmap_wc_mmio_bars(window);
+ kfree(window->paste_addr_name);
+ kfree(window);
+}
+
+static struct vas_window *vas_window_alloc(struct vas_instance *vinst, int id)
+{
+ struct vas_window *window;
+
+ window = kzalloc(sizeof(*window), GFP_KERNEL);
+ if (!window)
+ return NULL;
+
+ pr_devel("Initializing node %d chip %d window %d\n", vinst->node,
+ vinst->chip, id);
+ window->vinst = vinst;
+ window->winid = id;
+
+ if (map_wc_mmio_bars(window))
+ goto out_free;
+
+ return window;
+
+out_free:
+ kfree(window);
+ return NULL;
+}
+
int vas_window_reset(struct vas_instance *vinst, int winid)
{
+ struct vas_window *window;
+
+ window = vas_window_alloc(vinst, winid);
+ if (!window)
+ return -ENOMEM;
+
+ reset_window_regs(window);
+
+ vas_window_free(window);
+
return 0;
}
--
1.8.3.1
^ permalink raw reply related [flat|nested] 12+ messages in thread
* [RFC PATCH 06/11] VAS: Define vas_rx_win_open() and vas_win_close()
2016-11-11 17:02 [RFC PATCH 00/11] Enable VAS Sukadev Bhattiprolu
` (4 preceding siblings ...)
2016-11-11 17:02 ` [RFC PATCH 05/11] VAS: Define helpers to alloc/free windows Sukadev Bhattiprolu
@ 2016-11-11 17:02 ` Sukadev Bhattiprolu
2016-11-11 17:02 ` [RFC PATCH 07/11] VAS: Define vas_tx_win_open() Sukadev Bhattiprolu
` (4 subsequent siblings)
10 siblings, 0 replies; 12+ messages in thread
From: Sukadev Bhattiprolu @ 2016-11-11 17:02 UTC (permalink / raw)
To: Michael Ellerman
Cc: Benjamin Herrenschmidt, michael.neuling, stewart, hbabu,
linuxppc-dev
Define interfaces to open/close a VAS receive window. This interface
is intended to be used by the Nest Accelerator (NX) driver(s) to
setup receive windows for one or more NX engines (which implement
compression or encryption algorithms in the hardware).
A follow-on patch will provide an interface to open a send window
that subsystems in the kernel can use to access the NX engines.
While the hardware configurations required to open send and receive
windows differ, the configuration to close a window is the same for
both types of windows. So define a single interface to close the window.
The interface to open a receive window is expected to be invoked for
each instance (node, chip) of VAS in the system.
Signed-off-by: Sukadev Bhattiprolu <sukadev@linux.vnet.ibm.com>
---
arch/powerpc/include/asm/vas.h | 48 +++++++++
drivers/misc/vas/vas-internal.h | 11 ++
drivers/misc/vas/vas-window.c | 234 ++++++++++++++++++++++++++++++++++++++++
3 files changed, 293 insertions(+)
diff --git a/arch/powerpc/include/asm/vas.h b/arch/powerpc/include/asm/vas.h
index 1c10437..99bcc30 100644
--- a/arch/powerpc/include/asm/vas.h
+++ b/arch/powerpc/include/asm/vas.h
@@ -37,4 +37,52 @@ enum vas_thresh_ctl {
VAS_THRESH_FIFO_GT_EIGHTH_FULL,
};
+/*
+ * Receive window attributes specified by the (in-kernel) owner of window.
+ */
+struct vas_rx_win_attr {
+ void *rx_fifo;
+ int rx_fifo_size;
+ int wcreds_max;
+
+ bool pin_win;
+ bool rej_no_credit;
+ bool tx_wcred_mode;
+ bool rx_wcred_mode;
+ bool tx_win_ord_mode;
+ bool rx_win_ord_mode;
+ bool data_stamp;
+ bool nx_win;
+ bool fault_win;
+ bool notify_disable;
+ bool intr_disable;
+ bool notify_early;
+
+ int lnotify_lpid;
+ int lnotify_pid;
+ int lnotify_tid;
+ int pswid;
+
+ enum vas_thresh_ctl tc_mode;
+};
+
+/*
+ * Open a VAS receive window for the instance of VAS identified by @chipid.
+ * Use @attr to initialize the attributes of the window.
+ *
+ * Each chip can have a MAX_WINDOWS_PER_CHIP. If no free window is available,
+ * return -EAGAIN.
+ *
+ * Return a handle to the window or ERR_PTR() on error.
+ */
+struct vas_window *vas_rx_win_open(int node, int chip, enum vas_cop_type cop,
+ struct vas_rx_win_attr *attr);
+
+/*
+ * Close the send or receive window identified by @win. For receive windows
+ * return -EAGAIN if there are active send windows attached to this receive
+ * window.
+ */
+int vas_win_close(struct vas_window *win);
+
#endif
diff --git a/drivers/misc/vas/vas-internal.h b/drivers/misc/vas/vas-internal.h
index 953b7bb..7234ff6 100644
--- a/drivers/misc/vas/vas-internal.h
+++ b/drivers/misc/vas/vas-internal.h
@@ -378,6 +378,16 @@ extern struct vas_instance *find_vas_instance(int node, int chip);
#define VREG(r) VREG_SFX(r, _OFFSET)
#ifndef vas_debug
+static inline void dump_rx_win_attr(struct vas_rx_win_attr *attr)
+{
+ pr_err("VAS: 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",
+ attr->rx_fifo_size, VAS_RX_FIFO_SIZE_MAX);
+}
+
static inline void vas_log_write(struct vas_window *win, char *name,
void *regptr, uint64_t val)
{
@@ -390,6 +400,7 @@ static inline void vas_log_write(struct vas_window *win, char *name,
#else /* vas_debug */
#define vas_log_write(win, name, reg, val)
+#define dump_rx_win_attr(attr)
#endif /* vas_debug */
diff --git a/drivers/misc/vas/vas-window.c b/drivers/misc/vas/vas-window.c
index 056cfe9..dc35947 100644
--- a/drivers/misc/vas/vas-window.c
+++ b/drivers/misc/vas/vas-window.c
@@ -601,3 +601,237 @@ int vas_window_reset(struct vas_instance *vinst, int winid)
return 0;
}
+
+static void put_rx_win(struct vas_window *rxwin)
+{
+ /* Better not be a send window! */
+ WARN_ON_ONCE(rxwin->txwin);
+
+ atomic_dec(&rxwin->num_txwins);
+}
+
+struct vas_window *get_vinstance_rxwin(struct vas_instance *vinst,
+ enum vas_cop_type cop)
+{
+ struct vas_window *rxwin;
+
+ mutex_lock(&vinst->mutex);
+
+ rxwin = vinst->rxwin[cop];
+ if (rxwin)
+ atomic_inc(&rxwin->num_txwins);
+
+ mutex_unlock(&vinst->mutex);
+
+ return rxwin;
+}
+
+static void set_vinstance_rxwin(struct vas_instance *vinst,
+ enum vas_cop_type cop, struct vas_window *window)
+{
+ mutex_lock(&vinst->mutex);
+
+ /*
+ * There should only be one receive window for a coprocessor type.
+ */
+ WARN_ON_ONCE(vinst->rxwin[cop]);
+ vinst->rxwin[cop] = window;
+
+ mutex_unlock(&vinst->mutex);
+}
+
+static void init_winctx_for_rxwin(struct vas_window *rxwin,
+ struct vas_rx_win_attr *rxattr,
+ struct vas_winctx *winctx)
+{
+ /*
+ * We first zero (memset()) all fields and only set non-zero fields.
+ * Following fields are 0/false but maybe deserve a comment:
+ *
+ * ->user_win No support for user Rx windows yet
+ * ->notify_os_intr_reg In powerNV, send intrs to HV
+ * ->notify_disable False for NX windows
+ * ->xtra_write False for NX windows
+ * ->notify_early NA for NX windows
+ * ->rsvd_txbuf_count NA for Rx windows
+ * ->lpid, ->pid, ->tid NA for Rx windows
+ */
+
+ memset(winctx, 0, sizeof(struct vas_winctx));
+
+ winctx->rx_fifo = rxattr->rx_fifo;
+ winctx->rx_fifo_size = rxattr->rx_fifo_size;
+ winctx->wcreds_max = rxattr->wcreds_max ?: VAS_WCREDS_DEFAULT;
+ winctx->pin_win = rxattr->pin_win;
+
+ winctx->nx_win = rxattr->nx_win;
+ winctx->fault_win = rxattr->fault_win;
+ winctx->rx_win_ord_mode = true;
+ winctx->tx_win_ord_mode = true;
+
+ winctx->fault_win_id = fault_winid;
+
+ if (winctx->nx_win) {
+ winctx->data_stamp = true;
+ winctx->intr_disable = true;
+
+ WARN_ON_ONCE(!winctx->pin_win);
+ WARN_ON_ONCE(winctx->fault_win);
+ WARN_ON_ONCE(!winctx->rx_win_ord_mode);
+ WARN_ON_ONCE(!winctx->tx_win_ord_mode);
+ WARN_ON_ONCE(winctx->notify_after_count);
+ }
+
+ /* TODO: Are irq ports required for NX receive windows? */
+ winctx->irq_port = rxwin->irq_port;
+
+ winctx->lnotify_lpid = rxattr->lnotify_lpid;
+ winctx->lnotify_pid = rxattr->lnotify_pid;
+ winctx->lnotify_tid = rxattr->lnotify_tid;
+ winctx->pswid = rxattr->pswid;
+ winctx->dma_type = VAS_DMA_TYPE_INJECT;
+ winctx->tc_mode = rxattr->tc_mode;
+
+ winctx->min_scope = VAS_SCOPE_LOCAL;
+ winctx->max_scope = VAS_SCOPE_VECTORED_GROUP;
+}
+
+static bool rx_win_args_valid(enum vas_cop_type cop,
+ struct vas_rx_win_attr *attr)
+{
+ dump_rx_win_attr(attr);
+
+ if (cop >= VAS_COP_TYPE_MAX)
+ return false;
+
+ if (attr->rx_fifo_size > VAS_RX_FIFO_SIZE_MAX)
+ return false;
+
+ if (attr->nx_win) {
+ /* cannot be both fault and nx */
+ if (attr->fault_win)
+ return false;
+ /*
+ * Section 3.1.4.32: NX Windows must not disable notification,
+ * and must not enable interrupts or early notification.
+ */
+ if (attr->notify_disable || !attr->intr_disable ||
+ attr->notify_early)
+ return false;
+ } else if (attr->fault_win) {
+ /*
+ * Section 3.1.4.32: Fault windows must disable notification
+ * but not interrupts.
+ */
+ if (!attr->notify_disable || attr->intr_disable)
+ return false;
+ } else {
+ /* Rx window must be either NX or Fault window for now. */
+ return false;
+ }
+
+ return true;
+}
+
+struct vas_window *vas_rx_win_open(int node, int chip, enum vas_cop_type cop,
+ struct vas_rx_win_attr *rxattr)
+{
+ int rc, winid;
+ struct vas_instance *vinst;
+ struct vas_window *rxwin;
+ struct vas_winctx winctx;
+
+ if (!vas_initialized)
+ return ERR_PTR(-EAGAIN);
+
+ if (!rx_win_args_valid(cop, rxattr))
+ return ERR_PTR(-EINVAL);
+
+ vinst = find_vas_instance(node, chip);
+ if (!vinst) {
+ pr_devel("VAS: No instance found [%d, %d]!\n", node, chip);
+ return ERR_PTR(-EINVAL);
+ }
+ pr_devel("VAS: Found instance [%d, %d]\n", vinst->node, vinst->chip);
+
+ winid = vas_assign_window_id(&vinst->ida);
+ if (winid < 0)
+ return ERR_PTR(winid);
+
+ rc = -ENOMEM;
+ rxwin = vas_window_alloc(vinst, winid);
+ if (!rxwin) {
+ pr_devel("VAS: Unable to allocate memory for Rx window\n");
+ goto release_winid;
+ }
+
+ rxwin->txwin = false;
+ rxwin->cop = cop;
+
+ init_winctx_for_rxwin(rxwin, rxattr, &winctx);
+ rxwin->nx_win = winctx.nx_win;
+ init_winctx_regs(rxwin, &winctx);
+
+ set_vinstance_rxwin(vinst, cop, rxwin);
+
+ if (winctx.fault_win)
+ fault_winid = winid;
+
+ return rxwin;
+
+release_winid:
+ vas_release_window_id(&vinst->ida, rxwin->winid);
+ return ERR_PTR(rc);
+}
+
+int vas_win_close(struct vas_window *window)
+{
+ uint64_t val;
+ int cached;
+
+ if (!window)
+ return 0;
+
+ if (!window->txwin && atomic_read(&window->num_txwins) != 0) {
+ pr_devel("VAS: Attempting to close an active Rx window!\n");
+ WARN_ON_ONCE(1);
+ return -EAGAIN;
+ }
+
+ /* Unpin window from cache and close it */
+ val = 0ULL;
+ val = SET_FIELD(VAS_WINCTL_PIN, val, 0);
+ val = SET_FIELD(VAS_WINCTL_OPEN, val, 0);
+ write_hvwc_reg(window, VREG(WINCTL), val);
+
+ /*
+ * See Section 1.11.1 for details on closing window, including
+ * - disable new paste operations
+ * - block till pending requests are completed
+ * - If Rx window, ensure FIFO is empty.
+ */
+
+ /* Cast window context out of the cache */
+retry:
+ val = read_hvwc_reg(window, VREG(WIN_CTX_CACHING_CTL));
+ cached = GET_FIELD(val, VAS_WIN_CACHE_STATUS);
+ if (cached) {
+ val = 0ULL;
+ val = SET_FIELD(VAS_CASTOUT_REQ, val, 1);
+ val = SET_FIELD(VAS_PUSH_TO_MEM, val, 0);
+ write_hvwc_reg(window, VREG(WIN_CTX_CACHING_CTL), val);
+
+ schedule_timeout(2000);
+ goto retry;
+ }
+
+ /* if send window, drop reference to matching receive window */
+ if (window->txwin)
+ put_rx_win(window->rxwin);
+
+ vas_release_window_id(&window->vinst->ida, window->winid);
+
+ vas_window_free(window);
+
+ return 0;
+}
--
1.8.3.1
^ permalink raw reply related [flat|nested] 12+ messages in thread
* [RFC PATCH 07/11] VAS: Define vas_tx_win_open()
2016-11-11 17:02 [RFC PATCH 00/11] Enable VAS Sukadev Bhattiprolu
` (5 preceding siblings ...)
2016-11-11 17:02 ` [RFC PATCH 06/11] VAS: Define vas_rx_win_open() and vas_win_close() Sukadev Bhattiprolu
@ 2016-11-11 17:02 ` Sukadev Bhattiprolu
2016-11-11 17:02 ` [RFC PATCH 08/11] VAS: Define vas_copy_crb() and vas_paste_crb() Sukadev Bhattiprolu
` (3 subsequent siblings)
10 siblings, 0 replies; 12+ messages in thread
From: Sukadev Bhattiprolu @ 2016-11-11 17:02 UTC (permalink / raw)
To: Michael Ellerman
Cc: Benjamin Herrenschmidt, michael.neuling, stewart, hbabu,
linuxppc-dev
Define an interface to open a VAS send window. This interface is
intended to be used the Nest Accelerator (NX) driver(s) to open
a send window and use it to submit compression/encryption requests
to a VAS receive window.
The receive window, identified by the [node, chip, cop] parameters,
must already be open in VAS (i.e connected to an NX engine).
Signed-off-by: Sukadev Bhattiprolu <sukadev@linux.vnet.ibm.com>
---
arch/powerpc/include/asm/vas.h | 33 ++++++++++
drivers/misc/vas/vas-window.c | 143 +++++++++++++++++++++++++++++++++++++++++
2 files changed, 176 insertions(+)
diff --git a/arch/powerpc/include/asm/vas.h b/arch/powerpc/include/asm/vas.h
index 99bcc30..431692d 100644
--- a/arch/powerpc/include/asm/vas.h
+++ b/arch/powerpc/include/asm/vas.h
@@ -67,6 +67,26 @@ struct vas_rx_win_attr {
};
/*
+ * Window attributes specified by the in-kernel owner of a send window.
+ */
+struct vas_tx_win_attr {
+ enum vas_cop_type cop;
+ int wcreds_max;
+ int lpid;
+ int pid;
+ int pswid;
+ int rsvd_txbuf_count;
+
+ bool user_win;
+ bool pin_win;
+ bool rej_no_credit;
+ bool rsvd_txbuf_enable;
+ bool tx_win_ord_mode;
+ bool rx_win_ord_mode;
+ enum vas_thresh_ctl tc_mode;
+};
+
+/*
* Open a VAS receive window for the instance of VAS identified by @chipid.
* Use @attr to initialize the attributes of the window.
*
@@ -79,6 +99,19 @@ struct vas_window *vas_rx_win_open(int node, int chip, enum vas_cop_type cop,
struct vas_rx_win_attr *attr);
/*
+ * Open a VAS send window for the instance of VAS identified by @chipid
+ * and the co-processor type @cop. Use @attr to initialize the attributes
+ * of the window.
+ *
+ * Note: The instance of VAS must already have an open Receive window for
+ * the coprocessor type @cop.
+ *
+ * Return a handle to the send window or ERR_PTR() on error.
+ */
+struct vas_window *vas_tx_win_open(int node, int chip, enum vas_cop_type cop,
+ struct vas_tx_win_attr *attr);
+
+/*
* Close the send or receive window identified by @win. For receive windows
* return -EAGAIN if there are active send windows attached to this receive
* window.
diff --git a/drivers/misc/vas/vas-window.c b/drivers/misc/vas/vas-window.c
index dc35947..140ce80 100644
--- a/drivers/misc/vas/vas-window.c
+++ b/drivers/misc/vas/vas-window.c
@@ -784,6 +784,149 @@ release_winid:
return ERR_PTR(rc);
}
+static void init_winctx_for_txwin(struct vas_window *txwin,
+ struct vas_tx_win_attr *txattr,
+ struct vas_winctx *winctx)
+{
+ /*
+ * We first zero all fields and only set non-zero ones. Following
+ * are some fields set to 0/false for the stated reason:
+ *
+ * ->notify_os_intr_reg In powerNV, send intrs to HV
+ * ->rsvd_txbuf_count Not supported yet.
+ * ->notify_disable False for NX windows
+ * ->xtra_write False for NX windows
+ * ->notify_early NA for NX windows
+ * ->lnotify_lpid NA for Tx windows
+ * ->lnotify_pid NA for Tx windows
+ * ->lnotify_tid NA for Tx windows
+ * ->tx_win_cred_mode Ignore for now for NX windows
+ * ->rx_win_cred_mode Ignore for now for NX windows
+ */
+ memset(winctx, 0, sizeof(struct vas_winctx));
+
+ winctx->wcreds_max = txattr->wcreds_max ?: VAS_WCREDS_DEFAULT;
+
+ winctx->user_win = txattr->user_win;
+ winctx->nx_win = txwin->rxwin->nx_win;
+ winctx->pin_win = txattr->pin_win;
+
+ winctx->rx_win_ord_mode = true;
+ winctx->tx_win_ord_mode = true;
+
+ if (winctx->nx_win) {
+ winctx->data_stamp = true;
+ winctx->intr_disable = true;
+ }
+
+ winctx->lpid = txattr->lpid;
+ winctx->pid = txattr->pid;
+ winctx->rx_win_id = txwin->rxwin->winid;
+ winctx->fault_win_id = fault_winid;
+
+ winctx->dma_type = VAS_DMA_TYPE_INJECT;
+ winctx->tc_mode = txattr->tc_mode;
+ winctx->min_scope = VAS_SCOPE_LOCAL;
+ winctx->max_scope = VAS_SCOPE_VECTORED_GROUP;
+ winctx->irq_port = txwin->irq_port;
+}
+
+static bool tx_win_args_valid(enum vas_cop_type cop,
+ struct vas_tx_win_attr *attr)
+{
+ if (attr->tc_mode != VAS_THRESH_DISABLED)
+ return false;
+
+ if (cop > VAS_COP_TYPE_MAX)
+ return false;
+
+ if (attr->user_win) {
+ if (cop != VAS_COP_TYPE_GZIP && cop != VAS_COP_TYPE_GZIP_HIPRI)
+ return false;
+
+ if (attr->rsvd_txbuf_count != 0)
+ return false;
+ }
+
+ return true;
+}
+
+struct vas_window *vas_tx_win_open(int node, int chip, enum vas_cop_type cop,
+ struct vas_tx_win_attr *attr)
+{
+ int rc, winid;
+ struct vas_instance *vinst;
+ struct vas_window *txwin;
+ struct vas_window *rxwin;
+ struct vas_winctx winctx;
+ int size;
+ char *name;
+ uint64_t paste_busaddr;
+
+ if (!vas_initialized)
+ return ERR_PTR(-EAGAIN);
+
+ if (!tx_win_args_valid(cop, attr))
+ return ERR_PTR(-EINVAL);
+
+ vinst = find_vas_instance(node, chip);
+ if (!vinst) {
+ pr_devel("VAS: No instance found [%d, %d]!\n", node, chip);
+ return ERR_PTR(-EINVAL);
+ }
+
+ rxwin = get_vinstance_rxwin(vinst, cop);
+ if (!rxwin) {
+ pr_devel("VAS: No Rx window for [%d, %d] cop %d\n",
+ node, chip, cop);
+ return ERR_PTR(-EINVAL);
+ }
+
+ rc = -EAGAIN;
+ winid = vas_assign_window_id(&vinst->ida);
+ if (winid < 0)
+ goto put_rxwin;
+
+ rc = -ENOMEM;
+ txwin = vas_window_alloc(vinst, winid);
+ if (!txwin)
+ goto release_winid;
+
+ txwin->txwin = 1;
+ txwin->rxwin = rxwin;
+ txwin->nx_win = txwin->rxwin->nx_win;
+
+ init_winctx_for_txwin(txwin, attr, &winctx);
+
+ init_winctx_regs(txwin, &winctx);
+
+ name = kasprintf(GFP_KERNEL, "window-n%d-c%d-w%d", node, chip, winid);
+ if (!name)
+ goto release_winid;
+
+ txwin->paste_addr_name = name;
+ paste_busaddr = compute_paste_address(txwin, &size);
+
+ txwin->paste_kaddr = map_mmio_region(name, paste_busaddr, size);
+ if (!txwin->paste_kaddr)
+ goto free_name;
+
+ pr_devel("VAS: mapped paste addr 0x%llx to kaddr 0x%p\n",
+ paste_busaddr, txwin->paste_kaddr);
+ return txwin;
+
+free_name:
+ kfree(txwin->paste_addr_name);
+
+release_winid:
+ vas_release_window_id(&vinst->ida, txwin->winid);
+
+put_rxwin:
+ put_rx_win(rxwin);
+ return ERR_PTR(rc);
+
+}
+
int vas_win_close(struct vas_window *window)
{
uint64_t val;
--
1.8.3.1
^ permalink raw reply related [flat|nested] 12+ messages in thread
* [RFC PATCH 08/11] VAS: Define vas_copy_crb() and vas_paste_crb()
2016-11-11 17:02 [RFC PATCH 00/11] Enable VAS Sukadev Bhattiprolu
` (6 preceding siblings ...)
2016-11-11 17:02 ` [RFC PATCH 07/11] VAS: Define vas_tx_win_open() Sukadev Bhattiprolu
@ 2016-11-11 17:02 ` Sukadev Bhattiprolu
2016-11-11 17:02 ` [RFC PATCH 09/11] VAS: Define/use vas_print_regs() Sukadev Bhattiprolu
` (2 subsequent siblings)
10 siblings, 0 replies; 12+ messages in thread
From: Sukadev Bhattiprolu @ 2016-11-11 17:02 UTC (permalink / raw)
To: Michael Ellerman
Cc: Benjamin Herrenschmidt, michael.neuling, stewart, hbabu,
linuxppc-dev
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>
---
arch/powerpc/include/asm/vas.h | 13 +++++++
drivers/misc/vas/copy-paste.h | 78 +++++++++++++++++++++++++++++++++++++++++
drivers/misc/vas/vas-internal.h | 14 ++++++++
drivers/misc/vas/vas-window.c | 42 ++++++++++++++++++++++
4 files changed, 147 insertions(+)
create mode 100644 drivers/misc/vas/copy-paste.h
diff --git a/arch/powerpc/include/asm/vas.h b/arch/powerpc/include/asm/vas.h
index 431692d..5ed3357 100644
--- a/arch/powerpc/include/asm/vas.h
+++ b/arch/powerpc/include/asm/vas.h
@@ -118,4 +118,17 @@ struct vas_window *vas_tx_win_open(int node, int chip, 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.
+ * For now, @offset must be 0 and @first must be false.
+ */
+extern int vas_copy_crb(void *crb, int offset, bool first);
+
+/*
+ * Paste a previously copied CRB (see vas_copy_crb()) from the L2 cache to
+ * the hardware address associated with the window @win. For now, @off must
+ * 0 and @last must be false. @re is expected/assumed to be true for NX windows.
+ */
+extern int vas_paste_crb(struct vas_window *win, int off, bool last, bool re);
+
#endif
diff --git a/drivers/misc/vas/copy-paste.h b/drivers/misc/vas/copy-paste.h
new file mode 100644
index 0000000..977074b
--- /dev/null
+++ b/drivers/misc/vas/copy-paste.h
@@ -0,0 +1,78 @@
+/*
+ * Copyright 2016 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.
+ */
+
+/*
+ * Macros taken from tools/testing/selftests/powerpc/context_switch/cp_abort.c
+ */
+#define PASTE(RA, RB, L, RC) \
+ .long (0x7c00070c | (RA) << (31-15) | (RB) << (31-20) \
+ | (L) << (31-10) | (RC) << (31-31))
+
+#define COPY(RA, RB, L) \
+ .long (0x7c00060c | (RA) << (31-15) | (RB) << (31-20) \
+ | (L) << (31-10))
+
+#define CR0_FXM "0x80"
+#define CR0_SHIFT 28
+#define CR0_MASK 0xF
+/*
+ * Copy instruction:
+ *
+ * copy RA,RB,L
+ * Copy contents of address
+ *
+ * (RA) + effective_address(RB)
+ *
+ * to internal copy-buffer.
+ *
+ * L == 1 indicates this is the first copy. 0 indicates its
+ * a continuation of a prior first copy.
+ *
+ * paste RA,RB,L
+ * Paste contents of internal copy-buffer to the address:
+ *
+ * (RA) + effective_address(RB)
+ *
+ * L == 0 indicates its a continuation of a prior paste.
+ * i.e paste won't wait for the completion/status.
+ *
+ * L == 1 indicates this is the last paste. In this case,
+ * paste waits for the entire group to complete and
+ * updates the status in CR0.
+ *
+ * For Power9, the L bit must be 'true' in both copy and paste.
+ */
+
+static inline int vas_copy(void *crb, int offset, int first)
+{
+ WARN_ON_ONCE(!first);
+
+ __asm__ __volatile(stringify_in_c(COPY(%0, %1, %2))";"
+ :
+ : "b" (offset), "b" (crb), "i" (1)
+ : "memory");
+
+ return 0;
+}
+
+static inline int vas_paste(void *paste_address, int offset, int last)
+{
+ unsigned long long cr;
+
+ WARN_ON_ONCE(!last);
+
+ cr = 0;
+ __asm__ __volatile(stringify_in_c(PASTE(%1, %2, 1, 1))";"
+ "mfocrf %0," CR0_FXM ";"
+ : "=r" (cr)
+ : "b" (paste_address), "b" (offset)
+ : "memory");
+
+ return cr;
+}
diff --git a/drivers/misc/vas/vas-internal.h b/drivers/misc/vas/vas-internal.h
index 7234ff6..a58ffb2 100644
--- a/drivers/misc/vas/vas-internal.h
+++ b/drivers/misc/vas/vas-internal.h
@@ -433,4 +433,18 @@ static inline uint64_t 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
diff --git a/drivers/misc/vas/vas-window.c b/drivers/misc/vas/vas-window.c
index 140ce80..f6610de 100644
--- a/drivers/misc/vas/vas-window.c
+++ b/drivers/misc/vas/vas-window.c
@@ -13,6 +13,7 @@
#include <linux/io.h>
#include <asm/vas.h>
#include "vas-internal.h"
+#include "copy-paste.h"
static int fault_winid;
@@ -927,6 +928,47 @@ put_rxwin:
}
+int vas_copy_crb(void *crb, int offset, bool first)
+{
+ if (!vas_initialized)
+ return -1;
+
+ return vas_copy(crb, offset, first);
+}
+
+int vas_paste_crb(struct vas_window *txwin, int offset, bool last, bool re)
+{
+ int rc;
+ uint64_t val;
+ void *addr;
+
+ if (!vas_initialized)
+ return -1;
+ /*
+ * Only NX windows are supported for now and hardware assumes
+ * report-enable flag is set for NX windows. Ensure software
+ * complies too.
+ */
+ WARN_ON_ONCE(!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;
+ }
+
+ rc = vas_paste(addr, offset, last);
+
+ print_fifo_msg_count(txwin);
+
+ return rc;
+}
+
+
int vas_win_close(struct vas_window *window)
{
uint64_t val;
--
1.8.3.1
^ permalink raw reply related [flat|nested] 12+ messages in thread
* [RFC PATCH 09/11] VAS: Define/use vas_print_regs()
2016-11-11 17:02 [RFC PATCH 00/11] Enable VAS Sukadev Bhattiprolu
` (7 preceding siblings ...)
2016-11-11 17:02 ` [RFC PATCH 08/11] VAS: Define vas_copy_crb() and vas_paste_crb() Sukadev Bhattiprolu
@ 2016-11-11 17:02 ` Sukadev Bhattiprolu
2016-11-11 17:02 ` [RFC PATCH 10/11] VAS: Create a thread to monitor fault-window Sukadev Bhattiprolu
2016-11-11 17:02 ` [RFC PATCH 11/11] VAS: Define/use interface to setup irq handling Sukadev Bhattiprolu
10 siblings, 0 replies; 12+ messages in thread
From: Sukadev Bhattiprolu @ 2016-11-11 17:02 UTC (permalink / raw)
To: Michael Ellerman
Cc: Benjamin Herrenschmidt, michael.neuling, stewart, hbabu,
linuxppc-dev
Define an interface to read and print the VAS error/debug registers.
Currently this interface only prints the Fault Isolation Registers
(FIR). It needs to make OPAL call(s) to read the registers since
they are only available via the SCOM interface.
Signed-off-by: Sukadev Bhattiprolu <sukadev@linux.vnet.ibm.com>
---
arch/powerpc/include/asm/opal-api.h | 3 +-
arch/powerpc/include/asm/opal.h | 1 +
arch/powerpc/include/asm/vas.h | 5 ++++
arch/powerpc/kernel/process.c | 3 ++
arch/powerpc/platforms/powernv/opal-wrappers.S | 1 +
drivers/misc/vas/vas.c | 38 ++++++++++++++++++++++++++
6 files changed, 50 insertions(+), 1 deletion(-)
diff --git a/arch/powerpc/include/asm/opal-api.h b/arch/powerpc/include/asm/opal-api.h
index 0e2e57b..eabe07e 100644
--- a/arch/powerpc/include/asm/opal-api.h
+++ b/arch/powerpc/include/asm/opal-api.h
@@ -167,7 +167,8 @@
#define OPAL_INT_EOI 124
#define OPAL_INT_SET_MFRR 125
#define OPAL_PCI_TCE_KILL 126
-#define OPAL_LAST 126
+#define OPAL_VAS_READ_FIR 128
+#define OPAL_LAST 128
/* Device tree flags */
diff --git a/arch/powerpc/include/asm/opal.h b/arch/powerpc/include/asm/opal.h
index ee05bd2..b20ec10 100644
--- a/arch/powerpc/include/asm/opal.h
+++ b/arch/powerpc/include/asm/opal.h
@@ -228,6 +228,7 @@ int64_t opal_pci_tce_kill(uint64_t phb_id, uint32_t kill_type,
int64_t opal_rm_pci_tce_kill(uint64_t phb_id, uint32_t kill_type,
uint32_t pe_num, uint32_t tce_size,
uint64_t dma_addr, uint32_t npages);
+int64_t opal_vas_read_fir(uint32_t chip_id, int32_t idx, __be64 *fir);
/* Internal functions */
extern int early_init_dt_scan_opal(unsigned long node, const char *uname,
diff --git a/arch/powerpc/include/asm/vas.h b/arch/powerpc/include/asm/vas.h
index 5ed3357..ca5a3b0 100644
--- a/arch/powerpc/include/asm/vas.h
+++ b/arch/powerpc/include/asm/vas.h
@@ -131,4 +131,9 @@ extern int vas_copy_crb(void *crb, int offset, bool first);
*/
extern int vas_paste_crb(struct vas_window *win, int off, bool last, bool re);
+/*
+ * Print the VAS Fault Isolation Registers (FIR) for the chip @chip.
+ * Used when we encounter an error/exception in VAS.
+ */
+void vas_print_regs(int chip);
#endif
diff --git a/arch/powerpc/kernel/process.c b/arch/powerpc/kernel/process.c
index 9ee2623..1dbc8a8 100644
--- a/arch/powerpc/kernel/process.c
+++ b/arch/powerpc/kernel/process.c
@@ -62,6 +62,7 @@
#include <linux/kprobes.h>
#include <linux/kdebug.h>
+#include <asm/vas.h>
/* Transactional Memory debug */
#ifdef TM_DEBUG_SW
@@ -1339,6 +1340,8 @@ void show_regs(struct pt_regs * regs)
break;
}
printk("\n");
+
+ vas_print_regs(0);
#ifdef CONFIG_KALLSYMS
/*
* Lookup NIP late so we have the best change of getting the
diff --git a/arch/powerpc/platforms/powernv/opal-wrappers.S b/arch/powerpc/platforms/powernv/opal-wrappers.S
index 3d29d40..acb6396 100644
--- a/arch/powerpc/platforms/powernv/opal-wrappers.S
+++ b/arch/powerpc/platforms/powernv/opal-wrappers.S
@@ -308,3 +308,4 @@ OPAL_CALL(opal_int_eoi, OPAL_INT_EOI);
OPAL_CALL(opal_int_set_mfrr, OPAL_INT_SET_MFRR);
OPAL_CALL(opal_pci_tce_kill, OPAL_PCI_TCE_KILL);
OPAL_CALL_REAL(opal_rm_pci_tce_kill, OPAL_PCI_TCE_KILL);
+OPAL_CALL(opal_vas_read_fir, OPAL_VAS_READ_FIR);
diff --git a/drivers/misc/vas/vas.c b/drivers/misc/vas/vas.c
index 51f9c70..785e7a1 100644
--- a/drivers/misc/vas/vas.c
+++ b/drivers/misc/vas/vas.c
@@ -15,10 +15,48 @@
#include <linux/io.h>
#include <asm/vas.h>
#include "vas-internal.h"
+#include <asm/opal-api.h>
+#include <asm/opal.h>
int vas_initialized;
struct vas_instance *vas_instances;
+/*
+ * Read the Fault Isolation Registers (FIR) from skiboot into @fir.
+ */
+static void read_fault_regs(int chip, uint64_t *fir)
+{
+ int i;
+ int64_t rc;
+
+ for (i = 0; i < 8; i++)
+ rc = opal_vas_read_fir(chip, i, &fir[i]);
+}
+
+/*
+ * Print the VAS Fault Isolation Registers (FIR) for the chip @chip.
+ * Used when we encounter an error/exception in VAS.
+ *
+ * TODO: Find the chip id where the exception occurred. Hard coding to
+ * chip 0 for now.
+ */
+void vas_print_regs(int chip)
+{
+ int i;
+ uint64_t firs[8];
+
+ /* TODO: Only dump FIRs for first chip for now */
+ if (chip == -1)
+ chip = 0;
+
+ read_fault_regs(chip, firs);
+ for (i = 0; i < 8; i += 4) {
+ pr_err("FIR%d: 0x%llx 0x%llx 0x%llx 0x%llx\n", i,
+ firs[i], firs[i+1], firs[i+2], firs[i+3]);
+ }
+}
+
+
static void init_vas_chip(struct vas_instance *vinst)
{
int i;
--
1.8.3.1
^ permalink raw reply related [flat|nested] 12+ messages in thread
* [RFC PATCH 10/11] VAS: Create a thread to monitor fault-window
2016-11-11 17:02 [RFC PATCH 00/11] Enable VAS Sukadev Bhattiprolu
` (8 preceding siblings ...)
2016-11-11 17:02 ` [RFC PATCH 09/11] VAS: Define/use vas_print_regs() Sukadev Bhattiprolu
@ 2016-11-11 17:02 ` Sukadev Bhattiprolu
2016-11-11 17:02 ` [RFC PATCH 11/11] VAS: Define/use interface to setup irq handling Sukadev Bhattiprolu
10 siblings, 0 replies; 12+ messages in thread
From: Sukadev Bhattiprolu @ 2016-11-11 17:02 UTC (permalink / raw)
To: Michael Ellerman
Cc: Benjamin Herrenschmidt, michael.neuling, stewart, hbabu,
linuxppc-dev
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.
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);
/*
* 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)
}
}
+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?
+ */
+ 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;
+ }
+
+ /*
+ * Create a worker thread that processes the fault CRBs.
+ */
+ 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)
{
@@ -93,7 +236,7 @@ static void init_vas_instance(int node, int chip)
int vas_init(void)
{
- 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;
}
void vas_exit(void)
{
vas_initialized = 0;
+ destroy_fault_win();
kfree(vas_instances);
}
--
1.8.3.1
^ permalink raw reply related [flat|nested] 12+ messages in thread
* [RFC PATCH 11/11] VAS: Define/use interface to setup irq handling.
2016-11-11 17:02 [RFC PATCH 00/11] Enable VAS Sukadev Bhattiprolu
` (9 preceding siblings ...)
2016-11-11 17:02 ` [RFC PATCH 10/11] VAS: Create a thread to monitor fault-window Sukadev Bhattiprolu
@ 2016-11-11 17:02 ` Sukadev Bhattiprolu
10 siblings, 0 replies; 12+ messages in thread
From: Sukadev Bhattiprolu @ 2016-11-11 17:02 UTC (permalink / raw)
To: Michael Ellerman
Cc: Benjamin Herrenschmidt, michael.neuling, stewart, hbabu,
linuxppc-dev
When VAS hardware encounters an address translation error it will
post the failing CRB to a fault window and issue an interrupt to
the kernel.
Use OPAL/XIVE to register a IRQ trigger port for each send window
and setup IRQ handling in the kernel for this IRQ. (The existing
init_winctx_regs() call configures the trigger port in the VAS
registers.
When the VAS hardware generates an interrupt, the kernel interrupt
handler wakes up the fault thread (from previous patch) to process
the fault CRB. As mentioned in that patch, this interrupt handling
is needed when we support user space access to VAS/NX. But including
this patch of routing VAS interrupt to kernel handler for review.
Signed-off-by: Sukadev Bhattiprolu <sukadev@linux.vnet.ibm.com>
---
arch/powerpc/include/asm/opal-api.h | 3 +-
arch/powerpc/include/asm/opal.h | 2 +
arch/powerpc/platforms/powernv/opal-wrappers.S | 2 +
drivers/misc/vas/vas-window.c | 81 ++++++++++++++++++++++++++
4 files changed, 87 insertions(+), 1 deletion(-)
diff --git a/arch/powerpc/include/asm/opal-api.h b/arch/powerpc/include/asm/opal-api.h
index eabe07e..192d430 100644
--- a/arch/powerpc/include/asm/opal-api.h
+++ b/arch/powerpc/include/asm/opal-api.h
@@ -168,7 +168,8 @@
#define OPAL_INT_SET_MFRR 125
#define OPAL_PCI_TCE_KILL 126
#define OPAL_VAS_READ_FIR 128
-#define OPAL_LAST 128
+#define OPAL_VAS_GET_TRIGGER_PORT 129
+#define OPAL_LAST 129
/* Device tree flags */
diff --git a/arch/powerpc/include/asm/opal.h b/arch/powerpc/include/asm/opal.h
index b20ec10..30042f9 100644
--- a/arch/powerpc/include/asm/opal.h
+++ b/arch/powerpc/include/asm/opal.h
@@ -229,6 +229,8 @@ int64_t opal_rm_pci_tce_kill(uint64_t phb_id, uint32_t kill_type,
uint32_t pe_num, uint32_t tce_size,
uint64_t dma_addr, uint32_t npages);
int64_t opal_vas_read_fir(uint32_t chip_id, int32_t idx, __be64 *fir);
+int64_t opal_vas_get_trigger_port(uint32_t chip_id, int32_t idx, __be32 *girq,
+ __be64 *port);
/* Internal functions */
extern int early_init_dt_scan_opal(unsigned long node, const char *uname,
diff --git a/arch/powerpc/platforms/powernv/opal-wrappers.S b/arch/powerpc/platforms/powernv/opal-wrappers.S
index acb6396..9b88e22 100644
--- a/arch/powerpc/platforms/powernv/opal-wrappers.S
+++ b/arch/powerpc/platforms/powernv/opal-wrappers.S
@@ -309,3 +309,5 @@ OPAL_CALL(opal_int_set_mfrr, OPAL_INT_SET_MFRR);
OPAL_CALL(opal_pci_tce_kill, OPAL_PCI_TCE_KILL);
OPAL_CALL_REAL(opal_rm_pci_tce_kill, OPAL_PCI_TCE_KILL);
OPAL_CALL(opal_vas_read_fir, OPAL_VAS_READ_FIR);
+OPAL_CALL(opal_vas_get_trigger_port, OPAL_VAS_GET_TRIGGER_PORT);
+
diff --git a/drivers/misc/vas/vas-window.c b/drivers/misc/vas/vas-window.c
index f6610de..ba10922 100644
--- a/drivers/misc/vas/vas-window.c
+++ b/drivers/misc/vas/vas-window.c
@@ -10,7 +10,11 @@
#include <linux/types.h>
#include <linux/mutex.h>
#include <linux/slab.h>
+#include <linux/irqdomain.h>
+#include <linux/interrupt.h>
#include <linux/io.h>
+#include <asm/opal.h>
+#include <asm/opal-api.h>
#include <asm/vas.h>
#include "vas-internal.h"
#include "copy-paste.h"
@@ -603,6 +607,72 @@ int vas_window_reset(struct vas_instance *vinst, int winid)
return 0;
}
+static irqreturn_t vas_irq_handler(int virq, void *data)
+{
+ struct vas_window *win = data;
+
+ pr_devel("VAS: virq %d, window %d\n", virq, win->winid);
+ vas_wakeup_fault_win_thread();
+
+ return IRQ_HANDLED;
+}
+
+static int setup_irq_mapping(struct vas_window *win)
+{
+ int rc;
+ int winid;
+ uint32_t virq;
+ int32_t girq;
+ uint64_t port;
+ char devname[64];
+
+ winid = win->winid;
+ snprintf(devname, sizeof(devname), "vas-window-%d", winid);
+
+ girq = 0;
+ port = 0ULL;
+ rc = opal_vas_get_trigger_port(win->vinst->chip, winid, &girq, &port);
+
+ pr_devel("VAS: %swin #%d: IRQ trigger %d, port 0x%llx, rc %d\n",
+ win->txwin ? "Tx" : "Rx", winid, girq, port, rc);
+ if (rc)
+ return -EINVAL;
+
+ virq = irq_create_mapping(NULL, girq);
+ if (!virq) {
+ pr_devel("VAS: %swin #%d: Unable to map global irq %d\n",
+ win->txwin ? "Tx" : "Rx", winid, girq);
+ return -EINVAL;
+ }
+
+ rc = request_irq(virq, vas_irq_handler, 0, devname, win);
+ if (rc) {
+ pr_devel("VAS: %swin #%d: request_irq() returns %d\n",
+ win->txwin ? "Tx" : "Rx", winid, rc);
+ return rc;
+ }
+
+ win->hwirq = girq;
+ win->irq_port = port;
+
+ return 0;
+}
+
+static void free_irq_mapping(struct vas_window *win)
+{
+ unsigned int irq;
+
+ irq = irq_find_mapping(NULL, win->hwirq);
+ if (!irq) {
+ pr_devel("VAS: Receieved unknown hwirq %d\n", win->hwirq);
+ WARN_ON_ONCE(true);
+ return;
+ }
+
+ free_irq(irq, win);
+}
+
+
static void put_rx_win(struct vas_window *rxwin)
{
/* Better not be a send window! */
@@ -897,6 +967,15 @@ struct vas_window *vas_tx_win_open(int node, int chip, enum vas_cop_type cop,
txwin->rxwin = rxwin;
txwin->nx_win = txwin->rxwin->nx_win;
+ if (setup_irq_mapping(txwin)) {
+ /*
+ * TODO: IRQ mapping is essential for user space send windows.
+ * We only support in-kernel initially, so ignore errors
+ * in setting up IRQ mappings for now.
+ */
+ WARN_ON_ONCE(1);
+ }
+
init_winctx_for_txwin(txwin, attr, &winctx);
init_winctx_regs(txwin, &winctx);
@@ -1014,6 +1093,8 @@ retry:
if (window->txwin)
put_rx_win(window->rxwin);
+ free_irq_mapping(window);
+
vas_release_window_id(&window->vinst->ida, window->winid);
vas_window_free(window);
--
1.8.3.1
^ permalink raw reply related [flat|nested] 12+ messages in thread