All of lore.kernel.org
 help / color / mirror / Atom feed
From: Elliot Berman <quic_eberman@quicinc.com>
To: Bjorn Andersson <quic_bjorande@quicinc.com>,
	Jassi Brar <jassisinghbrar@gmail.com>
Cc: Elliot Berman <quic_eberman@quicinc.com>,
	Murali Nalajala <quic_mnalajal@quicinc.com>,
	Trilok Soni <quic_tsoni@quicinc.com>,
	"Srivatsa Vaddagiri" <quic_svaddagi@quicinc.com>,
	Carl van Schaik <quic_cvanscha@quicinc.com>,
	Andy Gross <agross@kernel.org>,
	Dmitry Baryshkov <dmitry.baryshkov@linaro.org>,
	<linux-arm-kernel@lists.infradead.org>,
	"Mark Rutland" <mark.rutland@arm.com>,
	Lorenzo Pieralisi <lorenzo.pieralisi@arm.com>,
	Sudeep Holla <sudeep.holla@arm.com>,
	"Marc Zyngier" <maz@kernel.org>, Rob Herring <robh+dt@kernel.org>,
	"Krzysztof Kozlowski" <krzysztof.kozlowski+dt@linaro.org>,
	Jonathan Corbet <corbet@lwn.net>, Will Deacon <will@kernel.org>,
	Catalin Marinas <catalin.marinas@arm.com>,
	Arnd Bergmann <arnd@arndb.de>,
	Greg Kroah-Hartman <gregkh@linuxfoundation.org>,
	<devicetree@vger.kernel.org>, <linux-doc@vger.kernel.org>,
	<linux-arm-msm@vger.kernel.org>, <linux-kernel@vger.kernel.org>
Subject: [PATCH v4 09/14] mailbox: Add Gunyah message queue mailbox
Date: Wed, 28 Sep 2022 12:56:28 -0700	[thread overview]
Message-ID: <20220928195633.2348848-10-quic_eberman@quicinc.com> (raw)
In-Reply-To: <20220928195633.2348848-1-quic_eberman@quicinc.com>

Gunyah message queues are a unidirectional inter-VM pipe for messages up
to 1024 bytes. This driver supports pairing a receiver message queue and
a transmitter message queue to expose a single mailbox channel.

Signed-off-by: Elliot Berman <quic_eberman@quicinc.com>
---
 MAINTAINERS                   |   2 +
 drivers/mailbox/Kconfig       |  10 ++
 drivers/mailbox/Makefile      |   2 +
 drivers/mailbox/gunyah-msgq.c | 232 ++++++++++++++++++++++++++++++++++
 drivers/virt/gunyah/Kconfig   |   2 +
 include/linux/gunyah.h        |  67 ++++++++++
 6 files changed, 315 insertions(+)
 create mode 100644 drivers/mailbox/gunyah-msgq.c
 create mode 100644 include/linux/gunyah.h

diff --git a/MAINTAINERS b/MAINTAINERS
index a26e67ef36b4..74053d8ff7ea 100644
--- a/MAINTAINERS
+++ b/MAINTAINERS
@@ -8889,8 +8889,10 @@ F:	Documentation/ABI/testing/sysfs-hypervisor-gunyah
 F:	Documentation/devicetree/bindings/firmware/gunyah-hypervisor.yaml
 F:	Documentation/virt/gunyah/
 F:	arch/arm64/gunyah/
+F:	drivers/mailbox/gunyah-msgq.c
 F:	drivers/virt/gunyah/
 F:	include/asm-generic/gunyah.h
+F:	include/linux/gunyah.h
 
 HABANALABS PCI DRIVER
 M:	Oded Gabbay <ogabbay@kernel.org>
diff --git a/drivers/mailbox/Kconfig b/drivers/mailbox/Kconfig
index 05d6fae800e3..baf9451c5f04 100644
--- a/drivers/mailbox/Kconfig
+++ b/drivers/mailbox/Kconfig
@@ -41,6 +41,16 @@ config IMX_MBOX
 	help
 	  Mailbox implementation for i.MX Messaging Unit (MU).
 
+config GUNYAH_MESSAGE_QUEUES
+	tristate "Gunyah Message Queue Mailbox"
+	depends on GUNYAH
+	help
+	  Mailbox implementation for Gunyah Message Queues. Gunyah message queues
+	  are an IPC mechanism to pass short messages between virtual machines
+	  running under the Gunyah hypervisor.
+
+	  Say Y here if you run Linux as a Gunyah virtual machine.
+
 config PLATFORM_MHU
 	tristate "Platform MHU Mailbox"
 	depends on OF
diff --git a/drivers/mailbox/Makefile b/drivers/mailbox/Makefile
index fc9376117111..5f929bb55e9a 100644
--- a/drivers/mailbox/Makefile
+++ b/drivers/mailbox/Makefile
@@ -55,6 +55,8 @@ obj-$(CONFIG_MTK_CMDQ_MBOX)	+= mtk-cmdq-mailbox.o
 
 obj-$(CONFIG_ZYNQMP_IPI_MBOX)	+= zynqmp-ipi-mailbox.o
 
+obj-$(CONFIG_GUNYAH)		+= gunyah-msgq.o
+
 obj-$(CONFIG_SUN6I_MSGBOX)	+= sun6i-msgbox.o
 
 obj-$(CONFIG_SPRD_MBOX)		+= sprd-mailbox.o
diff --git a/drivers/mailbox/gunyah-msgq.c b/drivers/mailbox/gunyah-msgq.c
new file mode 100644
index 000000000000..359f682d101c
--- /dev/null
+++ b/drivers/mailbox/gunyah-msgq.c
@@ -0,0 +1,232 @@
+// SPDX-License-Identifier: GPL-2.0-only
+/*
+ * Copyright (c) 2022 Qualcomm Innovation Center, Inc. All rights reserved.
+ */
+
+#include <linux/mailbox_controller.h>
+#include <linux/interrupt.h>
+#include <linux/gunyah.h>
+#include <linux/printk.h>
+#include <linux/init.h>
+#include <linux/slab.h>
+#include <linux/wait.h>
+
+#define mbox_chan_to_msgq(chan) (container_of(chan->mbox, struct gunyah_msgq, mbox))
+
+static inline bool gh_msgq_has_tx(struct gunyah_msgq *msgq)
+{
+	return msgq->tx_ghrsc.type == GUNYAH_RESOURCE_TYPE_MSGQ_TX;
+}
+
+static inline bool gh_msgq_has_rx(struct gunyah_msgq *msgq)
+{
+	return msgq->rx_ghrsc.type == GUNYAH_RESOURCE_TYPE_MSGQ_RX;
+}
+
+static ssize_t __gh_msgq_recv(struct gunyah_msgq *msgq, void *buff, size_t size, bool *ready)
+{
+	unsigned long gh_err;
+	size_t recv_size;
+	ssize_t ret;
+
+	gh_err = gh_hypercall_msgq_recv(msgq->rx_ghrsc.capid, (uintptr_t)buff, size,
+					&recv_size, ready);
+	switch (gh_err) {
+	case GH_ERROR_OK:
+		ret = recv_size;
+		break;
+	case GH_ERROR_MSGQUEUE_EMPTY:
+		ret = -EAGAIN;
+		*ready = false;
+		break;
+	default:
+		ret = gh_remap_error(gh_err);
+		break;
+	}
+
+	return ret;
+}
+
+static irqreturn_t gh_msgq_rx_irq_handler(int irq, void *data)
+{
+	struct gunyah_msgq *msgq = data;
+	struct gunyah_msgq_rx_data rx_data;
+	ssize_t ret;
+	bool more;
+
+	do {
+		ret = __gh_msgq_recv(msgq, &rx_data.data, sizeof(rx_data.data), &more);
+
+		if (ret >= 0) {
+			rx_data.length = ret;
+			mbox_chan_received_data(gunyah_msgq_chan(msgq), &rx_data);
+		} else if (ret != -EAGAIN)
+			pr_warn("Failed to receive data from msgq for %s: %ld\n",
+				msgq->mbox.dev ? dev_name(msgq->mbox.dev) : "", ret);
+	} while (ret >= 0 && more);
+
+	return IRQ_HANDLED;
+}
+
+static irqreturn_t gh_msgq_tx_irq_handler(int irq, void *data)
+{
+	struct gunyah_msgq *msgq = data;
+
+	mbox_chan_txdone(gunyah_msgq_chan(msgq), 0);
+
+	return IRQ_HANDLED;
+}
+
+static void gh_msgq_txdone_tasklet(unsigned long data)
+{
+	struct gunyah_msgq *msgq = (struct gunyah_msgq *)data;
+
+	mbox_chan_txdone(gunyah_msgq_chan(msgq), msgq->last_status);
+}
+
+static int __gh_msgq_send(struct gunyah_msgq *msgq, void *buff, size_t size, u64 tx_flags)
+{
+	unsigned long gh_err;
+	ssize_t ret;
+	bool ready;
+
+	gh_err = gh_hypercall_msgq_send(msgq->tx_ghrsc.capid, size, (uintptr_t)buff, tx_flags,
+					&ready);
+	switch (gh_err) {
+	case GH_ERROR_OK:
+		ret = !ready;
+		break;
+	case GH_ERROR_MSGQUEUE_FULL:
+		ret = -EAGAIN;
+		break;
+	default:
+		/* Not sure how to propagate these out to client. If we get here, nobody is going
+		 * to trigger a retry
+		 */
+		ret = gh_remap_error(gh_err);
+		break;
+	}
+
+	return ret;
+}
+
+static int gh_msgq_send_data(struct mbox_chan *chan, void *data)
+{
+	struct gunyah_msgq *msgq = mbox_chan_to_msgq(chan);
+	struct gunyah_msgq_tx_data *msgq_data = data;
+	u64 tx_flags = 0;
+	int ret;
+
+	if (msgq_data->push)
+		tx_flags |= GH_HYPERCALL_MSGQ_TX_FLAGS_PUSH;
+
+	ret = __gh_msgq_send(msgq, msgq_data->data, msgq_data->length, tx_flags);
+
+	/**
+	 * EAGAIN: message didn't send.
+	 * ret = 1: message sent, but now the message queue is full and we can't send any more msgs.
+	 * Either way, don't report that this message is done.
+	 */
+	if (ret == -EAGAIN || ret == 1)
+		return ret;
+
+	/**
+	 * Mailbox framework requires that tx done happens asynchronously to sending the message
+	 * IOW, a notification that the message was sent happens after sending the message.
+	 * To work around this, defer the txdone to a tasklet.
+	 */
+	msgq->last_status = ret;
+	tasklet_schedule(&msgq->txdone_tasklet);
+
+	return 0;
+}
+
+struct mbox_chan_ops gunyah_msgq_ops = {
+	.send_data = gh_msgq_send_data,
+};
+
+/**
+ * gunyah_msgq_init() - Initialize a Gunyah message queue with an mbox_client
+ * @parent: optional, device parent used for the mailbox controller
+ * @msgq: Pointer to the gunyah_msgq to initialize
+ * @cl: A mailbox client to bind to the mailbox channel that the message queue creates
+ * @tx_ghrsc: optional, the transmission side of the message queue
+ * @rx_ghrsc: optional, the receiving side of the message queue
+ *
+ * At least one of tx_ghrsc and rx_ghrsc should be not NULL. Most message queue use cases come with
+ * a pair of message queues to facilitiate bidirectional communication. When tx_ghrsc is set,
+ * the client can send messages with mbox_send_message(gunyah_msgq_chan(msgq), msg). When rx_ghrsc
+ * is set, the mbox_client should register an .rx_callback() and the message queue driver will
+ * push all available messages upon receiving the RX ready interrupt. The messages should be
+ * consumed or copied by the client right away as the gunyah_msgq_rx_data will be replaced/destroyed
+ * after the callback.
+ *
+ * Returns - 0 on success, negative otherwise
+ */
+int gunyah_msgq_init(struct device *parent, struct gunyah_msgq *msgq, struct mbox_client *cl,
+		     struct gunyah_resource *tx_ghrsc, struct gunyah_resource *rx_ghrsc)
+{
+	int ret;
+
+	/* Must have at least a tx_ghrsc or rx_ghrsc and that they are the right device types */
+	if ((!tx_ghrsc && !rx_ghrsc) ||
+	    (tx_ghrsc && tx_ghrsc->type != GUNYAH_RESOURCE_TYPE_MSGQ_TX) ||
+	    (rx_ghrsc && rx_ghrsc->type != GUNYAH_RESOURCE_TYPE_MSGQ_RX))
+		return -EINVAL;
+
+	msgq->tx_ghrsc = *tx_ghrsc;
+	msgq->rx_ghrsc = *rx_ghrsc;
+
+	msgq->mbox.dev = parent;
+	msgq->mbox.ops = &gunyah_msgq_ops;
+	msgq->mbox.chans = kcalloc(1, sizeof(*msgq->mbox.chans), GFP_KERNEL);
+	msgq->mbox.num_chans = 1;
+	msgq->mbox.txdone_irq = true;
+
+	if (gh_msgq_has_tx(msgq)) {
+		ret = request_irq(msgq->tx_ghrsc.irq, gh_msgq_tx_irq_handler, 0, "gh_msgq_tx",
+				msgq);
+		if (ret)
+			goto err_chans;
+	}
+
+	if (gh_msgq_has_rx(msgq)) {
+		ret = request_threaded_irq(msgq->rx_ghrsc.irq, NULL, gh_msgq_rx_irq_handler,
+						IRQF_ONESHOT, "gh_msgq_rx", msgq);
+		if (ret)
+			goto err_tx_irq;
+	}
+
+	tasklet_init(&msgq->txdone_tasklet, gh_msgq_txdone_tasklet, (unsigned long)msgq);
+
+	ret = mbox_controller_register(&msgq->mbox);
+	if (ret)
+		goto err_rx_irq;
+
+	ret = mbox_bind_client(gunyah_msgq_chan(msgq), cl);
+	if (ret)
+		goto err_mbox;
+
+	return 0;
+err_mbox:
+	mbox_controller_unregister(&msgq->mbox);
+err_rx_irq:
+	if (gh_msgq_has_rx(msgq))
+		free_irq(msgq->rx_ghrsc.irq, msgq);
+err_tx_irq:
+	if (gh_msgq_has_tx(msgq))
+		free_irq(msgq->tx_ghrsc.irq, msgq);
+err_chans:
+	kfree(msgq->mbox.chans);
+	return ret;
+}
+EXPORT_SYMBOL_GPL(gunyah_msgq_init);
+
+void gunyah_msgq_remove(struct gunyah_msgq *msgq)
+{
+	if (gh_msgq_has_tx(msgq))
+		free_irq(msgq->tx_ghrsc.irq, msgq);
+
+	kfree(msgq->mbox.chans);
+}
+EXPORT_SYMBOL_GPL(gunyah_msgq_remove);
diff --git a/drivers/virt/gunyah/Kconfig b/drivers/virt/gunyah/Kconfig
index 7ac917e0aa3f..f4c822a82f1a 100644
--- a/drivers/virt/gunyah/Kconfig
+++ b/drivers/virt/gunyah/Kconfig
@@ -4,6 +4,8 @@ config GUNYAH
 	tristate "Gunyah Virtualization drivers"
 	depends on ARM64
 	select AUXILIARY_BUS
