Hello,Attached is a patch fixes a problem with the "lazy [aka soft] interrupt disabling" mechanism in the perfmon2 port to the Power architecture. My original solution of using wrapper macros for the spin_*lock* calls was insufficient because interrupts needed to be locked out in more places than perfmon2 itself (e.g. sched()). The solution in this patch is to change the behavior of the interrupt handler so that it sets a cpu-specific flag, clears the PMU interrupt, disables hardware interrupts and returns. When interrupts are reenabled again, the flag is checked and the PMU interrupt is set again. The special wrapper macros are no longer used.
The upside of this change is that it doesn't require any changes to the head_64.S file to change the wrapper used for the PMU exception, and should also fix a potential problem with PMU interrupts being lost (I might have seen this problem before, but I'm not positive).
With this patch, there is still a problem with a kernel hang in a test case I have that generates about 2000 interrupts per second, which then signal a user-space thread. However, the behavior with this patch is improved (doesn't hang as often) and I'm no longer seeing any problems with spin locks.
Please review it and let me know if you see any problems. Thanks for your consideration, - Corey -- Corey Ashford Software Engineer IBM Linux Technology Center, Linux Toolchain Beaverton, OR 503-578-3507 [EMAIL PROTECTED]
diff --git a/arch/powerpc/kernel/irq.c b/arch/powerpc/kernel/irq.c index 2f73f70..cf8dac9 100644 --- a/arch/powerpc/kernel/irq.c +++ b/arch/powerpc/kernel/irq.c @@ -114,6 +114,24 @@ static inline void set_soft_enabled(unsigned long enable) : : "r" (enable), "i" (offsetof(struct paca_struct, soft_enabled))); } +#ifdef CONFIG_PERFMON +static inline unsigned long get_pmu_except_pending(void) +{ + unsigned long pending; + + __asm__ __volatile__("lbz %0,%1(13)" + : "=r" (pending) : "i" (offsetof(struct paca_struct, pmu_except_pending))); + + return pending; +} + +static inline void set_pmu_except_pending(unsigned long pending) +{ + __asm__ __volatile__("stb %0,%1(13)" + : : "r" (pending), "i" (offsetof(struct paca_struct, pmu_except_pending))); +} +#endif /* CONFIG_PERFMON */ + void raw_local_irq_restore(unsigned long en) { /* @@ -172,6 +190,19 @@ void raw_local_irq_restore(unsigned long en) lv1_get_version_info(&tmp); } +#ifdef CONFIG_PERFMON + /* + * If a PMU exception occurred while interrupts were soft disabled, + * force a PMU exception. + */ + if (get_pmu_except_pending()) { + set_pmu_except_pending(0); + /* Make sure we trigger the edge detection circuitry */ + mtspr(SPRN_MMCR0, mfspr(SPRN_MMCR0) & ~MMCR0_PMAO); + mtspr(SPRN_MMCR0, mfspr(SPRN_MMCR0) | MMCR0_PMAO); + } +#endif /* CONFIG_PERFMON */ + __hard_irq_enable(); } EXPORT_SYMBOL(raw_local_irq_restore); diff --git a/arch/powerpc/perfmon/perfmon.c b/arch/powerpc/perfmon/perfmon.c index 17a45fd..b1197d9 100644 --- a/arch/powerpc/perfmon/perfmon.c +++ b/arch/powerpc/perfmon/perfmon.c @@ -287,6 +290,21 @@ void powerpc_irq_handler(struct pt_regs *regs) struct pfm_arch_pmu_info *arch_info; struct pfm_context *ctx; + if (! regs->softe) { + /* + * We got a PMU interrupt while interrupts were soft + * disabled. Disable hardware interrupts by clearing + * MSR_EE and also clear PMAO because we will need to set + * that again later when interrupts are re-enabled and + * raw_local_irq_restore() sees that the pmu_except_pending + * flag is set. + */ + regs->msr &= ~MSR_EE; + get_paca()->pmu_except_pending = 1; + mtspr(SPRN_MMCR0, mfspr(SPRN_MMCR0) & ~MMCR0_PMAO); + return; + } + arch_info = pfm_pmu_info(); if (arch_info->irq_handler) { ctx = __get_cpu_var(pmu_ctx); diff --git a/arch/powerpc/perfmon/perfmon_power4.c b/arch/powerpc/perfmon/perfmon_power4.c index 6ea6dd5..c98a919 100644 diff --git a/include/asm-powerpc/paca.h b/include/asm-powerpc/paca.h index 7b56444..4fa87fc 100644 --- a/include/asm-powerpc/paca.h +++ b/include/asm-powerpc/paca.h @@ -99,6 +99,10 @@ struct paca_struct { u8 soft_enabled; /* irq soft-enable flag */ u8 hard_enabled; /* set if irqs are enabled in MSR */ u8 io_sync; /* writel() needs spin_unlock sync */ +#ifdef CONFIG_PERFMON + u8 pmu_except_pending; /* PMU exception occurred while soft + * disabled */ +#endif /* Stuff for accurate time accounting */ u64 user_time; /* accumulated usermode TB ticks */ diff --git a/include/asm-powerpc/perfmon_kern.h b/include/asm-powerpc/perfmon_kern.h index b3c7d3e..9b0533b 100644 --- a/include/asm-powerpc/perfmon_kern.h +++ b/include/asm-powerpc/perfmon_kern.h @@ -33,55 +33,6 @@ #define HID0_PMC5_6_GR_MODE (1UL << (63 - 40)) -/* - * The Linux port to the POWER architecture has a performance optimization - * where hardware interrupts are disabled not during a call to - * spin_lock_irqsave, but rather sets a cpu-specific flag and if an interrupt - * actually occurs the exception handler wrapper looks at that cpu-specific - * flag, and if it's set, hardware interrupts are disabled, a second - * cpu-specific flag is set indicating hardware interrupts have been disabled, - * and the wrapper returns to the interrupted code, leaving the exceptions - * pending. When the call to spin_unlock_irqrestore is made, that second - * cpu-specific flag is checked, and if it's set, hardware interrupts are - * restored, at which time any pending exceptions will occur. - * - * However, on POWER, this special wrapper is not used because it is - * desirable for oprofile to be able to profile spin_lock_irqsaved code. - * - * To get the best of both worlds, we stick with the original exception - * wrapper and change perfmon's usage of spin_lock_irqsave and - * spin_unlock_irqrestore so that we instead call pfm_spin_lock_irqsave and - * pfm_spin_unlock_irqrestore respectively: - * - * With this change, all other architectures have #defines that map - * pfm_spin_lock_irqsave and pfm_spin_lock_irqrestore back to - * spin_lock_irqsave and spin_lock_irqrestore. - * - * On POWER, the macros are changed such that pfm_spin_lock_irqsave forces the - * state where it does a hardware lockout of interrupts, and sets the - * cpu-specific flags as though we've done a "soft disable" and that an - * exception has already occurred, so that when the [unmodified] - * spin_unlock_irqrestore is called, it will do the right thing by re-enabling - * interrupts. - */ -#undef pfm_spin_lock_irqsave -#define pfm_spin_lock_irqsave(l,f) \ - do { \ - local_irq_save(f); \ - hard_irq_disable(); \ - spin_lock(l); \ - } while(0) - -/* - * on Power, due to lazy masking of the interrupts, we need to convert - * regular spin_lock in spin + mask. This affects context switches and - * interrupt handling - */ -#undef pfm_spin_lock -#define pfm_spin_lock(l, f) pfm_spin_lock_irqsave(l, f) -#undef pfm_spin_unlock -#define pfm_spin_unlock(l, f) pfm_spin_unlock_irqrestore(l, f) - enum powerpc_pmu_type { PFM_POWERPC_PMU_NONE, PFM_POWERPC_PMU_604,
------------------------------------------------------------------------- This SF.net email is sponsored by: Microsoft Defy all challenges. Microsoft(R) Visual Studio 2008. http://clk.atdmt.com/MRT/go/vse0120000070mrt/direct/01/
_______________________________________________ perfmon2-devel mailing list perfmon2-devel@lists.sourceforge.net https://lists.sourceforge.net/lists/listinfo/perfmon2-devel