Skip to content

Commit 8d2c2fa

Browse files
ambaruskrzk
authored andcommitted
firmware: exynos-acpm: fix timeouts on xfers handling
The mailbox framework has a single inflight request at a time. If a request is sent while another is still active, it will be queued to the mailbox core ring buffer. ACPM protocol did not serialize the calls to the mailbox subsystem so we could start the timeout ticks in parallel for multiple requests, while just one was being inflight. Consider a hypothetical case where the xfer timeout is 100ms and an ACPM transaction takes 90ms: | 0ms: Message #0 is queued in mailbox layer and sent out, then sits | at acpm_dequeue_by_polling() with a timeout of 100ms | 1ms: Message #1 is queued in mailbox layer but not sent out yet. | Since send_message() doesn't block, it also sits at | acpm_dequeue_by_polling() with a timeout of 100ms | ... | 90ms: Message #0 is completed, txdone is called and message #1 is sent | 101ms: Message #1 times out since the count started at 1ms. Even though | it has only been inflight for 11ms. Fix the problem by moving mbox_send_message() and mbox_client_txdone() immediately after the message has been written to the TX queue and while still keeping the ACPM TX queue lock. We thus tie together the TX write with the doorbell ring and mark the TX as done after the doorbell has been rung. This guarantees that the doorbell has been rang before starting the timeout ticks. We should also see some performance improvement as we no longer wait to receive a response before ringing the doorbell for the next request, so the ACPM firmware shall be able to drain faster the TX queue. Another benefit is that requests are no longer able to ring the doorbell one for the other, so it eases debugging. Finally, the mailbox software queue will always contain a single doorbell request due to the serialization done at the ACPM TX queue level. Protocols like ACPM, that handle their own hardware queues need a passthrough mailbox API, where they are able to just ring the doorbell or flip a bit directly into the mailbox controller. The mailbox software queue mechanism, the locking done into the mailbox core is not really needed, so hopefully this lays the foundation for a passthrough mailbox API. Reported-by: André Draszik <[email protected]> Fixes: a88927b ("firmware: add Exynos ACPM protocol driver") Signed-off-by: Tudor Ambarus <[email protected]> Link: https://lore.kernel.org/r/[email protected] Signed-off-by: Krzysztof Kozlowski <[email protected]>
1 parent f17d5b9 commit 8d2c2fa

File tree

1 file changed

+9
-16
lines changed

1 file changed

+9
-16
lines changed

drivers/firmware/samsung/exynos-acpm.c

Lines changed: 9 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -430,6 +430,9 @@ int acpm_do_xfer(const struct acpm_handle *handle, const struct acpm_xfer *xfer)
430430
return -EOPNOTSUPP;
431431
}
432432

433+
msg.chan_id = xfer->acpm_chan_id;
434+
msg.chan_type = EXYNOS_MBOX_CHAN_TYPE_DOORBELL;
435+
433436
scoped_guard(mutex, &achan->tx_lock) {
434437
tx_front = readl(achan->tx.front);
435438
idx = (tx_front + 1) % achan->qlen;
@@ -446,25 +449,15 @@ int acpm_do_xfer(const struct acpm_handle *handle, const struct acpm_xfer *xfer)
446449

447450
/* Advance TX front. */
448451
writel(idx, achan->tx.front);
449-
}
450452

451-
msg.chan_id = xfer->acpm_chan_id;
452-
msg.chan_type = EXYNOS_MBOX_CHAN_TYPE_DOORBELL;
453-
ret = mbox_send_message(achan->chan, (void *)&msg);
454-
if (ret < 0)
455-
return ret;
456-
457-
ret = acpm_wait_for_message_response(achan, xfer);
453+
ret = mbox_send_message(achan->chan, (void *)&msg);
454+
if (ret < 0)
455+
return ret;
458456

459-
/*
460-
* NOTE: we might prefer not to need the mailbox ticker to manage the
461-
* transfer queueing since the protocol layer queues things by itself.
462-
* Unfortunately, we have to kick the mailbox framework after we have
463-
* received our message.
464-
*/
465-
mbox_client_txdone(achan->chan, ret);
457+
mbox_client_txdone(achan->chan, 0);
458+
}
466459

467-
return ret;
460+
return acpm_wait_for_message_response(achan, xfer);
468461
}
469462

470463
/**

0 commit comments

Comments
 (0)