aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/acpi/sleep.c
diff options
context:
space:
mode:
authorLinus Torvalds <torvalds@linux-foundation.org>2017-07-04 16:39:41 -0400
committerLinus Torvalds <torvalds@linux-foundation.org>2017-07-04 16:39:41 -0400
commit408c9861c6979db974455b9e7a9bcadd60e0934c (patch)
tree9bdb862da2883cd4f74297d01ec8ce3b4619dd66 /drivers/acpi/sleep.c
parentb39de277b02ffd8e3dccb01e9159bd45cb07b95d (diff)
parent8f8e5c3e2796eaf150d6262115af12707c2616dd (diff)
Merge tag 'pm-4.13-rc1' of git://git.kernel.org/pub/scm/linux/kernel/git/rafael/linux-pm
Pull power management updates from Rafael Wysocki: "The big ticket items here are the rework of suspend-to-idle in order to add proper support for power button wakeup from it on recent Dell laptops and the rework of interfaces exporting the current CPU frequency on x86. In addition to that, support for a few new pieces of hardware is added, the PCI/ACPI device wakeup infrastructure is simplified significantly and the wakeup IRQ framework is fixed to unbreak the IRQ bus locking infrastructure. Also, there are some functional improvements for intel_pstate, tools updates and small fixes and cleanups all over. Specifics: - Rework suspend-to-idle to allow it to take wakeup events signaled by the EC into account on ACPI-based platforms in order to properly support power button wakeup from suspend-to-idle on recent Dell laptops (Rafael Wysocki). That includes the core suspend-to-idle code rework, support for the Low Power S0 _DSM interface, and support for the ACPI INT0002 Virtual GPIO device from Hans de Goede (required for USB keyboard wakeup from suspend-to-idle to work on some machines). - Stop trying to export the current CPU frequency via /proc/cpuinfo on x86 as that is inaccurate and confusing (Len Brown). - Rework the way in which the current CPU frequency is exported by the kernel (over the cpufreq sysfs interface) on x86 systems with the APERF and MPERF registers by always using values read from these registers, when available, to compute the current frequency regardless of which cpufreq driver is in use (Len Brown). - Rework the PCI/ACPI device wakeup infrastructure to remove the questionable and artificial distinction between "devices that can wake up the system from sleep states" and "devices that can generate wakeup signals in the working state" from it, which allows the code to be simplified quite a bit (Rafael Wysocki). - Fix the wakeup IRQ framework by making it use SRCU instead of RCU which doesn't allow sleeping in the read-side critical sections, but which in turn is expected to be allowed by the IRQ bus locking infrastructure (Thomas Gleixner). - Modify some computations in the intel_pstate driver to avoid rounding errors resulting from them (Srinivas Pandruvada). - Reduce the overhead of the intel_pstate driver in the HWP (hardware-managed P-states) mode and when the "performance" P-state selection algorithm is in use by making it avoid registering scheduler callbacks in those cases (Len Brown). - Rework the energy_performance_preference sysfs knob in intel_pstate by changing the values that correspond to different symbolic hint names used by it (Len Brown). - Make it possible to use more than one cpuidle driver at the same time on ARM (Daniel Lezcano). - Make it possible to prevent the cpuidle menu governor from using the 0 state by disabling it via sysfs (Nicholas Piggin). - Add support for FFH (Fixed Functional Hardware) MWAIT in ACPI C1 on AMD systems (Yazen Ghannam). - Make the CPPC cpufreq driver take the lowest nonlinear performance information into account (Prashanth Prakash). - Add support for hi3660 to the cpufreq-dt driver, fix the imx6q driver and clean up the sfi, exynos5440 and intel_pstate drivers (Colin Ian King, Krzysztof Kozlowski, Octavian Purdila, Rafael Wysocki, Tao Wang). - Fix a few minor issues in the generic power domains (genpd) framework and clean it up somewhat (Krzysztof Kozlowski, Mikko Perttunen, Viresh Kumar). - Fix a couple of minor issues in the operating performance points (OPP) framework and clean it up somewhat (Viresh Kumar). - Fix a CONFIG dependency in the hibernation core and clean it up slightly (Balbir Singh, Arvind Yadav, BaoJun Luo). - Add rk3228 support to the rockchip-io adaptive voltage scaling (AVS) driver (David Wu). - Fix an incorrect bit shift operation in the RAPL power capping driver (Adam Lessnau). - Add support for the EPP field in the HWP (hardware managed P-states) control register, HWP.EPP, to the x86_energy_perf_policy tool and update msr-index.h with HWP.EPP values (Len Brown). - Fix some minor issues in the turbostat tool (Len Brown). - Add support for AMD family 0x17 CPUs to the cpupower tool and fix a minor issue in it (Sherry Hurwitz). - Assorted cleanups, mostly related to the constification of some data structures (Arvind Yadav, Joe Perches, Kees Cook, Krzysztof Kozlowski)" * tag 'pm-4.13-rc1' of git://git.kernel.org/pub/scm/linux/kernel/git/rafael/linux-pm: (69 commits) cpufreq: Update scaling_cur_freq documentation cpufreq: intel_pstate: Clean up after performance governor changes PM: hibernate: constify attribute_group structures. cpuidle: menu: allow state 0 to be disabled intel_idle: Use more common logging style PM / Domains: Fix missing default_power_down_ok comment PM / Domains: Fix unsafe iteration over modified list of domains PM / Domains: Fix unsafe iteration over modified list of domain providers PM / Domains: Fix unsafe iteration over modified list of device links PM / Domains: Handle safely genpd_syscore_switch() call on non-genpd device PM / Domains: Call driver's noirq callbacks PM / core: Drop run_wake flag from struct dev_pm_info PCI / PM: Simplify device wakeup settings code PCI / PM: Drop pme_interrupt flag from struct pci_dev ACPI / PM: Consolidate device wakeup settings code ACPI / PM: Drop run_wake from struct acpi_device_wakeup_flags PM / QoS: constify *_attribute_group. PM / AVS: rockchip-io: add io selectors and supplies for rk3228 powercap/RAPL: prevent overridding bits outside of the mask PM / sysfs: Constify attribute groups ...
Diffstat (limited to 'drivers/acpi/sleep.c')
-rw-r--r--drivers/acpi/sleep.c152
1 files changed, 147 insertions, 5 deletions
diff --git a/drivers/acpi/sleep.c b/drivers/acpi/sleep.c
index 097d630ab886..be17664736b2 100644
--- a/drivers/acpi/sleep.c
+++ b/drivers/acpi/sleep.c
@@ -650,38 +650,165 @@ static const struct platform_suspend_ops acpi_suspend_ops_old = {
650 .recover = acpi_pm_finish, 650 .recover = acpi_pm_finish,
651}; 651};
652 652
653static bool s2idle_in_progress;
654static bool s2idle_wakeup;
655
656/*
657 * On platforms supporting the Low Power S0 Idle interface there is an ACPI
658 * device object with the PNP0D80 compatible device ID (System Power Management
659 * Controller) and a specific _DSM method under it. That method, if present,
660 * can be used to indicate to the platform that the OS is transitioning into a
661 * low-power state in which certain types of activity are not desirable or that
662 * it is leaving such a state, which allows the platform to adjust its operation
663 * mode accordingly.
664 */
665static const struct acpi_device_id lps0_device_ids[] = {
666 {"PNP0D80", },
667 {"", },
668};
669
670#define ACPI_LPS0_DSM_UUID "c4eb40a0-6cd2-11e2-bcfd-0800200c9a66"
671
672#define ACPI_LPS0_SCREEN_OFF 3
673#define ACPI_LPS0_SCREEN_ON 4
674#define ACPI_LPS0_ENTRY 5
675#define ACPI_LPS0_EXIT 6
676
677#define ACPI_S2IDLE_FUNC_MASK ((1 << ACPI_LPS0_ENTRY) | (1 << ACPI_LPS0_EXIT))
678
679static acpi_handle lps0_device_handle;
680static guid_t lps0_dsm_guid;
681static char lps0_dsm_func_mask;
682
683static void acpi_sleep_run_lps0_dsm(unsigned int func)
684{
685 union acpi_object *out_obj;
686
687 if (!(lps0_dsm_func_mask & (1 << func)))
688 return;
689
690 out_obj = acpi_evaluate_dsm(lps0_device_handle, &lps0_dsm_guid, 1, func, NULL);
691 ACPI_FREE(out_obj);
692
693 acpi_handle_debug(lps0_device_handle, "_DSM function %u evaluation %s\n",
694 func, out_obj ? "successful" : "failed");
695}
696
697static int lps0_device_attach(struct acpi_device *adev,
698 const struct acpi_device_id *not_used)
699{
700 union acpi_object *out_obj;
701
702 if (lps0_device_handle)
703 return 0;
704
705 if (!(acpi_gbl_FADT.flags & ACPI_FADT_LOW_POWER_S0))
706 return 0;
707
708 guid_parse(ACPI_LPS0_DSM_UUID, &lps0_dsm_guid);
709 /* Check if the _DSM is present and as expected. */
710 out_obj = acpi_evaluate_dsm(adev->handle, &lps0_dsm_guid, 1, 0, NULL);
711 if (out_obj && out_obj->type == ACPI_TYPE_BUFFER) {
712 char bitmask = *(char *)out_obj->buffer.pointer;
713
714 if ((bitmask & ACPI_S2IDLE_FUNC_MASK) == ACPI_S2IDLE_FUNC_MASK) {
715 lps0_dsm_func_mask = bitmask;
716 lps0_device_handle = adev->handle;
717 }
718
719 acpi_handle_debug(adev->handle, "_DSM function mask: 0x%x\n",
720 bitmask);
721 } else {
722 acpi_handle_debug(adev->handle,
723 "_DSM function 0 evaluation failed\n");
724 }
725 ACPI_FREE(out_obj);
726 return 0;
727}
728
729static struct acpi_scan_handler lps0_handler = {
730 .ids = lps0_device_ids,
731 .attach = lps0_device_attach,
732};
733
653static int acpi_freeze_begin(void) 734static int acpi_freeze_begin(void)
654{ 735{
655 acpi_scan_lock_acquire(); 736 acpi_scan_lock_acquire();
737 s2idle_in_progress = true;
656 return 0; 738 return 0;
657} 739}
658 740
659static int acpi_freeze_prepare(void) 741static int acpi_freeze_prepare(void)
660{ 742{
661 acpi_enable_wakeup_devices(ACPI_STATE_S0); 743 if (lps0_device_handle) {
662 acpi_enable_all_wakeup_gpes(); 744 acpi_sleep_run_lps0_dsm(ACPI_LPS0_SCREEN_OFF);
663 acpi_os_wait_events_complete(); 745 acpi_sleep_run_lps0_dsm(ACPI_LPS0_ENTRY);
746 } else {
747 /*
748 * The configuration of GPEs is changed here to avoid spurious
749 * wakeups, but that should not be necessary if this is a
750 * "low-power S0" platform and the low-power S0 _DSM is present.
751 */
752 acpi_enable_all_wakeup_gpes();
753 acpi_os_wait_events_complete();
754 }
664 if (acpi_sci_irq_valid()) 755 if (acpi_sci_irq_valid())
665 enable_irq_wake(acpi_sci_irq); 756 enable_irq_wake(acpi_sci_irq);
757
666 return 0; 758 return 0;
667} 759}
668 760
761static void acpi_freeze_wake(void)
762{
763 /*
764 * If IRQD_WAKEUP_ARMED is not set for the SCI at this point, it means
765 * that the SCI has triggered while suspended, so cancel the wakeup in
766 * case it has not been a wakeup event (the GPEs will be checked later).
767 */
768 if (acpi_sci_irq_valid() &&
769 !irqd_is_wakeup_armed(irq_get_irq_data(acpi_sci_irq))) {
770 pm_system_cancel_wakeup();
771 s2idle_wakeup = true;
772 }
773}
774
775static void acpi_freeze_sync(void)
776{
777 /*
778 * Process all pending events in case there are any wakeup ones.
779 *
780 * The EC driver uses the system workqueue, so that one needs to be
781 * flushed too.
782 */
783 acpi_os_wait_events_complete();
784 flush_scheduled_work();
785 s2idle_wakeup = false;
786}
787
669static void acpi_freeze_restore(void) 788static void acpi_freeze_restore(void)
670{ 789{
671 acpi_disable_wakeup_devices(ACPI_STATE_S0);
672 if (acpi_sci_irq_valid()) 790 if (acpi_sci_irq_valid())
673 disable_irq_wake(acpi_sci_irq); 791 disable_irq_wake(acpi_sci_irq);
674 acpi_enable_all_runtime_gpes(); 792
793 if (lps0_device_handle) {
794 acpi_sleep_run_lps0_dsm(ACPI_LPS0_EXIT);
795 acpi_sleep_run_lps0_dsm(ACPI_LPS0_SCREEN_ON);
796 } else {
797 acpi_enable_all_runtime_gpes();
798 }
675} 799}
676 800
677static void acpi_freeze_end(void) 801static void acpi_freeze_end(void)
678{ 802{
803 s2idle_in_progress = false;
679 acpi_scan_lock_release(); 804 acpi_scan_lock_release();
680} 805}
681 806
682static const struct platform_freeze_ops acpi_freeze_ops = { 807static const struct platform_freeze_ops acpi_freeze_ops = {
683 .begin = acpi_freeze_begin, 808 .begin = acpi_freeze_begin,
684 .prepare = acpi_freeze_prepare, 809 .prepare = acpi_freeze_prepare,
810 .wake = acpi_freeze_wake,
811 .sync = acpi_freeze_sync,
685 .restore = acpi_freeze_restore, 812 .restore = acpi_freeze_restore,
686 .end = acpi_freeze_end, 813 .end = acpi_freeze_end,
687}; 814};
@@ -696,13 +823,28 @@ static void acpi_sleep_suspend_setup(void)
696 823
697 suspend_set_ops(old_suspend_ordering ? 824 suspend_set_ops(old_suspend_ordering ?
698 &acpi_suspend_ops_old : &acpi_suspend_ops); 825 &acpi_suspend_ops_old : &acpi_suspend_ops);
826
827 acpi_scan_add_handler(&lps0_handler);
699 freeze_set_ops(&acpi_freeze_ops); 828 freeze_set_ops(&acpi_freeze_ops);
700} 829}
701 830
702#else /* !CONFIG_SUSPEND */ 831#else /* !CONFIG_SUSPEND */
832#define s2idle_in_progress (false)
833#define s2idle_wakeup (false)
834#define lps0_device_handle (NULL)
703static inline void acpi_sleep_suspend_setup(void) {} 835static inline void acpi_sleep_suspend_setup(void) {}
704#endif /* !CONFIG_SUSPEND */ 836#endif /* !CONFIG_SUSPEND */
705 837
838bool acpi_s2idle_wakeup(void)
839{
840 return s2idle_wakeup;
841}
842
843bool acpi_sleep_no_ec_events(void)
844{
845 return !s2idle_in_progress || !lps0_device_handle;
846}
847
706#ifdef CONFIG_PM_SLEEP 848#ifdef CONFIG_PM_SLEEP
707static u32 saved_bm_rld; 849static u32 saved_bm_rld;
708 850