+	select MAILBOX
+	select GUNYAH_MESSAGE_QUEUES
 	help
 	  The Gunyah drivers are the helper interfaces that runs in a guest VM
 	  such as basic inter-VM IPC and signaling mechanisms, and higher level
diff --git a/include/linux/gunyah.h b/include/linux/gunyah.h
new file mode 100644
index 000000000000..d5e80e2defab
--- /dev/null
+++ b/include/linux/gunyah.h
@@ -0,0 +1,67 @@
+/* SPDX-License-Identifier: GPL-2.0-only */
+/*
+ * Copyright (c) 2022 Qualcomm Innovation Center, Inc. All rights reserved.
+ */
+
+#ifndef _GUNYAH_H
+#define _GUNYAH_H
+
+#include <linux/mailbox_controller.h>
+#include <linux/mailbox_client.h>
+#include <linux/interrupt.h>
+
+#include <asm-generic/gunyah.h>
+
+/* Follows resource manager's resource types for VM_GET_HYP_RESOURCES */
+enum gunyah_resource_type {
+	GUNYAH_RESOURCE_TYPE_BELL_TX	= 0,
+	GUNYAH_RESOURCE_TYPE_BELL_RX	= 1,
+	GUNYAH_RESOURCE_TYPE_MSGQ_TX	= 2,
+	GUNYAH_RESOURCE_TYPE_MSGQ_RX	= 3,
+	GUNYAH_RESOURCE_TYPE_VCPU	= 4,
+};
+
+struct gunyah_resource {
+	enum gunyah_resource_type type;
+	u64 capid;
+	int irq;
+};
+
+/**
+ * Gunyah Message Queues
+ */
+
+#define GH_MSGQ_MAX_MSG_SIZE	1024
+
+struct gunyah_msgq_tx_data {
+	size_t length;
+	bool push;
+	char data[];
+};
+
+struct gunyah_msgq_rx_data {
+	size_t length;
+	char data[GH_MSGQ_MAX_MSG_SIZE];
+};
+
+struct gunyah_msgq {
+	struct gunyah_resource tx_ghrsc;
+	struct gunyah_resource rx_ghrsc;
+
+	/* msgq private */
+	int last_status;
+	struct mbox_controller mbox;
+	struct tasklet_struct txdone_tasklet;
+};
+
+
+int gunyah_msgq_init(struct device *parent, struct gunyah_msgq *msgq, struct mbox_client *cl,
+		     struct gunyah_resource *tx_ghrsc, struct gunyah_resource *rx_ghrsc);
+void gunyah_msgq_remove(struct gunyah_msgq *msgq);
+
+static inline struct mbox_chan *gunyah_msgq_chan(struct gunyah_msgq *msgq)
+{
+	return &msgq->mbox.chans[0];
+}
+
+#endif
-- 
2.25.1


