diff options
-rw-r--r-- | arch/sh/mm/cache-sh2a.c | 6 | ||||
-rw-r--r-- | arch/sh/mm/cache-sh4.c | 61 | ||||
-rw-r--r-- | arch/sh/mm/cache-sh5.c | 29 | ||||
-rw-r--r-- | arch/sh/mm/cache-sh7705.c | 8 |
4 files changed, 71 insertions, 33 deletions
diff --git a/arch/sh/mm/cache-sh2a.c b/arch/sh/mm/cache-sh2a.c index d783361e3f0a..975899d83564 100644 --- a/arch/sh/mm/cache-sh2a.c +++ b/arch/sh/mm/cache-sh2a.c | |||
@@ -102,10 +102,12 @@ static void sh2a_flush_icache_range(void *args) | |||
102 | struct flusher_data *data = args; | 102 | struct flusher_data *data = args; |
103 | unsigned long start, end; | 103 | unsigned long start, end; |
104 | unsigned long v; | 104 | unsigned long v; |
105 | unsigned long flags; | ||
105 | 106 | ||
106 | start = data->addr1 & ~(L1_CACHE_BYTES-1); | 107 | start = data->addr1 & ~(L1_CACHE_BYTES-1); |
107 | end = (data->addr2 + L1_CACHE_BYTES-1) & ~(L1_CACHE_BYTES-1); | 108 | end = (data->addr2 + L1_CACHE_BYTES-1) & ~(L1_CACHE_BYTES-1); |
108 | 109 | ||
110 | local_irq_save(flags); | ||
109 | jump_to_uncached(); | 111 | jump_to_uncached(); |
110 | 112 | ||
111 | for (v = start; v < end; v+=L1_CACHE_BYTES) { | 113 | for (v = start; v < end; v+=L1_CACHE_BYTES) { |
@@ -120,10 +122,12 @@ static void sh2a_flush_icache_range(void *args) | |||
120 | } | 122 | } |
121 | } | 123 | } |
122 | /* I-Cache invalidate */ | 124 | /* I-Cache invalidate */ |
123 | ctrl_outl(addr, CACHE_IC_ADDRESS_ARRAY | addr | 0x00000008); | 125 | ctrl_outl(addr, |
126 | CACHE_IC_ADDRESS_ARRAY | addr | 0x00000008); | ||
124 | } | 127 | } |
125 | 128 | ||
126 | back_to_cached(); | 129 | back_to_cached(); |
130 | local_irq_restore(flags); | ||
127 | } | 131 | } |
128 | 132 | ||
129 | void __init sh2a_cache_init(void) | 133 | void __init sh2a_cache_init(void) |
diff --git a/arch/sh/mm/cache-sh4.c b/arch/sh/mm/cache-sh4.c index 70fb906419dd..3ac4945cb493 100644 --- a/arch/sh/mm/cache-sh4.c +++ b/arch/sh/mm/cache-sh4.c | |||
@@ -48,44 +48,48 @@ static void sh4_flush_icache_range(void *args) | |||
48 | struct flusher_data *data = args; | 48 | struct flusher_data *data = args; |
49 | int icacheaddr; | 49 | int icacheaddr; |
50 | unsigned long start, end; | 50 | unsigned long start, end; |
51 | unsigned long v; | 51 | unsigned long flags, v; |
52 | int i; | 52 | int i; |
53 | 53 | ||
54 | start = data->addr1; | 54 | start = data->addr1; |
55 | end = data->addr2; | 55 | end = data->addr2; |
56 | 56 | ||
57 | /* If there are too many pages then just blow the caches */ | 57 | /* If there are too many pages then just blow the caches */ |
58 | if (((end - start) >> PAGE_SHIFT) >= MAX_ICACHE_PAGES) { | 58 | if (((end - start) >> PAGE_SHIFT) >= MAX_ICACHE_PAGES) { |
59 | local_flush_cache_all(args); | 59 | local_flush_cache_all(args); |
60 | } else { | 60 | } else { |
61 | /* selectively flush d-cache then invalidate the i-cache */ | 61 | /* selectively flush d-cache then invalidate the i-cache */ |
62 | /* this is inefficient, so only use for small ranges */ | 62 | /* this is inefficient, so only use for small ranges */ |
63 | start &= ~(L1_CACHE_BYTES-1); | 63 | start &= ~(L1_CACHE_BYTES-1); |
64 | end += L1_CACHE_BYTES-1; | 64 | end += L1_CACHE_BYTES-1; |
65 | end &= ~(L1_CACHE_BYTES-1); | 65 | end &= ~(L1_CACHE_BYTES-1); |
66 | 66 | ||
67 | jump_to_uncached(); | 67 | local_irq_save(flags); |
68 | 68 | jump_to_uncached(); | |
69 | for (v = start; v < end; v+=L1_CACHE_BYTES) { | 69 | |
70 | __ocbwb(v); | 70 | for (v = start; v < end; v+=L1_CACHE_BYTES) { |
71 | 71 | asm volatile("ocbwb %0" | |
72 | icacheaddr = CACHE_IC_ADDRESS_ARRAY | | 72 | : /* no output */ |
73 | (v & cpu_data->icache.entry_mask); | 73 | : "m" (__m(v))); |
74 | 74 | ||
75 | for (i = 0; i < cpu_data->icache.ways; | 75 | icacheaddr = CACHE_IC_ADDRESS_ARRAY | ( |
76 | i++, icacheaddr += cpu_data->icache.way_incr) | 76 | v & cpu_data->icache.entry_mask); |
77 | /* Clear i-cache line valid-bit */ | 77 | |
78 | ctrl_outl(0, icacheaddr); | 78 | for (i = 0; i < cpu_data->icache.ways; |
79 | } | 79 | i++, icacheaddr += cpu_data->icache.way_incr) |
80 | /* Clear i-cache line valid-bit */ | ||
81 | ctrl_outl(0, icacheaddr); | ||
82 | } | ||
80 | 83 | ||
81 | back_to_cached(); | 84 | back_to_cached(); |
85 | local_irq_restore(flags); | ||
82 | } | 86 | } |
83 | } | 87 | } |
84 | 88 | ||
85 | static inline void flush_cache_4096(unsigned long start, | 89 | static inline void flush_cache_4096(unsigned long start, |
86 | unsigned long phys) | 90 | unsigned long phys) |
87 | { | 91 | { |
88 | unsigned long exec_offset = 0; | 92 | unsigned long flags, exec_offset = 0; |
89 | 93 | ||
90 | /* | 94 | /* |
91 | * All types of SH-4 require PC to be in P2 to operate on the I-cache. | 95 | * All types of SH-4 require PC to be in P2 to operate on the I-cache. |
@@ -95,8 +99,10 @@ static inline void flush_cache_4096(unsigned long start, | |||
95 | (start < CACHE_OC_ADDRESS_ARRAY)) | 99 | (start < CACHE_OC_ADDRESS_ARRAY)) |
96 | exec_offset = 0x20000000; | 100 | exec_offset = 0x20000000; |
97 | 101 | ||
102 | local_irq_save(flags); | ||
98 | __flush_cache_4096(start | SH_CACHE_ASSOC, | 103 | __flush_cache_4096(start | SH_CACHE_ASSOC, |
99 | P1SEGADDR(phys), exec_offset); | 104 | P1SEGADDR(phys), exec_offset); |
105 | local_irq_restore(flags); | ||
100 | } | 106 | } |
101 | 107 | ||
102 | /* | 108 | /* |
@@ -130,8 +136,9 @@ static void sh4_flush_dcache_page(void *arg) | |||
130 | /* TODO: Selective icache invalidation through IC address array.. */ | 136 | /* TODO: Selective icache invalidation through IC address array.. */ |
131 | static void __uses_jump_to_uncached flush_icache_all(void) | 137 | static void __uses_jump_to_uncached flush_icache_all(void) |
132 | { | 138 | { |
133 | unsigned long ccr; | 139 | unsigned long flags, ccr; |
134 | 140 | ||
141 | local_irq_save(flags); | ||
135 | jump_to_uncached(); | 142 | jump_to_uncached(); |
136 | 143 | ||
137 | /* Flush I-cache */ | 144 | /* Flush I-cache */ |
@@ -143,7 +150,9 @@ static void __uses_jump_to_uncached flush_icache_all(void) | |||
143 | * back_to_cached() will take care of the barrier for us, don't add | 150 | * back_to_cached() will take care of the barrier for us, don't add |
144 | * another one! | 151 | * another one! |
145 | */ | 152 | */ |
153 | |||
146 | back_to_cached(); | 154 | back_to_cached(); |
155 | local_irq_restore(flags); | ||
147 | } | 156 | } |
148 | 157 | ||
149 | static inline void flush_dcache_all(void) | 158 | static inline void flush_dcache_all(void) |
diff --git a/arch/sh/mm/cache-sh5.c b/arch/sh/mm/cache-sh5.c index 2f9dd6df00a6..467ff8e260f7 100644 --- a/arch/sh/mm/cache-sh5.c +++ b/arch/sh/mm/cache-sh5.c | |||
@@ -34,22 +34,28 @@ static inline void | |||
34 | sh64_setup_dtlb_cache_slot(unsigned long eaddr, unsigned long asid, | 34 | sh64_setup_dtlb_cache_slot(unsigned long eaddr, unsigned long asid, |
35 | unsigned long paddr) | 35 | unsigned long paddr) |
36 | { | 36 | { |
37 | local_irq_disable(); | ||
37 | sh64_setup_tlb_slot(dtlb_cache_slot, eaddr, asid, paddr); | 38 | sh64_setup_tlb_slot(dtlb_cache_slot, eaddr, asid, paddr); |
38 | } | 39 | } |
39 | 40 | ||
40 | static inline void sh64_teardown_dtlb_cache_slot(void) | 41 | static inline void sh64_teardown_dtlb_cache_slot(void) |
41 | { | 42 | { |
42 | sh64_teardown_tlb_slot(dtlb_cache_slot); | 43 | sh64_teardown_tlb_slot(dtlb_cache_slot); |
44 | local_irq_enable(); | ||
43 | } | 45 | } |
44 | 46 | ||
45 | static inline void sh64_icache_inv_all(void) | 47 | static inline void sh64_icache_inv_all(void) |
46 | { | 48 | { |
47 | unsigned long long addr, flag, data; | 49 | unsigned long long addr, flag, data; |
50 | unsigned long flags; | ||
48 | 51 | ||
49 | addr = ICCR0; | 52 | addr = ICCR0; |
50 | flag = ICCR0_ICI; | 53 | flag = ICCR0_ICI; |
51 | data = 0; | 54 | data = 0; |
52 | 55 | ||
56 | /* Make this a critical section for safety (probably not strictly necessary.) */ | ||
57 | local_irq_save(flags); | ||
58 | |||
53 | /* Without %1 it gets unexplicably wrong */ | 59 | /* Without %1 it gets unexplicably wrong */ |
54 | __asm__ __volatile__ ( | 60 | __asm__ __volatile__ ( |
55 | "getcfg %3, 0, %0\n\t" | 61 | "getcfg %3, 0, %0\n\t" |
@@ -58,6 +64,8 @@ static inline void sh64_icache_inv_all(void) | |||
58 | "synci" | 64 | "synci" |
59 | : "=&r" (data) | 65 | : "=&r" (data) |
60 | : "0" (data), "r" (flag), "r" (addr)); | 66 | : "0" (data), "r" (flag), "r" (addr)); |
67 | |||
68 | local_irq_restore(flags); | ||
61 | } | 69 | } |
62 | 70 | ||
63 | static void sh64_icache_inv_kernel_range(unsigned long start, unsigned long end) | 71 | static void sh64_icache_inv_kernel_range(unsigned long start, unsigned long end) |
@@ -82,6 +90,7 @@ static void sh64_icache_inv_user_page(struct vm_area_struct *vma, unsigned long | |||
82 | Also, eaddr is page-aligned. */ | 90 | Also, eaddr is page-aligned. */ |
83 | unsigned int cpu = smp_processor_id(); | 91 | unsigned int cpu = smp_processor_id(); |
84 | unsigned long long addr, end_addr; | 92 | unsigned long long addr, end_addr; |
93 | unsigned long flags = 0; | ||
85 | unsigned long running_asid, vma_asid; | 94 | unsigned long running_asid, vma_asid; |
86 | addr = eaddr; | 95 | addr = eaddr; |
87 | end_addr = addr + PAGE_SIZE; | 96 | end_addr = addr + PAGE_SIZE; |
@@ -102,9 +111,10 @@ static void sh64_icache_inv_user_page(struct vm_area_struct *vma, unsigned long | |||
102 | 111 | ||
103 | running_asid = get_asid(); | 112 | running_asid = get_asid(); |
104 | vma_asid = cpu_asid(cpu, vma->vm_mm); | 113 | vma_asid = cpu_asid(cpu, vma->vm_mm); |
105 | if (running_asid != vma_asid) | 114 | if (running_asid != vma_asid) { |
115 | local_irq_save(flags); | ||
106 | switch_and_save_asid(vma_asid); | 116 | switch_and_save_asid(vma_asid); |
107 | 117 | } | |
108 | while (addr < end_addr) { | 118 | while (addr < end_addr) { |
109 | /* Worth unrolling a little */ | 119 | /* Worth unrolling a little */ |
110 | __asm__ __volatile__("icbi %0, 0" : : "r" (addr)); | 120 | __asm__ __volatile__("icbi %0, 0" : : "r" (addr)); |
@@ -113,9 +123,10 @@ static void sh64_icache_inv_user_page(struct vm_area_struct *vma, unsigned long | |||
113 | __asm__ __volatile__("icbi %0, 96" : : "r" (addr)); | 123 | __asm__ __volatile__("icbi %0, 96" : : "r" (addr)); |
114 | addr += 128; | 124 | addr += 128; |
115 | } | 125 | } |
116 | 126 | if (running_asid != vma_asid) { | |
117 | if (running_asid != vma_asid) | ||
118 | switch_and_save_asid(running_asid); | 127 | switch_and_save_asid(running_asid); |
128 | local_irq_restore(flags); | ||
129 | } | ||
119 | } | 130 | } |
120 | 131 | ||
121 | static void sh64_icache_inv_user_page_range(struct mm_struct *mm, | 132 | static void sh64_icache_inv_user_page_range(struct mm_struct *mm, |
@@ -148,12 +159,16 @@ static void sh64_icache_inv_user_page_range(struct mm_struct *mm, | |||
148 | unsigned long eaddr; | 159 | unsigned long eaddr; |
149 | unsigned long after_last_page_start; | 160 | unsigned long after_last_page_start; |
150 | unsigned long mm_asid, current_asid; | 161 | unsigned long mm_asid, current_asid; |
162 | unsigned long flags = 0; | ||
151 | 163 | ||
152 | mm_asid = cpu_asid(smp_processor_id(), mm); | 164 | mm_asid = cpu_asid(smp_processor_id(), mm); |
153 | current_asid = get_asid(); | 165 | current_asid = get_asid(); |
154 | 166 | ||
155 | if (mm_asid != current_asid) | 167 | if (mm_asid != current_asid) { |
168 | /* Switch ASID and run the invalidate loop under cli */ | ||
169 | local_irq_save(flags); | ||
156 | switch_and_save_asid(mm_asid); | 170 | switch_and_save_asid(mm_asid); |
171 | } | ||
157 | 172 | ||
158 | aligned_start = start & PAGE_MASK; | 173 | aligned_start = start & PAGE_MASK; |
159 | after_last_page_start = PAGE_SIZE + ((end - 1) & PAGE_MASK); | 174 | after_last_page_start = PAGE_SIZE + ((end - 1) & PAGE_MASK); |
@@ -179,8 +194,10 @@ static void sh64_icache_inv_user_page_range(struct mm_struct *mm, | |||
179 | aligned_start = vma->vm_end; /* Skip to start of next region */ | 194 | aligned_start = vma->vm_end; /* Skip to start of next region */ |
180 | } | 195 | } |
181 | 196 | ||
182 | if (mm_asid != current_asid) | 197 | if (mm_asid != current_asid) { |
183 | switch_and_save_asid(current_asid); | 198 | switch_and_save_asid(current_asid); |
199 | local_irq_restore(flags); | ||
200 | } | ||
184 | } | 201 | } |
185 | } | 202 | } |
186 | 203 | ||
diff --git a/arch/sh/mm/cache-sh7705.c b/arch/sh/mm/cache-sh7705.c index 9dc38660e3de..6293f57fa888 100644 --- a/arch/sh/mm/cache-sh7705.c +++ b/arch/sh/mm/cache-sh7705.c | |||
@@ -81,6 +81,7 @@ static void sh7705_flush_icache_range(void *args) | |||
81 | static void __flush_dcache_page(unsigned long phys) | 81 | static void __flush_dcache_page(unsigned long phys) |
82 | { | 82 | { |
83 | unsigned long ways, waysize, addrstart; | 83 | unsigned long ways, waysize, addrstart; |
84 | unsigned long flags; | ||
84 | 85 | ||
85 | phys |= SH_CACHE_VALID; | 86 | phys |= SH_CACHE_VALID; |
86 | 87 | ||
@@ -97,6 +98,7 @@ static void __flush_dcache_page(unsigned long phys) | |||
97 | * potential cache aliasing, therefore the optimisation is probably not | 98 | * potential cache aliasing, therefore the optimisation is probably not |
98 | * possible. | 99 | * possible. |
99 | */ | 100 | */ |
101 | local_irq_save(flags); | ||
100 | jump_to_uncached(); | 102 | jump_to_uncached(); |
101 | 103 | ||
102 | ways = current_cpu_data.dcache.ways; | 104 | ways = current_cpu_data.dcache.ways; |
@@ -124,6 +126,7 @@ static void __flush_dcache_page(unsigned long phys) | |||
124 | } while (--ways); | 126 | } while (--ways); |
125 | 127 | ||
126 | back_to_cached(); | 128 | back_to_cached(); |
129 | local_irq_restore(flags); | ||
127 | } | 130 | } |
128 | 131 | ||
129 | /* | 132 | /* |
@@ -142,9 +145,14 @@ static void sh7705_flush_dcache_page(void *page) | |||
142 | 145 | ||
143 | static void sh7705_flush_cache_all(void *args) | 146 | static void sh7705_flush_cache_all(void *args) |
144 | { | 147 | { |
148 | unsigned long flags; | ||
149 | |||
150 | local_irq_save(flags); | ||
145 | jump_to_uncached(); | 151 | jump_to_uncached(); |
152 | |||
146 | cache_wback_all(); | 153 | cache_wback_all(); |
147 | back_to_cached(); | 154 | back_to_cached(); |
155 | local_irq_restore(flags); | ||
148 | } | 156 | } |
149 | 157 | ||
150 | /* | 158 | /* |