powerpc/xive: fix hcall H_INT_RESET to support long busy delays
authorCédric Le Goater <clg@kaod.org>
Tue, 8 May 2018 07:05:15 +0000 (09:05 +0200)
committerMichael Ellerman <mpe@ellerman.id.au>
Thu, 10 May 2018 13:25:09 +0000 (23:25 +1000)
The hcall H_INT_RESET can take some time to complete and in such cases
it returns H_LONG_BUSY_* codes requiring the machine to sleep for a
while before retrying.

Signed-off-by: Cédric Le Goater <clg@kaod.org>
Signed-off-by: Michael Ellerman <mpe@ellerman.id.au>
arch/powerpc/sysdev/xive/spapr.c

index 091f1d0..864de3a 100644 (file)
@@ -19,6 +19,7 @@
 #include <linux/spinlock.h>
 #include <linux/cpumask.h>
 #include <linux/mm.h>
+#include <linux/delay.h>
 
 #include <asm/prom.h>
 #include <asm/io.h>
@@ -108,6 +109,51 @@ static void xive_irq_bitmap_free(int irq)
        }
 }
 
+
+/* Based on the similar routines in RTAS */
+static unsigned int plpar_busy_delay_time(long rc)
+{
+       unsigned int ms = 0;
+
+       if (H_IS_LONG_BUSY(rc)) {
+               ms = get_longbusy_msecs(rc);
+       } else if (rc == H_BUSY) {
+               ms = 10; /* seems appropriate for XIVE hcalls */
+       }
+
+       return ms;
+}
+
+static unsigned int plpar_busy_delay(int rc)
+{
+       unsigned int ms;
+
+       ms = plpar_busy_delay_time(rc);
+       if (ms)
+               mdelay(ms);
+
+       return ms;
+}
+
+/*
+ * Note: this call has a partition wide scope and can take a while to
+ * complete. If it returns H_LONG_BUSY_* it should be retried
+ * periodically.
+ */
+static long plpar_int_reset(unsigned long flags)
+{
+       long rc;
+
+       do {
+               rc = plpar_hcall_norets(H_INT_RESET, flags);
+       } while (plpar_busy_delay(rc));
+
+       if (rc)
+               pr_err("H_INT_RESET failed %ld\n", rc);
+
+       return rc;
+}
+
 static long plpar_int_get_source_info(unsigned long flags,
                                      unsigned long lisn,
                                      unsigned long *src_flags,
@@ -445,11 +491,7 @@ static void xive_spapr_put_ipi(unsigned int cpu, struct xive_cpu *xc)
 
 static void xive_spapr_shutdown(void)
 {
-       long rc;
-
-       rc = plpar_hcall_norets(H_INT_RESET, 0);
-       if (rc)
-               pr_err("H_INT_RESET failed %ld\n", rc);
+       plpar_int_reset(0);
 }
 
 /*