aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorWill Deacon <will.deacon@arm.com>2012-03-06 11:34:50 -0500
committerRussell King <rmk+kernel@arm.linux.org.uk>2012-03-07 04:40:49 -0500
commitf6f5a30c834135c9f2fa10400c59ebbdd9188567 (patch)
tree208358216772eedab5998070878db55df5d4e772
parent99c1745b9c76910e195889044f914b4898b7c9a5 (diff)
ARM: 7356/1: perf: check that we have an event in the PMU IRQ handlers
The PMU IRQ handlers in perf assume that if a counter has overflowed then perf must be responsible. In the paranoid world of crazy hardware, this could be false, so check that we do have a valid event before attempting to dereference NULL in the interrupt path. Cc: <stable@vger.kernel.org> Signed-off-by: Ming Lei <tom.leiming@gmail.com> Signed-off-by: Will Deacon <will.deacon@arm.com> Signed-off-by: Russell King <rmk+kernel@arm.linux.org.uk>
-rw-r--r--arch/arm/kernel/perf_event_v6.c20
-rw-r--r--arch/arm/kernel/perf_event_v7.c4
-rw-r--r--arch/arm/kernel/perf_event_xscale.c6
3 files changed, 12 insertions, 18 deletions
diff --git a/arch/arm/kernel/perf_event_v6.c b/arch/arm/kernel/perf_event_v6.c
index 88bf15253fbd..b78af0cc6ef3 100644
--- a/arch/arm/kernel/perf_event_v6.c
+++ b/arch/arm/kernel/perf_event_v6.c
@@ -467,23 +467,6 @@ armv6pmu_enable_event(struct hw_perf_event *hwc,
467 raw_spin_unlock_irqrestore(&events->pmu_lock, flags); 467 raw_spin_unlock_irqrestore(&events->pmu_lock, flags);
468} 468}
469 469
470static int counter_is_active(unsigned long pmcr, int idx)
471{
472 unsigned long mask = 0;
473 if (idx == ARMV6_CYCLE_COUNTER)
474 mask = ARMV6_PMCR_CCOUNT_IEN;
475 else if (idx == ARMV6_COUNTER0)
476 mask = ARMV6_PMCR_COUNT0_IEN;
477 else if (idx == ARMV6_COUNTER1)
478 mask = ARMV6_PMCR_COUNT1_IEN;
479
480 if (mask)
481 return pmcr & mask;
482
483 WARN_ONCE(1, "invalid counter number (%d)\n", idx);
484 return 0;
485}
486
487static irqreturn_t 470static irqreturn_t
488armv6pmu_handle_irq(int irq_num, 471armv6pmu_handle_irq(int irq_num,
489 void *dev) 472 void *dev)
@@ -513,7 +496,8 @@ armv6pmu_handle_irq(int irq_num,
513 struct perf_event *event = cpuc->events[idx]; 496 struct perf_event *event = cpuc->events[idx];
514 struct hw_perf_event *hwc; 497 struct hw_perf_event *hwc;
515 498
516 if (!counter_is_active(pmcr, idx)) 499 /* Ignore if we don't have an event. */
500 if (!event)
517 continue; 501 continue;
518 502
519 /* 503 /*
diff --git a/arch/arm/kernel/perf_event_v7.c b/arch/arm/kernel/perf_event_v7.c
index 050cc8bf7246..4d7095af2ab3 100644
--- a/arch/arm/kernel/perf_event_v7.c
+++ b/arch/arm/kernel/perf_event_v7.c
@@ -960,6 +960,10 @@ static irqreturn_t armv7pmu_handle_irq(int irq_num, void *dev)
960 struct perf_event *event = cpuc->events[idx]; 960 struct perf_event *event = cpuc->events[idx];
961 struct hw_perf_event *hwc; 961 struct hw_perf_event *hwc;
962 962
963 /* Ignore if we don't have an event. */
964 if (!event)
965 continue;
966
963 /* 967 /*
964 * We have a single interrupt for all counters. Check that 968 * We have a single interrupt for all counters. Check that
965 * each counter has overflowed before we process it. 969 * each counter has overflowed before we process it.
diff --git a/arch/arm/kernel/perf_event_xscale.c b/arch/arm/kernel/perf_event_xscale.c
index 831e019b017c..a5bbd360cc4b 100644
--- a/arch/arm/kernel/perf_event_xscale.c
+++ b/arch/arm/kernel/perf_event_xscale.c
@@ -255,6 +255,9 @@ xscale1pmu_handle_irq(int irq_num, void *dev)
255 struct perf_event *event = cpuc->events[idx]; 255 struct perf_event *event = cpuc->events[idx];
256 struct hw_perf_event *hwc; 256 struct hw_perf_event *hwc;
257 257
258 if (!event)
259 continue;
260
258 if (!xscale1_pmnc_counter_has_overflowed(pmnc, idx)) 261 if (!xscale1_pmnc_counter_has_overflowed(pmnc, idx))
259 continue; 262 continue;
260 263
@@ -592,6 +595,9 @@ xscale2pmu_handle_irq(int irq_num, void *dev)
592 struct perf_event *event = cpuc->events[idx]; 595 struct perf_event *event = cpuc->events[idx];
593 struct hw_perf_event *hwc; 596 struct hw_perf_event *hwc;
594 597
598 if (!event)
599 continue;
600
595 if (!xscale2_pmnc_counter_has_overflowed(pmnc, idx)) 601 if (!xscale2_pmnc_counter_has_overflowed(pmnc, idx))
596 continue; 602 continue;
597 603