diff options
author | Paul Mundt <lethal@linux-sh.org> | 2007-07-24 00:28:26 -0400 |
---|---|---|
committer | Paul Mundt <lethal@linux-sh.org> | 2007-07-24 00:28:26 -0400 |
commit | 8cf1a74305688c85fc8d23ab7432a0c447ee6413 (patch) | |
tree | d43af5f2515db35ef6a705e5929780f91d34e898 /arch/sh/mm/pg-sh4.c | |
parent | f695baf2df9e0413d3521661070103711545207a (diff) |
sh: Add kmap_coherent()/kunmap_coherent() interface for SH-4.
This wires up kmap_coherent() and kunmap_coherent() on SH-4, and
moves away from the p3map_mutex and reserved P3 space, opting to
use fixmaps for colouring instead.
The copy_user_page()/clear_user_page() implementations are moved
to this, which fixes the nasty blowups with spinlock debugging
as a result of having some of these calls nested under the page
table lock.
Signed-off-by: Paul Mundt <lethal@linux-sh.org>
Diffstat (limited to 'arch/sh/mm/pg-sh4.c')
-rw-r--r-- | arch/sh/mm/pg-sh4.c | 75 |
1 files changed, 34 insertions, 41 deletions
diff --git a/arch/sh/mm/pg-sh4.c b/arch/sh/mm/pg-sh4.c index df69da9ca69c..82b48e6a6239 100644 --- a/arch/sh/mm/pg-sh4.c +++ b/arch/sh/mm/pg-sh4.c | |||
@@ -2,7 +2,7 @@ | |||
2 | * arch/sh/mm/pg-sh4.c | 2 | * arch/sh/mm/pg-sh4.c |
3 | * | 3 | * |
4 | * Copyright (C) 1999, 2000, 2002 Niibe Yutaka | 4 | * Copyright (C) 1999, 2000, 2002 Niibe Yutaka |
5 | * Copyright (C) 2002 - 2005 Paul Mundt | 5 | * Copyright (C) 2002 - 2007 Paul Mundt |
6 | * | 6 | * |
7 | * Released under the terms of the GNU GPL v2.0. | 7 | * Released under the terms of the GNU GPL v2.0. |
8 | */ | 8 | */ |
@@ -11,10 +11,35 @@ | |||
11 | #include <asm/mmu_context.h> | 11 | #include <asm/mmu_context.h> |
12 | #include <asm/cacheflush.h> | 12 | #include <asm/cacheflush.h> |
13 | 13 | ||
14 | extern struct mutex p3map_mutex[]; | ||
15 | |||
16 | #define CACHE_ALIAS (current_cpu_data.dcache.alias_mask) | 14 | #define CACHE_ALIAS (current_cpu_data.dcache.alias_mask) |
17 | 15 | ||
16 | static inline void *kmap_coherent(struct page *page, unsigned long addr) | ||
17 | { | ||
18 | enum fixed_addresses idx; | ||
19 | unsigned long vaddr, flags; | ||
20 | pte_t pte; | ||
21 | |||
22 | inc_preempt_count(); | ||
23 | |||
24 | idx = (addr & current_cpu_data.dcache.alias_mask) >> PAGE_SHIFT; | ||
25 | vaddr = __fix_to_virt(FIX_CMAP_END - idx); | ||
26 | pte = mk_pte(page, PAGE_KERNEL); | ||
27 | |||
28 | local_irq_save(flags); | ||
29 | flush_tlb_one(get_asid(), vaddr); | ||
30 | local_irq_restore(flags); | ||
31 | |||
32 | update_mmu_cache(NULL, vaddr, pte); | ||
33 | |||
34 | return (void *)vaddr; | ||
35 | } | ||
36 | |||
37 | static inline void kunmap_coherent(struct page *page) | ||
38 | { | ||
39 | dec_preempt_count(); | ||
40 | preempt_check_resched(); | ||
41 | } | ||
42 | |||
18 | /* | 43 | /* |
19 | * clear_user_page | 44 | * clear_user_page |
20 | * @to: P1 address | 45 | * @to: P1 address |
@@ -27,25 +52,9 @@ void clear_user_page(void *to, unsigned long address, struct page *page) | |||
27 | if (((address ^ (unsigned long)to) & CACHE_ALIAS) == 0) | 52 | if (((address ^ (unsigned long)to) & CACHE_ALIAS) == 0) |
28 | clear_page(to); | 53 | clear_page(to); |
29 | else { | 54 | else { |
30 | unsigned long phys_addr = PHYSADDR(to); | 55 | void *vto = kmap_coherent(page, address); |
31 | unsigned long p3_addr = P3SEG + (address & CACHE_ALIAS); | 56 | __clear_user_page(vto, to); |
32 | pgd_t *pgd = pgd_offset_k(p3_addr); | 57 | kunmap_coherent(vto); |
33 | pud_t *pud = pud_offset(pgd, p3_addr); | ||
34 | pmd_t *pmd = pmd_offset(pud, p3_addr); | ||
35 | pte_t *pte = pte_offset_kernel(pmd, p3_addr); | ||
36 | pte_t entry; | ||
37 | unsigned long flags; | ||
38 | |||
39 | entry = pfn_pte(phys_addr >> PAGE_SHIFT, PAGE_KERNEL); | ||
40 | mutex_lock(&p3map_mutex[(address & CACHE_ALIAS)>>12]); | ||
41 | set_pte(pte, entry); | ||
42 | local_irq_save(flags); | ||
43 | flush_tlb_one(get_asid(), p3_addr); | ||
44 | local_irq_restore(flags); | ||
45 | update_mmu_cache(NULL, p3_addr, entry); | ||
46 | __clear_user_page((void *)p3_addr, to); | ||
47 | pte_clear(&init_mm, p3_addr, pte); | ||
48 | mutex_unlock(&p3map_mutex[(address & CACHE_ALIAS)>>12]); | ||
49 | } | 58 | } |
50 | } | 59 | } |
51 | 60 | ||
@@ -63,25 +72,9 @@ void copy_user_page(void *to, void *from, unsigned long address, | |||
63 | if (((address ^ (unsigned long)to) & CACHE_ALIAS) == 0) | 72 | if (((address ^ (unsigned long)to) & CACHE_ALIAS) == 0) |
64 | copy_page(to, from); | 73 | copy_page(to, from); |
65 | else { | 74 | else { |
66 | unsigned long phys_addr = PHYSADDR(to); | 75 | void *vfrom = kmap_coherent(page, address); |
67 | unsigned long p3_addr = P3SEG + (address & CACHE_ALIAS); | 76 | __copy_user_page(vfrom, from, to); |
68 | pgd_t *pgd = pgd_offset_k(p3_addr); | 77 | kunmap_coherent(vfrom); |
69 | pud_t *pud = pud_offset(pgd, p3_addr); | ||
70 | pmd_t *pmd = pmd_offset(pud, p3_addr); | ||
71 | pte_t *pte = pte_offset_kernel(pmd, p3_addr); | ||
72 | pte_t entry; | ||
73 | unsigned long flags; | ||
74 | |||
75 | entry = pfn_pte(phys_addr >> PAGE_SHIFT, PAGE_KERNEL); | ||
76 | mutex_lock(&p3map_mutex[(address & CACHE_ALIAS)>>12]); | ||
77 | set_pte(pte, entry); | ||
78 | local_irq_save(flags); | ||
79 | flush_tlb_one(get_asid(), p3_addr); | ||
80 | local_irq_restore(flags); | ||
81 | update_mmu_cache(NULL, p3_addr, entry); | ||
82 | __copy_user_page((void *)p3_addr, from, to); | ||
83 | pte_clear(&init_mm, p3_addr, pte); | ||
84 | mutex_unlock(&p3map_mutex[(address & CACHE_ALIAS)>>12]); | ||
85 | } | 78 | } |
86 | } | 79 | } |
87 | 80 | ||