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
13#define _GNU_SOURCE
14
15#include "dscr.h"
16
17#include <pthread.h>
18#include <semaphore.h>
19#include <unistd.h>
20
21static void *dscr_default_lockstep_writer(void *arg)
22{
23	sem_t *reader_sem = (sem_t *)arg;
24	sem_t *writer_sem = (sem_t *)arg + 1;
25	unsigned long expected_dscr = 0;
26
27	for (int i = 0; i < COUNT; i++) {
28		FAIL_IF_EXIT(sem_wait(writer_sem));
29
30		set_default_dscr(expected_dscr);
31		expected_dscr = (expected_dscr + 1) % DSCR_MAX;
32
33		FAIL_IF_EXIT(sem_post(reader_sem));
34	}
35
36	return NULL;
37}
38
39int dscr_default_lockstep_test(void)
40{
41	pthread_t writer;
42	sem_t rw_semaphores[2];
43	sem_t *reader_sem = &rw_semaphores[0];
44	sem_t *writer_sem = &rw_semaphores[1];
45	unsigned long expected_dscr = 0;
46
47	SKIP_IF(!have_hwcap2(PPC_FEATURE2_DSCR));
48
49	FAIL_IF(sem_init(reader_sem, 0, 0));
50	FAIL_IF(sem_init(writer_sem, 0, 1));  /* writer starts first */
51	FAIL_IF(bind_to_cpu(BIND_CPU_ANY) < 0);
52	FAIL_IF(pthread_create(&writer, NULL, dscr_default_lockstep_writer, (void *)rw_semaphores));
53
54	for (int i = 0; i < COUNT ; i++) {
55		FAIL_IF(sem_wait(reader_sem));
56
57		FAIL_IF(get_dscr() != expected_dscr);
58		FAIL_IF(get_dscr_usr() != expected_dscr);
59
60		expected_dscr = (expected_dscr + 1) % DSCR_MAX;
61
62		FAIL_IF(sem_post(writer_sem));
63	}
64
65	FAIL_IF(pthread_join(writer, NULL));
66	FAIL_IF(sem_destroy(reader_sem));
67	FAIL_IF(sem_destroy(writer_sem));
68
69	return 0;
70}
71
72struct random_thread_args {
73	pthread_t thread_id;
74	unsigned long *expected_system_dscr;
75	pthread_rwlock_t *rw_lock;
76	pthread_barrier_t *barrier;
77};
78
79static void *dscr_default_random_thread(void *in)
80{
81	struct random_thread_args *args = (struct random_thread_args *)in;
82	unsigned long *expected_dscr_p = args->expected_system_dscr;
83	pthread_rwlock_t *rw_lock = args->rw_lock;
84	int err;
85
86	srand(gettid());
87
88	err = pthread_barrier_wait(args->barrier);
89	FAIL_IF_EXIT(err != 0 && err != PTHREAD_BARRIER_SERIAL_THREAD);
90
91	for (int i = 0; i < COUNT; i++) {
92		unsigned long expected_dscr;
93		unsigned long current_dscr;
94		unsigned long current_dscr_usr;
95
96		FAIL_IF_EXIT(pthread_rwlock_rdlock(rw_lock));
97		expected_dscr = *expected_dscr_p;
98		current_dscr = get_dscr();
99		current_dscr_usr = get_dscr_usr();
100		FAIL_IF_EXIT(pthread_rwlock_unlock(rw_lock));
101
102		FAIL_IF_EXIT(current_dscr != expected_dscr);
103		FAIL_IF_EXIT(current_dscr_usr != expected_dscr);
104
105		if (rand() % 10 == 0) {
106			unsigned long next_dscr;
107
108			FAIL_IF_EXIT(pthread_rwlock_wrlock(rw_lock));
109			next_dscr = (*expected_dscr_p + 1) % DSCR_MAX;
110			set_default_dscr(next_dscr);
111			*expected_dscr_p = next_dscr;
112			FAIL_IF_EXIT(pthread_rwlock_unlock(rw_lock));
113		}
114	}
115
116	pthread_exit((void *)0);
117}
118
119int dscr_default_random_test(void)
120{
121	struct random_thread_args threads[THREADS];
122	unsigned long expected_system_dscr = 0;
123	pthread_rwlockattr_t rwlock_attr;
124	pthread_rwlock_t rw_lock;
125	pthread_barrier_t barrier;
126
127	SKIP_IF(!have_hwcap2(PPC_FEATURE2_DSCR));
128
129	FAIL_IF(pthread_rwlockattr_setkind_np(&rwlock_attr,
130					      PTHREAD_RWLOCK_PREFER_WRITER_NONRECURSIVE_NP));
131	FAIL_IF(pthread_rwlock_init(&rw_lock, &rwlock_attr));
132	FAIL_IF(pthread_barrier_init(&barrier, NULL, THREADS));
133
134	set_default_dscr(expected_system_dscr);
135
136	for (int i = 0; i < THREADS; i++) {
137		threads[i].expected_system_dscr = &expected_system_dscr;
138		threads[i].rw_lock = &rw_lock;
139		threads[i].barrier = &barrier;
140
141		FAIL_IF(pthread_create(&threads[i].thread_id, NULL,
142				       dscr_default_random_thread, (void *)&threads[i]));
143	}
144
145	for (int i = 0; i < THREADS; i++)
146		FAIL_IF(pthread_join(threads[i].thread_id, NULL));
147
148	FAIL_IF(pthread_barrier_destroy(&barrier));
149	FAIL_IF(pthread_rwlock_destroy(&rw_lock));
150
151	return 0;
152}
153
154int main(int argc, char *argv[])
155{
156	unsigned long orig_dscr_default = 0;
157	int err = 0;
158
159	if (have_hwcap2(PPC_FEATURE2_DSCR))
160		orig_dscr_default = get_default_dscr();
161
162	err |= test_harness(dscr_default_lockstep_test, "dscr_default_lockstep_test");
163	err |= test_harness(dscr_default_random_test, "dscr_default_random_test");
164
165	if (have_hwcap2(PPC_FEATURE2_DSCR))
166		set_default_dscr(orig_dscr_default);
167
168	return err;
169}
170