Skip to contentSkip to conversation

arm64 pmem support

PATCH New Robin Murphy 5 participants 17 messages Jul 25, 2017 – Aug 10, 2017

Subsystems (3)
lore
Share & tools
lore
#0 lore raw

cover arm64 pmem support

Hi all,

With the latest updates to the pmem API, the arch code contribution becomes very straightforward to wire up - I think there's about as much code here to just cope with the existence of our new instruction as there is to actually make use of it. I don't have access to any NVDIMMs nor suitable hardware to put them in, so this is written purely to spec - the extent of testing has been the feature detection on a v8.2 Fast Model vs. v8.0 systems.

Patch #1 could go in as a fix ahead of the rest; it just needs to come before patch #5 to prevent that blowing up the build.

Robin.

Robin Murphy (6):
arm64: mm: Fix set_memory_valid() declaration
arm64: Convert __inval_cache_range() to area-based
arm64: Expose DC CVAP to userspace
arm64: Handle trapped DC CVAP
arm64: Implement pmem API support
arm64: uaccess: Implement *_flushcache variants

 Documentation/arm64/cpu-feature-registers.txt |  2 ++
 arch/arm64/Kconfig                            | 12 +++++++
 arch/arm64/include/asm/assembler.h            |  6 ++++
 arch/arm64/include/asm/cacheflush.h           |  4 ++-
 arch/arm64/include/asm/cpucaps.h              |  3 +-
 arch/arm64/include/asm/esr.h                  |  3 +-
 arch/arm64/include/asm/string.h               |  4 +++
 arch/arm64/include/asm/sysreg.h               |  1 +
 arch/arm64/include/asm/uaccess.h              | 12 +++++++
 arch/arm64/include/uapi/asm/hwcap.h           |  1 +
 arch/arm64/kernel/cpufeature.c                | 13 ++++++++
 arch/arm64/kernel/cpuinfo.c                   |  1 +
 arch/arm64/kernel/head.S                      | 18 +++++-----
 arch/arm64/kernel/traps.c                     |  3 ++
 arch/arm64/lib/Makefile                       |  2 ++
 arch/arm64/lib/uaccess_flushcache.c           | 47 +++++++++++++++++++++++++++
 arch/arm64/mm/cache.S                         | 37 ++++++++++++++++-----
 arch/arm64/mm/pageattr.c                      | 18 ++++++++++
 18 files changed, 166 insertions(+), 21 deletions(-)
 create mode 100644 arch/arm64/lib/uaccess_flushcache.c
Signature · 6 lines
2.12.2.dirty

_______________________________________________
Linux-nvdimm mailing list
[email protected]
https://lists.01.org/mailman/listinfo/linux-nvdimm
#1 lore raw

PATCH 1/6 arm64: mm: Fix set_memory_valid() declaration

Clearly, set_memory_valid() has never been seen in the same room as its declaration... Whilst the type mismatch is such that kexec probably wasn't broken in practice, fix it to match the definition as it should.

Fixes 9b0aa14e3155 ("arm64: mm: add set_memory_valid()")
---
 arch/arm64/include/asm/cacheflush.h | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)
arch/arm64/include/asm/cacheflush.h +1 -1
index d74a284abdc2..4d4f650c290e 100644
@@ -150,6 +150,6 @@ static inline void flush_cache_vunmap(unsigned long start, unsigned long end)
 {
 }
 
-int set_memory_valid(unsigned long addr, unsigned long size, int enable);
+int set_memory_valid(unsigned long addr, int numpages, int enable);
 
 #endif
Signature · 6 lines
2.12.2.dirty

_______________________________________________
Linux-nvdimm mailing list
[email protected]
https://lists.01.org/mailman/listinfo/linux-nvdimm
#2 lore raw

PATCH 2/6 arm64: Convert __inval_cache_range() to area-based

In reply to Robin Murphy

__inval_cache_range() is already the odd one out among our data cache maintenance routines as the only remaining range-based one; as we're going to want an invalidation routine to call from C code for the pmem API, let's tweak the prototype and name to bring it in line with the clean operations, and to make its relationship with __dma_inv_area() neatly mirror that of __clean_dcache_area_poc() and __dma_clean_area(). The loop clearing the early page tables gets mildly massaged in the process for the sake of consistency.

---
 arch/arm64/include/asm/cacheflush.h |  1 +
 arch/arm64/kernel/head.S            | 18 +++++++++---------
 arch/arm64/mm/cache.S               | 23 ++++++++++++++---------
 3 files changed, 24 insertions(+), 18 deletions(-)
arch/arm64/include/asm/cacheflush.h +1 -0
index 4d4f650c290e..b4b43a94dffd 100644
@@ -67,6 +67,7 @@
  */
 extern void flush_icache_range(unsigned long start, unsigned long end);
 extern void __flush_dcache_area(void *addr, size_t len);
+extern void __inval_dcache_area(void *addr, size_t len);
 extern void __clean_dcache_area_poc(void *addr, size_t len);
 extern void __clean_dcache_area_pou(void *addr, size_t len);
 extern long __flush_cache_user_range(unsigned long start, unsigned long end);
arch/arm64/kernel/head.S +9 -9
index 973df7de7bf8..73a0531e0187 100644
@@ -143,8 +143,8 @@ preserve_boot_args:
 	dmb	sy				// needed before dc ivac with
 						// MMU off
 
-	add	x1, x0, #0x20			// 4 x 8 bytes
-	b	__inval_cache_range		// tail call
+	mov	x1, #0x20			// 4 x 8 bytes
+	b	__inval_dcache_area		// tail call
 ENDPROC(preserve_boot_args)
 
 /*
@@ -221,20 +221,20 @@ __create_page_tables:
 	 * dirty cache lines being evicted.
 	 */
 	adrp	x0, idmap_pg_dir
-	adrp	x1, swapper_pg_dir + SWAPPER_DIR_SIZE + RESERVED_TTBR0_SIZE
-	bl	__inval_cache_range
+	ldr	x1, =(IDMAP_DIR_SIZE + SWAPPER_DIR_SIZE + RESERVED_TTBR0_SIZE)
+	bl	__inval_dcache_area
 
 	/*
 	 * Clear the idmap and swapper page tables.
 	 */
 	adrp	x0, idmap_pg_dir
