]> xenbits.xensource.com Git - xen.git/commitdiff
IRQ injection changes for HVM PCI passthru.
authorkfraser@localhost.localdomain <kfraser@localhost.localdomain>
Tue, 18 Sep 2007 15:09:19 +0000 (16:09 +0100)
committerkfraser@localhost.localdomain <kfraser@localhost.localdomain>
Tue, 18 Sep 2007 15:09:19 +0000 (16:09 +0100)
Signed-off-by: Allen Kay <allen.m.kay@intel.com>
Signed-off-by: Guy Zana <guy@neocleus.com>
12 files changed:
xen/arch/x86/hvm/irq.c
xen/arch/x86/hvm/vioapic.c
xen/arch/x86/hvm/vmx/Makefile
xen/arch/x86/hvm/vmx/intr.c
xen/arch/x86/hvm/vmx/vtd/dmar.c
xen/arch/x86/hvm/vmx/vtd/intel-iommu.c
xen/arch/x86/hvm/vmx/vtd/io.c
xen/arch/x86/hvm/vmx/vtd/msi.h
xen/arch/x86/hvm/vpic.c
xen/arch/x86/io_apic.c
xen/include/asm-x86/hvm/irq.h
xen/include/xen/irq.h

index b41295a273710f1221bc96687139578a7ace3c72..60b89764db87e86274a82cde1c77d8eb3eae8074 100644 (file)
@@ -26,7 +26,7 @@
 #include <asm/hvm/domain.h>
 #include <asm/hvm/support.h>
 
