summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--Documentation/devicetree/bindings/arm/pmu.txt12
-rw-r--r--MAINTAINERS6
-rw-r--r--arch/arm/Kconfig8
-rw-r--r--arch/arm/kernel/Makefile3
-rw-r--r--arch/arm/kernel/perf_event_v6.c2
-rw-r--r--arch/arm/kernel/perf_event_v7.c2
-rw-r--r--arch/arm/kernel/perf_event_xscale.c2
-rw-r--r--arch/arm/kernel/reboot.c2
-rw-r--r--arch/arm/mach-ux500/cpu-db8500.c2
-rw-r--r--drivers/Kconfig2
-rw-r--r--drivers/Makefile1
-rw-r--r--drivers/perf/Kconfig15
-rw-r--r--drivers/perf/Makefile1
-rw-r--r--drivers/perf/arm_pmu.c (renamed from arch/arm/kernel/perf_event.c)72
-rw-r--r--include/linux/perf/arm_pmu.h (renamed from arch/arm/include/asm/pmu.h)4
15 files changed, 91 insertions, 43 deletions
diff --git a/Documentation/devicetree/bindings/arm/pmu.txt b/Documentation/devicetree/bindings/arm/pmu.txt
index 3b5f5d1088c6..435251fa9ce0 100644
--- a/Documentation/devicetree/bindings/arm/pmu.txt
+++ b/Documentation/devicetree/bindings/arm/pmu.txt
@@ -26,13 +26,19 @@ Required properties:
Optional properties:
-- interrupt-affinity : Valid only when using SPIs, specifies a list of phandles
- to CPU nodes corresponding directly to the affinity of
+- interrupt-affinity : When using SPIs, specifies a list of phandles to CPU
+ nodes corresponding directly to the affinity of
the SPIs listed in the interrupts property.
- This property should be present when there is more than
+ When using a PPI, specifies a list of phandles to CPU
+ nodes corresponding to the set of CPUs which have
+ a PMU of this type signalling the PPI listed in the
+ interrupts property.
+
+ This property should be present when there is more than
a single SPI.
+
- qcom,no-pc-write : Indicates that this PMU doesn't support the 0xc and 0xd
events.
diff --git a/MAINTAINERS b/MAINTAINERS
index 5106f7165a53..44998e18fd22 100644
--- a/MAINTAINERS
+++ b/MAINTAINERS
@@ -799,11 +799,13 @@ F: arch/arm/include/asm/floppy.h
ARM PMU PROFILING AND DEBUGGING
M: Will Deacon <will.deacon@arm.com>
S: Maintained
-F: arch/arm/kernel/perf_event*
+F: arch/arm/kernel/perf_*
F: arch/arm/oprofile/common.c
-F: arch/arm/include/asm/pmu.h
F: arch/arm/kernel/hw_breakpoint.c
F: arch/arm/include/asm/hw_breakpoint.h
+F: arch/arm/include/asm/perf_event.h
+F: drivers/perf/arm_pmu.c
+F: include/linux/perf/arm_pmu.h
ARM PORT
M: Russell King <linux@arm.linux.org.uk>
diff --git a/arch/arm/Kconfig b/arch/arm/Kconfig
index f5cd68425d8d..74fe545af38a 100644
--- a/arch/arm/Kconfig
+++ b/arch/arm/Kconfig
@@ -1702,12 +1702,8 @@ config HIGHPTE
user-space 2nd level page tables to reside in high memory.
config HW_PERF_EVENTS
- bool "Enable hardware performance counter support for perf events"
- depends on PERF_EVENTS
- default y
- help
- Enable hardware performance counter support for perf events. If
- disabled, perf events will use software events only.
+ def_bool y
+ depends on ARM_PMU
config SYS_SUPPORTS_HUGETLBFS
def_bool y
diff --git a/arch/arm/kernel/Makefile b/arch/arm/kernel/Makefile
index 3b995f5c524d..af9e59bf3831 100644
--- a/arch/arm/kernel/Makefile
+++ b/arch/arm/kernel/Makefile
@@ -71,8 +71,7 @@ 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 perf_callchain.o
-obj-$(CONFIG_HW_PERF_EVENTS) += perf_event.o \
- perf_event_xscale.o perf_event_v6.o \
+obj-$(CONFIG_HW_PERF_EVENTS) += perf_event_xscale.o perf_event_v6.o \
perf_event_v7.o
CFLAGS_pj4-cp0.o := -marm
AFLAGS_iwmmxt.o := -Wa,-mcpu=iwmmxt
diff --git a/arch/arm/kernel/perf_event_v6.c b/arch/arm/kernel/perf_event_v6.c
index 09f83e414a72..09413e7b49aa 100644
--- a/arch/arm/kernel/perf_event_v6.c
+++ b/arch/arm/kernel/perf_event_v6.c
@@ -34,9 +34,9 @@
#include <asm/cputype.h>
#include <asm/irq_regs.h>
-#include <asm/pmu.h>
#include <linux/of.h>
+#include <linux/perf/arm_pmu.h>
#include <linux/platform_device.h>
enum armv6_perf_types {
diff --git a/arch/arm/kernel/perf_event_v7.c b/arch/arm/kernel/perf_event_v7.c
index f9b37f876e20..126dc679b230 100644
--- a/arch/arm/kernel/perf_event_v7.c
+++ b/arch/arm/kernel/perf_event_v7.c
@@ -21,11 +21,11 @@
#include <asm/cp15.h>
#include <asm/cputype.h>
#include <asm/irq_regs.h>
-#include <asm/pmu.h>
#include <asm/vfp.h>
#include "../vfp/vfpinstr.h"
#include <linux/of.h>
+#include <linux/perf/arm_pmu.h>
#include <linux/platform_device.h>
/*
diff --git a/arch/arm/kernel/perf_event_xscale.c b/arch/arm/kernel/perf_event_xscale.c
index 304d056d5b25..aa0499e2eef7 100644
--- a/arch/arm/kernel/perf_event_xscale.c
+++ b/arch/arm/kernel/perf_event_xscale.c
@@ -16,9 +16,9 @@
#include <asm/cputype.h>
#include <asm/irq_regs.h>
-#include <asm/pmu.h>
#include <linux/of.h>
+#include <linux/perf/arm_pmu.h>
#include <linux/platform_device.h>
enum xscale_perf_types {
diff --git a/arch/arm/kernel/reboot.c b/arch/arm/kernel/reboot.c
index 1a4d232796be..38269358fd25 100644
--- a/arch/arm/kernel/reboot.c
+++ b/arch/arm/kernel/reboot.c
@@ -50,7 +50,7 @@ static void __soft_restart(void *addr)
flush_cache_all();
/* Switch to the identity mapping. */
- phys_reset = (phys_reset_t)(unsigned long)virt_to_phys(cpu_reset);
+ phys_reset = (phys_reset_t)(unsigned long)virt_to_idmap(cpu_reset);
phys_reset((unsigned long)addr);
/* Should never get here. */
diff --git a/arch/arm/mach-ux500/cpu-db8500.c b/arch/arm/mach-ux500/cpu-db8500.c
index 16913800bbf9..5578dc1ab52b 100644
--- a/arch/arm/mach-ux500/cpu-db8500.c
+++ b/arch/arm/mach-ux500/cpu-db8500.c
@@ -20,10 +20,10 @@
#include <linux/mfd/dbx500-prcmu.h>
#include <linux/of.h>
#include <linux/of_platform.h>
+#include <linux/perf/arm_pmu.h>
#include <linux/regulator/machine.h>
#include <linux/random.h>
-#include <asm/pmu.h>
#include <asm/mach/map.h>
#include "setup.h"
diff --git a/drivers/Kconfig b/drivers/Kconfig
index 6e973b8e3a3b..3497485f5eab 100644
--- a/drivers/Kconfig
+++ b/drivers/Kconfig
@@ -176,6 +176,8 @@ source "drivers/powercap/Kconfig"
source "drivers/mcb/Kconfig"
+source "drivers/perf/Kconfig"
+
source "drivers/ras/Kconfig"
source "drivers/thunderbolt/Kconfig"
diff --git a/drivers/Makefile b/drivers/Makefile
index b64b49f6e01b..f245f2291b8a 100644
--- a/drivers/Makefile
+++ b/drivers/Makefile
@@ -161,6 +161,7 @@ obj-$(CONFIG_NTB) += ntb/
obj-$(CONFIG_FMC) += fmc/
obj-$(CONFIG_POWERCAP) += powercap/
obj-$(CONFIG_MCB) += mcb/
+obj-$(CONFIG_PERF_EVENTS) += perf/
obj-$(CONFIG_RAS) += ras/
obj-$(CONFIG_THUNDERBOLT) += thunderbolt/
obj-$(CONFIG_CORESIGHT) += hwtracing/coresight/
diff --git a/drivers/perf/Kconfig b/drivers/perf/Kconfig
new file mode 100644
index 000000000000..d9de36ee165d
--- /dev/null
+++ b/drivers/perf/Kconfig
@@ -0,0 +1,15 @@
+#
+# Performance Monitor Drivers
+#
+
+menu "Performance monitor support"
+
+config ARM_PMU
+ depends on PERF_EVENTS && ARM
+ bool "ARM PMU framework"
+ default y
+ help
+ Say y if you want to use CPU performance monitors on ARM-based
+ systems.
+
+endmenu
diff --git a/drivers/perf/Makefile b/drivers/perf/Makefile
new file mode 100644
index 000000000000..acd2397ded94
--- /dev/null
+++ b/drivers/perf/Makefile
@@ -0,0 +1 @@
+obj-$(CONFIG_ARM_PMU) += arm_pmu.o
diff --git a/arch/arm/kernel/perf_event.c b/drivers/perf/arm_pmu.c
index 357f57ea83f4..2365a32a595e 100644
--- a/arch/arm/kernel/perf_event.c
+++ b/drivers/perf/arm_pmu.c
@@ -15,7 +15,8 @@
#include <linux/cpumask.h>
#include <linux/export.h>
#include <linux/kernel.h>
-#include <linux/of.h>
+#include <linux/of_device.h>
+#include <linux/perf/arm_pmu.h>
#include <linux/platform_device.h>
#include <linux/slab.h>
#include <linux/spinlock.h>
@@ -24,7 +25,6 @@
#include <asm/cputype.h>
#include <asm/irq_regs.h>
-#include <asm/pmu.h>
static int
armpmu_map_cache_event(const unsigned (*cache_map)
@@ -790,51 +790,77 @@ static int probe_current_pmu(struct arm_pmu *pmu,
static int of_pmu_irq_cfg(struct arm_pmu *pmu)
{
- int i, irq, *irqs;
+ int *irqs, i = 0;
+ bool using_spi = false;
struct platform_device *pdev = pmu->plat_device;
- /* Don't bother with PPIs; they're already affine */
- irq = platform_get_irq(pdev, 0);
- if (irq >= 0 && irq_is_percpu(irq))
- return 0;
-
irqs = kcalloc(pdev->num_resources, sizeof(*irqs), GFP_KERNEL);
if (!irqs)
return -ENOMEM;
- for (i = 0; i < pdev->num_resources; ++i) {
+ do {
struct device_node *dn;
- int cpu;
+ int cpu, irq;
- dn = of_parse_phandle(pdev->dev.of_node, "interrupt-affinity",
- i);
- if (!dn) {
- pr_warn("Failed to parse %s/interrupt-affinity[%d]\n",
- of_node_full_name(pdev->dev.of_node), i);
+ /* See if we have an affinity entry */
+ dn = of_parse_phandle(pdev->dev.of_node, "interrupt-affinity", i);
+ if (!dn)
break;
+
+ /* Check the IRQ type and prohibit a mix of PPIs and SPIs */
+ irq = platform_get_irq(pdev, i);
+ if (irq >= 0) {
+ bool spi = !irq_is_percpu(irq);
+
+ if (i > 0 && spi != using_spi) {
+ pr_err("PPI/SPI IRQ type mismatch for %s!\n",
+ dn->name);
+ kfree(irqs);
+ return -EINVAL;
+ }
+
+ using_spi = spi;
}
+ /* Now look up the logical CPU number */
for_each_possible_cpu(cpu)
- if (arch_find_n_match_cpu_physical_id(dn, cpu, NULL))
+ if (dn == of_cpu_device_node_get(cpu))
break;
- of_node_put(dn);
if (cpu >= nr_cpu_ids) {
pr_warn("Failed to find logical CPU for %s\n",
dn->name);
+ of_node_put(dn);
+ cpumask_setall(&pmu->supported_cpus);
break;
}
+ of_node_put(dn);
+
+ /* For SPIs, we need to track the affinity per IRQ */
+ if (using_spi) {
+ if (i >= pdev->num_resources) {
+ of_node_put(dn);
+ break;
+ }
- irqs[i] = cpu;
+ irqs[i] = cpu;
+ }
+
+ /* Keep track of the CPUs containing this PMU type */
cpumask_set_cpu(cpu, &pmu->supported_cpus);
- }
+ of_node_put(dn);
+ i++;
+ } while (1);
+
+ /* If we didn't manage to parse anything, claim to support all CPUs */
+ if (cpumask_weight(&pmu->supported_cpus) == 0)
+ cpumask_setall(&pmu->supported_cpus);
- if (i == pdev->num_resources) {
+ /* If we matched up the IRQ affinities, use them to route the SPIs */
+ if (using_spi && i == pdev->num_resources)
pmu->irq_affinity = irqs;
- } else {
+ else
kfree(irqs);
- cpumask_setall(&pmu->supported_cpus);
- }
return 0;
}
diff --git a/arch/arm/include/asm/pmu.h b/include/linux/perf/arm_pmu.h
index 3fc87dfd77e6..bfa673bb822d 100644
--- a/arch/arm/include/asm/pmu.h
+++ b/include/linux/perf/arm_pmu.h
@@ -30,7 +30,7 @@ struct arm_pmu_platdata {
irq_handler_t pmu_handler);
};
-#ifdef CONFIG_HW_PERF_EVENTS
+#ifdef CONFIG_ARM_PMU
/*
* The ARMv7 CPU PMU supports up to 32 event counters.
@@ -149,6 +149,6 @@ int arm_pmu_device_probe(struct platform_device *pdev,
const struct of_device_id *of_table,
const struct pmu_probe_info *probe_table);
-#endif /* CONFIG_HW_PERF_EVENTS */
+#endif /* CONFIG_ARM_PMU */
#endif /* __ARM_PMU_H__ */