virtio.c 31.8 KB
Newer Older
A
aliguori 已提交
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15
/*
 * Virtio Support
 *
 * Copyright IBM, Corp. 2007
 *
 * Authors:
 *  Anthony Liguori   <aliguori@us.ibm.com>
 *
 * This work is licensed under the terms of the GNU GPL, version 2.  See
 * the COPYING file in the top-level directory.
 *
 */

#include <inttypes.h>

16
#include "trace.h"
17
#include "qemu/error-report.h"
P
Paolo Bonzini 已提交
18
#include "hw/virtio/virtio.h"
19
#include "qemu/atomic.h"
P
Paolo Bonzini 已提交
20
#include "hw/virtio/virtio-bus.h"
A
aliguori 已提交
21

22 23 24 25 26
/*
 * The alignment to use between consumer and producer parts of vring.
 * x86 pagesize again. This is the default, used by transports like PCI
 * which don't provide a means for the guest to tell the host the alignment.
 */
27 28
#define VIRTIO_PCI_VRING_ALIGN         4096

A
aliguori 已提交
29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59
typedef struct VRingDesc
{
    uint64_t addr;
    uint32_t len;
    uint16_t flags;
    uint16_t next;
} VRingDesc;

typedef struct VRingAvail
{
    uint16_t flags;
    uint16_t idx;
    uint16_t ring[0];
} VRingAvail;

typedef struct VRingUsedElem
{
    uint32_t id;
    uint32_t len;
} VRingUsedElem;

typedef struct VRingUsed
{
    uint16_t flags;
    uint16_t idx;
    VRingUsedElem ring[0];
} VRingUsed;

typedef struct VRing
{
    unsigned int num;
60
    unsigned int align;
A
Avi Kivity 已提交
61 62 63
    hwaddr desc;
    hwaddr avail;
    hwaddr used;
A
aliguori 已提交
64 65 66 67 68
} VRing;

struct VirtQueue
{
    VRing vring;
A
Avi Kivity 已提交
69
    hwaddr pa;
A
aliguori 已提交
70
    uint16_t last_avail_idx;
M
Michael S. Tsirkin 已提交
71 72 73 74 75 76 77 78 79
    /* Last used index value we have signalled on */
    uint16_t signalled_used;

    /* Last used index value we have signalled on */
    bool signalled_used_valid;

    /* Notification enabled? */
    bool notification;

80 81
    uint16_t queue_index;

A
aliguori 已提交
82
    int inuse;
M
Michael S. Tsirkin 已提交
83

84
    uint16_t vector;
A
aliguori 已提交
85
    void (*handle_output)(VirtIODevice *vdev, VirtQueue *vq);
86 87 88
    VirtIODevice *vdev;
    EventNotifier guest_notifier;
    EventNotifier host_notifier;
A
aliguori 已提交
89 90 91
};

/* virt queue functions */
P
Paul Brook 已提交
92
static void virtqueue_init(VirtQueue *vq)
A
aliguori 已提交
93
{
A
Avi Kivity 已提交
94
    hwaddr pa = vq->pa;
P
Paul Brook 已提交
95

A
aliguori 已提交
96 97
    vq->vring.desc = pa;
    vq->vring.avail = pa + vq->vring.num * sizeof(VRingDesc);
98 99
    vq->vring.used = vring_align(vq->vring.avail +
                                 offsetof(VRingAvail, ring[vq->vring.num]),
100
                                 vq->vring.align);
A
aliguori 已提交
101 102
}

A
Avi Kivity 已提交
103
static inline uint64_t vring_desc_addr(hwaddr desc_pa, int i)
A
aliguori 已提交
104
{
A
Avi Kivity 已提交
105
    hwaddr pa;
106
    pa = desc_pa + sizeof(VRingDesc) * i + offsetof(VRingDesc, addr);
A
aliguori 已提交
107 108 109
    return ldq_phys(pa);
}

A
Avi Kivity 已提交
110
static inline uint32_t vring_desc_len(hwaddr desc_pa, int i)
A
aliguori 已提交
111
{
A
Avi Kivity 已提交
112
    hwaddr pa;
113
    pa = desc_pa + sizeof(VRingDesc) * i + offsetof(VRingDesc, len);
A
aliguori 已提交
114 115 116
    return ldl_phys(pa);
}

A
Avi Kivity 已提交
117
static inline uint16_t vring_desc_flags(hwaddr desc_pa, int i)
A
aliguori 已提交
118
{
A
Avi Kivity 已提交
119
    hwaddr pa;
120
    pa = desc_pa + sizeof(VRingDesc) * i + offsetof(VRingDesc, flags);
A
aliguori 已提交
121 122 123
    return lduw_phys(pa);
}

A
Avi Kivity 已提交
124
static inline uint16_t vring_desc_next(hwaddr desc_pa, int i)
A
aliguori 已提交
125
{
A
Avi Kivity 已提交
126
    hwaddr pa;
127
    pa = desc_pa + sizeof(VRingDesc) * i + offsetof(VRingDesc, next);
A
aliguori 已提交
128 129 130 131 132
    return lduw_phys(pa);
}

static inline uint16_t vring_avail_flags(VirtQueue *vq)
{
A
Avi Kivity 已提交
133
    hwaddr pa;
A
aliguori 已提交
134 135 136 137 138 139
    pa = vq->vring.avail + offsetof(VRingAvail, flags);
    return lduw_phys(pa);
}

static inline uint16_t vring_avail_idx(VirtQueue *vq)
{
A
Avi Kivity 已提交
140
    hwaddr pa;
A
aliguori 已提交
141 142 143 144 145 146
    pa = vq->vring.avail + offsetof(VRingAvail, idx);
    return lduw_phys(pa);
}

static inline uint16_t vring_avail_ring(VirtQueue *vq, int i)
{
A
Avi Kivity 已提交
147
    hwaddr pa;
A
aliguori 已提交
148 149 150 151
    pa = vq->vring.avail + offsetof(VRingAvail, ring[i]);
    return lduw_phys(pa);
}

M
Michael S. Tsirkin 已提交
152 153 154 155 156
static inline uint16_t vring_used_event(VirtQueue *vq)
{
    return vring_avail_ring(vq, vq->vring.num);
}

A
aliguori 已提交
157 158
static inline void vring_used_ring_id(VirtQueue *vq, int i, uint32_t val)
{
A
Avi Kivity 已提交
159
    hwaddr pa;
A
aliguori 已提交
160 161 162 163 164 165
    pa = vq->vring.used + offsetof(VRingUsed, ring[i].id);
    stl_phys(pa, val);
}

