linux-mm.kvack.org archive mirror
 help / color / mirror / Atom feed
From: Elliot Berman <quic_eberman@quicinc.com>
To: Alex Elder <elder@linaro.org>,
	Srinivas Kandagatla <srinivas.kandagatla@linaro.org>,
	Murali Nalajal <quic_mnalajal@quicinc.com>,
	Trilok Soni <quic_tsoni@quicinc.com>,
	Srivatsa Vaddagiri <quic_svaddagi@quicinc.com>,
	Carl van Schaik <quic_cvanscha@quicinc.com>,
	Philip Derrin <quic_pderrin@quicinc.com>,
	Prakruthi Deepak Heragu <quic_pheragu@quicinc.com>,
	Jonathan Corbet <corbet@lwn.net>,
	Rob Herring <robh+dt@kernel.org>,
	Krzysztof Kozlowski <krzysztof.kozlowski+dt@linaro.org>,
	Conor Dooley <conor+dt@kernel.org>,
	Catalin Marinas <catalin.marinas@arm.com>,
	Will Deacon <will@kernel.org>,
	Konrad Dybcio <konrad.dybcio@linaro.org>,
	Bjorn Andersson <andersson@kernel.org>,
	Dmitry Baryshkov <dmitry.baryshkov@linaro.org>,
	"Fuad Tabba" <tabba@google.com>,
	Sean Christopherson <seanjc@google.com>,
	"Andrew Morton" <akpm@linux-foundation.org>
Cc: <linux-arm-msm@vger.kernel.org>, <linux-doc@vger.kernel.org>,
	<linux-kernel@vger.kernel.org>, <devicetree@vger.kernel.org>,
	<linux-arm-kernel@lists.infradead.org>, <linux-mm@kvack.org>,
	Elliot Berman <quic_eberman@quicinc.com>
Subject: [PATCH v16 31/34] virt: gunyah: Add irqfd interface
Date: Tue, 9 Jan 2024 11:38:09 -0800	[thread overview]
Message-ID: <20240109-gunyah-v16-31-634904bf4ce9@quicinc.com> (raw)
In-Reply-To: <20240109-gunyah-v16-0-634904bf4ce9@quicinc.com>

Enable support for creating irqfds which can raise an interrupt on a
Gunyah virtual machine. irqfds are exposed to userspace as a Gunyah VM
function with the name "irqfd". If the VM devicetree is not configured
to create a doorbell with the corresponding label, userspace will still
be able to assert the eventfd but no interrupt will be raised on the
guest.

Acked-by: Alex Elder <elder@linaro.org>
Co-developed-by: Prakruthi Deepak Heragu <quic_pheragu@quicinc.com>
Signed-off-by: Prakruthi Deepak Heragu <quic_pheragu@quicinc.com>
Signed-off-by: Elliot Berman <quic_eberman@quicinc.com>
---
 drivers/virt/gunyah/Kconfig        |   9 ++
 drivers/virt/gunyah/Makefile       |   1 +
 drivers/virt/gunyah/gunyah_irqfd.c | 190 +++++++++++++++++++++++++++++++++++++
 include/uapi/linux/gunyah.h        |  35 +++++++
 4 files changed, 235 insertions(+)

diff --git a/drivers/virt/gunyah/Kconfig b/drivers/virt/gunyah/Kconfig
index fe2823dc48ba..1685b75fb77a 100644
--- a/drivers/virt/gunyah/Kconfig
+++ b/drivers/virt/gunyah/Kconfig
@@ -27,3 +27,12 @@ config GUNYAH_QCOM_PLATFORM
 	  extra platform-specific support.
 
 	  Say Y/M here to use Gunyah on Qualcomm platforms.
+
+config GUNYAH_IRQFD
+	tristate "Gunyah irqfd interface"
+	depends on GUNYAH
+	help
+	  Enable kernel support for creating irqfds which can raise an interrupt
+	  on Gunyah virtual machine.
+
+	  Say Y/M here if unsure and you want to support Gunyah VMMs.
diff --git a/drivers/virt/gunyah/Makefile b/drivers/virt/gunyah/Makefile
index c4505fce177d..b41b02792921 100644
--- a/drivers/virt/gunyah/Makefile
+++ b/drivers/virt/gunyah/Makefile
@@ -5,3 +5,4 @@ gunyah_rsc_mgr-y += rsc_mgr.o rsc_mgr_rpc.o vm_mgr.o vm_mgr_mem.o guest_memfd.o
 obj-$(CONFIG_GUNYAH) += gunyah.o gunyah_rsc_mgr.o gunyah_vcpu.o
 obj-$(CONFIG_GUNYAH_PLATFORM_HOOKS) += gunyah_platform_hooks.o
 obj-$(CONFIG_GUNYAH_QCOM_PLATFORM) += gunyah_qcom.o