-	adrp	x6, swapper_pg_dir + SWAPPER_DIR_SIZE + RESERVED_TTBR0_SIZE
+	ldr	x1, =(IDMAP_DIR_SIZE + SWAPPER_DIR_SIZE + RESERVED_TTBR0_SIZE)
 1:	stp	xzr, xzr, [x0], #16
 	stp	xzr, xzr, [x0], #16
 	stp	xzr, xzr, [x0], #16
 	stp	xzr, xzr, [x0], #16
-	cmp	x0, x6
-	b.lo	1b
+	subs	x1, x1, #64
+	b.ne	1b
 
 	mov	x7, SWAPPER_MM_MMUFLAGS
 
@@ -307,9 +307,9 @@ __create_page_tables:
 	 * tables again to remove any speculatively loaded cache lines.
 	 */
 	adrp	x0, idmap_pg_dir
-	adrp	x1, swapper_pg_dir + SWAPPER_DIR_SIZE + RESERVED_TTBR0_SIZE
+	ldr	x1, =(IDMAP_DIR_SIZE + SWAPPER_DIR_SIZE + RESERVED_TTBR0_SIZE)
 	dmb	sy
-	bl	__inval_cache_range
+	bl	__inval_dcache_area
 
 	ret	x28
 ENDPROC(__create_page_tables)
arch/arm64/mm/cache.S +14 -9
index 83c27b6e6dca..ed47fbbb4b05 100644
@@ -109,20 +109,25 @@ ENTRY(__clean_dcache_area_pou)
 ENDPROC(__clean_dcache_area_pou)
 
 /*
+ *	__inval_dcache_area(kaddr, size)
+ *
+ * 	Ensure that any D-cache lines for the interval [kaddr, kaddr+size)
+ * 	are invalidated. Any partial lines at the ends of the interval are
+ *	also cleaned to PoC to prevent data loss.
+ *
+ *	- kaddr   - kernel address
+ *	- size    - size in question
+ */
+ENTRY(__inval_dcache_area)
+	/* FALLTHROUGH */
+
+/*
  *	__dma_inv_area(start, size)
  *	- start   - virtual start address of region
  *	- size    - size in question
  */
 __dma_inv_area:
 	add	x1, x1, x0
-	/* FALLTHROUGH */
-
-/*
- *	__inval_cache_range(start, end)
- *	- start   - start address of region
- *	- end     - end address of region
- */
-ENTRY(__inval_cache_range)
 	dcache_line_size x2, x3
 	sub	x3, x2, #1
 	tst	x1, x3				// end cache line aligned?
@@ -140,7 +145,7 @@ ENTRY(__inval_cache_range)
 	b.lo	2b
 	dsb	sy
 	ret
-ENDPIPROC(__inval_cache_range)
+ENDPIPROC(__inval_dcache_area)
 ENDPROC(__dma_inv_area)
 
 /*
Signature · 6 lines
2.12.2.dirty

_______________________________________________
Linux-nvdimm mailing list
[email protected]
https://lists.01.org/mailman/listinfo/linux-nvdimm
#3 lore raw

PATCH 3/6 arm64: Expose DC CVAP to userspace

In reply to Robin Murphy

The ARMv8.2-DCPoP feature introduces persistent memory support to the architecture, by defining a point of persistence in the memory hierarchy, and a corresponding cache maintenance operation, DC CVAP. Expose the support via HWCAP and MRS emulation.

---
 Documentation/arm64/cpu-feature-registers.txt | 2 ++
 arch/arm64/include/asm/sysreg.h               | 1 +
 arch/arm64/include/uapi/asm/hwcap.h           | 1 +
 arch/arm64/kernel/cpufeature.c                | 2 ++
 arch/arm64/kernel/cpuinfo.c                   | 1 +
 5 files changed, 7 insertions(+)
Documentation/arm64/cpu-feature-registers.txt +2 -0
index d1c97f9f51cc..dad411d635d8 100644
@@ -179,6 +179,8 @@ infrastructure:
      | FCMA                         | [19-16] |    y    |
      |--------------------------------------------------|
      | JSCVT                        | [15-12] |    y    |
+     |--------------------------------------------------|
+     | DPB                          | [3-0]   |    y    |
      x--------------------------------------------------x
 
 Appendix I: Example
arch/arm64/include/asm/sysreg.h +1 -0
index 16e44fa9b3b6..1974731baa91 100644
@@ -329,6 +329,7 @@
 #define ID_AA64ISAR1_LRCPC_SHIFT	20
 #define ID_AA64ISAR1_FCMA_SHIFT		16
 #define ID_AA64ISAR1_JSCVT_SHIFT	12
+#define ID_AA64ISAR1_DPB_SHIFT		0
 
 /* id_aa64pfr0 */
 #define ID_AA64PFR0_GIC_SHIFT		24
arch/arm64/include/uapi/asm/hwcap.h +1 -0
index 4e187ce2a811..4b9344cba83a 100644
@@ -35,5 +35,6 @@
 #define HWCAP_JSCVT		(1 << 13)
 #define HWCAP_FCMA		(1 << 14)
 #define HWCAP_LRCPC		(1 << 15)
+#define HWCAP_DCPOP		(1 << 16)
 
 #endif /* _UAPI__ASM_HWCAP_H */
arch/arm64/kernel/cpufeature.c +2 -0
index 9f9e0064c8c1..a2542ef3ff25 100644
@@ -120,6 +120,7 @@ static const struct arm64_ftr_bits ftr_id_aa64isar1[] = {
 	ARM64_FTR_BITS(FTR_VISIBLE, FTR_STRICT, FTR_EXACT, ID_AA64ISAR1_LRCPC_SHIFT, 4, 0),
 	ARM64_FTR_BITS(FTR_VISIBLE, FTR_STRICT, FTR_EXACT, ID_AA64ISAR1_FCMA_SHIFT, 4, 0),
 	ARM64_FTR_BITS(FTR_VISIBLE, FTR_STRICT, FTR_EXACT, ID_AA64ISAR1_JSCVT_SHIFT, 4, 0),
+	ARM64_FTR_BITS(FTR_VISIBLE, FTR_STRICT, FTR_EXACT, ID_AA64ISAR1_DPB_SHIFT, 4, 0),
 	ARM64_FTR_END,
 };
 
