0001
0002
0003
0004
0005
0006
0007
0008
0009
0010
0011
0012
0013
0014
0015
0016
0017 #define _GNU_SOURCE
0018 #include <error.h>
0019 #include <stdio.h>
0020 #include <stdlib.h>
0021 #include <unistd.h>
0022 #include <inttypes.h>
0023 #include <stdbool.h>
0024 #include <pthread.h>
0025 #include <sched.h>
0026
0027 #include "tm.h"
0028
0029 #define DEBUG 0
0030
0031
0032 #define FP_UNA_EXCEPTION 0
0033 #define VEC_UNA_EXCEPTION 1
0034 #define VSX_UNA_EXCEPTION 2
0035
0036 #define NUM_EXCEPTIONS 3
0037 #define err_at_line(status, errnum, format, ...) \
0038 error_at_line(status, errnum, __FILE__, __LINE__, format ##__VA_ARGS__)
0039
0040 #define pr_warn(code, format, ...) err_at_line(0, code, format, ##__VA_ARGS__)
0041 #define pr_err(code, format, ...) err_at_line(1, code, format, ##__VA_ARGS__)
0042
0043 struct Flags {
0044 int touch_fp;
0045 int touch_vec;
0046 int result;
0047 int exception;
0048 } flags;
0049
0050 bool expecting_failure(void)
0051 {
0052 if (flags.touch_fp && flags.exception == FP_UNA_EXCEPTION)
0053 return false;
0054
0055 if (flags.touch_vec && flags.exception == VEC_UNA_EXCEPTION)
0056 return false;
0057
0058
0059
0060
0061
0062
0063
0064
0065 if ((flags.touch_fp && flags.touch_vec) &&
0066 flags.exception == VSX_UNA_EXCEPTION)
0067 return false;
0068
0069 return true;
0070 }
0071
0072
0073 bool is_failure(uint64_t condition_reg)
0074 {
0075
0076
0077
0078
0079
0080 return ((condition_reg >> 28) & 0xa) == 0xa;
0081 }
0082
0083 void *tm_una_ping(void *input)
0084 {
0085
0086
0087
0088
0089
0090 uint64_t high_vs0 = 0x5555555555555555;
0091 uint64_t low_vs0 = 0xffffffffffffffff;
0092 uint64_t high_vs32 = 0x5555555555555555;
0093 uint64_t low_vs32 = 0xffffffffffffffff;
0094
0095
0096 uint64_t counter = 0x1ff000000;
0097
0098
0099
0100
0101
0102 uint64_t cr_ = 0;
0103
0104
0105
0106
0107
0108 if (DEBUG)
0109 sleep(1);
0110
0111 printf("If MSR.FP=%d MSR.VEC=%d: ", flags.touch_fp, flags.touch_vec);
0112
0113 if (flags.exception != FP_UNA_EXCEPTION &&
0114 flags.exception != VEC_UNA_EXCEPTION &&
0115 flags.exception != VSX_UNA_EXCEPTION) {
0116 printf("No valid exception specified to test.\n");
0117 return NULL;
0118 }
0119
0120 asm (
0121
0122 " mtvsrd 33, %[high_vs0] ;"
0123 " mtvsrd 34, %[low_vs0] ;"
0124
0125
0126
0127
0128
0129 " xxmrghd 0, 33, 34 ;"
0130
0131
0132
0133
0134
0135 " xxmrghd 32, 33, 34 ;"
0136
0137
0138
0139
0140
0141 " mtctr %[counter] ;"
0142
0143
0144 "1: bdnz 1b ;"
0145
0146
0147
0148
0149
0150
0151 " cmpldi %[touch_fp], 0 ;"
0152 " beq no_fp ;"
0153 " fadd 10, 10, 10 ;"
0154 "no_fp: ;"
0155
0156
0157
0158
0159
0160
0161 " cmpldi %[touch_vec], 0 ;"
0162 " beq no_vec ;"
0163 " vaddcuw 10, 10, 10 ;"
0164 "no_vec: ;"
0165
0166
0167
0168
0169
0170
0171 " tbegin. ;"
0172 " beq trans_fail ;"
0173
0174
0175 " cmpldi %[exception], %[ex_fp] ;"
0176 " bne 1f ;"
0177 " fadd 10, 10, 10 ;"
0178 " b done ;"
0179
0180
0181 "1: cmpldi %[exception], %[ex_vec] ;"
0182 " bne 2f ;"
0183 " vaddcuw 10, 10, 10 ;"
0184 " b done ;"
0185
0186
0187
0188
0189
0190
0191
0192 "2: xxmrghd 10, 10, 10 ;"
0193
0194 "done: tend. ;"
0195
0196 "trans_fail: ;"
0197
0198
0199 " mfvsrd %[high_vs0], 0 ;"
0200 " xxsldwi 3, 0, 0, 2 ;"
0201 " mfvsrd %[low_vs0], 3 ;"
0202 " mfvsrd %[high_vs32], 32 ;"
0203 " xxsldwi 3, 32, 32, 2 ;"
0204 " mfvsrd %[low_vs32], 3 ;"
0205
0206
0207 " mfcr %[cr_] ;"
0208
0209 : [high_vs0] "+r" (high_vs0),
0210 [low_vs0] "+r" (low_vs0),
0211 [high_vs32] "=r" (high_vs32),
0212 [low_vs32] "=r" (low_vs32),
0213 [cr_] "+r" (cr_)
0214 : [touch_fp] "r" (flags.touch_fp),
0215 [touch_vec] "r" (flags.touch_vec),
0216 [exception] "r" (flags.exception),
0217 [ex_fp] "i" (FP_UNA_EXCEPTION),
0218 [ex_vec] "i" (VEC_UNA_EXCEPTION),
0219 [ex_vsx] "i" (VSX_UNA_EXCEPTION),
0220 [counter] "r" (counter)
0221
0222 : "cr0", "ctr", "v10", "vs0", "vs10", "vs3", "vs32", "vs33",
0223 "vs34", "fr10"
0224
0225 );
0226
0227
0228
0229
0230
0231
0232 if (expecting_failure() && !is_failure(cr_)) {
0233 printf("\n\tExpecting the transaction to fail, %s",
0234 "but it didn't\n\t");
0235 flags.result++;
0236 }
0237
0238
0239 if (!expecting_failure() && is_failure(cr_) &&
0240 !failure_is_reschedule()) {
0241 printf("\n\tUnexpected transaction failure 0x%02lx\n\t",
0242 failure_code());
0243 return (void *) -1;
0244 }
0245
0246
0247
0248
0249
0250
0251 if (is_failure(cr_) && !failure_is_unavailable() &&
0252 !failure_is_reschedule()) {
0253 printf("\n\tUnexpected failure cause 0x%02lx\n\t",
0254 failure_code());
0255 return (void *) -1;
0256 }
0257
0258
0259 if (DEBUG)
0260 printf("CR0: 0x%1lx ", cr_ >> 28);
0261
0262
0263 if (high_vs0 != 0x5555555555555555 || low_vs0 != 0xFFFFFFFFFFFFFFFF) {
0264 printf("FP corrupted!");
0265 printf(" high = %#16" PRIx64 " low = %#16" PRIx64 " ",
0266 high_vs0, low_vs0);
0267 flags.result++;
0268 } else
0269 printf("FP ok ");
0270
0271
0272 if (high_vs32 != 0x5555555555555555 || low_vs32 != 0xFFFFFFFFFFFFFFFF) {
0273 printf("VEC corrupted!");
0274 printf(" high = %#16" PRIx64 " low = %#16" PRIx64,
0275 high_vs32, low_vs32);
0276 flags.result++;
0277 } else
0278 printf("VEC ok");
0279
0280 putchar('\n');
0281
0282 return NULL;
0283 }
0284
0285
0286 void *tm_una_pong(void *not_used)
0287 {
0288
0289 if (DEBUG)
0290 sleep(1);
0291
0292
0293 while (1)
0294 sched_yield();
0295 }
0296
0297
0298 void test_fp_vec(int fp, int vec, pthread_attr_t *attr)
0299 {
0300 int retries = 2;
0301 void *ret_value;
0302 pthread_t t0;
0303
0304 flags.touch_fp = fp;
0305 flags.touch_vec = vec;
0306
0307
0308
0309
0310
0311
0312
0313
0314 do {
0315 int rc;
0316
0317
0318 rc = pthread_create(&t0, attr, tm_una_ping, (void *) &flags);
0319 if (rc)
0320 pr_err(rc, "pthread_create()");
0321 rc = pthread_setname_np(t0, "tm_una_ping");
0322 if (rc)
0323 pr_warn(rc, "pthread_setname_np");
0324 rc = pthread_join(t0, &ret_value);
0325 if (rc)
0326 pr_err(rc, "pthread_join");
0327
0328 retries--;
0329 } while (ret_value != NULL && retries);
0330
0331 if (!retries) {
0332 flags.result = 1;
0333 if (DEBUG)
0334 printf("All transactions failed unexpectedly\n");
0335
0336 }
0337 }
0338
0339 int tm_unavailable_test(void)
0340 {
0341 int cpu, rc, exception;
0342 pthread_t t1;
0343 pthread_attr_t attr;
0344 cpu_set_t cpuset;
0345
0346 SKIP_IF(!have_htm());
0347 SKIP_IF(htm_is_synthetic());
0348
0349 cpu = pick_online_cpu();
0350 FAIL_IF(cpu < 0);
0351
0352
0353 CPU_ZERO(&cpuset);
0354 CPU_SET(cpu, &cpuset);
0355
0356
0357 rc = pthread_attr_init(&attr);
0358 if (rc)
0359 pr_err(rc, "pthread_attr_init()");
0360
0361
0362 rc = pthread_attr_setaffinity_np(&attr, sizeof(cpu_set_t), &cpuset);
0363 if (rc)
0364 pr_err(rc, "pthread_attr_setaffinity_np()");
0365
0366 rc = pthread_create(&t1, &attr , tm_una_pong, NULL);
0367 if (rc)
0368 pr_err(rc, "pthread_create()");
0369
0370
0371 rc = pthread_setname_np(t1, "tm_una_pong");
0372 if (rc)
0373 pr_warn(rc, "pthread_create()");
0374
0375 flags.result = 0;
0376
0377 for (exception = 0; exception < NUM_EXCEPTIONS; exception++) {
0378 printf("Checking if FP/VEC registers are sane after");
0379
0380 if (exception == FP_UNA_EXCEPTION)
0381 printf(" a FP unavailable exception...\n");
0382
0383 else if (exception == VEC_UNA_EXCEPTION)
0384 printf(" a VEC unavailable exception...\n");
0385
0386 else
0387 printf(" a VSX unavailable exception...\n");
0388
0389 flags.exception = exception;
0390
0391 test_fp_vec(0, 0, &attr);
0392 test_fp_vec(1, 0, &attr);
0393 test_fp_vec(0, 1, &attr);
0394 test_fp_vec(1, 1, &attr);
0395
0396 }
0397
0398 if (flags.result > 0) {
0399 printf("result: failed!\n");
0400 exit(1);
0401 } else {
0402 printf("result: success\n");
0403 exit(0);
0404 }
0405 }
0406
0407 int main(int argc, char **argv)
0408 {
0409 test_harness_set_timeout(220);
0410 return test_harness(tm_unavailable_test, "tm_unavailable_test");
0411 }