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 /include/asm-mips | |
parent | bb12d612d4b2e6dc260fab081f69df783b74289f (diff) |
[MIPS] Handle IDE PIO cache aliases on SMP.
Signed-off-by: Ralf Baechle <ralf@linux-mips.org>
Diffstat (limited to 'include/asm-mips')
-rw-r--r-- | include/asm-mips/cacheflush.h | 1 | ||||
-rw-r--r-- | include/asm-mips/mach-generic/ide.h | 46 |
2 files changed, 45 insertions, 2 deletions
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? */ |