1b536b4b9623084d86f2b1f19cb44a2d6d74f00bfJeremy Fitzhardinge/*
2b536b4b9623084d86f2b1f19cb44a2d6d74f00bfJeremy Fitzhardinge * xen console driver interface to hvc_console.c
3b536b4b9623084d86f2b1f19cb44a2d6d74f00bfJeremy Fitzhardinge *
4b536b4b9623084d86f2b1f19cb44a2d6d74f00bfJeremy Fitzhardinge * (c) 2007 Gerd Hoffmann <kraxel@suse.de>
5b536b4b9623084d86f2b1f19cb44a2d6d74f00bfJeremy Fitzhardinge *
6b536b4b9623084d86f2b1f19cb44a2d6d74f00bfJeremy Fitzhardinge * This program is free software; you can redistribute it and/or modify
7b536b4b9623084d86f2b1f19cb44a2d6d74f00bfJeremy Fitzhardinge * it under the terms of the GNU General Public License as published by
8b536b4b9623084d86f2b1f19cb44a2d6d74f00bfJeremy Fitzhardinge * the Free Software Foundation; either version 2 of the License, or
9b536b4b9623084d86f2b1f19cb44a2d6d74f00bfJeremy Fitzhardinge * (at your option) any later version.
10b536b4b9623084d86f2b1f19cb44a2d6d74f00bfJeremy Fitzhardinge *
11b536b4b9623084d86f2b1f19cb44a2d6d74f00bfJeremy Fitzhardinge * This program is distributed in the hope that it will be useful,
12b536b4b9623084d86f2b1f19cb44a2d6d74f00bfJeremy Fitzhardinge * but WITHOUT ANY WARRANTY; without even the implied warranty of
13b536b4b9623084d86f2b1f19cb44a2d6d74f00bfJeremy Fitzhardinge * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
14b536b4b9623084d86f2b1f19cb44a2d6d74f00bfJeremy Fitzhardinge * GNU General Public License for more details.
15b536b4b9623084d86f2b1f19cb44a2d6d74f00bfJeremy Fitzhardinge *
16b536b4b9623084d86f2b1f19cb44a2d6d74f00bfJeremy Fitzhardinge * You should have received a copy of the GNU General Public License
17b536b4b9623084d86f2b1f19cb44a2d6d74f00bfJeremy Fitzhardinge * along with this program; if not, write to the Free Software
18b536b4b9623084d86f2b1f19cb44a2d6d74f00bfJeremy Fitzhardinge * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307 USA
19b536b4b9623084d86f2b1f19cb44a2d6d74f00bfJeremy Fitzhardinge */
20b536b4b9623084d86f2b1f19cb44a2d6d74f00bfJeremy Fitzhardinge
21b536b4b9623084d86f2b1f19cb44a2d6d74f00bfJeremy Fitzhardinge#include <linux/console.h>
22b536b4b9623084d86f2b1f19cb44a2d6d74f00bfJeremy Fitzhardinge#include <linux/delay.h>
23b536b4b9623084d86f2b1f19cb44a2d6d74f00bfJeremy Fitzhardinge#include <linux/err.h>
24b536b4b9623084d86f2b1f19cb44a2d6d74f00bfJeremy Fitzhardinge#include <linux/init.h>
25b536b4b9623084d86f2b1f19cb44a2d6d74f00bfJeremy Fitzhardinge#include <linux/types.h>
2602e19f9c7cacfb33d7b2f5cace7972fa60f92319Stefano Stabellini#include <linux/list.h>
27b536b4b9623084d86f2b1f19cb44a2d6d74f00bfJeremy Fitzhardinge
28eb5ef07151ba3c3cb4bcef0c8f146ff1115eaa55Stefano Stabellini#include <asm/io.h>
29b536b4b9623084d86f2b1f19cb44a2d6d74f00bfJeremy Fitzhardinge#include <asm/xen/hypervisor.h>
301ccbf5344c3daef046d2323190cc6807c44f1917Jeremy Fitzhardinge
311ccbf5344c3daef046d2323190cc6807c44f1917Jeremy Fitzhardinge#include <xen/xen.h>
32eb5ef07151ba3c3cb4bcef0c8f146ff1115eaa55Stefano Stabellini#include <xen/interface/xen.h>
33eb5ef07151ba3c3cb4bcef0c8f146ff1115eaa55Stefano Stabellini#include <xen/hvm.h>
3402e19f9c7cacfb33d7b2f5cace7972fa60f92319Stefano Stabellini#include <xen/grant_table.h>
35b536b4b9623084d86f2b1f19cb44a2d6d74f00bfJeremy Fitzhardinge#include <xen/page.h>
36b536b4b9623084d86f2b1f19cb44a2d6d74f00bfJeremy Fitzhardinge#include <xen/events.h>
37b536b4b9623084d86f2b1f19cb44a2d6d74f00bfJeremy Fitzhardinge#include <xen/interface/io/console.h>
38b536b4b9623084d86f2b1f19cb44a2d6d74f00bfJeremy Fitzhardinge#include <xen/hvc-console.h>
3902e19f9c7cacfb33d7b2f5cace7972fa60f92319Stefano Stabellini#include <xen/xenbus.h>
40b536b4b9623084d86f2b1f19cb44a2d6d74f00bfJeremy Fitzhardinge
41b536b4b9623084d86f2b1f19cb44a2d6d74f00bfJeremy Fitzhardinge#include "hvc_console.h"
42b536b4b9623084d86f2b1f19cb44a2d6d74f00bfJeremy Fitzhardinge
43b536b4b9623084d86f2b1f19cb44a2d6d74f00bfJeremy Fitzhardinge#define HVC_COOKIE   0x58656e /* "Xen" in hex */
44b536b4b9623084d86f2b1f19cb44a2d6d74f00bfJeremy Fitzhardinge
4502e19f9c7cacfb33d7b2f5cace7972fa60f92319Stefano Stabellinistruct xencons_info {
4602e19f9c7cacfb33d7b2f5cace7972fa60f92319Stefano Stabellini	struct list_head list;
4702e19f9c7cacfb33d7b2f5cace7972fa60f92319Stefano Stabellini	struct xenbus_device *xbdev;
4802e19f9c7cacfb33d7b2f5cace7972fa60f92319Stefano Stabellini	struct xencons_interface *intf;
4902e19f9c7cacfb33d7b2f5cace7972fa60f92319Stefano Stabellini	unsigned int evtchn;
5002e19f9c7cacfb33d7b2f5cace7972fa60f92319Stefano Stabellini	struct hvc_struct *hvc;
5102e19f9c7cacfb33d7b2f5cace7972fa60f92319Stefano Stabellini	int irq;
5202e19f9c7cacfb33d7b2f5cace7972fa60f92319Stefano Stabellini	int vtermno;
5302e19f9c7cacfb33d7b2f5cace7972fa60f92319Stefano Stabellini	grant_ref_t gntref;
5402e19f9c7cacfb33d7b2f5cace7972fa60f92319Stefano Stabellini};
5502e19f9c7cacfb33d7b2f5cace7972fa60f92319Stefano Stabellini
5602e19f9c7cacfb33d7b2f5cace7972fa60f92319Stefano Stabellinistatic LIST_HEAD(xenconsoles);
5702e19f9c7cacfb33d7b2f5cace7972fa60f92319Stefano Stabellinistatic DEFINE_SPINLOCK(xencons_lock);
58b536b4b9623084d86f2b1f19cb44a2d6d74f00bfJeremy Fitzhardinge
59b536b4b9623084d86f2b1f19cb44a2d6d74f00bfJeremy Fitzhardinge/* ------------------------------------------------------------------ */
60b536b4b9623084d86f2b1f19cb44a2d6d74f00bfJeremy Fitzhardinge
6102e19f9c7cacfb33d7b2f5cace7972fa60f92319Stefano Stabellinistatic struct xencons_info *vtermno_to_xencons(int vtermno)
6202e19f9c7cacfb33d7b2f5cace7972fa60f92319Stefano Stabellini{
6302e19f9c7cacfb33d7b2f5cace7972fa60f92319Stefano Stabellini	struct xencons_info *entry, *n, *ret = NULL;
6402e19f9c7cacfb33d7b2f5cace7972fa60f92319Stefano Stabellini
6502e19f9c7cacfb33d7b2f5cace7972fa60f92319Stefano Stabellini	if (list_empty(&xenconsoles))
6602e19f9c7cacfb33d7b2f5cace7972fa60f92319Stefano Stabellini			return NULL;
6702e19f9c7cacfb33d7b2f5cace7972fa60f92319Stefano Stabellini
6802e19f9c7cacfb33d7b2f5cace7972fa60f92319Stefano Stabellini	list_for_each_entry_safe(entry, n, &xenconsoles, list) {
6902e19f9c7cacfb33d7b2f5cace7972fa60f92319Stefano Stabellini		if (entry->vtermno == vtermno) {
7002e19f9c7cacfb33d7b2f5cace7972fa60f92319Stefano Stabellini			ret  = entry;
7102e19f9c7cacfb33d7b2f5cace7972fa60f92319Stefano Stabellini			break;
7202e19f9c7cacfb33d7b2f5cace7972fa60f92319Stefano Stabellini		}
7302e19f9c7cacfb33d7b2f5cace7972fa60f92319Stefano Stabellini	}
746b9b732d0e396a3f1a95977162a8624aafce38a1Jeremy Fitzhardinge
7502e19f9c7cacfb33d7b2f5cace7972fa60f92319Stefano Stabellini	return ret;
7602e19f9c7cacfb33d7b2f5cace7972fa60f92319Stefano Stabellini}
7702e19f9c7cacfb33d7b2f5cace7972fa60f92319Stefano Stabellini
7802e19f9c7cacfb33d7b2f5cace7972fa60f92319Stefano Stabellinistatic inline int xenbus_devid_to_vtermno(int devid)
79b536b4b9623084d86f2b1f19cb44a2d6d74f00bfJeremy Fitzhardinge{
8002e19f9c7cacfb33d7b2f5cace7972fa60f92319Stefano Stabellini	return devid + HVC_COOKIE;
81b536b4b9623084d86f2b1f19cb44a2d6d74f00bfJeremy Fitzhardinge}
82b536b4b9623084d86f2b1f19cb44a2d6d74f00bfJeremy Fitzhardinge
8302e19f9c7cacfb33d7b2f5cace7972fa60f92319Stefano Stabellinistatic inline void notify_daemon(struct xencons_info *cons)
84b536b4b9623084d86f2b1f19cb44a2d6d74f00bfJeremy Fitzhardinge{
85b536b4b9623084d86f2b1f19cb44a2d6d74f00bfJeremy Fitzhardinge	/* Use evtchn: this is called early, before irq is set up. */
8602e19f9c7cacfb33d7b2f5cace7972fa60f92319Stefano Stabellini	notify_remote_via_evtchn(cons->evtchn);
87b536b4b9623084d86f2b1f19cb44a2d6d74f00bfJeremy Fitzhardinge}
88b536b4b9623084d86f2b1f19cb44a2d6d74f00bfJeremy Fitzhardinge
8902e19f9c7cacfb33d7b2f5cace7972fa60f92319Stefano Stabellinistatic int __write_console(struct xencons_info *xencons,
9002e19f9c7cacfb33d7b2f5cace7972fa60f92319Stefano Stabellini		const char *data, int len)
91b536b4b9623084d86f2b1f19cb44a2d6d74f00bfJeremy Fitzhardinge{
92b536b4b9623084d86f2b1f19cb44a2d6d74f00bfJeremy Fitzhardinge	XENCONS_RING_IDX cons, prod;
9302e19f9c7cacfb33d7b2f5cace7972fa60f92319Stefano Stabellini	struct xencons_interface *intf = xencons->intf;
94b536b4b9623084d86f2b1f19cb44a2d6d74f00bfJeremy Fitzhardinge	int sent = 0;
95b536b4b9623084d86f2b1f19cb44a2d6d74f00bfJeremy Fitzhardinge
96b536b4b9623084d86f2b1f19cb44a2d6d74f00bfJeremy Fitzhardinge	cons = intf->out_cons;
97b536b4b9623084d86f2b1f19cb44a2d6d74f00bfJeremy Fitzhardinge	prod = intf->out_prod;
98b536b4b9623084d86f2b1f19cb44a2d6d74f00bfJeremy Fitzhardinge	mb();			/* update queue values before going on */
99b536b4b9623084d86f2b1f19cb44a2d6d74f00bfJeremy Fitzhardinge	BUG_ON((prod - cons) > sizeof(intf->out));
100b536b4b9623084d86f2b1f19cb44a2d6d74f00bfJeremy Fitzhardinge
101b536b4b9623084d86f2b1f19cb44a2d6d74f00bfJeremy Fitzhardinge	while ((sent < len) && ((prod - cons) < sizeof(intf->out)))
102b536b4b9623084d86f2b1f19cb44a2d6d74f00bfJeremy Fitzhardinge		intf->out[MASK_XENCONS_IDX(prod++, intf->out)] = data[sent++];
103b536b4b9623084d86f2b1f19cb44a2d6d74f00bfJeremy Fitzhardinge
104b536b4b9623084d86f2b1f19cb44a2d6d74f00bfJeremy Fitzhardinge	wmb();			/* write ring before updating pointer */
105b536b4b9623084d86f2b1f19cb44a2d6d74f00bfJeremy Fitzhardinge	intf->out_prod = prod;
106b536b4b9623084d86f2b1f19cb44a2d6d74f00bfJeremy Fitzhardinge
107403a85ff001710bb92689790b9a5c1c80e4b37a6Jeremy Fitzhardinge	if (sent)
10802e19f9c7cacfb33d7b2f5cace7972fa60f92319Stefano Stabellini		notify_daemon(xencons);
109b536b4b9623084d86f2b1f19cb44a2d6d74f00bfJeremy Fitzhardinge	return sent;
110b536b4b9623084d86f2b1f19cb44a2d6d74f00bfJeremy Fitzhardinge}
111b536b4b9623084d86f2b1f19cb44a2d6d74f00bfJeremy Fitzhardinge
1124fe7d5a708a955b35e3fdc4dea3e0b7a6ae2eb06Jeremy Fitzhardingestatic int domU_write_console(uint32_t vtermno, const char *data, int len)
1137825cf10e31c64ece3cac66fb01a742f1094da51Jeremy Fitzhardinge{
1147825cf10e31c64ece3cac66fb01a742f1094da51Jeremy Fitzhardinge	int ret = len;
11502e19f9c7cacfb33d7b2f5cace7972fa60f92319Stefano Stabellini	struct xencons_info *cons = vtermno_to_xencons(vtermno);
11602e19f9c7cacfb33d7b2f5cace7972fa60f92319Stefano Stabellini	if (cons == NULL)
11702e19f9c7cacfb33d7b2f5cace7972fa60f92319Stefano Stabellini		return -EINVAL;
1187825cf10e31c64ece3cac66fb01a742f1094da51Jeremy Fitzhardinge
1197825cf10e31c64ece3cac66fb01a742f1094da51Jeremy Fitzhardinge	/*
1207825cf10e31c64ece3cac66fb01a742f1094da51Jeremy Fitzhardinge	 * Make sure the whole buffer is emitted, polling if
1217825cf10e31c64ece3cac66fb01a742f1094da51Jeremy Fitzhardinge	 * necessary.  We don't ever want to rely on the hvc daemon
1227825cf10e31c64ece3cac66fb01a742f1094da51Jeremy Fitzhardinge	 * because the most interesting console output is when the
1237825cf10e31c64ece3cac66fb01a742f1094da51Jeremy Fitzhardinge	 * kernel is crippled.
1247825cf10e31c64ece3cac66fb01a742f1094da51Jeremy Fitzhardinge	 */
1257825cf10e31c64ece3cac66fb01a742f1094da51Jeremy Fitzhardinge	while (len) {
12602e19f9c7cacfb33d7b2f5cace7972fa60f92319Stefano Stabellini		int sent = __write_console(cons, data, len);
1277825cf10e31c64ece3cac66fb01a742f1094da51Jeremy Fitzhardinge
1287825cf10e31c64ece3cac66fb01a742f1094da51Jeremy Fitzhardinge		data += sent;
1297825cf10e31c64ece3cac66fb01a742f1094da51Jeremy Fitzhardinge		len -= sent;
1307825cf10e31c64ece3cac66fb01a742f1094da51Jeremy Fitzhardinge
1317825cf10e31c64ece3cac66fb01a742f1094da51Jeremy Fitzhardinge		if (unlikely(len))
1327825cf10e31c64ece3cac66fb01a742f1094da51Jeremy Fitzhardinge			HYPERVISOR_sched_op(SCHEDOP_yield, NULL);
1337825cf10e31c64ece3cac66fb01a742f1094da51Jeremy Fitzhardinge	}
1347825cf10e31c64ece3cac66fb01a742f1094da51Jeremy Fitzhardinge
1357825cf10e31c64ece3cac66fb01a742f1094da51Jeremy Fitzhardinge	return ret;
1367825cf10e31c64ece3cac66fb01a742f1094da51Jeremy Fitzhardinge}
1377825cf10e31c64ece3cac66fb01a742f1094da51Jeremy Fitzhardinge
1384fe7d5a708a955b35e3fdc4dea3e0b7a6ae2eb06Jeremy Fitzhardingestatic int domU_read_console(uint32_t vtermno, char *buf, int len)
139b536b4b9623084d86f2b1f19cb44a2d6d74f00bfJeremy Fitzhardinge{
14002e19f9c7cacfb33d7b2f5cace7972fa60f92319Stefano Stabellini	struct xencons_interface *intf;
141b536b4b9623084d86f2b1f19cb44a2d6d74f00bfJeremy Fitzhardinge	XENCONS_RING_IDX cons, prod;
142b536b4b9623084d86f2b1f19cb44a2d6d74f00bfJeremy Fitzhardinge	int recv = 0;
14302e19f9c7cacfb33d7b2f5cace7972fa60f92319Stefano Stabellini	struct xencons_info *xencons = vtermno_to_xencons(vtermno);
14402e19f9c7cacfb33d7b2f5cace7972fa60f92319Stefano Stabellini	if (xencons == NULL)
14502e19f9c7cacfb33d7b2f5cace7972fa60f92319Stefano Stabellini		return -EINVAL;
14602e19f9c7cacfb33d7b2f5cace7972fa60f92319Stefano Stabellini	intf = xencons->intf;
147b536b4b9623084d86f2b1f19cb44a2d6d74f00bfJeremy Fitzhardinge
148b536b4b9623084d86f2b1f19cb44a2d6d74f00bfJeremy Fitzhardinge	cons = intf->in_cons;
149b536b4b9623084d86f2b1f19cb44a2d6d74f00bfJeremy Fitzhardinge	prod = intf->in_prod;
150b536b4b9623084d86f2b1f19cb44a2d6d74f00bfJeremy Fitzhardinge	mb();			/* get pointers before reading ring */
151b536b4b9623084d86f2b1f19cb44a2d6d74f00bfJeremy Fitzhardinge	BUG_ON((prod - cons) > sizeof(intf->in));
152b536b4b9623084d86f2b1f19cb44a2d6d74f00bfJeremy Fitzhardinge
153b536b4b9623084d86f2b1f19cb44a2d6d74f00bfJeremy Fitzhardinge	while (cons != prod && recv < len)
154b536b4b9623084d86f2b1f19cb44a2d6d74f00bfJeremy Fitzhardinge		buf[recv++] = intf->in[MASK_XENCONS_IDX(cons++, intf->in)];
155b536b4b9623084d86f2b1f19cb44a2d6d74f00bfJeremy Fitzhardinge
156b536b4b9623084d86f2b1f19cb44a2d6d74f00bfJeremy Fitzhardinge	mb();			/* read ring before consuming */
157b536b4b9623084d86f2b1f19cb44a2d6d74f00bfJeremy Fitzhardinge	intf->in_cons = cons;
158b536b4b9623084d86f2b1f19cb44a2d6d74f00bfJeremy Fitzhardinge
15902e19f9c7cacfb33d7b2f5cace7972fa60f92319Stefano Stabellini	notify_daemon(xencons);
160b536b4b9623084d86f2b1f19cb44a2d6d74f00bfJeremy Fitzhardinge	return recv;
161b536b4b9623084d86f2b1f19cb44a2d6d74f00bfJeremy Fitzhardinge}
162b536b4b9623084d86f2b1f19cb44a2d6d74f00bfJeremy Fitzhardinge
1634fe7d5a708a955b35e3fdc4dea3e0b7a6ae2eb06Jeremy Fitzhardingestatic struct hv_ops domU_hvc_ops = {
1644fe7d5a708a955b35e3fdc4dea3e0b7a6ae2eb06Jeremy Fitzhardinge	.get_chars = domU_read_console,
1654fe7d5a708a955b35e3fdc4dea3e0b7a6ae2eb06Jeremy Fitzhardinge	.put_chars = domU_write_console,
166611e097d7707741a336a0677d9d69bec40f29f3dChristian Borntraeger	.notifier_add = notifier_add_irq,
167611e097d7707741a336a0677d9d69bec40f29f3dChristian Borntraeger	.notifier_del = notifier_del_irq,
168fc362e2e0efd8b652ebfb409a4e43e6189c04f6fHendrik Brueckner	.notifier_hangup = notifier_hangup_irq,
169b536b4b9623084d86f2b1f19cb44a2d6d74f00bfJeremy Fitzhardinge};
170b536b4b9623084d86f2b1f19cb44a2d6d74f00bfJeremy Fitzhardinge
1714fe7d5a708a955b35e3fdc4dea3e0b7a6ae2eb06Jeremy Fitzhardingestatic int dom0_read_console(uint32_t vtermno, char *buf, int len)
1724fe7d5a708a955b35e3fdc4dea3e0b7a6ae2eb06Jeremy Fitzhardinge{
1734fe7d5a708a955b35e3fdc4dea3e0b7a6ae2eb06Jeremy Fitzhardinge	return HYPERVISOR_console_io(CONSOLEIO_read, len, buf);
1744fe7d5a708a955b35e3fdc4dea3e0b7a6ae2eb06Jeremy Fitzhardinge}
1754fe7d5a708a955b35e3fdc4dea3e0b7a6ae2eb06Jeremy Fitzhardinge
1764fe7d5a708a955b35e3fdc4dea3e0b7a6ae2eb06Jeremy Fitzhardinge/*
1774fe7d5a708a955b35e3fdc4dea3e0b7a6ae2eb06Jeremy Fitzhardinge * Either for a dom0 to write to the system console, or a domU with a
1784fe7d5a708a955b35e3fdc4dea3e0b7a6ae2eb06Jeremy Fitzhardinge * debug version of Xen
1794fe7d5a708a955b35e3fdc4dea3e0b7a6ae2eb06Jeremy Fitzhardinge */
1804fe7d5a708a955b35e3fdc4dea3e0b7a6ae2eb06Jeremy Fitzhardingestatic int dom0_write_console(uint32_t vtermno, const char *str, int len)
1814fe7d5a708a955b35e3fdc4dea3e0b7a6ae2eb06Jeremy Fitzhardinge{
1824fe7d5a708a955b35e3fdc4dea3e0b7a6ae2eb06Jeremy Fitzhardinge	int rc = HYPERVISOR_console_io(CONSOLEIO_write, len, (char *)str);
1834fe7d5a708a955b35e3fdc4dea3e0b7a6ae2eb06Jeremy Fitzhardinge	if (rc < 0)
1844fe7d5a708a955b35e3fdc4dea3e0b7a6ae2eb06Jeremy Fitzhardinge		return 0;
1854fe7d5a708a955b35e3fdc4dea3e0b7a6ae2eb06Jeremy Fitzhardinge
1864fe7d5a708a955b35e3fdc4dea3e0b7a6ae2eb06Jeremy Fitzhardinge	return len;
1874fe7d5a708a955b35e3fdc4dea3e0b7a6ae2eb06Jeremy Fitzhardinge}
1884fe7d5a708a955b35e3fdc4dea3e0b7a6ae2eb06Jeremy Fitzhardinge
1894fe7d5a708a955b35e3fdc4dea3e0b7a6ae2eb06Jeremy Fitzhardingestatic struct hv_ops dom0_hvc_ops = {
1904fe7d5a708a955b35e3fdc4dea3e0b7a6ae2eb06Jeremy Fitzhardinge	.get_chars = dom0_read_console,
1914fe7d5a708a955b35e3fdc4dea3e0b7a6ae2eb06Jeremy Fitzhardinge	.put_chars = dom0_write_console,
1924fe7d5a708a955b35e3fdc4dea3e0b7a6ae2eb06Jeremy Fitzhardinge	.notifier_add = notifier_add_irq,
1934fe7d5a708a955b35e3fdc4dea3e0b7a6ae2eb06Jeremy Fitzhardinge	.notifier_del = notifier_del_irq,
1944fe7d5a708a955b35e3fdc4dea3e0b7a6ae2eb06Jeremy Fitzhardinge	.notifier_hangup = notifier_hangup_irq,
1954fe7d5a708a955b35e3fdc4dea3e0b7a6ae2eb06Jeremy Fitzhardinge};
1964fe7d5a708a955b35e3fdc4dea3e0b7a6ae2eb06Jeremy Fitzhardinge
197eb5ef07151ba3c3cb4bcef0c8f146ff1115eaa55Stefano Stabellinistatic int xen_hvm_console_init(void)
198eb5ef07151ba3c3cb4bcef0c8f146ff1115eaa55Stefano Stabellini{
199eb5ef07151ba3c3cb4bcef0c8f146ff1115eaa55Stefano Stabellini	int r;
200eb5ef07151ba3c3cb4bcef0c8f146ff1115eaa55Stefano Stabellini	uint64_t v = 0;
201eb5ef07151ba3c3cb4bcef0c8f146ff1115eaa55Stefano Stabellini	unsigned long mfn;
20202e19f9c7cacfb33d7b2f5cace7972fa60f92319Stefano Stabellini	struct xencons_info *info;
203eb5ef07151ba3c3cb4bcef0c8f146ff1115eaa55Stefano Stabellini
204eb5ef07151ba3c3cb4bcef0c8f146ff1115eaa55Stefano Stabellini	if (!xen_hvm_domain())
205eb5ef07151ba3c3cb4bcef0c8f146ff1115eaa55Stefano Stabellini		return -ENODEV;
206eb5ef07151ba3c3cb4bcef0c8f146ff1115eaa55Stefano Stabellini
20702e19f9c7cacfb33d7b2f5cace7972fa60f92319Stefano Stabellini	info = vtermno_to_xencons(HVC_COOKIE);
20802e19f9c7cacfb33d7b2f5cace7972fa60f92319Stefano Stabellini	if (!info) {
20902e19f9c7cacfb33d7b2f5cace7972fa60f92319Stefano Stabellini		info = kzalloc(sizeof(struct xencons_info), GFP_KERNEL | __GFP_ZERO);
21002e19f9c7cacfb33d7b2f5cace7972fa60f92319Stefano Stabellini		if (!info)
21102e19f9c7cacfb33d7b2f5cace7972fa60f92319Stefano Stabellini			return -ENOMEM;
21202e19f9c7cacfb33d7b2f5cace7972fa60f92319Stefano Stabellini	}
21302e19f9c7cacfb33d7b2f5cace7972fa60f92319Stefano Stabellini
21402e19f9c7cacfb33d7b2f5cace7972fa60f92319Stefano Stabellini	/* already configured */
21502e19f9c7cacfb33d7b2f5cace7972fa60f92319Stefano Stabellini	if (info->intf != NULL)
21602e19f9c7cacfb33d7b2f5cace7972fa60f92319Stefano Stabellini		return 0;
2172da19ffd395d0fdba4ccbc4a3c751554059d4aa3Konrad Rzeszutek Wilk	/*
2182da19ffd395d0fdba4ccbc4a3c751554059d4aa3Konrad Rzeszutek Wilk	 * If the toolstack (or the hypervisor) hasn't set these values, the
2192da19ffd395d0fdba4ccbc4a3c751554059d4aa3Konrad Rzeszutek Wilk	 * default value is 0. Even though mfn = 0 and evtchn = 0 are
2202da19ffd395d0fdba4ccbc4a3c751554059d4aa3Konrad Rzeszutek Wilk	 * theoretically correct values, in practice they never are and they
2212da19ffd395d0fdba4ccbc4a3c751554059d4aa3Konrad Rzeszutek Wilk	 * mean that a legacy toolstack hasn't initialized the pv console correctly.
2222da19ffd395d0fdba4ccbc4a3c751554059d4aa3Konrad Rzeszutek Wilk	 */
223eb5ef07151ba3c3cb4bcef0c8f146ff1115eaa55Stefano Stabellini	r = hvm_get_parameter(HVM_PARAM_CONSOLE_EVTCHN, &v);
2242da19ffd395d0fdba4ccbc4a3c751554059d4aa3Konrad Rzeszutek Wilk	if (r < 0 || v == 0)
2256a07cbc4ef9cea9f9eabc676fd6b8c03c11f51ccKonrad Rzeszutek Wilk		goto err;
22602e19f9c7cacfb33d7b2f5cace7972fa60f92319Stefano Stabellini	info->evtchn = v;
22785fc3e3eba89272acb005f320ccafa0588a48f49Konrad Rzeszutek Wilk	v = 0;
22885fc3e3eba89272acb005f320ccafa0588a48f49Konrad Rzeszutek Wilk	r = hvm_get_parameter(HVM_PARAM_CONSOLE_PFN, &v);
2292da19ffd395d0fdba4ccbc4a3c751554059d4aa3Konrad Rzeszutek Wilk	if (r < 0 || v == 0)
2306a07cbc4ef9cea9f9eabc676fd6b8c03c11f51ccKonrad Rzeszutek Wilk		goto err;
231eb5ef07151ba3c3cb4bcef0c8f146ff1115eaa55Stefano Stabellini	mfn = v;
23202e19f9c7cacfb33d7b2f5cace7972fa60f92319Stefano Stabellini	info->intf = ioremap(mfn << PAGE_SHIFT, PAGE_SIZE);
2336a07cbc4ef9cea9f9eabc676fd6b8c03c11f51ccKonrad Rzeszutek Wilk	if (info->intf == NULL)
2346a07cbc4ef9cea9f9eabc676fd6b8c03c11f51ccKonrad Rzeszutek Wilk		goto err;
23502e19f9c7cacfb33d7b2f5cace7972fa60f92319Stefano Stabellini	info->vtermno = HVC_COOKIE;
23602e19f9c7cacfb33d7b2f5cace7972fa60f92319Stefano Stabellini
23702e19f9c7cacfb33d7b2f5cace7972fa60f92319Stefano Stabellini	spin_lock(&xencons_lock);
23802e19f9c7cacfb33d7b2f5cace7972fa60f92319Stefano Stabellini	list_add_tail(&info->list, &xenconsoles);
23902e19f9c7cacfb33d7b2f5cace7972fa60f92319Stefano Stabellini	spin_unlock(&xencons_lock);
24002e19f9c7cacfb33d7b2f5cace7972fa60f92319Stefano Stabellini
24102e19f9c7cacfb33d7b2f5cace7972fa60f92319Stefano Stabellini	return 0;
2426a07cbc4ef9cea9f9eabc676fd6b8c03c11f51ccKonrad Rzeszutek Wilkerr:
2436a07cbc4ef9cea9f9eabc676fd6b8c03c11f51ccKonrad Rzeszutek Wilk	kfree(info);
2446a07cbc4ef9cea9f9eabc676fd6b8c03c11f51ccKonrad Rzeszutek Wilk	return -ENODEV;
24502e19f9c7cacfb33d7b2f5cace7972fa60f92319Stefano Stabellini}
24602e19f9c7cacfb33d7b2f5cace7972fa60f92319Stefano Stabellini
24702e19f9c7cacfb33d7b2f5cace7972fa60f92319Stefano Stabellinistatic int xen_pv_console_init(void)
24802e19f9c7cacfb33d7b2f5cace7972fa60f92319Stefano Stabellini{
24902e19f9c7cacfb33d7b2f5cace7972fa60f92319Stefano Stabellini	struct xencons_info *info;
25002e19f9c7cacfb33d7b2f5cace7972fa60f92319Stefano Stabellini
25102e19f9c7cacfb33d7b2f5cace7972fa60f92319Stefano Stabellini	if (!xen_pv_domain())
25202e19f9c7cacfb33d7b2f5cace7972fa60f92319Stefano Stabellini		return -ENODEV;
25302e19f9c7cacfb33d7b2f5cace7972fa60f92319Stefano Stabellini
25402e19f9c7cacfb33d7b2f5cace7972fa60f92319Stefano Stabellini	if (!xen_start_info->console.domU.evtchn)
25502e19f9c7cacfb33d7b2f5cace7972fa60f92319Stefano Stabellini		return -ENODEV;
25602e19f9c7cacfb33d7b2f5cace7972fa60f92319Stefano Stabellini
25702e19f9c7cacfb33d7b2f5cace7972fa60f92319Stefano Stabellini	info = vtermno_to_xencons(HVC_COOKIE);
25802e19f9c7cacfb33d7b2f5cace7972fa60f92319Stefano Stabellini	if (!info) {
25902e19f9c7cacfb33d7b2f5cace7972fa60f92319Stefano Stabellini		info = kzalloc(sizeof(struct xencons_info), GFP_KERNEL | __GFP_ZERO);
26002e19f9c7cacfb33d7b2f5cace7972fa60f92319Stefano Stabellini		if (!info)
26102e19f9c7cacfb33d7b2f5cace7972fa60f92319Stefano Stabellini			return -ENOMEM;
26202e19f9c7cacfb33d7b2f5cace7972fa60f92319Stefano Stabellini	}
26302e19f9c7cacfb33d7b2f5cace7972fa60f92319Stefano Stabellini
26402e19f9c7cacfb33d7b2f5cace7972fa60f92319Stefano Stabellini	/* already configured */
26502e19f9c7cacfb33d7b2f5cace7972fa60f92319Stefano Stabellini	if (info->intf != NULL)
26602e19f9c7cacfb33d7b2f5cace7972fa60f92319Stefano Stabellini		return 0;
26702e19f9c7cacfb33d7b2f5cace7972fa60f92319Stefano Stabellini
26802e19f9c7cacfb33d7b2f5cace7972fa60f92319Stefano Stabellini	info->evtchn = xen_start_info->console.domU.evtchn;
26902e19f9c7cacfb33d7b2f5cace7972fa60f92319Stefano Stabellini	info->intf = mfn_to_virt(xen_start_info->console.domU.mfn);
27002e19f9c7cacfb33d7b2f5cace7972fa60f92319Stefano Stabellini	info->vtermno = HVC_COOKIE;
27102e19f9c7cacfb33d7b2f5cace7972fa60f92319Stefano Stabellini
27202e19f9c7cacfb33d7b2f5cace7972fa60f92319Stefano Stabellini	spin_lock(&xencons_lock);
27302e19f9c7cacfb33d7b2f5cace7972fa60f92319Stefano Stabellini	list_add_tail(&info->list, &xenconsoles);
27402e19f9c7cacfb33d7b2f5cace7972fa60f92319Stefano Stabellini	spin_unlock(&xencons_lock);
27502e19f9c7cacfb33d7b2f5cace7972fa60f92319Stefano Stabellini
27602e19f9c7cacfb33d7b2f5cace7972fa60f92319Stefano Stabellini	return 0;
27702e19f9c7cacfb33d7b2f5cace7972fa60f92319Stefano Stabellini}
27802e19f9c7cacfb33d7b2f5cace7972fa60f92319Stefano Stabellini
27902e19f9c7cacfb33d7b2f5cace7972fa60f92319Stefano Stabellinistatic int xen_initial_domain_console_init(void)
28002e19f9c7cacfb33d7b2f5cace7972fa60f92319Stefano Stabellini{
28102e19f9c7cacfb33d7b2f5cace7972fa60f92319Stefano Stabellini	struct xencons_info *info;
28202e19f9c7cacfb33d7b2f5cace7972fa60f92319Stefano Stabellini
28302e19f9c7cacfb33d7b2f5cace7972fa60f92319Stefano Stabellini	if (!xen_initial_domain())
28402e19f9c7cacfb33d7b2f5cace7972fa60f92319Stefano Stabellini		return -ENODEV;
28502e19f9c7cacfb33d7b2f5cace7972fa60f92319Stefano Stabellini
28602e19f9c7cacfb33d7b2f5cace7972fa60f92319Stefano Stabellini	info = vtermno_to_xencons(HVC_COOKIE);
28702e19f9c7cacfb33d7b2f5cace7972fa60f92319Stefano Stabellini	if (!info) {
28802e19f9c7cacfb33d7b2f5cace7972fa60f92319Stefano Stabellini		info = kzalloc(sizeof(struct xencons_info), GFP_KERNEL | __GFP_ZERO);
28902e19f9c7cacfb33d7b2f5cace7972fa60f92319Stefano Stabellini		if (!info)
29002e19f9c7cacfb33d7b2f5cace7972fa60f92319Stefano Stabellini			return -ENOMEM;
29102e19f9c7cacfb33d7b2f5cace7972fa60f92319Stefano Stabellini	}
29202e19f9c7cacfb33d7b2f5cace7972fa60f92319Stefano Stabellini
29302e19f9c7cacfb33d7b2f5cace7972fa60f92319Stefano Stabellini	info->irq = bind_virq_to_irq(VIRQ_CONSOLE, 0);
29402e19f9c7cacfb33d7b2f5cace7972fa60f92319Stefano Stabellini	info->vtermno = HVC_COOKIE;
29502e19f9c7cacfb33d7b2f5cace7972fa60f92319Stefano Stabellini
29602e19f9c7cacfb33d7b2f5cace7972fa60f92319Stefano Stabellini	spin_lock(&xencons_lock);
29702e19f9c7cacfb33d7b2f5cace7972fa60f92319Stefano Stabellini	list_add_tail(&info->list, &xenconsoles);
29802e19f9c7cacfb33d7b2f5cace7972fa60f92319Stefano Stabellini	spin_unlock(&xencons_lock);
299eb5ef07151ba3c3cb4bcef0c8f146ff1115eaa55Stefano Stabellini
300eb5ef07151ba3c3cb4bcef0c8f146ff1115eaa55Stefano Stabellini	return 0;
301eb5ef07151ba3c3cb4bcef0c8f146ff1115eaa55Stefano Stabellini}
302eb5ef07151ba3c3cb4bcef0c8f146ff1115eaa55Stefano Stabellini
30302e19f9c7cacfb33d7b2f5cace7972fa60f92319Stefano Stabellinivoid xen_console_resume(void)
30402e19f9c7cacfb33d7b2f5cace7972fa60f92319Stefano Stabellini{
30502e19f9c7cacfb33d7b2f5cace7972fa60f92319Stefano Stabellini	struct xencons_info *info = vtermno_to_xencons(HVC_COOKIE);
30602e19f9c7cacfb33d7b2f5cace7972fa60f92319Stefano Stabellini	if (info != NULL && info->irq)
30702e19f9c7cacfb33d7b2f5cace7972fa60f92319Stefano Stabellini		rebind_evtchn_irq(info->evtchn, info->irq);
30802e19f9c7cacfb33d7b2f5cace7972fa60f92319Stefano Stabellini}
30902e19f9c7cacfb33d7b2f5cace7972fa60f92319Stefano Stabellini
31002e19f9c7cacfb33d7b2f5cace7972fa60f92319Stefano Stabellinistatic void xencons_disconnect_backend(struct xencons_info *info)
31102e19f9c7cacfb33d7b2f5cace7972fa60f92319Stefano Stabellini{
31202e19f9c7cacfb33d7b2f5cace7972fa60f92319Stefano Stabellini	if (info->irq > 0)
31302e19f9c7cacfb33d7b2f5cace7972fa60f92319Stefano Stabellini		unbind_from_irqhandler(info->irq, NULL);
31402e19f9c7cacfb33d7b2f5cace7972fa60f92319Stefano Stabellini	info->irq = 0;
31502e19f9c7cacfb33d7b2f5cace7972fa60f92319Stefano Stabellini	if (info->evtchn > 0)
31602e19f9c7cacfb33d7b2f5cace7972fa60f92319Stefano Stabellini		xenbus_free_evtchn(info->xbdev, info->evtchn);
31702e19f9c7cacfb33d7b2f5cace7972fa60f92319Stefano Stabellini	info->evtchn = 0;
31802e19f9c7cacfb33d7b2f5cace7972fa60f92319Stefano Stabellini	if (info->gntref > 0)
31902e19f9c7cacfb33d7b2f5cace7972fa60f92319Stefano Stabellini		gnttab_free_grant_references(info->gntref);
32002e19f9c7cacfb33d7b2f5cace7972fa60f92319Stefano Stabellini	info->gntref = 0;
32102e19f9c7cacfb33d7b2f5cace7972fa60f92319Stefano Stabellini	if (info->hvc != NULL)
32202e19f9c7cacfb33d7b2f5cace7972fa60f92319Stefano Stabellini		hvc_remove(info->hvc);
32302e19f9c7cacfb33d7b2f5cace7972fa60f92319Stefano Stabellini	info->hvc = NULL;
32402e19f9c7cacfb33d7b2f5cace7972fa60f92319Stefano Stabellini}
32502e19f9c7cacfb33d7b2f5cace7972fa60f92319Stefano Stabellini
32602e19f9c7cacfb33d7b2f5cace7972fa60f92319Stefano Stabellinistatic void xencons_free(struct xencons_info *info)
32702e19f9c7cacfb33d7b2f5cace7972fa60f92319Stefano Stabellini{
32802e19f9c7cacfb33d7b2f5cace7972fa60f92319Stefano Stabellini	free_page((unsigned long)info->intf);
32902e19f9c7cacfb33d7b2f5cace7972fa60f92319Stefano Stabellini	info->intf = NULL;
33002e19f9c7cacfb33d7b2f5cace7972fa60f92319Stefano Stabellini	info->vtermno = 0;
33102e19f9c7cacfb33d7b2f5cace7972fa60f92319Stefano Stabellini	kfree(info);
33202e19f9c7cacfb33d7b2f5cace7972fa60f92319Stefano Stabellini}
33302e19f9c7cacfb33d7b2f5cace7972fa60f92319Stefano Stabellini
33402e19f9c7cacfb33d7b2f5cace7972fa60f92319Stefano Stabellinistatic int xen_console_remove(struct xencons_info *info)
33502e19f9c7cacfb33d7b2f5cace7972fa60f92319Stefano Stabellini{
33602e19f9c7cacfb33d7b2f5cace7972fa60f92319Stefano Stabellini	xencons_disconnect_backend(info);
33702e19f9c7cacfb33d7b2f5cace7972fa60f92319Stefano Stabellini	spin_lock(&xencons_lock);
33802e19f9c7cacfb33d7b2f5cace7972fa60f92319Stefano Stabellini	list_del(&info->list);
33902e19f9c7cacfb33d7b2f5cace7972fa60f92319Stefano Stabellini	spin_unlock(&xencons_lock);
34002e19f9c7cacfb33d7b2f5cace7972fa60f92319Stefano Stabellini	if (info->xbdev != NULL)
34102e19f9c7cacfb33d7b2f5cace7972fa60f92319Stefano Stabellini		xencons_free(info);
34202e19f9c7cacfb33d7b2f5cace7972fa60f92319Stefano Stabellini	else {
34302e19f9c7cacfb33d7b2f5cace7972fa60f92319Stefano Stabellini		if (xen_hvm_domain())
34402e19f9c7cacfb33d7b2f5cace7972fa60f92319Stefano Stabellini			iounmap(info->intf);
34502e19f9c7cacfb33d7b2f5cace7972fa60f92319Stefano Stabellini		kfree(info);
3464fe7d5a708a955b35e3fdc4dea3e0b7a6ae2eb06Jeremy Fitzhardinge	}
34702e19f9c7cacfb33d7b2f5cace7972fa60f92319Stefano Stabellini	return 0;
34802e19f9c7cacfb33d7b2f5cace7972fa60f92319Stefano Stabellini}
3496b9b732d0e396a3f1a95977162a8624aafce38a1Jeremy Fitzhardinge
350cf8e019b523a8caa95b56ff0ce62a4856b14395fStefano Stabellini#ifdef CONFIG_HVC_XEN_FRONTEND
351cf8e019b523a8caa95b56ff0ce62a4856b14395fStefano Stabellinistatic struct xenbus_driver xencons_driver;
352cf8e019b523a8caa95b56ff0ce62a4856b14395fStefano Stabellini
35302e19f9c7cacfb33d7b2f5cace7972fa60f92319Stefano Stabellinistatic int xencons_remove(struct xenbus_device *dev)
35402e19f9c7cacfb33d7b2f5cace7972fa60f92319Stefano Stabellini{
35502e19f9c7cacfb33d7b2f5cace7972fa60f92319Stefano Stabellini	return xen_console_remove(dev_get_drvdata(&dev->dev));
35602e19f9c7cacfb33d7b2f5cace7972fa60f92319Stefano Stabellini}
357b536b4b9623084d86f2b1f19cb44a2d6d74f00bfJeremy Fitzhardinge
35802e19f9c7cacfb33d7b2f5cace7972fa60f92319Stefano Stabellinistatic int xencons_connect_backend(struct xenbus_device *dev,
35902e19f9c7cacfb33d7b2f5cace7972fa60f92319Stefano Stabellini				  struct xencons_info *info)
36002e19f9c7cacfb33d7b2f5cace7972fa60f92319Stefano Stabellini{
36102e19f9c7cacfb33d7b2f5cace7972fa60f92319Stefano Stabellini	int ret, evtchn, devid, ref, irq;
36202e19f9c7cacfb33d7b2f5cace7972fa60f92319Stefano Stabellini	struct xenbus_transaction xbt;
36302e19f9c7cacfb33d7b2f5cace7972fa60f92319Stefano Stabellini	grant_ref_t gref_head;
36402e19f9c7cacfb33d7b2f5cace7972fa60f92319Stefano Stabellini	unsigned long mfn;
36502e19f9c7cacfb33d7b2f5cace7972fa60f92319Stefano Stabellini
36602e19f9c7cacfb33d7b2f5cace7972fa60f92319Stefano Stabellini	ret = xenbus_alloc_evtchn(dev, &evtchn);
36702e19f9c7cacfb33d7b2f5cace7972fa60f92319Stefano Stabellini	if (ret)
36802e19f9c7cacfb33d7b2f5cace7972fa60f92319Stefano Stabellini		return ret;
36902e19f9c7cacfb33d7b2f5cace7972fa60f92319Stefano Stabellini	info->evtchn = evtchn;
37002e19f9c7cacfb33d7b2f5cace7972fa60f92319Stefano Stabellini	irq = bind_evtchn_to_irq(evtchn);
37102e19f9c7cacfb33d7b2f5cace7972fa60f92319Stefano Stabellini	if (irq < 0)
37202e19f9c7cacfb33d7b2f5cace7972fa60f92319Stefano Stabellini		return irq;
37302e19f9c7cacfb33d7b2f5cace7972fa60f92319Stefano Stabellini	info->irq = irq;
37402e19f9c7cacfb33d7b2f5cace7972fa60f92319Stefano Stabellini	devid = dev->nodename[strlen(dev->nodename) - 1] - '0';
37502e19f9c7cacfb33d7b2f5cace7972fa60f92319Stefano Stabellini	info->hvc = hvc_alloc(xenbus_devid_to_vtermno(devid),
37602e19f9c7cacfb33d7b2f5cace7972fa60f92319Stefano Stabellini			irq, &domU_hvc_ops, 256);
37702e19f9c7cacfb33d7b2f5cace7972fa60f92319Stefano Stabellini	if (IS_ERR(info->hvc))
37802e19f9c7cacfb33d7b2f5cace7972fa60f92319Stefano Stabellini		return PTR_ERR(info->hvc);
37902e19f9c7cacfb33d7b2f5cace7972fa60f92319Stefano Stabellini	if (xen_pv_domain())
38002e19f9c7cacfb33d7b2f5cace7972fa60f92319Stefano Stabellini		mfn = virt_to_mfn(info->intf);
38102e19f9c7cacfb33d7b2f5cace7972fa60f92319Stefano Stabellini	else
38202e19f9c7cacfb33d7b2f5cace7972fa60f92319Stefano Stabellini		mfn = __pa(info->intf) >> PAGE_SHIFT;
38302e19f9c7cacfb33d7b2f5cace7972fa60f92319Stefano Stabellini	ret = gnttab_alloc_grant_references(1, &gref_head);
38402e19f9c7cacfb33d7b2f5cace7972fa60f92319Stefano Stabellini	if (ret < 0)
38502e19f9c7cacfb33d7b2f5cace7972fa60f92319Stefano Stabellini		return ret;
38602e19f9c7cacfb33d7b2f5cace7972fa60f92319Stefano Stabellini	info->gntref = gref_head;
38702e19f9c7cacfb33d7b2f5cace7972fa60f92319Stefano Stabellini	ref = gnttab_claim_grant_reference(&gref_head);
38802e19f9c7cacfb33d7b2f5cace7972fa60f92319Stefano Stabellini	if (ref < 0)
38902e19f9c7cacfb33d7b2f5cace7972fa60f92319Stefano Stabellini		return ref;
39002e19f9c7cacfb33d7b2f5cace7972fa60f92319Stefano Stabellini	gnttab_grant_foreign_access_ref(ref, info->xbdev->otherend_id,
39102e19f9c7cacfb33d7b2f5cace7972fa60f92319Stefano Stabellini			mfn, 0);
39202e19f9c7cacfb33d7b2f5cace7972fa60f92319Stefano Stabellini
39302e19f9c7cacfb33d7b2f5cace7972fa60f92319Stefano Stabellini again:
39402e19f9c7cacfb33d7b2f5cace7972fa60f92319Stefano Stabellini	ret = xenbus_transaction_start(&xbt);
39502e19f9c7cacfb33d7b2f5cace7972fa60f92319Stefano Stabellini	if (ret) {
39602e19f9c7cacfb33d7b2f5cace7972fa60f92319Stefano Stabellini		xenbus_dev_fatal(dev, ret, "starting transaction");
39702e19f9c7cacfb33d7b2f5cace7972fa60f92319Stefano Stabellini		return ret;
39802e19f9c7cacfb33d7b2f5cace7972fa60f92319Stefano Stabellini	}
39902e19f9c7cacfb33d7b2f5cace7972fa60f92319Stefano Stabellini	ret = xenbus_printf(xbt, dev->nodename, "ring-ref", "%d", ref);
40002e19f9c7cacfb33d7b2f5cace7972fa60f92319Stefano Stabellini	if (ret)
40102e19f9c7cacfb33d7b2f5cace7972fa60f92319Stefano Stabellini		goto error_xenbus;
40202e19f9c7cacfb33d7b2f5cace7972fa60f92319Stefano Stabellini	ret = xenbus_printf(xbt, dev->nodename, "port", "%u",
40302e19f9c7cacfb33d7b2f5cace7972fa60f92319Stefano Stabellini			    evtchn);
40402e19f9c7cacfb33d7b2f5cace7972fa60f92319Stefano Stabellini	if (ret)
40502e19f9c7cacfb33d7b2f5cace7972fa60f92319Stefano Stabellini		goto error_xenbus;
40602e19f9c7cacfb33d7b2f5cace7972fa60f92319Stefano Stabellini	ret = xenbus_printf(xbt, dev->nodename, "type", "ioemu");
40702e19f9c7cacfb33d7b2f5cace7972fa60f92319Stefano Stabellini	if (ret)
40802e19f9c7cacfb33d7b2f5cace7972fa60f92319Stefano Stabellini		goto error_xenbus;
40902e19f9c7cacfb33d7b2f5cace7972fa60f92319Stefano Stabellini	ret = xenbus_transaction_end(xbt, 0);
41002e19f9c7cacfb33d7b2f5cace7972fa60f92319Stefano Stabellini	if (ret) {
41102e19f9c7cacfb33d7b2f5cace7972fa60f92319Stefano Stabellini		if (ret == -EAGAIN)
41202e19f9c7cacfb33d7b2f5cace7972fa60f92319Stefano Stabellini			goto again;
41302e19f9c7cacfb33d7b2f5cace7972fa60f92319Stefano Stabellini		xenbus_dev_fatal(dev, ret, "completing transaction");
41402e19f9c7cacfb33d7b2f5cace7972fa60f92319Stefano Stabellini		return ret;
41502e19f9c7cacfb33d7b2f5cace7972fa60f92319Stefano Stabellini	}
4166b9b732d0e396a3f1a95977162a8624aafce38a1Jeremy Fitzhardinge
41702e19f9c7cacfb33d7b2f5cace7972fa60f92319Stefano Stabellini	xenbus_switch_state(dev, XenbusStateInitialised);
418b536b4b9623084d86f2b1f19cb44a2d6d74f00bfJeremy Fitzhardinge	return 0;
41902e19f9c7cacfb33d7b2f5cace7972fa60f92319Stefano Stabellini
42002e19f9c7cacfb33d7b2f5cace7972fa60f92319Stefano Stabellini error_xenbus:
42102e19f9c7cacfb33d7b2f5cace7972fa60f92319Stefano Stabellini	xenbus_transaction_end(xbt, 1);
42202e19f9c7cacfb33d7b2f5cace7972fa60f92319Stefano Stabellini	xenbus_dev_fatal(dev, ret, "writing xenstore");
42302e19f9c7cacfb33d7b2f5cace7972fa60f92319Stefano Stabellini	return ret;
424b536b4b9623084d86f2b1f19cb44a2d6d74f00bfJeremy Fitzhardinge}
425b536b4b9623084d86f2b1f19cb44a2d6d74f00bfJeremy Fitzhardinge
42602e19f9c7cacfb33d7b2f5cace7972fa60f92319Stefano Stabellinistatic int __devinit xencons_probe(struct xenbus_device *dev,
42702e19f9c7cacfb33d7b2f5cace7972fa60f92319Stefano Stabellini				  const struct xenbus_device_id *id)
4286b9b732d0e396a3f1a95977162a8624aafce38a1Jeremy Fitzhardinge{
42902e19f9c7cacfb33d7b2f5cace7972fa60f92319Stefano Stabellini	int ret, devid;
43002e19f9c7cacfb33d7b2f5cace7972fa60f92319Stefano Stabellini	struct xencons_info *info;
43102e19f9c7cacfb33d7b2f5cace7972fa60f92319Stefano Stabellini
43202e19f9c7cacfb33d7b2f5cace7972fa60f92319Stefano Stabellini	devid = dev->nodename[strlen(dev->nodename) - 1] - '0';
43302e19f9c7cacfb33d7b2f5cace7972fa60f92319Stefano Stabellini	if (devid == 0)
43402e19f9c7cacfb33d7b2f5cace7972fa60f92319Stefano Stabellini		return -ENODEV;
43502e19f9c7cacfb33d7b2f5cace7972fa60f92319Stefano Stabellini
436284e7be895509cdaf9f58e2f789c00b5e9da2244Dan Carpenter	info = kzalloc(sizeof(struct xencons_info), GFP_KERNEL);
43702e19f9c7cacfb33d7b2f5cace7972fa60f92319Stefano Stabellini	if (!info)
438284e7be895509cdaf9f58e2f789c00b5e9da2244Dan Carpenter		return -ENOMEM;
43902e19f9c7cacfb33d7b2f5cace7972fa60f92319Stefano Stabellini	dev_set_drvdata(&dev->dev, info);
44002e19f9c7cacfb33d7b2f5cace7972fa60f92319Stefano Stabellini	info->xbdev = dev;
44102e19f9c7cacfb33d7b2f5cace7972fa60f92319Stefano Stabellini	info->vtermno = xenbus_devid_to_vtermno(devid);
44202e19f9c7cacfb33d7b2f5cace7972fa60f92319Stefano Stabellini	info->intf = (void *)__get_free_page(GFP_KERNEL | __GFP_ZERO);
44302e19f9c7cacfb33d7b2f5cace7972fa60f92319Stefano Stabellini	if (!info->intf)
44402e19f9c7cacfb33d7b2f5cace7972fa60f92319Stefano Stabellini		goto error_nomem;
44502e19f9c7cacfb33d7b2f5cace7972fa60f92319Stefano Stabellini
44602e19f9c7cacfb33d7b2f5cace7972fa60f92319Stefano Stabellini	ret = xencons_connect_backend(dev, info);
44702e19f9c7cacfb33d7b2f5cace7972fa60f92319Stefano Stabellini	if (ret < 0)
44802e19f9c7cacfb33d7b2f5cace7972fa60f92319Stefano Stabellini		goto error;
44902e19f9c7cacfb33d7b2f5cace7972fa60f92319Stefano Stabellini	spin_lock(&xencons_lock);
45002e19f9c7cacfb33d7b2f5cace7972fa60f92319Stefano Stabellini	list_add_tail(&info->list, &xenconsoles);
45102e19f9c7cacfb33d7b2f5cace7972fa60f92319Stefano Stabellini	spin_unlock(&xencons_lock);
45202e19f9c7cacfb33d7b2f5cace7972fa60f92319Stefano Stabellini
45302e19f9c7cacfb33d7b2f5cace7972fa60f92319Stefano Stabellini	return 0;
45402e19f9c7cacfb33d7b2f5cace7972fa60f92319Stefano Stabellini
45502e19f9c7cacfb33d7b2f5cace7972fa60f92319Stefano Stabellini error_nomem:
45602e19f9c7cacfb33d7b2f5cace7972fa60f92319Stefano Stabellini	ret = -ENOMEM;
45702e19f9c7cacfb33d7b2f5cace7972fa60f92319Stefano Stabellini	xenbus_dev_fatal(dev, ret, "allocating device memory");
45802e19f9c7cacfb33d7b2f5cace7972fa60f92319Stefano Stabellini error:
45902e19f9c7cacfb33d7b2f5cace7972fa60f92319Stefano Stabellini	xencons_disconnect_backend(info);
46002e19f9c7cacfb33d7b2f5cace7972fa60f92319Stefano Stabellini	xencons_free(info);
46102e19f9c7cacfb33d7b2f5cace7972fa60f92319Stefano Stabellini	return ret;
46202e19f9c7cacfb33d7b2f5cace7972fa60f92319Stefano Stabellini}
46302e19f9c7cacfb33d7b2f5cace7972fa60f92319Stefano Stabellini
46402e19f9c7cacfb33d7b2f5cace7972fa60f92319Stefano Stabellinistatic int xencons_resume(struct xenbus_device *dev)
46502e19f9c7cacfb33d7b2f5cace7972fa60f92319Stefano Stabellini{
46602e19f9c7cacfb33d7b2f5cace7972fa60f92319Stefano Stabellini	struct xencons_info *info = dev_get_drvdata(&dev->dev);
46702e19f9c7cacfb33d7b2f5cace7972fa60f92319Stefano Stabellini
46802e19f9c7cacfb33d7b2f5cace7972fa60f92319Stefano Stabellini	xencons_disconnect_backend(info);
46902e19f9c7cacfb33d7b2f5cace7972fa60f92319Stefano Stabellini	memset(info->intf, 0, PAGE_SIZE);
47002e19f9c7cacfb33d7b2f5cace7972fa60f92319Stefano Stabellini	return xencons_connect_backend(dev, info);
4716b9b732d0e396a3f1a95977162a8624aafce38a1Jeremy Fitzhardinge}
4726b9b732d0e396a3f1a95977162a8624aafce38a1Jeremy Fitzhardinge
47302e19f9c7cacfb33d7b2f5cace7972fa60f92319Stefano Stabellinistatic void xencons_backend_changed(struct xenbus_device *dev,
47402e19f9c7cacfb33d7b2f5cace7972fa60f92319Stefano Stabellini				   enum xenbus_state backend_state)
47502e19f9c7cacfb33d7b2f5cace7972fa60f92319Stefano Stabellini{
47602e19f9c7cacfb33d7b2f5cace7972fa60f92319Stefano Stabellini	switch (backend_state) {
47702e19f9c7cacfb33d7b2f5cace7972fa60f92319Stefano Stabellini	case XenbusStateReconfiguring:
47802e19f9c7cacfb33d7b2f5cace7972fa60f92319Stefano Stabellini	case XenbusStateReconfigured:
47902e19f9c7cacfb33d7b2f5cace7972fa60f92319Stefano Stabellini	case XenbusStateInitialising:
48002e19f9c7cacfb33d7b2f5cace7972fa60f92319Stefano Stabellini	case XenbusStateInitialised:
48102e19f9c7cacfb33d7b2f5cace7972fa60f92319Stefano Stabellini	case XenbusStateUnknown:
48202e19f9c7cacfb33d7b2f5cace7972fa60f92319Stefano Stabellini	case XenbusStateClosed:
48302e19f9c7cacfb33d7b2f5cace7972fa60f92319Stefano Stabellini		break;
48402e19f9c7cacfb33d7b2f5cace7972fa60f92319Stefano Stabellini
48502e19f9c7cacfb33d7b2f5cace7972fa60f92319Stefano Stabellini	case XenbusStateInitWait:
48602e19f9c7cacfb33d7b2f5cace7972fa60f92319Stefano Stabellini		break;
48702e19f9c7cacfb33d7b2f5cace7972fa60f92319Stefano Stabellini
48802e19f9c7cacfb33d7b2f5cace7972fa60f92319Stefano Stabellini	case XenbusStateConnected:
48902e19f9c7cacfb33d7b2f5cace7972fa60f92319Stefano Stabellini		xenbus_switch_state(dev, XenbusStateConnected);
49002e19f9c7cacfb33d7b2f5cace7972fa60f92319Stefano Stabellini		break;
49102e19f9c7cacfb33d7b2f5cace7972fa60f92319Stefano Stabellini
49202e19f9c7cacfb33d7b2f5cace7972fa60f92319Stefano Stabellini	case XenbusStateClosing:
49302e19f9c7cacfb33d7b2f5cace7972fa60f92319Stefano Stabellini		xenbus_frontend_closed(dev);
49402e19f9c7cacfb33d7b2f5cace7972fa60f92319Stefano Stabellini		break;
49502e19f9c7cacfb33d7b2f5cace7972fa60f92319Stefano Stabellini	}
49602e19f9c7cacfb33d7b2f5cace7972fa60f92319Stefano Stabellini}
49702e19f9c7cacfb33d7b2f5cace7972fa60f92319Stefano Stabellini
49802e19f9c7cacfb33d7b2f5cace7972fa60f92319Stefano Stabellinistatic const struct xenbus_device_id xencons_ids[] = {
49902e19f9c7cacfb33d7b2f5cace7972fa60f92319Stefano Stabellini	{ "console" },
50002e19f9c7cacfb33d7b2f5cace7972fa60f92319Stefano Stabellini	{ "" }
50102e19f9c7cacfb33d7b2f5cace7972fa60f92319Stefano Stabellini};
50202e19f9c7cacfb33d7b2f5cace7972fa60f92319Stefano Stabellini
50302e19f9c7cacfb33d7b2f5cace7972fa60f92319Stefano Stabellini
504cf8e019b523a8caa95b56ff0ce62a4856b14395fStefano Stabellinistatic DEFINE_XENBUS_DRIVER(xencons, "xenconsole",
505cf8e019b523a8caa95b56ff0ce62a4856b14395fStefano Stabellini	.probe = xencons_probe,
506cf8e019b523a8caa95b56ff0ce62a4856b14395fStefano Stabellini	.remove = xencons_remove,
507cf8e019b523a8caa95b56ff0ce62a4856b14395fStefano Stabellini	.resume = xencons_resume,
508cf8e019b523a8caa95b56ff0ce62a4856b14395fStefano Stabellini	.otherend_changed = xencons_backend_changed,
509cf8e019b523a8caa95b56ff0ce62a4856b14395fStefano Stabellini);
510cf8e019b523a8caa95b56ff0ce62a4856b14395fStefano Stabellini#endif /* CONFIG_HVC_XEN_FRONTEND */
511cf8e019b523a8caa95b56ff0ce62a4856b14395fStefano Stabellini
512cf8e019b523a8caa95b56ff0ce62a4856b14395fStefano Stabellinistatic int __init xen_hvc_init(void)
513cf8e019b523a8caa95b56ff0ce62a4856b14395fStefano Stabellini{
514cf8e019b523a8caa95b56ff0ce62a4856b14395fStefano Stabellini	int r;
515cf8e019b523a8caa95b56ff0ce62a4856b14395fStefano Stabellini	struct xencons_info *info;
516cf8e019b523a8caa95b56ff0ce62a4856b14395fStefano Stabellini	const struct hv_ops *ops;
517cf8e019b523a8caa95b56ff0ce62a4856b14395fStefano Stabellini
518cf8e019b523a8caa95b56ff0ce62a4856b14395fStefano Stabellini	if (!xen_domain())
519cf8e019b523a8caa95b56ff0ce62a4856b14395fStefano Stabellini		return -ENODEV;
520cf8e019b523a8caa95b56ff0ce62a4856b14395fStefano Stabellini
521cf8e019b523a8caa95b56ff0ce62a4856b14395fStefano Stabellini	if (xen_initial_domain()) {
522cf8e019b523a8caa95b56ff0ce62a4856b14395fStefano Stabellini		ops = &dom0_hvc_ops;
523cf8e019b523a8caa95b56ff0ce62a4856b14395fStefano Stabellini		r = xen_initial_domain_console_init();
524cf8e019b523a8caa95b56ff0ce62a4856b14395fStefano Stabellini		if (r < 0)
525cf8e019b523a8caa95b56ff0ce62a4856b14395fStefano Stabellini			return r;
526cf8e019b523a8caa95b56ff0ce62a4856b14395fStefano Stabellini		info = vtermno_to_xencons(HVC_COOKIE);
527cf8e019b523a8caa95b56ff0ce62a4856b14395fStefano Stabellini	} else {
528cf8e019b523a8caa95b56ff0ce62a4856b14395fStefano Stabellini		ops = &domU_hvc_ops;
529cf8e019b523a8caa95b56ff0ce62a4856b14395fStefano Stabellini		if (xen_hvm_domain())
530cf8e019b523a8caa95b56ff0ce62a4856b14395fStefano Stabellini			r = xen_hvm_console_init();
531cf8e019b523a8caa95b56ff0ce62a4856b14395fStefano Stabellini		else
532cf8e019b523a8caa95b56ff0ce62a4856b14395fStefano Stabellini			r = xen_pv_console_init();
533cf8e019b523a8caa95b56ff0ce62a4856b14395fStefano Stabellini		if (r < 0)
534cf8e019b523a8caa95b56ff0ce62a4856b14395fStefano Stabellini			return r;
535cf8e019b523a8caa95b56ff0ce62a4856b14395fStefano Stabellini
536cf8e019b523a8caa95b56ff0ce62a4856b14395fStefano Stabellini		info = vtermno_to_xencons(HVC_COOKIE);
537cf8e019b523a8caa95b56ff0ce62a4856b14395fStefano Stabellini		info->irq = bind_evtchn_to_irq(info->evtchn);
538cf8e019b523a8caa95b56ff0ce62a4856b14395fStefano Stabellini	}
539cf8e019b523a8caa95b56ff0ce62a4856b14395fStefano Stabellini	if (info->irq < 0)
540cf8e019b523a8caa95b56ff0ce62a4856b14395fStefano Stabellini		info->irq = 0; /* NO_IRQ */
541cf8e019b523a8caa95b56ff0ce62a4856b14395fStefano Stabellini	else
542cf8e019b523a8caa95b56ff0ce62a4856b14395fStefano Stabellini		irq_set_noprobe(info->irq);
543cf8e019b523a8caa95b56ff0ce62a4856b14395fStefano Stabellini
544cf8e019b523a8caa95b56ff0ce62a4856b14395fStefano Stabellini	info->hvc = hvc_alloc(HVC_COOKIE, info->irq, ops, 256);
545cf8e019b523a8caa95b56ff0ce62a4856b14395fStefano Stabellini	if (IS_ERR(info->hvc)) {
546cf8e019b523a8caa95b56ff0ce62a4856b14395fStefano Stabellini		r = PTR_ERR(info->hvc);
547cf8e019b523a8caa95b56ff0ce62a4856b14395fStefano Stabellini		spin_lock(&xencons_lock);
548cf8e019b523a8caa95b56ff0ce62a4856b14395fStefano Stabellini		list_del(&info->list);
549cf8e019b523a8caa95b56ff0ce62a4856b14395fStefano Stabellini		spin_unlock(&xencons_lock);
550cf8e019b523a8caa95b56ff0ce62a4856b14395fStefano Stabellini		if (info->irq)
551cf8e019b523a8caa95b56ff0ce62a4856b14395fStefano Stabellini			unbind_from_irqhandler(info->irq, NULL);
552cf8e019b523a8caa95b56ff0ce62a4856b14395fStefano Stabellini		kfree(info);
553cf8e019b523a8caa95b56ff0ce62a4856b14395fStefano Stabellini		return r;
554cf8e019b523a8caa95b56ff0ce62a4856b14395fStefano Stabellini	}
555cf8e019b523a8caa95b56ff0ce62a4856b14395fStefano Stabellini
556cf8e019b523a8caa95b56ff0ce62a4856b14395fStefano Stabellini	r = 0;
557cf8e019b523a8caa95b56ff0ce62a4856b14395fStefano Stabellini#ifdef CONFIG_HVC_XEN_FRONTEND
558cf8e019b523a8caa95b56ff0ce62a4856b14395fStefano Stabellini	r = xenbus_register_frontend(&xencons_driver);
559cf8e019b523a8caa95b56ff0ce62a4856b14395fStefano Stabellini#endif
560cf8e019b523a8caa95b56ff0ce62a4856b14395fStefano Stabellini	return r;
561cf8e019b523a8caa95b56ff0ce62a4856b14395fStefano Stabellini}
562cf8e019b523a8caa95b56ff0ce62a4856b14395fStefano Stabellini
5634fe7d5a708a955b35e3fdc4dea3e0b7a6ae2eb06Jeremy Fitzhardingestatic void __exit xen_hvc_fini(void)
564b536b4b9623084d86f2b1f19cb44a2d6d74f00bfJeremy Fitzhardinge{
56502e19f9c7cacfb33d7b2f5cace7972fa60f92319Stefano Stabellini	struct xencons_info *entry, *next;
56602e19f9c7cacfb33d7b2f5cace7972fa60f92319Stefano Stabellini
56702e19f9c7cacfb33d7b2f5cace7972fa60f92319Stefano Stabellini	if (list_empty(&xenconsoles))
56802e19f9c7cacfb33d7b2f5cace7972fa60f92319Stefano Stabellini			return;
56902e19f9c7cacfb33d7b2f5cace7972fa60f92319Stefano Stabellini
57002e19f9c7cacfb33d7b2f5cace7972fa60f92319Stefano Stabellini	list_for_each_entry_safe(entry, next, &xenconsoles, list) {
57102e19f9c7cacfb33d7b2f5cace7972fa60f92319Stefano Stabellini		xen_console_remove(entry);
57202e19f9c7cacfb33d7b2f5cace7972fa60f92319Stefano Stabellini	}
573b536b4b9623084d86f2b1f19cb44a2d6d74f00bfJeremy Fitzhardinge}
574b536b4b9623084d86f2b1f19cb44a2d6d74f00bfJeremy Fitzhardinge
575b536b4b9623084d86f2b1f19cb44a2d6d74f00bfJeremy Fitzhardingestatic int xen_cons_init(void)
576b536b4b9623084d86f2b1f19cb44a2d6d74f00bfJeremy Fitzhardinge{
577eb5ef07151ba3c3cb4bcef0c8f146ff1115eaa55Stefano Stabellini	const struct hv_ops *ops;
5784fe7d5a708a955b35e3fdc4dea3e0b7a6ae2eb06Jeremy Fitzhardinge
579eb5ef07151ba3c3cb4bcef0c8f146ff1115eaa55Stefano Stabellini	if (!xen_domain())
580b536b4b9623084d86f2b1f19cb44a2d6d74f00bfJeremy Fitzhardinge		return 0;
581b536b4b9623084d86f2b1f19cb44a2d6d74f00bfJeremy Fitzhardinge
5824fe7d5a708a955b35e3fdc4dea3e0b7a6ae2eb06Jeremy Fitzhardinge	if (xen_initial_domain())
5834fe7d5a708a955b35e3fdc4dea3e0b7a6ae2eb06Jeremy Fitzhardinge		ops = &dom0_hvc_ops;
584eb5ef07151ba3c3cb4bcef0c8f146ff1115eaa55Stefano Stabellini	else {
58502e19f9c7cacfb33d7b2f5cace7972fa60f92319Stefano Stabellini		int r;
5864fe7d5a708a955b35e3fdc4dea3e0b7a6ae2eb06Jeremy Fitzhardinge		ops = &domU_hvc_ops;
5874fe7d5a708a955b35e3fdc4dea3e0b7a6ae2eb06Jeremy Fitzhardinge
58802e19f9c7cacfb33d7b2f5cace7972fa60f92319Stefano Stabellini		if (xen_hvm_domain())
58902e19f9c7cacfb33d7b2f5cace7972fa60f92319Stefano Stabellini			r = xen_hvm_console_init();
590eb5ef07151ba3c3cb4bcef0c8f146ff1115eaa55Stefano Stabellini		else
59102e19f9c7cacfb33d7b2f5cace7972fa60f92319Stefano Stabellini			r = xen_pv_console_init();
59202e19f9c7cacfb33d7b2f5cace7972fa60f92319Stefano Stabellini		if (r < 0)
59302e19f9c7cacfb33d7b2f5cace7972fa60f92319Stefano Stabellini			return r;
594eb5ef07151ba3c3cb4bcef0c8f146ff1115eaa55Stefano Stabellini	}
595eb5ef07151ba3c3cb4bcef0c8f146ff1115eaa55Stefano Stabellini
5964fe7d5a708a955b35e3fdc4dea3e0b7a6ae2eb06Jeremy Fitzhardinge	hvc_instantiate(HVC_COOKIE, 0, ops);
597b536b4b9623084d86f2b1f19cb44a2d6d74f00bfJeremy Fitzhardinge	return 0;
598b536b4b9623084d86f2b1f19cb44a2d6d74f00bfJeremy Fitzhardinge}
599b536b4b9623084d86f2b1f19cb44a2d6d74f00bfJeremy Fitzhardinge
60002e19f9c7cacfb33d7b2f5cace7972fa60f92319Stefano Stabellini
6014fe7d5a708a955b35e3fdc4dea3e0b7a6ae2eb06Jeremy Fitzhardingemodule_init(xen_hvc_init);
6024fe7d5a708a955b35e3fdc4dea3e0b7a6ae2eb06Jeremy Fitzhardingemodule_exit(xen_hvc_fini);
603b536b4b9623084d86f2b1f19cb44a2d6d74f00bfJeremy Fitzhardingeconsole_initcall(xen_cons_init);
604b536b4b9623084d86f2b1f19cb44a2d6d74f00bfJeremy Fitzhardinge
6050922abdc3982ae54cbe1b24ac5aa91a260eca1bbJeremy Fitzhardinge#ifdef CONFIG_EARLY_PRINTK
606b536b4b9623084d86f2b1f19cb44a2d6d74f00bfJeremy Fitzhardingestatic void xenboot_write_console(struct console *console, const char *string,
607b536b4b9623084d86f2b1f19cb44a2d6d74f00bfJeremy Fitzhardinge				  unsigned len)
608b536b4b9623084d86f2b1f19cb44a2d6d74f00bfJeremy Fitzhardinge{
609b536b4b9623084d86f2b1f19cb44a2d6d74f00bfJeremy Fitzhardinge	unsigned int linelen, off = 0;
610b536b4b9623084d86f2b1f19cb44a2d6d74f00bfJeremy Fitzhardinge	const char *pos;
611b536b4b9623084d86f2b1f19cb44a2d6d74f00bfJeremy Fitzhardinge
612eb5ef07151ba3c3cb4bcef0c8f146ff1115eaa55Stefano Stabellini	if (!xen_pv_domain())
613eb5ef07151ba3c3cb4bcef0c8f146ff1115eaa55Stefano Stabellini		return;
614eb5ef07151ba3c3cb4bcef0c8f146ff1115eaa55Stefano Stabellini
6154fe7d5a708a955b35e3fdc4dea3e0b7a6ae2eb06Jeremy Fitzhardinge	dom0_write_console(0, string, len);
6164fe7d5a708a955b35e3fdc4dea3e0b7a6ae2eb06Jeremy Fitzhardinge
6174fe7d5a708a955b35e3fdc4dea3e0b7a6ae2eb06Jeremy Fitzhardinge	if (xen_initial_domain())
6184fe7d5a708a955b35e3fdc4dea3e0b7a6ae2eb06Jeremy Fitzhardinge		return;
6190922abdc3982ae54cbe1b24ac5aa91a260eca1bbJeremy Fitzhardinge
6204fe7d5a708a955b35e3fdc4dea3e0b7a6ae2eb06Jeremy Fitzhardinge	domU_write_console(0, "(early) ", 8);
621b536b4b9623084d86f2b1f19cb44a2d6d74f00bfJeremy Fitzhardinge	while (off < len && NULL != (pos = strchr(string+off, '\n'))) {
622b536b4b9623084d86f2b1f19cb44a2d6d74f00bfJeremy Fitzhardinge		linelen = pos-string+off;
623b536b4b9623084d86f2b1f19cb44a2d6d74f00bfJeremy Fitzhardinge		if (off + linelen > len)
624b536b4b9623084d86f2b1f19cb44a2d6d74f00bfJeremy Fitzhardinge			break;
6254fe7d5a708a955b35e3fdc4dea3e0b7a6ae2eb06Jeremy Fitzhardinge		domU_write_console(0, string+off, linelen);
6264fe7d5a708a955b35e3fdc4dea3e0b7a6ae2eb06Jeremy Fitzhardinge		domU_write_console(0, "\r\n", 2);
627b536b4b9623084d86f2b1f19cb44a2d6d74f00bfJeremy Fitzhardinge		off += linelen + 1;
628b536b4b9623084d86f2b1f19cb44a2d6d74f00bfJeremy Fitzhardinge	}
629b536b4b9623084d86f2b1f19cb44a2d6d74f00bfJeremy Fitzhardinge	if (off < len)
6304fe7d5a708a955b35e3fdc4dea3e0b7a6ae2eb06Jeremy Fitzhardinge		domU_write_console(0, string+off, len-off);
631b536b4b9623084d86f2b1f19cb44a2d6d74f00bfJeremy Fitzhardinge}
632b536b4b9623084d86f2b1f19cb44a2d6d74f00bfJeremy Fitzhardinge
633b536b4b9623084d86f2b1f19cb44a2d6d74f00bfJeremy Fitzhardingestruct console xenboot_console = {
634b536b4b9623084d86f2b1f19cb44a2d6d74f00bfJeremy Fitzhardinge	.name		= "xenboot",
635b536b4b9623084d86f2b1f19cb44a2d6d74f00bfJeremy Fitzhardinge	.write		= xenboot_write_console,
6360922abdc3982ae54cbe1b24ac5aa91a260eca1bbJeremy Fitzhardinge	.flags		= CON_PRINTBUFFER | CON_BOOT | CON_ANYTIME,
637b536b4b9623084d86f2b1f19cb44a2d6d74f00bfJeremy Fitzhardinge};
6380922abdc3982ae54cbe1b24ac5aa91a260eca1bbJeremy Fitzhardinge#endif	/* CONFIG_EARLY_PRINTK */
6390acf10d8fbd52926217d3933d196b33fe2468f18Jeremy Fitzhardinge
6400acf10d8fbd52926217d3933d196b33fe2468f18Jeremy Fitzhardingevoid xen_raw_console_write(const char *str)
6410acf10d8fbd52926217d3933d196b33fe2468f18Jeremy Fitzhardinge{
6424fe7d5a708a955b35e3fdc4dea3e0b7a6ae2eb06Jeremy Fitzhardinge	dom0_write_console(0, str, strlen(str));
6430acf10d8fbd52926217d3933d196b33fe2468f18Jeremy Fitzhardinge}
6440acf10d8fbd52926217d3933d196b33fe2468f18Jeremy Fitzhardinge
6450acf10d8fbd52926217d3933d196b33fe2468f18Jeremy Fitzhardingevoid xen_raw_printk(const char *fmt, ...)
6460acf10d8fbd52926217d3933d196b33fe2468f18Jeremy Fitzhardinge{
6470acf10d8fbd52926217d3933d196b33fe2468f18Jeremy Fitzhardinge	static char buf[512];
6480acf10d8fbd52926217d3933d196b33fe2468f18Jeremy Fitzhardinge	va_list ap;
6490acf10d8fbd52926217d3933d196b33fe2468f18Jeremy Fitzhardinge
6500acf10d8fbd52926217d3933d196b33fe2468f18Jeremy Fitzhardinge	va_start(ap, fmt);
6510acf10d8fbd52926217d3933d196b33fe2468f18Jeremy Fitzhardinge	vsnprintf(buf, sizeof(buf), fmt, ap);
6520acf10d8fbd52926217d3933d196b33fe2468f18Jeremy Fitzhardinge	va_end(ap);
6530acf10d8fbd52926217d3933d196b33fe2468f18Jeremy Fitzhardinge
6540acf10d8fbd52926217d3933d196b33fe2468f18Jeremy Fitzhardinge	xen_raw_console_write(buf);
6550acf10d8fbd52926217d3933d196b33fe2468f18Jeremy Fitzhardinge}
656