Statistics
| Branch: | Revision:

root / hw / virtio-serial-bus.c @ 471344db

History | View | Annotate | Download (21.8 kB)

1
/*
2
 * A bus for connecting virtio serial and console ports
3
 *
4
 * Copyright (C) 2009, 2010 Red Hat, Inc.
5
 *
6
 * Author(s):
7
 *  Amit Shah <amit.shah@redhat.com>
8
 *
9
 * Some earlier parts are:
10
 *  Copyright IBM, Corp. 2008
11
 * authored by
12
 *  Christian Ehrhardt <ehrhardt@linux.vnet.ibm.com>
13
 *
14
 * This work is licensed under the terms of the GNU GPL, version 2.  See
15
 * the COPYING file in the top-level directory.
16
 */
17

    
18
#include "iov.h"
19
#include "monitor.h"
20
#include "qemu-queue.h"
21
#include "sysbus.h"
22
#include "virtio-serial.h"
23

    
24
/* The virtio-serial bus on top of which the ports will ride as devices */
25
struct VirtIOSerialBus {
26
    BusState qbus;
27

    
28
    /* This is the parent device that provides the bus for ports. */
29
    VirtIOSerial *vser;
30

    
31
    /* The maximum number of ports that can ride on top of this bus */
32
    uint32_t max_nr_ports;
33
};
34

    
35
struct VirtIOSerial {
36
    VirtIODevice vdev;
37

    
38
    VirtQueue *c_ivq, *c_ovq;
39
    /* Arrays of ivqs and ovqs: one per port */
40
    VirtQueue **ivqs, **ovqs;
41

    
42
    VirtIOSerialBus *bus;
43

    
44
    DeviceState *qdev;
45

    
46
    QTAILQ_HEAD(, VirtIOSerialPort) ports;
47

    
48
    /* bitmap for identifying active ports */
49
    uint32_t *ports_map;
50

    
51
    struct virtio_console_config config;
52
};
53

    
54
static VirtIOSerialPort *find_port_by_id(VirtIOSerial *vser, uint32_t id)
55
{
56
    VirtIOSerialPort *port;
57

    
58
    if (id == VIRTIO_CONSOLE_BAD_ID) {
59
        return NULL;
60
    }
61

    
62
    QTAILQ_FOREACH(port, &vser->ports, next) {
63
        if (port->id == id)
64
            return port;
65
    }
66
    return NULL;
67
}
68

    
69
static VirtIOSerialPort *find_port_by_vq(VirtIOSerial *vser, VirtQueue *vq)
70
{
71
    VirtIOSerialPort *port;
72

    
73
    QTAILQ_FOREACH(port, &vser->ports, next) {
74
        if (port->ivq == vq || port->ovq == vq)
75
            return port;
76
    }
77
    return NULL;
78
}
79

    
80
static bool use_multiport(VirtIOSerial *vser)
81
{
82
    return vser->vdev.guest_features & (1 << VIRTIO_CONSOLE_F_MULTIPORT);
83
}
84

    
85
static size_t write_to_port(VirtIOSerialPort *port,
86
                            const uint8_t *buf, size_t size)
87
{
88
    VirtQueueElement elem;
89
    VirtQueue *vq;
90
    size_t offset;
91

    
92
    vq = port->ivq;
93
    if (!virtio_queue_ready(vq)) {
94
        return 0;
95
    }
96

    
97
    offset = 0;
98
    while (offset < size) {
99
        size_t len;
100

    
101
        if (!virtqueue_pop(vq, &elem)) {
102
            break;
103
        }
104

    
105
        len = iov_from_buf(elem.in_sg, elem.in_num,
106
                           buf + offset, size - offset);
107
        offset += len;
108

    
109
        virtqueue_push(vq, &elem, len);
110
    }
111

    
112
    virtio_notify(&port->vser->vdev, vq);
113
    return offset;
114
}
115

    
116
static void discard_vq_data(VirtQueue *vq, VirtIODevice *vdev)
117
{
118
    VirtQueueElement elem;
119

    
120
    while (virtqueue_pop(vq, &elem)) {
121
        virtqueue_push(vq, &elem, 0);
122
    }
123
    virtio_notify(vdev, vq);
124
}
125

    
126
static void do_flush_queued_data(VirtIOSerialPort *port, VirtQueue *vq,
127
                                 VirtIODevice *vdev)