WARNING: multiple messages have this Message-ID (diff)
From: Elliot Berman <quic_eberman@quicinc.com>
To: Bjorn Andersson <quic_bjorande@quicinc.com>,
	Jassi Brar <jassisinghbrar@gmail.com>
Cc: Elliot Berman <quic_eberman@quicinc.com>,
	Murali Nalajala <quic_mnalajal@quicinc.com>,
	Trilok Soni <quic_tsoni@quicinc.com>,
	"Srivatsa Vaddagiri" <quic_svaddagi@quicinc.com>,
	Carl van Schaik <quic_cvanscha@quicinc.com>,
	Andy Gross <agross@kernel.org>,
	Dmitry Baryshkov <dmitry.baryshkov@linaro.org>,
	<linux-arm-kernel@lists.infradead.org>,
	"Mark Rutland" <mark.rutland@arm.com>,
	Lorenzo Pieralisi <lorenzo.pieralisi@arm.com>,
	Sudeep Holla <sudeep.holla@arm.com>,
	"Marc Zyngier" <maz@kernel.org>, Rob Herring <robh+dt@kernel.org>,
	"Krzysztof Kozlowski" <krzysztof.kozlowski+dt@linaro.org>,
	Jonathan Corbet <corbet@lwn.net>, Will Deacon <will@kernel.org>,
	Catalin Marinas <catalin.marinas@arm.com>,
	Arnd Bergmann <arnd@arndb.de>,
	Greg Kroah-Hartman <gregkh@linuxfoundation.org>,
	<devicetree@vger.kernel.org>, <linux-doc@vger.kernel.org>,
	<linux-arm-msm@vger.kernel.org>, <linux-kernel@vger.kernel.org>
Subject: [PATCH v4 09/14] mailbox: Add Gunyah message queue mailbox
Date: Wed, 28 Sep 2022 12:56:28 -0700	[thread overview]
Message-ID: <20220928195633.2348848-10-quic_eberman@quicinc.com> (raw)
In-Reply-To: <20220928195633.2348848-1-quic_eberman@quicinc.com>

Gunyah message queues are a unidirectional inter-VM pipe for messages up
to 1024 bytes. This driver supports pairing a receiver message queue and
a transmitter message queue to expose a single mailbox channel.

Signed-off-by: Elliot Berman <quic_eberman@quicinc.com>
---
 MAINTAINERS                   |   2 +
 drivers/mailbox/Kconfig       |  10 ++
 drivers/mailbox/Makefile      |   2 +
 drivers/mailbox/gunyah-msgq.c | 232 ++++++++++++++++++++++++++++++++++
 drivers/virt/gunyah/Kconfig   |   2 +
 include/linux/gunyah.h        |  67 ++++++++++
 6 files changed, 315 insertions(+)
 create mode 100644 drivers/mailbox/gunyah-msgq.c
 create mode 100644 include/linux/gunyah.h

diff --git a/MAINTAINERS b/MAINTAINERS
index a26e67ef36b4..74053d8ff7ea 100644
--- a/MAINTAINERS
+++ b/MAINTAINERS
@@ -8889,8 +8889,10 @@ F:	Documentation/ABI/testing/sysfs-hypervisor-gunyah
 F:	Documentation/devicetree/bindings/firmware/gunyah-hypervisor.yaml
 F:	Documentation/virt/gunyah/
 F:	arch/arm64/gunyah/
+F:	drivers/mailbox/gunyah-msgq.c
 F:	drivers/virt/gunyah/
 F:	include/asm-generic/gunyah.h
+F:	include/linux/gunyah.h
 
 HABANALABS PCI DRIVER
 M:	Oded Gabbay <ogabbay@kernel.org>
diff --git a/drivers/mailbox/Kconfig b/drivers/mailbox/Kconfig
index 05d6fae800e3..baf9451c5f04 100644
--- a/drivers/mailbox/Kconfig
+++ b/drivers/mailbox/Kconfig
@@ -41,6 +41,16 @@ config IMX_MBOX
 	help
 	  Mailbox implementation for i.MX Messaging Unit (MU).
 
+config GUNYAH_MESSAGE_QUEUES
+	tristate "Gunyah Message Queue Mailbox"
+	depends on GUNYAH
+	help
+	  Mailbox implementation for Gunyah Message Queues. Gunyah message queues
+	  are an IPC mechanism to pass short messages between virtual machines
+	  running under the Gunyah hypervisor.
+
+	  Say Y here if you run Linux as a Gunyah virtual machine.
+
 config PLATFORM_MHU
 	tristate "Platform MHU Mailbox"
 	depends on OF
