ia64/xen-unstable

changeset 17541:6ecbb00e58cd

MSI 2/6: change the pirq to be per-domain

Signed-off-by: Jiang Yunhong <yunhong.jiang@intel.com>
Signed-off-by: Shan Haitao <haitao.shan@intel.com>
author Keir Fraser <keir.fraser@citrix.com>
date Thu May 01 10:30:22 2008 +0100 (2008-05-01)
parents 8bced3d8a907
children 86c0353f19d0
files tools/ioemu/hw/pass-through.c tools/libxc/xc_physdev.c tools/libxc/xc_private.h tools/libxc/xenctrl.h tools/python/xen/lowlevel/xc/xc.c tools/python/xen/xend/server/irqif.py tools/python/xen/xend/server/pciif.py xen/arch/x86/domain.c xen/arch/x86/hvm/vmx/intr.c xen/arch/x86/io_apic.c xen/arch/x86/irq.c xen/arch/x86/physdev.c xen/drivers/passthrough/io.c xen/drivers/passthrough/vtd/x86/vtd.c xen/include/asm-x86/domain.h xen/include/asm-x86/irq.h xen/include/asm-x86/pirq.h xen/include/public/physdev.h
line diff
     1.1 --- a/tools/ioemu/hw/pass-through.c	Thu May 01 10:26:58 2008 +0100
     1.2 +++ b/tools/ioemu/hw/pass-through.c	Thu May 01 10:30:22 2008 +0100
     1.3 @@ -519,7 +519,21 @@ struct pt_dev * register_real_device(PCI
     1.4      e_intx = assigned_device->dev.config[0x3d]-1;
     1.5  
     1.6      if ( PT_MACHINE_IRQ_AUTO == machine_irq )
     1.7 +    {
     1.8 +        int pirq = pci_dev->irq;
     1.9 +
    1.10          machine_irq = pci_dev->irq;
    1.11 +        rc = xc_physdev_map_pirq(xc_handle, domid, MAP_PIRQ_TYPE_GSI,
    1.12 +                                machine_irq, &pirq);
    1.13 +
    1.14 +        if ( rc )
    1.15 +        {
    1.16 +            /* TBD: unregister device in case of an error */
    1.17 +            PT_LOG("Error: Mapping irq failed, rc = %d\n", rc);
    1.18 +        }
    1.19 +        else
    1.20 +            machine_irq = pirq;
    1.21 +    }
    1.22  
    1.23      /* bind machine_irq to device */
    1.24      if ( 0 != machine_irq )
     2.1 --- a/tools/libxc/xc_physdev.c	Thu May 01 10:26:58 2008 +0100
     2.2 +++ b/tools/libxc/xc_physdev.c	Thu May 01 10:30:22 2008 +0100
     2.3 @@ -19,3 +19,43 @@ int xc_physdev_pci_access_modify(int xc_
     2.4      errno = ENOSYS;
     2.5      return -1;
     2.6  }
     2.7 +
     2.8 +int xc_physdev_map_pirq(int xc_handle,
     2.9 +                        int domid,
    2.10 +                        int type,
    2.11 +                        int index,
    2.12 +                        int *pirq)
    2.13 +{
    2.14 +    int rc;
    2.15 +    struct physdev_map_pirq map;
    2.16 +
    2.17 +    if ( !pirq )
    2.18 +        return -EINVAL;
    2.19 +
    2.20 +    map.domid = domid;
    2.21 +    map.type = type;
    2.22 +    map.index = index;
    2.23 +    map.pirq = *pirq;
    2.24 +
    2.25 +    rc = do_physdev_op(xc_handle, PHYSDEVOP_map_pirq, &map);
    2.26 +
    2.27 +    if ( !rc )
    2.28 +        *pirq = map.pirq;
    2.29 +
    2.30 +    return rc;
    2.31 +}
    2.32 +
    2.33 +int xc_physdev_unmap_pirq(int xc_handle,
    2.34 +                          int domid,
    2.35 +                          int pirq)
    2.36 +{
    2.37 +    int rc;
    2.38 +    struct physdev_unmap_pirq unmap;
    2.39 +
    2.40 +    unmap.domid = domid;
    2.41 +    unmap.pirq = pirq;
    2.42 +
    2.43 +    rc = do_physdev_op(xc_handle, PHYSDEVOP_unmap_pirq, &unmap);
    2.44 +
    2.45 +    return rc;
    2.46 +}
     3.1 --- a/tools/libxc/xc_private.h	Thu May 01 10:26:58 2008 +0100
     3.2 +++ b/tools/libxc/xc_private.h	Thu May 01 10:30:22 2008 +0100
     3.3 @@ -24,10 +24,12 @@
     3.4  #define DECLARE_HYPERCALL privcmd_hypercall_t hypercall = { 0 }
     3.5  #define DECLARE_DOMCTL struct xen_domctl domctl = { 0 }
     3.6  #define DECLARE_SYSCTL struct xen_sysctl sysctl = { 0 }
     3.7 +#define DECLARE_PHYSDEV_OP struct physdev_op physdev_op = { 0 }
     3.8  #else
     3.9  #define DECLARE_HYPERCALL privcmd_hypercall_t hypercall
    3.10  #define DECLARE_DOMCTL struct xen_domctl domctl
    3.11  #define DECLARE_SYSCTL struct xen_sysctl sysctl
    3.12 +#define DECLARE_PHYSDEV_OP struct physdev_op physdev_op
    3.13  #endif
    3.14  
    3.15  #undef PAGE_SHIFT
    3.16 @@ -96,6 +98,34 @@ static inline int do_xen_version(int xc_
    3.17      return do_xen_hypercall(xc_handle, &hypercall);
    3.18  }
    3.19  
    3.20 +static inline int do_physdev_op(int xc_handle, int cmd, void *op)
    3.21 +{
    3.22 +    int ret = -1;
    3.23 +
    3.24 +    DECLARE_HYPERCALL;
    3.25 +    hypercall.op = __HYPERVISOR_physdev_op;
    3.26 +    hypercall.arg[0] = (unsigned long) cmd;
    3.27 +    hypercall.arg[1] = (unsigned long) op;
    3.28 +
    3.29 +    if ( lock_pages(op, sizeof(*op)) != 0 )
    3.30 +    {
    3.31 +        PERROR("Could not lock memory for Xen hypercall");
    3.32 +        goto out1;
    3.33 +    }
    3.34 +
    3.35 +    if ( (ret = do_xen_hypercall(xc_handle, &hypercall)) < 0 )
    3.36 +    {
    3.37 +        if ( errno == EACCES )
    3.38 +            DPRINTF("physdev operation failed -- need to"
    3.39 +                    " rebuild the user-space tool set?\n");
    3.40 +    }
    3.41 +
    3.42 +    unlock_pages(op, sizeof(*op));
    3.43 +
    3.44 +out1:
    3.45 +    return ret;
    3.46 +}
    3.47 +
    3.48  static inline int do_domctl(int xc_handle, struct xen_domctl *domctl)
    3.49  {
    3.50      int ret = -1;
     4.1 --- a/tools/libxc/xenctrl.h	Thu May 01 10:26:58 2008 +0100
     4.2 +++ b/tools/libxc/xenctrl.h	Thu May 01 10:30:22 2008 +0100
     4.3 @@ -21,6 +21,7 @@
     4.4  #include <stdint.h>
     4.5  #include <xen/xen.h>
     4.6  #include <xen/domctl.h>
     4.7 +#include <xen/physdev.h>
     4.8  #include <xen/sysctl.h>
     4.9  #include <xen/version.h>
    4.10  #include <xen/event_channel.h>
    4.11 @@ -849,6 +850,16 @@ int xc_gnttab_munmap(int xcg_handle,
    4.12  int xc_gnttab_set_max_grants(int xcg_handle,
    4.13  			     uint32_t count);
    4.14  
    4.15 +int xc_physdev_map_pirq(int xc_handle,
    4.16 +                        int domid,
    4.17 +                        int type,
    4.18 +                        int index,
    4.19 +                        int *pirq);
    4.20 +
    4.21 +int xc_physdev_unmap_pirq(int xc_handle,
    4.22 +                          int domid,
    4.23 +                          int pirq);
    4.24 +
    4.25  int xc_hvm_set_pci_intx_level(
    4.26      int xc_handle, domid_t dom,
    4.27      uint8_t domain, uint8_t bus, uint8_t device, uint8_t intx,
     5.1 --- a/tools/python/xen/lowlevel/xc/xc.c	Thu May 01 10:26:58 2008 +0100
     5.2 +++ b/tools/python/xen/lowlevel/xc/xc.c	Thu May 01 10:30:22 2008 +0100
     5.3 @@ -799,6 +799,26 @@ static PyObject *pyxc_evtchn_reset(XcObj
     5.4      return zero;
     5.5  }
     5.6  
     5.7 +static PyObject *pyxc_physdev_map_pirq(PyObject *self,
     5.8 +                                       PyObject *args,
     5.9 +                                       PyObject *kwds)
    5.10 +{
    5.11 +    XcObject *xc = (XcObject *)self;
    5.12 +    uint32_t dom;
    5.13 +    int index, pirq, ret;
    5.14 +
    5.15 +    static char *kwd_list[] = {"domid", "index", "pirq", NULL};
    5.16 +
    5.17 +    if ( !PyArg_ParseTupleAndKeywords(args, kwds, "iii", kwd_list,
    5.18 +                                      &dom, &index, &pirq) )
    5.19 +        return NULL;
    5.20 +    ret = xc_physdev_map_pirq(xc->xc_handle, dom, MAP_PIRQ_TYPE_GSI,
    5.21 +                             index, &pirq);
    5.22 +    if ( ret != 0 )
    5.23 +          return pyxc_error_to_exception();
    5.24 +    return PyLong_FromUnsignedLong(pirq);
    5.25 +}
    5.26 +
    5.27  static PyObject *pyxc_physdev_pci_access_modify(XcObject *self,
    5.28                                                  PyObject *args,
    5.29                                                  PyObject *kwds)
    5.30 @@ -1589,6 +1609,15 @@ static PyMethodDef pyxc_methods[] = {
    5.31        "Reset all connections.\n"
    5.32        " dom [int]: Domain to reset.\n" },
    5.33  
    5.34 +    { "physdev_map_pirq",
    5.35 +      (PyCFunction)pyxc_physdev_map_pirq,
    5.36 +      METH_VARARGS | METH_KEYWORDS, "\n"
    5.37 +      "map physical irq to guest pirq.\n"
    5.38 +      " dom     [int]:      Identifier of domain to map for.\n"
    5.39 +      " index   [int]:      physical irq.\n"
    5.40 +      " pirq    [int]:      guest pirq.\n"
    5.41 +      "Returns: [long] value of the param.\n" },
    5.42 +
    5.43      { "physdev_pci_access_modify",
    5.44        (PyCFunction)pyxc_physdev_pci_access_modify,
    5.45        METH_VARARGS | METH_KEYWORDS, "\n"
     6.1 --- a/tools/python/xen/xend/server/irqif.py	Thu May 01 10:26:58 2008 +0100
     6.2 +++ b/tools/python/xen/xend/server/irqif.py	Thu May 01 10:30:22 2008 +0100
     6.3 @@ -69,5 +69,10 @@ class IRQController(DevController):
     6.4              #todo non-fatal
     6.5              raise VmError(
     6.6                  'irq: Failed to configure irq: %d' % (pirq))
     6.7 -
     6.8 +        rc = xc.physdev_map_pirq(domid = self.getDomid(),
     6.9 +                                index = pirq,
    6.10 +                                pirq  = pirq)
    6.11 +        if rc < 0:
    6.12 +            raise VmError(
    6.13 +                'irq: Failed to map irq %x' % (pirq))
    6.14          return (None, {}, {})
     7.1 --- a/tools/python/xen/xend/server/pciif.py	Thu May 01 10:26:58 2008 +0100
     7.2 +++ b/tools/python/xen/xend/server/pciif.py	Thu May 01 10:30:22 2008 +0100
     7.3 @@ -271,6 +271,12 @@ class PciController(DevController):
     7.4              if rc<0:
     7.5                  raise VmError(('pci: failed to configure I/O memory on device '+
     7.6                              '%s - errno=%d')%(dev.name,rc))
     7.7 +            rc = xc.physdev_map_pirq(domid = fe_domid,
     7.8 +                                   index = dev.irq,
     7.9 +                                   pirq  = dev.irq)
    7.10 +            if rc < 0:
    7.11 +                raise VmError(('pci: failed to map irq on device '+
    7.12 +                            '%s - errno=%d')%(dev.name,rc))
    7.13  
    7.14          if dev.irq>0:
    7.15              log.debug('pci: enabling irq %d'%dev.irq)
     8.1 --- a/xen/arch/x86/domain.c	Thu May 01 10:26:58 2008 +0100
     8.2 +++ b/xen/arch/x86/domain.c	Thu May 01 10:30:22 2008 +0100
     8.3 @@ -525,6 +525,8 @@ int arch_domain_create(struct domain *d,
     8.4              goto fail;
     8.5      }
     8.6  
     8.7 +    spin_lock_init(&d->arch.irq_lock);
     8.8 +
     8.9      if ( is_hvm_domain(d) )
    8.10      {
    8.11          if ( (rc = hvm_domain_initialise(d)) != 0 )
     9.1 --- a/xen/arch/x86/hvm/vmx/intr.c	Thu May 01 10:26:58 2008 +0100
     9.2 +++ b/xen/arch/x86/hvm/vmx/intr.c	Thu May 01 10:30:22 2008 +0100
     9.3 @@ -121,7 +121,7 @@ static void vmx_dirq_assist(struct vcpu 
     9.4          if ( !test_and_clear_bit(irq, &hvm_irq_dpci->dirq_mask) )
     9.5              continue;
     9.6  
     9.7 -        stop_timer(&hvm_irq_dpci->hvm_timer[irq_to_vector(irq)]);
     9.8 +        stop_timer(&hvm_irq_dpci->hvm_timer[domain_irq_to_vector(d, irq)]);
     9.9  
    9.10          list_for_each_entry ( digl, &hvm_irq_dpci->mirq[irq].digl_list, list )
    9.11          {
    9.12 @@ -140,7 +140,7 @@ static void vmx_dirq_assist(struct vcpu 
    9.13           * guest will never deal with the irq, then the physical interrupt line
    9.14           * will never be deasserted.
    9.15           */
    9.16 -        set_timer(&hvm_irq_dpci->hvm_timer[irq_to_vector(irq)],
    9.17 +        set_timer(&hvm_irq_dpci->hvm_timer[domain_irq_to_vector(d, irq)],
    9.18                    NOW() + PT_IRQ_TIME_OUT);
    9.19      }
    9.20  }
    10.1 --- a/xen/arch/x86/io_apic.c	Thu May 01 10:26:58 2008 +0100
    10.2 +++ b/xen/arch/x86/io_apic.c	Thu May 01 10:30:22 2008 +0100
    10.3 @@ -41,6 +41,25 @@
    10.4  int (*ioapic_renumber_irq)(int ioapic, int irq);
    10.5  atomic_t irq_mis_count;
    10.6  
    10.7 +int msi_irq_enable = 0;
    10.8 +boolean_param("msi_irq_enable", msi_irq_enable);
    10.9 +
   10.10 +int domain_irq_to_vector(struct domain *d, int irq)
   10.11 +{
   10.12 +    if ( !msi_irq_enable )
   10.13 +        return irq_to_vector(irq);
   10.14 +    else
   10.15 +        return d->arch.pirq_vector[irq];
   10.16 +}
   10.17 +
   10.18 +int domain_vector_to_irq(struct domain *d, int vector)
   10.19 +{
   10.20 +    if ( !msi_irq_enable )
   10.21 +        return vector_to_irq(vector);
   10.22 +    else
   10.23 +        return d->arch.vector_pirq[vector];
   10.24 +}
   10.25 +
   10.26  /* Where if anywhere is the i8259 connect in external int mode */
   10.27  static struct { int pin, apic; } ioapic_i8259 = { -1, -1 };
   10.28  
    11.1 --- a/xen/arch/x86/irq.c	Thu May 01 10:26:58 2008 +0100
    11.2 +++ b/xen/arch/x86/irq.c	Thu May 01 10:30:22 2008 +0100
    11.3 @@ -203,7 +203,6 @@ static DEFINE_PER_CPU(struct pending_eoi
    11.4  
    11.5  static void __do_IRQ_guest(int vector)
    11.6  {
    11.7 -    unsigned int        irq = vector_to_irq(vector);
    11.8      irq_desc_t         *desc = &irq_desc[vector];
    11.9      irq_guest_action_t *action = (irq_guest_action_t *)desc->action;
   11.10      struct domain      *d;
   11.11 @@ -232,7 +231,9 @@ static void __do_IRQ_guest(int vector)
   11.12  
   11.13      for ( i = 0; i < action->nr_guests; i++ )
   11.14      {
   11.15 +        unsigned int irq;
   11.16          d = action->guest[i];
   11.17 +        irq = domain_vector_to_irq(d, vector);
   11.18          if ( (action->ack_type != ACKTYPE_NONE) &&
   11.19               !test_and_set_bit(irq, d->pirq_mask) )
   11.20              action->in_flight++;
   11.21 @@ -305,8 +306,10 @@ static void __pirq_guest_eoi(struct doma
   11.22      irq_desc_t         *desc;
   11.23      irq_guest_action_t *action;
   11.24      cpumask_t           cpu_eoi_map;
   11.25 +    int                 vector;
   11.26  
   11.27 -    desc   = &irq_desc[irq_to_vector(irq)];
   11.28 +    vector = domain_irq_to_vector(d, irq);
   11.29 +    desc   = &irq_desc[vector];
   11.30      action = (irq_guest_action_t *)desc->action;
   11.31  
   11.32      spin_lock_irq(&desc->lock);
   11.33 @@ -324,7 +327,7 @@ static void __pirq_guest_eoi(struct doma
   11.34      if ( action->ack_type == ACKTYPE_UNMASK )
   11.35      {
   11.36          ASSERT(cpus_empty(action->cpu_eoi_map));
   11.37 -        desc->handler->end(irq_to_vector(irq));
   11.38 +        desc->handler->end(vector);
   11.39          spin_unlock_irq(&desc->lock);
   11.40          return;
   11.41      }
   11.42 @@ -375,12 +378,12 @@ int pirq_guest_unmask(struct domain *d)
   11.43  }
   11.44  
   11.45  extern int ioapic_ack_new;
   11.46 -int pirq_acktype(int irq)
   11.47 +int pirq_acktype(struct domain *d, int irq)
   11.48  {
   11.49      irq_desc_t  *desc;
   11.50      unsigned int vector;
   11.51  
   11.52 -    vector = irq_to_vector(irq);
   11.53 +    vector = domain_irq_to_vector(d, irq);
   11.54      if ( vector == 0 )
   11.55          return ACKTYPE_NONE;
   11.56  
   11.57 @@ -421,7 +424,7 @@ int pirq_acktype(int irq)
   11.58      return 0;
   11.59  }
   11.60  
   11.61 -int pirq_shared(int irq)
   11.62 +int pirq_shared(struct domain *d, int irq)
   11.63  {
   11.64      unsigned int        vector;
   11.65      irq_desc_t         *desc;
   11.66 @@ -429,7 +432,7 @@ int pirq_shared(int irq)
   11.67      unsigned long       flags;
   11.68      int                 shared;
   11.69  
   11.70 -    vector = irq_to_vector(irq);
   11.71 +    vector = domain_irq_to_vector(d, irq);
   11.72      if ( vector == 0 )
   11.73          return 0;
   11.74  
   11.75 @@ -453,7 +456,7 @@ int pirq_guest_bind(struct vcpu *v, int 
   11.76      cpumask_t           cpumask = CPU_MASK_NONE;
   11.77  
   11.78   retry:
   11.79 -    vector = irq_to_vector(irq);
   11.80 +    vector = domain_irq_to_vector(v->domain, irq);
   11.81      if ( vector == 0 )
   11.82          return -EINVAL;
   11.83  
   11.84 @@ -487,7 +490,7 @@ int pirq_guest_bind(struct vcpu *v, int 
   11.85          action->nr_guests   = 0;
   11.86          action->in_flight   = 0;
   11.87          action->shareable   = will_share;
   11.88 -        action->ack_type    = pirq_acktype(irq);
   11.89 +        action->ack_type    = pirq_acktype(v->domain, irq);
   11.90          cpus_clear(action->cpu_eoi_map);
   11.91  
   11.92          desc->depth = 0;
   11.93 @@ -538,13 +541,15 @@ int pirq_guest_bind(struct vcpu *v, int 
   11.94  
   11.95  int pirq_guest_unbind(struct domain *d, int irq)
   11.96  {
   11.97 -    unsigned int        vector = irq_to_vector(irq);
   11.98 -    irq_desc_t         *desc = &irq_desc[vector];
   11.99 +    unsigned int        vector;
  11.100 +    irq_desc_t         *desc;
  11.101      irq_guest_action_t *action;
  11.102      cpumask_t           cpu_eoi_map;
  11.103      unsigned long       flags;
  11.104      int                 i;
  11.105  
  11.106 +    vector = domain_irq_to_vector(d, irq);
  11.107 +    desc = &irq_desc[vector];
  11.108      BUG_ON(vector == 0);
  11.109  
  11.110      spin_lock_irqsave(&desc->lock, flags);
    12.1 --- a/xen/arch/x86/physdev.c	Thu May 01 10:26:58 2008 +0100
    12.2 +++ b/xen/arch/x86/physdev.c	Thu May 01 10:30:22 2008 +0100
    12.3 @@ -7,6 +7,7 @@
    12.4  #include <xen/irq.h>
    12.5  #include <xen/event.h>
    12.6  #include <xen/guest_access.h>
    12.7 +#include <xen/iocap.h>
    12.8  #include <asm/current.h>
    12.9  #include <asm/hypercall.h>
   12.10  #include <public/xen.h>
   12.11 @@ -24,6 +25,263 @@ int
   12.12  ioapic_guest_write(
   12.13      unsigned long physbase, unsigned int reg, u32 pval);
   12.14  
   12.15 +static int get_free_pirq(struct domain *d, int type, int index)
   12.16 +{
   12.17 +    int i;
   12.18 +
   12.19 +    if ( d == NULL )
   12.20 +        return -EINVAL;
   12.21 +
   12.22 +    ASSERT(spin_is_locked(&d->arch.irq_lock));
   12.23 +
   12.24 +    if ( type == MAP_PIRQ_TYPE_GSI )
   12.25 +    {
   12.26 +        for ( i = 16; i < NR_PIRQS; i++ )
   12.27 +            if ( !d->arch.pirq_vector[i] )
   12.28 +                break;
   12.29 +        if ( i == NR_PIRQS )
   12.30 +            return -ENOSPC;
   12.31 +    }
   12.32 +    else
   12.33 +    {
   12.34 +        for ( i = NR_PIRQS - 1; i >= 16; i-- )
   12.35 +            if ( !d->arch.pirq_vector[i] )
   12.36 +                break;
   12.37 +        if ( i == 16 )
   12.38 +            return -ENOSPC;
   12.39 +    }
   12.40 +
   12.41 +    return i;
   12.42 +}
   12.43 +
   12.44 +/*
   12.45 + * Caller hold the irq_lock
   12.46 + */
   12.47 +static int map_domain_pirq(struct domain *d, int pirq, int vector, int type)
   12.48 +{
   12.49 +    int ret = 0;
   12.50 +    int old_vector, old_pirq;
   12.51 +
   12.52 +    if ( d == NULL )
   12.53 +        return -EINVAL;
   12.54 +
   12.55 +    ASSERT(spin_is_locked(&d->arch.irq_lock));
   12.56 +
   12.57 +    if ( !IS_PRIV(current->domain) )
   12.58 +        return -EPERM;
   12.59 +
   12.60 +    if ( pirq < 0 || pirq >= NR_PIRQS || vector < 0 || vector >= NR_VECTORS )
   12.61 +    {
   12.62 +        gdprintk(XENLOG_G_ERR,
   12.63 +                 "invalid pirq %x or vector %x\n", pirq, vector);
   12.64 +        return -EINVAL;
   12.65 +    }
   12.66 +
   12.67 +    old_vector = d->arch.pirq_vector[pirq];
   12.68 +    old_pirq = d->arch.vector_pirq[vector];
   12.69 +
   12.70 +    if ( (old_vector && (old_vector != vector) ) ||
   12.71 +         (old_pirq && (old_pirq != pirq)) )
   12.72 +    {
   12.73 +        gdprintk(XENLOG_G_ERR, "remap pirq %x vector %x while not unmap\n",
   12.74 +                 pirq, vector);
   12.75 +        ret = -EINVAL;
   12.76 +        goto done;
   12.77 +    }
   12.78 +
   12.79 +    ret = irq_permit_access(d, pirq);
   12.80 +    if ( ret )
   12.81 +    {
   12.82 +        gdprintk(XENLOG_G_ERR, "add irq permit access %x failed\n", pirq);
   12.83 +        ret = -EINVAL;
   12.84 +        goto done;
   12.85 +    }
   12.86 +
   12.87 +    d->arch.pirq_vector[pirq] = vector;
   12.88 +    d->arch.vector_pirq[vector] = pirq;
   12.89 +
   12.90 +done:
   12.91 +    return ret;
   12.92 +}
   12.93 +
   12.94 +/*
   12.95 + * The pirq should has been unbound before this call
   12.96 + */
   12.97 +static int unmap_domain_pirq(struct domain *d, int pirq)
   12.98 +{
   12.99 +    int ret = 0;
  12.100 +    int vector;
  12.101 +
  12.102 +    if ( d == NULL || pirq < 0 || pirq > NR_PIRQS )
  12.103 +        return -EINVAL;
  12.104 +
  12.105 +    if ( !IS_PRIV(current->domain) )
  12.106 +        return -EINVAL;
  12.107 +
  12.108 +    ASSERT(spin_is_locked(&d->arch.irq_lock));
  12.109 +
  12.110 +    vector = d->arch.pirq_vector[pirq];
  12.111 +
  12.112 +    if ( !vector )
  12.113 +    {
  12.114 +        gdprintk(XENLOG_G_ERR, "domain %X: pirq %x not mapped still\n",
  12.115 +                 d->domain_id, pirq);
  12.116 +        ret = -EINVAL;
  12.117 +    }
  12.118 +    else
  12.119 +        d->arch.pirq_vector[pirq] = d->arch.vector_pirq[vector] = 0;
  12.120 +    ret = irq_deny_access(d, pirq);
  12.121 +
  12.122 +    if ( ret )
  12.123 +        gdprintk(XENLOG_G_ERR, "deny irq %x access failed\n", pirq);
  12.124 +
  12.125 +    return ret;
  12.126 +}
  12.127 +
  12.128 +extern int msi_irq_enable;
  12.129 +static int physdev_map_pirq(struct physdev_map_pirq *map)
  12.130 +{
  12.131 +    struct domain *d;
  12.132 +    int vector, pirq, ret = 0;
  12.133 +    unsigned long flags;
  12.134 +
  12.135 +    /* if msi_irq_enable is not enabled,map always success */
  12.136 +    if ( !msi_irq_enable )
  12.137 +        return 0;
  12.138 +
  12.139 +    if ( !IS_PRIV(current->domain) )
  12.140 +        return -EPERM;
  12.141 +
  12.142 +    if ( !map )
  12.143 +        return -EINVAL;
  12.144 +
  12.145 +    if ( map->domid == DOMID_SELF )
  12.146 +        d = rcu_lock_domain(current->domain);
  12.147 +    else
  12.148 +        d = rcu_lock_domain_by_id(map->domid);
  12.149 +
  12.150 +    if ( d == NULL )
  12.151 +    {
  12.152 +        ret = -ESRCH;
  12.153 +        goto free_domain;
  12.154 +    }
  12.155 +
  12.156 +    switch ( map->type )
  12.157 +    {
  12.158 +        case MAP_PIRQ_TYPE_GSI:
  12.159 +            if ( map->index >= NR_IRQS )
  12.160 +            {
  12.161 +                ret = -EINVAL;
  12.162 +                gdprintk(XENLOG_G_ERR,
  12.163 +                         "map invalid irq %x\n", map->index);
  12.164 +                goto free_domain;
  12.165 +            }
  12.166 +            vector = IO_APIC_VECTOR(map->index);
  12.167 +            if ( !vector )
  12.168 +            {
  12.169 +                ret = -EINVAL;
  12.170 +                gdprintk(XENLOG_G_ERR,
  12.171 +                         "map irq with no vector %x\n", map->index);
  12.172 +                goto free_domain;
  12.173 +            }
  12.174 +            break;
  12.175 +        case MAP_PIRQ_TYPE_MSI:
  12.176 +            vector = map->index;
  12.177 +            if ( vector < 0 || vector >= NR_VECTORS )
  12.178 +            {
  12.179 +                ret = -EINVAL;
  12.180 +                gdprintk(XENLOG_G_ERR,
  12.181 +                         "map_pirq with wrong vector %x\n", map->index);
  12.182 +                goto free_domain;
  12.183 +            }
  12.184 +            break;
  12.185 +        default:
  12.186 +            ret = -EINVAL;
  12.187 +            gdprintk(XENLOG_G_ERR, "wrong map_pirq type %x\n", map->type);
  12.188 +            goto free_domain;
  12.189 +            break;
  12.190 +    }
  12.191 +
  12.192 +    spin_lock_irqsave(&d->arch.irq_lock, flags);
  12.193 +    if ( map->pirq == -1 )
  12.194 +    {
  12.195 +        if ( d->arch.vector_pirq[vector] )
  12.196 +        {
  12.197 +            gdprintk(XENLOG_G_ERR, "%x %x mapped already%x\n",
  12.198 +                                    map->index, map->pirq,
  12.199 +                                    d->arch.vector_pirq[vector]);
  12.200 +            pirq = d->arch.vector_pirq[vector];
  12.201 +        }
  12.202 +        else
  12.203 +        {
  12.204 +            pirq = get_free_pirq(d, map->type, map->index);
  12.205 +            if ( pirq < 0 )
  12.206 +            {
  12.207 +                ret = pirq;
  12.208 +                gdprintk(XENLOG_G_ERR, "No free pirq\n");
  12.209 +                goto done;
  12.210 +            }
  12.211 +        }
  12.212 +    }
  12.213 +    else
  12.214 +    {
  12.215 +        if ( d->arch.vector_pirq[vector] &&
  12.216 +             d->arch.vector_pirq[vector] != map->pirq )
  12.217 +        {
  12.218 +            gdprintk(XENLOG_G_ERR, "%x conflict with %x\n",
  12.219 +              map->index, map->pirq);
  12.220 +            ret = -EEXIST;
  12.221 +            goto done;
  12.222 +        }
  12.223 +        else
  12.224 +            pirq = map->pirq;
  12.225 +    }
  12.226 +
  12.227 +    ret = map_domain_pirq(d, pirq, vector, map->type);
  12.228 +
  12.229 +    if ( !ret )
  12.230 +        map->pirq = pirq;
  12.231 +done:
  12.232 +    spin_unlock_irqrestore(&d->arch.irq_lock, flags);
  12.233 +free_domain:
  12.234 +    rcu_unlock_domain(d);
  12.235 +    return ret;
  12.236 +}
  12.237 +
  12.238 +static int physdev_unmap_pirq(struct physdev_unmap_pirq *unmap)
  12.239 +{
  12.240 +    struct domain *d;
  12.241 +    unsigned long flags;
  12.242 +    int ret;
  12.243 +
  12.244 +    if ( !msi_irq_enable )
  12.245 +        return 0;
  12.246 +
  12.247 +    if ( !IS_PRIV(current->domain) )
  12.248 +        return -EPERM;
  12.249 +
  12.250 +    if ( !unmap )
  12.251 +        return -EINVAL;
  12.252 +
  12.253 +    if ( unmap->domid == DOMID_SELF )
  12.254 +        d = rcu_lock_domain(current->domain);
  12.255 +    else
  12.256 +        d = rcu_lock_domain_by_id(unmap->domid);
  12.257 +
  12.258 +    if ( d == NULL )
  12.259 +    {
  12.260 +        rcu_unlock_domain(d);
  12.261 +        return -ESRCH;
  12.262 +    }
  12.263 +
  12.264 +    spin_lock_irqsave(&d->arch.irq_lock, flags);
  12.265 +    ret = unmap_domain_pirq(d, unmap->pirq);
  12.266 +    spin_unlock_irqrestore(&d->arch.irq_lock, flags);
  12.267 +    rcu_unlock_domain(d);
  12.268 +
  12.269 +    return ret;
  12.270 +}
  12.271 +
  12.272  ret_t do_physdev_op(int cmd, XEN_GUEST_HANDLE(void) arg)
  12.273  {
  12.274      int irq;
  12.275 @@ -57,14 +315,38 @@ ret_t do_physdev_op(int cmd, XEN_GUEST_H
  12.276          if ( (irq < 0) || (irq >= NR_IRQS) )
  12.277              break;
  12.278          irq_status_query.flags = 0;
  12.279 -        if ( pirq_acktype(irq) != 0 )
  12.280 +        if ( pirq_acktype(v->domain, irq) != 0 )
  12.281              irq_status_query.flags |= XENIRQSTAT_needs_eoi;
  12.282 -        if ( pirq_shared(irq) )
  12.283 +        if ( pirq_shared(v->domain, irq) )
  12.284              irq_status_query.flags |= XENIRQSTAT_shared;
  12.285          ret = copy_to_guest(arg, &irq_status_query, 1) ? -EFAULT : 0;
  12.286          break;
  12.287      }
  12.288  
  12.289 +    case PHYSDEVOP_map_pirq: {
  12.290 +        struct physdev_map_pirq map;
  12.291 +
  12.292 +        ret = -EFAULT;
  12.293 +        if ( copy_from_guest(&map, arg, 1) != 0 )
  12.294 +            break;
  12.295 +
  12.296 +        ret = physdev_map_pirq(&map);
  12.297 +        if ( copy_to_guest(arg, &map, 1) != 0 )
  12.298 +            ret = -EFAULT;
  12.299 +        break;
  12.300 +    }
  12.301 +
  12.302 +    case PHYSDEVOP_unmap_pirq: {
  12.303 +        struct physdev_unmap_pirq unmap;
  12.304 +
  12.305 +        ret = -EFAULT;
  12.306 +        if ( copy_from_guest(&unmap, arg, 1) != 0 )
  12.307 +            break;
  12.308 +
  12.309 +        ret = physdev_unmap_pirq(&unmap);
  12.310 +        break;
  12.311 +    }
  12.312 +
  12.313      case PHYSDEVOP_apic_read: {
  12.314          struct physdev_apic apic;
  12.315          ret = -EFAULT;
  12.316 @@ -99,6 +381,7 @@ ret_t do_physdev_op(int cmd, XEN_GUEST_H
  12.317  
  12.318      case PHYSDEVOP_alloc_irq_vector: {
  12.319          struct physdev_irq irq_op;
  12.320 +        unsigned long flags;
  12.321  
  12.322          ret = -EFAULT;
  12.323          if ( copy_from_guest(&irq_op, arg, 1) != 0 )
  12.324 @@ -118,7 +401,20 @@ ret_t do_physdev_op(int cmd, XEN_GUEST_H
  12.325              break;
  12.326  
  12.327          irq_op.vector = assign_irq_vector(irq);
  12.328 -        ret = copy_to_guest(arg, &irq_op, 1) ? -EFAULT : 0;
  12.329 +
  12.330 +        ret = 0;
  12.331 +
  12.332 +        if ( msi_irq_enable )
  12.333 +        {
  12.334 +            spin_lock_irqsave(&dom0->arch.irq_lock, flags);
  12.335 +            if ( irq != AUTO_ASSIGN )
  12.336 +                ret = map_domain_pirq(dom0, irq_op.irq, irq_op.vector,
  12.337 +                                     MAP_PIRQ_TYPE_GSI);
  12.338 +            spin_unlock_irqrestore(&dom0->arch.irq_lock, flags);
  12.339 +        }
  12.340 +
  12.341 +        if ( copy_to_guest(arg, &irq_op, 1) != 0 )
  12.342 +            ret = -EFAULT;
  12.343          break;
  12.344      }
  12.345  
    13.1 --- a/xen/drivers/passthrough/io.c	Thu May 01 10:26:58 2008 +0100
    13.2 +++ b/xen/drivers/passthrough/io.c	Thu May 01 10:30:22 2008 +0100
    13.3 @@ -25,6 +25,7 @@ static void pt_irq_time_out(void *data)
    13.4  {
    13.5      struct hvm_mirq_dpci_mapping *irq_map = data;
    13.6      unsigned int guest_gsi, machine_gsi = 0;
    13.7 +    int vector;
    13.8      struct hvm_irq_dpci *dpci = domain_get_irq_dpci(irq_map->dom);
    13.9      struct dev_intx_gsi_link *digl;
   13.10      uint32_t device, intx;
   13.11 @@ -39,7 +40,8 @@ static void pt_irq_time_out(void *data)
   13.12      }
   13.13  
   13.14      clear_bit(machine_gsi, dpci->dirq_mask);
   13.15 -    stop_timer(&dpci->hvm_timer[irq_to_vector(machine_gsi)]);
   13.16 +    vector = domain_irq_to_vector(irq_map->dom, machine_gsi);
   13.17 +    stop_timer(&dpci->hvm_timer[vector]);
   13.18      spin_lock(&dpci->dirq_lock);
   13.19      dpci->mirq[machine_gsi].pending = 0;
   13.20      spin_unlock(&dpci->dirq_lock);
   13.21 @@ -98,7 +100,7 @@ int pt_irq_create_bind_vtd(
   13.22          hvm_irq_dpci->mirq[machine_gsi].valid = 1;
   13.23          hvm_irq_dpci->mirq[machine_gsi].dom = d;
   13.24  
   13.25 -        init_timer(&hvm_irq_dpci->hvm_timer[irq_to_vector(machine_gsi)],
   13.26 +        init_timer(&hvm_irq_dpci->hvm_timer[domain_irq_to_vector(d, machine_gsi)],
   13.27                     pt_irq_time_out, &hvm_irq_dpci->mirq[machine_gsi], 0);
   13.28          /* Deal with gsi for legacy devices */
   13.29          pirq_guest_bind(d->vcpu[0], machine_gsi, BIND_PIRQ__WILL_SHARE);
   13.30 @@ -157,7 +159,7 @@ int pt_irq_destroy_bind_vtd(
   13.31          if ( list_empty(&hvm_irq_dpci->mirq[machine_gsi].digl_list) )
   13.32          {
   13.33              pirq_guest_unbind(d, machine_gsi);
   13.34 -            kill_timer(&hvm_irq_dpci->hvm_timer[irq_to_vector(machine_gsi)]);
   13.35 +            kill_timer(&hvm_irq_dpci->hvm_timer[domain_irq_to_vector(d, machine_gsi)]);
   13.36              hvm_irq_dpci->mirq[machine_gsi].dom   = NULL;
   13.37              hvm_irq_dpci->mirq[machine_gsi].valid = 0;
   13.38          }
   13.39 @@ -185,7 +187,7 @@ int hvm_do_IRQ_dpci(struct domain *d, un
   13.40       * PIC) and we need to detect that.
   13.41       */
   13.42      set_bit(mirq, dpci->dirq_mask);
   13.43 -    set_timer(&dpci->hvm_timer[irq_to_vector(mirq)],
   13.44 +    set_timer(&dpci->hvm_timer[domain_irq_to_vector(d, mirq)],
   13.45                NOW() + PT_IRQ_TIME_OUT);
   13.46      vcpu_kick(d->vcpu[0]);
   13.47  
   13.48 @@ -221,7 +223,7 @@ void hvm_dpci_eoi(struct domain *d, unsi
   13.49  
   13.50          gdprintk(XENLOG_INFO VTDPREFIX,
   13.51                   "hvm_dpci_eoi:: mirq = %x\n", machine_gsi);
   13.52 -        stop_timer(&hvm_irq_dpci->hvm_timer[irq_to_vector(machine_gsi)]);
   13.53 +        stop_timer(&hvm_irq_dpci->hvm_timer[domain_irq_to_vector(d, machine_gsi)]);
   13.54          if ( (ent == NULL) || !ent->fields.mask )
   13.55              pirq_guest_eoi(d, machine_gsi);
   13.56      }
    14.1 --- a/xen/drivers/passthrough/vtd/x86/vtd.c	Thu May 01 10:26:58 2008 +0100
    14.2 +++ b/xen/drivers/passthrough/vtd/x86/vtd.c	Thu May 01 10:30:22 2008 +0100
    14.3 @@ -114,7 +114,7 @@ void hvm_dpci_isairq_eoi(struct domain *
    14.4                  if ( --dpci->mirq[i].pending == 0 )
    14.5                  {
    14.6                      spin_unlock(&dpci->dirq_lock);
    14.7 -                    stop_timer(&dpci->hvm_timer[irq_to_vector(i)]);
    14.8 +                    stop_timer(&dpci->hvm_timer[domain_irq_to_vector(d, i)]);
    14.9                      pirq_guest_eoi(d, i);
   14.10                  }
   14.11                  else
    15.1 --- a/xen/include/asm-x86/domain.h	Thu May 01 10:26:58 2008 +0100
    15.2 +++ b/xen/include/asm-x86/domain.h	Thu May 01 10:30:22 2008 +0100
    15.3 @@ -6,6 +6,7 @@
    15.4  #include <asm/hvm/vcpu.h>
    15.5  #include <asm/hvm/domain.h>
    15.6  #include <asm/e820.h>
    15.7 +#include <asm/pirq.h>
    15.8  
    15.9  #define has_32bit_shinfo(d)    ((d)->arch.has_32bit_shinfo)
   15.10  #define is_pv_32bit_domain(d)  ((d)->arch.is_32bit_pv)
   15.11 @@ -222,6 +223,10 @@ struct arch_domain
   15.12      /* Shadow translated domain: P2M mapping */
   15.13      pagetable_t phys_table;
   15.14  
   15.15 +    spinlock_t irq_lock;
   15.16 +    int vector_pirq[NR_VECTORS];
   15.17 +    int pirq_vector[NR_PIRQS];
   15.18 +
   15.19      /* Pseudophysical e820 map (XENMEM_memory_map).  */
   15.20      struct e820entry e820[3];
   15.21      unsigned int nr_e820;
    16.1 --- a/xen/include/asm-x86/irq.h	Thu May 01 10:26:58 2008 +0100
    16.2 +++ b/xen/include/asm-x86/irq.h	Thu May 01 10:30:22 2008 +0100
    16.3 @@ -49,7 +49,9 @@ extern unsigned long io_apic_irqs;
    16.4  extern atomic_t irq_err_count;
    16.5  extern atomic_t irq_mis_count;
    16.6  
    16.7 -int pirq_acktype(int irq);
    16.8 -int pirq_shared(int irq);
    16.9 +int pirq_acktype(struct domain *d, int irq);
   16.10 +int pirq_shared(struct domain *d , int irq);
   16.11  
   16.12 +extern int domain_irq_to_vector(struct domain *d, int irq);
   16.13 +extern int domain_vector_to_irq(struct domain *d, int vector);
   16.14  #endif /* _ASM_HW_IRQ_H */
    17.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
    17.2 +++ b/xen/include/asm-x86/pirq.h	Thu May 01 10:30:22 2008 +0100
    17.3 @@ -0,0 +1,11 @@
    17.4 +#ifndef __XEN_PIRQ_H
    17.5 +#define __XEN_PIRQ_H
    17.6 +
    17.7 +#define PIRQ_BASE       0
    17.8 +#define NR_PIRQS        256
    17.9 +
   17.10 +#define DYNIRQ_BASE     (PIRQ_BASE + NR_PIRQS)
   17.11 +#define NR_DYNIRQS      256
   17.12 +
   17.13 +#endif /* __XEN_PIRQ_H */
   17.14 +
    18.1 --- a/xen/include/public/physdev.h	Thu May 01 10:26:58 2008 +0100
    18.2 +++ b/xen/include/public/physdev.h	Thu May 01 10:30:22 2008 +0100
    18.3 @@ -121,6 +121,33 @@ struct physdev_irq {
    18.4  };
    18.5  typedef struct physdev_irq physdev_irq_t;
    18.6  DEFINE_XEN_GUEST_HANDLE(physdev_irq_t);
    18.7 + 
    18.8 +#define MAP_PIRQ_TYPE_MSI               0x0
    18.9 +#define MAP_PIRQ_TYPE_GSI               0x1
   18.10 +#define MAP_PIRQ_TYPE_UNKNOWN           0x2
   18.11 +
   18.12 +#define PHYSDEVOP_map_pirq               13
   18.13 +struct physdev_map_pirq {
   18.14 +    domid_t domid;
   18.15 +    /* IN */
   18.16 +    int type;
   18.17 +    /* IN */
   18.18 +    int index;
   18.19 +    /* IN or OUT */
   18.20 +    int pirq;
   18.21 +};
   18.22 +typedef struct physdev_map_pirq physdev_map_pirq_t;
   18.23 +DEFINE_XEN_GUEST_HANDLE(physdev_map_pirq_t);
   18.24 +
   18.25 +#define PHYSDEVOP_unmap_pirq             14
   18.26 +struct physdev_unmap_pirq {
   18.27 +    domid_t domid;
   18.28 +    /* IN */
   18.29 +    int pirq;
   18.30 +};
   18.31 +
   18.32 +typedef struct physdev_unmap_pirq physdev_unmap_pirq_t;
   18.33 +DEFINE_XEN_GUEST_HANDLE(physdev_unmap_pirq_t);
   18.34  
   18.35  /*
   18.36   * Argument to physdev_op_compat() hypercall. Superceded by new physdev_op()