[PATCH] selftests/powerpc: Add a test of a simple copy/paste

Michael Ellerman mpe at ellerman.id.au
Wed Jun 7 15:14:06 AEST 2017


Power9 has two new instructions, copy and paste, which copy a cacheline
and then paste it somewhere.

We already have a test that the kernel correctly aborts the copy on
context switch, but we don't have a simple test to confirm copy/paste
itself actually works. So add one.

Signed-off-by: Michael Ellerman <mpe at ellerman.id.au>
---
 .../selftests/powerpc/context_switch/.gitignore    |   1 +
 .../selftests/powerpc/context_switch/Makefile      |   2 +-
 .../selftests/powerpc/context_switch/copy_paste.c  | 108 +++++++++++++++++++++
 3 files changed, 110 insertions(+), 1 deletion(-)
 create mode 100644 tools/testing/selftests/powerpc/context_switch/copy_paste.c

diff --git a/tools/testing/selftests/powerpc/context_switch/.gitignore b/tools/testing/selftests/powerpc/context_switch/.gitignore
index c1431af7b51c..6018c777e537 100644
--- a/tools/testing/selftests/powerpc/context_switch/.gitignore
+++ b/tools/testing/selftests/powerpc/context_switch/.gitignore
@@ -1 +1,2 @@
 cp_abort
+copy_paste
diff --git a/tools/testing/selftests/powerpc/context_switch/Makefile b/tools/testing/selftests/powerpc/context_switch/Makefile
index e9351bb4285d..f5ba79c6c3d1 100644
--- a/tools/testing/selftests/powerpc/context_switch/Makefile
+++ b/tools/testing/selftests/powerpc/context_switch/Makefile
@@ -1,4 +1,4 @@
-TEST_GEN_PROGS := cp_abort
+TEST_GEN_PROGS := cp_abort copy_paste
 
 include ../../lib.mk
 
diff --git a/tools/testing/selftests/powerpc/context_switch/copy_paste.c b/tools/testing/selftests/powerpc/context_switch/copy_paste.c
new file mode 100644
index 000000000000..0695c340bc82
--- /dev/null
+++ b/tools/testing/selftests/powerpc/context_switch/copy_paste.c
@@ -0,0 +1,108 @@
+/*
+ * Copyright 2016, Mikey Neuling, Chris Smart, IBM Corporation.
+ * Copyright 2017, Michael Ellerman, IBM Corporation.
+ *
+ * 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.
+ *
+ * Check that copy/paste works on Power9.
+ */
+
+#define _GNU_SOURCE
+
+#include <errno.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+
+#include "utils.h"
+
+
+#define NUM_LOOPS 1000
+
+
+/* This defines the "paste" instruction from Power ISA 3.0 Book II, section 4.4. */
+#define PASTE(RA, RB, L, RC) \
+	.long (0x7c00070c | (RA) << (31-15) | (RB) << (31-20) | (L) << (31-10) | (RC) << (31-31))
+
+int paste(void *i)
+{
+	int cr;
+
+	asm volatile(str(PASTE(0, %1, 1, 1))";"
+			"mfcr %0;"
+			: "=r" (cr)
+			: "b" (i)
+			: "memory"
+		    );
+	return cr;
+}
+
+/* This defines the "copy" instruction from Power ISA 3.0 Book II, section 4.4. */
+#define COPY(RA, RB, L) \
+	.long (0x7c00060c | (RA) << (31-15) | (RB) << (31-20) | (L) << (31-10))
+
+void copy(void *i)
+{
+	asm volatile(str(COPY(0, %0, 1))";"
+			:
+			: "b" (i)
+			: "memory"
+		    );
+}
+
+int test_copy_paste(void)
+{
+	/* 128 bytes for a full cache line */
+	char orig[128] __cacheline_aligned;
+	char src[128] __cacheline_aligned;
+	char dst[128] __cacheline_aligned;
+	int rc;
+
+	/* only run this test on a P9 or later */
+	SKIP_IF(!have_hwcap2(PPC_FEATURE2_ARCH_3_00));
+
+	memset(orig, 0x5a, sizeof(orig));
+	memset(src, 0x5a, sizeof(src));
+	memset(dst, 0x00, sizeof(dst));
+
+	/* Confirm orig and src match */
+	FAIL_IF(0 != memcmp(orig, src, sizeof(orig)));
+
+	/* Confirm src & dst are different */
+	FAIL_IF(0 == memcmp(src, dst, sizeof(src)));
+
+	/*
+	 * Paste can fail, eg. if we get context switched, so we do the
+	 * copy/paste in a loop and fail the test if it never succeeds.
+	 */
+	for (int i = 0; i < NUM_LOOPS; i++) {
+		copy(src);
+		rc = paste(dst);
+
+		/* A paste succeeds if CR0 EQ bit is set */
+		if (rc & 0x20000000) {
+			rc = 0;
+			break;
+		}
+		rc = EAGAIN;
+	}
+
+	FAIL_IF(rc);
+
+	/* Confirm orig and src still match */
+	FAIL_IF(0 != memcmp(orig, src, sizeof(orig)));
+
+	/* And that src and dst now match */
+	FAIL_IF(0 != memcmp(src, dst, sizeof(src)));
+
+	return 0;
+}
+
+int main(int argc, char *argv[])
+{
+	return test_harness(test_copy_paste, "copy_paste");
+}
-- 
2.7.4



More information about the Linuxppc-dev mailing list