diff --git a/xen/arch/x86/hpet.c b/xen/arch/x86/hpet.c index 4b08488ef1..57f68fa81b 100644 --- a/xen/arch/x86/hpet.c +++ b/xen/arch/x86/hpet.c @@ -11,6 +11,7 @@ #include #include #include +#include #include #include #include @@ -368,7 +369,7 @@ static int __init hpet_assign_irq(struct hpet_event_channel *ch) { int irq; - if ( (irq = create_irq(NUMA_NO_NODE)) < 0 ) + if ( (irq = create_irq(NUMA_NO_NODE, false)) < 0 ) return irq; ch->msi.irq = irq; diff --git a/xen/arch/x86/irq.c b/xen/arch/x86/irq.c index d96cf43542..e9b65b1d64 100644 --- a/xen/arch/x86/irq.c +++ b/xen/arch/x86/irq.c @@ -254,7 +254,8 @@ void __init clear_irq_vector(int irq) /* * Dynamic irq allocate and deallocation for MSI */ -int create_irq(nodeid_t node) + +int create_irq(nodeid_t node, bool grant_access) { int irq, ret; struct irq_desc *desc; @@ -282,18 +283,25 @@ int create_irq(nodeid_t node) } ret = assign_irq_vector(irq, mask); } + + ASSERT(desc->arch.creator_domid == DOMID_INVALID); + if (ret < 0) { desc->arch.used = IRQ_UNUSED; irq = ret; } - else if ( hardware_domain ) + else if ( grant_access ) { - ret = irq_permit_access(hardware_domain, irq); + struct domain *currd = current->domain; + + ret = irq_permit_access(currd, irq); if ( ret ) printk(XENLOG_G_ERR - "Could not grant Dom0 access to IRQ%d (error %d)\n", - irq, ret); + "Could not grant %pd access to IRQ%d (error %d)\n", + currd, irq, ret); + else + desc->arch.creator_domid = currd->domain_id; } return irq; @@ -307,14 +315,23 @@ void destroy_irq(unsigned int irq) BUG_ON(!MSI_IRQ(irq)); - if ( hardware_domain ) + if ( desc->arch.creator_domid != DOMID_INVALID ) { - int err = irq_deny_access(hardware_domain, irq); + struct domain *d = get_domain_by_id(desc->arch.creator_domid); - if ( err ) - printk(XENLOG_G_ERR - "Could not revoke Dom0 access to IRQ%u (error %d)\n", - irq, err); + if ( d ) + { + int err = irq_deny_access(d, irq); + + if ( err ) + printk(XENLOG_G_ERR + "Could not revoke %pd access to IRQ%u (error %d)\n", + d, irq, err); + + put_domain(d); + } + + desc->arch.creator_domid = DOMID_INVALID; } spin_lock_irqsave(&desc->lock, flags); @@ -381,6 +398,7 @@ int arch_init_one_irq_desc(struct irq_desc *desc) desc->arch.vector = IRQ_VECTOR_UNASSIGNED; desc->arch.old_vector = IRQ_VECTOR_UNASSIGNED; + desc->arch.creator_domid = DOMID_INVALID; return 0; } @@ -2133,7 +2151,7 @@ int map_domain_pirq( spin_unlock_irqrestore(&desc->lock, flags); info = NULL; - irq = create_irq(NUMA_NO_NODE); + irq = create_irq(NUMA_NO_NODE, true); ret = irq >= 0 ? prepare_domain_irq_pirq(d, irq, pirq + nr, &info) : irq; if ( ret < 0 ) @@ -2818,7 +2836,7 @@ int allocate_and_map_msi_pirq(struct domain *d, int index, int *pirq_p, if ( irq == -1 ) { case MAP_PIRQ_TYPE_MULTI_MSI: - irq = create_irq(NUMA_NO_NODE); + irq = create_irq(NUMA_NO_NODE, true); } if ( irq < nr_irqs_gsi || irq >= nr_irqs ) diff --git a/xen/drivers/char/ns16550.c b/xen/drivers/char/ns16550.c index 8667de6d67..fcd3979a39 100644 --- a/xen/drivers/char/ns16550.c +++ b/xen/drivers/char/ns16550.c @@ -722,7 +722,7 @@ static void __init ns16550_init_irq(struct serial_port *port) struct ns16550 *uart = port->uart; if ( uart->msi ) - uart->irq = create_irq(0); + uart->irq = create_irq(0, false); #endif } diff --git a/xen/drivers/passthrough/amd/iommu_init.c b/xen/drivers/passthrough/amd/iommu_init.c index 574f04dd81..6f53c7ec08 100644 --- a/xen/drivers/passthrough/amd/iommu_init.c +++ b/xen/drivers/passthrough/amd/iommu_init.c @@ -766,7 +766,7 @@ static bool_t __init set_iommu_interrupt_handler(struct amd_iommu *iommu) { int irq, ret; - irq = create_irq(NUMA_NO_NODE); + irq = create_irq(NUMA_NO_NODE, false); if ( irq <= 0 ) { dprintk(XENLOG_ERR, "IOMMU: no irqs\n"); diff --git a/xen/drivers/passthrough/vtd/iommu.c b/xen/drivers/passthrough/vtd/iommu.c index 3c17f11386..f08eec070d 100644 --- a/xen/drivers/passthrough/vtd/iommu.c +++ b/xen/drivers/passthrough/vtd/iommu.c @@ -1097,7 +1097,8 @@ static int __init iommu_set_interrupt(struct acpi_drhd_unit *drhd) struct irq_desc *desc; irq = create_irq(rhsa ? pxm_to_node(rhsa->proximity_domain) - : NUMA_NO_NODE); + : NUMA_NO_NODE, + false); if ( irq <= 0 ) { dprintk(XENLOG_ERR VTDPREFIX, "IOMMU: no irq available!\n"); diff --git a/xen/include/asm-x86/irq.h b/xen/include/asm-x86/irq.h index d3124f7b5d..5f720d30d1 100644 --- a/xen/include/asm-x86/irq.h +++ b/xen/include/asm-x86/irq.h @@ -45,6 +45,11 @@ struct arch_irq_desc { unsigned move_cleanup_count; u8 move_in_progress : 1; s8 used; + /* + * Weak reference to domain having permission over this IRQ (which can + * be different from the domain actually having the IRQ assigned) + */ + domid_t creator_domid; }; /* For use with irq_desc.arch.used */ @@ -161,7 +166,11 @@ int init_irq_data(void); void clear_irq_vector(int irq); int irq_to_vector(int irq); -int create_irq(nodeid_t node); +/* + * If grant_access is set the current domain is given permissions over + * the created IRQ. + */ +int create_irq(nodeid_t node, bool grant_access); void destroy_irq(unsigned int irq); int assign_irq_vector(int irq, const cpumask_t *);