[PATCH 2/4] firmware: samsung: acpm: Fix sequence number leak and infinite loop

From: Tudor Ambarus

Date: Thu Apr 23 2026 - 10:20:09 EST


Sashiko identified a sequence number leak and a possible infinite loop
[1].

ACPM IPC sequence numbers are tracked via a 64-bit bitmap
(`bitmap_seqnum`) to manage concurrent transactions. A bit is set when
a sequence number is allocated in `acpm_prepare_xfer()`.

Previously, if a transfer timed out during RX polling, or if the
underlying hardware mailbox failed to send the message via
`mbox_send_message()`, the allocated sequence number bit was never
cleared.

As these transient errors accumulate, all 63 available sequence numbers
could eventually be leaked. Once the bitmap is full, the next call to
`acpm_prepare_xfer()` would enter an infinite `while` loop attempting
to find a free sequence number, permanently deadlocking the CPU.

Fix this by ensuring the sequence number bit is explicitly cleared on
all error paths:
1. In `acpm_do_xfer()`, clear the bit if the mailbox transmission
fails.
2. In `acpm_dequeue_by_polling()`, clear the bit if the queue read fails
or if the response times out.

Cc: stable@xxxxxxxxxxxxxxx
Fixes: a88927b534ba ("firmware: add Exynos ACPM protocol driver")
Closes: https://sashiko.dev/#/patchset/20260420-acpm-tmu-v3-0-3dc8e93f0b26%40linaro.org [1]
Signed-off-by: Tudor Ambarus <tudor.ambarus@xxxxxxxxxx>
---
drivers/firmware/samsung/exynos-acpm.c | 10 ++++++++--
1 file changed, 8 insertions(+), 2 deletions(-)

diff --git a/drivers/firmware/samsung/exynos-acpm.c b/drivers/firmware/samsung/exynos-acpm.c
index e95edc350efa..a9baed5762d5 100644
--- a/drivers/firmware/samsung/exynos-acpm.c
+++ b/drivers/firmware/samsung/exynos-acpm.c
@@ -311,8 +311,10 @@ static int acpm_dequeue_by_polling(struct acpm_chan *achan,
timeout = ktime_add_us(ktime_get(), ACPM_POLL_TIMEOUT_US);
do {
ret = acpm_get_rx(achan, xfer);
- if (ret)
+ if (ret) {
+ clear_bit(seqnum - 1, achan->bitmap_seqnum);
return ret;
+ }

if (!test_bit(seqnum - 1, achan->bitmap_seqnum))
return 0;
@@ -324,6 +326,8 @@ static int acpm_dequeue_by_polling(struct acpm_chan *achan,
dev_err(dev, "Timeout! ch:%u s:%u bitmap:%lx.\n",
achan->id, seqnum, achan->bitmap_seqnum[0]);

+ clear_bit(seqnum - 1, achan->bitmap_seqnum);
+
return -ETIME;
}

@@ -455,8 +459,10 @@ int acpm_do_xfer(struct acpm_handle *handle, const struct acpm_xfer *xfer)
writel(idx, achan->tx.front);

ret = mbox_send_message(achan->chan, (void *)&msg);
- if (ret < 0)
+ if (ret < 0) {
+ clear_bit(achan->seqnum - 1, achan->bitmap_seqnum);
return ret;
+ }

mbox_client_txdone(achan->chan, 0);
}

--
2.54.0.545.g6539524ca2-goog