Linux clock framework development
 help / color / mirror / Atom feed
* [PATCH 0/4] Parallel message send using SBI MPXY
@ 2026-09-30 15:02 Anup Patel
  2026-09-30 15:02 ` [PATCH 1/4] RISC-V: Move common MPXY helper routines to arch/riscv Anup Patel
                   ` (3 more replies)
  0 siblings, 4 replies; 7+ messages in thread
From: Anup Patel @ 2026-09-30 15:02 UTC (permalink / raw)
  To: Palmer Dabbelt, Paul Walmsley, Rahul Pathak, Stephen Boyd,
	Brian Masney, Jerome Brunet, Thomas Gleixner, Radu Rendec,
	Jassi Brar
  Cc: Himanshu Chauhan, Atish Patra, Anup Patel, Amirreza Zarrabi,
	linux-riscv, linux-kernel, linux-clk, Anup Patel

This series primarily extends mailbox framework and SBI MPXY mailbox
driver to allow sending messages in-parallel from multiple CPUs. It
also serves as perparatory series for the upcoming RISC-V ACPI EINJ
support and RISC-V TEE support.

These patches can also be found in the riscv_mpxy_imp_v1 branch at:
https://github.com/avpatel/linux.git

Amirreza Zarrabi (2):
  RISC-V: Factor-out per-hart MPXY shared-memory acquisition
  mailbox: add direct synchronous send support

Anup Patel (2):
  RISC-V: Move common MPXY helper routines to arch/riscv
  mailbox: riscv-sbi-mpxy: Move to send_data_sync() for sending messages

 arch/riscv/include/asm/sbi.h               |  84 +++-
 arch/riscv/kernel/Makefile                 |   2 +-
 arch/riscv/kernel/sbi_mpxy.c               | 381 +++++++++++++++++++
 drivers/clk/clk-rpmi.c                     |   2 +-
 drivers/irqchip/irq-riscv-rpmi-sysmsi.c    |   2 +-
 drivers/mailbox/mailbox.c                  |  72 +++-
 drivers/mailbox/riscv-sbi-mpxy-mbox.c      | 423 +++------------------
 include/linux/mailbox/riscv-rpmi-message.h |  18 +-
 include/linux/mailbox_client.h             |   3 +
 include/linux/mailbox_controller.h         |  10 +
 10 files changed, 605 insertions(+), 392 deletions(-)
 create mode 100644 arch/riscv/kernel/sbi_mpxy.c

-- 
2.43.0


^ permalink raw reply	[flat|nested] 7+ messages in thread

* [PATCH 1/4] RISC-V: Move common MPXY helper routines to arch/riscv
  2026-09-30 15:02 [PATCH 0/4] Parallel message send using SBI MPXY Anup Patel
@ 2026-09-30 15:02 ` 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
                   ` (2 subsequent siblings)
  3 siblings, 1 reply; 7+ messages in thread
From: Anup Patel @ 2026-09-30 15:02 UTC (permalink / raw)
  To: Palmer Dabbelt, Paul Walmsley, Rahul Pathak, Stephen Boyd,
	Brian Masney, Jerome Brunet, Thomas Gleixner, Radu Rendec,
	Jassi Brar
  Cc: Himanshu Chauhan, Atish Patra, Anup Patel, Amirreza Zarrabi,
	linux-riscv, linux-kernel, linux-clk, Anup Patel,
	Himanshu Chauhan

There are upcoming kernel changes (such as RISC-V EINJ FFH support)
where the MPXY channel_id is known but the Linux mailbox channel
instance is not available. For such cases, the kernel will directly
do SBI MPXY calls bypassing the Linux mailbox framework and share
the MPXY shared memory with the Linux SBI MPXY mailbox driver.

To support the above, move the common MPXY helper routines and
MPXY shared memory management from Linux SBI MPXY mailbox driver
to arch/riscv.

Co-developed-by: Himanshu Chauhan <himanshu.chauhan@oss.qualcomm.com>
Signed-off-by: Himanshu Chauhan <himanshu.chauhan@oss.qualcomm.com>
Signed-off-by: Anup Patel <anup.patel@oss.qualcomm.com>
---
 arch/riscv/include/asm/sbi.h          |  84 +++++-
 arch/riscv/kernel/Makefile            |   2 +-
 arch/riscv/kernel/sbi_mpxy.c          | 340 +++++++++++++++++++++++
 drivers/mailbox/riscv-sbi-mpxy-mbox.c | 386 +++-----------------------
 4 files changed, 458 insertions(+), 354 deletions(-)
 create mode 100644 arch/riscv/kernel/sbi_mpxy.c

diff --git a/arch/riscv/include/asm/sbi.h b/arch/riscv/include/asm/sbi.h
index 5725e0ca4dda..c41e1af31a45 100644
--- a/arch/riscv/include/asm/sbi.h
+++ b/arch/riscv/include/asm/sbi.h
@@ -624,6 +624,37 @@ static inline int sbi_fwft_set_online_cpus(u32 feature, unsigned long value,
 	return sbi_fwft_set_cpumask(cpu_online_mask, feature, value, flags);
 }
 
