diff --git a/drivers/cpuidle/cpuidle.c b/drivers/cpuidle/cpuidle.c
index 8719731..be22174 100644
--- a/drivers/cpuidle/cpuidle.c
+++ b/drivers/cpuidle/cpuidle.c
@@ -23,6 +23,9 @@
 #include <linux/suspend.h>
 #include <linux/tick.h>
 #include <trace/events/power.h>
+#include <linux/cpumask.h>
+#include <linux/spinlock.h>
+#include <linux/syscore_ops.h>
 
 #include "cpuidle.h"
 
@@ -35,6 +38,8 @@
 static int enabled_devices;
 static int off __read_mostly;
 static int initialized __read_mostly;
+static struct cpumask s2idle_cpumask;
+static DEFINE_SPINLOCK(s2idle_spinlock);
 
 int cpuidle_disabled(void)
 {
@@ -137,15 +142,27 @@ static void enter_s2idle_proper(struct cpuidle_driver *drv,
 				struct cpuidle_device *dev, int index)
 {
 	ktime_t time_start, time_end;
+	int cpu;
 
 	time_start = ns_to_ktime(local_clock());
+	cpu = smp_processor_id();
+
+	tick_freeze();
 
 	/*
-	 * trace_suspend_resume() called by tick_freeze() for the last CPU
+	 * trace_suspend_resume() called by syscore_suepnd() for the last CPU
 	 * executing it contains RCU usage regarded as invalid in the idle
 	 * context, so tell RCU about that.
 	 */
-	RCU_NONIDLE(tick_freeze());
+	spin_lock(&s2idle_spinlock);
+	cpumask_set_cpu(cpu, &s2idle_cpumask);
+	if (cpumask_weight(&s2idle_cpumask) == num_online_cpus()) {
+		system_state = SYSTEM_SUSPEND;
+		RCU_NONIDLE(syscore_suspend());
+	}
+
+	spin_unlock(&s2idle_spinlock);
+
 	/*
 	 * The state used here cannot be a "coupled" one, because the "coupled"
 	 * cpuidle mechanism enables interrupts and doing that with timekeeping
@@ -154,12 +171,21 @@ static void enter_s2idle_proper(struct cpuidle_driver *drv,
 	stop_critical_timings();
 	drv->states[index].enter_s2idle(dev, drv, index);
 	WARN_ON(!irqs_disabled());
+
 	/*
-	 * timekeeping_resume() that will be called by tick_unfreeze() for the
+	 * timekeeping_resume() that will be called by syscore_reume() for the
 	 * first CPU executing it calls functions containing RCU read-side
 	 * critical sections, so tell RCU about that.
 	 */
-	RCU_NONIDLE(tick_unfreeze());
+	spin_lock(&s2idle_spinlock);
+	if (cpumask_weight(&s2idle_cpumask) == num_online_cpus()) {
+		RCU_NONIDLE(syscore_resume());
+		system_state = SYSTEM_RUNNING;
+	}
+	cpumask_clear_cpu(cpu, &s2idle_cpumask);
+	spin_unlock(&s2idle_spinlock);
+
+	tick_unfreeze();
 	start_critical_timings();
 
 	time_end = ns_to_ktime(local_clock());
@@ -745,6 +771,8 @@ static int __init cpuidle_init(void)
 	if (cpuidle_disabled())
 		return -ENODEV;
 
+	cpumask_clear(&s2idle_cpumask);
+
 	return cpuidle_add_interface(cpu_subsys.dev_root);
 }
 
diff --git a/kernel/cpu_pm.c b/kernel/cpu_pm.c
index 44a2593..6c2f5ce 100644
--- a/kernel/cpu_pm.c
+++ b/kernel/cpu_pm.c
@@ -12,6 +12,7 @@
 #include <linux/notifier.h>
 #include <linux/spinlock.h>
 #include <linux/syscore_ops.h>
+#include <linux/suspend.h>
 
 static ATOMIC_NOTIFIER_HEAD(cpu_pm_notifier_chain);
 
@@ -172,6 +173,14 @@ static int cpu_pm_suspend(void)
 {
 	int ret;
 
+#ifdef CONFIG_SUSPEND
+	/*
+	 * Skip cpu_pm_suspend in s2idle flow because cpu_pm notifier callbacks
+	 * are triggered in idle framework
+	 */
+	if (s2idle_state != S2IDLE_STATE_NONE)
+		return 0;
+#endif
 	ret = cpu_pm_enter();
 	if (ret)
 		return ret;
@@ -182,6 +191,14 @@ static int cpu_pm_suspend(void)
 
 static void cpu_pm_resume(void)
 {
+#ifdef CONFIG_SUSPEND
+	/*
+	 * Skip cpu_pm_resume in s2idle flow because cpu_pm notifier callbacks
+	 * are triggered in idle framework
+	 */
+	if (s2idle_state != S2IDLE_STATE_NONE)
+		return;
+#endif
 	cpu_cluster_pm_exit();
 	cpu_pm_exit();
 }
diff --git a/kernel/time/tick-common.c b/kernel/time/tick-common.c
index 6c9c342..19feeed 100644
--- a/kernel/time/tick-common.c
+++ b/kernel/time/tick-common.c
@@ -528,15 +528,8 @@ void tick_freeze(void)
 	raw_spin_lock(&tick_freeze_lock);
 
 	tick_freeze_depth++;
-	if (tick_freeze_depth == num_online_cpus()) {
-		trace_suspend_resume(TPS("timekeeping_freeze"),
-				     smp_processor_id(), true);
-		system_state = SYSTEM_SUSPEND;
-		sched_clock_suspend();
-		timekeeping_suspend();
-	} else {
+	if (tick_freeze_depth < num_online_cpus())
 		tick_suspend_local();
-	}
 
 	raw_spin_unlock(&tick_freeze_lock);
 }
@@ -554,13 +547,7 @@ void tick_unfreeze(void)
 {
 	raw_spin_lock(&tick_freeze_lock);
 
-	if (tick_freeze_depth == num_online_cpus()) {
-		timekeeping_resume();
-		sched_clock_resume();
-		system_state = SYSTEM_RUNNING;
-		trace_suspend_resume(TPS("timekeeping_freeze"),
-				     smp_processor_id(), false);
-	} else {
+	if (tick_freeze_depth < num_online_cpus()) {
 		touch_softlockup_watchdog();
 		tick_resume_local();
 	}
