2 * Copyright (C) ARM Limited 2011-2013. All rights reserved.
4 * This program is free software; you can redistribute it and/or modify
5 * it under the terms of the GNU General Public License version 2 as
6 * published by the Free Software Foundation.
10 // gator_hrtimer_gator.c is used if perf is not supported
11 // update, gator_hrtimer_gator.c always used until issues resolved with perf hrtimers
14 // Note: perf Cortex support added in 2.6.35 and PERF_COUNT_SW_CPU_CLOCK/hrtimer broken on 2.6.35 and 2.6.36
15 // not relevant as this code is not active until 3.0.0, but wanted to document the issue
17 void (*callback)(void);
18 static int profiling_interval;
19 static DEFINE_PER_CPU(struct perf_event *, perf_hrtimer);
20 static DEFINE_PER_CPU(struct perf_event_attr *, perf_hrtimer_attr);
22 static void gator_hrtimer_shutdown(void);
24 #if LINUX_VERSION_CODE < KERNEL_VERSION(3, 1, 0)
25 static void hrtimer_overflow_handler(struct perf_event *event, int unused, struct perf_sample_data *data, struct pt_regs *regs)
27 static void hrtimer_overflow_handler(struct perf_event *event, struct perf_sample_data *data, struct pt_regs *regs)
33 static int gator_online_single_hrtimer(int cpu)
35 if (per_cpu(perf_hrtimer, cpu) != 0 || per_cpu(perf_hrtimer_attr, cpu) == 0)
38 #if LINUX_VERSION_CODE < KERNEL_VERSION(3, 1, 0)
39 per_cpu(perf_hrtimer, cpu) = perf_event_create_kernel_counter(per_cpu(perf_hrtimer_attr, cpu), cpu, 0, hrtimer_overflow_handler);
41 per_cpu(perf_hrtimer, cpu) = perf_event_create_kernel_counter(per_cpu(perf_hrtimer_attr, cpu), cpu, 0, hrtimer_overflow_handler, 0);
43 if (IS_ERR(per_cpu(perf_hrtimer, cpu))) {
44 per_cpu(perf_hrtimer, cpu) = NULL;
48 if (per_cpu(perf_hrtimer, cpu)->state != PERF_EVENT_STATE_ACTIVE) {
49 perf_event_release_kernel(per_cpu(perf_hrtimer, cpu));
50 per_cpu(perf_hrtimer, cpu) = NULL;
57 static void gator_hrtimer_online(int cpu)
59 if (gator_online_single_hrtimer(cpu) < 0) {
60 pr_debug("gator: unable to online the hrtimer on cpu%d\n", cpu);
64 static void gator_hrtimer_offline(int cpu)
66 if (per_cpu(perf_hrtimer, cpu)) {
67 perf_event_release_kernel(per_cpu(perf_hrtimer, cpu));
68 per_cpu(perf_hrtimer, cpu) = NULL;
72 static int gator_hrtimer_init(int interval, void (*func)(void))
74 u32 size = sizeof(struct perf_event_attr);
79 // calculate profiling interval
80 profiling_interval = 1000000000 / interval;
82 for_each_present_cpu(cpu) {
83 per_cpu(perf_hrtimer, cpu) = 0;
84 per_cpu(perf_hrtimer_attr, cpu) = kmalloc(size, GFP_KERNEL);
85 if (per_cpu(perf_hrtimer_attr, cpu) == 0) {
86 gator_hrtimer_shutdown();
90 memset(per_cpu(perf_hrtimer_attr, cpu), 0, size);
91 per_cpu(perf_hrtimer_attr, cpu)->type = PERF_TYPE_SOFTWARE;
92 per_cpu(perf_hrtimer_attr, cpu)->size = size;
93 per_cpu(perf_hrtimer_attr, cpu)->config = PERF_COUNT_SW_CPU_CLOCK;
94 per_cpu(perf_hrtimer_attr, cpu)->sample_period = profiling_interval;
95 per_cpu(perf_hrtimer_attr, cpu)->pinned = 1;
101 static void gator_hrtimer_shutdown(void)
105 for_each_present_cpu(cpu) {
106 if (per_cpu(perf_hrtimer_attr, cpu)) {
107 kfree(per_cpu(perf_hrtimer_attr, cpu));
108 per_cpu(perf_hrtimer_attr, cpu) = NULL;