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 21 static 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 39 int 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 72 struct 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 79 static 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 119 int 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 154 int 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
Linux® is a registered trademark of Linus Torvalds in the United States and other countries.
TOMOYO® is a registered trademark of NTT DATA CORPORATION.