linux/arch/sparc/kernel/sstate.c
<<
>>
Prefs
   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/reboot.h>
  10#include <linux/init.h>
  11
  12#include <asm/hypervisor.h>
  13#include <asm/spitfire.h>
  14#include <asm/oplib.h>
  15#include <asm/head.h>
  16#include <asm/io.h>
  17
  18#include "kernel.h"
  19
  20static int hv_supports_soft_state;
  21
  22static void do_set_sstate(unsigned long state, const char *msg)
  23{
  24        unsigned long err;
  25
  26        if (!hv_supports_soft_state)
  27                return;
  28
  29        err = sun4v_mach_set_soft_state(state, kimage_addr_to_ra(msg));
  30        if (err) {
  31                printk(KERN_WARNING "SSTATE: Failed to set soft-state to "
  32                       "state[%lx] msg[%s], err=%lu\n",
  33                       state, msg, err);
  34        }
  35}
  36
  37static const char booting_msg[32] __attribute__((aligned(32))) =
  38        "Linux booting";
  39static const char running_msg[32] __attribute__((aligned(32))) =
  40        "Linux running";
  41static const char halting_msg[32] __attribute__((aligned(32))) =
  42        "Linux halting";
  43static const char poweroff_msg[32] __attribute__((aligned(32))) =
  44        "Linux powering off";
  45static const char rebooting_msg[32] __attribute__((aligned(32))) =
  46        "Linux rebooting";
  47static const char panicking_msg[32] __attribute__((aligned(32))) =
  48        "Linux panicking";
  49
  50static int sstate_reboot_call(struct notifier_block *np, unsigned long type, void *_unused)
  51{
  52        const char *msg;
  53
  54        switch (type) {
  55        case SYS_DOWN:
  56        default:
  57                msg = rebooting_msg;
  58                break;
  59
  60        case SYS_HALT:
  61                msg = halting_msg;
  62                break;
  63
  64        case SYS_POWER_OFF:
  65                msg = poweroff_msg;
  66                break;
  67        }
  68
  69        do_set_sstate(HV_SOFT_STATE_TRANSITION, msg);
  70
  71        return NOTIFY_OK;
  72}
  73
  74static struct notifier_block sstate_reboot_notifier = {
  75        .notifier_call = sstate_reboot_call,
  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, panicking_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
  90static int __init sstate_init(void)
  91{
  92        unsigned long major, minor;
  93
  94        if (tlb_type != hypervisor)
  95                return 0;
  96
  97        major = 1;
  98        minor = 0;
  99        if (sun4v_hvapi_register(HV_GRP_SOFT_STATE, major, &minor))
 100                return 0;
 101
 102        hv_supports_soft_state = 1;
 103
 104        prom_sun4v_guest_soft_state();
 105
 106        do_set_sstate(HV_SOFT_STATE_TRANSITION, booting_msg);
 107
 108        atomic_notifier_chain_register(&panic_notifier_list,
 109                                       &sstate_panic_block);
 110        register_reboot_notifier(&sstate_reboot_notifier);
 111
 112        return 0;
 113}
 114
 115core_initcall(sstate_init);
 116
 117static int __init sstate_running(void)
 118{
 119        do_set_sstate(HV_SOFT_STATE_NORMAL, running_msg);
 120        return 0;
 121}
 122
 123late_initcall(sstate_running);
 124