Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

powerpc/xive: fix hcall H_INT_RESET to support long busy delays

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>

authored by

Cédric Le Goater and committed by
Michael Ellerman
028555a5 d2b04b0c

+47 -5
+47 -5
arch/powerpc/sysdev/xive/spapr.c
··· 19 19 #include <linux/spinlock.h> 20 20 #include <linux/cpumask.h> 21 21 #include <linux/mm.h> 22 + #include <linux/delay.h> 22 23 23 24 #include <asm/prom.h> 24 25 #include <asm/io.h> ··· 107 106 break; 108 107 } 109 108 } 109 + } 110 + 111 + 112 + /* Based on the similar routines in RTAS */ 113 + static unsigned int plpar_busy_delay_time(long rc) 114 + { 115 + unsigned int ms = 0; 116 + 117 + if (H_IS_LONG_BUSY(rc)) { 118 + ms = get_longbusy_msecs(rc); 119 + } else if (rc == H_BUSY) { 120 + ms = 10; /* seems appropriate for XIVE hcalls */ 121 + } 122 + 123 + return ms; 124 + } 125 + 126 + static unsigned int plpar_busy_delay(int rc) 127 + { 128 + unsigned int ms; 129 + 130 + ms = plpar_busy_delay_time(rc); 131 + if (ms) 132 + mdelay(ms); 133 + 134 + return ms; 135 + } 136 + 137 + /* 138 + * Note: this call has a partition wide scope and can take a while to 139 + * complete. If it returns H_LONG_BUSY_* it should be retried 140 + * periodically. 141 + */ 142 + static long plpar_int_reset(unsigned long flags) 143 + { 144 + long rc; 145 + 146 + do { 147 + rc = plpar_hcall_norets(H_INT_RESET, flags); 148 + } while (plpar_busy_delay(rc)); 149 + 150 + if (rc) 151 + pr_err("H_INT_RESET failed %ld\n", rc); 152 + 153 + return rc; 110 154 } 111 155 112 156 static long plpar_int_get_source_info(unsigned long flags, ··· 491 445 492 446 static void xive_spapr_shutdown(void) 493 447 { 494 - long rc; 495 - 496 - rc = plpar_hcall_norets(H_INT_RESET, 0); 497 - if (rc) 498 - pr_err("H_INT_RESET failed %ld\n", rc); 448 + plpar_int_reset(0); 499 449 } 500 450 501 451 /*