diff --git a/drivers/base/firmware_class.c b/drivers/base/firmware_class.c index 453958892a69b..4f5105f575213 100644 --- a/drivers/base/firmware_class.c +++ b/drivers/base/firmware_class.c @@ -91,10 +91,11 @@ static inline bool fw_is_builtin_firmware(const struct firmware *fw) } #endif -enum { +enum fw_status { + FW_STATUS_UNKNOWN, FW_STATUS_LOADING, FW_STATUS_DONE, - FW_STATUS_ABORT, + FW_STATUS_ABORTED, }; static int loading_timeout = 60; /* In seconds */ @@ -104,6 +105,76 @@ static inline long firmware_loading_timeout(void) return loading_timeout > 0 ? loading_timeout * HZ : MAX_JIFFY_OFFSET; } +/* + * Concurrent request_firmware() for the same firmware need to be + * serialized. struct fw_state is simple state machine which hold the + * state of the firmware loading. + */ +struct fw_state { + struct completion completion; + unsigned long status; +}; + +static void fw_state_init(struct fw_state *fw_st) +{ + init_completion(&fw_st->completion); + fw_st->status = FW_STATUS_UNKNOWN; +} + +static int __fw_state_check(struct fw_state *fw_st, enum fw_status status) +{ + return test_bit(status, &fw_st->status); +} + +static long __fw_state_wait_common(struct fw_state *fw_st, long timeout) +{ + long ret; + + ret = wait_for_completion_interruptible_timeout(&fw_st->completion, + timeout); + if (ret != 0 && test_bit(FW_STATUS_ABORTED, &fw_st->status)) + return -ENOENT; + + return ret; +} + +static void __fw_state_set(struct fw_state *fw_st, + enum fw_status status) +{ + set_bit(status, &fw_st->status); + + if (status == FW_STATUS_DONE || status == FW_STATUS_ABORTED) { + clear_bit(FW_STATUS_LOADING, &fw_st->status); + complete_all(&fw_st->completion); + } +} + +#define fw_state_start(fw_st) \ + __fw_state_set(fw_st, FW_STATUS_LOADING) +#define fw_state_done(fw_st) \ + __fw_state_set(fw_st, FW_STATUS_DONE) +#define fw_state_is_done(fw_st) \ + __fw_state_check(fw_st, FW_STATUS_DONE) +#define fw_state_wait(fw_st) \ + __fw_state_wait_common(fw_st, MAX_SCHEDULE_TIMEOUT) + +#ifndef CONFIG_FW_LOADER_USER_HELPER + +#define fw_state_is_aborted(fw_st) false + +#else /* CONFIG_FW_LOADER_USER_HELPER */ + +#define fw_state_aborted(fw_st) \ + __fw_state_set(fw_st, FW_STATUS_ABORTED) +#define fw_state_is_loading(fw_st) \ + __fw_state_check(fw_st, FW_STATUS_LOADING) +#define fw_state_is_aborted(fw_st) \ + __fw_state_check(fw_st, FW_STATUS_ABORTED) +#define fw_state_wait_timeout(fw_st, timeout) \ + __fw_state_wait_common(fw_st, timeout) + +#endif /* CONFIG_FW_LOADER_USER_HELPER */ + /* firmware behavior options */ #define FW_OPT_UEVENT (1U << 0) #define FW_OPT_NOWAIT (1U << 1) @@ -145,9 +216,8 @@ struct firmware_cache { struct firmware_buf { struct kref ref; struct list_head list; - struct completion completion; struct firmware_cache *fwc; - unsigned long status; + struct fw_state fw_st; void *data; size_t size; size_t allocated_size; @@ -205,7 +275,7 @@ static struct firmware_buf *__allocate_fw_buf(const char *fw_name, buf->fwc = fwc; buf->data = dbuf; buf->allocated_size = size; - init_completion(&buf->completion); + fw_state_init(&buf->fw_st); #ifdef CONFIG_FW_LOADER_USER_HELPER INIT_LIST_HEAD(&buf->pending_list); #endif @@ -309,8 +379,7 @@ static void fw_finish_direct_load(struct device *device, struct firmware_buf *buf) { mutex_lock(&fw_lock); - set_bit(FW_STATUS_DONE, &buf->status); - complete_all(&buf->completion); + fw_state_done(&buf->fw_st); mutex_unlock(&fw_lock); } @@ -478,12 +547,11 @@ static void __fw_load_abort(struct firmware_buf *buf) * There is a small window in which user can write to 'loading' * between loading done and disappearance of 'loading' */ - if (test_bit(FW_STATUS_DONE, &buf->status)) + if (fw_state_is_done(&buf->fw_st)) return; list_del_init(&buf->pending_list); - set_bit(FW_STATUS_ABORT, &buf->status); - complete_all(&buf->completion); + fw_state_aborted(&buf->fw_st); } static void fw_load_abort(struct firmware_priv *fw_priv) @@ -496,9 +564,6 @@ static void fw_load_abort(struct firmware_priv *fw_priv) fw_priv->buf = NULL; } -#define is_fw_load_aborted(buf) \ - test_bit(FW_STATUS_ABORT, &(buf)->status) - static LIST_HEAD(pending_fw_head); /* reboot notifier for avoid deadlock with usermode_lock */ @@ -600,7 +665,7 @@ static ssize_t firmware_loading_show(struct device *dev, mutex_lock(&fw_lock); if (fw_priv->buf) - loading = test_bit(FW_STATUS_LOADING, &fw_priv->buf->status); + loading = fw_state_is_loading(&fw_priv->buf->fw_st); mutex_unlock(&fw_lock); return sprintf(buf, "%d\n", loading); @@ -655,23 +720,20 @@ static ssize_t firmware_loading_store(struct device *dev, switch (loading) { case 1: /* discarding any previous partial load */ - if (!test_bit(FW_STATUS_DONE, &fw_buf->status)) { + if (!fw_state_is_done(&fw_buf->fw_st)) { for (i = 0; i < fw_buf->nr_pages; i++) __free_page(fw_buf->pages[i]); vfree(fw_buf->pages); fw_buf->pages = NULL; fw_buf->page_array_size = 0; fw_buf->nr_pages = 0; - set_bit(FW_STATUS_LOADING, &fw_buf->status); + fw_state_start(&fw_buf->fw_st); } break; case 0: - if (test_bit(FW_STATUS_LOADING, &fw_buf->status)) { + if (fw_state_is_loading(&fw_buf->fw_st)) { int rc; - set_bit(FW_STATUS_DONE, &fw_buf->status); - clear_bit(FW_STATUS_LOADING, &fw_buf->status); - /* * Several loading requests may be pending on * one same firmware buf, so let all requests @@ -693,10 +755,11 @@ static ssize_t firmware_loading_store(struct device *dev, */ list_del_init(&fw_buf->pending_list); if (rc) { - set_bit(FW_STATUS_ABORT, &fw_buf->status); + fw_state_aborted(&fw_buf->fw_st); written = rc; + } else { + fw_state_done(&fw_buf->fw_st); } - complete_all(&fw_buf->completion); break; } /* fallthrough */ @@ -757,7 +820,7 @@ static ssize_t firmware_data_read(struct file *filp, struct kobject *kobj, mutex_lock(&fw_lock); buf = fw_priv->buf; - if (!buf || test_bit(FW_STATUS_DONE, &buf->status)) { + if (!buf || fw_state_is_done(&buf->fw_st)) { ret_count = -ENODEV; goto out; } @@ -844,7 +907,7 @@ static ssize_t firmware_data_write(struct file *filp, struct kobject *kobj, mutex_lock(&fw_lock); buf = fw_priv->buf; - if (!buf || test_bit(FW_STATUS_DONE, &buf->status)) { + if (!buf || fw_state_is_done(&buf->fw_st)) { retval = -ENODEV; goto out; } @@ -957,8 +1020,7 @@ static int _request_firmware_load(struct firmware_priv *fw_priv, timeout = MAX_JIFFY_OFFSET; } - timeout = wait_for_completion_interruptible_timeout(&buf->completion, - timeout); + timeout = fw_state_wait_timeout(&buf->fw_st, timeout); if (timeout == -ERESTARTSYS || !timeout) { retval = timeout; mutex_lock(&fw_lock); @@ -968,7 +1030,7 @@ static int _request_firmware_load(struct firmware_priv *fw_priv, retval = 0; } - if (is_fw_load_aborted(buf)) + if (fw_state_is_aborted(&buf->fw_st)) retval = -EAGAIN; else if (buf->is_paged_buf && !buf->data) retval = -ENOMEM; @@ -1018,9 +1080,6 @@ fw_load_from_user_helper(struct firmware *firmware, const char *name, return -ENOENT; } -/* No abort during direct loading */ -#define is_fw_load_aborted(buf) false - #ifdef CONFIG_PM_SLEEP static inline void kill_requests_without_uevent(void) { } #endif @@ -1034,13 +1093,13 @@ static int sync_cached_firmware_buf(struct firmware_buf *buf) int ret = 0; mutex_lock(&fw_lock); - while (!test_bit(FW_STATUS_DONE, &buf->status)) { - if (is_fw_load_aborted(buf)) { + while (!fw_state_is_done(&buf->fw_st)) { + if (fw_state_is_aborted(&buf->fw_st)) { ret = -ENOENT; break; } mutex_unlock(&fw_lock); - ret = wait_for_completion_interruptible(&buf->completion); + ret = fw_state_wait(&buf->fw_st); mutex_lock(&fw_lock); } mutex_unlock(&fw_lock); @@ -1098,7 +1157,7 @@ static int assign_firmware_buf(struct firmware *fw, struct device *device, struct firmware_buf *buf = fw->priv; mutex_lock(&fw_lock); - if (!buf->size || is_fw_load_aborted(buf)) { + if (!buf->size || fw_state_is_aborted(&buf->fw_st)) { mutex_unlock(&fw_lock); return -ENOENT; }