powerpc/vas: poll for return of window credits
authorSukadev Bhattiprolu <sukadev@linux.vnet.ibm.com>
Wed, 8 Nov 2017 02:23:48 +0000 (18:23 -0800)
committerMichael Ellerman <mpe@ellerman.id.au>
Sat, 11 Nov 2017 22:03:08 +0000 (09:03 +1100)
Normally, the NX driver waits for the CRBs to be processed before closing
the window. But it is better to ensure that the credits are returned before
the window gets reassigned later.

Signed-off-by: Sukadev Bhattiprolu <sukadev@linux.vnet.ibm.com>
Signed-off-by: Michael Ellerman <mpe@ellerman.id.au>
arch/powerpc/platforms/powernv/vas-window.c

index a59a187c0cd144431a63dcb8a8c71bd8e1851da9..23c13a7dcf89cc73c71705905281c14c6b1b95b6 100644 (file)
@@ -1062,6 +1062,49 @@ int vas_paste_crb(struct vas_window *txwin, int offset, bool re)
 }
 EXPORT_SYMBOL_GPL(vas_paste_crb);
 
+/*
+ * If credit checking is enabled for this window, poll for the return
+ * of window credits (i.e for NX engines to process any outstanding CRBs).
+ * Since NX-842 waits for the CRBs to be processed before closing the
+ * window, we should not have to wait for too long.
+ *
+ * TODO: We retry in 10ms intervals now. We could/should probably peek at
+ *     the VAS_LRFIFO_PUSH_OFFSET register to get an estimate of pending
+ *     CRBs on the FIFO and compute the delay dynamically on each retry.
+ *     But that is not really needed until we support NX-GZIP access from
+ *     user space. (NX-842 driver waits for CSB and Fast thread-wakeup
+ *     doesn't use credit checking).
+ */
+static void poll_window_credits(struct vas_window *window)
+{
+       u64 val;
+       int creds, mode;
+
+       val = read_hvwc_reg(window, VREG(WINCTL));
+       if (window->tx_win)
+               mode = GET_FIELD(VAS_WINCTL_TX_WCRED_MODE, val);
+       else
+               mode = GET_FIELD(VAS_WINCTL_RX_WCRED_MODE, val);
+
+       if (!mode)
+               return;
+retry:
+       if (window->tx_win) {
+               val = read_hvwc_reg(window, VREG(TX_WCRED));
+               creds = GET_FIELD(VAS_TX_WCRED, val);
+       } else {
+               val = read_hvwc_reg(window, VREG(LRX_WCRED));
+               creds = GET_FIELD(VAS_LRX_WCRED, val);
+       }
+
+       if (creds < window->wcreds_max) {
+               val = 0;
+               set_current_state(TASK_UNINTERRUPTIBLE);
+               schedule_timeout(msecs_to_jiffies(10));
+               goto retry;
+       }
+}
+
 /*
  * Wait for the window to go to "not-busy" state. It should only take a
  * short time to queue a CRB, so window should not be busy for too long.
@@ -1149,6 +1192,8 @@ int vas_win_close(struct vas_window *window)
 
        unpin_close_window(window);
 
+       poll_window_credits(window);
+
        poll_window_castout(window);
 
        /* if send window, drop reference to matching receive window */