1f50a7f3dSThomas Gleixner // SPDX-License-Identifier: GPL-2.0-only
216aab321SRashmica Gupta /*
316aab321SRashmica Gupta * Copyright 2015, Michael Neuling, IBM Corp.
416aab321SRashmica Gupta *
516aab321SRashmica Gupta * Original: Michael Neuling 3/4/2014
616aab321SRashmica Gupta * Modified: Rashmica Gupta 8/12/2015
716aab321SRashmica Gupta *
816aab321SRashmica Gupta * Check if any of the Transaction Memory SPRs get corrupted.
916aab321SRashmica Gupta * - TFIAR - stores address of location of transaction failure
1016aab321SRashmica Gupta * - TFHAR - stores address of software failure handler (if transaction
1116aab321SRashmica Gupta * fails)
1216aab321SRashmica Gupta * - TEXASR - lots of info about the transacion(s)
1316aab321SRashmica Gupta *
1416aab321SRashmica Gupta * (1) create more threads than cpus
1516aab321SRashmica Gupta * (2) in each thread:
1616aab321SRashmica Gupta * (a) set TFIAR and TFHAR a unique value
1716aab321SRashmica Gupta * (b) loop for awhile, continually checking to see if
1816aab321SRashmica Gupta * either register has been corrupted.
1916aab321SRashmica Gupta *
2016aab321SRashmica Gupta * (3) Loop:
2116aab321SRashmica Gupta * (a) begin transaction
2216aab321SRashmica Gupta * (b) abort transaction
2316aab321SRashmica Gupta * (c) check TEXASR to see if FS has been corrupted
2416aab321SRashmica Gupta */
2516aab321SRashmica Gupta
2616aab321SRashmica Gupta #define _GNU_SOURCE
2716aab321SRashmica Gupta #include <stdio.h>
2816aab321SRashmica Gupta #include <stdlib.h>
2916aab321SRashmica Gupta #include <unistd.h>
3016aab321SRashmica Gupta #include <pthread.h>
3116aab321SRashmica Gupta #include <string.h>
3216aab321SRashmica Gupta
3316aab321SRashmica Gupta #include "utils.h"
3416aab321SRashmica Gupta #include "tm.h"
3516aab321SRashmica Gupta
36b5a646a6SMichael Ellerman int num_loops = 1000000;
3716aab321SRashmica Gupta int passed = 1;
3816aab321SRashmica Gupta
tfiar_tfhar(void * in)3916aab321SRashmica Gupta void tfiar_tfhar(void *in)
4016aab321SRashmica Gupta {
4116aab321SRashmica Gupta unsigned long tfhar, tfhar_rd, tfiar, tfiar_rd;
4276962871SMichael Ellerman int i;
4316aab321SRashmica Gupta
4416aab321SRashmica Gupta /* TFIAR: Last bit has to be high so userspace can read register */
4516aab321SRashmica Gupta tfiar = ((unsigned long)in) + 1;
4616aab321SRashmica Gupta tfiar += 2;
4716aab321SRashmica Gupta mtspr(SPRN_TFIAR, tfiar);
4816aab321SRashmica Gupta
4916aab321SRashmica Gupta /* TFHAR: Last two bits are reserved */
5016aab321SRashmica Gupta tfhar = ((unsigned long)in);
5116aab321SRashmica Gupta tfhar &= ~0x3UL;
5216aab321SRashmica Gupta tfhar += 4;
5316aab321SRashmica Gupta mtspr(SPRN_TFHAR, tfhar);
5416aab321SRashmica Gupta
5516aab321SRashmica Gupta for (i = 0; i < num_loops; i++) {
5616aab321SRashmica Gupta tfhar_rd = mfspr(SPRN_TFHAR);
5716aab321SRashmica Gupta tfiar_rd = mfspr(SPRN_TFIAR);
5816aab321SRashmica Gupta if ( (tfhar != tfhar_rd) || (tfiar != tfiar_rd) ) {
5916aab321SRashmica Gupta passed = 0;
6016aab321SRashmica Gupta return;
6116aab321SRashmica Gupta }
6216aab321SRashmica Gupta }
6316aab321SRashmica Gupta return;
6416aab321SRashmica Gupta }
6516aab321SRashmica Gupta
texasr(void * in)6616aab321SRashmica Gupta void texasr(void *in)
6716aab321SRashmica Gupta {
6816aab321SRashmica Gupta unsigned long i;
6916aab321SRashmica Gupta uint64_t result = 0;
7016aab321SRashmica Gupta
7116aab321SRashmica Gupta for (i = 0; i < num_loops; i++) {
7216aab321SRashmica Gupta asm __volatile__(
7316aab321SRashmica Gupta "tbegin.;"
7416aab321SRashmica Gupta "beq 3f ;"
7516aab321SRashmica Gupta "tabort. 0 ;"
7616aab321SRashmica Gupta "tend.;"
7716aab321SRashmica Gupta
7816aab321SRashmica Gupta /* Abort handler */
7916aab321SRashmica Gupta "3: ;"
8016aab321SRashmica Gupta ::: "memory");
8116aab321SRashmica Gupta
8216aab321SRashmica Gupta /* Check the TEXASR */
8316aab321SRashmica Gupta result = mfspr(SPRN_TEXASR);
8416aab321SRashmica Gupta if ((result & TEXASR_FS) == 0) {
8516aab321SRashmica Gupta passed = 0;
8616aab321SRashmica Gupta return;
8716aab321SRashmica Gupta }
8816aab321SRashmica Gupta }
8916aab321SRashmica Gupta return;
9016aab321SRashmica Gupta }
9116aab321SRashmica Gupta
test_tmspr()9216aab321SRashmica Gupta int test_tmspr()
9316aab321SRashmica Gupta {
94693b31b2SBreno Leitao pthread_t *thread;
9516aab321SRashmica Gupta int thread_num;
9616aab321SRashmica Gupta unsigned long i;
9716aab321SRashmica Gupta
9816aab321SRashmica Gupta SKIP_IF(!have_htm());
99*e42edf9bSJordan Niethe SKIP_IF(htm_is_synthetic());
10016aab321SRashmica Gupta
10116aab321SRashmica Gupta /* To cause some context switching */
10216aab321SRashmica Gupta thread_num = 10 * sysconf(_SC_NPROCESSORS_ONLN);
10316aab321SRashmica Gupta
104693b31b2SBreno Leitao thread = malloc(thread_num * sizeof(pthread_t));
105693b31b2SBreno Leitao if (thread == NULL)
10616aab321SRashmica Gupta return EXIT_FAILURE;
10716aab321SRashmica Gupta
108693b31b2SBreno Leitao /* Test TFIAR and TFHAR */
109693b31b2SBreno Leitao for (i = 0; i < thread_num; i += 2) {
110693b31b2SBreno Leitao if (pthread_create(&thread[i], NULL, (void *)tfiar_tfhar,
111693b31b2SBreno Leitao (void *)i))
11216aab321SRashmica Gupta return EXIT_FAILURE;
11316aab321SRashmica Gupta }
114693b31b2SBreno Leitao /* Test TEXASR */
115693b31b2SBreno Leitao for (i = 1; i < thread_num; i += 2) {
116693b31b2SBreno Leitao if (pthread_create(&thread[i], NULL, (void *)texasr, (void *)i))
11716aab321SRashmica Gupta return EXIT_FAILURE;
118693b31b2SBreno Leitao }
119693b31b2SBreno Leitao
120693b31b2SBreno Leitao for (i = 0; i < thread_num; i++) {
121693b31b2SBreno Leitao if (pthread_join(thread[i], NULL) != 0)
122693b31b2SBreno Leitao return EXIT_FAILURE;
123693b31b2SBreno Leitao }
124693b31b2SBreno Leitao
125693b31b2SBreno Leitao free(thread);
12616aab321SRashmica Gupta
12716aab321SRashmica Gupta if (passed)
12816aab321SRashmica Gupta return 0;
12916aab321SRashmica Gupta else
13016aab321SRashmica Gupta return 1;
13116aab321SRashmica Gupta }
13216aab321SRashmica Gupta
main(int argc,char * argv[])13316aab321SRashmica Gupta int main(int argc, char *argv[])
13416aab321SRashmica Gupta {
13516aab321SRashmica Gupta if (argc > 1) {
13616aab321SRashmica Gupta if (strcmp(argv[1], "-h") == 0) {
13716aab321SRashmica Gupta printf("Syntax:\t [<num loops>]\n");
13816aab321SRashmica Gupta return 0;
13916aab321SRashmica Gupta } else {
14016aab321SRashmica Gupta num_loops = atoi(argv[1]);
14116aab321SRashmica Gupta }
14216aab321SRashmica Gupta }
14316aab321SRashmica Gupta return test_harness(test_tmspr, "tm_tmspr");
14416aab321SRashmica Gupta }
145