static inline void vring_used_ring_len(VirtQueue *vq, int i, uint32_t val)
{
A
Avi Kivity 已提交
166
    hwaddr pa;
A
aliguori 已提交
167 168 169 170 171 172
    pa = vq->vring.used + offsetof(VRingUsed, ring[i].len);
    stl_phys(pa, val);
}

static uint16_t vring_used_idx(VirtQueue *vq)
{
A
Avi Kivity 已提交
173
    hwaddr pa;
A
aliguori 已提交
174 175 176 177
    pa = vq->vring.used + offsetof(VRingUsed, idx);
    return lduw_phys(pa);
}

M
Michael S. Tsirkin 已提交
178
static inline void vring_used_idx_set(VirtQueue *vq, uint16_t val)
A
aliguori 已提交
179
{
A
Avi Kivity 已提交
180
    hwaddr pa;
A
aliguori 已提交
181
    pa = vq->vring.used + offsetof(VRingUsed, idx);
M
Michael S. Tsirkin 已提交
182
    stw_phys(pa, val);
A
aliguori 已提交
183 184 185 186
}

static inline void vring_used_flags_set_bit(VirtQueue *vq, int mask)
{
A
Avi Kivity 已提交
187
    hwaddr pa;
A
aliguori 已提交
188 189 190 191 192 193
    pa = vq->vring.used + offsetof(VRingUsed, flags);
    stw_phys(pa, lduw_phys(pa) | mask);
}

static inline void vring_used_flags_unset_bit(VirtQueue *vq, int mask)
{
A
Avi Kivity 已提交
194
    hwaddr pa;
A
aliguori 已提交
195 196 197 198
    pa = vq->vring.used + offsetof(VRingUsed, flags);
    stw_phys(pa, lduw_phys(pa) & ~mask);
}

M
Michael S. Tsirkin 已提交
199 200
static inline void vring_avail_event(VirtQueue *vq, uint16_t val)
{
A
Avi Kivity 已提交
201
    hwaddr pa;
M
Michael S. Tsirkin 已提交
202 203 204 205 206 207 208
    if (!vq->notification) {
        return;
    }
    pa = vq->vring.used + offsetof(VRingUsed, ring[vq->vring.num]);
    stw_phys(pa, val);
}

A
aliguori 已提交
209 210
void virtio_queue_set_notification(VirtQueue *vq, int enable)
{
M
Michael S. Tsirkin 已提交
211 212 213 214
    vq->notification = enable;
    if (vq->vdev->guest_features & (1 << VIRTIO_RING_F_EVENT_IDX)) {
        vring_avail_event(vq, vring_avail_idx(vq));
    } else if (enable) {
A
aliguori 已提交
215
        vring_used_flags_unset_bit(vq, VRING_USED_F_NO_NOTIFY);
M
Michael S. Tsirkin 已提交
216
    } else {
A
aliguori 已提交
217
        vring_used_flags_set_bit(vq, VRING_USED_F_NO_NOTIFY);
M
Michael S. Tsirkin 已提交
218
    }
219 220 221 222
    if (enable) {
        /* Expose avail event/used flags before caller checks the avail idx. */
        smp_mb();
    }
A
aliguori 已提交
223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240
}

int virtio_queue_ready(VirtQueue *vq)
{
    return vq->vring.avail != 0;
}

int virtio_queue_empty(VirtQueue *vq)
{
    return vring_avail_idx(vq) == vq->last_avail_idx;
}

void virtqueue_fill(VirtQueue *vq, const VirtQueueElement *elem,
                    unsigned int len, unsigned int idx)
{
    unsigned int offset;
    int i;

241 242
    trace_virtqueue_fill(vq, elem, len, idx);

A
aliguori 已提交
243 244 245 246
    offset = 0;
    for (i = 0; i < elem->in_num; i++) {
        size_t size = MIN(len - offset, elem->in_sg[i].iov_len);

247 248 249
        cpu_physical_memory_unmap(elem->in_sg[i].iov_base,
                                  elem->in_sg[i].iov_len,
                                  1, size);
A
aliguori 已提交
250

251
        offset += size;
A
aliguori 已提交
252 253
    }

254 255 256 257 258
    for (i = 0; i < elem->out_num; i++)
        cpu_physical_memory_unmap(elem->out_sg[i].iov_base,
                                  elem->out_sg[i].iov_len,
                                  0, elem->out_sg[i].iov_len);

A
aliguori 已提交
259 260 261 262 263 264 265 266 267
    idx = (idx + vring_used_idx(vq)) % vq->vring.num;

    /* Get a pointer to the next entry in the used ring. */
    vring_used_ring_id(vq, idx, elem->index);
    vring_used_ring_len(vq, idx, len);
}

void virtqueue_flush(VirtQueue *vq, unsigned int count)
{
M
Michael S. Tsirkin 已提交
268
    uint16_t old, new;
A
aliguori 已提交
269
    /* Make sure buffer is written before we update index. */
270
    smp_wmb();
271
    trace_virtqueue_flush(vq, count);
M
Michael S. Tsirkin 已提交
272 273 274
    old = vring_used_idx(vq);
    new = old + count;
    vring_used_idx_set(vq, new);
A
aliguori 已提交
275
    vq->inuse -= count;
M
Michael S. Tsirkin 已提交
276 277
    if (unlikely((int16_t)(new - vq->signalled_used) < (uint16_t)(new - old)))
        vq->signalled_used_valid = false;
A
aliguori 已提交
278 279 280 281 282 283 284 285 286 287 288 289 290 291
}

void virtqueue_push(VirtQueue *vq, const VirtQueueElement *elem,
                    unsigned int len)
{
    virtqueue_fill(vq, elem, len, 0);
    virtqueue_flush(vq, 1);
}

static int virtqueue_num_heads(VirtQueue *vq, unsigned int idx)
{
    uint16_t num_heads = vring_avail_idx(vq) - idx;

    /* Check it isn't doing very strange things with descriptor numbers. */
A
aliguori 已提交
292
    if (num_heads > vq->vring.num) {
293 294
        error_report("Guest moved used index from %u to %u",
                     idx, vring_avail_idx(vq));
A
aliguori 已提交
295 296
        exit(1);
    }
297 298 299 300 301
    /* On success, callers read a descriptor at vq->last_avail_idx.
     * Make sure descriptor read does not bypass avail index read. */
    if (num_heads) {
        smp_rmb();
    }
A
aliguori 已提交
302 303 304 305 306 307 308 309 310 311 312 313 314

    return num_heads;
}

static unsigned int virtqueue_get_head(VirtQueue *vq, unsigned int idx)
{
    unsigned int head;

    /* Grab the next descriptor number they're advertising, and increment
     * the index we've seen. */
    head = vring_avail_ring(vq, idx % vq->vring.num);

    /* If their number is silly, that's a fatal mistake. */
A
aliguori 已提交
315
    if (head >= vq->vring.num) {
316
        error_report("Guest says index %u is available", head);
A
aliguori 已提交
317 318
        exit(1);
    }
A
aliguori 已提交
319 320 321 322

    return head;
}

