* [PATCH 01/43] KVM: VMX: Don't use highmem pages for the msr and pio bitmaps
2009-05-18 9:22 [PATCH 00/43] KVM updates for the 2.6.31 merge window (batch 1/4) Avi Kivity
@ 2009-05-18 9:22 ` Avi Kivity
2009-05-18 9:22 ` [PATCH 02/43] KVM: VMX: Don't intercept MSR_KERNEL_GS_BASE Avi Kivity
` (41 subsequent siblings)
42 siblings, 0 replies; 44+ messages in thread
From: Avi Kivity @ 2009-05-18 9:22 UTC (permalink / raw)
To: linux-kernel; +Cc: kvm
Highmem pages are a pain, and saving three lowmem pages on i386 isn't worth
the extra code.
Signed-off-by: Avi Kivity <avi@redhat.com>
---
arch/x86/kvm/vmx.c | 59 ++++++++++++++++++++++------------------------------
1 files changed, 25 insertions(+), 34 deletions(-)
diff --git a/arch/x86/kvm/vmx.c b/arch/x86/kvm/vmx.c
index bb48133..b20c9e4 100644
--- a/arch/x86/kvm/vmx.c
+++ b/arch/x86/kvm/vmx.c
@@ -111,9 +111,9 @@ static DEFINE_PER_CPU(struct vmcs *, vmxarea);
static DEFINE_PER_CPU(struct vmcs *, current_vmcs);
static DEFINE_PER_CPU(struct list_head, vcpus_on_cpu);
-static struct page *vmx_io_bitmap_a;
-static struct page *vmx_io_bitmap_b;
-static struct page *vmx_msr_bitmap;
+static unsigned long *vmx_io_bitmap_a;
+static unsigned long *vmx_io_bitmap_b;
+static unsigned long *vmx_msr_bitmap;
static DECLARE_BITMAP(vmx_vpid_bitmap, VMX_NR_VPIDS);
static DEFINE_SPINLOCK(vmx_vpid_lock);
@@ -2082,9 +2082,9 @@ static void allocate_vpid(struct vcpu_vmx *vmx)
spin_unlock(&vmx_vpid_lock);
}
-static void vmx_disable_intercept_for_msr(struct page *msr_bitmap, u32 msr)
+static void vmx_disable_intercept_for_msr(unsigned long *msr_bitmap, u32 msr)
{
- void *va;
+ int f = sizeof(unsigned long);
if (!cpu_has_vmx_msr_bitmap())
return;
@@ -2094,16 +2094,14 @@ static void vmx_disable_intercept_for_msr(struct page *msr_bitmap, u32 msr)
* have the write-low and read-high bitmap offsets the wrong way round.
* We can control MSRs 0x00000000-0x00001fff and 0xc0000000-0xc0001fff.
*/
- va = kmap(msr_bitmap);
if (msr <= 0x1fff) {
- __clear_bit(msr, va + 0x000); /* read-low */
- __clear_bit(msr, va + 0x800); /* write-low */
+ __clear_bit(msr, msr_bitmap + 0x000 / f); /* read-low */
+ __clear_bit(msr, msr_bitmap + 0x800 / f); /* write-low */
} else if ((msr >= 0xc0000000) && (msr <= 0xc0001fff)) {
msr &= 0x1fff;
- __clear_bit(msr, va + 0x400); /* read-high */
- __clear_bit(msr, va + 0xc00); /* write-high */
+ __clear_bit(msr, msr_bitmap + 0x400 / f); /* read-high */
+ __clear_bit(msr, msr_bitmap + 0xc00 / f); /* write-high */
}
- kunmap(msr_bitmap);
}
/*
@@ -2121,11 +2119,11 @@ static int vmx_vcpu_setup(struct vcpu_vmx *vmx)
u32 exec_control;
/* I/O */
- vmcs_write64(IO_BITMAP_A, page_to_phys(vmx_io_bitmap_a));
- vmcs_write64(IO_BITMAP_B, page_to_phys(vmx_io_bitmap_b));
+ vmcs_write64(IO_BITMAP_A, __pa(vmx_io_bitmap_a));
+ vmcs_write64(IO_BITMAP_B, __pa(vmx_io_bitmap_b));
if (cpu_has_vmx_msr_bitmap())
- vmcs_write64(MSR_BITMAP, page_to_phys(vmx_msr_bitmap));
+ vmcs_write64(MSR_BITMAP, __pa(vmx_msr_bitmap));
vmcs_write64(VMCS_LINK_POINTER, -1ull); /* 22.3.1.5 */
@@ -3695,20 +3693,19 @@ static struct kvm_x86_ops vmx_x86_ops = {
static int __init vmx_init(void)
{
- void *va;
int r;
- vmx_io_bitmap_a = alloc_page(GFP_KERNEL | __GFP_HIGHMEM);
+ vmx_io_bitmap_a = (unsigned long *)__get_free_page(GFP_KERNEL);
if (!vmx_io_bitmap_a)
return -ENOMEM;
- vmx_io_bitmap_b = alloc_page(GFP_KERNEL | __GFP_HIGHMEM);
+ vmx_io_bitmap_b = (unsigned long *)__get_free_page(GFP_KERNEL);
if (!vmx_io_bitmap_b) {
r = -ENOMEM;
goto out;
}
- vmx_msr_bitmap = alloc_page(GFP_KERNEL | __GFP_HIGHMEM);
+ vmx_msr_bitmap = (unsigned long *)__get_free_page(GFP_KERNEL);
if (!vmx_msr_bitmap) {
r = -ENOMEM;
goto out1;
@@ -3718,18 +3715,12 @@ static int __init vmx_init(void)
* Allow direct access to the PC debug port (it is often used for I/O
* delays, but the vmexits simply slow things down).
*/
- va = kmap(vmx_io_bitmap_a);
- memset(va, 0xff, PAGE_SIZE);
- clear_bit(0x80, va);
- kunmap(vmx_io_bitmap_a);
+ memset(vmx_io_bitmap_a, 0xff, PAGE_SIZE);
+ clear_bit(0x80, vmx_io_bitmap_a);
- va = kmap(vmx_io_bitmap_b);
- memset(va, 0xff, PAGE_SIZE);
- kunmap(vmx_io_bitmap_b);
+ memset(vmx_io_bitmap_b, 0xff, PAGE_SIZE);
- va = kmap(vmx_msr_bitmap);
- memset(va, 0xff, PAGE_SIZE);
- kunmap(vmx_msr_bitmap);
+ memset(vmx_msr_bitmap, 0xff, PAGE_SIZE);
set_bit(0, vmx_vpid_bitmap); /* 0 is reserved for host */
@@ -3762,19 +3753,19 @@ static int __init vmx_init(void)
return 0;
out2:
- __free_page(vmx_msr_bitmap);
+ free_page((unsigned long)vmx_msr_bitmap);
out1:
- __free_page(vmx_io_bitmap_b);
+ free_page((unsigned long)vmx_io_bitmap_b);
out:
- __free_page(vmx_io_bitmap_a);
+ free_page((unsigned long)vmx_io_bitmap_a);
return r;
}
static void __exit vmx_exit(void)
{
- __free_page(vmx_msr_bitmap);
- __free_page(vmx_io_bitmap_b);
- __free_page(vmx_io_bitmap_a);
+ free_page((unsigned long)vmx_msr_bitmap);
+ free_page((unsigned long)vmx_io_bitmap_b);
+ free_page((unsigned long)vmx_io_bitmap_a);
kvm_exit();
}
--
1.6.0.6
^ permalink raw reply [flat|nested] 44+ messages in thread* [PATCH 02/43] KVM: VMX: Don't intercept MSR_KERNEL_GS_BASE
2009-05-18 9:22 [PATCH 00/43] KVM updates for the 2.6.31 merge window (batch 1/4) Avi Kivity
2009-05-18 9:22 ` [PATCH 01/43] KVM: VMX: Don't use highmem pages for the msr and pio bitmaps Avi Kivity
@ 2009-05-18 9:22 ` Avi Kivity
2009-05-18 9:22 ` [PATCH 03/43] KVM: Split IOAPIC structure Avi Kivity
` (40 subsequent siblings)
42 siblings, 0 replies; 44+ messages in thread
From: Avi Kivity @ 2009-05-18 9:22 UTC (permalink / raw)
To: linux-kernel; +Cc: kvm
Windows 2008 accesses this MSR often on context switch intensive workloads;
since we run in guest context with the guest MSR value loaded (so swapgs can
work correctly), we can simply disable interception of rdmsr/wrmsr for this
MSR.
A complication occurs since in legacy mode, we run with the host MSR value
loaded. In this case we enable interception. This means we need two MSR
bitmaps, one for legacy mode and one for long mode.
Signed-off-by: Avi Kivity <avi@redhat.com>
---
arch/x86/kvm/vmx.c | 57 +++++++++++++++++++++++++++++++++++++++------------
1 files changed, 43 insertions(+), 14 deletions(-)
diff --git a/arch/x86/kvm/vmx.c b/arch/x86/kvm/vmx.c
index b20c9e4..b5eae7a 100644
--- a/arch/x86/kvm/vmx.c
+++ b/arch/x86/kvm/vmx.c
@@ -113,7 +113,8 @@ static DEFINE_PER_CPU(struct list_head, vcpus_on_cpu);
static unsigned long *vmx_io_bitmap_a;
static unsigned long *vmx_io_bitmap_b;
-static unsigned long *vmx_msr_bitmap;
+static unsigned long *vmx_msr_bitmap_legacy;
+static unsigned long *vmx_msr_bitmap_longmode;
static DECLARE_BITMAP(vmx_vpid_bitmap, VMX_NR_VPIDS);
static DEFINE_SPINLOCK(vmx_vpid_lock);
@@ -812,6 +813,7 @@ static void move_msr_up(struct vcpu_vmx *vmx, int from, int to)
static void setup_msrs(struct vcpu_vmx *vmx)
{
int save_nmsrs;
+ unsigned long *msr_bitmap;
vmx_load_host_state(vmx);
save_nmsrs = 0;
@@ -847,6 +849,15 @@ static void setup_msrs(struct vcpu_vmx *vmx)
__find_msr_index(vmx, MSR_KERNEL_GS_BASE);
#endif
vmx->msr_offset_efer = __find_msr_index(vmx, MSR_EFER);
+
+ if (cpu_has_vmx_msr_bitmap()) {
+ if (is_long_mode(&vmx->vcpu))
+ msr_bitmap = vmx_msr_bitmap_longmode;
+ else
+ msr_bitmap = vmx_msr_bitmap_legacy;
+
+ vmcs_write64(MSR_BITMAP, __pa(msr_bitmap));
+ }
}
/*
@@ -2082,7 +2093,7 @@ static void allocate_vpid(struct vcpu_vmx *vmx)
spin_unlock(&vmx_vpid_lock);
}
-static void vmx_disable_intercept_for_msr(unsigned long *msr_bitmap, u32 msr)
+static void __vmx_disable_intercept_for_msr(unsigned long *msr_bitmap, u32 msr)
{
int f = sizeof(unsigned long);
@@ -2104,6 +2115,13 @@ static void vmx_disable_intercept_for_msr(unsigned long *msr_bitmap, u32 msr)
}
}
+static void vmx_disable_intercept_for_msr(u32 msr, bool longmode_only)
+{
+ if (!longmode_only)
+ __vmx_disable_intercept_for_msr(vmx_msr_bitmap_legacy, msr);
+ __vmx_disable_intercept_for_msr(vmx_msr_bitmap_longmode, msr);
+}
+
/*
* Sets up the vmcs for emulated real mode.
*/
@@ -2123,7 +2141,7 @@ static int vmx_vcpu_setup(struct vcpu_vmx *vmx)
vmcs_write64(IO_BITMAP_B, __pa(vmx_io_bitmap_b));
if (cpu_has_vmx_msr_bitmap())
- vmcs_write64(MSR_BITMAP, __pa(vmx_msr_bitmap));
+ vmcs_write64(MSR_BITMAP, __pa(vmx_msr_bitmap_legacy));
vmcs_write64(VMCS_LINK_POINTER, -1ull); /* 22.3.1.5 */
@@ -3705,12 +3723,18 @@ static int __init vmx_init(void)
goto out;
}
- vmx_msr_bitmap = (unsigned long *)__get_free_page(GFP_KERNEL);
- if (!vmx_msr_bitmap) {
+ vmx_msr_bitmap_legacy = (unsigned long *)__get_free_page(GFP_KERNEL);
+ if (!vmx_msr_bitmap_legacy) {
r = -ENOMEM;
goto out1;
}
+ vmx_msr_bitmap_longmode = (unsigned long *)__get_free_page(GFP_KERNEL);
+ if (!vmx_msr_bitmap_longmode) {
+ r = -ENOMEM;
+ goto out2;
+ }
+
/*
* Allow direct access to the PC debug port (it is often used for I/O
* delays, but the vmexits simply slow things down).
@@ -3720,19 +3744,21 @@ static int __init vmx_init(void)
memset(vmx_io_bitmap_b, 0xff, PAGE_SIZE);
- memset(vmx_msr_bitmap, 0xff, PAGE_SIZE);
+ memset(vmx_msr_bitmap_legacy, 0xff, PAGE_SIZE);
+ memset(vmx_msr_bitmap_longmode, 0xff, PAGE_SIZE);
set_bit(0, vmx_vpid_bitmap); /* 0 is reserved for host */
r = kvm_init(&vmx_x86_ops, sizeof(struct vcpu_vmx), THIS_MODULE);
if (r)
- goto out2;
+ goto out3;
- vmx_disable_intercept_for_msr(vmx_msr_bitmap, MSR_FS_BASE);
- vmx_disable_intercept_for_msr(vmx_msr_bitmap, MSR_GS_BASE);
- vmx_disable_intercept_for_msr(vmx_msr_bitmap, MSR_IA32_SYSENTER_CS);
- vmx_disable_intercept_for_msr(vmx_msr_bitmap, MSR_IA32_SYSENTER_ESP);
- vmx_disable_intercept_for_msr(vmx_msr_bitmap, MSR_IA32_SYSENTER_EIP);
+ vmx_disable_intercept_for_msr(MSR_FS_BASE, false);
+ vmx_disable_intercept_for_msr(MSR_GS_BASE, false);
+ vmx_disable_intercept_for_msr(MSR_KERNEL_GS_BASE, true);
+ vmx_disable_intercept_for_msr(MSR_IA32_SYSENTER_CS, false);
+ vmx_disable_intercept_for_msr(MSR_IA32_SYSENTER_ESP, false);
+ vmx_disable_intercept_for_msr(MSR_IA32_SYSENTER_EIP, false);
if (vm_need_ept()) {
bypass_guest_pf = 0;
@@ -3752,8 +3778,10 @@ static int __init vmx_init(void)
return 0;
+out3:
+ free_page((unsigned long)vmx_msr_bitmap_longmode);
out2:
- free_page((unsigned long)vmx_msr_bitmap);
+ free_page((unsigned long)vmx_msr_bitmap_legacy);
out1:
free_page((unsigned long)vmx_io_bitmap_b);
out:
@@ -3763,7 +3791,8 @@ out:
static void __exit vmx_exit(void)
{
- free_page((unsigned long)vmx_msr_bitmap);
+ free_page((unsigned long)vmx_msr_bitmap_legacy);
+ free_page((unsigned long)vmx_msr_bitmap_longmode);
free_page((unsigned long)vmx_io_bitmap_b);
free_page((unsigned long)vmx_io_bitmap_a);
--
1.6.0.6
^ permalink raw reply [flat|nested] 44+ messages in thread* [PATCH 03/43] KVM: Split IOAPIC structure
2009-05-18 9:22 [PATCH 00/43] KVM updates for the 2.6.31 merge window (batch 1/4) Avi Kivity
2009-05-18 9:22 ` [PATCH 01/43] KVM: VMX: Don't use highmem pages for the msr and pio bitmaps Avi Kivity
2009-05-18 9:22 ` [PATCH 02/43] KVM: VMX: Don't intercept MSR_KERNEL_GS_BASE Avi Kivity
@ 2009-05-18 9:22 ` Avi Kivity
2009-05-18 9:22 ` [PATCH 04/43] KVM: Unify the delivery of IOAPIC and MSI interrupts Avi Kivity
` (39 subsequent siblings)
42 siblings, 0 replies; 44+ messages in thread
From: Avi Kivity @ 2009-05-18 9:22 UTC (permalink / raw)
To: linux-kernel; +Cc: kvm
From: Sheng Yang <sheng@linux.intel.com>
Prepared for reuse ioapic_redir_entry for MSI.
Signed-off-by: Sheng Yang <sheng@linux.intel.com>
Signed-off-by: Avi Kivity <avi@redhat.com>
---
include/linux/kvm_types.h | 17 +++++++++++++++++
virt/kvm/ioapic.c | 6 +++---
virt/kvm/ioapic.h | 17 +----------------
3 files changed, 21 insertions(+), 19 deletions(-)
diff --git a/include/linux/kvm_types.h b/include/linux/kvm_types.h
index 2b8318c..b84aca3 100644
--- a/include/linux/kvm_types.h
+++ b/include/linux/kvm_types.h
@@ -40,4 +40,21 @@ typedef unsigned long hfn_t;
typedef hfn_t pfn_t;
+union kvm_ioapic_redirect_entry {
+ 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;
+};
+
#endif /* __KVM_TYPES_H__ */
diff --git a/virt/kvm/ioapic.c b/virt/kvm/ioapic.c
index c3b99de..8128013 100644
--- a/virt/kvm/ioapic.c
+++ b/virt/kvm/ioapic.c
@@ -85,7 +85,7 @@ static unsigned long ioapic_read_indirect(struct kvm_ioapic *ioapic,
static int ioapic_service(struct kvm_ioapic *ioapic, unsigned int idx)
{
- union ioapic_redir_entry *pent;
+ union kvm_ioapic_redirect_entry *pent;
int injected = -1;
pent = &ioapic->redirtbl[idx];
@@ -284,7 +284,7 @@ int kvm_ioapic_set_irq(struct kvm_ioapic *ioapic, int irq, int level)
{
u32 old_irr = ioapic->irr;
u32 mask = 1 << irq;
- union ioapic_redir_entry entry;
+ union kvm_ioapic_redirect_entry entry;
int ret = 1;
if (irq >= 0 && irq < IOAPIC_NUM_PINS) {
@@ -305,7 +305,7 @@ int kvm_ioapic_set_irq(struct kvm_ioapic *ioapic, int irq, int level)
static void __kvm_ioapic_update_eoi(struct kvm_ioapic *ioapic, int pin,
int trigger_mode)
{
- union ioapic_redir_entry *ent;
+ union kvm_ioapic_redirect_entry *ent;
ent = &ioapic->redirtbl[pin];
diff --git a/virt/kvm/ioapic.h b/virt/kvm/ioapic.h
index a34bd5e..008ec87 100644
--- a/virt/kvm/ioapic.h
+++ b/virt/kvm/ioapic.h
@@ -40,22 +40,7 @@ struct kvm_ioapic {
u32 id;
u32 irr;
u32 pad;
- union ioapic_redir_entry {
- 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[IOAPIC_NUM_PINS];
+ union kvm_ioapic_redirect_entry redirtbl[IOAPIC_NUM_PINS];
struct kvm_io_device dev;
struct kvm *kvm;
void (*ack_notifier)(void *opaque, int irq);
--
1.6.0.6
^ permalink raw reply [flat|nested] 44+ messages in thread* [PATCH 04/43] KVM: Unify the delivery of IOAPIC and MSI interrupts
2009-05-18 9:22 [PATCH 00/43] KVM updates for the 2.6.31 merge window (batch 1/4) Avi Kivity
` (2 preceding siblings ...)
2009-05-18 9:22 ` [PATCH 03/43] KVM: Split IOAPIC structure Avi Kivity
@ 2009-05-18 9:22 ` Avi Kivity
2009-05-18 9:22 ` [PATCH 05/43] KVM: Change API of kvm_ioapic_get_delivery_bitmask Avi Kivity
` (38 subsequent siblings)
42 siblings, 0 replies; 44+ messages in thread
From: Avi Kivity @ 2009-05-18 9:22 UTC (permalink / raw)
To: linux-kernel; +Cc: kvm
From: Sheng Yang <sheng@linux.intel.com>
Signed-off-by: Sheng Yang <sheng@linux.intel.com>
Signed-off-by: Avi Kivity <avi@redhat.com>
---
include/linux/kvm_host.h | 3 +
virt/kvm/ioapic.c | 91 ++++++++++++++++---------------------------
virt/kvm/irq_comm.c | 95 ++++++++++++++++++++++++++++------------------
3 files changed, 95 insertions(+), 94 deletions(-)
diff --git a/include/linux/kvm_host.h b/include/linux/kvm_host.h
index 894a56e..1a2f98f 100644
--- a/include/linux/kvm_host.h
+++ b/include/linux/kvm_host.h
@@ -352,6 +352,9 @@ void kvm_unregister_irq_mask_notifier(struct kvm *kvm, int irq,
struct kvm_irq_mask_notifier *kimn);
void kvm_fire_mask_notifiers(struct kvm *kvm, int irq, bool mask);
+void kvm_get_intr_delivery_bitmask(struct kvm_ioapic *ioapic,
+ union kvm_ioapic_redirect_entry *entry,
+ unsigned long *deliver_bitmask);
int kvm_set_irq(struct kvm *kvm, int irq_source_id, int irq, int level);
void kvm_notify_acked_irq(struct kvm *kvm, unsigned irqchip, unsigned pin);
void kvm_register_irq_ack_notifier(struct kvm *kvm,
diff --git a/virt/kvm/ioapic.c b/virt/kvm/ioapic.c
index 8128013..883fd0d 100644
--- a/virt/kvm/ioapic.c
+++ b/virt/kvm/ioapic.c
@@ -203,79 +203,56 @@ u32 kvm_ioapic_get_delivery_bitmask(struct kvm_ioapic *ioapic, u8 dest,
static int ioapic_deliver(struct kvm_ioapic *ioapic, int irq)
{
- u8 dest = ioapic->redirtbl[irq].fields.dest_id;
- u8 dest_mode = ioapic->redirtbl[irq].fields.dest_mode;
- u8 delivery_mode = ioapic->redirtbl[irq].fields.delivery_mode;
- u8 vector = ioapic->redirtbl[irq].fields.vector;
- u8 trig_mode = ioapic->redirtbl[irq].fields.trig_mode;
- u32 deliver_bitmask;
+ union kvm_ioapic_redirect_entry entry = ioapic->redirtbl[irq];
+ unsigned long deliver_bitmask;
struct kvm_vcpu *vcpu;
int vcpu_id, r = -1;
ioapic_debug("dest=%x dest_mode=%x delivery_mode=%x "
"vector=%x trig_mode=%x\n",
- dest, dest_mode, delivery_mode, vector, trig_mode);
+ entry.fields.dest, entry.fields.dest_mode,
+ entry.fields.delivery_mode, entry.fields.vector,
+ entry.fields.trig_mode);
- deliver_bitmask = kvm_ioapic_get_delivery_bitmask(ioapic, dest,
- dest_mode);
+ kvm_get_intr_delivery_bitmask(ioapic, &entry, &deliver_bitmask);
if (!deliver_bitmask) {
ioapic_debug("no target on destination\n");
return 0;
}
- switch (delivery_mode) {
- case IOAPIC_LOWEST_PRIORITY:
- vcpu = kvm_get_lowest_prio_vcpu(ioapic->kvm, vector,
- deliver_bitmask);
+ /* Always delivery PIT interrupt to vcpu 0 */
#ifdef CONFIG_X86
- if (irq == 0)
- vcpu = ioapic->kvm->vcpus[0];
+ if (irq == 0)
+ deliver_bitmask = 1;
#endif
- if (vcpu != NULL)
- r = ioapic_inj_irq(ioapic, vcpu, vector,
- trig_mode, delivery_mode);
- else
- ioapic_debug("null lowest prio vcpu: "
- "mask=%x vector=%x delivery_mode=%x\n",
- deliver_bitmask, vector, IOAPIC_LOWEST_PRIORITY);
- break;
- case IOAPIC_FIXED:
-#ifdef CONFIG_X86
- if (irq == 0)
- deliver_bitmask = 1;
-#endif
- for (vcpu_id = 0; deliver_bitmask != 0; vcpu_id++) {
- if (!(deliver_bitmask & (1 << vcpu_id)))
- continue;
- deliver_bitmask &= ~(1 << vcpu_id);
- vcpu = ioapic->kvm->vcpus[vcpu_id];
- if (vcpu) {
+
+ for (vcpu_id = 0; deliver_bitmask != 0; vcpu_id++) {
+ if (!(deliver_bitmask & (1 << vcpu_id)))
+ continue;
+ deliver_bitmask &= ~(1 << vcpu_id);
+ vcpu = ioapic->kvm->vcpus[vcpu_id];
+ if (vcpu) {
+ if (entry.fields.delivery_mode ==
+ IOAPIC_LOWEST_PRIORITY ||
+ entry.fields.delivery_mode == IOAPIC_FIXED) {
if (r < 0)
r = 0;
- r += ioapic_inj_irq(ioapic, vcpu, vector,
- trig_mode, delivery_mode);
- }
- }
- break;
- case IOAPIC_NMI:
- for (vcpu_id = 0; deliver_bitmask != 0; vcpu_id++) {
- if (!(deliver_bitmask & (1 << vcpu_id)))
- continue;
- deliver_bitmask &= ~(1 << vcpu_id);
- vcpu = ioapic->kvm->vcpus[vcpu_id];
- if (vcpu) {
- ioapic_inj_nmi(vcpu);
+ r += ioapic_inj_irq(ioapic, vcpu,
+ entry.fields.vector,
+ entry.fields.trig_mode,
+ entry.fields.delivery_mode);
+ } else if (entry.fields.delivery_mode == IOAPIC_NMI) {
r = 1;
- }
- else
- ioapic_debug("NMI to vcpu %d failed\n",
- vcpu->vcpu_id);
- }
- break;
- default:
- printk(KERN_WARNING "Unsupported delivery mode %d\n",
- delivery_mode);
- break;
+ ioapic_inj_nmi(vcpu);
+ } else
+ ioapic_debug("unsupported delivery mode %x!\n",
+ entry.fields.delivery_mode);
+ } else
+ ioapic_debug("null destination vcpu: "
+ "mask=%x vector=%x delivery_mode=%x\n",
+ entry.fields.deliver_bitmask,
+ entry.fields.vector,
+ entry.fields.delivery_mode);
}
return r;
}
diff --git a/virt/kvm/irq_comm.c b/virt/kvm/irq_comm.c
index 864ac54..aec7a0d 100644
--- a/virt/kvm/irq_comm.c
+++ b/virt/kvm/irq_comm.c
@@ -43,53 +43,74 @@ static int kvm_set_ioapic_irq(struct kvm_kernel_irq_routing_entry *e,
return kvm_ioapic_set_irq(kvm->arch.vioapic, e->irqchip.pin, level);
}
+void kvm_get_intr_delivery_bitmask(struct kvm_ioapic *ioapic,
+ union kvm_ioapic_redirect_entry *entry,
+ unsigned long *deliver_bitmask)
+{
+ struct kvm_vcpu *vcpu;
+
+ *deliver_bitmask = kvm_ioapic_get_delivery_bitmask(ioapic,
+ entry->fields.dest_id, entry->fields.dest_mode);
+ switch (entry->fields.delivery_mode) {
+ case IOAPIC_LOWEST_PRIORITY:
+ vcpu = kvm_get_lowest_prio_vcpu(ioapic->kvm,
+ entry->fields.vector, *deliver_bitmask);
+ *deliver_bitmask = 1 << vcpu->vcpu_id;
+ break;
+ case IOAPIC_FIXED:
+ case IOAPIC_NMI:
+ break;
+ default:
+ if (printk_ratelimit())
+ printk(KERN_INFO "kvm: unsupported delivery mode %d\n",
+ entry->fields.delivery_mode);
+ *deliver_bitmask = 0;
+ }
+}
+
static int kvm_set_msi(struct kvm_kernel_irq_routing_entry *e,
struct kvm *kvm, int level)
{
int vcpu_id, r = -1;
struct kvm_vcpu *vcpu;
struct kvm_ioapic *ioapic = ioapic_irqchip(kvm);
- int dest_id = (e->msi.address_lo & MSI_ADDR_DEST_ID_MASK)
- >> MSI_ADDR_DEST_ID_SHIFT;
- int vector = (e->msi.data & MSI_DATA_VECTOR_MASK)
- >> MSI_DATA_VECTOR_SHIFT;
- int dest_mode = test_bit(MSI_ADDR_DEST_MODE_SHIFT,
- (unsigned long *)&e->msi.address_lo);
- int trig_mode = test_bit(MSI_DATA_TRIGGER_SHIFT,
- (unsigned long *)&e->msi.data);
- int delivery_mode = test_bit(MSI_DATA_DELIVERY_MODE_SHIFT,
- (unsigned long *)&e->msi.data);
- u32 deliver_bitmask;
+ union kvm_ioapic_redirect_entry entry;
+ unsigned long deliver_bitmask;
BUG_ON(!ioapic);
- deliver_bitmask = kvm_ioapic_get_delivery_bitmask(ioapic,
- dest_id, dest_mode);
- /* IOAPIC delivery mode value is the same as MSI here */
- switch (delivery_mode) {
- case IOAPIC_LOWEST_PRIORITY:
- vcpu = kvm_get_lowest_prio_vcpu(ioapic->kvm, vector,
- deliver_bitmask);
- if (vcpu != NULL)
- r = kvm_apic_set_irq(vcpu, vector, trig_mode);
- else
- printk(KERN_INFO "kvm: null lowest priority vcpu!\n");
- break;
- case IOAPIC_FIXED:
- for (vcpu_id = 0; deliver_bitmask != 0; vcpu_id++) {
- if (!(deliver_bitmask & (1 << vcpu_id)))
- continue;
- deliver_bitmask &= ~(1 << vcpu_id);
- vcpu = ioapic->kvm->vcpus[vcpu_id];
- if (vcpu) {
- if (r < 0)
- r = 0;
- r += kvm_apic_set_irq(vcpu, vector, trig_mode);
- }
+ entry.bits = 0;
+ entry.fields.dest_id = (e->msi.address_lo &
+ MSI_ADDR_DEST_ID_MASK) >> MSI_ADDR_DEST_ID_SHIFT;
+ entry.fields.vector = (e->msi.data &
+ MSI_DATA_VECTOR_MASK) >> MSI_DATA_VECTOR_SHIFT;
+ entry.fields.dest_mode = test_bit(MSI_ADDR_DEST_MODE_SHIFT,
+ (unsigned long *)&e->msi.address_lo);
+ entry.fields.trig_mode = test_bit(MSI_DATA_TRIGGER_SHIFT,
+ (unsigned long *)&e->msi.data);
+ entry.fields.delivery_mode = test_bit(
+ MSI_DATA_DELIVERY_MODE_SHIFT,
+ (unsigned long *)&e->msi.data);
+
+ /* TODO Deal with RH bit of MSI message address */
+
+ kvm_get_intr_delivery_bitmask(ioapic, &entry, &deliver_bitmask);
+
+ if (!deliver_bitmask) {
+ printk(KERN_WARNING "kvm: no destination for MSI delivery!");
+ return -1;
+ }
+ for (vcpu_id = 0; deliver_bitmask != 0; vcpu_id++) {
+ if (!(deliver_bitmask & (1 << vcpu_id)))
+ continue;
+ deliver_bitmask &= ~(1 << vcpu_id);
+ vcpu = ioapic->kvm->vcpus[vcpu_id];
+ if (vcpu) {
+ if (r < 0)
+ r = 0;
+ r += kvm_apic_set_irq(vcpu, entry.fields.vector,
+ entry.fields.trig_mode);
}
- break;
- default:
- break;
}
return r;
}
--
1.6.0.6
^ permalink raw reply [flat|nested] 44+ messages in thread* [PATCH 05/43] KVM: Change API of kvm_ioapic_get_delivery_bitmask
2009-05-18 9:22 [PATCH 00/43] KVM updates for the 2.6.31 merge window (batch 1/4) Avi Kivity
` (3 preceding siblings ...)
2009-05-18 9:22 ` [PATCH 04/43] KVM: Unify the delivery of IOAPIC and MSI interrupts Avi Kivity
@ 2009-05-18 9:22 ` Avi Kivity
2009-05-18 9:22 ` [PATCH 06/43] KVM: Update intr delivery func to accept unsigned long* bitmap Avi Kivity
` (37 subsequent siblings)
42 siblings, 0 replies; 44+ messages in thread
From: Avi Kivity @ 2009-05-18 9:22 UTC (permalink / raw)
To: linux-kernel; +Cc: kvm
From: Sheng Yang <sheng@linux.intel.com>
In order to use with bit ops.
Signed-off-by: Sheng Yang <sheng@linux.intel.com>
Signed-off-by: Avi Kivity <avi@redhat.com>
---
virt/kvm/ioapic.c | 17 ++++++++---------
virt/kvm/ioapic.h | 4 ++--
virt/kvm/irq_comm.c | 5 +++--
3 files changed, 13 insertions(+), 13 deletions(-)
diff --git a/virt/kvm/ioapic.c b/virt/kvm/ioapic.c
index 883fd0d..3b53712 100644
--- a/virt/kvm/ioapic.c
+++ b/virt/kvm/ioapic.c
@@ -161,22 +161,22 @@ static void ioapic_inj_nmi(struct kvm_vcpu *vcpu)
kvm_vcpu_kick(vcpu);
}
-u32 kvm_ioapic_get_delivery_bitmask(struct kvm_ioapic *ioapic, u8 dest,
- u8 dest_mode)
+void kvm_ioapic_get_delivery_bitmask(struct kvm_ioapic *ioapic, u8 dest,
+ u8 dest_mode, unsigned long *mask)
{
- u32 mask = 0;
int i;
struct kvm *kvm = ioapic->kvm;
struct kvm_vcpu *vcpu;
ioapic_debug("dest %d dest_mode %d\n", dest, dest_mode);
+ *mask = 0;
if (dest_mode == 0) { /* Physical mode. */
if (dest == 0xFF) { /* Broadcast. */
for (i = 0; i < KVM_MAX_VCPUS; ++i)
if (kvm->vcpus[i] && kvm->vcpus[i]->arch.apic)
- mask |= 1 << i;
- return mask;
+ *mask |= 1 << i;
+ return;
}
for (i = 0; i < KVM_MAX_VCPUS; ++i) {
vcpu = kvm->vcpus[i];
@@ -184,7 +184,7 @@ u32 kvm_ioapic_get_delivery_bitmask(struct kvm_ioapic *ioapic, u8 dest,
continue;
if (kvm_apic_match_physical_addr(vcpu->arch.apic, dest)) {
if (vcpu->arch.apic)
- mask = 1 << i;
+ *mask = 1 << i;
break;
}
}
@@ -195,10 +195,9 @@ u32 kvm_ioapic_get_delivery_bitmask(struct kvm_ioapic *ioapic, u8 dest,
continue;
if (vcpu->arch.apic &&
kvm_apic_match_logical_addr(vcpu->arch.apic, dest))
- mask |= 1 << vcpu->vcpu_id;
+ *mask |= 1 << vcpu->vcpu_id;
}
- ioapic_debug("mask %x\n", mask);
- return mask;
+ ioapic_debug("mask %x\n", *mask);
}
static int ioapic_deliver(struct kvm_ioapic *ioapic, int irq)
diff --git a/virt/kvm/ioapic.h b/virt/kvm/ioapic.h
index 008ec87..f395798 100644
--- a/virt/kvm/ioapic.h
+++ b/virt/kvm/ioapic.h
@@ -70,7 +70,7 @@ void kvm_ioapic_update_eoi(struct kvm *kvm, int vector, int trigger_mode);
int kvm_ioapic_init(struct kvm *kvm);
int kvm_ioapic_set_irq(struct kvm_ioapic *ioapic, int irq, int level);
void kvm_ioapic_reset(struct kvm_ioapic *ioapic);
-u32 kvm_ioapic_get_delivery_bitmask(struct kvm_ioapic *ioapic, u8 dest,
- u8 dest_mode);
+void kvm_ioapic_get_delivery_bitmask(struct kvm_ioapic *ioapic, u8 dest,
+ u8 dest_mode, unsigned long *mask);
#endif
diff --git a/virt/kvm/irq_comm.c b/virt/kvm/irq_comm.c
index aec7a0d..e8ff89c 100644
--- a/virt/kvm/irq_comm.c
+++ b/virt/kvm/irq_comm.c
@@ -49,8 +49,9 @@ void kvm_get_intr_delivery_bitmask(struct kvm_ioapic *ioapic,
{
struct kvm_vcpu *vcpu;
- *deliver_bitmask = kvm_ioapic_get_delivery_bitmask(ioapic,
- entry->fields.dest_id, entry->fields.dest_mode);
+ kvm_ioapic_get_delivery_bitmask(ioapic, entry->fields.dest_id,
+ entry->fields.dest_mode,
+ deliver_bitmask);
switch (entry->fields.delivery_mode) {
case IOAPIC_LOWEST_PRIORITY:
vcpu = kvm_get_lowest_prio_vcpu(ioapic->kvm,
--
1.6.0.6
^ permalink raw reply [flat|nested] 44+ messages in thread* [PATCH 06/43] KVM: Update intr delivery func to accept unsigned long* bitmap
2009-05-18 9:22 [PATCH 00/43] KVM updates for the 2.6.31 merge window (batch 1/4) Avi Kivity
` (4 preceding siblings ...)
2009-05-18 9:22 ` [PATCH 05/43] KVM: Change API of kvm_ioapic_get_delivery_bitmask Avi Kivity
@ 2009-05-18 9:22 ` Avi Kivity
2009-05-18 9:22 ` [PATCH 07/43] KVM: bit ops for deliver_bitmap Avi Kivity
` (36 subsequent siblings)
42 siblings, 0 replies; 44+ messages in thread
From: Avi Kivity @ 2009-05-18 9:22 UTC (permalink / raw)
To: linux-kernel; +Cc: kvm
From: Sheng Yang <sheng@linux.intel.com>
Would be used with bit ops, and would be easily extended if KVM_MAX_VCPUS is
increased.
Signed-off-by: Sheng Yang <sheng@linux.intel.com>
Signed-off-by: Avi Kivity <avi@redhat.com>
---
arch/x86/kvm/lapic.c | 8 ++++----
virt/kvm/ioapic.h | 2 +-
virt/kvm/irq_comm.c | 2 +-
3 files changed, 6 insertions(+), 6 deletions(-)
diff --git a/arch/x86/kvm/lapic.c b/arch/x86/kvm/lapic.c
index f0b67f2..6aa8d20 100644
--- a/arch/x86/kvm/lapic.c
+++ b/arch/x86/kvm/lapic.c
@@ -409,7 +409,7 @@ static int __apic_accept_irq(struct kvm_lapic *apic, int delivery_mode,
}
static struct kvm_lapic *kvm_apic_round_robin(struct kvm *kvm, u8 vector,
- unsigned long bitmap)
+ unsigned long *bitmap)
{
int last;
int next;
@@ -421,7 +421,7 @@ static struct kvm_lapic *kvm_apic_round_robin(struct kvm *kvm, u8 vector,
do {
if (++next == KVM_MAX_VCPUS)
next = 0;
- if (kvm->vcpus[next] == NULL || !test_bit(next, &bitmap))
+ if (kvm->vcpus[next] == NULL || !test_bit(next, bitmap))
continue;
apic = kvm->vcpus[next]->arch.apic;
if (apic && apic_enabled(apic))
@@ -437,7 +437,7 @@ static struct kvm_lapic *kvm_apic_round_robin(struct kvm *kvm, u8 vector,
}
struct kvm_vcpu *kvm_get_lowest_prio_vcpu(struct kvm *kvm, u8 vector,
- unsigned long bitmap)
+ unsigned long *bitmap)
{
struct kvm_lapic *apic;
@@ -508,7 +508,7 @@ static void apic_send_ipi(struct kvm_lapic *apic)
}
if (delivery_mode == APIC_DM_LOWEST) {
- target = kvm_get_lowest_prio_vcpu(vcpu->kvm, vector, lpr_map);
+ target = kvm_get_lowest_prio_vcpu(vcpu->kvm, vector, &lpr_map);
if (target != NULL)
__apic_accept_irq(target->arch.apic, delivery_mode,
vector, level, trig_mode);
diff --git a/virt/kvm/ioapic.h b/virt/kvm/ioapic.h
index f395798..7275f87 100644
--- a/virt/kvm/ioapic.h
+++ b/virt/kvm/ioapic.h
@@ -65,7 +65,7 @@ static inline struct kvm_ioapic *ioapic_irqchip(struct kvm *kvm)
}
struct kvm_vcpu *kvm_get_lowest_prio_vcpu(struct kvm *kvm, u8 vector,
- unsigned long bitmap);
+ unsigned long *bitmap);
void kvm_ioapic_update_eoi(struct kvm *kvm, int vector, int trigger_mode);
int kvm_ioapic_init(struct kvm *kvm);
int kvm_ioapic_set_irq(struct kvm_ioapic *ioapic, int irq, int level);
diff --git a/virt/kvm/irq_comm.c b/virt/kvm/irq_comm.c
index e8ff89c..d4421cd 100644
--- a/virt/kvm/irq_comm.c
+++ b/virt/kvm/irq_comm.c
@@ -55,7 +55,7 @@ void kvm_get_intr_delivery_bitmask(struct kvm_ioapic *ioapic,
switch (entry->fields.delivery_mode) {
case IOAPIC_LOWEST_PRIORITY:
vcpu = kvm_get_lowest_prio_vcpu(ioapic->kvm,
- entry->fields.vector, *deliver_bitmask);
+ entry->fields.vector, deliver_bitmask);
*deliver_bitmask = 1 << vcpu->vcpu_id;
break;
case IOAPIC_FIXED:
--
1.6.0.6
^ permalink raw reply [flat|nested] 44+ messages in thread* [PATCH 07/43] KVM: bit ops for deliver_bitmap
2009-05-18 9:22 [PATCH 00/43] KVM updates for the 2.6.31 merge window (batch 1/4) Avi Kivity
` (5 preceding siblings ...)
2009-05-18 9:22 ` [PATCH 06/43] KVM: Update intr delivery func to accept unsigned long* bitmap Avi Kivity
@ 2009-05-18 9:22 ` Avi Kivity
2009-05-18 9:22 ` [PATCH 08/43] KVM: Ioctls for init MSI-X entry Avi Kivity
` (35 subsequent siblings)
42 siblings, 0 replies; 44+ messages in thread
From: Avi Kivity @ 2009-05-18 9:22 UTC (permalink / raw)
To: linux-kernel; +Cc: kvm
From: Sheng Yang <sheng@linux.intel.com>
It's also convenient when we extend KVM supported vcpu number in the future.
Signed-off-by: Sheng Yang <sheng@linux.intel.com>
Signed-off-by: Avi Kivity <avi@redhat.com>
---
arch/x86/kvm/lapic.c | 7 ++++---
virt/kvm/ioapic.c | 24 +++++++++++++-----------
virt/kvm/irq_comm.c | 17 +++++++++--------
3 files changed, 26 insertions(+), 22 deletions(-)
diff --git a/arch/x86/kvm/lapic.c b/arch/x86/kvm/lapic.c
index 6aa8d20..afc59b2 100644
--- a/arch/x86/kvm/lapic.c
+++ b/arch/x86/kvm/lapic.c
@@ -483,9 +483,10 @@ static void apic_send_ipi(struct kvm_lapic *apic)
struct kvm_vcpu *target;
struct kvm_vcpu *vcpu;
- unsigned long lpr_map = 0;
+ DECLARE_BITMAP(lpr_map, KVM_MAX_VCPUS);
int i;
+ bitmap_zero(lpr_map, KVM_MAX_VCPUS);
apic_debug("icr_high 0x%x, icr_low 0x%x, "
"short_hand 0x%x, dest 0x%x, trig_mode 0x%x, level 0x%x, "
"dest_mode 0x%x, delivery_mode 0x%x, vector 0x%x\n",
@@ -500,7 +501,7 @@ static void apic_send_ipi(struct kvm_lapic *apic)
if (vcpu->arch.apic &&
apic_match_dest(vcpu, apic, short_hand, dest, dest_mode)) {
if (delivery_mode == APIC_DM_LOWEST)
- set_bit(vcpu->vcpu_id, &lpr_map);
+ __set_bit(vcpu->vcpu_id, lpr_map);
else
__apic_accept_irq(vcpu->arch.apic, delivery_mode,
vector, level, trig_mode);
@@ -508,7 +509,7 @@ static void apic_send_ipi(struct kvm_lapic *apic)
}
if (delivery_mode == APIC_DM_LOWEST) {
- target = kvm_get_lowest_prio_vcpu(vcpu->kvm, vector, &lpr_map);
+ target = kvm_get_lowest_prio_vcpu(vcpu->kvm, vector, lpr_map);
if (target != NULL)
__apic_accept_irq(target->arch.apic, delivery_mode,
vector, level, trig_mode);
diff --git a/virt/kvm/ioapic.c b/virt/kvm/ioapic.c
index 3b53712..7c2cb2b 100644
--- a/virt/kvm/ioapic.c
+++ b/virt/kvm/ioapic.c
@@ -203,7 +203,7 @@ void kvm_ioapic_get_delivery_bitmask(struct kvm_ioapic *ioapic, u8 dest,
static int ioapic_deliver(struct kvm_ioapic *ioapic, int irq)
{
union kvm_ioapic_redirect_entry entry = ioapic->redirtbl[irq];
- unsigned long deliver_bitmask;
+ DECLARE_BITMAP(deliver_bitmask, KVM_MAX_VCPUS);
struct kvm_vcpu *vcpu;
int vcpu_id, r = -1;
@@ -213,22 +213,24 @@ static int ioapic_deliver(struct kvm_ioapic *ioapic, int irq)
entry.fields.delivery_mode, entry.fields.vector,
entry.fields.trig_mode);
- kvm_get_intr_delivery_bitmask(ioapic, &entry, &deliver_bitmask);
- if (!deliver_bitmask) {
- ioapic_debug("no target on destination\n");
- return 0;
- }
+ bitmap_zero(deliver_bitmask, KVM_MAX_VCPUS);
/* Always delivery PIT interrupt to vcpu 0 */
#ifdef CONFIG_X86
if (irq == 0)
- deliver_bitmask = 1;
+ __set_bit(0, deliver_bitmask);
+ else
#endif
+ kvm_get_intr_delivery_bitmask(ioapic, &entry, deliver_bitmask);
+
+ if (find_first_bit(deliver_bitmask, KVM_MAX_VCPUS) >= KVM_MAX_VCPUS) {
+ ioapic_debug("no target on destination\n");
+ return 0;
+ }
- for (vcpu_id = 0; deliver_bitmask != 0; vcpu_id++) {
- if (!(deliver_bitmask & (1 << vcpu_id)))
- continue;
- deliver_bitmask &= ~(1 << vcpu_id);
+ while ((vcpu_id = find_first_bit(deliver_bitmask, KVM_MAX_VCPUS))
+ < KVM_MAX_VCPUS) {
+ __clear_bit(vcpu_id, deliver_bitmask);
vcpu = ioapic->kvm->vcpus[vcpu_id];
if (vcpu) {
if (entry.fields.delivery_mode ==
diff --git a/virt/kvm/irq_comm.c b/virt/kvm/irq_comm.c
index d4421cd..d165e05 100644
--- a/virt/kvm/irq_comm.c
+++ b/virt/kvm/irq_comm.c
@@ -56,7 +56,7 @@ void kvm_get_intr_delivery_bitmask(struct kvm_ioapic *ioapic,
case IOAPIC_LOWEST_PRIORITY:
vcpu = kvm_get_lowest_prio_vcpu(ioapic->kvm,
entry->fields.vector, deliver_bitmask);
- *deliver_bitmask = 1 << vcpu->vcpu_id;
+ __set_bit(vcpu->vcpu_id, deliver_bitmask);
break;
case IOAPIC_FIXED:
case IOAPIC_NMI:
@@ -76,10 +76,12 @@ static int kvm_set_msi(struct kvm_kernel_irq_routing_entry *e,
struct kvm_vcpu *vcpu;
struct kvm_ioapic *ioapic = ioapic_irqchip(kvm);
union kvm_ioapic_redirect_entry entry;
- unsigned long deliver_bitmask;
+ DECLARE_BITMAP(deliver_bitmask, KVM_MAX_VCPUS);
BUG_ON(!ioapic);
+ bitmap_zero(deliver_bitmask, KVM_MAX_VCPUS);
+
entry.bits = 0;
entry.fields.dest_id = (e->msi.address_lo &
MSI_ADDR_DEST_ID_MASK) >> MSI_ADDR_DEST_ID_SHIFT;
@@ -95,16 +97,15 @@ static int kvm_set_msi(struct kvm_kernel_irq_routing_entry *e,
/* TODO Deal with RH bit of MSI message address */
- kvm_get_intr_delivery_bitmask(ioapic, &entry, &deliver_bitmask);
+ kvm_get_intr_delivery_bitmask(ioapic, &entry, deliver_bitmask);
- if (!deliver_bitmask) {
+ if (find_first_bit(deliver_bitmask, KVM_MAX_VCPUS) >= KVM_MAX_VCPUS) {
printk(KERN_WARNING "kvm: no destination for MSI delivery!");
return -1;
}
- for (vcpu_id = 0; deliver_bitmask != 0; vcpu_id++) {
- if (!(deliver_bitmask & (1 << vcpu_id)))
- continue;
- deliver_bitmask &= ~(1 << vcpu_id);
+ while ((vcpu_id = find_first_bit(deliver_bitmask,
+ KVM_MAX_VCPUS)) < KVM_MAX_VCPUS) {
+ __clear_bit(vcpu_id, deliver_bitmask);
vcpu = ioapic->kvm->vcpus[vcpu_id];
if (vcpu) {
if (r < 0)
--
1.6.0.6
^ permalink raw reply [flat|nested] 44+ messages in thread* [PATCH 08/43] KVM: Ioctls for init MSI-X entry
2009-05-18 9:22 [PATCH 00/43] KVM updates for the 2.6.31 merge window (batch 1/4) Avi Kivity
` (6 preceding siblings ...)
2009-05-18 9:22 ` [PATCH 07/43] KVM: bit ops for deliver_bitmap Avi Kivity
@ 2009-05-18 9:22 ` Avi Kivity
2009-05-18 9:22 ` [PATCH 09/43] KVM: Add MSI-X interrupt injection logic Avi Kivity
` (34 subsequent siblings)
42 siblings, 0 replies; 44+ messages in thread
From: Avi Kivity @ 2009-05-18 9:22 UTC (permalink / raw)
To: linux-kernel; +Cc: kvm
From: Sheng Yang <sheng@linux.intel.com>
Introduce KVM_SET_MSIX_NR and KVM_SET_MSIX_ENTRY two ioctls.
This two ioctls are used by userspace to specific guest device MSI-X entry
number and correlate MSI-X entry with GSI during the initialization stage.
MSI-X should be well initialzed before enabling.
Don't support change MSI-X entry number for now.
Signed-off-by: Sheng Yang <sheng@linux.intel.com>
Signed-off-by: Avi Kivity <avi@redhat.com>
---
include/linux/kvm.h | 18 ++++++++
include/linux/kvm_host.h | 10 ++++
virt/kvm/kvm_main.c | 104 ++++++++++++++++++++++++++++++++++++++++++++++
3 files changed, 132 insertions(+), 0 deletions(-)
diff --git a/include/linux/kvm.h b/include/linux/kvm.h
index 8cc1379..78cdee8 100644
--- a/include/linux/kvm.h
+++ b/include/linux/kvm.h
@@ -487,6 +487,10 @@ struct kvm_irq_routing {
#define KVM_REINJECT_CONTROL _IO(KVMIO, 0x71)
#define KVM_DEASSIGN_PCI_DEVICE _IOW(KVMIO, 0x72, \
struct kvm_assigned_pci_dev)
+#define KVM_ASSIGN_SET_MSIX_NR \
+ _IOW(KVMIO, 0x73, struct kvm_assigned_msix_nr)
+#define KVM_ASSIGN_SET_MSIX_ENTRY \
+ _IOW(KVMIO, 0x74, struct kvm_assigned_msix_entry)
/*
* ioctls for vcpu fds
@@ -607,4 +611,18 @@ struct kvm_assigned_irq {
#define KVM_DEV_IRQ_ASSIGN_MSI_ACTION KVM_DEV_IRQ_ASSIGN_ENABLE_MSI
#define KVM_DEV_IRQ_ASSIGN_ENABLE_MSI (1 << 0)
+struct kvm_assigned_msix_nr {
+ __u32 assigned_dev_id;
+ __u16 entry_nr;
+ __u16 padding;
+};
+
+#define KVM_MAX_MSIX_PER_DEV 512
+struct kvm_assigned_msix_entry {
+ __u32 assigned_dev_id;
+ __u32 gsi;
+ __u16 entry; /* The index of entry in the MSI-X table */
+ __u16 padding[3];
+};
+
#endif
diff --git a/include/linux/kvm_host.h b/include/linux/kvm_host.h
index 1a2f98f..432edc2 100644
--- a/include/linux/kvm_host.h
+++ b/include/linux/kvm_host.h
@@ -319,6 +319,12 @@ struct kvm_irq_ack_notifier {
void (*irq_acked)(struct kvm_irq_ack_notifier *kian);
};
+struct kvm_guest_msix_entry {
+ u32 vector;
+ u16 entry;
+ u16 flags;
+};
+
struct kvm_assigned_dev_kernel {
struct kvm_irq_ack_notifier ack_notifier;
struct work_struct interrupt_work;
@@ -326,13 +332,17 @@ struct kvm_assigned_dev_kernel {
int assigned_dev_id;
int host_busnr;
int host_devfn;
+ unsigned int entries_nr;
int host_irq;
bool host_irq_disabled;
+ struct msix_entry *host_msix_entries;
int guest_irq;
+ struct kvm_guest_msix_entry *guest_msix_entries;
#define KVM_ASSIGNED_DEV_GUEST_INTX (1 << 0)
#define KVM_ASSIGNED_DEV_GUEST_MSI (1 << 1)
#define KVM_ASSIGNED_DEV_HOST_INTX (1 << 8)
#define KVM_ASSIGNED_DEV_HOST_MSI (1 << 9)
+#define KVM_ASSIGNED_DEV_MSIX ((1 << 2) | (1 << 10))
unsigned long irq_requested_type;
int irq_source_id;
int flags;
diff --git a/virt/kvm/kvm_main.c b/virt/kvm/kvm_main.c
index 1ecbe23..fd33def 100644
--- a/virt/kvm/kvm_main.c
+++ b/virt/kvm/kvm_main.c
@@ -1593,6 +1593,88 @@ static int kvm_vcpu_ioctl_set_sigmask(struct kvm_vcpu *vcpu, sigset_t *sigset)
return 0;
}
+#ifdef __KVM_HAVE_MSIX
+static int kvm_vm_ioctl_set_msix_nr(struct kvm *kvm,
+ struct kvm_assigned_msix_nr *entry_nr)
+{
+ int r = 0;
+ struct kvm_assigned_dev_kernel *adev;
+
+ mutex_lock(&kvm->lock);
+
+ adev = kvm_find_assigned_dev(&kvm->arch.assigned_dev_head,
+ entry_nr->assigned_dev_id);
+ if (!adev) {
+ r = -EINVAL;
+ goto msix_nr_out;
+ }
+
+ if (adev->entries_nr == 0) {
+ adev->entries_nr = entry_nr->entry_nr;
+ if (adev->entries_nr == 0 ||
+ adev->entries_nr >= KVM_MAX_MSIX_PER_DEV) {
+ r = -EINVAL;
+ goto msix_nr_out;
+ }
+
+ adev->host_msix_entries = kzalloc(sizeof(struct msix_entry) *
+ entry_nr->entry_nr,
+ GFP_KERNEL);
+ if (!adev->host_msix_entries) {
+ r = -ENOMEM;
+ goto msix_nr_out;
+ }
+ adev->guest_msix_entries = kzalloc(
+ sizeof(struct kvm_guest_msix_entry) *
+ entry_nr->entry_nr, GFP_KERNEL);
+ if (!adev->guest_msix_entries) {
+ kfree(adev->host_msix_entries);
+ r = -ENOMEM;
+ goto msix_nr_out;
+ }
+ } else /* Not allowed set MSI-X number twice */
+ r = -EINVAL;
+msix_nr_out:
+ mutex_unlock(&kvm->lock);
+ return r;
+}
+
+static int kvm_vm_ioctl_set_msix_entry(struct kvm *kvm,
+ struct kvm_assigned_msix_entry *entry)
+{
+ int r = 0, i;
+ struct kvm_assigned_dev_kernel *adev;
+
+ mutex_lock(&kvm->lock);
+
+ adev = kvm_find_assigned_dev(&kvm->arch.assigned_dev_head,
+ entry->assigned_dev_id);
+
+ if (!adev) {
+ r = -EINVAL;
+ goto msix_entry_out;
+ }
+
+ for (i = 0; i < adev->entries_nr; i++)
+ if (adev->guest_msix_entries[i].vector == 0 ||
+ adev->guest_msix_entries[i].entry == entry->entry) {
+ adev->guest_msix_entries[i].entry = entry->entry;
+ adev->guest_msix_entries[i].vector = entry->gsi;
+ adev->host_msix_entries[i].entry = entry->entry;
+ break;
+ }
+ if (i == adev->entries_nr) {
+ r = -ENOSPC;
+ goto msix_entry_out;
+ }
+
+msix_entry_out:
+ mutex_unlock(&kvm->lock);
+
+ return r;
+}
+#endif
+
static long kvm_vcpu_ioctl(struct file *filp,
unsigned int ioctl, unsigned long arg)
{
@@ -1917,7 +1999,29 @@ static long kvm_vm_ioctl(struct file *filp,
vfree(entries);
break;
}
+#ifdef __KVM_HAVE_MSIX
+ case KVM_ASSIGN_SET_MSIX_NR: {
+ struct kvm_assigned_msix_nr entry_nr;
+ r = -EFAULT;
+ if (copy_from_user(&entry_nr, argp, sizeof entry_nr))
+ goto out;
+ r = kvm_vm_ioctl_set_msix_nr(kvm, &entry_nr);
+ if (r)
+ goto out;
+ break;
+ }
+ case KVM_ASSIGN_SET_MSIX_ENTRY: {
+ struct kvm_assigned_msix_entry entry;
+ r = -EFAULT;
+ if (copy_from_user(&entry, argp, sizeof entry))
+ goto out;
+ r = kvm_vm_ioctl_set_msix_entry(kvm, &entry);
+ if (r)
+ goto out;
+ break;
+ }
#endif
+#endif /* KVM_CAP_IRQ_ROUTING */
default:
r = kvm_arch_vm_ioctl(filp, ioctl, arg);
}
--
1.6.0.6
^ permalink raw reply [flat|nested] 44+ messages in thread* [PATCH 09/43] KVM: Add MSI-X interrupt injection logic
2009-05-18 9:22 [PATCH 00/43] KVM updates for the 2.6.31 merge window (batch 1/4) Avi Kivity
` (7 preceding siblings ...)
2009-05-18 9:22 ` [PATCH 08/43] KVM: Ioctls for init MSI-X entry Avi Kivity
@ 2009-05-18 9:22 ` Avi Kivity
2009-05-18 9:22 ` [PATCH 10/43] KVM: Enable MSI-X for KVM assigned device Avi Kivity
` (33 subsequent siblings)
42 siblings, 0 replies; 44+ messages in thread
From: Avi Kivity @ 2009-05-18 9:22 UTC (permalink / raw)
To: linux-kernel; +Cc: kvm
From: Sheng Yang <sheng@linux.intel.com>
We have to handle more than one interrupt with one handler for MSI-X. Avi
suggested to use a flag to indicate the pending. So here is it.
Signed-off-by: Sheng Yang <sheng@linux.intel.com>
Signed-off-by: Avi Kivity <avi@redhat.com>
---
include/linux/kvm_host.h | 1 +
virt/kvm/kvm_main.c | 66 +++++++++++++++++++++++++++++++++++++++++-----
2 files changed, 60 insertions(+), 7 deletions(-)
diff --git a/include/linux/kvm_host.h b/include/linux/kvm_host.h
index 432edc2..3832243 100644
--- a/include/linux/kvm_host.h
+++ b/include/linux/kvm_host.h
@@ -319,6 +319,7 @@ struct kvm_irq_ack_notifier {
void (*irq_acked)(struct kvm_irq_ack_notifier *kian);
};
+#define KVM_ASSIGNED_MSIX_PENDING 0x1
struct kvm_guest_msix_entry {
u32 vector;
u16 entry;
diff --git a/virt/kvm/kvm_main.c b/virt/kvm/kvm_main.c
index fd33def..7c20e06 100644
--- a/virt/kvm/kvm_main.c
+++ b/virt/kvm/kvm_main.c
@@ -95,25 +95,69 @@ static struct kvm_assigned_dev_kernel *kvm_find_assigned_dev(struct list_head *h
return NULL;
}
+static int find_index_from_host_irq(struct kvm_assigned_dev_kernel
+ *assigned_dev, int irq)
+{
+ int i, index;
+ struct msix_entry *host_msix_entries;
+
+ host_msix_entries = assigned_dev->host_msix_entries;
+
+ index = -1;
+ for (i = 0; i < assigned_dev->entries_nr; i++)
+ if (irq == host_msix_entries[i].vector) {
+ index = i;
+ break;
+ }
+ if (index < 0) {
+ printk(KERN_WARNING "Fail to find correlated MSI-X entry!\n");
+ return 0;
+ }
+
+ return index;
+}
+
static void kvm_assigned_dev_interrupt_work_handler(struct work_struct *work)
{
struct kvm_assigned_dev_kernel *assigned_dev;
+ struct kvm *kvm;
+ int irq, i;
assigned_dev = container_of(work, struct kvm_assigned_dev_kernel,
interrupt_work);
+ kvm = assigned_dev->kvm;
/* This is taken to safely inject irq inside the guest. When
* the interrupt injection (or the ioapic code) uses a
* finer-grained lock, update this
*/
- mutex_lock(&assigned_dev->kvm->lock);
- kvm_set_irq(assigned_dev->kvm, assigned_dev->irq_source_id,
- assigned_dev->guest_irq, 1);
-
- if (assigned_dev->irq_requested_type & KVM_ASSIGNED_DEV_GUEST_MSI) {
- enable_irq(assigned_dev->host_irq);
- assigned_dev->host_irq_disabled = false;
+ mutex_lock(&kvm->lock);
+ if (assigned_dev->irq_requested_type & KVM_ASSIGNED_DEV_MSIX) {
+ struct kvm_guest_msix_entry *guest_entries =
+ assigned_dev->guest_msix_entries;
+ for (i = 0; i < assigned_dev->entries_nr; i++) {
+ if (!(guest_entries[i].flags &
+ KVM_ASSIGNED_MSIX_PENDING))
+ continue;
+ guest_entries[i].flags &= ~KVM_ASSIGNED_MSIX_PENDING;
+ kvm_set_irq(assigned_dev->kvm,
+ assigned_dev->irq_source_id,
+ guest_entries[i].vector, 1);
+ irq = assigned_dev->host_msix_entries[i].vector;
+ if (irq != 0)
+ enable_irq(irq);
+ assigned_dev->host_irq_disabled = false;
+ }
+ } else {
+ kvm_set_irq(assigned_dev->kvm, assigned_dev->irq_source_id,
+ assigned_dev->guest_irq, 1);
+ if (assigned_dev->irq_requested_type &
+ KVM_ASSIGNED_DEV_GUEST_MSI) {
+ enable_irq(assigned_dev->host_irq);
+ assigned_dev->host_irq_disabled = false;
+ }
}
+
mutex_unlock(&assigned_dev->kvm->lock);
}
@@ -122,6 +166,14 @@ static irqreturn_t kvm_assigned_dev_intr(int irq, void *dev_id)
struct kvm_assigned_dev_kernel *assigned_dev =
(struct kvm_assigned_dev_kernel *) dev_id;
+ if (assigned_dev->irq_requested_type == KVM_ASSIGNED_DEV_MSIX) {
+ int index = find_index_from_host_irq(assigned_dev, irq);
+ if (index < 0)
+ return IRQ_HANDLED;
+ assigned_dev->guest_msix_entries[index].flags |=
+ KVM_ASSIGNED_MSIX_PENDING;
+ }
+
schedule_work(&assigned_dev->interrupt_work);
disable_irq_nosync(irq);
--
1.6.0.6
^ permalink raw reply [flat|nested] 44+ messages in thread* [PATCH 10/43] KVM: Enable MSI-X for KVM assigned device
2009-05-18 9:22 [PATCH 00/43] KVM updates for the 2.6.31 merge window (batch 1/4) Avi Kivity
` (8 preceding siblings ...)
2009-05-18 9:22 ` [PATCH 09/43] KVM: Add MSI-X interrupt injection logic Avi Kivity
@ 2009-05-18 9:22 ` Avi Kivity
2009-05-18 9:22 ` [PATCH 11/43] KVM: x86: silence preempt warning on kvm_write_guest_time Avi Kivity
` (32 subsequent siblings)
42 siblings, 0 replies; 44+ messages in thread
From: Avi Kivity @ 2009-05-18 9:22 UTC (permalink / raw)
To: linux-kernel; +Cc: kvm
From: Sheng Yang <sheng@linux.intel.com>
This patch finally enable MSI-X.
What we need for MSI-X:
1. Intercept one page in MMIO region of device. So that we can get guest desired
MSI-X table and set up the real one. Now this have been done by guest, and
transfer to kernel using ioctl KVM_SET_MSIX_NR and KVM_SET_MSIX_ENTRY.
2. Information for incoming interrupt. Now one device can have more than one
interrupt, and they are all handled by one workqueue structure. So we need to
identify them. The previous patch enable gsi_msg_pending_bitmap get this done.
3. Mapping from host IRQ to guest gsi as well as guest gsi to real MSI/MSI-X
message address/data. We used same entry number for the host and guest here, so
that it's easy to find the correlated guest gsi.
What we lack for now:
1. The PCI spec said nothing can existed with MSI-X table in the same page of
MMIO region, except pending bits. The patch ignore pending bits as the first
step (so they are always 0 - no pending).
2. The PCI spec allowed to change MSI-X table dynamically. That means, the OS
can enable MSI-X, then mask one MSI-X entry, modify it, and unmask it. The patch
didn't support this, and Linux also don't work in this way.
3. The patch didn't implement MSI-X mask all and mask single entry. I would
implement the former in driver/pci/msi.c later. And for single entry, userspace
should have reposibility to handle it.
Signed-off-by: Sheng Yang <sheng@linux.intel.com>
Signed-off-by: Avi Kivity <avi@redhat.com>
---
arch/x86/include/asm/kvm.h | 1 +
include/linux/kvm.h | 8 ++++
virt/kvm/kvm_main.c | 98 +++++++++++++++++++++++++++++++++++++++++---
3 files changed, 101 insertions(+), 6 deletions(-)
diff --git a/arch/x86/include/asm/kvm.h b/arch/x86/include/asm/kvm.h
index dc3f6cf..125be8b 100644
--- a/arch/x86/include/asm/kvm.h
+++ b/arch/x86/include/asm/kvm.h
@@ -16,6 +16,7 @@
#define __KVM_HAVE_MSI
#define __KVM_HAVE_USER_NMI
#define __KVM_HAVE_GUEST_DEBUG
+#define __KVM_HAVE_MSIX
/* Architectural interrupt line count. */
#define KVM_NR_INTERRUPTS 256
diff --git a/include/linux/kvm.h b/include/linux/kvm.h
index 78cdee8..640835e 100644
--- a/include/linux/kvm.h
+++ b/include/linux/kvm.h
@@ -409,6 +409,9 @@ struct kvm_trace_rec {
#ifdef __KVM_HAVE_DEVICE_ASSIGNMENT
#define KVM_CAP_DEVICE_DEASSIGNMENT 27
#endif
+#ifdef __KVM_HAVE_MSIX
+#define KVM_CAP_DEVICE_MSIX 28
+#endif
/* Another bug in KVM_SET_USER_MEMORY_REGION fixed: */
#define KVM_CAP_JOIN_MEMORY_REGIONS_WORKS 30
@@ -611,6 +614,11 @@ struct kvm_assigned_irq {
#define KVM_DEV_IRQ_ASSIGN_MSI_ACTION KVM_DEV_IRQ_ASSIGN_ENABLE_MSI
#define KVM_DEV_IRQ_ASSIGN_ENABLE_MSI (1 << 0)
+#define KVM_DEV_IRQ_ASSIGN_MSIX_ACTION (KVM_DEV_IRQ_ASSIGN_ENABLE_MSIX |\
+ KVM_DEV_IRQ_ASSIGN_MASK_MSIX)
+#define KVM_DEV_IRQ_ASSIGN_ENABLE_MSIX (1 << 1)
+#define KVM_DEV_IRQ_ASSIGN_MASK_MSIX (1 << 2)
+
struct kvm_assigned_msix_nr {
__u32 assigned_dev_id;
__u16 entry_nr;
diff --git a/virt/kvm/kvm_main.c b/virt/kvm/kvm_main.c
index 7c20e06..034ed43 100644
--- a/virt/kvm/kvm_main.c
+++ b/virt/kvm/kvm_main.c
@@ -236,13 +236,33 @@ static void kvm_free_assigned_irq(struct kvm *kvm,
* now, the kvm state is still legal for probably we also have to wait
* interrupt_work done.
*/
- disable_irq_nosync(assigned_dev->host_irq);
- cancel_work_sync(&assigned_dev->interrupt_work);
+ if (assigned_dev->irq_requested_type & KVM_ASSIGNED_DEV_MSIX) {
+ int i;
+ for (i = 0; i < assigned_dev->entries_nr; i++)
+ disable_irq_nosync(assigned_dev->
+ host_msix_entries[i].vector);
+
+ cancel_work_sync(&assigned_dev->interrupt_work);
- free_irq(assigned_dev->host_irq, (void *)assigned_dev);
+ for (i = 0; i < assigned_dev->entries_nr; i++)
+ free_irq(assigned_dev->host_msix_entries[i].vector,
+ (void *)assigned_dev);
- if (assigned_dev->irq_requested_type & KVM_ASSIGNED_DEV_HOST_MSI)
- pci_disable_msi(assigned_dev->dev);
+ assigned_dev->entries_nr = 0;
+ kfree(assigned_dev->host_msix_entries);
+ kfree(assigned_dev->guest_msix_entries);
+ pci_disable_msix(assigned_dev->dev);
+ } else {
+ /* Deal with MSI and INTx */
+ disable_irq_nosync(assigned_dev->host_irq);
+ cancel_work_sync(&assigned_dev->interrupt_work);
+
+ free_irq(assigned_dev->host_irq, (void *)assigned_dev);
+
+ if (assigned_dev->irq_requested_type &
+ KVM_ASSIGNED_DEV_HOST_MSI)
+ pci_disable_msi(assigned_dev->dev);
+ }
assigned_dev->irq_requested_type = 0;
}
@@ -373,6 +393,60 @@ static int assigned_device_update_msi(struct kvm *kvm,
}
#endif
+#ifdef __KVM_HAVE_MSIX
+static int assigned_device_update_msix(struct kvm *kvm,
+ struct kvm_assigned_dev_kernel *adev,
+ struct kvm_assigned_irq *airq)
+{
+ /* TODO Deal with KVM_DEV_IRQ_ASSIGNED_MASK_MSIX */
+ int i, r;
+
+ adev->ack_notifier.gsi = -1;
+
+ if (irqchip_in_kernel(kvm)) {
+ if (airq->flags & KVM_DEV_IRQ_ASSIGN_MASK_MSIX)
+ return -ENOTTY;
+
+ if (!(airq->flags & KVM_DEV_IRQ_ASSIGN_ENABLE_MSIX)) {
+ /* Guest disable MSI-X */
+ kvm_free_assigned_irq(kvm, adev);
+ if (msi2intx) {
+ pci_enable_msi(adev->dev);
+ if (adev->dev->msi_enabled)
+ return assigned_device_update_msi(kvm,
+ adev, airq);
+ }
+ return assigned_device_update_intx(kvm, adev, airq);
+ }
+
+ /* host_msix_entries and guest_msix_entries should have been
+ * initialized */
+ if (adev->entries_nr == 0)
+ return -EINVAL;
+
+ kvm_free_assigned_irq(kvm, adev);
+
+ r = pci_enable_msix(adev->dev, adev->host_msix_entries,
+ adev->entries_nr);
+ if (r)
+ return r;
+
+ for (i = 0; i < adev->entries_nr; i++) {
+ r = request_irq((adev->host_msix_entries + i)->vector,
+ kvm_assigned_dev_intr, 0,
+ "kvm_assigned_msix_device",
+ (void *)adev);
+ if (r)
+ return r;
+ }
+ }
+
+ adev->irq_requested_type |= KVM_ASSIGNED_DEV_MSIX;
+
+ return 0;
+}
+#endif
+
static int kvm_vm_ioctl_assign_irq(struct kvm *kvm,
struct kvm_assigned_irq
*assigned_irq)
@@ -417,12 +491,24 @@ static int kvm_vm_ioctl_assign_irq(struct kvm *kvm,
}
}
- if ((match->irq_requested_type & KVM_ASSIGNED_DEV_HOST_MSI) &&
+ if (match->irq_requested_type & KVM_ASSIGNED_DEV_MSIX)
+ current_flags |= KVM_DEV_IRQ_ASSIGN_ENABLE_MSIX;
+ else if ((match->irq_requested_type & KVM_ASSIGNED_DEV_HOST_MSI) &&
(match->irq_requested_type & KVM_ASSIGNED_DEV_GUEST_MSI))
current_flags |= KVM_DEV_IRQ_ASSIGN_ENABLE_MSI;
changed_flags = assigned_irq->flags ^ current_flags;
+#ifdef __KVM_HAVE_MSIX
+ if (changed_flags & KVM_DEV_IRQ_ASSIGN_MSIX_ACTION) {
+ r = assigned_device_update_msix(kvm, match, assigned_irq);
+ if (r) {
+ printk(KERN_WARNING "kvm: failed to execute "
+ "MSI-X action!\n");
+ goto out_release;
+ }
+ } else
+#endif
if ((changed_flags & KVM_DEV_IRQ_ASSIGN_MSI_ACTION) ||
(msi2intx && match->dev->msi_enabled)) {
#ifdef CONFIG_X86
--
1.6.0.6
^ permalink raw reply [flat|nested] 44+ messages in thread* [PATCH 11/43] KVM: x86: silence preempt warning on kvm_write_guest_time
2009-05-18 9:22 [PATCH 00/43] KVM updates for the 2.6.31 merge window (batch 1/4) Avi Kivity
` (9 preceding siblings ...)
2009-05-18 9:22 ` [PATCH 10/43] KVM: Enable MSI-X for KVM assigned device Avi Kivity
@ 2009-05-18 9:22 ` Avi Kivity
2009-05-18 9:22 ` [PATCH 12/43] KVM: x86: paravirt skip pit-through-ioapic boot check Avi Kivity
` (31 subsequent siblings)
42 siblings, 0 replies; 44+ messages in thread
From: Avi Kivity @ 2009-05-18 9:22 UTC (permalink / raw)
To: linux-kernel; +Cc: kvm
From: Matt T. Yourst <yourst@users.sourceforge.net>
This issue just appeared in kvm-84 when running on 2.6.28.7 (x86-64)
with PREEMPT enabled.
We're getting syslog warnings like this many (but not all) times qemu
tells KVM to run the VCPU:
BUG: using smp_processor_id() in preemptible [00000000] code:
qemu-system-x86/28938
caller is kvm_arch_vcpu_ioctl_run+0x5d1/0xc70 [kvm]
Pid: 28938, comm: qemu-system-x86 2.6.28.7-mtyrel-64bit
Call Trace:
debug_smp_processor_id+0xf7/0x100
kvm_arch_vcpu_ioctl_run+0x5d1/0xc70 [kvm]
? __wake_up+0x4e/0x70
? wake_futex+0x27/0x40
kvm_vcpu_ioctl+0x2e9/0x5a0 [kvm]
enqueue_hrtimer+0x8a/0x110
_spin_unlock_irqrestore+0x27/0x50
vfs_ioctl+0x31/0xa0
do_vfs_ioctl+0x74/0x480
sys_futex+0xb4/0x140
sys_ioctl+0x99/0xa0
system_call_fastpath+0x16/0x1b
As it turns out, the call trace is messed up due to gcc's inlining, but
I isolated the problem anyway: kvm_write_guest_time() is being used in a
non-thread-safe manner on preemptable kernels.
Basically kvm_write_guest_time()'s body needs to be surrounded by
preempt_disable() and preempt_enable(), since the kernel won't let us
query any per-CPU data (indirectly using smp_processor_id()) without
preemption disabled. The attached patch fixes this issue by disabling
preemption inside kvm_write_guest_time().
[marcelo: surround only __get_cpu_var calls since the warning
is harmless]
Signed-off-by: Marcelo Tosatti <mtosatti@redhat.com>
Signed-off-by: Avi Kivity <avi@redhat.com>
---
arch/x86/kvm/x86.c | 2 ++
1 files changed, 2 insertions(+), 0 deletions(-)
diff --git a/arch/x86/kvm/x86.c b/arch/x86/kvm/x86.c
index 49079a4..cac6e63 100644
--- a/arch/x86/kvm/x86.c
+++ b/arch/x86/kvm/x86.c
@@ -630,10 +630,12 @@ static void kvm_write_guest_time(struct kvm_vcpu *v)
if ((!vcpu->time_page))
return;
+ preempt_disable();
if (unlikely(vcpu->hv_clock_tsc_khz != __get_cpu_var(cpu_tsc_khz))) {
kvm_set_time_scale(__get_cpu_var(cpu_tsc_khz), &vcpu->hv_clock);
vcpu->hv_clock_tsc_khz = __get_cpu_var(cpu_tsc_khz);
}
+ preempt_enable();
/* Keep irq disabled to prevent changes to the clock */
local_irq_save(flags);
--
1.6.0.6
^ permalink raw reply [flat|nested] 44+ messages in thread* [PATCH 12/43] KVM: x86: paravirt skip pit-through-ioapic boot check
2009-05-18 9:22 [PATCH 00/43] KVM updates for the 2.6.31 merge window (batch 1/4) Avi Kivity
` (10 preceding siblings ...)
2009-05-18 9:22 ` [PATCH 11/43] KVM: x86: silence preempt warning on kvm_write_guest_time Avi Kivity
@ 2009-05-18 9:22 ` Avi Kivity
2009-05-18 9:22 ` [PATCH 13/43] KVM: declare ioapic functions only on affected hardware Avi Kivity
` (30 subsequent siblings)
42 siblings, 0 replies; 44+ messages in thread
From: Avi Kivity @ 2009-05-18 9:22 UTC (permalink / raw)
To: linux-kernel; +Cc: kvm
From: Marcelo Tosatti <mtosatti@redhat.com>
Skip the test which checks if the PIT is properly routed when
using the IOAPIC, aimed at buggy hardware.
Signed-off-by: Marcelo Tosatti <mtosatti@redhat.com>
Signed-off-by: Avi Kivity <avi@redhat.com>
---
arch/x86/kernel/kvm.c | 4 ++++
1 files changed, 4 insertions(+), 0 deletions(-)
diff --git a/arch/x86/kernel/kvm.c b/arch/x86/kernel/kvm.c
index 33019dd..057173d 100644
--- a/arch/x86/kernel/kvm.c
+++ b/arch/x86/kernel/kvm.c
@@ -27,6 +27,7 @@
#include <linux/mm.h>
#include <linux/highmem.h>
#include <linux/hardirq.h>
+#include <asm/timer.h>
#define MMU_QUEUE_SIZE 1024
@@ -230,6 +231,9 @@ static void paravirt_ops_setup(void)
pv_mmu_ops.lazy_mode.enter = kvm_enter_lazy_mmu;
pv_mmu_ops.lazy_mode.leave = kvm_leave_lazy_mmu;
}
+#ifdef CONFIG_X86_IO_APIC
+ no_timer_check = 1;
+#endif
}
void __init kvm_guest_init(void)
--
1.6.0.6
^ permalink raw reply [flat|nested] 44+ messages in thread* [PATCH 13/43] KVM: declare ioapic functions only on affected hardware
2009-05-18 9:22 [PATCH 00/43] KVM updates for the 2.6.31 merge window (batch 1/4) Avi Kivity
` (11 preceding siblings ...)
2009-05-18 9:22 ` [PATCH 12/43] KVM: x86: paravirt skip pit-through-ioapic boot check Avi Kivity
@ 2009-05-18 9:22 ` Avi Kivity
2009-05-18 9:22 ` [PATCH 14/43] KVM: PIT: remove unused scheduled variable Avi Kivity
` (29 subsequent siblings)
42 siblings, 0 replies; 44+ messages in thread
From: Avi Kivity @ 2009-05-18 9:22 UTC (permalink / raw)
To: linux-kernel; +Cc: kvm
From: Christian Borntraeger <borntraeger@de.ibm.com>
Since "KVM: Unify the delivery of IOAPIC and MSI interrupts"
I get the following warnings:
CC [M] arch/s390/kvm/kvm-s390.o
In file included from arch/s390/kvm/kvm-s390.c:22:
include/linux/kvm_host.h:357: warning: 'struct kvm_ioapic' declared inside parameter list
include/linux/kvm_host.h:357: warning: its scope is only this definition or declaration, which is probably not what you want
This patch limits IOAPIC functions for architectures that have one.
Signed-off-by: Christian Borntraeger <borntraeger@de.ibm.com>
Signed-off-by: Avi Kivity <avi@redhat.com>
---
include/linux/kvm_host.h | 2 ++
1 files changed, 2 insertions(+), 0 deletions(-)
diff --git a/include/linux/kvm_host.h b/include/linux/kvm_host.h
index 3832243..3b91ec9 100644
--- a/include/linux/kvm_host.h
+++ b/include/linux/kvm_host.h
@@ -363,9 +363,11 @@ void kvm_unregister_irq_mask_notifier(struct kvm *kvm, int irq,
struct kvm_irq_mask_notifier *kimn);
void kvm_fire_mask_notifiers(struct kvm *kvm, int irq, bool mask);
+#ifdef __KVM_HAVE_IOAPIC
void kvm_get_intr_delivery_bitmask(struct kvm_ioapic *ioapic,
union kvm_ioapic_redirect_entry *entry,
unsigned long *deliver_bitmask);
+#endif
int kvm_set_irq(struct kvm *kvm, int irq_source_id, int irq, int level);
void kvm_notify_acked_irq(struct kvm *kvm, unsigned irqchip, unsigned pin);
void kvm_register_irq_ack_notifier(struct kvm *kvm,
--
1.6.0.6
^ permalink raw reply [flat|nested] 44+ messages in thread* [PATCH 14/43] KVM: PIT: remove unused scheduled variable
2009-05-18 9:22 [PATCH 00/43] KVM updates for the 2.6.31 merge window (batch 1/4) Avi Kivity
` (12 preceding siblings ...)
2009-05-18 9:22 ` [PATCH 13/43] KVM: declare ioapic functions only on affected hardware Avi Kivity
@ 2009-05-18 9:22 ` Avi Kivity
2009-05-18 9:22 ` [PATCH 15/43] KVM: PIT: remove usage of count_load_time for channel 0 Avi Kivity
` (28 subsequent siblings)
42 siblings, 0 replies; 44+ messages in thread
From: Avi Kivity @ 2009-05-18 9:22 UTC (permalink / raw)
To: linux-kernel; +Cc: kvm
From: Marcelo Tosatti <mtosatti@redhat.com>
Unused.
Signed-off-by: Marcelo Tosatti <mtosatti@redhat.com>
Signed-off-by: Avi Kivity <avi@redhat.com>
---
arch/x86/kvm/i8254.c | 1 -
arch/x86/kvm/i8254.h | 1 -
2 files changed, 0 insertions(+), 2 deletions(-)
diff --git a/arch/x86/kvm/i8254.c b/arch/x86/kvm/i8254.c
index c13bb92..3eddae6 100644
--- a/arch/x86/kvm/i8254.c
+++ b/arch/x86/kvm/i8254.c
@@ -208,7 +208,6 @@ static int __pit_timer_fn(struct kvm_kpit_state *ps)
wake_up_interruptible(&vcpu0->wq);
hrtimer_add_expires_ns(&pt->timer, pt->period);
- pt->scheduled = hrtimer_get_expires_ns(&pt->timer);
if (pt->period)
ps->channels[0].count_load_time = ktime_get();
diff --git a/arch/x86/kvm/i8254.h b/arch/x86/kvm/i8254.h
index 6acbe4b..521accf 100644
--- a/arch/x86/kvm/i8254.h
+++ b/arch/x86/kvm/i8254.h
@@ -7,7 +7,6 @@ struct kvm_kpit_timer {
struct hrtimer timer;
int irq;
s64 period; /* unit: ns */
- s64 scheduled;
atomic_t pending;
bool reinject;
};
--
1.6.0.6
^ permalink raw reply [flat|nested] 44+ messages in thread* [PATCH 15/43] KVM: PIT: remove usage of count_load_time for channel 0
2009-05-18 9:22 [PATCH 00/43] KVM updates for the 2.6.31 merge window (batch 1/4) Avi Kivity
` (13 preceding siblings ...)
2009-05-18 9:22 ` [PATCH 14/43] KVM: PIT: remove unused scheduled variable Avi Kivity
@ 2009-05-18 9:22 ` Avi Kivity
2009-05-18 9:22 ` [PATCH 16/43] KVM: unify part of generic timer handling Avi Kivity
` (27 subsequent siblings)
42 siblings, 0 replies; 44+ messages in thread
From: Avi Kivity @ 2009-05-18 9:22 UTC (permalink / raw)
To: linux-kernel; +Cc: kvm
From: Marcelo Tosatti <mtosatti@redhat.com>
We can infer elapsed time from hrtimer_expires_remaining.
Signed-off-by: Marcelo Tosatti <mtosatti@redhat.com>
Signed-off-by: Avi Kivity <avi@redhat.com>
---
arch/x86/kvm/i8254.c | 37 +++++++++++++++++++++++++++++++------
1 files changed, 31 insertions(+), 6 deletions(-)
diff --git a/arch/x86/kvm/i8254.c b/arch/x86/kvm/i8254.c
index 3eddae6..09ae841 100644
--- a/arch/x86/kvm/i8254.c
+++ b/arch/x86/kvm/i8254.c
@@ -98,6 +98,32 @@ static int pit_get_gate(struct kvm *kvm, int channel)
return kvm->arch.vpit->pit_state.channels[channel].gate;
}
+static s64 __kpit_elapsed(struct kvm *kvm)
+{
+ s64 elapsed;
+ ktime_t remaining;
+ struct kvm_kpit_state *ps = &kvm->arch.vpit->pit_state;
+
+ remaining = hrtimer_expires_remaining(&ps->pit_timer.timer);
+ if (ktime_to_ns(remaining) < 0)
+ remaining = ktime_set(0, 0);
+
+ elapsed = ps->pit_timer.period;
+ if (ktime_to_ns(remaining) <= ps->pit_timer.period)
+ elapsed = ps->pit_timer.period - ktime_to_ns(remaining);
+
+ return elapsed;
+}
+
+static s64 kpit_elapsed(struct kvm *kvm, struct kvm_kpit_channel_state *c,
+ int channel)
+{
+ if (channel == 0)
+ return __kpit_elapsed(kvm);
+
+ return ktime_to_ns(ktime_sub(ktime_get(), c->count_load_time));
+}
+
static int pit_get_count(struct kvm *kvm, int channel)
{
struct kvm_kpit_channel_state *c =
@@ -107,7 +133,7 @@ static int pit_get_count(struct kvm *kvm, int channel)
WARN_ON(!mutex_is_locked(&kvm->arch.vpit->pit_state.lock));
- t = ktime_to_ns(ktime_sub(ktime_get(), c->count_load_time));
+ t = kpit_elapsed(kvm, c, channel);
d = muldiv64(t, KVM_PIT_FREQ, NSEC_PER_SEC);
switch (c->mode) {
@@ -137,7 +163,7 @@ static int pit_get_out(struct kvm *kvm, int channel)
WARN_ON(!mutex_is_locked(&kvm->arch.vpit->pit_state.lock));
- t = ktime_to_ns(ktime_sub(ktime_get(), c->count_load_time));
+ t = kpit_elapsed(kvm, c, channel);
d = muldiv64(t, KVM_PIT_FREQ, NSEC_PER_SEC);
switch (c->mode) {
@@ -208,8 +234,6 @@ static int __pit_timer_fn(struct kvm_kpit_state *ps)
wake_up_interruptible(&vcpu0->wq);
hrtimer_add_expires_ns(&pt->timer, pt->period);
- if (pt->period)
- ps->channels[0].count_load_time = ktime_get();
return (pt->period == 0 ? 0 : 1);
}
@@ -305,11 +329,12 @@ static void pit_load_count(struct kvm *kvm, int channel, u32 val)
if (val == 0)
val = 0x10000;
- ps->channels[channel].count_load_time = ktime_get();
ps->channels[channel].count = val;
- if (channel != 0)
+ if (channel != 0) {
+ ps->channels[channel].count_load_time = ktime_get();
return;
+ }
/* Two types of timer
* mode 1 is one shot, mode 2 is period, otherwise del timer */
--
1.6.0.6
^ permalink raw reply [flat|nested] 44+ messages in thread* [PATCH 16/43] KVM: unify part of generic timer handling
2009-05-18 9:22 [PATCH 00/43] KVM updates for the 2.6.31 merge window (batch 1/4) Avi Kivity
` (14 preceding siblings ...)
2009-05-18 9:22 ` [PATCH 15/43] KVM: PIT: remove usage of count_load_time for channel 0 Avi Kivity
@ 2009-05-18 9:22 ` Avi Kivity
2009-05-18 9:22 ` [PATCH 17/43] KVM: ia64: fix compilation error in kvm_get_lowest_prio_vcpu Avi Kivity
` (26 subsequent siblings)
42 siblings, 0 replies; 44+ messages in thread
From: Avi Kivity @ 2009-05-18 9:22 UTC (permalink / raw)
To: linux-kernel; +Cc: kvm
From: Marcelo Tosatti <mtosatti@redhat.com>
Hide the internals of vcpu awakening / injection from the in-kernel
emulated timers. This makes future changes in this logic easier and
decreases the distance to more generic timer handling.
Signed-off-by: Marcelo Tosatti <mtosatti@redhat.com>
Signed-off-by: Avi Kivity <avi@redhat.com>
---
arch/x86/kvm/Makefile | 2 +-
arch/x86/kvm/i8254.c | 57 ++++++++++------------------
arch/x86/kvm/i8254.h | 11 +----
arch/x86/kvm/kvm_timer.h | 18 +++++++++
arch/x86/kvm/lapic.c | 94 +++++++++++++++++++---------------------------
arch/x86/kvm/lapic.h | 9 +---
arch/x86/kvm/timer.c | 46 ++++++++++++++++++++++
7 files changed, 129 insertions(+), 108 deletions(-)
create mode 100644 arch/x86/kvm/kvm_timer.h
create mode 100644 arch/x86/kvm/timer.c
diff --git a/arch/x86/kvm/Makefile b/arch/x86/kvm/Makefile
index d3ec292..b43c4ef 100644
--- a/arch/x86/kvm/Makefile
+++ b/arch/x86/kvm/Makefile
@@ -14,7 +14,7 @@ endif
EXTRA_CFLAGS += -Ivirt/kvm -Iarch/x86/kvm
kvm-objs := $(common-objs) x86.o mmu.o x86_emulate.o i8259.o irq.o lapic.o \
- i8254.o
+ i8254.o timer.o
obj-$(CONFIG_KVM) += kvm.o
kvm-intel-objs = vmx.o
obj-$(CONFIG_KVM_INTEL) += kvm-intel.o
diff --git a/arch/x86/kvm/i8254.c b/arch/x86/kvm/i8254.c
index 09ae841..4e2e3f2 100644
--- a/arch/x86/kvm/i8254.c
+++ b/arch/x86/kvm/i8254.c
@@ -219,25 +219,6 @@ static void pit_latch_status(struct kvm *kvm, int channel)
}
}
-static int __pit_timer_fn(struct kvm_kpit_state *ps)
-{
- struct kvm_vcpu *vcpu0 = ps->pit->kvm->vcpus[0];
- struct kvm_kpit_timer *pt = &ps->pit_timer;
-
- if (!atomic_inc_and_test(&pt->pending))
- set_bit(KVM_REQ_PENDING_TIMER, &vcpu0->requests);
-
- if (!pt->reinject)
- atomic_set(&pt->pending, 1);
-
- if (vcpu0 && waitqueue_active(&vcpu0->wq))
- wake_up_interruptible(&vcpu0->wq);
-
- hrtimer_add_expires_ns(&pt->timer, pt->period);
-
- return (pt->period == 0 ? 0 : 1);
-}
-
int pit_has_pending_timer(struct kvm_vcpu *vcpu)
{
struct kvm_pit *pit = vcpu->kvm->arch.vpit;
@@ -258,21 +239,6 @@ static void kvm_pit_ack_irq(struct kvm_irq_ack_notifier *kian)
spin_unlock(&ps->inject_lock);
}
-static enum hrtimer_restart pit_timer_fn(struct hrtimer *data)
-{
- struct kvm_kpit_state *ps;
- int restart_timer = 0;
-
- ps = container_of(data, struct kvm_kpit_state, pit_timer.timer);
-
- restart_timer = __pit_timer_fn(ps);
-
- if (restart_timer)
- return HRTIMER_RESTART;
- else
- return HRTIMER_NORESTART;
-}
-
void __kvm_migrate_pit_timer(struct kvm_vcpu *vcpu)
{
struct kvm_pit *pit = vcpu->kvm->arch.vpit;
@@ -286,15 +252,26 @@ void __kvm_migrate_pit_timer(struct kvm_vcpu *vcpu)
hrtimer_start_expires(timer, HRTIMER_MODE_ABS);
}
-static void destroy_pit_timer(struct kvm_kpit_timer *pt)
+static void destroy_pit_timer(struct kvm_timer *pt)
{
pr_debug("pit: execute del timer!\n");
hrtimer_cancel(&pt->timer);
}
+static bool kpit_is_periodic(struct kvm_timer *ktimer)
+{
+ struct kvm_kpit_state *ps = container_of(ktimer, struct kvm_kpit_state,
+ pit_timer);
+ return ps->is_periodic;
+}
+
+struct kvm_timer_ops kpit_ops = {
+ .is_periodic = kpit_is_periodic,
+};
+
static void create_pit_timer(struct kvm_kpit_state *ps, u32 val, int is_period)
{
- struct kvm_kpit_timer *pt = &ps->pit_timer;
+ struct kvm_timer *pt = &ps->pit_timer;
s64 interval;
interval = muldiv64(val, NSEC_PER_SEC, KVM_PIT_FREQ);
@@ -304,7 +281,13 @@ static void create_pit_timer(struct kvm_kpit_state *ps, u32 val, int is_period)
/* TODO The new value only affected after the retriggered */
hrtimer_cancel(&pt->timer);
pt->period = (is_period == 0) ? 0 : interval;
- pt->timer.function = pit_timer_fn;
+ ps->is_periodic = is_period;
+
+ pt->timer.function = kvm_timer_fn;
+ pt->t_ops = &kpit_ops;
+ pt->kvm = ps->pit->kvm;
+ pt->vcpu_id = 0;
+
atomic_set(&pt->pending, 0);
ps->irq_ack = 1;
diff --git a/arch/x86/kvm/i8254.h b/arch/x86/kvm/i8254.h
index 521accf..bbd863f 100644
--- a/arch/x86/kvm/i8254.h
+++ b/arch/x86/kvm/i8254.h
@@ -3,14 +3,6 @@
#include "iodev.h"
-struct kvm_kpit_timer {
- struct hrtimer timer;
- int irq;
- s64 period; /* unit: ns */
- atomic_t pending;
- bool reinject;
-};
-
struct kvm_kpit_channel_state {
u32 count; /* can be 65536 */
u16 latched_count;
@@ -29,7 +21,8 @@ struct kvm_kpit_channel_state {
struct kvm_kpit_state {
struct kvm_kpit_channel_state channels[3];
- struct kvm_kpit_timer pit_timer;
+ struct kvm_timer pit_timer;
+ bool is_periodic;
u32 speaker_data_on;
struct mutex lock;
struct kvm_pit *pit;
diff --git a/arch/x86/kvm/kvm_timer.h b/arch/x86/kvm/kvm_timer.h
new file mode 100644
index 0000000..26bd6ba
--- /dev/null
+++ b/arch/x86/kvm/kvm_timer.h
@@ -0,0 +1,18 @@
+
+struct kvm_timer {
+ struct hrtimer timer;
+ s64 period; /* unit: ns */
+ atomic_t pending; /* accumulated triggered timers */
+ bool reinject;
+ struct kvm_timer_ops *t_ops;
+ struct kvm *kvm;
+ int vcpu_id;
+};
+
+struct kvm_timer_ops {
+ bool (*is_periodic)(struct kvm_timer *);
+};
+
+
+enum hrtimer_restart kvm_timer_fn(struct hrtimer *data);
+
diff --git a/arch/x86/kvm/lapic.c b/arch/x86/kvm/lapic.c
index afc59b2..27ca43e 100644
--- a/arch/x86/kvm/lapic.c
+++ b/arch/x86/kvm/lapic.c
@@ -528,12 +528,13 @@ static u32 apic_get_tmcct(struct kvm_lapic *apic)
if (apic_get_reg(apic, APIC_TMICT) == 0)
return 0;
- remaining = hrtimer_expires_remaining(&apic->timer.dev);
+ remaining = hrtimer_expires_remaining(&apic->lapic_timer.timer);
if (ktime_to_ns(remaining) < 0)
remaining = ktime_set(0, 0);
- ns = mod_64(ktime_to_ns(remaining), apic->timer.period);
- tmcct = div64_u64(ns, (APIC_BUS_CYCLE_NS * apic->timer.divide_count));
+ ns = mod_64(ktime_to_ns(remaining), apic->lapic_timer.period);
+ tmcct = div64_u64(ns,
+ (APIC_BUS_CYCLE_NS * apic->divide_count));
return tmcct;
}
@@ -620,25 +621,25 @@ static void update_divide_count(struct kvm_lapic *apic)
tdcr = apic_get_reg(apic, APIC_TDCR);
tmp1 = tdcr & 0xf;
tmp2 = ((tmp1 & 0x3) | ((tmp1 & 0x8) >> 1)) + 1;
- apic->timer.divide_count = 0x1 << (tmp2 & 0x7);
+ apic->divide_count = 0x1 << (tmp2 & 0x7);
apic_debug("timer divide count is 0x%x\n",
- apic->timer.divide_count);
+ apic->lapic_timer.divide_count);
}
static void start_apic_timer(struct kvm_lapic *apic)
{
- ktime_t now = apic->timer.dev.base->get_time();
+ ktime_t now = apic->lapic_timer.timer.base->get_time();
- apic->timer.period = apic_get_reg(apic, APIC_TMICT) *
- APIC_BUS_CYCLE_NS * apic->timer.divide_count;
- atomic_set(&apic->timer.pending, 0);
+ apic->lapic_timer.period = apic_get_reg(apic, APIC_TMICT) *
+ APIC_BUS_CYCLE_NS * apic->divide_count;
+ atomic_set(&apic->lapic_timer.pending, 0);
- if (!apic->timer.period)
+ if (!apic->lapic_timer.period)
return;
- hrtimer_start(&apic->timer.dev,
- ktime_add_ns(now, apic->timer.period),
+ hrtimer_start(&apic->lapic_timer.timer,
+ ktime_add_ns(now, apic->lapic_timer.period),
HRTIMER_MODE_ABS);
apic_debug("%s: bus cycle is %" PRId64 "ns, now 0x%016"
@@ -647,9 +648,9 @@ static void start_apic_timer(struct kvm_lapic *apic)
"expire @ 0x%016" PRIx64 ".\n", __func__,
APIC_BUS_CYCLE_NS, ktime_to_ns(now),
apic_get_reg(apic, APIC_TMICT),
- apic->timer.period,
+ apic->lapic_timer.period,
ktime_to_ns(ktime_add_ns(now,
- apic->timer.period)));
+ apic->lapic_timer.period)));
}
static void apic_manage_nmi_watchdog(struct kvm_lapic *apic, u32 lvt0_val)
@@ -731,7 +732,7 @@ static void apic_mmio_write(struct kvm_io_device *this,
apic_set_reg(apic, APIC_LVTT + 0x10 * i,
lvt_val | APIC_LVT_MASKED);
}
- atomic_set(&apic->timer.pending, 0);
+ atomic_set(&apic->lapic_timer.pending, 0);
}
break;
@@ -763,7 +764,7 @@ static void apic_mmio_write(struct kvm_io_device *this,
break;
case APIC_TMICT:
- hrtimer_cancel(&apic->timer.dev);
+ hrtimer_cancel(&apic->lapic_timer.timer);
apic_set_reg(apic, APIC_TMICT, val);
start_apic_timer(apic);
return;
@@ -803,7 +804,7 @@ void kvm_free_lapic(struct kvm_vcpu *vcpu)
if (!vcpu->arch.apic)
return;
- hrtimer_cancel(&vcpu->arch.apic->timer.dev);
+ hrtimer_cancel(&vcpu->arch.apic->lapic_timer.timer);
if (vcpu->arch.apic->regs_page)
__free_page(vcpu->arch.apic->regs_page);
@@ -881,7 +882,7 @@ void kvm_lapic_reset(struct kvm_vcpu *vcpu)
ASSERT(apic != NULL);
/* Stop the timer in case it's a reset to an active apic */
- hrtimer_cancel(&apic->timer.dev);
+ hrtimer_cancel(&apic->lapic_timer.timer);
apic_set_reg(apic, APIC_ID, vcpu->vcpu_id << 24);
apic_set_reg(apic, APIC_LVR, APIC_VERSION);
@@ -906,7 +907,7 @@ void kvm_lapic_reset(struct kvm_vcpu *vcpu)
apic_set_reg(apic, APIC_TMR + 0x10 * i, 0);
}
update_divide_count(apic);
- atomic_set(&apic->timer.pending, 0);
+ atomic_set(&apic->lapic_timer.pending, 0);
if (vcpu->vcpu_id == 0)
vcpu->arch.apic_base |= MSR_IA32_APICBASE_BSP;
apic_update_ppr(apic);
@@ -937,22 +938,11 @@ EXPORT_SYMBOL_GPL(kvm_lapic_enabled);
*----------------------------------------------------------------------
*/
-/* TODO: make sure __apic_timer_fn runs in current pCPU */
-static int __apic_timer_fn(struct kvm_lapic *apic)
+static bool lapic_is_periodic(struct kvm_timer *ktimer)
{
- int result = 0;
- wait_queue_head_t *q = &apic->vcpu->wq;
-
- if(!atomic_inc_and_test(&apic->timer.pending))
- set_bit(KVM_REQ_PENDING_TIMER, &apic->vcpu->requests);
- if (waitqueue_active(q))
- wake_up_interruptible(q);
-
- if (apic_lvtt_period(apic)) {
- result = 1;
- hrtimer_add_expires_ns(&apic->timer.dev, apic->timer.period);
- }
- return result;
+ struct kvm_lapic *apic = container_of(ktimer, struct kvm_lapic,
+ lapic_timer);
+ return apic_lvtt_period(apic);
}
int apic_has_pending_timer(struct kvm_vcpu *vcpu)
@@ -960,7 +950,7 @@ int apic_has_pending_timer(struct kvm_vcpu *vcpu)
struct kvm_lapic *lapic = vcpu->arch.apic;
if (lapic && apic_enabled(lapic) && apic_lvt_enabled(lapic, APIC_LVTT))
- return atomic_read(&lapic->timer.pending);
+ return atomic_read(&lapic->lapic_timer.pending);
return 0;
}
@@ -987,20 +977,9 @@ void kvm_apic_nmi_wd_deliver(struct kvm_vcpu *vcpu)
kvm_apic_local_deliver(apic, APIC_LVT0);
}
-static enum hrtimer_restart apic_timer_fn(struct hrtimer *data)
-{
- struct kvm_lapic *apic;
- int restart_timer = 0;
-
- apic = container_of(data, struct kvm_lapic, timer.dev);
-
- restart_timer = __apic_timer_fn(apic);
-
- if (restart_timer)
- return HRTIMER_RESTART;
- else
- return HRTIMER_NORESTART;
-}
+struct kvm_timer_ops lapic_timer_ops = {
+ .is_periodic = lapic_is_periodic,
+};
int kvm_create_lapic(struct kvm_vcpu *vcpu)
{
@@ -1025,8 +1004,13 @@ int kvm_create_lapic(struct kvm_vcpu *vcpu)
memset(apic->regs, 0, PAGE_SIZE);
apic->vcpu = vcpu;
- hrtimer_init(&apic->timer.dev, CLOCK_MONOTONIC, HRTIMER_MODE_ABS);
- apic->timer.dev.function = apic_timer_fn;
+ hrtimer_init(&apic->lapic_timer.timer, CLOCK_MONOTONIC,
+ HRTIMER_MODE_ABS);
+ apic->lapic_timer.timer.function = kvm_timer_fn;
+ apic->lapic_timer.t_ops = &lapic_timer_ops;
+ apic->lapic_timer.kvm = vcpu->kvm;
+ apic->lapic_timer.vcpu_id = vcpu->vcpu_id;
+
apic->base_address = APIC_DEFAULT_PHYS_BASE;
vcpu->arch.apic_base = APIC_DEFAULT_PHYS_BASE;
@@ -1079,9 +1063,9 @@ void kvm_inject_apic_timer_irqs(struct kvm_vcpu *vcpu)
{
struct kvm_lapic *apic = vcpu->arch.apic;
- if (apic && atomic_read(&apic->timer.pending) > 0) {
+ if (apic && atomic_read(&apic->lapic_timer.pending) > 0) {
if (kvm_apic_local_deliver(apic, APIC_LVTT))
- atomic_dec(&apic->timer.pending);
+ atomic_dec(&apic->lapic_timer.pending);
}
}
@@ -1107,7 +1091,7 @@ void kvm_apic_post_state_restore(struct kvm_vcpu *vcpu)
MSR_IA32_APICBASE_BASE;
apic_set_reg(apic, APIC_LVR, APIC_VERSION);
apic_update_ppr(apic);
- hrtimer_cancel(&apic->timer.dev);
+ hrtimer_cancel(&apic->lapic_timer.timer);
update_divide_count(apic);
start_apic_timer(apic);
}
@@ -1120,7 +1104,7 @@ void __kvm_migrate_apic_timer(struct kvm_vcpu *vcpu)
if (!apic)
return;
- timer = &apic->timer.dev;
+ timer = &apic->lapic_timer.timer;
if (hrtimer_cancel(timer))
hrtimer_start_expires(timer, HRTIMER_MODE_ABS);
}
diff --git a/arch/x86/kvm/lapic.h b/arch/x86/kvm/lapic.h
index 45ab6ee..2fc0d3c 100644
--- a/arch/x86/kvm/lapic.h
+++ b/arch/x86/kvm/lapic.h
@@ -2,18 +2,15 @@
#define __KVM_X86_LAPIC_H
#include "iodev.h"
+#include "kvm_timer.h"
#include <linux/kvm_host.h>
struct kvm_lapic {
unsigned long base_address;
struct kvm_io_device dev;
- struct {
- atomic_t pending;
- s64 period; /* unit: ns */
- u32 divide_count;
- struct hrtimer dev;
- } timer;
+ struct kvm_timer lapic_timer;
+ u32 divide_count;
struct kvm_vcpu *vcpu;
struct page *regs_page;
void *regs;
diff --git a/arch/x86/kvm/timer.c b/arch/x86/kvm/timer.c
new file mode 100644
index 0000000..86dbac0
--- /dev/null
+++ b/arch/x86/kvm/timer.c
@@ -0,0 +1,46 @@
+#include <linux/kvm_host.h>
+#include <linux/kvm.h>
+#include <linux/hrtimer.h>
+#include <asm/atomic.h>
+#include "kvm_timer.h"
+
+static int __kvm_timer_fn(struct kvm_vcpu *vcpu, struct kvm_timer *ktimer)
+{
+ int restart_timer = 0;
+ wait_queue_head_t *q = &vcpu->wq;
+
+ /* FIXME: this code should not know anything about vcpus */
+ if (!atomic_inc_and_test(&ktimer->pending))
+ set_bit(KVM_REQ_PENDING_TIMER, &vcpu->requests);
+
+ if (!ktimer->reinject)
+ atomic_set(&ktimer->pending, 1);
+
+ if (waitqueue_active(q))
+ wake_up_interruptible(q);
+
+ if (ktimer->t_ops->is_periodic(ktimer)) {
+ hrtimer_add_expires_ns(&ktimer->timer, ktimer->period);
+ restart_timer = 1;
+ }
+
+ return restart_timer;
+}
+
+enum hrtimer_restart kvm_timer_fn(struct hrtimer *data)
+{
+ int restart_timer;
+ struct kvm_vcpu *vcpu;
+ struct kvm_timer *ktimer = container_of(data, struct kvm_timer, timer);
+
+ vcpu = ktimer->kvm->vcpus[ktimer->vcpu_id];
+ if (!vcpu)
+ return HRTIMER_NORESTART;
+
+ restart_timer = __kvm_timer_fn(vcpu, ktimer);
+ if (restart_timer)
+ return HRTIMER_RESTART;
+ else
+ return HRTIMER_NORESTART;
+}
+
--
1.6.0.6
^ permalink raw reply [flat|nested] 44+ messages in thread* [PATCH 17/43] KVM: ia64: fix compilation error in kvm_get_lowest_prio_vcpu
2009-05-18 9:22 [PATCH 00/43] KVM updates for the 2.6.31 merge window (batch 1/4) Avi Kivity
` (15 preceding siblings ...)
2009-05-18 9:22 ` [PATCH 16/43] KVM: unify part of generic timer handling Avi Kivity
@ 2009-05-18 9:22 ` Avi Kivity
2009-05-18 9:22 ` [PATCH 18/43] KVM: Merge kvm_ioapic_get_delivery_bitmask into kvm_get_intr_delivery_bitmask Avi Kivity
` (25 subsequent siblings)
42 siblings, 0 replies; 44+ messages in thread
From: Avi Kivity @ 2009-05-18 9:22 UTC (permalink / raw)
To: linux-kernel; +Cc: kvm
From: Yang Zhang <yang.zhang@intel.com>
Modify the arg of kvm_get_lowest_prio_vcpu().
Make it consistent with its declaration.
Signed-off-by: Yang Zhang <yang.zhang@intel.com>
Signed-off-by: Marcelo Tosatti <mtosatti@redhat.com>
---
arch/ia64/kvm/kvm-ia64.c | 2 +-
1 files changed, 1 insertions(+), 1 deletions(-)
diff --git a/arch/ia64/kvm/kvm-ia64.c b/arch/ia64/kvm/kvm-ia64.c
index d20a5db..774f0d7 100644
--- a/arch/ia64/kvm/kvm-ia64.c
+++ b/arch/ia64/kvm/kvm-ia64.c
@@ -1837,7 +1837,7 @@ int kvm_apic_match_logical_addr(struct kvm_lapic *apic, u8 mda)
}
struct kvm_vcpu *kvm_get_lowest_prio_vcpu(struct kvm *kvm, u8 vector,
- unsigned long bitmap)
+ unsigned long *bitmap)
{
struct kvm_vcpu *lvcpu = kvm->vcpus[0];
int i;
--
1.6.0.6
^ permalink raw reply [flat|nested] 44+ messages in thread* [PATCH 18/43] KVM: Merge kvm_ioapic_get_delivery_bitmask into kvm_get_intr_delivery_bitmask
2009-05-18 9:22 [PATCH 00/43] KVM updates for the 2.6.31 merge window (batch 1/4) Avi Kivity
` (16 preceding siblings ...)
2009-05-18 9:22 ` [PATCH 17/43] KVM: ia64: fix compilation error in kvm_get_lowest_prio_vcpu Avi Kivity
@ 2009-05-18 9:22 ` Avi Kivity
2009-05-18 9:22 ` [PATCH 19/43] KVM: MMU: remove call to kvm_mmu_pte_write from walk_addr Avi Kivity
` (24 subsequent siblings)
42 siblings, 0 replies; 44+ messages in thread
From: Avi Kivity @ 2009-05-18 9:22 UTC (permalink / raw)
To: linux-kernel; +Cc: kvm
From: Sheng Yang <sheng@linux.intel.com>
Gleb fixed bitmap ops usage in kvm_ioapic_get_delivery_bitmask.
Sheng merged two functions, as well as fixed several issues in
kvm_get_intr_delivery_bitmask
1. deliver_bitmask is a bitmap rather than a unsigned long intereger.
2. Lowest priority target bitmap wrong calculated by mistake.
3. Prevent potential NULL reference.
4. Declaration in include/kvm_host.h caused powerpc compilation warning.
5. Add warning for guest broadcast interrupt with lowest priority delivery mode.
6. Removed duplicate bitmap clean up in caller of kvm_get_intr_delivery_bitmask.
Signed-off-by: Gleb Natapov <gleb@redhat.com>
Signed-off-by: Sheng Yang <sheng@linux.intel.com>
Signed-off-by: Marcelo Tosatti <mtosatti@redhat.com>
---
virt/kvm/ioapic.c | 46 +++-------------------------------------------
virt/kvm/ioapic.h | 5 +++--
virt/kvm/irq_comm.c | 49 +++++++++++++++++++++++++++++++++++++++++++------
3 files changed, 49 insertions(+), 51 deletions(-)
diff --git a/virt/kvm/ioapic.c b/virt/kvm/ioapic.c
index 7c2cb2b..ea268a8 100644
--- a/virt/kvm/ioapic.c
+++ b/virt/kvm/ioapic.c
@@ -161,45 +161,6 @@ static void ioapic_inj_nmi(struct kvm_vcpu *vcpu)
kvm_vcpu_kick(vcpu);
}
-void kvm_ioapic_get_delivery_bitmask(struct kvm_ioapic *ioapic, u8 dest,
- u8 dest_mode, unsigned long *mask)
-{
- int i;
- struct kvm *kvm = ioapic->kvm;
- struct kvm_vcpu *vcpu;
-
- ioapic_debug("dest %d dest_mode %d\n", dest, dest_mode);
-
- *mask = 0;
- if (dest_mode == 0) { /* Physical mode. */
- if (dest == 0xFF) { /* Broadcast. */
- for (i = 0; i < KVM_MAX_VCPUS; ++i)
- if (kvm->vcpus[i] && kvm->vcpus[i]->arch.apic)
- *mask |= 1 << i;
- return;
- }
- for (i = 0; i < KVM_MAX_VCPUS; ++i) {
- vcpu = kvm->vcpus[i];
- if (!vcpu)
- continue;
- if (kvm_apic_match_physical_addr(vcpu->arch.apic, dest)) {
- if (vcpu->arch.apic)
- *mask = 1 << i;
- break;
- }
- }
- } else if (dest != 0) /* Logical mode, MDA non-zero. */
- for (i = 0; i < KVM_MAX_VCPUS; ++i) {
- vcpu = kvm->vcpus[i];
- if (!vcpu)
- continue;
- if (vcpu->arch.apic &&
- kvm_apic_match_logical_addr(vcpu->arch.apic, dest))
- *mask |= 1 << vcpu->vcpu_id;
- }
- ioapic_debug("mask %x\n", *mask);
-}
-
static int ioapic_deliver(struct kvm_ioapic *ioapic, int irq)
{
union kvm_ioapic_redirect_entry entry = ioapic->redirtbl[irq];
@@ -213,13 +174,12 @@ static int ioapic_deliver(struct kvm_ioapic *ioapic, int irq)
entry.fields.delivery_mode, entry.fields.vector,
entry.fields.trig_mode);
- bitmap_zero(deliver_bitmask, KVM_MAX_VCPUS);
-
/* Always delivery PIT interrupt to vcpu 0 */
#ifdef CONFIG_X86
- if (irq == 0)
+ if (irq == 0) {
+ bitmap_zero(deliver_bitmask, KVM_MAX_VCPUS);
__set_bit(0, deliver_bitmask);
- else
+ } else
#endif
kvm_get_intr_delivery_bitmask(ioapic, &entry, deliver_bitmask);
diff --git a/virt/kvm/ioapic.h b/virt/kvm/ioapic.h
index 7275f87..c8032ab 100644
--- a/virt/kvm/ioapic.h
+++ b/virt/kvm/ioapic.h
@@ -70,7 +70,8 @@ void kvm_ioapic_update_eoi(struct kvm *kvm, int vector, int trigger_mode);
int kvm_ioapic_init(struct kvm *kvm);
int kvm_ioapic_set_irq(struct kvm_ioapic *ioapic, int irq, int level);
void kvm_ioapic_reset(struct kvm_ioapic *ioapic);
-void kvm_ioapic_get_delivery_bitmask(struct kvm_ioapic *ioapic, u8 dest,
- u8 dest_mode, unsigned long *mask);
+void kvm_get_intr_delivery_bitmask(struct kvm_ioapic *ioapic,
+ union kvm_ioapic_redirect_entry *entry,
+ unsigned long *deliver_bitmask);
#endif
diff --git a/virt/kvm/irq_comm.c b/virt/kvm/irq_comm.c
index d165e05..1c6ff6d 100644
--- a/virt/kvm/irq_comm.c
+++ b/virt/kvm/irq_comm.c
@@ -47,15 +47,54 @@ void kvm_get_intr_delivery_bitmask(struct kvm_ioapic *ioapic,
union kvm_ioapic_redirect_entry *entry,
unsigned long *deliver_bitmask)
{
+ int i;
+ struct kvm *kvm = ioapic->kvm;
struct kvm_vcpu *vcpu;
- kvm_ioapic_get_delivery_bitmask(ioapic, entry->fields.dest_id,
- entry->fields.dest_mode,
- deliver_bitmask);
+ bitmap_zero(deliver_bitmask, KVM_MAX_VCPUS);
+
+ if (entry->fields.dest_mode == 0) { /* Physical mode. */
+ if (entry->fields.dest_id == 0xFF) { /* Broadcast. */
+ for (i = 0; i < KVM_MAX_VCPUS; ++i)
+ if (kvm->vcpus[i] && kvm->vcpus[i]->arch.apic)
+ __set_bit(i, deliver_bitmask);
+ /* Lowest priority shouldn't combine with broadcast */
+ if (entry->fields.delivery_mode ==
+ IOAPIC_LOWEST_PRIORITY && printk_ratelimit())
+ printk(KERN_INFO "kvm: apic: phys broadcast "
+ "and lowest prio\n");
+ return;
+ }
+ for (i = 0; i < KVM_MAX_VCPUS; ++i) {
+ vcpu = kvm->vcpus[i];
+ if (!vcpu)
+ continue;
+ if (kvm_apic_match_physical_addr(vcpu->arch.apic,
+ entry->fields.dest_id)) {
+ if (vcpu->arch.apic)
+ __set_bit(i, deliver_bitmask);
+ break;
+ }
+ }
+ } else if (entry->fields.dest_id != 0) /* Logical mode, MDA non-zero. */
+ for (i = 0; i < KVM_MAX_VCPUS; ++i) {
+ vcpu = kvm->vcpus[i];
+ if (!vcpu)
+ continue;
+ if (vcpu->arch.apic &&
+ kvm_apic_match_logical_addr(vcpu->arch.apic,
+ entry->fields.dest_id))
+ __set_bit(i, deliver_bitmask);
+ }
+
switch (entry->fields.delivery_mode) {
case IOAPIC_LOWEST_PRIORITY:
+ /* Select one in deliver_bitmask */
vcpu = kvm_get_lowest_prio_vcpu(ioapic->kvm,
entry->fields.vector, deliver_bitmask);
+ bitmap_zero(deliver_bitmask, KVM_MAX_VCPUS);
+ if (!vcpu)
+ return;
__set_bit(vcpu->vcpu_id, deliver_bitmask);
break;
case IOAPIC_FIXED:
@@ -65,7 +104,7 @@ void kvm_get_intr_delivery_bitmask(struct kvm_ioapic *ioapic,
if (printk_ratelimit())
printk(KERN_INFO "kvm: unsupported delivery mode %d\n",
entry->fields.delivery_mode);
- *deliver_bitmask = 0;
+ bitmap_zero(deliver_bitmask, KVM_MAX_VCPUS);
}
}
@@ -80,8 +119,6 @@ static int kvm_set_msi(struct kvm_kernel_irq_routing_entry *e,
BUG_ON(!ioapic);
- bitmap_zero(deliver_bitmask, KVM_MAX_VCPUS);
-
entry.bits = 0;
entry.fields.dest_id = (e->msi.address_lo &
MSI_ADDR_DEST_ID_MASK) >> MSI_ADDR_DEST_ID_SHIFT;
--
1.6.0.6
^ permalink raw reply [flat|nested] 44+ messages in thread* [PATCH 19/43] KVM: MMU: remove call to kvm_mmu_pte_write from walk_addr
2009-05-18 9:22 [PATCH 00/43] KVM updates for the 2.6.31 merge window (batch 1/4) Avi Kivity
` (17 preceding siblings ...)
2009-05-18 9:22 ` [PATCH 18/43] KVM: Merge kvm_ioapic_get_delivery_bitmask into kvm_get_intr_delivery_bitmask Avi Kivity
@ 2009-05-18 9:22 ` Avi Kivity
2009-05-18 9:22 ` [PATCH 20/43] KVM: APIC: kvm_apic_set_irq deliver all kinds of interrupts Avi Kivity
` (23 subsequent siblings)
42 siblings, 0 replies; 44+ messages in thread
From: Avi Kivity @ 2009-05-18 9:22 UTC (permalink / raw)
To: linux-kernel; +Cc: kvm
From: Joerg Roedel <joerg.roedel@amd.com>
There is no reason to update the shadow pte here because the guest pte
is only changed to dirty state.
Signed-off-by: Joerg Roedel <joerg.roedel@amd.com>
Signed-off-by: Marcelo Tosatti <mtosatti@redhat.com>
---
arch/x86/kvm/paging_tmpl.h | 1 -
1 files changed, 0 insertions(+), 1 deletions(-)
diff --git a/arch/x86/kvm/paging_tmpl.h b/arch/x86/kvm/paging_tmpl.h
index 6bd7020..855eb71 100644
--- a/arch/x86/kvm/paging_tmpl.h
+++ b/arch/x86/kvm/paging_tmpl.h
@@ -209,7 +209,6 @@ walk:
if (ret)
goto walk;
pte |= PT_DIRTY_MASK;
- kvm_mmu_pte_write(vcpu, pte_gpa, (u8 *)&pte, sizeof(pte), 0);
walker->ptes[walker->level - 1] = pte;
}
--
1.6.0.6
^ permalink raw reply [flat|nested] 44+ messages in thread* [PATCH 20/43] KVM: APIC: kvm_apic_set_irq deliver all kinds of interrupts
2009-05-18 9:22 [PATCH 00/43] KVM updates for the 2.6.31 merge window (batch 1/4) Avi Kivity
` (18 preceding siblings ...)
2009-05-18 9:22 ` [PATCH 19/43] KVM: MMU: remove call to kvm_mmu_pte_write from walk_addr Avi Kivity
@ 2009-05-18 9:22 ` Avi Kivity
2009-05-18 9:22 ` [PATCH 21/43] KVM: ioapic/msi interrupt delivery consolidation Avi Kivity
` (22 subsequent siblings)
42 siblings, 0 replies; 44+ messages in thread
From: Avi Kivity @ 2009-05-18 9:22 UTC (permalink / raw)
To: linux-kernel; +Cc: kvm
From: Gleb Natapov <gleb@redhat.com>
Get rid of ioapic_inj_irq() and ioapic_inj_nmi() functions.
Signed-off-by: Gleb Natapov <gleb@redhat.com>
Signed-off-by: Marcelo Tosatti <mtosatti@redhat.com>
---
arch/ia64/include/asm/kvm_host.h | 1 -
arch/ia64/kvm/kvm-ia64.c | 8 +++---
arch/ia64/kvm/lapic.h | 2 +-
arch/x86/kvm/lapic.c | 47 +++++++++++++++++++++++--------------
arch/x86/kvm/lapic.h | 2 +-
virt/kvm/ioapic.c | 40 +++++---------------------------
virt/kvm/irq_comm.c | 1 +
7 files changed, 42 insertions(+), 59 deletions(-)
diff --git a/arch/ia64/include/asm/kvm_host.h b/arch/ia64/include/asm/kvm_host.h
index 4542651..5608488 100644
--- a/arch/ia64/include/asm/kvm_host.h
+++ b/arch/ia64/include/asm/kvm_host.h
@@ -585,7 +585,6 @@ int kvm_emulate_halt(struct kvm_vcpu *vcpu);
int kvm_pal_emul(struct kvm_vcpu *vcpu, struct kvm_run *kvm_run);
void kvm_sal_emul(struct kvm_vcpu *vcpu);
-static inline void kvm_inject_nmi(struct kvm_vcpu *vcpu) {}
#endif /* __ASSEMBLY__*/
#endif
diff --git a/arch/ia64/kvm/kvm-ia64.c b/arch/ia64/kvm/kvm-ia64.c
index 774f0d7..99d6d17 100644
--- a/arch/ia64/kvm/kvm-ia64.c
+++ b/arch/ia64/kvm/kvm-ia64.c
@@ -292,13 +292,13 @@ static void vcpu_deliver_ipi(struct kvm_vcpu *vcpu, uint64_t dm,
{
switch (dm) {
case SAPIC_FIXED:
- kvm_apic_set_irq(vcpu, vector, 0);
+ kvm_apic_set_irq(vcpu, vector, dm, 0);
break;
case SAPIC_NMI:
- kvm_apic_set_irq(vcpu, 2, 0);
+ kvm_apic_set_irq(vcpu, 2, dm, 0);
break;
case SAPIC_EXTINT:
- kvm_apic_set_irq(vcpu, 0, 0);
+ kvm_apic_set_irq(vcpu, 0, dm, 0);
break;
case SAPIC_INIT:
case SAPIC_PMI:
@@ -1813,7 +1813,7 @@ void kvm_vcpu_kick(struct kvm_vcpu *vcpu)
put_cpu();
}
-int kvm_apic_set_irq(struct kvm_vcpu *vcpu, u8 vec, u8 trig)
+int kvm_apic_set_irq(struct kvm_vcpu *vcpu, u8 vec, u8 dmode, u8 trig)
{
struct vpd *vpd = to_host(vcpu->kvm, vcpu->arch.vpd);
diff --git a/arch/ia64/kvm/lapic.h b/arch/ia64/kvm/lapic.h
index 6d6cbcb..cbcfaa6 100644
--- a/arch/ia64/kvm/lapic.h
+++ b/arch/ia64/kvm/lapic.h
@@ -20,6 +20,6 @@ void kvm_free_lapic(struct kvm_vcpu *vcpu);
int kvm_apic_match_physical_addr(struct kvm_lapic *apic, u16 dest);
int kvm_apic_match_logical_addr(struct kvm_lapic *apic, u8 mda);
-int kvm_apic_set_irq(struct kvm_vcpu *vcpu, u8 vec, u8 trig);
+int kvm_apic_set_irq(struct kvm_vcpu *vcpu, u8 vec, u8 dmode, u8 trig);
#endif
diff --git a/arch/x86/kvm/lapic.c b/arch/x86/kvm/lapic.c
index 27ca43e..a42f968 100644
--- a/arch/x86/kvm/lapic.c
+++ b/arch/x86/kvm/lapic.c
@@ -196,20 +196,30 @@ int kvm_lapic_find_highest_irr(struct kvm_vcpu *vcpu)
}
EXPORT_SYMBOL_GPL(kvm_lapic_find_highest_irr);
-int kvm_apic_set_irq(struct kvm_vcpu *vcpu, u8 vec, u8 trig)
+static int __apic_accept_irq(struct kvm_lapic *apic, int delivery_mode,
+ int vector, int level, int trig_mode);
+
+int kvm_apic_set_irq(struct kvm_vcpu *vcpu, u8 vec, u8 dmode, u8 trig)
{
struct kvm_lapic *apic = vcpu->arch.apic;
+ int lapic_dmode;
- if (!apic_test_and_set_irr(vec, apic)) {
- /* a new pending irq is set in IRR */
- if (trig)
- apic_set_vector(vec, apic->regs + APIC_TMR);
- else
- apic_clear_vector(vec, apic->regs + APIC_TMR);
- kvm_vcpu_kick(apic->vcpu);
- return 1;
+ switch (dmode) {
+ case IOAPIC_LOWEST_PRIORITY:
+ lapic_dmode = APIC_DM_LOWEST;
+ break;
+ case IOAPIC_FIXED:
+ lapic_dmode = APIC_DM_FIXED;
+ break;
+ case IOAPIC_NMI:
+ lapic_dmode = APIC_DM_NMI;
+ break;
+ default:
+ printk(KERN_DEBUG"Ignoring delivery mode %d\n", dmode);
+ return 0;
+ break;
}
- return 0;
+ return __apic_accept_irq(apic, lapic_dmode, vec, 1, trig);
}
static inline int apic_find_highest_isr(struct kvm_lapic *apic)
@@ -327,7 +337,7 @@ static int apic_match_dest(struct kvm_vcpu *vcpu, struct kvm_lapic *source,
static int __apic_accept_irq(struct kvm_lapic *apic, int delivery_mode,
int vector, int level, int trig_mode)
{
- int orig_irr, result = 0;
+ int result = 0;
struct kvm_vcpu *vcpu = apic->vcpu;
switch (delivery_mode) {
@@ -337,10 +347,11 @@ static int __apic_accept_irq(struct kvm_lapic *apic, int delivery_mode,
if (unlikely(!apic_enabled(apic)))
break;
- orig_irr = apic_test_and_set_irr(vector, apic);
- if (orig_irr && trig_mode) {
- apic_debug("level trig mode repeatedly for vector %d",
- vector);
+ result = !apic_test_and_set_irr(vector, apic);
+ if (!result) {
+ if (trig_mode)
+ apic_debug("level trig mode repeatedly for "
+ "vector %d", vector);
break;
}
@@ -349,10 +360,7 @@ static int __apic_accept_irq(struct kvm_lapic *apic, int delivery_mode,
apic_set_vector(vector, apic->regs + APIC_TMR);
} else
apic_clear_vector(vector, apic->regs + APIC_TMR);
-
kvm_vcpu_kick(vcpu);
-
- result = (orig_irr == 0);
break;
case APIC_DM_REMRD:
@@ -364,12 +372,14 @@ static int __apic_accept_irq(struct kvm_lapic *apic, int delivery_mode,
break;
case APIC_DM_NMI:
+ result = 1;
kvm_inject_nmi(vcpu);
kvm_vcpu_kick(vcpu);
break;
case APIC_DM_INIT:
if (level) {
+ result = 1;
if (vcpu->arch.mp_state == KVM_MP_STATE_RUNNABLE)
printk(KERN_DEBUG
"INIT on a runnable vcpu %d\n",
@@ -386,6 +396,7 @@ static int __apic_accept_irq(struct kvm_lapic *apic, int delivery_mode,
apic_debug("SIPI to vcpu %d vector 0x%02x\n",
vcpu->vcpu_id, vector);
if (vcpu->arch.mp_state == KVM_MP_STATE_INIT_RECEIVED) {
+ result = 1;
vcpu->arch.sipi_vector = vector;
vcpu->arch.mp_state = KVM_MP_STATE_SIPI_RECEIVED;
kvm_vcpu_kick(vcpu);
diff --git a/arch/x86/kvm/lapic.h b/arch/x86/kvm/lapic.h
index 2fc0d3c..1b0e3c0 100644
--- a/arch/x86/kvm/lapic.h
+++ b/arch/x86/kvm/lapic.h
@@ -31,7 +31,7 @@ u64 kvm_lapic_get_base(struct kvm_vcpu *vcpu);
int kvm_apic_match_physical_addr(struct kvm_lapic *apic, u16 dest);
int kvm_apic_match_logical_addr(struct kvm_lapic *apic, u8 mda);
-int kvm_apic_set_irq(struct kvm_vcpu *vcpu, u8 vec, u8 trig);
+int kvm_apic_set_irq(struct kvm_vcpu *vcpu, u8 vec, u8 dmode, u8 trig);
u64 kvm_get_apic_base(struct kvm_vcpu *vcpu);
void kvm_set_apic_base(struct kvm_vcpu *vcpu, u64 data);
diff --git a/virt/kvm/ioapic.c b/virt/kvm/ioapic.c
index ea268a8..d4a7948 100644
--- a/virt/kvm/ioapic.c
+++ b/virt/kvm/ioapic.c
@@ -142,25 +142,6 @@ static void ioapic_write_indirect(struct kvm_ioapic *ioapic, u32 val)
}
}
-static int ioapic_inj_irq(struct kvm_ioapic *ioapic,
- struct kvm_vcpu *vcpu,
- u8 vector, u8 trig_mode, u8 delivery_mode)
-{
- ioapic_debug("irq %d trig %d deliv %d\n", vector, trig_mode,
- delivery_mode);
-
- ASSERT((delivery_mode == IOAPIC_FIXED) ||
- (delivery_mode == IOAPIC_LOWEST_PRIORITY));
-
- return kvm_apic_set_irq(vcpu, vector, trig_mode);
-}
-
-static void ioapic_inj_nmi(struct kvm_vcpu *vcpu)
-{
- kvm_inject_nmi(vcpu);
- kvm_vcpu_kick(vcpu);
-}
-
static int ioapic_deliver(struct kvm_ioapic *ioapic, int irq)
{
union kvm_ioapic_redirect_entry entry = ioapic->redirtbl[irq];
@@ -193,21 +174,12 @@ static int ioapic_deliver(struct kvm_ioapic *ioapic, int irq)
__clear_bit(vcpu_id, deliver_bitmask);
vcpu = ioapic->kvm->vcpus[vcpu_id];
if (vcpu) {
- if (entry.fields.delivery_mode ==
- IOAPIC_LOWEST_PRIORITY ||
- entry.fields.delivery_mode == IOAPIC_FIXED) {
- if (r < 0)
- r = 0;
- r += ioapic_inj_irq(ioapic, vcpu,
- entry.fields.vector,
- entry.fields.trig_mode,
- entry.fields.delivery_mode);
- } else if (entry.fields.delivery_mode == IOAPIC_NMI) {
- r = 1;
- ioapic_inj_nmi(vcpu);
- } else
- ioapic_debug("unsupported delivery mode %x!\n",
- entry.fields.delivery_mode);
+ if (r < 0)
+ r = 0;
+ r += kvm_apic_set_irq(vcpu,
+ entry.fields.vector,
+ entry.fields.trig_mode,
+ entry.fields.delivery_mode);
} else
ioapic_debug("null destination vcpu: "
"mask=%x vector=%x delivery_mode=%x\n",
diff --git a/virt/kvm/irq_comm.c b/virt/kvm/irq_comm.c
index 1c6ff6d..325c668 100644
--- a/virt/kvm/irq_comm.c
+++ b/virt/kvm/irq_comm.c
@@ -148,6 +148,7 @@ static int kvm_set_msi(struct kvm_kernel_irq_routing_entry *e,
if (r < 0)
r = 0;
r += kvm_apic_set_irq(vcpu, entry.fields.vector,
+ entry.fields.dest_mode,
entry.fields.trig_mode);
}
}
--
1.6.0.6
^ permalink raw reply [flat|nested] 44+ messages in thread* [PATCH 21/43] KVM: ioapic/msi interrupt delivery consolidation
2009-05-18 9:22 [PATCH 00/43] KVM updates for the 2.6.31 merge window (batch 1/4) Avi Kivity
` (19 preceding siblings ...)
2009-05-18 9:22 ` [PATCH 20/43] KVM: APIC: kvm_apic_set_irq deliver all kinds of interrupts Avi Kivity
@ 2009-05-18 9:22 ` Avi Kivity
2009-05-18 9:22 ` [PATCH 22/43] KVM: consolidate ioapic/ipi interrupt delivery logic Avi Kivity
` (21 subsequent siblings)
42 siblings, 0 replies; 44+ messages in thread
From: Avi Kivity @ 2009-05-18 9:22 UTC (permalink / raw)
To: linux-kernel; +Cc: kvm
From: Gleb Natapov <gleb@redhat.com>
ioapic_deliver() and kvm_set_msi() have code duplication. Move
the code into ioapic_deliver_entry() function and call it from
both places.
Signed-off-by: Gleb Natapov <gleb@redhat.com>
Signed-off-by: Marcelo Tosatti <mtosatti@redhat.com>
---
include/linux/kvm_host.h | 2 +-
virt/kvm/ioapic.c | 61 ++++++++++++++++++++++++----------------------
virt/kvm/ioapic.h | 4 +-
virt/kvm/irq_comm.c | 32 ++----------------------
4 files changed, 38 insertions(+), 61 deletions(-)
diff --git a/include/linux/kvm_host.h b/include/linux/kvm_host.h
index 3b91ec9..ec9d078 100644
--- a/include/linux/kvm_host.h
+++ b/include/linux/kvm_host.h
@@ -364,7 +364,7 @@ void kvm_unregister_irq_mask_notifier(struct kvm *kvm, int irq,
void kvm_fire_mask_notifiers(struct kvm *kvm, int irq, bool mask);
#ifdef __KVM_HAVE_IOAPIC
-void kvm_get_intr_delivery_bitmask(struct kvm_ioapic *ioapic,
+void kvm_get_intr_delivery_bitmask(struct kvm *kvm,
union kvm_ioapic_redirect_entry *entry,
unsigned long *deliver_bitmask);
#endif
diff --git a/virt/kvm/ioapic.c b/virt/kvm/ioapic.c
index d4a7948..b71c044 100644
--- a/virt/kvm/ioapic.c
+++ b/virt/kvm/ioapic.c
@@ -142,54 +142,57 @@ static void ioapic_write_indirect(struct kvm_ioapic *ioapic, u32 val)
}
}
-static int ioapic_deliver(struct kvm_ioapic *ioapic, int irq)
+int ioapic_deliver_entry(struct kvm *kvm, union kvm_ioapic_redirect_entry *e)
{
- union kvm_ioapic_redirect_entry entry = ioapic->redirtbl[irq];
DECLARE_BITMAP(deliver_bitmask, KVM_MAX_VCPUS);
- struct kvm_vcpu *vcpu;
- int vcpu_id, r = -1;
+ int i, r = -1;
- ioapic_debug("dest=%x dest_mode=%x delivery_mode=%x "
- "vector=%x trig_mode=%x\n",
- entry.fields.dest, entry.fields.dest_mode,
- entry.fields.delivery_mode, entry.fields.vector,
- entry.fields.trig_mode);
-
- /* Always delivery PIT interrupt to vcpu 0 */
-#ifdef CONFIG_X86
- if (irq == 0) {
- bitmap_zero(deliver_bitmask, KVM_MAX_VCPUS);
- __set_bit(0, deliver_bitmask);
- } else
-#endif
- kvm_get_intr_delivery_bitmask(ioapic, &entry, deliver_bitmask);
+ kvm_get_intr_delivery_bitmask(kvm, e, deliver_bitmask);
if (find_first_bit(deliver_bitmask, KVM_MAX_VCPUS) >= KVM_MAX_VCPUS) {
ioapic_debug("no target on destination\n");
- return 0;
+ return r;
}
- while ((vcpu_id = find_first_bit(deliver_bitmask, KVM_MAX_VCPUS))
+ while ((i = find_first_bit(deliver_bitmask, KVM_MAX_VCPUS))
< KVM_MAX_VCPUS) {
- __clear_bit(vcpu_id, deliver_bitmask);
- vcpu = ioapic->kvm->vcpus[vcpu_id];
+ struct kvm_vcpu *vcpu = kvm->vcpus[i];
+ __clear_bit(i, deliver_bitmask);
if (vcpu) {
if (r < 0)
r = 0;
- r += kvm_apic_set_irq(vcpu,
- entry.fields.vector,
- entry.fields.trig_mode,
- entry.fields.delivery_mode);
+ r += kvm_apic_set_irq(vcpu, e->fields.vector,
+ e->fields.delivery_mode,
+ e->fields.trig_mode);
} else
ioapic_debug("null destination vcpu: "
"mask=%x vector=%x delivery_mode=%x\n",
- entry.fields.deliver_bitmask,
- entry.fields.vector,
- entry.fields.delivery_mode);
+ e->fields.deliver_bitmask,
+ e->fields.vector, e->fields.delivery_mode);
}
return r;
}
+static int ioapic_deliver(struct kvm_ioapic *ioapic, int irq)
+{
+ union kvm_ioapic_redirect_entry entry = ioapic->redirtbl[irq];
+
+ ioapic_debug("dest=%x dest_mode=%x delivery_mode=%x "
+ "vector=%x trig_mode=%x\n",
+ entry.fields.dest, entry.fields.dest_mode,
+ entry.fields.delivery_mode, entry.fields.vector,
+ entry.fields.trig_mode);
+
+#ifdef CONFIG_X86
+ /* Always delivery PIT interrupt to vcpu 0 */
+ if (irq == 0) {
+ entry.fields.dest_mode = 0; /* Physical mode. */
+ entry.fields.dest_id = ioapic->kvm->vcpus[0]->vcpu_id;
+ }
+#endif
+ return ioapic_deliver_entry(ioapic->kvm, &entry);
+}
+
int kvm_ioapic_set_irq(struct kvm_ioapic *ioapic, int irq, int level)
{
u32 old_irr = ioapic->irr;
diff --git a/virt/kvm/ioapic.h b/virt/kvm/ioapic.h
index c8032ab..bedeea5 100644
--- a/virt/kvm/ioapic.h
+++ b/virt/kvm/ioapic.h
@@ -70,8 +70,8 @@ void kvm_ioapic_update_eoi(struct kvm *kvm, int vector, int trigger_mode);
int kvm_ioapic_init(struct kvm *kvm);
int kvm_ioapic_set_irq(struct kvm_ioapic *ioapic, int irq, int level);
void kvm_ioapic_reset(struct kvm_ioapic *ioapic);
-void kvm_get_intr_delivery_bitmask(struct kvm_ioapic *ioapic,
+void kvm_get_intr_delivery_bitmask(struct kvm *kvm,
union kvm_ioapic_redirect_entry *entry,
unsigned long *deliver_bitmask);
-
+int ioapic_deliver_entry(struct kvm *kvm, union kvm_ioapic_redirect_entry *e);
#endif
diff --git a/virt/kvm/irq_comm.c b/virt/kvm/irq_comm.c
index 325c668..35397a5 100644
--- a/virt/kvm/irq_comm.c
+++ b/virt/kvm/irq_comm.c
@@ -43,12 +43,11 @@ static int kvm_set_ioapic_irq(struct kvm_kernel_irq_routing_entry *e,
return kvm_ioapic_set_irq(kvm->arch.vioapic, e->irqchip.pin, level);
}
-void kvm_get_intr_delivery_bitmask(struct kvm_ioapic *ioapic,
+void kvm_get_intr_delivery_bitmask(struct kvm *kvm,
union kvm_ioapic_redirect_entry *entry,
unsigned long *deliver_bitmask)
{
int i;
- struct kvm *kvm = ioapic->kvm;
struct kvm_vcpu *vcpu;
bitmap_zero(deliver_bitmask, KVM_MAX_VCPUS);
@@ -90,7 +89,7 @@ void kvm_get_intr_delivery_bitmask(struct kvm_ioapic *ioapic,
switch (entry->fields.delivery_mode) {
case IOAPIC_LOWEST_PRIORITY:
/* Select one in deliver_bitmask */
- vcpu = kvm_get_lowest_prio_vcpu(ioapic->kvm,
+ vcpu = kvm_get_lowest_prio_vcpu(kvm,
entry->fields.vector, deliver_bitmask);
bitmap_zero(deliver_bitmask, KVM_MAX_VCPUS);
if (!vcpu)
@@ -111,13 +110,7 @@ void kvm_get_intr_delivery_bitmask(struct kvm_ioapic *ioapic,
static int kvm_set_msi(struct kvm_kernel_irq_routing_entry *e,
struct kvm *kvm, int level)
{
- int vcpu_id, r = -1;
- struct kvm_vcpu *vcpu;
- struct kvm_ioapic *ioapic = ioapic_irqchip(kvm);
union kvm_ioapic_redirect_entry entry;
- DECLARE_BITMAP(deliver_bitmask, KVM_MAX_VCPUS);
-
- BUG_ON(!ioapic);
entry.bits = 0;
entry.fields.dest_id = (e->msi.address_lo &
@@ -133,26 +126,7 @@ static int kvm_set_msi(struct kvm_kernel_irq_routing_entry *e,
(unsigned long *)&e->msi.data);
/* TODO Deal with RH bit of MSI message address */
-
- kvm_get_intr_delivery_bitmask(ioapic, &entry, deliver_bitmask);
-
- if (find_first_bit(deliver_bitmask, KVM_MAX_VCPUS) >= KVM_MAX_VCPUS) {
- printk(KERN_WARNING "kvm: no destination for MSI delivery!");
- return -1;
- }
- while ((vcpu_id = find_first_bit(deliver_bitmask,
- KVM_MAX_VCPUS)) < KVM_MAX_VCPUS) {
- __clear_bit(vcpu_id, deliver_bitmask);
- vcpu = ioapic->kvm->vcpus[vcpu_id];
- if (vcpu) {
- if (r < 0)
- r = 0;
- r += kvm_apic_set_irq(vcpu, entry.fields.vector,
- entry.fields.dest_mode,
- entry.fields.trig_mode);
- }
- }
- return r;
+ return ioapic_deliver_entry(kvm, &entry);
}
/* This should be called with the kvm->lock mutex held
--
1.6.0.6
^ permalink raw reply [flat|nested] 44+ messages in thread* [PATCH 22/43] KVM: consolidate ioapic/ipi interrupt delivery logic
2009-05-18 9:22 [PATCH 00/43] KVM updates for the 2.6.31 merge window (batch 1/4) Avi Kivity
` (20 preceding siblings ...)
2009-05-18 9:22 ` [PATCH 21/43] KVM: ioapic/msi interrupt delivery consolidation Avi Kivity
@ 2009-05-18 9:22 ` Avi Kivity
2009-05-18 9:22 ` [PATCH 23/43] KVM: change the way how lowest priority vcpu is calculated Avi Kivity
` (20 subsequent siblings)
42 siblings, 0 replies; 44+ messages in thread
From: Avi Kivity @ 2009-05-18 9:22 UTC (permalink / raw)
To: linux-kernel; +Cc: kvm
From: Gleb Natapov <gleb@redhat.com>
Use kvm_apic_match_dest() in kvm_get_intr_delivery_bitmask() instead
of duplicating the same code. Use kvm_get_intr_delivery_bitmask() in
apic_send_ipi() to figure out ipi destination instead of reimplementing
the logic.
Signed-off-by: Gleb Natapov <gleb@redhat.com>
Signed-off-by: Marcelo Tosatti <mtosatti@redhat.com>
---
arch/ia64/kvm/kvm-ia64.c | 8 +++++
arch/ia64/kvm/lapic.h | 3 ++
arch/x86/kvm/lapic.c | 69 ++++++++++++++++--------------------------
arch/x86/kvm/lapic.h | 2 +
include/linux/kvm_host.h | 5 ---
virt/kvm/ioapic.c | 5 ++-
virt/kvm/ioapic.h | 10 ++++--
virt/kvm/irq_comm.c | 76 +++++++++++++--------------------------------
8 files changed, 71 insertions(+), 107 deletions(-)
diff --git a/arch/ia64/kvm/kvm-ia64.c b/arch/ia64/kvm/kvm-ia64.c
index 99d6d17..8eea9cb 100644
--- a/arch/ia64/kvm/kvm-ia64.c
+++ b/arch/ia64/kvm/kvm-ia64.c
@@ -1852,6 +1852,14 @@ struct kvm_vcpu *kvm_get_lowest_prio_vcpu(struct kvm *kvm, u8 vector,
return lvcpu;
}
+int kvm_apic_match_dest(struct kvm_vcpu *vcpu, struct kvm_lapic *source,
+ int short_hand, int dest, int dest_mode)
+{
+ return (dest_mode == 0) ?
+ kvm_apic_match_physical_addr(target, dest) :
+ kvm_apic_match_logical_addr(target, dest);
+}
+
static int find_highest_bits(int *dat)
{
u32 bits, bitnum;
diff --git a/arch/ia64/kvm/lapic.h b/arch/ia64/kvm/lapic.h
index cbcfaa6..31602e7 100644
--- a/arch/ia64/kvm/lapic.h
+++ b/arch/ia64/kvm/lapic.h
@@ -20,6 +20,9 @@ void kvm_free_lapic(struct kvm_vcpu *vcpu);
int kvm_apic_match_physical_addr(struct kvm_lapic *apic, u16 dest);
int kvm_apic_match_logical_addr(struct kvm_lapic *apic, u8 mda);
+int kvm_apic_match_dest(struct kvm_vcpu *vcpu, struct kvm_lapic *source,
+ int short_hand, int dest, int dest_mode);
+bool kvm_apic_present(struct kvm_vcpu *vcpu);
int kvm_apic_set_irq(struct kvm_vcpu *vcpu, u8 vec, u8 dmode, u8 trig);
#endif
diff --git a/arch/x86/kvm/lapic.c b/arch/x86/kvm/lapic.c
index a42f968..998862a 100644
--- a/arch/x86/kvm/lapic.c
+++ b/arch/x86/kvm/lapic.c
@@ -260,7 +260,7 @@ static void apic_set_tpr(struct kvm_lapic *apic, u32 tpr)
int kvm_apic_match_physical_addr(struct kvm_lapic *apic, u16 dest)
{
- return kvm_apic_id(apic) == dest;
+ return dest == 0xff || kvm_apic_id(apic) == dest;
}
int kvm_apic_match_logical_addr(struct kvm_lapic *apic, u8 mda)
@@ -289,37 +289,34 @@ int kvm_apic_match_logical_addr(struct kvm_lapic *apic, u8 mda)
return result;
}
-static int apic_match_dest(struct kvm_vcpu *vcpu, struct kvm_lapic *source,
+int kvm_apic_match_dest(struct kvm_vcpu *vcpu, struct kvm_lapic *source,
int short_hand, int dest, int dest_mode)
{
int result = 0;
struct kvm_lapic *target = vcpu->arch.apic;
apic_debug("target %p, source %p, dest 0x%x, "
- "dest_mode 0x%x, short_hand 0x%x",
+ "dest_mode 0x%x, short_hand 0x%x\n",
target, source, dest, dest_mode, short_hand);
ASSERT(!target);
switch (short_hand) {
case APIC_DEST_NOSHORT:
- if (dest_mode == 0) {
+ if (dest_mode == 0)
/* Physical mode. */
- if ((dest == 0xFF) || (dest == kvm_apic_id(target)))
- result = 1;
- } else
+ result = kvm_apic_match_physical_addr(target, dest);
+ else
/* Logical mode. */
result = kvm_apic_match_logical_addr(target, dest);
break;
case APIC_DEST_SELF:
- if (target == source)
- result = 1;
+ result = (target == source);
break;
case APIC_DEST_ALLINC:
result = 1;
break;
case APIC_DEST_ALLBUT:
- if (target != source)
- result = 1;
+ result = (target != source);
break;
default:
printk(KERN_WARNING "Bad dest shorthand value %x\n",
@@ -492,38 +489,26 @@ static void apic_send_ipi(struct kvm_lapic *apic)
unsigned int delivery_mode = icr_low & APIC_MODE_MASK;
unsigned int vector = icr_low & APIC_VECTOR_MASK;
- struct kvm_vcpu *target;
- struct kvm_vcpu *vcpu;
- DECLARE_BITMAP(lpr_map, KVM_MAX_VCPUS);
+ DECLARE_BITMAP(deliver_bitmask, KVM_MAX_VCPUS);
int i;
- bitmap_zero(lpr_map, KVM_MAX_VCPUS);
apic_debug("icr_high 0x%x, icr_low 0x%x, "
"short_hand 0x%x, dest 0x%x, trig_mode 0x%x, level 0x%x, "
"dest_mode 0x%x, delivery_mode 0x%x, vector 0x%x\n",
icr_high, icr_low, short_hand, dest,
trig_mode, level, dest_mode, delivery_mode, vector);
- for (i = 0; i < KVM_MAX_VCPUS; i++) {
- vcpu = apic->vcpu->kvm->vcpus[i];
- if (!vcpu)
- continue;
-
- if (vcpu->arch.apic &&
- apic_match_dest(vcpu, apic, short_hand, dest, dest_mode)) {
- if (delivery_mode == APIC_DM_LOWEST)
- __set_bit(vcpu->vcpu_id, lpr_map);
- else
- __apic_accept_irq(vcpu->arch.apic, delivery_mode,
- vector, level, trig_mode);
- }
- }
-
- if (delivery_mode == APIC_DM_LOWEST) {
- target = kvm_get_lowest_prio_vcpu(vcpu->kvm, vector, lpr_map);
- if (target != NULL)
- __apic_accept_irq(target->arch.apic, delivery_mode,
- vector, level, trig_mode);
+ kvm_get_intr_delivery_bitmask(apic->vcpu->kvm, apic, dest, dest_mode,
+ delivery_mode == APIC_DM_LOWEST, short_hand,
+ deliver_bitmask);
+
+ while ((i = find_first_bit(deliver_bitmask, KVM_MAX_VCPUS))
+ < KVM_MAX_VCPUS) {
+ struct kvm_vcpu *vcpu = apic->vcpu->kvm->vcpus[i];
+ __clear_bit(i, deliver_bitmask);
+ if (vcpu)
+ __apic_accept_irq(vcpu->arch.apic, delivery_mode,
+ vector, level, trig_mode);
}
}
@@ -930,16 +915,14 @@ void kvm_lapic_reset(struct kvm_vcpu *vcpu)
}
EXPORT_SYMBOL_GPL(kvm_lapic_reset);
-int kvm_lapic_enabled(struct kvm_vcpu *vcpu)
+bool kvm_apic_present(struct kvm_vcpu *vcpu)
{
- struct kvm_lapic *apic = vcpu->arch.apic;
- int ret = 0;
-
- if (!apic)
- return 0;
- ret = apic_enabled(apic);
+ return vcpu->arch.apic && apic_hw_enabled(vcpu->arch.apic);
+}
- return ret;
+int kvm_lapic_enabled(struct kvm_vcpu *vcpu)
+{
+ return kvm_apic_present(vcpu) && apic_sw_enabled(vcpu->arch.apic);
}
EXPORT_SYMBOL_GPL(kvm_lapic_enabled);
diff --git a/arch/x86/kvm/lapic.h b/arch/x86/kvm/lapic.h
index 1b0e3c0..b66dc14 100644
--- a/arch/x86/kvm/lapic.h
+++ b/arch/x86/kvm/lapic.h
@@ -37,6 +37,8 @@ u64 kvm_get_apic_base(struct kvm_vcpu *vcpu);
void kvm_set_apic_base(struct kvm_vcpu *vcpu, u64 data);
void kvm_apic_post_state_restore(struct kvm_vcpu *vcpu);
int kvm_lapic_enabled(struct kvm_vcpu *vcpu);
+bool kvm_apic_present(struct kvm_vcpu *vcpu);
+bool kvm_lapic_present(struct kvm_vcpu *vcpu);
int kvm_lapic_find_highest_irr(struct kvm_vcpu *vcpu);
void kvm_lapic_set_vapic_addr(struct kvm_vcpu *vcpu, gpa_t vapic_addr);
diff --git a/include/linux/kvm_host.h b/include/linux/kvm_host.h
index ec9d078..fb60f31 100644
--- a/include/linux/kvm_host.h
+++ b/include/linux/kvm_host.h
@@ -363,11 +363,6 @@ void kvm_unregister_irq_mask_notifier(struct kvm *kvm, int irq,
struct kvm_irq_mask_notifier *kimn);
void kvm_fire_mask_notifiers(struct kvm *kvm, int irq, bool mask);
-#ifdef __KVM_HAVE_IOAPIC
-void kvm_get_intr_delivery_bitmask(struct kvm *kvm,
- union kvm_ioapic_redirect_entry *entry,
- unsigned long *deliver_bitmask);
-#endif
int kvm_set_irq(struct kvm *kvm, int irq_source_id, int irq, int level);
void kvm_notify_acked_irq(struct kvm *kvm, unsigned irqchip, unsigned pin);
void kvm_register_irq_ack_notifier(struct kvm *kvm,
diff --git a/virt/kvm/ioapic.c b/virt/kvm/ioapic.c
index b71c044..43969bb 100644
--- a/virt/kvm/ioapic.c
+++ b/virt/kvm/ioapic.c
@@ -147,7 +147,10 @@ int ioapic_deliver_entry(struct kvm *kvm, union kvm_ioapic_redirect_entry *e)
DECLARE_BITMAP(deliver_bitmask, KVM_MAX_VCPUS);
int i, r = -1;
- kvm_get_intr_delivery_bitmask(kvm, e, deliver_bitmask);
+ kvm_get_intr_delivery_bitmask(kvm, NULL, e->fields.dest_id,
+ e->fields.dest_mode,
+ e->fields.delivery_mode == IOAPIC_LOWEST_PRIORITY,
+ 0, deliver_bitmask);
if (find_first_bit(deliver_bitmask, KVM_MAX_VCPUS) >= KVM_MAX_VCPUS) {
ioapic_debug("no target on destination\n");
diff --git a/virt/kvm/ioapic.h b/virt/kvm/ioapic.h
index bedeea5..d996c7a 100644
--- a/virt/kvm/ioapic.h
+++ b/virt/kvm/ioapic.h
@@ -65,13 +65,15 @@ static inline struct kvm_ioapic *ioapic_irqchip(struct kvm *kvm)
}
struct kvm_vcpu *kvm_get_lowest_prio_vcpu(struct kvm *kvm, u8 vector,
- unsigned long *bitmap);
+ unsigned long *bitmap);
+int kvm_apic_match_dest(struct kvm_vcpu *vcpu, struct kvm_lapic *source,
+ int short_hand, int dest, int dest_mode);
void kvm_ioapic_update_eoi(struct kvm *kvm, int vector, int trigger_mode);
int kvm_ioapic_init(struct kvm *kvm);
int kvm_ioapic_set_irq(struct kvm_ioapic *ioapic, int irq, int level);
void kvm_ioapic_reset(struct kvm_ioapic *ioapic);
-void kvm_get_intr_delivery_bitmask(struct kvm *kvm,
- union kvm_ioapic_redirect_entry *entry,
- unsigned long *deliver_bitmask);
+void kvm_get_intr_delivery_bitmask(struct kvm *kvm, struct kvm_lapic *src,
+ int dest_id, int dest_mode, bool low_prio, int short_hand,
+ unsigned long *deliver_bitmask);
int ioapic_deliver_entry(struct kvm *kvm, union kvm_ioapic_redirect_entry *e);
#endif
diff --git a/virt/kvm/irq_comm.c b/virt/kvm/irq_comm.c
index 35397a5..e43701c 100644
--- a/virt/kvm/irq_comm.c
+++ b/virt/kvm/irq_comm.c
@@ -43,67 +43,35 @@ static int kvm_set_ioapic_irq(struct kvm_kernel_irq_routing_entry *e,
return kvm_ioapic_set_irq(kvm->arch.vioapic, e->irqchip.pin, level);
}
-void kvm_get_intr_delivery_bitmask(struct kvm *kvm,
- union kvm_ioapic_redirect_entry *entry,
- unsigned long *deliver_bitmask)
+void kvm_get_intr_delivery_bitmask(struct kvm *kvm, struct kvm_lapic *src,
+ int dest_id, int dest_mode, bool low_prio, int short_hand,
+ unsigned long *deliver_bitmask)
{
int i;
struct kvm_vcpu *vcpu;
+ if (dest_mode == 0 && dest_id == 0xff && low_prio)
+ printk(KERN_INFO "kvm: apic: phys broadcast and lowest prio\n");
+
bitmap_zero(deliver_bitmask, KVM_MAX_VCPUS);
+ for (i = 0; i < KVM_MAX_VCPUS; i++) {
+ vcpu = kvm->vcpus[i];
- if (entry->fields.dest_mode == 0) { /* Physical mode. */
- if (entry->fields.dest_id == 0xFF) { /* Broadcast. */
- for (i = 0; i < KVM_MAX_VCPUS; ++i)
- if (kvm->vcpus[i] && kvm->vcpus[i]->arch.apic)
- __set_bit(i, deliver_bitmask);
- /* Lowest priority shouldn't combine with broadcast */
- if (entry->fields.delivery_mode ==
- IOAPIC_LOWEST_PRIORITY && printk_ratelimit())
- printk(KERN_INFO "kvm: apic: phys broadcast "
- "and lowest prio\n");
- return;
- }
- for (i = 0; i < KVM_MAX_VCPUS; ++i) {
- vcpu = kvm->vcpus[i];
- if (!vcpu)
- continue;
- if (kvm_apic_match_physical_addr(vcpu->arch.apic,
- entry->fields.dest_id)) {
- if (vcpu->arch.apic)
- __set_bit(i, deliver_bitmask);
- break;
- }
- }
- } else if (entry->fields.dest_id != 0) /* Logical mode, MDA non-zero. */
- for (i = 0; i < KVM_MAX_VCPUS; ++i) {
- vcpu = kvm->vcpus[i];
- if (!vcpu)
- continue;
- if (vcpu->arch.apic &&
- kvm_apic_match_logical_addr(vcpu->arch.apic,
- entry->fields.dest_id))
- __set_bit(i, deliver_bitmask);
- }
+ if (!vcpu || !kvm_apic_present(vcpu))
+ continue;
- switch (entry->fields.delivery_mode) {
- case IOAPIC_LOWEST_PRIORITY:
- /* Select one in deliver_bitmask */
- vcpu = kvm_get_lowest_prio_vcpu(kvm,
- entry->fields.vector, deliver_bitmask);
- bitmap_zero(deliver_bitmask, KVM_MAX_VCPUS);
- if (!vcpu)
- return;
- __set_bit(vcpu->vcpu_id, deliver_bitmask);
- break;
- case IOAPIC_FIXED:
- case IOAPIC_NMI:
- break;
- default:
- if (printk_ratelimit())
- printk(KERN_INFO "kvm: unsupported delivery mode %d\n",
- entry->fields.delivery_mode);
+ if (!kvm_apic_match_dest(vcpu, src, short_hand, dest_id,
+ dest_mode))
+ continue;
+
+ __set_bit(i, deliver_bitmask);
+ }
+
+ if (low_prio) {
+ vcpu = kvm_get_lowest_prio_vcpu(kvm, 0, deliver_bitmask);
bitmap_zero(deliver_bitmask, KVM_MAX_VCPUS);
+ if (vcpu)
+ __set_bit(vcpu->vcpu_id, deliver_bitmask);
}
}
--
1.6.0.6
^ permalink raw reply [flat|nested] 44+ messages in thread* [PATCH 23/43] KVM: change the way how lowest priority vcpu is calculated
2009-05-18 9:22 [PATCH 00/43] KVM updates for the 2.6.31 merge window (batch 1/4) Avi Kivity
` (21 preceding siblings ...)
2009-05-18 9:22 ` [PATCH 22/43] KVM: consolidate ioapic/ipi interrupt delivery logic Avi Kivity
@ 2009-05-18 9:22 ` Avi Kivity
2009-05-18 9:22 ` [PATCH 24/43] KVM: APIC: get rid of deliver_bitmask Avi Kivity
` (19 subsequent siblings)
42 siblings, 0 replies; 44+ messages in thread
From: Avi Kivity @ 2009-05-18 9:22 UTC (permalink / raw)
To: linux-kernel; +Cc: kvm
From: Gleb Natapov <gleb@redhat.com>
The new way does not require additional loop over vcpus to calculate
the one with lowest priority as one is chosen during delivery bitmap
construction.
Signed-off-by: Gleb Natapov <gleb@redhat.com>
Signed-off-by: Marcelo Tosatti <mtosatti@redhat.com>
---
arch/ia64/kvm/kvm-ia64.c | 15 +-----------
arch/ia64/kvm/lapic.h | 1 +
arch/x86/include/asm/kvm_host.h | 2 +-
arch/x86/kvm/lapic.c | 43 +++++---------------------------------
virt/kvm/ioapic.h | 3 +-
virt/kvm/irq_comm.c | 19 ++++++++++-------
6 files changed, 22 insertions(+), 61 deletions(-)
diff --git a/arch/ia64/kvm/kvm-ia64.c b/arch/ia64/kvm/kvm-ia64.c
index 8eea9cb..1887a93 100644
--- a/arch/ia64/kvm/kvm-ia64.c
+++ b/arch/ia64/kvm/kvm-ia64.c
@@ -1836,20 +1836,9 @@ int kvm_apic_match_logical_addr(struct kvm_lapic *apic, u8 mda)
return 0;
}
-struct kvm_vcpu *kvm_get_lowest_prio_vcpu(struct kvm *kvm, u8 vector,
- unsigned long *bitmap)
+int kvm_apic_compare_prio(struct kvm_vcpu *vcpu1, struct kvm_vcpu *vcpu2)
{
- struct kvm_vcpu *lvcpu = kvm->vcpus[0];
- int i;
-
- for (i = 1; i < kvm->arch.online_vcpus; i++) {
- if (!kvm->vcpus[i])
- continue;
- if (lvcpu->arch.xtp > kvm->vcpus[i]->arch.xtp)
- lvcpu = kvm->vcpus[i];
- }
-
- return lvcpu;
+ return vcpu1->arch.xtp - vcpu2->arch.xtp;
}
int kvm_apic_match_dest(struct kvm_vcpu *vcpu, struct kvm_lapic *source,
diff --git a/arch/ia64/kvm/lapic.h b/arch/ia64/kvm/lapic.h
index 31602e7..e42109e 100644
--- a/arch/ia64/kvm/lapic.h
+++ b/arch/ia64/kvm/lapic.h
@@ -22,6 +22,7 @@ int kvm_apic_match_physical_addr(struct kvm_lapic *apic, u16 dest);
int kvm_apic_match_logical_addr(struct kvm_lapic *apic, u8 mda);
int kvm_apic_match_dest(struct kvm_vcpu *vcpu, struct kvm_lapic *source,
int short_hand, int dest, int dest_mode);
+int kvm_apic_compare_prio(struct kvm_vcpu *vcpu1, struct kvm_vcpu *vcpu2);
bool kvm_apic_present(struct kvm_vcpu *vcpu);
int kvm_apic_set_irq(struct kvm_vcpu *vcpu, u8 vec, u8 dmode, u8 trig);
diff --git a/arch/x86/include/asm/kvm_host.h b/arch/x86/include/asm/kvm_host.h
index f0faf58..4627627 100644
--- a/arch/x86/include/asm/kvm_host.h
+++ b/arch/x86/include/asm/kvm_host.h
@@ -286,6 +286,7 @@ struct kvm_vcpu_arch {
u64 shadow_efer;
u64 apic_base;
struct kvm_lapic *apic; /* kernel irqchip context */
+ int32_t apic_arb_prio;
int mp_state;
int sipi_vector;
u64 ia32_misc_enable_msr;
@@ -400,7 +401,6 @@ struct kvm_arch{
struct hlist_head irq_ack_notifier_list;
int vapics_in_nmi_mode;
- int round_robin_prev_vcpu;
unsigned int tss_addr;
struct page *apic_access_page;
diff --git a/arch/x86/kvm/lapic.c b/arch/x86/kvm/lapic.c
index 998862a..814466f 100644
--- a/arch/x86/kvm/lapic.c
+++ b/arch/x86/kvm/lapic.c
@@ -338,8 +338,9 @@ static int __apic_accept_irq(struct kvm_lapic *apic, int delivery_mode,
struct kvm_vcpu *vcpu = apic->vcpu;
switch (delivery_mode) {
- case APIC_DM_FIXED:
case APIC_DM_LOWEST:
+ vcpu->arch.apic_arb_prio++;
+ case APIC_DM_FIXED:
/* FIXME add logic for vcpu on reset */
if (unlikely(!apic_enabled(apic)))
break;
@@ -416,43 +417,9 @@ static int __apic_accept_irq(struct kvm_lapic *apic, int delivery_mode,
return result;
}
-static struct kvm_lapic *kvm_apic_round_robin(struct kvm *kvm, u8 vector,
- unsigned long *bitmap)
+int kvm_apic_compare_prio(struct kvm_vcpu *vcpu1, struct kvm_vcpu *vcpu2)
{
- int last;
- int next;
- struct kvm_lapic *apic = NULL;
-
- last = kvm->arch.round_robin_prev_vcpu;
- next = last;
-
- do {
- if (++next == KVM_MAX_VCPUS)
- next = 0;
- if (kvm->vcpus[next] == NULL || !test_bit(next, bitmap))
- continue;
- apic = kvm->vcpus[next]->arch.apic;
- if (apic && apic_enabled(apic))
- break;
- apic = NULL;
- } while (next != last);
- kvm->arch.round_robin_prev_vcpu = next;
-
- if (!apic)
- printk(KERN_DEBUG "vcpu not ready for apic_round_robin\n");
-
- return apic;
-}
-
-struct kvm_vcpu *kvm_get_lowest_prio_vcpu(struct kvm *kvm, u8 vector,
- unsigned long *bitmap)
-{
- struct kvm_lapic *apic;
-
- apic = kvm_apic_round_robin(kvm, vector, bitmap);
- if (apic)
- return apic->vcpu;
- return NULL;
+ return vcpu1->arch.apic_arb_prio - vcpu2->arch.apic_arb_prio;
}
static void apic_set_eoi(struct kvm_lapic *apic)
@@ -908,6 +875,8 @@ void kvm_lapic_reset(struct kvm_vcpu *vcpu)
vcpu->arch.apic_base |= MSR_IA32_APICBASE_BSP;
apic_update_ppr(apic);
+ vcpu->arch.apic_arb_prio = 0;
+
apic_debug(KERN_INFO "%s: vcpu=%p, id=%d, base_msr="
"0x%016" PRIx64 ", base_address=0x%0lx.\n", __func__,
vcpu, kvm_apic_id(apic),
diff --git a/virt/kvm/ioapic.h b/virt/kvm/ioapic.h
index d996c7a..e7bc92d 100644
--- a/virt/kvm/ioapic.h
+++ b/virt/kvm/ioapic.h
@@ -64,10 +64,9 @@ static inline struct kvm_ioapic *ioapic_irqchip(struct kvm *kvm)
return kvm->arch.vioapic;
}
-struct kvm_vcpu *kvm_get_lowest_prio_vcpu(struct kvm *kvm, u8 vector,
- unsigned long *bitmap);
int kvm_apic_match_dest(struct kvm_vcpu *vcpu, struct kvm_lapic *source,
int short_hand, int dest, int dest_mode);
+int kvm_apic_compare_prio(struct kvm_vcpu *vcpu1, struct kvm_vcpu *vcpu2);
void kvm_ioapic_update_eoi(struct kvm *kvm, int vector, int trigger_mode);
int kvm_ioapic_init(struct kvm *kvm);
int kvm_ioapic_set_irq(struct kvm_ioapic *ioapic, int irq, int level);
diff --git a/virt/kvm/irq_comm.c b/virt/kvm/irq_comm.c
index e43701c..f5e059b 100644
--- a/virt/kvm/irq_comm.c
+++ b/virt/kvm/irq_comm.c
@@ -47,7 +47,7 @@ void kvm_get_intr_delivery_bitmask(struct kvm *kvm, struct kvm_lapic *src,
int dest_id, int dest_mode, bool low_prio, int short_hand,
unsigned long *deliver_bitmask)
{
- int i;
+ int i, lowest = -1;
struct kvm_vcpu *vcpu;
if (dest_mode == 0 && dest_id == 0xff && low_prio)
@@ -64,15 +64,18 @@ void kvm_get_intr_delivery_bitmask(struct kvm *kvm, struct kvm_lapic *src,
dest_mode))
continue;
- __set_bit(i, deliver_bitmask);
+ if (!low_prio) {
+ __set_bit(i, deliver_bitmask);
+ } else {
+ if (lowest < 0)
+ lowest = i;
+ if (kvm_apic_compare_prio(vcpu, kvm->vcpus[lowest]) < 0)
+ lowest = i;
+ }
}
- if (low_prio) {
- vcpu = kvm_get_lowest_prio_vcpu(kvm, 0, deliver_bitmask);
- bitmap_zero(deliver_bitmask, KVM_MAX_VCPUS);
- if (vcpu)
- __set_bit(vcpu->vcpu_id, deliver_bitmask);
- }
+ if (lowest != -1)
+ __set_bit(lowest, deliver_bitmask);
}
static int kvm_set_msi(struct kvm_kernel_irq_routing_entry *e,
--
1.6.0.6
^ permalink raw reply [flat|nested] 44+ messages in thread* [PATCH 24/43] KVM: APIC: get rid of deliver_bitmask
2009-05-18 9:22 [PATCH 00/43] KVM updates for the 2.6.31 merge window (batch 1/4) Avi Kivity
` (22 preceding siblings ...)
2009-05-18 9:22 ` [PATCH 23/43] KVM: change the way how lowest priority vcpu is calculated Avi Kivity
@ 2009-05-18 9:22 ` Avi Kivity
2009-05-18 9:22 ` [PATCH 25/43] KVM: ia64: Map in SN2 RTC registers to the VMM module Avi Kivity
` (18 subsequent siblings)
42 siblings, 0 replies; 44+ messages in thread
From: Avi Kivity @ 2009-05-18 9:22 UTC (permalink / raw)
To: linux-kernel; +Cc: kvm
From: Gleb Natapov <gleb@redhat.com>
Deliver interrupt during destination matching loop.
Signed-off-by: Gleb Natapov <gleb@redhat.com>
Acked-by: Xiantao Zhang <xiantao.zhang@intel.com>
Signed-off-by: Marcelo Tosatti <mtosatti@redhat.com>
---
arch/ia64/kvm/kvm-ia64.c | 33 ++++++++++++---------
arch/ia64/kvm/lapic.h | 4 +-
arch/x86/kvm/lapic.c | 59 ++++++++++---------------------------
arch/x86/kvm/lapic.h | 3 +-
include/linux/kvm_types.h | 10 ++++++
virt/kvm/ioapic.c | 57 ++++++++++--------------------------
virt/kvm/ioapic.h | 6 +--
virt/kvm/irq_comm.c | 71 ++++++++++++++++++++++++++------------------
8 files changed, 108 insertions(+), 135 deletions(-)
diff --git a/arch/ia64/kvm/kvm-ia64.c b/arch/ia64/kvm/kvm-ia64.c
index 1887a93..acf43ec 100644
--- a/arch/ia64/kvm/kvm-ia64.c
+++ b/arch/ia64/kvm/kvm-ia64.c
@@ -283,6 +283,18 @@ static int handle_sal_call(struct kvm_vcpu *vcpu, struct kvm_run *kvm_run)
}
+static int __apic_accept_irq(struct kvm_vcpu *vcpu, uint64_t vector)
+{
+ struct vpd *vpd = to_host(vcpu->kvm, vcpu->arch.vpd);
+
+ if (!test_and_set_bit(vector, &vpd->irr[0])) {
+ vcpu->arch.irq_new_pending = 1;
+ kvm_vcpu_kick(vcpu);
+ return 1;
+ }
+ return 0;
+}
+
/*
* offset: address offset to IPI space.
* value: deliver value.
@@ -292,20 +304,20 @@ static void vcpu_deliver_ipi(struct kvm_vcpu *vcpu, uint64_t dm,
{
switch (dm) {
case SAPIC_FIXED:
- kvm_apic_set_irq(vcpu, vector, dm, 0);
break;
case SAPIC_NMI:
- kvm_apic_set_irq(vcpu, 2, dm, 0);
+ vector = 2;
break;
case SAPIC_EXTINT:
- kvm_apic_set_irq(vcpu, 0, dm, 0);
+ vector = 0;
break;
case SAPIC_INIT:
case SAPIC_PMI:
default:
printk(KERN_ERR"kvm: Unimplemented Deliver reserved IPI!\n");
- break;
+ return;
}
+ __apic_accept_irq(vcpu, vector);
}
static struct kvm_vcpu *lid_to_vcpu(struct kvm *kvm, unsigned long id,
@@ -1813,17 +1825,9 @@ void kvm_vcpu_kick(struct kvm_vcpu *vcpu)
put_cpu();
}
-int kvm_apic_set_irq(struct kvm_vcpu *vcpu, u8 vec, u8 dmode, u8 trig)
+int kvm_apic_set_irq(struct kvm_vcpu *vcpu, struct kvm_lapic_irq *irq)
{
-
- struct vpd *vpd = to_host(vcpu->kvm, vcpu->arch.vpd);
-
- if (!test_and_set_bit(vec, &vpd->irr[0])) {
- vcpu->arch.irq_new_pending = 1;
- kvm_vcpu_kick(vcpu);
- return 1;
- }
- return 0;
+ return __apic_accept_irq(vcpu, irq->vector);
}
int kvm_apic_match_physical_addr(struct kvm_lapic *apic, u16 dest)
@@ -1844,6 +1848,7 @@ int kvm_apic_compare_prio(struct kvm_vcpu *vcpu1, struct kvm_vcpu *vcpu2)
int kvm_apic_match_dest(struct kvm_vcpu *vcpu, struct kvm_lapic *source,
int short_hand, int dest, int dest_mode)
{
+ struct kvm_lapic *target = vcpu->arch.apic;
return (dest_mode == 0) ?
kvm_apic_match_physical_addr(target, dest) :
kvm_apic_match_logical_addr(target, dest);
diff --git a/arch/ia64/kvm/lapic.h b/arch/ia64/kvm/lapic.h
index e42109e..ee541ce 100644
--- a/arch/ia64/kvm/lapic.h
+++ b/arch/ia64/kvm/lapic.h
@@ -23,7 +23,7 @@ int kvm_apic_match_logical_addr(struct kvm_lapic *apic, u8 mda);
int kvm_apic_match_dest(struct kvm_vcpu *vcpu, struct kvm_lapic *source,
int short_hand, int dest, int dest_mode);
int kvm_apic_compare_prio(struct kvm_vcpu *vcpu1, struct kvm_vcpu *vcpu2);
-bool kvm_apic_present(struct kvm_vcpu *vcpu);
-int kvm_apic_set_irq(struct kvm_vcpu *vcpu, u8 vec, u8 dmode, u8 trig);
+int kvm_apic_set_irq(struct kvm_vcpu *vcpu, struct kvm_lapic_irq *irq);
+#define kvm_apic_present(x) (true)
#endif
diff --git a/arch/x86/kvm/lapic.c b/arch/x86/kvm/lapic.c
index 814466f..dd934d2 100644
--- a/arch/x86/kvm/lapic.c
+++ b/arch/x86/kvm/lapic.c
@@ -199,27 +199,12 @@ EXPORT_SYMBOL_GPL(kvm_lapic_find_highest_irr);
static int __apic_accept_irq(struct kvm_lapic *apic, int delivery_mode,
int vector, int level, int trig_mode);
-int kvm_apic_set_irq(struct kvm_vcpu *vcpu, u8 vec, u8 dmode, u8 trig)
+int kvm_apic_set_irq(struct kvm_vcpu *vcpu, struct kvm_lapic_irq *irq)
{
struct kvm_lapic *apic = vcpu->arch.apic;
- int lapic_dmode;
- switch (dmode) {
- case IOAPIC_LOWEST_PRIORITY:
- lapic_dmode = APIC_DM_LOWEST;
- break;
- case IOAPIC_FIXED:
- lapic_dmode = APIC_DM_FIXED;
- break;
- case IOAPIC_NMI:
- lapic_dmode = APIC_DM_NMI;
- break;
- default:
- printk(KERN_DEBUG"Ignoring delivery mode %d\n", dmode);
- return 0;
- break;
- }
- return __apic_accept_irq(apic, lapic_dmode, vec, 1, trig);
+ return __apic_accept_irq(apic, irq->delivery_mode, irq->vector,
+ irq->level, irq->trig_mode);
}
static inline int apic_find_highest_isr(struct kvm_lapic *apic)
@@ -447,36 +432,24 @@ static void apic_send_ipi(struct kvm_lapic *apic)
{
u32 icr_low = apic_get_reg(apic, APIC_ICR);
u32 icr_high = apic_get_reg(apic, APIC_ICR2);
+ struct kvm_lapic_irq irq;
- unsigned int dest = GET_APIC_DEST_FIELD(icr_high);
- unsigned int short_hand = icr_low & APIC_SHORT_MASK;
- unsigned int trig_mode = icr_low & APIC_INT_LEVELTRIG;
- unsigned int level = icr_low & APIC_INT_ASSERT;
- unsigned int dest_mode = icr_low & APIC_DEST_MASK;
- unsigned int delivery_mode = icr_low & APIC_MODE_MASK;
- unsigned int vector = icr_low & APIC_VECTOR_MASK;
-
- DECLARE_BITMAP(deliver_bitmask, KVM_MAX_VCPUS);
- int i;
+ irq.vector = icr_low & APIC_VECTOR_MASK;
+ irq.delivery_mode = icr_low & APIC_MODE_MASK;
+ irq.dest_mode = icr_low & APIC_DEST_MASK;
+ irq.level = icr_low & APIC_INT_ASSERT;
+ irq.trig_mode = icr_low & APIC_INT_LEVELTRIG;
+ irq.shorthand = icr_low & APIC_SHORT_MASK;
+ irq.dest_id = GET_APIC_DEST_FIELD(icr_high);
apic_debug("icr_high 0x%x, icr_low 0x%x, "
"short_hand 0x%x, dest 0x%x, trig_mode 0x%x, level 0x%x, "
"dest_mode 0x%x, delivery_mode 0x%x, vector 0x%x\n",
- icr_high, icr_low, short_hand, dest,
- trig_mode, level, dest_mode, delivery_mode, vector);
-
- kvm_get_intr_delivery_bitmask(apic->vcpu->kvm, apic, dest, dest_mode,
- delivery_mode == APIC_DM_LOWEST, short_hand,
- deliver_bitmask);
-
- while ((i = find_first_bit(deliver_bitmask, KVM_MAX_VCPUS))
- < KVM_MAX_VCPUS) {
- struct kvm_vcpu *vcpu = apic->vcpu->kvm->vcpus[i];
- __clear_bit(i, deliver_bitmask);
- if (vcpu)
- __apic_accept_irq(vcpu->arch.apic, delivery_mode,
- vector, level, trig_mode);
- }
+ icr_high, icr_low, irq.shorthand, irq.dest,
+ irq.trig_mode, irq.level, irq.dest_mode, irq.delivery_mode,
+ irq.vector);
+
+ kvm_irq_delivery_to_apic(apic->vcpu->kvm, apic, &irq);
}
static u32 apic_get_tmcct(struct kvm_lapic *apic)
diff --git a/arch/x86/kvm/lapic.h b/arch/x86/kvm/lapic.h
index b66dc14..a587f83 100644
--- a/arch/x86/kvm/lapic.h
+++ b/arch/x86/kvm/lapic.h
@@ -31,14 +31,13 @@ u64 kvm_lapic_get_base(struct kvm_vcpu *vcpu);
int kvm_apic_match_physical_addr(struct kvm_lapic *apic, u16 dest);
int kvm_apic_match_logical_addr(struct kvm_lapic *apic, u8 mda);
-int kvm_apic_set_irq(struct kvm_vcpu *vcpu, u8 vec, u8 dmode, u8 trig);
+int kvm_apic_set_irq(struct kvm_vcpu *vcpu, struct kvm_lapic_irq *irq);
u64 kvm_get_apic_base(struct kvm_vcpu *vcpu);
void kvm_set_apic_base(struct kvm_vcpu *vcpu, u64 data);
void kvm_apic_post_state_restore(struct kvm_vcpu *vcpu);
int kvm_lapic_enabled(struct kvm_vcpu *vcpu);
bool kvm_apic_present(struct kvm_vcpu *vcpu);
-bool kvm_lapic_present(struct kvm_vcpu *vcpu);
int kvm_lapic_find_highest_irr(struct kvm_vcpu *vcpu);
void kvm_lapic_set_vapic_addr(struct kvm_vcpu *vcpu, gpa_t vapic_addr);
diff --git a/include/linux/kvm_types.h b/include/linux/kvm_types.h
index b84aca3..fb46efb 100644
--- a/include/linux/kvm_types.h
+++ b/include/linux/kvm_types.h
@@ -57,4 +57,14 @@ union kvm_ioapic_redirect_entry {
} fields;
};
+struct kvm_lapic_irq {
+ u32 vector;
+ u32 delivery_mode;
+ u32 dest_mode;
+ u32 level;
+ u32 trig_mode;
+ u32 shorthand;
+ u32 dest_id;
+};
+
#endif /* __KVM_TYPES_H__ */
diff --git a/virt/kvm/ioapic.c b/virt/kvm/ioapic.c
index 43969bb..1eddae9 100644
--- a/virt/kvm/ioapic.c
+++ b/virt/kvm/ioapic.c
@@ -142,58 +142,33 @@ static void ioapic_write_indirect(struct kvm_ioapic *ioapic, u32 val)
}
}
-int ioapic_deliver_entry(struct kvm *kvm, union kvm_ioapic_redirect_entry *e)
-{
- DECLARE_BITMAP(deliver_bitmask, KVM_MAX_VCPUS);
- int i, r = -1;
-
- kvm_get_intr_delivery_bitmask(kvm, NULL, e->fields.dest_id,
- e->fields.dest_mode,
- e->fields.delivery_mode == IOAPIC_LOWEST_PRIORITY,
- 0, deliver_bitmask);
-
- if (find_first_bit(deliver_bitmask, KVM_MAX_VCPUS) >= KVM_MAX_VCPUS) {
- ioapic_debug("no target on destination\n");
- return r;
- }
-
- while ((i = find_first_bit(deliver_bitmask, KVM_MAX_VCPUS))
- < KVM_MAX_VCPUS) {
- struct kvm_vcpu *vcpu = kvm->vcpus[i];
- __clear_bit(i, deliver_bitmask);
- if (vcpu) {
- if (r < 0)
- r = 0;
- r += kvm_apic_set_irq(vcpu, e->fields.vector,
- e->fields.delivery_mode,
- e->fields.trig_mode);
- } else
- ioapic_debug("null destination vcpu: "
- "mask=%x vector=%x delivery_mode=%x\n",
- e->fields.deliver_bitmask,
- e->fields.vector, e->fields.delivery_mode);
- }
- return r;
-}
-
static int ioapic_deliver(struct kvm_ioapic *ioapic, int irq)
{
- union kvm_ioapic_redirect_entry entry = ioapic->redirtbl[irq];
+ union kvm_ioapic_redirect_entry *entry = &ioapic->redirtbl[irq];
+ struct kvm_lapic_irq irqe;
ioapic_debug("dest=%x dest_mode=%x delivery_mode=%x "
"vector=%x trig_mode=%x\n",
- entry.fields.dest, entry.fields.dest_mode,
- entry.fields.delivery_mode, entry.fields.vector,
- entry.fields.trig_mode);
+ entry->fields.dest, entry->fields.dest_mode,
+ entry->fields.delivery_mode, entry->fields.vector,
+ entry->fields.trig_mode);
+
+ irqe.dest_id = entry->fields.dest_id;
+ irqe.vector = entry->fields.vector;
+ irqe.dest_mode = entry->fields.dest_mode;
+ irqe.trig_mode = entry->fields.trig_mode;
+ irqe.delivery_mode = entry->fields.delivery_mode << 8;
+ irqe.level = 1;
+ irqe.shorthand = 0;
#ifdef CONFIG_X86
/* Always delivery PIT interrupt to vcpu 0 */
if (irq == 0) {
- entry.fields.dest_mode = 0; /* Physical mode. */
- entry.fields.dest_id = ioapic->kvm->vcpus[0]->vcpu_id;
+ irqe.dest_mode = 0; /* Physical mode. */
+ irqe.dest_id = ioapic->kvm->vcpus[0]->vcpu_id;
}
#endif
- return ioapic_deliver_entry(ioapic->kvm, &entry);
+ return kvm_irq_delivery_to_apic(ioapic->kvm, NULL, &irqe);
}
int kvm_ioapic_set_irq(struct kvm_ioapic *ioapic, int irq, int level)
diff --git a/virt/kvm/ioapic.h b/virt/kvm/ioapic.h
index e7bc92d..7080b71 100644
--- a/virt/kvm/ioapic.h
+++ b/virt/kvm/ioapic.h
@@ -71,8 +71,6 @@ void kvm_ioapic_update_eoi(struct kvm *kvm, int vector, int trigger_mode);
int kvm_ioapic_init(struct kvm *kvm);
int kvm_ioapic_set_irq(struct kvm_ioapic *ioapic, int irq, int level);
void kvm_ioapic_reset(struct kvm_ioapic *ioapic);
-void kvm_get_intr_delivery_bitmask(struct kvm *kvm, struct kvm_lapic *src,
- int dest_id, int dest_mode, bool low_prio, int short_hand,
- unsigned long *deliver_bitmask);
-int ioapic_deliver_entry(struct kvm *kvm, union kvm_ioapic_redirect_entry *e);
+int kvm_irq_delivery_to_apic(struct kvm *kvm, struct kvm_lapic *src,
+ struct kvm_lapic_irq *irq);
#endif
diff --git a/virt/kvm/irq_comm.c b/virt/kvm/irq_comm.c
index f5e059b..4fa1f60 100644
--- a/virt/kvm/irq_comm.c
+++ b/virt/kvm/irq_comm.c
@@ -22,6 +22,9 @@
#include <linux/kvm_host.h>
#include <asm/msidef.h>
+#ifdef CONFIG_IA64
+#include <asm/iosapic.h>
+#endif
#include "irq.h"
@@ -43,61 +46,71 @@ static int kvm_set_ioapic_irq(struct kvm_kernel_irq_routing_entry *e,
return kvm_ioapic_set_irq(kvm->arch.vioapic, e->irqchip.pin, level);
}
-void kvm_get_intr_delivery_bitmask(struct kvm *kvm, struct kvm_lapic *src,
- int dest_id, int dest_mode, bool low_prio, int short_hand,
- unsigned long *deliver_bitmask)
+inline static bool kvm_is_dm_lowest_prio(struct kvm_lapic_irq *irq)
{
- int i, lowest = -1;
- struct kvm_vcpu *vcpu;
+#ifdef CONFIG_IA64
+ return irq->delivery_mode ==
+ (IOSAPIC_LOWEST_PRIORITY << IOSAPIC_DELIVERY_SHIFT);
+#else
+ return irq->delivery_mode == APIC_DM_LOWEST;
+#endif
+}
- if (dest_mode == 0 && dest_id == 0xff && low_prio)
+int kvm_irq_delivery_to_apic(struct kvm *kvm, struct kvm_lapic *src,
+ struct kvm_lapic_irq *irq)
+{
+ int i, r = -1;
+ struct kvm_vcpu *vcpu, *lowest = NULL;
+
+ if (irq->dest_mode == 0 && irq->dest_id == 0xff &&
+ kvm_is_dm_lowest_prio(irq))
printk(KERN_INFO "kvm: apic: phys broadcast and lowest prio\n");
- bitmap_zero(deliver_bitmask, KVM_MAX_VCPUS);
for (i = 0; i < KVM_MAX_VCPUS; i++) {
vcpu = kvm->vcpus[i];
if (!vcpu || !kvm_apic_present(vcpu))
continue;
- if (!kvm_apic_match_dest(vcpu, src, short_hand, dest_id,
- dest_mode))
+ if (!kvm_apic_match_dest(vcpu, src, irq->shorthand,
+ irq->dest_id, irq->dest_mode))
continue;
- if (!low_prio) {
- __set_bit(i, deliver_bitmask);
+ if (!kvm_is_dm_lowest_prio(irq)) {
+ if (r < 0)
+ r = 0;
+ r += kvm_apic_set_irq(vcpu, irq);
} else {
- if (lowest < 0)
- lowest = i;
- if (kvm_apic_compare_prio(vcpu, kvm->vcpus[lowest]) < 0)
- lowest = i;
+ if (!lowest)
+ lowest = vcpu;
+ else if (kvm_apic_compare_prio(vcpu, lowest) < 0)
+ lowest = vcpu;
}
}
- if (lowest != -1)
- __set_bit(lowest, deliver_bitmask);
+ if (lowest)
+ r = kvm_apic_set_irq(lowest, irq);
+
+ return r;
}
static int kvm_set_msi(struct kvm_kernel_irq_routing_entry *e,
struct kvm *kvm, int level)
{
- union kvm_ioapic_redirect_entry entry;
+ struct kvm_lapic_irq irq;
- entry.bits = 0;
- entry.fields.dest_id = (e->msi.address_lo &
+ irq.dest_id = (e->msi.address_lo &
MSI_ADDR_DEST_ID_MASK) >> MSI_ADDR_DEST_ID_SHIFT;
- entry.fields.vector = (e->msi.data &
+ irq.vector = (e->msi.data &
MSI_DATA_VECTOR_MASK) >> MSI_DATA_VECTOR_SHIFT;
- entry.fields.dest_mode = test_bit(MSI_ADDR_DEST_MODE_SHIFT,
- (unsigned long *)&e->msi.address_lo);
- entry.fields.trig_mode = test_bit(MSI_DATA_TRIGGER_SHIFT,
- (unsigned long *)&e->msi.data);
- entry.fields.delivery_mode = test_bit(
- MSI_DATA_DELIVERY_MODE_SHIFT,
- (unsigned long *)&e->msi.data);
+ irq.dest_mode = (1 << MSI_ADDR_DEST_MODE_SHIFT) & e->msi.address_lo;
+ irq.trig_mode = (1 << MSI_DATA_TRIGGER_SHIFT) & e->msi.data;
+ irq.delivery_mode = e->msi.data & 0x700;
+ irq.level = 1;
+ irq.shorthand = 0;
/* TODO Deal with RH bit of MSI message address */
- return ioapic_deliver_entry(kvm, &entry);
+ return kvm_irq_delivery_to_apic(kvm, NULL, &irq);
}
/* This should be called with the kvm->lock mutex held
--
1.6.0.6
^ permalink raw reply [flat|nested] 44+ messages in thread* [PATCH 25/43] KVM: ia64: Map in SN2 RTC registers to the VMM module
2009-05-18 9:22 [PATCH 00/43] KVM updates for the 2.6.31 merge window (batch 1/4) Avi Kivity
` (23 preceding siblings ...)
2009-05-18 9:22 ` [PATCH 24/43] KVM: APIC: get rid of deliver_bitmask Avi Kivity
@ 2009-05-18 9:22 ` Avi Kivity
2009-05-18 9:22 ` [PATCH 26/43] KVM: ia64: Create inline function kvm_get_itc() to centralize ITC reading Avi Kivity
` (17 subsequent siblings)
42 siblings, 0 replies; 44+ messages in thread
From: Avi Kivity @ 2009-05-18 9:22 UTC (permalink / raw)
To: linux-kernel; +Cc: kvm
From: Jes Sorensen <jes@sgi.com>
On SN2, map in the SN2 RTC registers to the VMM module, needed for ITC
emulation.
Signed-off-by: Jes Sorensen <jes@sgi.com>
Acked-by: Xiantao Zhang <xiantao.zhang@intel.com>
Signed-off-by: Avi Kivity <avi@redhat.com>
---
arch/ia64/include/asm/kvm_host.h | 2 +
arch/ia64/include/asm/pgtable.h | 2 +
arch/ia64/kvm/kvm-ia64.c | 43 +++++++++++++++++++++++++++++++++----
3 files changed, 42 insertions(+), 5 deletions(-)
diff --git a/arch/ia64/include/asm/kvm_host.h b/arch/ia64/include/asm/kvm_host.h
index 5608488..1243995 100644
--- a/arch/ia64/include/asm/kvm_host.h
+++ b/arch/ia64/include/asm/kvm_host.h
@@ -371,6 +371,7 @@ struct kvm_vcpu_arch {
int last_run_cpu;
int vmm_tr_slot;
int vm_tr_slot;
+ int sn_rtc_tr_slot;
#define KVM_MP_STATE_RUNNABLE 0
#define KVM_MP_STATE_UNINITIALIZED 1
@@ -465,6 +466,7 @@ struct kvm_arch {
unsigned long vmm_init_rr;
int online_vcpus;
+ int is_sn2;
struct kvm_ioapic *vioapic;
struct kvm_vm_stat stat;
diff --git a/arch/ia64/include/asm/pgtable.h b/arch/ia64/include/asm/pgtable.h
index 7a9bff4..0a9cc73 100644
--- a/arch/ia64/include/asm/pgtable.h
+++ b/arch/ia64/include/asm/pgtable.h
@@ -146,6 +146,8 @@
#define PAGE_GATE __pgprot(__ACCESS_BITS | _PAGE_PL_0 | _PAGE_AR_X_RX)
#define PAGE_KERNEL __pgprot(__DIRTY_BITS | _PAGE_PL_0 | _PAGE_AR_RWX)
#define PAGE_KERNELRX __pgprot(__ACCESS_BITS | _PAGE_PL_0 | _PAGE_AR_RX)
+#define PAGE_KERNEL_UC __pgprot(__DIRTY_BITS | _PAGE_PL_0 | _PAGE_AR_RWX | \
+ _PAGE_MA_UC)
# ifndef __ASSEMBLY__
diff --git a/arch/ia64/kvm/kvm-ia64.c b/arch/ia64/kvm/kvm-ia64.c
index acf43ec..14a3fab 100644
--- a/arch/ia64/kvm/kvm-ia64.c
+++ b/arch/ia64/kvm/kvm-ia64.c
@@ -41,6 +41,9 @@
#include <asm/div64.h>
#include <asm/tlb.h>
#include <asm/elf.h>
+#include <asm/sn/addrs.h>
+#include <asm/sn/clksupport.h>
+#include <asm/sn/shub_mmr.h>
#include "misc.h"
#include "vti.h"
@@ -119,8 +122,7 @@ void kvm_arch_hardware_enable(void *garbage)
unsigned long saved_psr;
int slot;
- pte = pte_val(mk_pte_phys(__pa(kvm_vmm_base),
- PAGE_KERNEL));
+ pte = pte_val(mk_pte_phys(__pa(kvm_vmm_base), PAGE_KERNEL));
local_irq_save(saved_psr);
slot = ia64_itr_entry(0x3, KVM_VMM_BASE, pte, KVM_VMM_SHIFT);
local_irq_restore(saved_psr);
@@ -425,6 +427,23 @@ static int handle_switch_rr6(struct kvm_vcpu *vcpu, struct kvm_run *kvm_run)
return 1;
}
+static int kvm_sn2_setup_mappings(struct kvm_vcpu *vcpu)
+{
+ unsigned long pte, rtc_phys_addr, map_addr;
+ int slot;
+
+ map_addr = KVM_VMM_BASE + (1UL << KVM_VMM_SHIFT);
+ rtc_phys_addr = LOCAL_MMR_OFFSET | SH_RTC;
+ pte = pte_val(mk_pte_phys(rtc_phys_addr, PAGE_KERNEL_UC));
+ slot = ia64_itr_entry(0x3, map_addr, pte, PAGE_SHIFT);
+ vcpu->arch.sn_rtc_tr_slot = slot;
+ if (slot < 0) {
+ printk(KERN_ERR "Mayday mayday! RTC mapping failed!\n");
+ slot = 0;
+ }
+ return slot;
+}
+
int kvm_emulate_halt(struct kvm_vcpu *vcpu)
{
@@ -563,18 +582,29 @@ static int kvm_insert_vmm_mapping(struct kvm_vcpu *vcpu)
if (r < 0)
goto out;
vcpu->arch.vm_tr_slot = r;
+
+#if defined(CONFIG_IA64_SGI_SN2) || defined(CONFIG_IA64_GENERIC)
+ if (kvm->arch.is_sn2) {
+ r = kvm_sn2_setup_mappings(vcpu);
+ if (r < 0)
+ goto out;
+ }
+#endif
+
r = 0;
out:
return r;
-
}
static void kvm_purge_vmm_mapping(struct kvm_vcpu *vcpu)
{
-
+ struct kvm *kvm = vcpu->kvm;
ia64_ptr_entry(0x3, vcpu->arch.vmm_tr_slot);
ia64_ptr_entry(0x3, vcpu->arch.vm_tr_slot);
-
+#if defined(CONFIG_IA64_SGI_SN2) || defined(CONFIG_IA64_GENERIC)
+ if (kvm->arch.is_sn2)
+ ia64_ptr_entry(0x3, vcpu->arch.sn_rtc_tr_slot);
+#endif
}
static int kvm_vcpu_pre_transition(struct kvm_vcpu *vcpu)
@@ -800,6 +830,9 @@ struct kvm *kvm_arch_create_vm(void)
if (IS_ERR(kvm))
return ERR_PTR(-ENOMEM);
+
+ kvm->arch.is_sn2 = ia64_platform_is("sn2");
+
kvm_init_vm(kvm);
kvm->arch.online_vcpus = 0;
--
1.6.0.6
^ permalink raw reply [flat|nested] 44+ messages in thread* [PATCH 26/43] KVM: ia64: Create inline function kvm_get_itc() to centralize ITC reading.
2009-05-18 9:22 [PATCH 00/43] KVM updates for the 2.6.31 merge window (batch 1/4) Avi Kivity
` (24 preceding siblings ...)
2009-05-18 9:22 ` [PATCH 25/43] KVM: ia64: Map in SN2 RTC registers to the VMM module Avi Kivity
@ 2009-05-18 9:22 ` Avi Kivity
2009-05-18 9:22 ` [PATCH 27/43] KVM: ia64: SN2 adjust emulated ITC frequency to match RTC frequency Avi Kivity
` (16 subsequent siblings)
42 siblings, 0 replies; 44+ messages in thread
From: Avi Kivity @ 2009-05-18 9:22 UTC (permalink / raw)
To: linux-kernel; +Cc: kvm
From: Jes Sorensen <jes@sgi.com>
Move all reading of special register 'AR_ITC' into two functions, one
in the kernel and one in the VMM module. When running on SN2, base the
result on the RTC rather the system ITC, as the ITC isn't
synchronized.
Signed-off-by: Jes Sorensen <jes@sgi.com>
Acked-by: Xiantao Zhang <xiantao.zhang@intel.com>
Signed-off-by: Avi Kivity <avi@redhat.com>
---
arch/ia64/kvm/kvm-ia64.c | 18 ++++++++++++++----
arch/ia64/kvm/vcpu.c | 20 ++++++++++++++++++--
2 files changed, 32 insertions(+), 6 deletions(-)
diff --git a/arch/ia64/kvm/kvm-ia64.c b/arch/ia64/kvm/kvm-ia64.c
index 14a3fab..ebbd995 100644
--- a/arch/ia64/kvm/kvm-ia64.c
+++ b/arch/ia64/kvm/kvm-ia64.c
@@ -68,6 +68,16 @@ struct kvm_stats_debugfs_item debugfs_entries[] = {
{ NULL }
};
+static unsigned long kvm_get_itc(struct kvm_vcpu *vcpu)
+{
+#if defined(CONFIG_IA64_SGI_SN2) || defined(CONFIG_IA64_GENERIC)
+ if (vcpu->kvm->arch.is_sn2)
+ return rtc_time();
+ else
+#endif
+ return ia64_getreg(_IA64_REG_AR_ITC);
+}
+
static void kvm_flush_icache(unsigned long start, unsigned long len)
{
int l;
@@ -457,7 +467,7 @@ int kvm_emulate_halt(struct kvm_vcpu *vcpu)
if (irqchip_in_kernel(vcpu->kvm)) {
- vcpu_now_itc = ia64_getreg(_IA64_REG_AR_ITC) + vcpu->arch.itc_offset;
+ vcpu_now_itc = kvm_get_itc(vcpu) + vcpu->arch.itc_offset;
if (time_after(vcpu_now_itc, vpd->itm)) {
vcpu->arch.timer_check = 1;
@@ -929,7 +939,7 @@ int kvm_arch_vcpu_ioctl_set_regs(struct kvm_vcpu *vcpu, struct kvm_regs *regs)
RESTORE_REGS(saved_gp);
vcpu->arch.irq_new_pending = 1;
- vcpu->arch.itc_offset = regs->saved_itc - ia64_getreg(_IA64_REG_AR_ITC);
+ vcpu->arch.itc_offset = regs->saved_itc - kvm_get_itc(vcpu);
set_bit(KVM_REQ_RESUME, &vcpu->requests);
vcpu_put(vcpu);
@@ -1210,7 +1220,7 @@ int kvm_arch_vcpu_init(struct kvm_vcpu *vcpu)
regs->cr_iip = PALE_RESET_ENTRY;
/*Initialize itc offset for vcpus*/
- itc_offset = 0UL - ia64_getreg(_IA64_REG_AR_ITC);
+ itc_offset = 0UL - kvm_get_itc(vcpu);
for (i = 0; i < kvm->arch.online_vcpus; i++) {
v = (struct kvm_vcpu *)((char *)vcpu +
sizeof(struct kvm_vcpu_data) * i);
@@ -1472,7 +1482,7 @@ int kvm_arch_vcpu_ioctl_get_regs(struct kvm_vcpu *vcpu, struct kvm_regs *regs)
}
for (i = 0; i < 4; i++)
regs->insvc[i] = vcpu->arch.insvc[i];
- regs->saved_itc = vcpu->arch.itc_offset + ia64_getreg(_IA64_REG_AR_ITC);
+ regs->saved_itc = vcpu->arch.itc_offset + kvm_get_itc(vcpu);
SAVE_REGS(xtp);
SAVE_REGS(metaphysical_rr0);
SAVE_REGS(metaphysical_rr4);
diff --git a/arch/ia64/kvm/vcpu.c b/arch/ia64/kvm/vcpu.c
index a18ee17..a2c6c15 100644
--- a/arch/ia64/kvm/vcpu.c
+++ b/arch/ia64/kvm/vcpu.c
@@ -788,13 +788,29 @@ void vcpu_set_fpreg(struct kvm_vcpu *vcpu, unsigned long reg,
setfpreg(reg, val, regs); /* FIXME: handle NATs later*/
}
+/*
+ * The Altix RTC is mapped specially here for the vmm module
+ */
+#define SN_RTC_BASE (u64 *)(KVM_VMM_BASE+(1UL<<KVM_VMM_SHIFT))
+static long kvm_get_itc(struct kvm_vcpu *vcpu)
+{
+#if defined(CONFIG_IA64_SGI_SN2) || defined(CONFIG_IA64_GENERIC)
+ struct kvm *kvm = (struct kvm *)KVM_VM_BASE;
+
+ if (kvm->arch.is_sn2)
+ return (*SN_RTC_BASE);
+ else
+#endif
+ return ia64_getreg(_IA64_REG_AR_ITC);
+}
+
/************************************************************************
* lsapic timer
***********************************************************************/
u64 vcpu_get_itc(struct kvm_vcpu *vcpu)
{
unsigned long guest_itc;
- guest_itc = VMX(vcpu, itc_offset) + ia64_getreg(_IA64_REG_AR_ITC);
+ guest_itc = VMX(vcpu, itc_offset) + kvm_get_itc(vcpu);
if (guest_itc >= VMX(vcpu, last_itc)) {
VMX(vcpu, last_itc) = guest_itc;
@@ -809,7 +825,7 @@ static void vcpu_set_itc(struct kvm_vcpu *vcpu, u64 val)
struct kvm_vcpu *v;
struct kvm *kvm;
int i;
- long itc_offset = val - ia64_getreg(_IA64_REG_AR_ITC);
+ long itc_offset = val - kvm_get_itc(vcpu);
unsigned long vitv = VCPU(vcpu, itv);
kvm = (struct kvm *)KVM_VM_BASE;
--
1.6.0.6
^ permalink raw reply [flat|nested] 44+ messages in thread* [PATCH 27/43] KVM: ia64: SN2 adjust emulated ITC frequency to match RTC frequency
2009-05-18 9:22 [PATCH 00/43] KVM updates for the 2.6.31 merge window (batch 1/4) Avi Kivity
` (25 preceding siblings ...)
2009-05-18 9:22 ` [PATCH 26/43] KVM: ia64: Create inline function kvm_get_itc() to centralize ITC reading Avi Kivity
@ 2009-05-18 9:22 ` Avi Kivity
2009-05-18 9:22 ` [PATCH 28/43] KVM: ia64: Drop in SN2 replacement of fast path ITC emulation fault handler Avi Kivity
` (15 subsequent siblings)
42 siblings, 0 replies; 44+ messages in thread
From: Avi Kivity @ 2009-05-18 9:22 UTC (permalink / raw)
To: linux-kernel; +Cc: kvm
From: Jes Sorensen <jes@sgi.com>
On SN2 do not pass down the real ITC frequency, but rather patch the
values to match the SN2 RTC frequency.
Signed-off-by: Jes Sorensen <jes@sgi.com>
Acked-by: Xiantao Zhang <xiantao.zhang@intel.com>
Signed-off-by: Avi Kivity <avi@redhat.com>
---
arch/ia64/kvm/kvm_fw.c | 28 +++++++++++++++++++++++++++-
1 files changed, 27 insertions(+), 1 deletions(-)
diff --git a/arch/ia64/kvm/kvm_fw.c b/arch/ia64/kvm/kvm_fw.c
index a8ae52e..e4b8231 100644
--- a/arch/ia64/kvm/kvm_fw.c
+++ b/arch/ia64/kvm/kvm_fw.c
@@ -21,6 +21,9 @@
#include <linux/kvm_host.h>
#include <linux/smp.h>
+#include <asm/sn/addrs.h>
+#include <asm/sn/clksupport.h>
+#include <asm/sn/shub_mmr.h>
#include "vti.h"
#include "misc.h"
@@ -188,12 +191,35 @@ static struct ia64_pal_retval pal_freq_base(struct kvm_vcpu *vcpu)
return result;
}
-static struct ia64_pal_retval pal_freq_ratios(struct kvm_vcpu *vcpu)
+/*
+ * On the SGI SN2, the ITC isn't stable. Emulation backed by the SN2
+ * RTC is used instead. This function patches the ratios from SAL
+ * to match the RTC before providing them to the guest.
+ */
+static void sn2_patch_itc_freq_ratios(struct ia64_pal_retval *result)
{
+ struct pal_freq_ratio *ratio;
+ unsigned long sal_freq, sal_drift, factor;
+
+ result->status = ia64_sal_freq_base(SAL_FREQ_BASE_PLATFORM,
+ &sal_freq, &sal_drift);
+ ratio = (struct pal_freq_ratio *)&result->v2;
+ factor = ((sal_freq * 3) + (sn_rtc_cycles_per_second / 2)) /
+ sn_rtc_cycles_per_second;
+
+ ratio->num = 3;
+ ratio->den = factor;
+}
+static struct ia64_pal_retval pal_freq_ratios(struct kvm_vcpu *vcpu)
+{
struct ia64_pal_retval result;
PAL_CALL(result, PAL_FREQ_RATIOS, 0, 0, 0);
+
+ if (vcpu->kvm->arch.is_sn2)
+ sn2_patch_itc_freq_ratios(&result);
+
return result;
}
--
1.6.0.6
^ permalink raw reply [flat|nested] 44+ messages in thread* [PATCH 28/43] KVM: ia64: Drop in SN2 replacement of fast path ITC emulation fault handler
2009-05-18 9:22 [PATCH 00/43] KVM updates for the 2.6.31 merge window (batch 1/4) Avi Kivity
` (26 preceding siblings ...)
2009-05-18 9:22 ` [PATCH 27/43] KVM: ia64: SN2 adjust emulated ITC frequency to match RTC frequency Avi Kivity
@ 2009-05-18 9:22 ` Avi Kivity
2009-05-18 9:22 ` [PATCH 29/43] KVM: make 'lapic_timer_ops' and 'kpit_ops' static Avi Kivity
` (14 subsequent siblings)
42 siblings, 0 replies; 44+ messages in thread
From: Avi Kivity @ 2009-05-18 9:22 UTC (permalink / raw)
To: linux-kernel; +Cc: kvm
From: Jes Sorensen <jes@sgi.com>
Copy in SN2 RTC based ITC emulation for fast exit. The two versions
have the same size, so a dropin is simpler than patching the branch
instruction to hit the SN2 version.
Signed-off-by: Jes Sorensen <jes@sgi.com>
Acked-by: Xiantao Zhang <xiantao.zhang@intel.com>
Signed-off-by: Avi Kivity <avi@redhat.com>
---
arch/ia64/include/asm/kvm_host.h | 2 ++
arch/ia64/kvm/kvm-ia64.c | 32 +++++++++++++++++++++++++++++++-
arch/ia64/kvm/optvfault.S | 30 ++++++++++++++++++++++++++++++
arch/ia64/kvm/vmm.c | 12 ++++++++----
4 files changed, 71 insertions(+), 5 deletions(-)
diff --git a/arch/ia64/include/asm/kvm_host.h b/arch/ia64/include/asm/kvm_host.h
index 1243995..589536f 100644
--- a/arch/ia64/include/asm/kvm_host.h
+++ b/arch/ia64/include/asm/kvm_host.h
@@ -580,6 +580,8 @@ struct kvm_vmm_info{
kvm_vmm_entry *vmm_entry;
kvm_tramp_entry *tramp_entry;
unsigned long vmm_ivt;
+ unsigned long patch_mov_ar;
+ unsigned long patch_mov_ar_sn2;
};
int kvm_highest_pending_irq(struct kvm_vcpu *vcpu);
diff --git a/arch/ia64/kvm/kvm-ia64.c b/arch/ia64/kvm/kvm-ia64.c
index ebbd995..4623a90 100644
--- a/arch/ia64/kvm/kvm-ia64.c
+++ b/arch/ia64/kvm/kvm-ia64.c
@@ -1671,8 +1671,37 @@ out:
return 0;
}
+
+/*
+ * On SN2, the ITC isn't stable, so copy in fast path code to use the
+ * SN2 RTC, replacing the ITC based default verion.
+ */
+static void kvm_patch_vmm(struct kvm_vmm_info *vmm_info,
+ struct module *module)
+{
+ unsigned long new_ar, new_ar_sn2;
+ unsigned long module_base;
+
+ if (!ia64_platform_is("sn2"))
+ return;
+
+ module_base = (unsigned long)module->module_core;
+
+ new_ar = kvm_vmm_base + vmm_info->patch_mov_ar - module_base;
+ new_ar_sn2 = kvm_vmm_base + vmm_info->patch_mov_ar_sn2 - module_base;
+
+ printk(KERN_INFO "kvm: Patching ITC emulation to use SGI SN2 RTC "
+ "as source\n");
+
+ /*
+ * Copy the SN2 version of mov_ar into place. They are both
+ * the same size, so 6 bundles is sufficient (6 * 0x10).
+ */
+ memcpy((void *)new_ar, (void *)new_ar_sn2, 0x60);
+}
+
static int kvm_relocate_vmm(struct kvm_vmm_info *vmm_info,
- struct module *module)
+ struct module *module)
{
unsigned long module_base;
unsigned long vmm_size;
@@ -1694,6 +1723,7 @@ static int kvm_relocate_vmm(struct kvm_vmm_info *vmm_info,
return -EFAULT;
memcpy((void *)kvm_vmm_base, (void *)module_base, vmm_size);
+ kvm_patch_vmm(vmm_info, module);
kvm_flush_icache(kvm_vmm_base, vmm_size);
/*Recalculate kvm_vmm_info based on new VMM*/
diff --git a/arch/ia64/kvm/optvfault.S b/arch/ia64/kvm/optvfault.S
index 32254ce..f793be3 100644
--- a/arch/ia64/kvm/optvfault.S
+++ b/arch/ia64/kvm/optvfault.S
@@ -11,6 +11,7 @@
#include <asm/asmmacro.h>
#include <asm/processor.h>
+#include <asm/kvm_host.h>
#include "vti.h"
#include "asm-offsets.h"
@@ -140,6 +141,35 @@ GLOBAL_ENTRY(kvm_asm_mov_from_ar)
;;
END(kvm_asm_mov_from_ar)
+/*
+ * Special SGI SN2 optimized version of mov_from_ar using the SN2 RTC
+ * clock as it's source for emulating the ITC. This version will be
+ * copied on top of the original version if the host is determined to
+ * be an SN2.
+ */
+GLOBAL_ENTRY(kvm_asm_mov_from_ar_sn2)
+ add r18=VMM_VCPU_ITC_OFS_OFFSET, r21
+ movl r19 = (KVM_VMM_BASE+(1<<KVM_VMM_SHIFT))
+
+ add r16=VMM_VCPU_LAST_ITC_OFFSET,r21
+ extr.u r17=r25,6,7
+ mov r24=b0
+ ;;
+ ld8 r18=[r18]
+ ld8 r19=[r19]
+ addl r20=@gprel(asm_mov_to_reg),gp
+ ;;
+ add r19=r19,r18
+ shladd r17=r17,4,r20
+ ;;
+ adds r30=kvm_resume_to_guest-asm_mov_to_reg,r20
+ st8 [r16] = r19
+ mov b0=r17
+ br.sptk.few b0
+ ;;
+END(kvm_asm_mov_from_ar_sn2)
+
+
// mov r1=rr[r3]
GLOBAL_ENTRY(kvm_asm_mov_from_rr)
diff --git a/arch/ia64/kvm/vmm.c b/arch/ia64/kvm/vmm.c
index 9eee5c0..f4b4c89 100644
--- a/arch/ia64/kvm/vmm.c
+++ b/arch/ia64/kvm/vmm.c
@@ -30,15 +30,19 @@ MODULE_AUTHOR("Intel");
MODULE_LICENSE("GPL");
extern char kvm_ia64_ivt;
+extern char kvm_asm_mov_from_ar;
+extern char kvm_asm_mov_from_ar_sn2;
extern fpswa_interface_t *vmm_fpswa_interface;
long vmm_sanity = 1;
struct kvm_vmm_info vmm_info = {
- .module = THIS_MODULE,
- .vmm_entry = vmm_entry,
- .tramp_entry = vmm_trampoline,
- .vmm_ivt = (unsigned long)&kvm_ia64_ivt,
+ .module = THIS_MODULE,
+ .vmm_entry = vmm_entry,
+ .tramp_entry = vmm_trampoline,
+ .vmm_ivt = (unsigned long)&kvm_ia64_ivt,
+ .patch_mov_ar = (unsigned long)&kvm_asm_mov_from_ar,
+ .patch_mov_ar_sn2 = (unsigned long)&kvm_asm_mov_from_ar_sn2,
};
static int __init kvm_vmm_init(void)
--
1.6.0.6
^ permalink raw reply [flat|nested] 44+ messages in thread* [PATCH 29/43] KVM: make 'lapic_timer_ops' and 'kpit_ops' static
2009-05-18 9:22 [PATCH 00/43] KVM updates for the 2.6.31 merge window (batch 1/4) Avi Kivity
` (27 preceding siblings ...)
2009-05-18 9:22 ` [PATCH 28/43] KVM: ia64: Drop in SN2 replacement of fast path ITC emulation fault handler Avi Kivity
@ 2009-05-18 9:22 ` Avi Kivity
2009-05-18 9:22 ` [PATCH 30/43] KVM: Device assignment framework rework Avi Kivity
` (13 subsequent siblings)
42 siblings, 0 replies; 44+ messages in thread
From: Avi Kivity @ 2009-05-18 9:22 UTC (permalink / raw)
To: linux-kernel; +Cc: kvm
From: Hannes Eder <hannes@hanneseder.net>
Fix this sparse warnings:
arch/x86/kvm/lapic.c:916:22: warning: symbol 'lapic_timer_ops' was not declared. Should it be static?
arch/x86/kvm/i8254.c:268:22: warning: symbol 'kpit_ops' was not declared. Should it be static?
Signed-off-by: Hannes Eder <hannes@hanneseder.net>
Signed-off-by: Avi Kivity <avi@redhat.com>
---
arch/x86/kvm/i8254.c | 2 +-
arch/x86/kvm/lapic.c | 2 +-
2 files changed, 2 insertions(+), 2 deletions(-)
diff --git a/arch/x86/kvm/i8254.c b/arch/x86/kvm/i8254.c
index 4e2e3f2..cf09bb6 100644
--- a/arch/x86/kvm/i8254.c
+++ b/arch/x86/kvm/i8254.c
@@ -265,7 +265,7 @@ static bool kpit_is_periodic(struct kvm_timer *ktimer)
return ps->is_periodic;
}
-struct kvm_timer_ops kpit_ops = {
+static struct kvm_timer_ops kpit_ops = {
.is_periodic = kpit_is_periodic,
};
diff --git a/arch/x86/kvm/lapic.c b/arch/x86/kvm/lapic.c
index dd934d2..4d76bb6 100644
--- a/arch/x86/kvm/lapic.c
+++ b/arch/x86/kvm/lapic.c
@@ -913,7 +913,7 @@ void kvm_apic_nmi_wd_deliver(struct kvm_vcpu *vcpu)
kvm_apic_local_deliver(apic, APIC_LVT0);
}
-struct kvm_timer_ops lapic_timer_ops = {
+static struct kvm_timer_ops lapic_timer_ops = {
.is_periodic = lapic_is_periodic,
};
--
1.6.0.6
^ permalink raw reply [flat|nested] 44+ messages in thread* [PATCH 30/43] KVM: Device assignment framework rework
2009-05-18 9:22 [PATCH 00/43] KVM updates for the 2.6.31 merge window (batch 1/4) Avi Kivity
` (28 preceding siblings ...)
2009-05-18 9:22 ` [PATCH 29/43] KVM: make 'lapic_timer_ops' and 'kpit_ops' static Avi Kivity
@ 2009-05-18 9:22 ` Avi Kivity
2009-05-18 9:22 ` [PATCH 31/43] KVM: MMU: do not free active mmu pages in free_mmu_pages() Avi Kivity
` (12 subsequent siblings)
42 siblings, 0 replies; 44+ messages in thread
From: Avi Kivity @ 2009-05-18 9:22 UTC (permalink / raw)
To: linux-kernel; +Cc: kvm
From: Sheng Yang <sheng@linux.intel.com>
After discussion with Marcelo, we decided to rework device assignment framework
together. The old problems are kernel logic is unnecessary complex. So Marcelo
suggest to split it into a more elegant way:
1. Split host IRQ assign and guest IRQ assign. And userspace determine the
combination. Also discard msi2intx parameter, userspace can specific
KVM_DEV_IRQ_HOST_MSI | KVM_DEV_IRQ_GUEST_INTX in assigned_irq->flags to
enable MSI to INTx convertion.
2. Split assign IRQ and deassign IRQ. Import two new ioctls:
KVM_ASSIGN_DEV_IRQ and KVM_DEASSIGN_DEV_IRQ.
This patch also fixed the reversed _IOR vs _IOW in definition(by deprecated the
old interface).
[avi: replace homemade bitcount() by hweight_long()]
Signed-off-by: Marcelo Tosatti <mtosatti@redhat.com>
Signed-off-by: Sheng Yang <sheng@linux.intel.com>
Signed-off-by: Avi Kivity <avi@redhat.com>
---
arch/x86/kvm/x86.c | 1 +
include/linux/kvm.h | 26 ++-
include/linux/kvm_host.h | 5 -
virt/kvm/kvm_main.c | 486 ++++++++++++++++++++++++----------------------
4 files changed, 276 insertions(+), 242 deletions(-)
diff --git a/arch/x86/kvm/x86.c b/arch/x86/kvm/x86.c
index cac6e63..a27a64c 100644
--- a/arch/x86/kvm/x86.c
+++ b/arch/x86/kvm/x86.c
@@ -1022,6 +1022,7 @@ int kvm_dev_ioctl_check_extension(long ext)
case KVM_CAP_SYNC_MMU:
case KVM_CAP_REINJECT_CONTROL:
case KVM_CAP_IRQ_INJECT_STATUS:
+ case KVM_CAP_ASSIGN_DEV_IRQ:
r = 1;
break;
case KVM_CAP_COALESCED_MMIO:
diff --git a/include/linux/kvm.h b/include/linux/kvm.h
index 640835e..644e3a9 100644
--- a/include/linux/kvm.h
+++ b/include/linux/kvm.h
@@ -412,6 +412,7 @@ struct kvm_trace_rec {
#ifdef __KVM_HAVE_MSIX
#define KVM_CAP_DEVICE_MSIX 28
#endif
+#define KVM_CAP_ASSIGN_DEV_IRQ 29
/* Another bug in KVM_SET_USER_MEMORY_REGION fixed: */
#define KVM_CAP_JOIN_MEMORY_REGIONS_WORKS 30
@@ -485,8 +486,10 @@ struct kvm_irq_routing {
#define KVM_ASSIGN_PCI_DEVICE _IOR(KVMIO, 0x69, \
struct kvm_assigned_pci_dev)
#define KVM_SET_GSI_ROUTING _IOW(KVMIO, 0x6a, struct kvm_irq_routing)
+/* deprecated, replaced by KVM_ASSIGN_DEV_IRQ */
#define KVM_ASSIGN_IRQ _IOR(KVMIO, 0x70, \
struct kvm_assigned_irq)
+#define KVM_ASSIGN_DEV_IRQ _IOW(KVMIO, 0x70, struct kvm_assigned_irq)
#define KVM_REINJECT_CONTROL _IO(KVMIO, 0x71)
#define KVM_DEASSIGN_PCI_DEVICE _IOW(KVMIO, 0x72, \
struct kvm_assigned_pci_dev)
@@ -494,6 +497,7 @@ struct kvm_irq_routing {
_IOW(KVMIO, 0x73, struct kvm_assigned_msix_nr)
#define KVM_ASSIGN_SET_MSIX_ENTRY \
_IOW(KVMIO, 0x74, struct kvm_assigned_msix_entry)
+#define KVM_DEASSIGN_DEV_IRQ _IOW(KVMIO, 0x75, struct kvm_assigned_irq)
/*
* ioctls for vcpu fds
@@ -584,6 +588,8 @@ struct kvm_debug_guest {
#define KVM_TRC_STLB_INVAL (KVM_TRC_HANDLER + 0x18)
#define KVM_TRC_PPC_INSTR (KVM_TRC_HANDLER + 0x19)
+#define KVM_DEV_ASSIGN_ENABLE_IOMMU (1 << 0)
+
struct kvm_assigned_pci_dev {
__u32 assigned_dev_id;
__u32 busnr;
@@ -594,6 +600,17 @@ struct kvm_assigned_pci_dev {
};
};
+#define KVM_DEV_IRQ_HOST_INTX (1 << 0)
+#define KVM_DEV_IRQ_HOST_MSI (1 << 1)
+#define KVM_DEV_IRQ_HOST_MSIX (1 << 2)
+
+#define KVM_DEV_IRQ_GUEST_INTX (1 << 8)
+#define KVM_DEV_IRQ_GUEST_MSI (1 << 9)
+#define KVM_DEV_IRQ_GUEST_MSIX (1 << 10)
+
+#define KVM_DEV_IRQ_HOST_MASK 0x00ff
+#define KVM_DEV_IRQ_GUEST_MASK 0xff00
+
struct kvm_assigned_irq {
__u32 assigned_dev_id;
__u32 host_irq;
@@ -609,15 +626,6 @@ struct kvm_assigned_irq {
};
};
-#define KVM_DEV_ASSIGN_ENABLE_IOMMU (1 << 0)
-
-#define KVM_DEV_IRQ_ASSIGN_MSI_ACTION KVM_DEV_IRQ_ASSIGN_ENABLE_MSI
-#define KVM_DEV_IRQ_ASSIGN_ENABLE_MSI (1 << 0)
-
-#define KVM_DEV_IRQ_ASSIGN_MSIX_ACTION (KVM_DEV_IRQ_ASSIGN_ENABLE_MSIX |\
- KVM_DEV_IRQ_ASSIGN_MASK_MSIX)
-#define KVM_DEV_IRQ_ASSIGN_ENABLE_MSIX (1 << 1)
-#define KVM_DEV_IRQ_ASSIGN_MASK_MSIX (1 << 2)
struct kvm_assigned_msix_nr {
__u32 assigned_dev_id;
diff --git a/include/linux/kvm_host.h b/include/linux/kvm_host.h
index fb60f31..40e49ed 100644
--- a/include/linux/kvm_host.h
+++ b/include/linux/kvm_host.h
@@ -339,11 +339,6 @@ struct kvm_assigned_dev_kernel {
struct msix_entry *host_msix_entries;
int guest_irq;
struct kvm_guest_msix_entry *guest_msix_entries;
-#define KVM_ASSIGNED_DEV_GUEST_INTX (1 << 0)
-#define KVM_ASSIGNED_DEV_GUEST_MSI (1 << 1)
-#define KVM_ASSIGNED_DEV_HOST_INTX (1 << 8)
-#define KVM_ASSIGNED_DEV_HOST_MSI (1 << 9)
-#define KVM_ASSIGNED_DEV_MSIX ((1 << 2) | (1 << 10))
unsigned long irq_requested_type;
int irq_source_id;
int flags;
diff --git a/virt/kvm/kvm_main.c b/virt/kvm/kvm_main.c
index 034ed43..231ca3c 100644
--- a/virt/kvm/kvm_main.c
+++ b/virt/kvm/kvm_main.c
@@ -41,6 +41,7 @@
#include <linux/pagemap.h>
#include <linux/mman.h>
#include <linux/swap.h>
+#include <linux/bitops.h>
#include <asm/processor.h>
#include <asm/io.h>
@@ -60,9 +61,6 @@
MODULE_AUTHOR("Qumranet");
MODULE_LICENSE("GPL");
-static int msi2intx = 1;
-module_param(msi2intx, bool, 0);
-
DEFINE_SPINLOCK(kvm_lock);
LIST_HEAD(vm_list);
@@ -132,7 +130,7 @@ static void kvm_assigned_dev_interrupt_work_handler(struct work_struct *work)
* finer-grained lock, update this
*/
mutex_lock(&kvm->lock);
- if (assigned_dev->irq_requested_type & KVM_ASSIGNED_DEV_MSIX) {
+ if (assigned_dev->irq_requested_type & KVM_DEV_IRQ_HOST_MSIX) {
struct kvm_guest_msix_entry *guest_entries =
assigned_dev->guest_msix_entries;
for (i = 0; i < assigned_dev->entries_nr; i++) {
@@ -152,7 +150,7 @@ static void kvm_assigned_dev_interrupt_work_handler(struct work_struct *work)
kvm_set_irq(assigned_dev->kvm, assigned_dev->irq_source_id,
assigned_dev->guest_irq, 1);
if (assigned_dev->irq_requested_type &
- KVM_ASSIGNED_DEV_GUEST_MSI) {
+ KVM_DEV_IRQ_GUEST_MSI) {
enable_irq(assigned_dev->host_irq);
assigned_dev->host_irq_disabled = false;
}
@@ -166,7 +164,7 @@ static irqreturn_t kvm_assigned_dev_intr(int irq, void *dev_id)
struct kvm_assigned_dev_kernel *assigned_dev =
(struct kvm_assigned_dev_kernel *) dev_id;
- if (assigned_dev->irq_requested_type == KVM_ASSIGNED_DEV_MSIX) {
+ if (assigned_dev->irq_requested_type & KVM_DEV_IRQ_HOST_MSIX) {
int index = find_index_from_host_irq(assigned_dev, irq);
if (index < 0)
return IRQ_HANDLED;
@@ -204,22 +202,22 @@ static void kvm_assigned_dev_ack_irq(struct kvm_irq_ack_notifier *kian)
}
}
-/* The function implicit hold kvm->lock mutex due to cancel_work_sync() */
-static void kvm_free_assigned_irq(struct kvm *kvm,
- struct kvm_assigned_dev_kernel *assigned_dev)
+static void deassign_guest_irq(struct kvm *kvm,
+ struct kvm_assigned_dev_kernel *assigned_dev)
{
- if (!irqchip_in_kernel(kvm))
- return;
-
kvm_unregister_irq_ack_notifier(&assigned_dev->ack_notifier);
+ assigned_dev->ack_notifier.gsi = -1;
if (assigned_dev->irq_source_id != -1)
kvm_free_irq_source_id(kvm, assigned_dev->irq_source_id);
assigned_dev->irq_source_id = -1;
+ assigned_dev->irq_requested_type &= ~(KVM_DEV_IRQ_GUEST_MASK);
+}
- if (!assigned_dev->irq_requested_type)
- return;
-
+/* The function implicit hold kvm->lock mutex due to cancel_work_sync() */
+static void deassign_host_irq(struct kvm *kvm,
+ struct kvm_assigned_dev_kernel *assigned_dev)
+{
/*
* In kvm_free_device_irq, cancel_work_sync return true if:
* 1. work is scheduled, and then cancelled.
@@ -236,7 +234,7 @@ static void kvm_free_assigned_irq(struct kvm *kvm,
* now, the kvm state is still legal for probably we also have to wait
* interrupt_work done.
*/
- if (assigned_dev->irq_requested_type & KVM_ASSIGNED_DEV_MSIX) {
+ if (assigned_dev->irq_requested_type & KVM_DEV_IRQ_HOST_MSIX) {
int i;
for (i = 0; i < assigned_dev->entries_nr; i++)
disable_irq_nosync(assigned_dev->
@@ -259,14 +257,41 @@ static void kvm_free_assigned_irq(struct kvm *kvm,
free_irq(assigned_dev->host_irq, (void *)assigned_dev);
- if (assigned_dev->irq_requested_type &
- KVM_ASSIGNED_DEV_HOST_MSI)
+ if (assigned_dev->irq_requested_type & KVM_DEV_IRQ_HOST_MSI)
pci_disable_msi(assigned_dev->dev);
}
- assigned_dev->irq_requested_type = 0;
+ assigned_dev->irq_requested_type &= ~(KVM_DEV_IRQ_HOST_MASK);
+}
+
+static int kvm_deassign_irq(struct kvm *kvm,
+ struct kvm_assigned_dev_kernel *assigned_dev,
+ unsigned long irq_requested_type)
+{
+ unsigned long guest_irq_type, host_irq_type;
+
+ if (!irqchip_in_kernel(kvm))
+ return -EINVAL;
+ /* no irq assignment to deassign */
+ if (!assigned_dev->irq_requested_type)
+ return -ENXIO;
+
+ host_irq_type = irq_requested_type & KVM_DEV_IRQ_HOST_MASK;
+ guest_irq_type = irq_requested_type & KVM_DEV_IRQ_GUEST_MASK;
+
+ if (host_irq_type)
+ deassign_host_irq(kvm, assigned_dev);
+ if (guest_irq_type)
+ deassign_guest_irq(kvm, assigned_dev);
+
+ return 0;
}
+static void kvm_free_assigned_irq(struct kvm *kvm,
+ struct kvm_assigned_dev_kernel *assigned_dev)
+{
+ kvm_deassign_irq(kvm, assigned_dev, assigned_dev->irq_requested_type);
+}
static void kvm_free_assigned_device(struct kvm *kvm,
struct kvm_assigned_dev_kernel
@@ -298,256 +323,244 @@ void kvm_free_all_assigned_devices(struct kvm *kvm)
}
}
-static int assigned_device_update_intx(struct kvm *kvm,
- struct kvm_assigned_dev_kernel *adev,
- struct kvm_assigned_irq *airq)
+static int assigned_device_enable_host_intx(struct kvm *kvm,
+ struct kvm_assigned_dev_kernel *dev)
{
- adev->guest_irq = airq->guest_irq;
- adev->ack_notifier.gsi = airq->guest_irq;
-
- if (adev->irq_requested_type & KVM_ASSIGNED_DEV_HOST_INTX)
- return 0;
-
- if (irqchip_in_kernel(kvm)) {
- if (!msi2intx &&
- (adev->irq_requested_type & KVM_ASSIGNED_DEV_HOST_MSI)) {
- free_irq(adev->host_irq, (void *)adev);
- pci_disable_msi(adev->dev);
- }
+ dev->host_irq = dev->dev->irq;
+ /* Even though this is PCI, we don't want to use shared
+ * interrupts. Sharing host devices with guest-assigned devices
+ * on the same interrupt line is not a happy situation: there
+ * are going to be long delays in accepting, acking, etc.
+ */
+ if (request_irq(dev->host_irq, kvm_assigned_dev_intr,
+ 0, "kvm_assigned_intx_device", (void *)dev))
+ return -EIO;
+ return 0;
+}
- if (!capable(CAP_SYS_RAWIO))
- return -EPERM;
+#ifdef __KVM_HAVE_MSI
+static int assigned_device_enable_host_msi(struct kvm *kvm,
+ struct kvm_assigned_dev_kernel *dev)
+{
+ int r;
- if (airq->host_irq)
- adev->host_irq = airq->host_irq;
- else
- adev->host_irq = adev->dev->irq;
+ if (!dev->dev->msi_enabled) {
+ r = pci_enable_msi(dev->dev);
+ if (r)
+ return r;
+ }
- /* Even though this is PCI, we don't want to use shared
- * interrupts. Sharing host devices with guest-assigned devices
- * on the same interrupt line is not a happy situation: there
- * are going to be long delays in accepting, acking, etc.
- */
- if (request_irq(adev->host_irq, kvm_assigned_dev_intr,
- 0, "kvm_assigned_intx_device", (void *)adev))
- return -EIO;
+ dev->host_irq = dev->dev->irq;
+ if (request_irq(dev->host_irq, kvm_assigned_dev_intr, 0,
+ "kvm_assigned_msi_device", (void *)dev)) {
+ pci_disable_msi(dev->dev);
+ return -EIO;
}
- adev->irq_requested_type = KVM_ASSIGNED_DEV_GUEST_INTX |
- KVM_ASSIGNED_DEV_HOST_INTX;
return 0;
}
+#endif
-#ifdef CONFIG_X86
-static int assigned_device_update_msi(struct kvm *kvm,
- struct kvm_assigned_dev_kernel *adev,
- struct kvm_assigned_irq *airq)
+#ifdef __KVM_HAVE_MSIX
+static int assigned_device_enable_host_msix(struct kvm *kvm,
+ struct kvm_assigned_dev_kernel *dev)
{
- int r;
+ int i, r = -EINVAL;
- adev->guest_irq = airq->guest_irq;
- if (airq->flags & KVM_DEV_IRQ_ASSIGN_ENABLE_MSI) {
- /* x86 don't care upper address of guest msi message addr */
- adev->irq_requested_type |= KVM_ASSIGNED_DEV_GUEST_MSI;
- adev->irq_requested_type &= ~KVM_ASSIGNED_DEV_GUEST_INTX;
- adev->ack_notifier.gsi = -1;
- } else if (msi2intx) {
- adev->irq_requested_type |= KVM_ASSIGNED_DEV_GUEST_INTX;
- adev->irq_requested_type &= ~KVM_ASSIGNED_DEV_GUEST_MSI;
- adev->ack_notifier.gsi = airq->guest_irq;
- } else {
- /*
- * Guest require to disable device MSI, we disable MSI and
- * re-enable INTx by default again. Notice it's only for
- * non-msi2intx.
- */
- assigned_device_update_intx(kvm, adev, airq);
- return 0;
- }
+ /* host_msix_entries and guest_msix_entries should have been
+ * initialized */
+ if (dev->entries_nr == 0)
+ return r;
- if (adev->irq_requested_type & KVM_ASSIGNED_DEV_HOST_MSI)
- return 0;
+ r = pci_enable_msix(dev->dev, dev->host_msix_entries, dev->entries_nr);
+ if (r)
+ return r;
- if (irqchip_in_kernel(kvm)) {
- if (!msi2intx) {
- if (adev->irq_requested_type &
- KVM_ASSIGNED_DEV_HOST_INTX)
- free_irq(adev->host_irq, (void *)adev);
+ for (i = 0; i < dev->entries_nr; i++) {
+ r = request_irq(dev->host_msix_entries[i].vector,
+ kvm_assigned_dev_intr, 0,
+ "kvm_assigned_msix_device",
+ (void *)dev);
+ /* FIXME: free requested_irq's on failure */
+ if (r)
+ return r;
+ }
- r = pci_enable_msi(adev->dev);
- if (r)
- return r;
- }
+ return 0;
+}
- adev->host_irq = adev->dev->irq;
- if (request_irq(adev->host_irq, kvm_assigned_dev_intr, 0,
- "kvm_assigned_msi_device", (void *)adev))
- return -EIO;
- }
+#endif
- if (!msi2intx)
- adev->irq_requested_type = KVM_ASSIGNED_DEV_GUEST_MSI;
+static int assigned_device_enable_guest_intx(struct kvm *kvm,
+ struct kvm_assigned_dev_kernel *dev,
+ struct kvm_assigned_irq *irq)
+{
+ dev->guest_irq = irq->guest_irq;
+ dev->ack_notifier.gsi = irq->guest_irq;
+ return 0;
+}
- adev->irq_requested_type |= KVM_ASSIGNED_DEV_HOST_MSI;
+#ifdef __KVM_HAVE_MSI
+static int assigned_device_enable_guest_msi(struct kvm *kvm,
+ struct kvm_assigned_dev_kernel *dev,
+ struct kvm_assigned_irq *irq)
+{
+ dev->guest_irq = irq->guest_irq;
+ dev->ack_notifier.gsi = -1;
return 0;
}
#endif
+#ifdef __KVM_HAVE_MSIX
+static int assigned_device_enable_guest_msix(struct kvm *kvm,
+ struct kvm_assigned_dev_kernel *dev,
+ struct kvm_assigned_irq *irq)
+{
+ dev->guest_irq = irq->guest_irq;
+ dev->ack_notifier.gsi = -1;
+ return 0;
+}
+#endif
+
+static int assign_host_irq(struct kvm *kvm,
+ struct kvm_assigned_dev_kernel *dev,
+ __u32 host_irq_type)
+{
+ int r = -EEXIST;
+
+ if (dev->irq_requested_type & KVM_DEV_IRQ_HOST_MASK)
+ return r;
+ switch (host_irq_type) {
+ case KVM_DEV_IRQ_HOST_INTX:
+ r = assigned_device_enable_host_intx(kvm, dev);
+ break;
+#ifdef __KVM_HAVE_MSI
+ case KVM_DEV_IRQ_HOST_MSI:
+ r = assigned_device_enable_host_msi(kvm, dev);
+ break;
+#endif
#ifdef __KVM_HAVE_MSIX
-static int assigned_device_update_msix(struct kvm *kvm,
- struct kvm_assigned_dev_kernel *adev,
- struct kvm_assigned_irq *airq)
-{
- /* TODO Deal with KVM_DEV_IRQ_ASSIGNED_MASK_MSIX */
- int i, r;
-
- adev->ack_notifier.gsi = -1;
-
- if (irqchip_in_kernel(kvm)) {
- if (airq->flags & KVM_DEV_IRQ_ASSIGN_MASK_MSIX)
- return -ENOTTY;
-
- if (!(airq->flags & KVM_DEV_IRQ_ASSIGN_ENABLE_MSIX)) {
- /* Guest disable MSI-X */
- kvm_free_assigned_irq(kvm, adev);
- if (msi2intx) {
- pci_enable_msi(adev->dev);
- if (adev->dev->msi_enabled)
- return assigned_device_update_msi(kvm,
- adev, airq);
- }
- return assigned_device_update_intx(kvm, adev, airq);
- }
+ case KVM_DEV_IRQ_HOST_MSIX:
+ r = assigned_device_enable_host_msix(kvm, dev);
+ break;
+#endif
+ default:
+ r = -EINVAL;
+ }
- /* host_msix_entries and guest_msix_entries should have been
- * initialized */
- if (adev->entries_nr == 0)
- return -EINVAL;
+ if (!r)
+ dev->irq_requested_type |= host_irq_type;
- kvm_free_assigned_irq(kvm, adev);
+ return r;
+}
- r = pci_enable_msix(adev->dev, adev->host_msix_entries,
- adev->entries_nr);
- if (r)
- return r;
+static int assign_guest_irq(struct kvm *kvm,
+ struct kvm_assigned_dev_kernel *dev,
+ struct kvm_assigned_irq *irq,
+ unsigned long guest_irq_type)
+{
+ int id;
+ int r = -EEXIST;
- for (i = 0; i < adev->entries_nr; i++) {
- r = request_irq((adev->host_msix_entries + i)->vector,
- kvm_assigned_dev_intr, 0,
- "kvm_assigned_msix_device",
- (void *)adev);
- if (r)
- return r;
- }
+ if (dev->irq_requested_type & KVM_DEV_IRQ_GUEST_MASK)
+ return r;
+
+ id = kvm_request_irq_source_id(kvm);
+ if (id < 0)
+ return id;
+
+ dev->irq_source_id = id;
+
+ switch (guest_irq_type) {
+ case KVM_DEV_IRQ_GUEST_INTX:
+ r = assigned_device_enable_guest_intx(kvm, dev, irq);
+ break;
+#ifdef __KVM_HAVE_MSI
+ case KVM_DEV_IRQ_GUEST_MSI:
+ r = assigned_device_enable_guest_msi(kvm, dev, irq);
+ break;
+#endif
+#ifdef __KVM_HAVE_MSIX
+ case KVM_DEV_IRQ_GUEST_MSIX:
+ r = assigned_device_enable_guest_msix(kvm, dev, irq);
+ break;
+#endif
+ default:
+ r = -EINVAL;
}
- adev->irq_requested_type |= KVM_ASSIGNED_DEV_MSIX;
+ if (!r) {
+ dev->irq_requested_type |= guest_irq_type;
+ kvm_register_irq_ack_notifier(kvm, &dev->ack_notifier);
+ } else
+ kvm_free_irq_source_id(kvm, dev->irq_source_id);
- return 0;
+ return r;
}
-#endif
+/* TODO Deal with KVM_DEV_IRQ_ASSIGNED_MASK_MSIX */
static int kvm_vm_ioctl_assign_irq(struct kvm *kvm,
- struct kvm_assigned_irq
- *assigned_irq)
+ struct kvm_assigned_irq *assigned_irq)
{
- int r = 0;
+ int r = -EINVAL;
struct kvm_assigned_dev_kernel *match;
- u32 current_flags = 0, changed_flags;
+ unsigned long host_irq_type, guest_irq_type;
- mutex_lock(&kvm->lock);
+ if (!capable(CAP_SYS_RAWIO))
+ return -EPERM;
+ if (!irqchip_in_kernel(kvm))
+ return r;
+
+ mutex_lock(&kvm->lock);
+ r = -ENODEV;
match = kvm_find_assigned_dev(&kvm->arch.assigned_dev_head,
assigned_irq->assigned_dev_id);
- if (!match) {
- mutex_unlock(&kvm->lock);
- return -EINVAL;
- }
-
- if (!match->irq_requested_type) {
- INIT_WORK(&match->interrupt_work,
- kvm_assigned_dev_interrupt_work_handler);
- if (irqchip_in_kernel(kvm)) {
- /* Register ack nofitier */
- match->ack_notifier.gsi = -1;
- match->ack_notifier.irq_acked =
- kvm_assigned_dev_ack_irq;
- kvm_register_irq_ack_notifier(kvm,
- &match->ack_notifier);
-
- /* Request IRQ source ID */
- r = kvm_request_irq_source_id(kvm);
- if (r < 0)
- goto out_release;
- else
- match->irq_source_id = r;
-
-#ifdef CONFIG_X86
- /* Determine host device irq type, we can know the
- * result from dev->msi_enabled */
- if (msi2intx)
- pci_enable_msi(match->dev);
-#endif
- }
- }
+ if (!match)
+ goto out;
- if (match->irq_requested_type & KVM_ASSIGNED_DEV_MSIX)
- current_flags |= KVM_DEV_IRQ_ASSIGN_ENABLE_MSIX;
- else if ((match->irq_requested_type & KVM_ASSIGNED_DEV_HOST_MSI) &&
- (match->irq_requested_type & KVM_ASSIGNED_DEV_GUEST_MSI))
- current_flags |= KVM_DEV_IRQ_ASSIGN_ENABLE_MSI;
+ host_irq_type = (assigned_irq->flags & KVM_DEV_IRQ_HOST_MASK);
+ guest_irq_type = (assigned_irq->flags & KVM_DEV_IRQ_GUEST_MASK);
- changed_flags = assigned_irq->flags ^ current_flags;
+ r = -EINVAL;
+ /* can only assign one type at a time */
+ if (hweight_long(host_irq_type) > 1)
+ goto out;
+ if (hweight_long(guest_irq_type) > 1)
+ goto out;
+ if (host_irq_type == 0 && guest_irq_type == 0)
+ goto out;
-#ifdef __KVM_HAVE_MSIX
- if (changed_flags & KVM_DEV_IRQ_ASSIGN_MSIX_ACTION) {
- r = assigned_device_update_msix(kvm, match, assigned_irq);
- if (r) {
- printk(KERN_WARNING "kvm: failed to execute "
- "MSI-X action!\n");
- goto out_release;
- }
- } else
-#endif
- if ((changed_flags & KVM_DEV_IRQ_ASSIGN_MSI_ACTION) ||
- (msi2intx && match->dev->msi_enabled)) {
-#ifdef CONFIG_X86
- r = assigned_device_update_msi(kvm, match, assigned_irq);
- if (r) {
- printk(KERN_WARNING "kvm: failed to enable "
- "MSI device!\n");
- goto out_release;
- }
-#else
- r = -ENOTTY;
-#endif
- } else if (assigned_irq->host_irq == 0 && match->dev->irq == 0) {
- /* Host device IRQ 0 means don't support INTx */
- if (!msi2intx) {
- printk(KERN_WARNING
- "kvm: wait device to enable MSI!\n");
- r = 0;
- } else {
- printk(KERN_WARNING
- "kvm: failed to enable MSI device!\n");
- r = -ENOTTY;
- goto out_release;
- }
- } else {
- /* Non-sharing INTx mode */
- r = assigned_device_update_intx(kvm, match, assigned_irq);
- if (r) {
- printk(KERN_WARNING "kvm: failed to enable "
- "INTx device!\n");
- goto out_release;
- }
- }
+ r = 0;
+ if (host_irq_type)
+ r = assign_host_irq(kvm, match, host_irq_type);
+ if (r)
+ goto out;
+ if (guest_irq_type)
+ r = assign_guest_irq(kvm, match, assigned_irq, guest_irq_type);
+out:
mutex_unlock(&kvm->lock);
return r;
-out_release:
+}
+
+static int kvm_vm_ioctl_deassign_dev_irq(struct kvm *kvm,
+ struct kvm_assigned_irq
+ *assigned_irq)
+{
+ int r = -ENODEV;
+ struct kvm_assigned_dev_kernel *match;
+
+ mutex_lock(&kvm->lock);
+
+ match = kvm_find_assigned_dev(&kvm->arch.assigned_dev_head,
+ assigned_irq->assigned_dev_id);
+ if (!match)
+ goto out;
+
+ r = kvm_deassign_irq(kvm, match, assigned_irq->flags);
+out:
mutex_unlock(&kvm->lock);
- kvm_free_assigned_device(kvm, match);
return r;
}
@@ -565,7 +578,7 @@ static int kvm_vm_ioctl_assign_device(struct kvm *kvm,
assigned_dev->assigned_dev_id);
if (match) {
/* device already assigned */
- r = -EINVAL;
+ r = -EEXIST;
goto out;
}
@@ -604,6 +617,9 @@ static int kvm_vm_ioctl_assign_device(struct kvm *kvm,
match->dev = dev;
match->irq_source_id = -1;
match->kvm = kvm;
+ match->ack_notifier.irq_acked = kvm_assigned_dev_ack_irq;
+ INIT_WORK(&match->interrupt_work,
+ kvm_assigned_dev_interrupt_work_handler);
list_add(&match->list, &kvm->arch.assigned_dev_head);
@@ -2084,6 +2100,11 @@ static long kvm_vm_ioctl(struct file *filp,
break;
}
case KVM_ASSIGN_IRQ: {
+ r = -EOPNOTSUPP;
+ break;
+ }
+#ifdef KVM_CAP_ASSIGN_DEV_IRQ
+ case KVM_ASSIGN_DEV_IRQ: {
struct kvm_assigned_irq assigned_irq;
r = -EFAULT;
@@ -2094,6 +2115,18 @@ static long kvm_vm_ioctl(struct file *filp,
goto out;
break;
}
+ case KVM_DEASSIGN_DEV_IRQ: {
+ struct kvm_assigned_irq assigned_irq;
+
+ r = -EFAULT;
+ if (copy_from_user(&assigned_irq, argp, sizeof assigned_irq))
+ goto out;
+ r = kvm_vm_ioctl_deassign_dev_irq(kvm, &assigned_irq);
+ if (r)
+ goto out;
+ break;
+ }
+#endif
#endif
#ifdef KVM_CAP_DEVICE_DEASSIGNMENT
case KVM_DEASSIGN_PCI_DEVICE: {
@@ -2595,9 +2628,6 @@ int kvm_init(void *opaque, unsigned int vcpu_size,
kvm_preempt_ops.sched_in = kvm_sched_in;
kvm_preempt_ops.sched_out = kvm_sched_out;
-#ifndef CONFIG_X86
- msi2intx = 0;
-#endif
return 0;
--
1.6.0.6
^ permalink raw reply [flat|nested] 44+ messages in thread* [PATCH 31/43] KVM: MMU: do not free active mmu pages in free_mmu_pages()
2009-05-18 9:22 [PATCH 00/43] KVM updates for the 2.6.31 merge window (batch 1/4) Avi Kivity
` (29 preceding siblings ...)
2009-05-18 9:22 ` [PATCH 30/43] KVM: Device assignment framework rework Avi Kivity
@ 2009-05-18 9:22 ` Avi Kivity
2009-05-18 9:22 ` [PATCH 32/43] KVM: x86: Ignore reads to EVNTSEL MSRs Avi Kivity
` (11 subsequent siblings)
42 siblings, 0 replies; 44+ messages in thread
From: Avi Kivity @ 2009-05-18 9:22 UTC (permalink / raw)
To: linux-kernel; +Cc: kvm
From: Gleb Natapov <gleb@redhat.com>
free_mmu_pages() should only undo what alloc_mmu_pages() does.
Free mmu pages from the generic VM destruction function, kvm_destroy_vm().
Signed-off-by: Gleb Natapov <gleb@redhat.com>
Signed-off-by: Avi Kivity <avi@redhat.com>
---
arch/x86/kvm/mmu.c | 8 --------
virt/kvm/kvm_main.c | 2 ++
2 files changed, 2 insertions(+), 8 deletions(-)
diff --git a/arch/x86/kvm/mmu.c b/arch/x86/kvm/mmu.c
index b6caf13..9256484 100644
--- a/arch/x86/kvm/mmu.c
+++ b/arch/x86/kvm/mmu.c
@@ -2638,14 +2638,6 @@ EXPORT_SYMBOL_GPL(kvm_disable_tdp);
static void free_mmu_pages(struct kvm_vcpu *vcpu)
{
- struct kvm_mmu_page *sp;
-
- while (!list_empty(&vcpu->kvm->arch.active_mmu_pages)) {
- sp = container_of(vcpu->kvm->arch.active_mmu_pages.next,
- struct kvm_mmu_page, link);
- kvm_mmu_zap_page(vcpu->kvm, sp);
- cond_resched();
- }
free_page((unsigned long)vcpu->arch.mmu.pae_root);
}
diff --git a/virt/kvm/kvm_main.c b/virt/kvm/kvm_main.c
index 231ca3c..7379eab 100644
--- a/virt/kvm/kvm_main.c
+++ b/virt/kvm/kvm_main.c
@@ -1032,6 +1032,8 @@ static void kvm_destroy_vm(struct kvm *kvm)
#endif
#if defined(CONFIG_MMU_NOTIFIER) && defined(KVM_ARCH_WANT_MMU_NOTIFIER)
mmu_notifier_unregister(&kvm->mmu_notifier, kvm->mm);
+#else
+ kvm_arch_flush_shadow(kvm);
#endif
kvm_arch_destroy_vm(kvm);
mmdrop(mm);
--
1.6.0.6
^ permalink raw reply [flat|nested] 44+ messages in thread* [PATCH 32/43] KVM: x86: Ignore reads to EVNTSEL MSRs
2009-05-18 9:22 [PATCH 00/43] KVM updates for the 2.6.31 merge window (batch 1/4) Avi Kivity
` (30 preceding siblings ...)
2009-05-18 9:22 ` [PATCH 31/43] KVM: MMU: do not free active mmu pages in free_mmu_pages() Avi Kivity
@ 2009-05-18 9:22 ` Avi Kivity
2009-05-18 9:22 ` [PATCH 33/43] KVM: SVM: Remove duplicate code in svm_do_inject_vector() Avi Kivity
` (10 subsequent siblings)
42 siblings, 0 replies; 44+ messages in thread
From: Avi Kivity @ 2009-05-18 9:22 UTC (permalink / raw)
To: linux-kernel; +Cc: kvm
From: Amit Shah <amit.shah@redhat.com>
We ignore writes to the performance counters and performance event
selector registers already. Kaspersky antivirus reads the eventsel
MSR causing it to crash with the current behaviour.
Return 0 as data when the eventsel registers are read to stop the
crash.
Signed-off-by: Amit Shah <amit.shah@redhat.com>
Signed-off-by: Avi Kivity <avi@redhat.com>
---
arch/x86/kvm/x86.c | 2 ++
1 files changed, 2 insertions(+), 0 deletions(-)
diff --git a/arch/x86/kvm/x86.c b/arch/x86/kvm/x86.c
index a27a64c..0131b5f 100644
--- a/arch/x86/kvm/x86.c
+++ b/arch/x86/kvm/x86.c
@@ -891,6 +891,8 @@ int kvm_get_msr_common(struct kvm_vcpu *vcpu, u32 msr, u64 *pdata)
case MSR_IA32_LASTINTFROMIP:
case MSR_IA32_LASTINTTOIP:
case MSR_VM_HSAVE_PA:
+ case MSR_P6_EVNTSEL0:
+ case MSR_P6_EVNTSEL1:
data = 0;
break;
case MSR_MTRRcap:
--
1.6.0.6
^ permalink raw reply [flat|nested] 44+ messages in thread* [PATCH 33/43] KVM: SVM: Remove duplicate code in svm_do_inject_vector()
2009-05-18 9:22 [PATCH 00/43] KVM updates for the 2.6.31 merge window (batch 1/4) Avi Kivity
` (31 preceding siblings ...)
2009-05-18 9:22 ` [PATCH 32/43] KVM: x86: Ignore reads to EVNTSEL MSRs Avi Kivity
@ 2009-05-18 9:22 ` Avi Kivity
2009-05-18 9:22 ` [PATCH 34/43] KVM: reuse (pop|push)_irq from svm.c in vmx.c Avi Kivity
` (9 subsequent siblings)
42 siblings, 0 replies; 44+ messages in thread
From: Avi Kivity @ 2009-05-18 9:22 UTC (permalink / raw)
To: linux-kernel; +Cc: kvm
From: Gleb Natapov <gleb@redhat.com>
svm_do_inject_vector() reimplements pop_irq().
Signed-off-by: Gleb Natapov <gleb@redhat.com>
Signed-off-by: Avi Kivity <avi@redhat.com>
---
arch/x86/kvm/svm.c | 10 +---------
1 files changed, 1 insertions(+), 9 deletions(-)
diff --git a/arch/x86/kvm/svm.c b/arch/x86/kvm/svm.c
index 1f8510c..5b35ebd 100644
--- a/arch/x86/kvm/svm.c
+++ b/arch/x86/kvm/svm.c
@@ -2346,15 +2346,7 @@ static void kvm_reput_irq(struct vcpu_svm *svm)
static void svm_do_inject_vector(struct vcpu_svm *svm)
{
- struct kvm_vcpu *vcpu = &svm->vcpu;
- int word_index = __ffs(vcpu->arch.irq_summary);
- int bit_index = __ffs(vcpu->arch.irq_pending[word_index]);
- int irq = word_index * BITS_PER_LONG + bit_index;
-
- clear_bit(bit_index, &vcpu->arch.irq_pending[word_index]);
- if (!vcpu->arch.irq_pending[word_index])
- clear_bit(word_index, &vcpu->arch.irq_summary);
- svm_inject_irq(svm, irq);
+ svm_inject_irq(svm, pop_irq(&svm->vcpu));
}
static void do_interrupt_requests(struct kvm_vcpu *vcpu,
--
1.6.0.6
^ permalink raw reply [flat|nested] 44+ messages in thread* [PATCH 34/43] KVM: reuse (pop|push)_irq from svm.c in vmx.c
2009-05-18 9:22 [PATCH 00/43] KVM updates for the 2.6.31 merge window (batch 1/4) Avi Kivity
` (32 preceding siblings ...)
2009-05-18 9:22 ` [PATCH 33/43] KVM: SVM: Remove duplicate code in svm_do_inject_vector() Avi Kivity
@ 2009-05-18 9:22 ` Avi Kivity
2009-05-18 9:22 ` [PATCH 35/43] KVM: VMX: Make module parameters readable Avi Kivity
` (8 subsequent siblings)
42 siblings, 0 replies; 44+ messages in thread
From: Avi Kivity @ 2009-05-18 9:22 UTC (permalink / raw)
To: linux-kernel; +Cc: kvm
From: Gleb Natapov <gleb@redhat.com>
The prioritized bit vector manipulation functions are useful in both vmx and
svm.
Signed-off-by: Gleb Natapov <gleb@redhat.com>
Signed-off-by: Avi Kivity <avi@redhat.com>
---
arch/x86/kvm/svm.c | 25 ++++---------------------
arch/x86/kvm/vmx.c | 17 ++---------------
arch/x86/kvm/x86.h | 18 ++++++++++++++++++
3 files changed, 24 insertions(+), 36 deletions(-)
diff --git a/arch/x86/kvm/svm.c b/arch/x86/kvm/svm.c
index 5b35ebd..aa528db 100644
--- a/arch/x86/kvm/svm.c
+++ b/arch/x86/kvm/svm.c
@@ -19,6 +19,7 @@
#include "irq.h"
#include "mmu.h"
#include "kvm_cache_regs.h"
+#include "x86.h"
#include <linux/module.h>
#include <linux/kernel.h>
@@ -132,24 +133,6 @@ static inline u32 svm_has(u32 feat)
return svm_features & feat;
}
-static inline u8 pop_irq(struct kvm_vcpu *vcpu)
-{
- int word_index = __ffs(vcpu->arch.irq_summary);
- int bit_index = __ffs(vcpu->arch.irq_pending[word_index]);
- int irq = word_index * BITS_PER_LONG + bit_index;
-
- clear_bit(bit_index, &vcpu->arch.irq_pending[word_index]);
- if (!vcpu->arch.irq_pending[word_index])
- clear_bit(word_index, &vcpu->arch.irq_summary);
- return irq;
-}
-
-static inline void push_irq(struct kvm_vcpu *vcpu, u8 irq)
-{
- set_bit(irq, vcpu->arch.irq_pending);
- set_bit(irq / BITS_PER_LONG, &vcpu->arch.irq_summary);
-}
-
static inline void clgi(void)
{
asm volatile (__ex(SVM_CLGI));
@@ -1116,7 +1099,7 @@ static int pf_interception(struct vcpu_svm *svm, struct kvm_run *kvm_run)
if (!irqchip_in_kernel(kvm) &&
is_external_interrupt(exit_int_info)) {
event_injection = true;
- push_irq(&svm->vcpu, exit_int_info & SVM_EVTINJ_VEC_MASK);
+ kvm_push_irq(&svm->vcpu, exit_int_info & SVM_EVTINJ_VEC_MASK);
}
fault_address = svm->vmcb->control.exit_info_2;
@@ -2336,7 +2319,7 @@ static void kvm_reput_irq(struct vcpu_svm *svm)
if ((control->int_ctl & V_IRQ_MASK)
&& !irqchip_in_kernel(svm->vcpu.kvm)) {
control->int_ctl &= ~V_IRQ_MASK;
- push_irq(&svm->vcpu, control->int_vector);
+ kvm_push_irq(&svm->vcpu, control->int_vector);
}
svm->vcpu.arch.interrupt_window_open =
@@ -2346,7 +2329,7 @@ static void kvm_reput_irq(struct vcpu_svm *svm)
static void svm_do_inject_vector(struct vcpu_svm *svm)
{
- svm_inject_irq(svm, pop_irq(&svm->vcpu));
+ svm_inject_irq(svm, kvm_pop_irq(&svm->vcpu));
}
static void do_interrupt_requests(struct kvm_vcpu *vcpu,
diff --git a/arch/x86/kvm/vmx.c b/arch/x86/kvm/vmx.c
index b5eae7a..2c0a2ed 100644
--- a/arch/x86/kvm/vmx.c
+++ b/arch/x86/kvm/vmx.c
@@ -2489,18 +2489,6 @@ static void vmx_update_window_states(struct kvm_vcpu *vcpu)
GUEST_INTR_STATE_MOV_SS)));
}
-static void kvm_do_inject_irq(struct kvm_vcpu *vcpu)
-{
- int word_index = __ffs(vcpu->arch.irq_summary);
- int bit_index = __ffs(vcpu->arch.irq_pending[word_index]);
- int irq = word_index * BITS_PER_LONG + bit_index;
-
- clear_bit(bit_index, &vcpu->arch.irq_pending[word_index]);
- if (!vcpu->arch.irq_pending[word_index])
- clear_bit(word_index, &vcpu->arch.irq_summary);
- kvm_queue_interrupt(vcpu, irq);
-}
-
static void do_interrupt_requests(struct kvm_vcpu *vcpu,
struct kvm_run *kvm_run)
{
@@ -2534,7 +2522,7 @@ static void do_interrupt_requests(struct kvm_vcpu *vcpu,
if (vcpu->arch.interrupt_window_open) {
if (vcpu->arch.irq_summary && !vcpu->arch.interrupt.pending)
- kvm_do_inject_irq(vcpu);
+ kvm_queue_interrupt(vcpu, kvm_pop_irq(vcpu));
if (vcpu->arch.interrupt.pending)
vmx_inject_irq(vcpu, vcpu->arch.interrupt.nr);
@@ -2619,8 +2607,7 @@ static int handle_exception(struct kvm_vcpu *vcpu, struct kvm_run *kvm_run)
if (!irqchip_in_kernel(vcpu->kvm) && is_external_interrupt(vect_info)) {
int irq = vect_info & VECTORING_INFO_VECTOR_MASK;
- set_bit(irq, vcpu->arch.irq_pending);
- set_bit(irq / BITS_PER_LONG, &vcpu->arch.irq_summary);
+ kvm_push_irq(vcpu, irq);
}
if ((intr_info & INTR_INFO_INTR_TYPE_MASK) == INTR_TYPE_NMI_INTR)
diff --git a/arch/x86/kvm/x86.h b/arch/x86/kvm/x86.h
index 6a4be78..2ab6791 100644
--- a/arch/x86/kvm/x86.h
+++ b/arch/x86/kvm/x86.h
@@ -19,4 +19,22 @@ static inline void kvm_clear_interrupt_queue(struct kvm_vcpu *vcpu)
vcpu->arch.interrupt.pending = false;
}
+static inline u8 kvm_pop_irq(struct kvm_vcpu *vcpu)
+{
+ int word_index = __ffs(vcpu->arch.irq_summary);
+ int bit_index = __ffs(vcpu->arch.irq_pending[word_index]);
+ int irq = word_index * BITS_PER_LONG + bit_index;
+
+ clear_bit(bit_index, &vcpu->arch.irq_pending[word_index]);
+ if (!vcpu->arch.irq_pending[word_index])
+ clear_bit(word_index, &vcpu->arch.irq_summary);
+ return irq;
+}
+
+static inline void kvm_push_irq(struct kvm_vcpu *vcpu, u8 irq)
+{
+ set_bit(irq, vcpu->arch.irq_pending);
+ set_bit(irq / BITS_PER_LONG, &vcpu->arch.irq_summary);
+}
+
#endif
--
1.6.0.6
^ permalink raw reply [flat|nested] 44+ messages in thread* [PATCH 35/43] KVM: VMX: Make module parameters readable
2009-05-18 9:22 [PATCH 00/43] KVM updates for the 2.6.31 merge window (batch 1/4) Avi Kivity
` (33 preceding siblings ...)
2009-05-18 9:22 ` [PATCH 34/43] KVM: reuse (pop|push)_irq from svm.c in vmx.c Avi Kivity
@ 2009-05-18 9:22 ` Avi Kivity
2009-05-18 9:22 ` [PATCH 36/43] KVM: VMX: Rename kvm_handle_exit() to vmx_handle_exit() Avi Kivity
` (7 subsequent siblings)
42 siblings, 0 replies; 44+ messages in thread
From: Avi Kivity @ 2009-05-18 9:22 UTC (permalink / raw)
To: linux-kernel; +Cc: kvm
Useful to see how the module was loaded.
Signed-off-by: Avi Kivity <avi@redhat.com>
---
arch/x86/kvm/vmx.c | 10 +++++-----
1 files changed, 5 insertions(+), 5 deletions(-)
diff --git a/arch/x86/kvm/vmx.c b/arch/x86/kvm/vmx.c
index 2c0a2ed..469787c 100644
--- a/arch/x86/kvm/vmx.c
+++ b/arch/x86/kvm/vmx.c
@@ -39,19 +39,19 @@ MODULE_AUTHOR("Qumranet");
MODULE_LICENSE("GPL");
static int bypass_guest_pf = 1;
-module_param(bypass_guest_pf, bool, 0);
+module_param(bypass_guest_pf, bool, S_IRUGO);
static int enable_vpid = 1;
-module_param(enable_vpid, bool, 0);
+module_param(enable_vpid, bool, 0444);
static int flexpriority_enabled = 1;
-module_param(flexpriority_enabled, bool, 0);
+module_param(flexpriority_enabled, bool, S_IRUGO);
static int enable_ept = 1;
-module_param(enable_ept, bool, 0);
+module_param(enable_ept, bool, S_IRUGO);
static int emulate_invalid_guest_state = 0;
-module_param(emulate_invalid_guest_state, bool, 0);
+module_param(emulate_invalid_guest_state, bool, S_IRUGO);
struct vmcs {
u32 revision_id;
--
1.6.0.6
^ permalink raw reply [flat|nested] 44+ messages in thread* [PATCH 36/43] KVM: VMX: Rename kvm_handle_exit() to vmx_handle_exit()
2009-05-18 9:22 [PATCH 00/43] KVM updates for the 2.6.31 merge window (batch 1/4) Avi Kivity
` (34 preceding siblings ...)
2009-05-18 9:22 ` [PATCH 35/43] KVM: VMX: Make module parameters readable Avi Kivity
@ 2009-05-18 9:22 ` Avi Kivity
2009-05-18 9:22 ` [PATCH 37/43] KVM: VMX: Simplify module parameter names Avi Kivity
` (6 subsequent siblings)
42 siblings, 0 replies; 44+ messages in thread
From: Avi Kivity @ 2009-05-18 9:22 UTC (permalink / raw)
To: linux-kernel; +Cc: kvm
It is a static vmx-specific function.
Signed-off-by: Avi Kivity <avi@redhat.com>
---
arch/x86/kvm/vmx.c | 4 ++--
1 files changed, 2 insertions(+), 2 deletions(-)
diff --git a/arch/x86/kvm/vmx.c b/arch/x86/kvm/vmx.c
index 469787c..85f4fd5 100644
--- a/arch/x86/kvm/vmx.c
+++ b/arch/x86/kvm/vmx.c
@@ -3162,7 +3162,7 @@ static const int kvm_vmx_max_exit_handlers =
* The guest has exited. See if we can fix it or if we need userspace
* assistance.
*/
-static int kvm_handle_exit(struct kvm_run *kvm_run, struct kvm_vcpu *vcpu)
+static int vmx_handle_exit(struct kvm_run *kvm_run, struct kvm_vcpu *vcpu)
{
u32 exit_reason = vmcs_read32(VM_EXIT_REASON);
struct vcpu_vmx *vmx = to_vmx(vcpu);
@@ -3681,7 +3681,7 @@ static struct kvm_x86_ops vmx_x86_ops = {
.tlb_flush = vmx_flush_tlb,
.run = vmx_vcpu_run,
- .handle_exit = kvm_handle_exit,
+ .handle_exit = vmx_handle_exit,
.skip_emulated_instruction = skip_emulated_instruction,
.patch_hypercall = vmx_patch_hypercall,
.get_irq = vmx_get_irq,
--
1.6.0.6
^ permalink raw reply [flat|nested] 44+ messages in thread* [PATCH 37/43] KVM: VMX: Simplify module parameter names
2009-05-18 9:22 [PATCH 00/43] KVM updates for the 2.6.31 merge window (batch 1/4) Avi Kivity
` (35 preceding siblings ...)
2009-05-18 9:22 ` [PATCH 36/43] KVM: VMX: Rename kvm_handle_exit() to vmx_handle_exit() Avi Kivity
@ 2009-05-18 9:22 ` Avi Kivity
2009-05-18 9:23 ` [PATCH 38/43] KVM: VMX: Annotate module parameters as __read_mostly Avi Kivity
` (5 subsequent siblings)
42 siblings, 0 replies; 44+ messages in thread
From: Avi Kivity @ 2009-05-18 9:22 UTC (permalink / raw)
To: linux-kernel; +Cc: kvm
Instead of 'enable_vpid=1', use a simple 'vpid=1'.
Signed-off-by: Avi Kivity <avi@redhat.com>
---
arch/x86/kvm/vmx.c | 6 +++---
1 files changed, 3 insertions(+), 3 deletions(-)
diff --git a/arch/x86/kvm/vmx.c b/arch/x86/kvm/vmx.c
index 85f4fd5..a69ba6b 100644
--- a/arch/x86/kvm/vmx.c
+++ b/arch/x86/kvm/vmx.c
@@ -42,13 +42,13 @@ static int bypass_guest_pf = 1;
module_param(bypass_guest_pf, bool, S_IRUGO);
static int enable_vpid = 1;
-module_param(enable_vpid, bool, 0444);
+module_param_named(vpid, enable_vpid, bool, 0444);
static int flexpriority_enabled = 1;
-module_param(flexpriority_enabled, bool, S_IRUGO);
+module_param_named(flexpriority, flexpriority_enabled, bool, S_IRUGO);
static int enable_ept = 1;
-module_param(enable_ept, bool, S_IRUGO);
+module_param_named(ept, enable_ept, bool, S_IRUGO);
static int emulate_invalid_guest_state = 0;
module_param(emulate_invalid_guest_state, bool, S_IRUGO);
--
1.6.0.6
^ permalink raw reply [flat|nested] 44+ messages in thread* [PATCH 38/43] KVM: VMX: Annotate module parameters as __read_mostly
2009-05-18 9:22 [PATCH 00/43] KVM updates for the 2.6.31 merge window (batch 1/4) Avi Kivity
` (36 preceding siblings ...)
2009-05-18 9:22 ` [PATCH 37/43] KVM: VMX: Simplify module parameter names Avi Kivity
@ 2009-05-18 9:23 ` Avi Kivity
2009-05-18 9:23 ` [PATCH 39/43] KVM: VMX: Zero the vpid module parameter if vpid is not supported Avi Kivity
` (4 subsequent siblings)
42 siblings, 0 replies; 44+ messages in thread
From: Avi Kivity @ 2009-05-18 9:23 UTC (permalink / raw)
To: linux-kernel; +Cc: kvm
Signed-off-by: Avi Kivity <avi@redhat.com>
---
arch/x86/kvm/vmx.c | 10 +++++-----
1 files changed, 5 insertions(+), 5 deletions(-)
diff --git a/arch/x86/kvm/vmx.c b/arch/x86/kvm/vmx.c
index a69ba6b..f4b6c4b 100644
--- a/arch/x86/kvm/vmx.c
+++ b/arch/x86/kvm/vmx.c
@@ -38,19 +38,19 @@
MODULE_AUTHOR("Qumranet");
MODULE_LICENSE("GPL");
-static int bypass_guest_pf = 1;
+static int __read_mostly bypass_guest_pf = 1;
module_param(bypass_guest_pf, bool, S_IRUGO);
-static int enable_vpid = 1;
+static int __read_mostly enable_vpid = 1;
module_param_named(vpid, enable_vpid, bool, 0444);
-static int flexpriority_enabled = 1;
+static int __read_mostly flexpriority_enabled = 1;
module_param_named(flexpriority, flexpriority_enabled, bool, S_IRUGO);
-static int enable_ept = 1;
+static int __read_mostly enable_ept = 1;
module_param_named(ept, enable_ept, bool, S_IRUGO);
-static int emulate_invalid_guest_state = 0;
+static int __read_mostly emulate_invalid_guest_state = 0;
module_param(emulate_invalid_guest_state, bool, S_IRUGO);
struct vmcs {
--
1.6.0.6
^ permalink raw reply [flat|nested] 44+ messages in thread* [PATCH 39/43] KVM: VMX: Zero the vpid module parameter if vpid is not supported
2009-05-18 9:22 [PATCH 00/43] KVM updates for the 2.6.31 merge window (batch 1/4) Avi Kivity
` (37 preceding siblings ...)
2009-05-18 9:23 ` [PATCH 38/43] KVM: VMX: Annotate module parameters as __read_mostly Avi Kivity
@ 2009-05-18 9:23 ` Avi Kivity
2009-05-18 9:23 ` [PATCH 40/43] KVM: VMX: Zero ept module parameter if ept is not present Avi Kivity
` (3 subsequent siblings)
42 siblings, 0 replies; 44+ messages in thread
From: Avi Kivity @ 2009-05-18 9:23 UTC (permalink / raw)
To: linux-kernel; +Cc: kvm
This allows reading back how the hardware is configured.
Signed-off-by: Avi Kivity <avi@redhat.com>
---
arch/x86/kvm/vmx.c | 5 ++++-
1 files changed, 4 insertions(+), 1 deletions(-)
diff --git a/arch/x86/kvm/vmx.c b/arch/x86/kvm/vmx.c
index f4b6c4b..9b97c8e 100644
--- a/arch/x86/kvm/vmx.c
+++ b/arch/x86/kvm/vmx.c
@@ -1202,6 +1202,9 @@ static __init int setup_vmcs_config(struct vmcs_config *vmcs_conf)
vmx_capability.ept, vmx_capability.vpid);
}
+ if (!cpu_has_vmx_vpid())
+ enable_vpid = 0;
+
min = 0;
#ifdef CONFIG_X86_64
min |= VM_EXIT_HOST_ADDR_SPACE_SIZE;
@@ -2082,7 +2085,7 @@ static void allocate_vpid(struct vcpu_vmx *vmx)
int vpid;
vmx->vpid = 0;
- if (!enable_vpid || !cpu_has_vmx_vpid())
+ if (!enable_vpid)
return;
spin_lock(&vmx_vpid_lock);
vpid = find_first_zero_bit(vmx_vpid_bitmap, VMX_NR_VPIDS);
--
1.6.0.6
^ permalink raw reply [flat|nested] 44+ messages in thread* [PATCH 40/43] KVM: VMX: Zero ept module parameter if ept is not present
2009-05-18 9:22 [PATCH 00/43] KVM updates for the 2.6.31 merge window (batch 1/4) Avi Kivity
` (38 preceding siblings ...)
2009-05-18 9:23 ` [PATCH 39/43] KVM: VMX: Zero the vpid module parameter if vpid is not supported Avi Kivity
@ 2009-05-18 9:23 ` Avi Kivity
2009-05-18 9:23 ` [PATCH 41/43] KVM: VMX: Fold vm_need_ept() into callers Avi Kivity
` (2 subsequent siblings)
42 siblings, 0 replies; 44+ messages in thread
From: Avi Kivity @ 2009-05-18 9:23 UTC (permalink / raw)
To: linux-kernel; +Cc: kvm
Allows reading back hardware capability.
Signed-off-by: Avi Kivity <avi@redhat.com>
---
arch/x86/kvm/vmx.c | 5 ++++-
1 files changed, 4 insertions(+), 1 deletions(-)
diff --git a/arch/x86/kvm/vmx.c b/arch/x86/kvm/vmx.c
index 9b97c8e..2f65120 100644
--- a/arch/x86/kvm/vmx.c
+++ b/arch/x86/kvm/vmx.c
@@ -265,7 +265,7 @@ static inline int cpu_has_vmx_ept(void)
static inline int vm_need_ept(void)
{
- return (cpu_has_vmx_ept() && enable_ept);
+ return enable_ept;
}
static inline int vm_need_virtualize_apic_accesses(struct kvm *kvm)
@@ -1205,6 +1205,9 @@ static __init int setup_vmcs_config(struct vmcs_config *vmcs_conf)
if (!cpu_has_vmx_vpid())
enable_vpid = 0;
+ if (!cpu_has_vmx_ept())
+ enable_ept = 0;
+
min = 0;
#ifdef CONFIG_X86_64
min |= VM_EXIT_HOST_ADDR_SPACE_SIZE;
--
1.6.0.6
^ permalink raw reply [flat|nested] 44+ messages in thread* [PATCH 41/43] KVM: VMX: Fold vm_need_ept() into callers
2009-05-18 9:22 [PATCH 00/43] KVM updates for the 2.6.31 merge window (batch 1/4) Avi Kivity
` (39 preceding siblings ...)
2009-05-18 9:23 ` [PATCH 40/43] KVM: VMX: Zero ept module parameter if ept is not present Avi Kivity
@ 2009-05-18 9:23 ` Avi Kivity
2009-05-18 9:23 ` [PATCH 42/43] KVM: Timer event should not unconditionally unhalt vcpu Avi Kivity
2009-05-18 9:23 ` [PATCH 43/43] KVM: Fix interrupt unhalting a vcpu when it shouldn't Avi Kivity
42 siblings, 0 replies; 44+ messages in thread
From: Avi Kivity @ 2009-05-18 9:23 UTC (permalink / raw)
To: linux-kernel; +Cc: kvm
Trivial.
Signed-off-by: Avi Kivity <avi@redhat.com>
---
arch/x86/kvm/vmx.c | 33 ++++++++++++++-------------------
1 files changed, 14 insertions(+), 19 deletions(-)
diff --git a/arch/x86/kvm/vmx.c b/arch/x86/kvm/vmx.c
index 2f65120..da6461d 100644
--- a/arch/x86/kvm/vmx.c
+++ b/arch/x86/kvm/vmx.c
@@ -263,11 +263,6 @@ static inline int cpu_has_vmx_ept(void)
SECONDARY_EXEC_ENABLE_EPT);
}
-static inline int vm_need_ept(void)
-{
- return enable_ept;
-}
-
static inline int vm_need_virtualize_apic_accesses(struct kvm *kvm)
{
return ((cpu_has_vmx_virtualize_apic_accesses()) &&
@@ -382,7 +377,7 @@ static inline void ept_sync_global(void)
static inline void ept_sync_context(u64 eptp)
{
- if (vm_need_ept()) {
+ if (enable_ept) {
if (cpu_has_vmx_invept_context())
__invept(VMX_EPT_EXTENT_CONTEXT, eptp, 0);
else
@@ -392,7 +387,7 @@ static inline void ept_sync_context(u64 eptp)
static inline void ept_sync_individual_addr(u64 eptp, gpa_t gpa)
{
- if (vm_need_ept()) {
+ if (enable_ept) {
if (cpu_has_vmx_invept_individual_addr())
__invept(VMX_EPT_EXTENT_INDIVIDUAL_ADDR,
eptp, gpa);
@@ -491,7 +486,7 @@ static void update_exception_bitmap(struct kvm_vcpu *vcpu)
}
if (vcpu->arch.rmode.active)
eb = ~0;
- if (vm_need_ept())
+ if (enable_ept)
eb &= ~(1u << PF_VECTOR); /* bypass_guest_pf = 0 */
vmcs_write32(EXCEPTION_BITMAP, eb);
}
@@ -1502,7 +1497,7 @@ static void exit_lmode(struct kvm_vcpu *vcpu)
static void vmx_flush_tlb(struct kvm_vcpu *vcpu)
{
vpid_sync_vcpu_all(to_vmx(vcpu));
- if (vm_need_ept())
+ if (enable_ept)
ept_sync_context(construct_eptp(vcpu->arch.mmu.root_hpa));
}
@@ -1587,7 +1582,7 @@ static void vmx_set_cr0(struct kvm_vcpu *vcpu, unsigned long cr0)
}
#endif
- if (vm_need_ept())
+ if (enable_ept)
ept_update_paging_mode_cr0(&hw_cr0, cr0, vcpu);
vmcs_writel(CR0_READ_SHADOW, cr0);
@@ -1616,7 +1611,7 @@ static void vmx_set_cr3(struct kvm_vcpu *vcpu, unsigned long cr3)
u64 eptp;
guest_cr3 = cr3;
- if (vm_need_ept()) {
+ if (enable_ept) {
eptp = construct_eptp(cr3);
vmcs_write64(EPT_POINTER, eptp);
ept_sync_context(eptp);
@@ -1637,7 +1632,7 @@ static void vmx_set_cr4(struct kvm_vcpu *vcpu, unsigned long cr4)
KVM_RMODE_VM_CR4_ALWAYS_ON : KVM_PMODE_VM_CR4_ALWAYS_ON);
vcpu->arch.cr4 = cr4;
- if (vm_need_ept())
+ if (enable_ept)
ept_update_paging_mode_cr4(&hw_cr4, vcpu);
vmcs_writel(CR4_READ_SHADOW, cr4);
@@ -1999,7 +1994,7 @@ static int init_rmode_identity_map(struct kvm *kvm)
pfn_t identity_map_pfn;
u32 tmp;
- if (!vm_need_ept())
+ if (!enable_ept)
return 1;
if (unlikely(!kvm->arch.ept_identity_pagetable)) {
printk(KERN_ERR "EPT: identity-mapping pagetable "
@@ -2163,7 +2158,7 @@ static int vmx_vcpu_setup(struct vcpu_vmx *vmx)
CPU_BASED_CR8_LOAD_EXITING;
#endif
}
- if (!vm_need_ept())
+ if (!enable_ept)
exec_control |= CPU_BASED_CR3_STORE_EXITING |
CPU_BASED_CR3_LOAD_EXITING |
CPU_BASED_INVLPG_EXITING;
@@ -2176,7 +2171,7 @@ static int vmx_vcpu_setup(struct vcpu_vmx *vmx)
~SECONDARY_EXEC_VIRTUALIZE_APIC_ACCESSES;
if (vmx->vpid == 0)
exec_control &= ~SECONDARY_EXEC_ENABLE_VPID;
- if (!vm_need_ept())
+ if (!enable_ept)
exec_control &= ~SECONDARY_EXEC_ENABLE_EPT;
vmcs_write32(SECONDARY_VM_EXEC_CONTROL, exec_control);
}
@@ -2637,7 +2632,7 @@ static int handle_exception(struct kvm_vcpu *vcpu, struct kvm_run *kvm_run)
error_code = vmcs_read32(VM_EXIT_INTR_ERROR_CODE);
if (is_page_fault(intr_info)) {
/* EPT won't cause page fault directly */
- if (vm_need_ept())
+ if (enable_ept)
BUG();
cr2 = vmcs_readl(EXIT_QUALIFICATION);
KVMTRACE_3D(PAGE_FAULT, vcpu, error_code, (u32)cr2,
@@ -3187,7 +3182,7 @@ static int vmx_handle_exit(struct kvm_run *kvm_run, struct kvm_vcpu *vcpu)
/* Access CR3 don't cause VMExit in paging mode, so we need
* to sync with guest real CR3. */
- if (vm_need_ept() && is_paging(vcpu)) {
+ if (enable_ept && is_paging(vcpu)) {
vcpu->arch.cr3 = vmcs_readl(GUEST_CR3);
ept_load_pdptrs(vcpu);
}
@@ -3602,7 +3597,7 @@ static struct kvm_vcpu *vmx_create_vcpu(struct kvm *kvm, unsigned int id)
if (alloc_apic_access_page(kvm) != 0)
goto free_vmcs;
- if (vm_need_ept())
+ if (enable_ept)
if (alloc_identity_pagetable(kvm) != 0)
goto free_vmcs;
@@ -3753,7 +3748,7 @@ static int __init vmx_init(void)
vmx_disable_intercept_for_msr(MSR_IA32_SYSENTER_ESP, false);
vmx_disable_intercept_for_msr(MSR_IA32_SYSENTER_EIP, false);
- if (vm_need_ept()) {
+ if (enable_ept) {
bypass_guest_pf = 0;
kvm_mmu_set_base_ptes(VMX_EPT_READABLE_MASK |
VMX_EPT_WRITABLE_MASK);
--
1.6.0.6
^ permalink raw reply [flat|nested] 44+ messages in thread* [PATCH 42/43] KVM: Timer event should not unconditionally unhalt vcpu.
2009-05-18 9:22 [PATCH 00/43] KVM updates for the 2.6.31 merge window (batch 1/4) Avi Kivity
` (40 preceding siblings ...)
2009-05-18 9:23 ` [PATCH 41/43] KVM: VMX: Fold vm_need_ept() into callers Avi Kivity
@ 2009-05-18 9:23 ` Avi Kivity
2009-05-18 9:23 ` [PATCH 43/43] KVM: Fix interrupt unhalting a vcpu when it shouldn't Avi Kivity
42 siblings, 0 replies; 44+ messages in thread
From: Avi Kivity @ 2009-05-18 9:23 UTC (permalink / raw)
To: linux-kernel; +Cc: kvm
From: Gleb Natapov <gleb@redhat.com>
Currently timer events are processed before entering guest mode. Move it
to main vcpu event loop since timer events should be processed even while
vcpu is halted. Timer may cause interrupt/nmi to be injected and only then
vcpu will be unhalted.
Signed-off-by: Gleb Natapov <gleb@redhat.com>
Signed-off-by: Avi Kivity <avi@redhat.com>
---
arch/ia64/kvm/kvm-ia64.c | 6 ++--
arch/x86/kvm/x86.c | 57 +++++++++++++++++++++++++++------------------
virt/kvm/kvm_main.c | 5 ++-
3 files changed, 40 insertions(+), 28 deletions(-)
diff --git a/arch/ia64/kvm/kvm-ia64.c b/arch/ia64/kvm/kvm-ia64.c
index 4623a90..d2a90fd 100644
--- a/arch/ia64/kvm/kvm-ia64.c
+++ b/arch/ia64/kvm/kvm-ia64.c
@@ -488,10 +488,10 @@ int kvm_emulate_halt(struct kvm_vcpu *vcpu)
hrtimer_cancel(p_ht);
vcpu->arch.ht_active = 0;
- if (test_and_clear_bit(KVM_REQ_UNHALT, &vcpu->requests))
+ if (test_and_clear_bit(KVM_REQ_UNHALT, &vcpu->requests) ||
+ kvm_cpu_has_pending_timer(vcpu))
if (vcpu->arch.mp_state == KVM_MP_STATE_HALTED)
- vcpu->arch.mp_state =
- KVM_MP_STATE_RUNNABLE;
+ vcpu->arch.mp_state = KVM_MP_STATE_RUNNABLE;
if (vcpu->arch.mp_state != KVM_MP_STATE_RUNNABLE)
return -EINTR;
diff --git a/arch/x86/kvm/x86.c b/arch/x86/kvm/x86.c
index 0131b5f..aa8b585 100644
--- a/arch/x86/kvm/x86.c
+++ b/arch/x86/kvm/x86.c
@@ -3129,9 +3129,6 @@ static int vcpu_enter_guest(struct kvm_vcpu *vcpu, struct kvm_run *kvm_run)
}
}
- clear_bit(KVM_REQ_PENDING_TIMER, &vcpu->requests);
- kvm_inject_pending_timer_irqs(vcpu);
-
preempt_disable();
kvm_x86_ops->prepare_guest_switch(vcpu);
@@ -3231,6 +3228,7 @@ out:
return r;
}
+
static int __vcpu_run(struct kvm_vcpu *vcpu, struct kvm_run *kvm_run)
{
int r;
@@ -3257,29 +3255,42 @@ static int __vcpu_run(struct kvm_vcpu *vcpu, struct kvm_run *kvm_run)
kvm_vcpu_block(vcpu);
down_read(&vcpu->kvm->slots_lock);
if (test_and_clear_bit(KVM_REQ_UNHALT, &vcpu->requests))
- if (vcpu->arch.mp_state == KVM_MP_STATE_HALTED)
+ {
+ switch(vcpu->arch.mp_state) {
+ case KVM_MP_STATE_HALTED:
vcpu->arch.mp_state =
- KVM_MP_STATE_RUNNABLE;
- if (vcpu->arch.mp_state != KVM_MP_STATE_RUNNABLE)
- r = -EINTR;
+ KVM_MP_STATE_RUNNABLE;
+ case KVM_MP_STATE_RUNNABLE:
+ break;
+ case KVM_MP_STATE_SIPI_RECEIVED:
+ default:
+ r = -EINTR;
+ break;
+ }
+ }
}
- if (r > 0) {
- if (dm_request_for_irq_injection(vcpu, kvm_run)) {
- r = -EINTR;
- kvm_run->exit_reason = KVM_EXIT_INTR;
- ++vcpu->stat.request_irq_exits;
- }
- if (signal_pending(current)) {
- r = -EINTR;
- kvm_run->exit_reason = KVM_EXIT_INTR;
- ++vcpu->stat.signal_exits;
- }
- if (need_resched()) {
- up_read(&vcpu->kvm->slots_lock);
- kvm_resched(vcpu);
- down_read(&vcpu->kvm->slots_lock);
- }
+ if (r <= 0)
+ break;
+
+ clear_bit(KVM_REQ_PENDING_TIMER, &vcpu->requests);
+ if (kvm_cpu_has_pending_timer(vcpu))
+ kvm_inject_pending_timer_irqs(vcpu);
+
+ if (dm_request_for_irq_injection(vcpu, kvm_run)) {
+ r = -EINTR;
+ kvm_run->exit_reason = KVM_EXIT_INTR;
+ ++vcpu->stat.request_irq_exits;
+ }
+ if (signal_pending(current)) {
+ r = -EINTR;
+ kvm_run->exit_reason = KVM_EXIT_INTR;
+ ++vcpu->stat.signal_exits;
+ }
+ if (need_resched()) {
+ up_read(&vcpu->kvm->slots_lock);
+ kvm_resched(vcpu);
+ down_read(&vcpu->kvm->slots_lock);
}
}
diff --git a/virt/kvm/kvm_main.c b/virt/kvm/kvm_main.c
index 7379eab..ffe2826 100644
--- a/virt/kvm/kvm_main.c
+++ b/virt/kvm/kvm_main.c
@@ -1611,11 +1611,12 @@ void kvm_vcpu_block(struct kvm_vcpu *vcpu)
prepare_to_wait(&vcpu->wq, &wait, TASK_INTERRUPTIBLE);
if (kvm_cpu_has_interrupt(vcpu) ||
- kvm_cpu_has_pending_timer(vcpu) ||
- kvm_arch_vcpu_runnable(vcpu)) {
+ kvm_arch_vcpu_runnable(vcpu)) {
set_bit(KVM_REQ_UNHALT, &vcpu->requests);
break;
}
+ if (kvm_cpu_has_pending_timer(vcpu))
+ break;
if (signal_pending(current))
break;
--
1.6.0.6
^ permalink raw reply [flat|nested] 44+ messages in thread* [PATCH 43/43] KVM: Fix interrupt unhalting a vcpu when it shouldn't
2009-05-18 9:22 [PATCH 00/43] KVM updates for the 2.6.31 merge window (batch 1/4) Avi Kivity
` (41 preceding siblings ...)
2009-05-18 9:23 ` [PATCH 42/43] KVM: Timer event should not unconditionally unhalt vcpu Avi Kivity
@ 2009-05-18 9:23 ` Avi Kivity
42 siblings, 0 replies; 44+ messages in thread
From: Avi Kivity @ 2009-05-18 9:23 UTC (permalink / raw)
To: linux-kernel; +Cc: kvm
From: Gleb Natapov <gleb@redhat.com>
kvm_vcpu_block() unhalts vpu on an interrupt/timer without checking
if interrupt window is actually opened.
Signed-off-by: Gleb Natapov <gleb@redhat.com>
Signed-off-by: Avi Kivity <avi@redhat.com>
---
arch/ia64/kvm/kvm-ia64.c | 6 ++++++
arch/powerpc/kvm/powerpc.c | 6 ++++++
arch/s390/kvm/interrupt.c | 6 ++++++
arch/x86/include/asm/kvm_host.h | 2 +-
arch/x86/kvm/svm.c | 10 ++++++++++
arch/x86/kvm/vmx.c | 8 +++++++-
arch/x86/kvm/x86.c | 5 +++++
include/linux/kvm_host.h | 1 +
virt/kvm/kvm_main.c | 3 ++-
9 files changed, 44 insertions(+), 3 deletions(-)
diff --git a/arch/ia64/kvm/kvm-ia64.c b/arch/ia64/kvm/kvm-ia64.c
index d2a90fd..3bf0a34 100644
--- a/arch/ia64/kvm/kvm-ia64.c
+++ b/arch/ia64/kvm/kvm-ia64.c
@@ -1963,6 +1963,12 @@ int kvm_cpu_has_interrupt(struct kvm_vcpu *vcpu)
return 0;
}
+int kvm_arch_interrupt_allowed(struct kvm_vcpu *vcpu)
+{
+ /* do real check here */
+ return 1;
+}
+
int kvm_cpu_has_pending_timer(struct kvm_vcpu *vcpu)
{
return vcpu->arch.timer_fired;
diff --git a/arch/powerpc/kvm/powerpc.c b/arch/powerpc/kvm/powerpc.c
index 9057335..2cf915e 100644
--- a/arch/powerpc/kvm/powerpc.c
+++ b/arch/powerpc/kvm/powerpc.c
@@ -41,6 +41,12 @@ int kvm_cpu_has_interrupt(struct kvm_vcpu *v)
return !!(v->arch.pending_exceptions);
}
+int kvm_arch_interrupt_allowed(struct kvm_vcpu *vcpu)
+{
+ /* do real check here */
+ return 1;
+}
+
int kvm_arch_vcpu_runnable(struct kvm_vcpu *v)
{
return !(v->arch.msr & MSR_WE);
diff --git a/arch/s390/kvm/interrupt.c b/arch/s390/kvm/interrupt.c
index 0189356..4ed4c3a 100644
--- a/arch/s390/kvm/interrupt.c
+++ b/arch/s390/kvm/interrupt.c
@@ -318,6 +318,12 @@ int kvm_cpu_has_interrupt(struct kvm_vcpu *vcpu)
return rc;
}
+int kvm_arch_interrupt_allowed(struct kvm_vcpu *vcpu)
+{
+ /* do real check here */
+ return 1;
+}
+
int kvm_cpu_has_pending_timer(struct kvm_vcpu *vcpu)
{
return 0;
diff --git a/arch/x86/include/asm/kvm_host.h b/arch/x86/include/asm/kvm_host.h
index 4627627..8351c4d 100644
--- a/arch/x86/include/asm/kvm_host.h
+++ b/arch/x86/include/asm/kvm_host.h
@@ -521,7 +521,7 @@ struct kvm_x86_ops {
void (*inject_pending_irq)(struct kvm_vcpu *vcpu);
void (*inject_pending_vectors)(struct kvm_vcpu *vcpu,
struct kvm_run *run);
-
+ int (*interrupt_allowed)(struct kvm_vcpu *vcpu);
int (*set_tss_addr)(struct kvm *kvm, unsigned int addr);
int (*get_tdp_level)(void);
int (*get_mt_mask_shift)(void);
diff --git a/arch/x86/kvm/svm.c b/arch/x86/kvm/svm.c
index aa528db..de74104 100644
--- a/arch/x86/kvm/svm.c
+++ b/arch/x86/kvm/svm.c
@@ -2270,6 +2270,15 @@ static void update_cr8_intercept(struct kvm_vcpu *vcpu)
vmcb->control.intercept_cr_write |= INTERCEPT_CR8_MASK;
}
+static int svm_interrupt_allowed(struct kvm_vcpu *vcpu)
+{
+ struct vcpu_svm *svm = to_svm(vcpu);
+ struct vmcb *vmcb = svm->vmcb;
+ return (vmcb->save.rflags & X86_EFLAGS_IF) &&
+ !(vmcb->control.int_state & SVM_INTERRUPT_SHADOW_MASK) &&
+ (svm->vcpu.arch.hflags & HF_GIF_MASK);
+}
+
static void svm_intr_assist(struct kvm_vcpu *vcpu)
{
struct vcpu_svm *svm = to_svm(vcpu);
@@ -2649,6 +2658,7 @@ static struct kvm_x86_ops svm_x86_ops = {
.exception_injected = svm_exception_injected,
.inject_pending_irq = svm_intr_assist,
.inject_pending_vectors = do_interrupt_requests,
+ .interrupt_allowed = svm_interrupt_allowed,
.set_tss_addr = svm_set_tss_addr,
.get_tdp_level = get_npt_level,
diff --git a/arch/x86/kvm/vmx.c b/arch/x86/kvm/vmx.c
index da6461d..b9e06b0 100644
--- a/arch/x86/kvm/vmx.c
+++ b/arch/x86/kvm/vmx.c
@@ -2490,6 +2490,12 @@ static void vmx_update_window_states(struct kvm_vcpu *vcpu)
GUEST_INTR_STATE_MOV_SS)));
}
+static int vmx_interrupt_allowed(struct kvm_vcpu *vcpu)
+{
+ vmx_update_window_states(vcpu);
+ return vcpu->arch.interrupt_window_open;
+}
+
static void do_interrupt_requests(struct kvm_vcpu *vcpu,
struct kvm_run *kvm_run)
{
@@ -3691,7 +3697,7 @@ static struct kvm_x86_ops vmx_x86_ops = {
.exception_injected = vmx_exception_injected,
.inject_pending_irq = vmx_intr_assist,
.inject_pending_vectors = do_interrupt_requests,
-
+ .interrupt_allowed = vmx_interrupt_allowed,
.set_tss_addr = vmx_set_tss_addr,
.get_tdp_level = get_ept_level,
.get_mt_mask_shift = vmx_get_mt_mask_shift,
diff --git a/arch/x86/kvm/x86.c b/arch/x86/kvm/x86.c
index aa8b585..ab61ea6 100644
--- a/arch/x86/kvm/x86.c
+++ b/arch/x86/kvm/x86.c
@@ -4471,3 +4471,8 @@ void kvm_vcpu_kick(struct kvm_vcpu *vcpu)
smp_call_function_single(ipi_pcpu, vcpu_kick_intr, vcpu, 0);
put_cpu();
}
+
+int kvm_arch_interrupt_allowed(struct kvm_vcpu *vcpu)
+{
+ return kvm_x86_ops->interrupt_allowed(vcpu);
+}
diff --git a/include/linux/kvm_host.h b/include/linux/kvm_host.h
index 40e49ed..72d5684 100644
--- a/include/linux/kvm_host.h
+++ b/include/linux/kvm_host.h
@@ -298,6 +298,7 @@ int kvm_arch_hardware_setup(void);
void kvm_arch_hardware_unsetup(void);
void kvm_arch_check_processor_compat(void *rtn);
int kvm_arch_vcpu_runnable(struct kvm_vcpu *vcpu);
+int kvm_arch_interrupt_allowed(struct kvm_vcpu *vcpu);
void kvm_free_physmem(struct kvm *kvm);
diff --git a/virt/kvm/kvm_main.c b/virt/kvm/kvm_main.c
index ffe2826..3265566 100644
--- a/virt/kvm/kvm_main.c
+++ b/virt/kvm/kvm_main.c
@@ -1610,7 +1610,8 @@ void kvm_vcpu_block(struct kvm_vcpu *vcpu)
for (;;) {
prepare_to_wait(&vcpu->wq, &wait, TASK_INTERRUPTIBLE);
- if (kvm_cpu_has_interrupt(vcpu) ||
+ if ((kvm_arch_interrupt_allowed(vcpu) &&
+ kvm_cpu_has_interrupt(vcpu)) ||
kvm_arch_vcpu_runnable(vcpu)) {
set_bit(KVM_REQ_UNHALT, &vcpu->requests);
break;
--
1.6.0.6
^ permalink raw reply [flat|nested] 44+ messages in thread