diff --git a/Documentation/admin-guide/kernel-parameters.txt b/Documentation/admin-guide/kernel-parameters.txt index 03df66c8a0ab..74740815d61f 100644 --- a/Documentation/admin-guide/kernel-parameters.txt +++ b/Documentation/admin-guide/kernel-parameters.txt @@ -8437,6 +8437,11 @@ Kernel parameters save/restore/migration must be enabled to handle larger domains. + xen_console_io [XEN,EARLY] + Boolean option to enable/disable the usage of the Xen + console_io hypercalls to read and write to the console. + Mostly useful for debugging and development. + xen_emul_unplug= [HW,X86,XEN,EARLY] Unplug Xen emulated devices Format: [unplug0,][unplug1] diff --git a/arch/x86/platform/pvh/head.S b/arch/x86/platform/pvh/head.S index 344030c1a81d..53ee2d53fcf8 100644 --- a/arch/x86/platform/pvh/head.S +++ b/arch/x86/platform/pvh/head.S @@ -91,10 +91,12 @@ SYM_CODE_START(pvh_start_xen) leal rva(early_stack_end)(%ebp), %esp +#if defined(CONFIG_X86_64) || defined(CONFIG_X86_PAE) /* Enable PAE mode. */ mov %cr4, %eax orl $X86_CR4_PAE, %eax mov %eax, %cr4 +#endif #ifdef CONFIG_X86_64 /* Enable Long mode. */ diff --git a/arch/x86/xen/enlighten.c b/arch/x86/xen/enlighten.c index 53282dc7d5ac..23b91bf9b663 100644 --- a/arch/x86/xen/enlighten.c +++ b/arch/x86/xen/enlighten.c @@ -470,7 +470,7 @@ int __init arch_xen_unpopulated_init(struct resource **res) * driver to know how much of the physmap is unpopulated and * set an accurate initial memory target. */ - xen_released_pages += xen_extra_mem[i].n_pfns; + xen_unpopulated_pages += xen_extra_mem[i].n_pfns; /* Zero so region is not also added to the balloon driver. */ xen_extra_mem[i].n_pfns = 0; } diff --git a/drivers/tty/hvc/hvc_xen.c b/drivers/tty/hvc/hvc_xen.c index 388a71afd6ef..95ec01b1aacf 100644 --- a/drivers/tty/hvc/hvc_xen.c +++ b/drivers/tty/hvc/hvc_xen.c @@ -51,6 +51,22 @@ static DEFINE_SPINLOCK(xencons_lock); /* ------------------------------------------------------------------ */ +static bool xen_console_io = false; +static int __initdata opt_console_io = -1; + +static int __init parse_xen_console_io(char *arg) +{ + bool val; + int ret; + + ret = kstrtobool(arg, &val); + if (ret == 0) + opt_console_io = (int)val; + + return ret; +} +early_param("xen_console_io", parse_xen_console_io); + static struct xencons_info *vtermno_to_xencons(int vtermno) { struct xencons_info *entry, *ret = NULL; @@ -331,7 +347,7 @@ static int xen_initial_domain_console_init(void) struct xencons_info *info; unsigned long flags; - if (!xen_initial_domain()) + if (!xen_console_io) return -ENODEV; info = vtermno_to_xencons(HVC_COOKIE); @@ -369,7 +385,7 @@ void xen_console_resume(void) { struct xencons_info *info = vtermno_to_xencons(HVC_COOKIE); if (info != NULL && info->irq) { - if (!xen_initial_domain()) + if (!xen_console_io) xen_console_update_evtchn(info); rebind_evtchn_irq(info->evtchn, info->irq); } @@ -601,7 +617,7 @@ static int __init xen_hvc_init(void) if (!xen_domain()) return -ENODEV; - if (xen_initial_domain()) { + if (xen_console_io) { ops = &dom0_hvc_ops; r = xen_initial_domain_console_init(); if (r < 0) @@ -647,14 +663,17 @@ static int __init xen_hvc_init(void) } device_initcall(xen_hvc_init); -static int xen_cons_init(void) +static int __init xen_cons_init(void) { const struct hv_ops *ops; + xen_console_io = opt_console_io >= 0 ? opt_console_io : + xen_initial_domain(); + if (!xen_domain()) return 0; - if (xen_initial_domain()) + if (xen_console_io) ops = &dom0_hvc_ops; else { int r; diff --git a/drivers/xen/balloon.c b/drivers/xen/balloon.c index 49c3f9926394..9b6531eb28b6 100644 --- a/drivers/xen/balloon.c +++ b/drivers/xen/balloon.c @@ -724,6 +724,8 @@ static int __init balloon_add_regions(void) static int __init balloon_init(void) { struct task_struct *task; + long current_pages = 0; + domid_t domid = DOMID_SELF; int rc; if (!xen_domain()) @@ -731,12 +733,24 @@ static int __init balloon_init(void) pr_info("Initialising balloon driver\n"); - if (xen_released_pages >= get_num_physpages()) { - WARN(1, "Released pages underflow current target"); - return -ERANGE; + if (xen_initial_domain()) + current_pages = HYPERVISOR_memory_op(XENMEM_current_reservation, + &domid); + if (current_pages <= 0) { + if (xen_pv_domain()) { + if (xen_released_pages >= xen_start_info->nr_pages) + goto underflow; + current_pages = min(xen_start_info->nr_pages - + xen_released_pages, max_pfn); + } else { + if (xen_unpopulated_pages >= get_num_physpages()) + goto underflow; + current_pages = get_num_physpages() - + xen_unpopulated_pages; + } } - balloon_stats.current_pages = get_num_physpages() - xen_released_pages; + balloon_stats.current_pages = current_pages; balloon_stats.target_pages = balloon_stats.current_pages; balloon_stats.balloon_low = 0; balloon_stats.balloon_high = 0; @@ -767,6 +781,10 @@ static int __init balloon_init(void) xen_balloon_init(); return 0; + + underflow: + WARN(1, "Released pages underflow current target"); + return -ERANGE; } subsys_initcall(balloon_init); diff --git a/drivers/xen/events/events_base.c b/drivers/xen/events/events_base.c index 9478fae014e5..663df17776fd 100644 --- a/drivers/xen/events/events_base.c +++ b/drivers/xen/events/events_base.c @@ -581,7 +581,7 @@ static void lateeoi_list_add(struct irq_info *info) eoi_list); if (!elem || info->eoi_time < elem->eoi_time) { list_add(&info->eoi_list, &eoi->eoi_list); - mod_delayed_work_on(info->eoi_cpu, system_wq, + mod_delayed_work_on(info->eoi_cpu, system_percpu_wq, &eoi->delayed, delay); } else { list_for_each_entry_reverse(elem, &eoi->eoi_list, eoi_list) { @@ -666,7 +666,7 @@ static void xen_irq_lateeoi_worker(struct work_struct *work) break; if (now < info->eoi_time) { - mod_delayed_work_on(info->eoi_cpu, system_wq, + mod_delayed_work_on(info->eoi_cpu, system_percpu_wq, &eoi->delayed, info->eoi_time - now); break; @@ -782,7 +782,7 @@ static void xen_free_irq(struct irq_info *info) WARN_ON(info->refcnt > 0); - queue_rcu_work(system_wq, &info->rwork); + queue_rcu_work(system_percpu_wq, &info->rwork); } /* Not called for lateeoi events. */ diff --git a/drivers/xen/grant-dma-ops.c b/drivers/xen/grant-dma-ops.c index 14077d23f2a1..c2603e700178 100644 --- a/drivers/xen/grant-dma-ops.c +++ b/drivers/xen/grant-dma-ops.c @@ -366,7 +366,8 @@ static int xen_grant_init_backend_domid(struct device *dev, if (np) { ret = xen_dt_grant_init_backend_domid(dev, np, backend_domid); of_node_put(np); - } else if (IS_ENABLED(CONFIG_XEN_VIRTIO_FORCE_GRANT) || xen_pv_domain()) { + } else if (!xen_initial_domain() && + (IS_ENABLED(CONFIG_XEN_VIRTIO_FORCE_GRANT) || xen_pv_domain())) { dev_info(dev, "Using dom0 as backend\n"); *backend_domid = 0; ret = 0; diff --git a/drivers/xen/mcelog.c b/drivers/xen/mcelog.c index 4f65b641c054..abe658c73b7b 100644 --- a/drivers/xen/mcelog.c +++ b/drivers/xen/mcelog.c @@ -165,9 +165,7 @@ static long xen_mce_chrdev_ioctl(struct file *f, unsigned int cmd, case MCE_GETCLEAR_FLAGS: { unsigned flags; - do { - flags = xen_mcelog.flags; - } while (cmpxchg(&xen_mcelog.flags, flags, 0) != flags); + flags = xchg(&xen_mcelog.flags, 0); return put_user(flags, p); } diff --git a/drivers/xen/privcmd.c b/drivers/xen/privcmd.c index f52a457b302d..402be080ad2c 100644 --- a/drivers/xen/privcmd.c +++ b/drivers/xen/privcmd.c @@ -1091,7 +1091,8 @@ static long privcmd_ioctl_irqfd(struct file *file, void __user *udata) static int privcmd_irqfd_init(void) { - irqfd_cleanup_wq = alloc_workqueue("privcmd-irqfd-cleanup", 0, 0); + irqfd_cleanup_wq = alloc_workqueue("privcmd-irqfd-cleanup", WQ_PERCPU, + 0); if (!irqfd_cleanup_wq) return -ENOMEM; diff --git a/drivers/xen/unpopulated-alloc.c b/drivers/xen/unpopulated-alloc.c index d6fc2aefe264..1dc0b495c8e5 100644 --- a/drivers/xen/unpopulated-alloc.c +++ b/drivers/xen/unpopulated-alloc.c @@ -18,6 +18,9 @@ static unsigned int list_count; static struct resource *target_resource; +/* Pages to subtract from the memory count when setting balloon target. */ +unsigned long xen_unpopulated_pages __initdata; + /* * If arch is not happy with system "iomem_resource" being used for * the region allocation it can provide it's own view by creating specific diff --git a/drivers/xen/xenbus/xenbus.h b/drivers/xen/xenbus/xenbus.h index 9ac0427724a3..daba7f5e05c4 100644 --- a/drivers/xen/xenbus/xenbus.h +++ b/drivers/xen/xenbus/xenbus.h @@ -120,9 +120,9 @@ int xenbus_probe_devices(struct xen_bus_type *bus); void xenbus_dev_changed(const char *node, struct xen_bus_type *bus); -int xenbus_dev_suspend(struct device *dev); -int xenbus_dev_resume(struct device *dev); -int xenbus_dev_cancel(struct device *dev); +int xenbus_dev_freeze(struct device *dev); +int xenbus_dev_restore(struct device *dev); +int xenbus_dev_thaw(struct device *dev); void xenbus_otherend_changed(struct xenbus_watch *watch, const char *path, const char *token, diff --git a/drivers/xen/xenbus/xenbus_probe.c b/drivers/xen/xenbus/xenbus_probe.c index 86fe6e779056..9f9011cd7447 100644 --- a/drivers/xen/xenbus/xenbus_probe.c +++ b/drivers/xen/xenbus/xenbus_probe.c @@ -668,7 +668,7 @@ void xenbus_dev_changed(const char *node, struct xen_bus_type *bus) } EXPORT_SYMBOL_GPL(xenbus_dev_changed); -int xenbus_dev_suspend(struct device *dev) +int xenbus_dev_freeze(struct device *dev) { int err = 0; struct xenbus_driver *drv; @@ -683,12 +683,12 @@ int xenbus_dev_suspend(struct device *dev) if (drv->suspend) err = drv->suspend(xdev); if (err) - dev_warn(dev, "suspend failed: %i\n", err); + dev_warn(dev, "freeze failed: %i\n", err); return 0; } -EXPORT_SYMBOL_GPL(xenbus_dev_suspend); +EXPORT_SYMBOL_GPL(xenbus_dev_freeze); -int xenbus_dev_resume(struct device *dev) +int xenbus_dev_restore(struct device *dev) { int err; struct xenbus_driver *drv; @@ -702,7 +702,7 @@ int xenbus_dev_resume(struct device *dev) drv = to_xenbus_driver(dev->driver); err = talk_to_otherend(xdev); if (err) { - dev_warn(dev, "resume (talk_to_otherend) failed: %i\n", err); + dev_warn(dev, "restore (talk_to_otherend) failed: %i\n", err); return err; } @@ -711,28 +711,28 @@ int xenbus_dev_resume(struct device *dev) if (drv->resume) { err = drv->resume(xdev); if (err) { - dev_warn(dev, "resume failed: %i\n", err); + dev_warn(dev, "restore failed: %i\n", err); return err; } } err = watch_otherend(xdev); if (err) { - dev_warn(dev, "resume (watch_otherend) failed: %d\n", err); + dev_warn(dev, "restore (watch_otherend) failed: %d\n", err); return err; } return 0; } -EXPORT_SYMBOL_GPL(xenbus_dev_resume); +EXPORT_SYMBOL_GPL(xenbus_dev_restore); -int xenbus_dev_cancel(struct device *dev) +int xenbus_dev_thaw(struct device *dev) { /* Do nothing */ - DPRINTK("cancel"); + DPRINTK("thaw"); return 0; } -EXPORT_SYMBOL_GPL(xenbus_dev_cancel); +EXPORT_SYMBOL_GPL(xenbus_dev_thaw); /* A flag to determine if xenstored is 'ready' (i.e. has started) */ int xenstored_ready; diff --git a/drivers/xen/xenbus/xenbus_probe_frontend.c b/drivers/xen/xenbus/xenbus_probe_frontend.c index 6d1819269cbe..f04707d1f667 100644 --- a/drivers/xen/xenbus/xenbus_probe_frontend.c +++ b/drivers/xen/xenbus/xenbus_probe_frontend.c @@ -91,14 +91,14 @@ static void backend_changed(struct xenbus_watch *watch, xenbus_otherend_changed(watch, path, token, 1); } -static void xenbus_frontend_delayed_resume(struct work_struct *w) +static void xenbus_frontend_delayed_restore(struct work_struct *w) { struct xenbus_device *xdev = container_of(w, struct xenbus_device, work); - xenbus_dev_resume(&xdev->dev); + xenbus_dev_restore(&xdev->dev); } -static int xenbus_frontend_dev_resume(struct device *dev) +static int xenbus_frontend_dev_restore(struct device *dev) { /* * If xenstored is running in this domain, we cannot access the backend @@ -112,14 +112,14 @@ static int xenbus_frontend_dev_resume(struct device *dev) return 0; } - return xenbus_dev_resume(dev); + return xenbus_dev_restore(dev); } static int xenbus_frontend_dev_probe(struct device *dev) { if (xen_store_domain_type == XS_LOCAL) { struct xenbus_device *xdev = to_xenbus_device(dev); - INIT_WORK(&xdev->work, xenbus_frontend_delayed_resume); + INIT_WORK(&xdev->work, xenbus_frontend_delayed_restore); } return xenbus_dev_probe(dev); @@ -148,11 +148,9 @@ static void xenbus_frontend_dev_shutdown(struct device *_dev) } static const struct dev_pm_ops xenbus_pm_ops = { - .suspend = xenbus_dev_suspend, - .resume = xenbus_frontend_dev_resume, - .freeze = xenbus_dev_suspend, - .thaw = xenbus_dev_cancel, - .restore = xenbus_dev_resume, + .freeze = xenbus_dev_freeze, + .thaw = xenbus_dev_thaw, + .restore = xenbus_frontend_dev_restore, }; static struct xen_bus_type xenbus_frontend = { diff --git a/include/xen/xen.h b/include/xen/xen.h index 61854e3f2837..f280c5dcf923 100644 --- a/include/xen/xen.h +++ b/include/xen/xen.h @@ -69,11 +69,13 @@ extern u64 xen_saved_max_mem_size; #endif #ifdef CONFIG_XEN_UNPOPULATED_ALLOC +extern unsigned long xen_unpopulated_pages; int xen_alloc_unpopulated_pages(unsigned int nr_pages, struct page **pages); void xen_free_unpopulated_pages(unsigned int nr_pages, struct page **pages); #include int arch_xen_unpopulated_init(struct resource **res); #else +#define xen_unpopulated_pages 0UL #include static inline int xen_alloc_unpopulated_pages(unsigned int nr_pages, struct page **pages)