pmsa-v7.c (e8b47e12d6c72f26a8ce85974f98a4050ac7ca24) pmsa-v7.c (a0995c0805b63c930b99970f2c9d5e4f167ca65b)
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
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
15static unsigned int __initdata mpu_min_region_order;
16static unsigned int __initdata mpu_max_regions;
17
15#define DRBAR __ACCESS_CP15(c6, 0, c1, 0)
16#define IRBAR __ACCESS_CP15(c6, 0, c1, 1)
17#define DRSR __ACCESS_CP15(c6, 0, c1, 2)
18#define IRSR __ACCESS_CP15(c6, 0, c1, 3)
19#define DRACR __ACCESS_CP15(c6, 0, c1, 4)
20#define IRACR __ACCESS_CP15(c6, 0, c1, 5)
21#define RNGNR __ACCESS_CP15(c6, 0, c2, 0)
22

--- 47 unchanged lines hidden (view full) ---

70 write_sysreg(v, IRBAR);
71}
72
73static inline u32 irbar_read(void)
74{
75 return read_sysreg(IRBAR);
76}
77
18#define DRBAR __ACCESS_CP15(c6, 0, c1, 0)
19#define IRBAR __ACCESS_CP15(c6, 0, c1, 1)
20#define DRSR __ACCESS_CP15(c6, 0, c1, 2)
21#define IRSR __ACCESS_CP15(c6, 0, c1, 3)
22#define DRACR __ACCESS_CP15(c6, 0, c1, 4)
23#define IRACR __ACCESS_CP15(c6, 0, c1, 5)
24#define RNGNR __ACCESS_CP15(c6, 0, c2, 0)
25

--- 47 unchanged lines hidden (view full) ---