A
Avi Kivity 已提交
323
static unsigned virtqueue_next_desc(hwaddr desc_pa,
324
                                    unsigned int i, unsigned int max)
A
aliguori 已提交
325 326 327 328
{
    unsigned int next;

    /* If this descriptor says it doesn't chain, we're done. */
329 330
    if (!(vring_desc_flags(desc_pa, i) & VRING_DESC_F_NEXT))
        return max;
A
aliguori 已提交
331 332

    /* Check they're not leading us off end of descriptors. */
333
    next = vring_desc_next(desc_pa, i);
A
aliguori 已提交
334
    /* Make sure compiler knows to grab that: we don't want it changing! */
335
    smp_wmb();
A
aliguori 已提交
336

337
    if (next >= max) {
338
        error_report("Desc next is %u", next);
A
aliguori 已提交
339 340
        exit(1);
    }
A
aliguori 已提交
341 342 343 344

    return next;
}

345
void virtqueue_get_avail_bytes(VirtQueue *vq, unsigned int *in_bytes,
346 347
                               unsigned int *out_bytes,
                               unsigned max_in_bytes, unsigned max_out_bytes)
A
aliguori 已提交
348
{
349
    unsigned int idx;
350
    unsigned int total_bufs, in_total, out_total;
A
aliguori 已提交
351 352 353

    idx = vq->last_avail_idx;

354
    total_bufs = in_total = out_total = 0;
A
aliguori 已提交
355
    while (virtqueue_num_heads(vq, idx)) {
356
        unsigned int max, num_bufs, indirect = 0;
A
Avi Kivity 已提交
357
        hwaddr desc_pa;
A
aliguori 已提交
358 359
        int i;

360 361
        max = vq->vring.num;
        num_bufs = total_bufs;
A
aliguori 已提交
362
        i = virtqueue_get_head(vq, idx++);
363 364 365 366
        desc_pa = vq->vring.desc;

        if (vring_desc_flags(desc_pa, i) & VRING_DESC_F_INDIRECT) {
            if (vring_desc_len(desc_pa, i) % sizeof(VRingDesc)) {
367
                error_report("Invalid size for indirect buffer table");
368 369 370 371 372
                exit(1);
            }

            /* If we've got too many, that implies a descriptor loop. */
            if (num_bufs >= max) {
373
                error_report("Looped descriptor");
374 375 376 377 378 379 380
                exit(1);
            }

            /* loop over the indirect descriptor table */
            indirect = 1;
            max = vring_desc_len(desc_pa, i) / sizeof(VRingDesc);
            desc_pa = vring_desc_addr(desc_pa, i);
381
            num_bufs = i = 0;
382 383
        }

A
aliguori 已提交
384 385
        do {
            /* If we've got too many, that implies a descriptor loop. */
386
            if (++num_bufs > max) {
387
                error_report("Looped descriptor");
A
aliguori 已提交
388 389
                exit(1);
            }
A
aliguori 已提交
390

391
            if (vring_desc_flags(desc_pa, i) & VRING_DESC_F_WRITE) {
392
                in_total += vring_desc_len(desc_pa, i);
A
aliguori 已提交
393
            } else {
394
                out_total += vring_desc_len(desc_pa, i);
A
aliguori 已提交
395
            }
396 397 398
            if (in_total >= max_in_bytes && out_total >= max_out_bytes) {
                goto done;
            }
399
        } while ((i = virtqueue_next_desc(desc_pa, i, max)) != max);
400 401 402 403 404

        if (!indirect)
            total_bufs = num_bufs;
        else
            total_bufs++;
A
aliguori 已提交
405
    }
406
done:
407 408 409 410 411 412 413
    if (in_bytes) {
        *in_bytes = in_total;
    }
    if (out_bytes) {
        *out_bytes = out_total;
    }
}
A
aliguori 已提交
414

415 416 417 418 419
int virtqueue_avail_bytes(VirtQueue *vq, unsigned int in_bytes,
                          unsigned int out_bytes)
{
    unsigned int in_total, out_total;

420 421
    virtqueue_get_avail_bytes(vq, &in_total, &out_total, in_bytes, out_bytes);
    return in_bytes <= in_total && out_bytes <= out_total;
A
aliguori 已提交
422 423
}

A
Avi Kivity 已提交
424
void virtqueue_map_sg(struct iovec *sg, hwaddr *addr,
K
Kevin Wolf 已提交
425 426 427
    size_t num_sg, int is_write)
{
    unsigned int i;
A
Avi Kivity 已提交
428
    hwaddr len;
K
Kevin Wolf 已提交
429 430 431 432 433

    for (i = 0; i < num_sg; i++) {
        len = sg[i].iov_len;
        sg[i].iov_base = cpu_physical_memory_map(addr[i], &len, is_write);
        if (sg[i].iov_base == NULL || len != sg[i].iov_len) {
434
            error_report("virtio: trying to map MMIO memory");
K
Kevin Wolf 已提交
435 436 437 438 439
            exit(1);
        }
    }
}

