ARM: support for IRQ and vmap'ed stacks [v6]
This tag covers the changes between the version of vmap'ed + IRQ stacks support pulled into rmk/devel-stable [0] (which was dropped from v5.17 due to issues discovered too late in the cycle), and my v5 proposed for the v5.18 cycle [1]. [0] git://git.kernel.org/pub/scm/linux/kernel/git/ardb/linux.git arm-irq-and-vmap-stacks-for-rmk [1] https://lore.kernel.org/linux-arm-kernel/20220124174744.1054712-1-ardb@kernel.org/ -----BEGIN PGP SIGNATURE----- iQGzBAABCgAdFiEE+9lifEBpyUIVN1cpw08iOZLZjyQFAmH3+1oACgkQw08iOZLZ jyRdyAv/TiYdEkpteCUz1MucDFEZsRz1FXYTUwFG5pxSIONUDdDm0KvjYoY80n7X wUMZyfAwjdHpQtP0iu4RwAmi7d373KtWTqFzwAoBG9RFTSy/4j4B3ZzsPkoCn9uN ANXpyJE2lqvN3d25WKnRq6+WGSxdvhYqBQARe1oznirgN4ilKtmBkKCL3W+gsO7l N6q5DLsqSI80kAIorFUr0sF8b1JEK/APOokaAICLyP6fkjp3hu+jUvJENCsJk27V rVHhFmKdtpwl02hs+I13I5nrAXwYN6COSBa9y0xuPRgBk2sgnpFKSMKAvYafwHhg AYwUuez/Tk6AHHowu+/ggoap2At04l4rdwzV0BIE/+9vdT3C+4M5tikHglQnRjtR PRyErdCPPEW6gz+fYdYoaCYXVfRGCQeCyInVQIl6U9HAqcVLPHNZecGz0rYBTQA2 GiUfi0YA3SASMIggP4mug4M5fwbgUbh/i3OgMYGcnCg+5phmR7Z+niJVN9j0uPf2 XMsCsTi/ =utwu -----END PGP SIGNATURE----- Merge tag 'arm-vmap-stacks-v6' of git://git.kernel.org/pub/scm/linux/kernel/git/ardb/linux into devel-stable ARM: support for IRQ and vmap'ed stacks [v6] This tag covers the changes between the version of vmap'ed + IRQ stacks support pulled into rmk/devel-stable [0] (which was dropped from v5.17 due to issues discovered too late in the cycle), and my v5 proposed for the v5.18 cycle [1]. [0] git://git.kernel.org/pub/scm/linux/kernel/git/ardb/linux.git arm-irq-and-vmap-stacks-for-rmk [1] https://lore.kernel.org/linux-arm-kernel/20220124174744.1054712-1-ardb@kernel.org/
This commit is contained in:
commit
2fa3948244
|
@ -128,7 +128,7 @@ config ARM
|
|||
select RTC_LIB
|
||||
select SYS_SUPPORTS_APM_EMULATION
|
||||
select THREAD_INFO_IN_TASK
|
||||
select HAVE_ARCH_VMAP_STACK if MMU && (!LD_IS_LLD || LLD_VERSION >= 140000) && !PM_SLEEP_SMP
|
||||
select HAVE_ARCH_VMAP_STACK if MMU && ARM_HAS_GROUP_RELOCS
|
||||
select TRACE_IRQFLAGS_SUPPORT if !CPU_V7M
|
||||
# Above selects are sorted alphabetically; please add new ones
|
||||
# according to that. Thanks.
|
||||
|
@ -140,6 +140,17 @@ config ARM
|
|||
Europe. There is an ARM Linux project with a web page at
|
||||
<http://www.arm.linux.org.uk/>.
|
||||
|
||||
config ARM_HAS_GROUP_RELOCS
|
||||
def_bool y
|
||||
depends on !LD_IS_LLD || LLD_VERSION >= 140000
|
||||
depends on !COMPILE_TEST
|
||||
help
|
||||
Whether or not to use R_ARM_ALU_PC_Gn or R_ARM_LDR_PC_Gn group
|
||||
relocations, which have been around for a long time, but were not
|
||||
supported in LLD until version 14. The combined range is -/+ 256 MiB,
|
||||
which is usually sufficient, but not for allyesconfig, so we disable
|
||||
this feature when doing compile testing.
|
||||
|
||||
config ARM_HAS_SG_CHAIN
|
||||
bool
|
||||
|
||||
|
|
|
@ -656,8 +656,8 @@ THUMB( orr \reg , \reg , #PSR_T_BIT )
|
|||
|
||||
.macro __ldst_va, op, reg, tmp, sym, cond
|
||||
#if __LINUX_ARM_ARCH__ >= 7 || \
|
||||
(defined(MODULE) && defined(CONFIG_ARM_MODULE_PLTS)) || \
|
||||
(defined(CONFIG_LD_IS_LLD) && CONFIG_LLD_VERSION < 140000)
|
||||
!defined(CONFIG_ARM_HAS_GROUP_RELOCS) || \
|
||||
(defined(MODULE) && defined(CONFIG_ARM_MODULE_PLTS))
|
||||
mov_l \tmp, \sym, \cond
|
||||
\op\cond \reg, [\tmp]
|
||||
#else
|
||||
|
@ -716,8 +716,8 @@ THUMB( orr \reg , \reg , #PSR_T_BIT )
|
|||
*/
|
||||
.macro ldr_this_cpu, rd:req, sym:req, t1:req, t2:req
|
||||
#if __LINUX_ARM_ARCH__ >= 7 || \
|
||||
(defined(MODULE) && defined(CONFIG_ARM_MODULE_PLTS)) || \
|
||||
(defined(CONFIG_LD_IS_LLD) && CONFIG_LLD_VERSION < 140000)
|
||||
!defined(CONFIG_ARM_HAS_GROUP_RELOCS) || \
|
||||
(defined(MODULE) && defined(CONFIG_ARM_MODULE_PLTS))
|
||||
this_cpu_offset \t1
|
||||
mov_l \t2, \sym
|
||||
ldr \rd, [\t1, \t2]
|
||||
|
|
|
@ -14,7 +14,7 @@ struct task_struct;
|
|||
|
||||
extern struct task_struct *__current;
|
||||
|
||||
static inline __attribute_const__ struct task_struct *get_current(void)
|
||||
static __always_inline __attribute_const__ struct task_struct *get_current(void)
|
||||
{
|
||||
struct task_struct *cur;
|
||||
|
||||
|
@ -37,8 +37,8 @@ static inline __attribute_const__ struct task_struct *get_current(void)
|
|||
#ifdef CONFIG_CPU_V6
|
||||
"1: \n\t"
|
||||
" .subsection 1 \n\t"
|
||||
#if !(defined(MODULE) && defined(CONFIG_ARM_MODULE_PLTS)) && \
|
||||
!(defined(CONFIG_LD_IS_LLD) && CONFIG_LLD_VERSION < 140000)
|
||||
#if defined(CONFIG_ARM_HAS_GROUP_RELOCS) && \
|
||||
!(defined(MODULE) && defined(CONFIG_ARM_MODULE_PLTS))
|
||||
"2: " LOAD_SYM_ARMV6(%0, __current) " \n\t"
|
||||
" b 1b \n\t"
|
||||
#else
|
||||
|
@ -55,8 +55,8 @@ static inline __attribute_const__ struct task_struct *get_current(void)
|
|||
#endif
|
||||
: "=r"(cur));
|
||||
#elif __LINUX_ARM_ARCH__>= 7 || \
|
||||
(defined(MODULE) && defined(CONFIG_ARM_MODULE_PLTS)) || \
|
||||
(defined(CONFIG_LD_IS_LLD) && CONFIG_LLD_VERSION < 140000)
|
||||
!defined(CONFIG_ARM_HAS_GROUP_RELOCS) || \
|
||||
(defined(MODULE) && defined(CONFIG_ARM_MODULE_PLTS))
|
||||
cur = __current;
|
||||
#else
|
||||
asm(LOAD_SYM_ARMV6(%0, __current) : "=r"(cur));
|
||||
|
|
|
@ -10,7 +10,7 @@ typedef struct {
|
|||
#else
|
||||
int switch_pending;
|
||||
#endif
|
||||
unsigned int vmalloc_seq;
|
||||
atomic_t vmalloc_seq;
|
||||
unsigned long sigpage;
|
||||
#ifdef CONFIG_VDSO
|
||||
unsigned long vdso;
|
||||
|
|
|
@ -23,6 +23,16 @@
|
|||
|
||||
void __check_vmalloc_seq(struct mm_struct *mm);
|
||||
|
||||
#ifdef CONFIG_MMU
|
||||
static inline void check_vmalloc_seq(struct mm_struct *mm)
|
||||
{
|
||||
if (!IS_ENABLED(CONFIG_ARM_LPAE) &&
|
||||
unlikely(atomic_read(&mm->context.vmalloc_seq) !=
|
||||
atomic_read(&init_mm.context.vmalloc_seq)))
|
||||
__check_vmalloc_seq(mm);
|
||||
}
|
||||
#endif
|
||||
|
||||
#ifdef CONFIG_CPU_HAS_ASID
|
||||
|
||||
void check_and_switch_context(struct mm_struct *mm, struct task_struct *tsk);
|
||||
|
@ -52,8 +62,7 @@ static inline void a15_erratum_get_cpumask(int this_cpu, struct mm_struct *mm,
|
|||
static inline void check_and_switch_context(struct mm_struct *mm,
|
||||
struct task_struct *tsk)
|
||||
{
|
||||
if (unlikely(mm->context.vmalloc_seq != init_mm.context.vmalloc_seq))
|
||||
__check_vmalloc_seq(mm);
|
||||
check_vmalloc_seq(mm);
|
||||
|
||||
if (irqs_disabled())
|
||||
/*
|
||||
|
@ -129,6 +138,15 @@ switch_mm(struct mm_struct *prev, struct mm_struct *next,
|
|||
#endif
|
||||
}
|
||||
|
||||
#ifdef CONFIG_VMAP_STACK
|
||||
static inline void enter_lazy_tlb(struct mm_struct *mm, struct task_struct *tsk)
|
||||
{
|
||||
if (mm != &init_mm)
|
||||
check_vmalloc_seq(mm);
|
||||
}
|
||||
#define enter_lazy_tlb enter_lazy_tlb
|
||||
#endif
|
||||
|
||||
#include <asm-generic/mmu_context.h>
|
||||
|
||||
#endif
|
||||
|
|
|
@ -147,11 +147,10 @@ extern void copy_page(void *to, const void *from);
|
|||
#include <asm/pgtable-3level-types.h>
|
||||
#else
|
||||
#include <asm/pgtable-2level-types.h>
|
||||
#endif
|
||||
|
||||
#ifdef CONFIG_VMAP_STACK
|
||||
#define ARCH_PAGE_TABLE_SYNC_MASK PGTBL_PMD_MODIFIED
|
||||
#endif
|
||||
#endif
|
||||
|
||||
#endif /* CONFIG_MMU */
|
||||
|
||||
|
|
|
@ -25,7 +25,7 @@ static inline void set_my_cpu_offset(unsigned long off)
|
|||
asm volatile("mcr p15, 0, %0, c13, c0, 4" : : "r" (off) : "memory");
|
||||
}
|
||||
|
||||
static inline unsigned long __my_cpu_offset(void)
|
||||
static __always_inline unsigned long __my_cpu_offset(void)
|
||||
{
|
||||
unsigned long off;
|
||||
|
||||
|
@ -38,8 +38,8 @@ static inline unsigned long __my_cpu_offset(void)
|
|||
#ifdef CONFIG_CPU_V6
|
||||
"1: \n\t"
|
||||
" .subsection 1 \n\t"
|
||||
#if !(defined(MODULE) && defined(CONFIG_ARM_MODULE_PLTS)) && \
|
||||
!(defined(CONFIG_LD_IS_LLD) && CONFIG_LLD_VERSION < 140000)
|
||||
#if defined(CONFIG_ARM_HAS_GROUP_RELOCS) && \
|
||||
!(defined(MODULE) && defined(CONFIG_ARM_MODULE_PLTS))
|
||||
"2: " LOAD_SYM_ARMV6(%0, __per_cpu_offset) " \n\t"
|
||||
" b 1b \n\t"
|
||||
#else
|
||||
|
|
|
@ -3,6 +3,7 @@
|
|||
#define __ASM_ARM_SWITCH_TO_H
|
||||
|
||||
#include <linux/thread_info.h>
|
||||
#include <asm/smp_plat.h>
|
||||
|
||||
/*
|
||||
* For v7 SMP cores running a preemptible kernel we may be pre-empted
|
||||
|
@ -40,8 +41,7 @@ static inline void set_ti_cpu(struct task_struct *p)
|
|||
do { \
|
||||
__complete_pending_tlbi(); \
|
||||
set_ti_cpu(next); \
|
||||
if (IS_ENABLED(CONFIG_CURRENT_POINTER_IN_TPIDRURO) || \
|
||||
IS_ENABLED(CONFIG_SMP)) \
|
||||
if (IS_ENABLED(CONFIG_CURRENT_POINTER_IN_TPIDRURO) || is_smp()) \
|
||||
__this_cpu_write(__entry_task, next); \
|
||||
last = __switch_to(prev,task_thread_info(prev), task_thread_info(next)); \
|
||||
} while (0)
|
||||
|
|
|
@ -18,22 +18,32 @@
|
|||
.endm
|
||||
|
||||
.macro switch_tls_v6, base, tp, tpuser, tmp1, tmp2
|
||||
#ifdef CONFIG_SMP
|
||||
ALT_SMP(nop)
|
||||
ALT_UP_B(.L0_\@)
|
||||
.subsection 1
|
||||
#endif
|
||||
.L0_\@:
|
||||
ldr_va \tmp1, elf_hwcap
|
||||
mov \tmp2, #0xffff0fff
|
||||
tst \tmp1, #HWCAP_TLS @ hardware TLS available?
|
||||
streq \tp, [\tmp2, #-15] @ set TLS value at 0xffff0ff0
|
||||
mrcne p15, 0, \tmp2, c13, c0, 2 @ get the user r/w register
|
||||
#ifndef CONFIG_SMP
|
||||
mcrne p15, 0, \tp, c13, c0, 3 @ yes, set TLS register
|
||||
beq .L2_\@
|
||||
mcr p15, 0, \tp, c13, c0, 3 @ yes, set TLS register
|
||||
#ifdef CONFIG_SMP
|
||||
b .L1_\@
|
||||
.previous
|
||||
#endif
|
||||
mcrne p15, 0, \tpuser, c13, c0, 2 @ set user r/w register
|
||||
strne \tmp2, [\base, #TI_TP_VALUE + 4] @ save it
|
||||
.L1_\@: switch_tls_v6k \base, \tp, \tpuser, \tmp1, \tmp2
|
||||
.L2_\@:
|
||||
.endm
|
||||
|
||||
.macro switch_tls_software, base, tp, tpuser, tmp1, tmp2
|
||||
mov \tmp1, #0xffff0fff
|
||||
str \tp, [\tmp1, #-15] @ set TLS value at 0xffff0ff0
|
||||
.endm
|
||||
#else
|
||||
#include <asm/smp_plat.h>
|
||||
#endif
|
||||
|
||||
#ifdef CONFIG_TLS_REG_EMUL
|
||||
|
@ -44,7 +54,7 @@
|
|||
#elif defined(CONFIG_CPU_V6)
|
||||
#define tls_emu 0
|
||||
#define has_tls_reg (elf_hwcap & HWCAP_TLS)
|
||||
#define defer_tls_reg_update IS_ENABLED(CONFIG_SMP)
|
||||
#define defer_tls_reg_update is_smp()
|
||||
#define switch_tls switch_tls_v6
|
||||
#elif defined(CONFIG_CPU_32v6K)
|
||||
#define tls_emu 0
|
||||
|
|
|
@ -38,11 +38,10 @@
|
|||
#ifdef CONFIG_UNWINDER_ARM
|
||||
mov fpreg, sp @ Preserve original SP
|
||||
#else
|
||||
mov r8, fp @ Preserve original FP
|
||||
mov r9, sp @ Preserve original SP
|
||||
mov r7, fp @ Preserve original FP
|
||||
mov r8, sp @ Preserve original SP
|
||||
#endif
|
||||
ldr_this_cpu sp, irq_stack_ptr, r2, r3
|
||||
|
||||
.if \from_user == 0
|
||||
UNWIND( .setfp fpreg, sp )
|
||||
@
|
||||
|
@ -82,8 +81,8 @@ UNWIND( .setfp fpreg, sp )
|
|||
#ifdef CONFIG_UNWINDER_ARM
|
||||
mov sp, fpreg @ Restore original SP
|
||||
#else
|
||||
mov fp, r8 @ Restore original FP
|
||||
mov sp, r9 @ Restore original SP
|
||||
mov fp, r7 @ Restore original FP
|
||||
mov sp, r8 @ Restore original SP
|
||||
#endif // CONFIG_UNWINDER_ARM
|
||||
#endif // CONFIG_IRQSTACKS
|
||||
.endm
|
||||
|
|
|
@ -292,21 +292,18 @@
|
|||
|
||||
|
||||
.macro restore_user_regs, fast = 0, offset = 0
|
||||
#if defined(CONFIG_CPU_32v6K) || defined(CONFIG_SMP)
|
||||
#if defined(CONFIG_CPU_V6) && defined(CONFIG_SMP)
|
||||
ALT_SMP(b .L1_\@ )
|
||||
ALT_UP( nop )
|
||||
ldr_va r1, elf_hwcap
|
||||
tst r1, #HWCAP_TLS @ hardware TLS available?
|
||||
beq .L2_\@
|
||||
.L1_\@:
|
||||
#if defined(CONFIG_CPU_32v6K) && \
|
||||
(!defined(CONFIG_CPU_V6) || defined(CONFIG_SMP))
|
||||
#ifdef CONFIG_CPU_V6
|
||||
ALT_SMP(nop)
|
||||
ALT_UP_B(.L1_\@)
|
||||
#endif
|
||||
@ The TLS register update is deferred until return to user space so we
|
||||
@ can use it for other things while running in the kernel
|
||||
get_thread_info r1
|
||||
mrc p15, 0, r1, c13, c0, 3 @ get current_thread_info pointer
|
||||
ldr r1, [r1, #TI_TP_VALUE]
|
||||
mcr p15, 0, r1, c13, c0, 3 @ set TLS register
|
||||
.L2_\@:
|
||||
.L1_\@:
|
||||
#endif
|
||||
|
||||
uaccess_enable r1, isb=0
|
||||
|
|
|
@ -424,6 +424,13 @@ ENDPROC(secondary_startup)
|
|||
ENDPROC(secondary_startup_arm)
|
||||
|
||||
ENTRY(__secondary_switched)
|
||||
#if defined(CONFIG_VMAP_STACK) && !defined(CONFIG_ARM_LPAE)
|
||||
@ Before using the vmap'ed stack, we have to switch to swapper_pg_dir
|
||||
@ as the ID map does not cover the vmalloc region.
|
||||
mrc p15, 0, ip, c2, c0, 1 @ read TTBR1
|
||||
mcr p15, 0, ip, c2, c0, 0 @ set TTBR0
|
||||
instr_sync
|
||||
#endif
|
||||
adr_l r7, secondary_data + 12 @ get secondary_data.stack
|
||||
ldr sp, [r7]
|
||||
ldr r0, [r7, #4] @ get secondary_data.task
|
||||
|
|
|
@ -68,6 +68,7 @@ bool module_exit_section(const char *name)
|
|||
strstarts(name, ".ARM.exidx.exit");
|
||||
}
|
||||
|
||||
#ifdef CONFIG_ARM_HAS_GROUP_RELOCS
|
||||
/*
|
||||
* This implements the partitioning algorithm for group relocations as
|
||||
* documented in the ARM AArch32 ELF psABI (IHI 0044).
|
||||
|
@ -103,6 +104,7 @@ static u32 get_group_rem(u32 group, u32 *offset)
|
|||
} while (group--);
|
||||
return shift;
|
||||
}
|
||||
#endif
|
||||
|
||||
int
|
||||
apply_relocate(Elf32_Shdr *sechdrs, const char *strtab, unsigned int symindex,
|
||||
|
@ -118,7 +120,9 @@ apply_relocate(Elf32_Shdr *sechdrs, const char *strtab, unsigned int symindex,
|
|||
unsigned long loc;
|
||||
Elf32_Sym *sym;
|
||||
const char *symname;
|
||||
#ifdef CONFIG_ARM_HAS_GROUP_RELOCS
|
||||
u32 shift, group = 1;
|
||||
#endif
|
||||
s32 offset;
|
||||
u32 tmp;
|
||||
#ifdef CONFIG_THUMB2_KERNEL
|
||||
|
@ -249,6 +253,7 @@ apply_relocate(Elf32_Shdr *sechdrs, const char *strtab, unsigned int symindex,
|
|||
*(u32 *)loc = __opcode_to_mem_arm(tmp);
|
||||
break;
|
||||
|
||||
#ifdef CONFIG_ARM_HAS_GROUP_RELOCS
|
||||
case R_ARM_ALU_PC_G0_NC:
|
||||
group = 0;
|
||||
fallthrough;
|
||||
|
@ -296,7 +301,7 @@ apply_relocate(Elf32_Shdr *sechdrs, const char *strtab, unsigned int symindex,
|
|||
}
|
||||
*(u32 *)loc = __opcode_to_mem_arm((tmp & ~0xfff) | offset);
|
||||
break;
|
||||
|
||||
#endif
|
||||
#ifdef CONFIG_THUMB2_KERNEL
|
||||
case R_ARM_THM_CALL:
|
||||
case R_ARM_THM_JUMP24:
|
||||
|
|
|
@ -119,6 +119,13 @@ ENTRY(cpu_resume_mmu)
|
|||
ENDPROC(cpu_resume_mmu)
|
||||
.popsection
|
||||
cpu_resume_after_mmu:
|
||||
#if defined(CONFIG_VMAP_STACK) && !defined(CONFIG_ARM_LPAE)
|
||||
@ Before using the vmap'ed stack, we have to switch to swapper_pg_dir
|
||||
@ as the ID map does not cover the vmalloc region.
|
||||
mrc p15, 0, ip, c2, c0, 1 @ read TTBR1
|
||||
mcr p15, 0, ip, c2, c0, 0 @ set TTBR0
|
||||
instr_sync
|
||||
#endif
|
||||
bl cpu_init @ restore the und/abt/irq banked regs
|
||||
mov r0, #0 @ return zero on success
|
||||
ldmfd sp!, {r4 - r11, pc}
|
||||
|
|
|
@ -405,11 +405,6 @@ static void smp_store_cpu_info(unsigned int cpuid)
|
|||
|
||||
static void set_current(struct task_struct *cur)
|
||||
{
|
||||
if (!IS_ENABLED(CONFIG_CURRENT_POINTER_IN_TPIDRURO) && !is_smp()) {
|
||||
__current = cur;
|
||||
return;
|
||||
}
|
||||
|
||||
/* Set TPIDRURO */
|
||||
asm("mcr p15, 0, %0, c13, c0, 3" :: "r"(cur) : "memory");
|
||||
}
|
||||
|
|
|
@ -885,6 +885,7 @@ asmlinkage void handle_bad_stack(struct pt_regs *regs)
|
|||
die("kernel stack overflow", regs, 0);
|
||||
}
|
||||
|
||||
#ifndef CONFIG_ARM_LPAE
|
||||
/*
|
||||
* Normally, we rely on the logic in do_translation_fault() to update stale PMD
|
||||
* entries covering the vmalloc space in a task's page tables when it first
|
||||
|
@ -895,26 +896,14 @@ asmlinkage void handle_bad_stack(struct pt_regs *regs)
|
|||
* So we need to ensure that these PMD entries are up to date *before* the MM
|
||||
* switch. As we already have some logic in the MM switch path that takes care
|
||||
* of this, let's trigger it by bumping the counter every time the core vmalloc
|
||||
* code modifies a PMD entry in the vmalloc region.
|
||||
* code modifies a PMD entry in the vmalloc region. Use release semantics on
|
||||
* the store so that other CPUs observing the counter's new value are
|
||||
* guaranteed to see the updated page table entries as well.
|
||||
*/
|
||||
void arch_sync_kernel_mappings(unsigned long start, unsigned long end)
|
||||
{
|
||||
if (start > VMALLOC_END || end < VMALLOC_START)
|
||||
return;
|
||||
|
||||
/*
|
||||
* This hooks into the core vmalloc code to receive notifications of
|
||||
* any PMD level changes that have been made to the kernel page tables.
|
||||
* This means it should only be triggered once for every MiB worth of
|
||||
* vmalloc space, given that we don't support huge vmalloc/vmap on ARM,
|
||||
* and that kernel PMD level table entries are rarely (if ever)
|
||||
* updated.
|
||||
*
|
||||
* This means that the counter is going to max out at ~250 for the
|
||||
* typical case. If it overflows, something entirely unexpected has
|
||||
* occurred so let's throw a warning if that happens.
|
||||
*/
|
||||
WARN_ON(++init_mm.context.vmalloc_seq == UINT_MAX);
|
||||
if (start < VMALLOC_END && end > VMALLOC_START)
|
||||
atomic_inc_return_release(&init_mm.context.vmalloc_seq);
|
||||
}
|
||||
|
||||
#endif
|
||||
#endif
|
||||
|
|
|
@ -59,7 +59,7 @@ struct irq_chip ext_chip = {
|
|||
.irq_unmask = iop32x_irq_unmask,
|
||||
};
|
||||
|
||||
void iop_handle_irq(struct pt_regs *regs)
|
||||
static void iop_handle_irq(struct pt_regs *regs)
|
||||
{
|
||||
u32 mask;
|
||||
|
||||
|
|
|
@ -240,8 +240,7 @@ void check_and_switch_context(struct mm_struct *mm, struct task_struct *tsk)
|
|||
unsigned int cpu = smp_processor_id();
|
||||
u64 asid;
|
||||
|
||||
if (unlikely(mm->context.vmalloc_seq != init_mm.context.vmalloc_seq))
|
||||
__check_vmalloc_seq(mm);
|
||||
check_vmalloc_seq(mm);
|
||||
|
||||
/*
|
||||
* We cannot update the pgd and the ASID atomicly with classic
|
||||
|
|
|
@ -117,16 +117,21 @@ EXPORT_SYMBOL(ioremap_page);
|
|||
|
||||
void __check_vmalloc_seq(struct mm_struct *mm)
|
||||
{
|
||||
unsigned int seq;
|
||||
int seq;
|
||||
|
||||
do {
|
||||
seq = init_mm.context.vmalloc_seq;
|
||||
seq = atomic_read(&init_mm.context.vmalloc_seq);
|
||||
memcpy(pgd_offset(mm, VMALLOC_START),
|
||||
pgd_offset_k(VMALLOC_START),
|
||||
sizeof(pgd_t) * (pgd_index(VMALLOC_END) -
|
||||
pgd_index(VMALLOC_START)));
|
||||
mm->context.vmalloc_seq = seq;
|
||||
} while (seq != init_mm.context.vmalloc_seq);
|
||||
/*
|
||||
* Use a store-release so that other CPUs that observe the
|
||||
* counter's new value are guaranteed to see the results of the
|
||||
* memcpy as well.
|
||||
*/
|
||||
atomic_set_release(&mm->context.vmalloc_seq, seq);
|
||||
} while (seq != atomic_read(&init_mm.context.vmalloc_seq));
|
||||
}
|
||||
|
||||
#if !defined(CONFIG_SMP) && !defined(CONFIG_ARM_LPAE)
|
||||
|
@ -157,7 +162,7 @@ static void unmap_area_sections(unsigned long virt, unsigned long size)
|
|||
* Note: this is still racy on SMP machines.
|
||||
*/
|
||||
pmd_clear(pmdp);
|
||||
init_mm.context.vmalloc_seq++;
|
||||
atomic_inc_return_release(&init_mm.context.vmalloc_seq);
|
||||
|
||||
/*
|
||||
* Free the page table, if there was one.
|
||||
|
@ -174,8 +179,7 @@ static void unmap_area_sections(unsigned long virt, unsigned long size)
|
|||
* Ensure that the active_mm is up to date - we want to
|
||||
* catch any use-after-iounmap cases.
|
||||
*/
|
||||
if (current->active_mm->context.vmalloc_seq != init_mm.context.vmalloc_seq)
|
||||
__check_vmalloc_seq(current->active_mm);
|
||||
check_vmalloc_seq(current->active_mm);
|
||||
|
||||
flush_tlb_kernel_range(virt, end);
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue