aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/xen
diff options
context:
space:
mode:
authorJeremy Fitzhardinge <jeremy.fitzhardinge@citrix.com>2010-08-04 17:49:16 -0400
committerJeremy Fitzhardinge <jeremy.fitzhardinge@citrix.com>2010-08-04 17:49:16 -0400
commitca50a5f39041497253c6362f2ba4da1b56d3e6cb (patch)
tree482f1607d12b60f6ef482bb4af2c9c58d7814d5f /drivers/xen
parenta70ce4b6064b64477ed12ef1878980f842819094 (diff)
parentca65f9fc0c447da5b270b05c41c21b19c88617c3 (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/Kconfig9
-rw-r--r--drivers/xen/Makefile3
-rw-r--r--drivers/xen/events.c95
-rw-r--r--drivers/xen/grant-table.c77
-rw-r--r--drivers/xen/manage.c46
-rw-r--r--drivers/xen/platform-pci.c207
-rw-r--r--drivers/xen/xenbus/xenbus_probe.c47
-rw-r--r--drivers/xen/xenfs/super.c4
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
65config 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.
65endmenu 74endmenu
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
9obj-$(CONFIG_XEN_BALLOON) += balloon.o 9obj-$(CONFIG_XEN_BALLOON) += balloon.o
10obj-$(CONFIG_XEN_DEV_EVTCHN) += evtchn.o 10obj-$(CONFIG_XEN_DEV_EVTCHN) += evtchn.o
11obj-$(CONFIG_XENFS) += xenfs/ 11obj-$(CONFIG_XENFS) += xenfs/
12obj-$(CONFIG_XEN_SYS_HYPERVISOR) += sys-hypervisor.o \ No newline at end of file 12obj-$(CONFIG_XEN_SYS_HYPERVISOR) += sys-hypervisor.o
13obj-$(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 */
620void xen_evtchn_do_upcall(struct pt_regs *regs) 634static 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
669out: 679out:
680
681 put_cpu();
682}
683
684void 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(); 697void xen_hvm_evtchn_do_upcall(void)
698{
699 __xen_evtchn_do_upcall();
674} 700}
701EXPORT_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. */
677void rebind_evtchn_irq(int evtchn, int irq) 704void 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
966int 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}
974EXPORT_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. */
980void 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
1001void xen_callback_vector(void) {}
1002#endif
1003
936void __init xen_init_IRQ(void) 1004void __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;
59static int gnttab_free_count; 61static int gnttab_free_count;
60static grant_ref_t gnttab_free_head; 62static grant_ref_t gnttab_free_head;
61static DEFINE_SPINLOCK(gnttab_list_lock); 63static DEFINE_SPINLOCK(gnttab_list_lock);
64unsigned long xen_hvm_resume_frames;
65EXPORT_SYMBOL_GPL(xen_hvm_resume_frames);
62 66
63static struct grant_entry *shared; 67static 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
436static inline unsigned int max_nr_grant_frames(void) 440unsigned 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}
448EXPORT_SYMBOL_GPL(gnttab_max_grant_frames);
444 449
445static int gnttab_map(unsigned int start_idx, unsigned int end_idx) 450static 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
477int gnttab_resume(void) 506int 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
484int gnttab_suspend(void) 531int 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
508static int __devinit gnttab_init(void) 555int 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}
603EXPORT_SYMBOL_GPL(gnttab_init);
604
605static 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
560core_initcall(gnttab_init); 617core_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
21enum shutdown_state { 23enum shutdown_state {
22 SHUTDOWN_INVALID = -1, 24 SHUTDOWN_INVALID = -1,
@@ -33,10 +35,30 @@ enum shutdown_state {
33static enum shutdown_state shutting_down = SHUTDOWN_INVALID; 35static enum shutdown_state shutting_down = SHUTDOWN_INVALID;
34 36
35#ifdef CONFIG_PM_SLEEP 37#ifdef CONFIG_PM_SLEEP
36static int xen_suspend(void *data) 38static 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
58static 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
258static int __init setup_shutdown_event(void) 283static 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
295int 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}
304EXPORT_SYMBOL_GPL(xen_setup_shutdown_event);
267 305
268subsys_initcall(setup_shutdown_event); 306subsys_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
39MODULE_AUTHOR("ssmith@xensource.com and stefano.stabellini@eu.citrix.com");
40MODULE_DESCRIPTION("Xen platform PCI device");
41MODULE_LICENSE("GPL");
42
43static unsigned long platform_mmio;
44static unsigned long platform_mmio_alloc;
45static unsigned long platform_mmiolen;
46static uint64_t callback_via;
47
48unsigned 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
59static 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
78static irqreturn_t do_hvm_evtchn_intr(int irq, void *dev_id)
79{
80 xen_hvm_evtchn_do_upcall();
81 return IRQ_HANDLED;
82}
83
84static 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
91static 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
104static 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
171out:
172 release_region(ioaddr, iolen);
173mem_out:
174 release_mem_region(mmio_addr, mmio_len);
175pci_out:
176 pci_disable_device(pdev);
177 return ret;
178}
179
180static 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
186MODULE_DEVICE_TABLE(pci, platform_pci_tbl);
187
188static 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
197static 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
207module_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}
782EXPORT_SYMBOL_GPL(xenbus_probe);
779 783
780static int __init xenbus_probe_init(void) 784static 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
796device_initcall(xenbus_probe_initcall);
797
798static 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
842postcore_initcall(xenbus_probe_init); 870postcore_initcall(xenbus_init);
843 871
844MODULE_LICENSE("GPL"); 872MODULE_LICENSE("GPL");
845 873
@@ -947,6 +975,9 @@ static void wait_for_devices(struct xenbus_driver *xendrv)
947#ifndef MODULE 975#ifndef MODULE
948static int __init boot_wait_for_devices(void) 976static 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
66static int __init xenfs_init(void) 66static 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
75static void __exit xenfs_exit(void) 75static 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