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 | |
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')
-rw-r--r-- | arch/sh/mm/cache-sh4.c | 11 | ||||
-rw-r--r-- | arch/sh/mm/pg-sh4.c | 75 |
2 files changed, 34 insertions, 52 deletions
diff --git a/arch/sh/mm/cache-sh4.c b/arch/sh/mm/cache-sh4.c index 981b04089055..5d0f73a4fbbb 100644 --- a/arch/sh/mm/cache-sh4.c +++ b/arch/sh/mm/cache-sh4.c | |||
@@ -77,16 +77,8 @@ static void __init emit_cache_params(void) | |||
77 | /* | 77 | /* |
78 | * SH-4 has virtually indexed and physically tagged cache. | 78 | * SH-4 has virtually indexed and physically tagged cache. |
79 | */ | 79 | */ |
80 | |||
81 | /* Worst case assumed to be 64k cache, direct-mapped i.e. 4 synonym bits. */ | ||
82 | #define MAX_P3_MUTEXES 16 | ||
83 | |||
84 | struct mutex p3map_mutex[MAX_P3_MUTEXES]; | ||
85 | |||
86 | void __init p3_cache_init(void) | 80 | void __init p3_cache_init(void) |
87 | { | 81 | { |
88 | int i; | ||
89 | |||
90 | compute_alias(¤t_cpu_data.icache); | 82 | compute_alias(¤t_cpu_data.icache); |
91 | compute_alias(¤t_cpu_data.dcache); | 83 | compute_alias(¤t_cpu_data.dcache); |
92 | 84 | ||
@@ -109,9 +101,6 @@ void __init p3_cache_init(void) | |||
109 | 101 | ||
110 | if (ioremap_page_range(P3SEG, P3SEG + (PAGE_SIZE * 4), 0, PAGE_KERNEL)) | 102 | if (ioremap_page_range(P3SEG, P3SEG + (PAGE_SIZE * 4), 0, PAGE_KERNEL)) |
111 | panic("%s failed.", __FUNCTION__); | 103 | panic("%s failed.", __FUNCTION__); |
112 | |||
113 | for (i = 0; i < current_cpu_data.dcache.n_aliases; i++) | ||
114 | mutex_init(&p3map_mutex[i]); | ||
115 | } | 104 | } |
116 | 105 | ||
117 | /* | 106 | /* |
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 | ||