firmware: arm_scmi: Fix timeout checks on polling path
commit c23c03bf1faa1e76be1eba35bad6da6a2a7c95ee upstream.
Polling mode transactions wait for a reply busy-looping without holding a
spinlock, but currently the timeout checks are based only on elapsed time:
as a result we could hit a false positive whenever our busy-looping thread
is pre-empted and scheduled out for a time greater than the polling
timeout.
Change the checks at the end of the busy-loop to make sure that the polling
wasn't indeed successful or an out-of-order reply caused the polling to be
forcibly terminated.
Fixes: 31d2f803c1 ("firmware: arm_scmi: Add sync_cmds_completed_on_ret transport flag")
Reported-by: Huangjie <huangjie1663@phytium.com.cn>
Closes: https://lore.kernel.org/arm-scmi/20250123083323.2363749-1-jackhuang021@gmail.com/
Signed-off-by: Cristian Marussi <cristian.marussi@arm.com>
Cc: stable@vger.kernel.org # 5.18.x
Message-Id: <20250310175800.1444293-1-cristian.marussi@arm.com>
Signed-off-by: Sudeep Holla <sudeep.holla@arm.com>
Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
This commit is contained in:
committed by
Greg Kroah-Hartman
parent
fe3da1bfd8
commit
14ee85b748
@@ -1219,7 +1219,8 @@ static void xfer_put(const struct scmi_protocol_handle *ph,
|
|||||||
}
|
}
|
||||||
|
|
||||||
static bool scmi_xfer_done_no_timeout(struct scmi_chan_info *cinfo,
|
static bool scmi_xfer_done_no_timeout(struct scmi_chan_info *cinfo,
|
||||||
struct scmi_xfer *xfer, ktime_t stop)
|
struct scmi_xfer *xfer, ktime_t stop,
|
||||||
|
bool *ooo)
|
||||||
{
|
{
|
||||||
struct scmi_info *info = handle_to_scmi_info(cinfo->handle);
|
struct scmi_info *info = handle_to_scmi_info(cinfo->handle);
|
||||||
|
|
||||||
@@ -1228,7 +1229,7 @@ static bool scmi_xfer_done_no_timeout(struct scmi_chan_info *cinfo,
|
|||||||
* in case of out-of-order receptions of delayed responses
|
* in case of out-of-order receptions of delayed responses
|
||||||
*/
|
*/
|
||||||
return info->desc->ops->poll_done(cinfo, xfer) ||
|
return info->desc->ops->poll_done(cinfo, xfer) ||
|
||||||
try_wait_for_completion(&xfer->done) ||
|
(*ooo = try_wait_for_completion(&xfer->done)) ||
|
||||||
ktime_after(ktime_get(), stop);
|
ktime_after(ktime_get(), stop);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1245,15 +1246,17 @@ static int scmi_wait_for_reply(struct device *dev, const struct scmi_desc *desc,
|
|||||||
* itself to support synchronous commands replies.
|
* itself to support synchronous commands replies.
|
||||||
*/
|
*/
|
||||||
if (!desc->sync_cmds_completed_on_ret) {
|
if (!desc->sync_cmds_completed_on_ret) {
|
||||||
|
bool ooo = false;
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Poll on xfer using transport provided .poll_done();
|
* Poll on xfer using transport provided .poll_done();
|
||||||
* assumes no completion interrupt was available.
|
* assumes no completion interrupt was available.
|
||||||
*/
|
*/
|
||||||
ktime_t stop = ktime_add_ms(ktime_get(), timeout_ms);
|
ktime_t stop = ktime_add_ms(ktime_get(), timeout_ms);
|
||||||
|
|
||||||
spin_until_cond(scmi_xfer_done_no_timeout(cinfo,
|
spin_until_cond(scmi_xfer_done_no_timeout(cinfo, xfer,
|
||||||
xfer, stop));
|
stop, &ooo));
|
||||||
if (ktime_after(ktime_get(), stop)) {
|
if (!ooo && !info->desc->ops->poll_done(cinfo, xfer)) {
|
||||||
dev_err(dev,
|
dev_err(dev,
|
||||||
"timed out in resp(caller: %pS) - polling\n",
|
"timed out in resp(caller: %pS) - polling\n",
|
||||||
(void *)_RET_IP_);
|
(void *)_RET_IP_);
|
||||||
|
|||||||
Reference in New Issue
Block a user