diff options
Diffstat (limited to 'drivers/xen/xenbus/xenbus_probe.c')
-rw-r--r-- | drivers/xen/xenbus/xenbus_probe.c | 137 |
1 files changed, 123 insertions, 14 deletions
diff --git a/drivers/xen/xenbus/xenbus_probe.c b/drivers/xen/xenbus/xenbus_probe.c index 217bcc092a96..27c48c90b2ab 100644 --- a/drivers/xen/xenbus/xenbus_probe.c +++ b/drivers/xen/xenbus/xenbus_probe.c | |||
@@ -674,29 +674,107 @@ void unregister_xenstore_notifier(struct notifier_block *nb) | |||
674 | } | 674 | } |
675 | EXPORT_SYMBOL_GPL(unregister_xenstore_notifier); | 675 | EXPORT_SYMBOL_GPL(unregister_xenstore_notifier); |
676 | 676 | ||
677 | void xenbus_probe(struct work_struct *unused) | 677 | static void xenbus_probe(void) |
678 | { | 678 | { |
679 | xenstored_ready = 1; | 679 | xenstored_ready = 1; |
680 | 680 | ||
681 | /* | ||
682 | * In the HVM case, xenbus_init() deferred its call to | ||
683 | * xs_init() in case callbacks were not operational yet. | ||
684 | * So do it now. | ||
685 | */ | ||
686 | if (xen_store_domain_type == XS_HVM) | ||
687 | xs_init(); | ||
688 | |||
681 | /* Notify others that xenstore is up */ | 689 | /* Notify others that xenstore is up */ |
682 | blocking_notifier_call_chain(&xenstore_chain, 0, NULL); | 690 | blocking_notifier_call_chain(&xenstore_chain, 0, NULL); |
683 | } | 691 | } |
684 | EXPORT_SYMBOL_GPL(xenbus_probe); | ||
685 | 692 | ||
686 | static int __init xenbus_probe_initcall(void) | 693 | /* |
694 | * Returns true when XenStore init must be deferred in order to | ||
695 | * allow the PCI platform device to be initialised, before we | ||
696 | * can actually have event channel interrupts working. | ||
697 | */ | ||
698 | static bool xs_hvm_defer_init_for_callback(void) | ||
687 | { | 699 | { |
688 | if (!xen_domain()) | 700 | #ifdef CONFIG_XEN_PVHVM |
689 | return -ENODEV; | 701 | return xen_store_domain_type == XS_HVM && |
702 | !xen_have_vector_callback; | ||
703 | #else | ||
704 | return false; | ||
705 | #endif | ||
706 | } | ||
690 | 707 | ||
691 | if (xen_initial_domain() || xen_hvm_domain()) | 708 | static int xenbus_probe_thread(void *unused) |
692 | return 0; | 709 | { |
710 | DEFINE_WAIT(w); | ||
693 | 711 | ||
694 | xenbus_probe(NULL); | 712 | /* |
713 | * We actually just want to wait for *any* trigger of xb_waitq, | ||
714 | * and run xenbus_probe() the moment it occurs. | ||
715 | */ | ||
716 | prepare_to_wait(&xb_waitq, &w, TASK_INTERRUPTIBLE); | ||
717 | schedule(); | ||
718 | finish_wait(&xb_waitq, &w); | ||
719 | |||
720 | DPRINTK("probing"); | ||
721 | xenbus_probe(); | ||
695 | return 0; | 722 | return 0; |
696 | } | 723 | } |
697 | 724 | ||
725 | static int __init xenbus_probe_initcall(void) | ||
726 | { | ||
727 | /* | ||
728 | * Probe XenBus here in the XS_PV case, and also XS_HVM unless we | ||
729 | * need to wait for the platform PCI device to come up. | ||
730 | */ | ||
731 | if (xen_store_domain_type == XS_PV || | ||
732 | (xen_store_domain_type == XS_HVM && | ||
733 | !xs_hvm_defer_init_for_callback())) | ||
734 | xenbus_probe(); | ||
735 | |||
736 | /* | ||
737 | * For XS_LOCAL, spawn a thread which will wait for xenstored | ||
738 | * or a xenstore-stubdom to be started, then probe. It will be | ||
739 | * triggered when communication starts happening, by waiting | ||
740 | * on xb_waitq. | ||
741 | */ | ||
742 | if (xen_store_domain_type == XS_LOCAL) { | ||
743 | struct task_struct *probe_task; | ||
744 | |||
745 | probe_task = kthread_run(xenbus_probe_thread, NULL, | ||
746 | "xenbus_probe"); | ||
747 | if (IS_ERR(probe_task)) | ||
748 | return PTR_ERR(probe_task); | ||
749 | } | ||
750 | return 0; | ||
751 | } | ||
698 | device_initcall(xenbus_probe_initcall); | 752 | device_initcall(xenbus_probe_initcall); |
699 | 753 | ||
754 | int xen_set_callback_via(uint64_t via) | ||
755 | { | ||
756 | struct xen_hvm_param a; | ||
757 | int ret; | ||
758 | |||
759 | a.domid = DOMID_SELF; | ||
760 | a.index = HVM_PARAM_CALLBACK_IRQ; | ||
761 | a.value = via; | ||
762 | |||
763 | ret = HYPERVISOR_hvm_op(HVMOP_set_param, &a); | ||
764 | if (ret) | ||
765 | return ret; | ||
766 | |||
767 | /* | ||
768 | * If xenbus_probe_initcall() deferred the xenbus_probe() | ||
769 | * due to the callback not functioning yet, we can do it now. | ||
770 | */ | ||
771 | if (!xenstored_ready && xs_hvm_defer_init_for_callback()) | ||
772 | xenbus_probe(); | ||
773 | |||
774 | return ret; | ||
775 | } | ||
776 | EXPORT_SYMBOL_GPL(xen_set_callback_via); | ||
777 | |||
700 | /* Set up event channel for xenstored which is run as a local process | 778 | /* Set up event channel for xenstored which is run as a local process |
701 | * (this is normally used only in dom0) | 779 | * (this is normally used only in dom0) |
702 | */ | 780 | */ |
@@ -760,7 +838,7 @@ static struct notifier_block xenbus_resume_nb = { | |||
760 | 838 | ||
761 | static int __init xenbus_init(void) | 839 | static int __init xenbus_init(void) |
762 | { | 840 | { |
763 | int err = 0; | 841 | int err; |
764 | uint64_t v = 0; | 842 | uint64_t v = 0; |
765 | xen_store_domain_type = XS_UNKNOWN; | 843 | xen_store_domain_type = XS_UNKNOWN; |
766 | 844 | ||
@@ -800,6 +878,29 @@ static int __init xenbus_init(void) | |||
800 | err = hvm_get_parameter(HVM_PARAM_STORE_PFN, &v); | 878 | err = hvm_get_parameter(HVM_PARAM_STORE_PFN, &v); |
801 | if (err) | 879 | if (err) |
802 | goto out_error; | 880 | goto out_error; |
881 | /* | ||
882 | * Uninitialized hvm_params are zero and return no error. | ||
883 | * Although it is theoretically possible to have | ||
884 | * HVM_PARAM_STORE_PFN set to zero on purpose, in reality it is | ||
885 | * not zero when valid. If zero, it means that Xenstore hasn't | ||
886 | * been properly initialized. Instead of attempting to map a | ||
887 | * wrong guest physical address return error. | ||
888 | * | ||
889 | * Also recognize all bits set as an invalid value. | ||
890 | */ | ||
891 | if (!v || !~v) { | ||
892 | err = -ENOENT; | ||
893 | goto out_error; | ||
894 | } | ||
895 | /* Avoid truncation on 32-bit. */ | ||
896 | #if BITS_PER_LONG == 32 | ||
897 | if (v > ULONG_MAX) { | ||
898 | pr_err("%s: cannot handle HVM_PARAM_STORE_PFN=%llx > ULONG_MAX\n", | ||
899 | __func__, v); | ||
900 | err = -EINVAL; | ||
901 | goto out_error; | ||
902 | } | ||
903 | #endif | ||
803 | xen_store_gfn = (unsigned long)v; | 904 | xen_store_gfn = (unsigned long)v; |
804 | xen_store_interface = | 905 | xen_store_interface = |
805 | xen_remap(xen_store_gfn << XEN_PAGE_SHIFT, | 906 | xen_remap(xen_store_gfn << XEN_PAGE_SHIFT, |
@@ -810,11 +911,17 @@ static int __init xenbus_init(void) | |||
810 | break; | 911 | break; |
811 | } | 912 | } |
812 | 913 | ||
813 | /* Initialize the interface to xenstore. */ | 914 | /* |
814 | err = xs_init(); | 915 | * HVM domains may not have a functional callback yet. In that |
815 | if (err) { | 916 | * case let xs_init() be called from xenbus_probe(), which will |
816 | pr_warn("Error initializing xenstore comms: %i\n", err); | 917 | * get invoked at an appropriate time. |
817 | goto out_error; | 918 | */ |
919 | if (xen_store_domain_type != XS_HVM) { | ||
920 | err = xs_init(); | ||
921 | if (err) { | ||
922 | pr_warn("Error initializing xenstore comms: %i\n", err); | ||
923 | goto out_error; | ||
924 | } | ||
818 | } | 925 | } |
819 | 926 | ||
820 | if ((xen_store_domain_type != XS_LOCAL) && | 927 | if ((xen_store_domain_type != XS_LOCAL) && |
@@ -828,8 +935,10 @@ static int __init xenbus_init(void) | |||
828 | */ | 935 | */ |
829 | proc_create_mount_point("xen"); | 936 | proc_create_mount_point("xen"); |
830 | #endif | 937 | #endif |
938 | return 0; | ||
831 | 939 | ||
832 | out_error: | 940 | out_error: |
941 | xen_store_domain_type = XS_UNKNOWN; | ||
833 | return err; | 942 | return err; |
834 | } | 943 | } |
835 | 944 | ||