Skip to content

Commit dcda487

Browse files
committed
Merge tag 'for-linus-5.11-rc4-tag' of git://git.kernel.org/pub/scm/linux/kernel/git/xen/tip
Pull xen fixes from Juergen Gross: - A series to fix a regression when running as a fully virtualized guest on an old Xen hypervisor not supporting PV interrupt callbacks for HVM guests. - A patch to add support to query Xen resource sizes (setting was possible already) from user mode. * tag 'for-linus-5.11-rc4-tag' of git://git.kernel.org/pub/scm/linux/kernel/git/xen/tip: x86/xen: Fix xen_hvm_smp_init() when vector callback not available x86/xen: Don't register Xen IPIs when they aren't going to be used x86/xen: Add xen_no_vector_callback option to test PCI INTX delivery xen: Set platform PCI device INTX affinity to CPU0 xen: Fix event channel callback via INTX/GSI xen/privcmd: allow fetching resource sizes
2 parents 7aec71c + 3d7746b commit dcda487

File tree

11 files changed

+129
-54
lines changed

11 files changed

+129
-54
lines changed

Documentation/admin-guide/kernel-parameters.txt

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5972,6 +5972,10 @@
59725972
This option is obsoleted by the "nopv" option, which
59735973
has equivalent effect for XEN platform.
59745974

5975+
xen_no_vector_callback
5976+
[KNL,X86,XEN] Disable the vector callback for Xen
5977+
event channel interrupts.
5978+
59755979
xen_scrub_pages= [XEN]
59765980
Boolean option to control scrubbing pages before giving them back
59775981
to Xen, for use by other domains. Can be also changed at runtime

arch/arm/xen/enlighten.c

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -371,7 +371,7 @@ static int __init xen_guest_init(void)
371371
}
372372
gnttab_init();
373373
if (!xen_initial_domain())
374-
xenbus_probe(NULL);
374+
xenbus_probe();
375375

