Commit 989d873f authored by Linus Torvalds's avatar Linus Torvalds

Merge master.kernel.org:/home/rmk/linux-2.6-arm

* master.kernel.org:/home/rmk/linux-2.6-arm:
  ARM: pxa: fix page table corruption on resume
  ARM: it8152: add IT8152_LAST_IRQ definition to fix build error
  ARM: pxa: PXA_ESERIES depends on FB_W100.
  ARM: 6605/1: Add missing include "asm/memory.h"
  ARM: 6540/1: Stop irqsoff trace on return to user
  ARM: 6537/1: update Nomadik, U300 and Ux500 maintainers
  ARM: 6536/1: Add missing SZ_{32,64,128}
  ARM: fix cache-feroceon-l2 after stack based kmap_atomic()
  ARM: fix cache-xsc3l2 after stack based kmap_atomic()
  ARM: get rid of kmap_high_l1_vipt()
  ARM: smp: avoid incrementing mm_users on CPU startup
  ARM: pxa: PXA_ESERIES depends on FB_W100.
parents d9a1abe4 04228460
...@@ -792,11 +792,14 @@ S: Maintained ...@@ -792,11 +792,14 @@ S: Maintained
ARM/NOMADIK ARCHITECTURE ARM/NOMADIK ARCHITECTURE
M: Alessandro Rubini <rubini@unipv.it> M: Alessandro Rubini <rubini@unipv.it>
M: Linus Walleij <linus.walleij@stericsson.com>
M: STEricsson <STEricsson_nomadik_linux@list.st.com> M: STEricsson <STEricsson_nomadik_linux@list.st.com>
L: linux-arm-kernel@lists.infradead.org (moderated for non-subscribers) L: linux-arm-kernel@lists.infradead.org (moderated for non-subscribers)
S: Maintained S: Maintained
F: arch/arm/mach-nomadik/ F: arch/arm/mach-nomadik/
F: arch/arm/plat-nomadik/ F: arch/arm/plat-nomadik/
F: drivers/i2c/busses/i2c-nomadik.c
T: git git://git.kernel.org/pub/scm/linux/kernel/git/linusw/linux-stericsson.git
ARM/OPENMOKO NEO FREERUNNER (GTA02) MACHINE SUPPORT ARM/OPENMOKO NEO FREERUNNER (GTA02) MACHINE SUPPORT
M: Nelson Castillo <arhuaco@freaks-unidos.net> M: Nelson Castillo <arhuaco@freaks-unidos.net>
...@@ -998,12 +1001,24 @@ F: drivers/i2c/busses/i2c-stu300.c ...@@ -998,12 +1001,24 @@ F: drivers/i2c/busses/i2c-stu300.c
F: drivers/rtc/rtc-coh901331.c F: drivers/rtc/rtc-coh901331.c
F: drivers/watchdog/coh901327_wdt.c F: drivers/watchdog/coh901327_wdt.c
F: drivers/dma/coh901318* F: drivers/dma/coh901318*
F: drivers/mfd/ab3100*
F: drivers/rtc/rtc-ab3100.c
F: drivers/rtc/rtc-coh901331.c
T: git git://git.kernel.org/pub/scm/linux/kernel/git/linusw/linux-stericsson.git
ARM/U8500 ARM ARCHITECTURE ARM/Ux500 ARM ARCHITECTURE
M: Srinidhi Kasagar <srinidhi.kasagar@stericsson.com> M: Srinidhi Kasagar <srinidhi.kasagar@stericsson.com>
M: Linus Walleij <linus.walleij@stericsson.com>
L: linux-arm-kernel@lists.infradead.org (moderated for non-subscribers) L: linux-arm-kernel@lists.infradead.org (moderated for non-subscribers)
S: Maintained S: Maintained
F: arch/arm/mach-ux500/ F: arch/arm/mach-ux500/
F: drivers/dma/ste_dma40*
F: drivers/mfd/ab3550*
F: drivers/mfd/abx500*
F: drivers/mfd/ab8500*
F: drivers/mfd/stmpe*
F: drivers/rtc/rtc-ab8500.c
T: git git://git.kernel.org/pub/scm/linux/kernel/git/linusw/linux-stericsson.git
ARM/VFP SUPPORT ARM/VFP SUPPORT
M: Russell King <linux@arm.linux.org.uk> M: Russell King <linux@arm.linux.org.uk>
......
...@@ -76,6 +76,7 @@ extern unsigned long it8152_base_address; ...@@ -76,6 +76,7 @@ extern unsigned long it8152_base_address;
IT8152_PD_IRQ(0) Audio controller (ACR) IT8152_PD_IRQ(0) Audio controller (ACR)
*/ */
#define IT8152_IRQ(x) (IRQ_BOARD_START + (x)) #define IT8152_IRQ(x) (IRQ_BOARD_START + (x))
#define IT8152_LAST_IRQ (IRQ_BOARD_START + 40)
/* IRQ-sources in 3 groups - local devices, LPC (serial), and external PCI */ /* IRQ-sources in 3 groups - local devices, LPC (serial), and external PCI */
#define IT8152_LD_IRQ_COUNT 9 #define IT8152_LD_IRQ_COUNT 9
......
...@@ -25,9 +25,6 @@ extern void *kmap_high(struct page *page); ...@@ -25,9 +25,6 @@ extern void *kmap_high(struct page *page);
extern void *kmap_high_get(struct page *page); extern void *kmap_high_get(struct page *page);
extern void kunmap_high(struct page *page); extern void kunmap_high(struct page *page);
extern void *kmap_high_l1_vipt(struct page *page, pte_t *saved_pte);
extern void kunmap_high_l1_vipt(struct page *page, pte_t saved_pte);
/* /*
* The following functions are already defined by <linux/highmem.h> * The following functions are already defined by <linux/highmem.h>
* when CONFIG_HIGHMEM is not set. * when CONFIG_HIGHMEM is not set.
......
...@@ -13,9 +13,6 @@ ...@@ -13,9 +13,6 @@
* along with this program; if not, write to the Free Software * along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/ */
/* DO NOT EDIT!! - this file automatically generated
* from .s file by awk -f s2h.awk
*/
/* Size definitions /* Size definitions
* Copyright (C) ARM Limited 1998. All rights reserved. * Copyright (C) ARM Limited 1998. All rights reserved.
*/ */
...@@ -25,6 +22,9 @@ ...@@ -25,6 +22,9 @@
/* handy sizes */ /* handy sizes */
#define SZ_16 0x00000010 #define SZ_16 0x00000010
#define SZ_32 0x00000020
#define SZ_64 0x00000040
#define SZ_128 0x00000080
#define SZ_256 0x00000100 #define SZ_256 0x00000100
#define SZ_512 0x00000200 #define SZ_512 0x00000200
......
...@@ -150,6 +150,7 @@ extern unsigned int user_debug; ...@@ -150,6 +150,7 @@ extern unsigned int user_debug;
#define rmb() dmb() #define rmb() dmb()
#define wmb() mb() #define wmb() mb()
#else #else
#include <asm/memory.h>
#define mb() do { if (arch_is_coherent()) dmb(); else barrier(); } while (0) #define mb() do { if (arch_is_coherent()) dmb(); else barrier(); } while (0)
#define rmb() do { if (arch_is_coherent()) dmb(); else barrier(); } while (0) #define rmb() do { if (arch_is_coherent()) dmb(); else barrier(); } while (0)
#define wmb() do { if (arch_is_coherent()) dmb(); else barrier(); } while (0) #define wmb() do { if (arch_is_coherent()) dmb(); else barrier(); } while (0)
......
...@@ -29,6 +29,9 @@ ret_fast_syscall: ...@@ -29,6 +29,9 @@ ret_fast_syscall:
ldr r1, [tsk, #TI_FLAGS] ldr r1, [tsk, #TI_FLAGS]
tst r1, #_TIF_WORK_MASK tst r1, #_TIF_WORK_MASK
bne fast_work_pending bne fast_work_pending
#if defined(CONFIG_IRQSOFF_TRACER)
asm_trace_hardirqs_on
#endif
/* perform architecture specific actions before user return */ /* perform architecture specific actions before user return */
arch_ret_to_user r1, lr arch_ret_to_user r1, lr
...@@ -65,6 +68,9 @@ ret_slow_syscall: ...@@ -65,6 +68,9 @@ ret_slow_syscall:
tst r1, #_TIF_WORK_MASK tst r1, #_TIF_WORK_MASK
bne work_pending bne work_pending
no_work_pending: no_work_pending:
#if defined(CONFIG_IRQSOFF_TRACER)
asm_trace_hardirqs_on
#endif
/* perform architecture specific actions before user return */ /* perform architecture specific actions before user return */
arch_ret_to_user r1, lr arch_ret_to_user r1, lr
......
...@@ -310,7 +310,6 @@ asmlinkage void __cpuinit secondary_start_kernel(void) ...@@ -310,7 +310,6 @@ asmlinkage void __cpuinit secondary_start_kernel(void)
* All kernel threads share the same mm context; grab a * All kernel threads share the same mm context; grab a
* reference and switch to it. * reference and switch to it.
*/ */
atomic_inc(&mm->mm_users);
atomic_inc(&mm->mm_count); atomic_inc(&mm->mm_count);
current->active_mm = mm; current->active_mm = mm;
cpumask_set_cpu(cpu, mm_cpumask(mm)); cpumask_set_cpu(cpu, mm_cpumask(mm));
......
...@@ -540,6 +540,7 @@ config MACH_ICONTROL ...@@ -540,6 +540,7 @@ config MACH_ICONTROL
config ARCH_PXA_ESERIES config ARCH_PXA_ESERIES
bool "PXA based Toshiba e-series PDAs" bool "PXA based Toshiba e-series PDAs"
select PXA25x select PXA25x
select FB_W100
config MACH_E330 config MACH_E330
bool "Toshiba e330" bool "Toshiba e330"
......
...@@ -353,8 +353,8 @@ resume_turn_on_mmu: ...@@ -353,8 +353,8 @@ resume_turn_on_mmu:
@ Let us ensure we jump to resume_after_mmu only when the mcr above @ Let us ensure we jump to resume_after_mmu only when the mcr above
@ actually took effect. They call it the "cpwait" operation. @ actually took effect. They call it the "cpwait" operation.
mrc p15, 0, r1, c2, c0, 0 @ queue a dependency on CP15 mrc p15, 0, r0, c2, c0, 0 @ queue a dependency on CP15
sub pc, r2, r1, lsr #32 @ jump to virtual addr sub pc, r2, r0, lsr #32 @ jump to virtual addr
nop nop
nop nop
nop nop
......
...@@ -13,13 +13,9 @@ ...@@ -13,13 +13,9 @@
*/ */
#include <linux/init.h> #include <linux/init.h>
#include <linux/highmem.h>
#include <asm/cacheflush.h> #include <asm/cacheflush.h>
#include <asm/kmap_types.h>
#include <asm/fixmap.h>
#include <asm/pgtable.h>
#include <asm/tlbflush.h>
#include <plat/cache-feroceon-l2.h> #include <plat/cache-feroceon-l2.h>
#include "mm.h"
/* /*
* Low-level cache maintenance operations. * Low-level cache maintenance operations.
...@@ -39,27 +35,30 @@ ...@@ -39,27 +35,30 @@
* between which we don't want to be preempted. * between which we don't want to be preempted.
*/ */
static inline unsigned long l2_start_va(unsigned long paddr) static inline unsigned long l2_get_va(unsigned long paddr)
{ {
#ifdef CONFIG_HIGHMEM #ifdef CONFIG_HIGHMEM
/* /*
* Let's do our own fixmap stuff in a minimal way here.
* Because range ops can't be done on physical addresses, * Because range ops can't be done on physical addresses,
* we simply install a virtual mapping for it only for the * we simply install a virtual mapping for it only for the
* TLB lookup to occur, hence no need to flush the untouched * TLB lookup to occur, hence no need to flush the untouched
* memory mapping. This is protected with the disabling of * memory mapping afterwards (note: a cache flush may happen
* interrupts by the caller. * in some circumstances depending on the path taken in kunmap_atomic).
*/ */
unsigned long idx = KM_L2_CACHE + KM_TYPE_NR * smp_processor_id(); void *vaddr = kmap_atomic_pfn(paddr >> PAGE_SHIFT);
unsigned long vaddr = __fix_to_virt(FIX_KMAP_BEGIN + idx); return (unsigned long)vaddr + (paddr & ~PAGE_MASK);
set_pte_ext(TOP_PTE(vaddr), pfn_pte(paddr >> PAGE_SHIFT, PAGE_KERNEL), 0);
local_flush_tlb_kernel_page(vaddr);
return vaddr + (paddr & ~PAGE_MASK);
#else #else
return __phys_to_virt(paddr); return __phys_to_virt(paddr);
#endif #endif
} }
static inline void l2_put_va(unsigned long vaddr)
{
#ifdef CONFIG_HIGHMEM
kunmap_atomic((void *)vaddr);
#endif
}
static inline void l2_clean_pa(unsigned long addr) static inline void l2_clean_pa(unsigned long addr)
{ {
__asm__("mcr p15, 1, %0, c15, c9, 3" : : "r" (addr)); __asm__("mcr p15, 1, %0, c15, c9, 3" : : "r" (addr));
...@@ -76,13 +75,14 @@ static inline void l2_clean_pa_range(unsigned long start, unsigned long end) ...@@ -76,13 +75,14 @@ static inline void l2_clean_pa_range(unsigned long start, unsigned long end)
*/ */
BUG_ON((start ^ end) >> PAGE_SHIFT); BUG_ON((start ^ end) >> PAGE_SHIFT);
raw_local_irq_save(flags); va_start = l2_get_va(start);
va_start = l2_start_va(start);
va_end = va_start + (end - start); va_end = va_start + (end - start);
raw_local_irq_save(flags);
__asm__("mcr p15, 1, %0, c15, c9, 4\n\t" __asm__("mcr p15, 1, %0, c15, c9, 4\n\t"
"mcr p15, 1, %1, c15, c9, 5" "mcr p15, 1, %1, c15, c9, 5"
: : "r" (va_start), "r" (va_end)); : : "r" (va_start), "r" (va_end));
raw_local_irq_restore(flags); raw_local_irq_restore(flags);
l2_put_va(va_start);
} }
static inline void l2_clean_inv_pa(unsigned long addr) static inline void l2_clean_inv_pa(unsigned long addr)
...@@ -106,13 +106,14 @@ static inline void l2_inv_pa_range(unsigned long start, unsigned long end) ...@@ -106,13 +106,14 @@ static inline void l2_inv_pa_range(unsigned long start, unsigned long end)
*/ */
BUG_ON((start ^ end) >> PAGE_SHIFT); BUG_ON((start ^ end) >> PAGE_SHIFT);
raw_local_irq_save(flags); va_start = l2_get_va(start);
va_start = l2_start_va(start);
va_end = va_start + (end - start); va_end = va_start + (end - start);
raw_local_irq_save(flags);
__asm__("mcr p15, 1, %0, c15, c11, 4\n\t" __asm__("mcr p15, 1, %0, c15, c11, 4\n\t"
"mcr p15, 1, %1, c15, c11, 5" "mcr p15, 1, %1, c15, c11, 5"
: : "r" (va_start), "r" (va_end)); : : "r" (va_start), "r" (va_end));
raw_local_irq_restore(flags); raw_local_irq_restore(flags);
l2_put_va(va_start);
} }
static inline void l2_inv_all(void) static inline void l2_inv_all(void)
......
...@@ -17,14 +17,10 @@ ...@@ -17,14 +17,10 @@
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/ */
#include <linux/init.h> #include <linux/init.h>
#include <linux/highmem.h>
#include <asm/system.h> #include <asm/system.h>
#include <asm/cputype.h> #include <asm/cputype.h>
#include <asm/cacheflush.h> #include <asm/cacheflush.h>
#include <asm/kmap_types.h>
#include <asm/fixmap.h>
#include <asm/pgtable.h>
#include <asm/tlbflush.h>
#include "mm.h"
#define CR_L2 (1 << 26) #define CR_L2 (1 << 26)
...@@ -71,16 +67,15 @@ static inline void xsc3_l2_inv_all(void) ...@@ -71,16 +67,15 @@ static inline void xsc3_l2_inv_all(void)
dsb(); dsb();
} }
static inline void l2_unmap_va(unsigned long va)
{
#ifdef CONFIG_HIGHMEM #ifdef CONFIG_HIGHMEM
#define l2_map_save_flags(x) raw_local_save_flags(x) if (va != -1)
#define l2_map_restore_flags(x) raw_local_irq_restore(x) kunmap_atomic((void *)va);
#else
#define l2_map_save_flags(x) ((x) = 0)
#define l2_map_restore_flags(x) ((void)(x))
#endif #endif
}
static inline unsigned long l2_map_va(unsigned long pa, unsigned long prev_va, static inline unsigned long l2_map_va(unsigned long pa, unsigned long prev_va)
unsigned long flags)
{ {
#ifdef CONFIG_HIGHMEM #ifdef CONFIG_HIGHMEM
unsigned long va = prev_va & PAGE_MASK; unsigned long va = prev_va & PAGE_MASK;
...@@ -89,17 +84,10 @@ static inline unsigned long l2_map_va(unsigned long pa, unsigned long prev_va, ...@@ -89,17 +84,10 @@ static inline unsigned long l2_map_va(unsigned long pa, unsigned long prev_va,
/* /*
* Switching to a new page. Because cache ops are * Switching to a new page. Because cache ops are
* using virtual addresses only, we must put a mapping * using virtual addresses only, we must put a mapping
* in place for it. We also enable interrupts for a * in place for it.
* short while and disable them again to protect this
* mapping.
*/ */
unsigned long idx; l2_unmap_va(prev_va);
raw_local_irq_restore(flags); va = (unsigned long)kmap_atomic_pfn(pa >> PAGE_SHIFT);
idx = KM_L2_CACHE + KM_TYPE_NR * smp_processor_id();
va = __fix_to_virt(FIX_KMAP_BEGIN + idx);
raw_local_irq_restore(flags | PSR_I_BIT);
set_pte_ext(TOP_PTE(va), pfn_pte(pa >> PAGE_SHIFT, PAGE_KERNEL), 0);
local_flush_tlb_kernel_page(va);
} }
return va + (pa_offset >> (32 - PAGE_SHIFT)); return va + (pa_offset >> (32 - PAGE_SHIFT));
#else #else
...@@ -109,7 +97,7 @@ static inline unsigned long l2_map_va(unsigned long pa, unsigned long prev_va, ...@@ -109,7 +97,7 @@ static inline unsigned long l2_map_va(unsigned long pa, unsigned long prev_va,
static void xsc3_l2_inv_range(unsigned long start, unsigned long end) static void xsc3_l2_inv_range(unsigned long start, unsigned long end)
{ {
unsigned long vaddr, flags; unsigned long vaddr;
if (start == 0 && end == -1ul) { if (start == 0 && end == -1ul) {
xsc3_l2_inv_all(); xsc3_l2_inv_all();
...@@ -117,13 +105,12 @@ static void xsc3_l2_inv_range(unsigned long start, unsigned long end) ...@@ -117,13 +105,12 @@ static void xsc3_l2_inv_range(unsigned long start, unsigned long end)
} }
vaddr = -1; /* to force the first mapping */ vaddr = -1; /* to force the first mapping */
l2_map_save_flags(flags);
/* /*
* Clean and invalidate partial first cache line. * Clean and invalidate partial first cache line.
*/ */
if (start & (CACHE_LINE_SIZE - 1)) { if (start & (CACHE_LINE_SIZE - 1)) {
vaddr = l2_map_va(start & ~(CACHE_LINE_SIZE - 1), vaddr, flags); vaddr = l2_map_va(start & ~(CACHE_LINE_SIZE - 1), vaddr);
xsc3_l2_clean_mva(vaddr); xsc3_l2_clean_mva(vaddr);
xsc3_l2_inv_mva(vaddr); xsc3_l2_inv_mva(vaddr);
start = (start | (CACHE_LINE_SIZE - 1)) + 1; start = (start | (CACHE_LINE_SIZE - 1)) + 1;
...@@ -133,7 +120,7 @@ static void xsc3_l2_inv_range(unsigned long start, unsigned long end) ...@@ -133,7 +120,7 @@ static void xsc3_l2_inv_range(unsigned long start, unsigned long end)
* Invalidate all full cache lines between 'start' and 'end'. * Invalidate all full cache lines between 'start' and 'end'.
*/ */
while (start < (end & ~(CACHE_LINE_SIZE - 1))) { while (start < (end & ~(CACHE_LINE_SIZE - 1))) {
vaddr = l2_map_va(start, vaddr, flags); vaddr = l2_map_va(start, vaddr);
xsc3_l2_inv_mva(vaddr); xsc3_l2_inv_mva(vaddr);
start += CACHE_LINE_SIZE; start += CACHE_LINE_SIZE;
} }
...@@ -142,31 +129,30 @@ static void xsc3_l2_inv_range(unsigned long start, unsigned long end) ...@@ -142,31 +129,30 @@ static void xsc3_l2_inv_range(unsigned long start, unsigned long end)
* Clean and invalidate partial last cache line. * Clean and invalidate partial last cache line.
*/ */
if (start < end) { if (start < end) {
vaddr = l2_map_va(start, vaddr, flags); vaddr = l2_map_va(start, vaddr);
xsc3_l2_clean_mva(vaddr); xsc3_l2_clean_mva(vaddr);
xsc3_l2_inv_mva(vaddr); xsc3_l2_inv_mva(vaddr);
} }
l2_map_restore_flags(flags); l2_unmap_va(vaddr);
dsb(); dsb();
} }
static void xsc3_l2_clean_range(unsigned long start, unsigned long end) static void xsc3_l2_clean_range(unsigned long start, unsigned long end)
{ {
unsigned long vaddr, flags; unsigned long vaddr;
vaddr = -1; /* to force the first mapping */ vaddr = -1; /* to force the first mapping */
l2_map_save_flags(flags);
start &= ~(CACHE_LINE_SIZE - 1); start &= ~(CACHE_LINE_SIZE - 1);
while (start < end) { while (start < end) {
vaddr = l2_map_va(start, vaddr, flags); vaddr = l2_map_va(start, vaddr);
xsc3_l2_clean_mva(vaddr); xsc3_l2_clean_mva(vaddr);
start += CACHE_LINE_SIZE; start += CACHE_LINE_SIZE;
} }
l2_map_restore_flags(flags); l2_unmap_va(vaddr);
dsb(); dsb();
} }
...@@ -193,7 +179,7 @@ static inline void xsc3_l2_flush_all(void) ...@@ -193,7 +179,7 @@ static inline void xsc3_l2_flush_all(void)
static void xsc3_l2_flush_range(unsigned long start, unsigned long end) static void xsc3_l2_flush_range(unsigned long start, unsigned long end)
{ {
unsigned long vaddr, flags; unsigned long vaddr;
if (start == 0 && end == -1ul) { if (start == 0 && end == -1ul) {
xsc3_l2_flush_all(); xsc3_l2_flush_all();
...@@ -201,17 +187,16 @@ static void xsc3_l2_flush_range(unsigned long start, unsigned long end) ...@@ -201,17 +187,16 @@ static void xsc3_l2_flush_range(unsigned long start, unsigned long end)
} }
vaddr = -1; /* to force the first mapping */ vaddr = -1; /* to force the first mapping */
l2_map_save_flags(flags);
start &= ~(CACHE_LINE_SIZE - 1); start &= ~(CACHE_LINE_SIZE - 1);
while (start < end) { while (start < end) {
vaddr = l2_map_va(start, vaddr, flags); vaddr = l2_map_va(start, vaddr);
xsc3_l2_clean_mva(vaddr); xsc3_l2_clean_mva(vaddr);
xsc3_l2_inv_mva(vaddr); xsc3_l2_inv_mva(vaddr);
start += CACHE_LINE_SIZE; start += CACHE_LINE_SIZE;
} }
l2_map_restore_flags(flags); l2_unmap_va(vaddr);
dsb(); dsb();
} }
......
...@@ -17,6 +17,7 @@ ...@@ -17,6 +17,7 @@
#include <linux/init.h> #include <linux/init.h>
#include <linux/device.h> #include <linux/device.h>
#include <linux/dma-mapping.h> #include <linux/dma-mapping.h>
#include <linux/highmem.h>
#include <asm/memory.h> #include <asm/memory.h>
#include <asm/highmem.h> #include <asm/highmem.h>
...@@ -480,10 +481,10 @@ static void dma_cache_maint_page(struct page *page, unsigned long offset, ...@@ -480,10 +481,10 @@ static void dma_cache_maint_page(struct page *page, unsigned long offset,
op(vaddr, len, dir); op(vaddr, len, dir);
kunmap_high(page); kunmap_high(page);
} else if (cache_is_vipt()) { } else if (cache_is_vipt()) {
pte_t saved_pte; /* unmapped pages might still be cached */
vaddr = kmap_high_l1_vipt(page, &saved_pte); vaddr = kmap_atomic(page);
op(vaddr + offset, len, dir); op(vaddr + offset, len, dir);
kunmap_high_l1_vipt(page, saved_pte); kunmap_atomic(vaddr);
} }
} else { } else {
vaddr = page_address(page) + offset; vaddr = page_address(page) + offset;
......
...@@ -10,6 +10,7 @@ ...@@ -10,6 +10,7 @@
#include <linux/module.h> #include <linux/module.h>
#include <linux/mm.h> #include <linux/mm.h>
#include <linux/pagemap.h> #include <linux/pagemap.h>
#include <linux/highmem.h>
#include <asm/cacheflush.h> #include <asm/cacheflush.h>
#include <asm/cachetype.h> #include <asm/cachetype.h>
...@@ -180,10 +181,10 @@ void __flush_dcache_page(struct address_space *mapping, struct page *page) ...@@ -180,10 +181,10 @@ void __flush_dcache_page(struct address_space *mapping, struct page *page)
__cpuc_flush_dcache_area(addr, PAGE_SIZE); __cpuc_flush_dcache_area(addr, PAGE_SIZE);
kunmap_high(page); kunmap_high(page);
} else if (cache_is_vipt()) { } else if (cache_is_vipt()) {
pte_t saved_pte; /* unmapped pages might still be cached */
addr = kmap_high_l1_vipt(page, &saved_pte); addr = kmap_atomic(page);
__cpuc_flush_dcache_area(addr, PAGE_SIZE); __cpuc_flush_dcache_area(addr, PAGE_SIZE);
kunmap_high_l1_vipt(page, saved_pte); kunmap_atomic(addr);
} }
} }
......
...@@ -140,90 +140,3 @@ struct page *kmap_atomic_to_page(const void *ptr) ...@@ -140,90 +140,3 @@ struct page *kmap_atomic_to_page(const void *ptr)
pte = TOP_PTE(vaddr); pte = TOP_PTE(vaddr);
return pte_page(*pte); return pte_page(*pte);
} }
#ifdef CONFIG_CPU_CACHE_VIPT
#include <linux/percpu.h>
/*
* The VIVT cache of a highmem page is always flushed before the page
* is unmapped. Hence unmapped highmem pages need no cache maintenance
* in that case.
*
* However unmapped pages may still be cached with a VIPT cache, and
* it is not possible to perform cache maintenance on them using physical
* addresses unfortunately. So we have no choice but to set up a temporary
* virtual mapping for that purpose.
*
* Yet this VIPT cache maintenance may be triggered from DMA support
* functions which are possibly called from interrupt context. As we don't
* want to keep interrupt disabled all the time when such maintenance is
* taking place, we therefore allow for some reentrancy by preserving and
* restoring the previous fixmap entry before the interrupted context is
* resumed. If the reentrancy depth is 0 then there is no need to restore
* the previous fixmap, and leaving the current one in place allow it to
* be reused the next time without a TLB flush (common with DMA).
*/
static DEFINE_PER_CPU(int, kmap_high_l1_vipt_depth);
void *kmap_high_l1_vipt(struct page *page, pte_t *saved_pte)
{
unsigned int idx, cpu;
int *depth;
unsigned long vaddr, flags;
pte_t pte, *ptep;
if (!in_interrupt())
preempt_disable();
cpu = smp_processor_id();
depth = &per_cpu(kmap_high_l1_vipt_depth, cpu);
idx = KM_L1_CACHE + KM_TYPE_NR * cpu;
vaddr = __fix_to_virt(FIX_KMAP_BEGIN + idx);
ptep = TOP_PTE(vaddr);
pte = mk_pte(page, kmap_prot);
raw_local_irq_save(flags);
(*depth)++;
if (pte_val(*ptep) == pte_val(pte)) {
*saved_pte = pte;
} else {
*saved_pte = *ptep;
set_pte_ext(ptep, pte, 0);
local_flush_tlb_kernel_page(vaddr);
}
raw_local_irq_restore(flags);
return (void *)vaddr;
}
void kunmap_high_l1_vipt(struct page *page, pte_t saved_pte)
{
unsigned int idx, cpu = smp_processor_id();
int *depth = &per_cpu(kmap_high_l1_vipt_depth, cpu);
unsigned long vaddr, flags;
pte_t pte, *ptep;
idx = KM_L1_CACHE + KM_TYPE_NR * cpu;
vaddr = __fix_to_virt(FIX_KMAP_BEGIN + idx);
ptep = TOP_PTE(vaddr);
pte = mk_pte(page, kmap_prot);
BUG_ON(pte_val(*ptep) != pte_val(pte));
BUG_ON(*depth <= 0);
raw_local_irq_save(flags);
(*depth)--;
if (*depth != 0 && pte_val(pte) != pte_val(saved_pte)) {
set_pte_ext(ptep, saved_pte, 0);
local_flush_tlb_kernel_page(vaddr);
}
raw_local_irq_restore(flags);
if (!in_interrupt())
preempt_enable();
}
#endif /* CONFIG_CPU_CACHE_VIPT */
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment