<html><head></head><body dir="auto" style="word-wrap: break-word; -webkit-nbsp-mode: space; line-break: after-white-space;" class="ApplePlainTextBody"><div class="ApplePlainTextBody"><br><br><blockquote type="cite">On 30-Jan-2021, at 6:38 PM, Nicholas Piggin <npiggin@gmail.com> wrote:<br><br>This is required in order to allow more significant differences between<br>NMI type interrupt handlers and regular asynchronous handlers.<br><br>Signed-off-by: Nicholas Piggin <npiggin@gmail.com><br>---<br>arch/powerpc/kernel/traps.c      | 31 +++++++++++++++++++++++++++-<br>arch/powerpc/perf/core-book3s.c  | 35 ++------------------------------<br>arch/powerpc/perf/core-fsl-emb.c | 25 -----------------------<br>3 files changed, 32 insertions(+), 59 deletions(-)<br><br>diff --git a/arch/powerpc/kernel/traps.c b/arch/powerpc/kernel/traps.c<br>index 4349b25807cf..6da3a3642dfb 100644<br>--- a/arch/powerpc/kernel/traps.c<br>+++ b/arch/powerpc/kernel/traps.c<br>@@ -1892,11 +1892,40 @@ void vsx_unavailable_tm(struct pt_regs *regs)<br>}<br>#endif /* CONFIG_PPC_TRANSACTIONAL_MEM */<br><br>-void performance_monitor_exception(struct pt_regs *regs)<br>+static void performance_monitor_exception_nmi(struct pt_regs *regs)<br>+{<br>+<span class="Apple-tab-span" style="white-space:pre">   </span>nmi_enter();<br>+<br>+<span class="Apple-tab-span" style="white-space:pre">  </span>__this_cpu_inc(irq_stat.pmu_irqs);<br>+<br>+<span class="Apple-tab-span" style="white-space:pre">    </span>perf_irq(regs);<br>+<br>+<span class="Apple-tab-span" style="white-space:pre">       </span>nmi_exit();<br>+}<br>+<br>+static void performance_monitor_exception_async(struct pt_regs *regs)<br>{<br>+<span class="Apple-tab-span" style="white-space:pre">    </span>irq_enter();<br>+<br><span class="Apple-tab-span" style="white-space:pre">   </span>__this_cpu_inc(irq_stat.pmu_irqs);<br><br><span class="Apple-tab-span" style="white-space:pre">      </span>perf_irq(regs);<br>+<br>+<span class="Apple-tab-span" style="white-space:pre">       </span>irq_exit();<br>+}<br>+<br>+void performance_monitor_exception(struct pt_regs *regs)<br>+{<br>+<span class="Apple-tab-span" style="white-space:pre">        </span>/*<br>+<span class="Apple-tab-span" style="white-space:pre">       </span> * On 64-bit, if perf interrupts hit in a local_irq_disable<br>+<span class="Apple-tab-span" style="white-space:pre">      </span> * (soft-masked) region, we consider them as NMIs. This is required to<br>+<span class="Apple-tab-span" style="white-space:pre">   </span> * prevent hash faults on user addresses when reading callchains (and<br>+<span class="Apple-tab-span" style="white-space:pre">    </span> * looks better from an irq tracing perspective).<br>+<span class="Apple-tab-span" style="white-space:pre">        </span> */<br>+<span class="Apple-tab-span" style="white-space:pre">      </span>if (IS_ENABLED(CONFIG_PPC64) && unlikely(arch_irq_disabled_regs(regs)))<br>+<span class="Apple-tab-span" style="white-space:pre">  </span><span class="Apple-tab-span" style="white-space:pre">    </span>performance_monitor_exception_nmi(regs);<br>+<span class="Apple-tab-span" style="white-space:pre"> </span>else<br>+<span class="Apple-tab-span" style="white-space:pre">     </span><span class="Apple-tab-span" style="white-space:pre">    </span>performance_monitor_exception_async(regs);<br>}<br><br></blockquote><br>Hi Nick,<br>Thanks for the change in tracing of PMI interrupts.<br><br>I tested with this patch that moves perf irq/nmi handling details into traps.c<br>and verified the patch works fine for NMI and asynchronous cases.<br><br>Test scenario1: My test kernel module tries to create one of performance monitor<br>counter overflow between local_irq_save/local_irq_restore which should be delivered as an NMI.<br><br>Verified it calls NMI exception handler from my ftrace logs below<br><br><<>><br>dummy_perf <-performance_monitor_exception_nmi<br><<>><br><br>Test scenario2: My test kernel module tries to create one of performance monitor counter<br>overflow between powerpc_local_irq_pmu_save/restore which should be delivered as an<br>asynchronous interrupt ( replayed PMI ).<br><br>Verified it calls correct handler from my ftrace logs:<br><br><<>><br>replay_soft_interrupts <-arch_local_irq_restore<br>irq_enter <-performance_monitor_exception_async<br>irq_enter_rcu <-performance_monitor_exception_async<br>dummy_perf <-performance_monitor_exception_async<br>irq_exit <-performance_monitor_exception_async<br><<>><br><br>Reviewed-and-Tested-by:  Athira Rajeev <atrajeev@linux.vnet.ibm.com><br><br><br><blockquote type="cite">#ifdef CONFIG_PPC_ADV_DEBUG_REGS<br>diff --git a/arch/powerpc/perf/core-book3s.c b/arch/powerpc/perf/core-book3s.c<br>index 28206b1fe172..9fd06010e8b6 100644<br>--- a/arch/powerpc/perf/core-book3s.c<br>+++ b/arch/powerpc/perf/core-book3s.c<br>@@ -110,10 +110,6 @@ static inline void perf_read_regs(struct pt_regs *regs)<br>{<br><span class="Apple-tab-span" style="white-space:pre">    </span>regs->result = 0;<br>}<br>-static inline int perf_intr_is_nmi(struct pt_regs *regs)<br>-{<br>-<span class="Apple-tab-span" style="white-space:pre">   </span>return 0;<br>-}<br><br>static inline int siar_valid(struct pt_regs *regs)<br>{<br>@@ -353,15 +349,6 @@ static inline void perf_read_regs(struct pt_regs *regs)<br><span class="Apple-tab-span" style="white-space:pre">      </span>regs->result = use_siar;<br>}<br><br>-/*<br>- * If interrupts were soft-disabled when a PMU interrupt occurs, treat<br>- * it as an NMI.<br>- */<br>-static inline int perf_intr_is_nmi(struct pt_regs *regs)<br>-{<br>-<span class="Apple-tab-span" style="white-space:pre">   </span>return (regs->softe & IRQS_DISABLED);<br>-}<br>-<br>/*<br> * On processors like P7+ that have the SIAR-Valid bit, marked instructions<br> * must be sampled only if the SIAR-valid bit is set.<br>@@ -2279,7 +2266,6 @@ static void __perf_event_interrupt(struct pt_regs *regs)<br><span class="Apple-tab-span" style="white-space:pre">       </span>struct perf_event *event;<br><span class="Apple-tab-span" style="white-space:pre"> </span>unsigned long val[8];<br><span class="Apple-tab-span" style="white-space:pre">     </span>int found, active;<br>-<span class="Apple-tab-span" style="white-space:pre">       </span>int nmi;<br><br><span class="Apple-tab-span" style="white-space:pre">        </span>if (cpuhw->n_limited)<br><span class="Apple-tab-span" style="white-space:pre">  </span><span class="Apple-tab-span" style="white-space:pre">    </span>freeze_limited_counters(cpuhw, mfspr(SPRN_PMC5),<br>@@ -2287,18 +2273,6 @@ static void __perf_event_interrupt(struct pt_regs *regs)<br><br><span class="Apple-tab-span" style="white-space:pre">       </span>perf_read_regs(regs);<br><br>-<span class="Apple-tab-span" style="white-space:pre">  </span>/*<br>-<span class="Apple-tab-span" style="white-space:pre">       </span> * If perf interrupts hit in a local_irq_disable (soft-masked) region,<br>-<span class="Apple-tab-span" style="white-space:pre">   </span> * we consider them as NMIs. This is required to prevent hash faults on<br>-<span class="Apple-tab-span" style="white-space:pre">  </span> * user addresses when reading callchains. See the NMI test in<br>-<span class="Apple-tab-span" style="white-space:pre">   </span> * do_hash_page.<br>-<span class="Apple-tab-span" style="white-space:pre"> </span> */<br>-<span class="Apple-tab-span" style="white-space:pre">      </span>nmi = perf_intr_is_nmi(regs);<br>-<span class="Apple-tab-span" style="white-space:pre">    </span>if (nmi)<br>-<span class="Apple-tab-span" style="white-space:pre"> </span><span class="Apple-tab-span" style="white-space:pre">    </span>nmi_enter();<br>-<span class="Apple-tab-span" style="white-space:pre">     </span>else<br>-<span class="Apple-tab-span" style="white-space:pre">     </span><span class="Apple-tab-span" style="white-space:pre">    </span>irq_enter();<br>-<br><span class="Apple-tab-span" style="white-space:pre">   </span>/* Read all the PMCs since we'll need them a bunch of times */<br><span class="Apple-tab-span" style="white-space:pre">    </span>for (i = 0; i < ppmu->n_counter; ++i)<br><span class="Apple-tab-span" style="white-space:pre">       </span><span class="Apple-tab-span" style="white-space:pre">    </span>val[i] = read_pmc(i + 1);<br>@@ -2344,8 +2318,8 @@ static void __perf_event_interrupt(struct pt_regs *regs)<br><span class="Apple-tab-span" style="white-space:pre"> </span><span class="Apple-tab-span" style="white-space:pre">    </span><span class="Apple-tab-span" style="white-space:pre">    </span>}<br><span class="Apple-tab-span" style="white-space:pre"> </span><span class="Apple-tab-span" style="white-space:pre">    </span>}<br><span class="Apple-tab-span" style="white-space:pre"> </span>}<br>-<span class="Apple-tab-span" style="white-space:pre">        </span>if (!found && !nmi && printk_ratelimit())<br>-<span class="Apple-tab-span" style="white-space:pre">        </span><span class="Apple-tab-span" style="white-space:pre">    </span>printk(KERN_WARNING "Can't find PMC that caused IRQ\n");<br>+<span class="Apple-tab-span" style="white-space:pre">       </span>if (unlikely(!found) && !arch_irq_disabled_regs(regs))<br>+<span class="Apple-tab-span" style="white-space:pre">   </span><span class="Apple-tab-span" style="white-space:pre">    </span>printk_ratelimited(KERN_WARNING "Can't find PMC that caused IRQ\n");<br><br><span class="Apple-tab-span" style="white-space:pre">  </span>/*<br><span class="Apple-tab-span" style="white-space:pre">        </span> * Reset MMCR0 to its normal value.  This will set PMXE and<br>@@ -2355,11 +2329,6 @@ static void __perf_event_interrupt(struct pt_regs *regs)<br><span class="Apple-tab-span" style="white-space:pre"> </span> * we get back out of this interrupt.<br><span class="Apple-tab-span" style="white-space:pre">     </span> */<br><span class="Apple-tab-span" style="white-space:pre">       </span>write_mmcr0(cpuhw, cpuhw->mmcr.mmcr0);<br>-<br>-<span class="Apple-tab-span" style="white-space:pre">     </span>if (nmi)<br>-<span class="Apple-tab-span" style="white-space:pre"> </span><span class="Apple-tab-span" style="white-space:pre">    </span>nmi_exit();<br>-<span class="Apple-tab-span" style="white-space:pre">      </span>else<br>-<span class="Apple-tab-span" style="white-space:pre">     </span><span class="Apple-tab-span" style="white-space:pre">    </span>irq_exit();<br>}<br><br>static void perf_event_interrupt(struct pt_regs *regs)<br>diff --git a/arch/powerpc/perf/core-fsl-emb.c b/arch/powerpc/perf/core-fsl-emb.c<br>index e0e7e276bfd2..ee721f420a7b 100644<br>--- a/arch/powerpc/perf/core-fsl-emb.c<br>+++ b/arch/powerpc/perf/core-fsl-emb.c<br>@@ -31,19 +31,6 @@ static atomic_t num_events;<br>/* Used to avoid races in calling reserve/release_pmc_hardware */<br>static DEFINE_MUTEX(pmc_reserve_mutex);<br><br>-/*<br>- * If interrupts were soft-disabled when a PMU interrupt occurs, treat<br>- * it as an NMI.<br>- */<br>-static inline int perf_intr_is_nmi(struct pt_regs *regs)<br>-{<br>-#ifdef __powerpc64__<br>-<span class="Apple-tab-span" style="white-space:pre">   </span>return (regs->softe & IRQS_DISABLED);<br>-#else<br>-<span class="Apple-tab-span" style="white-space:pre">     </span>return 0;<br>-#endif<br>-}<br>-<br>static void perf_event_interrupt(struct pt_regs *regs);<br><br>/*<br>@@ -659,13 +646,6 @@ static void perf_event_interrupt(struct pt_regs *regs)<br><span class="Apple-tab-span" style="white-space:pre">     </span>struct perf_event *event;<br><span class="Apple-tab-span" style="white-space:pre"> </span>unsigned long val;<br><span class="Apple-tab-span" style="white-space:pre">        </span>int found = 0;<br>-<span class="Apple-tab-span" style="white-space:pre">   </span>int nmi;<br>-<br>-<span class="Apple-tab-span" style="white-space:pre">      </span>nmi = perf_intr_is_nmi(regs);<br>-<span class="Apple-tab-span" style="white-space:pre">    </span>if (nmi)<br>-<span class="Apple-tab-span" style="white-space:pre"> </span><span class="Apple-tab-span" style="white-space:pre">    </span>nmi_enter();<br>-<span class="Apple-tab-span" style="white-space:pre">     </span>else<br>-<span class="Apple-tab-span" style="white-space:pre">     </span><span class="Apple-tab-span" style="white-space:pre">    </span>irq_enter();<br><br><span class="Apple-tab-span" style="white-space:pre">    </span>for (i = 0; i < ppmu->n_counter; ++i) {<br><span class="Apple-tab-span" style="white-space:pre">     </span><span class="Apple-tab-span" style="white-space:pre">    </span>event = cpuhw->event[i];<br>@@ -690,11 +670,6 @@ static void perf_event_interrupt(struct pt_regs *regs)<br><span class="Apple-tab-span" style="white-space:pre">  </span>mtmsr(mfmsr() | MSR_PMM);<br><span class="Apple-tab-span" style="white-space:pre"> </span>mtpmr(PMRN_PMGC0, PMGC0_PMIE | PMGC0_FCECE);<br><span class="Apple-tab-span" style="white-space:pre">      </span>isync();<br>-<br>-<span class="Apple-tab-span" style="white-space:pre">      </span>if (nmi)<br>-<span class="Apple-tab-span" style="white-space:pre"> </span><span class="Apple-tab-span" style="white-space:pre">    </span>nmi_exit();<br>-<span class="Apple-tab-span" style="white-space:pre">      </span>else<br>-<span class="Apple-tab-span" style="white-space:pre">     </span><span class="Apple-tab-span" style="white-space:pre">    </span>irq_exit();<br>}<br><br>void hw_perf_event_setup(int cpu)<br>-- <br>2.23.0<br><br></blockquote><br></div></body></html>