aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorKeir Fraser <keir.fraser@citrix.com>2009-09-18 08:46:32 +0100
committerKeir Fraser <keir.fraser@citrix.com>2009-09-18 08:46:32 +0100
commitd75c52c50c4b8ac03aca431f366ebe0b2f493dbe (patch)
tree0cae8642f37c1c54d9191bb9381cc6ae2d0fa005
parent41c06ea3f57221d4c99fd7226dfba01f0156a866 (diff)
downloadxen-d75c52c50c4b8ac03aca431f366ebe0b2f493dbe.tar.gz
xen-d75c52c50c4b8ac03aca431f366ebe0b2f493dbe.tar.bz2
xen-d75c52c50c4b8ac03aca431f366ebe0b2f493dbe.zip
iommu: Fix pirq conflict issue when guest adopts per-cpu vector.
Latest Linux and Windows may adopt per-cpu vector instead of global vector, so same vector in different vcpu may correspond to different interrupt sources. That is to say, vector and pirq should be 1:n mapping, and the array msi_gvec_pirq can't meet the mapping requirement, so need to improve the related logic, otherwise it may introduce strange issues. Signed-off-by: Xiantao Zhang <xiantao.zhang@intel.com>
-rw-r--r--xen/arch/x86/hvm/vmsi.c9
-rw-r--r--xen/drivers/passthrough/io.c23
-rw-r--r--xen/include/asm-x86/hvm/vlapic.h10
-rw-r--r--xen/include/xen/hvm/irq.h1
4 files changed, 25 insertions, 18 deletions
diff --git a/xen/arch/x86/hvm/vmsi.c b/xen/arch/x86/hvm/vmsi.c
index 24e38ebf6d..3662a4c757 100644
--- a/xen/arch/x86/hvm/vmsi.c
+++ b/xen/arch/x86/hvm/vmsi.c
@@ -64,15 +64,6 @@ static void vmsi_inj_irq(
}
}
-#define VMSI_RH_MASK 0x100
-#define VMSI_DM_MASK 0x200
-#define VMSI_DELIV_MASK 0x7000
-#define VMSI_TRIG_MODE 0x8000
-
-#define GFLAGS_SHIFT_RH 8
-#define GLFAGS_SHIFT_DELIV_MODE 12
-#define GLFAGS_SHIFT_TRG_MODE 15
-
int vmsi_deliver(struct domain *d, int pirq)
{
struct hvm_irq_dpci *hvm_irq_dpci = d->arch.hvm_domain.irq.dpci;
diff --git a/xen/drivers/passthrough/io.c b/xen/drivers/passthrough/io.c
index 79a0c9e53a..198c08962d 100644
--- a/xen/drivers/passthrough/io.c
+++ b/xen/drivers/passthrough/io.c
@@ -161,7 +161,6 @@ int pt_irq_create_bind_vtd(
HVM_IRQ_DPCI_GUEST_MSI;
hvm_irq_dpci->mirq[pirq].gmsi.gvec = pt_irq_bind->u.msi.gvec;
hvm_irq_dpci->mirq[pirq].gmsi.gflags = pt_irq_bind->u.msi.gflags;
- hvm_irq_dpci->msi_gvec_pirq[pt_irq_bind->u.msi.gvec] = pirq;
/* bind after hvm_irq_dpci is setup to avoid race with irq handler*/
rc = pirq_guest_bind(d->vcpu[0], pirq, 0);
if ( rc == 0 && pt_irq_bind->u.msi.gtable )
@@ -172,7 +171,6 @@ int pt_irq_create_bind_vtd(
}
if ( unlikely(rc) )
{
- hvm_irq_dpci->msi_gvec_pirq[pt_irq_bind->u.msi.gvec] = 0;
hvm_irq_dpci->mirq[pirq].gmsi.gflags = 0;
hvm_irq_dpci->mirq[pirq].gmsi.gvec = 0;
hvm_irq_dpci->mirq[pirq].flags = 0;
@@ -194,10 +192,8 @@ int pt_irq_create_bind_vtd(
/* if pirq is already mapped as vmsi, update the guest data/addr */
old_gvec = hvm_irq_dpci->mirq[pirq].gmsi.gvec;
- hvm_irq_dpci->msi_gvec_pirq[old_gvec] = 0;
hvm_irq_dpci->mirq[pirq].gmsi.gvec = pt_irq_bind->u.msi.gvec;
hvm_irq_dpci->mirq[pirq].gmsi.gflags = pt_irq_bind->u.msi.gflags;
- hvm_irq_dpci->msi_gvec_pirq[pt_irq_bind->u.msi.gvec] = pirq;
}
}
else
@@ -405,17 +401,28 @@ static void __msi_pirq_eoi(struct domain *d, int pirq)
void hvm_dpci_msi_eoi(struct domain *d, int vector)
{
+ int pirq, dest, dest_mode;
struct hvm_irq_dpci *hvm_irq_dpci = d->arch.hvm_domain.irq.dpci;
- int pirq;
if ( !iommu_enabled || (hvm_irq_dpci == NULL) )
return;
spin_lock(&d->event_lock);
+ for ( pirq = find_first_bit(hvm_irq_dpci->mapping, d->nr_pirqs);
+ pirq < d->nr_pirqs;
+ pirq = find_next_bit(hvm_irq_dpci->mapping, d->nr_pirqs, pirq + 1) )
+ {
+ if ( (!(hvm_irq_dpci->mirq[pirq].flags & HVM_IRQ_DPCI_MACH_MSI)) ||
+ (hvm_irq_dpci->mirq[pirq].gmsi.gvec != vector) )
+ continue;
- pirq = hvm_irq_dpci->msi_gvec_pirq[vector];
- __msi_pirq_eoi(d, pirq);
-
+ dest = hvm_irq_dpci->mirq[pirq].gmsi.gflags & VMSI_DEST_ID_MASK;
+ dest_mode = !!(hvm_irq_dpci->mirq[pirq].gmsi.gflags & VMSI_DM_MASK);
+ if ( vlapic_match_dest(vcpu_vlapic(current), NULL, 0, dest, dest_mode) )
+ break;
+ }
+ if ( pirq < d->nr_pirqs )
+ __msi_pirq_eoi(d, pirq);
spin_unlock(&d->event_lock);
}
diff --git a/xen/include/asm-x86/hvm/vlapic.h b/xen/include/asm-x86/hvm/vlapic.h
index 880754d2ab..d882af2d54 100644
--- a/xen/include/asm-x86/hvm/vlapic.h
+++ b/xen/include/asm-x86/hvm/vlapic.h
@@ -52,6 +52,16 @@
#define vlapic_base_address(vlapic) \
((vlapic)->hw.apic_base_msr & MSR_IA32_APICBASE_BASE)
+#define VMSI_DEST_ID_MASK 0xff
+#define VMSI_RH_MASK 0x100
+#define VMSI_DM_MASK 0x200
+#define VMSI_DELIV_MASK 0x7000
+#define VMSI_TRIG_MODE 0x8000
+
+#define GFLAGS_SHIFT_RH 8
+#define GLFAGS_SHIFT_DELIV_MODE 12
+#define GLFAGS_SHIFT_TRG_MODE 15
+
struct vlapic {
struct hvm_hw_lapic hw;
struct hvm_hw_lapic_regs *regs;
diff --git a/xen/include/xen/hvm/irq.h b/xen/include/xen/hvm/irq.h
index 739507af95..af298e5fe3 100644
--- a/xen/include/xen/hvm/irq.h
+++ b/xen/include/xen/hvm/irq.h
@@ -83,7 +83,6 @@ struct hvm_irq_dpci {
unsigned long *dirq_mask;
/* Guest IRQ to guest device/intx mapping. */
struct list_head girq[NR_HVM_IRQS];
- uint8_t msi_gvec_pirq[0x100];
/* Record of mapped ISA IRQs */
DECLARE_BITMAP(isairq_map, NR_ISAIRQS);
/* Record of mapped Links */