aboutsummaryrefslogtreecommitdiffstats
path: root/drivers
diff options
context:
space:
mode:
authorIan Campbell <ian.campbell@citrix.com>2011-03-03 11:57:44 -0500
committerKonrad Rzeszutek Wilk <konrad.wilk@oracle.com>2011-03-03 12:00:21 -0500
commit89911501f3aae44a43984793341a3bf1f4c583c2 (patch)
tree2d708361166bf75283561072008580ca2b5681e2 /drivers
parentc9df1ce585e3bb5a2f101c1d87381b285a9f962f (diff)
xen: events: allocate GSIs and dynamic IRQs from separate IRQ ranges.
There are three cases which we need to care about, PV guest, PV domain 0 and HVM guest. The PV guest case is simple since it has no access to ACPI or real APICs and therefore has no GSIs therefore we simply dynamically allocate all IRQs. The potentially interesting case here is PIRQ type event channels associated with passed through PCI devices. However even in this case the guest has no direct interaction with the physical GSI since that happens in the PCI backend. The PV domain 0 and HVM guest cases are actually the same. In domain 0 case the kernel sees the host ACPI and GSIs (although it only sees the APIC indirectly via the hypervisor) and in the HVM guest case it sees the virtualised ACPI and emulated APICs. In these cases we start allocating dynamic IRQs at nr_irqs_gsi so that they cannot clash with any GSI. Currently xen_allocate_irq_dynamic starts at nr_irqs and works backwards looking for a free IRQ in order to (try and) avoid clashing with GSIs used in domain 0 and in HVM guests. This change avoids that although we retain the behaviour of allowing dynamic IRQs to encroach on the GSI range if no suitable IRQs are available since a future IRQ clash is deemed preferable to failure right now. Signed-off-by: Ian Campbell <ian.campbell@citrix.com> Signed-off-by: Konrad Rzeszutek Wilk <konrad.wilk@oracle.com> Cc: Stefano Stabellini <stefano.stabellini@eu.citrix.com> Cc: Jeremy Fitzhardinge <jeremy@goop.org>
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. */