diff options
author | Vladimir Murzin <vladimir.murzin@arm.com> | 2017-10-16 07:52:35 -0400 |
---|---|---|
committer | Russell King <rmk+kernel@armlinux.org.uk> | 2017-10-23 11:58:31 -0400 |
commit | 877ec119dbbf9576953efc457ede5243621ad6eb (patch) | |
tree | 14b0e2a738222f9f046d1c3ebbb1fc6580dc2298 | |
parent | 59b6359dd92d18f5dc04b14a4c926fa08ab66f7c (diff) |
ARM: 8706/1: NOMMU: Move out MPU setup in separate module
Having MPU handling code in dedicated module makes it easier to
enhance/maintain it.
Tested-by: Szemző András <sza@esh.hu>
Tested-by: Alexandre TORGUE <alexandre.torgue@st.com>
Tested-by: Benjamin Gaignard <benjamin.gaignard@linaro.org>
Signed-off-by: Vladimir Murzin <vladimir.murzin@arm.com>
Signed-off-by: Russell King <rmk+kernel@armlinux.org.uk>
-rw-r--r-- | arch/arm/include/asm/mpu.h | 16 | ||||
-rw-r--r-- | arch/arm/mm/Makefile | 1 | ||||
-rw-r--r-- | arch/arm/mm/nommu.c | 254 | ||||
-rw-r--r-- | arch/arm/mm/pmsa-v7.c | 262 |
4 files changed, 276 insertions, 257 deletions
diff --git a/arch/arm/include/asm/mpu.h b/arch/arm/include/asm/mpu.h index c3247cc2fe08..edec5cf48471 100644 --- a/arch/arm/include/asm/mpu.h +++ b/arch/arm/include/asm/mpu.h | |||
@@ -1,8 +1,6 @@ | |||
1 | #ifndef __ARM_MPU_H | 1 | #ifndef __ARM_MPU_H |
2 | #define __ARM_MPU_H | 2 | #define __ARM_MPU_H |
3 | 3 | ||
4 | #ifdef CONFIG_ARM_MPU | ||
5 | |||
6 | /* MPUIR layout */ | 4 | /* MPUIR layout */ |
7 | #define MPUIR_nU 1 | 5 | #define MPUIR_nU 1 |
8 | #define MPUIR_DREGION 8 | 6 | #define MPUIR_DREGION 8 |
@@ -69,8 +67,18 @@ struct mpu_rgn_info { | |||
69 | }; | 67 | }; |
70 | extern struct mpu_rgn_info mpu_rgn_info; | 68 | extern struct mpu_rgn_info mpu_rgn_info; |
71 | 69 | ||
72 | #endif /* __ASSEMBLY__ */ | 70 | #ifdef CONFIG_ARM_MPU |
71 | |||
72 | extern void __init adjust_lowmem_bounds_mpu(void); | ||
73 | extern void __init mpu_setup(void); | ||
73 | 74 | ||
74 | #endif /* CONFIG_ARM_MPU */ | 75 | #else |
76 | |||
77 | static inline void adjust_lowmem_bounds_mpu(void) {} | ||
78 | static inline void mpu_setup(void) {} | ||
79 | |||
80 | #endif /* !CONFIG_ARM_MPU */ | ||
81 | |||
82 | #endif /* __ASSEMBLY__ */ | ||
75 | 83 | ||
76 | #endif | 84 | #endif |
diff --git a/arch/arm/mm/Makefile b/arch/arm/mm/Makefile index 950d19babb5f..bdb2ec11a2e3 100644 --- a/arch/arm/mm/Makefile +++ b/arch/arm/mm/Makefile | |||
@@ -9,6 +9,7 @@ obj-$(CONFIG_MMU) += fault-armv.o flush.o idmap.o ioremap.o \ | |||
9 | 9 | ||
10 | ifneq ($(CONFIG_MMU),y) | 10 | ifneq ($(CONFIG_MMU),y) |
11 | obj-y += nommu.o | 11 | obj-y += nommu.o |
12 | obj-$(CONFIG_ARM_MPU) += pmsa-v7.o | ||
12 | endif | 13 | endif |
13 | 14 | ||
14 | obj-$(CONFIG_ARM_PTDUMP) += dump.o | 15 | obj-$(CONFIG_ARM_PTDUMP) += dump.o |
diff --git a/arch/arm/mm/nommu.c b/arch/arm/mm/nommu.c index 3b8e728cc944..4c56b567cb47 100644 --- a/arch/arm/mm/nommu.c +++ b/arch/arm/mm/nommu.c | |||
@@ -27,259 +27,7 @@ unsigned long vectors_base; | |||
27 | 27 | ||
28 | #ifdef CONFIG_ARM_MPU | 28 | #ifdef CONFIG_ARM_MPU |
29 | struct mpu_rgn_info mpu_rgn_info; | 29 | struct mpu_rgn_info mpu_rgn_info; |
30 | 30 | #endif | |
31 | /* Region number */ | ||
32 | static void rgnr_write(u32 v) | ||
33 | { | ||
34 | asm("mcr p15, 0, %0, c6, c2, 0" : : "r" (v)); | ||
35 | } | ||
36 | |||
37 | /* Data-side / unified region attributes */ | ||
38 | |||
39 | /* Region access control register */ | ||
40 | static void dracr_write(u32 v) | ||
41 | { | ||
42 | asm("mcr p15, 0, %0, c6, c1, 4" : : "r" (v)); | ||
43 | } | ||
44 | |||
45 | /* Region size register */ | ||
46 | static void drsr_write(u32 v) | ||
47 | { | ||
48 | asm("mcr p15, 0, %0, c6, c1, 2" : : "r" (v)); | ||
49 | } | ||
50 | |||
51 | /* Region base address register */ | ||
52 | static void drbar_write(u32 v) | ||
53 | { | ||
54 | asm("mcr p15, 0, %0, c6, c1, 0" : : "r" (v)); | ||
55 | } | ||
56 | |||
57 | static u32 drbar_read(void) | ||
58 | { | ||
59 | u32 v; | ||
60 | asm("mrc p15, 0, %0, c6, c1, 0" : "=r" (v)); | ||
61 | return v; | ||
62 | } | ||
63 | /* Optional instruction-side region attributes */ | ||
64 | |||
65 | /* I-side Region access control register */ | ||
66 | static void iracr_write(u32 v) | ||
67 | { | ||
68 | asm("mcr p15, 0, %0, c6, c1, 5" : : "r" (v)); | ||
69 | } | ||
70 | |||
71 | /* I-side Region size register */ | ||
72 | static void irsr_write(u32 v) | ||
73 | { | ||
74 | asm("mcr p15, 0, %0, c6, c1, 3" : : "r" (v)); | ||
75 | } | ||
76 | |||
77 | /* I-side Region base address register */ | ||
78 | static void irbar_write(u32 v) | ||
79 | { | ||
80 | asm("mcr p15, 0, %0, c6, c1, 1" : : "r" (v)); | ||
81 | } | ||
82 | |||
83 | static unsigned long irbar_read(void) | ||
84 | { | ||
85 | unsigned long v; | ||
86 | asm("mrc p15, 0, %0, c6, c1, 1" : "=r" (v)); | ||
87 | return v; | ||
88 | } | ||
89 | |||
90 | /* MPU initialisation functions */ | ||
91 | void __init adjust_lowmem_bounds_mpu(void) | ||
92 | { | ||
93 | phys_addr_t phys_offset = PHYS_OFFSET; | ||
94 | phys_addr_t aligned_region_size, specified_mem_size, rounded_mem_size; | ||
95 | struct memblock_region *reg; | ||
96 | bool first = true; | ||
97 | phys_addr_t mem_start; | ||
98 | phys_addr_t mem_end; | ||
99 | |||
100 | for_each_memblock(memory, reg) { | ||
101 | if (first) { | ||
102 | /* | ||
103 | * Initially only use memory continuous from | ||
104 | * PHYS_OFFSET */ | ||
105 | if (reg->base != phys_offset) | ||
106 | panic("First memory bank must be contiguous from PHYS_OFFSET"); | ||
107 | |||
108 | mem_start = reg->base; | ||
109 | mem_end = reg->base + reg->size; | ||
110 | specified_mem_size = reg->size; | ||
111 | first = false; | ||
112 | } else { | ||
113 | /* | ||
114 | * memblock auto merges contiguous blocks, remove | ||
115 | * all blocks afterwards in one go (we can't remove | ||
116 | * blocks separately while iterating) | ||
117 | */ | ||
118 | pr_notice("Ignoring RAM after %pa, memory at %pa ignored\n", | ||
119 | &mem_end, ®->base); | ||
120 | memblock_remove(reg->base, 0 - reg->base); | ||
121 | break; | ||
122 | } | ||
123 | } | ||
124 | |||
125 | /* | ||
126 | * MPU has curious alignment requirements: Size must be power of 2, and | ||
127 | * region start must be aligned to the region size | ||
128 | */ | ||
129 | if (phys_offset != 0) | ||
130 | pr_info("PHYS_OFFSET != 0 => MPU Region size constrained by alignment requirements\n"); | ||
131 | |||
132 | /* | ||
133 | * Maximum aligned region might overflow phys_addr_t if phys_offset is | ||
134 | * 0. Hence we keep everything below 4G until we take the smaller of | ||
135 | * the aligned_region_size and rounded_mem_size, one of which is | ||
136 | * guaranteed to be smaller than the maximum physical address. | ||
137 | */ | ||
138 | aligned_region_size = (phys_offset - 1) ^ (phys_offset); | ||
139 | /* Find the max power-of-two sized region that fits inside our bank */ | ||
140 | rounded_mem_size = (1 << __fls(specified_mem_size)) - 1; | ||
141 | |||
142 | /* The actual region size is the smaller of the two */ | ||
143 | aligned_region_size = aligned_region_size < rounded_mem_size | ||
144 | ? aligned_region_size + 1 | ||
145 | : rounded_mem_size + 1; | ||
146 | |||
147 | if (aligned_region_size != specified_mem_size) { | ||
148 | pr_warn("Truncating memory from %pa to %pa (MPU region constraints)", | ||
149 | &specified_mem_size, &aligned_region_size); | ||
150 | memblock_remove(mem_start + aligned_region_size, | ||
151 | specified_mem_size - aligned_region_size); | ||
152 | |||
153 | mem_end = mem_start + aligned_region_size; | ||
154 | } | ||
155 | |||
156 | pr_debug("MPU Region from %pa size %pa (end %pa))\n", | ||
157 | &phys_offset, &aligned_region_size, &mem_end); | ||
158 | |||
159 | } | ||
160 | |||
161 | static int mpu_present(void) | ||
162 | { | ||
163 | return ((read_cpuid_ext(CPUID_EXT_MMFR0) & MMFR0_PMSA) == MMFR0_PMSAv7); | ||
164 | } | ||
165 | |||
166 | static int mpu_max_regions(void) | ||
167 | { | ||
168 | /* | ||
169 | * We don't support a different number of I/D side regions so if we | ||
170 | * have separate instruction and data memory maps then return | ||
171 | * whichever side has a smaller number of supported regions. | ||
172 | */ | ||
173 | u32 dregions, iregions, mpuir; | ||
174 | mpuir = read_cpuid(CPUID_MPUIR); | ||
175 | |||
176 | dregions = iregions = (mpuir & MPUIR_DREGION_SZMASK) >> MPUIR_DREGION; | ||
177 | |||
178 | /* Check for separate d-side and i-side memory maps */ | ||
179 | if (mpuir & MPUIR_nU) | ||
180 | iregions = (mpuir & MPUIR_IREGION_SZMASK) >> MPUIR_IREGION; | ||
181 | |||
182 | /* Use the smallest of the two maxima */ | ||
183 | return min(dregions, iregions); | ||
184 | } | ||
185 | |||
186 | static int mpu_iside_independent(void) | ||
187 | { | ||
188 | /* MPUIR.nU specifies whether there is *not* a unified memory map */ | ||
189 | return read_cpuid(CPUID_MPUIR) & MPUIR_nU; | ||
190 | } | ||
191 | |||
192 | static int mpu_min_region_order(void) | ||
193 | { | ||
194 | u32 drbar_result, irbar_result; | ||
195 | /* We've kept a region free for this probing */ | ||
196 | rgnr_write(MPU_PROBE_REGION); | ||
197 | isb(); | ||
198 | /* | ||
199 | * As per ARM ARM, write 0xFFFFFFFC to DRBAR to find the minimum | ||
200 | * region order | ||
201 | */ | ||
202 | drbar_write(0xFFFFFFFC); | ||
203 | drbar_result = irbar_result = drbar_read(); | ||
204 | drbar_write(0x0); | ||
205 | /* If the MPU is non-unified, we use the larger of the two minima*/ | ||
206 | if (mpu_iside_independent()) { | ||
207 | irbar_write(0xFFFFFFFC); | ||
208 | irbar_result = irbar_read(); | ||
209 | irbar_write(0x0); | ||
210 | } | ||
211 | isb(); /* Ensure that MPU region operations have completed */ | ||
212 | /* Return whichever result is larger */ | ||
213 | return __ffs(max(drbar_result, irbar_result)); | ||
214 | } | ||
215 | |||
216 | static int mpu_setup_region(unsigned int number, phys_addr_t start, | ||
217 | unsigned int size_order, unsigned int properties) | ||
218 | { | ||
219 | u32 size_data; | ||
220 | |||
221 | /* We kept a region free for probing resolution of MPU regions*/ | ||
222 | if (number > mpu_max_regions() || number == MPU_PROBE_REGION) | ||
223 | return -ENOENT; | ||
224 | |||
225 | if (size_order > 32) | ||
226 | return -ENOMEM; | ||
227 | |||
228 | if (size_order < mpu_min_region_order()) | ||
229 | return -ENOMEM; | ||
230 | |||
231 | /* Writing N to bits 5:1 (RSR_SZ) specifies region size 2^N+1 */ | ||
232 | size_data = ((size_order - 1) << MPU_RSR_SZ) | 1 << MPU_RSR_EN; | ||
233 | |||
234 | dsb(); /* Ensure all previous data accesses occur with old mappings */ | ||
235 | rgnr_write(number); | ||
236 | isb(); | ||
237 | drbar_write(start); | ||
238 | dracr_write(properties); | ||
239 | isb(); /* Propagate properties before enabling region */ | ||
240 | drsr_write(size_data); | ||
241 | |||
242 | /* Check for independent I-side registers */ | ||
243 | if (mpu_iside_independent()) { | ||
244 | irbar_write(start); | ||
245 | iracr_write(properties); | ||
246 | isb(); | ||
247 | irsr_write(size_data); | ||
248 | } | ||
249 | isb(); | ||
250 | |||
251 | /* Store region info (we treat i/d side the same, so only store d) */ | ||
252 | mpu_rgn_info.rgns[number].dracr = properties; | ||
253 | mpu_rgn_info.rgns[number].drbar = start; | ||
254 | mpu_rgn_info.rgns[number].drsr = size_data; | ||
255 | return 0; | ||
256 | } | ||
257 | |||
258 | /* | ||
259 | * Set up default MPU regions, doing nothing if there is no MPU | ||
260 | */ | ||
261 | void __init mpu_setup(void) | ||
262 | { | ||
263 | int region_err; | ||
264 | if (!mpu_present()) | ||
265 | return; | ||
266 | |||
267 | region_err = mpu_setup_region(MPU_RAM_REGION, PHYS_OFFSET, | ||
268 | ilog2(memblock.memory.regions[0].size), | ||
269 | MPU_AP_PL1RW_PL0RW | MPU_RGN_NORMAL); | ||
270 | if (region_err) { | ||
271 | panic("MPU region initialization failure! %d", region_err); | ||
272 | } else { | ||
273 | pr_info("Using ARMv7 PMSA Compliant MPU. " | ||
274 | "Region independence: %s, Max regions: %d\n", | ||
275 | mpu_iside_independent() ? "Yes" : "No", | ||
276 | mpu_max_regions()); | ||
277 | } | ||
278 | } | ||
279 | #else | ||
280 | static void adjust_lowmem_bounds_mpu(void) {} | ||
281 | static void __init mpu_setup(void) {} | ||
282 | #endif /* CONFIG_ARM_MPU */ | ||
283 | 31 | ||
284 | #ifdef CONFIG_CPU_CP15 | 32 | #ifdef CONFIG_CPU_CP15 |
285 | #ifdef CONFIG_CPU_HIGH_VECTOR | 33 | #ifdef CONFIG_CPU_HIGH_VECTOR |
diff --git a/arch/arm/mm/pmsa-v7.c b/arch/arm/mm/pmsa-v7.c new file mode 100644 index 000000000000..cc987715457d --- /dev/null +++ b/arch/arm/mm/pmsa-v7.c | |||
@@ -0,0 +1,262 @@ | |||
1 | /* | ||
2 | * Based on linux/arch/arm/mm/nommu.c | ||
3 | * | ||
4 | * ARM PMSAv7 supporting functions. | ||
5 | */ | ||
6 | |||
7 | #include <linux/memblock.h> | ||
8 | |||
9 | #include <asm/cp15.h> | ||
10 | #include <asm/cputype.h> | ||
11 | #include <asm/mpu.h> | ||
12 | |||
13 | #include "mm.h" | ||
14 | |||
15 | /* Region number */ | ||
16 | static void rgnr_write(u32 v) | ||
17 | { | ||
18 | asm("mcr p15, 0, %0, c6, c2, 0" : : "r" (v)); | ||
19 | } | ||
20 | |||
21 | /* Data-side / unified region attributes */ | ||
22 | |||
23 | /* Region access control register */ | ||
24 | static void dracr_write(u32 v) | ||
25 | { | ||
26 | asm("mcr p15, 0, %0, c6, c1, 4" : : "r" (v)); | ||
27 | } | ||
28 | |||
29 | /* Region size register */ | ||
30 | static void drsr_write(u32 v) | ||
31 | { | ||
32 | asm("mcr p15, 0, %0, c6, c1, 2" : : "r" (v)); | ||
33 | } | ||
34 | |||
35 | /* Region base address register */ | ||
36 | static void drbar_write(u32 v) | ||
37 | { | ||
38 | asm("mcr p15, 0, %0, c6, c1, 0" : : "r" (v)); | ||
39 | } | ||
40 | |||
41 | static u32 drbar_read(void) | ||
42 | { | ||
43 | u32 v; | ||
44 | asm("mrc p15, 0, %0, c6, c1, 0" : "=r" (v)); | ||
45 | return v; | ||
46 | } | ||
47 | /* Optional instruction-side region attributes */ | ||
48 | |||
49 | /* I-side Region access control register */ | ||
50 | static void iracr_write(u32 v) | ||
51 | { | ||
52 | asm("mcr p15, 0, %0, c6, c1, 5" : : "r" (v)); | ||
53 | } | ||
54 | |||
55 | /* I-side Region size register */ | ||
56 | static void irsr_write(u32 v) | ||
57 | { | ||
58 | asm("mcr p15, 0, %0, c6, c1, 3" : : "r" (v)); | ||
59 | } | ||
60 | |||
61 | /* I-side Region base address register */ | ||
62 | static void irbar_write(u32 v) | ||
63 | { | ||
64 | asm("mcr p15, 0, %0, c6, c1, 1" : : "r" (v)); | ||
65 | } | ||
66 | |||
67 | static unsigned long irbar_read(void) | ||
68 | { | ||
69 | unsigned long v; | ||
70 | asm("mrc p15, 0, %0, c6, c1, 1" : "=r" (v)); | ||
71 | return v; | ||
72 | } | ||
73 | |||
74 | /* MPU initialisation functions */ | ||
75 | void __init adjust_lowmem_bounds_mpu(void) | ||
76 | { | ||
77 | phys_addr_t phys_offset = PHYS_OFFSET; | ||
78 | phys_addr_t aligned_region_size, specified_mem_size, rounded_mem_size; | ||
79 | struct memblock_region *reg; | ||
80 | bool first = true; | ||
81 | phys_addr_t mem_start; | ||
82 | phys_addr_t mem_end; | ||
83 | |||
84 | for_each_memblock(memory, reg) { | ||
85 | if (first) { | ||
86 | /* | ||
87 | * Initially only use memory continuous from | ||
88 | * PHYS_OFFSET */ | ||
89 | if (reg->base != phys_offset) | ||
90 | panic("First memory bank must be contiguous from PHYS_OFFSET"); | ||
91 | |||
92 | mem_start = reg->base; | ||
93 | mem_end = reg->base + reg->size; | ||
94 | specified_mem_size = reg->size; | ||
95 | first = false; | ||
96 | } else { | ||
97 | /* | ||
98 | * memblock auto merges contiguous blocks, remove | ||
99 | * all blocks afterwards in one go (we can't remove | ||
100 | * blocks separately while iterating) | ||
101 | */ | ||
102 | pr_notice("Ignoring RAM after %pa, memory at %pa ignored\n", | ||
103 | &mem_end, ®->base); | ||
104 | memblock_remove(reg->base, 0 - reg->base); | ||
105 | break; | ||
106 | } | ||
107 | } | ||
108 | |||
109 | /* | ||
110 | * MPU has curious alignment requirements: Size must be power of 2, and | ||
111 | * region start must be aligned to the region size | ||
112 | */ | ||
113 | if (phys_offset != 0) | ||
114 | pr_info("PHYS_OFFSET != 0 => MPU Region size constrained by alignment requirements\n"); | ||
115 | |||
116 | /* | ||
117 | * Maximum aligned region might overflow phys_addr_t if phys_offset is | ||
118 | * 0. Hence we keep everything below 4G until we take the smaller of | ||
119 | * the aligned_region_size and rounded_mem_size, one of which is | ||
120 | * guaranteed to be smaller than the maximum physical address. | ||
121 | */ | ||
122 | aligned_region_size = (phys_offset - 1) ^ (phys_offset); | ||
123 | /* Find the max power-of-two sized region that fits inside our bank */ | ||
124 | rounded_mem_size = (1 << __fls(specified_mem_size)) - 1; | ||
125 | |||
126 | /* The actual region size is the smaller of the two */ | ||
127 | aligned_region_size = aligned_region_size < rounded_mem_size | ||
128 | ? aligned_region_size + 1 | ||
129 | : rounded_mem_size + 1; | ||
130 | |||
131 | if (aligned_region_size != specified_mem_size) { | ||
132 | pr_warn("Truncating memory from %pa to %pa (MPU region constraints)", | ||
133 | &specified_mem_size, &aligned_region_size); | ||
134 | memblock_remove(mem_start + aligned_region_size, | ||
135 | specified_mem_size - aligned_region_size); | ||
136 | |||
137 | mem_end = mem_start + aligned_region_size; | ||
138 | } | ||
139 | |||
140 | pr_debug("MPU Region from %pa size %pa (end %pa))\n", | ||
141 | &phys_offset, &aligned_region_size, &mem_end); | ||
142 | |||
143 | } | ||
144 | |||
145 | static int mpu_present(void) | ||
146 | { | ||
147 | return ((read_cpuid_ext(CPUID_EXT_MMFR0) & MMFR0_PMSA) == MMFR0_PMSAv7); | ||
148 | } | ||
149 | |||
150 | static int mpu_max_regions(void) | ||
151 | { | ||
152 | /* | ||
153 | * We don't support a different number of I/D side regions so if we | ||
154 | * have separate instruction and data memory maps then return | ||
155 | * whichever side has a smaller number of supported regions. | ||
156 | */ | ||
157 | u32 dregions, iregions, mpuir; | ||
158 | mpuir = read_cpuid(CPUID_MPUIR); | ||
159 | |||
160 | dregions = iregions = (mpuir & MPUIR_DREGION_SZMASK) >> MPUIR_DREGION; | ||
161 | |||
162 | /* Check for separate d-side and i-side memory maps */ | ||
163 | if (mpuir & MPUIR_nU) | ||
164 | iregions = (mpuir & MPUIR_IREGION_SZMASK) >> MPUIR_IREGION; | ||
165 | |||
166 | /* Use the smallest of the two maxima */ | ||
167 | return min(dregions, iregions); | ||
168 | } | ||
169 | |||
170 | static int mpu_iside_independent(void) | ||
171 | { | ||
172 | /* MPUIR.nU specifies whether there is *not* a unified memory map */ | ||
173 | return read_cpuid(CPUID_MPUIR) & MPUIR_nU; | ||
174 | } | ||
175 | |||
176 | static int mpu_min_region_order(void) | ||
177 | { | ||
178 | u32 drbar_result, irbar_result; | ||
179 | /* We've kept a region free for this probing */ | ||
180 | rgnr_write(MPU_PROBE_REGION); | ||
181 | isb(); | ||
182 | /* | ||
183 | * As per ARM ARM, write 0xFFFFFFFC to DRBAR to find the minimum | ||
184 | * region order | ||
185 | */ | ||
186 | drbar_write(0xFFFFFFFC); | ||
187 | drbar_result = irbar_result = drbar_read(); | ||
188 | drbar_write(0x0); | ||
189 | /* If the MPU is non-unified, we use the larger of the two minima*/ | ||
190 | if (mpu_iside_independent()) { | ||
191 | irbar_write(0xFFFFFFFC); | ||
192 | irbar_result = irbar_read(); | ||
193 | irbar_write(0x0); | ||
194 | } | ||
195 | isb(); /* Ensure that MPU region operations have completed */ | ||
196 | /* Return whichever result is larger */ | ||
197 | return __ffs(max(drbar_result, irbar_result)); | ||
198 | } | ||
199 | |||
200 | static int mpu_setup_region(unsigned int number, phys_addr_t start, | ||
201 | unsigned int size_order, unsigned int properties) | ||
202 | { | ||
203 | u32 size_data; | ||
204 | |||
205 | /* We kept a region free for probing resolution of MPU regions*/ | ||
206 | if (number > mpu_max_regions() || number == MPU_PROBE_REGION) | ||
207 | return -ENOENT; | ||
208 | |||
209 | if (size_order > 32) | ||
210 | return -ENOMEM; | ||
211 | |||
212 | if (size_order < mpu_min_region_order()) | ||
213 | return -ENOMEM; | ||
214 | |||
215 | /* Writing N to bits 5:1 (RSR_SZ) specifies region size 2^N+1 */ | ||
216 | size_data = ((size_order - 1) << MPU_RSR_SZ) | 1 << MPU_RSR_EN; | ||
217 | |||
218 | dsb(); /* Ensure all previous data accesses occur with old mappings */ | ||
219 | rgnr_write(number); | ||
220 | isb(); | ||
221 | drbar_write(start); | ||
222 | dracr_write(properties); | ||
223 | isb(); /* Propagate properties before enabling region */ | ||
224 | drsr_write(size_data); | ||
225 | |||
226 | /* Check for independent I-side registers */ | ||
227 | if (mpu_iside_independent()) { | ||
228 | irbar_write(start); | ||
229 | iracr_write(properties); | ||
230 | isb(); | ||
231 | irsr_write(size_data); | ||
232 | } | ||
233 | isb(); | ||
234 | |||
235 | /* Store region info (we treat i/d side the same, so only store d) */ | ||
236 | mpu_rgn_info.rgns[number].dracr = properties; | ||
237 | mpu_rgn_info.rgns[number].drbar = start; | ||
238 | mpu_rgn_info.rgns[number].drsr = size_data; | ||
239 | return 0; | ||
240 | } | ||
241 | |||
242 | /* | ||
243 | * Set up default MPU regions, doing nothing if there is no MPU | ||
244 | */ | ||
245 | void __init mpu_setup(void) | ||
246 | { | ||
247 | int region_err; | ||
248 | if (!mpu_present()) | ||
249 | return; | ||
250 | |||
251 | region_err = mpu_setup_region(MPU_RAM_REGION, PHYS_OFFSET, | ||
252 | ilog2(memblock.memory.regions[0].size), | ||
253 | MPU_AP_PL1RW_PL0RW | MPU_RGN_NORMAL); | ||
254 | if (region_err) { | ||
255 | panic("MPU region initialization failure! %d", region_err); | ||
256 | } else { | ||
257 | pr_info("Using ARMv7 PMSA Compliant MPU. " | ||
258 | "Region independence: %s, Max regions: %d\n", | ||
259 | mpu_iside_independent() ? "Yes" : "No", | ||
260 | mpu_max_regions()); | ||
261 | } | ||
262 | } | ||