]>
Commit | Line | Data |
---|---|---|
a23ea924 RR |
1 | /* |
2 | * Copyright (C) 2006, 2007, 2009 Rusty Russell, IBM Corporation | |
31610434 RR |
3 | * |
4 | * This program is free software; you can redistribute it and/or modify | |
5 | * it under the terms of the GNU General Public License as published by | |
6 | * the Free Software Foundation; either version 2 of the License, or | |
7 | * (at your option) any later version. | |
8 | * | |
9 | * This program is distributed in the hope that it will be useful, | |
10 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | |
11 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | |
12 | * GNU General Public License for more details. | |
13 | * | |
14 | * You should have received a copy of the GNU General Public License | |
15 | * along with this program; if not, write to the Free Software | |
16 | * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA | |
17 | */ | |
18 | #include <linux/err.h> | |
19 | #include <linux/init.h> | |
38edf58d AS |
20 | #include <linux/list.h> |
21 | #include <linux/spinlock.h> | |
31610434 RR |
22 | #include <linux/virtio.h> |
23 | #include <linux/virtio_console.h> | |
24 | #include "hvc_console.h" | |
25 | ||
38edf58d AS |
26 | /* |
27 | * This is a global struct for storing common data for all the devices | |
28 | * this driver handles. | |
29 | * | |
30 | * Mainly, it has a linked list for all the consoles in one place so | |
31 | * that callbacks from hvc for get_chars(), put_chars() work properly | |
32 | * across multiple devices and multiple ports per device. | |
33 | */ | |
34 | struct ports_driver_data { | |
d8a02bd5 RR |
35 | /* |
36 | * This is used to keep track of the number of hvc consoles | |
37 | * spawned by this driver. This number is given as the first | |
38 | * argument to hvc_alloc(). To correctly map an initial | |
39 | * console spawned via hvc_instantiate to the console being | |
40 | * hooked up via hvc_alloc, we need to pass the same vtermno. | |
41 | * | |
42 | * We also just assume the first console being initialised was | |
43 | * the first one that got used as the initial console. | |
44 | */ | |
45 | unsigned int next_vtermno; | |
46 | ||
38edf58d AS |
47 | /* All the console devices handled by this driver */ |
48 | struct list_head consoles; | |
49 | }; | |
50 | static struct ports_driver_data pdrvdata; | |
51 | ||
52 | DEFINE_SPINLOCK(pdrvdata_lock); | |
53 | ||
fdb9a054 AS |
54 | struct port_buffer { |
55 | char *buf; | |
56 | ||
57 | /* size of the buffer in *buf above */ | |
58 | size_t size; | |
59 | ||
60 | /* used length of the buffer */ | |
61 | size_t len; | |
62 | /* offset in the buf from which to consume data */ | |
63 | size_t offset; | |
64 | }; | |
65 | ||
21206ede RR |
66 | struct port { |
67 | struct virtqueue *in_vq, *out_vq; | |
68 | struct virtio_device *vdev; | |
fdb9a054 AS |
69 | |
70 | /* The current buffer from which data has to be fed to readers */ | |
71 | struct port_buffer *inbuf; | |
21206ede | 72 | |
38edf58d | 73 | /* For console ports, hvc != NULL and these are valid. */ |
21206ede RR |
74 | /* The hvc device */ |
75 | struct hvc_struct *hvc; | |
38edf58d AS |
76 | |
77 | /* We'll place all consoles in a list in the pdrvdata struct */ | |
78 | struct list_head list; | |
79 | ||
80 | /* Our vterm number. */ | |
81 | u32 vtermno; | |
21206ede | 82 | }; |
31610434 | 83 | |
971f3390 RR |
84 | /* This is the very early arch-specified put chars function. */ |
85 | static int (*early_put_chars)(u32, const char *, int); | |
86 | ||
38edf58d AS |
87 | static struct port *find_port_by_vtermno(u32 vtermno) |
88 | { | |
89 | struct port *port; | |
90 | unsigned long flags; | |
91 | ||
92 | spin_lock_irqsave(&pdrvdata_lock, flags); | |
93 | list_for_each_entry(port, &pdrvdata.consoles, list) { | |
94 | if (port->vtermno == vtermno) | |
95 | goto out; | |
96 | } | |
97 | port = NULL; | |
98 | out: | |
99 | spin_unlock_irqrestore(&pdrvdata_lock, flags); | |
100 | return port; | |
101 | } | |
102 | ||
fdb9a054 AS |
103 | static void free_buf(struct port_buffer *buf) |
104 | { | |
105 | kfree(buf->buf); | |
106 | kfree(buf); | |
107 | } | |
108 | ||
109 | static struct port_buffer *alloc_buf(size_t buf_size) | |
110 | { | |
111 | struct port_buffer *buf; | |
112 | ||
113 | buf = kmalloc(sizeof(*buf), GFP_KERNEL); | |
114 | if (!buf) | |
115 | goto fail; | |
116 | buf->buf = kzalloc(buf_size, GFP_KERNEL); | |
117 | if (!buf->buf) | |
118 | goto free_buf; | |
119 | buf->len = 0; | |
120 | buf->offset = 0; | |
121 | buf->size = buf_size; | |
122 | return buf; | |
123 | ||
124 | free_buf: | |
125 | kfree(buf); | |
126 | fail: | |
127 | return NULL; | |
128 | } | |
129 | ||
a3cde449 AS |
130 | /* Callers should take appropriate locks */ |
131 | static void *get_inbuf(struct port *port) | |
132 | { | |
133 | struct port_buffer *buf; | |
134 | struct virtqueue *vq; | |
135 | unsigned int len; | |
136 | ||
137 | vq = port->in_vq; | |
138 | buf = vq->vq_ops->get_buf(vq, &len); | |
139 | if (buf) { | |
140 | buf->len = len; | |
141 | buf->offset = 0; | |
142 | } | |
143 | return buf; | |
144 | } | |
145 | ||
e27b5198 AS |
146 | /* |
147 | * Create a scatter-gather list representing our input buffer and put | |
148 | * it in the queue. | |
149 | * | |
150 | * Callers should take appropriate locks. | |
151 | */ | |
152 | static void add_inbuf(struct virtqueue *vq, struct port_buffer *buf) | |
153 | { | |
154 | struct scatterlist sg[1]; | |
155 | sg_init_one(sg, buf->buf, buf->size); | |
156 | ||
157 | if (vq->vq_ops->add_buf(vq, sg, 0, 1, buf) < 0) | |
158 | BUG(); | |
159 | vq->vq_ops->kick(vq); | |
160 | } | |
161 | ||
a23ea924 RR |
162 | /* |
163 | * The put_chars() callback is pretty straightforward. | |
31610434 | 164 | * |
a23ea924 RR |
165 | * We turn the characters into a scatter-gather list, add it to the |
166 | * output queue and then kick the Host. Then we sit here waiting for | |
167 | * it to finish: inefficient in theory, but in practice | |
168 | * implementations will do it immediately (lguest's Launcher does). | |
169 | */ | |
31610434 RR |
170 | static int put_chars(u32 vtermno, const char *buf, int count) |
171 | { | |
172 | struct scatterlist sg[1]; | |
21206ede | 173 | struct port *port; |
38edf58d AS |
174 | unsigned int len; |
175 | ||
176 | port = find_port_by_vtermno(vtermno); | |
177 | if (!port) | |
178 | return 0; | |
31610434 | 179 | |
971f3390 RR |
180 | if (unlikely(early_put_chars)) |
181 | return early_put_chars(vtermno, buf, count); | |
182 | ||
31610434 RR |
183 | /* This is a convenient routine to initialize a single-elem sg list */ |
184 | sg_init_one(sg, buf, count); | |
185 | ||
21206ede RR |
186 | /* This shouldn't fail: if it does, we lose chars. */ |
187 | if (port->out_vq->vq_ops->add_buf(port->out_vq, sg, 1, 0, port) >= 0) { | |
31610434 | 188 | /* Tell Host to go! */ |
21206ede RR |
189 | port->out_vq->vq_ops->kick(port->out_vq); |
190 | while (!port->out_vq->vq_ops->get_buf(port->out_vq, &len)) | |
31610434 RR |
191 | cpu_relax(); |
192 | } | |
193 | ||
194 | /* We're expected to return the amount of data we wrote: all of it. */ | |
195 | return count; | |
196 | } | |
197 | ||
a23ea924 RR |
198 | /* |
199 | * get_chars() is the callback from the hvc_console infrastructure | |
200 | * when an interrupt is received. | |
31610434 | 201 | * |
a23ea924 RR |
202 | * Most of the code deals with the fact that the hvc_console() |
203 | * infrastructure only asks us for 16 bytes at a time. We keep | |
204 | * in_offset and in_used fields for partially-filled buffers. | |
205 | */ | |
31610434 RR |
206 | static int get_chars(u32 vtermno, char *buf, int count) |
207 | { | |
21206ede RR |
208 | struct port *port; |
209 | ||
38edf58d AS |
210 | |
211 | port = find_port_by_vtermno(vtermno); | |
212 | if (!port) | |
213 | return 0; | |
21206ede | 214 | |
31610434 | 215 | /* If we don't have an input queue yet, we can't get input. */ |
21206ede | 216 | BUG_ON(!port->in_vq); |
31610434 | 217 | |
21206ede | 218 | /* No more in buffer? See if they've (re)used it. */ |
fdb9a054 | 219 | if (port->inbuf->offset == port->inbuf->len) { |
a3cde449 | 220 | if (!get_inbuf(port)) |
31610434 RR |
221 | return 0; |
222 | } | |
223 | ||
224 | /* You want more than we have to give? Well, try wanting less! */ | |
fdb9a054 AS |
225 | if (port->inbuf->offset + count > port->inbuf->len) |
226 | count = port->inbuf->len - port->inbuf->offset; | |
31610434 RR |
227 | |
228 | /* Copy across to their buffer and increment offset. */ | |
fdb9a054 AS |
229 | memcpy(buf, port->inbuf->buf + port->inbuf->offset, count); |
230 | port->inbuf->offset += count; | |
31610434 RR |
231 | |
232 | /* Finished? Re-register buffer so Host will use it again. */ | |
fdb9a054 | 233 | if (port->inbuf->offset == port->inbuf->len) |
e27b5198 | 234 | add_inbuf(port->in_vq, port->inbuf); |
31610434 RR |
235 | |
236 | return count; | |
237 | } | |
31610434 | 238 | |
c2983458 CB |
239 | /* |
240 | * virtio console configuration. This supports: | |
241 | * - console resize | |
242 | */ | |
243 | static void virtcons_apply_config(struct virtio_device *dev) | |
244 | { | |
73954488 | 245 | struct port *port = dev->priv; |
c2983458 CB |
246 | struct winsize ws; |
247 | ||
248 | if (virtio_has_feature(dev, VIRTIO_CONSOLE_F_SIZE)) { | |
249 | dev->config->get(dev, | |
250 | offsetof(struct virtio_console_config, cols), | |
251 | &ws.ws_col, sizeof(u16)); | |
252 | dev->config->get(dev, | |
253 | offsetof(struct virtio_console_config, rows), | |
254 | &ws.ws_row, sizeof(u16)); | |
73954488 | 255 | hvc_resize(port->hvc, ws); |
c2983458 CB |
256 | } |
257 | } | |
258 | ||
38edf58d | 259 | /* We set the configuration at this point, since we now have a tty */ |
91fcad19 CB |
260 | static int notifier_add_vio(struct hvc_struct *hp, int data) |
261 | { | |
38edf58d AS |
262 | struct port *port; |
263 | ||
264 | port = find_port_by_vtermno(hp->vtermno); | |
265 | if (!port) | |
266 | return -EINVAL; | |
267 | ||
91fcad19 | 268 | hp->irq_requested = 1; |
38edf58d | 269 | virtcons_apply_config(port->vdev); |
c2983458 | 270 | |
91fcad19 CB |
271 | return 0; |
272 | } | |
273 | ||
274 | static void notifier_del_vio(struct hvc_struct *hp, int data) | |
275 | { | |
276 | hp->irq_requested = 0; | |
277 | } | |
278 | ||
279 | static void hvc_handle_input(struct virtqueue *vq) | |
280 | { | |
73954488 RR |
281 | struct port *port = vq->vdev->priv; |
282 | ||
283 | if (hvc_poll(port->hvc)) | |
91fcad19 CB |
284 | hvc_kick(); |
285 | } | |
286 | ||
971f3390 | 287 | /* The operations for the console. */ |
1dff3996 | 288 | static const struct hv_ops hv_ops = { |
971f3390 RR |
289 | .get_chars = get_chars, |
290 | .put_chars = put_chars, | |
291 | .notifier_add = notifier_add_vio, | |
292 | .notifier_del = notifier_del_vio, | |
293 | .notifier_hangup = notifier_del_vio, | |
294 | }; | |
295 | ||
296 | /* | |
297 | * Console drivers are initialized very early so boot messages can go | |
298 | * out, so we do things slightly differently from the generic virtio | |
299 | * initialization of the net and block drivers. | |
300 | * | |
301 | * At this stage, the console is output-only. It's too early to set | |
302 | * up a virtqueue, so we let the drivers do some boutique early-output | |
303 | * thing. | |
304 | */ | |
305 | int __init virtio_cons_early_init(int (*put_chars)(u32, const char *, int)) | |
306 | { | |
307 | early_put_chars = put_chars; | |
308 | return hvc_instantiate(0, 0, &hv_ops); | |
309 | } | |
310 | ||
d8a02bd5 RR |
311 | static struct port *__devinit add_port(u32 vtermno) |
312 | { | |
313 | struct port *port; | |
314 | ||
315 | port = kmalloc(sizeof(*port), GFP_KERNEL); | |
316 | if (!port) | |
317 | return NULL; | |
318 | ||
319 | port->inbuf = alloc_buf(PAGE_SIZE); | |
320 | if (!port->inbuf) { | |
321 | kfree(port); | |
322 | return NULL; | |
323 | } | |
324 | port->hvc = NULL; | |
325 | port->vtermno = vtermno; | |
326 | return port; | |
327 | } | |
328 | ||
329 | static void free_port(struct port *port) | |
330 | { | |
331 | free_buf(port->inbuf); | |
332 | kfree(port); | |
333 | } | |
334 | ||
a23ea924 RR |
335 | /* |
336 | * Once we're further in boot, we get probed like any other virtio | |
337 | * device. At this stage we set up the output virtqueue. | |
31610434 | 338 | * |
a23ea924 RR |
339 | * To set up and manage our virtual console, we call hvc_alloc(). |
340 | * Since we never remove the console device we never need this pointer | |
341 | * again. | |
31610434 | 342 | * |
a23ea924 RR |
343 | * Finally we put our input buffer in the input queue, ready to |
344 | * receive. | |
345 | */ | |
21206ede | 346 | static int __devinit virtcons_probe(struct virtio_device *vdev) |
31610434 | 347 | { |
d2a7ddda MT |
348 | vq_callback_t *callbacks[] = { hvc_handle_input, NULL}; |
349 | const char *names[] = { "input", "output" }; | |
350 | struct virtqueue *vqs[2]; | |
21206ede | 351 | struct port *port; |
31610434 | 352 | int err; |
31610434 | 353 | |
d8a02bd5 RR |
354 | port = add_port(pdrvdata.next_vtermno); |
355 | if (!port) { | |
356 | err = -ENOMEM; | |
357 | goto fail; | |
f550804a | 358 | } |
73954488 RR |
359 | |
360 | /* Attach this port to this virtio_device, and vice-versa. */ | |
21206ede | 361 | port->vdev = vdev; |
73954488 | 362 | vdev->priv = port; |
31610434 | 363 | |
d2a7ddda | 364 | /* Find the queues. */ |
d2a7ddda MT |
365 | err = vdev->config->find_vqs(vdev, 2, vqs, callbacks, names); |
366 | if (err) | |
31610434 | 367 | goto free; |
31610434 | 368 | |
21206ede RR |
369 | port->in_vq = vqs[0]; |
370 | port->out_vq = vqs[1]; | |
31610434 | 371 | |
a23ea924 RR |
372 | /* |
373 | * The first argument of hvc_alloc() is the virtual console | |
d8a02bd5 RR |
374 | * number. The second argument is the parameter for the |
375 | * notification mechanism (like irq number). We currently | |
376 | * leave this as zero, virtqueues have implicit notifications. | |
31610434 | 377 | * |
a23ea924 RR |
378 | * The third argument is a "struct hv_ops" containing the |
379 | * put_chars(), get_chars(), notifier_add() and notifier_del() | |
380 | * pointers. The final argument is the output buffer size: we | |
381 | * can do any size, so we put PAGE_SIZE here. | |
382 | */ | |
d8a02bd5 | 383 | port->hvc = hvc_alloc(port->vtermno, 0, &hv_ops, PAGE_SIZE); |
21206ede RR |
384 | if (IS_ERR(port->hvc)) { |
385 | err = PTR_ERR(port->hvc); | |
d2a7ddda | 386 | goto free_vqs; |
31610434 RR |
387 | } |
388 | ||
38edf58d AS |
389 | /* Add to vtermno list. */ |
390 | spin_lock_irq(&pdrvdata_lock); | |
d8a02bd5 | 391 | pdrvdata.next_vtermno++; |
38edf58d AS |
392 | list_add(&port->list, &pdrvdata.consoles); |
393 | spin_unlock_irq(&pdrvdata_lock); | |
394 | ||
31610434 | 395 | /* Register the input buffer the first time. */ |
e27b5198 | 396 | add_inbuf(port->in_vq, port->inbuf); |
971f3390 RR |
397 | |
398 | /* Start using the new console output. */ | |
399 | early_put_chars = NULL; | |
31610434 RR |
400 | return 0; |
401 | ||
d2a7ddda MT |
402 | free_vqs: |
403 | vdev->config->del_vqs(vdev); | |
31610434 | 404 | free: |
d8a02bd5 | 405 | free_port(port); |
31610434 RR |
406 | fail: |
407 | return err; | |
408 | } | |
409 | ||
410 | static struct virtio_device_id id_table[] = { | |
411 | { VIRTIO_ID_CONSOLE, VIRTIO_DEV_ANY_ID }, | |
412 | { 0 }, | |
413 | }; | |
414 | ||
c2983458 CB |
415 | static unsigned int features[] = { |
416 | VIRTIO_CONSOLE_F_SIZE, | |
417 | }; | |
418 | ||
31610434 | 419 | static struct virtio_driver virtio_console = { |
c2983458 CB |
420 | .feature_table = features, |
421 | .feature_table_size = ARRAY_SIZE(features), | |
31610434 RR |
422 | .driver.name = KBUILD_MODNAME, |
423 | .driver.owner = THIS_MODULE, | |
424 | .id_table = id_table, | |
425 | .probe = virtcons_probe, | |
c2983458 | 426 | .config_changed = virtcons_apply_config, |
31610434 RR |
427 | }; |
428 | ||
429 | static int __init init(void) | |
430 | { | |
38edf58d AS |
431 | INIT_LIST_HEAD(&pdrvdata.consoles); |
432 | ||
31610434 RR |
433 | return register_virtio_driver(&virtio_console); |
434 | } | |
435 | module_init(init); | |
436 | ||
437 | MODULE_DEVICE_TABLE(virtio, id_table); | |
438 | MODULE_DESCRIPTION("Virtio console driver"); | |
439 | MODULE_LICENSE("GPL"); |