BACKPORT: PM / core: Add support to skip power management in device/driver model
authorSudeep Holla <sudeep.holla@arm.com>
Thu, 14 Feb 2019 18:29:10 +0000 (18:29 +0000)
committerNolen Johnson <johnsonnolen@gmail.com>
Thu, 3 Oct 2024 15:05:01 +0000 (11:05 -0400)
All device objects in the driver model contain fields that control the
handling of various power management activities. However, it's not
always useful. There are few instances where pseudo devices are added
to the model just to take advantage of many other features like
kobjects, udev events, and so on. One such example is cpu devices and
their caches.

The sysfs for the cpu caches are managed by adding devices with cpu
as the parent in cpu_device_create() when secondary cpu is brought
online. Generally when the secondary CPUs are hotplugged back in as part
of resume from suspend-to-ram, we call cpu_device_create() from the cpu
hotplug state machine while the cpu device associated with that CPU is
not yet ready to be resumed as the device_resume() call happens bit
later. It's not really needed to set the flag is_prepared for cpu
devices as they are mostly pseudo device and hotplug framework deals
with state machine and not managed through the cpu device.

This often results in annoying warning when resuming:
Enabling non-boot CPUs ...
CPU1: Booted secondary processor
 cache: parent cpu1 should not be sleeping
CPU1 is up
CPU2: Booted secondary processor
 cache: parent cpu2 should not be sleeping
CPU2 is up
.... and so on.

So in order to fix these kind of errors, we could just completely avoid
doing any power management related initialisations and operations if
they are not used by these devices.

Add no_pm flags to indicate that the device doesn't require any sort of
PM activities and all of them can be completely skipped. We can use the
same flag to also avoid adding not used *power* sysfs entries for these
devices. For now, lets use this for cpu cache devices.

Reviewed-by: Ulf Hansson <ulf.hansson@linaro.org>
Signed-off-by: Sudeep Holla <sudeep.holla@arm.com>
Tested-by: Eugeniu Rosca <erosca@de.adit-jv.com>
Signed-off-by: Rafael J. Wysocki <rafael.j.wysocki@intel.com>
Signed-off-by: Albert I <kras@raphielgang.org>
Change-Id: Ia0fcfe47501397c8165a7760de0e4de0b0669699

drivers/base/cpu.c
drivers/base/power/main.c
drivers/base/power/sysfs.c
include/linux/device.h
include/linux/pm.h

index 88f89a38588a1ca2db773358d8f56a83843dd02f..b7b83c1347a33fba96f5c9845f8a80addf37f73b 100644 (file)
@@ -412,6 +412,7 @@ __cpu_device_create(struct device *parent, void *drvdata,
        dev->parent = parent;
        dev->groups = groups;
        dev->release = device_create_release;
+       device_set_pm_not_required(dev);
        dev_set_drvdata(dev, drvdata);
 
        retval = kobject_set_name_vargs(&dev->kobj, fmt, args);
index 8500a7380e61b6dca1c4e472f295363dc04466d7..810c8f9462b230685115c86dcdfcda6d7f5c8fe1 100644 (file)
@@ -124,6 +124,10 @@ void device_pm_unlock(void)
  */
 void device_pm_add(struct device *dev)
 {
+       /* Skip PM setup/initialization. */
+       if (device_pm_not_required(dev))
+               return;
+
        pr_debug("PM: Adding info for %s:%s\n",
                 dev->bus ? dev->bus->name : "No Bus", dev_name(dev));
        device_pm_check_callbacks(dev);
@@ -141,6 +145,9 @@ void device_pm_add(struct device *dev)
  */
 void device_pm_remove(struct device *dev)
 {
+       if (device_pm_not_required(dev))
+               return;
+
        pr_debug("PM: Removing info for %s:%s\n",
                 dev->bus ? dev->bus->name : "No Bus", dev_name(dev));
        complete_all(&dev->power.completion);
index 39efa7e6c0c0e80ae38669cfb9974b931ee910b9..9c6e6f0c90ad23dc2f1d77a05e2074dc4cf270cd 100644 (file)
@@ -679,6 +679,10 @@ int dpm_sysfs_add(struct device *dev)
 {
        int rc;
 
+       /* No need to create PM sysfs if explicitly disabled. */
+       if (device_pm_not_required(dev))
+               return 0;
+
        rc = sysfs_create_group(&dev->kobj, &pm_attr_group);
        if (rc)
                return rc;
@@ -758,6 +762,8 @@ void rpm_sysfs_remove(struct device *dev)
 
 void dpm_sysfs_remove(struct device *dev)
 {
+       if (device_pm_not_required(dev))
+               return;
        sysfs_unmerge_group(&dev->kobj, &pm_qos_latency_tolerance_attr_group);
        dev_pm_qos_constraints_destroy(dev);
        rpm_sysfs_remove(dev);
index e1f5ecf6fadfbe921d8bb648e735aa1b8730c737..be8e0de7ccc605bbc32363f2009c271e78365d4a 100644 (file)
@@ -985,6 +985,16 @@ static inline bool device_async_suspend_enabled(struct device *dev)
        return !!dev->power.async_suspend;
 }
 
+static inline bool device_pm_not_required(struct device *dev)
+{
+       return dev->power.no_pm;
+}
+
+static inline void device_set_pm_not_required(struct device *dev)
+{
+       dev->power.no_pm = true;
+}
+
 static inline void dev_pm_syscore_device(struct device *dev, bool val)
 {
 #ifdef CONFIG_PM_SLEEP
index 5b7964aaf3e8d59df339ee9da9ce56b283fe5850..ca11ec1d922f409cb6d7380a664a32378311bbb2 100644 (file)
@@ -574,6 +574,7 @@ struct dev_pm_info {
        bool                    is_suspended:1; /* Ditto */
        bool                    is_noirq_suspended:1;
        bool                    is_late_suspended:1;
+       bool                    no_pm:1;
        bool                    early_init:1;   /* Owned by the PM core */
        bool                    direct_complete:1;      /* Owned by the PM core */
        spinlock_t              lock;