134689Sbde// SPDX-License-Identifier: GPL-2.0-only 250476Speter/* 31573Srgrimes * POWER Data Stream Control Register (DSCR) explicit test 434689Sbde * 534689Sbde * This test modifies the DSCR value using mtspr instruction and 634689Sbde * verifies the change with mfspr instruction. It uses both the 738752Sbde * privilege state SPR and the problem state SPR for this purpose. 834689Sbde * 940306Sbde * When using the privilege state SPR, the instructions such as 1045691Sobrien * mfspr or mtspr are privileged and the kernel emulates them 1141123Sjdp * for us. Instructions using problem state SPR can be executed 1241123Sjdp * directly without any emulation if the HW supports them. Else 1350731Speter * they also get emulated by the kernel. 1441257Sjdp * 1541257Sjdp * Copyright 2012, Anton Blanchard, IBM Corporation. 1641257Sjdp * Copyright 2015, Anshuman Khandual, IBM Corporation. 1734689Sbde */ 1834689Sbde 1934689Sbde#define _GNU_SOURCE 2050633Speter 2150633Speter#include "dscr.h" 2239271Sphk#include "utils.h" 2350633Speter 2441912Sdfr#include <pthread.h> 2541257Sjdp#include <sched.h> 2644746Smarkm#include <semaphore.h> 2734689Sbde 2850633Spetervoid *dscr_explicit_lockstep_thread(void *args) 2950633Speter{ 3038632Sjb sem_t *prev = (sem_t *)args; 3138632Sjb sem_t *next = (sem_t *)args + 1; 3234330Sjb unsigned long expected_dscr = 0; 3334689Sbde 341573Srgrimes set_dscr(expected_dscr); 351573Srgrimes srand(gettid()); 3634330Sjb 3734689Sbde for (int i = 0; i < COUNT; i++) { 3817706Sjulian FAIL_IF_EXIT(sem_wait(prev)); 3917706Sjulian 4034738Smarkm FAIL_IF_EXIT(expected_dscr != get_dscr()); 4134738Smarkm FAIL_IF_EXIT(expected_dscr != get_dscr_usr()); 4236428Speter 4336428Speter expected_dscr = (expected_dscr + 1) % DSCR_MAX; 4436428Speter set_dscr(expected_dscr); 4534689Sbde 4611071Sache FAIL_IF_EXIT(sem_post(next)); 4711071Sache } 4834689Sbde 4938477Sgpalmer return NULL; 5034689Sbde} 5136026Sjb 5234689Sbdeint dscr_explicit_lockstep_test(void) 5332386Sjb{ 5434689Sbde pthread_t thread; 552119Sjkh sem_t semaphores[2]; 5634689Sbde sem_t *prev = &semaphores[1]; /* reversed prev/next than for the other thread */ 572119Sjkh sem_t *next = &semaphores[0]; 582119Sjkh unsigned long expected_dscr = 0; 5941912Sdfr 6041912Sdfr SKIP_IF(!have_hwcap2(PPC_FEATURE2_DSCR)); 6141912Sdfr 6241912Sdfr srand(gettid()); 6334689Sbde set_dscr(expected_dscr); 6434689Sbde 6534689Sbde FAIL_IF(sem_init(prev, 0, 0)); 6634689Sbde FAIL_IF(sem_init(next, 0, 1)); /* other thread starts first */ 6720845Speter FAIL_IF(bind_to_cpu(BIND_CPU_ANY) < 0); 681573Srgrimes FAIL_IF(pthread_create(&thread, NULL, dscr_explicit_lockstep_thread, (void *)semaphores)); 69 70 for (int i = 0; i < COUNT; i++) { 71 FAIL_IF(sem_wait(prev)); 72 73 FAIL_IF(expected_dscr != get_dscr()); 74 FAIL_IF(expected_dscr != get_dscr_usr()); 75 76 expected_dscr = (expected_dscr - 1) % DSCR_MAX; 77 set_dscr(expected_dscr); 78 79 FAIL_IF(sem_post(next)); 80 } 81 82 FAIL_IF(pthread_join(thread, NULL)); 83 FAIL_IF(sem_destroy(prev)); 84 FAIL_IF(sem_destroy(next)); 85 86 return 0; 87} 88 89struct random_thread_args { 90 pthread_t thread_id; 91 bool do_yields; 92 pthread_barrier_t *barrier; 93}; 94 95void *dscr_explicit_random_thread(void *in) 96{ 97 struct random_thread_args *args = (struct random_thread_args *)in; 98 unsigned long expected_dscr = 0; 99 int err; 100 101 srand(gettid()); 102 103 err = pthread_barrier_wait(args->barrier); 104 FAIL_IF_EXIT(err != 0 && err != PTHREAD_BARRIER_SERIAL_THREAD); 105 106 for (int i = 0; i < COUNT; i++) { 107 expected_dscr = rand() % DSCR_MAX; 108 set_dscr(expected_dscr); 109 110 for (int j = rand() % 5; j > 0; --j) { 111 FAIL_IF_EXIT(get_dscr() != expected_dscr); 112 FAIL_IF_EXIT(get_dscr_usr() != expected_dscr); 113 114 if (args->do_yields && rand() % 2) 115 sched_yield(); 116 } 117 118 expected_dscr = rand() % DSCR_MAX; 119 set_dscr_usr(expected_dscr); 120 121 for (int j = rand() % 5; j > 0; --j) { 122 FAIL_IF_EXIT(get_dscr() != expected_dscr); 123 FAIL_IF_EXIT(get_dscr_usr() != expected_dscr); 124 125 if (args->do_yields && rand() % 2) 126 sched_yield(); 127 } 128 } 129 130 return NULL; 131} 132 133int dscr_explicit_random_test(void) 134{ 135 struct random_thread_args threads[THREADS]; 136 pthread_barrier_t barrier; 137 138 SKIP_IF(!have_hwcap2(PPC_FEATURE2_DSCR)); 139 140 FAIL_IF(pthread_barrier_init(&barrier, NULL, THREADS)); 141 142 for (int i = 0; i < THREADS; i++) { 143 threads[i].do_yields = i % 2 == 0; 144 threads[i].barrier = &barrier; 145 146 FAIL_IF(pthread_create(&threads[i].thread_id, NULL, 147 dscr_explicit_random_thread, (void *)&threads[i])); 148 } 149 150 for (int i = 0; i < THREADS; i++) 151 FAIL_IF(pthread_join(threads[i].thread_id, NULL)); 152 153 FAIL_IF(pthread_barrier_destroy(&barrier)); 154 155 return 0; 156} 157 158int main(int argc, char *argv[]) 159{ 160 unsigned long orig_dscr_default = 0; 161 int err = 0; 162 163 if (have_hwcap2(PPC_FEATURE2_DSCR)) 164 orig_dscr_default = get_default_dscr(); 165 166 err |= test_harness(dscr_explicit_lockstep_test, "dscr_explicit_lockstep_test"); 167 err |= test_harness(dscr_explicit_random_test, "dscr_explicit_random_test"); 168 169 if (have_hwcap2(PPC_FEATURE2_DSCR)) 170 set_default_dscr(orig_dscr_default); 171 172 return err; 173} 174