diff options
author | Stefano Stabellini <stefano.stabellini@eu.citrix.com> | 2012-08-22 12:20:11 -0400 |
---|---|---|
committer | Konrad Rzeszutek Wilk <konrad.wilk@oracle.com> | 2012-08-23 10:18:07 -0400 |
commit | b5e579232d635b79a3da052964cb357ccda8d9ea (patch) | |
tree | b7920e93278da03f1cb2ba9950d010ba95bb0553 /drivers/xen/events.c | |
parent | 5c13f8067745efc15f6ad0158b58d57c44104c25 (diff) |
xen/events: fix unmask_evtchn for PV on HVM guests
When unmask_evtchn is called, if we already have an event pending, we
just set evtchn_pending_sel waiting for local_irq_enable to be called.
That is because PV guests set the irq_enable pvops to
xen_irq_enable_direct in xen_setup_vcpu_info_placement:
xen_irq_enable_direct is implemented in assembly in
arch/x86/xen/xen-asm.S and call xen_force_evtchn_callback if
XEN_vcpu_info_pending is set.
However HVM guests (and ARM guests) do not change or do not have the
irq_enable pvop, so evtchn_unmask cannot work properly for them.
Considering that having the pending_irq bit set when unmask_evtchn is
called is not very common, and it is simpler to keep the
native_irq_enable implementation for HVM guests (and ARM guests), the
best thing to do is just use the EVTCHNOP_unmask hypercall (Xen
re-injects pending events in response).
Signed-off-by: Stefano Stabellini <stefano.stabellini@eu.citrix.com>
Signed-off-by: Konrad Rzeszutek Wilk <konrad.wilk@oracle.com>
Diffstat (limited to 'drivers/xen/events.c')
-rw-r--r-- | drivers/xen/events.c | 17 |
1 files changed, 14 insertions, 3 deletions
diff --git a/drivers/xen/events.c b/drivers/xen/events.c index 7595581d032c..36bf17dc7bfc 100644 --- a/drivers/xen/events.c +++ b/drivers/xen/events.c | |||
@@ -373,11 +373,22 @@ static void unmask_evtchn(int port) | |||
373 | { | 373 | { |
374 | struct shared_info *s = HYPERVISOR_shared_info; | 374 | struct shared_info *s = HYPERVISOR_shared_info; |
375 | unsigned int cpu = get_cpu(); | 375 | unsigned int cpu = get_cpu(); |
376 | int do_hypercall = 0, evtchn_pending = 0; | ||
376 | 377 | ||
377 | BUG_ON(!irqs_disabled()); | 378 | BUG_ON(!irqs_disabled()); |
378 | 379 | ||
379 | /* Slow path (hypercall) if this is a non-local port. */ | 380 | if (unlikely((cpu != cpu_from_evtchn(port)))) |
380 | if (unlikely(cpu != cpu_from_evtchn(port))) { | 381 | do_hypercall = 1; |
382 | else | ||
383 | evtchn_pending = sync_test_bit(port, &s->evtchn_pending[0]); | ||
384 | |||
385 | if (unlikely(evtchn_pending && xen_hvm_domain())) | ||
386 | do_hypercall = 1; | ||
387 | |||
388 | /* Slow path (hypercall) if this is a non-local port or if this is | ||
389 | * an hvm domain and an event is pending (hvm domains don't have | ||
390 | * their own implementation of irq_enable). */ | ||
391 | if (do_hypercall) { | ||
381 | struct evtchn_unmask unmask = { .port = port }; | 392 | struct evtchn_unmask unmask = { .port = port }; |
382 | (void)HYPERVISOR_event_channel_op(EVTCHNOP_unmask, &unmask); | 393 | (void)HYPERVISOR_event_channel_op(EVTCHNOP_unmask, &unmask); |
383 | } else { | 394 | } else { |
@@ -390,7 +401,7 @@ static void unmask_evtchn(int port) | |||
390 | * 'hw_resend_irq'. Just like a real IO-APIC we 'lose | 401 | * 'hw_resend_irq'. Just like a real IO-APIC we 'lose |
391 | * the interrupt edge' if the channel is masked. | 402 | * the interrupt edge' if the channel is masked. |
392 | */ | 403 | */ |
393 | if (sync_test_bit(port, &s->evtchn_pending[0]) && | 404 | if (evtchn_pending && |
394 | !sync_test_and_set_bit(port / BITS_PER_LONG, | 405 | !sync_test_and_set_bit(port / BITS_PER_LONG, |
395 | &vcpu_info->evtchn_pending_sel)) | 406 | &vcpu_info->evtchn_pending_sel)) |
396 | vcpu_info->evtchn_upcall_pending = 1; | 407 | vcpu_info->evtchn_upcall_pending = 1; |