Deleted Added
full compact
virtio_console.c (273515) virtio_console.c (275273)
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

--- 13 unchanged lines hidden (view full) ---

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>
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

--- 13 unchanged lines hidden (view full) ---

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: head/sys/dev/virtio/console/virtio_console.c 273515 2014-10-23 04:47:32Z bryanv $");
30__FBSDID("$FreeBSD: stable/10/sys/dev/virtio/console/virtio_console.c 275273 2014-11-29 22:48:40Z bryanv $");
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>
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/kdb.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>

--- 5 unchanged lines hidden (view full) ---

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
38#include <sys/lock.h>
39#include <sys/mutex.h>
40#include <sys/sglist.h>
41#include <sys/sysctl.h>
42#include <sys/taskqueue.h>
43#include <sys/queue.h>
44
45#include <sys/conf.h>

--- 5 unchanged lines hidden (view full) ---

51#include <sys/bus.h>
52
53#include <dev/virtio/virtio.h>
54#include <dev/virtio/virtqueue.h>
55#include <dev/virtio/console/virtio_console.h>
56
57#include "virtio_if.h"
58
58#define VTCON_MAX_PORTS 1
59#define VTCON_MAX_PORTS 32
59#define VTCON_TTY_PREFIX "V"
60#define VTCON_BULK_BUFSZ 128
61
60#define VTCON_TTY_PREFIX "V"
61#define VTCON_BULK_BUFSZ 128
62
63/*
64 * The buffer cannot cross more than one page boundary due to the
65 * size of the sglist segment array used.
66 */
67CTASSERT(VTCON_BULK_BUFSZ <= PAGE_SIZE);
68
62struct vtcon_softc;
69struct vtcon_softc;
70struct vtcon_softc_port;
63
64struct vtcon_port {
71
72struct 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 struct mtx vtcport_mtx;
74 struct vtcon_softc *vtcport_sc;
75 struct vtcon_softc_port *vtcport_scport;
76 struct tty *vtcport_tty;
77 struct virtqueue *vtcport_invq;
78 struct virtqueue *vtcport_outvq;
79 int vtcport_id;
80 int vtcport_flags;
81#define VTCON_PORT_FLAG_GONE 0x01
82#define VTCON_PORT_FLAG_CONSOLE 0x02
83
84#if defined(KDB)
85 int vtcport_alt_break_state;
86#endif
73};
74
87};
88
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)
89#define VTCON_PORT_LOCK(_port) mtx_lock(&(_port)->vtcport_mtx)
90#define VTCON_PORT_UNLOCK(_port) mtx_unlock(&(_port)->vtcport_mtx)
85
91
92struct vtcon_softc_port {
93 struct vtcon_softc *vcsp_sc;
94 struct vtcon_port *vcsp_port;
95 struct virtqueue *vcsp_invq;
96 struct virtqueue *vcsp_outvq;
97};
98
86struct vtcon_softc {
87 device_t vtcon_dev;
88 struct mtx vtcon_mtx;
89 uint64_t vtcon_features;
99struct vtcon_softc {
100 device_t vtcon_dev;
101 struct mtx vtcon_mtx;
102 uint64_t vtcon_features;
103 uint32_t vtcon_max_ports;
90 uint32_t vtcon_flags;
104 uint32_t vtcon_flags;
91#define VTCON_FLAG_DETACHED 0x0001
92#define VTCON_FLAG_SIZE 0x0010
93#define VTCON_FLAG_MULTIPORT 0x0020
105#define VTCON_FLAG_DETACHED 0x01
106#define VTCON_FLAG_SIZE 0x02
107#define VTCON_FLAG_MULTIPORT 0x04
94
108
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 */
109 /*
110 * Ports can be added and removed during runtime, but we have
111 * to allocate all the virtqueues during attach. This array is
112 * indexed by the port ID.
113 */
108 struct vtcon_port_extra {
109 struct vtcon_port *port;
110 struct virtqueue *invq;
111 struct virtqueue *outvq;
112 } *vtcon_portsx;
114 struct vtcon_softc_port *vtcon_ports;
115
116 struct task vtcon_ctrl_task;
117 struct virtqueue *vtcon_ctrl_rxvq;
118 struct virtqueue *vtcon_ctrl_txvq;
119 struct mtx vtcon_ctrl_tx_mtx;
113};
114
120};
121
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)
122#define VTCON_LOCK(_sc) mtx_lock(&(_sc)->vtcon_mtx)
123#define VTCON_UNLOCK(_sc) mtx_unlock(&(_sc)->vtcon_mtx)
124#define VTCON_LOCK_ASSERT(_sc) \
125 mtx_assert(&(_sc)->vtcon_mtx, MA_OWNED)
126#define VTCON_LOCK_ASSERT_NOTOWNED(_sc) \
127 mtx_assert(&(_sc)->vtcon_mtx, MA_NOTOWNED)
124
128
129#define VTCON_CTRL_TX_LOCK(_sc) mtx_lock(&(_sc)->vtcon_ctrl_tx_mtx)
130#define VTCON_CTRL_TX_UNLOCK(_sc) mtx_unlock(&(_sc)->vtcon_ctrl_tx_mtx)
131
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
132#define VTCON_ASSERT_VALID_PORTID(_sc, _id) \
133 KASSERT((_id) >= 0 && (_id) < (_sc)->vtcon_max_ports, \
134 ("%s: port ID %d out of range", __func__, _id))
135
129#define VTCON_FEATURES 0
136#define VTCON_FEATURES VIRTIO_CONSOLE_F_MULTIPORT
130
131static struct virtio_feature_desc vtcon_feature_desc[] = {
132 { VIRTIO_CONSOLE_F_SIZE, "ConsoleSize" },
133 { VIRTIO_CONSOLE_F_MULTIPORT, "MultiplePorts" },
137
138static struct virtio_feature_desc vtcon_feature_desc[] = {
139 { VIRTIO_CONSOLE_F_SIZE, "ConsoleSize" },
140 { VIRTIO_CONSOLE_F_MULTIPORT, "MultiplePorts" },
141 { VIRTIO_CONSOLE_F_EMERG_WRITE, "EmergencyWrite" },
134
135 { 0, NULL }
136};
137
138static int vtcon_modevent(module_t, int, void *);
142
143 { 0, NULL }
144};
145
146static int vtcon_modevent(module_t, int, void *);
147static void vtcon_drain_all(void);
139
140static int vtcon_probe(device_t);
141static int vtcon_attach(device_t);
142static int vtcon_detach(device_t);
143static int vtcon_config_change(device_t);
144
148
149static int vtcon_probe(device_t);
150static int vtcon_attach(device_t);
151static int vtcon_detach(device_t);
152static int vtcon_config_change(device_t);
153
154static void vtcon_setup_features(struct vtcon_softc *);
145static void vtcon_negotiate_features(struct vtcon_softc *);
155static void vtcon_negotiate_features(struct vtcon_softc *);
156static int vtcon_alloc_scports(struct vtcon_softc *);
146static int vtcon_alloc_virtqueues(struct vtcon_softc *);
147static void vtcon_read_config(struct vtcon_softc *,
148 struct virtio_console_config *);
149
150static void vtcon_determine_max_ports(struct vtcon_softc *,
151 struct virtio_console_config *);
157static int vtcon_alloc_virtqueues(struct vtcon_softc *);
158static void vtcon_read_config(struct vtcon_softc *,
159 struct virtio_console_config *);
160
161static void vtcon_determine_max_ports(struct vtcon_softc *,
162 struct virtio_console_config *);
152static void vtcon_deinit_ports(struct vtcon_softc *);
163static void vtcon_destroy_ports(struct vtcon_softc *);
153static void vtcon_stop(struct vtcon_softc *);
154
164static void vtcon_stop(struct vtcon_softc *);
165
155static void vtcon_ctrl_rx_vq_intr(void *);
156static int vtcon_ctrl_enqueue_msg(struct vtcon_softc *,
166static int vtcon_ctrl_event_enqueue(struct vtcon_softc *,
157 struct virtio_console_control *);
167 struct virtio_console_control *);
158static int vtcon_ctrl_add_msg(struct vtcon_softc *);
159static void vtcon_ctrl_readd_msg(struct vtcon_softc *,
168static int vtcon_ctrl_event_create(struct vtcon_softc *);
169static void vtcon_ctrl_event_requeue(struct vtcon_softc *,
160 struct virtio_console_control *);
170 struct virtio_console_control *);
161static int vtcon_ctrl_populate(struct vtcon_softc *);
162static void vtcon_ctrl_send_msg(struct vtcon_softc *,
163 struct virtio_console_control *control);
164static void vtcon_ctrl_send_event(struct vtcon_softc *, uint32_t,
165 uint16_t, uint16_t);
171static int vtcon_ctrl_event_populate(struct vtcon_softc *);
172static void vtcon_ctrl_event_drain(struct vtcon_softc *);
166static int vtcon_ctrl_init(struct vtcon_softc *);
173static int vtcon_ctrl_init(struct vtcon_softc *);
167static void vtcon_ctrl_drain(struct vtcon_softc *);
168static void vtcon_ctrl_deinit(struct vtcon_softc *);
169static void vtcon_ctrl_port_add_event(struct vtcon_softc *, int);
170static void vtcon_ctrl_port_remove_event(struct vtcon_softc *, int);
171static void vtcon_ctrl_port_console_event(struct vtcon_softc *, int);
172static void vtcon_ctrl_port_open_event(struct vtcon_softc *, int);
174static void vtcon_ctrl_deinit(struct vtcon_softc *);
175static void vtcon_ctrl_port_add_event(struct vtcon_softc *, int);
176static void vtcon_ctrl_port_remove_event(struct vtcon_softc *, int);
177static void vtcon_ctrl_port_console_event(struct vtcon_softc *, int);
178static void vtcon_ctrl_port_open_event(struct vtcon_softc *, int);
173static void vtcon_ctrl_process_msg(struct vtcon_softc *,
179static void vtcon_ctrl_process_event(struct vtcon_softc *,
174 struct virtio_console_control *);
175static void vtcon_ctrl_task_cb(void *, int);
180 struct virtio_console_control *);
181static void vtcon_ctrl_task_cb(void *, int);
182static void vtcon_ctrl_event_intr(void *);
183static void vtcon_ctrl_poll(struct vtcon_softc *,
184 struct virtio_console_control *control);
185static void vtcon_ctrl_send_control(struct vtcon_softc *, uint32_t,
186 uint16_t, uint16_t);
176
187
177static int vtcon_port_add_inbuf(struct vtcon_port *);
178static void vtcon_port_readd_inbuf(struct vtcon_port *, void *);
188static int vtcon_port_enqueue_buf(struct vtcon_port *, void *, size_t);
189static int vtcon_port_create_buf(struct vtcon_port *);
190static void vtcon_port_requeue_buf(struct vtcon_port *, void *);
179static int vtcon_port_populate(struct vtcon_port *);
180static void vtcon_port_destroy(struct vtcon_port *);
191static int vtcon_port_populate(struct vtcon_port *);
192static void vtcon_port_destroy(struct vtcon_port *);
181static int vtcon_port_create(struct vtcon_softc *, int,
182 struct vtcon_port **);
183static void vtcon_port_drain_inbufs(struct vtcon_port *);
184static void vtcon_port_teardown(struct vtcon_port *, int);
193static int vtcon_port_create(struct vtcon_softc *, int);
194static void vtcon_port_drain_bufs(struct virtqueue *);
195static void vtcon_port_drain(struct vtcon_port *);
196static void vtcon_port_teardown(struct vtcon_port *);
185static void vtcon_port_change_size(struct vtcon_port *, uint16_t,
186 uint16_t);
197static void vtcon_port_change_size(struct vtcon_port *, uint16_t,
198 uint16_t);
199static void vtcon_port_update_console_size(struct vtcon_softc *);
187static void vtcon_port_enable_intr(struct vtcon_port *);
188static void vtcon_port_disable_intr(struct vtcon_port *);
200static void vtcon_port_enable_intr(struct vtcon_port *);
201static void vtcon_port_disable_intr(struct vtcon_port *);
189static void vtcon_port_intr(struct vtcon_port *);
190static void vtcon_port_in_vq_intr(void *);
191static void vtcon_port_put(struct vtcon_port *, void *, int);
192static void vtcon_port_send_ctrl_msg(struct vtcon_port *, uint16_t,
202static void vtcon_port_in(struct vtcon_port *);
203static void vtcon_port_intr(void *);
204static void vtcon_port_out(struct vtcon_port *, void *, int);
205static void vtcon_port_submit_event(struct vtcon_port *, uint16_t,
193 uint16_t);
206 uint16_t);
194static struct vtcon_port *vtcon_port_lookup_by_id(struct vtcon_softc *, int);
195
196static int vtcon_tty_open(struct tty *);
197static void vtcon_tty_close(struct tty *);
198static void vtcon_tty_outwakeup(struct tty *);
199static void vtcon_tty_free(void *);
200
201static void vtcon_get_console_size(struct vtcon_softc *, uint16_t *,
202 uint16_t *);

