@@ -42,6 +42,14 @@ struct evtchn_fifo_domain {
unsigned int num_evtchns;
};
+union evtchn_fifo_lastq {
+ uint32_t raw;
+ struct {
+ uint8_t last_priority;
+ uint16_t last_vcpu_id;
+ };
+};
+
static inline event_word_t *evtchn_fifo_word_from_port(const struct domain *d,
unsigned int port)
{
@@ -86,16 +94,18 @@ static struct evtchn_fifo_queue *lock_old_queue(const struct domain *d,
struct vcpu *v;
struct evtchn_fifo_queue *q, *old_q;
unsigned int try;
+ union evtchn_fifo_lastq lastq;
for ( try = 0; try < 3; try++ )
{
- v = d->vcpu[evtchn->last_vcpu_id];
- old_q = &v->evtchn_fifo->queue[evtchn->last_priority];
+ lastq.raw = read_atomic(&evtchn->fifo_lastq);
+ v = d->vcpu[lastq.last_vcpu_id];
+ old_q = &v->evtchn_fifo->queue[lastq.last_priority];
spin_lock_irqsave(&old_q->lock, *flags);
- v = d->vcpu[evtchn->last_vcpu_id];
- q = &v->evtchn_fifo->queue[evtchn->last_priority];
+ v = d->vcpu[lastq.last_vcpu_id];
+ q = &v->evtchn_fifo->queue[lastq.last_priority];
if ( old_q == q )
return old_q;
@@ -246,8 +256,11 @@ static void evtchn_fifo_set_pending(struct vcpu *v, struct evtchn *evtchn)
/* Moved to a different queue? */
if ( old_q != q )
{
- evtchn->last_vcpu_id = v->vcpu_id;
- evtchn->last_priority = q->priority;
+ union evtchn_fifo_lastq lastq = { };
+
+ lastq.last_vcpu_id = v->vcpu_id;
+ lastq.last_priority = q->priority;
+ write_atomic(&evtchn->fifo_lastq, lastq.raw);
spin_unlock_irqrestore(&old_q->lock, flags);
spin_lock_irqsave(&q->lock, flags);
@@ -114,8 +114,7 @@ struct evtchn
u16 virq; /* state == ECS_VIRQ */
} u;
u8 priority;
- u8 last_priority;
- u16 last_vcpu_id;
+ u32 fifo_lastq; /* Data for fifo events identifying last queue. */
#ifdef CONFIG_XSM
union {
#ifdef XSM_NEED_GENERIC_EVTCHN_SSID