18c2ecf20Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0-only 28c2ecf20Sopenharmony_ci/* 38c2ecf20Sopenharmony_ci * Copyright 2017, Gustavo Romero, Breno Leitao, Cyril Bur, IBM Corp. 48c2ecf20Sopenharmony_ci * 58c2ecf20Sopenharmony_ci * Force FP, VEC and VSX unavailable exception during transaction in all 68c2ecf20Sopenharmony_ci * possible scenarios regarding the MSR.FP and MSR.VEC state, e.g. when FP 78c2ecf20Sopenharmony_ci * is enable and VEC is disable, when FP is disable and VEC is enable, and 88c2ecf20Sopenharmony_ci * so on. Then we check if the restored state is correctly set for the 98c2ecf20Sopenharmony_ci * FP and VEC registers to the previous state we set just before we entered 108c2ecf20Sopenharmony_ci * in TM, i.e. we check if it corrupts somehow the recheckpointed FP and 118c2ecf20Sopenharmony_ci * VEC/Altivec registers on abortion due to an unavailable exception in TM. 128c2ecf20Sopenharmony_ci * N.B. In this test we do not test all the FP/Altivec/VSX registers for 138c2ecf20Sopenharmony_ci * corruption, but only for registers vs0 and vs32, which are respectively 148c2ecf20Sopenharmony_ci * representatives of FP and VEC/Altivec reg sets. 158c2ecf20Sopenharmony_ci */ 168c2ecf20Sopenharmony_ci 178c2ecf20Sopenharmony_ci#define _GNU_SOURCE 188c2ecf20Sopenharmony_ci#include <error.h> 198c2ecf20Sopenharmony_ci#include <stdio.h> 208c2ecf20Sopenharmony_ci#include <stdlib.h> 218c2ecf20Sopenharmony_ci#include <unistd.h> 228c2ecf20Sopenharmony_ci#include <inttypes.h> 238c2ecf20Sopenharmony_ci#include <stdbool.h> 248c2ecf20Sopenharmony_ci#include <pthread.h> 258c2ecf20Sopenharmony_ci#include <sched.h> 268c2ecf20Sopenharmony_ci 278c2ecf20Sopenharmony_ci#include "tm.h" 288c2ecf20Sopenharmony_ci 298c2ecf20Sopenharmony_ci#define DEBUG 0 308c2ecf20Sopenharmony_ci 318c2ecf20Sopenharmony_ci/* Unavailable exceptions to test in HTM */ 328c2ecf20Sopenharmony_ci#define FP_UNA_EXCEPTION 0 338c2ecf20Sopenharmony_ci#define VEC_UNA_EXCEPTION 1 348c2ecf20Sopenharmony_ci#define VSX_UNA_EXCEPTION 2 358c2ecf20Sopenharmony_ci 368c2ecf20Sopenharmony_ci#define NUM_EXCEPTIONS 3 378c2ecf20Sopenharmony_ci#define err_at_line(status, errnum, format, ...) \ 388c2ecf20Sopenharmony_ci error_at_line(status, errnum, __FILE__, __LINE__, format ##__VA_ARGS__) 398c2ecf20Sopenharmony_ci 408c2ecf20Sopenharmony_ci#define pr_warn(code, format, ...) err_at_line(0, code, format, ##__VA_ARGS__) 418c2ecf20Sopenharmony_ci#define pr_err(code, format, ...) err_at_line(1, code, format, ##__VA_ARGS__) 428c2ecf20Sopenharmony_ci 438c2ecf20Sopenharmony_cistruct Flags { 448c2ecf20Sopenharmony_ci int touch_fp; 458c2ecf20Sopenharmony_ci int touch_vec; 468c2ecf20Sopenharmony_ci int result; 478c2ecf20Sopenharmony_ci int exception; 488c2ecf20Sopenharmony_ci} flags; 498c2ecf20Sopenharmony_ci 508c2ecf20Sopenharmony_cibool expecting_failure(void) 518c2ecf20Sopenharmony_ci{ 528c2ecf20Sopenharmony_ci if (flags.touch_fp && flags.exception == FP_UNA_EXCEPTION) 538c2ecf20Sopenharmony_ci return false; 548c2ecf20Sopenharmony_ci 558c2ecf20Sopenharmony_ci if (flags.touch_vec && flags.exception == VEC_UNA_EXCEPTION) 568c2ecf20Sopenharmony_ci return false; 578c2ecf20Sopenharmony_ci 588c2ecf20Sopenharmony_ci /* 598c2ecf20Sopenharmony_ci * If both FP and VEC are touched it does not mean that touching VSX 608c2ecf20Sopenharmony_ci * won't raise an exception. However since FP and VEC state are already 618c2ecf20Sopenharmony_ci * correctly loaded, the transaction is not aborted (i.e. 628c2ecf20Sopenharmony_ci * treclaimed/trecheckpointed) and MSR.VSX is just set as 1, so a TM 638c2ecf20Sopenharmony_ci * failure is not expected also in this case. 648c2ecf20Sopenharmony_ci */ 658c2ecf20Sopenharmony_ci if ((flags.touch_fp && flags.touch_vec) && 668c2ecf20Sopenharmony_ci flags.exception == VSX_UNA_EXCEPTION) 678c2ecf20Sopenharmony_ci return false; 688c2ecf20Sopenharmony_ci 698c2ecf20Sopenharmony_ci return true; 708c2ecf20Sopenharmony_ci} 718c2ecf20Sopenharmony_ci 728c2ecf20Sopenharmony_ci/* Check if failure occurred whilst in transaction. */ 738c2ecf20Sopenharmony_cibool is_failure(uint64_t condition_reg) 748c2ecf20Sopenharmony_ci{ 758c2ecf20Sopenharmony_ci /* 768c2ecf20Sopenharmony_ci * When failure handling occurs, CR0 is set to 0b1010 (0xa). Otherwise 778c2ecf20Sopenharmony_ci * transaction completes without failure and hence reaches out 'tend.' 788c2ecf20Sopenharmony_ci * that sets CR0 to 0b0100 (0x4). 798c2ecf20Sopenharmony_ci */ 808c2ecf20Sopenharmony_ci return ((condition_reg >> 28) & 0xa) == 0xa; 818c2ecf20Sopenharmony_ci} 828c2ecf20Sopenharmony_ci 838c2ecf20Sopenharmony_civoid *tm_una_ping(void *input) 848c2ecf20Sopenharmony_ci{ 858c2ecf20Sopenharmony_ci 868c2ecf20Sopenharmony_ci /* 878c2ecf20Sopenharmony_ci * Expected values for vs0 and vs32 after a TM failure. They must never 888c2ecf20Sopenharmony_ci * change, otherwise they got corrupted. 898c2ecf20Sopenharmony_ci */ 908c2ecf20Sopenharmony_ci uint64_t high_vs0 = 0x5555555555555555; 918c2ecf20Sopenharmony_ci uint64_t low_vs0 = 0xffffffffffffffff; 928c2ecf20Sopenharmony_ci uint64_t high_vs32 = 0x5555555555555555; 938c2ecf20Sopenharmony_ci uint64_t low_vs32 = 0xffffffffffffffff; 948c2ecf20Sopenharmony_ci 958c2ecf20Sopenharmony_ci /* Counter for busy wait */ 968c2ecf20Sopenharmony_ci uint64_t counter = 0x1ff000000; 978c2ecf20Sopenharmony_ci 988c2ecf20Sopenharmony_ci /* 998c2ecf20Sopenharmony_ci * Variable to keep a copy of CR register content taken just after we 1008c2ecf20Sopenharmony_ci * leave the transactional state. 1018c2ecf20Sopenharmony_ci */ 1028c2ecf20Sopenharmony_ci uint64_t cr_ = 0; 1038c2ecf20Sopenharmony_ci 1048c2ecf20Sopenharmony_ci /* 1058c2ecf20Sopenharmony_ci * Wait a bit so thread can get its name "ping". This is not important 1068c2ecf20Sopenharmony_ci * to reproduce the issue but it's nice to have for systemtap debugging. 1078c2ecf20Sopenharmony_ci */ 1088c2ecf20Sopenharmony_ci if (DEBUG) 1098c2ecf20Sopenharmony_ci sleep(1); 1108c2ecf20Sopenharmony_ci 1118c2ecf20Sopenharmony_ci printf("If MSR.FP=%d MSR.VEC=%d: ", flags.touch_fp, flags.touch_vec); 1128c2ecf20Sopenharmony_ci 1138c2ecf20Sopenharmony_ci if (flags.exception != FP_UNA_EXCEPTION && 1148c2ecf20Sopenharmony_ci flags.exception != VEC_UNA_EXCEPTION && 1158c2ecf20Sopenharmony_ci flags.exception != VSX_UNA_EXCEPTION) { 1168c2ecf20Sopenharmony_ci printf("No valid exception specified to test.\n"); 1178c2ecf20Sopenharmony_ci return NULL; 1188c2ecf20Sopenharmony_ci } 1198c2ecf20Sopenharmony_ci 1208c2ecf20Sopenharmony_ci asm ( 1218c2ecf20Sopenharmony_ci /* Prepare to merge low and high. */ 1228c2ecf20Sopenharmony_ci " mtvsrd 33, %[high_vs0] ;" 1238c2ecf20Sopenharmony_ci " mtvsrd 34, %[low_vs0] ;" 1248c2ecf20Sopenharmony_ci 1258c2ecf20Sopenharmony_ci /* 1268c2ecf20Sopenharmony_ci * Adjust VS0 expected value after an TM failure, 1278c2ecf20Sopenharmony_ci * i.e. vs0 = 0x5555555555555555555FFFFFFFFFFFFFFFF 1288c2ecf20Sopenharmony_ci */ 1298c2ecf20Sopenharmony_ci " xxmrghd 0, 33, 34 ;" 1308c2ecf20Sopenharmony_ci 1318c2ecf20Sopenharmony_ci /* 1328c2ecf20Sopenharmony_ci * Adjust VS32 expected value after an TM failure, 1338c2ecf20Sopenharmony_ci * i.e. vs32 = 0x5555555555555555555FFFFFFFFFFFFFFFF 1348c2ecf20Sopenharmony_ci */ 1358c2ecf20Sopenharmony_ci " xxmrghd 32, 33, 34 ;" 1368c2ecf20Sopenharmony_ci 1378c2ecf20Sopenharmony_ci /* 1388c2ecf20Sopenharmony_ci * Wait an amount of context switches so load_fp and load_vec 1398c2ecf20Sopenharmony_ci * overflow and MSR.FP, MSR.VEC, and MSR.VSX become zero (off). 1408c2ecf20Sopenharmony_ci */ 1418c2ecf20Sopenharmony_ci " mtctr %[counter] ;" 1428c2ecf20Sopenharmony_ci 1438c2ecf20Sopenharmony_ci /* Decrement CTR branch if CTR non zero. */ 1448c2ecf20Sopenharmony_ci "1: bdnz 1b ;" 1458c2ecf20Sopenharmony_ci 1468c2ecf20Sopenharmony_ci /* 1478c2ecf20Sopenharmony_ci * Check if we want to touch FP prior to the test in order 1488c2ecf20Sopenharmony_ci * to set MSR.FP = 1 before provoking an unavailable 1498c2ecf20Sopenharmony_ci * exception in TM. 1508c2ecf20Sopenharmony_ci */ 1518c2ecf20Sopenharmony_ci " cmpldi %[touch_fp], 0 ;" 1528c2ecf20Sopenharmony_ci " beq no_fp ;" 1538c2ecf20Sopenharmony_ci " fadd 10, 10, 10 ;" 1548c2ecf20Sopenharmony_ci "no_fp: ;" 1558c2ecf20Sopenharmony_ci 1568c2ecf20Sopenharmony_ci /* 1578c2ecf20Sopenharmony_ci * Check if we want to touch VEC prior to the test in order 1588c2ecf20Sopenharmony_ci * to set MSR.VEC = 1 before provoking an unavailable 1598c2ecf20Sopenharmony_ci * exception in TM. 1608c2ecf20Sopenharmony_ci */ 1618c2ecf20Sopenharmony_ci " cmpldi %[touch_vec], 0 ;" 1628c2ecf20Sopenharmony_ci " beq no_vec ;" 1638c2ecf20Sopenharmony_ci " vaddcuw 10, 10, 10 ;" 1648c2ecf20Sopenharmony_ci "no_vec: ;" 1658c2ecf20Sopenharmony_ci 1668c2ecf20Sopenharmony_ci /* 1678c2ecf20Sopenharmony_ci * Perhaps it would be a better idea to do the 1688c2ecf20Sopenharmony_ci * compares outside transactional context and simply 1698c2ecf20Sopenharmony_ci * duplicate code. 1708c2ecf20Sopenharmony_ci */ 1718c2ecf20Sopenharmony_ci " tbegin. ;" 1728c2ecf20Sopenharmony_ci " beq trans_fail ;" 1738c2ecf20Sopenharmony_ci 1748c2ecf20Sopenharmony_ci /* Do we do FP Unavailable? */ 1758c2ecf20Sopenharmony_ci " cmpldi %[exception], %[ex_fp] ;" 1768c2ecf20Sopenharmony_ci " bne 1f ;" 1778c2ecf20Sopenharmony_ci " fadd 10, 10, 10 ;" 1788c2ecf20Sopenharmony_ci " b done ;" 1798c2ecf20Sopenharmony_ci 1808c2ecf20Sopenharmony_ci /* Do we do VEC Unavailable? */ 1818c2ecf20Sopenharmony_ci "1: cmpldi %[exception], %[ex_vec] ;" 1828c2ecf20Sopenharmony_ci " bne 2f ;" 1838c2ecf20Sopenharmony_ci " vaddcuw 10, 10, 10 ;" 1848c2ecf20Sopenharmony_ci " b done ;" 1858c2ecf20Sopenharmony_ci 1868c2ecf20Sopenharmony_ci /* 1878c2ecf20Sopenharmony_ci * Not FP or VEC, therefore VSX. Ensure this 1888c2ecf20Sopenharmony_ci * instruction always generates a VSX Unavailable. 1898c2ecf20Sopenharmony_ci * ISA 3.0 is tricky here. 1908c2ecf20Sopenharmony_ci * (xxmrghd will on ISA 2.07 and ISA 3.0) 1918c2ecf20Sopenharmony_ci */ 1928c2ecf20Sopenharmony_ci "2: xxmrghd 10, 10, 10 ;" 1938c2ecf20Sopenharmony_ci 1948c2ecf20Sopenharmony_ci "done: tend. ;" 1958c2ecf20Sopenharmony_ci 1968c2ecf20Sopenharmony_ci "trans_fail: ;" 1978c2ecf20Sopenharmony_ci 1988c2ecf20Sopenharmony_ci /* Give values back to C. */ 1998c2ecf20Sopenharmony_ci " mfvsrd %[high_vs0], 0 ;" 2008c2ecf20Sopenharmony_ci " xxsldwi 3, 0, 0, 2 ;" 2018c2ecf20Sopenharmony_ci " mfvsrd %[low_vs0], 3 ;" 2028c2ecf20Sopenharmony_ci " mfvsrd %[high_vs32], 32 ;" 2038c2ecf20Sopenharmony_ci " xxsldwi 3, 32, 32, 2 ;" 2048c2ecf20Sopenharmony_ci " mfvsrd %[low_vs32], 3 ;" 2058c2ecf20Sopenharmony_ci 2068c2ecf20Sopenharmony_ci /* Give CR back to C so that it can check what happened. */ 2078c2ecf20Sopenharmony_ci " mfcr %[cr_] ;" 2088c2ecf20Sopenharmony_ci 2098c2ecf20Sopenharmony_ci : [high_vs0] "+r" (high_vs0), 2108c2ecf20Sopenharmony_ci [low_vs0] "+r" (low_vs0), 2118c2ecf20Sopenharmony_ci [high_vs32] "=r" (high_vs32), 2128c2ecf20Sopenharmony_ci [low_vs32] "=r" (low_vs32), 2138c2ecf20Sopenharmony_ci [cr_] "+r" (cr_) 2148c2ecf20Sopenharmony_ci : [touch_fp] "r" (flags.touch_fp), 2158c2ecf20Sopenharmony_ci [touch_vec] "r" (flags.touch_vec), 2168c2ecf20Sopenharmony_ci [exception] "r" (flags.exception), 2178c2ecf20Sopenharmony_ci [ex_fp] "i" (FP_UNA_EXCEPTION), 2188c2ecf20Sopenharmony_ci [ex_vec] "i" (VEC_UNA_EXCEPTION), 2198c2ecf20Sopenharmony_ci [ex_vsx] "i" (VSX_UNA_EXCEPTION), 2208c2ecf20Sopenharmony_ci [counter] "r" (counter) 2218c2ecf20Sopenharmony_ci 2228c2ecf20Sopenharmony_ci : "cr0", "ctr", "v10", "vs0", "vs10", "vs3", "vs32", "vs33", 2238c2ecf20Sopenharmony_ci "vs34", "fr10" 2248c2ecf20Sopenharmony_ci 2258c2ecf20Sopenharmony_ci ); 2268c2ecf20Sopenharmony_ci 2278c2ecf20Sopenharmony_ci /* 2288c2ecf20Sopenharmony_ci * Check if we were expecting a failure and it did not occur by checking 2298c2ecf20Sopenharmony_ci * CR0 state just after we leave the transaction. Either way we check if 2308c2ecf20Sopenharmony_ci * vs0 or vs32 got corrupted. 2318c2ecf20Sopenharmony_ci */ 2328c2ecf20Sopenharmony_ci if (expecting_failure() && !is_failure(cr_)) { 2338c2ecf20Sopenharmony_ci printf("\n\tExpecting the transaction to fail, %s", 2348c2ecf20Sopenharmony_ci "but it didn't\n\t"); 2358c2ecf20Sopenharmony_ci flags.result++; 2368c2ecf20Sopenharmony_ci } 2378c2ecf20Sopenharmony_ci 2388c2ecf20Sopenharmony_ci /* Check if we were not expecting a failure and a it occurred. */ 2398c2ecf20Sopenharmony_ci if (!expecting_failure() && is_failure(cr_) && 2408c2ecf20Sopenharmony_ci !failure_is_reschedule()) { 2418c2ecf20Sopenharmony_ci printf("\n\tUnexpected transaction failure 0x%02lx\n\t", 2428c2ecf20Sopenharmony_ci failure_code()); 2438c2ecf20Sopenharmony_ci return (void *) -1; 2448c2ecf20Sopenharmony_ci } 2458c2ecf20Sopenharmony_ci 2468c2ecf20Sopenharmony_ci /* 2478c2ecf20Sopenharmony_ci * Check if TM failed due to the cause we were expecting. 0xda is a 2488c2ecf20Sopenharmony_ci * TM_CAUSE_FAC_UNAV cause, otherwise it's an unexpected cause, unless 2498c2ecf20Sopenharmony_ci * it was caused by a reschedule. 2508c2ecf20Sopenharmony_ci */ 2518c2ecf20Sopenharmony_ci if (is_failure(cr_) && !failure_is_unavailable() && 2528c2ecf20Sopenharmony_ci !failure_is_reschedule()) { 2538c2ecf20Sopenharmony_ci printf("\n\tUnexpected failure cause 0x%02lx\n\t", 2548c2ecf20Sopenharmony_ci failure_code()); 2558c2ecf20Sopenharmony_ci return (void *) -1; 2568c2ecf20Sopenharmony_ci } 2578c2ecf20Sopenharmony_ci 2588c2ecf20Sopenharmony_ci /* 0x4 is a success and 0xa is a fail. See comment in is_failure(). */ 2598c2ecf20Sopenharmony_ci if (DEBUG) 2608c2ecf20Sopenharmony_ci printf("CR0: 0x%1lx ", cr_ >> 28); 2618c2ecf20Sopenharmony_ci 2628c2ecf20Sopenharmony_ci /* Check FP (vs0) for the expected value. */ 2638c2ecf20Sopenharmony_ci if (high_vs0 != 0x5555555555555555 || low_vs0 != 0xFFFFFFFFFFFFFFFF) { 2648c2ecf20Sopenharmony_ci printf("FP corrupted!"); 2658c2ecf20Sopenharmony_ci printf(" high = %#16" PRIx64 " low = %#16" PRIx64 " ", 2668c2ecf20Sopenharmony_ci high_vs0, low_vs0); 2678c2ecf20Sopenharmony_ci flags.result++; 2688c2ecf20Sopenharmony_ci } else 2698c2ecf20Sopenharmony_ci printf("FP ok "); 2708c2ecf20Sopenharmony_ci 2718c2ecf20Sopenharmony_ci /* Check VEC (vs32) for the expected value. */ 2728c2ecf20Sopenharmony_ci if (high_vs32 != 0x5555555555555555 || low_vs32 != 0xFFFFFFFFFFFFFFFF) { 2738c2ecf20Sopenharmony_ci printf("VEC corrupted!"); 2748c2ecf20Sopenharmony_ci printf(" high = %#16" PRIx64 " low = %#16" PRIx64, 2758c2ecf20Sopenharmony_ci high_vs32, low_vs32); 2768c2ecf20Sopenharmony_ci flags.result++; 2778c2ecf20Sopenharmony_ci } else 2788c2ecf20Sopenharmony_ci printf("VEC ok"); 2798c2ecf20Sopenharmony_ci 2808c2ecf20Sopenharmony_ci putchar('\n'); 2818c2ecf20Sopenharmony_ci 2828c2ecf20Sopenharmony_ci return NULL; 2838c2ecf20Sopenharmony_ci} 2848c2ecf20Sopenharmony_ci 2858c2ecf20Sopenharmony_ci/* Thread to force context switch */ 2868c2ecf20Sopenharmony_civoid *tm_una_pong(void *not_used) 2878c2ecf20Sopenharmony_ci{ 2888c2ecf20Sopenharmony_ci /* Wait thread get its name "pong". */ 2898c2ecf20Sopenharmony_ci if (DEBUG) 2908c2ecf20Sopenharmony_ci sleep(1); 2918c2ecf20Sopenharmony_ci 2928c2ecf20Sopenharmony_ci /* Classed as an interactive-like thread. */ 2938c2ecf20Sopenharmony_ci while (1) 2948c2ecf20Sopenharmony_ci sched_yield(); 2958c2ecf20Sopenharmony_ci} 2968c2ecf20Sopenharmony_ci 2978c2ecf20Sopenharmony_ci/* Function that creates a thread and launches the "ping" task. */ 2988c2ecf20Sopenharmony_civoid test_fp_vec(int fp, int vec, pthread_attr_t *attr) 2998c2ecf20Sopenharmony_ci{ 3008c2ecf20Sopenharmony_ci int retries = 2; 3018c2ecf20Sopenharmony_ci void *ret_value; 3028c2ecf20Sopenharmony_ci pthread_t t0; 3038c2ecf20Sopenharmony_ci 3048c2ecf20Sopenharmony_ci flags.touch_fp = fp; 3058c2ecf20Sopenharmony_ci flags.touch_vec = vec; 3068c2ecf20Sopenharmony_ci 3078c2ecf20Sopenharmony_ci /* 3088c2ecf20Sopenharmony_ci * Without luck it's possible that the transaction is aborted not due to 3098c2ecf20Sopenharmony_ci * the unavailable exception caught in the middle as we expect but also, 3108c2ecf20Sopenharmony_ci * for instance, due to a context switch or due to a KVM reschedule (if 3118c2ecf20Sopenharmony_ci * it's running on a VM). Thus we try a few times before giving up, 3128c2ecf20Sopenharmony_ci * checking if the failure cause is the one we expect. 3138c2ecf20Sopenharmony_ci */ 3148c2ecf20Sopenharmony_ci do { 3158c2ecf20Sopenharmony_ci int rc; 3168c2ecf20Sopenharmony_ci 3178c2ecf20Sopenharmony_ci /* Bind to CPU 0, as specified in 'attr'. */ 3188c2ecf20Sopenharmony_ci rc = pthread_create(&t0, attr, tm_una_ping, (void *) &flags); 3198c2ecf20Sopenharmony_ci if (rc) 3208c2ecf20Sopenharmony_ci pr_err(rc, "pthread_create()"); 3218c2ecf20Sopenharmony_ci rc = pthread_setname_np(t0, "tm_una_ping"); 3228c2ecf20Sopenharmony_ci if (rc) 3238c2ecf20Sopenharmony_ci pr_warn(rc, "pthread_setname_np"); 3248c2ecf20Sopenharmony_ci rc = pthread_join(t0, &ret_value); 3258c2ecf20Sopenharmony_ci if (rc) 3268c2ecf20Sopenharmony_ci pr_err(rc, "pthread_join"); 3278c2ecf20Sopenharmony_ci 3288c2ecf20Sopenharmony_ci retries--; 3298c2ecf20Sopenharmony_ci } while (ret_value != NULL && retries); 3308c2ecf20Sopenharmony_ci 3318c2ecf20Sopenharmony_ci if (!retries) { 3328c2ecf20Sopenharmony_ci flags.result = 1; 3338c2ecf20Sopenharmony_ci if (DEBUG) 3348c2ecf20Sopenharmony_ci printf("All transactions failed unexpectedly\n"); 3358c2ecf20Sopenharmony_ci 3368c2ecf20Sopenharmony_ci } 3378c2ecf20Sopenharmony_ci} 3388c2ecf20Sopenharmony_ci 3398c2ecf20Sopenharmony_ciint tm_unavailable_test(void) 3408c2ecf20Sopenharmony_ci{ 3418c2ecf20Sopenharmony_ci int cpu, rc, exception; /* FP = 0, VEC = 1, VSX = 2 */ 3428c2ecf20Sopenharmony_ci pthread_t t1; 3438c2ecf20Sopenharmony_ci pthread_attr_t attr; 3448c2ecf20Sopenharmony_ci cpu_set_t cpuset; 3458c2ecf20Sopenharmony_ci 3468c2ecf20Sopenharmony_ci SKIP_IF(!have_htm()); 3478c2ecf20Sopenharmony_ci 3488c2ecf20Sopenharmony_ci cpu = pick_online_cpu(); 3498c2ecf20Sopenharmony_ci FAIL_IF(cpu < 0); 3508c2ecf20Sopenharmony_ci 3518c2ecf20Sopenharmony_ci // Set only one CPU in the mask. Both threads will be bound to that CPU. 3528c2ecf20Sopenharmony_ci CPU_ZERO(&cpuset); 3538c2ecf20Sopenharmony_ci CPU_SET(cpu, &cpuset); 3548c2ecf20Sopenharmony_ci 3558c2ecf20Sopenharmony_ci /* Init pthread attribute. */ 3568c2ecf20Sopenharmony_ci rc = pthread_attr_init(&attr); 3578c2ecf20Sopenharmony_ci if (rc) 3588c2ecf20Sopenharmony_ci pr_err(rc, "pthread_attr_init()"); 3598c2ecf20Sopenharmony_ci 3608c2ecf20Sopenharmony_ci /* Set CPU 0 mask into the pthread attribute. */ 3618c2ecf20Sopenharmony_ci rc = pthread_attr_setaffinity_np(&attr, sizeof(cpu_set_t), &cpuset); 3628c2ecf20Sopenharmony_ci if (rc) 3638c2ecf20Sopenharmony_ci pr_err(rc, "pthread_attr_setaffinity_np()"); 3648c2ecf20Sopenharmony_ci 3658c2ecf20Sopenharmony_ci rc = pthread_create(&t1, &attr /* Bind to CPU 0 */, tm_una_pong, NULL); 3668c2ecf20Sopenharmony_ci if (rc) 3678c2ecf20Sopenharmony_ci pr_err(rc, "pthread_create()"); 3688c2ecf20Sopenharmony_ci 3698c2ecf20Sopenharmony_ci /* Name it for systemtap convenience */ 3708c2ecf20Sopenharmony_ci rc = pthread_setname_np(t1, "tm_una_pong"); 3718c2ecf20Sopenharmony_ci if (rc) 3728c2ecf20Sopenharmony_ci pr_warn(rc, "pthread_create()"); 3738c2ecf20Sopenharmony_ci 3748c2ecf20Sopenharmony_ci flags.result = 0; 3758c2ecf20Sopenharmony_ci 3768c2ecf20Sopenharmony_ci for (exception = 0; exception < NUM_EXCEPTIONS; exception++) { 3778c2ecf20Sopenharmony_ci printf("Checking if FP/VEC registers are sane after"); 3788c2ecf20Sopenharmony_ci 3798c2ecf20Sopenharmony_ci if (exception == FP_UNA_EXCEPTION) 3808c2ecf20Sopenharmony_ci printf(" a FP unavailable exception...\n"); 3818c2ecf20Sopenharmony_ci 3828c2ecf20Sopenharmony_ci else if (exception == VEC_UNA_EXCEPTION) 3838c2ecf20Sopenharmony_ci printf(" a VEC unavailable exception...\n"); 3848c2ecf20Sopenharmony_ci 3858c2ecf20Sopenharmony_ci else 3868c2ecf20Sopenharmony_ci printf(" a VSX unavailable exception...\n"); 3878c2ecf20Sopenharmony_ci 3888c2ecf20Sopenharmony_ci flags.exception = exception; 3898c2ecf20Sopenharmony_ci 3908c2ecf20Sopenharmony_ci test_fp_vec(0, 0, &attr); 3918c2ecf20Sopenharmony_ci test_fp_vec(1, 0, &attr); 3928c2ecf20Sopenharmony_ci test_fp_vec(0, 1, &attr); 3938c2ecf20Sopenharmony_ci test_fp_vec(1, 1, &attr); 3948c2ecf20Sopenharmony_ci 3958c2ecf20Sopenharmony_ci } 3968c2ecf20Sopenharmony_ci 3978c2ecf20Sopenharmony_ci if (flags.result > 0) { 3988c2ecf20Sopenharmony_ci printf("result: failed!\n"); 3998c2ecf20Sopenharmony_ci exit(1); 4008c2ecf20Sopenharmony_ci } else { 4018c2ecf20Sopenharmony_ci printf("result: success\n"); 4028c2ecf20Sopenharmony_ci exit(0); 4038c2ecf20Sopenharmony_ci } 4048c2ecf20Sopenharmony_ci} 4058c2ecf20Sopenharmony_ci 4068c2ecf20Sopenharmony_ciint main(int argc, char **argv) 4078c2ecf20Sopenharmony_ci{ 4088c2ecf20Sopenharmony_ci test_harness_set_timeout(220); 4098c2ecf20Sopenharmony_ci return test_harness(tm_unavailable_test, "tm_unavailable_test"); 4108c2ecf20Sopenharmony_ci} 411