Back to home page

OSCL-LXR

 
 

    


0001 // SPDX-License-Identifier: GPL-2.0
0002 /*
0003  * Dump R4x00 TLB for debugging purposes.
0004  *
0005  * Copyright (C) 1994, 1995 by Waldorf Electronics, written by Ralf Baechle.
0006  * Copyright (C) 1999 by Silicon Graphics, Inc.
0007  */
0008 #include <linux/kernel.h>
0009 #include <linux/mm.h>
0010 
0011 #include <asm/hazards.h>
0012 #include <asm/mipsregs.h>
0013 #include <asm/mmu_context.h>
0014 #include <asm/page.h>
0015 #include <asm/tlbdebug.h>
0016 
0017 void dump_tlb_regs(void)
0018 {
0019     const int field = 2 * sizeof(unsigned long);
0020 
0021     pr_info("Index    : %0x\n", read_c0_index());
0022     pr_info("PageMask : %0x\n", read_c0_pagemask());
0023     if (cpu_has_guestid)
0024         pr_info("GuestCtl1: %0x\n", read_c0_guestctl1());
0025     pr_info("EntryHi  : %0*lx\n", field, read_c0_entryhi());
0026     pr_info("EntryLo0 : %0*lx\n", field, read_c0_entrylo0());
0027     pr_info("EntryLo1 : %0*lx\n", field, read_c0_entrylo1());
0028     pr_info("Wired    : %0x\n", read_c0_wired());
0029     switch (current_cpu_type()) {
0030     case CPU_R10000:
0031     case CPU_R12000:
0032     case CPU_R14000:
0033     case CPU_R16000:
0034         pr_info("FrameMask: %0x\n", read_c0_framemask());
0035         break;
0036     }
0037     if (cpu_has_small_pages || cpu_has_rixi || cpu_has_xpa)
0038         pr_info("PageGrain: %0x\n", read_c0_pagegrain());
0039     if (cpu_has_htw) {
0040         pr_info("PWField  : %0*lx\n", field, read_c0_pwfield());
0041         pr_info("PWSize   : %0*lx\n", field, read_c0_pwsize());
0042         pr_info("PWCtl    : %0x\n", read_c0_pwctl());
0043     }
0044 }
0045 
0046 static inline const char *msk2str(unsigned int mask)
0047 {
0048     switch (mask) {
0049     case PM_4K: return "4kb";
0050     case PM_16K:    return "16kb";
0051     case PM_64K:    return "64kb";
0052     case PM_256K:   return "256kb";
0053 #ifdef CONFIG_CPU_CAVIUM_OCTEON
0054     case PM_8K: return "8kb";
0055     case PM_32K:    return "32kb";
0056     case PM_128K:   return "128kb";
0057     case PM_512K:   return "512kb";
0058     case PM_2M: return "2Mb";
0059     case PM_8M: return "8Mb";
0060     case PM_32M:    return "32Mb";
0061 #endif
0062     }
0063     return "";
0064 }
0065 
0066 static void dump_tlb(int first, int last)
0067 {
0068     unsigned long s_entryhi, entryhi, asid, mmid;
0069     unsigned long long entrylo0, entrylo1, pa;
0070     unsigned int s_index, s_pagemask, s_guestctl1 = 0;
0071     unsigned int pagemask, guestctl1 = 0, c0, c1, i;
0072     unsigned long asidmask = cpu_asid_mask(&current_cpu_data);
0073     int asidwidth = DIV_ROUND_UP(ilog2(asidmask) + 1, 4);
0074     unsigned long s_mmid;
0075 #ifdef CONFIG_32BIT
0076     bool xpa = cpu_has_xpa && (read_c0_pagegrain() & PG_ELPA);
0077     int pwidth = xpa ? 11 : 8;
0078     int vwidth = 8;
0079 #else
0080     bool xpa = false;
0081     int pwidth = 11;
0082     int vwidth = 11;
0083 #endif
0084 
0085     s_pagemask = read_c0_pagemask();
0086     s_entryhi = read_c0_entryhi();
0087     s_index = read_c0_index();
0088 
0089     if (cpu_has_mmid)
0090         asid = s_mmid = read_c0_memorymapid();
0091     else
0092         asid = s_entryhi & asidmask;
0093 
0094     if (cpu_has_guestid)
0095         s_guestctl1 = read_c0_guestctl1();
0096 
0097     for (i = first; i <= last; i++) {
0098         write_c0_index(i);
0099         mtc0_tlbr_hazard();
0100         tlb_read();
0101         tlb_read_hazard();
0102         pagemask = read_c0_pagemask();
0103         entryhi  = read_c0_entryhi();
0104         entrylo0 = read_c0_entrylo0();
0105         entrylo1 = read_c0_entrylo1();
0106 
0107         if (cpu_has_mmid)
0108             mmid = read_c0_memorymapid();
0109         else
0110             mmid = entryhi & asidmask;
0111 
0112         if (cpu_has_guestid)
0113             guestctl1 = read_c0_guestctl1();
0114 
0115         /* EHINV bit marks entire entry as invalid */
0116         if (cpu_has_tlbinv && entryhi & MIPS_ENTRYHI_EHINV)
0117             continue;
0118         /*
0119          * Prior to tlbinv, unused entries have a virtual address of
0120          * CKSEG0.
0121          */
0122         if ((entryhi & ~0x1ffffUL) == CKSEG0)
0123             continue;
0124         /*
0125          * ASID takes effect in absence of G (global) bit.
0126          * We check both G bits, even though architecturally they should
0127          * match one another, because some revisions of the SB1 core may
0128          * leave only a single G bit set after a machine check exception
0129          * due to duplicate TLB entry.
0130          */
0131         if (!((entrylo0 | entrylo1) & ENTRYLO_G) && (mmid != asid))
0132             continue;
0133 
0134         /*
0135          * Only print entries in use
0136          */
0137         printk("Index: %2d pgmask=%s ", i, msk2str(pagemask));
0138 
0139         c0 = (entrylo0 & ENTRYLO_C) >> ENTRYLO_C_SHIFT;
0140         c1 = (entrylo1 & ENTRYLO_C) >> ENTRYLO_C_SHIFT;
0141 
0142         pr_cont("va=%0*lx asid=%0*lx",
0143             vwidth, (entryhi & ~0x1fffUL),
0144             asidwidth, mmid);
0145         if (cpu_has_guestid)
0146             pr_cont(" gid=%02lx",
0147                 (guestctl1 & MIPS_GCTL1_RID)
0148                     >> MIPS_GCTL1_RID_SHIFT);
0149         /* RI/XI are in awkward places, so mask them off separately */
0150         pa = entrylo0 & ~(MIPS_ENTRYLO_RI | MIPS_ENTRYLO_XI);
0151         if (xpa)
0152             pa |= (unsigned long long)readx_c0_entrylo0() << 30;
0153         pa = (pa << 6) & PAGE_MASK;
0154         pr_cont("\n\t[");
0155         if (cpu_has_rixi)
0156             pr_cont("ri=%d xi=%d ",
0157                 (entrylo0 & MIPS_ENTRYLO_RI) ? 1 : 0,
0158                 (entrylo0 & MIPS_ENTRYLO_XI) ? 1 : 0);
0159         pr_cont("pa=%0*llx c=%d d=%d v=%d g=%d] [",
0160             pwidth, pa, c0,
0161             (entrylo0 & ENTRYLO_D) ? 1 : 0,
0162             (entrylo0 & ENTRYLO_V) ? 1 : 0,
0163             (entrylo0 & ENTRYLO_G) ? 1 : 0);
0164         /* RI/XI are in awkward places, so mask them off separately */
0165         pa = entrylo1 & ~(MIPS_ENTRYLO_RI | MIPS_ENTRYLO_XI);
0166         if (xpa)
0167             pa |= (unsigned long long)readx_c0_entrylo1() << 30;
0168         pa = (pa << 6) & PAGE_MASK;
0169         if (cpu_has_rixi)
0170             pr_cont("ri=%d xi=%d ",
0171                 (entrylo1 & MIPS_ENTRYLO_RI) ? 1 : 0,
0172                 (entrylo1 & MIPS_ENTRYLO_XI) ? 1 : 0);
0173         pr_cont("pa=%0*llx c=%d d=%d v=%d g=%d]\n",
0174             pwidth, pa, c1,
0175             (entrylo1 & ENTRYLO_D) ? 1 : 0,
0176             (entrylo1 & ENTRYLO_V) ? 1 : 0,
0177             (entrylo1 & ENTRYLO_G) ? 1 : 0);
0178     }
0179     printk("\n");
0180 
0181     write_c0_entryhi(s_entryhi);
0182     write_c0_index(s_index);
0183     write_c0_pagemask(s_pagemask);
0184     if (cpu_has_guestid)
0185         write_c0_guestctl1(s_guestctl1);
0186 }
0187 
0188 void dump_tlb_all(void)
0189 {
0190     dump_tlb(0, current_cpu_data.tlbsize - 1);
0191 }