@@ -916,6 +917,7 @@ static const struct arm64_cpu_capabilities arm64_elf_hwcaps[] = {
 	HWCAP_CAP(SYS_ID_AA64PFR0_EL1, ID_AA64PFR0_FP_SHIFT, FTR_SIGNED, 1, CAP_HWCAP, HWCAP_FPHP),
 	HWCAP_CAP(SYS_ID_AA64PFR0_EL1, ID_AA64PFR0_ASIMD_SHIFT, FTR_SIGNED, 0, CAP_HWCAP, HWCAP_ASIMD),
 	HWCAP_CAP(SYS_ID_AA64PFR0_EL1, ID_AA64PFR0_ASIMD_SHIFT, FTR_SIGNED, 1, CAP_HWCAP, HWCAP_ASIMDHP),
+	HWCAP_CAP(SYS_ID_AA64ISAR1_EL1, ID_AA64ISAR1_DPB_SHIFT, FTR_UNSIGNED, 1, CAP_HWCAP, HWCAP_DCPOP),
 	HWCAP_CAP(SYS_ID_AA64ISAR1_EL1, ID_AA64ISAR1_JSCVT_SHIFT, FTR_UNSIGNED, 1, CAP_HWCAP, HWCAP_JSCVT),
 	HWCAP_CAP(SYS_ID_AA64ISAR1_EL1, ID_AA64ISAR1_FCMA_SHIFT, FTR_UNSIGNED, 1, CAP_HWCAP, HWCAP_FCMA),
 	HWCAP_CAP(SYS_ID_AA64ISAR1_EL1, ID_AA64ISAR1_LRCPC_SHIFT, FTR_UNSIGNED, 1, CAP_HWCAP, HWCAP_LRCPC),
arch/arm64/kernel/cpuinfo.c +1 -0
index f495ee5049fd..311885962830 100644
@@ -68,6 +68,7 @@ static const char *const hwcap_str[] = {
 	"jscvt",
 	"fcma",
 	"lrcpc",
+	"dcpop",
 	NULL
 };
 
Signature · 6 lines
2.12.2.dirty

_______________________________________________
Linux-nvdimm mailing list
[email protected]
https://lists.01.org/mailman/listinfo/linux-nvdimm
#4 lore raw

PATCH 4/6 arm64: Handle trapped DC CVAP

In reply to Robin Murphy

Cache clean to PoP is subject to the same access controls as to PoC, so if we are trapping userspace cache maintenance with SCTLR_EL1.UCI, we need to be prepared to handle it. To avoid getting into complicated fights with binutils about ARMv8.2 options, we'll just cheat and use the raw SYS instruction rather than the 'proper' DC alias.

---
 arch/arm64/include/asm/esr.h | 3 ++-
 arch/arm64/kernel/traps.c    | 3 +++
 2 files changed, 5 insertions(+), 1 deletion(-)
arch/arm64/include/asm/esr.h +2 -1
index 8cabd57b6348..2636df9a4d6b 100644
@@ -157,9 +157,10 @@
 /*
  * User space cache operations have the following sysreg encoding
  * in System instructions.
- * op0=1, op1=3, op2=1, crn=7, crm={ 5, 10, 11, 14 }, WRITE (L=0)
+ * op0=1, op1=3, op2=1, crn=7, crm={ 5, 10, 11, 12, 14 }, WRITE (L=0)
  */
 #define ESR_ELx_SYS64_ISS_CRM_DC_CIVAC	14
+#define ESR_ELx_SYS64_ISS_CRM_DC_CVAP	12
 #define ESR_ELx_SYS64_ISS_CRM_DC_CVAU	11
 #define ESR_ELx_SYS64_ISS_CRM_DC_CVAC	10
 #define ESR_ELx_SYS64_ISS_CRM_IC_IVAU	5
arch/arm64/kernel/traps.c +3 -0
index c7c7088097be..dc53a8ba1882 100644
@@ -480,6 +480,9 @@ static void user_cache_maint_handler(unsigned int esr, struct pt_regs *regs)
 	case ESR_ELx_SYS64_ISS_CRM_DC_CVAC:	/* DC CVAC, gets promoted */
 		__user_cache_maint("dc civac", address, ret);
 		break;
+	case ESR_ELx_SYS64_ISS_CRM_DC_CVAP:	/* DC CVAP */
+		__user_cache_maint("sys 3, c7, c12, 1", address, ret);
+		break;
 	case ESR_ELx_SYS64_ISS_CRM_DC_CIVAC:	/* DC CIVAC */
 		__user_cache_maint("dc civac", address, ret);
 		break;
Signature · 6 lines
2.12.2.dirty

_______________________________________________
Linux-nvdimm mailing list
[email protected]
https://lists.01.org/mailman/listinfo/linux-nvdimm
#5 lore raw

PATCH 5/6 arm64: Implement pmem API support

In reply to Robin Murphy

Add a clean-to-point-of-persistence cache maintenance helper, and wire up the basic architectural support for the pmem driver based on it.

---
 arch/arm64/Kconfig                  | 11 +++++++++++
 arch/arm64/include/asm/assembler.h  |  6 ++++++
 arch/arm64/include/asm/cacheflush.h |  1 +
 arch/arm64/include/asm/cpucaps.h    |  3 ++-
 arch/arm64/kernel/cpufeature.c      | 11 +++++++++++
 arch/arm64/mm/cache.S               | 14 ++++++++++++++
 arch/arm64/mm/pageattr.c            | 18 ++++++++++++++++++
 7 files changed, 63 insertions(+), 1 deletion(-)
arch/arm64/Kconfig +11 -0
index dfd908630631..0b0576a54724 100644
@@ -960,6 +960,17 @@ config ARM64_UAO
 	  regular load/store instructions if the cpu does not implement the
 	  feature.
 
+config ARM64_PMEM
+	bool "Enable support for persistent memory"
+	select ARCH_HAS_PMEM_API
+	help
+	  Say Y to enable support for the persistent memory API based on the
+	  ARMv8.2 DCPoP feature.
+
+	  The feature is detected at runtime, and the kernel will use DC CVAC
+	  operations if DC CVAP is not supported (following the behaviour of
+	  DC CVAP itself if the system does not define a point of persistence).
+
 endmenu
 
 config ARM64_MODULE_CMODEL_LARGE
arch/arm64/include/asm/assembler.h +6 -0
index 1b67c3782d00..5d8903c45031 100644
@@ -353,6 +353,12 @@ alternative_if_not ARM64_WORKAROUND_CLEAN_CACHE
 alternative_else
 	dc	civac, \kaddr
 alternative_endif
+	.elseif	(\op == cvap)
+alternative_if ARM64_HAS_DCPOP
+	sys 3, c7, c12, 1, \kaddr	// dc cvap
+alternative_else
+	dc	cvac, \kaddr
+alternative_endif
 	.else
 	dc	\op, \kaddr
 	.endif
arch/arm64/include/asm/cacheflush.h +1 -0
index b4b43a94dffd..76d1cc85d5b1 100644
@@ -69,6 +69,7 @@ extern void flush_icache_range(unsigned long start, unsigned long end);
 extern void __flush_dcache_area(void *addr, size_t len);
 extern void __inval_dcache_area(void *addr, size_t len);
 extern void __clean_dcache_area_poc(void *addr, size_t len);
+extern void __clean_dcache_area_pop(void *addr, size_t len);
 extern void __clean_dcache_area_pou(void *addr, size_t len);
 extern long __flush_cache_user_range(unsigned long start, unsigned long end);
 extern void sync_icache_aliases(void *kaddr, unsigned long len);
arch/arm64/include/asm/cpucaps.h +2 -1
index 8d2272c6822c..8da621627d7c 100644
@@ -39,7 +39,8 @@
 #define ARM64_WORKAROUND_QCOM_FALKOR_E1003	18
 #define ARM64_WORKAROUND_858921			19
 #define ARM64_WORKAROUND_CAVIUM_30115		20
+#define ARM64_HAS_DCPOP				21
 
-#define ARM64_NCAPS				21
+#define ARM64_NCAPS				22
 
 #endif /* __ASM_CPUCAPS_H */
arch/arm64/kernel/cpufeature.c +11 -0
index a2542ef3ff25..cd52d365d1f0 100644
@@ -889,6 +889,17 @@ static const struct arm64_cpu_capabilities arm64_features[] = {
 		.min_field_value = 0,
 		.matches = has_no_fpsimd,
 	},
+#ifdef CONFIG_ARM64_PMEM
+	{
+		.desc = "Data cache clean to Point of Persistence",
+		.capability = ARM64_HAS_DCPOP,
+		.def_scope = SCOPE_SYSTEM,
+		.matches = has_cpuid_feature,
+		.sys_reg = SYS_ID_AA64ISAR1_EL1,
+		.field_pos = ID_AA64ISAR1_DPB_SHIFT,
+		.min_field_value = 1,
+	},
+#endif
 	{},
 };
 
