diff options
| -rw-r--r-- | drivers/base/firmware_class.c | 51 |
1 files changed, 15 insertions, 36 deletions
diff --git a/drivers/base/firmware_class.c b/drivers/base/firmware_class.c index 45a20dd31c25..95f566c10a55 100644 --- a/drivers/base/firmware_class.c +++ b/drivers/base/firmware_class.c | |||
| @@ -30,6 +30,7 @@ | |||
| 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> | ||
| 33 | 34 | ||
| 34 | #include <generated/utsrelease.h> | 35 | #include <generated/utsrelease.h> |
| 35 | 36 | ||
| @@ -111,13 +112,13 @@ static inline long firmware_loading_timeout(void) | |||
| 111 | * state of the firmware loading. | 112 | * state of the firmware loading. |
| 112 | */ | 113 | */ |
| 113 | struct fw_state { | 114 | struct fw_state { |
| 114 | struct completion completion; | 115 | struct swait_queue_head wq; |
| 115 | enum fw_status status; | 116 | enum fw_status status; |
| 116 | }; | 117 | }; |
| 117 | 118 | ||
| 118 | static void fw_state_init(struct fw_state *fw_st) | 119 | static void fw_state_init(struct fw_state *fw_st) |
| 119 | { | 120 | { |
| 120 | init_completion(&fw_st->completion); | 121 | init_swait_queue_head(&fw_st->wq); |
| 121 | fw_st->status = FW_STATUS_UNKNOWN; | 122 | fw_st->status = FW_STATUS_UNKNOWN; |
| 122 | } | 123 | } |
| 123 | 124 | ||
| @@ -126,13 +127,19 @@ static int __fw_state_check(struct fw_state *fw_st, enum fw_status status) | |||
| 126 | return fw_st->status == status; | 127 | return fw_st->status == status; |
| 127 | } | 128 | } |
| 128 | 129 | ||
| 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 | |||
| 129 | static long __fw_state_wait_common(struct fw_state *fw_st, long timeout) | 135 | static long __fw_state_wait_common(struct fw_state *fw_st, long timeout) |
| 130 | { | 136 | { |
| 131 | long ret; | 137 | long ret; |
| 132 | 138 | ||
| 133 | ret = wait_for_completion_interruptible_timeout(&fw_st->completion, | 139 | ret = swait_event_interruptible_timeout(fw_st->wq, |
| 134 | timeout); | 140 | __fw_state_is_done(READ_ONCE(fw_st->status)), |
| 135 | if (ret != 0 && READ_ONCE(fw_st->status) == FW_STATUS_ABORTED) | 141 | timeout); |
| 142 | if (ret != 0 && fw_st->status == FW_STATUS_ABORTED) | ||
| 136 | return -ENOENT; | 143 | return -ENOENT; |
| 137 | 144 | ||
| 138 | return ret; | 145 | return ret; |
| @@ -144,7 +151,7 @@ static void __fw_state_set(struct fw_state *fw_st, | |||
| 144 | WRITE_ONCE(fw_st->status, status); | 151 | WRITE_ONCE(fw_st->status, status); |
| 145 | 152 | ||
| 146 | if (status == FW_STATUS_DONE || status == FW_STATUS_ABORTED) | 153 | if (status == FW_STATUS_DONE || status == FW_STATUS_ABORTED) |
| 147 | complete_all(&fw_st->completion); | 154 | swake_up(&fw_st->wq); |
| 148 | } | 155 | } |
| 149 | 156 | ||
| 150 | #define fw_state_start(fw_st) \ | 157 | #define fw_state_start(fw_st) \ |
| @@ -373,14 +380,6 @@ static const char * const fw_path[] = { | |||
| 373 | module_param_string(path, fw_path_para, sizeof(fw_path_para), 0644); | 380 | module_param_string(path, fw_path_para, sizeof(fw_path_para), 0644); |
| 374 | MODULE_PARM_DESC(path, "customized firmware image search path with a higher priority than default path"); | 381 | MODULE_PARM_DESC(path, "customized firmware image search path with a higher priority than default path"); |
| 375 | 382 | ||
| 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 | |||
| 384 | static int | 383 | static int |
| 385 | fw_get_filesystem_firmware(struct device *device, struct firmware_buf *buf) | 384 | fw_get_filesystem_firmware(struct device *device, struct firmware_buf *buf) |
| 386 | { | 385 | { |
| @@ -427,7 +426,7 @@ fw_get_filesystem_firmware(struct device *device, struct firmware_buf *buf) | |||
| 427 | } | 426 | } |
| 428 | dev_dbg(device, "direct-loading %s\n", buf->fw_id); | 427 | dev_dbg(device, "direct-loading %s\n", buf->fw_id); |
| 429 | buf->size = size; | 428 | buf->size = size; |
| 430 | fw_finish_direct_load(device, buf); | 429 | fw_state_done(&buf->fw_st); |
| 431 | break; | 430 | break; |
| 432 | } | 431 | } |
| 433 | __putname(path); | 432 | __putname(path); |
| @@ -1084,26 +1083,6 @@ static inline void kill_requests_without_uevent(void) { } | |||
| 1084 | 1083 | ||
| 1085 | #endif /* CONFIG_FW_LOADER_USER_HELPER */ | 1084 | #endif /* CONFIG_FW_LOADER_USER_HELPER */ |
| 1086 | 1085 | ||
| 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 | |||
| 1107 | /* prepare firmware and firmware_buf structs; | 1086 | /* prepare firmware and firmware_buf structs; |
| 1108 | * return 0 if a firmware is already assigned, 1 if need to load one, | 1087 | * return 0 if a firmware is already assigned, 1 if need to load one, |
| 1109 | * or a negative error code | 1088 | * or a negative error code |
| @@ -1137,7 +1116,7 @@ _request_firmware_prepare(struct firmware **firmware_p, const char *name, | |||
| 1137 | firmware->priv = buf; | 1116 | firmware->priv = buf; |
| 1138 | 1117 | ||
| 1139 | if (ret > 0) { | 1118 | if (ret > 0) { |
| 1140 | ret = sync_cached_firmware_buf(buf); | 1119 | ret = fw_state_wait(&buf->fw_st); |
| 1141 | if (!ret) { | 1120 | if (!ret) { |
| 1142 | fw_set_page_data(buf, firmware); | 1121 | fw_set_page_data(buf, firmware); |
| 1143 | return 0; /* assigned */ | 1122 | return 0; /* assigned */ |
