From f0c4b8d653f5ee091fb8d4d02ed7eaad397491bb Mon Sep 17 00:00:00 2001 From: Will Deacon Date: Fri, 20 Apr 2012 17:20:08 +0100 Subject: ARM: 7396/1: errata: only handle ARM erratum #326103 on affected cores Erratum #326103 ("FSR write bit incorrect on a SWP to read-only memory") only affects the ARM 1136 core prior to r1p0. The workaround disassembles the faulting instruction to determine whether it was a read or write access on all v6 cores. An issue has been reported on the ARM 11MPCore whereby loading the faulting instruction may happen in parallel with that page being unmapped, resulting in a deadlock due to the lack of TLB broadcasting in hardware: http://lists.infradead.org/pipermail/linux-arm-kernel/2012-March/091561.html This patch limits the workaround so that it is only used on affected cores, which are known to be UP only. Other v6 cores can rely on the FSR to indicate the access type correctly. Cc: stable@vger.kernel.org Signed-off-by: Will Deacon Signed-off-by: Russell King --- arch/arm/Kconfig | 9 +++++++++ arch/arm/mm/abort-ev6.S | 17 +++++++++++------ 2 files changed, 20 insertions(+), 6 deletions(-) diff --git a/arch/arm/Kconfig b/arch/arm/Kconfig index cf006d40342c..36586dba6fa6 100644 --- a/arch/arm/Kconfig +++ b/arch/arm/Kconfig @@ -1186,6 +1186,15 @@ if !MMU source "arch/arm/Kconfig-nommu" endif +config ARM_ERRATA_326103 + bool "ARM errata: FSR write bit incorrect on a SWP to read-only memory" + depends on CPU_V6 + help + Executing a SWP instruction to read-only memory does not set bit 11 + of the FSR on the ARM 1136 prior to r1p0. This causes the kernel to + treat the access as a read, preventing a COW from occurring and + causing the faulting task to livelock. + config ARM_ERRATA_411920 bool "ARM errata: Invalidation of the Instruction Cache operation can fail" depends on CPU_V6 || CPU_V6K diff --git a/arch/arm/mm/abort-ev6.S b/arch/arm/mm/abort-ev6.S index ff1f7cc11f87..80741992a9fc 100644 --- a/arch/arm/mm/abort-ev6.S +++ b/arch/arm/mm/abort-ev6.S @@ -26,18 +26,23 @@ ENTRY(v6_early_abort) mrc p15, 0, r1, c5, c0, 0 @ get FSR mrc p15, 0, r0, c6, c0, 0 @ get FAR /* - * Faulty SWP instruction on 1136 doesn't set bit 11 in DFSR (erratum 326103). - * The test below covers all the write situations, including Java bytecodes + * Faulty SWP instruction on 1136 doesn't set bit 11 in DFSR. */ - bic r1, r1, #1 << 11 @ clear bit 11 of FSR +#ifdef CONFIG_ARM_ERRATA_326103 + ldr ip, =0x4107b36 + mrc p15, 0, r3, c0, c0, 0 @ get processor id + teq ip, r3, lsr #4 @ r0 ARM1136? + bne do_DataAbort tst r5, #PSR_J_BIT @ Java? + tsteq r5, #PSR_T_BIT @ Thumb? bne do_DataAbort - do_thumb_abort fsr=r1, pc=r4, psr=r5, tmp=r3 - ldreq r3, [r4] @ read aborted ARM instruction + bic r1, r1, #1 << 11 @ clear bit 11 of FSR + ldr r3, [r4] @ read aborted ARM instruction #ifdef CONFIG_CPU_ENDIAN_BE8 - reveq r3, r3 + rev r3, r3 #endif do_ldrd_abort tmp=ip, insn=r3 tst r3, #1 << 20 @ L = 0 -> write orreq r1, r1, #1 << 11 @ yes. +#endif b do_DataAbort -- cgit v1.2.3 From f154fe9b806574437b47f08e924ad10c0e240b23 Mon Sep 17 00:00:00 2001 From: Will Deacon Date: Fri, 20 Apr 2012 17:21:08 +0100 Subject: ARM: 7397/1: l2x0: only apply workaround for erratum #753970 on PL310 The workaround for PL310 erratum #753970 can lead to deadlock on systems with an L220 cache controller. This patch makes the workaround effective only when the cache controller is identified as a PL310 at probe time. Cc: stable@vger.kernel.org Signed-off-by: Will Deacon Signed-off-by: Russell King --- arch/arm/mm/cache-l2x0.c | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/arch/arm/mm/cache-l2x0.c b/arch/arm/mm/cache-l2x0.c index a53fd2aaa2f4..a8d02c048a1f 100644 --- a/arch/arm/mm/cache-l2x0.c +++ b/arch/arm/mm/cache-l2x0.c @@ -32,6 +32,7 @@ static void __iomem *l2x0_base; static DEFINE_RAW_SPINLOCK(l2x0_lock); static u32 l2x0_way_mask; /* Bitmask of active ways */ static u32 l2x0_size; +static unsigned long sync_reg_offset = L2X0_CACHE_SYNC; struct l2x0_regs l2x0_saved_regs; @@ -61,12 +62,7 @@ static inline void cache_sync(void) { void __iomem *base = l2x0_base; -#ifdef CONFIG_PL310_ERRATA_753970 - /* write to an unmmapped register */ - writel_relaxed(0, base + L2X0_DUMMY_REG); -#else - writel_relaxed(0, base + L2X0_CACHE_SYNC); -#endif + writel_relaxed(0, base + sync_reg_offset); cache_wait(base + L2X0_CACHE_SYNC, 1); } @@ -331,6 +327,10 @@ void __init l2x0_init(void __iomem *base, u32 aux_val, u32 aux_mask) else ways = 8; type = "L310"; +#ifdef CONFIG_PL310_ERRATA_753970 + /* Unmapped register. */ + sync_reg_offset = L2X0_DUMMY_REG; +#endif break; case L2X0_CACHE_ID_PART_L210: ways = (aux >> 13) & 0xf; -- cgit v1.2.3 From ab4d536890853ab6675ede65db40e2c0980cb0ea Mon Sep 17 00:00:00 2001 From: Will Deacon Date: Fri, 20 Apr 2012 17:22:11 +0100 Subject: ARM: 7398/1: l2x0: only write to debug registers on PL310 PL310 errata #588369 and #727915 require writes to the debug registers of the cache controller to work around known problems. Writing these registers on L220 may cause deadlock, so ensure that we only perform this operation when we identify a PL310 at probe time. Cc: stable@vger.kernel.org Signed-off-by: Will Deacon Signed-off-by: Russell King --- arch/arm/mm/cache-l2x0.c | 13 ++++++++----- 1 file changed, 8 insertions(+), 5 deletions(-) diff --git a/arch/arm/mm/cache-l2x0.c b/arch/arm/mm/cache-l2x0.c index a8d02c048a1f..2a8e380501e8 100644 --- a/arch/arm/mm/cache-l2x0.c +++ b/arch/arm/mm/cache-l2x0.c @@ -81,10 +81,13 @@ static inline void l2x0_inv_line(unsigned long addr) } #if defined(CONFIG_PL310_ERRATA_588369) || defined(CONFIG_PL310_ERRATA_727915) +static inline void debug_writel(unsigned long val) +{ + if (outer_cache.set_debug) + outer_cache.set_debug(val); +} -#define debug_writel(val) outer_cache.set_debug(val) - -static void l2x0_set_debug(unsigned long val) +static void pl310_set_debug(unsigned long val) { writel_relaxed(val, l2x0_base + L2X0_DEBUG_CTRL); } @@ -94,7 +97,7 @@ static inline void debug_writel(unsigned long val) { } -#define l2x0_set_debug NULL +#define pl310_set_debug NULL #endif #ifdef CONFIG_PL310_ERRATA_588369 @@ -331,6 +334,7 @@ void __init l2x0_init(void __iomem *base, u32 aux_val, u32 aux_mask) /* Unmapped register. */ sync_reg_offset = L2X0_DUMMY_REG; #endif + outer_cache.set_debug = pl310_set_debug; break; case L2X0_CACHE_ID_PART_L210: ways = (aux >> 13) & 0xf; @@ -379,7 +383,6 @@ void __init l2x0_init(void __iomem *base, u32 aux_val, u32 aux_mask) outer_cache.flush_all = l2x0_flush_all; outer_cache.inv_all = l2x0_inv_all; outer_cache.disable = l2x0_disable; - outer_cache.set_debug = l2x0_set_debug; printk(KERN_INFO "%s cache controller enabled\n", type); printk(KERN_INFO "l2x0: %d ways, CACHE_ID 0x%08x, AUX_CTRL 0x%08x, Cache size: %d B\n", -- cgit v1.2.3 From 2498814fcb3068f19b82b1519b4038721f61af43 Mon Sep 17 00:00:00 2001 From: Will Deacon Date: Mon, 23 Apr 2012 15:38:28 +0100 Subject: ARM: 7399/1: vfp: move user vfp state save/restore code out of signal.c The user VFP state must be preserved (subject to ucontext modifications) across invocation of a signal handler and this is currently handled by vfp_{preserve,restore}_context in signal.c Since this code requires intimate low-level knowledge of the VFP state, this patch moves it into vfpmodule.c. Signed-off-by: Will Deacon Signed-off-by: Russell King --- arch/arm/include/asm/thread_info.h | 7 ++++ arch/arm/kernel/signal.c | 55 ++------------------------ arch/arm/vfp/vfpmodule.c | 79 ++++++++++++++++++++++++++++++++++++++ 3 files changed, 90 insertions(+), 51 deletions(-) diff --git a/arch/arm/include/asm/thread_info.h b/arch/arm/include/asm/thread_info.h index d4c24d412a8d..0f04d84582e1 100644 --- a/arch/arm/include/asm/thread_info.h +++ b/arch/arm/include/asm/thread_info.h @@ -118,6 +118,13 @@ extern void iwmmxt_task_switch(struct thread_info *); extern void vfp_sync_hwstate(struct thread_info *); extern void vfp_flush_hwstate(struct thread_info *); +struct user_vfp; +struct user_vfp_exc; + +extern int vfp_preserve_user_clear_hwstate(struct user_vfp __user *, + struct user_vfp_exc __user *); +extern int vfp_restore_user_hwstate(struct user_vfp __user *, + struct user_vfp_exc __user *); #endif /* diff --git a/arch/arm/kernel/signal.c b/arch/arm/kernel/signal.c index 7cb532fc8aa4..d68d1b694680 100644 --- a/arch/arm/kernel/signal.c +++ b/arch/arm/kernel/signal.c @@ -180,44 +180,23 @@ static int restore_iwmmxt_context(struct iwmmxt_sigframe *frame) static int preserve_vfp_context(struct vfp_sigframe __user *frame) { - struct thread_info *thread = current_thread_info(); - struct vfp_hard_struct *h = &thread->vfpstate.hard; const unsigned long magic = VFP_MAGIC; const unsigned long size = VFP_STORAGE_SIZE; int err = 0; - vfp_sync_hwstate(thread); __put_user_error(magic, &frame->magic, err); __put_user_error(size, &frame->size, err); - /* - * Copy the floating point registers. There can be unused - * registers see asm/hwcap.h for details. - */ - err |= __copy_to_user(&frame->ufp.fpregs, &h->fpregs, - sizeof(h->fpregs)); - /* - * Copy the status and control register. - */ - __put_user_error(h->fpscr, &frame->ufp.fpscr, err); - - /* - * Copy the exception registers. - */ - __put_user_error(h->fpexc, &frame->ufp_exc.fpexc, err); - __put_user_error(h->fpinst, &frame->ufp_exc.fpinst, err); - __put_user_error(h->fpinst2, &frame->ufp_exc.fpinst2, err); + if (err) + return -EFAULT; - return err ? -EFAULT : 0; + return vfp_preserve_user_clear_hwstate(&frame->ufp, &frame->ufp_exc); } static int restore_vfp_context(struct vfp_sigframe __user *frame) { - struct thread_info *thread = current_thread_info(); - struct vfp_hard_struct *h = &thread->vfpstate.hard; unsigned long magic; unsigned long size; - unsigned long fpexc; int err = 0; __get_user_error(magic, &frame->magic, err); @@ -228,33 +207,7 @@ static int restore_vfp_context(struct vfp_sigframe __user *frame) if (magic != VFP_MAGIC || size != VFP_STORAGE_SIZE) return -EINVAL; - vfp_flush_hwstate(thread); - - /* - * Copy the floating point registers. There can be unused - * registers see asm/hwcap.h for details. - */ - err |= __copy_from_user(&h->fpregs, &frame->ufp.fpregs, - sizeof(h->fpregs)); - /* - * Copy the status and control register. - */ - __get_user_error(h->fpscr, &frame->ufp.fpscr, err); - - /* - * Sanitise and restore the exception registers. - */ - __get_user_error(fpexc, &frame->ufp_exc.fpexc, err); - /* Ensure the VFP is enabled. */ - fpexc |= FPEXC_EN; - /* Ensure FPINST2 is invalid and the exception flag is cleared. */ - fpexc &= ~(FPEXC_EX | FPEXC_FP2V); - h->fpexc = fpexc; - - __get_user_error(h->fpinst, &frame->ufp_exc.fpinst, err); - __get_user_error(h->fpinst2, &frame->ufp_exc.fpinst2, err); - - return err ? -EFAULT : 0; + return vfp_restore_user_hwstate(&frame->ufp, &frame->ufp_exc); } #endif diff --git a/arch/arm/vfp/vfpmodule.c b/arch/arm/vfp/vfpmodule.c index 858748eaa144..05872d92fca2 100644 --- a/arch/arm/vfp/vfpmodule.c +++ b/arch/arm/vfp/vfpmodule.c @@ -17,6 +17,8 @@ #include #include #include +#include +#include #include #include @@ -528,6 +530,83 @@ void vfp_flush_hwstate(struct thread_info *thread) put_cpu(); } +/* + * Save the current VFP state into the provided structures and prepare + * for entry into a new function (signal handler). + */ +int vfp_preserve_user_clear_hwstate(struct user_vfp __user *ufp, + struct user_vfp_exc __user *ufp_exc) +{ + struct thread_info *thread = current_thread_info(); + struct vfp_hard_struct *hwstate = &thread->vfpstate.hard; + int err = 0; + + /* Ensure that the saved hwstate is up-to-date. */ + vfp_sync_hwstate(thread); + + /* + * Copy the floating point registers. There can be unused + * registers see asm/hwcap.h for details. + */ + err |= __copy_to_user(&ufp->fpregs, &hwstate->fpregs, + sizeof(hwstate->fpregs)); + /* + * Copy the status and control register. + */ + __put_user_error(hwstate->fpscr, &ufp->fpscr, err); + + /* + * Copy the exception registers. + */ + __put_user_error(hwstate->fpexc, &ufp_exc->fpexc, err); + __put_user_error(hwstate->fpinst, &ufp_exc->fpinst, err); + __put_user_error(hwstate->fpinst2, &ufp_exc->fpinst2, err); + + if (err) + return -EFAULT; + return 0; +} + +/* Sanitise and restore the current VFP state from the provided structures. */ +int vfp_restore_user_hwstate(struct user_vfp __user *ufp, + struct user_vfp_exc __user *ufp_exc) +{ + struct thread_info *thread = current_thread_info(); + struct vfp_hard_struct *hwstate = &thread->vfpstate.hard; + unsigned long fpexc; + int err = 0; + + vfp_flush_hwstate(thread); + + /* + * Copy the floating point registers. There can be unused + * registers see asm/hwcap.h for details. + */ + err |= __copy_from_user(&hwstate->fpregs, &ufp->fpregs, + sizeof(hwstate->fpregs)); + /* + * Copy the status and control register. + */ + __get_user_error(hwstate->fpscr, &ufp->fpscr, err); + + /* + * Sanitise and restore the exception registers. + */ + __get_user_error(fpexc, &ufp_exc->fpexc, err); + + /* Ensure the VFP is enabled. */ + fpexc |= FPEXC_EN; + + /* Ensure FPINST2 is invalid and the exception flag is cleared. */ + fpexc &= ~(FPEXC_EX | FPEXC_FP2V); + hwstate->fpexc = fpexc; + + __get_user_error(hwstate->fpinst, &ufp_exc->fpinst, err); + __get_user_error(hwstate->fpinst2, &ufp_exc->fpinst2, err); + + return err ? -EFAULT : 0; +} + /* * VFP hardware can lose all context when a CPU goes offline. * As we will be running in SMP mode with CPU hotplug, we will save the -- cgit v1.2.3 From ff9a184cfb6542bef98aff1789481284e122a4b3 Mon Sep 17 00:00:00 2001 From: Will Deacon Date: Mon, 23 Apr 2012 15:42:16 +0100 Subject: ARM: 7400/1: vfp: clear fpscr length and stride bits on entry to sig handler The ARM PCS mandates that the length and stride bits of the fpscr are cleared on entry to and return from a public interface. Although signal handlers run asynchronously with respect to the interrupted function, the handler itself expects to run as though it has been called like a normal function. This patch updates the state mirroring the VFP hardware before entry to a signal handler so that it adheres to the PCS. Furthermore, we disable VFP to ensure that we trap on any floating point operation performed by the signal handler and synchronise the hardware appropriately. A check is inserted after the signal handler to avoid redundant flushing if VFP was not used. Reported-by: Peter Maydell Signed-off-by: Will Deacon Signed-off-by: Russell King --- arch/arm/vfp/vfpmodule.c | 22 +++++++++++++++++++++- 1 file changed, 21 insertions(+), 1 deletion(-) diff --git a/arch/arm/vfp/vfpmodule.c b/arch/arm/vfp/vfpmodule.c index 05872d92fca2..bc683b8219b5 100644 --- a/arch/arm/vfp/vfpmodule.c +++ b/arch/arm/vfp/vfpmodule.c @@ -564,6 +564,21 @@ int vfp_preserve_user_clear_hwstate(struct user_vfp __user *ufp, if (err) return -EFAULT; + + /* Ensure that VFP is disabled. */ + vfp_flush_hwstate(thread); + + /* + * As per the PCS, clear the length and stride bits for function + * entry. + */ + hwstate->fpscr &= ~(FPSCR_LENGTH_MASK | FPSCR_STRIDE_MASK); + + /* + * Disable VFP in the hwstate so that we can detect if it gets + * used. + */ + hwstate->fpexc &= ~FPEXC_EN; return 0; } @@ -576,7 +591,12 @@ int vfp_restore_user_hwstate(struct user_vfp __user *ufp, unsigned long fpexc; int err = 0; - vfp_flush_hwstate(thread); + /* + * If VFP has been used, then disable it to avoid corrupting + * the new thread state. + */ + if (hwstate->fpexc & FPEXC_EN) + vfp_flush_hwstate(thread); /* * Copy the floating point registers. There can be unused -- cgit v1.2.3 From 754aba436bed2051deaa2af7bdda553df056b6fc Mon Sep 17 00:00:00 2001 From: Linus Walleij Date: Wed, 18 Apr 2012 22:26:51 +0100 Subject: ARM: 7390/1: dts: versatile-pb/ab fix MMC IRQs The MMCI driver will not work without two IRQs since this is not flagged as a single-irq variant. Looking through the complex IRQ definition for the MMCI on the versatile (including an #if 1 statement forcing MMCI IRQ0 to the VIC) this appears to the the correct IRQ number for both models. Cc: Niklas Hernaeus Signed-off-by: Linus Walleij Signed-off-by: Russell King --- arch/arm/boot/dts/versatile-ab.dts | 2 +- arch/arm/boot/dts/versatile-pb.dts | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/arch/arm/boot/dts/versatile-ab.dts b/arch/arm/boot/dts/versatile-ab.dts index 0b32925f2147..e2fe3195c0d1 100644 --- a/arch/arm/boot/dts/versatile-ab.dts +++ b/arch/arm/boot/dts/versatile-ab.dts @@ -173,7 +173,7 @@ mmc@5000 { compatible = "arm,primecell"; reg = < 0x5000 0x1000>; - interrupts = <22>; + interrupts = <22 34>; }; kmi@6000 { compatible = "arm,pl050", "arm,primecell"; diff --git a/arch/arm/boot/dts/versatile-pb.dts b/arch/arm/boot/dts/versatile-pb.dts index 166461073b78..7e8175269064 100644 --- a/arch/arm/boot/dts/versatile-pb.dts +++ b/arch/arm/boot/dts/versatile-pb.dts @@ -41,7 +41,7 @@ mmc@b000 { compatible = "arm,primecell"; reg = <0xb000 0x1000>; - interrupts = <23>; + interrupts = <23 34>; }; }; }; -- cgit v1.2.3 From 354535845ffb74d8a4827fbdaa493037d0030eea Mon Sep 17 00:00:00 2001 From: Russell King Date: Sat, 14 Apr 2012 18:57:10 +0100 Subject: ARM: OMAP: fix DMA vs memory ordering Using coherent DMA memory with the OMAP DMA engine results in unpredictable behaviour due to memory ordering issues; as things stand, there is no guarantee that data written to coherent DMA memory will be visible to the DMA hardware. This is because the OMAP dma_write() accessor contains no barriers, necessary on ARMv6 and above. The effect of this can be seen in comments in the OMAP serial driver, which incorrectly talks about cache flushing for the coherent DMA stuff. Rather than adding barriers to the accessors, add it in the DMA support code just before we enable DMA, and just after we disable DMA. This avoids having barriers for every DMA register access. Acked-by: Tony Lindgren Acked-by: Santosh Shilimkar Signed-off-by: Russell King --- arch/arm/plat-omap/dma.c | 14 ++++++++++++++ 1 file changed, 14 insertions(+) diff --git a/arch/arm/plat-omap/dma.c b/arch/arm/plat-omap/dma.c index ecdb3da0dea9..c58d896cd5c3 100644 --- a/arch/arm/plat-omap/dma.c +++ b/arch/arm/plat-omap/dma.c @@ -916,6 +916,13 @@ void omap_start_dma(int lch) l |= OMAP_DMA_CCR_BUFFERING_DISABLE; l |= OMAP_DMA_CCR_EN; + /* + * As dma_write() uses IO accessors which are weakly ordered, there + * is no guarantee that data in coherent DMA memory will be visible + * to the DMA device. Add a memory barrier here to ensure that any + * such data is visible prior to enabling DMA. + */ + mb(); p->dma_write(l, CCR, lch); dma_chan[lch].flags |= OMAP_DMA_ACTIVE; @@ -965,6 +972,13 @@ void omap_stop_dma(int lch) p->dma_write(l, CCR, lch); } + /* + * Ensure that data transferred by DMA is visible to any access + * after DMA has been disabled. This is important for coherent + * DMA regions. + */ + mb(); + if (!omap_dma_in_1510_mode() && dma_chan[lch].next_lch != -1) { int next_lch, cur_lch = lch; char dma_chan_link_map[dma_lch_count]; -- cgit v1.2.3 From 14904927fcef6bb881fd995b478a0d2e700c1818 Mon Sep 17 00:00:00 2001 From: Stephen Boyd Date: Fri, 27 Apr 2012 01:40:10 +0100 Subject: ARM: 7401/1: mm: Fix section mismatches WARNING: vmlinux.o(.text+0x111b8): Section mismatch in reference from the function arm_memory_present() to the function .init.text:memory_present() The function arm_memory_present() references the function __init memory_present(). This is often because arm_memory_present lacks a __init annotation or the annotation of memory_present is wrong. WARNING: arch/arm/mm/built-in.o(.text+0x1edc): Section mismatch in reference from the function alloc_init_pud() to the function .init.text:alloc_init_section() The function alloc_init_pud() references the function __init alloc_init_section(). This is often because alloc_init_pud lacks a __init annotation or the annotation of alloc_init_section is wrong. Signed-off-by: Stephen Boyd Signed-off-by: Russell King --- arch/arm/mm/init.c | 4 ++-- arch/arm/mm/mmu.c | 4 ++-- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/arch/arm/mm/init.c b/arch/arm/mm/init.c index 595079fa9d1d..8f5813bbffb5 100644 --- a/arch/arm/mm/init.c +++ b/arch/arm/mm/init.c @@ -293,11 +293,11 @@ EXPORT_SYMBOL(pfn_valid); #endif #ifndef CONFIG_SPARSEMEM -static void arm_memory_present(void) +static void __init arm_memory_present(void) { } #else -static void arm_memory_present(void) +static void __init arm_memory_present(void) { struct memblock_region *reg; diff --git a/arch/arm/mm/mmu.c b/arch/arm/mm/mmu.c index b86f8933ff91..2c7cf2f9c837 100644 --- a/arch/arm/mm/mmu.c +++ b/arch/arm/mm/mmu.c @@ -618,8 +618,8 @@ static void __init alloc_init_section(pud_t *pud, unsigned long addr, } } -static void alloc_init_pud(pgd_t *pgd, unsigned long addr, unsigned long end, - unsigned long phys, const struct mem_type *type) +static void __init alloc_init_pud(pgd_t *pgd, unsigned long addr, + unsigned long end, unsigned long phys, const struct mem_type *type) { pud_t *pud = pud_offset(pgd, addr); unsigned long next; -- cgit v1.2.3 From 6a1c53124aa161eb624ce7b1e40ade728186d34c Mon Sep 17 00:00:00 2001 From: Will Deacon Date: Fri, 27 Apr 2012 12:45:07 +0100 Subject: ARM: 7403/1: tls: remove covert channel via TPIDRURW TPIDRURW is a user read/write register forming part of the group of thread registers in more recent versions of the ARM architecture (~v6+). Currently, the kernel does not touch this register, which allows tasks to communicate covertly by reading and writing to the register without context-switching affecting its contents. This patch clears TPIDRURW when TPIDRURO is updated via the set_tls macro, which is called directly from __switch_to. Since the current behaviour makes the register useless to userspace as far as thread pointers are concerned, simply clearing the register (rather than saving and restoring it) will not cause any problems to userspace. Cc: stable@vger.kernel.org Signed-off-by: Will Deacon Signed-off-by: Russell King --- arch/arm/include/asm/tls.h | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/arch/arm/include/asm/tls.h b/arch/arm/include/asm/tls.h index 60843eb0f61c..73409e6c0251 100644 --- a/arch/arm/include/asm/tls.h +++ b/arch/arm/include/asm/tls.h @@ -7,6 +7,8 @@ .macro set_tls_v6k, tp, tmp1, tmp2 mcr p15, 0, \tp, c13, c0, 3 @ set TLS register + mov \tmp1, #0 + mcr p15, 0, \tmp1, c13, c0, 2 @ clear user r/w TLS register .endm .macro set_tls_v6, tp, tmp1, tmp2 @@ -15,6 +17,8 @@ mov \tmp2, #0xffff0fff tst \tmp1, #HWCAP_TLS @ hardware TLS available? mcrne p15, 0, \tp, c13, c0, 3 @ yes, set TLS register + movne \tmp1, #0 + mcrne p15, 0, \tmp1, c13, c0, 2 @ clear user r/w TLS register streq \tp, [\tmp2, #-15] @ set TLS value at 0xffff0ff0 .endm -- cgit v1.2.3 From 6fa99b7f80b4a7ed2cf616eae393bb6d9d51ba8f Mon Sep 17 00:00:00 2001 From: Will Deacon Date: Fri, 27 Apr 2012 12:51:43 +0100 Subject: ARM: 7405/1: kexec: call platform_cpu_kill on the killer rather than the victim When performing a kexec on an SMP system, the secondary cores are stopped by calling machine_shutdown(), which in turn issues IPIs to offline the other CPUs. Unfortunately, this isn't enough to reboot the cores into a new kernel (since they are just executing a cpu_relax loop somewhere in memory) so we make use of platform_cpu_kill, part of the CPU hotplug implementation, to place the cores somewhere safe. This function expects to be called on the killing CPU for each core that it takes out. This patch moves the platform_cpu_kill callback out of the IPI handler and into smp_send_stop, therefore ensuring that it executes on the killing CPU rather than on the victim, matching what the hotplug code requires. Cc: stable@vger.kernel.org Reported-by: Russell King Signed-off-by: Will Deacon Signed-off-by: Russell King --- arch/arm/kernel/smp.c | 28 +++++++++++++++++----------- 1 file changed, 17 insertions(+), 11 deletions(-) diff --git a/arch/arm/kernel/smp.c b/arch/arm/kernel/smp.c index addbbe8028c2..f6a4d32b0421 100644 --- a/arch/arm/kernel/smp.c +++ b/arch/arm/kernel/smp.c @@ -510,10 +510,6 @@ static void ipi_cpu_stop(unsigned int cpu) local_fiq_disable(); local_irq_disable(); -#ifdef CONFIG_HOTPLUG_CPU - platform_cpu_kill(cpu); -#endif - while (1) cpu_relax(); } @@ -576,17 +572,25 @@ void smp_send_reschedule(int cpu) smp_cross_call(cpumask_of(cpu), IPI_RESCHEDULE); } +#ifdef CONFIG_HOTPLUG_CPU +static void smp_kill_cpus(cpumask_t *mask) +{ + unsigned int cpu; + for_each_cpu(cpu, mask) + platform_cpu_kill(cpu); +} +#else +static void smp_kill_cpus(cpumask_t *mask) { } +#endif + void smp_send_stop(void) { unsigned long timeout; + struct cpumask mask; - if (num_online_cpus() > 1) { - struct cpumask mask; - cpumask_copy(&mask, cpu_online_mask); - cpumask_clear_cpu(smp_processor_id(), &mask); - - smp_cross_call(&mask, IPI_CPU_STOP); - } + cpumask_copy(&mask, cpu_online_mask); + cpumask_clear_cpu(smp_processor_id(), &mask); + smp_cross_call(&mask, IPI_CPU_STOP); /* Wait up to one second for other CPUs to stop */ timeout = USEC_PER_SEC; @@ -595,6 +599,8 @@ void smp_send_stop(void) if (num_online_cpus() > 1) pr_warning("SMP: failed to stop secondary CPUs\n"); + + smp_kill_cpus(&mask); } /* -- cgit v1.2.3 From 5e7371ded05adfcfcee44a8bc070bfc37979b8f2 Mon Sep 17 00:00:00 2001 From: Will Deacon Date: Fri, 27 Apr 2012 12:56:24 +0100 Subject: ARM: 7406/1: hotplug: copy the affinity mask when forcefully migrating IRQs When a CPU is hotplugged off, we migrate any IRQs currently affine to it away and onto another online CPU by calling the irq_set_affinity function of the relevant interrupt controller chip. This function returns either IRQ_SET_MASK_OK or IRQ_SET_MASK_OK_NOCOPY, to indicate whether irq_data.affinity was updated. If we are forcefully migrating an interrupt (because the affinity mask no longer identifies any online CPUs) then we should update the IRQ affinity mask to reflect the new CPU set. Failure to do so can potentially leave /proc/irq/n/smp_affinity identifying only offline CPUs, which may confuse userspace IRQ balancing daemons. This patch updates migrate_one_irq to copy the affinity mask when the interrupt chip returns IRQ_SET_MASK_OK after forcefully changing the affinity of an interrupt. Cc: stable@vger.kernel.org Reported-by: Leif Lindholm Signed-off-by: Will Deacon Signed-off-by: Russell King --- arch/arm/kernel/irq.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/arch/arm/kernel/irq.c b/arch/arm/kernel/irq.c index 71ccdbfed662..8349d4e97e2b 100644 --- a/arch/arm/kernel/irq.c +++ b/arch/arm/kernel/irq.c @@ -155,10 +155,10 @@ static bool migrate_one_irq(struct irq_desc *desc) } c = irq_data_get_irq_chip(d); - if (c->irq_set_affinity) - c->irq_set_affinity(d, affinity, true); - else + if (!c->irq_set_affinity) pr_debug("IRQ%u: unable to set affinity\n", d->irq); + else if (c->irq_set_affinity(d, affinity, true) == IRQ_SET_MASK_OK && ret) + cpumask_copy(d->affinity, affinity); return ret; } -- cgit v1.2.3