xref: /kvm-unit-tests/s390x/sck.c (revision adf6cc0c29431e409e47f6b60d30ddfc30b59219)
1*adf6cc0cSNico Boehr /* SPDX-License-Identifier: GPL-2.0-only */
2*adf6cc0cSNico Boehr /*
3*adf6cc0cSNico Boehr  * Perform Set Clock tests
4*adf6cc0cSNico Boehr  *
5*adf6cc0cSNico Boehr  * Copyright IBM Corp. 2022
6*adf6cc0cSNico Boehr  *
7*adf6cc0cSNico Boehr  * Authors:
8*adf6cc0cSNico Boehr  *  Nico Boehr <nrb@linux.ibm.com>
9*adf6cc0cSNico Boehr  */
10*adf6cc0cSNico Boehr #include <libcflat.h>
11*adf6cc0cSNico Boehr #include <uv.h>
12*adf6cc0cSNico Boehr #include <asm/interrupt.h>
13*adf6cc0cSNico Boehr #include <asm/time.h>
14*adf6cc0cSNico Boehr 
15*adf6cc0cSNico Boehr static inline int sck(uint64_t *time)
16*adf6cc0cSNico Boehr {
17*adf6cc0cSNico Boehr 	int cc;
18*adf6cc0cSNico Boehr 
19*adf6cc0cSNico Boehr 	asm volatile(
20*adf6cc0cSNico Boehr 		"	sck %[time]\n"
21*adf6cc0cSNico Boehr 		"	ipm %[cc]\n"
22*adf6cc0cSNico Boehr 		"	srl %[cc],28\n"
23*adf6cc0cSNico Boehr 		: [cc] "=d"(cc)
24*adf6cc0cSNico Boehr 		: [time] "Q"(*time)
25*adf6cc0cSNico Boehr 		: "cc"
26*adf6cc0cSNico Boehr 	);
27*adf6cc0cSNico Boehr 
28*adf6cc0cSNico Boehr 	return cc;
29*adf6cc0cSNico Boehr }
30*adf6cc0cSNico Boehr 
31*adf6cc0cSNico Boehr static inline int stck(uint64_t *time)
32*adf6cc0cSNico Boehr {
33*adf6cc0cSNico Boehr 	int cc;
34*adf6cc0cSNico Boehr 
35*adf6cc0cSNico Boehr 	asm volatile(
36*adf6cc0cSNico Boehr 		"	stck %[time]\n"
37*adf6cc0cSNico Boehr 		"	ipm %[cc]\n"
38*adf6cc0cSNico Boehr 		"	srl %[cc],28\n"
39*adf6cc0cSNico Boehr 		: [cc] "=d" (cc), [time] "=Q" (*time)
40*adf6cc0cSNico Boehr 		:
41*adf6cc0cSNico Boehr 		: "cc", "memory"
42*adf6cc0cSNico Boehr 	);
43*adf6cc0cSNico Boehr 
44*adf6cc0cSNico Boehr 	return cc;
45*adf6cc0cSNico Boehr }
46*adf6cc0cSNico Boehr 
47*adf6cc0cSNico Boehr static void test_priv(void)
48*adf6cc0cSNico Boehr {
49*adf6cc0cSNico Boehr 	uint64_t time_to_set_privileged = 0xfacef00dcafe0000,
50*adf6cc0cSNico Boehr 	    time_to_set_nonprivileged = 0xcafe0000,
51*adf6cc0cSNico Boehr 	    time_verify;
52*adf6cc0cSNico Boehr 	int cc;
53*adf6cc0cSNico Boehr 
54*adf6cc0cSNico Boehr 	report_prefix_push("privileged");
55*adf6cc0cSNico Boehr 	cc = sck(&time_to_set_privileged);
56*adf6cc0cSNico Boehr 	report(!cc, "set clock cc=%d", cc);
57*adf6cc0cSNico Boehr 
58*adf6cc0cSNico Boehr 	cc = stck(&time_verify);
59*adf6cc0cSNico Boehr 	report(!cc, "store clock cc=%d", cc);
60*adf6cc0cSNico Boehr 	report(time_verify > time_to_set_privileged,
61*adf6cc0cSNico Boehr 	       "privileged set affected the clock");
62*adf6cc0cSNico Boehr 	report_prefix_pop();
63*adf6cc0cSNico Boehr 
64*adf6cc0cSNico Boehr 	report_prefix_push("unprivileged");
65*adf6cc0cSNico Boehr 	expect_pgm_int();
66*adf6cc0cSNico Boehr 	enter_pstate();
67*adf6cc0cSNico Boehr 	sck(&time_to_set_nonprivileged);
68*adf6cc0cSNico Boehr 	leave_pstate();
69*adf6cc0cSNico Boehr 	check_pgm_int_code(PGM_INT_CODE_PRIVILEGED_OPERATION);
70*adf6cc0cSNico Boehr 
71*adf6cc0cSNico Boehr 	cc = stck(&time_verify);
72*adf6cc0cSNico Boehr 	report(!cc, "store clock cc=%d", cc);
73*adf6cc0cSNico Boehr 	report(time_verify > time_to_set_privileged,
74*adf6cc0cSNico Boehr 	       "unprivileged set did not affect the clock");
75*adf6cc0cSNico Boehr 	report_prefix_pop();
76*adf6cc0cSNico Boehr }
77*adf6cc0cSNico Boehr 
78*adf6cc0cSNico Boehr static void test_align(void)
79*adf6cc0cSNico Boehr {
80*adf6cc0cSNico Boehr 	const int align_to = 8;
81*adf6cc0cSNico Boehr 	char unalign[sizeof(uint64_t) + align_to] __attribute__((aligned(8)));
82*adf6cc0cSNico Boehr 
83*adf6cc0cSNico Boehr 	report_prefix_push("Unaligned operand");
84*adf6cc0cSNico Boehr 	for (int i = 1; i < align_to; i *= 2) {
85*adf6cc0cSNico Boehr 		report_prefix_pushf("%d", i);
86*adf6cc0cSNico Boehr 		expect_pgm_int();
87*adf6cc0cSNico Boehr 		sck((uint64_t *)(unalign + i));
88*adf6cc0cSNico Boehr 		check_pgm_int_code(PGM_INT_CODE_SPECIFICATION);
89*adf6cc0cSNico Boehr 		report_prefix_pop();
90*adf6cc0cSNico Boehr 	}
91*adf6cc0cSNico Boehr 	report_prefix_pop();
92*adf6cc0cSNico Boehr }
93*adf6cc0cSNico Boehr 
94*adf6cc0cSNico Boehr static void test_set(void)
95*adf6cc0cSNico Boehr {
96*adf6cc0cSNico Boehr 	uint64_t start = 0, end = 0, time = 0xcafef00dbeef;
97*adf6cc0cSNico Boehr 	const uint64_t ticks_per_ms = 1000 << 12, ms_to_wait = 5;
98*adf6cc0cSNico Boehr 	int cc;
99*adf6cc0cSNico Boehr 
100*adf6cc0cSNico Boehr 	report_prefix_push("set");
101*adf6cc0cSNico Boehr 
102*adf6cc0cSNico Boehr 	cc = sck(&time);
103*adf6cc0cSNico Boehr 	report(!cc, "set clock cc=%d", cc);
104*adf6cc0cSNico Boehr 
105*adf6cc0cSNico Boehr 	cc = stck(&start);
106*adf6cc0cSNico Boehr 	report(!cc, "store start clock cc=%d", cc);
107*adf6cc0cSNico Boehr 	report(start >= time, "start >= set value");
108*adf6cc0cSNico Boehr 
109*adf6cc0cSNico Boehr 	mdelay(ms_to_wait);
110*adf6cc0cSNico Boehr 
111*adf6cc0cSNico Boehr 	cc = stck(&end);
112*adf6cc0cSNico Boehr 	report(!cc, "store end clock cc=%d", cc);
113*adf6cc0cSNico Boehr 	report(end > time, "end > set value");
114*adf6cc0cSNico Boehr 
115*adf6cc0cSNico Boehr 	report(end - start > (ticks_per_ms * ms_to_wait), "Advances");
116*adf6cc0cSNico Boehr 
117*adf6cc0cSNico Boehr 	report_prefix_pop();
118*adf6cc0cSNico Boehr }
119*adf6cc0cSNico Boehr 
120*adf6cc0cSNico Boehr int main(void)
121*adf6cc0cSNico Boehr {
122*adf6cc0cSNico Boehr 	report_prefix_push("sck");
123*adf6cc0cSNico Boehr 
124*adf6cc0cSNico Boehr 	if (uv_os_is_guest()) {
125*adf6cc0cSNico Boehr 		report_skip("Test unsupported under PV");
126*adf6cc0cSNico Boehr 		goto out;
127*adf6cc0cSNico Boehr 	}
128*adf6cc0cSNico Boehr 
129*adf6cc0cSNico Boehr 	test_align();
130*adf6cc0cSNico Boehr 	test_set();
131*adf6cc0cSNico Boehr 	test_priv();
132*adf6cc0cSNico Boehr 
133*adf6cc0cSNico Boehr out:
134*adf6cc0cSNico Boehr 	report_prefix_pop();
135*adf6cc0cSNico Boehr 	return report_summary();
136*adf6cc0cSNico Boehr }
137