Commit 667832da authored by Russell King's avatar Russell King

Merge branch 'perf/updates' of...

Merge branch 'perf/updates' of git://git.kernel.org/pub/scm/linux/kernel/git/will/linux into devel-stable
parents 3587b1b0 2ac29a14
...@@ -21,4 +21,9 @@ ...@@ -21,4 +21,9 @@
#define C(_x) PERF_COUNT_HW_CACHE_##_x #define C(_x) PERF_COUNT_HW_CACHE_##_x
#define CACHE_OP_UNSUPPORTED 0xFFFF #define CACHE_OP_UNSUPPORTED 0xFFFF
struct pt_regs;
extern unsigned long perf_instruction_pointer(struct pt_regs *regs);
extern unsigned long perf_misc_flags(struct pt_regs *regs);
#define perf_misc_flags(regs) perf_misc_flags(regs)
#endif /* __ARM_PERF_EVENT_H__ */ #endif /* __ARM_PERF_EVENT_H__ */
...@@ -67,19 +67,19 @@ struct arm_pmu { ...@@ -67,19 +67,19 @@ struct arm_pmu {
cpumask_t active_irqs; cpumask_t active_irqs;
char *name; char *name;
irqreturn_t (*handle_irq)(int irq_num, void *dev); irqreturn_t (*handle_irq)(int irq_num, void *dev);
void (*enable)(struct hw_perf_event *evt, int idx); void (*enable)(struct perf_event *event);
void (*disable)(struct hw_perf_event *evt, int idx); void (*disable)(struct perf_event *event);
int (*get_event_idx)(struct pmu_hw_events *hw_events, int (*get_event_idx)(struct pmu_hw_events *hw_events,
struct hw_perf_event *hwc); struct perf_event *event);
int (*set_event_filter)(struct hw_perf_event *evt, int (*set_event_filter)(struct hw_perf_event *evt,
struct perf_event_attr *attr); struct perf_event_attr *attr);
u32 (*read_counter)(int idx); u32 (*read_counter)(struct perf_event *event);
void (*write_counter)(int idx, u32 val); void (*write_counter)(struct perf_event *event, u32 val);
void (*start)(void); void (*start)(struct arm_pmu *);
void (*stop)(void); void (*stop)(struct arm_pmu *);
void (*reset)(void *); void (*reset)(void *);
int (*request_irq)(irq_handler_t handler); int (*request_irq)(struct arm_pmu *, irq_handler_t handler);
void (*free_irq)(void); void (*free_irq)(struct arm_pmu *);
int (*map_event)(struct perf_event *event); int (*map_event)(struct perf_event *event);
int num_events; int num_events;
atomic_t active_events; atomic_t active_events;
...@@ -93,15 +93,11 @@ struct arm_pmu { ...@@ -93,15 +93,11 @@ struct arm_pmu {
extern const struct dev_pm_ops armpmu_dev_pm_ops; extern const struct dev_pm_ops armpmu_dev_pm_ops;
int armpmu_register(struct arm_pmu *armpmu, char *name, int type); int armpmu_register(struct arm_pmu *armpmu, int type);
u64 armpmu_event_update(struct perf_event *event, u64 armpmu_event_update(struct perf_event *event);
struct hw_perf_event *hwc,
int idx);
int armpmu_event_set_period(struct perf_event *event, int armpmu_event_set_period(struct perf_event *event);
struct hw_perf_event *hwc,
int idx);
int armpmu_map_event(struct perf_event *event, int armpmu_map_event(struct perf_event *event,
const unsigned (*event_map)[PERF_COUNT_HW_MAX], const unsigned (*event_map)[PERF_COUNT_HW_MAX],
......
...@@ -86,12 +86,10 @@ armpmu_map_event(struct perf_event *event, ...@@ -86,12 +86,10 @@ armpmu_map_event(struct perf_event *event,
return -ENOENT; return -ENOENT;
} }
int int armpmu_event_set_period(struct perf_event *event)
armpmu_event_set_period(struct perf_event *event,
struct hw_perf_event *hwc,
int idx)
{ {
struct arm_pmu *armpmu = to_arm_pmu(event->pmu); struct arm_pmu *armpmu = to_arm_pmu(event->pmu);
struct hw_perf_event *hwc = &event->hw;
s64 left = local64_read(&hwc->period_left); s64 left = local64_read(&hwc->period_left);
s64 period = hwc->sample_period; s64 period = hwc->sample_period;
int ret = 0; int ret = 0;
...@@ -119,24 +117,22 @@ armpmu_event_set_period(struct perf_event *event, ...@@ -119,24 +117,22 @@ armpmu_event_set_period(struct perf_event *event,
local64_set(&hwc->prev_count, (u64)-left); local64_set(&hwc->prev_count, (u64)-left);
armpmu->write_counter(idx, (u64)(-left) & 0xffffffff); armpmu->write_counter(event, (u64)(-left) & 0xffffffff);
perf_event_update_userpage(event); perf_event_update_userpage(event);
return ret; return ret;
} }
u64 u64 armpmu_event_update(struct perf_event *event)
armpmu_event_update(struct perf_event *event,
struct hw_perf_event *hwc,
int idx)
{ {
struct arm_pmu *armpmu = to_arm_pmu(event->pmu); struct arm_pmu *armpmu = to_arm_pmu(event->pmu);
struct hw_perf_event *hwc = &event->hw;
u64 delta, prev_raw_count, new_raw_count; u64 delta, prev_raw_count, new_raw_count;
again: again:
prev_raw_count = local64_read(&hwc->prev_count); prev_raw_count = local64_read(&hwc->prev_count);
new_raw_count = armpmu->read_counter(idx); new_raw_count = armpmu->read_counter(event);
if (local64_cmpxchg(&hwc->prev_count, prev_raw_count, if (local64_cmpxchg(&hwc->prev_count, prev_raw_count,
new_raw_count) != prev_raw_count) new_raw_count) != prev_raw_count)
...@@ -159,7 +155,7 @@ armpmu_read(struct perf_event *event) ...@@ -159,7 +155,7 @@ armpmu_read(struct perf_event *event)
if (hwc->idx < 0) if (hwc->idx < 0)
return; return;
armpmu_event_update(event, hwc, hwc->idx); armpmu_event_update(event);
} }
static void static void
...@@ -173,14 +169,13 @@ armpmu_stop(struct perf_event *event, int flags) ...@@ -173,14 +169,13 @@ armpmu_stop(struct perf_event *event, int flags)
* PERF_EF_UPDATE, see comments in armpmu_start(). * PERF_EF_UPDATE, see comments in armpmu_start().
*/ */
if (!(hwc->state & PERF_HES_STOPPED)) { if (!(hwc->state & PERF_HES_STOPPED)) {
armpmu->disable(hwc, hwc->idx); armpmu->disable(event);
armpmu_event_update(event, hwc, hwc->idx); armpmu_event_update(event);
hwc->state |= PERF_HES_STOPPED | PERF_HES_UPTODATE; hwc->state |= PERF_HES_STOPPED | PERF_HES_UPTODATE;
} }
} }
static void static void armpmu_start(struct perf_event *event, int flags)
armpmu_start(struct perf_event *event, int flags)
{ {
struct arm_pmu *armpmu = to_arm_pmu(event->pmu); struct arm_pmu *armpmu = to_arm_pmu(event->pmu);
struct hw_perf_event *hwc = &event->hw; struct hw_perf_event *hwc = &event->hw;
...@@ -200,8 +195,8 @@ armpmu_start(struct perf_event *event, int flags) ...@@ -200,8 +195,8 @@ armpmu_start(struct perf_event *event, int flags)
* get an interrupt too soon or *way* too late if the overflow has * get an interrupt too soon or *way* too late if the overflow has
* happened since disabling. * happened since disabling.
*/ */
armpmu_event_set_period(event, hwc, hwc->idx); armpmu_event_set_period(event);
armpmu->enable(hwc, hwc->idx); armpmu->enable(event);
} }
static void static void
...@@ -233,7 +228,7 @@ armpmu_add(struct perf_event *event, int flags) ...@@ -233,7 +228,7 @@ armpmu_add(struct perf_event *event, int flags)
perf_pmu_disable(event->pmu); perf_pmu_disable(event->pmu);
/* If we don't have a space for the counter then finish early. */ /* If we don't have a space for the counter then finish early. */
idx = armpmu->get_event_idx(hw_events, hwc); idx = armpmu->get_event_idx(hw_events, event);
if (idx < 0) { if (idx < 0) {
err = idx; err = idx;
goto out; goto out;
...@@ -244,7 +239,7 @@ armpmu_add(struct perf_event *event, int flags) ...@@ -244,7 +239,7 @@ armpmu_add(struct perf_event *event, int flags)
* sure it is disabled. * sure it is disabled.
*/ */
event->hw.idx = idx; event->hw.idx = idx;
armpmu->disable(hwc, idx); armpmu->disable(event);
hw_events->events[idx] = event; hw_events->events[idx] = event;
hwc->state = PERF_HES_STOPPED | PERF_HES_UPTODATE; hwc->state = PERF_HES_STOPPED | PERF_HES_UPTODATE;
...@@ -264,13 +259,12 @@ validate_event(struct pmu_hw_events *hw_events, ...@@ -264,13 +259,12 @@ validate_event(struct pmu_hw_events *hw_events,
struct perf_event *event) struct perf_event *event)
{ {
struct arm_pmu *armpmu = to_arm_pmu(event->pmu); struct arm_pmu *armpmu = to_arm_pmu(event->pmu);
struct hw_perf_event fake_event = event->hw;
struct pmu *leader_pmu = event->group_leader->pmu; struct pmu *leader_pmu = event->group_leader->pmu;
if (event->pmu != leader_pmu || event->state <= PERF_EVENT_STATE_OFF) if (event->pmu != leader_pmu || event->state <= PERF_EVENT_STATE_OFF)
return 1; return 1;
return armpmu->get_event_idx(hw_events, &fake_event) >= 0; return armpmu->get_event_idx(hw_events, event) >= 0;
} }
static int static int
...@@ -316,7 +310,7 @@ static irqreturn_t armpmu_dispatch_irq(int irq, void *dev) ...@@ -316,7 +310,7 @@ static irqreturn_t armpmu_dispatch_irq(int irq, void *dev)
static void static void
armpmu_release_hardware(struct arm_pmu *armpmu) armpmu_release_hardware(struct arm_pmu *armpmu)
{ {
armpmu->free_irq(); armpmu->free_irq(armpmu);
pm_runtime_put_sync(&armpmu->plat_device->dev); pm_runtime_put_sync(&armpmu->plat_device->dev);
} }
...@@ -330,7 +324,7 @@ armpmu_reserve_hardware(struct arm_pmu *armpmu) ...@@ -330,7 +324,7 @@ armpmu_reserve_hardware(struct arm_pmu *armpmu)
return -ENODEV; return -ENODEV;
pm_runtime_get_sync(&pmu_device->dev); pm_runtime_get_sync(&pmu_device->dev);
err = armpmu->request_irq(armpmu_dispatch_irq); err = armpmu->request_irq(armpmu, armpmu_dispatch_irq);
if (err) { if (err) {
armpmu_release_hardware(armpmu); armpmu_release_hardware(armpmu);
return err; return err;
...@@ -465,13 +459,13 @@ static void armpmu_enable(struct pmu *pmu) ...@@ -465,13 +459,13 @@ static void armpmu_enable(struct pmu *pmu)
int enabled = bitmap_weight(hw_events->used_mask, armpmu->num_events); int enabled = bitmap_weight(hw_events->used_mask, armpmu->num_events);
if (enabled) if (enabled)
armpmu->start(); armpmu->start(armpmu);
} }
static void armpmu_disable(struct pmu *pmu) static void armpmu_disable(struct pmu *pmu)
{ {
struct arm_pmu *armpmu = to_arm_pmu(pmu); struct arm_pmu *armpmu = to_arm_pmu(pmu);
armpmu->stop(); armpmu->stop(armpmu);
} }
#ifdef CONFIG_PM_RUNTIME #ifdef CONFIG_PM_RUNTIME
...@@ -517,12 +511,13 @@ static void __init armpmu_init(struct arm_pmu *armpmu) ...@@ -517,12 +511,13 @@ static void __init armpmu_init(struct arm_pmu *armpmu)
}; };
} }
int armpmu_register(struct arm_pmu *armpmu, char *name, int type) int armpmu_register(struct arm_pmu *armpmu, int type)
{ {
armpmu_init(armpmu); armpmu_init(armpmu);
pm_runtime_enable(&armpmu->plat_device->dev);
pr_info("enabled with %s PMU driver, %d counters available\n", pr_info("enabled with %s PMU driver, %d counters available\n",
armpmu->name, armpmu->num_events); armpmu->name, armpmu->num_events);
return perf_pmu_register(&armpmu->pmu, name, type); return perf_pmu_register(&armpmu->pmu, armpmu->name, type);
} }
/* /*
...@@ -576,6 +571,10 @@ perf_callchain_user(struct perf_callchain_entry *entry, struct pt_regs *regs) ...@@ -576,6 +571,10 @@ perf_callchain_user(struct perf_callchain_entry *entry, struct pt_regs *regs)
{ {
struct frame_tail __user *tail; struct frame_tail __user *tail;
if (perf_guest_cbs && perf_guest_cbs->is_in_guest()) {
/* We don't support guest os callchain now */
return;
}
tail = (struct frame_tail __user *)regs->ARM_fp - 1; tail = (struct frame_tail __user *)regs->ARM_fp - 1;
...@@ -603,9 +602,41 @@ perf_callchain_kernel(struct perf_callchain_entry *entry, struct pt_regs *regs) ...@@ -603,9 +602,41 @@ perf_callchain_kernel(struct perf_callchain_entry *entry, struct pt_regs *regs)
{ {
struct stackframe fr; struct stackframe fr;
if (perf_guest_cbs && perf_guest_cbs->is_in_guest()) {
/* We don't support guest os callchain now */
return;
}
fr.fp = regs->ARM_fp; fr.fp = regs->ARM_fp;
fr.sp = regs->ARM_sp; fr.sp = regs->ARM_sp;
fr.lr = regs->ARM_lr; fr.lr = regs->ARM_lr;
fr.pc = regs->ARM_pc; fr.pc = regs->ARM_pc;
walk_stackframe(&fr, callchain_trace, entry); walk_stackframe(&fr, callchain_trace, entry);
} }
unsigned long perf_instruction_pointer(struct pt_regs *regs)
{
if (perf_guest_cbs && perf_guest_cbs->is_in_guest())
return perf_guest_cbs->get_guest_ip();
return instruction_pointer(regs);
}
unsigned long perf_misc_flags(struct pt_regs *regs)
{
int misc = 0;
if (perf_guest_cbs && perf_guest_cbs->is_in_guest()) {
if (perf_guest_cbs->is_user_mode())
misc |= PERF_RECORD_MISC_GUEST_USER;
else
misc |= PERF_RECORD_MISC_GUEST_KERNEL;
} else {
if (user_mode(regs))
misc |= PERF_RECORD_MISC_USER;
else
misc |= PERF_RECORD_MISC_KERNEL;
}
return misc;
}
...@@ -23,6 +23,7 @@ ...@@ -23,6 +23,7 @@
#include <linux/kernel.h> #include <linux/kernel.h>
#include <linux/of.h> #include <linux/of.h>
#include <linux/platform_device.h> #include <linux/platform_device.h>
#include <linux/slab.h>
#include <linux/spinlock.h> #include <linux/spinlock.h>
#include <asm/cputype.h> #include <asm/cputype.h>
...@@ -45,7 +46,7 @@ const char *perf_pmu_name(void) ...@@ -45,7 +46,7 @@ const char *perf_pmu_name(void)
if (!cpu_pmu) if (!cpu_pmu)
return NULL; return NULL;
return cpu_pmu->pmu.name; return cpu_pmu->name;
} }
EXPORT_SYMBOL_GPL(perf_pmu_name); EXPORT_SYMBOL_GPL(perf_pmu_name);
...@@ -70,7 +71,7 @@ static struct pmu_hw_events *cpu_pmu_get_cpu_events(void) ...@@ -70,7 +71,7 @@ static struct pmu_hw_events *cpu_pmu_get_cpu_events(void)
return &__get_cpu_var(cpu_hw_events); return &__get_cpu_var(cpu_hw_events);
} }
static void cpu_pmu_free_irq(void) static void cpu_pmu_free_irq(struct arm_pmu *cpu_pmu)
{ {
int i, irq, irqs; int i, irq, irqs;
struct platform_device *pmu_device = cpu_pmu->plat_device; struct platform_device *pmu_device = cpu_pmu->plat_device;
...@@ -86,7 +87,7 @@ static void cpu_pmu_free_irq(void) ...@@ -86,7 +87,7 @@ static void cpu_pmu_free_irq(void)
} }
} }
static int cpu_pmu_request_irq(irq_handler_t handler) static int cpu_pmu_request_irq(struct arm_pmu *cpu_pmu, irq_handler_t handler)
{ {
int i, err, irq, irqs; int i, err, irq, irqs;
struct platform_device *pmu_device = cpu_pmu->plat_device; struct platform_device *pmu_device = cpu_pmu->plat_device;
...@@ -147,7 +148,7 @@ static void __devinit cpu_pmu_init(struct arm_pmu *cpu_pmu) ...@@ -147,7 +148,7 @@ static void __devinit cpu_pmu_init(struct arm_pmu *cpu_pmu)
/* Ensure the PMU has sane values out of reset. */ /* Ensure the PMU has sane values out of reset. */
if (cpu_pmu && cpu_pmu->reset) if (cpu_pmu && cpu_pmu->reset)
on_each_cpu(cpu_pmu->reset, NULL, 1); on_each_cpu(cpu_pmu->reset, cpu_pmu, 1);
} }
/* /*
...@@ -163,7 +164,9 @@ static int __cpuinit cpu_pmu_notify(struct notifier_block *b, ...@@ -163,7 +164,9 @@ static int __cpuinit cpu_pmu_notify(struct notifier_block *b,
return NOTIFY_DONE; return NOTIFY_DONE;
if (cpu_pmu && cpu_pmu->reset) if (cpu_pmu && cpu_pmu->reset)
cpu_pmu->reset(NULL); cpu_pmu->reset(cpu_pmu);
else
return NOTIFY_DONE;
return NOTIFY_OK; return NOTIFY_OK;
} }
...@@ -195,13 +198,13 @@ static struct platform_device_id __devinitdata cpu_pmu_plat_device_ids[] = { ...@@ -195,13 +198,13 @@ static struct platform_device_id __devinitdata cpu_pmu_plat_device_ids[] = {
/* /*
* CPU PMU identification and probing. * CPU PMU identification and probing.
*/ */
static struct arm_pmu *__devinit probe_current_pmu(void) static int __devinit probe_current_pmu(struct arm_pmu *pmu)
{ {
struct arm_pmu *pmu = NULL;
int cpu = get_cpu(); int cpu = get_cpu();
unsigned long cpuid = read_cpuid_id(); unsigned long cpuid = read_cpuid_id();
unsigned long implementor = (cpuid & 0xFF000000) >> 24; unsigned long implementor = (cpuid & 0xFF000000) >> 24;
unsigned long part_number = (cpuid & 0xFFF0); unsigned long part_number = (cpuid & 0xFFF0);
int ret = -ENODEV;
pr_info("probing PMU on CPU %d\n", cpu); pr_info("probing PMU on CPU %d\n", cpu);
...@@ -211,25 +214,25 @@ static struct arm_pmu *__devinit probe_current_pmu(void) ...@@ -211,25 +214,25 @@ static struct arm_pmu *__devinit probe_current_pmu(void)
case 0xB360: /* ARM1136 */ case 0xB360: /* ARM1136 */
case 0xB560: /* ARM1156 */ case 0xB560: /* ARM1156 */
case 0xB760: /* ARM1176 */ case 0xB760: /* ARM1176 */
pmu = armv6pmu_init(); ret = armv6pmu_init(pmu);
break; break;
case 0xB020: /* ARM11mpcore */ case 0xB020: /* ARM11mpcore */
pmu = armv6mpcore_pmu_init(); ret = armv6mpcore_pmu_init(pmu);
break; break;
case 0xC080: /* Cortex-A8 */ case 0xC080: /* Cortex-A8 */
pmu = armv7_a8_pmu_init(); ret = armv7_a8_pmu_init(pmu);
break; break;
case 0xC090: /* Cortex-A9 */ case 0xC090: /* Cortex-A9 */
pmu = armv7_a9_pmu_init(); ret = armv7_a9_pmu_init(pmu);
break; break;
case 0xC050: /* Cortex-A5 */ case 0xC050: /* Cortex-A5 */
pmu = armv7_a5_pmu_init(); ret = armv7_a5_pmu_init(pmu);
break; break;
case 0xC0F0: /* Cortex-A15 */ case 0xC0F0: /* Cortex-A15 */
pmu = armv7_a15_pmu_init(); ret = armv7_a15_pmu_init(pmu);
break; break;
case 0xC070: /* Cortex-A7 */ case 0xC070: /* Cortex-A7 */
pmu = armv7_a7_pmu_init(); ret = armv7_a7_pmu_init(pmu);
break; break;
} }
/* Intel CPUs [xscale]. */ /* Intel CPUs [xscale]. */
...@@ -237,43 +240,54 @@ static struct arm_pmu *__devinit probe_current_pmu(void) ...@@ -237,43 +240,54 @@ static struct arm_pmu *__devinit probe_current_pmu(void)
part_number = (cpuid >> 13) & 0x7; part_number = (cpuid >> 13) & 0x7;
switch (part_number) { switch (part_number) {
case 1: case 1:
pmu = xscale1pmu_init(); ret = xscale1pmu_init(pmu);
break; break;
case 2: case 2:
pmu = xscale2pmu_init(); ret = xscale2pmu_init(pmu);
break; break;
} }
} }
put_cpu(); put_cpu();
return pmu; return ret;
} }
static int __devinit cpu_pmu_device_probe(struct platform_device *pdev) static int __devinit cpu_pmu_device_probe(struct platform_device *pdev)
{ {
const struct of_device_id *of_id; const struct of_device_id *of_id;
struct arm_pmu *(*init_fn)(void); int (*init_fn)(struct arm_pmu *);
struct device_node *node = pdev->dev.of_node; struct device_node *node = pdev->dev.of_node;
struct arm_pmu *pmu;
int ret = -ENODEV;
if (cpu_pmu) { if (cpu_pmu) {
pr_info("attempt to register multiple PMU devices!"); pr_info("attempt to register multiple PMU devices!");
return -ENOSPC; return -ENOSPC;
} }
pmu = kzalloc(sizeof(struct arm_pmu), GFP_KERNEL);
if (!pmu) {
pr_info("failed to allocate PMU device!");
return -ENOMEM;
}
if (node && (of_id = of_match_node(cpu_pmu_of_device_ids, pdev->dev.of_node))) { if (node && (of_id = of_match_node(cpu_pmu_of_device_ids, pdev->dev.of_node))) {
init_fn = of_id->data; init_fn = of_id->data;
cpu_pmu = init_fn(); ret = init_fn(pmu);
} else { } else {
cpu_pmu = probe_current_pmu(); ret = probe_current_pmu(pmu);
} }
if (!cpu_pmu) if (ret) {
return -ENODEV; pr_info("failed to register PMU devices!");
kfree(pmu);
return ret;
}
cpu_pmu = pmu;
cpu_pmu->plat_device = pdev; cpu_pmu->plat_device = pdev;
cpu_pmu_init(cpu_pmu); cpu_pmu_init(cpu_pmu);
register_cpu_notifier(&cpu_pmu_hotplug_notifier); armpmu_register(cpu_pmu, PERF_TYPE_RAW);
armpmu_register(cpu_pmu, cpu_pmu->name, PERF_TYPE_RAW);
return 0; return 0;
} }
...@@ -290,6 +304,16 @@ static struct platform_driver cpu_pmu_driver = { ...@@ -290,6 +304,16 @@ static struct platform_driver cpu_pmu_driver = {
static int __init register_pmu_driver(void) static int __init register_pmu_driver(void)
{ {
return platform_driver_register(&cpu_pmu_driver); int err;
err = register_cpu_notifier(&cpu_pmu_hotplug_notifier);
if (err)
return err;
err = platform_driver_register(&cpu_pmu_driver);
if (err)
unregister_cpu_notifier(&cpu_pmu_hotplug_notifier);
return err;
} }
device_initcall(register_pmu_driver); device_initcall(register_pmu_driver);
...@@ -401,9 +401,10 @@ armv6_pmcr_counter_has_overflowed(unsigned long pmcr, ...@@ -401,9 +401,10 @@ armv6_pmcr_counter_has_overflowed(unsigned long pmcr,
return ret; return ret;
} }
static inline u32 static inline u32 armv6pmu_read_counter(struct perf_event *event)
armv6pmu_read_counter(int counter)
{ {
struct hw_perf_event *hwc = &event->hw;
int counter = hwc->idx;
unsigned long value = 0; unsigned long value = 0;
if (ARMV6_CYCLE_COUNTER == counter) if (ARMV6_CYCLE_COUNTER == counter)
...@@ -418,10 +419,11 @@ armv6pmu_read_counter(int counter) ...@@ -418,10 +419,11 @@ armv6pmu_read_counter(int counter)
return value; return value;
} }
static inline void static inline void armv6pmu_write_counter(struct perf_event *event, u32 value)
armv6pmu_write_counter(int counter,
u32 value)
{ {
struct hw_perf_event *hwc = &event->hw;
int counter = hwc->idx;
if (ARMV6_CYCLE_COUNTER == counter) if (ARMV6_CYCLE_COUNTER == counter)
asm volatile("mcr p15, 0, %0, c15, c12, 1" : : "r"(value)); asm volatile("mcr p15, 0, %0, c15, c12, 1" : : "r"(value));
else if (ARMV6_COUNTER0 == counter) else if (ARMV6_COUNTER0 == counter)
...@@ -432,12 +434,13 @@ armv6pmu_write_counter(int counter, ...@@ -432,12 +434,13 @@ armv6pmu_write_counter(int counter,
WARN_ONCE(1, "invalid counter number (%d)\n", counter); WARN_ONCE(1, "invalid counter number (%d)\n", counter);
} }
static void static void armv6pmu_enable_event(struct perf_event *event)
armv6pmu_enable_event(struct hw_perf_event *hwc,
int idx)
{ {
unsigned long val, mask, evt, flags; unsigned long val, mask, evt, flags;
struct arm_pmu *cpu_pmu = to_arm_pmu(event->pmu);
struct hw_perf_event *hwc = &event->hw;
struct pmu_hw_events *events = cpu_pmu->get_hw_events(); struct pmu_hw_events *events = cpu_pmu->get_hw_events();
int idx = hwc->idx;
if (ARMV6_CYCLE_COUNTER == idx) { if (ARMV6_CYCLE_COUNTER == idx) {
mask = 0; mask = 0;
...@@ -473,7 +476,8 @@ armv6pmu_handle_irq(int irq_num, ...@@ -473,7 +476,8 @@ armv6pmu_handle_irq(int irq_num,
{ {
unsigned long pmcr = armv6_pmcr_read(); unsigned long pmcr = armv6_pmcr_read();
struct perf_sample_data data; struct perf_sample_data data;
struct pmu_hw_events *cpuc; struct arm_pmu *cpu_pmu = (struct arm_pmu *)dev;
struct pmu_hw_events *cpuc = cpu_pmu->get_hw_events();
struct pt_regs *regs; struct pt_regs *regs;
int idx; int idx;
...@@ -489,7 +493,6 @@ armv6pmu_handle_irq(int irq_num, ...@@ -489,7 +493,6 @@ armv6pmu_handle_irq(int irq_num,
*/ */
armv6_pmcr_write(pmcr); armv6_pmcr_write(pmcr);
cpuc = &__get_cpu_var(cpu_hw_events);
for (idx = 0; idx < cpu_pmu->num_events; ++idx) { for (idx = 0; idx < cpu_pmu->num_events; ++idx) {
struct perf_event *event = cpuc->events[idx]; struct perf_event *event = cpuc->events[idx];
struct hw_perf_event *hwc; struct hw_perf_event *hwc;
...@@ -506,13 +509,13 @@ armv6pmu_handle_irq(int irq_num, ...@@ -506,13 +509,13 @@ armv6pmu_handle_irq(int irq_num,
continue; continue;
hwc = &event->hw; hwc = &event->hw;
armpmu_event_update(event, hwc, idx); armpmu_event_update(event);
perf_sample_data_init(&data, 0, hwc->last_period); perf_sample_data_init(&data, 0, hwc->last_period);
if (!armpmu_event_set_period(event, hwc, idx)) if (!armpmu_event_set_period(event))
continue; continue;
if (perf_event_overflow(event, &data, regs)) if (perf_event_overflow(event, &data, regs))
cpu_pmu->disable(hwc, idx); cpu_pmu->disable(event);
} }
/* /*
...@@ -527,8 +530,7 @@ armv6pmu_handle_irq(int irq_num, ...@@ -527,8 +530,7 @@ armv6pmu_handle_irq(int irq_num,
return IRQ_HANDLED; return IRQ_HANDLED;
} }
static void static void armv6pmu_start(struct arm_pmu *cpu_pmu)
armv6pmu_start(void)
{ {
unsigned long flags, val; unsigned long flags, val;
struct pmu_hw_events *events = cpu_pmu->get_hw_events(); struct pmu_hw_events *events = cpu_pmu->get_hw_events();
...@@ -540,8 +542,7 @@ armv6pmu_start(void) ...@@ -540,8 +542,7 @@ armv6pmu_start(void)
raw_spin_unlock_irqrestore(&events->pmu_lock, flags); raw_spin_unlock_irqrestore(&events->pmu_lock, flags);
} }
static void static void armv6pmu_stop(struct arm_pmu *cpu_pmu)
armv6pmu_stop(void)
{ {
unsigned long flags, val; unsigned long flags, val;
struct pmu_hw_events *events = cpu_pmu->get_hw_events(); struct pmu_hw_events *events = cpu_pmu->get_hw_events();
...@@ -555,10 +556,11 @@ armv6pmu_stop(void) ...@@ -555,10 +556,11 @@ armv6pmu_stop(void)
static int static int
armv6pmu_get_event_idx(struct pmu_hw_events *cpuc, armv6pmu_get_event_idx(struct pmu_hw_events *cpuc,
struct hw_perf_event *event) struct perf_event *event)
{ {
struct hw_perf_event *hwc = &event->hw;
/* Always place a cycle counter into the cycle counter. */ /* Always place a cycle counter into the cycle counter. */
if (ARMV6_PERFCTR_CPU_CYCLES == event->config_base) { if (ARMV6_PERFCTR_CPU_CYCLES == hwc->config_base) {
if (test_and_set_bit(ARMV6_CYCLE_COUNTER, cpuc->used_mask)) if (test_and_set_bit(ARMV6_CYCLE_COUNTER, cpuc->used_mask))
return -EAGAIN; return -EAGAIN;
...@@ -579,12 +581,13 @@ armv6pmu_get_event_idx(struct pmu_hw_events *cpuc, ...@@ -579,12 +581,13 @@ armv6pmu_get_event_idx(struct pmu_hw_events *cpuc,
} }
} }
static void static void armv6pmu_disable_event(struct perf_event *event)
armv6pmu_disable_event(struct hw_perf_event *hwc,
int idx)
{ {
unsigned long val, mask, evt, flags; unsigned long val, mask, evt, flags;
struct arm_pmu *cpu_pmu = to_arm_pmu(event->pmu);
struct hw_perf_event *hwc = &event->hw;
struct pmu_hw_events *events = cpu_pmu->get_hw_events(); struct pmu_hw_events *events = cpu_pmu->get_hw_events();
int idx = hwc->idx;
if (ARMV6_CYCLE_COUNTER == idx) { if (ARMV6_CYCLE_COUNTER == idx) {
mask = ARMV6_PMCR_CCOUNT_IEN; mask = ARMV6_PMCR_CCOUNT_IEN;
...@@ -613,12 +616,13 @@ armv6pmu_disable_event(struct hw_perf_event *hwc, ...@@ -613,12 +616,13 @@ armv6pmu_disable_event(struct hw_perf_event *hwc,
raw_spin_unlock_irqrestore(&events->pmu_lock, flags); raw_spin_unlock_irqrestore(&events->pmu_lock, flags);
} }
static void static void armv6mpcore_pmu_disable_event(struct perf_event *event)
armv6mpcore_pmu_disable_event(struct hw_perf_event *hwc,
int idx)
{ {
unsigned long val, mask, flags, evt = 0; unsigned long val, mask, flags, evt = 0;
struct arm_pmu *cpu_pmu = to_arm_pmu(event->pmu);
struct hw_perf_event *hwc = &event->hw;
struct pmu_hw_events *events = cpu_pmu->get_hw_events(); struct pmu_hw_events *events = cpu_pmu->get_hw_events();
int idx = hwc->idx;
if (ARMV6_CYCLE_COUNTER == idx) { if (ARMV6_CYCLE_COUNTER == idx) {
mask = ARMV6_PMCR_CCOUNT_IEN; mask = ARMV6_PMCR_CCOUNT_IEN;
...@@ -649,24 +653,22 @@ static int armv6_map_event(struct perf_event *event) ...@@ -649,24 +653,22 @@ static int armv6_map_event(struct perf_event *event)
&armv6_perf_cache_map, 0xFF); &armv6_perf_cache_map, 0xFF);
} }
static struct arm_pmu armv6pmu = { static int __devinit armv6pmu_init(struct arm_pmu *cpu_pmu)
.name = "v6",
.handle_irq = armv6pmu_handle_irq,
.enable = armv6pmu_enable_event,
.disable = armv6pmu_disable_event,
.read_counter = armv6pmu_read_counter,
.write_counter = armv6pmu_write_counter,
.get_event_idx = armv6pmu_get_event_idx,
.start = armv6pmu_start,
.stop = armv6pmu_stop,
.map_event = armv6_map_event,
.num_events = 3,
.max_period = (1LLU << 32) - 1,
};
static struct arm_pmu *__devinit armv6pmu_init(void)
{ {
return &armv6pmu; cpu_pmu->name = "v6";
cpu_pmu->handle_irq = armv6pmu_handle_irq;
cpu_pmu->enable = armv6pmu_enable_event;
cpu_pmu->disable = armv6pmu_disable_event;
cpu_pmu->read_counter = armv6pmu_read_counter;
cpu_pmu->write_counter = armv6pmu_write_counter;
cpu_pmu->get_event_idx = armv6pmu_get_event_idx;
cpu_pmu->start = armv6pmu_start;
cpu_pmu->stop = armv6pmu_stop;
cpu_pmu->map_event = armv6_map_event;
cpu_pmu->num_events = 3;
cpu_pmu->max_period = (1LLU << 32) - 1;
return 0;
} }
/* /*
...@@ -683,33 +685,31 @@ static int armv6mpcore_map_event(struct perf_event *event) ...@@ -683,33 +685,31 @@ static int armv6mpcore_map_event(struct perf_event *event)
&armv6mpcore_perf_cache_map, 0xFF); &armv6mpcore_perf_cache_map, 0xFF);
} }
static struct arm_pmu armv6mpcore_pmu = { static int __devinit armv6mpcore_pmu_init(struct arm_pmu *cpu_pmu)
.name = "v6mpcore",
.handle_irq = armv6pmu_handle_irq,
.enable = armv6pmu_enable_event,
.disable = armv6mpcore_pmu_disable_event,
.read_counter = armv6pmu_read_counter,
.write_counter = armv6pmu_write_counter,
.get_event_idx = armv6pmu_get_event_idx,
.start = armv6pmu_start,
.stop = armv6pmu_stop,
.map_event = armv6mpcore_map_event,
.num_events = 3,
.max_period = (1LLU << 32) - 1,
};
static struct arm_pmu *__devinit armv6mpcore_pmu_init(void)
{ {
return &armv6mpcore_pmu; cpu_pmu->name = "v6mpcore";
cpu_pmu->handle_irq = armv6pmu_handle_irq;
cpu_pmu->enable = armv6pmu_enable_event;
cpu_pmu->disable = armv6mpcore_pmu_disable_event;
cpu_pmu->read_counter = armv6pmu_read_counter;
cpu_pmu->write_counter = armv6pmu_write_counter;
cpu_pmu->get_event_idx = armv6pmu_get_event_idx;
cpu_pmu->start = armv6pmu_start;
cpu_pmu->stop = armv6pmu_stop;
cpu_pmu->map_event = armv6mpcore_map_event;
cpu_pmu->num_events = 3;
cpu_pmu->max_period = (1LLU << 32) - 1;
return 0;
} }
#else #else
static struct arm_pmu *__devinit armv6pmu_init(void) static int armv6pmu_init(struct arm_pmu *cpu_pmu)
{ {
return NULL; return -ENODEV;
} }
static struct arm_pmu *__devinit armv6mpcore_pmu_init(void) static int armv6mpcore_pmu_init(struct arm_pmu *cpu_pmu)
{ {
return NULL; return -ENODEV;
} }
#endif /* CONFIG_CPU_V6 || CONFIG_CPU_V6K */ #endif /* CONFIG_CPU_V6 || CONFIG_CPU_V6K */
...@@ -18,8 +18,6 @@ ...@@ -18,8 +18,6 @@
#ifdef CONFIG_CPU_V7 #ifdef CONFIG_CPU_V7
static struct arm_pmu armv7pmu;
/* /*
* Common ARMv7 event types * Common ARMv7 event types
* *
...@@ -738,7 +736,8 @@ static const unsigned armv7_a7_perf_cache_map[PERF_COUNT_HW_CACHE_MAX] ...@@ -738,7 +736,8 @@ static const unsigned armv7_a7_perf_cache_map[PERF_COUNT_HW_CACHE_MAX]
*/ */
#define ARMV7_IDX_CYCLE_COUNTER 0 #define ARMV7_IDX_CYCLE_COUNTER 0
#define ARMV7_IDX_COUNTER0 1 #define ARMV7_IDX_COUNTER0 1
#define ARMV7_IDX_COUNTER_LAST (ARMV7_IDX_CYCLE_COUNTER + cpu_pmu->num_events - 1) #define ARMV7_IDX_COUNTER_LAST(cpu_pmu) \
(ARMV7_IDX_CYCLE_COUNTER + cpu_pmu->num_events - 1)
#define ARMV7_MAX_COUNTERS 32 #define ARMV7_MAX_COUNTERS 32
#define ARMV7_COUNTER_MASK (ARMV7_MAX_COUNTERS - 1) #define ARMV7_COUNTER_MASK (ARMV7_MAX_COUNTERS - 1)
...@@ -804,49 +803,34 @@ static inline int armv7_pmnc_has_overflowed(u32 pmnc) ...@@ -804,49 +803,34 @@ static inline int armv7_pmnc_has_overflowed(u32 pmnc)
return pmnc & ARMV7_OVERFLOWED_MASK; return pmnc & ARMV7_OVERFLOWED_MASK;
} }
static inline int armv7_pmnc_counter_valid(int idx) static inline int armv7_pmnc_counter_valid(struct arm_pmu *cpu_pmu, int idx)
{ {
return idx >= ARMV7_IDX_CYCLE_COUNTER && idx <= ARMV7_IDX_COUNTER_LAST; return idx >= ARMV7_IDX_CYCLE_COUNTER &&
idx <= ARMV7_IDX_COUNTER_LAST(cpu_pmu);
} }
static inline int armv7_pmnc_counter_has_overflowed(u32 pmnc, int idx) static inline int armv7_pmnc_counter_has_overflowed(u32 pmnc, int idx)
{ {
int ret = 0; return pmnc & BIT(ARMV7_IDX_TO_COUNTER(idx));
u32 counter;
if (!armv7_pmnc_counter_valid(idx)) {
pr_err("CPU%u checking wrong counter %d overflow status\n",
smp_processor_id(), idx);
} else {
counter = ARMV7_IDX_TO_COUNTER(idx);
ret = pmnc & BIT(counter);
}
return ret;
} }
static inline int armv7_pmnc_select_counter(int idx) static inline int armv7_pmnc_select_counter(int idx)
{ {
u32 counter; u32 counter = ARMV7_IDX_TO_COUNTER(idx);
if (!armv7_pmnc_counter_valid(idx)) {
pr_err("CPU%u selecting wrong PMNC counter %d\n",
smp_processor_id(), idx);
return -EINVAL;
}
counter = ARMV7_IDX_TO_COUNTER(idx);
asm volatile("mcr p15, 0, %0, c9, c12, 5" : : "r" (counter)); asm volatile("mcr p15, 0, %0, c9, c12, 5" : : "r" (counter));
isb(); isb();
return idx; return idx;
} }
static inline u32 armv7pmu_read_counter(int idx) static inline u32 armv7pmu_read_counter(struct perf_event *event)
{ {
struct arm_pmu *cpu_pmu = to_arm_pmu(event->pmu);
struct hw_perf_event *hwc = &event->hw;
int idx = hwc->idx;
u32 value = 0; u32 value = 0;
if (!armv7_pmnc_counter_valid(idx)) if (!armv7_pmnc_counter_valid(cpu_pmu, idx))
pr_err("CPU%u reading wrong counter %d\n", pr_err("CPU%u reading wrong counter %d\n",
smp_processor_id(), idx); smp_processor_id(), idx);
else if (idx == ARMV7_IDX_CYCLE_COUNTER) else if (idx == ARMV7_IDX_CYCLE_COUNTER)
...@@ -857,9 +841,13 @@ static inline u32 armv7pmu_read_counter(int idx) ...@@ -857,9 +841,13 @@ static inline u32 armv7pmu_read_counter(int idx)
return value; return value;
} }
static inline void armv7pmu_write_counter(int idx, u32 value) static inline void armv7pmu_write_counter(struct perf_event *event, u32 value)
{ {
if (!armv7_pmnc_counter_valid(idx)) struct arm_pmu *cpu_pmu = to_arm_pmu(event->pmu);
struct hw_perf_event *hwc = &event->hw;
int idx = hwc->idx;
if (!armv7_pmnc_counter_valid(cpu_pmu, idx))
pr_err("CPU%u writing wrong counter %d\n", pr_err("CPU%u writing wrong counter %d\n",
smp_processor_id(), idx); smp_processor_id(), idx);
else if (idx == ARMV7_IDX_CYCLE_COUNTER) else if (idx == ARMV7_IDX_CYCLE_COUNTER)
...@@ -878,60 +866,28 @@ static inline void armv7_pmnc_write_evtsel(int idx, u32 val) ...@@ -878,60 +866,28 @@ static inline void armv7_pmnc_write_evtsel(int idx, u32 val)
static inline int armv7_pmnc_enable_counter(int idx) static inline int armv7_pmnc_enable_counter(int idx)
{ {
u32 counter; u32 counter = ARMV7_IDX_TO_COUNTER(idx);
if (!armv7_pmnc_counter_valid(idx)) {
pr_err("CPU%u enabling wrong PMNC counter %d\n",
smp_processor_id(), idx);
return -EINVAL;
}
counter = ARMV7_IDX_TO_COUNTER(idx);
asm volatile("mcr p15, 0, %0, c9, c12, 1" : : "r" (BIT(counter))); asm volatile("mcr p15, 0, %0, c9, c12, 1" : : "r" (BIT(counter)));
return idx; return idx;
} }
static inline int armv7_pmnc_disable_counter(int idx) static inline int armv7_pmnc_disable_counter(int idx)
{ {
u32 counter; u32 counter = ARMV7_IDX_TO_COUNTER(idx);
if (!armv7_pmnc_counter_valid(idx)) {
pr_err("CPU%u disabling wrong PMNC counter %d\n",
smp_processor_id(), idx);
return -EINVAL;
}
counter = ARMV7_IDX_TO_COUNTER(idx);
asm volatile("mcr p15, 0, %0, c9, c12, 2" : : "r" (BIT(counter))); asm volatile("mcr p15, 0, %0, c9, c12, 2" : : "r" (BIT(counter)));
return idx; return idx;
} }
static inline int armv7_pmnc_enable_intens(int idx) static inline int armv7_pmnc_enable_intens(int idx)
{ {
u32 counter; u32 counter = ARMV7_IDX_TO_COUNTER(idx);
if (!armv7_pmnc_counter_valid(idx)) {
pr_err("CPU%u enabling wrong PMNC counter IRQ enable %d\n",
smp_processor_id(), idx);
return -EINVAL;
}
counter = ARMV7_IDX_TO_COUNTER(idx);
asm volatile("mcr p15, 0, %0, c9, c14, 1" : : "r" (BIT(counter))); asm volatile("mcr p15, 0, %0, c9, c14, 1" : : "r" (BIT(counter)));
return idx; return idx;
} }
static inline int armv7_pmnc_disable_intens(int idx) static inline int armv7_pmnc_disable_intens(int idx)
{ {
u32 counter; u32 counter = ARMV7_IDX_TO_COUNTER(idx);
if (!armv7_pmnc_counter_valid(idx)) {
pr_err("CPU%u disabling wrong PMNC counter IRQ enable %d\n",
smp_processor_id(), idx);
return -EINVAL;
}
counter = ARMV7_IDX_TO_COUNTER(idx);
asm volatile("mcr p15, 0, %0, c9, c14, 2" : : "r" (BIT(counter))); asm volatile("mcr p15, 0, %0, c9, c14, 2" : : "r" (BIT(counter)));
isb(); isb();
/* Clear the overflow flag in case an interrupt is pending. */ /* Clear the overflow flag in case an interrupt is pending. */
...@@ -956,7 +912,7 @@ static inline u32 armv7_pmnc_getreset_flags(void) ...@@ -956,7 +912,7 @@ static inline u32 armv7_pmnc_getreset_flags(void)
} }
#ifdef DEBUG #ifdef DEBUG
static void armv7_pmnc_dump_regs(void) static void armv7_pmnc_dump_regs(struct arm_pmu *cpu_pmu)
{ {
u32 val; u32 val;
unsigned int cnt; unsigned int cnt;
...@@ -981,7 +937,8 @@ static void armv7_pmnc_dump_regs(void) ...@@ -981,7 +937,8 @@ static void armv7_pmnc_dump_regs(void)
asm volatile("mrc p15, 0, %0, c9, c13, 0" : "=r" (val)); asm volatile("mrc p15, 0, %0, c9, c13, 0" : "=r" (val));
printk(KERN_INFO "CCNT =0x%08x\n", val); printk(KERN_INFO "CCNT =0x%08x\n", val);
for (cnt = ARMV7_IDX_COUNTER0; cnt <= ARMV7_IDX_COUNTER_LAST; cnt++) { for (cnt = ARMV7_IDX_COUNTER0;
cnt <= ARMV7_IDX_COUNTER_LAST(cpu_pmu); cnt++) {
armv7_pmnc_select_counter(cnt); armv7_pmnc_select_counter(cnt);
asm volatile("mrc p15, 0, %0, c9, c13, 2" : "=r" (val)); asm volatile("mrc p15, 0, %0, c9, c13, 2" : "=r" (val));
printk(KERN_INFO "CNT[%d] count =0x%08x\n", printk(KERN_INFO "CNT[%d] count =0x%08x\n",
...@@ -993,10 +950,19 @@ static void armv7_pmnc_dump_regs(void) ...@@ -993,10 +950,19 @@ static void armv7_pmnc_dump_regs(void)
} }
#endif #endif
static void armv7pmu_enable_event(struct hw_perf_event *hwc, int idx) static void armv7pmu_enable_event(struct perf_event *event)
{ {
unsigned long flags; unsigned long flags;
struct hw_perf_event *hwc = &event->hw;
struct arm_pmu *cpu_pmu = to_arm_pmu(event->pmu);
struct pmu_hw_events *events = cpu_pmu->get_hw_events(); struct pmu_hw_events *events = cpu_pmu->get_hw_events();
int idx = hwc->idx;
if (!armv7_pmnc_counter_valid(cpu_pmu, idx)) {
pr_err("CPU%u enabling wrong PMNC counter IRQ enable %d\n",
smp_processor_id(), idx);
return;
}
/* /*
* Enable counter and interrupt, and set the counter to count * Enable counter and interrupt, and set the counter to count
...@@ -1014,7 +980,7 @@ static void armv7pmu_enable_event(struct hw_perf_event *hwc, int idx) ...@@ -1014,7 +980,7 @@ static void armv7pmu_enable_event(struct hw_perf_event *hwc, int idx)
* We only need to set the event for the cycle counter if we * We only need to set the event for the cycle counter if we
* have the ability to perform event filtering. * have the ability to perform event filtering.
*/ */
if (armv7pmu.set_event_filter || idx != ARMV7_IDX_CYCLE_COUNTER) if (cpu_pmu->set_event_filter || idx != ARMV7_IDX_CYCLE_COUNTER)
armv7_pmnc_write_evtsel(idx, hwc->config_base); armv7_pmnc_write_evtsel(idx, hwc->config_base);
/* /*
...@@ -1030,10 +996,19 @@ static void armv7pmu_enable_event(struct hw_perf_event *hwc, int idx) ...@@ -1030,10 +996,19 @@ static void armv7pmu_enable_event(struct hw_perf_event *hwc, int idx)
raw_spin_unlock_irqrestore(&events->pmu_lock, flags); raw_spin_unlock_irqrestore(&events->pmu_lock, flags);
} }
static void armv7pmu_disable_event(struct hw_perf_event *hwc, int idx) static void armv7pmu_disable_event(struct perf_event *event)
{ {
unsigned long flags; unsigned long flags;
struct hw_perf_event *hwc = &event->hw;
struct arm_pmu *cpu_pmu = to_arm_pmu(event->pmu);
struct pmu_hw_events *events = cpu_pmu->get_hw_events(); struct pmu_hw_events *events = cpu_pmu->get_hw_events();
int idx = hwc->idx;
if (!armv7_pmnc_counter_valid(cpu_pmu, idx)) {
pr_err("CPU%u disabling wrong PMNC counter IRQ enable %d\n",
smp_processor_id(), idx);
return;
}
/* /*
* Disable counter and interrupt * Disable counter and interrupt
...@@ -1057,7 +1032,8 @@ static irqreturn_t armv7pmu_handle_irq(int irq_num, void *dev) ...@@ -1057,7 +1032,8 @@ static irqreturn_t armv7pmu_handle_irq(int irq_num, void *dev)
{ {
u32 pmnc; u32 pmnc;
struct perf_sample_data data; struct perf_sample_data data;
struct pmu_hw_events *cpuc; struct arm_pmu *cpu_pmu = (struct arm_pmu *)dev;
struct pmu_hw_events *cpuc = cpu_pmu->get_hw_events();
struct pt_regs *regs; struct pt_regs *regs;
int idx; int idx;
...@@ -1077,7 +1053,6 @@ static irqreturn_t armv7pmu_handle_irq(int irq_num, void *dev) ...@@ -1077,7 +1053,6 @@ static irqreturn_t armv7pmu_handle_irq(int irq_num, void *dev)
*/ */
regs = get_irq_regs(); regs = get_irq_regs();
cpuc = &__get_cpu_var(cpu_hw_events);
for (idx = 0; idx < cpu_pmu->num_events; ++idx) { for (idx = 0; idx < cpu_pmu->num_events; ++idx) {
struct perf_event *event = cpuc->events[idx]; struct perf_event *event = cpuc->events[idx];
struct hw_perf_event *hwc; struct hw_perf_event *hwc;
...@@ -1094,13 +1069,13 @@ static irqreturn_t armv7pmu_handle_irq(int irq_num, void *dev) ...@@ -1094,13 +1069,13 @@ static irqreturn_t armv7pmu_handle_irq(int irq_num, void *dev)
continue; continue;
hwc = &event->hw; hwc = &event->hw;
armpmu_event_update(event, hwc, idx); armpmu_event_update(event);
perf_sample_data_init(&data, 0, hwc->last_period); perf_sample_data_init(&data, 0, hwc->last_period);
if (!armpmu_event_set_period(event, hwc, idx)) if (!armpmu_event_set_period(event))
continue; continue;
if (perf_event_overflow(event, &data, regs)) if (perf_event_overflow(event, &data, regs))
cpu_pmu->disable(hwc, idx); cpu_pmu->disable(event);
} }
/* /*
...@@ -1115,7 +1090,7 @@ static irqreturn_t armv7pmu_handle_irq(int irq_num, void *dev) ...@@ -1115,7 +1090,7 @@ static irqreturn_t armv7pmu_handle_irq(int irq_num, void *dev)
return IRQ_HANDLED; return IRQ_HANDLED;
} }
static void armv7pmu_start(void) static void armv7pmu_start(struct arm_pmu *cpu_pmu)
{ {
unsigned long flags; unsigned long flags;
struct pmu_hw_events *events = cpu_pmu->get_hw_events(); struct pmu_hw_events *events = cpu_pmu->get_hw_events();
...@@ -1126,7 +1101,7 @@ static void armv7pmu_start(void) ...@@ -1126,7 +1101,7 @@ static void armv7pmu_start(void)
raw_spin_unlock_irqrestore(&events->pmu_lock, flags); raw_spin_unlock_irqrestore(&events->pmu_lock, flags);
} }
static void armv7pmu_stop(void) static void armv7pmu_stop(struct arm_pmu *cpu_pmu)
{ {
unsigned long flags; unsigned long flags;
struct pmu_hw_events *events = cpu_pmu->get_hw_events(); struct pmu_hw_events *events = cpu_pmu->get_hw_events();
...@@ -1138,10 +1113,12 @@ static void armv7pmu_stop(void) ...@@ -1138,10 +1113,12 @@ static void armv7pmu_stop(void)
} }
static int armv7pmu_get_event_idx(struct pmu_hw_events *cpuc, static int armv7pmu_get_event_idx(struct pmu_hw_events *cpuc,
struct hw_perf_event *event) struct perf_event *event)
{ {
int idx; int idx;
unsigned long evtype = event->config_base & ARMV7_EVTYPE_EVENT; struct arm_pmu *cpu_pmu = to_arm_pmu(event->pmu);
struct hw_perf_event *hwc = &event->hw;
unsigned long evtype = hwc->config_base & ARMV7_EVTYPE_EVENT;
/* Always place a cycle counter into the cycle counter. */ /* Always place a cycle counter into the cycle counter. */
if (evtype == ARMV7_PERFCTR_CPU_CYCLES) { if (evtype == ARMV7_PERFCTR_CPU_CYCLES) {
...@@ -1192,11 +1169,14 @@ static int armv7pmu_set_event_filter(struct hw_perf_event *event, ...@@ -1192,11 +1169,14 @@ static int armv7pmu_set_event_filter(struct hw_perf_event *event,
static void armv7pmu_reset(void *info) static void armv7pmu_reset(void *info)
{ {
struct arm_pmu *cpu_pmu = (struct arm_pmu *)info;
u32 idx, nb_cnt = cpu_pmu->num_events; u32 idx, nb_cnt = cpu_pmu->num_events;
/* The counter and interrupt enable registers are unknown at reset. */ /* The counter and interrupt enable registers are unknown at reset. */
for (idx = ARMV7_IDX_CYCLE_COUNTER; idx < nb_cnt; ++idx) for (idx = ARMV7_IDX_CYCLE_COUNTER; idx < nb_cnt; ++idx) {
armv7pmu_disable_event(NULL, idx); armv7_pmnc_disable_counter(idx);
armv7_pmnc_disable_intens(idx);
}
/* Initialize & Reset PMNC: C and P bits */ /* Initialize & Reset PMNC: C and P bits */
armv7_pmnc_write(ARMV7_PMNC_P | ARMV7_PMNC_C); armv7_pmnc_write(ARMV7_PMNC_P | ARMV7_PMNC_C);
...@@ -1232,17 +1212,18 @@ static int armv7_a7_map_event(struct perf_event *event) ...@@ -1232,17 +1212,18 @@ static int armv7_a7_map_event(struct perf_event *event)
&armv7_a7_perf_cache_map, 0xFF); &armv7_a7_perf_cache_map, 0xFF);
} }
static struct arm_pmu armv7pmu = { static void armv7pmu_init(struct arm_pmu *cpu_pmu)
.handle_irq = armv7pmu_handle_irq, {
.enable = armv7pmu_enable_event, cpu_pmu->handle_irq = armv7pmu_handle_irq;
.disable = armv7pmu_disable_event, cpu_pmu->enable = armv7pmu_enable_event;
.read_counter = armv7pmu_read_counter, cpu_pmu->disable = armv7pmu_disable_event;
.write_counter = armv7pmu_write_counter, cpu_pmu->read_counter = armv7pmu_read_counter;
.get_event_idx = armv7pmu_get_event_idx, cpu_pmu->write_counter = armv7pmu_write_counter;
.start = armv7pmu_start, cpu_pmu->get_event_idx = armv7pmu_get_event_idx;
.stop = armv7pmu_stop, cpu_pmu->start = armv7pmu_start;
.reset = armv7pmu_reset, cpu_pmu->stop = armv7pmu_stop;
.max_period = (1LLU << 32) - 1, cpu_pmu->reset = armv7pmu_reset;
cpu_pmu->max_period = (1LLU << 32) - 1;
}; };
static u32 __devinit armv7_read_num_pmnc_events(void) static u32 __devinit armv7_read_num_pmnc_events(void)
...@@ -1256,70 +1237,75 @@ static u32 __devinit armv7_read_num_pmnc_events(void) ...@@ -1256,70 +1237,75 @@ static u32 __devinit armv7_read_num_pmnc_events(void)
return nb_cnt + 1; return nb_cnt + 1;
} }
static struct arm_pmu *__devinit armv7_a8_pmu_init(void) static int __devinit armv7_a8_pmu_init(struct arm_pmu *cpu_pmu)
{ {
armv7pmu.name = "ARMv7 Cortex-A8"; armv7pmu_init(cpu_pmu);
armv7pmu.map_event = armv7_a8_map_event; cpu_pmu->name = "ARMv7 Cortex-A8";
armv7pmu.num_events = armv7_read_num_pmnc_events(); cpu_pmu->map_event = armv7_a8_map_event;
return &armv7pmu; cpu_pmu->num_events = armv7_read_num_pmnc_events();
return 0;
} }
static struct arm_pmu *__devinit armv7_a9_pmu_init(void) static int __devinit armv7_a9_pmu_init(struct arm_pmu *cpu_pmu)
{ {
armv7pmu.name = "ARMv7 Cortex-A9"; armv7pmu_init(cpu_pmu);
armv7pmu.map_event = armv7_a9_map_event; cpu_pmu->name = "ARMv7 Cortex-A9";
armv7pmu.num_events = armv7_read_num_pmnc_events(); cpu_pmu->map_event = armv7_a9_map_event;
return &armv7pmu; cpu_pmu->num_events = armv7_read_num_pmnc_events();
return 0;
} }
static struct arm_pmu *__devinit armv7_a5_pmu_init(void) static int __devinit armv7_a5_pmu_init(struct arm_pmu *cpu_pmu)
{ {
armv7pmu.name = "ARMv7 Cortex-A5"; armv7pmu_init(cpu_pmu);
armv7pmu.map_event = armv7_a5_map_event; cpu_pmu->name = "ARMv7 Cortex-A5";
armv7pmu.num_events = armv7_read_num_pmnc_events(); cpu_pmu->map_event = armv7_a5_map_event;
return &armv7pmu; cpu_pmu->num_events = armv7_read_num_pmnc_events();
return 0;
} }
static struct arm_pmu *__devinit armv7_a15_pmu_init(void) static int __devinit armv7_a15_pmu_init(struct arm_pmu *cpu_pmu)
{ {
armv7pmu.name = "ARMv7 Cortex-A15"; armv7pmu_init(cpu_pmu);
armv7pmu.map_event = armv7_a15_map_event; cpu_pmu->name = "ARMv7 Cortex-A15";
armv7pmu.num_events = armv7_read_num_pmnc_events(); cpu_pmu->map_event = armv7_a15_map_event;
armv7pmu.set_event_filter = armv7pmu_set_event_filter; cpu_pmu->num_events = armv7_read_num_pmnc_events();
return &armv7pmu; cpu_pmu->set_event_filter = armv7pmu_set_event_filter;
return 0;
} }
static struct arm_pmu *__devinit armv7_a7_pmu_init(void) static int __devinit armv7_a7_pmu_init(struct arm_pmu *cpu_pmu)
{ {
armv7pmu.name = "ARMv7 Cortex-A7"; armv7pmu_init(cpu_pmu);
armv7pmu.map_event = armv7_a7_map_event; cpu_pmu->name = "ARMv7 Cortex-A7";
armv7pmu.num_events = armv7_read_num_pmnc_events(); cpu_pmu->map_event = armv7_a7_map_event;
armv7pmu.set_event_filter = armv7pmu_set_event_filter; cpu_pmu->num_events = armv7_read_num_pmnc_events();
return &armv7pmu; cpu_pmu->set_event_filter = armv7pmu_set_event_filter;
return 0;
} }
#else #else
static struct arm_pmu *__devinit armv7_a8_pmu_init(void) static inline int armv7_a8_pmu_init(struct arm_pmu *cpu_pmu)
{ {
return NULL; return -ENODEV;
} }
static struct arm_pmu *__devinit armv7_a9_pmu_init(void) static inline int armv7_a9_pmu_init(struct arm_pmu *cpu_pmu)
{ {
return NULL; return -ENODEV;
} }
static struct arm_pmu *__devinit armv7_a5_pmu_init(void) static inline int armv7_a5_pmu_init(struct arm_pmu *cpu_pmu)
{ {
return NULL; return -ENODEV;
} }
static struct arm_pmu *__devinit armv7_a15_pmu_init(void) static inline int armv7_a15_pmu_init(struct arm_pmu *cpu_pmu)
{ {
return NULL; return -ENODEV;
} }
static struct arm_pmu *__devinit armv7_a7_pmu_init(void) static inline int armv7_a7_pmu_init(struct arm_pmu *cpu_pmu)
{ {
return NULL; return -ENODEV;
} }
#endif /* CONFIG_CPU_V7 */ #endif /* CONFIG_CPU_V7 */
...@@ -224,7 +224,8 @@ xscale1pmu_handle_irq(int irq_num, void *dev) ...@@ -224,7 +224,8 @@ xscale1pmu_handle_irq(int irq_num, void *dev)
{ {
unsigned long pmnc; unsigned long pmnc;
struct perf_sample_data data; struct perf_sample_data data;
struct pmu_hw_events *cpuc; struct arm_pmu *cpu_pmu = (struct arm_pmu *)dev;
struct pmu_hw_events *cpuc = cpu_pmu->get_hw_events();
struct pt_regs *regs; struct pt_regs *regs;
int idx; int idx;
...@@ -248,7 +249,6 @@ xscale1pmu_handle_irq(int irq_num, void *dev) ...@@ -248,7 +249,6 @@ xscale1pmu_handle_irq(int irq_num, void *dev)
regs = get_irq_regs(); regs = get_irq_regs();
cpuc = &__get_cpu_var(cpu_hw_events);
for (idx = 0; idx < cpu_pmu->num_events; ++idx) { for (idx = 0; idx < cpu_pmu->num_events; ++idx) {
struct perf_event *event = cpuc->events[idx]; struct perf_event *event = cpuc->events[idx];
struct hw_perf_event *hwc; struct hw_perf_event *hwc;
...@@ -260,13 +260,13 @@ xscale1pmu_handle_irq(int irq_num, void *dev) ...@@ -260,13 +260,13 @@ xscale1pmu_handle_irq(int irq_num, void *dev)
continue; continue;
hwc = &event->hw; hwc = &event->hw;
armpmu_event_update(event, hwc, idx); armpmu_event_update(event);
perf_sample_data_init(&data, 0, hwc->last_period); perf_sample_data_init(&data, 0, hwc->last_period);
if (!armpmu_event_set_period(event, hwc, idx)) if (!armpmu_event_set_period(event))
continue; continue;
if (perf_event_overflow(event, &data, regs)) if (perf_event_overflow(event, &data, regs))
cpu_pmu->disable(hwc, idx); cpu_pmu->disable(event);
} }
irq_work_run(); irq_work_run();
...@@ -280,11 +280,13 @@ xscale1pmu_handle_irq(int irq_num, void *dev) ...@@ -280,11 +280,13 @@ xscale1pmu_handle_irq(int irq_num, void *dev)
return IRQ_HANDLED; return IRQ_HANDLED;
} }
static void static void xscale1pmu_enable_event(struct perf_event *event)
xscale1pmu_enable_event(struct hw_perf_event *hwc, int idx)
{ {
unsigned long val, mask, evt, flags; unsigned long val, mask, evt, flags;
struct arm_pmu *cpu_pmu = to_arm_pmu(event->pmu);
struct hw_perf_event *hwc = &event->hw;
struct pmu_hw_events *events = cpu_pmu->get_hw_events(); struct pmu_hw_events *events = cpu_pmu->get_hw_events();
int idx = hwc->idx;
switch (idx) { switch (idx) {
case XSCALE_CYCLE_COUNTER: case XSCALE_CYCLE_COUNTER:
...@@ -314,11 +316,13 @@ xscale1pmu_enable_event(struct hw_perf_event *hwc, int idx) ...@@ -314,11 +316,13 @@ xscale1pmu_enable_event(struct hw_perf_event *hwc, int idx)
raw_spin_unlock_irqrestore(&events->pmu_lock, flags); raw_spin_unlock_irqrestore(&events->pmu_lock, flags);
} }
static void static void xscale1pmu_disable_event(struct perf_event *event)
xscale1pmu_disable_event(struct hw_perf_event *hwc, int idx)
{ {
unsigned long val, mask, evt, flags; unsigned long val, mask, evt, flags;
struct arm_pmu *cpu_pmu = to_arm_pmu(event->pmu);
struct hw_perf_event *hwc = &event->hw;
struct pmu_hw_events *events = cpu_pmu->get_hw_events(); struct pmu_hw_events *events = cpu_pmu->get_hw_events();
int idx = hwc->idx;
switch (idx) { switch (idx) {
case XSCALE_CYCLE_COUNTER: case XSCALE_CYCLE_COUNTER:
...@@ -348,9 +352,10 @@ xscale1pmu_disable_event(struct hw_perf_event *hwc, int idx) ...@@ -348,9 +352,10 @@ xscale1pmu_disable_event(struct hw_perf_event *hwc, int idx)
static int static int
xscale1pmu_get_event_idx(struct pmu_hw_events *cpuc, xscale1pmu_get_event_idx(struct pmu_hw_events *cpuc,
struct hw_perf_event *event) struct perf_event *event)
{ {
if (XSCALE_PERFCTR_CCNT == event->config_base) { struct hw_perf_event *hwc = &event->hw;
if (XSCALE_PERFCTR_CCNT == hwc->config_base) {
if (test_and_set_bit(XSCALE_CYCLE_COUNTER, cpuc->used_mask)) if (test_and_set_bit(XSCALE_CYCLE_COUNTER, cpuc->used_mask))
return -EAGAIN; return -EAGAIN;
...@@ -366,8 +371,7 @@ xscale1pmu_get_event_idx(struct pmu_hw_events *cpuc, ...@@ -366,8 +371,7 @@ xscale1pmu_get_event_idx(struct pmu_hw_events *cpuc,
} }
} }
static void static void xscale1pmu_start(struct arm_pmu *cpu_pmu)
xscale1pmu_start(void)
{ {
unsigned long flags, val; unsigned long flags, val;
struct pmu_hw_events *events = cpu_pmu->get_hw_events(); struct pmu_hw_events *events = cpu_pmu->get_hw_events();
...@@ -379,8 +383,7 @@ xscale1pmu_start(void) ...@@ -379,8 +383,7 @@ xscale1pmu_start(void)
raw_spin_unlock_irqrestore(&events->pmu_lock, flags); raw_spin_unlock_irqrestore(&events->pmu_lock, flags);
} }
static void static void xscale1pmu_stop(struct arm_pmu *cpu_pmu)
xscale1pmu_stop(void)
{ {
unsigned long flags, val; unsigned long flags, val;
struct pmu_hw_events *events = cpu_pmu->get_hw_events(); struct pmu_hw_events *events = cpu_pmu->get_hw_events();
...@@ -392,9 +395,10 @@ xscale1pmu_stop(void) ...@@ -392,9 +395,10 @@ xscale1pmu_stop(void)
raw_spin_unlock_irqrestore(&events->pmu_lock, flags); raw_spin_unlock_irqrestore(&events->pmu_lock, flags);
} }
static inline u32 static inline u32 xscale1pmu_read_counter(struct perf_event *event)
xscale1pmu_read_counter(int counter)
{ {
struct hw_perf_event *hwc = &event->hw;
int counter = hwc->idx;
u32 val = 0; u32 val = 0;
switch (counter) { switch (counter) {
...@@ -412,9 +416,11 @@ xscale1pmu_read_counter(int counter) ...@@ -412,9 +416,11 @@ xscale1pmu_read_counter(int counter)
return val; return val;
} }
static inline void static inline void xscale1pmu_write_counter(struct perf_event *event, u32 val)
xscale1pmu_write_counter(int counter, u32 val)
{ {
struct hw_perf_event *hwc = &event->hw;
int counter = hwc->idx;
switch (counter) { switch (counter) {
case XSCALE_CYCLE_COUNTER: case XSCALE_CYCLE_COUNTER:
asm volatile("mcr p14, 0, %0, c1, c0, 0" : : "r" (val)); asm volatile("mcr p14, 0, %0, c1, c0, 0" : : "r" (val));
...@@ -434,24 +440,22 @@ static int xscale_map_event(struct perf_event *event) ...@@ -434,24 +440,22 @@ static int xscale_map_event(struct perf_event *event)
&xscale_perf_cache_map, 0xFF); &xscale_perf_cache_map, 0xFF);
} }
static struct arm_pmu xscale1pmu = { static int __devinit xscale1pmu_init(struct arm_pmu *cpu_pmu)
.name = "xscale1",
.handle_irq = xscale1pmu_handle_irq,
.enable = xscale1pmu_enable_event,
.disable = xscale1pmu_disable_event,
.read_counter = xscale1pmu_read_counter,
.write_counter = xscale1pmu_write_counter,
.get_event_idx = xscale1pmu_get_event_idx,
.start = xscale1pmu_start,
.stop = xscale1pmu_stop,
.map_event = xscale_map_event,
.num_events = 3,
.max_period = (1LLU << 32) - 1,
};
static struct arm_pmu *__devinit xscale1pmu_init(void)
{ {
return &xscale1pmu; cpu_pmu->name = "xscale1";
cpu_pmu->handle_irq = xscale1pmu_handle_irq;
cpu_pmu->enable = xscale1pmu_enable_event;
cpu_pmu->disable = xscale1pmu_disable_event;
cpu_pmu->read_counter = xscale1pmu_read_counter;
cpu_pmu->write_counter = xscale1pmu_write_counter;
cpu_pmu->get_event_idx = xscale1pmu_get_event_idx;
cpu_pmu->start = xscale1pmu_start;
cpu_pmu->stop = xscale1pmu_stop;
cpu_pmu->map_event = xscale_map_event;
cpu_pmu->num_events = 3;
cpu_pmu->max_period = (1LLU << 32) - 1;
return 0;
} }
#define XSCALE2_OVERFLOWED_MASK 0x01f #define XSCALE2_OVERFLOWED_MASK 0x01f
...@@ -567,7 +571,8 @@ xscale2pmu_handle_irq(int irq_num, void *dev) ...@@ -567,7 +571,8 @@ xscale2pmu_handle_irq(int irq_num, void *dev)
{ {
unsigned long pmnc, of_flags; unsigned long pmnc, of_flags;
struct perf_sample_data data; struct perf_sample_data data;
struct pmu_hw_events *cpuc; struct arm_pmu *cpu_pmu = (struct arm_pmu *)dev;
struct pmu_hw_events *cpuc = cpu_pmu->get_hw_events();
struct pt_regs *regs; struct pt_regs *regs;
int idx; int idx;
...@@ -585,7 +590,6 @@ xscale2pmu_handle_irq(int irq_num, void *dev) ...@@ -585,7 +590,6 @@ xscale2pmu_handle_irq(int irq_num, void *dev)
regs = get_irq_regs(); regs = get_irq_regs();
cpuc = &__get_cpu_var(cpu_hw_events);
for (idx = 0; idx < cpu_pmu->num_events; ++idx) { for (idx = 0; idx < cpu_pmu->num_events; ++idx) {
struct perf_event *event = cpuc->events[idx]; struct perf_event *event = cpuc->events[idx];
struct hw_perf_event *hwc; struct hw_perf_event *hwc;
...@@ -597,13 +601,13 @@ xscale2pmu_handle_irq(int irq_num, void *dev) ...@@ -597,13 +601,13 @@ xscale2pmu_handle_irq(int irq_num, void *dev)
continue; continue;
hwc = &event->hw; hwc = &event->hw;
armpmu_event_update(event, hwc, idx); armpmu_event_update(event);
perf_sample_data_init(&data, 0, hwc->last_period); perf_sample_data_init(&data, 0, hwc->last_period);
if (!armpmu_event_set_period(event, hwc, idx)) if (!armpmu_event_set_period(event))
continue; continue;
if (perf_event_overflow(event, &data, regs)) if (perf_event_overflow(event, &data, regs))
cpu_pmu->disable(hwc, idx); cpu_pmu->disable(event);
} }
irq_work_run(); irq_work_run();
...@@ -617,11 +621,13 @@ xscale2pmu_handle_irq(int irq_num, void *dev) ...@@ -617,11 +621,13 @@ xscale2pmu_handle_irq(int irq_num, void *dev)
return IRQ_HANDLED; return IRQ_HANDLED;
} }
static void static void xscale2pmu_enable_event(struct perf_event *event)
xscale2pmu_enable_event(struct hw_perf_event *hwc, int idx)
{ {
unsigned long flags, ien, evtsel; unsigned long flags, ien, evtsel;
struct arm_pmu *cpu_pmu = to_arm_pmu(event->pmu);
struct hw_perf_event *hwc = &event->hw;
struct pmu_hw_events *events = cpu_pmu->get_hw_events(); struct pmu_hw_events *events = cpu_pmu->get_hw_events();
int idx = hwc->idx;
ien = xscale2pmu_read_int_enable(); ien = xscale2pmu_read_int_enable();
evtsel = xscale2pmu_read_event_select(); evtsel = xscale2pmu_read_event_select();
...@@ -661,11 +667,13 @@ xscale2pmu_enable_event(struct hw_perf_event *hwc, int idx) ...@@ -661,11 +667,13 @@ xscale2pmu_enable_event(struct hw_perf_event *hwc, int idx)
raw_spin_unlock_irqrestore(&events->pmu_lock, flags); raw_spin_unlock_irqrestore(&events->pmu_lock, flags);
} }
static void static void xscale2pmu_disable_event(struct perf_event *event)
xscale2pmu_disable_event(struct hw_perf_event *hwc, int idx)
{ {
unsigned long flags, ien, evtsel, of_flags; unsigned long flags, ien, evtsel, of_flags;
struct arm_pmu *cpu_pmu = to_arm_pmu(event->pmu);
struct hw_perf_event *hwc = &event->hw;
struct pmu_hw_events *events = cpu_pmu->get_hw_events(); struct pmu_hw_events *events = cpu_pmu->get_hw_events();
int idx = hwc->idx;
ien = xscale2pmu_read_int_enable(); ien = xscale2pmu_read_int_enable();
evtsel = xscale2pmu_read_event_select(); evtsel = xscale2pmu_read_event_select();
...@@ -713,7 +721,7 @@ xscale2pmu_disable_event(struct hw_perf_event *hwc, int idx) ...@@ -713,7 +721,7 @@ xscale2pmu_disable_event(struct hw_perf_event *hwc, int idx)
static int static int
xscale2pmu_get_event_idx(struct pmu_hw_events *cpuc, xscale2pmu_get_event_idx(struct pmu_hw_events *cpuc,
struct hw_perf_event *event) struct perf_event *event)
{ {
int idx = xscale1pmu_get_event_idx(cpuc, event); int idx = xscale1pmu_get_event_idx(cpuc, event);
if (idx >= 0) if (idx >= 0)
...@@ -727,8 +735,7 @@ xscale2pmu_get_event_idx(struct pmu_hw_events *cpuc, ...@@ -727,8 +735,7 @@ xscale2pmu_get_event_idx(struct pmu_hw_events *cpuc,
return idx; return idx;
} }
static void static void xscale2pmu_start(struct arm_pmu *cpu_pmu)
xscale2pmu_start(void)
{ {
unsigned long flags, val; unsigned long flags, val;
struct pmu_hw_events *events = cpu_pmu->get_hw_events(); struct pmu_hw_events *events = cpu_pmu->get_hw_events();
...@@ -740,8 +747,7 @@ xscale2pmu_start(void) ...@@ -740,8 +747,7 @@ xscale2pmu_start(void)
raw_spin_unlock_irqrestore(&events->pmu_lock, flags); raw_spin_unlock_irqrestore(&events->pmu_lock, flags);
} }
static void static void xscale2pmu_stop(struct arm_pmu *cpu_pmu)
xscale2pmu_stop(void)
{ {
unsigned long flags, val; unsigned long flags, val;
struct pmu_hw_events *events = cpu_pmu->get_hw_events(); struct pmu_hw_events *events = cpu_pmu->get_hw_events();
...@@ -753,9 +759,10 @@ xscale2pmu_stop(void) ...@@ -753,9 +759,10 @@ xscale2pmu_stop(void)
raw_spin_unlock_irqrestore(&events->pmu_lock, flags); raw_spin_unlock_irqrestore(&events->pmu_lock, flags);
} }
static inline u32 static inline u32 xscale2pmu_read_counter(struct perf_event *event)
xscale2pmu_read_counter(int counter)
{ {
struct hw_perf_event *hwc = &event->hw;
int counter = hwc->idx;
u32 val = 0; u32 val = 0;
switch (counter) { switch (counter) {
...@@ -779,9 +786,11 @@ xscale2pmu_read_counter(int counter) ...@@ -779,9 +786,11 @@ xscale2pmu_read_counter(int counter)
return val; return val;
} }
static inline void static inline void xscale2pmu_write_counter(struct perf_event *event, u32 val)
xscale2pmu_write_counter(int counter, u32 val)
{ {
struct hw_perf_event *hwc = &event->hw;
int counter = hwc->idx;
switch (counter) { switch (counter) {
case XSCALE_CYCLE_COUNTER: case XSCALE_CYCLE_COUNTER:
asm volatile("mcr p14, 0, %0, c1, c1, 0" : : "r" (val)); asm volatile("mcr p14, 0, %0, c1, c1, 0" : : "r" (val));
...@@ -801,33 +810,31 @@ xscale2pmu_write_counter(int counter, u32 val) ...@@ -801,33 +810,31 @@ xscale2pmu_write_counter(int counter, u32 val)
} }
} }
static struct arm_pmu xscale2pmu = { static int __devinit xscale2pmu_init(struct arm_pmu *cpu_pmu)
.name = "xscale2",
.handle_irq = xscale2pmu_handle_irq,
.enable = xscale2pmu_enable_event,
.disable = xscale2pmu_disable_event,
.read_counter = xscale2pmu_read_counter,
.write_counter = xscale2pmu_write_counter,
.get_event_idx = xscale2pmu_get_event_idx,
.start = xscale2pmu_start,
.stop = xscale2pmu_stop,
.map_event = xscale_map_event,
.num_events = 5,
.max_period = (1LLU << 32) - 1,
};
static struct arm_pmu *__devinit xscale2pmu_init(void)
{ {
return &xscale2pmu; cpu_pmu->name = "xscale2";
cpu_pmu->handle_irq = xscale2pmu_handle_irq;
cpu_pmu->enable = xscale2pmu_enable_event;
cpu_pmu->disable = xscale2pmu_disable_event;
cpu_pmu->read_counter = xscale2pmu_read_counter;
cpu_pmu->write_counter = xscale2pmu_write_counter;
cpu_pmu->get_event_idx = xscale2pmu_get_event_idx;
cpu_pmu->start = xscale2pmu_start;
cpu_pmu->stop = xscale2pmu_stop;
cpu_pmu->map_event = xscale_map_event;
cpu_pmu->num_events = 5;
cpu_pmu->max_period = (1LLU << 32) - 1;
return 0;
} }
#else #else
static struct arm_pmu *__devinit xscale1pmu_init(void) static inline int xscale1pmu_init(struct arm_pmu *cpu_pmu)
{ {
return NULL; return -ENODEV;
} }
static struct arm_pmu *__devinit xscale2pmu_init(void) static inline int xscale2pmu_init(struct arm_pmu *cpu_pmu)
{ {
return NULL; return -ENODEV;
} }
#endif /* CONFIG_CPU_XSCALE */ #endif /* CONFIG_CPU_XSCALE */
...@@ -57,8 +57,6 @@ static int __init omap2_init_pmu(unsigned oh_num, char *oh_names[]) ...@@ -57,8 +57,6 @@ static int __init omap2_init_pmu(unsigned oh_num, char *oh_names[])
if (IS_ERR(omap_pmu_dev)) if (IS_ERR(omap_pmu_dev))
return PTR_ERR(omap_pmu_dev); return PTR_ERR(omap_pmu_dev);
pm_runtime_enable(&omap_pmu_dev->dev);
return 0; return 0;
} }
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment