1 // SPDX-License-Identifier: GPL-2.0-only 2 /* 3 * Copyright 2014, Michael Ellerman, IBM Corp. 4 */ 5 6 #include <sched.h> 7 #include <signal.h> 8 #include <stdbool.h> 9 #include <stdio.h> 10 #include <stdlib.h> 11 12 #include "ebb.h" 13 14 15 /* 16 * Test that the kernel properly handles PMAE across context switches. 17 * 18 * We test this by calling into the kernel inside our EBB handler, where PMAE 19 * is clear. A cpu eater companion thread is running on the same CPU as us to 20 * encourage the scheduler to switch us. 21 * 22 * The kernel must make sure that when it context switches us back in, it 23 * honours the fact that we had PMAE clear. 24 * 25 * Observed to hit the failing case on the first EBB with a broken kernel. 26 */ 27 28 static bool mmcr0_mismatch; 29 static uint64_t before, after; 30 31 static void syscall_ebb_callee(void) 32 { 33 uint64_t val; 34 35 val = mfspr(SPRN_BESCR); 36 if (!(val & BESCR_PMEO)) { 37 ebb_state.stats.spurious++; 38 goto out; 39 } 40 41 ebb_state.stats.ebb_count++; 42 count_pmc(1, sample_period); 43 44 before = mfspr(SPRN_MMCR0); 45 46 /* Try and get ourselves scheduled, to force a PMU context switch */ 47 sched_yield(); 48 49 after = mfspr(SPRN_MMCR0); 50 if (before != after) 51 mmcr0_mismatch = true; 52 53 out: 54 reset_ebb(); 55 } 56 57 static int test_body(void) 58 { 59 struct event event; 60 61 SKIP_IF(!ebb_is_supported()); 62 63 event_init_named(&event, 0x1001e, "cycles"); 64 event_leader_ebb_init(&event); 65 66 event.attr.exclude_kernel = 1; 67 event.attr.exclude_hv = 1; 68 event.attr.exclude_idle = 1; 69 70 FAIL_IF(event_open(&event)); 71 72 setup_ebb_handler(syscall_ebb_callee); 73 ebb_global_enable(); 74 75 FAIL_IF(ebb_event_enable(&event)); 76 77 mtspr(SPRN_PMC1, pmc_sample_period(sample_period)); 78 79 while (ebb_state.stats.ebb_count < 20 && !mmcr0_mismatch) 80 FAIL_IF(core_busy_loop()); 81 82 ebb_global_disable(); 83 ebb_freeze_pmcs(); 84 85 dump_ebb_state(); 86 87 if (mmcr0_mismatch) 88 printf("Saw MMCR0 before 0x%lx after 0x%lx\n", before, after); 89 90 event_close(&event); 91 92 FAIL_IF(ebb_state.stats.ebb_count == 0); 93 FAIL_IF(mmcr0_mismatch); 94 95 return 0; 96 } 97 98 int pmae_handling(void) 99 { 100 return eat_cpu(test_body); 101 } 102 103 int main(void) 104 { 105 return test_harness(pmae_handling, "pmae_handling"); 106 } 107