Loading arch/arm/Kconfig +2 −24 Original line number Diff line number Diff line Loading @@ -13,7 +13,7 @@ config ARM select RTC_LIB select SYS_SUPPORTS_APM_EMULATION select GENERIC_ATOMIC64 if (!CPU_32v6K) select HAVE_OPROFILE select HAVE_OPROFILE if (HAVE_PERF_EVENTS) select HAVE_ARCH_KGDB select HAVE_KPROBES if (!XIP_KERNEL) select HAVE_KRETPROBES if (HAVE_KPROBES) Loading Loading @@ -181,28 +181,6 @@ config ARM_L1_CACHE_SHIFT_6 help Setting ARM L1 cache line size to 64 Bytes. if OPROFILE config OPROFILE_ARMV6 def_bool y depends on CPU_V6 && !SMP select OPROFILE_ARM11_CORE config OPROFILE_MPCORE def_bool y depends on CPU_V6 && SMP select OPROFILE_ARM11_CORE config OPROFILE_ARM11_CORE bool config OPROFILE_ARMV7 def_bool y depends on CPU_V7 && !SMP bool endif config VECTORS_BASE hex default 0xffff0000 if MMU || CPU_HIGH_VECTOR Loading Loading @@ -1314,7 +1292,7 @@ config HIGHPTE config HW_PERF_EVENTS bool "Enable hardware performance counter support for perf events" depends on PERF_EVENTS && CPU_HAS_PMU && (CPU_V6 || CPU_V7) depends on PERF_EVENTS && CPU_HAS_PMU default y help Enable hardware performance counter support for perf events. If Loading arch/arm/include/asm/perf_event.h +17 −0 Original line number Diff line number Diff line Loading @@ -28,4 +28,21 @@ set_perf_event_pending(void) * same indexes here for consistency. */ #define PERF_EVENT_INDEX_OFFSET 1 /* ARM perf PMU IDs for use by internal perf clients. */ enum arm_perf_pmu_ids { ARM_PERF_PMU_ID_XSCALE1 = 0, ARM_PERF_PMU_ID_XSCALE2, ARM_PERF_PMU_ID_V6, ARM_PERF_PMU_ID_V6MP, ARM_PERF_PMU_ID_CA8, ARM_PERF_PMU_ID_CA9, ARM_NUM_PMU_IDS, }; extern enum arm_perf_pmu_ids armpmu_get_pmu_id(void); extern int armpmu_get_max_events(void); #endif /* __ARM_PERF_EVENT_H__ */ arch/arm/include/asm/pmu.h +12 −15 Original line number Diff line number Diff line Loading @@ -19,31 +19,26 @@ enum arm_pmu_type { #ifdef CONFIG_CPU_HAS_PMU struct pmu_irqs { const int *irqs; int num_irqs; }; /** * reserve_pmu() - reserve the hardware performance counters * * Reserve the hardware performance counters in the system for exclusive use. * The 'struct pmu_irqs' for the system is returned on success, ERR_PTR() * The platform_device for the system is returned on success, ERR_PTR() * encoded error on failure. */ extern const struct pmu_irqs * reserve_pmu(void); extern struct platform_device * reserve_pmu(enum arm_pmu_type device); /** * release_pmu() - Relinquish control of the performance counters * * Release the performance counters and allow someone else to use them. * Callers must have disabled the counters and released IRQs before calling * this. The 'struct pmu_irqs' returned from reserve_pmu() must be passed as * this. The platform_device returned from reserve_pmu() must be passed as * a cookie. */ extern int release_pmu(const struct pmu_irqs *irqs); release_pmu(struct platform_device *pdev); /** * init_pmu() - Initialise the PMU. Loading @@ -53,24 +48,26 @@ release_pmu(const struct pmu_irqs *irqs); * the actual hardware initialisation. */ extern int init_pmu(void); init_pmu(enum arm_pmu_type device); #else /* CONFIG_CPU_HAS_PMU */ static inline const struct pmu_irqs * reserve_pmu(void) #include <linux/err.h> static inline struct platform_device * reserve_pmu(enum arm_pmu_type device) { return ERR_PTR(-ENODEV); } static inline int release_pmu(const struct pmu_irqs *irqs) release_pmu(struct platform_device *pdev) { return -ENODEV; } static inline int init_pmu(void) init_pmu(enum arm_pmu_type device) { return -ENODEV; } Loading arch/arm/kernel/perf_event.c +892 −36 File changed.Preview size limit exceeded, changes collapsed. Show changes arch/arm/kernel/pmu.c +83 −44 Original line number Diff line number Diff line Loading @@ -2,6 +2,7 @@ * linux/arch/arm/kernel/pmu.c * * Copyright (C) 2009 picoChip Designs Ltd, Jamie Iles * Copyright (C) 2010 ARM Ltd, Will Deacon * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2 as Loading @@ -9,65 +10,78 @@ * */ #define pr_fmt(fmt) "PMU: " fmt #include <linux/cpumask.h> #include <linux/err.h> #include <linux/interrupt.h> #include <linux/kernel.h> #include <linux/module.h> #include <linux/platform_device.h> #include <asm/pmu.h> /* * Define the IRQs for the system. We could use something like a platform * device but that seems fairly heavyweight for this. Also, the performance * counters can't be removed or hotplugged. * * Ordering is important: init_pmu() will use the ordering to set the affinity * to the corresponding core. e.g. the first interrupt will go to cpu 0, the * second goes to cpu 1 etc. */ static const int irqs[] = { #if defined(CONFIG_ARCH_OMAP2) 3, #elif defined(CONFIG_ARCH_BCMRING) IRQ_PMUIRQ, #elif defined(CONFIG_MACH_REALVIEW_EB) IRQ_EB11MP_PMU_CPU0, IRQ_EB11MP_PMU_CPU1, IRQ_EB11MP_PMU_CPU2, IRQ_EB11MP_PMU_CPU3, #elif defined(CONFIG_ARCH_OMAP3) INT_34XX_BENCH_MPU_EMUL, #elif defined(CONFIG_ARCH_IOP32X) IRQ_IOP32X_CORE_PMU, #elif defined(CONFIG_ARCH_IOP33X) IRQ_IOP33X_CORE_PMU, #elif defined(CONFIG_ARCH_PXA) IRQ_PMU, #endif }; static volatile long pmu_lock; static struct platform_device *pmu_devices[ARM_NUM_PMU_DEVICES]; static int __devinit pmu_device_probe(struct platform_device *pdev) { if (pdev->id < 0 || pdev->id >= ARM_NUM_PMU_DEVICES) { pr_warning("received registration request for unknown " "device %d\n", pdev->id); return -EINVAL; } if (pmu_devices[pdev->id]) pr_warning("registering new PMU device type %d overwrites " "previous registration!\n", pdev->id); else pr_info("registered new PMU device of type %d\n", pdev->id); static const struct pmu_irqs pmu_irqs = { .irqs = irqs, .num_irqs = ARRAY_SIZE(irqs), pmu_devices[pdev->id] = pdev; return 0; } static struct platform_driver pmu_driver = { .driver = { .name = "arm-pmu", }, .probe = pmu_device_probe, }; static volatile long pmu_lock; static int __init register_pmu_driver(void) { return platform_driver_register(&pmu_driver); } device_initcall(register_pmu_driver); const struct pmu_irqs * reserve_pmu(void) struct platform_device * reserve_pmu(enum arm_pmu_type device) { return test_and_set_bit_lock(0, &pmu_lock) ? ERR_PTR(-EBUSY) : &pmu_irqs; struct platform_device *pdev; if (test_and_set_bit_lock(device, &pmu_lock)) { pdev = ERR_PTR(-EBUSY); } else if (pmu_devices[device] == NULL) { clear_bit_unlock(device, &pmu_lock); pdev = ERR_PTR(-ENODEV); } else { pdev = pmu_devices[device]; } return pdev; } EXPORT_SYMBOL_GPL(reserve_pmu); int release_pmu(const struct pmu_irqs *irqs) release_pmu(struct platform_device *pdev) { if (WARN_ON(irqs != &pmu_irqs)) if (WARN_ON(pdev != pmu_devices[pdev->id])) return -EINVAL; clear_bit_unlock(0, &pmu_lock); clear_bit_unlock(pdev->id, &pmu_lock); return 0; } EXPORT_SYMBOL_GPL(release_pmu); Loading @@ -87,17 +101,42 @@ set_irq_affinity(int irq, #endif } int init_pmu(void) static int init_cpu_pmu(void) { int i, err = 0; struct platform_device *pdev = pmu_devices[ARM_PMU_DEVICE_CPU]; if (!pdev) { err = -ENODEV; goto out; } for (i = 0; i < pmu_irqs.num_irqs; ++i) { err = set_irq_affinity(pmu_irqs.irqs[i], i); for (i = 0; i < pdev->num_resources; ++i) { err = set_irq_affinity(platform_get_irq(pdev, i), i); if (err) break; } out: return err; } int init_pmu(enum arm_pmu_type device) { int err = 0; switch (device) { case ARM_PMU_DEVICE_CPU: err = init_cpu_pmu(); break; default: pr_warning("attempt to initialise unknown device %d\n", device); err = -EINVAL; } return err; } EXPORT_SYMBOL_GPL(init_pmu); Loading
arch/arm/Kconfig +2 −24 Original line number Diff line number Diff line Loading @@ -13,7 +13,7 @@ config ARM select RTC_LIB select SYS_SUPPORTS_APM_EMULATION select GENERIC_ATOMIC64 if (!CPU_32v6K) select HAVE_OPROFILE select HAVE_OPROFILE if (HAVE_PERF_EVENTS) select HAVE_ARCH_KGDB select HAVE_KPROBES if (!XIP_KERNEL) select HAVE_KRETPROBES if (HAVE_KPROBES) Loading Loading @@ -181,28 +181,6 @@ config ARM_L1_CACHE_SHIFT_6 help Setting ARM L1 cache line size to 64 Bytes. if OPROFILE config OPROFILE_ARMV6 def_bool y depends on CPU_V6 && !SMP select OPROFILE_ARM11_CORE config OPROFILE_MPCORE def_bool y depends on CPU_V6 && SMP select OPROFILE_ARM11_CORE config OPROFILE_ARM11_CORE bool config OPROFILE_ARMV7 def_bool y depends on CPU_V7 && !SMP bool endif config VECTORS_BASE hex default 0xffff0000 if MMU || CPU_HIGH_VECTOR Loading Loading @@ -1314,7 +1292,7 @@ config HIGHPTE config HW_PERF_EVENTS bool "Enable hardware performance counter support for perf events" depends on PERF_EVENTS && CPU_HAS_PMU && (CPU_V6 || CPU_V7) depends on PERF_EVENTS && CPU_HAS_PMU default y help Enable hardware performance counter support for perf events. If Loading
arch/arm/include/asm/perf_event.h +17 −0 Original line number Diff line number Diff line Loading @@ -28,4 +28,21 @@ set_perf_event_pending(void) * same indexes here for consistency. */ #define PERF_EVENT_INDEX_OFFSET 1 /* ARM perf PMU IDs for use by internal perf clients. */ enum arm_perf_pmu_ids { ARM_PERF_PMU_ID_XSCALE1 = 0, ARM_PERF_PMU_ID_XSCALE2, ARM_PERF_PMU_ID_V6, ARM_PERF_PMU_ID_V6MP, ARM_PERF_PMU_ID_CA8, ARM_PERF_PMU_ID_CA9, ARM_NUM_PMU_IDS, }; extern enum arm_perf_pmu_ids armpmu_get_pmu_id(void); extern int armpmu_get_max_events(void); #endif /* __ARM_PERF_EVENT_H__ */
arch/arm/include/asm/pmu.h +12 −15 Original line number Diff line number Diff line Loading @@ -19,31 +19,26 @@ enum arm_pmu_type { #ifdef CONFIG_CPU_HAS_PMU struct pmu_irqs { const int *irqs; int num_irqs; }; /** * reserve_pmu() - reserve the hardware performance counters * * Reserve the hardware performance counters in the system for exclusive use. * The 'struct pmu_irqs' for the system is returned on success, ERR_PTR() * The platform_device for the system is returned on success, ERR_PTR() * encoded error on failure. */ extern const struct pmu_irqs * reserve_pmu(void); extern struct platform_device * reserve_pmu(enum arm_pmu_type device); /** * release_pmu() - Relinquish control of the performance counters * * Release the performance counters and allow someone else to use them. * Callers must have disabled the counters and released IRQs before calling * this. The 'struct pmu_irqs' returned from reserve_pmu() must be passed as * this. The platform_device returned from reserve_pmu() must be passed as * a cookie. */ extern int release_pmu(const struct pmu_irqs *irqs); release_pmu(struct platform_device *pdev); /** * init_pmu() - Initialise the PMU. Loading @@ -53,24 +48,26 @@ release_pmu(const struct pmu_irqs *irqs); * the actual hardware initialisation. */ extern int init_pmu(void); init_pmu(enum arm_pmu_type device); #else /* CONFIG_CPU_HAS_PMU */ static inline const struct pmu_irqs * reserve_pmu(void) #include <linux/err.h> static inline struct platform_device * reserve_pmu(enum arm_pmu_type device) { return ERR_PTR(-ENODEV); } static inline int release_pmu(const struct pmu_irqs *irqs) release_pmu(struct platform_device *pdev) { return -ENODEV; } static inline int init_pmu(void) init_pmu(enum arm_pmu_type device) { return -ENODEV; } Loading
arch/arm/kernel/perf_event.c +892 −36 File changed.Preview size limit exceeded, changes collapsed. Show changes
arch/arm/kernel/pmu.c +83 −44 Original line number Diff line number Diff line Loading @@ -2,6 +2,7 @@ * linux/arch/arm/kernel/pmu.c * * Copyright (C) 2009 picoChip Designs Ltd, Jamie Iles * Copyright (C) 2010 ARM Ltd, Will Deacon * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2 as Loading @@ -9,65 +10,78 @@ * */ #define pr_fmt(fmt) "PMU: " fmt #include <linux/cpumask.h> #include <linux/err.h> #include <linux/interrupt.h> #include <linux/kernel.h> #include <linux/module.h> #include <linux/platform_device.h> #include <asm/pmu.h> /* * Define the IRQs for the system. We could use something like a platform * device but that seems fairly heavyweight for this. Also, the performance * counters can't be removed or hotplugged. * * Ordering is important: init_pmu() will use the ordering to set the affinity * to the corresponding core. e.g. the first interrupt will go to cpu 0, the * second goes to cpu 1 etc. */ static const int irqs[] = { #if defined(CONFIG_ARCH_OMAP2) 3, #elif defined(CONFIG_ARCH_BCMRING) IRQ_PMUIRQ, #elif defined(CONFIG_MACH_REALVIEW_EB) IRQ_EB11MP_PMU_CPU0, IRQ_EB11MP_PMU_CPU1, IRQ_EB11MP_PMU_CPU2, IRQ_EB11MP_PMU_CPU3, #elif defined(CONFIG_ARCH_OMAP3) INT_34XX_BENCH_MPU_EMUL, #elif defined(CONFIG_ARCH_IOP32X) IRQ_IOP32X_CORE_PMU, #elif defined(CONFIG_ARCH_IOP33X) IRQ_IOP33X_CORE_PMU, #elif defined(CONFIG_ARCH_PXA) IRQ_PMU, #endif }; static volatile long pmu_lock; static struct platform_device *pmu_devices[ARM_NUM_PMU_DEVICES]; static int __devinit pmu_device_probe(struct platform_device *pdev) { if (pdev->id < 0 || pdev->id >= ARM_NUM_PMU_DEVICES) { pr_warning("received registration request for unknown " "device %d\n", pdev->id); return -EINVAL; } if (pmu_devices[pdev->id]) pr_warning("registering new PMU device type %d overwrites " "previous registration!\n", pdev->id); else pr_info("registered new PMU device of type %d\n", pdev->id); static const struct pmu_irqs pmu_irqs = { .irqs = irqs, .num_irqs = ARRAY_SIZE(irqs), pmu_devices[pdev->id] = pdev; return 0; } static struct platform_driver pmu_driver = { .driver = { .name = "arm-pmu", }, .probe = pmu_device_probe, }; static volatile long pmu_lock; static int __init register_pmu_driver(void) { return platform_driver_register(&pmu_driver); } device_initcall(register_pmu_driver); const struct pmu_irqs * reserve_pmu(void) struct platform_device * reserve_pmu(enum arm_pmu_type device) { return test_and_set_bit_lock(0, &pmu_lock) ? ERR_PTR(-EBUSY) : &pmu_irqs; struct platform_device *pdev; if (test_and_set_bit_lock(device, &pmu_lock)) { pdev = ERR_PTR(-EBUSY); } else if (pmu_devices[device] == NULL) { clear_bit_unlock(device, &pmu_lock); pdev = ERR_PTR(-ENODEV); } else { pdev = pmu_devices[device]; } return pdev; } EXPORT_SYMBOL_GPL(reserve_pmu); int release_pmu(const struct pmu_irqs *irqs) release_pmu(struct platform_device *pdev) { if (WARN_ON(irqs != &pmu_irqs)) if (WARN_ON(pdev != pmu_devices[pdev->id])) return -EINVAL; clear_bit_unlock(0, &pmu_lock); clear_bit_unlock(pdev->id, &pmu_lock); return 0; } EXPORT_SYMBOL_GPL(release_pmu); Loading @@ -87,17 +101,42 @@ set_irq_affinity(int irq, #endif } int init_pmu(void) static int init_cpu_pmu(void) { int i, err = 0; struct platform_device *pdev = pmu_devices[ARM_PMU_DEVICE_CPU]; if (!pdev) { err = -ENODEV; goto out; } for (i = 0; i < pmu_irqs.num_irqs; ++i) { err = set_irq_affinity(pmu_irqs.irqs[i], i); for (i = 0; i < pdev->num_resources; ++i) { err = set_irq_affinity(platform_get_irq(pdev, i), i); if (err) break; } out: return err; } int init_pmu(enum arm_pmu_type device) { int err = 0; switch (device) { case ARM_PMU_DEVICE_CPU: err = init_cpu_pmu(); break; default: pr_warning("attempt to initialise unknown device %d\n", device); err = -EINVAL; } return err; } EXPORT_SYMBOL_GPL(init_pmu);