diff options
Diffstat (limited to 'arch/ia64/kernel/sal.c')
-rw-r--r-- | arch/ia64/kernel/sal.c | 75 |
1 files changed, 75 insertions, 0 deletions
diff --git a/arch/ia64/kernel/sal.c b/arch/ia64/kernel/sal.c index acc0f132f86c..056f7a6eedc7 100644 --- a/arch/ia64/kernel/sal.c +++ b/arch/ia64/kernel/sal.c | |||
@@ -14,6 +14,7 @@ | |||
14 | #include <linux/spinlock.h> | 14 | #include <linux/spinlock.h> |
15 | #include <linux/string.h> | 15 | #include <linux/string.h> |
16 | 16 | ||
17 | #include <asm/delay.h> | ||
17 | #include <asm/page.h> | 18 | #include <asm/page.h> |
18 | #include <asm/sal.h> | 19 | #include <asm/sal.h> |
19 | #include <asm/pal.h> | 20 | #include <asm/pal.h> |
@@ -214,6 +215,78 @@ chk_nointroute_opt(void) | |||
214 | static void __init sal_desc_ap_wakeup(void *p) { } | 215 | static void __init sal_desc_ap_wakeup(void *p) { } |
215 | #endif | 216 | #endif |
216 | 217 | ||
218 | /* | ||
219 | * HP rx5670 firmware polls for interrupts during SAL_CACHE_FLUSH by reading | ||
220 | * cr.ivr, but it never writes cr.eoi. This leaves any interrupt marked as | ||
221 | * "in-service" and masks other interrupts of equal or lower priority. | ||
222 | * | ||
223 | * HP internal defect reports: F1859, F2775, F3031. | ||
224 | */ | ||
225 | static int sal_cache_flush_drops_interrupts; | ||
226 | |||
227 | static void __init | ||
228 | check_sal_cache_flush (void) | ||
229 | { | ||
230 | unsigned long flags, itv; | ||
231 | int cpu; | ||
232 | u64 vector; | ||
233 | |||
234 | cpu = get_cpu(); | ||
235 | local_irq_save(flags); | ||
236 | |||
237 | /* | ||
238 | * Schedule a timer interrupt, wait until it's reported, and see if | ||
239 | * SAL_CACHE_FLUSH drops it. | ||
240 | */ | ||
241 | itv = ia64_get_itv(); | ||
242 | BUG_ON((itv & (1 << 16)) == 0); | ||
243 | |||
244 | ia64_set_itv(IA64_TIMER_VECTOR); | ||
245 | ia64_set_itm(ia64_get_itc() + 1000); | ||
246 | |||
247 | while (!ia64_get_irr(IA64_TIMER_VECTOR)) | ||
248 | cpu_relax(); | ||
249 | |||
250 | ia64_sal_cache_flush(3); | ||
251 | |||
252 | if (ia64_get_irr(IA64_TIMER_VECTOR)) { | ||
253 | vector = ia64_get_ivr(); | ||
254 | ia64_eoi(); | ||
255 | WARN_ON(vector != IA64_TIMER_VECTOR); | ||
256 | } else { | ||
257 | sal_cache_flush_drops_interrupts = 1; | ||
258 | printk(KERN_ERR "SAL: SAL_CACHE_FLUSH drops interrupts; " | ||
259 | "PAL_CACHE_FLUSH will be used instead\n"); | ||
260 | ia64_eoi(); | ||
261 | } | ||
262 | |||
263 | ia64_set_itv(itv); | ||
264 | local_irq_restore(flags); | ||
265 | put_cpu(); | ||
266 | } | ||
267 | |||
268 | s64 | ||
269 | ia64_sal_cache_flush (u64 cache_type) | ||
270 | { | ||
271 | struct ia64_sal_retval isrv; | ||
272 | |||
273 | if (sal_cache_flush_drops_interrupts) { | ||
274 | unsigned long flags; | ||
275 | u64 progress; | ||
276 | s64 rc; | ||
277 | |||
278 | progress = 0; | ||
279 | local_irq_save(flags); | ||
280 | rc = ia64_pal_cache_flush(cache_type, | ||
281 | PAL_CACHE_FLUSH_INVALIDATE, &progress, NULL); | ||
282 | local_irq_restore(flags); | ||
283 | return rc; | ||
284 | } | ||
285 | |||
286 | SAL_CALL(isrv, SAL_CACHE_FLUSH, cache_type, 0, 0, 0, 0, 0, 0); | ||
287 | return isrv.status; | ||
288 | } | ||
289 | |||
217 | void __init | 290 | void __init |
218 | ia64_sal_init (struct ia64_sal_systab *systab) | 291 | ia64_sal_init (struct ia64_sal_systab *systab) |
219 | { | 292 | { |
@@ -262,6 +335,8 @@ ia64_sal_init (struct ia64_sal_systab *systab) | |||
262 | } | 335 | } |
263 | p += SAL_DESC_SIZE(*p); | 336 | p += SAL_DESC_SIZE(*p); |
264 | } | 337 | } |
338 | |||
339 | check_sal_cache_flush(); | ||
265 | } | 340 | } |
266 | 341 | ||
267 | int | 342 | int |