linux 2.6.16.38 w/ vs2.0.3-rc1
[linux-2.6.git] / arch / powerpc / kernel / rtas.c
index 77f1e06..b5b2add 100644 (file)
@@ -25,7 +25,6 @@
 #include <asm/hvcall.h>
 #include <asm/semaphore.h>
 #include <asm/machdep.h>
-#include <asm/firmware.h>
 #include <asm/page.h>
 #include <asm/param.h>
 #include <asm/system.h>
 #include <asm/uaccess.h>
 #include <asm/lmb.h>
 #include <asm/udbg.h>
-#include <asm/syscalls.h>
 
 struct rtas_t rtas = {
        .lock = SPIN_LOCK_UNLOCKED
 };
-EXPORT_SYMBOL(rtas);
 
 struct rtas_suspend_me_data {
        long waiting;
        struct rtas_args *args;
 };
 
-DEFINE_SPINLOCK(rtas_data_buf_lock);
-EXPORT_SYMBOL(rtas_data_buf_lock);
+EXPORT_SYMBOL(rtas);
 
+DEFINE_SPINLOCK(rtas_data_buf_lock);
 char rtas_data_buf[RTAS_DATA_BUF_SIZE] __cacheline_aligned;
-EXPORT_SYMBOL(rtas_data_buf);
-
 unsigned long rtas_rmo_buf;
 
 /*
@@ -109,71 +104,11 @@ static void call_rtas_display_status_delay(char c)
        }
 }
 
-void __init udbg_init_rtas_panel(void)
+void __init udbg_init_rtas(void)
 {
        udbg_putc = call_rtas_display_status_delay;
 }
 
-#ifdef CONFIG_UDBG_RTAS_CONSOLE
-
-/* If you think you're dying before early_init_dt_scan_rtas() does its
- * work, you can hard code the token values for your firmware here and
- * hardcode rtas.base/entry etc.
- */
-static unsigned int rtas_putchar_token = RTAS_UNKNOWN_SERVICE;
-static unsigned int rtas_getchar_token = RTAS_UNKNOWN_SERVICE;
-
-static void udbg_rtascon_putc(char c)
-{
-       int tries;
-
-       if (!rtas.base)
-               return;
-
-       /* Add CRs before LFs */
-       if (c == '\n')
-               udbg_rtascon_putc('\r');
-
-       /* if there is more than one character to be displayed, wait a bit */
-       for (tries = 0; tries < 16; tries++) {
-               if (rtas_call(rtas_putchar_token, 1, 1, NULL, c) == 0)
-                       break;
-               udelay(1000);
-       }
-}
-
-static int udbg_rtascon_getc_poll(void)
-{
-       int c;
-
-       if (!rtas.base)
-               return -1;
-
-       if (rtas_call(rtas_getchar_token, 0, 2, &c))
-               return -1;
-
-       return c;
-}
-
-static int udbg_rtascon_getc(void)
-{
-       int c;
-
-       while ((c = udbg_rtascon_getc_poll()) == -1)
-               ;
-
-       return c;
-}
-
-
-void __init udbg_init_rtas_console(void)
-{
-       udbg_putc = udbg_rtascon_putc;
-       udbg_getc = udbg_rtascon_getc;
-       udbg_getc_poll = udbg_rtascon_getc_poll;
-}
-#endif /* CONFIG_UDBG_RTAS_CONSOLE */
-
 void rtas_progress(char *s, unsigned short hex)
 {
        struct device_node *root;
@@ -299,7 +234,6 @@ int rtas_token(const char *service)
        tokp = (int *) get_property(rtas.dev, service, NULL);
        return tokp ? *tokp : RTAS_UNKNOWN_SERVICE;
 }
-EXPORT_SYMBOL(rtas_token);
 
 #ifdef CONFIG_RTAS_ERROR_LOGGING
 /*
@@ -392,7 +326,7 @@ int rtas_call(int token, int nargs, int nret, int *outputs, ...)
        char *buff_copy = NULL;
        int ret;
 
-       if (!rtas.entry || token == RTAS_UNKNOWN_SERVICE)
+       if (token == RTAS_UNKNOWN_SERVICE)
                return -1;
 
        /* Gotta do something different here, use global lock for now... */