arch/arm64/mm/cache.S +14 -0
index ed47fbbb4b05..7f1dbe962cf5 100644
@@ -172,6 +172,20 @@ ENDPIPROC(__clean_dcache_area_poc)
 ENDPROC(__dma_clean_area)
 
 /*
+ *	__clean_dcache_area_pop(kaddr, size)
+ *
+ * 	Ensure that any D-cache lines for the interval [kaddr, kaddr+size)
+ * 	are cleaned to the PoP.
+ *
+ *	- kaddr   - kernel address
+ *	- size    - size in question
+ */
+ENTRY(__clean_dcache_area_pop)
+	dcache_by_line_op cvap, sy, x0, x1, x2, x3
+	ret
+ENDPIPROC(__clean_dcache_area_pop)
+
+/*
  *	__dma_flush_area(start, size)
  *
  *	clean & invalidate D / U line
arch/arm64/mm/pageattr.c +18 -0
index a682a0a2a0fa..a461a00ceb3e 100644
@@ -183,3 +183,21 @@ bool kernel_page_present(struct page *page)
 }
 #endif /* CONFIG_HIBERNATION */
 #endif /* CONFIG_DEBUG_PAGEALLOC */
+
+#ifdef CONFIG_ARCH_HAS_PMEM_API
+#include <asm/cacheflush.h>
+
+static inline void arch_wb_cache_pmem(void *addr, size_t size)
+{
+	/* Ensure order against any prior non-cacheable writes */
+	dmb(sy);
+	__clean_dcache_area_pop(addr, size);
+}
+EXPORT_SYMBOL_GPL(arch_wb_cache_pmem);
+
+static inline void arch_invalidate_pmem(void *addr, size_t size)
+{
+	__inval_dcache_area(addr, size);
+}
+EXPORT_SYMBOL_GPL(arch_invalidate_pmem);
+#endif
Signature · 6 lines
2.12.2.dirty

_______________________________________________
Linux-nvdimm mailing list
[email protected]
https://lists.01.org/mailman/listinfo/linux-nvdimm
maintainer
#6 lore raw

PATCH 5/6 arm64: Implement pmem API support

Two minor comments below.

Quoted 6 lines · Robin Murphy
arch/arm64/Kconfig +0 -0
@@ -960,6 +960,17 @@ config ARM64_UAO
 	  regular load/store instructions if the cpu does not implement the
 	  feature.
 

arch/arm64/Kconfig config ARM64_UAO · line 972

Quoted 10 lines
arch/arm64/Kconfig +10 -0
+config ARM64_PMEM
+	bool "Enable support for persistent memory"
+	select ARCH_HAS_PMEM_API
+	help
+	  Say Y to enable support for the persistent memory API based on the
+	  ARMv8.2 DCPoP feature.
+
+	  The feature is detected at runtime, and the kernel will use DC CVAC
+	  operations if DC CVAP is not supported (following the behaviour of
+	  DC CVAP itself if the system does not define a point of persistence).

Any reason not to have this default y?

