diff options
author | Linus Torvalds <torvalds@linux-foundation.org> | 2010-05-21 20:22:52 -0400 |
---|---|---|
committer | Linus Torvalds <torvalds@linux-foundation.org> | 2010-05-21 20:22:52 -0400 |
commit | 1756ac3d3c41341297ea25b818b7fce505bb2a9a (patch) | |
tree | 96382220afbb82fd5c576c4c08b3c3e13282851f /drivers/char | |
parent | 98edb6ca4174f17a64890a02f44c211c8b44fb3c (diff) | |
parent | 0643e4c6e4fd67778fa886a89e6ec2320e0ff4d3 (diff) |
Merge branch 'virtio' of git://git.kernel.org/pub/scm/linux/kernel/git/rusty/linux-2.6-for-linus
* 'virtio' of git://git.kernel.org/pub/scm/linux/kernel/git/rusty/linux-2.6-for-linus: (27 commits)
drivers/char: Eliminate use after free
virtio: console: Accept console size along with resize control message
virtio: console: Store each console's size in the console structure
virtio: console: Resize console port 0 on config intr only if multiport is off
virtio: console: Add support for nonblocking write()s
virtio: console: Rename wait_is_over() to will_read_block()
virtio: console: Don't always create a port 0 if using multiport
virtio: console: Use a control message to add ports
virtio: console: Move code around for future patches
virtio: console: Remove config work handler
virtio: console: Don't call hvc_remove() on unplugging console ports
virtio: console: Return -EPIPE to hvc_console if we lost the connection
virtio: console: Let host know of port or device add failures
virtio: console: Add a __send_control_msg() that can send messages without a valid port
virtio: Revert "virtio: disable multiport console support."
virtio: add_buf_gfp
trans_virtio: use virtqueue_xxx wrappers
virtio-rng: use virtqueue_xxx wrappers
virtio_ring: remove a level of indirection
virtio_net: use virtqueue_xxx wrappers
...
Fix up conflicts in drivers/net/virtio_net.c due to new virtqueue_xxx
wrappers changes conflicting with some other cleanups.
Diffstat (limited to 'drivers/char')
-rw-r--r-- | drivers/char/hw_random/virtio-rng.c | 6 | ||||
-rw-r--r-- | drivers/char/virtio_console.c | 700 |
2 files changed, 380 insertions, 326 deletions
diff --git a/drivers/char/hw_random/virtio-rng.c b/drivers/char/hw_random/virtio-rng.c index 64fe0a793efd..75f1cbd61c17 100644 --- a/drivers/char/hw_random/virtio-rng.c +++ b/drivers/char/hw_random/virtio-rng.c | |||
@@ -32,7 +32,7 @@ static bool busy; | |||
32 | static void random_recv_done(struct virtqueue *vq) | 32 | static void random_recv_done(struct virtqueue *vq) |
33 | { | 33 | { |
34 | /* We can get spurious callbacks, e.g. shared IRQs + virtio_pci. */ | 34 | /* We can get spurious callbacks, e.g. shared IRQs + virtio_pci. */ |
35 | if (!vq->vq_ops->get_buf(vq, &data_avail)) | 35 | if (!virtqueue_get_buf(vq, &data_avail)) |
36 | return; | 36 | return; |
37 | 37 | ||
38 | complete(&have_data); | 38 | complete(&have_data); |
@@ -46,10 +46,10 @@ static void register_buffer(u8 *buf, size_t size) | |||
46 | sg_init_one(&sg, buf, size); | 46 | sg_init_one(&sg, buf, size); |
47 | 47 | ||
48 | /* There should always be room for one buffer. */ | 48 | /* There should always be room for one buffer. */ |
49 | if (vq->vq_ops->add_buf(vq, &sg, 0, 1, buf) < 0) | 49 | if (virtqueue_add_buf(vq, &sg, 0, 1, buf) < 0) |
50 | BUG(); | 50 | BUG(); |
51 | 51 | ||
52 | vq->vq_ops->kick(vq); | 52 | virtqueue_kick(vq); |
53 | } | 53 | } |
54 | 54 | ||
55 | static int virtio_read(struct hwrng *rng, void *buf, size_t size, bool wait) | 55 | static int virtio_read(struct hwrng *rng, void *buf, size_t size, bool wait) |
diff --git a/drivers/char/virtio_console.c b/drivers/char/virtio_console.c index 196428c2287a..8c99bf1b5e9f 100644 --- a/drivers/char/virtio_console.c +++ b/drivers/char/virtio_console.c | |||
@@ -33,35 +33,6 @@ | |||
33 | #include <linux/workqueue.h> | 33 | #include <linux/workqueue.h> |
34 | #include "hvc_console.h" | 34 | #include "hvc_console.h" |
35 | 35 | ||
36 | /* Moved here from .h file in order to disable MULTIPORT. */ | ||
37 | #define VIRTIO_CONSOLE_F_MULTIPORT 1 /* Does host provide multiple ports? */ | ||
38 | |||
39 | struct virtio_console_multiport_conf { | ||
40 | struct virtio_console_config config; | ||
41 | /* max. number of ports this device can hold */ | ||
42 | __u32 max_nr_ports; | ||
43 | /* number of ports added so far */ | ||
44 | __u32 nr_ports; | ||
45 | } __attribute__((packed)); | ||
46 | |||
47 | /* | ||
48 | * A message that's passed between the Host and the Guest for a | ||
49 | * particular port. | ||
50 | */ | ||
51 | struct virtio_console_control { | ||
52 | __u32 id; /* Port number */ | ||
53 | __u16 event; /* The kind of control event (see below) */ | ||
54 | __u16 value; /* Extra information for the key */ | ||
55 | }; | ||
56 | |||
57 | /* Some events for control messages */ | ||
58 | #define VIRTIO_CONSOLE_PORT_READY 0 | ||
59 | #define VIRTIO_CONSOLE_CONSOLE_PORT 1 | ||
60 | #define VIRTIO_CONSOLE_RESIZE 2 | ||
61 | #define VIRTIO_CONSOLE_PORT_OPEN 3 | ||
62 | #define VIRTIO_CONSOLE_PORT_NAME 4 | ||
63 | #define VIRTIO_CONSOLE_PORT_REMOVE 5 | ||
64 | |||
65 | /* | 36 | /* |
66 | * This is a global struct for storing common data for all the devices | 37 | * This is a global struct for storing common data for all the devices |
67 | * this driver handles. | 38 | * this driver handles. |
@@ -107,6 +78,9 @@ struct console { | |||
107 | /* The hvc device associated with this console port */ | 78 | /* The hvc device associated with this console port */ |
108 | struct hvc_struct *hvc; | 79 | struct hvc_struct *hvc; |
109 | 80 | ||
81 | /* The size of the console */ | ||
82 | struct winsize ws; | ||
83 | |||
110 | /* | 84 | /* |
111 | * This number identifies the number that we used to register | 85 | * This number identifies the number that we used to register |
112 | * with hvc in hvc_instantiate() and hvc_alloc(); this is the | 86 | * with hvc in hvc_instantiate() and hvc_alloc(); this is the |
@@ -139,7 +113,6 @@ struct ports_device { | |||
139 | * notification | 113 | * notification |
140 | */ | 114 | */ |
141 | struct work_struct control_work; | 115 | struct work_struct control_work; |
142 | struct work_struct config_work; | ||
143 | 116 | ||
144 | struct list_head ports; | 117 | struct list_head ports; |
145 | 118 | ||
@@ -150,7 +123,7 @@ struct ports_device { | |||
150 | spinlock_t cvq_lock; | 123 | spinlock_t cvq_lock; |
151 | 124 | ||
152 | /* The current config space is stored here */ | 125 | /* The current config space is stored here */ |
153 | struct virtio_console_multiport_conf config; | 126 | struct virtio_console_config config; |
154 | 127 | ||
155 | /* The virtio device we're associated with */ | 128 | /* The virtio device we're associated with */ |
156 | struct virtio_device *vdev; | 129 | struct virtio_device *vdev; |
@@ -189,6 +162,9 @@ struct port { | |||
189 | */ | 162 | */ |
190 | spinlock_t inbuf_lock; | 163 | spinlock_t inbuf_lock; |
191 | 164 | ||
165 | /* Protect the operations on the out_vq. */ | ||
166 | spinlock_t outvq_lock; | ||
167 | |||
192 | /* The IO vqs for this port */ | 168 | /* The IO vqs for this port */ |
193 | struct virtqueue *in_vq, *out_vq; | 169 | struct virtqueue *in_vq, *out_vq; |
194 | 170 | ||
@@ -214,6 +190,8 @@ struct port { | |||
214 | /* The 'id' to identify the port with the Host */ | 190 | /* The 'id' to identify the port with the Host */ |
215 | u32 id; | 191 | u32 id; |
216 | 192 | ||
193 | bool outvq_full; | ||
194 | |||
217 | /* Is the host device open */ | 195 | /* Is the host device open */ |
218 | bool host_connected; | 196 | bool host_connected; |
219 | 197 | ||
@@ -328,7 +306,7 @@ static void *get_inbuf(struct port *port) | |||
328 | unsigned int len; | 306 | unsigned int len; |
329 | 307 | ||
330 | vq = port->in_vq; | 308 | vq = port->in_vq; |
331 | buf = vq->vq_ops->get_buf(vq, &len); | 309 | buf = virtqueue_get_buf(vq, &len); |
332 | if (buf) { | 310 | if (buf) { |
333 | buf->len = len; | 311 | buf->len = len; |
334 | buf->offset = 0; | 312 | buf->offset = 0; |
@@ -349,8 +327,8 @@ static int add_inbuf(struct virtqueue *vq, struct port_buffer *buf) | |||
349 | 327 | ||
350 | sg_init_one(sg, buf->buf, buf->size); | 328 | sg_init_one(sg, buf->buf, buf->size); |
351 | 329 | ||
352 | ret = vq->vq_ops->add_buf(vq, sg, 0, 1, buf); | 330 | ret = virtqueue_add_buf(vq, sg, 0, 1, buf); |
353 | vq->vq_ops->kick(vq); | 331 | virtqueue_kick(vq); |
354 | return ret; | 332 | return ret; |
355 | } | 333 | } |
356 | 334 | ||
@@ -366,7 +344,7 @@ static void discard_port_data(struct port *port) | |||
366 | if (port->inbuf) | 344 | if (port->inbuf) |
367 | buf = port->inbuf; | 345 | buf = port->inbuf; |
368 | else | 346 | else |
369 | buf = vq->vq_ops->get_buf(vq, &len); | 347 | buf = virtqueue_get_buf(vq, &len); |
370 | 348 | ||
371 | ret = 0; | 349 | ret = 0; |
372 | while (buf) { | 350 | while (buf) { |
@@ -374,7 +352,7 @@ static void discard_port_data(struct port *port) | |||
374 | ret++; | 352 | ret++; |
375 | free_buf(buf); | 353 | free_buf(buf); |
376 | } | 354 | } |
377 | buf = vq->vq_ops->get_buf(vq, &len); | 355 | buf = virtqueue_get_buf(vq, &len); |
378 | } | 356 | } |
379 | port->inbuf = NULL; | 357 | port->inbuf = NULL; |
380 | if (ret) | 358 | if (ret) |
@@ -403,57 +381,96 @@ out: | |||
403 | return ret; | 381 | return ret; |
404 | } | 382 | } |
405 | 383 | ||
406 | static ssize_t send_control_msg(struct port *port, unsigned int event, | 384 | static ssize_t __send_control_msg(struct ports_device *portdev, u32 port_id, |
407 | unsigned int value) | 385 | unsigned int event, unsigned int value) |
408 | { | 386 | { |
409 | struct scatterlist sg[1]; | 387 | struct scatterlist sg[1]; |
410 | struct virtio_console_control cpkt; | 388 | struct virtio_console_control cpkt; |
411 | struct virtqueue *vq; | 389 | struct virtqueue *vq; |
412 | unsigned int len; | 390 | unsigned int len; |
413 | 391 | ||
414 | if (!use_multiport(port->portdev)) | 392 | if (!use_multiport(portdev)) |
415 | return 0; | 393 | return 0; |
416 | 394 | ||
417 | cpkt.id = port->id; | 395 | cpkt.id = port_id; |
418 | cpkt.event = event; | 396 | cpkt.event = event; |
419 | cpkt.value = value; | 397 | cpkt.value = value; |
420 | 398 | ||
421 | vq = port->portdev->c_ovq; | 399 | vq = portdev->c_ovq; |
422 | 400 | ||
423 | sg_init_one(sg, &cpkt, sizeof(cpkt)); | 401 | sg_init_one(sg, &cpkt, sizeof(cpkt)); |
424 | if (vq->vq_ops->add_buf(vq, sg, 1, 0, &cpkt) >= 0) { | 402 | if (virtqueue_add_buf(vq, sg, 1, 0, &cpkt) >= 0) { |
425 | vq->vq_ops->kick(vq); | 403 | virtqueue_kick(vq); |
426 | while (!vq->vq_ops->get_buf(vq, &len)) | 404 | while (!virtqueue_get_buf(vq, &len)) |
427 | cpu_relax(); | 405 | cpu_relax(); |
428 | } | 406 | } |
429 | return 0; | 407 | return 0; |
430 | } | 408 | } |
431 | 409 | ||
432 | static ssize_t send_buf(struct port *port, void *in_buf, size_t in_count) | 410 | static ssize_t send_control_msg(struct port *port, unsigned int event, |
411 | unsigned int value) | ||
412 | { | ||
413 | return __send_control_msg(port->portdev, port->id, event, value); | ||
414 | } | ||
415 | |||
416 | /* Callers must take the port->outvq_lock */ | ||
417 | static void reclaim_consumed_buffers(struct port *port) | ||
418 | { | ||
419 | void *buf; | ||
420 | unsigned int len; | ||
421 | |||
422 | while ((buf = virtqueue_get_buf(port->out_vq, &len))) { | ||
423 | kfree(buf); | ||
424 | port->outvq_full = false; | ||
425 | } | ||
426 | } | ||
427 | |||
428 | static ssize_t send_buf(struct port *port, void *in_buf, size_t in_count, | ||
429 | bool nonblock) | ||
433 | { | 430 | { |
434 | struct scatterlist sg[1]; | 431 | struct scatterlist sg[1]; |
435 | struct virtqueue *out_vq; | 432 | struct virtqueue *out_vq; |
436 | ssize_t ret; | 433 | ssize_t ret; |
434 | unsigned long flags; | ||
437 | unsigned int len; | 435 | unsigned int len; |
438 | 436 | ||
439 | out_vq = port->out_vq; | 437 | out_vq = port->out_vq; |
440 | 438 | ||
439 | spin_lock_irqsave(&port->outvq_lock, flags); | ||
440 | |||
441 | reclaim_consumed_buffers(port); | ||
442 | |||
441 | sg_init_one(sg, in_buf, in_count); | 443 | sg_init_one(sg, in_buf, in_count); |
442 | ret = out_vq->vq_ops->add_buf(out_vq, sg, 1, 0, in_buf); | 444 | ret = virtqueue_add_buf(out_vq, sg, 1, 0, in_buf); |
443 | 445 | ||
444 | /* Tell Host to go! */ | 446 | /* Tell Host to go! */ |
445 | out_vq->vq_ops->kick(out_vq); | 447 | virtqueue_kick(out_vq); |
446 | 448 | ||
447 | if (ret < 0) { | 449 | if (ret < 0) { |
448 | in_count = 0; | 450 | in_count = 0; |
449 | goto fail; | 451 | goto done; |
450 | } | 452 | } |
451 | 453 | ||
452 | /* Wait till the host acknowledges it pushed out the data we sent. */ | 454 | if (ret == 0) |
453 | while (!out_vq->vq_ops->get_buf(out_vq, &len)) | 455 | port->outvq_full = true; |
456 | |||
457 | if (nonblock) | ||
458 | goto done; | ||
459 | |||
460 | /* | ||
461 | * Wait till the host acknowledges it pushed out the data we | ||
462 | * sent. This is done for ports in blocking mode or for data | ||
463 | * from the hvc_console; the tty operations are performed with | ||
464 | * spinlocks held so we can't sleep here. | ||
465 | */ | ||
466 | while (!virtqueue_get_buf(out_vq, &len)) | ||
454 | cpu_relax(); | 467 | cpu_relax(); |
455 | fail: | 468 | done: |
456 | /* We're expected to return the amount of data we wrote */ | 469 | spin_unlock_irqrestore(&port->outvq_lock, flags); |
470 | /* | ||
471 | * We're expected to return the amount of data we wrote -- all | ||
472 | * of it | ||
473 | */ | ||
457 | return in_count; | 474 | return in_count; |
458 | } | 475 | } |
459 | 476 | ||
@@ -503,9 +520,28 @@ static ssize_t fill_readbuf(struct port *port, char *out_buf, size_t out_count, | |||
503 | } | 520 | } |
504 | 521 | ||
505 | /* The condition that must be true for polling to end */ | 522 | /* The condition that must be true for polling to end */ |
506 | static bool wait_is_over(struct port *port) | 523 | static bool will_read_block(struct port *port) |
524 | { | ||
525 | return !port_has_data(port) && port->host_connected; | ||
526 | } | ||
527 | |||
528 | static bool will_write_block(struct port *port) | ||
507 | { | 529 | { |
508 | return port_has_data(port) || !port->host_connected; | 530 | bool ret; |
531 | |||
532 | if (!port->host_connected) | ||
533 | return true; | ||
534 | |||
535 | spin_lock_irq(&port->outvq_lock); | ||
536 | /* | ||
537 | * Check if the Host has consumed any buffers since we last | ||
538 | * sent data (this is only applicable for nonblocking ports). | ||
539 | */ | ||
540 | reclaim_consumed_buffers(port); | ||
541 | ret = port->outvq_full; | ||
542 | spin_unlock_irq(&port->outvq_lock); | ||
543 | |||
544 | return ret; | ||
509 | } | 545 | } |
510 | 546 | ||
511 | static ssize_t port_fops_read(struct file *filp, char __user *ubuf, | 547 | static ssize_t port_fops_read(struct file *filp, char __user *ubuf, |
@@ -528,7 +564,7 @@ static ssize_t port_fops_read(struct file *filp, char __user *ubuf, | |||
528 | return -EAGAIN; | 564 | return -EAGAIN; |
529 | 565 | ||
530 | ret = wait_event_interruptible(port->waitqueue, | 566 | ret = wait_event_interruptible(port->waitqueue, |
531 | wait_is_over(port)); | 567 | !will_read_block(port)); |
532 | if (ret < 0) | 568 | if (ret < 0) |
533 | return ret; | 569 | return ret; |
534 | } | 570 | } |
@@ -554,9 +590,22 @@ static ssize_t port_fops_write(struct file *filp, const char __user *ubuf, | |||
554 | struct port *port; | 590 | struct port *port; |
555 | char *buf; | 591 | char *buf; |
556 | ssize_t ret; | 592 | ssize_t ret; |
593 | bool nonblock; | ||
557 | 594 | ||
558 | port = filp->private_data; | 595 | port = filp->private_data; |
559 | 596 | ||
597 | nonblock = filp->f_flags & O_NONBLOCK; | ||
598 | |||
599 | if (will_write_block(port)) { | ||
600 | if (nonblock) | ||
601 | return -EAGAIN; | ||
602 | |||
603 | ret = wait_event_interruptible(port->waitqueue, | ||
604 | !will_write_block(port)); | ||
605 | if (ret < 0) | ||
606 | return ret; | ||
607 | } | ||
608 | |||
560 | count = min((size_t)(32 * 1024), count); | 609 | count = min((size_t)(32 * 1024), count); |
561 | 610 | ||
562 | buf = kmalloc(count, GFP_KERNEL); | 611 | buf = kmalloc(count, GFP_KERNEL); |
@@ -569,9 +618,14 @@ static ssize_t port_fops_write(struct file *filp, const char __user *ubuf, | |||
569 | goto free_buf; | 618 | goto free_buf; |
570 | } | 619 | } |
571 | 620 | ||
572 | ret = send_buf(port, buf, count); | 621 | ret = send_buf(port, buf, count, nonblock); |
622 | |||
623 | if (nonblock && ret > 0) | ||
624 | goto out; | ||
625 | |||
573 | free_buf: | 626 | free_buf: |
574 | kfree(buf); | 627 | kfree(buf); |
628 | out: | ||
575 | return ret; | 629 | return ret; |
576 | } | 630 | } |
577 | 631 | ||
@@ -586,7 +640,7 @@ static unsigned int port_fops_poll(struct file *filp, poll_table *wait) | |||
586 | ret = 0; | 640 | ret = 0; |
587 | if (port->inbuf) | 641 | if (port->inbuf) |
588 | ret |= POLLIN | POLLRDNORM; | 642 | ret |= POLLIN | POLLRDNORM; |
589 | if (port->host_connected) | 643 | if (!will_write_block(port)) |
590 | ret |= POLLOUT; | 644 | ret |= POLLOUT; |
591 | if (!port->host_connected) | 645 | if (!port->host_connected) |
592 | ret |= POLLHUP; | 646 | ret |= POLLHUP; |
@@ -610,6 +664,10 @@ static int port_fops_release(struct inode *inode, struct file *filp) | |||
610 | 664 | ||
611 | spin_unlock_irq(&port->inbuf_lock); | 665 | spin_unlock_irq(&port->inbuf_lock); |
612 | 666 | ||
667 | spin_lock_irq(&port->outvq_lock); | ||
668 | reclaim_consumed_buffers(port); | ||
669 | spin_unlock_irq(&port->outvq_lock); | ||
670 | |||
613 | return 0; | 671 | return 0; |
614 | } | 672 | } |
615 | 673 | ||
@@ -638,6 +696,15 @@ static int port_fops_open(struct inode *inode, struct file *filp) | |||
638 | port->guest_connected = true; | 696 | port->guest_connected = true; |
639 | spin_unlock_irq(&port->inbuf_lock); | 697 | spin_unlock_irq(&port->inbuf_lock); |
640 | 698 | ||
699 | spin_lock_irq(&port->outvq_lock); | ||
700 | /* | ||
701 | * There might be a chance that we missed reclaiming a few | ||
702 | * buffers in the window of the port getting previously closed | ||
703 | * and opening now. | ||
704 | */ | ||
705 | reclaim_consumed_buffers(port); | ||
706 | spin_unlock_irq(&port->outvq_lock); | ||
707 | |||
641 | /* Notify host of port being opened */ | 708 | /* Notify host of port being opened */ |
642 | send_control_msg(filp->private_data, VIRTIO_CONSOLE_PORT_OPEN, 1); | 709 | send_control_msg(filp->private_data, VIRTIO_CONSOLE_PORT_OPEN, 1); |
643 | 710 | ||
@@ -676,9 +743,9 @@ static int put_chars(u32 vtermno, const char *buf, int count) | |||
676 | 743 | ||
677 | port = find_port_by_vtermno(vtermno); | 744 | port = find_port_by_vtermno(vtermno); |
678 | if (!port) | 745 | if (!port) |
679 | return 0; | 746 | return -EPIPE; |
680 | 747 | ||
681 | return send_buf(port, (void *)buf, count); | 748 | return send_buf(port, (void *)buf, count, false); |
682 | } | 749 | } |
683 | 750 | ||
684 | /* | 751 | /* |
@@ -692,9 +759,13 @@ static int get_chars(u32 vtermno, char *buf, int count) | |||
692 | { | 759 | { |
693 | struct port *port; | 760 | struct port *port; |
694 | 761 | ||
762 | /* If we've not set up the port yet, we have no input to give. */ | ||
763 | if (unlikely(early_put_chars)) | ||
764 | return 0; | ||
765 | |||
695 | port = find_port_by_vtermno(vtermno); | 766 | port = find_port_by_vtermno(vtermno); |
696 | if (!port) | 767 | if (!port) |
697 | return 0; | 768 | return -EPIPE; |
698 | 769 | ||
699 | /* If we don't have an input queue yet, we can't get input. */ | 770 | /* If we don't have an input queue yet, we can't get input. */ |
700 | BUG_ON(!port->in_vq); | 771 | BUG_ON(!port->in_vq); |
@@ -705,22 +776,14 @@ static int get_chars(u32 vtermno, char *buf, int count) | |||
705 | static void resize_console(struct port *port) | 776 | static void resize_console(struct port *port) |
706 | { | 777 | { |
707 | struct virtio_device *vdev; | 778 | struct virtio_device *vdev; |
708 | struct winsize ws; | ||
709 | 779 | ||
710 | /* The port could have been hot-unplugged */ | 780 | /* The port could have been hot-unplugged */ |
711 | if (!port) | 781 | if (!port || !is_console_port(port)) |
712 | return; | 782 | return; |
713 | 783 | ||
714 | vdev = port->portdev->vdev; | 784 | vdev = port->portdev->vdev; |
715 | if (virtio_has_feature(vdev, VIRTIO_CONSOLE_F_SIZE)) { | 785 | if (virtio_has_feature(vdev, VIRTIO_CONSOLE_F_SIZE)) |
716 | vdev->config->get(vdev, | 786 | hvc_resize(port->cons.hvc, port->cons.ws); |
717 | offsetof(struct virtio_console_config, cols), | ||
718 | &ws.ws_col, sizeof(u16)); | ||
719 | vdev->config->get(vdev, | ||
720 | offsetof(struct virtio_console_config, rows), | ||
721 | &ws.ws_row, sizeof(u16)); | ||
722 | hvc_resize(port->cons.hvc, ws); | ||
723 | } | ||
724 | } | 787 | } |
725 | 788 | ||
726 | /* We set the configuration at this point, since we now have a tty */ | 789 | /* We set the configuration at this point, since we now have a tty */ |
@@ -804,6 +867,13 @@ int init_port_console(struct port *port) | |||
804 | spin_unlock_irq(&pdrvdata_lock); | 867 | spin_unlock_irq(&pdrvdata_lock); |
805 | port->guest_connected = true; | 868 | port->guest_connected = true; |
806 | 869 | ||
870 | /* | ||
871 | * Start using the new console output if this is the first | ||
872 | * console to come up. | ||
873 | */ | ||
874 | if (early_put_chars) | ||
875 | early_put_chars = NULL; | ||
876 | |||
807 | /* Notify host of port being opened */ | 877 | /* Notify host of port being opened */ |
808 | send_control_msg(port, VIRTIO_CONSOLE_PORT_OPEN, 1); | 878 | send_control_msg(port, VIRTIO_CONSOLE_PORT_OPEN, 1); |
809 | 879 | ||
@@ -859,6 +929,8 @@ static ssize_t debugfs_read(struct file *filp, char __user *ubuf, | |||
859 | out_offset += snprintf(buf + out_offset, out_count - out_offset, | 929 | out_offset += snprintf(buf + out_offset, out_count - out_offset, |
860 | "host_connected: %d\n", port->host_connected); | 930 | "host_connected: %d\n", port->host_connected); |
861 | out_offset += snprintf(buf + out_offset, out_count - out_offset, | 931 | out_offset += snprintf(buf + out_offset, out_count - out_offset, |
932 | "outvq_full: %d\n", port->outvq_full); | ||
933 | out_offset += snprintf(buf + out_offset, out_count - out_offset, | ||
862 | "is_console: %s\n", | 934 | "is_console: %s\n", |
863 | is_console_port(port) ? "yes" : "no"); | 935 | is_console_port(port) ? "yes" : "no"); |
864 | out_offset += snprintf(buf + out_offset, out_count - out_offset, | 936 | out_offset += snprintf(buf + out_offset, out_count - out_offset, |
@@ -875,6 +947,153 @@ static const struct file_operations port_debugfs_ops = { | |||
875 | .read = debugfs_read, | 947 | .read = debugfs_read, |
876 | }; | 948 | }; |
877 | 949 | ||
950 | static void set_console_size(struct port *port, u16 rows, u16 cols) | ||
951 | { | ||
952 | if (!port || !is_console_port(port)) | ||
953 | return; | ||
954 | |||
955 | port->cons.ws.ws_row = rows; | ||
956 | port->cons.ws.ws_col = cols; | ||
957 | } | ||
958 | |||
959 | static unsigned int fill_queue(struct virtqueue *vq, spinlock_t *lock) | ||
960 | { | ||
961 | struct port_buffer *buf; | ||
962 | unsigned int nr_added_bufs; | ||
963 | int ret; | ||
964 | |||
965 | nr_added_bufs = 0; | ||
966 | do { | ||
967 | buf = alloc_buf(PAGE_SIZE); | ||
968 | if (!buf) | ||
969 | break; | ||
970 | |||
971 | spin_lock_irq(lock); | ||
972 | ret = add_inbuf(vq, buf); | ||
973 | if (ret < 0) { | ||
974 | spin_unlock_irq(lock); | ||
975 | free_buf(buf); | ||
976 | break; | ||
977 | } | ||
978 | nr_added_bufs++; | ||
979 | spin_unlock_irq(lock); | ||
980 | } while (ret > 0); | ||
981 | |||
982 | return nr_added_bufs; | ||
983 | } | ||
984 | |||
985 | static int add_port(struct ports_device *portdev, u32 id) | ||
986 | { | ||
987 | char debugfs_name[16]; | ||
988 | struct port *port; | ||
989 | struct port_buffer *buf; | ||
990 | dev_t devt; | ||
991 | unsigned int nr_added_bufs; | ||
992 | int err; | ||
993 | |||
994 | port = kmalloc(sizeof(*port), GFP_KERNEL); | ||
995 | if (!port) { | ||
996 | err = -ENOMEM; | ||
997 | goto fail; | ||
998 | } | ||
999 | |||
1000 | port->portdev = portdev; | ||
1001 | port->id = id; | ||
1002 | |||
1003 | port->name = NULL; | ||
1004 | port->inbuf = NULL; | ||
1005 | port->cons.hvc = NULL; | ||
1006 | |||
1007 | port->cons.ws.ws_row = port->cons.ws.ws_col = 0; | ||
1008 | |||
1009 | port->host_connected = port->guest_connected = false; | ||
1010 | |||
1011 | port->outvq_full = false; | ||
1012 | |||
1013 | port->in_vq = portdev->in_vqs[port->id]; | ||
1014 | port->out_vq = portdev->out_vqs[port->id]; | ||
1015 | |||
1016 | cdev_init(&port->cdev, &port_fops); | ||
1017 | |||
1018 | devt = MKDEV(portdev->chr_major, id); | ||
1019 | err = cdev_add(&port->cdev, devt, 1); | ||
1020 | if (err < 0) { | ||
1021 | dev_err(&port->portdev->vdev->dev, | ||
1022 | "Error %d adding cdev for port %u\n", err, id); | ||
1023 | goto free_port; | ||
1024 | } | ||
1025 | port->dev = device_create(pdrvdata.class, &port->portdev->vdev->dev, | ||
1026 | devt, port, "vport%up%u", | ||
1027 | port->portdev->drv_index, id); | ||
1028 | if (IS_ERR(port->dev)) { | ||
1029 | err = PTR_ERR(port->dev); | ||
1030 | dev_err(&port->portdev->vdev->dev, | ||
1031 | "Error %d creating device for port %u\n", | ||
1032 | err, id); | ||
1033 | goto free_cdev; | ||
1034 | } | ||
1035 | |||
1036 | spin_lock_init(&port->inbuf_lock); | ||
1037 | spin_lock_init(&port->outvq_lock); | ||
1038 | init_waitqueue_head(&port->waitqueue); | ||
1039 | |||
1040 | /* Fill the in_vq with buffers so the host can send us data. */ | ||
1041 | nr_added_bufs = fill_queue(port->in_vq, &port->inbuf_lock); | ||
1042 | if (!nr_added_bufs) { | ||
1043 | dev_err(port->dev, "Error allocating inbufs\n"); | ||
1044 | err = -ENOMEM; | ||
1045 | goto free_device; | ||
1046 | } | ||
1047 | |||
1048 | /* | ||
1049 | * If we're not using multiport support, this has to be a console port | ||
1050 | */ | ||
1051 | if (!use_multiport(port->portdev)) { | ||
1052 | err = init_port_console(port); | ||
1053 | if (err) | ||
1054 | goto free_inbufs; | ||
1055 | } | ||
1056 | |||
1057 | spin_lock_irq(&portdev->ports_lock); | ||
1058 | list_add_tail(&port->list, &port->portdev->ports); | ||
1059 | spin_unlock_irq(&portdev->ports_lock); | ||
1060 | |||
1061 | /* | ||
1062 | * Tell the Host we're set so that it can send us various | ||
1063 | * configuration parameters for this port (eg, port name, | ||
1064 | * caching, whether this is a console port, etc.) | ||
1065 | */ | ||
1066 | send_control_msg(port, VIRTIO_CONSOLE_PORT_READY, 1); | ||
1067 | |||
1068 | if (pdrvdata.debugfs_dir) { | ||
1069 | /* | ||
1070 | * Finally, create the debugfs file that we can use to | ||
1071 | * inspect a port's state at any time | ||
1072 | */ | ||
1073 | sprintf(debugfs_name, "vport%up%u", | ||
1074 | port->portdev->drv_index, id); | ||
1075 | port->debugfs_file = debugfs_create_file(debugfs_name, 0444, | ||
1076 | pdrvdata.debugfs_dir, | ||
1077 | port, | ||
1078 | &port_debugfs_ops); | ||
1079 | } | ||
1080 | return 0; | ||
1081 | |||
1082 | free_inbufs: | ||
1083 | while ((buf = virtqueue_detach_unused_buf(port->in_vq))) | ||
1084 | free_buf(buf); | ||
1085 | free_device: | ||
1086 | device_destroy(pdrvdata.class, port->dev->devt); | ||
1087 | free_cdev: | ||
1088 | cdev_del(&port->cdev); | ||
1089 | free_port: | ||
1090 | kfree(port); | ||
1091 | fail: | ||
1092 | /* The host might want to notify management sw about port add failure */ | ||
1093 | __send_control_msg(portdev, id, VIRTIO_CONSOLE_PORT_READY, 0); | ||
1094 | return err; | ||
1095 | } | ||
1096 | |||
878 | /* Remove all port-specific data. */ | 1097 | /* Remove all port-specific data. */ |
879 | static int remove_port(struct port *port) | 1098 | static int remove_port(struct port *port) |
880 | { | 1099 | { |
@@ -888,7 +1107,18 @@ static int remove_port(struct port *port) | |||
888 | spin_lock_irq(&pdrvdata_lock); | 1107 | spin_lock_irq(&pdrvdata_lock); |
889 | list_del(&port->cons.list); | 1108 | list_del(&port->cons.list); |
890 | spin_unlock_irq(&pdrvdata_lock); | 1109 | spin_unlock_irq(&pdrvdata_lock); |
1110 | #if 0 | ||
1111 | /* | ||
1112 | * hvc_remove() not called as removing one hvc port | ||
1113 | * results in other hvc ports getting frozen. | ||
1114 | * | ||
1115 | * Once this is resolved in hvc, this functionality | ||
1116 | * will be enabled. Till that is done, the -EPIPE | ||
1117 | * return from get_chars() above will help | ||
1118 | * hvc_console.c to clean up on ports we remove here. | ||
1119 | */ | ||
891 | hvc_remove(port->cons.hvc); | 1120 | hvc_remove(port->cons.hvc); |
1121 | #endif | ||
892 | } | 1122 | } |
893 | if (port->guest_connected) | 1123 | if (port->guest_connected) |
894 | send_control_msg(port, VIRTIO_CONSOLE_PORT_OPEN, 0); | 1124 | send_control_msg(port, VIRTIO_CONSOLE_PORT_OPEN, 0); |
@@ -900,8 +1130,10 @@ static int remove_port(struct port *port) | |||
900 | /* Remove unused data this port might have received. */ | 1130 | /* Remove unused data this port might have received. */ |
901 | discard_port_data(port); | 1131 | discard_port_data(port); |
902 | 1132 | ||
1133 | reclaim_consumed_buffers(port); | ||
1134 | |||
903 | /* Remove buffers we queued up for the Host to send us data in. */ | 1135 | /* Remove buffers we queued up for the Host to send us data in. */ |
904 | while ((buf = port->in_vq->vq_ops->detach_unused_buf(port->in_vq))) | 1136 | while ((buf = virtqueue_detach_unused_buf(port->in_vq))) |
905 | free_buf(buf); | 1137 | free_buf(buf); |
906 | 1138 | ||
907 | kfree(port->name); | 1139 | kfree(port->name); |
@@ -924,7 +1156,7 @@ static void handle_control_message(struct ports_device *portdev, | |||
924 | cpkt = (struct virtio_console_control *)(buf->buf + buf->offset); | 1156 | cpkt = (struct virtio_console_control *)(buf->buf + buf->offset); |
925 | 1157 | ||
926 | port = find_port_by_id(portdev, cpkt->id); | 1158 | port = find_port_by_id(portdev, cpkt->id); |
927 | if (!port) { | 1159 | if (!port && cpkt->event != VIRTIO_CONSOLE_PORT_ADD) { |
928 | /* No valid header at start of buffer. Drop it. */ | 1160 | /* No valid header at start of buffer. Drop it. */ |
929 | dev_dbg(&portdev->vdev->dev, | 1161 | dev_dbg(&portdev->vdev->dev, |
930 | "Invalid index %u in control packet\n", cpkt->id); | 1162 | "Invalid index %u in control packet\n", cpkt->id); |
@@ -932,6 +1164,24 @@ static void handle_control_message(struct ports_device *portdev, | |||
932 | } | 1164 | } |
933 | 1165 | ||
934 | switch (cpkt->event) { | 1166 | switch (cpkt->event) { |
1167 | case VIRTIO_CONSOLE_PORT_ADD: | ||
1168 | if (port) { | ||
1169 | dev_dbg(&portdev->vdev->dev, | ||
1170 | "Port %u already added\n", port->id); | ||
1171 | send_control_msg(port, VIRTIO_CONSOLE_PORT_READY, 1); | ||
1172 | break; | ||
1173 | } | ||
1174 | if (cpkt->id >= portdev->config.max_nr_ports) { | ||
1175 | dev_warn(&portdev->vdev->dev, | ||
1176 | "Request for adding port with out-of-bound id %u, max. supported id: %u\n", | ||
1177 | cpkt->id, portdev->config.max_nr_ports - 1); | ||
1178 | break; | ||
1179 | } | ||
1180 | add_port(portdev, cpkt->id); | ||
1181 | break; | ||
1182 | case VIRTIO_CONSOLE_PORT_REMOVE: | ||
1183 | remove_port(port); | ||
1184 | break; | ||
935 | case VIRTIO_CONSOLE_CONSOLE_PORT: | 1185 | case VIRTIO_CONSOLE_CONSOLE_PORT: |
936 | if (!cpkt->value) | 1186 | if (!cpkt->value) |
937 | break; | 1187 | break; |
@@ -944,15 +1194,34 @@ static void handle_control_message(struct ports_device *portdev, | |||
944 | * have to notify the host first. | 1194 | * have to notify the host first. |
945 | */ | 1195 | */ |
946 | break; | 1196 | break; |
947 | case VIRTIO_CONSOLE_RESIZE: | 1197 | case VIRTIO_CONSOLE_RESIZE: { |
1198 | struct { | ||
1199 | __u16 rows; | ||
1200 | __u16 cols; | ||
1201 | } size; | ||
1202 | |||
948 | if (!is_console_port(port)) | 1203 | if (!is_console_port(port)) |
949 | break; | 1204 | break; |
1205 | |||
1206 | memcpy(&size, buf->buf + buf->offset + sizeof(*cpkt), | ||
1207 | sizeof(size)); | ||
1208 | set_console_size(port, size.rows, size.cols); | ||
1209 | |||
950 | port->cons.hvc->irq_requested = 1; | 1210 | port->cons.hvc->irq_requested = 1; |
951 | resize_console(port); | 1211 | resize_console(port); |
952 | break; | 1212 | break; |
1213 | } | ||
953 | case VIRTIO_CONSOLE_PORT_OPEN: | 1214 | case VIRTIO_CONSOLE_PORT_OPEN: |
954 | port->host_connected = cpkt->value; | 1215 | port->host_connected = cpkt->value; |
955 | wake_up_interruptible(&port->waitqueue); | 1216 | wake_up_interruptible(&port->waitqueue); |
1217 | /* | ||
1218 | * If the host port got closed and the host had any | ||
1219 | * unconsumed buffers, we'll be able to reclaim them | ||
1220 | * now. | ||
1221 | */ | ||
1222 | spin_lock_irq(&port->outvq_lock); | ||
1223 | reclaim_consumed_buffers(port); | ||
1224 | spin_unlock_irq(&port->outvq_lock); | ||
956 | break; | 1225 | break; |
957 | case VIRTIO_CONSOLE_PORT_NAME: | 1226 | case VIRTIO_CONSOLE_PORT_NAME: |
958 | /* | 1227 | /* |
@@ -990,32 +1259,6 @@ static void handle_control_message(struct ports_device *portdev, | |||
990 | kobject_uevent(&port->dev->kobj, KOBJ_CHANGE); | 1259 | kobject_uevent(&port->dev->kobj, KOBJ_CHANGE); |
991 | } | 1260 | } |
992 | break; | 1261 | break; |
993 | case VIRTIO_CONSOLE_PORT_REMOVE: | ||
994 | /* | ||
995 | * Hot unplug the port. We don't decrement nr_ports | ||
996 | * since we don't want to deal with extra complexities | ||
997 | * of using the lowest-available port id: We can just | ||
998 | * pick up the nr_ports number as the id and not have | ||
999 | * userspace send it to us. This helps us in two | ||
1000 | * ways: | ||
1001 | * | ||
1002 | * - We don't need to have a 'port_id' field in the | ||
1003 | * config space when a port is hot-added. This is a | ||
1004 | * good thing as we might queue up multiple hotplug | ||
1005 | * requests issued in our workqueue. | ||
1006 | * | ||
1007 | * - Another way to deal with this would have been to | ||
1008 | * use a bitmap of the active ports and select the | ||
1009 | * lowest non-active port from that map. That | ||
1010 | * bloats the already tight config space and we | ||
1011 | * would end up artificially limiting the | ||
1012 | * max. number of ports to sizeof(bitmap). Right | ||
1013 | * now we can support 2^32 ports (as the port id is | ||
1014 | * stored in a u32 type). | ||
1015 | * | ||
1016 | */ | ||
1017 | remove_port(port); | ||
1018 | break; | ||
1019 | } | 1262 | } |
1020 | } | 1263 | } |
1021 | 1264 | ||
@@ -1030,7 +1273,7 @@ static void control_work_handler(struct work_struct *work) | |||
1030 | vq = portdev->c_ivq; | 1273 | vq = portdev->c_ivq; |
1031 | 1274 | ||
1032 | spin_lock(&portdev->cvq_lock); | 1275 | spin_lock(&portdev->cvq_lock); |
1033 | while ((buf = vq->vq_ops->get_buf(vq, &len))) { | 1276 | while ((buf = virtqueue_get_buf(vq, &len))) { |
1034 | spin_unlock(&portdev->cvq_lock); | 1277 | spin_unlock(&portdev->cvq_lock); |
1035 | 1278 | ||
1036 | buf->len = len; | 1279 | buf->len = len; |
@@ -1092,204 +1335,29 @@ static void config_intr(struct virtio_device *vdev) | |||
1092 | struct ports_device *portdev; | 1335 | struct ports_device *portdev; |
1093 | 1336 | ||
1094 | portdev = vdev->priv; | 1337 | portdev = vdev->priv; |
1095 | if (use_multiport(portdev)) { | ||
1096 | /* Handle port hot-add */ | ||
1097 | schedule_work(&portdev->config_work); | ||
1098 | } | ||
1099 | /* | ||
1100 | * We'll use this way of resizing only for legacy support. | ||
1101 | * For newer userspace (VIRTIO_CONSOLE_F_MULTPORT+), use | ||
1102 | * control messages to indicate console size changes so that | ||
1103 | * it can be done per-port | ||
1104 | */ | ||
1105 | resize_console(find_port_by_id(portdev, 0)); | ||
1106 | } | ||
1107 | |||
1108 | static unsigned int fill_queue(struct virtqueue *vq, spinlock_t *lock) | ||
1109 | { | ||
1110 | struct port_buffer *buf; | ||
1111 | unsigned int nr_added_bufs; | ||
1112 | int ret; | ||
1113 | |||
1114 | nr_added_bufs = 0; | ||
1115 | do { | ||
1116 | buf = alloc_buf(PAGE_SIZE); | ||
1117 | if (!buf) | ||
1118 | break; | ||
1119 | |||
1120 | spin_lock_irq(lock); | ||
1121 | ret = add_inbuf(vq, buf); | ||
1122 | if (ret < 0) { | ||
1123 | spin_unlock_irq(lock); | ||
1124 | free_buf(buf); | ||
1125 | break; | ||
1126 | } | ||
1127 | nr_added_bufs++; | ||
1128 | spin_unlock_irq(lock); | ||
1129 | } while (ret > 0); | ||
1130 | |||
1131 | return nr_added_bufs; | ||
1132 | } | ||
1133 | |||
1134 | static int add_port(struct ports_device *portdev, u32 id) | ||
1135 | { | ||
1136 | char debugfs_name[16]; | ||
1137 | struct port *port; | ||
1138 | struct port_buffer *buf; | ||
1139 | dev_t devt; | ||
1140 | unsigned int nr_added_bufs; | ||
1141 | int err; | ||
1142 | |||
1143 | port = kmalloc(sizeof(*port), GFP_KERNEL); | ||
1144 | if (!port) { | ||
1145 | err = -ENOMEM; | ||
1146 | goto fail; | ||
1147 | } | ||
1148 | |||
1149 | port->portdev = portdev; | ||
1150 | port->id = id; | ||
1151 | |||
1152 | port->name = NULL; | ||
1153 | port->inbuf = NULL; | ||
1154 | port->cons.hvc = NULL; | ||
1155 | |||
1156 | port->host_connected = port->guest_connected = false; | ||
1157 | |||
1158 | port->in_vq = portdev->in_vqs[port->id]; | ||
1159 | port->out_vq = portdev->out_vqs[port->id]; | ||
1160 | |||
1161 | cdev_init(&port->cdev, &port_fops); | ||
1162 | |||
1163 | devt = MKDEV(portdev->chr_major, id); | ||
1164 | err = cdev_add(&port->cdev, devt, 1); | ||
1165 | if (err < 0) { | ||
1166 | dev_err(&port->portdev->vdev->dev, | ||
1167 | "Error %d adding cdev for port %u\n", err, id); | ||
1168 | goto free_port; | ||
1169 | } | ||
1170 | port->dev = device_create(pdrvdata.class, &port->portdev->vdev->dev, | ||
1171 | devt, port, "vport%up%u", | ||
1172 | port->portdev->drv_index, id); | ||
1173 | if (IS_ERR(port->dev)) { | ||
1174 | err = PTR_ERR(port->dev); | ||
1175 | dev_err(&port->portdev->vdev->dev, | ||
1176 | "Error %d creating device for port %u\n", | ||
1177 | err, id); | ||
1178 | goto free_cdev; | ||
1179 | } | ||
1180 | |||
1181 | spin_lock_init(&port->inbuf_lock); | ||
1182 | init_waitqueue_head(&port->waitqueue); | ||
1183 | |||
1184 | /* Fill the in_vq with buffers so the host can send us data. */ | ||
1185 | nr_added_bufs = fill_queue(port->in_vq, &port->inbuf_lock); | ||
1186 | if (!nr_added_bufs) { | ||
1187 | dev_err(port->dev, "Error allocating inbufs\n"); | ||
1188 | err = -ENOMEM; | ||
1189 | goto free_device; | ||
1190 | } | ||
1191 | |||
1192 | /* | ||
1193 | * If we're not using multiport support, this has to be a console port | ||
1194 | */ | ||
1195 | if (!use_multiport(port->portdev)) { | ||
1196 | err = init_port_console(port); | ||
1197 | if (err) | ||
1198 | goto free_inbufs; | ||
1199 | } | ||
1200 | |||
1201 | spin_lock_irq(&portdev->ports_lock); | ||
1202 | list_add_tail(&port->list, &port->portdev->ports); | ||
1203 | spin_unlock_irq(&portdev->ports_lock); | ||
1204 | |||
1205 | /* | ||
1206 | * Tell the Host we're set so that it can send us various | ||
1207 | * configuration parameters for this port (eg, port name, | ||
1208 | * caching, whether this is a console port, etc.) | ||
1209 | */ | ||
1210 | send_control_msg(port, VIRTIO_CONSOLE_PORT_READY, 1); | ||
1211 | |||
1212 | if (pdrvdata.debugfs_dir) { | ||
1213 | /* | ||
1214 | * Finally, create the debugfs file that we can use to | ||
1215 | * inspect a port's state at any time | ||
1216 | */ | ||
1217 | sprintf(debugfs_name, "vport%up%u", | ||
1218 | port->portdev->drv_index, id); | ||
1219 | port->debugfs_file = debugfs_create_file(debugfs_name, 0444, | ||
1220 | pdrvdata.debugfs_dir, | ||
1221 | port, | ||
1222 | &port_debugfs_ops); | ||
1223 | } | ||
1224 | return 0; | ||
1225 | |||
1226 | free_inbufs: | ||
1227 | while ((buf = port->in_vq->vq_ops->detach_unused_buf(port->in_vq))) | ||
1228 | free_buf(buf); | ||
1229 | free_device: | ||
1230 | device_destroy(pdrvdata.class, port->dev->devt); | ||
1231 | free_cdev: | ||
1232 | cdev_del(&port->cdev); | ||
1233 | free_port: | ||
1234 | kfree(port); | ||
1235 | fail: | ||
1236 | return err; | ||
1237 | } | ||
1238 | 1338 | ||
1239 | /* | 1339 | if (!use_multiport(portdev)) { |
1240 | * The workhandler for config-space updates. | 1340 | struct port *port; |
1241 | * | 1341 | u16 rows, cols; |
1242 | * This is called when ports are hot-added. | ||
1243 | */ | ||
1244 | static void config_work_handler(struct work_struct *work) | ||
1245 | { | ||
1246 | struct virtio_console_multiport_conf virtconconf; | ||
1247 | struct ports_device *portdev; | ||
1248 | struct virtio_device *vdev; | ||
1249 | int err; | ||
1250 | 1342 | ||
1251 | portdev = container_of(work, struct ports_device, config_work); | 1343 | vdev->config->get(vdev, |
1344 | offsetof(struct virtio_console_config, cols), | ||
1345 | &cols, sizeof(u16)); | ||
1346 | vdev->config->get(vdev, | ||
1347 | offsetof(struct virtio_console_config, rows), | ||
1348 | &rows, sizeof(u16)); | ||
1252 | 1349 | ||
1253 | vdev = portdev->vdev; | 1350 | port = find_port_by_id(portdev, 0); |
1254 | vdev->config->get(vdev, | 1351 | set_console_size(port, rows, cols); |
1255 | offsetof(struct virtio_console_multiport_conf, | ||
1256 | nr_ports), | ||
1257 | &virtconconf.nr_ports, | ||
1258 | sizeof(virtconconf.nr_ports)); | ||
1259 | 1352 | ||
1260 | if (portdev->config.nr_ports == virtconconf.nr_ports) { | ||
1261 | /* | 1353 | /* |
1262 | * Port 0 got hot-added. Since we already did all the | 1354 | * We'll use this way of resizing only for legacy |
1263 | * other initialisation for it, just tell the Host | 1355 | * support. For newer userspace |
1264 | * that the port is ready if we find the port. In | 1356 | * (VIRTIO_CONSOLE_F_MULTPORT+), use control messages |
1265 | * case the port was hot-removed earlier, we call | 1357 | * to indicate console size changes so that it can be |
1266 | * add_port to add the port. | 1358 | * done per-port. |
1267 | */ | 1359 | */ |
1268 | struct port *port; | 1360 | resize_console(port); |
1269 | |||
1270 | port = find_port_by_id(portdev, 0); | ||
1271 | if (!port) | ||
1272 | add_port(portdev, 0); | ||
1273 | else | ||
1274 | send_control_msg(port, VIRTIO_CONSOLE_PORT_READY, 1); | ||
1275 | return; | ||
1276 | } | ||
1277 | if (virtconconf.nr_ports > portdev->config.max_nr_ports) { | ||
1278 | dev_warn(&vdev->dev, | ||
1279 | "More ports specified (%u) than allowed (%u)", | ||
1280 | portdev->config.nr_ports + 1, | ||
1281 | portdev->config.max_nr_ports); | ||
1282 | return; | ||
1283 | } | ||
1284 | if (virtconconf.nr_ports < portdev->config.nr_ports) | ||
1285 | return; | ||
1286 | |||
1287 | /* Hot-add ports */ | ||
1288 | while (virtconconf.nr_ports - portdev->config.nr_ports) { | ||
1289 | err = add_port(portdev, portdev->config.nr_ports); | ||
1290 | if (err) | ||
1291 | break; | ||
1292 | portdev->config.nr_ports++; | ||
1293 | } | 1361 | } |
1294 | } | 1362 | } |
1295 | 1363 | ||
@@ -1414,7 +1482,6 @@ static const struct file_operations portdev_fops = { | |||
1414 | static int __devinit virtcons_probe(struct virtio_device *vdev) | 1482 | static int __devinit virtcons_probe(struct virtio_device *vdev) |
1415 | { | 1483 | { |
1416 | struct ports_device *portdev; | 1484 | struct ports_device *portdev; |
1417 | u32 i; | ||
1418 | int err; | 1485 | int err; |
1419 | bool multiport; | 1486 | bool multiport; |
1420 | 1487 | ||
@@ -1443,37 +1510,19 @@ static int __devinit virtcons_probe(struct virtio_device *vdev) | |||
1443 | } | 1510 | } |
1444 | 1511 | ||
1445 | multiport = false; | 1512 | multiport = false; |
1446 | portdev->config.nr_ports = 1; | ||
1447 | portdev->config.max_nr_ports = 1; | 1513 | portdev->config.max_nr_ports = 1; |
1448 | #if 0 /* Multiport is not quite ready yet --RR */ | ||
1449 | if (virtio_has_feature(vdev, VIRTIO_CONSOLE_F_MULTIPORT)) { | 1514 | if (virtio_has_feature(vdev, VIRTIO_CONSOLE_F_MULTIPORT)) { |
1450 | multiport = true; | 1515 | multiport = true; |
1451 | vdev->features[0] |= 1 << VIRTIO_CONSOLE_F_MULTIPORT; | 1516 | vdev->features[0] |= 1 << VIRTIO_CONSOLE_F_MULTIPORT; |
1452 | 1517 | ||
1453 | vdev->config->get(vdev, | 1518 | vdev->config->get(vdev, offsetof(struct virtio_console_config, |
1454 | offsetof(struct virtio_console_multiport_conf, | 1519 | max_nr_ports), |
1455 | nr_ports), | ||
1456 | &portdev->config.nr_ports, | ||
1457 | sizeof(portdev->config.nr_ports)); | ||
1458 | vdev->config->get(vdev, | ||
1459 | offsetof(struct virtio_console_multiport_conf, | ||
1460 | max_nr_ports), | ||
1461 | &portdev->config.max_nr_ports, | 1520 | &portdev->config.max_nr_ports, |
1462 | sizeof(portdev->config.max_nr_ports)); | 1521 | sizeof(portdev->config.max_nr_ports)); |
1463 | if (portdev->config.nr_ports > portdev->config.max_nr_ports) { | ||
1464 | dev_warn(&vdev->dev, | ||
1465 | "More ports (%u) specified than allowed (%u). Will init %u ports.", | ||
1466 | portdev->config.nr_ports, | ||
1467 | portdev->config.max_nr_ports, | ||
1468 | portdev->config.max_nr_ports); | ||
1469 | |||
1470 | portdev->config.nr_ports = portdev->config.max_nr_ports; | ||
1471 | } | ||
1472 | } | 1522 | } |
1473 | 1523 | ||
1474 | /* Let the Host know we support multiple ports.*/ | 1524 | /* Let the Host know we support multiple ports.*/ |
1475 | vdev->config->finalize_features(vdev); | 1525 | vdev->config->finalize_features(vdev); |
1476 | #endif | ||
1477 | 1526 | ||
1478 | err = init_vqs(portdev); | 1527 | err = init_vqs(portdev); |
1479 | if (err < 0) { | 1528 | if (err < 0) { |
@@ -1489,7 +1538,6 @@ static int __devinit virtcons_probe(struct virtio_device *vdev) | |||
1489 | 1538 | ||
1490 | spin_lock_init(&portdev->cvq_lock); | 1539 | spin_lock_init(&portdev->cvq_lock); |
1491 | INIT_WORK(&portdev->control_work, &control_work_handler); | 1540 | INIT_WORK(&portdev->control_work, &control_work_handler); |
1492 | INIT_WORK(&portdev->config_work, &config_work_handler); | ||
1493 | 1541 | ||
1494 | nr_added_bufs = fill_queue(portdev->c_ivq, &portdev->cvq_lock); | 1542 | nr_added_bufs = fill_queue(portdev->c_ivq, &portdev->cvq_lock); |
1495 | if (!nr_added_bufs) { | 1543 | if (!nr_added_bufs) { |
@@ -1498,16 +1546,22 @@ static int __devinit virtcons_probe(struct virtio_device *vdev) | |||
1498 | err = -ENOMEM; | 1546 | err = -ENOMEM; |
1499 | goto free_vqs; | 1547 | goto free_vqs; |
1500 | } | 1548 | } |
1549 | } else { | ||
1550 | /* | ||
1551 | * For backward compatibility: Create a console port | ||
1552 | * if we're running on older host. | ||
1553 | */ | ||
1554 | add_port(portdev, 0); | ||
1501 | } | 1555 | } |
1502 | 1556 | ||
1503 | for (i = 0; i < portdev->config.nr_ports; i++) | 1557 | __send_control_msg(portdev, VIRTIO_CONSOLE_BAD_ID, |
1504 | add_port(portdev, i); | 1558 | VIRTIO_CONSOLE_DEVICE_READY, 1); |
1505 | |||
1506 | /* Start using the new console output. */ | ||
1507 | early_put_chars = NULL; | ||
1508 | return 0; | 1559 | return 0; |
1509 | 1560 | ||
1510 | free_vqs: | 1561 | free_vqs: |
1562 | /* The host might want to notify mgmt sw about device add failure */ | ||
1563 | __send_control_msg(portdev, VIRTIO_CONSOLE_BAD_ID, | ||
1564 | VIRTIO_CONSOLE_DEVICE_READY, 0); | ||
1511 | vdev->config->del_vqs(vdev); | 1565 | vdev->config->del_vqs(vdev); |
1512 | kfree(portdev->in_vqs); | 1566 | kfree(portdev->in_vqs); |
1513 | kfree(portdev->out_vqs); | 1567 | kfree(portdev->out_vqs); |
@@ -1529,17 +1583,16 @@ static void virtcons_remove(struct virtio_device *vdev) | |||
1529 | portdev = vdev->priv; | 1583 | portdev = vdev->priv; |
1530 | 1584 | ||
1531 | cancel_work_sync(&portdev->control_work); | 1585 | cancel_work_sync(&portdev->control_work); |
1532 | cancel_work_sync(&portdev->config_work); | ||
1533 | 1586 | ||
1534 | list_for_each_entry_safe(port, port2, &portdev->ports, list) | 1587 | list_for_each_entry_safe(port, port2, &portdev->ports, list) |
1535 | remove_port(port); | 1588 | remove_port(port); |
1536 | 1589 | ||
1537 | unregister_chrdev(portdev->chr_major, "virtio-portsdev"); | 1590 | unregister_chrdev(portdev->chr_major, "virtio-portsdev"); |
1538 | 1591 | ||
1539 | while ((buf = portdev->c_ivq->vq_ops->get_buf(portdev->c_ivq, &len))) | 1592 | while ((buf = virtqueue_get_buf(portdev->c_ivq, &len))) |
1540 | free_buf(buf); | 1593 | free_buf(buf); |
1541 | 1594 | ||
1542 | while ((buf = portdev->c_ivq->vq_ops->detach_unused_buf(portdev->c_ivq))) | 1595 | while ((buf = virtqueue_detach_unused_buf(portdev->c_ivq))) |
1543 | free_buf(buf); | 1596 | free_buf(buf); |
1544 | 1597 | ||
1545 | vdev->config->del_vqs(vdev); | 1598 | vdev->config->del_vqs(vdev); |
@@ -1556,6 +1609,7 @@ static struct virtio_device_id id_table[] = { | |||
1556 | 1609 | ||
1557 | static unsigned int features[] = { | 1610 | static unsigned int features[] = { |
1558 | VIRTIO_CONSOLE_F_SIZE, | 1611 | VIRTIO_CONSOLE_F_SIZE, |
1612 | VIRTIO_CONSOLE_F_MULTIPORT, | ||
1559 | }; | 1613 | }; |
1560 | 1614 | ||
1561 | static struct virtio_driver virtio_console = { | 1615 | static struct virtio_driver virtio_console = { |