sparc: Set reboot-cmd using reboot data hypervisor call if available.
David S. Miller [Tue, 2 Aug 2011 06:27:17 +0000 (23:27 -0700)]
Signed-off-by: David S. Miller <davem@davemloft.net>

arch/sparc/include/asm/hypervisor.h
arch/sparc/kernel/ds.c
arch/sparc/kernel/hvcalls.S
arch/sparc/kernel/kernel.h
arch/sparc/kernel/sstate.c

index 2b7da27..015a761 100644 (file)
@@ -2927,6 +2927,13 @@ extern unsigned long sun4v_ncs_request(unsigned long request,
 #define HV_FAST_FIRE_GET_PERFREG       0x120
 #define HV_FAST_FIRE_SET_PERFREG       0x121
 
+#define HV_FAST_REBOOT_DATA_SET                0x172
+
+#ifndef __ASSEMBLY__
+extern unsigned long sun4v_reboot_data_set(unsigned long ra,
+                                          unsigned long len);
+#endif
+
 /* Function numbers for HV_CORE_TRAP.  */
 #define HV_CORE_SET_VER                        0x00
 #define HV_CORE_PUTCHAR                        0x01
index dd1342c..490e541 100644 (file)
 #include <linux/reboot.h>
 #include <linux/cpu.h>
 
+#include <asm/hypervisor.h>
 #include <asm/ldc.h>
 #include <asm/vio.h>
 #include <asm/mdesc.h>
 #include <asm/head.h>
 #include <asm/irq.h>
 
+#include "kernel.h"
+
 #define DRV_MODULE_NAME                "ds"
 #define PFX DRV_MODULE_NAME    ": "
 #define DRV_MODULE_VERSION     "1.0"
@@ -828,18 +831,32 @@ void ldom_set_var(const char *var, const char *value)
        }
 }
 
+static char full_boot_str[256] __attribute__((aligned(32)));
+static int reboot_data_supported;
+
 void ldom_reboot(const char *boot_command)
 {
        /* Don't bother with any of this if the boot_command
         * is empty.
         */
        if (boot_command && strlen(boot_command)) {
-               char full_boot_str[256];
+               unsigned long len;
 
                strcpy(full_boot_str, "boot ");
                strcpy(full_boot_str + strlen("boot "), boot_command);
+               len = strlen(full_boot_str);
 
-               ldom_set_var("reboot-command", full_boot_str);
+               if (reboot_data_supported) {
+                       unsigned long ra = kimage_addr_to_ra(full_boot_str);
+                       unsigned long hv_ret;
+
+                       hv_ret = sun4v_reboot_data_set(ra, len);
+                       if (hv_ret != HV_EOK)
+                               pr_err("SUN4V: Unable to set reboot data "
+                                      "hv_ret=%lu\n", hv_ret);
+               } else {
+                       ldom_set_var("reboot-command", full_boot_str);
+               }
        }
        sun4v_mach_sir();
 }
@@ -1237,6 +1254,15 @@ static struct vio_driver ds_driver = {
 
 static int __init ds_init(void)
 {
+       unsigned long hv_ret, major, minor;
+
+       hv_ret = sun4v_get_version(HV_GRP_REBOOT_DATA, &major, &minor);
+       if (hv_ret == HV_EOK) {
+               pr_info("SUN4V: Reboot data supported (maj=%lu,min=%lu).\n",
+                       major, minor);
+               reboot_data_supported = 1;
+       }
+
        kthread_run(ds_thread, NULL, "kldomd");
 
        return vio_register_driver(&ds_driver);
index 8a5f35f..58d60de 100644 (file)
@@ -798,3 +798,10 @@ ENTRY(sun4v_niagara2_setperf)
        retl
         nop
 ENDPROC(sun4v_niagara2_setperf)
+
+ENTRY(sun4v_reboot_data_set)
+       mov     HV_FAST_REBOOT_DATA_SET, %o5
+       ta      HV_FAST_TRAP
+       retl
+        nop
+ENDPROC(sun4v_reboot_data_set)
index 8325d77..fd6c36b 100644 (file)
@@ -4,6 +4,8 @@
 #include <linux/interrupt.h>
 
 #include <asm/traps.h>
+#include <asm/head.h>
+#include <asm/io.h>
 
 /* cpu.c */
 extern const char *sparc_pmu_type;
@@ -14,6 +16,13 @@ extern int ncpus_probed;
 /* setup_64.c */
 struct seq_file;
 extern void cpucap_info(struct seq_file *);
+
+static inline unsigned long kimage_addr_to_ra(const char *p)
+{
+       unsigned long val = (unsigned long) p;
+
+       return kern_base + (val - KERNBASE);
+}
 #endif
 
 #ifdef CONFIG_SPARC32
index 8cdbe59..c59af54 100644 (file)
 #include <asm/head.h>
 #include <asm/io.h>
 
-static int hv_supports_soft_state;
-
-static unsigned long kimage_addr_to_ra(const char *p)
-{
-       unsigned long val = (unsigned long) p;
+#include "kernel.h"
 
-       return kern_base + (val - KERNBASE);
-}
+static int hv_supports_soft_state;
 
 static void do_set_sstate(unsigned long state, const char *msg)
 {