From 633dc92a28fc3fea6f08ef34de0b353ff5f9bf08 Mon Sep 17 00:00:00 2001 From: Russell King Date: Wed, 30 Jan 2013 23:55:35 +0000 Subject: ARM: DMA mapping: fix bad atomic test Realview fails to boot with this warning: BUG: spinlock lockup suspected on CPU#0, init/1 lock: 0xcf8bde10, .magic: dead4ead, .owner: init/1, .owner_cpu: 0 Backtrace: [] (dump_backtrace+0x0/0x10c) from [] (dump_stack+0x18/0x1c) r6:cf8bde10 r5:cf83d1c0 r4:cf8bde10 r3:cf83d1c0 [] (dump_stack+0x0/0x1c) from [] (spin_dump+0x84/0x98) [] (spin_dump+0x0/0x98) from [] (do_raw_spin_lock+0x100/0x198) [] (do_raw_spin_lock+0x0/0x198) from [] (_raw_spin_lock+0x3c/0x44) [] (_raw_spin_lock+0x0/0x44) from [] (pl011_console_write+0xe8/0x11c) [] (pl011_console_write+0x0/0x11c) from [] (call_console_drivers.clone.7+0xdc/0x104) [] (call_console_drivers.clone.7+0x0/0x104) from [] (console_unlock+0x2e8/0x454) [] (console_unlock+0x0/0x454) from [] (vprintk_emit+0x2d8/0x594) [] (vprintk_emit+0x0/0x594) from [] (printk+0x3c/0x44) [] (printk+0x0/0x44) from [] (warn_slowpath_common+0x28/0x6c) [] (warn_slowpath_common+0x0/0x6c) from [] (warn_slowpath_null+0x24/0x2c) [] (warn_slowpath_null+0x0/0x2c) from [] (lockdep_trace_alloc+0xd8/0xf0) [] (lockdep_trace_alloc+0x0/0xf0) from [] (kmem_cache_alloc+0x24/0x11c) [] (kmem_cache_alloc+0x0/0x11c) from [] (__get_vm_area_node.clone.24+0x7c/0x16c) [] (__get_vm_area_node.clone.24+0x0/0x16c) from [] (get_vm_area_caller+0x48/0x54) [] (get_vm_area_caller+0x0/0x54) from [] (__alloc_remap_buffer.clone.15+0x38/0xb8) [] (__alloc_remap_buffer.clone.15+0x0/0xb8) from [] (__dma_alloc+0x160/0x2c8) [] (__dma_alloc+0x0/0x2c8) from [] (arm_dma_alloc+0x88/0xa0)[] (arm_dma_alloc+0x0/0xa0) from [] (dma_pool_alloc+0xcc/0x1a8) [] (dma_pool_alloc+0x0/0x1a8) from [] (pl08x_fill_llis_for_desc+0x28/0x568) [] (pl08x_fill_llis_for_desc+0x0/0x568) from [] (pl08x_prep_slave_sg+0x258/0x3b0) [] (pl08x_prep_slave_sg+0x0/0x3b0) from [] (pl011_dma_tx_refill+0x140/0x288) [] (pl011_dma_tx_refill+0x0/0x288) from [] (pl011_start_tx+0xe4/0x120) [] (pl011_start_tx+0x0/0x120) from [] (__uart_start+0x48/0x4c) [] (__uart_start+0x0/0x4c) from [] (uart_start+0x2c/0x3c) [] (uart_start+0x0/0x3c) from [] (uart_write+0xcc/0xf4) [] (uart_write+0x0/0xf4) from [] (n_tty_write+0x1c0/0x3e4) [] (n_tty_write+0x0/0x3e4) from [] (tty_write+0x144/0x240) [] (tty_write+0x0/0x240) from [] (redirected_tty_write+0x98/0xac) [] (redirected_tty_write+0x0/0xac) from [] (vfs_write+0xbc/0x150) [] (vfs_write+0x0/0x150) from [] (sys_write+0x4c/0x78) [] (sys_write+0x0/0x78) from [] (ret_fast_syscall+0x0/0x3c) This happens because the DMA allocation code is not respecting atomic allocations correctly. GFP flags should not be tested for GFP_ATOMIC to determine if an atomic allocation is being requested. GFP_ATOMIC is not a flag but a value. The GFP bitmask flags are all prefixed with __GFP_. The rest of the kernel tests for __GFP_WAIT not being set to indicate an atomic allocation. We need to do the same. Signed-off-by: Russell King --- arch/arm/mm/dma-mapping.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'arch/arm/mm') diff --git a/arch/arm/mm/dma-mapping.c b/arch/arm/mm/dma-mapping.c index 076c26d..dda3904 100644 --- a/arch/arm/mm/dma-mapping.c +++ b/arch/arm/mm/dma-mapping.c @@ -640,7 +640,7 @@ static void *__dma_alloc(struct device *dev, size_t size, dma_addr_t *handle, if (is_coherent || nommu()) addr = __alloc_simple_buffer(dev, size, gfp, &page); - else if (gfp & GFP_ATOMIC) + else if (!(gfp & __GFP_WAIT)) addr = __alloc_from_pool(size, &page); else if (!IS_ENABLED(CONFIG_CMA)) addr = __alloc_remap_buffer(dev, size, gfp, prot, &page, caller); -- cgit v1.1 From b255188f90e2bade1bd11a986dd1ca4861869f4d Mon Sep 17 00:00:00 2001 From: Russell King Date: Mon, 25 Feb 2013 16:10:42 +0000 Subject: ARM: fix scheduling while atomic warning in alignment handling code Paolo Pisati reports that IPv6 triggers this warning: BUG: scheduling while atomic: swapper/0/0/0x40000100 Modules linked in: [] (unwind_backtrace+0x0/0xf0) from [] (__schedule_bug+0x48/0x5c) [] (__schedule_bug+0x48/0x5c) from [] (__schedule+0x700/0x740) [] (__schedule+0x700/0x740) from [] (__cond_resched+0x24/0x34) [] (__cond_resched+0x24/0x34) from [] (_cond_resched+0x3c/0x44) [] (_cond_resched+0x3c/0x44) from [] (do_alignment+0x178/0x78c) [] (do_alignment+0x178/0x78c) from [] (do_DataAbort+0x34/0x98) [] (do_DataAbort+0x34/0x98) from [] (__dabt_svc+0x40/0x60) Exception stack(0xc0763d70 to 0xc0763db8) 3d60: e97e805e e97e806e 2c000000 11000000 3d80: ea86bb00 0000002c 00000011 e97e807e c076d2a8 e97e805e e97e806e 0000002c 3da0: 3d000000 c0763dbc c04b98fc c02a8490 00000113 ffffffff [] (__dabt_svc+0x40/0x60) from [] (__csum_ipv6_magic+0x8/0xc8) Fix this by using probe_kernel_address() stead of __get_user(). Cc: Reported-by: Paolo Pisati Tested-by: Paolo Pisati Signed-off-by: Russell King --- arch/arm/mm/alignment.c | 11 ++++------- 1 file changed, 4 insertions(+), 7 deletions(-) (limited to 'arch/arm/mm') diff --git a/arch/arm/mm/alignment.c b/arch/arm/mm/alignment.c index b820eda..db26e2e 100644 --- a/arch/arm/mm/alignment.c +++ b/arch/arm/mm/alignment.c @@ -749,7 +749,6 @@ do_alignment(unsigned long addr, unsigned int fsr, struct pt_regs *regs) unsigned long instr = 0, instrptr; int (*handler)(unsigned long addr, unsigned long instr, struct pt_regs *regs); unsigned int type; - mm_segment_t fs; unsigned int fault; u16 tinstr = 0; int isize = 4; @@ -760,16 +759,15 @@ do_alignment(unsigned long addr, unsigned int fsr, struct pt_regs *regs) instrptr = instruction_pointer(regs); - fs = get_fs(); - set_fs(KERNEL_DS); if (thumb_mode(regs)) { - fault = __get_user(tinstr, (u16 *)(instrptr & ~1)); + u16 *ptr = (u16 *)(instrptr & ~1); + fault = probe_kernel_address(ptr, tinstr); if (!fault) { if (cpu_architecture() >= CPU_ARCH_ARMv7 && IS_T32(tinstr)) { /* Thumb-2 32-bit */ u16 tinst2 = 0; - fault = __get_user(tinst2, (u16 *)(instrptr+2)); + fault = probe_kernel_address(ptr + 1, tinst2); instr = (tinstr << 16) | tinst2; thumb2_32b = 1; } else { @@ -778,8 +776,7 @@ do_alignment(unsigned long addr, unsigned int fsr, struct pt_regs *regs) } } } else - fault = __get_user(instr, (u32 *)instrptr); - set_fs(fs); + fault = probe_kernel_address(instrptr, instr); if (fault) { type = TYPE_FAULT; -- cgit v1.1