* [PATCH 00/10] ARM: perf: updates for 3.2
@ 2011-08-08 17:16 Will Deacon
2011-08-08 17:16 ` [PATCH 01/10] ARM: perf: de-const struct arm_pmu Will Deacon
` (10 more replies)
0 siblings, 11 replies; 19+ messages in thread
From: Will Deacon @ 2011-08-08 17:16 UTC (permalink / raw)
To: linux-arm-kernel
Hello,
This patch series contains a number of updates to the ARM PMU and perf
code so that we can support mode exclusion, which is new in debug
architecture 7.1 (as implemented by the Cortex-A15). Some of these
updates also coincide with work to support System PMUs (PMUs that are
not affine to a single CPU) but that is a larger body of work which will
be posted separately at a later date.
The patches do the following:
1.) Greatly simplify the PMU reservation mechanism so that the
handling of platform_devices is moved into perf.
2.) Cleans up the interrupt registration and some of the types used
to represent events and registers.
3.) Moves event indexing to start from zero rather than one, making
the code more readable and also easier to extend for mode
exclusion.
4.) Adds support for mode exclusion (user / kernel / hyp) and
implements this for Cortex-A15.
I've been running these patches since 3.0, so they've been tested on
1176, 11MPCore, Cortex-A5, Cortex-A9 and Cortex-A15 platforms.
Once again, all feedback is welcome.
Will
Cc: Jean Pihet <j-pihet@ti.com>
Cc: Jamie Iles <jamie@jamieiles.com>
Mark Rutland (1):
ARM: perf: de-const struct arm_pmu
Will Deacon (9):
ARM: PMU: move CPU PMU platform device handling and init into perf
ARM: perf: use cpumask_t to record active IRQs
ARM: perf: use u32 instead of unsigned long for PMNC register
ARM: perf: use integers for ARMv7 event indices
ARM: perf: index ARMv7 event counters starting from zero
ARM: perf: index Xscale and ARMv6 event counters starting from zero
ARM: perf: index PMU registers from zero
ARM: perf: allow armpmu to implement mode exclusion
ARM: perf: add mode exclusion for Cortex-A15 PMU
arch/arm/include/asm/pmu.h | 39 +---
arch/arm/kernel/perf_event.c | 176 ++++++++++++-------
arch/arm/kernel/perf_event_v6.c | 16 +-
arch/arm/kernel/perf_event_v7.c | 327 ++++++++++++++++-------------------
arch/arm/kernel/perf_event_xscale.c | 18 +-
arch/arm/kernel/pmu.c | 181 +------------------
6 files changed, 302 insertions(+), 455 deletions(-)
^ permalink raw reply [flat|nested] 19+ messages in thread
* [PATCH 01/10] ARM: perf: de-const struct arm_pmu
2011-08-08 17:16 [PATCH 00/10] ARM: perf: updates for 3.2 Will Deacon
@ 2011-08-08 17:16 ` Will Deacon
2011-08-08 17:16 ` [PATCH 02/10] ARM: PMU: move CPU PMU platform device handling and init into perf Will Deacon
` (9 subsequent siblings)
10 siblings, 0 replies; 19+ messages in thread
From: Will Deacon @ 2011-08-08 17:16 UTC (permalink / raw)
To: linux-arm-kernel
From: Mark Rutland <mark.rutland@arm.com>
This patch removes const qualifiers from instances of struct arm_pmu,
and functions initialising them, in preparation for generalising
arm_pmu usage to system (AKA uncore) PMUs.
This will allow for dynamically modifiable structures (locks,
struct pmu) to be added as members of struct arm_pmu.
Signed-off-by: Mark Rutland <mark.rutland@arm.com>
Signed-off-by: Will Deacon <will.deacon@arm.com>
---
arch/arm/kernel/perf_event.c | 2 +-
arch/arm/kernel/perf_event_v6.c | 12 ++++++------
arch/arm/kernel/perf_event_v7.c | 16 ++++++++--------
arch/arm/kernel/perf_event_xscale.c | 12 ++++++------
4 files changed, 21 insertions(+), 21 deletions(-)
diff --git a/arch/arm/kernel/perf_event.c b/arch/arm/kernel/perf_event.c
index 53c9c26..7304996 100644
--- a/arch/arm/kernel/perf_event.c
+++ b/arch/arm/kernel/perf_event.c
@@ -90,7 +90,7 @@ struct arm_pmu {
};
/* Set at runtime when we know what CPU type we are. */
-static const struct arm_pmu *armpmu;
+static struct arm_pmu *armpmu;
enum arm_perf_pmu_ids
armpmu_get_pmu_id(void)
diff --git a/arch/arm/kernel/perf_event_v6.c b/arch/arm/kernel/perf_event_v6.c
index dd7f3b9..d1abe97 100644
--- a/arch/arm/kernel/perf_event_v6.c
+++ b/arch/arm/kernel/perf_event_v6.c
@@ -635,7 +635,7 @@ armv6mpcore_pmu_disable_event(struct hw_perf_event *hwc,
raw_spin_unlock_irqrestore(&pmu_lock, flags);
}
-static const struct arm_pmu armv6pmu = {
+static struct arm_pmu armv6pmu = {
.id = ARM_PERF_PMU_ID_V6,
.name = "v6",
.handle_irq = armv6pmu_handle_irq,
@@ -653,7 +653,7 @@ static const struct arm_pmu armv6pmu = {
.max_period = (1LLU << 32) - 1,
};
-static const struct arm_pmu *__init armv6pmu_init(void)
+static struct arm_pmu *__init armv6pmu_init(void)
{
return &armv6pmu;
}
@@ -665,7 +665,7 @@ static const struct arm_pmu *__init armv6pmu_init(void)
* disable the interrupt reporting and update the event. When unthrottling we
* reset the period and enable the interrupt reporting.
*/
-static const struct arm_pmu armv6mpcore_pmu = {
+static struct arm_pmu armv6mpcore_pmu = {
.id = ARM_PERF_PMU_ID_V6MP,
.name = "v6mpcore",
.handle_irq = armv6pmu_handle_irq,
@@ -683,17 +683,17 @@ static const struct arm_pmu armv6mpcore_pmu = {
.max_period = (1LLU << 32) - 1,
};
-static const struct arm_pmu *__init armv6mpcore_pmu_init(void)
+static struct arm_pmu *__init armv6mpcore_pmu_init(void)
{
return &armv6mpcore_pmu;
}
#else
-static const struct arm_pmu *__init armv6pmu_init(void)
+static struct arm_pmu *__init armv6pmu_init(void)
{
return NULL;
}
-static const struct arm_pmu *__init armv6mpcore_pmu_init(void)
+static struct arm_pmu *__init armv6mpcore_pmu_init(void)
{
return NULL;
}
diff --git a/arch/arm/kernel/perf_event_v7.c b/arch/arm/kernel/perf_event_v7.c
index 4c85183..74f9119 100644
--- a/arch/arm/kernel/perf_event_v7.c
+++ b/arch/arm/kernel/perf_event_v7.c
@@ -1188,7 +1188,7 @@ static u32 __init armv7_read_num_pmnc_events(void)
return nb_cnt + 1;
}
-static const struct arm_pmu *__init armv7_a8_pmu_init(void)
+static struct arm_pmu *__init armv7_a8_pmu_init(void)
{
armv7pmu.id = ARM_PERF_PMU_ID_CA8;
armv7pmu.name = "ARMv7 Cortex-A8";
@@ -1198,7 +1198,7 @@ static const struct arm_pmu *__init armv7_a8_pmu_init(void)
return &armv7pmu;
}
-static const struct arm_pmu *__init armv7_a9_pmu_init(void)
+static struct arm_pmu *__init armv7_a9_pmu_init(void)
{
armv7pmu.id = ARM_PERF_PMU_ID_CA9;
armv7pmu.name = "ARMv7 Cortex-A9";
@@ -1208,7 +1208,7 @@ static const struct arm_pmu *__init armv7_a9_pmu_init(void)
return &armv7pmu;
}
-static const struct arm_pmu *__init armv7_a5_pmu_init(void)
+static struct arm_pmu *__init armv7_a5_pmu_init(void)
{
armv7pmu.id = ARM_PERF_PMU_ID_CA5;
armv7pmu.name = "ARMv7 Cortex-A5";
@@ -1218,7 +1218,7 @@ static const struct arm_pmu *__init armv7_a5_pmu_init(void)
return &armv7pmu;
}
-static const struct arm_pmu *__init armv7_a15_pmu_init(void)
+static struct arm_pmu *__init armv7_a15_pmu_init(void)
{
armv7pmu.id = ARM_PERF_PMU_ID_CA15;
armv7pmu.name = "ARMv7 Cortex-A15";
@@ -1228,22 +1228,22 @@ static const struct arm_pmu *__init armv7_a15_pmu_init(void)
return &armv7pmu;
}
#else
-static const struct arm_pmu *__init armv7_a8_pmu_init(void)
+static struct arm_pmu *__init armv7_a8_pmu_init(void)
{
return NULL;
}
-static const struct arm_pmu *__init armv7_a9_pmu_init(void)
+static struct arm_pmu *__init armv7_a9_pmu_init(void)
{
return NULL;
}
-static const struct arm_pmu *__init armv7_a5_pmu_init(void)
+static struct arm_pmu *__init armv7_a5_pmu_init(void)
{
return NULL;
}
-static const struct arm_pmu *__init armv7_a15_pmu_init(void)
+static struct arm_pmu *__init armv7_a15_pmu_init(void)
{
return NULL;
}
diff --git a/arch/arm/kernel/perf_event_xscale.c b/arch/arm/kernel/perf_event_xscale.c
index 3c43974..730b1c2 100644
--- a/arch/arm/kernel/perf_event_xscale.c
+++ b/arch/arm/kernel/perf_event_xscale.c
@@ -424,7 +424,7 @@ xscale1pmu_write_counter(int counter, u32 val)
}
}
-static const struct arm_pmu xscale1pmu = {
+static struct arm_pmu xscale1pmu = {
.id = ARM_PERF_PMU_ID_XSCALE1,
.name = "xscale1",
.handle_irq = xscale1pmu_handle_irq,
@@ -442,7 +442,7 @@ static const struct arm_pmu xscale1pmu = {
.max_period = (1LLU << 32) - 1,
};
-static const struct arm_pmu *__init xscale1pmu_init(void)
+static struct arm_pmu *__init xscale1pmu_init(void)
{
return &xscale1pmu;
}
@@ -786,7 +786,7 @@ xscale2pmu_write_counter(int counter, u32 val)
}
}
-static const struct arm_pmu xscale2pmu = {
+static struct arm_pmu xscale2pmu = {
.id = ARM_PERF_PMU_ID_XSCALE2,
.name = "xscale2",
.handle_irq = xscale2pmu_handle_irq,
@@ -804,17 +804,17 @@ static const struct arm_pmu xscale2pmu = {
.max_period = (1LLU << 32) - 1,
};
-static const struct arm_pmu *__init xscale2pmu_init(void)
+static struct arm_pmu *__init xscale2pmu_init(void)
{
return &xscale2pmu;
}
#else
-static const struct arm_pmu *__init xscale1pmu_init(void)
+static struct arm_pmu *__init xscale1pmu_init(void)
{
return NULL;
}
-static const struct arm_pmu *__init xscale2pmu_init(void)
+static struct arm_pmu *__init xscale2pmu_init(void)
{
return NULL;
}
--
1.7.0.4
^ permalink raw reply related [flat|nested] 19+ messages in thread
* [PATCH 02/10] ARM: PMU: move CPU PMU platform device handling and init into perf
2011-08-08 17:16 [PATCH 00/10] ARM: perf: updates for 3.2 Will Deacon
2011-08-08 17:16 ` [PATCH 01/10] ARM: perf: de-const struct arm_pmu Will Deacon
@ 2011-08-08 17:16 ` Will Deacon
2011-08-08 17:16 ` [PATCH 03/10] ARM: perf: use cpumask_t to record active IRQs Will Deacon
` (8 subsequent siblings)
10 siblings, 0 replies; 19+ messages in thread
From: Will Deacon @ 2011-08-08 17:16 UTC (permalink / raw)
To: linux-arm-kernel
Once upon a time, OProfile and Perf fought hard over who could play with
the PMU. To stop all hell from breaking loose, pmu.c offered an internal
reserve/release API and took care of parsing PMU platform data passed in
from board support code.
Now that Perf has ingested OProfile, let's move the platform device
handling into the Perf driver and out of the PMU locking code.
Unfortunately, the lock has to remain to prevent Perf being bitten by
out-of-tree modules such as LTTng, which still claim a right to the PMU
when Perf isn't looking.
Signed-off-by: Will Deacon <will.deacon@arm.com>
---
arch/arm/include/asm/pmu.h | 39 +++-------
arch/arm/kernel/perf_event.c | 74 ++++++++++++++---
arch/arm/kernel/pmu.c | 181 ++----------------------------------------
3 files changed, 80 insertions(+), 214 deletions(-)
diff --git a/arch/arm/include/asm/pmu.h b/arch/arm/include/asm/pmu.h
index 67c70a3..f210708 100644
--- a/arch/arm/include/asm/pmu.h
+++ b/arch/arm/include/asm/pmu.h
@@ -14,6 +14,10 @@
#include <linux/interrupt.h>
+/*
+ * Types of PMUs that can be accessed directly and require mutual
+ * exclusion between profiling tools.
+ */
enum arm_pmu_type {
ARM_PMU_DEVICE_CPU = 0,
ARM_NUM_PMU_DEVICES,
@@ -37,54 +41,31 @@ struct arm_pmu_platdata {
* reserve_pmu() - reserve the hardware performance counters
*
* Reserve the hardware performance counters in the system for exclusive use.
- * The platform_device for the system is returned on success, ERR_PTR()
- * encoded error on failure.
+ * Returns 0 on success or -EBUSY if the lock is already held.
*/
-extern struct platform_device *
+extern int
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 platform_device returned from reserve_pmu() must be passed as
- * a cookie.
*/
-extern int
+extern void
release_pmu(enum arm_pmu_type type);
-/**
- * init_pmu() - Initialise the PMU.
- *
- * Initialise the system ready for PMU enabling. This should typically set the
- * IRQ affinity and nothing else. The users (oprofile/perf events etc) will do
- * the actual hardware initialisation.
- */
-extern int
-init_pmu(enum arm_pmu_type device);
-
#else /* CONFIG_CPU_HAS_PMU */
#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(struct platform_device *pdev)
+reserve_pmu(enum arm_pmu_type device)
{
return -ENODEV;
}
-static inline int
-init_pmu(enum arm_pmu_type device)
-{
- return -ENODEV;
-}
+static inline void
+release_pmu(struct platform_device *pdev) { }
#endif /* CONFIG_CPU_HAS_PMU */
diff --git a/arch/arm/kernel/perf_event.c b/arch/arm/kernel/perf_event.c
index 7304996..8514855 100644
--- a/arch/arm/kernel/perf_event.c
+++ b/arch/arm/kernel/perf_event.c
@@ -393,15 +393,15 @@ armpmu_reserve_hardware(void)
{
struct arm_pmu_platdata *plat;
irq_handler_t handle_irq;
- int i, err = -ENODEV, irq;
+ int i, err, irq, irqs;
- pmu_device = reserve_pmu(ARM_PMU_DEVICE_CPU);
- if (IS_ERR(pmu_device)) {
+ err = reserve_pmu(ARM_PMU_DEVICE_CPU);
+ if (err) {
pr_warning("unable to reserve pmu\n");
- return PTR_ERR(pmu_device);
+ return err;
}
- init_pmu(ARM_PMU_DEVICE_CPU);
+ irqs = pmu_device->num_resources;
plat = dev_get_platdata(&pmu_device->dev);
if (plat && plat->handle_irq)
@@ -409,22 +409,34 @@ armpmu_reserve_hardware(void)
else
handle_irq = armpmu->handle_irq;
- if (pmu_device->num_resources < 1) {
+ if (irqs < 1) {
pr_err("no irqs for PMUs defined\n");
return -ENODEV;
}
- for (i = 0; i < pmu_device->num_resources; ++i) {
+ for (i = 0; i < irqs; ++i) {
irq = platform_get_irq(pmu_device, i);
if (irq < 0)
continue;
+ /*
+ * If we have a single PMU interrupt that we can't shift,
+ * assume that we're running on a uniprocessor machine and
+ * continue.
+ */
+ err = irq_set_affinity(irq, cpumask_of(i));
+ if (err && irqs > 1) {
+ pr_err("unable to set irq affinity (irq=%d, cpu=%u)\n",
+ irq, i);
+ break;
+ }
+
err = request_irq(irq, handle_irq,
IRQF_DISABLED | IRQF_NOBALANCING,
- "armpmu", NULL);
+ "arm-pmu", NULL);
if (err) {
- pr_warning("unable to request IRQ%d for ARM perf "
- "counters\n", irq);
+ pr_err("unable to request IRQ%d for ARM PMU counters\n",
+ irq);
break;
}
}
@@ -436,7 +448,6 @@ armpmu_reserve_hardware(void)
free_irq(irq, NULL);
}
release_pmu(ARM_PMU_DEVICE_CPU);
- pmu_device = NULL;
}
return err;
@@ -455,7 +466,6 @@ armpmu_release_hardware(void)
armpmu->stop();
release_pmu(ARM_PMU_DEVICE_CPU);
- pmu_device = NULL;
}
static atomic_t active_events = ATOMIC_INIT(0);
@@ -638,6 +648,46 @@ armpmu_reset(void)
}
arch_initcall(armpmu_reset);
+/*
+ * PMU platform driver and devicetree bindings.
+ */
+static struct of_device_id armpmu_of_device_ids[] = {
+ {.compatible = "arm,cortex-a9-pmu"},
+ {.compatible = "arm,cortex-a8-pmu"},
+ {.compatible = "arm,arm1136-pmu"},
+ {.compatible = "arm,arm1176-pmu"},
+ {},
+};
+
+static struct platform_device_id armpmu_plat_device_ids[] = {
+ {.name = "arm-pmu"},
+ {},
+};
+
+static int __devinit armpmu_device_probe(struct platform_device *pdev)
+{
+ pmu_device = pdev;
+ return 0;
+}
+
+static struct platform_driver armpmu_driver = {
+ .driver = {
+ .name = "arm-pmu",
+ .of_match_table = armpmu_of_device_ids,
+ },
+ .probe = armpmu_device_probe,
+ .id_table = armpmu_plat_device_ids,
+};
+
+static int __init register_pmu_driver(void)
+{
+ return platform_driver_register(&armpmu_driver);
+}
+device_initcall(register_pmu_driver);
+
+/*
+ * CPU PMU identification and registration.
+ */
static int __init
init_hw_perf_events(void)
{
diff --git a/arch/arm/kernel/pmu.c b/arch/arm/kernel/pmu.c
index 2b70709..98d0736 100644
--- a/arch/arm/kernel/pmu.c
+++ b/arch/arm/kernel/pmu.c
@@ -10,192 +10,27 @@
*
*/
-#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/of_device.h>
-#include <linux/platform_device.h>
#include <asm/pmu.h>
-static volatile long pmu_lock;
-
-static struct platform_device *pmu_devices[ARM_NUM_PMU_DEVICES];
-
-static int __devinit pmu_register(struct platform_device *pdev,
- enum arm_pmu_type type)
-{
- if (type < 0 || type >= ARM_NUM_PMU_DEVICES) {
- pr_warning("received registration request for unknown "
- "device %d\n", type);
- return -EINVAL;
- }
-
- if (pmu_devices[type]) {
- pr_warning("rejecting duplicate registration of PMU device "
- "type %d.", type);
- return -ENOSPC;
- }
-
- pr_info("registered new PMU device of type %d\n", type);
- pmu_devices[type] = pdev;
- return 0;
-}
-
-#define OF_MATCH_PMU(_name, _type) { \
- .compatible = _name, \
- .data = (void *)_type, \
-}
-
-#define OF_MATCH_CPU(name) OF_MATCH_PMU(name, ARM_PMU_DEVICE_CPU)
-
-static struct of_device_id armpmu_of_device_ids[] = {
- OF_MATCH_CPU("arm,cortex-a9-pmu"),
- OF_MATCH_CPU("arm,cortex-a8-pmu"),
- OF_MATCH_CPU("arm,arm1136-pmu"),
- OF_MATCH_CPU("arm,arm1176-pmu"),
- {},
-};
-
-#define PLAT_MATCH_PMU(_name, _type) { \
- .name = _name, \
- .driver_data = _type, \
-}
-
-#define PLAT_MATCH_CPU(_name) PLAT_MATCH_PMU(_name, ARM_PMU_DEVICE_CPU)
-
-static struct platform_device_id armpmu_plat_device_ids[] = {
- PLAT_MATCH_CPU("arm-pmu"),
- {},
-};
-
-enum arm_pmu_type armpmu_device_type(struct platform_device *pdev)
-{
- const struct of_device_id *of_id;
- const struct platform_device_id *pdev_id;
-
- /* provided by of_device_id table */
- if (pdev->dev.of_node) {
- of_id = of_match_device(armpmu_of_device_ids, &pdev->dev);
- BUG_ON(!of_id);
- return (enum arm_pmu_type)of_id->data;
- }
-
- /* Provided by platform_device_id table */
- pdev_id = platform_get_device_id(pdev);
- BUG_ON(!pdev_id);
- return pdev_id->driver_data;
-}
-
-static int __devinit armpmu_device_probe(struct platform_device *pdev)
-{
- return pmu_register(pdev, armpmu_device_type(pdev));
-}
-
-static struct platform_driver armpmu_driver = {
- .driver = {
- .name = "arm-pmu",
- .of_match_table = armpmu_of_device_ids,
- },
- .probe = armpmu_device_probe,
- .id_table = armpmu_plat_device_ids,
-};
-
-static int __init register_pmu_driver(void)
-{
- return platform_driver_register(&armpmu_driver);
-}
-device_initcall(register_pmu_driver);
+/*
+ * PMU locking to ensure mutual exclusion between different subsystems.
+ */
+static unsigned long pmu_lock[BITS_TO_LONGS(ARM_NUM_PMU_DEVICES)];
-struct platform_device *
+int
reserve_pmu(enum arm_pmu_type device)
{
- 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;
+ return test_and_set_bit_lock(device, pmu_lock) ? -EBUSY : 0;
}
EXPORT_SYMBOL_GPL(reserve_pmu);
-int
+void
release_pmu(enum arm_pmu_type device)
{
- if (WARN_ON(!pmu_devices[device]))
- return -EINVAL;
- clear_bit_unlock(device, &pmu_lock);
- return 0;
+ clear_bit_unlock(device, pmu_lock);
}
EXPORT_SYMBOL_GPL(release_pmu);
-
-static int
-set_irq_affinity(int irq,
- unsigned int cpu)
-{
-#ifdef CONFIG_SMP
- int err = irq_set_affinity(irq, cpumask_of(cpu));
- if (err)
- pr_warning("unable to set irq affinity (irq=%d, cpu=%u)\n",
- irq, cpu);
- return err;
-#else
- return -EINVAL;
-#endif
-}
-
-static int
-init_cpu_pmu(void)
-{
- int i, irqs, err = 0;
- struct platform_device *pdev = pmu_devices[ARM_PMU_DEVICE_CPU];
-
- if (!pdev)
- return -ENODEV;
-
- irqs = pdev->num_resources;
-
- /*
- * If we have a single PMU interrupt that we can't shift, assume that
- * we're running on a uniprocessor machine and continue.
- */
- if (irqs == 1 && !irq_can_set_affinity(platform_get_irq(pdev, 0)))
- return 0;
-
- for (i = 0; i < irqs; ++i) {
- err = set_irq_affinity(platform_get_irq(pdev, i), i);
- if (err)
- break;
- }
-
- 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);
--
1.7.0.4
^ permalink raw reply related [flat|nested] 19+ messages in thread
* [PATCH 03/10] ARM: perf: use cpumask_t to record active IRQs
2011-08-08 17:16 [PATCH 00/10] ARM: perf: updates for 3.2 Will Deacon
2011-08-08 17:16 ` [PATCH 01/10] ARM: perf: de-const struct arm_pmu Will Deacon
2011-08-08 17:16 ` [PATCH 02/10] ARM: PMU: move CPU PMU platform device handling and init into perf Will Deacon
@ 2011-08-08 17:16 ` Will Deacon
2011-08-08 17:16 ` [PATCH 04/10] ARM: perf: use u32 instead of unsigned long for PMNC register Will Deacon
` (7 subsequent siblings)
10 siblings, 0 replies; 19+ messages in thread
From: Will Deacon @ 2011-08-08 17:16 UTC (permalink / raw)
To: linux-arm-kernel
Commit 5dfc54e0 ("ARM: GIC: avoid routing interrupts to offline CPUs")
prevents the GIC from setting the affinity of an IRQ to a CPU with
id >= nr_cpu_ids. This was previously abused by perf on some platforms
where more IRQs were registered than possible CPUs.
This patch fixes the problem by using a cpumask_t to keep track of the
active (requested) interrupts in perf. The same effect could be achieved
by limiting the number of IRQs to the number of CPUs, but using a mask
instead will be useful for adding extended CPU hotplug support in the
future.
Signed-off-by: Will Deacon <will.deacon@arm.com>
---
arch/arm/kernel/perf_event.c | 64 ++++++++++++++++++++---------------------
1 files changed, 31 insertions(+), 33 deletions(-)
diff --git a/arch/arm/kernel/perf_event.c b/arch/arm/kernel/perf_event.c
index 8514855..d507fe1 100644
--- a/arch/arm/kernel/perf_event.c
+++ b/arch/arm/kernel/perf_event.c
@@ -69,6 +69,7 @@ static DEFINE_PER_CPU(struct cpu_hw_events, cpu_hw_events);
struct arm_pmu {
enum arm_perf_pmu_ids id;
+ cpumask_t active_irqs;
const char *name;
irqreturn_t (*handle_irq)(int irq_num, void *dev);
void (*enable)(struct hw_perf_event *evt, int idx);
@@ -388,6 +389,25 @@ static irqreturn_t armpmu_platform_irq(int irq, void *dev)
return plat->handle_irq(irq, dev, armpmu->handle_irq);
}
+static void
+armpmu_release_hardware(void)
+{
+ int i, irq, irqs;
+
+ irqs = min(pmu_device->num_resources, num_possible_cpus());
+
+ for (i = 0; i < irqs; ++i) {
+ if (!cpumask_test_and_clear_cpu(i, &armpmu->active_irqs))
+ continue;
+ irq = platform_get_irq(pmu_device, i);
+ if (irq >= 0)
+ free_irq(irq, NULL);
+ }
+
+ armpmu->stop();
+ release_pmu(ARM_PMU_DEVICE_CPU);
+}
+
static int
armpmu_reserve_hardware(void)
{
@@ -401,20 +421,20 @@ armpmu_reserve_hardware(void)
return err;
}
- irqs = pmu_device->num_resources;
-
plat = dev_get_platdata(&pmu_device->dev);
if (plat && plat->handle_irq)
handle_irq = armpmu_platform_irq;
else
handle_irq = armpmu->handle_irq;
+ irqs = min(pmu_device->num_resources, num_possible_cpus());
if (irqs < 1) {
pr_err("no irqs for PMUs defined\n");
return -ENODEV;
}
for (i = 0; i < irqs; ++i) {
+ err = 0;
irq = platform_get_irq(pmu_device, i);
if (irq < 0)
continue;
@@ -422,13 +442,12 @@ armpmu_reserve_hardware(void)
/*
* If we have a single PMU interrupt that we can't shift,
* assume that we're running on a uniprocessor machine and
- * continue.
+ * continue. Otherwise, continue without this interrupt.
*/
- err = irq_set_affinity(irq, cpumask_of(i));
- if (err && irqs > 1) {
- pr_err("unable to set irq affinity (irq=%d, cpu=%u)\n",
- irq, i);
- break;
+ if (irq_set_affinity(irq, cpumask_of(i)) && irqs > 1) {
+ pr_warning("unable to set irq affinity (irq=%d, cpu=%u)\n",
+ irq, i);
+ continue;
}
err = request_irq(irq, handle_irq,
@@ -437,35 +456,14 @@ armpmu_reserve_hardware(void)
if (err) {
pr_err("unable to request IRQ%d for ARM PMU counters\n",
irq);
- break;
+ armpmu_release_hardware();
+ return err;
}
- }
- if (err) {
- for (i = i - 1; i >= 0; --i) {
- irq = platform_get_irq(pmu_device, i);
- if (irq >= 0)
- free_irq(irq, NULL);
- }
- release_pmu(ARM_PMU_DEVICE_CPU);
+ cpumask_set_cpu(i, &armpmu->active_irqs);
}
- return err;
-}
-
-static void
-armpmu_release_hardware(void)
-{
- int i, irq;
-
- for (i = pmu_device->num_resources - 1; i >= 0; --i) {
- irq = platform_get_irq(pmu_device, i);
- if (irq >= 0)
- free_irq(irq, NULL);
- }
- armpmu->stop();
-
- release_pmu(ARM_PMU_DEVICE_CPU);
+ return 0;
}
static atomic_t active_events = ATOMIC_INIT(0);
--
1.7.0.4
^ permalink raw reply related [flat|nested] 19+ messages in thread
* [PATCH 04/10] ARM: perf: use u32 instead of unsigned long for PMNC register
2011-08-08 17:16 [PATCH 00/10] ARM: perf: updates for 3.2 Will Deacon
` (2 preceding siblings ...)
2011-08-08 17:16 ` [PATCH 03/10] ARM: perf: use cpumask_t to record active IRQs Will Deacon
@ 2011-08-08 17:16 ` Will Deacon
2011-08-08 17:16 ` [PATCH 05/10] ARM: perf: use integers for ARMv7 event indices Will Deacon
` (6 subsequent siblings)
10 siblings, 0 replies; 19+ messages in thread
From: Will Deacon @ 2011-08-08 17:16 UTC (permalink / raw)
To: linux-arm-kernel
The ARMv7 perf backend mixes up u32 and unsigned long, which is rather
ugly.
This patch makes the ARMv7 PMU code consistently use the u32 type
instead.
Signed-off-by: Will Deacon <will.deacon@arm.com>
---
arch/arm/kernel/perf_event_v7.c | 12 ++++++------
1 files changed, 6 insertions(+), 6 deletions(-)
diff --git a/arch/arm/kernel/perf_event_v7.c b/arch/arm/kernel/perf_event_v7.c
index 74f9119..f4f260d 100644
--- a/arch/arm/kernel/perf_event_v7.c
+++ b/arch/arm/kernel/perf_event_v7.c
@@ -758,26 +758,26 @@ enum armv7_counters {
#define ARMV7_FLAG_MASK 0xffffffff /* Mask for writable bits */
#define ARMV7_OVERFLOWED_MASK ARMV7_FLAG_MASK
-static inline unsigned long armv7_pmnc_read(void)
+static inline u32 armv7_pmnc_read(void)
{
u32 val;
asm volatile("mrc p15, 0, %0, c9, c12, 0" : "=r"(val));
return val;
}
-static inline void armv7_pmnc_write(unsigned long val)
+static inline void armv7_pmnc_write(u32 val)
{
val &= ARMV7_PMNC_MASK;
isb();
asm volatile("mcr p15, 0, %0, c9, c12, 0" : : "r"(val));
}
-static inline int armv7_pmnc_has_overflowed(unsigned long pmnc)
+static inline int armv7_pmnc_has_overflowed(u32 pmnc)
{
return pmnc & ARMV7_OVERFLOWED_MASK;
}
-static inline int armv7_pmnc_counter_has_overflowed(unsigned long pmnc,
+static inline int armv7_pmnc_counter_has_overflowed(u32 pmnc,
enum armv7_counters counter)
{
int ret = 0;
@@ -812,7 +812,7 @@ static inline int armv7_pmnc_select_counter(unsigned int idx)
static inline u32 armv7pmu_read_counter(int idx)
{
- unsigned long value = 0;
+ u32 value = 0;
if (idx == ARMV7_CYCLE_COUNTER)
asm volatile("mrc p15, 0, %0, c9, c13, 0" : "=r" (value));
@@ -1044,7 +1044,7 @@ static void armv7pmu_disable_event(struct hw_perf_event *hwc, int idx)
static irqreturn_t armv7pmu_handle_irq(int irq_num, void *dev)
{
- unsigned long pmnc;
+ u32 pmnc;
struct perf_sample_data data;
struct cpu_hw_events *cpuc;
struct pt_regs *regs;
--
1.7.0.4
^ permalink raw reply related [flat|nested] 19+ messages in thread
* [PATCH 05/10] ARM: perf: use integers for ARMv7 event indices
2011-08-08 17:16 [PATCH 00/10] ARM: perf: updates for 3.2 Will Deacon
` (3 preceding siblings ...)
2011-08-08 17:16 ` [PATCH 04/10] ARM: perf: use u32 instead of unsigned long for PMNC register Will Deacon
@ 2011-08-08 17:16 ` Will Deacon
2011-08-08 17:16 ` [PATCH 06/10] ARM: perf: index ARMv7 event counters starting from zero Will Deacon
` (5 subsequent siblings)
10 siblings, 0 replies; 19+ messages in thread
From: Will Deacon @ 2011-08-08 17:16 UTC (permalink / raw)
To: linux-arm-kernel
This patch ensures that integers are used to represent event indices in
the ARMv7 PMU backend. This ensures consistency between functions and
also with the arm_pmu structure.
Signed-off-by: Will Deacon <will.deacon@arm.com>
---
arch/arm/kernel/perf_event_v7.c | 12 ++++++------
1 files changed, 6 insertions(+), 6 deletions(-)
diff --git a/arch/arm/kernel/perf_event_v7.c b/arch/arm/kernel/perf_event_v7.c
index f4f260d..e39bc89 100644
--- a/arch/arm/kernel/perf_event_v7.c
+++ b/arch/arm/kernel/perf_event_v7.c
@@ -793,7 +793,7 @@ static inline int armv7_pmnc_counter_has_overflowed(u32 pmnc,
return ret;
}
-static inline int armv7_pmnc_select_counter(unsigned int idx)
+static inline int armv7_pmnc_select_counter(int idx)
{
u32 val;
@@ -840,7 +840,7 @@ static inline void armv7pmu_write_counter(int idx, u32 value)
smp_processor_id(), idx);
}
-static inline void armv7_pmnc_write_evtsel(unsigned int idx, u32 val)
+static inline void armv7_pmnc_write_evtsel(int idx, u32 val)
{
if (armv7_pmnc_select_counter(idx) == idx) {
val &= ARMV7_EVTSEL_MASK;
@@ -848,7 +848,7 @@ static inline void armv7_pmnc_write_evtsel(unsigned int idx, u32 val)
}
}
-static inline u32 armv7_pmnc_enable_counter(unsigned int idx)
+static inline int armv7_pmnc_enable_counter(int idx)
{
u32 val;
@@ -869,7 +869,7 @@ static inline u32 armv7_pmnc_enable_counter(unsigned int idx)
return idx;
}
-static inline u32 armv7_pmnc_disable_counter(unsigned int idx)
+static inline int armv7_pmnc_disable_counter(int idx)
{
u32 val;
@@ -891,7 +891,7 @@ static inline u32 armv7_pmnc_disable_counter(unsigned int idx)
return idx;
}
-static inline u32 armv7_pmnc_enable_intens(unsigned int idx)
+static inline int armv7_pmnc_enable_intens(int idx)
{
u32 val;
@@ -912,7 +912,7 @@ static inline u32 armv7_pmnc_enable_intens(unsigned int idx)
return idx;
}
-static inline u32 armv7_pmnc_disable_intens(unsigned int idx)
+static inline int armv7_pmnc_disable_intens(int idx)
{
u32 val;
--
1.7.0.4
^ permalink raw reply related [flat|nested] 19+ messages in thread
* [PATCH 06/10] ARM: perf: index ARMv7 event counters starting from zero
2011-08-08 17:16 [PATCH 00/10] ARM: perf: updates for 3.2 Will Deacon
` (4 preceding siblings ...)
2011-08-08 17:16 ` [PATCH 05/10] ARM: perf: use integers for ARMv7 event indices Will Deacon
@ 2011-08-08 17:16 ` Will Deacon
2011-08-08 17:16 ` [PATCH 07/10] ARM: perf: index Xscale and ARMv6 " Will Deacon
` (4 subsequent siblings)
10 siblings, 0 replies; 19+ messages in thread
From: Will Deacon @ 2011-08-08 17:16 UTC (permalink / raw)
To: linux-arm-kernel
The current ARMv7 PMU backend indexes event counters from two, with
index zero being reserved and index one being used to represent the
cycle counter.
This patch tidies up the code by indexing from one instead (with zero
for the cycle counter). This allows us to remove many of the accessor
macros along with the counter enumeration and makes the code much more
readable.
Signed-off-by: Will Deacon <will.deacon@arm.com>
---
arch/arm/kernel/perf_event_v7.c | 239 ++++++++++++++------------------------
1 files changed, 88 insertions(+), 151 deletions(-)
diff --git a/arch/arm/kernel/perf_event_v7.c b/arch/arm/kernel/perf_event_v7.c
index e39bc89..0934c82 100644
--- a/arch/arm/kernel/perf_event_v7.c
+++ b/arch/arm/kernel/perf_event_v7.c
@@ -676,23 +676,24 @@ static const unsigned armv7_a15_perf_cache_map[PERF_COUNT_HW_CACHE_MAX]
};
/*
- * Perf Events counters
+ * Perf Events' indices
*/
-enum armv7_counters {
- ARMV7_CYCLE_COUNTER = 1, /* Cycle counter */
- ARMV7_COUNTER0 = 2, /* First event counter */
-};
+#define ARMV7_IDX_CYCLE_COUNTER 0
+#define ARMV7_IDX_COUNTER0 1
+#define ARMV7_IDX_COUNTER_LAST (ARMV7_IDX_CYCLE_COUNTER + armpmu->num_events - 1)
+
+#define ARMV7_MAX_COUNTERS 32
+#define ARMV7_COUNTER_MASK (ARMV7_MAX_COUNTERS - 1)
/*
- * The cycle counter is ARMV7_CYCLE_COUNTER.
- * The first event counter is ARMV7_COUNTER0.
- * The last event counter is (ARMV7_COUNTER0 + armpmu->num_events - 1).
+ * ARMv7 low level PMNC access
*/
-#define ARMV7_COUNTER_LAST (ARMV7_COUNTER0 + armpmu->num_events - 1)
/*
- * ARMv7 low level PMNC access
+ * Perf Event to low level counters mapping
*/
+#define ARMV7_IDX_TO_COUNTER(x) \
+ (((x) - ARMV7_IDX_COUNTER0) & ARMV7_COUNTER_MASK)
/*
* Per-CPU PMNC: config reg
@@ -708,53 +709,13 @@ enum armv7_counters {
#define ARMV7_PMNC_MASK 0x3f /* Mask for writable bits */
/*
- * Available counters
- */
-#define ARMV7_CNT0 0 /* First event counter */
-#define ARMV7_CCNT 31 /* Cycle counter */
-
-/* Perf Event to low level counters mapping */
-#define ARMV7_EVENT_CNT_TO_CNTx (ARMV7_COUNTER0 - ARMV7_CNT0)
-
-/*
- * CNTENS: counters enable reg
- */
-#define ARMV7_CNTENS_P(idx) (1 << (idx - ARMV7_EVENT_CNT_TO_CNTx))
-#define ARMV7_CNTENS_C (1 << ARMV7_CCNT)
-
-/*
- * CNTENC: counters disable reg
- */
-#define ARMV7_CNTENC_P(idx) (1 << (idx - ARMV7_EVENT_CNT_TO_CNTx))
-#define ARMV7_CNTENC_C (1 << ARMV7_CCNT)
-
-/*
- * INTENS: counters overflow interrupt enable reg
- */
-#define ARMV7_INTENS_P(idx) (1 << (idx - ARMV7_EVENT_CNT_TO_CNTx))
-#define ARMV7_INTENS_C (1 << ARMV7_CCNT)
-
-/*
- * INTENC: counters overflow interrupt disable reg
- */
-#define ARMV7_INTENC_P(idx) (1 << (idx - ARMV7_EVENT_CNT_TO_CNTx))
-#define ARMV7_INTENC_C (1 << ARMV7_CCNT)
-
-/*
* EVTSEL: Event selection reg
*/
#define ARMV7_EVTSEL_MASK 0xff /* Mask for writable bits */
/*
- * SELECT: Counter selection reg
- */
-#define ARMV7_SELECT_MASK 0x1f /* Mask for writable bits */
-
-/*
* FLAG: counters overflow flag status reg
*/
-#define ARMV7_FLAG_P(idx) (1 << (idx - ARMV7_EVENT_CNT_TO_CNTx))
-#define ARMV7_FLAG_C (1 << ARMV7_CCNT)
#define ARMV7_FLAG_MASK 0xffffffff /* Mask for writable bits */
#define ARMV7_OVERFLOWED_MASK ARMV7_FLAG_MASK
@@ -777,34 +738,39 @@ static inline int armv7_pmnc_has_overflowed(u32 pmnc)
return pmnc & ARMV7_OVERFLOWED_MASK;
}
-static inline int armv7_pmnc_counter_has_overflowed(u32 pmnc,
- enum armv7_counters counter)
+static inline int armv7_pmnc_counter_valid(int idx)
+{
+ return idx >= ARMV7_IDX_CYCLE_COUNTER && idx <= ARMV7_IDX_COUNTER_LAST;
+}
+
+static inline int armv7_pmnc_counter_has_overflowed(u32 pmnc, int idx)
{
int ret = 0;
+ u32 counter;
- if (counter == ARMV7_CYCLE_COUNTER)
- ret = pmnc & ARMV7_FLAG_C;
- else if ((counter >= ARMV7_COUNTER0) && (counter <= ARMV7_COUNTER_LAST))
- ret = pmnc & ARMV7_FLAG_P(counter);
- else
+ if (!armv7_pmnc_counter_valid(idx)) {
pr_err("CPU%u checking wrong counter %d overflow status\n",
- smp_processor_id(), counter);
+ smp_processor_id(), idx);
+ } else {
+ counter = ARMV7_IDX_TO_COUNTER(idx);
+ ret = pmnc & BIT(counter);
+ }
return ret;
}
static inline int armv7_pmnc_select_counter(int idx)
{
- u32 val;
+ u32 counter;
- if ((idx < ARMV7_COUNTER0) || (idx > ARMV7_COUNTER_LAST)) {
- pr_err("CPU%u selecting wrong PMNC counter"
- " %d\n", smp_processor_id(), idx);
- return -1;
+ if (!armv7_pmnc_counter_valid(idx)) {
+ pr_err("CPU%u selecting wrong PMNC counter %d\n",
+ smp_processor_id(), idx);
+ return -EINVAL;
}
- val = (idx - ARMV7_EVENT_CNT_TO_CNTx) & ARMV7_SELECT_MASK;
- asm volatile("mcr p15, 0, %0, c9, c12, 5" : : "r" (val));
+ counter = ARMV7_IDX_TO_COUNTER(idx);
+ asm volatile("mcr p15, 0, %0, c9, c12, 5" : : "r" (counter));
isb();
return idx;
@@ -814,30 +780,26 @@ static inline u32 armv7pmu_read_counter(int idx)
{
u32 value = 0;
- if (idx == ARMV7_CYCLE_COUNTER)
- asm volatile("mrc p15, 0, %0, c9, c13, 0" : "=r" (value));
- else if ((idx >= ARMV7_COUNTER0) && (idx <= ARMV7_COUNTER_LAST)) {
- if (armv7_pmnc_select_counter(idx) == idx)
- asm volatile("mrc p15, 0, %0, c9, c13, 2"
- : "=r" (value));
- } else
+ if (!armv7_pmnc_counter_valid(idx))
pr_err("CPU%u reading wrong counter %d\n",
smp_processor_id(), idx);
+ 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)
+ asm volatile("mrc p15, 0, %0, c9, c13, 2" : "=r" (value));
return value;
}
static inline void armv7pmu_write_counter(int idx, u32 value)
{
- if (idx == ARMV7_CYCLE_COUNTER)
- asm volatile("mcr p15, 0, %0, c9, c13, 0" : : "r" (value));
- else if ((idx >= ARMV7_COUNTER0) && (idx <= ARMV7_COUNTER_LAST)) {
- if (armv7_pmnc_select_counter(idx) == idx)
- asm volatile("mcr p15, 0, %0, c9, c13, 2"
- : : "r" (value));
- } else
+ if (!armv7_pmnc_counter_valid(idx))
pr_err("CPU%u writing wrong counter %d\n",
smp_processor_id(), idx);
+ 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)
+ asm volatile("mcr p15, 0, %0, c9, c13, 2" : : "r" (value));
}
static inline void armv7_pmnc_write_evtsel(int idx, u32 val)
@@ -850,86 +812,61 @@ static inline void armv7_pmnc_write_evtsel(int idx, u32 val)
static inline int armv7_pmnc_enable_counter(int idx)
{
- u32 val;
+ u32 counter;
- if ((idx != ARMV7_CYCLE_COUNTER) &&
- ((idx < ARMV7_COUNTER0) || (idx > ARMV7_COUNTER_LAST))) {
- pr_err("CPU%u enabling wrong PMNC counter"
- " %d\n", smp_processor_id(), idx);
- return -1;
+ if (!armv7_pmnc_counter_valid(idx)) {
+ pr_err("CPU%u enabling wrong PMNC counter %d\n",
+ smp_processor_id(), idx);
+ return -EINVAL;
}
- if (idx == ARMV7_CYCLE_COUNTER)
- val = ARMV7_CNTENS_C;
- else
- val = ARMV7_CNTENS_P(idx);
-
- asm volatile("mcr p15, 0, %0, c9, c12, 1" : : "r" (val));
-
+ 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)
{
- u32 val;
+ u32 counter;
-
- if ((idx != ARMV7_CYCLE_COUNTER) &&
- ((idx < ARMV7_COUNTER0) || (idx > ARMV7_COUNTER_LAST))) {
- pr_err("CPU%u disabling wrong PMNC counter"
- " %d\n", smp_processor_id(), idx);
- return -1;
+ if (!armv7_pmnc_counter_valid(idx)) {
+ pr_err("CPU%u disabling wrong PMNC counter %d\n",
+ smp_processor_id(), idx);
+ return -EINVAL;
}
- if (idx == ARMV7_CYCLE_COUNTER)
- val = ARMV7_CNTENC_C;
- else
- val = ARMV7_CNTENC_P(idx);
-
- asm volatile("mcr p15, 0, %0, c9, c12, 2" : : "r" (val));
-
+ 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)
{
- u32 val;
+ u32 counter;
- if ((idx != ARMV7_CYCLE_COUNTER) &&
- ((idx < ARMV7_COUNTER0) || (idx > ARMV7_COUNTER_LAST))) {
- pr_err("CPU%u enabling wrong PMNC counter"
- " interrupt enable %d\n", smp_processor_id(), idx);
- return -1;
+ if (!armv7_pmnc_counter_valid(idx)) {
+ pr_err("CPU%u enabling wrong PMNC counter IRQ enable %d\n",
+ smp_processor_id(), idx);
+ return -EINVAL;
}
- if (idx == ARMV7_CYCLE_COUNTER)
- val = ARMV7_INTENS_C;
- else
- val = ARMV7_INTENS_P(idx);
-
- asm volatile("mcr p15, 0, %0, c9, c14, 1" : : "r" (val));
-
+ 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)
{
- u32 val;
+ u32 counter;
- if ((idx != ARMV7_CYCLE_COUNTER) &&
- ((idx < ARMV7_COUNTER0) || (idx > ARMV7_COUNTER_LAST))) {
- pr_err("CPU%u disabling wrong PMNC counter"
- " interrupt enable %d\n", smp_processor_id(), idx);
- return -1;
+ if (!armv7_pmnc_counter_valid(idx)) {
+ pr_err("CPU%u disabling wrong PMNC counter IRQ enable %d\n",
+ smp_processor_id(), idx);
+ return -EINVAL;
}
- if (idx == ARMV7_CYCLE_COUNTER)
- val = ARMV7_INTENC_C;
- else
- val = ARMV7_INTENC_P(idx);
-
- asm volatile("mcr p15, 0, %0, c9, c14, 2" : : "r" (val));
-
+ counter = ARMV7_IDX_TO_COUNTER(idx);
+ asm volatile("mcr p15, 0, %0, c9, c14, 2" : : "r" (BIT(counter)));
return idx;
}
@@ -973,14 +910,14 @@ static void armv7_pmnc_dump_regs(void)
asm volatile("mrc p15, 0, %0, c9, c13, 0" : "=r" (val));
printk(KERN_INFO "CCNT =0x%08x\n", val);
- for (cnt = ARMV7_COUNTER0; cnt < ARMV7_COUNTER_LAST; cnt++) {
+ for (cnt = ARMV7_IDX_COUNTER0; cnt <= ARMV7_IDX_COUNTER_LAST; 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",
- cnt-ARMV7_EVENT_CNT_TO_CNTx, val);
+ 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",
- cnt-ARMV7_EVENT_CNT_TO_CNTx, val);
+ ARMV7_IDX_TO_COUNTER(cnt), val);
}
}
#endif
@@ -1004,7 +941,7 @@ static void armv7pmu_enable_event(struct hw_perf_event *hwc, int idx)
* Set event (if destined for PMNx counters)
* We don't need to set the event if it's a cycle count
*/
- if (idx != ARMV7_CYCLE_COUNTER)
+ if (idx != ARMV7_IDX_CYCLE_COUNTER)
armv7_pmnc_write_evtsel(idx, hwc->config_base);
/*
@@ -1069,7 +1006,7 @@ static irqreturn_t armv7pmu_handle_irq(int irq_num, void *dev)
perf_sample_data_init(&data, 0);
cpuc = &__get_cpu_var(cpu_hw_events);
- for (idx = 0; idx <= armpmu->num_events; ++idx) {
+ for (idx = 0; idx < armpmu->num_events; ++idx) {
struct perf_event *event = cpuc->events[idx];
struct hw_perf_event *hwc;
@@ -1132,23 +1069,23 @@ static int armv7pmu_get_event_idx(struct cpu_hw_events *cpuc,
/* Always place a cycle counter into the cycle counter. */
if (event->config_base == ARMV7_PERFCTR_CPU_CYCLES) {
- if (test_and_set_bit(ARMV7_CYCLE_COUNTER, cpuc->used_mask))
+ if (test_and_set_bit(ARMV7_IDX_CYCLE_COUNTER, cpuc->used_mask))
return -EAGAIN;
- return ARMV7_CYCLE_COUNTER;
- } else {
- /*
- * For anything other than a cycle counter, try and use
- * the events counters
- */
- for (idx = ARMV7_COUNTER0; idx <= armpmu->num_events; ++idx) {
- if (!test_and_set_bit(idx, cpuc->used_mask))
- return idx;
- }
+ return ARMV7_IDX_CYCLE_COUNTER;
+ }
- /* The counters are all in use. */
- return -EAGAIN;
+ /*
+ * For anything other than a cycle counter, try and use
+ * the events counters
+ */
+ for (idx = ARMV7_IDX_COUNTER0; idx < armpmu->num_events; ++idx) {
+ if (!test_and_set_bit(idx, cpuc->used_mask))
+ return idx;
}
+
+ /* The counters are all in use. */
+ return -EAGAIN;
}
static void armv7pmu_reset(void *info)
@@ -1156,7 +1093,7 @@ static void armv7pmu_reset(void *info)
u32 idx, nb_cnt = armpmu->num_events;
/* The counter and interrupt enable registers are unknown at reset. */
- for (idx = 1; idx < nb_cnt; ++idx)
+ for (idx = ARMV7_IDX_CYCLE_COUNTER; idx < nb_cnt; ++idx)
armv7pmu_disable_event(NULL, idx);
/* Initialize & Reset PMNC: C and P bits */
--
1.7.0.4
^ permalink raw reply related [flat|nested] 19+ messages in thread
* [PATCH 07/10] ARM: perf: index Xscale and ARMv6 event counters starting from zero
2011-08-08 17:16 [PATCH 00/10] ARM: perf: updates for 3.2 Will Deacon
` (5 preceding siblings ...)
2011-08-08 17:16 ` [PATCH 06/10] ARM: perf: index ARMv7 event counters starting from zero Will Deacon
@ 2011-08-08 17:16 ` Will Deacon
2011-08-08 17:16 ` [PATCH 08/10] ARM: perf: index PMU registers " Will Deacon
` (3 subsequent siblings)
10 siblings, 0 replies; 19+ messages in thread
From: Will Deacon @ 2011-08-08 17:16 UTC (permalink / raw)
To: linux-arm-kernel
Now that the ARMv7 PMU backend indexes event counters from zero, follow
suit and do the same for ARMv6 and Xscale.
Signed-off-by: Mark Rutland <mark.rutland@arm.com>
Signed-off-by: Will Deacon <will.deacon@arm.com>
---
arch/arm/kernel/perf_event_v6.c | 4 ++--
arch/arm/kernel/perf_event_xscale.c | 6 +++---
2 files changed, 5 insertions(+), 5 deletions(-)
diff --git a/arch/arm/kernel/perf_event_v6.c b/arch/arm/kernel/perf_event_v6.c
index d1abe97..87f29b5 100644
--- a/arch/arm/kernel/perf_event_v6.c
+++ b/arch/arm/kernel/perf_event_v6.c
@@ -54,7 +54,7 @@ enum armv6_perf_types {
};
enum armv6_counters {
- ARMV6_CYCLE_COUNTER = 1,
+ ARMV6_CYCLE_COUNTER = 0,
ARMV6_COUNTER0,
ARMV6_COUNTER1,
};
@@ -487,7 +487,7 @@ armv6pmu_handle_irq(int irq_num,
perf_sample_data_init(&data, 0);
cpuc = &__get_cpu_var(cpu_hw_events);
- for (idx = 0; idx <= armpmu->num_events; ++idx) {
+ for (idx = 0; idx < armpmu->num_events; ++idx) {
struct perf_event *event = cpuc->events[idx];
struct hw_perf_event *hwc;
diff --git a/arch/arm/kernel/perf_event_xscale.c b/arch/arm/kernel/perf_event_xscale.c
index 730b1c2..54312fc 100644
--- a/arch/arm/kernel/perf_event_xscale.c
+++ b/arch/arm/kernel/perf_event_xscale.c
@@ -40,7 +40,7 @@ enum xscale_perf_types {
};
enum xscale_counters {
- XSCALE_CYCLE_COUNTER = 1,
+ XSCALE_CYCLE_COUNTER = 0,
XSCALE_COUNTER0,
XSCALE_COUNTER1,
XSCALE_COUNTER2,
@@ -249,7 +249,7 @@ xscale1pmu_handle_irq(int irq_num, void *dev)
perf_sample_data_init(&data, 0);
cpuc = &__get_cpu_var(cpu_hw_events);
- for (idx = 0; idx <= armpmu->num_events; ++idx) {
+ for (idx = 0; idx < armpmu->num_events; ++idx) {
struct perf_event *event = cpuc->events[idx];
struct hw_perf_event *hwc;
@@ -581,7 +581,7 @@ xscale2pmu_handle_irq(int irq_num, void *dev)
perf_sample_data_init(&data, 0);
cpuc = &__get_cpu_var(cpu_hw_events);
- for (idx = 0; idx <= armpmu->num_events; ++idx) {
+ for (idx = 0; idx < armpmu->num_events; ++idx) {
struct perf_event *event = cpuc->events[idx];
struct hw_perf_event *hwc;
--
1.7.0.4
^ permalink raw reply related [flat|nested] 19+ messages in thread
* [PATCH 08/10] ARM: perf: index PMU registers from zero
2011-08-08 17:16 [PATCH 00/10] ARM: perf: updates for 3.2 Will Deacon
` (6 preceding siblings ...)
2011-08-08 17:16 ` [PATCH 07/10] ARM: perf: index Xscale and ARMv6 " Will Deacon
@ 2011-08-08 17:16 ` Will Deacon
2011-08-08 17:16 ` [PATCH 09/10] ARM: perf: allow armpmu to implement mode exclusion Will Deacon
` (2 subsequent siblings)
10 siblings, 0 replies; 19+ messages in thread
From: Will Deacon @ 2011-08-08 17:16 UTC (permalink / raw)
To: linux-arm-kernel
ARM PMU code used to use 1-based indices for PMU registers. This caused
several data structures (pmu_hw_events::{active_events, used_mask, events})
to have an unused element at index zero. ARMPMU_MAX_HWEVENTS still takes
this indexing into account, and currently equates to 33.
This patch updates the core ARM perf code to use the 0th index again.
Signed-off-by: Mark Rutland <mark.rutland@arm.com>
Signed-off-by: Will Deacon <will.deacon@arm.com>
---
arch/arm/kernel/perf_event.c | 6 +++---
1 files changed, 3 insertions(+), 3 deletions(-)
diff --git a/arch/arm/kernel/perf_event.c b/arch/arm/kernel/perf_event.c
index d507fe1..00e57f1 100644
--- a/arch/arm/kernel/perf_event.c
+++ b/arch/arm/kernel/perf_event.c
@@ -35,7 +35,7 @@ static struct platform_device *pmu_device;
static DEFINE_RAW_SPINLOCK(pmu_lock);
/*
- * ARMv6 supports a maximum of 3 events, starting from index 1. If we add
+ * ARMv6 supports a maximum of 3 events, starting from index 0. If we add
* another platform that supports more, we need to increase this to be the
* largest of all platforms.
*
@@ -43,7 +43,7 @@ static DEFINE_RAW_SPINLOCK(pmu_lock);
* cycle counter CCNT + 31 events counters CNT0..30.
* Cortex-A8 has 1+4 counters, Cortex-A9 has 1+6 counters.
*/
-#define ARMPMU_MAX_HWEVENTS 33
+#define ARMPMU_MAX_HWEVENTS 32
/* The events for a given CPU. */
struct cpu_hw_events {
@@ -597,7 +597,7 @@ static void armpmu_enable(struct pmu *pmu)
if (!armpmu)
return;
- for (idx = 0; idx <= armpmu->num_events; ++idx) {
+ for (idx = 0; idx < armpmu->num_events; ++idx) {
struct perf_event *event = cpuc->events[idx];
if (!event)
--
1.7.0.4
^ permalink raw reply related [flat|nested] 19+ messages in thread
* [PATCH 09/10] ARM: perf: allow armpmu to implement mode exclusion
2011-08-08 17:16 [PATCH 00/10] ARM: perf: updates for 3.2 Will Deacon
` (7 preceding siblings ...)
2011-08-08 17:16 ` [PATCH 08/10] ARM: perf: index PMU registers " Will Deacon
@ 2011-08-08 17:16 ` Will Deacon
2011-08-08 17:16 ` [PATCH 10/10] ARM: perf: add mode exclusion for Cortex-A15 PMU Will Deacon
2011-08-09 9:35 ` [PATCH 00/10] ARM: perf: updates for 3.2 Jamie Iles
10 siblings, 0 replies; 19+ messages in thread
From: Will Deacon @ 2011-08-08 17:16 UTC (permalink / raw)
To: linux-arm-kernel
Modern PMUs allow for mode exclusion, so we no longer wish to return
-EPERM if it is requested.
This patch provides a hook in the armpmu structure for implementing
mode exclusion. The hw_perf_event initialisation is slightly delayed so
that the backend code can update the structure if required.
Signed-off-by: Will Deacon <will.deacon@arm.com>
---
arch/arm/kernel/perf_event.c | 44 +++++++++++++++++++++++------------------
1 files changed, 25 insertions(+), 19 deletions(-)
diff --git a/arch/arm/kernel/perf_event.c b/arch/arm/kernel/perf_event.c
index 00e57f1..8a5e2ac 100644
--- a/arch/arm/kernel/perf_event.c
+++ b/arch/arm/kernel/perf_event.c
@@ -76,6 +76,8 @@ struct arm_pmu {
void (*disable)(struct hw_perf_event *evt, int idx);
int (*get_event_idx)(struct cpu_hw_events *cpuc,
struct hw_perf_event *hwc);
+ int (*set_event_filter)(struct hw_perf_event *evt,
+ struct perf_event_attr *attr);
u32 (*read_counter)(int idx);
void (*write_counter)(int idx, u32 val);
void (*start)(void);
@@ -479,6 +481,13 @@ hw_perf_event_destroy(struct perf_event *event)
}
static int
+event_requires_mode_exclusion(struct perf_event_attr *attr)
+{
+ return attr->exclude_idle || attr->exclude_user ||
+ attr->exclude_kernel || attr->exclude_hv;
+}
+
+static int
__hw_perf_event_init(struct perf_event *event)
{
struct hw_perf_event *hwc = &event->hw;
@@ -503,34 +512,31 @@ __hw_perf_event_init(struct perf_event *event)
}
/*
+ * We don't assign an index until we actually place the event onto
+ * hardware. Use -1 to signify that we haven't decided where to put it
+ * yet. For SMP systems, each core has it's own PMU so we can't do any
+ * clever allocation or constraints checking at this point.
+ */
+ hwc->idx = -1;
+ hwc->config_base = 0;
+ hwc->config = 0;
+ hwc->event_base = 0;
+
+ /*
* Check whether we need to exclude the counter from certain modes.
- * The ARM performance counters are on all of the time so if someone
- * has asked us for some excludes then we have to fail.
*/
- if (event->attr.exclude_kernel || event->attr.exclude_user ||
- event->attr.exclude_hv || event->attr.exclude_idle) {
+ if ((!armpmu->set_event_filter ||
+ armpmu->set_event_filter(hwc, &event->attr)) &&
+ event_requires_mode_exclusion(&event->attr)) {
pr_debug("ARM performance counters do not support "
"mode exclusion\n");
return -EPERM;
}
/*
- * We don't assign an index until we actually place the event onto
- * hardware. Use -1 to signify that we haven't decided where to put it
- * yet. For SMP systems, each core has it's own PMU so we can't do any
- * clever allocation or constraints checking at this point.
- */
- hwc->idx = -1;
-
- /*
- * Store the event encoding into the config_base field. config and
- * event_base are unused as the only 2 things we need to know are
- * the event mapping and the counter to use. The counter to use is
- * also the indx and the config_base is the event type.
+ * Store the event encoding into the config_base field.
*/
- hwc->config_base = (unsigned long)mapping;
- hwc->config = 0;
- hwc->event_base = 0;
+ hwc->config_base |= (unsigned long)mapping;
if (!hwc->sample_period) {
hwc->sample_period = armpmu->max_period;
--
1.7.0.4
^ permalink raw reply related [flat|nested] 19+ messages in thread
* [PATCH 10/10] ARM: perf: add mode exclusion for Cortex-A15 PMU
2011-08-08 17:16 [PATCH 00/10] ARM: perf: updates for 3.2 Will Deacon
` (8 preceding siblings ...)
2011-08-08 17:16 ` [PATCH 09/10] ARM: perf: allow armpmu to implement mode exclusion Will Deacon
@ 2011-08-08 17:16 ` Will Deacon
[not found] ` <CAKHPGBZ1eXzhsjFvLt_KTYKsR_OH7rgbeSGedTY5g8dhi90uzQ@mail.gmail.com>
2011-08-09 9:35 ` [PATCH 00/10] ARM: perf: updates for 3.2 Jamie Iles
10 siblings, 1 reply; 19+ messages in thread
From: Will Deacon @ 2011-08-08 17:16 UTC (permalink / raw)
To: linux-arm-kernel
The Cortex-A15 PMU implements the PMUv2 specification and therefore
has support for some mode exclusion.
This patch adds support for excluding user, kernel and hypervisor counts
from a given event.
Signed-off-by: Will Deacon <will.deacon@arm.com>
---
arch/arm/kernel/perf_event_v7.c | 58 +++++++++++++++++++++++++++++++++------
1 files changed, 49 insertions(+), 9 deletions(-)
diff --git a/arch/arm/kernel/perf_event_v7.c b/arch/arm/kernel/perf_event_v7.c
index 0934c82..fe6c931 100644
--- a/arch/arm/kernel/perf_event_v7.c
+++ b/arch/arm/kernel/perf_event_v7.c
@@ -17,6 +17,9 @@
*/
#ifdef CONFIG_CPU_V7
+
+static struct arm_pmu armv7pmu;
+
/*
* Common ARMv7 event types
*
@@ -709,16 +712,24 @@ static const unsigned armv7_a15_perf_cache_map[PERF_COUNT_HW_CACHE_MAX]
#define ARMV7_PMNC_MASK 0x3f /* Mask for writable bits */
/*
- * EVTSEL: Event selection reg
- */
-#define ARMV7_EVTSEL_MASK 0xff /* Mask for writable bits */
-
-/*
* FLAG: counters overflow flag status reg
*/
#define ARMV7_FLAG_MASK 0xffffffff /* Mask for writable bits */
#define ARMV7_OVERFLOWED_MASK ARMV7_FLAG_MASK
+/*
+ * PMXEVTYPER: Event selection reg
+ */
+#define ARMV7_EVTYPE_MASK 0xc00000ff /* Mask for writable bits */
+#define ARMV7_EVTYPE_EVENT 0xff /* Mask for EVENT bits */
+
+/*
+ * Event filters for PMUv2
+ */
+#define ARMV7_EXCLUDE_PL1 (1 << 31)
+#define ARMV7_EXCLUDE_USER (1 << 30)
+#define ARMV7_INCLUDE_HYP (1 << 27)
+
static inline u32 armv7_pmnc_read(void)
{
u32 val;
@@ -805,7 +816,7 @@ static inline void armv7pmu_write_counter(int idx, u32 value)
static inline void armv7_pmnc_write_evtsel(int idx, u32 val)
{
if (armv7_pmnc_select_counter(idx) == idx) {
- val &= ARMV7_EVTSEL_MASK;
+ val &= ARMV7_EVTYPE_MASK;
asm volatile("mcr p15, 0, %0, c9, c13, 1" : : "r" (val));
}
}
@@ -939,9 +950,10 @@ static void armv7pmu_enable_event(struct hw_perf_event *hwc, int idx)
/*
* Set event (if destined for PMNx counters)
- * We don't need to set the event if it's a cycle count
+ * We only need to set the event for the cycle counter if we
+ * have the ability to perform event filtering.
*/
- if (idx != ARMV7_IDX_CYCLE_COUNTER)
+ if (armv7pmu.set_event_filter || idx != ARMV7_IDX_CYCLE_COUNTER)
armv7_pmnc_write_evtsel(idx, hwc->config_base);
/*
@@ -1066,9 +1078,10 @@ static int armv7pmu_get_event_idx(struct cpu_hw_events *cpuc,
struct hw_perf_event *event)
{
int idx;
+ unsigned long evtype = event->config_base & ARMV7_EVTYPE_EVENT;
/* Always place a cycle counter into the cycle counter. */
- if (event->config_base == ARMV7_PERFCTR_CPU_CYCLES) {
+ if (evtype == ARMV7_PERFCTR_CPU_CYCLES) {
if (test_and_set_bit(ARMV7_IDX_CYCLE_COUNTER, cpuc->used_mask))
return -EAGAIN;
@@ -1088,6 +1101,32 @@ static int armv7pmu_get_event_idx(struct cpu_hw_events *cpuc,
return -EAGAIN;
}
+/*
+ * Add an event filter to a given event. This will only work for PMUv2 PMUs.
+ */
+static int armv7pmu_set_event_filter(struct hw_perf_event *event,
+ struct perf_event_attr *attr)
+{
+ unsigned long config_base = 0;
+
+ if (attr->exclude_idle)
+ return -EPERM;
+ if (attr->exclude_user)
+ config_base |= ARMV7_EXCLUDE_USER;
+ if (attr->exclude_kernel)
+ config_base |= ARMV7_EXCLUDE_PL1;
+ if (!attr->exclude_hv)
+ config_base |= ARMV7_INCLUDE_HYP;
+
+ /*
+ * Install the filter into config_base as this is used to
+ * construct the event type.
+ */
+ event->config_base = config_base;
+
+ return 0;
+}
+
static void armv7pmu_reset(void *info)
{
u32 idx, nb_cnt = armpmu->num_events;
@@ -1162,6 +1201,7 @@ static struct arm_pmu *__init armv7_a15_pmu_init(void)
armv7pmu.cache_map = &armv7_a15_perf_cache_map;
armv7pmu.event_map = &armv7_a15_perf_map;
armv7pmu.num_events = armv7_read_num_pmnc_events();
+ armv7pmu.set_event_filter = armv7pmu_set_event_filter;
return &armv7pmu;
}
#else
--
1.7.0.4
^ permalink raw reply related [flat|nested] 19+ messages in thread
* [PATCH 00/10] ARM: perf: updates for 3.2
2011-08-08 17:16 [PATCH 00/10] ARM: perf: updates for 3.2 Will Deacon
` (9 preceding siblings ...)
2011-08-08 17:16 ` [PATCH 10/10] ARM: perf: add mode exclusion for Cortex-A15 PMU Will Deacon
@ 2011-08-09 9:35 ` Jamie Iles
2011-08-09 9:42 ` Will Deacon
10 siblings, 1 reply; 19+ messages in thread
From: Jamie Iles @ 2011-08-09 9:35 UTC (permalink / raw)
To: linux-arm-kernel
Hi Will,
On Mon, Aug 08, 2011 at 06:16:01PM +0100, Will Deacon wrote:
> Hello,
>
> This patch series contains a number of updates to the ARM PMU and perf
> code so that we can support mode exclusion, which is new in debug
> architecture 7.1 (as implemented by the Cortex-A15). Some of these
> updates also coincide with work to support System PMUs (PMUs that are
> not affine to a single CPU) but that is a larger body of work which will
> be posted separately at a later date.
>
> The patches do the following:
>
> 1.) Greatly simplify the PMU reservation mechanism so that the
> handling of platform_devices is moved into perf.
> 2.) Cleans up the interrupt registration and some of the types used
> to represent events and registers.
> 3.) Moves event indexing to start from zero rather than one, making
> the code more readable and also easier to extend for mode
> exclusion.
> 4.) Adds support for mode exclusion (user / kernel / hyp) and
> implements this for Cortex-A15.
>
> I've been running these patches since 3.0, so they've been tested on
> 1176, 11MPCore, Cortex-A5, Cortex-A9 and Cortex-A15 platforms.
A quick glance through them and they all look nice to me, but I can't
get them to apply to any tree (next and master). It looks like they're
based on a tree with changes to the v7 perf support so I'm guessing it's
your patches with A15 support.
Jamie
^ permalink raw reply [flat|nested] 19+ messages in thread
* [PATCH 00/10] ARM: perf: updates for 3.2
2011-08-09 9:35 ` [PATCH 00/10] ARM: perf: updates for 3.2 Jamie Iles
@ 2011-08-09 9:42 ` Will Deacon
2011-08-09 9:54 ` Jamie Iles
0 siblings, 1 reply; 19+ messages in thread
From: Will Deacon @ 2011-08-09 9:42 UTC (permalink / raw)
To: linux-arm-kernel
On Tue, Aug 09, 2011 at 10:35:05AM +0100, Jamie Iles wrote:
> Hi Will,
Hi Jamie,
> On Mon, Aug 08, 2011 at 06:16:01PM +0100, Will Deacon wrote:
> > Hello,
> >
> > This patch series contains a number of updates to the ARM PMU and perf
> > code so that we can support mode exclusion, which is new in debug
> > architecture 7.1 (as implemented by the Cortex-A15). Some of these
> > updates also coincide with work to support System PMUs (PMUs that are
> > not affine to a single CPU) but that is a larger body of work which will
> > be posted separately at a later date.
> >
> > The patches do the following:
> >
> > 1.) Greatly simplify the PMU reservation mechanism so that the
> > handling of platform_devices is moved into perf.
> > 2.) Cleans up the interrupt registration and some of the types used
> > to represent events and registers.
> > 3.) Moves event indexing to start from zero rather than one, making
> > the code more readable and also easier to extend for mode
> > exclusion.
> > 4.) Adds support for mode exclusion (user / kernel / hyp) and
> > implements this for Cortex-A15.
> >
> > I've been running these patches since 3.0, so they've been tested on
> > 1176, 11MPCore, Cortex-A5, Cortex-A9 and Cortex-A15 platforms.
>
> A quick glance through them and they all look nice to me, but I can't
> get them to apply to any tree (next and master). It looks like they're
> based on a tree with changes to the v7 perf support so I'm guessing it's
> your patches with A15 support.
Thanks for taking a look. The patches should just apply against -rc1:
http://www.linux-arm.org/git?p=linux-2.6-wd.git;a=shortlog;h=refs/heads/perf-updates
Cheers,
Will
^ permalink raw reply [flat|nested] 19+ messages in thread
* [PATCH 00/10] ARM: perf: updates for 3.2
2011-08-09 9:42 ` Will Deacon
@ 2011-08-09 9:54 ` Jamie Iles
2011-08-09 10:01 ` Will Deacon
0 siblings, 1 reply; 19+ messages in thread
From: Jamie Iles @ 2011-08-09 9:54 UTC (permalink / raw)
To: linux-arm-kernel
On Tue, Aug 09, 2011 at 10:42:34AM +0100, Will Deacon wrote:
> On Tue, Aug 09, 2011 at 10:35:05AM +0100, Jamie Iles wrote:
> > Hi Will,
>
> Hi Jamie,
>
> > On Mon, Aug 08, 2011 at 06:16:01PM +0100, Will Deacon wrote:
> > > Hello,
> > >
> > > This patch series contains a number of updates to the ARM PMU and perf
> > > code so that we can support mode exclusion, which is new in debug
> > > architecture 7.1 (as implemented by the Cortex-A15). Some of these
> > > updates also coincide with work to support System PMUs (PMUs that are
> > > not affine to a single CPU) but that is a larger body of work which will
> > > be posted separately at a later date.
> > >
> > > The patches do the following:
> > >
> > > 1.) Greatly simplify the PMU reservation mechanism so that the
> > > handling of platform_devices is moved into perf.
> > > 2.) Cleans up the interrupt registration and some of the types used
> > > to represent events and registers.
> > > 3.) Moves event indexing to start from zero rather than one, making
> > > the code more readable and also easier to extend for mode
> > > exclusion.
> > > 4.) Adds support for mode exclusion (user / kernel / hyp) and
> > > implements this for Cortex-A15.
> > >
> > > I've been running these patches since 3.0, so they've been tested on
> > > 1176, 11MPCore, Cortex-A5, Cortex-A9 and Cortex-A15 platforms.
> >
> > A quick glance through them and they all look nice to me, but I can't
> > get them to apply to any tree (next and master). It looks like they're
> > based on a tree with changes to the v7 perf support so I'm guessing it's
> > your patches with A15 support.
>
> Thanks for taking a look. The patches should just apply against -rc1:
>
> http://www.linux-arm.org/git?p=linux-2.6-wd.git;a=shortlog;h=refs/heads/perf-updates
Yes, you're quite right. I seem to have lost patches 1 and 4. Probably
finger trouble on my part!
Anyhow, I've pulled from your git tree and they appear to work nicely,
so:
Acked-by: Jamie Iles <jamie@jamieiles.com>
Jamie
^ permalink raw reply [flat|nested] 19+ messages in thread
* [PATCH 00/10] ARM: perf: updates for 3.2
2011-08-09 9:54 ` Jamie Iles
@ 2011-08-09 10:01 ` Will Deacon
2011-08-09 10:14 ` Jean Pihet
0 siblings, 1 reply; 19+ messages in thread
From: Will Deacon @ 2011-08-09 10:01 UTC (permalink / raw)
To: linux-arm-kernel
On Tue, Aug 09, 2011 at 10:54:34AM +0100, Jamie Iles wrote:
> On Tue, Aug 09, 2011 at 10:42:34AM +0100, Will Deacon wrote:
> > Thanks for taking a look. The patches should just apply against -rc1:
> >
> > http://www.linux-arm.org/git?p=linux-2.6-wd.git;a=shortlog;h=refs/heads/perf-updates
>
> Yes, you're quite right. I seem to have lost patches 1 and 4. Probably
> finger trouble on my part!
>
> Anyhow, I've pulled from your git tree and they appear to work nicely,
> so:
>
> Acked-by: Jamie Iles <jamie@jamieiles.com>
Thanks a lot Jamie, I'll update that branch with your acks.
Will
^ permalink raw reply [flat|nested] 19+ messages in thread
* [PATCH 00/10] ARM: perf: updates for 3.2
2011-08-09 10:01 ` Will Deacon
@ 2011-08-09 10:14 ` Jean Pihet
2011-08-09 10:52 ` Will Deacon
0 siblings, 1 reply; 19+ messages in thread
From: Jean Pihet @ 2011-08-09 10:14 UTC (permalink / raw)
To: linux-arm-kernel
Hi Will,
I had a review of the patches and they all look all good to me.
Although [06/10] is not easy to look at it seems correct and indeed
the resulting code is easier to read.
Not tested though, sorry ;(
Feel free to add:
Reviewed-by: Jean Pihet <j-pihet@ti.com>
Thanks!
Jean
On Tue, Aug 9, 2011 at 12:01 PM, Will Deacon <will.deacon@arm.com> wrote:
> On Tue, Aug 09, 2011 at 10:54:34AM +0100, Jamie Iles wrote:
>> On Tue, Aug 09, 2011 at 10:42:34AM +0100, Will Deacon wrote:
>> > Thanks for taking a look. The patches should just apply against -rc1:
>> >
>> > http://www.linux-arm.org/git?p=linux-2.6-wd.git;a=shortlog;h=refs/heads/perf-updates
>>
>> Yes, you're quite right. ?I seem to have lost patches 1 and 4. ?Probably
>> finger trouble on my part!
>>
>> Anyhow, I've pulled from your git tree and they appear to work nicely,
>> so:
>>
>> Acked-by: Jamie Iles <jamie@jamieiles.com>
>
> Thanks a lot Jamie, I'll update that branch with your acks.
>
> Will
>
> _______________________________________________
> linux-arm-kernel mailing list
> linux-arm-kernel at lists.infradead.org
> http://lists.infradead.org/mailman/listinfo/linux-arm-kernel
>
^ permalink raw reply [flat|nested] 19+ messages in thread
* [PATCH 00/10] ARM: perf: updates for 3.2
2011-08-09 10:14 ` Jean Pihet
@ 2011-08-09 10:52 ` Will Deacon
0 siblings, 0 replies; 19+ messages in thread
From: Will Deacon @ 2011-08-09 10:52 UTC (permalink / raw)
To: linux-arm-kernel
On Tue, Aug 09, 2011 at 11:14:11AM +0100, Jean Pihet wrote:
> Hi Will,
Hello,
> I had a review of the patches and they all look all good to me.
> Although [06/10] is not easy to look at it seems correct and indeed
> the resulting code is easier to read.
> Not tested though, sorry ;(
Thanks for having a look. If you do get a chance to test, please let me know
how you get on.
> Feel free to add:
> Reviewed-by: Jean Pihet <j-pihet@ti.com>
Will do, cheers.
Will
^ permalink raw reply [flat|nested] 19+ messages in thread
* [PATCH 10/10] ARM: perf: add mode exclusion for Cortex-A15 PMU
[not found] ` <CAKHPGBZ1eXzhsjFvLt_KTYKsR_OH7rgbeSGedTY5g8dhi90uzQ@mail.gmail.com>
@ 2011-08-25 3:09 ` Ashwin Chaugule
2011-08-25 9:51 ` Will Deacon
0 siblings, 1 reply; 19+ messages in thread
From: Ashwin Chaugule @ 2011-08-25 3:09 UTC (permalink / raw)
To: linux-arm-kernel
Hey Will,
> From: Will Deacon <will.deacon@arm.com>
>
> The Cortex-A15 PMU implements the PMUv2 specification and therefore
> has support for some mode exclusion.
>
> This patch adds support for excluding user, kernel and hypervisor counts
> from a given event.
>
> Signed-off-by: Will Deacon <will.deacon@arm.com>
> ---
--8<---
> +
> +/*
> + * Event filters for PMUv2
> + */
> +#define ARMV7_EXCLUDE_PL1 (1 << 31)
> +#define ARMV7_EXCLUDE_USER (1 << 30)
> +#define ARMV7_INCLUDE_HYP (1 << 27)
> +
This mode exclusion stuff is confusing me.
For exclude user mode, shouldn't PMXEVTYPER[PL1,U] = 0b11
With this patch the counters will spin with secure mode activity as well,
if exclude user mode is selected ?
/me goes to bother the h/w guys.
--
Sent by an employee of the Qualcomm Innovation Center, Inc.
The Qualcomm Innovation Center, Inc. is a member of the Code Aurora Forum.
^ permalink raw reply [flat|nested] 19+ messages in thread
* [PATCH 10/10] ARM: perf: add mode exclusion for Cortex-A15 PMU
2011-08-25 3:09 ` Ashwin Chaugule
@ 2011-08-25 9:51 ` Will Deacon
0 siblings, 0 replies; 19+ messages in thread
From: Will Deacon @ 2011-08-25 9:51 UTC (permalink / raw)
To: linux-arm-kernel
On Thu, Aug 25, 2011 at 04:09:13AM +0100, Ashwin Chaugule wrote:
> Hey Will,
Hi Ashwin,
> > From: Will Deacon <will.deacon@arm.com>
> >
> > The Cortex-A15 PMU implements the PMUv2 specification and therefore
> > has support for some mode exclusion.
> >
> > This patch adds support for excluding user, kernel and hypervisor counts
> > from a given event.
> >
> > Signed-off-by: Will Deacon <will.deacon@arm.com>
> > ---
>
>
> --8<---
>
> > +
> > +/*
> > + * Event filters for PMUv2
> > + */
> > +#define ARMV7_EXCLUDE_PL1 (1 << 31)
> > +#define ARMV7_EXCLUDE_USER (1 << 30)
> > +#define ARMV7_INCLUDE_HYP (1 << 27)
> > +
>
> This mode exclusion stuff is confusing me.
I'm not surprised, the wording is pretty hard to follow in the
documentation.
> For exclude user mode, shouldn't PMXEVTYPER[PL1,U] = 0b11
No - this is a reserved encoding and results in the counters stopping for
*all* modes!
> With this patch the counters will spin with secure mode activity as well,
> if exclude user mode is selected ?
Yes, but they won't tick for either secure or non-secure user-mode, which is
what we want. Note that secure software can stop the counters ticking by
messing with the SDER.
> /me goes to bother the h/w guys.
Bah, they deserve it :)
Will
^ permalink raw reply [flat|nested] 19+ messages in thread
end of thread, other threads:[~2011-08-25 9:51 UTC | newest]
Thread overview: 19+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2011-08-08 17:16 [PATCH 00/10] ARM: perf: updates for 3.2 Will Deacon
2011-08-08 17:16 ` [PATCH 01/10] ARM: perf: de-const struct arm_pmu Will Deacon
2011-08-08 17:16 ` [PATCH 02/10] ARM: PMU: move CPU PMU platform device handling and init into perf Will Deacon
2011-08-08 17:16 ` [PATCH 03/10] ARM: perf: use cpumask_t to record active IRQs Will Deacon
2011-08-08 17:16 ` [PATCH 04/10] ARM: perf: use u32 instead of unsigned long for PMNC register Will Deacon
2011-08-08 17:16 ` [PATCH 05/10] ARM: perf: use integers for ARMv7 event indices Will Deacon
2011-08-08 17:16 ` [PATCH 06/10] ARM: perf: index ARMv7 event counters starting from zero Will Deacon
2011-08-08 17:16 ` [PATCH 07/10] ARM: perf: index Xscale and ARMv6 " Will Deacon
2011-08-08 17:16 ` [PATCH 08/10] ARM: perf: index PMU registers " Will Deacon
2011-08-08 17:16 ` [PATCH 09/10] ARM: perf: allow armpmu to implement mode exclusion Will Deacon
2011-08-08 17:16 ` [PATCH 10/10] ARM: perf: add mode exclusion for Cortex-A15 PMU Will Deacon
[not found] ` <CAKHPGBZ1eXzhsjFvLt_KTYKsR_OH7rgbeSGedTY5g8dhi90uzQ@mail.gmail.com>
2011-08-25 3:09 ` Ashwin Chaugule
2011-08-25 9:51 ` Will Deacon
2011-08-09 9:35 ` [PATCH 00/10] ARM: perf: updates for 3.2 Jamie Iles
2011-08-09 9:42 ` Will Deacon
2011-08-09 9:54 ` Jamie Iles
2011-08-09 10:01 ` Will Deacon
2011-08-09 10:14 ` Jean Pihet
2011-08-09 10:52 ` Will Deacon
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).