selftests/powerpc: Load Monitor Register Tests
authorJack Miller <jack@codezen.org>
Thu, 9 Jun 2016 02:31:10 +0000 (12:31 +1000)
committerMichael Ellerman <mpe@ellerman.id.au>
Tue, 21 Jun 2016 05:30:50 +0000 (15:30 +1000)
Adds two tests. One is a simple test to ensure that the new registers
LMRR and LMSER are properly maintained. The other actually uses the
existing EBB test infrastructure to test that LMRR and LMSER behave as
documented.

Signed-off-by: Jack Miller <jack@codezen.org>
Signed-off-by: Michael Neuling <mikey@neuling.org>
Signed-off-by: Michael Ellerman <mpe@ellerman.id.au>
tools/testing/selftests/powerpc/pmu/ebb/.gitignore
tools/testing/selftests/powerpc/pmu/ebb/Makefile
tools/testing/selftests/powerpc/pmu/ebb/ebb_lmr.c [new file with mode: 0644]
tools/testing/selftests/powerpc/pmu/ebb/ebb_lmr.h [new file with mode: 0644]
tools/testing/selftests/powerpc/pmu/ebb/ebb_lmr_regs.c [new file with mode: 0644]
tools/testing/selftests/powerpc/reg.h

index 42bddbed8b6464bf3bb774f471376ac8f832d2a1..44b7df14a9368db88ea3bca3e144f0b740c12151 100644 (file)
@@ -20,3 +20,5 @@ back_to_back_ebbs_test
 lost_exception_test
 no_handler_test
 cycles_with_mmcr2_test
+ebb_lmr
+ebb_lmr_regs
\ No newline at end of file
index 8d2279c4bb4b6a81cb5713f6ba3bf92b72f2e3e7..6b0453e60d531d7bef149cc47041c58332d83b5d 100644 (file)
@@ -14,7 +14,7 @@ TEST_PROGS := reg_access_test event_attributes_test cycles_test       \
         fork_cleanup_test ebb_on_child_test                    \
         ebb_on_willing_child_test back_to_back_ebbs_test       \
         lost_exception_test no_handler_test                    \
-        cycles_with_mmcr2_test
+        cycles_with_mmcr2_test ebb_lmr ebb_lmr_regs
 
 all: $(TEST_PROGS)
 
