gru: improve GRU TLB dropin statistics
[safe/jmp/linux-2.6] / drivers / misc / sgi-gru / grufault.c
index 3e64404..38657cd 100644 (file)
@@ -192,10 +192,11 @@ static int non_atomic_pte_lookup(struct vm_area_struct *vma,
 {
        struct page *page;
 
-       /* ZZZ Need to handle HUGE pages */
-       if (is_vm_hugetlb_page(vma))
-               return -EFAULT;
+#ifdef CONFIG_HUGETLB_PAGE
+       *pageshift = is_vm_hugetlb_page(vma) ? HPAGE_SHIFT : PAGE_SHIFT;
+#else
        *pageshift = PAGE_SHIFT;
+#endif
        if (get_user_pages
            (current, current->mm, vaddr, 1, write, 0, &page, NULL) <= 0)
                return -EFAULT;
@@ -253,7 +254,6 @@ static int atomic_pte_lookup(struct vm_area_struct *vma, unsigned long vaddr,
        return 0;
 
 err:
-       local_irq_enable();
        return 1;
 }
 
@@ -360,7 +360,8 @@ static void gru_preload_tlb(struct gru_state *gru,
  *             < 0 = error code
  *
  */
-static int gru_try_dropin(struct gru_thread_state *gts,
+static int gru_try_dropin(struct gru_state *gru,
+                         struct gru_thread_state *gts,
                          struct gru_tlb_fault_handle *tfh,
                          struct gru_instruction_bits *cbk)
 {
@@ -432,17 +433,18 @@ static int gru_try_dropin(struct gru_thread_state *gts,
        }
 
        if (unlikely(cbe) && pageshift == PAGE_SHIFT) {
-               gru_preload_tlb(gts->ts_gru, gts, atomic, vaddr, asid, write, tlb_preload_count, tfh, cbe);
+               gru_preload_tlb(gru, gts, atomic, vaddr, asid, write, tlb_preload_count, tfh, cbe);
                gru_flush_cache_cbe(cbe);
        }
 
        gru_cb_set_istatus_active(cbk);
+       gts->ustats.tlbdropin++;
        tfh_write_restart(tfh, gpa, GAA_RAM, vaddr, asid, write,
                          GRU_PAGESIZE(pageshift));
        gru_dbg(grudev,
                "%s: gid %d, gts 0x%p, tfh 0x%p, vaddr 0x%lx, asid 0x%x, indexway 0x%x,"
                " rw %d, ps %d, gpa 0x%lx\n",
-               atomic ? "atomic" : "non-atomic", gts->ts_gru->gs_gid, gts, tfh, vaddr, asid,
+               atomic ? "atomic" : "non-atomic", gru->gs_gid, gts, tfh, vaddr, asid,
                indexway, write, pageshift, gpa);
        STAT(tlb_dropin);
        return 0;
@@ -528,6 +530,7 @@ static irqreturn_t gru_intr(int chiplet, int blade)
        struct gru_tlb_fault_map imap, dmap;
        struct gru_thread_state *gts;
        struct gru_tlb_fault_handle *tfh = NULL;
+       struct completion *cmp;
        int cbrnum, ctxnum;
 
        STAT(intr);
@@ -547,9 +550,11 @@ static irqreturn_t gru_intr(int chiplet, int blade)
 
        for_each_cbr_in_tfm(cbrnum, dmap.fault_bits) {
                STAT(intr_cbr);
-               complete(gru->gs_blade->bs_async_wq);
+               cmp = gru->gs_blade->bs_async_wq;
+               if (cmp)
+                       complete(cmp);
                gru_dbg(grudev, "gid %d, cbr_done %d, done %d\n",
-                       gru->gs_gid, cbrnum, gru->gs_blade->bs_async_wq->done);
+                       gru->gs_gid, cbrnum, cmp ? cmp->done : -1);
        }
 
        for_each_cbr_in_tfm(cbrnum, imap.fault_bits) {
@@ -566,14 +571,20 @@ static irqreturn_t gru_intr(int chiplet, int blade)
                ctxnum = tfh->ctxnum;
                gts = gru->gs_gts[ctxnum];
 
+               /* Spurious interrupts can cause this. Ignore. */
+               if (!gts) {
+                       STAT(intr_spurious);
+                       continue;
+               }
+
                /*
                 * This is running in interrupt context. Trylock the mmap_sem.
                 * If it fails, retry the fault in user context.
                 */
+               gts->ustats.fmm_tlbmiss++;
                if (!gts->ts_force_cch_reload &&
                                        down_read_trylock(&gts->ts_mm->mmap_sem)) {
-                       gts->ustats.fmm_tlbdropin++;
-                       gru_try_dropin(gts, tfh, NULL);
+                       gru_try_dropin(gru, gts, tfh, NULL);
                        up_read(&gts->ts_mm->mmap_sem);
                } else {
                        tfh_user_polling_mode(tfh);
@@ -614,12 +625,12 @@ static int gru_user_dropin(struct gru_thread_state *gts,
        struct gru_mm_struct *gms = gts->ts_gms;
        int ret;
 
-       gts->ustats.upm_tlbdropin++;
+       gts->ustats.upm_tlbmiss++;
        while (1) {
                wait_event(gms->ms_wait_queue,
                           atomic_read(&gms->ms_range_active) == 0);
                prefetchw(tfh); /* Helps on hdw, required for emulator */
-               ret = gru_try_dropin(gts, tfh, cb);
+               ret = gru_try_dropin(gts->ts_gru, gts, tfh, cb);
                if (ret <= 0)
                        return ret;
                STAT(call_os_wait_queue);