int             exopc;
        long            exceptdet0;
        int             exceptdet1;
+       int             cbrstate;
+       int             cbrexecstatus;
 };
 
 /*
     unsigned char              reserved2: 2;
     unsigned char              istatus:   2;
     unsigned char              isubstatus:4;
-    unsigned char              reserved3: 2;
+    unsigned char              reserved3: 1;
+    unsigned char              tlb_fault_color: 1;
     /* DW 1 */
     unsigned long              idef4;          /* 42 bits: TRi1, BufSize */
     /* DW 2-6 */
 #define CBE_CAUSE_RESPONSE_DATA_ERROR          (1 << 16)
 #define CBE_CAUSE_PROTOCOL_STATE_DATA_ERROR    (1 << 17)
 
+/* CBE cbrexecstatus bits */
+#define CBR_EXS_ABORT_OCC_BIT                  0
+#define CBR_EXS_INT_OCC_BIT                    1
+#define CBR_EXS_PENDING_BIT                    2
+#define CBR_EXS_QUEUED_BIT                     3
+#define CBR_EXS_TLBHW_BIT                      4
+#define CBR_EXS_EXCEPTION_BIT                  5
+
+#define CBR_EXS_ABORT_OCC                      (1 << CBR_EXS_ABORT_OCC_BIT)
+#define CBR_EXS_INT_OCC                                (1 << CBR_EXS_INT_OCC_BIT)
+#define CBR_EXS_PENDING                                (1 << CBR_EXS_PENDING_BIT)
+#define CBR_EXS_QUEUED                         (1 << CBR_EXS_QUEUED_BIT)
+#define CBR_EXS_TLBHW                          (1 << CBR_EXS_TLBHW_BIT)
+#define CBR_EXS_EXCEPTION                      (1 << CBR_EXS_EXCEPTION_BIT)
+
 /*
  * Exceptions are retried for the following cases. If any OTHER bits are set
  * in ecause, the exception is not retryable.
 
         * Might be a hardware race OR a stupid user. Ignore FMM because FMM
         * is a transient state.
         */
+       if (tfh->status != TFHSTATUS_EXCEPTION)
+               goto failnoexception;
        if (tfh->state == TFHSTATE_IDLE)
                goto failidle;
        if (tfh->state == TFHSTATE_MISS_FMM && cb)
        gru_dbg(grudev, "FAILED fmm tfh: 0x%p, state %d\n", tfh, tfh->state);
        return 0;
 
+failnoexception:
+       /* TFH status did not show exception pending */
+       gru_flush_cache(tfh);
+       if (cb)
+               gru_flush_cache(cb);
+       STAT(tlb_dropin_fail_no_exception);
+       gru_dbg(grudev, "FAILED non-exception tfh: 0x%p, status %d, state %d\n", tfh, tfh->status, tfh->state);
+       return 0;
+
 failidle:
-       /* TFH was idle  - no miss pending */
+       /* TFH state was idle  - no miss pending */
        gru_flush_cache(tfh);
        if (cb)
                gru_flush_cache(cb);
                 * This is running in interrupt context. Trylock the mmap_sem.
                 * If it fails, retry the fault in user context.
                 */
