clear-pkgs-linux-iot-lts2018/0466-VHM-add-interrupt-inje...

293 lines
9.1 KiB
Diff

From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
From: liang ding <liang.ding@intel.com>
Date: Fri, 29 Dec 2017 16:38:20 +0800
Subject: [PATCH] VHM: add interrupt injection support
VHM provides interrupt injection service for emulated devices.
this patch added interrupt injection support APIs.
Change-Id: I10385318877aa52026d6d2fc56f5fdbc8106bbd9
Tracked-On: 218445
Signed-off-by: liang ding <liang.ding@intel.com>
Signed-off-by: Xiao Zheng <xiao.zheng@intel.com>
Signed-off-by: Jason Chen CJ <jason.cj.chen@intel.com>
Signed-off-by: Mingqiang Chi <mingqiang.chi@intel.com>
Reviewed-on:
Reviewed-by: Dong, Eddie <eddie.dong@intel.com>
Tested-by: Dong, Eddie <eddie.dong@intel.com>
---
drivers/char/vhm/vhm_dev.c | 29 +++++++++++++++
drivers/vhm/vhm_hypercall.c | 59 ++++++++++++++++++++++++++++++
drivers/vhm/vhm_vm_mngt.c | 18 +++++++++
include/linux/vhm/acrn_common.h | 32 ++++++++++++++++
include/linux/vhm/acrn_hv_defs.h | 7 ++++
include/linux/vhm/vhm_hypercall.h | 4 ++
include/linux/vhm/vhm_ioctl_defs.h | 7 ++++
include/linux/vhm/vhm_vm_mngt.h | 2 +
8 files changed, 158 insertions(+)
diff --git a/drivers/char/vhm/vhm_dev.c b/drivers/char/vhm/vhm_dev.c
index 3129a8f1503b..97f7c466e11d 100644
--- a/drivers/char/vhm/vhm_dev.c
+++ b/drivers/char/vhm/vhm_dev.c
@@ -238,6 +238,35 @@ static long vhm_dev_ioctl(struct file *filep,
break;
}
+ case IC_ASSERT_IRQLINE: {
+ ret = vhm_assert_irqline(vm, ioctl_param);
+ break;
+ }
+
+ case IC_DEASSERT_IRQLINE: {
+ ret = vhm_deassert_irqline(vm, ioctl_param);
+ break;
+ }
+
+ case IC_PULSE_IRQLINE: {
+ ret = vhm_pulse_irqline(vm, ioctl_param);
+ break;
+ }
+
+ case IC_INJECT_MSI: {
+ struct acrn_msi_entry msi;
+
+ if (copy_from_user(&msi, (void *)ioctl_param, sizeof(msi)))
+ return -EFAULT;
+
+ ret = hcall_inject_msi(vm->vmid, virt_to_phys(&msi));
+ if (ret < 0) {
+ pr_err("vhm: failed to inject!\n");
+ return -EFAULT;
+ }
+ break;
+ }
+
default:
pr_warn("Unknown IOCTL 0x%x\n", ioctl_num);
ret = 0;
diff --git a/drivers/vhm/vhm_hypercall.c b/drivers/vhm/vhm_hypercall.c
index 1b25f4ec4d06..dc87d30151d5 100644
--- a/drivers/vhm/vhm_hypercall.c
+++ b/drivers/vhm/vhm_hypercall.c
@@ -53,6 +53,11 @@
#include <linux/vhm/acrn_hv_defs.h>
#include <linux/vhm/vhm_hypercall.h>
+inline long hcall_inject_msi(unsigned long vmid, unsigned long msi)
+{
+ return acrn_hypercall2(HC_INJECT_MSI, vmid, msi);
+}
+
inline long hcall_set_ioreq_buffer(unsigned long vmid, unsigned long buffer)
{
return acrn_hypercall2(HC_SET_IOREQ_BUFFER, vmid, buffer);
@@ -147,3 +152,57 @@ inline long vhm_query_vm_state(struct vhm_vm *vm)
return ret;
}
+
+inline long vhm_assert_irqline(struct vhm_vm *vm, unsigned long ioctl_param)
+{
+ long ret = 0;
+ struct acrn_irqline irq;
+
+ if (copy_from_user(&irq, (void *)ioctl_param, sizeof(irq)))
+ return -EFAULT;
+
+ ret = acrn_hypercall2(HC_ASSERT_IRQLINE, vm->vmid,
+ virt_to_phys(&irq));
+ if (ret < 0) {
+ pr_err("vhm: failed to assert irq!\n");
+ return -EFAULT;
+ }
+
+ return ret;
+}
+
+inline long vhm_deassert_irqline(struct vhm_vm *vm, unsigned long ioctl_param)
+{
+ long ret = 0;
+ struct acrn_irqline irq;
+
+ if (copy_from_user(&irq, (void *)ioctl_param, sizeof(irq)))
+ return -EFAULT;
+
+ ret = acrn_hypercall2(HC_DEASSERT_IRQLINE, vm->vmid,
+ virt_to_phys(&irq));
+ if (ret < 0) {
+ pr_err("vhm: failed to deassert irq!\n");
+ return -EFAULT;
+ }
+
+ return ret;
+}
+
+inline long vhm_pulse_irqline(struct vhm_vm *vm, unsigned long ioctl_param)
+{
+ long ret = 0;
+ struct acrn_irqline irq;
+
+ if (copy_from_user(&irq, (void *)ioctl_param, sizeof(irq)))
+ return -EFAULT;
+
+ ret = acrn_hypercall2(HC_PULSE_IRQLINE, vm->vmid,
+ virt_to_phys(&irq));
+ if (ret < 0) {
+ pr_err("vhm: failed to assert irq!\n");
+ return -EFAULT;
+ }
+
+ return ret;
+}
diff --git a/drivers/vhm/vhm_vm_mngt.c b/drivers/vhm/vhm_vm_mngt.c
index 564435f2bb40..048ab41f4f9c 100644
--- a/drivers/vhm/vhm_vm_mngt.c
+++ b/drivers/vhm/vhm_vm_mngt.c
@@ -95,6 +95,24 @@ void put_vm(struct vhm_vm *vm)
mutex_unlock(&vhm_vm_list_lock);
}
+int vhm_inject_msi(unsigned long vmid, unsigned long msi_addr,
+ unsigned long msi_data)
+{
+ struct acrn_msi_entry msi;
+ int ret;
+
+ /* msi_addr: addr[19:12] with dest vcpu id */
+ /* msi_data: data[7:0] with vector */
+ msi.msi_addr = msi_addr;
+ msi.msi_data = msi_data;
+ ret = hcall_inject_msi(vmid, virt_to_phys(&msi));
+ if (ret < 0) {
+ pr_err("vhm: failed to inject!\n");
+ return -EFAULT;
+ }
+ return 0;
+}
+
void vm_list_add(struct list_head *list)
{
list_add(list, &vhm_vm_list);
diff --git a/include/linux/vhm/acrn_common.h b/include/linux/vhm/acrn_common.h
index bc2237331231..cafb171490ca 100644
--- a/include/linux/vhm/acrn_common.h
+++ b/include/linux/vhm/acrn_common.h
@@ -56,6 +56,20 @@
* Commmon structures for ACRN/VHM/DM
*/
+enum irq_mode {
+ IRQ_PULSE,
+ IRQ_ASSERT,
+ IRQ_DEASSERT,
+} __attribute__((aligned(4)));
+
+/* ISA type
+ * inject interrut to both PIC and IOAPIC
+ */
+enum interrupt_type {
+ ACRN_INTR_TYPE_ISA,
+ ACRN_INTR_TYPE_IOAPIC,
+} __attribute__((aligned(4)));
+
/*
* IO request
*/
@@ -179,4 +193,22 @@ struct acrn_ioreq_notify {
unsigned long vcpu_mask;
} __attribute__((aligned(8)));
+/* For ISA, PIC, IOAPIC etc */
+struct acrn_irqline {
+ enum interrupt_type intr_type;
+ unsigned long pic_irq; /* IN: for ISA type */
+ unsigned long ioapic_irq; /* IN: for IOAPIC type, -1 don't inject */
+} __attribute__((aligned(8)));
+
+/* For MSI type inject */
+struct acrn_msi_entry {
+ unsigned long msi_addr; /* IN: addr[19:12] with dest vcpu id */
+ unsigned long msi_data; /* IN: data[7:0] with vector */
+} __attribute__((aligned(8)));
+
+/* For NMI inject */
+struct acrn_nmi_entry {
+ unsigned long vcpuid; /* IN: -1 means vcpu0 */
+} __attribute__((aligned(8)));
+
#endif /* ACRN_COMMON_H */
diff --git a/include/linux/vhm/acrn_hv_defs.h b/include/linux/vhm/acrn_hv_defs.h
index f57f2b62e972..7b438cc01b48 100644
--- a/include/linux/vhm/acrn_hv_defs.h
+++ b/include/linux/vhm/acrn_hv_defs.h
@@ -74,6 +74,13 @@
#define HC_PAUSE_VM _HC_ID(HC_ID, HC_ID_VM_BASE + 0x04)
#define HC_QUERY_VMSTATE _HC_ID(HC_ID, HC_ID_VM_BASE + 0x05)
+/* IRQ and Interrupts */
+#define HC_ID_IRQ_BASE 0x100UL
+#define HC_ASSERT_IRQLINE _HC_ID(HC_ID, HC_ID_IRQ_BASE + 0x00)
+#define HC_DEASSERT_IRQLINE _HC_ID(HC_ID, HC_ID_IRQ_BASE + 0x01)
+#define HC_PULSE_IRQLINE _HC_ID(HC_ID, HC_ID_IRQ_BASE + 0x02)
+#define HC_INJECT_MSI _HC_ID(HC_ID, HC_ID_IRQ_BASE + 0x03)
+
/* DM ioreq management */
#define HC_ID_IOREQ_BASE 0x200UL
#define HC_SET_IOREQ_BUFFER _HC_ID(HC_ID, HC_ID_IOREQ_BASE + 0x00)
diff --git a/include/linux/vhm/vhm_hypercall.h b/include/linux/vhm/vhm_hypercall.h
index 86b5f579687a..e372ea48fa81 100644
--- a/include/linux/vhm/vhm_hypercall.h
+++ b/include/linux/vhm/vhm_hypercall.h
@@ -139,6 +139,7 @@ static inline long acrn_hypercall4(unsigned long hyp_id, unsigned long param1,
return result;
}
+inline long hcall_inject_msi(unsigned long vmid, unsigned long msi);
inline long hcall_set_ioreq_buffer(unsigned long vmid, unsigned long buffer);
inline long hcall_notify_req_finish(unsigned long vmid,
unsigned long vcpu_mask);
@@ -148,5 +149,8 @@ inline long vhm_resume_vm(struct vhm_vm *vm);
inline long vhm_pause_vm(struct vhm_vm *vm);
inline long vhm_destroy_vm(struct vhm_vm *vm);
inline long vhm_query_vm_state(struct vhm_vm *vm);
+inline long vhm_assert_irqline(struct vhm_vm *vm, unsigned long ioctl_param);
+inline long vhm_deassert_irqline(struct vhm_vm *vm, unsigned long ioctl_param);
+inline long vhm_pulse_irqline(struct vhm_vm *vm, unsigned long ioctl_param);
#endif /* VHM_HYPERCALL_H */
diff --git a/include/linux/vhm/vhm_ioctl_defs.h b/include/linux/vhm/vhm_ioctl_defs.h
index 01adcfade99c..3be6aca40844 100644
--- a/include/linux/vhm/vhm_ioctl_defs.h
+++ b/include/linux/vhm/vhm_ioctl_defs.h
@@ -64,6 +64,13 @@
#define IC_PAUSE_VM _IC_ID(IC_ID, IC_ID_VM_BASE + 0x04)
#define IC_QUERY_VMSTATE _IC_ID(IC_ID, IC_ID_VM_BASE + 0x05)
+/* IRQ and Interrupts */
+#define IC_ID_IRQ_BASE 0x100UL
+#define IC_ASSERT_IRQLINE _IC_ID(IC_ID, IC_ID_IRQ_BASE + 0x00)
+#define IC_DEASSERT_IRQLINE _IC_ID(IC_ID, IC_ID_IRQ_BASE + 0x01)
+#define IC_PULSE_IRQLINE _IC_ID(IC_ID, IC_ID_IRQ_BASE + 0x02)
+#define IC_INJECT_MSI _IC_ID(IC_ID, IC_ID_IRQ_BASE + 0x03)
+
/* DM ioreq management */
#define IC_ID_IOREQ_BASE 0x200UL
#define IC_SET_IOREQ_BUFFER _IC_ID(IC_ID, IC_ID_IOREQ_BASE + 0x00)
diff --git a/include/linux/vhm/vhm_vm_mngt.h b/include/linux/vhm/vhm_vm_mngt.h
index eb410024157f..fb02c00ec5e2 100644
--- a/include/linux/vhm/vhm_vm_mngt.h
+++ b/include/linux/vhm/vhm_vm_mngt.h
@@ -77,6 +77,8 @@ struct vhm_vm {
struct vhm_vm *find_get_vm(unsigned long vmid);
void put_vm(struct vhm_vm *vm);
+int vhm_inject_msi(unsigned long vmid, unsigned long msi_addr,
+ unsigned long msi_data);
void vm_list_add(struct list_head *list);
void vm_mutex_lock(struct mutex *mlock);
--
https://clearlinux.org