]>
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 | ||
4f23c573 AS |
54 | /* This struct holds information that's relevant only for console ports */ |
55 | struct console { | |
56 | /* We'll place all consoles in a list in the pdrvdata struct */ | |
57 | struct list_head list; | |
58 | ||
59 | /* The hvc device associated with this console port */ | |
60 | struct hvc_struct *hvc; | |
61 | ||
62 | /* | |
63 | * This number identifies the number that we used to register | |
64 | * with hvc in hvc_instantiate() and hvc_alloc(); this is the | |
65 | * number passed on by the hvc callbacks to us to | |
66 | * differentiate between the other console ports handled by | |
67 | * this driver | |
68 | */ | |
69 | u32 vtermno; | |
70 | }; | |
71 | ||
1c85bf35 AS |
72 | /* |
73 | * This is a per-device struct that stores data common to all the | |
74 | * ports for that device (vdev->priv). | |
75 | */ | |
76 | struct ports_device { | |
2658a79a AS |
77 | /* Array of per-port IO virtqueues */ |
78 | struct virtqueue **in_vqs, **out_vqs; | |
79 | ||
1c85bf35 AS |
80 | struct virtio_device *vdev; |
81 | }; | |
82 | ||
fdb9a054 AS |
83 | struct port_buffer { |
84 | char *buf; | |
85 | ||
86 | /* size of the buffer in *buf above */ | |
87 | size_t size; | |
88 | ||
89 | /* used length of the buffer */ | |
90 | size_t len; | |
91 | /* offset in the buf from which to consume data */ | |
92 | size_t offset; | |
93 | }; | |
94 | ||
1c85bf35 | 95 | /* This struct holds the per-port data */ |
21206ede | 96 | struct port { |
1c85bf35 AS |
97 | /* Pointer to the parent virtio_console device */ |
98 | struct ports_device *portdev; | |
fdb9a054 AS |
99 | |
100 | /* The current buffer from which data has to be fed to readers */ | |
101 | struct port_buffer *inbuf; | |
21206ede | 102 | |
1c85bf35 AS |
103 | /* The IO vqs for this port */ |
104 | struct virtqueue *in_vq, *out_vq; | |
105 | ||
4f23c573 AS |
106 | /* |
107 | * The entries in this struct will be valid if this port is | |
108 | * hooked up to an hvc console | |
109 | */ | |
110 | struct console cons; | |
21206ede | 111 | }; |
31610434 | 112 | |
971f3390 RR |
113 | /* This is the very early arch-specified put chars function. */ |
114 | static int (*early_put_chars)(u32, const char *, int); | |
115 | ||
38edf58d AS |
116 | static struct port *find_port_by_vtermno(u32 vtermno) |
117 | { | |
118 | struct port *port; | |
4f23c573 | 119 | struct console *cons; |
38edf58d AS |
120 | unsigned long flags; |
121 | ||
122 | spin_lock_irqsave(&pdrvdata_lock, flags); | |
4f23c573 AS |
123 | list_for_each_entry(cons, &pdrvdata.consoles, list) { |
124 | if (cons->vtermno == vtermno) { | |
125 | port = container_of(cons, struct port, cons); | |
38edf58d | 126 | goto out; |
4f23c573 | 127 | } |
38edf58d AS |
128 | } |
129 | port = NULL; | |
130 | out: | |
131 | spin_unlock_irqrestore(&pdrvdata_lock, flags); | |
132 | return port; | |
133 | } | |
134 | ||
fdb9a054 AS |
135 | static void free_buf(struct port_buffer *buf) |
136 | { | |
137 | kfree(buf->buf); | |
138 | kfree(buf); | |
139 | } | |
140 | ||
141 | static struct port_buffer *alloc_buf(size_t buf_size) | |
142 | { | |
143 | struct port_buffer *buf; | |
144 | ||
145 | buf = kmalloc(sizeof(*buf), GFP_KERNEL); | |
146 | if (!buf) | |
147 | goto fail; | |
148 | buf->buf = kzalloc(buf_size, GFP_KERNEL); | |
149 | if (!buf->buf) | |
150 | goto free_buf; | |
151 | buf->len = 0; | |
152 | buf->offset = 0; | |
153 | buf->size = buf_size; | |
154 | return buf; | |
155 | ||
156 | free_buf: | |
157 | kfree(buf); | |
158 | fail: | |
159 | return NULL; | |
160 | } | |
161 | ||
a3cde449 AS |
162 | /* Callers should take appropriate locks */ |
163 | static void *get_inbuf(struct port *port) | |
164 | { | |
165 | struct port_buffer *buf; | |
166 | struct virtqueue *vq; | |
167 | unsigned int len; | |
168 | ||
169 | vq = port->in_vq; | |
170 | buf = vq->vq_ops->get_buf(vq, &len); | |
171 | if (buf) { | |
172 | buf->len = len; | |
173 | buf->offset = 0; | |
174 | } | |
175 | return buf; | |
176 | } | |
177 | ||
e27b5198 AS |
178 | /* |
179 | * Create a scatter-gather list representing our input buffer and put | |
180 | * it in the queue. | |
181 | * | |
182 | * Callers should take appropriate locks. | |
183 | */ | |
184 | static void add_inbuf(struct virtqueue *vq, struct port_buffer *buf) | |
185 | { | |
186 | struct scatterlist sg[1]; | |
1c85bf35 | 187 | |
e27b5198 AS |
188 | sg_init_one(sg, buf->buf, buf->size); |
189 | ||
190 | if (vq->vq_ops->add_buf(vq, sg, 0, 1, buf) < 0) | |
191 | BUG(); | |
192 | vq->vq_ops->kick(vq); | |
193 | } | |
194 | ||
a23ea924 RR |
195 | /* |
196 | * The put_chars() callback is pretty straightforward. | |
31610434 | 197 | * |
a23ea924 RR |
198 | * We turn the characters into a scatter-gather list, add it to the |
199 | * output queue and then kick the Host. Then we sit here waiting for | |
200 | * it to finish: inefficient in theory, but in practice | |
201 | * implementations will do it immediately (lguest's Launcher does). | |
202 | */ | |
31610434 RR |
203 | static int put_chars(u32 vtermno, const char *buf, int count) |
204 | { | |
205 | struct scatterlist sg[1]; | |
21206ede | 206 | struct port *port; |
1c85bf35 | 207 | struct virtqueue *out_vq; |
38edf58d AS |
208 | unsigned int len; |
209 | ||
210 | port = find_port_by_vtermno(vtermno); | |
211 | if (!port) | |
212 | return 0; | |
31610434 | 213 | |
971f3390 RR |
214 | if (unlikely(early_put_chars)) |
215 | return early_put_chars(vtermno, buf, count); | |
216 | ||
1c85bf35 | 217 | out_vq = port->out_vq; |
31610434 RR |
218 | /* This is a convenient routine to initialize a single-elem sg list */ |
219 | sg_init_one(sg, buf, count); | |
220 | ||
21206ede | 221 | /* This shouldn't fail: if it does, we lose chars. */ |
1c85bf35 | 222 | if (out_vq->vq_ops->add_buf(out_vq, sg, 1, 0, port) >= 0) { |
31610434 | 223 | /* Tell Host to go! */ |
1c85bf35 AS |
224 | out_vq->vq_ops->kick(out_vq); |
225 | while (!out_vq->vq_ops->get_buf(out_vq, &len)) | |
31610434 RR |
226 | cpu_relax(); |
227 | } | |
228 | ||
229 | /* We're expected to return the amount of data we wrote: all of it. */ | |
230 | return count; | |
231 | } | |
232 | ||
a23ea924 RR |
233 | /* |
234 | * get_chars() is the callback from the hvc_console infrastructure | |
235 | * when an interrupt is received. | |
31610434 | 236 | * |
a23ea924 RR |
237 | * Most of the code deals with the fact that the hvc_console() |
238 | * infrastructure only asks us for 16 bytes at a time. We keep | |
239 | * in_offset and in_used fields for partially-filled buffers. | |
240 | */ | |
31610434 RR |
241 | static int get_chars(u32 vtermno, char *buf, int count) |
242 | { | |
21206ede RR |
243 | struct port *port; |
244 | ||
38edf58d AS |
245 | port = find_port_by_vtermno(vtermno); |
246 | if (!port) | |
247 | return 0; | |
21206ede | 248 | |
31610434 | 249 | /* If we don't have an input queue yet, we can't get input. */ |
21206ede | 250 | BUG_ON(!port->in_vq); |
31610434 | 251 | |
21206ede | 252 | /* No more in buffer? See if they've (re)used it. */ |
fdb9a054 | 253 | if (port->inbuf->offset == port->inbuf->len) { |
a3cde449 | 254 | if (!get_inbuf(port)) |
31610434 RR |
255 | return 0; |
256 | } | |
257 | ||
258 | /* You want more than we have to give? Well, try wanting less! */ | |
fdb9a054 AS |
259 | if (port->inbuf->offset + count > port->inbuf->len) |
260 | count = port->inbuf->len - port->inbuf->offset; | |
31610434 RR |
261 | |
262 | /* Copy across to their buffer and increment offset. */ | |
fdb9a054 AS |
263 | memcpy(buf, port->inbuf->buf + port->inbuf->offset, count); |
264 | port->inbuf->offset += count; | |
31610434 RR |
265 | |
266 | /* Finished? Re-register buffer so Host will use it again. */ | |
fdb9a054 | 267 | if (port->inbuf->offset == port->inbuf->len) |
e27b5198 | 268 | add_inbuf(port->in_vq, port->inbuf); |
31610434 RR |
269 | |
270 | return count; | |
271 | } | |
31610434 | 272 | |
cb06e367 | 273 | static void resize_console(struct port *port) |
c2983458 | 274 | { |
cb06e367 | 275 | struct virtio_device *vdev; |
c2983458 CB |
276 | struct winsize ws; |
277 | ||
cb06e367 AS |
278 | vdev = port->portdev->vdev; |
279 | if (virtio_has_feature(vdev, VIRTIO_CONSOLE_F_SIZE)) { | |
280 | vdev->config->get(vdev, | |
281 | offsetof(struct virtio_console_config, cols), | |
282 | &ws.ws_col, sizeof(u16)); | |
283 | vdev->config->get(vdev, | |
284 | offsetof(struct virtio_console_config, rows), | |
285 | &ws.ws_row, sizeof(u16)); | |
4f23c573 | 286 | hvc_resize(port->cons.hvc, ws); |
c2983458 CB |
287 | } |
288 | } | |
289 | ||
cb06e367 AS |
290 | static void virtcons_apply_config(struct virtio_device *vdev) |
291 | { | |
292 | resize_console(find_port_by_vtermno(0)); | |
293 | } | |
294 | ||
38edf58d | 295 | /* We set the configuration at this point, since we now have a tty */ |
91fcad19 CB |
296 | static int notifier_add_vio(struct hvc_struct *hp, int data) |
297 | { | |
38edf58d AS |
298 | struct port *port; |
299 | ||
300 | port = find_port_by_vtermno(hp->vtermno); | |
301 | if (!port) | |
302 | return -EINVAL; | |
303 | ||
91fcad19 | 304 | hp->irq_requested = 1; |
cb06e367 | 305 | resize_console(port); |
c2983458 | 306 | |
91fcad19 CB |
307 | return 0; |
308 | } | |
309 | ||
310 | static void notifier_del_vio(struct hvc_struct *hp, int data) | |
311 | { | |
312 | hp->irq_requested = 0; | |
313 | } | |
314 | ||
315 | static void hvc_handle_input(struct virtqueue *vq) | |
316 | { | |
4f23c573 | 317 | struct console *cons; |
1c85bf35 AS |
318 | bool activity = false; |
319 | ||
4f23c573 AS |
320 | list_for_each_entry(cons, &pdrvdata.consoles, list) |
321 | activity |= hvc_poll(cons->hvc); | |
73954488 | 322 | |
1c85bf35 | 323 | if (activity) |
91fcad19 CB |
324 | hvc_kick(); |
325 | } | |
326 | ||
971f3390 | 327 | /* The operations for the console. */ |
1dff3996 | 328 | static const struct hv_ops hv_ops = { |
971f3390 RR |
329 | .get_chars = get_chars, |
330 | .put_chars = put_chars, | |
331 | .notifier_add = notifier_add_vio, | |
332 | .notifier_del = notifier_del_vio, | |
333 | .notifier_hangup = notifier_del_vio, | |
334 | }; | |
335 | ||
336 | /* | |
337 | * Console drivers are initialized very early so boot messages can go | |
338 | * out, so we do things slightly differently from the generic virtio | |
339 | * initialization of the net and block drivers. | |
340 | * | |
341 | * At this stage, the console is output-only. It's too early to set | |
342 | * up a virtqueue, so we let the drivers do some boutique early-output | |
343 | * thing. | |
344 | */ | |
345 | int __init virtio_cons_early_init(int (*put_chars)(u32, const char *, int)) | |
346 | { | |
347 | early_put_chars = put_chars; | |
348 | return hvc_instantiate(0, 0, &hv_ops); | |
349 | } | |
350 | ||
cfa6d379 AS |
351 | int __devinit init_port_console(struct port *port) |
352 | { | |
353 | int ret; | |
354 | ||
355 | /* | |
356 | * The Host's telling us this port is a console port. Hook it | |
357 | * up with an hvc console. | |
358 | * | |
359 | * To set up and manage our virtual console, we call | |
360 | * hvc_alloc(). | |
361 | * | |
362 | * The first argument of hvc_alloc() is the virtual console | |
363 | * number. The second argument is the parameter for the | |
364 | * notification mechanism (like irq number). We currently | |
365 | * leave this as zero, virtqueues have implicit notifications. | |
366 | * | |
367 | * The third argument is a "struct hv_ops" containing the | |
368 | * put_chars() get_chars(), notifier_add() and notifier_del() | |
369 | * pointers. The final argument is the output buffer size: we | |
370 | * can do any size, so we put PAGE_SIZE here. | |
371 | */ | |
372 | port->cons.vtermno = pdrvdata.next_vtermno; | |
373 | ||
374 | port->cons.hvc = hvc_alloc(port->cons.vtermno, 0, &hv_ops, PAGE_SIZE); | |
375 | if (IS_ERR(port->cons.hvc)) { | |
376 | ret = PTR_ERR(port->cons.hvc); | |
377 | port->cons.hvc = NULL; | |
378 | return ret; | |
379 | } | |
380 | spin_lock_irq(&pdrvdata_lock); | |
381 | pdrvdata.next_vtermno++; | |
382 | list_add_tail(&port->cons.list, &pdrvdata.consoles); | |
383 | spin_unlock_irq(&pdrvdata_lock); | |
384 | ||
385 | return 0; | |
386 | } | |
387 | ||
1c85bf35 | 388 | static int __devinit add_port(struct ports_device *portdev) |
d8a02bd5 | 389 | { |
21206ede | 390 | struct port *port; |
31610434 | 391 | int err; |
31610434 | 392 | |
1c85bf35 | 393 | port = kmalloc(sizeof(*port), GFP_KERNEL); |
d8a02bd5 RR |
394 | if (!port) { |
395 | err = -ENOMEM; | |
396 | goto fail; | |
f550804a | 397 | } |
73954488 | 398 | |
1c85bf35 | 399 | port->portdev = portdev; |
2658a79a AS |
400 | port->in_vq = portdev->in_vqs[0]; |
401 | port->out_vq = portdev->out_vqs[0]; | |
31610434 | 402 | |
1c85bf35 AS |
403 | port->inbuf = alloc_buf(PAGE_SIZE); |
404 | if (!port->inbuf) { | |
405 | err = -ENOMEM; | |
406 | goto free_port; | |
407 | } | |
31610434 | 408 | |
cfa6d379 AS |
409 | err = init_port_console(port); |
410 | if (err) | |
1c85bf35 | 411 | goto free_inbuf; |
38edf58d | 412 | |
31610434 | 413 | /* Register the input buffer the first time. */ |
e27b5198 | 414 | add_inbuf(port->in_vq, port->inbuf); |
971f3390 | 415 | |
1c85bf35 AS |
416 | return 0; |
417 | ||
418 | free_inbuf: | |
419 | free_buf(port->inbuf); | |
420 | free_port: | |
421 | kfree(port); | |
422 | fail: | |
423 | return err; | |
424 | } | |
425 | ||
2658a79a AS |
426 | static int init_vqs(struct ports_device *portdev) |
427 | { | |
428 | vq_callback_t **io_callbacks; | |
429 | char **io_names; | |
430 | struct virtqueue **vqs; | |
431 | u32 nr_ports, nr_queues; | |
432 | int err; | |
433 | ||
434 | /* We currently only have one port and two queues for that port */ | |
435 | nr_ports = 1; | |
436 | nr_queues = 2; | |
437 | ||
438 | vqs = kmalloc(nr_queues * sizeof(struct virtqueue *), GFP_KERNEL); | |
439 | if (!vqs) { | |
440 | err = -ENOMEM; | |
441 | goto fail; | |
442 | } | |
443 | io_callbacks = kmalloc(nr_queues * sizeof(vq_callback_t *), GFP_KERNEL); | |
444 | if (!io_callbacks) { | |
445 | err = -ENOMEM; | |
446 | goto free_vqs; | |
447 | } | |
448 | io_names = kmalloc(nr_queues * sizeof(char *), GFP_KERNEL); | |
449 | if (!io_names) { | |
450 | err = -ENOMEM; | |
451 | goto free_callbacks; | |
452 | } | |
453 | portdev->in_vqs = kmalloc(nr_ports * sizeof(struct virtqueue *), | |
454 | GFP_KERNEL); | |
455 | if (!portdev->in_vqs) { | |
456 | err = -ENOMEM; | |
457 | goto free_names; | |
458 | } | |
459 | portdev->out_vqs = kmalloc(nr_ports * sizeof(struct virtqueue *), | |
460 | GFP_KERNEL); | |
461 | if (!portdev->out_vqs) { | |
462 | err = -ENOMEM; | |
463 | goto free_invqs; | |
464 | } | |
465 | ||
466 | io_callbacks[0] = hvc_handle_input; | |
467 | io_callbacks[1] = NULL; | |
468 | io_names[0] = "input"; | |
469 | io_names[1] = "output"; | |
470 | ||
471 | /* Find the queues. */ | |
472 | err = portdev->vdev->config->find_vqs(portdev->vdev, nr_queues, vqs, | |
473 | io_callbacks, | |
474 | (const char **)io_names); | |
475 | if (err) | |
476 | goto free_outvqs; | |
477 | ||
478 | portdev->in_vqs[0] = vqs[0]; | |
479 | portdev->out_vqs[0] = vqs[1]; | |
480 | ||
481 | kfree(io_callbacks); | |
482 | kfree(io_names); | |
483 | kfree(vqs); | |
484 | ||
485 | return 0; | |
486 | ||
487 | free_names: | |
488 | kfree(io_names); | |
489 | free_callbacks: | |
490 | kfree(io_callbacks); | |
491 | free_outvqs: | |
492 | kfree(portdev->out_vqs); | |
493 | free_invqs: | |
494 | kfree(portdev->in_vqs); | |
495 | free_vqs: | |
496 | kfree(vqs); | |
497 | fail: | |
498 | return err; | |
499 | } | |
500 | ||
1c85bf35 AS |
501 | /* |
502 | * Once we're further in boot, we get probed like any other virtio | |
503 | * device. | |
504 | */ | |
505 | static int __devinit virtcons_probe(struct virtio_device *vdev) | |
506 | { | |
1c85bf35 AS |
507 | struct ports_device *portdev; |
508 | int err; | |
509 | ||
510 | portdev = kmalloc(sizeof(*portdev), GFP_KERNEL); | |
511 | if (!portdev) { | |
512 | err = -ENOMEM; | |
513 | goto fail; | |
514 | } | |
515 | ||
516 | /* Attach this portdev to this virtio_device, and vice-versa. */ | |
517 | portdev->vdev = vdev; | |
518 | vdev->priv = portdev; | |
519 | ||
2658a79a AS |
520 | err = init_vqs(portdev); |
521 | if (err < 0) { | |
522 | dev_err(&vdev->dev, "Error %d initializing vqs\n", err); | |
1c85bf35 | 523 | goto free; |
2658a79a | 524 | } |
1c85bf35 AS |
525 | |
526 | /* We only have one port. */ | |
527 | err = add_port(portdev); | |
528 | if (err) | |
529 | goto free_vqs; | |
530 | ||
971f3390 RR |
531 | /* Start using the new console output. */ |
532 | early_put_chars = NULL; | |
31610434 RR |
533 | return 0; |
534 | ||
d2a7ddda MT |
535 | free_vqs: |
536 | vdev->config->del_vqs(vdev); | |
2658a79a AS |
537 | kfree(portdev->in_vqs); |
538 | kfree(portdev->out_vqs); | |
31610434 | 539 | free: |
1c85bf35 | 540 | kfree(portdev); |
31610434 RR |
541 | fail: |
542 | return err; | |
543 | } | |
544 | ||
545 | static struct virtio_device_id id_table[] = { | |
546 | { VIRTIO_ID_CONSOLE, VIRTIO_DEV_ANY_ID }, | |
547 | { 0 }, | |
548 | }; | |
549 | ||
c2983458 CB |
550 | static unsigned int features[] = { |
551 | VIRTIO_CONSOLE_F_SIZE, | |
552 | }; | |
553 | ||
31610434 | 554 | static struct virtio_driver virtio_console = { |
c2983458 CB |
555 | .feature_table = features, |
556 | .feature_table_size = ARRAY_SIZE(features), | |
31610434 RR |
557 | .driver.name = KBUILD_MODNAME, |
558 | .driver.owner = THIS_MODULE, | |
559 | .id_table = id_table, | |
560 | .probe = virtcons_probe, | |
c2983458 | 561 | .config_changed = virtcons_apply_config, |
31610434 RR |
562 | }; |
563 | ||
564 | static int __init init(void) | |
565 | { | |
38edf58d AS |
566 | INIT_LIST_HEAD(&pdrvdata.consoles); |
567 | ||
31610434 RR |
568 | return register_virtio_driver(&virtio_console); |
569 | } | |
570 | module_init(init); | |
571 | ||
572 | MODULE_DEVICE_TABLE(virtio, id_table); | |
573 | MODULE_DESCRIPTION("Virtio console driver"); | |
574 | MODULE_LICENSE("GPL"); |