A
aliguori 已提交
440 441
int virtqueue_pop(VirtQueue *vq, VirtQueueElement *elem)
{
442
    unsigned int i, head, max;
A
Avi Kivity 已提交
443
    hwaddr desc_pa = vq->vring.desc;
A
aliguori 已提交
444 445 446 447 448 449 450

    if (!virtqueue_num_heads(vq, vq->last_avail_idx))
        return 0;

    /* When we start there are none of either input nor output. */
    elem->out_num = elem->in_num = 0;

451 452
    max = vq->vring.num;

A
aliguori 已提交
453
    i = head = virtqueue_get_head(vq, vq->last_avail_idx++);
M
Michael S. Tsirkin 已提交
454 455 456
    if (vq->vdev->guest_features & (1 << VIRTIO_RING_F_EVENT_IDX)) {
        vring_avail_event(vq, vring_avail_idx(vq));
    }
457 458 459

    if (vring_desc_flags(desc_pa, i) & VRING_DESC_F_INDIRECT) {
        if (vring_desc_len(desc_pa, i) % sizeof(VRingDesc)) {
460
            error_report("Invalid size for indirect buffer table");
461 462 463 464 465 466 467 468 469
            exit(1);
        }

        /* loop over the indirect descriptor table */
        max = vring_desc_len(desc_pa, i) / sizeof(VRingDesc);
        desc_pa = vring_desc_addr(desc_pa, i);
        i = 0;
    }

K
Kevin Wolf 已提交
470
    /* Collect all the descriptors */
A
aliguori 已提交
471 472 473
    do {
        struct iovec *sg;

474
        if (vring_desc_flags(desc_pa, i) & VRING_DESC_F_WRITE) {
475 476 477 478
            if (elem->in_num >= ARRAY_SIZE(elem->in_sg)) {
                error_report("Too many write descriptors in indirect table");
                exit(1);
            }
479
            elem->in_addr[elem->in_num] = vring_desc_addr(desc_pa, i);
A
aliguori 已提交
480
            sg = &elem->in_sg[elem->in_num++];
K
Kevin Wolf 已提交
481
        } else {
482 483 484 485
            if (elem->out_num >= ARRAY_SIZE(elem->out_sg)) {
                error_report("Too many read descriptors in indirect table");
                exit(1);
            }
K
Kevin Wolf 已提交
486
            elem->out_addr[elem->out_num] = vring_desc_addr(desc_pa, i);
A
aliguori 已提交
487
            sg = &elem->out_sg[elem->out_num++];
K
Kevin Wolf 已提交
488
        }
A
aliguori 已提交
489

490
        sg->iov_len = vring_desc_len(desc_pa, i);
A
aliguori 已提交
491 492

        /* If we've got too many, that implies a descriptor loop. */
493
        if ((elem->in_num + elem->out_num) > max) {
494
            error_report("Looped descriptor");
A
aliguori 已提交
495 496
            exit(1);
        }
497
    } while ((i = virtqueue_next_desc(desc_pa, i, max)) != max);
A
aliguori 已提交
498

K
Kevin Wolf 已提交
499 500 501 502
    /* Now map what we have collected */
    virtqueue_map_sg(elem->in_sg, elem->in_addr, elem->in_num, 1);
    virtqueue_map_sg(elem->out_sg, elem->out_addr, elem->out_num, 0);

A
aliguori 已提交
503 504 505 506
    elem->index = head;

    vq->inuse++;

507
    trace_virtqueue_pop(vq, elem, elem->in_num, elem->out_num);
A
aliguori 已提交
508 509 510 511
    return elem->in_num + elem->out_num;
}

/* virtio device */
512 513
static void virtio_notify_vector(VirtIODevice *vdev, uint16_t vector)
{
K
KONRAD Frederic 已提交
514 515 516 517 518
    BusState *qbus = qdev_get_parent_bus(DEVICE(vdev));
    VirtioBusClass *k = VIRTIO_BUS_GET_CLASS(qbus);

    if (k->notify) {
        k->notify(qbus->parent, vector);
519 520
    }
}
A
aliguori 已提交
521

P
Paul Brook 已提交
522
void virtio_update_irq(VirtIODevice *vdev)
A
aliguori 已提交
523
{
524
    virtio_notify_vector(vdev, VIRTIO_NO_VECTOR);
A
aliguori 已提交
525 526
}

527 528
void virtio_set_status(VirtIODevice *vdev, uint8_t val)
{
529
    VirtioDeviceClass *k = VIRTIO_DEVICE_GET_CLASS(vdev);
530 531
    trace_virtio_set_status(vdev, val);

532 533
    if (k->set_status) {
        k->set_status(vdev, val);
534 535 536 537
    }
    vdev->status = val;
}

P
Paul Brook 已提交
538
void virtio_reset(void *opaque)
A
aliguori 已提交
539 540
{
    VirtIODevice *vdev = opaque;
541
    VirtioDeviceClass *k = VIRTIO_DEVICE_GET_CLASS(vdev);
A
aliguori 已提交
542 543
    int i;

544 545
    virtio_set_status(vdev, 0);

546 547 548
    if (k->reset) {
        k->reset(vdev);
    }
A
aliguori 已提交
549

550
    vdev->guest_features = 0;
A
aliguori 已提交
551 552 553
    vdev->queue_sel = 0;
    vdev->status = 0;
    vdev->isr = 0;
554 555
    vdev->config_vector = VIRTIO_NO_VECTOR;
    virtio_notify_vector(vdev, vdev->config_vector);
A
aliguori 已提交
556 557 558 559 560 561

    for(i = 0; i < VIRTIO_PCI_QUEUE_MAX; i++) {
        vdev->vq[i].vring.desc = 0;
        vdev->vq[i].vring.avail = 0;
        vdev->vq[i].vring.used = 0;
        vdev->vq[i].last_avail_idx = 0;
P
Paul Brook 已提交
562
        vdev->vq[i].pa = 0;
563
        vdev->vq[i].vector = VIRTIO_NO_VECTOR;
M
Michael S. Tsirkin 已提交
564 565 566
        vdev->vq[i].signalled_used = 0;
        vdev->vq[i].signalled_used_valid = false;
        vdev->vq[i].notification = true;
A
aliguori 已提交
567 568 569
    }
}

P
Paul Brook 已提交
570
uint32_t virtio_config_readb(VirtIODevice *vdev, uint32_t addr)
A
aliguori 已提交
571
{
572
    VirtioDeviceClass *k = VIRTIO_DEVICE_GET_CLASS(vdev);
A
aliguori 已提交
573 574
    uint8_t val;

575
    if (addr + sizeof(val) > vdev->config_len) {
A
aliguori 已提交
576
        return (uint32_t)-1;
577 578 579
    }

    k->get_config(vdev, vdev->config);
A
aliguori 已提交
580

581
    val = ldub_p(vdev->config + addr);
A
aliguori 已提交
582 583 584
    return val;
}

P
Paul Brook 已提交
585
uint32_t virtio_config_readw(VirtIODevice *vdev, uint32_t addr)
A
aliguori 已提交
586
{
587
    VirtioDeviceClass *k = VIRTIO_DEVICE_GET_CLASS(vdev);
A
aliguori 已提交
588 589
    uint16_t val;

590
    if (addr + sizeof(val) > vdev->config_len) {
A
aliguori 已提交
591
        return (uint32_t)-1;
592 593 594
    }

    k->get_config(vdev, vdev->config);
A
aliguori 已提交
595

596
    val = lduw_p(vdev->config + addr);
A
aliguori 已提交
597 598 599
    return val;
}

P
Paul Brook 已提交
600
uint32_t virtio_config_readl(VirtIODevice *vdev, uint32_t addr)
A
aliguori 已提交
601
{
602
    VirtioDeviceClass *k = VIRTIO_DEVICE_GET_CLASS(vdev);
A
aliguori 已提交
603 604
    uint32_t val;

605
    if (addr + sizeof(val) > vdev->config_len) {
A
aliguori 已提交
606
        return (uint32_t)-1;
607 608 609
    }

    k->get_config(vdev, vdev->config);
A
aliguori 已提交
610

611
    val = ldl_p(vdev->config + addr);
A
aliguori 已提交
612 613 614
    return val;
}

