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 | |
| 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>
| -rw-r--r-- | drivers/xen/events.c | 45 | ||||
| -rw-r--r-- | include/xen/interface/physdev.h | 10 |
2 files changed, 30 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), |
diff --git a/include/xen/interface/physdev.h b/include/xen/interface/physdev.h index 2b2c66c3df00..534cac89a77d 100644 --- a/include/xen/interface/physdev.h +++ b/include/xen/interface/physdev.h | |||
| @@ -188,6 +188,16 @@ struct physdev_nr_pirqs { | |||
| 188 | uint32_t nr_pirqs; | 188 | uint32_t nr_pirqs; |
| 189 | }; | 189 | }; |
| 190 | 190 | ||
| 191 | /* type is MAP_PIRQ_TYPE_GSI or MAP_PIRQ_TYPE_MSI | ||
| 192 | * the hypercall returns a free pirq */ | ||
| 193 | #define PHYSDEVOP_get_free_pirq 23 | ||
| 194 | struct physdev_get_free_pirq { | ||
| 195 | /* IN */ | ||
| 196 | int type; | ||
| 197 | /* OUT */ | ||
| 198 | uint32_t pirq; | ||
| 199 | }; | ||
| 200 | |||
| 191 | /* | 201 | /* |
| 192 | * Notify that some PIRQ-bound event channels have been unmasked. | 202 | * Notify that some PIRQ-bound event channels have been unmasked. |
| 193 | * ** This command is obsolete since interface version 0x00030202 and is ** | 203 | * ** This command is obsolete since interface version 0x00030202 and is ** |
