From: Lin Ming ming.m@intel.com
Add runtime pm helper functions:
void blk_pm_runtime_init(struct request_queue *q, struct device *dev)
- Initialization function for drivers to call.
int blk_pre_runtime_suspend(struct request_queue *q)
- If any requests are in the queue, mark last busy and return -EBUSY.
Otherwise set q-rpm_status to RPM_SUSPENDING and return 0.
void blk_post_runtime_suspend(struct request_queue *q, int err)
- If the suspend succeeded then set q-rpm_status to RPM_SUSPENDED.
Otherwise set it to RPM_ACTIVE.
void blk_pre_runtime_resume(struct request_queue *q)
- Set q-rpm_status to RPM_RESUMING.
void blk_post_runtime_resume(struct request_queue *q, int err)
- If the resume succeeded then set q-rpm_status to RPM_ACTIVE
and call __blk_run_queue, then mark last busy and autosuspend.
Otherwise set q-rpm_status to RPM_SUSPENDED.
Signed-off-by: Lin Ming ming.m@intel.com
Signed-off-by: Aaron Lu aaron...@intel.com
---
block/blk-core.c | 143 +
include/linux/blkdev.h | 27 ++
2 files changed, 170 insertions(+)
diff --git a/block/blk-core.c b/block/blk-core.c
index 66d3168..1ec09f6 100644
--- a/block/blk-core.c
+++ b/block/blk-core.c
@@ -30,6 +30,7 @@
#include linux/list_sort.h
#include linux/delay.h
#include linux/ratelimit.h
+#include linux/pm_runtime.h
#define CREATE_TRACE_POINTS
#include trace/events/block.h
@@ -3043,6 +3044,148 @@ void blk_finish_plug(struct blk_plug *plug)
}
EXPORT_SYMBOL(blk_finish_plug);
+#ifdef CONFIG_PM_RUNTIME
+/**
+ * blk_pm_runtime_init - Block layer runtime PM initialization routine
+ * @q: the queue of the device
+ * @dev: the device the queue belongs to
+ *
+ * Description:
+ *Initialize runtime-PM-related fields for @q and start auto suspend for
+ *@dev. Drivers that want to take advantage of request-based runtime PM
+ *should call this function after @dev has been initialized, and its
+ *request queue @q has been allocated, and runtime PM for it can not happen
+ *yet(either due to disabled/forbidden or its usage_count 0). In most
+ *cases, driver should call this function before any I/O has taken place.
+ *
+ *This function takes care of setting up using auto suspend for the device,
+ *the autosuspend delay is set to -1 to make runtime suspend impossible
+ *until an updated value is either set by user or by driver. Drivers do
+ *not need to touch other autosuspend settings.
+ *
+ *The block layer runtime PM is request based, so only works for drivers
+ *that use request as their IO unit instead of those directly use bio's.
+ */
+void blk_pm_runtime_init(struct request_queue *q, struct device *dev)
+{
+ q-dev = dev;
+ q-rpm_status = RPM_ACTIVE;
+ pm_runtime_set_autosuspend_delay(q-dev, -1);
+ pm_runtime_use_autosuspend(q-dev);
+ pm_runtime_mark_last_busy(q-dev);
+ pm_runtime_autosuspend(q-dev);
+}
+EXPORT_SYMBOL(blk_pm_runtime_init);
+
+/**
+ * blk_pre_runtime_suspend - Pre runtime suspend check
+ * @q: the queue of the device
+ *
+ * Description:
+ *This function will check if runtime suspend is allowed for the device
+ *by examining if there are any requests pending in the queue. If there
+ *are requests pending, the device can not be runtime suspended; otherwise,
+ *the queue's status will be updated to SUSPENDING and the driver can
+ *proceed to suspend the device.
+ *
+ *For the not allowed case, we mark last busy for the device so that
+ *runtime PM core will try to autosuspend it some time later.
+ *
+ *This function should be called near the start of the device's
+ *runtime_suspend callback.
+ *
+ * Return:
+ *0- OK to runtime suspend the device
+ *-EBUSY - Device should not be runtime suspended
+ */
+int blk_pre_runtime_suspend(struct request_queue *q)
+{
+ int ret = 0;
+
+ spin_lock_irq(q-queue_lock);
+ if (q-nr_pending) {
+ ret = -EBUSY;
+ pm_runtime_mark_last_busy(q-dev);
+ } else {
+ q-rpm_status = RPM_SUSPENDING;
+ }
+ spin_unlock_irq(q-queue_lock);
+ return ret;
+}
+EXPORT_SYMBOL(blk_pre_runtime_suspend);
+
+/**
+ * blk_post_runtime_suspend - Post runtime suspend processing
+ * @q: the queue of the device
+ * @err: return value of the device's runtime_suspend function
+ *
+ * Description:
+ *Update the queue's runtime status according to the return value of the
+ *device's runtime suspend function.
+ *
+ *This function should be called near the end of the device's
+ *runtime_suspend callback.
+ */
+void blk_post_runtime_suspend(struct request_queue *q, int err)
+{
+ spin_lock_irq(q-queue_lock);
+ if (!err)
+ q-rpm_status = RPM_SUSPENDED;
+ else
+ q-rpm_status = RPM_ACTIVE;
+ spin_unlock_irq(q-queue_lock);
+}