P
Paul Brook 已提交
615
void virtio_config_writeb(VirtIODevice *vdev, uint32_t addr, uint32_t data)
A
aliguori 已提交
616
{
617
    VirtioDeviceClass *k = VIRTIO_DEVICE_GET_CLASS(vdev);
A
aliguori 已提交
618 619
    uint8_t val = data;

620
    if (addr + sizeof(val) > vdev->config_len) {
A
aliguori 已提交
621
        return;
622
    }
A
aliguori 已提交
623

624
    stb_p(vdev->config + addr, val);
A
aliguori 已提交
625

626 627 628
    if (k->set_config) {
        k->set_config(vdev, vdev->config);
    }
A
aliguori 已提交
629 630
}

P
Paul Brook 已提交
631
void virtio_config_writew(VirtIODevice *vdev, uint32_t addr, uint32_t data)
A
aliguori 已提交
632
{
633
    VirtioDeviceClass *k = VIRTIO_DEVICE_GET_CLASS(vdev);
A
aliguori 已提交
634 635
    uint16_t val = data;

636
    if (addr + sizeof(val) > vdev->config_len) {
A
aliguori 已提交
637
        return;
638
    }
A
aliguori 已提交
639

640
    stw_p(vdev->config + addr, val);
A
aliguori 已提交
641

642 643 644
    if (k->set_config) {
        k->set_config(vdev, vdev->config);
    }
A
aliguori 已提交
645 646
}

P
Paul Brook 已提交
647
void virtio_config_writel(VirtIODevice *vdev, uint32_t addr, uint32_t data)
A
aliguori 已提交
648
{
649
    VirtioDeviceClass *k = VIRTIO_DEVICE_GET_CLASS(vdev);
A
aliguori 已提交
650 651
    uint32_t val = data;

652
    if (addr + sizeof(val) > vdev->config_len) {
A
aliguori 已提交
653
        return;
654
    }
A
aliguori 已提交
655

656
    stl_p(vdev->config + addr, val);
A
aliguori 已提交
657

658 659 660
    if (k->set_config) {
        k->set_config(vdev, vdev->config);
    }
A
aliguori 已提交
661 662
}

A
Avi Kivity 已提交
663
void virtio_queue_set_addr(VirtIODevice *vdev, int n, hwaddr addr)
A
aliguori 已提交
664
{
665 666
    vdev->vq[n].pa = addr;
    virtqueue_init(&vdev->vq[n]);
P
Paul Brook 已提交
667 668
}

A
Avi Kivity 已提交
669
hwaddr virtio_queue_get_addr(VirtIODevice *vdev, int n)
P
Paul Brook 已提交
670 671 672 673
{
    return vdev->vq[n].pa;
}

674 675
void virtio_queue_set_num(VirtIODevice *vdev, int n, int num)
{
676 677 678 679 680 681 682
    /* Don't allow guest to flip queue between existent and
     * nonexistent states, or to set it to an invalid size.
     */
    if (!!num != !!vdev->vq[n].vring.num ||
        num > VIRTQUEUE_MAX_SIZE ||
        num < 0) {
        return;
683
    }
684 685
    vdev->vq[n].vring.num = num;
    virtqueue_init(&vdev->vq[n]);
686 687
}

P
Paul Brook 已提交
688 689 690 691
int virtio_queue_get_num(VirtIODevice *vdev, int n)
{
    return vdev->vq[n].vring.num;
}
A
aliguori 已提交
692

P
Paolo Bonzini 已提交
693 694 695 696 697 698 699
int virtio_queue_get_id(VirtQueue *vq)
{
    VirtIODevice *vdev = vq->vdev;
    assert(vq >= &vdev->vq[0] && vq < &vdev->vq[VIRTIO_PCI_QUEUE_MAX]);
    return vq - &vdev->vq[0];
}

700 701 702 703 704 705 706 707 708 709 710 711 712 713 714
void virtio_queue_set_align(VirtIODevice *vdev, int n, int align)
{
    BusState *qbus = qdev_get_parent_bus(DEVICE(vdev));
    VirtioBusClass *k = VIRTIO_BUS_GET_CLASS(qbus);

    /* Check that the transport told us it was going to do this
     * (so a buggy transport will immediately assert rather than
     * silently failing to migrate this state)
     */
    assert(k->has_variable_vring_alignment);

    vdev->vq[n].vring.align = align;
    virtqueue_init(&vdev->vq[n]);
}

715 716 717 718 719 720 721 722 723
void virtio_queue_notify_vq(VirtQueue *vq)
{
    if (vq->vring.desc) {
        VirtIODevice *vdev = vq->vdev;
        trace_virtio_queue_notify(vdev, vq - vdev->vq, vq);
        vq->handle_output(vdev, vq);
    }
}

P
Paul Brook 已提交
724 725
void virtio_queue_notify(VirtIODevice *vdev, int n)
{
726
    virtio_queue_notify_vq(&vdev->vq[n]);
A
aliguori 已提交
727 728
}

729 730 731 732 733 734 735 736 737 738 739 740
uint16_t virtio_queue_vector(VirtIODevice *vdev, int n)
{
    return n < VIRTIO_PCI_QUEUE_MAX ? vdev->vq[n].vector :
        VIRTIO_NO_VECTOR;
}

void virtio_queue_set_vector(VirtIODevice *vdev, int n, uint16_t vector)
{
    if (n < VIRTIO_PCI_QUEUE_MAX)
        vdev->vq[n].vector = vector;
}

A
aliguori 已提交
741 742 743 744 745 746 747 748 749 750 751 752 753 754
VirtQueue *virtio_add_queue(VirtIODevice *vdev, int queue_size,
                            void (*handle_output)(VirtIODevice *, VirtQueue *))
{
    int i;

    for (i = 0; i < VIRTIO_PCI_QUEUE_MAX; i++) {
        if (vdev->vq[i].vring.num == 0)
            break;
    }

    if (i == VIRTIO_PCI_QUEUE_MAX || queue_size > VIRTQUEUE_MAX_SIZE)
        abort();

    vdev->vq[i].vring.num = queue_size;
755
    vdev->vq[i].vring.align = VIRTIO_PCI_VRING_ALIGN;
A
aliguori 已提交
756 757 758 759 760
    vdev->vq[i].handle_output = handle_output;

    return &vdev->vq[i];
}

761 762 763 764 765 766 767 768 769
void virtio_del_queue(VirtIODevice *vdev, int n)
{
    if (n < 0 || n >= VIRTIO_PCI_QUEUE_MAX) {
        abort();
    }

    vdev->vq[n].vring.num = 0;
}

