Re: [PATCH v4 5/9] virt: geniezone: Add irqfd support

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

 



Il 09/06/23 10:52, Yi-De Wu ha scritto:
From: "Yingshiuan Pan" <yingshiuan.pan@xxxxxxxxxxxx>

irqfd enables other threads than vcpu threads to inject virtual
interrupt through irqfd asynchronously rather through ioctl interface.
This interface is necessary for VMM which creates separated thread for
IO handling or uses vhost devices.

Signed-off-by: Yingshiuan Pan <yingshiuan.pan@xxxxxxxxxxxx>
Signed-off-by: Liju Chen <liju-clr.chen@xxxxxxxxxxxx>
Signed-off-by: Yi-De Wu <yi-de.wu@xxxxxxxxxxxx>
---
  arch/arm64/geniezone/gzvm_arch_common.h |   6 +
  drivers/virt/geniezone/Makefile         |   4 +-
  drivers/virt/geniezone/gzvm_irqfd.c     | 537 ++++++++++++++++++++++++
  drivers/virt/geniezone/gzvm_main.c      |   3 +-
  drivers/virt/geniezone/gzvm_vcpu.c      |   1 +
  drivers/virt/geniezone/gzvm_vm.c        |  18 +
  include/linux/gzvm_drv.h                |  27 ++
  include/uapi/linux/gzvm.h               |  18 +
  8 files changed, 611 insertions(+), 3 deletions(-)
  create mode 100644 drivers/virt/geniezone/gzvm_irqfd.c

diff --git a/arch/arm64/geniezone/gzvm_arch_common.h b/arch/arm64/geniezone/gzvm_arch_common.h
index 1b315264bf24..5affa28b935a 100644
--- a/arch/arm64/geniezone/gzvm_arch_common.h
+++ b/arch/arm64/geniezone/gzvm_arch_common.h
@@ -46,6 +46,7 @@ enum {
  #define MT_HVC_GZVM_CREATE_DEVICE	GZVM_HCALL_ID(GZVM_FUNC_CREATE_DEVICE)
  #define MT_HVC_GZVM_PROBE		GZVM_HCALL_ID(GZVM_FUNC_PROBE)
  #define MT_HVC_GZVM_ENABLE_CAP		GZVM_HCALL_ID(GZVM_FUNC_ENABLE_CAP)
+#define GIC_V3_NR_LRS			16
/**
   * gzvm_hypercall_wrapper()
@@ -72,6 +73,11 @@ static inline gzvm_vcpu_id_t get_vcpuid_from_tuple(unsigned int tuple)
  	return (gzvm_vcpu_id_t)(tuple & 0xffff);
  }
+struct gzvm_vcpu_hwstate {

No documentation?

+	__u32 nr_lrs;
+	__u64 lr[GIC_V3_NR_LRS];
+};
+
  static inline unsigned int
  assemble_vm_vcpu_tuple(gzvm_id_t vmid, gzvm_vcpu_id_t vcpuid)
  {
diff --git a/drivers/virt/geniezone/Makefile b/drivers/virt/geniezone/Makefile
index 67ba3ed76ea7..aa52cee3ca8e 100644
--- a/drivers/virt/geniezone/Makefile
+++ b/drivers/virt/geniezone/Makefile
@@ -7,5 +7,5 @@
  GZVM_DIR ?= ../../../drivers/virt/geniezone
gzvm-y := $(GZVM_DIR)/gzvm_main.o $(GZVM_DIR)/gzvm_vm.o \
-	  $(GZVM_DIR)/gzvm_vcpu.o $(GZVM_DIR)/gzvm_irqchip.o
-
+	  $(GZVM_DIR)/gzvm_vcpu.o $(GZVM_DIR)/gzvm_irqchip.o \
+	  $(GZVM_DIR)/gzvm_irqfd.o
diff --git a/drivers/virt/geniezone/gzvm_irqfd.c b/drivers/virt/geniezone/gzvm_irqfd.c
new file mode 100644
index 000000000000..3a395b972fdf
--- /dev/null
+++ b/drivers/virt/geniezone/gzvm_irqfd.c
@@ -0,0 +1,537 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * Copyright (c) 2023 MediaTek Inc.
+ */
+
+#include <linux/eventfd.h>
+#include <linux/syscalls.h>
+#include <linux/gzvm_drv.h>
+#include "gzvm_common.h"
+
+struct gzvm_irq_ack_notifier {
+	struct hlist_node link;
+	unsigned int gsi;
+	void (*irq_acked)(struct gzvm_irq_ack_notifier *ian);
+};
+
+/**
+ * struct gzvm_kernel_irqfd_resampler - irqfd resampler descriptor.
+ * @gzvm: Poiner to gzvm.
+ * @list_head list: List of resampling struct _irqfd objects sharing this gsi.

This is just `@list`

+ *		    RCU list modified under gzvm->irqfds.resampler_lock.
+ * @notifier: gzvm irq ack notifier.
+ * @list_head link: Entry in list of gzvm->irqfd.resampler_list.

and this is `@link`.

+ *		    Use for sharing esamplers among irqfds on the same gsi.
+ *		    Accessed and modified under gzvm->irqfds.resampler_lock.
+ *
+ * Resampling irqfds are a special variety of irqfds used to emulate
+ * level triggered interrupts.  The interrupt is asserted on eventfd
+ * trigger.  On acknowledgment through the irq ack notifier, the
+ * interrupt is de-asserted and userspace is notified through the
+ * resamplefd.  All resamplers on the same gsi are de-asserted
+ * together, so we don't need to track the state of each individual
+ * user.  We can also therefore share the same irq source ID.
+ */
+struct gzvm_kernel_irqfd_resampler {
+	struct gzvm *gzvm;
+
+	struct list_head list;
+	struct gzvm_irq_ack_notifier notifier;
+
+	struct list_head link;
+};
+
+/**
+ * struct gzvm_kernel_irqfd: gzvm kernel irqfd descriptor.
+ * @gzvm: Pointer to gzvm.
+ * @wait: Wait queue entry.
+ * @gsi: Used for level IRQ fast-path.
+ * @resampler: The resampler used by this irqfd (resampler-only).
+ * @resamplefd: Eventfd notified on resample (resampler-only).
+ * @resampler_link: Entry in list of irqfds for a resampler (resampler-only).
+ * @eventfd: Used for setup/shutdown.

You're not documenting `list`, `pt`, `shutdown`: that will trigger a kerneldoc
warning. Please fix.

+ */
+struct gzvm_kernel_irqfd {
+	struct gzvm *gzvm;
+	wait_queue_entry_t wait;
+
+	int gsi;
+
+	struct gzvm_kernel_irqfd_resampler *resampler;
+
+	struct eventfd_ctx *resamplefd;
+
+	struct list_head resampler_link;
+
+	struct eventfd_ctx *eventfd;
+	struct list_head list;
+	poll_table pt;
+	struct work_struct shutdown;
+};

..snip..

diff --git a/drivers/virt/geniezone/gzvm_main.c b/drivers/virt/geniezone/gzvm_main.c
index 230970cb0953..e62c046d76b3 100644
--- a/drivers/virt/geniezone/gzvm_main.c
+++ b/drivers/virt/geniezone/gzvm_main.c
@@ -113,11 +113,12 @@ static int gzvm_drv_probe(void)
  		return ret;
  	gzvm_debug_dev = &gzvm_dev;
- return 0;
+	return gzvm_drv_irqfd_init();

ret = gzvm_drv_irqfd_init();
if (ret)
	return ret;

return 0;

  }
