1 // SPDX-License-Identifier: GPL-2.0-only
3 * POWER Data Stream Control Register (DSCR) explicit test
5 * This test modifies the DSCR value using mtspr instruction and
6 * verifies the change with mfspr instruction. It uses both the
7 * privilege state SPR and the problem state SPR for this purpose.
9 * When using the privilege state SPR, the instructions such as
10 * mfspr or mtspr are privileged and the kernel emulates them
11 * for us. Instructions using problem state SPR can be executed
12 * directly without any emulation if the HW supports them. Else
13 * they also get emulated by the kernel.
15 * Copyright 2012, Anton Blanchard, IBM Corporation.
16 * Copyright 2015, Anshuman Khandual, IBM Corporation.
26 #include <semaphore.h>
28 void *dscr_explicit_lockstep_thread(void *args)
30 sem_t *prev = (sem_t *)args;
31 sem_t *next = (sem_t *)args + 1;
32 unsigned long expected_dscr = 0;
34 set_dscr(expected_dscr);
37 for (int i = 0; i < COUNT; i++) {
38 FAIL_IF_EXIT(sem_wait(prev));
40 FAIL_IF_EXIT(expected_dscr != get_dscr());
41 FAIL_IF_EXIT(expected_dscr != get_dscr_usr());
43 expected_dscr = (expected_dscr + 1) % DSCR_MAX;
44 set_dscr(expected_dscr);
46 FAIL_IF_EXIT(sem_post(next));
52 int dscr_explicit_lockstep_test(void)
56 sem_t *prev = &semaphores[1]; /* reversed prev/next than for the other thread */
57 sem_t *next = &semaphores[0];
58 unsigned long expected_dscr = 0;
60 SKIP_IF(!have_hwcap2(PPC_FEATURE2_DSCR));
63 set_dscr(expected_dscr);
65 FAIL_IF(sem_init(prev, 0, 0));
66 FAIL_IF(sem_init(next, 0, 1)); /* other thread starts first */
67 FAIL_IF(bind_to_cpu(BIND_CPU_ANY) < 0);
68 FAIL_IF(pthread_create(&thread, NULL, dscr_explicit_lockstep_thread, (void *)semaphores));
70 for (int i = 0; i < COUNT; i++) {
71 FAIL_IF(sem_wait(prev));
73 FAIL_IF(expected_dscr != get_dscr());
74 FAIL_IF(expected_dscr != get_dscr_usr());
76 expected_dscr = (expected_dscr - 1) % DSCR_MAX;
77 set_dscr(expected_dscr);
79 FAIL_IF(sem_post(next));
82 FAIL_IF(pthread_join(thread, NULL));
83 FAIL_IF(sem_destroy(prev));
84 FAIL_IF(sem_destroy(next));
89 struct random_thread_args {
92 pthread_barrier_t *barrier;
95 void *dscr_explicit_random_thread(void *in)
97 struct random_thread_args *args = (struct random_thread_args *)in;
98 unsigned long expected_dscr = 0;
103 err = pthread_barrier_wait(args->barrier);
104 FAIL_IF_EXIT(err != 0 && err != PTHREAD_BARRIER_SERIAL_THREAD);
106 for (int i = 0; i < COUNT; i++) {
107 expected_dscr = rand() % DSCR_MAX;
108 set_dscr(expected_dscr);
110 for (int j = rand() % 5; j > 0; --j) {
111 FAIL_IF_EXIT(get_dscr() != expected_dscr);
112 FAIL_IF_EXIT(get_dscr_usr() != expected_dscr);
114 if (args->do_yields && rand() % 2)
118 expected_dscr = rand() % DSCR_MAX;
119 set_dscr_usr(expected_dscr);
121 for (int j = rand() % 5; j > 0; --j) {
122 FAIL_IF_EXIT(get_dscr() != expected_dscr);
123 FAIL_IF_EXIT(get_dscr_usr() != expected_dscr);
125 if (args->do_yields && rand() % 2)
133 int dscr_explicit_random_test(void)
135 struct random_thread_args threads[THREADS];
136 pthread_barrier_t barrier;
138 SKIP_IF(!have_hwcap2(PPC_FEATURE2_DSCR));
140 FAIL_IF(pthread_barrier_init(&barrier, NULL, THREADS));
142 for (int i = 0; i < THREADS; i++) {
143 threads[i].do_yields = i % 2 == 0;
144 threads[i].barrier = &barrier;
146 FAIL_IF(pthread_create(&threads[i].thread_id, NULL,
147 dscr_explicit_random_thread, (void *)&threads[i]));
150 for (int i = 0; i < THREADS; i++)
151 FAIL_IF(pthread_join(threads[i].thread_id, NULL));
153 FAIL_IF(pthread_barrier_destroy(&barrier));
158 int main(int argc, char *argv[])
160 unsigned long orig_dscr_default = 0;
163 if (have_hwcap2(PPC_FEATURE2_DSCR))
164 orig_dscr_default = get_default_dscr();
166 err |= test_harness(dscr_explicit_lockstep_test, "dscr_explicit_lockstep_test");
167 err |= test_harness(dscr_explicit_random_test, "dscr_explicit_random_test");
169 if (have_hwcap2(PPC_FEATURE2_DSCR))
170 set_default_dscr(orig_dscr_default);