1bca6b067SBart Van Assche // SPDX-License-Identifier: GPL-2.0
2bca6b067SBart Van Assche
3bca6b067SBart Van Assche #include <linux/blk-pm.h>
4bca6b067SBart Van Assche #include <linux/blkdev.h>
5bca6b067SBart Van Assche #include <linux/pm_runtime.h>
67cedffecSBart Van Assche #include "blk-mq.h"
7bca6b067SBart Van Assche
8bca6b067SBart Van Assche /**
9bca6b067SBart Van Assche * blk_pm_runtime_init - Block layer runtime PM initialization routine
10bca6b067SBart Van Assche * @q: the queue of the device
11bca6b067SBart Van Assche * @dev: the device the queue belongs to
12bca6b067SBart Van Assche *
13bca6b067SBart Van Assche * Description:
14bca6b067SBart Van Assche * Initialize runtime-PM-related fields for @q and start auto suspend for
15bca6b067SBart Van Assche * @dev. Drivers that want to take advantage of request-based runtime PM
16bca6b067SBart Van Assche * should call this function after @dev has been initialized, and its
17bca6b067SBart Van Assche * request queue @q has been allocated, and runtime PM for it can not happen
18bca6b067SBart Van Assche * yet(either due to disabled/forbidden or its usage_count > 0). In most
19bca6b067SBart Van Assche * cases, driver should call this function before any I/O has taken place.
20bca6b067SBart Van Assche *
21bca6b067SBart Van Assche * This function takes care of setting up using auto suspend for the device,
22bca6b067SBart Van Assche * the autosuspend delay is set to -1 to make runtime suspend impossible
23bca6b067SBart Van Assche * until an updated value is either set by user or by driver. Drivers do
24bca6b067SBart Van Assche * not need to touch other autosuspend settings.
25bca6b067SBart Van Assche *
26bca6b067SBart Van Assche * The block layer runtime PM is request based, so only works for drivers
27bca6b067SBart Van Assche * that use request as their IO unit instead of those directly use bio's.
28bca6b067SBart Van Assche */
blk_pm_runtime_init(struct request_queue * q,struct device * dev)29bca6b067SBart Van Assche void blk_pm_runtime_init(struct request_queue *q, struct device *dev)
30bca6b067SBart Van Assche {
31bca6b067SBart Van Assche q->dev = dev;
32bca6b067SBart Van Assche q->rpm_status = RPM_ACTIVE;
33bca6b067SBart Van Assche pm_runtime_set_autosuspend_delay(q->dev, -1);
34bca6b067SBart Van Assche pm_runtime_use_autosuspend(q->dev);
35bca6b067SBart Van Assche }
36bca6b067SBart Van Assche EXPORT_SYMBOL(blk_pm_runtime_init);
37bca6b067SBart Van Assche
38bca6b067SBart Van Assche /**
39bca6b067SBart Van Assche * blk_pre_runtime_suspend - Pre runtime suspend check
40bca6b067SBart Van Assche * @q: the queue of the device
41bca6b067SBart Van Assche *
42bca6b067SBart Van Assche * Description:
43bca6b067SBart Van Assche * This function will check if runtime suspend is allowed for the device
44bca6b067SBart Van Assche * by examining if there are any requests pending in the queue. If there
45bca6b067SBart Van Assche * are requests pending, the device can not be runtime suspended; otherwise,
46bca6b067SBart Van Assche * the queue's status will be updated to SUSPENDING and the driver can
47bca6b067SBart Van Assche * proceed to suspend the device.
48bca6b067SBart Van Assche *
49bca6b067SBart Van Assche * For the not allowed case, we mark last busy for the device so that
50bca6b067SBart Van Assche * runtime PM core will try to autosuspend it some time later.
51bca6b067SBart Van Assche *
52bca6b067SBart Van Assche * This function should be called near the start of the device's
53bca6b067SBart Van Assche * runtime_suspend callback.
54bca6b067SBart Van Assche *
55bca6b067SBart Van Assche * Return:
56bca6b067SBart Van Assche * 0 - OK to runtime suspend the device
57bca6b067SBart Van Assche * -EBUSY - Device should not be runtime suspended
58bca6b067SBart Van Assche */
blk_pre_runtime_suspend(struct request_queue * q)59bca6b067SBart Van Assche int blk_pre_runtime_suspend(struct request_queue *q)
60bca6b067SBart Van Assche {
61bca6b067SBart Van Assche int ret = 0;
62bca6b067SBart Van Assche
63bca6b067SBart Van Assche if (!q->dev)
64bca6b067SBart Van Assche return ret;
65bca6b067SBart Van Assche
667cedffecSBart Van Assche WARN_ON_ONCE(q->rpm_status != RPM_ACTIVE);
677cedffecSBart Van Assche
68fa4d0f19SBart Van Assche spin_lock_irq(&q->queue_lock);
69fa4d0f19SBart Van Assche q->rpm_status = RPM_SUSPENDING;
70fa4d0f19SBart Van Assche spin_unlock_irq(&q->queue_lock);
71fa4d0f19SBart Van Assche
727cedffecSBart Van Assche /*
737cedffecSBart Van Assche * Increase the pm_only counter before checking whether any
747cedffecSBart Van Assche * non-PM blk_queue_enter() calls are in progress to avoid that any
757cedffecSBart Van Assche * new non-PM blk_queue_enter() calls succeed before the pm_only
767cedffecSBart Van Assche * counter is decreased again.
777cedffecSBart Van Assche */
787cedffecSBart Van Assche blk_set_pm_only(q);
79bca6b067SBart Van Assche ret = -EBUSY;
807cedffecSBart Van Assche /* Switch q_usage_counter from per-cpu to atomic mode. */
817cedffecSBart Van Assche blk_freeze_queue_start(q);
827cedffecSBart Van Assche /*
837cedffecSBart Van Assche * Wait until atomic mode has been reached. Since that
847cedffecSBart Van Assche * involves calling call_rcu(), it is guaranteed that later
857cedffecSBart Van Assche * blk_queue_enter() calls see the pm-only state. See also
867cedffecSBart Van Assche * http://lwn.net/Articles/573497/.
877cedffecSBart Van Assche */
887cedffecSBart Van Assche percpu_ref_switch_to_atomic_sync(&q->q_usage_counter);
897cedffecSBart Van Assche if (percpu_ref_is_zero(&q->q_usage_counter))
907cedffecSBart Van Assche ret = 0;
917cedffecSBart Van Assche /* Switch q_usage_counter back to per-cpu mode. */
927cedffecSBart Van Assche blk_mq_unfreeze_queue(q);
937cedffecSBart Van Assche
94fa4d0f19SBart Van Assche if (ret < 0) {
950d945c1fSChristoph Hellwig spin_lock_irq(&q->queue_lock);
96fa4d0f19SBart Van Assche q->rpm_status = RPM_ACTIVE;
97bca6b067SBart Van Assche pm_runtime_mark_last_busy(q->dev);
980d945c1fSChristoph Hellwig spin_unlock_irq(&q->queue_lock);
997cedffecSBart Van Assche
1007cedffecSBart Van Assche blk_clear_pm_only(q);
101fa4d0f19SBart Van Assche }
1027cedffecSBart Van Assche
103bca6b067SBart Van Assche return ret;
104bca6b067SBart Van Assche }
105bca6b067SBart Van Assche EXPORT_SYMBOL(blk_pre_runtime_suspend);
106bca6b067SBart Van Assche
107bca6b067SBart Van Assche /**
108bca6b067SBart Van Assche * blk_post_runtime_suspend - Post runtime suspend processing
109bca6b067SBart Van Assche * @q: the queue of the device
110bca6b067SBart Van Assche * @err: return value of the device's runtime_suspend function
111bca6b067SBart Van Assche *
112bca6b067SBart Van Assche * Description:
113bca6b067SBart Van Assche * Update the queue's runtime status according to the return value of the
114bca6b067SBart Van Assche * device's runtime suspend function and mark last busy for the device so
115bca6b067SBart Van Assche * that PM core will try to auto suspend the device at a later time.
116bca6b067SBart Van Assche *
117bca6b067SBart Van Assche * This function should be called near the end of the device's
118bca6b067SBart Van Assche * runtime_suspend callback.
119bca6b067SBart Van Assche */
blk_post_runtime_suspend(struct request_queue * q,int err)120bca6b067SBart Van Assche void blk_post_runtime_suspend(struct request_queue *q, int err)
121bca6b067SBart Van Assche {
122bca6b067SBart Van Assche if (!q->dev)
123bca6b067SBart Van Assche return;
124bca6b067SBart Van Assche
1250d945c1fSChristoph Hellwig spin_lock_irq(&q->queue_lock);
126bca6b067SBart Van Assche if (!err) {
127bca6b067SBart Van Assche q->rpm_status = RPM_SUSPENDED;
128bca6b067SBart Van Assche } else {
129bca6b067SBart Van Assche q->rpm_status = RPM_ACTIVE;
130bca6b067SBart Van Assche pm_runtime_mark_last_busy(q->dev);
131bca6b067SBart Van Assche }
1320d945c1fSChristoph Hellwig spin_unlock_irq(&q->queue_lock);
1337cedffecSBart Van Assche
1347cedffecSBart Van Assche if (err)
1357cedffecSBart Van Assche blk_clear_pm_only(q);
136bca6b067SBart Van Assche }
137bca6b067SBart Van Assche EXPORT_SYMBOL(blk_post_runtime_suspend);
138bca6b067SBart Van Assche
139bca6b067SBart Van Assche /**
140bca6b067SBart Van Assche * blk_pre_runtime_resume - Pre runtime resume processing
141bca6b067SBart Van Assche * @q: the queue of the device
142bca6b067SBart Van Assche *
143bca6b067SBart Van Assche * Description:
144bca6b067SBart Van Assche * Update the queue's runtime status to RESUMING in preparation for the
145bca6b067SBart Van Assche * runtime resume of the device.
146bca6b067SBart Van Assche *
147bca6b067SBart Van Assche * This function should be called near the start of the device's
148bca6b067SBart Van Assche * runtime_resume callback.
149bca6b067SBart Van Assche */
blk_pre_runtime_resume(struct request_queue * q)150bca6b067SBart Van Assche void blk_pre_runtime_resume(struct request_queue *q)
151bca6b067SBart Van Assche {
152bca6b067SBart Van Assche if (!q->dev)
153bca6b067SBart Van Assche return;
154bca6b067SBart Van Assche
1550d945c1fSChristoph Hellwig spin_lock_irq(&q->queue_lock);
156bca6b067SBart Van Assche q->rpm_status = RPM_RESUMING;
1570d945c1fSChristoph Hellwig spin_unlock_irq(&q->queue_lock);
158bca6b067SBart Van Assche }
159bca6b067SBart Van Assche EXPORT_SYMBOL(blk_pre_runtime_resume);
160bca6b067SBart Van Assche
161bca6b067SBart Van Assche /**
162bca6b067SBart Van Assche * blk_post_runtime_resume - Post runtime resume processing
163bca6b067SBart Van Assche * @q: the queue of the device
164bca6b067SBart Van Assche *
165bca6b067SBart Van Assche * Description:
166*6e1fcab0SAlan Stern * For historical reasons, this routine merely calls blk_set_runtime_active()
167*6e1fcab0SAlan Stern * to do the real work of restarting the queue. It does this regardless of
168*6e1fcab0SAlan Stern * whether the device's runtime-resume succeeded; even if it failed the
169*6e1fcab0SAlan Stern * driver or error handler will need to communicate with the device.
170bca6b067SBart Van Assche *
171bca6b067SBart Van Assche * This function should be called near the end of the device's
172bca6b067SBart Van Assche * runtime_resume callback.
173bca6b067SBart Van Assche */
blk_post_runtime_resume(struct request_queue * q)174*6e1fcab0SAlan Stern void blk_post_runtime_resume(struct request_queue *q)
175bca6b067SBart Van Assche {
1768f38f8e0SAlan Stern blk_set_runtime_active(q);
177bca6b067SBart Van Assche }
178bca6b067SBart Van Assche EXPORT_SYMBOL(blk_post_runtime_resume);
179bca6b067SBart Van Assche
180bca6b067SBart Van Assche /**
181bca6b067SBart Van Assche * blk_set_runtime_active - Force runtime status of the queue to be active
182bca6b067SBart Van Assche * @q: the queue of the device
183bca6b067SBart Van Assche *
184bca6b067SBart Van Assche * If the device is left runtime suspended during system suspend the resume
185bca6b067SBart Van Assche * hook typically resumes the device and corrects runtime status
186bca6b067SBart Van Assche * accordingly. However, that does not affect the queue runtime PM status
187bca6b067SBart Van Assche * which is still "suspended". This prevents processing requests from the
188bca6b067SBart Van Assche * queue.
189bca6b067SBart Van Assche *
190bca6b067SBart Van Assche * This function can be used in driver's resume hook to correct queue
191bca6b067SBart Van Assche * runtime PM status and re-enable peeking requests from the queue. It
192bca6b067SBart Van Assche * should be called before first request is added to the queue.
1938f38f8e0SAlan Stern *
194*6e1fcab0SAlan Stern * This function is also called by blk_post_runtime_resume() for
1958f38f8e0SAlan Stern * runtime resumes. It does everything necessary to restart the queue.
196bca6b067SBart Van Assche */
blk_set_runtime_active(struct request_queue * q)197bca6b067SBart Van Assche void blk_set_runtime_active(struct request_queue *q)
198bca6b067SBart Van Assche {
1998f38f8e0SAlan Stern int old_status;
2008f38f8e0SAlan Stern
2018f38f8e0SAlan Stern if (!q->dev)
2028f38f8e0SAlan Stern return;
2038f38f8e0SAlan Stern
2040d945c1fSChristoph Hellwig spin_lock_irq(&q->queue_lock);
2058f38f8e0SAlan Stern old_status = q->rpm_status;
206bca6b067SBart Van Assche q->rpm_status = RPM_ACTIVE;
207bca6b067SBart Van Assche pm_runtime_mark_last_busy(q->dev);
208bca6b067SBart Van Assche pm_request_autosuspend(q->dev);
2090d945c1fSChristoph Hellwig spin_unlock_irq(&q->queue_lock);
2108f38f8e0SAlan Stern
2118f38f8e0SAlan Stern if (old_status != RPM_ACTIVE)
2128f38f8e0SAlan Stern blk_clear_pm_only(q);
2138a15b4d7SStanley Chu }
214bca6b067SBart Van Assche EXPORT_SYMBOL(blk_set_runtime_active);
215