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 | ||
