1 // SPDX-License-Identifier: GPL-2.0 2 /* sstate.c: System soft state support. 3 * 4 * Copyright (C) 2007, 2008 David S. Miller <davem@davemloft.net> 5 */ 6 7 #include <linux/kernel.h> 8 #include <linux/notifier.h> 9 #include <linux/panic_notifier.h> 10 #include <linux/reboot.h> 11 #include <linux/init.h> 12 13 #include <asm/hypervisor.h> 14 #include <asm/spitfire.h> 15 #include <asm/oplib.h> 16 #include <asm/head.h> 17 #include <asm/io.h> 18 19 #include "kernel.h" 20 21 static int hv_supports_soft_state; 22 23 static void do_set_sstate(unsigned long state, const char *msg) 24 { 25 unsigned long err; 26 27 if (!hv_supports_soft_state) 28 return; 29 30 err = sun4v_mach_set_soft_state(state, kimage_addr_to_ra(msg)); 31 if (err) { 32 printk(KERN_WARNING "SSTATE: Failed to set soft-state to " 33 "state[%lx] msg[%s], err=%lu\n", 34 state, msg, err); 35 } 36 } 37 38 static const char booting_msg[32] __attribute__((aligned(32))) = 39 "Linux booting"; 40 static const char running_msg[32] __attribute__((aligned(32))) = 41 "Linux running"; 42 static const char halting_msg[32] __attribute__((aligned(32))) = 43 "Linux halting"; 44 static const char poweroff_msg[32] __attribute__((aligned(32))) = 45 "Linux powering off"; 46 static const char rebooting_msg[32] __attribute__((aligned(32))) = 47 "Linux rebooting"; 48 static const char panicking_msg[32] __attribute__((aligned(32))) = 49 "Linux panicking"; 50 51 static int sstate_reboot_call(struct notifier_block *np, unsigned long type, void *_unused) 52 { 53 const char *msg; 54 55 switch (type) { 56 case SYS_DOWN: 57 default: 58 msg = rebooting_msg; 59 break; 60 61 case SYS_HALT: 62 msg = halting_msg; 63 break; 64 65 case SYS_POWER_OFF: 66 msg = poweroff_msg; 67 break; 68 } 69 70 do_set_sstate(HV_SOFT_STATE_TRANSITION, msg); 71 72 return NOTIFY_OK; 73 } 74 75 static struct notifier_block sstate_reboot_notifier = { 76 .notifier_call = sstate_reboot_call, 77 }; 78 79 static int sstate_panic_event(struct notifier_block *n, unsigned long event, void *ptr) 80 { 81 do_set_sstate(HV_SOFT_STATE_TRANSITION, panicking_msg); 82 83 return NOTIFY_DONE; 84 } 85 86 static struct notifier_block sstate_panic_block = { 87 .notifier_call = sstate_panic_event, 88 .priority = INT_MAX, 89 }; 90 91 static int __init sstate_init(void) 92 { 93 unsigned long major, minor; 94 95 if (tlb_type != hypervisor) 96 return 0; 97 98 major = 1; 99 minor = 0; 100 if (sun4v_hvapi_register(HV_GRP_SOFT_STATE, major, &minor)) 101 return 0; 102 103 hv_supports_soft_state = 1; 104 105 prom_sun4v_guest_soft_state(); 106 107 do_set_sstate(HV_SOFT_STATE_TRANSITION, booting_msg); 108 109 atomic_notifier_chain_register(&panic_notifier_list, 110 &sstate_panic_block); 111 register_reboot_notifier(&sstate_reboot_notifier); 112 113 return 0; 114 } 115 116 core_initcall(sstate_init); 117 118 static int __init sstate_running(void) 119 { 120 do_set_sstate(HV_SOFT_STATE_NORMAL, running_msg); 121 return 0; 122 } 123 124 late_initcall(sstate_running); 125