ia64/xen-unstable

changeset 19005:9671a4d66f40

passthrough: MSI-INTx translation for HVM

The patch adds a new type of pt_irq: PT_IRQ_TYPE_MSI_TRANSLATE.
With it, guest dpci irq can now use msi as the underlying pirq
while injected as INTx irq.

Signed-off-by: Qing He <qing.he@intel.com>
author Keir Fraser <keir.fraser@citrix.com>
date Thu Jan 08 11:25:06 2009 +0000 (2009-01-08)
parents e9cd8e7c3b44
children 13c8e6bac9ab
files tools/libxc/xc_domain.c xen/arch/x86/hvm/vmsi.c xen/drivers/passthrough/io.c xen/include/public/domctl.h xen/include/xen/hvm/irq.h
line diff
     1.1 --- a/tools/libxc/xc_domain.c	Thu Jan 08 11:21:23 2009 +0000
     1.2 +++ b/tools/libxc/xc_domain.c	Thu Jan 08 11:25:06 2009 +0000
     1.3 @@ -958,7 +958,8 @@ int xc_domain_bind_pt_irq(
     1.4      bind->hvm_domid = domid;
     1.5      bind->irq_type = irq_type;
     1.6      bind->machine_irq = machine_irq;
     1.7 -    if ( irq_type == PT_IRQ_TYPE_PCI )
     1.8 +    if ( irq_type == PT_IRQ_TYPE_PCI ||
     1.9 +         irq_type == PT_IRQ_TYPE_MSI_TRANSLATE )
    1.10      {
    1.11          bind->u.pci.bus = bus;
    1.12          bind->u.pci.device = device;    
     2.1 --- a/xen/arch/x86/hvm/vmsi.c	Thu Jan 08 11:21:23 2009 +0000
     2.2 +++ b/xen/arch/x86/hvm/vmsi.c	Thu Jan 08 11:25:06 2009 +0000
     2.3 @@ -134,7 +134,7 @@ int vmsi_deliver(struct domain *d, int p
     2.4                  "vector=%x trig_mode=%x\n",
     2.5                  dest, dest_mode, delivery_mode, vector, trig_mode);
     2.6  
     2.7 -    if ( !test_bit(_HVM_IRQ_DPCI_MSI, &hvm_irq_dpci->mirq[pirq].flags) )
     2.8 +    if ( !( hvm_irq_dpci->mirq[pirq].flags & HVM_IRQ_DPCI_GUEST_MSI ) )
     2.9      {
    2.10          gdprintk(XENLOG_WARNING, "pirq %x not msi \n", pirq);
    2.11          return 0;
     3.1 --- a/xen/drivers/passthrough/io.c	Thu Jan 08 11:21:23 2009 +0000
     3.2 +++ b/xen/drivers/passthrough/io.c	Thu Jan 08 11:25:06 2009 +0000
     3.3 @@ -24,6 +24,11 @@
     3.4  #include <asm/hvm/iommu.h>
     3.5  #include <xen/hvm/irq.h>
     3.6  
     3.7 +static int pt_irq_need_timer(uint32_t flags)
     3.8 +{
     3.9 +    return !(flags & (HVM_IRQ_DPCI_GUEST_MSI | HVM_IRQ_DPCI_TRANSLATE));
    3.10 +}
    3.11 +
    3.12  static void pt_irq_time_out(void *data)
    3.13  {
    3.14      struct hvm_mirq_dpci_mapping *irq_map = data;
    3.15 @@ -93,7 +98,8 @@ int pt_irq_create_bind_vtd(
    3.16  
    3.17          if ( !test_and_set_bit(pirq, hvm_irq_dpci->mapping))
    3.18          {
    3.19 -            set_bit(_HVM_IRQ_DPCI_MSI, &hvm_irq_dpci->mirq[pirq].flags);
    3.20 +            hvm_irq_dpci->mirq[pirq].flags = HVM_IRQ_DPCI_MACH_MSI |
    3.21 +                                             HVM_IRQ_DPCI_GUEST_MSI;
    3.22              hvm_irq_dpci->mirq[pirq].gmsi.gvec = pt_irq_bind->u.msi.gvec;
    3.23              hvm_irq_dpci->mirq[pirq].gmsi.gflags = pt_irq_bind->u.msi.gflags;
    3.24              hvm_irq_dpci->msi_gvec_pirq[pt_irq_bind->u.msi.gvec] = pirq;
    3.25 @@ -104,7 +110,7 @@ int pt_irq_create_bind_vtd(
    3.26                  hvm_irq_dpci->msi_gvec_pirq[pt_irq_bind->u.msi.gvec] = 0;
    3.27                  hvm_irq_dpci->mirq[pirq].gmsi.gflags = 0;
    3.28                  hvm_irq_dpci->mirq[pirq].gmsi.gvec = 0;
    3.29 -                clear_bit(_HVM_IRQ_DPCI_MSI, &hvm_irq_dpci->mirq[pirq].flags);
    3.30 +                hvm_irq_dpci->mirq[pirq].flags = 0;
    3.31                  clear_bit(pirq, hvm_irq_dpci->mapping);
    3.32                  spin_unlock(&d->event_lock);
    3.33                  return rc;
    3.34 @@ -150,17 +156,33 @@ int pt_irq_create_bind_vtd(
    3.35          if ( !test_and_set_bit(machine_gsi, hvm_irq_dpci->mapping))
    3.36          {
    3.37              unsigned int vector = domain_irq_to_vector(d, machine_gsi);
    3.38 +            unsigned int share;
    3.39  
    3.40              hvm_irq_dpci->mirq[machine_gsi].dom = d;
    3.41 +            if ( pt_irq_bind->irq_type == PT_IRQ_TYPE_MSI_TRANSLATE )
    3.42 +            {
    3.43 +                hvm_irq_dpci->mirq[machine_gsi].flags = HVM_IRQ_DPCI_MACH_MSI |
    3.44 +                                                        HVM_IRQ_DPCI_GUEST_PCI |
    3.45 +                                                        HVM_IRQ_DPCI_TRANSLATE;
    3.46 +                share = 0;
    3.47 +            }
    3.48 +            else    /* PT_IRQ_TYPE_PCI */
    3.49 +            {
    3.50 +                hvm_irq_dpci->mirq[machine_gsi].flags = HVM_IRQ_DPCI_MACH_PCI |
    3.51 +                                                        HVM_IRQ_DPCI_GUEST_PCI;
    3.52 +                share = BIND_PIRQ__WILL_SHARE;
    3.53 +            }
    3.54  
    3.55              /* Init timer before binding */
    3.56 -            init_timer(&hvm_irq_dpci->hvm_timer[vector],
    3.57 -                       pt_irq_time_out, &hvm_irq_dpci->mirq[machine_gsi], 0);
    3.58 +            if ( pt_irq_need_timer(hvm_irq_dpci->mirq[machine_gsi].flags) )
    3.59 +                init_timer(&hvm_irq_dpci->hvm_timer[vector],
    3.60 +                           pt_irq_time_out, &hvm_irq_dpci->mirq[machine_gsi], 0);
    3.61              /* Deal with gsi for legacy devices */
    3.62 -            rc = pirq_guest_bind(d->vcpu[0], machine_gsi, BIND_PIRQ__WILL_SHARE);
    3.63 +            rc = pirq_guest_bind(d->vcpu[0], machine_gsi, share);
    3.64              if ( unlikely(rc) )
    3.65              {
    3.66 -                kill_timer(&hvm_irq_dpci->hvm_timer[vector]);
    3.67 +                if ( pt_irq_need_timer(hvm_irq_dpci->mirq[machine_gsi].flags) )
    3.68 +                    kill_timer(&hvm_irq_dpci->hvm_timer[vector]);
    3.69                  hvm_irq_dpci->mirq[machine_gsi].dom = NULL;
    3.70                  clear_bit(machine_gsi, hvm_irq_dpci->mapping);
    3.71                  hvm_irq_dpci->girq[guest_gsi].machine_gsi = 0;
    3.72 @@ -237,7 +259,8 @@ int pt_irq_destroy_bind_vtd(
    3.73          if ( list_empty(&hvm_irq_dpci->mirq[machine_gsi].digl_list) )
    3.74          {
    3.75              pirq_guest_unbind(d, machine_gsi);
    3.76 -            kill_timer(&hvm_irq_dpci->hvm_timer[domain_irq_to_vector(d, machine_gsi)]);
    3.77 +            if ( pt_irq_need_timer(hvm_irq_dpci->mirq[machine_gsi].flags) )
    3.78 +                kill_timer(&hvm_irq_dpci->hvm_timer[domain_irq_to_vector(d, machine_gsi)]);
    3.79              hvm_irq_dpci->mirq[machine_gsi].dom   = NULL;
    3.80              hvm_irq_dpci->mirq[machine_gsi].flags = 0;
    3.81              clear_bit(machine_gsi, hvm_irq_dpci->mapping);
    3.82 @@ -267,7 +290,7 @@ int hvm_do_IRQ_dpci(struct domain *d, un
    3.83       * PIC) and we need to detect that.
    3.84       */
    3.85      set_bit(mirq, dpci->dirq_mask);
    3.86 -    if ( !test_bit(_HVM_IRQ_DPCI_MSI, &dpci->mirq[mirq].flags) )
    3.87 +    if ( pt_irq_need_timer(dpci->mirq[mirq].flags) )
    3.88          set_timer(&dpci->hvm_timer[domain_irq_to_vector(d, mirq)],
    3.89                    NOW() + PT_IRQ_TIME_OUT);
    3.90      vcpu_kick(d->vcpu[0]);
    3.91 @@ -276,35 +299,40 @@ int hvm_do_IRQ_dpci(struct domain *d, un
    3.92  }
    3.93  
    3.94  #ifdef SUPPORT_MSI_REMAPPING
    3.95 +/* called with d->event_lock held */
    3.96 +static void __msi_pirq_eoi(struct domain *d, int pirq)
    3.97 +{
    3.98 +    struct hvm_irq_dpci *hvm_irq_dpci = d->arch.hvm_domain.irq.dpci;
    3.99 +    irq_desc_t *desc;
   3.100 +
   3.101 +    if ( ( pirq >= 0 ) && ( pirq < NR_IRQS ) &&
   3.102 +         test_bit(pirq, hvm_irq_dpci->mapping) &&
   3.103 +         ( hvm_irq_dpci->mirq[pirq].flags & HVM_IRQ_DPCI_MACH_MSI) )
   3.104 +    {
   3.105 +         BUG_ON(!local_irq_is_enabled());
   3.106 +         desc = domain_spin_lock_irq_desc(d, pirq, NULL);
   3.107 +         if ( !desc )
   3.108 +            return;
   3.109 +
   3.110 +         desc->status &= ~IRQ_INPROGRESS;
   3.111 +         spin_unlock_irq(&desc->lock);
   3.112 +
   3.113 +         pirq_guest_eoi(d, pirq);
   3.114 +    }
   3.115 +}
   3.116 +
   3.117  void hvm_dpci_msi_eoi(struct domain *d, int vector)
   3.118  {
   3.119      struct hvm_irq_dpci *hvm_irq_dpci = d->arch.hvm_domain.irq.dpci;
   3.120 -    irq_desc_t *desc;
   3.121      int pirq;
   3.122  
   3.123      if ( !iommu_enabled || (hvm_irq_dpci == NULL) )
   3.124         return;
   3.125  
   3.126      spin_lock(&d->event_lock);
   3.127 +
   3.128      pirq = hvm_irq_dpci->msi_gvec_pirq[vector];
   3.129 -
   3.130 -    if ( ( pirq >= 0 ) && (pirq < NR_IRQS) &&
   3.131 -          test_bit(pirq, hvm_irq_dpci->mapping) &&
   3.132 -         (test_bit(_HVM_IRQ_DPCI_MSI, &hvm_irq_dpci->mirq[pirq].flags)))
   3.133 -     {
   3.134 -         BUG_ON(!local_irq_is_enabled());
   3.135 -         desc = domain_spin_lock_irq_desc(d, pirq, NULL);
   3.136 -         if (!desc)
   3.137 -         {
   3.138 -            spin_unlock(&d->event_lock);
   3.139 -            return;
   3.140 -         }
   3.141 -
   3.142 -         desc->status &= ~IRQ_INPROGRESS;
   3.143 -         spin_unlock_irq(&desc->lock);
   3.144 -
   3.145 -         pirq_guest_eoi(d, pirq);
   3.146 -     }
   3.147 +    __msi_pirq_eoi(d, pirq);
   3.148  
   3.149      spin_unlock(&d->event_lock);
   3.150  }
   3.151 @@ -336,14 +364,15 @@ void hvm_dirq_assist(struct vcpu *v)
   3.152  
   3.153          spin_lock(&d->event_lock);
   3.154  #ifdef SUPPORT_MSI_REMAPPING
   3.155 -        if ( test_bit(_HVM_IRQ_DPCI_MSI, &hvm_irq_dpci->mirq[irq].flags) )
   3.156 +        if ( hvm_irq_dpci->mirq[irq].flags & HVM_IRQ_DPCI_GUEST_MSI )
   3.157          {
   3.158              hvm_pci_msi_assert(d, irq);
   3.159              spin_unlock(&d->event_lock);
   3.160              continue;
   3.161          }
   3.162  #endif
   3.163 -        stop_timer(&hvm_irq_dpci->hvm_timer[domain_irq_to_vector(d, irq)]);
   3.164 +        if ( pt_irq_need_timer(hvm_irq_dpci->mirq[irq].flags) )
   3.165 +            stop_timer(&hvm_irq_dpci->hvm_timer[domain_irq_to_vector(d, irq)]);
   3.166  
   3.167          list_for_each_entry ( digl, &hvm_irq_dpci->mirq[irq].digl_list, list )
   3.168          {
   3.169 @@ -351,6 +380,14 @@ void hvm_dirq_assist(struct vcpu *v)
   3.170              intx = digl->intx;
   3.171              hvm_pci_intx_assert(d, device, intx);
   3.172              hvm_irq_dpci->mirq[irq].pending++;
   3.173 +
   3.174 +#ifdef SUPPORT_MSI_REMAPPING
   3.175 +            if ( hvm_irq_dpci->mirq[irq].flags & HVM_IRQ_DPCI_TRANSLATE )
   3.176 +            {
   3.177 +                /* for translated MSI to INTx interrupt, eoi as early as possible */
   3.178 +                __msi_pirq_eoi(d, irq);
   3.179 +            }
   3.180 +#endif
   3.181          }
   3.182  
   3.183          /*
   3.184 @@ -360,8 +397,9 @@ void hvm_dirq_assist(struct vcpu *v)
   3.185           * guest will never deal with the irq, then the physical interrupt line
   3.186           * will never be deasserted.
   3.187           */
   3.188 -        set_timer(&hvm_irq_dpci->hvm_timer[domain_irq_to_vector(d, irq)],
   3.189 -                  NOW() + PT_IRQ_TIME_OUT);
   3.190 +        if ( pt_irq_need_timer(hvm_irq_dpci->mirq[irq].flags) )
   3.191 +            set_timer(&hvm_irq_dpci->hvm_timer[domain_irq_to_vector(d, irq)],
   3.192 +                      NOW() + PT_IRQ_TIME_OUT);
   3.193          spin_unlock(&d->event_lock);
   3.194      }
   3.195  }
   3.196 @@ -405,9 +443,12 @@ void hvm_dpci_eoi(struct domain *d, unsi
   3.197               * No need to get vector lock for timer
   3.198               * since interrupt is still not EOIed
   3.199               */
   3.200 -            stop_timer(&hvm_irq_dpci->hvm_timer[
   3.201 -                domain_irq_to_vector(d, machine_gsi)]);
   3.202 -            pirq_guest_eoi(d, machine_gsi);
   3.203 +            if ( pt_irq_need_timer(hvm_irq_dpci->mirq[machine_gsi].flags) )
   3.204 +            {
   3.205 +                stop_timer(&hvm_irq_dpci->hvm_timer[
   3.206 +                    domain_irq_to_vector(d, machine_gsi)]);
   3.207 +                pirq_guest_eoi(d, machine_gsi);
   3.208 +            }
   3.209          }
   3.210      }
   3.211      spin_unlock(&d->event_lock);
     4.1 --- a/xen/include/public/domctl.h	Thu Jan 08 11:21:23 2009 +0000
     4.2 +++ b/xen/include/public/domctl.h	Thu Jan 08 11:25:06 2009 +0000
     4.3 @@ -466,6 +466,7 @@ typedef enum pt_irq_type_e {
     4.4      PT_IRQ_TYPE_PCI,
     4.5      PT_IRQ_TYPE_ISA,
     4.6      PT_IRQ_TYPE_MSI,
     4.7 +    PT_IRQ_TYPE_MSI_TRANSLATE,
     4.8  } pt_irq_type_t;
     4.9  struct xen_domctl_bind_pt_irq {
    4.10      uint32_t machine_irq;
     5.1 --- a/xen/include/xen/hvm/irq.h	Thu Jan 08 11:21:23 2009 +0000
     5.2 +++ b/xen/include/xen/hvm/irq.h	Thu Jan 08 11:25:06 2009 +0000
     5.3 @@ -35,7 +35,16 @@ struct dev_intx_gsi_link {
     5.4      uint8_t link;
     5.5  };
     5.6  
     5.7 -#define _HVM_IRQ_DPCI_MSI  0x1
     5.8 +#define _HVM_IRQ_DPCI_MACH_PCI_SHIFT            0
     5.9 +#define _HVM_IRQ_DPCI_MACH_MSI_SHIFT            1
    5.10 +#define _HVM_IRQ_DPCI_GUEST_PCI_SHIFT           4
    5.11 +#define _HVM_IRQ_DPCI_GUEST_MSI_SHIFT           5
    5.12 +#define _HVM_IRQ_DPCI_TRANSLATE_SHIFT          15
    5.13 +#define HVM_IRQ_DPCI_MACH_PCI        (1 << _HVM_IRQ_DPCI_MACH_PCI_SHIFT)
    5.14 +#define HVM_IRQ_DPCI_MACH_MSI        (1 << _HVM_IRQ_DPCI_MACH_MSI_SHIFT)
    5.15 +#define HVM_IRQ_DPCI_GUEST_PCI       (1 << _HVM_IRQ_DPCI_GUEST_PCI_SHIFT)
    5.16 +#define HVM_IRQ_DPCI_GUEST_MSI       (1 << _HVM_IRQ_DPCI_GUEST_MSI_SHIFT)
    5.17 +#define HVM_IRQ_DPCI_TRANSLATE       (1 << _HVM_IRQ_DPCI_TRANSLATE_SHIFT)
    5.18  
    5.19  struct hvm_gmsi_info {
    5.20      uint32_t gvec;