[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index] [Xen-changelog] [xen-unstable] IRQ injection changes for HVM PCI passthru.
# HG changeset patch # User kfraser@xxxxxxxxxxxxxxxxxxxxx # Date 1190128159 -3600 # Node ID b7eb2bb9b6251c0533bac7361218c398ad3e8cbf # Parent b594583d6e44346d91233bd7b9a6ea0eab648802 IRQ injection changes for HVM PCI passthru. Signed-off-by: Allen Kay <allen.m.kay@xxxxxxxxx> Signed-off-by: Guy Zana <guy@xxxxxxxxxxxx> --- xen/arch/x86/hvm/irq.c | 4 - xen/arch/x86/hvm/vioapic.c | 4 + xen/arch/x86/hvm/vmx/Makefile | 2 xen/arch/x86/hvm/vmx/intr.c | 21 +++++++++ xen/arch/x86/hvm/vmx/vtd/dmar.c | 20 ++++++-- xen/arch/x86/hvm/vmx/vtd/intel-iommu.c | 12 +++-- xen/arch/x86/hvm/vmx/vtd/io.c | 76 ++++++++++++++++----------------- xen/arch/x86/hvm/vmx/vtd/msi.h | 1 xen/arch/x86/hvm/vpic.c | 8 ++- xen/arch/x86/io_apic.c | 76 +++++++++++++++++++++++++++++++-- xen/include/asm-x86/hvm/irq.h | 4 + xen/include/xen/irq.h | 7 --- 12 files changed, 175 insertions(+), 60 deletions(-) diff -r b594583d6e44 -r b7eb2bb9b625 xen/arch/x86/hvm/irq.c --- a/xen/arch/x86/hvm/irq.c Tue Sep 18 15:11:39 2007 +0100 +++ b/xen/arch/x86/hvm/irq.c Tue Sep 18 16:09:19 2007 +0100 @@ -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; diff -r b594583d6e44 -r b7eb2bb9b625 xen/arch/x86/hvm/vioapic.c --- a/xen/arch/x86/hvm/vioapic.c Tue Sep 18 15:11:39 2007 +0100 +++ b/xen/arch/x86/hvm/vioapic.c Tue Sep 18 16:09:19 2007 +0100 @@ -458,6 +458,10 @@ void vioapic_update_EOI(struct domain *d 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] ) diff -r b594583d6e44 -r b7eb2bb9b625 xen/arch/x86/hvm/vmx/Makefile --- a/xen/arch/x86/hvm/vmx/Makefile Tue Sep 18 15:11:39 2007 +0100 +++ b/xen/arch/x86/hvm/vmx/Makefile Tue Sep 18 16:09:19 2007 +0100 @@ -1,3 +1,5 @@ subdir-$(x86_32) += x86_32 +subdir-y += vtd + subdir-$(x86_32) += x86_32 subdir-$(x86_64) += x86_64 diff -r b594583d6e44 -r b7eb2bb9b625 xen/arch/x86/hvm/vmx/intr.c --- a/xen/arch/x86/hvm/vmx/intr.c Tue Sep 18 15:11:39 2007 +0100 +++ b/xen/arch/x86/hvm/vmx/intr.c Tue Sep 18 16:09:19 2007 +0100 @@ -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 { diff -r b594583d6e44 -r b7eb2bb9b625 xen/arch/x86/hvm/vmx/vtd/dmar.c --- a/xen/arch/x86/hvm/vmx/vtd/dmar.c Tue Sep 18 15:11:39 2007 +0100 +++ b/xen/arch/x86/hvm/vmx/vtd/dmar.c Tue Sep 18 16:09:19 2007 +0100 @@ -30,6 +30,10 @@ #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, 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; - return 0; -} + } + + /* Use fake-vector style of IOAPIC acknowledgement. */ + if (vtd_enabled) + ioapic_ack_new = 0; + + return 0; +} diff -r b594583d6e44 -r b7eb2bb9b625 xen/arch/x86/hvm/vmx/vtd/intel-iommu.c --- a/xen/arch/x86/hvm/vmx/vtd/intel-iommu.c Tue Sep 18 15:11:39 2007 +0100 +++ b/xen/arch/x86/hvm/vmx/vtd/intel-iommu.c Tue Sep 18 16:09:19 2007 +0100 @@ -34,10 +34,16 @@ #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 @@ int iommu_set_interrupt(struct iommu *io 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 *io 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"); diff -r b594583d6e44 -r b7eb2bb9b625 xen/arch/x86/hvm/vmx/vtd/io.c --- a/xen/arch/x86/hvm/vmx/vtd/io.c Tue Sep 18 15:11:39 2007 +0100 +++ b/xen/arch/x86/hvm/vmx/vtd/io.c Tue Sep 18 16:09:19 2007 +0100 @@ -50,33 +50,31 @@ int hvm_do_IRQ_dpci(struct domain *d, un 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]; + + if ( !d->arch.hvm_domain.irq.girq[isa_irq].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]; + 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; + } - 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"); - } + dprintk(XENLOG_INFO, "mirq already pending\n"); return 0; } @@ -86,18 +84,21 @@ void hvm_dpci_eoi(unsigned int guest_gsi 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; } diff -r b594583d6e44 -r b7eb2bb9b625 xen/arch/x86/hvm/vmx/vtd/msi.h --- a/xen/arch/x86/hvm/vmx/vtd/msi.h Tue Sep 18 15:11:39 2007 +0100 +++ b/xen/arch/x86/hvm/vmx/vtd/msi.h Tue Sep 18 16:09:19 2007 +0100 @@ -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); /* diff -r b594583d6e44 -r b7eb2bb9b625 xen/arch/x86/hvm/vpic.c --- a/xen/arch/x86/hvm/vpic.c Tue Sep 18 15:11:39 2007 +0100 +++ b/xen/arch/x86/hvm/vpic.c Tue Sep 18 16:09:19 2007 +0100 @@ -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; diff -r b594583d6e44 -r b7eb2bb9b625 xen/arch/x86/io_apic.c --- a/xen/arch/x86/io_apic.c Tue Sep 18 15:11:39 2007 +0100 +++ b/xen/arch/x86/io_apic.c Tue Sep 18 16:09:19 2007 +0100 @@ -182,6 +182,68 @@ static void __modify_IO_APIC_irq (unsign break; entry = irq_2_pin + entry->next; } +} + +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 */ @@ -1356,7 +1418,11 @@ static void mask_and_ack_level_ioapic_ir 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 (unsign 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; } diff -r b594583d6e44 -r b7eb2bb9b625 xen/include/asm-x86/hvm/irq.h --- a/xen/include/asm-x86/hvm/irq.h Tue Sep 18 15:11:39 2007 +0100 +++ b/xen/include/asm-x86/hvm/irq.h Tue Sep 18 16:09:19 2007 +0100 @@ -114,7 +114,11 @@ 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); diff -r b594583d6e44 -r b7eb2bb9b625 xen/include/xen/irq.h --- a/xen/include/xen/irq.h Tue Sep 18 15:11:39 2007 +0100 +++ b/xen/include/xen/irq.h Tue Sep 18 16:09:19 2007 +0100 @@ -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 doma 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__ */ _______________________________________________ Xen-changelog mailing list Xen-changelog@xxxxxxxxxxxxxxxxxxx http://lists.xensource.com/xen-changelog
|
Lists.xenproject.org is hosted with RackSpace, monitoring our |