Statistics
| Branch: | Revision:

root / hw / virtio-serial-bus.c @ 0d877c66

History | View | Annotate | Download (25.2 kB)

1 98b19252 Amit Shah
/*
2 98b19252 Amit Shah
 * A bus for connecting virtio serial and console ports
3 98b19252 Amit Shah
 *
4 71c092e9 Amit Shah
 * Copyright (C) 2009, 2010 Red Hat, Inc.
5 98b19252 Amit Shah
 *
6 98b19252 Amit Shah
 * Author(s):
7 98b19252 Amit Shah
 *  Amit Shah <amit.shah@redhat.com>
8 98b19252 Amit Shah
 *
9 98b19252 Amit Shah
 * Some earlier parts are:
10 98b19252 Amit Shah
 *  Copyright IBM, Corp. 2008
11 98b19252 Amit Shah
 * authored by
12 98b19252 Amit Shah
 *  Christian Ehrhardt <ehrhardt@linux.vnet.ibm.com>
13 98b19252 Amit Shah
 *
14 98b19252 Amit Shah
 * This work is licensed under the terms of the GNU GPL, version 2.  See
15 98b19252 Amit Shah
 * the COPYING file in the top-level directory.
16 98b19252 Amit Shah
 */
17 98b19252 Amit Shah
18 e4d5639d Amit Shah
#include "iov.h"
19 98b19252 Amit Shah
#include "monitor.h"
20 98b19252 Amit Shah
#include "qemu-queue.h"
21 98b19252 Amit Shah
#include "sysbus.h"
22 49e3fdd7 Amit Shah
#include "trace.h"
23 98b19252 Amit Shah
#include "virtio-serial.h"
24 98b19252 Amit Shah
25 98b19252 Amit Shah
/* The virtio-serial bus on top of which the ports will ride as devices */
26 98b19252 Amit Shah
struct VirtIOSerialBus {
27 98b19252 Amit Shah
    BusState qbus;
28 98b19252 Amit Shah
29 98b19252 Amit Shah
    /* This is the parent device that provides the bus for ports. */
30 98b19252 Amit Shah
    VirtIOSerial *vser;
31 98b19252 Amit Shah
32 98b19252 Amit Shah
    /* The maximum number of ports that can ride on top of this bus */
33 98b19252 Amit Shah
    uint32_t max_nr_ports;
34 98b19252 Amit Shah
};
35 98b19252 Amit Shah
36 98b19252 Amit Shah
struct VirtIOSerial {
37 98b19252 Amit Shah
    VirtIODevice vdev;
38 98b19252 Amit Shah
39 98b19252 Amit Shah
    VirtQueue *c_ivq, *c_ovq;
40 98b19252 Amit Shah
    /* Arrays of ivqs and ovqs: one per port */
41 98b19252 Amit Shah
    VirtQueue **ivqs, **ovqs;
42 98b19252 Amit Shah
43 5e52e5f9 Markus Armbruster
    VirtIOSerialBus bus;
44 98b19252 Amit Shah
45 8b53a865 Amit Shah
    DeviceState *qdev;
46 8b53a865 Amit Shah
47 98b19252 Amit Shah
    QTAILQ_HEAD(, VirtIOSerialPort) ports;
48 055b889f Amit Shah
49 055b889f Amit Shah
    /* bitmap for identifying active ports */
50 055b889f Amit Shah
    uint32_t *ports_map;
51 055b889f Amit Shah
52 98b19252 Amit Shah
    struct virtio_console_config config;
53 98b19252 Amit Shah
};
54 98b19252 Amit Shah
55 98b19252 Amit Shah
static VirtIOSerialPort *find_port_by_id(VirtIOSerial *vser, uint32_t id)
56 98b19252 Amit Shah
{
57 98b19252 Amit Shah
    VirtIOSerialPort *port;
58 98b19252 Amit Shah
59 055b889f Amit Shah
    if (id == VIRTIO_CONSOLE_BAD_ID) {
60 055b889f Amit Shah
        return NULL;
61 055b889f Amit Shah
    }
62 055b889f Amit Shah
63 98b19252 Amit Shah
    QTAILQ_FOREACH(port, &vser->ports, next) {
64 98b19252 Amit Shah
        if (port->id == id)
65 98b19252 Amit Shah
            return port;
66 98b19252 Amit Shah
    }
67 98b19252 Amit Shah
    return NULL;
68 98b19252 Amit Shah
}
69 98b19252 Amit Shah
70 98b19252 Amit Shah
static VirtIOSerialPort *find_port_by_vq(VirtIOSerial *vser, VirtQueue *vq)
71 98b19252 Amit Shah
{
72 98b19252 Amit Shah
    VirtIOSerialPort *port;
73 98b19252 Amit Shah
74 98b19252 Amit Shah
    QTAILQ_FOREACH(port, &vser->ports, next) {
75 98b19252 Amit Shah
        if (port->ivq == vq || port->ovq == vq)
76 98b19252 Amit Shah
            return port;
77 98b19252 Amit Shah
    }
78 98b19252 Amit Shah
    return NULL;
79 98b19252 Amit Shah
}
80 98b19252 Amit Shah
81 6663a195 Amit Shah
static bool use_multiport(VirtIOSerial *vser)
82 6663a195 Amit Shah
{
83 6663a195 Amit Shah
    return vser->vdev.guest_features & (1 << VIRTIO_CONSOLE_F_MULTIPORT);
84 6663a195 Amit Shah
}
85 6663a195 Amit Shah
86 98b19252 Amit Shah
static size_t write_to_port(VirtIOSerialPort *port,
87 98b19252 Amit Shah
                            const uint8_t *buf, size_t size)
88 98b19252 Amit Shah
{
89 98b19252 Amit Shah
    VirtQueueElement elem;
90 98b19252 Amit Shah
    VirtQueue *vq;
91 e4d5639d Amit Shah
    size_t offset;
92 98b19252 Amit Shah
93 98b19252 Amit Shah
    vq = port->ivq;
94 98b19252 Amit Shah
    if (!virtio_queue_ready(vq)) {
95 98b19252 Amit Shah
        return 0;
96 98b19252 Amit Shah
    }
97 98b19252 Amit Shah
98 e4d5639d Amit Shah
    offset = 0;
99 98b19252 Amit Shah
    while (offset < size) {
100 e4d5639d Amit Shah
        size_t len;
101 98b19252 Amit Shah
102 98b19252 Amit Shah
        if (!virtqueue_pop(vq, &elem)) {
103 98b19252 Amit Shah
            break;
104 98b19252 Amit Shah
        }
105 98b19252 Amit Shah
106 e4d5639d Amit Shah
        len = iov_from_buf(elem.in_sg, elem.in_num,
107 348e7b8d Hannes Reinecke
                           buf + offset, 0, size - offset);
108 e4d5639d Amit Shah
        offset += len;
109 98b19252 Amit Shah
110 98b19252 Amit Shah
        virtqueue_push(vq, &elem, len);
111 98b19252 Amit Shah
    }
112 98b19252 Amit Shah
113 98b19252 Amit Shah
    virtio_notify(&port->vser->vdev, vq);
114 98b19252 Amit Shah
    return offset;
115 98b19252 Amit Shah
}
116 98b19252 Amit Shah
117 6bff8656 Amit Shah
static void discard_vq_data(VirtQueue *vq, VirtIODevice *vdev)
118 a69c7600 Amit Shah
{
119 a69c7600 Amit Shah
    VirtQueueElement elem;
120 a69c7600 Amit Shah
121 7185f931 Amit Shah
    if (!virtio_queue_ready(vq)) {
122 7185f931 Amit Shah
        return;
123 7185f931 Amit Shah
    }
124 6bff8656 Amit Shah
    while (virtqueue_pop(vq, &elem)) {
125 6bff8656 Amit Shah
        virtqueue_push(vq, &elem, 0);
126 6bff8656 Amit Shah
    }
127 6bff8656 Amit Shah
    virtio_notify(vdev, vq);
128 6bff8656 Amit Shah
}
129 6bff8656 Amit Shah
130 9ed7b059 Amit Shah
static void do_flush_queued_data(VirtIOSerialPort *port, VirtQueue *vq,
131 6bff8656 Amit Shah
                                 VirtIODevice *vdev)
