xref: /qemu/hw/virtio/virtio-pci.c (revision c8075caf19b000b975349f8976958cedf7d2613a)
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"
329c17d615SPaolo Bonzini #include "sysemu/blockdev.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 
89ac7af112SAndreas Färber static void virtio_pci_bus_new(VirtioBusState *bus, size_t bus_size,
90ac7af112SAndreas Färber                                VirtIOPCIProxy *dev);
91d51fcfacSKONRAD Frederic 
9253c25ceaSPaul Brook /* virtio device */
93d2a0ccc6SMichael S. Tsirkin /* DeviceState to VirtIOPCIProxy. For use off data-path. TODO: use QOM. */
94d2a0ccc6SMichael S. Tsirkin static inline VirtIOPCIProxy *to_virtio_pci_proxy(DeviceState *d)
9553c25ceaSPaul Brook {
96d2a0ccc6SMichael S. Tsirkin     return container_of(d, VirtIOPCIProxy, pci_dev.qdev);
97d2a0ccc6SMichael S. Tsirkin }
98d2a0ccc6SMichael S. Tsirkin 
99d2a0ccc6SMichael S. Tsirkin /* DeviceState to VirtIOPCIProxy. Note: used on datapath,
100d2a0ccc6SMichael S. Tsirkin  * be careful and test performance if you change this.
101d2a0ccc6SMichael S. Tsirkin  */
102d2a0ccc6SMichael S. Tsirkin static inline VirtIOPCIProxy *to_virtio_pci_proxy_fast(DeviceState *d)
103d2a0ccc6SMichael S. Tsirkin {
104d2a0ccc6SMichael S. Tsirkin     return container_of(d, VirtIOPCIProxy, pci_dev.qdev);
105d2a0ccc6SMichael S. Tsirkin }
106d2a0ccc6SMichael S. Tsirkin 
107d2a0ccc6SMichael S. Tsirkin static void virtio_pci_notify(DeviceState *d, uint16_t vector)
108d2a0ccc6SMichael S. Tsirkin {
109d2a0ccc6SMichael S. Tsirkin     VirtIOPCIProxy *proxy = to_virtio_pci_proxy_fast(d);
110a3fc66d9SPaolo Bonzini 
111aba800a3SMichael S. Tsirkin     if (msix_enabled(&proxy->pci_dev))
112aba800a3SMichael S. Tsirkin         msix_notify(&proxy->pci_dev, vector);
113a3fc66d9SPaolo Bonzini     else {
114a3fc66d9SPaolo Bonzini         VirtIODevice *vdev = virtio_bus_get_device(&proxy->bus);
115a3fc66d9SPaolo Bonzini         pci_set_irq(&proxy->pci_dev, vdev->isr & 1);
116a3fc66d9SPaolo Bonzini     }
11753c25ceaSPaul Brook }
11853c25ceaSPaul Brook 
119d2a0ccc6SMichael S. Tsirkin static void virtio_pci_save_config(DeviceState *d, QEMUFile *f)
120ff24bd58SMichael S. Tsirkin {
121d2a0ccc6SMichael S. Tsirkin     VirtIOPCIProxy *proxy = to_virtio_pci_proxy(d);
122a3fc66d9SPaolo Bonzini     VirtIODevice *vdev = virtio_bus_get_device(&proxy->bus);
123a3fc66d9SPaolo Bonzini 
124ff24bd58SMichael S. Tsirkin     pci_device_save(&proxy->pci_dev, f);
125ff24bd58SMichael S. Tsirkin     msix_save(&proxy->pci_dev, f);
126ff24bd58SMichael S. Tsirkin     if (msix_present(&proxy->pci_dev))
127a3fc66d9SPaolo Bonzini         qemu_put_be16(f, vdev->config_vector);
128ff24bd58SMichael S. Tsirkin }
129ff24bd58SMichael S. Tsirkin 
130d2a0ccc6SMichael S. Tsirkin static void virtio_pci_save_queue(DeviceState *d, int n, QEMUFile *f)
131ff24bd58SMichael S. Tsirkin {
132d2a0ccc6SMichael S. Tsirkin     VirtIOPCIProxy *proxy = to_virtio_pci_proxy(d);
133a3fc66d9SPaolo Bonzini     VirtIODevice *vdev = virtio_bus_get_device(&proxy->bus);
134a3fc66d9SPaolo Bonzini 
135ff24bd58SMichael S. Tsirkin     if (msix_present(&proxy->pci_dev))
136a3fc66d9SPaolo Bonzini         qemu_put_be16(f, virtio_queue_vector(vdev, n));
137ff24bd58SMichael S. Tsirkin }
138ff24bd58SMichael S. Tsirkin 
139d2a0ccc6SMichael S. Tsirkin static int virtio_pci_load_config(DeviceState *d, QEMUFile *f)
140ff24bd58SMichael S. Tsirkin {
141d2a0ccc6SMichael S. Tsirkin     VirtIOPCIProxy *proxy = to_virtio_pci_proxy(d);
142a3fc66d9SPaolo Bonzini     VirtIODevice *vdev = virtio_bus_get_device(&proxy->bus);
143a3fc66d9SPaolo Bonzini 
144ff24bd58SMichael S. Tsirkin     int ret;
145ff24bd58SMichael S. Tsirkin     ret = pci_device_load(&proxy->pci_dev, f);
146e6da7680SMichael S. Tsirkin     if (ret) {
147ff24bd58SMichael S. Tsirkin         return ret;
148e6da7680SMichael S. Tsirkin     }
1493cac001eSMichael S. Tsirkin     msix_unuse_all_vectors(&proxy->pci_dev);
150ff24bd58SMichael S. Tsirkin     msix_load(&proxy->pci_dev, f);
151e6da7680SMichael S. Tsirkin     if (msix_present(&proxy->pci_dev)) {
152a3fc66d9SPaolo Bonzini         qemu_get_be16s(f, &vdev->config_vector);
153e6da7680SMichael S. Tsirkin     } else {
154a3fc66d9SPaolo Bonzini         vdev->config_vector = VIRTIO_NO_VECTOR;
155e6da7680SMichael S. Tsirkin     }
156a3fc66d9SPaolo Bonzini     if (vdev->config_vector != VIRTIO_NO_VECTOR) {
157a3fc66d9SPaolo Bonzini         return msix_vector_use(&proxy->pci_dev, vdev->config_vector);
158e6da7680SMichael S. Tsirkin     }
159ff24bd58SMichael S. Tsirkin     return 0;
160ff24bd58SMichael S. Tsirkin }
161ff24bd58SMichael S. Tsirkin 
162d2a0ccc6SMichael S. Tsirkin static int virtio_pci_load_queue(DeviceState *d, int n, QEMUFile *f)
163ff24bd58SMichael S. Tsirkin {
164d2a0ccc6SMichael S. Tsirkin     VirtIOPCIProxy *proxy = to_virtio_pci_proxy(d);
165a3fc66d9SPaolo Bonzini     VirtIODevice *vdev = virtio_bus_get_device(&proxy->bus);
166a3fc66d9SPaolo Bonzini 
167ff24bd58SMichael S. Tsirkin     uint16_t vector;
168e6da7680SMichael S. Tsirkin     if (msix_present(&proxy->pci_dev)) {
169ff24bd58SMichael S. Tsirkin         qemu_get_be16s(f, &vector);
170e6da7680SMichael S. Tsirkin     } else {
171e6da7680SMichael S. Tsirkin         vector = VIRTIO_NO_VECTOR;
172e6da7680SMichael S. Tsirkin     }
173a3fc66d9SPaolo Bonzini     virtio_queue_set_vector(vdev, n, vector);
174e6da7680SMichael S. Tsirkin     if (vector != VIRTIO_NO_VECTOR) {
175e6da7680SMichael S. Tsirkin         return msix_vector_use(&proxy->pci_dev, vector);
176e6da7680SMichael S. Tsirkin     }
177ff24bd58SMichael S. Tsirkin     return 0;
178ff24bd58SMichael S. Tsirkin }
179ff24bd58SMichael S. Tsirkin 
18025db9ebeSStefan Hajnoczi static int virtio_pci_set_host_notifier_internal(VirtIOPCIProxy *proxy,
18126b9b5feSPaolo Bonzini                                                  int n, bool assign, bool set_handler)
18225db9ebeSStefan Hajnoczi {
183a3fc66d9SPaolo Bonzini     VirtIODevice *vdev = virtio_bus_get_device(&proxy->bus);
184a3fc66d9SPaolo Bonzini     VirtQueue *vq = virtio_get_queue(vdev, n);
18525db9ebeSStefan Hajnoczi     EventNotifier *notifier = virtio_queue_get_host_notifier(vq);
186da146d0aSAvi Kivity     int r = 0;
187da146d0aSAvi Kivity 
18825db9ebeSStefan Hajnoczi     if (assign) {
18925db9ebeSStefan Hajnoczi         r = event_notifier_init(notifier, 1);
19025db9ebeSStefan Hajnoczi         if (r < 0) {
191b36e3914SMichael S. Tsirkin             error_report("%s: unable to init event notifier: %d",
192b36e3914SMichael S. Tsirkin                          __func__, r);
19325db9ebeSStefan Hajnoczi             return r;
19425db9ebeSStefan Hajnoczi         }
19526b9b5feSPaolo Bonzini         virtio_queue_set_host_notifier_fd_handler(vq, true, set_handler);
196da146d0aSAvi Kivity         memory_region_add_eventfd(&proxy->bar, VIRTIO_PCI_QUEUE_NOTIFY, 2,
197753d5e14SPaolo Bonzini                                   true, n, notifier);
19825db9ebeSStefan Hajnoczi     } else {
199da146d0aSAvi Kivity         memory_region_del_eventfd(&proxy->bar, VIRTIO_PCI_QUEUE_NOTIFY, 2,
200753d5e14SPaolo Bonzini                                   true, n, notifier);
20126b9b5feSPaolo Bonzini         virtio_queue_set_host_notifier_fd_handler(vq, false, false);
20225db9ebeSStefan Hajnoczi         event_notifier_cleanup(notifier);
20325db9ebeSStefan Hajnoczi     }
20425db9ebeSStefan Hajnoczi     return r;
20525db9ebeSStefan Hajnoczi }
20625db9ebeSStefan Hajnoczi 
207b36e3914SMichael S. Tsirkin static void virtio_pci_start_ioeventfd(VirtIOPCIProxy *proxy)
20825db9ebeSStefan Hajnoczi {
209a3fc66d9SPaolo Bonzini     VirtIODevice *vdev = virtio_bus_get_device(&proxy->bus);
21025db9ebeSStefan Hajnoczi     int n, r;
21125db9ebeSStefan Hajnoczi 
21225db9ebeSStefan Hajnoczi     if (!(proxy->flags & VIRTIO_PCI_FLAG_USE_IOEVENTFD) ||
21325db9ebeSStefan Hajnoczi         proxy->ioeventfd_disabled ||
21425db9ebeSStefan Hajnoczi         proxy->ioeventfd_started) {
215b36e3914SMichael S. Tsirkin         return;
21625db9ebeSStefan Hajnoczi     }
21725db9ebeSStefan Hajnoczi 
21825db9ebeSStefan Hajnoczi     for (n = 0; n < VIRTIO_PCI_QUEUE_MAX; n++) {
219a3fc66d9SPaolo Bonzini         if (!virtio_queue_get_num(vdev, n)) {
22025db9ebeSStefan Hajnoczi             continue;
22125db9ebeSStefan Hajnoczi         }
22225db9ebeSStefan Hajnoczi 
22326b9b5feSPaolo Bonzini         r = virtio_pci_set_host_notifier_internal(proxy, n, true, true);
22425db9ebeSStefan Hajnoczi         if (r < 0) {
22525db9ebeSStefan Hajnoczi             goto assign_error;
22625db9ebeSStefan Hajnoczi         }
22725db9ebeSStefan Hajnoczi     }
22825db9ebeSStefan Hajnoczi     proxy->ioeventfd_started = true;
229b36e3914SMichael S. Tsirkin     return;
23025db9ebeSStefan Hajnoczi 
23125db9ebeSStefan Hajnoczi assign_error:
23225db9ebeSStefan Hajnoczi     while (--n >= 0) {
233a3fc66d9SPaolo Bonzini         if (!virtio_queue_get_num(vdev, n)) {
23425db9ebeSStefan Hajnoczi             continue;
23525db9ebeSStefan Hajnoczi         }
23625db9ebeSStefan Hajnoczi 
23726b9b5feSPaolo Bonzini         r = virtio_pci_set_host_notifier_internal(proxy, n, false, false);
238b36e3914SMichael S. Tsirkin         assert(r >= 0);
23925db9ebeSStefan Hajnoczi     }
24025db9ebeSStefan Hajnoczi     proxy->ioeventfd_started = false;
241b36e3914SMichael S. Tsirkin     error_report("%s: failed. Fallback to a userspace (slower).", __func__);
24225db9ebeSStefan Hajnoczi }
24325db9ebeSStefan Hajnoczi 
244b36e3914SMichael S. Tsirkin static void virtio_pci_stop_ioeventfd(VirtIOPCIProxy *proxy)
24525db9ebeSStefan Hajnoczi {
246a3fc66d9SPaolo Bonzini     VirtIODevice *vdev = virtio_bus_get_device(&proxy->bus);
247b36e3914SMichael S. Tsirkin     int r;
24825db9ebeSStefan Hajnoczi     int n;
24925db9ebeSStefan Hajnoczi 
25025db9ebeSStefan Hajnoczi     if (!proxy->ioeventfd_started) {
251b36e3914SMichael S. Tsirkin         return;
25225db9ebeSStefan Hajnoczi     }
25325db9ebeSStefan Hajnoczi 
25425db9ebeSStefan Hajnoczi     for (n = 0; n < VIRTIO_PCI_QUEUE_MAX; n++) {
255a3fc66d9SPaolo Bonzini         if (!virtio_queue_get_num(vdev, n)) {
25625db9ebeSStefan Hajnoczi             continue;
25725db9ebeSStefan Hajnoczi         }
25825db9ebeSStefan Hajnoczi 
25926b9b5feSPaolo Bonzini         r = virtio_pci_set_host_notifier_internal(proxy, n, false, false);
260b36e3914SMichael S. Tsirkin         assert(r >= 0);
26125db9ebeSStefan Hajnoczi     }
26225db9ebeSStefan Hajnoczi     proxy->ioeventfd_started = false;
26325db9ebeSStefan Hajnoczi }
26425db9ebeSStefan Hajnoczi 
26553c25ceaSPaul Brook static void virtio_ioport_write(void *opaque, uint32_t addr, uint32_t val)
26653c25ceaSPaul Brook {
26753c25ceaSPaul Brook     VirtIOPCIProxy *proxy = opaque;
268a3fc66d9SPaolo Bonzini     VirtIODevice *vdev = virtio_bus_get_device(&proxy->bus);
269a8170e5eSAvi Kivity     hwaddr pa;
27053c25ceaSPaul Brook 
27153c25ceaSPaul Brook     switch (addr) {
27253c25ceaSPaul Brook     case VIRTIO_PCI_GUEST_FEATURES:
27353c25ceaSPaul Brook         /* Guest does not negotiate properly?  We have to assume nothing. */
27453c25ceaSPaul Brook         if (val & (1 << VIRTIO_F_BAD_FEATURE)) {
275181103cdSKONRAD Frederic             val = virtio_bus_get_vdev_bad_features(&proxy->bus);
27653c25ceaSPaul Brook         }
277ad0c9332SPaolo Bonzini         virtio_set_features(vdev, val);
27853c25ceaSPaul Brook         break;
27953c25ceaSPaul Brook     case VIRTIO_PCI_QUEUE_PFN:
280a8170e5eSAvi Kivity         pa = (hwaddr)val << VIRTIO_PCI_QUEUE_ADDR_SHIFT;
2811b8e9b27SMichael S. Tsirkin         if (pa == 0) {
28225db9ebeSStefan Hajnoczi             virtio_pci_stop_ioeventfd(proxy);
283a3fc66d9SPaolo Bonzini             virtio_reset(vdev);
2841b8e9b27SMichael S. Tsirkin             msix_unuse_all_vectors(&proxy->pci_dev);
2851b8e9b27SMichael S. Tsirkin         }
2867055e687SMichael S. Tsirkin         else
28753c25ceaSPaul Brook             virtio_queue_set_addr(vdev, vdev->queue_sel, pa);
28853c25ceaSPaul Brook         break;
28953c25ceaSPaul Brook     case VIRTIO_PCI_QUEUE_SEL:
29053c25ceaSPaul Brook         if (val < VIRTIO_PCI_QUEUE_MAX)
29153c25ceaSPaul Brook             vdev->queue_sel = val;
29253c25ceaSPaul Brook         break;
29353c25ceaSPaul Brook     case VIRTIO_PCI_QUEUE_NOTIFY:
2947157e2e2SStefan Hajnoczi         if (val < VIRTIO_PCI_QUEUE_MAX) {
29553c25ceaSPaul Brook             virtio_queue_notify(vdev, val);
2967157e2e2SStefan Hajnoczi         }
29753c25ceaSPaul Brook         break;
29853c25ceaSPaul Brook     case VIRTIO_PCI_STATUS:
29925db9ebeSStefan Hajnoczi         if (!(val & VIRTIO_CONFIG_S_DRIVER_OK)) {
30025db9ebeSStefan Hajnoczi             virtio_pci_stop_ioeventfd(proxy);
30125db9ebeSStefan Hajnoczi         }
30225db9ebeSStefan Hajnoczi 
3033e607cb5SMichael S. Tsirkin         virtio_set_status(vdev, val & 0xFF);
30425db9ebeSStefan Hajnoczi 
30525db9ebeSStefan Hajnoczi         if (val & VIRTIO_CONFIG_S_DRIVER_OK) {
30625db9ebeSStefan Hajnoczi             virtio_pci_start_ioeventfd(proxy);
30725db9ebeSStefan Hajnoczi         }
30825db9ebeSStefan Hajnoczi 
3091b8e9b27SMichael S. Tsirkin         if (vdev->status == 0) {
310a3fc66d9SPaolo Bonzini             virtio_reset(vdev);
3111b8e9b27SMichael S. Tsirkin             msix_unuse_all_vectors(&proxy->pci_dev);
3121b8e9b27SMichael S. Tsirkin         }
313c81131dbSAlexander Graf 
314e43c0b2eSMichael S. Tsirkin         /* Linux before 2.6.34 drives the device without enabling
315e43c0b2eSMichael S. Tsirkin            the PCI device bus master bit. Enable it automatically
316e43c0b2eSMichael S. Tsirkin            for the guest. This is a PCI spec violation but so is
317e43c0b2eSMichael S. Tsirkin            initiating DMA with bus master bit clear. */
318e43c0b2eSMichael S. Tsirkin         if (val == (VIRTIO_CONFIG_S_ACKNOWLEDGE | VIRTIO_CONFIG_S_DRIVER)) {
319e43c0b2eSMichael S. Tsirkin             pci_default_write_config(&proxy->pci_dev, PCI_COMMAND,
320e43c0b2eSMichael S. Tsirkin                                      proxy->pci_dev.config[PCI_COMMAND] |
321e43c0b2eSMichael S. Tsirkin                                      PCI_COMMAND_MASTER, 1);
322e43c0b2eSMichael S. Tsirkin         }
32353c25ceaSPaul Brook         break;
324aba800a3SMichael S. Tsirkin     case VIRTIO_MSI_CONFIG_VECTOR:
325aba800a3SMichael S. Tsirkin         msix_vector_unuse(&proxy->pci_dev, vdev->config_vector);
326aba800a3SMichael S. Tsirkin         /* Make it possible for guest to discover an error took place. */
327aba800a3SMichael S. Tsirkin         if (msix_vector_use(&proxy->pci_dev, val) < 0)
328aba800a3SMichael S. Tsirkin             val = VIRTIO_NO_VECTOR;
329aba800a3SMichael S. Tsirkin         vdev->config_vector = val;
330aba800a3SMichael S. Tsirkin         break;
331aba800a3SMichael S. Tsirkin     case VIRTIO_MSI_QUEUE_VECTOR:
332aba800a3SMichael S. Tsirkin         msix_vector_unuse(&proxy->pci_dev,
333aba800a3SMichael S. Tsirkin                           virtio_queue_vector(vdev, vdev->queue_sel));
334aba800a3SMichael S. Tsirkin         /* Make it possible for guest to discover an error took place. */
335aba800a3SMichael S. Tsirkin         if (msix_vector_use(&proxy->pci_dev, val) < 0)
336aba800a3SMichael S. Tsirkin             val = VIRTIO_NO_VECTOR;
337aba800a3SMichael S. Tsirkin         virtio_queue_set_vector(vdev, vdev->queue_sel, val);
338aba800a3SMichael S. Tsirkin         break;
339aba800a3SMichael S. Tsirkin     default:
3404e02d460SStefan Hajnoczi         error_report("%s: unexpected address 0x%x value 0x%x",
341aba800a3SMichael S. Tsirkin                      __func__, addr, val);
342aba800a3SMichael S. Tsirkin         break;
34353c25ceaSPaul Brook     }
34453c25ceaSPaul Brook }
34553c25ceaSPaul Brook 
346aba800a3SMichael S. Tsirkin static uint32_t virtio_ioport_read(VirtIOPCIProxy *proxy, uint32_t addr)
34753c25ceaSPaul Brook {
348a3fc66d9SPaolo Bonzini     VirtIODevice *vdev = virtio_bus_get_device(&proxy->bus);
34953c25ceaSPaul Brook     uint32_t ret = 0xFFFFFFFF;
35053c25ceaSPaul Brook 
35153c25ceaSPaul Brook     switch (addr) {
35253c25ceaSPaul Brook     case VIRTIO_PCI_HOST_FEATURES:
3538172539dSMichael S. Tsirkin         ret = proxy->host_features;
35453c25ceaSPaul Brook         break;
35553c25ceaSPaul Brook     case VIRTIO_PCI_GUEST_FEATURES:
356704a76fcSMichael S. Tsirkin         ret = vdev->guest_features;
35753c25ceaSPaul Brook         break;
35853c25ceaSPaul Brook     case VIRTIO_PCI_QUEUE_PFN:
35953c25ceaSPaul Brook         ret = virtio_queue_get_addr(vdev, vdev->queue_sel)
36053c25ceaSPaul Brook               >> VIRTIO_PCI_QUEUE_ADDR_SHIFT;
36153c25ceaSPaul Brook         break;
36253c25ceaSPaul Brook     case VIRTIO_PCI_QUEUE_NUM:
36353c25ceaSPaul Brook         ret = virtio_queue_get_num(vdev, vdev->queue_sel);
36453c25ceaSPaul Brook         break;
36553c25ceaSPaul Brook     case VIRTIO_PCI_QUEUE_SEL:
36653c25ceaSPaul Brook         ret = vdev->queue_sel;
36753c25ceaSPaul Brook         break;
36853c25ceaSPaul Brook     case VIRTIO_PCI_STATUS:
36953c25ceaSPaul Brook         ret = vdev->status;
37053c25ceaSPaul Brook         break;
37153c25ceaSPaul Brook     case VIRTIO_PCI_ISR:
37253c25ceaSPaul Brook         /* reading from the ISR also clears it. */
37353c25ceaSPaul Brook         ret = vdev->isr;
37453c25ceaSPaul Brook         vdev->isr = 0;
3759e64f8a3SMarcel Apfelbaum         pci_irq_deassert(&proxy->pci_dev);
37653c25ceaSPaul Brook         break;
377aba800a3SMichael S. Tsirkin     case VIRTIO_MSI_CONFIG_VECTOR:
378aba800a3SMichael S. Tsirkin         ret = vdev->config_vector;
379aba800a3SMichael S. Tsirkin         break;
380aba800a3SMichael S. Tsirkin     case VIRTIO_MSI_QUEUE_VECTOR:
381aba800a3SMichael S. Tsirkin         ret = virtio_queue_vector(vdev, vdev->queue_sel);
382aba800a3SMichael S. Tsirkin         break;
38353c25ceaSPaul Brook     default:
38453c25ceaSPaul Brook         break;
38553c25ceaSPaul Brook     }
38653c25ceaSPaul Brook 
38753c25ceaSPaul Brook     return ret;
38853c25ceaSPaul Brook }
38953c25ceaSPaul Brook 
390df6db5b3SAlexander Graf static uint64_t virtio_pci_config_read(void *opaque, hwaddr addr,
391df6db5b3SAlexander Graf                                        unsigned size)
39253c25ceaSPaul Brook {
39353c25ceaSPaul Brook     VirtIOPCIProxy *proxy = opaque;
394a3fc66d9SPaolo Bonzini     VirtIODevice *vdev = virtio_bus_get_device(&proxy->bus);
395aba800a3SMichael S. Tsirkin     uint32_t config = VIRTIO_PCI_CONFIG(&proxy->pci_dev);
396df6db5b3SAlexander Graf     uint64_t val = 0;
397df6db5b3SAlexander Graf     if (addr < config) {
398aba800a3SMichael S. Tsirkin         return virtio_ioport_read(proxy, addr);
39953c25ceaSPaul Brook     }
400aba800a3SMichael S. Tsirkin     addr -= config;
401df6db5b3SAlexander Graf 
402df6db5b3SAlexander Graf     switch (size) {
403df6db5b3SAlexander Graf     case 1:
404a3fc66d9SPaolo Bonzini         val = virtio_config_readb(vdev, addr);
405df6db5b3SAlexander Graf         break;
406df6db5b3SAlexander Graf     case 2:
407a3fc66d9SPaolo Bonzini         val = virtio_config_readw(vdev, addr);
408616a6552SGreg Kurz         if (virtio_is_big_endian(vdev)) {
4098e4a424bSBlue Swirl             val = bswap16(val);
4108e4a424bSBlue Swirl         }
411df6db5b3SAlexander Graf         break;
412df6db5b3SAlexander Graf     case 4:
413a3fc66d9SPaolo Bonzini         val = virtio_config_readl(vdev, addr);
414616a6552SGreg Kurz         if (virtio_is_big_endian(vdev)) {
4158e4a424bSBlue Swirl             val = bswap32(val);
4168e4a424bSBlue Swirl         }
417df6db5b3SAlexander Graf         break;
418df6db5b3SAlexander Graf     }
41982afa586SBenjamin Herrenschmidt     return val;
42053c25ceaSPaul Brook }
42153c25ceaSPaul Brook 
422df6db5b3SAlexander Graf static void virtio_pci_config_write(void *opaque, hwaddr addr,
423df6db5b3SAlexander Graf                                     uint64_t val, unsigned size)
42453c25ceaSPaul Brook {
42553c25ceaSPaul Brook     VirtIOPCIProxy *proxy = opaque;
426aba800a3SMichael S. Tsirkin     uint32_t config = VIRTIO_PCI_CONFIG(&proxy->pci_dev);
427a3fc66d9SPaolo Bonzini     VirtIODevice *vdev = virtio_bus_get_device(&proxy->bus);
428aba800a3SMichael S. Tsirkin     if (addr < config) {
429aba800a3SMichael S. Tsirkin         virtio_ioport_write(proxy, addr, val);
430aba800a3SMichael S. Tsirkin         return;
431aba800a3SMichael S. Tsirkin     }
432aba800a3SMichael S. Tsirkin     addr -= config;
433df6db5b3SAlexander Graf     /*
434df6db5b3SAlexander Graf      * Virtio-PCI is odd. Ioports are LE but config space is target native
435df6db5b3SAlexander Graf      * endian.
436df6db5b3SAlexander Graf      */
437df6db5b3SAlexander Graf     switch (size) {
438df6db5b3SAlexander Graf     case 1:
439a3fc66d9SPaolo Bonzini         virtio_config_writeb(vdev, addr, val);
440df6db5b3SAlexander Graf         break;
441df6db5b3SAlexander Graf     case 2:
442616a6552SGreg Kurz         if (virtio_is_big_endian(vdev)) {
4438e4a424bSBlue Swirl             val = bswap16(val);
4448e4a424bSBlue Swirl         }
445a3fc66d9SPaolo Bonzini         virtio_config_writew(vdev, addr, val);
446df6db5b3SAlexander Graf         break;
447df6db5b3SAlexander Graf     case 4:
448616a6552SGreg Kurz         if (virtio_is_big_endian(vdev)) {
4498e4a424bSBlue Swirl             val = bswap32(val);
4508e4a424bSBlue Swirl         }
451a3fc66d9SPaolo Bonzini         virtio_config_writel(vdev, addr, val);
452df6db5b3SAlexander Graf         break;
453df6db5b3SAlexander Graf     }
45453c25ceaSPaul Brook }
45553c25ceaSPaul Brook 
456da146d0aSAvi Kivity static const MemoryRegionOps virtio_pci_config_ops = {
457df6db5b3SAlexander Graf     .read = virtio_pci_config_read,
458df6db5b3SAlexander Graf     .write = virtio_pci_config_write,
459df6db5b3SAlexander Graf     .impl = {
460df6db5b3SAlexander Graf         .min_access_size = 1,
461df6db5b3SAlexander Graf         .max_access_size = 4,
462df6db5b3SAlexander Graf     },
4638e4a424bSBlue Swirl     .endianness = DEVICE_LITTLE_ENDIAN,
464da146d0aSAvi Kivity };
465aba800a3SMichael S. Tsirkin 
466aba800a3SMichael S. Tsirkin static void virtio_write_config(PCIDevice *pci_dev, uint32_t address,
467aba800a3SMichael S. Tsirkin                                 uint32_t val, int len)
468aba800a3SMichael S. Tsirkin {
469ed757e14SYan Vugenfirer     VirtIOPCIProxy *proxy = DO_UPCAST(VirtIOPCIProxy, pci_dev, pci_dev);
470a3fc66d9SPaolo Bonzini     VirtIODevice *vdev = virtio_bus_get_device(&proxy->bus);
471ed757e14SYan Vugenfirer 
4724d43d3f3SMichael S. Tsirkin     uint8_t cmd = proxy->pci_dev.config[PCI_COMMAND];
4734d43d3f3SMichael S. Tsirkin 
4741129714fSMichael S. Tsirkin     pci_default_write_config(pci_dev, address, val, len);
4751129714fSMichael S. Tsirkin 
4761129714fSMichael S. Tsirkin     if (range_covers_byte(address, len, PCI_COMMAND) &&
4771129714fSMichael S. Tsirkin         !(pci_dev->config[PCI_COMMAND] & PCI_COMMAND_MASTER) &&
4784d43d3f3SMichael S. Tsirkin         (cmd & PCI_COMMAND_MASTER)) {
4794d43d3f3SMichael S. Tsirkin         /* Bus driver disables bus mastering - make it act
4804d43d3f3SMichael S. Tsirkin          * as a kind of reset to render the device quiescent. */
48125db9ebeSStefan Hajnoczi         virtio_pci_stop_ioeventfd(proxy);
4824d43d3f3SMichael S. Tsirkin         virtio_reset(vdev);
4834d43d3f3SMichael S. Tsirkin         msix_unuse_all_vectors(&proxy->pci_dev);
484ed757e14SYan Vugenfirer     }
48553c25ceaSPaul Brook }
48653c25ceaSPaul Brook 
487d2a0ccc6SMichael S. Tsirkin static unsigned virtio_pci_get_features(DeviceState *d)
4886d74ca5aSMichael S. Tsirkin {
489d2a0ccc6SMichael S. Tsirkin     VirtIOPCIProxy *proxy = to_virtio_pci_proxy(d);
4908172539dSMichael S. Tsirkin     return proxy->host_features;
4916d74ca5aSMichael S. Tsirkin }
4926d74ca5aSMichael S. Tsirkin 
4937d37d351SJan Kiszka static int kvm_virtio_pci_vq_vector_use(VirtIOPCIProxy *proxy,
4947d37d351SJan Kiszka                                         unsigned int queue_no,
4957d37d351SJan Kiszka                                         unsigned int vector,
4967d37d351SJan Kiszka                                         MSIMessage msg)
4977d37d351SJan Kiszka {
4987d37d351SJan Kiszka     VirtIOIRQFD *irqfd = &proxy->vector_irqfd[vector];
49915b2bd18SPaolo Bonzini     int ret;
5007d37d351SJan Kiszka 
5017d37d351SJan Kiszka     if (irqfd->users == 0) {
5027d37d351SJan Kiszka         ret = kvm_irqchip_add_msi_route(kvm_state, msg);
5037d37d351SJan Kiszka         if (ret < 0) {
5047d37d351SJan Kiszka             return ret;
5057d37d351SJan Kiszka         }
5067d37d351SJan Kiszka         irqfd->virq = ret;
5077d37d351SJan Kiszka     }
5087d37d351SJan Kiszka     irqfd->users++;
5097d37d351SJan Kiszka     return 0;
5107d37d351SJan Kiszka }
5117d37d351SJan Kiszka 
5127d37d351SJan Kiszka static void kvm_virtio_pci_vq_vector_release(VirtIOPCIProxy *proxy,
513774345f9SMichael S. Tsirkin                                              unsigned int vector)
514774345f9SMichael S. Tsirkin {
515774345f9SMichael S. Tsirkin     VirtIOIRQFD *irqfd = &proxy->vector_irqfd[vector];
516774345f9SMichael S. Tsirkin     if (--irqfd->users == 0) {
517774345f9SMichael S. Tsirkin         kvm_irqchip_release_virq(kvm_state, irqfd->virq);
518774345f9SMichael S. Tsirkin     }
519774345f9SMichael S. Tsirkin }
520774345f9SMichael S. Tsirkin 
521f1d0f15aSMichael S. Tsirkin static int kvm_virtio_pci_irqfd_use(VirtIOPCIProxy *proxy,
522f1d0f15aSMichael S. Tsirkin                                  unsigned int queue_no,
523f1d0f15aSMichael S. Tsirkin                                  unsigned int vector)
524f1d0f15aSMichael S. Tsirkin {
525f1d0f15aSMichael S. Tsirkin     VirtIOIRQFD *irqfd = &proxy->vector_irqfd[vector];
526a3fc66d9SPaolo Bonzini     VirtIODevice *vdev = virtio_bus_get_device(&proxy->bus);
527a3fc66d9SPaolo Bonzini     VirtQueue *vq = virtio_get_queue(vdev, queue_no);
528f1d0f15aSMichael S. Tsirkin     EventNotifier *n = virtio_queue_get_guest_notifier(vq);
529f1d0f15aSMichael S. Tsirkin     int ret;
530ca916d37SVincenzo Maffione     ret = kvm_irqchip_add_irqfd_notifier(kvm_state, n, NULL, irqfd->virq);
531f1d0f15aSMichael S. Tsirkin     return ret;
532f1d0f15aSMichael S. Tsirkin }
533f1d0f15aSMichael S. Tsirkin 
534f1d0f15aSMichael S. Tsirkin static void kvm_virtio_pci_irqfd_release(VirtIOPCIProxy *proxy,
5357d37d351SJan Kiszka                                       unsigned int queue_no,
5367d37d351SJan Kiszka                                       unsigned int vector)
5377d37d351SJan Kiszka {
538a3fc66d9SPaolo Bonzini     VirtIODevice *vdev = virtio_bus_get_device(&proxy->bus);
539a3fc66d9SPaolo Bonzini     VirtQueue *vq = virtio_get_queue(vdev, queue_no);
54015b2bd18SPaolo Bonzini     EventNotifier *n = virtio_queue_get_guest_notifier(vq);
5417d37d351SJan Kiszka     VirtIOIRQFD *irqfd = &proxy->vector_irqfd[vector];
54215b2bd18SPaolo Bonzini     int ret;
5437d37d351SJan Kiszka 
544b131c74aSJan Kiszka     ret = kvm_irqchip_remove_irqfd_notifier(kvm_state, n, irqfd->virq);
5457d37d351SJan Kiszka     assert(ret == 0);
546f1d0f15aSMichael S. Tsirkin }
5477d37d351SJan Kiszka 
548774345f9SMichael S. Tsirkin static int kvm_virtio_pci_vector_use(VirtIOPCIProxy *proxy, int nvqs)
549774345f9SMichael S. Tsirkin {
550774345f9SMichael S. Tsirkin     PCIDevice *dev = &proxy->pci_dev;
551a3fc66d9SPaolo Bonzini     VirtIODevice *vdev = virtio_bus_get_device(&proxy->bus);
552181103cdSKONRAD Frederic     VirtioDeviceClass *k = VIRTIO_DEVICE_GET_CLASS(vdev);
553774345f9SMichael S. Tsirkin     unsigned int vector;
554774345f9SMichael S. Tsirkin     int ret, queue_no;
555774345f9SMichael S. Tsirkin     MSIMessage msg;
556774345f9SMichael S. Tsirkin 
557774345f9SMichael S. Tsirkin     for (queue_no = 0; queue_no < nvqs; queue_no++) {
558774345f9SMichael S. Tsirkin         if (!virtio_queue_get_num(vdev, queue_no)) {
559774345f9SMichael S. Tsirkin             break;
560774345f9SMichael S. Tsirkin         }
561774345f9SMichael S. Tsirkin         vector = virtio_queue_vector(vdev, queue_no);
562774345f9SMichael S. Tsirkin         if (vector >= msix_nr_vectors_allocated(dev)) {
563774345f9SMichael S. Tsirkin             continue;
564774345f9SMichael S. Tsirkin         }
565774345f9SMichael S. Tsirkin         msg = msix_get_message(dev, vector);
566774345f9SMichael S. Tsirkin         ret = kvm_virtio_pci_vq_vector_use(proxy, queue_no, vector, msg);
567774345f9SMichael S. Tsirkin         if (ret < 0) {
568774345f9SMichael S. Tsirkin             goto undo;
569774345f9SMichael S. Tsirkin         }
570f1d0f15aSMichael S. Tsirkin         /* If guest supports masking, set up irqfd now.
571f1d0f15aSMichael S. Tsirkin          * Otherwise, delay until unmasked in the frontend.
572f1d0f15aSMichael S. Tsirkin          */
573181103cdSKONRAD Frederic         if (k->guest_notifier_mask) {
574f1d0f15aSMichael S. Tsirkin             ret = kvm_virtio_pci_irqfd_use(proxy, queue_no, vector);
575f1d0f15aSMichael S. Tsirkin             if (ret < 0) {
576f1d0f15aSMichael S. Tsirkin                 kvm_virtio_pci_vq_vector_release(proxy, vector);
577f1d0f15aSMichael S. Tsirkin                 goto undo;
578f1d0f15aSMichael S. Tsirkin             }
579f1d0f15aSMichael S. Tsirkin         }
580774345f9SMichael S. Tsirkin     }
581774345f9SMichael S. Tsirkin     return 0;
582774345f9SMichael S. Tsirkin 
583774345f9SMichael S. Tsirkin undo:
584774345f9SMichael S. Tsirkin     while (--queue_no >= 0) {
585774345f9SMichael S. Tsirkin         vector = virtio_queue_vector(vdev, queue_no);
586774345f9SMichael S. Tsirkin         if (vector >= msix_nr_vectors_allocated(dev)) {
587774345f9SMichael S. Tsirkin             continue;
588774345f9SMichael S. Tsirkin         }
589181103cdSKONRAD Frederic         if (k->guest_notifier_mask) {
590e387f99eSMichael S. Tsirkin             kvm_virtio_pci_irqfd_release(proxy, queue_no, vector);
591f1d0f15aSMichael S. Tsirkin         }
592774345f9SMichael S. Tsirkin         kvm_virtio_pci_vq_vector_release(proxy, vector);
593774345f9SMichael S. Tsirkin     }
594774345f9SMichael S. Tsirkin     return ret;
595774345f9SMichael S. Tsirkin }
596774345f9SMichael S. Tsirkin 
597774345f9SMichael S. Tsirkin static void kvm_virtio_pci_vector_release(VirtIOPCIProxy *proxy, int nvqs)
598774345f9SMichael S. Tsirkin {
599774345f9SMichael S. Tsirkin     PCIDevice *dev = &proxy->pci_dev;
600a3fc66d9SPaolo Bonzini     VirtIODevice *vdev = virtio_bus_get_device(&proxy->bus);
601774345f9SMichael S. Tsirkin     unsigned int vector;
602774345f9SMichael S. Tsirkin     int queue_no;
603181103cdSKONRAD Frederic     VirtioDeviceClass *k = VIRTIO_DEVICE_GET_CLASS(vdev);
604774345f9SMichael S. Tsirkin 
605774345f9SMichael S. Tsirkin     for (queue_no = 0; queue_no < nvqs; queue_no++) {
606774345f9SMichael S. Tsirkin         if (!virtio_queue_get_num(vdev, queue_no)) {
607774345f9SMichael S. Tsirkin             break;
608774345f9SMichael S. Tsirkin         }
609774345f9SMichael S. Tsirkin         vector = virtio_queue_vector(vdev, queue_no);
610774345f9SMichael S. Tsirkin         if (vector >= msix_nr_vectors_allocated(dev)) {
611774345f9SMichael S. Tsirkin             continue;
612774345f9SMichael S. Tsirkin         }
613f1d0f15aSMichael S. Tsirkin         /* If guest supports masking, clean up irqfd now.
614f1d0f15aSMichael S. Tsirkin          * Otherwise, it was cleaned when masked in the frontend.
615f1d0f15aSMichael S. Tsirkin          */
616181103cdSKONRAD Frederic         if (k->guest_notifier_mask) {
617e387f99eSMichael S. Tsirkin             kvm_virtio_pci_irqfd_release(proxy, queue_no, vector);
618f1d0f15aSMichael S. Tsirkin         }
619774345f9SMichael S. Tsirkin         kvm_virtio_pci_vq_vector_release(proxy, vector);
6207d37d351SJan Kiszka     }
6217d37d351SJan Kiszka }
6227d37d351SJan Kiszka 
623a38b2c49SMichael S. Tsirkin static int virtio_pci_vq_vector_unmask(VirtIOPCIProxy *proxy,
624774345f9SMichael S. Tsirkin                                        unsigned int queue_no,
625774345f9SMichael S. Tsirkin                                        unsigned int vector,
626774345f9SMichael S. Tsirkin                                        MSIMessage msg)
627774345f9SMichael S. Tsirkin {
628a3fc66d9SPaolo Bonzini     VirtIODevice *vdev = virtio_bus_get_device(&proxy->bus);
629a3fc66d9SPaolo Bonzini     VirtioDeviceClass *k = VIRTIO_DEVICE_GET_CLASS(vdev);
630a3fc66d9SPaolo Bonzini     VirtQueue *vq = virtio_get_queue(vdev, queue_no);
631774345f9SMichael S. Tsirkin     EventNotifier *n = virtio_queue_get_guest_notifier(vq);
632a38b2c49SMichael S. Tsirkin     VirtIOIRQFD *irqfd;
63353510bfcSMichael Roth     int ret = 0;
634774345f9SMichael S. Tsirkin 
635a38b2c49SMichael S. Tsirkin     if (proxy->vector_irqfd) {
636a38b2c49SMichael S. Tsirkin         irqfd = &proxy->vector_irqfd[vector];
637774345f9SMichael S. Tsirkin         if (irqfd->msg.data != msg.data || irqfd->msg.address != msg.address) {
638774345f9SMichael S. Tsirkin             ret = kvm_irqchip_update_msi_route(kvm_state, irqfd->virq, msg);
639774345f9SMichael S. Tsirkin             if (ret < 0) {
640774345f9SMichael S. Tsirkin                 return ret;
641774345f9SMichael S. Tsirkin             }
642774345f9SMichael S. Tsirkin         }
643a38b2c49SMichael S. Tsirkin     }
644774345f9SMichael S. Tsirkin 
645f1d0f15aSMichael S. Tsirkin     /* If guest supports masking, irqfd is already setup, unmask it.
646f1d0f15aSMichael S. Tsirkin      * Otherwise, set it up now.
647f1d0f15aSMichael S. Tsirkin      */
648181103cdSKONRAD Frederic     if (k->guest_notifier_mask) {
649a3fc66d9SPaolo Bonzini         k->guest_notifier_mask(vdev, queue_no, false);
650f1d0f15aSMichael S. Tsirkin         /* Test after unmasking to avoid losing events. */
651181103cdSKONRAD Frederic         if (k->guest_notifier_pending &&
652a3fc66d9SPaolo Bonzini             k->guest_notifier_pending(vdev, queue_no)) {
653f1d0f15aSMichael S. Tsirkin             event_notifier_set(n);
654f1d0f15aSMichael S. Tsirkin         }
655f1d0f15aSMichael S. Tsirkin     } else {
656f1d0f15aSMichael S. Tsirkin         ret = kvm_virtio_pci_irqfd_use(proxy, queue_no, vector);
657f1d0f15aSMichael S. Tsirkin     }
658774345f9SMichael S. Tsirkin     return ret;
659774345f9SMichael S. Tsirkin }
660774345f9SMichael S. Tsirkin 
661a38b2c49SMichael S. Tsirkin static void virtio_pci_vq_vector_mask(VirtIOPCIProxy *proxy,
6627d37d351SJan Kiszka                                              unsigned int queue_no,
6637d37d351SJan Kiszka                                              unsigned int vector)
6647d37d351SJan Kiszka {
665a3fc66d9SPaolo Bonzini     VirtIODevice *vdev = virtio_bus_get_device(&proxy->bus);
666a3fc66d9SPaolo Bonzini     VirtioDeviceClass *k = VIRTIO_DEVICE_GET_CLASS(vdev);
667181103cdSKONRAD Frederic 
668f1d0f15aSMichael S. Tsirkin     /* If guest supports masking, keep irqfd but mask it.
669f1d0f15aSMichael S. Tsirkin      * Otherwise, clean it up now.
670f1d0f15aSMichael S. Tsirkin      */
671181103cdSKONRAD Frederic     if (k->guest_notifier_mask) {
672a3fc66d9SPaolo Bonzini         k->guest_notifier_mask(vdev, queue_no, true);
673f1d0f15aSMichael S. Tsirkin     } else {
674e387f99eSMichael S. Tsirkin         kvm_virtio_pci_irqfd_release(proxy, queue_no, vector);
675f1d0f15aSMichael S. Tsirkin     }
6767d37d351SJan Kiszka }
6777d37d351SJan Kiszka 
678a38b2c49SMichael S. Tsirkin static int virtio_pci_vector_unmask(PCIDevice *dev, unsigned vector,
6797d37d351SJan Kiszka                                     MSIMessage msg)
6807d37d351SJan Kiszka {
6817d37d351SJan Kiszka     VirtIOPCIProxy *proxy = container_of(dev, VirtIOPCIProxy, pci_dev);
682a3fc66d9SPaolo Bonzini     VirtIODevice *vdev = virtio_bus_get_device(&proxy->bus);
6837d37d351SJan Kiszka     int ret, queue_no;
6847d37d351SJan Kiszka 
6852d620f59SMichael S. Tsirkin     for (queue_no = 0; queue_no < proxy->nvqs_with_notifiers; queue_no++) {
6867d37d351SJan Kiszka         if (!virtio_queue_get_num(vdev, queue_no)) {
6877d37d351SJan Kiszka             break;
6887d37d351SJan Kiszka         }
6897d37d351SJan Kiszka         if (virtio_queue_vector(vdev, queue_no) != vector) {
6907d37d351SJan Kiszka             continue;
6917d37d351SJan Kiszka         }
692a38b2c49SMichael S. Tsirkin         ret = virtio_pci_vq_vector_unmask(proxy, queue_no, vector, msg);
6937d37d351SJan Kiszka         if (ret < 0) {
6947d37d351SJan Kiszka             goto undo;
6957d37d351SJan Kiszka         }
6967d37d351SJan Kiszka     }
6977d37d351SJan Kiszka     return 0;
6987d37d351SJan Kiszka 
6997d37d351SJan Kiszka undo:
7007d37d351SJan Kiszka     while (--queue_no >= 0) {
7017d37d351SJan Kiszka         if (virtio_queue_vector(vdev, queue_no) != vector) {
7027d37d351SJan Kiszka             continue;
7037d37d351SJan Kiszka         }
704a38b2c49SMichael S. Tsirkin         virtio_pci_vq_vector_mask(proxy, queue_no, vector);
7057d37d351SJan Kiszka     }
7067d37d351SJan Kiszka     return ret;
7077d37d351SJan Kiszka }
7087d37d351SJan Kiszka 
709a38b2c49SMichael S. Tsirkin static void virtio_pci_vector_mask(PCIDevice *dev, unsigned vector)
7107d37d351SJan Kiszka {
7117d37d351SJan Kiszka     VirtIOPCIProxy *proxy = container_of(dev, VirtIOPCIProxy, pci_dev);
712a3fc66d9SPaolo Bonzini     VirtIODevice *vdev = virtio_bus_get_device(&proxy->bus);
7137d37d351SJan Kiszka     int queue_no;
7147d37d351SJan Kiszka 
7152d620f59SMichael S. Tsirkin     for (queue_no = 0; queue_no < proxy->nvqs_with_notifiers; queue_no++) {
7167d37d351SJan Kiszka         if (!virtio_queue_get_num(vdev, queue_no)) {
7177d37d351SJan Kiszka             break;
7187d37d351SJan Kiszka         }
7197d37d351SJan Kiszka         if (virtio_queue_vector(vdev, queue_no) != vector) {
7207d37d351SJan Kiszka             continue;
7217d37d351SJan Kiszka         }
722a38b2c49SMichael S. Tsirkin         virtio_pci_vq_vector_mask(proxy, queue_no, vector);
7237d37d351SJan Kiszka     }
7247d37d351SJan Kiszka }
7257d37d351SJan Kiszka 
726a38b2c49SMichael S. Tsirkin static void virtio_pci_vector_poll(PCIDevice *dev,
72789d62be9SMichael S. Tsirkin                                    unsigned int vector_start,
72889d62be9SMichael S. Tsirkin                                    unsigned int vector_end)
72989d62be9SMichael S. Tsirkin {
73089d62be9SMichael S. Tsirkin     VirtIOPCIProxy *proxy = container_of(dev, VirtIOPCIProxy, pci_dev);
731a3fc66d9SPaolo Bonzini     VirtIODevice *vdev = virtio_bus_get_device(&proxy->bus);
732181103cdSKONRAD Frederic     VirtioDeviceClass *k = VIRTIO_DEVICE_GET_CLASS(vdev);
73389d62be9SMichael S. Tsirkin     int queue_no;
73489d62be9SMichael S. Tsirkin     unsigned int vector;
73589d62be9SMichael S. Tsirkin     EventNotifier *notifier;
73689d62be9SMichael S. Tsirkin     VirtQueue *vq;
73789d62be9SMichael S. Tsirkin 
7382d620f59SMichael S. Tsirkin     for (queue_no = 0; queue_no < proxy->nvqs_with_notifiers; queue_no++) {
73989d62be9SMichael S. Tsirkin         if (!virtio_queue_get_num(vdev, queue_no)) {
74089d62be9SMichael S. Tsirkin             break;
74189d62be9SMichael S. Tsirkin         }
74289d62be9SMichael S. Tsirkin         vector = virtio_queue_vector(vdev, queue_no);
74389d62be9SMichael S. Tsirkin         if (vector < vector_start || vector >= vector_end ||
74489d62be9SMichael S. Tsirkin             !msix_is_masked(dev, vector)) {
74589d62be9SMichael S. Tsirkin             continue;
74689d62be9SMichael S. Tsirkin         }
74789d62be9SMichael S. Tsirkin         vq = virtio_get_queue(vdev, queue_no);
74889d62be9SMichael S. Tsirkin         notifier = virtio_queue_get_guest_notifier(vq);
749181103cdSKONRAD Frederic         if (k->guest_notifier_pending) {
750181103cdSKONRAD Frederic             if (k->guest_notifier_pending(vdev, queue_no)) {
751f1d0f15aSMichael S. Tsirkin                 msix_set_pending(dev, vector);
752f1d0f15aSMichael S. Tsirkin             }
753f1d0f15aSMichael S. Tsirkin         } else if (event_notifier_test_and_clear(notifier)) {
75489d62be9SMichael S. Tsirkin             msix_set_pending(dev, vector);
75589d62be9SMichael S. Tsirkin         }
75689d62be9SMichael S. Tsirkin     }
75789d62be9SMichael S. Tsirkin }
75889d62be9SMichael S. Tsirkin 
75989d62be9SMichael S. Tsirkin static int virtio_pci_set_guest_notifier(DeviceState *d, int n, bool assign,
76089d62be9SMichael S. Tsirkin                                          bool with_irqfd)
761ade80dc8SMichael S. Tsirkin {
762d2a0ccc6SMichael S. Tsirkin     VirtIOPCIProxy *proxy = to_virtio_pci_proxy(d);
763a3fc66d9SPaolo Bonzini     VirtIODevice *vdev = virtio_bus_get_device(&proxy->bus);
764a3fc66d9SPaolo Bonzini     VirtioDeviceClass *vdc = VIRTIO_DEVICE_GET_CLASS(vdev);
765a3fc66d9SPaolo Bonzini     VirtQueue *vq = virtio_get_queue(vdev, n);
766ade80dc8SMichael S. Tsirkin     EventNotifier *notifier = virtio_queue_get_guest_notifier(vq);
767ade80dc8SMichael S. Tsirkin 
768ade80dc8SMichael S. Tsirkin     if (assign) {
769ade80dc8SMichael S. Tsirkin         int r = event_notifier_init(notifier, 0);
770ade80dc8SMichael S. Tsirkin         if (r < 0) {
771ade80dc8SMichael S. Tsirkin             return r;
772ade80dc8SMichael S. Tsirkin         }
77389d62be9SMichael S. Tsirkin         virtio_queue_set_guest_notifier_fd_handler(vq, true, with_irqfd);
774ade80dc8SMichael S. Tsirkin     } else {
77589d62be9SMichael S. Tsirkin         virtio_queue_set_guest_notifier_fd_handler(vq, false, with_irqfd);
776ade80dc8SMichael S. Tsirkin         event_notifier_cleanup(notifier);
777ade80dc8SMichael S. Tsirkin     }
778ade80dc8SMichael S. Tsirkin 
77962c96360SMichael S. Tsirkin     if (!msix_enabled(&proxy->pci_dev) && vdc->guest_notifier_mask) {
780a3fc66d9SPaolo Bonzini         vdc->guest_notifier_mask(vdev, n, !assign);
78162c96360SMichael S. Tsirkin     }
78262c96360SMichael S. Tsirkin 
783ade80dc8SMichael S. Tsirkin     return 0;
784ade80dc8SMichael S. Tsirkin }
785ade80dc8SMichael S. Tsirkin 
786d2a0ccc6SMichael S. Tsirkin static bool virtio_pci_query_guest_notifiers(DeviceState *d)
7875430a28fSmst@redhat.com {
788d2a0ccc6SMichael S. Tsirkin     VirtIOPCIProxy *proxy = to_virtio_pci_proxy(d);
7895430a28fSmst@redhat.com     return msix_enabled(&proxy->pci_dev);
7905430a28fSmst@redhat.com }
7915430a28fSmst@redhat.com 
7922d620f59SMichael S. Tsirkin static int virtio_pci_set_guest_notifiers(DeviceState *d, int nvqs, bool assign)
79354dd9321SMichael S. Tsirkin {
794d2a0ccc6SMichael S. Tsirkin     VirtIOPCIProxy *proxy = to_virtio_pci_proxy(d);
795a3fc66d9SPaolo Bonzini     VirtIODevice *vdev = virtio_bus_get_device(&proxy->bus);
796181103cdSKONRAD Frederic     VirtioDeviceClass *k = VIRTIO_DEVICE_GET_CLASS(vdev);
79754dd9321SMichael S. Tsirkin     int r, n;
79889d62be9SMichael S. Tsirkin     bool with_irqfd = msix_enabled(&proxy->pci_dev) &&
79989d62be9SMichael S. Tsirkin         kvm_msi_via_irqfd_enabled();
80054dd9321SMichael S. Tsirkin 
8012d620f59SMichael S. Tsirkin     nvqs = MIN(nvqs, VIRTIO_PCI_QUEUE_MAX);
8022d620f59SMichael S. Tsirkin 
8032d620f59SMichael S. Tsirkin     /* When deassigning, pass a consistent nvqs value
8042d620f59SMichael S. Tsirkin      * to avoid leaking notifiers.
8052d620f59SMichael S. Tsirkin      */
8062d620f59SMichael S. Tsirkin     assert(assign || nvqs == proxy->nvqs_with_notifiers);
8072d620f59SMichael S. Tsirkin 
8082d620f59SMichael S. Tsirkin     proxy->nvqs_with_notifiers = nvqs;
8092d620f59SMichael S. Tsirkin 
8107d37d351SJan Kiszka     /* Must unset vector notifier while guest notifier is still assigned */
811181103cdSKONRAD Frederic     if ((proxy->vector_irqfd || k->guest_notifier_mask) && !assign) {
8127d37d351SJan Kiszka         msix_unset_vector_notifiers(&proxy->pci_dev);
813a38b2c49SMichael S. Tsirkin         if (proxy->vector_irqfd) {
814774345f9SMichael S. Tsirkin             kvm_virtio_pci_vector_release(proxy, nvqs);
8157d37d351SJan Kiszka             g_free(proxy->vector_irqfd);
8167d37d351SJan Kiszka             proxy->vector_irqfd = NULL;
8177d37d351SJan Kiszka         }
818a38b2c49SMichael S. Tsirkin     }
8197d37d351SJan Kiszka 
8202d620f59SMichael S. Tsirkin     for (n = 0; n < nvqs; n++) {
82154dd9321SMichael S. Tsirkin         if (!virtio_queue_get_num(vdev, n)) {
82254dd9321SMichael S. Tsirkin             break;
82354dd9321SMichael S. Tsirkin         }
82454dd9321SMichael S. Tsirkin 
82523fe2b3fSMichael S. Tsirkin         r = virtio_pci_set_guest_notifier(d, n, assign, with_irqfd);
82654dd9321SMichael S. Tsirkin         if (r < 0) {
82754dd9321SMichael S. Tsirkin             goto assign_error;
82854dd9321SMichael S. Tsirkin         }
82954dd9321SMichael S. Tsirkin     }
83054dd9321SMichael S. Tsirkin 
8317d37d351SJan Kiszka     /* Must set vector notifier after guest notifier has been assigned */
832181103cdSKONRAD Frederic     if ((with_irqfd || k->guest_notifier_mask) && assign) {
833a38b2c49SMichael S. Tsirkin         if (with_irqfd) {
8347d37d351SJan Kiszka             proxy->vector_irqfd =
8357d37d351SJan Kiszka                 g_malloc0(sizeof(*proxy->vector_irqfd) *
8367d37d351SJan Kiszka                           msix_nr_vectors_allocated(&proxy->pci_dev));
837774345f9SMichael S. Tsirkin             r = kvm_virtio_pci_vector_use(proxy, nvqs);
8387d37d351SJan Kiszka             if (r < 0) {
8397d37d351SJan Kiszka                 goto assign_error;
8407d37d351SJan Kiszka             }
841a38b2c49SMichael S. Tsirkin         }
842774345f9SMichael S. Tsirkin         r = msix_set_vector_notifiers(&proxy->pci_dev,
843a38b2c49SMichael S. Tsirkin                                       virtio_pci_vector_unmask,
844a38b2c49SMichael S. Tsirkin                                       virtio_pci_vector_mask,
845a38b2c49SMichael S. Tsirkin                                       virtio_pci_vector_poll);
846774345f9SMichael S. Tsirkin         if (r < 0) {
847774345f9SMichael S. Tsirkin             goto notifiers_error;
848774345f9SMichael S. Tsirkin         }
8497d37d351SJan Kiszka     }
8507d37d351SJan Kiszka 
85154dd9321SMichael S. Tsirkin     return 0;
85254dd9321SMichael S. Tsirkin 
853774345f9SMichael S. Tsirkin notifiers_error:
854a38b2c49SMichael S. Tsirkin     if (with_irqfd) {
855774345f9SMichael S. Tsirkin         assert(assign);
856774345f9SMichael S. Tsirkin         kvm_virtio_pci_vector_release(proxy, nvqs);
857a38b2c49SMichael S. Tsirkin     }
858774345f9SMichael S. Tsirkin 
85954dd9321SMichael S. Tsirkin assign_error:
86054dd9321SMichael S. Tsirkin     /* We get here on assignment failure. Recover by undoing for VQs 0 .. n. */
8617d37d351SJan Kiszka     assert(assign);
86254dd9321SMichael S. Tsirkin     while (--n >= 0) {
86389d62be9SMichael S. Tsirkin         virtio_pci_set_guest_notifier(d, n, !assign, with_irqfd);
86454dd9321SMichael S. Tsirkin     }
86554dd9321SMichael S. Tsirkin     return r;
86654dd9321SMichael S. Tsirkin }
86754dd9321SMichael S. Tsirkin 
868d2a0ccc6SMichael S. Tsirkin static int virtio_pci_set_host_notifier(DeviceState *d, int n, bool assign)
869ade80dc8SMichael S. Tsirkin {
870d2a0ccc6SMichael S. Tsirkin     VirtIOPCIProxy *proxy = to_virtio_pci_proxy(d);
87125db9ebeSStefan Hajnoczi 
87225db9ebeSStefan Hajnoczi     /* Stop using ioeventfd for virtqueue kick if the device starts using host
87325db9ebeSStefan Hajnoczi      * notifiers.  This makes it easy to avoid stepping on each others' toes.
87425db9ebeSStefan Hajnoczi      */
87525db9ebeSStefan Hajnoczi     proxy->ioeventfd_disabled = assign;
876ade80dc8SMichael S. Tsirkin     if (assign) {
87725db9ebeSStefan Hajnoczi         virtio_pci_stop_ioeventfd(proxy);
878ade80dc8SMichael S. Tsirkin     }
87925db9ebeSStefan Hajnoczi     /* We don't need to start here: it's not needed because backend
88025db9ebeSStefan Hajnoczi      * currently only stops on status change away from ok,
88125db9ebeSStefan Hajnoczi      * reset, vmstop and such. If we do add code to start here,
88225db9ebeSStefan Hajnoczi      * need to check vmstate, device state etc. */
88326b9b5feSPaolo Bonzini     return virtio_pci_set_host_notifier_internal(proxy, n, assign, false);
884ade80dc8SMichael S. Tsirkin }
88525db9ebeSStefan Hajnoczi 
886d2a0ccc6SMichael S. Tsirkin static void virtio_pci_vmstate_change(DeviceState *d, bool running)
88725db9ebeSStefan Hajnoczi {
888d2a0ccc6SMichael S. Tsirkin     VirtIOPCIProxy *proxy = to_virtio_pci_proxy(d);
889a3fc66d9SPaolo Bonzini     VirtIODevice *vdev = virtio_bus_get_device(&proxy->bus);
89025db9ebeSStefan Hajnoczi 
89125db9ebeSStefan Hajnoczi     if (running) {
8924d43d3f3SMichael S. Tsirkin         /* Linux before 2.6.34 drives the device without enabling
8934d43d3f3SMichael S. Tsirkin            the PCI device bus master bit. Enable it automatically
8944d43d3f3SMichael S. Tsirkin            for the guest. This is a PCI spec violation but so is
8954d43d3f3SMichael S. Tsirkin            initiating DMA with bus master bit clear.
8964d43d3f3SMichael S. Tsirkin            Note: this only makes a difference when migrating
8974d43d3f3SMichael S. Tsirkin            across QEMU versions from an old QEMU, as for new QEMU
8984d43d3f3SMichael S. Tsirkin            bus master and driver bits are always in sync.
8994d43d3f3SMichael S. Tsirkin            TODO: consider enabling conditionally for compat machine types. */
9004d43d3f3SMichael S. Tsirkin         if (vdev->status & (VIRTIO_CONFIG_S_ACKNOWLEDGE |
9014d43d3f3SMichael S. Tsirkin                             VIRTIO_CONFIG_S_DRIVER)) {
9024d43d3f3SMichael S. Tsirkin             pci_default_write_config(&proxy->pci_dev, PCI_COMMAND,
9034d43d3f3SMichael S. Tsirkin                                      proxy->pci_dev.config[PCI_COMMAND] |
9044d43d3f3SMichael S. Tsirkin                                      PCI_COMMAND_MASTER, 1);
90589c473fdSMichael S. Tsirkin         }
90625db9ebeSStefan Hajnoczi         virtio_pci_start_ioeventfd(proxy);
907ade80dc8SMichael S. Tsirkin     } else {
90825db9ebeSStefan Hajnoczi         virtio_pci_stop_ioeventfd(proxy);
909ade80dc8SMichael S. Tsirkin     }
910ade80dc8SMichael S. Tsirkin }
911ade80dc8SMichael S. Tsirkin 
91260653b28SPaolo Bonzini #ifdef CONFIG_VIRTFS
913234a336fSKONRAD Frederic static int virtio_9p_init_pci(VirtIOPCIProxy *vpci_dev)
91460653b28SPaolo Bonzini {
915234a336fSKONRAD Frederic     V9fsPCIState *dev = VIRTIO_9P_PCI(vpci_dev);
916234a336fSKONRAD Frederic     DeviceState *vdev = DEVICE(&dev->vdev);
91760653b28SPaolo Bonzini 
918234a336fSKONRAD Frederic     qdev_set_parent_bus(vdev, BUS(&vpci_dev->bus));
919234a336fSKONRAD Frederic     if (qdev_init(vdev) < 0) {
920234a336fSKONRAD Frederic         return -1;
921234a336fSKONRAD Frederic     }
92260653b28SPaolo Bonzini     return 0;
92360653b28SPaolo Bonzini }
92460653b28SPaolo Bonzini 
925234a336fSKONRAD Frederic static Property virtio_9p_pci_properties[] = {
926234a336fSKONRAD Frederic     DEFINE_PROP_BIT("ioeventfd", VirtIOPCIProxy, flags,
927234a336fSKONRAD Frederic                     VIRTIO_PCI_FLAG_USE_IOEVENTFD_BIT, true),
92860653b28SPaolo Bonzini     DEFINE_PROP_UINT32("vectors", VirtIOPCIProxy, nvectors, 2),
92960653b28SPaolo Bonzini     DEFINE_PROP_END_OF_LIST(),
93060653b28SPaolo Bonzini };
93160653b28SPaolo Bonzini 
932234a336fSKONRAD Frederic static void virtio_9p_pci_class_init(ObjectClass *klass, void *data)
93360653b28SPaolo Bonzini {
93460653b28SPaolo Bonzini     DeviceClass *dc = DEVICE_CLASS(klass);
935234a336fSKONRAD Frederic     PCIDeviceClass *pcidev_k = PCI_DEVICE_CLASS(klass);
936234a336fSKONRAD Frederic     VirtioPCIClass *k = VIRTIO_PCI_CLASS(klass);
93760653b28SPaolo Bonzini 
93860653b28SPaolo Bonzini     k->init = virtio_9p_init_pci;
939234a336fSKONRAD Frederic     pcidev_k->vendor_id = PCI_VENDOR_ID_REDHAT_QUMRANET;
940234a336fSKONRAD Frederic     pcidev_k->device_id = PCI_DEVICE_ID_VIRTIO_9P;
941234a336fSKONRAD Frederic     pcidev_k->revision = VIRTIO_PCI_ABI_VERSION;
942234a336fSKONRAD Frederic     pcidev_k->class_id = 0x2;
943125ee0edSMarcel Apfelbaum     set_bit(DEVICE_CATEGORY_STORAGE, dc->categories);
944234a336fSKONRAD Frederic     dc->props = virtio_9p_pci_properties;
94560653b28SPaolo Bonzini }
94660653b28SPaolo Bonzini 
947234a336fSKONRAD Frederic static void virtio_9p_pci_instance_init(Object *obj)
948234a336fSKONRAD Frederic {
949234a336fSKONRAD Frederic     V9fsPCIState *dev = VIRTIO_9P_PCI(obj);
950*c8075cafSGonglei 
951*c8075cafSGonglei     virtio_instance_init_common(obj, &dev->vdev, sizeof(dev->vdev),
952*c8075cafSGonglei                                 TYPE_VIRTIO_9P);
953234a336fSKONRAD Frederic }
954234a336fSKONRAD Frederic 
955234a336fSKONRAD Frederic static const TypeInfo virtio_9p_pci_info = {
956234a336fSKONRAD Frederic     .name          = TYPE_VIRTIO_9P_PCI,
957234a336fSKONRAD Frederic     .parent        = TYPE_VIRTIO_PCI,
958234a336fSKONRAD Frederic     .instance_size = sizeof(V9fsPCIState),
959234a336fSKONRAD Frederic     .instance_init = virtio_9p_pci_instance_init,
960234a336fSKONRAD Frederic     .class_init    = virtio_9p_pci_class_init,
96160653b28SPaolo Bonzini };
962234a336fSKONRAD Frederic #endif /* CONFIG_VIRTFS */
96360653b28SPaolo Bonzini 
964085bccb7SKONRAD Frederic /*
965085bccb7SKONRAD Frederic  * virtio-pci: This is the PCIDevice which has a virtio-pci-bus.
966085bccb7SKONRAD Frederic  */
967085bccb7SKONRAD Frederic 
968085bccb7SKONRAD Frederic /* This is called by virtio-bus just after the device is plugged. */
969085bccb7SKONRAD Frederic static void virtio_pci_device_plugged(DeviceState *d)
970085bccb7SKONRAD Frederic {
971085bccb7SKONRAD Frederic     VirtIOPCIProxy *proxy = VIRTIO_PCI(d);
972085bccb7SKONRAD Frederic     VirtioBusState *bus = &proxy->bus;
973085bccb7SKONRAD Frederic     uint8_t *config;
974085bccb7SKONRAD Frederic     uint32_t size;
975085bccb7SKONRAD Frederic 
976085bccb7SKONRAD Frederic     config = proxy->pci_dev.config;
977085bccb7SKONRAD Frederic     if (proxy->class_code) {
978085bccb7SKONRAD Frederic         pci_config_set_class(config, proxy->class_code);
979085bccb7SKONRAD Frederic     }
980085bccb7SKONRAD Frederic     pci_set_word(config + PCI_SUBSYSTEM_VENDOR_ID,
981085bccb7SKONRAD Frederic                  pci_get_word(config + PCI_VENDOR_ID));
982085bccb7SKONRAD Frederic     pci_set_word(config + PCI_SUBSYSTEM_ID, virtio_bus_get_vdev_id(bus));
983085bccb7SKONRAD Frederic     config[PCI_INTERRUPT_PIN] = 1;
984085bccb7SKONRAD Frederic 
985085bccb7SKONRAD Frederic     if (proxy->nvectors &&
986085bccb7SKONRAD Frederic         msix_init_exclusive_bar(&proxy->pci_dev, proxy->nvectors, 1)) {
987c7ff5482SFam Zheng         error_report("unable to init msix vectors to %" PRIu32,
988c7ff5482SFam Zheng                      proxy->nvectors);
989085bccb7SKONRAD Frederic         proxy->nvectors = 0;
990085bccb7SKONRAD Frederic     }
991085bccb7SKONRAD Frederic 
992085bccb7SKONRAD Frederic     proxy->pci_dev.config_write = virtio_write_config;
993085bccb7SKONRAD Frederic 
994085bccb7SKONRAD Frederic     size = VIRTIO_PCI_REGION_SIZE(&proxy->pci_dev)
995085bccb7SKONRAD Frederic          + virtio_bus_get_vdev_config_len(bus);
996085bccb7SKONRAD Frederic     if (size & (size - 1)) {
997085bccb7SKONRAD Frederic         size = 1 << qemu_fls(size);
998085bccb7SKONRAD Frederic     }
999085bccb7SKONRAD Frederic 
100022fc860bSPaolo Bonzini     memory_region_init_io(&proxy->bar, OBJECT(proxy), &virtio_pci_config_ops,
100122fc860bSPaolo Bonzini                           proxy, "virtio-pci", size);
1002085bccb7SKONRAD Frederic     pci_register_bar(&proxy->pci_dev, 0, PCI_BASE_ADDRESS_SPACE_IO,
1003085bccb7SKONRAD Frederic                      &proxy->bar);
1004085bccb7SKONRAD Frederic 
1005085bccb7SKONRAD Frederic     if (!kvm_has_many_ioeventfds()) {
1006085bccb7SKONRAD Frederic         proxy->flags &= ~VIRTIO_PCI_FLAG_USE_IOEVENTFD;
1007085bccb7SKONRAD Frederic     }
1008085bccb7SKONRAD Frederic 
1009085bccb7SKONRAD Frederic     proxy->host_features |= 0x1 << VIRTIO_F_NOTIFY_ON_EMPTY;
1010085bccb7SKONRAD Frederic     proxy->host_features |= 0x1 << VIRTIO_F_BAD_FEATURE;
1011085bccb7SKONRAD Frederic     proxy->host_features = virtio_bus_get_vdev_features(bus,
1012085bccb7SKONRAD Frederic                                                       proxy->host_features);
1013085bccb7SKONRAD Frederic }
1014085bccb7SKONRAD Frederic 
101506a13073SPaolo Bonzini static void virtio_pci_device_unplugged(DeviceState *d)
101606a13073SPaolo Bonzini {
101706a13073SPaolo Bonzini     VirtIOPCIProxy *proxy = VIRTIO_PCI(d);
101806a13073SPaolo Bonzini 
101906a13073SPaolo Bonzini     virtio_pci_stop_ioeventfd(proxy);
102006a13073SPaolo Bonzini }
102106a13073SPaolo Bonzini 
1022085bccb7SKONRAD Frederic static int virtio_pci_init(PCIDevice *pci_dev)
1023085bccb7SKONRAD Frederic {
1024085bccb7SKONRAD Frederic     VirtIOPCIProxy *dev = VIRTIO_PCI(pci_dev);
1025085bccb7SKONRAD Frederic     VirtioPCIClass *k = VIRTIO_PCI_GET_CLASS(pci_dev);
1026ac7af112SAndreas Färber     virtio_pci_bus_new(&dev->bus, sizeof(dev->bus), dev);
1027085bccb7SKONRAD Frederic     if (k->init != NULL) {
1028085bccb7SKONRAD Frederic         return k->init(dev);
1029085bccb7SKONRAD Frederic     }
1030085bccb7SKONRAD Frederic     return 0;
1031085bccb7SKONRAD Frederic }
1032085bccb7SKONRAD Frederic 
1033085bccb7SKONRAD Frederic static void virtio_pci_exit(PCIDevice *pci_dev)
1034085bccb7SKONRAD Frederic {
10358b81bb3bSPaolo Bonzini     msix_uninit_exclusive_bar(pci_dev);
1036085bccb7SKONRAD Frederic }
1037085bccb7SKONRAD Frederic 
103859ccd20aSKONRAD Frederic static void virtio_pci_reset(DeviceState *qdev)
1039085bccb7SKONRAD Frederic {
1040085bccb7SKONRAD Frederic     VirtIOPCIProxy *proxy = VIRTIO_PCI(qdev);
1041085bccb7SKONRAD Frederic     VirtioBusState *bus = VIRTIO_BUS(&proxy->bus);
1042085bccb7SKONRAD Frederic     virtio_pci_stop_ioeventfd(proxy);
1043085bccb7SKONRAD Frederic     virtio_bus_reset(bus);
1044085bccb7SKONRAD Frederic     msix_unuse_all_vectors(&proxy->pci_dev);
1045085bccb7SKONRAD Frederic }
1046085bccb7SKONRAD Frederic 
104785d1277eSMing Lei static Property virtio_pci_properties[] = {
104885d1277eSMing Lei     DEFINE_VIRTIO_COMMON_FEATURES(VirtIOPCIProxy, host_features),
104985d1277eSMing Lei     DEFINE_PROP_END_OF_LIST(),
105085d1277eSMing Lei };
105185d1277eSMing Lei 
1052085bccb7SKONRAD Frederic static void virtio_pci_class_init(ObjectClass *klass, void *data)
1053085bccb7SKONRAD Frederic {
1054085bccb7SKONRAD Frederic     DeviceClass *dc = DEVICE_CLASS(klass);
1055085bccb7SKONRAD Frederic     PCIDeviceClass *k = PCI_DEVICE_CLASS(klass);
1056085bccb7SKONRAD Frederic 
105785d1277eSMing Lei     dc->props = virtio_pci_properties;
1058085bccb7SKONRAD Frederic     k->init = virtio_pci_init;
1059085bccb7SKONRAD Frederic     k->exit = virtio_pci_exit;
1060085bccb7SKONRAD Frederic     k->vendor_id = PCI_VENDOR_ID_REDHAT_QUMRANET;
1061085bccb7SKONRAD Frederic     k->revision = VIRTIO_PCI_ABI_VERSION;
1062085bccb7SKONRAD Frederic     k->class_id = PCI_CLASS_OTHERS;
106359ccd20aSKONRAD Frederic     dc->reset = virtio_pci_reset;
1064085bccb7SKONRAD Frederic }
1065085bccb7SKONRAD Frederic 
1066085bccb7SKONRAD Frederic static const TypeInfo virtio_pci_info = {
1067085bccb7SKONRAD Frederic     .name          = TYPE_VIRTIO_PCI,
1068085bccb7SKONRAD Frederic     .parent        = TYPE_PCI_DEVICE,
1069085bccb7SKONRAD Frederic     .instance_size = sizeof(VirtIOPCIProxy),
1070085bccb7SKONRAD Frederic     .class_init    = virtio_pci_class_init,
1071085bccb7SKONRAD Frederic     .class_size    = sizeof(VirtioPCIClass),
1072085bccb7SKONRAD Frederic     .abstract      = true,
1073085bccb7SKONRAD Frederic };
1074085bccb7SKONRAD Frederic 
1075653ced07SKONRAD Frederic /* virtio-blk-pci */
1076653ced07SKONRAD Frederic 
1077653ced07SKONRAD Frederic static Property virtio_blk_pci_properties[] = {
1078c7bcc85dSPaolo Bonzini     DEFINE_PROP_UINT32("class", VirtIOPCIProxy, class_code, 0),
1079653ced07SKONRAD Frederic     DEFINE_PROP_BIT("ioeventfd", VirtIOPCIProxy, flags,
1080653ced07SKONRAD Frederic                     VIRTIO_PCI_FLAG_USE_IOEVENTFD_BIT, true),
1081653ced07SKONRAD Frederic     DEFINE_PROP_UINT32("vectors", VirtIOPCIProxy, nvectors, 2),
1082653ced07SKONRAD Frederic     DEFINE_PROP_END_OF_LIST(),
1083653ced07SKONRAD Frederic };
1084653ced07SKONRAD Frederic 
1085653ced07SKONRAD Frederic static int virtio_blk_pci_init(VirtIOPCIProxy *vpci_dev)
1086653ced07SKONRAD Frederic {
1087653ced07SKONRAD Frederic     VirtIOBlkPCI *dev = VIRTIO_BLK_PCI(vpci_dev);
1088653ced07SKONRAD Frederic     DeviceState *vdev = DEVICE(&dev->vdev);
1089653ced07SKONRAD Frederic     qdev_set_parent_bus(vdev, BUS(&vpci_dev->bus));
1090653ced07SKONRAD Frederic     if (qdev_init(vdev) < 0) {
1091653ced07SKONRAD Frederic         return -1;
1092653ced07SKONRAD Frederic     }
1093653ced07SKONRAD Frederic     return 0;
1094653ced07SKONRAD Frederic }
1095653ced07SKONRAD Frederic 
1096653ced07SKONRAD Frederic static void virtio_blk_pci_class_init(ObjectClass *klass, void *data)
1097653ced07SKONRAD Frederic {
1098653ced07SKONRAD Frederic     DeviceClass *dc = DEVICE_CLASS(klass);
1099653ced07SKONRAD Frederic     VirtioPCIClass *k = VIRTIO_PCI_CLASS(klass);
1100653ced07SKONRAD Frederic     PCIDeviceClass *pcidev_k = PCI_DEVICE_CLASS(klass);
1101653ced07SKONRAD Frederic 
1102125ee0edSMarcel Apfelbaum     set_bit(DEVICE_CATEGORY_STORAGE, dc->categories);
1103653ced07SKONRAD Frederic     dc->props = virtio_blk_pci_properties;
1104653ced07SKONRAD Frederic     k->init = virtio_blk_pci_init;
1105653ced07SKONRAD Frederic     pcidev_k->vendor_id = PCI_VENDOR_ID_REDHAT_QUMRANET;
1106653ced07SKONRAD Frederic     pcidev_k->device_id = PCI_DEVICE_ID_VIRTIO_BLOCK;
1107653ced07SKONRAD Frederic     pcidev_k->revision = VIRTIO_PCI_ABI_VERSION;
1108653ced07SKONRAD Frederic     pcidev_k->class_id = PCI_CLASS_STORAGE_SCSI;
1109653ced07SKONRAD Frederic }
1110653ced07SKONRAD Frederic 
1111653ced07SKONRAD Frederic static void virtio_blk_pci_instance_init(Object *obj)
1112653ced07SKONRAD Frederic {
1113653ced07SKONRAD Frederic     VirtIOBlkPCI *dev = VIRTIO_BLK_PCI(obj);
1114*c8075cafSGonglei 
1115*c8075cafSGonglei     virtio_instance_init_common(obj, &dev->vdev, sizeof(dev->vdev),
1116*c8075cafSGonglei                                 TYPE_VIRTIO_BLK);
1117467b3f33SStefan Hajnoczi     object_property_add_alias(obj, "iothread", OBJECT(&dev->vdev),"iothread",
1118467b3f33SStefan Hajnoczi                               &error_abort);
1119653ced07SKONRAD Frederic }
1120653ced07SKONRAD Frederic 
1121653ced07SKONRAD Frederic static const TypeInfo virtio_blk_pci_info = {
1122653ced07SKONRAD Frederic     .name          = TYPE_VIRTIO_BLK_PCI,
1123653ced07SKONRAD Frederic     .parent        = TYPE_VIRTIO_PCI,
1124653ced07SKONRAD Frederic     .instance_size = sizeof(VirtIOBlkPCI),
1125653ced07SKONRAD Frederic     .instance_init = virtio_blk_pci_instance_init,
1126653ced07SKONRAD Frederic     .class_init    = virtio_blk_pci_class_init,
1127653ced07SKONRAD Frederic };
1128653ced07SKONRAD Frederic 
1129bc7b90a0SKONRAD Frederic /* virtio-scsi-pci */
1130bc7b90a0SKONRAD Frederic 
1131bc7b90a0SKONRAD Frederic static Property virtio_scsi_pci_properties[] = {
1132bc7b90a0SKONRAD Frederic     DEFINE_PROP_BIT("ioeventfd", VirtIOPCIProxy, flags,
1133bc7b90a0SKONRAD Frederic                     VIRTIO_PCI_FLAG_USE_IOEVENTFD_BIT, true),
1134bc7b90a0SKONRAD Frederic     DEFINE_PROP_UINT32("vectors", VirtIOPCIProxy, nvectors,
1135bc7b90a0SKONRAD Frederic                        DEV_NVECTORS_UNSPECIFIED),
1136bc7b90a0SKONRAD Frederic     DEFINE_VIRTIO_SCSI_FEATURES(VirtIOPCIProxy, host_features),
1137bc7b90a0SKONRAD Frederic     DEFINE_PROP_END_OF_LIST(),
1138bc7b90a0SKONRAD Frederic };
1139bc7b90a0SKONRAD Frederic 
1140bc7b90a0SKONRAD Frederic static int virtio_scsi_pci_init_pci(VirtIOPCIProxy *vpci_dev)
1141bc7b90a0SKONRAD Frederic {
1142bc7b90a0SKONRAD Frederic     VirtIOSCSIPCI *dev = VIRTIO_SCSI_PCI(vpci_dev);
1143bc7b90a0SKONRAD Frederic     DeviceState *vdev = DEVICE(&dev->vdev);
1144292c8e50SPaolo Bonzini     VirtIOSCSICommon *vs = VIRTIO_SCSI_COMMON(vdev);
11456f32a6b4SKONRAD Frederic     DeviceState *proxy = DEVICE(vpci_dev);
11466f32a6b4SKONRAD Frederic     char *bus_name;
1147bc7b90a0SKONRAD Frederic 
1148bc7b90a0SKONRAD Frederic     if (vpci_dev->nvectors == DEV_NVECTORS_UNSPECIFIED) {
1149292c8e50SPaolo Bonzini         vpci_dev->nvectors = vs->conf.num_queues + 3;
1150bc7b90a0SKONRAD Frederic     }
1151bc7b90a0SKONRAD Frederic 
11526f32a6b4SKONRAD Frederic     /*
11536f32a6b4SKONRAD Frederic      * For command line compatibility, this sets the virtio-scsi-device bus
11546f32a6b4SKONRAD Frederic      * name as before.
11556f32a6b4SKONRAD Frederic      */
11566f32a6b4SKONRAD Frederic     if (proxy->id) {
11576f32a6b4SKONRAD Frederic         bus_name = g_strdup_printf("%s.0", proxy->id);
11586f32a6b4SKONRAD Frederic         virtio_device_set_child_bus_name(VIRTIO_DEVICE(vdev), bus_name);
11596f32a6b4SKONRAD Frederic         g_free(bus_name);
11606f32a6b4SKONRAD Frederic     }
11616f32a6b4SKONRAD Frederic 
1162bc7b90a0SKONRAD Frederic     qdev_set_parent_bus(vdev, BUS(&vpci_dev->bus));
1163bc7b90a0SKONRAD Frederic     if (qdev_init(vdev) < 0) {
1164bc7b90a0SKONRAD Frederic         return -1;
1165bc7b90a0SKONRAD Frederic     }
1166bc7b90a0SKONRAD Frederic     return 0;
1167bc7b90a0SKONRAD Frederic }
1168bc7b90a0SKONRAD Frederic 
1169bc7b90a0SKONRAD Frederic static void virtio_scsi_pci_class_init(ObjectClass *klass, void *data)
1170bc7b90a0SKONRAD Frederic {
1171bc7b90a0SKONRAD Frederic     DeviceClass *dc = DEVICE_CLASS(klass);
1172bc7b90a0SKONRAD Frederic     VirtioPCIClass *k = VIRTIO_PCI_CLASS(klass);
1173bc7b90a0SKONRAD Frederic     PCIDeviceClass *pcidev_k = PCI_DEVICE_CLASS(klass);
1174bc7b90a0SKONRAD Frederic     k->init = virtio_scsi_pci_init_pci;
1175125ee0edSMarcel Apfelbaum     set_bit(DEVICE_CATEGORY_STORAGE, dc->categories);
1176bc7b90a0SKONRAD Frederic     dc->props = virtio_scsi_pci_properties;
1177bc7b90a0SKONRAD Frederic     pcidev_k->vendor_id = PCI_VENDOR_ID_REDHAT_QUMRANET;
1178bc7b90a0SKONRAD Frederic     pcidev_k->device_id = PCI_DEVICE_ID_VIRTIO_SCSI;
1179bc7b90a0SKONRAD Frederic     pcidev_k->revision = 0x00;
1180bc7b90a0SKONRAD Frederic     pcidev_k->class_id = PCI_CLASS_STORAGE_SCSI;
1181bc7b90a0SKONRAD Frederic }
1182bc7b90a0SKONRAD Frederic 
1183bc7b90a0SKONRAD Frederic static void virtio_scsi_pci_instance_init(Object *obj)
1184bc7b90a0SKONRAD Frederic {
1185bc7b90a0SKONRAD Frederic     VirtIOSCSIPCI *dev = VIRTIO_SCSI_PCI(obj);
1186*c8075cafSGonglei 
1187*c8075cafSGonglei     virtio_instance_init_common(obj, &dev->vdev, sizeof(dev->vdev),
1188*c8075cafSGonglei                                 TYPE_VIRTIO_SCSI);
1189bc7b90a0SKONRAD Frederic }
1190bc7b90a0SKONRAD Frederic 
1191bc7b90a0SKONRAD Frederic static const TypeInfo virtio_scsi_pci_info = {
1192bc7b90a0SKONRAD Frederic     .name          = TYPE_VIRTIO_SCSI_PCI,
1193bc7b90a0SKONRAD Frederic     .parent        = TYPE_VIRTIO_PCI,
1194bc7b90a0SKONRAD Frederic     .instance_size = sizeof(VirtIOSCSIPCI),
1195bc7b90a0SKONRAD Frederic     .instance_init = virtio_scsi_pci_instance_init,
1196bc7b90a0SKONRAD Frederic     .class_init    = virtio_scsi_pci_class_init,
1197bc7b90a0SKONRAD Frederic };
1198bc7b90a0SKONRAD Frederic 
119950787628SNicholas Bellinger /* vhost-scsi-pci */
120050787628SNicholas Bellinger 
120150787628SNicholas Bellinger #ifdef CONFIG_VHOST_SCSI
120250787628SNicholas Bellinger static Property vhost_scsi_pci_properties[] = {
120350787628SNicholas Bellinger     DEFINE_PROP_UINT32("vectors", VirtIOPCIProxy, nvectors,
120450787628SNicholas Bellinger                        DEV_NVECTORS_UNSPECIFIED),
120550787628SNicholas Bellinger     DEFINE_PROP_END_OF_LIST(),
120650787628SNicholas Bellinger };
120750787628SNicholas Bellinger 
120850787628SNicholas Bellinger static int vhost_scsi_pci_init_pci(VirtIOPCIProxy *vpci_dev)
120950787628SNicholas Bellinger {
121050787628SNicholas Bellinger     VHostSCSIPCI *dev = VHOST_SCSI_PCI(vpci_dev);
121150787628SNicholas Bellinger     DeviceState *vdev = DEVICE(&dev->vdev);
121250787628SNicholas Bellinger     VirtIOSCSICommon *vs = VIRTIO_SCSI_COMMON(vdev);
121350787628SNicholas Bellinger 
121450787628SNicholas Bellinger     if (vpci_dev->nvectors == DEV_NVECTORS_UNSPECIFIED) {
121550787628SNicholas Bellinger         vpci_dev->nvectors = vs->conf.num_queues + 3;
121650787628SNicholas Bellinger     }
121750787628SNicholas Bellinger 
121850787628SNicholas Bellinger     qdev_set_parent_bus(vdev, BUS(&vpci_dev->bus));
121950787628SNicholas Bellinger     if (qdev_init(vdev) < 0) {
122050787628SNicholas Bellinger         return -1;
122150787628SNicholas Bellinger     }
122250787628SNicholas Bellinger     return 0;
122350787628SNicholas Bellinger }
122450787628SNicholas Bellinger 
122550787628SNicholas Bellinger static void vhost_scsi_pci_class_init(ObjectClass *klass, void *data)
122650787628SNicholas Bellinger {
122750787628SNicholas Bellinger     DeviceClass *dc = DEVICE_CLASS(klass);
122850787628SNicholas Bellinger     VirtioPCIClass *k = VIRTIO_PCI_CLASS(klass);
122950787628SNicholas Bellinger     PCIDeviceClass *pcidev_k = PCI_DEVICE_CLASS(klass);
123050787628SNicholas Bellinger     k->init = vhost_scsi_pci_init_pci;
1231125ee0edSMarcel Apfelbaum     set_bit(DEVICE_CATEGORY_STORAGE, dc->categories);
123250787628SNicholas Bellinger     dc->props = vhost_scsi_pci_properties;
123350787628SNicholas Bellinger     pcidev_k->vendor_id = PCI_VENDOR_ID_REDHAT_QUMRANET;
123450787628SNicholas Bellinger     pcidev_k->device_id = PCI_DEVICE_ID_VIRTIO_SCSI;
123550787628SNicholas Bellinger     pcidev_k->revision = 0x00;
123650787628SNicholas Bellinger     pcidev_k->class_id = PCI_CLASS_STORAGE_SCSI;
123750787628SNicholas Bellinger }
123850787628SNicholas Bellinger 
123950787628SNicholas Bellinger static void vhost_scsi_pci_instance_init(Object *obj)
124050787628SNicholas Bellinger {
124150787628SNicholas Bellinger     VHostSCSIPCI *dev = VHOST_SCSI_PCI(obj);
1242*c8075cafSGonglei 
1243*c8075cafSGonglei     virtio_instance_init_common(obj, &dev->vdev, sizeof(dev->vdev),
1244*c8075cafSGonglei                                 TYPE_VHOST_SCSI);
124550787628SNicholas Bellinger }
124650787628SNicholas Bellinger 
124750787628SNicholas Bellinger static const TypeInfo vhost_scsi_pci_info = {
124850787628SNicholas Bellinger     .name          = TYPE_VHOST_SCSI_PCI,
124950787628SNicholas Bellinger     .parent        = TYPE_VIRTIO_PCI,
125050787628SNicholas Bellinger     .instance_size = sizeof(VHostSCSIPCI),
125150787628SNicholas Bellinger     .instance_init = vhost_scsi_pci_instance_init,
125250787628SNicholas Bellinger     .class_init    = vhost_scsi_pci_class_init,
125350787628SNicholas Bellinger };
125450787628SNicholas Bellinger #endif
125550787628SNicholas Bellinger 
1256e378e88dSKONRAD Frederic /* virtio-balloon-pci */
1257e378e88dSKONRAD Frederic 
125824a6e7f4SKONRAD Frederic static void balloon_pci_stats_get_all(Object *obj, struct Visitor *v,
125924a6e7f4SKONRAD Frederic                                       void *opaque, const char *name,
126024a6e7f4SKONRAD Frederic                                       Error **errp)
126124a6e7f4SKONRAD Frederic {
126224a6e7f4SKONRAD Frederic     VirtIOBalloonPCI *dev = opaque;
126324a6e7f4SKONRAD Frederic     object_property_get(OBJECT(&dev->vdev), v, "guest-stats", errp);
126424a6e7f4SKONRAD Frederic }
126524a6e7f4SKONRAD Frederic 
126624a6e7f4SKONRAD Frederic static void balloon_pci_stats_get_poll_interval(Object *obj, struct Visitor *v,
126724a6e7f4SKONRAD Frederic                                                 void *opaque, const char *name,
126824a6e7f4SKONRAD Frederic                                                 Error **errp)
126924a6e7f4SKONRAD Frederic {
127024a6e7f4SKONRAD Frederic     VirtIOBalloonPCI *dev = opaque;
127124a6e7f4SKONRAD Frederic     object_property_get(OBJECT(&dev->vdev), v, "guest-stats-polling-interval",
127224a6e7f4SKONRAD Frederic                         errp);
127324a6e7f4SKONRAD Frederic }
127424a6e7f4SKONRAD Frederic 
127524a6e7f4SKONRAD Frederic static void balloon_pci_stats_set_poll_interval(Object *obj, struct Visitor *v,
127624a6e7f4SKONRAD Frederic                                                 void *opaque, const char *name,
127724a6e7f4SKONRAD Frederic                                                 Error **errp)
127824a6e7f4SKONRAD Frederic {
127924a6e7f4SKONRAD Frederic     VirtIOBalloonPCI *dev = opaque;
128024a6e7f4SKONRAD Frederic     object_property_set(OBJECT(&dev->vdev), v, "guest-stats-polling-interval",
128124a6e7f4SKONRAD Frederic                         errp);
128224a6e7f4SKONRAD Frederic }
128324a6e7f4SKONRAD Frederic 
1284e378e88dSKONRAD Frederic static Property virtio_balloon_pci_properties[] = {
1285c7bcc85dSPaolo Bonzini     DEFINE_PROP_UINT32("class", VirtIOPCIProxy, class_code, 0),
1286e378e88dSKONRAD Frederic     DEFINE_PROP_END_OF_LIST(),
1287e378e88dSKONRAD Frederic };
1288e378e88dSKONRAD Frederic 
1289e378e88dSKONRAD Frederic static int virtio_balloon_pci_init(VirtIOPCIProxy *vpci_dev)
1290e378e88dSKONRAD Frederic {
1291e378e88dSKONRAD Frederic     VirtIOBalloonPCI *dev = VIRTIO_BALLOON_PCI(vpci_dev);
1292e378e88dSKONRAD Frederic     DeviceState *vdev = DEVICE(&dev->vdev);
1293e378e88dSKONRAD Frederic 
1294e378e88dSKONRAD Frederic     if (vpci_dev->class_code != PCI_CLASS_OTHERS &&
1295e378e88dSKONRAD Frederic         vpci_dev->class_code != PCI_CLASS_MEMORY_RAM) { /* qemu < 1.1 */
1296e378e88dSKONRAD Frederic         vpci_dev->class_code = PCI_CLASS_OTHERS;
1297e378e88dSKONRAD Frederic     }
1298e378e88dSKONRAD Frederic 
1299e378e88dSKONRAD Frederic     qdev_set_parent_bus(vdev, BUS(&vpci_dev->bus));
1300e378e88dSKONRAD Frederic     if (qdev_init(vdev) < 0) {
1301e378e88dSKONRAD Frederic         return -1;
1302e378e88dSKONRAD Frederic     }
1303e378e88dSKONRAD Frederic     return 0;
1304e378e88dSKONRAD Frederic }
1305e378e88dSKONRAD Frederic 
1306e378e88dSKONRAD Frederic static void virtio_balloon_pci_class_init(ObjectClass *klass, void *data)
1307e378e88dSKONRAD Frederic {
1308e378e88dSKONRAD Frederic     DeviceClass *dc = DEVICE_CLASS(klass);
1309e378e88dSKONRAD Frederic     VirtioPCIClass *k = VIRTIO_PCI_CLASS(klass);
1310e378e88dSKONRAD Frederic     PCIDeviceClass *pcidev_k = PCI_DEVICE_CLASS(klass);
1311e378e88dSKONRAD Frederic     k->init = virtio_balloon_pci_init;
1312125ee0edSMarcel Apfelbaum     set_bit(DEVICE_CATEGORY_MISC, dc->categories);
1313e378e88dSKONRAD Frederic     dc->props = virtio_balloon_pci_properties;
1314e378e88dSKONRAD Frederic     pcidev_k->vendor_id = PCI_VENDOR_ID_REDHAT_QUMRANET;
1315e378e88dSKONRAD Frederic     pcidev_k->device_id = PCI_DEVICE_ID_VIRTIO_BALLOON;
1316e378e88dSKONRAD Frederic     pcidev_k->revision = VIRTIO_PCI_ABI_VERSION;
1317e378e88dSKONRAD Frederic     pcidev_k->class_id = PCI_CLASS_OTHERS;
1318e378e88dSKONRAD Frederic }
1319e378e88dSKONRAD Frederic 
1320e378e88dSKONRAD Frederic static void virtio_balloon_pci_instance_init(Object *obj)
1321e378e88dSKONRAD Frederic {
1322e378e88dSKONRAD Frederic     VirtIOBalloonPCI *dev = VIRTIO_BALLOON_PCI(obj);
1323213f0c4fSAndreas Färber     object_initialize(&dev->vdev, sizeof(dev->vdev), TYPE_VIRTIO_BALLOON);
1324e378e88dSKONRAD Frederic     object_property_add_child(obj, "virtio-backend", OBJECT(&dev->vdev), NULL);
132591ba2120SGonglei     object_unref(OBJECT(&dev->vdev));
132624a6e7f4SKONRAD Frederic     object_property_add(obj, "guest-stats", "guest statistics",
132724a6e7f4SKONRAD Frederic                         balloon_pci_stats_get_all, NULL, NULL, dev,
132824a6e7f4SKONRAD Frederic                         NULL);
132924a6e7f4SKONRAD Frederic 
133024a6e7f4SKONRAD Frederic     object_property_add(obj, "guest-stats-polling-interval", "int",
133124a6e7f4SKONRAD Frederic                         balloon_pci_stats_get_poll_interval,
133224a6e7f4SKONRAD Frederic                         balloon_pci_stats_set_poll_interval,
133324a6e7f4SKONRAD Frederic                         NULL, dev, NULL);
1334e378e88dSKONRAD Frederic }
1335e378e88dSKONRAD Frederic 
1336e378e88dSKONRAD Frederic static const TypeInfo virtio_balloon_pci_info = {
1337e378e88dSKONRAD Frederic     .name          = TYPE_VIRTIO_BALLOON_PCI,
1338e378e88dSKONRAD Frederic     .parent        = TYPE_VIRTIO_PCI,
1339e378e88dSKONRAD Frederic     .instance_size = sizeof(VirtIOBalloonPCI),
1340e378e88dSKONRAD Frederic     .instance_init = virtio_balloon_pci_instance_init,
1341e378e88dSKONRAD Frederic     .class_init    = virtio_balloon_pci_class_init,
1342e378e88dSKONRAD Frederic };
1343e378e88dSKONRAD Frederic 
1344f7f7464aSKONRAD Frederic /* virtio-serial-pci */
1345f7f7464aSKONRAD Frederic 
1346f7f7464aSKONRAD Frederic static int virtio_serial_pci_init(VirtIOPCIProxy *vpci_dev)
1347f7f7464aSKONRAD Frederic {
1348f7f7464aSKONRAD Frederic     VirtIOSerialPCI *dev = VIRTIO_SERIAL_PCI(vpci_dev);
1349f7f7464aSKONRAD Frederic     DeviceState *vdev = DEVICE(&dev->vdev);
135080270a19SKONRAD Frederic     DeviceState *proxy = DEVICE(vpci_dev);
135180270a19SKONRAD Frederic     char *bus_name;
1352f7f7464aSKONRAD Frederic 
1353f7f7464aSKONRAD Frederic     if (vpci_dev->class_code != PCI_CLASS_COMMUNICATION_OTHER &&
1354f7f7464aSKONRAD Frederic         vpci_dev->class_code != PCI_CLASS_DISPLAY_OTHER && /* qemu 0.10 */
1355f7f7464aSKONRAD Frederic         vpci_dev->class_code != PCI_CLASS_OTHERS) {        /* qemu-kvm  */
1356f7f7464aSKONRAD Frederic             vpci_dev->class_code = PCI_CLASS_COMMUNICATION_OTHER;
1357f7f7464aSKONRAD Frederic     }
1358f7f7464aSKONRAD Frederic 
1359f7f7464aSKONRAD Frederic     /* backwards-compatibility with machines that were created with
1360f7f7464aSKONRAD Frederic        DEV_NVECTORS_UNSPECIFIED */
1361f7f7464aSKONRAD Frederic     if (vpci_dev->nvectors == DEV_NVECTORS_UNSPECIFIED) {
1362f7f7464aSKONRAD Frederic         vpci_dev->nvectors = dev->vdev.serial.max_virtserial_ports + 1;
1363f7f7464aSKONRAD Frederic     }
1364f7f7464aSKONRAD Frederic 
136580270a19SKONRAD Frederic     /*
136680270a19SKONRAD Frederic      * For command line compatibility, this sets the virtio-serial-device bus
136780270a19SKONRAD Frederic      * name as before.
136880270a19SKONRAD Frederic      */
136980270a19SKONRAD Frederic     if (proxy->id) {
137080270a19SKONRAD Frederic         bus_name = g_strdup_printf("%s.0", proxy->id);
137180270a19SKONRAD Frederic         virtio_device_set_child_bus_name(VIRTIO_DEVICE(vdev), bus_name);
137280270a19SKONRAD Frederic         g_free(bus_name);
137380270a19SKONRAD Frederic     }
137480270a19SKONRAD Frederic 
1375f7f7464aSKONRAD Frederic     qdev_set_parent_bus(vdev, BUS(&vpci_dev->bus));
1376f7f7464aSKONRAD Frederic     if (qdev_init(vdev) < 0) {
1377f7f7464aSKONRAD Frederic         return -1;
1378f7f7464aSKONRAD Frederic     }
1379f7f7464aSKONRAD Frederic     return 0;
1380f7f7464aSKONRAD Frederic }
1381f7f7464aSKONRAD Frederic 
1382f7f7464aSKONRAD Frederic static Property virtio_serial_pci_properties[] = {
1383f7f7464aSKONRAD Frederic     DEFINE_PROP_BIT("ioeventfd", VirtIOPCIProxy, flags,
1384f7f7464aSKONRAD Frederic                     VIRTIO_PCI_FLAG_USE_IOEVENTFD_BIT, true),
1385f7f7464aSKONRAD Frederic     DEFINE_PROP_UINT32("vectors", VirtIOPCIProxy, nvectors, 2),
1386c7bcc85dSPaolo Bonzini     DEFINE_PROP_UINT32("class", VirtIOPCIProxy, class_code, 0),
1387f7f7464aSKONRAD Frederic     DEFINE_PROP_END_OF_LIST(),
1388f7f7464aSKONRAD Frederic };
1389f7f7464aSKONRAD Frederic 
1390f7f7464aSKONRAD Frederic static void virtio_serial_pci_class_init(ObjectClass *klass, void *data)
1391f7f7464aSKONRAD Frederic {
1392f7f7464aSKONRAD Frederic     DeviceClass *dc = DEVICE_CLASS(klass);
1393f7f7464aSKONRAD Frederic     VirtioPCIClass *k = VIRTIO_PCI_CLASS(klass);
1394f7f7464aSKONRAD Frederic     PCIDeviceClass *pcidev_k = PCI_DEVICE_CLASS(klass);
1395f7f7464aSKONRAD Frederic     k->init = virtio_serial_pci_init;
1396125ee0edSMarcel Apfelbaum     set_bit(DEVICE_CATEGORY_INPUT, dc->categories);
1397f7f7464aSKONRAD Frederic     dc->props = virtio_serial_pci_properties;
1398f7f7464aSKONRAD Frederic     pcidev_k->vendor_id = PCI_VENDOR_ID_REDHAT_QUMRANET;
1399f7f7464aSKONRAD Frederic     pcidev_k->device_id = PCI_DEVICE_ID_VIRTIO_CONSOLE;
1400f7f7464aSKONRAD Frederic     pcidev_k->revision = VIRTIO_PCI_ABI_VERSION;
1401f7f7464aSKONRAD Frederic     pcidev_k->class_id = PCI_CLASS_COMMUNICATION_OTHER;
1402f7f7464aSKONRAD Frederic }
1403f7f7464aSKONRAD Frederic 
1404f7f7464aSKONRAD Frederic static void virtio_serial_pci_instance_init(Object *obj)
1405f7f7464aSKONRAD Frederic {
1406f7f7464aSKONRAD Frederic     VirtIOSerialPCI *dev = VIRTIO_SERIAL_PCI(obj);
1407*c8075cafSGonglei 
1408*c8075cafSGonglei     virtio_instance_init_common(obj, &dev->vdev, sizeof(dev->vdev),
1409*c8075cafSGonglei                                 TYPE_VIRTIO_SERIAL);
1410f7f7464aSKONRAD Frederic }
1411f7f7464aSKONRAD Frederic 
1412f7f7464aSKONRAD Frederic static const TypeInfo virtio_serial_pci_info = {
1413f7f7464aSKONRAD Frederic     .name          = TYPE_VIRTIO_SERIAL_PCI,
1414f7f7464aSKONRAD Frederic     .parent        = TYPE_VIRTIO_PCI,
1415f7f7464aSKONRAD Frederic     .instance_size = sizeof(VirtIOSerialPCI),
1416f7f7464aSKONRAD Frederic     .instance_init = virtio_serial_pci_instance_init,
1417f7f7464aSKONRAD Frederic     .class_init    = virtio_serial_pci_class_init,
1418f7f7464aSKONRAD Frederic };
1419f7f7464aSKONRAD Frederic 
1420e37da394SKONRAD Frederic /* virtio-net-pci */
1421e37da394SKONRAD Frederic 
1422e37da394SKONRAD Frederic static Property virtio_net_properties[] = {
1423e37da394SKONRAD Frederic     DEFINE_PROP_BIT("ioeventfd", VirtIOPCIProxy, flags,
1424e37da394SKONRAD Frederic                     VIRTIO_PCI_FLAG_USE_IOEVENTFD_BIT, false),
1425e37da394SKONRAD Frederic     DEFINE_PROP_UINT32("vectors", VirtIOPCIProxy, nvectors, 3),
1426e37da394SKONRAD Frederic     DEFINE_VIRTIO_NET_FEATURES(VirtIOPCIProxy, host_features),
1427e37da394SKONRAD Frederic     DEFINE_PROP_END_OF_LIST(),
1428e37da394SKONRAD Frederic };
1429e37da394SKONRAD Frederic 
1430e37da394SKONRAD Frederic static int virtio_net_pci_init(VirtIOPCIProxy *vpci_dev)
1431e37da394SKONRAD Frederic {
1432800ced8cSKONRAD Frederic     DeviceState *qdev = DEVICE(vpci_dev);
1433e37da394SKONRAD Frederic     VirtIONetPCI *dev = VIRTIO_NET_PCI(vpci_dev);
1434e37da394SKONRAD Frederic     DeviceState *vdev = DEVICE(&dev->vdev);
1435e37da394SKONRAD Frederic 
1436e37da394SKONRAD Frederic     virtio_net_set_config_size(&dev->vdev, vpci_dev->host_features);
1437800ced8cSKONRAD Frederic     virtio_net_set_netclient_name(&dev->vdev, qdev->id,
1438800ced8cSKONRAD Frederic                                   object_get_typename(OBJECT(qdev)));
1439e37da394SKONRAD Frederic     qdev_set_parent_bus(vdev, BUS(&vpci_dev->bus));
1440e37da394SKONRAD Frederic     if (qdev_init(vdev) < 0) {
1441e37da394SKONRAD Frederic         return -1;
1442e37da394SKONRAD Frederic     }
1443e37da394SKONRAD Frederic     return 0;
1444e37da394SKONRAD Frederic }
1445e37da394SKONRAD Frederic 
1446e37da394SKONRAD Frederic static void virtio_net_pci_class_init(ObjectClass *klass, void *data)
1447e37da394SKONRAD Frederic {
1448e37da394SKONRAD Frederic     DeviceClass *dc = DEVICE_CLASS(klass);
1449e37da394SKONRAD Frederic     PCIDeviceClass *k = PCI_DEVICE_CLASS(klass);
1450e37da394SKONRAD Frederic     VirtioPCIClass *vpciklass = VIRTIO_PCI_CLASS(klass);
1451e37da394SKONRAD Frederic 
1452e37da394SKONRAD Frederic     k->romfile = "efi-virtio.rom";
1453e37da394SKONRAD Frederic     k->vendor_id = PCI_VENDOR_ID_REDHAT_QUMRANET;
1454e37da394SKONRAD Frederic     k->device_id = PCI_DEVICE_ID_VIRTIO_NET;
1455e37da394SKONRAD Frederic     k->revision = VIRTIO_PCI_ABI_VERSION;
1456e37da394SKONRAD Frederic     k->class_id = PCI_CLASS_NETWORK_ETHERNET;
1457125ee0edSMarcel Apfelbaum     set_bit(DEVICE_CATEGORY_NETWORK, dc->categories);
1458e37da394SKONRAD Frederic     dc->props = virtio_net_properties;
1459e37da394SKONRAD Frederic     vpciklass->init = virtio_net_pci_init;
1460e37da394SKONRAD Frederic }
1461e37da394SKONRAD Frederic 
1462e37da394SKONRAD Frederic static void virtio_net_pci_instance_init(Object *obj)
1463e37da394SKONRAD Frederic {
1464e37da394SKONRAD Frederic     VirtIONetPCI *dev = VIRTIO_NET_PCI(obj);
1465*c8075cafSGonglei 
1466*c8075cafSGonglei     virtio_instance_init_common(obj, &dev->vdev, sizeof(dev->vdev),
1467*c8075cafSGonglei                                 TYPE_VIRTIO_NET);
1468e37da394SKONRAD Frederic }
1469e37da394SKONRAD Frederic 
1470e37da394SKONRAD Frederic static const TypeInfo virtio_net_pci_info = {
1471e37da394SKONRAD Frederic     .name          = TYPE_VIRTIO_NET_PCI,
1472e37da394SKONRAD Frederic     .parent        = TYPE_VIRTIO_PCI,
1473e37da394SKONRAD Frederic     .instance_size = sizeof(VirtIONetPCI),
1474e37da394SKONRAD Frederic     .instance_init = virtio_net_pci_instance_init,
1475e37da394SKONRAD Frederic     .class_init    = virtio_net_pci_class_init,
1476e37da394SKONRAD Frederic };
1477e37da394SKONRAD Frederic 
147859ccd20aSKONRAD Frederic /* virtio-rng-pci */
147959ccd20aSKONRAD Frederic 
148059ccd20aSKONRAD Frederic static Property virtio_rng_pci_properties[] = {
148159ccd20aSKONRAD Frederic     DEFINE_PROP_END_OF_LIST(),
148259ccd20aSKONRAD Frederic };
148359ccd20aSKONRAD Frederic 
148459ccd20aSKONRAD Frederic static int virtio_rng_pci_init(VirtIOPCIProxy *vpci_dev)
148559ccd20aSKONRAD Frederic {
148659ccd20aSKONRAD Frederic     VirtIORngPCI *vrng = VIRTIO_RNG_PCI(vpci_dev);
148759ccd20aSKONRAD Frederic     DeviceState *vdev = DEVICE(&vrng->vdev);
148859ccd20aSKONRAD Frederic 
148959ccd20aSKONRAD Frederic     qdev_set_parent_bus(vdev, BUS(&vpci_dev->bus));
149059ccd20aSKONRAD Frederic     if (qdev_init(vdev) < 0) {
149159ccd20aSKONRAD Frederic         return -1;
149259ccd20aSKONRAD Frederic     }
149359ccd20aSKONRAD Frederic 
149459ccd20aSKONRAD Frederic     object_property_set_link(OBJECT(vrng),
14955b456438SCole Robinson                              OBJECT(vrng->vdev.conf.rng), "rng",
149659ccd20aSKONRAD Frederic                              NULL);
149759ccd20aSKONRAD Frederic 
149859ccd20aSKONRAD Frederic     return 0;
149959ccd20aSKONRAD Frederic }
150059ccd20aSKONRAD Frederic 
150159ccd20aSKONRAD Frederic static void virtio_rng_pci_class_init(ObjectClass *klass, void *data)
150259ccd20aSKONRAD Frederic {
150359ccd20aSKONRAD Frederic     DeviceClass *dc = DEVICE_CLASS(klass);
150459ccd20aSKONRAD Frederic     VirtioPCIClass *k = VIRTIO_PCI_CLASS(klass);
150559ccd20aSKONRAD Frederic     PCIDeviceClass *pcidev_k = PCI_DEVICE_CLASS(klass);
150659ccd20aSKONRAD Frederic 
150759ccd20aSKONRAD Frederic     k->init = virtio_rng_pci_init;
1508125ee0edSMarcel Apfelbaum     set_bit(DEVICE_CATEGORY_MISC, dc->categories);
150959ccd20aSKONRAD Frederic     dc->props = virtio_rng_pci_properties;
151059ccd20aSKONRAD Frederic 
151159ccd20aSKONRAD Frederic     pcidev_k->vendor_id = PCI_VENDOR_ID_REDHAT_QUMRANET;
151259ccd20aSKONRAD Frederic     pcidev_k->device_id = PCI_DEVICE_ID_VIRTIO_RNG;
151359ccd20aSKONRAD Frederic     pcidev_k->revision = VIRTIO_PCI_ABI_VERSION;
151459ccd20aSKONRAD Frederic     pcidev_k->class_id = PCI_CLASS_OTHERS;
151559ccd20aSKONRAD Frederic }
151659ccd20aSKONRAD Frederic 
151759ccd20aSKONRAD Frederic static void virtio_rng_initfn(Object *obj)
151859ccd20aSKONRAD Frederic {
151959ccd20aSKONRAD Frederic     VirtIORngPCI *dev = VIRTIO_RNG_PCI(obj);
1520*c8075cafSGonglei 
1521*c8075cafSGonglei     virtio_instance_init_common(obj, &dev->vdev, sizeof(dev->vdev),
1522*c8075cafSGonglei                                 TYPE_VIRTIO_RNG);
152359ccd20aSKONRAD Frederic     object_property_add_link(obj, "rng", TYPE_RNG_BACKEND,
15249561fda8SStefan Hajnoczi                              (Object **)&dev->vdev.conf.rng,
152539f72ef9SStefan Hajnoczi                              qdev_prop_allow_set_link_before_realize,
15269561fda8SStefan Hajnoczi                              OBJ_PROP_LINK_UNREF_ON_RELEASE, NULL);
152759ccd20aSKONRAD Frederic 
152859ccd20aSKONRAD Frederic }
152959ccd20aSKONRAD Frederic 
153059ccd20aSKONRAD Frederic static const TypeInfo virtio_rng_pci_info = {
153159ccd20aSKONRAD Frederic     .name          = TYPE_VIRTIO_RNG_PCI,
153259ccd20aSKONRAD Frederic     .parent        = TYPE_VIRTIO_PCI,
153359ccd20aSKONRAD Frederic     .instance_size = sizeof(VirtIORngPCI),
153459ccd20aSKONRAD Frederic     .instance_init = virtio_rng_initfn,
153559ccd20aSKONRAD Frederic     .class_init    = virtio_rng_pci_class_init,
153659ccd20aSKONRAD Frederic };
153759ccd20aSKONRAD Frederic 
15380a2acf5eSKONRAD Frederic /* virtio-pci-bus */
15390a2acf5eSKONRAD Frederic 
1540ac7af112SAndreas Färber static void virtio_pci_bus_new(VirtioBusState *bus, size_t bus_size,
1541ac7af112SAndreas Färber                                VirtIOPCIProxy *dev)
15420a2acf5eSKONRAD Frederic {
15430a2acf5eSKONRAD Frederic     DeviceState *qdev = DEVICE(dev);
15440a2acf5eSKONRAD Frederic     BusState *qbus;
1545f4dd69aaSKONRAD Frederic     char virtio_bus_name[] = "virtio-bus";
1546f4dd69aaSKONRAD Frederic 
1547fb17dfe0SAndreas Färber     qbus_create_inplace(bus, bus_size, TYPE_VIRTIO_PCI_BUS, qdev,
1548f4dd69aaSKONRAD Frederic                         virtio_bus_name);
15490a2acf5eSKONRAD Frederic     qbus = BUS(bus);
1550cbd19063SKONRAD Frederic     qbus->allow_hotplug = 1;
15510a2acf5eSKONRAD Frederic }
15520a2acf5eSKONRAD Frederic 
15530a2acf5eSKONRAD Frederic static void virtio_pci_bus_class_init(ObjectClass *klass, void *data)
15540a2acf5eSKONRAD Frederic {
15550a2acf5eSKONRAD Frederic     BusClass *bus_class = BUS_CLASS(klass);
15560a2acf5eSKONRAD Frederic     VirtioBusClass *k = VIRTIO_BUS_CLASS(klass);
15570a2acf5eSKONRAD Frederic     bus_class->max_dev = 1;
15580a2acf5eSKONRAD Frederic     k->notify = virtio_pci_notify;
15590a2acf5eSKONRAD Frederic     k->save_config = virtio_pci_save_config;
15600a2acf5eSKONRAD Frederic     k->load_config = virtio_pci_load_config;
15610a2acf5eSKONRAD Frederic     k->save_queue = virtio_pci_save_queue;
15620a2acf5eSKONRAD Frederic     k->load_queue = virtio_pci_load_queue;
15630a2acf5eSKONRAD Frederic     k->get_features = virtio_pci_get_features;
15640a2acf5eSKONRAD Frederic     k->query_guest_notifiers = virtio_pci_query_guest_notifiers;
15650a2acf5eSKONRAD Frederic     k->set_host_notifier = virtio_pci_set_host_notifier;
15660a2acf5eSKONRAD Frederic     k->set_guest_notifiers = virtio_pci_set_guest_notifiers;
15670a2acf5eSKONRAD Frederic     k->vmstate_change = virtio_pci_vmstate_change;
1568085bccb7SKONRAD Frederic     k->device_plugged = virtio_pci_device_plugged;
156906a13073SPaolo Bonzini     k->device_unplugged = virtio_pci_device_unplugged;
15700a2acf5eSKONRAD Frederic }
15710a2acf5eSKONRAD Frederic 
15720a2acf5eSKONRAD Frederic static const TypeInfo virtio_pci_bus_info = {
15730a2acf5eSKONRAD Frederic     .name          = TYPE_VIRTIO_PCI_BUS,
15740a2acf5eSKONRAD Frederic     .parent        = TYPE_VIRTIO_BUS,
15750a2acf5eSKONRAD Frederic     .instance_size = sizeof(VirtioPCIBusState),
15760a2acf5eSKONRAD Frederic     .class_init    = virtio_pci_bus_class_init,
15770a2acf5eSKONRAD Frederic };
15780a2acf5eSKONRAD Frederic 
157983f7d43aSAndreas Färber static void virtio_pci_register_types(void)
158053c25ceaSPaul Brook {
158159ccd20aSKONRAD Frederic     type_register_static(&virtio_rng_pci_info);
15820a2acf5eSKONRAD Frederic     type_register_static(&virtio_pci_bus_info);
1583085bccb7SKONRAD Frederic     type_register_static(&virtio_pci_info);
158460653b28SPaolo Bonzini #ifdef CONFIG_VIRTFS
1585234a336fSKONRAD Frederic     type_register_static(&virtio_9p_pci_info);
158660653b28SPaolo Bonzini #endif
1587653ced07SKONRAD Frederic     type_register_static(&virtio_blk_pci_info);
1588bc7b90a0SKONRAD Frederic     type_register_static(&virtio_scsi_pci_info);
1589e378e88dSKONRAD Frederic     type_register_static(&virtio_balloon_pci_info);
1590f7f7464aSKONRAD Frederic     type_register_static(&virtio_serial_pci_info);
1591e37da394SKONRAD Frederic     type_register_static(&virtio_net_pci_info);
159250787628SNicholas Bellinger #ifdef CONFIG_VHOST_SCSI
159350787628SNicholas Bellinger     type_register_static(&vhost_scsi_pci_info);
159450787628SNicholas Bellinger #endif
159553c25ceaSPaul Brook }
159653c25ceaSPaul Brook 
159783f7d43aSAndreas Färber type_init(virtio_pci_register_types)
1598