lkml.org 
[lkml]   [2023]   [Jun]   [12]   [last100]   RSS Feed
Views: [wrap][no wrap]   [headers]  [forward] 
 
Messages in this thread
    Patch in this message
    /
    Date
    SubjectRe: [PATCH v4 5/9] virt: geniezone: Add irqfd support
    From
    Il 09/06/23 10:52, Yi-De Wu ha scritto:
    > From: "Yingshiuan Pan" <yingshiuan.pan@mediatek.com>
    >
    > 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@mediatek.com>
    > Signed-off-by: Liju Chen <liju-clr.chen@mediatek.com>
    > Signed-off-by: Yi-De Wu <yi-de.wu@mediatek.com>
    > ---
    > 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

    \
     
     \ /
      Last update: 2023-06-12 10:00    [W:2.150 / U:0.360 seconds]
    ©2003-2020 Jasper Spaans|hosted at Digital Ocean and TransIP|Read the blog|Advertise on this site