1/* sstate.c: System soft state support.
2 *
3 * Copyright (C) 2007 David S. Miller <davem@davemloft.net>
4 */
5
6#include <linux/kernel.h>
7#include <linux/notifier.h>
8#include <linux/init.h>
9
10#include <asm/hypervisor.h>
11#include <asm/sstate.h>
12#include <asm/oplib.h>
13#include <asm/head.h>
14#include <asm/io.h>
15
16static int hv_supports_soft_state;
17
18static unsigned long kimage_addr_to_ra(const char *p)
19{
20	unsigned long val = (unsigned long) p;
21
22	return kern_base + (val - KERNBASE);
23}
24
25static void do_set_sstate(unsigned long state, const char *msg)
26{
27	unsigned long err;
28
29	if (!hv_supports_soft_state)
30		return;
31
32	err = sun4v_mach_set_soft_state(state, kimage_addr_to_ra(msg));
33	if (err) {
34		printk(KERN_WARNING "SSTATE: Failed to set soft-state to "
35		       "state[%lx] msg[%s], err=%lu\n",
36		       state, msg, err);
37	}
38}
39
40static const char booting_msg[32] __attribute__((aligned(32))) =
41	"Linux booting";
42static const char running_msg[32] __attribute__((aligned(32))) =
43	"Linux running";
44static const char halting_msg[32] __attribute__((aligned(32))) =
45	"Linux halting";
46static const char poweroff_msg[32] __attribute__((aligned(32))) =
47	"Linux powering off";
48static const char rebooting_msg[32] __attribute__((aligned(32))) =
49	"Linux rebooting";
50static const char panicing_msg[32] __attribute__((aligned(32))) =
51	"Linux panicing";
52
53void sstate_booting(void)
54{
55	do_set_sstate(HV_SOFT_STATE_TRANSITION, booting_msg);
56}
57
58void sstate_running(void)
59{
60	do_set_sstate(HV_SOFT_STATE_NORMAL, running_msg);
61}
62
63void sstate_halt(void)
64{
65	do_set_sstate(HV_SOFT_STATE_TRANSITION, halting_msg);
66}
67
68void sstate_poweroff(void)
69{
70	do_set_sstate(HV_SOFT_STATE_TRANSITION, poweroff_msg);
71}
72
73void sstate_reboot(void)
74{
75	do_set_sstate(HV_SOFT_STATE_TRANSITION, rebooting_msg);
76}
77
78static int sstate_panic_event(struct notifier_block *n, unsigned long event, void *ptr)
79{
80	do_set_sstate(HV_SOFT_STATE_TRANSITION, panicing_msg);
81
82	return NOTIFY_DONE;
83}
84
85static struct notifier_block sstate_panic_block = {
86	.notifier_call	=	sstate_panic_event,
87	.priority	=	INT_MAX,
88};
89
90void __init sun4v_sstate_init(void)
91{
92	unsigned long major, minor;
93
94	major = 1;
95	minor = 0;
96	if (sun4v_hvapi_register(HV_GRP_SOFT_STATE, major, &minor))
97		return;
98
99	hv_supports_soft_state = 1;
100
101	prom_sun4v_guest_soft_state();
102	atomic_notifier_chain_register(&panic_notifier_list,
103				       &sstate_panic_block);
104}
105