diff --git a/tools/testing/selftests/powerpc/pmu/ebb/ebb_lmr.c b/tools/testing/selftests/powerpc/pmu/ebb/ebb_lmr.c
new file mode 100644 (file)
index 0000000..c47ebd5
--- /dev/null
@@ -0,0 +1,143 @@
+/*
+ * Copyright 2016, Jack Miller, IBM Corp.
+ * Licensed under GPLv2.
+ */
+
+#include <stdlib.h>
+#include <stdio.h>
+
+#include "ebb.h"
+#include "ebb_lmr.h"
+
+#define SIZE           (32 * 1024 * 1024)      /* 32M */
+#define LM_SIZE                0       /* Smallest encoding, 32M */
+
+#define SECTIONS       64      /* 1 per bit in LMSER */
+#define SECTION_SIZE   (SIZE / SECTIONS)
+#define SECTION_LONGS   (SECTION_SIZE / sizeof(long))
+
+static unsigned long *test_mem;
+
+static int lmr_count = 0;
+
+void ebb_lmr_handler(void)
+{
+       lmr_count++;
+}
+
+void ldmx_full_section(unsigned long *mem, int section)
+{
+       unsigned long *ptr;
+       int i;
+
+       for (i = 0; i < SECTION_LONGS; i++) {
+               ptr = &mem[(SECTION_LONGS * section) + i];
+               ldmx((unsigned long) &ptr);
+               ebb_lmr_reset();
+       }
+}
+
+unsigned long section_masks[] = {
+       0x8000000000000000,
+       0xFF00000000000000,
+       0x0000000F70000000,
+       0x8000000000000001,
+       0xF0F0F0F0F0F0F0F0,
+       0x0F0F0F0F0F0F0F0F,
+       0x0
+};
+
+int ebb_lmr_section_test(unsigned long *mem)
+{
+       unsigned long *mask = section_masks;
+       int i;
+
+       for (; *mask; mask++) {
+               mtspr(SPRN_LMSER, *mask);
+               printf("Testing mask 0x%016lx\n", mfspr(SPRN_LMSER));
+
+               for (i = 0; i < 64; i++) {
+                       lmr_count = 0;
+                       ldmx_full_section(mem, i);
+                       if (*mask & (1UL << (63 - i)))
+                               FAIL_IF(lmr_count != SECTION_LONGS);
+                       else
+                               FAIL_IF(lmr_count);
+               }
+       }
+
+       return 0;
+}
+
+int ebb_lmr(void)
+{
+       int i;
+
+       SKIP_IF(!lmr_is_supported());
+
+       setup_ebb_handler(ebb_lmr_handler);
+
+       ebb_global_enable();
+
+       FAIL_IF(posix_memalign((void **)&test_mem, SIZE, SIZE) != 0);
+
+       mtspr(SPRN_LMSER, 0);
+
+       FAIL_IF(mfspr(SPRN_LMSER) != 0);
+
+       mtspr(SPRN_LMRR, ((unsigned long)test_mem | LM_SIZE));
+
+       FAIL_IF(mfspr(SPRN_LMRR) != ((unsigned long)test_mem | LM_SIZE));
+
+       /* Read every single byte to ensure we get no false positives */
+       for (i = 0; i < SECTIONS; i++)
+               ldmx_full_section(test_mem, i);
+
+       FAIL_IF(lmr_count != 0);
+
+       /* Turn on the first section */
+
+       mtspr(SPRN_LMSER, (1UL << 63));
+       FAIL_IF(mfspr(SPRN_LMSER) != (1UL << 63));
+
+       /* Enable LM (BESCR) */
+
+       mtspr(SPRN_BESCR, mfspr(SPRN_BESCR) | BESCR_LME);
+       FAIL_IF(!(mfspr(SPRN_BESCR) & BESCR_LME));
+
+       ldmx((unsigned long)&test_mem);
+
+       FAIL_IF(lmr_count != 1);        // exactly one exception
+       FAIL_IF(mfspr(SPRN_BESCR) & BESCR_LME); // LM now disabled
+       FAIL_IF(!(mfspr(SPRN_BESCR) & BESCR_LMEO));     // occurred bit set
+
+       printf("Simple LMR EBB OK\n");
+
+       /* This shouldn't cause an EBB since it's been disabled */
+       ldmx((unsigned long)&test_mem);
+       FAIL_IF(lmr_count != 1);
+
+       printf("LMR disable on EBB OK\n");
+
+       ebb_lmr_reset();
+
+       /* This should cause an EBB or reset is broken */
+       ldmx((unsigned long)&test_mem);
+       FAIL_IF(lmr_count != 2);
+
+       printf("LMR reset EBB OK\n");
+
+       ebb_lmr_reset();
+
+       return ebb_lmr_section_test(test_mem);
+}
+
+int main(void)
+{
+       int ret = test_harness(ebb_lmr, "ebb_lmr");
+
+       if (test_mem)
+               free(test_mem);
+
+       return ret;
+}
diff --git a/tools/testing/selftests/powerpc/pmu/ebb/ebb_lmr.h b/tools/testing/selftests/powerpc/pmu/ebb/ebb_lmr.h
new file mode 100644 (file)
index 0000000..ef50abd
--- /dev/null
@@ -0,0 +1,39 @@
+#ifndef _SELFTESTS_POWERPC_PMU_EBB_LMR_H
+#define _SELFTESTS_POWERPC_PMU_EBB_LMR_H
+
+#include "reg.h"
+
+#ifndef PPC_FEATURE2_ARCH_3_00
+#define PPC_FEATURE2_ARCH_3_00 0x00800000
+#endif
+
+#define lmr_is_supported() have_hwcap2(PPC_FEATURE2_ARCH_3_00)
+
+static inline void ebb_lmr_reset(void)
+{
+       unsigned long bescr = mfspr(SPRN_BESCR);
+       bescr &= ~(BESCR_LMEO);
+       bescr |= BESCR_LME;
+       mtspr(SPRN_BESCR, bescr);
+}
+
+#define LDMX(t, a, b)\
+       (0x7c00026a |                           \
+        (((t) & 0x1f) << 21) |                 \
+        (((a) & 0x1f) << 16) |                 \
+        (((b) & 0x1f) << 11))
+
+static inline unsigned long ldmx(unsigned long address)
+{
+       unsigned long ret;
+
+       asm volatile ("mr 9, %1\r\n"
+                     ".long " __stringify(LDMX(9, 0, 9)) "\r\n"
+                     "mr %0, 9\r\n":"=r"(ret)
+                     :"r"(address)
+                     :"r9");
+
+       return ret;
+}
+
+#endif
diff --git a/tools/testing/selftests/powerpc/pmu/ebb/ebb_lmr_regs.c b/tools/testing/selftests/powerpc/pmu/ebb/ebb_lmr_regs.c
new file mode 100644 (file)
index 0000000..aff4241
--- /dev/null
@@ -0,0 +1,37 @@
+/*
+ * Copyright 2016, Jack Miller, IBM Corp.
+ * Licensed under GPLv2.
+ */
+
+#include <stdlib.h>
+#include <stdio.h>
+#include <unistd.h>
+
+#include "ebb.h"
+#include "ebb_lmr.h"
+
+#define CHECKS 10000
+
+int ebb_lmr_regs(void)
+{
+       int i;
+
+       SKIP_IF(!lmr_is_supported());
+
+       ebb_global_enable();
+
+       for (i = 0; i < CHECKS; i++) {
+               mtspr(SPRN_LMRR, i << 25);      // skip size and rsvd bits
+               mtspr(SPRN_LMSER, i);
+
+               FAIL_IF(mfspr(SPRN_LMRR) != (i << 25));
+               FAIL_IF(mfspr(SPRN_LMSER) != i);
+       }
+
+       return 0;
+}
+
+int main(void)
+{
+       return test_harness(ebb_lmr_regs, "ebb_lmr_regs");
+}
index 65bfdeeebdee876c77a2094776b4904f440eca4f..fddf368ed82f44800cb95f16a14c46b56d195c0a 100644 (file)
 
 #define BESCR_PMEO     0x1     /* PMU Event-based exception Occurred */
 #define BESCR_PME      (0x1ul << 32) /* PMU Event-based exception Enable */
+#define BESCR_LME      (0x1ul << 34) /* Load Monitor Enable */
+#define BESCR_LMEO     (0x1ul << 2)  /* Load Monitor Exception Occurred */
+
+#define SPRN_LMRR      813     /* Load Monitor Region Register */
+#define SPRN_LMSER     814     /* Load Monitor Section Enable Register */
 
 #define SPRN_PMC1      771
 #define SPRN_PMC2      772