diff options
Diffstat (limited to 'drivers/tty/hvc/hvc_xen.c')
| -rw-r--r-- | drivers/tty/hvc/hvc_xen.c | 104 |
1 files changed, 55 insertions, 49 deletions
diff --git a/drivers/tty/hvc/hvc_xen.c b/drivers/tty/hvc/hvc_xen.c index 83d5c88e716..2dc2831840c 100644 --- a/drivers/tty/hvc/hvc_xen.c +++ b/drivers/tty/hvc/hvc_xen.c @@ -21,6 +21,7 @@ #include <linux/console.h> #include <linux/delay.h> #include <linux/err.h> +#include <linux/irq.h> #include <linux/init.h> #include <linux/types.h> #include <linux/list.h> @@ -35,6 +36,7 @@ #include <xen/page.h> #include <xen/events.h> #include <xen/interface/io/console.h> +#include <xen/interface/sched.h> #include <xen/hvc-console.h> #include <xen/xenbus.h> @@ -181,7 +183,7 @@ static int dom0_write_console(uint32_t vtermno, const char *str, int len) { int rc = HYPERVISOR_console_io(CONSOLEIO_write, len, (char *)str); if (rc < 0) - return 0; + return rc; return len; } @@ -206,32 +208,31 @@ static int xen_hvm_console_init(void) info = vtermno_to_xencons(HVC_COOKIE); if (!info) { - info = kzalloc(sizeof(struct xencons_info), GFP_KERNEL | __GFP_ZERO); + info = kzalloc(sizeof(struct xencons_info), GFP_KERNEL); if (!info) return -ENOMEM; - } - - /* already configured */ - if (info->intf != NULL) + } else if (info->intf != NULL) { + /* already configured */ return 0; - - r = hvm_get_parameter(HVM_PARAM_CONSOLE_EVTCHN, &v); - if (r < 0) { - kfree(info); - return -ENODEV; } + /* + * If the toolstack (or the hypervisor) hasn't set these values, the + * default value is 0. Even though mfn = 0 and evtchn = 0 are + * theoretically correct values, in practice they never are and they + * mean that a legacy toolstack hasn't initialized the pv console correctly. + */ + r = hvm_get_parameter(HVM_PARAM_CONSOLE_EVTCHN, &v); + if (r < 0 || v == 0) + goto err; info->evtchn = v; - hvm_get_parameter(HVM_PARAM_CONSOLE_PFN, &v); - if (r < 0) { - kfree(info); - return -ENODEV; - } + v = 0; + r = hvm_get_parameter(HVM_PARAM_CONSOLE_PFN, &v); + if (r < 0 || v == 0) + goto err; mfn = v; - info->intf = ioremap(mfn << PAGE_SHIFT, PAGE_SIZE); - if (info->intf == NULL) { - kfree(info); - return -ENODEV; - } + info->intf = xen_remap(mfn << PAGE_SHIFT, PAGE_SIZE); + if (info->intf == NULL) + goto err; info->vtermno = HVC_COOKIE; spin_lock(&xencons_lock); @@ -239,6 +240,9 @@ static int xen_hvm_console_init(void) spin_unlock(&xencons_lock); return 0; +err: + kfree(info); + return -ENODEV; } static int xen_pv_console_init(void) @@ -253,15 +257,13 @@ static int xen_pv_console_init(void) info = vtermno_to_xencons(HVC_COOKIE); if (!info) { - info = kzalloc(sizeof(struct xencons_info), GFP_KERNEL | __GFP_ZERO); + info = kzalloc(sizeof(struct xencons_info), GFP_KERNEL); if (!info) return -ENOMEM; - } - - /* already configured */ - if (info->intf != NULL) + } else if (info->intf != NULL) { + /* already configured */ return 0; - + } info->evtchn = xen_start_info->console.domU.evtchn; info->intf = mfn_to_virt(xen_start_info->console.domU.mfn); info->vtermno = HVC_COOKIE; @@ -282,7 +284,7 @@ static int xen_initial_domain_console_init(void) info = vtermno_to_xencons(HVC_COOKIE); if (!info) { - info = kzalloc(sizeof(struct xencons_info), GFP_KERNEL | __GFP_ZERO); + info = kzalloc(sizeof(struct xencons_info), GFP_KERNEL); if (!info) return -ENOMEM; } @@ -420,7 +422,7 @@ static int xencons_connect_backend(struct xenbus_device *dev, return ret; } -static int __devinit xencons_probe(struct xenbus_device *dev, +static int xencons_probe(struct xenbus_device *dev, const struct xenbus_device_id *id) { int ret, devid; @@ -430,9 +432,9 @@ static int __devinit xencons_probe(struct xenbus_device *dev, if (devid == 0) return -ENODEV; - info = kzalloc(sizeof(struct xencons_info), GFP_KERNEL | __GFP_ZERO); + info = kzalloc(sizeof(struct xencons_info), GFP_KERNEL); if (!info) - goto error_nomem; + return -ENOMEM; dev_set_drvdata(&dev->dev, info); info->xbdev = dev; info->vtermno = xenbus_devid_to_vtermno(devid); @@ -476,7 +478,6 @@ static void xencons_backend_changed(struct xenbus_device *dev, case XenbusStateInitialising: case XenbusStateInitialised: case XenbusStateUnknown: - case XenbusStateClosed: break; case XenbusStateInitWait: @@ -486,6 +487,10 @@ static void xencons_backend_changed(struct xenbus_device *dev, xenbus_switch_state(dev, XenbusStateConnected); break; + case XenbusStateClosed: + if (dev->state == XenbusStateClosed) + break; + /* Missed the backend's CLOSING state -- fallthrough */ case XenbusStateClosing: xenbus_frontend_closed(dev); break; @@ -556,18 +561,7 @@ static int __init xen_hvc_init(void) #endif return r; } - -static void __exit xen_hvc_fini(void) -{ - struct xencons_info *entry, *next; - - if (list_empty(&xenconsoles)) - return; - - list_for_each_entry_safe(entry, next, &xenconsoles, list) { - xen_console_remove(entry); - } -} +device_initcall(xen_hvc_init); static int xen_cons_init(void) { @@ -593,10 +587,6 @@ static int xen_cons_init(void) hvc_instantiate(HVC_COOKIE, 0, ops); return 0; } - - -module_init(xen_hvc_init); -module_exit(xen_hvc_fini); console_initcall(xen_cons_init); #ifdef CONFIG_EARLY_PRINTK @@ -631,12 +621,28 @@ struct console xenboot_console = { .name = "xenboot", .write = xenboot_write_console, .flags = CON_PRINTBUFFER | CON_BOOT | CON_ANYTIME, + .index = -1, }; #endif /* CONFIG_EARLY_PRINTK */ void xen_raw_console_write(const char *str) { - dom0_write_console(0, str, strlen(str)); + ssize_t len = strlen(str); + int rc = 0; + + if (xen_domain()) { + rc = dom0_write_console(0, str, len); +#ifdef CONFIG_X86 + if (rc == -ENOSYS && xen_hvm_domain()) + goto outb_print; + + } else if (xen_cpuid_base()) { + int i; +outb_print: + for (i = 0; i < len; i++) + outb(str[i], 0xe9); +#endif + } } void xen_raw_printk(const char *fmt, ...) |
