* [PATCH] use msleep() for RTAS delays @ 2006-05-31 19:32 John Rose 2006-06-01 5:31 ` Benjamin Herrenschmidt 0 siblings, 1 reply; 16+ messages in thread From: John Rose @ 2006-05-31 19:32 UTC (permalink / raw) To: External List; +Cc: Paul Mackerras The current use of udelay() for RTAS extended delay conditions can result in CPU soft lockups. The use of msleep() won't tie up the CPU. Signed-off-by: John Rose <johnrose@austin.ibm.com> --- Thanks- John diff -puN arch/powerpc/kernel/rtas.c~msleep_rtas arch/powerpc/kernel/rtas.c --- 2_6_linus/arch/powerpc/kernel/rtas.c~msleep_rtas 2006-05-31 14:07:51.000000000 -0500 +++ 2_6_linus-johnrose/arch/powerpc/kernel/rtas.c 2006-05-31 14:10:09.000000000 -0500 @@ -447,10 +447,10 @@ int rtas_set_power_level(int powerdomain while (1) { rc = rtas_call(token, 2, 2, setlevel, powerdomain, level); if (rc == RTAS_BUSY) - udelay(1); + msleep(1); else if (rtas_is_extended_busy(rc)) { wait_time = rtas_extended_busy_delay_time(rc); - udelay(wait_time * 1000); + msleep(wait_time); } else break; } @@ -472,10 +472,10 @@ int rtas_get_sensor(int sensor, int inde while (1) { rc = rtas_call(token, 2, 2, state, sensor, index); if (rc == RTAS_BUSY) - udelay(1); + msleep(1); else if (rtas_is_extended_busy(rc)) { wait_time = rtas_extended_busy_delay_time(rc); - udelay(wait_time * 1000); + msleep(wait_time); } else break; } @@ -497,12 +497,11 @@ int rtas_set_indicator(int indicator, in while (1) { rc = rtas_call(token, 3, 1, NULL, indicator, index, new_value); if (rc == RTAS_BUSY) - udelay(1); + msleep(1); else if (rtas_is_extended_busy(rc)) { wait_time = rtas_extended_busy_delay_time(rc); - udelay(wait_time * 1000); - } - else + msleep(wait_time); + } else break; } diff -puN arch/powerpc/kernel/rtas_flash.c~msleep_rtas arch/powerpc/kernel/rtas_flash.c --- 2_6_linus/arch/powerpc/kernel/rtas_flash.c~msleep_rtas 2006-05-31 14:10:47.000000000 -0500 +++ 2_6_linus-johnrose/arch/powerpc/kernel/rtas_flash.c 2006-05-31 14:19:30.000000000 -0500 @@ -16,7 +16,7 @@ #include <linux/module.h> #include <linux/init.h> #include <linux/proc_fs.h> -#include <asm/delay.h> +#include <linux/delay.h> #include <asm/uaccess.h> #include <asm/rtas.h> #include <asm/abs_addr.h> @@ -372,10 +372,10 @@ static void manage_flash(struct rtas_man rc = rtas_call(rtas_token("ibm,manage-flash-image"), 1, 1, NULL, args_buf->op); if (rc == RTAS_RC_BUSY) - udelay(1); + msleep(1); else if (rtas_is_extended_busy(rc)) { wait_time = rtas_extended_busy_delay_time(rc); - udelay(wait_time * 1000); + msleep(wait_time); } else break; } @@ -465,10 +465,10 @@ static void validate_flash(struct rtas_v spin_unlock(&rtas_data_buf_lock); if (rc == RTAS_RC_BUSY) - udelay(1); + msleep(1); else if (rtas_is_extended_busy(rc)) { wait_time = rtas_extended_busy_delay_time(rc); - udelay(wait_time * 1000); + msleep(wait_time); } else break; } _ ^ permalink raw reply [flat|nested] 16+ messages in thread
* Re: [PATCH] use msleep() for RTAS delays 2006-05-31 19:32 [PATCH] use msleep() for RTAS delays John Rose @ 2006-06-01 5:31 ` Benjamin Herrenschmidt 2006-06-01 5:39 ` Paul Mackerras 2006-06-01 15:55 ` John Rose 0 siblings, 2 replies; 16+ messages in thread From: Benjamin Herrenschmidt @ 2006-06-01 5:31 UTC (permalink / raw) To: John Rose; +Cc: External List, Paul Mackerras On Wed, 2006-05-31 at 14:32 -0500, John Rose wrote: > The current use of udelay() for RTAS extended delay conditions can > result in CPU soft lockups. The use of msleep() won't tie up the CPU. What about putting this whole thing in a helper ? There is a few more things I've seen floating around implementing the exact same logic (for example Jake's MSI patches). We could either do something like for (;;) { rc = rtas_call(...); if (!rtas_check_busy(rc)) break; } Or something inside rtas_call rtas_call_waitbusy(...); Ben. > Signed-off-by: John Rose <johnrose@austin.ibm.com> > > --- > > Thanks- > John > > diff -puN arch/powerpc/kernel/rtas.c~msleep_rtas arch/powerpc/kernel/rtas.c > --- 2_6_linus/arch/powerpc/kernel/rtas.c~msleep_rtas 2006-05-31 14:07:51.000000000 -0500 > +++ 2_6_linus-johnrose/arch/powerpc/kernel/rtas.c 2006-05-31 14:10:09.000000000 -0500 > @@ -447,10 +447,10 @@ int rtas_set_power_level(int powerdomain > while (1) { > rc = rtas_call(token, 2, 2, setlevel, powerdomain, level); > if (rc == RTAS_BUSY) > - udelay(1); > + msleep(1); > else if (rtas_is_extended_busy(rc)) { > wait_time = rtas_extended_busy_delay_time(rc); > - udelay(wait_time * 1000); > + msleep(wait_time); > } else > break; > } > @@ -472,10 +472,10 @@ int rtas_get_sensor(int sensor, int inde > while (1) { > rc = rtas_call(token, 2, 2, state, sensor, index); > if (rc == RTAS_BUSY) > - udelay(1); > + msleep(1); > else if (rtas_is_extended_busy(rc)) { > wait_time = rtas_extended_busy_delay_time(rc); > - udelay(wait_time * 1000); > + msleep(wait_time); > } else > break; > } > @@ -497,12 +497,11 @@ int rtas_set_indicator(int indicator, in > while (1) { > rc = rtas_call(token, 3, 1, NULL, indicator, index, new_value); > if (rc == RTAS_BUSY) > - udelay(1); > + msleep(1); > else if (rtas_is_extended_busy(rc)) { > wait_time = rtas_extended_busy_delay_time(rc); > - udelay(wait_time * 1000); > - } > - else > + msleep(wait_time); > + } else > break; > } > > diff -puN arch/powerpc/kernel/rtas_flash.c~msleep_rtas arch/powerpc/kernel/rtas_flash.c > --- 2_6_linus/arch/powerpc/kernel/rtas_flash.c~msleep_rtas 2006-05-31 14:10:47.000000000 -0500 > +++ 2_6_linus-johnrose/arch/powerpc/kernel/rtas_flash.c 2006-05-31 14:19:30.000000000 -0500 > @@ -16,7 +16,7 @@ > #include <linux/module.h> > #include <linux/init.h> > #include <linux/proc_fs.h> > -#include <asm/delay.h> > +#include <linux/delay.h> > #include <asm/uaccess.h> > #include <asm/rtas.h> > #include <asm/abs_addr.h> > @@ -372,10 +372,10 @@ static void manage_flash(struct rtas_man > rc = rtas_call(rtas_token("ibm,manage-flash-image"), 1, > 1, NULL, args_buf->op); > if (rc == RTAS_RC_BUSY) > - udelay(1); > + msleep(1); > else if (rtas_is_extended_busy(rc)) { > wait_time = rtas_extended_busy_delay_time(rc); > - udelay(wait_time * 1000); > + msleep(wait_time); > } else > break; > } > @@ -465,10 +465,10 @@ static void validate_flash(struct rtas_v > spin_unlock(&rtas_data_buf_lock); > > if (rc == RTAS_RC_BUSY) > - udelay(1); > + msleep(1); > else if (rtas_is_extended_busy(rc)) { > wait_time = rtas_extended_busy_delay_time(rc); > - udelay(wait_time * 1000); > + msleep(wait_time); > } else > break; > } > > _ > > _______________________________________________ > Linuxppc-dev mailing list > Linuxppc-dev@ozlabs.org > https://ozlabs.org/mailman/listinfo/linuxppc-dev ^ permalink raw reply [flat|nested] 16+ messages in thread
* Re: [PATCH] use msleep() for RTAS delays 2006-06-01 5:31 ` Benjamin Herrenschmidt @ 2006-06-01 5:39 ` Paul Mackerras 2006-06-01 18:09 ` Arnd Bergmann 2006-06-01 15:55 ` John Rose 1 sibling, 1 reply; 16+ messages in thread From: Paul Mackerras @ 2006-06-01 5:39 UTC (permalink / raw) To: Benjamin Herrenschmidt; +Cc: External List Benjamin Herrenschmidt writes: > We could either do something like > > for (;;) { > rc = rtas_call(...); > if (!rtas_check_busy(rc)) > break; rtas_check_busy might need some state, such as the number of times we have seen an RTAS_BUSY return value. > Or something inside rtas_call > > rtas_call_waitbusy(...); That's a good idea... Paul. ^ permalink raw reply [flat|nested] 16+ messages in thread
* Re: [PATCH] use msleep() for RTAS delays 2006-06-01 5:39 ` Paul Mackerras @ 2006-06-01 18:09 ` Arnd Bergmann 0 siblings, 0 replies; 16+ messages in thread From: Arnd Bergmann @ 2006-06-01 18:09 UTC (permalink / raw) To: linuxppc-dev; +Cc: Paul Mackerras On Thursday 01 June 2006 07:39, Paul Mackerras wrote: > > > rtas_call_waitbusy(...); > > That's a good idea... Do we also need an atomic version of that? Maybe there are places where we actually need to call a slow rtas call under a spinlock. At the very least, rtas_call_waitbusy() should have a might_sleep() in it to find those places. Arnd <>< ^ permalink raw reply [flat|nested] 16+ messages in thread
* Re: [PATCH] use msleep() for RTAS delays 2006-06-01 5:31 ` Benjamin Herrenschmidt 2006-06-01 5:39 ` Paul Mackerras @ 2006-06-01 15:55 ` John Rose 2006-06-01 22:25 ` John Rose 1 sibling, 1 reply; 16+ messages in thread From: John Rose @ 2006-06-01 15:55 UTC (permalink / raw) To: Benjamin Herrenschmidt; +Cc: External List, Paul Mackerras Hi Ben- > What about putting this whole thing in a helper ? There is a few more > things I've seen floating around implementing the exact same logic (for > example Jake's MSI patches). I don't mind writing this up. The previous patch fixes a reported bug with minimal reorg. If possible, I'd like to restructure on top of that. > Or something inside rtas_call > > rtas_call_waitbusy(...); Certain RTAS calls expect identical inputs between successive calls, while others (ibm,change-msi) expect modified "sequence" inputs, etc. Given this inconsistency, we probably can't handle busy rcs inside rtas_call(). Thanks- John ^ permalink raw reply [flat|nested] 16+ messages in thread
* Re: [PATCH] use msleep() for RTAS delays 2006-06-01 15:55 ` John Rose @ 2006-06-01 22:25 ` John Rose 2006-06-02 20:30 ` [PATCH] reorg RTAS delay code John Rose 0 siblings, 1 reply; 16+ messages in thread From: John Rose @ 2006-06-01 22:25 UTC (permalink / raw) To: Benjamin Herrenschmidt; +Cc: External List, Paul Mackerras > I don't mind writing this up. The previous patch fixes a reported bug > with minimal reorg. If possible, I'd like to restructure on top of > that. On second thought, why not reorg now! I'll have a patch shortly. Thanks- John ^ permalink raw reply [flat|nested] 16+ messages in thread
* [PATCH] reorg RTAS delay code 2006-06-01 22:25 ` John Rose @ 2006-06-02 20:30 ` John Rose 2006-06-02 21:33 ` Nathan Lynch 0 siblings, 1 reply; 16+ messages in thread From: John Rose @ 2006-06-02 20:30 UTC (permalink / raw) To: Benjamin Herrenschmidt; +Cc: External List, Paul Mackerras This patch attempts to handle RTAS "busy" return codes in a more simple and consistent manner. Typical callers of RTAS shouldn't have to manage wait times and delay calls. This patch also changes the kernel to use msleep() rather than udelay() when a runtime delay is necessary. This will avoid CPU soft lockups for extended delay conditions. Signed-off-by: John Rose <johnrose@austin.ibm.com> --- This obsoletes the patch in the parent thread, "use msleep for RTAS delays". Sniff tested on POWER5. Thanks- John 2_6_linus-johnrose/arch/powerpc/kernel/rtas-rtc.c | 30 +++--- 2_6_linus-johnrose/arch/powerpc/kernel/rtas.c | 86 ++++++++------------ 2_6_linus-johnrose/arch/powerpc/kernel/rtas_flash.c | 25 ----- 2_6_linus-johnrose/include/asm-powerpc/rtas.h | 8 - 4 files changed, 57 insertions(+), 92 deletions(-) diff -puN arch/powerpc/kernel/rtas.c~rtas_delay_reorg arch/powerpc/kernel/rtas.c --- 2_6_linus/arch/powerpc/kernel/rtas.c~rtas_delay_reorg 2006-06-02 15:09:43.000000000 -0500 +++ 2_6_linus-johnrose/arch/powerpc/kernel/rtas.c 2006-06-02 15:22:37.000000000 -0500 @@ -370,24 +370,35 @@ int rtas_call(int token, int nargs, int return ret; } -/* Given an RTAS status code of 990n compute the hinted delay of 10^n - * (last digit) milliseconds. For now we bound at n=5 (100 sec). +/* For RTAS_BUSY (-2), delay for 1 millisecond. For an extended busy status + * code of 990n, perform the hinted delay of 10^n (last digit) milliseconds. */ -unsigned int rtas_extended_busy_delay_time(int status) +unsigned int rtas_busy_delay_time(int status) { - int order = status - 9900; - unsigned long ms; + int order; + unsigned int ms = 0; - if (order < 0) - order = 0; /* RTC depends on this for -2 clock busy */ - else if (order > 5) - order = 5; /* bound */ + if (status == RTAS_BUSY) { + ms = 1; + } else if (status >= 9900 && status <= 9905) { + order = status - 9900; + for (ms = 1; order > 0; order--) + ms *= 10; + } + + return ms; +} - /* Use microseconds for reasonable accuracy */ - for (ms = 1; order > 0; order--) - ms *= 10; +/* For an RTAS busy status code, perform the hinted delay. */ +unsigned int rtas_busy_delay(int status) +{ + unsigned int ms; - return ms; + ms = rtas_busy_delay_time(status); + if (ms) + msleep(ms); + + return ms; } int rtas_error_rc(int rtas_rc) @@ -438,22 +449,14 @@ int rtas_get_power_level(int powerdomain int rtas_set_power_level(int powerdomain, int level, int *setlevel) { int token = rtas_token("set-power-level"); - unsigned int wait_time; int rc; if (token == RTAS_UNKNOWN_SERVICE) return -ENOENT; - while (1) { + do rc = rtas_call(token, 2, 2, setlevel, powerdomain, level); - if (rc == RTAS_BUSY) - udelay(1); - else if (rtas_is_extended_busy(rc)) { - wait_time = rtas_extended_busy_delay_time(rc); - udelay(wait_time * 1000); - } else - break; - } + while (rtas_busy_delay(rc)); if (rc < 0) return rtas_error_rc(rc); @@ -463,22 +466,14 @@ int rtas_set_power_level(int powerdomain int rtas_get_sensor(int sensor, int index, int *state) { int token = rtas_token("get-sensor-state"); - unsigned int wait_time; int rc; if (token == RTAS_UNKNOWN_SERVICE) return -ENOENT; - while (1) { + do rc = rtas_call(token, 2, 2, state, sensor, index); - if (rc == RTAS_BUSY) - udelay(1); - else if (rtas_is_extended_busy(rc)) { - wait_time = rtas_extended_busy_delay_time(rc); - udelay(wait_time * 1000); - } else - break; - } + while (rtas_busy_delay(rc)); if (rc < 0) return rtas_error_rc(rc); @@ -488,23 +483,14 @@ int rtas_get_sensor(int sensor, int inde int rtas_set_indicator(int indicator, int index, int new_value) { int token = rtas_token("set-indicator"); - unsigned int wait_time; int rc; if (token == RTAS_UNKNOWN_SERVICE) return -ENOENT; - while (1) { + do rc = rtas_call(token, 3, 1, NULL, indicator, index, new_value); - if (rc == RTAS_BUSY) - udelay(1); - else if (rtas_is_extended_busy(rc)) { - wait_time = rtas_extended_busy_delay_time(rc); - udelay(wait_time * 1000); - } - else - break; - } + while (rtas_busy_delay(rc)); if (rc < 0) return rtas_error_rc(rc); @@ -552,16 +538,14 @@ void rtas_os_term(char *str) snprintf(rtas_os_term_buf, 2048, "OS panic: %s", str); - do { + do status = rtas_call(rtas_token("ibm,os-term"), 1, 1, NULL, __pa(rtas_os_term_buf)); + while (rtas_busy_delay(status)); - if (status == RTAS_BUSY) - udelay(1); - else if (status != 0) - printk(KERN_EMERG "ibm,os-term call failed %d\n", + if (status != 0) + printk(KERN_EMERG "ibm,os-term call failed %d\n", status); - } while (status == RTAS_BUSY); } static int ibm_suspend_me_token = RTAS_UNKNOWN_SERVICE; @@ -789,7 +773,7 @@ EXPORT_SYMBOL(rtas_token); EXPORT_SYMBOL(rtas_call); EXPORT_SYMBOL(rtas_data_buf); EXPORT_SYMBOL(rtas_data_buf_lock); -EXPORT_SYMBOL(rtas_extended_busy_delay_time); +EXPORT_SYMBOL(rtas_busy_delay_time); EXPORT_SYMBOL(rtas_get_sensor); EXPORT_SYMBOL(rtas_get_power_level); EXPORT_SYMBOL(rtas_set_power_level); diff -puN arch/powerpc/kernel/rtas-rtc.c~rtas_delay_reorg arch/powerpc/kernel/rtas-rtc.c --- 2_6_linus/arch/powerpc/kernel/rtas-rtc.c~rtas_delay_reorg 2006-06-02 15:09:43.000000000 -0500 +++ 2_6_linus-johnrose/arch/powerpc/kernel/rtas-rtc.c 2006-06-02 15:09:43.000000000 -0500 @@ -14,19 +14,20 @@ unsigned long __init rtas_get_boot_time(void) { int ret[8]; - int error, wait_time; + int error; + unsigned int wait_time; u64 max_wait_tb; max_wait_tb = get_tb() + tb_ticks_per_usec * 1000 * MAX_RTC_WAIT; do { error = rtas_call(rtas_token("get-time-of-day"), 0, 8, ret); - if (error == RTAS_CLOCK_BUSY || rtas_is_extended_busy(error)) { - wait_time = rtas_extended_busy_delay_time(error); + + wait_time = rtas_busy_delay_time(error); + if (wait_time) { /* This is boot time so we spin. */ udelay(wait_time*1000); - error = RTAS_CLOCK_BUSY; } - } while (error == RTAS_CLOCK_BUSY && (get_tb() < max_wait_tb)); + } while (wait_time && (get_tb() < max_wait_tb)); if (error != 0 && printk_ratelimit()) { printk(KERN_WARNING "error: reading the clock failed (%d)\n", @@ -44,24 +45,25 @@ unsigned long __init rtas_get_boot_time( void rtas_get_rtc_time(struct rtc_time *rtc_tm) { int ret[8]; - int error, wait_time; + int error; + unsigned int wait_time; u64 max_wait_tb; max_wait_tb = get_tb() + tb_ticks_per_usec * 1000 * MAX_RTC_WAIT; do { error = rtas_call(rtas_token("get-time-of-day"), 0, 8, ret); - if (error == RTAS_CLOCK_BUSY || rtas_is_extended_busy(error)) { + + wait_time = rtas_busy_delay_time(error); + if (wait_time) { if (in_interrupt() && printk_ratelimit()) { memset(rtc_tm, 0, sizeof(struct rtc_time)); printk(KERN_WARNING "error: reading clock" " would delay interrupt\n"); return; /* delay not allowed */ } - wait_time = rtas_extended_busy_delay_time(error); msleep(wait_time); - error = RTAS_CLOCK_BUSY; } - } while (error == RTAS_CLOCK_BUSY && (get_tb() < max_wait_tb)); + } while (wait_time && (get_tb() < max_wait_tb)); if (error != 0 && printk_ratelimit()) { printk(KERN_WARNING "error: reading the clock failed (%d)\n", @@ -88,14 +90,14 @@ int rtas_set_rtc_time(struct rtc_time *t tm->tm_year + 1900, tm->tm_mon + 1, tm->tm_mday, tm->tm_hour, tm->tm_min, tm->tm_sec, 0); - if (error == RTAS_CLOCK_BUSY || rtas_is_extended_busy(error)) { + + wait_time = rtas_busy_delay_time(error); + if (wait_time) { if (in_interrupt()) return 1; /* probably decrementer */ - wait_time = rtas_extended_busy_delay_time(error); msleep(wait_time); - error = RTAS_CLOCK_BUSY; } - } while (error == RTAS_CLOCK_BUSY && (get_tb() < max_wait_tb)); + } while (wait_time && (get_tb() < max_wait_tb)); if (error != 0 && printk_ratelimit()) printk(KERN_WARNING "error: setting the clock failed (%d)\n", diff -puN include/asm-powerpc/rtas.h~rtas_delay_reorg include/asm-powerpc/rtas.h --- 2_6_linus/include/asm-powerpc/rtas.h~rtas_delay_reorg 2006-06-02 15:09:43.000000000 -0500 +++ 2_6_linus-johnrose/include/asm-powerpc/rtas.h 2006-06-02 15:09:43.000000000 -0500 @@ -177,12 +177,8 @@ extern unsigned long rtas_get_boot_time( extern void rtas_get_rtc_time(struct rtc_time *rtc_time); extern int rtas_set_rtc_time(struct rtc_time *rtc_time); -/* Given an RTAS status code of 9900..9905 compute the hinted delay */ -unsigned int rtas_extended_busy_delay_time(int status); -static inline int rtas_is_extended_busy(int status) -{ - return status >= 9900 && status <= 9909; -} +extern unsigned int rtas_busy_delay_time(int status); +extern unsigned int rtas_busy_delay(int status); extern void pSeries_log_error(char *buf, unsigned int err_type, int fatal); diff -puN arch/powerpc/kernel/rtas_flash.c~rtas_delay_reorg arch/powerpc/kernel/rtas_flash.c --- 2_6_linus/arch/powerpc/kernel/rtas_flash.c~rtas_delay_reorg 2006-06-02 15:09:43.000000000 -0500 +++ 2_6_linus-johnrose/arch/powerpc/kernel/rtas_flash.c 2006-06-02 15:09:43.000000000 -0500 @@ -365,20 +365,12 @@ static int rtas_excl_release(struct inod static void manage_flash(struct rtas_manage_flash_t *args_buf) { - unsigned int wait_time; s32 rc; - while (1) { + do rc = rtas_call(rtas_token("ibm,manage-flash-image"), 1, 1, NULL, args_buf->op); - if (rc == RTAS_RC_BUSY) - udelay(1); - else if (rtas_is_extended_busy(rc)) { - wait_time = rtas_extended_busy_delay_time(rc); - udelay(wait_time * 1000); - } else - break; - } + while (rtas_busy_delay(rc)); args_buf->status = rc; } @@ -451,27 +443,18 @@ static ssize_t manage_flash_write(struct static void validate_flash(struct rtas_validate_flash_t *args_buf) { int token = rtas_token("ibm,validate-flash-image"); - unsigned int wait_time; int update_results; s32 rc; rc = 0; - while(1) { + do { spin_lock(&rtas_data_buf_lock); memcpy(rtas_data_buf, args_buf->buf, VALIDATE_BUF_SIZE); rc = rtas_call(token, 2, 2, &update_results, (u32) __pa(rtas_data_buf), args_buf->buf_size); memcpy(args_buf->buf, rtas_data_buf, VALIDATE_BUF_SIZE); spin_unlock(&rtas_data_buf_lock); - - if (rc == RTAS_RC_BUSY) - udelay(1); - else if (rtas_is_extended_busy(rc)) { - wait_time = rtas_extended_busy_delay_time(rc); - udelay(wait_time * 1000); - } else - break; - } + } while (rtas_busy_delay(rc)); args_buf->status = rc; args_buf->update_results = update_results; _ ^ permalink raw reply [flat|nested] 16+ messages in thread
* Re: [PATCH] reorg RTAS delay code 2006-06-02 20:30 ` [PATCH] reorg RTAS delay code John Rose @ 2006-06-02 21:33 ` Nathan Lynch 2006-06-05 21:31 ` John Rose 0 siblings, 1 reply; 16+ messages in thread From: Nathan Lynch @ 2006-06-02 21:33 UTC (permalink / raw) To: John Rose; +Cc: Paul Mackerras, linuxppc-dev > +/* For an RTAS busy status code, perform the hinted delay. */ > +unsigned int rtas_busy_delay(int status) > +{ > + unsigned int ms; > > - return ms; > + ms = rtas_busy_delay_time(status); > + if (ms) > + msleep(ms); > + > + return ms; > } Can you put a might_sleep() at the beginning of this function so that we can reliably catch unsafe uses of it? Otherwise we'll get warnings only when a delay is actually executed. > @@ -438,22 +449,14 @@ int rtas_get_power_level(int powerdomain > int rtas_set_power_level(int powerdomain, int level, int *setlevel) > { > int token = rtas_token("set-power-level"); > - unsigned int wait_time; > int rc; > > if (token == RTAS_UNKNOWN_SERVICE) > return -ENOENT; > > - while (1) { > + do > rc = rtas_call(token, 2, 2, setlevel, powerdomain, level); > - if (rc == RTAS_BUSY) > - udelay(1); > - else if (rtas_is_extended_busy(rc)) { > - wait_time = rtas_extended_busy_delay_time(rc); > - udelay(wait_time * 1000); > - } else > - break; > - } > + while (rtas_busy_delay(rc)); Coding style nit -- am I alone in thinking that do/while without the brackets looks weird? Given the single-statement body of the loop, I guess the brackets aren't necessary, but omitting the brackets doesn't save lines in this case. ^ permalink raw reply [flat|nested] 16+ messages in thread
* [PATCH] reorg RTAS delay code 2006-06-02 21:33 ` Nathan Lynch @ 2006-06-05 21:31 ` John Rose 2006-06-05 21:54 ` Nathan Lynch ` (2 more replies) 0 siblings, 3 replies; 16+ messages in thread From: John Rose @ 2006-06-05 21:31 UTC (permalink / raw) To: Nathan Lynch; +Cc: Paul Mackerras, External List This patch attempts to handle RTAS "busy" return codes in a more simple and consistent manner. Typical callers of RTAS shouldn't have to manage wait times and delay calls. This patch also changes the kernel to use msleep() rather than udelay() when a runtime delay is necessary. This will avoid CPU soft lockups for extended delay conditions. Signed-off-by: John Rose <johnrose@austin.ibm.com> --- Resend - added the suggested might_sleep() and braces. Thanks- John 2_6_linus-johnrose/arch/powerpc/kernel/rtas-rtc.c | 30 +++---- 2_6_linus-johnrose/arch/powerpc/kernel/rtas.c | 85 ++++++++------------ 2_6_linus-johnrose/arch/powerpc/kernel/rtas_flash.c | 25 ----- 2_6_linus-johnrose/include/asm-powerpc/rtas.h | 8 - 4 files changed, 57 insertions(+), 91 deletions(-) diff -puN arch/powerpc/kernel/rtas.c~rtas_delay_reorg arch/powerpc/kernel/rtas.c --- 2_6_linus/arch/powerpc/kernel/rtas.c~rtas_delay_reorg 2006-06-02 15:09:43.000000000 -0500 +++ 2_6_linus-johnrose/arch/powerpc/kernel/rtas.c 2006-06-05 15:00:03.000000000 -0500 @@ -370,24 +370,36 @@ int rtas_call(int token, int nargs, int return ret; } -/* Given an RTAS status code of 990n compute the hinted delay of 10^n - * (last digit) milliseconds. For now we bound at n=5 (100 sec). +/* For RTAS_BUSY (-2), delay for 1 millisecond. For an extended busy status + * code of 990n, perform the hinted delay of 10^n (last digit) milliseconds. */ -unsigned int rtas_extended_busy_delay_time(int status) +unsigned int rtas_busy_delay_time(int status) { - int order = status - 9900; - unsigned long ms; + int order; + unsigned int ms = 0; - if (order < 0) - order = 0; /* RTC depends on this for -2 clock busy */ - else if (order > 5) - order = 5; /* bound */ + if (status == RTAS_BUSY) { + ms = 1; + } else if (status >= 9900 && status <= 9905) { + order = status - 9900; + for (ms = 1; order > 0; order--) + ms *= 10; + } + + return ms; +} + +/* For an RTAS busy status code, perform the hinted delay. */ +unsigned int rtas_busy_delay(int status) +{ + unsigned int ms; - /* Use microseconds for reasonable accuracy */ - for (ms = 1; order > 0; order--) - ms *= 10; + might_sleep(); + ms = rtas_busy_delay_time(status); + if (ms) + msleep(ms); - return ms; + return ms; } int rtas_error_rc(int rtas_rc) @@ -438,22 +450,14 @@ int rtas_get_power_level(int powerdomain int rtas_set_power_level(int powerdomain, int level, int *setlevel) { int token = rtas_token("set-power-level"); - unsigned int wait_time; int rc; if (token == RTAS_UNKNOWN_SERVICE) return -ENOENT; - while (1) { + do { rc = rtas_call(token, 2, 2, setlevel, powerdomain, level); - if (rc == RTAS_BUSY) - udelay(1); - else if (rtas_is_extended_busy(rc)) { - wait_time = rtas_extended_busy_delay_time(rc); - udelay(wait_time * 1000); - } else - break; - } + } while (rtas_busy_delay(rc)); if (rc < 0) return rtas_error_rc(rc); @@ -463,22 +467,14 @@ int rtas_set_power_level(int powerdomain int rtas_get_sensor(int sensor, int index, int *state) { int token = rtas_token("get-sensor-state"); - unsigned int wait_time; int rc; if (token == RTAS_UNKNOWN_SERVICE) return -ENOENT; - while (1) { + do { rc = rtas_call(token, 2, 2, state, sensor, index); - if (rc == RTAS_BUSY) - udelay(1); - else if (rtas_is_extended_busy(rc)) { - wait_time = rtas_extended_busy_delay_time(rc); - udelay(wait_time * 1000); - } else - break; - } + } while (rtas_busy_delay(rc)); if (rc < 0) return rtas_error_rc(rc); @@ -488,23 +484,14 @@ int rtas_get_sensor(int sensor, int inde int rtas_set_indicator(int indicator, int index, int new_value) { int token = rtas_token("set-indicator"); - unsigned int wait_time; int rc; if (token == RTAS_UNKNOWN_SERVICE) return -ENOENT; - while (1) { + do { rc = rtas_call(token, 3, 1, NULL, indicator, index, new_value); - if (rc == RTAS_BUSY) - udelay(1); - else if (rtas_is_extended_busy(rc)) { - wait_time = rtas_extended_busy_delay_time(rc); - udelay(wait_time * 1000); - } - else - break; - } + } while (rtas_busy_delay(rc)); if (rc < 0) return rtas_error_rc(rc); @@ -555,13 +542,11 @@ void rtas_os_term(char *str) do { status = rtas_call(rtas_token("ibm,os-term"), 1, 1, NULL, __pa(rtas_os_term_buf)); + } while (rtas_busy_delay(status)); - if (status == RTAS_BUSY) - udelay(1); - else if (status != 0) - printk(KERN_EMERG "ibm,os-term call failed %d\n", + if (status != 0) + printk(KERN_EMERG "ibm,os-term call failed %d\n", status); - } while (status == RTAS_BUSY); } static int ibm_suspend_me_token = RTAS_UNKNOWN_SERVICE; @@ -789,7 +774,7 @@ EXPORT_SYMBOL(rtas_token); EXPORT_SYMBOL(rtas_call); EXPORT_SYMBOL(rtas_data_buf); EXPORT_SYMBOL(rtas_data_buf_lock); -EXPORT_SYMBOL(rtas_extended_busy_delay_time); +EXPORT_SYMBOL(rtas_busy_delay_time); EXPORT_SYMBOL(rtas_get_sensor); EXPORT_SYMBOL(rtas_get_power_level); EXPORT_SYMBOL(rtas_set_power_level); diff -puN arch/powerpc/kernel/rtas-rtc.c~rtas_delay_reorg arch/powerpc/kernel/rtas-rtc.c --- 2_6_linus/arch/powerpc/kernel/rtas-rtc.c~rtas_delay_reorg 2006-06-02 15:09:43.000000000 -0500 +++ 2_6_linus-johnrose/arch/powerpc/kernel/rtas-rtc.c 2006-06-02 15:09:43.000000000 -0500 @@ -14,19 +14,20 @@ unsigned long __init rtas_get_boot_time(void) { int ret[8]; - int error, wait_time; + int error; + unsigned int wait_time; u64 max_wait_tb; max_wait_tb = get_tb() + tb_ticks_per_usec * 1000 * MAX_RTC_WAIT; do { error = rtas_call(rtas_token("get-time-of-day"), 0, 8, ret); - if (error == RTAS_CLOCK_BUSY || rtas_is_extended_busy(error)) { - wait_time = rtas_extended_busy_delay_time(error); + + wait_time = rtas_busy_delay_time(error); + if (wait_time) { /* This is boot time so we spin. */ udelay(wait_time*1000); - error = RTAS_CLOCK_BUSY; } - } while (error == RTAS_CLOCK_BUSY && (get_tb() < max_wait_tb)); + } while (wait_time && (get_tb() < max_wait_tb)); if (error != 0 && printk_ratelimit()) { printk(KERN_WARNING "error: reading the clock failed (%d)\n", @@ -44,24 +45,25 @@ unsigned long __init rtas_get_boot_time( void rtas_get_rtc_time(struct rtc_time *rtc_tm) { int ret[8]; - int error, wait_time; + int error; + unsigned int wait_time; u64 max_wait_tb; max_wait_tb = get_tb() + tb_ticks_per_usec * 1000 * MAX_RTC_WAIT; do { error = rtas_call(rtas_token("get-time-of-day"), 0, 8, ret); - if (error == RTAS_CLOCK_BUSY || rtas_is_extended_busy(error)) { + + wait_time = rtas_busy_delay_time(error); + if (wait_time) { if (in_interrupt() && printk_ratelimit()) { memset(rtc_tm, 0, sizeof(struct rtc_time)); printk(KERN_WARNING "error: reading clock" " would delay interrupt\n"); return; /* delay not allowed */ } - wait_time = rtas_extended_busy_delay_time(error); msleep(wait_time); - error = RTAS_CLOCK_BUSY; } - } while (error == RTAS_CLOCK_BUSY && (get_tb() < max_wait_tb)); + } while (wait_time && (get_tb() < max_wait_tb)); if (error != 0 && printk_ratelimit()) { printk(KERN_WARNING "error: reading the clock failed (%d)\n", @@ -88,14 +90,14 @@ int rtas_set_rtc_time(struct rtc_time *t tm->tm_year + 1900, tm->tm_mon + 1, tm->tm_mday, tm->tm_hour, tm->tm_min, tm->tm_sec, 0); - if (error == RTAS_CLOCK_BUSY || rtas_is_extended_busy(error)) { + + wait_time = rtas_busy_delay_time(error); + if (wait_time) { if (in_interrupt()) return 1; /* probably decrementer */ - wait_time = rtas_extended_busy_delay_time(error); msleep(wait_time); - error = RTAS_CLOCK_BUSY; } - } while (error == RTAS_CLOCK_BUSY && (get_tb() < max_wait_tb)); + } while (wait_time && (get_tb() < max_wait_tb)); if (error != 0 && printk_ratelimit()) printk(KERN_WARNING "error: setting the clock failed (%d)\n", diff -puN include/asm-powerpc/rtas.h~rtas_delay_reorg include/asm-powerpc/rtas.h --- 2_6_linus/include/asm-powerpc/rtas.h~rtas_delay_reorg 2006-06-02 15:09:43.000000000 -0500 +++ 2_6_linus-johnrose/include/asm-powerpc/rtas.h 2006-06-02 15:09:43.000000000 -0500 @@ -177,12 +177,8 @@ extern unsigned long rtas_get_boot_time( extern void rtas_get_rtc_time(struct rtc_time *rtc_time); extern int rtas_set_rtc_time(struct rtc_time *rtc_time); -/* Given an RTAS status code of 9900..9905 compute the hinted delay */ -unsigned int rtas_extended_busy_delay_time(int status); -static inline int rtas_is_extended_busy(int status) -{ - return status >= 9900 && status <= 9909; -} +extern unsigned int rtas_busy_delay_time(int status); +extern unsigned int rtas_busy_delay(int status); extern void pSeries_log_error(char *buf, unsigned int err_type, int fatal); diff -puN arch/powerpc/kernel/rtas_flash.c~rtas_delay_reorg arch/powerpc/kernel/rtas_flash.c --- 2_6_linus/arch/powerpc/kernel/rtas_flash.c~rtas_delay_reorg 2006-06-02 15:09:43.000000000 -0500 +++ 2_6_linus-johnrose/arch/powerpc/kernel/rtas_flash.c 2006-06-05 15:00:44.000000000 -0500 @@ -365,20 +365,12 @@ static int rtas_excl_release(struct inod static void manage_flash(struct rtas_manage_flash_t *args_buf) { - unsigned int wait_time; s32 rc; - while (1) { + do { rc = rtas_call(rtas_token("ibm,manage-flash-image"), 1, 1, NULL, args_buf->op); - if (rc == RTAS_RC_BUSY) - udelay(1); - else if (rtas_is_extended_busy(rc)) { - wait_time = rtas_extended_busy_delay_time(rc); - udelay(wait_time * 1000); - } else - break; - } + } while (rtas_busy_delay(rc)); args_buf->status = rc; } @@ -451,27 +443,18 @@ static ssize_t manage_flash_write(struct static void validate_flash(struct rtas_validate_flash_t *args_buf) { int token = rtas_token("ibm,validate-flash-image"); - unsigned int wait_time; int update_results; s32 rc; rc = 0; - while(1) { + do { spin_lock(&rtas_data_buf_lock); memcpy(rtas_data_buf, args_buf->buf, VALIDATE_BUF_SIZE); rc = rtas_call(token, 2, 2, &update_results, (u32) __pa(rtas_data_buf), args_buf->buf_size); memcpy(args_buf->buf, rtas_data_buf, VALIDATE_BUF_SIZE); spin_unlock(&rtas_data_buf_lock); - - if (rc == RTAS_RC_BUSY) - udelay(1); - else if (rtas_is_extended_busy(rc)) { - wait_time = rtas_extended_busy_delay_time(rc); - udelay(wait_time * 1000); - } else - break; - } + } while (rtas_busy_delay(rc)); args_buf->status = rc; args_buf->update_results = update_results; _ ^ permalink raw reply [flat|nested] 16+ messages in thread
* Re: [PATCH] reorg RTAS delay code 2006-06-05 21:31 ` John Rose @ 2006-06-05 21:54 ` Nathan Lynch 2006-06-10 2:04 ` Anton Blanchard 2006-07-13 18:20 ` [PATCH] reorg RTAS delay code Nathan Lynch 2 siblings, 0 replies; 16+ messages in thread From: Nathan Lynch @ 2006-06-05 21:54 UTC (permalink / raw) To: John Rose; +Cc: Paul Mackerras, External List John Rose wrote: > This patch attempts to handle RTAS "busy" return codes in a more simple > and consistent manner. Typical callers of RTAS shouldn't have to > manage wait times and delay calls. > > This patch also changes the kernel to use msleep() rather than udelay() > when a runtime delay is necessary. This will avoid CPU soft lockups > for extended delay conditions. > > Signed-off-by: John Rose <johnrose@austin.ibm.com> > > --- > > Resend - added the suggested might_sleep() and braces. FWIW: Acked-by: Nathan Lynch <ntl@pobox.com> > 2_6_linus-johnrose/arch/powerpc/kernel/rtas-rtc.c | 30 +++---- > 2_6_linus-johnrose/arch/powerpc/kernel/rtas.c | 85 ++++++++------------ > 2_6_linus-johnrose/arch/powerpc/kernel/rtas_flash.c | 25 ----- > 2_6_linus-johnrose/include/asm-powerpc/rtas.h | 8 - > 4 files changed, 57 insertions(+), 91 deletions(-) > > diff -puN arch/powerpc/kernel/rtas.c~rtas_delay_reorg arch/powerpc/kernel/rtas.c > --- 2_6_linus/arch/powerpc/kernel/rtas.c~rtas_delay_reorg 2006-06-02 15:09:43.000000000 -0500 > +++ 2_6_linus-johnrose/arch/powerpc/kernel/rtas.c 2006-06-05 15:00:03.000000000 -0500 > @@ -370,24 +370,36 @@ int rtas_call(int token, int nargs, int > return ret; > } > > -/* Given an RTAS status code of 990n compute the hinted delay of 10^n > - * (last digit) milliseconds. For now we bound at n=5 (100 sec). > +/* For RTAS_BUSY (-2), delay for 1 millisecond. For an extended busy status > + * code of 990n, perform the hinted delay of 10^n (last digit) milliseconds. > */ > -unsigned int rtas_extended_busy_delay_time(int status) > +unsigned int rtas_busy_delay_time(int status) > { > - int order = status - 9900; > - unsigned long ms; > + int order; > + unsigned int ms = 0; > > - if (order < 0) > - order = 0; /* RTC depends on this for -2 clock busy */ > - else if (order > 5) > - order = 5; /* bound */ > + if (status == RTAS_BUSY) { > + ms = 1; > + } else if (status >= 9900 && status <= 9905) { > + order = status - 9900; > + for (ms = 1; order > 0; order--) > + ms *= 10; > + } > + > + return ms; > +} > + > +/* For an RTAS busy status code, perform the hinted delay. */ > +unsigned int rtas_busy_delay(int status) > +{ > + unsigned int ms; > > - /* Use microseconds for reasonable accuracy */ > - for (ms = 1; order > 0; order--) > - ms *= 10; > + might_sleep(); > + ms = rtas_busy_delay_time(status); > + if (ms) > + msleep(ms); > > - return ms; > + return ms; > } > > int rtas_error_rc(int rtas_rc) > @@ -438,22 +450,14 @@ int rtas_get_power_level(int powerdomain > int rtas_set_power_level(int powerdomain, int level, int *setlevel) > { > int token = rtas_token("set-power-level"); > - unsigned int wait_time; > int rc; > > if (token == RTAS_UNKNOWN_SERVICE) > return -ENOENT; > > - while (1) { > + do { > rc = rtas_call(token, 2, 2, setlevel, powerdomain, level); > - if (rc == RTAS_BUSY) > - udelay(1); > - else if (rtas_is_extended_busy(rc)) { > - wait_time = rtas_extended_busy_delay_time(rc); > - udelay(wait_time * 1000); > - } else > - break; > - } > + } while (rtas_busy_delay(rc)); > > if (rc < 0) > return rtas_error_rc(rc); > @@ -463,22 +467,14 @@ int rtas_set_power_level(int powerdomain > int rtas_get_sensor(int sensor, int index, int *state) > { > int token = rtas_token("get-sensor-state"); > - unsigned int wait_time; > int rc; > > if (token == RTAS_UNKNOWN_SERVICE) > return -ENOENT; > > - while (1) { > + do { > rc = rtas_call(token, 2, 2, state, sensor, index); > - if (rc == RTAS_BUSY) > - udelay(1); > - else if (rtas_is_extended_busy(rc)) { > - wait_time = rtas_extended_busy_delay_time(rc); > - udelay(wait_time * 1000); > - } else > - break; > - } > + } while (rtas_busy_delay(rc)); > > if (rc < 0) > return rtas_error_rc(rc); > @@ -488,23 +484,14 @@ int rtas_get_sensor(int sensor, int inde > int rtas_set_indicator(int indicator, int index, int new_value) > { > int token = rtas_token("set-indicator"); > - unsigned int wait_time; > int rc; > > if (token == RTAS_UNKNOWN_SERVICE) > return -ENOENT; > > - while (1) { > + do { > rc = rtas_call(token, 3, 1, NULL, indicator, index, new_value); > - if (rc == RTAS_BUSY) > - udelay(1); > - else if (rtas_is_extended_busy(rc)) { > - wait_time = rtas_extended_busy_delay_time(rc); > - udelay(wait_time * 1000); > - } > - else > - break; > - } > + } while (rtas_busy_delay(rc)); > > if (rc < 0) > return rtas_error_rc(rc); > @@ -555,13 +542,11 @@ void rtas_os_term(char *str) > do { > status = rtas_call(rtas_token("ibm,os-term"), 1, 1, NULL, > __pa(rtas_os_term_buf)); > + } while (rtas_busy_delay(status)); > > - if (status == RTAS_BUSY) > - udelay(1); > - else if (status != 0) > - printk(KERN_EMERG "ibm,os-term call failed %d\n", > + if (status != 0) > + printk(KERN_EMERG "ibm,os-term call failed %d\n", > status); > - } while (status == RTAS_BUSY); > } > > static int ibm_suspend_me_token = RTAS_UNKNOWN_SERVICE; > @@ -789,7 +774,7 @@ EXPORT_SYMBOL(rtas_token); > EXPORT_SYMBOL(rtas_call); > EXPORT_SYMBOL(rtas_data_buf); > EXPORT_SYMBOL(rtas_data_buf_lock); > -EXPORT_SYMBOL(rtas_extended_busy_delay_time); > +EXPORT_SYMBOL(rtas_busy_delay_time); > EXPORT_SYMBOL(rtas_get_sensor); > EXPORT_SYMBOL(rtas_get_power_level); > EXPORT_SYMBOL(rtas_set_power_level); > diff -puN arch/powerpc/kernel/rtas-rtc.c~rtas_delay_reorg arch/powerpc/kernel/rtas-rtc.c > --- 2_6_linus/arch/powerpc/kernel/rtas-rtc.c~rtas_delay_reorg 2006-06-02 15:09:43.000000000 -0500 > +++ 2_6_linus-johnrose/arch/powerpc/kernel/rtas-rtc.c 2006-06-02 15:09:43.000000000 -0500 > @@ -14,19 +14,20 @@ > unsigned long __init rtas_get_boot_time(void) > { > int ret[8]; > - int error, wait_time; > + int error; > + unsigned int wait_time; > u64 max_wait_tb; > > max_wait_tb = get_tb() + tb_ticks_per_usec * 1000 * MAX_RTC_WAIT; > do { > error = rtas_call(rtas_token("get-time-of-day"), 0, 8, ret); > - if (error == RTAS_CLOCK_BUSY || rtas_is_extended_busy(error)) { > - wait_time = rtas_extended_busy_delay_time(error); > + > + wait_time = rtas_busy_delay_time(error); > + if (wait_time) { > /* This is boot time so we spin. */ > udelay(wait_time*1000); > - error = RTAS_CLOCK_BUSY; > } > - } while (error == RTAS_CLOCK_BUSY && (get_tb() < max_wait_tb)); > + } while (wait_time && (get_tb() < max_wait_tb)); > > if (error != 0 && printk_ratelimit()) { > printk(KERN_WARNING "error: reading the clock failed (%d)\n", > @@ -44,24 +45,25 @@ unsigned long __init rtas_get_boot_time( > void rtas_get_rtc_time(struct rtc_time *rtc_tm) > { > int ret[8]; > - int error, wait_time; > + int error; > + unsigned int wait_time; > u64 max_wait_tb; > > max_wait_tb = get_tb() + tb_ticks_per_usec * 1000 * MAX_RTC_WAIT; > do { > error = rtas_call(rtas_token("get-time-of-day"), 0, 8, ret); > - if (error == RTAS_CLOCK_BUSY || rtas_is_extended_busy(error)) { > + > + wait_time = rtas_busy_delay_time(error); > + if (wait_time) { > if (in_interrupt() && printk_ratelimit()) { > memset(rtc_tm, 0, sizeof(struct rtc_time)); > printk(KERN_WARNING "error: reading clock" > " would delay interrupt\n"); > return; /* delay not allowed */ > } > - wait_time = rtas_extended_busy_delay_time(error); > msleep(wait_time); > - error = RTAS_CLOCK_BUSY; > } > - } while (error == RTAS_CLOCK_BUSY && (get_tb() < max_wait_tb)); > + } while (wait_time && (get_tb() < max_wait_tb)); > > if (error != 0 && printk_ratelimit()) { > printk(KERN_WARNING "error: reading the clock failed (%d)\n", > @@ -88,14 +90,14 @@ int rtas_set_rtc_time(struct rtc_time *t > tm->tm_year + 1900, tm->tm_mon + 1, > tm->tm_mday, tm->tm_hour, tm->tm_min, > tm->tm_sec, 0); > - if (error == RTAS_CLOCK_BUSY || rtas_is_extended_busy(error)) { > + > + wait_time = rtas_busy_delay_time(error); > + if (wait_time) { > if (in_interrupt()) > return 1; /* probably decrementer */ > - wait_time = rtas_extended_busy_delay_time(error); > msleep(wait_time); > - error = RTAS_CLOCK_BUSY; > } > - } while (error == RTAS_CLOCK_BUSY && (get_tb() < max_wait_tb)); > + } while (wait_time && (get_tb() < max_wait_tb)); > > if (error != 0 && printk_ratelimit()) > printk(KERN_WARNING "error: setting the clock failed (%d)\n", > diff -puN include/asm-powerpc/rtas.h~rtas_delay_reorg include/asm-powerpc/rtas.h > --- 2_6_linus/include/asm-powerpc/rtas.h~rtas_delay_reorg 2006-06-02 15:09:43.000000000 -0500 > +++ 2_6_linus-johnrose/include/asm-powerpc/rtas.h 2006-06-02 15:09:43.000000000 -0500 > @@ -177,12 +177,8 @@ extern unsigned long rtas_get_boot_time( > extern void rtas_get_rtc_time(struct rtc_time *rtc_time); > extern int rtas_set_rtc_time(struct rtc_time *rtc_time); > > -/* Given an RTAS status code of 9900..9905 compute the hinted delay */ > -unsigned int rtas_extended_busy_delay_time(int status); > -static inline int rtas_is_extended_busy(int status) > -{ > - return status >= 9900 && status <= 9909; > -} > +extern unsigned int rtas_busy_delay_time(int status); > +extern unsigned int rtas_busy_delay(int status); > > extern void pSeries_log_error(char *buf, unsigned int err_type, int fatal); > > diff -puN arch/powerpc/kernel/rtas_flash.c~rtas_delay_reorg arch/powerpc/kernel/rtas_flash.c > --- 2_6_linus/arch/powerpc/kernel/rtas_flash.c~rtas_delay_reorg 2006-06-02 15:09:43.000000000 -0500 > +++ 2_6_linus-johnrose/arch/powerpc/kernel/rtas_flash.c 2006-06-05 15:00:44.000000000 -0500 > @@ -365,20 +365,12 @@ static int rtas_excl_release(struct inod > > static void manage_flash(struct rtas_manage_flash_t *args_buf) > { > - unsigned int wait_time; > s32 rc; > > - while (1) { > + do { > rc = rtas_call(rtas_token("ibm,manage-flash-image"), 1, > 1, NULL, args_buf->op); > - if (rc == RTAS_RC_BUSY) > - udelay(1); > - else if (rtas_is_extended_busy(rc)) { > - wait_time = rtas_extended_busy_delay_time(rc); > - udelay(wait_time * 1000); > - } else > - break; > - } > + } while (rtas_busy_delay(rc)); > > args_buf->status = rc; > } > @@ -451,27 +443,18 @@ static ssize_t manage_flash_write(struct > static void validate_flash(struct rtas_validate_flash_t *args_buf) > { > int token = rtas_token("ibm,validate-flash-image"); > - unsigned int wait_time; > int update_results; > s32 rc; > > rc = 0; > - while(1) { > + do { > spin_lock(&rtas_data_buf_lock); > memcpy(rtas_data_buf, args_buf->buf, VALIDATE_BUF_SIZE); > rc = rtas_call(token, 2, 2, &update_results, > (u32) __pa(rtas_data_buf), args_buf->buf_size); > memcpy(args_buf->buf, rtas_data_buf, VALIDATE_BUF_SIZE); > spin_unlock(&rtas_data_buf_lock); > - > - if (rc == RTAS_RC_BUSY) > - udelay(1); > - else if (rtas_is_extended_busy(rc)) { > - wait_time = rtas_extended_busy_delay_time(rc); > - udelay(wait_time * 1000); > - } else > - break; > - } > + } while (rtas_busy_delay(rc)); > > args_buf->status = rc; > args_buf->update_results = update_results; > > _ > > ^ permalink raw reply [flat|nested] 16+ messages in thread
* Re: [PATCH] reorg RTAS delay code 2006-06-05 21:31 ` John Rose 2006-06-05 21:54 ` Nathan Lynch @ 2006-06-10 2:04 ` Anton Blanchard 2006-06-10 2:08 ` Anton Blanchard 2006-07-13 18:20 ` [PATCH] reorg RTAS delay code Nathan Lynch 2 siblings, 1 reply; 16+ messages in thread From: Anton Blanchard @ 2006-06-10 2:04 UTC (permalink / raw) To: John Rose; +Cc: Paul Mackerras, Nathan Lynch, External List Hi John, > This patch attempts to handle RTAS "busy" return codes in a more simple > and consistent manner. Typical callers of RTAS shouldn't have to > manage wait times and delay calls. > > This patch also changes the kernel to use msleep() rather than udelay() > when a runtime delay is necessary. This will avoid CPU soft lockups > for extended delay conditions. Looks like you missed one: WARNING: ".rtas_extended_busy_delay_time" [arch/powerpc/platforms/pseries/scanlog.ko] undefined! Anton ^ permalink raw reply [flat|nested] 16+ messages in thread
* Re: [PATCH] reorg RTAS delay code 2006-06-10 2:04 ` Anton Blanchard @ 2006-06-10 2:08 ` Anton Blanchard 2006-06-12 16:18 ` John Rose 0 siblings, 1 reply; 16+ messages in thread From: Anton Blanchard @ 2006-06-10 2:08 UTC (permalink / raw) To: John Rose; +Cc: Paul Mackerras, Nathan Lynch, External List > Looks like you missed one: > > WARNING: ".rtas_extended_busy_delay_time" [arch/powerpc/platforms/pseries/scanlog.ko] undefined! And a missing export: WARNING: ".rtas_busy_delay" [arch/powerpc/kernel/rtas_flash.ko] undefined! ANton ^ permalink raw reply [flat|nested] 16+ messages in thread
* Re: [PATCH] reorg RTAS delay code 2006-06-10 2:08 ` Anton Blanchard @ 2006-06-12 16:18 ` John Rose [not found] ` <17553.4390.79327.634945@cargo.ozlabs.ibm.com> 0 siblings, 1 reply; 16+ messages in thread From: John Rose @ 2006-06-12 16:18 UTC (permalink / raw) To: Anton Blanchard; +Cc: Paul Mackerras, Nathan Lynch, External List This patch attempts to handle RTAS "busy" return codes in a more simple and consistent manner. Typical callers of RTAS shouldn't have to manage wait times and delay calls. This patch also changes the kernel to use msleep() rather than udelay() when a runtime delay is necessary. This will avoid CPU soft lockups for extended delay conditions. Signed-off-by: John Rose <johnrose@austin.ibm.com> --- Resend - Addressed module build breaks. Thanks Anton. Thanks- John --- 2_6_linus-johnrose/arch/powerpc/kernel/rtas-rtc.c | 30 ++-- 2_6_linus-johnrose/arch/powerpc/kernel/rtas.c | 86 +++++------- 2_6_linus-johnrose/arch/powerpc/kernel/rtas_flash.c | 25 --- 2_6_linus-johnrose/arch/powerpc/platforms/pseries/scanlog.c | 6 2_6_linus-johnrose/include/asm-powerpc/rtas.h | 8 - 5 files changed, 61 insertions(+), 94 deletions(-) diff -puN arch/powerpc/kernel/rtas-rtc.c~rtas_delay_reorg arch/powerpc/kernel/rtas-rtc.c --- 2_6_linus/arch/powerpc/kernel/rtas-rtc.c~rtas_delay_reorg 2006-06-12 11:21:29.000000000 -0500 +++ 2_6_linus-johnrose/arch/powerpc/kernel/rtas-rtc.c 2006-06-12 11:21:29.000000000 -0500 @@ -14,19 +14,20 @@ unsigned long __init rtas_get_boot_time(void) { int ret[8]; - int error, wait_time; + int error; + unsigned int wait_time; u64 max_wait_tb; max_wait_tb = get_tb() + tb_ticks_per_usec * 1000 * MAX_RTC_WAIT; do { error = rtas_call(rtas_token("get-time-of-day"), 0, 8, ret); - if (error == RTAS_CLOCK_BUSY || rtas_is_extended_busy(error)) { - wait_time = rtas_extended_busy_delay_time(error); + + wait_time = rtas_busy_delay_time(error); + if (wait_time) { /* This is boot time so we spin. */ udelay(wait_time*1000); - error = RTAS_CLOCK_BUSY; } - } while (error == RTAS_CLOCK_BUSY && (get_tb() < max_wait_tb)); + } while (wait_time && (get_tb() < max_wait_tb)); if (error != 0 && printk_ratelimit()) { printk(KERN_WARNING "error: reading the clock failed (%d)\n", @@ -44,24 +45,25 @@ unsigned long __init rtas_get_boot_time( void rtas_get_rtc_time(struct rtc_time *rtc_tm) { int ret[8]; - int error, wait_time; + int error; + unsigned int wait_time; u64 max_wait_tb; max_wait_tb = get_tb() + tb_ticks_per_usec * 1000 * MAX_RTC_WAIT; do { error = rtas_call(rtas_token("get-time-of-day"), 0, 8, ret); - if (error == RTAS_CLOCK_BUSY || rtas_is_extended_busy(error)) { + + wait_time = rtas_busy_delay_time(error); + if (wait_time) { if (in_interrupt() && printk_ratelimit()) { memset(rtc_tm, 0, sizeof(struct rtc_time)); printk(KERN_WARNING "error: reading clock" " would delay interrupt\n"); return; /* delay not allowed */ } - wait_time = rtas_extended_busy_delay_time(error); msleep(wait_time); - error = RTAS_CLOCK_BUSY; } - } while (error == RTAS_CLOCK_BUSY && (get_tb() < max_wait_tb)); + } while (wait_time && (get_tb() < max_wait_tb)); if (error != 0 && printk_ratelimit()) { printk(KERN_WARNING "error: reading the clock failed (%d)\n", @@ -88,14 +90,14 @@ int rtas_set_rtc_time(struct rtc_time *t tm->tm_year + 1900, tm->tm_mon + 1, tm->tm_mday, tm->tm_hour, tm->tm_min, tm->tm_sec, 0); - if (error == RTAS_CLOCK_BUSY || rtas_is_extended_busy(error)) { + + wait_time = rtas_busy_delay_time(error); + if (wait_time) { if (in_interrupt()) return 1; /* probably decrementer */ - wait_time = rtas_extended_busy_delay_time(error); msleep(wait_time); - error = RTAS_CLOCK_BUSY; } - } while (error == RTAS_CLOCK_BUSY && (get_tb() < max_wait_tb)); + } while (wait_time && (get_tb() < max_wait_tb)); if (error != 0 && printk_ratelimit()) printk(KERN_WARNING "error: setting the clock failed (%d)\n", diff -puN arch/powerpc/kernel/rtas.c~rtas_delay_reorg arch/powerpc/kernel/rtas.c --- 2_6_linus/arch/powerpc/kernel/rtas.c~rtas_delay_reorg 2006-06-12 11:21:29.000000000 -0500 +++ 2_6_linus-johnrose/arch/powerpc/kernel/rtas.c 2006-06-12 11:21:29.000000000 -0500 @@ -370,24 +370,36 @@ int rtas_call(int token, int nargs, int return ret; } -/* Given an RTAS status code of 990n compute the hinted delay of 10^n - * (last digit) milliseconds. For now we bound at n=5 (100 sec). +/* For RTAS_BUSY (-2), delay for 1 millisecond. For an extended busy status + * code of 990n, perform the hinted delay of 10^n (last digit) milliseconds. */ -unsigned int rtas_extended_busy_delay_time(int status) +unsigned int rtas_busy_delay_time(int status) { - int order = status - 9900; - unsigned long ms; + int order; + unsigned int ms = 0; - if (order < 0) - order = 0; /* RTC depends on this for -2 clock busy */ - else if (order > 5) - order = 5; /* bound */ + if (status == RTAS_BUSY) { + ms = 1; + } else if (status >= 9900 && status <= 9905) { + order = status - 9900; + for (ms = 1; order > 0; order--) + ms *= 10; + } + + return ms; +} + +/* For an RTAS busy status code, perform the hinted delay. */ +unsigned int rtas_busy_delay(int status) +{ + unsigned int ms; - /* Use microseconds for reasonable accuracy */ - for (ms = 1; order > 0; order--) - ms *= 10; + might_sleep(); + ms = rtas_busy_delay_time(status); + if (ms) + msleep(ms); - return ms; + return ms; } int rtas_error_rc(int rtas_rc) @@ -438,22 +450,14 @@ int rtas_get_power_level(int powerdomain int rtas_set_power_level(int powerdomain, int level, int *setlevel) { int token = rtas_token("set-power-level"); - unsigned int wait_time; int rc; if (token == RTAS_UNKNOWN_SERVICE) return -ENOENT; - while (1) { + do { rc = rtas_call(token, 2, 2, setlevel, powerdomain, level); - if (rc == RTAS_BUSY) - udelay(1); - else if (rtas_is_extended_busy(rc)) { - wait_time = rtas_extended_busy_delay_time(rc); - udelay(wait_time * 1000); - } else - break; - } + } while (rtas_busy_delay(rc)); if (rc < 0) return rtas_error_rc(rc); @@ -463,22 +467,14 @@ int rtas_set_power_level(int powerdomain int rtas_get_sensor(int sensor, int index, int *state) { int token = rtas_token("get-sensor-state"); - unsigned int wait_time; int rc; if (token == RTAS_UNKNOWN_SERVICE) return -ENOENT; - while (1) { + do { rc = rtas_call(token, 2, 2, state, sensor, index); - if (rc == RTAS_BUSY) - udelay(1); - else if (rtas_is_extended_busy(rc)) { - wait_time = rtas_extended_busy_delay_time(rc); - udelay(wait_time * 1000); - } else - break; - } + } while (rtas_busy_delay(rc)); if (rc < 0) return rtas_error_rc(rc); @@ -488,23 +484,14 @@ int rtas_get_sensor(int sensor, int inde int rtas_set_indicator(int indicator, int index, int new_value) { int token = rtas_token("set-indicator"); - unsigned int wait_time; int rc; if (token == RTAS_UNKNOWN_SERVICE) return -ENOENT; - while (1) { + do { rc = rtas_call(token, 3, 1, NULL, indicator, index, new_value); - if (rc == RTAS_BUSY) - udelay(1); - else if (rtas_is_extended_busy(rc)) { - wait_time = rtas_extended_busy_delay_time(rc); - udelay(wait_time * 1000); - } - else - break; - } + } while (rtas_busy_delay(rc)); if (rc < 0) return rtas_error_rc(rc); @@ -555,13 +542,11 @@ void rtas_os_term(char *str) do { status = rtas_call(rtas_token("ibm,os-term"), 1, 1, NULL, __pa(rtas_os_term_buf)); + } while (rtas_busy_delay(status)); - if (status == RTAS_BUSY) - udelay(1); - else if (status != 0) - printk(KERN_EMERG "ibm,os-term call failed %d\n", + if (status != 0) + printk(KERN_EMERG "ibm,os-term call failed %d\n", status); - } while (status == RTAS_BUSY); } static int ibm_suspend_me_token = RTAS_UNKNOWN_SERVICE; @@ -789,7 +774,8 @@ EXPORT_SYMBOL(rtas_token); EXPORT_SYMBOL(rtas_call); EXPORT_SYMBOL(rtas_data_buf); EXPORT_SYMBOL(rtas_data_buf_lock); -EXPORT_SYMBOL(rtas_extended_busy_delay_time); +EXPORT_SYMBOL(rtas_busy_delay); +EXPORT_SYMBOL(rtas_busy_delay_time); EXPORT_SYMBOL(rtas_get_sensor); EXPORT_SYMBOL(rtas_get_power_level); EXPORT_SYMBOL(rtas_set_power_level); diff -puN arch/powerpc/kernel/rtas_flash.c~rtas_delay_reorg arch/powerpc/kernel/rtas_flash.c --- 2_6_linus/arch/powerpc/kernel/rtas_flash.c~rtas_delay_reorg 2006-06-12 11:21:29.000000000 -0500 +++ 2_6_linus-johnrose/arch/powerpc/kernel/rtas_flash.c 2006-06-12 11:21:29.000000000 -0500 @@ -365,20 +365,12 @@ static int rtas_excl_release(struct inod static void manage_flash(struct rtas_manage_flash_t *args_buf) { - unsigned int wait_time; s32 rc; - while (1) { + do { rc = rtas_call(rtas_token("ibm,manage-flash-image"), 1, 1, NULL, args_buf->op); - if (rc == RTAS_RC_BUSY) - udelay(1); - else if (rtas_is_extended_busy(rc)) { - wait_time = rtas_extended_busy_delay_time(rc); - udelay(wait_time * 1000); - } else - break; - } + } while (rtas_busy_delay(rc)); args_buf->status = rc; } @@ -451,27 +443,18 @@ static ssize_t manage_flash_write(struct static void validate_flash(struct rtas_validate_flash_t *args_buf) { int token = rtas_token("ibm,validate-flash-image"); - unsigned int wait_time; int update_results; s32 rc; rc = 0; - while(1) { + do { spin_lock(&rtas_data_buf_lock); memcpy(rtas_data_buf, args_buf->buf, VALIDATE_BUF_SIZE); rc = rtas_call(token, 2, 2, &update_results, (u32) __pa(rtas_data_buf), args_buf->buf_size); memcpy(args_buf->buf, rtas_data_buf, VALIDATE_BUF_SIZE); spin_unlock(&rtas_data_buf_lock); - - if (rc == RTAS_RC_BUSY) - udelay(1); - else if (rtas_is_extended_busy(rc)) { - wait_time = rtas_extended_busy_delay_time(rc); - udelay(wait_time * 1000); - } else - break; - } + } while (rtas_busy_delay(rc)); args_buf->status = rc; args_buf->update_results = update_results; diff -puN include/asm-powerpc/rtas.h~rtas_delay_reorg include/asm-powerpc/rtas.h --- 2_6_linus/include/asm-powerpc/rtas.h~rtas_delay_reorg 2006-06-12 11:21:29.000000000 -0500 +++ 2_6_linus-johnrose/include/asm-powerpc/rtas.h 2006-06-12 11:21:29.000000000 -0500 @@ -177,12 +177,8 @@ extern unsigned long rtas_get_boot_time( extern void rtas_get_rtc_time(struct rtc_time *rtc_time); extern int rtas_set_rtc_time(struct rtc_time *rtc_time); -/* Given an RTAS status code of 9900..9905 compute the hinted delay */ -unsigned int rtas_extended_busy_delay_time(int status); -static inline int rtas_is_extended_busy(int status) -{ - return status >= 9900 && status <= 9909; -} +extern unsigned int rtas_busy_delay_time(int status); +extern unsigned int rtas_busy_delay(int status); extern void pSeries_log_error(char *buf, unsigned int err_type, int fatal); diff -puN arch/powerpc/platforms/pseries/scanlog.c~rtas_delay_reorg arch/powerpc/platforms/pseries/scanlog.c --- 2_6_linus/arch/powerpc/platforms/pseries/scanlog.c~rtas_delay_reorg 2006-06-12 11:21:29.000000000 -0500 +++ 2_6_linus-johnrose/arch/powerpc/platforms/pseries/scanlog.c 2006-06-12 11:21:29.000000000 -0500 @@ -107,9 +107,9 @@ static ssize_t scanlog_read(struct file /* Break to sleep default time */ break; default: - if (status > 9900 && status <= 9905) { - wait_time = rtas_extended_busy_delay_time(status); - } else { + /* Assume extended busy */ + wait_time = rtas_busy_delay_time(status); + if (!wait_time) { printk(KERN_ERR "scanlog: unknown error from rtas: %d\n", status); return -EIO; } _ ^ permalink raw reply [flat|nested] 16+ messages in thread
[parent not found: <17553.4390.79327.634945@cargo.ozlabs.ibm.com>]
* [PATCH] powerpc: RTAS delay, fix module build breaks [not found] ` <17553.4390.79327.634945@cargo.ozlabs.ibm.com> @ 2006-06-15 22:32 ` John Rose 0 siblings, 0 replies; 16+ messages in thread From: John Rose @ 2006-06-15 22:32 UTC (permalink / raw) To: Paul Mackerras; +Cc: External List, Anton Blanchard Export both news RTAS delay functions, and change the scanlog module to use the new delay functions. Signed-off-by: John Rose <johnrose@austin.ibm.com> --- Respun against the powerpc git tree. Thanks Paul. 2_6_ppc-johnrose/arch/powerpc/kernel/rtas.c | 1 + 2_6_ppc-johnrose/arch/powerpc/platforms/pseries/scanlog.c | 6 +++--- 2 files changed, 4 insertions(+), 3 deletions(-) diff -puN arch/powerpc/kernel/rtas.c~finish_delay_reorg arch/powerpc/kernel/rtas.c --- 2_6_ppc/arch/powerpc/kernel/rtas.c~finish_delay_reorg 2006-06-15 17:27:20.000000000 -0500 +++ 2_6_ppc-johnrose/arch/powerpc/kernel/rtas.c 2006-06-15 17:28:11.000000000 -0500 @@ -797,6 +797,7 @@ EXPORT_SYMBOL(rtas_call); EXPORT_SYMBOL(rtas_data_buf); EXPORT_SYMBOL(rtas_data_buf_lock); EXPORT_SYMBOL(rtas_busy_delay_time); +EXPORT_SYMBOL(rtas_busy_delay); EXPORT_SYMBOL(rtas_get_sensor); EXPORT_SYMBOL(rtas_get_power_level); EXPORT_SYMBOL(rtas_set_power_level); diff -puN arch/powerpc/platforms/pseries/scanlog.c~finish_delay_reorg arch/powerpc/platforms/pseries/scanlog.c --- 2_6_ppc/arch/powerpc/platforms/pseries/scanlog.c~finish_delay_reorg 2006-06-15 17:28:30.000000000 -0500 +++ 2_6_ppc-johnrose/arch/powerpc/platforms/pseries/scanlog.c 2006-06-15 17:29:30.000000000 -0500 @@ -107,9 +107,9 @@ static ssize_t scanlog_read(struct file /* Break to sleep default time */ break; default: - if (status > 9900 && status <= 9905) { - wait_time = rtas_extended_busy_delay_time(status); - } else { + /* Assume extended busy */ + wait_time = rtas_busy_delay_time(status); + if (!wait_time) { printk(KERN_ERR "scanlog: unknown error from rtas: %d\n", status); return -EIO; } _ ^ permalink raw reply [flat|nested] 16+ messages in thread
* Re: [PATCH] reorg RTAS delay code 2006-06-05 21:31 ` John Rose 2006-06-05 21:54 ` Nathan Lynch 2006-06-10 2:04 ` Anton Blanchard @ 2006-07-13 18:20 ` Nathan Lynch 2006-07-25 4:39 ` Haren Myneni 2 siblings, 1 reply; 16+ messages in thread From: Nathan Lynch @ 2006-07-13 18:20 UTC (permalink / raw) To: John Rose; +Cc: External List, Paul Mackerras Hi folks- John Rose wrote: > This patch attempts to handle RTAS "busy" return codes in a more simple > and consistent manner. Typical callers of RTAS shouldn't have to > manage wait times and delay calls. > > This patch also changes the kernel to use msleep() rather than udelay() > when a runtime delay is necessary. This will avoid CPU soft lockups > for extended delay conditions. ... > +/* For an RTAS busy status code, perform the hinted delay. */ > +unsigned int rtas_busy_delay(int status) > +{ > + unsigned int ms; > > - /* Use microseconds for reasonable accuracy */ > - for (ms = 1; order > 0; order--) > - ms *= 10; > + might_sleep(); > + ms = rtas_busy_delay_time(status); > + if (ms) > + msleep(ms); > > - return ms; > + return ms; > } So I managed to test this with cpu hotplug recently and the might_sleep warning triggers in the cpu offline path (I had to reconstruct this from xmon due to the kernel crashing later on for a different reason, so it might be a little off): BUG: sleeping function called from invalid context at arch/powerpc/kernel/rtas.c:463. in_atomic():1, irqs_disabled():1. Call Trace: [C0000000AAD379A0] [C000000000010ADC] .show_stack+0x68/0x1b4 (unreliable) [C0000000AAD37A50] [C000000000050C98] .__might_sleep+0xd0/0xec [C0000000AAD37AE0] [C00000000001DF5C] .rtas_busy_delay+0x20/0x54 [C0000000AAD37B70] [C00000000001E2D0] .rtas_set_indicator+0x70/0xd4 [C0000000AAD37C10] [C0000000000491C8] .xics_migrate_irqs_away+0x78/0x228 [C0000000AAD37CD0] [C000000000047C14] .pSeries_cpu_disable+0x98/0xb4 [C0000000AAD37D50] [C000000000029A5C] .__cpu_disable+0x4c/0x60 [C0000000AAD37DC0] [C000000000080834] .take_cpu_down+0x10/0x38 [C0000000AAD37E40] [C00000000008D1C0] .do_stop+0x198/0x248 [C0000000AAD37EE0] [C000000000078124] .kthread+0x124/0x174 [C0000000AAD37F90] [C000000000026568] .kernel_thread+0x4c/0x68 As it turns out, set-indicator is not allowed to return a busy delay in this context, so we're actually safe here. Maybe we need an rtas_set_indicator_fast which could take that into account, e.g. int rtas_set_indicator_fast(int indicator, int index, int new_value) { int token = rtas_token("set-indicator"); int rc; rc = rtas_call(token, 3, 1, NULL, indicator, index, new_value); WARN_ON(rc == -2 || rc >= 9000 || rc <= 9005); if (rc < 0) return rtas_error_rc(rc); return rc; } ^ permalink raw reply [flat|nested] 16+ messages in thread
* Re: [PATCH] reorg RTAS delay code 2006-07-13 18:20 ` [PATCH] reorg RTAS delay code Nathan Lynch @ 2006-07-25 4:39 ` Haren Myneni 0 siblings, 0 replies; 16+ messages in thread From: Haren Myneni @ 2006-07-25 4:39 UTC (permalink / raw) To: Nathan Lynch; +Cc: External List, Paul Mackerras, Milton Miller II Nathan Lynch wrote: >Hi folks- > >John Rose wrote: > > >>This patch attempts to handle RTAS "busy" return codes in a more simple >>and consistent manner. Typical callers of RTAS shouldn't have to >>manage wait times and delay calls. >> >>This patch also changes the kernel to use msleep() rather than udelay() >>when a runtime delay is necessary. This will avoid CPU soft lockups >>for extended delay conditions. >> >> > >... > > > >>+/* For an RTAS busy status code, perform the hinted delay. */ >>+unsigned int rtas_busy_delay(int status) >>+{ >>+ unsigned int ms; >> >>- /* Use microseconds for reasonable accuracy */ >>- for (ms = 1; order > 0; order--) >>- ms *= 10; >>+ might_sleep(); >>+ ms = rtas_busy_delay_time(status); >>+ if (ms) >>+ msleep(ms); >> >>- return ms; >>+ return ms; >> } >> >> > >So I managed to test this with cpu hotplug recently and the >might_sleep warning triggers in the cpu offline path (I had to >reconstruct this from xmon due to the kernel crashing later on for a >different reason, so it might be a little off): > >BUG: sleeping function called from invalid context at arch/powerpc/kernel/rtas.c:463. >in_atomic():1, irqs_disabled():1. >Call Trace: >[C0000000AAD379A0] [C000000000010ADC] .show_stack+0x68/0x1b4 (unreliable) >[C0000000AAD37A50] [C000000000050C98] .__might_sleep+0xd0/0xec >[C0000000AAD37AE0] [C00000000001DF5C] .rtas_busy_delay+0x20/0x54 >[C0000000AAD37B70] [C00000000001E2D0] .rtas_set_indicator+0x70/0xd4 >[C0000000AAD37C10] [C0000000000491C8] .xics_migrate_irqs_away+0x78/0x228 >[C0000000AAD37CD0] [C000000000047C14] .pSeries_cpu_disable+0x98/0xb4 >[C0000000AAD37D50] [C000000000029A5C] .__cpu_disable+0x4c/0x60 >[C0000000AAD37DC0] [C000000000080834] .take_cpu_down+0x10/0x38 >[C0000000AAD37E40] [C00000000008D1C0] .do_stop+0x198/0x248 >[C0000000AAD37EE0] [C000000000078124] .kthread+0x124/0x174 >[C0000000AAD37F90] [C000000000026568] .kernel_thread+0x4c/0x68 > > >As it turns out, set-indicator is not allowed to return a busy delay >in this context, so we're actually safe here. Maybe we need an >rtas_set_indicator_fast which could take that into account, e.g. > >int rtas_set_indicator_fast(int indicator, int index, int new_value) >{ > int token = rtas_token("set-indicator"); > int rc; > > rc = rtas_call(token, 3, 1, NULL, indicator, index, new_value); > > WARN_ON(rc == -2 || rc >= 9000 || rc <= 9005); > > if (rc < 0) > return rtas_error_rc(rc); > return rc; >} > > > > Hi, I am also noticing the similar stack trace from __might_sleep() for kdump boot. Before attempts kexec boot, kdump code calls rtas_set_indicator() from xics_teardown_cpu(). Also, might_sleep() calls might_resched() -> cond_resched(). What about when the preemption is enabled? will the CPU get scheduled on another task? Can we have separate function rtas_set_indicator_fast() as mentioned above or int rtas_set_indicator(int indicator, int index, int new_value, int sleep_on_delay) { int token = rtas_token("set-indicator"); int rc; if (token == RTAS_UNKNOWN_SERVICE) return -ENOENT; rc = rtas_call(token, 3, 1, NULL, indicator, index, new_value); if (!sleep_on_delay) WARN_ON(rc == -2 || rc >= 9000 || rc <= 9005); else while (rtas_busy_delay(rc)) rc = rtas_call(token, 3, 1, NULL, indicator, index, new_value); if (rc < 0) return rtas_error_rc(rc); return rc; } Thanks Haren >_______________________________________________ >Linuxppc-dev mailing list >Linuxppc-dev@ozlabs.org >https://ozlabs.org/mailman/listinfo/linuxppc-dev > > ^ permalink raw reply [flat|nested] 16+ messages in thread
end of thread, other threads:[~2006-07-25 4:40 UTC | newest] Thread overview: 16+ messages (download: mbox.gz follow: Atom feed -- links below jump to the message on this page -- 2006-05-31 19:32 [PATCH] use msleep() for RTAS delays John Rose 2006-06-01 5:31 ` Benjamin Herrenschmidt 2006-06-01 5:39 ` Paul Mackerras 2006-06-01 18:09 ` Arnd Bergmann 2006-06-01 15:55 ` John Rose 2006-06-01 22:25 ` John Rose 2006-06-02 20:30 ` [PATCH] reorg RTAS delay code John Rose 2006-06-02 21:33 ` Nathan Lynch 2006-06-05 21:31 ` John Rose 2006-06-05 21:54 ` Nathan Lynch 2006-06-10 2:04 ` Anton Blanchard 2006-06-10 2:08 ` Anton Blanchard 2006-06-12 16:18 ` John Rose [not found] ` <17553.4390.79327.634945@cargo.ozlabs.ibm.com> 2006-06-15 22:32 ` [PATCH] powerpc: RTAS delay, fix module build breaks John Rose 2006-07-13 18:20 ` [PATCH] reorg RTAS delay code Nathan Lynch 2006-07-25 4:39 ` Haren Myneni
This is a public inbox, see mirroring instructions for how to clone and mirror all data and code used for this inbox; as well as URLs for NNTP newsgroup(s).