From 068048faa53b96265855dba5175f0a2df1497864 Mon Sep 17 00:00:00 2001 From: Jon Medhurst Date: Thu, 10 May 2012 17:30:53 +0100 Subject: gator: Version 5.10 New gator release (build 1385) for ARM DS-5 v5.10 Signed-off-by: Jon Medhurst --- drivers/gator/gator_ebs.c | 158 ++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 158 insertions(+) create mode 100644 drivers/gator/gator_ebs.c (limited to 'drivers/gator/gator_ebs.c') diff --git a/drivers/gator/gator_ebs.c b/drivers/gator/gator_ebs.c new file mode 100644 index 00000000000..1208d69fbfd --- /dev/null +++ b/drivers/gator/gator_ebs.c @@ -0,0 +1,158 @@ +/** + * Copyright (C) ARM Limited 2012. All rights reserved. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + * + */ + +#if defined(__arm__) && (GATOR_PERF_PMU_SUPPORT) +#include +#include +#include + +#include + +static DEFINE_MUTEX(perf_mutex); + +extern int pmnc_counters; +extern int ccnt; +extern unsigned long pmnc_enabled[]; +extern unsigned long pmnc_event[]; +extern unsigned long pmnc_count[]; +extern unsigned long pmnc_key[]; + +static DEFINE_PER_CPU(struct perf_event *, pevent); +static DEFINE_PER_CPU(struct perf_event_attr *, pevent_attr); +static DEFINE_PER_CPU(int, key); +static DEFINE_PER_CPU(unsigned int, prev_value); + +#if LINUX_VERSION_CODE < KERNEL_VERSION(3, 1, 0) +static void ebs_overflow_handler(struct perf_event *event, int unused, struct perf_sample_data *data, struct pt_regs *regs) +#else +static void ebs_overflow_handler(struct perf_event *event, struct perf_sample_data *data, struct pt_regs *regs) +#endif +{ + int cpu = smp_processor_id(); + + if (event != per_cpu(pevent, cpu)) + return; + + // Output backtrace + gator_add_sample(cpu, BACKTRACE_BUF, regs); + + // Collect counters + collect_counters(); +} + +static void gator_event_sampling_online_dispatch(int cpu) +{ + struct perf_event * ev; + + if (!event_based_sampling) + return; + +#if LINUX_VERSION_CODE < KERNEL_VERSION(3, 1, 0) + ev = per_cpu(pevent, cpu) = perf_event_create_kernel_counter(per_cpu(pevent_attr, cpu), cpu, 0, ebs_overflow_handler); +#else + ev = per_cpu(pevent, cpu) = perf_event_create_kernel_counter(per_cpu(pevent_attr, cpu), cpu, 0, ebs_overflow_handler, 0); +#endif + + if (IS_ERR(ev)) { + pr_err("gator: unable to start event-based-sampling"); + return; + } + + if (ev->state != PERF_EVENT_STATE_ACTIVE) { + pr_err("gator: unable to start event-based-sampling"); + perf_event_release_kernel(ev); + return; + } + + ev->pmu->read(ev); + per_cpu(prev_value, cpu) = local64_read(&ev->count); +} + +static void gator_event_sampling_offline_dispatch(int cpu) +{ + struct perf_event * pe = NULL; + + mutex_lock(&perf_mutex); + if (per_cpu(pevent, cpu)) { + pe = per_cpu(pevent, cpu); + per_cpu(pevent, cpu) = NULL; + } + mutex_unlock(&perf_mutex); + + if (pe) { + perf_event_release_kernel(pe); + } +} + +static int gator_event_sampling_start(void) +{ + int cnt, event = 0, count = 0, ebs_key = 0, cpu; + + for_each_present_cpu(cpu) { + per_cpu(pevent, cpu) = NULL; + per_cpu(pevent_attr, cpu) = NULL; + } + + event_based_sampling = false; + for (cnt = 0; cnt < pmnc_counters; cnt++) { + if (pmnc_count[cnt] > 0) { + event_based_sampling = true; + event = pmnc_event[cnt]; + count = pmnc_count[cnt]; + ebs_key = pmnc_key[cnt]; + break; + } + } + + if (!event_based_sampling) + return 0; + + for_each_present_cpu(cpu) { + u32 size = sizeof(struct perf_event_attr); + per_cpu(pevent_attr, cpu) = kmalloc(size, GFP_KERNEL); + if (!per_cpu(pevent_attr, cpu)) + return -1; + + memset(per_cpu(pevent_attr, cpu), 0, size); + per_cpu(pevent_attr, cpu)->type = PERF_TYPE_RAW; + per_cpu(pevent_attr, cpu)->size = size; + per_cpu(pevent_attr, cpu)->config = event; + per_cpu(pevent_attr, cpu)->sample_period = count; + per_cpu(pevent_attr, cpu)->pinned = 1; + + // handle special case for ccnt + if (cnt == ccnt) { + per_cpu(pevent_attr, cpu)->type = PERF_TYPE_HARDWARE; + per_cpu(pevent_attr, cpu)->config = PERF_COUNT_HW_CPU_CYCLES; + } + + per_cpu(key, cpu) = ebs_key; + } + + return 0; +} + +static void gator_event_sampling_stop(void) +{ + int cpu; + + for_each_present_cpu(cpu) { + if (per_cpu(pevent_attr, cpu)) { + kfree(per_cpu(pevent_attr, cpu)); + per_cpu(pevent_attr, cpu) = NULL; + } + } +} + +#else +static void gator_event_sampling_online_dispatch(int cpu) {} +static void gator_event_sampling_offline_dispatch(int cpu) {} +static int gator_event_sampling_start(void) {return 0;} +static void gator_event_sampling_stop(void) {} +#endif -- cgit v1.2.3