diff options
author | Linus Torvalds <torvalds@linux-foundation.org> | 2010-12-03 14:30:57 -0500 |
---|---|---|
committer | Linus Torvalds <torvalds@linux-foundation.org> | 2010-12-03 14:30:57 -0500 |
commit | 11e8896474495dec7ce19a542f67def847ec208f (patch) | |
tree | 3eeb941629110b2ad9f5a3fe08fa23c846f6a44e /drivers/xen | |
parent | 8338fded137681bc3c1e99a69ac937a4fb016fe4 (diff) | |
parent | 512b109ec9620d037d6d2f6bd1bae9ce34dd6779 (diff) |
Merge branch '2.6.37-rc4-pvhvm-fixes' of git://xenbits.xen.org/people/sstabellini/linux-pvhvm
* '2.6.37-rc4-pvhvm-fixes' of git://xenbits.xen.org/people/sstabellini/linux-pvhvm:
xen: unplug the emulated devices at resume time
xen: fix save/restore for PV on HVM guests with pirq remapping
xen: resume the pv console for hvm guests too
xen: fix MSI setup and teardown for PV on HVM guests
xen: use PHYSDEVOP_get_free_pirq to implement find_unbound_pirq
Diffstat (limited to 'drivers/xen')
-rw-r--r-- | drivers/xen/events.c | 105 | ||||
-rw-r--r-- | drivers/xen/manage.c | 1 |
2 files changed, 75 insertions, 31 deletions
diff --git a/drivers/xen/events.c b/drivers/xen/events.c index 0009e489272c..31af0ac31a98 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 | ||
@@ -664,17 +668,21 @@ out: | |||
664 | #include <linux/msi.h> | 668 | #include <linux/msi.h> |
665 | #include "../pci/msi.h" | 669 | #include "../pci/msi.h" |
666 | 670 | ||
667 | void xen_allocate_pirq_msi(char *name, int *irq, int *pirq) | 671 | void xen_allocate_pirq_msi(char *name, int *irq, int *pirq, int alloc) |
668 | { | 672 | { |
669 | spin_lock(&irq_mapping_update_lock); | 673 | spin_lock(&irq_mapping_update_lock); |
670 | 674 | ||
671 | *irq = find_unbound_irq(); | 675 | if (alloc & XEN_ALLOC_IRQ) { |
672 | if (*irq == -1) | 676 | *irq = find_unbound_irq(); |
673 | goto out; | 677 | if (*irq == -1) |
678 | goto out; | ||
679 | } | ||
674 | 680 | ||
675 | *pirq = find_unbound_pirq(); | 681 | if (alloc & XEN_ALLOC_PIRQ) { |
676 | if (*pirq == -1) | 682 | *pirq = find_unbound_pirq(MAP_PIRQ_TYPE_MSI); |
677 | goto out; | 683 | if (*pirq == -1) |
684 | goto out; | ||
685 | } | ||
678 | 686 | ||
679 | set_irq_chip_and_handler_name(*irq, &xen_pirq_chip, | 687 | set_irq_chip_and_handler_name(*irq, &xen_pirq_chip, |
680 | handle_level_irq, name); | 688 | handle_level_irq, name); |
@@ -762,6 +770,7 @@ int xen_destroy_irq(int irq) | |||
762 | printk(KERN_WARNING "unmap irq failed %d\n", rc); | 770 | printk(KERN_WARNING "unmap irq failed %d\n", rc); |
763 | goto out; | 771 | goto out; |
764 | } | 772 | } |
773 | pirq_to_irq[info->u.pirq.pirq] = -1; | ||
765 | } | 774 | } |
766 | irq_info[irq] = mk_unbound_info(); | 775 | irq_info[irq] = mk_unbound_info(); |
767 | 776 | ||
@@ -782,6 +791,11 @@ int xen_gsi_from_irq(unsigned irq) | |||
782 | return gsi_from_irq(irq); | 791 | return gsi_from_irq(irq); |
783 | } | 792 | } |
784 | 793 | ||
794 | int xen_irq_from_pirq(unsigned pirq) | ||
795 | { | ||
796 | return pirq_to_irq[pirq]; | ||
797 | } | ||
798 | |||
785 | int bind_evtchn_to_irq(unsigned int evtchn) | 799 | int bind_evtchn_to_irq(unsigned int evtchn) |
786 | { | 800 | { |
787 | int irq; | 801 | int irq; |
@@ -1279,6 +1293,42 @@ static int retrigger_dynirq(unsigned int irq) | |||
1279 | return ret; | 1293 | return ret; |
1280 | } | 1294 | } |
1281 | 1295 | ||
1296 | static void restore_cpu_pirqs(void) | ||
1297 | { | ||
1298 | int pirq, rc, irq, gsi; | ||
1299 | struct physdev_map_pirq map_irq; | ||
1300 | |||
1301 | for (pirq = 0; pirq < nr_irqs; pirq++) { | ||
1302 | irq = pirq_to_irq[pirq]; | ||
1303 | if (irq == -1) | ||
1304 | continue; | ||
1305 | |||
1306 | /* save/restore of PT devices doesn't work, so at this point the | ||
1307 | * only devices present are GSI based emulated devices */ | ||
1308 | gsi = gsi_from_irq(irq); | ||
1309 | if (!gsi) | ||
1310 | continue; | ||
1311 | |||
1312 | map_irq.domid = DOMID_SELF; | ||
1313 | map_irq.type = MAP_PIRQ_TYPE_GSI; | ||
1314 | map_irq.index = gsi; | ||
1315 | map_irq.pirq = pirq; | ||
1316 | |||
1317 | rc = HYPERVISOR_physdev_op(PHYSDEVOP_map_pirq, &map_irq); | ||
1318 | if (rc) { | ||
1319 | printk(KERN_WARNING "xen map irq failed gsi=%d irq=%d pirq=%d rc=%d\n", | ||
1320 | gsi, irq, pirq, rc); | ||
1321 | irq_info[irq] = mk_unbound_info(); | ||
1322 | pirq_to_irq[pirq] = -1; | ||
1323 | continue; | ||
1324 | } | ||
1325 | |||
1326 | printk(KERN_DEBUG "xen: --> irq=%d, pirq=%d\n", irq, map_irq.pirq); | ||
1327 | |||
1328 | startup_pirq(irq); | ||
1329 | } | ||
1330 | } | ||
1331 | |||
1282 | static void restore_cpu_virqs(unsigned int cpu) | 1332 | static void restore_cpu_virqs(unsigned int cpu) |
1283 | { | 1333 | { |
1284 | struct evtchn_bind_virq bind_virq; | 1334 | struct evtchn_bind_virq bind_virq; |
@@ -1422,6 +1472,8 @@ void xen_irq_resume(void) | |||
1422 | 1472 | ||
1423 | unmask_evtchn(evtchn); | 1473 | unmask_evtchn(evtchn); |
1424 | } | 1474 | } |
1475 | |||
1476 | restore_cpu_pirqs(); | ||
1425 | } | 1477 | } |
1426 | 1478 | ||
1427 | static struct irq_chip xen_dynamic_chip __read_mostly = { | 1479 | static struct irq_chip xen_dynamic_chip __read_mostly = { |
@@ -1506,26 +1558,17 @@ void xen_callback_vector(void) {} | |||
1506 | 1558 | ||
1507 | void __init xen_init_IRQ(void) | 1559 | void __init xen_init_IRQ(void) |
1508 | { | 1560 | { |
1509 | int i, rc; | 1561 | int i; |
1510 | struct physdev_nr_pirqs op_nr_pirqs; | ||
1511 | 1562 | ||
1512 | cpu_evtchn_mask_p = kcalloc(nr_cpu_ids, sizeof(struct cpu_evtchn_s), | 1563 | cpu_evtchn_mask_p = kcalloc(nr_cpu_ids, sizeof(struct cpu_evtchn_s), |
1513 | GFP_KERNEL); | 1564 | GFP_KERNEL); |
1514 | irq_info = kcalloc(nr_irqs, sizeof(*irq_info), GFP_KERNEL); | 1565 | irq_info = kcalloc(nr_irqs, sizeof(*irq_info), GFP_KERNEL); |
1515 | 1566 | ||
1516 | rc = HYPERVISOR_physdev_op(PHYSDEVOP_get_nr_pirqs, &op_nr_pirqs); | 1567 | /* We are using nr_irqs as the maximum number of pirq available but |
1517 | if (rc < 0) { | 1568 | * that number is actually chosen by Xen and we don't know exactly |
1518 | nr_pirqs = nr_irqs; | 1569 | * what it is. Be careful choosing high pirq numbers. */ |
1519 | if (rc != -ENOSYS) | 1570 | 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); | 1571 | 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; | 1572 | pirq_to_irq[i] = -1; |
1530 | 1573 | ||
1531 | evtchn_to_irq = kcalloc(NR_EVENT_CHANNELS, sizeof(*evtchn_to_irq), | 1574 | evtchn_to_irq = kcalloc(NR_EVENT_CHANNELS, sizeof(*evtchn_to_irq), |
diff --git a/drivers/xen/manage.c b/drivers/xen/manage.c index ef9c7db52077..db8c4c4ac880 100644 --- a/drivers/xen/manage.c +++ b/drivers/xen/manage.c | |||
@@ -49,6 +49,7 @@ static int xen_hvm_suspend(void *data) | |||
49 | 49 | ||
50 | if (!*cancelled) { | 50 | if (!*cancelled) { |
51 | xen_irq_resume(); | 51 | xen_irq_resume(); |
52 | xen_console_resume(); | ||
52 | xen_timer_resume(); | 53 | xen_timer_resume(); |
53 | } | 54 | } |
54 | 55 | ||