diff options
author | Ralf Baechle <ralf@linux-mips.org> | 2006-04-05 15:42:04 -0400 |
---|---|---|
committer | Ralf Baechle <ralf@linux-mips.org> | 2006-04-18 22:14:29 -0400 |
commit | 7e3bfc7cfc402458b0386086ab650ce811720927 (patch) | |
tree | d7512049fad83d13a909a9ad8085c33f9d44b13f | |
parent | bb12d612d4b2e6dc260fab081f69df783b74289f (diff) |
[MIPS] Handle IDE PIO cache aliases on SMP.
Signed-off-by: Ralf Baechle <ralf@linux-mips.org>
-rw-r--r-- | arch/mips/mm/c-r3k.c | 5 | ||||
-rw-r--r-- | arch/mips/mm/c-r4k.c | 1 | ||||
-rw-r--r-- | arch/mips/mm/c-sb1.c | 1 | ||||
-rw-r--r-- | arch/mips/mm/c-tx39.c | 7 | ||||
-rw-r--r-- | arch/mips/mm/cache.c | 1 | ||||
-rw-r--r-- | include/asm-mips/cacheflush.h | 1 | ||||
-rw-r--r-- | include/asm-mips/mach-generic/ide.h | 46 |
7 files changed, 60 insertions, 2 deletions
diff --git a/arch/mips/mm/c-r3k.c b/arch/mips/mm/c-r3k.c index 9dd1352d5748..bb041a22f20a 100644 --- a/arch/mips/mm/c-r3k.c +++ b/arch/mips/mm/c-r3k.c | |||
@@ -260,6 +260,10 @@ static void r3k_flush_cache_page(struct vm_area_struct *vma, unsigned long page, | |||
260 | { | 260 | { |
261 | } | 261 | } |
262 | 262 | ||
263 | static void local_r3k_flush_data_cache_page(unsigned long addr) | ||
264 | { | ||
265 | } | ||
266 | |||
263 | static void r3k_flush_data_cache_page(unsigned long addr) | 267 | static void r3k_flush_data_cache_page(unsigned long addr) |
264 | { | 268 | { |
265 | } | 269 | } |
@@ -335,6 +339,7 @@ void __init r3k_cache_init(void) | |||
335 | flush_icache_range = r3k_flush_icache_range; | 339 | flush_icache_range = r3k_flush_icache_range; |
336 | 340 | ||
337 | flush_cache_sigtramp = r3k_flush_cache_sigtramp; | 341 | flush_cache_sigtramp = r3k_flush_cache_sigtramp; |
342 | local_flush_data_cache_page = local_r3k_flush_data_cache_page; | ||
338 | flush_data_cache_page = r3k_flush_data_cache_page; | 343 | flush_data_cache_page = r3k_flush_data_cache_page; |
339 | 344 | ||
340 | _dma_cache_wback_inv = r3k_dma_cache_wback_inv; | 345 | _dma_cache_wback_inv = r3k_dma_cache_wback_inv; |
diff --git a/arch/mips/mm/c-r4k.c b/arch/mips/mm/c-r4k.c index c4c208449d87..d88c6686413a 100644 --- a/arch/mips/mm/c-r4k.c +++ b/arch/mips/mm/c-r4k.c | |||
@@ -1199,6 +1199,7 @@ void __init r4k_cache_init(void) | |||
1199 | 1199 | ||
1200 | flush_cache_sigtramp = r4k_flush_cache_sigtramp; | 1200 | flush_cache_sigtramp = r4k_flush_cache_sigtramp; |
1201 | flush_icache_all = r4k_flush_icache_all; | 1201 | flush_icache_all = r4k_flush_icache_all; |
1202 | local_flush_data_cache_page = local_r4k_flush_data_cache_page; | ||
1202 | flush_data_cache_page = r4k_flush_data_cache_page; | 1203 | flush_data_cache_page = r4k_flush_data_cache_page; |
1203 | flush_icache_range = r4k_flush_icache_range; | 1204 | flush_icache_range = r4k_flush_icache_range; |
1204 | 1205 | ||
diff --git a/arch/mips/mm/c-sb1.c b/arch/mips/mm/c-sb1.c index 2f08b535f20e..f9b129491b1e 100644 --- a/arch/mips/mm/c-sb1.c +++ b/arch/mips/mm/c-sb1.c | |||
@@ -528,6 +528,7 @@ void sb1_cache_init(void) | |||
528 | flush_cache_page = sb1_flush_cache_page; | 528 | flush_cache_page = sb1_flush_cache_page; |
529 | 529 | ||
530 | flush_cache_sigtramp = sb1_flush_cache_sigtramp; | 530 | flush_cache_sigtramp = sb1_flush_cache_sigtramp; |
531 | local_flush_data_cache_page = (void *) sb1_nop; | ||
531 | flush_data_cache_page = (void *) sb1_nop; | 532 | flush_data_cache_page = (void *) sb1_nop; |
532 | 533 | ||
533 | /* Full flush */ | 534 | /* Full flush */ |
diff --git a/arch/mips/mm/c-tx39.c b/arch/mips/mm/c-tx39.c index fe232e3988e3..5dfc9b1901f6 100644 --- a/arch/mips/mm/c-tx39.c +++ b/arch/mips/mm/c-tx39.c | |||
@@ -216,6 +216,11 @@ static void tx39_flush_cache_page(struct vm_area_struct *vma, unsigned long page | |||
216 | tx39_blast_icache_page_indexed(page); | 216 | tx39_blast_icache_page_indexed(page); |
217 | } | 217 | } |
218 | 218 | ||
219 | static void local_tx39_flush_data_cache_page(void * addr) | ||
220 | { | ||
221 | tx39_blast_dcache_page(addr); | ||
222 | } | ||
223 | |||
219 | static void tx39_flush_data_cache_page(unsigned long addr) | 224 | static void tx39_flush_data_cache_page(unsigned long addr) |
220 | { | 225 | { |
221 | tx39_blast_dcache_page(addr); | 226 | tx39_blast_dcache_page(addr); |
@@ -381,6 +386,7 @@ void __init tx39_cache_init(void) | |||
381 | flush_icache_range = (void *) tx39h_flush_icache_all; | 386 | flush_icache_range = (void *) tx39h_flush_icache_all; |
382 | 387 | ||
383 | flush_cache_sigtramp = (void *) tx39h_flush_icache_all; | 388 | flush_cache_sigtramp = (void *) tx39h_flush_icache_all; |
389 | local_flush_data_cache_page = (void *) tx39h_flush_icache_all; | ||
384 | flush_data_cache_page = (void *) tx39h_flush_icache_all; | 390 | flush_data_cache_page = (void *) tx39h_flush_icache_all; |
385 | 391 | ||
386 | _dma_cache_wback_inv = tx39h_dma_cache_wback_inv; | 392 | _dma_cache_wback_inv = tx39h_dma_cache_wback_inv; |
@@ -406,6 +412,7 @@ void __init tx39_cache_init(void) | |||
406 | flush_icache_range = tx39_flush_icache_range; | 412 | flush_icache_range = tx39_flush_icache_range; |
407 | 413 | ||
408 | flush_cache_sigtramp = tx39_flush_cache_sigtramp; | 414 | flush_cache_sigtramp = tx39_flush_cache_sigtramp; |
415 | local_flush_data_cache_page = local_tx39_flush_data_cache_page; | ||
409 | flush_data_cache_page = tx39_flush_data_cache_page; | 416 | flush_data_cache_page = tx39_flush_data_cache_page; |
410 | 417 | ||
411 | _dma_cache_wback_inv = tx39_dma_cache_wback_inv; | 418 | _dma_cache_wback_inv = tx39_dma_cache_wback_inv; |
diff --git a/arch/mips/mm/cache.c b/arch/mips/mm/cache.c index 591c22b080e4..83a56296be86 100644 --- a/arch/mips/mm/cache.c +++ b/arch/mips/mm/cache.c | |||
@@ -30,6 +30,7 @@ void (*flush_icache_page)(struct vm_area_struct *vma, struct page *page); | |||
30 | 30 | ||
31 | /* MIPS specific cache operations */ | 31 | /* MIPS specific cache operations */ |
32 | void (*flush_cache_sigtramp)(unsigned long addr); | 32 | void (*flush_cache_sigtramp)(unsigned long addr); |
33 | void (*local_flush_data_cache_page)(void * addr); | ||
33 | void (*flush_data_cache_page)(unsigned long addr); | 34 | void (*flush_data_cache_page)(unsigned long addr); |
34 | void (*flush_icache_all)(void); | 35 | void (*flush_icache_all)(void); |
35 | 36 | ||
diff --git a/include/asm-mips/cacheflush.h b/include/asm-mips/cacheflush.h index aeae9fabf4a9..47bc8f6c20d2 100644 --- a/include/asm-mips/cacheflush.h +++ b/include/asm-mips/cacheflush.h | |||
@@ -74,6 +74,7 @@ static inline void copy_from_user_page(struct vm_area_struct *vma, | |||
74 | 74 | ||
75 | extern void (*flush_cache_sigtramp)(unsigned long addr); | 75 | extern void (*flush_cache_sigtramp)(unsigned long addr); |
76 | extern void (*flush_icache_all)(void); | 76 | extern void (*flush_icache_all)(void); |
77 | extern void (*local_flush_data_cache_page)(void * addr); | ||
77 | extern void (*flush_data_cache_page)(unsigned long addr); | 78 | extern void (*flush_data_cache_page)(unsigned long addr); |
78 | 79 | ||
79 | /* | 80 | /* |
diff --git a/include/asm-mips/mach-generic/ide.h b/include/asm-mips/mach-generic/ide.h index 550979a9ea9d..e3315359500a 100644 --- a/include/asm-mips/mach-generic/ide.h +++ b/include/asm-mips/mach-generic/ide.h | |||
@@ -104,65 +104,107 @@ static __inline__ unsigned long ide_default_io_base(int index) | |||
104 | #endif | 104 | #endif |
105 | 105 | ||
106 | /* MIPS port and memory-mapped I/O string operations. */ | 106 | /* MIPS port and memory-mapped I/O string operations. */ |
107 | static inline void __ide_flush_prologue(void) | ||
108 | { | ||
109 | #ifdef CONFIG_SMP | ||
110 | if (cpu_has_dc_aliases) | ||
111 | preempt_disable(); | ||
112 | #endif | ||
113 | } | ||
114 | |||
115 | static inline void __ide_flush_epilogue(void) | ||
116 | { | ||
117 | #ifdef CONFIG_SMP | ||
118 | if (cpu_has_dc_aliases) | ||
119 | preempt_enable(); | ||
120 | #endif | ||
121 | } | ||
107 | 122 | ||
108 | static inline void __ide_flush_dcache_range(unsigned long addr, unsigned long size) | 123 | static inline void __ide_flush_dcache_range(unsigned long addr, unsigned long size) |
109 | { | 124 | { |
110 | if (cpu_has_dc_aliases) { | 125 | if (cpu_has_dc_aliases) { |
111 | unsigned long end = addr + size; | 126 | unsigned long end = addr + size; |
112 | for (; addr < end; addr += PAGE_SIZE) | 127 | |
113 | flush_dcache_page(virt_to_page(addr)); | 128 | while (addr < end) { |
129 | local_flush_data_cache_page((void *)addr); | ||
130 | addr += PAGE_SIZE; | ||
131 | } | ||
114 | } | 132 | } |
115 | } | 133 | } |
116 | 134 | ||
135 | /* | ||
136 | * insw() and gang might be called with interrupts disabled, so we can't | ||
137 | * send IPIs for flushing due to the potencial of deadlocks, see the comment | ||
138 | * above smp_call_function() in arch/mips/kernel/smp.c. We work around the | ||
139 | * problem by disabling preemption so we know we actually perform the flush | ||
140 | * on the processor that actually has the lines to be flushed which hopefully | ||
141 | * is even better for performance anyway. | ||
142 | */ | ||
117 | static inline void __ide_insw(unsigned long port, void *addr, | 143 | static inline void __ide_insw(unsigned long port, void *addr, |
118 | unsigned int count) | 144 | unsigned int count) |
119 | { | 145 | { |
146 | __ide_flush_prologue(); | ||
120 | insw(port, addr, count); | 147 | insw(port, addr, count); |
121 | __ide_flush_dcache_range((unsigned long)addr, count * 2); | 148 | __ide_flush_dcache_range((unsigned long)addr, count * 2); |
149 | __ide_flush_epilogue(); | ||
122 | } | 150 | } |
123 | 151 | ||
124 | static inline void __ide_insl(unsigned long port, void *addr, unsigned int count) | 152 | static inline void __ide_insl(unsigned long port, void *addr, unsigned int count) |
125 | { | 153 | { |
154 | __ide_flush_prologue(); | ||
126 | insl(port, addr, count); | 155 | insl(port, addr, count); |
127 | __ide_flush_dcache_range((unsigned long)addr, count * 4); | 156 | __ide_flush_dcache_range((unsigned long)addr, count * 4); |
157 | __ide_flush_epilogue(); | ||
128 | } | 158 | } |
129 | 159 | ||
130 | static inline void __ide_outsw(unsigned long port, const void *addr, | 160 | static inline void __ide_outsw(unsigned long port, const void *addr, |
131 | unsigned long count) | 161 | unsigned long count) |
132 | { | 162 | { |
163 | __ide_flush_prologue(); | ||
133 | outsw(port, addr, count); | 164 | outsw(port, addr, count); |
134 | __ide_flush_dcache_range((unsigned long)addr, count * 2); | 165 | __ide_flush_dcache_range((unsigned long)addr, count * 2); |
166 | __ide_flush_epilogue(); | ||
135 | } | 167 | } |
136 | 168 | ||
137 | static inline void __ide_outsl(unsigned long port, const void *addr, | 169 | static inline void __ide_outsl(unsigned long port, const void *addr, |
138 | unsigned long count) | 170 | unsigned long count) |
139 | { | 171 | { |
172 | __ide_flush_prologue(); | ||
140 | outsl(port, addr, count); | 173 | outsl(port, addr, count); |
141 | __ide_flush_dcache_range((unsigned long)addr, count * 4); | 174 | __ide_flush_dcache_range((unsigned long)addr, count * 4); |
175 | __ide_flush_epilogue(); | ||
142 | } | 176 | } |
143 | 177 | ||
144 | static inline void __ide_mm_insw(void __iomem *port, void *addr, u32 count) | 178 | static inline void __ide_mm_insw(void __iomem *port, void *addr, u32 count) |
145 | { | 179 | { |
180 | __ide_flush_prologue(); | ||
146 | readsw(port, addr, count); | 181 | readsw(port, addr, count); |
147 | __ide_flush_dcache_range((unsigned long)addr, count * 2); | 182 | __ide_flush_dcache_range((unsigned long)addr, count * 2); |
183 | __ide_flush_epilogue(); | ||
148 | } | 184 | } |
149 | 185 | ||
150 | static inline void __ide_mm_insl(void __iomem *port, void *addr, u32 count) | 186 | static inline void __ide_mm_insl(void __iomem *port, void *addr, u32 count) |
151 | { | 187 | { |
188 | __ide_flush_prologue(); | ||
152 | readsl(port, addr, count); | 189 | readsl(port, addr, count); |
153 | __ide_flush_dcache_range((unsigned long)addr, count * 4); | 190 | __ide_flush_dcache_range((unsigned long)addr, count * 4); |
191 | __ide_flush_epilogue(); | ||
154 | } | 192 | } |
155 | 193 | ||
156 | static inline void __ide_mm_outsw(void __iomem *port, void *addr, u32 count) | 194 | static inline void __ide_mm_outsw(void __iomem *port, void *addr, u32 count) |
157 | { | 195 | { |
196 | __ide_flush_prologue(); | ||
158 | writesw(port, addr, count); | 197 | writesw(port, addr, count); |
159 | __ide_flush_dcache_range((unsigned long)addr, count * 2); | 198 | __ide_flush_dcache_range((unsigned long)addr, count * 2); |
199 | __ide_flush_epilogue(); | ||
160 | } | 200 | } |
161 | 201 | ||
162 | static inline void __ide_mm_outsl(void __iomem * port, void *addr, u32 count) | 202 | static inline void __ide_mm_outsl(void __iomem * port, void *addr, u32 count) |
163 | { | 203 | { |
204 | __ide_flush_prologue(); | ||
164 | writesl(port, addr, count); | 205 | writesl(port, addr, count); |
165 | __ide_flush_dcache_range((unsigned long)addr, count * 4); | 206 | __ide_flush_dcache_range((unsigned long)addr, count * 4); |
207 | __ide_flush_epilogue(); | ||
166 | } | 208 | } |
167 | 209 | ||
168 | /* ide_insw calls insw, not __ide_insw. Why? */ | 210 | /* ide_insw calls insw, not __ide_insw. Why? */ |