--- 40 unchanged lines hidden (view full) ---

243{
244 int error;
245
246 switch (type) {
247 case MOD_LOAD:
248 error = 0;
249 break;
250 case MOD_QUIESCE:
207
208static int vtcon_tty_open(struct tty *);
209static void vtcon_tty_close(struct tty *);
210static void vtcon_tty_outwakeup(struct tty *);
211static void vtcon_tty_free(void *);
212
213static void vtcon_get_console_size(struct vtcon_softc *, uint16_t *,
214 uint16_t *);

--- 40 unchanged lines hidden (view full) ---

255{
256 int error;
257
258 switch (type) {
259 case MOD_LOAD:
260 error = 0;
261 break;
262 case MOD_QUIESCE:
263 error = 0;
264 break;
251 case MOD_UNLOAD:
265 case MOD_UNLOAD:
252 error = vtcon_pending_free != 0 ? EBUSY : 0;
253 /* error = EOPNOTSUPP; */
266 vtcon_drain_all();
267 error = 0;
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
268 break;
269 case MOD_SHUTDOWN:
270 error = 0;
271 break;
272 default:
273 error = EOPNOTSUPP;
274 break;
275 }
276
277 return (error);
278}
279
280static void
281vtcon_drain_all(void)
282{
283 int first;
284
285 for (first = 1; vtcon_pending_free != 0; first = 0) {
286 if (first != 0) {
287 printf("virtio_console: Waiting for all detached TTY "
288 "devices to have open fds closed.\n");
289 }
290 pause("vtcondra", hz);
291 }
292}
293
266static int
267vtcon_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");

--- 6 unchanged lines hidden (view full) ---

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
294static int
295vtcon_probe(device_t dev)
296{
297
298 if (virtio_get_device_type(dev) != VIRTIO_ID_CONSOLE)
299 return (ENXIO);
300
301 device_set_desc(dev, "VirtIO Console Adapter");

--- 6 unchanged lines hidden (view full) ---

308{
309 struct vtcon_softc *sc;
310 struct virtio_console_config concfg;
311 int error;
312
313 sc = device_get_softc(dev);
314 sc->vtcon_dev = dev;
315
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);
316 mtx_init(&sc->vtcon_mtx, "vtconmtx", NULL, MTX_DEF);
317 mtx_init(&sc->vtcon_ctrl_tx_mtx, "vtconctrlmtx", NULL, MTX_DEF);
291
292 virtio_set_feature_desc(dev, vtcon_feature_desc);
318
319 virtio_set_feature_desc(dev, vtcon_feature_desc);
293 vtcon_negotiate_features(sc);
320 vtcon_setup_features(sc);
294
321
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
322 vtcon_read_config(sc, &concfg);
323 vtcon_determine_max_ports(sc, &concfg);
324
325 error = vtcon_alloc_scports(sc);
326 if (error) {
327 device_printf(dev, "cannot allocate softc port structures\n");
328 goto fail;
329 }
330
303 error = vtcon_alloc_virtqueues(sc);
304 if (error) {
305 device_printf(dev, "cannot allocate virtqueues\n");
306 goto fail;
307 }
308
331 error = vtcon_alloc_virtqueues(sc);
332 if (error) {
333 device_printf(dev, "cannot allocate virtqueues\n");
334 goto fail;
335 }
336
309 if (sc->vtcon_flags & VTCON_FLAG_MULTIPORT)
337 if (sc->vtcon_flags & VTCON_FLAG_MULTIPORT) {
338 TASK_INIT(&sc->vtcon_ctrl_task, 0, vtcon_ctrl_task_cb, sc);
310 error = vtcon_ctrl_init(sc);
339 error = vtcon_ctrl_init(sc);
311 else
312 error = vtcon_port_create(sc, 0, NULL);
313 if (error)
314 goto fail;
340 if (error)
341 goto fail;
342 } else {
343 error = vtcon_port_create(sc, 0);
344 if (error)
345 goto fail;
346 if (sc->vtcon_flags & VTCON_FLAG_SIZE)
347 vtcon_port_update_console_size(sc);
348 }
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
349
350 error = virtio_setup_intr(dev, INTR_TYPE_TTY);
351 if (error) {
352 device_printf(dev, "cannot setup virtqueue interrupts\n");
353 goto fail;
354 }
355
356 vtcon_enable_interrupts(sc);
357
324 vtcon_ctrl_send_event(sc, VIRTIO_CONSOLE_BAD_ID,
358 vtcon_ctrl_send_control(sc, VIRTIO_CONSOLE_BAD_ID,
325 VIRTIO_CONSOLE_DEVICE_READY, 1);
326
327fail:
328 if (error)
329 vtcon_detach(dev);
330
331 return (error);
332}

--- 6 unchanged lines hidden (view full) ---

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
359 VIRTIO_CONSOLE_DEVICE_READY, 1);
360
361fail:
362 if (error)
363 vtcon_detach(dev);
364
365 return (error);
366}

--- 6 unchanged lines hidden (view full) ---

373 sc = device_get_softc(dev);
374
375 VTCON_LOCK(sc);
376 sc->vtcon_flags |= VTCON_FLAG_DETACHED;
377 if (device_is_attached(dev))
378 vtcon_stop(sc);
379 VTCON_UNLOCK(sc);
380
347 taskqueue_drain(taskqueue_thread, &sc->vtcon_ctrl_task);
348
349 if (sc->vtcon_flags & VTCON_FLAG_MULTIPORT)
381 if (sc->vtcon_flags & VTCON_FLAG_MULTIPORT) {
382 taskqueue_drain(taskqueue_thread, &sc->vtcon_ctrl_task);
350 vtcon_ctrl_deinit(sc);
383 vtcon_ctrl_deinit(sc);
384 }
351
385
352 vtcon_deinit_ports(sc);
386 vtcon_destroy_ports(sc);
387 mtx_destroy(&sc->vtcon_mtx);
388 mtx_destroy(&sc->vtcon_ctrl_tx_mtx);
353
389
354 VTCON_LOCK_DESTROY(sc);
355
356 return (0);
357}
358
359static int
360vtcon_config_change(device_t dev)
361{
362 struct vtcon_softc *sc;
390 return (0);
391}
392
393static int
394vtcon_config_change(device_t dev)
395{
396 struct vtcon_softc *sc;
363 struct vtcon_port *port;
364 uint16_t cols, rows;
365
366 sc = device_get_softc(dev);
367
368 /*
397
398 sc = device_get_softc(dev);
399
400 /*
369 * With the multiport feature, all configuration changes are
370 * done through control virtqueue events. This is a spurious
371 * interrupt.
401 * When the multiport feature is negotiated, all configuration
402 * changes are done through control virtqueue events.
372 */
403 */
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);
404 if ((sc->vtcon_flags & VTCON_FLAG_MULTIPORT) == 0) {
405 if (sc->vtcon_flags & VTCON_FLAG_SIZE)
406 vtcon_port_update_console_size(sc);
387 }
388
389 return (0);
390}
391
392static void
393vtcon_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
407 }
408
409 return (0);
410}
411
412static void
413vtcon_negotiate_features(struct vtcon_softc *sc)
414{
415 device_t dev;
416 uint64_t features;
417
418 dev = sc->vtcon_dev;
419 features = VTCON_FEATURES;
420
421 sc->vtcon_features = virtio_negotiate_features(dev, features);
422}
423
424static void
425vtcon_setup_features(struct vtcon_softc *sc)
426{
427 device_t dev;
428
429 dev = sc->vtcon_dev;
430
431 vtcon_negotiate_features(sc);
432
433 if (virtio_with_feature(dev, VIRTIO_CONSOLE_F_SIZE))
434 sc->vtcon_flags |= VTCON_FLAG_SIZE;
435 if (virtio_with_feature(dev, VIRTIO_CONSOLE_F_MULTIPORT))
436 sc->vtcon_flags |= VTCON_FLAG_MULTIPORT;
437}
438
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
411static void
412vtcon_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
439#define VTCON_GET_CONFIG(_dev, _feature, _field, _cfg) \
440 if (virtio_with_feature(_dev, _feature)) { \
441 virtio_read_device_config(_dev, \
442 offsetof(struct virtio_console_config, _field), \
443 &(_cfg)->_field, sizeof((_cfg)->_field)); \
444 }
445
446static void
447vtcon_read_config(struct vtcon_softc *sc, struct virtio_console_config *concfg)
448{
449 device_t dev;
450
451 dev = sc->vtcon_dev;
452
453 bzero(concfg, sizeof(struct virtio_console_config));
454
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
428static int
455 VTCON_GET_CONFIG(dev, VIRTIO_CONSOLE_F_SIZE, cols, concfg);
456 VTCON_GET_CONFIG(dev, VIRTIO_CONSOLE_F_SIZE, rows, concfg);
457 VTCON_GET_CONFIG(dev, VIRTIO_CONSOLE_F_MULTIPORT, max_nr_ports, concfg);
458}
459
460#undef VTCON_GET_CONFIG
461
462static int
463vtcon_alloc_scports(struct vtcon_softc *sc)
464{
465 struct vtcon_softc_port *scport;
466 int max, i;
467
468 max = sc->vtcon_max_ports;
469
470 sc->vtcon_ports = malloc(sizeof(struct vtcon_softc_port) * max,
471 M_DEVBUF, M_NOWAIT | M_ZERO);
472 if (sc->vtcon_ports == NULL)
473 return (ENOMEM);
474
475 for (i = 0; i < max; i++) {
476 scport = &sc->vtcon_ports[i];
477 scport->vcsp_sc = sc;
478 }
479
480 return (0);
481}
482
483static int
429vtcon_alloc_virtqueues(struct vtcon_softc *sc)
430{
431 device_t dev;
432 struct vq_alloc_info *info;
484vtcon_alloc_virtqueues(struct vtcon_softc *sc)
485{
486 device_t dev;
487 struct vq_alloc_info *info;
433 struct vtcon_port_extra *portx;
488 struct vtcon_softc_port *scport;
434 int i, idx, portidx, nvqs, error;
435
436 dev = sc->vtcon_dev;
437
489 int i, idx, portidx, nvqs, error;
490
491 dev = sc->vtcon_dev;
492
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
493 nvqs = sc->vtcon_max_ports * 2;
494 if (sc->vtcon_flags & VTCON_FLAG_MULTIPORT)
495 nvqs += 2;
496
497 info = malloc(sizeof(struct vq_alloc_info) * nvqs, M_TEMP, M_NOWAIT);
498 if (info == NULL)
499 return (ENOMEM);
500
451 for (i = 0, idx = 0, portidx = 0; i < nvqs / 2; i++, idx+=2) {
501 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,
502
503 if (i == 1) {
504 /* The control virtqueues are after the first port. */
505 VQ_ALLOC_INFO_INIT(&info[idx], 0,
456 vtcon_ctrl_rx_vq_intr, sc, &sc->vtcon_ctrl_rxvq,
506 vtcon_ctrl_event_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
507 "%s-control rx", device_get_nameunit(dev));
508 VQ_ALLOC_INFO_INIT(&info[idx+1], 0,
509 NULL, sc, &sc->vtcon_ctrl_txvq,
510 "%s-control tx", device_get_nameunit(dev));
511 continue;
512 }
513
464 portx = &sc->vtcon_portsx[portidx];
514 scport = &sc->vtcon_ports[portidx];
465
515
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);
516 VQ_ALLOC_INFO_INIT(&info[idx], 0, vtcon_port_intr,
517 scport, &scport->vcsp_invq, "%s-port%d in",
518 device_get_nameunit(dev), i);
469 VQ_ALLOC_INFO_INIT(&info[idx+1], 0, NULL,
519 VQ_ALLOC_INFO_INIT(&info[idx+1], 0, NULL,
470 NULL, &portx->outvq, "%s-port%d out",
471 device_get_nameunit(dev), portidx);
520 NULL, &scport->vcsp_outvq, "%s-port%d out",
521 device_get_nameunit(dev), i);
472
473 portidx++;
474 }
475
476 error = virtio_alloc_virtqueues(dev, 0, nvqs, info);
477 free(info, M_TEMP);
478
479 return (error);

--- 9 unchanged lines hidden (view full) ---

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
496static void
522
523 portidx++;
524 }
525
526 error = virtio_alloc_virtqueues(dev, 0, nvqs, info);
527 free(info, M_TEMP);
528
529 return (error);

