linux/arch/mips/lib/dump_tlb.c
<<
>>
Prefs
   1/*
   2 * Dump R4x00 TLB for debugging purposes.
   3 *
   4 * Copyright (C) 1994, 1995 by Waldorf Electronics, written by Ralf Baechle.
   5 * Copyright (C) 1999 by Silicon Graphics, Inc.
   6 */
   7#include <linux/kernel.h>
   8#include <linux/mm.h>
   9
  10#include <asm/hazards.h>
  11#include <asm/mipsregs.h>
  12#include <asm/page.h>
  13#include <asm/pgtable.h>
  14#include <asm/tlbdebug.h>
  15
  16void dump_tlb_regs(void)
  17{
  18        const int field = 2 * sizeof(unsigned long);
  19
  20        pr_info("Index    : %0x\n", read_c0_index());
  21        pr_info("PageMask : %0x\n", read_c0_pagemask());
  22        pr_info("EntryHi  : %0*lx\n", field, read_c0_entryhi());
  23        pr_info("EntryLo0 : %0*lx\n", field, read_c0_entrylo0());
  24        pr_info("EntryLo1 : %0*lx\n", field, read_c0_entrylo1());
  25        pr_info("Wired    : %0x\n", read_c0_wired());
  26        switch (current_cpu_type()) {
  27        case CPU_R10000:
  28        case CPU_R12000:
  29        case CPU_R14000:
  30        case CPU_R16000:
  31                pr_info("FrameMask: %0x\n", read_c0_framemask());
  32                break;
  33        }
  34        if (cpu_has_small_pages || cpu_has_rixi || cpu_has_xpa)
  35                pr_info("PageGrain: %0x\n", read_c0_pagegrain());
  36        if (cpu_has_htw) {
  37                pr_info("PWField  : %0*lx\n", field, read_c0_pwfield());
  38                pr_info("PWSize   : %0*lx\n", field, read_c0_pwsize());
  39                pr_info("PWCtl    : %0x\n", read_c0_pwctl());
  40        }
  41}
  42
  43static inline const char *msk2str(unsigned int mask)
  44{
  45        switch (mask) {
  46        case PM_4K:     return "4kb";
  47        case PM_16K:    return "16kb";
  48        case PM_64K:    return "64kb";
  49        case PM_256K:   return "256kb";
  50#ifdef CONFIG_CPU_CAVIUM_OCTEON
  51        case PM_8K:     return "8kb";
  52        case PM_32K:    return "32kb";
  53        case PM_128K:   return "128kb";
  54        case PM_512K:   return "512kb";
  55        case PM_2M:     return "2Mb";
  56        case PM_8M:     return "8Mb";
  57        case PM_32M:    return "32Mb";
  58#endif
  59#ifndef CONFIG_CPU_VR41XX
  60        case PM_1M:     return "1Mb";
  61        case PM_4M:     return "4Mb";
  62        case PM_16M:    return "16Mb";
  63        case PM_64M:    return "64Mb";
  64        case PM_256M:   return "256Mb";
  65        case PM_1G:     return "1Gb";
  66#endif
  67        }
  68        return "";
  69}
  70
  71static void dump_tlb(int first, int last)
  72{
  73        unsigned long s_entryhi, entryhi, asid;
  74        unsigned long long entrylo0, entrylo1, pa;
  75        unsigned int s_index, s_pagemask, pagemask, c0, c1, i;
  76#ifdef CONFIG_32BIT
  77        bool xpa = cpu_has_xpa && (read_c0_pagegrain() & PG_ELPA);
  78        int pwidth = xpa ? 11 : 8;
  79        int vwidth = 8;
  80#else
  81        bool xpa = false;
  82        int pwidth = 11;
  83        int vwidth = 11;
  84#endif
  85
  86        s_pagemask = read_c0_pagemask();
  87        s_entryhi = read_c0_entryhi();
  88        s_index = read_c0_index();
  89        asid = s_entryhi & 0xff;
  90
  91        for (i = first; i <= last; i++) {
  92                write_c0_index(i);
  93                mtc0_tlbr_hazard();
  94                tlb_read();
  95                tlb_read_hazard();
  96                pagemask = read_c0_pagemask();
  97                entryhi  = read_c0_entryhi();
  98                entrylo0 = read_c0_entrylo0();
  99                entrylo1 = read_c0_entrylo1();
 100
 101                /* EHINV bit marks entire entry as invalid */
 102                if (cpu_has_tlbinv && entryhi & MIPS_ENTRYHI_EHINV)
 103                        continue;
 104                /*
 105                 * Prior to tlbinv, unused entries have a virtual address of
 106                 * CKSEG0.
 107                 */
 108                if ((entryhi & ~0x1ffffUL) == CKSEG0)
 109                        continue;
 110                /*
 111                 * ASID takes effect in absence of G (global) bit.
 112                 * We check both G bits, even though architecturally they should
 113                 * match one another, because some revisions of the SB1 core may
 114                 * leave only a single G bit set after a machine check exception
 115                 * due to duplicate TLB entry.
 116                 */
 117                if (!((entrylo0 | entrylo1) & ENTRYLO_G) &&
 118                    (entryhi & 0xff) != asid)
 119                        continue;
 120
 121                /*
 122                 * Only print entries in use
 123                 */
 124                printk("Index: %2d pgmask=%s ", i, msk2str(pagemask));
 125
 126                c0 = (entrylo0 & ENTRYLO_C) >> ENTRYLO_C_SHIFT;
 127                c1 = (entrylo1 & ENTRYLO_C) >> ENTRYLO_C_SHIFT;
 128
 129                printk("va=%0*lx asid=%02lx\n",
 130                       vwidth, (entryhi & ~0x1fffUL),
 131                       entryhi & 0xff);
 132                /* RI/XI are in awkward places, so mask them off separately */
 133                pa = entrylo0 & ~(MIPS_ENTRYLO_RI | MIPS_ENTRYLO_XI);
 134                if (xpa)
 135                        pa |= (unsigned long long)readx_c0_entrylo0() << 30;
 136                pa = (pa << 6) & PAGE_MASK;
 137                printk("\t[");
 138                if (cpu_has_rixi)
 139                        printk("ri=%d xi=%d ",
 140                               (entrylo0 & MIPS_ENTRYLO_RI) ? 1 : 0,
 141                               (entrylo0 & MIPS_ENTRYLO_XI) ? 1 : 0);
 142                printk("pa=%0*llx c=%d d=%d v=%d g=%d] [",
 143                       pwidth, pa, c0,
 144                       (entrylo0 & ENTRYLO_D) ? 1 : 0,
 145                       (entrylo0 & ENTRYLO_V) ? 1 : 0,
 146                       (entrylo0 & ENTRYLO_G) ? 1 : 0);
 147                /* RI/XI are in awkward places, so mask them off separately */
 148                pa = entrylo1 & ~(MIPS_ENTRYLO_RI | MIPS_ENTRYLO_XI);
 149                if (xpa)
 150                        pa |= (unsigned long long)readx_c0_entrylo1() << 30;
 151                pa = (pa << 6) & PAGE_MASK;
 152                if (cpu_has_rixi)
 153                        printk("ri=%d xi=%d ",
 154                               (entrylo1 & MIPS_ENTRYLO_RI) ? 1 : 0,
 155                               (entrylo1 & MIPS_ENTRYLO_XI) ? 1 : 0);
 156                printk("pa=%0*llx c=%d d=%d v=%d g=%d]\n",
 157                       pwidth, pa, c1,
 158                       (entrylo1 & ENTRYLO_D) ? 1 : 0,
 159                       (entrylo1 & ENTRYLO_V) ? 1 : 0,
 160                       (entrylo1 & ENTRYLO_G) ? 1 : 0);
 161        }
 162        printk("\n");
 163
 164        write_c0_entryhi(s_entryhi);
 165        write_c0_index(s_index);
 166        write_c0_pagemask(s_pagemask);
 167}
 168
 169void dump_tlb_all(void)
 170{
 171        dump_tlb(0, current_cpu_data.tlbsize - 1);
 172}
 173