diff options
author | Mark Nelson <markn@au1.ibm.com> | 2010-02-07 11:45:12 -0500 |
---|---|---|
committer | Benjamin Herrenschmidt <benh@kernel.crashing.org> | 2010-02-07 23:29:19 -0500 |
commit | 36350e00696df148507246c817cf6f86329479fd (patch) | |
tree | 2a57c7ae1583006658eea1c35232caf5b7cef7ee /arch | |
parent | 1a45dcfe2525e9432cb4aba461d4994fc2befe42 (diff) |
powerpc/pseries: Fix kexec regression caused by CPPR tracking
The code to track the CPPR values added by commit
49bd3647134ea47420067aea8d1401e722bf2aac ("powerpc/pseries: Track previous
CPPR values to correctly EOI interrupts") broke kexec on pseries because
the kexec code in xics.c calls xics_set_cpu_priority() before the IPI has
been EOI'ed. This wasn't a problem previously but it now triggers a BUG_ON
in xics_set_cpu_priority() because os_cppr->index isn't 0.
Fix this problem by setting the index on the CPPR stack to 0 before calling
xics_set_cpu_priority() in xics_teardown_cpu().
Also make it clear that we only want to set the priority when there's just
one CPPR value in the stack, and enforce it by updating the value of
os_cppr->stack[0] rather than os_cppr->stack[os_cppr->index].
While we're at it change the BUG_ON to a WARN_ON.
Reported-by: Anton Blanchard <anton@samba.org>
Signed-off-by: Mark Nelson <markn@au1.ibm.com>
Signed-off-by: Benjamin Herrenschmidt <benh@kernel.crashing.org>
Diffstat (limited to 'arch')
-rw-r--r-- | arch/powerpc/platforms/pseries/xics.c | 14 |
1 files changed, 12 insertions, 2 deletions
diff --git a/arch/powerpc/platforms/pseries/xics.c b/arch/powerpc/platforms/pseries/xics.c index 1ee66db003be..f5f79196721c 100644 --- a/arch/powerpc/platforms/pseries/xics.c +++ b/arch/powerpc/platforms/pseries/xics.c | |||
@@ -784,9 +784,13 @@ static void xics_set_cpu_priority(unsigned char cppr) | |||
784 | { | 784 | { |
785 | struct xics_cppr *os_cppr = &__get_cpu_var(xics_cppr); | 785 | struct xics_cppr *os_cppr = &__get_cpu_var(xics_cppr); |
786 | 786 | ||
787 | BUG_ON(os_cppr->index != 0); | 787 | /* |
788 | * we only really want to set the priority when there's | ||
789 | * just one cppr value on the stack | ||
790 | */ | ||
791 | WARN_ON(os_cppr->index != 0); | ||
788 | 792 | ||
789 | os_cppr->stack[os_cppr->index] = cppr; | 793 | os_cppr->stack[0] = cppr; |
790 | 794 | ||
791 | if (firmware_has_feature(FW_FEATURE_LPAR)) | 795 | if (firmware_has_feature(FW_FEATURE_LPAR)) |
792 | lpar_cppr_info(cppr); | 796 | lpar_cppr_info(cppr); |
@@ -821,8 +825,14 @@ void xics_setup_cpu(void) | |||
821 | 825 | ||
822 | void xics_teardown_cpu(void) | 826 | void xics_teardown_cpu(void) |
823 | { | 827 | { |
828 | struct xics_cppr *os_cppr = &__get_cpu_var(xics_cppr); | ||
824 | int cpu = smp_processor_id(); | 829 | int cpu = smp_processor_id(); |
825 | 830 | ||
831 | /* | ||
832 | * we have to reset the cppr index to 0 because we're | ||
833 | * not going to return from the IPI | ||
834 | */ | ||
835 | os_cppr->index = 0; | ||
826 | xics_set_cpu_priority(0); | 836 | xics_set_cpu_priority(0); |
827 | 837 | ||
828 | /* Clear any pending IPI request */ | 838 | /* Clear any pending IPI request */ |