128
{
129
    VirtQueueElement elem;
130

    
131
    assert(port);
132
    assert(virtio_queue_ready(vq));
133

    
134
    while (!port->throttled && virtqueue_pop(vq, &elem)) {
135
        unsigned int i;
136

    
137
        for (i = 0; i < elem.out_num; i++) {
138
            size_t buf_size;
139

    
140
            buf_size = elem.out_sg[i].iov_len;
141

    
142
            port->info->have_data(port,
143
                                  elem.out_sg[i].iov_base,
144
                                  buf_size);
145
        }
146
        virtqueue_push(vq, &elem, 0);
147
    }
148
    virtio_notify(vdev, vq);
149
}
150

    
151
static void flush_queued_data(VirtIOSerialPort *port)
152
{
153
    assert(port);
154

    
155
    if (!virtio_queue_ready(port->ovq)) {
156
        return;
157
    }
158
    do_flush_queued_data(port, port->ovq, &port->vser->vdev);
159
}
160

    
161
static size_t send_control_msg(VirtIOSerialPort *port, void *buf, size_t len)
162
{
163
    VirtQueueElement elem;
164
    VirtQueue *vq;
165
    struct virtio_console_control *cpkt;
166

    
167
    vq = port->vser->c_ivq;
168
    if (!virtio_queue_ready(vq)) {
169
        return 0;
170
    }
171
    if (!virtqueue_pop(vq, &elem)) {
172
        return 0;
173
    }
174

    
175
    cpkt = (struct virtio_console_control *)buf;
176
    stl_p(&cpkt->id, port->id);
177
    memcpy(elem.in_sg[0].iov_base, buf, len);
178

    
179
    virtqueue_push(vq, &elem, len);
180
    virtio_notify(&port->vser->vdev, vq);
181
    return len;
182
}
183

    
184
static size_t send_control_event(VirtIOSerialPort *port, uint16_t event,
185
                                 uint16_t value)
186
{
187
    struct virtio_console_control cpkt;
188

    
189
    stw_p(&cpkt.event, event);
190
    stw_p(&cpkt.value, value);
191

    
192
    return send_control_msg(port, &cpkt, sizeof(cpkt));
193
}
194

    
195
/* Functions for use inside qemu to open and read from/write to ports */
196
int virtio_serial_open(VirtIOSerialPort *port)
197
{
198
    /* Don't allow opening an already-open port */
199
    if (port->host_connected) {
200
        return 0;
201
    }
202
    /* Send port open notification to the guest */
203
    port->host_connected = true;
204
    send_control_event(port, VIRTIO_CONSOLE_PORT_OPEN, 1);
205

    
206
    return 0;
207
}
208

    
209
int virtio_serial_close(VirtIOSerialPort *port)
210
{
211
    port->host_connected = false;
212
    /*
213
     * If there's any data the guest sent which the app didn't
214
     * consume, reset the throttling flag and discard the data.
215
     */
216
    port->throttled = false;
217
    discard_vq_data(port->ovq, &port->vser->vdev);
218

    
219
    send_control_event(port, VIRTIO_CONSOLE_PORT_OPEN, 0);
220

    
221
    return 0;
222
}
223

    
224
/* Individual ports/apps call this function to write to the guest. */
225
ssize_t virtio_serial_write(VirtIOSerialPort *port, const uint8_t *buf,
226
                            size_t size)
227
{
228
    if (!port || !port->host_connected || !port->guest_connected) {
229
        return 0;
230
    }
231
    return write_to_port(port, buf, size);
232
}
233

    
234
/*
235
 * Readiness of the guest to accept data on a port.
236
 * Returns max. data the guest can receive
237
 */
