[PATCH 3/7] mailbox: Find a matching mailbox by fwnode rather than device

From: Douglas Anderson

Date: Tue Jul 14 2026 - 18:28:49 EST


Sometimes, instead of registering one mailbox with a number of
channels, it makes for a cleaner design to register more than one
mailbox. To make it concrete, you might want a device to look like
this when represented in device tree:

mailbox@abc {
compatible = "my,mailbox";
reg = <abc ...>;

north_mailbox: mailbox-north {
#mbox-cells = <0>;
};
south_mailbox: mailbox-south {
#mbox-cells = <0>;
};
}

mailbox-client@xyz {
compatible = "my,mailbox-client";
reg = <xyz ...>;
mboxes = <&north_mailbox>;
};

You might want a design like the above for a few reasons, including
(but not limited to):
* There may not be an obvious numbering of mailboxes. In the above
example, it's not clear which of the "north" or "south" mailbox
should be ID 0 vs ID 1. While an arbitrary mapping could be created,
it's cleaner not to introduce an arbitrary mapping.
* A single device could have mailboxes with very different properties
from each other. A mailbox with "channels" implies that all the
channels are fairly homogeneous. A design with sub-nodes and no
"channels" allows each sub-node to be independent.

At the moment a device tree design like the above doesn't work
because, when searching the mailbox list in mbox_request_channel() we
check against the main `fwnode` of a device.

Extend the mailbox interface to allow a `mbox_controller` to specify a
`fwnode` to use. If this `fwnode` is NULL then keep using the `fwnode`
from the `mbox_controller`'s `struct device` so that existing code
will keep working with no changes.

Signed-off-by: Douglas Anderson <dianders@xxxxxxxxxxxx>
---

drivers/mailbox/mailbox.c | 8 +++++++-
include/linux/mailbox_controller.h | 4 ++++
2 files changed, 11 insertions(+), 1 deletion(-)

diff --git a/drivers/mailbox/mailbox.c b/drivers/mailbox/mailbox.c
index 6c9d426f4e58..692087d461a5 100644
--- a/drivers/mailbox/mailbox.c
+++ b/drivers/mailbox/mailbox.c
@@ -463,7 +463,7 @@ struct mbox_chan *mbox_request_channel(struct mbox_client *cl, int index)
scoped_guard(mutex, &con_mutex) {
chan = ERR_PTR(-EPROBE_DEFER);
list_for_each_entry(mbox, &mbox_cons, node) {
- if (device_match_fwnode(mbox->dev, fwspec.fwnode)) {
+ if (mbox->fwnode == fwspec.fwnode) {
if (mbox->fw_xlate) {
chan = mbox->fw_xlate(mbox, &fwspec);
if (!IS_ERR(chan))
@@ -580,6 +580,10 @@ int mbox_controller_register(struct mbox_controller *mbox)
if (!mbox->fw_xlate && !mbox->of_xlate)
mbox->fw_xlate = fw_mbox_index_xlate;

+ if (!mbox->fwnode)
+ mbox->fwnode = dev_fwnode(mbox->dev);
+ mbox->fwnode = fwnode_handle_get(mbox->fwnode);
+
scoped_guard(mutex, &con_mutex)
list_add_tail(&mbox->node, &mbox_cons);

@@ -607,6 +611,8 @@ void mbox_controller_unregister(struct mbox_controller *mbox)
if (mbox->txdone_poll)
hrtimer_cancel(&mbox->poll_hrt);
}
+
+ fwnode_handle_put(mbox->fwnode);
}
EXPORT_SYMBOL_GPL(mbox_controller_unregister);

diff --git a/include/linux/mailbox_controller.h b/include/linux/mailbox_controller.h
index 26a238a6f941..591ccce3de3a 100644
--- a/include/linux/mailbox_controller.h
+++ b/include/linux/mailbox_controller.h
@@ -63,6 +63,9 @@ struct mbox_chan_ops {
/**
* struct mbox_controller - Controller of a class of communication channels
* @dev: Device backing this controller. Required.
+ * @fwnode: Firmware node related to this controller. If NULL
+ * the firmware node of `dev` will be used. Register
+ * will grab a refcount and unregister will drop it.
* @ops: Operators that work on each communication chan. Required.
* @chans: Array of channels. Required.
* @num_chans: Number of channels in the 'chans' array. Required.
@@ -83,6 +86,7 @@ struct mbox_chan_ops {
*/
struct mbox_controller {
struct device *dev;
+ struct fwnode_handle *fwnode;
const struct mbox_chan_ops *ops;
struct mbox_chan *chans;
int num_chans;
--
2.55.0.141.g00534a21ce-goog