diff --git a/drivers/mailbox/Makefile b/drivers/mailbox/Makefile
index fc9376117111..5f929bb55e9a 100644
--- a/drivers/mailbox/Makefile
+++ b/drivers/mailbox/Makefile
@@ -55,6 +55,8 @@ obj-$(CONFIG_MTK_CMDQ_MBOX)	+= mtk-cmdq-mailbox.o
 
 obj-$(CONFIG_ZYNQMP_IPI_MBOX)	+= zynqmp-ipi-mailbox.o
 
+obj-$(CONFIG_GUNYAH)		+= gunyah-msgq.o
+
 obj-$(CONFIG_SUN6I_MSGBOX)	+= sun6i-msgbox.o
 
 obj-$(CONFIG_SPRD_MBOX)		+= sprd-mailbox.o
diff --git a/drivers/mailbox/gunyah-msgq.c b/drivers/mailbox/gunyah-msgq.c
new file mode 100644
index 000000000000..359f682d101c
--- /dev/null
+++ b/drivers/mailbox/gunyah-msgq.c
@@ -0,0 +1,232 @@
+// SPDX-License-Identifier: GPL-2.0-only
+/*
+ * Copyright (c) 2022 Qualcomm Innovation Center, Inc. All rights reserved.
+ */
+
+#include <linux/mailbox_controller.h>
+#include <linux/interrupt.h>
+#include <linux/gunyah.h>
+#include <linux/printk.h>
+#include <linux/init.h>
+#include <linux/slab.h>
+#include <linux/wait.h>
+
+#define mbox_chan_to_msgq(chan) (container_of(chan->mbox, struct gunyah_msgq, mbox))
+
+static inline bool gh_msgq_has_tx(struct gunyah_msgq *msgq)
+{
+	return msgq->tx_ghrsc.type == GUNYAH_RESOURCE_TYPE_MSGQ_TX;
+}
+
+static inline bool gh_msgq_has_rx(struct gunyah_msgq *msgq)
+{
+	return msgq->rx_ghrsc.type == GUNYAH_RESOURCE_TYPE_MSGQ_RX;
+}
+
+static ssize_t __gh_msgq_recv(struct gunyah_msgq *msgq, void *buff, size_t size, bool *ready)
+{
+	unsigned long gh_err;
+	size_t recv_size;
+	ssize_t ret;
+
+	gh_err = gh_hypercall_msgq_recv(msgq->rx_ghrsc.capid, (uintptr_t)buff, size,
+					&recv_size, ready);
+	switch (gh_err) {
+	case GH_ERROR_OK:
+		ret = recv_size;
+		break;
+	case GH_ERROR_MSGQUEUE_EMPTY:
+		ret = -EAGAIN;
+		*ready = false;
+		break;
+	default:
+		ret = gh_remap_error(gh_err);
+		break;
+	}
+
+	return ret;
+}
+
+static irqreturn_t gh_msgq_rx_irq_handler(int irq, void *data)
+{
+	struct gunyah_msgq *msgq = data;
+	struct gunyah_msgq_rx_data rx_data;
+	ssize_t ret;
+	bool more;
+
+	do {
+		ret = __gh_msgq_recv(msgq, &rx_data.data, sizeof(rx_data.data), &more);
+
+		if (ret >= 0) {
+			rx_data.length = ret;
+			mbox_chan_received_data(gunyah_msgq_chan(msgq), &rx_data);
+		} else if (ret != -EAGAIN)
+			pr_warn("Failed to receive data from msgq for %s: %ld\n",
+				msgq->mbox.dev ? dev_name(msgq->mbox.dev) : "", ret);
+	} while (ret >= 0 && more);
+
+	return IRQ_HANDLED;
+}
+
+static irqreturn_t gh_msgq_tx_irq_handler(int irq, void *data)
+{
+	struct gunyah_msgq *msgq = data;
+
+	mbox_chan_txdone(gunyah_msgq_chan(msgq), 0);
+
+	return IRQ_HANDLED;
+}
+
+static void gh_msgq_txdone_tasklet(unsigned long data)
+{
+	struct gunyah_msgq *msgq = (struct gunyah_msgq *)data;
+
+	mbox_chan_txdone(gunyah_msgq_chan(msgq), msgq->last_status);
+}
+
+static int __gh_msgq_send(struct gunyah_msgq *msgq, void *buff, size_t size, u64 tx_flags)
+{
+	unsigned long gh_err;
+	ssize_t ret;
+	bool ready;
+
+	gh_err = gh_hypercall_msgq_send(msgq->tx_ghrsc.capid, size, (uintptr_t)buff, tx_flags,
+					&ready);
+	switch (gh_err) {
+	case GH_ERROR_OK:
+		ret = !ready;
+		break;
+	case GH_ERROR_MSGQUEUE_FULL:
+		ret = -EAGAIN;
+		break;
+	default:
+		/* Not sure how to propagate these out to client. If we get here, nobody is going
+		 * to trigger a retry
+		 */
+		ret = gh_remap_error(gh_err);
+		break;
+	}
+
+	return ret;
+}
+
+static int gh_msgq_send_data(struct mbox_chan *chan, void *data)
+{
+	struct gunyah_msgq *msgq = mbox_chan_to_msgq(chan);
+	struct gunyah_msgq_tx_data *msgq_data = data;
+	u64 tx_flags = 0;
+	int ret;
+
+	if (msgq_data->push)
+		tx_flags |= GH_HYPERCALL_MSGQ_TX_FLAGS_PUSH;
+
+	ret = __gh_msgq_send(msgq, msgq_data->data, msgq_data->length, tx_flags);
+
+	/**
+	 * EAGAIN: message didn't send.
+	 * ret = 1: message sent, but now the message queue is full and we can't send any more msgs.
+	 * Either way, don't report that this message is done.
+	 */
+	if (ret == -EAGAIN || ret == 1)
+		return ret;
+
+	/**
+	 * Mailbox framework requires that tx done happens asynchronously to sending the message
+	 * IOW, a notification that the message was sent happens after sending the message.
+	 * To work around this, defer the txdone to a tasklet.
+	 */
+	msgq->last_status = ret;
+	tasklet_schedule(&msgq->txdone_tasklet);
+
+	return 0;
+}
+
+struct mbox_chan_ops gunyah_msgq_ops = {
+	.send_data = gh_msgq_send_data,
+};
+
+/**
+ * gunyah_msgq_init() - Initialize a Gunyah message queue with an mbox_client
+ * @parent: optional, device parent used for the mailbox controller
+ * @msgq: Pointer to the gunyah_msgq to initialize
+ * @cl: A mailbox client to bind to the mailbox channel that the message queue creates
+ * @tx_ghrsc: optional, the transmission side of the message queue
+ * @rx_ghrsc: optional, the receiving side of the message queue
+ *
+ * At least one of tx_ghrsc and rx_ghrsc should be not NULL. Most message queue use cases come with
+ * a pair of message queues to facilitiate bidirectional communication. When tx_ghrsc is set,
+ * the client can send messages with mbox_send_message(gunyah_msgq_chan(msgq), msg). When rx_ghrsc
+ * is set, the mbox_client should register an .rx_callback() and the message queue driver will
+ * push all available messages upon receiving the RX ready interrupt. The messages should be
+ * consumed or copied by the client right away as the gunyah_msgq_rx_data will be replaced/destroyed
+ * after the callback.
+ *
+ * Returns - 0 on success, negative otherwise
+ */
+int gunyah_msgq_init(struct device *parent, struct gunyah_msgq *msgq, struct mbox_client *cl,
+		     struct gunyah_resource *tx_ghrsc, struct gunyah_resource *rx_ghrsc)
+{
+	int ret;
+
+	/* Must have at least a tx_ghrsc or rx_ghrsc and that they are the right device types */
+	if ((!tx_ghrsc && !rx_ghrsc) ||
+	    (tx_ghrsc && tx_ghrsc->type != GUNYAH_RESOURCE_TYPE_MSGQ_TX) ||
+	    (rx_ghrsc && rx_ghrsc->type != GUNYAH_RESOURCE_TYPE_MSGQ_RX))
+		return -EINVAL;
+
+	msgq->tx_ghrsc = *tx_ghrsc;
+	msgq->rx_ghrsc = *rx_ghrsc;
+
+	msgq->mbox.dev = parent;
+	msgq->mbox.ops = &gunyah_msgq_ops;
+	msgq->mbox.chans = kcalloc(1, sizeof(*msgq->mbox.chans), GFP_KERNEL);
+	msgq->mbox.num_chans = 1;
+	msgq->mbox.txdone_irq = true;
+
+	if (gh_msgq_has_tx(msgq)) {
+		ret = request_irq(msgq->tx_ghrsc.irq, gh_msgq_tx_irq_handler, 0, "gh_msgq_tx",
+				msgq);
+		if (ret)
+			goto err_chans;
+	}
+
+	if (gh_msgq_has_rx(msgq)) {
+		ret = request_threaded_irq(msgq->rx_ghrsc.irq, NULL, gh_msgq_rx_irq_handler,
+						IRQF_ONESHOT, "gh_msgq_rx", msgq);
+		if (ret)
+			goto err_tx_irq;
+	}
+
+	tasklet_init(&msgq->txdone_tasklet, gh_msgq_txdone_tasklet, (unsigned long)msgq);
+
+	ret = mbox_controller_register(&msgq->mbox);
+	if (ret)
+		goto err_rx_irq;
+
+	ret = mbox_bind_client(gunyah_msgq_chan(msgq), cl);
+	if (ret)
+		goto err_mbox;
+
+	return 0;
+err_mbox:
+	mbox_controller_unregister(&msgq->mbox);
+err_rx_irq:
+	if (gh_msgq_has_rx(msgq))
+		free_irq(msgq->rx_ghrsc.irq, msgq);
+err_tx_irq:
+	if (gh_msgq_has_tx(msgq))
+		free_irq(msgq->tx_ghrsc.irq, msgq);
+err_chans:
+	kfree(msgq->mbox.chans);
+	return ret;
+}
+EXPORT_SYMBOL_GPL(gunyah_msgq_init);
+
+void gunyah_msgq_remove(struct gunyah_msgq *msgq)
+{
+	if (gh_msgq_has_tx(msgq))
+		free_irq(msgq->tx_ghrsc.irq, msgq);
+
+	kfree(msgq->mbox.chans);
+}
+EXPORT_SYMBOL_GPL(gunyah_msgq_remove);
diff --git a/drivers/virt/gunyah/Kconfig b/drivers/virt/gunyah/Kconfig
index 7ac917e0aa3f..f4c822a82f1a 100644
--- a/drivers/virt/gunyah/Kconfig
+++ b/drivers/virt/gunyah/Kconfig
@@ -4,6 +4,8 @@ config GUNYAH
 	tristate "Gunyah Virtualization drivers"
 	depends on ARM64
 	select AUXILIARY_BUS