238
size_t virtio_serial_guest_ready(VirtIOSerialPort *port)
239
{
240
    VirtQueue *vq = port->ivq;
241

    
242
    if (!virtio_queue_ready(vq) ||
243
        !(port->vser->vdev.status & VIRTIO_CONFIG_S_DRIVER_OK) ||
244
        virtio_queue_empty(vq)) {
245
        return 0;
246
    }
247
    if (use_multiport(port->vser) && !port->guest_connected) {
248
        return 0;
249
    }
250

    
251
    if (virtqueue_avail_bytes(vq, 4096, 0)) {
252
        return 4096;
253
    }
254
    if (virtqueue_avail_bytes(vq, 1, 0)) {
255
        return 1;
256
    }
257
    return 0;
258
}
259

    
260
void virtio_serial_throttle_port(VirtIOSerialPort *port, bool throttle)
261
{
262
    if (!port) {
263
        return;
264
    }
265

    
266
    port->throttled = throttle;
267
    if (throttle) {
268
        return;
269
    }
270

    
271
    flush_queued_data(port);
272
}
273

    
274
/* Guest wants to notify us of some event */
275
static void handle_control_message(VirtIOSerial *vser, void *buf, size_t len)
276
{
277
    struct VirtIOSerialPort *port;
278
    struct virtio_console_control cpkt, *gcpkt;
279
    uint8_t *buffer;
280
    size_t buffer_len;
281

    
282
    gcpkt = buf;
283

    
284
    if (len < sizeof(cpkt)) {
285
        /* The guest sent an invalid control packet */
286
        return;
287
    }
288

    
289
    cpkt.event = lduw_p(&gcpkt->event);
290
    cpkt.value = lduw_p(&gcpkt->value);
291

    
292
    port = find_port_by_id(vser, ldl_p(&gcpkt->id));
293
    if (!port && cpkt.event != VIRTIO_CONSOLE_DEVICE_READY)
294
        return;
295

    
296
    switch(cpkt.event) {
297
    case VIRTIO_CONSOLE_DEVICE_READY:
298
        if (!cpkt.value) {
299
            error_report("virtio-serial-bus: Guest failure in adding device %s\n",
300
                         vser->bus->qbus.name);
301
            break;
302
        }
303
        /*
304
         * The device is up, we can now tell the device about all the
305
         * ports we have here.
306
         */
307
        QTAILQ_FOREACH(port, &vser->ports, next) {
308
            send_control_event(port, VIRTIO_CONSOLE_PORT_ADD, 1);
309
        }
310
        break;
311

    
312
    case VIRTIO_CONSOLE_PORT_READY:
313
        if (!cpkt.value) {
314
            error_report("virtio-serial-bus: Guest failure in adding port %u for device %s\n",
315
                         port->id, vser->bus->qbus.name);
316
            break;
317
        }
318
        /*
319
         * Now that we know the guest asked for the port name, we're
320
         * sure the guest has initialised whatever state is necessary
321
         * for this port. Now's a good time to let the guest know if
322
         * this port is a console port so that the guest can hook it
323
         * up to hvc.
324
         */
325
        if (port->is_console) {
326
            send_control_event(port, VIRTIO_CONSOLE_CONSOLE_PORT, 1);
327
        }
328

    
329
        if (port->name) {
330
            stw_p(&cpkt.event, VIRTIO_CONSOLE_PORT_NAME);
331
            stw_p(&cpkt.value, 1);
332

    
333
            buffer_len = sizeof(cpkt) + strlen(port->name) + 1;
334
            buffer = qemu_malloc(buffer_len);
335

    
336
            memcpy(buffer, &cpkt, sizeof(cpkt));
337
            memcpy(buffer + sizeof(cpkt), port->name, strlen(port->name));
338
            buffer[buffer_len - 1] = 0;
339

    
340
            send_control_msg(port, buffer, buffer_len);
341
            qemu_free(buffer);
342
        }
343

    
344
        if (port->host_connected) {
345
            send_control_event(port, VIRTIO_CONSOLE_PORT_OPEN, 1);
346
        }
347

    
348
        /*
349
         * When the guest has asked us for this information it means
350
         * the guest is all setup and has its virtqueues
351
         * initialised. If some app is interested in knowing about
352
         * this event, let it know.
353
         */
354
        if (port->info->guest_ready) {
355
            port->info->guest_ready(port);
356
        }
357
        break;
358

    
359
    case VIRTIO_CONSOLE_PORT_OPEN:
360
        port->guest_connected = cpkt.value;
361
        if (cpkt.value && port->info->guest_open) {
362
            /* Send the guest opened notification if an app is interested */
363
            port->info->guest_open(port);
364
        }
365

    
366
        if (!cpkt.value && port->info->guest_close) {
367
            /* Send the guest closed notification if an app is interested */
368
            port->info->guest_close(port);
369
        }
370
        break;
371
    }
372
}
373

    
374
static void control_in(VirtIODevice *vdev, VirtQueue *vq)
375
{
376
}
377

    
378
static void control_out(VirtIODevice *vdev, VirtQueue *vq)
379
{
380
    VirtQueueElement elem;
381
    VirtIOSerial *vser;
382
    uint8_t *buf;
383
    size_t len;
384

    
385
    vser = DO_UPCAST(VirtIOSerial, vdev, vdev);
386

    
387
    len = 0;
388
    buf = NULL;
389
    while (virtqueue_pop(vq, &elem)) {
390
        size_t cur_len, copied;
391

    
392
        cur_len = iov_size(elem.out_sg, elem.out_num);
393
        /*
394
         * Allocate a new buf only if we didn't have one previously or
395
         * if the size of the buf differs
396
         */
397
        if (cur_len > len) {
398
            qemu_free(buf);
399

    
400
            buf = qemu_malloc(cur_len);
401
            len = cur_len;
402
        }
403
        copied = iov_to_buf(elem.out_sg, elem.out_num, buf, 0, len);
404

    
405
        handle_control_message(vser, buf, copied);
406
        virtqueue_push(vq, &elem, 0);
407
    }
408
    qemu_free(buf);
409
    virtio_notify(vdev, vq);
410
}
411

    
412
/* Guest wrote something to some port. */
413
static void handle_output(VirtIODevice *vdev, VirtQueue *vq)
414
{
415
    VirtIOSerial *vser;
416
    VirtIOSerialPort *port;
417
    bool discard;
418

    
419
    vser = DO_UPCAST(VirtIOSerial, vdev, vdev);
420
    port = find_port_by_vq(vser, vq);
421

    
422
    discard = false;
423
    if (!port || !port->host_connected || !port->info->have_data) {
424
        discard = true;
425
    }
426

    
427
    if (discard) {
428
        discard_vq_data(vq, vdev);
429
        return;
430
    }
431
    if (port->throttled) {
432
        return;
433
    }
434

    
435
    do_flush_queued_data(port, vq, vdev);
436
}
437

    
438
static void handle_input(VirtIODevice *vdev, VirtQueue *vq)
439
{
440
}
441

    
442
static uint32_t get_features(VirtIODevice *vdev, uint32_t features)
443
{
444
    VirtIOSerial *vser;
445

    
446
    vser = DO_UPCAST(VirtIOSerial, vdev, vdev);
447

    
448
    if (vser->bus->max_nr_ports > 1) {
449
        features |= (1 << VIRTIO_CONSOLE_F_MULTIPORT);
450
    }
451
    return features;
452
}
453

    
454
/* Guest requested config info */
455
static void get_config(VirtIODevice *vdev, uint8_t *config_data)
456
{
457
    VirtIOSerial *vser;
458

    
459
    vser = DO_UPCAST(VirtIOSerial, vdev, vdev);
460
    memcpy(config_data, &vser->config, sizeof(struct virtio_console_config));
461
}
462

    
463
static void set_config(VirtIODevice *vdev, const uint8_t *config_data)
464
{
465
    struct virtio_console_config config;
466

    
467
    memcpy(&config, config_data, sizeof(config));
468
}
469

    
470
static void virtio_serial_save(QEMUFile *f, void *opaque)
471
{
472
    VirtIOSerial *s = opaque;
473
    VirtIOSerialPort *port;
474
    uint32_t nr_active_ports;
475
    unsigned int i;
476

    
477
    /* The virtio device */
478
    virtio_save(&s->vdev, f);
479

    
480
    /* The config space */
481
    qemu_put_be16s(f, &s->config.cols);
482
    qemu_put_be16s(f, &s->config.rows);
483

    
484
    qemu_put_be32s(f, &s->config.max_nr_ports);
485

    
486
    /* The ports map */
487

    
488
    for (i = 0; i < (s->config.max_nr_ports + 31) / 32; i++) {
489
        qemu_put_be32s(f, &s->ports_map[i]);
490
    }
491

    
492
    /* Ports */
493

    
494
    nr_active_ports = 0;
495
    QTAILQ_FOREACH(port, &s->ports, next) {
496
        nr_active_ports++;
497
    }
498

    
499
    qemu_put_be32s(f, &nr_active_ports);
500

    
501
    /*
502
     * Items in struct VirtIOSerialPort.
503
     */
504
    QTAILQ_FOREACH(port, &s->ports, next) {
505
        qemu_put_be32s(f, &port->id);
506
        qemu_put_byte(f, port->guest_connected);
507
        qemu_put_byte(f, port->host_connected);
508
    }
509
}
510

    
511
static int virtio_serial_load(QEMUFile *f, void *opaque, int version_id)
512
{
513
    VirtIOSerial *s = opaque;
514
    VirtIOSerialPort *port;
515
    uint32_t max_nr_ports, nr_active_ports, ports_map;
516
    unsigned int i;
517

    
518
    if (version_id > 2) {
519
        return -EINVAL;
520
    }
521

    
522
    /* The virtio device */
523
    virtio_load(&s->vdev, f);
524

    
525
    if (version_id < 2) {
526
        return 0;
527
    }
528

    
529
    /* The config space */
530
    qemu_get_be16s(f, &s->config.cols);
531
    qemu_get_be16s(f, &s->config.rows);
532

    
533
    qemu_get_be32s(f, &max_nr_ports);
534
    if (max_nr_ports > s->config.max_nr_ports) {
535
        /* Source could have had more ports than us. Fail migration. */
536
        return -EINVAL;
537
    }
538

    
539
    for (i = 0; i < (max_nr_ports + 31) / 32; i++) {
540
        qemu_get_be32s(f, &ports_map);
541

    
542
        if (ports_map != s->ports_map[i]) {
543
            /*
544
             * Ports active on source and destination don't
545
             * match. Fail migration.
546
             */
547
            return -EINVAL;
548
        }
549
    }
550

    
551
    qemu_get_be32s(f, &nr_active_ports);
552

    
553
    /* Items in struct VirtIOSerialPort */
554
    for (i = 0; i < nr_active_ports; i++) {
555
        uint32_t id;
556
        bool host_connected;
557

    
558
        id = qemu_get_be32(f);
559
        port = find_port_by_id(s, id);
560

    
561
        port->guest_connected = qemu_get_byte(f);
562
        host_connected = qemu_get_byte(f);
563
        if (host_connected != port->host_connected) {
564
            /*
565
             * We have to let the guest know of the host connection
566
             * status change
567
             */
568
            send_control_event(port, VIRTIO_CONSOLE_PORT_OPEN,
569
                               port->host_connected);
570
        }
571
    }
572
    return 0;
573
}
574

    
575
static void virtser_bus_dev_print(Monitor *mon, DeviceState *qdev, int indent);
576

    
577
static struct BusInfo virtser_bus_info = {
578
    .name      = "virtio-serial-bus",
579
    .size      = sizeof(VirtIOSerialBus),
580
    .print_dev = virtser_bus_dev_print,
581
};
582

    
583
static VirtIOSerialBus *virtser_bus_new(DeviceState *dev)
584
{
585
    VirtIOSerialBus *bus;
586

    
587
    bus = FROM_QBUS(VirtIOSerialBus, qbus_create(&virtser_bus_info, dev, NULL));
588
    bus->qbus.allow_hotplug = 1;
589

    
590
    return bus;
591
}
592

    
593
static void virtser_bus_dev_print(Monitor *mon, DeviceState *qdev, int indent)
594
{
595
    VirtIOSerialDevice *dev = DO_UPCAST(VirtIOSerialDevice, qdev, qdev);
596
    VirtIOSerialPort *port = DO_UPCAST(VirtIOSerialPort, dev, &dev->qdev);
597

    
598
    monitor_printf(mon, "%*s dev-prop-int: id: %u\n",
599
                   indent, "", port->id);
600
    monitor_printf(mon, "%*s dev-prop-int: guest_connected: %d\n",
601
                   indent, "", port->guest_connected);
602
    monitor_printf(mon, "%*s dev-prop-int: host_connected: %d\n",
603
                   indent, "", port->host_connected);
604
    monitor_printf(mon, "%*s dev-prop-int: throttled: %d\n",
605
                   indent, "", port->throttled);
606
}
607

    
608
/* This function is only used if a port id is not provided by the user */
609
static uint32_t find_free_port_id(VirtIOSerial *vser)
610
{
611
    unsigned int i;
612

    
613
    for (i = 0; i < (vser->config.max_nr_ports + 31) / 32; i++) {
614
        uint32_t map, bit;
615

    
616
        map = vser->ports_map[i];
617
        bit = ffs(~map);
618
        if (bit) {
619
            return (bit - 1) + i * 32;
620
        }
621
    }
622
    return VIRTIO_CONSOLE_BAD_ID;
623
}
624

    
625
static void mark_port_added(VirtIOSerial *vser, uint32_t port_id)
626
{
627
    unsigned int i;
628

    
629
    i = port_id / 32;
630
    vser->ports_map[i] |= 1U << (port_id % 32);
631
}
632

    
633
static void add_port(VirtIOSerial *vser, uint32_t port_id)
634
{
635
    mark_port_added(vser, port_id);
636

    
637
    send_control_event(find_port_by_id(vser, port_id),
638
                       VIRTIO_CONSOLE_PORT_ADD, 1);
639
}
640

    
641
static void remove_port(VirtIOSerial *vser, uint32_t port_id)
642
{
643
    VirtIOSerialPort *port;
644
    unsigned int i;
645

    
646
    i = port_id / 32;
647
    vser->ports_map[i] &= ~(1U << (port_id % 32));
648

    
649
    port = find_port_by_id(vser, port_id);
650
    /* Flush out any unconsumed buffers first */
651
    discard_vq_data(port->ovq, &port->vser->vdev);
652

    
653
    send_control_event(port, VIRTIO_CONSOLE_PORT_REMOVE, 1);
654
}
655

    
656
static int virtser_port_qdev_init(DeviceState *qdev, DeviceInfo *base)
657
{
658
    VirtIOSerialDevice *dev = DO_UPCAST(VirtIOSerialDevice, qdev, qdev);
659
    VirtIOSerialPortInfo *info = DO_UPCAST(VirtIOSerialPortInfo, qdev, base);
660
    VirtIOSerialPort *port = DO_UPCAST(VirtIOSerialPort, dev, &dev->qdev);
661
    VirtIOSerialBus *bus = DO_UPCAST(VirtIOSerialBus, qbus, qdev->parent_bus);
662
    int ret;
663
    bool plugging_port0;
664

    
665
    port->vser = bus->vser;
666

    
667
    /*
668
     * Is the first console port we're seeing? If so, put it up at
669
     * location 0. This is done for backward compatibility (old
670
     * kernel, new qemu).
671
     */
672
    plugging_port0 = port->is_console && !find_port_by_id(port->vser, 0);
673

    
674
    if (find_port_by_id(port->vser, port->id)) {
675
        error_report("virtio-serial-bus: A port already exists at id %u\n",
676
                     port->id);
677
        return -1;
678
    }
679

    
680
    if (port->id == VIRTIO_CONSOLE_BAD_ID) {
681
        if (plugging_port0) {
682
            port->id = 0;
683
        } else {
684
            port->id = find_free_port_id(port->vser);
685
            if (port->id == VIRTIO_CONSOLE_BAD_ID) {
686
                error_report("virtio-serial-bus: Maximum port limit for this device reached\n");
687
                return -1;
688
            }
689
        }
690
    }
691

    
692
    if (port->id >= port->vser->config.max_nr_ports) {
693
        error_report("virtio-serial-bus: Out-of-range port id specified, max. allowed: %u\n",
694
                     port->vser->config.max_nr_ports - 1);
695
        return -1;
696
    }
697

    
698
    dev->info = info;
699
    ret = info->init(dev);
700
    if (ret) {
701
        return ret;
702
    }
703

    
704
    if (!use_multiport(port->vser)) {
705
        /*
706
         * Allow writes to guest in this case; we have no way of
707
         * knowing if a guest port is connected.
708
         */
709
        port->guest_connected = true;
710
    }
711

    
712
    QTAILQ_INSERT_TAIL(&port->vser->ports, port, next);
713
    port->ivq = port->vser->ivqs[port->id];
714
    port->ovq = port->vser->ovqs[port->id];
715

    
716
    add_port(port->vser, port->id);
717

    
718
    /* Send an update to the guest about this new port added */
719
    virtio_notify_config(&port->vser->vdev);
720

    
721
    return ret;
722
}
723

    
724
static int virtser_port_qdev_exit(DeviceState *qdev)
725
{
726
    VirtIOSerialDevice *dev = DO_UPCAST(VirtIOSerialDevice, qdev, qdev);
727
    VirtIOSerialPort *port = DO_UPCAST(VirtIOSerialPort, dev, &dev->qdev);
728
    VirtIOSerial *vser = port->vser;
729

    
730
    remove_port(port->vser, port->id);
731

    
732
    QTAILQ_REMOVE(&vser->ports, port, next);
733

    
734
    if (port->info->exit)
735
        port->info->exit(dev);
736

    
737
    return 0;
738
}
739

    
740
void virtio_serial_port_qdev_register(VirtIOSerialPortInfo *info)
741
{
742
    info->qdev.init = virtser_port_qdev_init;
743
    info->qdev.bus_info = &virtser_bus_info;
744
    info->qdev.exit = virtser_port_qdev_exit;
745
    info->qdev.unplug = qdev_simple_unplug_cb;
746
    qdev_register(&info->qdev);
747
}
748

    
749
VirtIODevice *virtio_serial_init(DeviceState *dev, uint32_t max_nr_ports)
750
{
751
    VirtIOSerial *vser;
752
    VirtIODevice *vdev;
753
    uint32_t i, max_supported_ports;
754

    
755
    if (!max_nr_ports)
756
        return NULL;
757

    
758
    /* Each port takes 2 queues, and one pair is for the control queue */
759
    max_supported_ports = VIRTIO_PCI_QUEUE_MAX / 2 - 1;
760

    
761
    if (max_nr_ports > max_supported_ports) {
762
        error_report("maximum ports supported: %u", max_supported_ports);
763
        return NULL;
764
    }
765

    
766
    vdev = virtio_common_init("virtio-serial", VIRTIO_ID_CONSOLE,
767
                              sizeof(struct virtio_console_config),
768
                              sizeof(VirtIOSerial));
769

    
770
    vser = DO_UPCAST(VirtIOSerial, vdev, vdev);
771

    
772
    /* Spawn a new virtio-serial bus on which the ports will ride as devices */
773
    vser->bus = virtser_bus_new(dev);
774
    vser->bus->vser = vser;
775
    QTAILQ_INIT(&vser->ports);
776

    
777
    vser->bus->max_nr_ports = max_nr_ports;
778
    vser->ivqs = qemu_malloc(max_nr_ports * sizeof(VirtQueue *));
779
    vser->ovqs = qemu_malloc(max_nr_ports * sizeof(VirtQueue *));
780

    
781
    /* Add a queue for host to guest transfers for port 0 (backward compat) */
782
    vser->ivqs[0] = virtio_add_queue(vdev, 128, handle_input);
783
    /* Add a queue for guest to host transfers for port 0 (backward compat) */
784
    vser->ovqs[0] = virtio_add_queue(vdev, 128, handle_output);
785

    
786
    /* control queue: host to guest */
787
    vser->c_ivq = virtio_add_queue(vdev, 16, control_in);
788
    /* control queue: guest to host */
789
    vser->c_ovq = virtio_add_queue(vdev, 16, control_out);
790

    
791
    for (i = 1; i < vser->bus->max_nr_ports; i++) {
792
        /* Add a per-port queue for host to guest transfers */
793
        vser->ivqs[i] = virtio_add_queue(vdev, 128, handle_input);
794
        /* Add a per-per queue for guest to host transfers */
795
        vser->ovqs[i] = virtio_add_queue(vdev, 128, handle_output);
796
    }
797

    
798
    vser->config.max_nr_ports = max_nr_ports;
799
    vser->ports_map = qemu_mallocz(((max_nr_ports + 31) / 32)
800
        * sizeof(vser->ports_map[0]));
801
    /*
802
     * Reserve location 0 for a console port for backward compat
803
     * (old kernel, new qemu)
804
     */
805
    mark_port_added(vser, 0);
806

    
807
    vser->vdev.get_features = get_features;
808
    vser->vdev.get_config = get_config;
809
    vser->vdev.set_config = set_config;
810

    
811
    vser->qdev = dev;
812

    
813
    /*
814
     * Register for the savevm section with the virtio-console name
815
     * to preserve backward compat
816
     */
817
    register_savevm(dev, "virtio-console", -1, 2, virtio_serial_save,
818
                    virtio_serial_load, vser);
819

    
820
    return vdev;
821
}
822

    
823
void virtio_serial_exit(VirtIODevice *vdev)
824
{
825
    VirtIOSerial *vser = DO_UPCAST(VirtIOSerial, vdev, vdev);
826

    
827
    unregister_savevm(vser->qdev, "virtio-console", vser);
828

    
829
    qemu_free(vser->ivqs);
830
    qemu_free(vser->ovqs);
831
    qemu_free(vser->ports_map);
832

    
833
    virtio_cleanup(vdev);
834
}