-               if (down_read_trylock(>s->ts_mm->mmap_sem)) {
+               if (!gts->ts_force_cch_reload &&
+                                       down_read_trylock(>s->ts_mm->mmap_sem)) {
                        gru_try_dropin(gts, tfh, NULL);
                        up_read(>s->ts_mm->mmap_sem);
                } else {
                excdet.ecause = cbe->ecause;
                excdet.exceptdet0 = cbe->idef1upd;
                excdet.exceptdet1 = cbe->idef3upd;
+               excdet.cbrstate = cbe->cbrstate;
+               excdet.cbrexecstatus = cbe->cbrexecstatus;
                ret = 0;
        } else {
                ret = -EAGAIN;
        }
        gru_unlock_gts(gts);
 
-       gru_dbg(grudev, "address 0x%lx, ecause 0x%x\n", excdet.cb,
-               excdet.ecause);
+       gru_dbg(grudev,
+               "cb 0x%lx, op %d, exopc %d, cbrstate %d, cbrexecstatus 0x%x, ecause 0x%x, "
+               "exdet0 0x%lx, exdet1 0x%x\n",
+               excdet.cb, excdet.opc, excdet.exopc, excdet.cbrstate, excdet.cbrexecstatus,
+               excdet.ecause, excdet.exceptdet0, excdet.exceptdet1);
        if (!ret && copy_to_user((void __user *)arg, &excdet, sizeof(excdet)))
                ret = -EFAULT;
        return ret;
 
        unsigned int fill1:9;
 
        unsigned int status:2;
-       unsigned int fill2:1;
-       unsigned int color:1;
+       unsigned int fill2:2;
        unsigned int state:3;
        unsigned int fill3:1;
 
-       unsigned int cause:7;           /* DW 0 - high 32 */
+       unsigned int cause:7;
        unsigned int fill4:1;
 
-       unsigned int indexway:12;
+       unsigned int indexway:12;       /* DW 0 - high 32 */
        unsigned int fill5:4;
 
        unsigned int ctxnum:4;
        CBRSTATE_BUSY_INTERRUPT,
 };
 
-/* CBE cbrexecstatus bits */
-#define CBR_EXS_ABORT_OCC_BIT                  0
-#define CBR_EXS_INT_OCC_BIT                    1
-#define CBR_EXS_PENDING_BIT                    2
-#define CBR_EXS_QUEUED_BIT                     3
-#define CBR_EXS_TLBHW_BIT                      4
-#define CBR_EXS_EXCEPTION_BIT                  5
-
-#define CBR_EXS_ABORT_OCC                      (1 << CBR_EXS_ABORT_OCC_BIT)
-#define CBR_EXS_INT_OCC                                (1 << CBR_EXS_INT_OCC_BIT)
-#define CBR_EXS_PENDING                                (1 << CBR_EXS_PENDING_BIT)
-#define CBR_EXS_QUEUED                         (1 << CBR_EXS_QUEUED_BIT)
-#define CBR_EXS_TLBHW                          (1 << CBR_EXS_TLBHW_BIT)
-#define CBR_EXS_EXCEPTION                      (1 << CBR_EXS_EXCEPTION_BIT)
-
+/* CBE cbrexecstatus bits  - defined in gru_instructions.h*/
 /* CBE ecause bits  - defined in gru_instructions.h */
 
 /*
 
                                cch->sizeavail[i] = gts->ts_sizeavail;
                        gts->ts_tlb_int_select = gru_cpu_fault_map_id();
                        cch->tlb_int_select = gru_cpu_fault_map_id();
+                       cch->tfm_fault_bit_enable =
+                           (gts->ts_user_options == GRU_OPT_MISS_FMM_POLL
+                           || gts->ts_user_options == GRU_OPT_MISS_FMM_INTR);
                } else {
                        for (i = 0; i < 8; i++)
                                cch->asid[i] = 0;
 
        printstat(s, tlb_dropin_fail_range_active);
        printstat(s, tlb_dropin_fail_idle);
        printstat(s, tlb_dropin_fail_fmm);
+       printstat(s, tlb_dropin_fail_no_exception);
+       printstat(s, tlb_dropin_fail_no_exception_war);
        printstat(s, mmu_invalidate_range);
        printstat(s, mmu_invalidate_page);
        printstat(s, mmu_clear_flush_young);
        unsigned long val;
        char buf[80];
 
-       if (copy_from_user
-           (buf, userbuf, count < sizeof(buf) ? count : sizeof(buf)))
+       if (strncpy_from_user(buf, userbuf, sizeof(buf) - 1) < 0)
                return -EFAULT;
        buf[count - 1] = '\0';
        if (!strict_strtoul(buf, 10, &val))
 
        atomic_long_t tlb_dropin_fail_range_active;
        atomic_long_t tlb_dropin_fail_idle;
        atomic_long_t tlb_dropin_fail_fmm;
+       atomic_long_t tlb_dropin_fail_no_exception;
+       atomic_long_t tlb_dropin_fail_no_exception_war;
        atomic_long_t mmu_invalidate_range;
        atomic_long_t mmu_invalidate_page;
        atomic_long_t mmu_clear_flush_young;