// SPDX-License-Identifier: GPL-2.0-only /* * POWER Data Stream Control Register (DSCR) default test * * This test modifies the system wide default DSCR through * it's sysfs interface and then verifies that all threads * see the correct changed DSCR value immediately. * * Copyright 2012, Anton Blanchard, IBM Corporation. * Copyright 2015, Anshuman Khandual, IBM Corporation. */ #define _GNU_SOURCE #include "dscr.h" #include #include #include static void *dscr_default_lockstep_writer(void *arg) { sem_t *reader_sem = (sem_t *)arg; sem_t *writer_sem = (sem_t *)arg + 1; unsigned long expected_dscr = 0; for (int i = 0; i < COUNT; i++) { FAIL_IF_EXIT(sem_wait(writer_sem)); set_default_dscr(expected_dscr); expected_dscr = (expected_dscr + 1) % DSCR_MAX; FAIL_IF_EXIT(sem_post(reader_sem)); } return NULL; } int dscr_default_lockstep_test(void) { pthread_t writer; sem_t rw_semaphores[2]; sem_t *reader_sem = &rw_semaphores[0]; sem_t *writer_sem = &rw_semaphores[1]; unsigned long expected_dscr = 0; SKIP_IF(!have_hwcap2(PPC_FEATURE2_DSCR)); FAIL_IF(sem_init(reader_sem, 0, 0)); FAIL_IF(sem_init(writer_sem, 0, 1)); /* writer starts first */ FAIL_IF(bind_to_cpu(BIND_CPU_ANY) < 0); FAIL_IF(pthread_create(&writer, NULL, dscr_default_lockstep_writer, (void *)rw_semaphores)); for (int i = 0; i < COUNT ; i++) { FAIL_IF(sem_wait(reader_sem)); FAIL_IF(get_dscr() != expected_dscr); FAIL_IF(get_dscr_usr() != expected_dscr); expected_dscr = (expected_dscr + 1) % DSCR_MAX; FAIL_IF(sem_post(writer_sem)); } FAIL_IF(pthread_join(writer, NULL)); FAIL_IF(sem_destroy(reader_sem)); FAIL_IF(sem_destroy(writer_sem)); return 0; } struct random_thread_args { pthread_t thread_id; unsigned long *expected_system_dscr; pthread_rwlock_t *rw_lock; pthread_barrier_t *barrier; }; static void *dscr_default_random_thread(void *in) { struct random_thread_args *args = (struct random_thread_args *)in; unsigned long *expected_dscr_p = args->expected_system_dscr; pthread_rwlock_t *rw_lock = args->rw_lock; int err; srand(gettid()); err = pthread_barrier_wait(args->barrier); FAIL_IF_EXIT(err != 0 && err != PTHREAD_BARRIER_SERIAL_THREAD); for (int i = 0; i < COUNT; i++) { unsigned long expected_dscr; unsigned long current_dscr; unsigned long current_dscr_usr; FAIL_IF_EXIT(pthread_rwlock_rdlock(rw_lock)); expected_dscr = *expected_dscr_p; current_dscr = get_dscr(); current_dscr_usr = get_dscr_usr(); FAIL_IF_EXIT(pthread_rwlock_unlock(rw_lock)); FAIL_IF_EXIT(current_dscr != expected_dscr); FAIL_IF_EXIT(current_dscr_usr != expected_dscr); if (rand() % 10 == 0) { unsigned long next_dscr; FAIL_IF_EXIT(pthread_rwlock_wrlock(rw_lock)); next_dscr = (*expected_dscr_p + 1) % DSCR_MAX; set_default_dscr(next_dscr); *expected_dscr_p = next_dscr; FAIL_IF_EXIT(pthread_rwlock_unlock(rw_lock)); } } pthread_exit((void *)0); } int dscr_default_random_test(void) { struct random_thread_args threads[THREADS]; unsigned long expected_system_dscr = 0; pthread_rwlockattr_t rwlock_attr; pthread_rwlock_t rw_lock; pthread_barrier_t barrier; SKIP_IF(!have_hwcap2(PPC_FEATURE2_DSCR)); FAIL_IF(pthread_rwlockattr_setkind_np(&rwlock_attr, PTHREAD_RWLOCK_PREFER_WRITER_NONRECURSIVE_NP)); FAIL_IF(pthread_rwlock_init(&rw_lock, &rwlock_attr)); FAIL_IF(pthread_barrier_init(&barrier, NULL, THREADS)); set_default_dscr(expected_system_dscr); for (int i = 0; i < THREADS; i++) { threads[i].expected_system_dscr = &expected_system_dscr; threads[i].rw_lock = &rw_lock; threads[i].barrier = &barrier; FAIL_IF(pthread_create(&threads[i].thread_id, NULL, dscr_default_random_thread, (void *)&threads[i])); } for (int i = 0; i < THREADS; i++) FAIL_IF(pthread_join(threads[i].thread_id, NULL)); FAIL_IF(pthread_barrier_destroy(&barrier)); FAIL_IF(pthread_rwlock_destroy(&rw_lock)); return 0; } int main(int argc, char *argv[]) { unsigned long orig_dscr_default = 0; int err = 0; if (have_hwcap2(PPC_FEATURE2_DSCR)) orig_dscr_default = get_default_dscr(); err |= test_harness(dscr_default_lockstep_test, "dscr_default_lockstep_test"); err |= test_harness(dscr_default_random_test, "dscr_default_random_test"); if (have_hwcap2(PPC_FEATURE2_DSCR)) set_default_dscr(orig_dscr_default); return err; }