1 | // SPDX-License-Identifier: GPL-2.0 |
2 | /* Test context switching to see if the DSCR SPR is correctly preserved |
3 | * when within a transaction. |
4 | * |
5 | * Note: We assume that the DSCR has been left at the default value (0) |
6 | * for all CPUs. |
7 | * |
8 | * Method: |
9 | * |
10 | * Set a value into the DSCR. |
11 | * |
12 | * Start a transaction, and suspend it (*). |
13 | * |
14 | * Hard loop checking to see if the transaction has become doomed. |
15 | * |
16 | * Now that we *may* have been preempted, record the DSCR and TEXASR SPRS. |
17 | * |
18 | * If the abort was because of a context switch, check the DSCR value. |
19 | * Otherwise, try again. |
20 | * |
21 | * (*) If the transaction is not suspended we can't see the problem because |
22 | * the transaction abort handler will restore the DSCR to it's checkpointed |
23 | * value before we regain control. |
24 | */ |
25 | |
26 | #include <inttypes.h> |
27 | #include <stdio.h> |
28 | #include <stdlib.h> |
29 | #include <assert.h> |
30 | #include <asm/tm.h> |
31 | |
32 | #include "utils.h" |
33 | #include "tm.h" |
34 | #include "../pmu/lib.h" |
35 | |
36 | #define SPRN_DSCR 0x03 |
37 | |
38 | int test_body(void) |
39 | { |
40 | uint64_t rv, dscr1 = 1, dscr2, texasr; |
41 | |
42 | SKIP_IF(!have_htm()); |
43 | SKIP_IF(htm_is_synthetic()); |
44 | |
45 | printf("Check DSCR TM context switch: " ); |
46 | fflush(stdout); |
47 | for (;;) { |
48 | asm __volatile__ ( |
49 | /* set a known value into the DSCR */ |
50 | "ld 3, %[dscr1];" |
51 | "mtspr %[sprn_dscr], 3;" |
52 | |
53 | "li %[rv], 1;" |
54 | /* start and suspend a transaction */ |
55 | "tbegin.;" |
56 | "beq 1f;" |
57 | "tsuspend.;" |
58 | |
59 | /* hard loop until the transaction becomes doomed */ |
60 | "2: ;" |
61 | "tcheck 0;" |
62 | "bc 4, 0, 2b;" |
63 | |
64 | /* record DSCR and TEXASR */ |
65 | "mfspr 3, %[sprn_dscr];" |
66 | "std 3, %[dscr2];" |
67 | "mfspr 3, %[sprn_texasr];" |
68 | "std 3, %[texasr];" |
69 | |
70 | "tresume.;" |
71 | "tend.;" |
72 | "li %[rv], 0;" |
73 | "1: ;" |
74 | : [rv]"=r" (rv), [dscr2]"=m" (dscr2), [texasr]"=m" (texasr) |
75 | : [dscr1]"m" (dscr1) |
76 | , [sprn_dscr]"i" (SPRN_DSCR), [sprn_texasr]"i" (SPRN_TEXASR) |
77 | : "memory" , "r3" |
78 | ); |
79 | assert(rv); /* make sure the transaction aborted */ |
80 | if ((texasr >> 56) != TM_CAUSE_RESCHED) { |
81 | continue; |
82 | } |
83 | if (dscr2 != dscr1) { |
84 | printf(" FAIL\n" ); |
85 | return 1; |
86 | } else { |
87 | printf(" OK\n" ); |
88 | return 0; |
89 | } |
90 | } |
91 | } |
92 | |
93 | static int tm_resched_dscr(void) |
94 | { |
95 | return eat_cpu(test_body); |
96 | } |
97 | |
98 | int main(int argc, const char *argv[]) |
99 | { |
100 | return test_harness(tm_resched_dscr, "tm_resched_dscr" ); |
101 | } |
102 | |