Home | History | Annotate | Download | only in ebb
      1 /*
      2  * Copyright 2014, Michael Ellerman, IBM Corp.
      3  * Licensed under GPLv2.
      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 	count_pmc(1, sample_period);
     86 
     87 	dump_ebb_state();
     88 
     89 	if (mmcr0_mismatch)
     90 		printf("Saw MMCR0 before 0x%lx after 0x%lx\n", before, after);
     91 
     92 	event_close(&event);
     93 
     94 	FAIL_IF(ebb_state.stats.ebb_count == 0);
     95 	FAIL_IF(mmcr0_mismatch);
     96 
     97 	return 0;
     98 }
     99 
    100 int pmae_handling(void)
    101 {
    102 	return eat_cpu(test_body);
    103 }
    104 
    105 int main(void)
    106 {
    107 	return test_harness(pmae_handling, "pmae_handling");
    108 }
    109