Skip to content

Commit

Permalink
powerpc/mce: Fix MCE handling for huge pages
Browse files Browse the repository at this point in the history
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: ba41e1e ("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
  • Loading branch information
Balbir Singh authored and Michael Ellerman committed Aug 21, 2019
1 parent b5bda62 commit 99ead78
Showing 1 changed file with 13 additions and 6 deletions.
19 changes: 13 additions & 6 deletions arch/powerpc/kernel/mce_power.c
Original file line number Diff line number Diff line change
Expand Up @@ -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;

Expand All @@ -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);
}

Expand Down Expand Up @@ -344,7 +350,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)
{
/*
Expand Down Expand Up @@ -541,7 +547,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;
}
Expand Down

0 comments on commit 99ead78

Please sign in to comment.