static int gzvm_drv_remove(void)
  {
+	gzvm_drv_irqfd_exit();
  	destroy_all_vm();
  	misc_deregister(&gzvm_dev);
  	return 0;
diff --git a/drivers/virt/geniezone/gzvm_vcpu.c b/drivers/virt/geniezone/gzvm_vcpu.c
index 5e9d34fcc1ea..94ead15fea3f 100644
--- a/drivers/virt/geniezone/gzvm_vcpu.c
+++ b/drivers/virt/geniezone/gzvm_vcpu.c
@@ -211,6 +211,7 @@ int gzvm_vm_ioctl_create_vcpu(struct gzvm *gzvm, u32 cpuid)
  		ret = -ENOMEM;
  		goto free_vcpu;
  	}
+	vcpu->hwstate = (void *)vcpu->run + PAGE_SIZE;
  	vcpu->vcpuid = cpuid;
  	vcpu->gzvm = gzvm;
  	mutex_init(&vcpu->lock);
diff --git a/drivers/virt/geniezone/gzvm_vm.c b/drivers/virt/geniezone/gzvm_vm.c
index 0cab67b0bdf8..eedc2d5c24ad 100644
--- a/drivers/virt/geniezone/gzvm_vm.c
+++ b/drivers/virt/geniezone/gzvm_vm.c
@@ -361,6 +361,15 @@ static long gzvm_vm_ioctl(struct file *filp, unsigned int ioctl,
  		ret = gzvm_vm_ioctl_create_device(gzvm, argp);
  		break;
  	}
+	case GZVM_IRQFD: {
+		struct gzvm_irqfd data;
+
+		ret = -EFAULT;
+		if (copy_from_user(&data, argp, sizeof(data)))

if (copy_from_user...) {
		ret = -EFAULT;
		goto out;
}

+			goto out;
+		ret = gzvm_irqfd(gzvm, &data);
+		break;
+	}
  	case GZVM_ENABLE_CAP: {
  		struct gzvm_enable_cap cap;
@@ -385,6 +394,7 @@ static void gzvm_destroy_vm(struct gzvm *gzvm) mutex_lock(&gzvm->lock); + gzvm_vm_irqfd_release(gzvm);
  	gzvm_destroy_vcpus(gzvm);
  	gzvm_arch_destroy_vm(gzvm->vm_id);
@@ -430,6 +440,14 @@ static struct gzvm *gzvm_create_vm(unsigned long vm_type)
  	gzvm->mm = current->mm;
  	mutex_init(&gzvm->lock);
+ ret = gzvm_vm_irqfd_init(gzvm);
+	if (ret) {
+		dev_err(gzvm_debug_dev->this_device,
+			"Failed to initialize irqfd\n");
+		kfree(gzvm);
+		return ERR_PTR(ret);
+	}
+
  	mutex_lock(&gzvm_list_lock);
  	list_add(&gzvm->vm_list, &gzvm_list);
  	mutex_unlock(&gzvm_list_lock);
diff --git a/include/linux/gzvm_drv.h b/include/linux/gzvm_drv.h
index 842a026df9f3..54b0a3d443c5 100644
--- a/include/linux/gzvm_drv.h
+++ b/include/linux/gzvm_drv.h
@@ -11,6 +11,7 @@
  #include <linux/mutex.h>
  #include <linux/platform_device.h>
  #include <linux/gzvm.h>
+#include <linux/srcu.h>
#define MODULE_NAME "gzvm"
  #define GZVM_VCPU_MMAP_SIZE  PAGE_SIZE
@@ -26,6 +27,8 @@
  #define ERR_NOT_SUPPORTED       (-24)
  #define ERR_NOT_IMPLEMENTED     (-27)
  #define ERR_FAULT               (-40)
+#define GZVM_USERSPACE_IRQ_SOURCE_ID            0
+#define GZVM_IRQFD_RESAMPLE_IRQ_SOURCE_ID       1
/**
   * The following data structures are for data transferring between driver and
@@ -69,6 +72,7 @@ struct gzvm_vcpu {
  	/* lock of vcpu*/
  	struct mutex lock;
  	struct gzvm_vcpu_run *run;
+	struct gzvm_vcpu_hwstate *hwstate;
  };
struct gzvm {
@@ -78,8 +82,23 @@ struct gzvm {
  	struct gzvm_memslot memslot[GZVM_MAX_MEM_REGION];
  	/* lock for list_add*/
  	struct mutex lock;
+
+	struct {
+		/* lock for irqfds list operation */
+		spinlock_t        lock;
+		struct list_head  items;
+		struct list_head  resampler_list;
+		/* lock for irqfds resampler */
+		struct mutex      resampler_lock;
+	} irqfds;
+
  	struct list_head vm_list;
  	gzvm_id_t vm_id;
+
+	struct hlist_head irq_ack_notifier_list;
+	struct srcu_struct irq_srcu;
+	/* lock for irq injection */
+	struct mutex irq_lock;
  };
long gzvm_dev_ioctl_check_extension(struct gzvm *gzvm, unsigned long args);
@@ -113,6 +132,14 @@ int gzvm_arch_create_device(gzvm_id_t vm_id, struct gzvm_create_device *gzvm_dev
  int gzvm_arch_inject_irq(struct gzvm *gzvm, unsigned int vcpu_idx, u32 irq_type,
  			 u32 irq, bool level);
+void gzvm_notify_acked_irq(struct gzvm *gzvm, unsigned int gsi);
+int gzvm_irqfd(struct gzvm *gzvm, struct gzvm_irqfd *args);
+int gzvm_drv_irqfd_init(void);
+void gzvm_drv_irqfd_exit(void);
+int gzvm_vm_irqfd_init(struct gzvm *gzvm);
+void gzvm_vm_irqfd_release(struct gzvm *gzvm);
+void gzvm_sync_hwstate(struct gzvm_vcpu *vcpu);
+
  extern struct miscdevice *gzvm_debug_dev;
#endif /* __GZVM_DRV_H__ */
diff --git a/include/uapi/linux/gzvm.h b/include/uapi/linux/gzvm.h
index 279b52192366..3f1e829f855d 100644
--- a/include/uapi/linux/gzvm.h
+++ b/include/uapi/linux/gzvm.h
@@ -224,4 +224,22 @@ struct gzvm_one_reg {
#define GZVM_REG_GENERIC 0x0000000000000000ULL +#define GZVM_IRQFD_FLAG_DEASSIGN (1 << 0)

This is BIT(0)

+/**
+ * GZVM_IRQFD_FLAG_RESAMPLE indicates resamplefd is valid and specifies
+ * the irqfd to operate in resampling mode for level triggered interrupt
+ * emulation.
+ */
+#define GZVM_IRQFD_FLAG_RESAMPLE	(1 << 1)

...and this is BIT(1).

+
+struct gzvm_irqfd {

...no documentation?

+	__u32 fd;
+	__u32 gsi;
+	__u32 flags;
+	__u32 resamplefd;
+	__u8  pad[16];
+};
+
+#define GZVM_IRQFD	_IOW(GZVM_IOC_MAGIC, 0x76, struct gzvm_irqfd)
+
  #endif /* __GZVM_H__ */

Regards,
Angelo



[Index of Archives]     [Linux Kernel]     [Kernel Newbies]     [x86 Platform Driver]     [Netdev]     [Linux Wireless]     [Netfilter]     [Bugtraq]     [Linux Filesystems]     [Yosemite Discussion]     [MIPS Linux]     [ARM Linux]     [Linux Security]     [Linux RAID]     [Samba]     [Device Mapper]

  Powered by Linux