diff options
author | Jeremy Fitzhardinge <jeremy.fitzhardinge@citrix.com> | 2010-08-04 17:49:16 -0400 |
---|---|---|
committer | Jeremy Fitzhardinge <jeremy.fitzhardinge@citrix.com> | 2010-08-04 17:49:16 -0400 |
commit | ca50a5f39041497253c6362f2ba4da1b56d3e6cb (patch) | |
tree | 482f1607d12b60f6ef482bb4af2c9c58d7814d5f /drivers/xen | |
parent | a70ce4b6064b64477ed12ef1878980f842819094 (diff) | |
parent | ca65f9fc0c447da5b270b05c41c21b19c88617c3 (diff) |
Merge branch 'upstream/pvhvm' into upstream/xen
* upstream/pvhvm:
Introduce CONFIG_XEN_PVHVM compile option
blkfront: do not create a PV cdrom device if xen_hvm_guest
support multiple .discard.* sections to avoid section type conflicts
xen/pvhvm: fix build problem when !CONFIG_XEN
xenfs: enable for HVM domains too
x86: Call HVMOP_pagetable_dying on exit_mmap.
x86: Unplug emulated disks and nics.
x86: Use xen_vcpuop_clockevent, xen_clocksource and xen wallclock.
xen: Fix find_unbound_irq in presence of ioapic irqs.
xen: Add suspend/resume support for PV on HVM guests.
xen: Xen PCI platform device driver.
x86/xen: event channels delivery on HVM.
x86: early PV on HVM features initialization.
xen: Add support for HVM hypercalls.
Conflicts:
arch/x86/xen/enlighten.c
arch/x86/xen/time.c
Diffstat (limited to 'drivers/xen')
-rw-r--r-- | drivers/xen/Kconfig | 9 | ||||
-rw-r--r-- | drivers/xen/Makefile | 3 | ||||
-rw-r--r-- | drivers/xen/events.c | 95 | ||||
-rw-r--r-- | drivers/xen/grant-table.c | 77 | ||||
-rw-r--r-- | drivers/xen/manage.c | 46 | ||||
-rw-r--r-- | drivers/xen/platform-pci.c | 207 | ||||
-rw-r--r-- | drivers/xen/xenbus/xenbus_probe.c | 47 | ||||
-rw-r--r-- | drivers/xen/xenfs/super.c | 4 |
8 files changed, 452 insertions, 36 deletions
diff --git a/drivers/xen/Kconfig b/drivers/xen/Kconfig index fad3df2c1276..0a8826936639 100644 --- a/drivers/xen/Kconfig +++ b/drivers/xen/Kconfig | |||
@@ -62,4 +62,13 @@ config XEN_SYS_HYPERVISOR | |||
62 | virtual environment, /sys/hypervisor will still be present, | 62 | virtual environment, /sys/hypervisor will still be present, |
63 | but will have no xen contents. | 63 | but will have no xen contents. |
64 | 64 | ||
65 | config XEN_PLATFORM_PCI | ||
66 | tristate "xen platform pci device driver" | ||
67 | depends on XEN_PVHVM | ||
68 | default m | ||
69 | help | ||
70 | Driver for the Xen PCI Platform device: it is responsible for | ||
71 | initializing xenbus and grant_table when running in a Xen HVM | ||
72 | domain. As a consequence this driver is required to run any Xen PV | ||
73 | frontend on Xen HVM. | ||
65 | endmenu | 74 | endmenu |
diff --git a/drivers/xen/Makefile b/drivers/xen/Makefile index 7c284342f30f..e392fb776af3 100644 --- a/drivers/xen/Makefile +++ b/drivers/xen/Makefile | |||
@@ -9,4 +9,5 @@ obj-$(CONFIG_XEN_XENCOMM) += xencomm.o | |||
9 | obj-$(CONFIG_XEN_BALLOON) += balloon.o | 9 | obj-$(CONFIG_XEN_BALLOON) += balloon.o |
10 | obj-$(CONFIG_XEN_DEV_EVTCHN) += evtchn.o | 10 | obj-$(CONFIG_XEN_DEV_EVTCHN) += evtchn.o |
11 | obj-$(CONFIG_XENFS) += xenfs/ | 11 | obj-$(CONFIG_XENFS) += xenfs/ |
12 | obj-$(CONFIG_XEN_SYS_HYPERVISOR) += sys-hypervisor.o \ No newline at end of file | 12 | obj-$(CONFIG_XEN_SYS_HYPERVISOR) += sys-hypervisor.o |
13 | obj-$(CONFIG_XEN_PLATFORM_PCI) += platform-pci.o | ||
diff --git a/drivers/xen/events.c b/drivers/xen/events.c index db8f506817f0..5e1f34892dcc 100644 --- a/drivers/xen/events.c +++ b/drivers/xen/events.c | |||
@@ -29,6 +29,7 @@ | |||
29 | #include <linux/bootmem.h> | 29 | #include <linux/bootmem.h> |
30 | #include <linux/slab.h> | 30 | #include <linux/slab.h> |
31 | 31 | ||
32 | #include <asm/desc.h> | ||
32 | #include <asm/ptrace.h> | 33 | #include <asm/ptrace.h> |
33 | #include <asm/irq.h> | 34 | #include <asm/irq.h> |
34 | #include <asm/idle.h> | 35 | #include <asm/idle.h> |
@@ -36,10 +37,14 @@ | |||
36 | #include <asm/xen/hypercall.h> | 37 | #include <asm/xen/hypercall.h> |
37 | #include <asm/xen/hypervisor.h> | 38 | #include <asm/xen/hypervisor.h> |
38 | 39 | ||
40 | #include <xen/xen.h> | ||
41 | #include <xen/hvm.h> | ||
39 | #include <xen/xen-ops.h> | 42 | #include <xen/xen-ops.h> |
40 | #include <xen/events.h> | 43 | #include <xen/events.h> |
41 | #include <xen/interface/xen.h> | 44 | #include <xen/interface/xen.h> |
42 | #include <xen/interface/event_channel.h> | 45 | #include <xen/interface/event_channel.h> |
46 | #include <xen/interface/hvm/hvm_op.h> | ||
47 | #include <xen/interface/hvm/params.h> | ||
43 | 48 | ||
44 | /* | 49 | /* |
45 | * This lock protects updates to the following mapping and reference-count | 50 | * This lock protects updates to the following mapping and reference-count |
@@ -335,9 +340,18 @@ static int find_unbound_irq(void) | |||
335 | int irq; | 340 | int irq; |
336 | struct irq_desc *desc; | 341 | struct irq_desc *desc; |
337 | 342 | ||
338 | for (irq = 0; irq < nr_irqs; irq++) | 343 | for (irq = 0; irq < nr_irqs; irq++) { |
344 | desc = irq_to_desc(irq); | ||
345 | /* only 0->15 have init'd desc; handle irq > 16 */ | ||
346 | if (desc == NULL) | ||
347 | break; | ||
348 | if (desc->chip == &no_irq_chip) | ||
349 | break; | ||
350 | if (desc->chip != &xen_dynamic_chip) | ||
351 | continue; | ||
339 | if (irq_info[irq].type == IRQT_UNBOUND) | 352 | if (irq_info[irq].type == IRQT_UNBOUND) |
340 | break; | 353 | break; |
354 | } | ||
341 | 355 | ||
342 | if (irq == nr_irqs) | 356 | if (irq == nr_irqs) |
343 | panic("No available IRQ to bind to: increase nr_irqs!\n"); | 357 | panic("No available IRQ to bind to: increase nr_irqs!\n"); |
@@ -346,7 +360,7 @@ static int find_unbound_irq(void) | |||
346 | if (WARN_ON(desc == NULL)) | 360 | if (WARN_ON(desc == NULL)) |
347 | return -1; | 361 | return -1; |
348 | 362 | ||
349 | dynamic_irq_init(irq); | 363 | dynamic_irq_init_keep_chip_data(irq); |
350 | 364 | ||
351 | return irq; | 365 | return irq; |
352 | } | 366 | } |
@@ -617,17 +631,13 @@ static DEFINE_PER_CPU(unsigned, xed_nesting_count); | |||
617 | * a bitset of words which contain pending event bits. The second | 631 | * a bitset of words which contain pending event bits. The second |
618 | * level is a bitset of pending events themselves. | 632 | * level is a bitset of pending events themselves. |
619 | */ | 633 | */ |
620 | void xen_evtchn_do_upcall(struct pt_regs *regs) | 634 | static void __xen_evtchn_do_upcall(void) |
621 | { | 635 | { |
622 | int cpu = get_cpu(); | 636 | int cpu = get_cpu(); |
623 | struct pt_regs *old_regs = set_irq_regs(regs); | ||
624 | struct shared_info *s = HYPERVISOR_shared_info; | 637 | struct shared_info *s = HYPERVISOR_shared_info; |
625 | struct vcpu_info *vcpu_info = __get_cpu_var(xen_vcpu); | 638 | struct vcpu_info *vcpu_info = __get_cpu_var(xen_vcpu); |
626 | unsigned count; | 639 | unsigned count; |
627 | 640 | ||
628 | exit_idle(); | ||
629 | irq_enter(); | ||
630 | |||
631 | do { | 641 | do { |
632 | unsigned long pending_words; | 642 | unsigned long pending_words; |
633 | 643 | ||
@@ -664,14 +674,31 @@ void xen_evtchn_do_upcall(struct pt_regs *regs) | |||
664 | 674 | ||
665 | count = __get_cpu_var(xed_nesting_count); | 675 | count = __get_cpu_var(xed_nesting_count); |
666 | __get_cpu_var(xed_nesting_count) = 0; | 676 | __get_cpu_var(xed_nesting_count) = 0; |
667 | } while(count != 1); | 677 | } while (count != 1 || vcpu_info->evtchn_upcall_pending); |
668 | 678 | ||
669 | out: | 679 | out: |
680 | |||
681 | put_cpu(); | ||
682 | } | ||
683 | |||
684 | void xen_evtchn_do_upcall(struct pt_regs *regs) | ||
685 | { | ||
686 | struct pt_regs *old_regs = set_irq_regs(regs); | ||
687 | |||
688 | exit_idle(); | ||
689 | irq_enter(); | ||
690 | |||
691 | __xen_evtchn_do_upcall(); | ||
692 | |||
670 | irq_exit(); | 693 | irq_exit(); |
671 | set_irq_regs(old_regs); | 694 | set_irq_regs(old_regs); |
695 | } | ||
672 | 696 | ||
673 | put_cpu(); | 697 | void xen_hvm_evtchn_do_upcall(void) |
698 | { | ||
699 | __xen_evtchn_do_upcall(); | ||
674 | } | 700 | } |
701 | EXPORT_SYMBOL_GPL(xen_hvm_evtchn_do_upcall); | ||
675 | 702 | ||
676 | /* Rebind a new event channel to an existing irq. */ | 703 | /* Rebind a new event channel to an existing irq. */ |
677 | void rebind_evtchn_irq(int evtchn, int irq) | 704 | void rebind_evtchn_irq(int evtchn, int irq) |
@@ -708,7 +735,10 @@ static int rebind_irq_to_cpu(unsigned irq, unsigned tcpu) | |||
708 | struct evtchn_bind_vcpu bind_vcpu; | 735 | struct evtchn_bind_vcpu bind_vcpu; |
709 | int evtchn = evtchn_from_irq(irq); | 736 | int evtchn = evtchn_from_irq(irq); |
710 | 737 | ||
711 | if (!VALID_EVTCHN(evtchn)) | 738 | /* events delivered via platform PCI interrupts are always |
739 | * routed to vcpu 0 */ | ||
740 | if (!VALID_EVTCHN(evtchn) || | ||
741 | (xen_hvm_domain() && !xen_have_vector_callback)) | ||
712 | return -1; | 742 | return -1; |
713 | 743 | ||
714 | /* Send future instances of this interrupt to other vcpu. */ | 744 | /* Send future instances of this interrupt to other vcpu. */ |
@@ -933,6 +963,44 @@ static struct irq_chip xen_dynamic_chip __read_mostly = { | |||
933 | .retrigger = retrigger_dynirq, | 963 | .retrigger = retrigger_dynirq, |
934 | }; | 964 | }; |
935 | 965 | ||
966 | int xen_set_callback_via(uint64_t via) | ||
967 | { | ||
968 | struct xen_hvm_param a; | ||
969 | a.domid = DOMID_SELF; | ||
970 | a.index = HVM_PARAM_CALLBACK_IRQ; | ||
971 | a.value = via; | ||
972 | return HYPERVISOR_hvm_op(HVMOP_set_param, &a); | ||
973 | } | ||
974 | EXPORT_SYMBOL_GPL(xen_set_callback_via); | ||
975 | |||
976 | #ifdef CONFIG_XEN_PVHVM | ||
977 | /* Vector callbacks are better than PCI interrupts to receive event | ||
978 | * channel notifications because we can receive vector callbacks on any | ||
979 | * vcpu and we don't need PCI support or APIC interactions. */ | ||
980 | void xen_callback_vector(void) | ||
981 | { | ||
982 | int rc; | ||
983 | uint64_t callback_via; | ||
984 | if (xen_have_vector_callback) { | ||
985 | callback_via = HVM_CALLBACK_VECTOR(XEN_HVM_EVTCHN_CALLBACK); | ||
986 | rc = xen_set_callback_via(callback_via); | ||
987 | if (rc) { | ||
988 | printk(KERN_ERR "Request for Xen HVM callback vector" | ||
989 | " failed.\n"); | ||
990 | xen_have_vector_callback = 0; | ||
991 | return; | ||
992 | } | ||
993 | printk(KERN_INFO "Xen HVM callback vector for event delivery is " | ||
994 | "enabled\n"); | ||
995 | /* in the restore case the vector has already been allocated */ | ||
996 | if (!test_bit(XEN_HVM_EVTCHN_CALLBACK, used_vectors)) | ||
997 | alloc_intr_gate(XEN_HVM_EVTCHN_CALLBACK, xen_hvm_callback_vector); | ||
998 | } | ||
999 | } | ||
1000 | #else | ||
1001 | void xen_callback_vector(void) {} | ||
1002 | #endif | ||
1003 | |||
936 | void __init xen_init_IRQ(void) | 1004 | void __init xen_init_IRQ(void) |
937 | { | 1005 | { |
938 | int i; | 1006 | int i; |
@@ -947,5 +1015,10 @@ void __init xen_init_IRQ(void) | |||
947 | for (i = 0; i < NR_EVENT_CHANNELS; i++) | 1015 | for (i = 0; i < NR_EVENT_CHANNELS; i++) |
948 | mask_evtchn(i); | 1016 | mask_evtchn(i); |
949 | 1017 | ||
950 | irq_ctx_init(smp_processor_id()); | 1018 | if (xen_hvm_domain()) { |
1019 | xen_callback_vector(); | ||
1020 | native_init_IRQ(); | ||
1021 | } else { | ||
1022 | irq_ctx_init(smp_processor_id()); | ||
1023 | } | ||
951 | } | 1024 | } |
diff --git a/drivers/xen/grant-table.c b/drivers/xen/grant-table.c index f66db3b91d61..6c4531816496 100644 --- a/drivers/xen/grant-table.c +++ b/drivers/xen/grant-table.c | |||
@@ -37,11 +37,13 @@ | |||
37 | #include <linux/slab.h> | 37 | #include <linux/slab.h> |
38 | #include <linux/vmalloc.h> | 38 | #include <linux/vmalloc.h> |
39 | #include <linux/uaccess.h> | 39 | #include <linux/uaccess.h> |
40 | #include <linux/io.h> | ||
40 | 41 | ||
41 | #include <xen/xen.h> | 42 | #include <xen/xen.h> |
42 | #include <xen/interface/xen.h> | 43 | #include <xen/interface/xen.h> |
43 | #include <xen/page.h> | 44 | #include <xen/page.h> |
44 | #include <xen/grant_table.h> | 45 | #include <xen/grant_table.h> |
46 | #include <xen/interface/memory.h> | ||
45 | #include <asm/xen/hypercall.h> | 47 | #include <asm/xen/hypercall.h> |
46 | 48 | ||
47 | #include <asm/pgtable.h> | 49 | #include <asm/pgtable.h> |
@@ -59,6 +61,8 @@ static unsigned int boot_max_nr_grant_frames; | |||
59 | static int gnttab_free_count; | 61 | static int gnttab_free_count; |
60 | static grant_ref_t gnttab_free_head; | 62 | static grant_ref_t gnttab_free_head; |
61 | static DEFINE_SPINLOCK(gnttab_list_lock); | 63 | static DEFINE_SPINLOCK(gnttab_list_lock); |
64 | unsigned long xen_hvm_resume_frames; | ||
65 | EXPORT_SYMBOL_GPL(xen_hvm_resume_frames); | ||
62 | 66 | ||
63 | static struct grant_entry *shared; | 67 | static struct grant_entry *shared; |
64 | 68 | ||
@@ -433,7 +437,7 @@ static unsigned int __max_nr_grant_frames(void) | |||
433 | return query.max_nr_frames; | 437 | return query.max_nr_frames; |
434 | } | 438 | } |
435 | 439 | ||
436 | static inline unsigned int max_nr_grant_frames(void) | 440 | unsigned int gnttab_max_grant_frames(void) |
437 | { | 441 | { |
438 | unsigned int xen_max = __max_nr_grant_frames(); | 442 | unsigned int xen_max = __max_nr_grant_frames(); |
439 | 443 | ||
@@ -441,6 +445,7 @@ static inline unsigned int max_nr_grant_frames(void) | |||
441 | return boot_max_nr_grant_frames; | 445 | return boot_max_nr_grant_frames; |
442 | return xen_max; | 446 | return xen_max; |
443 | } | 447 | } |
448 | EXPORT_SYMBOL_GPL(gnttab_max_grant_frames); | ||
444 | 449 | ||
445 | static int gnttab_map(unsigned int start_idx, unsigned int end_idx) | 450 | static int gnttab_map(unsigned int start_idx, unsigned int end_idx) |
446 | { | 451 | { |
@@ -449,6 +454,30 @@ static int gnttab_map(unsigned int start_idx, unsigned int end_idx) | |||
449 | unsigned int nr_gframes = end_idx + 1; | 454 | unsigned int nr_gframes = end_idx + 1; |
450 | int rc; | 455 | int rc; |
451 | 456 | ||
457 | if (xen_hvm_domain()) { | ||
458 | struct xen_add_to_physmap xatp; | ||
459 | unsigned int i = end_idx; | ||
460 | rc = 0; | ||
461 | /* | ||
462 | * Loop backwards, so that the first hypercall has the largest | ||
463 | * index, ensuring that the table will grow only once. | ||
464 | */ | ||
465 | do { | ||
466 | xatp.domid = DOMID_SELF; | ||
467 | xatp.idx = i; | ||
468 | xatp.space = XENMAPSPACE_grant_table; | ||
469 | xatp.gpfn = (xen_hvm_resume_frames >> PAGE_SHIFT) + i; | ||
470 | rc = HYPERVISOR_memory_op(XENMEM_add_to_physmap, &xatp); | ||
471 | if (rc != 0) { | ||
472 | printk(KERN_WARNING | ||
473 | "grant table add_to_physmap failed, err=%d\n", rc); | ||
474 | break; | ||
475 | } | ||
476 | } while (i-- > start_idx); | ||
477 | |||
478 | return rc; | ||
479 | } | ||
480 | |||
452 | frames = kmalloc(nr_gframes * sizeof(unsigned long), GFP_ATOMIC); | 481 | frames = kmalloc(nr_gframes * sizeof(unsigned long), GFP_ATOMIC); |
453 | if (!frames) | 482 | if (!frames) |
454 | return -ENOMEM; | 483 | return -ENOMEM; |
@@ -465,7 +494,7 @@ static int gnttab_map(unsigned int start_idx, unsigned int end_idx) | |||
465 | 494 | ||
466 | BUG_ON(rc || setup.status); | 495 | BUG_ON(rc || setup.status); |
467 | 496 | ||
468 | rc = arch_gnttab_map_shared(frames, nr_gframes, max_nr_grant_frames(), | 497 | rc = arch_gnttab_map_shared(frames, nr_gframes, gnttab_max_grant_frames(), |
469 | &shared); | 498 | &shared); |
470 | BUG_ON(rc); | 499 | BUG_ON(rc); |
471 | 500 | ||
@@ -476,9 +505,27 @@ static int gnttab_map(unsigned int start_idx, unsigned int end_idx) | |||
476 | 505 | ||
477 | int gnttab_resume(void) | 506 | int gnttab_resume(void) |
478 | { | 507 | { |
479 | if (max_nr_grant_frames() < nr_grant_frames) | 508 | unsigned int max_nr_gframes; |
509 | |||
510 | max_nr_gframes = gnttab_max_grant_frames(); | ||
511 | if (max_nr_gframes < nr_grant_frames) | ||
480 | return -ENOSYS; | 512 | return -ENOSYS; |
481 | return gnttab_map(0, nr_grant_frames - 1); | 513 | |
514 | if (xen_pv_domain()) | ||
515 | return gnttab_map(0, nr_grant_frames - 1); | ||
516 | |||
517 | if (!shared) { | ||
518 | shared = ioremap(xen_hvm_resume_frames, PAGE_SIZE * max_nr_gframes); | ||
519 | if (shared == NULL) { | ||
520 | printk(KERN_WARNING | ||
521 | "Failed to ioremap gnttab share frames!"); | ||
522 | return -ENOMEM; | ||
523 | } | ||
524 | } | ||
525 | |||
526 | gnttab_map(0, nr_grant_frames - 1); | ||
527 | |||
528 | return 0; | ||
482 | } | 529 | } |
483 | 530 | ||
484 | int gnttab_suspend(void) | 531 | int gnttab_suspend(void) |
@@ -495,7 +542,7 @@ static int gnttab_expand(unsigned int req_entries) | |||
495 | cur = nr_grant_frames; | 542 | cur = nr_grant_frames; |
496 | extra = ((req_entries + (GREFS_PER_GRANT_FRAME-1)) / | 543 | extra = ((req_entries + (GREFS_PER_GRANT_FRAME-1)) / |
497 | GREFS_PER_GRANT_FRAME); | 544 | GREFS_PER_GRANT_FRAME); |
498 | if (cur + extra > max_nr_grant_frames()) | 545 | if (cur + extra > gnttab_max_grant_frames()) |
499 | return -ENOSPC; | 546 | return -ENOSPC; |
500 | 547 | ||
501 | rc = gnttab_map(cur, cur + extra - 1); | 548 | rc = gnttab_map(cur, cur + extra - 1); |
@@ -505,15 +552,12 @@ static int gnttab_expand(unsigned int req_entries) | |||
505 | return rc; | 552 | return rc; |
506 | } | 553 | } |
507 | 554 | ||
508 | static int __devinit gnttab_init(void) | 555 | int gnttab_init(void) |
509 | { | 556 | { |
510 | int i; | 557 | int i; |
511 | unsigned int max_nr_glist_frames, nr_glist_frames; | 558 | unsigned int max_nr_glist_frames, nr_glist_frames; |
512 | unsigned int nr_init_grefs; | 559 | unsigned int nr_init_grefs; |
513 | 560 | ||
514 | if (!xen_domain()) | ||
515 | return -ENODEV; | ||
516 | |||
517 | nr_grant_frames = 1; | 561 | nr_grant_frames = 1; |
518 | boot_max_nr_grant_frames = __max_nr_grant_frames(); | 562 | boot_max_nr_grant_frames = __max_nr_grant_frames(); |
519 | 563 | ||
@@ -556,5 +600,18 @@ static int __devinit gnttab_init(void) | |||
556 | kfree(gnttab_list); | 600 | kfree(gnttab_list); |
557 | return -ENOMEM; | 601 | return -ENOMEM; |
558 | } | 602 | } |
603 | EXPORT_SYMBOL_GPL(gnttab_init); | ||
604 | |||
605 | static int __devinit __gnttab_init(void) | ||
606 | { | ||
607 | /* Delay grant-table initialization in the PV on HVM case */ | ||
608 | if (xen_hvm_domain()) | ||
609 | return 0; | ||
610 | |||
611 | if (!xen_pv_domain()) | ||
612 | return -ENODEV; | ||
613 | |||
614 | return gnttab_init(); | ||
615 | } | ||
559 | 616 | ||
560 | core_initcall(gnttab_init); | 617 | core_initcall(__gnttab_init); |
diff --git a/drivers/xen/manage.c b/drivers/xen/manage.c index 07e857b0de13..1799bd890315 100644 --- a/drivers/xen/manage.c +++ b/drivers/xen/manage.c | |||
@@ -9,6 +9,7 @@ | |||
9 | #include <linux/stop_machine.h> | 9 | #include <linux/stop_machine.h> |
10 | #include <linux/freezer.h> | 10 | #include <linux/freezer.h> |
11 | 11 | ||
12 | #include <xen/xen.h> | ||
12 | #include <xen/xenbus.h> | 13 | #include <xen/xenbus.h> |
13 | #include <xen/grant_table.h> | 14 | #include <xen/grant_table.h> |
14 | #include <xen/events.h> | 15 | #include <xen/events.h> |
@@ -17,6 +18,7 @@ | |||
17 | 18 | ||
18 | #include <asm/xen/hypercall.h> | 19 | #include <asm/xen/hypercall.h> |
19 | #include <asm/xen/page.h> | 20 | #include <asm/xen/page.h> |
21 | #include <asm/xen/hypervisor.h> | ||
20 | 22 | ||
21 | enum shutdown_state { | 23 | enum shutdown_state { |
22 | SHUTDOWN_INVALID = -1, | 24 | SHUTDOWN_INVALID = -1, |
@@ -33,10 +35,30 @@ enum shutdown_state { | |||
33 | static enum shutdown_state shutting_down = SHUTDOWN_INVALID; | 35 | static enum shutdown_state shutting_down = SHUTDOWN_INVALID; |
34 | 36 | ||
35 | #ifdef CONFIG_PM_SLEEP | 37 | #ifdef CONFIG_PM_SLEEP |
36 | static int xen_suspend(void *data) | 38 | static int xen_hvm_suspend(void *data) |
37 | { | 39 | { |
40 | struct sched_shutdown r = { .reason = SHUTDOWN_suspend }; | ||
38 | int *cancelled = data; | 41 | int *cancelled = data; |
42 | |||
43 | BUG_ON(!irqs_disabled()); | ||
44 | |||
45 | *cancelled = HYPERVISOR_sched_op(SCHEDOP_shutdown, &r); | ||
46 | |||
47 | xen_hvm_post_suspend(*cancelled); | ||
48 | gnttab_resume(); | ||
49 | |||
50 | if (!*cancelled) { | ||
51 | xen_irq_resume(); | ||
52 | xen_timer_resume(); | ||
53 | } | ||
54 | |||
55 | return 0; | ||
56 | } | ||
57 | |||
58 | static int xen_suspend(void *data) | ||
59 | { | ||
39 | int err; | 60 | int err; |
61 | int *cancelled = data; | ||
40 | 62 | ||
41 | BUG_ON(!irqs_disabled()); | 63 | BUG_ON(!irqs_disabled()); |
42 | 64 | ||
@@ -106,7 +128,10 @@ static void do_suspend(void) | |||
106 | goto out_resume; | 128 | goto out_resume; |
107 | } | 129 | } |
108 | 130 | ||
109 | err = stop_machine(xen_suspend, &cancelled, cpumask_of(0)); | 131 | if (xen_hvm_domain()) |
132 | err = stop_machine(xen_hvm_suspend, &cancelled, cpumask_of(0)); | ||
133 | else | ||
134 | err = stop_machine(xen_suspend, &cancelled, cpumask_of(0)); | ||
110 | 135 | ||
111 | dpm_resume_noirq(PMSG_RESUME); | 136 | dpm_resume_noirq(PMSG_RESUME); |
112 | 137 | ||
@@ -255,7 +280,19 @@ static int shutdown_event(struct notifier_block *notifier, | |||
255 | return NOTIFY_DONE; | 280 | return NOTIFY_DONE; |
256 | } | 281 | } |
257 | 282 | ||
258 | static int __init setup_shutdown_event(void) | 283 | static int __init __setup_shutdown_event(void) |
284 | { | ||
285 | /* Delay initialization in the PV on HVM case */ | ||
286 | if (xen_hvm_domain()) | ||
287 | return 0; | ||
288 | |||
289 | if (!xen_pv_domain()) | ||
290 | return -ENODEV; | ||
291 | |||
292 | return xen_setup_shutdown_event(); | ||
293 | } | ||
294 | |||
295 | int xen_setup_shutdown_event(void) | ||
259 | { | 296 | { |
260 | static struct notifier_block xenstore_notifier = { | 297 | static struct notifier_block xenstore_notifier = { |
261 | .notifier_call = shutdown_event | 298 | .notifier_call = shutdown_event |
@@ -264,5 +301,6 @@ static int __init setup_shutdown_event(void) | |||
264 | 301 | ||
265 | return 0; | 302 | return 0; |
266 | } | 303 | } |
304 | EXPORT_SYMBOL_GPL(xen_setup_shutdown_event); | ||
267 | 305 | ||
268 | subsys_initcall(setup_shutdown_event); | 306 | subsys_initcall(__setup_shutdown_event); |
diff --git a/drivers/xen/platform-pci.c b/drivers/xen/platform-pci.c new file mode 100644 index 000000000000..c01b5ddce529 --- /dev/null +++ b/drivers/xen/platform-pci.c | |||
@@ -0,0 +1,207 @@ | |||
1 | /****************************************************************************** | ||
2 | * platform-pci.c | ||
3 | * | ||
4 | * Xen platform PCI device driver | ||
5 | * Copyright (c) 2005, Intel Corporation. | ||
6 | * Copyright (c) 2007, XenSource Inc. | ||
7 | * Copyright (c) 2010, Citrix | ||
8 | * | ||
9 | * This program is free software; you can redistribute it and/or modify it | ||
10 | * under the terms and conditions of the GNU General Public License, | ||
11 | * version 2, as published by the Free Software Foundation. | ||
12 | * | ||
13 | * This program is distributed in the hope it will be useful, but WITHOUT | ||
14 | * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or | ||
15 | * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for | ||
16 | * more details. | ||
17 | * | ||
18 | * You should have received a copy of the GNU General Public License along with | ||
19 | * this program; if not, write to the Free Software Foundation, Inc., 59 Temple | ||
20 | * Place - Suite 330, Boston, MA 02111-1307 USA. | ||
21 | * | ||
22 | */ | ||
23 | |||
24 | |||
25 | #include <linux/interrupt.h> | ||
26 | #include <linux/io.h> | ||
27 | #include <linux/module.h> | ||
28 | #include <linux/pci.h> | ||
29 | |||
30 | #include <xen/platform_pci.h> | ||
31 | #include <xen/grant_table.h> | ||
32 | #include <xen/xenbus.h> | ||
33 | #include <xen/events.h> | ||
34 | #include <xen/hvm.h> | ||
35 | #include <xen/xen-ops.h> | ||
36 | |||
37 | #define DRV_NAME "xen-platform-pci" | ||
38 | |||
39 | MODULE_AUTHOR("ssmith@xensource.com and stefano.stabellini@eu.citrix.com"); | ||
40 | MODULE_DESCRIPTION("Xen platform PCI device"); | ||
41 | MODULE_LICENSE("GPL"); | ||
42 | |||
43 | static unsigned long platform_mmio; | ||
44 | static unsigned long platform_mmio_alloc; | ||
45 | static unsigned long platform_mmiolen; | ||
46 | static uint64_t callback_via; | ||
47 | |||
48 | unsigned long alloc_xen_mmio(unsigned long len) | ||
49 | { | ||
50 | unsigned long addr; | ||
51 | |||
52 | addr = platform_mmio + platform_mmio_alloc; | ||
53 | platform_mmio_alloc += len; | ||
54 | BUG_ON(platform_mmio_alloc > platform_mmiolen); | ||
55 | |||
56 | return addr; | ||
57 | } | ||
58 | |||
59 | static uint64_t get_callback_via(struct pci_dev *pdev) | ||
60 | { | ||
61 | u8 pin; | ||
62 | int irq; | ||
63 | |||
64 | irq = pdev->irq; | ||
65 | if (irq < 16) | ||
66 | return irq; /* ISA IRQ */ | ||
67 | |||
68 | pin = pdev->pin; | ||
69 | |||
70 | /* We don't know the GSI. Specify the PCI INTx line instead. */ | ||
71 | return ((uint64_t)0x01 << 56) | /* PCI INTx identifier */ | ||
72 | ((uint64_t)pci_domain_nr(pdev->bus) << 32) | | ||
73 | ((uint64_t)pdev->bus->number << 16) | | ||
74 | ((uint64_t)(pdev->devfn & 0xff) << 8) | | ||
75 | ((uint64_t)(pin - 1) & 3); | ||
76 | } | ||
77 | |||
78 | static irqreturn_t do_hvm_evtchn_intr(int irq, void *dev_id) | ||
79 | { | ||
80 | xen_hvm_evtchn_do_upcall(); | ||
81 | return IRQ_HANDLED; | ||
82 | } | ||
83 | |||
84 | static int xen_allocate_irq(struct pci_dev *pdev) | ||
85 | { | ||
86 | return request_irq(pdev->irq, do_hvm_evtchn_intr, | ||
87 | IRQF_DISABLED | IRQF_NOBALANCING | IRQF_TRIGGER_RISING, | ||
88 | "xen-platform-pci", pdev); | ||
89 | } | ||
90 | |||
91 | static int platform_pci_resume(struct pci_dev *pdev) | ||
92 | { | ||
93 | int err; | ||
94 | if (xen_have_vector_callback) | ||
95 | return 0; | ||
96 | err = xen_set_callback_via(callback_via); | ||
97 | if (err) { | ||
98 | dev_err(&pdev->dev, "platform_pci_resume failure!\n"); | ||
99 | return err; | ||
100 | } | ||
101 | return 0; | ||
102 | } | ||
103 | |||
104 | static int __devinit platform_pci_init(struct pci_dev *pdev, | ||
105 | const struct pci_device_id *ent) | ||
106 | { | ||
107 | int i, ret; | ||
108 | long ioaddr, iolen; | ||
109 | long mmio_addr, mmio_len; | ||
110 | unsigned int max_nr_gframes; | ||
111 | |||
112 | i = pci_enable_device(pdev); | ||
113 | if (i) | ||
114 | return i; | ||
115 | |||
116 | ioaddr = pci_resource_start(pdev, 0); | ||
117 | iolen = pci_resource_len(pdev, 0); | ||
118 | |||
119 | mmio_addr = pci_resource_start(pdev, 1); | ||
120 | mmio_len = pci_resource_len(pdev, 1); | ||
121 | |||
122 | if (mmio_addr == 0 || ioaddr == 0) { | ||
123 | dev_err(&pdev->dev, "no resources found\n"); | ||
124 | ret = -ENOENT; | ||
125 | goto pci_out; | ||
126 | } | ||
127 | |||
128 | if (request_mem_region(mmio_addr, mmio_len, DRV_NAME) == NULL) { | ||
129 | dev_err(&pdev->dev, "MEM I/O resource 0x%lx @ 0x%lx busy\n", | ||
130 | mmio_addr, mmio_len); | ||
131 | ret = -EBUSY; | ||
132 | goto pci_out; | ||
133 | } | ||
134 | |||
135 | if (request_region(ioaddr, iolen, DRV_NAME) == NULL) { | ||
136 | dev_err(&pdev->dev, "I/O resource 0x%lx @ 0x%lx busy\n", | ||
137 | iolen, ioaddr); | ||
138 | ret = -EBUSY; | ||
139 | goto mem_out; | ||
140 | } | ||
141 | |||
142 | platform_mmio = mmio_addr; | ||
143 | platform_mmiolen = mmio_len; | ||
144 | |||
145 | if (!xen_have_vector_callback) { | ||
146 | ret = xen_allocate_irq(pdev); | ||
147 | if (ret) { | ||
148 | dev_warn(&pdev->dev, "request_irq failed err=%d\n", ret); | ||
149 | goto out; | ||
150 | } | ||
151 | callback_via = get_callback_via(pdev); | ||
152 | ret = xen_set_callback_via(callback_via); | ||
153 | if (ret) { | ||
154 | dev_warn(&pdev->dev, "Unable to set the evtchn callback " | ||
155 | "err=%d\n", ret); | ||
156 | goto out; | ||
157 | } | ||
158 | } | ||
159 | |||
160 | max_nr_gframes = gnttab_max_grant_frames(); | ||
161 | xen_hvm_resume_frames = alloc_xen_mmio(PAGE_SIZE * max_nr_gframes); | ||
162 | ret = gnttab_init(); | ||
163 | if (ret) | ||
164 | goto out; | ||
165 | xenbus_probe(NULL); | ||
166 | ret = xen_setup_shutdown_event(); | ||
167 | if (ret) | ||
168 | goto out; | ||
169 | return 0; | ||
170 | |||
171 | out: | ||
172 | release_region(ioaddr, iolen); | ||
173 | mem_out: | ||
174 | release_mem_region(mmio_addr, mmio_len); | ||
175 | pci_out: | ||
176 | pci_disable_device(pdev); | ||
177 | return ret; | ||
178 | } | ||
179 | |||
180 | static struct pci_device_id platform_pci_tbl[] __devinitdata = { | ||
181 | {PCI_VENDOR_ID_XEN, PCI_DEVICE_ID_XEN_PLATFORM, | ||
182 | PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0}, | ||
183 | {0,} | ||
184 | }; | ||
185 | |||
186 | MODULE_DEVICE_TABLE(pci, platform_pci_tbl); | ||
187 | |||
188 | static struct pci_driver platform_driver = { | ||
189 | .name = DRV_NAME, | ||
190 | .probe = platform_pci_init, | ||
191 | .id_table = platform_pci_tbl, | ||
192 | #ifdef CONFIG_PM | ||
193 | .resume_early = platform_pci_resume, | ||
194 | #endif | ||
195 | }; | ||
196 | |||
197 | static int __init platform_pci_module_init(void) | ||
198 | { | ||
199 | /* no unplug has been done, IGNORE hasn't been specified: just | ||
200 | * return now */ | ||
201 | if (!xen_platform_pci_unplug) | ||
202 | return -ENODEV; | ||
203 | |||
204 | return pci_register_driver(&platform_driver); | ||
205 | } | ||
206 | |||
207 | module_init(platform_pci_module_init); | ||
diff --git a/drivers/xen/xenbus/xenbus_probe.c b/drivers/xen/xenbus/xenbus_probe.c index abc12426ef0a..29bac5118877 100644 --- a/drivers/xen/xenbus/xenbus_probe.c +++ b/drivers/xen/xenbus/xenbus_probe.c | |||
@@ -56,6 +56,9 @@ | |||
56 | #include <xen/events.h> | 56 | #include <xen/events.h> |
57 | #include <xen/page.h> | 57 | #include <xen/page.h> |
58 | 58 | ||
59 | #include <xen/platform_pci.h> | ||
60 | #include <xen/hvm.h> | ||
61 | |||
59 | #include "xenbus_comms.h" | 62 | #include "xenbus_comms.h" |
60 | #include "xenbus_probe.h" | 63 | #include "xenbus_probe.h" |
61 | 64 | ||
@@ -776,8 +779,23 @@ void xenbus_probe(struct work_struct *unused) | |||
776 | /* Notify others that xenstore is up */ | 779 | /* Notify others that xenstore is up */ |
777 | blocking_notifier_call_chain(&xenstore_chain, 0, NULL); | 780 | blocking_notifier_call_chain(&xenstore_chain, 0, NULL); |
778 | } | 781 | } |
782 | EXPORT_SYMBOL_GPL(xenbus_probe); | ||
779 | 783 | ||
780 | static int __init xenbus_probe_init(void) | 784 | static int __init xenbus_probe_initcall(void) |
785 | { | ||
786 | if (!xen_domain()) | ||
787 | return -ENODEV; | ||
788 | |||
789 | if (xen_initial_domain() || xen_hvm_domain()) | ||
790 | return 0; | ||
791 | |||
792 | xenbus_probe(NULL); | ||
793 | return 0; | ||
794 | } | ||
795 | |||
796 | device_initcall(xenbus_probe_initcall); | ||
797 | |||
798 | static int __init xenbus_init(void) | ||
781 | { | 799 | { |
782 | int err = 0; | 800 | int err = 0; |
783 | 801 | ||
@@ -802,11 +820,24 @@ static int __init xenbus_probe_init(void) | |||
802 | if (xen_initial_domain()) { | 820 | if (xen_initial_domain()) { |
803 | /* dom0 not yet supported */ | 821 | /* dom0 not yet supported */ |
804 | } else { | 822 | } else { |
823 | if (xen_hvm_domain()) { | ||
824 | uint64_t v = 0; | ||
825 | err = hvm_get_parameter(HVM_PARAM_STORE_EVTCHN, &v); | ||
826 | if (err) | ||
827 | goto out_error; | ||
828 | xen_store_evtchn = (int)v; | ||
829 | err = hvm_get_parameter(HVM_PARAM_STORE_PFN, &v); | ||
830 | if (err) | ||
831 | goto out_error; | ||
832 | xen_store_mfn = (unsigned long)v; | ||
833 | xen_store_interface = ioremap(xen_store_mfn << PAGE_SHIFT, PAGE_SIZE); | ||
834 | } else { | ||
835 | xen_store_evtchn = xen_start_info->store_evtchn; | ||
836 | xen_store_mfn = xen_start_info->store_mfn; | ||
837 | xen_store_interface = mfn_to_virt(xen_store_mfn); | ||
838 | } | ||
805 | xenstored_ready = 1; | 839 | xenstored_ready = 1; |
806 | xen_store_evtchn = xen_start_info->store_evtchn; | ||
807 | xen_store_mfn = xen_start_info->store_mfn; | ||
808 | } | 840 | } |
809 | xen_store_interface = mfn_to_virt(xen_store_mfn); | ||
810 | 841 | ||
811 | /* Initialize the interface to xenstore. */ | 842 | /* Initialize the interface to xenstore. */ |
812 | err = xs_init(); | 843 | err = xs_init(); |
@@ -816,9 +847,6 @@ static int __init xenbus_probe_init(void) | |||
816 | goto out_unreg_back; | 847 | goto out_unreg_back; |
817 | } | 848 | } |
818 | 849 | ||
819 | if (!xen_initial_domain()) | ||
820 | xenbus_probe(NULL); | ||
821 | |||
822 | #ifdef CONFIG_XEN_COMPAT_XENFS | 850 | #ifdef CONFIG_XEN_COMPAT_XENFS |
823 | /* | 851 | /* |
824 | * Create xenfs mountpoint in /proc for compatibility with | 852 | * Create xenfs mountpoint in /proc for compatibility with |
@@ -839,7 +867,7 @@ static int __init xenbus_probe_init(void) | |||
839 | return err; | 867 | return err; |
840 | } | 868 | } |
841 | 869 | ||
842 | postcore_initcall(xenbus_probe_init); | 870 | postcore_initcall(xenbus_init); |
843 | 871 | ||
844 | MODULE_LICENSE("GPL"); | 872 | MODULE_LICENSE("GPL"); |
845 | 873 | ||
@@ -947,6 +975,9 @@ static void wait_for_devices(struct xenbus_driver *xendrv) | |||
947 | #ifndef MODULE | 975 | #ifndef MODULE |
948 | static int __init boot_wait_for_devices(void) | 976 | static int __init boot_wait_for_devices(void) |
949 | { | 977 | { |
978 | if (xen_hvm_domain() && !xen_platform_pci_unplug) | ||
979 | return -ENODEV; | ||
980 | |||
950 | ready_to_wait_for_devices = 1; | 981 | ready_to_wait_for_devices = 1; |
951 | wait_for_devices(NULL); | 982 | wait_for_devices(NULL); |
952 | return 0; | 983 | return 0; |
diff --git a/drivers/xen/xenfs/super.c b/drivers/xen/xenfs/super.c index 8924d93136f1..78bfab0700ba 100644 --- a/drivers/xen/xenfs/super.c +++ b/drivers/xen/xenfs/super.c | |||
@@ -65,7 +65,7 @@ static struct file_system_type xenfs_type = { | |||
65 | 65 | ||
66 | static int __init xenfs_init(void) | 66 | static int __init xenfs_init(void) |
67 | { | 67 | { |
68 | if (xen_pv_domain()) | 68 | if (xen_domain()) |
69 | return register_filesystem(&xenfs_type); | 69 | return register_filesystem(&xenfs_type); |
70 | 70 | ||
71 | printk(KERN_INFO "XENFS: not registering filesystem on non-xen platform\n"); | 71 | printk(KERN_INFO "XENFS: not registering filesystem on non-xen platform\n"); |
@@ -74,7 +74,7 @@ static int __init xenfs_init(void) | |||
74 | 74 | ||
75 | static void __exit xenfs_exit(void) | 75 | static void __exit xenfs_exit(void) |
76 | { | 76 | { |
77 | if (xen_pv_domain()) | 77 | if (xen_domain()) |
78 | unregister_filesystem(&xenfs_type); | 78 | unregister_filesystem(&xenfs_type); |
79 | } | 79 | } |
80 | 80 | ||