From: Anup Patel <anup.patel@oss.qualcomm.com>
To: Palmer Dabbelt <palmer@dabbelt.com>,
Paul Walmsley <pjw@kernel.org>,
Rahul Pathak <rahul@summations.net>,
Stephen Boyd <sboyd@kernel.org>,
Brian Masney <bmasney+clk@redhat.com>,
Jerome Brunet <jbrunet+clk@baylibre.com>,
Thomas Gleixner <tglx@kernel.org>, Radu Rendec <radu@rendec.net>,
Jassi Brar <jassisinghbrar@gmail.com>
Cc: Himanshu Chauhan <hchauhan@ventanamicro.com>,
Atish Patra <atish.patra@linux.dev>,
Anup Patel <anup@brainfault.org>,
Amirreza Zarrabi <amirreza.zarrabi@oss.qualcomm.com>,
linux-riscv@lists.infradead.org, linux-kernel@vger.kernel.org,
linux-clk@vger.kernel.org,
Anup Patel <anup.patel@oss.qualcomm.com>
Subject: [PATCH 3/4] mailbox: add direct synchronous send support
Date: Wed, 30 Sep 2026 20:32:12 +0530 [thread overview]
Message-ID: <20260930150213.799245-4-anup.patel@oss.qualcomm.com> (raw)
In-Reply-To: <20260930150213.799245-1-anup.patel@oss.qualcomm.com>
From: Amirreza Zarrabi <amirreza.zarrabi@oss.qualcomm.com>
Some mailbox controllers can complete a transaction entirely within
the calling context, without going through the queued TX state
machine or a TX-done interrupt. Add a synchronous send path so their
clients can request one and wait for the result directly.
Controllers advertise support via the new send_data_sync() op and
clients opt in by setting tx_sync when requesting the channel.
Channels bound this way must not call mbox_chan_txdone() or
mbox_client_txdone(), and mbox_send_message() and mbox_flush() now
reject them, since only mbox_send_message_sync() is a valid
transmit path. The client remains responsible for serializing calls
to mbox_send_message_sync() against mbox_free_channel().
Signed-off-by: Amirreza Zarrabi <amirreza.zarrabi@oss.qualcomm.com>
Signed-off-by: Anup Patel <anup.patel@oss.qualcomm.com>
---
drivers/mailbox/mailbox.c | 72 +++++++++++++++++++++++++++++-
include/linux/mailbox_client.h | 3 ++
include/linux/mailbox_controller.h | 10 +++++
3 files changed, 83 insertions(+), 2 deletions(-)
diff --git a/drivers/mailbox/mailbox.c b/drivers/mailbox/mailbox.c
index efacd24a085d..c640b19de608 100644
--- a/drivers/mailbox/mailbox.c
+++ b/drivers/mailbox/mailbox.c
@@ -166,6 +166,12 @@ EXPORT_SYMBOL_GPL(mbox_chan_received_data);
*/
void mbox_chan_txdone(struct mbox_chan *chan, int r)
{
+ if (unlikely(chan->txdone_method & MBOX_TXDONE_BY_RETURN)) {
+ dev_err(chan->mbox->dev,
+ "TX-done notification on direct synchronous channel\n");
+ return;
+ }
+
if (unlikely(!(chan->txdone_method & MBOX_TXDONE_BY_IRQ))) {
dev_err(chan->mbox->dev,
"Controller can't run the TX ticker\n");
@@ -187,6 +193,12 @@ EXPORT_SYMBOL_GPL(mbox_chan_txdone);
*/
void mbox_client_txdone(struct mbox_chan *chan, int r)
{
+ if (unlikely(chan->txdone_method & MBOX_TXDONE_BY_RETURN)) {
+ dev_err(chan->mbox->dev,
+ "TX-done notification on direct synchronous channel\n");
+ return;
+ }
+
if (unlikely(!(chan->txdone_method & MBOX_TXDONE_BY_ACK))) {
dev_err(chan->mbox->dev, "Client can't run the TX ticker\n");
return;
@@ -278,6 +290,9 @@ int mbox_send_message(struct mbox_chan *chan, void *mssg)
if (!chan || !chan->cl || mssg == MBOX_NO_MSG)
return -EINVAL;
+ if (chan->txdone_method & MBOX_TXDONE_BY_RETURN)
+ return -EOPNOTSUPP;
+
t = add_to_rbuf(chan, mssg);
if (t < 0) {
dev_err(chan->mbox->dev, "Try increasing MBOX_TX_QUEUE_LEN\n");
@@ -308,6 +323,43 @@ int mbox_send_message(struct mbox_chan *chan, void *mssg)
}
EXPORT_SYMBOL_GPL(mbox_send_message);
+/**
+ * mbox_send_message_sync - Send data and wait for transaction completion
+ * @chan: Mailbox channel assigned to this client
+ * @mssg: Client specific message typecasted
+ *
+ * For a channel bound with tx_sync, ask the controller to transmit @mssg and
+ * only return on completion. This function may sleep and must not be called
+ * from atomic context. @mssg must remain valid until this function returns.
+ *
+ * The direct synchronous path does not queue @mssg, does not use active_req,
+ * and does not use a TX-done notification. The client must serialize this
+ * function against mbox_free_channel().
+ *
+ * Return: 0 on success or a negative error code.
+ */
+int mbox_send_message_sync(struct mbox_chan *chan, void *mssg)
+{
+ int ret;
+
+ if (!chan || !chan->cl || mssg == MBOX_NO_MSG)
+ return -EINVAL;
+
+ if (!(chan->txdone_method & MBOX_TXDONE_BY_RETURN))
+ return -EOPNOTSUPP;
+
+ if (chan->cl->tx_prepare)
+ chan->cl->tx_prepare(chan->cl, mssg);
+ /* Try to submit a message to the MBOX controller synchonously */
+ ret = chan->mbox->ops->send_data_sync(chan, mssg);
+
+ if (chan->cl->tx_done)
+ chan->cl->tx_done(chan->cl, mssg, ret);
+
+ return ret;
+}
+EXPORT_SYMBOL_GPL(mbox_send_message_sync);
+
/**
* mbox_flush - flush a mailbox channel
* @chan: mailbox channel to flush
@@ -326,8 +378,11 @@ int mbox_flush(struct mbox_chan *chan, unsigned long timeout)
{
int ret;
+ if (chan->txdone_method & MBOX_TXDONE_BY_RETURN)
+ return -EOPNOTSUPP;
+
if (!chan->mbox->ops->flush)
- return -ENOTSUPP;
+ return -EOPNOTSUPP;
ret = chan->mbox->ops->flush(chan, timeout);
if (ret < 0)
@@ -343,7 +398,9 @@ static void mbox_clean_and_put_channel(struct mbox_chan *chan)
scoped_guard(spinlock_irqsave, &chan->lock) {
chan->cl = NULL;
chan->active_req = MBOX_NO_MSG;
- if (chan->txdone_method == MBOX_TXDONE_BY_ACK)
+ if (chan->txdone_method & MBOX_TXDONE_BY_RETURN)
+ chan->txdone_method &= ~MBOX_TXDONE_BY_RETURN;
+ else if (chan->txdone_method == MBOX_TXDONE_BY_ACK)
chan->txdone_method = MBOX_TXDONE_BY_POLL;
}
@@ -355,6 +412,14 @@ static int __mbox_bind_client(struct mbox_chan *chan, struct mbox_client *cl)
struct device *dev = cl->dev;
int ret;
+ if (cl->tx_sync) {
+ if (!chan->mbox->ops->send_data_sync)
+ return -EOPNOTSUPP;
+
+ if (cl->tx_block || cl->tx_tout || cl->knows_txdone)
+ return -EINVAL;
+ }
+
if (chan->cl || !try_module_get(chan->mbox->dev->driver->owner)) {
dev_err(dev, "%s: mailbox not free\n", __func__);
return -EBUSY;
@@ -380,6 +445,9 @@ static int __mbox_bind_client(struct mbox_chan *chan, struct mbox_client *cl)
}
}
+ if (cl->tx_sync)
+ chan->txdone_method |= MBOX_TXDONE_BY_RETURN;
+
return 0;
}
diff --git a/include/linux/mailbox_client.h b/include/linux/mailbox_client.h
index e5997120f45c..32b1d5ad3bfa 100644
--- a/include/linux/mailbox_client.h
+++ b/include/linux/mailbox_client.h
@@ -21,6 +21,7 @@ struct mbox_chan;
* @knows_txdone: If the client could run the TX state machine. Usually
* if the client receives some ACK packet for transmission.
* Unused if the controller already has TX_Done/RTR IRQ.
+ * @tx_sync: Bind the channel for mbox_send_message_sync().
* @rx_callback: Atomic callback to provide client the data received
* @tx_prepare: Atomic callback to ask client to prepare the payload
* before initiating the transmission if required.
@@ -31,6 +32,7 @@ struct mbox_client {
bool tx_block;
unsigned long tx_tout;
bool knows_txdone;
+ bool tx_sync;
void (*rx_callback)(struct mbox_client *cl, void *mssg);
void (*tx_prepare)(struct mbox_client *cl, void *mssg);
@@ -42,6 +44,7 @@ struct mbox_chan *mbox_request_channel_byname(struct mbox_client *cl,
const char *name);
struct mbox_chan *mbox_request_channel(struct mbox_client *cl, int index);
int mbox_send_message(struct mbox_chan *chan, void *mssg);
+int mbox_send_message_sync(struct mbox_chan *chan, void *mssg);
int mbox_flush(struct mbox_chan *chan, unsigned long timeout);
void mbox_client_txdone(struct mbox_chan *chan, int r); /* atomic */
bool mbox_client_peek_data(struct mbox_chan *chan); /* atomic */
diff --git a/include/linux/mailbox_controller.h b/include/linux/mailbox_controller.h
index 26a238a6f941..c7dc098324ef 100644
--- a/include/linux/mailbox_controller.h
+++ b/include/linux/mailbox_controller.h
@@ -18,6 +18,7 @@ struct mbox_chan;
#define MBOX_TXDONE_BY_IRQ BIT(0) /* controller has remote RTR irq */
#define MBOX_TXDONE_BY_POLL BIT(1) /* controller can read status of last TX */
#define MBOX_TXDONE_BY_ACK BIT(2) /* S/W ACK received by Client ticks the TX */
+#define MBOX_TXDONE_BY_RETURN BIT(3) /* TX completes by function return */
/**
* struct mbox_chan_ops - methods to control mailbox channels
@@ -28,6 +29,14 @@ struct mbox_chan;
* transmission of data is reported by the controller via
* mbox_chan_txdone (if it has some TX ACK irq). It must not
* sleep.
+ * @send_data_sync: The API asks the MBOX controller driver, in non-atomic
+ * context, to transmit a message on the bus and wait for the
+ * transaction to complete. It returns 0 if the transaction
+ * completed successfully or a negative error code otherwise.
+ * The controller must not call mbox_chan_txdone() or
+ * mbox_client_txdone() for this operation. Concurrent calls for one
+ * controller must support them, serialize them internally, or
+ * return -EBUSY for a conflicting transaction.
* @flush: Called when a client requests transmissions to be blocking but
* the context doesn't allow sleeping. Typically the controller
* will implement a busy loop waiting for the data to flush out.
@@ -53,6 +62,7 @@ struct mbox_chan;
*/
struct mbox_chan_ops {
int (*send_data)(struct mbox_chan *chan, void *data);
+ int (*send_data_sync)(struct mbox_chan *chan, void *data);
int (*flush)(struct mbox_chan *chan, unsigned long timeout);
int (*startup)(struct mbox_chan *chan);
void (*shutdown)(struct mbox_chan *chan);
--
2.43.0
next prev parent reply other threads:[~2026-09-30 15:06 UTC|newest]
Thread overview: 7+ messages / expand[flat|nested] mbox.gz Atom feed top
2026-09-30 15:02 [PATCH 0/4] Parallel message send using SBI MPXY Anup Patel
2026-09-30 15:02 ` [PATCH 1/4] RISC-V: Move common MPXY helper routines to arch/riscv Anup Patel
2026-09-30 15:30 ` sashiko-bot
2026-09-30 15:02 ` [PATCH 2/4] RISC-V: Factor-out per-hart MPXY shared-memory acquisition Anup Patel
2026-09-30 15:02 ` Anup Patel [this message]
2026-09-30 15:02 ` [PATCH 4/4] mailbox: riscv-sbi-mpxy: Move to send_data_sync() for sending messages Anup Patel
2026-09-30 15:38 ` sashiko-bot
Reply instructions:
You may reply publicly to this message via plain-text email
using any one of the following methods:
* Save the following mbox file, import it into your mail client,
and reply-to-all from there: mbox
Avoid top-posting and favor interleaved quoting:
https://en.wikipedia.org/wiki/Posting_style#Interleaved_style
* Reply using the --to, --cc, and --in-reply-to
switches of git-send-email(1):
git send-email \
--in-reply-to=20260930150213.799245-4-anup.patel@oss.qualcomm.com \
--to=anup.patel@oss.qualcomm.com \
--cc=amirreza.zarrabi@oss.qualcomm.com \
--cc=anup@brainfault.org \
--cc=atish.patra@linux.dev \
--cc=bmasney+clk@redhat.com \
--cc=hchauhan@ventanamicro.com \
--cc=jassisinghbrar@gmail.com \
--cc=jbrunet+clk@baylibre.com \
--cc=linux-clk@vger.kernel.org \
--cc=linux-kernel@vger.kernel.org \
--cc=linux-riscv@lists.infradead.org \
--cc=palmer@dabbelt.com \
--cc=pjw@kernel.org \
--cc=radu@rendec.net \
--cc=rahul@summations.net \
--cc=sboyd@kernel.org \
--cc=tglx@kernel.org \
/path/to/YOUR_REPLY
https://kernel.org/pub/software/scm/git/docs/git-send-email.html
* If your mail client supports setting the In-Reply-To header
via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line
before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox