From bf8801145c01ab600f8df66e8c879ac642fa5846 Mon Sep 17 00:00:00 2001 From: Will Deacon Date: Thu, 16 Aug 2012 18:55:44 +0100 Subject: ARM: 7496/1: hw_breakpoint: don't rely on dfsr to show watchpoint access type From ARM debug architecture v7.1 onwards, a watchpoint exception causes the DFAR to be updated with the faulting data address. However, DFSR.WnR takes an UNKNOWN value and therefore cannot be used in general to determine the access type that triggered the watchpoint. This patch forbids watchpoints without an overflow handler from specifying a specific access type (load/store). Those with overflow handlers must be able to handle false positives potentially triggered by a watchpoint of a different access type on the same address. For SIGTRAP-based handlers (i.e. ptrace), this should have no impact. Cc: Signed-off-by: Will Deacon Signed-off-by: Russell King --- arch/arm/kernel/hw_breakpoint.c | 55 ++++++++++++++++++++++++++++++----------- 1 file changed, 40 insertions(+), 15 deletions(-) (limited to 'arch/arm') diff --git a/arch/arm/kernel/hw_breakpoint.c b/arch/arm/kernel/hw_breakpoint.c index ba386bd94107..18d39ea4c02f 100644 --- a/arch/arm/kernel/hw_breakpoint.c +++ b/arch/arm/kernel/hw_breakpoint.c @@ -159,6 +159,12 @@ static int debug_arch_supported(void) arch >= ARM_DEBUG_ARCH_V7_1; } +/* Can we determine the watchpoint access type from the fsr? */ +static int debug_exception_updates_fsr(void) +{ + return 0; +} + /* Determine number of WRP registers available. */ static int get_num_wrp_resources(void) { @@ -619,18 +625,35 @@ int arch_validate_hwbkpt_settings(struct perf_event *bp) info->address &= ~alignment_mask; info->ctrl.len <<= offset; - /* - * Currently we rely on an overflow handler to take - * care of single-stepping the breakpoint when it fires. - * In the case of userspace breakpoints on a core with V7 debug, - * we can use the mismatch feature as a poor-man's hardware - * single-step, but this only works for per-task breakpoints. - */ - if (!bp->overflow_handler && (arch_check_bp_in_kernelspace(bp) || - !core_has_mismatch_brps() || !bp->hw.bp_target)) { - pr_warning("overflow handler required but none found\n"); - ret = -EINVAL; + if (!bp->overflow_handler) { + /* + * Mismatch breakpoints are required for single-stepping + * breakpoints. + */ + if (!core_has_mismatch_brps()) + return -EINVAL; + + /* We don't allow mismatch breakpoints in kernel space. */ + if (arch_check_bp_in_kernelspace(bp)) + return -EPERM; + + /* + * Per-cpu breakpoints are not supported by our stepping + * mechanism. + */ + if (!bp->hw.bp_target) + return -EINVAL; + + /* + * We only support specific access types if the fsr + * reports them. + */ + if (!debug_exception_updates_fsr() && + (info->ctrl.type == ARM_BREAKPOINT_LOAD || + info->ctrl.type == ARM_BREAKPOINT_STORE)) + return -EINVAL; } + out: return ret; } @@ -706,10 +729,12 @@ static void watchpoint_handler(unsigned long addr, unsigned int fsr, goto unlock; /* Check that the access type matches. */ - access = (fsr & ARM_FSR_ACCESS_MASK) ? HW_BREAKPOINT_W : - HW_BREAKPOINT_R; - if (!(access & hw_breakpoint_type(wp))) - goto unlock; + if (debug_exception_updates_fsr()) { + access = (fsr & ARM_FSR_ACCESS_MASK) ? + HW_BREAKPOINT_W : HW_BREAKPOINT_R; + if (!(access & hw_breakpoint_type(wp))) + goto unlock; + } /* We have a winner. */ info->trigger = addr; -- cgit v1.2.3 From d968d2b801d877601d54e35e6dd0f52d9c797c99 Mon Sep 17 00:00:00 2001 From: Will Deacon Date: Thu, 16 Aug 2012 19:02:12 +0100 Subject: ARM: 7497/1: hw_breakpoint: allow single-byte watchpoints on all addresses Breakpoint validation currently fails for single-byte watchpoints on addresses ending in 11b. There is no reason to forbid such a watchpoint, so extend the validation code to allow it. Cc: Ulrich Weigand Signed-off-by: Will Deacon Signed-off-by: Russell King --- arch/arm/kernel/hw_breakpoint.c | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) (limited to 'arch/arm') diff --git a/arch/arm/kernel/hw_breakpoint.c b/arch/arm/kernel/hw_breakpoint.c index 18d39ea4c02f..281bf3301241 100644 --- a/arch/arm/kernel/hw_breakpoint.c +++ b/arch/arm/kernel/hw_breakpoint.c @@ -610,13 +610,14 @@ int arch_validate_hwbkpt_settings(struct perf_event *bp) /* Aligned */ break; case 1: - /* Allow single byte watchpoint. */ - if (info->ctrl.len == ARM_BREAKPOINT_LEN_1) - break; case 2: /* Allow halfword watchpoints and breakpoints. */ if (info->ctrl.len == ARM_BREAKPOINT_LEN_2) break; + case 3: + /* Allow single byte watchpoint. */ + if (info->ctrl.len == ARM_BREAKPOINT_LEN_1) + break; default: ret = -EINVAL; goto out; -- cgit v1.2.3 From dbece45894d3ab1baac15a96dc4e1e8e23f64a93 Mon Sep 17 00:00:00 2001 From: Will Deacon Date: Fri, 24 Aug 2012 15:20:59 +0100 Subject: ARM: 7501/1: decompressor: reset ttbcr for VMSA ARMv7 cores When enabling the MMU for ARMv7 CPUs, the decompressor does not touch the ttbcr register, assuming that it will be zeroed (N == 0, EAE == 0). Given that only EAE is defined as 0 for non-secure copies of the register (and a bootloader such as kexec may leave it set to 1 anyway), we should ensure that we reset the register ourselves before turning on the MMU. This patch zeroes TTBCR.EAE and TTBCR.N prior to enabling the MMU for ARMv7 cores in the decompressor, configuring us exclusively for 32-bit translation tables via TTBR0. Cc: Acked-by: Nicolas Pitre Signed-off-by: Matthew Leach Signed-off-by: Will Deacon Signed-off-by: Russell King --- arch/arm/boot/compressed/head.S | 4 ++++ 1 file changed, 4 insertions(+) (limited to 'arch/arm') diff --git a/arch/arm/boot/compressed/head.S b/arch/arm/boot/compressed/head.S index b8c64b80bafc..81769c1341fa 100644 --- a/arch/arm/boot/compressed/head.S +++ b/arch/arm/boot/compressed/head.S @@ -659,10 +659,14 @@ __armv7_mmu_cache_on: #ifdef CONFIG_CPU_ENDIAN_BE8 orr r0, r0, #1 << 25 @ big-endian page tables #endif + mrcne p15, 0, r6, c2, c0, 2 @ read ttb control reg orrne r0, r0, #1 @ MMU enabled movne r1, #0xfffffffd @ domain 0 = client + bic r6, r6, #1 << 31 @ 32-bit translation system + bic r6, r6, #3 << 0 @ use only ttbr0 mcrne p15, 0, r3, c2, c0, 0 @ load page table pointer mcrne p15, 0, r1, c3, c0, 0 @ load domain access control + mcrne p15, 0, r6, c2, c0, 2 @ load ttb control #endif mcr p15, 0, r0, c7, c5, 4 @ ISB mcr p15, 0, r0, c1, c0, 0 @ load control register -- cgit v1.2.3 From ae3790b8a916429be5fa61da95992929e6b34d64 Mon Sep 17 00:00:00 2001 From: Will Deacon Date: Fri, 24 Aug 2012 15:21:52 +0100 Subject: 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,#8' Reported-by: Arnd Bergmann Signed-off-by: Will Deacon Signed-off-by: Russell King --- arch/arm/mm/context.c | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) (limited to 'arch/arm') diff --git a/arch/arm/mm/context.c b/arch/arm/mm/context.c index 119bc52ab93e..4e07eec1270d 100644 --- a/arch/arm/mm/context.c +++ b/arch/arm/mm/context.c @@ -63,10 +63,11 @@ static int contextidr_notifier(struct notifier_block *unused, unsigned long cmd, pid = task_pid_nr(thread->task) << ASID_BITS; asm volatile( " mrc p15, 0, %0, c13, c0, 1\n" - " bfi %1, %0, #0, %2\n" - " mcr p15, 0, %1, c13, c0, 1\n" + " and %0, %0, %2\n" + " orr %0, %0, %1\n" + " mcr p15, 0, %0, c13, c0, 1\n" : "=r" (contextidr), "+r" (pid) - : "I" (ASID_BITS)); + : "I" (~ASID_MASK)); isb(); return NOTIFY_OK; -- cgit v1.2.3 From df547e08e800275a431e560a7f0a6b6f24ab2904 Mon Sep 17 00:00:00 2001 From: Will Deacon Date: Fri, 24 Aug 2012 15:23:06 +0100 Subject: ARM: 7503/1: mm: only flush both pmd entries for classic MMU LPAE does not use two pmd entries for a pte, so the additional tlb flushing is not required. Signed-off-by: Will Deacon Signed-off-by: Russell King --- arch/arm/include/asm/tlb.h | 4 ++++ 1 file changed, 4 insertions(+) (limited to 'arch/arm') diff --git a/arch/arm/include/asm/tlb.h b/arch/arm/include/asm/tlb.h index 314d4664eae7..99a19512ee26 100644 --- a/arch/arm/include/asm/tlb.h +++ b/arch/arm/include/asm/tlb.h @@ -199,6 +199,9 @@ static inline void __pte_free_tlb(struct mmu_gather *tlb, pgtable_t pte, { pgtable_page_dtor(pte); +#ifdef CONFIG_ARM_LPAE + tlb_add_flush(tlb, addr); +#else /* * With the classic ARM MMU, a pte page has two corresponding pmd * entries, each covering 1MB. @@ -206,6 +209,7 @@ static inline void __pte_free_tlb(struct mmu_gather *tlb, pgtable_t pte, addr &= PMD_MASK; tlb_add_flush(tlb, addr + SZ_1M - PAGE_SIZE); tlb_add_flush(tlb, addr + SZ_1M); +#endif tlb_remove_page(tlb, pte); } -- cgit v1.2.3 From 36418c516b31bff4ff949c7c618430a1a514debe Mon Sep 17 00:00:00 2001 From: Jonathan Austin Date: Thu, 23 Aug 2012 14:02:59 +0100 Subject: ARM: 7499/1: mm: Fix vmalloc overlap check for !HIGHMEM With !HIGHMEM, sanity_check_meminfo checks for banks that completely or partially overlap the vmalloc region. The test for partial overlap checks __va(bank->start + bank->size) > vmalloc_min. This is not appropriate if there is a non-linear translation between virtual and physical addresses, as bank->start + bank->size is actually in the bank following the one being interrogated. In most cases, even when using SPARSEMEM, this is not problematic as the subsequent bank will start at a higher va than the one in question. However if the physical to virtual address conversion is not monotonic increasing, the incorrect test could result in a bank not being truncated when it should be. This patch ensures we perform the va-pa conversion on memory from the bank we are interested in, not the following one. Reported-by: ??? (Steve) Signed-off-by: Jonathan Austin Acked-by: Nicolas Pitre Signed-off-by: Russell King --- arch/arm/mm/mmu.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'arch/arm') diff --git a/arch/arm/mm/mmu.c b/arch/arm/mm/mmu.c index eab94bc6f805..c2fa21d0103e 100644 --- a/arch/arm/mm/mmu.c +++ b/arch/arm/mm/mmu.c @@ -961,8 +961,8 @@ void __init sanity_check_meminfo(void) * Check whether this memory bank would partially overlap * the vmalloc area. */ - if (__va(bank->start + bank->size) > vmalloc_min || - __va(bank->start + bank->size) < __va(bank->start)) { + if (__va(bank->start + bank->size - 1) >= vmalloc_min || + __va(bank->start + bank->size - 1) <= __va(bank->start)) { unsigned long newsize = vmalloc_min - __va(bank->start); printk(KERN_NOTICE "Truncating RAM at %.8llx-%.8llx " "to -%.8llx (vmalloc region overlap).\n", -- cgit v1.2.3 From 45caae74d238ef6583e9402cb8c550cc0b0f7dbd Mon Sep 17 00:00:00 2001 From: Igor Grinberg Date: Tue, 28 Aug 2012 01:26:14 +0300 Subject: ARM: OMAP: timer: obey the !CONFIG_OMAP_32K_TIMER Currently, omap2_sync32k_clocksource_init() function initializes the 32K timer as the system clock source regardless of the CONFIG_OMAP_32K_TIMER setting. Fix this by providing a default implementation for !CONFIG_OMAP_32K_TIMER case. Signed-off-by: Igor Grinberg Reviewed-by: Paul Walmsley Acked-by: Santosh Shilimkar Cc: stable@vger.kernel.org Signed-off-by: Tony Lindgren --- arch/arm/mach-omap2/timer.c | 7 +++++++ 1 file changed, 7 insertions(+) (limited to 'arch/arm') diff --git a/arch/arm/mach-omap2/timer.c b/arch/arm/mach-omap2/timer.c index 2ff6d41ec6c6..2ba4f57dda86 100644 --- a/arch/arm/mach-omap2/timer.c +++ b/arch/arm/mach-omap2/timer.c @@ -260,6 +260,7 @@ static u32 notrace dmtimer_read_sched_clock(void) return 0; } +#ifdef CONFIG_OMAP_32K_TIMER /* Setup free-running counter for clocksource */ static int __init omap2_sync32k_clocksource_init(void) { @@ -299,6 +300,12 @@ static int __init omap2_sync32k_clocksource_init(void) return ret; } +#else +static inline int omap2_sync32k_clocksource_init(void) +{ + return -ENODEV; +} +#endif static void __init omap2_gptimer_clocksource_init(int gptimer_id, const char *fck_source) -- cgit v1.2.3 From 528c28f5c1cd435c45515b323919205c95342331 Mon Sep 17 00:00:00 2001 From: Aaro Koskinen Date: Wed, 29 Aug 2012 18:24:30 +0300 Subject: ARM: OMAP: sram: fix OMAP4 errata handling OMAP4-specific code should be executed only if we are running on OMAP4. Otherwise it may break multi-OMAP kernels. Found by reading the code. Signed-off-by: Aaro Koskinen Acked-by: Santosh Shilimkar Signed-off-by: Tony Lindgren --- arch/arm/plat-omap/sram.c | 2 ++ 1 file changed, 2 insertions(+) (limited to 'arch/arm') diff --git a/arch/arm/plat-omap/sram.c b/arch/arm/plat-omap/sram.c index 766181cb5c95..85c23db25034 100644 --- a/arch/arm/plat-omap/sram.c +++ b/arch/arm/plat-omap/sram.c @@ -175,8 +175,10 @@ static void __init omap_map_sram(void) return; #ifdef CONFIG_OMAP4_ERRATA_I688 + if (cpu_is_omap44xx()) { omap_sram_start += PAGE_SIZE; omap_sram_size -= SZ_16K; + } #endif if (cpu_is_omap34xx()) { /* -- cgit v1.2.3 From b285673489e39252a2c3f0c7a7d77fd28a6cda38 Mon Sep 17 00:00:00 2001 From: Aaro Koskinen Date: Wed, 29 Aug 2012 18:24:31 +0300 Subject: ARM: OMAP: sram: skip the first 16K on OMAP3 HS In some OMAP3 HS devices (at least Nokia N9 and N950), the public SRAM seems to conflict with secure portition of SRAM. When booting the 3.6-rc3 kernel (and also earlier) on these devices, the kernel gets tainted with tons of the following warnings: [ 6.894348] In-band Error seen by MPU at address 0 [...] [ 6.894378] WARNING: at arch/arm/mach-omap2/omap_l3_smx.c:162 Fix this by skipping the first 16K of the public SRAM. (Note that the mapping could not be changed, as it resulted in secure monitor call failure in save_secure_sram().) This will leave 12K SRAM available that should be still sufficient. The patch has been boot tested with vanilla 3.6-rc3 on N900, N950 and N9. Signed-off-by: Aaro Koskinen Acked-by: Santosh Shilimkar Signed-off-by: Tony Lindgren --- arch/arm/plat-omap/sram.c | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) (limited to 'arch/arm') diff --git a/arch/arm/plat-omap/sram.c b/arch/arm/plat-omap/sram.c index 85c23db25034..024f3b08db29 100644 --- a/arch/arm/plat-omap/sram.c +++ b/arch/arm/plat-omap/sram.c @@ -68,6 +68,7 @@ static unsigned long omap_sram_start; static void __iomem *omap_sram_base; +static unsigned long omap_sram_skip; static unsigned long omap_sram_size; static void __iomem *omap_sram_ceil; @@ -106,6 +107,7 @@ static int is_sram_locked(void) */ static void __init omap_detect_sram(void) { + omap_sram_skip = SRAM_BOOTLOADER_SZ; if (cpu_class_is_omap2()) { if (is_sram_locked()) { if (cpu_is_omap34xx()) { @@ -113,6 +115,7 @@ static void __init omap_detect_sram(void) if ((omap_type() == OMAP2_DEVICE_TYPE_EMU) || (omap_type() == OMAP2_DEVICE_TYPE_SEC)) { omap_sram_size = 0x7000; /* 28K */ + omap_sram_skip += SZ_16K; } else { omap_sram_size = 0x8000; /* 32K */ } @@ -205,8 +208,8 @@ static void __init omap_map_sram(void) * Looks like we need to preserve some bootloader code at the * beginning of SRAM for jumping to flash for reboot to work... */ - memset_io(omap_sram_base + SRAM_BOOTLOADER_SZ, 0, - omap_sram_size - SRAM_BOOTLOADER_SZ); + memset_io(omap_sram_base + omap_sram_skip, 0, + omap_sram_size - omap_sram_skip); } /* @@ -220,7 +223,7 @@ void *omap_sram_push_address(unsigned long size) { unsigned long available, new_ceil = (unsigned long)omap_sram_ceil; - available = omap_sram_ceil - (omap_sram_base + SRAM_BOOTLOADER_SZ); + available = omap_sram_ceil - (omap_sram_base + omap_sram_skip); if (size > available) { pr_err("Not enough space in SRAM\n"); -- cgit v1.2.3 From a17fb8f520c3c662686aa54a86773f354002c7d3 Mon Sep 17 00:00:00 2001 From: Radek Pilar Date: Fri, 17 Aug 2012 18:03:43 +0200 Subject: ARM: OMAP: Config fix for omap3-touchbook board Fix inconsistency between mach-types and CONFIG_ name that prevents touchbook board from booting. Signed-off-by: Radek Pilar Signed-off-by: Tony Lindgren --- arch/arm/mach-omap2/Kconfig | 3 ++- arch/arm/mach-omap2/Makefile | 2 +- 2 files changed, 3 insertions(+), 2 deletions(-) (limited to 'arch/arm') diff --git a/arch/arm/mach-omap2/Kconfig b/arch/arm/mach-omap2/Kconfig index dd2db025f778..0a3e1b9f1fbc 100644 --- a/arch/arm/mach-omap2/Kconfig +++ b/arch/arm/mach-omap2/Kconfig @@ -231,10 +231,11 @@ config MACH_OMAP3_PANDORA select OMAP_PACKAGE_CBB select REGULATOR_FIXED_VOLTAGE if REGULATOR -config MACH_OMAP3_TOUCHBOOK +config MACH_TOUCHBOOK bool "OMAP3 Touch Book" depends on ARCH_OMAP3 default y + select OMAP_PACKAGE_CBB config MACH_OMAP_3430SDP bool "OMAP 3430 SDP board" diff --git a/arch/arm/mach-omap2/Makefile b/arch/arm/mach-omap2/Makefile index f6a24b3f9c4f..34c2c7f59f0a 100644 --- a/arch/arm/mach-omap2/Makefile +++ b/arch/arm/mach-omap2/Makefile @@ -255,7 +255,7 @@ obj-$(CONFIG_MACH_OMAP_3630SDP) += board-zoom-display.o obj-$(CONFIG_MACH_CM_T35) += board-cm-t35.o obj-$(CONFIG_MACH_CM_T3517) += board-cm-t3517.o obj-$(CONFIG_MACH_IGEP0020) += board-igep0020.o -obj-$(CONFIG_MACH_OMAP3_TOUCHBOOK) += board-omap3touchbook.o +obj-$(CONFIG_MACH_TOUCHBOOK) += board-omap3touchbook.o obj-$(CONFIG_MACH_OMAP_4430SDP) += board-4430sdp.o obj-$(CONFIG_MACH_OMAP4_PANDA) += board-omap4panda.o -- cgit v1.2.3 From 577650139062dcc20246da3f61e0bdafc65edf8f Mon Sep 17 00:00:00 2001 From: Vaibhav Hiremath Date: Mon, 3 Sep 2012 11:50:36 -0600 Subject: ARM: OMAP2+: am33xx: Fix the timer fck clock naming convention With commit ae6df418a21f3a361c5f9b878e32a8aba4e17692 Sub: ARM: OMAP2+: dmtimer: cleanup fclk usage) The Timer functional clock naming convention has changed from gptX_fck => timerXfck, and so as the timer init function in mach-omap2/timer.c. OMAP4 clocktree also has changed accordingly. AM33xx Clock Tree has been merged during rc3-4 timeframe, before above commit got merged, so similar change is required for AM33xx as well (Change the gptX_fck => timerX_fck). Signed-off-by: Vaibhav Hiremath Signed-off-by: Paul Walmsley --- arch/arm/mach-omap2/clock33xx_data.c | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) (limited to 'arch/arm') diff --git a/arch/arm/mach-omap2/clock33xx_data.c b/arch/arm/mach-omap2/clock33xx_data.c index 25bbcc7ca4dc..ae27de8899a6 100644 --- a/arch/arm/mach-omap2/clock33xx_data.c +++ b/arch/arm/mach-omap2/clock33xx_data.c @@ -1036,13 +1036,13 @@ static struct omap_clk am33xx_clks[] = { CLK(NULL, "mmu_fck", &mmu_fck, CK_AM33XX), CLK(NULL, "smartreflex0_fck", &smartreflex0_fck, CK_AM33XX), CLK(NULL, "smartreflex1_fck", &smartreflex1_fck, CK_AM33XX), - CLK(NULL, "gpt1_fck", &timer1_fck, CK_AM33XX), - CLK(NULL, "gpt2_fck", &timer2_fck, CK_AM33XX), - CLK(NULL, "gpt3_fck", &timer3_fck, CK_AM33XX), - CLK(NULL, "gpt4_fck", &timer4_fck, CK_AM33XX), - CLK(NULL, "gpt5_fck", &timer5_fck, CK_AM33XX), - CLK(NULL, "gpt6_fck", &timer6_fck, CK_AM33XX), - CLK(NULL, "gpt7_fck", &timer7_fck, CK_AM33XX), + CLK(NULL, "timer1_fck", &timer1_fck, CK_AM33XX), + CLK(NULL, "timer2_fck", &timer2_fck, CK_AM33XX), + CLK(NULL, "timer3_fck", &timer3_fck, CK_AM33XX), + CLK(NULL, "timer4_fck", &timer4_fck, CK_AM33XX), + CLK(NULL, "timer5_fck", &timer5_fck, CK_AM33XX), + CLK(NULL, "timer6_fck", &timer6_fck, CK_AM33XX), + CLK(NULL, "timer7_fck", &timer7_fck, CK_AM33XX), CLK(NULL, "usbotg_fck", &usbotg_fck, CK_AM33XX), CLK(NULL, "ieee5000_fck", &ieee5000_fck, CK_AM33XX), CLK(NULL, "wdt1_fck", &wdt1_fck, CK_AM33XX), -- cgit v1.2.3 From bfb7dd25fcde96d08591258bc7e97500337a57ee Mon Sep 17 00:00:00 2001 From: Paul Walmsley Date: Mon, 3 Sep 2012 11:50:43 -0600 Subject: ARM: OMAP3xxx: clockdomain: fix software supervised wakeup/sleep Commit 4da71ae6 ("OMAP: clockdomain: Arch specific funcs for clkdm_clk_enable/disable") called the OMAP2xxx-specific functions for clockdomain wakeup and sleep. This would probably have broken software-supervised clockdomain wakeup and sleep on OMAP3. Signed-off-by: Paul Walmsley Cc: Rajendra Nayak Cc: Jon Hunter Acked-by: Rajendra Nayak --- arch/arm/mach-omap2/clockdomain2xxx_3xxx.c | 50 ++++++++++++++++++++++++++++-- 1 file changed, 48 insertions(+), 2 deletions(-) (limited to 'arch/arm') diff --git a/arch/arm/mach-omap2/clockdomain2xxx_3xxx.c b/arch/arm/mach-omap2/clockdomain2xxx_3xxx.c index a0d68dbecfa3..f99e65cfb862 100644 --- a/arch/arm/mach-omap2/clockdomain2xxx_3xxx.c +++ b/arch/arm/mach-omap2/clockdomain2xxx_3xxx.c @@ -241,6 +241,52 @@ static void omap3_clkdm_deny_idle(struct clockdomain *clkdm) _clkdm_del_autodeps(clkdm); } +static int omap3xxx_clkdm_clk_enable(struct clockdomain *clkdm) +{ + bool hwsup = false; + + if (!clkdm->clktrctrl_mask) + return 0; + + hwsup = omap2_cm_is_clkdm_in_hwsup(clkdm->pwrdm.ptr->prcm_offs, + clkdm->clktrctrl_mask); + + if (hwsup) { + /* Disable HW transitions when we are changing deps */ + _disable_hwsup(clkdm); + _clkdm_add_autodeps(clkdm); + _enable_hwsup(clkdm); + } else { + if (clkdm->flags & CLKDM_CAN_FORCE_WAKEUP) + omap3_clkdm_wakeup(clkdm); + } + + return 0; +} + +static int omap3xxx_clkdm_clk_disable(struct clockdomain *clkdm) +{ + bool hwsup = false; + + if (!clkdm->clktrctrl_mask) + return 0; + + hwsup = omap2_cm_is_clkdm_in_hwsup(clkdm->pwrdm.ptr->prcm_offs, + clkdm->clktrctrl_mask); + + if (hwsup) { + /* Disable HW transitions when we are changing deps */ + _disable_hwsup(clkdm); + _clkdm_del_autodeps(clkdm); + _enable_hwsup(clkdm); + } else { + if (clkdm->flags & CLKDM_CAN_FORCE_SLEEP) + omap3_clkdm_sleep(clkdm); + } + + return 0; +} + struct clkdm_ops omap2_clkdm_operations = { .clkdm_add_wkdep = omap2_clkdm_add_wkdep, .clkdm_del_wkdep = omap2_clkdm_del_wkdep, @@ -267,6 +313,6 @@ struct clkdm_ops omap3_clkdm_operations = { .clkdm_wakeup = omap3_clkdm_wakeup, .clkdm_allow_idle = omap3_clkdm_allow_idle, .clkdm_deny_idle = omap3_clkdm_deny_idle, - .clkdm_clk_enable = omap2_clkdm_clk_enable, - .clkdm_clk_disable = omap2_clkdm_clk_disable, + .clkdm_clk_enable = omap3xxx_clkdm_clk_enable, + .clkdm_clk_disable = omap3xxx_clkdm_clk_disable, }; -- cgit v1.2.3 From ed733619d85262439f625cc9d8b00cdaae761070 Mon Sep 17 00:00:00 2001 From: Tero Kristo Date: Mon, 3 Sep 2012 11:50:52 -0600 Subject: ARM: OMAP3: hwmod data: fix iva2 reset info IVA2 hwmod resets were missing the status bit offsets. Also, as the hwmod itself didn't have prcm info at all, resetting iva hwmod was accessing some bogus memory addresses. Added both infos to fix this. Signed-off-by: Tero Kristo Signed-off-by: Paul Walmsley --- arch/arm/mach-omap2/cm-regbits-34xx.h | 1 + arch/arm/mach-omap2/omap_hwmod_3xxx_data.c | 15 ++++++++++++--- 2 files changed, 13 insertions(+), 3 deletions(-) (limited to 'arch/arm') diff --git a/arch/arm/mach-omap2/cm-regbits-34xx.h b/arch/arm/mach-omap2/cm-regbits-34xx.h index 766338fe4d34..975f6bda0e0b 100644 --- a/arch/arm/mach-omap2/cm-regbits-34xx.h +++ b/arch/arm/mach-omap2/cm-regbits-34xx.h @@ -67,6 +67,7 @@ #define OMAP3430_EN_IVA2_DPLL_MASK (0x7 << 0) /* CM_IDLEST_IVA2 */ +#define OMAP3430_ST_IVA2_SHIFT 0 #define OMAP3430_ST_IVA2_MASK (1 << 0) /* CM_IDLEST_PLL_IVA2 */ diff --git a/arch/arm/mach-omap2/omap_hwmod_3xxx_data.c b/arch/arm/mach-omap2/omap_hwmod_3xxx_data.c index c9e38200216b..ce7e6068768f 100644 --- a/arch/arm/mach-omap2/omap_hwmod_3xxx_data.c +++ b/arch/arm/mach-omap2/omap_hwmod_3xxx_data.c @@ -100,9 +100,9 @@ static struct omap_hwmod omap3xxx_mpu_hwmod = { /* IVA2 (IVA2) */ static struct omap_hwmod_rst_info omap3xxx_iva_resets[] = { - { .name = "logic", .rst_shift = 0 }, - { .name = "seq0", .rst_shift = 1 }, - { .name = "seq1", .rst_shift = 2 }, + { .name = "logic", .rst_shift = 0, .st_shift = 8 }, + { .name = "seq0", .rst_shift = 1, .st_shift = 9 }, + { .name = "seq1", .rst_shift = 2, .st_shift = 10 }, }; static struct omap_hwmod omap3xxx_iva_hwmod = { @@ -112,6 +112,15 @@ static struct omap_hwmod omap3xxx_iva_hwmod = { .rst_lines = omap3xxx_iva_resets, .rst_lines_cnt = ARRAY_SIZE(omap3xxx_iva_resets), .main_clk = "iva2_ck", + .prcm = { + .omap2 = { + .module_offs = OMAP3430_IVA2_MOD, + .prcm_reg_id = 1, + .module_bit = OMAP3430_CM_FCLKEN_IVA2_EN_IVA2_SHIFT, + .idlest_reg_id = 1, + .idlest_idle_bit = OMAP3430_ST_IVA2_SHIFT, + } + }, }; /* timer class */ -- cgit v1.2.3 From 471a009b6db7670299a8674cd7fb2557c8c2797f Mon Sep 17 00:00:00 2001 From: Misael Lopez Cruz Date: Mon, 3 Sep 2012 11:50:52 -0600 Subject: ARM: OMAP: hwmod code: Disable module when hwmod enable fails Clock and module mode are explictly enable when hwmod is enabled. But if the hwmod doesn't get ready on time, clocks are disabled but module is left enabled. Signed-off-by: Misael Lopez Cruz Signed-off-by: Rajendra Nayak Cc: Paul Walmsley Cc: Benoit Cousson Signed-off-by: Paul Walmsley --- arch/arm/mach-omap2/omap_hwmod.c | 1 + 1 file changed, 1 insertion(+) (limited to 'arch/arm') diff --git a/arch/arm/mach-omap2/omap_hwmod.c b/arch/arm/mach-omap2/omap_hwmod.c index 6ca8e519968d..37afbd173c2c 100644 --- a/arch/arm/mach-omap2/omap_hwmod.c +++ b/arch/arm/mach-omap2/omap_hwmod.c @@ -1889,6 +1889,7 @@ static int _enable(struct omap_hwmod *oh) _enable_sysc(oh); } } else { + _omap4_disable_module(oh); _disable_clocks(oh); pr_debug("omap_hwmod: %s: _wait_target_ready: %d\n", oh->name, r); -- cgit v1.2.3 From b360124ea008fcccf440840bde2c7f317bc31509 Mon Sep 17 00:00:00 2001 From: Tero Kristo Date: Mon, 3 Sep 2012 11:50:53 -0600 Subject: ARM: OMAP4: hwmod data: temporarily comment out data for the sl2if IP block MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The OMAP4 sl2if IP block requires some special programming for it to enter idle. Without this programming, it will prevent the rest of the chip from entering full chip idle. This patch comments out the IP block data. Later, once the appropriate support is available, this patch can be reverted. Cc: Paul Walmsley Cc: BenoƮt Cousson Signed-off-by: Tero Kristo Signed-off-by: Paul Walmsley --- arch/arm/mach-omap2/omap_hwmod_44xx_data.c | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) (limited to 'arch/arm') diff --git a/arch/arm/mach-omap2/omap_hwmod_44xx_data.c b/arch/arm/mach-omap2/omap_hwmod_44xx_data.c index 242aee498ceb..afb60917a948 100644 --- a/arch/arm/mach-omap2/omap_hwmod_44xx_data.c +++ b/arch/arm/mach-omap2/omap_hwmod_44xx_data.c @@ -4210,7 +4210,7 @@ static struct omap_hwmod_ocp_if omap44xx_dsp__iva = { }; /* dsp -> sl2if */ -static struct omap_hwmod_ocp_if omap44xx_dsp__sl2if = { +static struct omap_hwmod_ocp_if __maybe_unused omap44xx_dsp__sl2if = { .master = &omap44xx_dsp_hwmod, .slave = &omap44xx_sl2if_hwmod, .clk = "dpll_iva_m5x2_ck", @@ -4828,7 +4828,7 @@ static struct omap_hwmod_ocp_if omap44xx_l3_main_2__iss = { }; /* iva -> sl2if */ -static struct omap_hwmod_ocp_if omap44xx_iva__sl2if = { +static struct omap_hwmod_ocp_if __maybe_unused omap44xx_iva__sl2if = { .master = &omap44xx_iva_hwmod, .slave = &omap44xx_sl2if_hwmod, .clk = "dpll_iva_m5x2_ck", @@ -5362,7 +5362,7 @@ static struct omap_hwmod_ocp_if omap44xx_l4_wkup__scrm = { }; /* l3_main_2 -> sl2if */ -static struct omap_hwmod_ocp_if omap44xx_l3_main_2__sl2if = { +static struct omap_hwmod_ocp_if __maybe_unused omap44xx_l3_main_2__sl2if = { .master = &omap44xx_l3_main_2_hwmod, .slave = &omap44xx_sl2if_hwmod, .clk = "l3_div_ck", @@ -6032,7 +6032,7 @@ static struct omap_hwmod_ocp_if *omap44xx_hwmod_ocp_ifs[] __initdata = { &omap44xx_l4_abe__dmic, &omap44xx_l4_abe__dmic_dma, &omap44xx_dsp__iva, - &omap44xx_dsp__sl2if, + /* &omap44xx_dsp__sl2if, */ &omap44xx_l4_cfg__dsp, &omap44xx_l3_main_2__dss, &omap44xx_l4_per__dss, @@ -6068,7 +6068,7 @@ static struct omap_hwmod_ocp_if *omap44xx_hwmod_ocp_ifs[] __initdata = { &omap44xx_l4_per__i2c4, &omap44xx_l3_main_2__ipu, &omap44xx_l3_main_2__iss, - &omap44xx_iva__sl2if, + /* &omap44xx_iva__sl2if, */ &omap44xx_l3_main_2__iva, &omap44xx_l4_wkup__kbd, &omap44xx_l4_cfg__mailbox, @@ -6099,7 +6099,7 @@ static struct omap_hwmod_ocp_if *omap44xx_hwmod_ocp_ifs[] __initdata = { &omap44xx_l4_cfg__cm_core, &omap44xx_l4_wkup__prm, &omap44xx_l4_wkup__scrm, - &omap44xx_l3_main_2__sl2if, + /* &omap44xx_l3_main_2__sl2if, */ &omap44xx_l4_abe__slimbus1, &omap44xx_l4_abe__slimbus1_dma, &omap44xx_l4_per__slimbus2, -- cgit v1.2.3 From e534e871a94ba2e3bfdf0edd3685eb805fc960d8 Mon Sep 17 00:00:00 2001 From: Tony Lindgren Date: Tue, 4 Sep 2012 17:22:45 -0700 Subject: ARM: OMAP4: Fix array size for irq_target_cpu If NR_IRQS is less than MAX_IRQS, we end up writing past the irq_target_cpu array in omap_wakeupgen_init(): /* Associate all the IRQs to boot CPU like GIC init does. */ for (i = 0; i < max_irqs; i++) irq_target_cpu[i] = boot_cpu; This can happen if SPARSE_IRQ is enabled as by default NR_IRQS is set to 16. Without this patch we're overwriting other data during the boot. Looks like a similar fix was posted by Benoit Cousson earlier as "ARM: OMAP2+: wakeupgen: Fix wrong array size for irq_target_cpu" but was lost. Cc: stable@vger.kernel.org Acked-by: Santosh Shilimkar Signed-off-by: Tony Lindgren --- arch/arm/mach-omap2/omap-wakeupgen.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'arch/arm') diff --git a/arch/arm/mach-omap2/omap-wakeupgen.c b/arch/arm/mach-omap2/omap-wakeupgen.c index 05fdebfaa195..330d4c6e746b 100644 --- a/arch/arm/mach-omap2/omap-wakeupgen.c +++ b/arch/arm/mach-omap2/omap-wakeupgen.c @@ -46,7 +46,7 @@ static void __iomem *wakeupgen_base; static void __iomem *sar_base; static DEFINE_SPINLOCK(wakeupgen_lock); -static unsigned int irq_target_cpu[NR_IRQS]; +static unsigned int irq_target_cpu[MAX_IRQS]; static unsigned int irq_banks = MAX_NR_REG_BANKS; static unsigned int max_irqs = MAX_IRQS; static unsigned int omap_secure_apis; -- cgit v1.2.3 From b4ad51559c2f12c34a0340b26ffb02e4b285bc51 Mon Sep 17 00:00:00 2001 From: Stephen Boyd Date: Tue, 4 Sep 2012 20:04:35 +0100 Subject: ARM: 7512/1: Fix XIP build due to PHYS_OFFSET definition moving During the p2v changes, the PHYS_OFFSET #define moved into a !__ASSEMBLY__ section. This causes a XIP build to fail with arch/arm/kernel/head.o: In function 'stext': arch/arm/kernel/head.S:146: undefined reference to 'PHYS_OFFSET' Momentarily leave the #ifndef __ASSEMBLY__ section so we can define PHYS_OFFSET for all compilation units. Signed-off-by: Stephen Boyd Signed-off-by: Russell King --- arch/arm/include/asm/memory.h | 3 +++ 1 file changed, 3 insertions(+) (limited to 'arch/arm') diff --git a/arch/arm/include/asm/memory.h b/arch/arm/include/asm/memory.h index e965f1b560f1..5f6ddcc56452 100644 --- a/arch/arm/include/asm/memory.h +++ b/arch/arm/include/asm/memory.h @@ -187,6 +187,7 @@ static inline unsigned long __phys_to_virt(unsigned long x) #define __phys_to_virt(x) ((x) - PHYS_OFFSET + PAGE_OFFSET) #endif #endif +#endif /* __ASSEMBLY__ */ #ifndef PHYS_OFFSET #ifdef PLAT_PHYS_OFFSET @@ -196,6 +197,8 @@ static inline unsigned long __phys_to_virt(unsigned long x) #endif #endif +#ifndef __ASSEMBLY__ + /* * PFNs are used to describe any physical page; this means * PFN 0 == physical address 0. -- cgit v1.2.3 From 70b0476a2394de4f4e32e0b67288d80ff71ca963 Mon Sep 17 00:00:00 2001 From: David Brown Date: Tue, 4 Sep 2012 21:36:37 +0100 Subject: ARM: 7513/1: Make sure dtc is built before running it 'make dtbs' in a clean tree will try running the dtc before actually building it. Make these rules depend upon the scripts to build it. Cc: Signed-off-by: David Brown Signed-off-by: Russell King --- arch/arm/Makefile | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'arch/arm') diff --git a/arch/arm/Makefile b/arch/arm/Makefile index 30eae87ead6d..a051dfbdd7db 100644 --- a/arch/arm/Makefile +++ b/arch/arm/Makefile @@ -284,10 +284,10 @@ zImage Image xipImage bootpImage uImage: vmlinux zinstall uinstall install: vmlinux $(Q)$(MAKE) $(build)=$(boot) MACHINE=$(MACHINE) $@ -%.dtb: +%.dtb: scripts $(Q)$(MAKE) $(build)=$(boot) MACHINE=$(MACHINE) $(boot)/$@ -dtbs: +dtbs: scripts $(Q)$(MAKE) $(build)=$(boot) MACHINE=$(MACHINE) $(boot)/$@ # We use MRPROPER_FILES and CLEAN_FILES now -- cgit v1.2.3 From 62194bdab89b30f451d210247d09e1c146e6d0ad Mon Sep 17 00:00:00 2001 From: Stephen Boyd Date: Thu, 6 Sep 2012 21:24:32 +0100 Subject: ARM: 7521/1: Fix semihosting Kconfig text It seems we were missing some text in the title for the semihosting DEBUG_LL option. Add in the "/O" and fix up some minor typos in the help text. Signed-off-by: Stephen Boyd Acked-by: Nicolas Pitre Signed-off-by: Russell King --- arch/arm/Kconfig.debug | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) (limited to 'arch/arm') diff --git a/arch/arm/Kconfig.debug b/arch/arm/Kconfig.debug index f15f82bf3a50..e968a52e4881 100644 --- a/arch/arm/Kconfig.debug +++ b/arch/arm/Kconfig.debug @@ -356,15 +356,15 @@ choice is nothing connected to read from the DCC. config DEBUG_SEMIHOSTING - bool "Kernel low-level debug output via semihosting I" + bool "Kernel low-level debug output via semihosting I/O" help Semihosting enables code running on an ARM target to use the I/O facilities on a host debugger/emulator through a - simple SVC calls. The host debugger or emulator must have + simple SVC call. The host debugger or emulator must have semihosting enabled for the special svc call to be trapped otherwise the kernel will crash. - This is known to work with OpenOCD, as wellas + This is known to work with OpenOCD, as well as ARM's Fast Models, or any other controlling environment that implements semihosting. -- cgit v1.2.3 From 2b2040af0b64cd93e5d4df2494c4486cf604090d Mon Sep 17 00:00:00 2001 From: Will Deacon Date: Fri, 7 Sep 2012 18:21:44 +0100 Subject: ARM: 7526/1: traps: send SIGILL if get_user fails on undef handling path get_user may fail to load from the provided __user address due to an unhandled fault generated by the access. In the case of the undefined instruction trap, this results in failure to load the faulting instruction, in which case we should send SIGILL to the task rather than continue with potentially uninitialised data. Signed-off-by: Will Deacon Cc: stable@vger.kernel.org Signed-off-by: Russell King --- arch/arm/kernel/traps.c | 11 +++++++---- 1 file changed, 7 insertions(+), 4 deletions(-) (limited to 'arch/arm') diff --git a/arch/arm/kernel/traps.c b/arch/arm/kernel/traps.c index f7945218b8c6..b0179b89a04c 100644 --- a/arch/arm/kernel/traps.c +++ b/arch/arm/kernel/traps.c @@ -420,20 +420,23 @@ asmlinkage void __exception do_undefinstr(struct pt_regs *regs) #endif instr = *(u32 *) pc; } else if (thumb_mode(regs)) { - get_user(instr, (u16 __user *)pc); + if (get_user(instr, (u16 __user *)pc)) + goto die_sig; if (is_wide_instruction(instr)) { unsigned int instr2; - get_user(instr2, (u16 __user *)pc+1); + if (get_user(instr2, (u16 __user *)pc+1)) + goto die_sig; instr <<= 16; instr |= instr2; } - } else { - get_user(instr, (u32 __user *)pc); + } else if (get_user(instr, (u32 __user *)pc)) { + goto die_sig; } if (call_undef_hook(regs, instr) == 0) return; +die_sig: #ifdef CONFIG_DEBUG_USER if (user_debug & UDBG_UNDEFINED) { printk(KERN_INFO "%s (%d): undefined instruction: pc=%p\n", -- cgit v1.2.3 From 8404663f81d212918ff85f493649a7991209fa04 Mon Sep 17 00:00:00 2001 From: Russell King Date: Fri, 7 Sep 2012 18:22:28 +0100 Subject: ARM: 7527/1: uaccess: explicitly check __user pointer when !CPU_USE_DOMAINS The {get,put}_user macros don't perform range checking on the provided __user address when !CPU_HAS_DOMAINS. This patch reworks the out-of-line assembly accessors to check the user address against a specified limit, returning -EFAULT if is is out of range. [will: changed get_user register allocation to match put_user] [rmk: fixed building on older ARM architectures] Reported-by: Catalin Marinas Signed-off-by: Will Deacon Cc: stable@vger.kernel.org Signed-off-by: Russell King --- arch/arm/include/asm/assembler.h | 8 ++++++++ arch/arm/include/asm/uaccess.h | 40 +++++++++++++++++++++++++++------------- arch/arm/lib/getuser.S | 23 +++++++++++++++-------- arch/arm/lib/putuser.S | 6 ++++++ 4 files changed, 56 insertions(+), 21 deletions(-) (limited to 'arch/arm') diff --git a/arch/arm/include/asm/assembler.h b/arch/arm/include/asm/assembler.h index 03fb93621d0d..5c8b3bf4d825 100644 --- a/arch/arm/include/asm/assembler.h +++ b/arch/arm/include/asm/assembler.h @@ -320,4 +320,12 @@ .size \name , . - \name .endm + .macro check_uaccess, addr:req, size:req, limit:req, tmp:req, bad:req +#ifndef CONFIG_CPU_USE_DOMAINS + adds \tmp, \addr, #\size - 1 + sbcccs \tmp, \tmp, \limit + bcs \bad +#endif + .endm + #endif /* __ASM_ASSEMBLER_H__ */ diff --git a/arch/arm/include/asm/uaccess.h b/arch/arm/include/asm/uaccess.h index 479a6352e0b5..6f83ad6e4d3d 100644 --- a/arch/arm/include/asm/uaccess.h +++ b/arch/arm/include/asm/uaccess.h @@ -101,28 +101,39 @@ extern int __get_user_1(void *); extern int __get_user_2(void *); extern int __get_user_4(void *); -#define __get_user_x(__r2,__p,__e,__s,__i...) \ +#define __GUP_CLOBBER_1 "lr", "cc" +#ifdef CONFIG_CPU_USE_DOMAINS +#define __GUP_CLOBBER_2 "ip", "lr", "cc" +#else +#define __GUP_CLOBBER_2 "lr", "cc" +#endif +#define __GUP_CLOBBER_4 "lr", "cc" + +#define __get_user_x(__r2,__p,__e,__l,__s) \ __asm__ __volatile__ ( \ __asmeq("%0", "r0") __asmeq("%1", "r2") \ + __asmeq("%3", "r1") \ "bl __get_user_" #__s \ : "=&r" (__e), "=r" (__r2) \ - : "0" (__p) \ - : __i, "cc") + : "0" (__p), "r" (__l) \ + : __GUP_CLOBBER_##__s) #define get_user(x,p) \ ({ \ + unsigned long __limit = current_thread_info()->addr_limit - 1; \ register const typeof(*(p)) __user *__p asm("r0") = (p);\ register unsigned long __r2 asm("r2"); \ + register unsigned long __l asm("r1") = __limit; \ register int __e asm("r0"); \ switch (sizeof(*(__p))) { \ case 1: \ - __get_user_x(__r2, __p, __e, 1, "lr"); \ - break; \ + __get_user_x(__r2, __p, __e, __l, 1); \ + break; \ case 2: \ - __get_user_x(__r2, __p, __e, 2, "r3", "lr"); \ + __get_user_x(__r2, __p, __e, __l, 2); \ break; \ case 4: \ - __get_user_x(__r2, __p, __e, 4, "lr"); \ + __get_user_x(__r2, __p, __e, __l, 4); \ break; \ default: __e = __get_user_bad(); break; \ } \ @@ -135,31 +146,34 @@ extern int __put_user_2(void *, unsigned int); extern int __put_user_4(void *, unsigned int); extern int __put_user_8(void *, unsigned long long); -#define __put_user_x(__r2,__p,__e,__s) \ +#define __put_user_x(__r2,__p,__e,__l,__s) \ __asm__ __volatile__ ( \ __asmeq("%0", "r0") __asmeq("%2", "r2") \ + __asmeq("%3", "r1") \ "bl __put_user_" #__s \ : "=&r" (__e) \ - : "0" (__p), "r" (__r2) \ + : "0" (__p), "r" (__r2), "r" (__l) \ : "ip", "lr", "cc") #define put_user(x,p) \ ({ \ + unsigned long __limit = current_thread_info()->addr_limit - 1; \ register const typeof(*(p)) __r2 asm("r2") = (x); \ register const typeof(*(p)) __user *__p asm("r0") = (p);\ + register unsigned long __l asm("r1") = __limit; \ register int __e asm("r0"); \ switch (sizeof(*(__p))) { \ case 1: \ - __put_user_x(__r2, __p, __e, 1); \ + __put_user_x(__r2, __p, __e, __l, 1); \ break; \ case 2: \ - __put_user_x(__r2, __p, __e, 2); \ + __put_user_x(__r2, __p, __e, __l, 2); \ break; \ case 4: \ - __put_user_x(__r2, __p, __e, 4); \ + __put_user_x(__r2, __p, __e, __l, 4); \ break; \ case 8: \ - __put_user_x(__r2, __p, __e, 8); \ + __put_user_x(__r2, __p, __e, __l, 8); \ break; \ default: __e = __put_user_bad(); break; \ } \ diff --git a/arch/arm/lib/getuser.S b/arch/arm/lib/getuser.S index 11093a7c3e32..9b06bb41fca6 100644 --- a/arch/arm/lib/getuser.S +++ b/arch/arm/lib/getuser.S @@ -16,8 +16,9 @@ * __get_user_X * * Inputs: r0 contains the address + * r1 contains the address limit, which must be preserved * Outputs: r0 is the error code - * r2, r3 contains the zero-extended value + * r2 contains the zero-extended value * lr corrupted * * No other registers must be altered. (see @@ -27,33 +28,39 @@ * Note also that it is intended that __get_user_bad is not global. */ #include +#include #include #include ENTRY(__get_user_1) + check_uaccess r0, 1, r1, r2, __get_user_bad 1: TUSER(ldrb) r2, [r0] mov r0, #0 mov pc, lr ENDPROC(__get_user_1) ENTRY(__get_user_2) -#ifdef CONFIG_THUMB2_KERNEL -2: TUSER(ldrb) r2, [r0] -3: TUSER(ldrb) r3, [r0, #1] + check_uaccess r0, 2, r1, r2, __get_user_bad +#ifdef CONFIG_CPU_USE_DOMAINS +rb .req ip +2: ldrbt r2, [r0], #1 +3: ldrbt rb, [r0], #0 #else -2: TUSER(ldrb) r2, [r0], #1 -3: TUSER(ldrb) r3, [r0] +rb .req r0 +2: ldrb r2, [r0] +3: ldrb rb, [r0, #1] #endif #ifndef __ARMEB__ - orr r2, r2, r3, lsl #8 + orr r2, r2, rb, lsl #8 #else - orr r2, r3, r2, lsl #8 + orr r2, rb, r2, lsl #8 #endif mov r0, #0 mov pc, lr ENDPROC(__get_user_2) ENTRY(__get_user_4) + check_uaccess r0, 4, r1, r2, __get_user_bad 4: TUSER(ldr) r2, [r0] mov r0, #0 mov pc, lr diff --git a/arch/arm/lib/putuser.S b/arch/arm/lib/putuser.S index 7db25990c589..3d73dcb959b0 100644 --- a/arch/arm/lib/putuser.S +++ b/arch/arm/lib/putuser.S @@ -16,6 +16,7 @@ * __put_user_X * * Inputs: r0 contains the address + * r1 contains the address limit, which must be preserved * r2, r3 contains the value * Outputs: r0 is the error code * lr corrupted @@ -27,16 +28,19 @@ * Note also that it is intended that __put_user_bad is not global. */ #include +#include #include #include ENTRY(__put_user_1) + check_uaccess r0, 1, r1, ip, __put_user_bad 1: TUSER(strb) r2, [r0] mov r0, #0 mov pc, lr ENDPROC(__put_user_1) ENTRY(__put_user_2) + check_uaccess r0, 2, r1, ip, __put_user_bad mov ip, r2, lsr #8 #ifdef CONFIG_THUMB2_KERNEL #ifndef __ARMEB__ @@ -60,12 +64,14 @@ ENTRY(__put_user_2) ENDPROC(__put_user_2) ENTRY(__put_user_4) + check_uaccess r0, 4, r1, ip, __put_user_bad 4: TUSER(str) r2, [r0] mov r0, #0 mov pc, lr ENDPROC(__put_user_4) ENTRY(__put_user_8) + check_uaccess r0, 8, r1, ip, __put_user_bad #ifdef CONFIG_THUMB2_KERNEL 5: TUSER(str) r2, [r0] 6: TUSER(str) r3, [r0, #4] -- cgit v1.2.3 From ad72907acd2943304c292ae36960bb66e6dc23c9 Mon Sep 17 00:00:00 2001 From: Will Deacon Date: Fri, 7 Sep 2012 18:24:10 +0100 Subject: ARM: 7528/1: uaccess: annotate [__]{get,put}_user functions with might_fault() The user access functions may generate a fault, resulting in invocation of a handler that may sleep. This patch annotates the accessors with might_fault() so that we print a warning if they are invoked from atomic context and help lockdep keep track of mmap_sem. Signed-off-by: Will Deacon Signed-off-by: Russell King --- arch/arm/include/asm/uaccess.h | 18 ++++++++++++++++-- 1 file changed, 16 insertions(+), 2 deletions(-) (limited to 'arch/arm') diff --git a/arch/arm/include/asm/uaccess.h b/arch/arm/include/asm/uaccess.h index 6f83ad6e4d3d..77bd79f2ffdb 100644 --- a/arch/arm/include/asm/uaccess.h +++ b/arch/arm/include/asm/uaccess.h @@ -118,7 +118,7 @@ extern int __get_user_4(void *); : "0" (__p), "r" (__l) \ : __GUP_CLOBBER_##__s) -#define get_user(x,p) \ +#define __get_user_check(x,p) \ ({ \ unsigned long __limit = current_thread_info()->addr_limit - 1; \ register const typeof(*(p)) __user *__p asm("r0") = (p);\ @@ -141,6 +141,12 @@ extern int __get_user_4(void *); __e; \ }) +#define get_user(x,p) \ + ({ \ + might_fault(); \ + __get_user_check(x,p); \ + }) + extern int __put_user_1(void *, unsigned int); extern int __put_user_2(void *, unsigned int); extern int __put_user_4(void *, unsigned int); @@ -155,7 +161,7 @@ extern int __put_user_8(void *, unsigned long long); : "0" (__p), "r" (__r2), "r" (__l) \ : "ip", "lr", "cc") -#define put_user(x,p) \ +#define __put_user_check(x,p) \ ({ \ unsigned long __limit = current_thread_info()->addr_limit - 1; \ register const typeof(*(p)) __r2 asm("r2") = (x); \ @@ -180,6 +186,12 @@ extern int __put_user_8(void *, unsigned long long); __e; \ }) +#define put_user(x,p) \ + ({ \ + might_fault(); \ + __put_user_check(x,p); \ + }) + #else /* CONFIG_MMU */ /* @@ -233,6 +245,7 @@ do { \ unsigned long __gu_addr = (unsigned long)(ptr); \ unsigned long __gu_val; \ __chk_user_ptr(ptr); \ + might_fault(); \ switch (sizeof(*(ptr))) { \ case 1: __get_user_asm_byte(__gu_val,__gu_addr,err); break; \ case 2: __get_user_asm_half(__gu_val,__gu_addr,err); break; \ @@ -314,6 +327,7 @@ do { \ unsigned long __pu_addr = (unsigned long)(ptr); \ __typeof__(*(ptr)) __pu_val = (x); \ __chk_user_ptr(ptr); \ + might_fault(); \ switch (sizeof(*(ptr))) { \ case 1: __put_user_asm_byte(__pu_val,__pu_addr,err); break; \ case 2: __put_user_asm_half(__pu_val,__pu_addr,err); break; \ -- cgit v1.2.3 From beafa0de3d3e0d0ece7638cded879815f359f1cb Mon Sep 17 00:00:00 2001 From: Will Deacon Date: Fri, 7 Sep 2012 18:24:53 +0100 Subject: ARM: 7529/1: delay: set loops_per_jiffy when moving to timer-based loop The delay functions may be called by some platforms between switching to the timer-based delay loop but before calibration. In this case, the initial loops_per_jiffy may not be suitable for the timer (although a compromise may be achievable) and delay times may be considered too inaccurate. This patch updates loops_per_jiffy when switching to the timer-based delay loop so that delays are consistent prior to calibration. Signed-off-by: Will Deacon Signed-off-by: Russell King --- arch/arm/lib/delay.c | 1 + 1 file changed, 1 insertion(+) (limited to 'arch/arm') diff --git a/arch/arm/lib/delay.c b/arch/arm/lib/delay.c index d6dacc69254e..395d5fbb8fa2 100644 --- a/arch/arm/lib/delay.c +++ b/arch/arm/lib/delay.c @@ -59,6 +59,7 @@ void __init init_current_timer_delay(unsigned long freq) { pr_info("Switching to timer-based delay loop\n"); lpj_fine = freq / HZ; + loops_per_jiffy = lpj_fine; arm_delay_ops.delay = __timer_delay; arm_delay_ops.const_udelay = __timer_const_udelay; arm_delay_ops.udelay = __timer_udelay; -- cgit v1.2.3 From f3d87524975f01b885fc3d009c6ab6afd0d00746 Mon Sep 17 00:00:00 2001 From: Thomas Petazzoni Date: Mon, 10 Sep 2012 16:14:16 +0200 Subject: arm: mm: fix DMA pool affiliation check The __free_from_pool() function was changed in e9da6e9905e639b0f842a244bc770b48ad0523e9. Unfortunately, the test that checks whether the provided (start,size) is within the DMA pool has been improperly modified. It used to be: if (start < coherent_head.vm_start || end > coherent_head.vm_end) Where coherent_head.vm_end was non-inclusive (i.e, it did not include the first byte after the pool). The test has been changed to: if (start < pool->vaddr || start > pool->vaddr + pool->size) So now pool->vaddr + pool->size is inclusive (i.e, it includes the first byte after the pool), so the test should be >= instead of >. This bug causes the following message when freeing the *first* DMA coherent buffer that has been allocated, because its virtual address is exactly equal to pool->vaddr + pool->size : WARNING: at /home/thomas/projets/linux-2.6/arch/arm/mm/dma-mapping.c:463 __free_from_pool+0xa4/0xc0() freeing wrong coherent size from pool Signed-off-by: Thomas Petazzoni Cc: Marek Szyprowski Cc: Russell King Cc: Lior Amsalem Cc: Maen Suleiman Cc: Tawfik Bayouk Cc: Shadi Ammouri Cc: Eran Ben-Avi Cc: Yehuda Yitschak Cc: Nadav Haklai [m.szyprowski: rebased onto v3.6-rc5 and resolved conflict] Signed-off-by: Marek Szyprowski --- arch/arm/mm/dma-mapping.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'arch/arm') diff --git a/arch/arm/mm/dma-mapping.c b/arch/arm/mm/dma-mapping.c index 051204fc4617..e59c4ab71bcb 100644 --- a/arch/arm/mm/dma-mapping.c +++ b/arch/arm/mm/dma-mapping.c @@ -489,7 +489,7 @@ static bool __in_atomic_pool(void *start, size_t size) void *pool_start = pool->vaddr; void *pool_end = pool->vaddr + pool->size; - if (start < pool_start || start > pool_end) + if (start < pool_start || start >= pool_end) return false; if (end <= pool_end) -- cgit v1.2.3 From 912bfe76528c287bc4812521b8d53366954b39a5 Mon Sep 17 00:00:00 2001 From: Fabio Estevam Date: Sun, 19 Aug 2012 14:05:59 -0300 Subject: ARM: clk-imx25: Fix SSI clock registration SSI block has two types of clock: ipg: bus clock, the clock needed for accessing registers. per: peripheral clock, the clock needed for generating the bit rate. Currently SSI driver only supports slave mode and only need to handle the ipg clock, because the peripheral clock comes from the master codec. Only register the ipg clock and do not register the peripheral clock for ssi. Signed-off-by: Fabio Estevam Signed-off-by: Sascha Hauer Cc: stable@vger.kernel.org --- arch/arm/mach-imx/clk-imx25.c | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) (limited to 'arch/arm') diff --git a/arch/arm/mach-imx/clk-imx25.c b/arch/arm/mach-imx/clk-imx25.c index fdd8cc87c9fe..4431a62fff5b 100644 --- a/arch/arm/mach-imx/clk-imx25.c +++ b/arch/arm/mach-imx/clk-imx25.c @@ -222,10 +222,8 @@ int __init mx25_clocks_init(void) clk_register_clkdev(clk[lcdc_ipg], "ipg", "imx-fb.0"); clk_register_clkdev(clk[lcdc_ahb], "ahb", "imx-fb.0"); clk_register_clkdev(clk[wdt_ipg], NULL, "imx2-wdt.0"); - clk_register_clkdev(clk[ssi1_ipg_per], "per", "imx-ssi.0"); - clk_register_clkdev(clk[ssi1_ipg], "ipg", "imx-ssi.0"); - clk_register_clkdev(clk[ssi2_ipg_per], "per", "imx-ssi.1"); - clk_register_clkdev(clk[ssi2_ipg], "ipg", "imx-ssi.1"); + clk_register_clkdev(clk[ssi1_ipg], NULL, "imx-ssi.0"); + clk_register_clkdev(clk[ssi2_ipg], NULL, "imx-ssi.1"); clk_register_clkdev(clk[esdhc1_ipg_per], "per", "sdhci-esdhc-imx25.0"); clk_register_clkdev(clk[esdhc1_ipg], "ipg", "sdhci-esdhc-imx25.0"); clk_register_clkdev(clk[esdhc1_ahb], "ahb", "sdhci-esdhc-imx25.0"); -- cgit v1.2.3 From 48540058612786d365602f3324ed97f9071092de Mon Sep 17 00:00:00 2001 From: Fabio Estevam Date: Mon, 20 Aug 2012 09:39:22 -0300 Subject: ARM: clk-imx35: Fix SSI clock registration SSI block has two types of clock: ipg: bus clock, the clock needed for accessing registers. per: peripheral clock, the clock needed for generating the bit rate. Currently SSI driver only supports slave mode and only need to handle the ipg clock, because the peripheral clock comes from the master codec. Only register the ipg clock and do not register the peripheral clock for ssi. Signed-off-by: Fabio Estevam Tested-by: Mark Brown Signed-off-by: Sascha Hauer Cc: stable@vger.kernel.org --- arch/arm/mach-imx/clk-imx35.c | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) (limited to 'arch/arm') diff --git a/arch/arm/mach-imx/clk-imx35.c b/arch/arm/mach-imx/clk-imx35.c index c6422fb10bae..65fb8bcd86cb 100644 --- a/arch/arm/mach-imx/clk-imx35.c +++ b/arch/arm/mach-imx/clk-imx35.c @@ -230,10 +230,8 @@ int __init mx35_clocks_init() clk_register_clkdev(clk[ipu_gate], NULL, "mx3_sdc_fb"); clk_register_clkdev(clk[owire_gate], NULL, "mxc_w1"); clk_register_clkdev(clk[sdma_gate], NULL, "imx35-sdma"); - clk_register_clkdev(clk[ipg], "ipg", "imx-ssi.0"); - clk_register_clkdev(clk[ssi1_div_post], "per", "imx-ssi.0"); - clk_register_clkdev(clk[ipg], "ipg", "imx-ssi.1"); - clk_register_clkdev(clk[ssi2_div_post], "per", "imx-ssi.1"); + clk_register_clkdev(clk[ssi1_gate], NULL, "imx-ssi.0"); + clk_register_clkdev(clk[ssi2_gate], NULL, "imx-ssi.1"); /* i.mx35 has the i.mx21 type uart */ clk_register_clkdev(clk[uart1_gate], "per", "imx21-uart.0"); clk_register_clkdev(clk[ipg], "ipg", "imx21-uart.0"); -- cgit v1.2.3 From e2187b940fa6f17c372f895ec7d7eec026341385 Mon Sep 17 00:00:00 2001 From: Laxman Dewangan Date: Thu, 16 Aug 2012 04:13:13 +0000 Subject: ARM: tegra: config: enable dmaengine based APB DMA driver Enable config for dmaengine based Tegra APB DMA driver and disable the legacy APB DMA driver (SYSTEM_DMA). [swarren: removed CONFIG_TEGRA_SYSTEM_DMA not set line, since the option is removed entirely in a later patch] Signed-off-by: Laxman Dewangan Signed-off-by: Stephen Warren --- arch/arm/configs/tegra_defconfig | 2 ++ 1 file changed, 2 insertions(+) (limited to 'arch/arm') diff --git a/arch/arm/configs/tegra_defconfig b/arch/arm/configs/tegra_defconfig index db2245353f0f..0d6bb738c6de 100644 --- a/arch/arm/configs/tegra_defconfig +++ b/arch/arm/configs/tegra_defconfig @@ -145,6 +145,8 @@ CONFIG_MMC_SDHCI_TEGRA=y CONFIG_RTC_CLASS=y CONFIG_RTC_DRV_EM3027=y CONFIG_RTC_DRV_TEGRA=y +CONFIG_DMADEVICES=y +CONFIG_TEGRA20_APB_DMA=y CONFIG_STAGING=y CONFIG_SENSORS_ISL29018=y CONFIG_SENSORS_ISL29028=y -- cgit v1.2.3 From b4c2696798daddee46e01f974251f4ca3d6588eb Mon Sep 17 00:00:00 2001 From: Laxman Dewangan Date: Thu, 16 Aug 2012 04:13:14 +0000 Subject: ARM: tegra: dma: remove legacy APB DMA driver Remove the legacy APB dma driver. The APB DMA support is moved to dmaengine based Tegra APB DMA driver. All clients are also moved to dmaengine based APB DMA driver. Signed-off-by: Laxman Dewangan Signed-off-by: Stephen Warren --- arch/arm/mach-tegra/Kconfig | 7 - arch/arm/mach-tegra/Makefile | 1 - arch/arm/mach-tegra/dma.c | 823 --------------------------------- arch/arm/mach-tegra/include/mach/dma.h | 97 ---- 4 files changed, 928 deletions(-) delete mode 100644 arch/arm/mach-tegra/dma.c (limited to 'arch/arm') diff --git a/arch/arm/mach-tegra/Kconfig b/arch/arm/mach-tegra/Kconfig index 9077aaa398d9..dddbc79c7bec 100644 --- a/arch/arm/mach-tegra/Kconfig +++ b/arch/arm/mach-tegra/Kconfig @@ -130,13 +130,6 @@ config TEGRA_DEBUG_UART_AUTO_SCRATCH endchoice -config TEGRA_SYSTEM_DMA - bool "Enable system DMA driver for NVIDIA Tegra SoCs" - default y - help - Adds system DMA functionality for NVIDIA Tegra SoCs, used by - several Tegra device drivers - config TEGRA_EMC_SCALING_ENABLE bool "Enable scaling the memory frequency" diff --git a/arch/arm/mach-tegra/Makefile b/arch/arm/mach-tegra/Makefile index c3d7303b9ac8..95c2ba9df389 100644 --- a/arch/arm/mach-tegra/Makefile +++ b/arch/arm/mach-tegra/Makefile @@ -18,7 +18,6 @@ obj-$(CONFIG_ARCH_TEGRA_3x_SOC) += tegra30_clocks.o obj-$(CONFIG_SMP) += platsmp.o headsmp.o obj-$(CONFIG_SMP) += reset.o obj-$(CONFIG_HOTPLUG_CPU) += hotplug.o -obj-$(CONFIG_TEGRA_SYSTEM_DMA) += dma.o obj-$(CONFIG_CPU_FREQ) += cpu-tegra.o obj-$(CONFIG_TEGRA_PCI) += pcie.o obj-$(CONFIG_USB_SUPPORT) += usb_phy.o diff --git a/arch/arm/mach-tegra/dma.c b/arch/arm/mach-tegra/dma.c deleted file mode 100644 index 29c5114d607c..000000000000 --- a/arch/arm/mach-tegra/dma.c +++ /dev/null @@ -1,823 +0,0 @@ -/* - * arch/arm/mach-tegra/dma.c - * - * System DMA driver for NVIDIA Tegra SoCs - * - * Copyright (c) 2008-2009, NVIDIA Corporation. - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for - * more details. - * - * You should have received a copy of the GNU General Public License along - * with this program; if not, write to the Free Software Foundation, Inc., - * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. - */ - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include "apbio.h" - -#define APB_DMA_GEN 0x000 -#define GEN_ENABLE (1<<31) - -#define APB_DMA_CNTRL 0x010 - -#define APB_DMA_IRQ_MASK 0x01c - -#define APB_DMA_IRQ_MASK_SET 0x020 - -#define APB_DMA_CHAN_CSR 0x000 -#define CSR_ENB (1<<31) -#define CSR_IE_EOC (1<<30) -#define CSR_HOLD (1<<29) -#define CSR_DIR (1<<28) -#define CSR_ONCE (1<<27) -#define CSR_FLOW (1<<21) -#define CSR_REQ_SEL_SHIFT 16 -#define CSR_WCOUNT_SHIFT 2 -#define CSR_WCOUNT_MASK 0xFFFC - -#define APB_DMA_CHAN_STA 0x004 -#define STA_BUSY (1<<31) -#define STA_ISE_EOC (1<<30) -#define STA_HALT (1<<29) -#define STA_PING_PONG (1<<28) -#define STA_COUNT_SHIFT 2 -#define STA_COUNT_MASK 0xFFFC - -#define APB_DMA_CHAN_AHB_PTR 0x010 - -#define APB_DMA_CHAN_AHB_SEQ 0x014 -#define AHB_SEQ_INTR_ENB (1<<31) -#define AHB_SEQ_BUS_WIDTH_SHIFT 28 -#define AHB_SEQ_BUS_WIDTH_MASK (0x7<list.next, typeof(*req), node); - - tegra_dma_dequeue_req(ch, req); - return; -} - -static void tegra_dma_stop(struct tegra_dma_channel *ch) -{ - u32 csr; - u32 status; - - csr = readl(ch->addr + APB_DMA_CHAN_CSR); - csr &= ~CSR_IE_EOC; - writel(csr, ch->addr + APB_DMA_CHAN_CSR); - - csr &= ~CSR_ENB; - writel(csr, ch->addr + APB_DMA_CHAN_CSR); - - status = readl(ch->addr + APB_DMA_CHAN_STA); - if (status & STA_ISE_EOC) - writel(status, ch->addr + APB_DMA_CHAN_STA); -} - -static int tegra_dma_cancel(struct tegra_dma_channel *ch) -{ - unsigned long irq_flags; - - spin_lock_irqsave(&ch->lock, irq_flags); - while (!list_empty(&ch->list)) - list_del(ch->list.next); - - tegra_dma_stop(ch); - - spin_unlock_irqrestore(&ch->lock, irq_flags); - return 0; -} - -static unsigned int get_channel_status(struct tegra_dma_channel *ch, - struct tegra_dma_req *req, bool is_stop_dma) -{ - void __iomem *addr = IO_ADDRESS(TEGRA_APB_DMA_BASE); - unsigned int status; - - if (is_stop_dma) { - /* - * STOP the DMA and get the transfer count. - * Getting the transfer count is tricky. - * - Globally disable DMA on all channels - * - Read the channel's status register to know the number - * of pending bytes to be transfered. - * - Stop the dma channel - * - Globally re-enable DMA to resume other transfers - */ - spin_lock(&enable_lock); - writel(0, addr + APB_DMA_GEN); - udelay(20); - status = readl(ch->addr + APB_DMA_CHAN_STA); - tegra_dma_stop(ch); - writel(GEN_ENABLE, addr + APB_DMA_GEN); - spin_unlock(&enable_lock); - if (status & STA_ISE_EOC) { - pr_err("Got Dma Int here clearing"); - writel(status, ch->addr + APB_DMA_CHAN_STA); - } - req->status = TEGRA_DMA_REQ_ERROR_ABORTED; - } else { - status = readl(ch->addr + APB_DMA_CHAN_STA); - } - return status; -} - -/* should be called with the channel lock held */ -static unsigned int dma_active_count(struct tegra_dma_channel *ch, - struct tegra_dma_req *req, unsigned int status) -{ - unsigned int to_transfer; - unsigned int req_transfer_count; - unsigned int bytes_transferred; - - to_transfer = ((status & STA_COUNT_MASK) >> STA_COUNT_SHIFT) + 1; - req_transfer_count = ch->req_transfer_count + 1; - bytes_transferred = req_transfer_count; - if (status & STA_BUSY) - bytes_transferred -= to_transfer; - /* - * In continuous transfer mode, DMA only tracks the count of the - * half DMA buffer. So, if the DMA already finished half the DMA - * then add the half buffer to the completed count. - */ - if (ch->mode & TEGRA_DMA_MODE_CONTINOUS) { - if (req->buffer_status == TEGRA_DMA_REQ_BUF_STATUS_HALF_FULL) - bytes_transferred += req_transfer_count; - if (status & STA_ISE_EOC) - bytes_transferred += req_transfer_count; - } - bytes_transferred *= 4; - return bytes_transferred; -} - -int tegra_dma_dequeue_req(struct tegra_dma_channel *ch, - struct tegra_dma_req *_req) -{ - unsigned int status; - struct tegra_dma_req *req = NULL; - int found = 0; - unsigned long irq_flags; - int stop = 0; - - spin_lock_irqsave(&ch->lock, irq_flags); - - if (list_entry(ch->list.next, struct tegra_dma_req, node) == _req) - stop = 1; - - list_for_each_entry(req, &ch->list, node) { - if (req == _req) { - list_del(&req->node); - found = 1; - break; - } - } - if (!found) { - spin_unlock_irqrestore(&ch->lock, irq_flags); - return 0; - } - - if (!stop) - goto skip_stop_dma; - - status = get_channel_status(ch, req, true); - req->bytes_transferred = dma_active_count(ch, req, status); - - if (!list_empty(&ch->list)) { - /* if the list is not empty, queue the next request */ - struct tegra_dma_req *next_req; - next_req = list_entry(ch->list.next, - typeof(*next_req), node); - tegra_dma_update_hw(ch, next_req); - } - -skip_stop_dma: - req->status = -TEGRA_DMA_REQ_ERROR_ABORTED; - - spin_unlock_irqrestore(&ch->lock, irq_flags); - - /* Callback should be called without any lock */ - req->complete(req); - return 0; -} -EXPORT_SYMBOL(tegra_dma_dequeue_req); - -bool tegra_dma_is_empty(struct tegra_dma_channel *ch) -{ - unsigned long irq_flags; - bool is_empty; - - spin_lock_irqsave(&ch->lock, irq_flags); - if (list_empty(&ch->list)) - is_empty = true; - else - is_empty = false; - spin_unlock_irqrestore(&ch->lock, irq_flags); - return is_empty; -} -EXPORT_SYMBOL(tegra_dma_is_empty); - -bool tegra_dma_is_req_inflight(struct tegra_dma_channel *ch, - struct tegra_dma_req *_req) -{ - unsigned long irq_flags; - struct tegra_dma_req *req; - - spin_lock_irqsave(&ch->lock, irq_flags); - list_for_each_entry(req, &ch->list, node) { - if (req == _req) { - spin_unlock_irqrestore(&ch->lock, irq_flags); - return true; - } - } - spin_unlock_irqrestore(&ch->lock, irq_flags); - return false; -} -EXPORT_SYMBOL(tegra_dma_is_req_inflight); - -int tegra_dma_enqueue_req(struct tegra_dma_channel *ch, - struct tegra_dma_req *req) -{ - unsigned long irq_flags; - struct tegra_dma_req *_req; - int start_dma = 0; - - if (req->size > NV_DMA_MAX_TRASFER_SIZE || - req->source_addr & 0x3 || req->dest_addr & 0x3) { - pr_err("Invalid DMA request for channel %d\n", ch->id); - return -EINVAL; - } - - spin_lock_irqsave(&ch->lock, irq_flags); - - list_for_each_entry(_req, &ch->list, node) { - if (req == _req) { - spin_unlock_irqrestore(&ch->lock, irq_flags); - return -EEXIST; - } - } - - req->bytes_transferred = 0; - req->status = 0; - req->buffer_status = 0; - if (list_empty(&ch->list)) - start_dma = 1; - - list_add_tail(&req->node, &ch->list); - - if (start_dma) - tegra_dma_update_hw(ch, req); - - spin_unlock_irqrestore(&ch->lock, irq_flags); - - return 0; -} -EXPORT_SYMBOL(tegra_dma_enqueue_req); - -struct tegra_dma_channel *tegra_dma_allocate_channel(int mode) -{ - int channel; - struct tegra_dma_channel *ch = NULL; - - if (!tegra_dma_initialized) - return NULL; - - mutex_lock(&tegra_dma_lock); - - /* first channel is the shared channel */ - if (mode & TEGRA_DMA_SHARED) { - channel = TEGRA_SYSTEM_DMA_CH_MIN; - } else { - channel = find_first_zero_bit(channel_usage, - ARRAY_SIZE(dma_channels)); - if (channel >= ARRAY_SIZE(dma_channels)) - goto out; - } - __set_bit(channel, channel_usage); - ch = &dma_channels[channel]; - ch->mode = mode; - -out: - mutex_unlock(&tegra_dma_lock); - return ch; -} -EXPORT_SYMBOL(tegra_dma_allocate_channel); - -void tegra_dma_free_channel(struct tegra_dma_channel *ch) -{ - if (ch->mode & TEGRA_DMA_SHARED) - return; - tegra_dma_cancel(ch); - mutex_lock(&tegra_dma_lock); - __clear_bit(ch->id, channel_usage); - mutex_unlock(&tegra_dma_lock); -} -EXPORT_SYMBOL(tegra_dma_free_channel); - -static void tegra_dma_update_hw_partial(struct tegra_dma_channel *ch, - struct tegra_dma_req *req) -{ - u32 apb_ptr; - u32 ahb_ptr; - - if (req->to_memory) { - apb_ptr = req->source_addr; - ahb_ptr = req->dest_addr; - } else { - apb_ptr = req->dest_addr; - ahb_ptr = req->source_addr; - } - writel(apb_ptr, ch->addr + APB_DMA_CHAN_APB_PTR); - writel(ahb_ptr, ch->addr + APB_DMA_CHAN_AHB_PTR); - - req->status = TEGRA_DMA_REQ_INFLIGHT; - return; -} - -static void tegra_dma_update_hw(struct tegra_dma_channel *ch, - struct tegra_dma_req *req) -{ - int ahb_addr_wrap; - int apb_addr_wrap; - int ahb_bus_width; - int apb_bus_width; - int index; - - u32 ahb_seq; - u32 apb_seq; - u32 ahb_ptr; - u32 apb_ptr; - u32 csr; - - csr = CSR_IE_EOC | CSR_FLOW; - ahb_seq = AHB_SEQ_INTR_ENB | AHB_SEQ_BURST_1; - apb_seq = 0; - - csr |= req->req_sel << CSR_REQ_SEL_SHIFT; - - /* One shot mode is always single buffered, - * continuous mode is always double buffered - * */ - if (ch->mode & TEGRA_DMA_MODE_ONESHOT) { - csr |= CSR_ONCE; - ch->req_transfer_count = (req->size >> 2) - 1; - } else { - ahb_seq |= AHB_SEQ_DBL_BUF; - - /* In double buffered mode, we set the size to half the - * requested size and interrupt when half the buffer - * is full */ - ch->req_transfer_count = (req->size >> 3) - 1; - } - - csr |= ch->req_transfer_count << CSR_WCOUNT_SHIFT; - - if (req->to_memory) { - apb_ptr = req->source_addr; - ahb_ptr = req->dest_addr; - - apb_addr_wrap = req->source_wrap; - ahb_addr_wrap = req->dest_wrap; - apb_bus_width = req->source_bus_width; - ahb_bus_width = req->dest_bus_width; - - } else { - csr |= CSR_DIR; - apb_ptr = req->dest_addr; - ahb_ptr = req->source_addr; - - apb_addr_wrap = req->dest_wrap; - ahb_addr_wrap = req->source_wrap; - apb_bus_width = req->dest_bus_width; - ahb_bus_width = req->source_bus_width; - } - - apb_addr_wrap >>= 2; - ahb_addr_wrap >>= 2; - - /* set address wrap for APB size */ - index = 0; - do { - if (apb_addr_wrap_table[index] == apb_addr_wrap) - break; - index++; - } while (index < ARRAY_SIZE(apb_addr_wrap_table)); - BUG_ON(index == ARRAY_SIZE(apb_addr_wrap_table)); - apb_seq |= index << APB_SEQ_WRAP_SHIFT; - - /* set address wrap for AHB size */ - index = 0; - do { - if (ahb_addr_wrap_table[index] == ahb_addr_wrap) - break; - index++; - } while (index < ARRAY_SIZE(ahb_addr_wrap_table)); - BUG_ON(index == ARRAY_SIZE(ahb_addr_wrap_table)); - ahb_seq |= index << AHB_SEQ_WRAP_SHIFT; - - for (index = 0; index < ARRAY_SIZE(bus_width_table); index++) { - if (bus_width_table[index] == ahb_bus_width) - break; - } - BUG_ON(index == ARRAY_SIZE(bus_width_table)); - ahb_seq |= index << AHB_SEQ_BUS_WIDTH_SHIFT; - - for (index = 0; index < ARRAY_SIZE(bus_width_table); index++) { - if (bus_width_table[index] == apb_bus_width) - break; - } - BUG_ON(index == ARRAY_SIZE(bus_width_table)); - apb_seq |= index << APB_SEQ_BUS_WIDTH_SHIFT; - - writel(csr, ch->addr + APB_DMA_CHAN_CSR); - writel(apb_seq, ch->addr + APB_DMA_CHAN_APB_SEQ); - writel(apb_ptr, ch->addr + APB_DMA_CHAN_APB_PTR); - writel(ahb_seq, ch->addr + APB_DMA_CHAN_AHB_SEQ); - writel(ahb_ptr, ch->addr + APB_DMA_CHAN_AHB_PTR); - - csr |= CSR_ENB; - writel(csr, ch->addr + APB_DMA_CHAN_CSR); - - req->status = TEGRA_DMA_REQ_INFLIGHT; -} - -static void handle_oneshot_dma(struct tegra_dma_channel *ch) -{ - struct tegra_dma_req *req; - unsigned long irq_flags; - - spin_lock_irqsave(&ch->lock, irq_flags); - if (list_empty(&ch->list)) { - spin_unlock_irqrestore(&ch->lock, irq_flags); - return; - } - - req = list_entry(ch->list.next, typeof(*req), node); - if (req) { - int bytes_transferred; - - bytes_transferred = ch->req_transfer_count; - bytes_transferred += 1; - bytes_transferred <<= 2; - - list_del(&req->node); - req->bytes_transferred = bytes_transferred; - req->status = TEGRA_DMA_REQ_SUCCESS; - - spin_unlock_irqrestore(&ch->lock, irq_flags); - /* Callback should be called without any lock */ - pr_debug("%s: transferred %d bytes\n", __func__, - req->bytes_transferred); - req->complete(req); - spin_lock_irqsave(&ch->lock, irq_flags); - } - - if (!list_empty(&ch->list)) { - req = list_entry(ch->list.next, typeof(*req), node); - /* the complete function we just called may have enqueued - another req, in which case dma has already started */ - if (req->status != TEGRA_DMA_REQ_INFLIGHT) - tegra_dma_update_hw(ch, req); - } - spin_unlock_irqrestore(&ch->lock, irq_flags); -} - -static void handle_continuous_dma(struct tegra_dma_channel *ch) -{ - struct tegra_dma_req *req; - unsigned long irq_flags; - - spin_lock_irqsave(&ch->lock, irq_flags); - if (list_empty(&ch->list)) { - spin_unlock_irqrestore(&ch->lock, irq_flags); - return; - } - - req = list_entry(ch->list.next, typeof(*req), node); - if (req) { - if (req->buffer_status == TEGRA_DMA_REQ_BUF_STATUS_EMPTY) { - bool is_dma_ping_complete; - is_dma_ping_complete = (readl(ch->addr + APB_DMA_CHAN_STA) - & STA_PING_PONG) ? true : false; - if (req->to_memory) - is_dma_ping_complete = !is_dma_ping_complete; - /* Out of sync - Release current buffer */ - if (!is_dma_ping_complete) { - int bytes_transferred; - - bytes_transferred = ch->req_transfer_count; - bytes_transferred += 1; - bytes_transferred <<= 3; - req->buffer_status = TEGRA_DMA_REQ_BUF_STATUS_FULL; - req->bytes_transferred = bytes_transferred; - req->status = TEGRA_DMA_REQ_SUCCESS; - tegra_dma_stop(ch); - - if (!list_is_last(&req->node, &ch->list)) { - struct tegra_dma_req *next_req; - - next_req = list_entry(req->node.next, - typeof(*next_req), node); - tegra_dma_update_hw(ch, next_req); - } - - list_del(&req->node); - - /* DMA lock is NOT held when callbak is called */ - spin_unlock_irqrestore(&ch->lock, irq_flags); - req->complete(req); - return; - } - /* Load the next request into the hardware, if available - * */ - if (!list_is_last(&req->node, &ch->list)) { - struct tegra_dma_req *next_req; - - next_req = list_entry(req->node.next, - typeof(*next_req), node); - tegra_dma_update_hw_partial(ch, next_req); - } - req->buffer_status = TEGRA_DMA_REQ_BUF_STATUS_HALF_FULL; - req->status = TEGRA_DMA_REQ_SUCCESS; - /* DMA lock is NOT held when callback is called */ - spin_unlock_irqrestore(&ch->lock, irq_flags); - if (likely(req->threshold)) - req->threshold(req); - return; - - } else if (req->buffer_status == - TEGRA_DMA_REQ_BUF_STATUS_HALF_FULL) { - /* Callback when the buffer is completely full (i.e on - * the second interrupt */ - int bytes_transferred; - - bytes_transferred = ch->req_transfer_count; - bytes_transferred += 1; - bytes_transferred <<= 3; - - req->buffer_status = TEGRA_DMA_REQ_BUF_STATUS_FULL; - req->bytes_transferred = bytes_transferred; - req->status = TEGRA_DMA_REQ_SUCCESS; - list_del(&req->node); - - /* DMA lock is NOT held when callbak is called */ - spin_unlock_irqrestore(&ch->lock, irq_flags); - req->complete(req); - return; - - } else { - BUG(); - } - } - spin_unlock_irqrestore(&ch->lock, irq_flags); -} - -static irqreturn_t dma_isr(int irq, void *data) -{ - struct tegra_dma_channel *ch = data; - unsigned long status; - - status = readl(ch->addr + APB_DMA_CHAN_STA); - if (status & STA_ISE_EOC) - writel(status, ch->addr + APB_DMA_CHAN_STA); - else { - pr_warning("Got a spurious ISR for DMA channel %d\n", ch->id); - return IRQ_HANDLED; - } - return IRQ_WAKE_THREAD; -} - -static irqreturn_t dma_thread_fn(int irq, void *data) -{ - struct tegra_dma_channel *ch = data; - - if (ch->mode & TEGRA_DMA_MODE_ONESHOT) - handle_oneshot_dma(ch); - else - handle_continuous_dma(ch); - - - return IRQ_HANDLED; -} - -int __init tegra_dma_init(void) -{ - int ret = 0; - int i; - unsigned int irq; - void __iomem *addr; - struct clk *c; - - bitmap_fill(channel_usage, NV_DMA_MAX_CHANNELS); - - c = clk_get_sys("tegra-apbdma", NULL); - if (IS_ERR(c)) { - pr_err("Unable to get clock for APB DMA\n"); - ret = PTR_ERR(c); - goto fail; - } - ret = clk_prepare_enable(c); - if (ret != 0) { - pr_err("Unable to enable clock for APB DMA\n"); - goto fail; - } - - addr = IO_ADDRESS(TEGRA_APB_DMA_BASE); - writel(GEN_ENABLE, addr + APB_DMA_GEN); - writel(0, addr + APB_DMA_CNTRL); - writel(0xFFFFFFFFul >> (31 - TEGRA_SYSTEM_DMA_CH_MAX), - addr + APB_DMA_IRQ_MASK_SET); - - for (i = TEGRA_SYSTEM_DMA_CH_MIN; i <= TEGRA_SYSTEM_DMA_CH_MAX; i++) { - struct tegra_dma_channel *ch = &dma_channels[i]; - - ch->id = i; - snprintf(ch->name, TEGRA_DMA_NAME_SIZE, "dma_channel_%d", i); - - ch->addr = IO_ADDRESS(TEGRA_APB_DMA_CH0_BASE + - TEGRA_APB_DMA_CH0_SIZE * i); - - spin_lock_init(&ch->lock); - INIT_LIST_HEAD(&ch->list); - - irq = INT_APB_DMA_CH0 + i; - ret = request_threaded_irq(irq, dma_isr, dma_thread_fn, 0, - dma_channels[i].name, ch); - if (ret) { - pr_err("Failed to register IRQ %d for DMA %d\n", - irq, i); - goto fail; - } - ch->irq = irq; - - __clear_bit(i, channel_usage); - } - /* mark the shared channel allocated */ - __set_bit(TEGRA_SYSTEM_DMA_CH_MIN, channel_usage); - - tegra_dma_initialized = true; - - return 0; -fail: - writel(0, addr + APB_DMA_GEN); - for (i = TEGRA_SYSTEM_DMA_CH_MIN; i <= TEGRA_SYSTEM_DMA_CH_MAX; i++) { - struct tegra_dma_channel *ch = &dma_channels[i]; - if (ch->irq) - free_irq(ch->irq, ch); - } - return ret; -} -postcore_initcall(tegra_dma_init); - -#ifdef CONFIG_PM -static u32 apb_dma[5*TEGRA_SYSTEM_DMA_CH_NR + 3]; - -void tegra_dma_suspend(void) -{ - void __iomem *addr = IO_ADDRESS(TEGRA_APB_DMA_BASE); - u32 *ctx = apb_dma; - int i; - - *ctx++ = readl(addr + APB_DMA_GEN); - *ctx++ = readl(addr + APB_DMA_CNTRL); - *ctx++ = readl(addr + APB_DMA_IRQ_MASK); - - for (i = 0; i < TEGRA_SYSTEM_DMA_CH_NR; i++) { - addr = IO_ADDRESS(TEGRA_APB_DMA_CH0_BASE + - TEGRA_APB_DMA_CH0_SIZE * i); - - *ctx++ = readl(addr + APB_DMA_CHAN_CSR); - *ctx++ = readl(addr + APB_DMA_CHAN_AHB_PTR); - *ctx++ = readl(addr + APB_DMA_CHAN_AHB_SEQ); - *ctx++ = readl(addr + APB_DMA_CHAN_APB_PTR); - *ctx++ = readl(addr + APB_DMA_CHAN_APB_SEQ); - } -} - -void tegra_dma_resume(void) -{ - void __iomem *addr = IO_ADDRESS(TEGRA_APB_DMA_BASE); - u32 *ctx = apb_dma; - int i; - - writel(*ctx++, addr + APB_DMA_GEN); - writel(*ctx++, addr + APB_DMA_CNTRL); - writel(*ctx++, addr + APB_DMA_IRQ_MASK); - - for (i = 0; i < TEGRA_SYSTEM_DMA_CH_NR; i++) { - addr = IO_ADDRESS(TEGRA_APB_DMA_CH0_BASE + - TEGRA_APB_DMA_CH0_SIZE * i); - - writel(*ctx++, addr + APB_DMA_CHAN_CSR); - writel(*ctx++, addr + APB_DMA_CHAN_AHB_PTR); - writel(*ctx++, addr + APB_DMA_CHAN_AHB_SEQ); - writel(*ctx++, addr + APB_DMA_CHAN_APB_PTR); - writel(*ctx++, addr + APB_DMA_CHAN_APB_SEQ); - } -} - -#endif diff --git a/arch/arm/mach-tegra/include/mach/dma.h b/arch/arm/mach-tegra/include/mach/dma.h index 9077092812c0..3081cc6dda3b 100644 --- a/arch/arm/mach-tegra/include/mach/dma.h +++ b/arch/arm/mach-tegra/include/mach/dma.h @@ -51,101 +51,4 @@ #define TEGRA_DMA_REQ_SEL_OWR 25 #define TEGRA_DMA_REQ_SEL_INVALID 31 -struct tegra_dma_req; -struct tegra_dma_channel; - -enum tegra_dma_mode { - TEGRA_DMA_SHARED = 1, - TEGRA_DMA_MODE_CONTINOUS = 2, - TEGRA_DMA_MODE_ONESHOT = 4, -}; - -enum tegra_dma_req_error { - TEGRA_DMA_REQ_SUCCESS = 0, - TEGRA_DMA_REQ_ERROR_ABORTED, - TEGRA_DMA_REQ_INFLIGHT, -}; - -enum tegra_dma_req_buff_status { - TEGRA_DMA_REQ_BUF_STATUS_EMPTY = 0, - TEGRA_DMA_REQ_BUF_STATUS_HALF_FULL, - TEGRA_DMA_REQ_BUF_STATUS_FULL, -}; - -struct tegra_dma_req { - struct list_head node; - unsigned int modid; - int instance; - - /* Called when the req is complete and from the DMA ISR context. - * When this is called the req structure is no longer queued by - * the DMA channel. - * - * State of the DMA depends on the number of req it has. If there are - * no DMA requests queued up, then it will STOP the DMA. It there are - * more requests in the DMA, then it will queue the next request. - */ - void (*complete)(struct tegra_dma_req *req); - - /* This is a called from the DMA ISR context when the DMA is still in - * progress and is actively filling same buffer. - * - * In case of continuous mode receive, this threshold is 1/2 the buffer - * size. In other cases, this will not even be called as there is no - * hardware support for it. - * - * In the case of continuous mode receive, if there is next req already - * queued, DMA programs the HW to use that req when this req is - * completed. If there is no "next req" queued, then DMA ISR doesn't do - * anything before calling this callback. - * - * This is mainly used by the cases, where the clients has queued - * only one req and want to get some sort of DMA threshold - * callback to program the next buffer. - * - */ - void (*threshold)(struct tegra_dma_req *req); - - /* 1 to copy to memory. - * 0 to copy from the memory to device FIFO */ - int to_memory; - - void *virt_addr; - - unsigned long source_addr; - unsigned long dest_addr; - unsigned long dest_wrap; - unsigned long source_wrap; - unsigned long source_bus_width; - unsigned long dest_bus_width; - unsigned long req_sel; - unsigned int size; - - /* Updated by the DMA driver on the conpletion of the request. */ - int bytes_transferred; - int status; - - /* DMA completion tracking information */ - int buffer_status; - - /* Client specific data */ - void *dev; -}; - -int tegra_dma_enqueue_req(struct tegra_dma_channel *ch, - struct tegra_dma_req *req); -int tegra_dma_dequeue_req(struct tegra_dma_channel *ch, - struct tegra_dma_req *req); -void tegra_dma_dequeue(struct tegra_dma_channel *ch); -void tegra_dma_flush(struct tegra_dma_channel *ch); - -bool tegra_dma_is_req_inflight(struct tegra_dma_channel *ch, - struct tegra_dma_req *req); -bool tegra_dma_is_empty(struct tegra_dma_channel *ch); - -struct tegra_dma_channel *tegra_dma_allocate_channel(int mode); -void tegra_dma_free_channel(struct tegra_dma_channel *ch); - -int __init tegra_dma_init(void); - #endif -- cgit v1.2.3 From 6a2473c51a29c4a5498a13db1a2357792d42b78b Mon Sep 17 00:00:00 2001 From: Laxman Dewangan Date: Thu, 16 Aug 2012 04:13:15 +0000 Subject: ARM: tegra: apbio: remove support of legacy DMA driver based access Remove the support code which uses the legacy APB DMA driver for accessing the apbio register. The driver will use the dmaengine based APB DMA driver for accessing apbio register. Signed-off-by: Laxman Dewangan Signed-off-by: Stephen Warren --- arch/arm/mach-tegra/apbio.c | 118 +------------------------------------------- 1 file changed, 1 insertion(+), 117 deletions(-) (limited to 'arch/arm') diff --git a/arch/arm/mach-tegra/apbio.c b/arch/arm/mach-tegra/apbio.c index dc0fe389be56..47d7d2c404a8 100644 --- a/arch/arm/mach-tegra/apbio.c +++ b/arch/arm/mach-tegra/apbio.c @@ -28,7 +28,7 @@ #include "apbio.h" -#if defined(CONFIG_TEGRA_SYSTEM_DMA) || defined(CONFIG_TEGRA20_APB_DMA) +#if defined(CONFIG_TEGRA20_APB_DMA) static DEFINE_MUTEX(tegra_apb_dma_lock); static u32 *tegra_apb_bb; static dma_addr_t tegra_apb_bb_phys; @@ -37,121 +37,6 @@ static DECLARE_COMPLETION(tegra_apb_wait); static u32 tegra_apb_readl_direct(unsigned long offset); static void tegra_apb_writel_direct(u32 value, unsigned long offset); -#if defined(CONFIG_TEGRA_SYSTEM_DMA) -static struct tegra_dma_channel *tegra_apb_dma; - -bool tegra_apb_init(void) -{ - struct tegra_dma_channel *ch; - - mutex_lock(&tegra_apb_dma_lock); - - /* Check to see if we raced to setup */ - if (tegra_apb_dma) - goto out; - - ch = tegra_dma_allocate_channel(TEGRA_DMA_MODE_ONESHOT | - TEGRA_DMA_SHARED); - - if (!ch) - goto out_fail; - - tegra_apb_bb = dma_alloc_coherent(NULL, sizeof(u32), - &tegra_apb_bb_phys, GFP_KERNEL); - if (!tegra_apb_bb) { - pr_err("%s: can not allocate bounce buffer\n", __func__); - tegra_dma_free_channel(ch); - goto out_fail; - } - - tegra_apb_dma = ch; -out: - mutex_unlock(&tegra_apb_dma_lock); - return true; - -out_fail: - mutex_unlock(&tegra_apb_dma_lock); - return false; -} - -static void apb_dma_complete(struct tegra_dma_req *req) -{ - complete(&tegra_apb_wait); -} - -static u32 tegra_apb_readl_using_dma(unsigned long offset) -{ - struct tegra_dma_req req; - int ret; - - if (!tegra_apb_dma && !tegra_apb_init()) - return tegra_apb_readl_direct(offset); - - mutex_lock(&tegra_apb_dma_lock); - req.complete = apb_dma_complete; - req.to_memory = 1; - req.dest_addr = tegra_apb_bb_phys; - req.dest_bus_width = 32; - req.dest_wrap = 1; - req.source_addr = offset; - req.source_bus_width = 32; - req.source_wrap = 4; - req.req_sel = TEGRA_DMA_REQ_SEL_CNTR; - req.size = 4; - - INIT_COMPLETION(tegra_apb_wait); - - tegra_dma_enqueue_req(tegra_apb_dma, &req); - - ret = wait_for_completion_timeout(&tegra_apb_wait, - msecs_to_jiffies(50)); - - if (WARN(ret == 0, "apb read dma timed out")) { - tegra_dma_dequeue_req(tegra_apb_dma, &req); - *(u32 *)tegra_apb_bb = 0; - } - - mutex_unlock(&tegra_apb_dma_lock); - return *((u32 *)tegra_apb_bb); -} - -static void tegra_apb_writel_using_dma(u32 value, unsigned long offset) -{ - struct tegra_dma_req req; - int ret; - - if (!tegra_apb_dma && !tegra_apb_init()) { - tegra_apb_writel_direct(value, offset); - return; - } - - mutex_lock(&tegra_apb_dma_lock); - *((u32 *)tegra_apb_bb) = value; - req.complete = apb_dma_complete; - req.to_memory = 0; - req.dest_addr = offset; - req.dest_wrap = 4; - req.dest_bus_width = 32; - req.source_addr = tegra_apb_bb_phys; - req.source_bus_width = 32; - req.source_wrap = 1; - req.req_sel = TEGRA_DMA_REQ_SEL_CNTR; - req.size = 4; - - INIT_COMPLETION(tegra_apb_wait); - - tegra_dma_enqueue_req(tegra_apb_dma, &req); - - ret = wait_for_completion_timeout(&tegra_apb_wait, - msecs_to_jiffies(50)); - - if (WARN(ret == 0, "apb write dma timed out")) - tegra_dma_dequeue_req(tegra_apb_dma, &req); - - mutex_unlock(&tegra_apb_dma_lock); -} - -#else static struct dma_chan *tegra_apb_dma_chan; static struct dma_slave_config dma_sconfig; @@ -279,7 +164,6 @@ static void tegra_apb_writel_using_dma(u32 value, unsigned long offset) pr_err("error in writing offset 0x%08lx using dma\n", offset); mutex_unlock(&tegra_apb_dma_lock); } -#endif #else #define tegra_apb_readl_using_dma tegra_apb_readl_direct #define tegra_apb_writel_using_dma tegra_apb_writel_direct -- cgit v1.2.3