aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorLinus Torvalds <torvalds@linux-foundation.org>2017-08-13 15:44:18 -0400
committerLinus Torvalds <torvalds@linux-foundation.org>2017-08-13 15:44:18 -0400
commitc9dc281d91aed57251e94c7cca81a5c8777e3e4a (patch)
tree4c154e7070cf59198635df19b989f74b391ce333
parentce7ba95cf078337c9921b301a7e4b9e82561db38 (diff)
parent260d9f2fc5655a2552701cdd0b909c4466732f19 (diff)
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
-rw-r--r--drivers/base/firmware_class.c49
1 files changed, 34 insertions, 15 deletions
diff --git a/drivers/base/firmware_class.c b/drivers/base/firmware_class.c
index b9f907eedbf7..bfbe1e154128 100644
--- a/drivers/base/firmware_class.c
+++ b/drivers/base/firmware_class.c
@@ -30,7 +30,6 @@
30#include <linux/syscore_ops.h> 30#include <linux/syscore_ops.h>
31#include <linux/reboot.h> 31#include <linux/reboot.h>
32#include <linux/security.h> 32#include <linux/security.h>
33#include <linux/swait.h>
34 33
35#include <generated/utsrelease.h> 34#include <generated/utsrelease.h>
36 35
@@ -112,13 +111,13 @@ static inline long firmware_loading_timeout(void)
112 * state of the firmware loading. 111 * state of the firmware loading.
113 */ 112 */
114struct fw_state { 113struct fw_state {
115 struct swait_queue_head wq; 114 struct completion completion;
116 enum fw_status status; 115 enum fw_status status;
117}; 116};
118 117
119static void fw_state_init(struct fw_state *fw_st) 118static void fw_state_init(struct fw_state *fw_st)
120{ 119{
121 init_swait_queue_head(&fw_st->wq); 120 init_completion(&fw_st->completion);
122 fw_st->status = FW_STATUS_UNKNOWN; 121 fw_st->status = FW_STATUS_UNKNOWN;
123} 122}
124 123
@@ -131,9 +130,7 @@ static int __fw_state_wait_common(struct fw_state *fw_st, long timeout)
131{ 130{
132 long ret; 131 long ret;
133 132
134 ret = swait_event_interruptible_timeout(fw_st->wq, 133 ret = wait_for_completion_killable_timeout(&fw_st->completion, timeout);
135 __fw_state_is_done(READ_ONCE(fw_st->status)),
136 timeout);
137 if (ret != 0 && fw_st->status == FW_STATUS_ABORTED) 134 if (ret != 0 && fw_st->status == FW_STATUS_ABORTED)
138 return -ENOENT; 135 return -ENOENT;
139 if (!ret) 136 if (!ret)
@@ -148,35 +145,34 @@ static void __fw_state_set(struct fw_state *fw_st,
148 WRITE_ONCE(fw_st->status, status); 145 WRITE_ONCE(fw_st->status, status);
149 146
150 if (status == FW_STATUS_DONE || status == FW_STATUS_ABORTED) 147 if (status == FW_STATUS_DONE || status == FW_STATUS_ABORTED)
151 swake_up(&fw_st->wq); 148 complete_all(&fw_st->completion);
152} 149}
153 150
154#define fw_state_start(fw_st) \ 151#define fw_state_start(fw_st) \
155 __fw_state_set(fw_st, FW_STATUS_LOADING) 152 __fw_state_set(fw_st, FW_STATUS_LOADING)
156#define fw_state_done(fw_st) \ 153#define fw_state_done(fw_st) \
157 __fw_state_set(fw_st, FW_STATUS_DONE) 154 __fw_state_set(fw_st, FW_STATUS_DONE)
155#define fw_state_aborted(fw_st) \
156 __fw_state_set(fw_st, FW_STATUS_ABORTED)
158#define fw_state_wait(fw_st) \ 157#define fw_state_wait(fw_st) \
159 __fw_state_wait_common(fw_st, MAX_SCHEDULE_TIMEOUT) 158 __fw_state_wait_common(fw_st, MAX_SCHEDULE_TIMEOUT)
160 159
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
167static int __fw_state_check(struct fw_state *fw_st, enum fw_status status) 160static int __fw_state_check(struct fw_state *fw_st, enum fw_status status)
168{ 161{
169 return fw_st->status == status; 162 return fw_st->status == status;
170} 163}
171 164
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
172#define fw_state_aborted(fw_st) \ 170#define fw_state_aborted(fw_st) \
173 __fw_state_set(fw_st, FW_STATUS_ABORTED) 171 __fw_state_set(fw_st, FW_STATUS_ABORTED)
174#define fw_state_is_done(fw_st) \ 172#define fw_state_is_done(fw_st) \
175 __fw_state_check(fw_st, FW_STATUS_DONE) 173 __fw_state_check(fw_st, FW_STATUS_DONE)
176#define fw_state_is_loading(fw_st) \ 174#define fw_state_is_loading(fw_st) \
177 __fw_state_check(fw_st, FW_STATUS_LOADING) 175 __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)
180#define fw_state_wait_timeout(fw_st, timeout) \ 176#define fw_state_wait_timeout(fw_st, timeout) \
181 __fw_state_wait_common(fw_st, timeout) 177 __fw_state_wait_common(fw_st, timeout)
182 178
@@ -1200,6 +1196,28 @@ _request_firmware_prepare(struct firmware **firmware_p, const char *name,
1200 return 1; /* need to load */ 1196 return 1; /* need to load */
1201} 1197}
1202 1198
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 */
1208static 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
1203/* called from request_firmware() and request_firmware_work_func() */ 1221/* called from request_firmware() and request_firmware_work_func() */
1204static int 1222static int
1205_request_firmware(const struct firmware **firmware_p, const char *name, 1223_request_firmware(const struct firmware **firmware_p, const char *name,
@@ -1243,6 +1261,7 @@ _request_firmware(const struct firmware **firmware_p, const char *name,
1243 1261
1244 out: 1262 out:
1245 if (ret < 0) { 1263 if (ret < 0) {
1264 fw_abort_batch_reqs(fw);
1246 release_firmware(fw); 1265 release_firmware(fw);
1247 fw = NULL; 1266 fw = NULL;
1248 } 1267 }