376376
/*
377377
* Making sure board specific code will not set up ops for

arch/x86/xen/enlighten_hvm.c

Lines changed: 12 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -164,10 +164,10 @@ static int xen_cpu_up_prepare_hvm(unsigned int cpu)
164164
else
165165
per_cpu(xen_vcpu_id, cpu) = cpu;
166166
rc = xen_vcpu_setup(cpu);
167-
if (rc)
167+
if (rc || !xen_have_vector_callback)
168168
return rc;
169169

170-
if (xen_have_vector_callback && xen_feature(XENFEAT_hvm_safe_pvclock))
170+
if (xen_feature(XENFEAT_hvm_safe_pvclock))
171171
xen_setup_timer(cpu);
172172

173173
rc = xen_smp_intr_init(cpu);
@@ -188,6 +188,8 @@ static int xen_cpu_dead_hvm(unsigned int cpu)
188188
return 0;
189189
}
190190

191+
static bool no_vector_callback __initdata;
192+
191193
static void __init xen_hvm_guest_init(void)
192194
{
193195
if (xen_pv_domain())
@@ -207,7 +209,7 @@ static void __init xen_hvm_guest_init(void)
207209

208210
xen_panic_handler_init();
209211

210-
if (xen_feature(XENFEAT_hvm_callback_vector))
212+
if (!no_vector_callback && xen_feature(XENFEAT_hvm_callback_vector))
211213
xen_have_vector_callback = 1;
212214

213215
xen_hvm_smp_init();
@@ -233,6 +235,13 @@ static __init int xen_parse_nopv(char *arg)
233235
}
234236
early_param("xen_nopv", xen_parse_nopv);
235237

238+
static __init int xen_parse_no_vector_callback(char *arg)
239+
{
240+
no_vector_callback = true;
241+
return 0;
242+
}
243+
early_param("xen_no_vector_callback", xen_parse_no_vector_callback);
244+
236245
bool __init xen_hvm_need_lapic(void)
237246
{
238247
if (xen_pv_domain())

arch/x86/xen/smp_hvm.c

Lines changed: 17 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -33,9 +33,11 @@ static void __init xen_hvm_smp_prepare_cpus(unsigned int max_cpus)
3333
int cpu;
3434

3535
native_smp_prepare_cpus(max_cpus);
36-
WARN_ON(xen_smp_intr_init(0));
3736

38-
xen_init_lock_cpu(0);
37+
if (xen_have_vector_callback) {
38+
WARN_ON(xen_smp_intr_init(0));
39+
xen_init_lock_cpu(0);
40+
}
3941

4042
for_each_possible_cpu(cpu) {
4143
if (cpu == 0)
@@ -50,9 +52,11 @@ static void __init xen_hvm_smp_prepare_cpus(unsigned int max_cpus)
5052
static void xen_hvm_cpu_die(unsigned int cpu)
5153
{
5254
if (common_cpu_die(cpu) == 0) {
53-
xen_smp_intr_free(cpu);
54-
xen_uninit_lock_cpu(cpu);
55-
xen_teardown_timer(cpu);
55+
if (xen_have_vector_callback) {
56+
xen_smp_intr_free(cpu);
57+
xen_uninit_lock_cpu(cpu);
58+
xen_teardown_timer(cpu);
59+
}
5660
}
5761
}
5862
#else
@@ -64,14 +68,17 @@ static void xen_hvm_cpu_die(unsigned int cpu)
6468

6569
void __init xen_hvm_smp_init(void)
6670
{
67-
if (!xen_have_vector_callback)
71+
smp_ops.smp_prepare_boot_cpu = xen_hvm_smp_prepare_boot_cpu;
72+
smp_ops.smp_prepare_cpus = xen_hvm_smp_prepare_cpus;
73+
smp_ops.smp_cpus_done = xen_smp_cpus_done;
74+
smp_ops.cpu_die = xen_hvm_cpu_die;
75+
76+
if (!xen_have_vector_callback) {
77+
nopvspin = true;
6878
return;
79+
}
6980

70-
smp_ops.smp_prepare_cpus = xen_hvm_smp_prepare_cpus;
7181
smp_ops.smp_send_reschedule = xen_smp_send_reschedule;
72-
smp_ops.cpu_die = xen_hvm_cpu_die;
7382
smp_ops.send_call_func_ipi = xen_smp_send_call_function_ipi;
7483
smp_ops.send_call_func_single_ipi = xen_smp_send_call_function_single_ipi;
75-
smp_ops.smp_prepare_boot_cpu = xen_hvm_smp_prepare_boot_cpu;
76-
smp_ops.smp_cpus_done = xen_smp_cpus_done;
7784
}

drivers/xen/events/events_base.c

Lines changed: 0 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -2060,16 +2060,6 @@ static struct irq_chip xen_percpu_chip __read_mostly = {
20602060
.irq_ack = ack_dynirq,
20612061
};
20622062

2063-
int xen_set_callback_via(uint64_t via)
2064-
{
2065-
struct xen_hvm_param a;
2066-
a.domid = DOMID_SELF;
2067-
a.index = HVM_PARAM_CALLBACK_IRQ;
2068-
a.value = via;
2069-
return HYPERVISOR_hvm_op(HVMOP_set_param, &a);
2070-
}
2071-
EXPORT_SYMBOL_GPL(xen_set_callback_via);
2072-
20732063
#ifdef CONFIG_XEN_PVHVM
20742064
/* Vector callbacks are better than PCI interrupts to receive event
20752065
* channel notifications because we can receive vector callbacks on any

drivers/xen/platform-pci.c

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -132,6 +132,13 @@ static int platform_pci_probe(struct pci_dev *pdev,
132132
dev_warn(&pdev->dev, "request_irq failed err=%d\n", ret);
133133
goto out;
134134
}
135+
/*
136+
* It doesn't strictly *have* to run on CPU0 but it sure
137+
* as hell better process the event channel ports delivered
138+
* to CPU0.
139+
*/
140+
irq_set_affinity(pdev->irq, cpumask_of(0));
141+
135142
callback_via = get_callback_via(pdev);
136143
ret = xen_set_callback_via(callback_via);
137144
if (ret) {
@@ -149,7 +156,6 @@ static int platform_pci_probe(struct pci_dev *pdev,
149156
ret = gnttab_init();
150157
if (ret)
151158
goto grant_out;
152-
xenbus_probe(NULL);
153159
return 0;
154160
grant_out:
155161
gnttab_free_auto_xlat_frames();

drivers/xen/privcmd.c

Lines changed: 19 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -717,14 +717,15 @@ static long privcmd_ioctl_restrict(struct file *file, void __user *udata)
717717
return 0;
718718
}
719719

720-
static long privcmd_ioctl_mmap_resource(struct file *file, void __user *udata)
720+
static long privcmd_ioctl_mmap_resource(struct file *file,
721+
struct privcmd_mmap_resource __user *udata)
721722
{
722723
struct privcmd_data *data = file->private_data;
723724
struct mm_struct *mm = current->mm;
724725
struct vm_area_struct *vma;
725726
struct privcmd_mmap_resource kdata;
726727
xen_pfn_t *pfns = NULL;
727-
struct xen_mem_acquire_resource xdata;
728+
struct xen_mem_acquire_resource xdata = { };
728729
int rc;
729730

730731
if (copy_from_user(&kdata, udata, sizeof(kdata)))
@@ -734,6 +735,22 @@ static long privcmd_ioctl_mmap_resource(struct file *file, void __user *udata)
734735
if (data->domid != DOMID_INVALID && data->domid != kdata.dom)
735736
return -EPERM;
736737

738+
/* Both fields must be set or unset */
739+
if (!!kdata.addr != !!kdata.num)
740+
return -EINVAL;
741+
742+
xdata.domid = kdata.dom;
743+
xdata.type = kdata.type;
744+
xdata.id = kdata.id;
745+
746+
if (!kdata.addr && !kdata.num) {
747+
/* Query the size of the resource. */
748+
rc = HYPERVISOR_memory_op(XENMEM_acquire_resource, &xdata);
749+
if (rc)
750+
return rc;
751+
return __put_user(xdata.nr_frames, &udata->num);
752+
}
753+
737754
mmap_write_lock(mm);
738755

739756
vma = find_vma(mm, kdata.addr);
@@ -768,10 +785,6 @@ static long privcmd_ioctl_mmap_resource(struct file *file, void __user *udata)
768785
} else
769786
vma->vm_private_data = PRIV_VMA_LOCKED;
770787

771-
memset(&xdata, 0, sizeof(xdata));
772-
xdata.domid = kdata.dom;
773-
xdata.type = kdata.type;
774-
xdata.id = kdata.id;
775788
xdata.frame = kdata.idx;
776789
xdata.nr_frames = kdata.num;
777790
set_xen_guest_handle(xdata.frame_list, pfns);

drivers/xen/xenbus/xenbus.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -115,6 +115,7 @@ int xenbus_probe_node(struct xen_bus_type *bus,
115115
const char *type,
116116
const char *nodename);
117117
int xenbus_probe_devices(struct xen_bus_type *bus);
118+
void xenbus_probe(void);
118119

119120
void xenbus_dev_changed(const char *node, struct xen_bus_type *bus);
120121

drivers/xen/xenbus/xenbus_comms.c

Lines changed: 0 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -57,16 +57,8 @@ DEFINE_MUTEX(xs_response_mutex);
5757
static int xenbus_irq;
5858
static struct task_struct *xenbus_task;
5959

60-
static DECLARE_WORK(probe_work, xenbus_probe);
61-
62-
6360
static irqreturn_t wake_waiting(int irq, void *unused)
6461
{
65-
if (unlikely(xenstored_ready == 0)) {
66-
xenstored_ready = 1;
67-
schedule_work(&probe_work);
68-
}
69-
7062
wake_up(&xb_waitq);
7163
return IRQ_HANDLED;
7264
}

drivers/xen/xenbus/xenbus_probe.c

Lines changed: 67 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -683,29 +683,76 @@ void unregister_xenstore_notifier(struct notifier_block *nb)
683683
}
684684
EXPORT_SYMBOL_GPL(unregister_xenstore_notifier);
685685

