1 /* SPDX-License-Identifier: GPL-2.0-only */
2 /*
3  * Copyright 2015, Michael Ellerman, IBM Corp.
4  */
5 
6 #ifndef _SELFTESTS_POWERPC_TM_TM_H
7 #define _SELFTESTS_POWERPC_TM_TM_H
8 
9 #include <stdbool.h>
10 #include <asm/tm.h>
11 
12 #include "utils.h"
13 #include "reg.h"
14 
15 #define TM_RETRIES 100
16 
17 static inline bool have_htm(void)
18 {
19 #ifdef PPC_FEATURE2_HTM
20 	return have_hwcap2(PPC_FEATURE2_HTM);
21 #else
22 	printf("PPC_FEATURE2_HTM not defined, can't check AT_HWCAP2\n");
23 	return false;
24 #endif
25 }
26 
27 static inline bool have_htm_nosc(void)
28 {
29 #ifdef PPC_FEATURE2_HTM_NOSC
30 	return have_hwcap2(PPC_FEATURE2_HTM_NOSC);
31 #else
32 	printf("PPC_FEATURE2_HTM_NOSC not defined, can't check AT_HWCAP2\n");
33 	return false;
34 #endif
35 }
36 
37 /*
38  * Transactional Memory was removed in ISA 3.1. A synthetic TM implementation
39  * is provided on P10 for threads running in P8/P9 compatibility  mode. The
40  * synthetic implementation immediately fails after tbegin. This failure sets
41  * Bit 7 (Failure Persistent) and Bit 15 (Implementation-specific).
42  */
43 static inline bool htm_is_synthetic(void)
44 {
45 	int i;
46 
47 	/*
48 	 * Per the ISA, the Failure Persistent bit may be incorrect. Try a few
49 	 * times in case we got an Implementation-specific failure on a non ISA
50 	 * v3.1 system. On these systems the Implementation-specific failure
51 	 * should not be persistent.
52 	 */
53 	for (i = 0; i < TM_RETRIES; i++) {
54 		asm volatile(
55 		"tbegin.;"
56 		"beq 1f;"
57 		"tend.;"
58 		"1:"
59 		:
60 		:
61 		: "memory");
62 
63 		if ((__builtin_get_texasr() & (TEXASR_FP | TEXASR_IC)) !=
64 		    (TEXASR_FP | TEXASR_IC))
65 			break;
66 	}
67 	return i == TM_RETRIES;
68 }
69 
70 static inline long failure_code(void)
71 {
72 	return __builtin_get_texasru() >> 24;
73 }
74 
75 static inline bool failure_is_persistent(void)
76 {
77 	return (failure_code() & TM_CAUSE_PERSISTENT) == TM_CAUSE_PERSISTENT;
78 }
79 
80 static inline bool failure_is_syscall(void)
81 {
82 	return (failure_code() & TM_CAUSE_SYSCALL) == TM_CAUSE_SYSCALL;
83 }
84 
85 static inline bool failure_is_unavailable(void)
86 {
87 	return (failure_code() & TM_CAUSE_FAC_UNAV) == TM_CAUSE_FAC_UNAV;
88 }
89 
90 static inline bool failure_is_reschedule(void)
91 {
92 	if ((failure_code() & TM_CAUSE_RESCHED) == TM_CAUSE_RESCHED ||
93 	    (failure_code() & TM_CAUSE_KVM_RESCHED) == TM_CAUSE_KVM_RESCHED ||
94 	    (failure_code() & TM_CAUSE_KVM_FAC_UNAV) == TM_CAUSE_KVM_FAC_UNAV)
95 		return true;
96 
97 	return false;
98 }
99 
100 static inline bool failure_is_nesting(void)
101 {
102 	return (__builtin_get_texasru() & 0x400000);
103 }
104 
105 static inline int tcheck(void)
106 {
107 	long cr;
108 	asm volatile ("tcheck 0" : "=r"(cr) : : "cr0");
109 	return (cr >> 28) & 4;
110 }
111 
112 static inline bool tcheck_doomed(void)
113 {
114 	return tcheck() & 8;
115 }
116 
117 static inline bool tcheck_active(void)
118 {
119 	return tcheck() & 4;
120 }
121 
122 static inline bool tcheck_suspended(void)
123 {
124 	return tcheck() & 2;
125 }
126 
127 static inline bool tcheck_transactional(void)
128 {
129 	return tcheck() & 6;
130 }
131 
132 #endif /* _SELFTESTS_POWERPC_TM_TM_H */
133