+obj-$(CONFIG_GUNYAH_IRQFD) += gunyah_irqfd.o
diff --git a/drivers/virt/gunyah/gunyah_irqfd.c b/drivers/virt/gunyah/gunyah_irqfd.c
new file mode 100644
index 000000000000..030af9069639
--- /dev/null
+++ b/drivers/virt/gunyah/gunyah_irqfd.c
@@ -0,0 +1,190 @@
+// SPDX-License-Identifier: GPL-2.0-only
+/*
+ * Copyright (c) 2022-2024 Qualcomm Innovation Center, Inc. All rights reserved.
+ */
+
+#include <linux/eventfd.h>
+#include <linux/device/driver.h>
+#include <linux/file.h>
+#include <linux/fs.h>
+#include <linux/gunyah.h>
+#include <linux/module.h>
+#include <linux/poll.h>
+#include <linux/printk.h>
+
+#include <uapi/linux/gunyah.h>
+
+struct gunyah_irqfd {
+	struct gunyah_resource *ghrsc;
+	struct gunyah_vm_resource_ticket ticket;
+	struct gunyah_vm_function_instance *f;
+
+	bool level;
+
+	struct eventfd_ctx *ctx;
+	wait_queue_entry_t wait;
+	poll_table pt;
+};
+
+static int irqfd_wakeup(wait_queue_entry_t *wait, unsigned int mode, int sync,
+			void *key)
+{
+	struct gunyah_irqfd *irqfd =
+		container_of(wait, struct gunyah_irqfd, wait);
+	__poll_t flags = key_to_poll(key);
+	int ret = 0;
+
+	if (flags & EPOLLIN) {
+		if (irqfd->ghrsc) {
+			ret = gunyah_hypercall_bell_send(irqfd->ghrsc->capid, 1,
+							 NULL);
+			if (ret)
+				pr_err_ratelimited(
+					"Failed to inject interrupt %d: %d\n",
+					irqfd->ticket.label, ret);
+		} else
+			pr_err_ratelimited(
+				"Premature injection of interrupt\n");
+	}
+
+	return 0;
+}
+
+static void irqfd_ptable_queue_proc(struct file *file, wait_queue_head_t *wqh,
+				    poll_table *pt)
+{
+	struct gunyah_irqfd *irq_ctx =
+		container_of(pt, struct gunyah_irqfd, pt);
+
+	add_wait_queue(wqh, &irq_ctx->wait);
+}
+
+static bool gunyah_irqfd_populate(struct gunyah_vm_resource_ticket *ticket,
+				  struct gunyah_resource *ghrsc)
+{
+	struct gunyah_irqfd *irqfd =
+		container_of(ticket, struct gunyah_irqfd, ticket);
+	int ret;
+
+	if (irqfd->ghrsc) {
+		pr_warn("irqfd%d already got a Gunyah resource. Check if multiple resources with same label were configured.\n",
+			irqfd->ticket.label);
+		return false;
+	}
+
+	irqfd->ghrsc = ghrsc;
+	if (irqfd->level) {
+		/* Configure the bell to trigger when bit 0 is asserted (see
+		 * irq_wakeup) and for bell to automatically clear bit 0 once
+		 * received by the VM (ack_mask).  need to make sure bit 0 is cleared right away,
+		 * otherwise the line will never be deasserted. Emulating edge
+		 * trigger interrupt does not need to set either mask
+		 * because irq is listed only once per gunyah_hypercall_bell_send
+		 */
+		ret = gunyah_hypercall_bell_set_mask(irqfd->ghrsc->capid, 1, 1);
+		if (ret)
+			pr_warn("irq %d couldn't be set as level triggered. Might cause IRQ storm if asserted\n",
+				irqfd->ticket.label);
+	}
+
+	return true;
+}
+
+static void gunyah_irqfd_unpopulate(struct gunyah_vm_resource_ticket *ticket,
+				    struct gunyah_resource *ghrsc)
+{
+	struct gunyah_irqfd *irqfd =
+		container_of(ticket, struct gunyah_irqfd, ticket);
+	u64 cnt;
+
+	eventfd_ctx_remove_wait_queue(irqfd->ctx, &irqfd->wait, &cnt);
+}
+
+static long gunyah_irqfd_bind(struct gunyah_vm_function_instance *f)
+{
+	struct gunyah_fn_irqfd_arg *args = f->argp;
+	struct gunyah_irqfd *irqfd;
+	__poll_t events;
+	struct fd fd;
+	long r;
+
+	if (f->arg_size != sizeof(*args))
+		return -EINVAL;
+
+	/* All other flag bits are reserved for future use */
+	if (args->flags & ~GUNYAH_IRQFD_FLAGS_LEVEL)
+		return -EINVAL;
+
+	irqfd = kzalloc(sizeof(*irqfd), GFP_KERNEL);
+	if (!irqfd)
+		return -ENOMEM;
+
+	irqfd->f = f;
+	f->data = irqfd;
+
+	fd = fdget(args->fd);
+	if (!fd.file) {
+		kfree(irqfd);
+		return -EBADF;
+	}
+
+	irqfd->ctx = eventfd_ctx_fileget(fd.file);
+	if (IS_ERR(irqfd->ctx)) {
+		r = PTR_ERR(irqfd->ctx);
+		goto err_fdput;
+	}
+
+	if (args->flags & GUNYAH_IRQFD_FLAGS_LEVEL)
+		irqfd->level = true;
+
+	init_waitqueue_func_entry(&irqfd->wait, irqfd_wakeup);
+	init_poll_funcptr(&irqfd->pt, irqfd_ptable_queue_proc);
+
+	irqfd->ticket.resource_type = GUNYAH_RESOURCE_TYPE_BELL_TX;
+	irqfd->ticket.label = args->label;
+	irqfd->ticket.owner = THIS_MODULE;
+	irqfd->ticket.populate = gunyah_irqfd_populate;
+	irqfd->ticket.unpopulate = gunyah_irqfd_unpopulate;
+
+	r = gunyah_vm_add_resource_ticket(f->ghvm, &irqfd->ticket);
+	if (r)
+		goto err_ctx;
+
+	events = vfs_poll(fd.file, &irqfd->pt);
+	if (events & EPOLLIN)
+		pr_warn("Premature injection of interrupt\n");
+	fdput(fd);
+
+	return 0;
+err_ctx:
+	eventfd_ctx_put(irqfd->ctx);
+err_fdput:
+	fdput(fd);
+	kfree(irqfd);
+	return r;
+}
+
+static void gunyah_irqfd_unbind(struct gunyah_vm_function_instance *f)
+{
+	struct gunyah_irqfd *irqfd = f->data;
+
+	gunyah_vm_remove_resource_ticket(irqfd->f->ghvm, &irqfd->ticket);
+	eventfd_ctx_put(irqfd->ctx);
+	kfree(irqfd);
+}
+
+static bool gunyah_irqfd_compare(const struct gunyah_vm_function_instance *f,
+				 const void *arg, size_t size)
+{
+	const struct gunyah_fn_irqfd_arg *instance = f->argp, *other = arg;
+
+	if (sizeof(*other) != size)
+		return false;
+
+	return instance->label == other->label;
+}
+
+DECLARE_GUNYAH_VM_FUNCTION_INIT(irqfd, GUNYAH_FN_IRQFD, 2, gunyah_irqfd_bind,
+				gunyah_irqfd_unbind, gunyah_irqfd_compare);
+MODULE_DESCRIPTION("Gunyah irqfd VM Function");
+MODULE_LICENSE("GPL");
diff --git a/include/uapi/linux/gunyah.h b/include/uapi/linux/gunyah.h
index 574116f54472..cb7b0bb9bef3 100644
--- a/include/uapi/linux/gunyah.h
+++ b/include/uapi/linux/gunyah.h
@@ -63,9 +63,12 @@ struct gunyah_vm_dtb_config {
  * @GUNYAH_FN_VCPU: create a vCPU instance to control a vCPU
  *              &struct gunyah_fn_desc.arg is a pointer to &struct gunyah_fn_vcpu_arg
  *              Return: file descriptor to manipulate the vcpu.
+ * @GUNYAH_FN_IRQFD: register eventfd to assert a Gunyah doorbell
+ *               &struct gunyah_fn_desc.arg is a pointer to &struct gunyah_fn_irqfd_arg
  */
 enum gunyah_fn_type {
 	GUNYAH_FN_VCPU = 1,
+	GUNYAH_FN_IRQFD,
 };
 
 #define GUNYAH_FN_MAX_ARG_SIZE		256
@@ -85,6 +88,38 @@ struct gunyah_fn_vcpu_arg {
 	__u32 id;
 };
 
+/**
+ * enum gunyah_irqfd_flags - flags for use in gunyah_fn_irqfd_arg
+ * @GUNYAH_IRQFD_FLAGS_LEVEL: make the interrupt operate like a level triggered
+ *                        interrupt on guest side. Triggering IRQFD before
+ *                        guest handles the interrupt causes interrupt to
+ *                        stay asserted.
+ */
+enum gunyah_irqfd_flags {
+	GUNYAH_IRQFD_FLAGS_LEVEL		= 1UL << 0,
+};
+
+/**
+ * struct gunyah_fn_irqfd_arg - Arguments to create an irqfd function.
+ *
+ * Create this function with &GUNYAH_VM_ADD_FUNCTION using type &GUNYAH_FN_IRQFD.
+ *
+ * Allows setting an eventfd to directly trigger a guest interrupt.
+ * irqfd.fd specifies the file descriptor to use as the eventfd.
+ * irqfd.label corresponds to the doorbell label used in the guest VM's devicetree.
+ *
+ * @fd: an eventfd which when written to will raise a doorbell
+ * @label: Label of the doorbell created on the guest VM
+ * @flags: see &enum gunyah_irqfd_flags
+ * @padding: padding bytes
+ */
+struct gunyah_fn_irqfd_arg {
+	__u32 fd;
+	__u32 label;
+	__u32 flags;
+	__u32 padding;
+};
+
 /**
  * struct gunyah_fn_desc - Arguments to create a VM function
  * @type: Type of the function. See &enum gunyah_fn_type.

-- 
2.34.1



  parent reply	other threads:[~2024-01-09 19:39 UTC|newest]

Thread overview: 38+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2024-01-09 19:37 [PATCH v16 00/34] Drivers for Gunyah hypervisor Elliot Berman
2024-01-09 19:37 ` [PATCH v16 01/34] docs: gunyah: Introduce Gunyah Hypervisor Elliot Berman
2024-01-09 23:31   ` Randy Dunlap
2024-01-10  0:28     ` Elliot Berman
2024-01-10  0:31       ` Randy Dunlap
2024-01-09 19:37 ` [PATCH v16 02/34] dt-bindings: Add binding for gunyah hypervisor Elliot Berman
2024-01-09 19:37 ` [PATCH v16 03/34] gunyah: Common types and error codes for Gunyah hypercalls Elliot Berman
2024-01-09 19:37 ` [PATCH v16 04/34] virt: gunyah: Add hypercalls to identify Gunyah Elliot Berman
2024-01-09 19:37 ` [PATCH v16 05/34] virt: gunyah: Add hypervisor driver Elliot Berman
2024-01-09 19:37 ` [PATCH v16 06/34] virt: gunyah: msgq: Add hypercalls to send and receive messages Elliot Berman
2024-01-09 19:37 ` [PATCH v16 07/34] gunyah: rsc_mgr: Add resource manager RPC core Elliot Berman
2024-01-09 19:37 ` [PATCH v16 08/34] gunyah: vm_mgr: Introduce basic VM Manager Elliot Berman
2024-01-09 19:37 ` [PATCH v16 09/34] gunyah: rsc_mgr: Add VM lifecycle RPC Elliot Berman
2024-01-09 19:37 ` [PATCH v16 10/34] gunyah: vm_mgr: Add VM start/stop Elliot Berman
2024-01-09 19:37 ` [PATCH v16 11/34] virt: gunyah: Translate gh_rm_hyp_resource into gunyah_resource Elliot Berman
2024-01-09 19:37 ` [PATCH v16 12/34] virt: gunyah: Add resource tickets Elliot Berman
2024-01-09 19:37 ` [PATCH v16 13/34] gunyah: vm_mgr: Add framework for VM Functions Elliot Berman
2024-01-09 19:37 ` [PATCH v16 14/34] virt: gunyah: Add hypercalls for running a vCPU Elliot Berman
2024-01-09 19:37 ` [PATCH v16 15/34] virt: gunyah: Add proxy-scheduled vCPUs Elliot Berman
2024-01-09 19:37 ` [PATCH v16 16/34] gunyah: Add hypercalls for demand paging Elliot Berman
2024-01-09 19:37 ` [PATCH v16 17/34] gunyah: rsc_mgr: Add memory parcel RPC Elliot Berman
2024-01-09 19:37 ` [PATCH v16 18/34] virt: gunyah: Add interfaces to map memory into guest address space Elliot Berman
2024-01-09 19:37 ` [PATCH v16 19/34] gunyah: rsc_mgr: Add platform ops on mem_lend/mem_reclaim Elliot Berman
2024-01-09 19:37 ` [PATCH v16 20/34] virt: gunyah: Add Qualcomm Gunyah platform ops Elliot Berman
2024-01-09 19:37 ` [PATCH v16 21/34] virt: gunyah: Implement guestmemfd Elliot Berman
2024-01-09 19:38 ` [PATCH v16 22/34] virt: gunyah: Add ioctl to bind guestmem to VMs Elliot Berman
2024-01-09 19:38 ` [PATCH v16 23/34] virt: gunyah: guestmem: Initialize RM mem parcels from guestmem Elliot Berman
2024-01-09 19:38 ` [PATCH v16 24/34] virt: gunyah: Share guest VM dtb configuration to Gunyah Elliot Berman
2024-01-09 19:38 ` [PATCH v16 25/34] gunyah: rsc_mgr: Add RPC to enable demand paging Elliot Berman
2024-01-09 19:38 ` [PATCH v16 26/34] mm/interval_tree: Export iter_first/iter_next Elliot Berman
2024-01-09 19:38 ` [PATCH v16 27/34] virt: gunyah: Enable demand paging Elliot Berman
2024-01-09 19:38 ` [PATCH v16 28/34] gunyah: rsc_mgr: Add RPC to set VM boot context Elliot Berman
2024-01-09 19:38 ` [PATCH v16 29/34] virt: gunyah: Allow userspace to initialize context of primary vCPU Elliot Berman
2024-01-09 19:38 ` [PATCH v16 30/34] virt: gunyah: Add hypercalls for sending doorbell Elliot Berman
2024-01-09 19:38 ` Elliot Berman [this message]
2024-01-09 19:38 ` [PATCH v16 32/34] virt: gunyah: Add IO handlers Elliot Berman
2024-01-09 19:38 ` [PATCH v16 33/34] virt: gunyah: Add ioeventfd Elliot Berman
2024-01-09 19:38 ` [PATCH v16 34/34] MAINTAINERS: Add Gunyah hypervisor drivers section 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=20240109-gunyah-v16-31-634904bf4ce9@quicinc.com \
    --to=quic_eberman@quicinc.com \
    --cc=akpm@linux-foundation.org \
    --cc=andersson@kernel.org \
    --cc=catalin.marinas@arm.com \
    --cc=conor+dt@kernel.org \
    --cc=corbet@lwn.net \
    --cc=devicetree@vger.kernel.org \
    --cc=dmitry.baryshkov@linaro.org \
    --cc=elder@linaro.org \
    --cc=konrad.dybcio@linaro.org \
    --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=linux-mm@kvack.org \
    --cc=quic_cvanscha@quicinc.com \
    --cc=quic_mnalajal@quicinc.com \
    --cc=quic_pderrin@quicinc.com \
    --cc=quic_pheragu@quicinc.com \
    --cc=quic_svaddagi@quicinc.com \
    --cc=quic_tsoni@quicinc.com \
    --cc=robh+dt@kernel.org \
    --cc=seanjc@google.com \
    --cc=srinivas.kandagatla@linaro.org \
    --cc=tabba@google.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 a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox