162306a36Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0-only 262306a36Sopenharmony_ci/* 362306a36Sopenharmony_ci * Copyright 2017, Gustavo Romero, Breno Leitao, Cyril Bur, IBM Corp. 462306a36Sopenharmony_ci * 562306a36Sopenharmony_ci * Force FP, VEC and VSX unavailable exception during transaction in all 662306a36Sopenharmony_ci * possible scenarios regarding the MSR.FP and MSR.VEC state, e.g. when FP 762306a36Sopenharmony_ci * is enable and VEC is disable, when FP is disable and VEC is enable, and 862306a36Sopenharmony_ci * so on. Then we check if the restored state is correctly set for the 962306a36Sopenharmony_ci * FP and VEC registers to the previous state we set just before we entered 1062306a36Sopenharmony_ci * in TM, i.e. we check if it corrupts somehow the recheckpointed FP and 1162306a36Sopenharmony_ci * VEC/Altivec registers on abortion due to an unavailable exception in TM. 1262306a36Sopenharmony_ci * N.B. In this test we do not test all the FP/Altivec/VSX registers for 1362306a36Sopenharmony_ci * corruption, but only for registers vs0 and vs32, which are respectively 1462306a36Sopenharmony_ci * representatives of FP and VEC/Altivec reg sets. 1562306a36Sopenharmony_ci */ 1662306a36Sopenharmony_ci 1762306a36Sopenharmony_ci#define _GNU_SOURCE 1862306a36Sopenharmony_ci#include <error.h> 1962306a36Sopenharmony_ci#include <stdio.h> 2062306a36Sopenharmony_ci#include <stdlib.h> 2162306a36Sopenharmony_ci#include <unistd.h> 2262306a36Sopenharmony_ci#include <inttypes.h> 2362306a36Sopenharmony_ci#include <stdbool.h> 2462306a36Sopenharmony_ci#include <pthread.h> 2562306a36Sopenharmony_ci#include <sched.h> 2662306a36Sopenharmony_ci 2762306a36Sopenharmony_ci#include "tm.h" 2862306a36Sopenharmony_ci 2962306a36Sopenharmony_ci#define DEBUG 0 3062306a36Sopenharmony_ci 3162306a36Sopenharmony_ci/* Unavailable exceptions to test in HTM */ 3262306a36Sopenharmony_ci#define FP_UNA_EXCEPTION 0 3362306a36Sopenharmony_ci#define VEC_UNA_EXCEPTION 1 3462306a36Sopenharmony_ci#define VSX_UNA_EXCEPTION 2 3562306a36Sopenharmony_ci 3662306a36Sopenharmony_ci#define NUM_EXCEPTIONS 3 3762306a36Sopenharmony_ci#define err_at_line(status, errnum, format, ...) \ 3862306a36Sopenharmony_ci error_at_line(status, errnum, __FILE__, __LINE__, format ##__VA_ARGS__) 3962306a36Sopenharmony_ci 4062306a36Sopenharmony_ci#define pr_warn(code, format, ...) err_at_line(0, code, format, ##__VA_ARGS__) 4162306a36Sopenharmony_ci#define pr_err(code, format, ...) err_at_line(1, code, format, ##__VA_ARGS__) 4262306a36Sopenharmony_ci 4362306a36Sopenharmony_cistruct Flags { 4462306a36Sopenharmony_ci int touch_fp; 4562306a36Sopenharmony_ci int touch_vec; 4662306a36Sopenharmony_ci int result; 4762306a36Sopenharmony_ci int exception; 4862306a36Sopenharmony_ci} flags; 4962306a36Sopenharmony_ci 5062306a36Sopenharmony_cibool expecting_failure(void) 5162306a36Sopenharmony_ci{ 5262306a36Sopenharmony_ci if (flags.touch_fp && flags.exception == FP_UNA_EXCEPTION) 5362306a36Sopenharmony_ci return false; 5462306a36Sopenharmony_ci 5562306a36Sopenharmony_ci if (flags.touch_vec && flags.exception == VEC_UNA_EXCEPTION) 5662306a36Sopenharmony_ci return false; 5762306a36Sopenharmony_ci 5862306a36Sopenharmony_ci /* 5962306a36Sopenharmony_ci * If both FP and VEC are touched it does not mean that touching VSX 6062306a36Sopenharmony_ci * won't raise an exception. However since FP and VEC state are already 6162306a36Sopenharmony_ci * correctly loaded, the transaction is not aborted (i.e. 6262306a36Sopenharmony_ci * treclaimed/trecheckpointed) and MSR.VSX is just set as 1, so a TM 6362306a36Sopenharmony_ci * failure is not expected also in this case. 6462306a36Sopenharmony_ci */ 6562306a36Sopenharmony_ci if ((flags.touch_fp && flags.touch_vec) && 6662306a36Sopenharmony_ci flags.exception == VSX_UNA_EXCEPTION) 6762306a36Sopenharmony_ci return false; 6862306a36Sopenharmony_ci 6962306a36Sopenharmony_ci return true; 7062306a36Sopenharmony_ci} 7162306a36Sopenharmony_ci 7262306a36Sopenharmony_ci/* Check if failure occurred whilst in transaction. */ 7362306a36Sopenharmony_cibool is_failure(uint64_t condition_reg) 7462306a36Sopenharmony_ci{ 7562306a36Sopenharmony_ci /* 7662306a36Sopenharmony_ci * When failure handling occurs, CR0 is set to 0b1010 (0xa). Otherwise 7762306a36Sopenharmony_ci * transaction completes without failure and hence reaches out 'tend.' 7862306a36Sopenharmony_ci * that sets CR0 to 0b0100 (0x4). 7962306a36Sopenharmony_ci */ 8062306a36Sopenharmony_ci return ((condition_reg >> 28) & 0xa) == 0xa; 8162306a36Sopenharmony_ci} 8262306a36Sopenharmony_ci 8362306a36Sopenharmony_civoid *tm_una_ping(void *input) 8462306a36Sopenharmony_ci{ 8562306a36Sopenharmony_ci 8662306a36Sopenharmony_ci /* 8762306a36Sopenharmony_ci * Expected values for vs0 and vs32 after a TM failure. They must never 8862306a36Sopenharmony_ci * change, otherwise they got corrupted. 8962306a36Sopenharmony_ci */ 9062306a36Sopenharmony_ci uint64_t high_vs0 = 0x5555555555555555; 9162306a36Sopenharmony_ci uint64_t low_vs0 = 0xffffffffffffffff; 9262306a36Sopenharmony_ci uint64_t high_vs32 = 0x5555555555555555; 9362306a36Sopenharmony_ci uint64_t low_vs32 = 0xffffffffffffffff; 9462306a36Sopenharmony_ci 9562306a36Sopenharmony_ci /* Counter for busy wait */ 9662306a36Sopenharmony_ci uint64_t counter = 0x1ff000000; 9762306a36Sopenharmony_ci 9862306a36Sopenharmony_ci /* 9962306a36Sopenharmony_ci * Variable to keep a copy of CR register content taken just after we 10062306a36Sopenharmony_ci * leave the transactional state. 10162306a36Sopenharmony_ci */ 10262306a36Sopenharmony_ci uint64_t cr_ = 0; 10362306a36Sopenharmony_ci 10462306a36Sopenharmony_ci /* 10562306a36Sopenharmony_ci * Wait a bit so thread can get its name "ping". This is not important 10662306a36Sopenharmony_ci * to reproduce the issue but it's nice to have for systemtap debugging. 10762306a36Sopenharmony_ci */ 10862306a36Sopenharmony_ci if (DEBUG) 10962306a36Sopenharmony_ci sleep(1); 11062306a36Sopenharmony_ci 11162306a36Sopenharmony_ci printf("If MSR.FP=%d MSR.VEC=%d: ", flags.touch_fp, flags.touch_vec); 11262306a36Sopenharmony_ci 11362306a36Sopenharmony_ci if (flags.exception != FP_UNA_EXCEPTION && 11462306a36Sopenharmony_ci flags.exception != VEC_UNA_EXCEPTION && 11562306a36Sopenharmony_ci flags.exception != VSX_UNA_EXCEPTION) { 11662306a36Sopenharmony_ci printf("No valid exception specified to test.\n"); 11762306a36Sopenharmony_ci return NULL; 11862306a36Sopenharmony_ci } 11962306a36Sopenharmony_ci 12062306a36Sopenharmony_ci asm ( 12162306a36Sopenharmony_ci /* Prepare to merge low and high. */ 12262306a36Sopenharmony_ci " mtvsrd 33, %[high_vs0] ;" 12362306a36Sopenharmony_ci " mtvsrd 34, %[low_vs0] ;" 12462306a36Sopenharmony_ci 12562306a36Sopenharmony_ci /* 12662306a36Sopenharmony_ci * Adjust VS0 expected value after an TM failure, 12762306a36Sopenharmony_ci * i.e. vs0 = 0x5555555555555555555FFFFFFFFFFFFFFFF 12862306a36Sopenharmony_ci */ 12962306a36Sopenharmony_ci " xxmrghd 0, 33, 34 ;" 13062306a36Sopenharmony_ci 13162306a36Sopenharmony_ci /* 13262306a36Sopenharmony_ci * Adjust VS32 expected value after an TM failure, 13362306a36Sopenharmony_ci * i.e. vs32 = 0x5555555555555555555FFFFFFFFFFFFFFFF 13462306a36Sopenharmony_ci */ 13562306a36Sopenharmony_ci " xxmrghd 32, 33, 34 ;" 13662306a36Sopenharmony_ci 13762306a36Sopenharmony_ci /* 13862306a36Sopenharmony_ci * Wait an amount of context switches so load_fp and load_vec 13962306a36Sopenharmony_ci * overflow and MSR.FP, MSR.VEC, and MSR.VSX become zero (off). 14062306a36Sopenharmony_ci */ 14162306a36Sopenharmony_ci " mtctr %[counter] ;" 14262306a36Sopenharmony_ci 14362306a36Sopenharmony_ci /* Decrement CTR branch if CTR non zero. */ 14462306a36Sopenharmony_ci "1: bdnz 1b ;" 14562306a36Sopenharmony_ci 14662306a36Sopenharmony_ci /* 14762306a36Sopenharmony_ci * Check if we want to touch FP prior to the test in order 14862306a36Sopenharmony_ci * to set MSR.FP = 1 before provoking an unavailable 14962306a36Sopenharmony_ci * exception in TM. 15062306a36Sopenharmony_ci */ 15162306a36Sopenharmony_ci " cmpldi %[touch_fp], 0 ;" 15262306a36Sopenharmony_ci " beq no_fp ;" 15362306a36Sopenharmony_ci " fadd 10, 10, 10 ;" 15462306a36Sopenharmony_ci "no_fp: ;" 15562306a36Sopenharmony_ci 15662306a36Sopenharmony_ci /* 15762306a36Sopenharmony_ci * Check if we want to touch VEC prior to the test in order 15862306a36Sopenharmony_ci * to set MSR.VEC = 1 before provoking an unavailable 15962306a36Sopenharmony_ci * exception in TM. 16062306a36Sopenharmony_ci */ 16162306a36Sopenharmony_ci " cmpldi %[touch_vec], 0 ;" 16262306a36Sopenharmony_ci " beq no_vec ;" 16362306a36Sopenharmony_ci " vaddcuw 10, 10, 10 ;" 16462306a36Sopenharmony_ci "no_vec: ;" 16562306a36Sopenharmony_ci 16662306a36Sopenharmony_ci /* 16762306a36Sopenharmony_ci * Perhaps it would be a better idea to do the 16862306a36Sopenharmony_ci * compares outside transactional context and simply 16962306a36Sopenharmony_ci * duplicate code. 17062306a36Sopenharmony_ci */ 17162306a36Sopenharmony_ci " tbegin. ;" 17262306a36Sopenharmony_ci " beq trans_fail ;" 17362306a36Sopenharmony_ci 17462306a36Sopenharmony_ci /* Do we do FP Unavailable? */ 17562306a36Sopenharmony_ci " cmpldi %[exception], %[ex_fp] ;" 17662306a36Sopenharmony_ci " bne 1f ;" 17762306a36Sopenharmony_ci " fadd 10, 10, 10 ;" 17862306a36Sopenharmony_ci " b done ;" 17962306a36Sopenharmony_ci 18062306a36Sopenharmony_ci /* Do we do VEC Unavailable? */ 18162306a36Sopenharmony_ci "1: cmpldi %[exception], %[ex_vec] ;" 18262306a36Sopenharmony_ci " bne 2f ;" 18362306a36Sopenharmony_ci " vaddcuw 10, 10, 10 ;" 18462306a36Sopenharmony_ci " b done ;" 18562306a36Sopenharmony_ci 18662306a36Sopenharmony_ci /* 18762306a36Sopenharmony_ci * Not FP or VEC, therefore VSX. Ensure this 18862306a36Sopenharmony_ci * instruction always generates a VSX Unavailable. 18962306a36Sopenharmony_ci * ISA 3.0 is tricky here. 19062306a36Sopenharmony_ci * (xxmrghd will on ISA 2.07 and ISA 3.0) 19162306a36Sopenharmony_ci */ 19262306a36Sopenharmony_ci "2: xxmrghd 10, 10, 10 ;" 19362306a36Sopenharmony_ci 19462306a36Sopenharmony_ci "done: tend. ;" 19562306a36Sopenharmony_ci 19662306a36Sopenharmony_ci "trans_fail: ;" 19762306a36Sopenharmony_ci 19862306a36Sopenharmony_ci /* Give values back to C. */ 19962306a36Sopenharmony_ci " mfvsrd %[high_vs0], 0 ;" 20062306a36Sopenharmony_ci " xxsldwi 3, 0, 0, 2 ;" 20162306a36Sopenharmony_ci " mfvsrd %[low_vs0], 3 ;" 20262306a36Sopenharmony_ci " mfvsrd %[high_vs32], 32 ;" 20362306a36Sopenharmony_ci " xxsldwi 3, 32, 32, 2 ;" 20462306a36Sopenharmony_ci " mfvsrd %[low_vs32], 3 ;" 20562306a36Sopenharmony_ci 20662306a36Sopenharmony_ci /* Give CR back to C so that it can check what happened. */ 20762306a36Sopenharmony_ci " mfcr %[cr_] ;" 20862306a36Sopenharmony_ci 20962306a36Sopenharmony_ci : [high_vs0] "+r" (high_vs0), 21062306a36Sopenharmony_ci [low_vs0] "+r" (low_vs0), 21162306a36Sopenharmony_ci [high_vs32] "=r" (high_vs32), 21262306a36Sopenharmony_ci [low_vs32] "=r" (low_vs32), 21362306a36Sopenharmony_ci [cr_] "+r" (cr_) 21462306a36Sopenharmony_ci : [touch_fp] "r" (flags.touch_fp), 21562306a36Sopenharmony_ci [touch_vec] "r" (flags.touch_vec), 21662306a36Sopenharmony_ci [exception] "r" (flags.exception), 21762306a36Sopenharmony_ci [ex_fp] "i" (FP_UNA_EXCEPTION), 21862306a36Sopenharmony_ci [ex_vec] "i" (VEC_UNA_EXCEPTION), 21962306a36Sopenharmony_ci [ex_vsx] "i" (VSX_UNA_EXCEPTION), 22062306a36Sopenharmony_ci [counter] "r" (counter) 22162306a36Sopenharmony_ci 22262306a36Sopenharmony_ci : "cr0", "ctr", "v10", "vs0", "vs10", "vs3", "vs32", "vs33", 22362306a36Sopenharmony_ci "vs34", "fr10" 22462306a36Sopenharmony_ci 22562306a36Sopenharmony_ci ); 22662306a36Sopenharmony_ci 22762306a36Sopenharmony_ci /* 22862306a36Sopenharmony_ci * Check if we were expecting a failure and it did not occur by checking 22962306a36Sopenharmony_ci * CR0 state just after we leave the transaction. Either way we check if 23062306a36Sopenharmony_ci * vs0 or vs32 got corrupted. 23162306a36Sopenharmony_ci */ 23262306a36Sopenharmony_ci if (expecting_failure() && !is_failure(cr_)) { 23362306a36Sopenharmony_ci printf("\n\tExpecting the transaction to fail, %s", 23462306a36Sopenharmony_ci "but it didn't\n\t"); 23562306a36Sopenharmony_ci flags.result++; 23662306a36Sopenharmony_ci } 23762306a36Sopenharmony_ci 23862306a36Sopenharmony_ci /* Check if we were not expecting a failure and a it occurred. */ 23962306a36Sopenharmony_ci if (!expecting_failure() && is_failure(cr_) && 24062306a36Sopenharmony_ci !failure_is_reschedule()) { 24162306a36Sopenharmony_ci printf("\n\tUnexpected transaction failure 0x%02lx\n\t", 24262306a36Sopenharmony_ci failure_code()); 24362306a36Sopenharmony_ci return (void *) -1; 24462306a36Sopenharmony_ci } 24562306a36Sopenharmony_ci 24662306a36Sopenharmony_ci /* 24762306a36Sopenharmony_ci * Check if TM failed due to the cause we were expecting. 0xda is a 24862306a36Sopenharmony_ci * TM_CAUSE_FAC_UNAV cause, otherwise it's an unexpected cause, unless 24962306a36Sopenharmony_ci * it was caused by a reschedule. 25062306a36Sopenharmony_ci */ 25162306a36Sopenharmony_ci if (is_failure(cr_) && !failure_is_unavailable() && 25262306a36Sopenharmony_ci !failure_is_reschedule()) { 25362306a36Sopenharmony_ci printf("\n\tUnexpected failure cause 0x%02lx\n\t", 25462306a36Sopenharmony_ci failure_code()); 25562306a36Sopenharmony_ci return (void *) -1; 25662306a36Sopenharmony_ci } 25762306a36Sopenharmony_ci 25862306a36Sopenharmony_ci /* 0x4 is a success and 0xa is a fail. See comment in is_failure(). */ 25962306a36Sopenharmony_ci if (DEBUG) 26062306a36Sopenharmony_ci printf("CR0: 0x%1lx ", cr_ >> 28); 26162306a36Sopenharmony_ci 26262306a36Sopenharmony_ci /* Check FP (vs0) for the expected value. */ 26362306a36Sopenharmony_ci if (high_vs0 != 0x5555555555555555 || low_vs0 != 0xFFFFFFFFFFFFFFFF) { 26462306a36Sopenharmony_ci printf("FP corrupted!"); 26562306a36Sopenharmony_ci printf(" high = %#16" PRIx64 " low = %#16" PRIx64 " ", 26662306a36Sopenharmony_ci high_vs0, low_vs0); 26762306a36Sopenharmony_ci flags.result++; 26862306a36Sopenharmony_ci } else 26962306a36Sopenharmony_ci printf("FP ok "); 27062306a36Sopenharmony_ci 27162306a36Sopenharmony_ci /* Check VEC (vs32) for the expected value. */ 27262306a36Sopenharmony_ci if (high_vs32 != 0x5555555555555555 || low_vs32 != 0xFFFFFFFFFFFFFFFF) { 27362306a36Sopenharmony_ci printf("VEC corrupted!"); 27462306a36Sopenharmony_ci printf(" high = %#16" PRIx64 " low = %#16" PRIx64, 27562306a36Sopenharmony_ci high_vs32, low_vs32); 27662306a36Sopenharmony_ci flags.result++; 27762306a36Sopenharmony_ci } else 27862306a36Sopenharmony_ci printf("VEC ok"); 27962306a36Sopenharmony_ci 28062306a36Sopenharmony_ci putchar('\n'); 28162306a36Sopenharmony_ci 28262306a36Sopenharmony_ci return NULL; 28362306a36Sopenharmony_ci} 28462306a36Sopenharmony_ci 28562306a36Sopenharmony_ci/* Thread to force context switch */ 28662306a36Sopenharmony_civoid *tm_una_pong(void *not_used) 28762306a36Sopenharmony_ci{ 28862306a36Sopenharmony_ci /* Wait thread get its name "pong". */ 28962306a36Sopenharmony_ci if (DEBUG) 29062306a36Sopenharmony_ci sleep(1); 29162306a36Sopenharmony_ci 29262306a36Sopenharmony_ci /* Classed as an interactive-like thread. */ 29362306a36Sopenharmony_ci while (1) 29462306a36Sopenharmony_ci sched_yield(); 29562306a36Sopenharmony_ci} 29662306a36Sopenharmony_ci 29762306a36Sopenharmony_ci/* Function that creates a thread and launches the "ping" task. */ 29862306a36Sopenharmony_civoid test_fp_vec(int fp, int vec, pthread_attr_t *attr) 29962306a36Sopenharmony_ci{ 30062306a36Sopenharmony_ci int retries = 2; 30162306a36Sopenharmony_ci void *ret_value; 30262306a36Sopenharmony_ci pthread_t t0; 30362306a36Sopenharmony_ci 30462306a36Sopenharmony_ci flags.touch_fp = fp; 30562306a36Sopenharmony_ci flags.touch_vec = vec; 30662306a36Sopenharmony_ci 30762306a36Sopenharmony_ci /* 30862306a36Sopenharmony_ci * Without luck it's possible that the transaction is aborted not due to 30962306a36Sopenharmony_ci * the unavailable exception caught in the middle as we expect but also, 31062306a36Sopenharmony_ci * for instance, due to a context switch or due to a KVM reschedule (if 31162306a36Sopenharmony_ci * it's running on a VM). Thus we try a few times before giving up, 31262306a36Sopenharmony_ci * checking if the failure cause is the one we expect. 31362306a36Sopenharmony_ci */ 31462306a36Sopenharmony_ci do { 31562306a36Sopenharmony_ci int rc; 31662306a36Sopenharmony_ci 31762306a36Sopenharmony_ci /* Bind to CPU 0, as specified in 'attr'. */ 31862306a36Sopenharmony_ci rc = pthread_create(&t0, attr, tm_una_ping, (void *) &flags); 31962306a36Sopenharmony_ci if (rc) 32062306a36Sopenharmony_ci pr_err(rc, "pthread_create()"); 32162306a36Sopenharmony_ci rc = pthread_setname_np(t0, "tm_una_ping"); 32262306a36Sopenharmony_ci if (rc) 32362306a36Sopenharmony_ci pr_warn(rc, "pthread_setname_np"); 32462306a36Sopenharmony_ci rc = pthread_join(t0, &ret_value); 32562306a36Sopenharmony_ci if (rc) 32662306a36Sopenharmony_ci pr_err(rc, "pthread_join"); 32762306a36Sopenharmony_ci 32862306a36Sopenharmony_ci retries--; 32962306a36Sopenharmony_ci } while (ret_value != NULL && retries); 33062306a36Sopenharmony_ci 33162306a36Sopenharmony_ci if (!retries) { 33262306a36Sopenharmony_ci flags.result = 1; 33362306a36Sopenharmony_ci if (DEBUG) 33462306a36Sopenharmony_ci printf("All transactions failed unexpectedly\n"); 33562306a36Sopenharmony_ci 33662306a36Sopenharmony_ci } 33762306a36Sopenharmony_ci} 33862306a36Sopenharmony_ci 33962306a36Sopenharmony_ciint tm_unavailable_test(void) 34062306a36Sopenharmony_ci{ 34162306a36Sopenharmony_ci int cpu, rc, exception; /* FP = 0, VEC = 1, VSX = 2 */ 34262306a36Sopenharmony_ci pthread_t t1; 34362306a36Sopenharmony_ci pthread_attr_t attr; 34462306a36Sopenharmony_ci cpu_set_t cpuset; 34562306a36Sopenharmony_ci 34662306a36Sopenharmony_ci SKIP_IF(!have_htm()); 34762306a36Sopenharmony_ci SKIP_IF(htm_is_synthetic()); 34862306a36Sopenharmony_ci 34962306a36Sopenharmony_ci cpu = pick_online_cpu(); 35062306a36Sopenharmony_ci FAIL_IF(cpu < 0); 35162306a36Sopenharmony_ci 35262306a36Sopenharmony_ci // Set only one CPU in the mask. Both threads will be bound to that CPU. 35362306a36Sopenharmony_ci CPU_ZERO(&cpuset); 35462306a36Sopenharmony_ci CPU_SET(cpu, &cpuset); 35562306a36Sopenharmony_ci 35662306a36Sopenharmony_ci /* Init pthread attribute. */ 35762306a36Sopenharmony_ci rc = pthread_attr_init(&attr); 35862306a36Sopenharmony_ci if (rc) 35962306a36Sopenharmony_ci pr_err(rc, "pthread_attr_init()"); 36062306a36Sopenharmony_ci 36162306a36Sopenharmony_ci /* Set CPU 0 mask into the pthread attribute. */ 36262306a36Sopenharmony_ci rc = pthread_attr_setaffinity_np(&attr, sizeof(cpu_set_t), &cpuset); 36362306a36Sopenharmony_ci if (rc) 36462306a36Sopenharmony_ci pr_err(rc, "pthread_attr_setaffinity_np()"); 36562306a36Sopenharmony_ci 36662306a36Sopenharmony_ci rc = pthread_create(&t1, &attr /* Bind to CPU 0 */, tm_una_pong, NULL); 36762306a36Sopenharmony_ci if (rc) 36862306a36Sopenharmony_ci pr_err(rc, "pthread_create()"); 36962306a36Sopenharmony_ci 37062306a36Sopenharmony_ci /* Name it for systemtap convenience */ 37162306a36Sopenharmony_ci rc = pthread_setname_np(t1, "tm_una_pong"); 37262306a36Sopenharmony_ci if (rc) 37362306a36Sopenharmony_ci pr_warn(rc, "pthread_create()"); 37462306a36Sopenharmony_ci 37562306a36Sopenharmony_ci flags.result = 0; 37662306a36Sopenharmony_ci 37762306a36Sopenharmony_ci for (exception = 0; exception < NUM_EXCEPTIONS; exception++) { 37862306a36Sopenharmony_ci printf("Checking if FP/VEC registers are sane after"); 37962306a36Sopenharmony_ci 38062306a36Sopenharmony_ci if (exception == FP_UNA_EXCEPTION) 38162306a36Sopenharmony_ci printf(" a FP unavailable exception...\n"); 38262306a36Sopenharmony_ci 38362306a36Sopenharmony_ci else if (exception == VEC_UNA_EXCEPTION) 38462306a36Sopenharmony_ci printf(" a VEC unavailable exception...\n"); 38562306a36Sopenharmony_ci 38662306a36Sopenharmony_ci else 38762306a36Sopenharmony_ci printf(" a VSX unavailable exception...\n"); 38862306a36Sopenharmony_ci 38962306a36Sopenharmony_ci flags.exception = exception; 39062306a36Sopenharmony_ci 39162306a36Sopenharmony_ci test_fp_vec(0, 0, &attr); 39262306a36Sopenharmony_ci test_fp_vec(1, 0, &attr); 39362306a36Sopenharmony_ci test_fp_vec(0, 1, &attr); 39462306a36Sopenharmony_ci test_fp_vec(1, 1, &attr); 39562306a36Sopenharmony_ci 39662306a36Sopenharmony_ci } 39762306a36Sopenharmony_ci 39862306a36Sopenharmony_ci if (flags.result > 0) { 39962306a36Sopenharmony_ci printf("result: failed!\n"); 40062306a36Sopenharmony_ci exit(1); 40162306a36Sopenharmony_ci } else { 40262306a36Sopenharmony_ci printf("result: success\n"); 40362306a36Sopenharmony_ci exit(0); 40462306a36Sopenharmony_ci } 40562306a36Sopenharmony_ci} 40662306a36Sopenharmony_ci 40762306a36Sopenharmony_ciint main(int argc, char **argv) 40862306a36Sopenharmony_ci{ 40962306a36Sopenharmony_ci test_harness_set_timeout(220); 41062306a36Sopenharmony_ci return test_harness(tm_unavailable_test, "tm_unavailable_test"); 41162306a36Sopenharmony_ci} 412