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
17static unsigned long dscr;		/* System DSCR default */
18static unsigned long sequence;
19static unsigned long result[THREADS];
20
21static 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 = ACCESS_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
63int 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;
119fail:
120	set_default_dscr(orig_dscr_default);
121	return 1;
122}
123
124int main(int argc, char *argv[])
125{
126	return test_harness(dscr_default, "dscr_default_test");
127}
128