| From 40f760b382b2eabea385881df704cf12ec584668 Mon Sep 17 00:00:00 2001 |
| From: Balbir Singh <bsingharora@gmail.com> |
| Date: Tue, 20 Aug 2019 13:43:47 +0530 |
| Subject: [PATCH] powerpc/mce: Fix MCE handling for huge pages |
| |
| commit 99ead78afd1128bfcebe7f88f3b102fb2da09aee upstream. |
| |
| The current code would fail on huge pages addresses, since the shift would |
| be incorrect. Use the correct page shift value returned by |
| __find_linux_pte() to get the correct physical address. The code is more |
| generic and can handle both regular and compound pages. |
| |
| Fixes: ba41e1e1ccb9 ("powerpc/mce: Hookup derror (load/store) UE errors") |
| Signed-off-by: Balbir Singh <bsingharora@gmail.com> |
| [arbab@linux.ibm.com: Fixup pseries_do_memory_failure()] |
| Signed-off-by: Reza Arbab <arbab@linux.ibm.com> |
| Tested-by: Mahesh Salgaonkar <mahesh@linux.vnet.ibm.com> |
| Signed-off-by: Santosh Sivaraj <santosh@fossix.org> |
| Cc: stable@vger.kernel.org # v4.15+ |
| Signed-off-by: Michael Ellerman <mpe@ellerman.id.au> |
| Link: https://lore.kernel.org/r/20190820081352.8641-3-santosh@fossix.org |
| Signed-off-by: Paul Gortmaker <paul.gortmaker@windriver.com> |
| |
| diff --git a/arch/powerpc/kernel/mce_power.c b/arch/powerpc/kernel/mce_power.c |
| index e39536aad30d..2177492dd2f6 100644 |
| --- a/arch/powerpc/kernel/mce_power.c |
| +++ b/arch/powerpc/kernel/mce_power.c |
| @@ -26,6 +26,7 @@ |
| unsigned long addr_to_pfn(struct pt_regs *regs, unsigned long addr) |
| { |
| pte_t *ptep; |
| + unsigned int shift; |
| unsigned long flags; |
| struct mm_struct *mm; |
| |
| @@ -35,13 +36,18 @@ unsigned long addr_to_pfn(struct pt_regs *regs, unsigned long addr) |
| mm = &init_mm; |
| |
| local_irq_save(flags); |
| - if (mm == current->mm) |
| - ptep = find_current_mm_pte(mm->pgd, addr, NULL, NULL); |
| - else |
| - ptep = find_init_mm_pte(addr, NULL); |
| + ptep = __find_linux_pte(mm->pgd, addr, NULL, &shift); |
| local_irq_restore(flags); |
| + |
| if (!ptep || pte_special(*ptep)) |
| return ULONG_MAX; |
| + |
| + if (shift > PAGE_SHIFT) { |
| + unsigned long rpnmask = (1ul << shift) - PAGE_SIZE; |
| + |
| + return pte_pfn(__pte(pte_val(*ptep) | (addr & rpnmask))); |
| + } |
| + |
| return pte_pfn(*ptep); |
| } |
| |
| @@ -345,7 +351,7 @@ static const struct mce_derror_table mce_p9_derror_table[] = { |
| MCE_INITIATOR_CPU, MCE_SEV_SEVERE, true }, |
| { 0, false, 0, 0, 0, 0, 0 } }; |
| |
| -static int mce_find_instr_ea_and_pfn(struct pt_regs *regs, uint64_t *addr, |
| +static int mce_find_instr_ea_and_phys(struct pt_regs *regs, uint64_t *addr, |
| uint64_t *phys_addr) |
| { |
| /* |
| @@ -542,7 +548,8 @@ static int mce_handle_derror(struct pt_regs *regs, |
| * kernel/exception-64s.h |
| */ |
| if (get_paca()->in_mce < MAX_MCE_DEPTH) |
| - mce_find_instr_ea_and_pfn(regs, addr, phys_addr); |
| + mce_find_instr_ea_and_phys(regs, addr, |
| + phys_addr); |
| } |
| found = 1; |
| } |
| -- |
| 2.7.4 |
| |