@@ -11,6 +11,7 @@
#include <xen/softirq.h>
#include <xen/irq.h>
#include <xen/numa.h>
+#include <xen/sched.h>
#include <asm/fixmap.h>
#include <asm/div64.h>
#include <asm/hpet.h>
@@ -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;
@@ -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,23 @@ 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);
+ ret = irq_permit_access(current->domain, 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",
+ current->domain, irq, ret);
+ else
+ desc->arch.creator_domid = current->domain->domain_id;
}
return irq;
@@ -307,14 +313,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 +396,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 +2149,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 +2834,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 )
@@ -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
}
@@ -765,7 +765,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");
@@ -1138,7 +1138,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");
@@ -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 *);