770 771
void virtio_irq(VirtQueue *vq)
{
772
    trace_virtio_irq(vq);
773 774 775 776
    vq->vdev->isr |= 0x01;
    virtio_notify_vector(vq->vdev, vq->vector);
}

M
Michael S. Tsirkin 已提交
777 778 779 780
/* Assuming a given event_idx value from the other size, if
 * we have just incremented index from old to new_idx,
 * should we trigger an event? */
static inline int vring_need_event(uint16_t event, uint16_t new, uint16_t old)
A
aliguori 已提交
781
{
M
Michael S. Tsirkin 已提交
782 783 784 785 786 787 788 789 790 791 792 793
	/* Note: Xen has similar logic for notification hold-off
	 * in include/xen/interface/io/ring.h with req_event and req_prod
	 * corresponding to event_idx + 1 and new respectively.
	 * Note also that req_event and req_prod in Xen start at 1,
	 * event indexes in virtio start at 0. */
	return (uint16_t)(new - event - 1) < (uint16_t)(new - old);
}

static bool vring_notify(VirtIODevice *vdev, VirtQueue *vq)
{
    uint16_t old, new;
    bool v;
794 795
    /* We need to expose used array entries before checking used event. */
    smp_mb();
796
    /* Always notify when queue is empty (when feature acknowledge) */
M
Michael S. Tsirkin 已提交
797 798 799 800 801 802 803 804 805 806 807 808 809 810 811 812 813 814 815
    if (((vdev->guest_features & (1 << VIRTIO_F_NOTIFY_ON_EMPTY)) &&
         !vq->inuse && vring_avail_idx(vq) == vq->last_avail_idx)) {
        return true;
    }

    if (!(vdev->guest_features & (1 << VIRTIO_RING_F_EVENT_IDX))) {
        return !(vring_avail_flags(vq) & VRING_AVAIL_F_NO_INTERRUPT);
    }

    v = vq->signalled_used_valid;
    vq->signalled_used_valid = true;
    old = vq->signalled_used;
    new = vq->signalled_used = vring_used_idx(vq);
    return !v || vring_need_event(vring_used_event(vq), new, old);
}

void virtio_notify(VirtIODevice *vdev, VirtQueue *vq)
{
    if (!vring_notify(vdev, vq)) {
A
aliguori 已提交
816
        return;
M
Michael S. Tsirkin 已提交
817
    }
A
aliguori 已提交
818

819
    trace_virtio_notify(vdev, vq);
A
aliguori 已提交
820
    vdev->isr |= 0x01;
821
    virtio_notify_vector(vdev, vq->vector);
A
aliguori 已提交
822 823 824 825
}

void virtio_notify_config(VirtIODevice *vdev)
{
826 827 828
    if (!(vdev->status & VIRTIO_CONFIG_S_DRIVER_OK))
        return;

A
aliguori 已提交
829
    vdev->isr |= 0x03;
830
    virtio_notify_vector(vdev, vdev->config_vector);
A
aliguori 已提交
831 832 833 834
}

void virtio_save(VirtIODevice *vdev, QEMUFile *f)
{
K
KONRAD Frederic 已提交
835 836
    BusState *qbus = qdev_get_parent_bus(DEVICE(vdev));
    VirtioBusClass *k = VIRTIO_BUS_GET_CLASS(qbus);
A
aliguori 已提交
837 838
    int i;

K
KONRAD Frederic 已提交
839 840 841
    if (k->save_config) {
        k->save_config(qbus->parent, f);
    }
A
aliguori 已提交
842 843 844 845

    qemu_put_8s(f, &vdev->status);
    qemu_put_8s(f, &vdev->isr);
    qemu_put_be16s(f, &vdev->queue_sel);
846
    qemu_put_be32s(f, &vdev->guest_features);
A
aliguori 已提交
847 848 849 850 851 852 853 854 855 856 857 858 859 860 861
    qemu_put_be32(f, vdev->config_len);
    qemu_put_buffer(f, vdev->config, vdev->config_len);

    for (i = 0; i < VIRTIO_PCI_QUEUE_MAX; i++) {
        if (vdev->vq[i].vring.num == 0)
            break;
    }

    qemu_put_be32(f, i);

    for (i = 0; i < VIRTIO_PCI_QUEUE_MAX; i++) {
        if (vdev->vq[i].vring.num == 0)
            break;

        qemu_put_be32(f, vdev->vq[i].vring.num);
862 863 864
        if (k->has_variable_vring_alignment) {
            qemu_put_be32(f, vdev->vq[i].vring.align);
        }
P
Paul Brook 已提交
865
        qemu_put_be64(f, vdev->vq[i].pa);
A
aliguori 已提交
866
        qemu_put_be16s(f, &vdev->vq[i].last_avail_idx);
K
KONRAD Frederic 已提交
867 868 869
        if (k->save_queue) {
            k->save_queue(qbus->parent, i, f);
        }
A
aliguori 已提交
870 871 872
    }
}

873 874
int virtio_set_features(VirtIODevice *vdev, uint32_t val)
{
K
KONRAD Frederic 已提交
875 876
    BusState *qbus = qdev_get_parent_bus(DEVICE(vdev));
    VirtioBusClass *vbusk = VIRTIO_BUS_GET_CLASS(qbus);
877
    VirtioDeviceClass *k = VIRTIO_DEVICE_GET_CLASS(vdev);
K
KONRAD Frederic 已提交
878
    uint32_t supported_features = vbusk->get_features(qbus->parent);
879 880 881
    bool bad = (val & ~supported_features) != 0;

    val &= supported_features;
882 883
    if (k->set_features) {
        k->set_features(vdev, val);
884 885 886 887 888
    }
    vdev->guest_features = val;
    return bad ? -1 : 0;
}

