diff options
Diffstat (limited to 'drivers')
-rw-r--r-- | drivers/xen/events.c | 77 |
1 files changed, 27 insertions, 50 deletions
diff --git a/drivers/xen/events.c b/drivers/xen/events.c index 81a53eb6cd1d..06f2e61de691 100644 --- a/drivers/xen/events.c +++ b/drivers/xen/events.c | |||
@@ -376,72 +376,49 @@ static void unmask_evtchn(int port) | |||
376 | put_cpu(); | 376 | put_cpu(); |
377 | } | 377 | } |
378 | 378 | ||
379 | static int get_nr_hw_irqs(void) | 379 | static int xen_allocate_irq_dynamic(void) |
380 | { | 380 | { |
381 | int ret = 1; | 381 | int first = 0; |
382 | int irq; | ||
382 | 383 | ||
383 | #ifdef CONFIG_X86_IO_APIC | 384 | #ifdef CONFIG_X86_IO_APIC |
384 | ret = get_nr_irqs_gsi(); | 385 | /* |
386 | * For an HVM guest or domain 0 which see "real" (emulated or | ||
387 | * actual repectively) GSIs we allocate dynamic IRQs | ||
388 | * e.g. those corresponding to event channels or MSIs | ||
389 | * etc. from the range above those "real" GSIs to avoid | ||
390 | * collisions. | ||
391 | */ | ||
392 | if (xen_initial_domain() || xen_hvm_domain()) | ||
393 | first = get_nr_irqs_gsi(); | ||
385 | #endif | 394 | #endif |
386 | 395 | ||
387 | return ret; | 396 | retry: |
388 | } | 397 | irq = irq_alloc_desc_from(first, -1); |
389 | 398 | ||
390 | static int xen_allocate_irq_dynamic(void) | 399 | if (irq == -ENOMEM && first > NR_IRQS_LEGACY) { |
391 | { | 400 | printk(KERN_ERR "Out of dynamic IRQ space and eating into GSI space. You should increase nr_irqs\n"); |
392 | struct irq_data *data; | 401 | first = max(NR_IRQS_LEGACY, first - NR_IRQS_LEGACY); |
393 | int irq, res; | 402 | goto retry; |
394 | int bottom = get_nr_hw_irqs(); | ||
395 | int top = nr_irqs-1; | ||
396 | |||
397 | if (bottom == nr_irqs) | ||
398 | goto no_irqs; | ||
399 | |||
400 | /* This loop starts from the top of IRQ space and goes down. | ||
401 | * We need this b/c if we have a PCI device in a Xen PV guest | ||
402 | * we do not have an IO-APIC (though the backend might have them) | ||
403 | * mapped in. To not have a collision of physical IRQs with the Xen | ||
404 | * event channels start at the top of the IRQ space for virtual IRQs. | ||
405 | */ | ||
406 | for (irq = top; irq > bottom; irq--) { | ||
407 | data = irq_get_irq_data(irq); | ||
408 | /* only 15->0 have init'd desc; handle irq > 16 */ | ||
409 | if (!data) | ||
410 | break; | ||
411 | if (data->chip == &no_irq_chip) | ||
412 | break; | ||
413 | if (data->chip != &xen_dynamic_chip) | ||
414 | continue; | ||
415 | if (irq_info[irq].type == IRQT_UNBOUND) | ||
416 | return irq; | ||
417 | } | 403 | } |
418 | 404 | ||
419 | if (irq == bottom) | 405 | if (irq < 0) |
420 | goto no_irqs; | 406 | panic("No available IRQ to bind to: increase nr_irqs!\n"); |
421 | |||
422 | res = irq_alloc_desc_at(irq, -1); | ||
423 | |||
424 | if (WARN_ON(res != irq)) | ||
425 | return -1; | ||
426 | 407 | ||
427 | return irq; | 408 | return irq; |
428 | |||
429 | no_irqs: | ||
430 | panic("No available IRQ to bind to: increase nr_irqs!\n"); | ||
431 | } | ||
432 | |||
433 | static bool identity_mapped_irq(unsigned irq) | ||
434 | { | ||
435 | /* identity map all the hardware irqs */ | ||
436 | return irq < get_nr_hw_irqs(); | ||
437 | } | 409 | } |
438 | 410 | ||
439 | static int xen_allocate_irq_gsi(unsigned gsi) | 411 | static int xen_allocate_irq_gsi(unsigned gsi) |
440 | { | 412 | { |
441 | int irq; | 413 | int irq; |
442 | 414 | ||
443 | if (!identity_mapped_irq(gsi) && | 415 | /* |
444 | (xen_initial_domain() || !xen_pv_domain())) | 416 | * A PV guest has no concept of a GSI (since it has no ACPI |
417 | * nor access to/knowledge of the physical APICs). Therefore | ||
418 | * all IRQs are dynamically allocated from the entire IRQ | ||
419 | * space. | ||
420 | */ | ||
421 | if (xen_pv_domain() && !xen_initial_domain()) | ||
445 | return xen_allocate_irq_dynamic(); | 422 | return xen_allocate_irq_dynamic(); |
446 | 423 | ||
447 | /* Legacy IRQ descriptors are already allocated by the arch. */ | 424 | /* Legacy IRQ descriptors are already allocated by the arch. */ |