diff options
Diffstat (limited to 'tools/testing/selftests/powerpc/math')
-rw-r--r-- | tools/testing/selftests/powerpc/math/.gitignore | 1 | ||||
-rw-r--r-- | tools/testing/selftests/powerpc/math/Makefile | 5 | ||||
-rw-r--r-- | tools/testing/selftests/powerpc/math/fpu_asm.S | 73 | ||||
-rw-r--r-- | tools/testing/selftests/powerpc/math/vmx_asm.S | 85 | ||||
-rw-r--r-- | tools/testing/selftests/powerpc/math/vsx_asm.S | 61 | ||||
-rw-r--r-- | tools/testing/selftests/powerpc/math/vsx_preempt.c | 147 |
6 files changed, 219 insertions, 153 deletions
diff --git a/tools/testing/selftests/powerpc/math/.gitignore b/tools/testing/selftests/powerpc/math/.gitignore index 4fe13a439fd7..50ded63e25b7 100644 --- a/tools/testing/selftests/powerpc/math/.gitignore +++ b/tools/testing/selftests/powerpc/math/.gitignore @@ -4,3 +4,4 @@ fpu_preempt vmx_preempt fpu_signal vmx_signal +vsx_preempt diff --git a/tools/testing/selftests/powerpc/math/Makefile b/tools/testing/selftests/powerpc/math/Makefile index 5b88875d5955..a505b66d408a 100644 --- a/tools/testing/selftests/powerpc/math/Makefile +++ b/tools/testing/selftests/powerpc/math/Makefile @@ -1,4 +1,4 @@ -TEST_PROGS := fpu_syscall fpu_preempt fpu_signal vmx_syscall vmx_preempt vmx_signal +TEST_PROGS := fpu_syscall fpu_preempt fpu_signal vmx_syscall vmx_preempt vmx_signal vsx_preempt all: $(TEST_PROGS) @@ -13,6 +13,9 @@ vmx_syscall: vmx_asm.S vmx_preempt: vmx_asm.S vmx_signal: vmx_asm.S +vsx_preempt: CFLAGS += -mvsx +vsx_preempt: vsx_asm.S + include ../../lib.mk clean: diff --git a/tools/testing/selftests/powerpc/math/fpu_asm.S b/tools/testing/selftests/powerpc/math/fpu_asm.S index f3711d80e709..241f067a510f 100644 --- a/tools/testing/selftests/powerpc/math/fpu_asm.S +++ b/tools/testing/selftests/powerpc/math/fpu_asm.S @@ -8,70 +8,7 @@ */ #include "../basic_asm.h" - -#define PUSH_FPU(pos) \ - stfd f14,pos(sp); \ - stfd f15,pos+8(sp); \ - stfd f16,pos+16(sp); \ - stfd f17,pos+24(sp); \ - stfd f18,pos+32(sp); \ - stfd f19,pos+40(sp); \ - stfd f20,pos+48(sp); \ - stfd f21,pos+56(sp); \ - stfd f22,pos+64(sp); \ - stfd f23,pos+72(sp); \ - stfd f24,pos+80(sp); \ - stfd f25,pos+88(sp); \ - stfd f26,pos+96(sp); \ - stfd f27,pos+104(sp); \ - stfd f28,pos+112(sp); \ - stfd f29,pos+120(sp); \ - stfd f30,pos+128(sp); \ - stfd f31,pos+136(sp); - -#define POP_FPU(pos) \ - lfd f14,pos(sp); \ - lfd f15,pos+8(sp); \ - lfd f16,pos+16(sp); \ - lfd f17,pos+24(sp); \ - lfd f18,pos+32(sp); \ - lfd f19,pos+40(sp); \ - lfd f20,pos+48(sp); \ - lfd f21,pos+56(sp); \ - lfd f22,pos+64(sp); \ - lfd f23,pos+72(sp); \ - lfd f24,pos+80(sp); \ - lfd f25,pos+88(sp); \ - lfd f26,pos+96(sp); \ - lfd f27,pos+104(sp); \ - lfd f28,pos+112(sp); \ - lfd f29,pos+120(sp); \ - lfd f30,pos+128(sp); \ - lfd f31,pos+136(sp); - -# Careful calling this, it will 'clobber' fpu (by design) -# Don't call this from C -FUNC_START(load_fpu) - lfd f14,0(r3) - lfd f15,8(r3) - lfd f16,16(r3) - lfd f17,24(r3) - lfd f18,32(r3) - lfd f19,40(r3) - lfd f20,48(r3) - lfd f21,56(r3) - lfd f22,64(r3) - lfd f23,72(r3) - lfd f24,80(r3) - lfd f25,88(r3) - lfd f26,96(r3) - lfd f27,104(r3) - lfd f28,112(r3) - lfd f29,120(r3) - lfd f30,128(r3) - lfd f31,136(r3) - blr -FUNC_END(load_fpu) +#include "../fpu_asm.h" FUNC_START(check_fpu) mr r4,r3 @@ -138,9 +75,9 @@ FUNC_START(test_fpu) # r4 holds pointer to the pid # f14-f31 are non volatiles PUSH_BASIC_STACK(256) + PUSH_FPU(256) std r3,STACK_FRAME_PARAM(0)(sp) # Address of darray std r4,STACK_FRAME_PARAM(1)(sp) # Address of pid - PUSH_FPU(STACK_FRAME_LOCAL(2,0)) bl load_fpu nop @@ -155,7 +92,7 @@ FUNC_START(test_fpu) bl check_fpu nop - POP_FPU(STACK_FRAME_LOCAL(2,0)) + POP_FPU(256) POP_BASIC_STACK(256) blr FUNC_END(test_fpu) @@ -166,10 +103,10 @@ FUNC_END(test_fpu) # registers while running is not zero. FUNC_START(preempt_fpu) PUSH_BASIC_STACK(256) + PUSH_FPU(256) std r3,STACK_FRAME_PARAM(0)(sp) # double *darray std r4,STACK_FRAME_PARAM(1)(sp) # int *threads_starting std r5,STACK_FRAME_PARAM(2)(sp) # int *running - PUSH_FPU(STACK_FRAME_LOCAL(3,0)) bl load_fpu nop @@ -192,7 +129,7 @@ FUNC_START(preempt_fpu) cmpwi r5,0 bne 2b -3: POP_FPU(STACK_FRAME_LOCAL(3,0)) +3: POP_FPU(256) POP_BASIC_STACK(256) blr FUNC_END(preempt_fpu) diff --git a/tools/testing/selftests/powerpc/math/vmx_asm.S b/tools/testing/selftests/powerpc/math/vmx_asm.S index 1b8c248b3ac1..fd74da488625 100644 --- a/tools/testing/selftests/powerpc/math/vmx_asm.S +++ b/tools/testing/selftests/powerpc/math/vmx_asm.S @@ -8,90 +8,7 @@ */ #include "../basic_asm.h" - -# POS MUST BE 16 ALIGNED! -#define PUSH_VMX(pos,reg) \ - li reg,pos; \ - stvx v20,reg,sp; \ - addi reg,reg,16; \ - stvx v21,reg,sp; \ - addi reg,reg,16; \ - stvx v22,reg,sp; \ - addi reg,reg,16; \ - stvx v23,reg,sp; \ - addi reg,reg,16; \ - stvx v24,reg,sp; \ - addi reg,reg,16; \ - stvx v25,reg,sp; \ - addi reg,reg,16; \ - stvx v26,reg,sp; \ - addi reg,reg,16; \ - stvx v27,reg,sp; \ - addi reg,reg,16; \ - stvx v28,reg,sp; \ - addi reg,reg,16; \ - stvx v29,reg,sp; \ - addi reg,reg,16; \ - stvx v30,reg,sp; \ - addi reg,reg,16; \ - stvx v31,reg,sp; - -# POS MUST BE 16 ALIGNED! -#define POP_VMX(pos,reg) \ - li reg,pos; \ - lvx v20,reg,sp; \ - addi reg,reg,16; \ - lvx v21,reg,sp; \ - addi reg,reg,16; \ - lvx v22,reg,sp; \ - addi reg,reg,16; \ - lvx v23,reg,sp; \ - addi reg,reg,16; \ - lvx v24,reg,sp; \ - addi reg,reg,16; \ - lvx v25,reg,sp; \ - addi reg,reg,16; \ - lvx v26,reg,sp; \ - addi reg,reg,16; \ - lvx v27,reg,sp; \ - addi reg,reg,16; \ - lvx v28,reg,sp; \ - addi reg,reg,16; \ - lvx v29,reg,sp; \ - addi reg,reg,16; \ - lvx v30,reg,sp; \ - addi reg,reg,16; \ - lvx v31,reg,sp; - -# Carefull this will 'clobber' vmx (by design) -# Don't call this from C -FUNC_START(load_vmx) - li r5,0 - lvx v20,r5,r3 - addi r5,r5,16 - lvx v21,r5,r3 - addi r5,r5,16 - lvx v22,r5,r3 - addi r5,r5,16 - lvx v23,r5,r3 - addi r5,r5,16 - lvx v24,r5,r3 - addi r5,r5,16 - lvx v25,r5,r3 - addi r5,r5,16 - lvx v26,r5,r3 - addi r5,r5,16 - lvx v27,r5,r3 - addi r5,r5,16 - lvx v28,r5,r3 - addi r5,r5,16 - lvx v29,r5,r3 - addi r5,r5,16 - lvx v30,r5,r3 - addi r5,r5,16 - lvx v31,r5,r3 - blr -FUNC_END(load_vmx) +#include "../vmx_asm.h" # Should be safe from C, only touches r4, r5 and v0,v1,v2 FUNC_START(check_vmx) diff --git a/tools/testing/selftests/powerpc/math/vsx_asm.S b/tools/testing/selftests/powerpc/math/vsx_asm.S new file mode 100644 index 000000000000..a110dd882d5e --- /dev/null +++ b/tools/testing/selftests/powerpc/math/vsx_asm.S @@ -0,0 +1,61 @@ +/* + * Copyright 2015, Cyril Bur, IBM Corp. + * + * 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. + */ + +#include "../basic_asm.h" +#include "../vsx_asm.h" + +#long check_vsx(vector int *r3); +#This function wraps storeing VSX regs to the end of an array and a +#call to a comparison function in C which boils down to a memcmp() +FUNC_START(check_vsx) + PUSH_BASIC_STACK(32) + std r3,STACK_FRAME_PARAM(0)(sp) + addi r3, r3, 16 * 12 #Second half of array + bl store_vsx + ld r3,STACK_FRAME_PARAM(0)(sp) + bl vsx_memcmp + POP_BASIC_STACK(32) + blr +FUNC_END(check_vsx) + +# int preempt_vmx(vector int *varray, int *threads_starting, +# int *running); +# On starting will (atomically) decrement threads_starting as a signal +# that the VMX have been loaded with varray. Will proceed to check the +# validity of the VMX registers while running is not zero. +FUNC_START(preempt_vsx) + PUSH_BASIC_STACK(512) + std r3,STACK_FRAME_PARAM(0)(sp) # vector int *varray + std r4,STACK_FRAME_PARAM(1)(sp) # int *threads_starting + std r5,STACK_FRAME_PARAM(2)(sp) # int *running + + bl load_vsx + nop + + sync + # Atomic DEC + ld r3,STACK_FRAME_PARAM(1)(sp) +1: lwarx r4,0,r3 + addi r4,r4,-1 + stwcx. r4,0,r3 + bne- 1b + +2: ld r3,STACK_FRAME_PARAM(0)(sp) + bl check_vsx + nop + cmpdi r3,0 + bne 3f + ld r4,STACK_FRAME_PARAM(2)(sp) + ld r5,0(r4) + cmpwi r5,0 + bne 2b + +3: POP_BASIC_STACK(512) + blr +FUNC_END(preempt_vsx) diff --git a/tools/testing/selftests/powerpc/math/vsx_preempt.c b/tools/testing/selftests/powerpc/math/vsx_preempt.c new file mode 100644 index 000000000000..6387f03a0a6a --- /dev/null +++ b/tools/testing/selftests/powerpc/math/vsx_preempt.c @@ -0,0 +1,147 @@ +/* + * Copyright 2015, Cyril Bur, IBM Corp. + * + * 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. + * + * This test attempts to see if the VSX registers change across preemption. + * There is no way to be sure preemption happened so this test just + * uses many threads and a long wait. As such, a successful test + * doesn't mean much but a failure is bad. + */ + +#include <stdio.h> +#include <string.h> +#include <unistd.h> +#include <sys/syscall.h> +#include <sys/time.h> +#include <sys/types.h> +#include <sys/wait.h> +#include <stdlib.h> +#include <pthread.h> + +#include "utils.h" + +/* Time to wait for workers to get preempted (seconds) */ +#define PREEMPT_TIME 20 +/* + * Factor by which to multiply number of online CPUs for total number of + * worker threads + */ +#define THREAD_FACTOR 8 + +/* + * Ensure there is twice the number of non-volatile VMX regs! + * check_vmx() is going to use the other half as space to put the live + * registers before calling vsx_memcmp() + */ +__thread vector int varray[24] = { + {1, 2, 3, 4 }, {5, 6, 7, 8 }, {9, 10,11,12}, + {13,14,15,16}, {17,18,19,20}, {21,22,23,24}, + {25,26,27,28}, {29,30,31,32}, {33,34,35,36}, + {37,38,39,40}, {41,42,43,44}, {45,46,47,48} +}; + +int threads_starting; +int running; + +extern long preempt_vsx(vector int *varray, int *threads_starting, int *running); + +long vsx_memcmp(vector int *a) { + vector int zero = {0, 0, 0, 0}; + int i; + + FAIL_IF(a != varray); + + for(i = 0; i < 12; i++) { + if (memcmp(&a[i + 12], &zero, sizeof(vector int)) == 0) { + fprintf(stderr, "Detected zero from the VSX reg %d\n", i + 12); + return 2; + } + } + + if (memcmp(a, &a[12], 12 * sizeof(vector int))) { + long *p = (long *)a; + fprintf(stderr, "VSX mismatch\n"); + for (i = 0; i < 24; i=i+2) + fprintf(stderr, "%d: 0x%08lx%08lx | 0x%08lx%08lx\n", + i/2 + i%2 + 20, p[i], p[i + 1], p[i + 24], p[i + 25]); + return 1; + } + return 0; +} + +void *preempt_vsx_c(void *p) +{ + int i, j; + long rc; + srand(pthread_self()); + for (i = 0; i < 12; i++) + for (j = 0; j < 4; j++) { + varray[i][j] = rand(); + /* Don't want zero because it hides kernel problems */ + if (varray[i][j] == 0) + j--; + } + rc = preempt_vsx(varray, &threads_starting, &running); + if (rc == 2) + fprintf(stderr, "Caught zeros in VSX compares\n"); + return (void *)rc; +} + +int test_preempt_vsx(void) +{ + int i, rc, threads; + pthread_t *tids; + + threads = sysconf(_SC_NPROCESSORS_ONLN) * THREAD_FACTOR; + tids = malloc(threads * sizeof(pthread_t)); + FAIL_IF(!tids); + + running = true; + threads_starting = threads; + for (i = 0; i < threads; i++) { + rc = pthread_create(&tids[i], NULL, preempt_vsx_c, NULL); + FAIL_IF(rc); + } + + setbuf(stdout, NULL); + /* Not really nessesary but nice to wait for every thread to start */ + printf("\tWaiting for %d workers to start...", threads_starting); + while(threads_starting) + asm volatile("": : :"memory"); + printf("done\n"); + + printf("\tWaiting for %d seconds to let some workers get preempted...", PREEMPT_TIME); + sleep(PREEMPT_TIME); + printf("done\n"); + + printf("\tStopping workers..."); + /* + * Working are checking this value every loop. In preempt_vsx 'cmpwi r5,0; bne 2b'. + * r5 will have loaded the value of running. + */ + running = 0; + for (i = 0; i < threads; i++) { + void *rc_p; + pthread_join(tids[i], &rc_p); + + /* + * Harness will say the fail was here, look at why preempt_vsx + * returned + */ + if ((long) rc_p) + printf("oops\n"); + FAIL_IF((long) rc_p); + } + printf("done\n"); + + return 0; +} + +int main(int argc, char *argv[]) +{ + return test_harness(test_preempt_vsx, "vsx_preempt"); +} |