Skip to content

Commit c9dc281

Browse files
committed
Merge tag 'driver-core-4.13-rc5' of git://git.kernel.org/pub/scm/linux/kernel/git/gregkh/driver-core
Pull driver core fixes from Greg KH: "Here are three firmware core fixes for 4.13-rc5. All three of these fix reported issues and have been floating around for a few weeks. They have been in linux-next with no reported problems" * tag 'driver-core-4.13-rc5' of git://git.kernel.org/pub/scm/linux/kernel/git/gregkh/driver-core: firmware: avoid invalid fallback aborts by using killable wait firmware: fix batched requests - send wake up on failure on direct lookups firmware: fix batched requests - wake all waiters
2 parents ce7ba95 + 260d9f2 commit c9dc281

File tree

1 file changed

+34
-15
lines changed

1 file changed

+34
-15
lines changed

drivers/base/firmware_class.c

Lines changed: 34 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -30,7 +30,6 @@
3030
#include <linux/syscore_ops.h>
3131
#include <linux/reboot.h>
3232
#include <linux/security.h>
33-
#include <linux/swait.h>
3433

3534
#include <generated/utsrelease.h>
3635

@@ -112,13 +111,13 @@ static inline long firmware_loading_timeout(void)
112111
* state of the firmware loading.
113112
*/
114113
struct fw_state {
115-
struct swait_queue_head wq;
114+
struct completion completion;
116115
enum fw_status status;
117116
};
118117

119118
static void fw_state_init(struct fw_state *fw_st)
120119
{
121-
init_swait_queue_head(&fw_st->wq);
120+
init_completion(&fw_st->completion);
122121
fw_st->status = FW_STATUS_UNKNOWN;
123122
}
124123

@@ -131,9 +130,7 @@ static int __fw_state_wait_common(struct fw_state *fw_st, long timeout)
131130
{
132131
long ret;
133132

134-
ret = swait_event_interruptible_timeout(fw_st->wq,
135-
__fw_state_is_done(READ_ONCE(fw_st->status)),
136-
timeout);
133+
ret = wait_for_completion_killable_timeout(&fw_st->completion, timeout);
137134
if (ret != 0 && fw_st->status == FW_STATUS_ABORTED)
138135
return -ENOENT;
139136
if (!ret)
@@ -148,35 +145,34 @@ static void __fw_state_set(struct fw_state *fw_st,
148145
WRITE_ONCE(fw_st->status, status);
149146

150147
if (status == FW_STATUS_DONE || status == FW_STATUS_ABORTED)
151-
swake_up(&fw_st->wq);
148+
complete_all(&fw_st->completion);
152149
}
153150

154151
#define fw_state_start(fw_st) \
155152
__fw_state_set(fw_st, FW_STATUS_LOADING)
156153
#define fw_state_done(fw_st) \
157154
__fw_state_set(fw_st, FW_STATUS_DONE)
155+
#define fw_state_aborted(fw_st) \
156+
__fw_state_set(fw_st, FW_STATUS_ABORTED)
158157
#define fw_state_wait(fw_st) \
159158
__fw_state_wait_common(fw_st, MAX_SCHEDULE_TIMEOUT)
160159

161-
#ifndef CONFIG_FW_LOADER_USER_HELPER
162-
163-
#define fw_state_is_aborted(fw_st) false
164-
165-
#else /* CONFIG_FW_LOADER_USER_HELPER */
166-
167160
static int __fw_state_check(struct fw_state *fw_st, enum fw_status status)
168161
{
169162
return fw_st->status == status;
170163
}
171164

165+
#define fw_state_is_aborted(fw_st) \
166+
__fw_state_check(fw_st, FW_STATUS_ABORTED)
167+
168+
#ifdef CONFIG_FW_LOADER_USER_HELPER
169+
172170
#define fw_state_aborted(fw_st) \
173171
__fw_state_set(fw_st, FW_STATUS_ABORTED)
174172
#define fw_state_is_done(fw_st) \
175173
__fw_state_check(fw_st, FW_STATUS_DONE)
176174
#define fw_state_is_loading(fw_st) \
177175
__fw_state_check(fw_st, FW_STATUS_LOADING)
178-
#define fw_state_is_aborted(fw_st) \
179-
__fw_state_check(fw_st, FW_STATUS_ABORTED)
180176
#define fw_state_wait_timeout(fw_st, timeout) \
181177
__fw_state_wait_common(fw_st, timeout)
182178

@@ -1200,6 +1196,28 @@ _request_firmware_prepare(struct firmware **firmware_p, const char *name,
12001196
return 1; /* need to load */
12011197
}
12021198

1199+
/*
1200+
* Batched requests need only one wake, we need to do this step last due to the
1201+
* fallback mechanism. The buf is protected with kref_get(), and it won't be
1202+
* released until the last user calls release_firmware().
1203+
*
1204+
* Failed batched requests are possible as well, in such cases we just share
1205+
* the struct firmware_buf and won't release it until all requests are woken
1206+
* and have gone through this same path.
1207+
*/
1208+
static void fw_abort_batch_reqs(struct firmware *fw)
1209+
{
1210+
struct firmware_buf *buf;
1211+
1212+
/* Loaded directly? */
1213+
if (!fw || !fw->priv)
1214+
return;
1215+
1216+
buf = fw->priv;
1217+
if (!fw_state_is_aborted(&buf->fw_st))
1218+
fw_state_aborted(&buf->fw_st);
1219+
}
1220+
12031221
/* called from request_firmware() and request_firmware_work_func() */
12041222
static int
12051223
_request_firmware(const struct firmware **firmware_p, const char *name,
@@ -1243,6 +1261,7 @@ _request_firmware(const struct firmware **firmware_p, const char *name,
12431261

12441262
out:
12451263
if (ret < 0) {
1264+
fw_abort_batch_reqs(fw);
12461265
release_firmware(fw);
12471266
fw = NULL;
12481267
}

0 commit comments

Comments
 (0)