linux/tools/testing/selftests/powerpc/pmu/ebb/lost_exception_test.c
<<
>>
Prefs
   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
  21static int test_body(void)
  22{
  23        int i, orig_period, max_period;
  24        struct event event;
  25
  26        SKIP_IF(!ebb_is_supported());
  27
  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
  94static int lost_exception(void)
  95{
  96        return eat_cpu(test_body);
  97}
  98
  99int main(void)
 100{
 101        return test_harness(lost_exception, "lost_exception");
 102}
 103