Skip to content

Commit 5b02962

Browse files
Daniel Wagnergregkh
Daniel Wagner
authored andcommitted
firmware: do not use fw_lock for fw_state protection
fw_lock is to use to protect 'corner cases' inside firmware_class. It is not exactly clear what those corner cases are nor what it exactly protects. fw_state can be used without needing the fw_lock to protect its state transition and wake ups. fw_state is holds the state in status and the completion is used to wake up all waiters (in this case that is the user land helper so only one). This operation has to be 'atomic' to avoid races. We can do this by using swait which takes care we don't miss any wake up. We use also swait instead of wait because don't need all the additional features wait provides. Note there some more cleanups possible after with this change. For example for !CONFIG_FW_LOADER_USER_HELPER we don't check for the state anymore. Let's to this in the next patch instead mingling to many changes into this one. And yes you get a gcc warning "‘__fw_state_check’ defined but not used [-Wunused-function] code." for the time beeing. Cc: Ming Lei <[email protected]> Signed-off-by: Daniel Wagner <[email protected]> Acked-by: Luis R. Rodriguez <[email protected]> Signed-off-by: Greg Kroah-Hartman <[email protected]>
1 parent 0430caf commit 5b02962

File tree

1 file changed

+15
-36
lines changed

1 file changed

+15
-36
lines changed

drivers/base/firmware_class.c

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

3435
#include <generated/utsrelease.h>
3536

@@ -111,13 +112,13 @@ static inline long firmware_loading_timeout(void)
111112
* state of the firmware loading.
112113
*/
113114
struct fw_state {
114-
struct completion completion;
115+
struct swait_queue_head wq;
115116
enum fw_status status;
116117
};
117118

118119
static void fw_state_init(struct fw_state *fw_st)
119120
{
120-
init_completion(&fw_st->completion);
121+
init_swait_queue_head(&fw_st->wq);
121122
fw_st->status = FW_STATUS_UNKNOWN;
122123
}
123124

@@ -126,13 +127,19 @@ static int __fw_state_check(struct fw_state *fw_st, enum fw_status status)
126127
return fw_st->status == status;
127128
}
128129

130+
static inline bool __fw_state_is_done(enum fw_status status)
131+
{
132+
return status == FW_STATUS_DONE || status == FW_STATUS_ABORTED;
133+
}
134+
129135
static long __fw_state_wait_common(struct fw_state *fw_st, long timeout)
130136
{
131137
long ret;
132138

133-
ret = wait_for_completion_interruptible_timeout(&fw_st->completion,
134-
timeout);
135-
if (ret != 0 && READ_ONCE(fw_st->status) == FW_STATUS_ABORTED)
139+
ret = swait_event_interruptible_timeout(fw_st->wq,
140+
__fw_state_is_done(READ_ONCE(fw_st->status)),
141+
timeout);
142+
if (ret != 0 && fw_st->status == FW_STATUS_ABORTED)
136143
return -ENOENT;
137144

138145
return ret;
@@ -144,7 +151,7 @@ static void __fw_state_set(struct fw_state *fw_st,
144151
WRITE_ONCE(fw_st->status, status);
145152

146153
if (status == FW_STATUS_DONE || status == FW_STATUS_ABORTED)
147-
complete_all(&fw_st->completion);
154+
swake_up(&fw_st->wq);
148155
}
149156

150157
#define fw_state_start(fw_st) \
@@ -373,14 +380,6 @@ static const char * const fw_path[] = {
373380
module_param_string(path, fw_path_para, sizeof(fw_path_para), 0644);
374381
MODULE_PARM_DESC(path, "customized firmware image search path with a higher priority than default path");
375382

376-
static void fw_finish_direct_load(struct device *device,
377-
struct firmware_buf *buf)
378-
{
379-
mutex_lock(&fw_lock);
380-
fw_state_done(&buf->fw_st);
381-
mutex_unlock(&fw_lock);
382-
}
383-
384383
static int
385384
fw_get_filesystem_firmware(struct device *device, struct firmware_buf *buf)
386385
{
@@ -427,7 +426,7 @@ fw_get_filesystem_firmware(struct device *device, struct firmware_buf *buf)
427426
}
428427
dev_dbg(device, "direct-loading %s\n", buf->fw_id);
429428
buf->size = size;
430-
fw_finish_direct_load(device, buf);
429+
fw_state_done(&buf->fw_st);
431430
break;
432431
}
433432
__putname(path);
@@ -1084,26 +1083,6 @@ static inline void kill_requests_without_uevent(void) { }
10841083

10851084
#endif /* CONFIG_FW_LOADER_USER_HELPER */
10861085

1087-
1088-
/* wait until the shared firmware_buf becomes ready (or error) */
1089-
static int sync_cached_firmware_buf(struct firmware_buf *buf)
1090-
{
1091-
int ret = 0;
1092-
1093-
mutex_lock(&fw_lock);
1094-
while (!fw_state_is_done(&buf->fw_st)) {
1095-
if (fw_state_is_aborted(&buf->fw_st)) {
1096-
ret = -ENOENT;
1097-
break;
1098-
}
1099-
mutex_unlock(&fw_lock);
1100-
ret = fw_state_wait(&buf->fw_st);
1101-
mutex_lock(&fw_lock);
1102-
}
1103-
mutex_unlock(&fw_lock);
1104-
return ret;
1105-
}
1106-
11071086
/* prepare firmware and firmware_buf structs;
11081087
* return 0 if a firmware is already assigned, 1 if need to load one,
11091088
* or a negative error code
@@ -1137,7 +1116,7 @@ _request_firmware_prepare(struct firmware **firmware_p, const char *name,
11371116
firmware->priv = buf;
11381117

11391118
if (ret > 0) {
1140-
ret = sync_cached_firmware_buf(buf);
1119+
ret = fw_state_wait(&buf->fw_st);
11411120
if (!ret) {
11421121
fw_set_page_data(buf, firmware);
11431122
return 0; /* assigned */

0 commit comments

Comments
 (0)