X-Git-Url: https://git.openpandora.org/cgi-bin/gitweb.cgi?a=blobdiff_plain;f=arch%2Farm%2Fkernel%2Fperf_event.c;h=e6e5d7c84f1a4330bc37e9516694f8d1797be8a9;hb=46b51ea2099fa2082342e52b8284aa828429b80b;hp=7f31eff00b8001dc8c5e597749b1a991dad1f5c2;hpb=8a16b34e21199eb5fcf2c5050d3bc414fc5d6563;p=pandora-kernel.git diff --git a/arch/arm/kernel/perf_event.c b/arch/arm/kernel/perf_event.c index 7f31eff00b80..e6e5d7c84f1a 100644 --- a/arch/arm/kernel/perf_event.c +++ b/arch/arm/kernel/perf_event.c @@ -12,6 +12,7 @@ */ #define pr_fmt(fmt) "hw perfevents: " fmt +#include #include #include #include @@ -37,66 +38,22 @@ */ #define ARMPMU_MAX_HWEVENTS 32 -/* The events for a given CPU. */ -struct cpu_hw_events { - /* - * The events that are active on the CPU for the given index. - */ - struct perf_event *events[ARMPMU_MAX_HWEVENTS]; - - /* - * A 1 bit for an index indicates that the counter is being used for - * an event. A 0 means that the counter can be used. - */ - unsigned long used_mask[BITS_TO_LONGS(ARMPMU_MAX_HWEVENTS)]; - - /* - * Hardware lock to serialize accesses to PMU registers. Needed for the - * read/modify/write sequences. - */ - raw_spinlock_t pmu_lock; -}; -static DEFINE_PER_CPU(struct cpu_hw_events, cpu_hw_events); - -struct arm_pmu { - struct pmu pmu; - enum arm_perf_pmu_ids id; - enum arm_pmu_type type; - cpumask_t active_irqs; - const char *name; - irqreturn_t (*handle_irq)(int irq_num, void *dev); - void (*enable)(struct hw_perf_event *evt, int idx); - void (*disable)(struct hw_perf_event *evt, int idx); - int (*get_event_idx)(struct cpu_hw_events *cpuc, - struct hw_perf_event *hwc); - int (*set_event_filter)(struct hw_perf_event *evt, - struct perf_event_attr *attr); - u32 (*read_counter)(int idx); - void (*write_counter)(int idx, u32 val); - void (*start)(void); - void (*stop)(void); - void (*reset)(void *); - int (*map_event)(struct perf_event *event); - int num_events; - atomic_t active_events; - struct mutex reserve_mutex; - u64 max_period; - struct platform_device *plat_device; - struct cpu_hw_events *(*get_hw_events)(void); -}; +static DEFINE_PER_CPU(struct perf_event * [ARMPMU_MAX_HWEVENTS], hw_events); +static DEFINE_PER_CPU(unsigned long [BITS_TO_LONGS(ARMPMU_MAX_HWEVENTS)], used_mask); +static DEFINE_PER_CPU(struct pmu_hw_events, cpu_hw_events); #define to_arm_pmu(p) (container_of(p, struct arm_pmu, pmu)) /* Set at runtime when we know what CPU type we are. */ -static struct arm_pmu *armpmu; +static struct arm_pmu *cpu_pmu; enum arm_perf_pmu_ids armpmu_get_pmu_id(void) { int id = -ENODEV; - if (armpmu != NULL) - id = armpmu->id; + if (cpu_pmu != NULL) + id = cpu_pmu->id; return id; } @@ -107,8 +64,8 @@ armpmu_get_max_events(void) { int max_events = 0; - if (armpmu != NULL) - max_events = armpmu->num_events; + if (cpu_pmu != NULL) + max_events = cpu_pmu->num_events; return max_events; } @@ -191,7 +148,7 @@ static int map_cpu_event(struct perf_event *event, return -ENOENT; } -static int +int armpmu_event_set_period(struct perf_event *event, struct hw_perf_event *hwc, int idx) @@ -227,7 +184,7 @@ armpmu_event_set_period(struct perf_event *event, return ret; } -static u64 +u64 armpmu_event_update(struct perf_event *event, struct hw_perf_event *hwc, int idx, int overflow) @@ -316,15 +273,15 @@ static void armpmu_del(struct perf_event *event, int flags) { struct arm_pmu *armpmu = to_arm_pmu(event->pmu); - struct cpu_hw_events *cpuc = armpmu->get_hw_events(); + struct pmu_hw_events *hw_events = armpmu->get_hw_events(); struct hw_perf_event *hwc = &event->hw; int idx = hwc->idx; WARN_ON(idx < 0); armpmu_stop(event, PERF_EF_UPDATE); - cpuc->events[idx] = NULL; - clear_bit(idx, cpuc->used_mask); + hw_events->events[idx] = NULL; + clear_bit(idx, hw_events->used_mask); perf_event_update_userpage(event); } @@ -333,7 +290,7 @@ static int armpmu_add(struct perf_event *event, int flags) { struct arm_pmu *armpmu = to_arm_pmu(event->pmu); - struct cpu_hw_events *cpuc = armpmu->get_hw_events(); + struct pmu_hw_events *hw_events = armpmu->get_hw_events(); struct hw_perf_event *hwc = &event->hw; int idx; int err = 0; @@ -341,7 +298,7 @@ armpmu_add(struct perf_event *event, int flags) perf_pmu_disable(event->pmu); /* If we don't have a space for the counter then finish early. */ - idx = armpmu->get_event_idx(cpuc, hwc); + idx = armpmu->get_event_idx(hw_events, hwc); if (idx < 0) { err = idx; goto out; @@ -353,7 +310,7 @@ armpmu_add(struct perf_event *event, int flags) */ event->hw.idx = idx; armpmu->disable(hwc, idx); - cpuc->events[idx] = event; + hw_events->events[idx] = event; hwc->state = PERF_HES_STOPPED | PERF_HES_UPTODATE; if (flags & PERF_EF_START) @@ -368,7 +325,7 @@ out: } static int -validate_event(struct cpu_hw_events *cpuc, +validate_event(struct pmu_hw_events *hw_events, struct perf_event *event) { struct arm_pmu *armpmu = to_arm_pmu(event->pmu); @@ -378,14 +335,14 @@ validate_event(struct cpu_hw_events *cpuc, if (event->pmu != leader_pmu || event->state <= PERF_EVENT_STATE_OFF) return 1; - return armpmu->get_event_idx(cpuc, &fake_event) >= 0; + return armpmu->get_event_idx(hw_events, &fake_event) >= 0; } static int validate_group(struct perf_event *event) { struct perf_event *sibling, *leader = event->group_leader; - struct cpu_hw_events fake_pmu; + struct pmu_hw_events fake_pmu; memset(&fake_pmu, 0, sizeof(fake_pmu)); @@ -602,19 +559,8 @@ static int armpmu_event_init(struct perf_event *event) static void armpmu_enable(struct pmu *pmu) { struct arm_pmu *armpmu = to_arm_pmu(pmu); - /* Enable all of the perf events on hardware. */ - int idx, enabled = 0; - struct cpu_hw_events *cpuc = armpmu->get_hw_events(); - - for (idx = 0; idx < armpmu->num_events; ++idx) { - struct perf_event *event = cpuc->events[idx]; - - if (!event) - continue; - - armpmu->enable(&event->hw, idx); - enabled = 1; - } + struct pmu_hw_events *hw_events = armpmu->get_hw_events(); + int enabled = bitmap_weight(hw_events->used_mask, armpmu->num_events); if (enabled) armpmu->start(); @@ -643,7 +589,7 @@ static void __init armpmu_init(struct arm_pmu *armpmu) }; } -static int __init armpmu_register(struct arm_pmu *armpmu, char *name, int type) +int __init armpmu_register(struct arm_pmu *armpmu, char *name, int type) { armpmu_init(armpmu); return perf_pmu_register(&armpmu->pmu, name, type); @@ -659,13 +605,13 @@ static int __init armpmu_register(struct arm_pmu *armpmu, char *name, int type) * This requires SMP to be available, so exists as a separate initcall. */ static int __init -armpmu_reset(void) +cpu_pmu_reset(void) { - if (armpmu && armpmu->reset) - return on_each_cpu(armpmu->reset, NULL, 1); + if (cpu_pmu && cpu_pmu->reset) + return on_each_cpu(cpu_pmu->reset, NULL, 1); return 0; } -arch_initcall(armpmu_reset); +arch_initcall(cpu_pmu_reset); /* * PMU platform driver and devicetree bindings. @@ -685,7 +631,7 @@ static struct platform_device_id armpmu_plat_device_ids[] = { static int __devinit armpmu_device_probe(struct platform_device *pdev) { - armpmu->plat_device = pdev; + cpu_pmu->plat_device = pdev; return 0; } @@ -704,7 +650,7 @@ static int __init register_pmu_driver(void) } device_initcall(register_pmu_driver); -static struct cpu_hw_events *armpmu_get_cpu_events(void) +static struct pmu_hw_events *armpmu_get_cpu_events(void) { return &__get_cpu_var(cpu_hw_events); } @@ -713,7 +659,9 @@ static void __init cpu_pmu_init(struct arm_pmu *armpmu) { int cpu; for_each_possible_cpu(cpu) { - struct cpu_hw_events *events = &per_cpu(cpu_hw_events, cpu); + struct pmu_hw_events *events = &per_cpu(cpu_hw_events, cpu); + events->events = per_cpu(hw_events, cpu); + events->used_mask = per_cpu(used_mask, cpu); raw_spin_lock_init(&events->pmu_lock); } armpmu->get_hw_events = armpmu_get_cpu_events; @@ -736,22 +684,22 @@ init_hw_perf_events(void) case 0xB360: /* ARM1136 */ case 0xB560: /* ARM1156 */ case 0xB760: /* ARM1176 */ - armpmu = armv6pmu_init(); + cpu_pmu = armv6pmu_init(); break; case 0xB020: /* ARM11mpcore */ - armpmu = armv6mpcore_pmu_init(); + cpu_pmu = armv6mpcore_pmu_init(); break; case 0xC080: /* Cortex-A8 */ - armpmu = armv7_a8_pmu_init(); + cpu_pmu = armv7_a8_pmu_init(); break; case 0xC090: /* Cortex-A9 */ - armpmu = armv7_a9_pmu_init(); + cpu_pmu = armv7_a9_pmu_init(); break; case 0xC050: /* Cortex-A5 */ - armpmu = armv7_a5_pmu_init(); + cpu_pmu = armv7_a5_pmu_init(); break; case 0xC0F0: /* Cortex-A15 */ - armpmu = armv7_a15_pmu_init(); + cpu_pmu = armv7_a15_pmu_init(); break; } /* Intel CPUs [xscale]. */ @@ -759,19 +707,19 @@ init_hw_perf_events(void) part_number = (cpuid >> 13) & 0x7; switch (part_number) { case 1: - armpmu = xscale1pmu_init(); + cpu_pmu = xscale1pmu_init(); break; case 2: - armpmu = xscale2pmu_init(); + cpu_pmu = xscale2pmu_init(); break; } } - if (armpmu) { + if (cpu_pmu) { pr_info("enabled with %s PMU driver, %d counters available\n", - armpmu->name, armpmu->num_events); - cpu_pmu_init(armpmu); - armpmu_register(armpmu, "cpu", PERF_TYPE_RAW); + cpu_pmu->name, cpu_pmu->num_events); + cpu_pmu_init(cpu_pmu); + armpmu_register(cpu_pmu, "cpu", PERF_TYPE_RAW); } else { pr_info("no hardware support available\n"); }