From cb6eb108a7be04709f8db0cedde30bee0e0a64ee Mon Sep 17 00:00:00 2001 From: chai wen Date: Wed, 22 Oct 2014 13:16:49 +0100 Subject: ARM: perf: remove useless return and check of idx in counter handling Idx sanity check was once implemented separately in these counter handling functions and then return value was treated as a judgement. armv7_pmnc_select_counter() armv7_pmnc_enable_counter() armv7_pmnc_disable_counter() armv7_pmnc_enable_intens() armv7_pmnc_disable_intens() But we do not need to do this now, as idx validation check was moved out all these functions by commit 7279adbd9bb8ef8f(ARM: perf: check ARMv7 counter validity on a per-pmu basis). Let's remove the useless return of idx from these functions. Acked-by: Mark Rutland Signed-off-by: chai wen Signed-off-by: Will Deacon --- arch/arm/kernel/perf_event_v7.c | 40 ++++++++++++++++++---------------------- 1 file changed, 18 insertions(+), 22 deletions(-) (limited to 'arch') diff --git a/arch/arm/kernel/perf_event_v7.c b/arch/arm/kernel/perf_event_v7.c index 116758b77f93..aaf5314e8dad 100644 --- a/arch/arm/kernel/perf_event_v7.c +++ b/arch/arm/kernel/perf_event_v7.c @@ -564,13 +564,11 @@ static inline int armv7_pmnc_counter_has_overflowed(u32 pmnc, int idx) return pmnc & BIT(ARMV7_IDX_TO_COUNTER(idx)); } -static inline int armv7_pmnc_select_counter(int idx) +static inline void armv7_pmnc_select_counter(int idx) { u32 counter = ARMV7_IDX_TO_COUNTER(idx); asm volatile("mcr p15, 0, %0, c9, c12, 5" : : "r" (counter)); isb(); - - return idx; } static inline u32 armv7pmu_read_counter(struct perf_event *event) @@ -580,13 +578,15 @@ static inline u32 armv7pmu_read_counter(struct perf_event *event) int idx = hwc->idx; u32 value = 0; - if (!armv7_pmnc_counter_valid(cpu_pmu, idx)) + if (!armv7_pmnc_counter_valid(cpu_pmu, idx)) { pr_err("CPU%u reading wrong counter %d\n", smp_processor_id(), idx); - else if (idx == ARMV7_IDX_CYCLE_COUNTER) + } else if (idx == ARMV7_IDX_CYCLE_COUNTER) { asm volatile("mrc p15, 0, %0, c9, c13, 0" : "=r" (value)); - else if (armv7_pmnc_select_counter(idx) == idx) + } else { + armv7_pmnc_select_counter(idx); asm volatile("mrc p15, 0, %0, c9, c13, 2" : "=r" (value)); + } return value; } @@ -597,45 +597,43 @@ static inline void armv7pmu_write_counter(struct perf_event *event, u32 value) struct hw_perf_event *hwc = &event->hw; int idx = hwc->idx; - if (!armv7_pmnc_counter_valid(cpu_pmu, idx)) + if (!armv7_pmnc_counter_valid(cpu_pmu, idx)) { pr_err("CPU%u writing wrong counter %d\n", smp_processor_id(), idx); - else if (idx == ARMV7_IDX_CYCLE_COUNTER) + } else if (idx == ARMV7_IDX_CYCLE_COUNTER) { asm volatile("mcr p15, 0, %0, c9, c13, 0" : : "r" (value)); - else if (armv7_pmnc_select_counter(idx) == idx) + } else { + armv7_pmnc_select_counter(idx); asm volatile("mcr p15, 0, %0, c9, c13, 2" : : "r" (value)); + } } static inline void armv7_pmnc_write_evtsel(int idx, u32 val) { - if (armv7_pmnc_select_counter(idx) == idx) { - val &= ARMV7_EVTYPE_MASK; - asm volatile("mcr p15, 0, %0, c9, c13, 1" : : "r" (val)); - } + armv7_pmnc_select_counter(idx); + val &= ARMV7_EVTYPE_MASK; + asm volatile("mcr p15, 0, %0, c9, c13, 1" : : "r" (val)); } -static inline int armv7_pmnc_enable_counter(int idx) +static inline void armv7_pmnc_enable_counter(int idx) { u32 counter = ARMV7_IDX_TO_COUNTER(idx); asm volatile("mcr p15, 0, %0, c9, c12, 1" : : "r" (BIT(counter))); - return idx; } -static inline int armv7_pmnc_disable_counter(int idx) +static inline void armv7_pmnc_disable_counter(int idx) { u32 counter = ARMV7_IDX_TO_COUNTER(idx); asm volatile("mcr p15, 0, %0, c9, c12, 2" : : "r" (BIT(counter))); - return idx; } -static inline int armv7_pmnc_enable_intens(int idx) +static inline void armv7_pmnc_enable_intens(int idx) { u32 counter = ARMV7_IDX_TO_COUNTER(idx); asm volatile("mcr p15, 0, %0, c9, c14, 1" : : "r" (BIT(counter))); - return idx; } -static inline int armv7_pmnc_disable_intens(int idx) +static inline void armv7_pmnc_disable_intens(int idx) { u32 counter = ARMV7_IDX_TO_COUNTER(idx); asm volatile("mcr p15, 0, %0, c9, c14, 2" : : "r" (BIT(counter))); @@ -643,8 +641,6 @@ static inline int armv7_pmnc_disable_intens(int idx) /* Clear the overflow flag in case an interrupt is pending. */ asm volatile("mcr p15, 0, %0, c9, c12, 3" : : "r" (BIT(counter))); isb(); - - return idx; } static inline u32 armv7_pmnc_getreset_flags(void) -- cgit v1.2.3 From 52a5566e7617ce2678c2a35c7982b808cb2b53f6 Mon Sep 17 00:00:00 2001 From: Will Deacon Date: Thu, 30 Oct 2014 11:26:57 +0000 Subject: ARM: perf: use pr_* instead of printk There are a few remaining uses of printk in the ARM perf code, so move them over to the pr_* variants instead. Reported-by: Russell King Signed-off-by: Will Deacon --- arch/arm/kernel/perf_event_cpu.c | 2 +- arch/arm/kernel/perf_event_v7.c | 18 +++++++++--------- 2 files changed, 10 insertions(+), 10 deletions(-) (limited to 'arch') diff --git a/arch/arm/kernel/perf_event_cpu.c b/arch/arm/kernel/perf_event_cpu.c index eb2c4d55666b..a5e808f155e1 100644 --- a/arch/arm/kernel/perf_event_cpu.c +++ b/arch/arm/kernel/perf_event_cpu.c @@ -120,7 +120,7 @@ static int cpu_pmu_request_irq(struct arm_pmu *cpu_pmu, irq_handler_t handler) irqs = min(pmu_device->num_resources, num_possible_cpus()); if (irqs < 1) { - printk_once("perf/ARM: No irqs for PMU defined, sampling events not supported\n"); + pr_warn_once("perf/ARM: No irqs for PMU defined, sampling events not supported\n"); return 0; } diff --git a/arch/arm/kernel/perf_event_v7.c b/arch/arm/kernel/perf_event_v7.c index aaf5314e8dad..d62b27ce55e9 100644 --- a/arch/arm/kernel/perf_event_v7.c +++ b/arch/arm/kernel/perf_event_v7.c @@ -663,34 +663,34 @@ static void armv7_pmnc_dump_regs(struct arm_pmu *cpu_pmu) u32 val; unsigned int cnt; - printk(KERN_INFO "PMNC registers dump:\n"); + pr_info("PMNC registers dump:\n"); asm volatile("mrc p15, 0, %0, c9, c12, 0" : "=r" (val)); - printk(KERN_INFO "PMNC =0x%08x\n", val); + pr_info("PMNC =0x%08x\n", val); asm volatile("mrc p15, 0, %0, c9, c12, 1" : "=r" (val)); - printk(KERN_INFO "CNTENS=0x%08x\n", val); + pr_info("CNTENS=0x%08x\n", val); asm volatile("mrc p15, 0, %0, c9, c14, 1" : "=r" (val)); - printk(KERN_INFO "INTENS=0x%08x\n", val); + pr_info("INTENS=0x%08x\n", val); asm volatile("mrc p15, 0, %0, c9, c12, 3" : "=r" (val)); - printk(KERN_INFO "FLAGS =0x%08x\n", val); + pr_info("FLAGS =0x%08x\n", val); asm volatile("mrc p15, 0, %0, c9, c12, 5" : "=r" (val)); - printk(KERN_INFO "SELECT=0x%08x\n", val); + pr_info("SELECT=0x%08x\n", val); asm volatile("mrc p15, 0, %0, c9, c13, 0" : "=r" (val)); - printk(KERN_INFO "CCNT =0x%08x\n", val); + pr_info("CCNT =0x%08x\n", val); for (cnt = ARMV7_IDX_COUNTER0; cnt <= ARMV7_IDX_COUNTER_LAST(cpu_pmu); cnt++) { armv7_pmnc_select_counter(cnt); asm volatile("mrc p15, 0, %0, c9, c13, 2" : "=r" (val)); - printk(KERN_INFO "CNT[%d] count =0x%08x\n", + pr_info("CNT[%d] count =0x%08x\n", ARMV7_IDX_TO_COUNTER(cnt), val); asm volatile("mrc p15, 0, %0, c9, c13, 1" : "=r" (val)); - printk(KERN_INFO "CNT[%d] evtsel=0x%08x\n", + pr_info("CNT[%d] evtsel=0x%08x\n", ARMV7_IDX_TO_COUNTER(cnt), val); } } -- cgit v1.2.3 From d39976f0fd144d1cef4830d696e2a1e6d8058dc6 Mon Sep 17 00:00:00 2001 From: Mark Rutland Date: Mon, 29 Sep 2014 17:15:32 +0100 Subject: arm: perf: factor out callchain code The ARM callchain handling code is currently bundled with the ARM PMU management code, despite the two having no dependency on each other. This bundling has the unfortunate property of making callchain handling depend on CONFIG_HW_PERF_EVENTS, even though the callchain handling could be applied to software events in the absence of PMU hardware support. This patch separates the two, placing the callchain handling in perf_callchain.c and making it depend on CONFIG_PERF_EVENTS rather than CONFIG_HW_PERF_EVENTS, enabling callchain recording on kernels built without hardware perf event support. Signed-off-by: Mark Rutland Reviewed-by: Will Deacon Signed-off-by: Will Deacon --- arch/arm/include/asm/perf_event.h | 2 +- arch/arm/kernel/Makefile | 2 +- arch/arm/kernel/perf_callchain.c | 136 ++++++++++++++++++++++++++++++++++++++ arch/arm/kernel/perf_event.c | 132 +----------------------------------- 4 files changed, 139 insertions(+), 133 deletions(-) create mode 100644 arch/arm/kernel/perf_callchain.c (limited to 'arch') diff --git a/arch/arm/include/asm/perf_event.h b/arch/arm/include/asm/perf_event.h index c3a83691af8e..d9cf138fd7d4 100644 --- a/arch/arm/include/asm/perf_event.h +++ b/arch/arm/include/asm/perf_event.h @@ -12,7 +12,7 @@ #ifndef __ARM_PERF_EVENT_H__ #define __ARM_PERF_EVENT_H__ -#ifdef CONFIG_HW_PERF_EVENTS +#ifdef CONFIG_PERF_EVENTS struct pt_regs; extern unsigned long perf_instruction_pointer(struct pt_regs *regs); extern unsigned long perf_misc_flags(struct pt_regs *regs); diff --git a/arch/arm/kernel/Makefile b/arch/arm/kernel/Makefile index 38ddd9f83d0e..8dcbed5016ac 100644 --- a/arch/arm/kernel/Makefile +++ b/arch/arm/kernel/Makefile @@ -82,7 +82,7 @@ obj-$(CONFIG_CPU_MOHAWK) += xscale-cp0.o obj-$(CONFIG_CPU_PJ4) += pj4-cp0.o obj-$(CONFIG_CPU_PJ4B) += pj4-cp0.o obj-$(CONFIG_IWMMXT) += iwmmxt.o -obj-$(CONFIG_PERF_EVENTS) += perf_regs.o +obj-$(CONFIG_PERF_EVENTS) += perf_regs.o perf_callchain.o obj-$(CONFIG_HW_PERF_EVENTS) += perf_event.o perf_event_cpu.o AFLAGS_iwmmxt.o := -Wa,-mcpu=iwmmxt obj-$(CONFIG_ARM_CPU_TOPOLOGY) += topology.o diff --git a/arch/arm/kernel/perf_callchain.c b/arch/arm/kernel/perf_callchain.c new file mode 100644 index 000000000000..4e02ae5950ff --- /dev/null +++ b/arch/arm/kernel/perf_callchain.c @@ -0,0 +1,136 @@ +/* + * ARM callchain support + * + * Copyright (C) 2009 picoChip Designs, Ltd., Jamie Iles + * Copyright (C) 2010 ARM Ltd., Will Deacon + * + * This code is based on the ARM OProfile backtrace code. + */ +#include +#include + +#include + +/* + * The registers we're interested in are at the end of the variable + * length saved register structure. The fp points at the end of this + * structure so the address of this struct is: + * (struct frame_tail *)(xxx->fp)-1 + * + * This code has been adapted from the ARM OProfile support. + */ +struct frame_tail { + struct frame_tail __user *fp; + unsigned long sp; + unsigned long lr; +} __attribute__((packed)); + +/* + * Get the return address for a single stackframe and return a pointer to the + * next frame tail. + */ +static struct frame_tail __user * +user_backtrace(struct frame_tail __user *tail, + struct perf_callchain_entry *entry) +{ + struct frame_tail buftail; + unsigned long err; + + if (!access_ok(VERIFY_READ, tail, sizeof(buftail))) + return NULL; + + pagefault_disable(); + err = __copy_from_user_inatomic(&buftail, tail, sizeof(buftail)); + pagefault_enable(); + + if (err) + return NULL; + + perf_callchain_store(entry, buftail.lr); + + /* + * Frame pointers should strictly progress back up the stack + * (towards higher addresses). + */ + if (tail + 1 >= buftail.fp) + return NULL; + + return buftail.fp - 1; +} + +void +perf_callchain_user(struct perf_callchain_entry *entry, struct pt_regs *regs) +{ + struct frame_tail __user *tail; + + if (perf_guest_cbs && perf_guest_cbs->is_in_guest()) { + /* We don't support guest os callchain now */ + return; + } + + perf_callchain_store(entry, regs->ARM_pc); + + if (!current->mm) + return; + + tail = (struct frame_tail __user *)regs->ARM_fp - 1; + + while ((entry->nr < PERF_MAX_STACK_DEPTH) && + tail && !((unsigned long)tail & 0x3)) + tail = user_backtrace(tail, entry); +} + +/* + * Gets called by walk_stackframe() for every stackframe. This will be called + * whist unwinding the stackframe and is like a subroutine return so we use + * the PC. + */ +static int +callchain_trace(struct stackframe *fr, + void *data) +{ + struct perf_callchain_entry *entry = data; + perf_callchain_store(entry, fr->pc); + return 0; +} + +void +perf_callchain_kernel(struct perf_callchain_entry *entry, struct pt_regs *regs) +{ + struct stackframe fr; + + if (perf_guest_cbs && perf_guest_cbs->is_in_guest()) { + /* We don't support guest os callchain now */ + return; + } + + arm_get_current_stackframe(regs, &fr); + 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; +} diff --git a/arch/arm/kernel/perf_event.c b/arch/arm/kernel/perf_event.c index 266cba46db3e..ae96b986d50f 100644 --- a/arch/arm/kernel/perf_event.c +++ b/arch/arm/kernel/perf_event.c @@ -7,21 +7,18 @@ * Copyright (C) 2010 ARM Ltd., Will Deacon * * This code is based on the sparc64 perf event code, which is in turn based - * on the x86 code. Callchain code is based on the ARM OProfile backtrace - * code. + * on the x86 code. */ #define pr_fmt(fmt) "hw perfevents: " fmt #include #include #include -#include #include #include #include #include -#include static int armpmu_map_cache_event(const unsigned (*cache_map) @@ -533,130 +530,3 @@ int armpmu_register(struct arm_pmu *armpmu, int type) return perf_pmu_register(&armpmu->pmu, armpmu->name, type); } -/* - * Callchain handling code. - */ - -/* - * The registers we're interested in are at the end of the variable - * length saved register structure. The fp points at the end of this - * structure so the address of this struct is: - * (struct frame_tail *)(xxx->fp)-1 - * - * This code has been adapted from the ARM OProfile support. - */ -struct frame_tail { - struct frame_tail __user *fp; - unsigned long sp; - unsigned long lr; -} __attribute__((packed)); - -/* - * Get the return address for a single stackframe and return a pointer to the - * next frame tail. - */ -static struct frame_tail __user * -user_backtrace(struct frame_tail __user *tail, - struct perf_callchain_entry *entry) -{ - struct frame_tail buftail; - unsigned long err; - - if (!access_ok(VERIFY_READ, tail, sizeof(buftail))) - return NULL; - - pagefault_disable(); - err = __copy_from_user_inatomic(&buftail, tail, sizeof(buftail)); - pagefault_enable(); - - if (err) - return NULL; - - perf_callchain_store(entry, buftail.lr); - - /* - * Frame pointers should strictly progress back up the stack - * (towards higher addresses). - */ - if (tail + 1 >= buftail.fp) - return NULL; - - return buftail.fp - 1; -} - -void -perf_callchain_user(struct perf_callchain_entry *entry, struct pt_regs *regs) -{ - struct frame_tail __user *tail; - - if (perf_guest_cbs && perf_guest_cbs->is_in_guest()) { - /* We don't support guest os callchain now */ - return; - } - - perf_callchain_store(entry, regs->ARM_pc); - - if (!current->mm) - return; - - tail = (struct frame_tail __user *)regs->ARM_fp - 1; - - while ((entry->nr < PERF_MAX_STACK_DEPTH) && - tail && !((unsigned long)tail & 0x3)) - tail = user_backtrace(tail, entry); -} - -/* - * Gets called by walk_stackframe() for every stackframe. This will be called - * whist unwinding the stackframe and is like a subroutine return so we use - * the PC. - */ -static int -callchain_trace(struct stackframe *fr, - void *data) -{ - struct perf_callchain_entry *entry = data; - perf_callchain_store(entry, fr->pc); - return 0; -} - -void -perf_callchain_kernel(struct perf_callchain_entry *entry, struct pt_regs *regs) -{ - struct stackframe fr; - - if (perf_guest_cbs && perf_guest_cbs->is_in_guest()) { - /* We don't support guest os callchain now */ - return; - } - - arm_get_current_stackframe(regs, &fr); - 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; -} -- cgit v1.2.3 From 0f2a21018a71d8d3fec507f9c55ae8ed03ab9321 Mon Sep 17 00:00:00 2001 From: Mark Rutland Date: Thu, 23 Oct 2014 15:59:35 +0100 Subject: arm: perf: add missing pr_info newlines Most of the pr_info format strings in perf_event_cpu.c are missing newlines. Currently we get away with this as the format strings for subsequent calls to printk (including all pr_* calls) begin with a log prefix, and the printk core adds the omitted newline for this case. While generates the output we expect, we probably should not rely on the format of successive printk calls in order to get legible output. This patch adds the missing newlines to pr_info format strings in perf_event_cpu.c, making them consistent with the format strings for other pr_info, warn, and pr_err calls, and preventing potentially illegible output if the next printk/pr_* format string doesn't begin with a log prefix. Signed-off-by: Mark Rutland Reviewed-by: Stephen Boyd Signed-off-by: Will Deacon --- arch/arm/kernel/perf_event_cpu.c | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) (limited to 'arch') diff --git a/arch/arm/kernel/perf_event_cpu.c b/arch/arm/kernel/perf_event_cpu.c index a5e808f155e1..8ba23ad22113 100644 --- a/arch/arm/kernel/perf_event_cpu.c +++ b/arch/arm/kernel/perf_event_cpu.c @@ -299,13 +299,13 @@ static int cpu_pmu_device_probe(struct platform_device *pdev) int ret = -ENODEV; if (cpu_pmu) { - pr_info("attempt to register multiple PMU devices!"); + pr_info("attempt to register multiple PMU devices!\n"); return -ENOSPC; } pmu = kzalloc(sizeof(struct arm_pmu), GFP_KERNEL); if (!pmu) { - pr_info("failed to allocate PMU device!"); + pr_info("failed to allocate PMU device!\n"); return -ENOMEM; } @@ -320,7 +320,7 @@ static int cpu_pmu_device_probe(struct platform_device *pdev) } if (ret) { - pr_info("failed to probe PMU!"); + pr_info("failed to probe PMU!\n"); goto out_free; } @@ -331,7 +331,7 @@ static int cpu_pmu_device_probe(struct platform_device *pdev) return 0; out_free: - pr_info("failed to register PMU devices!"); + pr_info("failed to register PMU devices!\n"); kfree(pmu); return ret; } -- cgit v1.2.3 From 548a86cae4858433cab7e101bca2c6856ab55887 Mon Sep 17 00:00:00 2001 From: Mark Rutland Date: Fri, 23 May 2014 18:11:14 +0100 Subject: arm: perf: make PMU probing data-driven The current PMU probing logic consists of a single switch statement, which means that the core arm_pmu core in perf_event_cpu.c needs to know about every CPU PMU variant supported by a driver using the arm_pmu framework. This makes it rather difficult to decouple the drivers from the (otherwise generic) probing code. The patch refactors that switch statement to a table-driven lookup, separating the logic and knowledge (in the form of the table). Later patches will split the table across the relevant PMU drivers, which can pass their tables to the generic probing function. Signed-off-by: Mark Rutland Reviewed-by: Will Deacon Reviewed-by: Stephen Boyd Signed-off-by: Will Deacon --- arch/arm/include/asm/pmu.h | 23 ++++++++++++++++++ arch/arm/kernel/perf_event_cpu.c | 50 +++++++++++++++------------------------- 2 files changed, 41 insertions(+), 32 deletions(-) (limited to 'arch') diff --git a/arch/arm/include/asm/pmu.h b/arch/arm/include/asm/pmu.h index 0b648c541293..ff39290965af 100644 --- a/arch/arm/include/asm/pmu.h +++ b/arch/arm/include/asm/pmu.h @@ -15,6 +15,8 @@ #include #include +#include + /* * struct arm_pmu_platdata - ARM PMU platform data * @@ -127,6 +129,27 @@ int armpmu_map_event(struct perf_event *event, [PERF_COUNT_HW_CACHE_RESULT_MAX], u32 raw_event_mask); +struct pmu_probe_info { + unsigned int cpuid; + unsigned int mask; + int (*init)(struct arm_pmu *); +}; + +#define PMU_PROBE(_cpuid, _mask, _fn) \ +{ \ + .cpuid = (_cpuid), \ + .mask = (_mask), \ + .init = (_fn), \ +} + +#define ARM_PMU_PROBE(_cpuid, _fn) \ + PMU_PROBE(_cpuid, ARM_CPU_PART_MASK, _fn) + +#define ARM_PMU_XSCALE_MASK ((0xff << 24) | ARM_CPU_XSCALE_ARCH_MASK) + +#define XSCALE_PMU_PROBE(_version, _fn) \ + PMU_PROBE(ARM_CPU_IMP_INTEL << 24 | _version, ARM_PMU_XSCALE_MASK, _fn) + #endif /* CONFIG_HW_PERF_EVENTS */ #endif /* __ARM_PMU_H__ */ diff --git a/arch/arm/kernel/perf_event_cpu.c b/arch/arm/kernel/perf_event_cpu.c index 8ba23ad22113..e7d265210f27 100644 --- a/arch/arm/kernel/perf_event_cpu.c +++ b/arch/arm/kernel/perf_event_cpu.c @@ -241,48 +241,34 @@ static struct platform_device_id cpu_pmu_plat_device_ids[] = { {}, }; +static const struct pmu_probe_info pmu_probe_table[] = { + ARM_PMU_PROBE(ARM_CPU_PART_ARM1136, armv6_1136_pmu_init), + ARM_PMU_PROBE(ARM_CPU_PART_ARM1156, armv6_1156_pmu_init), + ARM_PMU_PROBE(ARM_CPU_PART_ARM1176, armv6_1176_pmu_init), + ARM_PMU_PROBE(ARM_CPU_PART_ARM11MPCORE, armv6mpcore_pmu_init), + ARM_PMU_PROBE(ARM_CPU_PART_CORTEX_A8, armv7_a8_pmu_init), + ARM_PMU_PROBE(ARM_CPU_PART_CORTEX_A9, armv7_a9_pmu_init), + XSCALE_PMU_PROBE(ARM_CPU_XSCALE_ARCH_V1, xscale1pmu_init), + XSCALE_PMU_PROBE(ARM_CPU_XSCALE_ARCH_V2, xscale2pmu_init), + { /* sentinel value */ } +}; + /* * CPU PMU identification and probing. */ static int probe_current_pmu(struct arm_pmu *pmu) { int cpu = get_cpu(); + unsigned int cpuid = read_cpuid_id(); int ret = -ENODEV; + const struct pmu_probe_info *info; pr_info("probing PMU on CPU %d\n", cpu); - switch (read_cpuid_part()) { - /* ARM Ltd CPUs. */ - case ARM_CPU_PART_ARM1136: - ret = armv6_1136_pmu_init(pmu); - break; - case ARM_CPU_PART_ARM1156: - ret = armv6_1156_pmu_init(pmu); - break; - case ARM_CPU_PART_ARM1176: - ret = armv6_1176_pmu_init(pmu); - break; - case ARM_CPU_PART_ARM11MPCORE: - ret = armv6mpcore_pmu_init(pmu); - break; - case ARM_CPU_PART_CORTEX_A8: - ret = armv7_a8_pmu_init(pmu); - break; - case ARM_CPU_PART_CORTEX_A9: - ret = armv7_a9_pmu_init(pmu); - break; - - default: - if (read_cpuid_implementor() == ARM_CPU_IMP_INTEL) { - switch (xscale_cpu_arch_version()) { - case ARM_CPU_XSCALE_ARCH_V1: - ret = xscale1pmu_init(pmu); - break; - case ARM_CPU_XSCALE_ARCH_V2: - ret = xscale2pmu_init(pmu); - break; - } - } + for (info = pmu_probe_table; info->init != NULL; info++) { + if ((cpuid & info->mask) != info->cpuid) + continue; + ret = info->init(pmu); break; } -- cgit v1.2.3 From 67b4305aab0fa993d91fa4c6ea2169cfb3f41c93 Mon Sep 17 00:00:00 2001 From: Mark Rutland Date: Wed, 12 Sep 2012 10:53:23 +0100 Subject: arm: perf: use IDR types for CPU PMUs For systems with heterogeneous CPUs (e.g. big.LITTLE systems) the PMUs can be different in each cluster, and not all events can be migrated between clusters. To allow userspace to deal with this, it must be possible to address each PMU independently. This patch changes PMUs to be registered with dynamic (IDR) types, allowing them to be targeted individually. Each PMU's type can be found in ${SYSFS_ROOT}/bus/event_source/devices/${PMU_NAME}/type. From userspace, raw events can be targeted at a specific PMU: $ perf stat -e ${PMU_NAME}/config=V,config1=V1,.../ Doing this does not break existing tools which use existing perf types: when perf core can't find a PMU of matching type (in perf_init_event) it'll iterate over the set of all PMUs. If a compatible PMU exists, it'll be found eventually. If more than one compatible PMU exists, the event will be handled by whichever PMU happens to be earlier in the pmus list (which currently will be the last compatible PMU registered). Signed-off-by: Mark Rutland Reviewed-by: Will Deacon Signed-off-by: Will Deacon --- arch/arm/kernel/perf_event.c | 6 +++++- arch/arm/kernel/perf_event_cpu.c | 2 +- 2 files changed, 6 insertions(+), 2 deletions(-) (limited to 'arch') diff --git a/arch/arm/kernel/perf_event.c b/arch/arm/kernel/perf_event.c index ae96b986d50f..7ffb267fb628 100644 --- a/arch/arm/kernel/perf_event.c +++ b/arch/arm/kernel/perf_event.c @@ -77,8 +77,12 @@ armpmu_map_event(struct perf_event *event, u32 raw_event_mask) { u64 config = event->attr.config; + int type = event->attr.type; - switch (event->attr.type) { + if (type == event->pmu->type) + return armpmu_map_raw_event(raw_event_mask, config); + + switch (type) { case PERF_TYPE_HARDWARE: return armpmu_map_hw_event(event_map, config); case PERF_TYPE_HW_CACHE: diff --git a/arch/arm/kernel/perf_event_cpu.c b/arch/arm/kernel/perf_event_cpu.c index e7d265210f27..7677d73cccc8 100644 --- a/arch/arm/kernel/perf_event_cpu.c +++ b/arch/arm/kernel/perf_event_cpu.c @@ -311,7 +311,7 @@ static int cpu_pmu_device_probe(struct platform_device *pdev) } cpu_pmu_init(cpu_pmu); - ret = armpmu_register(cpu_pmu, PERF_TYPE_RAW); + ret = armpmu_register(cpu_pmu, -1); if (!ret) return 0; -- cgit v1.2.3 From a4560846eba60830a444d9e336c8a18f92e099ee Mon Sep 17 00:00:00 2001 From: Mark Rutland Date: Tue, 13 May 2014 19:08:19 +0100 Subject: arm: perf: limit size of accounting data Commit 3fc2c83087 (ARM: perf: remove event limit from pmu_hw_events) got rid of the upper limit on the number of events an arm_pmu could handle, but introduced additional complexity and places a burden on each PMU driver to allocate accounting data somehow. So far this has not generally been useful as the only users of arm_pmu are the CPU backend and the CCI driver. Now that the CCI driver plugs into the perf subsystem directly, we can remove some of the complexities that get in the way of supporting heterogeneous CPU PMUs. This patch restores the original limits on pmu_hw_events fields such that the pmu_hw_events data can be allocated as a contiguous block. This will simplify dynamic pmu_hw_events allocation in later patches. Signed-off-by: Mark Rutland Reviewed-by: Will Deacon Reviewed-by: Stephen Boyd Tested-by: Stephen Boyd Signed-off-by: Will Deacon --- arch/arm/include/asm/pmu.h | 4 ++-- arch/arm/kernel/perf_event.c | 4 +--- arch/arm/kernel/perf_event_cpu.c | 4 ---- 3 files changed, 3 insertions(+), 9 deletions(-) (limited to 'arch') diff --git a/arch/arm/include/asm/pmu.h b/arch/arm/include/asm/pmu.h index ff39290965af..3d7e30bc9ffb 100644 --- a/arch/arm/include/asm/pmu.h +++ b/arch/arm/include/asm/pmu.h @@ -68,13 +68,13 @@ struct pmu_hw_events { /* * The events that are active on the PMU for the given index. */ - struct perf_event **events; + 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; + DECLARE_BITMAP(used_mask, ARMPMU_MAX_HWEVENTS); /* * Hardware lock to serialize accesses to PMU registers. Needed for the diff --git a/arch/arm/kernel/perf_event.c b/arch/arm/kernel/perf_event.c index 7ffb267fb628..864810713cfc 100644 --- a/arch/arm/kernel/perf_event.c +++ b/arch/arm/kernel/perf_event.c @@ -275,14 +275,12 @@ validate_group(struct perf_event *event) { struct perf_event *sibling, *leader = event->group_leader; struct pmu_hw_events fake_pmu; - DECLARE_BITMAP(fake_used_mask, ARMPMU_MAX_HWEVENTS); /* * Initialise the fake PMU. We only need to populate the * used_mask for the purposes of validation. */ - memset(fake_used_mask, 0, sizeof(fake_used_mask)); - fake_pmu.used_mask = fake_used_mask; + memset(&fake_pmu.used_mask, 0, sizeof(fake_pmu.used_mask)); if (!validate_event(&fake_pmu, leader)) return -EINVAL; diff --git a/arch/arm/kernel/perf_event_cpu.c b/arch/arm/kernel/perf_event_cpu.c index 7677d73cccc8..28d04642fa33 100644 --- a/arch/arm/kernel/perf_event_cpu.c +++ b/arch/arm/kernel/perf_event_cpu.c @@ -36,8 +36,6 @@ static struct arm_pmu *cpu_pmu; static DEFINE_PER_CPU(struct arm_pmu *, percpu_pmu); -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); /* @@ -172,8 +170,6 @@ static void cpu_pmu_init(struct arm_pmu *cpu_pmu) int cpu; for_each_possible_cpu(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); per_cpu(percpu_pmu, cpu) = cpu_pmu; } -- cgit v1.2.3 From 116792508607002896b706fbad8310419fcc5742 Mon Sep 17 00:00:00 2001 From: Mark Rutland Date: Tue, 13 May 2014 19:36:31 +0100 Subject: arm: perf: kill get_hw_events() Now that the arm pmu code is limited to CPU PMUs the get_hw_events() function is superfluous, as we'll always have a set of per-cpu pmu_hw_events structures. This patch removes the get_hw_events() function, replacing it with a percpu hw_events pointer. Uses of get_hw_events are updated to use this_cpu_ptr. Signed-off-by: Mark Rutland Reviewed-by: Will Deacon Reviewed-by: Stephen Boyd Signed-off-by: Will Deacon --- arch/arm/include/asm/pmu.h | 2 +- arch/arm/kernel/perf_event.c | 6 +++--- arch/arm/kernel/perf_event_cpu.c | 7 +------ arch/arm/kernel/perf_event_v6.c | 12 ++++++------ arch/arm/kernel/perf_event_v7.c | 14 +++++++------- arch/arm/kernel/perf_event_xscale.c | 20 ++++++++++---------- 6 files changed, 28 insertions(+), 33 deletions(-) (limited to 'arch') diff --git a/arch/arm/include/asm/pmu.h b/arch/arm/include/asm/pmu.h index 3d7e30bc9ffb..f273dd2285a1 100644 --- a/arch/arm/include/asm/pmu.h +++ b/arch/arm/include/asm/pmu.h @@ -109,7 +109,7 @@ struct arm_pmu { struct mutex reserve_mutex; u64 max_period; struct platform_device *plat_device; - struct pmu_hw_events *(*get_hw_events)(void); + struct pmu_hw_events __percpu *hw_events; }; #define to_arm_pmu(p) (container_of(p, struct arm_pmu, pmu)) diff --git a/arch/arm/kernel/perf_event.c b/arch/arm/kernel/perf_event.c index 864810713cfc..05ac5ee6e2bb 100644 --- a/arch/arm/kernel/perf_event.c +++ b/arch/arm/kernel/perf_event.c @@ -201,7 +201,7 @@ static void armpmu_del(struct perf_event *event, int flags) { struct arm_pmu *armpmu = to_arm_pmu(event->pmu); - struct pmu_hw_events *hw_events = armpmu->get_hw_events(); + struct pmu_hw_events *hw_events = this_cpu_ptr(armpmu->hw_events); struct hw_perf_event *hwc = &event->hw; int idx = hwc->idx; @@ -218,7 +218,7 @@ static int armpmu_add(struct perf_event *event, int flags) { struct arm_pmu *armpmu = to_arm_pmu(event->pmu); - struct pmu_hw_events *hw_events = armpmu->get_hw_events(); + struct pmu_hw_events *hw_events = this_cpu_ptr(armpmu->hw_events); struct hw_perf_event *hwc = &event->hw; int idx; int err = 0; @@ -467,7 +467,7 @@ static int armpmu_event_init(struct perf_event *event) static void armpmu_enable(struct pmu *pmu) { struct arm_pmu *armpmu = to_arm_pmu(pmu); - struct pmu_hw_events *hw_events = armpmu->get_hw_events(); + struct pmu_hw_events *hw_events = this_cpu_ptr(armpmu->hw_events); int enabled = bitmap_weight(hw_events->used_mask, armpmu->num_events); if (enabled) diff --git a/arch/arm/kernel/perf_event_cpu.c b/arch/arm/kernel/perf_event_cpu.c index 28d04642fa33..fd24ad84dba6 100644 --- a/arch/arm/kernel/perf_event_cpu.c +++ b/arch/arm/kernel/perf_event_cpu.c @@ -67,11 +67,6 @@ EXPORT_SYMBOL_GPL(perf_num_counters); #include "perf_event_v6.c" #include "perf_event_v7.c" -static struct pmu_hw_events *cpu_pmu_get_cpu_events(void) -{ - return this_cpu_ptr(&cpu_hw_events); -} - static void cpu_pmu_enable_percpu_irq(void *data) { int irq = *(int *)data; @@ -174,7 +169,7 @@ static void cpu_pmu_init(struct arm_pmu *cpu_pmu) per_cpu(percpu_pmu, cpu) = cpu_pmu; } - cpu_pmu->get_hw_events = cpu_pmu_get_cpu_events; + cpu_pmu->hw_events = &cpu_hw_events; cpu_pmu->request_irq = cpu_pmu_request_irq; cpu_pmu->free_irq = cpu_pmu_free_irq; diff --git a/arch/arm/kernel/perf_event_v6.c b/arch/arm/kernel/perf_event_v6.c index abfeb04f3213..f2ffd5c542ed 100644 --- a/arch/arm/kernel/perf_event_v6.c +++ b/arch/arm/kernel/perf_event_v6.c @@ -262,7 +262,7 @@ static void armv6pmu_enable_event(struct perf_event *event) 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 = this_cpu_ptr(cpu_pmu->hw_events); int idx = hwc->idx; if (ARMV6_CYCLE_COUNTER == idx) { @@ -300,7 +300,7 @@ armv6pmu_handle_irq(int irq_num, unsigned long pmcr = armv6_pmcr_read(); struct perf_sample_data data; struct arm_pmu *cpu_pmu = (struct arm_pmu *)dev; - struct pmu_hw_events *cpuc = cpu_pmu->get_hw_events(); + struct pmu_hw_events *cpuc = this_cpu_ptr(cpu_pmu->hw_events); struct pt_regs *regs; int idx; @@ -356,7 +356,7 @@ armv6pmu_handle_irq(int irq_num, static void armv6pmu_start(struct arm_pmu *cpu_pmu) { unsigned long flags, val; - struct pmu_hw_events *events = cpu_pmu->get_hw_events(); + struct pmu_hw_events *events = this_cpu_ptr(cpu_pmu->hw_events); raw_spin_lock_irqsave(&events->pmu_lock, flags); val = armv6_pmcr_read(); @@ -368,7 +368,7 @@ static void armv6pmu_start(struct arm_pmu *cpu_pmu) static void armv6pmu_stop(struct arm_pmu *cpu_pmu) { unsigned long flags, val; - struct pmu_hw_events *events = cpu_pmu->get_hw_events(); + struct pmu_hw_events *events = this_cpu_ptr(cpu_pmu->hw_events); raw_spin_lock_irqsave(&events->pmu_lock, flags); val = armv6_pmcr_read(); @@ -409,7 +409,7 @@ static void armv6pmu_disable_event(struct perf_event *event) 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 = this_cpu_ptr(cpu_pmu->hw_events); int idx = hwc->idx; if (ARMV6_CYCLE_COUNTER == idx) { @@ -444,7 +444,7 @@ static void armv6mpcore_pmu_disable_event(struct perf_event *event) 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 = this_cpu_ptr(cpu_pmu->hw_events); int idx = hwc->idx; if (ARMV6_CYCLE_COUNTER == idx) { diff --git a/arch/arm/kernel/perf_event_v7.c b/arch/arm/kernel/perf_event_v7.c index d62b27ce55e9..8993770c47de 100644 --- a/arch/arm/kernel/perf_event_v7.c +++ b/arch/arm/kernel/perf_event_v7.c @@ -701,7 +701,7 @@ static void armv7pmu_enable_event(struct perf_event *event) 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 = this_cpu_ptr(cpu_pmu->hw_events); int idx = hwc->idx; if (!armv7_pmnc_counter_valid(cpu_pmu, idx)) { @@ -747,7 +747,7 @@ static void armv7pmu_disable_event(struct perf_event *event) 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 = this_cpu_ptr(cpu_pmu->hw_events); int idx = hwc->idx; if (!armv7_pmnc_counter_valid(cpu_pmu, idx)) { @@ -779,7 +779,7 @@ static irqreturn_t armv7pmu_handle_irq(int irq_num, void *dev) u32 pmnc; struct perf_sample_data data; struct arm_pmu *cpu_pmu = (struct arm_pmu *)dev; - struct pmu_hw_events *cpuc = cpu_pmu->get_hw_events(); + struct pmu_hw_events *cpuc = this_cpu_ptr(cpu_pmu->hw_events); struct pt_regs *regs; int idx; @@ -839,7 +839,7 @@ static irqreturn_t armv7pmu_handle_irq(int irq_num, void *dev) static void armv7pmu_start(struct arm_pmu *cpu_pmu) { unsigned long flags; - struct pmu_hw_events *events = cpu_pmu->get_hw_events(); + struct pmu_hw_events *events = this_cpu_ptr(cpu_pmu->hw_events); raw_spin_lock_irqsave(&events->pmu_lock, flags); /* Enable all counters */ @@ -850,7 +850,7 @@ static void armv7pmu_start(struct arm_pmu *cpu_pmu) static void armv7pmu_stop(struct arm_pmu *cpu_pmu) { unsigned long flags; - struct pmu_hw_events *events = cpu_pmu->get_hw_events(); + struct pmu_hw_events *events = this_cpu_ptr(cpu_pmu->hw_events); raw_spin_lock_irqsave(&events->pmu_lock, flags); /* Disable all counters */ @@ -1283,7 +1283,7 @@ static void krait_pmu_disable_event(struct perf_event *event) struct hw_perf_event *hwc = &event->hw; int idx = hwc->idx; 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 = this_cpu_ptr(cpu_pmu->hw_events); /* Disable counter and interrupt */ raw_spin_lock_irqsave(&events->pmu_lock, flags); @@ -1309,7 +1309,7 @@ static void krait_pmu_enable_event(struct perf_event *event) struct hw_perf_event *hwc = &event->hw; int idx = hwc->idx; 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 = this_cpu_ptr(cpu_pmu->hw_events); /* * Enable counter and interrupt, and set the counter to count diff --git a/arch/arm/kernel/perf_event_xscale.c b/arch/arm/kernel/perf_event_xscale.c index 08da0af550b7..8af9f1f82c68 100644 --- a/arch/arm/kernel/perf_event_xscale.c +++ b/arch/arm/kernel/perf_event_xscale.c @@ -138,7 +138,7 @@ xscale1pmu_handle_irq(int irq_num, void *dev) unsigned long pmnc; struct perf_sample_data data; struct arm_pmu *cpu_pmu = (struct arm_pmu *)dev; - struct pmu_hw_events *cpuc = cpu_pmu->get_hw_events(); + struct pmu_hw_events *cpuc = this_cpu_ptr(cpu_pmu->hw_events); struct pt_regs *regs; int idx; @@ -198,7 +198,7 @@ static void xscale1pmu_enable_event(struct perf_event *event) 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 = this_cpu_ptr(cpu_pmu->hw_events); int idx = hwc->idx; switch (idx) { @@ -234,7 +234,7 @@ static void xscale1pmu_disable_event(struct perf_event *event) 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 = this_cpu_ptr(cpu_pmu->hw_events); int idx = hwc->idx; switch (idx) { @@ -287,7 +287,7 @@ xscale1pmu_get_event_idx(struct pmu_hw_events *cpuc, static void xscale1pmu_start(struct arm_pmu *cpu_pmu) { unsigned long flags, val; - struct pmu_hw_events *events = cpu_pmu->get_hw_events(); + struct pmu_hw_events *events = this_cpu_ptr(cpu_pmu->hw_events); raw_spin_lock_irqsave(&events->pmu_lock, flags); val = xscale1pmu_read_pmnc(); @@ -299,7 +299,7 @@ static void xscale1pmu_start(struct arm_pmu *cpu_pmu) static void xscale1pmu_stop(struct arm_pmu *cpu_pmu) { unsigned long flags, val; - struct pmu_hw_events *events = cpu_pmu->get_hw_events(); + struct pmu_hw_events *events = this_cpu_ptr(cpu_pmu->hw_events); raw_spin_lock_irqsave(&events->pmu_lock, flags); val = xscale1pmu_read_pmnc(); @@ -485,7 +485,7 @@ xscale2pmu_handle_irq(int irq_num, void *dev) unsigned long pmnc, of_flags; struct perf_sample_data data; struct arm_pmu *cpu_pmu = (struct arm_pmu *)dev; - struct pmu_hw_events *cpuc = cpu_pmu->get_hw_events(); + struct pmu_hw_events *cpuc = this_cpu_ptr(cpu_pmu->hw_events); struct pt_regs *regs; int idx; @@ -539,7 +539,7 @@ static void xscale2pmu_enable_event(struct perf_event *event) 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 = this_cpu_ptr(cpu_pmu->hw_events); int idx = hwc->idx; ien = xscale2pmu_read_int_enable(); @@ -585,7 +585,7 @@ static void xscale2pmu_disable_event(struct perf_event *event) 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 = this_cpu_ptr(cpu_pmu->hw_events); int idx = hwc->idx; ien = xscale2pmu_read_int_enable(); @@ -651,7 +651,7 @@ out: static void xscale2pmu_start(struct arm_pmu *cpu_pmu) { unsigned long flags, val; - struct pmu_hw_events *events = cpu_pmu->get_hw_events(); + struct pmu_hw_events *events = this_cpu_ptr(cpu_pmu->hw_events); raw_spin_lock_irqsave(&events->pmu_lock, flags); val = xscale2pmu_read_pmnc() & ~XSCALE_PMU_CNT64; @@ -663,7 +663,7 @@ static void xscale2pmu_start(struct arm_pmu *cpu_pmu) static void xscale2pmu_stop(struct arm_pmu *cpu_pmu) { unsigned long flags, val; - struct pmu_hw_events *events = cpu_pmu->get_hw_events(); + struct pmu_hw_events *events = this_cpu_ptr(cpu_pmu->hw_events); raw_spin_lock_irqsave(&events->pmu_lock, flags); val = xscale2pmu_read_pmnc(); -- cgit v1.2.3 From 5ebd92003494a19ac5246ae385c073be16de1144 Mon Sep 17 00:00:00 2001 From: Mark Rutland Date: Tue, 13 May 2014 19:46:10 +0100 Subject: arm: perf: fold percpu_pmu into pmu_hw_events Currently the percpu_pmu pointers used as percpu_irq dev_id values are defined separately from the other per-cpu accounting data, which make dynamically allocating the data (as will be required for systems with heterogeneous CPUs) difficult. This patch moves the percpu_pmu pointers into pmu_hw_events (which is itself allocated per cpu), which will allow for easier dynamic allocation. Both percpu and regular irqs are requested using percpu_pmu pointers as tokens, freeing us from having to know whether an irq is percpu within the handler, and thus avoiding a radix tree lookup on the handler path. Signed-off-by: Mark Rutland Reviewed-by: Will Deacon Reviewed-by: Stephen Boyd Tested-by: Stephen Boyd Signed-off-by: Will Deacon --- arch/arm/include/asm/pmu.h | 6 ++++++ arch/arm/kernel/perf_event.c | 14 +++++++++----- arch/arm/kernel/perf_event_cpu.c | 14 ++++++++------ 3 files changed, 23 insertions(+), 11 deletions(-) (limited to 'arch') diff --git a/arch/arm/include/asm/pmu.h b/arch/arm/include/asm/pmu.h index f273dd2285a1..cc0149835507 100644 --- a/arch/arm/include/asm/pmu.h +++ b/arch/arm/include/asm/pmu.h @@ -81,6 +81,12 @@ struct pmu_hw_events { * read/modify/write sequences. */ raw_spinlock_t pmu_lock; + + /* + * When using percpu IRQs, we need a percpu dev_id. Place it here as we + * already have to allocate this struct per cpu. + */ + struct arm_pmu *percpu_pmu; }; struct arm_pmu { diff --git a/arch/arm/kernel/perf_event.c b/arch/arm/kernel/perf_event.c index 05ac5ee6e2bb..e34934f63a49 100644 --- a/arch/arm/kernel/perf_event.c +++ b/arch/arm/kernel/perf_event.c @@ -304,17 +304,21 @@ static irqreturn_t armpmu_dispatch_irq(int irq, void *dev) int ret; u64 start_clock, finish_clock; - if (irq_is_percpu(irq)) - dev = *(void **)dev; - armpmu = dev; + /* + * we request the IRQ with a (possibly percpu) struct arm_pmu**, but + * the handlers expect a struct arm_pmu*. The percpu_irq framework will + * do any necessary shifting, we just need to perform the first + * dereference. + */ + armpmu = *(void **)dev; plat_device = armpmu->plat_device; plat = dev_get_platdata(&plat_device->dev); start_clock = sched_clock(); if (plat && plat->handle_irq) - ret = plat->handle_irq(irq, dev, armpmu->handle_irq); + ret = plat->handle_irq(irq, armpmu, armpmu->handle_irq); else - ret = armpmu->handle_irq(irq, dev); + ret = armpmu->handle_irq(irq, armpmu); finish_clock = sched_clock(); perf_sample_event_took(finish_clock - start_clock); diff --git a/arch/arm/kernel/perf_event_cpu.c b/arch/arm/kernel/perf_event_cpu.c index fd24ad84dba6..b9391fa2368d 100644 --- a/arch/arm/kernel/perf_event_cpu.c +++ b/arch/arm/kernel/perf_event_cpu.c @@ -35,7 +35,6 @@ /* Set at runtime when we know what CPU type we are. */ static struct arm_pmu *cpu_pmu; -static DEFINE_PER_CPU(struct arm_pmu *, percpu_pmu); static DEFINE_PER_CPU(struct pmu_hw_events, cpu_hw_events); /* @@ -85,20 +84,21 @@ static void cpu_pmu_free_irq(struct arm_pmu *cpu_pmu) { int i, irq, irqs; struct platform_device *pmu_device = cpu_pmu->plat_device; + struct pmu_hw_events __percpu *hw_events = cpu_pmu->hw_events; irqs = min(pmu_device->num_resources, num_possible_cpus()); irq = platform_get_irq(pmu_device, 0); if (irq >= 0 && irq_is_percpu(irq)) { on_each_cpu(cpu_pmu_disable_percpu_irq, &irq, 1); - free_percpu_irq(irq, &percpu_pmu); + free_percpu_irq(irq, &hw_events->percpu_pmu); } else { for (i = 0; i < irqs; ++i) { if (!cpumask_test_and_clear_cpu(i, &cpu_pmu->active_irqs)) continue; irq = platform_get_irq(pmu_device, i); if (irq >= 0) - free_irq(irq, cpu_pmu); + free_irq(irq, per_cpu_ptr(&hw_events->percpu_pmu, i)); } } } @@ -107,6 +107,7 @@ static int cpu_pmu_request_irq(struct arm_pmu *cpu_pmu, irq_handler_t handler) { int i, err, irq, irqs; struct platform_device *pmu_device = cpu_pmu->plat_device; + struct pmu_hw_events __percpu *hw_events = cpu_pmu->hw_events; if (!pmu_device) return -ENODEV; @@ -119,7 +120,8 @@ static int cpu_pmu_request_irq(struct arm_pmu *cpu_pmu, irq_handler_t handler) irq = platform_get_irq(pmu_device, 0); if (irq >= 0 && irq_is_percpu(irq)) { - err = request_percpu_irq(irq, handler, "arm-pmu", &percpu_pmu); + err = request_percpu_irq(irq, handler, "arm-pmu", + &hw_events->percpu_pmu); if (err) { pr_err("unable to request IRQ%d for ARM PMU counters\n", irq); @@ -146,7 +148,7 @@ static int cpu_pmu_request_irq(struct arm_pmu *cpu_pmu, irq_handler_t handler) err = request_irq(irq, handler, IRQF_NOBALANCING | IRQF_NO_THREAD, "arm-pmu", - cpu_pmu); + per_cpu_ptr(&hw_events->percpu_pmu, i)); if (err) { pr_err("unable to request IRQ%d for ARM PMU counters\n", irq); @@ -166,7 +168,7 @@ static void cpu_pmu_init(struct arm_pmu *cpu_pmu) for_each_possible_cpu(cpu) { struct pmu_hw_events *events = &per_cpu(cpu_hw_events, cpu); raw_spin_lock_init(&events->pmu_lock); - per_cpu(percpu_pmu, cpu) = cpu_pmu; + events->percpu_pmu = cpu_pmu; } cpu_pmu->hw_events = &cpu_hw_events; -- cgit v1.2.3 From abdf655a30b6464fe86c8369de60ccf92f73f589 Mon Sep 17 00:00:00 2001 From: Mark Rutland Date: Tue, 21 Oct 2014 14:11:23 +0100 Subject: arm: perf: dynamically allocate cpu hardware data To support multiple PMUs, each PMU will need its own accounting data. As we don't know how (in general) many PMUs we'll have to support at compile-time, we must allocate the data at runtime dynamically Signed-off-by: Mark Rutland Reviewed-by: Stephen Boyd Signed-off-by: Will Deacon --- arch/arm/kernel/perf_event_cpu.c | 33 +++++++++++++++++++++++++-------- 1 file changed, 25 insertions(+), 8 deletions(-) (limited to 'arch') diff --git a/arch/arm/kernel/perf_event_cpu.c b/arch/arm/kernel/perf_event_cpu.c index b9391fa2368d..f0f6c5ef41b0 100644 --- a/arch/arm/kernel/perf_event_cpu.c +++ b/arch/arm/kernel/perf_event_cpu.c @@ -35,8 +35,6 @@ /* Set at runtime when we know what CPU type we are. */ static struct arm_pmu *cpu_pmu; -static DEFINE_PER_CPU(struct pmu_hw_events, cpu_hw_events); - /* * Despite the names, these two functions are CPU-specific and are used * by the OProfile/perf code. @@ -162,16 +160,22 @@ static int cpu_pmu_request_irq(struct arm_pmu *cpu_pmu, irq_handler_t handler) return 0; } -static void cpu_pmu_init(struct arm_pmu *cpu_pmu) +static int cpu_pmu_init(struct arm_pmu *cpu_pmu) { int cpu; + struct pmu_hw_events __percpu *cpu_hw_events; + + cpu_hw_events = alloc_percpu(struct pmu_hw_events); + if (!cpu_hw_events) + return -ENOMEM; + for_each_possible_cpu(cpu) { - struct pmu_hw_events *events = &per_cpu(cpu_hw_events, cpu); + struct pmu_hw_events *events = per_cpu_ptr(cpu_hw_events, cpu); raw_spin_lock_init(&events->pmu_lock); events->percpu_pmu = cpu_pmu; } - cpu_pmu->hw_events = &cpu_hw_events; + cpu_pmu->hw_events = cpu_hw_events; cpu_pmu->request_irq = cpu_pmu_request_irq; cpu_pmu->free_irq = cpu_pmu_free_irq; @@ -182,6 +186,13 @@ static void cpu_pmu_init(struct arm_pmu *cpu_pmu) /* If no interrupts available, set the corresponding capability flag */ if (!platform_get_irq(cpu_pmu->plat_device, 0)) cpu_pmu->pmu.capabilities |= PERF_PMU_CAP_NO_INTERRUPT; + + return 0; +} + +static void cpu_pmu_destroy(struct arm_pmu *cpu_pmu) +{ + free_percpu(cpu_pmu->hw_events); } /* @@ -303,12 +314,18 @@ static int cpu_pmu_device_probe(struct platform_device *pdev) goto out_free; } - cpu_pmu_init(cpu_pmu); + ret = cpu_pmu_init(cpu_pmu); + if (ret) + goto out_free; + ret = armpmu_register(cpu_pmu, -1); + if (ret) + goto out_destroy; - if (!ret) - return 0; + return 0; +out_destroy: + cpu_pmu_destroy(cpu_pmu); out_free: pr_info("failed to register PMU devices!\n"); kfree(pmu); -- cgit v1.2.3 From af66abfe2ec8bd82211e9e4f036a64c902ff4cdb Mon Sep 17 00:00:00 2001 From: Mark Rutland Date: Thu, 23 Oct 2014 15:23:35 +0100 Subject: arm: perf: fold hotplug notifier into arm_pmu Handling multiple PMUs using a single hotplug notifier requires a list of PMUs to be maintained, with synchronisation in the probe, remove, and notify paths. This is error-prone and makes the code much harder to maintain. Instead of using a single notifier, we can dynamically allocate a notifier block per-PMU. The end result is the same, but the list of PMUs is implicit in the hotplug notifier list rather than within a perf-local data structure, which makes the code far easier to handle. Signed-off-by: Mark Rutland Reviewed-by: Stephen Boyd Signed-off-by: Will Deacon --- arch/arm/include/asm/pmu.h | 1 + arch/arm/kernel/perf_event_cpu.c | 69 ++++++++++++++++++++-------------------- 2 files changed, 35 insertions(+), 35 deletions(-) (limited to 'arch') diff --git a/arch/arm/include/asm/pmu.h b/arch/arm/include/asm/pmu.h index cc0149835507..b1596bd59129 100644 --- a/arch/arm/include/asm/pmu.h +++ b/arch/arm/include/asm/pmu.h @@ -116,6 +116,7 @@ struct arm_pmu { u64 max_period; struct platform_device *plat_device; struct pmu_hw_events __percpu *hw_events; + struct notifier_block hotplug_nb; }; #define to_arm_pmu(p) (container_of(p, struct arm_pmu, pmu)) diff --git a/arch/arm/kernel/perf_event_cpu.c b/arch/arm/kernel/perf_event_cpu.c index f0f6c5ef41b0..dd9acc95ebc0 100644 --- a/arch/arm/kernel/perf_event_cpu.c +++ b/arch/arm/kernel/perf_event_cpu.c @@ -160,8 +160,31 @@ static int cpu_pmu_request_irq(struct arm_pmu *cpu_pmu, irq_handler_t handler) return 0; } +/* + * PMU hardware loses all context when a CPU goes offline. + * When a CPU is hotplugged back in, since some hardware registers are + * UNKNOWN at reset, the PMU must be explicitly reset to avoid reading + * junk values out of them. + */ +static int cpu_pmu_notify(struct notifier_block *b, unsigned long action, + void *hcpu) +{ + struct arm_pmu *pmu = container_of(b, struct arm_pmu, hotplug_nb); + + if ((action & ~CPU_TASKS_FROZEN) != CPU_STARTING) + return NOTIFY_DONE; + + if (pmu->reset) + pmu->reset(pmu); + else + return NOTIFY_DONE; + + return NOTIFY_OK; +} + static int cpu_pmu_init(struct arm_pmu *cpu_pmu) { + int err; int cpu; struct pmu_hw_events __percpu *cpu_hw_events; @@ -169,6 +192,11 @@ static int cpu_pmu_init(struct arm_pmu *cpu_pmu) if (!cpu_hw_events) return -ENOMEM; + cpu_pmu->hotplug_nb.notifier_call = cpu_pmu_notify; + err = register_cpu_notifier(&cpu_pmu->hotplug_nb); + if (err) + goto out_hw_events; + for_each_possible_cpu(cpu) { struct pmu_hw_events *events = per_cpu_ptr(cpu_hw_events, cpu); raw_spin_lock_init(&events->pmu_lock); @@ -188,37 +216,18 @@ static int cpu_pmu_init(struct arm_pmu *cpu_pmu) cpu_pmu->pmu.capabilities |= PERF_PMU_CAP_NO_INTERRUPT; return 0; + +out_hw_events: + free_percpu(cpu_hw_events); + return err; } static void cpu_pmu_destroy(struct arm_pmu *cpu_pmu) { + unregister_cpu_notifier(&cpu_pmu->hotplug_nb); free_percpu(cpu_pmu->hw_events); } -/* - * PMU hardware loses all context when a CPU goes offline. - * When a CPU is hotplugged back in, since some hardware registers are - * UNKNOWN at reset, the PMU must be explicitly reset to avoid reading - * junk values out of them. - */ -static int cpu_pmu_notify(struct notifier_block *b, unsigned long action, - void *hcpu) -{ - if ((action & ~CPU_TASKS_FROZEN) != CPU_STARTING) - return NOTIFY_DONE; - - if (cpu_pmu && cpu_pmu->reset) - cpu_pmu->reset(cpu_pmu); - else - return NOTIFY_DONE; - - return NOTIFY_OK; -} - -static struct notifier_block cpu_pmu_hotplug_notifier = { - .notifier_call = cpu_pmu_notify, -}; - /* * PMU platform driver and devicetree bindings. */ @@ -344,16 +353,6 @@ static struct platform_driver cpu_pmu_driver = { static int __init register_pmu_driver(void) { - 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; + return platform_driver_register(&cpu_pmu_driver); } device_initcall(register_pmu_driver); -- cgit v1.2.3 From a98250217997f3b8d47d21ffaedd39b32d1798eb Mon Sep 17 00:00:00 2001 From: Boris BREZILLON Date: Tue, 23 Sep 2014 13:18:33 +0200 Subject: ARM: at91: add clk_lookup entry for RTT devices First export the clk32k clk. Then add clk_lookup entries for RTT devices so that rtc-at91sam9 driver can retrieve and manipulate the slow clk. Signed-off-by: Boris BREZILLON Acked-by: Alexandre Belloni Acked-by: Johan Hovold Acked-by: Arnd Bergmann Signed-off-by: Nicolas Ferre --- arch/arm/mach-at91/at91sam9260.c | 2 ++ arch/arm/mach-at91/at91sam9261.c | 2 ++ arch/arm/mach-at91/at91sam9263.c | 4 ++++ arch/arm/mach-at91/at91sam9g45.c | 2 ++ arch/arm/mach-at91/at91sam9rl.c | 2 ++ arch/arm/mach-at91/clock.c | 2 +- arch/arm/mach-at91/clock.h | 1 + 7 files changed, 14 insertions(+), 1 deletion(-) (limited to 'arch') diff --git a/arch/arm/mach-at91/at91sam9260.c b/arch/arm/mach-at91/at91sam9260.c index aab1f969a7c3..990b82fdd409 100644 --- a/arch/arm/mach-at91/at91sam9260.c +++ b/arch/arm/mach-at91/at91sam9260.c @@ -217,6 +217,7 @@ static struct clk_lookup periph_clocks_lookups[] = { CLKDEV_CON_DEV_ID("pclk", "fffbc000.ssc", &ssc_clk), CLKDEV_CON_DEV_ID(NULL, "i2c-at91sam9260.0", &twi_clk), CLKDEV_CON_DEV_ID(NULL, "i2c-at91sam9g20.0", &twi_clk), + CLKDEV_CON_DEV_ID(NULL, "rtc-at91sam9.0", &clk32k), /* more usart lookup table for DT entries */ CLKDEV_CON_DEV_ID("usart", "fffff200.serial", &mck), CLKDEV_CON_DEV_ID("usart", "fffb0000.serial", &usart0_clk), @@ -237,6 +238,7 @@ static struct clk_lookup periph_clocks_lookups[] = { CLKDEV_CON_DEV_ID("mci_clk", "fffa8000.mmc", &mmc_clk), CLKDEV_CON_DEV_ID("spi_clk", "fffc8000.spi", &spi0_clk), CLKDEV_CON_DEV_ID("spi_clk", "fffcc000.spi", &spi1_clk), + CLKDEV_CON_DEV_ID(NULL, "fffffd20.rtc", &clk32k), /* fake hclk clock */ CLKDEV_CON_DEV_ID("hclk", "at91_ohci", &ohci_clk), CLKDEV_CON_ID("pioA", &pioA_clk), diff --git a/arch/arm/mach-at91/at91sam9261.c b/arch/arm/mach-at91/at91sam9261.c index a8bd35963332..a23b3cfbc6af 100644 --- a/arch/arm/mach-at91/at91sam9261.c +++ b/arch/arm/mach-at91/at91sam9261.c @@ -192,6 +192,7 @@ static struct clk_lookup periph_clocks_lookups[] = { CLKDEV_CON_ID("pioA", &pioA_clk), CLKDEV_CON_ID("pioB", &pioB_clk), CLKDEV_CON_ID("pioC", &pioC_clk), + CLKDEV_CON_DEV_ID(NULL, "rtc-at91sam9.0", &clk32k), /* more lookup table for DT entries */ CLKDEV_CON_DEV_ID("usart", "fffff200.serial", &mck), CLKDEV_CON_DEV_ID("usart", "fffb0000.serial", &usart0_clk), @@ -209,6 +210,7 @@ static struct clk_lookup periph_clocks_lookups[] = { CLKDEV_CON_DEV_ID(NULL, "fffff400.gpio", &pioA_clk), CLKDEV_CON_DEV_ID(NULL, "fffff600.gpio", &pioB_clk), CLKDEV_CON_DEV_ID(NULL, "fffff800.gpio", &pioC_clk), + CLKDEV_CON_DEV_ID(NULL, "fffffd20.rtc", &clk32k), }; static struct clk_lookup usart_clocks_lookups[] = { diff --git a/arch/arm/mach-at91/at91sam9263.c b/arch/arm/mach-at91/at91sam9263.c index fbff228cc63e..1082fd488263 100644 --- a/arch/arm/mach-at91/at91sam9263.c +++ b/arch/arm/mach-at91/at91sam9263.c @@ -201,6 +201,8 @@ static struct clk_lookup periph_clocks_lookups[] = { CLKDEV_CON_DEV_ID("t0_clk", "atmel_tcb.0", &tcb_clk), CLKDEV_CON_DEV_ID(NULL, "i2c-at91sam9260.0", &twi_clk), CLKDEV_CON_DEV_ID(NULL, "at91sam9rl-pwm", &pwm_clk), + CLKDEV_CON_DEV_ID(NULL, "rtc-at91sam9.0", &clk32k), + CLKDEV_CON_DEV_ID(NULL, "rtc-at91sam9.1", &clk32k), /* fake hclk clock */ CLKDEV_CON_DEV_ID("hclk", "at91_ohci", &ohci_clk), CLKDEV_CON_ID("pioA", &pioA_clk), @@ -227,6 +229,8 @@ static struct clk_lookup periph_clocks_lookups[] = { CLKDEV_CON_DEV_ID(NULL, "fffff800.gpio", &pioCDE_clk), CLKDEV_CON_DEV_ID(NULL, "fffffa00.gpio", &pioCDE_clk), CLKDEV_CON_DEV_ID(NULL, "fffb8000.pwm", &pwm_clk), + CLKDEV_CON_DEV_ID(NULL, "fffffd20.rtc", &clk32k), + CLKDEV_CON_DEV_ID(NULL, "fffffd50.rtc", &clk32k), }; static struct clk_lookup usart_clocks_lookups[] = { diff --git a/arch/arm/mach-at91/at91sam9g45.c b/arch/arm/mach-at91/at91sam9g45.c index 405427ec05f8..9c4c4cebfdf1 100644 --- a/arch/arm/mach-at91/at91sam9g45.c +++ b/arch/arm/mach-at91/at91sam9g45.c @@ -254,6 +254,7 @@ static struct clk_lookup periph_clocks_lookups[] = { CLKDEV_CON_DEV_ID(NULL, "atmel_tdes", &aestdessha_clk), CLKDEV_CON_DEV_ID(NULL, "atmel_aes", &aestdessha_clk), CLKDEV_CON_DEV_ID(NULL, "at91sam9rl-pwm", &pwm_clk), + CLKDEV_CON_DEV_ID(NULL, "rtc-at91sam9.0", &clk32k), /* more usart lookup table for DT entries */ CLKDEV_CON_DEV_ID("usart", "ffffee00.serial", &mck), CLKDEV_CON_DEV_ID("usart", "fff8c000.serial", &usart0_clk), @@ -280,6 +281,7 @@ static struct clk_lookup periph_clocks_lookups[] = { CLKDEV_CON_DEV_ID(NULL, "fffff600.gpio", &pioC_clk), CLKDEV_CON_DEV_ID(NULL, "fffff800.gpio", &pioDE_clk), CLKDEV_CON_DEV_ID(NULL, "fffffa00.gpio", &pioDE_clk), + CLKDEV_CON_DEV_ID(NULL, "fffffd20.rtc", &clk32k), CLKDEV_CON_ID("pioA", &pioA_clk), CLKDEV_CON_ID("pioB", &pioB_clk), diff --git a/arch/arm/mach-at91/at91sam9rl.c b/arch/arm/mach-at91/at91sam9rl.c index f553e4ea034b..40c815c62742 100644 --- a/arch/arm/mach-at91/at91sam9rl.c +++ b/arch/arm/mach-at91/at91sam9rl.c @@ -205,6 +205,7 @@ static struct clk_lookup periph_clocks_lookups[] = { CLKDEV_CON_ID("pioB", &pioB_clk), CLKDEV_CON_ID("pioC", &pioC_clk), CLKDEV_CON_ID("pioD", &pioD_clk), + CLKDEV_CON_DEV_ID(NULL, "rtc-at91sam9.0", &clk32k), /* more lookup table for DT entries */ CLKDEV_CON_DEV_ID("usart", "fffff200.serial", &mck), CLKDEV_CON_DEV_ID("usart", "fffb0000.serial", &usart0_clk), @@ -223,6 +224,7 @@ static struct clk_lookup periph_clocks_lookups[] = { CLKDEV_CON_DEV_ID(NULL, "fffff600.gpio", &pioB_clk), CLKDEV_CON_DEV_ID(NULL, "fffff800.gpio", &pioC_clk), CLKDEV_CON_DEV_ID(NULL, "fffffa00.gpio", &pioD_clk), + CLKDEV_CON_DEV_ID(NULL, "fffffd20.rtc", &clk32k), CLKDEV_CON_ID("adc_clk", &tsc_clk), }; diff --git a/arch/arm/mach-at91/clock.c b/arch/arm/mach-at91/clock.c index d66f102c352a..f569e4826848 100644 --- a/arch/arm/mach-at91/clock.c +++ b/arch/arm/mach-at91/clock.c @@ -115,7 +115,7 @@ static u32 at91_pllb_usb_init; * 48 MHz (unless no USB function clocks are needed). The main clock and * both PLLs are turned off to run in "slow clock mode" (system suspend). */ -static struct clk clk32k = { +struct clk clk32k = { .name = "clk32k", .rate_hz = AT91_SLOW_CLOCK, .users = 1, /* always on */ diff --git a/arch/arm/mach-at91/clock.h b/arch/arm/mach-at91/clock.h index a98a39bbd883..6eb825abbdde 100644 --- a/arch/arm/mach-at91/clock.h +++ b/arch/arm/mach-at91/clock.h @@ -34,6 +34,7 @@ struct clk { extern int __init clk_register(struct clk *clk); extern struct clk mck; extern struct clk utmi_clk; +extern struct clk clk32k; #define CLKDEV_CON_ID(_id, _clk) \ { \ -- cgit v1.2.3 From 0690cbd2e55a72a8eae557c389d1a136ed9fa142 Mon Sep 17 00:00:00 2001 From: Joerg Roedel Date: Wed, 5 Nov 2014 15:28:30 +0100 Subject: powerpc/iommu: Rename iommu_[un]map_sg functions The IOMMU-API gained support for a new iommu_map_sg function. This causes compile failures on powerpc because the function name is already globally used there. This patch renames adds a ppc_ prefix to these functions to solve the compile problem. Signed-off-by: Joerg Roedel --- arch/powerpc/include/asm/iommu.h | 17 ++++++++++------- arch/powerpc/kernel/dma-iommu.c | 8 ++++---- arch/powerpc/kernel/iommu.c | 16 ++++++++-------- arch/powerpc/platforms/cell/iommu.c | 9 +++++---- 4 files changed, 27 insertions(+), 23 deletions(-) (limited to 'arch') diff --git a/arch/powerpc/include/asm/iommu.h b/arch/powerpc/include/asm/iommu.h index 42632c7a2a4e..9cfa3706a1b8 100644 --- a/arch/powerpc/include/asm/iommu.h +++ b/arch/powerpc/include/asm/iommu.h @@ -137,13 +137,16 @@ static inline void set_iommu_table_base_and_group(struct device *dev, iommu_add_device(dev); } -extern int iommu_map_sg(struct device *dev, struct iommu_table *tbl, - struct scatterlist *sglist, int nelems, - unsigned long mask, enum dma_data_direction direction, - struct dma_attrs *attrs); -extern void iommu_unmap_sg(struct iommu_table *tbl, struct scatterlist *sglist, - int nelems, enum dma_data_direction direction, - struct dma_attrs *attrs); +extern int ppc_iommu_map_sg(struct device *dev, struct iommu_table *tbl, + struct scatterlist *sglist, int nelems, + unsigned long mask, + enum dma_data_direction direction, + struct dma_attrs *attrs); +extern void ppc_iommu_unmap_sg(struct iommu_table *tbl, + struct scatterlist *sglist, + int nelems, + enum dma_data_direction direction, + struct dma_attrs *attrs); extern void *iommu_alloc_coherent(struct device *dev, struct iommu_table *tbl, size_t size, dma_addr_t *dma_handle, diff --git a/arch/powerpc/kernel/dma-iommu.c b/arch/powerpc/kernel/dma-iommu.c index 54d0116256f7..4c68bfe4108a 100644 --- a/arch/powerpc/kernel/dma-iommu.c +++ b/arch/powerpc/kernel/dma-iommu.c @@ -60,16 +60,16 @@ static int dma_iommu_map_sg(struct device *dev, struct scatterlist *sglist, int nelems, enum dma_data_direction direction, struct dma_attrs *attrs) { - return iommu_map_sg(dev, get_iommu_table_base(dev), sglist, nelems, - device_to_mask(dev), direction, attrs); + return ppc_iommu_map_sg(dev, get_iommu_table_base(dev), sglist, nelems, + device_to_mask(dev), direction, attrs); } static void dma_iommu_unmap_sg(struct device *dev, struct scatterlist *sglist, int nelems, enum dma_data_direction direction, struct dma_attrs *attrs) { - iommu_unmap_sg(get_iommu_table_base(dev), sglist, nelems, direction, - attrs); + ppc_iommu_unmap_sg(get_iommu_table_base(dev), sglist, nelems, + direction, attrs); } /* We support DMA to/from any memory page via the iommu */ diff --git a/arch/powerpc/kernel/iommu.c b/arch/powerpc/kernel/iommu.c index a10642a0d861..a83cf5ef6488 100644 --- a/arch/powerpc/kernel/iommu.c +++ b/arch/powerpc/kernel/iommu.c @@ -428,10 +428,10 @@ static void iommu_free(struct iommu_table *tbl, dma_addr_t dma_addr, ppc_md.tce_flush(tbl); } -int iommu_map_sg(struct device *dev, struct iommu_table *tbl, - struct scatterlist *sglist, int nelems, - unsigned long mask, enum dma_data_direction direction, - struct dma_attrs *attrs) +int ppc_iommu_map_sg(struct device *dev, struct iommu_table *tbl, + struct scatterlist *sglist, int nelems, + unsigned long mask, enum dma_data_direction direction, + struct dma_attrs *attrs) { dma_addr_t dma_next = 0, dma_addr; struct scatterlist *s, *outs, *segstart; @@ -539,7 +539,7 @@ int iommu_map_sg(struct device *dev, struct iommu_table *tbl, DBG("mapped %d elements:\n", outcount); - /* For the sake of iommu_unmap_sg, we clear out the length in the + /* For the sake of ppc_iommu_unmap_sg, we clear out the length in the * next entry of the sglist if we didn't fill the list completely */ if (outcount < incount) { @@ -572,9 +572,9 @@ int iommu_map_sg(struct device *dev, struct iommu_table *tbl, } -void iommu_unmap_sg(struct iommu_table *tbl, struct scatterlist *sglist, - int nelems, enum dma_data_direction direction, - struct dma_attrs *attrs) +void ppc_iommu_unmap_sg(struct iommu_table *tbl, struct scatterlist *sglist, + int nelems, enum dma_data_direction direction, + struct dma_attrs *attrs) { struct scatterlist *sg; diff --git a/arch/powerpc/platforms/cell/iommu.c b/arch/powerpc/platforms/cell/iommu.c index 2b90ff8a93be..c7c8720aa39f 100644 --- a/arch/powerpc/platforms/cell/iommu.c +++ b/arch/powerpc/platforms/cell/iommu.c @@ -621,8 +621,9 @@ static int dma_fixed_map_sg(struct device *dev, struct scatterlist *sg, if (iommu_fixed_is_weak == dma_get_attr(DMA_ATTR_WEAK_ORDERING, attrs)) return dma_direct_ops.map_sg(dev, sg, nents, direction, attrs); else - return iommu_map_sg(dev, cell_get_iommu_table(dev), sg, nents, - device_to_mask(dev), direction, attrs); + return ppc_iommu_map_sg(dev, cell_get_iommu_table(dev), sg, + nents, device_to_mask(dev), + direction, attrs); } static void dma_fixed_unmap_sg(struct device *dev, struct scatterlist *sg, @@ -632,8 +633,8 @@ static void dma_fixed_unmap_sg(struct device *dev, struct scatterlist *sg, if (iommu_fixed_is_weak == dma_get_attr(DMA_ATTR_WEAK_ORDERING, attrs)) dma_direct_ops.unmap_sg(dev, sg, nents, direction, attrs); else - iommu_unmap_sg(cell_get_iommu_table(dev), sg, nents, direction, - attrs); + ppc_iommu_unmap_sg(cell_get_iommu_table(dev), sg, nents, + direction, attrs); } static int dma_fixed_dma_supported(struct device *dev, u64 mask) -- cgit v1.2.3 From a2b1175131ccb5d4a15456f4f31836356abbce09 Mon Sep 17 00:00:00 2001 From: Daniel Mack Date: Tue, 26 Aug 2014 10:52:53 +0200 Subject: ARM: common: edma: add suspend resume hook This patch makes the edma driver resume correctly after suspend. Tested on an AM33xx platform with cyclic audio streams and omap_hsmmc. All information can be reconstructed by already known runtime information. As we now use some functions that were previously only used from __init context, annotations had to be dropped. [nm@ti.com: added error handling for runtime + suspend_late/early_resume] Signed-off-by: Nishanth Menon Signed-off-by: Daniel Mack Tested-by: Joel Fernandes Acked-by: Joel Fernandes [nsekhar@ti.com: remove unneeded pm_runtime_get_sync() from resume] Signed-off-by: Sekhar Nori --- arch/arm/common/edma.c | 52 ++++++++++++++++++++++++++++++++++++++++++++++++-- 1 file changed, 50 insertions(+), 2 deletions(-) (limited to 'arch') diff --git a/arch/arm/common/edma.c b/arch/arm/common/edma.c index d86771abbf57..79de6a23047b 100644 --- a/arch/arm/common/edma.c +++ b/arch/arm/common/edma.c @@ -244,6 +244,8 @@ struct edma { /* list of channels with no even trigger; terminated by "-1" */ const s8 *noevent; + struct edma_soc_info *info; + /* The edma_inuse bit for each PaRAM slot is clear unless the * channel is in use ... by ARM or DSP, for QDMA, or whatever. */ @@ -295,7 +297,7 @@ static void map_dmach_queue(unsigned ctlr, unsigned ch_no, ~(0x7 << bit), queue_no << bit); } -static void __init assign_priority_to_queue(unsigned ctlr, int queue_no, +static void assign_priority_to_queue(unsigned ctlr, int queue_no, int priority) { int bit = queue_no * 4; @@ -314,7 +316,7 @@ static void __init assign_priority_to_queue(unsigned ctlr, int queue_no, * included in that particular EDMA variant (Eg : dm646x) * */ -static void __init map_dmach_param(unsigned ctlr) +static void map_dmach_param(unsigned ctlr) { int i; for (i = 0; i < EDMA_MAX_DMACH; i++) @@ -1792,15 +1794,61 @@ static int edma_probe(struct platform_device *pdev) edma_write_array2(j, EDMA_DRAE, i, 1, 0x0); edma_write_array(j, EDMA_QRAE, i, 0x0); } + edma_cc[j]->info = info[j]; arch_num_cc++; } return 0; } +static int edma_pm_resume(struct device *dev) +{ + int i, j; + + for (j = 0; j < arch_num_cc; j++) { + struct edma *cc = edma_cc[j]; + + s8 (*queue_priority_mapping)[2]; + + queue_priority_mapping = cc->info->queue_priority_mapping; + + /* Event queue priority mapping */ + for (i = 0; queue_priority_mapping[i][0] != -1; i++) + assign_priority_to_queue(j, + queue_priority_mapping[i][0], + queue_priority_mapping[i][1]); + + /* + * Map the channel to param entry if channel mapping logic + * exist + */ + if (edma_read(j, EDMA_CCCFG) & CHMAP_EXIST) + map_dmach_param(j); + + for (i = 0; i < cc->num_channels; i++) { + if (test_bit(i, cc->edma_inuse)) { + /* ensure access through shadow region 0 */ + edma_or_array2(j, EDMA_DRAE, 0, i >> 5, + BIT(i & 0x1f)); + + setup_dma_interrupt(i, + cc->intr_data[i].callback, + cc->intr_data[i].data); + } + } + } + + return 0; +} + +static const struct dev_pm_ops edma_pm_ops = { + SET_LATE_SYSTEM_SLEEP_PM_OPS(NULL, edma_pm_resume) +}; + static struct platform_driver edma_driver = { .driver = { .name = "edma", + .pm = &edma_pm_ops, .of_match_table = edma_of_ids, }, .probe = edma_probe, -- cgit v1.2.3 From a850c427029e5b9953fe4d4fe4fef10a61ee165a Mon Sep 17 00:00:00 2001 From: Arnd Bergmann Date: Fri, 21 Nov 2014 11:48:54 +0100 Subject: ARM: common: edma: edma_pm_resume may be unused The recently introduced resume hook in the edma driver is not referenced when CONFIG_PM_SLEEP is not set, which results in a compile warning in keystone builds. This adds an appropriate #ifdef. Cc: Nishanth Menon Cc: Daniel Mack Cc: Joel Fernandes Acked-by: Sekhar Nori Fixes: a2b1175131: ("ARM: common: edma: add suspend resume hook") Signed-off-by: Arnd Bergmann --- arch/arm/common/edma.c | 2 ++ 1 file changed, 2 insertions(+) (limited to 'arch') diff --git a/arch/arm/common/edma.c b/arch/arm/common/edma.c index 79de6a23047b..e093f2fcee7a 100644 --- a/arch/arm/common/edma.c +++ b/arch/arm/common/edma.c @@ -1801,6 +1801,7 @@ static int edma_probe(struct platform_device *pdev) return 0; } +#ifdef CONFIG_PM_SLEEP static int edma_pm_resume(struct device *dev) { int i, j; @@ -1840,6 +1841,7 @@ static int edma_pm_resume(struct device *dev) return 0; } +#endif static const struct dev_pm_ops edma_pm_ops = { SET_LATE_SYSTEM_SLEEP_PM_OPS(NULL, edma_pm_resume) -- cgit v1.2.3 From d075f4a2b8b9b3531a00fa359fdc4c8eb3fad97b Mon Sep 17 00:00:00 2001 From: Thierry Reding Date: Thu, 2 Oct 2014 14:57:43 +0200 Subject: amba: Add Kconfig file Rather than duplicate the ARM_AMBA Kconfig symbol in both 32-bit and 64-bit ARM architectures, move the common definition to drivers/amba where dependent drivers will be located. Signed-off-by: Thierry Reding --- arch/arm/Kconfig | 3 --- arch/arm64/Kconfig | 3 --- 2 files changed, 6 deletions(-) (limited to 'arch') diff --git a/arch/arm/Kconfig b/arch/arm/Kconfig index 89c4b5ccc68d..77f8ca5cc3e6 100644 --- a/arch/arm/Kconfig +++ b/arch/arm/Kconfig @@ -1259,9 +1259,6 @@ source "arch/arm/common/Kconfig" menu "Bus support" -config ARM_AMBA - bool - config ISA bool help diff --git a/arch/arm64/Kconfig b/arch/arm64/Kconfig index 9532f8d5857e..db1aa5446a57 100644 --- a/arch/arm64/Kconfig +++ b/arch/arm64/Kconfig @@ -166,9 +166,6 @@ endmenu menu "Bus support" -config ARM_AMBA - bool - config PCI bool "PCI support" help -- cgit v1.2.3 From bd968d59ad1bf0a21dfadda01e842c477712097d Mon Sep 17 00:00:00 2001 From: Thierry Reding Date: Tue, 29 Jul 2014 16:24:25 +0200 Subject: ARM: tegra: Move AHB Kconfig to drivers/amba This will allow the Kconfig option to be shared among 32-bit and 64-bit ARM. Signed-off-by: Thierry Reding --- arch/arm/mach-tegra/Kconfig | 9 +-------- 1 file changed, 1 insertion(+), 8 deletions(-) (limited to 'arch') diff --git a/arch/arm/mach-tegra/Kconfig b/arch/arm/mach-tegra/Kconfig index 095399618ca5..d0be9a1ef6b8 100644 --- a/arch/arm/mach-tegra/Kconfig +++ b/arch/arm/mach-tegra/Kconfig @@ -2,6 +2,7 @@ menuconfig ARCH_TEGRA bool "NVIDIA Tegra" if ARCH_MULTI_V7 select ARCH_REQUIRE_GPIOLIB select ARCH_SUPPORTS_TRUSTED_FOUNDATIONS + select ARM_AMBA select ARM_GIC select CLKSRC_MMIO select HAVE_ARM_SCU if SMP @@ -59,12 +60,4 @@ config ARCH_TEGRA_124_SOC Support for NVIDIA Tegra T124 processor family, based on the ARM CortexA15MP CPU -config TEGRA_AHB - bool "Enable AHB driver for NVIDIA Tegra SoCs" - default y - help - Adds AHB configuration functionality for NVIDIA Tegra SoCs, - which controls AHB bus master arbitration and some - performance parameters(priority, prefech size). - endif -- cgit v1.2.3 From 0b46b8a718c6e90910a1b1b0fe797be3c167e186 Mon Sep 17 00:00:00 2001 From: Sonny Rao Date: Sun, 23 Nov 2014 23:02:44 -0800 Subject: clocksource: arch_timer: Fix code to use physical timers when requested This is a bug fix for using physical arch timers when the arch_timer_use_virtual boolean is false. It restores the arch_counter_get_cntpct() function after removal in 0d651e4e "clocksource: arch_timer: use virtual counters" We need this on certain ARMv7 systems which are architected like this: * The firmware doesn't know and doesn't care about hypervisor mode and we don't want to add the complexity of hypervisor there. * The firmware isn't involved in SMP bringup or resume. * The ARCH timer come up with an uninitialized offset between the virtual and physical counters. Each core gets a different random offset. * The device boots in "Secure SVC" mode. * Nothing has touched the reset value of CNTHCTL.PL1PCEN or CNTHCTL.PL1PCTEN (both default to 1 at reset) One example of such as system is RK3288 where it is much simpler to use the physical counter since there's nobody managing the offset and each time a core goes down and comes back up it will get reinitialized to some other random value. Fixes: 0d651e4e65e9 ("clocksource: arch_timer: use virtual counters") Cc: stable@vger.kernel.org Signed-off-by: Sonny Rao Acked-by: Catalin Marinas Acked-by: Daniel Lezcano Signed-off-by: Olof Johansson --- arch/arm/include/asm/arch_timer.h | 9 +++++++++ arch/arm64/include/asm/arch_timer.h | 9 +++++++++ 2 files changed, 18 insertions(+) (limited to 'arch') diff --git a/arch/arm/include/asm/arch_timer.h b/arch/arm/include/asm/arch_timer.h index 92793ba69c40..d4ebf5679f1f 100644 --- a/arch/arm/include/asm/arch_timer.h +++ b/arch/arm/include/asm/arch_timer.h @@ -78,6 +78,15 @@ static inline u32 arch_timer_get_cntfrq(void) return val; } +static inline u64 arch_counter_get_cntpct(void) +{ + u64 cval; + + isb(); + asm volatile("mrrc p15, 0, %Q0, %R0, c14" : "=r" (cval)); + return cval; +} + static inline u64 arch_counter_get_cntvct(void) { u64 cval; diff --git a/arch/arm64/include/asm/arch_timer.h b/arch/arm64/include/asm/arch_timer.h index f19097134b02..b1fa4e614718 100644 --- a/arch/arm64/include/asm/arch_timer.h +++ b/arch/arm64/include/asm/arch_timer.h @@ -104,6 +104,15 @@ static inline void arch_timer_set_cntkctl(u32 cntkctl) asm volatile("msr cntkctl_el1, %0" : : "r" (cntkctl)); } +static inline u64 arch_counter_get_cntpct(void) +{ + /* + * AArch64 kernel and user space mandate the use of CNTVCT. + */ + BUG(); + return 0; +} + static inline u64 arch_counter_get_cntvct(void) { u64 cval; -- cgit v1.2.3