--- v8
+++ v3
@@ -4,24 +4,6 @@
Signed-off-by: Sukadev Bhattiprolu <sukadev@linux.vnet.ibm.com>
---
-Changelog[v8]:
- - Update comments (ISA references and some cleanup)
- - Use 0 or 1 when setting boolean fields with SET_FIELD()
- - Don't write to spare/unused registers.
- - Use kernel integer types (u64/u32/s32)
-Changelog[v6]
- - Add support for FTW windows and drop the fault window id
- code since it is not needed for FTW/kernel windows.
-Changelog[v5]
- - Fix: Copy the FIFO address into LFIFO_BAR register as is (don't
- shift address into bits 8:53).
-
-Changelog[v4]
- - Michael Neuling] Use ilog2(), radix_enabled() helpers;
- drop warning when 32-bit app uses VAS (a follow-on patch
- will check and return error). Set MSR_PR state to 0 for
- kernel (rather than reading from MSR).
-
Changelog[v3]
- Have caller, rather than init_xlate_regs() reset window regs
so we don't reset any settings caller may already have set.
@@ -31,23 +13,106 @@
initialized from the HVWC.
- Check winctx->user_win when setting translation registers
---
- arch/powerpc/platforms/powernv/vas-window.c | 299 ++++++++++++++++++++++++++++
- arch/powerpc/platforms/powernv/vas.h | 55 +++++
- 2 files changed, 354 insertions(+)
+ drivers/misc/vas/vas-internal.h | 59 ++++++-
+ drivers/misc/vas/vas-window.c | 334 ++++++++++++++++++++++++++++++++++++++++
+ 2 files changed, 390 insertions(+), 3 deletions(-)
-diff --git a/arch/powerpc/platforms/powernv/vas-window.c b/arch/powerpc/platforms/powernv/vas-window.c
-index 642814a2..68dfe53 100644
---- a/arch/powerpc/platforms/powernv/vas-window.c
-+++ b/arch/powerpc/platforms/powernv/vas-window.c
-@@ -13,6 +13,7 @@
- #include <linux/mutex.h>
- #include <linux/slab.h>
- #include <linux/io.h>
-+#include <linux/log2.h>
+diff --git a/drivers/misc/vas/vas-internal.h b/drivers/misc/vas/vas-internal.h
+index 15b62e0..8e721df 100644
+--- a/drivers/misc/vas/vas-internal.h
++++ b/drivers/misc/vas/vas-internal.h
+@@ -11,6 +11,7 @@
+ #define VAS_INTERNAL_H
+ #include <linux/atomic.h>
+ #include <linux/idr.h>
++#include <linux/io.h>
+ #include <asm/vas.h>
- #include "vas.h"
+ #ifdef CONFIG_PPC_4K_PAGES
+@@ -336,9 +337,6 @@ struct vas_window {
+ /* Feilds applicable only to receive windows */
+ enum vas_cop_type cop;
+ atomic_t num_txwins;
+-
+- int32_t hwirq;
+- uint64_t irq_port;
+ };
-@@ -186,6 +187,304 @@ int map_winctx_mmio_bars(struct vas_window *window)
+ /*
+@@ -392,4 +390,59 @@ struct vas_winctx {
+ extern int vas_initialized;
+ extern int vas_window_reset(struct vas_instance *vinst, int winid);
+ extern struct vas_instance *find_vas_instance(int vasid);
++
++/*
++ * 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->tx_win ? "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 32dd1d0..edf5c9f 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;
++
+ /*
+ * Compute the paste address region for the window @window using the
+ * ->win_base_addr and ->win_id_shift we got from device tree.
+@@ -138,6 +140,338 @@ int map_wc_mmio_bars(struct vas_window *window)
return 0;
}
@@ -58,7 +123,7 @@
+ * 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.
++ * with valid registers (or is that only in Simics?).
+ */
+void reset_window_regs(struct vas_window *window)
+{
@@ -73,6 +138,12 @@
+ 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);
@@ -118,26 +189,35 @@
+ */
+static void init_xlate_regs(struct vas_window *window, bool user_win)
+{
-+ u64 lpcr, val;
-+
-+ /*
-+ * MSR_TA, MSR_US are false for both kernel and user.
-+ * MSR_DR and MSR_PR are false for kernel.
-+ */
-+ val = 0ULL;
-+ val = SET_FIELD(VAS_XLATE_MSR_HV, val, 1);
-+ val = SET_FIELD(VAS_XLATE_MSR_SF, val, 1);
++ uint64_t lpcr, msr, val;
++
++ msr = mfmsr();
++ WARN_ON_ONCE(!(msr & MSR_SF));
++ val = 0ULL;
+ if (user_win) {
-+ val = SET_FIELD(VAS_XLATE_MSR_DR, val, 1);
-+ val = SET_FIELD(VAS_XLATE_MSR_PR, val, 1);
++ 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.8.1 Segment Lookaside Buffer of the
-+ * Power ISA, v3.0B, Page size encoding is 0 = 4KB, 5 = 64KB.
++ * 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.
@@ -152,11 +232,11 @@
+ * Section 1.3.1 (Address translation Context) of NMMU workbook.
+ * 0b00 Hashed Page Table mode
+ * 0b01 Reserved
-+ * 0b10 Radix on HPT
-+ * 0b11 Radix on Radix
-+ */
-+ val = 0ULL;
-+ val = SET_FIELD(VAS_XLATE_MODE, val, radix_enabled() ? 3 : 2);
++ * 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, 0x3);
+ write_hvwc_reg(window, VREG(XLATE_CTL), val);
+
+ /*
@@ -166,6 +246,11 @@
+ 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);
@@ -185,6 +270,29 @@
+ 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;
+}
+
+/*
@@ -205,7 +313,7 @@
+ */
+int init_winctx_regs(struct vas_window *window, struct vas_winctx *winctx)
+{
-+ u64 val;
++ uint64_t val;
+ int fifo_size;
+
+ reset_window_regs(window);
@@ -221,7 +329,7 @@
+ init_xlate_regs(window, winctx->user_win);
+
+ val = 0ULL;
-+ val = SET_FIELD(VAS_FAULT_TX_WIN, val, 0);
++ 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. */
@@ -239,16 +347,9 @@
+ write_hvwc_reg(window, VREG(SPARE2), 0ULL);
+ write_hvwc_reg(window, VREG(SPARE3), 0ULL);
+
-+ /*
-+ * NOTE: VAS expects the FIFO address to be copied into the LFIFO_BAR
-+ * register as is - do NOT shift the address into VAS_LFIFO_BAR
-+ * bit fields! Ok to set the page migration select fields -
-+ * VAS ignores the lower 10+ bits in the address anyway, because
-+ * the minimum FIFO size is 1K?
-+ *
-+ * See also: Design note in function header.
-+ */
-+ val = __pa(winctx->rx_fifo);
++ /* 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);
+
@@ -258,7 +359,6 @@
+
+ val = 0ULL;
+ val = SET_FIELD(VAS_LDMA_TYPE, val, winctx->dma_type);
-+ val = SET_FIELD(VAS_LDMA_FIFO_DISABLE, val, winctx->fifo_disable);
+ write_hvwc_reg(window, VREG(LDMA_CACHE_CTL), val);
+
+ write_hvwc_reg(window, VREG(LRFIFO_PUSH), 0ULL);
@@ -276,10 +376,9 @@
+ write_hvwc_reg(window, VREG(LRX_WCRED_ADDER), 0ULL);
+ write_hvwc_reg(window, VREG(TX_WCRED_ADDER), 0ULL);
+
-+ fifo_size = winctx->rx_fifo_size / 1024;
-+
-+ val = 0ULL;
-+ val = SET_FIELD(VAS_LFIFO_SIZE, val, ilog2(fifo_size));
++ 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
@@ -350,78 +449,7 @@
+}
+
/* stub for now */
- int vas_win_close(struct vas_window *window)
+ int vas_window_reset(struct vas_instance *vinst, int winid)
{
-diff --git a/arch/powerpc/platforms/powernv/vas.h b/arch/powerpc/platforms/powernv/vas.h
-index 650805d..60a3c3c 100644
---- a/arch/powerpc/platforms/powernv/vas.h
-+++ b/arch/powerpc/platforms/powernv/vas.h
-@@ -12,6 +12,7 @@
- #include <linux/atomic.h>
- #include <linux/idr.h>
- #include <asm/vas.h>
-+#include <linux/io.h>
-
- /*
- * Overview of Virtual Accelerator Switchboard (VAS).
-@@ -381,4 +382,58 @@ struct vas_winctx {
-
- extern struct vas_instance *find_vas_instance(int vasid);
-
-+/*
-+ * 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)
-+
-+#ifdef vas_debug
-+static inline void vas_log_write(struct vas_window *win, char *name,
-+ void *regptr, u64 val)
-+{
-+ if (val)
-+ pr_err("%swin #%d: %s reg %p, val 0x%016llx\n",
-+ win->tx_win ? "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,
-+ s32 reg, u64 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,
-+ s32 reg, u64 val)
-+{
-+ void *regptr;
-+
-+ regptr = win->hvwc_map + reg;
-+ vas_log_write(win, name, regptr, val);
-+
-+ out_be64(regptr, val);
-+}
-+
-+static inline u64 read_hvwc_reg(struct vas_window *win,
-+ char *name __maybe_unused, s32 reg)
-+{
-+ return in_be64(win->hvwc_map+reg);
-+}
-+
- #endif /* _VAS_H */
--
2.7.4