1 // SPDX-License-Identifier: GPL-2.0-only
2 /*
3 * POWER Data Stream Control Register (DSCR) default test
4 *
5 * This test modifies the system wide default DSCR through
6 * it's sysfs interface and then verifies that all threads
7 * see the correct changed DSCR value immediately.
8 *
9 * Copyright 2012, Anton Blanchard, IBM Corporation.
10 * Copyright 2015, Anshuman Khandual, IBM Corporation.
11 */
12 #include "dscr.h"
13
14 static unsigned long dscr; /* System DSCR default */
15 static unsigned long sequence;
16 static unsigned long result[THREADS];
17
do_test(void * in)18 static void *do_test(void *in)
19 {
20 unsigned long thread = (unsigned long)in;
21 unsigned long i;
22
23 for (i = 0; i < COUNT; i++) {
24 unsigned long d, cur_dscr, cur_dscr_usr;
25 unsigned long s1, s2;
26
27 s1 = READ_ONCE(sequence);
28 if (s1 & 1)
29 continue;
30 rmb();
31
32 d = dscr;
33 cur_dscr = get_dscr();
34 cur_dscr_usr = get_dscr_usr();
35
36 rmb();
37 s2 = sequence;
38
39 if (s1 != s2)
40 continue;
41
42 if (cur_dscr != d) {
43 fprintf(stderr, "thread %ld kernel DSCR should be %ld "
44 "but is %ld\n", thread, d, cur_dscr);
45 result[thread] = 1;
46 pthread_exit(&result[thread]);
47 }
48
49 if (cur_dscr_usr != d) {
50 fprintf(stderr, "thread %ld user DSCR should be %ld "
51 "but is %ld\n", thread, d, cur_dscr_usr);
52 result[thread] = 1;
53 pthread_exit(&result[thread]);
54 }
55 }
56 result[thread] = 0;
57 pthread_exit(&result[thread]);
58 }
59
dscr_default(void)60 int dscr_default(void)
61 {
62 pthread_t threads[THREADS];
63 unsigned long i, *status[THREADS];
64 unsigned long orig_dscr_default;
65
66 SKIP_IF(!have_hwcap2(PPC_FEATURE2_DSCR));
67
68 orig_dscr_default = get_default_dscr();
69
70 /* Initial DSCR default */
71 dscr = 1;
72 set_default_dscr(dscr);
73
74 /* Spawn all testing threads */
75 for (i = 0; i < THREADS; i++) {
76 if (pthread_create(&threads[i], NULL, do_test, (void *)i)) {
77 perror("pthread_create() failed");
78 goto fail;
79 }
80 }
81
82 srand(getpid());
83
84 /* Keep changing the DSCR default */
85 for (i = 0; i < COUNT; i++) {
86 double ret = uniform_deviate(rand());
87
88 if (ret < 0.0001) {
89 sequence++;
90 wmb();
91
92 dscr++;
93 if (dscr > DSCR_MAX)
94 dscr = 0;
95
96 set_default_dscr(dscr);
97
98 wmb();
99 sequence++;
100 }
101 }
102
103 /* Individual testing thread exit status */
104 for (i = 0; i < THREADS; i++) {
105 if (pthread_join(threads[i], (void **)&(status[i]))) {
106 perror("pthread_join() failed");
107 goto fail;
108 }
109
110 if (*status[i]) {
111 printf("%ldth thread failed to join with %ld status\n",
112 i, *status[i]);
113 goto fail;
114 }
115 }
116 set_default_dscr(orig_dscr_default);
117 return 0;
118 fail:
119 set_default_dscr(orig_dscr_default);
120 return 1;
121 }
122
main(int argc,char * argv[])123 int main(int argc, char *argv[])
124 {
125 return test_harness(dscr_default, "dscr_default_test");
126 }
127