132 a69c7600 Amit Shah
{
133 a15bb0d6 Markus Armbruster
    VirtIOSerialPortInfo *info;
134 a15bb0d6 Markus Armbruster
135 6bff8656 Amit Shah
    assert(port);
136 fd11a78b Amit Shah
    assert(virtio_queue_ready(vq));
137 a69c7600 Amit Shah
138 a15bb0d6 Markus Armbruster
    info = DO_UPCAST(VirtIOSerialPortInfo, qdev, port->dev.info);
139 a15bb0d6 Markus Armbruster
140 f1925dff Amit Shah
    while (!port->throttled) {
141 471344db Amit Shah
        unsigned int i;
142 a69c7600 Amit Shah
143 f1925dff Amit Shah
        /* Pop an elem only if we haven't left off a previous one mid-way */
144 f1925dff Amit Shah
        if (!port->elem.out_num) {
145 f1925dff Amit Shah
            if (!virtqueue_pop(vq, &port->elem)) {
146 f1925dff Amit Shah
                break;
147 f1925dff Amit Shah
            }
148 f1925dff Amit Shah
            port->iov_idx = 0;
149 f1925dff Amit Shah
            port->iov_offset = 0;
150 f1925dff Amit Shah
        }
151 a69c7600 Amit Shah
152 f1925dff Amit Shah
        for (i = port->iov_idx; i < port->elem.out_num; i++) {
153 f1925dff Amit Shah
            size_t buf_size;
154 f1925dff Amit Shah
            ssize_t ret;
155 f1925dff Amit Shah
156 f1925dff Amit Shah
            buf_size = port->elem.out_sg[i].iov_len - port->iov_offset;
157 a15bb0d6 Markus Armbruster
            ret = info->have_data(port,
158 a15bb0d6 Markus Armbruster
                                  port->elem.out_sg[i].iov_base
159 a15bb0d6 Markus Armbruster
                                  + port->iov_offset,
160 a15bb0d6 Markus Armbruster
                                  buf_size);
161 f1925dff Amit Shah
            if (ret < 0 && ret != -EAGAIN) {
162 f1925dff Amit Shah
                /* We don't handle any other type of errors here */
163 f1925dff Amit Shah
                abort();
164 f1925dff Amit Shah
            }
165 f1925dff Amit Shah
            if (ret == -EAGAIN || (ret >= 0 && ret < buf_size)) {
166 f1925dff Amit Shah
                virtio_serial_throttle_port(port, true);
167 f1925dff Amit Shah
                port->iov_idx = i;
168 f1925dff Amit Shah
                if (ret > 0) {
169 f1925dff Amit Shah
                    port->iov_offset += ret;
170 f1925dff Amit Shah
                }
171 f1925dff Amit Shah
                break;
172 f1925dff Amit Shah
            }
173 f1925dff Amit Shah
            port->iov_offset = 0;
174 a69c7600 Amit Shah
        }
175 f1925dff Amit Shah
        if (port->throttled) {
176 f1925dff Amit Shah
            break;
177 f1925dff Amit Shah
        }
178 f1925dff Amit Shah
        virtqueue_push(vq, &port->elem, 0);
179 f1925dff Amit Shah
        port->elem.out_num = 0;
180 a69c7600 Amit Shah
    }
181 a69c7600 Amit Shah
    virtio_notify(vdev, vq);
182 a69c7600 Amit Shah
}
183 a69c7600 Amit Shah
184 6bff8656 Amit Shah
static void flush_queued_data(VirtIOSerialPort *port)
185 9ed7b059 Amit Shah
{
186 a1c59752 Amit Shah
    assert(port);
187 9ed7b059 Amit Shah
188 6b611d3a Amit Shah
    if (!virtio_queue_ready(port->ovq)) {
189 6b611d3a Amit Shah
        return;
190 6b611d3a Amit Shah
    }
191 6bff8656 Amit Shah
    do_flush_queued_data(port, port->ovq, &port->vser->vdev);
192 9ed7b059 Amit Shah
}
193 9ed7b059 Amit Shah
194 98b19252 Amit Shah
static size_t send_control_msg(VirtIOSerialPort *port, void *buf, size_t len)
195 98b19252 Amit Shah
{
196 98b19252 Amit Shah
    VirtQueueElement elem;
197 98b19252 Amit Shah
    VirtQueue *vq;
198 98b19252 Amit Shah
    struct virtio_console_control *cpkt;
199 98b19252 Amit Shah
200 98b19252 Amit Shah
    vq = port->vser->c_ivq;
201 98b19252 Amit Shah
    if (!virtio_queue_ready(vq)) {
202 98b19252 Amit Shah
        return 0;
203 98b19252 Amit Shah
    }
204 98b19252 Amit Shah
    if (!virtqueue_pop(vq, &elem)) {
205 98b19252 Amit Shah
        return 0;
206 98b19252 Amit Shah
    }
207 98b19252 Amit Shah
208 98b19252 Amit Shah
    cpkt = (struct virtio_console_control *)buf;
209 98b19252 Amit Shah
    stl_p(&cpkt->id, port->id);
210 98b19252 Amit Shah
    memcpy(elem.in_sg[0].iov_base, buf, len);
211 98b19252 Amit Shah
212 98b19252 Amit Shah
    virtqueue_push(vq, &elem, len);
213 98b19252 Amit Shah
    virtio_notify(&port->vser->vdev, vq);
214 98b19252 Amit Shah
    return len;
215 98b19252 Amit Shah
}
216 98b19252 Amit Shah
217 98b19252 Amit Shah
static size_t send_control_event(VirtIOSerialPort *port, uint16_t event,
218 98b19252 Amit Shah
                                 uint16_t value)
219 98b19252 Amit Shah
{
220 98b19252 Amit Shah
    struct virtio_console_control cpkt;
221 98b19252 Amit Shah
222 98b19252 Amit Shah
    stw_p(&cpkt.event, event);
223 98b19252 Amit Shah
    stw_p(&cpkt.value, value);
224 98b19252 Amit Shah
225 49e3fdd7 Amit Shah
    trace_virtio_serial_send_control_event(port->id, event, value);
226 98b19252 Amit Shah
    return send_control_msg(port, &cpkt, sizeof(cpkt));
227 98b19252 Amit Shah
}
228 98b19252 Amit Shah
229 98b19252 Amit Shah
/* Functions for use inside qemu to open and read from/write to ports */
230 98b19252 Amit Shah
int virtio_serial_open(VirtIOSerialPort *port)
231 98b19252 Amit Shah
{
232 6663a195 Amit Shah
    /* Don't allow opening an already-open port */
233 6663a195 Amit Shah
    if (port->host_connected) {
234 6663a195 Amit Shah
        return 0;
235 6663a195 Amit Shah
    }
236 6663a195 Amit Shah
    /* Send port open notification to the guest */
237 6663a195 Amit Shah
    port->host_connected = true;
238 6663a195 Amit Shah
    send_control_event(port, VIRTIO_CONSOLE_PORT_OPEN, 1);
239 6663a195 Amit Shah
240 98b19252 Amit Shah
    return 0;
241 98b19252 Amit Shah
}
242 98b19252 Amit Shah
243 98b19252 Amit Shah
int virtio_serial_close(VirtIOSerialPort *port)
244 98b19252 Amit Shah
{
245 6663a195 Amit Shah
    port->host_connected = false;
246 9ed7b059 Amit Shah
    /*
247 9ed7b059 Amit Shah
     * If there's any data the guest sent which the app didn't
248 9ed7b059 Amit Shah
     * consume, reset the throttling flag and discard the data.
249 9ed7b059 Amit Shah
     */
250 9ed7b059 Amit Shah
    port->throttled = false;
251 6bff8656 Amit Shah
    discard_vq_data(port->ovq, &port->vser->vdev);
252 9ed7b059 Amit Shah
253 6663a195 Amit Shah
    send_control_event(port, VIRTIO_CONSOLE_PORT_OPEN, 0);
254 6663a195 Amit Shah
255 98b19252 Amit Shah
    return 0;
256 98b19252 Amit Shah
}
257 98b19252 Amit Shah
258 98b19252 Amit Shah
/* Individual ports/apps call this function to write to the guest. */
259 98b19252 Amit Shah
ssize_t virtio_serial_write(VirtIOSerialPort *port, const uint8_t *buf,
260 98b19252 Amit Shah
                            size_t size)
