    KVM: in-kernel IOAPIC save and restore support
    
    This patch adds support for in-kernel ioapic save and restore (to and from
    userspace). It uses the same get/set_irqchip ioctl as in-kernel PIC.
    
    Signed-off-by: Qing He <qing.he@intel.com>
    Signed-off-by: Yaozu (Eddie) Dong <eddie.dong@intel.com>

---
 drivers/kvm/irq.h      |    9 +++++----
 drivers/kvm/kvm.h      |    5 +++++
 drivers/kvm/kvm_main.c |   10 ++++++++++
 include/linux/kvm.h    |   29 ++++++++++++++++++++++++++++-
 4 files changed, 48 insertions(+), 5 deletions(-)

diff --git a/drivers/kvm/irq.h b/drivers/kvm/irq.h
index 9e184d7..92e1cfb 100644
--- a/drivers/kvm/irq.h
+++ b/drivers/kvm/irq.h
@@ -61,7 +61,7 @@ int kvm_cpu_get_interrupt(struct kvm_vcpu *v);
 int kvm_cpu_has_interrupt(struct kvm_vcpu *v);
 void kvm_pic_update_irq(struct kvm_pic *s);
 
-#define IOAPIC_NUM_PINS  24
+#define IOAPIC_NUM_PINS  KVM_IOAPIC_NUM_PINS
 #define IOAPIC_VERSION_ID 0x11	/* IOAPIC version */
 #define IOAPIC_EDGE_TRIG  0
 #define IOAPIC_LEVEL_TRIG 1
@@ -80,12 +80,11 @@ void kvm_pic_update_irq(struct kvm_pic *s);
 #define IOAPIC_REG_ARB_ID  0x02	/* x86 IOAPIC only */
 
 struct kvm_ioapic {
-	struct kvm_io_device dev;
-	unsigned long base_address;
-	struct kvm *kvm;
+	u64 base_address;
 	u32 ioregsel;
 	u32 id;
 	u32 irr;
+	u32 pad;
 	union ioapic_redir_entry {
 		u64 bits;
 		struct {
@@ -102,6 +101,8 @@ struct kvm_ioapic {
 			u8 dest_id;
 		} fields;
 	} redirtbl[IOAPIC_NUM_PINS];
+	struct kvm_io_device dev;
+	struct kvm *kvm;
 };
 
 struct kvm_lapic {
diff --git a/drivers/kvm/kvm.h b/drivers/kvm/kvm.h
index 42b0408..99d3b36 100644
--- a/drivers/kvm/kvm.h
+++ b/drivers/kvm/kvm.h
@@ -429,6 +429,11 @@ static inline struct kvm_pic *pic_irqchip(struct kvm *kvm)
 	return kvm->vpic;
 }
 
+static inline struct kvm_ioapic *ioapic_irqchip(struct kvm *kvm)
+{
+	return kvm->vioapic;
+}
+
 static inline int irqchip_in_kernel(struct kvm *kvm)
 {
 	return pic_irqchip(kvm) != 0;
diff --git a/drivers/kvm/kvm_main.c b/drivers/kvm/kvm_main.c
index 4f644f9..4c66f6d 100644
--- a/drivers/kvm/kvm_main.c
+++ b/drivers/kvm/kvm_main.c
@@ -923,6 +923,11 @@ static int kvm_vm_ioctl_get_irqchip(struct kvm *kvm, struct kvm_irqchip *chip)
 			&pic_irqchip(kvm)->pics[1],
 			sizeof(struct kvm_ioctl_pic));
 		break;
+	case KVM_IRQCHIP_IOAPIC:
+		memcpy (&chip->chip.ioapic,
+			ioapic_irqchip(kvm),
+			sizeof(struct kvm_ioctl_ioapic));
+		break;
 	default:
 		r = -EINVAL;
 		break;
@@ -946,6 +951,11 @@ static int kvm_vm_ioctl_set_irqchip(struct kvm *kvm, struct kvm_irqchip *chip)
 			&chip->chip.pic,
 			sizeof(struct kvm_ioctl_pic));
 		break;
+	case KVM_IRQCHIP_IOAPIC:
+		memcpy (ioapic_irqchip(kvm),
+			&chip->chip.ioapic,
+			sizeof(struct kvm_ioctl_ioapic));
+		break;
 	default:
 		r = -EINVAL;
 		break;
diff --git a/include/linux/kvm.h b/include/linux/kvm.h
index 0e81143..3295a06 100644
--- a/include/linux/kvm.h
+++ b/include/linux/kvm.h
@@ -45,7 +45,7 @@ struct kvm_irq_level {
 	__u32 level;
 };
 
-/* for KVM_GET_IRQCHIP / KVM_SET_IRQCHIP */
+/* for KVM_GET_IRQCHIP and KVM_SET_IRQCHIP */
 struct kvm_ioctl_pic {
 	__u8 last_irr;	/* edge detection */
 	__u8 irr;		/* interrupt request register */
@@ -65,9 +65,35 @@ struct kvm_ioctl_pic {
 	__u8 elcr_mask;
 };
 
+#define KVM_IOAPIC_NUM_PINS  24
+struct kvm_ioctl_ioapic {
+	__u64 base_address;
+	__u32 ioregsel;
+	__u32 id;
+	__u32 irr;
+	__u32 pad;
+	union {
+		__u64 bits;
+		struct {
+			__u8 vector;
+			__u8 delivery_mode:3;
+			__u8 dest_mode:1;
+			__u8 delivery_status:1;
+			__u8 polarity:1;
+			__u8 remote_irr:1;
+			__u8 trig_mode:1;
+			__u8 mask:1;
+			__u8 reserve:7;
+			__u8 reserved[4];
+			__u8 dest_id;
+		} fields;
+	} redirtbl[KVM_IOAPIC_NUM_PINS];
+};
+
 enum kvm_irqchip_id {
 	KVM_IRQCHIP_PIC_MASTER	 = 0,
 	KVM_IRQCHIP_PIC_SLAVE	 = 1,
+	KVM_IRQCHIP_IOAPIC       = 2,
 };
 
 struct kvm_irqchip {
@@ -76,6 +102,7 @@ struct kvm_irqchip {
         union {
 		char dummy[512];  /* reserving space */
 		struct kvm_ioctl_pic pic;
+		struct kvm_ioctl_ioapic ioapic;
 	} chip;
 };
 

