1d2912cb1SThomas Gleixner // SPDX-License-Identifier: GPL-2.0-only
21554f21aSAnshuman Khandual /*
31554f21aSAnshuman Khandual * POWER Data Stream Control Register (DSCR) explicit test
41554f21aSAnshuman Khandual *
51554f21aSAnshuman Khandual * This test modifies the DSCR value using mtspr instruction and
61554f21aSAnshuman Khandual * verifies the change with mfspr instruction. It uses both the
71554f21aSAnshuman Khandual * privilege state SPR and the problem state SPR for this purpose.
81554f21aSAnshuman Khandual *
91554f21aSAnshuman Khandual * When using the privilege state SPR, the instructions such as
1015f0c260SBenjamin Gray * mfspr or mtspr are privileged and the kernel emulates them
1115f0c260SBenjamin Gray * for us. Instructions using problem state SPR can be executed
121554f21aSAnshuman Khandual * directly without any emulation if the HW supports them. Else
131554f21aSAnshuman Khandual * they also get emulated by the kernel.
141554f21aSAnshuman Khandual *
151554f21aSAnshuman Khandual * Copyright 2012, Anton Blanchard, IBM Corporation.
161554f21aSAnshuman Khandual * Copyright 2015, Anshuman Khandual, IBM Corporation.
171554f21aSAnshuman Khandual */
181554f21aSAnshuman Khandual
19fda81588SBenjamin Gray #define _GNU_SOURCE
20fda81588SBenjamin Gray
21fda81588SBenjamin Gray #include "dscr.h"
22fda81588SBenjamin Gray #include "utils.h"
23fda81588SBenjamin Gray
24fda81588SBenjamin Gray #include <pthread.h>
25fda81588SBenjamin Gray #include <sched.h>
26fda81588SBenjamin Gray #include <semaphore.h>
27fda81588SBenjamin Gray
dscr_explicit_lockstep_thread(void * args)28fda81588SBenjamin Gray void *dscr_explicit_lockstep_thread(void *args)
29fda81588SBenjamin Gray {
30fda81588SBenjamin Gray sem_t *prev = (sem_t *)args;
31fda81588SBenjamin Gray sem_t *next = (sem_t *)args + 1;
32fda81588SBenjamin Gray unsigned long expected_dscr = 0;
33fda81588SBenjamin Gray
34fda81588SBenjamin Gray set_dscr(expected_dscr);
35fda81588SBenjamin Gray srand(gettid());
36fda81588SBenjamin Gray
37fda81588SBenjamin Gray for (int i = 0; i < COUNT; i++) {
38fda81588SBenjamin Gray FAIL_IF_EXIT(sem_wait(prev));
39fda81588SBenjamin Gray
40fda81588SBenjamin Gray FAIL_IF_EXIT(expected_dscr != get_dscr());
41fda81588SBenjamin Gray FAIL_IF_EXIT(expected_dscr != get_dscr_usr());
42fda81588SBenjamin Gray
43fda81588SBenjamin Gray expected_dscr = (expected_dscr + 1) % DSCR_MAX;
44fda81588SBenjamin Gray set_dscr(expected_dscr);
45fda81588SBenjamin Gray
46fda81588SBenjamin Gray FAIL_IF_EXIT(sem_post(next));
47fda81588SBenjamin Gray }
48fda81588SBenjamin Gray
49fda81588SBenjamin Gray return NULL;
50fda81588SBenjamin Gray }
51fda81588SBenjamin Gray
dscr_explicit_lockstep_test(void)52fda81588SBenjamin Gray int dscr_explicit_lockstep_test(void)
53fda81588SBenjamin Gray {
54fda81588SBenjamin Gray pthread_t thread;
55fda81588SBenjamin Gray sem_t semaphores[2];
56fda81588SBenjamin Gray sem_t *prev = &semaphores[1]; /* reversed prev/next than for the other thread */
57fda81588SBenjamin Gray sem_t *next = &semaphores[0];
58fda81588SBenjamin Gray unsigned long expected_dscr = 0;
59fda81588SBenjamin Gray
60fda81588SBenjamin Gray SKIP_IF(!have_hwcap2(PPC_FEATURE2_DSCR));
61fda81588SBenjamin Gray
62fda81588SBenjamin Gray srand(gettid());
63fda81588SBenjamin Gray set_dscr(expected_dscr);
64fda81588SBenjamin Gray
65fda81588SBenjamin Gray FAIL_IF(sem_init(prev, 0, 0));
66fda81588SBenjamin Gray FAIL_IF(sem_init(next, 0, 1)); /* other thread starts first */
67fda81588SBenjamin Gray FAIL_IF(bind_to_cpu(BIND_CPU_ANY) < 0);
68fda81588SBenjamin Gray FAIL_IF(pthread_create(&thread, NULL, dscr_explicit_lockstep_thread, (void *)semaphores));
69fda81588SBenjamin Gray
70fda81588SBenjamin Gray for (int i = 0; i < COUNT; i++) {
71fda81588SBenjamin Gray FAIL_IF(sem_wait(prev));
72fda81588SBenjamin Gray
73fda81588SBenjamin Gray FAIL_IF(expected_dscr != get_dscr());
74fda81588SBenjamin Gray FAIL_IF(expected_dscr != get_dscr_usr());
75fda81588SBenjamin Gray
76fda81588SBenjamin Gray expected_dscr = (expected_dscr - 1) % DSCR_MAX;
77fda81588SBenjamin Gray set_dscr(expected_dscr);
78fda81588SBenjamin Gray
79fda81588SBenjamin Gray FAIL_IF(sem_post(next));
80fda81588SBenjamin Gray }
81fda81588SBenjamin Gray
82fda81588SBenjamin Gray FAIL_IF(pthread_join(thread, NULL));
83fda81588SBenjamin Gray FAIL_IF(sem_destroy(prev));
84fda81588SBenjamin Gray FAIL_IF(sem_destroy(next));
85fda81588SBenjamin Gray
86fda81588SBenjamin Gray return 0;
87fda81588SBenjamin Gray }
88fda81588SBenjamin Gray
89*3067b89aSBenjamin Gray struct random_thread_args {
90*3067b89aSBenjamin Gray pthread_t thread_id;
91*3067b89aSBenjamin Gray bool do_yields;
92*3067b89aSBenjamin Gray pthread_barrier_t *barrier;
93*3067b89aSBenjamin Gray };
94*3067b89aSBenjamin Gray
dscr_explicit_random_thread(void * in)95*3067b89aSBenjamin Gray void *dscr_explicit_random_thread(void *in)
96*3067b89aSBenjamin Gray {
97*3067b89aSBenjamin Gray struct random_thread_args *args = (struct random_thread_args *)in;
98*3067b89aSBenjamin Gray unsigned long expected_dscr = 0;
99*3067b89aSBenjamin Gray int err;
100*3067b89aSBenjamin Gray
101*3067b89aSBenjamin Gray srand(gettid());
102*3067b89aSBenjamin Gray
103*3067b89aSBenjamin Gray err = pthread_barrier_wait(args->barrier);
104*3067b89aSBenjamin Gray FAIL_IF_EXIT(err != 0 && err != PTHREAD_BARRIER_SERIAL_THREAD);
105*3067b89aSBenjamin Gray
106*3067b89aSBenjamin Gray for (int i = 0; i < COUNT; i++) {
107*3067b89aSBenjamin Gray expected_dscr = rand() % DSCR_MAX;
108*3067b89aSBenjamin Gray set_dscr(expected_dscr);
109*3067b89aSBenjamin Gray
110*3067b89aSBenjamin Gray for (int j = rand() % 5; j > 0; --j) {
111*3067b89aSBenjamin Gray FAIL_IF_EXIT(get_dscr() != expected_dscr);
112*3067b89aSBenjamin Gray FAIL_IF_EXIT(get_dscr_usr() != expected_dscr);
113*3067b89aSBenjamin Gray
114*3067b89aSBenjamin Gray if (args->do_yields && rand() % 2)
115*3067b89aSBenjamin Gray sched_yield();
116*3067b89aSBenjamin Gray }
117*3067b89aSBenjamin Gray
118*3067b89aSBenjamin Gray expected_dscr = rand() % DSCR_MAX;
119*3067b89aSBenjamin Gray set_dscr_usr(expected_dscr);
120*3067b89aSBenjamin Gray
121*3067b89aSBenjamin Gray for (int j = rand() % 5; j > 0; --j) {
122*3067b89aSBenjamin Gray FAIL_IF_EXIT(get_dscr() != expected_dscr);
123*3067b89aSBenjamin Gray FAIL_IF_EXIT(get_dscr_usr() != expected_dscr);
124*3067b89aSBenjamin Gray
125*3067b89aSBenjamin Gray if (args->do_yields && rand() % 2)
126*3067b89aSBenjamin Gray sched_yield();
127*3067b89aSBenjamin Gray }
128*3067b89aSBenjamin Gray }
129*3067b89aSBenjamin Gray
130*3067b89aSBenjamin Gray return NULL;
131*3067b89aSBenjamin Gray }
132*3067b89aSBenjamin Gray
dscr_explicit_random_test(void)133fda81588SBenjamin Gray int dscr_explicit_random_test(void)
1341554f21aSAnshuman Khandual {
135*3067b89aSBenjamin Gray struct random_thread_args threads[THREADS];
136*3067b89aSBenjamin Gray pthread_barrier_t barrier;
1371554f21aSAnshuman Khandual
1384c3c3c50SMichael Ellerman SKIP_IF(!have_hwcap2(PPC_FEATURE2_DSCR));
1394c3c3c50SMichael Ellerman
140*3067b89aSBenjamin Gray FAIL_IF(pthread_barrier_init(&barrier, NULL, THREADS));
1411554f21aSAnshuman Khandual
142*3067b89aSBenjamin Gray for (int i = 0; i < THREADS; i++) {
143*3067b89aSBenjamin Gray threads[i].do_yields = i % 2 == 0;
144*3067b89aSBenjamin Gray threads[i].barrier = &barrier;
1451554f21aSAnshuman Khandual
146*3067b89aSBenjamin Gray FAIL_IF(pthread_create(&threads[i].thread_id, NULL,
147*3067b89aSBenjamin Gray dscr_explicit_random_thread, (void *)&threads[i]));
1481554f21aSAnshuman Khandual }
1491554f21aSAnshuman Khandual
150*3067b89aSBenjamin Gray for (int i = 0; i < THREADS; i++)
151*3067b89aSBenjamin Gray FAIL_IF(pthread_join(threads[i].thread_id, NULL));
1521554f21aSAnshuman Khandual
153*3067b89aSBenjamin Gray FAIL_IF(pthread_barrier_destroy(&barrier));
1541554f21aSAnshuman Khandual
1551554f21aSAnshuman Khandual return 0;
1561554f21aSAnshuman Khandual }
1571554f21aSAnshuman Khandual
main(int argc,char * argv[])1581554f21aSAnshuman Khandual int main(int argc, char *argv[])
1591554f21aSAnshuman Khandual {
160fda81588SBenjamin Gray unsigned long orig_dscr_default = 0;
161fda81588SBenjamin Gray int err = 0;
162fda81588SBenjamin Gray
163fda81588SBenjamin Gray if (have_hwcap2(PPC_FEATURE2_DSCR))
164fda81588SBenjamin Gray orig_dscr_default = get_default_dscr();
165fda81588SBenjamin Gray
166fda81588SBenjamin Gray err |= test_harness(dscr_explicit_lockstep_test, "dscr_explicit_lockstep_test");
167fda81588SBenjamin Gray err |= test_harness(dscr_explicit_random_test, "dscr_explicit_random_test");
168fda81588SBenjamin Gray
169fda81588SBenjamin Gray if (have_hwcap2(PPC_FEATURE2_DSCR))
170fda81588SBenjamin Gray set_default_dscr(orig_dscr_default);
171fda81588SBenjamin Gray
172fda81588SBenjamin Gray return err;
1731554f21aSAnshuman Khandual }
174