summaryrefslogtreecommitdiff
path: root/arch/arm/mm
diff options
context:
space:
mode:
authorVladimir Murzin <vladimir.murzin@arm.com>2017-10-16 14:54:05 +0300
committerRussell King <rmk+kernel@armlinux.org.uk>2017-10-23 18:58:59 +0300
commita0995c0805b63c930b99970f2c9d5e4f167ca65b (patch)
tree2eb909c3771888be542586ab98c03d3244fc87e2 /arch/arm/mm
parente8b47e12d6c72f26a8ce85974f98a4050ac7ca24 (diff)
downloadlinux-a0995c0805b63c930b99970f2c9d5e4f167ca65b.tar.xz
ARM: 8708/1: NOMMU: Rework MPU to be mostly done in C
Currently, there are several issues with how MPU is setup: 1. We won't boot if MPU is missing 2. We won't boot if use XIP 3. Further extension of MPU setup requires asm skills The 1st point can be relaxed, so we can continue with boot CPU even if MPU is missed and fail boot for secondaries only. To address the 2nd point we could create region covering CONFIG_XIP_PHYS_ADDR - _end and that might work for the first stage of MPU enable, but due to MPU's alignment requirement we could cover too much, IOW we need more flexibility in how we're partitioning memory regions... and it'd be hardly possible to archive because of the 3rd point. This patch is trying to address 1st and 3rd issues and paves the path for 2nd and further improvements. The most visible change introduced with this patch is that we start using mpu_rgn_info array (as it was supposed?), so change in MPU setup done by boot CPU is recorded there and feed to secondaries. It allows us to keep minimal region setup for boot CPU and do the rest in C. Since we start programming MPU regions in C evaluation of MPU constrains (number of regions supported and minimal region order) can be done once, which in turn open possibility to free-up "probe" region early. 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>
Diffstat (limited to 'arch/arm/mm')
-rw-r--r--arch/arm/mm/pmsa-v7.c70
1 files changed, 51 insertions, 19 deletions
diff --git a/arch/arm/mm/pmsa-v7.c b/arch/arm/mm/pmsa-v7.c
index 484f5aa51090..cd798271a78d 100644
--- a/arch/arm/mm/pmsa-v7.c
+++ b/arch/arm/mm/pmsa-v7.c
@@ -12,6 +12,9 @@
#include "mm.h"
+static unsigned int __initdata mpu_min_region_order;
+static unsigned int __initdata mpu_max_regions;
+
#define DRBAR __ACCESS_CP15(c6, 0, c1, 0)
#define IRBAR __ACCESS_CP15(c6, 0, c1, 1)
#define DRSR __ACCESS_CP15(c6, 0, c1, 2)
@@ -75,6 +78,11 @@ static inline u32 irbar_read(void)
return read_sysreg(IRBAR);
}
+static int __init mpu_present(void)
+{
+ return ((read_cpuid_ext(CPUID_EXT_MMFR0) & MMFR0_PMSA) == MMFR0_PMSAv7);
+}
+
/* MPU initialisation functions */
void __init adjust_lowmem_bounds_mpu(void)
{
@@ -85,6 +93,9 @@ void __init adjust_lowmem_bounds_mpu(void)
phys_addr_t mem_start;
phys_addr_t mem_end;
+ if (!mpu_present())
+ return;
+
for_each_memblock(memory, reg) {
if (first) {
/*
@@ -146,12 +157,7 @@ void __init adjust_lowmem_bounds_mpu(void)
}
-static int mpu_present(void)
-{
- return ((read_cpuid_ext(CPUID_EXT_MMFR0) & MMFR0_PMSA) == MMFR0_PMSAv7);
-}
-
-static int mpu_max_regions(void)
+static int __init __mpu_max_regions(void)
{
/*
* We don't support a different number of I/D side regions so if we
@@ -159,6 +165,7 @@ static int mpu_max_regions(void)
* whichever side has a smaller number of supported regions.
*/
u32 dregions, iregions, mpuir;
+
mpuir = read_cpuid(CPUID_MPUIR);
dregions = iregions = (mpuir & MPUIR_DREGION_SZMASK) >> MPUIR_DREGION;
@@ -171,15 +178,16 @@ static int mpu_max_regions(void)
return min(dregions, iregions);
}
-static int mpu_iside_independent(void)
+static int __init mpu_iside_independent(void)
{
/* MPUIR.nU specifies whether there is *not* a unified memory map */
return read_cpuid(CPUID_MPUIR) & MPUIR_nU;
}
-static int mpu_min_region_order(void)
+static int __init __mpu_min_region_order(void)
{
u32 drbar_result, irbar_result;
+
/* We've kept a region free for this probing */
rgnr_write(MPU_PROBE_REGION);
isb();
@@ -198,22 +206,24 @@ static int mpu_min_region_order(void)
}
isb(); /* Ensure that MPU region operations have completed */
/* Return whichever result is larger */
+
return __ffs(max(drbar_result, irbar_result));
}
-static int mpu_setup_region(unsigned int number, phys_addr_t start,
+static int __init mpu_setup_region(unsigned int number, phys_addr_t start,
unsigned int size_order, unsigned int properties)
{
u32 size_data;
/* We kept a region free for probing resolution of MPU regions*/
- if (number > mpu_max_regions() || number == MPU_PROBE_REGION)
+ if (number > mpu_max_regions
+ || number >= MPU_MAX_REGIONS)
return -ENOENT;
if (size_order > 32)
return -ENOMEM;
- if (size_order < mpu_min_region_order())
+ if (size_order < mpu_min_region_order)
return -ENOMEM;
/* Writing N to bits 5:1 (RSR_SZ) specifies region size 2^N+1 */
@@ -240,6 +250,9 @@ static int mpu_setup_region(unsigned int number, phys_addr_t start,
mpu_rgn_info.rgns[number].dracr = properties;
mpu_rgn_info.rgns[number].drbar = start;
mpu_rgn_info.rgns[number].drsr = size_data;
+
+ mpu_rgn_info.used++;
+
return 0;
}
@@ -248,19 +261,38 @@ static int mpu_setup_region(unsigned int number, phys_addr_t start,
*/
void __init mpu_setup(void)
{
- int region_err;
+ int region = 0, err = 0;
+
if (!mpu_present())
return;
- region_err = mpu_setup_region(MPU_RAM_REGION, PHYS_OFFSET,
- ilog2(memblock.memory.regions[0].size),
- MPU_AP_PL1RW_PL0RW | MPU_RGN_NORMAL);
- if (region_err) {
- panic("MPU region initialization failure! %d", region_err);
+ /* Free-up MPU_PROBE_REGION */
+ mpu_min_region_order = __mpu_min_region_order();
+
+ /* How many regions are supported */
+ mpu_max_regions = __mpu_max_regions();
+
+ /* Now setup MPU (order is important) */
+
+ /* Background */
+ err |= mpu_setup_region(region++, 0, 32,
+ MPU_ACR_XN | MPU_RGN_STRONGLY_ORDERED | MPU_AP_PL1RW_PL0NA);
+
+ /* RAM */
+ err |= mpu_setup_region(region++, PHYS_OFFSET,
+ ilog2(memblock.memory.regions[0].size),
+ MPU_AP_PL1RW_PL0RW | MPU_RGN_NORMAL);
+
+ /* Vectors */
+ err |= mpu_setup_region(region++, vectors_base,
+ ilog2(2 * PAGE_SIZE),
+ MPU_AP_PL1RW_PL0NA | MPU_RGN_NORMAL);
+ if (err) {
+ panic("MPU region initialization failure! %d", err);
} else {
pr_info("Using ARMv7 PMSA Compliant MPU. "
- "Region independence: %s, Max regions: %d\n",
+ "Region independence: %s, Used %d of %d regions\n",
mpu_iside_independent() ? "Yes" : "No",
- mpu_max_regions());
+ mpu_rgn_info.used, mpu_max_regions);
}
}