Skip to content

Commit 58ecdf0

Browse files
committed
firmware: arm_scmi: Add support for asynchronous commands and delayed response
Messages that are sent to platform, also known as commands and can be: 1. Synchronous commands that block the channel until the requested work has been completed. The platform responds to these commands over the same channel and hence can't be used to send another command until the previous command has completed. 2. Asynchronous commands on the other hand, the platform schedules the requested work to complete later in time and returns almost immediately freeing the channel for new commands. The response indicates the success or failure in the ability to schedule the requested work. When the work has completed, the platform sends an additional delayed response message. Using the same transmit buffer used for sending the asynchronous command even for the delayed response corresponding to it simplifies handling of the delayed response. It's the caller of asynchronous command that is responsible for allocating the completion flag that scmi driver can complete to indicate the arrival of delayed response. Signed-off-by: Sudeep Holla <[email protected]>
1 parent 22d1f76 commit 58ecdf0

File tree

2 files changed

+46
-3
lines changed

2 files changed

+46
-3
lines changed

drivers/firmware/arm_scmi/common.h

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -84,17 +84,21 @@ struct scmi_msg {
8484
* @rx: Receive message, the buffer should be pre-allocated to store
8585
* message. If request-ACK protocol is used, we can reuse the same
8686
* buffer for the rx path as we use for the tx path.
87-
* @done: completion event
87+
* @done: command message transmit completion event
88+
* @async: pointer to delayed response message received event completion
8889
*/
8990
struct scmi_xfer {
9091
struct scmi_msg_hdr hdr;
9192
struct scmi_msg tx;
9293
struct scmi_msg rx;
9394
struct completion done;
95+
struct completion *async_done;
9496
};
9597

9698
void scmi_xfer_put(const struct scmi_handle *h, struct scmi_xfer *xfer);
9799
int scmi_do_xfer(const struct scmi_handle *h, struct scmi_xfer *xfer);
100+
int scmi_do_xfer_with_response(const struct scmi_handle *h,
101+
struct scmi_xfer *xfer);
98102
int scmi_xfer_get_init(const struct scmi_handle *h, u8 msg_id, u8 prot_id,
99103
size_t tx_size, size_t rx_size, struct scmi_xfer **p);
100104
int scmi_handle_put(const struct scmi_handle *handle);

drivers/firmware/arm_scmi/driver.c

Lines changed: 41 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -345,6 +345,8 @@ __scmi_xfer_put(struct scmi_xfers_info *minfo, struct scmi_xfer *xfer)
345345
*/
346346
static void scmi_rx_callback(struct mbox_client *cl, void *m)
347347
{
348+
u8 msg_type;
349+
u32 msg_hdr;
348350
u16 xfer_id;
349351
struct scmi_xfer *xfer;
350352
struct scmi_chan_info *cinfo = client_to_scmi_chan_info(cl);
@@ -353,7 +355,12 @@ static void scmi_rx_callback(struct mbox_client *cl, void *m)
353355
struct scmi_xfers_info *minfo = &info->tx_minfo;
354356
struct scmi_shared_mem __iomem *mem = cinfo->payload;
355357

356-
xfer_id = MSG_XTRACT_TOKEN(ioread32(&mem->msg_header));
358+
msg_hdr = ioread32(&mem->msg_header);
359+
msg_type = MSG_XTRACT_TYPE(msg_hdr);
360+
xfer_id = MSG_XTRACT_TOKEN(msg_hdr);
361+
362+
if (msg_type == MSG_TYPE_NOTIFICATION)
363+
return; /* Notifications not yet supported */
357364

358365
/* Are we even expecting this? */
359366
if (!test_bit(xfer_id, minfo->xfer_alloc_table)) {
@@ -366,7 +373,11 @@ static void scmi_rx_callback(struct mbox_client *cl, void *m)
366373
scmi_dump_header_dbg(dev, &xfer->hdr);
367374

368375
scmi_fetch_response(xfer, mem);
369-
complete(&xfer->done);
376+
377+
if (msg_type == MSG_TYPE_DELAYED_RESP)
378+
complete(xfer->async_done);
379+
else
380+
complete(&xfer->done);
370381
}
371382

372383
/**
@@ -470,6 +481,34 @@ int scmi_do_xfer(const struct scmi_handle *handle, struct scmi_xfer *xfer)
470481
return ret;
471482
}
472483

484+
#define SCMI_MAX_RESPONSE_TIMEOUT (2 * MSEC_PER_SEC)
485+
486+
/**
487+
* scmi_do_xfer_with_response() - Do one transfer and wait until the delayed
488+
* response is received
489+
*
490+
* @handle: Pointer to SCMI entity handle
491+
* @xfer: Transfer to initiate and wait for response
492+
*
493+
* Return: -ETIMEDOUT in case of no delayed response, if transmit error,
494+
* return corresponding error, else if all goes well, return 0.
495+
*/
496+
int scmi_do_xfer_with_response(const struct scmi_handle *handle,
497+
struct scmi_xfer *xfer)
498+
{
499+
int ret, timeout = msecs_to_jiffies(SCMI_MAX_RESPONSE_TIMEOUT);
500+
DECLARE_COMPLETION_ONSTACK(async_response);
501+
502+
xfer->async_done = &async_response;
503+
504+
ret = scmi_do_xfer(handle, xfer);
505+
if (!ret && !wait_for_completion_timeout(xfer->async_done, timeout))
506+
ret = -ETIMEDOUT;
507+
508+
xfer->async_done = NULL;
509+
return ret;
510+
}
511+
473512
/**
474513
* scmi_xfer_get_init() - Allocate and initialise one message for transmit
475514
*

0 commit comments

Comments
 (0)