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