Skip to content

Commit fba333a

Browse files
neobuddy89gregtwallace
authored andcommitted
ARM: Use TTBR1 instead of reserved context ID
On ARMv7 CPUs that cache first level page table entries (like the Cortex-A15), using a reserved ASID while changing the TTBR or flushing the TLB is unsafe. This is because the CPU may cache the first level entry as the result of a speculative memory access while the reserved ASID is assigned. After the process owning the page tables dies, the memory will be reallocated and may be written with junk values which can be interpreted as global, valid PTEs by the processor. This will result in the TLB being populated with bogus global entries. This patch avoids the use of a reserved context ID in the v7 switch_mm and ASID rollover code by temporarily using the swapper_pg_dir pointed at by TTBR1, which contains only global entries that are not tagged with ASIDs. Reviewed-by: Frank Rowand <[email protected]> Tested-by: Marc Zyngier <[email protected]> Signed-off-by: Will Deacon <[email protected]> [[email protected]: add LPAE support] Signed-off-by: Catalin Marinas <[email protected]> Change-Id: I2dd82501dac5ee402765aaa0ffb3f7f577a603c9 ARM: Remove __ARCH_WANT_INTERRUPTS_ON_CTXSW on ASID-capable CPUs Since the ASIDs must be unique to an mm across all the CPUs in a system, the __new_context() function needs to broadcast a context reset event to all the CPUs during ASID allocation if a roll-over occurred. Such IPIs cannot be issued with interrupts disabled and ARM had to define __ARCH_WANT_INTERRUPTS_ON_CTXSW. This patch changes the check_context() function to check_and_switch_context() called from switch_mm(). In case of ASID-capable CPUs (ARMv6 onwards), if a new ASID is needed and the interrupts are disabled, it defers the __new_context() and cpu_switch_mm() calls to the post-lock switch hook where the interrupts are enabled. Setting the reserved TTBR0 was also moved to check_and_switch_context() from cpu_v7_switch_mm(). Reviewed-by: Will Deacon <[email protected]> Tested-by: Will Deacon <[email protected]> Reviewed-by: Frank Rowand <[email protected]> Tested-by: Marc Zyngier <[email protected]> Signed-off-by: Catalin Marinas <[email protected]> Conflicts: arch/arm/mm/proc-v7-2level.S Change-Id: I48e39730c49ff8d30ce566e8a03cf54557869a52 ARM: Remove current_mm per-cpu variable The current_mm variable was used to store the new mm between the switch_mm() and switch_to() calls where an IPI to reset the context could have set the wrong mm. Since the interrupts are disabled during context switch, there is no need for this variable, current->active_mm already points to the current mm when interrupts are re-enabled. Reviewed-by: Will Deacon <[email protected]> Tested-by: Will Deacon <[email protected]> Reviewed-by: Frank Rowand <[email protected]> Tested-by: Marc Zyngier <[email protected]> Signed-off-by: Catalin Marinas <[email protected]> ARM: 7502/1: contextidr: avoid using bfi instruction during notifier The bfi instruction is not available on ARMv6, so instead use an and/orr sequence in the contextidr_notifier. This gets rid of the assembler error: Assembler messages: Error: selected processor does not support ARM mode `bfi r3,r2,#0,lg-devs#8' Reported-by: Arnd Bergmann <[email protected]> Signed-off-by: Will Deacon <[email protected]> Signed-off-by: Russell King <[email protected]> Conflicts: arch/arm/mm/context.c Change-Id: Id64c0145d0dcd1cfe9e2aba59f86c08ec5fbf649 ARM: mm: remove IPI broadcasting on ASID rollover ASIDs are allocated to MMU contexts based on a rolling counter. This means that after 255 allocations we must invalidate all existing ASIDs via an expensive IPI mechanism to synchronise all of the online CPUs and ensure that all tasks execute with an ASID from the new generation. This patch changes the rollover behaviour so that we rely instead on the hardware broadcasting of the TLB invalidation to avoid the IPI calls. This works by keeping track of the active ASID on each core, which is then reserved in the case of a rollover so that currently scheduled tasks can continue to run. For cores without hardware TLB broadcasting, we keep track of pending flushes in a cpumask, so cores can flush their local TLB before scheduling a new mm. Reviewed-by: Catalin Marinas <[email protected]> Tested-by: Marc Zyngier <[email protected]> Signed-off-by: Will Deacon <[email protected]> Conflicts: arch/arm/mm/context.c Change-Id: I58990400aaaaef35319f7b3fb2f84fe7e46cb581 ARM: mm: avoid taking ASID spinlock on fastpath When scheduling a new mm, we take a spinlock so that we can: 1. Safely allocate a new ASID, if required 2. Update our active_asids field without worrying about parallel updates to reserved_asids 3. Ensure that we flush our local TLB, if required However, this has the nasty affect of serialising context-switch across all CPUs in the system. The usual (fast) case is where the next mm has a valid ASID for the current generation. In such a scenario, we can avoid taking the lock and instead use atomic64_xchg to update the active_asids variable for the current CPU. If a rollover occurs on another CPU (which would take the lock), when copying the active_asids into the reserved_asids another atomic64_xchg is used to replace each active_asids with 0. The fast path can then detect this case and fall back to spinning on the lock. Tested-by: Marc Zyngier <[email protected]> Signed-off-by: Will Deacon <[email protected]> ARM: mm: use bitmap operations when allocating new ASIDs When allocating a new ASID, we must take care not to re-assign a reserved ASID-value to a new mm. This requires us to check each candidate ASID against those currently reserved by other cores before assigning a new ASID to the current mm. This patch improves the ASID allocation algorithm by using a bitmap-based approach. Rather than iterating over the reserved ASID array for each candidate ASID, we simply find the first zero bit, ensuring that those indices corresponding to reserved ASIDs are set when flushing during a rollover event. Tested-by: Marc Zyngier <[email protected]> Signed-off-by: Will Deacon <[email protected]> ARM: 7649/1: mm: mm->context.id fix for big-endian Since the new ASID code in b5466f8728527a05a493cc4abe9e6f034a1bbaab ("ARM: mm: remove IPI broadcasting on ASID rollover") was changed to use 64bit operations it has broken the BE operation due to an issue with the MM code accessing sub-fields of mm->context.id. When running in BE mode we see the values in mm->context.id are stored with the highest value first, so the LDR in the arch/arm/mm/proc-macros.S reads the wrong part of this field. To resolve this, change the LDR in the mmid macro to load from +4. Acked-by: Will Deacon <[email protected]> Signed-off-by: Ben Dooks <[email protected]> Signed-off-by: Russell King <[email protected]> ARM: 7658/1: mm: fix race updating mm->context.id on ASID rollover If a thread triggers an ASID rollover, other threads of the same process must be made to wait until the mm->context.id for the shared mm_struct has been updated to new generation and associated book-keeping (e.g. TLB invalidation) has ben performed. However, there is a *tiny* window where both mm->context.id and the relevant active_asids entry are updated to the new generation, but the TLB flush has not been performed, which could allow another thread to return to userspace with a dirty TLB, potentially leading to data corruption. In reality this will never occur because one CPU would need to perform a context-switch in the time it takes another to do a couple of atomic test/set operations but we should plug the race anyway. This patch moves the active_asids update until after the potential TLB flush on context-switch. Cc: <[email protected]> # 3.8 Reviewed-by: Catalin Marinas <[email protected]> Signed-off-by: Will Deacon <[email protected]> Signed-off-by: Russell King <[email protected]> ARM: 7659/1: mm: make mm->context.id an atomic64_t variable mm->context.id is updated under asid_lock when a new ASID is allocated to an mm_struct. However, it is also read without the lock when a task is being scheduled and checking whether or not the current ASID generation is up-to-date. If two threads of the same process are being scheduled in parallel and the bottom bits of the generation in their mm->context.id match the current generation (that is, the mm_struct has not been used for ~2^24 rollovers) then the non-atomic, lockless access to mm->context.id may yield the incorrect ASID. This patch fixes this issue by making mm->context.id and atomic64_t, ensuring that the generation is always read consistently. For code that only requires access to the ASID bits (e.g. TLB flushing by mm), then the value is accessed directly, which GCC converts to an ldrb. Cc: <[email protected]> # 3.8 Reviewed-by: Catalin Marinas <[email protected]> Signed-off-by: Will Deacon <[email protected]> Signed-off-by: Russell King <[email protected]> Conflicts: arch/arm/include/asm/mmu.h Change-Id: I682895d6357a91ecc439c8543fa94f1aecbfcb4c ARM: 7661/1: mm: perform explicit branch predictor maintenance when required The ARM ARM requires branch predictor maintenance if, for a given ASID, the instructions at a specific virtual address appear to change. From the kernel's point of view, that means: - Changing the kernel's view of memory (e.g. switching to the identity map) - ASID rollover (since ASIDs will be re-allocated to new tasks) This patch adds explicit branch predictor maintenance when either of the two conditions above are met. Reviewed-by: Catalin Marinas <[email protected]> Signed-off-by: Will Deacon <[email protected]> Signed-off-by: Russell King <[email protected]> ARM: 7684/1: errata: Workaround for Cortex-A15 erratum 798181 (TLBI/DSB operations) On Cortex-A15 (r0p0..r3p2) the TLBI/DSB are not adequately shooting down all use of the old entries. This patch implements the erratum workaround which consists of: 1. Dummy TLBIMVAIS and DSB on the CPU doing the TLBI operation. 2. Send IPI to the CPUs that are running the same mm (and ASID) as the one being invalidated (or all the online CPUs for global pages). 3. CPU receiving the IPI executes a DMB and CLREX (part of the exception return code already). Signed-off-by: Catalin Marinas <[email protected]> Signed-off-by: Russell King <[email protected]> Conflicts: arch/arm/Kconfig Change-Id: I4513d042301a1faad817b83434280462cc176df1 msm: rtb: Log the context id in the rtb Store the context id in the register trace buffer. The process id can be derived from the context id. This gives a general idea about what process was last running when the RTB stopped. Change-Id: I2fb8934d008b8cf3666f1df2652846c15faca776 Signed-off-by: Laura Abbott <[email protected]> (cherry picked from commit 445eb9a) Conflicts: arch/arm/mach-msm/include/mach/msm_rtb.h 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 <[email protected]> Acked-by: Catalin Carinas <[email protected]> Signed-off-by: Marc Zyngier <[email protected]> Signed-off-by: Russell King <[email protected]> Signed-off-by: Greg Kroah-Hartman <[email protected]> ARM: 7768/1: prevent risks of out-of-bound access in ASID allocator commit b8e4a4740fa2b17c0a447b3ab783b3dc10702e27 upstream. On a CPU that never ran anything, both the active and reserved ASID fields are set to zero. In this case the ASID_TO_IDX() macro will return -1, which is not a very useful value to index a bitmap. Instead of trying to offset the ASID so that ASID lg-devs#1 is actually bit 0 in the asid_map bitmap, just always ignore bit 0 and start the search from bit 1. This makes the code a bit more readable, and without risk of OoB access. Acked-by: Will Deacon <[email protected]> Acked-by: Catalin Marinas <[email protected]> Reported-by: Catalin Marinas <[email protected]> Signed-off-by: Marc Zyngier <[email protected]> Signed-off-by: Russell King <[email protected]> Signed-off-by: Greg Kroah-Hartman <[email protected]> ARM: 7703/1: Disable preemption in broadcast_tlb*_a15_erratum() Commit 93dc688 (ARM: 7684/1: errata: Workaround for Cortex-A15 erratum 798181 (TLBI/DSB operations)) introduces calls to smp_processor_id() and smp_call_function_many() with preemption enabled. This patch disables preemption and also optimises the smp_processor_id() call in broadcast_tlb_mm_a15_erratum(). The broadcast_tlb_a15_erratum() function is changed to use smp_call_function() which disables preemption. Signed-off-by: Catalin Marinas <[email protected]> Reported-by: Geoff Levand <[email protected]> Reported-by: Nicolas Pitre <[email protected]> Signed-off-by: Russell King <[email protected]> ARM: 7769/1: Cortex-A15: fix erratum 798181 implementation commit 0d0752bca1f9a91fb646647aa4abbb21156f316c upstream. Looking into the active_asids array is not enough, as we also need to look into the reserved_asids array (they both represent processes that are currently running). Also, not holding the ASID allocator lock is racy, as another CPU could schedule that process and trigger a rollover, making the erratum workaround miss an IPI. Exposing this outside of context.c is a little ugly on the side, so let's define a new entry point that the erratum workaround can call to obtain the cpumask. Acked-by: Will Deacon <[email protected]> Acked-by: Catalin Marinas <[email protected]> Signed-off-by: Marc Zyngier <[email protected]> Signed-off-by: Russell King <[email protected]> Signed-off-by: Greg Kroah-Hartman <[email protected]> arm: mm: Clean ASID patchset Change-Id: Id5b0cc6d5300d293e33baf6603453bde0df6d6d8 android/lowmemorykiller: Ignore tasks with freed mm A killed task can stay in the task list long after its memory has been returned to the system, therefore ignore any tasks whose mm struct has been freed. Change-Id: I76394b203b4ab2312437c839976f0ecb7b6dde4e CRs-fixed: 450383 Signed-off-by: Liam Mark <[email protected]> Signed-off-by: Pranav Vashi <[email protected]>
1 parent 0231cde commit fba333a

File tree

14 files changed

+306
-219
lines changed

14 files changed

+306
-219
lines changed

arch/arm/Kconfig

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1534,6 +1534,16 @@ config ARM_ERRATA_775420
15341534
to deadlock. This workaround puts DSB before executing ISB if
15351535
an abort may occur on cache maintenance.
15361536

1537+
config ARM_ERRATA_798181
1538+
bool "ARM errata: TLBI/DSB failure on Cortex-A15"
1539+
depends on CPU_V7 && SMP
1540+
help
1541+
On Cortex-A15 (r0p0..r3p2) the TLBI*IS/DSB operations are not
1542+
adequately shooting down all use of the old entries. This
1543+
option enables the Linux kernel workaround for this erratum
1544+
which sends an IPI to the CPUs that are running the same ASID
1545+
as the one being invalidated.
1546+
15371547
endmenu
15381548

15391549
source "arch/arm/common/Kconfig"

arch/arm/include/asm/highmem.h

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -41,6 +41,13 @@ extern void kunmap_high(struct page *page);
4141
#endif
4242
#endif
4343

44+
/*
45+
* Needed to be able to broadcast the TLB invalidation for kmap.
46+
*/
47+
#ifdef CONFIG_ARM_ERRATA_798181
48+
#undef ARCH_NEEDS_KMAP_HIGH_GET
49+
#endif
50+
4451
#ifdef ARCH_NEEDS_KMAP_HIGH_GET
4552
extern void *kmap_high_get(struct page *page);
4653
#else

arch/arm/include/asm/mmu.h

Lines changed: 7 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -5,19 +5,16 @@
55

66
typedef struct {
77
#ifdef CONFIG_CPU_HAS_ASID
8-
unsigned int id;
9-
raw_spinlock_t id_lock;
8+
atomic64_t id;
109
#endif
1110
unsigned int kvm_seq;
1211
unsigned long sigpage;
1312
} mm_context_t;
1413

1514
#ifdef CONFIG_CPU_HAS_ASID
16-
#define ASID(mm) ((mm)->context.id & 255)
17-
18-
/* init_mm.context.id_lock should be initialized. */
19-
#define INIT_MM_CONTEXT(name) \
20-
.context.id_lock = __RAW_SPIN_LOCK_UNLOCKED(name.context.id_lock),
15+
#define ASID_BITS 8
16+
#define ASID_MASK ((~0ULL) << ASID_BITS)
17+
#define ASID(mm) ((mm)->context.id.counter & ~ASID_MASK)
2118
#else
2219
#define ASID(mm) (0)
2320
#endif
@@ -30,7 +27,7 @@ typedef struct {
3027
* modified for 2.6 by Hyok S. Choi <[email protected]>
3128
*/
3229
typedef struct {
33-
unsigned long end_brk;
30+
unsigned long end_brk;
3431
} mm_context_t;
3532

3633
#endif
@@ -40,6 +37,8 @@ typedef struct {
4037
* so enable interrupts over the context switch to avoid high
4138
* latency.
4239
*/
40+
#ifndef CONFIG_CPU_HAS_ASID
4341
#define __ARCH_WANT_INTERRUPTS_ON_CTXSW
42+
#endif
4443

4544
#endif

arch/arm/include/asm/mmu_context.h

Lines changed: 19 additions & 52 deletions
Original file line numberDiff line numberDiff line change
@@ -24,66 +24,39 @@ void __check_kvm_seq(struct mm_struct *mm);
2424

2525
#ifdef CONFIG_CPU_HAS_ASID
2626

27-
/*
28-
* On ARMv6, we have the following structure in the Context ID:
29-
*
30-
* 31 7 0
31-
* +-------------------------+-----------+
32-
* | process ID | ASID |
33-
* +-------------------------+-----------+
34-
* | context ID |
35-
* +-------------------------------------+
36-
*
37-
* The ASID is used to tag entries in the CPU caches and TLBs.
38-
* The context ID is used by debuggers and trace logic, and
39-
* should be unique within all running processes.
40-
*/
41-
#define ASID_BITS 8
42-
#define ASID_MASK ((~0) << ASID_BITS)
43-
#define ASID_FIRST_VERSION (1 << ASID_BITS)
44-
45-
extern unsigned int cpu_last_asid;
46-
#ifdef CONFIG_SMP
47-
DECLARE_PER_CPU(struct mm_struct *, current_mm);
48-
#endif
49-
50-
void __init_new_context(struct task_struct *tsk, struct mm_struct *mm);
51-
void __new_context(struct mm_struct *mm);
52-
53-
static inline void check_context(struct mm_struct *mm)
27+
void check_and_switch_context(struct mm_struct *mm, struct task_struct *tsk);
28+
#define init_new_context(tsk,mm) ({ atomic64_set(&mm->context.id, 0); 0; })
29+
30+
#ifdef CONFIG_ARM_ERRATA_798181
31+
void a15_erratum_get_cpumask(int this_cpu, struct mm_struct *mm,
32+
cpumask_t *mask);
33+
#else /* !CONFIG_ARM_ERRATA_798181 */
34+
static inline void a15_erratum_get_cpumask(int this_cpu, struct mm_struct *mm,
35+
cpumask_t *mask)
5436
{
55-
/*
56-
* This code is executed with interrupts enabled. Therefore,
57-
* mm->context.id cannot be updated to the latest ASID version
58-
* on a different CPU (and condition below not triggered)
59-
* without first getting an IPI to reset the context. The
60-
* alternative is to take a read_lock on mm->context.id_lock
61-
* (after changing its type to rwlock_t).
62-
*/
63-
if (unlikely((mm->context.id ^ cpu_last_asid) >> ASID_BITS))
64-
__new_context(mm);
65-
66-
if (unlikely(mm->context.kvm_seq != init_mm.context.kvm_seq))
67-
__check_kvm_seq(mm);
6837
}
38+
#endif /* CONFIG_ARM_ERRATA_798181 */
6939

70-
#define init_new_context(tsk,mm) (__init_new_context(tsk,mm),0)
71-
72-
#else
40+
#else /* !CONFIG_CPU_HAS_ASID */
7341

74-
static inline void check_context(struct mm_struct *mm)
42+
static inline void check_and_switch_context(struct mm_struct *mm,
43+
struct task_struct *tsk)
7544
{
7645
#ifdef CONFIG_MMU
7746
if (unlikely(mm->context.kvm_seq != init_mm.context.kvm_seq))
7847
__check_kvm_seq(mm);
48+
cpu_switch_mm(mm->pgd, mm);
7949
#endif
8050
}
8151

8252
#define init_new_context(tsk,mm) 0
8353

84-
#endif
54+
#define finish_arch_post_lock_switch() do { } while (0)
55+
56+
#endif /* CONFIG_CPU_HAS_ASID */
8557

8658
#define destroy_context(mm) do { } while(0)
59+
#define activate_mm(prev,next) switch_mm(prev, next, NULL)
8760

8861
/*
8962
* This is called when "tsk" is about to enter lazy TLB mode.
@@ -119,19 +92,13 @@ switch_mm(struct mm_struct *prev, struct mm_struct *next,
11992
__flush_icache_all();
12093
#endif
12194
if (!cpumask_test_and_set_cpu(cpu, mm_cpumask(next)) || prev != next) {
122-
#ifdef CONFIG_SMP
123-
struct mm_struct **crt_mm = &per_cpu(current_mm, cpu);
124-
*crt_mm = next;
125-
#endif
126-
check_context(next);
127-
cpu_switch_mm(next->pgd, next);
95+
check_and_switch_context(next, tsk);
12896
if (cache_is_vivt())
12997
cpumask_clear_cpu(cpu, mm_cpumask(prev));
13098
}
13199
#endif
132100
}
133101

134102
#define deactivate_mm(tsk,mm) do { } while (0)
135-
#define activate_mm(prev,next) switch_mm(prev, next, NULL)
136103

137104
#endif

arch/arm/include/asm/thread_info.h

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -154,7 +154,9 @@ extern int vfp_restore_user_hwstate(struct user_vfp __user *,
154154
#define TIF_MEMDIE 18 /* is terminating due to OOM killer */
155155
#define TIF_RESTORE_SIGMASK 20
156156
#define TIF_SECCOMP 21
157-
#define TIF_MM_RELEASED 22 /* task MM has been released */
157+
#define TIF_SWITCH_MM 22 /* deferred switch_mm */
158+
#define TIF_MM_RELEASED 23 /* task MM has been released */
159+
158160
#define _TIF_SIGPENDING (1 << TIF_SIGPENDING)
159161
#define _TIF_NEED_RESCHED (1 << TIF_NEED_RESCHED)
160162
#define _TIF_NOTIFY_RESUME (1 << TIF_NOTIFY_RESUME)

arch/arm/include/asm/tlbflush.h

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -471,6 +471,21 @@ static inline void local_flush_bp_all(void)
471471
isb();
472472
}
473473

474+
#ifdef CONFIG_ARM_ERRATA_798181
475+
static inline void dummy_flush_tlb_a15_erratum(void)
476+
{
477+
/*
478+
* Dummy TLBIMVAIS. Using the unmapped address 0 and ASID 0.
479+
*/
480+
asm("mcr p15, 0, %0, c8, c3, 1" : : "r" (0));
481+
dsb();
482+
}
483+
#else
484+
static inline void dummy_flush_tlb_a15_erratum(void)
485+
{
486+
}
487+
#endif
488+
474489
/*
475490
* flush_pmd_entry
476491
*

arch/arm/kernel/asm-offsets.c

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -105,7 +105,7 @@ int main(void)
105105
BLANK();
106106
#endif
107107
#ifdef CONFIG_CPU_HAS_ASID
108-
DEFINE(MM_CONTEXT_ID, offsetof(struct mm_struct, context.id));
108+
DEFINE(MM_CONTEXT_ID, offsetof(struct mm_struct, context.id.counter));
109109
BLANK();
110110
#endif
111111
DEFINE(VMA_VM_MM, offsetof(struct vm_area_struct, vm_mm));

arch/arm/kernel/smp.c

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -297,6 +297,7 @@ asmlinkage void __cpuinit secondary_start_kernel(void)
297297
* switch away from it before attempting any exclusive accesses.
298298
*/
299299
cpu_switch_mm(mm->pgd, mm);
300+
local_flush_bp_all();
300301
enter_lazy_tlb(mm, current);
301302
local_flush_tlb_all();
302303

arch/arm/kernel/smp_tlb.c

Lines changed: 53 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,7 @@
1212

1313
#include <asm/smp_plat.h>
1414
#include <asm/tlbflush.h>
15+
#include <asm/mmu_context.h>
1516

1617
/**********************************************************************/
1718

@@ -69,12 +70,59 @@ static inline void ipi_flush_bp_all(void *ignored)
6970
local_flush_bp_all();
7071
}
7172

73+
#ifdef CONFIG_ARM_ERRATA_798181
74+
static int erratum_a15_798181(void)
75+
{
76+
unsigned int midr = read_cpuid_id();
77+
78+
/* Cortex-A15 r0p0..r3p2 affected */
79+
if ((midr & 0xff0ffff0) != 0x410fc0f0 || midr > 0x413fc0f2)
80+
return 0;
81+
return 1;
82+
}
83+
#else
84+
static int erratum_a15_798181(void)
85+
{
86+
return 0;
87+
}
88+
#endif
89+
90+
static void ipi_flush_tlb_a15_erratum(void *arg)
91+
{
92+
dmb();
93+
}
94+
95+
static void broadcast_tlb_a15_erratum(void)
96+
{
97+
if (!erratum_a15_798181())
98+
return;
99+
100+
dummy_flush_tlb_a15_erratum();
101+
smp_call_function(ipi_flush_tlb_a15_erratum, NULL, 1);
102+
}
103+
104+
static void broadcast_tlb_mm_a15_erratum(struct mm_struct *mm)
105+
{
106+
int this_cpu;
107+
cpumask_t mask = { CPU_BITS_NONE };
108+
109+
if (!erratum_a15_798181())
110+
return;
111+
112+
dummy_flush_tlb_a15_erratum();
113+
this_cpu = get_cpu();
114+
a15_erratum_get_cpumask(this_cpu, mm, &mask);
115+
smp_call_function_many(&mask, ipi_flush_tlb_a15_erratum, NULL, 1);
116+
put_cpu();
117+
}
118+
72119
void flush_tlb_all(void)
73120
{
74121
if (tlb_ops_need_broadcast())
75122
on_each_cpu(ipi_flush_tlb_all, NULL, 1);
76123
else
77124
local_flush_tlb_all();
125+
broadcast_tlb_a15_erratum();
78126
}
79127

80128
void flush_tlb_mm(struct mm_struct *mm)
@@ -83,6 +131,7 @@ void flush_tlb_mm(struct mm_struct *mm)
83131
on_each_cpu_mask(mm_cpumask(mm), ipi_flush_tlb_mm, mm, 1);
84132
else
85133
local_flush_tlb_mm(mm);
134+
broadcast_tlb_mm_a15_erratum(mm);
86135
}
87136

88137
void flush_tlb_page(struct vm_area_struct *vma, unsigned long uaddr)
@@ -95,6 +144,7 @@ void flush_tlb_page(struct vm_area_struct *vma, unsigned long uaddr)
95144
&ta, 1);
96145
} else
97146
local_flush_tlb_page(vma, uaddr);
147+
broadcast_tlb_mm_a15_erratum(vma->vm_mm);
98148
}
99149

100150
void flush_tlb_kernel_page(unsigned long kaddr)
@@ -105,6 +155,7 @@ void flush_tlb_kernel_page(unsigned long kaddr)
105155
on_each_cpu(ipi_flush_tlb_kernel_page, &ta, 1);
106156
} else
107157
local_flush_tlb_kernel_page(kaddr);
158+
broadcast_tlb_a15_erratum();
108159
}
109160

110161
void flush_tlb_range(struct vm_area_struct *vma,
@@ -119,6 +170,7 @@ void flush_tlb_range(struct vm_area_struct *vma,
119170
&ta, 1);
120171
} else
121172
local_flush_tlb_range(vma, start, end);
173+
broadcast_tlb_mm_a15_erratum(vma->vm_mm);
122174
}
123175

124176
void flush_tlb_kernel_range(unsigned long start, unsigned long end)
@@ -130,6 +182,7 @@ void flush_tlb_kernel_range(unsigned long start, unsigned long end)
130182
on_each_cpu(ipi_flush_tlb_kernel_range, &ta, 1);
131183
} else
132184
local_flush_tlb_kernel_range(start, end);
185+
broadcast_tlb_a15_erratum();
133186
}
134187

135188
void flush_bp_all(void)

arch/arm/kernel/suspend.c

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -68,6 +68,7 @@ int cpu_suspend(unsigned long arg, int (*fn)(unsigned long))
6868
ret = __cpu_suspend(arg, fn);
6969
if (ret == 0) {
7070
cpu_switch_mm(mm->pgd, mm);
71+
local_flush_bp_all();
7172
local_flush_tlb_all();
7273
}
7374

0 commit comments

Comments
 (0)