aboutsummaryrefslogtreecommitdiffstats
path: root/xen/arch/x86/irq.c
diff options
context:
space:
mode:
authorJan Beulich <jbeulich@novell.com>2011-06-23 11:32:43 +0100
committerJan Beulich <jbeulich@novell.com>2011-06-23 11:32:43 +0100
commitc24536b636f23e4d3202968fcad129d979881e2c (patch)
treee3e188d484b371f8770714bc0453f6395d6da241 /xen/arch/x86/irq.c
parenteebfd58f212c5fb75e602ac1aa126863452375da (diff)
downloadxen-c24536b636f23e4d3202968fcad129d979881e2c.tar.gz
xen-c24536b636f23e4d3202968fcad129d979881e2c.tar.bz2
xen-c24536b636f23e4d3202968fcad129d979881e2c.zip
replace d->nr_pirqs sized arrays with radix tree
With this it is questionable whether retaining struct domain's nr_pirqs is actually necessary - the value now only serves for bounds checking, and this boundary could easily be nr_irqs. Note that ia64, the build of which is broken currently anyway, is only being partially fixed up. v2: adjustments for split setup/teardown of translation data v3: re-sync with radix tree implementation changes Signed-off-by: Jan Beulich <jbeulich@novell.com>
Diffstat (limited to 'xen/arch/x86/irq.c')
-rw-r--r--xen/arch/x86/irq.c304
1 files changed, 199 insertions, 105 deletions
diff --git a/xen/arch/x86/irq.c b/xen/arch/x86/irq.c
index 0a84bf8dfb..b8366bedc4 100644
--- a/xen/arch/x86/irq.c
+++ b/xen/arch/x86/irq.c
@@ -814,7 +814,7 @@ static void irq_guest_eoi_timer_fn(void *data)
{
struct domain *d = action->guest[i];
unsigned int pirq = domain_irq_to_pirq(d, irq);
- if ( test_and_clear_bit(pirq, d->pirq_mask) )
+ if ( test_and_clear_bool(pirq_info(d, pirq)->masked) )
action->in_flight--;
}
}
@@ -874,11 +874,12 @@ static void __do_IRQ_guest(int irq)
for ( i = 0; i < action->nr_guests; i++ )
{
- unsigned int pirq;
+ struct pirq *pirq;
+
d = action->guest[i];
- pirq = domain_irq_to_pirq(d, irq);
+ pirq = pirq_info(d, domain_irq_to_pirq(d, irq));
if ( (action->ack_type != ACKTYPE_NONE) &&
- !test_and_set_bit(pirq, d->pirq_mask) )
+ !test_and_set_bool(pirq->masked) )
action->in_flight++;
if ( hvm_do_IRQ_dpci(d, pirq) )
{
@@ -950,31 +951,74 @@ struct irq_desc *domain_spin_lock_irq_desc(
return desc;
}
-static int prepare_domain_irq_pirq(struct domain *d, int irq, int pirq)
+/*
+ * Same with struct pirq already looked up, and d->event_lock already
+ * held (thus the PIRQ <-> IRQ mapping can't change under our feet).
+ */
+struct irq_desc *pirq_spin_lock_irq_desc(
+ struct domain *d, const struct pirq *pirq, unsigned long *pflags)
+{
+ int irq = pirq->arch.irq;
+ struct irq_desc *desc;
+ unsigned long flags;
+
+ ASSERT(spin_is_locked(&d->event_lock));
+
+ if ( irq <= 0 )
+ return NULL;
+
+ desc = irq_to_desc(irq);
+ spin_lock_irqsave(&desc->lock, flags);
+
+ if ( pflags )
+ *pflags = flags;
+
+ ASSERT(pirq == pirq_info(d, domain_irq_to_pirq(d, irq)));
+ ASSERT(irq == pirq->arch.irq);
+
+ return desc;
+}
+
+static int prepare_domain_irq_pirq(struct domain *d, int irq, int pirq,
+ struct pirq **pinfo)
{
int err = radix_tree_insert(&d->arch.irq_pirq, irq,
radix_tree_int_to_ptr(0));
- return (err != -EEXIST) ? err : 0;
+ struct pirq *info;
+
+ if ( err && err != -EEXIST )
+ return err;
+ info = pirq_get_info(d, pirq);
+ if ( !info )
+ {
+ if ( !err )
+ radix_tree_delete(&d->arch.irq_pirq, irq);
+ return -ENOMEM;
+ }
+ *pinfo = info;
+ return 0;
}
-static void set_domain_irq_pirq(struct domain *d, int irq, int pirq)
+static void set_domain_irq_pirq(struct domain *d, int irq, struct pirq *pirq)
{
radix_tree_replace_slot(
radix_tree_lookup_slot(&d->arch.irq_pirq, irq),
- radix_tree_int_to_ptr(pirq));
- d->arch.pirq_irq[pirq] = irq;
+ radix_tree_int_to_ptr(pirq->pirq));
+ pirq->arch.irq = irq;
}
-static void clear_domain_irq_pirq(struct domain *d, int irq, int pirq)
+static void clear_domain_irq_pirq(struct domain *d, int irq, struct pirq *pirq)
{
- d->arch.pirq_irq[pirq] = 0;
+ pirq->arch.irq = 0;
radix_tree_replace_slot(
radix_tree_lookup_slot(&d->arch.irq_pirq, irq),
radix_tree_int_to_ptr(0));
}
-static void cleanup_domain_irq_pirq(struct domain *d, int irq, int pirq)
+static void cleanup_domain_irq_pirq(struct domain *d, int irq,
+ struct pirq *pirq)
{
+ pirq_cleanup_check(pirq, d);
radix_tree_delete(&d->arch.irq_pirq, irq);
}
@@ -989,12 +1033,14 @@ int init_domain_irq_mapping(struct domain *d)
for ( i = 1; platform_legacy_irq(i); ++i )
{
+ struct pirq *info;
+
if ( IO_APIC_IRQ(i) )
continue;
- err = prepare_domain_irq_pirq(d, i, i);
+ err = prepare_domain_irq_pirq(d, i, i, &info);
if ( err )
break;
- set_domain_irq_pirq(d, i, i);
+ set_domain_irq_pirq(d, i, info);
}
if ( err )
@@ -1009,6 +1055,48 @@ void cleanup_domain_irq_mapping(struct domain *d)
radix_tree_destroy(&d->arch.hvm_domain.emuirq_pirq, NULL);
}
+struct pirq *alloc_pirq_struct(struct domain *d)
+{
+ size_t sz = is_hvm_domain(d) ? sizeof(struct pirq) :
+ offsetof(struct pirq, arch.hvm);
+ struct pirq *pirq = xmalloc_bytes(sz);
+
+ if ( pirq )
+ {
+ memset(pirq, 0, sz);
+ if ( is_hvm_domain(d) )
+ {
+ pirq->arch.hvm.emuirq = IRQ_UNBOUND;
+ pt_pirq_init(d, &pirq->arch.hvm.dpci);
+ }
+ }
+
+ return pirq;
+}
+
+void (pirq_cleanup_check)(struct pirq *pirq, struct domain *d)
+{
+ /*
+ * Check whether all fields have their default values, and delete
+ * the entry from the tree if so.
+ *
+ * NB: Common parts were already checked.
+ */
+ if ( pirq->arch.irq )
+ return;
+
+ if ( is_hvm_domain(d) )
+ {
+ if ( pirq->arch.hvm.emuirq != IRQ_UNBOUND )
+ return;
+ if ( !pt_pirq_cleanup_check(&pirq->arch.hvm.dpci) )
+ return;
+ }
+
+ if ( radix_tree_delete(&d->pirq_tree, pirq->pirq) != pirq )
+ BUG();
+}
+
/* Flush all ready EOIs from the top of this CPU's pending-EOI stack. */
static void flush_ready_eoi(void)
{
@@ -1069,18 +1157,22 @@ static void set_eoi_ready(void *data)
flush_ready_eoi();
}
-static void __pirq_guest_eoi(struct domain *d, int pirq)
+void pirq_guest_eoi(struct domain *d, struct pirq *pirq)
+{
+ struct irq_desc *desc;
+
+ ASSERT(local_irq_is_enabled());
+ desc = pirq_spin_lock_irq_desc(d, pirq, NULL);
+ if ( desc )
+ desc_guest_eoi(d, desc, pirq);
+}
+
+void desc_guest_eoi(struct domain *d, struct irq_desc *desc, struct pirq *pirq)
{
- struct irq_desc *desc;
irq_guest_action_t *action;
cpumask_t cpu_eoi_map;
int irq;
- ASSERT(local_irq_is_enabled());
- desc = domain_spin_lock_irq_desc(d, pirq, NULL);
- if ( desc == NULL )
- return;
-
if ( !(desc->status & IRQ_GUEST) )
{
spin_unlock_irq(&desc->lock);
@@ -1092,12 +1184,12 @@ static void __pirq_guest_eoi(struct domain *d, int pirq)
if ( action->ack_type == ACKTYPE_NONE )
{
- ASSERT(!test_bit(pirq, d->pirq_mask));
+ ASSERT(!pirq->masked);
stop_timer(&action->eoi_timer);
_irq_guest_eoi(desc);
}
- if ( unlikely(!test_and_clear_bit(pirq, d->pirq_mask)) ||
+ if ( unlikely(!test_and_clear_bool(pirq->masked)) ||
unlikely(--action->in_flight != 0) )
{
spin_unlock_irq(&desc->lock);
@@ -1132,27 +1224,22 @@ static void __pirq_guest_eoi(struct domain *d, int pirq)
on_selected_cpus(&cpu_eoi_map, set_eoi_ready, desc, 0);
}
-int pirq_guest_eoi(struct domain *d, int irq)
-{
- if ( (irq < 0) || (irq >= d->nr_pirqs) )
- return -EINVAL;
-
- __pirq_guest_eoi(d, irq);
-
- return 0;
-}
-
int pirq_guest_unmask(struct domain *d)
{
- unsigned int irq, nr = d->nr_pirqs;
+ unsigned int pirq = 0, n, i;
+ struct pirq *pirqs[16];
- for ( irq = find_first_bit(d->pirq_mask, nr);
- irq < nr;
- irq = find_next_bit(d->pirq_mask, nr, irq+1) )
- {
- if ( !test_bit(d->pirq_to_evtchn[irq], &shared_info(d, evtchn_mask)) )
- __pirq_guest_eoi(d, irq);
- }
+ do {
+ n = radix_tree_gang_lookup(&d->pirq_tree, (void **)pirqs, pirq,
+ ARRAY_SIZE(pirqs));
+ for ( i = 0; i < n; ++i )
+ {
+ pirq = pirqs[i]->pirq;
+ if ( pirqs[i]->masked &&
+ !test_bit(pirqs[i]->evtchn, &shared_info(d, evtchn_mask)) )
+ pirq_guest_eoi(d, pirqs[i]);
+ }
+ } while ( ++pirq < d->nr_pirqs && n == ARRAY_SIZE(pirqs) );
return 0;
}
@@ -1222,7 +1309,7 @@ int pirq_shared(struct domain *d, int pirq)
return shared;
}
-int pirq_guest_bind(struct vcpu *v, int pirq, int will_share)
+int pirq_guest_bind(struct vcpu *v, struct pirq *pirq, int will_share)
{
unsigned int irq;
struct irq_desc *desc;
@@ -1234,7 +1321,7 @@ int pirq_guest_bind(struct vcpu *v, int pirq, int will_share)
BUG_ON(!local_irq_is_enabled());
retry:
- desc = domain_spin_lock_irq_desc(v->domain, pirq, NULL);
+ desc = pirq_spin_lock_irq_desc(v->domain, pirq, NULL);
if ( desc == NULL )
{
rc = -EINVAL;
@@ -1250,7 +1337,7 @@ int pirq_guest_bind(struct vcpu *v, int pirq, int will_share)
{
gdprintk(XENLOG_INFO,
"Cannot bind IRQ %d to guest. In use by '%s'.\n",
- pirq, desc->action->name);
+ pirq->pirq, desc->action->name);
rc = -EBUSY;
goto unlock_out;
}
@@ -1262,7 +1349,7 @@ int pirq_guest_bind(struct vcpu *v, int pirq, int will_share)
goto retry;
gdprintk(XENLOG_INFO,
"Cannot bind IRQ %d to guest. Out of memory.\n",
- pirq);
+ pirq->pirq);
rc = -ENOMEM;
goto out;
}
@@ -1274,7 +1361,7 @@ int pirq_guest_bind(struct vcpu *v, int pirq, int will_share)
action->nr_guests = 0;
action->in_flight = 0;
action->shareable = will_share;
- action->ack_type = pirq_acktype(v->domain, pirq);
+ action->ack_type = pirq_acktype(v->domain, pirq->pirq);
cpus_clear(action->cpu_eoi_map);
init_timer(&action->eoi_timer, irq_guest_eoi_timer_fn, desc, 0);
@@ -1291,7 +1378,7 @@ int pirq_guest_bind(struct vcpu *v, int pirq, int will_share)
else if ( !will_share || !action->shareable )
{
gdprintk(XENLOG_INFO, "Cannot bind IRQ %d to guest. %s.\n",
- pirq,
+ pirq->pirq,
will_share ?
"Others do not share" :
"Will not share with others");
@@ -1314,7 +1401,7 @@ int pirq_guest_bind(struct vcpu *v, int pirq, int will_share)
if ( action->nr_guests == IRQ_MAX_GUESTS )
{
gdprintk(XENLOG_INFO, "Cannot bind IRQ %d to guest. "
- "Already at max share.\n", pirq);
+ "Already at max share.\n", pirq->pirq);
rc = -EBUSY;
goto unlock_out;
}
@@ -1322,9 +1409,9 @@ int pirq_guest_bind(struct vcpu *v, int pirq, int will_share)
action->guest[action->nr_guests++] = v->domain;
if ( action->ack_type != ACKTYPE_NONE )
- set_pirq_eoi(v->domain, pirq);
+ set_pirq_eoi(v->domain, pirq->pirq);
else
- clear_pirq_eoi(v->domain, pirq);
+ clear_pirq_eoi(v->domain, pirq->pirq);
unlock_out:
spin_unlock_irq(&desc->lock);
@@ -1335,7 +1422,7 @@ int pirq_guest_bind(struct vcpu *v, int pirq, int will_share)
}
static irq_guest_action_t *__pirq_guest_unbind(
- struct domain *d, int pirq, struct irq_desc *desc)
+ struct domain *d, struct pirq *pirq, struct irq_desc *desc)
{
unsigned int irq;
irq_guest_action_t *action;
@@ -1350,7 +1437,7 @@ static irq_guest_action_t *__pirq_guest_unbind(
if ( unlikely(action == NULL) )
{
dprintk(XENLOG_G_WARNING, "dom%d: pirq %d: desc->action is NULL!\n",
- d->domain_id, pirq);
+ d->domain_id, pirq->pirq);
return NULL;
}
@@ -1364,13 +1451,13 @@ static irq_guest_action_t *__pirq_guest_unbind(
switch ( action->ack_type )
{
case ACKTYPE_UNMASK:
- if ( test_and_clear_bit(pirq, d->pirq_mask) &&
+ if ( test_and_clear_bool(pirq->masked) &&
(--action->in_flight == 0) )
desc->handler->end(irq);
break;
case ACKTYPE_EOI:
/* NB. If #guests == 0 then we clear the eoi_map later on. */
- if ( test_and_clear_bit(pirq, d->pirq_mask) &&
+ if ( test_and_clear_bool(pirq->masked) &&
(--action->in_flight == 0) &&
(action->nr_guests != 0) )
{
@@ -1388,9 +1475,9 @@ static irq_guest_action_t *__pirq_guest_unbind(
/*
* The guest cannot re-bind to this IRQ until this function returns. So,
- * when we have flushed this IRQ from pirq_mask, it should remain flushed.
+ * when we have flushed this IRQ from ->masked, it should remain flushed.
*/
- BUG_ON(test_bit(pirq, d->pirq_mask));
+ BUG_ON(pirq->masked);
if ( action->nr_guests != 0 )
return NULL;
@@ -1428,7 +1515,7 @@ static irq_guest_action_t *__pirq_guest_unbind(
return action;
}
-void pirq_guest_unbind(struct domain *d, int pirq)
+void pirq_guest_unbind(struct domain *d, struct pirq *pirq)
{
irq_guest_action_t *oldaction = NULL;
struct irq_desc *desc;
@@ -1437,11 +1524,11 @@ void pirq_guest_unbind(struct domain *d, int pirq)
WARN_ON(!spin_is_locked(&d->event_lock));
BUG_ON(!local_irq_is_enabled());
- desc = domain_spin_lock_irq_desc(d, pirq, NULL);
+ desc = pirq_spin_lock_irq_desc(d, pirq, NULL);
if ( desc == NULL )
{
- irq = -domain_pirq_to_irq(d, pirq);
+ irq = -pirq->arch.irq;
BUG_ON(irq <= 0);
desc = irq_to_desc(irq);
spin_lock_irq(&desc->lock);
@@ -1463,7 +1550,7 @@ void pirq_guest_unbind(struct domain *d, int pirq)
cleanup_domain_irq_pirq(d, irq, pirq);
}
-static int pirq_guest_force_unbind(struct domain *d, int irq)
+static int pirq_guest_force_unbind(struct domain *d, struct pirq *pirq)
{
struct irq_desc *desc;
irq_guest_action_t *action, *oldaction = NULL;
@@ -1472,7 +1559,7 @@ static int pirq_guest_force_unbind(struct domain *d, int irq)
WARN_ON(!spin_is_locked(&d->event_lock));
BUG_ON(!local_irq_is_enabled());
- desc = domain_spin_lock_irq_desc(d, irq, NULL);
+ desc = pirq_spin_lock_irq_desc(d, pirq, NULL);
BUG_ON(desc == NULL);
if ( !(desc->status & IRQ_GUEST) )
@@ -1482,7 +1569,7 @@ static int pirq_guest_force_unbind(struct domain *d, int irq)
if ( unlikely(action == NULL) )
{
dprintk(XENLOG_G_WARNING, "dom%d: pirq %d: desc->action is NULL!\n",
- d->domain_id, irq);
+ d->domain_id, pirq->pirq);
goto out;
}
@@ -1492,7 +1579,7 @@ static int pirq_guest_force_unbind(struct domain *d, int irq)
goto out;
bound = 1;
- oldaction = __pirq_guest_unbind(d, irq, desc);
+ oldaction = __pirq_guest_unbind(d, pirq, desc);
out:
spin_unlock_irq(&desc->lock);
@@ -1506,6 +1593,13 @@ static int pirq_guest_force_unbind(struct domain *d, int irq)
return bound;
}
+static inline bool_t is_free_pirq(const struct domain *d,
+ const struct pirq *pirq)
+{
+ return !pirq || (!pirq->arch.irq && (!is_hvm_domain(d) ||
+ pirq->arch.hvm.emuirq == IRQ_UNBOUND));
+}
+
int get_free_pirq(struct domain *d, int type, int index)
{
int i;
@@ -1515,29 +1609,17 @@ int get_free_pirq(struct domain *d, int type, int index)
if ( type == MAP_PIRQ_TYPE_GSI )
{
for ( i = 16; i < nr_irqs_gsi; i++ )
- if ( !d->arch.pirq_irq[i] )
- {
- if ( !is_hvm_domain(d) ||
- d->arch.pirq_emuirq[i] == IRQ_UNBOUND )
- break;
- }
- if ( i == nr_irqs_gsi )
- return -ENOSPC;
+ if ( is_free_pirq(d, pirq_info(d, i)) )
+ return i;
}
else
{
for ( i = d->nr_pirqs - 1; i >= nr_irqs_gsi; i-- )
- if ( !d->arch.pirq_irq[i] )
- {
- if ( !is_hvm_domain(d) ||
- d->arch.pirq_emuirq[i] == IRQ_UNBOUND )
- break;
- }
- if ( i < nr_irqs_gsi )
- return -ENOSPC;
+ if ( is_free_pirq(d, pirq_info(d, i)) )
+ return i;
}
- return i;
+ return -ENOSPC;
}
int map_domain_pirq(
@@ -1545,6 +1627,7 @@ int map_domain_pirq(
{
int ret = 0;
int old_irq, old_pirq;
+ struct pirq *info;
struct irq_desc *desc;
unsigned long flags;
struct msi_desc *msi_desc;
@@ -1584,7 +1667,7 @@ int map_domain_pirq(
return ret;
}
- ret = prepare_domain_irq_pirq(d, irq, pirq);
+ ret = prepare_domain_irq_pirq(d, irq, pirq, &info);
if ( ret )
return ret;
@@ -1609,20 +1692,20 @@ int map_domain_pirq(
dprintk(XENLOG_G_ERR, "dom%d: irq %d in use\n",
d->domain_id, irq);
desc->handler = &pci_msi_type;
- set_domain_irq_pirq(d, irq, pirq);
+ set_domain_irq_pirq(d, irq, info);
setup_msi_irq(pdev, msi_desc, irq);
spin_unlock_irqrestore(&desc->lock, flags);
}
else
{
spin_lock_irqsave(&desc->lock, flags);
- set_domain_irq_pirq(d, irq, pirq);
+ set_domain_irq_pirq(d, irq, info);
spin_unlock_irqrestore(&desc->lock, flags);
}
done:
if ( ret )
- cleanup_domain_irq_pirq(d, irq, pirq);
+ cleanup_domain_irq_pirq(d, irq, info);
return ret;
}
@@ -1633,6 +1716,7 @@ int unmap_domain_pirq(struct domain *d, int pirq)
struct irq_desc *desc;
int irq, ret = 0;
bool_t forced_unbind;
+ struct pirq *info;
struct msi_desc *msi_desc = NULL;
if ( (pirq < 0) || (pirq >= d->nr_pirqs) )
@@ -1641,8 +1725,8 @@ int unmap_domain_pirq(struct domain *d, int pirq)
ASSERT(spin_is_locked(&pcidevs_lock));
ASSERT(spin_is_locked(&d->event_lock));
- irq = domain_pirq_to_irq(d, pirq);
- if ( irq <= 0 )
+ info = pirq_info(d, pirq);
+ if ( !info || (irq = info->arch.irq) <= 0 )
{
dprintk(XENLOG_G_ERR, "dom%d: pirq %d not mapped\n",
d->domain_id, pirq);
@@ -1650,7 +1734,7 @@ int unmap_domain_pirq(struct domain *d, int pirq)
goto done;
}
- forced_unbind = pirq_guest_force_unbind(d, pirq);
+ forced_unbind = pirq_guest_force_unbind(d, info);
if ( forced_unbind )
dprintk(XENLOG_G_WARNING, "dom%d: forcing unbind of pirq %d\n",
d->domain_id, pirq);
@@ -1665,10 +1749,10 @@ int unmap_domain_pirq(struct domain *d, int pirq)
BUG_ON(irq != domain_pirq_to_irq(d, pirq));
if ( !forced_unbind )
- clear_domain_irq_pirq(d, irq, pirq);
+ clear_domain_irq_pirq(d, irq, info);
else
{
- d->arch.pirq_irq[pirq] = -irq;
+ info->arch.irq = -irq;
radix_tree_replace_slot(
radix_tree_lookup_slot(&d->arch.irq_pirq, irq),
radix_tree_int_to_ptr(-pirq));
@@ -1679,7 +1763,7 @@ int unmap_domain_pirq(struct domain *d, int pirq)
msi_free_irq(msi_desc);
if ( !forced_unbind )
- cleanup_domain_irq_pirq(d, irq, pirq);
+ cleanup_domain_irq_pirq(d, irq, info);
ret = irq_deny_access(d, pirq);
if ( ret )
@@ -1701,7 +1785,7 @@ void free_domain_pirqs(struct domain *d)
spin_lock(&d->event_lock);
for ( i = 0; i < d->nr_pirqs; i++ )
- if ( d->arch.pirq_irq[i] > 0 )
+ if ( domain_pirq_to_irq(d, i) > 0 )
unmap_domain_pirq(d, i);
spin_unlock(&d->event_lock);
@@ -1715,6 +1799,7 @@ static void dump_irqs(unsigned char key)
struct irq_cfg *cfg;
irq_guest_action_t *action;
struct domain *d;
+ const struct pirq *info;
unsigned long flags;
printk("Guest interrupt information:\n");
@@ -1749,20 +1834,18 @@ static void dump_irqs(unsigned char key)
{
d = action->guest[i];
pirq = domain_irq_to_pirq(d, irq);
+ info = pirq_info(d, pirq);
printk("%u:%3d(%c%c%c%c)",
d->domain_id, pirq,
- (test_bit(d->pirq_to_evtchn[pirq],
+ (test_bit(info->evtchn,
&shared_info(d, evtchn_pending)) ?
'P' : '-'),
- (test_bit(d->pirq_to_evtchn[pirq] /
- BITS_PER_EVTCHN_WORD(d),
+ (test_bit(info->evtchn / BITS_PER_EVTCHN_WORD(d),
&vcpu_info(d->vcpu[0], evtchn_pending_sel)) ?
'S' : '-'),
- (test_bit(d->pirq_to_evtchn[pirq],
- &shared_info(d, evtchn_mask)) ?
+ (test_bit(info->evtchn, &shared_info(d, evtchn_mask)) ?
'M' : '-'),
- (test_bit(pirq, d->pirq_mask) ?
- 'M' : '-'));
+ (info->masked ? 'M' : '-'));
if ( i != action->nr_guests )
printk(",");
}
@@ -1869,6 +1952,7 @@ void fixup_irqs(void)
int map_domain_emuirq_pirq(struct domain *d, int pirq, int emuirq)
{
int old_emuirq = IRQ_UNBOUND, old_pirq = IRQ_UNBOUND;
+ struct pirq *info;
ASSERT(spin_is_locked(&d->event_lock));
@@ -1895,6 +1979,10 @@ int map_domain_emuirq_pirq(struct domain *d, int pirq, int emuirq)
return 0;
}
+ info = pirq_get_info(d, pirq);
+ if ( !info )
+ return -ENOMEM;
+
/* do not store emuirq mappings for pt devices */
if ( emuirq != IRQ_PT )
{
@@ -1912,10 +2000,11 @@ int map_domain_emuirq_pirq(struct domain *d, int pirq, int emuirq)
radix_tree_int_to_ptr(pirq));
break;
default:
+ pirq_cleanup_check(info, d);
return err;
}
}
- d->arch.pirq_emuirq[pirq] = emuirq;
+ info->arch.hvm.emuirq = emuirq;
return 0;
}
@@ -1923,6 +2012,7 @@ int map_domain_emuirq_pirq(struct domain *d, int pirq, int emuirq)
int unmap_domain_pirq_emuirq(struct domain *d, int pirq)
{
int emuirq, ret = 0;
+ struct pirq *info;
if ( !is_hvm_domain(d) )
return -EINVAL;
@@ -1941,7 +2031,12 @@ int unmap_domain_pirq_emuirq(struct domain *d, int pirq)
goto done;
}
- d->arch.pirq_emuirq[pirq] = IRQ_UNBOUND;
+ info = pirq_info(d, pirq);
+ if ( info )
+ {
+ info->arch.hvm.emuirq = IRQ_UNBOUND;
+ pirq_cleanup_check(info, d);
+ }
if ( emuirq != IRQ_PT )
radix_tree_delete(&d->arch.hvm_domain.emuirq_pirq, emuirq);
@@ -1949,10 +2044,9 @@ int unmap_domain_pirq_emuirq(struct domain *d, int pirq)
return ret;
}
-int hvm_domain_use_pirq(struct domain *d, int pirq)
+bool_t hvm_domain_use_pirq(const struct domain *d, const struct pirq *pirq)
{
- if ( !is_hvm_domain(d) || pirq < 0 )
- return 0;
-
- return (domain_pirq_to_emuirq(d, pirq) != IRQ_UNBOUND);
+ return is_hvm_domain(d) && pirq &&
+ pirq->arch.hvm.emuirq != IRQ_UNBOUND &&
+ pirq->evtchn != 0;
}