diff options
Diffstat (limited to 'arch/powerpc/mm/dump_bats.c')
-rw-r--r-- | arch/powerpc/mm/dump_bats.c | 173 |
1 files changed, 173 insertions, 0 deletions
diff --git a/arch/powerpc/mm/dump_bats.c b/arch/powerpc/mm/dump_bats.c new file mode 100644 index 000000000000..a0d23e96e841 --- /dev/null +++ b/arch/powerpc/mm/dump_bats.c | |||
@@ -0,0 +1,173 @@ | |||
1 | // SPDX-License-Identifier: GPL-2.0+ | ||
2 | /* | ||
3 | * Copyright 2018, Christophe Leroy CS S.I. | ||
4 | * <christophe.leroy@c-s.fr> | ||
5 | * | ||
6 | * This dumps the content of BATS | ||
7 | */ | ||
8 | |||
9 | #include <asm/debugfs.h> | ||
10 | #include <asm/pgtable.h> | ||
11 | #include <asm/cpu_has_feature.h> | ||
12 | |||
13 | static char *pp_601(int k, int pp) | ||
14 | { | ||
15 | if (pp == 0) | ||
16 | return k ? "NA" : "RWX"; | ||
17 | if (pp == 1) | ||
18 | return k ? "ROX" : "RWX"; | ||
19 | if (pp == 2) | ||
20 | return k ? "RWX" : "RWX"; | ||
21 | return k ? "ROX" : "ROX"; | ||
22 | } | ||
23 | |||
24 | static void bat_show_601(struct seq_file *m, int idx, u32 lower, u32 upper) | ||
25 | { | ||
26 | u32 blpi = upper & 0xfffe0000; | ||
27 | u32 k = (upper >> 2) & 3; | ||
28 | u32 pp = upper & 3; | ||
29 | phys_addr_t pbn = PHYS_BAT_ADDR(lower); | ||
30 | u32 bsm = lower & 0x3ff; | ||
31 | u32 size = (bsm + 1) << 17; | ||
32 | |||
33 | seq_printf(m, "%d: ", idx); | ||
34 | if (!(lower & 0x40)) { | ||
35 | seq_puts(m, " -\n"); | ||
36 | return; | ||
37 | } | ||
38 | |||
39 | seq_printf(m, "0x%08x-0x%08x ", blpi, blpi + size - 1); | ||
40 | #ifdef CONFIG_PHYS_64BIT | ||
41 | seq_printf(m, "0x%016llx ", pbn); | ||
42 | #else | ||
43 | seq_printf(m, "0x%08x ", pbn); | ||
44 | #endif | ||
45 | |||
46 | seq_printf(m, "Kernel %s User %s", pp_601(k & 2, pp), pp_601(k & 1, pp)); | ||
47 | |||
48 | if (lower & _PAGE_WRITETHRU) | ||
49 | seq_puts(m, "write through "); | ||
50 | if (lower & _PAGE_NO_CACHE) | ||
51 | seq_puts(m, "no cache "); | ||
52 | if (lower & _PAGE_COHERENT) | ||
53 | seq_puts(m, "coherent "); | ||
54 | seq_puts(m, "\n"); | ||
55 | } | ||
56 | |||
57 | #define BAT_SHOW_601(_m, _n, _l, _u) bat_show_601(_m, _n, mfspr(_l), mfspr(_u)) | ||
58 | |||
59 | static int bats_show_601(struct seq_file *m, void *v) | ||
60 | { | ||
61 | seq_puts(m, "---[ Block Address Translation ]---\n"); | ||
62 | |||
63 | BAT_SHOW_601(m, 0, SPRN_IBAT0L, SPRN_IBAT0U); | ||
64 | BAT_SHOW_601(m, 1, SPRN_IBAT1L, SPRN_IBAT1U); | ||
65 | BAT_SHOW_601(m, 2, SPRN_IBAT2L, SPRN_IBAT2U); | ||
66 | BAT_SHOW_601(m, 3, SPRN_IBAT3L, SPRN_IBAT3U); | ||
67 | |||
68 | return 0; | ||
69 | } | ||
70 | |||
71 | static void bat_show_603(struct seq_file *m, int idx, u32 lower, u32 upper, bool is_d) | ||
72 | { | ||
73 | u32 bepi = upper & 0xfffe0000; | ||
74 | u32 bl = (upper >> 2) & 0x7ff; | ||
75 | u32 k = upper & 3; | ||
76 | phys_addr_t brpn = PHYS_BAT_ADDR(lower); | ||
77 | u32 size = (bl + 1) << 17; | ||
78 | |||
79 | seq_printf(m, "%d: ", idx); | ||
80 | if (k == 0) { | ||
81 | seq_puts(m, " -\n"); | ||
82 | return; | ||
83 | } | ||
84 | |||
85 | seq_printf(m, "0x%08x-0x%08x ", bepi, bepi + size - 1); | ||
86 | #ifdef CONFIG_PHYS_64BIT | ||
87 | seq_printf(m, "0x%016llx ", brpn); | ||
88 | #else | ||
89 | seq_printf(m, "0x%08x ", brpn); | ||
90 | #endif | ||
91 | |||
92 | if (k == 1) | ||
93 | seq_puts(m, "User "); | ||
94 | else if (k == 2) | ||
95 | seq_puts(m, "Kernel "); | ||
96 | else | ||
97 | seq_puts(m, "Kernel/User "); | ||
98 | |||
99 | if (lower & BPP_RX) | ||
100 | seq_puts(m, is_d ? "RO " : "EXEC "); | ||
101 | else if (lower & BPP_RW) | ||
102 | seq_puts(m, is_d ? "RW " : "EXEC "); | ||
103 | else | ||
104 | seq_puts(m, is_d ? "NA " : "NX "); | ||
105 | |||
106 | if (lower & _PAGE_WRITETHRU) | ||
107 | seq_puts(m, "write through "); | ||
108 | if (lower & _PAGE_NO_CACHE) | ||
109 | seq_puts(m, "no cache "); | ||
110 | if (lower & _PAGE_COHERENT) | ||
111 | seq_puts(m, "coherent "); | ||
112 | if (lower & _PAGE_GUARDED) | ||
113 | seq_puts(m, "guarded "); | ||
114 | seq_puts(m, "\n"); | ||
115 | } | ||
116 | |||
117 | #define BAT_SHOW_603(_m, _n, _l, _u, _d) bat_show_603(_m, _n, mfspr(_l), mfspr(_u), _d) | ||
118 | |||
119 | static int bats_show_603(struct seq_file *m, void *v) | ||
120 | { | ||
121 | seq_puts(m, "---[ Instruction Block Address Translation ]---\n"); | ||
122 | |||
123 | BAT_SHOW_603(m, 0, SPRN_IBAT0L, SPRN_IBAT0U, false); | ||
124 | BAT_SHOW_603(m, 1, SPRN_IBAT1L, SPRN_IBAT1U, false); | ||
125 | BAT_SHOW_603(m, 2, SPRN_IBAT2L, SPRN_IBAT2U, false); | ||
126 | BAT_SHOW_603(m, 3, SPRN_IBAT3L, SPRN_IBAT3U, false); | ||
127 | if (mmu_has_feature(MMU_FTR_USE_HIGH_BATS)) { | ||
128 | BAT_SHOW_603(m, 4, SPRN_IBAT4L, SPRN_IBAT4U, false); | ||
129 | BAT_SHOW_603(m, 5, SPRN_IBAT5L, SPRN_IBAT5U, false); | ||
130 | BAT_SHOW_603(m, 6, SPRN_IBAT6L, SPRN_IBAT6U, false); | ||
131 | BAT_SHOW_603(m, 7, SPRN_IBAT7L, SPRN_IBAT7U, false); | ||
132 | } | ||
133 | |||
134 | seq_puts(m, "\n---[ Data Block Address Translation ]---\n"); | ||
135 | |||
136 | BAT_SHOW_603(m, 0, SPRN_DBAT0L, SPRN_DBAT0U, true); | ||
137 | BAT_SHOW_603(m, 1, SPRN_DBAT1L, SPRN_DBAT1U, true); | ||
138 | BAT_SHOW_603(m, 2, SPRN_DBAT2L, SPRN_DBAT2U, true); | ||
139 | BAT_SHOW_603(m, 3, SPRN_DBAT3L, SPRN_DBAT3U, true); | ||
140 | if (mmu_has_feature(MMU_FTR_USE_HIGH_BATS)) { | ||
141 | BAT_SHOW_603(m, 4, SPRN_DBAT4L, SPRN_DBAT4U, true); | ||
142 | BAT_SHOW_603(m, 5, SPRN_DBAT5L, SPRN_DBAT5U, true); | ||
143 | BAT_SHOW_603(m, 6, SPRN_DBAT6L, SPRN_DBAT6U, true); | ||
144 | BAT_SHOW_603(m, 7, SPRN_DBAT7L, SPRN_DBAT7U, true); | ||
145 | } | ||
146 | |||
147 | return 0; | ||
148 | } | ||
149 | |||
150 | static int bats_open(struct inode *inode, struct file *file) | ||
151 | { | ||
152 | if (cpu_has_feature(CPU_FTR_601)) | ||
153 | return single_open(file, bats_show_601, NULL); | ||
154 | |||
155 | return single_open(file, bats_show_603, NULL); | ||
156 | } | ||
157 | |||
158 | static const struct file_operations bats_fops = { | ||
159 | .open = bats_open, | ||
160 | .read = seq_read, | ||
161 | .llseek = seq_lseek, | ||
162 | .release = single_release, | ||
163 | }; | ||
164 | |||
165 | static int __init bats_init(void) | ||
166 | { | ||
167 | struct dentry *debugfs_file; | ||
168 | |||
169 | debugfs_file = debugfs_create_file("block_address_translation", 0400, | ||
170 | powerpc_debugfs_root, NULL, &bats_fops); | ||
171 | return debugfs_file ? 0 : -ENOMEM; | ||
172 | } | ||
173 | device_initcall(bats_init); | ||