Quoted 31 lines
arch/arm64/mm/cache.S +14 -0
@@ -172,6 +172,20 @@ ENDPIPROC(__clean_dcache_area_poc)
 ENDPROC(__dma_clean_area)
 
 /*
+ *	__clean_dcache_area_pop(kaddr, size)
+ *
+ * 	Ensure that any D-cache lines for the interval [kaddr, kaddr+size)
+ * 	are cleaned to the PoP.
+ *
+ *	- kaddr   - kernel address
+ *	- size    - size in question
+ */
+ENTRY(__clean_dcache_area_pop)
+	dcache_by_line_op cvap, sy, x0, x1, x2, x3
+	ret
+ENDPIPROC(__clean_dcache_area_pop)
+
+/*
  *	__dma_flush_area(start, size)
  *
  *	clean & invalidate D / U line
arch/arm64/mm/pageattr.c +0 -0
index a682a0a2a0fa..a461a00ceb3e 100644
@@ -183,3 +183,21 @@ bool kernel_page_present(struct page *page)
 }
 #endif /* CONFIG_HIBERNATION */
 #endif /* CONFIG_DEBUG_PAGEALLOC */

arch/arm64/mm/pageattr.c bool kernel_page_present(struct page *page) · line 195

Quoted 10 lines
arch/arm64/mm/pageattr.c +10 -0
+
+#ifdef CONFIG_ARCH_HAS_PMEM_API
+#include <asm/cacheflush.h>
+
+static inline void arch_wb_cache_pmem(void *addr, size_t size)
+{
+	/* Ensure order against any prior non-cacheable writes */
+	dmb(sy);
+	__clean_dcache_area_pop(addr, size);
+}

Could we keep the dmb() in the actual __clean_dcache_area_pop() implementation?

I can do the changes myself if you don't have any objections.

Signature · 5 lines
Catalin
_______________________________________________
Linux-nvdimm mailing list
[email protected]
https://lists.01.org/mailman/listinfo/linux-nvdimm
#7 lore raw

PATCH 5/6 arm64: Implement pmem API support

Quoted 9 lines · Catalin Marinas

Two minor comments below.

Quoted 6 lines · Robin Murphy
arch/arm64/Kconfig +0 -0
@@ -960,6 +960,17 @@ config ARM64_UAO
 	  regular load/store instructions if the cpu does not implement the
 	  feature.
 
Quoted 12 lines

arch/arm64/Kconfig config ARM64_UAO · line 972

Quoted 10 lines
arch/arm64/Kconfig +10 -0
+config ARM64_PMEM
+	bool "Enable support for persistent memory"
+	select ARCH_HAS_PMEM_API
+	help
+	  Say Y to enable support for the persistent memory API based on the
+	  ARMv8.2 DCPoP feature.
+
+	  The feature is detected at runtime, and the kernel will use DC CVAC
+	  operations if DC CVAP is not supported (following the behaviour of
+	  DC CVAP itself if the system does not define a point of persistence).

Any reason not to have this default y?

Mostly because it's untested, and not actually useful without some way of describing persistent memory regions to the kernel (I'm currently trying to make sense of what exactly ARCH_HAS_MMIO_FLUSH is supposed to mean in order to enable ACPI NFIT support).

There's also the potential issue that we can't disable ARCH_HAS_PMEM_API at runtime on pre-v8.2 systems where DC CVAC may not strictly give the guarantee of persistence that that is supposed to imply. However, I guess that's more of an open problem, since even on a v8.2 CPU reporting (mandatory) DC CVAP support we've still no way to actually know whether the interconnect/memory controller/etc. of any old system is up to the job. At this point I'm mostly hoping that people will only be sticking NVDIMMs into systems that *are* properly designed to support them, v8.2 CPUs or not.

Quoted 36 lines
Quoted 36 lines
arch/arm64/mm/cache.S +14 -0
@@ -172,6 +172,20 @@ ENDPIPROC(__clean_dcache_area_poc)
 ENDPROC(__dma_clean_area)
 
 /*
+ *	__clean_dcache_area_pop(kaddr, size)
+ *
+ * 	Ensure that any D-cache lines for the interval [kaddr, kaddr+size)
+ * 	are cleaned to the PoP.
+ *
+ *	- kaddr   - kernel address
+ *	- size    - size in question
+ */
+ENTRY(__clean_dcache_area_pop)
+	dcache_by_line_op cvap, sy, x0, x1, x2, x3
+	ret
+ENDPIPROC(__clean_dcache_area_pop)
+
+/*
  *	__dma_flush_area(start, size)
  *
  *	clean & invalidate D / U line
arch/arm64/mm/pageattr.c +5 -0
index a682a0a2a0fa..a461a00ceb3e 100644
@@ -183,3 +183,21 @@ bool kernel_page_present(struct page *page)
 }
 #endif /* CONFIG_HIBERNATION */
 #endif /* CONFIG_DEBUG_PAGEALLOC */
+
+#ifdef CONFIG_ARCH_HAS_PMEM_API
+#include <asm/cacheflush.h>
+
+static inline void arch_wb_cache_pmem(void *addr, size_t size)
Quoted 8 lines

arch/arm64/mm/pageattr.c bool kernel_page_present(struct page *page) · line 195

Quoted 5 lines
arch/arm64/mm/pageattr.c +5 -0
+{
+	/* Ensure order against any prior non-cacheable writes */
+	dmb(sy);
+	__clean_dcache_area_pop(addr, size);
+}

Could we keep the dmb() in the actual __clean_dcache_area_pop() implementation?

Mark held the opinion that it should follow the same pattern as the other cache maintenance primitives - e.g. we don't have such a dmb in __inval_cache_range(), but do place them at callsites where we know it may be necessary (head.S) - and I found it hard to disagree. The callers in patch #6 should never need a barrier, and arguably we may not even need this one, since it looks like pmem should currently always be mapped as MEMREMAP_WB if ARCH_HAS_PMEM_API.

Quoted 1 line

I can do the changes myself if you don't have any objections.

If you would prefer to play safe and move it back into the assembly that's fine by me, but note that the associated comments in patch #6 should also be removed if so.

Robin.
_______________________________________________
Linux-nvdimm mailing list
[email protected]
https://lists.01.org/mailman/listinfo/linux-nvdimm

#8 lore raw

PATCH 5/6 arm64: Implement pmem API support

Quoted 23 lines · Robin Murphy
Quoted 9 lines · Catalin Marinas

Two minor comments below.

Quoted 6 lines · Robin Murphy
arch/arm64/Kconfig +0 -0
@@ -960,6 +960,17 @@ config ARM64_UAO
       regular load/store instructions if the cpu does not implement the
       feature.
 
Quoted 12 lines

arch/arm64/Kconfig config ARM64_UAO · line 972