261 98b19252 Amit Shah
{
262 6663a195 Amit Shah
    if (!port || !port->host_connected || !port->guest_connected) {
263 6663a195 Amit Shah
        return 0;
264 6663a195 Amit Shah
    }
265 98b19252 Amit Shah
    return write_to_port(port, buf, size);
266 98b19252 Amit Shah
}
267 98b19252 Amit Shah
268 98b19252 Amit Shah
/*
269 98b19252 Amit Shah
 * Readiness of the guest to accept data on a port.
270 98b19252 Amit Shah
 * Returns max. data the guest can receive
271 98b19252 Amit Shah
 */
272 98b19252 Amit Shah
size_t virtio_serial_guest_ready(VirtIOSerialPort *port)
273 98b19252 Amit Shah
{
274 98b19252 Amit Shah
    VirtQueue *vq = port->ivq;
275 98b19252 Amit Shah
276 98b19252 Amit Shah
    if (!virtio_queue_ready(vq) ||
277 98b19252 Amit Shah
        !(port->vser->vdev.status & VIRTIO_CONFIG_S_DRIVER_OK) ||
278 98b19252 Amit Shah
        virtio_queue_empty(vq)) {
279 98b19252 Amit Shah
        return 0;
280 98b19252 Amit Shah
    }
281 6663a195 Amit Shah
    if (use_multiport(port->vser) && !port->guest_connected) {
282 6663a195 Amit Shah
        return 0;
283 6663a195 Amit Shah
    }
284 98b19252 Amit Shah
285 98b19252 Amit Shah
    if (virtqueue_avail_bytes(vq, 4096, 0)) {
286 98b19252 Amit Shah
        return 4096;
287 98b19252 Amit Shah
    }
288 98b19252 Amit Shah
    if (virtqueue_avail_bytes(vq, 1, 0)) {
289 98b19252 Amit Shah
        return 1;
290 98b19252 Amit Shah
    }
291 98b19252 Amit Shah
    return 0;
292 98b19252 Amit Shah
}
293 98b19252 Amit Shah
294 199646d8 Alon Levy
static void flush_queued_data_bh(void *opaque)
295 199646d8 Alon Levy
{
296 199646d8 Alon Levy
    VirtIOSerialPort *port = opaque;
297 199646d8 Alon Levy
298 199646d8 Alon Levy
    flush_queued_data(port);
299 199646d8 Alon Levy
}
300 199646d8 Alon Levy
301 9ed7b059 Amit Shah
void virtio_serial_throttle_port(VirtIOSerialPort *port, bool throttle)
302 9ed7b059 Amit Shah
{
303 9ed7b059 Amit Shah
    if (!port) {
304 9ed7b059 Amit Shah
        return;
305 9ed7b059 Amit Shah
    }
306 9ed7b059 Amit Shah
307 49e3fdd7 Amit Shah
    trace_virtio_serial_throttle_port(port->id, throttle);
308 9ed7b059 Amit Shah
    port->throttled = throttle;
309 9ed7b059 Amit Shah
    if (throttle) {
310 9ed7b059 Amit Shah
        return;
311 9ed7b059 Amit Shah
    }
312 199646d8 Alon Levy
    qemu_bh_schedule(port->bh);
313 9ed7b059 Amit Shah
}
314 9ed7b059 Amit Shah
315 98b19252 Amit Shah
/* Guest wants to notify us of some event */
316 e61da14d Amit Shah
static void handle_control_message(VirtIOSerial *vser, void *buf, size_t len)
317 98b19252 Amit Shah
{
318 98b19252 Amit Shah
    struct VirtIOSerialPort *port;
319 a15bb0d6 Markus Armbruster
    struct VirtIOSerialPortInfo *info;
320 98b19252 Amit Shah
    struct virtio_console_control cpkt, *gcpkt;
321 160600fd Amit Shah
    uint8_t *buffer;
322 160600fd Amit Shah
    size_t buffer_len;
323 98b19252 Amit Shah
324 98b19252 Amit Shah
    gcpkt = buf;
325 98b19252 Amit Shah
326 e61da14d Amit Shah
    if (len < sizeof(cpkt)) {
327 e61da14d Amit Shah
        /* The guest sent an invalid control packet */
328 e61da14d Amit Shah
        return;
329 e61da14d Amit Shah
    }
330 e61da14d Amit Shah
331 98b19252 Amit Shah
    cpkt.event = lduw_p(&gcpkt->event);
332 98b19252 Amit Shah
    cpkt.value = lduw_p(&gcpkt->value);
333 98b19252 Amit Shah
334 49e3fdd7 Amit Shah
    trace_virtio_serial_handle_control_message(cpkt.event, cpkt.value);
335 49e3fdd7 Amit Shah
336 d2e4d08b Luiz Capitulino
    if (cpkt.event == VIRTIO_CONSOLE_DEVICE_READY) {
337 4048c7c3 Amit Shah
        if (!cpkt.value) {
338 6daf194d Markus Armbruster
            error_report("virtio-serial-bus: Guest failure in adding device %s",
339 5e52e5f9 Markus Armbruster
                         vser->bus.qbus.name);
340 d2e4d08b Luiz Capitulino
            return;
341 4048c7c3 Amit Shah
        }
342 055b889f Amit Shah
        /*
343 055b889f Amit Shah
         * The device is up, we can now tell the device about all the
344 055b889f Amit Shah
         * ports we have here.
345 055b889f Amit Shah
         */
346 055b889f Amit Shah
        QTAILQ_FOREACH(port, &vser->ports, next) {
347 055b889f Amit Shah
            send_control_event(port, VIRTIO_CONSOLE_PORT_ADD, 1);
348 055b889f Amit Shah
        }
349 d2e4d08b Luiz Capitulino
        return;
350 d2e4d08b Luiz Capitulino
    }
351 055b889f Amit Shah
352 d2e4d08b Luiz Capitulino
    port = find_port_by_id(vser, ldl_p(&gcpkt->id));
353 d2e4d08b Luiz Capitulino
    if (!port) {
354 95c9cde2 Amit Shah
        error_report("virtio-serial-bus: Unexpected port id %u for device %s",
355 d2e4d08b Luiz Capitulino
                     ldl_p(&gcpkt->id), vser->bus.qbus.name);
356 d2e4d08b Luiz Capitulino
        return;
357 d2e4d08b Luiz Capitulino
    }
358 d2e4d08b Luiz Capitulino
359 49e3fdd7 Amit Shah
    trace_virtio_serial_handle_control_message_port(port->id);
360 49e3fdd7 Amit Shah
361 d2e4d08b Luiz Capitulino
    info = DO_UPCAST(VirtIOSerialPortInfo, qdev, port->dev.info);
362 d2e4d08b Luiz Capitulino
363 d2e4d08b Luiz Capitulino
    switch(cpkt.event) {
364 98b19252 Amit Shah
    case VIRTIO_CONSOLE_PORT_READY:
365 4048c7c3 Amit Shah
        if (!cpkt.value) {
366 6daf194d Markus Armbruster
            error_report("virtio-serial-bus: Guest failure in adding port %u for device %s",
367 5e52e5f9 Markus Armbruster
                         port->id, vser->bus.qbus.name);
368 4048c7c3 Amit Shah
            break;
369 4048c7c3 Amit Shah
        }
370 98b19252 Amit Shah
        /*
371 98b19252 Amit Shah
         * Now that we know the guest asked for the port name, we're
372 98b19252 Amit Shah
         * sure the guest has initialised whatever state is necessary
373 98b19252 Amit Shah
         * for this port. Now's a good time to let the guest know if
374 98b19252 Amit Shah
         * this port is a console port so that the guest can hook it
375 98b19252 Amit Shah
         * up to hvc.
376 98b19252 Amit Shah
         */
377 a15bb0d6 Markus Armbruster
        if (info->is_console) {
378 98b19252 Amit Shah
            send_control_event(port, VIRTIO_CONSOLE_CONSOLE_PORT, 1);
379 98b19252 Amit Shah
        }
380 6663a195 Amit Shah
381 160600fd Amit Shah
        if (port->name) {
382 160600fd Amit Shah
            stw_p(&cpkt.event, VIRTIO_CONSOLE_PORT_NAME);
383 160600fd Amit Shah
            stw_p(&cpkt.value, 1);
384 160600fd Amit Shah
385 160600fd Amit Shah
            buffer_len = sizeof(cpkt) + strlen(port->name) + 1;
386 7267c094 Anthony Liguori
            buffer = g_malloc(buffer_len);
387 160600fd Amit Shah
388 160600fd Amit Shah
            memcpy(buffer, &cpkt, sizeof(cpkt));
389 160600fd Amit Shah
            memcpy(buffer + sizeof(cpkt), port->name, strlen(port->name));
390 160600fd Amit Shah
            buffer[buffer_len - 1] = 0;
391 160600fd Amit Shah
392 160600fd Amit Shah
            send_control_msg(port, buffer, buffer_len);
393 7267c094 Anthony Liguori
            g_free(buffer);
394 160600fd Amit Shah
        }
395 160600fd Amit Shah
396 6663a195 Amit Shah
        if (port->host_connected) {
397 6663a195 Amit Shah
            send_control_event(port, VIRTIO_CONSOLE_PORT_OPEN, 1);
398 6663a195 Amit Shah
        }
399 6663a195 Amit Shah
400 98b19252 Amit Shah
        /*
401 98b19252 Amit Shah
         * When the guest has asked us for this information it means
402 98b19252 Amit Shah
         * the guest is all setup and has its virtqueues
403 98b19252 Amit Shah
         * initialised. If some app is interested in knowing about
404 98b19252 Amit Shah
         * this event, let it know.
405 98b19252 Amit Shah
         */
406 a15bb0d6 Markus Armbruster
        if (info->guest_ready) {
407 a15bb0d6 Markus Armbruster
            info->guest_ready(port);
408 98b19252 Amit Shah
        }
409 98b19252 Amit Shah
        break;
410 6663a195 Amit Shah
411 6663a195 Amit Shah
    case VIRTIO_CONSOLE_PORT_OPEN:
412 6663a195 Amit Shah
        port->guest_connected = cpkt.value;
413 a15bb0d6 Markus Armbruster
        if (cpkt.value && info->guest_open) {
414 6663a195 Amit Shah
            /* Send the guest opened notification if an app is interested */
415 a15bb0d6 Markus Armbruster
            info->guest_open(port);
416 6663a195 Amit Shah
        }
417 6663a195 Amit Shah
418 a15bb0d6 Markus Armbruster
        if (!cpkt.value && info->guest_close) {
419 6663a195 Amit Shah
            /* Send the guest closed notification if an app is interested */
420 a15bb0d6 Markus Armbruster
            info->guest_close(port);
421 6663a195 Amit Shah
        }
422 6663a195 Amit Shah
        break;
423 98b19252 Amit Shah
    }
424 98b19252 Amit Shah
}
425 98b19252 Amit Shah
426 98b19252 Amit Shah
static void control_in(VirtIODevice *vdev, VirtQueue *vq)
427 98b19252 Amit Shah
{
428 98b19252 Amit Shah
}
429 98b19252 Amit Shah
430 98b19252 Amit Shah
static void control_out(VirtIODevice *vdev, VirtQueue *vq)
431 98b19252 Amit Shah
{
432 98b19252 Amit Shah
    VirtQueueElement elem;
433 98b19252 Amit Shah
    VirtIOSerial *vser;
434 e61da14d Amit Shah
    uint8_t *buf;
435 e61da14d Amit Shah
    size_t len;
436 98b19252 Amit Shah
437 98b19252 Amit Shah
    vser = DO_UPCAST(VirtIOSerial, vdev, vdev);
438 98b19252 Amit Shah
439 e61da14d Amit Shah
    len = 0;
440 e61da14d Amit Shah
    buf = NULL;
441 98b19252 Amit Shah
    while (virtqueue_pop(vq, &elem)) {
442 e61da14d Amit Shah
        size_t cur_len, copied;
443 e61da14d Amit Shah
444 e61da14d Amit Shah
        cur_len = iov_size(elem.out_sg, elem.out_num);
445 e61da14d Amit Shah
        /*
446 e61da14d Amit Shah
         * Allocate a new buf only if we didn't have one previously or
447 e61da14d Amit Shah
         * if the size of the buf differs
448 e61da14d Amit Shah
         */
449 e61da14d Amit Shah
        if (cur_len > len) {
450 7267c094 Anthony Liguori
            g_free(buf);
451 e61da14d Amit Shah
452 7267c094 Anthony Liguori
            buf = g_malloc(cur_len);
453 e61da14d Amit Shah
            len = cur_len;
454 e61da14d Amit Shah
        }
455 e61da14d Amit Shah
        copied = iov_to_buf(elem.out_sg, elem.out_num, buf, 0, len);
456 e61da14d Amit Shah
457 e61da14d Amit Shah
        handle_control_message(vser, buf, copied);
458 1e4476aa Amit Shah
        virtqueue_push(vq, &elem, 0);
459 98b19252 Amit Shah
    }
460 7267c094 Anthony Liguori
    g_free(buf);
461 98b19252 Amit Shah
    virtio_notify(vdev, vq);
462 98b19252 Amit Shah
}
463 98b19252 Amit Shah
464 98b19252 Amit Shah
/* Guest wrote something to some port. */
465 98b19252 Amit Shah
static void handle_output(VirtIODevice *vdev, VirtQueue *vq)
466 98b19252 Amit Shah
{
467 98b19252 Amit Shah
    VirtIOSerial *vser;
468 a69c7600 Amit Shah
    VirtIOSerialPort *port;
469 a15bb0d6 Markus Armbruster
    VirtIOSerialPortInfo *info;
470 98b19252 Amit Shah
471 98b19252 Amit Shah
    vser = DO_UPCAST(VirtIOSerial, vdev, vdev);
472 a69c7600 Amit Shah
    port = find_port_by_vq(vser, vq);
473 a15bb0d6 Markus Armbruster
    info = port ? DO_UPCAST(VirtIOSerialPortInfo, qdev, port->dev.info) : NULL;
474 98b19252 Amit Shah
475 a15bb0d6 Markus Armbruster
    if (!port || !port->host_connected || !info->have_data) {
476 6bff8656 Amit Shah
        discard_vq_data(vq, vdev);
477 6bff8656 Amit Shah
        return;
478 6bff8656 Amit Shah
    }
479 e9b382b0 Amit Shah
480 e9b382b0 Amit Shah
    if (!port->throttled) {
481 e9b382b0 Amit Shah
        do_flush_queued_data(port, vq, vdev);
482 9ed7b059 Amit Shah
        return;
483 9ed7b059 Amit Shah
    }
484 98b19252 Amit Shah
}
485 98b19252 Amit Shah
486 98b19252 Amit Shah
static void handle_input(VirtIODevice *vdev, VirtQueue *vq)
487 98b19252 Amit Shah
{
488 98b19252 Amit Shah
}
489 98b19252 Amit Shah
490 98b19252 Amit Shah
static uint32_t get_features(VirtIODevice *vdev, uint32_t features)
491 98b19252 Amit Shah
{
492 306eb457 Amit Shah
    VirtIOSerial *vser;
493 306eb457 Amit Shah
494 306eb457 Amit Shah
    vser = DO_UPCAST(VirtIOSerial, vdev, vdev);
495 306eb457 Amit Shah
496 5e52e5f9 Markus Armbruster
    if (vser->bus.max_nr_ports > 1) {
497 ee4d45be Michael S. Tsirkin
        features |= (1 << VIRTIO_CONSOLE_F_MULTIPORT);
498 ee4d45be Michael S. Tsirkin
    }
499 98b19252 Amit Shah
    return features;
500 98b19252 Amit Shah
}
501 98b19252 Amit Shah
502 98b19252 Amit Shah
/* Guest requested config info */
503 98b19252 Amit Shah
static void get_config(VirtIODevice *vdev, uint8_t *config_data)
504 98b19252 Amit Shah
{
505 98b19252 Amit Shah
    VirtIOSerial *vser;
506 98b19252 Amit Shah
507 98b19252 Amit Shah
    vser = DO_UPCAST(VirtIOSerial, vdev, vdev);
508 98b19252 Amit Shah
    memcpy(config_data, &vser->config, sizeof(struct virtio_console_config));
509 98b19252 Amit Shah
}
510 98b19252 Amit Shah
511 98b19252 Amit Shah
static void set_config(VirtIODevice *vdev, const uint8_t *config_data)
512 98b19252 Amit Shah
{
513 98b19252 Amit Shah
    struct virtio_console_config config;
514 98b19252 Amit Shah
515 98b19252 Amit Shah
    memcpy(&config, config_data, sizeof(config));
516 98b19252 Amit Shah
}
517 98b19252 Amit Shah
518 98b19252 Amit Shah
static void virtio_serial_save(QEMUFile *f, void *opaque)
519 98b19252 Amit Shah
{
520 98b19252 Amit Shah
    VirtIOSerial *s = opaque;
521 6663a195 Amit Shah
    VirtIOSerialPort *port;
522 6663a195 Amit Shah
    uint32_t nr_active_ports;
523 5c1c9bb2 Alexey Kardashevskiy
    unsigned int i, max_nr_ports;
524 98b19252 Amit Shah
525 98b19252 Amit Shah
    /* The virtio device */
526 98b19252 Amit Shah
    virtio_save(&s->vdev, f);
527 98b19252 Amit Shah
528 98b19252 Amit Shah
    /* The config space */
529 98b19252 Amit Shah
    qemu_put_be16s(f, &s->config.cols);
530 98b19252 Amit Shah
    qemu_put_be16s(f, &s->config.rows);
531 6663a195 Amit Shah
532 055b889f Amit Shah
    qemu_put_be32s(f, &s->config.max_nr_ports);
533 055b889f Amit Shah
534 055b889f Amit Shah
    /* The ports map */
535 5c1c9bb2 Alexey Kardashevskiy
    max_nr_ports = tswap32(s->config.max_nr_ports);
536 5c1c9bb2 Alexey Kardashevskiy
    for (i = 0; i < (max_nr_ports + 31) / 32; i++) {
537 055b889f Amit Shah
        qemu_put_be32s(f, &s->ports_map[i]);
538 055b889f Amit Shah
    }
539 6663a195 Amit Shah
540 055b889f Amit Shah
    /* Ports */
541 e245795b Amit Shah
542 6663a195 Amit Shah
    nr_active_ports = 0;
543 e245795b Amit Shah
    QTAILQ_FOREACH(port, &s->ports, next) {
544 6663a195 Amit Shah
        nr_active_ports++;
545 e245795b Amit Shah
    }
546 6663a195 Amit Shah
547 6663a195 Amit Shah
    qemu_put_be32s(f, &nr_active_ports);
548 6663a195 Amit Shah
549 6663a195 Amit Shah
    /*
550 6663a195 Amit Shah
     * Items in struct VirtIOSerialPort.
551 6663a195 Amit Shah
     */
552 6663a195 Amit Shah
    QTAILQ_FOREACH(port, &s->ports, next) {
553 37f95bf3 Amit Shah
        uint32_t elem_popped;
554 37f95bf3 Amit Shah
555 6663a195 Amit Shah
        qemu_put_be32s(f, &port->id);
556 6663a195 Amit Shah
        qemu_put_byte(f, port->guest_connected);
557 31abe21f Amit Shah
        qemu_put_byte(f, port->host_connected);
558 37f95bf3 Amit Shah
559 37f95bf3 Amit Shah
        elem_popped = 0;
560 37f95bf3 Amit Shah
        if (port->elem.out_num) {
561 37f95bf3 Amit Shah
            elem_popped = 1;
562 37f95bf3 Amit Shah
        }
563 37f95bf3 Amit Shah
        qemu_put_be32s(f, &elem_popped);
564 37f95bf3 Amit Shah
        if (elem_popped) {
565 37f95bf3 Amit Shah
            qemu_put_be32s(f, &port->iov_idx);
566 37f95bf3 Amit Shah
            qemu_put_be64s(f, &port->iov_offset);
567 37f95bf3 Amit Shah
568 37f95bf3 Amit Shah
            qemu_put_buffer(f, (unsigned char *)&port->elem,
569 37f95bf3 Amit Shah
                            sizeof(port->elem));
570 37f95bf3 Amit Shah
        }
571 6663a195 Amit Shah
    }
572 98b19252 Amit Shah
}
573 98b19252 Amit Shah
574 98b19252 Amit Shah
static int virtio_serial_load(QEMUFile *f, void *opaque, int version_id)
575 98b19252 Amit Shah
{
576 98b19252 Amit Shah
    VirtIOSerial *s = opaque;
577 6663a195 Amit Shah
    VirtIOSerialPort *port;
578 f83ccb3e Markus Armbruster
    uint32_t max_nr_ports, nr_active_ports, ports_map;
579 6663a195 Amit Shah
    unsigned int i;
580 98b19252 Amit Shah
581 37f95bf3 Amit Shah
    if (version_id > 3) {
582 98b19252 Amit Shah
        return -EINVAL;
583 98b19252 Amit Shah
    }
584 6663a195 Amit Shah
585 98b19252 Amit Shah
    /* The virtio device */
586 98b19252 Amit Shah
    virtio_load(&s->vdev, f);
587 98b19252 Amit Shah
588 98b19252 Amit Shah
    if (version_id < 2) {
589 98b19252 Amit Shah
        return 0;
590 98b19252 Amit Shah
    }
591 98b19252 Amit Shah
592 98b19252 Amit Shah
    /* The config space */
593 98b19252 Amit Shah
    qemu_get_be16s(f, &s->config.cols);
594 98b19252 Amit Shah
    qemu_get_be16s(f, &s->config.rows);
595 295587f7 Amit Shah
596 055b889f Amit Shah
    qemu_get_be32s(f, &max_nr_ports);
597 5c1c9bb2 Alexey Kardashevskiy
    tswap32s(&max_nr_ports);
598 5c1c9bb2 Alexey Kardashevskiy
    if (max_nr_ports > tswap32(s->config.max_nr_ports)) {
599 055b889f Amit Shah
        /* Source could have had more ports than us. Fail migration. */
600 295587f7 Amit Shah
        return -EINVAL;
601 295587f7 Amit Shah
    }
602 98b19252 Amit Shah
603 055b889f Amit Shah
    for (i = 0; i < (max_nr_ports + 31) / 32; i++) {
604 f83ccb3e Markus Armbruster
        qemu_get_be32s(f, &ports_map);
605 055b889f Amit Shah
606 f83ccb3e Markus Armbruster
        if (ports_map != s->ports_map[i]) {
607 055b889f Amit Shah
            /*
608 055b889f Amit Shah
             * Ports active on source and destination don't
609 055b889f Amit Shah
             * match. Fail migration.
610 055b889f Amit Shah
             */
611 055b889f Amit Shah
            return -EINVAL;
612 055b889f Amit Shah
        }
613 e245795b Amit Shah
    }
614 e245795b Amit Shah
615 6663a195 Amit Shah
    qemu_get_be32s(f, &nr_active_ports);
616 6663a195 Amit Shah
617 6663a195 Amit Shah
    /* Items in struct VirtIOSerialPort */
618 6663a195 Amit Shah
    for (i = 0; i < nr_active_ports; i++) {
619 6663a195 Amit Shah
        uint32_t id;
620 31abe21f Amit Shah
        bool host_connected;
621 6663a195 Amit Shah
622 6663a195 Amit Shah
        id = qemu_get_be32(f);
623 6663a195 Amit Shah
        port = find_port_by_id(s, id);
624 fbe0c559 Michael S. Tsirkin
        if (!port) {
625 fbe0c559 Michael S. Tsirkin
            return -EINVAL;
626 fbe0c559 Michael S. Tsirkin
        }
627 6663a195 Amit Shah
628 6663a195 Amit Shah
        port->guest_connected = qemu_get_byte(f);
629 31abe21f Amit Shah
        host_connected = qemu_get_byte(f);
630 31abe21f Amit Shah
        if (host_connected != port->host_connected) {
631 31abe21f Amit Shah
            /*
632 31abe21f Amit Shah
             * We have to let the guest know of the host connection
633 31abe21f Amit Shah
             * status change
634 31abe21f Amit Shah
             */
635 31abe21f Amit Shah
            send_control_event(port, VIRTIO_CONSOLE_PORT_OPEN,
636 31abe21f Amit Shah
                               port->host_connected);
637 31abe21f Amit Shah
        }
638 37f95bf3 Amit Shah
639 37f95bf3 Amit Shah
        if (version_id > 2) {
640 37f95bf3 Amit Shah
            uint32_t elem_popped;
641 37f95bf3 Amit Shah
642 37f95bf3 Amit Shah
            qemu_get_be32s(f, &elem_popped);
643 37f95bf3 Amit Shah
            if (elem_popped) {
644 37f95bf3 Amit Shah
                qemu_get_be32s(f, &port->iov_idx);
645 37f95bf3 Amit Shah
                qemu_get_be64s(f, &port->iov_offset);
646 37f95bf3 Amit Shah
647 37f95bf3 Amit Shah
                qemu_get_buffer(f, (unsigned char *)&port->elem,
648 37f95bf3 Amit Shah
                                sizeof(port->elem));
649 37f95bf3 Amit Shah
                virtqueue_map_sg(port->elem.in_sg, port->elem.in_addr,
650 37f95bf3 Amit Shah
                                 port->elem.in_num, 1);
651 37f95bf3 Amit Shah
                virtqueue_map_sg(port->elem.out_sg, port->elem.out_addr,
652 37f95bf3 Amit Shah
                                 port->elem.out_num, 1);
653 37f95bf3 Amit Shah
654 37f95bf3 Amit Shah
                /*
655 37f95bf3 Amit Shah
                 *  Port was throttled on source machine.  Let's
656 37f95bf3 Amit Shah
                 *  unthrottle it here so data starts flowing again.
657 37f95bf3 Amit Shah
                 */
658 37f95bf3 Amit Shah
                virtio_serial_throttle_port(port, false);
659 37f95bf3 Amit Shah
            }
660 37f95bf3 Amit Shah
        }
661 6663a195 Amit Shah
    }
662 98b19252 Amit Shah
    return 0;
663 98b19252 Amit Shah
}
664 98b19252 Amit Shah
665 98b19252 Amit Shah
static void virtser_bus_dev_print(Monitor *mon, DeviceState *qdev, int indent);
666 98b19252 Amit Shah
667 98b19252 Amit Shah
static struct BusInfo virtser_bus_info = {
668 98b19252 Amit Shah
    .name      = "virtio-serial-bus",
669 98b19252 Amit Shah
    .size      = sizeof(VirtIOSerialBus),
670 98b19252 Amit Shah
    .print_dev = virtser_bus_dev_print,
671 d6cca4b0 Markus Armbruster
    .props      = (Property[]) {
672 d6cca4b0 Markus Armbruster
        DEFINE_PROP_UINT32("nr", VirtIOSerialPort, id, VIRTIO_CONSOLE_BAD_ID),
673 d6cca4b0 Markus Armbruster
        DEFINE_PROP_STRING("name", VirtIOSerialPort, name),
674 d6cca4b0 Markus Armbruster
        DEFINE_PROP_END_OF_LIST()
675 d6cca4b0 Markus Armbruster
    }
676 98b19252 Amit Shah
};
677 98b19252 Amit Shah
678 98b19252 Amit Shah
static void virtser_bus_dev_print(Monitor *mon, DeviceState *qdev, int indent)
679 98b19252 Amit Shah
{
680 a43f9c90 Gerd Hoffmann
    VirtIOSerialPort *port = DO_UPCAST(VirtIOSerialPort, dev, qdev);
681 98b19252 Amit Shah
682 021a1318 Markus Armbruster
    monitor_printf(mon, "%*sport %d, guest %s, host %s, throttle %s\n",
683 021a1318 Markus Armbruster
                   indent, "", port->id,
684 021a1318 Markus Armbruster
                   port->guest_connected ? "on" : "off",
685 021a1318 Markus Armbruster
                   port->host_connected ? "on" : "off",
686 021a1318 Markus Armbruster
                   port->throttled ? "on" : "off");
687 98b19252 Amit Shah
}
688 98b19252 Amit Shah
689 055b889f Amit Shah
/* This function is only used if a port id is not provided by the user */
690 055b889f Amit Shah
static uint32_t find_free_port_id(VirtIOSerial *vser)
691 055b889f Amit Shah
{
692 5c1c9bb2 Alexey Kardashevskiy
    unsigned int i, max_nr_ports;
693 055b889f Amit Shah
694 5c1c9bb2 Alexey Kardashevskiy
    max_nr_ports = tswap32(vser->config.max_nr_ports);
695 5c1c9bb2 Alexey Kardashevskiy
    for (i = 0; i < (max_nr_ports + 31) / 32; i++) {
696 055b889f Amit Shah
        uint32_t map, bit;
697 055b889f Amit Shah
698 055b889f Amit Shah
        map = vser->ports_map[i];
699 055b889f Amit Shah
        bit = ffs(~map);
700 055b889f Amit Shah
        if (bit) {
701 055b889f Amit Shah
            return (bit - 1) + i * 32;
702 055b889f Amit Shah
        }
703 055b889f Amit Shah
    }
704 055b889f Amit Shah
    return VIRTIO_CONSOLE_BAD_ID;
705 055b889f Amit Shah
}
706 055b889f Amit Shah
707 055b889f Amit Shah
static void mark_port_added(VirtIOSerial *vser, uint32_t port_id)
708 055b889f Amit Shah
{
709 055b889f Amit Shah
    unsigned int i;
710 055b889f Amit Shah
711 055b889f Amit Shah
    i = port_id / 32;
712 055b889f Amit Shah
    vser->ports_map[i] |= 1U << (port_id % 32);
713 055b889f Amit Shah
}
714 055b889f Amit Shah
715 055b889f Amit Shah
static void add_port(VirtIOSerial *vser, uint32_t port_id)
716 055b889f Amit Shah
{
717 055b889f Amit Shah
    mark_port_added(vser, port_id);
718 055b889f Amit Shah
719 055b889f Amit Shah
    send_control_event(find_port_by_id(vser, port_id),
720 055b889f Amit Shah
                       VIRTIO_CONSOLE_PORT_ADD, 1);
721 055b889f Amit Shah
}
722 055b889f Amit Shah
723 055b889f Amit Shah
static void remove_port(VirtIOSerial *vser, uint32_t port_id)
724 055b889f Amit Shah
{
725 9ed7b059 Amit Shah
    VirtIOSerialPort *port;
726 055b889f Amit Shah
    unsigned int i;
727 055b889f Amit Shah
728 055b889f Amit Shah
    i = port_id / 32;
729 055b889f Amit Shah
    vser->ports_map[i] &= ~(1U << (port_id % 32));
730 055b889f Amit Shah
731 9ed7b059 Amit Shah
    port = find_port_by_id(vser, port_id);
732 9ed7b059 Amit Shah
    /* Flush out any unconsumed buffers first */
733 6bff8656 Amit Shah
    discard_vq_data(port->ovq, &port->vser->vdev);
734 9ed7b059 Amit Shah
735 9ed7b059 Amit Shah
    send_control_event(port, VIRTIO_CONSOLE_PORT_REMOVE, 1);
736 055b889f Amit Shah
}
737 055b889f Amit Shah
738 98b19252 Amit Shah
static int virtser_port_qdev_init(DeviceState *qdev, DeviceInfo *base)
739 98b19252 Amit Shah
{
740 a43f9c90 Gerd Hoffmann
    VirtIOSerialPort *port = DO_UPCAST(VirtIOSerialPort, dev, qdev);
741 98b19252 Amit Shah
    VirtIOSerialPortInfo *info = DO_UPCAST(VirtIOSerialPortInfo, qdev, base);
742 98b19252 Amit Shah
    VirtIOSerialBus *bus = DO_UPCAST(VirtIOSerialBus, qbus, qdev->parent_bus);
743 5c1c9bb2 Alexey Kardashevskiy
    int ret, max_nr_ports;
744 98b19252 Amit Shah
    bool plugging_port0;
745 98b19252 Amit Shah
746 98b19252 Amit Shah
    port->vser = bus->vser;
747 199646d8 Alon Levy
    port->bh = qemu_bh_new(flush_queued_data_bh, port);
748 98b19252 Amit Shah
749 98b19252 Amit Shah
    /*
750 98b19252 Amit Shah
     * Is the first console port we're seeing? If so, put it up at
751 98b19252 Amit Shah
     * location 0. This is done for backward compatibility (old
752 98b19252 Amit Shah
     * kernel, new qemu).
753 98b19252 Amit Shah
     */
754 2a3d57ce Markus Armbruster
    plugging_port0 = info->is_console && !find_port_by_id(port->vser, 0);
755 98b19252 Amit Shah
756 055b889f Amit Shah
    if (find_port_by_id(port->vser, port->id)) {
757 6daf194d Markus Armbruster
        error_report("virtio-serial-bus: A port already exists at id %u",
758 055b889f Amit Shah
                     port->id);
759 98b19252 Amit Shah
        return -1;
760 98b19252 Amit Shah
    }
761 98b19252 Amit Shah
762 055b889f Amit Shah
    if (port->id == VIRTIO_CONSOLE_BAD_ID) {
763 055b889f Amit Shah
        if (plugging_port0) {
764 055b889f Amit Shah
            port->id = 0;
765 055b889f Amit Shah
        } else {
766 055b889f Amit Shah
            port->id = find_free_port_id(port->vser);
767 055b889f Amit Shah
            if (port->id == VIRTIO_CONSOLE_BAD_ID) {
768 6daf194d Markus Armbruster
                error_report("virtio-serial-bus: Maximum port limit for this device reached");
769 055b889f Amit Shah
                return -1;
770 055b889f Amit Shah
            }
771 055b889f Amit Shah
        }
772 055b889f Amit Shah
    }
773 055b889f Amit Shah
774 5c1c9bb2 Alexey Kardashevskiy
    max_nr_ports = tswap32(port->vser->config.max_nr_ports);
775 5c1c9bb2 Alexey Kardashevskiy
    if (port->id >= max_nr_ports) {
776 6daf194d Markus Armbruster
        error_report("virtio-serial-bus: Out-of-range port id specified, max. allowed: %u",
777 5c1c9bb2 Alexey Kardashevskiy
                     max_nr_ports - 1);
778 055b889f Amit Shah
        return -1;
779 055b889f Amit Shah
    }
780 055b889f Amit Shah
781 a43f9c90 Gerd Hoffmann
    ret = info->init(port);
782 98b19252 Amit Shah
    if (ret) {
783 98b19252 Amit Shah
        return ret;
784 98b19252 Amit Shah
    }
785 98b19252 Amit Shah
786 6663a195 Amit Shah
    if (!use_multiport(port->vser)) {
787 6663a195 Amit Shah
        /*
788 6663a195 Amit Shah
         * Allow writes to guest in this case; we have no way of
789 6663a195 Amit Shah
         * knowing if a guest port is connected.
790 6663a195 Amit Shah
         */
791 6663a195 Amit Shah
        port->guest_connected = true;
792 6663a195 Amit Shah
    }
793 6663a195 Amit Shah
794 f1925dff Amit Shah
    port->elem.out_num = 0;
795 f1925dff Amit Shah
796 98b19252 Amit Shah
    QTAILQ_INSERT_TAIL(&port->vser->ports, port, next);
797 98b19252 Amit Shah
    port->ivq = port->vser->ivqs[port->id];
798 98b19252 Amit Shah
    port->ovq = port->vser->ovqs[port->id];
799 98b19252 Amit Shah
800 055b889f Amit Shah
    add_port(port->vser, port->id);
801 055b889f Amit Shah
802 98b19252 Amit Shah
    /* Send an update to the guest about this new port added */
803 98b19252 Amit Shah
    virtio_notify_config(&port->vser->vdev);
804 98b19252 Amit Shah
805 98b19252 Amit Shah
    return ret;
806 98b19252 Amit Shah
}
807 98b19252 Amit Shah
808 98b19252 Amit Shah
static int virtser_port_qdev_exit(DeviceState *qdev)
809 98b19252 Amit Shah
{
810 a43f9c90 Gerd Hoffmann
    VirtIOSerialPort *port = DO_UPCAST(VirtIOSerialPort, dev, qdev);
811 a15bb0d6 Markus Armbruster
    VirtIOSerialPortInfo *info = DO_UPCAST(VirtIOSerialPortInfo, qdev,
812 a15bb0d6 Markus Armbruster
                                           port->dev.info);
813 98b19252 Amit Shah
    VirtIOSerial *vser = port->vser;
814 98b19252 Amit Shah
815 199646d8 Alon Levy
    qemu_bh_delete(port->bh);
816 055b889f Amit Shah
    remove_port(port->vser, port->id);
817 f146ec9a Amit Shah
818 98b19252 Amit Shah
    QTAILQ_REMOVE(&vser->ports, port, next);
819 98b19252 Amit Shah
820 a15bb0d6 Markus Armbruster
    if (info->exit) {
821 a15bb0d6 Markus Armbruster
        info->exit(port);
822 a15bb0d6 Markus Armbruster
    }
823 98b19252 Amit Shah
    return 0;
824 98b19252 Amit Shah
}
825 98b19252 Amit Shah
826 98b19252 Amit Shah
void virtio_serial_port_qdev_register(VirtIOSerialPortInfo *info)
827 98b19252 Amit Shah
{
828 98b19252 Amit Shah
    info->qdev.init = virtser_port_qdev_init;
829 98b19252 Amit Shah
    info->qdev.bus_info = &virtser_bus_info;
830 98b19252 Amit Shah
    info->qdev.exit = virtser_port_qdev_exit;
831 98b19252 Amit Shah
    info->qdev.unplug = qdev_simple_unplug_cb;
832 98b19252 Amit Shah
    qdev_register(&info->qdev);
833 98b19252 Amit Shah
}
834 98b19252 Amit Shah
835 6b331efb Amit Shah
VirtIODevice *virtio_serial_init(DeviceState *dev, virtio_serial_conf *conf)
836 98b19252 Amit Shah
{
837 98b19252 Amit Shah
    VirtIOSerial *vser;
838 98b19252 Amit Shah
    VirtIODevice *vdev;
839 5ab4bb59 Amit Shah
    uint32_t i, max_supported_ports;
840 98b19252 Amit Shah
841 6b331efb Amit Shah
    if (!conf->max_virtserial_ports)
842 98b19252 Amit Shah
        return NULL;
843 98b19252 Amit Shah
844 5ab4bb59 Amit Shah
    /* Each port takes 2 queues, and one pair is for the control queue */
845 5ab4bb59 Amit Shah
    max_supported_ports = VIRTIO_PCI_QUEUE_MAX / 2 - 1;
846 5ab4bb59 Amit Shah
847 6b331efb Amit Shah
    if (conf->max_virtserial_ports > max_supported_ports) {
848 5ab4bb59 Amit Shah
        error_report("maximum ports supported: %u", max_supported_ports);
849 5ab4bb59 Amit Shah
        return NULL;
850 5ab4bb59 Amit Shah
    }
851 5ab4bb59 Amit Shah
852 98b19252 Amit Shah
    vdev = virtio_common_init("virtio-serial", VIRTIO_ID_CONSOLE,
853 98b19252 Amit Shah
                              sizeof(struct virtio_console_config),
854 98b19252 Amit Shah
                              sizeof(VirtIOSerial));
855 98b19252 Amit Shah
856 98b19252 Amit Shah
    vser = DO_UPCAST(VirtIOSerial, vdev, vdev);
857 98b19252 Amit Shah
858 98b19252 Amit Shah
    /* Spawn a new virtio-serial bus on which the ports will ride as devices */
859 5e52e5f9 Markus Armbruster
    qbus_create_inplace(&vser->bus.qbus, &virtser_bus_info, dev, NULL);
860 5e52e5f9 Markus Armbruster
    vser->bus.qbus.allow_hotplug = 1;
861 5e52e5f9 Markus Armbruster
    vser->bus.vser = vser;
862 98b19252 Amit Shah
    QTAILQ_INIT(&vser->ports);
863 98b19252 Amit Shah
864 5e52e5f9 Markus Armbruster
    vser->bus.max_nr_ports = conf->max_virtserial_ports;
865 7267c094 Anthony Liguori
    vser->ivqs = g_malloc(conf->max_virtserial_ports * sizeof(VirtQueue *));
866 7267c094 Anthony Liguori
    vser->ovqs = g_malloc(conf->max_virtserial_ports * sizeof(VirtQueue *));
867 98b19252 Amit Shah
868 98b19252 Amit Shah
    /* Add a queue for host to guest transfers for port 0 (backward compat) */
869 98b19252 Amit Shah
    vser->ivqs[0] = virtio_add_queue(vdev, 128, handle_input);
870 98b19252 Amit Shah
    /* Add a queue for guest to host transfers for port 0 (backward compat) */
871 98b19252 Amit Shah
    vser->ovqs[0] = virtio_add_queue(vdev, 128, handle_output);
872 98b19252 Amit Shah
873 a01a9cb8 Amit Shah
    /* TODO: host to guest notifications can get dropped
874 a01a9cb8 Amit Shah
     * if the queue fills up. Implement queueing in host,
875 a01a9cb8 Amit Shah
     * this might also make it possible to reduce the control
876 a01a9cb8 Amit Shah
     * queue size: as guest preposts buffers there,
877 a01a9cb8 Amit Shah
     * this will save 4Kbyte of guest memory per entry. */
878 a01a9cb8 Amit Shah
879 98b19252 Amit Shah
    /* control queue: host to guest */
880 a01a9cb8 Amit Shah
    vser->c_ivq = virtio_add_queue(vdev, 32, control_in);
881 98b19252 Amit Shah
    /* control queue: guest to host */
882 a01a9cb8 Amit Shah
    vser->c_ovq = virtio_add_queue(vdev, 32, control_out);
883 98b19252 Amit Shah
884 5e52e5f9 Markus Armbruster
    for (i = 1; i < vser->bus.max_nr_ports; i++) {
885 98b19252 Amit Shah
        /* Add a per-port queue for host to guest transfers */
886 98b19252 Amit Shah
        vser->ivqs[i] = virtio_add_queue(vdev, 128, handle_input);
887 98b19252 Amit Shah
        /* Add a per-per queue for guest to host transfers */
888 98b19252 Amit Shah
        vser->ovqs[i] = virtio_add_queue(vdev, 128, handle_output);
889 98b19252 Amit Shah
    }
890 98b19252 Amit Shah
891 5c1c9bb2 Alexey Kardashevskiy
    vser->config.max_nr_ports = tswap32(conf->max_virtserial_ports);
892 7267c094 Anthony Liguori
    vser->ports_map = g_malloc0(((conf->max_virtserial_ports + 31) / 32)
893 a132a679 Alon Levy
        * sizeof(vser->ports_map[0]));
894 98b19252 Amit Shah
    /*
895 98b19252 Amit Shah
     * Reserve location 0 for a console port for backward compat
896 98b19252 Amit Shah
     * (old kernel, new qemu)
897 98b19252 Amit Shah
     */
898 055b889f Amit Shah
    mark_port_added(vser, 0);
899 98b19252 Amit Shah
900 98b19252 Amit Shah
    vser->vdev.get_features = get_features;
901 98b19252 Amit Shah
    vser->vdev.get_config = get_config;
902 98b19252 Amit Shah
    vser->vdev.set_config = set_config;
903 98b19252 Amit Shah
904 8b53a865 Amit Shah
    vser->qdev = dev;
905 8b53a865 Amit Shah
906 98b19252 Amit Shah
    /*
907 98b19252 Amit Shah
     * Register for the savevm section with the virtio-console name
908 98b19252 Amit Shah
     * to preserve backward compat
909 98b19252 Amit Shah
     */
910 37f95bf3 Amit Shah
    register_savevm(dev, "virtio-console", -1, 3, virtio_serial_save,
911 98b19252 Amit Shah
                    virtio_serial_load, vser);
912 98b19252 Amit Shah
913 98b19252 Amit Shah
    return vdev;
914 98b19252 Amit Shah
}
915 8b53a865 Amit Shah
916 8b53a865 Amit Shah
void virtio_serial_exit(VirtIODevice *vdev)
917 8b53a865 Amit Shah
{
918 8b53a865 Amit Shah
    VirtIOSerial *vser = DO_UPCAST(VirtIOSerial, vdev, vdev);
919 8b53a865 Amit Shah
920 8b53a865 Amit Shah
    unregister_savevm(vser->qdev, "virtio-console", vser);
921 8b53a865 Amit Shah
922 7267c094 Anthony Liguori
    g_free(vser->ivqs);
923 7267c094 Anthony Liguori
    g_free(vser->ovqs);
924 7267c094 Anthony Liguori
    g_free(vser->ports_map);
925 8b53a865 Amit Shah
926 8b53a865 Amit Shah
    virtio_cleanup(vdev);
927 8b53a865 Amit Shah
}