diff options
| author | Jamie Gibbons <[email protected]> | 2026-07-22 16:45:48 +0100 |
|---|---|---|
| committer | Leo Yu-Chi Liang <[email protected]> | 2026-08-05 10:16:07 -0700 |
| commit | 47cd1fd361e61be4c8293e02aa4b6c60c2d26d76 (patch) | |
| tree | 93e87e5006ac0ac6746adc5d3b09e08375004d11 | |
| parent | 899cbeee1c8a521cf9f2c4242bc17c26c6ebc448 (diff) | |
mailbox: mpfs-mbox: replace unbounded BUSY polling with bounded waits
The MPFS mailbox driver used unbounded polling loops and treated the
BUSY bit as a fatal condition in several paths. On MPFS, BUSY may be
transiently reasserted even after response data is written, which is
observable in U-Boot’s synchronous, polled execution model.
Replace the unbounded loops with a bounded
regmap_read_poll_timeout()-based helper that waits for the controller to
become idle.
This preserves existing behaviour while preventing infinite stalls
and avoiding spurious failures during early boot.
Signed-off-by: Jamie Gibbons <[email protected]>
Reviewed-by: Conor Dooley <[email protected]>
| -rw-r--r-- | drivers/mailbox/mpfs-mbox.c | 20 |
1 files changed, 14 insertions, 6 deletions
diff --git a/drivers/mailbox/mpfs-mbox.c b/drivers/mailbox/mpfs-mbox.c index b1ce377525e..165d9d89630 100644 --- a/drivers/mailbox/mpfs-mbox.c +++ b/drivers/mailbox/mpfs-mbox.c @@ -18,6 +18,7 @@ #include <linux/compat.h> #include <linux/err.h> #include <linux/errno.h> +#include <linux/iopoll.h> #include <log.h> #include <mailbox-uclass.h> #include <mpfs-mailbox.h> @@ -60,6 +61,7 @@ static int mpfs_mbox_send(struct mbox_chan *chan, const void *data) u32 mailbox_val, cmd_shifted, value; u8 *byte_buf; u8 idx, byte_idx, byte_offset; + int ret; u32 *word_buf = (u32 *)msg->cmd_data; @@ -86,13 +88,19 @@ static int mpfs_mbox_send(struct mbox_chan *chan, const void *data) regmap_write(mbox->control_scb, SERVICES_CR_OFFSET, cmd_shifted); - do { - regmap_read(mbox->control_scb, SERVICES_CR_OFFSET, &value); - } while (SERVICE_CR_REQ_MASK == (value & SERVICE_CR_REQ_MASK)); + ret = regmap_read_poll_timeout(mbox->control_scb, SERVICES_CR_OFFSET, + value, !(value & SERVICE_CR_REQ_MASK), + 1, /* poll every 1 µs */ + 20); /* timeout 20 ms */ + if (ret) + return ret; - do { - regmap_read(mbox->control_scb, SERVICES_SR_OFFSET, &value); - } while (SERVICE_SR_BUSY_MASK == (value & SERVICE_SR_BUSY_MASK)); + ret = regmap_read_poll_timeout(mbox->control_scb, SERVICES_SR_OFFSET, + value, !(value & SERVICE_SR_BUSY_MASK), + 1, + 20); + if (ret) + return ret; msg->response->resp_status = (value >> SERVICE_SR_STATUS_SHIFT); if (msg->response->resp_status) |
