diff options
Diffstat (limited to 'drivers/xen/events.c')
-rw-r--r-- | drivers/xen/events.c | 39 |
1 files changed, 30 insertions, 9 deletions
diff --git a/drivers/xen/events.c b/drivers/xen/events.c index d17aa41a9041..2647ad8e1f19 100644 --- a/drivers/xen/events.c +++ b/drivers/xen/events.c | |||
@@ -403,11 +403,23 @@ static void unmask_evtchn(int port) | |||
403 | 403 | ||
404 | if (unlikely((cpu != cpu_from_evtchn(port)))) | 404 | if (unlikely((cpu != cpu_from_evtchn(port)))) |
405 | do_hypercall = 1; | 405 | do_hypercall = 1; |
406 | else | 406 | else { |
407 | /* | ||
408 | * Need to clear the mask before checking pending to | ||
409 | * avoid a race with an event becoming pending. | ||
410 | * | ||
411 | * EVTCHNOP_unmask will only trigger an upcall if the | ||
412 | * mask bit was set, so if a hypercall is needed | ||
413 | * remask the event. | ||
414 | */ | ||
415 | sync_clear_bit(port, BM(&s->evtchn_mask[0])); | ||
407 | evtchn_pending = sync_test_bit(port, BM(&s->evtchn_pending[0])); | 416 | evtchn_pending = sync_test_bit(port, BM(&s->evtchn_pending[0])); |
408 | 417 | ||
409 | if (unlikely(evtchn_pending && xen_hvm_domain())) | 418 | if (unlikely(evtchn_pending && xen_hvm_domain())) { |
410 | do_hypercall = 1; | 419 | sync_set_bit(port, BM(&s->evtchn_mask[0])); |
420 | do_hypercall = 1; | ||
421 | } | ||
422 | } | ||
411 | 423 | ||
412 | /* Slow path (hypercall) if this is a non-local port or if this is | 424 | /* Slow path (hypercall) if this is a non-local port or if this is |
413 | * an hvm domain and an event is pending (hvm domains don't have | 425 | * an hvm domain and an event is pending (hvm domains don't have |
@@ -418,8 +430,6 @@ static void unmask_evtchn(int port) | |||
418 | } else { | 430 | } else { |
419 | struct vcpu_info *vcpu_info = __this_cpu_read(xen_vcpu); | 431 | struct vcpu_info *vcpu_info = __this_cpu_read(xen_vcpu); |
420 | 432 | ||
421 | sync_clear_bit(port, BM(&s->evtchn_mask[0])); | ||
422 | |||
423 | /* | 433 | /* |
424 | * The following is basically the equivalent of | 434 | * The following is basically the equivalent of |
425 | * 'hw_resend_irq'. Just like a real IO-APIC we 'lose | 435 | * 'hw_resend_irq'. Just like a real IO-APIC we 'lose |
@@ -1306,7 +1316,7 @@ static void __xen_evtchn_do_upcall(void) | |||
1306 | { | 1316 | { |
1307 | int start_word_idx, start_bit_idx; | 1317 | int start_word_idx, start_bit_idx; |
1308 | int word_idx, bit_idx; | 1318 | int word_idx, bit_idx; |
1309 | int i; | 1319 | int i, irq; |
1310 | int cpu = get_cpu(); | 1320 | int cpu = get_cpu(); |
1311 | struct shared_info *s = HYPERVISOR_shared_info; | 1321 | struct shared_info *s = HYPERVISOR_shared_info; |
1312 | struct vcpu_info *vcpu_info = __this_cpu_read(xen_vcpu); | 1322 | struct vcpu_info *vcpu_info = __this_cpu_read(xen_vcpu); |
@@ -1314,6 +1324,8 @@ static void __xen_evtchn_do_upcall(void) | |||
1314 | 1324 | ||
1315 | do { | 1325 | do { |
1316 | xen_ulong_t pending_words; | 1326 | xen_ulong_t pending_words; |
1327 | xen_ulong_t pending_bits; | ||
1328 | struct irq_desc *desc; | ||
1317 | 1329 | ||
1318 | vcpu_info->evtchn_upcall_pending = 0; | 1330 | vcpu_info->evtchn_upcall_pending = 0; |
1319 | 1331 | ||
@@ -1325,6 +1337,17 @@ static void __xen_evtchn_do_upcall(void) | |||
1325 | * selector flag. xchg_xen_ulong must contain an | 1337 | * selector flag. xchg_xen_ulong must contain an |
1326 | * appropriate barrier. | 1338 | * appropriate barrier. |
1327 | */ | 1339 | */ |
1340 | if ((irq = per_cpu(virq_to_irq, cpu)[VIRQ_TIMER]) != -1) { | ||
1341 | int evtchn = evtchn_from_irq(irq); | ||
1342 | word_idx = evtchn / BITS_PER_LONG; | ||
1343 | pending_bits = evtchn % BITS_PER_LONG; | ||
1344 | if (active_evtchns(cpu, s, word_idx) & (1ULL << pending_bits)) { | ||
1345 | desc = irq_to_desc(irq); | ||
1346 | if (desc) | ||
1347 | generic_handle_irq_desc(irq, desc); | ||
1348 | } | ||
1349 | } | ||
1350 | |||
1328 | pending_words = xchg_xen_ulong(&vcpu_info->evtchn_pending_sel, 0); | 1351 | pending_words = xchg_xen_ulong(&vcpu_info->evtchn_pending_sel, 0); |
1329 | 1352 | ||
1330 | start_word_idx = __this_cpu_read(current_word_idx); | 1353 | start_word_idx = __this_cpu_read(current_word_idx); |
@@ -1333,7 +1356,6 @@ static void __xen_evtchn_do_upcall(void) | |||
1333 | word_idx = start_word_idx; | 1356 | word_idx = start_word_idx; |
1334 | 1357 | ||
1335 | for (i = 0; pending_words != 0; i++) { | 1358 | for (i = 0; pending_words != 0; i++) { |
1336 | xen_ulong_t pending_bits; | ||
1337 | xen_ulong_t words; | 1359 | xen_ulong_t words; |
1338 | 1360 | ||
1339 | words = MASK_LSBS(pending_words, word_idx); | 1361 | words = MASK_LSBS(pending_words, word_idx); |
@@ -1362,8 +1384,7 @@ static void __xen_evtchn_do_upcall(void) | |||
1362 | 1384 | ||
1363 | do { | 1385 | do { |
1364 | xen_ulong_t bits; | 1386 | xen_ulong_t bits; |
1365 | int port, irq; | 1387 | int port; |
1366 | struct irq_desc *desc; | ||
1367 | 1388 | ||
1368 | bits = MASK_LSBS(pending_bits, bit_idx); | 1389 | bits = MASK_LSBS(pending_bits, bit_idx); |
1369 | 1390 | ||