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