Linux IOMMU Development
 help / color / mirror / Atom feed
From: Pranjal Shrivastava <praan@google.com>
To: Joerg Roedel <joro@8bytes.org>, Will Deacon <will@kernel.org>,
	 Robin Murphy <robin.murphy@arm.com>,
	Jason Gunthorpe <jgg@ziepe.ca>,
	 "Rafael J. Wysocki" <rafael@kernel.org>
Cc: Nicolin Chen <nicolinc@nvidia.com>,
	Mostafa Saleh <smostafa@google.com>,
	 Daniel Mentz <danielmentz@google.com>,
	iommu@lists.linux.dev,  Pranjal Shrivastava <praan@google.com>
Subject: [RFC PATCH v3 5/8] pm: runtime: Introduce pm_runtime_get_if_not_suspended()
Date: Mon, 16 Jun 2025 20:31:46 +0000	[thread overview]
Message-ID: <20250616203149.2649118-6-praan@google.com> (raw)
In-Reply-To: <20250616203149.2649118-1-praan@google.com>

The existing opportunistic helpers like pm_runtime_get_if_active() and
pm_runtime_get_if_in_use(), are too strict for certain use cases. They
fail if the device is in a transient state like RPM_SUSPENDING, which
can lead to drivers making incorrect assumptions about the dev's state.

These helpers don't suffice for cases where one wishes to elide HW clean
up like queue flushes or TLB invalidations if the device is powered off.
It is wasteful to wake up the device in cases where the resume callback
resets the device well OR if the HW resets in a clean state. Thus, if a
device is powered off, it is preferred to elide any clean-up HW ops like
queue flushes / TLB invalidations when the device will resume afresh.

Consider the following sequence of operations:

1. The device is in `RPM_SUSPENDING` state
2. The driver calls pm_runtime_get_if_active/in_use
3. Depending on these API, the driver elides a HW clean-up op like:

if (pm_runtime_get_if_in_active(dev))
	invalidate_tlb(dev);
else
	// Skip flush, assuming device will fully suspend

4. Now, another rpm dev-linked device wakes up, causing the device's
   state to bounce from RPM_SUSPENDING to RPM_ACTIVE without invoking
   any rpm callbacks, preventing them from resetting the dev correctly.

5. The device continues to be active with an invalid HW state (e.g.
   stale TLB entries, unflushed packets/commands etc.)

Introduce a new helper function, pm_runtime_get_if_not_suspended(),
to address the problem. The pm_runtime_get_if_not_suspended() increments
the device's runtime PM reference only if it's rpm state is NOT
RPM_SUSPENDED and it cancels any pending autosuspend timers.

Signed-off-by: Pranjal Shrivastava <praan@google.com>
---
 drivers/base/power/runtime.c | 41 ++++++++++++++++++++++++++++++++++++
 include/linux/pm_runtime.h   |  5 +++++
 2 files changed, 46 insertions(+)

diff --git a/drivers/base/power/runtime.c b/drivers/base/power/runtime.c
index 0e127b0329c0..f1c81b6723cc 100644
--- a/drivers/base/power/runtime.c
+++ b/drivers/base/power/runtime.c
@@ -1260,6 +1260,47 @@ int pm_runtime_get_if_in_use(struct device *dev)
 }
 EXPORT_SYMBOL_GPL(pm_runtime_get_if_in_use);
 
