diff options
Diffstat (limited to 'arch')
-rw-r--r-- | arch/powerpc/kernel/exceptions-64e.S | 9 | ||||
-rw-r--r-- | arch/powerpc/kernel/head_fsl_booke.S | 10 | ||||
-rw-r--r-- | arch/powerpc/kernel/idle.c | 3 | ||||
-rw-r--r-- | arch/powerpc/kernel/time.c | 11 | ||||
-rw-r--r-- | arch/powerpc/platforms/Kconfig.cputype | 42 |
5 files changed, 74 insertions, 1 deletions
diff --git a/arch/powerpc/kernel/exceptions-64e.S b/arch/powerpc/kernel/exceptions-64e.S index 39308c7..5e6a242 100644 --- a/arch/powerpc/kernel/exceptions-64e.S +++ b/arch/powerpc/kernel/exceptions-64e.S @@ -444,6 +444,14 @@ END_FTR_SECTION_IFSET(CPU_FTR_ALTIVEC) fixed_interval, .unknown_exception, ACK_FIT) /* Watchdog Timer Interrupt */ +#ifdef CONFIG_FSL_ERRATUM_A_006184 + START_EXCEPTION(watchdog) + mtspr SPRN_SPRG_CRIT_SCRATCH, r3 + lis r3, TSR_WIS@h + mtspr SPRN_TSR, r3 + mfspr r3, SPRN_SPRG_CRIT_SCRATCH + rfci +#else START_EXCEPTION(watchdog); CRIT_EXCEPTION_PROLOG(0x9f0, BOOKE_INTERRUPT_WATCHDOG, PROLOG_ADDITION_NONE) @@ -454,6 +462,7 @@ END_FTR_SECTION_IFSET(CPU_FTR_ALTIVEC) // bl .unknown_exception // b ret_from_crit_except b . +#endif /* System Call Interrupt */ START_EXCEPTION(system_call) diff --git a/arch/powerpc/kernel/head_fsl_booke.S b/arch/powerpc/kernel/head_fsl_booke.S index 58925b6..987a3f1 100644 --- a/arch/powerpc/kernel/head_fsl_booke.S +++ b/arch/powerpc/kernel/head_fsl_booke.S @@ -369,7 +369,15 @@ interrupt_base: unknown_exception, EXC_XFER_EE) /* Watchdog Timer Interrupt */ -#ifdef CONFIG_BOOKE_WDT +#ifdef CONFIG_FSL_ERRATUM_A_006184 + START_EXCEPTION(WatchdogTimer) + mtspr SPRN_SPRG_WSCRATCH_CRIT, r3 + lis r3, TSR_WIS@h + mtspr SPRN_TSR, r3 + /* use WSCRATCH to avoid any potential problems with KVM paravirt */ + mfspr r3, SPRN_SPRG_WSCRATCH_CRIT + rfci +#elif defined(CONFIG_BOOKE_WDT) CRITICAL_EXCEPTION(0x3200, WATCHDOG, WatchdogTimer, WatchdogException) #else CRITICAL_EXCEPTION(0x3200, WATCHDOG, WatchdogTimer, unknown_exception) diff --git a/arch/powerpc/kernel/idle.c b/arch/powerpc/kernel/idle.c index ea78761..c6ac64b 100644 --- a/arch/powerpc/kernel/idle.c +++ b/arch/powerpc/kernel/idle.c @@ -102,6 +102,9 @@ void cpu_idle(void) ppc64_runlatch_on(); rcu_idle_exit(); tick_nohz_idle_exit(); +#ifdef CONFIG_FSL_ERRATUM_A_006184 + mtspr(SPRN_TSR, TSR_ENW); +#endif if (cpu_should_die()) { sched_preempt_enable_no_resched(); cpu_die(); diff --git a/arch/powerpc/kernel/time.c b/arch/powerpc/kernel/time.c index 127361e..9a9112f 100644 --- a/arch/powerpc/kernel/time.c +++ b/arch/powerpc/kernel/time.c @@ -488,6 +488,9 @@ void timer_interrupt(struct pt_regs * regs) struct clock_event_device *evt = &__get_cpu_var(decrementers); u64 now; +#ifdef CONFIG_FSL_ERRATUM_A_006184 + mtspr(SPRN_TSR, TSR_ENW); +#endif /* Ensure a positive value is written to the decrementer, or else * some CPUs will continue to take decrementer exceptions. */ @@ -638,7 +641,15 @@ void start_cpu_decrementer(void) mtspr(SPRN_TSR, TSR_ENW | TSR_WIS | TSR_DIS | TSR_FIS); /* Enable decrementer interrupt */ +#ifdef CONFIG_FSL_ERRATUM_A_006184 +#define WDTP(x) ((((x)&0x3)<<30)|(((x)&0x3c)<<15)) + { + u32 period = WDTP(CONFIG_FSL_ERRATUM_A_006184_PERIOD); + mtspr(SPRN_TCR, TCR_DIE | TCR_WIE | period); + } +#else mtspr(SPRN_TCR, TCR_DIE); +#endif #endif /* defined(CONFIG_BOOKE) || defined(CONFIG_40x) */ } diff --git a/arch/powerpc/platforms/Kconfig.cputype b/arch/powerpc/platforms/Kconfig.cputype index 421bae9..550ceba 100644 --- a/arch/powerpc/platforms/Kconfig.cputype +++ b/arch/powerpc/platforms/Kconfig.cputype @@ -174,6 +174,48 @@ config PPC_E6500_REV1_BUGS Do not define this if you are running on a simulator or rev2, and want features like hardware tablewalk. +config FSL_ERRATUM_A_006184 + bool "Work around erratum A-006184" + help + Define this to work around erratum A-006184 ("Simultaneous + Instruction L1 MMU miss (due to eviction) and interrupt + servicing can cause a core hang"). This erratum affects + e500v1, e500v2, e500mc, and e5500. The workaround will + cause a watchdog interrupt to occur periodically. It will + not avoid the hang described by the erratum, but it will + recover from it when the next watchdog interrupt expires. + + The normal watchdog functionality cannot be used when this + workaround is enabled. + + If you are running Linux as the guest of a hypervisor, you + should enable this (or a similar workaround) in the host + instead. + + Note that it is believed that it is unlikely that the hang + will be encountered in normal Linux operation. Running KVM + or using hugetlbfs could increase the chance of seeing the + hang. + +config FSL_ERRATUM_A_006184_PERIOD + int "Watchdog period for A-006184 workaround" + range 32 52 + default 43 + help + This is the watchdog period to be used for the A-006184 + workaround. The watchdog will fire whenever the bit selected + transitions from 0 to 1 in the time base. The bits are + numbered with 0 starting at the most-signficant end -- + larger numbers give a more frequent period. + + The period must be set longer than the non-idle decrementer + period, to ensure that the watchdog interrupt only actually + happens when stuck -- but the longer the period, the worse the + latency will be if a hang does occur. Long decrementer + timeouts when idle due to CONFIG_NO_HZ should not be a problem, + since when idle we will always have just executed from the main + kernel mapping, so it should not be absent from the L1 I-MMU. + config FSL_ERRATUM_A_006198 bool "Work around e6500 rev1 erratum A-006198" depends on PPC_E500MC |