--- 9 unchanged lines hidden (view full) ---

539 min(concfg->max_nr_ports, VTCON_MAX_PORTS);
540 if (sc->vtcon_max_ports == 0)
541 sc->vtcon_max_ports = 1;
542 } else
543 sc->vtcon_max_ports = 1;
544}
545
546static void
497vtcon_deinit_ports(struct vtcon_softc *sc)
547vtcon_destroy_ports(struct vtcon_softc *sc)
498{
548{
499 struct vtcon_port *port, *tmp;
549 struct vtcon_softc_port *scport;
550 struct vtcon_port *port;
551 struct virtqueue *vq;
552 int i;
500
553
501 TAILQ_FOREACH_SAFE(port, &sc->vtcon_ports, vtcport_next, tmp) {
502 vtcon_port_teardown(port, 1);
503 }
554 if (sc->vtcon_ports == NULL)
555 return;
504
556
505 if (sc->vtcon_portsx != NULL) {
506 free(sc->vtcon_portsx, M_DEVBUF);
507 sc->vtcon_portsx = NULL;
557 VTCON_LOCK(sc);
558 for (i = 0; i < sc->vtcon_max_ports; i++) {
559 scport = &sc->vtcon_ports[i];
560
561 port = scport->vcsp_port;
562 if (port != NULL) {
563 scport->vcsp_port = NULL;
564 VTCON_PORT_LOCK(port);
565 VTCON_UNLOCK(sc);
566 vtcon_port_teardown(port);
567 VTCON_LOCK(sc);
568 }
569
570 vq = scport->vcsp_invq;
571 if (vq != NULL)
572 vtcon_port_drain_bufs(vq);
508 }
573 }
574 VTCON_UNLOCK(sc);
575
576 free(sc->vtcon_ports, M_DEVBUF);
577 sc->vtcon_ports = NULL;
509}
510
511static void
512vtcon_stop(struct vtcon_softc *sc)
513{
514
515 vtcon_disable_interrupts(sc);
516 virtio_stop(sc->vtcon_dev);
517}
518
578}
579
580static void
581vtcon_stop(struct vtcon_softc *sc)
582{
583
584 vtcon_disable_interrupts(sc);
585 virtio_stop(sc->vtcon_dev);
586}
587
519static void
520vtcon_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
533static int
588static int
534vtcon_ctrl_enqueue_msg(struct vtcon_softc *sc,
589vtcon_ctrl_event_enqueue(struct vtcon_softc *sc,
535 struct virtio_console_control *control)
536{
590 struct virtio_console_control *control)
591{
537 struct sglist_seg segs[1];
592 struct sglist_seg segs[2];
538 struct sglist sg;
539 struct virtqueue *vq;
593 struct sglist sg;
594 struct virtqueue *vq;
540 int error __unused;
595 int error;
541
542 vq = sc->vtcon_ctrl_rxvq;
543
596
597 vq = sc->vtcon_ctrl_rxvq;
598
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));
599 sglist_init(&sg, 2, segs);
600 error = sglist_append(&sg, control,
601 sizeof(struct virtio_console_control));
602 KASSERT(error == 0, ("%s: error %d adding control to sglist",
603 __func__, error));
548
604
549 return (virtqueue_enqueue(vq, control, &sg, 0, 1));
605 return (virtqueue_enqueue(vq, control, &sg, 0, sg.sg_nseg));
550}
551
552static int
606}
607
608static int
553vtcon_ctrl_add_msg(struct vtcon_softc *sc)
609vtcon_ctrl_event_create(struct vtcon_softc *sc)
554{
555 struct virtio_console_control *control;
556 int error;
557
610{
611 struct virtio_console_control *control;
612 int error;
613
558 control = malloc(sizeof(*control), M_DEVBUF, M_ZERO | M_NOWAIT);
614 control = malloc(sizeof(struct virtio_console_control), M_DEVBUF,
615 M_ZERO | M_NOWAIT);
559 if (control == NULL)
560 return (ENOMEM);
561
616 if (control == NULL)
617 return (ENOMEM);
618
562 error = vtcon_ctrl_enqueue_msg(sc, control);
619 error = vtcon_ctrl_event_enqueue(sc, control);
563 if (error)
564 free(control, M_DEVBUF);
565
566 return (error);
567}
568
569static void
620 if (error)
621 free(control, M_DEVBUF);
622
623 return (error);
624}
625
626static void
570vtcon_ctrl_readd_msg(struct vtcon_softc *sc,
627vtcon_ctrl_event_requeue(struct vtcon_softc *sc,
571 struct virtio_console_control *control)
572{
573 int error;
574
628 struct virtio_console_control *control)
629{
630 int error;
631
575 bzero(control, sizeof(*control));
632 bzero(control, sizeof(struct virtio_console_control));
576
633
577 error = vtcon_ctrl_enqueue_msg(sc, control);
634 error = vtcon_ctrl_event_enqueue(sc, control);
578 KASSERT(error == 0,
579 ("%s: cannot requeue control buffer %d", __func__, error));
580}
581
582static int
635 KASSERT(error == 0,
636 ("%s: cannot requeue control buffer %d", __func__, error));
637}
638
639static int
583vtcon_ctrl_populate(struct vtcon_softc *sc)
640vtcon_ctrl_event_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++) {
641{
642 struct virtqueue *vq;
643 int nbufs, error;
644
645 vq = sc->vtcon_ctrl_rxvq;
646 error = ENOSPC;
647
648 for (nbufs = 0; !virtqueue_full(vq); nbufs++) {
592 error = vtcon_ctrl_add_msg(sc);
649 error = vtcon_ctrl_event_create(sc);
593 if (error)
594 break;
595 }
596
597 if (nbufs > 0) {
598 virtqueue_notify(vq);
650 if (error)
651 break;
652 }
653
654 if (nbufs > 0) {
655 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;
656 error = 0;
606 }
607
608 return (error);
609}
610
611static void
657 }
658
659 return (error);
660}
661
662static void
612vtcon_ctrl_send_msg(struct vtcon_softc *sc,
613 struct virtio_console_control *control)
663vtcon_ctrl_event_drain(struct vtcon_softc *sc)
614{
664{
615 struct sglist_seg segs[1];
616 struct sglist sg;
665 struct virtio_console_control *control;
617 struct virtqueue *vq;
666 struct virtqueue *vq;
618 int error;
667 int last;
619
668
620 vq = sc->vtcon_ctrl_txvq;
621 KASSERT(virtqueue_empty(vq),
622 ("%s: virtqueue is not emtpy", __func__));
669 vq = sc->vtcon_ctrl_rxvq;
670 last = 0;
623
671
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
636static void
637vtcon_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)
672 if (vq == NULL)
643 return;
644
673 return;
674
645 control.id = portid;
646 control.event = event;
647 control.value = value;
648
649 vtcon_ctrl_send_msg(sc, &control);
675 VTCON_LOCK(sc);
676 while ((control = virtqueue_drain(vq, &last)) != NULL)
677 free(control, M_DEVBUF);
678 VTCON_UNLOCK(sc);
650}
651
652static int
653vtcon_ctrl_init(struct vtcon_softc *sc)
654{
655 int error;
656
679}
680
681static int
682vtcon_ctrl_init(struct vtcon_softc *sc)
683{
684 int error;
685
657 error = vtcon_ctrl_populate(sc);
686 error = vtcon_ctrl_event_populate(sc);
658
659 return (error);
660}
661
662static void
687
688 return (error);
689}
690
691static void
663vtcon_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
679static void
680vtcon_ctrl_deinit(struct vtcon_softc *sc)
681{
682
692vtcon_ctrl_deinit(struct vtcon_softc *sc)
693{
694
683 vtcon_ctrl_drain(sc);
695 vtcon_ctrl_event_drain(sc);
684}
685
686static void
687vtcon_ctrl_port_add_event(struct vtcon_softc *sc, int id)
688{
689 device_t dev;
696}
697
698static void
699vtcon_ctrl_port_add_event(struct vtcon_softc *sc, int id)
700{
701 device_t dev;
690 struct vtcon_port *port;
691 int error;
692
693 dev = sc->vtcon_dev;
694
702 int error;
703
704 dev = sc->vtcon_dev;
705
695 if (vtcon_port_lookup_by_id(sc, id) != NULL) {
706 /* This single thread only way for ports to be created. */
707 if (sc->vtcon_ports[id].vcsp_port != NULL) {
696 device_printf(dev, "%s: adding port %d, but already exists\n",
697 __func__, id);
698 return;
699 }
700
708 device_printf(dev, "%s: adding port %d, but already exists\n",
709 __func__, id);
710 return;
711 }
712
701 error = vtcon_port_create(sc, id, &port);
713 error = vtcon_port_create(sc, id);
702 if (error) {
703 device_printf(dev, "%s: cannot create port %d: %d\n",
704 __func__, id, error);
714 if (error) {
715 device_printf(dev, "%s: cannot create port %d: %d\n",
716 __func__, id, error);
717 vtcon_ctrl_send_control(sc, id, VIRTIO_CONSOLE_PORT_READY, 0);
705 return;
706 }
718 return;
719 }
707
708 vtcon_port_send_ctrl_msg(port, VIRTIO_CONSOLE_PORT_READY, 1);
709}
710
711static void
712vtcon_ctrl_port_remove_event(struct vtcon_softc *sc, int id)
713{
714 device_t dev;
720}
721
722static void
723vtcon_ctrl_port_remove_event(struct vtcon_softc *sc, int id)
724{
725 device_t dev;
726 struct vtcon_softc_port *scport;
715 struct vtcon_port *port;
716
717 dev = sc->vtcon_dev;
727 struct vtcon_port *port;
728
729 dev = sc->vtcon_dev;
730 scport = &sc->vtcon_ports[id];
718
731
719 port = vtcon_port_lookup_by_id(sc, id);
732 VTCON_LOCK(sc);
733 port = scport->vcsp_port;
720 if (port == NULL) {
734 if (port == NULL) {
735 VTCON_UNLOCK(sc);
721 device_printf(dev, "%s: remove port %d, but does not exist\n",
722 __func__, id);
723 return;
724 }
725
736 device_printf(dev, "%s: remove port %d, but does not exist\n",
737 __func__, id);
738 return;
739 }
740
726 vtcon_port_teardown(port, 1);
741 scport->vcsp_port = NULL;
742 VTCON_PORT_LOCK(port);
743 VTCON_UNLOCK(sc);
744 vtcon_port_teardown(port);
727}
728
729static void
730vtcon_ctrl_port_console_event(struct vtcon_softc *sc, int id)
731{
732 device_t dev;
745}
746
747static void
748vtcon_ctrl_port_console_event(struct vtcon_softc *sc, int id)
749{
750 device_t dev;
751 struct vtcon_softc_port *scport;
752 struct vtcon_port *port;
733
734 dev = sc->vtcon_dev;
753
754 dev = sc->vtcon_dev;
755 scport = &sc->vtcon_ports[id];
735
756
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);
757 VTCON_LOCK(sc);
758 port = scport->vcsp_port;
759 if (port == NULL) {
760 VTCON_UNLOCK(sc);
761 device_printf(dev, "%s: console port %d, but does not exist\n",
762 __func__, id);
763 return;
764 }
765
766 VTCON_PORT_LOCK(port);
767 VTCON_UNLOCK(sc);
768 port->vtcport_flags |= VTCON_PORT_FLAG_CONSOLE;
769 vtcon_port_submit_event(port, VIRTIO_CONSOLE_PORT_OPEN, 1);
770 VTCON_PORT_UNLOCK(port);
740}
741
742static void
743vtcon_ctrl_port_open_event(struct vtcon_softc *sc, int id)
744{
745 device_t dev;
771}
772
773static void
774vtcon_ctrl_port_open_event(struct vtcon_softc *sc, int id)
775{
776 device_t dev;
777 struct vtcon_softc_port *scport;
746 struct vtcon_port *port;
747
748 dev = sc->vtcon_dev;
778 struct vtcon_port *port;
779
780 dev = sc->vtcon_dev;
781 scport = &sc->vtcon_ports[id];
749
782
750 port = vtcon_port_lookup_by_id(sc, id);
783 VTCON_LOCK(sc);
784 port = scport->vcsp_port;
751 if (port == NULL) {
785 if (port == NULL) {
786 VTCON_UNLOCK(sc);
752 device_printf(dev, "%s: open port %d, but does not exist\n",
753 __func__, id);
754 return;
755 }
756
787 device_printf(dev, "%s: open port %d, but does not exist\n",
788 __func__, id);
789 return;
790 }
791
792 VTCON_PORT_LOCK(port);
793 VTCON_UNLOCK(sc);
757 vtcon_port_enable_intr(port);
794 vtcon_port_enable_intr(port);
795 VTCON_PORT_UNLOCK(port);
758}
759
760static void
796}
797
798static void
761vtcon_ctrl_process_msg(struct vtcon_softc *sc,
799vtcon_ctrl_process_event(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

--- 28 unchanged lines hidden (view full) ---

798}
799
800static void
801vtcon_ctrl_task_cb(void *xsc, int pending)
802{
803 struct vtcon_softc *sc;
804 struct virtqueue *vq;
805 struct virtio_console_control *control;
800 struct virtio_console_control *control)
801{
802 device_t dev;
803 int id;
804
805 dev = sc->vtcon_dev;
806 id = control->id;
807

--- 28 unchanged lines hidden (view full) ---

836}
837
838static void
839vtcon_ctrl_task_cb(void *xsc, int pending)
840{
841 struct vtcon_softc *sc;
842 struct virtqueue *vq;
843 struct virtio_console_control *control;
844 int detached;
806
807 sc = xsc;
808 vq = sc->vtcon_ctrl_rxvq;
809
810 VTCON_LOCK(sc);
845
846 sc = xsc;
847 vq = sc->vtcon_ctrl_rxvq;
848
849 VTCON_LOCK(sc);
811 while ((sc->vtcon_flags & VTCON_FLAG_DETACHED) == 0) {
850
851 while ((detached = (sc->vtcon_flags & VTCON_FLAG_DETACHED)) == 0) {
812 control = virtqueue_dequeue(vq, NULL);
813 if (control == NULL)
814 break;
815
816 VTCON_UNLOCK(sc);
852 control = virtqueue_dequeue(vq, NULL);
853 if (control == NULL)
854 break;
855
856 VTCON_UNLOCK(sc);
817 vtcon_ctrl_process_msg(sc, control);
857 vtcon_ctrl_process_event(sc, control);
818 VTCON_LOCK(sc);
858 VTCON_LOCK(sc);
819 vtcon_ctrl_readd_msg(sc, control);
859 vtcon_ctrl_event_requeue(sc, control);
820 }
860 }
861
862 if (!detached) {
863 virtqueue_notify(vq);
864 if (virtqueue_enable_intr(vq) != 0)
865 taskqueue_enqueue(taskqueue_thread,
866 &sc->vtcon_ctrl_task);
867 }
868
821 VTCON_UNLOCK(sc);
869 VTCON_UNLOCK(sc);
870}
822
871
823 if (virtqueue_enable_intr(vq) != 0)
824 taskqueue_enqueue(taskqueue_thread, &sc->vtcon_ctrl_task);
872static void
873vtcon_ctrl_event_intr(void *xsc)
874{
875 struct vtcon_softc *sc;
876
877 sc = xsc;
878
879 /*
880 * Only some events require us to potentially block, but it
881 * easier to just defer all event handling to the taskqueue.
882 */
883 taskqueue_enqueue(taskqueue_thread, &sc->vtcon_ctrl_task);
825}
826
884}
885
886static void
887vtcon_ctrl_poll(struct vtcon_softc *sc,
888 struct virtio_console_control *control)
889{
890 struct sglist_seg segs[2];
891 struct sglist sg;
892 struct virtqueue *vq;
893 int error;
894
895 vq = sc->vtcon_ctrl_txvq;
896
897 sglist_init(&sg, 2, segs);
898 error = sglist_append(&sg, control,
899 sizeof(struct virtio_console_control));
900 KASSERT(error == 0, ("%s: error %d adding control to sglist",
901 __func__, error));
902
903 /*
904 * We cannot use the softc lock to serialize access to this
905 * virtqueue since this is called from the tty layer with the
906 * port lock held. Acquiring the softc would violate our lock
907 * ordering.
908 */
909 VTCON_CTRL_TX_LOCK(sc);
910 KASSERT(virtqueue_empty(vq),
911 ("%s: virtqueue is not emtpy", __func__));
912 error = virtqueue_enqueue(vq, control, &sg, sg.sg_nseg, 0);
913 if (error == 0) {
914 virtqueue_notify(vq);
915 virtqueue_poll(vq, NULL);
916 }
917 VTCON_CTRL_TX_UNLOCK(sc);
918}
919
920static void
921vtcon_ctrl_send_control(struct vtcon_softc *sc, uint32_t portid,
922 uint16_t event, uint16_t value)
923{
924 struct virtio_console_control control;
925
926 if ((sc->vtcon_flags & VTCON_FLAG_MULTIPORT) == 0)
927 return;
928
929 control.id = portid;
930 control.event = event;
931 control.value = value;
932
933 vtcon_ctrl_poll(sc, &control);
934}
935
827static int
936static int
828vtcon_port_enqueue_inbuf(struct vtcon_port *port, void *buf, size_t len)
937vtcon_port_enqueue_buf(struct vtcon_port *port, void *buf, size_t len)
829{
938{
830 struct sglist_seg segs[1];
939 struct sglist_seg segs[2];
831 struct sglist sg;
832 struct virtqueue *vq;
833 int error;
834
835 vq = port->vtcport_invq;
836
940 struct sglist sg;
941 struct virtqueue *vq;
942 int error;
943
944 vq = port->vtcport_invq;
945
837 sglist_init(&sg, 1, segs);
946 sglist_init(&sg, 2, segs);
838 error = sglist_append(&sg, buf, len);
947 error = sglist_append(&sg, buf, len);
839 KASSERT(error == 0 && sg.sg_nseg == 1,
948 KASSERT(error == 0,
840 ("%s: error %d adding buffer to sglist", __func__, error));
841
949 ("%s: error %d adding buffer to sglist", __func__, error));
950
842 return (virtqueue_enqueue(vq, buf, &sg, 0, 1));
951 error = virtqueue_enqueue(vq, buf, &sg, 0, sg.sg_nseg);
952
953 return (error);
843}
844
845static int
954}
955
956static int
846vtcon_port_add_inbuf(struct vtcon_port *port)
957vtcon_port_create_buf(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
958{
959 void *buf;
960 int error;
961
962 buf = malloc(VTCON_BULK_BUFSZ, M_DEVBUF, M_ZERO | M_NOWAIT);
963 if (buf == NULL)
964 return (ENOMEM);
965
855 error = vtcon_port_enqueue_inbuf(port, buf, VTCON_BULK_BUFSZ);
966 error = vtcon_port_enqueue_buf(port, buf, VTCON_BULK_BUFSZ);
856 if (error)
857 free(buf, M_DEVBUF);
858
859 return (error);
860}
861
862static void
967 if (error)
968 free(buf, M_DEVBUF);
969
970 return (error);
971}
972
973static void
863vtcon_port_readd_inbuf(struct vtcon_port *port, void *buf)
974vtcon_port_requeue_buf(struct vtcon_port *port, void *buf)
864{
975{
865 int error __unused;
976 int error;
866
977
867 error = vtcon_port_enqueue_inbuf(port, buf, VTCON_BULK_BUFSZ);
978 error = vtcon_port_enqueue_buf(port, buf, VTCON_BULK_BUFSZ);
868 KASSERT(error == 0,
869 ("%s: cannot requeue input buffer %d", __func__, error));
870}
871
872static int
873vtcon_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++) {
979 KASSERT(error == 0,
980 ("%s: cannot requeue input buffer %d", __func__, error));
981}
982
983static int
984vtcon_port_populate(struct vtcon_port *port)
985{
986 struct virtqueue *vq;
987 int nbufs, error;
988
989 vq = port->vtcport_invq;
990 error = ENOSPC;
991
992 for (nbufs = 0; !virtqueue_full(vq); nbufs++) {
882 error = vtcon_port_add_inbuf(port);
993 error = vtcon_port_create_buf(port);
883 if (error)
884 break;
885 }
886
887 if (nbufs > 0) {
888 virtqueue_notify(vq);
994 if (error)
995 break;
996 }
997
998 if (nbufs > 0) {
999 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;
1000 error = 0;
896 }
897
898 return (error);
899}
900
901static void
902vtcon_port_destroy(struct vtcon_port *port)
903{
904
905 port->vtcport_sc = NULL;
1001 }
1002
1003 return (error);
1004}
1005
1006static void
1007vtcon_port_destroy(struct vtcon_port *port)
1008{
1009
1010 port->vtcport_sc = NULL;
1011 port->vtcport_scport = NULL;
1012 port->vtcport_invq = NULL;
1013 port->vtcport_outvq = NULL;
906 port->vtcport_id = -1;
1014 port->vtcport_id = -1;
907 VTCON_PORT_LOCK_DESTROY(port);
1015 mtx_destroy(&port->vtcport_mtx);
908 free(port, M_DEVBUF);
909}
910
911static int
1016 free(port, M_DEVBUF);
1017}
1018
1019static int
912vtcon_port_create(struct vtcon_softc *sc, int id, struct vtcon_port **portp)
1020vtcon_port_init_vqs(struct vtcon_port *port)
913{
1021{
1022 struct vtcon_softc_port *scport;
1023 int error;
1024
1025 scport = port->vtcport_scport;
1026
1027 port->vtcport_invq = scport->vcsp_invq;
1028 port->vtcport_outvq = scport->vcsp_outvq;
1029
1030 /*
1031 * Free any data left over from when this virtqueue was in use by a
1032 * prior port. We have not yet notified the host that the port is
1033 * ready, so assume nothing in the virtqueue can be for us.
1034 */
1035 vtcon_port_drain(port);
1036
1037 KASSERT(virtqueue_empty(port->vtcport_invq),
1038 ("%s: in virtqueue is not empty", __func__));
1039 KASSERT(virtqueue_empty(port->vtcport_outvq),
1040 ("%s: out virtqueue is not empty", __func__));
1041
1042 error = vtcon_port_populate(port);
1043 if (error)
1044 return (error);
1045
1046 return (0);
1047}
1048
1049static int
1050vtcon_port_create(struct vtcon_softc *sc, int id)
1051{
914 device_t dev;
1052 device_t dev;
915 struct vtcon_port_extra *portx;
1053 struct vtcon_softc_port *scport;
916 struct vtcon_port *port;
917 int error;
918
1054 struct vtcon_port *port;
1055 int error;
1056
919 MPASS(id < sc->vtcon_max_ports);
920 dev = sc->vtcon_dev;
1057 dev = sc->vtcon_dev;
921 portx = &sc->vtcon_portsx[id];
1058 scport = &sc->vtcon_ports[id];
922
1059
923 if (portx->port != NULL)
924 return (EEXIST);
1060 VTCON_ASSERT_VALID_PORTID(sc, id);
1061 MPASS(scport->vcsp_port == NULL);
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;
1062
1063 port = malloc(sizeof(struct vtcon_port), M_DEVBUF, M_NOWAIT | M_ZERO);
1064 if (port == NULL)
1065 return (ENOMEM);
1066
1067 port->vtcport_sc = sc;
1068 port->vtcport_scport = scport;
931 port->vtcport_id = id;
1069 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);
1070 mtx_init(&port->vtcport_mtx, "vtcpmtx", NULL, MTX_DEF);
935 port->vtcport_tty = tty_alloc_mutex(&vtcon_tty_class, port,
936 &port->vtcport_mtx);
937
1071 port->vtcport_tty = tty_alloc_mutex(&vtcon_tty_class, port,
1072 &port->vtcport_mtx);
1073
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);
1074 error = vtcon_port_init_vqs(port);
947 if (error) {
1075 if (error) {
948 vtcon_port_teardown(port, 0);
1076 VTCON_PORT_LOCK(port);
1077 vtcon_port_teardown(port);
949 return (error);
950 }
951
1078 return (error);
1079 }
1080
952 tty_makedev(port->vtcport_tty, NULL, "%s%r.%r", VTCON_TTY_PREFIX,
953 device_get_unit(dev), id);
954
955 VTCON_LOCK(sc);
1081 VTCON_LOCK(sc);
956 portx->port = port;
957 TAILQ_INSERT_TAIL(&sc->vtcon_ports, port, vtcport_next);
1082 VTCON_PORT_LOCK(port);
1083 scport->vcsp_port = port;
1084 vtcon_port_enable_intr(port);
1085 vtcon_port_submit_event(port, VIRTIO_CONSOLE_PORT_READY, 1);
1086 VTCON_PORT_UNLOCK(port);
958 VTCON_UNLOCK(sc);
959
1087 VTCON_UNLOCK(sc);
1088
960 if (portp != NULL)
961 *portp = port;
1089 tty_makedev(port->vtcport_tty, NULL, "%s%r.%r", VTCON_TTY_PREFIX,
1090 device_get_unit(dev), id);
962
963 return (0);
964}
965
966static void
1091
1092 return (0);
1093}
1094
1095static void
967vtcon_port_drain_inbufs(struct vtcon_port *port)
1096vtcon_port_drain_bufs(struct virtqueue *vq)
968{
1097{
969 struct virtqueue *vq;
970 void *buf;
971 int last;
972
1098 void *buf;
1099 int last;
1100
973 vq = port->vtcport_invq;
974 last = 0;
975
1101 last = 0;
1102
976 if (vq == NULL)
977 return;
978
979 while ((buf = virtqueue_drain(vq, &last)) != NULL)
980 free(buf, M_DEVBUF);
981}
982
983static void
1103 while ((buf = virtqueue_drain(vq, &last)) != NULL)
1104 free(buf, M_DEVBUF);
1105}
1106
1107static void
984vtcon_port_teardown(struct vtcon_port *port, int ontailq)
1108vtcon_port_drain(struct vtcon_port *port)
985{
1109{
986 struct vtcon_softc *sc;
987 struct vtcon_port_extra *portx;
1110
1111 vtcon_port_drain_bufs(port->vtcport_invq);
1112}
1113
1114static void
1115vtcon_port_teardown(struct vtcon_port *port)
1116{
988 struct tty *tp;
1117 struct tty *tp;
989 int id;
990
1118
991 sc = port->vtcport_sc;
992 id = port->vtcport_id;
993 tp = port->vtcport_tty;
994
1119 tp = port->vtcport_tty;
1120
995 VTCON_ASSERT_VALID_PORTID(sc, id);
996 portx = &sc->vtcon_portsx[id];
1121 port->vtcport_flags |= VTCON_PORT_FLAG_GONE;
997
1122
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) {
1123 if (tp != NULL) {
1011 port->vtcport_tty = NULL;
1012 atomic_add_int(&vtcon_pending_free, 1);
1124 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
1020static void
1021vtcon_port_change_size(struct vtcon_port *port, uint16_t cols, uint16_t rows)
1022{

--- 4 unchanged lines hidden (view full) ---

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
1125 tty_rel_gone(tp);
1126 } else
1127 vtcon_port_destroy(port);
1128}
1129
1130static void
1131vtcon_port_change_size(struct vtcon_port *port, uint16_t cols, uint16_t rows)
1132{

--- 4 unchanged lines hidden (view full) ---

1137
1138 if (tp == NULL)
1139 return;
1140
1141 bzero(&sz, sizeof(struct winsize));
1142 sz.ws_col = cols;
1143 sz.ws_row = rows;
1144
1035 VTCON_PORT_LOCK(port);
1036 tty_set_winsize(tp, &sz);
1145 tty_set_winsize(tp, &sz);
1037 VTCON_PORT_UNLOCK(port);
1038}
1039
1040static void
1146}
1147
1148static void
1041vtcon_port_enable_intr(struct vtcon_port *port)
1149vtcon_port_update_console_size(struct vtcon_softc *sc)
1042{
1150{
1151 struct vtcon_port *port;
1152 struct vtcon_softc_port *scport;
1153 uint16_t cols, rows;
1043
1154
1155 vtcon_get_console_size(sc, &cols, &rows);
1156
1044 /*
1157 /*
1045 * NOTE: The out virtqueue is always polled, so we keep its
1046 * interupt disabled.
1158 * For now, assume the first (only) port is the console. Note
1159 * QEMU does not implement this feature yet.
1047 */
1160 */
1161 scport = &sc->vtcon_ports[0];
1048
1162
1163 VTCON_LOCK(sc);
1164 port = scport->vcsp_port;
1165
1166 if (port != NULL) {
1167 VTCON_PORT_LOCK(port);
1168 VTCON_UNLOCK(sc);
1169 vtcon_port_change_size(port, cols, rows);
1170 VTCON_PORT_UNLOCK(port);
1171 } else
1172 VTCON_UNLOCK(sc);
1173}
1174
1175static void
1176vtcon_port_enable_intr(struct vtcon_port *port)
1177{
1178
1179 /*
1180 * NOTE: The out virtqueue is always polled, so its interupt
1181 * kept disabled.
1182 */
1049 virtqueue_enable_intr(port->vtcport_invq);
1050}
1051
1052static void
1053vtcon_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
1062static void
1183 virtqueue_enable_intr(port->vtcport_invq);
1184}
1185
1186static void
1187vtcon_port_disable_intr(struct vtcon_port *port)
1188{
1189
1190 if (port->vtcport_invq != NULL)
1191 virtqueue_disable_intr(port->vtcport_invq);
1192 if (port->vtcport_outvq != NULL)
1193 virtqueue_disable_intr(port->vtcport_outvq);
1194}
1195
1196static void
1063vtcon_port_intr(struct vtcon_port *port)
1197vtcon_port_in(struct vtcon_port *port)
1064{
1198{
1065 struct tty *tp;
1066 struct virtqueue *vq;
1199 struct virtqueue *vq;
1200 struct tty *tp;
1067 char *buf;
1068 uint32_t len;
1069 int i, deq;
1070
1071 tp = port->vtcport_tty;
1072 vq = port->vtcport_invq;
1073
1074again:
1075 deq = 0;
1076
1201 char *buf;
1202 uint32_t len;
1203 int i, deq;
1204
1205 tp = port->vtcport_tty;
1206 vq = port->vtcport_invq;
1207
1208again:
1209 deq = 0;
1210
1077 VTCON_PORT_LOCK(port);
1078 while ((buf = virtqueue_dequeue(vq, &len)) != NULL) {
1211 while ((buf = virtqueue_dequeue(vq, &len)) != NULL) {
1079 deq++;
1080 for (i = 0; i < len; i++)
1212 for (i = 0; i < len; i++) {
1213#if defined(KDB)
1214 if (port->vtcport_flags & VTCON_PORT_FLAG_CONSOLE)
1215 kdb_alt_break(buf[i],
1216 &port->vtcport_alt_break_state);
1217#endif
1081 ttydisc_rint(tp, buf[i], 0);
1218 ttydisc_rint(tp, buf[i], 0);
1082 vtcon_port_readd_inbuf(port, buf);
1219 }
1220 vtcon_port_requeue_buf(port, buf);
1221 deq++;
1083 }
1084 ttydisc_rint_done(tp);
1222 }
1223 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
1094static void
1224
1225 if (deq > 0)
1226 virtqueue_notify(vq);
1227
1228 if (virtqueue_enable_intr(vq) != 0)
1229 goto again;
1230}
1231
1232static void
1095vtcon_port_in_vq_intr(void *xportx)
1233vtcon_port_intr(void *scportx)
1096{
1234{
1097 struct vtcon_port_extra *portx;
1235 struct vtcon_softc_port *scport;
1236 struct vtcon_softc *sc;
1098 struct vtcon_port *port;
1099
1237 struct vtcon_port *port;
1238
1100 portx = xportx;
1101 port = portx->port;
1239 scport = scportx;
1240 sc = scport->vcsp_sc;
1102
1241
1103 if (port != NULL)
1104 vtcon_port_intr(port);
1242 VTCON_LOCK(sc);
1243 port = scport->vcsp_port;
1244 if (port == NULL) {
1245 VTCON_UNLOCK(sc);
1246 return;
1247 }
1248 VTCON_PORT_LOCK(port);
1249 VTCON_UNLOCK(sc);
1250 if ((port->vtcport_flags & VTCON_PORT_FLAG_GONE) == 0)
1251 vtcon_port_in(port);
1252 VTCON_PORT_UNLOCK(port);
1105}
1106
1107static void
1253}
1254
1255static void
1108vtcon_port_put(struct vtcon_port *port, void *buf, int bufsize)
1256vtcon_port_out(struct vtcon_port *port, void *buf, int bufsize)
1109{
1257{
1110 struct sglist_seg segs[1];
1258 struct sglist_seg segs[2];
1111 struct sglist sg;
1112 struct virtqueue *vq;
1113 int error;
1114
1115 vq = port->vtcport_outvq;
1259 struct sglist sg;
1260 struct virtqueue *vq;
1261 int error;
1262
1263 vq = port->vtcport_outvq;
1264 KASSERT(virtqueue_empty(vq),
1265 ("%s: port %p out virtqueue not emtpy", __func__, port));
1116
1266
1117 sglist_init(&sg, 1, segs);
1267 sglist_init(&sg, 2, segs);
1118 error = sglist_append(&sg, buf, bufsize);
1268 error = sglist_append(&sg, buf, bufsize);
1119 KASSERT(error == 0 && sg.sg_nseg == 1,
1120 ("%s: error %d adding buffer to sglist", __func__, error));
1269 KASSERT(error == 0, ("%s: error %d adding buffer to sglist",
1270 __func__, error));
1121
1271
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) {
1272 error = virtqueue_enqueue(vq, buf, &sg, sg.sg_nseg, 0);
1273 if (error == 0) {
1126 virtqueue_notify(vq);
1127 virtqueue_poll(vq, NULL);
1128 }
1129}
1130
1131static void
1274 virtqueue_notify(vq);
1275 virtqueue_poll(vq, NULL);
1276 }
1277}
1278
1279static void
1132vtcon_port_send_ctrl_msg(struct vtcon_port *port, uint16_t event,
1280vtcon_port_submit_event(struct vtcon_port *port, uint16_t event,
1133 uint16_t value)
1134{
1135 struct vtcon_softc *sc;
1136
1137 sc = port->vtcport_sc;
1138
1281 uint16_t value)
1282{
1283 struct vtcon_softc *sc;
1284
1285 sc = port->vtcport_sc;
1286
1139 if (sc->vtcon_flags & VTCON_FLAG_MULTIPORT)
1140 vtcon_ctrl_send_event(sc, port->vtcport_id, event, value);
1287 vtcon_ctrl_send_control(sc, port->vtcport_id, event, value);
1141}
1142
1288}
1289
1143static struct vtcon_port *
1144vtcon_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
1156static int
1157vtcon_tty_open(struct tty *tp)
1158{
1159 struct vtcon_port *port;
1160
1161 port = tty_softc(tp);
1162
1290static int
1291vtcon_tty_open(struct tty *tp)
1292{
1293 struct vtcon_port *port;
1294
1295 port = tty_softc(tp);
1296
1163 vtcon_port_send_ctrl_msg(port, VIRTIO_CONSOLE_PORT_OPEN, 1);
1297 if (port->vtcport_flags & VTCON_PORT_FLAG_GONE)
1298 return (ENXIO);
1164
1299
1300 vtcon_port_submit_event(port, VIRTIO_CONSOLE_PORT_OPEN, 1);
1301
1165 return (0);
1166}
1167
1168static void
1169vtcon_tty_close(struct tty *tp)
1170{
1171 struct vtcon_port *port;
1172
1173 port = tty_softc(tp);
1174
1302 return (0);
1303}
1304
1305static void
1306vtcon_tty_close(struct tty *tp)
1307{
1308 struct vtcon_port *port;
1309
1310 port = tty_softc(tp);
1311
1175 vtcon_port_send_ctrl_msg(port, VIRTIO_CONSOLE_PORT_OPEN, 0);
1312 if (port->vtcport_flags & VTCON_PORT_FLAG_GONE)
1313 return;
1314
1315 vtcon_port_submit_event(port, VIRTIO_CONSOLE_PORT_OPEN, 0);
1176}
1177
1178static void
1179vtcon_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
1316}
1317
1318static void
1319vtcon_tty_outwakeup(struct tty *tp)
1320{
1321 struct vtcon_port *port;
1322 char buf[VTCON_BULK_BUFSZ];
1323 int len;
1324
1325 port = tty_softc(tp);
1326
1327 if (port->vtcport_flags & VTCON_PORT_FLAG_GONE)
1328 return;
1329
1187 while ((len = ttydisc_getc(tp, buf, sizeof(buf))) != 0)
1330 while ((len = ttydisc_getc(tp, buf, sizeof(buf))) != 0)
1188 vtcon_port_put(port, buf, len);
1331 vtcon_port_out(port, buf, len);
1189}
1190
1191static void
1192vtcon_tty_free(void *xport)
1193{
1194 struct vtcon_port *port;
1195
1196 port = xport;

--- 14 unchanged lines hidden (view full) ---

1211
1212 *cols = concfg.cols;
1213 *rows = concfg.rows;
1214}
1215
1216static void
1217vtcon_enable_interrupts(struct vtcon_softc *sc)
1218{
1332}
1333
1334static void
1335vtcon_tty_free(void *xport)
1336{
1337 struct vtcon_port *port;
1338
1339 port = xport;

--- 14 unchanged lines hidden (view full) ---

1354
1355 *cols = concfg.cols;
1356 *rows = concfg.rows;
1357}
1358
1359static void
1360vtcon_enable_interrupts(struct vtcon_softc *sc)
1361{
1362 struct vtcon_softc_port *scport;
1219 struct vtcon_port *port;
1363 struct vtcon_port *port;
1364 int i;
1220
1365
1366 VTCON_LOCK(sc);
1367
1221 if (sc->vtcon_flags & VTCON_FLAG_MULTIPORT)
1222 virtqueue_enable_intr(sc->vtcon_ctrl_rxvq);
1223
1368 if (sc->vtcon_flags & VTCON_FLAG_MULTIPORT)
1369 virtqueue_enable_intr(sc->vtcon_ctrl_rxvq);
1370
1224 TAILQ_FOREACH(port, &sc->vtcon_ports, vtcport_next)
1371 for (i = 0; i < sc->vtcon_max_ports; i++) {
1372 scport = &sc->vtcon_ports[i];
1373
1374 port = scport->vcsp_port;
1375 if (port == NULL)
1376 continue;
1377
1378 VTCON_PORT_LOCK(port);
1225 vtcon_port_enable_intr(port);
1379 vtcon_port_enable_intr(port);
1380 VTCON_PORT_UNLOCK(port);
1381 }
1382
1383 VTCON_UNLOCK(sc);
1226}
1227
1228static void
1229vtcon_disable_interrupts(struct vtcon_softc *sc)
1230{
1384}
1385
1386static void
1387vtcon_disable_interrupts(struct vtcon_softc *sc)
1388{
1389 struct vtcon_softc_port *scport;
1231 struct vtcon_port *port;
1390 struct vtcon_port *port;
1391 int i;
1232
1392
1393 VTCON_LOCK_ASSERT(sc);
1394
1233 if (sc->vtcon_flags & VTCON_FLAG_MULTIPORT)
1234 virtqueue_disable_intr(sc->vtcon_ctrl_rxvq);
1235
1395 if (sc->vtcon_flags & VTCON_FLAG_MULTIPORT)
1396 virtqueue_disable_intr(sc->vtcon_ctrl_rxvq);
1397
1236 TAILQ_FOREACH(port, &sc->vtcon_ports, vtcport_next)
1398 for (i = 0; i < sc->vtcon_max_ports; i++) {
1399 scport = &sc->vtcon_ports[i];
1400
1401 port = scport->vcsp_port;
1402 if (port == NULL)
1403 continue;
1404
1405 VTCON_PORT_LOCK(port);
1237 vtcon_port_disable_intr(port);
1406 vtcon_port_disable_intr(port);
1407 VTCON_PORT_UNLOCK(port);
1408 }
1238}
1409}