+/**
+ * pm_runtime_get_if_not_suspended - Conditionally bump up runtime PM usage count.
+ * @dev: Target device.
+ *
+ * Increment the runtime PM usage counter of @dev if its runtime PM status is NOT
+ * %RPM_SUSPENDED, in which case it returns 1. If the device state is %RPM_SUSPENDED
+ * 0 is returned. -EINVAL is returned if runtime PM is disabled for the device, in
+ * which case also the usage_count will remain unmodified.
+ *
+ * NOTE: This also cancels any pending autosuspend request.
+ */
+int pm_runtime_get_if_not_suspended(struct device *dev)
+{
+	unsigned long flags;
+	int retval;
+
+	spin_lock_irqsave(&dev->power.lock, flags);
+	if (dev->power.disable_depth > 0) {
+		retval = -EINVAL;
+		goto out;
+	}
+
+	if (dev->power.runtime_status == RPM_SUSPENDED) {
+		retval = 0;
+		goto out;
+	}
+
+	/* Cancel the auto-suspend timer */
+	pm_runtime_cancel_pending(dev);
+	atomic_inc(&dev->power.usage_count);
+	__update_runtime_status(dev, RPM_ACTIVE);
+	retval = 1;
+	spin_unlock_irqrestore(&dev->power.lock, flags);
+
+	return retval;
+out:
+	spin_unlock_irqrestore(&dev->power.lock, flags);
+	return retval;
+}
+EXPORT_SYMBOL_GPL(pm_runtime_get_if_not_suspended);
+
 /**
  * __pm_runtime_set_status - Set runtime PM status of a device.
  * @dev: Device to handle.
diff --git a/include/linux/pm_runtime.h b/include/linux/pm_runtime.h
index 7fb5a459847e..d07bca2b6a83 100644
--- a/include/linux/pm_runtime.h
+++ b/include/linux/pm_runtime.h
@@ -75,6 +75,7 @@ extern int __pm_runtime_suspend(struct device *dev, int rpmflags);
 extern int __pm_runtime_resume(struct device *dev, int rpmflags);
 extern int pm_runtime_get_if_active(struct device *dev);
 extern int pm_runtime_get_if_in_use(struct device *dev);
+extern int pm_runtime_get_if_not_suspended(struct device *dev);
 extern int pm_schedule_suspend(struct device *dev, unsigned int delay);
 extern int __pm_runtime_set_status(struct device *dev, unsigned int status);
 extern int pm_runtime_barrier(struct device *dev);
@@ -283,6 +284,10 @@ static inline int pm_runtime_get_if_active(struct device *dev)
 {
 	return -EINVAL;
 }
+static int pm_runtime_get_if_not_suspended(struct device *dev)
+{
+	return -EINVAL;
+}
 static inline int __pm_runtime_set_status(struct device *dev,
 					    unsigned int status) { return 0; }
 static inline int pm_runtime_barrier(struct device *dev) { return 0; }
-- 
2.50.0.rc2.692.g299adb8693-goog


  parent reply	other threads:[~2025-06-16 20:32 UTC|newest]

Thread overview: 27+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2025-06-16 20:31 [RFC PATCH v3 0/8] iommu/arm-smmu-v3: Implement Runtime/System Sleep ops Pranjal Shrivastava
2025-06-16 20:31 ` [RFC PATCH v3 1/8] iommu/arm-smmu-v3: Refactor arm_smmu_setup_irqs Pranjal Shrivastava
2025-07-08 15:15   ` Mostafa Saleh
2025-06-16 20:31 ` [RFC PATCH v3 2/8] iommu/arm-smmu-v3: Add a helper to drain cmd queues Pranjal Shrivastava
2025-07-08 15:32   ` Mostafa Saleh
2025-07-14  9:24     ` Pranjal Shrivastava
2025-06-16 20:31 ` [RFC PATCH v3 3/8] iommu/tegra241-cmdqv: Add a helper to drain VCMDQs Pranjal Shrivastava
2025-06-16 20:31 ` [RFC PATCH v3 4/8] iommu/arm-smmu-v3: Cache and restore MSI config Pranjal Shrivastava
2025-07-08 15:34   ` Mostafa Saleh
2025-07-14  9:01     ` Pranjal Shrivastava
2025-06-16 20:31 ` Pranjal Shrivastava [this message]
2025-07-08 22:00   ` [RFC PATCH v3 5/8] pm: runtime: Introduce pm_runtime_get_if_not_suspended() Nicolin Chen
2025-07-09 15:51     ` Pranjal Shrivastava
2025-07-09  6:44   ` Rafael J. Wysocki
2025-07-09 15:51     ` Pranjal Shrivastava
2025-07-09 16:35       ` Rafael J. Wysocki
2025-07-09 17:06         ` Pranjal Shrivastava
2025-07-09 19:37           ` Rafael J. Wysocki
2025-07-10  8:59             ` Pranjal Shrivastava
2025-07-10 10:29               ` Rafael J. Wysocki
2025-07-11 10:20                 ` Pranjal Shrivastava
2025-07-15 23:52                   ` Daniel Mentz
2025-07-16 12:53                     ` Rafael J. Wysocki
2025-07-21 12:44                       ` Will Deacon
2025-06-16 20:31 ` [RFC PATCH v3 6/8] iommu/arm-smmu-v3: Implement pm_runtime & system sleep ops Pranjal Shrivastava
2025-06-16 20:31 ` [RFC PATCH v3 7/8] iommu/arm-smmu-v3: Enable pm_runtime and setup devlinks Pranjal Shrivastava
2025-06-16 20:31 ` [RFC PATCH v3 8/8] iommu/arm-smmu-v3: Invoke pm_runtime before hw access Pranjal Shrivastava

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=20250616203149.2649118-6-praan@google.com \
    --to=praan@google.com \
    --cc=danielmentz@google.com \
    --cc=iommu@lists.linux.dev \
    --cc=jgg@ziepe.ca \
    --cc=joro@8bytes.org \
    --cc=nicolinc@nvidia.com \
    --cc=rafael@kernel.org \
    --cc=robin.murphy@arm.com \
    --cc=smostafa@google.com \
    --cc=will@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 a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox