OSDN Git Service

RISC-V: KVM: Skeletal in-kernel AIA irqchip support
authorAnup Patel <apatel@ventanamicro.com>
Thu, 15 Jun 2023 07:33:48 +0000 (13:03 +0530)
committerAnup Patel <anup@brainfault.org>
Sun, 18 Jun 2023 15:54:40 +0000 (21:24 +0530)
To incrementally implement in-kernel AIA irqchip support, we first
add minimal skeletal support which only compiles but does not provide
any functionality.

Signed-off-by: Anup Patel <apatel@ventanamicro.com>
Reviewed-by: Atish Patra <atishp@rivosinc.com>
Signed-off-by: Anup Patel <anup@brainfault.org>
arch/riscv/include/asm/kvm_aia.h
arch/riscv/include/asm/kvm_host.h
arch/riscv/include/uapi/asm/kvm.h
arch/riscv/kvm/Kconfig
arch/riscv/kvm/aia.c
arch/riscv/kvm/vm.c

index 0938e0c..3bc0a0e 100644 (file)
@@ -45,6 +45,7 @@ struct kvm_vcpu_aia {
 #define irqchip_in_kernel(k)           ((k)->arch.aia.in_kernel)
 
 extern unsigned int kvm_riscv_aia_nr_hgei;
+extern unsigned int kvm_riscv_aia_max_ids;
 DECLARE_STATIC_KEY_FALSE(kvm_riscv_aia_available);
 #define kvm_riscv_aia_available() \
        static_branch_unlikely(&kvm_riscv_aia_available)
@@ -116,6 +117,25 @@ static inline void kvm_riscv_vcpu_aia_deinit(struct kvm_vcpu *vcpu)
 {
 }
 
+static inline int kvm_riscv_aia_inject_msi_by_id(struct kvm *kvm,
+                                                u32 hart_index,
+                                                u32 guest_index, u32 iid)
+{
+       return 0;
+}
+
+static inline int kvm_riscv_aia_inject_msi(struct kvm *kvm,
+                                          struct kvm_msi *msi)
+{
+       return 0;
+}
+
+static inline int kvm_riscv_aia_inject_irq(struct kvm *kvm,
+                                          unsigned int irq, bool level)
+{
+       return 0;
+}
+
 static inline void kvm_riscv_aia_init_vm(struct kvm *kvm)
 {
 }
index ee0accc..8714325 100644 (file)
@@ -27,6 +27,8 @@
 
 #define KVM_VCPU_MAX_FEATURES          0
 
+#define KVM_IRQCHIP_NUM_PINS           1024
+
 #define KVM_REQ_SLEEP \
        KVM_ARCH_REQ_FLAGS(0, KVM_REQUEST_WAIT | KVM_REQUEST_NO_WAKEUP)
 #define KVM_REQ_VCPU_RESET             KVM_ARCH_REQ(1)
@@ -318,6 +320,8 @@ int kvm_riscv_gstage_vmid_init(struct kvm *kvm);
 bool kvm_riscv_gstage_vmid_ver_changed(struct kvm_vmid *vmid);
 void kvm_riscv_gstage_vmid_update(struct kvm_vcpu *vcpu);
 
+int kvm_riscv_setup_default_irq_routing(struct kvm *kvm, u32 lines);
+
 void __kvm_riscv_unpriv_trap(void);
 
 unsigned long kvm_riscv_vcpu_unpriv_read(struct kvm_vcpu *vcpu,
index f92790c..332d4a2 100644 (file)
@@ -15,6 +15,7 @@
 #include <asm/bitsperlong.h>
 #include <asm/ptrace.h>
 
+#define __KVM_HAVE_IRQ_LINE
 #define __KVM_HAVE_READONLY_MEM
 
 #define KVM_COALESCED_MMIO_PAGE_OFFSET 1
@@ -203,6 +204,9 @@ enum KVM_RISCV_SBI_EXT_ID {
 #define KVM_REG_RISCV_SBI_MULTI_REG_LAST       \
                KVM_REG_RISCV_SBI_MULTI_REG(KVM_RISCV_SBI_EXT_MAX - 1)
 
+/* One single KVM irqchip, ie. the AIA */
+#define KVM_NR_IRQCHIPS                        1
+
 #endif
 
 #endif /* __LINUX_KVM_RISCV_H */
index 28891e5..dfc237d 100644 (file)
@@ -21,6 +21,10 @@ config KVM
        tristate "Kernel-based Virtual Machine (KVM) support (EXPERIMENTAL)"
        depends on RISCV_SBI && MMU
        select HAVE_KVM_EVENTFD
+       select HAVE_KVM_IRQCHIP
+       select HAVE_KVM_IRQFD
+       select HAVE_KVM_IRQ_ROUTING
+       select HAVE_KVM_MSI
        select HAVE_KVM_VCPU_ASYNC_IOCTL
        select KVM_GENERIC_DIRTYLOG_READ_PROTECT
        select KVM_GENERIC_HARDWARE_ENABLING
index 3f97575..18c442c 100644 (file)
@@ -26,6 +26,7 @@ static DEFINE_PER_CPU(struct aia_hgei_control, aia_hgei);
 static int hgei_parent_irq;
 
 unsigned int kvm_riscv_aia_nr_hgei;
+unsigned int kvm_riscv_aia_max_ids;
 DEFINE_STATIC_KEY_FALSE(kvm_riscv_aia_available);
 
 static int aia_find_hgei(struct kvm_vcpu *owner)
@@ -618,6 +619,13 @@ int kvm_riscv_aia_init(void)
         */
        kvm_riscv_aia_nr_hgei = 0;
 
+       /*
+        * Find number of guest MSI IDs
+        *
+        * TODO: To be updated later by AIA IMSIC HW guest file support
+        */
+       kvm_riscv_aia_max_ids = IMSIC_MAX_ID;
+
        /* Initialize guest external interrupt line management */
        rc = aia_hgei_init();
        if (rc)
index 6ef15f7..7e2b50c 100644 (file)
@@ -55,11 +55,129 @@ void kvm_arch_destroy_vm(struct kvm *kvm)
        kvm_riscv_aia_destroy_vm(kvm);
 }
 
+int kvm_vm_ioctl_irq_line(struct kvm *kvm, struct kvm_irq_level *irql,
+                         bool line_status)
+{
+       if (!irqchip_in_kernel(kvm))
+               return -ENXIO;
+
+       return kvm_riscv_aia_inject_irq(kvm, irql->irq, irql->level);
+}
+
+int kvm_set_msi(struct kvm_kernel_irq_routing_entry *e,
+               struct kvm *kvm, int irq_source_id,
+               int level, bool line_status)
+{
+       struct kvm_msi msi;
+
+       if (!level)
+               return -1;
+
+       msi.address_lo = e->msi.address_lo;
+       msi.address_hi = e->msi.address_hi;
+       msi.data = e->msi.data;
+       msi.flags = e->msi.flags;
+       msi.devid = e->msi.devid;
+
+       return kvm_riscv_aia_inject_msi(kvm, &msi);
+}
+
+static int kvm_riscv_set_irq(struct kvm_kernel_irq_routing_entry *e,
+                            struct kvm *kvm, int irq_source_id,
+                            int level, bool line_status)
+{
+       return kvm_riscv_aia_inject_irq(kvm, e->irqchip.pin, level);
+}
+
+int kvm_riscv_setup_default_irq_routing(struct kvm *kvm, u32 lines)
+{
+       struct kvm_irq_routing_entry *ents;
+       int i, rc;
+
+       ents = kcalloc(lines, sizeof(*ents), GFP_KERNEL);
+       if (!ents)
+               return -ENOMEM;
+
+       for (i = 0; i < lines; i++) {
+               ents[i].gsi = i;
+               ents[i].type = KVM_IRQ_ROUTING_IRQCHIP;
+               ents[i].u.irqchip.irqchip = 0;
+               ents[i].u.irqchip.pin = i;
+       }
+       rc = kvm_set_irq_routing(kvm, ents, lines, 0);
+       kfree(ents);
+
+       return rc;
+}
+
+bool kvm_arch_can_set_irq_routing(struct kvm *kvm)
+{
+       return irqchip_in_kernel(kvm);
+}
+
+int kvm_set_routing_entry(struct kvm *kvm,
+                         struct kvm_kernel_irq_routing_entry *e,
+                         const struct kvm_irq_routing_entry *ue)
+{
+       int r = -EINVAL;
+
+       switch (ue->type) {
+       case KVM_IRQ_ROUTING_IRQCHIP:
+               e->set = kvm_riscv_set_irq;
+               e->irqchip.irqchip = ue->u.irqchip.irqchip;
+               e->irqchip.pin = ue->u.irqchip.pin;
+               if ((e->irqchip.pin >= KVM_IRQCHIP_NUM_PINS) ||
+                   (e->irqchip.irqchip >= KVM_NR_IRQCHIPS))
+                       goto out;
+               break;
+       case KVM_IRQ_ROUTING_MSI:
+               e->set = kvm_set_msi;
+               e->msi.address_lo = ue->u.msi.address_lo;
+               e->msi.address_hi = ue->u.msi.address_hi;
+               e->msi.data = ue->u.msi.data;
+               e->msi.flags = ue->flags;
+               e->msi.devid = ue->u.msi.devid;
+               break;
+       default:
+               goto out;
+       }
+       r = 0;
+out:
+       return r;
+}
+
+int kvm_arch_set_irq_inatomic(struct kvm_kernel_irq_routing_entry *e,
+                             struct kvm *kvm, int irq_source_id, int level,
+                             bool line_status)
+{
+       if (!level)
+               return -EWOULDBLOCK;
+
+       switch (e->type) {
+       case KVM_IRQ_ROUTING_MSI:
+               return kvm_set_msi(e, kvm, irq_source_id, level, line_status);
+
+       case KVM_IRQ_ROUTING_IRQCHIP:
+               return kvm_riscv_set_irq(e, kvm, irq_source_id,
+                                        level, line_status);
+       }
+
+       return -EWOULDBLOCK;
+}
+
+bool kvm_arch_irqchip_in_kernel(struct kvm *kvm)
+{
+       return irqchip_in_kernel(kvm);
+}
+
 int kvm_vm_ioctl_check_extension(struct kvm *kvm, long ext)
 {
        int r;
 
        switch (ext) {
+       case KVM_CAP_IRQCHIP:
+               r = kvm_riscv_aia_available();
+               break;
        case KVM_CAP_IOEVENTFD:
        case KVM_CAP_DEVICE_CTRL:
        case KVM_CAP_USER_MEMORY: