Skip to content

Commit

Permalink
firmware: arm_scmi: Add sync_cmds_completed_on_ret transport flag
Browse files Browse the repository at this point in the history
Add a flag to let the transport signal to the core if its handling of sync
command implies that, after .send_message has returned successfully, the
requested command can be assumed to be fully and completely executed on
SCMI platform side so that any possible response value is already
immediately available to be retrieved by a .fetch_response: in other words
the polling phase can be skipped in such a case and the response values
accessed straight away.

Note that all of the above applies only when polling mode of operation was
selected by the core: if instead a completion IRQ was found to be available
the normal response processing path based on completions will still be
followed.

Link: https://lore.kernel.org/r/20211220195646.44498-4-cristian.marussi@arm.com
Signed-off-by: Cristian Marussi <cristian.marussi@arm.com>
Signed-off-by: Sudeep Holla <sudeep.holla@arm.com>
  • Loading branch information
Cristian Marussi authored and Sudeep Holla committed Dec 21, 2021
1 parent f716cbd commit 31d2f80
Show file tree
Hide file tree
Showing 2 changed files with 32 additions and 10 deletions.
8 changes: 8 additions & 0 deletions drivers/firmware/arm_scmi/common.h
Original file line number Diff line number Diff line change
Expand Up @@ -409,6 +409,13 @@ struct scmi_device *scmi_child_dev_find(struct device *parent,
* @max_msg_size: Maximum size of data per message that can be handled.
* @force_polling: Flag to force this whole transport to use SCMI core polling
* mechanism instead of completion interrupts even if available.
* @sync_cmds_completed_on_ret: Flag to indicate that the transport assures
* synchronous-command messages are atomically
* completed on .send_message: no need to poll
* actively waiting for a response.
* Used by core internally only when polling is
* selected as a waiting for reply method: i.e.
* if a completion irq was found use that anyway.
*/
struct scmi_desc {
int (*transport_init)(void);
Expand All @@ -418,6 +425,7 @@ struct scmi_desc {
int max_msg;
int max_msg_size;
const bool force_polling;
const bool sync_cmds_completed_on_ret;
};

#ifdef CONFIG_ARM_SCMI_TRANSPORT_MAILBOX
Expand Down
34 changes: 24 additions & 10 deletions drivers/firmware/arm_scmi/driver.c
Original file line number Diff line number Diff line change
Expand Up @@ -617,7 +617,8 @@ static inline bool is_polling_required(struct scmi_chan_info *cinfo,

static inline bool is_transport_polling_capable(struct scmi_info *info)
{
return info->desc->ops->poll_done;
return info->desc->ops->poll_done ||
info->desc->sync_cmds_completed_on_ret;
}

static inline bool is_polling_enabled(struct scmi_chan_info *cinfo,
Expand Down Expand Up @@ -781,10 +782,28 @@ static int scmi_wait_for_message_response(struct scmi_chan_info *cinfo,
xfer->hdr.poll_completion);

if (xfer->hdr.poll_completion) {
ktime_t stop = ktime_add_ms(ktime_get(), timeout_ms);
/*
* Real polling is needed only if transport has NOT declared
* itself to support synchronous commands replies.
*/
if (!info->desc->sync_cmds_completed_on_ret) {
/*
* Poll on xfer using transport provided .poll_done();
* assumes no completion interrupt was available.
*/
ktime_t stop = ktime_add_ms(ktime_get(), timeout_ms);

spin_until_cond(scmi_xfer_done_no_timeout(cinfo,
xfer, stop));
if (ktime_after(ktime_get(), stop)) {
dev_err(dev,
"timed out in resp(caller: %pS) - polling\n",
(void *)_RET_IP_);
ret = -ETIMEDOUT;
}
}

spin_until_cond(scmi_xfer_done_no_timeout(cinfo, xfer, stop));
if (ktime_before(ktime_get(), stop)) {
if (!ret) {
unsigned long flags;

/*
Expand All @@ -797,11 +816,6 @@ static int scmi_wait_for_message_response(struct scmi_chan_info *cinfo,
xfer->state = SCMI_XFER_RESP_OK;
}
spin_unlock_irqrestore(&xfer->lock, flags);
} else {
dev_err(dev,
"timed out in resp(caller: %pS) - polling\n",
(void *)_RET_IP_);
ret = -ETIMEDOUT;
}
} else {
/* And we wait for the response. */
Expand Down Expand Up @@ -836,7 +850,7 @@ static int do_xfer(const struct scmi_protocol_handle *ph,
struct scmi_chan_info *cinfo;

/* Check for polling request on custom command xfers at first */
if (xfer->hdr.poll_completion && !info->desc->ops->poll_done) {
if (xfer->hdr.poll_completion && !is_transport_polling_capable(info)) {
dev_warn_once(dev,
"Polling mode is not supported by transport.\n");
return -EINVAL;
Expand Down

0 comments on commit 31d2f80

Please sign in to comment.