- Update Xen patches to 3.3-rc5 and c/s 1157.
[linux-flexiantxendom0-3.2.10.git] / drivers / xen / console / xencons_ring.c
1 /* 
2  * This program is free software; you can redistribute it and/or
3  * modify it under the terms of the GNU General Public License version 2
4  * as published by the Free Software Foundation; or, when distributed
5  * separately from the Linux kernel or incorporated into other
6  * software packages, subject to the following license:
7  * 
8  * Permission is hereby granted, free of charge, to any person obtaining a copy
9  * of this source file (the "Software"), to deal in the Software without
10  * restriction, including without limitation the rights to use, copy, modify,
11  * merge, publish, distribute, sublicense, and/or sell copies of the Software,
12  * and to permit persons to whom the Software is furnished to do so, subject to
13  * the following conditions:
14  * 
15  * The above copyright notice and this permission notice shall be included in
16  * all copies or substantial portions of the Software.
17  * 
18  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
19  * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
20  * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
21  * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
22  * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
23  * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
24  * IN THE SOFTWARE.
25  */
26
27 #include <linux/errno.h>
28 #include <linux/signal.h>
29 #include <linux/sched.h>
30 #include <linux/interrupt.h>
31 #include <linux/tty.h>
32 #include <linux/tty_flip.h>
33 #include <linux/serial.h>
34 #include <linux/major.h>
35 #include <linux/ptrace.h>
36 #include <linux/ioport.h>
37 #include <linux/mm.h>
38 #include <linux/slab.h>
39
40 #include <asm/hypervisor.h>
41 #include <xen/evtchn.h>
42 #include <xen/xencons.h>
43 #include <linux/wait.h>
44 #include <linux/interrupt.h>
45 #include <linux/sched.h>
46 #include <linux/err.h>
47 #include <xen/interface/io/console.h>
48
49 static int xencons_irq;
50
51 static inline struct xencons_interface *xencons_interface(void)
52 {
53         return mfn_to_virt(xen_start_info->console.domU.mfn);
54 }
55
56 static inline void notify_daemon(void)
57 {
58         /* Use evtchn: this is called early, before irq is set up. */
59         notify_remote_via_evtchn(xen_start_info->console.domU.evtchn);
60 }
61
62 int xencons_ring_send(const char *data, unsigned len)
63 {
64         int sent = 0;
65         struct xencons_interface *intf = xencons_interface();
66         XENCONS_RING_IDX cons, prod;
67
68         cons = intf->out_cons;
69         prod = intf->out_prod;
70         mb();
71         BUG_ON((prod - cons) > sizeof(intf->out));
72
73         while ((sent < len) && ((prod - cons) < sizeof(intf->out)))
74                 intf->out[MASK_XENCONS_IDX(prod++, intf->out)] = data[sent++];
75
76         wmb();
77         intf->out_prod = prod;
78
79         notify_daemon();
80
81         return sent;
82 }
83
84 static irqreturn_t handle_input(int irq, void *unused)
85 {
86         struct xencons_interface *intf = xencons_interface();
87         XENCONS_RING_IDX cons, prod;
88
89         cons = intf->in_cons;
90         prod = intf->in_prod;
91         mb();
92         BUG_ON((prod - cons) > sizeof(intf->in));
93
94         while (cons != prod) {
95                 xencons_rx(intf->in+MASK_XENCONS_IDX(cons,intf->in), 1);
96                 cons++;
97         }
98
99         mb();
100         intf->in_cons = cons;
101
102         notify_daemon();
103
104         xencons_tx();
105
106         return IRQ_HANDLED;
107 }
108
109 int xencons_ring_init(void)
110 {
111         int irq;
112
113         if (xencons_irq)
114                 unbind_from_irqhandler(xencons_irq, NULL);
115         xencons_irq = 0;
116
117         if (!is_running_on_xen() ||
118             is_initial_xendomain() ||
119             !xen_start_info->console.domU.evtchn)
120                 return -ENODEV;
121
122         irq = bind_caller_port_to_irqhandler(
123                 xen_start_info->console.domU.evtchn,
124                 handle_input, 0, "xencons", NULL);
125         if (irq < 0) {
126                 pr_err("XEN console request irq failed %i\n", irq);
127                 return irq;
128         }
129
130         xencons_irq = irq;
131
132         /* In case we have in-flight data after save/restore... */
133         notify_daemon();
134
135         return 0;
136 }
137
138 void xencons_resume(void)
139 {
140         (void)xencons_ring_init();
141 }