1 | // SPDX-License-Identifier: GPL-2.0-only |
2 | /* |
3 | * Copyright 2014, Michael Ellerman, IBM Corp. |
4 | */ |
5 | |
6 | #include <stdbool.h> |
7 | #include <stdio.h> |
8 | #include <stdlib.h> |
9 | |
10 | #include "ebb.h" |
11 | |
12 | |
13 | #define NUMBER_OF_EBBS 50 |
14 | |
15 | /* |
16 | * Test that if we overflow the counter while in the EBB handler, we take |
17 | * another EBB on exiting from the handler. |
18 | * |
19 | * We do this by counting with a stupidly low sample period, causing us to |
20 | * overflow the PMU while we're still in the EBB handler, leading to another |
21 | * EBB. |
22 | * |
23 | * We get out of what would otherwise be an infinite loop by leaving the |
24 | * counter frozen once we've taken enough EBBs. |
25 | */ |
26 | |
27 | static void ebb_callee(void) |
28 | { |
29 | uint64_t siar, val; |
30 | |
31 | val = mfspr(SPRN_BESCR); |
32 | if (!(val & BESCR_PMEO)) { |
33 | ebb_state.stats.spurious++; |
34 | goto out; |
35 | } |
36 | |
37 | ebb_state.stats.ebb_count++; |
38 | trace_log_counter(tb: ebb_state.trace, value: ebb_state.stats.ebb_count); |
39 | |
40 | /* Resets the PMC */ |
41 | count_pmc(pmc: 1, sample_period); |
42 | |
43 | out: |
44 | if (ebb_state.stats.ebb_count == NUMBER_OF_EBBS) |
45 | /* Reset but leave counters frozen */ |
46 | reset_ebb_with_clear_mask(mmcr0_clear_mask: MMCR0_PMAO); |
47 | else |
48 | /* Unfreezes */ |
49 | reset_ebb(); |
50 | |
51 | /* Do some stuff to chew some cycles and pop the counter */ |
52 | siar = mfspr(SPRN_SIAR); |
53 | trace_log_reg(tb: ebb_state.trace, reg: SPRN_SIAR, value: siar); |
54 | |
55 | val = mfspr(SPRN_PMC1); |
56 | trace_log_reg(tb: ebb_state.trace, reg: SPRN_PMC1, value: val); |
57 | |
58 | val = mfspr(SPRN_MMCR0); |
59 | trace_log_reg(tb: ebb_state.trace, reg: SPRN_MMCR0, value: val); |
60 | } |
61 | |
62 | int back_to_back_ebbs(void) |
63 | { |
64 | struct event event; |
65 | |
66 | SKIP_IF(!ebb_is_supported()); |
67 | |
68 | event_init_named(e: &event, config: 0x1001e, name: "cycles" ); |
69 | event_leader_ebb_init(e: &event); |
70 | |
71 | event.attr.exclude_kernel = 1; |
72 | event.attr.exclude_hv = 1; |
73 | event.attr.exclude_idle = 1; |
74 | |
75 | FAIL_IF(event_open(e: &event)); |
76 | |
77 | setup_ebb_handler(ebb_callee); |
78 | |
79 | FAIL_IF(ebb_event_enable(e: &event)); |
80 | |
81 | sample_period = 5; |
82 | |
83 | ebb_freeze_pmcs(); |
84 | mtspr(SPRN_PMC1, pmc_sample_period(value: sample_period)); |
85 | ebb_global_enable(); |
86 | ebb_unfreeze_pmcs(); |
87 | |
88 | while (ebb_state.stats.ebb_count < NUMBER_OF_EBBS) |
89 | FAIL_IF(core_busy_loop()); |
90 | |
91 | ebb_global_disable(); |
92 | ebb_freeze_pmcs(); |
93 | |
94 | dump_ebb_state(); |
95 | |
96 | event_close(e: &event); |
97 | |
98 | FAIL_IF(ebb_state.stats.ebb_count != NUMBER_OF_EBBS); |
99 | |
100 | return 0; |
101 | } |
102 | |
103 | int main(void) |
104 | { |
105 | return test_harness(back_to_back_ebbs, "back_to_back_ebbs" ); |
106 | } |
107 | |