889
int virtio_load(VirtIODevice *vdev, QEMUFile *f)
A
aliguori 已提交
890
{
891
    int num, i, ret;
892
    uint32_t features;
893
    uint32_t supported_features;
K
KONRAD Frederic 已提交
894 895
    BusState *qbus = qdev_get_parent_bus(DEVICE(vdev));
    VirtioBusClass *k = VIRTIO_BUS_GET_CLASS(qbus);
A
aliguori 已提交
896

K
KONRAD Frederic 已提交
897 898
    if (k->load_config) {
        ret = k->load_config(qbus->parent, f);
899 900 901
        if (ret)
            return ret;
    }
A
aliguori 已提交
902 903 904 905

    qemu_get_8s(f, &vdev->status);
    qemu_get_8s(f, &vdev->isr);
    qemu_get_be16s(f, &vdev->queue_sel);
906
    qemu_get_be32s(f, &features);
907 908

    if (virtio_set_features(vdev, features) < 0) {
K
KONRAD Frederic 已提交
909
        supported_features = k->get_features(qbus->parent);
910 911
        error_report("Features 0x%x unsupported. Allowed features: 0x%x",
                     features, supported_features);
912 913
        return -1;
    }
A
aliguori 已提交
914 915 916 917 918 919 920
    vdev->config_len = qemu_get_be32(f);
    qemu_get_buffer(f, vdev->config, vdev->config_len);

    num = qemu_get_be32(f);

    for (i = 0; i < num; i++) {
        vdev->vq[i].vring.num = qemu_get_be32(f);
921 922 923
        if (k->has_variable_vring_alignment) {
            vdev->vq[i].vring.align = qemu_get_be32(f);
        }
P
Paul Brook 已提交
924
        vdev->vq[i].pa = qemu_get_be64(f);
A
aliguori 已提交
925
        qemu_get_be16s(f, &vdev->vq[i].last_avail_idx);
M
Michael S. Tsirkin 已提交
926 927
        vdev->vq[i].signalled_used_valid = false;
        vdev->vq[i].notification = true;
A
aliguori 已提交
928

P
Paul Brook 已提交
929
        if (vdev->vq[i].pa) {
M
Michael S. Tsirkin 已提交
930
            uint16_t nheads;
P
Paul Brook 已提交
931
            virtqueue_init(&vdev->vq[i]);
M
Michael S. Tsirkin 已提交
932 933 934 935
            nheads = vring_avail_idx(&vdev->vq[i]) - vdev->vq[i].last_avail_idx;
            /* Check it isn't doing very strange things with descriptor numbers. */
            if (nheads > vdev->vq[i].vring.num) {
                error_report("VQ %d size 0x%x Guest index 0x%x "
936
                             "inconsistent with Host index 0x%x: delta 0x%x",
M
Michael S. Tsirkin 已提交
937 938 939 940 941 942 943
                             i, vdev->vq[i].vring.num,
                             vring_avail_idx(&vdev->vq[i]),
                             vdev->vq[i].last_avail_idx, nheads);
                return -1;
            }
        } else if (vdev->vq[i].last_avail_idx) {
            error_report("VQ %d address 0x0 "
944
                         "inconsistent with Host index 0x%x",
M
Michael S. Tsirkin 已提交
945 946
                         i, vdev->vq[i].last_avail_idx);
                return -1;
947
	}
K
KONRAD Frederic 已提交
948 949
        if (k->load_queue) {
            ret = k->load_queue(qbus->parent, i, f);
950 951
            if (ret)
                return ret;
952
        }
A
aliguori 已提交
953 954
    }

955
    virtio_notify_vector(vdev, VIRTIO_NO_VECTOR);
956
    return 0;
A
aliguori 已提交
957 958
}

959
void virtio_cleanup(VirtIODevice *vdev)
960
{
961
    qemu_del_vm_change_state_handler(vdev->vmstate);
962
    g_free(vdev->config);
963
    g_free(vdev->vq);
964 965
}

966
static void virtio_vmstate_change(void *opaque, int running, RunState state)
967 968
{
    VirtIODevice *vdev = opaque;
K
KONRAD Frederic 已提交
969 970
    BusState *qbus = qdev_get_parent_bus(DEVICE(vdev));
    VirtioBusClass *k = VIRTIO_BUS_GET_CLASS(qbus);
971 972 973 974 975 976 977
    bool backend_run = running && (vdev->status & VIRTIO_CONFIG_S_DRIVER_OK);
    vdev->vm_running = running;

    if (backend_run) {
        virtio_set_status(vdev, vdev->status);
    }

K
KONRAD Frederic 已提交
978 979
    if (k->vmstate_change) {
        k->vmstate_change(qbus->parent, backend_run);
980 981 982 983 984 985 986
    }

    if (!backend_run) {
        virtio_set_status(vdev, vdev->status);
    }
}

987 988
void virtio_init(VirtIODevice *vdev, const char *name,
                 uint16_t device_id, size_t config_size)
A
aliguori 已提交
989
{
990
    int i;
P
Paul Brook 已提交
991
    vdev->device_id = device_id;
A
aliguori 已提交
992 993 994
    vdev->status = 0;
    vdev->isr = 0;
    vdev->queue_sel = 0;
995
    vdev->config_vector = VIRTIO_NO_VECTOR;
996
    vdev->vq = g_malloc0(sizeof(VirtQueue) * VIRTIO_PCI_QUEUE_MAX);
997
    vdev->vm_running = runstate_is_running();
998
    for (i = 0; i < VIRTIO_PCI_QUEUE_MAX; i++) {
999
        vdev->vq[i].vector = VIRTIO_NO_VECTOR;
1000
        vdev->vq[i].vdev = vdev;
1001
        vdev->vq[i].queue_index = i;
1002
    }
A
aliguori 已提交
1003 1004 1005

    vdev->name = name;
    vdev->config_len = config_size;
1006
    if (vdev->config_len) {
1007
        vdev->config = g_malloc0(config_size);
1008
    } else {
A
aliguori 已提交
1009
        vdev->config = NULL;
1010 1011 1012 1013
    }
    vdev->vmstate = qemu_add_vm_change_state_handler(virtio_vmstate_change,
                                                     vdev);
}
A
aliguori 已提交
1014

A
Avi Kivity 已提交
1015
hwaddr virtio_queue_get_desc_addr(VirtIODevice *vdev, int n)
1016 1017 1018 1019
{
    return vdev->vq[n].vring.desc;
}

A
Avi Kivity 已提交
1020
hwaddr virtio_queue_get_avail_addr(VirtIODevice *vdev, int n)
1021 1022 1023 1024
{
    return vdev->vq[n].vring.avail;
}

A
Avi Kivity 已提交
1025
hwaddr virtio_queue_get_used_addr(VirtIODevice *vdev, int n)
1026 1027 1028 1029
{
    return vdev->vq[n].vring.used;
}

A
Avi Kivity 已提交
1030
hwaddr virtio_queue_get_ring_addr(VirtIODevice *vdev, int n)
1031 1032 1033 1034
{
    return vdev->vq[n].vring.desc;
}

A
Avi Kivity 已提交
1035
hwaddr virtio_queue_get_desc_size(VirtIODevice *vdev, int n)
1036 1037 1038 1039
{
    return sizeof(VRingDesc) * vdev->vq[n].vring.num;
}

A
Avi Kivity 已提交
1040
hwaddr virtio_queue_get_avail_size(VirtIODevice *vdev, int n)
1041 1042
{
    return offsetof(VRingAvail, ring) +
1043
        sizeof(uint64_t) * vdev->vq[n].vring.num;
1044 1045
}

