18c2ecf20Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0-only 28c2ecf20Sopenharmony_ci/* 38c2ecf20Sopenharmony_ci * Copyright 2015, Michael Neuling, IBM Corp. 48c2ecf20Sopenharmony_ci * 58c2ecf20Sopenharmony_ci * Original: Michael Neuling 3/4/2014 68c2ecf20Sopenharmony_ci * Modified: Rashmica Gupta 8/12/2015 78c2ecf20Sopenharmony_ci * 88c2ecf20Sopenharmony_ci * Check if any of the Transaction Memory SPRs get corrupted. 98c2ecf20Sopenharmony_ci * - TFIAR - stores address of location of transaction failure 108c2ecf20Sopenharmony_ci * - TFHAR - stores address of software failure handler (if transaction 118c2ecf20Sopenharmony_ci * fails) 128c2ecf20Sopenharmony_ci * - TEXASR - lots of info about the transacion(s) 138c2ecf20Sopenharmony_ci * 148c2ecf20Sopenharmony_ci * (1) create more threads than cpus 158c2ecf20Sopenharmony_ci * (2) in each thread: 168c2ecf20Sopenharmony_ci * (a) set TFIAR and TFHAR a unique value 178c2ecf20Sopenharmony_ci * (b) loop for awhile, continually checking to see if 188c2ecf20Sopenharmony_ci * either register has been corrupted. 198c2ecf20Sopenharmony_ci * 208c2ecf20Sopenharmony_ci * (3) Loop: 218c2ecf20Sopenharmony_ci * (a) begin transaction 228c2ecf20Sopenharmony_ci * (b) abort transaction 238c2ecf20Sopenharmony_ci * (c) check TEXASR to see if FS has been corrupted 248c2ecf20Sopenharmony_ci */ 258c2ecf20Sopenharmony_ci 268c2ecf20Sopenharmony_ci#define _GNU_SOURCE 278c2ecf20Sopenharmony_ci#include <stdio.h> 288c2ecf20Sopenharmony_ci#include <stdlib.h> 298c2ecf20Sopenharmony_ci#include <unistd.h> 308c2ecf20Sopenharmony_ci#include <pthread.h> 318c2ecf20Sopenharmony_ci#include <string.h> 328c2ecf20Sopenharmony_ci 338c2ecf20Sopenharmony_ci#include "utils.h" 348c2ecf20Sopenharmony_ci#include "tm.h" 358c2ecf20Sopenharmony_ci 368c2ecf20Sopenharmony_ciint num_loops = 1000000; 378c2ecf20Sopenharmony_ciint passed = 1; 388c2ecf20Sopenharmony_ci 398c2ecf20Sopenharmony_civoid tfiar_tfhar(void *in) 408c2ecf20Sopenharmony_ci{ 418c2ecf20Sopenharmony_ci unsigned long tfhar, tfhar_rd, tfiar, tfiar_rd; 428c2ecf20Sopenharmony_ci int i; 438c2ecf20Sopenharmony_ci 448c2ecf20Sopenharmony_ci /* TFIAR: Last bit has to be high so userspace can read register */ 458c2ecf20Sopenharmony_ci tfiar = ((unsigned long)in) + 1; 468c2ecf20Sopenharmony_ci tfiar += 2; 478c2ecf20Sopenharmony_ci mtspr(SPRN_TFIAR, tfiar); 488c2ecf20Sopenharmony_ci 498c2ecf20Sopenharmony_ci /* TFHAR: Last two bits are reserved */ 508c2ecf20Sopenharmony_ci tfhar = ((unsigned long)in); 518c2ecf20Sopenharmony_ci tfhar &= ~0x3UL; 528c2ecf20Sopenharmony_ci tfhar += 4; 538c2ecf20Sopenharmony_ci mtspr(SPRN_TFHAR, tfhar); 548c2ecf20Sopenharmony_ci 558c2ecf20Sopenharmony_ci for (i = 0; i < num_loops; i++) { 568c2ecf20Sopenharmony_ci tfhar_rd = mfspr(SPRN_TFHAR); 578c2ecf20Sopenharmony_ci tfiar_rd = mfspr(SPRN_TFIAR); 588c2ecf20Sopenharmony_ci if ( (tfhar != tfhar_rd) || (tfiar != tfiar_rd) ) { 598c2ecf20Sopenharmony_ci passed = 0; 608c2ecf20Sopenharmony_ci return; 618c2ecf20Sopenharmony_ci } 628c2ecf20Sopenharmony_ci } 638c2ecf20Sopenharmony_ci return; 648c2ecf20Sopenharmony_ci} 658c2ecf20Sopenharmony_ci 668c2ecf20Sopenharmony_civoid texasr(void *in) 678c2ecf20Sopenharmony_ci{ 688c2ecf20Sopenharmony_ci unsigned long i; 698c2ecf20Sopenharmony_ci uint64_t result = 0; 708c2ecf20Sopenharmony_ci 718c2ecf20Sopenharmony_ci for (i = 0; i < num_loops; i++) { 728c2ecf20Sopenharmony_ci asm __volatile__( 738c2ecf20Sopenharmony_ci "tbegin.;" 748c2ecf20Sopenharmony_ci "beq 3f ;" 758c2ecf20Sopenharmony_ci "tabort. 0 ;" 768c2ecf20Sopenharmony_ci "tend.;" 778c2ecf20Sopenharmony_ci 788c2ecf20Sopenharmony_ci /* Abort handler */ 798c2ecf20Sopenharmony_ci "3: ;" 808c2ecf20Sopenharmony_ci ::: "memory"); 818c2ecf20Sopenharmony_ci 828c2ecf20Sopenharmony_ci /* Check the TEXASR */ 838c2ecf20Sopenharmony_ci result = mfspr(SPRN_TEXASR); 848c2ecf20Sopenharmony_ci if ((result & TEXASR_FS) == 0) { 858c2ecf20Sopenharmony_ci passed = 0; 868c2ecf20Sopenharmony_ci return; 878c2ecf20Sopenharmony_ci } 888c2ecf20Sopenharmony_ci } 898c2ecf20Sopenharmony_ci return; 908c2ecf20Sopenharmony_ci} 918c2ecf20Sopenharmony_ci 928c2ecf20Sopenharmony_ciint test_tmspr() 938c2ecf20Sopenharmony_ci{ 948c2ecf20Sopenharmony_ci pthread_t *thread; 958c2ecf20Sopenharmony_ci int thread_num; 968c2ecf20Sopenharmony_ci unsigned long i; 978c2ecf20Sopenharmony_ci 988c2ecf20Sopenharmony_ci SKIP_IF(!have_htm()); 998c2ecf20Sopenharmony_ci 1008c2ecf20Sopenharmony_ci /* To cause some context switching */ 1018c2ecf20Sopenharmony_ci thread_num = 10 * sysconf(_SC_NPROCESSORS_ONLN); 1028c2ecf20Sopenharmony_ci 1038c2ecf20Sopenharmony_ci thread = malloc(thread_num * sizeof(pthread_t)); 1048c2ecf20Sopenharmony_ci if (thread == NULL) 1058c2ecf20Sopenharmony_ci return EXIT_FAILURE; 1068c2ecf20Sopenharmony_ci 1078c2ecf20Sopenharmony_ci /* Test TFIAR and TFHAR */ 1088c2ecf20Sopenharmony_ci for (i = 0; i < thread_num; i += 2) { 1098c2ecf20Sopenharmony_ci if (pthread_create(&thread[i], NULL, (void *)tfiar_tfhar, 1108c2ecf20Sopenharmony_ci (void *)i)) 1118c2ecf20Sopenharmony_ci return EXIT_FAILURE; 1128c2ecf20Sopenharmony_ci } 1138c2ecf20Sopenharmony_ci /* Test TEXASR */ 1148c2ecf20Sopenharmony_ci for (i = 1; i < thread_num; i += 2) { 1158c2ecf20Sopenharmony_ci if (pthread_create(&thread[i], NULL, (void *)texasr, (void *)i)) 1168c2ecf20Sopenharmony_ci return EXIT_FAILURE; 1178c2ecf20Sopenharmony_ci } 1188c2ecf20Sopenharmony_ci 1198c2ecf20Sopenharmony_ci for (i = 0; i < thread_num; i++) { 1208c2ecf20Sopenharmony_ci if (pthread_join(thread[i], NULL) != 0) 1218c2ecf20Sopenharmony_ci return EXIT_FAILURE; 1228c2ecf20Sopenharmony_ci } 1238c2ecf20Sopenharmony_ci 1248c2ecf20Sopenharmony_ci free(thread); 1258c2ecf20Sopenharmony_ci 1268c2ecf20Sopenharmony_ci if (passed) 1278c2ecf20Sopenharmony_ci return 0; 1288c2ecf20Sopenharmony_ci else 1298c2ecf20Sopenharmony_ci return 1; 1308c2ecf20Sopenharmony_ci} 1318c2ecf20Sopenharmony_ci 1328c2ecf20Sopenharmony_ciint main(int argc, char *argv[]) 1338c2ecf20Sopenharmony_ci{ 1348c2ecf20Sopenharmony_ci if (argc > 1) { 1358c2ecf20Sopenharmony_ci if (strcmp(argv[1], "-h") == 0) { 1368c2ecf20Sopenharmony_ci printf("Syntax:\t [<num loops>]\n"); 1378c2ecf20Sopenharmony_ci return 0; 1388c2ecf20Sopenharmony_ci } else { 1398c2ecf20Sopenharmony_ci num_loops = atoi(argv[1]); 1408c2ecf20Sopenharmony_ci } 1418c2ecf20Sopenharmony_ci } 1428c2ecf20Sopenharmony_ci return test_harness(test_tmspr, "tm_tmspr"); 1438c2ecf20Sopenharmony_ci} 144