linux/drivers/acpi/sleep.c
<<
>>
Prefs
   1/*
   2 * sleep.c - ACPI sleep support.
   3 *
   4 * Copyright (c) 2005 Alexey Starikovskiy <alexey.y.starikovskiy@intel.com>
   5 * Copyright (c) 2004 David Shaohua Li <shaohua.li@intel.com>
   6 * Copyright (c) 2000-2003 Patrick Mochel
   7 * Copyright (c) 2003 Open Source Development Lab
   8 *
   9 * This file is released under the GPLv2.
  10 *
  11 */
  12
  13#include <linux/delay.h>
  14#include <linux/irq.h>
  15#include <linux/dmi.h>
  16#include <linux/device.h>
  17#include <linux/suspend.h>
  18#include <linux/reboot.h>
  19#include <linux/acpi.h>
  20#include <linux/module.h>
  21
  22#include <asm/io.h>
  23
  24#include <acpi/acpi_bus.h>
  25#include <acpi/acpi_drivers.h>
  26
  27#include "internal.h"
  28#include "sleep.h"
  29
  30static u8 sleep_states[ACPI_S_STATE_COUNT];
  31
  32static void acpi_sleep_tts_switch(u32 acpi_state)
  33{
  34        union acpi_object in_arg = { ACPI_TYPE_INTEGER };
  35        struct acpi_object_list arg_list = { 1, &in_arg };
  36        acpi_status status = AE_OK;
  37
  38        in_arg.integer.value = acpi_state;
  39        status = acpi_evaluate_object(NULL, "\\_TTS", &arg_list, NULL);
  40        if (ACPI_FAILURE(status) && status != AE_NOT_FOUND) {
  41                /*
  42                 * OS can't evaluate the _TTS object correctly. Some warning
  43                 * message will be printed. But it won't break anything.
  44                 */
  45                printk(KERN_NOTICE "Failure in evaluating _TTS object\n");
  46        }
  47}
  48
  49static int tts_notify_reboot(struct notifier_block *this,
  50                        unsigned long code, void *x)
  51{
  52        acpi_sleep_tts_switch(ACPI_STATE_S5);
  53        return NOTIFY_DONE;
  54}
  55
  56static struct notifier_block tts_notifier = {
  57        .notifier_call  = tts_notify_reboot,
  58        .next           = NULL,
  59        .priority       = 0,
  60};
  61
  62static int acpi_sleep_prepare(u32 acpi_state)
  63{
  64#ifdef CONFIG_ACPI_SLEEP
  65        /* do we have a wakeup address for S2 and S3? */
  66        if (acpi_state == ACPI_STATE_S3) {
  67                if (!acpi_wakeup_address)
  68                        return -EFAULT;
  69                acpi_set_firmware_waking_vector(acpi_wakeup_address);
  70
  71        }
  72        ACPI_FLUSH_CPU_CACHE();
  73#endif
  74        printk(KERN_INFO PREFIX "Preparing to enter system sleep state S%d\n",
  75                acpi_state);
  76        acpi_enable_wakeup_devices(acpi_state);
  77        acpi_enter_sleep_state_prep(acpi_state);
  78        return 0;
  79}
  80
  81#ifdef CONFIG_ACPI_SLEEP
  82static u32 acpi_target_sleep_state = ACPI_STATE_S0;
  83
  84u32 acpi_target_system_state(void)
  85{
  86        return acpi_target_sleep_state;
  87}
  88
  89static bool pwr_btn_event_pending;
  90
  91/*
  92 * The ACPI specification wants us to save NVS memory regions during hibernation
  93 * and to restore them during the subsequent resume.  Windows does that also for
  94 * suspend to RAM.  However, it is known that this mechanism does not work on
  95 * all machines, so we allow the user to disable it with the help of the
  96 * 'acpi_sleep=nonvs' kernel command line option.
  97 */
  98static bool nvs_nosave;
  99
 100void __init acpi_nvs_nosave(void)
 101{
 102        nvs_nosave = true;
 103}
 104
 105/*
 106 * The ACPI specification wants us to save NVS memory regions during hibernation
 107 * but says nothing about saving NVS during S3.  Not all versions of Windows
 108 * save NVS on S3 suspend either, and it is clear that not all systems need
 109 * NVS to be saved at S3 time.  To improve suspend/resume time, allow the
 110 * user to disable saving NVS on S3 if their system does not require it, but
 111 * continue to save/restore NVS for S4 as specified.
 112 */
 113static bool nvs_nosave_s3;
 114
 115void __init acpi_nvs_nosave_s3(void)
 116{
 117        nvs_nosave_s3 = true;
 118}
 119
 120/*
 121 * ACPI 1.0 wants us to execute _PTS before suspending devices, so we allow the
 122 * user to request that behavior by using the 'acpi_old_suspend_ordering'
 123 * kernel command line option that causes the following variable to be set.
 124 */
 125static bool old_suspend_ordering;
 126
 127void __init acpi_old_suspend_ordering(void)
 128{
 129        old_suspend_ordering = true;
 130}
 131
 132static int __init init_old_suspend_ordering(const struct dmi_system_id *d)
 133{
 134        acpi_old_suspend_ordering();
 135        return 0;
 136}
 137
 138static int __init init_nvs_nosave(const struct dmi_system_id *d)
 139{
 140        acpi_nvs_nosave();
 141        return 0;
 142}
 143
 144static struct dmi_system_id __initdata acpisleep_dmi_table[] = {
 145        {
 146        .callback = init_old_suspend_ordering,
 147        .ident = "Abit KN9 (nForce4 variant)",
 148        .matches = {
 149                DMI_MATCH(DMI_BOARD_VENDOR, "http://www.abit.com.tw/"),
 150                DMI_MATCH(DMI_BOARD_NAME, "KN9 Series(NF-CK804)"),
 151                },
 152        },
 153        {
 154        .callback = init_old_suspend_ordering,
 155        .ident = "HP xw4600 Workstation",
 156        .matches = {
 157                DMI_MATCH(DMI_SYS_VENDOR, "Hewlett-Packard"),
 158                DMI_MATCH(DMI_PRODUCT_NAME, "HP xw4600 Workstation"),
 159                },
 160        },
 161        {
 162        .callback = init_old_suspend_ordering,
 163        .ident = "Asus Pundit P1-AH2 (M2N8L motherboard)",
 164        .matches = {
 165                DMI_MATCH(DMI_BOARD_VENDOR, "ASUSTek Computer INC."),
 166                DMI_MATCH(DMI_BOARD_NAME, "M2N8L"),
 167                },
 168        },
 169        {
 170        .callback = init_old_suspend_ordering,
 171        .ident = "Panasonic CF51-2L",
 172        .matches = {
 173                DMI_MATCH(DMI_BOARD_VENDOR,
 174                                "Matsushita Electric Industrial Co.,Ltd."),
 175                DMI_MATCH(DMI_BOARD_NAME, "CF51-2L"),
 176                },
 177        },
 178        {
 179        .callback = init_nvs_nosave,
 180        .ident = "Sony Vaio VGN-FW41E_H",
 181        .matches = {
 182                DMI_MATCH(DMI_SYS_VENDOR, "Sony Corporation"),
 183                DMI_MATCH(DMI_PRODUCT_NAME, "VGN-FW41E_H"),
 184                },
 185        },
 186        {
 187        .callback = init_nvs_nosave,
 188        .ident = "Sony Vaio VGN-FW21E",
 189        .matches = {
 190                DMI_MATCH(DMI_SYS_VENDOR, "Sony Corporation"),
 191                DMI_MATCH(DMI_PRODUCT_NAME, "VGN-FW21E"),
 192                },
 193        },
 194        {
 195        .callback = init_nvs_nosave,
 196        .ident = "Sony Vaio VGN-FW21M",
 197        .matches = {
 198                DMI_MATCH(DMI_SYS_VENDOR, "Sony Corporation"),
 199                DMI_MATCH(DMI_PRODUCT_NAME, "VGN-FW21M"),
 200                },
 201        },
 202        {
 203        .callback = init_nvs_nosave,
 204        .ident = "Sony Vaio VPCEB17FX",
 205        .matches = {
 206                DMI_MATCH(DMI_SYS_VENDOR, "Sony Corporation"),
 207                DMI_MATCH(DMI_PRODUCT_NAME, "VPCEB17FX"),
 208                },
 209        },
 210        {
 211        .callback = init_nvs_nosave,
 212        .ident = "Sony Vaio VGN-SR11M",
 213        .matches = {
 214                DMI_MATCH(DMI_SYS_VENDOR, "Sony Corporation"),
 215                DMI_MATCH(DMI_PRODUCT_NAME, "VGN-SR11M"),
 216                },
 217        },
 218        {
 219        .callback = init_nvs_nosave,
 220        .ident = "Everex StepNote Series",
 221        .matches = {
 222                DMI_MATCH(DMI_SYS_VENDOR, "Everex Systems, Inc."),
 223                DMI_MATCH(DMI_PRODUCT_NAME, "Everex StepNote Series"),
 224                },
 225        },
 226        {
 227        .callback = init_nvs_nosave,
 228        .ident = "Sony Vaio VPCEB1Z1E",
 229        .matches = {
 230                DMI_MATCH(DMI_SYS_VENDOR, "Sony Corporation"),
 231                DMI_MATCH(DMI_PRODUCT_NAME, "VPCEB1Z1E"),
 232                },
 233        },
 234        {
 235        .callback = init_nvs_nosave,
 236        .ident = "Sony Vaio VGN-NW130D",
 237        .matches = {
 238                DMI_MATCH(DMI_SYS_VENDOR, "Sony Corporation"),
 239                DMI_MATCH(DMI_PRODUCT_NAME, "VGN-NW130D"),
 240                },
 241        },
 242        {
 243        .callback = init_nvs_nosave,
 244        .ident = "Sony Vaio VPCCW29FX",
 245        .matches = {
 246                DMI_MATCH(DMI_SYS_VENDOR, "Sony Corporation"),
 247                DMI_MATCH(DMI_PRODUCT_NAME, "VPCCW29FX"),
 248                },
 249        },
 250        {
 251        .callback = init_nvs_nosave,
 252        .ident = "Averatec AV1020-ED2",
 253        .matches = {
 254                DMI_MATCH(DMI_SYS_VENDOR, "AVERATEC"),
 255                DMI_MATCH(DMI_PRODUCT_NAME, "1000 Series"),
 256                },
 257        },
 258        {
 259        .callback = init_old_suspend_ordering,
 260        .ident = "Asus A8N-SLI DELUXE",
 261        .matches = {
 262                DMI_MATCH(DMI_BOARD_VENDOR, "ASUSTeK Computer INC."),
 263                DMI_MATCH(DMI_BOARD_NAME, "A8N-SLI DELUXE"),
 264                },
 265        },
 266        {
 267        .callback = init_old_suspend_ordering,
 268        .ident = "Asus A8N-SLI Premium",
 269        .matches = {
 270                DMI_MATCH(DMI_BOARD_VENDOR, "ASUSTeK Computer INC."),
 271                DMI_MATCH(DMI_BOARD_NAME, "A8N-SLI Premium"),
 272                },
 273        },
 274        {
 275        .callback = init_nvs_nosave,
 276        .ident = "Sony Vaio VGN-SR26GN_P",
 277        .matches = {
 278                DMI_MATCH(DMI_SYS_VENDOR, "Sony Corporation"),
 279                DMI_MATCH(DMI_PRODUCT_NAME, "VGN-SR26GN_P"),
 280                },
 281        },
 282        {
 283        .callback = init_nvs_nosave,
 284        .ident = "Sony Vaio VPCEB1S1E",
 285        .matches = {
 286                DMI_MATCH(DMI_SYS_VENDOR, "Sony Corporation"),
 287                DMI_MATCH(DMI_PRODUCT_NAME, "VPCEB1S1E"),
 288                },
 289        },
 290        {
 291        .callback = init_nvs_nosave,
 292        .ident = "Sony Vaio VGN-FW520F",
 293        .matches = {
 294                DMI_MATCH(DMI_SYS_VENDOR, "Sony Corporation"),
 295                DMI_MATCH(DMI_PRODUCT_NAME, "VGN-FW520F"),
 296                },
 297        },
 298        {
 299        .callback = init_nvs_nosave,
 300        .ident = "Asus K54C",
 301        .matches = {
 302                DMI_MATCH(DMI_SYS_VENDOR, "ASUSTeK Computer Inc."),
 303                DMI_MATCH(DMI_PRODUCT_NAME, "K54C"),
 304                },
 305        },
 306        {
 307        .callback = init_nvs_nosave,
 308        .ident = "Asus K54HR",
 309        .matches = {
 310                DMI_MATCH(DMI_SYS_VENDOR, "ASUSTeK Computer Inc."),
 311                DMI_MATCH(DMI_PRODUCT_NAME, "K54HR"),
 312                },
 313        },
 314        {},
 315};
 316
 317static void acpi_sleep_dmi_check(void)
 318{
 319        dmi_check_system(acpisleep_dmi_table);
 320}
 321
 322/**
 323 * acpi_pm_freeze - Disable the GPEs and suspend EC transactions.
 324 */
 325static int acpi_pm_freeze(void)
 326{
 327        acpi_disable_all_gpes();
 328        acpi_os_wait_events_complete();
 329        acpi_ec_block_transactions();
 330        return 0;
 331}
 332
 333/**
 334 * acpi_pre_suspend - Enable wakeup devices, "freeze" EC and save NVS.
 335 */
 336static int acpi_pm_pre_suspend(void)
 337{
 338        acpi_pm_freeze();
 339        return suspend_nvs_save();
 340}
 341
 342/**
 343 *      __acpi_pm_prepare - Prepare the platform to enter the target state.
 344 *
 345 *      If necessary, set the firmware waking vector and do arch-specific
 346 *      nastiness to get the wakeup code to the waking vector.
 347 */
 348static int __acpi_pm_prepare(void)
 349{
 350        int error = acpi_sleep_prepare(acpi_target_sleep_state);
 351        if (error)
 352                acpi_target_sleep_state = ACPI_STATE_S0;
 353
 354        return error;
 355}
 356
 357/**
 358 *      acpi_pm_prepare - Prepare the platform to enter the target sleep
 359 *              state and disable the GPEs.
 360 */
 361static int acpi_pm_prepare(void)
 362{
 363        int error = __acpi_pm_prepare();
 364        if (!error)
 365                error = acpi_pm_pre_suspend();
 366
 367        return error;
 368}
 369
 370static int find_powerf_dev(struct device *dev, void *data)
 371{
 372        struct acpi_device *device = to_acpi_device(dev);
 373        const char *hid = acpi_device_hid(device);
 374
 375        return !strcmp(hid, ACPI_BUTTON_HID_POWERF);
 376}
 377
 378/**
 379 *      acpi_pm_finish - Instruct the platform to leave a sleep state.
 380 *
 381 *      This is called after we wake back up (or if entering the sleep state
 382 *      failed).
 383 */
 384static void acpi_pm_finish(void)
 385{
 386        struct device *pwr_btn_dev;
 387        u32 acpi_state = acpi_target_sleep_state;
 388
 389        acpi_ec_unblock_transactions();
 390        suspend_nvs_free();
 391
 392        if (acpi_state == ACPI_STATE_S0)
 393                return;
 394
 395        printk(KERN_INFO PREFIX "Waking up from system sleep state S%d\n",
 396                acpi_state);
 397        acpi_disable_wakeup_devices(acpi_state);
 398        acpi_leave_sleep_state(acpi_state);
 399
 400        /* reset firmware waking vector */
 401        acpi_set_firmware_waking_vector((acpi_physical_address) 0);
 402
 403        acpi_target_sleep_state = ACPI_STATE_S0;
 404
 405        acpi_resume_power_resources();
 406
 407        /* If we were woken with the fixed power button, provide a small
 408         * hint to userspace in the form of a wakeup event on the fixed power
 409         * button device (if it can be found).
 410         *
 411         * We delay the event generation til now, as the PM layer requires
 412         * timekeeping to be running before we generate events. */
 413        if (!pwr_btn_event_pending)
 414                return;
 415
 416        pwr_btn_event_pending = false;
 417        pwr_btn_dev = bus_find_device(&acpi_bus_type, NULL, NULL,
 418                                      find_powerf_dev);
 419        if (pwr_btn_dev) {
 420                pm_wakeup_event(pwr_btn_dev, 0);
 421                put_device(pwr_btn_dev);
 422        }
 423}
 424
 425/**
 426 *      acpi_pm_end - Finish up suspend sequence.
 427 */
 428static void acpi_pm_end(void)
 429{
 430        /*
 431         * This is necessary in case acpi_pm_finish() is not called during a
 432         * failing transition to a sleep state.
 433         */
 434        acpi_target_sleep_state = ACPI_STATE_S0;
 435        acpi_sleep_tts_switch(acpi_target_sleep_state);
 436}
 437#else /* !CONFIG_ACPI_SLEEP */
 438#define acpi_target_sleep_state ACPI_STATE_S0
 439static inline void acpi_sleep_dmi_check(void) {}
 440#endif /* CONFIG_ACPI_SLEEP */
 441
 442#ifdef CONFIG_SUSPEND
 443static u32 acpi_suspend_states[] = {
 444        [PM_SUSPEND_ON] = ACPI_STATE_S0,
 445        [PM_SUSPEND_STANDBY] = ACPI_STATE_S1,
 446        [PM_SUSPEND_MEM] = ACPI_STATE_S3,
 447        [PM_SUSPEND_MAX] = ACPI_STATE_S5
 448};
 449
 450/**
 451 *      acpi_suspend_begin - Set the target system sleep state to the state
 452 *              associated with given @pm_state, if supported.
 453 */
 454static int acpi_suspend_begin(suspend_state_t pm_state)
 455{
 456        u32 acpi_state = acpi_suspend_states[pm_state];
 457        int error = 0;
 458
 459        error = (nvs_nosave || nvs_nosave_s3) ? 0 : suspend_nvs_alloc();
 460        if (error)
 461                return error;
 462
 463        if (sleep_states[acpi_state]) {
 464                acpi_target_sleep_state = acpi_state;
 465                acpi_sleep_tts_switch(acpi_target_sleep_state);
 466        } else {
 467                printk(KERN_ERR "ACPI does not support this state: %d\n",
 468                        pm_state);
 469                error = -ENOSYS;
 470        }
 471        return error;
 472}
 473
 474/**
 475 *      acpi_suspend_enter - Actually enter a sleep state.
 476 *      @pm_state: ignored
 477 *
 478 *      Flush caches and go to sleep. For STR we have to call arch-specific
 479 *      assembly, which in turn call acpi_enter_sleep_state().
 480 *      It's unfortunate, but it works. Please fix if you're feeling frisky.
 481 */
 482static int acpi_suspend_enter(suspend_state_t pm_state)
 483{
 484        acpi_status status = AE_OK;
 485        u32 acpi_state = acpi_target_sleep_state;
 486        int error;
 487
 488        ACPI_FLUSH_CPU_CACHE();
 489
 490        switch (acpi_state) {
 491        case ACPI_STATE_S1:
 492                barrier();
 493                status = acpi_enter_sleep_state(acpi_state);
 494                break;
 495
 496        case ACPI_STATE_S3:
 497                if (!acpi_suspend_lowlevel)
 498                        return -ENOSYS;
 499                error = acpi_suspend_lowlevel();
 500                if (error)
 501                        return error;
 502                pr_info(PREFIX "Low-level resume complete\n");
 503                break;
 504        }
 505
 506        /* This violates the spec but is required for bug compatibility. */
 507        acpi_write_bit_register(ACPI_BITREG_SCI_ENABLE, 1);
 508
 509        /* Reprogram control registers */
 510        acpi_leave_sleep_state_prep(acpi_state);
 511
 512        /* ACPI 3.0 specs (P62) says that it's the responsibility
 513         * of the OSPM to clear the status bit [ implying that the
 514         * POWER_BUTTON event should not reach userspace ]
 515         *
 516         * However, we do generate a small hint for userspace in the form of
 517         * a wakeup event. We flag this condition for now and generate the
 518         * event later, as we're currently too early in resume to be able to
 519         * generate wakeup events.
 520         */
 521        if (ACPI_SUCCESS(status) && (acpi_state == ACPI_STATE_S3)) {
 522                acpi_event_status pwr_btn_status;
 523
 524                acpi_get_event_status(ACPI_EVENT_POWER_BUTTON, &pwr_btn_status);
 525
 526                if (pwr_btn_status & ACPI_EVENT_FLAG_SET) {
 527                        acpi_clear_event(ACPI_EVENT_POWER_BUTTON);
 528                        /* Flag for later */
 529                        pwr_btn_event_pending = true;
 530                }
 531        }
 532
 533        /*
 534         * Disable and clear GPE status before interrupt is enabled. Some GPEs
 535         * (like wakeup GPE) haven't handler, this can avoid such GPE misfire.
 536         * acpi_leave_sleep_state will reenable specific GPEs later
 537         */
 538        acpi_disable_all_gpes();
 539        /* Allow EC transactions to happen. */
 540        acpi_ec_unblock_transactions_early();
 541
 542        suspend_nvs_restore();
 543
 544        return ACPI_SUCCESS(status) ? 0 : -EFAULT;
 545}
 546
 547static int acpi_suspend_state_valid(suspend_state_t pm_state)
 548{
 549        u32 acpi_state;
 550
 551        switch (pm_state) {
 552        case PM_SUSPEND_ON:
 553        case PM_SUSPEND_STANDBY:
 554        case PM_SUSPEND_MEM:
 555                acpi_state = acpi_suspend_states[pm_state];
 556
 557                return sleep_states[acpi_state];
 558        default:
 559                return 0;
 560        }
 561}
 562
 563static const struct platform_suspend_ops acpi_suspend_ops = {
 564        .valid = acpi_suspend_state_valid,
 565        .begin = acpi_suspend_begin,
 566        .prepare_late = acpi_pm_prepare,
 567        .enter = acpi_suspend_enter,
 568        .wake = acpi_pm_finish,
 569        .end = acpi_pm_end,
 570};
 571
 572/**
 573 *      acpi_suspend_begin_old - Set the target system sleep state to the
 574 *              state associated with given @pm_state, if supported, and
 575 *              execute the _PTS control method.  This function is used if the
 576 *              pre-ACPI 2.0 suspend ordering has been requested.
 577 */
 578static int acpi_suspend_begin_old(suspend_state_t pm_state)
 579{
 580        int error = acpi_suspend_begin(pm_state);
 581        if (!error)
 582                error = __acpi_pm_prepare();
 583
 584        return error;
 585}
 586
 587/*
 588 * The following callbacks are used if the pre-ACPI 2.0 suspend ordering has
 589 * been requested.
 590 */
 591static const struct platform_suspend_ops acpi_suspend_ops_old = {
 592        .valid = acpi_suspend_state_valid,
 593        .begin = acpi_suspend_begin_old,
 594        .prepare_late = acpi_pm_pre_suspend,
 595        .enter = acpi_suspend_enter,
 596        .wake = acpi_pm_finish,
 597        .end = acpi_pm_end,
 598        .recover = acpi_pm_finish,
 599};
 600
 601static void acpi_sleep_suspend_setup(void)
 602{
 603        int i;
 604
 605        for (i = ACPI_STATE_S1; i < ACPI_STATE_S4; i++) {
 606                acpi_status status;
 607                u8 type_a, type_b;
 608
 609                status = acpi_get_sleep_type_data(i, &type_a, &type_b);
 610                if (ACPI_SUCCESS(status)) {
 611                        sleep_states[i] = 1;
 612                }
 613        }
 614
 615        suspend_set_ops(old_suspend_ordering ?
 616                &acpi_suspend_ops_old : &acpi_suspend_ops);
 617}
 618#else /* !CONFIG_SUSPEND */
 619static inline void acpi_sleep_suspend_setup(void) {}
 620#endif /* !CONFIG_SUSPEND */
 621
 622#ifdef CONFIG_HIBERNATION
 623static unsigned long s4_hardware_signature;
 624static struct acpi_table_facs *facs;
 625static bool nosigcheck;
 626
 627void __init acpi_no_s4_hw_signature(void)
 628{
 629        nosigcheck = true;
 630}
 631
 632static int acpi_hibernation_begin(void)
 633{
 634        int error;
 635
 636        error = nvs_nosave ? 0 : suspend_nvs_alloc();
 637        if (!error) {
 638                acpi_target_sleep_state = ACPI_STATE_S4;
 639                acpi_sleep_tts_switch(acpi_target_sleep_state);
 640        }
 641
 642        return error;
 643}
 644
 645static int acpi_hibernation_enter(void)
 646{
 647        acpi_status status = AE_OK;
 648
 649        ACPI_FLUSH_CPU_CACHE();
 650
 651        /* This shouldn't return.  If it returns, we have a problem */
 652        status = acpi_enter_sleep_state(ACPI_STATE_S4);
 653        /* Reprogram control registers */
 654        acpi_leave_sleep_state_prep(ACPI_STATE_S4);
 655
 656        return ACPI_SUCCESS(status) ? 0 : -EFAULT;
 657}
 658
 659static void acpi_hibernation_leave(void)
 660{
 661        /*
 662         * If ACPI is not enabled by the BIOS and the boot kernel, we need to
 663         * enable it here.
 664         */
 665        acpi_enable();
 666        /* Reprogram control registers */
 667        acpi_leave_sleep_state_prep(ACPI_STATE_S4);
 668        /* Check the hardware signature */
 669        if (facs && s4_hardware_signature != facs->hardware_signature) {
 670                printk(KERN_EMERG "ACPI: Hardware changed while hibernated, "
 671                        "cannot resume!\n");
 672                panic("ACPI S4 hardware signature mismatch");
 673        }
 674        /* Restore the NVS memory area */
 675        suspend_nvs_restore();
 676        /* Allow EC transactions to happen. */
 677        acpi_ec_unblock_transactions_early();
 678}
 679
 680static void acpi_pm_thaw(void)
 681{
 682        acpi_ec_unblock_transactions();
 683        acpi_enable_all_runtime_gpes();
 684}
 685
 686static const struct platform_hibernation_ops acpi_hibernation_ops = {
 687        .begin = acpi_hibernation_begin,
 688        .end = acpi_pm_end,
 689        .pre_snapshot = acpi_pm_prepare,
 690        .finish = acpi_pm_finish,
 691        .prepare = acpi_pm_prepare,
 692        .enter = acpi_hibernation_enter,
 693        .leave = acpi_hibernation_leave,
 694        .pre_restore = acpi_pm_freeze,
 695        .restore_cleanup = acpi_pm_thaw,
 696};
 697
 698/**
 699 *      acpi_hibernation_begin_old - Set the target system sleep state to
 700 *              ACPI_STATE_S4 and execute the _PTS control method.  This
 701 *              function is used if the pre-ACPI 2.0 suspend ordering has been
 702 *              requested.
 703 */
 704static int acpi_hibernation_begin_old(void)
 705{
 706        int error;
 707        /*
 708         * The _TTS object should always be evaluated before the _PTS object.
 709         * When the old_suspended_ordering is true, the _PTS object is
 710         * evaluated in the acpi_sleep_prepare.
 711         */
 712        acpi_sleep_tts_switch(ACPI_STATE_S4);
 713
 714        error = acpi_sleep_prepare(ACPI_STATE_S4);
 715
 716        if (!error) {
 717                if (!nvs_nosave)
 718                        error = suspend_nvs_alloc();
 719                if (!error)
 720                        acpi_target_sleep_state = ACPI_STATE_S4;
 721        }
 722        return error;
 723}
 724
 725/*
 726 * The following callbacks are used if the pre-ACPI 2.0 suspend ordering has
 727 * been requested.
 728 */
 729static const struct platform_hibernation_ops acpi_hibernation_ops_old = {
 730        .begin = acpi_hibernation_begin_old,
 731        .end = acpi_pm_end,
 732        .pre_snapshot = acpi_pm_pre_suspend,
 733        .prepare = acpi_pm_freeze,
 734        .finish = acpi_pm_finish,
 735        .enter = acpi_hibernation_enter,
 736        .leave = acpi_hibernation_leave,
 737        .pre_restore = acpi_pm_freeze,
 738        .restore_cleanup = acpi_pm_thaw,
 739        .recover = acpi_pm_finish,
 740};
 741
 742static void acpi_sleep_hibernate_setup(void)
 743{
 744        acpi_status status;
 745        u8 type_a, type_b;
 746
 747        status = acpi_get_sleep_type_data(ACPI_STATE_S4, &type_a, &type_b);
 748        if (ACPI_FAILURE(status))
 749                return;
 750
 751        hibernation_set_ops(old_suspend_ordering ?
 752                        &acpi_hibernation_ops_old : &acpi_hibernation_ops);
 753        sleep_states[ACPI_STATE_S4] = 1;
 754        if (nosigcheck)
 755                return;
 756
 757        acpi_get_table(ACPI_SIG_FACS, 1, (struct acpi_table_header **)&facs);
 758        if (facs)
 759                s4_hardware_signature = facs->hardware_signature;
 760}
 761#else /* !CONFIG_HIBERNATION */
 762static inline void acpi_sleep_hibernate_setup(void) {}
 763#endif /* !CONFIG_HIBERNATION */
 764
 765int acpi_suspend(u32 acpi_state)
 766{
 767        suspend_state_t states[] = {
 768                [1] = PM_SUSPEND_STANDBY,
 769                [3] = PM_SUSPEND_MEM,
 770                [5] = PM_SUSPEND_MAX
 771        };
 772
 773        if (acpi_state < 6 && states[acpi_state])
 774                return pm_suspend(states[acpi_state]);
 775        if (acpi_state == 4)
 776                return hibernate();
 777        return -EINVAL;
 778}
 779
 780static void acpi_power_off_prepare(void)
 781{
 782        /* Prepare to power off the system */
 783        acpi_sleep_prepare(ACPI_STATE_S5);
 784        acpi_disable_all_gpes();
 785}
 786
 787static void acpi_power_off(void)
 788{
 789        /* acpi_sleep_prepare(ACPI_STATE_S5) should have already been called */
 790        printk(KERN_DEBUG "%s called\n", __func__);
 791        local_irq_disable();
 792        acpi_enter_sleep_state(ACPI_STATE_S5);
 793}
 794
 795int __init acpi_sleep_init(void)
 796{
 797        acpi_status status;
 798        u8 type_a, type_b;
 799        char supported[ACPI_S_STATE_COUNT * 3 + 1];
 800        char *pos = supported;
 801        int i;
 802
 803        if (acpi_disabled)
 804                return 0;
 805
 806        acpi_sleep_dmi_check();
 807
 808        sleep_states[ACPI_STATE_S0] = 1;
 809
 810        acpi_sleep_suspend_setup();
 811        acpi_sleep_hibernate_setup();
 812
 813        status = acpi_get_sleep_type_data(ACPI_STATE_S5, &type_a, &type_b);
 814        if (ACPI_SUCCESS(status)) {
 815                sleep_states[ACPI_STATE_S5] = 1;
 816                pm_power_off_prepare = acpi_power_off_prepare;
 817                pm_power_off = acpi_power_off;
 818        }
 819
 820        supported[0] = 0;
 821        for (i = 0; i < ACPI_S_STATE_COUNT; i++) {
 822                if (sleep_states[i])
 823                        pos += sprintf(pos, " S%d", i);
 824        }
 825        pr_info(PREFIX "(supports%s)\n", supported);
 826
 827        /*
 828         * Register the tts_notifier to reboot notifier list so that the _TTS
 829         * object can also be evaluated when the system enters S5.
 830         */
 831        register_reboot_notifier(&tts_notifier);
 832        return 0;
 833}
 834
lxr.linux.no kindly hosted by Redpill Linpro AS, provider of Linux consulting and operations services since 1995.