diff options
-rw-r--r-- | arch/sparc64/kernel/Makefile | 2 | ||||
-rw-r--r-- | arch/sparc64/kernel/entry.S | 12 | ||||
-rw-r--r-- | arch/sparc64/kernel/hvapi.c | 3 | ||||
-rw-r--r-- | arch/sparc64/kernel/power.c | 2 | ||||
-rw-r--r-- | arch/sparc64/kernel/process.c | 4 | ||||
-rw-r--r-- | arch/sparc64/kernel/sstate.c | 104 | ||||
-rw-r--r-- | arch/sparc64/mm/init.c | 3 | ||||
-rw-r--r-- | arch/sparc64/prom/misc.c | 19 | ||||
-rw-r--r-- | include/asm-sparc64/bugs.h | 8 | ||||
-rw-r--r-- | include/asm-sparc64/hypervisor.h | 10 | ||||
-rw-r--r-- | include/asm-sparc64/oplib.h | 2 | ||||
-rw-r--r-- | include/asm-sparc64/sstate.h | 13 |
12 files changed, 175 insertions, 7 deletions
diff --git a/arch/sparc64/kernel/Makefile b/arch/sparc64/kernel/Makefile index c749dccacc3..18e31a8db01 100644 --- a/arch/sparc64/kernel/Makefile +++ b/arch/sparc64/kernel/Makefile @@ -12,7 +12,7 @@ obj-y := process.o setup.o cpu.o idprom.o \ irq.o ptrace.o time.o sys_sparc.o signal.o \ unaligned.o central.o pci.o starfire.o semaphore.o \ power.o sbus.o iommu_common.o sparc64_ksyms.o chmc.o \ - visemul.o prom.o of_device.o hvapi.o + visemul.o prom.o of_device.o hvapi.o sstate.o obj-$(CONFIG_STACKTRACE) += stacktrace.o obj-$(CONFIG_PCI) += ebus.o isa.o pci_common.o pci_iommu.o \ diff --git a/arch/sparc64/kernel/entry.S b/arch/sparc64/kernel/entry.S index 732b77cb71f..b5dbd570915 100644 --- a/arch/sparc64/kernel/entry.S +++ b/arch/sparc64/kernel/entry.S @@ -1937,3 +1937,15 @@ sun4v_con_write: stx %o1, [%o4] retl nop + + /* %o0: soft state + * %o1: address of description string + * + * returns %o0: status + */ + .globl sun4v_mach_set_soft_state +sun4v_mach_set_soft_state: + mov HV_FAST_MACH_SET_SOFT_STATE, %o5 + ta HV_FAST_TRAP + retl + nop diff --git a/arch/sparc64/kernel/hvapi.c b/arch/sparc64/kernel/hvapi.c index f54b3ed3b09..f34f5d6181e 100644 --- a/arch/sparc64/kernel/hvapi.c +++ b/arch/sparc64/kernel/hvapi.c @@ -9,6 +9,7 @@ #include <asm/hypervisor.h> #include <asm/oplib.h> +#include <asm/sstate.h> /* If the hypervisor indicates that the API setting * calls are unsupported, by returning HV_EBADTRAP or @@ -179,6 +180,8 @@ void __init sun4v_hvapi_init(void) if (sun4v_hvapi_register(group, major, &minor)) goto bad; + sun4v_sstate_init(); + return; bad: diff --git a/arch/sparc64/kernel/power.c b/arch/sparc64/kernel/power.c index 699b24b890d..5d6adea3967 100644 --- a/arch/sparc64/kernel/power.c +++ b/arch/sparc64/kernel/power.c @@ -19,6 +19,7 @@ #include <asm/prom.h> #include <asm/of_device.h> #include <asm/io.h> +#include <asm/sstate.h> #include <linux/unistd.h> @@ -53,6 +54,7 @@ static void (*poweroff_method)(void) = machine_alt_power_off; void machine_power_off(void) { + sstate_poweroff(); if (!serial_console || scons_pwroff) { #ifdef CONFIG_PCI if (power_reg) { diff --git a/arch/sparc64/kernel/process.c b/arch/sparc64/kernel/process.c index 952762bfb4c..f5f97e2c669 100644 --- a/arch/sparc64/kernel/process.c +++ b/arch/sparc64/kernel/process.c @@ -45,6 +45,7 @@ #include <asm/mmu_context.h> #include <asm/unistd.h> #include <asm/hypervisor.h> +#include <asm/sstate.h> /* #define VERBOSE_SHOWREGS */ @@ -106,6 +107,7 @@ extern void (*prom_keyboard)(void); void machine_halt(void) { + sstate_halt(); if (!serial_console && prom_palette) prom_palette (1); if (prom_keyboard) @@ -116,6 +118,7 @@ void machine_halt(void) void machine_alt_power_off(void) { + sstate_poweroff(); if (!serial_console && prom_palette) prom_palette(1); if (prom_keyboard) @@ -128,6 +131,7 @@ void machine_restart(char * cmd) { char *p; + sstate_reboot(); p = strchr (reboot_command, '\n'); if (p) *p = 0; if (!serial_console && prom_palette) diff --git a/arch/sparc64/kernel/sstate.c b/arch/sparc64/kernel/sstate.c new file mode 100644 index 00000000000..5b6e75b7f05 --- /dev/null +++ b/arch/sparc64/kernel/sstate.c @@ -0,0 +1,104 @@ +/* sstate.c: System soft state support. + * + * Copyright (C) 2007 David S. Miller <davem@davemloft.net> + */ + +#include <linux/kernel.h> +#include <linux/notifier.h> +#include <linux/init.h> + +#include <asm/hypervisor.h> +#include <asm/sstate.h> +#include <asm/oplib.h> +#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; + + return kern_base + (val - KERNBASE); +} + +static void do_set_sstate(unsigned long state, const char *msg) +{ + unsigned long err; + + if (!hv_supports_soft_state) + return; + + err = sun4v_mach_set_soft_state(state, kimage_addr_to_ra(msg)); + if (err) { + printk(KERN_WARNING "SSTATE: Failed to set soft-state to " + "state[%lx] msg[%s], err=%lu\n", + state, msg, err); + } +} + +static const char booting_msg[32] __attribute__((aligned(32))) = + "Linux booting"; +static const char running_msg[32] __attribute__((aligned(32))) = + "Linux running"; +static const char halting_msg[32] __attribute__((aligned(32))) = + "Linux halting"; +static const char poweroff_msg[32] __attribute__((aligned(32))) = + "Linux powering off"; +static const char rebooting_msg[32] __attribute__((aligned(32))) = + "Linux rebooting"; +static const char panicing_msg[32] __attribute__((aligned(32))) = + "Linux panicing"; + +void sstate_booting(void) +{ + do_set_sstate(HV_SOFT_STATE_TRANSITION, booting_msg); +} + +void sstate_running(void) +{ + do_set_sstate(HV_SOFT_STATE_NORMAL, running_msg); +} + +void sstate_halt(void) +{ + do_set_sstate(HV_SOFT_STATE_TRANSITION, halting_msg); +} + +void sstate_poweroff(void) +{ + do_set_sstate(HV_SOFT_STATE_TRANSITION, poweroff_msg); +} + +void sstate_reboot(void) +{ + do_set_sstate(HV_SOFT_STATE_TRANSITION, rebooting_msg); +} + +static int sstate_panic_event(struct notifier_block *n, unsigned long event, void *ptr) +{ + do_set_sstate(HV_SOFT_STATE_TRANSITION, panicing_msg); + + return NOTIFY_DONE; +} + +static struct notifier_block sstate_panic_block = { + .notifier_call = sstate_panic_event, + .priority = INT_MAX, +}; + +void __init sun4v_sstate_init(void) +{ + unsigned long major, minor; + + major = 1; + minor = 0; + if (sun4v_hvapi_register(HV_GRP_SOFT_STATE, major, &minor)) + return; + + hv_supports_soft_state = 1; + + prom_sun4v_guest_soft_state(); + atomic_notifier_chain_register(&panic_notifier_list, + &sstate_panic_block); +} diff --git a/arch/sparc64/mm/init.c b/arch/sparc64/mm/init.c index 6e5b01d779d..0c9995c3b8e 100644 --- a/arch/sparc64/mm/init.c +++ b/arch/sparc64/mm/init.c @@ -43,6 +43,7 @@ #include <asm/tsb.h> #include <asm/hypervisor.h> #include <asm/prom.h> +#include <asm/sstate.h> extern void device_scan(void); @@ -1348,6 +1349,8 @@ void __init paging_init(void) kern_base = (prom_boot_mapping_phys_low >> 22UL) << 22UL; kern_size = (unsigned long)&_end - (unsigned long)KERNBASE; + sstate_booting(); + /* Invalidate both kernel TSBs. */ memset(swapper_tsb, 0x40, sizeof(swapper_tsb)); #ifndef CONFIG_DEBUG_PAGEALLOC diff --git a/arch/sparc64/prom/misc.c b/arch/sparc64/prom/misc.c index 0b4213720d4..f3e0c14e9ee 100644 --- a/arch/sparc64/prom/misc.c +++ b/arch/sparc64/prom/misc.c @@ -15,6 +15,25 @@ #include <asm/oplib.h> #include <asm/system.h> +int prom_service_exists(const char *service_name) +{ + int err = p1275_cmd("test", P1275_ARG(0, P1275_ARG_IN_STRING) | + P1275_INOUT(1, 1), service_name); + + if (err) + return 0; + return 1; +} + +void prom_sun4v_guest_soft_state(void) +{ + const char *svc = "SUNW,soft-state-supported"; + + if (!prom_service_exists(svc)) + return; + p1275_cmd(svc, P1275_INOUT(0, 0)); +} + /* Reset and reboot the machine with the command 'bcommand'. */ void prom_reboot(const char *bcommand) { diff --git a/include/asm-sparc64/bugs.h b/include/asm-sparc64/bugs.h index 120422fdb02..bf39d86c0c9 100644 --- a/include/asm-sparc64/bugs.h +++ b/include/asm-sparc64/bugs.h @@ -1,9 +1,8 @@ -/* $Id: bugs.h,v 1.1 1996/12/26 13:25:20 davem Exp $ - * include/asm-sparc64/bugs.h: Sparc probes for various bugs. +/* bugs.h: Sparc64 probes for various bugs. * - * Copyright (C) 1996 David S. Miller (davem@caip.rutgers.edu) + * Copyright (C) 1996, 2007 David S. Miller (davem@davemloft.net) */ - +#include <asm/sstate.h> extern unsigned long loops_per_jiffy; @@ -12,4 +11,5 @@ static void __init check_bugs(void) #ifndef CONFIG_SMP cpu_data(0).udelay_val = loops_per_jiffy; #endif + sstate_running(); } diff --git a/include/asm-sparc64/hypervisor.h b/include/asm-sparc64/hypervisor.h index a5558c87556..17b233b64af 100644 --- a/include/asm-sparc64/hypervisor.h +++ b/include/asm-sparc64/hypervisor.h @@ -162,10 +162,15 @@ * terminated 7-bit ASCII string of up to 31 characters not including the * NULL termination. */ -#define HV_FAST_MACH_SET_SOFT_STATE 0x03 +#define HV_FAST_MACH_SET_SOFT_STATE 0x70 #define HV_SOFT_STATE_NORMAL 0x01 #define HV_SOFT_STATE_TRANSITION 0x02 +#ifndef __ASSEMBLY__ +extern unsigned long sun4v_mach_set_soft_state(unsigned long soft_state, + unsigned long msg_string_ra); +#endif + /* mach_get_soft_state() * TRAP: HV_FAST_TRAP * FUNCTION: HV_FAST_MACH_GET_SOFT_STATE @@ -181,7 +186,7 @@ * for the software state pointer are the same as for mach_set_soft_state() * above. */ -#define HV_FAST_MACH_GET_SOFT_STATE 0x04 +#define HV_FAST_MACH_GET_SOFT_STATE 0x71 /* CPU services. * @@ -2204,6 +2209,7 @@ extern void sun4v_hvapi_unregister(unsigned long group); extern int sun4v_hvapi_get(unsigned long group, unsigned long *major, unsigned long *minor); +extern void sun4v_hvapi_init(void); #endif #endif /* !(_SPARC64_HYPERVISOR_H) */ diff --git a/include/asm-sparc64/oplib.h b/include/asm-sparc64/oplib.h index 6a0da3b1695..07275e2366a 100644 --- a/include/asm-sparc64/oplib.h +++ b/include/asm-sparc64/oplib.h @@ -316,6 +316,8 @@ extern int prom_setprop(int node, const char *prop_name, char *prop_value, extern int prom_pathtoinode(const char *path); extern int prom_inst2pkg(int); +extern int prom_service_exists(const char *service_name); +extern void prom_sun4v_guest_soft_state(void); /* CPU probing helpers. */ struct device_node; diff --git a/include/asm-sparc64/sstate.h b/include/asm-sparc64/sstate.h new file mode 100644 index 00000000000..a7c35dbcb28 --- /dev/null +++ b/include/asm-sparc64/sstate.h @@ -0,0 +1,13 @@ +#ifndef _SPARC64_SSTATE_H +#define _SPARC64_SSTATE_H + +extern void sstate_booting(void); +extern void sstate_running(void); +extern void sstate_halt(void); +extern void sstate_poweroff(void); +extern void sstate_panic(void); +extern void sstate_reboot(void); + +extern void sun4v_sstate_init(void); + +#endif /* _SPARC64_SSTATE_H */ |