Commit | Line | Data |
---|---|---|
3752e453 ME |
1 | /* |
2 | * Copyright 2014, Michael Ellerman, IBM Corp. | |
3 | * Licensed under GPLv2. | |
4 | */ | |
5 | ||
6 | #include <sched.h> | |
7 | #include <signal.h> | |
8 | #include <stdio.h> | |
9 | #include <stdlib.h> | |
10 | #include <sys/mman.h> | |
11 | ||
12 | #include "ebb.h" | |
13 | ||
14 | ||
15 | /* | |
16 | * Test that tries to trigger CPU_FTR_PMAO_BUG. Which is a hardware defect | |
17 | * where an exception triggers but we context switch before it is delivered and | |
18 | * lose the exception. | |
19 | */ | |
20 | ||
21 | static int test_body(void) | |
22 | { | |
23 | int i, orig_period, max_period; | |
24 | struct event event; | |
25 | ||
39fcfb91 DK |
26 | SKIP_IF(!ebb_is_supported()); |
27 | ||
3752e453 ME |
28 | /* We use PMC4 to make sure the kernel switches all counters correctly */ |
29 | event_init_named(&event, 0x40002, "instructions"); | |
30 | event_leader_ebb_init(&event); | |
31 | ||
32 | event.attr.exclude_kernel = 1; | |
33 | event.attr.exclude_hv = 1; | |
34 | event.attr.exclude_idle = 1; | |
35 | ||
36 | FAIL_IF(event_open(&event)); | |
37 | ||
38 | ebb_enable_pmc_counting(4); | |
39 | setup_ebb_handler(standard_ebb_callee); | |
40 | ebb_global_enable(); | |
41 | FAIL_IF(ebb_event_enable(&event)); | |
42 | ||
43 | /* | |
44 | * We want a low sample period, but we also want to get out of the EBB | |
45 | * handler without tripping up again. | |
46 | * | |
47 | * This value picked after much experimentation. | |
48 | */ | |
49 | orig_period = max_period = sample_period = 400; | |
50 | ||
51 | mtspr(SPRN_PMC4, pmc_sample_period(sample_period)); | |
52 | ||
53 | while (ebb_state.stats.ebb_count < 1000000) { | |
54 | /* | |
55 | * We are trying to get the EBB exception to race exactly with | |
56 | * us entering the kernel to do the syscall. We then need the | |
57 | * kernel to decide our timeslice is up and context switch to | |
58 | * the other thread. When we come back our EBB will have been | |
59 | * lost and we'll spin in this while loop forever. | |
60 | */ | |
61 | ||
62 | for (i = 0; i < 100000; i++) | |
63 | sched_yield(); | |
64 | ||
65 | /* Change the sample period slightly to try and hit the race */ | |
66 | if (sample_period >= (orig_period + 200)) | |
67 | sample_period = orig_period; | |
68 | else | |
69 | sample_period++; | |
70 | ||
71 | if (sample_period > max_period) | |
72 | max_period = sample_period; | |
73 | } | |
74 | ||
75 | ebb_freeze_pmcs(); | |
76 | ebb_global_disable(); | |
77 | ||
78 | count_pmc(4, sample_period); | |
79 | mtspr(SPRN_PMC4, 0xdead); | |
80 | ||
81 | dump_summary_ebb_state(); | |
82 | dump_ebb_hw_state(); | |
83 | ||
84 | event_close(&event); | |
85 | ||
86 | FAIL_IF(ebb_state.stats.ebb_count == 0); | |
87 | ||
88 | /* We vary our sample period so we need extra fudge here */ | |
89 | FAIL_IF(!ebb_check_count(4, orig_period, 2 * (max_period - orig_period))); | |
90 | ||
91 | return 0; | |
92 | } | |
93 | ||
94 | static int lost_exception(void) | |
95 | { | |
96 | return eat_cpu(test_body); | |
97 | } | |
98 | ||
99 | int main(void) | |
100 | { | |
101 | return test_harness(lost_exception, "lost_exception"); | |
102 | } |