+	select MAILBOX
+	select GUNYAH_MESSAGE_QUEUES
 	help
 	  The Gunyah drivers are the helper interfaces that runs in a guest VM
 	  such as basic inter-VM IPC and signaling mechanisms, and higher level
diff --git a/include/linux/gunyah.h b/include/linux/gunyah.h
new file mode 100644
index 000000000000..d5e80e2defab
--- /dev/null
+++ b/include/linux/gunyah.h
@@ -0,0 +1,67 @@
+/* SPDX-License-Identifier: GPL-2.0-only */
+/*
+ * Copyright (c) 2022 Qualcomm Innovation Center, Inc. All rights reserved.
+ */
+
+#ifndef _GUNYAH_H
+#define _GUNYAH_H
+
+#include <linux/mailbox_controller.h>
+#include <linux/mailbox_client.h>
+#include <linux/interrupt.h>
+
+#include <asm-generic/gunyah.h>
+
+/* Follows resource manager's resource types for VM_GET_HYP_RESOURCES */
+enum gunyah_resource_type {
+	GUNYAH_RESOURCE_TYPE_BELL_TX	= 0,
+	GUNYAH_RESOURCE_TYPE_BELL_RX	= 1,
+	GUNYAH_RESOURCE_TYPE_MSGQ_TX	= 2,
+	GUNYAH_RESOURCE_TYPE_MSGQ_RX	= 3,
+	GUNYAH_RESOURCE_TYPE_VCPU	= 4,
+};
+
+struct gunyah_resource {
+	enum gunyah_resource_type type;
+	u64 capid;
+	int irq;
+};
+
+/**
+ * Gunyah Message Queues
+ */
+
+#define GH_MSGQ_MAX_MSG_SIZE	1024
+
+struct gunyah_msgq_tx_data {
+	size_t length;
+	bool push;
+	char data[];
+};
+
+struct gunyah_msgq_rx_data {
+	size_t length;
+	char data[GH_MSGQ_MAX_MSG_SIZE];
+};
+
+struct gunyah_msgq {
+	struct gunyah_resource tx_ghrsc;
+	struct gunyah_resource rx_ghrsc;
+
+	/* msgq private */
+	int last_status;
+	struct mbox_controller mbox;
+	struct tasklet_struct txdone_tasklet;
+};
+
+
+int gunyah_msgq_init(struct device *parent, struct gunyah_msgq *msgq, struct mbox_client *cl,
+		     struct gunyah_resource *tx_ghrsc, struct gunyah_resource *rx_ghrsc);
+void gunyah_msgq_remove(struct gunyah_msgq *msgq);
+
+static inline struct mbox_chan *gunyah_msgq_chan(struct gunyah_msgq *msgq)
+{
+	return &msgq->mbox.chans[0];
+}
+
+#endif
-- 
2.25.1