Quoted 10 lines
arch/arm64/Kconfig +10 -0
+config ARM64_PMEM
+    bool "Enable support for persistent memory"
+    select ARCH_HAS_PMEM_API
+    help
+      Say Y to enable support for the persistent memory API based on the
+      ARMv8.2 DCPoP feature.
+
+      The feature is detected at runtime, and the kernel will use DC CVAC
+      operations if DC CVAP is not supported (following the behaviour of
+      DC CVAP itself if the system does not define a point of persistence).

Any reason not to have this default y?

Quoted 4 lines

Mostly because it's untested, and not actually useful without some way of describing persistent memory regions to the kernel (I'm currently trying to make sense of what exactly ARCH_HAS_MMIO_FLUSH is supposed to mean in order to enable ACPI NFIT support).

This is related to block-aperture support described by the NFIT where a sliding-memory-mapped window can be programmed to access different ranges of the NVDIMM. Before the window is programmed to a new DIMM-address we need to flush any dirty data through the current window setting to media. See the call to mmio_flush_range() in acpi_nfit_blk_single_io(). I think it's ok to omit ARCH_HAS_MMIO_FLUSH support, and add a configuration option to compile out the block-aperture support.
_______________________________________________
Linux-nvdimm mailing list
[email protected]
https://lists.01.org/mailman/listinfo/linux-nvdimm

#9 lore raw

PATCH 5/6 arm64: Implement pmem API support

Quoted 29 lines · Dan Williams
Quoted 23 lines · Robin Murphy
Quoted 9 lines · Catalin Marinas

Two minor comments below.

Quoted 6 lines · Robin Murphy
arch/arm64/Kconfig +0 -0
@@ -960,6 +960,17 @@ config ARM64_UAO
       regular load/store instructions if the cpu does not implement the
       feature.
 
Quoted 12 lines

arch/arm64/Kconfig config ARM64_UAO · line 972

Quoted 10 lines
arch/arm64/Kconfig +10 -0
+config ARM64_PMEM
+    bool "Enable support for persistent memory"
+    select ARCH_HAS_PMEM_API
+    help
+      Say Y to enable support for the persistent memory API based on the
+      ARMv8.2 DCPoP feature.
+
+      The feature is detected at runtime, and the kernel will use DC CVAC
+      operations if DC CVAP is not supported (following the behaviour of
+      DC CVAP itself if the system does not define a point of persistence).

Any reason not to have this default y?

Quoted 4 lines

Mostly because it's untested, and not actually useful without some way of describing persistent memory regions to the kernel (I'm currently trying to make sense of what exactly ARCH_HAS_MMIO_FLUSH is supposed to mean in order to enable ACPI NFIT support).

Quoted 8 lines

This is related to block-aperture support described by the NFIT where a sliding-memory-mapped window can be programmed to access different ranges of the NVDIMM. Before the window is programmed to a new DIMM-address we need to flush any dirty data through the current window setting to media. See the call to mmio_flush_range() in acpi_nfit_blk_single_io(). I think it's ok to omit ARCH_HAS_MMIO_FLUSH support, and add a configuration option to compile out the block-aperture support.

Oh, I have every intention of implementing it one way or another if necessary - it's not difficult, it's just been a question of working through the NFIT code to figure out the subtleties of translation to arm64 ;)

If mmio_flush_range() is for true MMIO (i.e. __iomem) mappings, then arm64 should only need a barrier, rather than actual cache operations. If on the other hand it's misleadingly named and only actually used on MEMREMAP_WB mappings (as I'm staring to think it might be), then I can't help thinking it could simply go away in favour of arch_wb_pmem(), since that now seems to have those same semantics and intent, plus a much more appropriate name.

Robin.
_______________________________________________
Linux-nvdimm mailing list
[email protected]
https://lists.01.org/mailman/listinfo/linux-nvdimm

#10 lore raw

PATCH 5/6 arm64: Implement pmem API support

Quoted 44 lines · Robin Murphy
Quoted 29 lines · Dan Williams
Quoted 23 lines · Robin Murphy
Quoted 9 lines · Catalin Marinas

Two minor comments below.

Quoted 6 lines · Robin Murphy
arch/arm64/Kconfig +0 -0
@@ -960,6 +960,17 @@ config ARM64_UAO
       regular load/store instructions if the cpu does not implement the
       feature.
 
Quoted 12 lines

arch/arm64/Kconfig config ARM64_UAO · line 972

Quoted 10 lines
arch/arm64/Kconfig +10 -0
+config ARM64_PMEM
+    bool "Enable support for persistent memory"
+    select ARCH_HAS_PMEM_API
+    help
+      Say Y to enable support for the persistent memory API based on the
+      ARMv8.2 DCPoP feature.
+
+      The feature is detected at runtime, and the kernel will use DC CVAC
+      operations if DC CVAP is not supported (following the behaviour of
+      DC CVAP itself if the system does not define a point of persistence).

Any reason not to have this default y?

Quoted 4 lines

Mostly because it's untested, and not actually useful without some way of describing persistent memory regions to the kernel (I'm currently trying to make sense of what exactly ARCH_HAS_MMIO_FLUSH is supposed to mean in order to enable ACPI NFIT support).

Quoted 8 lines

This is related to block-aperture support described by the NFIT where a sliding-memory-mapped window can be programmed to access different ranges of the NVDIMM. Before the window is programmed to a new DIMM-address we need to flush any dirty data through the current window setting to media. See the call to mmio_flush_range() in acpi_nfit_blk_single_io(). I think it's ok to omit ARCH_HAS_MMIO_FLUSH support, and add a configuration option to compile out the block-aperture support.

Oh, I have every intention of implementing it one way or another if necessary - it's not difficult, it's just been a question of working through the NFIT code to figure out the subtleties of translation to arm64 ;)

Quoted 8 lines

If mmio_flush_range() is for true MMIO (i.e. __iomem) mappings, then arm64 should only need a barrier, rather than actual cache operations. If on the other hand it's misleadingly named and only actually used on MEMREMAP_WB mappings (as I'm staring to think it might be), then I can't help thinking it could simply go away in favour of arch_wb_pmem(), since that now seems to have those same semantics and intent, plus a much more appropriate name.

