All of lore.kernel.org
 help / color / mirror / Atom feed
From: Vimal Kumar <vimal.kumar32@gmail.com>
To: "Rafael J. Wysocki" <rafael@kernel.org>,
	Len Brown <len.brown@intel.com>, Pavel Machek <pavel@ucw.cz>,
	Greg Kroah-Hartman <gregkh@linuxfoundation.org>,
	linux-pm@vger.kernel.org, linux-kernel@vger.kernel.org
Cc: chinmoyghosh2001@gmail.com, badolevishal1116@gmail.com,
	mintupatel89@gmail.com, Vimal Kumar <vimal.kumar32@gmail.com>
Subject: [PATCH] PM / sleep: Mechanism to find source aborting kernel suspend transition
Date: Sat,  9 Dec 2023 13:40:54 +0530	[thread overview]
Message-ID: <20231209081056.1497-1-vimal.kumar32@gmail.com> (raw)

Sometimes kernel suspend transitions can be aborted unconditionally by
manipulating pm_abort_suspend value using "hard" wakeup triggers or
through "pm_system_wakeup()".

There is no way to trace the source path of module or subsystem which
aborted the suspend transitions. This change will create a list of
wakeup sources aborting suspend in progress through "hard" events as
well as subsytems aborting suspend using "pm_system_wakeup()".

Example: Existing suspend failure logs:
[  349.708359] PM: Some devices failed to suspend, or early wake event detected
[  350.327842] PM: suspend exit

Suspend failure logs with this change:
[  518.761835] PM: Some devices failed to suspend, or early wake event detected
[  519.486939] Abort: ws or subsystem uart_suspend_port aborted suspend
[  519.500594] PM: suspend exit

Here we can clearly identify the module triggerring abort suspend.

Co-developed-by: Chinmoy Ghosh <chinmoyghosh2001@gmail.com>
Signed-off-by: Chinmoy Ghosh <chinmoyghosh2001@gmail.com>
Co-developed-by: Mintu Patel <mintupatel89@gmail.com>
Signed-off-by: Mintu Patel <mintupatel89@gmail.com>
Co-developed-by: Vishal Badole <badolevishal1116@gmail.com>
Signed-off-by: Vishal Badole <badolevishal1116@gmail.com>
Signed-off-by: Vimal Kumar <vimal.kumar32@gmail.com>
---
 drivers/base/power/wakeup.c | 75 ++++++++++++++++++++++++++++++++++++-
 include/linux/suspend.h     |  2 +
 kernel/power/suspend.c      |  1 +
 3 files changed, 77 insertions(+), 1 deletion(-)