_______________________________________________
linux-arm-kernel mailing list
linux-arm-kernel@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/linux-arm-kernel

  parent reply	other threads:[~2022-09-28 19:57 UTC|newest]

Thread overview: 102+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2022-09-28 19:56 [PATCH v4 00/14] Drivers for gunyah hypervisor Elliot Berman
2022-09-28 19:56 ` Elliot Berman
2022-09-28 19:56 ` [PATCH v4 01/14] docs: gunyah: Introduce Gunyah Hypervisor Elliot Berman
2022-09-28 19:56   ` Elliot Berman
2022-09-29  3:43   ` Bagas Sanjaya
2022-09-29  3:43     ` Bagas Sanjaya
2022-09-29  4:02     ` Elliot Berman
2022-09-29  4:02       ` Elliot Berman
2022-09-28 19:56 ` [PATCH v4 02/14] dt-bindings: Add binding for gunyah hypervisor Elliot Berman
2022-09-28 19:56   ` Elliot Berman
2022-09-28 19:56 ` [PATCH v4 03/14] gunyah: Common types and error codes for Gunyah hypercalls Elliot Berman
2022-09-28 19:56   ` Elliot Berman
2022-09-28 19:56 ` [PATCH v4 04/14] arm64: smccc: Include alternative-macros.h Elliot Berman
2022-09-28 19:56   ` Elliot Berman
2022-09-28 19:56 ` [PATCH v4 05/14] virt: gunyah: Add hypercalls to identify Gunyah Elliot Berman
2022-09-28 19:56   ` Elliot Berman
2022-09-28 19:56 ` [PATCH v4 06/14] virt: gunyah: Add sysfs nodes Elliot Berman
2022-09-28 19:56   ` Elliot Berman
2022-09-30 12:09   ` Greg Kroah-Hartman
2022-09-30 12:09     ` Greg Kroah-Hartman
2022-10-04 23:50     ` Elliot Berman
2022-10-04 23:50       ` Elliot Berman
2022-10-05  6:23       ` Greg Kroah-Hartman
2022-10-05  6:23         ` Greg Kroah-Hartman
2022-09-28 19:56 ` [PATCH v4 07/14] mailbox: Allow direct registration to a channel Elliot Berman
2022-09-28 19:56   ` Elliot Berman
2022-09-28 19:56 ` [PATCH v4 08/14] virt: gunyah: msgq: Add hypercalls to send and receive messages Elliot Berman
2022-09-28 19:56   ` Elliot Berman
2022-09-28 19:56 ` Elliot Berman [this message]
2022-09-28 19:56   ` [PATCH v4 09/14] mailbox: Add Gunyah message queue mailbox Elliot Berman
2022-09-29 16:59   ` Bjorn Andersson
2022-09-29 16:59     ` Bjorn Andersson
2022-09-29 17:37     ` Jassi Brar
2022-09-29 17:37       ` Jassi Brar
2022-09-28 19:56 ` [PATCH v4 10/14] gunyah: sysfs: Add node to describe supported features Elliot Berman
2022-09-28 19:56   ` Elliot Berman
2022-09-29  7:36   ` Joe Perches
2022-09-29  7:36     ` Joe Perches
2022-09-29 20:47     ` Elliot Berman
2022-09-29 20:47       ` Elliot Berman
2022-10-02 23:30     ` Jeff Johnson
2022-10-02 23:30       ` Jeff Johnson
2022-10-02 23:58       ` Joe Perches
2022-10-02 23:58         ` Joe Perches
2022-09-30 12:06   ` Greg Kroah-Hartman
2022-09-30 12:06     ` Greg Kroah-Hartman
2022-10-04 23:53     ` Elliot Berman
2022-10-04 23:53       ` Elliot Berman
2022-09-28 19:56 ` [PATCH v4 11/14] gunyah: rsc_mgr: Add resource manager RPC core Elliot Berman
2022-09-28 19:56   ` Elliot Berman
2022-09-28 19:56 ` [PATCH v4 12/14] gunyah: rsc_mgr: Add RPC for console services Elliot Berman
2022-09-28 19:56   ` Elliot Berman
2022-09-30 12:22   ` Greg Kroah-Hartman
2022-09-30 12:22     ` Greg Kroah-Hartman
2022-10-03  1:46     ` new checkpatch flexible array test ? (was Re: [PATCH v4 12/14] gunyah: rsc_mgr: Add RPC for console services) Joe Perches
2022-10-03  1:46       ` Joe Perches
2022-10-03  5:29       ` Greg Kroah-Hartman
2022-10-03  5:29         ` Greg Kroah-Hartman
2022-10-03  5:38         ` Joe Perches
2022-10-03  5:38           ` Joe Perches
2022-10-31 18:23           ` Gustavo A. R. Silva
2022-10-31 18:23             ` Gustavo A. R. Silva
2022-09-28 19:56 ` [PATCH v4 13/14] gunyah: rsc_mgr: Add auxiliary devices for console Elliot Berman
2022-09-28 19:56   ` Elliot Berman
2022-09-30 12:19   ` Greg Kroah-Hartman
2022-09-30 12:19     ` Greg Kroah-Hartman
2022-10-04 23:49     ` Elliot Berman
2022-10-04 23:49       ` Elliot Berman
2022-10-05  6:21       ` Greg Kroah-Hartman
2022-10-05  6:21         ` Greg Kroah-Hartman
2022-10-05 21:47         ` Elliot Berman
2022-10-05 21:47           ` Elliot Berman
2022-10-06  6:28           ` Greg Kroah-Hartman
2022-10-06  6:28             ` Greg Kroah-Hartman
2022-09-28 19:56 ` [PATCH v4 14/14] tty: gunyah: Add tty console driver for RM Console Services Elliot Berman
2022-09-28 19:56   ` Elliot Berman
2022-09-30 12:17   ` Greg Kroah-Hartman
2022-09-30 12:17     ` Greg Kroah-Hartman
2022-10-07  5:59     ` Elliot Berman
2022-10-07  5:59       ` Elliot Berman
2022-10-07  7:40       ` Greg Kroah-Hartman
2022-10-07  7:40         ` Greg Kroah-Hartman
2022-10-09 20:59         ` Elliot Berman
2022-10-09 20:59           ` Elliot Berman
2022-10-10 20:23           ` Greg Kroah-Hartman
2022-10-10 20:23             ` Greg Kroah-Hartman
2022-10-10 20:58             ` Elliot Berman
2022-10-10 20:58               ` Elliot Berman
2022-10-11  6:22               ` Greg Kroah-Hartman
2022-10-11  6:22                 ` Greg Kroah-Hartman
2022-10-11 22:04                 ` Elliot Berman
2022-10-11 22:04                   ` Elliot Berman
2022-10-12  6:53                   ` Greg Kroah-Hartman
2022-10-12  6:53                     ` Greg Kroah-Hartman
2022-10-08  7:41     ` Zhou Furong
2022-10-08  7:41       ` Zhou Furong
2022-10-08  9:52       ` Greg Kroah-Hartman
2022-10-08  9:52         ` Greg Kroah-Hartman
2022-10-03  7:01   ` Jiri Slaby
2022-10-03  7:01     ` Jiri Slaby
2022-10-10 18:06     ` Elliot Berman
2022-10-10 18:06       ` Elliot Berman

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=20220928195633.2348848-10-quic_eberman@quicinc.com \
    --to=quic_eberman@quicinc.com \
    --cc=agross@kernel.org \
    --cc=arnd@arndb.de \
    --cc=catalin.marinas@arm.com \
    --cc=corbet@lwn.net \
    --cc=devicetree@vger.kernel.org \
    --cc=dmitry.baryshkov@linaro.org \
    --cc=gregkh@linuxfoundation.org \
    --cc=jassisinghbrar@gmail.com \
    --cc=krzysztof.kozlowski+dt@linaro.org \
    --cc=linux-arm-kernel@lists.infradead.org \
    --cc=linux-arm-msm@vger.kernel.org \
    --cc=linux-doc@vger.kernel.org \
    --cc=linux-kernel@vger.kernel.org \
    --cc=lorenzo.pieralisi@arm.com \
    --cc=mark.rutland@arm.com \
    --cc=maz@kernel.org \
    --cc=quic_bjorande@quicinc.com \
    --cc=quic_cvanscha@quicinc.com \
    --cc=quic_mnalajal@quicinc.com \
    --cc=quic_svaddagi@quicinc.com \
    --cc=quic_tsoni@quicinc.com \
    --cc=robh+dt@kernel.org \
    --cc=sudeep.holla@arm.com \
    --cc=will@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 an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.