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