| From 8c42a5c02bec6c7eccf08957be3c6c8fccf9790b Mon Sep 17 00:00:00 2001 |
| From: Vineet Gupta <vgupta@synopsys.com> |
| Date: Thu, 22 Oct 2020 03:16:22 -0700 |
| Subject: ARC: perf: redo the pct irq missing in device-tree handling |
| |
| From: Vineet Gupta <vgupta@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: <stable@vger.kernel.org> |
| Signed-off-by: Vineet Gupta <vgupta@synopsys.com> |
| Signed-off-by: Greg Kroah-Hartman <gregkh@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 |