xref: /qemu/hw/virtio/virtio-pci.c (revision 4be746345f13e99e468c60acbd3a355e8183e3ce)
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 
200d09e41aSPaolo Bonzini #include "hw/virtio/virtio.h"
210d09e41aSPaolo Bonzini #include "hw/virtio/virtio-blk.h"
220d09e41aSPaolo Bonzini #include "hw/virtio/virtio-net.h"
230d09e41aSPaolo Bonzini #include "hw/virtio/virtio-serial.h"
240d09e41aSPaolo Bonzini #include "hw/virtio/virtio-scsi.h"
250d09e41aSPaolo Bonzini #include "hw/virtio/virtio-balloon.h"
2683c9f4caSPaolo Bonzini #include "hw/pci/pci.h"
271de7afc9SPaolo Bonzini #include "qemu/error-report.h"
2883c9f4caSPaolo Bonzini #include "hw/pci/msi.h"
2983c9f4caSPaolo Bonzini #include "hw/pci/msix.h"
3083c9f4caSPaolo Bonzini #include "hw/loader.h"
319c17d615SPaolo Bonzini #include "sysemu/kvm.h"
32*4be74634SMarkus Armbruster #include "sysemu/block-backend.h"
3347b43a1fSPaolo Bonzini #include "virtio-pci.h"
341de7afc9SPaolo Bonzini #include "qemu/range.h"
350d09e41aSPaolo Bonzini #include "hw/virtio/virtio-bus.h"
3624a6e7f4SKONRAD Frederic #include "qapi/visitor.h"
3753c25ceaSPaul Brook 
3853c25ceaSPaul Brook /* from Linux's linux/virtio_pci.h */
3953c25ceaSPaul Brook 
4053c25ceaSPaul Brook /* A 32-bit r/o bitmask of the features supported by the host */
4153c25ceaSPaul Brook #define VIRTIO_PCI_HOST_FEATURES        0
4253c25ceaSPaul Brook 
4353c25ceaSPaul Brook /* A 32-bit r/w bitmask of features activated by the guest */
4453c25ceaSPaul Brook #define VIRTIO_PCI_GUEST_FEATURES       4
4553c25ceaSPaul Brook 
4653c25ceaSPaul Brook /* A 32-bit r/w PFN for the currently selected queue */
4753c25ceaSPaul Brook #define VIRTIO_PCI_QUEUE_PFN            8
4853c25ceaSPaul Brook 
4953c25ceaSPaul Brook /* A 16-bit r/o queue size for the currently selected queue */
5053c25ceaSPaul Brook #define VIRTIO_PCI_QUEUE_NUM            12
5153c25ceaSPaul Brook 
5253c25ceaSPaul Brook /* A 16-bit r/w queue selector */
5353c25ceaSPaul Brook #define VIRTIO_PCI_QUEUE_SEL            14
5453c25ceaSPaul Brook 
5553c25ceaSPaul Brook /* A 16-bit r/w queue notifier */
5653c25ceaSPaul Brook #define VIRTIO_PCI_QUEUE_NOTIFY         16
5753c25ceaSPaul Brook 
5853c25ceaSPaul Brook /* An 8-bit device status register.  */
5953c25ceaSPaul Brook #define VIRTIO_PCI_STATUS               18
6053c25ceaSPaul Brook 
6153c25ceaSPaul Brook /* An 8-bit r/o interrupt status register.  Reading the value will return the
6253c25ceaSPaul Brook  * current contents of the ISR and will also clear it.  This is effectively
6353c25ceaSPaul Brook  * a read-and-acknowledge. */
6453c25ceaSPaul Brook #define VIRTIO_PCI_ISR                  19
6553c25ceaSPaul Brook 
66aba800a3SMichael S. Tsirkin /* MSI-X registers: only enabled if MSI-X is enabled. */
67aba800a3SMichael S. Tsirkin /* A 16-bit vector for configuration changes. */
68aba800a3SMichael S. Tsirkin #define VIRTIO_MSI_CONFIG_VECTOR        20
69aba800a3SMichael S. Tsirkin /* A 16-bit vector for selected queue notifications. */
70aba800a3SMichael S. Tsirkin #define VIRTIO_MSI_QUEUE_VECTOR         22
71aba800a3SMichael S. Tsirkin 
72aba800a3SMichael S. Tsirkin /* Config space size */
73aba800a3SMichael S. Tsirkin #define VIRTIO_PCI_CONFIG_NOMSI         20
74aba800a3SMichael S. Tsirkin #define VIRTIO_PCI_CONFIG_MSI           24
75aba800a3SMichael S. Tsirkin #define VIRTIO_PCI_REGION_SIZE(dev)     (msix_present(dev) ? \
76aba800a3SMichael S. Tsirkin                                          VIRTIO_PCI_CONFIG_MSI : \
77aba800a3SMichael S. Tsirkin                                          VIRTIO_PCI_CONFIG_NOMSI)
78aba800a3SMichael S. Tsirkin 
79aba800a3SMichael S. Tsirkin /* The remaining space is defined by each driver as the per-driver
80aba800a3SMichael S. Tsirkin  * configuration space */
81aba800a3SMichael S. Tsirkin #define VIRTIO_PCI_CONFIG(dev)          (msix_enabled(dev) ? \
82aba800a3SMichael S. Tsirkin                                          VIRTIO_PCI_CONFIG_MSI : \
83aba800a3SMichael S. Tsirkin                                          VIRTIO_PCI_CONFIG_NOMSI)
8453c25ceaSPaul Brook 
8553c25ceaSPaul Brook /* How many bits to shift physical queue address written to QUEUE_PFN.
8653c25ceaSPaul Brook  * 12 is historical, and due to x86 page size. */
8753c25ceaSPaul Brook #define VIRTIO_PCI_QUEUE_ADDR_SHIFT    12
8853c25ceaSPaul Brook 
8945363e46SMichael S. Tsirkin /* Flags track per-device state like workarounds for quirks in older guests. */
9045363e46SMichael S. Tsirkin #define VIRTIO_PCI_FLAG_BUS_MASTER_BUG  (1 << 0)
9145363e46SMichael S. Tsirkin 
92ac7af112SAndreas Färber static void virtio_pci_bus_new(VirtioBusState *bus, size_t bus_size,
93ac7af112SAndreas Färber                                VirtIOPCIProxy *dev);
94d51fcfacSKONRAD Frederic 
9553c25ceaSPaul Brook /* virtio device */
96d2a0ccc6SMichael S. Tsirkin /* DeviceState to VirtIOPCIProxy. For use off data-path. TODO: use QOM. */
97d2a0ccc6SMichael S. Tsirkin static inline VirtIOPCIProxy *to_virtio_pci_proxy(DeviceState *d)
9853c25ceaSPaul Brook {
99d2a0ccc6SMichael S. Tsirkin     return container_of(d, VirtIOPCIProxy, pci_dev.qdev);
100d2a0ccc6SMichael S. Tsirkin }
101d2a0ccc6SMichael S. Tsirkin 
102d2a0ccc6SMichael S. Tsirkin /* DeviceState to VirtIOPCIProxy. Note: used on datapath,
103d2a0ccc6SMichael S. Tsirkin  * be careful and test performance if you change this.
104d2a0ccc6SMichael S. Tsirkin  */
105d2a0ccc6SMichael S. Tsirkin static inline VirtIOPCIProxy *to_virtio_pci_proxy_fast(DeviceState *d)
106d2a0ccc6SMichael S. Tsirkin {
107d2a0ccc6SMichael S. Tsirkin     return container_of(d, VirtIOPCIProxy, pci_dev.qdev);
108d2a0ccc6SMichael S. Tsirkin }
109d2a0ccc6SMichael S. Tsirkin 
110d2a0ccc6SMichael S. Tsirkin static void virtio_pci_notify(DeviceState *d, uint16_t vector)
111d2a0ccc6SMichael S. Tsirkin {
112d2a0ccc6SMichael S. Tsirkin     VirtIOPCIProxy *proxy = to_virtio_pci_proxy_fast(d);
113a3fc66d9SPaolo Bonzini 
114aba800a3SMichael S. Tsirkin     if (msix_enabled(&proxy->pci_dev))
115aba800a3SMichael S. Tsirkin         msix_notify(&proxy->pci_dev, vector);
116a3fc66d9SPaolo Bonzini     else {
117a3fc66d9SPaolo Bonzini         VirtIODevice *vdev = virtio_bus_get_device(&proxy->bus);
118a3fc66d9SPaolo Bonzini         pci_set_irq(&proxy->pci_dev, vdev->isr & 1);
119a3fc66d9SPaolo Bonzini     }
12053c25ceaSPaul Brook }
12153c25ceaSPaul Brook 
122d2a0ccc6SMichael S. Tsirkin static void virtio_pci_save_config(DeviceState *d, QEMUFile *f)
123ff24bd58SMichael S. Tsirkin {
124d2a0ccc6SMichael S. Tsirkin     VirtIOPCIProxy *proxy = to_virtio_pci_proxy(d);
125a3fc66d9SPaolo Bonzini     VirtIODevice *vdev = virtio_bus_get_device(&proxy->bus);
126a3fc66d9SPaolo Bonzini 
127ff24bd58SMichael S. Tsirkin     pci_device_save(&proxy->pci_dev, f);
128ff24bd58SMichael S. Tsirkin     msix_save(&proxy->pci_dev, f);
129ff24bd58SMichael S. Tsirkin     if (msix_present(&proxy->pci_dev))
130a3fc66d9SPaolo Bonzini         qemu_put_be16(f, vdev->config_vector);
131ff24bd58SMichael S. Tsirkin }
132ff24bd58SMichael S. Tsirkin 
133d2a0ccc6SMichael S. Tsirkin static void virtio_pci_save_queue(DeviceState *d, int n, QEMUFile *f)
134ff24bd58SMichael S. Tsirkin {
135d2a0ccc6SMichael S. Tsirkin     VirtIOPCIProxy *proxy = to_virtio_pci_proxy(d);
136a3fc66d9SPaolo Bonzini     VirtIODevice *vdev = virtio_bus_get_device(&proxy->bus);
137a3fc66d9SPaolo Bonzini 
138ff24bd58SMichael S. Tsirkin     if (msix_present(&proxy->pci_dev))
139a3fc66d9SPaolo Bonzini         qemu_put_be16(f, virtio_queue_vector(vdev, n));
140ff24bd58SMichael S. Tsirkin }
141ff24bd58SMichael S. Tsirkin 
142d2a0ccc6SMichael S. Tsirkin static int virtio_pci_load_config(DeviceState *d, QEMUFile *f)
143ff24bd58SMichael S. Tsirkin {
144d2a0ccc6SMichael S. Tsirkin     VirtIOPCIProxy *proxy = to_virtio_pci_proxy(d);
145a3fc66d9SPaolo Bonzini     VirtIODevice *vdev = virtio_bus_get_device(&proxy->bus);
146a3fc66d9SPaolo Bonzini 
147ff24bd58SMichael S. Tsirkin     int ret;
148ff24bd58SMichael S. Tsirkin     ret = pci_device_load(&proxy->pci_dev, f);
149e6da7680SMichael S. Tsirkin     if (ret) {
150ff24bd58SMichael S. Tsirkin         return ret;
151e6da7680SMichael S. Tsirkin     }
1523cac001eSMichael S. Tsirkin     msix_unuse_all_vectors(&proxy->pci_dev);
153ff24bd58SMichael S. Tsirkin     msix_load(&proxy->pci_dev, f);
154e6da7680SMichael S. Tsirkin     if (msix_present(&proxy->pci_dev)) {
155a3fc66d9SPaolo Bonzini         qemu_get_be16s(f, &vdev->config_vector);
156e6da7680SMichael S. Tsirkin     } else {
157a3fc66d9SPaolo Bonzini         vdev->config_vector = VIRTIO_NO_VECTOR;
158e6da7680SMichael S. Tsirkin     }
159a3fc66d9SPaolo Bonzini     if (vdev->config_vector != VIRTIO_NO_VECTOR) {
160a3fc66d9SPaolo Bonzini         return msix_vector_use(&proxy->pci_dev, vdev->config_vector);
161e6da7680SMichael S. Tsirkin     }
162ff24bd58SMichael S. Tsirkin     return 0;
163ff24bd58SMichael S. Tsirkin }
164ff24bd58SMichael S. Tsirkin 
165d2a0ccc6SMichael S. Tsirkin static int virtio_pci_load_queue(DeviceState *d, int n, QEMUFile *f)
166ff24bd58SMichael S. Tsirkin {
167d2a0ccc6SMichael S. Tsirkin     VirtIOPCIProxy *proxy = to_virtio_pci_proxy(d);
168a3fc66d9SPaolo Bonzini     VirtIODevice *vdev = virtio_bus_get_device(&proxy->bus);
169a3fc66d9SPaolo Bonzini 
170ff24bd58SMichael S. Tsirkin     uint16_t vector;
171e6da7680SMichael S. Tsirkin     if (msix_present(&proxy->pci_dev)) {
172ff24bd58SMichael S. Tsirkin         qemu_get_be16s(f, &vector);
173e6da7680SMichael S. Tsirkin     } else {
174e6da7680SMichael S. Tsirkin         vector = VIRTIO_NO_VECTOR;
175e6da7680SMichael S. Tsirkin     }
176a3fc66d9SPaolo Bonzini     virtio_queue_set_vector(vdev, n, vector);
177e6da7680SMichael S. Tsirkin     if (vector != VIRTIO_NO_VECTOR) {
178e6da7680SMichael S. Tsirkin         return msix_vector_use(&proxy->pci_dev, vector);
179e6da7680SMichael S. Tsirkin     }
180ff24bd58SMichael S. Tsirkin     return 0;
181ff24bd58SMichael S. Tsirkin }
182ff24bd58SMichael S. Tsirkin 
18325db9ebeSStefan Hajnoczi static int virtio_pci_set_host_notifier_internal(VirtIOPCIProxy *proxy,
18426b9b5feSPaolo Bonzini                                                  int n, bool assign, bool set_handler)
18525db9ebeSStefan Hajnoczi {
186a3fc66d9SPaolo Bonzini     VirtIODevice *vdev = virtio_bus_get_device(&proxy->bus);
187a3fc66d9SPaolo Bonzini     VirtQueue *vq = virtio_get_queue(vdev, n);
18825db9ebeSStefan Hajnoczi     EventNotifier *notifier = virtio_queue_get_host_notifier(vq);
189da146d0aSAvi Kivity     int r = 0;
190da146d0aSAvi Kivity 
19125db9ebeSStefan Hajnoczi     if (assign) {
19225db9ebeSStefan Hajnoczi         r = event_notifier_init(notifier, 1);
19325db9ebeSStefan Hajnoczi         if (r < 0) {
194b36e3914SMichael S. Tsirkin             error_report("%s: unable to init event notifier: %d",
195b36e3914SMichael S. Tsirkin                          __func__, r);
19625db9ebeSStefan Hajnoczi             return r;
19725db9ebeSStefan Hajnoczi         }
19826b9b5feSPaolo Bonzini         virtio_queue_set_host_notifier_fd_handler(vq, true, set_handler);
199da146d0aSAvi Kivity         memory_region_add_eventfd(&proxy->bar, VIRTIO_PCI_QUEUE_NOTIFY, 2,
200753d5e14SPaolo Bonzini                                   true, n, notifier);
20125db9ebeSStefan Hajnoczi     } else {
202da146d0aSAvi Kivity         memory_region_del_eventfd(&proxy->bar, VIRTIO_PCI_QUEUE_NOTIFY, 2,
203753d5e14SPaolo Bonzini                                   true, n, notifier);
20426b9b5feSPaolo Bonzini         virtio_queue_set_host_notifier_fd_handler(vq, false, false);
20525db9ebeSStefan Hajnoczi         event_notifier_cleanup(notifier);
20625db9ebeSStefan Hajnoczi     }
20725db9ebeSStefan Hajnoczi     return r;
20825db9ebeSStefan Hajnoczi }
20925db9ebeSStefan Hajnoczi 
210b36e3914SMichael S. Tsirkin static void virtio_pci_start_ioeventfd(VirtIOPCIProxy *proxy)
21125db9ebeSStefan Hajnoczi {
212a3fc66d9SPaolo Bonzini     VirtIODevice *vdev = virtio_bus_get_device(&proxy->bus);
21325db9ebeSStefan Hajnoczi     int n, r;
21425db9ebeSStefan Hajnoczi 
21525db9ebeSStefan Hajnoczi     if (!(proxy->flags & VIRTIO_PCI_FLAG_USE_IOEVENTFD) ||
21625db9ebeSStefan Hajnoczi         proxy->ioeventfd_disabled ||
21725db9ebeSStefan Hajnoczi         proxy->ioeventfd_started) {
218b36e3914SMichael S. Tsirkin         return;
21925db9ebeSStefan Hajnoczi     }
22025db9ebeSStefan Hajnoczi 
22125db9ebeSStefan Hajnoczi     for (n = 0; n < VIRTIO_PCI_QUEUE_MAX; n++) {
222a3fc66d9SPaolo Bonzini         if (!virtio_queue_get_num(vdev, n)) {
22325db9ebeSStefan Hajnoczi             continue;
22425db9ebeSStefan Hajnoczi         }
22525db9ebeSStefan Hajnoczi 
22626b9b5feSPaolo Bonzini         r = virtio_pci_set_host_notifier_internal(proxy, n, true, true);
22725db9ebeSStefan Hajnoczi         if (r < 0) {
22825db9ebeSStefan Hajnoczi             goto assign_error;
22925db9ebeSStefan Hajnoczi         }
23025db9ebeSStefan Hajnoczi     }
23125db9ebeSStefan Hajnoczi     proxy->ioeventfd_started = true;
232b36e3914SMichael S. Tsirkin     return;
23325db9ebeSStefan Hajnoczi 
23425db9ebeSStefan Hajnoczi assign_error:
23525db9ebeSStefan Hajnoczi     while (--n >= 0) {
236a3fc66d9SPaolo Bonzini         if (!virtio_queue_get_num(vdev, n)) {
23725db9ebeSStefan Hajnoczi             continue;
23825db9ebeSStefan Hajnoczi         }
23925db9ebeSStefan Hajnoczi 
24026b9b5feSPaolo Bonzini         r = virtio_pci_set_host_notifier_internal(proxy, n, false, false);
241b36e3914SMichael S. Tsirkin         assert(r >= 0);
24225db9ebeSStefan Hajnoczi     }
24325db9ebeSStefan Hajnoczi     proxy->ioeventfd_started = false;
244b36e3914SMichael S. Tsirkin     error_report("%s: failed. Fallback to a userspace (slower).", __func__);
24525db9ebeSStefan Hajnoczi }
24625db9ebeSStefan Hajnoczi 
247b36e3914SMichael S. Tsirkin static void virtio_pci_stop_ioeventfd(VirtIOPCIProxy *proxy)
24825db9ebeSStefan Hajnoczi {
249a3fc66d9SPaolo Bonzini     VirtIODevice *vdev = virtio_bus_get_device(&proxy->bus);
250b36e3914SMichael S. Tsirkin     int r;
25125db9ebeSStefan Hajnoczi     int n;
25225db9ebeSStefan Hajnoczi 
25325db9ebeSStefan Hajnoczi     if (!proxy->ioeventfd_started) {
254b36e3914SMichael S. Tsirkin         return;
25525db9ebeSStefan Hajnoczi     }
25625db9ebeSStefan Hajnoczi 
25725db9ebeSStefan Hajnoczi     for (n = 0; n < VIRTIO_PCI_QUEUE_MAX; n++) {
258a3fc66d9SPaolo Bonzini         if (!virtio_queue_get_num(vdev, n)) {
25925db9ebeSStefan Hajnoczi             continue;
26025db9ebeSStefan Hajnoczi         }
26125db9ebeSStefan Hajnoczi 
26226b9b5feSPaolo Bonzini         r = virtio_pci_set_host_notifier_internal(proxy, n, false, false);
263b36e3914SMichael S. Tsirkin         assert(r >= 0);
26425db9ebeSStefan Hajnoczi     }
26525db9ebeSStefan Hajnoczi     proxy->ioeventfd_started = false;
26625db9ebeSStefan Hajnoczi }
26725db9ebeSStefan Hajnoczi 
26853c25ceaSPaul Brook static void virtio_ioport_write(void *opaque, uint32_t addr, uint32_t val)
26953c25ceaSPaul Brook {
27053c25ceaSPaul Brook     VirtIOPCIProxy *proxy = opaque;
271a3fc66d9SPaolo Bonzini     VirtIODevice *vdev = virtio_bus_get_device(&proxy->bus);
272a8170e5eSAvi Kivity     hwaddr pa;
27353c25ceaSPaul Brook 
27453c25ceaSPaul Brook     switch (addr) {
27553c25ceaSPaul Brook     case VIRTIO_PCI_GUEST_FEATURES:
27653c25ceaSPaul Brook         /* Guest does not negotiate properly?  We have to assume nothing. */
27753c25ceaSPaul Brook         if (val & (1 << VIRTIO_F_BAD_FEATURE)) {
278181103cdSKONRAD Frederic             val = virtio_bus_get_vdev_bad_features(&proxy->bus);
27953c25ceaSPaul Brook         }
280ad0c9332SPaolo Bonzini         virtio_set_features(vdev, val);
28153c25ceaSPaul Brook         break;
28253c25ceaSPaul Brook     case VIRTIO_PCI_QUEUE_PFN:
283a8170e5eSAvi Kivity         pa = (hwaddr)val << VIRTIO_PCI_QUEUE_ADDR_SHIFT;
2841b8e9b27SMichael S. Tsirkin         if (pa == 0) {
28525db9ebeSStefan Hajnoczi             virtio_pci_stop_ioeventfd(proxy);
286a3fc66d9SPaolo Bonzini             virtio_reset(vdev);
2871b8e9b27SMichael S. Tsirkin             msix_unuse_all_vectors(&proxy->pci_dev);
2881b8e9b27SMichael S. Tsirkin         }
2897055e687SMichael S. Tsirkin         else
29053c25ceaSPaul Brook             virtio_queue_set_addr(vdev, vdev->queue_sel, pa);
29153c25ceaSPaul Brook         break;
29253c25ceaSPaul Brook     case VIRTIO_PCI_QUEUE_SEL:
29353c25ceaSPaul Brook         if (val < VIRTIO_PCI_QUEUE_MAX)
29453c25ceaSPaul Brook             vdev->queue_sel = val;
29553c25ceaSPaul Brook         break;
29653c25ceaSPaul Brook     case VIRTIO_PCI_QUEUE_NOTIFY:
2977157e2e2SStefan Hajnoczi         if (val < VIRTIO_PCI_QUEUE_MAX) {
29853c25ceaSPaul Brook             virtio_queue_notify(vdev, val);
2997157e2e2SStefan Hajnoczi         }
30053c25ceaSPaul Brook         break;
30153c25ceaSPaul Brook     case VIRTIO_PCI_STATUS:
30225db9ebeSStefan Hajnoczi         if (!(val & VIRTIO_CONFIG_S_DRIVER_OK)) {
30325db9ebeSStefan Hajnoczi             virtio_pci_stop_ioeventfd(proxy);
30425db9ebeSStefan Hajnoczi         }
30525db9ebeSStefan Hajnoczi 
3063e607cb5SMichael S. Tsirkin         virtio_set_status(vdev, val & 0xFF);
30725db9ebeSStefan Hajnoczi 
30825db9ebeSStefan Hajnoczi         if (val & VIRTIO_CONFIG_S_DRIVER_OK) {
30925db9ebeSStefan Hajnoczi             virtio_pci_start_ioeventfd(proxy);
31025db9ebeSStefan Hajnoczi         }
31125db9ebeSStefan Hajnoczi 
3121b8e9b27SMichael S. Tsirkin         if (vdev->status == 0) {
313a3fc66d9SPaolo Bonzini             virtio_reset(vdev);
3141b8e9b27SMichael S. Tsirkin             msix_unuse_all_vectors(&proxy->pci_dev);
3151b8e9b27SMichael S. Tsirkin         }
316c81131dbSAlexander Graf 
317e43c0b2eSMichael S. Tsirkin         /* Linux before 2.6.34 drives the device without enabling
318e43c0b2eSMichael S. Tsirkin            the PCI device bus master bit. Enable it automatically
319e43c0b2eSMichael S. Tsirkin            for the guest. This is a PCI spec violation but so is
320e43c0b2eSMichael S. Tsirkin            initiating DMA with bus master bit clear. */
321e43c0b2eSMichael S. Tsirkin         if (val == (VIRTIO_CONFIG_S_ACKNOWLEDGE | VIRTIO_CONFIG_S_DRIVER)) {
322e43c0b2eSMichael S. Tsirkin             pci_default_write_config(&proxy->pci_dev, PCI_COMMAND,
323e43c0b2eSMichael S. Tsirkin                                      proxy->pci_dev.config[PCI_COMMAND] |
324e43c0b2eSMichael S. Tsirkin                                      PCI_COMMAND_MASTER, 1);
325e43c0b2eSMichael S. Tsirkin         }
32645363e46SMichael S. Tsirkin 
32745363e46SMichael S. Tsirkin         /* Linux before 2.6.34 sets the device as OK without enabling
32845363e46SMichael S. Tsirkin            the PCI device bus master bit. In this case we need to disable
32945363e46SMichael S. Tsirkin            some safety checks. */
33045363e46SMichael S. Tsirkin         if ((val & VIRTIO_CONFIG_S_DRIVER_OK) &&
33145363e46SMichael S. Tsirkin             !(proxy->pci_dev.config[PCI_COMMAND] & PCI_COMMAND_MASTER)) {
33245363e46SMichael S. Tsirkin             proxy->flags |= VIRTIO_PCI_FLAG_BUS_MASTER_BUG;
33345363e46SMichael S. Tsirkin         }
33453c25ceaSPaul Brook         break;
335aba800a3SMichael S. Tsirkin     case VIRTIO_MSI_CONFIG_VECTOR:
336aba800a3SMichael S. Tsirkin         msix_vector_unuse(&proxy->pci_dev, vdev->config_vector);
337aba800a3SMichael S. Tsirkin         /* Make it possible for guest to discover an error took place. */
338aba800a3SMichael S. Tsirkin         if (msix_vector_use(&proxy->pci_dev, val) < 0)
339aba800a3SMichael S. Tsirkin             val = VIRTIO_NO_VECTOR;
340aba800a3SMichael S. Tsirkin         vdev->config_vector = val;
341aba800a3SMichael S. Tsirkin         break;
342aba800a3SMichael S. Tsirkin     case VIRTIO_MSI_QUEUE_VECTOR:
343aba800a3SMichael S. Tsirkin         msix_vector_unuse(&proxy->pci_dev,
344aba800a3SMichael S. Tsirkin                           virtio_queue_vector(vdev, vdev->queue_sel));
345aba800a3SMichael S. Tsirkin         /* Make it possible for guest to discover an error took place. */
346aba800a3SMichael S. Tsirkin         if (msix_vector_use(&proxy->pci_dev, val) < 0)
347aba800a3SMichael S. Tsirkin             val = VIRTIO_NO_VECTOR;
348aba800a3SMichael S. Tsirkin         virtio_queue_set_vector(vdev, vdev->queue_sel, val);
349aba800a3SMichael S. Tsirkin         break;
350aba800a3SMichael S. Tsirkin     default:
3514e02d460SStefan Hajnoczi         error_report("%s: unexpected address 0x%x value 0x%x",
352aba800a3SMichael S. Tsirkin                      __func__, addr, val);
353aba800a3SMichael S. Tsirkin         break;
35453c25ceaSPaul Brook     }
35553c25ceaSPaul Brook }
35653c25ceaSPaul Brook 
357aba800a3SMichael S. Tsirkin static uint32_t virtio_ioport_read(VirtIOPCIProxy *proxy, uint32_t addr)
35853c25ceaSPaul Brook {
359a3fc66d9SPaolo Bonzini     VirtIODevice *vdev = virtio_bus_get_device(&proxy->bus);
36053c25ceaSPaul Brook     uint32_t ret = 0xFFFFFFFF;
36153c25ceaSPaul Brook 
36253c25ceaSPaul Brook     switch (addr) {
36353c25ceaSPaul Brook     case VIRTIO_PCI_HOST_FEATURES:
3648172539dSMichael S. Tsirkin         ret = proxy->host_features;
36553c25ceaSPaul Brook         break;
36653c25ceaSPaul Brook     case VIRTIO_PCI_GUEST_FEATURES:
367704a76fcSMichael S. Tsirkin         ret = vdev->guest_features;
36853c25ceaSPaul Brook         break;
36953c25ceaSPaul Brook     case VIRTIO_PCI_QUEUE_PFN:
37053c25ceaSPaul Brook         ret = virtio_queue_get_addr(vdev, vdev->queue_sel)
37153c25ceaSPaul Brook               >> VIRTIO_PCI_QUEUE_ADDR_SHIFT;
37253c25ceaSPaul Brook         break;
37353c25ceaSPaul Brook     case VIRTIO_PCI_QUEUE_NUM:
37453c25ceaSPaul Brook         ret = virtio_queue_get_num(vdev, vdev->queue_sel);
37553c25ceaSPaul Brook         break;
37653c25ceaSPaul Brook     case VIRTIO_PCI_QUEUE_SEL:
37753c25ceaSPaul Brook         ret = vdev->queue_sel;
37853c25ceaSPaul Brook         break;
37953c25ceaSPaul Brook     case VIRTIO_PCI_STATUS:
38053c25ceaSPaul Brook         ret = vdev->status;
38153c25ceaSPaul Brook         break;
38253c25ceaSPaul Brook     case VIRTIO_PCI_ISR:
38353c25ceaSPaul Brook         /* reading from the ISR also clears it. */
38453c25ceaSPaul Brook         ret = vdev->isr;
38553c25ceaSPaul Brook         vdev->isr = 0;
3869e64f8a3SMarcel Apfelbaum         pci_irq_deassert(&proxy->pci_dev);
38753c25ceaSPaul Brook         break;
388aba800a3SMichael S. Tsirkin     case VIRTIO_MSI_CONFIG_VECTOR:
389aba800a3SMichael S. Tsirkin         ret = vdev->config_vector;
390aba800a3SMichael S. Tsirkin         break;
391aba800a3SMichael S. Tsirkin     case VIRTIO_MSI_QUEUE_VECTOR:
392aba800a3SMichael S. Tsirkin         ret = virtio_queue_vector(vdev, vdev->queue_sel);
393aba800a3SMichael S. Tsirkin         break;
39453c25ceaSPaul Brook     default:
39553c25ceaSPaul Brook         break;
39653c25ceaSPaul Brook     }
39753c25ceaSPaul Brook 
39853c25ceaSPaul Brook     return ret;
39953c25ceaSPaul Brook }
40053c25ceaSPaul Brook 
401df6db5b3SAlexander Graf static uint64_t virtio_pci_config_read(void *opaque, hwaddr addr,
402df6db5b3SAlexander Graf                                        unsigned size)
40353c25ceaSPaul Brook {
40453c25ceaSPaul Brook     VirtIOPCIProxy *proxy = opaque;
405a3fc66d9SPaolo Bonzini     VirtIODevice *vdev = virtio_bus_get_device(&proxy->bus);
406aba800a3SMichael S. Tsirkin     uint32_t config = VIRTIO_PCI_CONFIG(&proxy->pci_dev);
407df6db5b3SAlexander Graf     uint64_t val = 0;
408df6db5b3SAlexander Graf     if (addr < config) {
409aba800a3SMichael S. Tsirkin         return virtio_ioport_read(proxy, addr);
41053c25ceaSPaul Brook     }
411aba800a3SMichael S. Tsirkin     addr -= config;
412df6db5b3SAlexander Graf 
413df6db5b3SAlexander Graf     switch (size) {
414df6db5b3SAlexander Graf     case 1:
415a3fc66d9SPaolo Bonzini         val = virtio_config_readb(vdev, addr);
416df6db5b3SAlexander Graf         break;
417df6db5b3SAlexander Graf     case 2:
418a3fc66d9SPaolo Bonzini         val = virtio_config_readw(vdev, addr);
419616a6552SGreg Kurz         if (virtio_is_big_endian(vdev)) {
4208e4a424bSBlue Swirl             val = bswap16(val);
4218e4a424bSBlue Swirl         }
422df6db5b3SAlexander Graf         break;
423df6db5b3SAlexander Graf     case 4:
424a3fc66d9SPaolo Bonzini         val = virtio_config_readl(vdev, addr);
425616a6552SGreg Kurz         if (virtio_is_big_endian(vdev)) {
4268e4a424bSBlue Swirl             val = bswap32(val);
4278e4a424bSBlue Swirl         }
428df6db5b3SAlexander Graf         break;
429df6db5b3SAlexander Graf     }
43082afa586SBenjamin Herrenschmidt     return val;
43153c25ceaSPaul Brook }
43253c25ceaSPaul Brook 
433df6db5b3SAlexander Graf static void virtio_pci_config_write(void *opaque, hwaddr addr,
434df6db5b3SAlexander Graf                                     uint64_t val, unsigned size)
43553c25ceaSPaul Brook {
43653c25ceaSPaul Brook     VirtIOPCIProxy *proxy = opaque;
437aba800a3SMichael S. Tsirkin     uint32_t config = VIRTIO_PCI_CONFIG(&proxy->pci_dev);
438a3fc66d9SPaolo Bonzini     VirtIODevice *vdev = virtio_bus_get_device(&proxy->bus);
439aba800a3SMichael S. Tsirkin     if (addr < config) {
440aba800a3SMichael S. Tsirkin         virtio_ioport_write(proxy, addr, val);
441aba800a3SMichael S. Tsirkin         return;
442aba800a3SMichael S. Tsirkin     }
443aba800a3SMichael S. Tsirkin     addr -= config;
444df6db5b3SAlexander Graf     /*
445df6db5b3SAlexander Graf      * Virtio-PCI is odd. Ioports are LE but config space is target native
446df6db5b3SAlexander Graf      * endian.
447df6db5b3SAlexander Graf      */
448df6db5b3SAlexander Graf     switch (size) {
449df6db5b3SAlexander Graf     case 1:
450a3fc66d9SPaolo Bonzini         virtio_config_writeb(vdev, addr, val);
451df6db5b3SAlexander Graf         break;
452df6db5b3SAlexander Graf     case 2:
453616a6552SGreg Kurz         if (virtio_is_big_endian(vdev)) {
4548e4a424bSBlue Swirl             val = bswap16(val);
4558e4a424bSBlue Swirl         }
456a3fc66d9SPaolo Bonzini         virtio_config_writew(vdev, addr, val);
457df6db5b3SAlexander Graf         break;
458df6db5b3SAlexander Graf     case 4:
459616a6552SGreg Kurz         if (virtio_is_big_endian(vdev)) {
4608e4a424bSBlue Swirl             val = bswap32(val);
4618e4a424bSBlue Swirl         }
462a3fc66d9SPaolo Bonzini         virtio_config_writel(vdev, addr, val);
463df6db5b3SAlexander Graf         break;
464df6db5b3SAlexander Graf     }
46553c25ceaSPaul Brook }
46653c25ceaSPaul Brook 
467da146d0aSAvi Kivity static const MemoryRegionOps virtio_pci_config_ops = {
468df6db5b3SAlexander Graf     .read = virtio_pci_config_read,
469df6db5b3SAlexander Graf     .write = virtio_pci_config_write,
470df6db5b3SAlexander Graf     .impl = {
471df6db5b3SAlexander Graf         .min_access_size = 1,
472df6db5b3SAlexander Graf         .max_access_size = 4,
473df6db5b3SAlexander Graf     },
4748e4a424bSBlue Swirl     .endianness = DEVICE_LITTLE_ENDIAN,
475da146d0aSAvi Kivity };
476aba800a3SMichael S. Tsirkin 
477aba800a3SMichael S. Tsirkin static void virtio_write_config(PCIDevice *pci_dev, uint32_t address,
478aba800a3SMichael S. Tsirkin                                 uint32_t val, int len)
479aba800a3SMichael S. Tsirkin {
480ed757e14SYan Vugenfirer     VirtIOPCIProxy *proxy = DO_UPCAST(VirtIOPCIProxy, pci_dev, pci_dev);
481a3fc66d9SPaolo Bonzini     VirtIODevice *vdev = virtio_bus_get_device(&proxy->bus);
482ed757e14SYan Vugenfirer 
4831129714fSMichael S. Tsirkin     pci_default_write_config(pci_dev, address, val, len);
4841129714fSMichael S. Tsirkin 
4851129714fSMichael S. Tsirkin     if (range_covers_byte(address, len, PCI_COMMAND) &&
4861129714fSMichael S. Tsirkin         !(pci_dev->config[PCI_COMMAND] & PCI_COMMAND_MASTER) &&
48745363e46SMichael S. Tsirkin         !(proxy->flags & VIRTIO_PCI_FLAG_BUS_MASTER_BUG)) {
48825db9ebeSStefan Hajnoczi         virtio_pci_stop_ioeventfd(proxy);
48945363e46SMichael S. Tsirkin         virtio_set_status(vdev, vdev->status & ~VIRTIO_CONFIG_S_DRIVER_OK);
490ed757e14SYan Vugenfirer     }
49153c25ceaSPaul Brook }
49253c25ceaSPaul Brook 
493d2a0ccc6SMichael S. Tsirkin static unsigned virtio_pci_get_features(DeviceState *d)
4946d74ca5aSMichael S. Tsirkin {
495d2a0ccc6SMichael S. Tsirkin     VirtIOPCIProxy *proxy = to_virtio_pci_proxy(d);
4968172539dSMichael S. Tsirkin     return proxy->host_features;
4976d74ca5aSMichael S. Tsirkin }
4986d74ca5aSMichael S. Tsirkin 
4997d37d351SJan Kiszka static int kvm_virtio_pci_vq_vector_use(VirtIOPCIProxy *proxy,
5007d37d351SJan Kiszka                                         unsigned int queue_no,
5017d37d351SJan Kiszka                                         unsigned int vector,
5027d37d351SJan Kiszka                                         MSIMessage msg)
5037d37d351SJan Kiszka {
5047d37d351SJan Kiszka     VirtIOIRQFD *irqfd = &proxy->vector_irqfd[vector];
50515b2bd18SPaolo Bonzini     int ret;
5067d37d351SJan Kiszka 
5077d37d351SJan Kiszka     if (irqfd->users == 0) {
5087d37d351SJan Kiszka         ret = kvm_irqchip_add_msi_route(kvm_state, msg);
5097d37d351SJan Kiszka         if (ret < 0) {
5107d37d351SJan Kiszka             return ret;
5117d37d351SJan Kiszka         }
5127d37d351SJan Kiszka         irqfd->virq = ret;
5137d37d351SJan Kiszka     }
5147d37d351SJan Kiszka     irqfd->users++;
5157d37d351SJan Kiszka     return 0;
5167d37d351SJan Kiszka }
5177d37d351SJan Kiszka 
5187d37d351SJan Kiszka static void kvm_virtio_pci_vq_vector_release(VirtIOPCIProxy *proxy,
519774345f9SMichael S. Tsirkin                                              unsigned int vector)
520774345f9SMichael S. Tsirkin {
521774345f9SMichael S. Tsirkin     VirtIOIRQFD *irqfd = &proxy->vector_irqfd[vector];
522774345f9SMichael S. Tsirkin     if (--irqfd->users == 0) {
523774345f9SMichael S. Tsirkin         kvm_irqchip_release_virq(kvm_state, irqfd->virq);
524774345f9SMichael S. Tsirkin     }
525774345f9SMichael S. Tsirkin }
526774345f9SMichael S. Tsirkin 
527f1d0f15aSMichael S. Tsirkin static int kvm_virtio_pci_irqfd_use(VirtIOPCIProxy *proxy,
528f1d0f15aSMichael S. Tsirkin                                  unsigned int queue_no,
529f1d0f15aSMichael S. Tsirkin                                  unsigned int vector)
530f1d0f15aSMichael S. Tsirkin {
531f1d0f15aSMichael S. Tsirkin     VirtIOIRQFD *irqfd = &proxy->vector_irqfd[vector];
532a3fc66d9SPaolo Bonzini     VirtIODevice *vdev = virtio_bus_get_device(&proxy->bus);
533a3fc66d9SPaolo Bonzini     VirtQueue *vq = virtio_get_queue(vdev, queue_no);
534f1d0f15aSMichael S. Tsirkin     EventNotifier *n = virtio_queue_get_guest_notifier(vq);
535f1d0f15aSMichael S. Tsirkin     int ret;
536ca916d37SVincenzo Maffione     ret = kvm_irqchip_add_irqfd_notifier(kvm_state, n, NULL, irqfd->virq);
537f1d0f15aSMichael S. Tsirkin     return ret;
538f1d0f15aSMichael S. Tsirkin }
539f1d0f15aSMichael S. Tsirkin 
540f1d0f15aSMichael S. Tsirkin static void kvm_virtio_pci_irqfd_release(VirtIOPCIProxy *proxy,
5417d37d351SJan Kiszka                                       unsigned int queue_no,
5427d37d351SJan Kiszka                                       unsigned int vector)
5437d37d351SJan Kiszka {
544a3fc66d9SPaolo Bonzini     VirtIODevice *vdev = virtio_bus_get_device(&proxy->bus);
545a3fc66d9SPaolo Bonzini     VirtQueue *vq = virtio_get_queue(vdev, queue_no);
54615b2bd18SPaolo Bonzini     EventNotifier *n = virtio_queue_get_guest_notifier(vq);
5477d37d351SJan Kiszka     VirtIOIRQFD *irqfd = &proxy->vector_irqfd[vector];
54815b2bd18SPaolo Bonzini     int ret;
5497d37d351SJan Kiszka 
550b131c74aSJan Kiszka     ret = kvm_irqchip_remove_irqfd_notifier(kvm_state, n, irqfd->virq);
5517d37d351SJan Kiszka     assert(ret == 0);
552f1d0f15aSMichael S. Tsirkin }
5537d37d351SJan Kiszka 
554774345f9SMichael S. Tsirkin static int kvm_virtio_pci_vector_use(VirtIOPCIProxy *proxy, int nvqs)
555774345f9SMichael S. Tsirkin {
556774345f9SMichael S. Tsirkin     PCIDevice *dev = &proxy->pci_dev;
557a3fc66d9SPaolo Bonzini     VirtIODevice *vdev = virtio_bus_get_device(&proxy->bus);
558181103cdSKONRAD Frederic     VirtioDeviceClass *k = VIRTIO_DEVICE_GET_CLASS(vdev);
559774345f9SMichael S. Tsirkin     unsigned int vector;
560774345f9SMichael S. Tsirkin     int ret, queue_no;
561774345f9SMichael S. Tsirkin     MSIMessage msg;
562774345f9SMichael S. Tsirkin 
563774345f9SMichael S. Tsirkin     for (queue_no = 0; queue_no < nvqs; queue_no++) {
564774345f9SMichael S. Tsirkin         if (!virtio_queue_get_num(vdev, queue_no)) {
565774345f9SMichael S. Tsirkin             break;
566774345f9SMichael S. Tsirkin         }
567774345f9SMichael S. Tsirkin         vector = virtio_queue_vector(vdev, queue_no);
568774345f9SMichael S. Tsirkin         if (vector >= msix_nr_vectors_allocated(dev)) {
569774345f9SMichael S. Tsirkin             continue;
570774345f9SMichael S. Tsirkin         }
571774345f9SMichael S. Tsirkin         msg = msix_get_message(dev, vector);
572774345f9SMichael S. Tsirkin         ret = kvm_virtio_pci_vq_vector_use(proxy, queue_no, vector, msg);
573774345f9SMichael S. Tsirkin         if (ret < 0) {
574774345f9SMichael S. Tsirkin             goto undo;
575774345f9SMichael S. Tsirkin         }
576f1d0f15aSMichael S. Tsirkin         /* If guest supports masking, set up irqfd now.
577f1d0f15aSMichael S. Tsirkin          * Otherwise, delay until unmasked in the frontend.
578f1d0f15aSMichael S. Tsirkin          */
579181103cdSKONRAD Frederic         if (k->guest_notifier_mask) {
580f1d0f15aSMichael S. Tsirkin             ret = kvm_virtio_pci_irqfd_use(proxy, queue_no, vector);
581f1d0f15aSMichael S. Tsirkin             if (ret < 0) {
582f1d0f15aSMichael S. Tsirkin                 kvm_virtio_pci_vq_vector_release(proxy, vector);
583f1d0f15aSMichael S. Tsirkin                 goto undo;
584f1d0f15aSMichael S. Tsirkin             }
585f1d0f15aSMichael S. Tsirkin         }
586774345f9SMichael S. Tsirkin     }
587774345f9SMichael S. Tsirkin     return 0;
588774345f9SMichael S. Tsirkin 
589774345f9SMichael S. Tsirkin undo:
590774345f9SMichael S. Tsirkin     while (--queue_no >= 0) {
591774345f9SMichael S. Tsirkin         vector = virtio_queue_vector(vdev, queue_no);
592774345f9SMichael S. Tsirkin         if (vector >= msix_nr_vectors_allocated(dev)) {
593774345f9SMichael S. Tsirkin             continue;
594774345f9SMichael S. Tsirkin         }
595181103cdSKONRAD Frederic         if (k->guest_notifier_mask) {
596e387f99eSMichael S. Tsirkin             kvm_virtio_pci_irqfd_release(proxy, queue_no, vector);
597f1d0f15aSMichael S. Tsirkin         }
598774345f9SMichael S. Tsirkin         kvm_virtio_pci_vq_vector_release(proxy, vector);
599774345f9SMichael S. Tsirkin     }
600774345f9SMichael S. Tsirkin     return ret;
601774345f9SMichael S. Tsirkin }
602774345f9SMichael S. Tsirkin 
603774345f9SMichael S. Tsirkin static void kvm_virtio_pci_vector_release(VirtIOPCIProxy *proxy, int nvqs)
604774345f9SMichael S. Tsirkin {
605774345f9SMichael S. Tsirkin     PCIDevice *dev = &proxy->pci_dev;
606a3fc66d9SPaolo Bonzini     VirtIODevice *vdev = virtio_bus_get_device(&proxy->bus);
607774345f9SMichael S. Tsirkin     unsigned int vector;
608774345f9SMichael S. Tsirkin     int queue_no;
609181103cdSKONRAD Frederic     VirtioDeviceClass *k = VIRTIO_DEVICE_GET_CLASS(vdev);
610774345f9SMichael S. Tsirkin 
611774345f9SMichael S. Tsirkin     for (queue_no = 0; queue_no < nvqs; queue_no++) {
612774345f9SMichael S. Tsirkin         if (!virtio_queue_get_num(vdev, queue_no)) {
613774345f9SMichael S. Tsirkin             break;
614774345f9SMichael S. Tsirkin         }
615774345f9SMichael S. Tsirkin         vector = virtio_queue_vector(vdev, queue_no);
616774345f9SMichael S. Tsirkin         if (vector >= msix_nr_vectors_allocated(dev)) {
617774345f9SMichael S. Tsirkin             continue;
618774345f9SMichael S. Tsirkin         }
619f1d0f15aSMichael S. Tsirkin         /* If guest supports masking, clean up irqfd now.
620f1d0f15aSMichael S. Tsirkin          * Otherwise, it was cleaned when masked in the frontend.
621f1d0f15aSMichael S. Tsirkin          */
622181103cdSKONRAD Frederic         if (k->guest_notifier_mask) {
623e387f99eSMichael S. Tsirkin             kvm_virtio_pci_irqfd_release(proxy, queue_no, vector);
624f1d0f15aSMichael S. Tsirkin         }
625774345f9SMichael S. Tsirkin         kvm_virtio_pci_vq_vector_release(proxy, vector);
6267d37d351SJan Kiszka     }
6277d37d351SJan Kiszka }
6287d37d351SJan Kiszka 
629a38b2c49SMichael S. Tsirkin static int virtio_pci_vq_vector_unmask(VirtIOPCIProxy *proxy,
630774345f9SMichael S. Tsirkin                                        unsigned int queue_no,
631774345f9SMichael S. Tsirkin                                        unsigned int vector,
632774345f9SMichael S. Tsirkin                                        MSIMessage msg)
633774345f9SMichael S. Tsirkin {
634a3fc66d9SPaolo Bonzini     VirtIODevice *vdev = virtio_bus_get_device(&proxy->bus);
635a3fc66d9SPaolo Bonzini     VirtioDeviceClass *k = VIRTIO_DEVICE_GET_CLASS(vdev);
636a3fc66d9SPaolo Bonzini     VirtQueue *vq = virtio_get_queue(vdev, queue_no);
637774345f9SMichael S. Tsirkin     EventNotifier *n = virtio_queue_get_guest_notifier(vq);
638a38b2c49SMichael S. Tsirkin     VirtIOIRQFD *irqfd;
63953510bfcSMichael Roth     int ret = 0;
640774345f9SMichael S. Tsirkin 
641a38b2c49SMichael S. Tsirkin     if (proxy->vector_irqfd) {
642a38b2c49SMichael S. Tsirkin         irqfd = &proxy->vector_irqfd[vector];
643774345f9SMichael S. Tsirkin         if (irqfd->msg.data != msg.data || irqfd->msg.address != msg.address) {
644774345f9SMichael S. Tsirkin             ret = kvm_irqchip_update_msi_route(kvm_state, irqfd->virq, msg);
645774345f9SMichael S. Tsirkin             if (ret < 0) {
646774345f9SMichael S. Tsirkin                 return ret;
647774345f9SMichael S. Tsirkin             }
648774345f9SMichael S. Tsirkin         }
649a38b2c49SMichael S. Tsirkin     }
650774345f9SMichael S. Tsirkin 
651f1d0f15aSMichael S. Tsirkin     /* If guest supports masking, irqfd is already setup, unmask it.
652f1d0f15aSMichael S. Tsirkin      * Otherwise, set it up now.
653f1d0f15aSMichael S. Tsirkin      */
654181103cdSKONRAD Frederic     if (k->guest_notifier_mask) {
655a3fc66d9SPaolo Bonzini         k->guest_notifier_mask(vdev, queue_no, false);
656f1d0f15aSMichael S. Tsirkin         /* Test after unmasking to avoid losing events. */
657181103cdSKONRAD Frederic         if (k->guest_notifier_pending &&
658a3fc66d9SPaolo Bonzini             k->guest_notifier_pending(vdev, queue_no)) {
659f1d0f15aSMichael S. Tsirkin             event_notifier_set(n);
660f1d0f15aSMichael S. Tsirkin         }
661f1d0f15aSMichael S. Tsirkin     } else {
662f1d0f15aSMichael S. Tsirkin         ret = kvm_virtio_pci_irqfd_use(proxy, queue_no, vector);
663f1d0f15aSMichael S. Tsirkin     }
664774345f9SMichael S. Tsirkin     return ret;
665774345f9SMichael S. Tsirkin }
666774345f9SMichael S. Tsirkin 
667a38b2c49SMichael S. Tsirkin static void virtio_pci_vq_vector_mask(VirtIOPCIProxy *proxy,
6687d37d351SJan Kiszka                                              unsigned int queue_no,
6697d37d351SJan Kiszka                                              unsigned int vector)
6707d37d351SJan Kiszka {
671a3fc66d9SPaolo Bonzini     VirtIODevice *vdev = virtio_bus_get_device(&proxy->bus);
672a3fc66d9SPaolo Bonzini     VirtioDeviceClass *k = VIRTIO_DEVICE_GET_CLASS(vdev);
673181103cdSKONRAD Frederic 
674f1d0f15aSMichael S. Tsirkin     /* If guest supports masking, keep irqfd but mask it.
675f1d0f15aSMichael S. Tsirkin      * Otherwise, clean it up now.
676f1d0f15aSMichael S. Tsirkin      */
677181103cdSKONRAD Frederic     if (k->guest_notifier_mask) {
678a3fc66d9SPaolo Bonzini         k->guest_notifier_mask(vdev, queue_no, true);
679f1d0f15aSMichael S. Tsirkin     } else {
680e387f99eSMichael S. Tsirkin         kvm_virtio_pci_irqfd_release(proxy, queue_no, vector);
681f1d0f15aSMichael S. Tsirkin     }
6827d37d351SJan Kiszka }
6837d37d351SJan Kiszka 
684a38b2c49SMichael S. Tsirkin static int virtio_pci_vector_unmask(PCIDevice *dev, unsigned vector,
6857d37d351SJan Kiszka                                     MSIMessage msg)
6867d37d351SJan Kiszka {
6877d37d351SJan Kiszka     VirtIOPCIProxy *proxy = container_of(dev, VirtIOPCIProxy, pci_dev);
688a3fc66d9SPaolo Bonzini     VirtIODevice *vdev = virtio_bus_get_device(&proxy->bus);
6897d37d351SJan Kiszka     int ret, queue_no;
6907d37d351SJan Kiszka 
6912d620f59SMichael S. Tsirkin     for (queue_no = 0; queue_no < proxy->nvqs_with_notifiers; queue_no++) {
6927d37d351SJan Kiszka         if (!virtio_queue_get_num(vdev, queue_no)) {
6937d37d351SJan Kiszka             break;
6947d37d351SJan Kiszka         }
6957d37d351SJan Kiszka         if (virtio_queue_vector(vdev, queue_no) != vector) {
6967d37d351SJan Kiszka             continue;
6977d37d351SJan Kiszka         }
698a38b2c49SMichael S. Tsirkin         ret = virtio_pci_vq_vector_unmask(proxy, queue_no, vector, msg);
6997d37d351SJan Kiszka         if (ret < 0) {
7007d37d351SJan Kiszka             goto undo;
7017d37d351SJan Kiszka         }
7027d37d351SJan Kiszka     }
7037d37d351SJan Kiszka     return 0;
7047d37d351SJan Kiszka 
7057d37d351SJan Kiszka undo:
7067d37d351SJan Kiszka     while (--queue_no >= 0) {
7077d37d351SJan Kiszka         if (virtio_queue_vector(vdev, queue_no) != vector) {
7087d37d351SJan Kiszka             continue;
7097d37d351SJan Kiszka         }
710a38b2c49SMichael S. Tsirkin         virtio_pci_vq_vector_mask(proxy, queue_no, vector);
7117d37d351SJan Kiszka     }
7127d37d351SJan Kiszka     return ret;
7137d37d351SJan Kiszka }
7147d37d351SJan Kiszka 
715a38b2c49SMichael S. Tsirkin static void virtio_pci_vector_mask(PCIDevice *dev, unsigned vector)
7167d37d351SJan Kiszka {
7177d37d351SJan Kiszka     VirtIOPCIProxy *proxy = container_of(dev, VirtIOPCIProxy, pci_dev);
718a3fc66d9SPaolo Bonzini     VirtIODevice *vdev = virtio_bus_get_device(&proxy->bus);
7197d37d351SJan Kiszka     int queue_no;
7207d37d351SJan Kiszka 
7212d620f59SMichael S. Tsirkin     for (queue_no = 0; queue_no < proxy->nvqs_with_notifiers; queue_no++) {
7227d37d351SJan Kiszka         if (!virtio_queue_get_num(vdev, queue_no)) {
7237d37d351SJan Kiszka             break;
7247d37d351SJan Kiszka         }
7257d37d351SJan Kiszka         if (virtio_queue_vector(vdev, queue_no) != vector) {
7267d37d351SJan Kiszka             continue;
7277d37d351SJan Kiszka         }
728a38b2c49SMichael S. Tsirkin         virtio_pci_vq_vector_mask(proxy, queue_no, vector);
7297d37d351SJan Kiszka     }
7307d37d351SJan Kiszka }
7317d37d351SJan Kiszka 
732a38b2c49SMichael S. Tsirkin static void virtio_pci_vector_poll(PCIDevice *dev,
73389d62be9SMichael S. Tsirkin                                    unsigned int vector_start,
73489d62be9SMichael S. Tsirkin                                    unsigned int vector_end)
73589d62be9SMichael S. Tsirkin {
73689d62be9SMichael S. Tsirkin     VirtIOPCIProxy *proxy = container_of(dev, VirtIOPCIProxy, pci_dev);
737a3fc66d9SPaolo Bonzini     VirtIODevice *vdev = virtio_bus_get_device(&proxy->bus);
738181103cdSKONRAD Frederic     VirtioDeviceClass *k = VIRTIO_DEVICE_GET_CLASS(vdev);
73989d62be9SMichael S. Tsirkin     int queue_no;
74089d62be9SMichael S. Tsirkin     unsigned int vector;
74189d62be9SMichael S. Tsirkin     EventNotifier *notifier;
74289d62be9SMichael S. Tsirkin     VirtQueue *vq;
74389d62be9SMichael S. Tsirkin 
7442d620f59SMichael S. Tsirkin     for (queue_no = 0; queue_no < proxy->nvqs_with_notifiers; queue_no++) {
74589d62be9SMichael S. Tsirkin         if (!virtio_queue_get_num(vdev, queue_no)) {
74689d62be9SMichael S. Tsirkin             break;
74789d62be9SMichael S. Tsirkin         }
74889d62be9SMichael S. Tsirkin         vector = virtio_queue_vector(vdev, queue_no);
74989d62be9SMichael S. Tsirkin         if (vector < vector_start || vector >= vector_end ||
75089d62be9SMichael S. Tsirkin             !msix_is_masked(dev, vector)) {
75189d62be9SMichael S. Tsirkin             continue;
75289d62be9SMichael S. Tsirkin         }
75389d62be9SMichael S. Tsirkin         vq = virtio_get_queue(vdev, queue_no);
75489d62be9SMichael S. Tsirkin         notifier = virtio_queue_get_guest_notifier(vq);
755181103cdSKONRAD Frederic         if (k->guest_notifier_pending) {
756181103cdSKONRAD Frederic             if (k->guest_notifier_pending(vdev, queue_no)) {
757f1d0f15aSMichael S. Tsirkin                 msix_set_pending(dev, vector);
758f1d0f15aSMichael S. Tsirkin             }
759f1d0f15aSMichael S. Tsirkin         } else if (event_notifier_test_and_clear(notifier)) {
76089d62be9SMichael S. Tsirkin             msix_set_pending(dev, vector);
76189d62be9SMichael S. Tsirkin         }
76289d62be9SMichael S. Tsirkin     }
76389d62be9SMichael S. Tsirkin }
76489d62be9SMichael S. Tsirkin 
76589d62be9SMichael S. Tsirkin static int virtio_pci_set_guest_notifier(DeviceState *d, int n, bool assign,
76689d62be9SMichael S. Tsirkin                                          bool with_irqfd)
767ade80dc8SMichael S. Tsirkin {
768d2a0ccc6SMichael S. Tsirkin     VirtIOPCIProxy *proxy = to_virtio_pci_proxy(d);
769a3fc66d9SPaolo Bonzini     VirtIODevice *vdev = virtio_bus_get_device(&proxy->bus);
770a3fc66d9SPaolo Bonzini     VirtioDeviceClass *vdc = VIRTIO_DEVICE_GET_CLASS(vdev);
771a3fc66d9SPaolo Bonzini     VirtQueue *vq = virtio_get_queue(vdev, n);
772ade80dc8SMichael S. Tsirkin     EventNotifier *notifier = virtio_queue_get_guest_notifier(vq);
773ade80dc8SMichael S. Tsirkin 
774ade80dc8SMichael S. Tsirkin     if (assign) {
775ade80dc8SMichael S. Tsirkin         int r = event_notifier_init(notifier, 0);
776ade80dc8SMichael S. Tsirkin         if (r < 0) {
777ade80dc8SMichael S. Tsirkin             return r;
778ade80dc8SMichael S. Tsirkin         }
77989d62be9SMichael S. Tsirkin         virtio_queue_set_guest_notifier_fd_handler(vq, true, with_irqfd);
780ade80dc8SMichael S. Tsirkin     } else {
78189d62be9SMichael S. Tsirkin         virtio_queue_set_guest_notifier_fd_handler(vq, false, with_irqfd);
782ade80dc8SMichael S. Tsirkin         event_notifier_cleanup(notifier);
783ade80dc8SMichael S. Tsirkin     }
784ade80dc8SMichael S. Tsirkin 
78562c96360SMichael S. Tsirkin     if (!msix_enabled(&proxy->pci_dev) && vdc->guest_notifier_mask) {
786a3fc66d9SPaolo Bonzini         vdc->guest_notifier_mask(vdev, n, !assign);
78762c96360SMichael S. Tsirkin     }
78862c96360SMichael S. Tsirkin 
789ade80dc8SMichael S. Tsirkin     return 0;
790ade80dc8SMichael S. Tsirkin }
791ade80dc8SMichael S. Tsirkin 
792d2a0ccc6SMichael S. Tsirkin static bool virtio_pci_query_guest_notifiers(DeviceState *d)
7935430a28fSmst@redhat.com {
794d2a0ccc6SMichael S. Tsirkin     VirtIOPCIProxy *proxy = to_virtio_pci_proxy(d);
7955430a28fSmst@redhat.com     return msix_enabled(&proxy->pci_dev);
7965430a28fSmst@redhat.com }
7975430a28fSmst@redhat.com 
7982d620f59SMichael S. Tsirkin static int virtio_pci_set_guest_notifiers(DeviceState *d, int nvqs, bool assign)
79954dd9321SMichael S. Tsirkin {
800d2a0ccc6SMichael S. Tsirkin     VirtIOPCIProxy *proxy = to_virtio_pci_proxy(d);
801a3fc66d9SPaolo Bonzini     VirtIODevice *vdev = virtio_bus_get_device(&proxy->bus);
802181103cdSKONRAD Frederic     VirtioDeviceClass *k = VIRTIO_DEVICE_GET_CLASS(vdev);
80354dd9321SMichael S. Tsirkin     int r, n;
80489d62be9SMichael S. Tsirkin     bool with_irqfd = msix_enabled(&proxy->pci_dev) &&
80589d62be9SMichael S. Tsirkin         kvm_msi_via_irqfd_enabled();
80654dd9321SMichael S. Tsirkin 
8072d620f59SMichael S. Tsirkin     nvqs = MIN(nvqs, VIRTIO_PCI_QUEUE_MAX);
8082d620f59SMichael S. Tsirkin 
8092d620f59SMichael S. Tsirkin     /* When deassigning, pass a consistent nvqs value
8102d620f59SMichael S. Tsirkin      * to avoid leaking notifiers.
8112d620f59SMichael S. Tsirkin      */
8122d620f59SMichael S. Tsirkin     assert(assign || nvqs == proxy->nvqs_with_notifiers);
8132d620f59SMichael S. Tsirkin 
8142d620f59SMichael S. Tsirkin     proxy->nvqs_with_notifiers = nvqs;
8152d620f59SMichael S. Tsirkin 
8167d37d351SJan Kiszka     /* Must unset vector notifier while guest notifier is still assigned */
817181103cdSKONRAD Frederic     if ((proxy->vector_irqfd || k->guest_notifier_mask) && !assign) {
8187d37d351SJan Kiszka         msix_unset_vector_notifiers(&proxy->pci_dev);
819a38b2c49SMichael S. Tsirkin         if (proxy->vector_irqfd) {
820774345f9SMichael S. Tsirkin             kvm_virtio_pci_vector_release(proxy, nvqs);
8217d37d351SJan Kiszka             g_free(proxy->vector_irqfd);
8227d37d351SJan Kiszka             proxy->vector_irqfd = NULL;
8237d37d351SJan Kiszka         }
824a38b2c49SMichael S. Tsirkin     }
8257d37d351SJan Kiszka 
8262d620f59SMichael S. Tsirkin     for (n = 0; n < nvqs; n++) {
82754dd9321SMichael S. Tsirkin         if (!virtio_queue_get_num(vdev, n)) {
82854dd9321SMichael S. Tsirkin             break;
82954dd9321SMichael S. Tsirkin         }
83054dd9321SMichael S. Tsirkin 
83123fe2b3fSMichael S. Tsirkin         r = virtio_pci_set_guest_notifier(d, n, assign, with_irqfd);
83254dd9321SMichael S. Tsirkin         if (r < 0) {
83354dd9321SMichael S. Tsirkin             goto assign_error;
83454dd9321SMichael S. Tsirkin         }
83554dd9321SMichael S. Tsirkin     }
83654dd9321SMichael S. Tsirkin 
8377d37d351SJan Kiszka     /* Must set vector notifier after guest notifier has been assigned */
838181103cdSKONRAD Frederic     if ((with_irqfd || k->guest_notifier_mask) && assign) {
839a38b2c49SMichael S. Tsirkin         if (with_irqfd) {
8407d37d351SJan Kiszka             proxy->vector_irqfd =
8417d37d351SJan Kiszka                 g_malloc0(sizeof(*proxy->vector_irqfd) *
8427d37d351SJan Kiszka                           msix_nr_vectors_allocated(&proxy->pci_dev));
843774345f9SMichael S. Tsirkin             r = kvm_virtio_pci_vector_use(proxy, nvqs);
8447d37d351SJan Kiszka             if (r < 0) {
8457d37d351SJan Kiszka                 goto assign_error;
8467d37d351SJan Kiszka             }
847a38b2c49SMichael S. Tsirkin         }
848774345f9SMichael S. Tsirkin         r = msix_set_vector_notifiers(&proxy->pci_dev,
849a38b2c49SMichael S. Tsirkin                                       virtio_pci_vector_unmask,
850a38b2c49SMichael S. Tsirkin                                       virtio_pci_vector_mask,
851a38b2c49SMichael S. Tsirkin                                       virtio_pci_vector_poll);
852774345f9SMichael S. Tsirkin         if (r < 0) {
853774345f9SMichael S. Tsirkin             goto notifiers_error;
854774345f9SMichael S. Tsirkin         }
8557d37d351SJan Kiszka     }
8567d37d351SJan Kiszka 
85754dd9321SMichael S. Tsirkin     return 0;
85854dd9321SMichael S. Tsirkin 
859774345f9SMichael S. Tsirkin notifiers_error:
860a38b2c49SMichael S. Tsirkin     if (with_irqfd) {
861774345f9SMichael S. Tsirkin         assert(assign);
862774345f9SMichael S. Tsirkin         kvm_virtio_pci_vector_release(proxy, nvqs);
863a38b2c49SMichael S. Tsirkin     }
864774345f9SMichael S. Tsirkin 
86554dd9321SMichael S. Tsirkin assign_error:
86654dd9321SMichael S. Tsirkin     /* We get here on assignment failure. Recover by undoing for VQs 0 .. n. */
8677d37d351SJan Kiszka     assert(assign);
86854dd9321SMichael S. Tsirkin     while (--n >= 0) {
86989d62be9SMichael S. Tsirkin         virtio_pci_set_guest_notifier(d, n, !assign, with_irqfd);
87054dd9321SMichael S. Tsirkin     }
87154dd9321SMichael S. Tsirkin     return r;
87254dd9321SMichael S. Tsirkin }
87354dd9321SMichael S. Tsirkin 
874d2a0ccc6SMichael S. Tsirkin static int virtio_pci_set_host_notifier(DeviceState *d, int n, bool assign)
875ade80dc8SMichael S. Tsirkin {
876d2a0ccc6SMichael S. Tsirkin     VirtIOPCIProxy *proxy = to_virtio_pci_proxy(d);
87725db9ebeSStefan Hajnoczi 
87825db9ebeSStefan Hajnoczi     /* Stop using ioeventfd for virtqueue kick if the device starts using host
87925db9ebeSStefan Hajnoczi      * notifiers.  This makes it easy to avoid stepping on each others' toes.
88025db9ebeSStefan Hajnoczi      */
88125db9ebeSStefan Hajnoczi     proxy->ioeventfd_disabled = assign;
882ade80dc8SMichael S. Tsirkin     if (assign) {
88325db9ebeSStefan Hajnoczi         virtio_pci_stop_ioeventfd(proxy);
884ade80dc8SMichael S. Tsirkin     }
88525db9ebeSStefan Hajnoczi     /* We don't need to start here: it's not needed because backend
88625db9ebeSStefan Hajnoczi      * currently only stops on status change away from ok,
88725db9ebeSStefan Hajnoczi      * reset, vmstop and such. If we do add code to start here,
88825db9ebeSStefan Hajnoczi      * need to check vmstate, device state etc. */
88926b9b5feSPaolo Bonzini     return virtio_pci_set_host_notifier_internal(proxy, n, assign, false);
890ade80dc8SMichael S. Tsirkin }
89125db9ebeSStefan Hajnoczi 
892d2a0ccc6SMichael S. Tsirkin static void virtio_pci_vmstate_change(DeviceState *d, bool running)
89325db9ebeSStefan Hajnoczi {
894d2a0ccc6SMichael S. Tsirkin     VirtIOPCIProxy *proxy = to_virtio_pci_proxy(d);
895a3fc66d9SPaolo Bonzini     VirtIODevice *vdev = virtio_bus_get_device(&proxy->bus);
89625db9ebeSStefan Hajnoczi 
89725db9ebeSStefan Hajnoczi     if (running) {
89845363e46SMichael S. Tsirkin         /* Try to find out if the guest has bus master disabled, but is
89945363e46SMichael S. Tsirkin            in ready state. Then we have a buggy guest OS. */
90045363e46SMichael S. Tsirkin         if ((vdev->status & VIRTIO_CONFIG_S_DRIVER_OK) &&
90145363e46SMichael S. Tsirkin             !(proxy->pci_dev.config[PCI_COMMAND] & PCI_COMMAND_MASTER)) {
90245363e46SMichael S. Tsirkin             proxy->flags |= VIRTIO_PCI_FLAG_BUS_MASTER_BUG;
90389c473fdSMichael S. Tsirkin         }
90425db9ebeSStefan Hajnoczi         virtio_pci_start_ioeventfd(proxy);
905ade80dc8SMichael S. Tsirkin     } else {
90625db9ebeSStefan Hajnoczi         virtio_pci_stop_ioeventfd(proxy);
907ade80dc8SMichael S. Tsirkin     }
908ade80dc8SMichael S. Tsirkin }
909ade80dc8SMichael S. Tsirkin 
91060653b28SPaolo Bonzini #ifdef CONFIG_VIRTFS
911234a336fSKONRAD Frederic static int virtio_9p_init_pci(VirtIOPCIProxy *vpci_dev)
91260653b28SPaolo Bonzini {
913234a336fSKONRAD Frederic     V9fsPCIState *dev = VIRTIO_9P_PCI(vpci_dev);
914234a336fSKONRAD Frederic     DeviceState *vdev = DEVICE(&dev->vdev);
91560653b28SPaolo Bonzini 
916234a336fSKONRAD Frederic     qdev_set_parent_bus(vdev, BUS(&vpci_dev->bus));
917234a336fSKONRAD Frederic     if (qdev_init(vdev) < 0) {
918234a336fSKONRAD Frederic         return -1;
919234a336fSKONRAD Frederic     }
92060653b28SPaolo Bonzini     return 0;
92160653b28SPaolo Bonzini }
92260653b28SPaolo Bonzini 
923234a336fSKONRAD Frederic static Property virtio_9p_pci_properties[] = {
924234a336fSKONRAD Frederic     DEFINE_PROP_BIT("ioeventfd", VirtIOPCIProxy, flags,
925234a336fSKONRAD Frederic                     VIRTIO_PCI_FLAG_USE_IOEVENTFD_BIT, true),
92660653b28SPaolo Bonzini     DEFINE_PROP_UINT32("vectors", VirtIOPCIProxy, nvectors, 2),
92760653b28SPaolo Bonzini     DEFINE_PROP_END_OF_LIST(),
92860653b28SPaolo Bonzini };
92960653b28SPaolo Bonzini 
930234a336fSKONRAD Frederic static void virtio_9p_pci_class_init(ObjectClass *klass, void *data)
93160653b28SPaolo Bonzini {
93260653b28SPaolo Bonzini     DeviceClass *dc = DEVICE_CLASS(klass);
933234a336fSKONRAD Frederic     PCIDeviceClass *pcidev_k = PCI_DEVICE_CLASS(klass);
934234a336fSKONRAD Frederic     VirtioPCIClass *k = VIRTIO_PCI_CLASS(klass);
93560653b28SPaolo Bonzini 
93660653b28SPaolo Bonzini     k->init = virtio_9p_init_pci;
937234a336fSKONRAD Frederic     pcidev_k->vendor_id = PCI_VENDOR_ID_REDHAT_QUMRANET;
938234a336fSKONRAD Frederic     pcidev_k->device_id = PCI_DEVICE_ID_VIRTIO_9P;
939234a336fSKONRAD Frederic     pcidev_k->revision = VIRTIO_PCI_ABI_VERSION;
940234a336fSKONRAD Frederic     pcidev_k->class_id = 0x2;
941125ee0edSMarcel Apfelbaum     set_bit(DEVICE_CATEGORY_STORAGE, dc->categories);
942234a336fSKONRAD Frederic     dc->props = virtio_9p_pci_properties;
94360653b28SPaolo Bonzini }
94460653b28SPaolo Bonzini 
945234a336fSKONRAD Frederic static void virtio_9p_pci_instance_init(Object *obj)
946234a336fSKONRAD Frederic {
947234a336fSKONRAD Frederic     V9fsPCIState *dev = VIRTIO_9P_PCI(obj);
948c8075cafSGonglei 
949c8075cafSGonglei     virtio_instance_init_common(obj, &dev->vdev, sizeof(dev->vdev),
950c8075cafSGonglei                                 TYPE_VIRTIO_9P);
951234a336fSKONRAD Frederic }
952234a336fSKONRAD Frederic 
953234a336fSKONRAD Frederic static const TypeInfo virtio_9p_pci_info = {
954234a336fSKONRAD Frederic     .name          = TYPE_VIRTIO_9P_PCI,
955234a336fSKONRAD Frederic     .parent        = TYPE_VIRTIO_PCI,
956234a336fSKONRAD Frederic     .instance_size = sizeof(V9fsPCIState),
957234a336fSKONRAD Frederic     .instance_init = virtio_9p_pci_instance_init,
958234a336fSKONRAD Frederic     .class_init    = virtio_9p_pci_class_init,
95960653b28SPaolo Bonzini };
960234a336fSKONRAD Frederic #endif /* CONFIG_VIRTFS */
96160653b28SPaolo Bonzini 
962085bccb7SKONRAD Frederic /*
963085bccb7SKONRAD Frederic  * virtio-pci: This is the PCIDevice which has a virtio-pci-bus.
964085bccb7SKONRAD Frederic  */
965085bccb7SKONRAD Frederic 
966085bccb7SKONRAD Frederic /* This is called by virtio-bus just after the device is plugged. */
967085bccb7SKONRAD Frederic static void virtio_pci_device_plugged(DeviceState *d)
968085bccb7SKONRAD Frederic {
969085bccb7SKONRAD Frederic     VirtIOPCIProxy *proxy = VIRTIO_PCI(d);
970085bccb7SKONRAD Frederic     VirtioBusState *bus = &proxy->bus;
971085bccb7SKONRAD Frederic     uint8_t *config;
972085bccb7SKONRAD Frederic     uint32_t size;
973085bccb7SKONRAD Frederic 
974085bccb7SKONRAD Frederic     config = proxy->pci_dev.config;
975085bccb7SKONRAD Frederic     if (proxy->class_code) {
976085bccb7SKONRAD Frederic         pci_config_set_class(config, proxy->class_code);
977085bccb7SKONRAD Frederic     }
978085bccb7SKONRAD Frederic     pci_set_word(config + PCI_SUBSYSTEM_VENDOR_ID,
979085bccb7SKONRAD Frederic                  pci_get_word(config + PCI_VENDOR_ID));
980085bccb7SKONRAD Frederic     pci_set_word(config + PCI_SUBSYSTEM_ID, virtio_bus_get_vdev_id(bus));
981085bccb7SKONRAD Frederic     config[PCI_INTERRUPT_PIN] = 1;
982085bccb7SKONRAD Frederic 
983085bccb7SKONRAD Frederic     if (proxy->nvectors &&
984085bccb7SKONRAD Frederic         msix_init_exclusive_bar(&proxy->pci_dev, proxy->nvectors, 1)) {
985c7ff5482SFam Zheng         error_report("unable to init msix vectors to %" PRIu32,
986c7ff5482SFam Zheng                      proxy->nvectors);
987085bccb7SKONRAD Frederic         proxy->nvectors = 0;
988085bccb7SKONRAD Frederic     }
989085bccb7SKONRAD Frederic 
990085bccb7SKONRAD Frederic     proxy->pci_dev.config_write = virtio_write_config;
991085bccb7SKONRAD Frederic 
992085bccb7SKONRAD Frederic     size = VIRTIO_PCI_REGION_SIZE(&proxy->pci_dev)
993085bccb7SKONRAD Frederic          + virtio_bus_get_vdev_config_len(bus);
994085bccb7SKONRAD Frederic     if (size & (size - 1)) {
995085bccb7SKONRAD Frederic         size = 1 << qemu_fls(size);
996085bccb7SKONRAD Frederic     }
997085bccb7SKONRAD Frederic 
99822fc860bSPaolo Bonzini     memory_region_init_io(&proxy->bar, OBJECT(proxy), &virtio_pci_config_ops,
99922fc860bSPaolo Bonzini                           proxy, "virtio-pci", size);
1000085bccb7SKONRAD Frederic     pci_register_bar(&proxy->pci_dev, 0, PCI_BASE_ADDRESS_SPACE_IO,
1001085bccb7SKONRAD Frederic                      &proxy->bar);
1002085bccb7SKONRAD Frederic 
1003085bccb7SKONRAD Frederic     if (!kvm_has_many_ioeventfds()) {
1004085bccb7SKONRAD Frederic         proxy->flags &= ~VIRTIO_PCI_FLAG_USE_IOEVENTFD;
1005085bccb7SKONRAD Frederic     }
1006085bccb7SKONRAD Frederic 
1007085bccb7SKONRAD Frederic     proxy->host_features |= 0x1 << VIRTIO_F_NOTIFY_ON_EMPTY;
1008085bccb7SKONRAD Frederic     proxy->host_features |= 0x1 << VIRTIO_F_BAD_FEATURE;
1009085bccb7SKONRAD Frederic     proxy->host_features = virtio_bus_get_vdev_features(bus,
1010085bccb7SKONRAD Frederic                                                       proxy->host_features);
1011085bccb7SKONRAD Frederic }
1012085bccb7SKONRAD Frederic 
101306a13073SPaolo Bonzini static void virtio_pci_device_unplugged(DeviceState *d)
101406a13073SPaolo Bonzini {
101506a13073SPaolo Bonzini     VirtIOPCIProxy *proxy = VIRTIO_PCI(d);
101606a13073SPaolo Bonzini 
101706a13073SPaolo Bonzini     virtio_pci_stop_ioeventfd(proxy);
101806a13073SPaolo Bonzini }
101906a13073SPaolo Bonzini 
1020085bccb7SKONRAD Frederic static int virtio_pci_init(PCIDevice *pci_dev)
1021085bccb7SKONRAD Frederic {
1022085bccb7SKONRAD Frederic     VirtIOPCIProxy *dev = VIRTIO_PCI(pci_dev);
1023085bccb7SKONRAD Frederic     VirtioPCIClass *k = VIRTIO_PCI_GET_CLASS(pci_dev);
1024ac7af112SAndreas Färber     virtio_pci_bus_new(&dev->bus, sizeof(dev->bus), dev);
1025085bccb7SKONRAD Frederic     if (k->init != NULL) {
1026085bccb7SKONRAD Frederic         return k->init(dev);
1027085bccb7SKONRAD Frederic     }
1028085bccb7SKONRAD Frederic     return 0;
1029085bccb7SKONRAD Frederic }
1030085bccb7SKONRAD Frederic 
1031085bccb7SKONRAD Frederic static void virtio_pci_exit(PCIDevice *pci_dev)
1032085bccb7SKONRAD Frederic {
10338b81bb3bSPaolo Bonzini     msix_uninit_exclusive_bar(pci_dev);
1034085bccb7SKONRAD Frederic }
1035085bccb7SKONRAD Frederic 
103659ccd20aSKONRAD Frederic static void virtio_pci_reset(DeviceState *qdev)
1037085bccb7SKONRAD Frederic {
1038085bccb7SKONRAD Frederic     VirtIOPCIProxy *proxy = VIRTIO_PCI(qdev);
1039085bccb7SKONRAD Frederic     VirtioBusState *bus = VIRTIO_BUS(&proxy->bus);
1040085bccb7SKONRAD Frederic     virtio_pci_stop_ioeventfd(proxy);
1041085bccb7SKONRAD Frederic     virtio_bus_reset(bus);
1042085bccb7SKONRAD Frederic     msix_unuse_all_vectors(&proxy->pci_dev);
104345363e46SMichael S. Tsirkin     proxy->flags &= ~VIRTIO_PCI_FLAG_BUS_MASTER_BUG;
1044085bccb7SKONRAD Frederic }
1045085bccb7SKONRAD Frederic 
104685d1277eSMing Lei static Property virtio_pci_properties[] = {
104785d1277eSMing Lei     DEFINE_VIRTIO_COMMON_FEATURES(VirtIOPCIProxy, host_features),
104885d1277eSMing Lei     DEFINE_PROP_END_OF_LIST(),
104985d1277eSMing Lei };
105085d1277eSMing Lei 
1051085bccb7SKONRAD Frederic static void virtio_pci_class_init(ObjectClass *klass, void *data)
1052085bccb7SKONRAD Frederic {
1053085bccb7SKONRAD Frederic     DeviceClass *dc = DEVICE_CLASS(klass);
1054085bccb7SKONRAD Frederic     PCIDeviceClass *k = PCI_DEVICE_CLASS(klass);
1055085bccb7SKONRAD Frederic 
105685d1277eSMing Lei     dc->props = virtio_pci_properties;
1057085bccb7SKONRAD Frederic     k->init = virtio_pci_init;
1058085bccb7SKONRAD Frederic     k->exit = virtio_pci_exit;
1059085bccb7SKONRAD Frederic     k->vendor_id = PCI_VENDOR_ID_REDHAT_QUMRANET;
1060085bccb7SKONRAD Frederic     k->revision = VIRTIO_PCI_ABI_VERSION;
1061085bccb7SKONRAD Frederic     k->class_id = PCI_CLASS_OTHERS;
106259ccd20aSKONRAD Frederic     dc->reset = virtio_pci_reset;
1063085bccb7SKONRAD Frederic }
1064085bccb7SKONRAD Frederic 
1065085bccb7SKONRAD Frederic static const TypeInfo virtio_pci_info = {
1066085bccb7SKONRAD Frederic     .name          = TYPE_VIRTIO_PCI,
1067085bccb7SKONRAD Frederic     .parent        = TYPE_PCI_DEVICE,
1068085bccb7SKONRAD Frederic     .instance_size = sizeof(VirtIOPCIProxy),
1069085bccb7SKONRAD Frederic     .class_init    = virtio_pci_class_init,
1070085bccb7SKONRAD Frederic     .class_size    = sizeof(VirtioPCIClass),
1071085bccb7SKONRAD Frederic     .abstract      = true,
1072085bccb7SKONRAD Frederic };
1073085bccb7SKONRAD Frederic 
1074653ced07SKONRAD Frederic /* virtio-blk-pci */
1075653ced07SKONRAD Frederic 
1076653ced07SKONRAD Frederic static Property virtio_blk_pci_properties[] = {
1077c7bcc85dSPaolo Bonzini     DEFINE_PROP_UINT32("class", VirtIOPCIProxy, class_code, 0),
1078653ced07SKONRAD Frederic     DEFINE_PROP_BIT("ioeventfd", VirtIOPCIProxy, flags,
1079653ced07SKONRAD Frederic                     VIRTIO_PCI_FLAG_USE_IOEVENTFD_BIT, true),
1080653ced07SKONRAD Frederic     DEFINE_PROP_UINT32("vectors", VirtIOPCIProxy, nvectors, 2),
1081653ced07SKONRAD Frederic     DEFINE_PROP_END_OF_LIST(),
1082653ced07SKONRAD Frederic };
1083653ced07SKONRAD Frederic 
1084653ced07SKONRAD Frederic static int virtio_blk_pci_init(VirtIOPCIProxy *vpci_dev)
1085653ced07SKONRAD Frederic {
1086653ced07SKONRAD Frederic     VirtIOBlkPCI *dev = VIRTIO_BLK_PCI(vpci_dev);
1087653ced07SKONRAD Frederic     DeviceState *vdev = DEVICE(&dev->vdev);
1088653ced07SKONRAD Frederic     qdev_set_parent_bus(vdev, BUS(&vpci_dev->bus));
1089653ced07SKONRAD Frederic     if (qdev_init(vdev) < 0) {
1090653ced07SKONRAD Frederic         return -1;
1091653ced07SKONRAD Frederic     }
1092653ced07SKONRAD Frederic     return 0;
1093653ced07SKONRAD Frederic }
1094653ced07SKONRAD Frederic 
1095653ced07SKONRAD Frederic static void virtio_blk_pci_class_init(ObjectClass *klass, void *data)
1096653ced07SKONRAD Frederic {
1097653ced07SKONRAD Frederic     DeviceClass *dc = DEVICE_CLASS(klass);
1098653ced07SKONRAD Frederic     VirtioPCIClass *k = VIRTIO_PCI_CLASS(klass);
1099653ced07SKONRAD Frederic     PCIDeviceClass *pcidev_k = PCI_DEVICE_CLASS(klass);
1100653ced07SKONRAD Frederic 
1101125ee0edSMarcel Apfelbaum     set_bit(DEVICE_CATEGORY_STORAGE, dc->categories);
1102653ced07SKONRAD Frederic     dc->props = virtio_blk_pci_properties;
1103653ced07SKONRAD Frederic     k->init = virtio_blk_pci_init;
1104653ced07SKONRAD Frederic     pcidev_k->vendor_id = PCI_VENDOR_ID_REDHAT_QUMRANET;
1105653ced07SKONRAD Frederic     pcidev_k->device_id = PCI_DEVICE_ID_VIRTIO_BLOCK;
1106653ced07SKONRAD Frederic     pcidev_k->revision = VIRTIO_PCI_ABI_VERSION;
1107653ced07SKONRAD Frederic     pcidev_k->class_id = PCI_CLASS_STORAGE_SCSI;
1108653ced07SKONRAD Frederic }
1109653ced07SKONRAD Frederic 
1110653ced07SKONRAD Frederic static void virtio_blk_pci_instance_init(Object *obj)
1111653ced07SKONRAD Frederic {
1112653ced07SKONRAD Frederic     VirtIOBlkPCI *dev = VIRTIO_BLK_PCI(obj);
1113c8075cafSGonglei 
1114c8075cafSGonglei     virtio_instance_init_common(obj, &dev->vdev, sizeof(dev->vdev),
1115c8075cafSGonglei                                 TYPE_VIRTIO_BLK);
1116467b3f33SStefan Hajnoczi     object_property_add_alias(obj, "iothread", OBJECT(&dev->vdev),"iothread",
1117467b3f33SStefan Hajnoczi                               &error_abort);
1118aeb98ddcSGonglei     object_property_add_alias(obj, "bootindex", OBJECT(&dev->vdev),
1119aeb98ddcSGonglei                               "bootindex", &error_abort);
1120653ced07SKONRAD Frederic }
1121653ced07SKONRAD Frederic 
1122653ced07SKONRAD Frederic static const TypeInfo virtio_blk_pci_info = {
1123653ced07SKONRAD Frederic     .name          = TYPE_VIRTIO_BLK_PCI,
1124653ced07SKONRAD Frederic     .parent        = TYPE_VIRTIO_PCI,
1125653ced07SKONRAD Frederic     .instance_size = sizeof(VirtIOBlkPCI),
1126653ced07SKONRAD Frederic     .instance_init = virtio_blk_pci_instance_init,
1127653ced07SKONRAD Frederic     .class_init    = virtio_blk_pci_class_init,
1128653ced07SKONRAD Frederic };
1129653ced07SKONRAD Frederic 
1130bc7b90a0SKONRAD Frederic /* virtio-scsi-pci */
1131bc7b90a0SKONRAD Frederic 
1132bc7b90a0SKONRAD Frederic static Property virtio_scsi_pci_properties[] = {
1133bc7b90a0SKONRAD Frederic     DEFINE_PROP_BIT("ioeventfd", VirtIOPCIProxy, flags,
1134bc7b90a0SKONRAD Frederic                     VIRTIO_PCI_FLAG_USE_IOEVENTFD_BIT, true),
1135bc7b90a0SKONRAD Frederic     DEFINE_PROP_UINT32("vectors", VirtIOPCIProxy, nvectors,
1136bc7b90a0SKONRAD Frederic                        DEV_NVECTORS_UNSPECIFIED),
1137bc7b90a0SKONRAD Frederic     DEFINE_VIRTIO_SCSI_FEATURES(VirtIOPCIProxy, host_features),
1138bc7b90a0SKONRAD Frederic     DEFINE_PROP_END_OF_LIST(),
1139bc7b90a0SKONRAD Frederic };
1140bc7b90a0SKONRAD Frederic 
1141bc7b90a0SKONRAD Frederic static int virtio_scsi_pci_init_pci(VirtIOPCIProxy *vpci_dev)
1142bc7b90a0SKONRAD Frederic {
1143bc7b90a0SKONRAD Frederic     VirtIOSCSIPCI *dev = VIRTIO_SCSI_PCI(vpci_dev);
1144bc7b90a0SKONRAD Frederic     DeviceState *vdev = DEVICE(&dev->vdev);
1145292c8e50SPaolo Bonzini     VirtIOSCSICommon *vs = VIRTIO_SCSI_COMMON(vdev);
11466f32a6b4SKONRAD Frederic     DeviceState *proxy = DEVICE(vpci_dev);
11476f32a6b4SKONRAD Frederic     char *bus_name;
1148bc7b90a0SKONRAD Frederic 
1149bc7b90a0SKONRAD Frederic     if (vpci_dev->nvectors == DEV_NVECTORS_UNSPECIFIED) {
1150292c8e50SPaolo Bonzini         vpci_dev->nvectors = vs->conf.num_queues + 3;
1151bc7b90a0SKONRAD Frederic     }
1152bc7b90a0SKONRAD Frederic 
11536f32a6b4SKONRAD Frederic     /*
11546f32a6b4SKONRAD Frederic      * For command line compatibility, this sets the virtio-scsi-device bus
11556f32a6b4SKONRAD Frederic      * name as before.
11566f32a6b4SKONRAD Frederic      */
11576f32a6b4SKONRAD Frederic     if (proxy->id) {
11586f32a6b4SKONRAD Frederic         bus_name = g_strdup_printf("%s.0", proxy->id);
11596f32a6b4SKONRAD Frederic         virtio_device_set_child_bus_name(VIRTIO_DEVICE(vdev), bus_name);
11606f32a6b4SKONRAD Frederic         g_free(bus_name);
11616f32a6b4SKONRAD Frederic     }
11626f32a6b4SKONRAD Frederic 
1163bc7b90a0SKONRAD Frederic     qdev_set_parent_bus(vdev, BUS(&vpci_dev->bus));
1164bc7b90a0SKONRAD Frederic     if (qdev_init(vdev) < 0) {
1165bc7b90a0SKONRAD Frederic         return -1;
1166bc7b90a0SKONRAD Frederic     }
1167bc7b90a0SKONRAD Frederic     return 0;
1168bc7b90a0SKONRAD Frederic }
1169bc7b90a0SKONRAD Frederic 
1170bc7b90a0SKONRAD Frederic static void virtio_scsi_pci_class_init(ObjectClass *klass, void *data)
1171bc7b90a0SKONRAD Frederic {
1172bc7b90a0SKONRAD Frederic     DeviceClass *dc = DEVICE_CLASS(klass);
1173bc7b90a0SKONRAD Frederic     VirtioPCIClass *k = VIRTIO_PCI_CLASS(klass);
1174bc7b90a0SKONRAD Frederic     PCIDeviceClass *pcidev_k = PCI_DEVICE_CLASS(klass);
1175bc7b90a0SKONRAD Frederic     k->init = virtio_scsi_pci_init_pci;
1176125ee0edSMarcel Apfelbaum     set_bit(DEVICE_CATEGORY_STORAGE, dc->categories);
1177bc7b90a0SKONRAD Frederic     dc->props = virtio_scsi_pci_properties;
1178bc7b90a0SKONRAD Frederic     pcidev_k->vendor_id = PCI_VENDOR_ID_REDHAT_QUMRANET;
1179bc7b90a0SKONRAD Frederic     pcidev_k->device_id = PCI_DEVICE_ID_VIRTIO_SCSI;
1180bc7b90a0SKONRAD Frederic     pcidev_k->revision = 0x00;
1181bc7b90a0SKONRAD Frederic     pcidev_k->class_id = PCI_CLASS_STORAGE_SCSI;
1182bc7b90a0SKONRAD Frederic }
1183bc7b90a0SKONRAD Frederic 
1184bc7b90a0SKONRAD Frederic static void virtio_scsi_pci_instance_init(Object *obj)
1185bc7b90a0SKONRAD Frederic {
1186bc7b90a0SKONRAD Frederic     VirtIOSCSIPCI *dev = VIRTIO_SCSI_PCI(obj);
1187c8075cafSGonglei 
1188c8075cafSGonglei     virtio_instance_init_common(obj, &dev->vdev, sizeof(dev->vdev),
1189c8075cafSGonglei                                 TYPE_VIRTIO_SCSI);
119019d339f1SFam Zheng     object_property_add_alias(obj, "iothread", OBJECT(&dev->vdev), "iothread",
119119d339f1SFam Zheng                               &error_abort);
1192bc7b90a0SKONRAD Frederic }
1193bc7b90a0SKONRAD Frederic 
1194bc7b90a0SKONRAD Frederic static const TypeInfo virtio_scsi_pci_info = {
1195bc7b90a0SKONRAD Frederic     .name          = TYPE_VIRTIO_SCSI_PCI,
1196bc7b90a0SKONRAD Frederic     .parent        = TYPE_VIRTIO_PCI,
1197bc7b90a0SKONRAD Frederic     .instance_size = sizeof(VirtIOSCSIPCI),
1198bc7b90a0SKONRAD Frederic     .instance_init = virtio_scsi_pci_instance_init,
1199bc7b90a0SKONRAD Frederic     .class_init    = virtio_scsi_pci_class_init,
1200bc7b90a0SKONRAD Frederic };
1201bc7b90a0SKONRAD Frederic 
120250787628SNicholas Bellinger /* vhost-scsi-pci */
120350787628SNicholas Bellinger 
120450787628SNicholas Bellinger #ifdef CONFIG_VHOST_SCSI
120550787628SNicholas Bellinger static Property vhost_scsi_pci_properties[] = {
120650787628SNicholas Bellinger     DEFINE_PROP_UINT32("vectors", VirtIOPCIProxy, nvectors,
120750787628SNicholas Bellinger                        DEV_NVECTORS_UNSPECIFIED),
120850787628SNicholas Bellinger     DEFINE_PROP_END_OF_LIST(),
120950787628SNicholas Bellinger };
121050787628SNicholas Bellinger 
121150787628SNicholas Bellinger static int vhost_scsi_pci_init_pci(VirtIOPCIProxy *vpci_dev)
121250787628SNicholas Bellinger {
121350787628SNicholas Bellinger     VHostSCSIPCI *dev = VHOST_SCSI_PCI(vpci_dev);
121450787628SNicholas Bellinger     DeviceState *vdev = DEVICE(&dev->vdev);
121550787628SNicholas Bellinger     VirtIOSCSICommon *vs = VIRTIO_SCSI_COMMON(vdev);
121650787628SNicholas Bellinger 
121750787628SNicholas Bellinger     if (vpci_dev->nvectors == DEV_NVECTORS_UNSPECIFIED) {
121850787628SNicholas Bellinger         vpci_dev->nvectors = vs->conf.num_queues + 3;
121950787628SNicholas Bellinger     }
122050787628SNicholas Bellinger 
122150787628SNicholas Bellinger     qdev_set_parent_bus(vdev, BUS(&vpci_dev->bus));
122250787628SNicholas Bellinger     if (qdev_init(vdev) < 0) {
122350787628SNicholas Bellinger         return -1;
122450787628SNicholas Bellinger     }
122550787628SNicholas Bellinger     return 0;
122650787628SNicholas Bellinger }
122750787628SNicholas Bellinger 
122850787628SNicholas Bellinger static void vhost_scsi_pci_class_init(ObjectClass *klass, void *data)
122950787628SNicholas Bellinger {
123050787628SNicholas Bellinger     DeviceClass *dc = DEVICE_CLASS(klass);
123150787628SNicholas Bellinger     VirtioPCIClass *k = VIRTIO_PCI_CLASS(klass);
123250787628SNicholas Bellinger     PCIDeviceClass *pcidev_k = PCI_DEVICE_CLASS(klass);
123350787628SNicholas Bellinger     k->init = vhost_scsi_pci_init_pci;
1234125ee0edSMarcel Apfelbaum     set_bit(DEVICE_CATEGORY_STORAGE, dc->categories);
123550787628SNicholas Bellinger     dc->props = vhost_scsi_pci_properties;
123650787628SNicholas Bellinger     pcidev_k->vendor_id = PCI_VENDOR_ID_REDHAT_QUMRANET;
123750787628SNicholas Bellinger     pcidev_k->device_id = PCI_DEVICE_ID_VIRTIO_SCSI;
123850787628SNicholas Bellinger     pcidev_k->revision = 0x00;
123950787628SNicholas Bellinger     pcidev_k->class_id = PCI_CLASS_STORAGE_SCSI;
124050787628SNicholas Bellinger }
124150787628SNicholas Bellinger 
124250787628SNicholas Bellinger static void vhost_scsi_pci_instance_init(Object *obj)
124350787628SNicholas Bellinger {
124450787628SNicholas Bellinger     VHostSCSIPCI *dev = VHOST_SCSI_PCI(obj);
1245c8075cafSGonglei 
1246c8075cafSGonglei     virtio_instance_init_common(obj, &dev->vdev, sizeof(dev->vdev),
1247c8075cafSGonglei                                 TYPE_VHOST_SCSI);
124850787628SNicholas Bellinger }
124950787628SNicholas Bellinger 
125050787628SNicholas Bellinger static const TypeInfo vhost_scsi_pci_info = {
125150787628SNicholas Bellinger     .name          = TYPE_VHOST_SCSI_PCI,
125250787628SNicholas Bellinger     .parent        = TYPE_VIRTIO_PCI,
125350787628SNicholas Bellinger     .instance_size = sizeof(VHostSCSIPCI),
125450787628SNicholas Bellinger     .instance_init = vhost_scsi_pci_instance_init,
125550787628SNicholas Bellinger     .class_init    = vhost_scsi_pci_class_init,
125650787628SNicholas Bellinger };
125750787628SNicholas Bellinger #endif
125850787628SNicholas Bellinger 
1259e378e88dSKONRAD Frederic /* virtio-balloon-pci */
1260e378e88dSKONRAD Frederic 
126124a6e7f4SKONRAD Frederic static void balloon_pci_stats_get_all(Object *obj, struct Visitor *v,
126224a6e7f4SKONRAD Frederic                                       void *opaque, const char *name,
126324a6e7f4SKONRAD Frederic                                       Error **errp)
126424a6e7f4SKONRAD Frederic {
126524a6e7f4SKONRAD Frederic     VirtIOBalloonPCI *dev = opaque;
126624a6e7f4SKONRAD Frederic     object_property_get(OBJECT(&dev->vdev), v, "guest-stats", errp);
126724a6e7f4SKONRAD Frederic }
126824a6e7f4SKONRAD Frederic 
126924a6e7f4SKONRAD Frederic static void balloon_pci_stats_get_poll_interval(Object *obj, struct Visitor *v,
127024a6e7f4SKONRAD Frederic                                                 void *opaque, const char *name,
127124a6e7f4SKONRAD Frederic                                                 Error **errp)
127224a6e7f4SKONRAD Frederic {
127324a6e7f4SKONRAD Frederic     VirtIOBalloonPCI *dev = opaque;
127424a6e7f4SKONRAD Frederic     object_property_get(OBJECT(&dev->vdev), v, "guest-stats-polling-interval",
127524a6e7f4SKONRAD Frederic                         errp);
127624a6e7f4SKONRAD Frederic }
127724a6e7f4SKONRAD Frederic 
127824a6e7f4SKONRAD Frederic static void balloon_pci_stats_set_poll_interval(Object *obj, struct Visitor *v,
127924a6e7f4SKONRAD Frederic                                                 void *opaque, const char *name,
128024a6e7f4SKONRAD Frederic                                                 Error **errp)
128124a6e7f4SKONRAD Frederic {
128224a6e7f4SKONRAD Frederic     VirtIOBalloonPCI *dev = opaque;
128324a6e7f4SKONRAD Frederic     object_property_set(OBJECT(&dev->vdev), v, "guest-stats-polling-interval",
128424a6e7f4SKONRAD Frederic                         errp);
128524a6e7f4SKONRAD Frederic }
128624a6e7f4SKONRAD Frederic 
1287e378e88dSKONRAD Frederic static Property virtio_balloon_pci_properties[] = {
1288c7bcc85dSPaolo Bonzini     DEFINE_PROP_UINT32("class", VirtIOPCIProxy, class_code, 0),
1289e378e88dSKONRAD Frederic     DEFINE_PROP_END_OF_LIST(),
1290e378e88dSKONRAD Frederic };
1291e378e88dSKONRAD Frederic 
1292e378e88dSKONRAD Frederic static int virtio_balloon_pci_init(VirtIOPCIProxy *vpci_dev)
1293e378e88dSKONRAD Frederic {
1294e378e88dSKONRAD Frederic     VirtIOBalloonPCI *dev = VIRTIO_BALLOON_PCI(vpci_dev);
1295e378e88dSKONRAD Frederic     DeviceState *vdev = DEVICE(&dev->vdev);
1296e378e88dSKONRAD Frederic 
1297e378e88dSKONRAD Frederic     if (vpci_dev->class_code != PCI_CLASS_OTHERS &&
1298e378e88dSKONRAD Frederic         vpci_dev->class_code != PCI_CLASS_MEMORY_RAM) { /* qemu < 1.1 */
1299e378e88dSKONRAD Frederic         vpci_dev->class_code = PCI_CLASS_OTHERS;
1300e378e88dSKONRAD Frederic     }
1301e378e88dSKONRAD Frederic 
1302e378e88dSKONRAD Frederic     qdev_set_parent_bus(vdev, BUS(&vpci_dev->bus));
1303e378e88dSKONRAD Frederic     if (qdev_init(vdev) < 0) {
1304e378e88dSKONRAD Frederic         return -1;
1305e378e88dSKONRAD Frederic     }
1306e378e88dSKONRAD Frederic     return 0;
1307e378e88dSKONRAD Frederic }
1308e378e88dSKONRAD Frederic 
1309e378e88dSKONRAD Frederic static void virtio_balloon_pci_class_init(ObjectClass *klass, void *data)
1310e378e88dSKONRAD Frederic {
1311e378e88dSKONRAD Frederic     DeviceClass *dc = DEVICE_CLASS(klass);
1312e378e88dSKONRAD Frederic     VirtioPCIClass *k = VIRTIO_PCI_CLASS(klass);
1313e378e88dSKONRAD Frederic     PCIDeviceClass *pcidev_k = PCI_DEVICE_CLASS(klass);
1314e378e88dSKONRAD Frederic     k->init = virtio_balloon_pci_init;
1315125ee0edSMarcel Apfelbaum     set_bit(DEVICE_CATEGORY_MISC, dc->categories);
1316e378e88dSKONRAD Frederic     dc->props = virtio_balloon_pci_properties;
1317e378e88dSKONRAD Frederic     pcidev_k->vendor_id = PCI_VENDOR_ID_REDHAT_QUMRANET;
1318e378e88dSKONRAD Frederic     pcidev_k->device_id = PCI_DEVICE_ID_VIRTIO_BALLOON;
1319e378e88dSKONRAD Frederic     pcidev_k->revision = VIRTIO_PCI_ABI_VERSION;
1320e378e88dSKONRAD Frederic     pcidev_k->class_id = PCI_CLASS_OTHERS;
1321e378e88dSKONRAD Frederic }
1322e378e88dSKONRAD Frederic 
1323e378e88dSKONRAD Frederic static void virtio_balloon_pci_instance_init(Object *obj)
1324e378e88dSKONRAD Frederic {
1325e378e88dSKONRAD Frederic     VirtIOBalloonPCI *dev = VIRTIO_BALLOON_PCI(obj);
1326213f0c4fSAndreas Färber     object_initialize(&dev->vdev, sizeof(dev->vdev), TYPE_VIRTIO_BALLOON);
1327e378e88dSKONRAD Frederic     object_property_add_child(obj, "virtio-backend", OBJECT(&dev->vdev), NULL);
132891ba2120SGonglei     object_unref(OBJECT(&dev->vdev));
132924a6e7f4SKONRAD Frederic     object_property_add(obj, "guest-stats", "guest statistics",
133024a6e7f4SKONRAD Frederic                         balloon_pci_stats_get_all, NULL, NULL, dev,
133124a6e7f4SKONRAD Frederic                         NULL);
133224a6e7f4SKONRAD Frederic 
133324a6e7f4SKONRAD Frederic     object_property_add(obj, "guest-stats-polling-interval", "int",
133424a6e7f4SKONRAD Frederic                         balloon_pci_stats_get_poll_interval,
133524a6e7f4SKONRAD Frederic                         balloon_pci_stats_set_poll_interval,
133624a6e7f4SKONRAD Frederic                         NULL, dev, NULL);
1337e378e88dSKONRAD Frederic }
1338e378e88dSKONRAD Frederic 
1339e378e88dSKONRAD Frederic static const TypeInfo virtio_balloon_pci_info = {
1340e378e88dSKONRAD Frederic     .name          = TYPE_VIRTIO_BALLOON_PCI,
1341e378e88dSKONRAD Frederic     .parent        = TYPE_VIRTIO_PCI,
1342e378e88dSKONRAD Frederic     .instance_size = sizeof(VirtIOBalloonPCI),
1343e378e88dSKONRAD Frederic     .instance_init = virtio_balloon_pci_instance_init,
1344e378e88dSKONRAD Frederic     .class_init    = virtio_balloon_pci_class_init,
1345e378e88dSKONRAD Frederic };
1346e378e88dSKONRAD Frederic 
1347f7f7464aSKONRAD Frederic /* virtio-serial-pci */
1348f7f7464aSKONRAD Frederic 
1349f7f7464aSKONRAD Frederic static int virtio_serial_pci_init(VirtIOPCIProxy *vpci_dev)
1350f7f7464aSKONRAD Frederic {
1351f7f7464aSKONRAD Frederic     VirtIOSerialPCI *dev = VIRTIO_SERIAL_PCI(vpci_dev);
1352f7f7464aSKONRAD Frederic     DeviceState *vdev = DEVICE(&dev->vdev);
135380270a19SKONRAD Frederic     DeviceState *proxy = DEVICE(vpci_dev);
135480270a19SKONRAD Frederic     char *bus_name;
1355f7f7464aSKONRAD Frederic 
1356f7f7464aSKONRAD Frederic     if (vpci_dev->class_code != PCI_CLASS_COMMUNICATION_OTHER &&
1357f7f7464aSKONRAD Frederic         vpci_dev->class_code != PCI_CLASS_DISPLAY_OTHER && /* qemu 0.10 */
1358f7f7464aSKONRAD Frederic         vpci_dev->class_code != PCI_CLASS_OTHERS) {        /* qemu-kvm  */
1359f7f7464aSKONRAD Frederic             vpci_dev->class_code = PCI_CLASS_COMMUNICATION_OTHER;
1360f7f7464aSKONRAD Frederic     }
1361f7f7464aSKONRAD Frederic 
1362f7f7464aSKONRAD Frederic     /* backwards-compatibility with machines that were created with
1363f7f7464aSKONRAD Frederic        DEV_NVECTORS_UNSPECIFIED */
1364f7f7464aSKONRAD Frederic     if (vpci_dev->nvectors == DEV_NVECTORS_UNSPECIFIED) {
1365f7f7464aSKONRAD Frederic         vpci_dev->nvectors = dev->vdev.serial.max_virtserial_ports + 1;
1366f7f7464aSKONRAD Frederic     }
1367f7f7464aSKONRAD Frederic 
136880270a19SKONRAD Frederic     /*
136980270a19SKONRAD Frederic      * For command line compatibility, this sets the virtio-serial-device bus
137080270a19SKONRAD Frederic      * name as before.
137180270a19SKONRAD Frederic      */
137280270a19SKONRAD Frederic     if (proxy->id) {
137380270a19SKONRAD Frederic         bus_name = g_strdup_printf("%s.0", proxy->id);
137480270a19SKONRAD Frederic         virtio_device_set_child_bus_name(VIRTIO_DEVICE(vdev), bus_name);
137580270a19SKONRAD Frederic         g_free(bus_name);
137680270a19SKONRAD Frederic     }
137780270a19SKONRAD Frederic 
1378f7f7464aSKONRAD Frederic     qdev_set_parent_bus(vdev, BUS(&vpci_dev->bus));
1379f7f7464aSKONRAD Frederic     if (qdev_init(vdev) < 0) {
1380f7f7464aSKONRAD Frederic         return -1;
1381f7f7464aSKONRAD Frederic     }
1382f7f7464aSKONRAD Frederic     return 0;
1383f7f7464aSKONRAD Frederic }
1384f7f7464aSKONRAD Frederic 
1385f7f7464aSKONRAD Frederic static Property virtio_serial_pci_properties[] = {
1386f7f7464aSKONRAD Frederic     DEFINE_PROP_BIT("ioeventfd", VirtIOPCIProxy, flags,
1387f7f7464aSKONRAD Frederic                     VIRTIO_PCI_FLAG_USE_IOEVENTFD_BIT, true),
1388f7f7464aSKONRAD Frederic     DEFINE_PROP_UINT32("vectors", VirtIOPCIProxy, nvectors, 2),
1389c7bcc85dSPaolo Bonzini     DEFINE_PROP_UINT32("class", VirtIOPCIProxy, class_code, 0),
1390f7f7464aSKONRAD Frederic     DEFINE_PROP_END_OF_LIST(),
1391f7f7464aSKONRAD Frederic };
1392f7f7464aSKONRAD Frederic 
1393f7f7464aSKONRAD Frederic static void virtio_serial_pci_class_init(ObjectClass *klass, void *data)
1394f7f7464aSKONRAD Frederic {
1395f7f7464aSKONRAD Frederic     DeviceClass *dc = DEVICE_CLASS(klass);
1396f7f7464aSKONRAD Frederic     VirtioPCIClass *k = VIRTIO_PCI_CLASS(klass);
1397f7f7464aSKONRAD Frederic     PCIDeviceClass *pcidev_k = PCI_DEVICE_CLASS(klass);
1398f7f7464aSKONRAD Frederic     k->init = virtio_serial_pci_init;
1399125ee0edSMarcel Apfelbaum     set_bit(DEVICE_CATEGORY_INPUT, dc->categories);
1400f7f7464aSKONRAD Frederic     dc->props = virtio_serial_pci_properties;
1401f7f7464aSKONRAD Frederic     pcidev_k->vendor_id = PCI_VENDOR_ID_REDHAT_QUMRANET;
1402f7f7464aSKONRAD Frederic     pcidev_k->device_id = PCI_DEVICE_ID_VIRTIO_CONSOLE;
1403f7f7464aSKONRAD Frederic     pcidev_k->revision = VIRTIO_PCI_ABI_VERSION;
1404f7f7464aSKONRAD Frederic     pcidev_k->class_id = PCI_CLASS_COMMUNICATION_OTHER;
1405f7f7464aSKONRAD Frederic }
1406f7f7464aSKONRAD Frederic 
1407f7f7464aSKONRAD Frederic static void virtio_serial_pci_instance_init(Object *obj)
1408f7f7464aSKONRAD Frederic {
1409f7f7464aSKONRAD Frederic     VirtIOSerialPCI *dev = VIRTIO_SERIAL_PCI(obj);
1410c8075cafSGonglei 
1411c8075cafSGonglei     virtio_instance_init_common(obj, &dev->vdev, sizeof(dev->vdev),
1412c8075cafSGonglei                                 TYPE_VIRTIO_SERIAL);
1413f7f7464aSKONRAD Frederic }
1414f7f7464aSKONRAD Frederic 
1415f7f7464aSKONRAD Frederic static const TypeInfo virtio_serial_pci_info = {
1416f7f7464aSKONRAD Frederic     .name          = TYPE_VIRTIO_SERIAL_PCI,
1417f7f7464aSKONRAD Frederic     .parent        = TYPE_VIRTIO_PCI,
1418f7f7464aSKONRAD Frederic     .instance_size = sizeof(VirtIOSerialPCI),
1419f7f7464aSKONRAD Frederic     .instance_init = virtio_serial_pci_instance_init,
1420f7f7464aSKONRAD Frederic     .class_init    = virtio_serial_pci_class_init,
1421f7f7464aSKONRAD Frederic };
1422f7f7464aSKONRAD Frederic 
1423e37da394SKONRAD Frederic /* virtio-net-pci */
1424e37da394SKONRAD Frederic 
1425e37da394SKONRAD Frederic static Property virtio_net_properties[] = {
1426e37da394SKONRAD Frederic     DEFINE_PROP_BIT("ioeventfd", VirtIOPCIProxy, flags,
1427e37da394SKONRAD Frederic                     VIRTIO_PCI_FLAG_USE_IOEVENTFD_BIT, false),
1428e37da394SKONRAD Frederic     DEFINE_PROP_UINT32("vectors", VirtIOPCIProxy, nvectors, 3),
1429e37da394SKONRAD Frederic     DEFINE_VIRTIO_NET_FEATURES(VirtIOPCIProxy, host_features),
1430e37da394SKONRAD Frederic     DEFINE_PROP_END_OF_LIST(),
1431e37da394SKONRAD Frederic };
1432e37da394SKONRAD Frederic 
1433e37da394SKONRAD Frederic static int virtio_net_pci_init(VirtIOPCIProxy *vpci_dev)
1434e37da394SKONRAD Frederic {
1435800ced8cSKONRAD Frederic     DeviceState *qdev = DEVICE(vpci_dev);
1436e37da394SKONRAD Frederic     VirtIONetPCI *dev = VIRTIO_NET_PCI(vpci_dev);
1437e37da394SKONRAD Frederic     DeviceState *vdev = DEVICE(&dev->vdev);
1438e37da394SKONRAD Frederic 
1439e37da394SKONRAD Frederic     virtio_net_set_config_size(&dev->vdev, vpci_dev->host_features);
1440800ced8cSKONRAD Frederic     virtio_net_set_netclient_name(&dev->vdev, qdev->id,
1441800ced8cSKONRAD Frederic                                   object_get_typename(OBJECT(qdev)));
1442e37da394SKONRAD Frederic     qdev_set_parent_bus(vdev, BUS(&vpci_dev->bus));
1443e37da394SKONRAD Frederic     if (qdev_init(vdev) < 0) {
1444e37da394SKONRAD Frederic         return -1;
1445e37da394SKONRAD Frederic     }
1446e37da394SKONRAD Frederic     return 0;
1447e37da394SKONRAD Frederic }
1448e37da394SKONRAD Frederic 
1449e37da394SKONRAD Frederic static void virtio_net_pci_class_init(ObjectClass *klass, void *data)
1450e37da394SKONRAD Frederic {
1451e37da394SKONRAD Frederic     DeviceClass *dc = DEVICE_CLASS(klass);
1452e37da394SKONRAD Frederic     PCIDeviceClass *k = PCI_DEVICE_CLASS(klass);
1453e37da394SKONRAD Frederic     VirtioPCIClass *vpciklass = VIRTIO_PCI_CLASS(klass);
1454e37da394SKONRAD Frederic 
1455e37da394SKONRAD Frederic     k->romfile = "efi-virtio.rom";
1456e37da394SKONRAD Frederic     k->vendor_id = PCI_VENDOR_ID_REDHAT_QUMRANET;
1457e37da394SKONRAD Frederic     k->device_id = PCI_DEVICE_ID_VIRTIO_NET;
1458e37da394SKONRAD Frederic     k->revision = VIRTIO_PCI_ABI_VERSION;
1459e37da394SKONRAD Frederic     k->class_id = PCI_CLASS_NETWORK_ETHERNET;
1460125ee0edSMarcel Apfelbaum     set_bit(DEVICE_CATEGORY_NETWORK, dc->categories);
1461e37da394SKONRAD Frederic     dc->props = virtio_net_properties;
1462e37da394SKONRAD Frederic     vpciklass->init = virtio_net_pci_init;
1463e37da394SKONRAD Frederic }
1464e37da394SKONRAD Frederic 
1465e37da394SKONRAD Frederic static void virtio_net_pci_instance_init(Object *obj)
1466e37da394SKONRAD Frederic {
1467e37da394SKONRAD Frederic     VirtIONetPCI *dev = VIRTIO_NET_PCI(obj);
1468c8075cafSGonglei 
1469c8075cafSGonglei     virtio_instance_init_common(obj, &dev->vdev, sizeof(dev->vdev),
1470c8075cafSGonglei                                 TYPE_VIRTIO_NET);
14710cf63c3eSGonglei     object_property_add_alias(obj, "bootindex", OBJECT(&dev->vdev),
14720cf63c3eSGonglei                               "bootindex", &error_abort);
1473e37da394SKONRAD Frederic }
1474e37da394SKONRAD Frederic 
1475e37da394SKONRAD Frederic static const TypeInfo virtio_net_pci_info = {
1476e37da394SKONRAD Frederic     .name          = TYPE_VIRTIO_NET_PCI,
1477e37da394SKONRAD Frederic     .parent        = TYPE_VIRTIO_PCI,
1478e37da394SKONRAD Frederic     .instance_size = sizeof(VirtIONetPCI),
1479e37da394SKONRAD Frederic     .instance_init = virtio_net_pci_instance_init,
1480e37da394SKONRAD Frederic     .class_init    = virtio_net_pci_class_init,
1481e37da394SKONRAD Frederic };
1482e37da394SKONRAD Frederic 
148359ccd20aSKONRAD Frederic /* virtio-rng-pci */
148459ccd20aSKONRAD Frederic 
148559ccd20aSKONRAD Frederic static Property virtio_rng_pci_properties[] = {
148659ccd20aSKONRAD Frederic     DEFINE_PROP_END_OF_LIST(),
148759ccd20aSKONRAD Frederic };
148859ccd20aSKONRAD Frederic 
148959ccd20aSKONRAD Frederic static int virtio_rng_pci_init(VirtIOPCIProxy *vpci_dev)
149059ccd20aSKONRAD Frederic {
149159ccd20aSKONRAD Frederic     VirtIORngPCI *vrng = VIRTIO_RNG_PCI(vpci_dev);
149259ccd20aSKONRAD Frederic     DeviceState *vdev = DEVICE(&vrng->vdev);
149359ccd20aSKONRAD Frederic 
149459ccd20aSKONRAD Frederic     qdev_set_parent_bus(vdev, BUS(&vpci_dev->bus));
149559ccd20aSKONRAD Frederic     if (qdev_init(vdev) < 0) {
149659ccd20aSKONRAD Frederic         return -1;
149759ccd20aSKONRAD Frederic     }
149859ccd20aSKONRAD Frederic 
149959ccd20aSKONRAD Frederic     object_property_set_link(OBJECT(vrng),
15005b456438SCole Robinson                              OBJECT(vrng->vdev.conf.rng), "rng",
150159ccd20aSKONRAD Frederic                              NULL);
150259ccd20aSKONRAD Frederic 
150359ccd20aSKONRAD Frederic     return 0;
150459ccd20aSKONRAD Frederic }
150559ccd20aSKONRAD Frederic 
150659ccd20aSKONRAD Frederic static void virtio_rng_pci_class_init(ObjectClass *klass, void *data)
150759ccd20aSKONRAD Frederic {
150859ccd20aSKONRAD Frederic     DeviceClass *dc = DEVICE_CLASS(klass);
150959ccd20aSKONRAD Frederic     VirtioPCIClass *k = VIRTIO_PCI_CLASS(klass);
151059ccd20aSKONRAD Frederic     PCIDeviceClass *pcidev_k = PCI_DEVICE_CLASS(klass);
151159ccd20aSKONRAD Frederic 
151259ccd20aSKONRAD Frederic     k->init = virtio_rng_pci_init;
1513125ee0edSMarcel Apfelbaum     set_bit(DEVICE_CATEGORY_MISC, dc->categories);
151459ccd20aSKONRAD Frederic     dc->props = virtio_rng_pci_properties;
151559ccd20aSKONRAD Frederic 
151659ccd20aSKONRAD Frederic     pcidev_k->vendor_id = PCI_VENDOR_ID_REDHAT_QUMRANET;
151759ccd20aSKONRAD Frederic     pcidev_k->device_id = PCI_DEVICE_ID_VIRTIO_RNG;
151859ccd20aSKONRAD Frederic     pcidev_k->revision = VIRTIO_PCI_ABI_VERSION;
151959ccd20aSKONRAD Frederic     pcidev_k->class_id = PCI_CLASS_OTHERS;
152059ccd20aSKONRAD Frederic }
152159ccd20aSKONRAD Frederic 
152259ccd20aSKONRAD Frederic static void virtio_rng_initfn(Object *obj)
152359ccd20aSKONRAD Frederic {
152459ccd20aSKONRAD Frederic     VirtIORngPCI *dev = VIRTIO_RNG_PCI(obj);
1525c8075cafSGonglei 
1526c8075cafSGonglei     virtio_instance_init_common(obj, &dev->vdev, sizeof(dev->vdev),
1527c8075cafSGonglei                                 TYPE_VIRTIO_RNG);
152859ccd20aSKONRAD Frederic     object_property_add_link(obj, "rng", TYPE_RNG_BACKEND,
15299561fda8SStefan Hajnoczi                              (Object **)&dev->vdev.conf.rng,
153039f72ef9SStefan Hajnoczi                              qdev_prop_allow_set_link_before_realize,
15319561fda8SStefan Hajnoczi                              OBJ_PROP_LINK_UNREF_ON_RELEASE, NULL);
153259ccd20aSKONRAD Frederic 
153359ccd20aSKONRAD Frederic }
153459ccd20aSKONRAD Frederic 
153559ccd20aSKONRAD Frederic static const TypeInfo virtio_rng_pci_info = {
153659ccd20aSKONRAD Frederic     .name          = TYPE_VIRTIO_RNG_PCI,
153759ccd20aSKONRAD Frederic     .parent        = TYPE_VIRTIO_PCI,
153859ccd20aSKONRAD Frederic     .instance_size = sizeof(VirtIORngPCI),
153959ccd20aSKONRAD Frederic     .instance_init = virtio_rng_initfn,
154059ccd20aSKONRAD Frederic     .class_init    = virtio_rng_pci_class_init,
154159ccd20aSKONRAD Frederic };
154259ccd20aSKONRAD Frederic 
15430a2acf5eSKONRAD Frederic /* virtio-pci-bus */
15440a2acf5eSKONRAD Frederic 
1545ac7af112SAndreas Färber static void virtio_pci_bus_new(VirtioBusState *bus, size_t bus_size,
1546ac7af112SAndreas Färber                                VirtIOPCIProxy *dev)
15470a2acf5eSKONRAD Frederic {
15480a2acf5eSKONRAD Frederic     DeviceState *qdev = DEVICE(dev);
1549f4dd69aaSKONRAD Frederic     char virtio_bus_name[] = "virtio-bus";
1550f4dd69aaSKONRAD Frederic 
1551fb17dfe0SAndreas Färber     qbus_create_inplace(bus, bus_size, TYPE_VIRTIO_PCI_BUS, qdev,
1552f4dd69aaSKONRAD Frederic                         virtio_bus_name);
15530a2acf5eSKONRAD Frederic }
15540a2acf5eSKONRAD Frederic 
15550a2acf5eSKONRAD Frederic static void virtio_pci_bus_class_init(ObjectClass *klass, void *data)
15560a2acf5eSKONRAD Frederic {
15570a2acf5eSKONRAD Frederic     BusClass *bus_class = BUS_CLASS(klass);
15580a2acf5eSKONRAD Frederic     VirtioBusClass *k = VIRTIO_BUS_CLASS(klass);
15590a2acf5eSKONRAD Frederic     bus_class->max_dev = 1;
15600a2acf5eSKONRAD Frederic     k->notify = virtio_pci_notify;
15610a2acf5eSKONRAD Frederic     k->save_config = virtio_pci_save_config;
15620a2acf5eSKONRAD Frederic     k->load_config = virtio_pci_load_config;
15630a2acf5eSKONRAD Frederic     k->save_queue = virtio_pci_save_queue;
15640a2acf5eSKONRAD Frederic     k->load_queue = virtio_pci_load_queue;
15650a2acf5eSKONRAD Frederic     k->get_features = virtio_pci_get_features;
15660a2acf5eSKONRAD Frederic     k->query_guest_notifiers = virtio_pci_query_guest_notifiers;
15670a2acf5eSKONRAD Frederic     k->set_host_notifier = virtio_pci_set_host_notifier;
15680a2acf5eSKONRAD Frederic     k->set_guest_notifiers = virtio_pci_set_guest_notifiers;
15690a2acf5eSKONRAD Frederic     k->vmstate_change = virtio_pci_vmstate_change;
1570085bccb7SKONRAD Frederic     k->device_plugged = virtio_pci_device_plugged;
157106a13073SPaolo Bonzini     k->device_unplugged = virtio_pci_device_unplugged;
15720a2acf5eSKONRAD Frederic }
15730a2acf5eSKONRAD Frederic 
15740a2acf5eSKONRAD Frederic static const TypeInfo virtio_pci_bus_info = {
15750a2acf5eSKONRAD Frederic     .name          = TYPE_VIRTIO_PCI_BUS,
15760a2acf5eSKONRAD Frederic     .parent        = TYPE_VIRTIO_BUS,
15770a2acf5eSKONRAD Frederic     .instance_size = sizeof(VirtioPCIBusState),
15780a2acf5eSKONRAD Frederic     .class_init    = virtio_pci_bus_class_init,
15790a2acf5eSKONRAD Frederic };
15800a2acf5eSKONRAD Frederic 
158183f7d43aSAndreas Färber static void virtio_pci_register_types(void)
158253c25ceaSPaul Brook {
158359ccd20aSKONRAD Frederic     type_register_static(&virtio_rng_pci_info);
15840a2acf5eSKONRAD Frederic     type_register_static(&virtio_pci_bus_info);
1585085bccb7SKONRAD Frederic     type_register_static(&virtio_pci_info);
158660653b28SPaolo Bonzini #ifdef CONFIG_VIRTFS
1587234a336fSKONRAD Frederic     type_register_static(&virtio_9p_pci_info);
158860653b28SPaolo Bonzini #endif
1589653ced07SKONRAD Frederic     type_register_static(&virtio_blk_pci_info);
1590bc7b90a0SKONRAD Frederic     type_register_static(&virtio_scsi_pci_info);
1591e378e88dSKONRAD Frederic     type_register_static(&virtio_balloon_pci_info);
1592f7f7464aSKONRAD Frederic     type_register_static(&virtio_serial_pci_info);
1593e37da394SKONRAD Frederic     type_register_static(&virtio_net_pci_info);
159450787628SNicholas Bellinger #ifdef CONFIG_VHOST_SCSI
159550787628SNicholas Bellinger     type_register_static(&vhost_scsi_pci_info);
159650787628SNicholas Bellinger #endif
159753c25ceaSPaul Brook }
159853c25ceaSPaul Brook 
159983f7d43aSAndreas Färber type_init(virtio_pci_register_types)
1600