A
Avi Kivity 已提交
1046
hwaddr virtio_queue_get_used_size(VirtIODevice *vdev, int n)
1047 1048 1049 1050 1051
{
    return offsetof(VRingUsed, ring) +
        sizeof(VRingUsedElem) * vdev->vq[n].vring.num;
}

A
Avi Kivity 已提交
1052
hwaddr virtio_queue_get_ring_size(VirtIODevice *vdev, int n)
1053 1054 1055 1056 1057 1058 1059 1060 1061 1062 1063 1064 1065 1066 1067
{
    return vdev->vq[n].vring.used - vdev->vq[n].vring.desc +
	    virtio_queue_get_used_size(vdev, n);
}

uint16_t virtio_queue_get_last_avail_idx(VirtIODevice *vdev, int n)
{
    return vdev->vq[n].last_avail_idx;
}

void virtio_queue_set_last_avail_idx(VirtIODevice *vdev, int n, uint16_t idx)
{
    vdev->vq[n].last_avail_idx = idx;
}

1068 1069 1070 1071 1072
void virtio_queue_invalidate_signalled_used(VirtIODevice *vdev, int n)
{
    vdev->vq[n].signalled_used_valid = false;
}

1073 1074 1075 1076 1077
VirtQueue *virtio_get_queue(VirtIODevice *vdev, int n)
{
    return vdev->vq + n;
}

1078 1079 1080 1081 1082
uint16_t virtio_get_queue_index(VirtQueue *vq)
{
    return vq->queue_index;
}

1083 1084 1085 1086 1087 1088 1089 1090 1091 1092 1093 1094 1095 1096 1097 1098 1099 1100 1101 1102 1103 1104 1105 1106
static void virtio_queue_guest_notifier_read(EventNotifier *n)
{
    VirtQueue *vq = container_of(n, VirtQueue, guest_notifier);
    if (event_notifier_test_and_clear(n)) {
        virtio_irq(vq);
    }
}

void virtio_queue_set_guest_notifier_fd_handler(VirtQueue *vq, bool assign,
                                                bool with_irqfd)
{
    if (assign && !with_irqfd) {
        event_notifier_set_handler(&vq->guest_notifier,
                                   virtio_queue_guest_notifier_read);
    } else {
        event_notifier_set_handler(&vq->guest_notifier, NULL);
    }
    if (!assign) {
        /* Test and clear notifier before closing it,
         * in case poll callback didn't have time to run. */
        virtio_queue_guest_notifier_read(&vq->guest_notifier);
    }
}

1107 1108 1109 1110
EventNotifier *virtio_queue_get_guest_notifier(VirtQueue *vq)
{
    return &vq->guest_notifier;
}
1111 1112 1113 1114 1115 1116 1117 1118 1119

static void virtio_queue_host_notifier_read(EventNotifier *n)
{
    VirtQueue *vq = container_of(n, VirtQueue, host_notifier);
    if (event_notifier_test_and_clear(n)) {
        virtio_queue_notify_vq(vq);
    }
}

P
Paolo Bonzini 已提交
1120 1121
void virtio_queue_set_host_notifier_fd_handler(VirtQueue *vq, bool assign,
                                               bool set_handler)
1122
{
P
Paolo Bonzini 已提交
1123
    if (assign && set_handler) {
1124 1125 1126 1127
        event_notifier_set_handler(&vq->host_notifier,
                                   virtio_queue_host_notifier_read);
    } else {
        event_notifier_set_handler(&vq->host_notifier, NULL);
P
Paolo Bonzini 已提交
1128 1129
    }
    if (!assign) {
1130 1131 1132 1133 1134 1135
        /* Test and clear notifier before after disabling event,
         * in case poll callback didn't have time to run. */
        virtio_queue_host_notifier_read(&vq->host_notifier);
    }
}

1136 1137 1138 1139
EventNotifier *virtio_queue_get_host_notifier(VirtQueue *vq)
{
    return &vq->host_notifier;
}
1140

1141 1142 1143 1144 1145 1146 1147 1148 1149 1150 1151 1152
void virtio_device_set_child_bus_name(VirtIODevice *vdev, char *bus_name)
{
    if (vdev->bus_name) {
        g_free(vdev->bus_name);
        vdev->bus_name = NULL;
    }

    if (bus_name) {
        vdev->bus_name = g_strdup(bus_name);
    }
}

1153 1154 1155 1156 1157 1158 1159 1160 1161 1162 1163 1164
static void virtio_device_realize(DeviceState *dev, Error **errp)
{
    VirtIODevice *vdev = VIRTIO_DEVICE(dev);
    VirtioDeviceClass *vdc = VIRTIO_DEVICE_GET_CLASS(dev);
    Error *err = NULL;

    if (vdc->realize != NULL) {
        vdc->realize(dev, &err);
        if (err != NULL) {
            error_propagate(errp, err);
            return;
        }
1165
    }
1166
    virtio_bus_device_plugged(vdev);
1167 1168
}

1169
static void virtio_device_unrealize(DeviceState *dev, Error **errp)
1170
{
1171
    VirtIODevice *vdev = VIRTIO_DEVICE(dev);
1172 1173
    VirtioDeviceClass *vdc = VIRTIO_DEVICE_GET_CLASS(dev);
    Error *err = NULL;
1174

1175 1176
    virtio_bus_device_unplugged(vdev);

1177 1178 1179 1180 1181 1182
    if (vdc->unrealize != NULL) {
        vdc->unrealize(dev, &err);
        if (err != NULL) {
            error_propagate(errp, err);
            return;
        }
1183
    }
1184

1185 1186 1187 1188 1189 1190
    if (vdev->bus_name) {
        g_free(vdev->bus_name);
        vdev->bus_name = NULL;
    }
}

1191 1192 1193 1194
static void virtio_device_class_init(ObjectClass *klass, void *data)
{
    /* Set the default value here. */
    DeviceClass *dc = DEVICE_CLASS(klass);
1195 1196 1197

    dc->realize = virtio_device_realize;
    dc->unrealize = virtio_device_unrealize;
1198 1199 1200 1201 1202 1203 1204 1205 1206 1207 1208 1209 1210 1211 1212 1213 1214 1215
    dc->bus_type = TYPE_VIRTIO_BUS;
}

static const TypeInfo virtio_device_info = {
    .name = TYPE_VIRTIO_DEVICE,
    .parent = TYPE_DEVICE,
    .instance_size = sizeof(VirtIODevice),
    .class_init = virtio_device_class_init,
    .abstract = true,
    .class_size = sizeof(VirtioDeviceClass),
};

static void virtio_register_types(void)
{
    type_register_static(&virtio_device_info);
}

type_init(virtio_register_types)