686-
void xenbus_probe(struct work_struct *unused)
686+
void xenbus_probe(void)
687687
{
688688
xenstored_ready = 1;
689689

690+
/*
691+
* In the HVM case, xenbus_init() deferred its call to
692+
* xs_init() in case callbacks were not operational yet.
693+
* So do it now.
694+
*/
695+
if (xen_store_domain_type == XS_HVM)
696+
xs_init();
697+
690698
/* Notify others that xenstore is up */
691699
blocking_notifier_call_chain(&xenstore_chain, 0, NULL);
692700
}
693-
EXPORT_SYMBOL_GPL(xenbus_probe);
694701

695-
static int __init xenbus_probe_initcall(void)
702+
/*
703+
* Returns true when XenStore init must be deferred in order to
704+
* allow the PCI platform device to be initialised, before we
705+
* can actually have event channel interrupts working.
706+
*/
707+
static bool xs_hvm_defer_init_for_callback(void)
696708
{
697-
if (!xen_domain())
698-
return -ENODEV;
709+
#ifdef CONFIG_XEN_PVHVM
710+
return xen_store_domain_type == XS_HVM &&
711+
!xen_have_vector_callback;
712+
#else
713+
return false;
714+
#endif
715+
}
699716

700-
if (xen_initial_domain() || xen_hvm_domain())
701-
return 0;
717+
static int __init xenbus_probe_initcall(void)
718+
{
719+
/*
720+
* Probe XenBus here in the XS_PV case, and also XS_HVM unless we
721+
* need to wait for the platform PCI device to come up.
722+
*/
723+
if (xen_store_domain_type == XS_PV ||
724+
(xen_store_domain_type == XS_HVM &&
725+
!xs_hvm_defer_init_for_callback()))
726+
xenbus_probe();
702727

703-
xenbus_probe(NULL);
704728
return 0;
705729
}
706-
707730
device_initcall(xenbus_probe_initcall);
708731

