aboutsummaryrefslogtreecommitdiffstats
path: root/drivers
diff options
context:
space:
mode:
Diffstat (limited to 'drivers')
-rw-r--r--drivers/xen/events.c77
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
379static int get_nr_hw_irqs(void) 379static 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; 396retry:
388} 397 irq = irq_alloc_desc_from(first, -1);
389 398
390static 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
429no_irqs:
430 panic("No available IRQ to bind to: increase nr_irqs!\n");
431}
432
433static 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
439static int xen_allocate_irq_gsi(unsigned gsi) 411static 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. */