[PATCH 3/5] lib: utils/mailbox: Reference count mailbox channels

Nick Hu nick.hu at sifive.com
Sun Nov 1 19:47:17 PST 2026


mbox_controller_request_chan() returns the already allocated channel
when another client requests the same channel arguments, so a single
struct mbox_chan can be shared by multiple mailbox clients (for example
the RPMI system MSI irqchip driver and the MPXY RPMI system MSI driver
both using the SYSMSI service group channel).

However, mbox_controller_free_chan() unconditionally releases the
channel, so one client freeing the channel on its error path leaves
the other clients with a dangling pointer.

Add a reference count to struct mbox_chan which is set to one when the
channel is created, incremented whenever an existing channel is handed
out again, and decremented by mbox_controller_free_chan(). The channel
is only unlinked and released once the last reference is dropped.

Signed-off-by: Nick Hu <nick.hu at sifive.com>
---
 include/sbi_utils/mailbox/mailbox.h |  5 +++++
 lib/utils/mailbox/mailbox.c         | 10 ++++++++--
 2 files changed, 13 insertions(+), 2 deletions(-)

diff --git a/include/sbi_utils/mailbox/mailbox.h b/include/sbi_utils/mailbox/mailbox.h
index 46fd8770..2a906aa2 100644
--- a/include/sbi_utils/mailbox/mailbox.h
+++ b/include/sbi_utils/mailbox/mailbox.h
@@ -26,6 +26,11 @@ struct mbox_chan {
 	 */
 #define MBOX_CHAN_MAX_ARGS	2
 	u32 chan_args[MBOX_CHAN_MAX_ARGS];
+	/**
+	 * Number of users holding this channel. Managed by
+	 * mbox_controller_request_chan() and mbox_controller_free_chan().
+	 */
+	u32 ref_count;
 };
 
 #define to_mbox_chan(__node)	\
diff --git a/lib/utils/mailbox/mailbox.c b/lib/utils/mailbox/mailbox.c
index a617cc5d..c8ac1f62 100644
--- a/lib/utils/mailbox/mailbox.c
+++ b/lib/utils/mailbox/mailbox.c
@@ -71,8 +71,10 @@ struct mbox_chan *mbox_controller_request_chan(struct mbox_controller *mbox,
 	sbi_list_for_each(pos, &mbox->chan_list) {
 		ret = to_mbox_chan(pos);
 		if (!sbi_memcmp(ret->chan_args, chan_args,
-				sizeof(ret->chan_args)))
+				sizeof(ret->chan_args))) {
+			ret->ref_count++;
 			return ret;
+		}
 	}
 
 	ret = mbox->request_chan(mbox, chan_args);
@@ -81,13 +83,17 @@ struct mbox_chan *mbox_controller_request_chan(struct mbox_controller *mbox,
 
 	ret->mbox = mbox;
 	sbi_memcpy(ret->chan_args, chan_args, sizeof(ret->chan_args));
+	ret->ref_count = 1;
 	sbi_list_add(&ret->node, &mbox->chan_list);
 	return ret;
 }
 
 void mbox_controller_free_chan(struct mbox_chan *chan)
 {
-	if (!chan || !chan->mbox)
+	if (!chan || !chan->mbox || !chan->ref_count)
+		return;
+
+	if (--chan->ref_count)
 		return;
 
 	sbi_list_del(&chan->node);

-- 
2.43.7




More information about the opensbi mailing list