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@xxxxxxxxx>
Signed-off-by: Chinmoy Ghosh <chinmoyghosh2001@xxxxxxxxx>
Co-developed-by: Mintu Patel <mintupatel89@xxxxxxxxx>
Signed-off-by: Mintu Patel <mintupatel89@xxxxxxxxx>
Co-developed-by: Vishal Badole <badolevishal1116@xxxxxxxxx>
Signed-off-by: Vishal Badole <badolevishal1116@xxxxxxxxx>
Signed-off-by: Vimal Kumar <vimal.kumar32@xxxxxxxxx>
---
+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);