ia64/xen-unstable

changeset 15927:b7eb2bb9b625

IRQ injection changes for HVM PCI passthru.
Signed-off-by: Allen Kay <allen.m.kay@intel.com>
Signed-off-by: Guy Zana <guy@neocleus.com>
author kfraser@localhost.localdomain
date Tue Sep 18 16:09:19 2007 +0100 (2007-09-18)
parents b594583d6e44
children aad813d8a8ad
files 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
line diff
     1.1 --- a/xen/arch/x86/hvm/irq.c	Tue Sep 18 15:11:39 2007 +0100
     1.2 +++ b/xen/arch/x86/hvm/irq.c	Tue Sep 18 16:09:19 2007 +0100
     1.3 @@ -26,7 +26,7 @@
     1.4  #include <asm/hvm/domain.h>
     1.5  #include <asm/hvm/support.h>
     1.6  
     1.7 -static void __hvm_pci_intx_assert(
     1.8 +void __hvm_pci_intx_assert(
     1.9      struct domain *d, unsigned int device, unsigned int intx)
    1.10  {
    1.11      struct hvm_irq *hvm_irq = &d->arch.hvm_domain.irq;
    1.12 @@ -59,7 +59,7 @@ void hvm_pci_intx_assert(
    1.13      spin_unlock(&d->arch.hvm_domain.irq_lock);
    1.14  }
    1.15  
    1.16 -static void __hvm_pci_intx_deassert(
    1.17 +void __hvm_pci_intx_deassert(
    1.18      struct domain *d, unsigned int device, unsigned int intx)
    1.19  {
    1.20      struct hvm_irq *hvm_irq = &d->arch.hvm_domain.irq;
     2.1 --- a/xen/arch/x86/hvm/vioapic.c	Tue Sep 18 15:11:39 2007 +0100
     2.2 +++ b/xen/arch/x86/hvm/vioapic.c	Tue Sep 18 16:09:19 2007 +0100
     2.3 @@ -458,6 +458,10 @@ void vioapic_update_EOI(struct domain *d
     2.4      ent = &vioapic->redirtbl[gsi];
     2.5  
     2.6      ent->fields.remote_irr = 0;
     2.7 +
     2.8 +    if ( vtd_enabled )
     2.9 +        hvm_dpci_eoi(gsi, ent);
    2.10 +
    2.11      if ( (ent->fields.trig_mode == VIOAPIC_LEVEL_TRIG) &&
    2.12           !ent->fields.mask &&
    2.13           hvm_irq->gsi_assert_count[gsi] )
     3.1 --- a/xen/arch/x86/hvm/vmx/Makefile	Tue Sep 18 15:11:39 2007 +0100
     3.2 +++ b/xen/arch/x86/hvm/vmx/Makefile	Tue Sep 18 16:09:19 2007 +0100
     3.3 @@ -1,3 +1,5 @@
     3.4 +subdir-y += vtd
     3.5 +
     3.6  subdir-$(x86_32) += x86_32
     3.7  subdir-$(x86_64) += x86_64
     3.8  
     4.1 --- a/xen/arch/x86/hvm/vmx/intr.c	Tue Sep 18 15:11:39 2007 +0100
     4.2 +++ b/xen/arch/x86/hvm/vmx/intr.c	Tue Sep 18 16:09:19 2007 +0100
     4.3 @@ -138,6 +138,23 @@ static void update_tpr_threshold(
     4.4      __vmwrite(TPR_THRESHOLD, threshold);
     4.5  }
     4.6  
     4.7 +static void vmx_dirq_assist(struct domain *d)
     4.8 +{
     4.9 +    unsigned int irq;
    4.10 +    uint32_t device, intx;
    4.11 +    struct hvm_irq *hvm_irq = &d->arch.hvm_domain.irq;
    4.12 +
    4.13 +    for ( irq = find_first_bit(hvm_irq->dirq_mask, NR_IRQS);
    4.14 +          irq < NR_IRQS;
    4.15 +          irq = find_next_bit(hvm_irq->dirq_mask, NR_IRQS, irq + 1) )
    4.16 +    {
    4.17 +        test_and_clear_bit(irq, &hvm_irq->dirq_mask);
    4.18 +        device = hvm_irq->mirq[irq].device;
    4.19 +        intx = hvm_irq->mirq[irq].intx;
    4.20 +        hvm_pci_intx_assert(d, device, intx);
    4.21 +    }
    4.22 +}
    4.23 +
    4.24  asmlinkage void vmx_intr_assist(void)
    4.25  {
    4.26      int intr_vector;
    4.27 @@ -147,6 +164,10 @@ asmlinkage void vmx_intr_assist(void)
    4.28  
    4.29      /* Crank the handle on interrupt state. */
    4.30      pt_update_irq(v);
    4.31 +
    4.32 +    if ( vtd_enabled && (v->vcpu_id == 0) )
    4.33 +        vmx_dirq_assist(v->domain);
    4.34 +  
    4.35      hvm_set_callback_irq_level();
    4.36  
    4.37      do {
     5.1 --- a/xen/arch/x86/hvm/vmx/vtd/dmar.c	Tue Sep 18 15:11:39 2007 +0100
     5.2 +++ b/xen/arch/x86/hvm/vmx/vtd/dmar.c	Tue Sep 18 16:09:19 2007 +0100
     5.3 @@ -30,6 +30,10 @@
     5.4  #include "pci-direct.h"
     5.5  #include "pci_regs.h"
     5.6  
     5.7 +#define VTDPREFIX
     5.8 +int vtd_enabled;
     5.9 +boolean_param("vtd", vtd_enabled);
    5.10 +
    5.11  #undef PREFIX
    5.12  #define PREFIX VTDPREFIX "ACPI DMAR:"
    5.13  #define DEBUG
    5.14 @@ -484,11 +488,19 @@ acpi_parse_dmar(unsigned long phys_addr,
    5.15  
    5.16  int acpi_dmar_init(void)
    5.17  {
    5.18 +    extern int ioapic_ack_new;
    5.19 +
    5.20      acpi_table_parse(ACPI_DMAR, acpi_parse_dmar);
    5.21 +
    5.22      if (list_empty(&acpi_drhd_units)) {
    5.23          printk(KERN_ERR PREFIX "No DMAR devices found\n");
    5.24 +        vtd_enabled = 0;
    5.25          return -ENODEV;
    5.26 -    } else
    5.27 -        vtd_enabled = 1;
    5.28 +    }
    5.29 +
    5.30 +    /* Use fake-vector style of IOAPIC acknowledgement. */
    5.31 +    if (vtd_enabled)
    5.32 +        ioapic_ack_new = 0;
    5.33 +
    5.34      return 0;
    5.35  }
     6.1 --- a/xen/arch/x86/hvm/vmx/vtd/intel-iommu.c	Tue Sep 18 15:11:39 2007 +0100
     6.2 +++ b/xen/arch/x86/hvm/vmx/vtd/intel-iommu.c	Tue Sep 18 16:09:19 2007 +0100
     6.3 @@ -34,10 +34,16 @@
     6.4  #include "pci_regs.h"
     6.5  #include "msi.h"
     6.6  
     6.7 +#define VTDPREFIX
     6.8 +static inline int request_irq(int vector, void *func,
     6.9 +                              int flags, char *name, void *data)
    6.10 +{
    6.11 +    return -ENOSYS;
    6.12 +}
    6.13 +
    6.14  extern void print_iommu_regs(struct acpi_drhd_unit *drhd);
    6.15  extern void print_vtd_entries(struct domain *d, int bus, int devfn,
    6.16                         unsigned long gmfn);
    6.17 -extern void (*interrupt[])(void);
    6.18  
    6.19  #define DMAR_OPERATION_TIMEOUT (HZ*60) /* 1m */
    6.20  
    6.21 @@ -831,7 +837,6 @@ static struct hw_interrupt_type dma_msi_
    6.22  int iommu_set_interrupt(struct iommu *iommu)
    6.23  {
    6.24      int vector, ret;
    6.25 -    unsigned long flags;
    6.26  
    6.27      vector = assign_irq_vector(AUTO_ASSIGN);
    6.28      vector_to_iommu[vector] = iommu;
    6.29 @@ -845,10 +850,7 @@ int iommu_set_interrupt(struct iommu *io
    6.30          return -EINVAL;
    6.31      }
    6.32  
    6.33 -    spin_lock_irqsave(&irq_desc[vector].lock, flags);
    6.34      irq_desc[vector].handler = &dma_msi_type;
    6.35 -    spin_unlock_irqrestore(&irq_desc[vector].lock, flags);
    6.36 -    set_intr_gate(vector, interrupt[vector]);
    6.37      ret = request_irq(vector, iommu_page_fault, 0, "dmar", iommu);
    6.38      if (ret)
    6.39          gdprintk(XENLOG_ERR VTDPREFIX, "IOMMU: can't request irq\n");
     7.1 --- a/xen/arch/x86/hvm/vmx/vtd/io.c	Tue Sep 18 15:11:39 2007 +0100
     7.2 +++ b/xen/arch/x86/hvm/vmx/vtd/io.c	Tue Sep 18 16:09:19 2007 +0100
     7.3 @@ -50,33 +50,31 @@ int hvm_do_IRQ_dpci(struct domain *d, un
     7.4      uint32_t link, isa_irq;
     7.5      struct hvm_irq *hvm_irq;
     7.6  
     7.7 -    if (!vtd_enabled || (d == dom0))
     7.8 +    if ( !vtd_enabled || (d == dom0) ||
     7.9 +         !d->arch.hvm_domain.irq.mirq[mirq].valid )
    7.10          return 0;
    7.11  
    7.12 -    if (d->arch.hvm_domain.irq.mirq[mirq].valid)
    7.13 -    {
    7.14 -        device = d->arch.hvm_domain.irq.mirq[mirq].device;
    7.15 -        intx = d->arch.hvm_domain.irq.mirq[mirq].intx;
    7.16 -        link = hvm_pci_intx_link(device, intx);
    7.17 -        hvm_irq = &d->arch.hvm_domain.irq;
    7.18 -        isa_irq = hvm_irq->pci_link.route[link];
    7.19 +    device = d->arch.hvm_domain.irq.mirq[mirq].device;
    7.20 +    intx = d->arch.hvm_domain.irq.mirq[mirq].intx;
    7.21 +    link = hvm_pci_intx_link(device, intx);
    7.22 +    hvm_irq = &d->arch.hvm_domain.irq;
    7.23 +    isa_irq = hvm_irq->pci_link.route[link];
    7.24  
    7.25 -        if ( !d->arch.hvm_domain.irq.girq[isa_irq].valid )
    7.26 -        {
    7.27 -            d->arch.hvm_domain.irq.girq[isa_irq].valid = 1;
    7.28 -            d->arch.hvm_domain.irq.girq[isa_irq].device = device;
    7.29 -            d->arch.hvm_domain.irq.girq[isa_irq].intx = intx;
    7.30 -            d->arch.hvm_domain.irq.girq[isa_irq].machine_gsi = mirq;
    7.31 -        }
    7.32 +    if ( !d->arch.hvm_domain.irq.girq[isa_irq].valid )
    7.33 +    {
    7.34 +        d->arch.hvm_domain.irq.girq[isa_irq].valid = 1;
    7.35 +        d->arch.hvm_domain.irq.girq[isa_irq].device = device;
    7.36 +        d->arch.hvm_domain.irq.girq[isa_irq].intx = intx;
    7.37 +        d->arch.hvm_domain.irq.girq[isa_irq].machine_gsi = mirq;
    7.38 +    }
    7.39  
    7.40 -        if ( !test_and_set_bit(mirq, d->arch.hvm_domain.irq.dirq_mask) )
    7.41 -        {
    7.42 -            vcpu_kick(d->vcpu[0]);
    7.43 -            return 1;
    7.44 -        }
    7.45 -        else
    7.46 -            dprintk(XENLOG_INFO, "Want to pending mirq, but failed\n");
    7.47 +    if ( !test_and_set_bit(mirq, d->arch.hvm_domain.irq.dirq_mask) )
    7.48 +    {
    7.49 +        vcpu_kick(d->vcpu[0]);
    7.50 +        return 1;
    7.51      }
    7.52 +
    7.53 +    dprintk(XENLOG_INFO, "mirq already pending\n");
    7.54      return 0;
    7.55  }
    7.56  
    7.57 @@ -86,18 +84,21 @@ void hvm_dpci_eoi(unsigned int guest_gsi
    7.58      uint32_t device, intx, machine_gsi;
    7.59      irq_desc_t *desc;
    7.60  
    7.61 -    if (d->arch.hvm_domain.irq.girq[guest_gsi].valid)
    7.62 +    ASSERT(spin_is_locked(&d->arch.hvm_domain.irq_lock));
    7.63 +
    7.64 +    if ( !vtd_enabled || !d->arch.hvm_domain.irq.girq[guest_gsi].valid )
    7.65 +        return;
    7.66 +
    7.67 +    device = d->arch.hvm_domain.irq.girq[guest_gsi].device;
    7.68 +    intx = d->arch.hvm_domain.irq.girq[guest_gsi].intx;
    7.69 +    machine_gsi = d->arch.hvm_domain.irq.girq[guest_gsi].machine_gsi;
    7.70 +    gdprintk(XENLOG_INFO, "hvm_dpci_eoi:: device %x intx %x\n",
    7.71 +             device, intx);
    7.72 +    __hvm_pci_intx_deassert(d, device, intx);
    7.73 +    if ( (ent == NULL) || (ent->fields.mask == 0) )
    7.74      {
    7.75 -        device = d->arch.hvm_domain.irq.girq[guest_gsi].device;
    7.76 -        intx = d->arch.hvm_domain.irq.girq[guest_gsi].intx;
    7.77 -        machine_gsi = d->arch.hvm_domain.irq.girq[guest_gsi].machine_gsi;
    7.78 -        gdprintk(XENLOG_INFO, "hvm_dpci_eoi:: device %x intx %x\n",
    7.79 -            device, intx);
    7.80 -        hvm_pci_intx_deassert(d, device, intx);
    7.81 -        if ( (ent == NULL) || (ent && ent->fields.mask == 0) ) {
    7.82 -            desc = &irq_desc[irq_to_vector(machine_gsi)];
    7.83 -            desc->handler->end(irq_to_vector(machine_gsi));
    7.84 -        }
    7.85 +        desc = &irq_desc[irq_to_vector(machine_gsi)];
    7.86 +        desc->handler->end(irq_to_vector(machine_gsi));
    7.87      }
    7.88  }
    7.89  
    7.90 @@ -107,14 +108,13 @@ int release_devices(struct domain *d)
    7.91      uint32_t i;
    7.92      int ret = 0;
    7.93  
    7.94 -    if (!vtd_enabled)
    7.95 +    if ( !vtd_enabled )
    7.96          return ret;
    7.97  
    7.98 -    /* unbind irq */
    7.99 -    for (i = 0; i < NR_IRQS; i++) {
   7.100 -        if (hd->irq.mirq[i].valid)
   7.101 +    for ( i = 0; i < NR_IRQS; i++ )
   7.102 +        if ( hd->irq.mirq[i].valid )
   7.103              ret = pirq_guest_unbind(d, i);
   7.104 -    }
   7.105 +
   7.106      iommu_domain_teardown(d);
   7.107      return ret;
   7.108  }
     8.1 --- a/xen/arch/x86/hvm/vmx/vtd/msi.h	Tue Sep 18 15:11:39 2007 +0100
     8.2 +++ b/xen/arch/x86/hvm/vmx/vtd/msi.h	Tue Sep 18 16:09:19 2007 +0100
     8.3 @@ -17,7 +17,6 @@
     8.4  #define NR_HP_RESERVED_VECTORS 	20
     8.5  
     8.6  extern int vector_irq[NR_VECTORS];
     8.7 -extern void (*interrupt[NR_IRQS])(void);
     8.8  extern int pci_vector_resources(int last, int nr_released);
     8.9  
    8.10  /*
     9.1 --- a/xen/arch/x86/hvm/vpic.c	Tue Sep 18 15:11:39 2007 +0100
     9.2 +++ b/xen/arch/x86/hvm/vpic.c	Tue Sep 18 16:09:19 2007 +0100
     9.3 @@ -182,8 +182,7 @@ static void vpic_ioport_write(
     9.4  
     9.5      vpic_lock(vpic);
     9.6  
     9.7 -    addr &= 1;
     9.8 -    if ( addr == 0 )
     9.9 +    if ( (addr & 1) == 0 )
    9.10      {
    9.11          if ( val & 0x10 )
    9.12          {
    9.13 @@ -250,6 +249,11 @@ static void vpic_ioport_write(
    9.14                  vpic->isr &= ~(1 << irq);
    9.15                  if ( cmd == 7 )
    9.16                      vpic->priority_add = (irq + 1) & 7;
    9.17 +                if ( vtd_enabled )
    9.18 +                {
    9.19 +                    irq |= ((addr & 0xa0) == 0xa0) ? 8 : 0;
    9.20 +                    hvm_dpci_eoi(hvm_isa_irq_to_gsi(irq), NULL);
    9.21 +                }
    9.22                  break;
    9.23              case 6: /* Set Priority                */
    9.24                  vpic->priority_add = (val + 1) & 7;
    10.1 --- a/xen/arch/x86/io_apic.c	Tue Sep 18 15:11:39 2007 +0100
    10.2 +++ b/xen/arch/x86/io_apic.c	Tue Sep 18 16:09:19 2007 +0100
    10.3 @@ -184,6 +184,68 @@ static void __modify_IO_APIC_irq (unsign
    10.4      }
    10.5  }
    10.6  
    10.7 +static int real_vector[MAX_IRQ_SOURCES];
    10.8 +static int fake_vector=-1;
    10.9 +
   10.10 +/*
   10.11 + * Following 2 functions are used to workaround spurious interrupt
   10.12 + * problem related to mask/unmask of interrupts.  Instead we program
   10.13 + * an unused vector in the IOAPIC before issueing EOI to LAPIC.
   10.14 + */
   10.15 +static void write_fake_IO_APIC_vector (unsigned int irq)
   10.16 +{
   10.17 +    struct irq_pin_list *entry = irq_2_pin + irq;
   10.18 +    unsigned int pin, reg;
   10.19 +    unsigned long flags;
   10.20 +
   10.21 +    spin_lock_irqsave(&ioapic_lock, flags);
   10.22 +    for (;;) {
   10.23 +        pin = entry->pin;
   10.24 +        if (pin == -1)
   10.25 +            break;
   10.26 +        reg = io_apic_read(entry->apic, 0x10 + pin*2);
   10.27 +        real_vector[irq] = reg & 0xff;
   10.28 +        reg &= ~0xff;
   10.29 +
   10.30 +        if (fake_vector == -1)
   10.31 +            fake_vector = assign_irq_vector(MAX_IRQ_SOURCES-1);
   10.32 +
   10.33 +        reg |= fake_vector;
   10.34 +        io_apic_write(entry->apic, 0x10 + pin*2, reg);
   10.35 +
   10.36 +        if (!entry->next)
   10.37 +            break;
   10.38 +        entry = irq_2_pin + entry->next;
   10.39 +    }
   10.40 +    spin_unlock_irqrestore(&ioapic_lock, flags);
   10.41 +}
   10.42 +
   10.43 +static void restore_real_IO_APIC_vector (unsigned int irq)
   10.44 +{
   10.45 +    struct irq_pin_list *entry = irq_2_pin + irq;
   10.46 +    unsigned int pin, reg;
   10.47 +    unsigned long flags;
   10.48 +
   10.49 +    spin_lock_irqsave(&ioapic_lock, flags);
   10.50 +    for (;;) {
   10.51 +        pin = entry->pin;
   10.52 +        if (pin == -1)
   10.53 +            break;
   10.54 +
   10.55 +        reg = io_apic_read(entry->apic, 0x10 + pin*2);
   10.56 +        reg &= ~0xff;
   10.57 +        reg |= real_vector[irq];
   10.58 +        io_apic_write(entry->apic, 0x10 + pin*2, reg);
   10.59 +        mb();
   10.60 +        *(IO_APIC_BASE(entry->apic) + 0x10) = reg & 0xff;
   10.61 +
   10.62 +        if (!entry->next)
   10.63 +            break;
   10.64 +        entry = irq_2_pin + entry->next;
   10.65 +    }
   10.66 +    spin_unlock_irqrestore(&ioapic_lock, flags);
   10.67 +}
   10.68 +
   10.69  /* mask = 1 */
   10.70  static void __mask_IO_APIC_irq (unsigned int irq)
   10.71  {
   10.72 @@ -1356,7 +1418,11 @@ static void mask_and_ack_level_ioapic_ir
   10.73      if ( ioapic_ack_new )
   10.74          return;
   10.75  
   10.76 -    mask_IO_APIC_irq(irq);
   10.77 +    if ( vtd_enabled )
   10.78 +        write_fake_IO_APIC_vector(irq);
   10.79 +    else
   10.80 +        mask_IO_APIC_irq(irq);
   10.81 +
   10.82  /*
   10.83   * It appears there is an erratum which affects at least version 0x11
   10.84   * of I/O APIC (that's the 82093AA and cores integrated into various
   10.85 @@ -1398,8 +1464,12 @@ static void end_level_ioapic_irq (unsign
   10.86  
   10.87      if ( !ioapic_ack_new )
   10.88      {
   10.89 -        if ( !(irq_desc[IO_APIC_VECTOR(irq)].status & IRQ_DISABLED) )
   10.90 -            unmask_IO_APIC_irq(irq);
   10.91 +        if ( !(irq_desc[IO_APIC_VECTOR(irq)].status & IRQ_DISABLED) ) {
   10.92 +            if ( vtd_enabled )
   10.93 +                restore_real_IO_APIC_vector(irq);
   10.94 +            else
   10.95 +                unmask_IO_APIC_irq(irq);
   10.96 +        }
   10.97          return;
   10.98      }
   10.99  
    11.1 --- a/xen/include/asm-x86/hvm/irq.h	Tue Sep 18 15:11:39 2007 +0100
    11.2 +++ b/xen/include/asm-x86/hvm/irq.h	Tue Sep 18 16:09:19 2007 +0100
    11.3 @@ -114,8 +114,12 @@ struct hvm_irq {
    11.4  #define hvm_isa_irq_to_gsi(isa_irq) ((isa_irq) ? : 2)
    11.5  
    11.6  /* Modify state of a PCI INTx wire. */
    11.7 +void __hvm_pci_intx_assert(
    11.8 +    struct domain *d, unsigned int device, unsigned int intx);
    11.9  void hvm_pci_intx_assert(
   11.10      struct domain *d, unsigned int device, unsigned int intx);
   11.11 +void __hvm_pci_intx_deassert(
   11.12 +    struct domain *d, unsigned int device, unsigned int intx);
   11.13  void hvm_pci_intx_deassert(
   11.14      struct domain *d, unsigned int device, unsigned int intx);
   11.15  
    12.1 --- a/xen/include/xen/irq.h	Tue Sep 18 15:11:39 2007 +0100
    12.2 +++ b/xen/include/xen/irq.h	Tue Sep 18 16:09:19 2007 +0100
    12.3 @@ -64,9 +64,6 @@ extern irq_desc_t irq_desc[NR_IRQS];
    12.4  
    12.5  extern int setup_irq(unsigned int, struct irqaction *);
    12.6  extern void free_irq(unsigned int);
    12.7 -extern int request_irq(unsigned int irq,
    12.8 -               void (*handler)(int, void *, struct cpu_user_regs *),
    12.9 -               unsigned long irqflags, const char * devname, void *dev_id);
   12.10  
   12.11  extern hw_irq_controller no_irq_type;
   12.12  extern void no_action(int cpl, void *dev_id, struct cpu_user_regs *regs);
   12.13 @@ -80,11 +77,11 @@ extern int pirq_guest_unbind(struct doma
   12.14  
   12.15  static inline void set_native_irq_info(int irq, cpumask_t mask)
   12.16  {
   12.17 -	irq_desc[irq].affinity = mask;
   12.18 +    irq_desc[irq].affinity = mask;
   12.19  }
   12.20  
   12.21  static inline void set_irq_info(int irq, cpumask_t mask)
   12.22  {
   12.23 -	set_native_irq_info(irq, mask);
   12.24 +    set_native_irq_info(irq, mask);
   12.25  }
   12.26  #endif /* __XEN_IRQ_H__ */