xref: /qemu/hw/virtio/virtio-pci.c (revision b8f059081d93f1802480059d1d49fe5c1d32f60c)
153c25ceaSPaul Brook /*
253c25ceaSPaul Brook  * Virtio PCI Bindings
353c25ceaSPaul Brook  *
453c25ceaSPaul Brook  * Copyright IBM, Corp. 2007
553c25ceaSPaul Brook  * Copyright (c) 2009 CodeSourcery
653c25ceaSPaul Brook  *
753c25ceaSPaul Brook  * Authors:
853c25ceaSPaul Brook  *  Anthony Liguori   <aliguori@us.ibm.com>
953c25ceaSPaul Brook  *  Paul Brook        <paul@codesourcery.com>
1053c25ceaSPaul Brook  *
1153c25ceaSPaul Brook  * This work is licensed under the terms of the GNU GPL, version 2.  See
1253c25ceaSPaul Brook  * the COPYING file in the top-level directory.
1353c25ceaSPaul Brook  *
146b620ca3SPaolo Bonzini  * Contributions after 2012-01-13 are licensed under the terms of the
156b620ca3SPaolo Bonzini  * GNU GPL, version 2 or (at your option) any later version.
1653c25ceaSPaul Brook  */
1753c25ceaSPaul Brook 
1853c25ceaSPaul Brook #include <inttypes.h>
1953c25ceaSPaul Brook 
20cbbe4f50SMichael S. Tsirkin #include "standard-headers/linux/virtio_pci.h"
210d09e41aSPaolo Bonzini #include "hw/virtio/virtio.h"
220d09e41aSPaolo Bonzini #include "hw/virtio/virtio-blk.h"
230d09e41aSPaolo Bonzini #include "hw/virtio/virtio-net.h"
240d09e41aSPaolo Bonzini #include "hw/virtio/virtio-serial.h"
250d09e41aSPaolo Bonzini #include "hw/virtio/virtio-scsi.h"
260d09e41aSPaolo Bonzini #include "hw/virtio/virtio-balloon.h"
2783c9f4caSPaolo Bonzini #include "hw/pci/pci.h"
281de7afc9SPaolo Bonzini #include "qemu/error-report.h"
2983c9f4caSPaolo Bonzini #include "hw/pci/msi.h"
3083c9f4caSPaolo Bonzini #include "hw/pci/msix.h"
3183c9f4caSPaolo Bonzini #include "hw/loader.h"
329c17d615SPaolo Bonzini #include "sysemu/kvm.h"
334be74634SMarkus Armbruster #include "sysemu/block-backend.h"
3447b43a1fSPaolo Bonzini #include "virtio-pci.h"
351de7afc9SPaolo Bonzini #include "qemu/range.h"
360d09e41aSPaolo Bonzini #include "hw/virtio/virtio-bus.h"
3724a6e7f4SKONRAD Frederic #include "qapi/visitor.h"
3853c25ceaSPaul Brook 
39cbbe4f50SMichael S. Tsirkin #define VIRTIO_PCI_REGION_SIZE(dev)     VIRTIO_PCI_CONFIG_OFF(msix_present(dev))
40aba800a3SMichael S. Tsirkin 
41c17bef33SMichael S. Tsirkin #undef VIRTIO_PCI_CONFIG
42c17bef33SMichael S. Tsirkin 
43aba800a3SMichael S. Tsirkin /* The remaining space is defined by each driver as the per-driver
44aba800a3SMichael S. Tsirkin  * configuration space */
45cbbe4f50SMichael S. Tsirkin #define VIRTIO_PCI_CONFIG_SIZE(dev)     VIRTIO_PCI_CONFIG_OFF(msix_enabled(dev))
4653c25ceaSPaul Brook 
47ac7af112SAndreas Färber static void virtio_pci_bus_new(VirtioBusState *bus, size_t bus_size,
48ac7af112SAndreas Färber                                VirtIOPCIProxy *dev);
49d51fcfacSKONRAD Frederic 
5053c25ceaSPaul Brook /* virtio device */
51d2a0ccc6SMichael S. Tsirkin /* DeviceState to VirtIOPCIProxy. For use off data-path. TODO: use QOM. */
52d2a0ccc6SMichael S. Tsirkin static inline VirtIOPCIProxy *to_virtio_pci_proxy(DeviceState *d)
5353c25ceaSPaul Brook {
54d2a0ccc6SMichael S. Tsirkin     return container_of(d, VirtIOPCIProxy, pci_dev.qdev);
55d2a0ccc6SMichael S. Tsirkin }
56d2a0ccc6SMichael S. Tsirkin 
57d2a0ccc6SMichael S. Tsirkin /* DeviceState to VirtIOPCIProxy. Note: used on datapath,
58d2a0ccc6SMichael S. Tsirkin  * be careful and test performance if you change this.
59d2a0ccc6SMichael S. Tsirkin  */
60d2a0ccc6SMichael S. Tsirkin static inline VirtIOPCIProxy *to_virtio_pci_proxy_fast(DeviceState *d)
61d2a0ccc6SMichael S. Tsirkin {
62d2a0ccc6SMichael S. Tsirkin     return container_of(d, VirtIOPCIProxy, pci_dev.qdev);
63d2a0ccc6SMichael S. Tsirkin }
64d2a0ccc6SMichael S. Tsirkin 
65d2a0ccc6SMichael S. Tsirkin static void virtio_pci_notify(DeviceState *d, uint16_t vector)
66d2a0ccc6SMichael S. Tsirkin {
67d2a0ccc6SMichael S. Tsirkin     VirtIOPCIProxy *proxy = to_virtio_pci_proxy_fast(d);
68a3fc66d9SPaolo Bonzini 
69aba800a3SMichael S. Tsirkin     if (msix_enabled(&proxy->pci_dev))
70aba800a3SMichael S. Tsirkin         msix_notify(&proxy->pci_dev, vector);
71a3fc66d9SPaolo Bonzini     else {
72a3fc66d9SPaolo Bonzini         VirtIODevice *vdev = virtio_bus_get_device(&proxy->bus);
73a3fc66d9SPaolo Bonzini         pci_set_irq(&proxy->pci_dev, vdev->isr & 1);
74a3fc66d9SPaolo Bonzini     }
7553c25ceaSPaul Brook }
7653c25ceaSPaul Brook 
77d2a0ccc6SMichael S. Tsirkin static void virtio_pci_save_config(DeviceState *d, QEMUFile *f)
78ff24bd58SMichael S. Tsirkin {
79d2a0ccc6SMichael S. Tsirkin     VirtIOPCIProxy *proxy = to_virtio_pci_proxy(d);
80a3fc66d9SPaolo Bonzini     VirtIODevice *vdev = virtio_bus_get_device(&proxy->bus);
81a3fc66d9SPaolo Bonzini 
82ff24bd58SMichael S. Tsirkin     pci_device_save(&proxy->pci_dev, f);
83ff24bd58SMichael S. Tsirkin     msix_save(&proxy->pci_dev, f);
84ff24bd58SMichael S. Tsirkin     if (msix_present(&proxy->pci_dev))
85a3fc66d9SPaolo Bonzini         qemu_put_be16(f, vdev->config_vector);
86ff24bd58SMichael S. Tsirkin }
87ff24bd58SMichael S. Tsirkin 
88d2a0ccc6SMichael S. Tsirkin static void virtio_pci_save_queue(DeviceState *d, int n, QEMUFile *f)
89ff24bd58SMichael S. Tsirkin {
90d2a0ccc6SMichael S. Tsirkin     VirtIOPCIProxy *proxy = to_virtio_pci_proxy(d);
91a3fc66d9SPaolo Bonzini     VirtIODevice *vdev = virtio_bus_get_device(&proxy->bus);
92a3fc66d9SPaolo Bonzini 
93ff24bd58SMichael S. Tsirkin     if (msix_present(&proxy->pci_dev))
94a3fc66d9SPaolo Bonzini         qemu_put_be16(f, virtio_queue_vector(vdev, n));
95ff24bd58SMichael S. Tsirkin }
96ff24bd58SMichael S. Tsirkin 
97d2a0ccc6SMichael S. Tsirkin static int virtio_pci_load_config(DeviceState *d, QEMUFile *f)
98ff24bd58SMichael S. Tsirkin {
99d2a0ccc6SMichael S. Tsirkin     VirtIOPCIProxy *proxy = to_virtio_pci_proxy(d);
100a3fc66d9SPaolo Bonzini     VirtIODevice *vdev = virtio_bus_get_device(&proxy->bus);
101a3fc66d9SPaolo Bonzini 
102ff24bd58SMichael S. Tsirkin     int ret;
103ff24bd58SMichael S. Tsirkin     ret = pci_device_load(&proxy->pci_dev, f);
104e6da7680SMichael S. Tsirkin     if (ret) {
105ff24bd58SMichael S. Tsirkin         return ret;
106e6da7680SMichael S. Tsirkin     }
1073cac001eSMichael S. Tsirkin     msix_unuse_all_vectors(&proxy->pci_dev);
108ff24bd58SMichael S. Tsirkin     msix_load(&proxy->pci_dev, f);
109e6da7680SMichael S. Tsirkin     if (msix_present(&proxy->pci_dev)) {
110a3fc66d9SPaolo Bonzini         qemu_get_be16s(f, &vdev->config_vector);
111e6da7680SMichael S. Tsirkin     } else {
112a3fc66d9SPaolo Bonzini         vdev->config_vector = VIRTIO_NO_VECTOR;
113e6da7680SMichael S. Tsirkin     }
114a3fc66d9SPaolo Bonzini     if (vdev->config_vector != VIRTIO_NO_VECTOR) {
115a3fc66d9SPaolo Bonzini         return msix_vector_use(&proxy->pci_dev, vdev->config_vector);
116e6da7680SMichael S. Tsirkin     }
117ff24bd58SMichael S. Tsirkin     return 0;
118ff24bd58SMichael S. Tsirkin }
119ff24bd58SMichael S. Tsirkin 
120d2a0ccc6SMichael S. Tsirkin static int virtio_pci_load_queue(DeviceState *d, int n, QEMUFile *f)
121ff24bd58SMichael S. Tsirkin {
122d2a0ccc6SMichael S. Tsirkin     VirtIOPCIProxy *proxy = to_virtio_pci_proxy(d);
123a3fc66d9SPaolo Bonzini     VirtIODevice *vdev = virtio_bus_get_device(&proxy->bus);
124a3fc66d9SPaolo Bonzini 
125ff24bd58SMichael S. Tsirkin     uint16_t vector;
126e6da7680SMichael S. Tsirkin     if (msix_present(&proxy->pci_dev)) {
127ff24bd58SMichael S. Tsirkin         qemu_get_be16s(f, &vector);
128e6da7680SMichael S. Tsirkin     } else {
129e6da7680SMichael S. Tsirkin         vector = VIRTIO_NO_VECTOR;
130e6da7680SMichael S. Tsirkin     }
131a3fc66d9SPaolo Bonzini     virtio_queue_set_vector(vdev, n, vector);
132e6da7680SMichael S. Tsirkin     if (vector != VIRTIO_NO_VECTOR) {
133e6da7680SMichael S. Tsirkin         return msix_vector_use(&proxy->pci_dev, vector);
134e6da7680SMichael S. Tsirkin     }
135ff24bd58SMichael S. Tsirkin     return 0;
136ff24bd58SMichael S. Tsirkin }
137ff24bd58SMichael S. Tsirkin 
13825db9ebeSStefan Hajnoczi static int virtio_pci_set_host_notifier_internal(VirtIOPCIProxy *proxy,
13926b9b5feSPaolo Bonzini                                                  int n, bool assign, bool set_handler)
14025db9ebeSStefan Hajnoczi {
141a3fc66d9SPaolo Bonzini     VirtIODevice *vdev = virtio_bus_get_device(&proxy->bus);
142a3fc66d9SPaolo Bonzini     VirtQueue *vq = virtio_get_queue(vdev, n);
14325db9ebeSStefan Hajnoczi     EventNotifier *notifier = virtio_queue_get_host_notifier(vq);
144da146d0aSAvi Kivity     int r = 0;
145da146d0aSAvi Kivity 
14625db9ebeSStefan Hajnoczi     if (assign) {
14725db9ebeSStefan Hajnoczi         r = event_notifier_init(notifier, 1);
14825db9ebeSStefan Hajnoczi         if (r < 0) {
149b36e3914SMichael S. Tsirkin             error_report("%s: unable to init event notifier: %d",
150b36e3914SMichael S. Tsirkin                          __func__, r);
15125db9ebeSStefan Hajnoczi             return r;
15225db9ebeSStefan Hajnoczi         }
15326b9b5feSPaolo Bonzini         virtio_queue_set_host_notifier_fd_handler(vq, true, set_handler);
154da146d0aSAvi Kivity         memory_region_add_eventfd(&proxy->bar, VIRTIO_PCI_QUEUE_NOTIFY, 2,
155753d5e14SPaolo Bonzini                                   true, n, notifier);
15625db9ebeSStefan Hajnoczi     } else {
157da146d0aSAvi Kivity         memory_region_del_eventfd(&proxy->bar, VIRTIO_PCI_QUEUE_NOTIFY, 2,
158753d5e14SPaolo Bonzini                                   true, n, notifier);
15926b9b5feSPaolo Bonzini         virtio_queue_set_host_notifier_fd_handler(vq, false, false);
16025db9ebeSStefan Hajnoczi         event_notifier_cleanup(notifier);
16125db9ebeSStefan Hajnoczi     }
16225db9ebeSStefan Hajnoczi     return r;
16325db9ebeSStefan Hajnoczi }
16425db9ebeSStefan Hajnoczi 
165b36e3914SMichael S. Tsirkin static void virtio_pci_start_ioeventfd(VirtIOPCIProxy *proxy)
16625db9ebeSStefan Hajnoczi {
167a3fc66d9SPaolo Bonzini     VirtIODevice *vdev = virtio_bus_get_device(&proxy->bus);
16825db9ebeSStefan Hajnoczi     int n, r;
16925db9ebeSStefan Hajnoczi 
17025db9ebeSStefan Hajnoczi     if (!(proxy->flags & VIRTIO_PCI_FLAG_USE_IOEVENTFD) ||
17125db9ebeSStefan Hajnoczi         proxy->ioeventfd_disabled ||
17225db9ebeSStefan Hajnoczi         proxy->ioeventfd_started) {
173b36e3914SMichael S. Tsirkin         return;
17425db9ebeSStefan Hajnoczi     }
17525db9ebeSStefan Hajnoczi 
17687b3bd1cSJason Wang     for (n = 0; n < VIRTIO_QUEUE_MAX; n++) {
177a3fc66d9SPaolo Bonzini         if (!virtio_queue_get_num(vdev, n)) {
17825db9ebeSStefan Hajnoczi             continue;
17925db9ebeSStefan Hajnoczi         }
18025db9ebeSStefan Hajnoczi 
18126b9b5feSPaolo Bonzini         r = virtio_pci_set_host_notifier_internal(proxy, n, true, true);
18225db9ebeSStefan Hajnoczi         if (r < 0) {
18325db9ebeSStefan Hajnoczi             goto assign_error;
18425db9ebeSStefan Hajnoczi         }
18525db9ebeSStefan Hajnoczi     }
18625db9ebeSStefan Hajnoczi     proxy->ioeventfd_started = true;
187b36e3914SMichael S. Tsirkin     return;
18825db9ebeSStefan Hajnoczi 
18925db9ebeSStefan Hajnoczi assign_error:
19025db9ebeSStefan Hajnoczi     while (--n >= 0) {
191a3fc66d9SPaolo Bonzini         if (!virtio_queue_get_num(vdev, n)) {
19225db9ebeSStefan Hajnoczi             continue;
19325db9ebeSStefan Hajnoczi         }
19425db9ebeSStefan Hajnoczi 
19526b9b5feSPaolo Bonzini         r = virtio_pci_set_host_notifier_internal(proxy, n, false, false);
196b36e3914SMichael S. Tsirkin         assert(r >= 0);
19725db9ebeSStefan Hajnoczi     }
19825db9ebeSStefan Hajnoczi     proxy->ioeventfd_started = false;
199b36e3914SMichael S. Tsirkin     error_report("%s: failed. Fallback to a userspace (slower).", __func__);
20025db9ebeSStefan Hajnoczi }
20125db9ebeSStefan Hajnoczi 
202b36e3914SMichael S. Tsirkin static void virtio_pci_stop_ioeventfd(VirtIOPCIProxy *proxy)
20325db9ebeSStefan Hajnoczi {
204a3fc66d9SPaolo Bonzini     VirtIODevice *vdev = virtio_bus_get_device(&proxy->bus);
205b36e3914SMichael S. Tsirkin     int r;
20625db9ebeSStefan Hajnoczi     int n;
20725db9ebeSStefan Hajnoczi 
20825db9ebeSStefan Hajnoczi     if (!proxy->ioeventfd_started) {
209b36e3914SMichael S. Tsirkin         return;
21025db9ebeSStefan Hajnoczi     }
21125db9ebeSStefan Hajnoczi 
21287b3bd1cSJason Wang     for (n = 0; n < VIRTIO_QUEUE_MAX; n++) {
213a3fc66d9SPaolo Bonzini         if (!virtio_queue_get_num(vdev, n)) {
21425db9ebeSStefan Hajnoczi             continue;
21525db9ebeSStefan Hajnoczi         }
21625db9ebeSStefan Hajnoczi 
21726b9b5feSPaolo Bonzini         r = virtio_pci_set_host_notifier_internal(proxy, n, false, false);
218b36e3914SMichael S. Tsirkin         assert(r >= 0);
21925db9ebeSStefan Hajnoczi     }
22025db9ebeSStefan Hajnoczi     proxy->ioeventfd_started = false;
22125db9ebeSStefan Hajnoczi }
22225db9ebeSStefan Hajnoczi 
22353c25ceaSPaul Brook static void virtio_ioport_write(void *opaque, uint32_t addr, uint32_t val)
22453c25ceaSPaul Brook {
22553c25ceaSPaul Brook     VirtIOPCIProxy *proxy = opaque;
226a3fc66d9SPaolo Bonzini     VirtIODevice *vdev = virtio_bus_get_device(&proxy->bus);
227a8170e5eSAvi Kivity     hwaddr pa;
22853c25ceaSPaul Brook 
22953c25ceaSPaul Brook     switch (addr) {
23053c25ceaSPaul Brook     case VIRTIO_PCI_GUEST_FEATURES:
23153c25ceaSPaul Brook         /* Guest does not negotiate properly?  We have to assume nothing. */
23253c25ceaSPaul Brook         if (val & (1 << VIRTIO_F_BAD_FEATURE)) {
233181103cdSKONRAD Frederic             val = virtio_bus_get_vdev_bad_features(&proxy->bus);
23453c25ceaSPaul Brook         }
235ad0c9332SPaolo Bonzini         virtio_set_features(vdev, val);
23653c25ceaSPaul Brook         break;
23753c25ceaSPaul Brook     case VIRTIO_PCI_QUEUE_PFN:
238a8170e5eSAvi Kivity         pa = (hwaddr)val << VIRTIO_PCI_QUEUE_ADDR_SHIFT;
2391b8e9b27SMichael S. Tsirkin         if (pa == 0) {
24025db9ebeSStefan Hajnoczi             virtio_pci_stop_ioeventfd(proxy);
241a3fc66d9SPaolo Bonzini             virtio_reset(vdev);
2421b8e9b27SMichael S. Tsirkin             msix_unuse_all_vectors(&proxy->pci_dev);
2431b8e9b27SMichael S. Tsirkin         }
2447055e687SMichael S. Tsirkin         else
24553c25ceaSPaul Brook             virtio_queue_set_addr(vdev, vdev->queue_sel, pa);
24653c25ceaSPaul Brook         break;
24753c25ceaSPaul Brook     case VIRTIO_PCI_QUEUE_SEL:
24887b3bd1cSJason Wang         if (val < VIRTIO_QUEUE_MAX)
24953c25ceaSPaul Brook             vdev->queue_sel = val;
25053c25ceaSPaul Brook         break;
25153c25ceaSPaul Brook     case VIRTIO_PCI_QUEUE_NOTIFY:
25287b3bd1cSJason Wang         if (val < VIRTIO_QUEUE_MAX) {
25353c25ceaSPaul Brook             virtio_queue_notify(vdev, val);
2547157e2e2SStefan Hajnoczi         }
25553c25ceaSPaul Brook         break;
25653c25ceaSPaul Brook     case VIRTIO_PCI_STATUS:
25725db9ebeSStefan Hajnoczi         if (!(val & VIRTIO_CONFIG_S_DRIVER_OK)) {
25825db9ebeSStefan Hajnoczi             virtio_pci_stop_ioeventfd(proxy);
25925db9ebeSStefan Hajnoczi         }
26025db9ebeSStefan Hajnoczi 
2613e607cb5SMichael S. Tsirkin         virtio_set_status(vdev, val & 0xFF);
26225db9ebeSStefan Hajnoczi 
26325db9ebeSStefan Hajnoczi         if (val & VIRTIO_CONFIG_S_DRIVER_OK) {
26425db9ebeSStefan Hajnoczi             virtio_pci_start_ioeventfd(proxy);
26525db9ebeSStefan Hajnoczi         }
26625db9ebeSStefan Hajnoczi 
2671b8e9b27SMichael S. Tsirkin         if (vdev->status == 0) {
268a3fc66d9SPaolo Bonzini             virtio_reset(vdev);
2691b8e9b27SMichael S. Tsirkin             msix_unuse_all_vectors(&proxy->pci_dev);
2701b8e9b27SMichael S. Tsirkin         }
271c81131dbSAlexander Graf 
272e43c0b2eSMichael S. Tsirkin         /* Linux before 2.6.34 drives the device without enabling
273e43c0b2eSMichael S. Tsirkin            the PCI device bus master bit. Enable it automatically
274e43c0b2eSMichael S. Tsirkin            for the guest. This is a PCI spec violation but so is
275e43c0b2eSMichael S. Tsirkin            initiating DMA with bus master bit clear. */
276e43c0b2eSMichael S. Tsirkin         if (val == (VIRTIO_CONFIG_S_ACKNOWLEDGE | VIRTIO_CONFIG_S_DRIVER)) {
277e43c0b2eSMichael S. Tsirkin             pci_default_write_config(&proxy->pci_dev, PCI_COMMAND,
278e43c0b2eSMichael S. Tsirkin                                      proxy->pci_dev.config[PCI_COMMAND] |
279e43c0b2eSMichael S. Tsirkin                                      PCI_COMMAND_MASTER, 1);
280e43c0b2eSMichael S. Tsirkin         }
28153c25ceaSPaul Brook         break;
282aba800a3SMichael S. Tsirkin     case VIRTIO_MSI_CONFIG_VECTOR:
283aba800a3SMichael S. Tsirkin         msix_vector_unuse(&proxy->pci_dev, vdev->config_vector);
284aba800a3SMichael S. Tsirkin         /* Make it possible for guest to discover an error took place. */
285aba800a3SMichael S. Tsirkin         if (msix_vector_use(&proxy->pci_dev, val) < 0)
286aba800a3SMichael S. Tsirkin             val = VIRTIO_NO_VECTOR;
287aba800a3SMichael S. Tsirkin         vdev->config_vector = val;
288aba800a3SMichael S. Tsirkin         break;
289aba800a3SMichael S. Tsirkin     case VIRTIO_MSI_QUEUE_VECTOR:
290aba800a3SMichael S. Tsirkin         msix_vector_unuse(&proxy->pci_dev,
291aba800a3SMichael S. Tsirkin                           virtio_queue_vector(vdev, vdev->queue_sel));
292aba800a3SMichael S. Tsirkin         /* Make it possible for guest to discover an error took place. */
293aba800a3SMichael S. Tsirkin         if (msix_vector_use(&proxy->pci_dev, val) < 0)
294aba800a3SMichael S. Tsirkin             val = VIRTIO_NO_VECTOR;
295aba800a3SMichael S. Tsirkin         virtio_queue_set_vector(vdev, vdev->queue_sel, val);
296aba800a3SMichael S. Tsirkin         break;
297aba800a3SMichael S. Tsirkin     default:
2984e02d460SStefan Hajnoczi         error_report("%s: unexpected address 0x%x value 0x%x",
299aba800a3SMichael S. Tsirkin                      __func__, addr, val);
300aba800a3SMichael S. Tsirkin         break;
30153c25ceaSPaul Brook     }
30253c25ceaSPaul Brook }
30353c25ceaSPaul Brook 
304aba800a3SMichael S. Tsirkin static uint32_t virtio_ioport_read(VirtIOPCIProxy *proxy, uint32_t addr)
30553c25ceaSPaul Brook {
306a3fc66d9SPaolo Bonzini     VirtIODevice *vdev = virtio_bus_get_device(&proxy->bus);
30753c25ceaSPaul Brook     uint32_t ret = 0xFFFFFFFF;
30853c25ceaSPaul Brook 
30953c25ceaSPaul Brook     switch (addr) {
31053c25ceaSPaul Brook     case VIRTIO_PCI_HOST_FEATURES:
3116b8f1020SCornelia Huck         ret = vdev->host_features;
31253c25ceaSPaul Brook         break;
31353c25ceaSPaul Brook     case VIRTIO_PCI_GUEST_FEATURES:
314704a76fcSMichael S. Tsirkin         ret = vdev->guest_features;
31553c25ceaSPaul Brook         break;
31653c25ceaSPaul Brook     case VIRTIO_PCI_QUEUE_PFN:
31753c25ceaSPaul Brook         ret = virtio_queue_get_addr(vdev, vdev->queue_sel)
31853c25ceaSPaul Brook               >> VIRTIO_PCI_QUEUE_ADDR_SHIFT;
31953c25ceaSPaul Brook         break;
32053c25ceaSPaul Brook     case VIRTIO_PCI_QUEUE_NUM:
32153c25ceaSPaul Brook         ret = virtio_queue_get_num(vdev, vdev->queue_sel);
32253c25ceaSPaul Brook         break;
32353c25ceaSPaul Brook     case VIRTIO_PCI_QUEUE_SEL:
32453c25ceaSPaul Brook         ret = vdev->queue_sel;
32553c25ceaSPaul Brook         break;
32653c25ceaSPaul Brook     case VIRTIO_PCI_STATUS:
32753c25ceaSPaul Brook         ret = vdev->status;
32853c25ceaSPaul Brook         break;
32953c25ceaSPaul Brook     case VIRTIO_PCI_ISR:
33053c25ceaSPaul Brook         /* reading from the ISR also clears it. */
33153c25ceaSPaul Brook         ret = vdev->isr;
33253c25ceaSPaul Brook         vdev->isr = 0;
3339e64f8a3SMarcel Apfelbaum         pci_irq_deassert(&proxy->pci_dev);
33453c25ceaSPaul Brook         break;
335aba800a3SMichael S. Tsirkin     case VIRTIO_MSI_CONFIG_VECTOR:
336aba800a3SMichael S. Tsirkin         ret = vdev->config_vector;
337aba800a3SMichael S. Tsirkin         break;
338aba800a3SMichael S. Tsirkin     case VIRTIO_MSI_QUEUE_VECTOR:
339aba800a3SMichael S. Tsirkin         ret = virtio_queue_vector(vdev, vdev->queue_sel);
340aba800a3SMichael S. Tsirkin         break;
34153c25ceaSPaul Brook     default:
34253c25ceaSPaul Brook         break;
34353c25ceaSPaul Brook     }
34453c25ceaSPaul Brook 
34553c25ceaSPaul Brook     return ret;
34653c25ceaSPaul Brook }
34753c25ceaSPaul Brook 
348df6db5b3SAlexander Graf static uint64_t virtio_pci_config_read(void *opaque, hwaddr addr,
349df6db5b3SAlexander Graf                                        unsigned size)
35053c25ceaSPaul Brook {
35153c25ceaSPaul Brook     VirtIOPCIProxy *proxy = opaque;
352a3fc66d9SPaolo Bonzini     VirtIODevice *vdev = virtio_bus_get_device(&proxy->bus);
353cbbe4f50SMichael S. Tsirkin     uint32_t config = VIRTIO_PCI_CONFIG_SIZE(&proxy->pci_dev);
354df6db5b3SAlexander Graf     uint64_t val = 0;
355df6db5b3SAlexander Graf     if (addr < config) {
356aba800a3SMichael S. Tsirkin         return virtio_ioport_read(proxy, addr);
35753c25ceaSPaul Brook     }
358aba800a3SMichael S. Tsirkin     addr -= config;
359df6db5b3SAlexander Graf 
360df6db5b3SAlexander Graf     switch (size) {
361df6db5b3SAlexander Graf     case 1:
362a3fc66d9SPaolo Bonzini         val = virtio_config_readb(vdev, addr);
363df6db5b3SAlexander Graf         break;
364df6db5b3SAlexander Graf     case 2:
365a3fc66d9SPaolo Bonzini         val = virtio_config_readw(vdev, addr);
366616a6552SGreg Kurz         if (virtio_is_big_endian(vdev)) {
3678e4a424bSBlue Swirl             val = bswap16(val);
3688e4a424bSBlue Swirl         }
369df6db5b3SAlexander Graf         break;
370df6db5b3SAlexander Graf     case 4:
371a3fc66d9SPaolo Bonzini         val = virtio_config_readl(vdev, addr);
372616a6552SGreg Kurz         if (virtio_is_big_endian(vdev)) {
3738e4a424bSBlue Swirl             val = bswap32(val);
3748e4a424bSBlue Swirl         }
375df6db5b3SAlexander Graf         break;
376df6db5b3SAlexander Graf     }
37782afa586SBenjamin Herrenschmidt     return val;
37853c25ceaSPaul Brook }
37953c25ceaSPaul Brook 
380df6db5b3SAlexander Graf static void virtio_pci_config_write(void *opaque, hwaddr addr,
381df6db5b3SAlexander Graf                                     uint64_t val, unsigned size)
38253c25ceaSPaul Brook {
38353c25ceaSPaul Brook     VirtIOPCIProxy *proxy = opaque;
384cbbe4f50SMichael S. Tsirkin     uint32_t config = VIRTIO_PCI_CONFIG_SIZE(&proxy->pci_dev);
385a3fc66d9SPaolo Bonzini     VirtIODevice *vdev = virtio_bus_get_device(&proxy->bus);
386aba800a3SMichael S. Tsirkin     if (addr < config) {
387aba800a3SMichael S. Tsirkin         virtio_ioport_write(proxy, addr, val);
388aba800a3SMichael S. Tsirkin         return;
389aba800a3SMichael S. Tsirkin     }
390aba800a3SMichael S. Tsirkin     addr -= config;
391df6db5b3SAlexander Graf     /*
392df6db5b3SAlexander Graf      * Virtio-PCI is odd. Ioports are LE but config space is target native
393df6db5b3SAlexander Graf      * endian.
394df6db5b3SAlexander Graf      */
395df6db5b3SAlexander Graf     switch (size) {
396df6db5b3SAlexander Graf     case 1:
397a3fc66d9SPaolo Bonzini         virtio_config_writeb(vdev, addr, val);
398df6db5b3SAlexander Graf         break;
399df6db5b3SAlexander Graf     case 2:
400616a6552SGreg Kurz         if (virtio_is_big_endian(vdev)) {
4018e4a424bSBlue Swirl             val = bswap16(val);
4028e4a424bSBlue Swirl         }
403a3fc66d9SPaolo Bonzini         virtio_config_writew(vdev, addr, val);
404df6db5b3SAlexander Graf         break;
405df6db5b3SAlexander Graf     case 4:
406616a6552SGreg Kurz         if (virtio_is_big_endian(vdev)) {
4078e4a424bSBlue Swirl             val = bswap32(val);
4088e4a424bSBlue Swirl         }
409a3fc66d9SPaolo Bonzini         virtio_config_writel(vdev, addr, val);
410df6db5b3SAlexander Graf         break;
411df6db5b3SAlexander Graf     }
41253c25ceaSPaul Brook }
41353c25ceaSPaul Brook 
414da146d0aSAvi Kivity static const MemoryRegionOps virtio_pci_config_ops = {
415df6db5b3SAlexander Graf     .read = virtio_pci_config_read,
416df6db5b3SAlexander Graf     .write = virtio_pci_config_write,
417df6db5b3SAlexander Graf     .impl = {
418df6db5b3SAlexander Graf         .min_access_size = 1,
419df6db5b3SAlexander Graf         .max_access_size = 4,
420df6db5b3SAlexander Graf     },
4218e4a424bSBlue Swirl     .endianness = DEVICE_LITTLE_ENDIAN,
422da146d0aSAvi Kivity };
423aba800a3SMichael S. Tsirkin 
424aba800a3SMichael S. Tsirkin static void virtio_write_config(PCIDevice *pci_dev, uint32_t address,
425aba800a3SMichael S. Tsirkin                                 uint32_t val, int len)
426aba800a3SMichael S. Tsirkin {
427ed757e14SYan Vugenfirer     VirtIOPCIProxy *proxy = DO_UPCAST(VirtIOPCIProxy, pci_dev, pci_dev);
428a3fc66d9SPaolo Bonzini     VirtIODevice *vdev = virtio_bus_get_device(&proxy->bus);
429ed757e14SYan Vugenfirer 
4301129714fSMichael S. Tsirkin     pci_default_write_config(pci_dev, address, val, len);
4311129714fSMichael S. Tsirkin 
4321129714fSMichael S. Tsirkin     if (range_covers_byte(address, len, PCI_COMMAND) &&
43368a27b20SMichael S. Tsirkin         !(pci_dev->config[PCI_COMMAND] & PCI_COMMAND_MASTER)) {
43425db9ebeSStefan Hajnoczi         virtio_pci_stop_ioeventfd(proxy);
43545363e46SMichael S. Tsirkin         virtio_set_status(vdev, vdev->status & ~VIRTIO_CONFIG_S_DRIVER_OK);
436ed757e14SYan Vugenfirer     }
43753c25ceaSPaul Brook }
43853c25ceaSPaul Brook 
4397d37d351SJan Kiszka static int kvm_virtio_pci_vq_vector_use(VirtIOPCIProxy *proxy,
4407d37d351SJan Kiszka                                         unsigned int queue_no,
4417d37d351SJan Kiszka                                         unsigned int vector,
4427d37d351SJan Kiszka                                         MSIMessage msg)
4437d37d351SJan Kiszka {
4447d37d351SJan Kiszka     VirtIOIRQFD *irqfd = &proxy->vector_irqfd[vector];
44515b2bd18SPaolo Bonzini     int ret;
4467d37d351SJan Kiszka 
4477d37d351SJan Kiszka     if (irqfd->users == 0) {
4487d37d351SJan Kiszka         ret = kvm_irqchip_add_msi_route(kvm_state, msg);
4497d37d351SJan Kiszka         if (ret < 0) {
4507d37d351SJan Kiszka             return ret;
4517d37d351SJan Kiszka         }
4527d37d351SJan Kiszka         irqfd->virq = ret;
4537d37d351SJan Kiszka     }
4547d37d351SJan Kiszka     irqfd->users++;
4557d37d351SJan Kiszka     return 0;
4567d37d351SJan Kiszka }
4577d37d351SJan Kiszka 
4587d37d351SJan Kiszka static void kvm_virtio_pci_vq_vector_release(VirtIOPCIProxy *proxy,
459774345f9SMichael S. Tsirkin                                              unsigned int vector)
460774345f9SMichael S. Tsirkin {
461774345f9SMichael S. Tsirkin     VirtIOIRQFD *irqfd = &proxy->vector_irqfd[vector];
462774345f9SMichael S. Tsirkin     if (--irqfd->users == 0) {
463774345f9SMichael S. Tsirkin         kvm_irqchip_release_virq(kvm_state, irqfd->virq);
464774345f9SMichael S. Tsirkin     }
465774345f9SMichael S. Tsirkin }
466774345f9SMichael S. Tsirkin 
467f1d0f15aSMichael S. Tsirkin static int kvm_virtio_pci_irqfd_use(VirtIOPCIProxy *proxy,
468f1d0f15aSMichael S. Tsirkin                                  unsigned int queue_no,
469f1d0f15aSMichael S. Tsirkin                                  unsigned int vector)
470f1d0f15aSMichael S. Tsirkin {
471f1d0f15aSMichael S. Tsirkin     VirtIOIRQFD *irqfd = &proxy->vector_irqfd[vector];
472a3fc66d9SPaolo Bonzini     VirtIODevice *vdev = virtio_bus_get_device(&proxy->bus);
473a3fc66d9SPaolo Bonzini     VirtQueue *vq = virtio_get_queue(vdev, queue_no);
474f1d0f15aSMichael S. Tsirkin     EventNotifier *n = virtio_queue_get_guest_notifier(vq);
475f1d0f15aSMichael S. Tsirkin     int ret;
476ca916d37SVincenzo Maffione     ret = kvm_irqchip_add_irqfd_notifier(kvm_state, n, NULL, irqfd->virq);
477f1d0f15aSMichael S. Tsirkin     return ret;
478f1d0f15aSMichael S. Tsirkin }
479f1d0f15aSMichael S. Tsirkin 
480f1d0f15aSMichael S. Tsirkin static void kvm_virtio_pci_irqfd_release(VirtIOPCIProxy *proxy,
4817d37d351SJan Kiszka                                       unsigned int queue_no,
4827d37d351SJan Kiszka                                       unsigned int vector)
4837d37d351SJan Kiszka {
484a3fc66d9SPaolo Bonzini     VirtIODevice *vdev = virtio_bus_get_device(&proxy->bus);
485a3fc66d9SPaolo Bonzini     VirtQueue *vq = virtio_get_queue(vdev, queue_no);
48615b2bd18SPaolo Bonzini     EventNotifier *n = virtio_queue_get_guest_notifier(vq);
4877d37d351SJan Kiszka     VirtIOIRQFD *irqfd = &proxy->vector_irqfd[vector];
48815b2bd18SPaolo Bonzini     int ret;
4897d37d351SJan Kiszka 
490b131c74aSJan Kiszka     ret = kvm_irqchip_remove_irqfd_notifier(kvm_state, n, irqfd->virq);
4917d37d351SJan Kiszka     assert(ret == 0);
492f1d0f15aSMichael S. Tsirkin }
4937d37d351SJan Kiszka 
494774345f9SMichael S. Tsirkin static int kvm_virtio_pci_vector_use(VirtIOPCIProxy *proxy, int nvqs)
495774345f9SMichael S. Tsirkin {
496774345f9SMichael S. Tsirkin     PCIDevice *dev = &proxy->pci_dev;
497a3fc66d9SPaolo Bonzini     VirtIODevice *vdev = virtio_bus_get_device(&proxy->bus);
498181103cdSKONRAD Frederic     VirtioDeviceClass *k = VIRTIO_DEVICE_GET_CLASS(vdev);
499774345f9SMichael S. Tsirkin     unsigned int vector;
500774345f9SMichael S. Tsirkin     int ret, queue_no;
501774345f9SMichael S. Tsirkin     MSIMessage msg;
502774345f9SMichael S. Tsirkin 
503774345f9SMichael S. Tsirkin     for (queue_no = 0; queue_no < nvqs; queue_no++) {
504774345f9SMichael S. Tsirkin         if (!virtio_queue_get_num(vdev, queue_no)) {
505774345f9SMichael S. Tsirkin             break;
506774345f9SMichael S. Tsirkin         }
507774345f9SMichael S. Tsirkin         vector = virtio_queue_vector(vdev, queue_no);
508774345f9SMichael S. Tsirkin         if (vector >= msix_nr_vectors_allocated(dev)) {
509774345f9SMichael S. Tsirkin             continue;
510774345f9SMichael S. Tsirkin         }
511774345f9SMichael S. Tsirkin         msg = msix_get_message(dev, vector);
512774345f9SMichael S. Tsirkin         ret = kvm_virtio_pci_vq_vector_use(proxy, queue_no, vector, msg);
513774345f9SMichael S. Tsirkin         if (ret < 0) {
514774345f9SMichael S. Tsirkin             goto undo;
515774345f9SMichael S. Tsirkin         }
516f1d0f15aSMichael S. Tsirkin         /* If guest supports masking, set up irqfd now.
517f1d0f15aSMichael S. Tsirkin          * Otherwise, delay until unmasked in the frontend.
518f1d0f15aSMichael S. Tsirkin          */
519181103cdSKONRAD Frederic         if (k->guest_notifier_mask) {
520f1d0f15aSMichael S. Tsirkin             ret = kvm_virtio_pci_irqfd_use(proxy, queue_no, vector);
521f1d0f15aSMichael S. Tsirkin             if (ret < 0) {
522f1d0f15aSMichael S. Tsirkin                 kvm_virtio_pci_vq_vector_release(proxy, vector);
523f1d0f15aSMichael S. Tsirkin                 goto undo;
524f1d0f15aSMichael S. Tsirkin             }
525f1d0f15aSMichael S. Tsirkin         }
526774345f9SMichael S. Tsirkin     }
527774345f9SMichael S. Tsirkin     return 0;
528774345f9SMichael S. Tsirkin 
529774345f9SMichael S. Tsirkin undo:
530774345f9SMichael S. Tsirkin     while (--queue_no >= 0) {
531774345f9SMichael S. Tsirkin         vector = virtio_queue_vector(vdev, queue_no);
532774345f9SMichael S. Tsirkin         if (vector >= msix_nr_vectors_allocated(dev)) {
533774345f9SMichael S. Tsirkin             continue;
534774345f9SMichael S. Tsirkin         }
535181103cdSKONRAD Frederic         if (k->guest_notifier_mask) {
536e387f99eSMichael S. Tsirkin             kvm_virtio_pci_irqfd_release(proxy, queue_no, vector);
537f1d0f15aSMichael S. Tsirkin         }
538774345f9SMichael S. Tsirkin         kvm_virtio_pci_vq_vector_release(proxy, vector);
539774345f9SMichael S. Tsirkin     }
540774345f9SMichael S. Tsirkin     return ret;
541774345f9SMichael S. Tsirkin }
542774345f9SMichael S. Tsirkin 
543774345f9SMichael S. Tsirkin static void kvm_virtio_pci_vector_release(VirtIOPCIProxy *proxy, int nvqs)
544774345f9SMichael S. Tsirkin {
545774345f9SMichael S. Tsirkin     PCIDevice *dev = &proxy->pci_dev;
546a3fc66d9SPaolo Bonzini     VirtIODevice *vdev = virtio_bus_get_device(&proxy->bus);
547774345f9SMichael S. Tsirkin     unsigned int vector;
548774345f9SMichael S. Tsirkin     int queue_no;
549181103cdSKONRAD Frederic     VirtioDeviceClass *k = VIRTIO_DEVICE_GET_CLASS(vdev);
550774345f9SMichael S. Tsirkin 
551774345f9SMichael S. Tsirkin     for (queue_no = 0; queue_no < nvqs; queue_no++) {
552774345f9SMichael S. Tsirkin         if (!virtio_queue_get_num(vdev, queue_no)) {
553774345f9SMichael S. Tsirkin             break;
554774345f9SMichael S. Tsirkin         }
555774345f9SMichael S. Tsirkin         vector = virtio_queue_vector(vdev, queue_no);
556774345f9SMichael S. Tsirkin         if (vector >= msix_nr_vectors_allocated(dev)) {
557774345f9SMichael S. Tsirkin             continue;
558774345f9SMichael S. Tsirkin         }
559f1d0f15aSMichael S. Tsirkin         /* If guest supports masking, clean up irqfd now.
560f1d0f15aSMichael S. Tsirkin          * Otherwise, it was cleaned when masked in the frontend.
561f1d0f15aSMichael S. Tsirkin          */
562181103cdSKONRAD Frederic         if (k->guest_notifier_mask) {
563e387f99eSMichael S. Tsirkin             kvm_virtio_pci_irqfd_release(proxy, queue_no, vector);
564f1d0f15aSMichael S. Tsirkin         }
565774345f9SMichael S. Tsirkin         kvm_virtio_pci_vq_vector_release(proxy, vector);
5667d37d351SJan Kiszka     }
5677d37d351SJan Kiszka }
5687d37d351SJan Kiszka 
569a38b2c49SMichael S. Tsirkin static int virtio_pci_vq_vector_unmask(VirtIOPCIProxy *proxy,
570774345f9SMichael S. Tsirkin                                        unsigned int queue_no,
571774345f9SMichael S. Tsirkin                                        unsigned int vector,
572774345f9SMichael S. Tsirkin                                        MSIMessage msg)
573774345f9SMichael S. Tsirkin {
574a3fc66d9SPaolo Bonzini     VirtIODevice *vdev = virtio_bus_get_device(&proxy->bus);
575a3fc66d9SPaolo Bonzini     VirtioDeviceClass *k = VIRTIO_DEVICE_GET_CLASS(vdev);
576a3fc66d9SPaolo Bonzini     VirtQueue *vq = virtio_get_queue(vdev, queue_no);
577774345f9SMichael S. Tsirkin     EventNotifier *n = virtio_queue_get_guest_notifier(vq);
578a38b2c49SMichael S. Tsirkin     VirtIOIRQFD *irqfd;
57953510bfcSMichael Roth     int ret = 0;
580774345f9SMichael S. Tsirkin 
581a38b2c49SMichael S. Tsirkin     if (proxy->vector_irqfd) {
582a38b2c49SMichael S. Tsirkin         irqfd = &proxy->vector_irqfd[vector];
583774345f9SMichael S. Tsirkin         if (irqfd->msg.data != msg.data || irqfd->msg.address != msg.address) {
584774345f9SMichael S. Tsirkin             ret = kvm_irqchip_update_msi_route(kvm_state, irqfd->virq, msg);
585774345f9SMichael S. Tsirkin             if (ret < 0) {
586774345f9SMichael S. Tsirkin                 return ret;
587774345f9SMichael S. Tsirkin             }
588774345f9SMichael S. Tsirkin         }
589a38b2c49SMichael S. Tsirkin     }
590774345f9SMichael S. Tsirkin 
591f1d0f15aSMichael S. Tsirkin     /* If guest supports masking, irqfd is already setup, unmask it.
592f1d0f15aSMichael S. Tsirkin      * Otherwise, set it up now.
593f1d0f15aSMichael S. Tsirkin      */
594181103cdSKONRAD Frederic     if (k->guest_notifier_mask) {
595a3fc66d9SPaolo Bonzini         k->guest_notifier_mask(vdev, queue_no, false);
596f1d0f15aSMichael S. Tsirkin         /* Test after unmasking to avoid losing events. */
597181103cdSKONRAD Frederic         if (k->guest_notifier_pending &&
598a3fc66d9SPaolo Bonzini             k->guest_notifier_pending(vdev, queue_no)) {
599f1d0f15aSMichael S. Tsirkin             event_notifier_set(n);
600f1d0f15aSMichael S. Tsirkin         }
601f1d0f15aSMichael S. Tsirkin     } else {
602f1d0f15aSMichael S. Tsirkin         ret = kvm_virtio_pci_irqfd_use(proxy, queue_no, vector);
603f1d0f15aSMichael S. Tsirkin     }
604774345f9SMichael S. Tsirkin     return ret;
605774345f9SMichael S. Tsirkin }
606774345f9SMichael S. Tsirkin 
607a38b2c49SMichael S. Tsirkin static void virtio_pci_vq_vector_mask(VirtIOPCIProxy *proxy,
6087d37d351SJan Kiszka                                              unsigned int queue_no,
6097d37d351SJan Kiszka                                              unsigned int vector)
6107d37d351SJan Kiszka {
611a3fc66d9SPaolo Bonzini     VirtIODevice *vdev = virtio_bus_get_device(&proxy->bus);
612a3fc66d9SPaolo Bonzini     VirtioDeviceClass *k = VIRTIO_DEVICE_GET_CLASS(vdev);
613181103cdSKONRAD Frederic 
614f1d0f15aSMichael S. Tsirkin     /* If guest supports masking, keep irqfd but mask it.
615f1d0f15aSMichael S. Tsirkin      * Otherwise, clean it up now.
616f1d0f15aSMichael S. Tsirkin      */
617181103cdSKONRAD Frederic     if (k->guest_notifier_mask) {
618a3fc66d9SPaolo Bonzini         k->guest_notifier_mask(vdev, queue_no, true);
619f1d0f15aSMichael S. Tsirkin     } else {
620e387f99eSMichael S. Tsirkin         kvm_virtio_pci_irqfd_release(proxy, queue_no, vector);
621f1d0f15aSMichael S. Tsirkin     }
6227d37d351SJan Kiszka }
6237d37d351SJan Kiszka 
624a38b2c49SMichael S. Tsirkin static int virtio_pci_vector_unmask(PCIDevice *dev, unsigned vector,
6257d37d351SJan Kiszka                                     MSIMessage msg)
6267d37d351SJan Kiszka {
6277d37d351SJan Kiszka     VirtIOPCIProxy *proxy = container_of(dev, VirtIOPCIProxy, pci_dev);
628a3fc66d9SPaolo Bonzini     VirtIODevice *vdev = virtio_bus_get_device(&proxy->bus);
629851c2a75SJason Wang     VirtQueue *vq = virtio_vector_first_queue(vdev, vector);
630851c2a75SJason Wang     int ret, index, unmasked = 0;
6317d37d351SJan Kiszka 
632851c2a75SJason Wang     while (vq) {
633851c2a75SJason Wang         index = virtio_get_queue_index(vq);
634851c2a75SJason Wang         if (!virtio_queue_get_num(vdev, index)) {
6357d37d351SJan Kiszka             break;
6367d37d351SJan Kiszka         }
6376652d081SJason Wang         if (index < proxy->nvqs_with_notifiers) {
638851c2a75SJason Wang             ret = virtio_pci_vq_vector_unmask(proxy, index, vector, msg);
6397d37d351SJan Kiszka             if (ret < 0) {
6407d37d351SJan Kiszka                 goto undo;
6417d37d351SJan Kiszka             }
642851c2a75SJason Wang             ++unmasked;
6437d37d351SJan Kiszka         }
6446652d081SJason Wang         vq = virtio_vector_next_queue(vq);
6456652d081SJason Wang     }
646851c2a75SJason Wang 
6477d37d351SJan Kiszka     return 0;
6487d37d351SJan Kiszka 
6497d37d351SJan Kiszka undo:
650851c2a75SJason Wang     vq = virtio_vector_first_queue(vdev, vector);
6516652d081SJason Wang     while (vq && unmasked >= 0) {
652851c2a75SJason Wang         index = virtio_get_queue_index(vq);
6536652d081SJason Wang         if (index < proxy->nvqs_with_notifiers) {
654851c2a75SJason Wang             virtio_pci_vq_vector_mask(proxy, index, vector);
6556652d081SJason Wang             --unmasked;
6566652d081SJason Wang         }
657851c2a75SJason Wang         vq = virtio_vector_next_queue(vq);
6587d37d351SJan Kiszka     }
6597d37d351SJan Kiszka     return ret;
6607d37d351SJan Kiszka }
6617d37d351SJan Kiszka 
662a38b2c49SMichael S. Tsirkin static void virtio_pci_vector_mask(PCIDevice *dev, unsigned vector)
6637d37d351SJan Kiszka {
6647d37d351SJan Kiszka     VirtIOPCIProxy *proxy = container_of(dev, VirtIOPCIProxy, pci_dev);
665a3fc66d9SPaolo Bonzini     VirtIODevice *vdev = virtio_bus_get_device(&proxy->bus);
666851c2a75SJason Wang     VirtQueue *vq = virtio_vector_first_queue(vdev, vector);
667851c2a75SJason Wang     int index;
6687d37d351SJan Kiszka 
669851c2a75SJason Wang     while (vq) {
670851c2a75SJason Wang         index = virtio_get_queue_index(vq);
671851c2a75SJason Wang         if (!virtio_queue_get_num(vdev, index)) {
6727d37d351SJan Kiszka             break;
6737d37d351SJan Kiszka         }
6746652d081SJason Wang         if (index < proxy->nvqs_with_notifiers) {
675851c2a75SJason Wang             virtio_pci_vq_vector_mask(proxy, index, vector);
6766652d081SJason Wang         }
677851c2a75SJason Wang         vq = virtio_vector_next_queue(vq);
6787d37d351SJan Kiszka     }
6797d37d351SJan Kiszka }
6807d37d351SJan Kiszka 
681a38b2c49SMichael S. Tsirkin static void virtio_pci_vector_poll(PCIDevice *dev,
68289d62be9SMichael S. Tsirkin                                    unsigned int vector_start,
68389d62be9SMichael S. Tsirkin                                    unsigned int vector_end)
68489d62be9SMichael S. Tsirkin {
68589d62be9SMichael S. Tsirkin     VirtIOPCIProxy *proxy = container_of(dev, VirtIOPCIProxy, pci_dev);
686a3fc66d9SPaolo Bonzini     VirtIODevice *vdev = virtio_bus_get_device(&proxy->bus);
687181103cdSKONRAD Frederic     VirtioDeviceClass *k = VIRTIO_DEVICE_GET_CLASS(vdev);
68889d62be9SMichael S. Tsirkin     int queue_no;
68989d62be9SMichael S. Tsirkin     unsigned int vector;
69089d62be9SMichael S. Tsirkin     EventNotifier *notifier;
69189d62be9SMichael S. Tsirkin     VirtQueue *vq;
69289d62be9SMichael S. Tsirkin 
6932d620f59SMichael S. Tsirkin     for (queue_no = 0; queue_no < proxy->nvqs_with_notifiers; queue_no++) {
69489d62be9SMichael S. Tsirkin         if (!virtio_queue_get_num(vdev, queue_no)) {
69589d62be9SMichael S. Tsirkin             break;
69689d62be9SMichael S. Tsirkin         }
69789d62be9SMichael S. Tsirkin         vector = virtio_queue_vector(vdev, queue_no);
69889d62be9SMichael S. Tsirkin         if (vector < vector_start || vector >= vector_end ||
69989d62be9SMichael S. Tsirkin             !msix_is_masked(dev, vector)) {
70089d62be9SMichael S. Tsirkin             continue;
70189d62be9SMichael S. Tsirkin         }
70289d62be9SMichael S. Tsirkin         vq = virtio_get_queue(vdev, queue_no);
70389d62be9SMichael S. Tsirkin         notifier = virtio_queue_get_guest_notifier(vq);
704181103cdSKONRAD Frederic         if (k->guest_notifier_pending) {
705181103cdSKONRAD Frederic             if (k->guest_notifier_pending(vdev, queue_no)) {
706f1d0f15aSMichael S. Tsirkin                 msix_set_pending(dev, vector);
707f1d0f15aSMichael S. Tsirkin             }
708f1d0f15aSMichael S. Tsirkin         } else if (event_notifier_test_and_clear(notifier)) {
70989d62be9SMichael S. Tsirkin             msix_set_pending(dev, vector);
71089d62be9SMichael S. Tsirkin         }
71189d62be9SMichael S. Tsirkin     }
71289d62be9SMichael S. Tsirkin }
71389d62be9SMichael S. Tsirkin 
71489d62be9SMichael S. Tsirkin static int virtio_pci_set_guest_notifier(DeviceState *d, int n, bool assign,
71589d62be9SMichael S. Tsirkin                                          bool with_irqfd)
716ade80dc8SMichael S. Tsirkin {
717d2a0ccc6SMichael S. Tsirkin     VirtIOPCIProxy *proxy = to_virtio_pci_proxy(d);
718a3fc66d9SPaolo Bonzini     VirtIODevice *vdev = virtio_bus_get_device(&proxy->bus);
719a3fc66d9SPaolo Bonzini     VirtioDeviceClass *vdc = VIRTIO_DEVICE_GET_CLASS(vdev);
720a3fc66d9SPaolo Bonzini     VirtQueue *vq = virtio_get_queue(vdev, n);
721ade80dc8SMichael S. Tsirkin     EventNotifier *notifier = virtio_queue_get_guest_notifier(vq);
722ade80dc8SMichael S. Tsirkin 
723ade80dc8SMichael S. Tsirkin     if (assign) {
724ade80dc8SMichael S. Tsirkin         int r = event_notifier_init(notifier, 0);
725ade80dc8SMichael S. Tsirkin         if (r < 0) {
726ade80dc8SMichael S. Tsirkin             return r;
727ade80dc8SMichael S. Tsirkin         }
72889d62be9SMichael S. Tsirkin         virtio_queue_set_guest_notifier_fd_handler(vq, true, with_irqfd);
729ade80dc8SMichael S. Tsirkin     } else {
73089d62be9SMichael S. Tsirkin         virtio_queue_set_guest_notifier_fd_handler(vq, false, with_irqfd);
731ade80dc8SMichael S. Tsirkin         event_notifier_cleanup(notifier);
732ade80dc8SMichael S. Tsirkin     }
733ade80dc8SMichael S. Tsirkin 
73462c96360SMichael S. Tsirkin     if (!msix_enabled(&proxy->pci_dev) && vdc->guest_notifier_mask) {
735a3fc66d9SPaolo Bonzini         vdc->guest_notifier_mask(vdev, n, !assign);
73662c96360SMichael S. Tsirkin     }
73762c96360SMichael S. Tsirkin 
738ade80dc8SMichael S. Tsirkin     return 0;
739ade80dc8SMichael S. Tsirkin }
740ade80dc8SMichael S. Tsirkin 
741d2a0ccc6SMichael S. Tsirkin static bool virtio_pci_query_guest_notifiers(DeviceState *d)
7425430a28fSmst@redhat.com {
743d2a0ccc6SMichael S. Tsirkin     VirtIOPCIProxy *proxy = to_virtio_pci_proxy(d);
7445430a28fSmst@redhat.com     return msix_enabled(&proxy->pci_dev);
7455430a28fSmst@redhat.com }
7465430a28fSmst@redhat.com 
7472d620f59SMichael S. Tsirkin static int virtio_pci_set_guest_notifiers(DeviceState *d, int nvqs, bool assign)
74854dd9321SMichael S. Tsirkin {
749d2a0ccc6SMichael S. Tsirkin     VirtIOPCIProxy *proxy = to_virtio_pci_proxy(d);
750a3fc66d9SPaolo Bonzini     VirtIODevice *vdev = virtio_bus_get_device(&proxy->bus);
751181103cdSKONRAD Frederic     VirtioDeviceClass *k = VIRTIO_DEVICE_GET_CLASS(vdev);
75254dd9321SMichael S. Tsirkin     int r, n;
75389d62be9SMichael S. Tsirkin     bool with_irqfd = msix_enabled(&proxy->pci_dev) &&
75489d62be9SMichael S. Tsirkin         kvm_msi_via_irqfd_enabled();
75554dd9321SMichael S. Tsirkin 
75687b3bd1cSJason Wang     nvqs = MIN(nvqs, VIRTIO_QUEUE_MAX);
7572d620f59SMichael S. Tsirkin 
7582d620f59SMichael S. Tsirkin     /* When deassigning, pass a consistent nvqs value
7592d620f59SMichael S. Tsirkin      * to avoid leaking notifiers.
7602d620f59SMichael S. Tsirkin      */
7612d620f59SMichael S. Tsirkin     assert(assign || nvqs == proxy->nvqs_with_notifiers);
7622d620f59SMichael S. Tsirkin 
7632d620f59SMichael S. Tsirkin     proxy->nvqs_with_notifiers = nvqs;
7642d620f59SMichael S. Tsirkin 
7657d37d351SJan Kiszka     /* Must unset vector notifier while guest notifier is still assigned */
766181103cdSKONRAD Frederic     if ((proxy->vector_irqfd || k->guest_notifier_mask) && !assign) {
7677d37d351SJan Kiszka         msix_unset_vector_notifiers(&proxy->pci_dev);
768a38b2c49SMichael S. Tsirkin         if (proxy->vector_irqfd) {
769774345f9SMichael S. Tsirkin             kvm_virtio_pci_vector_release(proxy, nvqs);
7707d37d351SJan Kiszka             g_free(proxy->vector_irqfd);
7717d37d351SJan Kiszka             proxy->vector_irqfd = NULL;
7727d37d351SJan Kiszka         }
773a38b2c49SMichael S. Tsirkin     }
7747d37d351SJan Kiszka 
7752d620f59SMichael S. Tsirkin     for (n = 0; n < nvqs; n++) {
77654dd9321SMichael S. Tsirkin         if (!virtio_queue_get_num(vdev, n)) {
77754dd9321SMichael S. Tsirkin             break;
77854dd9321SMichael S. Tsirkin         }
77954dd9321SMichael S. Tsirkin 
78023fe2b3fSMichael S. Tsirkin         r = virtio_pci_set_guest_notifier(d, n, assign, with_irqfd);
78154dd9321SMichael S. Tsirkin         if (r < 0) {
78254dd9321SMichael S. Tsirkin             goto assign_error;
78354dd9321SMichael S. Tsirkin         }
78454dd9321SMichael S. Tsirkin     }
78554dd9321SMichael S. Tsirkin 
7867d37d351SJan Kiszka     /* Must set vector notifier after guest notifier has been assigned */
787181103cdSKONRAD Frederic     if ((with_irqfd || k->guest_notifier_mask) && assign) {
788a38b2c49SMichael S. Tsirkin         if (with_irqfd) {
7897d37d351SJan Kiszka             proxy->vector_irqfd =
7907d37d351SJan Kiszka                 g_malloc0(sizeof(*proxy->vector_irqfd) *
7917d37d351SJan Kiszka                           msix_nr_vectors_allocated(&proxy->pci_dev));
792774345f9SMichael S. Tsirkin             r = kvm_virtio_pci_vector_use(proxy, nvqs);
7937d37d351SJan Kiszka             if (r < 0) {
7947d37d351SJan Kiszka                 goto assign_error;
7957d37d351SJan Kiszka             }
796a38b2c49SMichael S. Tsirkin         }
797774345f9SMichael S. Tsirkin         r = msix_set_vector_notifiers(&proxy->pci_dev,
798a38b2c49SMichael S. Tsirkin                                       virtio_pci_vector_unmask,
799a38b2c49SMichael S. Tsirkin                                       virtio_pci_vector_mask,
800a38b2c49SMichael S. Tsirkin                                       virtio_pci_vector_poll);
801774345f9SMichael S. Tsirkin         if (r < 0) {
802774345f9SMichael S. Tsirkin             goto notifiers_error;
803774345f9SMichael S. Tsirkin         }
8047d37d351SJan Kiszka     }
8057d37d351SJan Kiszka 
80654dd9321SMichael S. Tsirkin     return 0;
80754dd9321SMichael S. Tsirkin 
808774345f9SMichael S. Tsirkin notifiers_error:
809a38b2c49SMichael S. Tsirkin     if (with_irqfd) {
810774345f9SMichael S. Tsirkin         assert(assign);
811774345f9SMichael S. Tsirkin         kvm_virtio_pci_vector_release(proxy, nvqs);
812a38b2c49SMichael S. Tsirkin     }
813774345f9SMichael S. Tsirkin 
81454dd9321SMichael S. Tsirkin assign_error:
81554dd9321SMichael S. Tsirkin     /* We get here on assignment failure. Recover by undoing for VQs 0 .. n. */
8167d37d351SJan Kiszka     assert(assign);
81754dd9321SMichael S. Tsirkin     while (--n >= 0) {
81889d62be9SMichael S. Tsirkin         virtio_pci_set_guest_notifier(d, n, !assign, with_irqfd);
81954dd9321SMichael S. Tsirkin     }
82054dd9321SMichael S. Tsirkin     return r;
82154dd9321SMichael S. Tsirkin }
82254dd9321SMichael S. Tsirkin 
823d2a0ccc6SMichael S. Tsirkin static int virtio_pci_set_host_notifier(DeviceState *d, int n, bool assign)
824ade80dc8SMichael S. Tsirkin {
825d2a0ccc6SMichael S. Tsirkin     VirtIOPCIProxy *proxy = to_virtio_pci_proxy(d);
82625db9ebeSStefan Hajnoczi 
82725db9ebeSStefan Hajnoczi     /* Stop using ioeventfd for virtqueue kick if the device starts using host
82825db9ebeSStefan Hajnoczi      * notifiers.  This makes it easy to avoid stepping on each others' toes.
82925db9ebeSStefan Hajnoczi      */
83025db9ebeSStefan Hajnoczi     proxy->ioeventfd_disabled = assign;
831ade80dc8SMichael S. Tsirkin     if (assign) {
83225db9ebeSStefan Hajnoczi         virtio_pci_stop_ioeventfd(proxy);
833ade80dc8SMichael S. Tsirkin     }
83425db9ebeSStefan Hajnoczi     /* We don't need to start here: it's not needed because backend
83525db9ebeSStefan Hajnoczi      * currently only stops on status change away from ok,
83625db9ebeSStefan Hajnoczi      * reset, vmstop and such. If we do add code to start here,
83725db9ebeSStefan Hajnoczi      * need to check vmstate, device state etc. */
83826b9b5feSPaolo Bonzini     return virtio_pci_set_host_notifier_internal(proxy, n, assign, false);
839ade80dc8SMichael S. Tsirkin }
84025db9ebeSStefan Hajnoczi 
841d2a0ccc6SMichael S. Tsirkin static void virtio_pci_vmstate_change(DeviceState *d, bool running)
84225db9ebeSStefan Hajnoczi {
843d2a0ccc6SMichael S. Tsirkin     VirtIOPCIProxy *proxy = to_virtio_pci_proxy(d);
844a3fc66d9SPaolo Bonzini     VirtIODevice *vdev = virtio_bus_get_device(&proxy->bus);
84525db9ebeSStefan Hajnoczi 
84625db9ebeSStefan Hajnoczi     if (running) {
84768a27b20SMichael S. Tsirkin         /* Old QEMU versions did not set bus master enable on status write.
84868a27b20SMichael S. Tsirkin          * Detect DRIVER set and enable it.
84968a27b20SMichael S. Tsirkin          */
85068a27b20SMichael S. Tsirkin         if ((proxy->flags & VIRTIO_PCI_FLAG_BUS_MASTER_BUG_MIGRATION) &&
85168a27b20SMichael S. Tsirkin             (vdev->status & VIRTIO_CONFIG_S_DRIVER) &&
85245363e46SMichael S. Tsirkin             !(proxy->pci_dev.config[PCI_COMMAND] & PCI_COMMAND_MASTER)) {
85368a27b20SMichael S. Tsirkin             pci_default_write_config(&proxy->pci_dev, PCI_COMMAND,
85468a27b20SMichael S. Tsirkin                                      proxy->pci_dev.config[PCI_COMMAND] |
85568a27b20SMichael S. Tsirkin                                      PCI_COMMAND_MASTER, 1);
85689c473fdSMichael S. Tsirkin         }
85725db9ebeSStefan Hajnoczi         virtio_pci_start_ioeventfd(proxy);
858ade80dc8SMichael S. Tsirkin     } else {
85925db9ebeSStefan Hajnoczi         virtio_pci_stop_ioeventfd(proxy);
860ade80dc8SMichael S. Tsirkin     }
861ade80dc8SMichael S. Tsirkin }
862ade80dc8SMichael S. Tsirkin 
86360653b28SPaolo Bonzini #ifdef CONFIG_VIRTFS
864fc079951SMarkus Armbruster static void virtio_9p_pci_realize(VirtIOPCIProxy *vpci_dev, Error **errp)
86560653b28SPaolo Bonzini {
866234a336fSKONRAD Frederic     V9fsPCIState *dev = VIRTIO_9P_PCI(vpci_dev);
867234a336fSKONRAD Frederic     DeviceState *vdev = DEVICE(&dev->vdev);
86860653b28SPaolo Bonzini 
869234a336fSKONRAD Frederic     qdev_set_parent_bus(vdev, BUS(&vpci_dev->bus));
870fc079951SMarkus Armbruster     object_property_set_bool(OBJECT(vdev), true, "realized", errp);
87160653b28SPaolo Bonzini }
87260653b28SPaolo Bonzini 
873234a336fSKONRAD Frederic static Property virtio_9p_pci_properties[] = {
874234a336fSKONRAD Frederic     DEFINE_PROP_BIT("ioeventfd", VirtIOPCIProxy, flags,
875234a336fSKONRAD Frederic                     VIRTIO_PCI_FLAG_USE_IOEVENTFD_BIT, true),
87660653b28SPaolo Bonzini     DEFINE_PROP_UINT32("vectors", VirtIOPCIProxy, nvectors, 2),
87760653b28SPaolo Bonzini     DEFINE_PROP_END_OF_LIST(),
87860653b28SPaolo Bonzini };
87960653b28SPaolo Bonzini 
880234a336fSKONRAD Frederic static void virtio_9p_pci_class_init(ObjectClass *klass, void *data)
88160653b28SPaolo Bonzini {
88260653b28SPaolo Bonzini     DeviceClass *dc = DEVICE_CLASS(klass);
883234a336fSKONRAD Frederic     PCIDeviceClass *pcidev_k = PCI_DEVICE_CLASS(klass);
884234a336fSKONRAD Frederic     VirtioPCIClass *k = VIRTIO_PCI_CLASS(klass);
88560653b28SPaolo Bonzini 
886fc079951SMarkus Armbruster     k->realize = virtio_9p_pci_realize;
887234a336fSKONRAD Frederic     pcidev_k->vendor_id = PCI_VENDOR_ID_REDHAT_QUMRANET;
888234a336fSKONRAD Frederic     pcidev_k->device_id = PCI_DEVICE_ID_VIRTIO_9P;
889234a336fSKONRAD Frederic     pcidev_k->revision = VIRTIO_PCI_ABI_VERSION;
890234a336fSKONRAD Frederic     pcidev_k->class_id = 0x2;
891125ee0edSMarcel Apfelbaum     set_bit(DEVICE_CATEGORY_STORAGE, dc->categories);
892234a336fSKONRAD Frederic     dc->props = virtio_9p_pci_properties;
89360653b28SPaolo Bonzini }
89460653b28SPaolo Bonzini 
895234a336fSKONRAD Frederic static void virtio_9p_pci_instance_init(Object *obj)
896234a336fSKONRAD Frederic {
897234a336fSKONRAD Frederic     V9fsPCIState *dev = VIRTIO_9P_PCI(obj);
898c8075cafSGonglei 
899c8075cafSGonglei     virtio_instance_init_common(obj, &dev->vdev, sizeof(dev->vdev),
900c8075cafSGonglei                                 TYPE_VIRTIO_9P);
901234a336fSKONRAD Frederic }
902234a336fSKONRAD Frederic 
903234a336fSKONRAD Frederic static const TypeInfo virtio_9p_pci_info = {
904234a336fSKONRAD Frederic     .name          = TYPE_VIRTIO_9P_PCI,
905234a336fSKONRAD Frederic     .parent        = TYPE_VIRTIO_PCI,
906234a336fSKONRAD Frederic     .instance_size = sizeof(V9fsPCIState),
907234a336fSKONRAD Frederic     .instance_init = virtio_9p_pci_instance_init,
908234a336fSKONRAD Frederic     .class_init    = virtio_9p_pci_class_init,
90960653b28SPaolo Bonzini };
910234a336fSKONRAD Frederic #endif /* CONFIG_VIRTFS */
91160653b28SPaolo Bonzini 
912085bccb7SKONRAD Frederic /*
913085bccb7SKONRAD Frederic  * virtio-pci: This is the PCIDevice which has a virtio-pci-bus.
914085bccb7SKONRAD Frederic  */
915085bccb7SKONRAD Frederic 
916e0d686bfSJason Wang static int virtio_pci_query_nvectors(DeviceState *d)
917e0d686bfSJason Wang {
918e0d686bfSJason Wang     VirtIOPCIProxy *proxy = VIRTIO_PCI(d);
919e0d686bfSJason Wang 
920e0d686bfSJason Wang     return proxy->nvectors;
921e0d686bfSJason Wang }
922e0d686bfSJason Wang 
923dfb8e184SMichael S. Tsirkin static void virtio_pci_add_mem_cap(VirtIOPCIProxy *proxy,
924dfb8e184SMichael S. Tsirkin                                    struct virtio_pci_cap *cap)
925dfb8e184SMichael S. Tsirkin {
926dfb8e184SMichael S. Tsirkin     PCIDevice *dev = &proxy->pci_dev;
927dfb8e184SMichael S. Tsirkin     int offset;
928dfb8e184SMichael S. Tsirkin 
929dfb8e184SMichael S. Tsirkin     cap->bar = 2;
930dfb8e184SMichael S. Tsirkin 
931dfb8e184SMichael S. Tsirkin     offset = pci_add_capability(dev, PCI_CAP_ID_VNDR, 0, cap->cap_len);
932dfb8e184SMichael S. Tsirkin     assert(offset > 0);
933dfb8e184SMichael S. Tsirkin 
934dfb8e184SMichael S. Tsirkin     assert(cap->cap_len >= sizeof *cap);
935dfb8e184SMichael S. Tsirkin     memcpy(dev->config + offset + PCI_CAP_FLAGS, &cap->cap_len,
936dfb8e184SMichael S. Tsirkin            cap->cap_len - PCI_CAP_FLAGS);
937dfb8e184SMichael S. Tsirkin }
938dfb8e184SMichael S. Tsirkin 
939dfb8e184SMichael S. Tsirkin #define QEMU_VIRTIO_PCI_QUEUE_MEM_MULT 0x10000
940dfb8e184SMichael S. Tsirkin 
941dfb8e184SMichael S. Tsirkin static uint64_t virtio_pci_common_read(void *opaque, hwaddr addr,
942dfb8e184SMichael S. Tsirkin                                        unsigned size)
943dfb8e184SMichael S. Tsirkin {
944dfb8e184SMichael S. Tsirkin     VirtIOPCIProxy *proxy = opaque;
945dfb8e184SMichael S. Tsirkin     VirtIODevice *vdev = virtio_bus_get_device(&proxy->bus);
946dfb8e184SMichael S. Tsirkin     uint32_t val = 0;
947dfb8e184SMichael S. Tsirkin     int i;
948dfb8e184SMichael S. Tsirkin 
949dfb8e184SMichael S. Tsirkin     switch (addr) {
950dfb8e184SMichael S. Tsirkin     case VIRTIO_PCI_COMMON_DFSELECT:
951dfb8e184SMichael S. Tsirkin         val = proxy->dfselect;
952dfb8e184SMichael S. Tsirkin         break;
953dfb8e184SMichael S. Tsirkin     case VIRTIO_PCI_COMMON_DF:
954dfb8e184SMichael S. Tsirkin         if (proxy->dfselect <= 1) {
955dfb8e184SMichael S. Tsirkin             val = vdev->host_features >> (32 * proxy->dfselect);
956dfb8e184SMichael S. Tsirkin         }
957dfb8e184SMichael S. Tsirkin         break;
958dfb8e184SMichael S. Tsirkin     case VIRTIO_PCI_COMMON_GFSELECT:
959dfb8e184SMichael S. Tsirkin         val = proxy->gfselect;
960dfb8e184SMichael S. Tsirkin         break;
961dfb8e184SMichael S. Tsirkin     case VIRTIO_PCI_COMMON_GF:
962dfb8e184SMichael S. Tsirkin         if (proxy->gfselect <= ARRAY_SIZE(proxy->guest_features)) {
963dfb8e184SMichael S. Tsirkin             val = proxy->guest_features[proxy->gfselect];
964dfb8e184SMichael S. Tsirkin         }
965dfb8e184SMichael S. Tsirkin         break;
966dfb8e184SMichael S. Tsirkin     case VIRTIO_PCI_COMMON_MSIX:
967dfb8e184SMichael S. Tsirkin         val = vdev->config_vector;
968dfb8e184SMichael S. Tsirkin         break;
969dfb8e184SMichael S. Tsirkin     case VIRTIO_PCI_COMMON_NUMQ:
970dfb8e184SMichael S. Tsirkin         for (i = 0; i < VIRTIO_QUEUE_MAX; ++i) {
971dfb8e184SMichael S. Tsirkin             if (virtio_queue_get_num(vdev, i)) {
972dfb8e184SMichael S. Tsirkin                 val = i + 1;
973dfb8e184SMichael S. Tsirkin             }
974dfb8e184SMichael S. Tsirkin         }
975dfb8e184SMichael S. Tsirkin         break;
976dfb8e184SMichael S. Tsirkin     case VIRTIO_PCI_COMMON_STATUS:
977dfb8e184SMichael S. Tsirkin         val = vdev->status;
978dfb8e184SMichael S. Tsirkin         break;
979dfb8e184SMichael S. Tsirkin     case VIRTIO_PCI_COMMON_CFGGENERATION:
980*b8f05908SMichael S. Tsirkin         val = vdev->generation;
981dfb8e184SMichael S. Tsirkin         break;
982dfb8e184SMichael S. Tsirkin     case VIRTIO_PCI_COMMON_Q_SELECT:
983dfb8e184SMichael S. Tsirkin         val = vdev->queue_sel;
984dfb8e184SMichael S. Tsirkin         break;
985dfb8e184SMichael S. Tsirkin     case VIRTIO_PCI_COMMON_Q_SIZE:
986dfb8e184SMichael S. Tsirkin         val = virtio_queue_get_num(vdev, vdev->queue_sel);
987dfb8e184SMichael S. Tsirkin         break;
988dfb8e184SMichael S. Tsirkin     case VIRTIO_PCI_COMMON_Q_MSIX:
989dfb8e184SMichael S. Tsirkin         val = virtio_queue_vector(vdev, vdev->queue_sel);
990dfb8e184SMichael S. Tsirkin         break;
991dfb8e184SMichael S. Tsirkin     case VIRTIO_PCI_COMMON_Q_ENABLE:
992dfb8e184SMichael S. Tsirkin         val = proxy->vqs[vdev->queue_sel].enabled;
993dfb8e184SMichael S. Tsirkin         break;
994dfb8e184SMichael S. Tsirkin     case VIRTIO_PCI_COMMON_Q_NOFF:
995dfb8e184SMichael S. Tsirkin         /* Simply map queues in order */
996dfb8e184SMichael S. Tsirkin         val = vdev->queue_sel;
997dfb8e184SMichael S. Tsirkin         break;
998dfb8e184SMichael S. Tsirkin     case VIRTIO_PCI_COMMON_Q_DESCLO:
999dfb8e184SMichael S. Tsirkin         val = proxy->vqs[vdev->queue_sel].desc[0];
1000dfb8e184SMichael S. Tsirkin         break;
1001dfb8e184SMichael S. Tsirkin     case VIRTIO_PCI_COMMON_Q_DESCHI:
1002dfb8e184SMichael S. Tsirkin         val = proxy->vqs[vdev->queue_sel].desc[1];
1003dfb8e184SMichael S. Tsirkin         break;
1004dfb8e184SMichael S. Tsirkin     case VIRTIO_PCI_COMMON_Q_AVAILLO:
1005dfb8e184SMichael S. Tsirkin         val = proxy->vqs[vdev->queue_sel].avail[0];
1006dfb8e184SMichael S. Tsirkin         break;
1007dfb8e184SMichael S. Tsirkin     case VIRTIO_PCI_COMMON_Q_AVAILHI:
1008dfb8e184SMichael S. Tsirkin         val = proxy->vqs[vdev->queue_sel].avail[1];
1009dfb8e184SMichael S. Tsirkin         break;
1010dfb8e184SMichael S. Tsirkin     case VIRTIO_PCI_COMMON_Q_USEDLO:
1011dfb8e184SMichael S. Tsirkin         val = proxy->vqs[vdev->queue_sel].used[0];
1012dfb8e184SMichael S. Tsirkin         break;
1013dfb8e184SMichael S. Tsirkin     case VIRTIO_PCI_COMMON_Q_USEDHI:
1014dfb8e184SMichael S. Tsirkin         val = proxy->vqs[vdev->queue_sel].used[1];
1015dfb8e184SMichael S. Tsirkin         break;
1016dfb8e184SMichael S. Tsirkin     default:
1017dfb8e184SMichael S. Tsirkin         val = 0;
1018dfb8e184SMichael S. Tsirkin     }
1019dfb8e184SMichael S. Tsirkin 
1020dfb8e184SMichael S. Tsirkin     return val;
1021dfb8e184SMichael S. Tsirkin }
1022dfb8e184SMichael S. Tsirkin 
1023dfb8e184SMichael S. Tsirkin static void virtio_pci_common_write(void *opaque, hwaddr addr,
1024dfb8e184SMichael S. Tsirkin                                     uint64_t val, unsigned size)
1025dfb8e184SMichael S. Tsirkin {
1026dfb8e184SMichael S. Tsirkin     VirtIOPCIProxy *proxy = opaque;
1027dfb8e184SMichael S. Tsirkin     VirtIODevice *vdev = virtio_bus_get_device(&proxy->bus);
1028dfb8e184SMichael S. Tsirkin 
1029dfb8e184SMichael S. Tsirkin     switch (addr) {
1030dfb8e184SMichael S. Tsirkin     case VIRTIO_PCI_COMMON_DFSELECT:
1031dfb8e184SMichael S. Tsirkin         proxy->dfselect = val;
1032dfb8e184SMichael S. Tsirkin         break;
1033dfb8e184SMichael S. Tsirkin     case VIRTIO_PCI_COMMON_GFSELECT:
1034dfb8e184SMichael S. Tsirkin         proxy->gfselect = val;
1035dfb8e184SMichael S. Tsirkin         break;
1036dfb8e184SMichael S. Tsirkin     case VIRTIO_PCI_COMMON_GF:
1037dfb8e184SMichael S. Tsirkin         if (proxy->gfselect <= ARRAY_SIZE(proxy->guest_features)) {
1038dfb8e184SMichael S. Tsirkin             proxy->guest_features[proxy->gfselect] = val;
1039dfb8e184SMichael S. Tsirkin             virtio_set_features(vdev,
1040dfb8e184SMichael S. Tsirkin                                 (((uint64_t)proxy->guest_features[1]) << 32) |
1041dfb8e184SMichael S. Tsirkin                                 proxy->guest_features[0]);
1042dfb8e184SMichael S. Tsirkin         }
1043dfb8e184SMichael S. Tsirkin         break;
1044dfb8e184SMichael S. Tsirkin     case VIRTIO_PCI_COMMON_MSIX:
1045dfb8e184SMichael S. Tsirkin         msix_vector_unuse(&proxy->pci_dev, vdev->config_vector);
1046dfb8e184SMichael S. Tsirkin         /* Make it possible for guest to discover an error took place. */
1047dfb8e184SMichael S. Tsirkin         if (msix_vector_use(&proxy->pci_dev, val) < 0) {
1048dfb8e184SMichael S. Tsirkin             val = VIRTIO_NO_VECTOR;
1049dfb8e184SMichael S. Tsirkin         }
1050dfb8e184SMichael S. Tsirkin         vdev->config_vector = val;
1051dfb8e184SMichael S. Tsirkin         break;
1052dfb8e184SMichael S. Tsirkin     case VIRTIO_PCI_COMMON_STATUS:
1053dfb8e184SMichael S. Tsirkin         if (!(val & VIRTIO_CONFIG_S_DRIVER_OK)) {
1054dfb8e184SMichael S. Tsirkin             virtio_pci_stop_ioeventfd(proxy);
1055dfb8e184SMichael S. Tsirkin         }
1056dfb8e184SMichael S. Tsirkin 
1057dfb8e184SMichael S. Tsirkin         virtio_set_status(vdev, val & 0xFF);
1058dfb8e184SMichael S. Tsirkin 
1059dfb8e184SMichael S. Tsirkin         if (val & VIRTIO_CONFIG_S_DRIVER_OK) {
1060dfb8e184SMichael S. Tsirkin             virtio_pci_start_ioeventfd(proxy);
1061dfb8e184SMichael S. Tsirkin         }
1062dfb8e184SMichael S. Tsirkin 
1063dfb8e184SMichael S. Tsirkin         if (vdev->status == 0) {
1064dfb8e184SMichael S. Tsirkin             virtio_reset(vdev);
1065dfb8e184SMichael S. Tsirkin             msix_unuse_all_vectors(&proxy->pci_dev);
1066dfb8e184SMichael S. Tsirkin         }
1067dfb8e184SMichael S. Tsirkin 
1068dfb8e184SMichael S. Tsirkin         break;
1069dfb8e184SMichael S. Tsirkin     case VIRTIO_PCI_COMMON_Q_SELECT:
1070dfb8e184SMichael S. Tsirkin         if (val < VIRTIO_QUEUE_MAX) {
1071dfb8e184SMichael S. Tsirkin             vdev->queue_sel = val;
1072dfb8e184SMichael S. Tsirkin         }
1073dfb8e184SMichael S. Tsirkin         break;
1074dfb8e184SMichael S. Tsirkin     case VIRTIO_PCI_COMMON_Q_SIZE:
1075dfb8e184SMichael S. Tsirkin         proxy->vqs[vdev->queue_sel].num = val;
1076dfb8e184SMichael S. Tsirkin         break;
1077dfb8e184SMichael S. Tsirkin     case VIRTIO_PCI_COMMON_Q_MSIX:
1078dfb8e184SMichael S. Tsirkin         msix_vector_unuse(&proxy->pci_dev,
1079dfb8e184SMichael S. Tsirkin                           virtio_queue_vector(vdev, vdev->queue_sel));
1080dfb8e184SMichael S. Tsirkin         /* Make it possible for guest to discover an error took place. */
1081dfb8e184SMichael S. Tsirkin         if (msix_vector_use(&proxy->pci_dev, val) < 0) {
1082dfb8e184SMichael S. Tsirkin             val = VIRTIO_NO_VECTOR;
1083dfb8e184SMichael S. Tsirkin         }
1084dfb8e184SMichael S. Tsirkin         virtio_queue_set_vector(vdev, vdev->queue_sel, val);
1085dfb8e184SMichael S. Tsirkin         break;
1086dfb8e184SMichael S. Tsirkin     case VIRTIO_PCI_COMMON_Q_ENABLE:
1087dfb8e184SMichael S. Tsirkin         /* TODO: need a way to put num back on reset. */
1088dfb8e184SMichael S. Tsirkin         virtio_queue_set_num(vdev, vdev->queue_sel,
1089dfb8e184SMichael S. Tsirkin                              proxy->vqs[vdev->queue_sel].num);
1090dfb8e184SMichael S. Tsirkin         virtio_queue_set_rings(vdev, vdev->queue_sel,
1091dfb8e184SMichael S. Tsirkin                        ((uint64_t)proxy->vqs[vdev->queue_sel].desc[1]) << 32 |
1092dfb8e184SMichael S. Tsirkin                        proxy->vqs[vdev->queue_sel].desc[0],
1093dfb8e184SMichael S. Tsirkin                        ((uint64_t)proxy->vqs[vdev->queue_sel].avail[1]) << 32 |
1094dfb8e184SMichael S. Tsirkin                        proxy->vqs[vdev->queue_sel].avail[0],
1095dfb8e184SMichael S. Tsirkin                        ((uint64_t)proxy->vqs[vdev->queue_sel].used[1]) << 32 |
1096dfb8e184SMichael S. Tsirkin                        proxy->vqs[vdev->queue_sel].used[0]);
1097dfb8e184SMichael S. Tsirkin         break;
1098dfb8e184SMichael S. Tsirkin     case VIRTIO_PCI_COMMON_Q_DESCLO:
1099dfb8e184SMichael S. Tsirkin         proxy->vqs[vdev->queue_sel].desc[0] = val;
1100dfb8e184SMichael S. Tsirkin         break;
1101dfb8e184SMichael S. Tsirkin     case VIRTIO_PCI_COMMON_Q_DESCHI:
1102dfb8e184SMichael S. Tsirkin         proxy->vqs[vdev->queue_sel].desc[1] = val;
1103dfb8e184SMichael S. Tsirkin         break;
1104dfb8e184SMichael S. Tsirkin     case VIRTIO_PCI_COMMON_Q_AVAILLO:
1105dfb8e184SMichael S. Tsirkin         proxy->vqs[vdev->queue_sel].avail[0] = val;
1106dfb8e184SMichael S. Tsirkin         break;
1107dfb8e184SMichael S. Tsirkin     case VIRTIO_PCI_COMMON_Q_AVAILHI:
1108dfb8e184SMichael S. Tsirkin         proxy->vqs[vdev->queue_sel].avail[1] = val;
1109dfb8e184SMichael S. Tsirkin         break;
1110dfb8e184SMichael S. Tsirkin     case VIRTIO_PCI_COMMON_Q_USEDLO:
1111dfb8e184SMichael S. Tsirkin         proxy->vqs[vdev->queue_sel].used[0] = val;
1112dfb8e184SMichael S. Tsirkin         break;
1113dfb8e184SMichael S. Tsirkin     case VIRTIO_PCI_COMMON_Q_USEDHI:
1114dfb8e184SMichael S. Tsirkin         proxy->vqs[vdev->queue_sel].used[1] = val;
1115dfb8e184SMichael S. Tsirkin         break;
1116dfb8e184SMichael S. Tsirkin     default:
1117dfb8e184SMichael S. Tsirkin         break;
1118dfb8e184SMichael S. Tsirkin     }
1119dfb8e184SMichael S. Tsirkin }
1120dfb8e184SMichael S. Tsirkin 
1121dfb8e184SMichael S. Tsirkin 
1122dfb8e184SMichael S. Tsirkin static uint64_t virtio_pci_notify_read(void *opaque, hwaddr addr,
1123dfb8e184SMichael S. Tsirkin                                        unsigned size)
1124dfb8e184SMichael S. Tsirkin {
1125dfb8e184SMichael S. Tsirkin     return 0;
1126dfb8e184SMichael S. Tsirkin }
1127dfb8e184SMichael S. Tsirkin 
1128dfb8e184SMichael S. Tsirkin static void virtio_pci_notify_write(void *opaque, hwaddr addr,
1129dfb8e184SMichael S. Tsirkin                                     uint64_t val, unsigned size)
1130dfb8e184SMichael S. Tsirkin {
1131dfb8e184SMichael S. Tsirkin     VirtIODevice *vdev = opaque;
1132dfb8e184SMichael S. Tsirkin     unsigned queue = addr / QEMU_VIRTIO_PCI_QUEUE_MEM_MULT;
1133dfb8e184SMichael S. Tsirkin 
1134dfb8e184SMichael S. Tsirkin     if (queue < VIRTIO_QUEUE_MAX) {
1135dfb8e184SMichael S. Tsirkin         virtio_queue_notify(vdev, queue);
1136dfb8e184SMichael S. Tsirkin     }
1137dfb8e184SMichael S. Tsirkin }
1138dfb8e184SMichael S. Tsirkin 
1139dfb8e184SMichael S. Tsirkin static uint64_t virtio_pci_isr_read(void *opaque, hwaddr addr,
1140dfb8e184SMichael S. Tsirkin                                     unsigned size)
1141dfb8e184SMichael S. Tsirkin {
1142dfb8e184SMichael S. Tsirkin     VirtIOPCIProxy *proxy = opaque;
1143dfb8e184SMichael S. Tsirkin     VirtIODevice *vdev = virtio_bus_get_device(&proxy->bus);
1144dfb8e184SMichael S. Tsirkin     uint64_t val = vdev->isr;
1145dfb8e184SMichael S. Tsirkin 
1146dfb8e184SMichael S. Tsirkin     vdev->isr = 0;
1147dfb8e184SMichael S. Tsirkin     pci_irq_deassert(&proxy->pci_dev);
1148dfb8e184SMichael S. Tsirkin 
1149dfb8e184SMichael S. Tsirkin     return val;
1150dfb8e184SMichael S. Tsirkin }
1151dfb8e184SMichael S. Tsirkin 
1152dfb8e184SMichael S. Tsirkin static void virtio_pci_isr_write(void *opaque, hwaddr addr,
1153dfb8e184SMichael S. Tsirkin                                  uint64_t val, unsigned size)
1154dfb8e184SMichael S. Tsirkin {
1155dfb8e184SMichael S. Tsirkin }
1156dfb8e184SMichael S. Tsirkin 
1157dfb8e184SMichael S. Tsirkin static uint64_t virtio_pci_device_read(void *opaque, hwaddr addr,
1158dfb8e184SMichael S. Tsirkin                                        unsigned size)
1159dfb8e184SMichael S. Tsirkin {
1160dfb8e184SMichael S. Tsirkin     VirtIODevice *vdev = opaque;
1161dfb8e184SMichael S. Tsirkin     uint64_t val = 0;
1162dfb8e184SMichael S. Tsirkin 
1163dfb8e184SMichael S. Tsirkin     switch (size) {
1164dfb8e184SMichael S. Tsirkin     case 1:
1165dfb8e184SMichael S. Tsirkin         val = virtio_config_readb(vdev, addr);
1166dfb8e184SMichael S. Tsirkin         break;
1167dfb8e184SMichael S. Tsirkin     case 2:
1168dfb8e184SMichael S. Tsirkin         val = virtio_config_readw(vdev, addr);
1169dfb8e184SMichael S. Tsirkin         break;
1170dfb8e184SMichael S. Tsirkin     case 4:
1171dfb8e184SMichael S. Tsirkin         val = virtio_config_readl(vdev, addr);
1172dfb8e184SMichael S. Tsirkin         break;
1173dfb8e184SMichael S. Tsirkin     }
1174dfb8e184SMichael S. Tsirkin     return val;
1175dfb8e184SMichael S. Tsirkin }
1176dfb8e184SMichael S. Tsirkin 
1177dfb8e184SMichael S. Tsirkin static void virtio_pci_device_write(void *opaque, hwaddr addr,
1178dfb8e184SMichael S. Tsirkin                                     uint64_t val, unsigned size)
1179dfb8e184SMichael S. Tsirkin {
1180dfb8e184SMichael S. Tsirkin     VirtIODevice *vdev = opaque;
1181dfb8e184SMichael S. Tsirkin     switch (size) {
1182dfb8e184SMichael S. Tsirkin     case 1:
1183dfb8e184SMichael S. Tsirkin         virtio_config_writeb(vdev, addr, val);
1184dfb8e184SMichael S. Tsirkin         break;
1185dfb8e184SMichael S. Tsirkin     case 2:
1186dfb8e184SMichael S. Tsirkin         virtio_config_writew(vdev, addr, val);
1187dfb8e184SMichael S. Tsirkin         break;
1188dfb8e184SMichael S. Tsirkin     case 4:
1189dfb8e184SMichael S. Tsirkin         virtio_config_writel(vdev, addr, val);
1190dfb8e184SMichael S. Tsirkin         break;
1191dfb8e184SMichael S. Tsirkin     }
1192dfb8e184SMichael S. Tsirkin }
1193dfb8e184SMichael S. Tsirkin 
1194dfb8e184SMichael S. Tsirkin 
1195085bccb7SKONRAD Frederic /* This is called by virtio-bus just after the device is plugged. */
1196e8398045SJason Wang static void virtio_pci_device_plugged(DeviceState *d, Error **errp)
1197085bccb7SKONRAD Frederic {
1198085bccb7SKONRAD Frederic     VirtIOPCIProxy *proxy = VIRTIO_PCI(d);
1199085bccb7SKONRAD Frederic     VirtioBusState *bus = &proxy->bus;
1200085bccb7SKONRAD Frederic     uint8_t *config;
1201085bccb7SKONRAD Frederic     uint32_t size;
12026b8f1020SCornelia Huck     VirtIODevice *vdev = virtio_bus_get_device(&proxy->bus);
1203085bccb7SKONRAD Frederic 
1204085bccb7SKONRAD Frederic     config = proxy->pci_dev.config;
1205085bccb7SKONRAD Frederic     if (proxy->class_code) {
1206085bccb7SKONRAD Frederic         pci_config_set_class(config, proxy->class_code);
1207085bccb7SKONRAD Frederic     }
1208085bccb7SKONRAD Frederic     pci_set_word(config + PCI_SUBSYSTEM_VENDOR_ID,
1209085bccb7SKONRAD Frederic                  pci_get_word(config + PCI_VENDOR_ID));
1210085bccb7SKONRAD Frederic     pci_set_word(config + PCI_SUBSYSTEM_ID, virtio_bus_get_vdev_id(bus));
1211085bccb7SKONRAD Frederic     config[PCI_INTERRUPT_PIN] = 1;
1212085bccb7SKONRAD Frederic 
1213dfb8e184SMichael S. Tsirkin 
1214dfb8e184SMichael S. Tsirkin     if (1) { /* TODO: Make this optional, dependent on virtio 1.0 */
1215dfb8e184SMichael S. Tsirkin         struct virtio_pci_cap common = {
1216dfb8e184SMichael S. Tsirkin             .cfg_type = VIRTIO_PCI_CAP_COMMON_CFG,
1217dfb8e184SMichael S. Tsirkin             .cap_len = sizeof common,
1218dfb8e184SMichael S. Tsirkin             .offset = cpu_to_le32(0x0),
1219dfb8e184SMichael S. Tsirkin             .length = cpu_to_le32(0x1000),
1220dfb8e184SMichael S. Tsirkin         };
1221dfb8e184SMichael S. Tsirkin         struct virtio_pci_cap isr = {
1222dfb8e184SMichael S. Tsirkin             .cfg_type = VIRTIO_PCI_CAP_ISR_CFG,
1223dfb8e184SMichael S. Tsirkin             .cap_len = sizeof isr,
1224dfb8e184SMichael S. Tsirkin             .offset = cpu_to_le32(0x1000),
1225dfb8e184SMichael S. Tsirkin             .length = cpu_to_le32(0x1000),
1226dfb8e184SMichael S. Tsirkin         };
1227dfb8e184SMichael S. Tsirkin         struct virtio_pci_cap device = {
1228dfb8e184SMichael S. Tsirkin             .cfg_type = VIRTIO_PCI_CAP_DEVICE_CFG,
1229dfb8e184SMichael S. Tsirkin             .cap_len = sizeof device,
1230dfb8e184SMichael S. Tsirkin             .offset = cpu_to_le32(0x2000),
1231dfb8e184SMichael S. Tsirkin             .length = cpu_to_le32(0x1000),
1232dfb8e184SMichael S. Tsirkin         };
1233dfb8e184SMichael S. Tsirkin         struct virtio_pci_notify_cap notify = {
1234dfb8e184SMichael S. Tsirkin             .cap.cfg_type = VIRTIO_PCI_CAP_NOTIFY_CFG,
1235dfb8e184SMichael S. Tsirkin             .cap.cap_len = sizeof notify,
1236dfb8e184SMichael S. Tsirkin             .cap.offset = cpu_to_le32(0x3000),
1237dfb8e184SMichael S. Tsirkin             .cap.length = cpu_to_le32(QEMU_VIRTIO_PCI_QUEUE_MEM_MULT *
1238dfb8e184SMichael S. Tsirkin                                       VIRTIO_QUEUE_MAX),
1239dfb8e184SMichael S. Tsirkin             .notify_off_multiplier =
1240dfb8e184SMichael S. Tsirkin                 cpu_to_le32(QEMU_VIRTIO_PCI_QUEUE_MEM_MULT),
1241dfb8e184SMichael S. Tsirkin         };
1242dfb8e184SMichael S. Tsirkin 
1243dfb8e184SMichael S. Tsirkin         static const MemoryRegionOps common_ops = {
1244dfb8e184SMichael S. Tsirkin             .read = virtio_pci_common_read,
1245dfb8e184SMichael S. Tsirkin             .write = virtio_pci_common_write,
1246dfb8e184SMichael S. Tsirkin             .impl = {
1247dfb8e184SMichael S. Tsirkin                 .min_access_size = 1,
1248dfb8e184SMichael S. Tsirkin                 .max_access_size = 4,
1249dfb8e184SMichael S. Tsirkin             },
1250dfb8e184SMichael S. Tsirkin             .endianness = DEVICE_LITTLE_ENDIAN,
1251dfb8e184SMichael S. Tsirkin         };
1252dfb8e184SMichael S. Tsirkin 
1253dfb8e184SMichael S. Tsirkin         static const MemoryRegionOps isr_ops = {
1254dfb8e184SMichael S. Tsirkin             .read = virtio_pci_isr_read,
1255dfb8e184SMichael S. Tsirkin             .write = virtio_pci_isr_write,
1256dfb8e184SMichael S. Tsirkin             .impl = {
1257dfb8e184SMichael S. Tsirkin                 .min_access_size = 1,
1258dfb8e184SMichael S. Tsirkin                 .max_access_size = 4,
1259dfb8e184SMichael S. Tsirkin             },
1260dfb8e184SMichael S. Tsirkin             .endianness = DEVICE_LITTLE_ENDIAN,
1261dfb8e184SMichael S. Tsirkin         };
1262dfb8e184SMichael S. Tsirkin 
1263dfb8e184SMichael S. Tsirkin         static const MemoryRegionOps device_ops = {
1264dfb8e184SMichael S. Tsirkin             .read = virtio_pci_device_read,
1265dfb8e184SMichael S. Tsirkin             .write = virtio_pci_device_write,
1266dfb8e184SMichael S. Tsirkin             .impl = {
1267dfb8e184SMichael S. Tsirkin                 .min_access_size = 1,
1268dfb8e184SMichael S. Tsirkin                 .max_access_size = 4,
1269dfb8e184SMichael S. Tsirkin             },
1270dfb8e184SMichael S. Tsirkin             .endianness = DEVICE_LITTLE_ENDIAN,
1271dfb8e184SMichael S. Tsirkin         };
1272dfb8e184SMichael S. Tsirkin 
1273dfb8e184SMichael S. Tsirkin         static const MemoryRegionOps notify_ops = {
1274dfb8e184SMichael S. Tsirkin             .read = virtio_pci_notify_read,
1275dfb8e184SMichael S. Tsirkin             .write = virtio_pci_notify_write,
1276dfb8e184SMichael S. Tsirkin             .impl = {
1277dfb8e184SMichael S. Tsirkin                 .min_access_size = 1,
1278dfb8e184SMichael S. Tsirkin                 .max_access_size = 4,
1279dfb8e184SMichael S. Tsirkin             },
1280dfb8e184SMichael S. Tsirkin             .endianness = DEVICE_LITTLE_ENDIAN,
1281dfb8e184SMichael S. Tsirkin         };
1282dfb8e184SMichael S. Tsirkin 
1283dfb8e184SMichael S. Tsirkin         /* TODO: add io access for speed */
1284dfb8e184SMichael S. Tsirkin         virtio_pci_add_mem_cap(proxy, &common);
1285dfb8e184SMichael S. Tsirkin         virtio_pci_add_mem_cap(proxy, &isr);
1286dfb8e184SMichael S. Tsirkin         virtio_pci_add_mem_cap(proxy, &device);
1287dfb8e184SMichael S. Tsirkin         virtio_pci_add_mem_cap(proxy, &notify.cap);
1288dfb8e184SMichael S. Tsirkin 
1289dfb8e184SMichael S. Tsirkin         virtio_add_feature(&vdev->host_features, VIRTIO_F_VERSION_1);
1290dfb8e184SMichael S. Tsirkin         memory_region_init(&proxy->modern_bar, OBJECT(proxy), "virtio-pci",
1291dfb8e184SMichael S. Tsirkin                            2 * QEMU_VIRTIO_PCI_QUEUE_MEM_MULT *
1292dfb8e184SMichael S. Tsirkin                            VIRTIO_QUEUE_MAX);
1293dfb8e184SMichael S. Tsirkin         memory_region_init_io(&proxy->common, OBJECT(proxy),
1294dfb8e184SMichael S. Tsirkin                               &common_ops,
1295dfb8e184SMichael S. Tsirkin                               proxy,
1296dfb8e184SMichael S. Tsirkin                               "virtio-pci-common", 0x1000);
1297dfb8e184SMichael S. Tsirkin         memory_region_add_subregion(&proxy->modern_bar, 0, &proxy->common);
1298dfb8e184SMichael S. Tsirkin         memory_region_init_io(&proxy->isr, OBJECT(proxy),
1299dfb8e184SMichael S. Tsirkin                               &isr_ops,
1300dfb8e184SMichael S. Tsirkin                               proxy,
1301dfb8e184SMichael S. Tsirkin                               "virtio-pci-isr", 0x1000);
1302dfb8e184SMichael S. Tsirkin         memory_region_add_subregion(&proxy->modern_bar, 0x1000, &proxy->isr);
1303dfb8e184SMichael S. Tsirkin         memory_region_init_io(&proxy->device, OBJECT(proxy),
1304dfb8e184SMichael S. Tsirkin                               &device_ops,
1305dfb8e184SMichael S. Tsirkin                               virtio_bus_get_device(&proxy->bus),
1306dfb8e184SMichael S. Tsirkin                               "virtio-pci-device", 0x1000);
1307dfb8e184SMichael S. Tsirkin         memory_region_add_subregion(&proxy->modern_bar, 0x2000, &proxy->device);
1308dfb8e184SMichael S. Tsirkin         memory_region_init_io(&proxy->notify, OBJECT(proxy),
1309dfb8e184SMichael S. Tsirkin                               &notify_ops,
1310dfb8e184SMichael S. Tsirkin                               virtio_bus_get_device(&proxy->bus),
1311dfb8e184SMichael S. Tsirkin                               "virtio-pci-notify",
1312dfb8e184SMichael S. Tsirkin                               QEMU_VIRTIO_PCI_QUEUE_MEM_MULT *
1313dfb8e184SMichael S. Tsirkin                               VIRTIO_QUEUE_MAX);
1314dfb8e184SMichael S. Tsirkin         memory_region_add_subregion(&proxy->modern_bar, 0x3000, &proxy->notify);
1315dfb8e184SMichael S. Tsirkin         pci_register_bar(&proxy->pci_dev, 2, PCI_BASE_ADDRESS_SPACE_MEMORY,
1316dfb8e184SMichael S. Tsirkin                          &proxy->modern_bar);
1317dfb8e184SMichael S. Tsirkin     }
1318dfb8e184SMichael S. Tsirkin 
1319085bccb7SKONRAD Frederic     if (proxy->nvectors &&
1320085bccb7SKONRAD Frederic         msix_init_exclusive_bar(&proxy->pci_dev, proxy->nvectors, 1)) {
1321c7ff5482SFam Zheng         error_report("unable to init msix vectors to %" PRIu32,
1322c7ff5482SFam Zheng                      proxy->nvectors);
1323085bccb7SKONRAD Frederic         proxy->nvectors = 0;
1324085bccb7SKONRAD Frederic     }
1325085bccb7SKONRAD Frederic 
1326085bccb7SKONRAD Frederic     proxy->pci_dev.config_write = virtio_write_config;
1327085bccb7SKONRAD Frederic 
1328085bccb7SKONRAD Frederic     size = VIRTIO_PCI_REGION_SIZE(&proxy->pci_dev)
1329085bccb7SKONRAD Frederic          + virtio_bus_get_vdev_config_len(bus);
1330085bccb7SKONRAD Frederic     if (size & (size - 1)) {
1331085bccb7SKONRAD Frederic         size = 1 << qemu_fls(size);
1332085bccb7SKONRAD Frederic     }
1333085bccb7SKONRAD Frederic 
133422fc860bSPaolo Bonzini     memory_region_init_io(&proxy->bar, OBJECT(proxy), &virtio_pci_config_ops,
133522fc860bSPaolo Bonzini                           proxy, "virtio-pci", size);
1336dfb8e184SMichael S. Tsirkin 
1337085bccb7SKONRAD Frederic     pci_register_bar(&proxy->pci_dev, 0, PCI_BASE_ADDRESS_SPACE_IO,
1338085bccb7SKONRAD Frederic                      &proxy->bar);
1339085bccb7SKONRAD Frederic 
1340085bccb7SKONRAD Frederic     if (!kvm_has_many_ioeventfds()) {
1341085bccb7SKONRAD Frederic         proxy->flags &= ~VIRTIO_PCI_FLAG_USE_IOEVENTFD;
1342085bccb7SKONRAD Frederic     }
1343085bccb7SKONRAD Frederic 
13446b8f1020SCornelia Huck     virtio_add_feature(&vdev->host_features, VIRTIO_F_BAD_FEATURE);
1345085bccb7SKONRAD Frederic }
1346085bccb7SKONRAD Frederic 
134706a13073SPaolo Bonzini static void virtio_pci_device_unplugged(DeviceState *d)
134806a13073SPaolo Bonzini {
134906a13073SPaolo Bonzini     VirtIOPCIProxy *proxy = VIRTIO_PCI(d);
135006a13073SPaolo Bonzini 
135106a13073SPaolo Bonzini     virtio_pci_stop_ioeventfd(proxy);
135206a13073SPaolo Bonzini }
135306a13073SPaolo Bonzini 
1354fc079951SMarkus Armbruster static void virtio_pci_realize(PCIDevice *pci_dev, Error **errp)
1355085bccb7SKONRAD Frederic {
1356085bccb7SKONRAD Frederic     VirtIOPCIProxy *dev = VIRTIO_PCI(pci_dev);
1357085bccb7SKONRAD Frederic     VirtioPCIClass *k = VIRTIO_PCI_GET_CLASS(pci_dev);
1358fc079951SMarkus Armbruster 
1359ac7af112SAndreas Färber     virtio_pci_bus_new(&dev->bus, sizeof(dev->bus), dev);
1360fc079951SMarkus Armbruster     if (k->realize) {
1361fc079951SMarkus Armbruster         k->realize(dev, errp);
1362085bccb7SKONRAD Frederic     }
1363085bccb7SKONRAD Frederic }
1364085bccb7SKONRAD Frederic 
1365085bccb7SKONRAD Frederic static void virtio_pci_exit(PCIDevice *pci_dev)
1366085bccb7SKONRAD Frederic {
13678b81bb3bSPaolo Bonzini     msix_uninit_exclusive_bar(pci_dev);
1368085bccb7SKONRAD Frederic }
1369085bccb7SKONRAD Frederic 
137059ccd20aSKONRAD Frederic static void virtio_pci_reset(DeviceState *qdev)
1371085bccb7SKONRAD Frederic {
1372085bccb7SKONRAD Frederic     VirtIOPCIProxy *proxy = VIRTIO_PCI(qdev);
1373085bccb7SKONRAD Frederic     VirtioBusState *bus = VIRTIO_BUS(&proxy->bus);
1374085bccb7SKONRAD Frederic     virtio_pci_stop_ioeventfd(proxy);
1375085bccb7SKONRAD Frederic     virtio_bus_reset(bus);
1376085bccb7SKONRAD Frederic     msix_unuse_all_vectors(&proxy->pci_dev);
1377085bccb7SKONRAD Frederic }
1378085bccb7SKONRAD Frederic 
137985d1277eSMing Lei static Property virtio_pci_properties[] = {
138068a27b20SMichael S. Tsirkin     DEFINE_PROP_BIT("virtio-pci-bus-master-bug-migration", VirtIOPCIProxy, flags,
138168a27b20SMichael S. Tsirkin                     VIRTIO_PCI_FLAG_BUS_MASTER_BUG_MIGRATION_BIT, false),
138285d1277eSMing Lei     DEFINE_PROP_END_OF_LIST(),
138385d1277eSMing Lei };
138485d1277eSMing Lei 
1385085bccb7SKONRAD Frederic static void virtio_pci_class_init(ObjectClass *klass, void *data)
1386085bccb7SKONRAD Frederic {
1387085bccb7SKONRAD Frederic     DeviceClass *dc = DEVICE_CLASS(klass);
1388085bccb7SKONRAD Frederic     PCIDeviceClass *k = PCI_DEVICE_CLASS(klass);
1389085bccb7SKONRAD Frederic 
139085d1277eSMing Lei     dc->props = virtio_pci_properties;
1391fc079951SMarkus Armbruster     k->realize = virtio_pci_realize;
1392085bccb7SKONRAD Frederic     k->exit = virtio_pci_exit;
1393085bccb7SKONRAD Frederic     k->vendor_id = PCI_VENDOR_ID_REDHAT_QUMRANET;
1394085bccb7SKONRAD Frederic     k->revision = VIRTIO_PCI_ABI_VERSION;
1395085bccb7SKONRAD Frederic     k->class_id = PCI_CLASS_OTHERS;
139659ccd20aSKONRAD Frederic     dc->reset = virtio_pci_reset;
1397085bccb7SKONRAD Frederic }
1398085bccb7SKONRAD Frederic 
1399085bccb7SKONRAD Frederic static const TypeInfo virtio_pci_info = {
1400085bccb7SKONRAD Frederic     .name          = TYPE_VIRTIO_PCI,
1401085bccb7SKONRAD Frederic     .parent        = TYPE_PCI_DEVICE,
1402085bccb7SKONRAD Frederic     .instance_size = sizeof(VirtIOPCIProxy),
1403085bccb7SKONRAD Frederic     .class_init    = virtio_pci_class_init,
1404085bccb7SKONRAD Frederic     .class_size    = sizeof(VirtioPCIClass),
1405085bccb7SKONRAD Frederic     .abstract      = true,
1406085bccb7SKONRAD Frederic };
1407085bccb7SKONRAD Frederic 
1408653ced07SKONRAD Frederic /* virtio-blk-pci */
1409653ced07SKONRAD Frederic 
1410653ced07SKONRAD Frederic static Property virtio_blk_pci_properties[] = {
1411c7bcc85dSPaolo Bonzini     DEFINE_PROP_UINT32("class", VirtIOPCIProxy, class_code, 0),
1412653ced07SKONRAD Frederic     DEFINE_PROP_BIT("ioeventfd", VirtIOPCIProxy, flags,
1413653ced07SKONRAD Frederic                     VIRTIO_PCI_FLAG_USE_IOEVENTFD_BIT, true),
1414653ced07SKONRAD Frederic     DEFINE_PROP_UINT32("vectors", VirtIOPCIProxy, nvectors, 2),
1415653ced07SKONRAD Frederic     DEFINE_PROP_END_OF_LIST(),
1416653ced07SKONRAD Frederic };
1417653ced07SKONRAD Frederic 
1418fc079951SMarkus Armbruster static void virtio_blk_pci_realize(VirtIOPCIProxy *vpci_dev, Error **errp)
1419653ced07SKONRAD Frederic {
1420653ced07SKONRAD Frederic     VirtIOBlkPCI *dev = VIRTIO_BLK_PCI(vpci_dev);
1421653ced07SKONRAD Frederic     DeviceState *vdev = DEVICE(&dev->vdev);
1422fc079951SMarkus Armbruster 
1423653ced07SKONRAD Frederic     qdev_set_parent_bus(vdev, BUS(&vpci_dev->bus));
1424fc079951SMarkus Armbruster     object_property_set_bool(OBJECT(vdev), true, "realized", errp);
1425653ced07SKONRAD Frederic }
1426653ced07SKONRAD Frederic 
1427653ced07SKONRAD Frederic static void virtio_blk_pci_class_init(ObjectClass *klass, void *data)
1428653ced07SKONRAD Frederic {
1429653ced07SKONRAD Frederic     DeviceClass *dc = DEVICE_CLASS(klass);
1430653ced07SKONRAD Frederic     VirtioPCIClass *k = VIRTIO_PCI_CLASS(klass);
1431653ced07SKONRAD Frederic     PCIDeviceClass *pcidev_k = PCI_DEVICE_CLASS(klass);
1432653ced07SKONRAD Frederic 
1433125ee0edSMarcel Apfelbaum     set_bit(DEVICE_CATEGORY_STORAGE, dc->categories);
1434653ced07SKONRAD Frederic     dc->props = virtio_blk_pci_properties;
1435fc079951SMarkus Armbruster     k->realize = virtio_blk_pci_realize;
1436653ced07SKONRAD Frederic     pcidev_k->vendor_id = PCI_VENDOR_ID_REDHAT_QUMRANET;
1437653ced07SKONRAD Frederic     pcidev_k->device_id = PCI_DEVICE_ID_VIRTIO_BLOCK;
1438653ced07SKONRAD Frederic     pcidev_k->revision = VIRTIO_PCI_ABI_VERSION;
1439653ced07SKONRAD Frederic     pcidev_k->class_id = PCI_CLASS_STORAGE_SCSI;
1440653ced07SKONRAD Frederic }
1441653ced07SKONRAD Frederic 
1442653ced07SKONRAD Frederic static void virtio_blk_pci_instance_init(Object *obj)
1443653ced07SKONRAD Frederic {
1444653ced07SKONRAD Frederic     VirtIOBlkPCI *dev = VIRTIO_BLK_PCI(obj);
1445c8075cafSGonglei 
1446c8075cafSGonglei     virtio_instance_init_common(obj, &dev->vdev, sizeof(dev->vdev),
1447c8075cafSGonglei                                 TYPE_VIRTIO_BLK);
1448467b3f33SStefan Hajnoczi     object_property_add_alias(obj, "iothread", OBJECT(&dev->vdev),"iothread",
1449467b3f33SStefan Hajnoczi                               &error_abort);
1450aeb98ddcSGonglei     object_property_add_alias(obj, "bootindex", OBJECT(&dev->vdev),
1451aeb98ddcSGonglei                               "bootindex", &error_abort);
1452653ced07SKONRAD Frederic }
1453653ced07SKONRAD Frederic 
1454653ced07SKONRAD Frederic static const TypeInfo virtio_blk_pci_info = {
1455653ced07SKONRAD Frederic     .name          = TYPE_VIRTIO_BLK_PCI,
1456653ced07SKONRAD Frederic     .parent        = TYPE_VIRTIO_PCI,
1457653ced07SKONRAD Frederic     .instance_size = sizeof(VirtIOBlkPCI),
1458653ced07SKONRAD Frederic     .instance_init = virtio_blk_pci_instance_init,
1459653ced07SKONRAD Frederic     .class_init    = virtio_blk_pci_class_init,
1460653ced07SKONRAD Frederic };
1461653ced07SKONRAD Frederic 
1462bc7b90a0SKONRAD Frederic /* virtio-scsi-pci */
1463bc7b90a0SKONRAD Frederic 
1464bc7b90a0SKONRAD Frederic static Property virtio_scsi_pci_properties[] = {
1465bc7b90a0SKONRAD Frederic     DEFINE_PROP_BIT("ioeventfd", VirtIOPCIProxy, flags,
1466bc7b90a0SKONRAD Frederic                     VIRTIO_PCI_FLAG_USE_IOEVENTFD_BIT, true),
1467bc7b90a0SKONRAD Frederic     DEFINE_PROP_UINT32("vectors", VirtIOPCIProxy, nvectors,
1468bc7b90a0SKONRAD Frederic                        DEV_NVECTORS_UNSPECIFIED),
1469bc7b90a0SKONRAD Frederic     DEFINE_PROP_END_OF_LIST(),
1470bc7b90a0SKONRAD Frederic };
1471bc7b90a0SKONRAD Frederic 
1472fc079951SMarkus Armbruster static void virtio_scsi_pci_realize(VirtIOPCIProxy *vpci_dev, Error **errp)
1473bc7b90a0SKONRAD Frederic {
1474bc7b90a0SKONRAD Frederic     VirtIOSCSIPCI *dev = VIRTIO_SCSI_PCI(vpci_dev);
1475bc7b90a0SKONRAD Frederic     DeviceState *vdev = DEVICE(&dev->vdev);
1476292c8e50SPaolo Bonzini     VirtIOSCSICommon *vs = VIRTIO_SCSI_COMMON(vdev);
14776f32a6b4SKONRAD Frederic     DeviceState *proxy = DEVICE(vpci_dev);
14786f32a6b4SKONRAD Frederic     char *bus_name;
1479bc7b90a0SKONRAD Frederic 
1480bc7b90a0SKONRAD Frederic     if (vpci_dev->nvectors == DEV_NVECTORS_UNSPECIFIED) {
1481292c8e50SPaolo Bonzini         vpci_dev->nvectors = vs->conf.num_queues + 3;
1482bc7b90a0SKONRAD Frederic     }
1483bc7b90a0SKONRAD Frederic 
14846f32a6b4SKONRAD Frederic     /*
14856f32a6b4SKONRAD Frederic      * For command line compatibility, this sets the virtio-scsi-device bus
14866f32a6b4SKONRAD Frederic      * name as before.
14876f32a6b4SKONRAD Frederic      */
14886f32a6b4SKONRAD Frederic     if (proxy->id) {
14896f32a6b4SKONRAD Frederic         bus_name = g_strdup_printf("%s.0", proxy->id);
14906f32a6b4SKONRAD Frederic         virtio_device_set_child_bus_name(VIRTIO_DEVICE(vdev), bus_name);
14916f32a6b4SKONRAD Frederic         g_free(bus_name);
14926f32a6b4SKONRAD Frederic     }
14936f32a6b4SKONRAD Frederic 
1494bc7b90a0SKONRAD Frederic     qdev_set_parent_bus(vdev, BUS(&vpci_dev->bus));
1495fc079951SMarkus Armbruster     object_property_set_bool(OBJECT(vdev), true, "realized", errp);
1496bc7b90a0SKONRAD Frederic }
1497bc7b90a0SKONRAD Frederic 
1498bc7b90a0SKONRAD Frederic static void virtio_scsi_pci_class_init(ObjectClass *klass, void *data)
1499bc7b90a0SKONRAD Frederic {
1500bc7b90a0SKONRAD Frederic     DeviceClass *dc = DEVICE_CLASS(klass);
1501bc7b90a0SKONRAD Frederic     VirtioPCIClass *k = VIRTIO_PCI_CLASS(klass);
1502bc7b90a0SKONRAD Frederic     PCIDeviceClass *pcidev_k = PCI_DEVICE_CLASS(klass);
1503fc079951SMarkus Armbruster 
1504fc079951SMarkus Armbruster     k->realize = virtio_scsi_pci_realize;
1505125ee0edSMarcel Apfelbaum     set_bit(DEVICE_CATEGORY_STORAGE, dc->categories);
1506bc7b90a0SKONRAD Frederic     dc->props = virtio_scsi_pci_properties;
1507bc7b90a0SKONRAD Frederic     pcidev_k->vendor_id = PCI_VENDOR_ID_REDHAT_QUMRANET;
1508bc7b90a0SKONRAD Frederic     pcidev_k->device_id = PCI_DEVICE_ID_VIRTIO_SCSI;
1509bc7b90a0SKONRAD Frederic     pcidev_k->revision = 0x00;
1510bc7b90a0SKONRAD Frederic     pcidev_k->class_id = PCI_CLASS_STORAGE_SCSI;
1511bc7b90a0SKONRAD Frederic }
1512bc7b90a0SKONRAD Frederic 
1513bc7b90a0SKONRAD Frederic static void virtio_scsi_pci_instance_init(Object *obj)
1514bc7b90a0SKONRAD Frederic {
1515bc7b90a0SKONRAD Frederic     VirtIOSCSIPCI *dev = VIRTIO_SCSI_PCI(obj);
1516c8075cafSGonglei 
1517c8075cafSGonglei     virtio_instance_init_common(obj, &dev->vdev, sizeof(dev->vdev),
1518c8075cafSGonglei                                 TYPE_VIRTIO_SCSI);
151919d339f1SFam Zheng     object_property_add_alias(obj, "iothread", OBJECT(&dev->vdev), "iothread",
152019d339f1SFam Zheng                               &error_abort);
1521bc7b90a0SKONRAD Frederic }
1522bc7b90a0SKONRAD Frederic 
1523bc7b90a0SKONRAD Frederic static const TypeInfo virtio_scsi_pci_info = {
1524bc7b90a0SKONRAD Frederic     .name          = TYPE_VIRTIO_SCSI_PCI,
1525bc7b90a0SKONRAD Frederic     .parent        = TYPE_VIRTIO_PCI,
1526bc7b90a0SKONRAD Frederic     .instance_size = sizeof(VirtIOSCSIPCI),
1527bc7b90a0SKONRAD Frederic     .instance_init = virtio_scsi_pci_instance_init,
1528bc7b90a0SKONRAD Frederic     .class_init    = virtio_scsi_pci_class_init,
1529bc7b90a0SKONRAD Frederic };
1530bc7b90a0SKONRAD Frederic 
153150787628SNicholas Bellinger /* vhost-scsi-pci */
153250787628SNicholas Bellinger 
153350787628SNicholas Bellinger #ifdef CONFIG_VHOST_SCSI
153450787628SNicholas Bellinger static Property vhost_scsi_pci_properties[] = {
153550787628SNicholas Bellinger     DEFINE_PROP_UINT32("vectors", VirtIOPCIProxy, nvectors,
153650787628SNicholas Bellinger                        DEV_NVECTORS_UNSPECIFIED),
153750787628SNicholas Bellinger     DEFINE_PROP_END_OF_LIST(),
153850787628SNicholas Bellinger };
153950787628SNicholas Bellinger 
1540fc079951SMarkus Armbruster static void vhost_scsi_pci_realize(VirtIOPCIProxy *vpci_dev, Error **errp)
154150787628SNicholas Bellinger {
154250787628SNicholas Bellinger     VHostSCSIPCI *dev = VHOST_SCSI_PCI(vpci_dev);
154350787628SNicholas Bellinger     DeviceState *vdev = DEVICE(&dev->vdev);
154450787628SNicholas Bellinger     VirtIOSCSICommon *vs = VIRTIO_SCSI_COMMON(vdev);
154550787628SNicholas Bellinger 
154650787628SNicholas Bellinger     if (vpci_dev->nvectors == DEV_NVECTORS_UNSPECIFIED) {
154750787628SNicholas Bellinger         vpci_dev->nvectors = vs->conf.num_queues + 3;
154850787628SNicholas Bellinger     }
154950787628SNicholas Bellinger 
155050787628SNicholas Bellinger     qdev_set_parent_bus(vdev, BUS(&vpci_dev->bus));
1551fc079951SMarkus Armbruster     object_property_set_bool(OBJECT(vdev), true, "realized", errp);
155250787628SNicholas Bellinger }
155350787628SNicholas Bellinger 
155450787628SNicholas Bellinger static void vhost_scsi_pci_class_init(ObjectClass *klass, void *data)
155550787628SNicholas Bellinger {
155650787628SNicholas Bellinger     DeviceClass *dc = DEVICE_CLASS(klass);
155750787628SNicholas Bellinger     VirtioPCIClass *k = VIRTIO_PCI_CLASS(klass);
155850787628SNicholas Bellinger     PCIDeviceClass *pcidev_k = PCI_DEVICE_CLASS(klass);
1559fc079951SMarkus Armbruster     k->realize = vhost_scsi_pci_realize;
1560125ee0edSMarcel Apfelbaum     set_bit(DEVICE_CATEGORY_STORAGE, dc->categories);
156150787628SNicholas Bellinger     dc->props = vhost_scsi_pci_properties;
156250787628SNicholas Bellinger     pcidev_k->vendor_id = PCI_VENDOR_ID_REDHAT_QUMRANET;
156350787628SNicholas Bellinger     pcidev_k->device_id = PCI_DEVICE_ID_VIRTIO_SCSI;
156450787628SNicholas Bellinger     pcidev_k->revision = 0x00;
156550787628SNicholas Bellinger     pcidev_k->class_id = PCI_CLASS_STORAGE_SCSI;
156650787628SNicholas Bellinger }
156750787628SNicholas Bellinger 
156850787628SNicholas Bellinger static void vhost_scsi_pci_instance_init(Object *obj)
156950787628SNicholas Bellinger {
157050787628SNicholas Bellinger     VHostSCSIPCI *dev = VHOST_SCSI_PCI(obj);
1571c8075cafSGonglei 
1572c8075cafSGonglei     virtio_instance_init_common(obj, &dev->vdev, sizeof(dev->vdev),
1573c8075cafSGonglei                                 TYPE_VHOST_SCSI);
1574d4433f32SGonglei     object_property_add_alias(obj, "bootindex", OBJECT(&dev->vdev),
1575d4433f32SGonglei                               "bootindex", &error_abort);
157650787628SNicholas Bellinger }
157750787628SNicholas Bellinger 
157850787628SNicholas Bellinger static const TypeInfo vhost_scsi_pci_info = {
157950787628SNicholas Bellinger     .name          = TYPE_VHOST_SCSI_PCI,
158050787628SNicholas Bellinger     .parent        = TYPE_VIRTIO_PCI,
158150787628SNicholas Bellinger     .instance_size = sizeof(VHostSCSIPCI),
158250787628SNicholas Bellinger     .instance_init = vhost_scsi_pci_instance_init,
158350787628SNicholas Bellinger     .class_init    = vhost_scsi_pci_class_init,
158450787628SNicholas Bellinger };
158550787628SNicholas Bellinger #endif
158650787628SNicholas Bellinger 
1587e378e88dSKONRAD Frederic /* virtio-balloon-pci */
1588e378e88dSKONRAD Frederic 
1589e378e88dSKONRAD Frederic static Property virtio_balloon_pci_properties[] = {
1590c7bcc85dSPaolo Bonzini     DEFINE_PROP_UINT32("class", VirtIOPCIProxy, class_code, 0),
1591e378e88dSKONRAD Frederic     DEFINE_PROP_END_OF_LIST(),
1592e378e88dSKONRAD Frederic };
1593e378e88dSKONRAD Frederic 
1594fc079951SMarkus Armbruster static void virtio_balloon_pci_realize(VirtIOPCIProxy *vpci_dev, Error **errp)
1595e378e88dSKONRAD Frederic {
1596e378e88dSKONRAD Frederic     VirtIOBalloonPCI *dev = VIRTIO_BALLOON_PCI(vpci_dev);
1597e378e88dSKONRAD Frederic     DeviceState *vdev = DEVICE(&dev->vdev);
1598e378e88dSKONRAD Frederic 
1599e378e88dSKONRAD Frederic     if (vpci_dev->class_code != PCI_CLASS_OTHERS &&
1600e378e88dSKONRAD Frederic         vpci_dev->class_code != PCI_CLASS_MEMORY_RAM) { /* qemu < 1.1 */
1601e378e88dSKONRAD Frederic         vpci_dev->class_code = PCI_CLASS_OTHERS;
1602e378e88dSKONRAD Frederic     }
1603e378e88dSKONRAD Frederic 
1604e378e88dSKONRAD Frederic     qdev_set_parent_bus(vdev, BUS(&vpci_dev->bus));
1605fc079951SMarkus Armbruster     object_property_set_bool(OBJECT(vdev), true, "realized", errp);
1606e378e88dSKONRAD Frederic }
1607e378e88dSKONRAD Frederic 
1608e378e88dSKONRAD Frederic static void virtio_balloon_pci_class_init(ObjectClass *klass, void *data)
1609e378e88dSKONRAD Frederic {
1610e378e88dSKONRAD Frederic     DeviceClass *dc = DEVICE_CLASS(klass);
1611e378e88dSKONRAD Frederic     VirtioPCIClass *k = VIRTIO_PCI_CLASS(klass);
1612e378e88dSKONRAD Frederic     PCIDeviceClass *pcidev_k = PCI_DEVICE_CLASS(klass);
1613fc079951SMarkus Armbruster     k->realize = virtio_balloon_pci_realize;
1614125ee0edSMarcel Apfelbaum     set_bit(DEVICE_CATEGORY_MISC, dc->categories);
1615e378e88dSKONRAD Frederic     dc->props = virtio_balloon_pci_properties;
1616e378e88dSKONRAD Frederic     pcidev_k->vendor_id = PCI_VENDOR_ID_REDHAT_QUMRANET;
1617e378e88dSKONRAD Frederic     pcidev_k->device_id = PCI_DEVICE_ID_VIRTIO_BALLOON;
1618e378e88dSKONRAD Frederic     pcidev_k->revision = VIRTIO_PCI_ABI_VERSION;
1619e378e88dSKONRAD Frederic     pcidev_k->class_id = PCI_CLASS_OTHERS;
1620e378e88dSKONRAD Frederic }
1621e378e88dSKONRAD Frederic 
1622e378e88dSKONRAD Frederic static void virtio_balloon_pci_instance_init(Object *obj)
1623e378e88dSKONRAD Frederic {
1624e378e88dSKONRAD Frederic     VirtIOBalloonPCI *dev = VIRTIO_BALLOON_PCI(obj);
162539b87c7bSShannon Zhao 
1626a6027b0fSDenis V. Lunev     virtio_instance_init_common(obj, &dev->vdev, sizeof(dev->vdev),
1627a6027b0fSDenis V. Lunev                                 TYPE_VIRTIO_BALLOON);
162839b87c7bSShannon Zhao     object_property_add_alias(obj, "guest-stats", OBJECT(&dev->vdev),
162939b87c7bSShannon Zhao                                   "guest-stats", &error_abort);
163039b87c7bSShannon Zhao     object_property_add_alias(obj, "guest-stats-polling-interval",
163139b87c7bSShannon Zhao                               OBJECT(&dev->vdev),
163239b87c7bSShannon Zhao                               "guest-stats-polling-interval", &error_abort);
1633e378e88dSKONRAD Frederic }
1634e378e88dSKONRAD Frederic 
1635e378e88dSKONRAD Frederic static const TypeInfo virtio_balloon_pci_info = {
1636e378e88dSKONRAD Frederic     .name          = TYPE_VIRTIO_BALLOON_PCI,
1637e378e88dSKONRAD Frederic     .parent        = TYPE_VIRTIO_PCI,
1638e378e88dSKONRAD Frederic     .instance_size = sizeof(VirtIOBalloonPCI),
1639e378e88dSKONRAD Frederic     .instance_init = virtio_balloon_pci_instance_init,
1640e378e88dSKONRAD Frederic     .class_init    = virtio_balloon_pci_class_init,
1641e378e88dSKONRAD Frederic };
1642e378e88dSKONRAD Frederic 
1643f7f7464aSKONRAD Frederic /* virtio-serial-pci */
1644f7f7464aSKONRAD Frederic 
1645fc079951SMarkus Armbruster static void virtio_serial_pci_realize(VirtIOPCIProxy *vpci_dev, Error **errp)
1646f7f7464aSKONRAD Frederic {
1647f7f7464aSKONRAD Frederic     VirtIOSerialPCI *dev = VIRTIO_SERIAL_PCI(vpci_dev);
1648f7f7464aSKONRAD Frederic     DeviceState *vdev = DEVICE(&dev->vdev);
164980270a19SKONRAD Frederic     DeviceState *proxy = DEVICE(vpci_dev);
165080270a19SKONRAD Frederic     char *bus_name;
1651f7f7464aSKONRAD Frederic 
1652f7f7464aSKONRAD Frederic     if (vpci_dev->class_code != PCI_CLASS_COMMUNICATION_OTHER &&
1653f7f7464aSKONRAD Frederic         vpci_dev->class_code != PCI_CLASS_DISPLAY_OTHER && /* qemu 0.10 */
1654f7f7464aSKONRAD Frederic         vpci_dev->class_code != PCI_CLASS_OTHERS) {        /* qemu-kvm  */
1655f7f7464aSKONRAD Frederic             vpci_dev->class_code = PCI_CLASS_COMMUNICATION_OTHER;
1656f7f7464aSKONRAD Frederic     }
1657f7f7464aSKONRAD Frederic 
1658f7f7464aSKONRAD Frederic     /* backwards-compatibility with machines that were created with
1659f7f7464aSKONRAD Frederic        DEV_NVECTORS_UNSPECIFIED */
1660f7f7464aSKONRAD Frederic     if (vpci_dev->nvectors == DEV_NVECTORS_UNSPECIFIED) {
1661f7f7464aSKONRAD Frederic         vpci_dev->nvectors = dev->vdev.serial.max_virtserial_ports + 1;
1662f7f7464aSKONRAD Frederic     }
1663f7f7464aSKONRAD Frederic 
166480270a19SKONRAD Frederic     /*
166580270a19SKONRAD Frederic      * For command line compatibility, this sets the virtio-serial-device bus
166680270a19SKONRAD Frederic      * name as before.
166780270a19SKONRAD Frederic      */
166880270a19SKONRAD Frederic     if (proxy->id) {
166980270a19SKONRAD Frederic         bus_name = g_strdup_printf("%s.0", proxy->id);
167080270a19SKONRAD Frederic         virtio_device_set_child_bus_name(VIRTIO_DEVICE(vdev), bus_name);
167180270a19SKONRAD Frederic         g_free(bus_name);
167280270a19SKONRAD Frederic     }
167380270a19SKONRAD Frederic 
1674f7f7464aSKONRAD Frederic     qdev_set_parent_bus(vdev, BUS(&vpci_dev->bus));
1675fc079951SMarkus Armbruster     object_property_set_bool(OBJECT(vdev), true, "realized", errp);
1676f7f7464aSKONRAD Frederic }
1677f7f7464aSKONRAD Frederic 
1678f7f7464aSKONRAD Frederic static Property virtio_serial_pci_properties[] = {
1679f7f7464aSKONRAD Frederic     DEFINE_PROP_BIT("ioeventfd", VirtIOPCIProxy, flags,
1680f7f7464aSKONRAD Frederic                     VIRTIO_PCI_FLAG_USE_IOEVENTFD_BIT, true),
1681f7f7464aSKONRAD Frederic     DEFINE_PROP_UINT32("vectors", VirtIOPCIProxy, nvectors, 2),
1682c7bcc85dSPaolo Bonzini     DEFINE_PROP_UINT32("class", VirtIOPCIProxy, class_code, 0),
1683f7f7464aSKONRAD Frederic     DEFINE_PROP_END_OF_LIST(),
1684f7f7464aSKONRAD Frederic };
1685f7f7464aSKONRAD Frederic 
1686f7f7464aSKONRAD Frederic static void virtio_serial_pci_class_init(ObjectClass *klass, void *data)
1687f7f7464aSKONRAD Frederic {
1688f7f7464aSKONRAD Frederic     DeviceClass *dc = DEVICE_CLASS(klass);
1689f7f7464aSKONRAD Frederic     VirtioPCIClass *k = VIRTIO_PCI_CLASS(klass);
1690f7f7464aSKONRAD Frederic     PCIDeviceClass *pcidev_k = PCI_DEVICE_CLASS(klass);
1691fc079951SMarkus Armbruster     k->realize = virtio_serial_pci_realize;
1692125ee0edSMarcel Apfelbaum     set_bit(DEVICE_CATEGORY_INPUT, dc->categories);
1693f7f7464aSKONRAD Frederic     dc->props = virtio_serial_pci_properties;
1694f7f7464aSKONRAD Frederic     pcidev_k->vendor_id = PCI_VENDOR_ID_REDHAT_QUMRANET;
1695f7f7464aSKONRAD Frederic     pcidev_k->device_id = PCI_DEVICE_ID_VIRTIO_CONSOLE;
1696f7f7464aSKONRAD Frederic     pcidev_k->revision = VIRTIO_PCI_ABI_VERSION;
1697f7f7464aSKONRAD Frederic     pcidev_k->class_id = PCI_CLASS_COMMUNICATION_OTHER;
1698f7f7464aSKONRAD Frederic }
1699f7f7464aSKONRAD Frederic 
1700f7f7464aSKONRAD Frederic static void virtio_serial_pci_instance_init(Object *obj)
1701f7f7464aSKONRAD Frederic {
1702f7f7464aSKONRAD Frederic     VirtIOSerialPCI *dev = VIRTIO_SERIAL_PCI(obj);
1703c8075cafSGonglei 
1704c8075cafSGonglei     virtio_instance_init_common(obj, &dev->vdev, sizeof(dev->vdev),
1705c8075cafSGonglei                                 TYPE_VIRTIO_SERIAL);
1706f7f7464aSKONRAD Frederic }
1707f7f7464aSKONRAD Frederic 
1708f7f7464aSKONRAD Frederic static const TypeInfo virtio_serial_pci_info = {
1709f7f7464aSKONRAD Frederic     .name          = TYPE_VIRTIO_SERIAL_PCI,
1710f7f7464aSKONRAD Frederic     .parent        = TYPE_VIRTIO_PCI,
1711f7f7464aSKONRAD Frederic     .instance_size = sizeof(VirtIOSerialPCI),
1712f7f7464aSKONRAD Frederic     .instance_init = virtio_serial_pci_instance_init,
1713f7f7464aSKONRAD Frederic     .class_init    = virtio_serial_pci_class_init,
1714f7f7464aSKONRAD Frederic };
1715f7f7464aSKONRAD Frederic 
1716e37da394SKONRAD Frederic /* virtio-net-pci */
1717e37da394SKONRAD Frederic 
1718e37da394SKONRAD Frederic static Property virtio_net_properties[] = {
1719e37da394SKONRAD Frederic     DEFINE_PROP_BIT("ioeventfd", VirtIOPCIProxy, flags,
1720e37da394SKONRAD Frederic                     VIRTIO_PCI_FLAG_USE_IOEVENTFD_BIT, false),
1721e37da394SKONRAD Frederic     DEFINE_PROP_UINT32("vectors", VirtIOPCIProxy, nvectors, 3),
1722e37da394SKONRAD Frederic     DEFINE_PROP_END_OF_LIST(),
1723e37da394SKONRAD Frederic };
1724e37da394SKONRAD Frederic 
1725fc079951SMarkus Armbruster static void virtio_net_pci_realize(VirtIOPCIProxy *vpci_dev, Error **errp)
1726e37da394SKONRAD Frederic {
1727800ced8cSKONRAD Frederic     DeviceState *qdev = DEVICE(vpci_dev);
1728e37da394SKONRAD Frederic     VirtIONetPCI *dev = VIRTIO_NET_PCI(vpci_dev);
1729e37da394SKONRAD Frederic     DeviceState *vdev = DEVICE(&dev->vdev);
1730e37da394SKONRAD Frederic 
1731800ced8cSKONRAD Frederic     virtio_net_set_netclient_name(&dev->vdev, qdev->id,
1732800ced8cSKONRAD Frederic                                   object_get_typename(OBJECT(qdev)));
1733e37da394SKONRAD Frederic     qdev_set_parent_bus(vdev, BUS(&vpci_dev->bus));
1734fc079951SMarkus Armbruster     object_property_set_bool(OBJECT(vdev), true, "realized", errp);
1735e37da394SKONRAD Frederic }
1736e37da394SKONRAD Frederic 
1737e37da394SKONRAD Frederic static void virtio_net_pci_class_init(ObjectClass *klass, void *data)
1738e37da394SKONRAD Frederic {
1739e37da394SKONRAD Frederic     DeviceClass *dc = DEVICE_CLASS(klass);
1740e37da394SKONRAD Frederic     PCIDeviceClass *k = PCI_DEVICE_CLASS(klass);
1741e37da394SKONRAD Frederic     VirtioPCIClass *vpciklass = VIRTIO_PCI_CLASS(klass);
1742e37da394SKONRAD Frederic 
1743e37da394SKONRAD Frederic     k->romfile = "efi-virtio.rom";
1744e37da394SKONRAD Frederic     k->vendor_id = PCI_VENDOR_ID_REDHAT_QUMRANET;
1745e37da394SKONRAD Frederic     k->device_id = PCI_DEVICE_ID_VIRTIO_NET;
1746e37da394SKONRAD Frederic     k->revision = VIRTIO_PCI_ABI_VERSION;
1747e37da394SKONRAD Frederic     k->class_id = PCI_CLASS_NETWORK_ETHERNET;
1748125ee0edSMarcel Apfelbaum     set_bit(DEVICE_CATEGORY_NETWORK, dc->categories);
1749e37da394SKONRAD Frederic     dc->props = virtio_net_properties;
1750fc079951SMarkus Armbruster     vpciklass->realize = virtio_net_pci_realize;
1751e37da394SKONRAD Frederic }
1752e37da394SKONRAD Frederic 
1753e37da394SKONRAD Frederic static void virtio_net_pci_instance_init(Object *obj)
1754e37da394SKONRAD Frederic {
1755e37da394SKONRAD Frederic     VirtIONetPCI *dev = VIRTIO_NET_PCI(obj);
1756c8075cafSGonglei 
1757c8075cafSGonglei     virtio_instance_init_common(obj, &dev->vdev, sizeof(dev->vdev),
1758c8075cafSGonglei                                 TYPE_VIRTIO_NET);
17590cf63c3eSGonglei     object_property_add_alias(obj, "bootindex", OBJECT(&dev->vdev),
17600cf63c3eSGonglei                               "bootindex", &error_abort);
1761e37da394SKONRAD Frederic }
1762e37da394SKONRAD Frederic 
1763e37da394SKONRAD Frederic static const TypeInfo virtio_net_pci_info = {
1764e37da394SKONRAD Frederic     .name          = TYPE_VIRTIO_NET_PCI,
1765e37da394SKONRAD Frederic     .parent        = TYPE_VIRTIO_PCI,
1766e37da394SKONRAD Frederic     .instance_size = sizeof(VirtIONetPCI),
1767e37da394SKONRAD Frederic     .instance_init = virtio_net_pci_instance_init,
1768e37da394SKONRAD Frederic     .class_init    = virtio_net_pci_class_init,
1769e37da394SKONRAD Frederic };
1770e37da394SKONRAD Frederic 
177159ccd20aSKONRAD Frederic /* virtio-rng-pci */
177259ccd20aSKONRAD Frederic 
177359ccd20aSKONRAD Frederic static Property virtio_rng_pci_properties[] = {
177459ccd20aSKONRAD Frederic     DEFINE_PROP_END_OF_LIST(),
177559ccd20aSKONRAD Frederic };
177659ccd20aSKONRAD Frederic 
1777fc079951SMarkus Armbruster static void virtio_rng_pci_realize(VirtIOPCIProxy *vpci_dev, Error **errp)
177859ccd20aSKONRAD Frederic {
177959ccd20aSKONRAD Frederic     VirtIORngPCI *vrng = VIRTIO_RNG_PCI(vpci_dev);
178059ccd20aSKONRAD Frederic     DeviceState *vdev = DEVICE(&vrng->vdev);
1781fc079951SMarkus Armbruster     Error *err = NULL;
178259ccd20aSKONRAD Frederic 
178359ccd20aSKONRAD Frederic     qdev_set_parent_bus(vdev, BUS(&vpci_dev->bus));
1784fc079951SMarkus Armbruster     object_property_set_bool(OBJECT(vdev), true, "realized", &err);
1785fc079951SMarkus Armbruster     if (err) {
1786fc079951SMarkus Armbruster         error_propagate(errp, err);
1787fc079951SMarkus Armbruster         return;
178859ccd20aSKONRAD Frederic     }
178959ccd20aSKONRAD Frederic 
179059ccd20aSKONRAD Frederic     object_property_set_link(OBJECT(vrng),
17915b456438SCole Robinson                              OBJECT(vrng->vdev.conf.rng), "rng",
179259ccd20aSKONRAD Frederic                              NULL);
179359ccd20aSKONRAD Frederic }
179459ccd20aSKONRAD Frederic 
179559ccd20aSKONRAD Frederic static void virtio_rng_pci_class_init(ObjectClass *klass, void *data)
179659ccd20aSKONRAD Frederic {
179759ccd20aSKONRAD Frederic     DeviceClass *dc = DEVICE_CLASS(klass);
179859ccd20aSKONRAD Frederic     VirtioPCIClass *k = VIRTIO_PCI_CLASS(klass);
179959ccd20aSKONRAD Frederic     PCIDeviceClass *pcidev_k = PCI_DEVICE_CLASS(klass);
180059ccd20aSKONRAD Frederic 
1801fc079951SMarkus Armbruster     k->realize = virtio_rng_pci_realize;
1802125ee0edSMarcel Apfelbaum     set_bit(DEVICE_CATEGORY_MISC, dc->categories);
180359ccd20aSKONRAD Frederic     dc->props = virtio_rng_pci_properties;
180459ccd20aSKONRAD Frederic 
180559ccd20aSKONRAD Frederic     pcidev_k->vendor_id = PCI_VENDOR_ID_REDHAT_QUMRANET;
180659ccd20aSKONRAD Frederic     pcidev_k->device_id = PCI_DEVICE_ID_VIRTIO_RNG;
180759ccd20aSKONRAD Frederic     pcidev_k->revision = VIRTIO_PCI_ABI_VERSION;
180859ccd20aSKONRAD Frederic     pcidev_k->class_id = PCI_CLASS_OTHERS;
180959ccd20aSKONRAD Frederic }
181059ccd20aSKONRAD Frederic 
181159ccd20aSKONRAD Frederic static void virtio_rng_initfn(Object *obj)
181259ccd20aSKONRAD Frederic {
181359ccd20aSKONRAD Frederic     VirtIORngPCI *dev = VIRTIO_RNG_PCI(obj);
1814c8075cafSGonglei 
1815c8075cafSGonglei     virtio_instance_init_common(obj, &dev->vdev, sizeof(dev->vdev),
1816c8075cafSGonglei                                 TYPE_VIRTIO_RNG);
1817cbd5ac69SPaolo Bonzini     object_property_add_alias(obj, "rng", OBJECT(&dev->vdev), "rng",
1818cbd5ac69SPaolo Bonzini                               &error_abort);
181959ccd20aSKONRAD Frederic }
182059ccd20aSKONRAD Frederic 
182159ccd20aSKONRAD Frederic static const TypeInfo virtio_rng_pci_info = {
182259ccd20aSKONRAD Frederic     .name          = TYPE_VIRTIO_RNG_PCI,
182359ccd20aSKONRAD Frederic     .parent        = TYPE_VIRTIO_PCI,
182459ccd20aSKONRAD Frederic     .instance_size = sizeof(VirtIORngPCI),
182559ccd20aSKONRAD Frederic     .instance_init = virtio_rng_initfn,
182659ccd20aSKONRAD Frederic     .class_init    = virtio_rng_pci_class_init,
182759ccd20aSKONRAD Frederic };
182859ccd20aSKONRAD Frederic 
18290a2acf5eSKONRAD Frederic /* virtio-pci-bus */
18300a2acf5eSKONRAD Frederic 
1831ac7af112SAndreas Färber static void virtio_pci_bus_new(VirtioBusState *bus, size_t bus_size,
1832ac7af112SAndreas Färber                                VirtIOPCIProxy *dev)
18330a2acf5eSKONRAD Frederic {
18340a2acf5eSKONRAD Frederic     DeviceState *qdev = DEVICE(dev);
1835f4dd69aaSKONRAD Frederic     char virtio_bus_name[] = "virtio-bus";
1836f4dd69aaSKONRAD Frederic 
1837fb17dfe0SAndreas Färber     qbus_create_inplace(bus, bus_size, TYPE_VIRTIO_PCI_BUS, qdev,
1838f4dd69aaSKONRAD Frederic                         virtio_bus_name);
18390a2acf5eSKONRAD Frederic }
18400a2acf5eSKONRAD Frederic 
18410a2acf5eSKONRAD Frederic static void virtio_pci_bus_class_init(ObjectClass *klass, void *data)
18420a2acf5eSKONRAD Frederic {
18430a2acf5eSKONRAD Frederic     BusClass *bus_class = BUS_CLASS(klass);
18440a2acf5eSKONRAD Frederic     VirtioBusClass *k = VIRTIO_BUS_CLASS(klass);
18450a2acf5eSKONRAD Frederic     bus_class->max_dev = 1;
18460a2acf5eSKONRAD Frederic     k->notify = virtio_pci_notify;
18470a2acf5eSKONRAD Frederic     k->save_config = virtio_pci_save_config;
18480a2acf5eSKONRAD Frederic     k->load_config = virtio_pci_load_config;
18490a2acf5eSKONRAD Frederic     k->save_queue = virtio_pci_save_queue;
18500a2acf5eSKONRAD Frederic     k->load_queue = virtio_pci_load_queue;
18510a2acf5eSKONRAD Frederic     k->query_guest_notifiers = virtio_pci_query_guest_notifiers;
18520a2acf5eSKONRAD Frederic     k->set_host_notifier = virtio_pci_set_host_notifier;
18530a2acf5eSKONRAD Frederic     k->set_guest_notifiers = virtio_pci_set_guest_notifiers;
18540a2acf5eSKONRAD Frederic     k->vmstate_change = virtio_pci_vmstate_change;
1855085bccb7SKONRAD Frederic     k->device_plugged = virtio_pci_device_plugged;
185606a13073SPaolo Bonzini     k->device_unplugged = virtio_pci_device_unplugged;
1857e0d686bfSJason Wang     k->query_nvectors = virtio_pci_query_nvectors;
18580a2acf5eSKONRAD Frederic }
18590a2acf5eSKONRAD Frederic 
18600a2acf5eSKONRAD Frederic static const TypeInfo virtio_pci_bus_info = {
18610a2acf5eSKONRAD Frederic     .name          = TYPE_VIRTIO_PCI_BUS,
18620a2acf5eSKONRAD Frederic     .parent        = TYPE_VIRTIO_BUS,
18630a2acf5eSKONRAD Frederic     .instance_size = sizeof(VirtioPCIBusState),
18640a2acf5eSKONRAD Frederic     .class_init    = virtio_pci_bus_class_init,
18650a2acf5eSKONRAD Frederic };
18660a2acf5eSKONRAD Frederic 
186783f7d43aSAndreas Färber static void virtio_pci_register_types(void)
186853c25ceaSPaul Brook {
186959ccd20aSKONRAD Frederic     type_register_static(&virtio_rng_pci_info);
18700a2acf5eSKONRAD Frederic     type_register_static(&virtio_pci_bus_info);
1871085bccb7SKONRAD Frederic     type_register_static(&virtio_pci_info);
187260653b28SPaolo Bonzini #ifdef CONFIG_VIRTFS
1873234a336fSKONRAD Frederic     type_register_static(&virtio_9p_pci_info);
187460653b28SPaolo Bonzini #endif
1875653ced07SKONRAD Frederic     type_register_static(&virtio_blk_pci_info);
1876bc7b90a0SKONRAD Frederic     type_register_static(&virtio_scsi_pci_info);
1877e378e88dSKONRAD Frederic     type_register_static(&virtio_balloon_pci_info);
1878f7f7464aSKONRAD Frederic     type_register_static(&virtio_serial_pci_info);
1879e37da394SKONRAD Frederic     type_register_static(&virtio_net_pci_info);
188050787628SNicholas Bellinger #ifdef CONFIG_VHOST_SCSI
188150787628SNicholas Bellinger     type_register_static(&vhost_scsi_pci_info);
188250787628SNicholas Bellinger #endif
188353c25ceaSPaul Brook }
188453c25ceaSPaul Brook 
188583f7d43aSAndreas Färber type_init(virtio_pci_register_types)
1886