@@ -433,41 +367,26 @@ int rtas_call(int token, int nargs, int nret, int *outputs, ...)
        }
        return ret;
 }
-EXPORT_SYMBOL(rtas_call);
 
-/* 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.
+/* 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).
  */
-unsigned int rtas_busy_delay_time(int status)
+unsigned int rtas_extended_busy_delay_time(int status)
 {
-       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;
-       }
-
-       return ms;
-}
-EXPORT_SYMBOL(rtas_busy_delay_time);
+       int order = status - 9900;
+       unsigned long ms;
 
-/* For an RTAS busy status code, perform the hinted delay. */
-unsigned int rtas_busy_delay(int status)
-{
-       unsigned int ms;
+       if (order < 0)
+               order = 0;      /* RTC depends on this for -2 clock busy */
+       else if (order > 5)
+               order = 5;      /* bound */
 
-       might_sleep();
-       ms = rtas_busy_delay_time(status);
-       if (ms)
-               msleep(ms);
+       /* Use microseconds for reasonable accuracy */
+       for (ms = 1; order > 0; order--)
+               ms *= 10;
 
-       return ms;
+       return ms; 
 }
-EXPORT_SYMBOL(rtas_busy_delay);
 
 int rtas_error_rc(int rtas_rc)
 {
@@ -513,80 +432,80 @@ int rtas_get_power_level(int powerdomain, int *level)
                return rtas_error_rc(rc);
        return rc;
 }
-EXPORT_SYMBOL(rtas_get_power_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;
 
-       do {
+       while (1) {
                rc = rtas_call(token, 2, 2, setlevel, powerdomain, level);
-       } while (rtas_busy_delay(rc));
+               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;
+       }
 
        if (rc < 0)
                return rtas_error_rc(rc);
        return rc;
 }
-EXPORT_SYMBOL(rtas_set_power_level);
 
 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;
 
-       do {
+       while (1) {
                rc = rtas_call(token, 2, 2, state, sensor, index);
-       } while (rtas_busy_delay(rc));
+               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;
+       }
 
        if (rc < 0)
                return rtas_error_rc(rc);
        return rc;
 }
-EXPORT_SYMBOL(rtas_get_sensor);
 
 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;
 
-       do {
+       while (1) {
                rc = rtas_call(token, 3, 1, NULL, indicator, index, new_value);
-       } while (rtas_busy_delay(rc));
-
-       if (rc < 0)
-               return rtas_error_rc(rc);
-       return rc;
-}
-EXPORT_SYMBOL(rtas_set_indicator);
-
-/*
- * Ignoring RTAS extended delay
- */
-int rtas_set_indicator_fast(int indicator, int index, int new_value)
-{
-       int rc;
-       int token = rtas_token("set-indicator");
-
-       if (token == RTAS_UNKNOWN_SERVICE)
-               return -ENOENT;
-
-       rc = rtas_call(token, 3, 1, NULL, indicator, index, new_value);
-
-       WARN_ON(rc == -2 || (rc >= 9900 && rc <= 9905));
+               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;
+       }
 
        if (rc < 0)
                return rtas_error_rc(rc);
-
        return rc;
 }
 
@@ -634,11 +553,13 @@ 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 != 0)
-               printk(KERN_EMERG "ibm,os-term call failed %d\n",
+               if (status == RTAS_BUSY)
+                       udelay(1);
+               else 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;
@@ -655,26 +576,26 @@ static void rtas_percpu_suspend_me(void *info)
         * We use "waiting" to indicate our state.  As long
         * as it is >0, we are still trying to all join up.
         * If it goes to 0, we have successfully joined up and
-        * one thread got H_CONTINUE.  If any error happens,
+        * one thread got H_Continue.  If any error happens,
         * we set it to <0.
         */
        local_irq_save(flags);
        do {
                rc = plpar_hcall_norets(H_JOIN);
                smp_rmb();
-       } while (rc == H_SUCCESS && data->waiting > 0);
-       if (rc == H_SUCCESS)
+       } while (rc == H_Success && data->waiting > 0);
+       if (rc == H_Success)
                goto out;
 
