xref: /freebsd/sys/dev/virtio/console/virtio_console.c (revision 0677dfd1c4dadb62482e2c72fa4c6720902128a4)
1 /*-
2  * Copyright (c) 2014, Bryan Venteicher <bryanv@FreeBSD.org>
3  * All rights reserved.
4  *
5  * Redistribution and use in source and binary forms, with or without
6  * modification, are permitted provided that the following conditions
7  * are met:
8  * 1. Redistributions of source code must retain the above copyright
9  *    notice unmodified, this list of conditions, and the following
10  *    disclaimer.
11  * 2. Redistributions in binary form must reproduce the above copyright
12  *    notice, this list of conditions and the following disclaimer in the
13  *    documentation and/or other materials provided with the distribution.
14  *
15  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
16  * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
17  * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
18  * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
19  * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
20  * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
21  * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
22  * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
23  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
24  * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
25  */
26 
27 /* Driver for VirtIO console devices. */
28 
29 #include <sys/cdefs.h>
30 __FBSDID("$FreeBSD$");
31 
32 #include <sys/param.h>
33 #include <sys/systm.h>
34 #include <sys/kernel.h>
35 #include <sys/malloc.h>
36 #include <sys/module.h>
37 #include <sys/lock.h>
38 #include <sys/mutex.h>
39 #include <sys/sglist.h>
40 #include <sys/sysctl.h>
41 #include <sys/taskqueue.h>
42 #include <sys/queue.h>
43 
44 #include <sys/conf.h>
45 #include <sys/cons.h>
46 #include <sys/tty.h>
47 
48 #include <machine/bus.h>
49 #include <machine/resource.h>
50 #include <sys/bus.h>
51 
52 #include <dev/virtio/virtio.h>
53 #include <dev/virtio/virtqueue.h>
54 #include <dev/virtio/console/virtio_console.h>
55 
56 #include "virtio_if.h"
57 
58 #define VTCON_MAX_PORTS	1
59 #define VTCON_TTY_PREFIX "V"
60 #define VTCON_BULK_BUFSZ 128
61 
62 struct vtcon_softc;
63 
64 struct vtcon_port {
65 	struct vtcon_softc	*vtcport_sc;
66 	TAILQ_ENTRY(vtcon_port)  vtcport_next;
67 	struct mtx		 vtcport_mtx;
68 	int			 vtcport_id;
69 	struct tty		*vtcport_tty;
70 	struct virtqueue	*vtcport_invq;
71 	struct virtqueue	*vtcport_outvq;
72 	char			 vtcport_name[16];
73 };
74 
75 #define VTCON_PORT_MTX(_port)		&(_port)->vtcport_mtx
76 #define VTCON_PORT_LOCK_INIT(_port) \
77     mtx_init(VTCON_PORT_MTX((_port)), (_port)->vtcport_name, NULL, MTX_DEF)
78 #define VTCON_PORT_LOCK(_port)		mtx_lock(VTCON_PORT_MTX((_port)))
79 #define VTCON_PORT_UNLOCK(_port)	mtx_unlock(VTCON_PORT_MTX((_port)))
80 #define VTCON_PORT_LOCK_DESTROY(_port)	mtx_destroy(VTCON_PORT_MTX((_port)))
81 #define VTCON_PORT_LOCK_ASSERT(_port) \
82     mtx_assert(VTCON_PORT_MTX((_port)), MA_OWNED)
83 #define VTCON_PORT_LOCK_ASSERT_NOTOWNED(_port) \
84     mtx_assert(VTCON_PORT_MTX((_port)), MA_NOTOWNED)
85 
86 struct vtcon_softc {
87 	device_t		 vtcon_dev;
88 	struct mtx		 vtcon_mtx;
89 	uint64_t		 vtcon_features;
90 	uint32_t		 vtcon_flags;
91 #define VTCON_FLAG_DETACHED	0x0001
92 #define VTCON_FLAG_SIZE		0x0010
93 #define VTCON_FLAG_MULTIPORT	0x0020
94 
95 	struct task		 vtcon_ctrl_task;
96 	struct virtqueue	*vtcon_ctrl_rxvq;
97 	struct virtqueue	*vtcon_ctrl_txvq;
98 
99 	uint32_t		 vtcon_max_ports;
100 	TAILQ_HEAD(, vtcon_port)
101 				 vtcon_ports;
102 
103 	/*
104 	 * Ports can be added and removed during runtime, but we have
105 	 * to allocate all the virtqueues during attach. This array is
106 	 * indexed by the port ID.
107 	 */
108 	struct vtcon_port_extra {
109 		struct vtcon_port	*port;
110 		struct virtqueue	*invq;
111 		struct virtqueue	*outvq;
112 	}			*vtcon_portsx;
113 };
114 
115 #define VTCON_MTX(_sc)		&(_sc)->vtcon_mtx
116 #define VTCON_LOCK_INIT(_sc, _name) \
117     mtx_init(VTCON_MTX((_sc)), (_name), NULL, MTX_DEF)
118 #define VTCON_LOCK(_sc)		mtx_lock(VTCON_MTX((_sc)))
119 #define VTCON_UNLOCK(_sc)	mtx_unlock(VTCON_MTX((_sc)))
120 #define VTCON_LOCK_DESTROY(_sc)	mtx_destroy(VTCON_MTX((_sc)))
121 #define VTCON_LOCK_ASSERT(_sc)	mtx_assert(VTCON_MTX((_sc)), MA_OWNED)
122 #define VTCON_LOCK_ASSERT_NOTOWNED(_sc) \
123     mtx_assert(VTCON_MTX((_sc)), MA_NOTOWNED)
124 
125 #define VTCON_ASSERT_VALID_PORTID(_sc, _id)			\
126     KASSERT((_id) >= 0 && (_id) < (_sc)->vtcon_max_ports,	\
127         ("%s: port ID %d out of range", __func__, _id))
128 
129 #define VTCON_FEATURES  0
130 
131 static struct virtio_feature_desc vtcon_feature_desc[] = {
132 	{ VIRTIO_CONSOLE_F_SIZE,	"ConsoleSize"	},
133 	{ VIRTIO_CONSOLE_F_MULTIPORT,	"MultiplePorts"	},
134 
135 	{ 0, NULL }
136 };
137 
138 static int	 vtcon_modevent(module_t, int, void *);
139 
140 static int	 vtcon_probe(device_t);
141 static int	 vtcon_attach(device_t);
142 static int	 vtcon_detach(device_t);
143 static int	 vtcon_config_change(device_t);
144 
145 static void	 vtcon_negotiate_features(struct vtcon_softc *);
146 static int	 vtcon_alloc_virtqueues(struct vtcon_softc *);
147 static void	 vtcon_read_config(struct vtcon_softc *,
148 		     struct virtio_console_config *);
149 
150 static void	 vtcon_determine_max_ports(struct vtcon_softc *,
151 		     struct virtio_console_config *);
152 static void	 vtcon_deinit_ports(struct vtcon_softc *);
153 static void	 vtcon_stop(struct vtcon_softc *);
154 
155 static void	 vtcon_ctrl_rx_vq_intr(void *);
156 static int	 vtcon_ctrl_enqueue_msg(struct vtcon_softc *,
157 		     struct virtio_console_control *);
158 static int	 vtcon_ctrl_add_msg(struct vtcon_softc *);
159 static void	 vtcon_ctrl_readd_msg(struct vtcon_softc *,
160 		     struct virtio_console_control *);
161 static int	 vtcon_ctrl_populate(struct vtcon_softc *);
162 static void	 vtcon_ctrl_send_msg(struct vtcon_softc *,
163 		     struct virtio_console_control *control);
164 static void	 vtcon_ctrl_send_event(struct vtcon_softc *, uint32_t,
165 		     uint16_t, uint16_t);
166 static int	 vtcon_ctrl_init(struct vtcon_softc *);
167 static void	 vtcon_ctrl_drain(struct vtcon_softc *);
168 static void	 vtcon_ctrl_deinit(struct vtcon_softc *);
169 static void	 vtcon_ctrl_port_add_event(struct vtcon_softc *, int);
170 static void	 vtcon_ctrl_port_remove_event(struct vtcon_softc *, int);
171 static void	 vtcon_ctrl_port_console_event(struct vtcon_softc *, int);
172 static void	 vtcon_ctrl_port_open_event(struct vtcon_softc *, int);
173 static void	 vtcon_ctrl_process_msg(struct vtcon_softc *,
174 		     struct virtio_console_control *);
175 static void	 vtcon_ctrl_task_cb(void *, int);
176 
177 static int	 vtcon_port_add_inbuf(struct vtcon_port *);
178 static void	 vtcon_port_readd_inbuf(struct vtcon_port *, void *);
179 static int	 vtcon_port_populate(struct vtcon_port *);
180 static void	 vtcon_port_destroy(struct vtcon_port *);
181 static int	 vtcon_port_create(struct vtcon_softc *, int,
182 		     struct vtcon_port **);
183 static void	 vtcon_port_drain_inbufs(struct vtcon_port *);
184 static void	 vtcon_port_teardown(struct vtcon_port *, int);
185 static void	 vtcon_port_change_size(struct vtcon_port *, uint16_t,
186 		     uint16_t);
187 static void	 vtcon_port_enable_intr(struct vtcon_port *);
188 static void	 vtcon_port_disable_intr(struct vtcon_port *);
189 static void	 vtcon_port_intr(struct vtcon_port *);
190 static void	 vtcon_port_in_vq_intr(void *);
191 static void	 vtcon_port_put(struct vtcon_port *, void *, int);
192 static void	 vtcon_port_send_ctrl_msg(struct vtcon_port *, uint16_t,
193 		     uint16_t);
194 static struct vtcon_port *vtcon_port_lookup_by_id(struct vtcon_softc *, int);
195 
196 static int	 vtcon_tty_open(struct tty *);
197 static void	 vtcon_tty_close(struct tty *);
198 static void	 vtcon_tty_outwakeup(struct tty *);
199 static void	 vtcon_tty_free(void *);
200 
201 static void	 vtcon_get_console_size(struct vtcon_softc *, uint16_t *,
202 		     uint16_t *);
203 
204 static void	 vtcon_enable_interrupts(struct vtcon_softc *);
205 static void	 vtcon_disable_interrupts(struct vtcon_softc *);
206 
207 static int	 vtcon_pending_free;
208 
209 static struct ttydevsw vtcon_tty_class = {
210 	.tsw_flags	= 0,
211 	.tsw_open	= vtcon_tty_open,
212 	.tsw_close	= vtcon_tty_close,
213 	.tsw_outwakeup	= vtcon_tty_outwakeup,
214 	.tsw_free	= vtcon_tty_free,
215 };
216 
217 static device_method_t vtcon_methods[] = {
218 	/* Device methods. */
219 	DEVMETHOD(device_probe,		vtcon_probe),
220 	DEVMETHOD(device_attach,	vtcon_attach),
221 	DEVMETHOD(device_detach,	vtcon_detach),
222 
223 	/* VirtIO methods. */
224 	DEVMETHOD(virtio_config_change,	vtcon_config_change),
225 
226 	DEVMETHOD_END
227 };
228 
229 static driver_t vtcon_driver = {
230 	"vtcon",
231 	vtcon_methods,
232 	sizeof(struct vtcon_softc)
233 };
234 static devclass_t vtcon_devclass;
235 
236 DRIVER_MODULE(virtio_console, virtio_pci, vtcon_driver, vtcon_devclass,
237     vtcon_modevent, 0);
238 MODULE_VERSION(virtio_console, 1);
239 MODULE_DEPEND(virtio_console, virtio, 1, 1, 1);
240 
241 static int
242 vtcon_modevent(module_t mod, int type, void *unused)
243 {
244 	int error;
245 
246 	switch (type) {
247 	case MOD_LOAD:
248 		error = 0;
249 		break;
250 	case MOD_QUIESCE:
251 	case MOD_UNLOAD:
252 		error = vtcon_pending_free != 0 ? EBUSY : 0;
253 		/* error = EOPNOTSUPP; */
254 		break;
255 	case MOD_SHUTDOWN:
256 		error = 0;
257 		break;
258 	default:
259 		error = EOPNOTSUPP;
260 		break;
261 	}
262 
263 	return (error);
264 }
265 
266 static int
267 vtcon_probe(device_t dev)
268 {
269 
270 	if (virtio_get_device_type(dev) != VIRTIO_ID_CONSOLE)
271 		return (ENXIO);
272 
273 	device_set_desc(dev, "VirtIO Console Adapter");
274 
275 	return (BUS_PROBE_DEFAULT);
276 }
277 
278 static int
279 vtcon_attach(device_t dev)
280 {
281 	struct vtcon_softc *sc;
282 	struct virtio_console_config concfg;
283 	int error;
284 
285 	sc = device_get_softc(dev);
286 	sc->vtcon_dev = dev;
287 
288 	VTCON_LOCK_INIT(sc, device_get_nameunit(dev));
289 	TASK_INIT(&sc->vtcon_ctrl_task, 0, vtcon_ctrl_task_cb, sc);
290 	TAILQ_INIT(&sc->vtcon_ports);
291 
292 	virtio_set_feature_desc(dev, vtcon_feature_desc);
293 	vtcon_negotiate_features(sc);
294 
295 	if (virtio_with_feature(dev, VIRTIO_CONSOLE_F_SIZE))
296 		sc->vtcon_flags |= VTCON_FLAG_SIZE;
297 	if (virtio_with_feature(dev, VIRTIO_CONSOLE_F_MULTIPORT))
298 		sc->vtcon_flags |= VTCON_FLAG_MULTIPORT;
299 
300 	vtcon_read_config(sc, &concfg);
301 	vtcon_determine_max_ports(sc, &concfg);
302 
303 	error = vtcon_alloc_virtqueues(sc);
304 	if (error) {
305 		device_printf(dev, "cannot allocate virtqueues\n");
306 		goto fail;
307 	}
308 
309 	if (sc->vtcon_flags & VTCON_FLAG_MULTIPORT)
310 		error = vtcon_ctrl_init(sc);
311 	else
312 		error = vtcon_port_create(sc, 0, NULL);
313 	if (error)
314 		goto fail;
315 
316 	error = virtio_setup_intr(dev, INTR_TYPE_TTY);
317 	if (error) {
318 		device_printf(dev, "cannot setup virtqueue interrupts\n");
319 		goto fail;
320 	}
321 
322 	vtcon_enable_interrupts(sc);
323 
324 	vtcon_ctrl_send_event(sc, VIRTIO_CONSOLE_BAD_ID,
325 	    VIRTIO_CONSOLE_DEVICE_READY, 1);
326 
327 fail:
328 	if (error)
329 		vtcon_detach(dev);
330 
331 	return (error);
332 }
333 
334 static int
335 vtcon_detach(device_t dev)
336 {
337 	struct vtcon_softc *sc;
338 
339 	sc = device_get_softc(dev);
340 
341 	VTCON_LOCK(sc);
342 	sc->vtcon_flags |= VTCON_FLAG_DETACHED;
343 	if (device_is_attached(dev))
344 		vtcon_stop(sc);
345 	VTCON_UNLOCK(sc);
346 
347 	taskqueue_drain(taskqueue_thread, &sc->vtcon_ctrl_task);
348 
349 	if (sc->vtcon_flags & VTCON_FLAG_MULTIPORT)
350 		vtcon_ctrl_deinit(sc);
351 
352 	vtcon_deinit_ports(sc);
353 
354 	VTCON_LOCK_DESTROY(sc);
355 
356 	return (0);
357 }
358 
359 static int
360 vtcon_config_change(device_t dev)
361 {
362 	struct vtcon_softc *sc;
363 	struct vtcon_port *port;
364 	uint16_t cols, rows;
365 
366 	sc = device_get_softc(dev);
367 
368 	/*
369 	 * With the multiport feature, all configuration changes are
370 	 * done through control virtqueue events. This is a spurious
371 	 * interrupt.
372 	 */
373 	if (sc->vtcon_flags & VTCON_FLAG_MULTIPORT)
374 		return (0);
375 
376 	if (sc->vtcon_flags & VTCON_FLAG_SIZE) {
377 		/*
378 		 * For now, assume the first (only) port is the 'console'.
379 		 * Note QEMU does not implement this feature yet.
380 		 */
381 		VTCON_LOCK(sc);
382 		if ((port = vtcon_port_lookup_by_id(sc, 0)) != NULL) {
383 			vtcon_get_console_size(sc, &cols, &rows);
384 			vtcon_port_change_size(port, cols, rows);
385 		}
386 		VTCON_UNLOCK(sc);
387 	}
388 
389 	return (0);
390 }
391 
392 static void
393 vtcon_negotiate_features(struct vtcon_softc *sc)
394 {
395 	device_t dev;
396 	uint64_t features;
397 
398 	dev = sc->vtcon_dev;
399 	features = VTCON_FEATURES;
400 
401 	sc->vtcon_features = virtio_negotiate_features(dev, features);
402 }
403 
404 #define VTCON_GET_CONFIG(_dev, _feature, _field, _cfg)			\
405 	if (virtio_with_feature(_dev, _feature)) {			\
406 		virtio_read_device_config(_dev,				\
407 		    offsetof(struct virtio_console_config, _field),	\
408 		    &(_cfg)->_field, sizeof((_cfg)->_field));		\
409 	}
410 
411 static void
412 vtcon_read_config(struct vtcon_softc *sc, struct virtio_console_config *concfg)
413 {
414 	device_t dev;
415 
416 	dev = sc->vtcon_dev;
417 
418 	bzero(concfg, sizeof(struct virtio_console_config));
419 
420 	/* Read the configuration if the feature was negotiated. */
421 	VTCON_GET_CONFIG(dev, VIRTIO_CONSOLE_F_SIZE, cols, concfg);
422 	VTCON_GET_CONFIG(dev, VIRTIO_CONSOLE_F_SIZE, rows, concfg);
423 	VTCON_GET_CONFIG(dev, VIRTIO_CONSOLE_F_MULTIPORT, max_nr_ports, concfg);
424 }
425 
426 #undef VTCON_GET_CONFIG
427 
428 static int
429 vtcon_alloc_virtqueues(struct vtcon_softc *sc)
430 {
431 	device_t dev;
432 	struct vq_alloc_info *info;
433 	struct vtcon_port_extra *portx;
434 	int i, idx, portidx, nvqs, error;
435 
436 	dev = sc->vtcon_dev;
437 
438 	sc->vtcon_portsx = malloc(sizeof(struct vtcon_port_extra) *
439 	    sc->vtcon_max_ports, M_DEVBUF, M_NOWAIT | M_ZERO);
440 	if (sc->vtcon_portsx == NULL)
441 		return (ENOMEM);
442 
443 	nvqs = sc->vtcon_max_ports * 2;
444 	if (sc->vtcon_flags & VTCON_FLAG_MULTIPORT)
445 		nvqs += 2;
446 
447 	info = malloc(sizeof(struct vq_alloc_info) * nvqs, M_TEMP, M_NOWAIT);
448 	if (info == NULL)
449 		return (ENOMEM);
450 
451 	for (i = 0, idx = 0, portidx = 0; i < nvqs / 2; i++, idx+=2) {
452 
453 		if (i == 1) {
454 			/* The control virtqueues are after the first port. */
455 			VQ_ALLOC_INFO_INIT(&info[idx], 0,
456 			    vtcon_ctrl_rx_vq_intr, sc, &sc->vtcon_ctrl_rxvq,
457 			    "%s-control rx", device_get_nameunit(dev));
458 			VQ_ALLOC_INFO_INIT(&info[idx+1], 0,
459 			    NULL, sc, &sc->vtcon_ctrl_txvq,
460 			    "%s-control tx", device_get_nameunit(dev));
461 			continue;
462 		}
463 
464 		portx = &sc->vtcon_portsx[portidx];
465 
466 		VQ_ALLOC_INFO_INIT(&info[idx], 0, vtcon_port_in_vq_intr,
467 		    portx, &portx->invq, "%s-port%d in",
468 		    device_get_nameunit(dev), portidx);
469 		VQ_ALLOC_INFO_INIT(&info[idx+1], 0, NULL,
470 		    NULL, &portx->outvq, "%s-port%d out",
471 		    device_get_nameunit(dev), portidx);
472 
473 		portidx++;
474 	}
475 
476 	error = virtio_alloc_virtqueues(dev, 0, nvqs, info);
477 	free(info, M_TEMP);
478 
479 	return (error);
480 }
481 
482 static void
483 vtcon_determine_max_ports(struct vtcon_softc *sc,
484     struct virtio_console_config *concfg)
485 {
486 
487 	if (sc->vtcon_flags & VTCON_FLAG_MULTIPORT) {
488 		sc->vtcon_max_ports =
489 		    min(concfg->max_nr_ports, VTCON_MAX_PORTS);
490 		if (sc->vtcon_max_ports == 0)
491 			sc->vtcon_max_ports = 1;
492 	} else
493 		sc->vtcon_max_ports = 1;
494 }
495 
496 static void
497 vtcon_deinit_ports(struct vtcon_softc *sc)
498 {
499 	struct vtcon_port *port, *tmp;
500 
501 	TAILQ_FOREACH_SAFE(port, &sc->vtcon_ports, vtcport_next, tmp) {
502 		vtcon_port_teardown(port, 1);
503 	}
504 
505 	if (sc->vtcon_portsx != NULL) {
506 		free(sc->vtcon_portsx, M_DEVBUF);
507 		sc->vtcon_portsx = NULL;
508 	}
509 }
510 
511 static void
512 vtcon_stop(struct vtcon_softc *sc)
513 {
514 
515 	vtcon_disable_interrupts(sc);
516 	virtio_stop(sc->vtcon_dev);
517 }
518 
519 static void
520 vtcon_ctrl_rx_vq_intr(void *xsc)
521 {
522 	struct vtcon_softc *sc;
523 
524 	sc = xsc;
525 
526 	/*
527 	 * Some events require us to potentially block, but it easier
528 	 * to just defer all event handling to a seperate thread.
529 	 */
530 	taskqueue_enqueue(taskqueue_thread, &sc->vtcon_ctrl_task);
531 }
532 
533 static int
534 vtcon_ctrl_enqueue_msg(struct vtcon_softc *sc,
535     struct virtio_console_control *control)
536 {
537 	struct sglist_seg segs[1];
538 	struct sglist sg;
539 	struct virtqueue *vq;
540 	int error __unused;
541 
542 	vq = sc->vtcon_ctrl_rxvq;
543 
544 	sglist_init(&sg, 1, segs);
545 	error = sglist_append(&sg, control, sizeof(*control));
546 	KASSERT(error == 0 && sg.sg_nseg == 1,
547 	    ("%s: error %d adding control msg to sglist", __func__, error));
548 
549 	return (virtqueue_enqueue(vq, control, &sg, 0, 1));
550 }
551 
552 static int
553 vtcon_ctrl_add_msg(struct vtcon_softc *sc)
554 {
555 	struct virtio_console_control *control;
556 	int error;
557 
558 	control = malloc(sizeof(*control), M_DEVBUF, M_ZERO | M_NOWAIT);
559 	if (control == NULL)
560 		return (ENOMEM);
561 
562 	error = vtcon_ctrl_enqueue_msg(sc, control);
563 	if (error)
564 		free(control, M_DEVBUF);
565 
566 	return (error);
567 }
568 
569 static void
570 vtcon_ctrl_readd_msg(struct vtcon_softc *sc,
571     struct virtio_console_control *control)
572 {
573 	int error;
574 
575 	bzero(control, sizeof(*control));
576 
577 	error = vtcon_ctrl_enqueue_msg(sc, control);
578 	KASSERT(error == 0,
579 	    ("%s: cannot requeue control buffer %d", __func__, error));
580 }
581 
582 static int
583 vtcon_ctrl_populate(struct vtcon_softc *sc)
584 {
585 	struct virtqueue *vq;
586 	int nbufs, error;
587 
588 	vq = sc->vtcon_ctrl_rxvq;
589 	error = ENOSPC;
590 
591 	for (nbufs = 0; !virtqueue_full(vq); nbufs++) {
592 		error = vtcon_ctrl_add_msg(sc);
593 		if (error)
594 			break;
595 	}
596 
597 	if (nbufs > 0) {
598 		virtqueue_notify(vq);
599 		/*
600 		 * EMSGSIZE signifies the virtqueue did not have enough
601 		 * entries available to hold the last buf. This is not
602 		 * an error.
603 		 */
604 		if (error == EMSGSIZE)
605 			error = 0;
606 	}
607 
608 	return (error);
609 }
610 
611 static void
612 vtcon_ctrl_send_msg(struct vtcon_softc *sc,
613     struct virtio_console_control *control)
614 {
615 	struct sglist_seg segs[1];
616 	struct sglist sg;
617 	struct virtqueue *vq;
618 	int error;
619 
620 	vq = sc->vtcon_ctrl_txvq;
621 	KASSERT(virtqueue_empty(vq),
622 	    ("%s: virtqueue is not emtpy", __func__));
623 
624 	sglist_init(&sg, 1, segs);
625 	error = sglist_append(&sg, control, sizeof(*control));
626 	KASSERT(error == 0 && sg.sg_nseg == 1,
627 	    ("%s: error %d adding control msg to sglist", __func__, error));
628 
629 	error = virtqueue_enqueue(vq, control, &sg, 1, 0);
630 	if (error == 0) {
631 		virtqueue_notify(vq);
632 		virtqueue_poll(vq, NULL);
633 	}
634 }
635 
636 static void
637 vtcon_ctrl_send_event(struct vtcon_softc *sc, uint32_t portid, uint16_t event,
638     uint16_t value)
639 {
640 	struct virtio_console_control control;
641 
642 	if ((sc->vtcon_flags & VTCON_FLAG_MULTIPORT) == 0)
643 		return;
644 
645 	control.id = portid;
646 	control.event = event;
647 	control.value = value;
648 
649 	vtcon_ctrl_send_msg(sc, &control);
650 }
651 
652 static int
653 vtcon_ctrl_init(struct vtcon_softc *sc)
654 {
655 	int error;
656 
657 	error = vtcon_ctrl_populate(sc);
658 
659 	return (error);
660 }
661 
662 static void
663 vtcon_ctrl_drain(struct vtcon_softc *sc)
664 {
665 	struct virtio_console_control *control;
666 	struct virtqueue *vq;
667 	int last;
668 
669 	vq = sc->vtcon_ctrl_rxvq;
670 	last = 0;
671 
672 	if (vq == NULL)
673 		return;
674 
675 	while ((control = virtqueue_drain(vq, &last)) != NULL)
676 		free(control, M_DEVBUF);
677 }
678 
679 static void
680 vtcon_ctrl_deinit(struct vtcon_softc *sc)
681 {
682 
683 	vtcon_ctrl_drain(sc);
684 }
685 
686 static void
687 vtcon_ctrl_port_add_event(struct vtcon_softc *sc, int id)
688 {
689 	device_t dev;
690 	struct vtcon_port *port;
691 	int error;
692 
693 	dev = sc->vtcon_dev;
694 
695 	if (vtcon_port_lookup_by_id(sc, id) != NULL) {
696 		device_printf(dev, "%s: adding port %d, but already exists\n",
697 		    __func__, id);
698 		return;
699 	}
700 
701 	error = vtcon_port_create(sc, id, &port);
702 	if (error) {
703 		device_printf(dev, "%s: cannot create port %d: %d\n",
704 		    __func__, id, error);
705 		return;
706 	}
707 
708 	vtcon_port_send_ctrl_msg(port, VIRTIO_CONSOLE_PORT_READY, 1);
709 }
710 
711 static void
712 vtcon_ctrl_port_remove_event(struct vtcon_softc *sc, int id)
713 {
714 	device_t dev;
715 	struct vtcon_port *port;
716 
717 	dev = sc->vtcon_dev;
718 
719 	port = vtcon_port_lookup_by_id(sc, id);
720 	if (port == NULL) {
721 		device_printf(dev, "%s: remove port %d, but does not exist\n",
722 		    __func__, id);
723 		return;
724 	}
725 
726 	vtcon_port_teardown(port, 1);
727 }
728 
729 static void
730 vtcon_ctrl_port_console_event(struct vtcon_softc *sc, int id)
731 {
732 	device_t dev;
733 
734 	dev = sc->vtcon_dev;
735 
736 	/*
737 	 * BMV: I don't think we need to do anything.
738 	 */
739 	device_printf(dev, "%s: port %d console event\n", __func__, id);
740 }
741 
742 static void
743 vtcon_ctrl_port_open_event(struct vtcon_softc *sc, int id)
744 {
745 	device_t dev;
746 	struct vtcon_port *port;
747 
748 	dev = sc->vtcon_dev;
749 
750 	port = vtcon_port_lookup_by_id(sc, id);
751 	if (port == NULL) {
752 		device_printf(dev, "%s: open port %d, but does not exist\n",
753 		    __func__, id);
754 		return;
755 	}
756 
757 	vtcon_port_enable_intr(port);
758 }
759 
760 static void
761 vtcon_ctrl_process_msg(struct vtcon_softc *sc,
762     struct virtio_console_control *control)
763 {
764 	device_t dev;
765 	int id;
766 
767 	dev = sc->vtcon_dev;
768 	id = control->id;
769 
770 	if (id < 0 || id >= sc->vtcon_max_ports) {
771 		device_printf(dev, "%s: invalid port ID %d\n", __func__, id);
772 		return;
773 	}
774 
775 	switch (control->event) {
776 	case VIRTIO_CONSOLE_PORT_ADD:
777 		vtcon_ctrl_port_add_event(sc, id);
778 		break;
779 
780 	case VIRTIO_CONSOLE_PORT_REMOVE:
781 		vtcon_ctrl_port_remove_event(sc, id);
782 		break;
783 
784 	case VIRTIO_CONSOLE_CONSOLE_PORT:
785 		vtcon_ctrl_port_console_event(sc, id);
786 		break;
787 
788 	case VIRTIO_CONSOLE_RESIZE:
789 		break;
790 
791 	case VIRTIO_CONSOLE_PORT_OPEN:
792 		vtcon_ctrl_port_open_event(sc, id);
793 		break;
794 
795 	case VIRTIO_CONSOLE_PORT_NAME:
796 		break;
797 	}
798 }
799 
800 static void
801 vtcon_ctrl_task_cb(void *xsc, int pending)
802 {
803 	struct vtcon_softc *sc;
804 	struct virtqueue *vq;
805 	struct virtio_console_control *control;
806 
807 	sc = xsc;
808 	vq = sc->vtcon_ctrl_rxvq;
809 
810 	VTCON_LOCK(sc);
811 	while ((sc->vtcon_flags & VTCON_FLAG_DETACHED) == 0) {
812 		control = virtqueue_dequeue(vq, NULL);
813 		if (control == NULL)
814 			break;
815 
816 		VTCON_UNLOCK(sc);
817 		vtcon_ctrl_process_msg(sc, control);
818 		VTCON_LOCK(sc);
819 		vtcon_ctrl_readd_msg(sc, control);
820 	}
821 	VTCON_UNLOCK(sc);
822 
823 	if (virtqueue_enable_intr(vq) != 0)
824 		taskqueue_enqueue(taskqueue_thread, &sc->vtcon_ctrl_task);
825 }
826 
827 static int
828 vtcon_port_enqueue_inbuf(struct vtcon_port *port, void *buf, size_t len)
829 {
830 	struct sglist_seg segs[1];
831 	struct sglist sg;
832 	struct virtqueue *vq;
833 	int error;
834 
835 	vq = port->vtcport_invq;
836 
837 	sglist_init(&sg, 1, segs);
838 	error = sglist_append(&sg, buf, len);
839 	KASSERT(error == 0 && sg.sg_nseg == 1,
840 	    ("%s: error %d adding buffer to sglist", __func__, error));
841 
842 	return (virtqueue_enqueue(vq, buf, &sg, 0, 1));
843 }
844 
845 static int
846 vtcon_port_add_inbuf(struct vtcon_port *port)
847 {
848 	void *buf;
849 	int error;
850 
851 	buf = malloc(VTCON_BULK_BUFSZ, M_DEVBUF, M_ZERO | M_NOWAIT);
852 	if (buf == NULL)
853 		return (ENOMEM);
854 
855 	error = vtcon_port_enqueue_inbuf(port, buf, VTCON_BULK_BUFSZ);
856 	if (error)
857 		free(buf, M_DEVBUF);
858 
859 	return (error);
860 }
861 
862 static void
863 vtcon_port_readd_inbuf(struct vtcon_port *port, void *buf)
864 {
865 	int error __unused;
866 
867 	error = vtcon_port_enqueue_inbuf(port, buf, VTCON_BULK_BUFSZ);
868 	KASSERT(error == 0,
869 	    ("%s: cannot requeue input buffer %d", __func__, error));
870 }
871 
872 static int
873 vtcon_port_populate(struct vtcon_port *port)
874 {
875 	struct virtqueue *vq;
876 	int nbufs, error;
877 
878 	vq = port->vtcport_invq;
879 	error = ENOSPC;
880 
881 	for (nbufs = 0; !virtqueue_full(vq); nbufs++) {
882 		error = vtcon_port_add_inbuf(port);
883 		if (error)
884 			break;
885 	}
886 
887 	if (nbufs > 0) {
888 		virtqueue_notify(vq);
889 		/*
890 		 * EMSGSIZE signifies the virtqueue did not have enough
891 		 * entries available to hold the last buf. This is not
892 		 * an error.
893 		 */
894 		if (error == EMSGSIZE)
895 			error = 0;
896 	}
897 
898 	return (error);
899 }
900 
901 static void
902 vtcon_port_destroy(struct vtcon_port *port)
903 {
904 
905 	port->vtcport_sc = NULL;
906 	port->vtcport_id = -1;
907 	VTCON_PORT_LOCK_DESTROY(port);
908 	free(port, M_DEVBUF);
909 }
910 
911 static int
912 vtcon_port_create(struct vtcon_softc *sc, int id, struct vtcon_port **portp)
913 {
914 	device_t dev;
915 	struct vtcon_port_extra *portx;
916 	struct vtcon_port *port;
917 	int error;
918 
919 	MPASS(id < sc->vtcon_max_ports);
920 	dev = sc->vtcon_dev;
921 	portx = &sc->vtcon_portsx[id];
922 
923 	if (portx->port != NULL)
924 		return (EEXIST);
925 
926 	port = malloc(sizeof(struct vtcon_port), M_DEVBUF, M_NOWAIT | M_ZERO);
927 	if (port == NULL)
928 		return (ENOMEM);
929 
930 	port->vtcport_sc = sc;
931 	port->vtcport_id = id;
932 	snprintf(port->vtcport_name, sizeof(port->vtcport_name), "%s-port%d",
933 	    device_get_nameunit(dev), id);
934 	VTCON_PORT_LOCK_INIT(port);
935 	port->vtcport_tty = tty_alloc_mutex(&vtcon_tty_class, port,
936 	    &port->vtcport_mtx);
937 
938 	/*
939 	 * Assign virtqueues saved from attach. To be safe, clear the
940 	 * virtqueue too.
941 	 */
942 	port->vtcport_invq = portx->invq;
943 	port->vtcport_outvq = portx->outvq;
944 	vtcon_port_drain_inbufs(port);
945 
946 	error = vtcon_port_populate(port);
947 	if (error) {
948 		vtcon_port_teardown(port, 0);
949 		return (error);
950 	}
951 
952 	tty_makedev(port->vtcport_tty, NULL, "%s%r.%r", VTCON_TTY_PREFIX,
953 	    device_get_unit(dev), id);
954 
955 	VTCON_LOCK(sc);
956 	portx->port = port;
957 	TAILQ_INSERT_TAIL(&sc->vtcon_ports, port, vtcport_next);
958 	VTCON_UNLOCK(sc);
959 
960 	if (portp != NULL)
961 		*portp = port;
962 
963 	return (0);
964 }
965 
966 static void
967 vtcon_port_drain_inbufs(struct vtcon_port *port)
968 {
969 	struct virtqueue *vq;
970 	void *buf;
971 	int last;
972 
973 	vq = port->vtcport_invq;
974 	last = 0;
975 
976 	if (vq == NULL)
977 		return;
978 
979 	while ((buf = virtqueue_drain(vq, &last)) != NULL)
980 		free(buf, M_DEVBUF);
981 }
982 
983 static void
984 vtcon_port_teardown(struct vtcon_port *port, int ontailq)
985 {
986 	struct vtcon_softc *sc;
987 	struct vtcon_port_extra *portx;
988 	struct tty *tp;
989 	int id;
990 
991 	sc = port->vtcport_sc;
992 	id = port->vtcport_id;
993 	tp = port->vtcport_tty;
994 
995 	VTCON_ASSERT_VALID_PORTID(sc, id);
996 	portx = &sc->vtcon_portsx[id];
997 
998 	VTCON_PORT_LOCK(port);
999 	vtcon_port_drain_inbufs(port);
1000 	VTCON_PORT_UNLOCK(port);
1001 
1002 	VTCON_LOCK(sc);
1003 	KASSERT(portx->port == NULL || portx->port == port,
1004 	    ("%s: port %d mismatch %p/%p", __func__, id, portx->port, port));
1005 	portx->port = NULL;
1006 	if (ontailq != 0)
1007 		TAILQ_REMOVE(&sc->vtcon_ports, port, vtcport_next);
1008 	VTCON_UNLOCK(sc);
1009 
1010 	if (tp != NULL) {
1011 		port->vtcport_tty = NULL;
1012 		atomic_add_int(&vtcon_pending_free, 1);
1013 
1014 		VTCON_PORT_LOCK(port);
1015 		tty_rel_gone(tp);
1016 	} else
1017 		vtcon_port_destroy(port);
1018 }
1019 
1020 static void
1021 vtcon_port_change_size(struct vtcon_port *port, uint16_t cols, uint16_t rows)
1022 {
1023 	struct tty *tp;
1024 	struct winsize sz;
1025 
1026 	tp = port->vtcport_tty;
1027 
1028 	if (tp == NULL)
1029 		return;
1030 
1031 	bzero(&sz, sizeof(struct winsize));
1032 	sz.ws_col = cols;
1033 	sz.ws_row = rows;
1034 
1035 	VTCON_PORT_LOCK(port);
1036 	tty_set_winsize(tp, &sz);
1037 	VTCON_PORT_UNLOCK(port);
1038 }
1039 
1040 static void
1041 vtcon_port_enable_intr(struct vtcon_port *port)
1042 {
1043 
1044 	/*
1045 	 * NOTE: The out virtqueue is always polled, so we keep its
1046 	 * interupt disabled.
1047 	 */
1048 
1049 	virtqueue_enable_intr(port->vtcport_invq);
1050 }
1051 
1052 static void
1053 vtcon_port_disable_intr(struct vtcon_port *port)
1054 {
1055 
1056 	if (port->vtcport_invq != NULL)
1057 		virtqueue_disable_intr(port->vtcport_invq);
1058 	if (port->vtcport_outvq != NULL)
1059 		virtqueue_disable_intr(port->vtcport_outvq);
1060 }
1061 
1062 static void
1063 vtcon_port_intr(struct vtcon_port *port)
1064 {
1065 	struct tty *tp;
1066 	struct virtqueue *vq;
1067 	char *buf;
1068 	uint32_t len;
1069 	int i, deq;
1070 
1071 	tp = port->vtcport_tty;
1072 	vq = port->vtcport_invq;
1073 
1074 again:
1075 	deq = 0;
1076 
1077 	VTCON_PORT_LOCK(port);
1078 	while ((buf = virtqueue_dequeue(vq, &len)) != NULL) {
1079 		deq++;
1080 		for (i = 0; i < len; i++)
1081 			ttydisc_rint(tp, buf[i], 0);
1082 		vtcon_port_readd_inbuf(port, buf);
1083 	}
1084 	ttydisc_rint_done(tp);
1085 	VTCON_PORT_UNLOCK(port);
1086 
1087 	if (deq > 0)
1088 		virtqueue_notify(vq);
1089 
1090 	if (virtqueue_enable_intr(vq) != 0)
1091 		goto again;
1092 }
1093 
1094 static void
1095 vtcon_port_in_vq_intr(void *xportx)
1096 {
1097 	struct vtcon_port_extra *portx;
1098 	struct vtcon_port *port;
1099 
1100 	portx = xportx;
1101 	port = portx->port;
1102 
1103 	if (port != NULL)
1104 		vtcon_port_intr(port);
1105 }
1106 
1107 static void
1108 vtcon_port_put(struct vtcon_port *port, void *buf, int bufsize)
1109 {
1110 	struct sglist_seg segs[1];
1111 	struct sglist sg;
1112 	struct virtqueue *vq;
1113 	int error;
1114 
1115 	vq = port->vtcport_outvq;
1116 
1117 	sglist_init(&sg, 1, segs);
1118 	error = sglist_append(&sg, buf, bufsize);
1119 	KASSERT(error == 0 && sg.sg_nseg == 1,
1120 	    ("%s: error %d adding buffer to sglist", __func__, error));
1121 
1122 	KASSERT(virtqueue_empty(vq), ("%s: port %p virtqueue not emtpy",
1123 	     __func__, port));
1124 
1125 	if (virtqueue_enqueue(vq, buf, &sg, 1, 0) == 0) {
1126 		virtqueue_notify(vq);
1127 		virtqueue_poll(vq, NULL);
1128 	}
1129 }
1130 
1131 static void
1132 vtcon_port_send_ctrl_msg(struct vtcon_port *port, uint16_t event,
1133     uint16_t value)
1134 {
1135 	struct vtcon_softc *sc;
1136 
1137 	sc = port->vtcport_sc;
1138 
1139 	if (sc->vtcon_flags & VTCON_FLAG_MULTIPORT)
1140 		vtcon_ctrl_send_event(sc, port->vtcport_id, event, value);
1141 }
1142 
1143 static struct vtcon_port *
1144 vtcon_port_lookup_by_id(struct vtcon_softc *sc, int id)
1145 {
1146 	struct vtcon_port *port;
1147 
1148 	TAILQ_FOREACH(port, &sc->vtcon_ports, vtcport_next) {
1149 		if (port->vtcport_id == id)
1150 			break;
1151 	}
1152 
1153 	return (port);
1154 }
1155 
1156 static int
1157 vtcon_tty_open(struct tty *tp)
1158 {
1159 	struct vtcon_port *port;
1160 
1161 	port = tty_softc(tp);
1162 
1163 	vtcon_port_send_ctrl_msg(port, VIRTIO_CONSOLE_PORT_OPEN, 1);
1164 
1165 	return (0);
1166 }
1167 
1168 static void
1169 vtcon_tty_close(struct tty *tp)
1170 {
1171 	struct vtcon_port *port;
1172 
1173 	port = tty_softc(tp);
1174 
1175 	vtcon_port_send_ctrl_msg(port, VIRTIO_CONSOLE_PORT_OPEN, 0);
1176 }
1177 
1178 static void
1179 vtcon_tty_outwakeup(struct tty *tp)
1180 {
1181 	struct vtcon_port *port;
1182 	char buf[VTCON_BULK_BUFSZ];
1183 	int len;
1184 
1185 	port = tty_softc(tp);
1186 
1187 	while ((len = ttydisc_getc(tp, buf, sizeof(buf))) != 0)
1188 		vtcon_port_put(port, buf, len);
1189 }
1190 
1191 static void
1192 vtcon_tty_free(void *xport)
1193 {
1194 	struct vtcon_port *port;
1195 
1196 	port = xport;
1197 
1198 	vtcon_port_destroy(port);
1199 	atomic_subtract_int(&vtcon_pending_free, 1);
1200 }
1201 
1202 static void
1203 vtcon_get_console_size(struct vtcon_softc *sc, uint16_t *cols, uint16_t *rows)
1204 {
1205 	struct virtio_console_config concfg;
1206 
1207 	KASSERT(sc->vtcon_flags & VTCON_FLAG_SIZE,
1208 	    ("%s: size feature not negotiated", __func__));
1209 
1210 	vtcon_read_config(sc, &concfg);
1211 
1212 	*cols = concfg.cols;
1213 	*rows = concfg.rows;
1214 }
1215 
1216 static void
1217 vtcon_enable_interrupts(struct vtcon_softc *sc)
1218 {
1219 	struct vtcon_port *port;
1220 
1221 	if (sc->vtcon_flags & VTCON_FLAG_MULTIPORT)
1222 		virtqueue_enable_intr(sc->vtcon_ctrl_rxvq);
1223 
1224 	TAILQ_FOREACH(port, &sc->vtcon_ports, vtcport_next)
1225 		vtcon_port_enable_intr(port);
1226 }
1227 
1228 static void
1229 vtcon_disable_interrupts(struct vtcon_softc *sc)
1230 {
1231 	struct vtcon_port *port;
1232 
1233 	if (sc->vtcon_flags & VTCON_FLAG_MULTIPORT)
1234 		virtqueue_disable_intr(sc->vtcon_ctrl_rxvq);
1235 
1236 	TAILQ_FOREACH(port, &sc->vtcon_ports, vtcport_next)
1237 		vtcon_port_disable_intr(port);
1238 }
1239