From ca0074e519fdc29c8574356b1ba551c8a1b235bb Mon Sep 17 00:00:00 2001 From: Keir Fraser Date: Thu, 1 May 2008 10:30:22 +0100 Subject: MSI 2/6: change the pirq to be per-domain Signed-off-by: Jiang Yunhong Signed-off-by: Shan Haitao --- tools/ioemu/hw/pass-through.c | 14 ++ tools/libxc/xc_physdev.c | 40 +++++ tools/libxc/xc_private.h | 30 ++++ tools/libxc/xenctrl.h | 11 ++ tools/python/xen/lowlevel/xc/xc.c | 29 ++++ tools/python/xen/xend/server/irqif.py | 7 +- tools/python/xen/xend/server/pciif.py | 6 + xen/arch/x86/domain.c | 2 + xen/arch/x86/hvm/vmx/intr.c | 4 +- xen/arch/x86/io_apic.c | 19 +++ xen/arch/x86/irq.c | 27 +-- xen/arch/x86/physdev.c | 302 +++++++++++++++++++++++++++++++++- xen/drivers/passthrough/io.c | 12 +- xen/drivers/passthrough/vtd/x86/vtd.c | 2 +- xen/include/asm-x86/domain.h | 5 + xen/include/asm-x86/irq.h | 6 +- xen/include/asm-x86/pirq.h | 11 ++ xen/include/public/physdev.h | 27 +++ 18 files changed, 529 insertions(+), 25 deletions(-) create mode 100644 xen/include/asm-x86/pirq.h diff --git a/tools/ioemu/hw/pass-through.c b/tools/ioemu/hw/pass-through.c index 29ffda451e..0da7176d44 100644 --- a/tools/ioemu/hw/pass-through.c +++ b/tools/ioemu/hw/pass-through.c @@ -519,7 +519,21 @@ struct pt_dev * register_real_device(PCIBus *e_bus, e_intx = assigned_device->dev.config[0x3d]-1; if ( PT_MACHINE_IRQ_AUTO == machine_irq ) + { + int pirq = pci_dev->irq; + machine_irq = pci_dev->irq; + rc = xc_physdev_map_pirq(xc_handle, domid, MAP_PIRQ_TYPE_GSI, + machine_irq, &pirq); + + if ( rc ) + { + /* TBD: unregister device in case of an error */ + PT_LOG("Error: Mapping irq failed, rc = %d\n", rc); + } + else + machine_irq = pirq; + } /* bind machine_irq to device */ if ( 0 != machine_irq ) diff --git a/tools/libxc/xc_physdev.c b/tools/libxc/xc_physdev.c index 43ea7ff53f..1c5e8cb5da 100644 --- a/tools/libxc/xc_physdev.c +++ b/tools/libxc/xc_physdev.c @@ -19,3 +19,43 @@ int xc_physdev_pci_access_modify(int xc_handle, errno = ENOSYS; return -1; } + +int xc_physdev_map_pirq(int xc_handle, + int domid, + int type, + int index, + int *pirq) +{ + int rc; + struct physdev_map_pirq map; + + if ( !pirq ) + return -EINVAL; + + map.domid = domid; + map.type = type; + map.index = index; + map.pirq = *pirq; + + rc = do_physdev_op(xc_handle, PHYSDEVOP_map_pirq, &map); + + if ( !rc ) + *pirq = map.pirq; + + return rc; +} + +int xc_physdev_unmap_pirq(int xc_handle, + int domid, + int pirq) +{ + int rc; + struct physdev_unmap_pirq unmap; + + unmap.domid = domid; + unmap.pirq = pirq; + + rc = do_physdev_op(xc_handle, PHYSDEVOP_unmap_pirq, &unmap); + + return rc; +} diff --git a/tools/libxc/xc_private.h b/tools/libxc/xc_private.h index b068e45dbe..0570e62dfb 100644 --- a/tools/libxc/xc_private.h +++ b/tools/libxc/xc_private.h @@ -24,10 +24,12 @@ #define DECLARE_HYPERCALL privcmd_hypercall_t hypercall = { 0 } #define DECLARE_DOMCTL struct xen_domctl domctl = { 0 } #define DECLARE_SYSCTL struct xen_sysctl sysctl = { 0 } +#define DECLARE_PHYSDEV_OP struct physdev_op physdev_op = { 0 } #else #define DECLARE_HYPERCALL privcmd_hypercall_t hypercall #define DECLARE_DOMCTL struct xen_domctl domctl #define DECLARE_SYSCTL struct xen_sysctl sysctl +#define DECLARE_PHYSDEV_OP struct physdev_op physdev_op #endif #undef PAGE_SHIFT @@ -96,6 +98,34 @@ static inline int do_xen_version(int xc_handle, int cmd, void *dest) return do_xen_hypercall(xc_handle, &hypercall); } +static inline int do_physdev_op(int xc_handle, int cmd, void *op) +{ + int ret = -1; + + DECLARE_HYPERCALL; + hypercall.op = __HYPERVISOR_physdev_op; + hypercall.arg[0] = (unsigned long) cmd; + hypercall.arg[1] = (unsigned long) op; + + if ( lock_pages(op, sizeof(*op)) != 0 ) + { + PERROR("Could not lock memory for Xen hypercall"); + goto out1; + } + + if ( (ret = do_xen_hypercall(xc_handle, &hypercall)) < 0 ) + { + if ( errno == EACCES ) + DPRINTF("physdev operation failed -- need to" + " rebuild the user-space tool set?\n"); + } + + unlock_pages(op, sizeof(*op)); + +out1: + return ret; +} + static inline int do_domctl(int xc_handle, struct xen_domctl *domctl) { int ret = -1; diff --git a/tools/libxc/xenctrl.h b/tools/libxc/xenctrl.h index e05df73162..09e7becea3 100644 --- a/tools/libxc/xenctrl.h +++ b/tools/libxc/xenctrl.h @@ -21,6 +21,7 @@ #include #include #include +#include #include #include #include @@ -849,6 +850,16 @@ int xc_gnttab_munmap(int xcg_handle, int xc_gnttab_set_max_grants(int xcg_handle, uint32_t count); +int xc_physdev_map_pirq(int xc_handle, + int domid, + int type, + int index, + int *pirq); + +int xc_physdev_unmap_pirq(int xc_handle, + int domid, + int pirq); + int xc_hvm_set_pci_intx_level( int xc_handle, domid_t dom, uint8_t domain, uint8_t bus, uint8_t device, uint8_t intx, diff --git a/tools/python/xen/lowlevel/xc/xc.c b/tools/python/xen/lowlevel/xc/xc.c index 53a26eed6b..709bbba62b 100644 --- a/tools/python/xen/lowlevel/xc/xc.c +++ b/tools/python/xen/lowlevel/xc/xc.c @@ -799,6 +799,26 @@ static PyObject *pyxc_evtchn_reset(XcObject *self, return zero; } +static PyObject *pyxc_physdev_map_pirq(PyObject *self, + PyObject *args, + PyObject *kwds) +{ + XcObject *xc = (XcObject *)self; + uint32_t dom; + int index, pirq, ret; + + static char *kwd_list[] = {"domid", "index", "pirq", NULL}; + + if ( !PyArg_ParseTupleAndKeywords(args, kwds, "iii", kwd_list, + &dom, &index, &pirq) ) + return NULL; + ret = xc_physdev_map_pirq(xc->xc_handle, dom, MAP_PIRQ_TYPE_GSI, + index, &pirq); + if ( ret != 0 ) + return pyxc_error_to_exception(); + return PyLong_FromUnsignedLong(pirq); +} + static PyObject *pyxc_physdev_pci_access_modify(XcObject *self, PyObject *args, PyObject *kwds) @@ -1589,6 +1609,15 @@ static PyMethodDef pyxc_methods[] = { "Reset all connections.\n" " dom [int]: Domain to reset.\n" }, + { "physdev_map_pirq", + (PyCFunction)pyxc_physdev_map_pirq, + METH_VARARGS | METH_KEYWORDS, "\n" + "map physical irq to guest pirq.\n" + " dom [int]: Identifier of domain to map for.\n" + " index [int]: physical irq.\n" + " pirq [int]: guest pirq.\n" + "Returns: [long] value of the param.\n" }, + { "physdev_pci_access_modify", (PyCFunction)pyxc_physdev_pci_access_modify, METH_VARARGS | METH_KEYWORDS, "\n" diff --git a/tools/python/xen/xend/server/irqif.py b/tools/python/xen/xend/server/irqif.py index 7e96726834..db4b1deedd 100644 --- a/tools/python/xen/xend/server/irqif.py +++ b/tools/python/xen/xend/server/irqif.py @@ -69,5 +69,10 @@ class IRQController(DevController): #todo non-fatal raise VmError( 'irq: Failed to configure irq: %d' % (pirq)) - + rc = xc.physdev_map_pirq(domid = self.getDomid(), + index = pirq, + pirq = pirq) + if rc < 0: + raise VmError( + 'irq: Failed to map irq %x' % (pirq)) return (None, {}, {}) diff --git a/tools/python/xen/xend/server/pciif.py b/tools/python/xen/xend/server/pciif.py index e616ebfe11..6f08e77e7c 100644 --- a/tools/python/xen/xend/server/pciif.py +++ b/tools/python/xen/xend/server/pciif.py @@ -271,6 +271,12 @@ class PciController(DevController): if rc<0: raise VmError(('pci: failed to configure I/O memory on device '+ '%s - errno=%d')%(dev.name,rc)) + rc = xc.physdev_map_pirq(domid = fe_domid, + index = dev.irq, + pirq = dev.irq) + if rc < 0: + raise VmError(('pci: failed to map irq on device '+ + '%s - errno=%d')%(dev.name,rc)) if dev.irq>0: log.debug('pci: enabling irq %d'%dev.irq) diff --git a/xen/arch/x86/domain.c b/xen/arch/x86/domain.c index 4fd1ac1f51..85ff65eadc 100644 --- a/xen/arch/x86/domain.c +++ b/xen/arch/x86/domain.c @@ -525,6 +525,8 @@ int arch_domain_create(struct domain *d, unsigned int domcr_flags) goto fail; } + spin_lock_init(&d->arch.irq_lock); + if ( is_hvm_domain(d) ) { if ( (rc = hvm_domain_initialise(d)) != 0 ) diff --git a/xen/arch/x86/hvm/vmx/intr.c b/xen/arch/x86/hvm/vmx/intr.c index 3fcfc52175..72dfd1d6ac 100644 --- a/xen/arch/x86/hvm/vmx/intr.c +++ b/xen/arch/x86/hvm/vmx/intr.c @@ -121,7 +121,7 @@ static void vmx_dirq_assist(struct vcpu *v) if ( !test_and_clear_bit(irq, &hvm_irq_dpci->dirq_mask) ) continue; - stop_timer(&hvm_irq_dpci->hvm_timer[irq_to_vector(irq)]); + stop_timer(&hvm_irq_dpci->hvm_timer[domain_irq_to_vector(d, irq)]); list_for_each_entry ( digl, &hvm_irq_dpci->mirq[irq].digl_list, list ) { @@ -140,7 +140,7 @@ static void vmx_dirq_assist(struct vcpu *v) * guest will never deal with the irq, then the physical interrupt line * will never be deasserted. */ - set_timer(&hvm_irq_dpci->hvm_timer[irq_to_vector(irq)], + set_timer(&hvm_irq_dpci->hvm_timer[domain_irq_to_vector(d, irq)], NOW() + PT_IRQ_TIME_OUT); } } diff --git a/xen/arch/x86/io_apic.c b/xen/arch/x86/io_apic.c index b7e50ae8f1..67cfed78b6 100644 --- a/xen/arch/x86/io_apic.c +++ b/xen/arch/x86/io_apic.c @@ -41,6 +41,25 @@ int (*ioapic_renumber_irq)(int ioapic, int irq); atomic_t irq_mis_count; +int msi_irq_enable = 0; +boolean_param("msi_irq_enable", msi_irq_enable); + +int domain_irq_to_vector(struct domain *d, int irq) +{ + if ( !msi_irq_enable ) + return irq_to_vector(irq); + else + return d->arch.pirq_vector[irq]; +} + +int domain_vector_to_irq(struct domain *d, int vector) +{ + if ( !msi_irq_enable ) + return vector_to_irq(vector); + else + return d->arch.vector_pirq[vector]; +} + /* Where if anywhere is the i8259 connect in external int mode */ static struct { int pin, apic; } ioapic_i8259 = { -1, -1 }; diff --git a/xen/arch/x86/irq.c b/xen/arch/x86/irq.c index fc050d7d60..ea840dfbdd 100644 --- a/xen/arch/x86/irq.c +++ b/xen/arch/x86/irq.c @@ -203,7 +203,6 @@ static DEFINE_PER_CPU(struct pending_eoi, pending_eoi[NR_VECTORS]); static void __do_IRQ_guest(int vector) { - unsigned int irq = vector_to_irq(vector); irq_desc_t *desc = &irq_desc[vector]; irq_guest_action_t *action = (irq_guest_action_t *)desc->action; struct domain *d; @@ -232,7 +231,9 @@ static void __do_IRQ_guest(int vector) for ( i = 0; i < action->nr_guests; i++ ) { + unsigned int irq; d = action->guest[i]; + irq = domain_vector_to_irq(d, vector); if ( (action->ack_type != ACKTYPE_NONE) && !test_and_set_bit(irq, d->pirq_mask) ) action->in_flight++; @@ -305,8 +306,10 @@ static void __pirq_guest_eoi(struct domain *d, int irq) irq_desc_t *desc; irq_guest_action_t *action; cpumask_t cpu_eoi_map; + int vector; - desc = &irq_desc[irq_to_vector(irq)]; + vector = domain_irq_to_vector(d, irq); + desc = &irq_desc[vector]; action = (irq_guest_action_t *)desc->action; spin_lock_irq(&desc->lock); @@ -324,7 +327,7 @@ static void __pirq_guest_eoi(struct domain *d, int irq) if ( action->ack_type == ACKTYPE_UNMASK ) { ASSERT(cpus_empty(action->cpu_eoi_map)); - desc->handler->end(irq_to_vector(irq)); + desc->handler->end(vector); spin_unlock_irq(&desc->lock); return; } @@ -375,12 +378,12 @@ int pirq_guest_unmask(struct domain *d) } extern int ioapic_ack_new; -int pirq_acktype(int irq) +int pirq_acktype(struct domain *d, int irq) { irq_desc_t *desc; unsigned int vector; - vector = irq_to_vector(irq); + vector = domain_irq_to_vector(d, irq); if ( vector == 0 ) return ACKTYPE_NONE; @@ -421,7 +424,7 @@ int pirq_acktype(int irq) return 0; } -int pirq_shared(int irq) +int pirq_shared(struct domain *d, int irq) { unsigned int vector; irq_desc_t *desc; @@ -429,7 +432,7 @@ int pirq_shared(int irq) unsigned long flags; int shared; - vector = irq_to_vector(irq); + vector = domain_irq_to_vector(d, irq); if ( vector == 0 ) return 0; @@ -453,7 +456,7 @@ int pirq_guest_bind(struct vcpu *v, int irq, int will_share) cpumask_t cpumask = CPU_MASK_NONE; retry: - vector = irq_to_vector(irq); + vector = domain_irq_to_vector(v->domain, irq); if ( vector == 0 ) return -EINVAL; @@ -487,7 +490,7 @@ int pirq_guest_bind(struct vcpu *v, int irq, int will_share) action->nr_guests = 0; action->in_flight = 0; action->shareable = will_share; - action->ack_type = pirq_acktype(irq); + action->ack_type = pirq_acktype(v->domain, irq); cpus_clear(action->cpu_eoi_map); desc->depth = 0; @@ -538,13 +541,15 @@ int pirq_guest_bind(struct vcpu *v, int irq, int will_share) int pirq_guest_unbind(struct domain *d, int irq) { - unsigned int vector = irq_to_vector(irq); - irq_desc_t *desc = &irq_desc[vector]; + unsigned int vector; + irq_desc_t *desc; irq_guest_action_t *action; cpumask_t cpu_eoi_map; unsigned long flags; int i; + vector = domain_irq_to_vector(d, irq); + desc = &irq_desc[vector]; BUG_ON(vector == 0); spin_lock_irqsave(&desc->lock, flags); diff --git a/xen/arch/x86/physdev.c b/xen/arch/x86/physdev.c index e42379d4ac..dd396fed07 100644 --- a/xen/arch/x86/physdev.c +++ b/xen/arch/x86/physdev.c @@ -7,6 +7,7 @@ #include #include #include +#include #include #include #include @@ -24,6 +25,263 @@ int ioapic_guest_write( unsigned long physbase, unsigned int reg, u32 pval); +static int get_free_pirq(struct domain *d, int type, int index) +{ + int i; + + if ( d == NULL ) + return -EINVAL; + + ASSERT(spin_is_locked(&d->arch.irq_lock)); + + if ( type == MAP_PIRQ_TYPE_GSI ) + { + for ( i = 16; i < NR_PIRQS; i++ ) + if ( !d->arch.pirq_vector[i] ) + break; + if ( i == NR_PIRQS ) + return -ENOSPC; + } + else + { + for ( i = NR_PIRQS - 1; i >= 16; i-- ) + if ( !d->arch.pirq_vector[i] ) + break; + if ( i == 16 ) + return -ENOSPC; + } + + return i; +} + +/* + * Caller hold the irq_lock + */ +static int map_domain_pirq(struct domain *d, int pirq, int vector, int type) +{ + int ret = 0; + int old_vector, old_pirq; + + if ( d == NULL ) + return -EINVAL; + + ASSERT(spin_is_locked(&d->arch.irq_lock)); + + if ( !IS_PRIV(current->domain) ) + return -EPERM; + + if ( pirq < 0 || pirq >= NR_PIRQS || vector < 0 || vector >= NR_VECTORS ) + { + gdprintk(XENLOG_G_ERR, + "invalid pirq %x or vector %x\n", pirq, vector); + return -EINVAL; + } + + old_vector = d->arch.pirq_vector[pirq]; + old_pirq = d->arch.vector_pirq[vector]; + + if ( (old_vector && (old_vector != vector) ) || + (old_pirq && (old_pirq != pirq)) ) + { + gdprintk(XENLOG_G_ERR, "remap pirq %x vector %x while not unmap\n", + pirq, vector); + ret = -EINVAL; + goto done; + } + + ret = irq_permit_access(d, pirq); + if ( ret ) + { + gdprintk(XENLOG_G_ERR, "add irq permit access %x failed\n", pirq); + ret = -EINVAL; + goto done; + } + + d->arch.pirq_vector[pirq] = vector; + d->arch.vector_pirq[vector] = pirq; + +done: + return ret; +} + +/* + * The pirq should has been unbound before this call + */ +static int unmap_domain_pirq(struct domain *d, int pirq) +{ + int ret = 0; + int vector; + + if ( d == NULL || pirq < 0 || pirq > NR_PIRQS ) + return -EINVAL; + + if ( !IS_PRIV(current->domain) ) + return -EINVAL; + + ASSERT(spin_is_locked(&d->arch.irq_lock)); + + vector = d->arch.pirq_vector[pirq]; + + if ( !vector ) + { + gdprintk(XENLOG_G_ERR, "domain %X: pirq %x not mapped still\n", + d->domain_id, pirq); + ret = -EINVAL; + } + else + d->arch.pirq_vector[pirq] = d->arch.vector_pirq[vector] = 0; + ret = irq_deny_access(d, pirq); + + if ( ret ) + gdprintk(XENLOG_G_ERR, "deny irq %x access failed\n", pirq); + + return ret; +} + +extern int msi_irq_enable; +static int physdev_map_pirq(struct physdev_map_pirq *map) +{ + struct domain *d; + int vector, pirq, ret = 0; + unsigned long flags; + + /* if msi_irq_enable is not enabled,map always success */ + if ( !msi_irq_enable ) + return 0; + + if ( !IS_PRIV(current->domain) ) + return -EPERM; + + if ( !map ) + return -EINVAL; + + if ( map->domid == DOMID_SELF ) + d = rcu_lock_domain(current->domain); + else + d = rcu_lock_domain_by_id(map->domid); + + if ( d == NULL ) + { + ret = -ESRCH; + goto free_domain; + } + + switch ( map->type ) + { + case MAP_PIRQ_TYPE_GSI: + if ( map->index >= NR_IRQS ) + { + ret = -EINVAL; + gdprintk(XENLOG_G_ERR, + "map invalid irq %x\n", map->index); + goto free_domain; + } + vector = IO_APIC_VECTOR(map->index); + if ( !vector ) + { + ret = -EINVAL; + gdprintk(XENLOG_G_ERR, + "map irq with no vector %x\n", map->index); + goto free_domain; + } + break; + case MAP_PIRQ_TYPE_MSI: + vector = map->index; + if ( vector < 0 || vector >= NR_VECTORS ) + { + ret = -EINVAL; + gdprintk(XENLOG_G_ERR, + "map_pirq with wrong vector %x\n", map->index); + goto free_domain; + } + break; + default: + ret = -EINVAL; + gdprintk(XENLOG_G_ERR, "wrong map_pirq type %x\n", map->type); + goto free_domain; + break; + } + + spin_lock_irqsave(&d->arch.irq_lock, flags); + if ( map->pirq == -1 ) + { + if ( d->arch.vector_pirq[vector] ) + { + gdprintk(XENLOG_G_ERR, "%x %x mapped already%x\n", + map->index, map->pirq, + d->arch.vector_pirq[vector]); + pirq = d->arch.vector_pirq[vector]; + } + else + { + pirq = get_free_pirq(d, map->type, map->index); + if ( pirq < 0 ) + { + ret = pirq; + gdprintk(XENLOG_G_ERR, "No free pirq\n"); + goto done; + } + } + } + else + { + if ( d->arch.vector_pirq[vector] && + d->arch.vector_pirq[vector] != map->pirq ) + { + gdprintk(XENLOG_G_ERR, "%x conflict with %x\n", + map->index, map->pirq); + ret = -EEXIST; + goto done; + } + else + pirq = map->pirq; + } + + ret = map_domain_pirq(d, pirq, vector, map->type); + + if ( !ret ) + map->pirq = pirq; +done: + spin_unlock_irqrestore(&d->arch.irq_lock, flags); +free_domain: + rcu_unlock_domain(d); + return ret; +} + +static int physdev_unmap_pirq(struct physdev_unmap_pirq *unmap) +{ + struct domain *d; + unsigned long flags; + int ret; + + if ( !msi_irq_enable ) + return 0; + + if ( !IS_PRIV(current->domain) ) + return -EPERM; + + if ( !unmap ) + return -EINVAL; + + if ( unmap->domid == DOMID_SELF ) + d = rcu_lock_domain(current->domain); + else + d = rcu_lock_domain_by_id(unmap->domid); + + if ( d == NULL ) + { + rcu_unlock_domain(d); + return -ESRCH; + } + + spin_lock_irqsave(&d->arch.irq_lock, flags); + ret = unmap_domain_pirq(d, unmap->pirq); + spin_unlock_irqrestore(&d->arch.irq_lock, flags); + rcu_unlock_domain(d); + + return ret; +} + ret_t do_physdev_op(int cmd, XEN_GUEST_HANDLE(void) arg) { int irq; @@ -57,14 +315,38 @@ ret_t do_physdev_op(int cmd, XEN_GUEST_HANDLE(void) arg) if ( (irq < 0) || (irq >= NR_IRQS) ) break; irq_status_query.flags = 0; - if ( pirq_acktype(irq) != 0 ) + if ( pirq_acktype(v->domain, irq) != 0 ) irq_status_query.flags |= XENIRQSTAT_needs_eoi; - if ( pirq_shared(irq) ) + if ( pirq_shared(v->domain, irq) ) irq_status_query.flags |= XENIRQSTAT_shared; ret = copy_to_guest(arg, &irq_status_query, 1) ? -EFAULT : 0; break; } + case PHYSDEVOP_map_pirq: { + struct physdev_map_pirq map; + + ret = -EFAULT; + if ( copy_from_guest(&map, arg, 1) != 0 ) + break; + + ret = physdev_map_pirq(&map); + if ( copy_to_guest(arg, &map, 1) != 0 ) + ret = -EFAULT; + break; + } + + case PHYSDEVOP_unmap_pirq: { + struct physdev_unmap_pirq unmap; + + ret = -EFAULT; + if ( copy_from_guest(&unmap, arg, 1) != 0 ) + break; + + ret = physdev_unmap_pirq(&unmap); + break; + } + case PHYSDEVOP_apic_read: { struct physdev_apic apic; ret = -EFAULT; @@ -99,6 +381,7 @@ ret_t do_physdev_op(int cmd, XEN_GUEST_HANDLE(void) arg) case PHYSDEVOP_alloc_irq_vector: { struct physdev_irq irq_op; + unsigned long flags; ret = -EFAULT; if ( copy_from_guest(&irq_op, arg, 1) != 0 ) @@ -118,7 +401,20 @@ ret_t do_physdev_op(int cmd, XEN_GUEST_HANDLE(void) arg) break; irq_op.vector = assign_irq_vector(irq); - ret = copy_to_guest(arg, &irq_op, 1) ? -EFAULT : 0; + + ret = 0; + + if ( msi_irq_enable ) + { + spin_lock_irqsave(&dom0->arch.irq_lock, flags); + if ( irq != AUTO_ASSIGN ) + ret = map_domain_pirq(dom0, irq_op.irq, irq_op.vector, + MAP_PIRQ_TYPE_GSI); + spin_unlock_irqrestore(&dom0->arch.irq_lock, flags); + } + + if ( copy_to_guest(arg, &irq_op, 1) != 0 ) + ret = -EFAULT; break; } diff --git a/xen/drivers/passthrough/io.c b/xen/drivers/passthrough/io.c index 528839550b..b0f55bc802 100644 --- a/xen/drivers/passthrough/io.c +++ b/xen/drivers/passthrough/io.c @@ -25,6 +25,7 @@ static void pt_irq_time_out(void *data) { struct hvm_mirq_dpci_mapping *irq_map = data; unsigned int guest_gsi, machine_gsi = 0; + int vector; struct hvm_irq_dpci *dpci = domain_get_irq_dpci(irq_map->dom); struct dev_intx_gsi_link *digl; uint32_t device, intx; @@ -39,7 +40,8 @@ static void pt_irq_time_out(void *data) } clear_bit(machine_gsi, dpci->dirq_mask); - stop_timer(&dpci->hvm_timer[irq_to_vector(machine_gsi)]); + vector = domain_irq_to_vector(irq_map->dom, machine_gsi); + stop_timer(&dpci->hvm_timer[vector]); spin_lock(&dpci->dirq_lock); dpci->mirq[machine_gsi].pending = 0; spin_unlock(&dpci->dirq_lock); @@ -98,7 +100,7 @@ int pt_irq_create_bind_vtd( hvm_irq_dpci->mirq[machine_gsi].valid = 1; hvm_irq_dpci->mirq[machine_gsi].dom = d; - init_timer(&hvm_irq_dpci->hvm_timer[irq_to_vector(machine_gsi)], + init_timer(&hvm_irq_dpci->hvm_timer[domain_irq_to_vector(d, machine_gsi)], pt_irq_time_out, &hvm_irq_dpci->mirq[machine_gsi], 0); /* Deal with gsi for legacy devices */ pirq_guest_bind(d->vcpu[0], machine_gsi, BIND_PIRQ__WILL_SHARE); @@ -157,7 +159,7 @@ int pt_irq_destroy_bind_vtd( if ( list_empty(&hvm_irq_dpci->mirq[machine_gsi].digl_list) ) { pirq_guest_unbind(d, machine_gsi); - kill_timer(&hvm_irq_dpci->hvm_timer[irq_to_vector(machine_gsi)]); + kill_timer(&hvm_irq_dpci->hvm_timer[domain_irq_to_vector(d, machine_gsi)]); hvm_irq_dpci->mirq[machine_gsi].dom = NULL; hvm_irq_dpci->mirq[machine_gsi].valid = 0; } @@ -185,7 +187,7 @@ int hvm_do_IRQ_dpci(struct domain *d, unsigned int mirq) * PIC) and we need to detect that. */ set_bit(mirq, dpci->dirq_mask); - set_timer(&dpci->hvm_timer[irq_to_vector(mirq)], + set_timer(&dpci->hvm_timer[domain_irq_to_vector(d, mirq)], NOW() + PT_IRQ_TIME_OUT); vcpu_kick(d->vcpu[0]); @@ -221,7 +223,7 @@ void hvm_dpci_eoi(struct domain *d, unsigned int guest_gsi, gdprintk(XENLOG_INFO VTDPREFIX, "hvm_dpci_eoi:: mirq = %x\n", machine_gsi); - stop_timer(&hvm_irq_dpci->hvm_timer[irq_to_vector(machine_gsi)]); + stop_timer(&hvm_irq_dpci->hvm_timer[domain_irq_to_vector(d, machine_gsi)]); if ( (ent == NULL) || !ent->fields.mask ) pirq_guest_eoi(d, machine_gsi); } diff --git a/xen/drivers/passthrough/vtd/x86/vtd.c b/xen/drivers/passthrough/vtd/x86/vtd.c index b78bce80ed..098a1b949a 100644 --- a/xen/drivers/passthrough/vtd/x86/vtd.c +++ b/xen/drivers/passthrough/vtd/x86/vtd.c @@ -114,7 +114,7 @@ void hvm_dpci_isairq_eoi(struct domain *d, unsigned int isairq) if ( --dpci->mirq[i].pending == 0 ) { spin_unlock(&dpci->dirq_lock); - stop_timer(&dpci->hvm_timer[irq_to_vector(i)]); + stop_timer(&dpci->hvm_timer[domain_irq_to_vector(d, i)]); pirq_guest_eoi(d, i); } else diff --git a/xen/include/asm-x86/domain.h b/xen/include/asm-x86/domain.h index 8c4ee649b4..106a90656e 100644 --- a/xen/include/asm-x86/domain.h +++ b/xen/include/asm-x86/domain.h @@ -6,6 +6,7 @@ #include #include #include +#include #define has_32bit_shinfo(d) ((d)->arch.has_32bit_shinfo) #define is_pv_32bit_domain(d) ((d)->arch.is_32bit_pv) @@ -222,6 +223,10 @@ struct arch_domain /* Shadow translated domain: P2M mapping */ pagetable_t phys_table; + spinlock_t irq_lock; + int vector_pirq[NR_VECTORS]; + int pirq_vector[NR_PIRQS]; + /* Pseudophysical e820 map (XENMEM_memory_map). */ struct e820entry e820[3]; unsigned int nr_e820; diff --git a/xen/include/asm-x86/irq.h b/xen/include/asm-x86/irq.h index e92e775945..8858b4eb95 100644 --- a/xen/include/asm-x86/irq.h +++ b/xen/include/asm-x86/irq.h @@ -49,7 +49,9 @@ extern unsigned long io_apic_irqs; extern atomic_t irq_err_count; extern atomic_t irq_mis_count; -int pirq_acktype(int irq); -int pirq_shared(int irq); +int pirq_acktype(struct domain *d, int irq); +int pirq_shared(struct domain *d , int irq); +extern int domain_irq_to_vector(struct domain *d, int irq); +extern int domain_vector_to_irq(struct domain *d, int vector); #endif /* _ASM_HW_IRQ_H */ diff --git a/xen/include/asm-x86/pirq.h b/xen/include/asm-x86/pirq.h new file mode 100644 index 0000000000..2041262134 --- /dev/null +++ b/xen/include/asm-x86/pirq.h @@ -0,0 +1,11 @@ +#ifndef __XEN_PIRQ_H +#define __XEN_PIRQ_H + +#define PIRQ_BASE 0 +#define NR_PIRQS 256 + +#define DYNIRQ_BASE (PIRQ_BASE + NR_PIRQS) +#define NR_DYNIRQS 256 + +#endif /* __XEN_PIRQ_H */ + diff --git a/xen/include/public/physdev.h b/xen/include/public/physdev.h index 75990545b2..fdf6c2bf16 100644 --- a/xen/include/public/physdev.h +++ b/xen/include/public/physdev.h @@ -121,6 +121,33 @@ struct physdev_irq { }; typedef struct physdev_irq physdev_irq_t; DEFINE_XEN_GUEST_HANDLE(physdev_irq_t); + +#define MAP_PIRQ_TYPE_MSI 0x0 +#define MAP_PIRQ_TYPE_GSI 0x1 +#define MAP_PIRQ_TYPE_UNKNOWN 0x2 + +#define PHYSDEVOP_map_pirq 13 +struct physdev_map_pirq { + domid_t domid; + /* IN */ + int type; + /* IN */ + int index; + /* IN or OUT */ + int pirq; +}; +typedef struct physdev_map_pirq physdev_map_pirq_t; +DEFINE_XEN_GUEST_HANDLE(physdev_map_pirq_t); + +#define PHYSDEVOP_unmap_pirq 14 +struct physdev_unmap_pirq { + domid_t domid; + /* IN */ + int pirq; +}; + +typedef struct physdev_unmap_pirq physdev_unmap_pirq_t; +DEFINE_XEN_GUEST_HANDLE(physdev_unmap_pirq_t); /* * Argument to physdev_op_compat() hypercall. Superceded by new physdev_op() -- cgit v1.2.3