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 <[email protected]> --- .../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
