aboutsummaryrefslogtreecommitdiffstats
path: root/arch
diff options
context:
space:
mode:
authorMarc Zyngier <Marc.Zyngier@arm.com>2013-06-21 07:06:19 -0400
committerGreg Kroah-Hartman <gregkh@linuxfoundation.org>2013-07-21 21:21:33 -0400
commitb7dc4032cd44843ea93119adb00a5f15b7b05943 (patch)
tree52faa078648b8fa6418ee78ae4abca59265bca66 /arch
parentc9f3f7f79f3ee852f253bdb1dbbb43d79bcaa6c2 (diff)
ARM: 7767/1: let the ASID allocator handle suspended animation
commit ae120d9edfe96628f03d87634acda0bfa7110632 upstream. When a CPU is running a process, the ASID for that process is held in a per-CPU variable (the "active ASIDs" array). When the ASID allocator handles a rollover, it copies the active ASIDs into a "reserved ASIDs" array to ensure that a process currently running on another CPU will continue to run unaffected. The active array is zero-ed to indicate that a rollover occurred. Because of this mechanism, a reserved ASID is only remembered for a single rollover. A subsequent rollover will completely refill the reserved ASIDs array. In a severely oversubscribed environment where a CPU can be prevented from running for extended periods of time (think virtual machines), the above has a horrible side effect: [P{a} denotes process P running with ASID a] CPU-0 CPU-1 A{x} [active = <x 0>] [suspended] runs B{y} [active = <x y>] [rollover: active = <0 0> reserved = <x y>] runs B{y} [active = <0 y> reserved = <x y>] [rollover: active = <0 0> reserved = <0 y>] runs C{x} [active = <0 x>] [resumes] runs A{x} At that stage, both A and C have the same ASID, with deadly consequences. The fix is to preserve reserved ASIDs across rollovers if the CPU doesn't have an active ASID when the rollover occurs. Acked-by: Will Deacon <will.deacon@arm.com> Acked-by: Catalin Carinas <catalin.marinas@arm.com> Signed-off-by: Marc Zyngier <marc.zyngier@arm.com> Signed-off-by: Russell King <rmk+kernel@arm.linux.org.uk> Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
Diffstat (limited to 'arch')
-rw-r--r--arch/arm/mm/context.c9
1 files changed, 9 insertions, 0 deletions
diff --git a/arch/arm/mm/context.c b/arch/arm/mm/context.c
index 2ac37372ef52..8e12fcbb2c63 100644
--- a/arch/arm/mm/context.c
+++ b/arch/arm/mm/context.c
@@ -128,6 +128,15 @@ static void flush_context(unsigned int cpu)
128 asid = 0; 128 asid = 0;
129 } else { 129 } else {
130 asid = atomic64_xchg(&per_cpu(active_asids, i), 0); 130 asid = atomic64_xchg(&per_cpu(active_asids, i), 0);
131 /*
132 * If this CPU has already been through a
133 * rollover, but hasn't run another task in
134 * the meantime, we must preserve its reserved
135 * ASID, as this is the only trace we have of
136 * the process it is still running.
137 */
138 if (asid == 0)
139 asid = per_cpu(reserved_asids, i);
131 __set_bit(ASID_TO_IDX(asid), asid_map); 140 __set_bit(ASID_TO_IDX(asid), asid_map);
132 } 141 }
133 per_cpu(reserved_asids, i) = asid; 142 per_cpu(reserved_asids, i) = asid;