diff options
author | Jack Steiner <steiner@sgi.com> | 2009-06-17 19:28:19 -0400 |
---|---|---|
committer | Linus Torvalds <torvalds@linux-foundation.org> | 2009-06-18 16:03:59 -0400 |
commit | cd1334f03f7b799bc6893b511daf2080e8f73863 (patch) | |
tree | 468d9bc99e19aa7895321927eaf30c4dae55166f /drivers/misc/sgi-gru/grufault.c | |
parent | d6580a9f15238b87e618310c862231ae3f352d2d (diff) |
gru: bug fixes for GRU exception handling
Bug fixes for GRU exception handling. Additional fields from the CBR must
be returned to the user to allow the user to correctly diagnose GRU
exceptions.
Handle endcase in TFH TLB miss handling. Verify that TFH actually
indicates a pending exception.
Signed-off-by: Jack Steiner <steiner@sgi.com>
Signed-off-by: Andrew Morton <akpm@linux-foundation.org>
Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>
Diffstat (limited to 'drivers/misc/sgi-gru/grufault.c')
-rw-r--r-- | drivers/misc/sgi-gru/grufault.c | 25 |
1 files changed, 21 insertions, 4 deletions
diff --git a/drivers/misc/sgi-gru/grufault.c b/drivers/misc/sgi-gru/grufault.c index ab118558552e..4089f862aa29 100644 --- a/drivers/misc/sgi-gru/grufault.c +++ b/drivers/misc/sgi-gru/grufault.c | |||
@@ -334,6 +334,8 @@ static int gru_try_dropin(struct gru_thread_state *gts, | |||
334 | * Might be a hardware race OR a stupid user. Ignore FMM because FMM | 334 | * Might be a hardware race OR a stupid user. Ignore FMM because FMM |
335 | * is a transient state. | 335 | * is a transient state. |
336 | */ | 336 | */ |
337 | if (tfh->status != TFHSTATUS_EXCEPTION) | ||
338 | goto failnoexception; | ||
337 | if (tfh->state == TFHSTATE_IDLE) | 339 | if (tfh->state == TFHSTATE_IDLE) |
338 | goto failidle; | 340 | goto failidle; |
339 | if (tfh->state == TFHSTATE_MISS_FMM && cb) | 341 | if (tfh->state == TFHSTATE_MISS_FMM && cb) |
@@ -401,8 +403,17 @@ failfmm: | |||
401 | gru_dbg(grudev, "FAILED fmm tfh: 0x%p, state %d\n", tfh, tfh->state); | 403 | gru_dbg(grudev, "FAILED fmm tfh: 0x%p, state %d\n", tfh, tfh->state); |
402 | return 0; | 404 | return 0; |
403 | 405 | ||
406 | failnoexception: | ||
407 | /* TFH status did not show exception pending */ | ||
408 | gru_flush_cache(tfh); | ||
409 | if (cb) | ||
410 | gru_flush_cache(cb); | ||
411 | STAT(tlb_dropin_fail_no_exception); | ||
412 | gru_dbg(grudev, "FAILED non-exception tfh: 0x%p, status %d, state %d\n", tfh, tfh->status, tfh->state); | ||
413 | return 0; | ||
414 | |||
404 | failidle: | 415 | failidle: |
405 | /* TFH was idle - no miss pending */ | 416 | /* TFH state was idle - no miss pending */ |
406 | gru_flush_cache(tfh); | 417 | gru_flush_cache(tfh); |
407 | if (cb) | 418 | if (cb) |
408 | gru_flush_cache(cb); | 419 | gru_flush_cache(cb); |
@@ -472,7 +483,8 @@ irqreturn_t gru_intr(int irq, void *dev_id) | |||
472 | * This is running in interrupt context. Trylock the mmap_sem. | 483 | * This is running in interrupt context. Trylock the mmap_sem. |
473 | * If it fails, retry the fault in user context. | 484 | * If it fails, retry the fault in user context. |
474 | */ | 485 | */ |
475 | if (down_read_trylock(>s->ts_mm->mmap_sem)) { | 486 | if (!gts->ts_force_cch_reload && |
487 | down_read_trylock(>s->ts_mm->mmap_sem)) { | ||
476 | gru_try_dropin(gts, tfh, NULL); | 488 | gru_try_dropin(gts, tfh, NULL); |
477 | up_read(>s->ts_mm->mmap_sem); | 489 | up_read(>s->ts_mm->mmap_sem); |
478 | } else { | 490 | } else { |
@@ -595,14 +607,19 @@ int gru_get_exception_detail(unsigned long arg) | |||
595 | excdet.ecause = cbe->ecause; | 607 | excdet.ecause = cbe->ecause; |
596 | excdet.exceptdet0 = cbe->idef1upd; | 608 | excdet.exceptdet0 = cbe->idef1upd; |
597 | excdet.exceptdet1 = cbe->idef3upd; | 609 | excdet.exceptdet1 = cbe->idef3upd; |
610 | excdet.cbrstate = cbe->cbrstate; | ||
611 | excdet.cbrexecstatus = cbe->cbrexecstatus; | ||
598 | ret = 0; | 612 | ret = 0; |
599 | } else { | 613 | } else { |
600 | ret = -EAGAIN; | 614 | ret = -EAGAIN; |
601 | } | 615 | } |
602 | gru_unlock_gts(gts); | 616 | gru_unlock_gts(gts); |
603 | 617 | ||
604 | gru_dbg(grudev, "address 0x%lx, ecause 0x%x\n", excdet.cb, | 618 | gru_dbg(grudev, |
605 | excdet.ecause); | 619 | "cb 0x%lx, op %d, exopc %d, cbrstate %d, cbrexecstatus 0x%x, ecause 0x%x, " |
620 | "exdet0 0x%lx, exdet1 0x%x\n", | ||
621 | excdet.cb, excdet.opc, excdet.exopc, excdet.cbrstate, excdet.cbrexecstatus, | ||
622 | excdet.ecause, excdet.exceptdet0, excdet.exceptdet1); | ||
606 | if (!ret && copy_to_user((void __user *)arg, &excdet, sizeof(excdet))) | 623 | if (!ret && copy_to_user((void __user *)arg, &excdet, sizeof(excdet))) |
607 | ret = -EFAULT; | 624 | ret = -EFAULT; |
608 | return ret; | 625 | return ret; |