aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/misc
diff options
context:
space:
mode:
authorJack Steiner <steiner@sgi.com>2009-06-17 19:28:19 -0400
committerLinus Torvalds <torvalds@linux-foundation.org>2009-06-18 16:03:59 -0400
commitcd1334f03f7b799bc6893b511daf2080e8f73863 (patch)
tree468d9bc99e19aa7895321927eaf30c4dae55166f /drivers/misc
parentd6580a9f15238b87e618310c862231ae3f352d2d (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')
-rw-r--r--drivers/misc/sgi-gru/gru_instructions.h20
-rw-r--r--drivers/misc/sgi-gru/grufault.c25
-rw-r--r--drivers/misc/sgi-gru/gruhandles.h23
-rw-r--r--drivers/misc/sgi-gru/grumain.c3
-rw-r--r--drivers/misc/sgi-gru/gruprocfs.c5
-rw-r--r--drivers/misc/sgi-gru/grutables.h2
6 files changed, 52 insertions, 26 deletions
diff --git a/drivers/misc/sgi-gru/gru_instructions.h b/drivers/misc/sgi-gru/gru_instructions.h
index 3fde33c1e8f3..2feb885ca96f 100644
--- a/drivers/misc/sgi-gru/gru_instructions.h
+++ b/drivers/misc/sgi-gru/gru_instructions.h
@@ -81,6 +81,8 @@ struct control_block_extended_exc_detail {
81 int exopc; 81 int exopc;
82 long exceptdet0; 82 long exceptdet0;
83 int exceptdet1; 83 int exceptdet1;
84 int cbrstate;
85 int cbrexecstatus;
84}; 86};
85 87
86/* 88/*
@@ -107,7 +109,8 @@ struct gru_instruction_bits {
107 unsigned char reserved2: 2; 109 unsigned char reserved2: 2;
108 unsigned char istatus: 2; 110 unsigned char istatus: 2;
109 unsigned char isubstatus:4; 111 unsigned char isubstatus:4;
110 unsigned char reserved3: 2; 112 unsigned char reserved3: 1;
113 unsigned char tlb_fault_color: 1;
111 /* DW 1 */ 114 /* DW 1 */
112 unsigned long idef4; /* 42 bits: TRi1, BufSize */ 115 unsigned long idef4; /* 42 bits: TRi1, BufSize */
113 /* DW 2-6 */ 116 /* DW 2-6 */
@@ -253,6 +256,21 @@ struct gru_instruction {
253#define CBE_CAUSE_RESPONSE_DATA_ERROR (1 << 16) 256#define CBE_CAUSE_RESPONSE_DATA_ERROR (1 << 16)
254#define CBE_CAUSE_PROTOCOL_STATE_DATA_ERROR (1 << 17) 257#define CBE_CAUSE_PROTOCOL_STATE_DATA_ERROR (1 << 17)
255 258
259/* CBE cbrexecstatus bits */
260#define CBR_EXS_ABORT_OCC_BIT 0
261#define CBR_EXS_INT_OCC_BIT 1
262#define CBR_EXS_PENDING_BIT 2
263#define CBR_EXS_QUEUED_BIT 3
264#define CBR_EXS_TLBHW_BIT 4
265#define CBR_EXS_EXCEPTION_BIT 5
266
267#define CBR_EXS_ABORT_OCC (1 << CBR_EXS_ABORT_OCC_BIT)
268#define CBR_EXS_INT_OCC (1 << CBR_EXS_INT_OCC_BIT)
269#define CBR_EXS_PENDING (1 << CBR_EXS_PENDING_BIT)
270#define CBR_EXS_QUEUED (1 << CBR_EXS_QUEUED_BIT)
271#define CBR_EXS_TLBHW (1 << CBR_EXS_TLBHW_BIT)
272#define CBR_EXS_EXCEPTION (1 << CBR_EXS_EXCEPTION_BIT)
273
256/* 274/*
257 * Exceptions are retried for the following cases. If any OTHER bits are set 275 * Exceptions are retried for the following cases. If any OTHER bits are set
258 * in ecause, the exception is not retryable. 276 * in ecause, the exception is not retryable.
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
406failnoexception:
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
404failidle: 415failidle:
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(&gts->ts_mm->mmap_sem)) { 486 if (!gts->ts_force_cch_reload &&
487 down_read_trylock(&gts->ts_mm->mmap_sem)) {
476 gru_try_dropin(gts, tfh, NULL); 488 gru_try_dropin(gts, tfh, NULL);
477 up_read(&gts->ts_mm->mmap_sem); 489 up_read(&gts->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;
diff --git a/drivers/misc/sgi-gru/gruhandles.h b/drivers/misc/sgi-gru/gruhandles.h
index 1ed74d7508c8..03b76a1993c3 100644
--- a/drivers/misc/sgi-gru/gruhandles.h
+++ b/drivers/misc/sgi-gru/gruhandles.h
@@ -251,15 +251,14 @@ struct gru_tlb_fault_handle {
251 unsigned int fill1:9; 251 unsigned int fill1:9;
252 252
253 unsigned int status:2; 253 unsigned int status:2;
254 unsigned int fill2:1; 254 unsigned int fill2:2;
255 unsigned int color:1;
256 unsigned int state:3; 255 unsigned int state:3;
257 unsigned int fill3:1; 256 unsigned int fill3:1;
258 257
259 unsigned int cause:7; /* DW 0 - high 32 */ 258 unsigned int cause:7;
260 unsigned int fill4:1; 259 unsigned int fill4:1;
261 260
262 unsigned int indexway:12; 261 unsigned int indexway:12; /* DW 0 - high 32 */
263 unsigned int fill5:4; 262 unsigned int fill5:4;
264 263
265 unsigned int ctxnum:4; 264 unsigned int ctxnum:4;
@@ -457,21 +456,7 @@ enum gru_cbr_state {
457 CBRSTATE_BUSY_INTERRUPT, 456 CBRSTATE_BUSY_INTERRUPT,
458}; 457};
459 458
460/* CBE cbrexecstatus bits */ 459/* CBE cbrexecstatus bits - defined in gru_instructions.h*/
461#define CBR_EXS_ABORT_OCC_BIT 0
462#define CBR_EXS_INT_OCC_BIT 1
463#define CBR_EXS_PENDING_BIT 2
464#define CBR_EXS_QUEUED_BIT 3
465#define CBR_EXS_TLBHW_BIT 4
466#define CBR_EXS_EXCEPTION_BIT 5
467
468#define CBR_EXS_ABORT_OCC (1 << CBR_EXS_ABORT_OCC_BIT)
469#define CBR_EXS_INT_OCC (1 << CBR_EXS_INT_OCC_BIT)
470#define CBR_EXS_PENDING (1 << CBR_EXS_PENDING_BIT)
471#define CBR_EXS_QUEUED (1 << CBR_EXS_QUEUED_BIT)
472#define CBR_EXS_TLBHW (1 << CBR_EXS_TLBHW_BIT)
473#define CBR_EXS_EXCEPTION (1 << CBR_EXS_EXCEPTION_BIT)
474
475/* CBE ecause bits - defined in gru_instructions.h */ 460/* CBE ecause bits - defined in gru_instructions.h */
476 461
477/* 462/*
diff --git a/drivers/misc/sgi-gru/grumain.c b/drivers/misc/sgi-gru/grumain.c
index ec3f7a17d221..374af38862e6 100644
--- a/drivers/misc/sgi-gru/grumain.c
+++ b/drivers/misc/sgi-gru/grumain.c
@@ -599,6 +599,9 @@ int gru_update_cch(struct gru_thread_state *gts, int force_unload)
599 cch->sizeavail[i] = gts->ts_sizeavail; 599 cch->sizeavail[i] = gts->ts_sizeavail;
600 gts->ts_tlb_int_select = gru_cpu_fault_map_id(); 600 gts->ts_tlb_int_select = gru_cpu_fault_map_id();
601 cch->tlb_int_select = gru_cpu_fault_map_id(); 601 cch->tlb_int_select = gru_cpu_fault_map_id();
602 cch->tfm_fault_bit_enable =
603 (gts->ts_user_options == GRU_OPT_MISS_FMM_POLL
604 || gts->ts_user_options == GRU_OPT_MISS_FMM_INTR);
602 } else { 605 } else {
603 for (i = 0; i < 8; i++) 606 for (i = 0; i < 8; i++)
604 cch->asid[i] = 0; 607 cch->asid[i] = 0;
diff --git a/drivers/misc/sgi-gru/gruprocfs.c b/drivers/misc/sgi-gru/gruprocfs.c
index ee74821b171c..c46c1c5f0c73 100644
--- a/drivers/misc/sgi-gru/gruprocfs.c
+++ b/drivers/misc/sgi-gru/gruprocfs.c
@@ -84,6 +84,8 @@ static int statistics_show(struct seq_file *s, void *p)
84 printstat(s, tlb_dropin_fail_range_active); 84 printstat(s, tlb_dropin_fail_range_active);
85 printstat(s, tlb_dropin_fail_idle); 85 printstat(s, tlb_dropin_fail_idle);
86 printstat(s, tlb_dropin_fail_fmm); 86 printstat(s, tlb_dropin_fail_fmm);
87 printstat(s, tlb_dropin_fail_no_exception);
88 printstat(s, tlb_dropin_fail_no_exception_war);
87 printstat(s, mmu_invalidate_range); 89 printstat(s, mmu_invalidate_range);
88 printstat(s, mmu_invalidate_page); 90 printstat(s, mmu_invalidate_page);
89 printstat(s, mmu_clear_flush_young); 91 printstat(s, mmu_clear_flush_young);
@@ -158,8 +160,7 @@ static ssize_t options_write(struct file *file, const char __user *userbuf,
158 unsigned long val; 160 unsigned long val;
159 char buf[80]; 161 char buf[80];
160 162
161 if (copy_from_user 163 if (strncpy_from_user(buf, userbuf, sizeof(buf) - 1) < 0)
162 (buf, userbuf, count < sizeof(buf) ? count : sizeof(buf)))
163 return -EFAULT; 164 return -EFAULT;
164 buf[count - 1] = '\0'; 165 buf[count - 1] = '\0';
165 if (!strict_strtoul(buf, 10, &val)) 166 if (!strict_strtoul(buf, 10, &val))
diff --git a/drivers/misc/sgi-gru/grutables.h b/drivers/misc/sgi-gru/grutables.h
index bf1eeb7553ed..ebf6183c1635 100644
--- a/drivers/misc/sgi-gru/grutables.h
+++ b/drivers/misc/sgi-gru/grutables.h
@@ -207,6 +207,8 @@ struct gru_stats_s {
207 atomic_long_t tlb_dropin_fail_range_active; 207 atomic_long_t tlb_dropin_fail_range_active;
208 atomic_long_t tlb_dropin_fail_idle; 208 atomic_long_t tlb_dropin_fail_idle;
209 atomic_long_t tlb_dropin_fail_fmm; 209 atomic_long_t tlb_dropin_fail_fmm;
210 atomic_long_t tlb_dropin_fail_no_exception;
211 atomic_long_t tlb_dropin_fail_no_exception_war;
210 atomic_long_t mmu_invalidate_range; 212 atomic_long_t mmu_invalidate_range;
211 atomic_long_t mmu_invalidate_page; 213 atomic_long_t mmu_invalidate_page;
212 atomic_long_t mmu_clear_flush_young; 214 atomic_long_t mmu_clear_flush_young;