2
0
mirror of https://github.com/edk2-porting/linux-next.git synced 2024-12-23 04:34:11 +08:00
linux-next/arch/mips/lib/dump_tlb.c
James Hogan 48269c78fb MIPS: dump_tlb: Take global bit into account
The TLB only matches the ASID when the global bit isn't set, so
dump_tlb() shouldn't really be skipping global entries just because the
ASID doesn't match. Fix the condition to read the TLB entry's global bit
from EntryLo0. Note that after a TLB read the global bits in both
EntryLo registers reflect the same global bit in the TLB entry.

Signed-off-by: James Hogan <james.hogan@imgtec.com>
Cc: Maciej W. Rozycki <macro@linux-mips.org>
Cc: linux-mips@linux-mips.org
Patchwork: https://patchwork.linux-mips.org/patch/10079/
Signed-off-by: Ralf Baechle <ralf@linux-mips.org>
2015-06-21 21:52:35 +02:00

122 lines
3.1 KiB
C

/*
* Dump R4x00 TLB for debugging purposes.
*
* Copyright (C) 1994, 1995 by Waldorf Electronics, written by Ralf Baechle.
* Copyright (C) 1999 by Silicon Graphics, Inc.
*/
#include <linux/kernel.h>
#include <linux/mm.h>
#include <asm/hazards.h>
#include <asm/mipsregs.h>
#include <asm/page.h>
#include <asm/pgtable.h>
#include <asm/tlbdebug.h>
static inline const char *msk2str(unsigned int mask)
{
switch (mask) {
case PM_4K: return "4kb";
case PM_16K: return "16kb";
case PM_64K: return "64kb";
case PM_256K: return "256kb";
#ifdef CONFIG_CPU_CAVIUM_OCTEON
case PM_8K: return "8kb";
case PM_32K: return "32kb";
case PM_128K: return "128kb";
case PM_512K: return "512kb";
case PM_2M: return "2Mb";
case PM_8M: return "8Mb";
case PM_32M: return "32Mb";
#endif
#ifndef CONFIG_CPU_VR41XX
case PM_1M: return "1Mb";
case PM_4M: return "4Mb";
case PM_16M: return "16Mb";
case PM_64M: return "64Mb";
case PM_256M: return "256Mb";
case PM_1G: return "1Gb";
#endif
}
return "";
}
static void dump_tlb(int first, int last)
{
unsigned long s_entryhi, entryhi, asid;
unsigned long long entrylo0, entrylo1;
unsigned int s_index, s_pagemask, pagemask, c0, c1, i;
#ifdef CONFIG_32BIT
int width = 8;
#else
int width = 11;
#endif
s_pagemask = read_c0_pagemask();
s_entryhi = read_c0_entryhi();
s_index = read_c0_index();
asid = s_entryhi & 0xff;
for (i = first; i <= last; i++) {
write_c0_index(i);
mtc0_tlbr_hazard();
tlb_read();
tlb_read_hazard();
pagemask = read_c0_pagemask();
entryhi = read_c0_entryhi();
entrylo0 = read_c0_entrylo0();
entrylo1 = read_c0_entrylo1();
/*
* Prior to tlbinv, unused entries have a virtual address of
* CKSEG0.
*/
if ((entryhi & ~0x1ffffUL) == CKSEG0)
continue;
/*
* ASID takes effect in absence of G (global) bit.
* We check both G bits, even though architecturally they should
* match one another, because some revisions of the SB1 core may
* leave only a single G bit set after a machine check exception
* due to duplicate TLB entry.
*/
if (!((entrylo0 | entrylo1) & MIPS_ENTRYLO_G) &&
(entryhi & 0xff) != asid)
continue;
/*
* Only print entries in use
*/
printk("Index: %2d pgmask=%s ", i, msk2str(pagemask));
c0 = (entrylo0 & MIPS_ENTRYLO_C) >> MIPS_ENTRYLO_C_SHIFT;
c1 = (entrylo1 & MIPS_ENTRYLO_C) >> MIPS_ENTRYLO_C_SHIFT;
printk("va=%0*lx asid=%02lx\n",
width, (entryhi & ~0x1fffUL),
entryhi & 0xff);
printk("\t[pa=%0*llx c=%d d=%d v=%d g=%d] ",
width,
(entrylo0 << 6) & PAGE_MASK, c0,
(entrylo0 & MIPS_ENTRYLO_D) ? 1 : 0,
(entrylo0 & MIPS_ENTRYLO_V) ? 1 : 0,
(entrylo0 & MIPS_ENTRYLO_G) ? 1 : 0);
printk("[pa=%0*llx c=%d d=%d v=%d g=%d]\n",
width,
(entrylo1 << 6) & PAGE_MASK, c1,
(entrylo1 & MIPS_ENTRYLO_D) ? 1 : 0,
(entrylo1 & MIPS_ENTRYLO_V) ? 1 : 0,
(entrylo1 & MIPS_ENTRYLO_G) ? 1 : 0);
}
printk("\n");
write_c0_entryhi(s_entryhi);
write_c0_index(s_index);
write_c0_pagemask(s_pagemask);
}
void dump_tlb_all(void)
{
dump_tlb(0, current_cpu_data.tlbsize - 1);
}