-       if (rc == H_CONTINUE) {
+       if (rc == H_Continue) {
                data->waiting = 0;
                data->args->args[data->args->nargs] =
                        rtas_call(ibm_suspend_me_token, 0, 1, NULL);
-               for_each_possible_cpu(i)
+               for_each_cpu(i)
                        plpar_hcall_norets(H_PROD,i);
        } else {
                data->waiting = -EBUSY;
-               printk(KERN_ERR "Error on H_JOIN hypervisor call\n");
+               printk(KERN_ERR "Error on H_Join hypervisor call\n");
        }
 
 out:
@@ -685,31 +606,9 @@ out:
 static int rtas_ibm_suspend_me(struct rtas_args *args)
 {
        int i;
-       long state;
-       long rc;
-       unsigned long dummy;
 
        struct rtas_suspend_me_data data;
 
-       /* Make sure the state is valid */
-       rc = plpar_hcall(H_VASI_STATE,
-                        ((u64)args->args[0] << 32) | args->args[1],
-                        0, 0, 0,
-                        &state, &dummy, &dummy);
-
-       if (rc) {
-               printk(KERN_ERR "rtas_ibm_suspend_me: vasi_state returned %ld\n",rc);
-               return rc;
-       } else if (state == H_VASI_ENABLED) {
-               args->args[args->nargs] = RTAS_NOT_SUSPENDABLE;
-               return 0;
-       } else if (state != H_VASI_SUSPENDING) {
-               printk(KERN_ERR "rtas_ibm_suspend_me: vasi_state returned state %ld\n",
-                      state);
-               args->args[args->nargs] = -1;
-               return 0;
-       }
-
        data.waiting = 1;
        data.args = args;
 
@@ -723,9 +622,9 @@ static int rtas_ibm_suspend_me(struct rtas_args *args)
                printk(KERN_ERR "Error doing global join\n");
 
        /* Prod each CPU.  This won't hurt, and will wake
-        * anyone we successfully put to sleep with H_JOIN.
+        * anyone we successfully put to sleep with H_Join
         */
-       for_each_possible_cpu(i)
+       for_each_cpu(i)
                plpar_hcall_norets(H_PROD, i);
 
        return data.waiting;
@@ -868,7 +767,7 @@ void __init rtas_initialize(void)
         * the stop-self token if any
         */
 #ifdef CONFIG_PPC64
-       if (machine_is(pseries) && firmware_has_feature(FW_FEATURE_LPAR)) {
+       if (_machine == PLATFORM_PSERIES_LPAR) {
                rtas_region = min(lmb.rmo_size, RTAS_INSTANTIATE_MAX);
                ibm_suspend_me_token = rtas_token("ibm,suspend-me");
        }
@@ -883,34 +782,13 @@ void __init rtas_initialize(void)
 #endif
 }
 
-int __init early_init_dt_scan_rtas(unsigned long node,
-               const char *uname, int depth, void *data)
-{
-       u32 *basep, *entryp, *sizep;
-
-       if (depth != 1 || strcmp(uname, "rtas") != 0)
-               return 0;
-
-       basep  = of_get_flat_dt_prop(node, "linux,rtas-base", NULL);
-       entryp = of_get_flat_dt_prop(node, "linux,rtas-entry", NULL);
-       sizep  = of_get_flat_dt_prop(node, "rtas-size", NULL);
-
-       if (basep && entryp && sizep) {
-               rtas.base = *basep;
-               rtas.entry = *entryp;
-               rtas.size = *sizep;
-       }
-
-#ifdef CONFIG_UDBG_RTAS_CONSOLE
-       basep = of_get_flat_dt_prop(node, "put-term-char", NULL);
-       if (basep)
-               rtas_putchar_token = *basep;
-
-       basep = of_get_flat_dt_prop(node, "get-term-char", NULL);
-       if (basep)
-               rtas_getchar_token = *basep;
-#endif
 
-       /* break now */
-       return 1;
-}
+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_get_sensor);
+EXPORT_SYMBOL(rtas_get_power_level);
+EXPORT_SYMBOL(rtas_set_power_level);
+EXPORT_SYMBOL(rtas_set_indicator);