diff options
Diffstat (limited to 'drivers/tty/hvc/hvc_xen.c')
-rw-r--r-- | drivers/tty/hvc/hvc_xen.c | 465 |
1 files changed, 422 insertions, 43 deletions
diff --git a/drivers/tty/hvc/hvc_xen.c b/drivers/tty/hvc/hvc_xen.c index a1b0a75c3eae..83d5c88e7165 100644 --- a/drivers/tty/hvc/hvc_xen.c +++ b/drivers/tty/hvc/hvc_xen.c | |||
@@ -23,44 +23,74 @@ | |||
23 | #include <linux/err.h> | 23 | #include <linux/err.h> |
24 | #include <linux/init.h> | 24 | #include <linux/init.h> |
25 | #include <linux/types.h> | 25 | #include <linux/types.h> |
26 | #include <linux/list.h> | ||
26 | 27 | ||
28 | #include <asm/io.h> | ||
27 | #include <asm/xen/hypervisor.h> | 29 | #include <asm/xen/hypervisor.h> |
28 | 30 | ||
29 | #include <xen/xen.h> | 31 | #include <xen/xen.h> |
32 | #include <xen/interface/xen.h> | ||
33 | #include <xen/hvm.h> | ||
34 | #include <xen/grant_table.h> | ||
30 | #include <xen/page.h> | 35 | #include <xen/page.h> |
31 | #include <xen/events.h> | 36 | #include <xen/events.h> |
32 | #include <xen/interface/io/console.h> | 37 | #include <xen/interface/io/console.h> |
33 | #include <xen/hvc-console.h> | 38 | #include <xen/hvc-console.h> |
39 | #include <xen/xenbus.h> | ||
34 | 40 | ||
35 | #include "hvc_console.h" | 41 | #include "hvc_console.h" |
36 | 42 | ||
37 | #define HVC_COOKIE 0x58656e /* "Xen" in hex */ | 43 | #define HVC_COOKIE 0x58656e /* "Xen" in hex */ |
38 | 44 | ||
39 | static struct hvc_struct *hvc; | 45 | struct xencons_info { |
40 | static int xencons_irq; | 46 | struct list_head list; |
47 | struct xenbus_device *xbdev; | ||
48 | struct xencons_interface *intf; | ||
49 | unsigned int evtchn; | ||
50 | struct hvc_struct *hvc; | ||
51 | int irq; | ||
52 | int vtermno; | ||
53 | grant_ref_t gntref; | ||
54 | }; | ||
55 | |||
56 | static LIST_HEAD(xenconsoles); | ||
57 | static DEFINE_SPINLOCK(xencons_lock); | ||
41 | 58 | ||
42 | /* ------------------------------------------------------------------ */ | 59 | /* ------------------------------------------------------------------ */ |
43 | 60 | ||
44 | static unsigned long console_pfn = ~0ul; | 61 | static struct xencons_info *vtermno_to_xencons(int vtermno) |
62 | { | ||
63 | struct xencons_info *entry, *n, *ret = NULL; | ||
64 | |||
65 | if (list_empty(&xenconsoles)) | ||
66 | return NULL; | ||
67 | |||
68 | list_for_each_entry_safe(entry, n, &xenconsoles, list) { | ||
69 | if (entry->vtermno == vtermno) { | ||
70 | ret = entry; | ||
71 | break; | ||
72 | } | ||
73 | } | ||
74 | |||
75 | return ret; | ||
76 | } | ||
45 | 77 | ||
46 | static inline struct xencons_interface *xencons_interface(void) | 78 | static inline int xenbus_devid_to_vtermno(int devid) |
47 | { | 79 | { |
48 | if (console_pfn == ~0ul) | 80 | return devid + HVC_COOKIE; |
49 | return mfn_to_virt(xen_start_info->console.domU.mfn); | ||
50 | else | ||
51 | return __va(console_pfn << PAGE_SHIFT); | ||
52 | } | 81 | } |
53 | 82 | ||
54 | static inline void notify_daemon(void) | 83 | static inline void notify_daemon(struct xencons_info *cons) |
55 | { | 84 | { |
56 | /* Use evtchn: this is called early, before irq is set up. */ | 85 | /* Use evtchn: this is called early, before irq is set up. */ |
57 | notify_remote_via_evtchn(xen_start_info->console.domU.evtchn); | 86 | notify_remote_via_evtchn(cons->evtchn); |
58 | } | 87 | } |
59 | 88 | ||
60 | static int __write_console(const char *data, int len) | 89 | static int __write_console(struct xencons_info *xencons, |
90 | const char *data, int len) | ||
61 | { | 91 | { |
62 | struct xencons_interface *intf = xencons_interface(); | ||
63 | XENCONS_RING_IDX cons, prod; | 92 | XENCONS_RING_IDX cons, prod; |
93 | struct xencons_interface *intf = xencons->intf; | ||
64 | int sent = 0; | 94 | int sent = 0; |
65 | 95 | ||
66 | cons = intf->out_cons; | 96 | cons = intf->out_cons; |
@@ -75,13 +105,16 @@ static int __write_console(const char *data, int len) | |||
75 | intf->out_prod = prod; | 105 | intf->out_prod = prod; |
76 | 106 | ||
77 | if (sent) | 107 | if (sent) |
78 | notify_daemon(); | 108 | notify_daemon(xencons); |
79 | return sent; | 109 | return sent; |
80 | } | 110 | } |
81 | 111 | ||
82 | static int domU_write_console(uint32_t vtermno, const char *data, int len) | 112 | static int domU_write_console(uint32_t vtermno, const char *data, int len) |
83 | { | 113 | { |
84 | int ret = len; | 114 | int ret = len; |
115 | struct xencons_info *cons = vtermno_to_xencons(vtermno); | ||
116 | if (cons == NULL) | ||
117 | return -EINVAL; | ||
85 | 118 | ||
86 | /* | 119 | /* |
87 | * Make sure the whole buffer is emitted, polling if | 120 | * Make sure the whole buffer is emitted, polling if |
@@ -90,7 +123,7 @@ static int domU_write_console(uint32_t vtermno, const char *data, int len) | |||
90 | * kernel is crippled. | 123 | * kernel is crippled. |
91 | */ | 124 | */ |
92 | while (len) { | 125 | while (len) { |
93 | int sent = __write_console(data, len); | 126 | int sent = __write_console(cons, data, len); |
94 | 127 | ||
95 | data += sent; | 128 | data += sent; |
96 | len -= sent; | 129 | len -= sent; |
@@ -104,9 +137,13 @@ static int domU_write_console(uint32_t vtermno, const char *data, int len) | |||
104 | 137 | ||
105 | static int domU_read_console(uint32_t vtermno, char *buf, int len) | 138 | static int domU_read_console(uint32_t vtermno, char *buf, int len) |
106 | { | 139 | { |
107 | struct xencons_interface *intf = xencons_interface(); | 140 | struct xencons_interface *intf; |
108 | XENCONS_RING_IDX cons, prod; | 141 | XENCONS_RING_IDX cons, prod; |
109 | int recv = 0; | 142 | int recv = 0; |
143 | struct xencons_info *xencons = vtermno_to_xencons(vtermno); | ||
144 | if (xencons == NULL) | ||
145 | return -EINVAL; | ||
146 | intf = xencons->intf; | ||
110 | 147 | ||
111 | cons = intf->in_cons; | 148 | cons = intf->in_cons; |
112 | prod = intf->in_prod; | 149 | prod = intf->in_prod; |
@@ -119,7 +156,7 @@ static int domU_read_console(uint32_t vtermno, char *buf, int len) | |||
119 | mb(); /* read ring before consuming */ | 156 | mb(); /* read ring before consuming */ |
120 | intf->in_cons = cons; | 157 | intf->in_cons = cons; |
121 | 158 | ||
122 | notify_daemon(); | 159 | notify_daemon(xencons); |
123 | return recv; | 160 | return recv; |
124 | } | 161 | } |
125 | 162 | ||
@@ -157,68 +194,407 @@ static struct hv_ops dom0_hvc_ops = { | |||
157 | .notifier_hangup = notifier_hangup_irq, | 194 | .notifier_hangup = notifier_hangup_irq, |
158 | }; | 195 | }; |
159 | 196 | ||
160 | static int __init xen_hvc_init(void) | 197 | static int xen_hvm_console_init(void) |
198 | { | ||
199 | int r; | ||
200 | uint64_t v = 0; | ||
201 | unsigned long mfn; | ||
202 | struct xencons_info *info; | ||
203 | |||
204 | if (!xen_hvm_domain()) | ||
205 | return -ENODEV; | ||
206 | |||
207 | info = vtermno_to_xencons(HVC_COOKIE); | ||
208 | if (!info) { | ||
209 | info = kzalloc(sizeof(struct xencons_info), GFP_KERNEL | __GFP_ZERO); | ||
210 | if (!info) | ||
211 | return -ENOMEM; | ||
212 | } | ||
213 | |||
214 | /* already configured */ | ||
215 | if (info->intf != NULL) | ||
216 | return 0; | ||
217 | |||
218 | r = hvm_get_parameter(HVM_PARAM_CONSOLE_EVTCHN, &v); | ||
219 | if (r < 0) { | ||
220 | kfree(info); | ||
221 | return -ENODEV; | ||
222 | } | ||
223 | info->evtchn = v; | ||
224 | hvm_get_parameter(HVM_PARAM_CONSOLE_PFN, &v); | ||
225 | if (r < 0) { | ||
226 | kfree(info); | ||
227 | return -ENODEV; | ||
228 | } | ||
229 | mfn = v; | ||
230 | info->intf = ioremap(mfn << PAGE_SHIFT, PAGE_SIZE); | ||
231 | if (info->intf == NULL) { | ||
232 | kfree(info); | ||
233 | return -ENODEV; | ||
234 | } | ||
235 | info->vtermno = HVC_COOKIE; | ||
236 | |||
237 | spin_lock(&xencons_lock); | ||
238 | list_add_tail(&info->list, &xenconsoles); | ||
239 | spin_unlock(&xencons_lock); | ||
240 | |||
241 | return 0; | ||
242 | } | ||
243 | |||
244 | static int xen_pv_console_init(void) | ||
161 | { | 245 | { |
162 | struct hvc_struct *hp; | 246 | struct xencons_info *info; |
163 | struct hv_ops *ops; | ||
164 | 247 | ||
165 | if (!xen_pv_domain()) | 248 | if (!xen_pv_domain()) |
166 | return -ENODEV; | 249 | return -ENODEV; |
167 | 250 | ||
168 | if (xen_initial_domain()) { | 251 | if (!xen_start_info->console.domU.evtchn) |
169 | ops = &dom0_hvc_ops; | 252 | return -ENODEV; |
170 | xencons_irq = bind_virq_to_irq(VIRQ_CONSOLE, 0); | ||
171 | } else { | ||
172 | if (!xen_start_info->console.domU.evtchn) | ||
173 | return -ENODEV; | ||
174 | 253 | ||
175 | ops = &domU_hvc_ops; | 254 | info = vtermno_to_xencons(HVC_COOKIE); |
176 | xencons_irq = bind_evtchn_to_irq(xen_start_info->console.domU.evtchn); | 255 | if (!info) { |
256 | info = kzalloc(sizeof(struct xencons_info), GFP_KERNEL | __GFP_ZERO); | ||
257 | if (!info) | ||
258 | return -ENOMEM; | ||
177 | } | 259 | } |
178 | if (xencons_irq < 0) | ||
179 | xencons_irq = 0; | ||
180 | else | ||
181 | irq_set_noprobe(xencons_irq); | ||
182 | 260 | ||
183 | hp = hvc_alloc(HVC_COOKIE, xencons_irq, ops, 256); | 261 | /* already configured */ |
184 | if (IS_ERR(hp)) | 262 | if (info->intf != NULL) |
185 | return PTR_ERR(hp); | 263 | return 0; |
264 | |||
265 | info->evtchn = xen_start_info->console.domU.evtchn; | ||
266 | info->intf = mfn_to_virt(xen_start_info->console.domU.mfn); | ||
267 | info->vtermno = HVC_COOKIE; | ||
268 | |||
269 | spin_lock(&xencons_lock); | ||
270 | list_add_tail(&info->list, &xenconsoles); | ||
271 | spin_unlock(&xencons_lock); | ||
272 | |||
273 | return 0; | ||
274 | } | ||
275 | |||
276 | static int xen_initial_domain_console_init(void) | ||
277 | { | ||
278 | struct xencons_info *info; | ||
279 | |||
280 | if (!xen_initial_domain()) | ||
281 | return -ENODEV; | ||
282 | |||
283 | info = vtermno_to_xencons(HVC_COOKIE); | ||
284 | if (!info) { | ||
285 | info = kzalloc(sizeof(struct xencons_info), GFP_KERNEL | __GFP_ZERO); | ||
286 | if (!info) | ||
287 | return -ENOMEM; | ||
288 | } | ||
186 | 289 | ||
187 | hvc = hp; | 290 | info->irq = bind_virq_to_irq(VIRQ_CONSOLE, 0); |
291 | info->vtermno = HVC_COOKIE; | ||
188 | 292 | ||
189 | console_pfn = mfn_to_pfn(xen_start_info->console.domU.mfn); | 293 | spin_lock(&xencons_lock); |
294 | list_add_tail(&info->list, &xenconsoles); | ||
295 | spin_unlock(&xencons_lock); | ||
190 | 296 | ||
191 | return 0; | 297 | return 0; |
192 | } | 298 | } |
193 | 299 | ||
194 | void xen_console_resume(void) | 300 | void xen_console_resume(void) |
195 | { | 301 | { |
196 | if (xencons_irq) | 302 | struct xencons_info *info = vtermno_to_xencons(HVC_COOKIE); |
197 | rebind_evtchn_irq(xen_start_info->console.domU.evtchn, xencons_irq); | 303 | if (info != NULL && info->irq) |
304 | rebind_evtchn_irq(info->evtchn, info->irq); | ||
305 | } | ||
306 | |||
307 | static void xencons_disconnect_backend(struct xencons_info *info) | ||
308 | { | ||
309 | if (info->irq > 0) | ||
310 | unbind_from_irqhandler(info->irq, NULL); | ||
311 | info->irq = 0; | ||
312 | if (info->evtchn > 0) | ||
313 | xenbus_free_evtchn(info->xbdev, info->evtchn); | ||
314 | info->evtchn = 0; | ||
315 | if (info->gntref > 0) | ||
316 | gnttab_free_grant_references(info->gntref); | ||
317 | info->gntref = 0; | ||
318 | if (info->hvc != NULL) | ||
319 | hvc_remove(info->hvc); | ||
320 | info->hvc = NULL; | ||
321 | } | ||
322 | |||
323 | static void xencons_free(struct xencons_info *info) | ||
324 | { | ||
325 | free_page((unsigned long)info->intf); | ||
326 | info->intf = NULL; | ||
327 | info->vtermno = 0; | ||
328 | kfree(info); | ||
329 | } | ||
330 | |||
331 | static int xen_console_remove(struct xencons_info *info) | ||
332 | { | ||
333 | xencons_disconnect_backend(info); | ||
334 | spin_lock(&xencons_lock); | ||
335 | list_del(&info->list); | ||
336 | spin_unlock(&xencons_lock); | ||
337 | if (info->xbdev != NULL) | ||
338 | xencons_free(info); | ||
339 | else { | ||
340 | if (xen_hvm_domain()) | ||
341 | iounmap(info->intf); | ||
342 | kfree(info); | ||
343 | } | ||
344 | return 0; | ||
345 | } | ||
346 | |||
347 | #ifdef CONFIG_HVC_XEN_FRONTEND | ||
348 | static struct xenbus_driver xencons_driver; | ||
349 | |||
350 | static int xencons_remove(struct xenbus_device *dev) | ||
351 | { | ||
352 | return xen_console_remove(dev_get_drvdata(&dev->dev)); | ||
353 | } | ||
354 | |||
355 | static int xencons_connect_backend(struct xenbus_device *dev, | ||
356 | struct xencons_info *info) | ||
357 | { | ||
358 | int ret, evtchn, devid, ref, irq; | ||
359 | struct xenbus_transaction xbt; | ||
360 | grant_ref_t gref_head; | ||
361 | unsigned long mfn; | ||
362 | |||
363 | ret = xenbus_alloc_evtchn(dev, &evtchn); | ||
364 | if (ret) | ||
365 | return ret; | ||
366 | info->evtchn = evtchn; | ||
367 | irq = bind_evtchn_to_irq(evtchn); | ||
368 | if (irq < 0) | ||
369 | return irq; | ||
370 | info->irq = irq; | ||
371 | devid = dev->nodename[strlen(dev->nodename) - 1] - '0'; | ||
372 | info->hvc = hvc_alloc(xenbus_devid_to_vtermno(devid), | ||
373 | irq, &domU_hvc_ops, 256); | ||
374 | if (IS_ERR(info->hvc)) | ||
375 | return PTR_ERR(info->hvc); | ||
376 | if (xen_pv_domain()) | ||
377 | mfn = virt_to_mfn(info->intf); | ||
378 | else | ||
379 | mfn = __pa(info->intf) >> PAGE_SHIFT; | ||
380 | ret = gnttab_alloc_grant_references(1, &gref_head); | ||
381 | if (ret < 0) | ||
382 | return ret; | ||
383 | info->gntref = gref_head; | ||
384 | ref = gnttab_claim_grant_reference(&gref_head); | ||
385 | if (ref < 0) | ||
386 | return ref; | ||
387 | gnttab_grant_foreign_access_ref(ref, info->xbdev->otherend_id, | ||
388 | mfn, 0); | ||
389 | |||
390 | again: | ||
391 | ret = xenbus_transaction_start(&xbt); | ||
392 | if (ret) { | ||
393 | xenbus_dev_fatal(dev, ret, "starting transaction"); | ||
394 | return ret; | ||
395 | } | ||
396 | ret = xenbus_printf(xbt, dev->nodename, "ring-ref", "%d", ref); | ||
397 | if (ret) | ||
398 | goto error_xenbus; | ||
399 | ret = xenbus_printf(xbt, dev->nodename, "port", "%u", | ||
400 | evtchn); | ||
401 | if (ret) | ||
402 | goto error_xenbus; | ||
403 | ret = xenbus_printf(xbt, dev->nodename, "type", "ioemu"); | ||
404 | if (ret) | ||
405 | goto error_xenbus; | ||
406 | ret = xenbus_transaction_end(xbt, 0); | ||
407 | if (ret) { | ||
408 | if (ret == -EAGAIN) | ||
409 | goto again; | ||
410 | xenbus_dev_fatal(dev, ret, "completing transaction"); | ||
411 | return ret; | ||
412 | } | ||
413 | |||
414 | xenbus_switch_state(dev, XenbusStateInitialised); | ||
415 | return 0; | ||
416 | |||
417 | error_xenbus: | ||
418 | xenbus_transaction_end(xbt, 1); | ||
419 | xenbus_dev_fatal(dev, ret, "writing xenstore"); | ||
420 | return ret; | ||
421 | } | ||
422 | |||
423 | static int __devinit xencons_probe(struct xenbus_device *dev, | ||
424 | const struct xenbus_device_id *id) | ||
425 | { | ||
426 | int ret, devid; | ||
427 | struct xencons_info *info; | ||
428 | |||
429 | devid = dev->nodename[strlen(dev->nodename) - 1] - '0'; | ||
430 | if (devid == 0) | ||
431 | return -ENODEV; | ||
432 | |||
433 | info = kzalloc(sizeof(struct xencons_info), GFP_KERNEL | __GFP_ZERO); | ||
434 | if (!info) | ||
435 | goto error_nomem; | ||
436 | dev_set_drvdata(&dev->dev, info); | ||
437 | info->xbdev = dev; | ||
438 | info->vtermno = xenbus_devid_to_vtermno(devid); | ||
439 | info->intf = (void *)__get_free_page(GFP_KERNEL | __GFP_ZERO); | ||
440 | if (!info->intf) | ||
441 | goto error_nomem; | ||
442 | |||
443 | ret = xencons_connect_backend(dev, info); | ||
444 | if (ret < 0) | ||
445 | goto error; | ||
446 | spin_lock(&xencons_lock); | ||
447 | list_add_tail(&info->list, &xenconsoles); | ||
448 | spin_unlock(&xencons_lock); | ||
449 | |||
450 | return 0; | ||
451 | |||
452 | error_nomem: | ||
453 | ret = -ENOMEM; | ||
454 | xenbus_dev_fatal(dev, ret, "allocating device memory"); | ||
455 | error: | ||
456 | xencons_disconnect_backend(info); | ||
457 | xencons_free(info); | ||
458 | return ret; | ||
459 | } | ||
460 | |||
461 | static int xencons_resume(struct xenbus_device *dev) | ||
462 | { | ||
463 | struct xencons_info *info = dev_get_drvdata(&dev->dev); | ||
464 | |||
465 | xencons_disconnect_backend(info); | ||
466 | memset(info->intf, 0, PAGE_SIZE); | ||
467 | return xencons_connect_backend(dev, info); | ||
468 | } | ||
469 | |||
470 | static void xencons_backend_changed(struct xenbus_device *dev, | ||
471 | enum xenbus_state backend_state) | ||
472 | { | ||
473 | switch (backend_state) { | ||
474 | case XenbusStateReconfiguring: | ||
475 | case XenbusStateReconfigured: | ||
476 | case XenbusStateInitialising: | ||
477 | case XenbusStateInitialised: | ||
478 | case XenbusStateUnknown: | ||
479 | case XenbusStateClosed: | ||
480 | break; | ||
481 | |||
482 | case XenbusStateInitWait: | ||
483 | break; | ||
484 | |||
485 | case XenbusStateConnected: | ||
486 | xenbus_switch_state(dev, XenbusStateConnected); | ||
487 | break; | ||
488 | |||
489 | case XenbusStateClosing: | ||
490 | xenbus_frontend_closed(dev); | ||
491 | break; | ||
492 | } | ||
493 | } | ||
494 | |||
495 | static const struct xenbus_device_id xencons_ids[] = { | ||
496 | { "console" }, | ||
497 | { "" } | ||
498 | }; | ||
499 | |||
500 | |||
501 | static DEFINE_XENBUS_DRIVER(xencons, "xenconsole", | ||
502 | .probe = xencons_probe, | ||
503 | .remove = xencons_remove, | ||
504 | .resume = xencons_resume, | ||
505 | .otherend_changed = xencons_backend_changed, | ||
506 | ); | ||
507 | #endif /* CONFIG_HVC_XEN_FRONTEND */ | ||
508 | |||
509 | static int __init xen_hvc_init(void) | ||
510 | { | ||
511 | int r; | ||
512 | struct xencons_info *info; | ||
513 | const struct hv_ops *ops; | ||
514 | |||
515 | if (!xen_domain()) | ||
516 | return -ENODEV; | ||
517 | |||
518 | if (xen_initial_domain()) { | ||
519 | ops = &dom0_hvc_ops; | ||
520 | r = xen_initial_domain_console_init(); | ||
521 | if (r < 0) | ||
522 | return r; | ||
523 | info = vtermno_to_xencons(HVC_COOKIE); | ||
524 | } else { | ||
525 | ops = &domU_hvc_ops; | ||
526 | if (xen_hvm_domain()) | ||
527 | r = xen_hvm_console_init(); | ||
528 | else | ||
529 | r = xen_pv_console_init(); | ||
530 | if (r < 0) | ||
531 | return r; | ||
532 | |||
533 | info = vtermno_to_xencons(HVC_COOKIE); | ||
534 | info->irq = bind_evtchn_to_irq(info->evtchn); | ||
535 | } | ||
536 | if (info->irq < 0) | ||
537 | info->irq = 0; /* NO_IRQ */ | ||
538 | else | ||
539 | irq_set_noprobe(info->irq); | ||
540 | |||
541 | info->hvc = hvc_alloc(HVC_COOKIE, info->irq, ops, 256); | ||
542 | if (IS_ERR(info->hvc)) { | ||
543 | r = PTR_ERR(info->hvc); | ||
544 | spin_lock(&xencons_lock); | ||
545 | list_del(&info->list); | ||
546 | spin_unlock(&xencons_lock); | ||
547 | if (info->irq) | ||
548 | unbind_from_irqhandler(info->irq, NULL); | ||
549 | kfree(info); | ||
550 | return r; | ||
551 | } | ||
552 | |||
553 | r = 0; | ||
554 | #ifdef CONFIG_HVC_XEN_FRONTEND | ||
555 | r = xenbus_register_frontend(&xencons_driver); | ||
556 | #endif | ||
557 | return r; | ||
198 | } | 558 | } |
199 | 559 | ||
200 | static void __exit xen_hvc_fini(void) | 560 | static void __exit xen_hvc_fini(void) |
201 | { | 561 | { |
202 | if (hvc) | 562 | struct xencons_info *entry, *next; |
203 | hvc_remove(hvc); | 563 | |
564 | if (list_empty(&xenconsoles)) | ||
565 | return; | ||
566 | |||
567 | list_for_each_entry_safe(entry, next, &xenconsoles, list) { | ||
568 | xen_console_remove(entry); | ||
569 | } | ||
204 | } | 570 | } |
205 | 571 | ||
206 | static int xen_cons_init(void) | 572 | static int xen_cons_init(void) |
207 | { | 573 | { |
208 | struct hv_ops *ops; | 574 | const struct hv_ops *ops; |
209 | 575 | ||
210 | if (!xen_pv_domain()) | 576 | if (!xen_domain()) |
211 | return 0; | 577 | return 0; |
212 | 578 | ||
213 | if (xen_initial_domain()) | 579 | if (xen_initial_domain()) |
214 | ops = &dom0_hvc_ops; | 580 | ops = &dom0_hvc_ops; |
215 | else | 581 | else { |
582 | int r; | ||
216 | ops = &domU_hvc_ops; | 583 | ops = &domU_hvc_ops; |
217 | 584 | ||
585 | if (xen_hvm_domain()) | ||
586 | r = xen_hvm_console_init(); | ||
587 | else | ||
588 | r = xen_pv_console_init(); | ||
589 | if (r < 0) | ||
590 | return r; | ||
591 | } | ||
592 | |||
218 | hvc_instantiate(HVC_COOKIE, 0, ops); | 593 | hvc_instantiate(HVC_COOKIE, 0, ops); |
219 | return 0; | 594 | return 0; |
220 | } | 595 | } |
221 | 596 | ||
597 | |||
222 | module_init(xen_hvc_init); | 598 | module_init(xen_hvc_init); |
223 | module_exit(xen_hvc_fini); | 599 | module_exit(xen_hvc_fini); |
224 | console_initcall(xen_cons_init); | 600 | console_initcall(xen_cons_init); |
@@ -230,6 +606,9 @@ static void xenboot_write_console(struct console *console, const char *string, | |||
230 | unsigned int linelen, off = 0; | 606 | unsigned int linelen, off = 0; |
231 | const char *pos; | 607 | const char *pos; |
232 | 608 | ||
609 | if (!xen_pv_domain()) | ||
610 | return; | ||
611 | |||
233 | dom0_write_console(0, string, len); | 612 | dom0_write_console(0, string, len); |
234 | 613 | ||
235 | if (xen_initial_domain()) | 614 | if (xen_initial_domain()) |