732+
int xen_set_callback_via(uint64_t via)
733+
{
734+
struct xen_hvm_param a;
735+
int ret;
736+
737+
a.domid = DOMID_SELF;
738+
a.index = HVM_PARAM_CALLBACK_IRQ;
739+
a.value = via;
740+
741+
ret = HYPERVISOR_hvm_op(HVMOP_set_param, &a);
742+
if (ret)
743+
return ret;
744+
745+
/*
746+
* If xenbus_probe_initcall() deferred the xenbus_probe()
747+
* due to the callback not functioning yet, we can do it now.
748+
*/
749+
if (!xenstored_ready && xs_hvm_defer_init_for_callback())
750+
xenbus_probe();
751+
752+
return ret;
753+
}
754+
EXPORT_SYMBOL_GPL(xen_set_callback_via);
755+
709756
/* Set up event channel for xenstored which is run as a local process
710757
* (this is normally used only in dom0)
711758
*/
@@ -818,11 +865,17 @@ static int __init xenbus_init(void)
818865
break;
819866
}
820867

821-
/* Initialize the interface to xenstore. */
822-
err = xs_init();
823-
if (err) {
824-
pr_warn("Error initializing xenstore comms: %i\n", err);
825-
goto out_error;
868+
/*
869+
* HVM domains may not have a functional callback yet. In that
870+
* case let xs_init() be called from xenbus_probe(), which will
871+
* get invoked at an appropriate time.
872+
*/
873+
if (xen_store_domain_type != XS_HVM) {
874+
err = xs_init();
875+
if (err) {
876+
pr_warn("Error initializing xenstore comms: %i\n", err);
877+
goto out_error;
878+
}
826879
}
827880

828881
if ((xen_store_domain_type != XS_LOCAL) &&

0 commit comments

Comments
 (0)