-static void __hvm_pci_intx_assert(
+void __hvm_pci_intx_assert(
     struct domain *d, unsigned int device, unsigned int intx)
 {
     struct hvm_irq *hvm_irq = &d->arch.hvm_domain.irq;
@@ -59,7 +59,7 @@ void hvm_pci_intx_assert(
     spin_unlock(&d->arch.hvm_domain.irq_lock);
 }
 
-static void __hvm_pci_intx_deassert(
+void __hvm_pci_intx_deassert(
     struct domain *d, unsigned int device, unsigned int intx)
 {
     struct hvm_irq *hvm_irq = &d->arch.hvm_domain.irq;
index 6f708b5a0ca35c9c33c776c943c2a2e75899d764..c6faba349004c3cde829266cd4ca0703ed7589d9 100644 (file)
@@ -458,6 +458,10 @@ void vioapic_update_EOI(struct domain *d, int vector)
     ent = &vioapic->redirtbl[gsi];
 
     ent->fields.remote_irr = 0;
+
+    if ( vtd_enabled )
+        hvm_dpci_eoi(gsi, ent);
+
     if ( (ent->fields.trig_mode == VIOAPIC_LEVEL_TRIG) &&
          !ent->fields.mask &&
          hvm_irq->gsi_assert_count[gsi] )
index ba31793c2f8260959ed9290f23ecbd28ca4a1da7..a7d51d4675cf527f5b08132e7f004a133086639a 100644 (file)
@@ -1,3 +1,5 @@
+subdir-y += vtd
+
 subdir-$(x86_32) += x86_32
 subdir-$(x86_64) += x86_64
 
index 352b9111eadd4525e2b8b85d2d5a5993b821e996..1fdad07c3d5494bebf0318d3e9420e21125fb7cc 100644 (file)
@@ -138,6 +138,23 @@ static void update_tpr_threshold(
     __vmwrite(TPR_THRESHOLD, threshold);
 }
 
+static void vmx_dirq_assist(struct domain *d)
+{
+    unsigned int irq;
+    uint32_t device, intx;
+    struct hvm_irq *hvm_irq = &d->arch.hvm_domain.irq;
+
+    for ( irq = find_first_bit(hvm_irq->dirq_mask, NR_IRQS);
+          irq < NR_IRQS;
+          irq = find_next_bit(hvm_irq->dirq_mask, NR_IRQS, irq + 1) )
+    {
+        test_and_clear_bit(irq, &hvm_irq->dirq_mask);
+        device = hvm_irq->mirq[irq].device;
+        intx = hvm_irq->mirq[irq].intx;
+        hvm_pci_intx_assert(d, device, intx);
+    }
+}
+
 asmlinkage void vmx_intr_assist(void)
 {
     int intr_vector;
@@ -147,6 +164,10 @@ asmlinkage void vmx_intr_assist(void)
 
     /* Crank the handle on interrupt state. */
     pt_update_irq(v);
+
+    if ( vtd_enabled && (v->vcpu_id == 0) )
+        vmx_dirq_assist(v->domain);
+  
     hvm_set_callback_irq_level();
 
     do {
index 59e59543e1b22b9dc52cb51ac1e31fd3279805c9..784af118187e3a9ef116579f69251e096c31c85a 100644 (file)
 #include "pci-direct.h"
 #include "pci_regs.h"
 
+#define VTDPREFIX
+int vtd_enabled;
+boolean_param("vtd", vtd_enabled);
+
 #undef PREFIX
 #define PREFIX VTDPREFIX "ACPI DMAR:"
 #define DEBUG
@@ -484,11 +488,19 @@ acpi_parse_dmar(unsigned long phys_addr, unsigned long size)
 
 int acpi_dmar_init(void)
 {
+    extern int ioapic_ack_new;
+
     acpi_table_parse(ACPI_DMAR, acpi_parse_dmar);
+
     if (list_empty(&acpi_drhd_units)) {
         printk(KERN_ERR PREFIX "No DMAR devices found\n");
+        vtd_enabled = 0;
         return -ENODEV;
-    } else
-        vtd_enabled = 1;
+    }
+
+    /* Use fake-vector style of IOAPIC acknowledgement. */
+    if (vtd_enabled)
+        ioapic_ack_new = 0;
+
     return 0;
 }
index 5af112bfe2b5f961746928efc3e2a2a2bc5935f7..3146490f018e911096c9736f1d30fd43efae888e 100644 (file)
 #include "pci_regs.h"
 #include "msi.h"
 
+#define VTDPREFIX
+static inline int request_irq(int vector, void *func,
+                              int flags, char *name, void *data)
+{
+    return -ENOSYS;
+}
+
 extern void print_iommu_regs(struct acpi_drhd_unit *drhd);
 extern void print_vtd_entries(struct domain *d, int bus, int devfn,
                        unsigned long gmfn);
-extern void (*interrupt[])(void);
 
 #define DMAR_OPERATION_TIMEOUT (HZ*60) /* 1m */
 
@@ -831,7 +837,6 @@ static struct hw_interrupt_type dma_msi_type = {
 int iommu_set_interrupt(struct iommu *iommu)
 {
     int vector, ret;
-    unsigned long flags;
 
     vector = assign_irq_vector(AUTO_ASSIGN);
     vector_to_iommu[vector] = iommu;
@@ -845,10 +850,7 @@ int iommu_set_interrupt(struct iommu *iommu)
         return -EINVAL;
     }
 
-    spin_lock_irqsave(&irq_desc[vector].lock, flags);
     irq_desc[vector].handler = &dma_msi_type;
-    spin_unlock_irqrestore(&irq_desc[vector].lock, flags);
-    set_intr_gate(vector, interrupt[vector]);
     ret = request_irq(vector, iommu_page_fault, 0, "dmar", iommu);
     if (ret)
         gdprintk(XENLOG_ERR VTDPREFIX, "IOMMU: can't request irq\n");
index 851c54dcdf9bec834a820efcf56a128322149c59..40d57dfd98708b92fbe63328b6c6485a6301a86b 100644 (file)
@@ -50,33 +50,31 @@ int hvm_do_IRQ_dpci(struct domain *d, unsigned int mirq)
     uint32_t link, isa_irq;
     struct hvm_irq *hvm_irq;
 
-    if (!vtd_enabled || (d == dom0))
+    if ( !vtd_enabled || (d == dom0) ||
+         !d->arch.hvm_domain.irq.mirq[mirq].valid )
         return 0;
 
-    if (d->arch.hvm_domain.irq.mirq[mirq].valid)
-    {
-        device = d->arch.hvm_domain.irq.mirq[mirq].device;
-        intx = d->arch.hvm_domain.irq.mirq[mirq].intx;
-        link = hvm_pci_intx_link(device, intx);
-        hvm_irq = &d->arch.hvm_domain.irq;
-        isa_irq = hvm_irq->pci_link.route[link];
+    device = d->arch.hvm_domain.irq.mirq[mirq].device;
+    intx = d->arch.hvm_domain.irq.mirq[mirq].intx;
+    link = hvm_pci_intx_link(device, intx);
+    hvm_irq = &d->arch.hvm_domain.irq;
+    isa_irq = hvm_irq->pci_link.route[link];
 
-        if ( !d->arch.hvm_domain.irq.girq[isa_irq].valid )
-        {
-            d->arch.hvm_domain.irq.girq[isa_irq].valid = 1;
-            d->arch.hvm_domain.irq.girq[isa_irq].device = device;
-            d->arch.hvm_domain.irq.girq[isa_irq].intx = intx;
-            d->arch.hvm_domain.irq.girq[isa_irq].machine_gsi = mirq;
-        }
+    if ( !d->arch.hvm_domain.irq.girq[isa_irq].valid )
+    {
+        d->arch.hvm_domain.irq.girq[isa_irq].valid = 1;
+        d->arch.hvm_domain.irq.girq[isa_irq].device = device;
+        d->arch.hvm_domain.irq.girq[isa_irq].intx = intx;
+        d->arch.hvm_domain.irq.girq[isa_irq].machine_gsi = mirq;
+    }
 
-        if ( !test_and_set_bit(mirq, d->arch.hvm_domain.irq.dirq_mask) )
-        {
-            vcpu_kick(d->vcpu[0]);
-            return 1;
-        }
-        else
-            dprintk(XENLOG_INFO, "Want to pending mirq, but failed\n");
+    if ( !test_and_set_bit(mirq, d->arch.hvm_domain.irq.dirq_mask) )
+    {
+        vcpu_kick(d->vcpu[0]);
+        return 1;
     }
+
+    dprintk(XENLOG_INFO, "mirq already pending\n");
     return 0;
 }
 
@@ -86,18 +84,21 @@ void hvm_dpci_eoi(unsigned int guest_gsi, union vioapic_redir_entry *ent)
     uint32_t device, intx, machine_gsi;
     irq_desc_t *desc;
 
-    if (d->arch.hvm_domain.irq.girq[guest_gsi].valid)
+    ASSERT(spin_is_locked(&d->arch.hvm_domain.irq_lock));
+
+    if ( !vtd_enabled || !d->arch.hvm_domain.irq.girq[guest_gsi].valid )
+        return;
+
+    device = d->arch.hvm_domain.irq.girq[guest_gsi].device;
+    intx = d->arch.hvm_domain.irq.girq[guest_gsi].intx;
+    machine_gsi = d->arch.hvm_domain.irq.girq[guest_gsi].machine_gsi;
+    gdprintk(XENLOG_INFO, "hvm_dpci_eoi:: device %x intx %x\n",
+             device, intx);
+    __hvm_pci_intx_deassert(d, device, intx);
+    if ( (ent == NULL) || (ent->fields.mask == 0) )
     {
-        device = d->arch.hvm_domain.irq.girq[guest_gsi].device;
-        intx = d->arch.hvm_domain.irq.girq[guest_gsi].intx;
-        machine_gsi = d->arch.hvm_domain.irq.girq[guest_gsi].machine_gsi;
-        gdprintk(XENLOG_INFO, "hvm_dpci_eoi:: device %x intx %x\n",
-            device, intx);
-        hvm_pci_intx_deassert(d, device, intx);
-        if ( (ent == NULL) || (ent && ent->fields.mask == 0) ) {
-            desc = &irq_desc[irq_to_vector(machine_gsi)];
-            desc->handler->end(irq_to_vector(machine_gsi));
-        }
+        desc = &irq_desc[irq_to_vector(machine_gsi)];
+        desc->handler->end(irq_to_vector(machine_gsi));
     }
 }
 
@@ -107,14 +108,13 @@ int release_devices(struct domain *d)
     uint32_t i;
     int ret = 0;
 
-    if (!vtd_enabled)
+    if ( !vtd_enabled )
         return ret;
 
-    /* unbind irq */
-    for (i = 0; i < NR_IRQS; i++) {
-        if (hd->irq.mirq[i].valid)
+    for ( i = 0; i < NR_IRQS; i++ )
+        if ( hd->irq.mirq[i].valid )
             ret = pirq_guest_unbind(d, i);
-    }
+
     iommu_domain_teardown(d);
     return ret;
 }
index f8256607fb1212d0023c922a5814b8b126e1df51..cf3d1fe110dd19b260f5b299b8aeaef02e89d262 100644 (file)
@@ -17,7 +17,6 @@
 #define NR_HP_RESERVED_VECTORS         20
 
 extern int vector_irq[NR_VECTORS];
-extern void (*interrupt[NR_IRQS])(void);
 extern int pci_vector_resources(int last, int nr_released);
 
 /*
index 46ab18fc46be265e4a1a02ea97fbaeb28401b43f..1ac08320fa65eadcc551c6d9169d9682f123266c 100644 (file)
@@ -182,8 +182,7 @@ static void vpic_ioport_write(
 
     vpic_lock(vpic);
 
-    addr &= 1;
-    if ( addr == 0 )
+    if ( (addr & 1) == 0 )
     {
         if ( val & 0x10 )
         {
@@ -250,6 +249,11 @@ static void vpic_ioport_write(
                 vpic->isr &= ~(1 << irq);
                 if ( cmd == 7 )
                     vpic->priority_add = (irq + 1) & 7;
+                if ( vtd_enabled )
+                {
+                    irq |= ((addr & 0xa0) == 0xa0) ? 8 : 0;
+                    hvm_dpci_eoi(hvm_isa_irq_to_gsi(irq), NULL);
+                }
                 break;
             case 6: /* Set Priority                */
                 vpic->priority_add = (val + 1) & 7;
index 6eba445b458ac69ae38a9682f90929116ca6d92a..7b399850ce06764a478fc5876a182970ad0cdbe4 100644 (file)
@@ -184,6 +184,68 @@ static void __modify_IO_APIC_irq (unsigned int irq, unsigned long enable, unsign
     }
 }
 
+static int real_vector[MAX_IRQ_SOURCES];
+static int fake_vector=-1;
+
+/*
+ * Following 2 functions are used to workaround spurious interrupt
+ * problem related to mask/unmask of interrupts.  Instead we program
+ * an unused vector in the IOAPIC before issueing EOI to LAPIC.
+ */
+static void write_fake_IO_APIC_vector (unsigned int irq)
+{
+    struct irq_pin_list *entry = irq_2_pin + irq;
+    unsigned int pin, reg;
+    unsigned long flags;
+
+    spin_lock_irqsave(&ioapic_lock, flags);
+    for (;;) {
+        pin = entry->pin;
+        if (pin == -1)
+            break;
+        reg = io_apic_read(entry->apic, 0x10 + pin*2);
+        real_vector[irq] = reg & 0xff;
+        reg &= ~0xff;
+
+        if (fake_vector == -1)
+            fake_vector = assign_irq_vector(MAX_IRQ_SOURCES-1);
+
+        reg |= fake_vector;
+        io_apic_write(entry->apic, 0x10 + pin*2, reg);
+
+        if (!entry->next)
+            break;
+        entry = irq_2_pin + entry->next;
+    }
+    spin_unlock_irqrestore(&ioapic_lock, flags);
+}
+
+static void restore_real_IO_APIC_vector (unsigned int irq)
+{
+    struct irq_pin_list *entry = irq_2_pin + irq;
+    unsigned int pin, reg;
+    unsigned long flags;
+
+    spin_lock_irqsave(&ioapic_lock, flags);
+    for (;;) {
+        pin = entry->pin;
+        if (pin == -1)
+            break;
+
+        reg = io_apic_read(entry->apic, 0x10 + pin*2);
+        reg &= ~0xff;
+        reg |= real_vector[irq];
+        io_apic_write(entry->apic, 0x10 + pin*2, reg);
+        mb();
+        *(IO_APIC_BASE(entry->apic) + 0x10) = reg & 0xff;
+
+        if (!entry->next)
+            break;
+        entry = irq_2_pin + entry->next;
+    }
+    spin_unlock_irqrestore(&ioapic_lock, flags);
+}
+
 /* mask = 1 */
 static void __mask_IO_APIC_irq (unsigned int irq)
 {
@@ -1356,7 +1418,11 @@ static void mask_and_ack_level_ioapic_irq (unsigned int irq)
     if ( ioapic_ack_new )
         return;
 
-    mask_IO_APIC_irq(irq);
+    if ( vtd_enabled )
+        write_fake_IO_APIC_vector(irq);
+    else
+        mask_IO_APIC_irq(irq);
+
 /*
  * It appears there is an erratum which affects at least version 0x11
  * of I/O APIC (that's the 82093AA and cores integrated into various
@@ -1398,8 +1464,12 @@ static void end_level_ioapic_irq (unsigned int irq)
 
     if ( !ioapic_ack_new )
     {
-        if ( !(irq_desc[IO_APIC_VECTOR(irq)].status & IRQ_DISABLED) )
-            unmask_IO_APIC_irq(irq);
+        if ( !(irq_desc[IO_APIC_VECTOR(irq)].status & IRQ_DISABLED) ) {
+            if ( vtd_enabled )
+                restore_real_IO_APIC_vector(irq);
+            else
+                unmask_IO_APIC_irq(irq);
+        }
         return;
     }
 
index e0a9faddbfdb391530aafb290ecc4be0bac1c06f..142aeadd41cf198a28f08e1697c9eab0d2d3a677 100644 (file)
@@ -114,8 +114,12 @@ struct hvm_irq {
 #define hvm_isa_irq_to_gsi(isa_irq) ((isa_irq) ? : 2)
 
 /* Modify state of a PCI INTx wire. */
+void __hvm_pci_intx_assert(
+    struct domain *d, unsigned int device, unsigned int intx);
 void hvm_pci_intx_assert(
     struct domain *d, unsigned int device, unsigned int intx);
+void __hvm_pci_intx_deassert(
+    struct domain *d, unsigned int device, unsigned int intx);
 void hvm_pci_intx_deassert(
     struct domain *d, unsigned int device, unsigned int intx);
 
index ca55235519d2b83a0a67bba77d922ad241bd77c3..b92f785b94262666e0e651c7cab125a68643a2f2 100644 (file)
@@ -64,9 +64,6 @@ extern irq_desc_t irq_desc[NR_IRQS];
 
 extern int setup_irq(unsigned int, struct irqaction *);
 extern void free_irq(unsigned int);
-extern int request_irq(unsigned int irq,
-               void (*handler)(int, void *, struct cpu_user_regs *),
-               unsigned long irqflags, const char * devname, void *dev_id);
 
 extern hw_irq_controller no_irq_type;
 extern void no_action(int cpl, void *dev_id, struct cpu_user_regs *regs);
@@ -80,11 +77,11 @@ extern int pirq_guest_unbind(struct domain *d, int irq);
 
 static inline void set_native_irq_info(int irq, cpumask_t mask)
 {
-       irq_desc[irq].affinity = mask;
+    irq_desc[irq].affinity = mask;
 }
 
 static inline void set_irq_info(int irq, cpumask_t mask)
 {
-       set_native_irq_info(irq, mask);
+    set_native_irq_info(irq, mask);
 }
 #endif /* __XEN_IRQ_H__ */