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