aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorBjorn Andersson <bjorn.andersson@linaro.org>2016-12-06 20:01:45 -0500
committerGreg Kroah-Hartman <gregkh@linuxfoundation.org>2016-12-08 15:05:54 -0500
commit5d47ec02c37ea632398cb251c884e3a488dff794 (patch)
tree743813f72d14ed2a4b1981fe0a70f3b0466221b4
parent64df1148876e35e81e91195e01c8197edc66fcc5 (diff)
firmware: Correct handling of fw_state_wait() return value
When request_firmware() finds an already open firmware object it will wait for that object to become fully loaded and then check the status. As __fw_state_wait_common() succeeds the timeout value returned will be truncated in _request_firmware_prepare() and interpreted as -EPERM. Prior to "firmware: do not use fw_lock for fw_state protection" the code did test if we where in the "done" state before sleeping, causing this particular code path to succeed, in some cases. As the callers are interested in the result of the wait and not the remaining timeout the return value of __fw_state_wait_common() is changed to signal "done" or "error", which simplifies the logic in _request_firmware_load() as well. Fixes: 5b029624948d ("firmware: do not use fw_lock for fw_state protection") Signed-off-by: Bjorn Andersson <bjorn.andersson@linaro.org> Reviewed-by: Daniel Wagner <daniel.wagner@bmw-carit.de> Acked-by: Luis R. Rodriguez <mcgrof@kernel.org> Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
-rw-r--r--drivers/base/firmware_class.c13
1 files changed, 6 insertions, 7 deletions
diff --git a/drivers/base/firmware_class.c b/drivers/base/firmware_class.c
index eb95cf7c3b28..4497d263209f 100644
--- a/drivers/base/firmware_class.c
+++ b/drivers/base/firmware_class.c
@@ -127,7 +127,7 @@ static inline bool __fw_state_is_done(enum fw_status status)
127 return status == FW_STATUS_DONE || status == FW_STATUS_ABORTED; 127 return status == FW_STATUS_DONE || status == FW_STATUS_ABORTED;
128} 128}
129 129
130static long __fw_state_wait_common(struct fw_state *fw_st, long timeout) 130static int __fw_state_wait_common(struct fw_state *fw_st, long timeout)
131{ 131{
132 long ret; 132 long ret;
133 133
@@ -136,8 +136,10 @@ static long __fw_state_wait_common(struct fw_state *fw_st, long timeout)
136 timeout); 136 timeout);
137 if (ret != 0 && fw_st->status == FW_STATUS_ABORTED) 137 if (ret != 0 && fw_st->status == FW_STATUS_ABORTED)
138 return -ENOENT; 138 return -ENOENT;
139 if (!ret)
140 return -ETIMEDOUT;
139 141
140 return ret; 142 return ret < 0 ? ret : 0;
141} 143}
142 144
143static void __fw_state_set(struct fw_state *fw_st, 145static void __fw_state_set(struct fw_state *fw_st,
@@ -1017,14 +1019,11 @@ static int _request_firmware_load(struct firmware_priv *fw_priv,
1017 timeout = MAX_JIFFY_OFFSET; 1019 timeout = MAX_JIFFY_OFFSET;
1018 } 1020 }
1019 1021
1020 timeout = fw_state_wait_timeout(&buf->fw_st, timeout); 1022 retval = fw_state_wait_timeout(&buf->fw_st, timeout);
1021 if (timeout == -ERESTARTSYS || !timeout) { 1023 if (retval < 0) {
1022 retval = timeout;
1023 mutex_lock(&fw_lock); 1024 mutex_lock(&fw_lock);
1024 fw_load_abort(fw_priv); 1025 fw_load_abort(fw_priv);
1025 mutex_unlock(&fw_lock); 1026 mutex_unlock(&fw_lock);
1026 } else if (timeout > 0) {
1027 retval = 0;
1028 } 1027 }
1029 1028
1030 if (fw_state_is_aborted(&buf->fw_st)) 1029 if (fw_state_is_aborted(&buf->fw_st))