Commit dff790f9 authored by Ross Lagerwall's avatar Ross Lagerwall Committed by Luis Henriques

xen/events/fifo: Consume unprocessed events when a CPU dies

commit 3de88d62 upstream.

When a CPU is offlined, there may be unprocessed events on a port for
that CPU.  If the port is subsequently reused on a different CPU, it
could be in an unexpected state with the link bit set, resulting in
interrupts being missed. Fix this by consuming any unprocessed events
for a particular CPU when that CPU dies.
Signed-off-by: default avatarRoss Lagerwall <ross.lagerwall@citrix.com>
Signed-off-by: default avatarDavid Vrabel <david.vrabel@citrix.com>
[ luis: backported to 3.16: adjusted context ]
Signed-off-by: default avatarLuis Henriques <luis.henriques@canonical.com>
parent 50affdc4
...@@ -281,7 +281,8 @@ static void handle_irq_for_port(unsigned port) ...@@ -281,7 +281,8 @@ static void handle_irq_for_port(unsigned port)
static void consume_one_event(unsigned cpu, static void consume_one_event(unsigned cpu,
struct evtchn_fifo_control_block *control_block, struct evtchn_fifo_control_block *control_block,
unsigned priority, unsigned long *ready) unsigned priority, unsigned long *ready,
bool drop)
{ {
struct evtchn_fifo_queue *q = &per_cpu(cpu_queue, cpu); struct evtchn_fifo_queue *q = &per_cpu(cpu_queue, cpu);
uint32_t head; uint32_t head;
...@@ -313,13 +314,17 @@ static void consume_one_event(unsigned cpu, ...@@ -313,13 +314,17 @@ static void consume_one_event(unsigned cpu,
if (head == 0) if (head == 0)
clear_bit(priority, ready); clear_bit(priority, ready);
if (evtchn_fifo_is_pending(port) && !evtchn_fifo_is_masked(port)) if (evtchn_fifo_is_pending(port) && !evtchn_fifo_is_masked(port)) {
if (unlikely(drop))
pr_warn("Dropping pending event for port %u\n", port);
else
handle_irq_for_port(port); handle_irq_for_port(port);
}
q->head[priority] = head; q->head[priority] = head;
} }
static void evtchn_fifo_handle_events(unsigned cpu) static void __evtchn_fifo_handle_events(unsigned cpu, bool drop)
{ {
struct evtchn_fifo_control_block *control_block; struct evtchn_fifo_control_block *control_block;
unsigned long ready; unsigned long ready;
...@@ -331,11 +336,16 @@ static void evtchn_fifo_handle_events(unsigned cpu) ...@@ -331,11 +336,16 @@ static void evtchn_fifo_handle_events(unsigned cpu)
while (ready) { while (ready) {
q = find_first_bit(BM(&ready), EVTCHN_FIFO_MAX_QUEUES); q = find_first_bit(BM(&ready), EVTCHN_FIFO_MAX_QUEUES);
consume_one_event(cpu, control_block, q, &ready); consume_one_event(cpu, control_block, q, &ready, drop);
ready |= xchg(&control_block->ready, 0); ready |= xchg(&control_block->ready, 0);
} }
} }
static void evtchn_fifo_handle_events(unsigned cpu)
{
__evtchn_fifo_handle_events(cpu, false);
}
static void evtchn_fifo_resume(void) static void evtchn_fifo_resume(void)
{ {
unsigned cpu; unsigned cpu;
...@@ -420,6 +430,9 @@ static int evtchn_fifo_cpu_notification(struct notifier_block *self, ...@@ -420,6 +430,9 @@ static int evtchn_fifo_cpu_notification(struct notifier_block *self,
if (!per_cpu(cpu_control_block, cpu)) if (!per_cpu(cpu_control_block, cpu))
ret = evtchn_fifo_alloc_control_block(cpu); ret = evtchn_fifo_alloc_control_block(cpu);
break; break;
case CPU_DEAD:
__evtchn_fifo_handle_events(cpu, true);
break;
default: default:
break; break;
} }
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment