diff options
author | Stefano Stabellini <stefano.stabellini@eu.citrix.com> | 2010-12-01 09:51:44 -0500 |
---|---|---|
committer | Stefano Stabellini <stefano.stabellini@eu.citrix.com> | 2010-12-02 09:28:22 -0500 |
commit | e5fc7345412d5e4758fcef55a74354c5cbefd61e (patch) | |
tree | 00f8303544240826fb2dd2b97de5ff66596e7beb /drivers | |
parent | e8a7e48bb248a1196484d3f8afa53bded2b24e71 (diff) |
xen: use PHYSDEVOP_get_free_pirq to implement find_unbound_pirq
Use the new hypercall PHYSDEVOP_get_free_pirq to ask Xen to allocate a
pirq. Remove the unsupported PHYSDEVOP_get_nr_pirqs hypercall to get the
amount of pirq available.
This fixes find_unbound_pirq that otherwise would return a number
starting from nr_irqs that might very well be out of range in Xen.
The symptom of this bug is that when you passthrough an MSI capable pci
device to a PV on HVM guest, Linux would fail to enable MSIs on the
device.
Signed-off-by: Stefano Stabellini <stefano.stabellini@eu.citrix.com>
Diffstat (limited to 'drivers')
-rw-r--r-- | drivers/xen/events.c | 45 |
1 files changed, 20 insertions, 25 deletions
diff --git a/drivers/xen/events.c b/drivers/xen/events.c index 2811bb988ea0..7ab43c33f746 100644 --- a/drivers/xen/events.c +++ b/drivers/xen/events.c | |||
@@ -105,7 +105,6 @@ struct irq_info | |||
105 | 105 | ||
106 | static struct irq_info *irq_info; | 106 | static struct irq_info *irq_info; |
107 | static int *pirq_to_irq; | 107 | static int *pirq_to_irq; |
108 | static int nr_pirqs; | ||
109 | 108 | ||
110 | static int *evtchn_to_irq; | 109 | static int *evtchn_to_irq; |
111 | struct cpu_evtchn_s { | 110 | struct cpu_evtchn_s { |
@@ -385,12 +384,17 @@ static int get_nr_hw_irqs(void) | |||
385 | return ret; | 384 | return ret; |
386 | } | 385 | } |
387 | 386 | ||
388 | /* callers of this function should make sure that PHYSDEVOP_get_nr_pirqs | 387 | static int find_unbound_pirq(int type) |
389 | * succeeded otherwise nr_pirqs won't hold the right value */ | ||
390 | static int find_unbound_pirq(void) | ||
391 | { | 388 | { |
392 | int i; | 389 | int rc, i; |
393 | for (i = nr_pirqs-1; i >= 0; i--) { | 390 | struct physdev_get_free_pirq op_get_free_pirq; |
391 | op_get_free_pirq.type = type; | ||
392 | |||
393 | rc = HYPERVISOR_physdev_op(PHYSDEVOP_get_free_pirq, &op_get_free_pirq); | ||
394 | if (!rc) | ||
395 | return op_get_free_pirq.pirq; | ||
396 | |||
397 | for (i = 0; i < nr_irqs; i++) { | ||
394 | if (pirq_to_irq[i] < 0) | 398 | if (pirq_to_irq[i] < 0) |
395 | return i; | 399 | return i; |
396 | } | 400 | } |
@@ -611,10 +615,10 @@ int xen_map_pirq_gsi(unsigned pirq, unsigned gsi, int shareable, char *name) | |||
611 | 615 | ||
612 | spin_lock(&irq_mapping_update_lock); | 616 | spin_lock(&irq_mapping_update_lock); |
613 | 617 | ||
614 | if ((pirq > nr_pirqs) || (gsi > nr_irqs)) { | 618 | if ((pirq > nr_irqs) || (gsi > nr_irqs)) { |
615 | printk(KERN_WARNING "xen_map_pirq_gsi: %s %s is incorrect!\n", | 619 | printk(KERN_WARNING "xen_map_pirq_gsi: %s %s is incorrect!\n", |
616 | pirq > nr_pirqs ? "nr_pirqs" :"", | 620 | pirq > nr_irqs ? "pirq" :"", |
617 | gsi > nr_irqs ? "nr_irqs" : ""); | 621 | gsi > nr_irqs ? "gsi" : ""); |
618 | goto out; | 622 | goto out; |
619 | } | 623 | } |
620 | 624 | ||
@@ -672,7 +676,7 @@ void xen_allocate_pirq_msi(char *name, int *irq, int *pirq) | |||
672 | if (*irq == -1) | 676 | if (*irq == -1) |
673 | goto out; | 677 | goto out; |
674 | 678 | ||
675 | *pirq = find_unbound_pirq(); | 679 | *pirq = find_unbound_pirq(MAP_PIRQ_TYPE_MSI); |
676 | if (*pirq == -1) | 680 | if (*pirq == -1) |
677 | goto out; | 681 | goto out; |
678 | 682 | ||
@@ -1506,26 +1510,17 @@ void xen_callback_vector(void) {} | |||
1506 | 1510 | ||
1507 | void __init xen_init_IRQ(void) | 1511 | void __init xen_init_IRQ(void) |
1508 | { | 1512 | { |
1509 | int i, rc; | 1513 | int i; |
1510 | struct physdev_nr_pirqs op_nr_pirqs; | ||
1511 | 1514 | ||
1512 | cpu_evtchn_mask_p = kcalloc(nr_cpu_ids, sizeof(struct cpu_evtchn_s), | 1515 | cpu_evtchn_mask_p = kcalloc(nr_cpu_ids, sizeof(struct cpu_evtchn_s), |
1513 | GFP_KERNEL); | 1516 | GFP_KERNEL); |
1514 | irq_info = kcalloc(nr_irqs, sizeof(*irq_info), GFP_KERNEL); | 1517 | irq_info = kcalloc(nr_irqs, sizeof(*irq_info), GFP_KERNEL); |
1515 | 1518 | ||
1516 | rc = HYPERVISOR_physdev_op(PHYSDEVOP_get_nr_pirqs, &op_nr_pirqs); | 1519 | /* We are using nr_irqs as the maximum number of pirq available but |
1517 | if (rc < 0) { | 1520 | * that number is actually chosen by Xen and we don't know exactly |
1518 | nr_pirqs = nr_irqs; | 1521 | * what it is. Be careful choosing high pirq numbers. */ |
1519 | if (rc != -ENOSYS) | 1522 | pirq_to_irq = kcalloc(nr_irqs, sizeof(*pirq_to_irq), GFP_KERNEL); |
1520 | printk(KERN_WARNING "PHYSDEVOP_get_nr_pirqs returned rc=%d\n", rc); | 1523 | for (i = 0; i < nr_irqs; i++) |
1521 | } else { | ||
1522 | if (xen_pv_domain() && !xen_initial_domain()) | ||
1523 | nr_pirqs = max((int)op_nr_pirqs.nr_pirqs, nr_irqs); | ||
1524 | else | ||
1525 | nr_pirqs = op_nr_pirqs.nr_pirqs; | ||
1526 | } | ||
1527 | pirq_to_irq = kcalloc(nr_pirqs, sizeof(*pirq_to_irq), GFP_KERNEL); | ||
1528 | for (i = 0; i < nr_pirqs; i++) | ||
1529 | pirq_to_irq[i] = -1; | 1524 | pirq_to_irq[i] = -1; |
1530 | 1525 | ||
1531 | evtchn_to_irq = kcalloc(NR_EVENT_CHANNELS, sizeof(*evtchn_to_irq), | 1526 | evtchn_to_irq = kcalloc(NR_EVENT_CHANNELS, sizeof(*evtchn_to_irq), |