aboutsummaryrefslogtreecommitdiffstats
path: root/tools/testing/selftests/powerpc/tm/tm-tmspr.c
blob: 17becf3dcee49c6e25e4c1959f71d1f3614757a7 (plain) (blame)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
// SPDX-License-Identifier: GPL-2.0-only
/*
 * Copyright 2015, Michael Neuling, IBM Corp.
 *
 * Original: Michael Neuling 3/4/2014
 * Modified: Rashmica Gupta 8/12/2015
 *
 * Check if any of the Transaction Memory SPRs get corrupted.
 * - TFIAR  - stores address of location of transaction failure
 * - TFHAR  - stores address of software failure handler (if transaction
 *   fails)
 * - TEXASR - lots of info about the transacion(s)
 *
 * (1) create more threads than cpus
 * (2) in each thread:
 * 	(a) set TFIAR and TFHAR a unique value
 * 	(b) loop for awhile, continually checking to see if
 * 	either register has been corrupted.
 *
 * (3) Loop:
 * 	(a) begin transaction
 *    	(b) abort transaction
 *	(c) check TEXASR to see if FS has been corrupted
 */

#define _GNU_SOURCE
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <pthread.h>
#include <string.h>

#include "utils.h"
#include "tm.h"

int	num_loops	= 10000;
int	passed = 1;

void tfiar_tfhar(void *in)
{
	int i, cpu;
	unsigned long tfhar, tfhar_rd, tfiar, tfiar_rd;
	cpu_set_t cpuset;

	CPU_ZERO(&cpuset);
	cpu = (unsigned long)in >> 1;
	CPU_SET(cpu, &cpuset);
	sched_setaffinity(0, sizeof(cpuset), &cpuset);

	/* TFIAR: Last bit has to be high so userspace can read register */
	tfiar = ((unsigned long)in) + 1;
	tfiar += 2;
	mtspr(SPRN_TFIAR, tfiar);

	/* TFHAR: Last two bits are reserved */
	tfhar = ((unsigned long)in);
	tfhar &= ~0x3UL;
	tfhar += 4;
	mtspr(SPRN_TFHAR, tfhar);

	for (i = 0; i < num_loops; i++)	{
		tfhar_rd = mfspr(SPRN_TFHAR);
		tfiar_rd = mfspr(SPRN_TFIAR);
		if ( (tfhar != tfhar_rd) || (tfiar != tfiar_rd) ) {
			passed = 0;
			return;
		}
	}
	return;
}

void texasr(void *in)
{
	unsigned long i;
	uint64_t result = 0;

	for (i = 0; i < num_loops; i++) {
		asm __volatile__(
			"tbegin.;"
			"beq    3f ;"
			"tabort. 0 ;"
			"tend.;"

			/* Abort handler */
			"3: ;"
			::: "memory");

                /* Check the TEXASR */
                result = mfspr(SPRN_TEXASR);
		if ((result & TEXASR_FS) == 0) {
			passed = 0;
			return;
		}
	}
	return;
}

int test_tmspr()
{
	pthread_t	*thread;
	int	   	thread_num;
	unsigned long	i;

	SKIP_IF(!have_htm());

	/* To cause some context switching */
	thread_num = 10 * sysconf(_SC_NPROCESSORS_ONLN);

	thread = malloc(thread_num * sizeof(pthread_t));
	if (thread == NULL)
		return EXIT_FAILURE;

	/* Test TFIAR and TFHAR */
	for (i = 0; i < thread_num; i += 2) {
		if (pthread_create(&thread[i], NULL, (void *)tfiar_tfhar,
				   (void *)i))
			return EXIT_FAILURE;
	}
	/* Test TEXASR */
	for (i = 1; i < thread_num; i += 2) {
		if (pthread_create(&thread[i], NULL, (void *)texasr, (void *)i))
			return EXIT_FAILURE;
	}

	for (i = 0; i < thread_num; i++) {
		if (pthread_join(thread[i], NULL) != 0)
			return EXIT_FAILURE;
	}

	free(thread);

	if (passed)
		return 0;
	else
		return 1;
}

int main(int argc, char *argv[])
{
	if (argc > 1) {
		if (strcmp(argv[1], "-h") == 0) {
			printf("Syntax:\t [<num loops>]\n");
			return 0;
		} else {
			num_loops = atoi(argv[1]);
		}
	}
	return test_harness(test_tmspr, "tm_tmspr");
}