diff --git a/drivers/base/power/wakeup.c b/drivers/base/power/wakeup.c
index a917219feea6..f640034cab6d 100644
--- a/drivers/base/power/wakeup.c
+++ b/drivers/base/power/wakeup.c
@@ -73,6 +73,13 @@ static struct wakeup_source deleted_ws = {
 
 static DEFINE_IDA(wakeup_ida);
 
+struct pm_abort_suspend_source {
+	struct list_head list;     //linux kernel list implementation
+	char *source_triggering_abort_suspend;
+};
+
+LIST_HEAD(pm_abort_suspend_list);
+
 /**
  * wakeup_source_create - Create a struct wakeup_source object.
  * @name: Name of the new wakeup source.
@@ -575,6 +582,53 @@ static void wakeup_source_activate(struct wakeup_source *ws)
 	trace_wakeup_source_activate(ws->name, cec);
 }
 
+/**
+ * clear_abort_suspend_list: To clear the list containing sources which
+ * aborted suspend transitions.
+ * Functionality: The list will be cleared every time system PM exits as we
+ * can find sources which aborted suspend in the current suspend transisions.
+ */
+void clear_abort_suspend_list(void)
+{
+	struct pm_abort_suspend_source *info, *tmp;
+
+	if (!list_empty(&pm_abort_suspend_list))
+		list_for_each_entry_safe(info, tmp, &pm_abort_suspend_list, list) {
+			list_del(&info->list);
+			kfree(info);
+		}
+}
+EXPORT_SYMBOL_GPL(clear_abort_suspend_list);
+
+/**
+ * pm_add_abort_suspend_source: add sources who aborted system suspend transitions.
+ * @func_name: Name of the WS or subsystem which needs to added in the list
+ */
+void pm_add_abort_suspend_source(const char *source_name)
+{
+	struct pm_abort_suspend_source *info = NULL;
+
+	info = kmalloc(sizeof(struct pm_abort_suspend_source), GFP_KERNEL);
+	if (unlikely(!info)) {
+		pr_err("Failed to alloc memory for pm_abort_suspend_source info\n");
+		return;
+	}
+
+	/* Initialize the list within the struct if it's not already initialized */
+	if (list_empty(&info->list))
+		INIT_LIST_HEAD(&info->list);
+
+	info->source_triggering_abort_suspend = kstrdup(source_name, GFP_KERNEL);
+	if (unlikely(!info->source_triggering_abort_suspend)) {
+		pr_err("Failed to get abort_suspend source_name\n");
+		kfree(info);
+		return;
+	}
+
+	list_add_tail(&info->list, &pm_abort_suspend_list);
+}
+EXPORT_SYMBOL_GPL(pm_add_abort_suspend_source);
+
 /**
  * wakeup_source_report_event - Report wakeup event using the given source.
  * @ws: Wakeup source to report the event for.
@@ -590,8 +644,11 @@ static void wakeup_source_report_event(struct wakeup_source *ws, bool hard)
 	if (!ws->active)
 		wakeup_source_activate(ws);
 
-	if (hard)
+	if (hard) {
+		if (pm_suspend_target_state != PM_SUSPEND_ON)
+			pm_add_abort_suspend_source(ws->name);
 		pm_system_wakeup();
+	}
 }
 
 /**
@@ -893,12 +950,28 @@ bool pm_wakeup_pending(void)
 		pm_print_active_wakeup_sources();
 	}
 
+	if (atomic_read(&pm_abort_suspend) > 0) {
+		if (!list_empty(&pm_abort_suspend_list))
+			list_for_each_entry(info, &pm_abort_suspend_list, list) {
+				log_suspend_abort_reason("ws or subsystem %s aborted suspend\n",
+						info->source_triggering_abort_suspend);
+			}
+	}
+
 	return ret || atomic_read(&pm_abort_suspend) > 0;
 }
 EXPORT_SYMBOL_GPL(pm_wakeup_pending);
 
 void pm_system_wakeup(void)
 {
+	char buf[MAX_SUSPEND_ABORT_LEN];
+
+	if (pm_suspend_target_state != PM_SUSPEND_ON) {
+		sprintf(buf, "%ps", __builtin_return_address(0));
+		if (strcmp(buf, "pm_wakeup_ws_event"))
+			pm_add_abort_suspend_source(buf);
+	}
+
 	atomic_inc(&pm_abort_suspend);
 	s2idle_wake();
 }
diff --git a/include/linux/suspend.h b/include/linux/suspend.h
index ef503088942d..803071f664e7 100644
--- a/include/linux/suspend.h
+++ b/include/linux/suspend.h
@@ -528,6 +528,7 @@ extern void pm_print_active_wakeup_sources(void);
 
 extern unsigned int lock_system_sleep(void);
 extern void unlock_system_sleep(unsigned int);
+extern void clear_abort_suspend_list(void);
 
 #else /* !CONFIG_PM_SLEEP */
 
@@ -556,6 +557,7 @@ static inline void pm_system_irq_wakeup(unsigned int irq_number) {}
 
 static inline unsigned int lock_system_sleep(void) { return 0; }
 static inline void unlock_system_sleep(unsigned int flags) {}
+static inline void clear_abort_suspend_list(void) {}
 
 #endif /* !CONFIG_PM_SLEEP */
 
diff --git a/kernel/power/suspend.c b/kernel/power/suspend.c
index fa3bf161d13f..64a99f26bd51 100644
--- a/kernel/power/suspend.c
+++ b/kernel/power/suspend.c
@@ -623,6 +623,7 @@ int pm_suspend(suspend_state_t state)
 	} else {
 		suspend_stats.success++;
 	}
+	clear_abort_suspend_list();
 	pr_info("suspend exit\n");
 	return error;
 }
-- 
2.25.1


             reply	other threads:[~2023-12-09  8:11 UTC|newest]

Thread overview: 7+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2023-12-09  8:10 Vimal Kumar [this message]
2023-12-09  9:21 ` [PATCH] PM / sleep: Mechanism to find source aborting kernel suspend transition Greg Kroah-Hartman
2023-12-09 14:53   ` Vimal Kumar
2023-12-09 15:26 ` Christophe JAILLET
2023-12-09 17:52 ` kernel test robot
2023-12-09 17:52 ` kernel test robot
2023-12-09 21:24 ` kernel test robot

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=20231209081056.1497-1-vimal.kumar32@gmail.com \
    --to=vimal.kumar32@gmail.com \
    --cc=badolevishal1116@gmail.com \
    --cc=chinmoyghosh2001@gmail.com \
    --cc=gregkh@linuxfoundation.org \
    --cc=len.brown@intel.com \
    --cc=linux-kernel@vger.kernel.org \
    --cc=linux-pm@vger.kernel.org \
    --cc=mintupatel89@gmail.com \
    --cc=pavel@ucw.cz \
    --cc=rafael@kernel.org \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.