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 |