The mapping type of block-apertures is up to the architecture, so you could mark them uncacheable and not worry about mmio_flush_range(). Also, arch_wb_pmem() is not a replacement for mmio_flush_range() since we also need the cache to be invalidated. arch_wb_pmem() is allowed to leave clean cache lines present.
_______________________________________________
Linux-nvdimm mailing list
[email protected]
https://lists.01.org/mailman/listinfo/linux-nvdimm

#11 lore raw

PATCH 5/6 arm64: Implement pmem API support

In reply to Catalin Marinas
Quoted 67 lines · Catalin Marinas

Two minor comments below.

Quoted 6 lines · Robin Murphy
arch/arm64/Kconfig +0 -0
@@ -960,6 +960,17 @@ config ARM64_UAO
 	  regular load/store instructions if the cpu does not implement the
 	  feature.
 

arch/arm64/Kconfig config ARM64_UAO · line 972

Quoted 10 lines
arch/arm64/Kconfig +10 -0
+config ARM64_PMEM
+	bool "Enable support for persistent memory"
+	select ARCH_HAS_PMEM_API
+	help
+	  Say Y to enable support for the persistent memory API based on the
+	  ARMv8.2 DCPoP feature.
+
+	  The feature is detected at runtime, and the kernel will use DC CVAC
+	  operations if DC CVAP is not supported (following the behaviour of
+	  DC CVAP itself if the system does not define a point of persistence).

Any reason not to have this default y?

Quoted 31 lines
arch/arm64/mm/cache.S +14 -0
@@ -172,6 +172,20 @@ ENDPIPROC(__clean_dcache_area_poc)
 ENDPROC(__dma_clean_area)
 
 /*
+ *	__clean_dcache_area_pop(kaddr, size)
+ *
+ * 	Ensure that any D-cache lines for the interval [kaddr, kaddr+size)
+ * 	are cleaned to the PoP.
+ *
+ *	- kaddr   - kernel address
+ *	- size    - size in question
+ */
+ENTRY(__clean_dcache_area_pop)
+	dcache_by_line_op cvap, sy, x0, x1, x2, x3
+	ret
+ENDPIPROC(__clean_dcache_area_pop)
+
+/*
  *	__dma_flush_area(start, size)
  *
  *	clean & invalidate D / U line
arch/arm64/mm/pageattr.c +0 -0
index a682a0a2a0fa..a461a00ceb3e 100644
@@ -183,3 +183,21 @@ bool kernel_page_present(struct page *page)
 }
 #endif /* CONFIG_HIBERNATION */
 #endif /* CONFIG_DEBUG_PAGEALLOC */

arch/arm64/mm/pageattr.c bool kernel_page_present(struct page *page) · line 195

Quoted 10 lines
arch/arm64/mm/pageattr.c +10 -0
+
+#ifdef CONFIG_ARCH_HAS_PMEM_API
+#include <asm/cacheflush.h>
+
+static inline void arch_wb_cache_pmem(void *addr, size_t size)
+{
+	/* Ensure order against any prior non-cacheable writes */
+	dmb(sy);
+	__clean_dcache_area_pop(addr, size);
+}

Could we keep the dmb() in the actual __clean_dcache_area_pop() implementation?

Quoted 1 line

I can do the changes myself if you don't have any objections.

I *think* the DMB can also be reworked to use the outer-shareable domain, much as we do for the dma_* barriers.

Will
_______________________________________________
Linux-nvdimm mailing list
[email protected]
https://lists.01.org/mailman/listinfo/linux-nvdimm

#12 lore raw

PATCH 6/6 arm64: uaccess: Implement *_flushcache variants

In reply to Robin Murphy

Implement the set of copy functions with guarantees of a clean cache upon completion necessary to support the pmem driver.

---
 arch/arm64/Kconfig                  |  1 +
 arch/arm64/include/asm/string.h     |  4 ++++
 arch/arm64/include/asm/uaccess.h    | 12 ++++++++++
 arch/arm64/lib/Makefile             |  2 ++
 arch/arm64/lib/uaccess_flushcache.c | 47 +++++++++++++++++++++++++++++++++++++
 5 files changed, 66 insertions(+)
 create mode 100644 arch/arm64/lib/uaccess_flushcache.c
arch/arm64/Kconfig +1 -0
index 0b0576a54724..e43a63b3d14b 100644
@@ -963,6 +963,7 @@ config ARM64_UAO
 config ARM64_PMEM
 	bool "Enable support for persistent memory"
 	select ARCH_HAS_PMEM_API
+	select ARCH_HAS_UACCESS_FLUSHCACHE
 	help
 	  Say Y to enable support for the persistent memory API based on the
 	  ARMv8.2 DCPoP feature.
arch/arm64/include/asm/string.h +4 -0
index d0aa42907569..dd95d33a5bd5 100644
@@ -52,6 +52,10 @@ extern void *__memset(void *, int, __kernel_size_t);
 #define __HAVE_ARCH_MEMCMP
 extern int memcmp(const void *, const void *, size_t);
 
+#ifdef CONFIG_ARCH_HAS_UACCESS_FLUSHCACHE
+#define __HAVE_ARCH_MEMCPY_FLUSHCACHE
+void memcpy_flushcache(void *dst, const void *src, size_t cnt);
+#endif
 
 #if defined(CONFIG_KASAN) && !defined(__SANITIZE_ADDRESS__)
 
arch/arm64/include/asm/uaccess.h +12 -0
index 8f0a1de11e4a..bb056fee297c 100644
@@ -347,4 +347,16 @@ extern long strncpy_from_user(char *dest, const char __user *src, long count);
 
 extern __must_check long strnlen_user(const char __user *str, long n);
 
+#ifdef CONFIG_ARCH_HAS_UACCESS_FLUSHCACHE
+struct page;
+void memcpy_page_flushcache(char *to, struct page *page, size_t offset, size_t len);
+extern unsigned long __must_check __copy_user_flushcache(void *to, const void __user *from, unsigned long n);
+
+static inline int __copy_from_user_flushcache(void *dst, const void __user *src, unsigned size)
+{
+	kasan_check_write(dst, size);
+	return __copy_user_flushcache(dst, src, size);
+}
+#endif
+
 #endif /* __ASM_UACCESS_H */
