aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/char
diff options
context:
space:
mode:
authorJeremy Fitzhardinge <jeremy@xensource.com>2007-07-17 21:37:06 -0400
committerJeremy Fitzhardinge <jeremy@goop.org>2007-07-18 11:47:44 -0400
commitb536b4b9623084d86f2b1f19cb44a2d6d74f00bf (patch)
tree86c1981309dbd8b9bf120d4ddba50abd105af89a /drivers/char
parent8b84ad942b534f8faeb34b68f0f7277ea375fed0 (diff)
xen: use the hvc console infrastructure for Xen console
Implement a Xen back-end for hvc console. * * * Add early printk support via hvc console, enable using "earlyprintk=xen" on the kernel command line. From: Gerd Hoffmann <kraxel@suse.de> Signed-off-by: Jeremy Fitzhardinge <jeremy@xensource.com> Signed-off-by: Chris Wright <chrisw@sous-sol.org> Acked-by: Ingo Molnar <mingo@elte.hu> Acked-by: Olof Johansson <olof@lixom.net>
Diffstat (limited to 'drivers/char')
-rw-r--r--drivers/char/Kconfig8
-rw-r--r--drivers/char/Makefile1
-rw-r--r--drivers/char/hvc_xen.c159
3 files changed, 168 insertions, 0 deletions
diff --git a/drivers/char/Kconfig b/drivers/char/Kconfig
index 97bd71bc3aea..9e8f21410d2d 100644
--- a/drivers/char/Kconfig
+++ b/drivers/char/Kconfig
@@ -604,6 +604,14 @@ config HVC_BEAT
604 help 604 help
605 Toshiba's Cell Reference Set Beat Console device driver 605 Toshiba's Cell Reference Set Beat Console device driver
606 606
607config HVC_XEN
608 bool "Xen Hypervisor Console support"
609 depends on XEN
610 select HVC_DRIVER
611 default y
612 help
613 Xen virtual console device driver
614
607config HVCS 615config HVCS
608 tristate "IBM Hypervisor Virtual Console Server support" 616 tristate "IBM Hypervisor Virtual Console Server support"
609 depends on PPC_PSERIES 617 depends on PPC_PSERIES
diff --git a/drivers/char/Makefile b/drivers/char/Makefile
index f2996a95eb07..8852b8d643cf 100644
--- a/drivers/char/Makefile
+++ b/drivers/char/Makefile
@@ -48,6 +48,7 @@ obj-$(CONFIG_HVC_ISERIES) += hvc_iseries.o
48obj-$(CONFIG_HVC_RTAS) += hvc_rtas.o 48obj-$(CONFIG_HVC_RTAS) += hvc_rtas.o
49obj-$(CONFIG_HVC_BEAT) += hvc_beat.o 49obj-$(CONFIG_HVC_BEAT) += hvc_beat.o
50obj-$(CONFIG_HVC_DRIVER) += hvc_console.o 50obj-$(CONFIG_HVC_DRIVER) += hvc_console.o
51obj-$(CONFIG_HVC_XEN) += hvc_xen.o
51obj-$(CONFIG_RAW_DRIVER) += raw.o 52obj-$(CONFIG_RAW_DRIVER) += raw.o
52obj-$(CONFIG_SGI_SNSC) += snsc.o snsc_event.o 53obj-$(CONFIG_SGI_SNSC) += snsc.o snsc_event.o
53obj-$(CONFIG_MSPEC) += mspec.o 54obj-$(CONFIG_MSPEC) += mspec.o
diff --git a/drivers/char/hvc_xen.c b/drivers/char/hvc_xen.c
new file mode 100644
index 000000000000..dd68f8541c2d
--- /dev/null
+++ b/drivers/char/hvc_xen.c
@@ -0,0 +1,159 @@
1/*
2 * xen console driver interface to hvc_console.c
3 *
4 * (c) 2007 Gerd Hoffmann <kraxel@suse.de>
5 *
6 * This program is free software; you can redistribute it and/or modify
7 * it under the terms of the GNU General Public License as published by
8 * the Free Software Foundation; either version 2 of the License, or
9 * (at your option) any later version.
10 *
11 * This program is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 * GNU General Public License for more details.
15 *
16 * You should have received a copy of the GNU General Public License
17 * along with this program; if not, write to the Free Software
18 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
19 */
20
21#include <linux/console.h>
22#include <linux/delay.h>
23#include <linux/err.h>
24#include <linux/init.h>
25#include <linux/types.h>
26
27#include <asm/xen/hypervisor.h>
28#include <xen/page.h>
29#include <xen/events.h>
30#include <xen/interface/io/console.h>
31#include <xen/hvc-console.h>
32
33#include "hvc_console.h"
34
35#define HVC_COOKIE 0x58656e /* "Xen" in hex */
36
37static struct hvc_struct *hvc;
38static int xencons_irq;
39
40/* ------------------------------------------------------------------ */
41
42static inline struct xencons_interface *xencons_interface(void)
43{
44 return mfn_to_virt(xen_start_info->console.domU.mfn);
45}
46
47static inline void notify_daemon(void)
48{
49 /* Use evtchn: this is called early, before irq is set up. */
50 notify_remote_via_evtchn(xen_start_info->console.domU.evtchn);
51}
52
53static int write_console(uint32_t vtermno, const char *data, int len)
54{
55 struct xencons_interface *intf = xencons_interface();
56 XENCONS_RING_IDX cons, prod;
57 int sent = 0;
58
59 cons = intf->out_cons;
60 prod = intf->out_prod;
61 mb(); /* update queue values before going on */
62 BUG_ON((prod - cons) > sizeof(intf->out));
63
64 while ((sent < len) && ((prod - cons) < sizeof(intf->out)))
65 intf->out[MASK_XENCONS_IDX(prod++, intf->out)] = data[sent++];
66
67 wmb(); /* write ring before updating pointer */
68 intf->out_prod = prod;
69
70 notify_daemon();
71 return sent;
72}
73
74static int read_console(uint32_t vtermno, char *buf, int len)
75{
76 struct xencons_interface *intf = xencons_interface();
77 XENCONS_RING_IDX cons, prod;
78 int recv = 0;
79
80 cons = intf->in_cons;
81 prod = intf->in_prod;
82 mb(); /* get pointers before reading ring */
83 BUG_ON((prod - cons) > sizeof(intf->in));
84
85 while (cons != prod && recv < len)
86 buf[recv++] = intf->in[MASK_XENCONS_IDX(cons++, intf->in)];
87
88 mb(); /* read ring before consuming */
89 intf->in_cons = cons;
90
91 notify_daemon();
92 return recv;
93}
94
95static struct hv_ops hvc_ops = {
96 .get_chars = read_console,
97 .put_chars = write_console,
98};
99
100static int __init xen_init(void)
101{
102 struct hvc_struct *hp;
103
104 if (!is_running_on_xen())
105 return 0;
106
107 xencons_irq = bind_evtchn_to_irq(xen_start_info->console.domU.evtchn);
108 if (xencons_irq < 0)
109 xencons_irq = 0 /* NO_IRQ */;
110 hp = hvc_alloc(HVC_COOKIE, xencons_irq, &hvc_ops, 256);
111 if (IS_ERR(hp))
112 return PTR_ERR(hp);
113
114 hvc = hp;
115 return 0;
116}
117
118static void __exit xen_fini(void)
119{
120 if (hvc)
121 hvc_remove(hvc);
122}
123
124static int xen_cons_init(void)
125{
126 if (!is_running_on_xen())
127 return 0;
128
129 hvc_instantiate(HVC_COOKIE, 0, &hvc_ops);
130 return 0;
131}
132
133module_init(xen_init);
134module_exit(xen_fini);
135console_initcall(xen_cons_init);
136
137static void xenboot_write_console(struct console *console, const char *string,
138 unsigned len)
139{
140 unsigned int linelen, off = 0;
141 const char *pos;
142
143 while (off < len && NULL != (pos = strchr(string+off, '\n'))) {
144 linelen = pos-string+off;
145 if (off + linelen > len)
146 break;
147 write_console(0, string+off, linelen);
148 write_console(0, "\r\n", 2);
149 off += linelen + 1;
150 }
151 if (off < len)
152 write_console(0, string+off, len-off);
153}
154
155struct console xenboot_console = {
156 .name = "xenboot",
157 .write = xenboot_write_console,
158 .flags = CON_PRINTBUFFER | CON_BOOT,
159};