[PATCH] powerpc: reorg RTAS delay code
authorJohn Rose <johnrose@austin.ibm.com>
Mon, 5 Jun 2006 21:31:48 +0000 (16:31 -0500)
committerPaul Mackerras <paulus@samba.org>
Fri, 9 Jun 2006 11:21:06 +0000 (21:21 +1000)
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>
Signed-off-by: Paul Mackerras <paulus@samba.org>
arch/powerpc/kernel/rtas-rtc.c
arch/powerpc/kernel/rtas.c
arch/powerpc/kernel/rtas_flash.c
include/asm-powerpc/rtas.h

index 34d073fb60911aff9f672971275bbe8c44e09386..77578c093ddafc6b57936f9e9715d725ec740829 100644 (file)
 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)
 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 *tm)
                                  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",
index 0112318213ab5aada8c00e5ec6877c801501ccd3..13496f3198554fbe1bb6c339fd1f71cefa8b8d25 100644 (file)
@@ -370,24 +370,36 @@ int rtas_call(int token, int nargs, int nret, int *outputs, ...)
        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 (status == RTAS_BUSY) {
+               ms = 1;
+       } else if (status >= 9900 && status <= 9905) {
+               order = status - 9900;
+               for (ms = 1; order > 0; order--)
+                       ms *= 10;
+       }
 
-       if (order < 0)
-               order = 0;      /* RTC depends on this for -2 clock busy */
-       else if (order > 5)
-               order = 5;      /* bound */
+       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; 
+       might_sleep();
+       ms = rtas_busy_delay_time(status);
+       if (ms)
+               msleep(ms);
+
+       return ms;
 }
 
 int rtas_error_rc(int rtas_rc)
@@ -438,22 +450,14 @@ int rtas_get_power_level(int powerdomain, int *level)
 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 level, int *setlevel)
 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 index, int *state)
 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);
index aaf384c3f04a62eca2bbe497bdfd0b80e905b265..1442b63a75daa1998f5d8c4bc22a6b8d758f46e7 100644 (file)
@@ -365,20 +365,12 @@ static int rtas_excl_release(struct inode *inode, struct file *file)
 
 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 file *file, const char __user *buf,
 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;
index f43c6835e62a1911c5a18205c0a86a0599e33297..a3b4e55569c7b203321c49eaa9c9546318bc399e 100644 (file)
@@ -177,12 +177,8 @@ extern unsigned long rtas_get_boot_time(void);
 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);