73 write_sysreg(v, IRBAR);
74}
75
76static inline u32 irbar_read(void)
77{
78 return read_sysreg(IRBAR);
79}
80
81static int __init mpu_present(void)
82{
83 return ((read_cpuid_ext(CPUID_EXT_MMFR0) & MMFR0_PMSA) == MMFR0_PMSAv7);
84}
85
78/* MPU initialisation functions */
79void __init adjust_lowmem_bounds_mpu(void)
80{
81 phys_addr_t phys_offset = PHYS_OFFSET;
82 phys_addr_t aligned_region_size, specified_mem_size, rounded_mem_size;
83 struct memblock_region *reg;
84 bool first = true;
85 phys_addr_t mem_start;
86 phys_addr_t mem_end;
87
86/* MPU initialisation functions */
87void __init adjust_lowmem_bounds_mpu(void)
88{
89 phys_addr_t phys_offset = PHYS_OFFSET;
90 phys_addr_t aligned_region_size, specified_mem_size, rounded_mem_size;
91 struct memblock_region *reg;
92 bool first = true;
93 phys_addr_t mem_start;
94 phys_addr_t mem_end;
95
96 if (!mpu_present())
97 return;
98
88 for_each_memblock(memory, reg) {
89 if (first) {
90 /*
91 * Initially only use memory continuous from
92 * PHYS_OFFSET */
93 if (reg->base != phys_offset)
94 panic("First memory bank must be contiguous from PHYS_OFFSET");
95

--- 45 unchanged lines hidden (view full) ---

141 mem_end = mem_start + aligned_region_size;
142 }
143
144 pr_debug("MPU Region from %pa size %pa (end %pa))\n",
145 &phys_offset, &aligned_region_size, &mem_end);
146
147}
148
99 for_each_memblock(memory, reg) {
100 if (first) {
101 /*
102 * Initially only use memory continuous from
103 * PHYS_OFFSET */
104 if (reg->base != phys_offset)
105 panic("First memory bank must be contiguous from PHYS_OFFSET");
106

--- 45 unchanged lines hidden (view full) ---

152 mem_end = mem_start + aligned_region_size;
153 }
154
155 pr_debug("MPU Region from %pa size %pa (end %pa))\n",
156 &phys_offset, &aligned_region_size, &mem_end);
157
158}
159
149static int mpu_present(void)
160static int __init __mpu_max_regions(void)
150{
161{
151 return ((read_cpuid_ext(CPUID_EXT_MMFR0) & MMFR0_PMSA) == MMFR0_PMSAv7);
152}
153
154static int mpu_max_regions(void)
155{
156 /*
157 * We don't support a different number of I/D side regions so if we
158 * have separate instruction and data memory maps then return
159 * whichever side has a smaller number of supported regions.
160 */
161 u32 dregions, iregions, mpuir;
162 /*
163 * We don't support a different number of I/D side regions so if we
164 * have separate instruction and data memory maps then return
165 * whichever side has a smaller number of supported regions.
166 */
167 u32 dregions, iregions, mpuir;
168
162 mpuir = read_cpuid(CPUID_MPUIR);
163
164 dregions = iregions = (mpuir & MPUIR_DREGION_SZMASK) >> MPUIR_DREGION;
165
166 /* Check for separate d-side and i-side memory maps */
167 if (mpuir & MPUIR_nU)
168 iregions = (mpuir & MPUIR_IREGION_SZMASK) >> MPUIR_IREGION;
169
170 /* Use the smallest of the two maxima */
171 return min(dregions, iregions);
172}
173
169 mpuir = read_cpuid(CPUID_MPUIR);
170
171 dregions = iregions = (mpuir & MPUIR_DREGION_SZMASK) >> MPUIR_DREGION;
172
173 /* Check for separate d-side and i-side memory maps */
174 if (mpuir & MPUIR_nU)
175 iregions = (mpuir & MPUIR_IREGION_SZMASK) >> MPUIR_IREGION;
176
177 /* Use the smallest of the two maxima */
178 return min(dregions, iregions);
179}
180
174static int mpu_iside_independent(void)
181static int __init mpu_iside_independent(void)
175{
176 /* MPUIR.nU specifies whether there is *not* a unified memory map */
177 return read_cpuid(CPUID_MPUIR) & MPUIR_nU;
178}
179
182{
183 /* MPUIR.nU specifies whether there is *not* a unified memory map */
184 return read_cpuid(CPUID_MPUIR) & MPUIR_nU;
185}
186
180static int mpu_min_region_order(void)
187static int __init __mpu_min_region_order(void)
181{
182 u32 drbar_result, irbar_result;
188{
189 u32 drbar_result, irbar_result;
190
183 /* We've kept a region free for this probing */
184 rgnr_write(MPU_PROBE_REGION);
185 isb();
186 /*
187 * As per ARM ARM, write 0xFFFFFFFC to DRBAR to find the minimum
188 * region order
189 */
190 drbar_write(0xFFFFFFFC);
191 drbar_result = irbar_result = drbar_read();
192 drbar_write(0x0);
193 /* If the MPU is non-unified, we use the larger of the two minima*/
194 if (mpu_iside_independent()) {
195 irbar_write(0xFFFFFFFC);
196 irbar_result = irbar_read();
197 irbar_write(0x0);
198 }
199 isb(); /* Ensure that MPU region operations have completed */
200 /* Return whichever result is larger */
191 /* We've kept a region free for this probing */
192 rgnr_write(MPU_PROBE_REGION);
193 isb();
194 /*
195 * As per ARM ARM, write 0xFFFFFFFC to DRBAR to find the minimum
196 * region order
197 */
198 drbar_write(0xFFFFFFFC);
199 drbar_result = irbar_result = drbar_read();
200 drbar_write(0x0);
201 /* If the MPU is non-unified, we use the larger of the two minima*/
202 if (mpu_iside_independent()) {
203 irbar_write(0xFFFFFFFC);
204 irbar_result = irbar_read();
205 irbar_write(0x0);
206 }
207 isb(); /* Ensure that MPU region operations have completed */
208 /* Return whichever result is larger */
209
201 return __ffs(max(drbar_result, irbar_result));
202}
203
210 return __ffs(max(drbar_result, irbar_result));
211}
212
204static int mpu_setup_region(unsigned int number, phys_addr_t start,
213static int __init mpu_setup_region(unsigned int number, phys_addr_t start,
205 unsigned int size_order, unsigned int properties)
206{
207 u32 size_data;
208
209 /* We kept a region free for probing resolution of MPU regions*/
214 unsigned int size_order, unsigned int properties)
215{
216 u32 size_data;
217
218 /* We kept a region free for probing resolution of MPU regions*/
210 if (number > mpu_max_regions() || number == MPU_PROBE_REGION)
219 if (number > mpu_max_regions
220 || number >= MPU_MAX_REGIONS)
211 return -ENOENT;
212
213 if (size_order > 32)
214 return -ENOMEM;
215
221 return -ENOENT;
222
223 if (size_order > 32)
224 return -ENOMEM;
225
216 if (size_order < mpu_min_region_order())
226 if (size_order < mpu_min_region_order)
217 return -ENOMEM;
218
219 /* Writing N to bits 5:1 (RSR_SZ) specifies region size 2^N+1 */
220 size_data = ((size_order - 1) << MPU_RSR_SZ) | 1 << MPU_RSR_EN;
221
222 dsb(); /* Ensure all previous data accesses occur with old mappings */
223 rgnr_write(number);
224 isb();

--- 10 unchanged lines hidden (view full) ---

235 irsr_write(size_data);
236 }
237 isb();
238
239 /* Store region info (we treat i/d side the same, so only store d) */
240 mpu_rgn_info.rgns[number].dracr = properties;
241 mpu_rgn_info.rgns[number].drbar = start;
242 mpu_rgn_info.rgns[number].drsr = size_data;
227 return -ENOMEM;
228
229 /* Writing N to bits 5:1 (RSR_SZ) specifies region size 2^N+1 */
230 size_data = ((size_order - 1) << MPU_RSR_SZ) | 1 << MPU_RSR_EN;
231
232 dsb(); /* Ensure all previous data accesses occur with old mappings */
233 rgnr_write(number);
234 isb();

--- 10 unchanged lines hidden (view full) ---

245 irsr_write(size_data);
246 }
247 isb();
248
249 /* Store region info (we treat i/d side the same, so only store d) */
250 mpu_rgn_info.rgns[number].dracr = properties;
251 mpu_rgn_info.rgns[number].drbar = start;
252 mpu_rgn_info.rgns[number].drsr = size_data;
253
254 mpu_rgn_info.used++;
255
243 return 0;
244}
245
246/*
247* Set up default MPU regions, doing nothing if there is no MPU
248*/
249void __init mpu_setup(void)
250{
256 return 0;
257}
258
259/*
260* Set up default MPU regions, doing nothing if there is no MPU
261*/
262void __init mpu_setup(void)
263{
251 int region_err;
264 int region = 0, err = 0;
265
252 if (!mpu_present())
253 return;
254
266 if (!mpu_present())
267 return;
268
255 region_err = mpu_setup_region(MPU_RAM_REGION, PHYS_OFFSET,
256 ilog2(memblock.memory.regions[0].size),
257 MPU_AP_PL1RW_PL0RW | MPU_RGN_NORMAL);
258 if (region_err) {
259 panic("MPU region initialization failure! %d", region_err);
269 /* Free-up MPU_PROBE_REGION */
270 mpu_min_region_order = __mpu_min_region_order();
271
272 /* How many regions are supported */
273 mpu_max_regions = __mpu_max_regions();
274
275 /* Now setup MPU (order is important) */
276
277 /* Background */
278 err |= mpu_setup_region(region++, 0, 32,
279 MPU_ACR_XN | MPU_RGN_STRONGLY_ORDERED | MPU_AP_PL1RW_PL0NA);
280
281 /* RAM */
282 err |= mpu_setup_region(region++, PHYS_OFFSET,
283 ilog2(memblock.memory.regions[0].size),
284 MPU_AP_PL1RW_PL0RW | MPU_RGN_NORMAL);
285
286 /* Vectors */
287 err |= mpu_setup_region(region++, vectors_base,
288 ilog2(2 * PAGE_SIZE),
289 MPU_AP_PL1RW_PL0NA | MPU_RGN_NORMAL);
290 if (err) {
291 panic("MPU region initialization failure! %d", err);
260 } else {
261 pr_info("Using ARMv7 PMSA Compliant MPU. "
292 } else {
293 pr_info("Using ARMv7 PMSA Compliant MPU. "
262 "Region independence: %s, Max regions: %d\n",
294 "Region independence: %s, Used %d of %d regions\n",
263 mpu_iside_independent() ? "Yes" : "No",
295 mpu_iside_independent() ? "Yes" : "No",
264 mpu_max_regions());
296 mpu_rgn_info.used, mpu_max_regions);
265 }
266}
297 }
298}