tlb-debugfs.c (3742B)
1/* 2 * arch/sh/mm/tlb-debugfs.c 3 * 4 * debugfs ops for SH-4 ITLB/UTLBs. 5 * 6 * Copyright (C) 2010 Matt Fleming 7 * 8 * This file is subject to the terms and conditions of the GNU General Public 9 * License. See the file "COPYING" in the main directory of this archive 10 * for more details. 11 */ 12#include <linux/init.h> 13#include <linux/module.h> 14#include <linux/debugfs.h> 15#include <linux/seq_file.h> 16#include <asm/processor.h> 17#include <asm/mmu_context.h> 18#include <asm/tlbflush.h> 19 20enum tlb_type { 21 TLB_TYPE_ITLB, 22 TLB_TYPE_UTLB, 23}; 24 25static struct { 26 int bits; 27 const char *size; 28} tlb_sizes[] = { 29 { 0x0, " 1KB" }, 30 { 0x1, " 4KB" }, 31 { 0x2, " 8KB" }, 32 { 0x4, " 64KB" }, 33 { 0x5, "256KB" }, 34 { 0x7, " 1MB" }, 35 { 0x8, " 4MB" }, 36 { 0xc, " 64MB" }, 37}; 38 39static int tlb_seq_show(struct seq_file *file, void *iter) 40{ 41 unsigned int tlb_type = (unsigned int)file->private; 42 unsigned long addr1, addr2, data1, data2; 43 unsigned long flags; 44 unsigned long mmucr; 45 unsigned int nentries, entry; 46 unsigned int urb; 47 48 mmucr = __raw_readl(MMUCR); 49 if ((mmucr & 0x1) == 0) { 50 seq_printf(file, "address translation disabled\n"); 51 return 0; 52 } 53 54 if (tlb_type == TLB_TYPE_ITLB) { 55 addr1 = MMU_ITLB_ADDRESS_ARRAY; 56 addr2 = MMU_ITLB_ADDRESS_ARRAY2; 57 data1 = MMU_ITLB_DATA_ARRAY; 58 data2 = MMU_ITLB_DATA_ARRAY2; 59 nentries = 4; 60 } else { 61 addr1 = MMU_UTLB_ADDRESS_ARRAY; 62 addr2 = MMU_UTLB_ADDRESS_ARRAY2; 63 data1 = MMU_UTLB_DATA_ARRAY; 64 data2 = MMU_UTLB_DATA_ARRAY2; 65 nentries = 64; 66 } 67 68 local_irq_save(flags); 69 jump_to_uncached(); 70 71 urb = (mmucr & MMUCR_URB) >> MMUCR_URB_SHIFT; 72 73 /* Make the "entry >= urb" test fail. */ 74 if (urb == 0) 75 urb = MMUCR_URB_NENTRIES + 1; 76 77 if (tlb_type == TLB_TYPE_ITLB) { 78 addr1 = MMU_ITLB_ADDRESS_ARRAY; 79 addr2 = MMU_ITLB_ADDRESS_ARRAY2; 80 data1 = MMU_ITLB_DATA_ARRAY; 81 data2 = MMU_ITLB_DATA_ARRAY2; 82 nentries = 4; 83 } else { 84 addr1 = MMU_UTLB_ADDRESS_ARRAY; 85 addr2 = MMU_UTLB_ADDRESS_ARRAY2; 86 data1 = MMU_UTLB_DATA_ARRAY; 87 data2 = MMU_UTLB_DATA_ARRAY2; 88 nentries = 64; 89 } 90 91 seq_printf(file, "entry: vpn ppn asid size valid wired\n"); 92 93 for (entry = 0; entry < nentries; entry++) { 94 unsigned long vpn, ppn, asid, size; 95 unsigned long valid; 96 unsigned long val; 97 const char *sz = " ?"; 98 int i; 99 100 val = __raw_readl(addr1 | (entry << MMU_TLB_ENTRY_SHIFT)); 101 ctrl_barrier(); 102 vpn = val & 0xfffffc00; 103 valid = val & 0x100; 104 105 val = __raw_readl(addr2 | (entry << MMU_TLB_ENTRY_SHIFT)); 106 ctrl_barrier(); 107 asid = val & MMU_CONTEXT_ASID_MASK; 108 109 val = __raw_readl(data1 | (entry << MMU_TLB_ENTRY_SHIFT)); 110 ctrl_barrier(); 111 ppn = (val & 0x0ffffc00) << 4; 112 113 val = __raw_readl(data2 | (entry << MMU_TLB_ENTRY_SHIFT)); 114 ctrl_barrier(); 115 size = (val & 0xf0) >> 4; 116 117 for (i = 0; i < ARRAY_SIZE(tlb_sizes); i++) { 118 if (tlb_sizes[i].bits == size) 119 break; 120 } 121 122 if (i != ARRAY_SIZE(tlb_sizes)) 123 sz = tlb_sizes[i].size; 124 125 seq_printf(file, "%2d: 0x%08lx 0x%08lx %5lu %s %s %s\n", 126 entry, vpn, ppn, asid, 127 sz, valid ? "V" : "-", 128 (urb <= entry) ? "W" : "-"); 129 } 130 131 back_to_cached(); 132 local_irq_restore(flags); 133 134 return 0; 135} 136 137static int tlb_debugfs_open(struct inode *inode, struct file *file) 138{ 139 return single_open(file, tlb_seq_show, inode->i_private); 140} 141 142static const struct file_operations tlb_debugfs_fops = { 143 .owner = THIS_MODULE, 144 .open = tlb_debugfs_open, 145 .read = seq_read, 146 .llseek = seq_lseek, 147 .release = single_release, 148}; 149 150static int __init tlb_debugfs_init(void) 151{ 152 debugfs_create_file("itlb", S_IRUSR, arch_debugfs_dir, 153 (void *)TLB_TYPE_ITLB, &tlb_debugfs_fops); 154 debugfs_create_file("utlb", S_IRUSR, arch_debugfs_dir, 155 (void *)TLB_TYPE_UTLB, &tlb_debugfs_fops); 156 return 0; 157} 158module_init(tlb_debugfs_init); 159 160MODULE_LICENSE("GPL v2");