arch/arm64/lib/Makefile +2 -0
index c86b7909ef31..a0abc142c92b 100644
@@ -17,3 +17,5 @@ CFLAGS_atomic_ll_sc.o	:= -fcall-used-x0 -ffixed-x1 -ffixed-x2		\
 		   -fcall-saved-x10 -fcall-saved-x11 -fcall-saved-x12	\
 		   -fcall-saved-x13 -fcall-saved-x14 -fcall-saved-x15	\
 		   -fcall-saved-x18
+
+lib-$(CONFIG_ARCH_HAS_UACCESS_FLUSHCACHE) += uaccess_flushcache.o
arch/arm64/lib/uaccess_flushcache.c new file +47 -0

47 lines not on this page · raw message

Signature · 6 lines
2.12.2.dirty

_______________________________________________
Linux-nvdimm mailing list
[email protected]
https://lists.01.org/mailman/listinfo/linux-nvdimm
#13 lore raw

PATCH 6/6 arm64: uaccess: Implement *_flushcache variants

Quoted 12 lines · Robin Murphy

Implement the set of copy functions with guarantees of a clean cache upon completion necessary to support the pmem driver.

---
 arch/arm64/Kconfig                  |  1 +
 arch/arm64/include/asm/string.h     |  4 ++++
 arch/arm64/include/asm/uaccess.h    | 12 ++++++++++
 arch/arm64/lib/Makefile             |  2 ++
 arch/arm64/lib/uaccess_flushcache.c | 47 +++++++++++++++++++++++++++++++++++++
 5 files changed, 66 insertions(+)
 create mode 100644 arch/arm64/lib/uaccess_flushcache.c

[...]

Quoted 38 lines
arch/arm64/lib/uaccess_flushcache.c new file +32 -0
new file mode 100644
index 000000000000..b6ceafdb8b72
@@ -0,0 +1,47 @@
+/*
+ * Copyright (C) 2017 ARM Ltd.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program.  If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include <linux/uaccess.h>
+#include <asm/barrier.h>
+#include <asm/cacheflush.h>
+
+void memcpy_flushcache(void *dst, const void *src, size_t cnt)
+{
+	/*
+	 * We assume this should not be called with @dst pointing to
+	 * non-cacheable memory, such that we don't need an explicit
+	 * barrier to order the cache maintenance against the memcpy.
+	 */
+	memcpy(dst, src, cnt);
+	__clean_dcache_area_pop(dst, cnt);
+}
+EXPORT_SYMBOL_GPL(memcpy_flushcache);
+

arch/arm64/lib/uaccess_flushcache.c line 42

Quoted 10 lines
arch/arm64/lib/uaccess_flushcache.c new file +10 -0
+void memcpy_page_flushcache(char *to, struct page *page, size_t offset,
+			    size_t len)
+{
+	memcpy_flushcache(to, page_address(page) + offset, len);
+}
+
+unsigned long __copy_user_flushcache(void *to, const void __user *from,
+				     unsigned long n)
+{
+	unsigned long rc = __arch_copy_from_user(to, from, n);

I'm a bit nervous calling the bare user accessor here without an access_ok check beforehand. Can we rely on the caller having done the check for us? I tried to follow the breadcrumbs back out, but I noticed that other iov iterators (such as copy_from_iter) *do* do the bounds check, whereas the pmem version (copy_from_iter_nocache) doesn't appear to check the address.

Is that right?

Will
_______________________________________________
Linux-nvdimm mailing list
[email protected]
https://lists.01.org/mailman/listinfo/linux-nvdimm

#14 lore raw

PATCH 6/6 arm64: uaccess: Implement *_flushcache variants

In reply to Robin Murphy
Quoted 4 lines · Robin Murphy

Implement the set of copy functions with guarantees of a clean cache upon completion necessary to support the pmem driver.

Quoted 8 lines
---
 arch/arm64/Kconfig                  |  1 +
 arch/arm64/include/asm/string.h     |  4 ++++
 arch/arm64/include/asm/uaccess.h    | 12 ++++++++++
 arch/arm64/lib/Makefile             |  2 ++
 arch/arm64/lib/uaccess_flushcache.c | 47 +++++++++++++++++++++++++++++++++++++
 5 files changed, 66 insertions(+)
 create mode 100644 arch/arm64/lib/uaccess_flushcache.c

It looks like Catalin applied part of this patch but forgot to add arch/arm64/lib/uaccess_flushcache.c

Arnd
_______________________________________________
Linux-nvdimm mailing list
[email protected]
https://lists.01.org/mailman/listinfo/linux-nvdimm

maintainer
#15 lore raw

PATCH 6/6 arm64: uaccess: Implement *_flushcache variants

Quoted 14 lines · Arnd Bergmann
Quoted 4 lines · Robin Murphy

Implement the set of copy functions with guarantees of a clean cache upon completion necessary to support the pmem driver.

Quoted 8 lines
---
 arch/arm64/Kconfig                  |  1 +
 arch/arm64/include/asm/string.h     |  4 ++++
 arch/arm64/include/asm/uaccess.h    | 12 ++++++++++
 arch/arm64/lib/Makefile             |  2 ++
 arch/arm64/lib/uaccess_flushcache.c | 47 +++++++++++++++++++++++++++++++++++++
 5 files changed, 66 insertions(+)
 create mode 100644 arch/arm64/lib/uaccess_flushcache.c
Quoted 2 lines

It looks like Catalin applied part of this patch but forgot to add arch/arm64/lib/uaccess_flushcache.c

Added it now, thanks.

Signature · 5 lines
Catalin
_______________________________________________
Linux-nvdimm mailing list
[email protected]
https://lists.01.org/mailman/listinfo/linux-nvdimm
#16 lore raw

cover arm64 pmem support

In reply to Robin Murphy
Quoted 10 lines · Robin Murphy

With the latest updates to the pmem API, the arch code contribution becomes very straightforward to wire up - I think there's about as much code here to just cope with the existence of our new instruction as there is to actually make use of it. I don't have access to any NVDIMMs nor suitable hardware to put them in, so this is written purely to spec - the extent of testing has been the feature detection on a v8.2 Fast Model vs. v8.0 systems.

Patch #1 could go in as a fix ahead of the rest; it just needs to come before patch #5 to prevent that blowing up the build.

Modulo my two comments:

Will
_______________________________________________
Linux-nvdimm mailing list
[email protected]
https://lists.01.org/mailman/listinfo/linux-nvdimm