9100d24dfd
-----BEGIN PGP SIGNATURE----- iQIzBAABCAAdFiEEZH8oZUiU471FcZm+ONu9yGCSaT4FAmYaZdgACgkQONu9yGCS aT4oMxAA0pATFAq8RN5f9CmYlMg5HqHgzZ8lJv8P0/reOINhUa+F5sJb1n+x+Ch4 WQbmiFeZRzfsKZ2qKhIdNR0Lg+9JOr/DtYXdSBZ6InfSWrTAIrQ9fjl5Warkmcgg O4WbgF5BVgU3vGFATgxLvnUZwhR1D7WK93oMDunzrT7+OqyncU3f1Uj53ZAu9030 z18UNqnTxDLYH/CMGwAeRkaZqBev9gZ1HdgQWA27SVLqWQwZq0al81Cmlo+ECVmk 5dF6V2pid4qfKGJjDDfx1NS0PVnoP68iK4By1SXyoFV9VBiSwp77nUUyDr7YsHsT u8GpZHr9jZvSO5/xtKv20NPLejTPCRKc06CbkwpikDRtGOocBL8em0GuVqlf8hMs KwDb6ZEzYhXZGPJHbJM+aRD1tq/KHw9X7TrldOszMQPr6lubBtscPbg1FCg3OlcC HUrtub0i275x7TH0dJeRTD8TRE9jRmF+tl7KQytEJM3JRrquFjLyhDj+/VJnZkiB lzj3FRf4zshzgz4+CAeqXO/8Lu8b3fGYmcW1acCmk7emjDcXUKojPj/Aig6T4l7P oCWDY3+w1E6eiyE8BazxY1KUa/41ld0VJnlW5JWGRaDFTJwrk0h6/rvf9qImSckw IGx24UezRyp6NS1op3Qm2iwHLr41pFRfKxNm9ppgH9iBPzOhe38= =pkLL -----END PGP SIGNATURE----- Merge 5.10.215 into android12-5.10-lts Changes in 5.10.215 amdkfd: use calloc instead of kzalloc to avoid integer overflow Documentation/hw-vuln: Update spectre doc x86/cpu: Support AMD Automatic IBRS x86/bugs: Use sysfs_emit() timers: Update kernel-doc for various functions timers: Use del_timer_sync() even on UP timers: Rename del_timer_sync() to timer_delete_sync() wifi: brcmfmac: Fix use-after-free bug in brcmf_cfg80211_detach media: staging: ipu3-imgu: Set fields before media_entity_pads_init() clk: qcom: gcc-sdm845: Add soft dependency on rpmhpd smack: Set SMACK64TRANSMUTE only for dirs in smack_inode_setxattr() smack: Handle SMACK64TRANSMUTE in smack_inode_setsecurity() arm: dts: marvell: Fix maxium->maxim typo in brownstone dts drm/vmwgfx: stop using ttm_bo_create v2 drm/vmwgfx: switch over to the new pin interface v2 drm/vmwgfx/vmwgfx_cmdbuf_res: Remove unused variable 'ret' drm/vmwgfx: Fix some static checker warnings drm/vmwgfx: Fix possible null pointer derefence with invalid contexts serial: max310x: fix NULL pointer dereference in I2C instantiation media: xc4000: Fix atomicity violation in xc4000_get_frequency KVM: Always flush async #PF workqueue when vCPU is being destroyed sparc64: NMI watchdog: fix return value of __setup handler sparc: vDSO: fix return value of __setup handler crypto: qat - fix double free during reset crypto: qat - resolve race condition during AER recovery selftests/mqueue: Set timeout to 180 seconds ext4: correct best extent lstart adjustment logic block: introduce zone_write_granularity limit block: Clear zone limits for a non-zoned stacked queue bounds: support non-power-of-two CONFIG_NR_CPUS fat: fix uninitialized field in nostale filehandles ubifs: Set page uptodate in the correct place ubi: Check for too small LEB size in VTBL code ubi: correct the calculation of fastmap size mtd: rawnand: meson: fix scrambling mode value in command macro parisc: Avoid clobbering the C/B bits in the PSW with tophys and tovirt macros parisc: Fix ip_fast_csum parisc: Fix csum_ipv6_magic on 32-bit systems parisc: Fix csum_ipv6_magic on 64-bit systems parisc: Strip upper 32 bit of sum in csum_ipv6_magic for 64-bit builds PM: suspend: Set mem_sleep_current during kernel command line setup clk: qcom: gcc-ipq6018: fix terminating of frequency table arrays clk: qcom: gcc-ipq8074: fix terminating of frequency table arrays clk: qcom: mmcc-apq8084: fix terminating of frequency table arrays clk: qcom: mmcc-msm8974: fix terminating of frequency table arrays powerpc/fsl: Fix mfpmr build errors with newer binutils USB: serial: ftdi_sio: add support for GMC Z216C Adapter IR-USB USB: serial: add device ID for VeriFone adapter USB: serial: cp210x: add ID for MGP Instruments PDS100 USB: serial: option: add MeiG Smart SLM320 product USB: serial: cp210x: add pid/vid for TDK NC0110013M and MM0110113M PM: sleep: wakeirq: fix wake irq warning in system suspend mmc: tmio: avoid concurrent runs of mmc_request_done() fuse: fix root lookup with nonzero generation fuse: don't unhash root usb: typec: ucsi: Clean up UCSI_CABLE_PROP macros printk/console: Split out code that enables default console serial: Lock console when calling into driver before registration btrfs: fix off-by-one chunk length calculation at contains_pending_extent() PCI: Drop pci_device_remove() test of pci_dev->driver PCI/PM: Drain runtime-idle callbacks before driver removal PCI/ERR: Cache RCEC EA Capability offset in pci_init_capabilities() PCI: Cache PCIe Device Capabilities register PCI: Work around Intel I210 ROM BAR overlap defect PCI/ASPM: Make Intel DG2 L1 acceptable latency unlimited PCI/DPC: Quirk PIO log size for certain Intel Root Ports PCI/DPC: Quirk PIO log size for Intel Raptor Lake Root Ports Revert "Revert "md/raid5: Wait for MD_SB_CHANGE_PENDING in raid5d"" dm-raid: fix lockdep waring in "pers->hot_add_disk" mac802154: fix llsec key resources release in mac802154_llsec_key_del mm: swap: fix race between free_swap_and_cache() and swapoff() mmc: core: Fix switch on gp3 partition drm/etnaviv: Restore some id values hwmon: (amc6821) add of_match table ext4: fix corruption during on-line resize nvmem: meson-efuse: fix function pointer type mismatch slimbus: core: Remove usage of the deprecated ida_simple_xx() API phy: tegra: xusb: Add API to retrieve the port number of phy usb: gadget: tegra-xudc: Use dev_err_probe() usb: gadget: tegra-xudc: Fix USB3 PHY retrieval logic speakup: Fix 8bit characters from direct synth PCI/ERR: Clear AER status only when we control AER PCI/AER: Block runtime suspend when handling errors nfs: fix UAF in direct writes kbuild: Move -Wenum-{compare-conditional,enum-conversion} into W=1 PCI: dwc: endpoint: Fix advertised resizable BAR size vfio/platform: Disable virqfds on cleanup ring-buffer: Fix waking up ring buffer readers ring-buffer: Do not set shortest_full when full target is hit ring-buffer: Fix resetting of shortest_full ring-buffer: Fix full_waiters_pending in poll soc: fsl: qbman: Always disable interrupts when taking cgr_lock soc: fsl: qbman: Add helper for sanity checking cgr ops soc: fsl: qbman: Add CGR update function soc: fsl: qbman: Use raw spinlock for cgr_lock s390/zcrypt: fix reference counting on zcrypt card objects drm/panel: do not return negative error codes from drm_panel_get_modes() drm/exynos: do not return negative values from .get_modes() drm/imx/ipuv3: do not return negative values from .get_modes() drm/vc4: hdmi: do not return negative values from .get_modes() memtest: use {READ,WRITE}_ONCE in memory scanning nilfs2: fix failure to detect DAT corruption in btree and direct mappings nilfs2: prevent kernel bug at submit_bh_wbc() cpufreq: dt: always allocate zeroed cpumask x86/CPU/AMD: Update the Zenbleed microcode revisions net: hns3: tracing: fix hclgevf trace event strings wireguard: netlink: check for dangling peer via is_dead instead of empty list wireguard: netlink: access device through ctx instead of peer ahci: asm1064: correct count of reported ports ahci: asm1064: asm1166: don't limit reported ports drm/amd/display: Return the correct HDCP error code drm/amd/display: Fix noise issue on HDMI AV mute dm snapshot: fix lockup in dm_exception_table_exit vxge: remove unnecessary cast in kfree() x86/stackprotector/32: Make the canary into a regular percpu variable x86/pm: Work around false positive kmemleak report in msr_build_context() scripts: kernel-doc: Fix syntax error due to undeclared args variable comedi: comedi_test: Prevent timers rescheduling during deletion cpufreq: brcmstb-avs-cpufreq: fix up "add check for cpufreq_cpu_get's return value" netfilter: nf_tables: mark set as dead when unbinding anonymous set with timeout netfilter: nf_tables: disallow anonymous set with timeout flag netfilter: nf_tables: reject constant set with timeout Drivers: hv: vmbus: Calculate ring buffer size for more efficient use of memory xfrm: Avoid clang fortify warning in copy_to_user_tmpl() KVM: SVM: Flush pages under kvm->lock to fix UAF in svm_register_enc_region() ALSA: hda/realtek - Fix headset Mic no show at resume back for Lenovo ALC897 platform USB: usb-storage: Prevent divide-by-0 error in isd200_ata_command usb: gadget: ncm: Fix handling of zero block length packets usb: port: Don't try to peer unused USB ports based on location tty: serial: fsl_lpuart: avoid idle preamble pending if CTS is enabled mei: me: add arrow lake point S DID mei: me: add arrow lake point H DID vt: fix unicode buffer corruption when deleting characters fs/aio: Check IOCB_AIO_RW before the struct aio_kiocb conversion tee: optee: Fix kernel panic caused by incorrect error handling xen/events: close evtchn after mapping cleanup printk: Update @console_may_schedule in console_trylock_spinning() btrfs: allocate btrfs_ioctl_defrag_range_args on stack x86/asm: Add _ASM_RIP() macro for x86-64 (%rip) suffix x86/bugs: Add asm helpers for executing VERW x86/entry_64: Add VERW just before userspace transition x86/entry_32: Add VERW just before userspace transition x86/bugs: Use ALTERNATIVE() instead of mds_user_clear static key KVM/VMX: Use BT+JNC, i.e. EFLAGS.CF to select VMRESUME vs. VMLAUNCH KVM/VMX: Move VERW closer to VMentry for MDS mitigation x86/mmio: Disable KVM mitigation when X86_FEATURE_CLEAR_CPU_BUF is set Documentation/hw-vuln: Add documentation for RFDS x86/rfds: Mitigate Register File Data Sampling (RFDS) KVM/x86: Export RFDS_NO and RFDS_CLEAR to guests perf/core: Fix reentry problem in perf_output_read_group() efivarfs: Request at most 512 bytes for variable names powerpc: xor_vmx: Add '-mhard-float' to CFLAGS serial: sc16is7xx: convert from _raw_ to _noinc_ regmap functions for FIFO mm/memory-failure: fix an incorrect use of tail pages mm/migrate: set swap entry values of THP tail pages properly. init: open /initrd.image with O_LARGEFILE wifi: mac80211: check/clear fast rx for non-4addr sta VLAN changes exec: Fix NOMMU linux_binprm::exec in transfer_args_to_stack() hexagon: vmlinux.lds.S: handle attributes section mmc: core: Initialize mmc_blk_ioc_data mmc: core: Avoid negative index with array access net: ll_temac: platform_get_resource replaced by wrong function usb: cdc-wdm: close race between read and workqueue ALSA: sh: aica: reorder cleanup operations to avoid UAF bugs scsi: core: Fix unremoved procfs host directory regression staging: vc04_services: changen strncpy() to strscpy_pad() staging: vc04_services: fix information leak in create_component() USB: core: Add hub_get() and hub_put() routines usb: dwc2: host: Fix remote wakeup from hibernation usb: dwc2: host: Fix hibernation flow usb: dwc2: host: Fix ISOC flow in DDMA mode usb: dwc2: gadget: LPM flow fix usb: udc: remove warning when queue disabled ep usb: typec: ucsi: Ack unsupported commands usb: typec: ucsi: Clear UCSI_CCI_RESET_COMPLETE before reset scsi: qla2xxx: Split FCE|EFT trace control scsi: qla2xxx: Fix command flush on cable pull scsi: qla2xxx: Delay I/O Abort on PCI error x86/cpu: Enable STIBP on AMD if Automatic IBRS is enabled PCI/DPC: Quirk PIO log size for Intel Ice Lake Root Ports scsi: lpfc: Correct size for wqe for memset() USB: core: Fix deadlock in usb_deauthorize_interface() nfc: nci: Fix uninit-value in nci_dev_up and nci_ntf_packet ixgbe: avoid sleeping allocation in ixgbe_ipsec_vf_add_sa() tcp: properly terminate timers for kernel sockets ACPICA: debugger: check status of acpi_evaluate_object() in acpi_db_walk_for_fields() bpf: Protect against int overflow for stack access size Octeontx2-af: fix pause frame configuration in GMP mode dm integrity: fix out-of-range warning r8169: fix issue caused by buggy BIOS on certain boards with RTL8168d x86/cpufeatures: Add new word for scattered features Bluetooth: hci_event: set the conn encrypted before conn establishes Bluetooth: Fix TOCTOU in HCI debugfs implementation netfilter: nf_tables: disallow timeout for anonymous sets net/rds: fix possible cp null dereference vfio/pci: Disable auto-enable of exclusive INTx IRQ vfio/pci: Lock external INTx masking ops vfio: Introduce interface to flush virqfd inject workqueue vfio/pci: Create persistent INTx handler vfio/platform: Create persistent IRQ handlers vfio/fsl-mc: Block calling interrupt handler without trigger io_uring: ensure '0' is returned on file registration success Revert "x86/mm/ident_map: Use gbpages only where full GB page should be mapped." mm, vmscan: prevent infinite loop for costly GFP_NOIO | __GFP_RETRY_MAYFAIL allocations x86/srso: Add SRSO mitigation for Hygon processors block: add check that partition length needs to be aligned with block size netfilter: nf_tables: reject new basechain after table flag update netfilter: nf_tables: flush pending destroy work before exit_net release netfilter: nf_tables: Fix potential data-race in __nft_flowtable_type_get() netfilter: validate user input for expected length vboxsf: Avoid an spurious warning if load_nls_xxx() fails bpf, sockmap: Prevent lock inversion deadlock in map delete elem net/sched: act_skbmod: prevent kernel-infoleak net: stmmac: fix rx queue priority assignment erspan: make sure erspan_base_hdr is present in skb->head selftests: reuseaddr_conflict: add missing new line at the end of the output ipv6: Fix infinite recursion in fib6_dump_done(). udp: do not transition UDP GRO fraglist partial checksums to unnecessary octeontx2-pf: check negative error code in otx2_open() i40e: fix i40e_count_filters() to count only active/new filters i40e: fix vf may be used uninitialized in this function warning scsi: qla2xxx: Update manufacturer details scsi: qla2xxx: Update manufacturer detail Revert "usb: phy: generic: Get the vbus supply" udp: do not accept non-tunnel GSO skbs landing in a tunnel net: ravb: Always process TX descriptor ring arm64: dts: qcom: sc7180: Remove clock for bluetooth on Trogdor arm64: dts: qcom: sc7180-trogdor: mark bluetooth address as broken ASoC: ops: Fix wraparound for mask in snd_soc_get_volsw ata: sata_sx4: fix pdc20621_get_from_dimm() on 64-bit scsi: mylex: Fix sysfs buffer lengths ata: sata_mv: Fix PCI device ID table declaration compilation warning ALSA: hda/realtek: Update Panasonic CF-SZ6 quirk to support headset with microphone driver core: Introduce device_link_wait_removal() of: dynamic: Synchronize of_changeset_destroy() with the devlink removals x86/mce: Make sure to grab mce_sysfs_mutex in set_bank() s390/entry: align system call table on 8 bytes riscv: Fix spurious errors from __get/put_kernel_nofault x86/bugs: Fix the SRSO mitigation on Zen3/4 x86/retpoline: Do the necessary fixup to the Zen3/4 srso return thunk for !SRSO mptcp: don't account accept() of non-MPC client as fallback to TCP x86/cpufeatures: Add CPUID_LNX_5 to track recently added Linux-defined word objtool: Add asm version of STACK_FRAME_NON_STANDARD wifi: ath9k: fix LNA selection in ath_ant_try_scan() VMCI: Fix memcpy() run-time warning in dg_dispatch_as_host() panic: Flush kernel log buffer at the end arm64: dts: rockchip: fix rk3328 hdmi ports node arm64: dts: rockchip: fix rk3399 hdmi ports node ionic: set adminq irq affinity pstore/zone: Add a null pointer check to the psz_kmsg_read tools/power x86_energy_perf_policy: Fix file leak in get_pkg_num() btrfs: handle chunk tree lookup error in btrfs_relocate_sys_chunks() btrfs: export: handle invalid inode or root reference in btrfs_get_parent() btrfs: send: handle path ref underflow in header iterate_inode_ref() net/smc: reduce rtnl pressure in smc_pnet_create_pnetids_list() Bluetooth: btintel: Fix null ptr deref in btintel_read_version Input: synaptics-rmi4 - fail probing if memory allocation for "phys" fails pinctrl: renesas: checker: Limit cfg reg enum checks to provided IDs sysv: don't call sb_bread() with pointers_lock held scsi: lpfc: Fix possible memory leak in lpfc_rcv_padisc() isofs: handle CDs with bad root inode but good Joliet root directory media: sta2x11: fix irq handler cast ext4: add a hint for block bitmap corrupt state in mb_groups ext4: forbid commit inconsistent quota data when errors=remount-ro drm/amd/display: Fix nanosec stat overflow SUNRPC: increase size of rpc_wait_queue.qlen from unsigned short to unsigned int Revert "ACPI: PM: Block ASUS B1400CEAE from suspend to idle by default" libperf evlist: Avoid out-of-bounds access block: prevent division by zero in blk_rq_stat_sum() RDMA/cm: add timeout to cm_destroy_id wait Input: allocate keycode for Display refresh rate toggle platform/x86: touchscreen_dmi: Add an extra entry for a variant of the Chuwi Vi8 tablet ktest: force $buildonly = 1 for 'make_warnings_file' test type ring-buffer: use READ_ONCE() to read cpu_buffer->commit_page in concurrent environment tools: iio: replace seekdir() in iio_generic_buffer usb: typec: tcpci: add generic tcpci fallback compatible usb: sl811-hcd: only defined function checkdone if QUIRK2 is defined fbdev: viafb: fix typo in hw_bitblt_1 and hw_bitblt_2 drivers/nvme: Add quirks for device 126f:2262 fbmon: prevent division by zero in fb_videomode_from_videomode() netfilter: nf_tables: release batch on table validation from abort path netfilter: nf_tables: release mutex after nft_gc_seq_end from abort path netfilter: nf_tables: discard table flag update with pending basechain deletion tty: n_gsm: require CAP_NET_ADMIN to attach N_GSM0710 ldisc virtio: reenable config if freezing device failed x86/mm/pat: fix VM_PAT handling in COW mappings drm/i915/gt: Reset queue_priority_hint on parking Bluetooth: btintel: Fixe build regression VMCI: Fix possible memcpy() run-time warning in vmci_datagram_invoke_guest_handler() kbuild: dummy-tools: adjust to stricter stackprotector check scsi: sd: Fix wrong zone_write_granularity value during revalidate x86/retpoline: Add NOENDBR annotation to the SRSO dummy return thunk x86/head/64: Re-enable stack protection Linux 5.10.215 Change-Id: I45a0a9c4a0683ff5ef97315690f1f884f666e1b5 Signed-off-by: Greg Kroah-Hartman <gregkh@google.com>
636 lines
16 KiB
C
636 lines
16 KiB
C
// SPDX-License-Identifier: GPL-2.0-only
|
|
/*
|
|
* kernel/power/suspend.c - Suspend to RAM and standby functionality.
|
|
*
|
|
* Copyright (c) 2003 Patrick Mochel
|
|
* Copyright (c) 2003 Open Source Development Lab
|
|
* Copyright (c) 2009 Rafael J. Wysocki <rjw@sisk.pl>, Novell Inc.
|
|
*/
|
|
|
|
#define pr_fmt(fmt) "PM: " fmt
|
|
|
|
#include <linux/string.h>
|
|
#include <linux/delay.h>
|
|
#include <linux/errno.h>
|
|
#include <linux/init.h>
|
|
#include <linux/console.h>
|
|
#include <linux/cpu.h>
|
|
#include <linux/cpuidle.h>
|
|
#include <linux/gfp.h>
|
|
#include <linux/io.h>
|
|
#include <linux/kernel.h>
|
|
#include <linux/list.h>
|
|
#include <linux/mm.h>
|
|
#include <linux/slab.h>
|
|
#include <linux/export.h>
|
|
#include <linux/suspend.h>
|
|
#include <linux/syscore_ops.h>
|
|
#include <linux/swait.h>
|
|
#include <linux/ftrace.h>
|
|
#include <trace/events/power.h>
|
|
#include <linux/compiler.h>
|
|
#include <linux/moduleparam.h>
|
|
#include <linux/wakeup_reason.h>
|
|
|
|
#include "power.h"
|
|
|
|
const char * const pm_labels[] = {
|
|
[PM_SUSPEND_TO_IDLE] = "freeze",
|
|
[PM_SUSPEND_STANDBY] = "standby",
|
|
[PM_SUSPEND_MEM] = "mem",
|
|
};
|
|
const char *pm_states[PM_SUSPEND_MAX];
|
|
static const char * const mem_sleep_labels[] = {
|
|
[PM_SUSPEND_TO_IDLE] = "s2idle",
|
|
[PM_SUSPEND_STANDBY] = "shallow",
|
|
[PM_SUSPEND_MEM] = "deep",
|
|
};
|
|
const char *mem_sleep_states[PM_SUSPEND_MAX];
|
|
|
|
suspend_state_t mem_sleep_current = PM_SUSPEND_TO_IDLE;
|
|
suspend_state_t mem_sleep_default = PM_SUSPEND_MAX;
|
|
suspend_state_t pm_suspend_target_state;
|
|
EXPORT_SYMBOL_GPL(pm_suspend_target_state);
|
|
|
|
unsigned int pm_suspend_global_flags;
|
|
EXPORT_SYMBOL_GPL(pm_suspend_global_flags);
|
|
|
|
static const struct platform_suspend_ops *suspend_ops;
|
|
static const struct platform_s2idle_ops *s2idle_ops;
|
|
static DECLARE_SWAIT_QUEUE_HEAD(s2idle_wait_head);
|
|
|
|
enum s2idle_states __read_mostly s2idle_state;
|
|
static DEFINE_RAW_SPINLOCK(s2idle_lock);
|
|
|
|
/**
|
|
* pm_suspend_default_s2idle - Check if suspend-to-idle is the default suspend.
|
|
*
|
|
* Return 'true' if suspend-to-idle has been selected as the default system
|
|
* suspend method.
|
|
*/
|
|
bool pm_suspend_default_s2idle(void)
|
|
{
|
|
return mem_sleep_current == PM_SUSPEND_TO_IDLE;
|
|
}
|
|
EXPORT_SYMBOL_GPL(pm_suspend_default_s2idle);
|
|
|
|
void s2idle_set_ops(const struct platform_s2idle_ops *ops)
|
|
{
|
|
lock_system_sleep();
|
|
s2idle_ops = ops;
|
|
unlock_system_sleep();
|
|
}
|
|
|
|
static void s2idle_begin(void)
|
|
{
|
|
s2idle_state = S2IDLE_STATE_NONE;
|
|
}
|
|
|
|
static void s2idle_enter(void)
|
|
{
|
|
trace_suspend_resume(TPS("machine_suspend"), PM_SUSPEND_TO_IDLE, true);
|
|
|
|
raw_spin_lock_irq(&s2idle_lock);
|
|
if (pm_wakeup_pending())
|
|
goto out;
|
|
|
|
s2idle_state = S2IDLE_STATE_ENTER;
|
|
raw_spin_unlock_irq(&s2idle_lock);
|
|
|
|
get_online_cpus();
|
|
cpuidle_resume();
|
|
|
|
/* Push all the CPUs into the idle loop. */
|
|
wake_up_all_idle_cpus();
|
|
/* Make the current CPU wait so it can enter the idle loop too. */
|
|
swait_event_exclusive(s2idle_wait_head,
|
|
s2idle_state == S2IDLE_STATE_WAKE);
|
|
|
|
cpuidle_pause();
|
|
put_online_cpus();
|
|
|
|
raw_spin_lock_irq(&s2idle_lock);
|
|
|
|
out:
|
|
s2idle_state = S2IDLE_STATE_NONE;
|
|
raw_spin_unlock_irq(&s2idle_lock);
|
|
|
|
trace_suspend_resume(TPS("machine_suspend"), PM_SUSPEND_TO_IDLE, false);
|
|
}
|
|
|
|
static void s2idle_loop(void)
|
|
{
|
|
pm_pr_dbg("suspend-to-idle\n");
|
|
|
|
/*
|
|
* Suspend-to-idle equals:
|
|
* frozen processes + suspended devices + idle processors.
|
|
* Thus s2idle_enter() should be called right after all devices have
|
|
* been suspended.
|
|
*
|
|
* Wakeups during the noirq suspend of devices may be spurious, so try
|
|
* to avoid them upfront.
|
|
*/
|
|
for (;;) {
|
|
if (s2idle_ops && s2idle_ops->wake) {
|
|
if (s2idle_ops->wake())
|
|
break;
|
|
} else if (pm_wakeup_pending()) {
|
|
break;
|
|
}
|
|
|
|
clear_wakeup_reasons();
|
|
s2idle_enter();
|
|
}
|
|
|
|
pm_pr_dbg("resume from suspend-to-idle\n");
|
|
}
|
|
|
|
void s2idle_wake(void)
|
|
{
|
|
unsigned long flags;
|
|
|
|
raw_spin_lock_irqsave(&s2idle_lock, flags);
|
|
if (s2idle_state > S2IDLE_STATE_NONE) {
|
|
s2idle_state = S2IDLE_STATE_WAKE;
|
|
swake_up_one(&s2idle_wait_head);
|
|
}
|
|
raw_spin_unlock_irqrestore(&s2idle_lock, flags);
|
|
}
|
|
EXPORT_SYMBOL_GPL(s2idle_wake);
|
|
|
|
static bool valid_state(suspend_state_t state)
|
|
{
|
|
/*
|
|
* PM_SUSPEND_STANDBY and PM_SUSPEND_MEM states need low level
|
|
* support and need to be valid to the low level
|
|
* implementation, no valid callback implies that none are valid.
|
|
*/
|
|
return suspend_ops && suspend_ops->valid && suspend_ops->valid(state);
|
|
}
|
|
|
|
void __init pm_states_init(void)
|
|
{
|
|
/* "mem" and "freeze" are always present in /sys/power/state. */
|
|
pm_states[PM_SUSPEND_MEM] = pm_labels[PM_SUSPEND_MEM];
|
|
pm_states[PM_SUSPEND_TO_IDLE] = pm_labels[PM_SUSPEND_TO_IDLE];
|
|
/*
|
|
* Suspend-to-idle should be supported even without any suspend_ops,
|
|
* initialize mem_sleep_states[] accordingly here.
|
|
*/
|
|
mem_sleep_states[PM_SUSPEND_TO_IDLE] = mem_sleep_labels[PM_SUSPEND_TO_IDLE];
|
|
}
|
|
|
|
static int __init mem_sleep_default_setup(char *str)
|
|
{
|
|
suspend_state_t state;
|
|
|
|
for (state = PM_SUSPEND_TO_IDLE; state <= PM_SUSPEND_MEM; state++)
|
|
if (mem_sleep_labels[state] &&
|
|
!strcmp(str, mem_sleep_labels[state])) {
|
|
mem_sleep_default = state;
|
|
mem_sleep_current = state;
|
|
break;
|
|
}
|
|
|
|
return 1;
|
|
}
|
|
__setup("mem_sleep_default=", mem_sleep_default_setup);
|
|
|
|
/**
|
|
* suspend_set_ops - Set the global suspend method table.
|
|
* @ops: Suspend operations to use.
|
|
*/
|
|
void suspend_set_ops(const struct platform_suspend_ops *ops)
|
|
{
|
|
lock_system_sleep();
|
|
|
|
suspend_ops = ops;
|
|
|
|
if (valid_state(PM_SUSPEND_STANDBY)) {
|
|
mem_sleep_states[PM_SUSPEND_STANDBY] = mem_sleep_labels[PM_SUSPEND_STANDBY];
|
|
pm_states[PM_SUSPEND_STANDBY] = pm_labels[PM_SUSPEND_STANDBY];
|
|
if (mem_sleep_default == PM_SUSPEND_STANDBY)
|
|
mem_sleep_current = PM_SUSPEND_STANDBY;
|
|
}
|
|
if (valid_state(PM_SUSPEND_MEM)) {
|
|
mem_sleep_states[PM_SUSPEND_MEM] = mem_sleep_labels[PM_SUSPEND_MEM];
|
|
if (mem_sleep_default >= PM_SUSPEND_MEM)
|
|
mem_sleep_current = PM_SUSPEND_MEM;
|
|
}
|
|
|
|
unlock_system_sleep();
|
|
}
|
|
EXPORT_SYMBOL_GPL(suspend_set_ops);
|
|
|
|
/**
|
|
* suspend_valid_only_mem - Generic memory-only valid callback.
|
|
*
|
|
* Platform drivers that implement mem suspend only and only need to check for
|
|
* that in their .valid() callback can use this instead of rolling their own
|
|
* .valid() callback.
|
|
*/
|
|
int suspend_valid_only_mem(suspend_state_t state)
|
|
{
|
|
return state == PM_SUSPEND_MEM;
|
|
}
|
|
EXPORT_SYMBOL_GPL(suspend_valid_only_mem);
|
|
|
|
static bool sleep_state_supported(suspend_state_t state)
|
|
{
|
|
return state == PM_SUSPEND_TO_IDLE || (suspend_ops && suspend_ops->enter);
|
|
}
|
|
|
|
static int platform_suspend_prepare(suspend_state_t state)
|
|
{
|
|
return state != PM_SUSPEND_TO_IDLE && suspend_ops->prepare ?
|
|
suspend_ops->prepare() : 0;
|
|
}
|
|
|
|
static int platform_suspend_prepare_late(suspend_state_t state)
|
|
{
|
|
return state == PM_SUSPEND_TO_IDLE && s2idle_ops && s2idle_ops->prepare ?
|
|
s2idle_ops->prepare() : 0;
|
|
}
|
|
|
|
static int platform_suspend_prepare_noirq(suspend_state_t state)
|
|
{
|
|
if (state == PM_SUSPEND_TO_IDLE)
|
|
return s2idle_ops && s2idle_ops->prepare_late ?
|
|
s2idle_ops->prepare_late() : 0;
|
|
|
|
return suspend_ops->prepare_late ? suspend_ops->prepare_late() : 0;
|
|
}
|
|
|
|
static void platform_resume_noirq(suspend_state_t state)
|
|
{
|
|
if (state == PM_SUSPEND_TO_IDLE) {
|
|
if (s2idle_ops && s2idle_ops->restore_early)
|
|
s2idle_ops->restore_early();
|
|
} else if (suspend_ops->wake) {
|
|
suspend_ops->wake();
|
|
}
|
|
}
|
|
|
|
static void platform_resume_early(suspend_state_t state)
|
|
{
|
|
if (state == PM_SUSPEND_TO_IDLE && s2idle_ops && s2idle_ops->restore)
|
|
s2idle_ops->restore();
|
|
}
|
|
|
|
static void platform_resume_finish(suspend_state_t state)
|
|
{
|
|
if (state != PM_SUSPEND_TO_IDLE && suspend_ops->finish)
|
|
suspend_ops->finish();
|
|
}
|
|
|
|
static int platform_suspend_begin(suspend_state_t state)
|
|
{
|
|
if (state == PM_SUSPEND_TO_IDLE && s2idle_ops && s2idle_ops->begin)
|
|
return s2idle_ops->begin();
|
|
else if (suspend_ops && suspend_ops->begin)
|
|
return suspend_ops->begin(state);
|
|
else
|
|
return 0;
|
|
}
|
|
|
|
static void platform_resume_end(suspend_state_t state)
|
|
{
|
|
if (state == PM_SUSPEND_TO_IDLE && s2idle_ops && s2idle_ops->end)
|
|
s2idle_ops->end();
|
|
else if (suspend_ops && suspend_ops->end)
|
|
suspend_ops->end();
|
|
}
|
|
|
|
static void platform_recover(suspend_state_t state)
|
|
{
|
|
if (state != PM_SUSPEND_TO_IDLE && suspend_ops->recover)
|
|
suspend_ops->recover();
|
|
}
|
|
|
|
static bool platform_suspend_again(suspend_state_t state)
|
|
{
|
|
return state != PM_SUSPEND_TO_IDLE && suspend_ops->suspend_again ?
|
|
suspend_ops->suspend_again() : false;
|
|
}
|
|
|
|
#ifdef CONFIG_PM_DEBUG
|
|
static unsigned int pm_test_delay = 5;
|
|
module_param(pm_test_delay, uint, 0644);
|
|
MODULE_PARM_DESC(pm_test_delay,
|
|
"Number of seconds to wait before resuming from suspend test");
|
|
#endif
|
|
|
|
static int suspend_test(int level)
|
|
{
|
|
#ifdef CONFIG_PM_DEBUG
|
|
if (pm_test_level == level) {
|
|
pr_info("suspend debug: Waiting for %d second(s).\n",
|
|
pm_test_delay);
|
|
mdelay(pm_test_delay * 1000);
|
|
return 1;
|
|
}
|
|
#endif /* !CONFIG_PM_DEBUG */
|
|
return 0;
|
|
}
|
|
|
|
/**
|
|
* suspend_prepare - Prepare for entering system sleep state.
|
|
*
|
|
* Common code run for every system sleep state that can be entered (except for
|
|
* hibernation). Run suspend notifiers, allocate the "suspend" console and
|
|
* freeze processes.
|
|
*/
|
|
static int suspend_prepare(suspend_state_t state)
|
|
{
|
|
int error;
|
|
|
|
if (!sleep_state_supported(state))
|
|
return -EPERM;
|
|
|
|
pm_prepare_console();
|
|
|
|
error = pm_notifier_call_chain_robust(PM_SUSPEND_PREPARE, PM_POST_SUSPEND);
|
|
if (error)
|
|
goto Restore;
|
|
|
|
trace_suspend_resume(TPS("freeze_processes"), 0, true);
|
|
error = suspend_freeze_processes();
|
|
trace_suspend_resume(TPS("freeze_processes"), 0, false);
|
|
if (!error)
|
|
return 0;
|
|
|
|
log_suspend_abort_reason("One or more tasks refusing to freeze");
|
|
suspend_stats.failed_freeze++;
|
|
dpm_save_failed_step(SUSPEND_FREEZE);
|
|
pm_notifier_call_chain(PM_POST_SUSPEND);
|
|
Restore:
|
|
pm_restore_console();
|
|
return error;
|
|
}
|
|
|
|
/* default implementation */
|
|
void __weak arch_suspend_disable_irqs(void)
|
|
{
|
|
local_irq_disable();
|
|
}
|
|
|
|
/* default implementation */
|
|
void __weak arch_suspend_enable_irqs(void)
|
|
{
|
|
local_irq_enable();
|
|
}
|
|
|
|
/**
|
|
* suspend_enter - Make the system enter the given sleep state.
|
|
* @state: System sleep state to enter.
|
|
* @wakeup: Returns information that the sleep state should not be re-entered.
|
|
*
|
|
* This function should be called after devices have been suspended.
|
|
*/
|
|
static int suspend_enter(suspend_state_t state, bool *wakeup)
|
|
{
|
|
int error, last_dev;
|
|
|
|
error = platform_suspend_prepare(state);
|
|
if (error)
|
|
goto Platform_finish;
|
|
|
|
error = dpm_suspend_late(PMSG_SUSPEND);
|
|
if (error) {
|
|
last_dev = suspend_stats.last_failed_dev + REC_FAILED_NUM - 1;
|
|
last_dev %= REC_FAILED_NUM;
|
|
pr_err("late suspend of devices failed\n");
|
|
log_suspend_abort_reason("late suspend of %s device failed",
|
|
suspend_stats.failed_devs[last_dev]);
|
|
goto Platform_finish;
|
|
}
|
|
error = platform_suspend_prepare_late(state);
|
|
if (error)
|
|
goto Devices_early_resume;
|
|
|
|
error = dpm_suspend_noirq(PMSG_SUSPEND);
|
|
if (error) {
|
|
last_dev = suspend_stats.last_failed_dev + REC_FAILED_NUM - 1;
|
|
last_dev %= REC_FAILED_NUM;
|
|
pr_err("noirq suspend of devices failed\n");
|
|
log_suspend_abort_reason("noirq suspend of %s device failed",
|
|
suspend_stats.failed_devs[last_dev]);
|
|
goto Platform_early_resume;
|
|
}
|
|
error = platform_suspend_prepare_noirq(state);
|
|
if (error)
|
|
goto Platform_wake;
|
|
|
|
if (suspend_test(TEST_PLATFORM))
|
|
goto Platform_wake;
|
|
|
|
if (state == PM_SUSPEND_TO_IDLE) {
|
|
s2idle_loop();
|
|
goto Platform_wake;
|
|
}
|
|
|
|
error = suspend_disable_secondary_cpus();
|
|
if (error || suspend_test(TEST_CPUS)) {
|
|
log_suspend_abort_reason("Disabling non-boot cpus failed");
|
|
goto Enable_cpus;
|
|
}
|
|
|
|
arch_suspend_disable_irqs();
|
|
BUG_ON(!irqs_disabled());
|
|
|
|
system_state = SYSTEM_SUSPEND;
|
|
|
|
error = syscore_suspend();
|
|
if (!error) {
|
|
*wakeup = pm_wakeup_pending();
|
|
if (!(suspend_test(TEST_CORE) || *wakeup)) {
|
|
trace_suspend_resume(TPS("machine_suspend"),
|
|
state, true);
|
|
error = suspend_ops->enter(state);
|
|
trace_suspend_resume(TPS("machine_suspend"),
|
|
state, false);
|
|
} else if (*wakeup) {
|
|
error = -EBUSY;
|
|
}
|
|
syscore_resume();
|
|
}
|
|
|
|
system_state = SYSTEM_RUNNING;
|
|
|
|
arch_suspend_enable_irqs();
|
|
BUG_ON(irqs_disabled());
|
|
|
|
Enable_cpus:
|
|
suspend_enable_secondary_cpus();
|
|
|
|
Platform_wake:
|
|
platform_resume_noirq(state);
|
|
dpm_resume_noirq(PMSG_RESUME);
|
|
|
|
Platform_early_resume:
|
|
platform_resume_early(state);
|
|
|
|
Devices_early_resume:
|
|
dpm_resume_early(PMSG_RESUME);
|
|
|
|
Platform_finish:
|
|
platform_resume_finish(state);
|
|
return error;
|
|
}
|
|
|
|
/**
|
|
* suspend_devices_and_enter - Suspend devices and enter system sleep state.
|
|
* @state: System sleep state to enter.
|
|
*/
|
|
int suspend_devices_and_enter(suspend_state_t state)
|
|
{
|
|
int error;
|
|
bool wakeup = false;
|
|
|
|
if (!sleep_state_supported(state))
|
|
return -ENOSYS;
|
|
|
|
pm_suspend_target_state = state;
|
|
|
|
if (state == PM_SUSPEND_TO_IDLE)
|
|
pm_set_suspend_no_platform();
|
|
|
|
error = platform_suspend_begin(state);
|
|
if (error)
|
|
goto Close;
|
|
|
|
suspend_console();
|
|
suspend_test_start();
|
|
error = dpm_suspend_start(PMSG_SUSPEND);
|
|
if (error) {
|
|
pr_err("Some devices failed to suspend, or early wake event detected\n");
|
|
log_suspend_abort_reason(
|
|
"Some devices failed to suspend, or early wake event detected");
|
|
goto Recover_platform;
|
|
}
|
|
suspend_test_finish("suspend devices");
|
|
if (suspend_test(TEST_DEVICES))
|
|
goto Recover_platform;
|
|
|
|
do {
|
|
error = suspend_enter(state, &wakeup);
|
|
} while (!error && !wakeup && platform_suspend_again(state));
|
|
|
|
Resume_devices:
|
|
suspend_test_start();
|
|
dpm_resume_end(PMSG_RESUME);
|
|
suspend_test_finish("resume devices");
|
|
trace_suspend_resume(TPS("resume_console"), state, true);
|
|
resume_console();
|
|
trace_suspend_resume(TPS("resume_console"), state, false);
|
|
|
|
Close:
|
|
platform_resume_end(state);
|
|
pm_suspend_target_state = PM_SUSPEND_ON;
|
|
return error;
|
|
|
|
Recover_platform:
|
|
platform_recover(state);
|
|
goto Resume_devices;
|
|
}
|
|
|
|
/**
|
|
* suspend_finish - Clean up before finishing the suspend sequence.
|
|
*
|
|
* Call platform code to clean up, restart processes, and free the console that
|
|
* we've allocated. This routine is not called for hibernation.
|
|
*/
|
|
static void suspend_finish(void)
|
|
{
|
|
suspend_thaw_processes();
|
|
pm_notifier_call_chain(PM_POST_SUSPEND);
|
|
pm_restore_console();
|
|
}
|
|
|
|
/**
|
|
* enter_state - Do common work needed to enter system sleep state.
|
|
* @state: System sleep state to enter.
|
|
*
|
|
* Make sure that no one else is trying to put the system into a sleep state.
|
|
* Fail if that's not the case. Otherwise, prepare for system suspend, make the
|
|
* system enter the given sleep state and clean up after wakeup.
|
|
*/
|
|
static int enter_state(suspend_state_t state)
|
|
{
|
|
int error;
|
|
|
|
trace_suspend_resume(TPS("suspend_enter"), state, true);
|
|
if (state == PM_SUSPEND_TO_IDLE) {
|
|
#ifdef CONFIG_PM_DEBUG
|
|
if (pm_test_level != TEST_NONE && pm_test_level <= TEST_CPUS) {
|
|
pr_warn("Unsupported test mode for suspend to idle, please choose none/freezer/devices/platform.\n");
|
|
return -EAGAIN;
|
|
}
|
|
#endif
|
|
} else if (!valid_state(state)) {
|
|
return -EINVAL;
|
|
}
|
|
if (!mutex_trylock(&system_transition_mutex))
|
|
return -EBUSY;
|
|
|
|
if (state == PM_SUSPEND_TO_IDLE)
|
|
s2idle_begin();
|
|
|
|
if (sync_on_suspend_enabled) {
|
|
trace_suspend_resume(TPS("sync_filesystems"), 0, true);
|
|
ksys_sync_helper();
|
|
trace_suspend_resume(TPS("sync_filesystems"), 0, false);
|
|
}
|
|
|
|
pm_pr_dbg("Preparing system for sleep (%s)\n", mem_sleep_labels[state]);
|
|
pm_suspend_clear_flags();
|
|
error = suspend_prepare(state);
|
|
if (error)
|
|
goto Unlock;
|
|
|
|
if (suspend_test(TEST_FREEZER))
|
|
goto Finish;
|
|
|
|
trace_suspend_resume(TPS("suspend_enter"), state, false);
|
|
pm_pr_dbg("Suspending system (%s)\n", mem_sleep_labels[state]);
|
|
pm_restrict_gfp_mask();
|
|
error = suspend_devices_and_enter(state);
|
|
pm_restore_gfp_mask();
|
|
|
|
Finish:
|
|
events_check_enabled = false;
|
|
pm_pr_dbg("Finishing wakeup.\n");
|
|
suspend_finish();
|
|
Unlock:
|
|
mutex_unlock(&system_transition_mutex);
|
|
return error;
|
|
}
|
|
|
|
/**
|
|
* pm_suspend - Externally visible function for suspending the system.
|
|
* @state: System sleep state to enter.
|
|
*
|
|
* Check if the value of @state represents one of the supported states,
|
|
* execute enter_state() and update system suspend statistics.
|
|
*/
|
|
int pm_suspend(suspend_state_t state)
|
|
{
|
|
int error;
|
|
|
|
if (state <= PM_SUSPEND_ON || state >= PM_SUSPEND_MAX)
|
|
return -EINVAL;
|
|
|
|
pr_info("suspend entry (%s)\n", mem_sleep_labels[state]);
|
|
error = enter_state(state);
|
|
if (error) {
|
|
suspend_stats.fail++;
|
|
dpm_save_failed_errno(error);
|
|
} else {
|
|
suspend_stats.success++;
|
|
}
|
|
pr_info("suspend exit\n");
|
|
return error;
|
|
}
|
|
EXPORT_SYMBOL(pm_suspend);
|