+/* SBI MPXY notification data in shared memory */
+struct sbi_mpxy_notification_data {
+	/* Remaining number of notification events */
+	__le32 remaining;
+	/* Number of notification events returned */
+	__le32 returned;
+	/* Number of notification events lost */
+	__le32 lost;
+	/* Reserved for future use */
+	__le32 reserved;
+	/* Returned channel id array */
+	u8 events_data[];
+};
+
+unsigned long sbi_mpxy_shmem_size(void);
+int sbi_mpxy_get_channel_count(u32 *channel_count);
+int sbi_mpxy_get_channel_ids(u32 channel_count, u32 *channel_ids);
+int sbi_mpxy_read_attrs(u32 channel_id, u32 base_attrid, u32 attr_count,
+			u32 *attrs_buf);
+int sbi_mpxy_write_attrs(u32 channel_id, u32 base_attrid, u32 attr_count,
+			 u32 *attrs_buf);
+int sbi_mpxy_send_message_with_resp(u32 channel_id, u32 msg_id,
+				    void *tx, unsigned long tx_len,
+				    void *rx, unsigned long max_rx_len,
+				    unsigned long *rx_len);
+int sbi_mpxy_send_message_without_resp(u32 channel_id, u32 msg_id,
+				       void *tx, unsigned long tx_len);
+int sbi_mpxy_get_notifications(u32 channel_id,
+			       struct sbi_mpxy_notification_data *notif_data,
+			       unsigned long *events_data_len);
+
 /* Check if current SBI specification version is 0.1 or not */
 static inline int sbi_spec_is_0_1(void)
 {
@@ -685,7 +716,58 @@ int sbi_debug_console_read(char *bytes, unsigned int num_bytes);
 
 #else /* CONFIG_RISCV_SBI */
 static inline int sbi_remote_fence_i(const struct cpumask *cpu_mask) { return -1; }
-static inline void sbi_init(void) {}
+static inline void sbi_init(void)
+{
+}
+
+static inline unsigned long sbi_mpxy_shmem_size(void)
+{
+	return 0;
+}
+
+static inline int sbi_mpxy_get_channel_count(u32 *channel_count)
+{
+	return -ENODEV;
+}
+
+static inline int sbi_mpxy_get_channel_ids(u32 channel_count, u32 *channel_ids)
+{
+	return -ENODEV;
+}
+
+int sbi_mpxy_read_attrs(u32 channel_id, u32 base_attrid, u32 attr_count,
+			u32 *attrs_buf)
+{
+	return -ENODEV;
+}
+
+int sbi_mpxy_write_attrs(u32 channel_id, u32 base_attrid, u32 attr_count,
+			 u32 *attrs_buf)
+{
+	return -ENODEV;
+}
+
+int sbi_mpxy_send_message_with_resp(u32 channel_id, u32 msg_id,
+				    void *tx, unsigned long tx_len,
+				    void *rx, unsigned long max_rx_len,
+				    unsigned long *rx_len)
+{
+	return -ENODEV;
+}
+
+int sbi_mpxy_send_message_without_resp(u32 channel_id, u32 msg_id,
+				       void *tx, unsigned long tx_len)
+{
+	return -ENODEV;
+}
+
+int sbi_mpxy_get_notifications(u32 channel_id,
+			       struct sbi_mpxy_notification_data *notif_data,
+			       unsigned long *events_data_len)
+{
+	return -ENODEV;
+}
+
 #endif /* CONFIG_RISCV_SBI */
 
 unsigned long riscv_get_mvendorid(void);
diff --git a/arch/riscv/kernel/Makefile b/arch/riscv/kernel/Makefile
index 9bcce9cad256..053d4353d40e 100644
--- a/arch/riscv/kernel/Makefile
+++ b/arch/riscv/kernel/Makefile
@@ -101,7 +101,7 @@ obj-$(CONFIG_DYNAMIC_FTRACE)	+= mcount-dyn.o
 
 obj-$(CONFIG_PERF_EVENTS)	+= perf_callchain.o
 obj-$(CONFIG_HAVE_PERF_REGS)	+= perf_regs.o
-obj-$(CONFIG_RISCV_SBI)		+= sbi.o sbi_ecall.o
+obj-$(CONFIG_RISCV_SBI)		+= sbi.o sbi_ecall.o sbi_mpxy.o
 ifeq ($(CONFIG_RISCV_SBI), y)
 obj-$(CONFIG_SMP)		+= sbi-ipi.o
 obj-$(CONFIG_SMP) += cpu_ops_sbi.o
diff --git a/arch/riscv/kernel/sbi_mpxy.c b/arch/riscv/kernel/sbi_mpxy.c
new file mode 100644
index 000000000000..17a2cee21311
--- /dev/null
+++ b/arch/riscv/kernel/sbi_mpxy.c
@@ -0,0 +1,340 @@
+// SPDX-License-Identifier: GPL-2.0-only
+/*
+ * Common SBI MPXY access library.
+ *
+ * Copyright (c) 2026 Qualcomm Technologies, Inc.
+ */
+
+#define pr_fmt(fmt) "riscv: " fmt
+#include <linux/cpu.h>
+#include <linux/init.h>
+#include <linux/mm.h>
+#include <linux/percpu.h>
+#include <linux/printk.h>
+#include <linux/string.h>
+#include <linux/types.h>
+#include <asm/byteorder.h>
+#include <asm/sbi.h>
+
+/* SBI MPXY channel IDs data in shared memory */
+struct sbi_mpxy_channel_ids_data {
+	/* Remaining number of channel ids */
+	__le32 remaining;
+	/* Returned channel ids in current function call */
+	__le32 returned;
+	/* Returned channel id array */
+	__le32 channel_array[];
+};
+
+/* MPXY Per-CPU or local context */
+struct mpxy_local {
+	/* Shared memory base address */
+	void *shmem;
+	/* Shared memory physical address */
+	phys_addr_t shmem_phys_addr;
+	/* Flag representing whether shared memory is active or not */
+	bool shmem_active;
+};
+
+static DEFINE_PER_CPU(struct mpxy_local, mpxy_local);
+static unsigned long mpxy_shmem_size;
+static bool mpxy_shmem_init_done;
+
+unsigned long sbi_mpxy_shmem_size(void)
+{
+	if (!mpxy_shmem_init_done)
+		return 0;
+	return mpxy_shmem_size;
+}
+EXPORT_SYMBOL_GPL(sbi_mpxy_shmem_size);
+
+int sbi_mpxy_get_channel_count(u32 *channel_count)
+{
+	struct mpxy_local *mpxy = this_cpu_ptr(&mpxy_local);
+	struct sbi_mpxy_channel_ids_data *sdata = mpxy->shmem;
+	u32 remaining, returned;
+	struct sbiret sret;
+
+	if (!mpxy->shmem_active)
+		return -ENODEV;
+	if (!channel_count)
+		return -EINVAL;
+
+	get_cpu();
+
+	/* Get the remaining and returned fields to calculate total */
+	sret = sbi_ecall(SBI_EXT_MPXY, SBI_EXT_MPXY_GET_CHANNEL_IDS,
+			 0, 0, 0, 0, 0, 0);
+	if (sret.error)
+		goto err_put_cpu;
+
+	remaining = le32_to_cpu(sdata->remaining);
+	returned = le32_to_cpu(sdata->returned);
+	*channel_count = remaining + returned;
+
+err_put_cpu:
+	put_cpu();
+	return sbi_err_map_linux_errno(sret.error);
+}
+EXPORT_SYMBOL_GPL(sbi_mpxy_get_channel_count);
+
+int sbi_mpxy_get_channel_ids(u32 channel_count, u32 *channel_ids)
+{
+	struct mpxy_local *mpxy = this_cpu_ptr(&mpxy_local);
+	struct sbi_mpxy_channel_ids_data *sdata = mpxy->shmem;
+	u32 remaining, returned, count, start_index = 0;
+	struct sbiret sret;
+
+	if (!mpxy->shmem_active)
+		return -ENODEV;
+	if (!channel_count || !channel_ids)
+		return -EINVAL;
+
+	get_cpu();
+
+	do {
+		sret = sbi_ecall(SBI_EXT_MPXY, SBI_EXT_MPXY_GET_CHANNEL_IDS,
+				 start_index, 0, 0, 0, 0, 0);
+		if (sret.error)
+			goto err_put_cpu;
+
+		remaining = le32_to_cpu(sdata->remaining);
+		returned = le32_to_cpu(sdata->returned);
+
+		count = returned < (channel_count - start_index) ?
+			returned : (channel_count - start_index);
+		memcpy_from_le32(&channel_ids[start_index], sdata->channel_array, count);
+		start_index += count;
+	} while (remaining && start_index < channel_count);
+
+err_put_cpu:
+	put_cpu();
+	return sbi_err_map_linux_errno(sret.error);
+}
+EXPORT_SYMBOL_GPL(sbi_mpxy_get_channel_ids);
+
+int sbi_mpxy_read_attrs(u32 channel_id, u32 base_attrid, u32 attr_count,
+			u32 *attrs_buf)
+{
+	struct mpxy_local *mpxy = this_cpu_ptr(&mpxy_local);
+	struct sbiret sret;
+
+	if (!mpxy->shmem_active)
+		return -ENODEV;
+	if (!attr_count || !attrs_buf)
+		return -EINVAL;
+
+	get_cpu();
+
+	sret = sbi_ecall(SBI_EXT_MPXY, SBI_EXT_MPXY_READ_ATTRS,
+			 channel_id, base_attrid, attr_count, 0, 0, 0);
+	if (sret.error)
+		goto err_put_cpu;
+
+	memcpy_from_le32(attrs_buf, (__le32 *)mpxy->shmem, attr_count);
+
+err_put_cpu:
+	put_cpu();
+	return sbi_err_map_linux_errno(sret.error);
+}
+EXPORT_SYMBOL_GPL(sbi_mpxy_read_attrs);
+
+int sbi_mpxy_write_attrs(u32 channel_id, u32 base_attrid, u32 attr_count,
+			 u32 *attrs_buf)
+{
+	struct mpxy_local *mpxy = this_cpu_ptr(&mpxy_local);
+	struct sbiret sret;
+
+	if (!mpxy->shmem_active)
+		return -ENODEV;
+	if (!attr_count || !attrs_buf)
+		return -EINVAL;
+
+	get_cpu();
+
+	memcpy_to_le32((__le32 *)mpxy->shmem, attrs_buf, attr_count);
+	sret = sbi_ecall(SBI_EXT_MPXY, SBI_EXT_MPXY_WRITE_ATTRS,
+			 channel_id, base_attrid, attr_count, 0, 0, 0);
+
+	put_cpu();
+	return sbi_err_map_linux_errno(sret.error);
+}
+EXPORT_SYMBOL_GPL(sbi_mpxy_write_attrs);
+
+int sbi_mpxy_send_message_with_resp(u32 channel_id, u32 msg_id,
+				    void *tx, unsigned long tx_len,
+				    void *rx, unsigned long max_rx_len,
+				    unsigned long *rx_len)
+{
+	struct mpxy_local *mpxy = this_cpu_ptr(&mpxy_local);
+	unsigned long rx_bytes;
+	struct sbiret sret;
+
+	if (!mpxy->shmem_active)
+		return -ENODEV;
+	if (!tx && tx_len)
+		return -EINVAL;
+
+	get_cpu();
+
+	/* Message protocols allowed to have no data in messages */
+	if (tx_len)
+		memcpy(mpxy->shmem, tx, tx_len);
+
+	sret = sbi_ecall(SBI_EXT_MPXY, SBI_EXT_MPXY_SEND_MSG_WITH_RESP,
+			 channel_id, msg_id, tx_len, 0, 0, 0);
+	if (rx && !sret.error) {
+		rx_bytes = sret.value;
+		if (rx_bytes > max_rx_len) {
+			put_cpu();
+			return -ENOSPC;
+		}
+
+		memcpy(rx, mpxy->shmem, rx_bytes);
+		if (rx_len)
+			*rx_len = rx_bytes;
+	}
+
+	put_cpu();
+	return sbi_err_map_linux_errno(sret.error);
+}
+EXPORT_SYMBOL_GPL(sbi_mpxy_send_message_with_resp);
+
+int sbi_mpxy_send_message_without_resp(u32 channel_id, u32 msg_id,
+				       void *tx, unsigned long tx_len)
+{
+	struct mpxy_local *mpxy = this_cpu_ptr(&mpxy_local);
+	struct sbiret sret;
+
+	if (!mpxy->shmem_active)
+		return -ENODEV;
+	if (!tx && tx_len)
+		return -EINVAL;
+
+	get_cpu();
+
+	/* Message protocols allowed to have no data in messages */
+	if (tx_len)
+		memcpy(mpxy->shmem, tx, tx_len);
+
+	sret = sbi_ecall(SBI_EXT_MPXY, SBI_EXT_MPXY_SEND_MSG_WITHOUT_RESP,
+			 channel_id, msg_id, tx_len, 0, 0, 0);
+
+	put_cpu();
+	return sbi_err_map_linux_errno(sret.error);
+}
+EXPORT_SYMBOL_GPL(sbi_mpxy_send_message_without_resp);
+
+int sbi_mpxy_get_notifications(u32 channel_id,
+			       struct sbi_mpxy_notification_data *notif_data,
+			       unsigned long *events_data_len)
+{
+	struct mpxy_local *mpxy = this_cpu_ptr(&mpxy_local);
+	struct sbiret sret;
+
+	if (!mpxy->shmem_active)
+		return -ENODEV;
+	if (!notif_data || !events_data_len)
+		return -EINVAL;
+
+	get_cpu();
+
+	sret = sbi_ecall(SBI_EXT_MPXY, SBI_EXT_MPXY_GET_NOTIFICATION_EVENTS,
+			 channel_id, 0, 0, 0, 0, 0);
+	if (sret.error)
+		goto err_put_cpu;
+	if (sret.value < 0 || mpxy_shmem_size < sizeof(*notif_data) ||
+	    sret.value > mpxy_shmem_size - sizeof(*notif_data)) {
+		put_cpu();
+		return -EOVERFLOW;
+	}
+
+	memcpy(notif_data, mpxy->shmem, sret.value + sizeof(*notif_data));
+	*events_data_len = sret.value;
+
+err_put_cpu:
+	put_cpu();
+	return sbi_err_map_linux_errno(sret.error);
+}
+EXPORT_SYMBOL_GPL(sbi_mpxy_get_notifications);
+
+static int mpxy_get_shmem_size(unsigned long *shmem_size)
+{
+	struct sbiret sret;
+
+	sret = sbi_ecall(SBI_EXT_MPXY, SBI_EXT_MPXY_GET_SHMEM_SIZE,
+			 0, 0, 0, 0, 0, 0);
+	if (sret.error)
+		return sbi_err_map_linux_errno(sret.error);
+	if (shmem_size)
+		*shmem_size = sret.value;
+	return 0;
+}
+
+static int mpxy_setup_shmem(unsigned int cpu)
+{
+	struct page *shmem_page;
+	struct mpxy_local *mpxy;
+	struct sbiret sret;
+
+	mpxy = per_cpu_ptr(&mpxy_local, cpu);
+	if (mpxy->shmem_active)
+		return 0;
+
+	shmem_page = alloc_pages(GFP_KERNEL | __GFP_ZERO, get_order(mpxy_shmem_size));
+	if (!shmem_page)
+		return -ENOMEM;
+
+	/*
+	 * Linux setup of shmem is done in mpxy OVERWRITE mode.
+	 * flags[1:0] = 00b
+	 */
+	sret = sbi_ecall(SBI_EXT_MPXY, SBI_EXT_MPXY_SET_SHMEM,
+			 page_to_phys(shmem_page), 0, 0, 0, 0, 0);
+	if (sret.error) {
+		free_pages((unsigned long)page_to_virt(shmem_page),
+			   get_order(mpxy_shmem_size));
+		return sbi_err_map_linux_errno(sret.error);
+	}
+
+	mpxy->shmem = page_to_virt(shmem_page);
+	mpxy->shmem_phys_addr = page_to_phys(shmem_page);
+	mpxy->shmem_active = true;
+
+	return 0;
+}
+
+static int __init sbi_mpxy_init(void)
+{
+	int rc;
+
+	/* Skip quietly when MPXY extension is not supported. */
+	if (sbi_spec_version < sbi_mk_version(3, 0) ||
+	    !sbi_probe_extension(SBI_EXT_MPXY))
+		return 0;
+	pr_info("SBI MPXY extension detected\n");
+
+	/* Find-out shared memory size */
+	rc = mpxy_get_shmem_size(&mpxy_shmem_size);
+	if (rc) {
+		pr_err("failed to get MPXY shared memory size\n");
+		return rc;
+	}
+
+	/*
+	 * Setup MPXY shared memory on each CPU
+	 *
+	 * Note: Don't cleanup MPXY shared memory upon CPU power-down
+	 * because the RPMI System MSI irqchip driver needs it to be
+	 * available when migrating IRQs in CPU power-down path.
+	 */
+	rc = cpuhp_setup_state(CPUHP_AP_ONLINE_DYN, "riscv/sbi-mpxy-shmem",
+			       mpxy_setup_shmem, NULL);
+	if (rc < 0)
+		return rc;
+
+	/* Mark as MPXY shared memory initialization done */
+	mpxy_shmem_init_done = true;
+	return 0;
+}
+arch_initcall(sbi_mpxy_init);
diff --git a/drivers/mailbox/riscv-sbi-mpxy-mbox.c b/drivers/mailbox/riscv-sbi-mpxy-mbox.c
index ea69c6b6b4f9..cba95b8406ee 100644
--- a/drivers/mailbox/riscv-sbi-mpxy-mbox.c
+++ b/drivers/mailbox/riscv-sbi-mpxy-mbox.c
@@ -17,7 +17,6 @@
 #include <linux/module.h>
 #include <linux/msi.h>
 #include <linux/of_irq.h>
-#include <linux/percpu.h>
 #include <linux/platform_device.h>
 #include <linux/smp.h>
 #include <linux/string.h>
@@ -85,295 +84,6 @@ struct sbi_mpxy_rpmi_channel_attrs {
 	u32 impl_version;
 };
 
-/* SBI MPXY channel IDs data in shared memory */
-struct sbi_mpxy_channel_ids_data {
-	/* Remaining number of channel ids */
-	__le32 remaining;
-	/* Returned channel ids in current function call */
-	__le32 returned;
-	/* Returned channel id array */
-	__le32 channel_array[];
-};
-
-/* SBI MPXY notification data in shared memory */
-struct sbi_mpxy_notification_data {
-	/* Remaining number of notification events */
-	__le32 remaining;
-	/* Number of notification events returned */
-	__le32 returned;
-	/* Number of notification events lost */
-	__le32 lost;
-	/* Reserved for future use */
-	__le32 reserved;
-	/* Returned channel id array */
-	u8 events_data[];
-};
-
-/* ====== MPXY data structures & helper routines ====== */
-
-/* MPXY Per-CPU or local context */
-struct mpxy_local {
-	/* Shared memory base address */
-	void *shmem;
-	/* Shared memory physical address */
-	phys_addr_t shmem_phys_addr;
-	/* Flag representing whether shared memory is active or not */
-	bool shmem_active;
-};
-
-static DEFINE_PER_CPU(struct mpxy_local, mpxy_local);
-static unsigned long mpxy_shmem_size;
-static bool mpxy_shmem_init_done;
-
-static int mpxy_get_channel_count(u32 *channel_count)
-{
-	struct mpxy_local *mpxy = this_cpu_ptr(&mpxy_local);
-	struct sbi_mpxy_channel_ids_data *sdata = mpxy->shmem;
-	u32 remaining, returned;
-	struct sbiret sret;
-
-	if (!mpxy->shmem_active)
-		return -ENODEV;
-	if (!channel_count)
-		return -EINVAL;
-
-	get_cpu();
-
-	/* Get the remaining and returned fields to calculate total */
-	sret = sbi_ecall(SBI_EXT_MPXY, SBI_EXT_MPXY_GET_CHANNEL_IDS,
-			 0, 0, 0, 0, 0, 0);
-	if (sret.error)
-		goto err_put_cpu;
-
-	remaining = le32_to_cpu(sdata->remaining);
-	returned = le32_to_cpu(sdata->returned);
-	*channel_count = remaining + returned;
-
-err_put_cpu:
-	put_cpu();
-	return sbi_err_map_linux_errno(sret.error);
-}
-
-static int mpxy_get_channel_ids(u32 channel_count, u32 *channel_ids)
-{
-	struct mpxy_local *mpxy = this_cpu_ptr(&mpxy_local);
-	struct sbi_mpxy_channel_ids_data *sdata = mpxy->shmem;
-	u32 remaining, returned, count, start_index = 0;
-	struct sbiret sret;
-
-	if (!mpxy->shmem_active)
-		return -ENODEV;
-	if (!channel_count || !channel_ids)
-		return -EINVAL;
-
-	get_cpu();
-
-	do {
-		sret = sbi_ecall(SBI_EXT_MPXY, SBI_EXT_MPXY_GET_CHANNEL_IDS,
-				 start_index, 0, 0, 0, 0, 0);
-		if (sret.error)
-			goto err_put_cpu;
-
-		remaining = le32_to_cpu(sdata->remaining);
-		returned = le32_to_cpu(sdata->returned);
-
-		count = returned < (channel_count - start_index) ?
-			returned : (channel_count - start_index);
-		memcpy_from_le32(&channel_ids[start_index], sdata->channel_array, count);
-		start_index += count;
-	} while (remaining && start_index < channel_count);
-
-err_put_cpu:
-	put_cpu();
-	return sbi_err_map_linux_errno(sret.error);
-}
-
-static int mpxy_read_attrs(u32 channel_id, u32 base_attrid, u32 attr_count,
-			   u32 *attrs_buf)
-{
-	struct mpxy_local *mpxy = this_cpu_ptr(&mpxy_local);
-	struct sbiret sret;
-
-	if (!mpxy->shmem_active)
-		return -ENODEV;
-	if (!attr_count || !attrs_buf)
-		return -EINVAL;
-
-	get_cpu();
-
-	sret = sbi_ecall(SBI_EXT_MPXY, SBI_EXT_MPXY_READ_ATTRS,
-			 channel_id, base_attrid, attr_count, 0, 0, 0);
-	if (sret.error)
-		goto err_put_cpu;
-
-	memcpy_from_le32(attrs_buf, (__le32 *)mpxy->shmem, attr_count);
-
-err_put_cpu:
-	put_cpu();
-	return sbi_err_map_linux_errno(sret.error);
-}
-
-static int mpxy_write_attrs(u32 channel_id, u32 base_attrid, u32 attr_count,
-			    u32 *attrs_buf)
-{
-	struct mpxy_local *mpxy = this_cpu_ptr(&mpxy_local);
-	struct sbiret sret;
-
-	if (!mpxy->shmem_active)
-		return -ENODEV;
-	if (!attr_count || !attrs_buf)
-		return -EINVAL;
-
-	get_cpu();
-
-	memcpy_to_le32((__le32 *)mpxy->shmem, attrs_buf, attr_count);
-	sret = sbi_ecall(SBI_EXT_MPXY, SBI_EXT_MPXY_WRITE_ATTRS,
-			 channel_id, base_attrid, attr_count, 0, 0, 0);
-
-	put_cpu();
-	return sbi_err_map_linux_errno(sret.error);
-}
-
-static int mpxy_send_message_with_resp(u32 channel_id, u32 msg_id,
-				       void *tx, unsigned long tx_len,
-				       void *rx, unsigned long max_rx_len,
-				       unsigned long *rx_len)
-{
-	struct mpxy_local *mpxy = this_cpu_ptr(&mpxy_local);
-	unsigned long rx_bytes;
-	struct sbiret sret;
-
-	if (!mpxy->shmem_active)
-		return -ENODEV;
-	if (!tx && tx_len)
-		return -EINVAL;
-
-	get_cpu();
-
-	/* Message protocols allowed to have no data in messages */
-	if (tx_len)
-		memcpy(mpxy->shmem, tx, tx_len);
-
-	sret = sbi_ecall(SBI_EXT_MPXY, SBI_EXT_MPXY_SEND_MSG_WITH_RESP,
-			 channel_id, msg_id, tx_len, 0, 0, 0);
-	if (rx && !sret.error) {
-		rx_bytes = sret.value;
-		if (rx_bytes > max_rx_len) {
-			put_cpu();
-			return -ENOSPC;
-		}
-
-		memcpy(rx, mpxy->shmem, rx_bytes);
-		if (rx_len)
-			*rx_len = rx_bytes;
-	}
-
-	put_cpu();
-	return sbi_err_map_linux_errno(sret.error);
-}
-
-static int mpxy_send_message_without_resp(u32 channel_id, u32 msg_id,
-					  void *tx, unsigned long tx_len)
-{
-	struct mpxy_local *mpxy = this_cpu_ptr(&mpxy_local);
-	struct sbiret sret;
-
-	if (!mpxy->shmem_active)
-		return -ENODEV;
-	if (!tx && tx_len)
-		return -EINVAL;
-
-	get_cpu();
-
-	/* Message protocols allowed to have no data in messages */
-	if (tx_len)
-		memcpy(mpxy->shmem, tx, tx_len);
-
-	sret = sbi_ecall(SBI_EXT_MPXY, SBI_EXT_MPXY_SEND_MSG_WITHOUT_RESP,
-			 channel_id, msg_id, tx_len, 0, 0, 0);
-
-	put_cpu();
-	return sbi_err_map_linux_errno(sret.error);
-}
-
-static int mpxy_get_notifications(u32 channel_id,
-				  struct sbi_mpxy_notification_data *notif_data,
-				  unsigned long *events_data_len)
-{
-	struct mpxy_local *mpxy = this_cpu_ptr(&mpxy_local);
-	struct sbiret sret;
-
-	if (!mpxy->shmem_active)
-		return -ENODEV;
-	if (!notif_data || !events_data_len)
-		return -EINVAL;
-
-	get_cpu();
-
-	sret = sbi_ecall(SBI_EXT_MPXY, SBI_EXT_MPXY_GET_NOTIFICATION_EVENTS,
-			 channel_id, 0, 0, 0, 0, 0);
-	if (sret.error)
-		goto err_put_cpu;
-	if (sret.value < 0 || mpxy_shmem_size < sizeof(*notif_data) ||
-	    sret.value > mpxy_shmem_size - sizeof(*notif_data)) {
-		put_cpu();
-		return -EOVERFLOW;
-	}
-
-	memcpy(notif_data, mpxy->shmem, sret.value + sizeof(*notif_data));
-	*events_data_len = sret.value;
-
-err_put_cpu:
-	put_cpu();
-	return sbi_err_map_linux_errno(sret.error);
-}
-
-static int mpxy_get_shmem_size(unsigned long *shmem_size)
-{
-	struct sbiret sret;
-
-	sret = sbi_ecall(SBI_EXT_MPXY, SBI_EXT_MPXY_GET_SHMEM_SIZE,
-			 0, 0, 0, 0, 0, 0);
-	if (sret.error)
-		return sbi_err_map_linux_errno(sret.error);
-	if (shmem_size)
-		*shmem_size = sret.value;
-	return 0;
-}
-
-static int mpxy_setup_shmem(unsigned int cpu)
-{
-	struct page *shmem_page;
-	struct mpxy_local *mpxy;
-	struct sbiret sret;
-
-	mpxy = per_cpu_ptr(&mpxy_local, cpu);
-	if (mpxy->shmem_active)
-		return 0;
-
-	shmem_page = alloc_pages(GFP_KERNEL | __GFP_ZERO, get_order(mpxy_shmem_size));
-	if (!shmem_page)
-		return -ENOMEM;
-
-	/*
-	 * Linux setup of shmem is done in mpxy OVERWRITE mode.
-	 * flags[1:0] = 00b
-	 */
-	sret = sbi_ecall(SBI_EXT_MPXY, SBI_EXT_MPXY_SET_SHMEM,
-			 page_to_phys(shmem_page), 0, 0, 0, 0, 0);
-	if (sret.error) {
-		free_pages((unsigned long)page_to_virt(shmem_page),
-			   get_order(mpxy_shmem_size));
-		return sbi_err_map_linux_errno(sret.error);
-	}
-
-	mpxy->shmem = page_to_virt(shmem_page);
-	mpxy->shmem_phys_addr = page_to_phys(shmem_page);
-	mpxy->shmem_active = true;
-
-	return 0;
-}
-
 /* ====== MPXY mailbox data structures ====== */
 
 /* MPXY mailbox channel */
@@ -447,13 +157,13 @@ static void mpxy_mbox_send_rpmi_data(struct mpxy_mbox_channel *mchan,
 			msg->error = -EIO;
 			break;
 		}
-		msg->error = mpxy_send_message_with_resp(mchan->channel_id,
-							 msg->data.service_id,
-							 msg->data.request,
-							 msg->data.request_len,
-							 msg->data.response,
-							 msg->data.max_response_len,
-							 &msg->data.out_response_len);
+		msg->error = sbi_mpxy_send_message_with_resp(mchan->channel_id,
+							     msg->data.service_id,
+							     msg->data.request,
+							     msg->data.request_len,
+							     msg->data.response,
+							     msg->data.max_response_len,
+							     &msg->data.out_response_len);
 		break;
 	case RPMI_MBOX_MSG_TYPE_SEND_WITHOUT_RESPONSE:
 		if ((!msg->data.request && msg->data.request_len) ||
@@ -465,10 +175,10 @@ static void mpxy_mbox_send_rpmi_data(struct mpxy_mbox_channel *mchan,
 			msg->error = -EIO;
 			break;
 		}
-		msg->error = mpxy_send_message_without_resp(mchan->channel_id,
-							    msg->data.service_id,
-							    msg->data.request,
-							    msg->data.request_len);
+		msg->error = sbi_mpxy_send_message_without_resp(mchan->channel_id,
+								msg->data.service_id,
+								msg->data.request,
+								msg->data.request_len);
 		break;
 	default:
 		msg->error = -EOPNOTSUPP;
@@ -504,10 +214,10 @@ static void mpxy_mbox_peek_rpmi_data(struct mbox_chan *chan,
 
 static int mpxy_mbox_read_rpmi_attrs(struct mpxy_mbox_channel *mchan)
 {
-	return mpxy_read_attrs(mchan->channel_id,
-			       SBI_MPXY_ATTR_MSGPROTO_ATTR_START,
-			       sizeof(mchan->rpmi_attrs) / sizeof(u32),
-			       (u32 *)&mchan->rpmi_attrs);
+	return sbi_mpxy_read_attrs(mchan->channel_id,
+				   SBI_MPXY_ATTR_MSGPROTO_ATTR_START,
+				   sizeof(mchan->rpmi_attrs) / sizeof(u32),
+				   (u32 *)&mchan->rpmi_attrs);
 }
 
 /* ====== MPXY mailbox callbacks ====== */
@@ -536,7 +246,7 @@ static bool mpxy_mbox_peek_data(struct mbox_chan *chan)
 		return false;
 
 	do {
-		rc = mpxy_get_notifications(mchan->channel_id, notif, &data_len);
+		rc = sbi_mpxy_get_notifications(mchan->channel_id, notif, &data_len);
 		if (rc || !data_len)
 			break;
 
@@ -580,8 +290,8 @@ static int mpxy_mbox_setup_msi(struct mbox_chan *chan,
 
 	/* Enable channel MSI control */
 	mchan->attrs.msi_control = 1;
-	rc = mpxy_write_attrs(mchan->channel_id, SBI_MPXY_ATTR_MSI_CONTROL,
-			      1, &mchan->attrs.msi_control);
+	rc = sbi_mpxy_write_attrs(mchan->channel_id, SBI_MPXY_ATTR_MSI_CONTROL,
+				  1, &mchan->attrs.msi_control);
 	if (rc) {
 		dev_err(dev, "enable MSI control failed for MPXY channel 0x%x\n",
 			mchan->channel_id);
@@ -609,8 +319,8 @@ static void mpxy_mbox_cleanup_msi(struct mbox_chan *chan,
 
 	/* Disable channel MSI control */
 	mchan->attrs.msi_control = 0;
-	rc = mpxy_write_attrs(mchan->channel_id, SBI_MPXY_ATTR_MSI_CONTROL,
-			      1, &mchan->attrs.msi_control);
+	rc = sbi_mpxy_write_attrs(mchan->channel_id, SBI_MPXY_ATTR_MSI_CONTROL,
+				  1, &mchan->attrs.msi_control);
 	if (rc) {
 		dev_err(dev, "disable MSI control failed for MPXY channel 0x%x\n",
 			mchan->channel_id);
@@ -635,8 +345,8 @@ static int mpxy_mbox_setup_events(struct mpxy_mbox_channel *mchan)
 
 	/* Enable channel events state */
 	mchan->attrs.events_state_ctrl = 1;
-	rc = mpxy_write_attrs(mchan->channel_id, SBI_MPXY_ATTR_EVENTS_STATE_CONTROL,
-			      1, &mchan->attrs.events_state_ctrl);
+	rc = sbi_mpxy_write_attrs(mchan->channel_id, SBI_MPXY_ATTR_EVENTS_STATE_CONTROL,
+				  1, &mchan->attrs.events_state_ctrl);
 	if (rc) {
 		dev_err(dev, "enable events state failed for MPXY channel 0x%x\n",
 			mchan->channel_id);
@@ -662,8 +372,8 @@ static void mpxy_mbox_cleanup_events(struct mpxy_mbox_channel *mchan)
 
 	/* Disable channel events state */
 	mchan->attrs.events_state_ctrl = 0;
-	rc = mpxy_write_attrs(mchan->channel_id, SBI_MPXY_ATTR_EVENTS_STATE_CONTROL,
-			      1, &mchan->attrs.events_state_ctrl);
+	rc = sbi_mpxy_write_attrs(mchan->channel_id, SBI_MPXY_ATTR_EVENTS_STATE_CONTROL,
+				  1, &mchan->attrs.events_state_ctrl);
 	if (rc)
 		dev_err(dev, "disable events state failed for MPXY channel 0x%x\n",
 			mchan->channel_id);
@@ -741,8 +451,8 @@ static void mpxy_mbox_msi_write(struct msi_desc *desc, struct msi_msg *msg)
 	minfo->msi_addr_hi = msg->address_hi;
 	minfo->msi_data = msg->data;
 
-	rc = mpxy_write_attrs(mchan->channel_id, SBI_MPXY_ATTR_MSI_ADDR_LO,
-			      sizeof(*minfo) / sizeof(u32), (u32 *)minfo);
+	rc = sbi_mpxy_write_attrs(mchan->channel_id, SBI_MPXY_ATTR_MSI_ADDR_LO,
+				  sizeof(*minfo) / sizeof(u32), (u32 *)minfo);
 	if (rc) {
 		dev_warn(dev, "failed to write MSI info for MPXY channel 0x%x\n",
 			 mchan->channel_id);
@@ -776,7 +486,7 @@ static int mpxy_mbox_populate_channels(struct mpxy_mbox *mbox)
 	int rc;
 
 	/* Find-out of number of channels */
-	rc = mpxy_get_channel_count(&mbox->channel_count);
+	rc = sbi_mpxy_get_channel_count(&mbox->channel_count);
 	if (rc)
 		return dev_err_probe(mbox->dev, rc, "failed to get number of MPXY channels\n");
 	if (!mbox->channel_count)
@@ -786,7 +496,7 @@ static int mpxy_mbox_populate_channels(struct mpxy_mbox *mbox)
 	channel_ids = kzalloc_objs(*channel_ids, mbox->channel_count);
 	if (!channel_ids)
 		return -ENOMEM;
-	rc = mpxy_get_channel_ids(mbox->channel_count, channel_ids);
+	rc = sbi_mpxy_get_channel_ids(mbox->channel_count, channel_ids);
 	if (rc)
 		return dev_err_probe(mbox->dev, rc, "failed to get MPXY channel IDs\n");
 
@@ -800,9 +510,9 @@ static int mpxy_mbox_populate_channels(struct mpxy_mbox *mbox)
 		mchan->mbox = mbox;
 		mchan->channel_id = channel_ids[i];
 
-		rc = mpxy_read_attrs(mchan->channel_id, SBI_MPXY_ATTR_MSG_PROT_ID,
-				     sizeof(mchan->attrs) / sizeof(u32),
-				     (u32 *)&mchan->attrs);
+		rc = sbi_mpxy_read_attrs(mchan->channel_id, SBI_MPXY_ATTR_MSG_PROT_ID,
+					 sizeof(mchan->attrs) / sizeof(u32),
+					 (u32 *)&mchan->attrs);
 		if (rc) {
 			return dev_err_probe(mbox->dev, rc,
 					     "MPXY channel 0x%x read attrs failed\n",
@@ -818,11 +528,11 @@ static int mpxy_mbox_populate_channels(struct mpxy_mbox *mbox)
 			}
 		}
 
-		mchan->notif = devm_kzalloc(mbox->dev, mpxy_shmem_size, GFP_KERNEL);
+		mchan->notif = devm_kzalloc(mbox->dev, sbi_mpxy_shmem_size(), GFP_KERNEL);
 		if (!mchan->notif)
 			return -ENOMEM;
 
-		mchan->max_xfer_len = min(mpxy_shmem_size, mchan->attrs.msg_max_len);
+		mchan->max_xfer_len = min(sbi_mpxy_shmem_size(), mchan->attrs.msg_max_len);
 
 		if ((mchan->attrs.capability & SBI_MPXY_CHAN_CAP_GET_NOTIFICATIONS) &&
 		    (mchan->attrs.capability & SBI_MPXY_CHAN_CAP_EVENTS_STATE))
@@ -847,40 +557,12 @@ static int mpxy_mbox_probe(struct platform_device *pdev)
 	int msi_idx, rc;
 	u32 i;
 
-	/*
-	 * Initialize MPXY shared memory only once. This also ensures
-	 * that SBI MPXY mailbox is probed only once.
-	 */
-	if (mpxy_shmem_init_done) {
-		dev_err(dev, "SBI MPXY mailbox already initialized\n");
-		return -EALREADY;
-	}
-
 	/* Probe for SBI MPXY extension */
-	if (sbi_spec_version < sbi_mk_version(1, 0) ||
-	    sbi_probe_extension(SBI_EXT_MPXY) <= 0) {
+	if (!sbi_mpxy_shmem_size()) {
 		dev_info(dev, "SBI MPXY extension not available\n");
 		return -ENODEV;
 	}
 
-	/* Find-out shared memory size */
-	rc = mpxy_get_shmem_size(&mpxy_shmem_size);
-	if (rc)
-		return dev_err_probe(dev, rc, "failed to get MPXY shared memory size\n");
-
-	/*
-	 * Setup MPXY shared memory on each CPU
-	 *
-	 * Note: Don't cleanup MPXY shared memory upon CPU power-down
-	 * because the RPMI System MSI irqchip driver needs it to be
-	 * available when migrating IRQs in CPU power-down path.
-	 */
-	cpuhp_setup_state(CPUHP_AP_ONLINE_DYN, "riscv/sbi-mpxy-shmem",
-			  mpxy_setup_shmem, NULL);
-
-	/* Mark as MPXY shared memory initialization done */
-	mpxy_shmem_init_done = true;
-
 	/* Allocate mailbox instance */
 	mbox = devm_kzalloc(dev, sizeof(*mbox), GFP_KERNEL);
 	if (!mbox)
-- 
2.43.0


^ permalink raw reply related	[flat|nested] 7+ messages in thread

* [PATCH 2/4] RISC-V: Factor-out per-hart MPXY shared-memory acquisition
  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:02 ` Anup Patel
  2026-09-30 15:02 ` [PATCH 3/4] mailbox: add direct synchronous send support Anup Patel
  2026-09-30 15:02 ` [PATCH 4/4] mailbox: riscv-sbi-mpxy: Move to send_data_sync() for sending messages Anup Patel
  3 siblings, 0 replies; 7+ messages in thread
From: Anup Patel @ 2026-09-30 15:02 UTC (permalink / raw)
  To: Palmer Dabbelt, Paul Walmsley, Rahul Pathak, Stephen Boyd,
	Brian Masney, Jerome Brunet, Thomas Gleixner, Radu Rendec,
	Jassi Brar
  Cc: Himanshu Chauhan, Atish Patra, Anup Patel, Amirreza Zarrabi,
	linux-riscv, linux-kernel, linux-clk, Anup Patel

From: Amirreza Zarrabi <amirreza.zarrabi@oss.qualcomm.com>

Most of the SBI MPXY functions need to access MPXY shared-memory so
they have to acquire underlying host CPU before accessing the MPXY
shared-memory and release the host CPU after the work is done.

Factor-out the above mentioned per-hart MPXY shared-memory and host
CPU acquisition into mpxy_local_get()/put() functions.

Signed-off-by: Amirreza Zarrabi <amirreza.zarrabi@oss.qualcomm.com>
Signed-off-by: Anup Patel <anup.patel@oss.qualcomm.com>
---
 arch/riscv/kernel/sbi_mpxy.c | 159 ++++++++++++++++++++++-------------
 1 file changed, 100 insertions(+), 59 deletions(-)

diff --git a/arch/riscv/kernel/sbi_mpxy.c b/arch/riscv/kernel/sbi_mpxy.c
index 17a2cee21311..b2b34991fd42 100644
--- a/arch/riscv/kernel/sbi_mpxy.c
+++ b/arch/riscv/kernel/sbi_mpxy.c
@@ -40,6 +40,26 @@ static DEFINE_PER_CPU(struct mpxy_local, mpxy_local);
 static unsigned long mpxy_shmem_size;
 static bool mpxy_shmem_init_done;
 
+static int mpxy_local_get(struct mpxy_local **out)
+{
+	struct mpxy_local *mpxy;
+
+	get_cpu();
+	mpxy = this_cpu_ptr(&mpxy_local);
+	if (!mpxy->shmem_active) {
+		put_cpu();
+		return -ENODEV;
+	}
+
+	*out = mpxy;
+	return 0;
+}
+
+static void mpxy_local_put(void)
+{
+	put_cpu();
+}
+
 unsigned long sbi_mpxy_shmem_size(void)
 {
 	if (!mpxy_shmem_init_done)
@@ -50,53 +70,61 @@ EXPORT_SYMBOL_GPL(sbi_mpxy_shmem_size);
 
 int sbi_mpxy_get_channel_count(u32 *channel_count)
 {
-	struct mpxy_local *mpxy = this_cpu_ptr(&mpxy_local);
-	struct sbi_mpxy_channel_ids_data *sdata = mpxy->shmem;
+	struct sbi_mpxy_channel_ids_data *sdata;
+	struct mpxy_local *mpxy;
 	u32 remaining, returned;
 	struct sbiret sret;
+	int rc = 0;
 
-	if (!mpxy->shmem_active)
-		return -ENODEV;
 	if (!channel_count)
 		return -EINVAL;
 
-	get_cpu();
+	rc = mpxy_local_get(&mpxy);
+	if (rc)
+		return rc;
+	sdata = mpxy->shmem;
 
 	/* Get the remaining and returned fields to calculate total */
 	sret = sbi_ecall(SBI_EXT_MPXY, SBI_EXT_MPXY_GET_CHANNEL_IDS,
 			 0, 0, 0, 0, 0, 0);
-	if (sret.error)
-		goto err_put_cpu;
+	if (sret.error) {
+		rc = sbi_err_map_linux_errno(sret.error);
+		goto out;
+	}
 
 	remaining = le32_to_cpu(sdata->remaining);
 	returned = le32_to_cpu(sdata->returned);
 	*channel_count = remaining + returned;
 
-err_put_cpu:
-	put_cpu();
-	return sbi_err_map_linux_errno(sret.error);
+out:
+	mpxy_local_put();
+	return rc;
 }
 EXPORT_SYMBOL_GPL(sbi_mpxy_get_channel_count);
 
 int sbi_mpxy_get_channel_ids(u32 channel_count, u32 *channel_ids)
 {
-	struct mpxy_local *mpxy = this_cpu_ptr(&mpxy_local);
-	struct sbi_mpxy_channel_ids_data *sdata = mpxy->shmem;
 	u32 remaining, returned, count, start_index = 0;
+	struct sbi_mpxy_channel_ids_data *sdata;
+	struct mpxy_local *mpxy;
 	struct sbiret sret;
+	int rc = 0;
 
-	if (!mpxy->shmem_active)
-		return -ENODEV;
 	if (!channel_count || !channel_ids)
 		return -EINVAL;
 
-	get_cpu();
+	rc = mpxy_local_get(&mpxy);
+	if (rc)
+		return rc;
+	sdata = mpxy->shmem;
 
 	do {
 		sret = sbi_ecall(SBI_EXT_MPXY, SBI_EXT_MPXY_GET_CHANNEL_IDS,
 				 start_index, 0, 0, 0, 0, 0);
-		if (sret.error)
-			goto err_put_cpu;
+		if (sret.error) {
+			rc = sbi_err_map_linux_errno(sret.error);
+			goto out;
+		}
 
 		remaining = le32_to_cpu(sdata->remaining);
 		returned = le32_to_cpu(sdata->returned);
@@ -107,56 +135,60 @@ int sbi_mpxy_get_channel_ids(u32 channel_count, u32 *channel_ids)
 		start_index += count;
 	} while (remaining && start_index < channel_count);
 
-err_put_cpu:
-	put_cpu();
-	return sbi_err_map_linux_errno(sret.error);
+out:
+	mpxy_local_put();
+	return rc;
 }
 EXPORT_SYMBOL_GPL(sbi_mpxy_get_channel_ids);
 
 int sbi_mpxy_read_attrs(u32 channel_id, u32 base_attrid, u32 attr_count,
 			u32 *attrs_buf)
 {
-	struct mpxy_local *mpxy = this_cpu_ptr(&mpxy_local);
+	struct mpxy_local *mpxy;
 	struct sbiret sret;
+	int rc = 0;
 
-	if (!mpxy->shmem_active)
-		return -ENODEV;
 	if (!attr_count || !attrs_buf)
 		return -EINVAL;
 
-	get_cpu();
+	rc = mpxy_local_get(&mpxy);
+	if (rc)
+		return rc;
 
 	sret = sbi_ecall(SBI_EXT_MPXY, SBI_EXT_MPXY_READ_ATTRS,
 			 channel_id, base_attrid, attr_count, 0, 0, 0);
-	if (sret.error)
-		goto err_put_cpu;
+	if (sret.error) {
+		rc = sbi_err_map_linux_errno(sret.error);
+		goto out;
+	}
 
 	memcpy_from_le32(attrs_buf, (__le32 *)mpxy->shmem, attr_count);
 
-err_put_cpu:
-	put_cpu();
-	return sbi_err_map_linux_errno(sret.error);
+out:
+	mpxy_local_put();
+	return rc;
 }
 EXPORT_SYMBOL_GPL(sbi_mpxy_read_attrs);
 
 int sbi_mpxy_write_attrs(u32 channel_id, u32 base_attrid, u32 attr_count,
 			 u32 *attrs_buf)
 {
-	struct mpxy_local *mpxy = this_cpu_ptr(&mpxy_local);
+	struct mpxy_local *mpxy;
 	struct sbiret sret;
+	int rc = 0;
 
-	if (!mpxy->shmem_active)
-		return -ENODEV;
 	if (!attr_count || !attrs_buf)
 		return -EINVAL;
 
-	get_cpu();
+	rc = mpxy_local_get(&mpxy);
+	if (rc)
+		return rc;
 
 	memcpy_to_le32((__le32 *)mpxy->shmem, attrs_buf, attr_count);
 	sret = sbi_ecall(SBI_EXT_MPXY, SBI_EXT_MPXY_WRITE_ATTRS,
 			 channel_id, base_attrid, attr_count, 0, 0, 0);
 
-	put_cpu();
+	mpxy_local_put();
 	return sbi_err_map_linux_errno(sret.error);
 }
 EXPORT_SYMBOL_GPL(sbi_mpxy_write_attrs);
@@ -166,16 +198,17 @@ int sbi_mpxy_send_message_with_resp(u32 channel_id, u32 msg_id,
 				    void *rx, unsigned long max_rx_len,
 				    unsigned long *rx_len)
 {
-	struct mpxy_local *mpxy = this_cpu_ptr(&mpxy_local);
+	struct mpxy_local *mpxy;
 	unsigned long rx_bytes;
 	struct sbiret sret;
+	int rc = 0;
 
-	if (!mpxy->shmem_active)
-		return -ENODEV;
 	if (!tx && tx_len)
 		return -EINVAL;
 
-	get_cpu();
+	rc = mpxy_local_get(&mpxy);
+	if (rc)
+		return rc;
 
 	/* Message protocols allowed to have no data in messages */
 	if (tx_len)
@@ -186,8 +219,8 @@ int sbi_mpxy_send_message_with_resp(u32 channel_id, u32 msg_id,
 	if (rx && !sret.error) {
 		rx_bytes = sret.value;
 		if (rx_bytes > max_rx_len) {
-			put_cpu();
-			return -ENOSPC;
+			rc = -ENOSPC;
+			goto out;
 		}
 
 		memcpy(rx, mpxy->shmem, rx_bytes);
@@ -195,23 +228,26 @@ int sbi_mpxy_send_message_with_resp(u32 channel_id, u32 msg_id,
 			*rx_len = rx_bytes;
 	}
 
-	put_cpu();
-	return sbi_err_map_linux_errno(sret.error);
+	rc = sbi_err_map_linux_errno(sret.error);
+out:
+	mpxy_local_put();
+	return rc;
 }
 EXPORT_SYMBOL_GPL(sbi_mpxy_send_message_with_resp);
 
 int sbi_mpxy_send_message_without_resp(u32 channel_id, u32 msg_id,
 				       void *tx, unsigned long tx_len)
 {
-	struct mpxy_local *mpxy = this_cpu_ptr(&mpxy_local);
+	struct mpxy_local *mpxy;
 	struct sbiret sret;
+	int rc = 0;
 
-	if (!mpxy->shmem_active)
-		return -ENODEV;
 	if (!tx && tx_len)
 		return -EINVAL;
 
-	get_cpu();
+	rc = mpxy_local_get(&mpxy);
+	if (rc)
+		return rc;
 
 	/* Message protocols allowed to have no data in messages */
 	if (tx_len)
@@ -220,8 +256,9 @@ int sbi_mpxy_send_message_without_resp(u32 channel_id, u32 msg_id,
 	sret = sbi_ecall(SBI_EXT_MPXY, SBI_EXT_MPXY_SEND_MSG_WITHOUT_RESP,
 			 channel_id, msg_id, tx_len, 0, 0, 0);
 
-	put_cpu();
-	return sbi_err_map_linux_errno(sret.error);
+	rc = sbi_err_map_linux_errno(sret.error);
+	mpxy_local_put();
+	return rc;
 }
 EXPORT_SYMBOL_GPL(sbi_mpxy_send_message_without_resp);
 
@@ -229,32 +266,36 @@ int sbi_mpxy_get_notifications(u32 channel_id,
 			       struct sbi_mpxy_notification_data *notif_data,
 			       unsigned long *events_data_len)
 {
-	struct mpxy_local *mpxy = this_cpu_ptr(&mpxy_local);
+	struct mpxy_local *mpxy;
 	struct sbiret sret;
+	int rc = 0;
 
-	if (!mpxy->shmem_active)
-		return -ENODEV;
 	if (!notif_data || !events_data_len)
 		return -EINVAL;
 
-	get_cpu();
+	rc = mpxy_local_get(&mpxy);
+	if (rc)
+		return rc;
 
 	sret = sbi_ecall(SBI_EXT_MPXY, SBI_EXT_MPXY_GET_NOTIFICATION_EVENTS,
 			 channel_id, 0, 0, 0, 0, 0);
-	if (sret.error)
-		goto err_put_cpu;
+	if (sret.error) {
+		rc = sbi_err_map_linux_errno(sret.error);
+		goto out;
+	}
 	if (sret.value < 0 || mpxy_shmem_size < sizeof(*notif_data) ||
 	    sret.value > mpxy_shmem_size - sizeof(*notif_data)) {
-		put_cpu();
-		return -EOVERFLOW;
+		rc = -EOVERFLOW;
+		goto out;
 	}
 
 	memcpy(notif_data, mpxy->shmem, sret.value + sizeof(*notif_data));
 	*events_data_len = sret.value;
 
-err_put_cpu:
-	put_cpu();
-	return sbi_err_map_linux_errno(sret.error);
+	rc = sbi_err_map_linux_errno(sret.error);
+out:
+	mpxy_local_put();
+	return rc;
 }
 EXPORT_SYMBOL_GPL(sbi_mpxy_get_notifications);
 
-- 
2.43.0


^ permalink raw reply related	[flat|nested] 7+ messages in thread

* [PATCH 3/4] mailbox: add direct synchronous send support
  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:02 ` [PATCH 2/4] RISC-V: Factor-out per-hart MPXY shared-memory acquisition Anup Patel
@ 2026-09-30 15:02 ` Anup Patel
  2026-09-30 15:02 ` [PATCH 4/4] mailbox: riscv-sbi-mpxy: Move to send_data_sync() for sending messages Anup Patel
  3 siblings, 0 replies; 7+ messages in thread
From: Anup Patel @ 2026-09-30 15:02 UTC (permalink / raw)
  To: Palmer Dabbelt, Paul Walmsley, Rahul Pathak, Stephen Boyd,
	Brian Masney, Jerome Brunet, Thomas Gleixner, Radu Rendec,
	Jassi Brar
  Cc: Himanshu Chauhan, Atish Patra, Anup Patel, Amirreza Zarrabi,
	linux-riscv, linux-kernel, linux-clk, Anup Patel

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


^ permalink raw reply related	[flat|nested] 7+ messages in thread

* [PATCH 4/4] mailbox: riscv-sbi-mpxy: Move to send_data_sync() for sending messages
  2026-09-30 15:02 [PATCH 0/4] Parallel message send using SBI MPXY Anup Patel
                   ` (2 preceding siblings ...)
  2026-09-30 15:02 ` [PATCH 3/4] mailbox: add direct synchronous send support Anup Patel
@ 2026-09-30 15:02 ` Anup Patel
  2026-09-30 15:38   ` sashiko-bot
  3 siblings, 1 reply; 7+ messages in thread
From: Anup Patel @ 2026-09-30 15:02 UTC (permalink / raw)
  To: Palmer Dabbelt, Paul Walmsley, Rahul Pathak, Stephen Boyd,
	Brian Masney, Jerome Brunet, Thomas Gleixner, Radu Rendec,
	Jassi Brar
  Cc: Himanshu Chauhan, Atish Patra, Anup Patel, Amirreza Zarrabi,
	linux-riscv, linux-kernel, linux-clk, Anup Patel

Currently, the SBI MPXY mailbox driver retrofits synchronous message
exchanges over existing send_data() callback and client driver explicitly
calls mbox_client_txdone().

As a side effect of this retrofitting, all messages sent via SBI MPXY
mailbox channel are serialized using per-channel spinlock which in-turn
prevents multiple CPUs simultaneously sending messages. On the contrary,
the SBI MPXY specification defines per-CPU MPXY shared memory so multiple
CPUs are allowed to send messages in-parallel.

To address the above, update the SBI MPXY mailbox driver to use the
send_data_sync() callback instead of send_data() callback. This removes
the redundant per-channel spinlock from the message sending path thereby
enabling parallel message sending from multiple CPUs. Also, the "error"
field in struct rpmi_mbox_message is now redundant because it was being
used to save the error dropped by msg_submit() function hence remove it.

Co-developed-by: Amirreza Zarrabi <amirreza.zarrabi@oss.qualcomm.com>
Signed-off-by: Amirreza Zarrabi <amirreza.zarrabi@oss.qualcomm.com>
Signed-off-by: Anup Patel <anup.patel@oss.qualcomm.com>
---
 drivers/clk/clk-rpmi.c                     |  2 +-
 drivers/irqchip/irq-riscv-rpmi-sysmsi.c    |  2 +-
 drivers/mailbox/riscv-sbi-mpxy-mbox.c      | 59 +++++++++++-----------
 include/linux/mailbox/riscv-rpmi-message.h | 18 +------
 4 files changed, 34 insertions(+), 47 deletions(-)

diff --git a/drivers/clk/clk-rpmi.c b/drivers/clk/clk-rpmi.c
index 921296aafa68..e365cb8a8dac 100644
--- a/drivers/clk/clk-rpmi.c
+++ b/drivers/clk/clk-rpmi.c
@@ -527,7 +527,7 @@ static int rpmi_clk_probe(struct platform_device *pdev)
 	context->client.dev		= context->dev;
 	context->client.rx_callback	= NULL;
 	context->client.tx_block	= false;
-	context->client.knows_txdone	= true;
+	context->client.tx_sync		= true;
 	context->client.tx_tout		= 0;
 
 	context->chan = mbox_request_channel(&context->client, 0);
diff --git a/drivers/irqchip/irq-riscv-rpmi-sysmsi.c b/drivers/irqchip/irq-riscv-rpmi-sysmsi.c
index 612f3972f7af..ca638900aa74 100644
--- a/drivers/irqchip/irq-riscv-rpmi-sysmsi.c
+++ b/drivers/irqchip/irq-riscv-rpmi-sysmsi.c
@@ -224,7 +224,7 @@ static int rpmi_sysmsi_probe(struct platform_device *pdev)
 	priv->client.dev		= priv->dev;
 	priv->client.rx_callback	= NULL;
 	priv->client.tx_block		= false;
-	priv->client.knows_txdone	= true;
+	priv->client.tx_sync		= true;
 	priv->client.tx_tout		= 0;
 
 	/* Request mailbox channel */
diff --git a/drivers/mailbox/riscv-sbi-mpxy-mbox.c b/drivers/mailbox/riscv-sbi-mpxy-mbox.c
index cba95b8406ee..18d5ed0b1561 100644
--- a/drivers/mailbox/riscv-sbi-mpxy-mbox.c
+++ b/drivers/mailbox/riscv-sbi-mpxy-mbox.c
@@ -112,10 +112,10 @@ struct mpxy_mbox {
 
 /* ====== MPXY RPMI processing ====== */
 
-static void mpxy_mbox_send_rpmi_data(struct mpxy_mbox_channel *mchan,
-				     struct rpmi_mbox_message *msg)
+static int mpxy_mbox_send_rpmi_data(struct mpxy_mbox_channel *mchan,
+				    struct rpmi_mbox_message *msg)
 {
-	msg->error = 0;
+	int error = 0;
 	switch (msg->type) {
 	case RPMI_MBOX_MSG_TYPE_GET_ATTRIBUTE:
 		switch (msg->attr.id) {
@@ -138,52 +138,54 @@ static void mpxy_mbox_send_rpmi_data(struct mpxy_mbox_channel *mchan,
 			msg->attr.value = mchan->rpmi_attrs.impl_version;
 			break;
 		default:
-			msg->error = -EOPNOTSUPP;
+			error = -EOPNOTSUPP;
 			break;
 		}
 		break;
 	case RPMI_MBOX_MSG_TYPE_SET_ATTRIBUTE:
 		/* None of the RPMI linux mailbox attributes are writeable */
-		msg->error = -EOPNOTSUPP;
+		error = -EOPNOTSUPP;
 		break;
 	case RPMI_MBOX_MSG_TYPE_SEND_WITH_RESPONSE:
 		if ((!msg->data.request && msg->data.request_len) ||
 		    (msg->data.request && msg->data.request_len > mchan->max_xfer_len) ||
 		    (!msg->data.response && msg->data.max_response_len)) {
-			msg->error = -EINVAL;
+			error = -EINVAL;
 			break;
 		}
 		if (!(mchan->attrs.capability & SBI_MPXY_CHAN_CAP_SEND_WITH_RESP)) {
-			msg->error = -EIO;
+			error = -EIO;
 			break;
 		}
-		msg->error = sbi_mpxy_send_message_with_resp(mchan->channel_id,
-							     msg->data.service_id,
-							     msg->data.request,
-							     msg->data.request_len,
-							     msg->data.response,
-							     msg->data.max_response_len,
-							     &msg->data.out_response_len);
+		error = sbi_mpxy_send_message_with_resp(mchan->channel_id,
+							msg->data.service_id,
+							msg->data.request,
+							msg->data.request_len,
+							msg->data.response,
+							msg->data.max_response_len,
+							&msg->data.out_response_len);
 		break;
 	case RPMI_MBOX_MSG_TYPE_SEND_WITHOUT_RESPONSE:
 		if ((!msg->data.request && msg->data.request_len) ||
 		    (msg->data.request && msg->data.request_len > mchan->max_xfer_len)) {
-			msg->error = -EINVAL;
+			error = -EINVAL;
 			break;
 		}
 		if (!(mchan->attrs.capability & SBI_MPXY_CHAN_CAP_SEND_WITHOUT_RESP)) {
-			msg->error = -EIO;
+			error = -EIO;
 			break;
 		}
-		msg->error = sbi_mpxy_send_message_without_resp(mchan->channel_id,
-								msg->data.service_id,
-								msg->data.request,
-								msg->data.request_len);
+		error = sbi_mpxy_send_message_without_resp(mchan->channel_id,
+							   msg->data.service_id,
+							   msg->data.request,
+							   msg->data.request_len);
 		break;
 	default:
-		msg->error = -EOPNOTSUPP;
+		error = -EOPNOTSUPP;
 		break;
 	}
+
+	return error;
 }
 
 static void mpxy_mbox_peek_rpmi_data(struct mbox_chan *chan,
@@ -205,7 +207,6 @@ static void mpxy_mbox_peek_rpmi_data(struct mbox_chan *chan,
 			break;
 		msg.notif.event_id = event->event_id;
 		msg.notif.event_data = event->event_data;
-		msg.error = 0;
 
 		mbox_chan_received_data(chan, &msg);
 		pos += sizeof(*event) + msg.notif.event_datalen;
@@ -222,16 +223,16 @@ static int mpxy_mbox_read_rpmi_attrs(struct mpxy_mbox_channel *mchan)
 
 /* ====== MPXY mailbox callbacks ====== */
 
-static int mpxy_mbox_send_data(struct mbox_chan *chan, void *data)
+static int mpxy_mbox_send_data_sync(struct mbox_chan *chan, void *data)
 {
 	struct mpxy_mbox_channel *mchan = chan->con_priv;
 
-	if (mchan->attrs.msg_proto_id == SBI_MPXY_MSGPROTO_RPMI_ID) {
-		mpxy_mbox_send_rpmi_data(mchan, data);
-		return 0;
+	switch (mchan->attrs.msg_proto_id) {
+	case SBI_MPXY_MSGPROTO_RPMI_ID:
+		return mpxy_mbox_send_rpmi_data(mchan, data);
+	default:
+		return -EOPNOTSUPP;
 	}
-
-	return -EOPNOTSUPP;
 }
 
 static bool mpxy_mbox_peek_data(struct mbox_chan *chan)
@@ -423,7 +424,7 @@ static void mpxy_mbox_shutdown(struct mbox_chan *chan)
 }
 
 static const struct mbox_chan_ops mpxy_mbox_ops = {
-	.send_data = mpxy_mbox_send_data,
+	.send_data_sync = mpxy_mbox_send_data_sync,
 	.peek_data = mpxy_mbox_peek_data,
 	.startup = mpxy_mbox_startup,
 	.shutdown = mpxy_mbox_shutdown,
diff --git a/include/linux/mailbox/riscv-rpmi-message.h b/include/linux/mailbox/riscv-rpmi-message.h
index e135c6564d0c..0278f1cee51f 100644
--- a/include/linux/mailbox/riscv-rpmi-message.h
+++ b/include/linux/mailbox/riscv-rpmi-message.h
@@ -164,7 +164,6 @@ struct rpmi_mbox_message {
 			u8 *event_data;
 		} notif;
 	};
-	int error;
 };
 
 /* RPMI Linux mailbox message helper routines */
@@ -174,7 +173,6 @@ static inline void rpmi_mbox_init_get_attribute(struct rpmi_mbox_message *msg,
 	msg->type = RPMI_MBOX_MSG_TYPE_GET_ATTRIBUTE;
 	msg->attr.id = id;
 	msg->attr.value = 0;
-	msg->error = 0;
 }
 
 static inline void rpmi_mbox_init_set_attribute(struct rpmi_mbox_message *msg,
@@ -184,7 +182,6 @@ static inline void rpmi_mbox_init_set_attribute(struct rpmi_mbox_message *msg,
 	msg->type = RPMI_MBOX_MSG_TYPE_SET_ATTRIBUTE;
 	msg->attr.id = id;
 	msg->attr.value = value;
-	msg->error = 0;
 }
 
 static inline void rpmi_mbox_init_send_with_response(struct rpmi_mbox_message *msg,
@@ -201,7 +198,6 @@ static inline void rpmi_mbox_init_send_with_response(struct rpmi_mbox_message *m
 	msg->data.response = response;
 	msg->data.max_response_len = max_response_len;
 	msg->data.out_response_len = 0;
-	msg->error = 0;
 }
 
 static inline void rpmi_mbox_init_send_without_response(struct rpmi_mbox_message *msg,
@@ -216,7 +212,6 @@ static inline void rpmi_mbox_init_send_without_response(struct rpmi_mbox_message
 	msg->data.response = NULL;
 	msg->data.max_response_len = 0;
 	msg->data.out_response_len = 0;
-	msg->error = 0;
 }
 
 static inline void *rpmi_mbox_get_msg_response(struct rpmi_mbox_message *msg)
@@ -227,17 +222,8 @@ static inline void *rpmi_mbox_get_msg_response(struct rpmi_mbox_message *msg)
 static inline int rpmi_mbox_send_message(struct mbox_chan *chan,
 					 struct rpmi_mbox_message *msg)
 {
-	int ret;
-
-	/* Send message for the underlying mailbox channel */
-	ret = mbox_send_message(chan, msg);
-	if (ret < 0)
-		return ret;
-
-	/* Explicitly signal txdone for mailbox channel */
-	ret = msg->error;
-	mbox_client_txdone(chan, ret);
-	return ret;
+	/* Send message for the underlying mailbox channel synchronously */
+	return mbox_send_message_sync(chan, msg);
 }
 
 #endif /* _LINUX_RISCV_RPMI_MESSAGE_H_ */
-- 
2.43.0


^ permalink raw reply related	[flat|nested] 7+ messages in thread

* Re: [PATCH 1/4] RISC-V: Move common MPXY helper routines to arch/riscv
  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
  0 siblings, 0 replies; 7+ messages in thread
From: sashiko-bot @ 2026-09-30 15:30 UTC (permalink / raw)
  To: Anup Patel; +Cc: linux-clk

Thank you for your contribution! Sashiko AI review found 1 potential issue(s) to consider:
- [Low] build: missing static inline on sbi_mpxy stub functions
--

commit ca97cea8474e30458386eddc230906510a535e88
Author: Anup Patel <anup.patel@oss.qualcomm.com>

RISC-V: Move common MPXY helper routines to arch/riscv
    
This commit moves the common MPXY helper routines and MPXY shared memory
management from the Linux SBI MPXY mailbox driver into arch/riscv. This
allows the kernel to directly perform SBI MPXY calls and share memory with
the mailbox driver when the Linux mailbox channel instance is unavailable.

> diff --git a/arch/riscv/include/asm/sbi.h b/arch/riscv/include/asm/sbi.h
> index 5725e0ca4dda3..c41e1af31a45f 100644
> --- a/arch/riscv/include/asm/sbi.h
> +++ b/arch/riscv/include/asm/sbi.h
[ ... ]
> @@ -685,7 +716,58 @@ int sbi_debug_console_read(char *bytes, unsigned int num_bytes);
>  
>  #else /* CONFIG_RISCV_SBI */
>  static inline int sbi_remote_fence_i(const struct cpumask *cpu_mask) { return -1; }
[ ... ]
> +static inline int sbi_mpxy_get_channel_ids(u32 channel_count, u32 *channel_ids)
> +{
> +	return -ENODEV;
> +}
> +
> +int sbi_mpxy_read_attrs(u32 channel_id, u32 base_attrid, u32 attr_count,
> +			u32 *attrs_buf)
> +{
> +	return -ENODEV;
> +}

[Severity: Low]
Does this omitted static inline modifier break compilation when
CONFIG_RISCV_SBI=n?

Without static inline on sbi_mpxy_read_attrs (and the other stub functions
below it), every C file including this header will generate a global symbol
for the function. This typically leads to multiple definition linker errors
across different translation units.

> +
> +int sbi_mpxy_write_attrs(u32 channel_id, u32 base_attrid, u32 attr_count,
> +			 u32 *attrs_buf)
> +{
> +	return -ENODEV;
> +}

-- 
Sashiko AI review · https://sashiko.dev/#/patchset/20260930150213.799245-1-anup.patel@oss.qualcomm.com?part=1

^ permalink raw reply	[flat|nested] 7+ messages in thread

* Re: [PATCH 4/4] mailbox: riscv-sbi-mpxy: Move to send_data_sync() for sending messages
  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
  0 siblings, 0 replies; 7+ messages in thread
From: sashiko-bot @ 2026-09-30 15:38 UTC (permalink / raw)
  To: Anup Patel; +Cc: linux-clk

Thank you for your contribution! Sashiko AI review found 3 potential issue(s) to consider:
- [High] pmdomain: riscv: missing tx_sync causes RPMI PM domain probe failure
- [High] mailbox: riscv-sbi-mpxy: missing IRQ disable causes payload corruption
- [Medium] mailbox: riscv-rpmi: atomic context calls sleepable mbox_send_message_sync()
--

commit 612dfab344d90d3c136efe88349ea5fa93e33818
Author: Anup Patel <anup.patel@oss.qualcomm.com>

mailbox: riscv-sbi-mpxy: Move to send_data_sync() for sending messages

This commit transitions the SBI MPXY mailbox driver from the asynchronous
send_data() callback to the synchronous send_data_sync() callback. It removes
the per-channel spinlock and the manual mbox_client_txdone() call to allow
parallel message sending from multiple CPUs.

> diff --git a/drivers/clk/clk-rpmi.c b/drivers/clk/clk-rpmi.c
> index 921296aafa686..e365cb8a8dac3 100644
> --- a/drivers/clk/clk-rpmi.c
> +++ b/drivers/clk/clk-rpmi.c
> @@ -527,7 +527,7 @@ static int rpmi_clk_probe(struct platform_device *pdev)
>  	context->client.dev		= context->dev;
>  	context->client.rx_callback	= NULL;
>  	context->client.tx_block	= false;
> -	context->client.knows_txdone	= true;
> +	context->client.tx_sync		= true;

[Severity: High]
This updates the clock driver to set tx_sync = true, but was the pmdomain
driver in drivers/pmdomain/riscv/riscv-rpmi-device-power.c missed?

The core mailbox framework in mbox_send_message_sync() returns -EOPNOTSUPP
if MBOX_TXDONE_BY_RETURN is missing (which happens when tx_sync is false).

Since rpmi_pm_domain_probe() still sets knows_txdone = true rather than
tx_sync = true, won't its mailbox messages be rejected during probe, causing
it to fail unconditionally?

>  	context->client.tx_tout		= 0;
>  
>  	context->chan = mbox_request_channel(&context->client, 0);

> [ ... ]

> diff --git a/drivers/mailbox/riscv-sbi-mpxy-mbox.c b/drivers/mailbox/riscv-sbi-mpxy-mbox.c
> index cba95b8406ee9..18d5ed0b15610 100644
> --- a/drivers/mailbox/riscv-sbi-mpxy-mbox.c
> +++ b/drivers/mailbox/riscv-sbi-mpxy-mbox.c
> [ ... ]
> @@ -138,52 +138,54 @@ static void mpxy_mbox_send_rpmi_data(struct mpxy_mbox_channel *mchan,
> [ ... ]
>  		if (!(mchan->attrs.capability & SBI_MPXY_CHAN_CAP_SEND_WITH_RESP)) {
> -			msg->error = -EIO;
> +			error = -EIO;
>  			break;
>  		}
> -		msg->error = sbi_mpxy_send_message_with_resp(mchan->channel_id,
> -							     msg->data.service_id,
> -							     msg->data.request,
> -							     msg->data.request_len,
> -							     msg->data.response,
> -							     msg->data.max_response_len,
> -							     &msg->data.out_response_len);
> +		error = sbi_mpxy_send_message_with_resp(mchan->channel_id,
> +							msg->data.service_id,
> +							msg->data.request,
> +							msg->data.request_len,
> +							msg->data.response,
> +							msg->data.max_response_len,
> +							&msg->data.out_response_len);

[Severity: High]
By moving to mbox_send_message_sync(), we no longer take the channel spinlock
(which safely serialized calls and disabled hard interrupts) before sending
messages.

Inside sbi_mpxy_send_message_with_resp(), mpxy_local_get() uses get_cpu(),
which only disables preemption but leaves local interrupts enabled.

If a hardirq (like rpmi_sysmsi_irq_mask()) preempts a process-context message
on the same CPU, won't both concurrently access the exact same per-CPU
mpxy->shmem buffer?

Could this silently overwrite the interrupted thread's payload and lead to
data corruption in the SBI MPXY payload before it reaches the firmware?

>  		break;
>  	case RPMI_MBOX_MSG_TYPE_SEND_WITHOUT_RESPONSE:

> [ ... ]

> diff --git a/include/linux/mailbox/riscv-rpmi-message.h b/include/linux/mailbox/riscv-rpmi-message.h
> index d5362b5821f95..5269ccf064930 100644
> --- a/include/linux/mailbox/riscv-rpmi-message.h
> +++ b/include/linux/mailbox/riscv-rpmi-message.h
> [ ... ]
> @@ -238,17 +233,8 @@ static inline void *rpmi_mbox_get_msg_response(struct rpmi_mbox_message *msg)
>  static inline int rpmi_mbox_send_message(struct mbox_chan *chan,
>  					 struct rpmi_mbox_message *msg)
>  {
> -	int ret;
> -
> -	/* Send message for the underlying mailbox channel */
> -	ret = mbox_send_message(chan, msg);
> -	if (ret < 0)
> -		return ret;
> -
> -	/* Explicitly signal txdone for mailbox channel */
> -	ret = msg->error;
> -	mbox_client_txdone(chan, ret);
> -	return ret;
> +	/* Send message for the underlying mailbox channel synchronously */
> +	return mbox_send_message_sync(chan, msg);

[Severity: Medium]
The mbox_send_message_sync() API is explicitly documented as a sleepable
function that must not be called from atomic context.

However, rpmi_mbox_send_message() is indirectly called by
rpmi_sysmsi_irq_mask() from the core IRQ framework in an atomic context
with raw spinlocks held.

Although the current riscv-sbi-mpxy controller implementation might not
sleep, could this API contract violation trigger a warning or break if the
mailbox core adds might_sleep() checks?

>  }
>  
>  #endif /* _LINUX_RISCV_RPMI_MESSAGE_H_ */

-- 
Sashiko AI review · https://sashiko.dev/#/patchset/20260930150213.799245-1-anup.patel@oss.qualcomm.com?part=4

^ permalink raw reply	[flat|nested] 7+ messages in thread

end of thread, other threads:[~2026-09-30 15:38 UTC | newest]

Thread overview: 7+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
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 ` [PATCH 3/4] mailbox: add direct synchronous send support Anup Patel
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

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox