Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
torvalds
GitHub Repository: torvalds/linux
Path: blob/master/block/blk-pm.c
26242 views
1
// SPDX-License-Identifier: GPL-2.0
2
3
#include <linux/blk-pm.h>
4
#include <linux/blkdev.h>
5
#include <linux/pm_runtime.h>
6
#include "blk-mq.h"
7
8
/**
9
* blk_pm_runtime_init - Block layer runtime PM initialization routine
10
* @q: the queue of the device
11
* @dev: the device the queue belongs to
12
*
13
* Description:
14
* Initialize runtime-PM-related fields for @q and start auto suspend for
15
* @dev. Drivers that want to take advantage of request-based runtime PM
16
* should call this function after @dev has been initialized, and its
17
* request queue @q has been allocated, and runtime PM for it can not happen
18
* yet(either due to disabled/forbidden or its usage_count > 0). In most
19
* cases, driver should call this function before any I/O has taken place.
20
*
21
* This function takes care of setting up using auto suspend for the device,
22
* the autosuspend delay is set to -1 to make runtime suspend impossible
23
* until an updated value is either set by user or by driver. Drivers do
24
* not need to touch other autosuspend settings.
25
*
26
* The block layer runtime PM is request based, so only works for drivers
27
* that use request as their IO unit instead of those directly use bio's.
28
*/
29
void blk_pm_runtime_init(struct request_queue *q, struct device *dev)
30
{
31
q->dev = dev;
32
q->rpm_status = RPM_ACTIVE;
33
pm_runtime_set_autosuspend_delay(q->dev, -1);
34
pm_runtime_use_autosuspend(q->dev);
35
}
36
EXPORT_SYMBOL(blk_pm_runtime_init);
37
38
/**
39
* blk_pre_runtime_suspend - Pre runtime suspend check
40
* @q: the queue of the device
41
*
42
* Description:
43
* This function will check if runtime suspend is allowed for the device
44
* by examining if there are any requests pending in the queue. If there
45
* are requests pending, the device can not be runtime suspended; otherwise,
46
* the queue's status will be updated to SUSPENDING and the driver can
47
* proceed to suspend the device.
48
*
49
* For the not allowed case, we mark last busy for the device so that
50
* runtime PM core will try to autosuspend it some time later.
51
*
52
* This function should be called near the start of the device's
53
* runtime_suspend callback.
54
*
55
* Return:
56
* 0 - OK to runtime suspend the device
57
* -EBUSY - Device should not be runtime suspended
58
*/
59
int blk_pre_runtime_suspend(struct request_queue *q)
60
{
61
int ret = 0;
62
63
if (!q->dev)
64
return ret;
65
66
WARN_ON_ONCE(q->rpm_status != RPM_ACTIVE);
67
68
spin_lock_irq(&q->queue_lock);
69
q->rpm_status = RPM_SUSPENDING;
70
spin_unlock_irq(&q->queue_lock);
71
72
/*
73
* Increase the pm_only counter before checking whether any
74
* non-PM blk_queue_enter() calls are in progress to avoid that any
75
* new non-PM blk_queue_enter() calls succeed before the pm_only
76
* counter is decreased again.
77
*/
78
blk_set_pm_only(q);
79
ret = -EBUSY;
80
/* Switch q_usage_counter from per-cpu to atomic mode. */
81
blk_freeze_queue_start(q);
82
/*
83
* Wait until atomic mode has been reached. Since that
84
* involves calling call_rcu(), it is guaranteed that later
85
* blk_queue_enter() calls see the pm-only state. See also
86
* http://lwn.net/Articles/573497/.
87
*/
88
percpu_ref_switch_to_atomic_sync(&q->q_usage_counter);
89
if (percpu_ref_is_zero(&q->q_usage_counter))
90
ret = 0;
91
/* Switch q_usage_counter back to per-cpu mode. */
92
blk_mq_unfreeze_queue_nomemrestore(q);
93
94
if (ret < 0) {
95
spin_lock_irq(&q->queue_lock);
96
q->rpm_status = RPM_ACTIVE;
97
pm_runtime_mark_last_busy(q->dev);
98
spin_unlock_irq(&q->queue_lock);
99
100
blk_clear_pm_only(q);
101
}
102
103
return ret;
104
}
105
EXPORT_SYMBOL(blk_pre_runtime_suspend);
106
107
/**
108
* blk_post_runtime_suspend - Post runtime suspend processing
109
* @q: the queue of the device
110
* @err: return value of the device's runtime_suspend function
111
*
112
* Description:
113
* Update the queue's runtime status according to the return value of the
114
* device's runtime suspend function and mark last busy for the device so
115
* that PM core will try to auto suspend the device at a later time.
116
*
117
* This function should be called near the end of the device's
118
* runtime_suspend callback.
119
*/
120
void blk_post_runtime_suspend(struct request_queue *q, int err)
121
{
122
if (!q->dev)
123
return;
124
125
spin_lock_irq(&q->queue_lock);
126
if (!err) {
127
q->rpm_status = RPM_SUSPENDED;
128
} else {
129
q->rpm_status = RPM_ACTIVE;
130
pm_runtime_mark_last_busy(q->dev);
131
}
132
spin_unlock_irq(&q->queue_lock);
133
134
if (err)
135
blk_clear_pm_only(q);
136
}
137
EXPORT_SYMBOL(blk_post_runtime_suspend);
138
139
/**
140
* blk_pre_runtime_resume - Pre runtime resume processing
141
* @q: the queue of the device
142
*
143
* Description:
144
* Update the queue's runtime status to RESUMING in preparation for the
145
* runtime resume of the device.
146
*
147
* This function should be called near the start of the device's
148
* runtime_resume callback.
149
*/
150
void blk_pre_runtime_resume(struct request_queue *q)
151
{
152
if (!q->dev)
153
return;
154
155
spin_lock_irq(&q->queue_lock);
156
q->rpm_status = RPM_RESUMING;
157
spin_unlock_irq(&q->queue_lock);
158
}
159
EXPORT_SYMBOL(blk_pre_runtime_resume);
160
161
/**
162
* blk_post_runtime_resume - Post runtime resume processing
163
* @q: the queue of the device
164
*
165
* Description:
166
* Restart the queue of a runtime suspended device. It does this regardless
167
* of whether the device's runtime-resume succeeded; even if it failed the
168
* driver or error handler will need to communicate with the device.
169
*
170
* This function should be called near the end of the device's
171
* runtime_resume callback to correct queue runtime PM status and re-enable
172
* peeking requests from the queue.
173
*/
174
void blk_post_runtime_resume(struct request_queue *q)
175
{
176
int old_status;
177
178
if (!q->dev)
179
return;
180
181
spin_lock_irq(&q->queue_lock);
182
old_status = q->rpm_status;
183
q->rpm_status = RPM_ACTIVE;
184
pm_runtime_mark_last_busy(q->dev);
185
pm_request_autosuspend(q->dev);
186
spin_unlock_irq(&q->queue_lock);
187
188
if (old_status != RPM_ACTIVE)
189
blk_clear_pm_only(q);
190
}
191
EXPORT_SYMBOL(blk_post_runtime_resume);
192
193