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