From: Vineet Gupta <vgu...@synopsys.com>

commit 8c42a5c02bec6c7eccf08957be3c6c8fccf9790b upstream.

commit feb92d7d3813456c11dce21 "(ARC: perf: don't bail setup if pct irq
missing in device-tree)" introduced a silly brown-paper bag bug:
The assignment and comparison in an if statement were not bracketed
correctly leaving the order of evaluation undefined.

|
| if (has_interrupts && (irq = platform_get_irq(pdev, 0) >= 0)) {
|                           ^^^                         ^^^^

And given such a chance, the compiler will bite you hard, fully entitled
to generating this piece of beauty:

|
| # if (has_interrupts && (irq = platform_get_irq(pdev, 0) >= 0)) {
|
| bl.d @platform_get_irq  <-- irq returned in r0
|
| setge r2, r0, 0       <-- r2 is bool 1 or 0 if irq >= 0 true/false
| brlt.d r0, 0, @.L114
|
| st_s  r2,[sp]         <-- irq saved is bool 1 or 0, not actual return val
| st    1,[r3,160]      # arc_pmu.18_29->irq <-- drops bool and assumes 1
|
| # return __request_percpu_irq(irq, handler, 0,
|
| bl.d @__request_percpu_irq;
| mov_s r0,1       <-- drops even bool and assumes 1 which fails

With the snafu fixed, everything is as expected.

| bl.d @platform_get_irq        <-- returns irq in r0
|
| mov_s r2,r0
| brlt.d r2, 0, @.L112
|
| st_s  r0,[sp]                 <-- irq isaved is actual return value above
| st    r0,[r13,160]    #arc_pmu.18_27->irq
|
| bl.d @__request_percpu_irq    <-- r0 unchanged so actual irq returned
| add r4,r4,r12 #, tmp363, __ptr

Cc: <sta...@vger.kernel.org>
Signed-off-by: Vineet Gupta <vgu...@synopsys.com>
Signed-off-by: Greg Kroah-Hartman <gre...@linuxfoundation.org>

---
 arch/arc/kernel/perf_event.c |   29 +++++++++++++++++++----------
 1 file changed, 19 insertions(+), 10 deletions(-)

--- a/arch/arc/kernel/perf_event.c
+++ b/arch/arc/kernel/perf_event.c
@@ -562,7 +562,7 @@ static int arc_pmu_device_probe(struct p
 {
        struct arc_reg_pct_build pct_bcr;
        struct arc_reg_cc_build cc_bcr;
-       int i, has_interrupts, irq;
+       int i, has_interrupts, irq = -1;
        int counter_size;       /* in bits */
 
        union cc_name {
@@ -637,18 +637,27 @@ static int arc_pmu_device_probe(struct p
                .attr_groups    = arc_pmu->attr_groups,
        };
 
-       if (has_interrupts && (irq = platform_get_irq(pdev, 0) >= 0)) {
+       if (has_interrupts) {
+               irq = platform_get_irq(pdev, 0);
+               if (irq >= 0) {
+                       int ret;
+
+                       arc_pmu->irq = irq;
+
+                       /* intc map function ensures irq_set_percpu_devid() 
called */
+                       ret = request_percpu_irq(irq, arc_pmu_intr, "ARC perf 
counters",
+                                                this_cpu_ptr(&arc_pmu_cpu));
+
+                       if (!ret)
+                               on_each_cpu(arc_cpu_pmu_irq_init, &irq, 1);
+                       else
+                               irq = -1;
+               }
 
-               arc_pmu->irq = irq;
-
-               /* intc map function ensures irq_set_percpu_devid() called */
-               request_percpu_irq(irq, arc_pmu_intr, "ARC perf counters",
-                                  this_cpu_ptr(&arc_pmu_cpu));
+       }
 
-               on_each_cpu(arc_cpu_pmu_irq_init, &irq, 1);
-       } else {
+       if (irq == -1)
                arc_pmu->pmu.capabilities |= PERF_PMU_CAP_NO_INTERRUPT;
-       }
 
        /*
         * perf parser doesn't really like '-' symbol in events name, so let's


Reply via email to