xref: /qemu/hw/virtio/virtio-pci.c (revision e83980455c8c7eb066405de512be7c4bace3ac4d)
153c25ceaSPaul Brook /*
253c25ceaSPaul Brook  * Virtio PCI Bindings
353c25ceaSPaul Brook  *
453c25ceaSPaul Brook  * Copyright IBM, Corp. 2007
553c25ceaSPaul Brook  * Copyright (c) 2009 CodeSourcery
653c25ceaSPaul Brook  *
753c25ceaSPaul Brook  * Authors:
853c25ceaSPaul Brook  *  Anthony Liguori   <aliguori@us.ibm.com>
953c25ceaSPaul Brook  *  Paul Brook        <paul@codesourcery.com>
1053c25ceaSPaul Brook  *
1153c25ceaSPaul Brook  * This work is licensed under the terms of the GNU GPL, version 2.  See
1253c25ceaSPaul Brook  * the COPYING file in the top-level directory.
1353c25ceaSPaul Brook  *
146b620ca3SPaolo Bonzini  * Contributions after 2012-01-13 are licensed under the terms of the
156b620ca3SPaolo Bonzini  * GNU GPL, version 2 or (at your option) any later version.
1653c25ceaSPaul Brook  */
1753c25ceaSPaul Brook 
1853c25ceaSPaul Brook #include <inttypes.h>
1953c25ceaSPaul Brook 
20cbbe4f50SMichael S. Tsirkin #include "standard-headers/linux/virtio_pci.h"
210d09e41aSPaolo Bonzini #include "hw/virtio/virtio.h"
220d09e41aSPaolo Bonzini #include "hw/virtio/virtio-blk.h"
230d09e41aSPaolo Bonzini #include "hw/virtio/virtio-net.h"
240d09e41aSPaolo Bonzini #include "hw/virtio/virtio-serial.h"
250d09e41aSPaolo Bonzini #include "hw/virtio/virtio-scsi.h"
260d09e41aSPaolo Bonzini #include "hw/virtio/virtio-balloon.h"
2783c9f4caSPaolo Bonzini #include "hw/pci/pci.h"
281de7afc9SPaolo Bonzini #include "qemu/error-report.h"
2983c9f4caSPaolo Bonzini #include "hw/pci/msi.h"
3083c9f4caSPaolo Bonzini #include "hw/pci/msix.h"
3183c9f4caSPaolo Bonzini #include "hw/loader.h"
329c17d615SPaolo Bonzini #include "sysemu/kvm.h"
334be74634SMarkus Armbruster #include "sysemu/block-backend.h"
3447b43a1fSPaolo Bonzini #include "virtio-pci.h"
351de7afc9SPaolo Bonzini #include "qemu/range.h"
360d09e41aSPaolo Bonzini #include "hw/virtio/virtio-bus.h"
3724a6e7f4SKONRAD Frederic #include "qapi/visitor.h"
3853c25ceaSPaul Brook 
39cbbe4f50SMichael S. Tsirkin #define VIRTIO_PCI_REGION_SIZE(dev)     VIRTIO_PCI_CONFIG_OFF(msix_present(dev))
40aba800a3SMichael S. Tsirkin 
41aba800a3SMichael S. Tsirkin /* The remaining space is defined by each driver as the per-driver
42aba800a3SMichael S. Tsirkin  * configuration space */
43cbbe4f50SMichael S. Tsirkin #define VIRTIO_PCI_CONFIG_SIZE(dev)     VIRTIO_PCI_CONFIG_OFF(msix_enabled(dev))
4453c25ceaSPaul Brook 
45ac7af112SAndreas Färber static void virtio_pci_bus_new(VirtioBusState *bus, size_t bus_size,
46ac7af112SAndreas Färber                                VirtIOPCIProxy *dev);
47d51fcfacSKONRAD Frederic 
4853c25ceaSPaul Brook /* virtio device */
49d2a0ccc6SMichael S. Tsirkin /* DeviceState to VirtIOPCIProxy. For use off data-path. TODO: use QOM. */
50d2a0ccc6SMichael S. Tsirkin static inline VirtIOPCIProxy *to_virtio_pci_proxy(DeviceState *d)
5153c25ceaSPaul Brook {
52d2a0ccc6SMichael S. Tsirkin     return container_of(d, VirtIOPCIProxy, pci_dev.qdev);
53d2a0ccc6SMichael S. Tsirkin }
54d2a0ccc6SMichael S. Tsirkin 
55d2a0ccc6SMichael S. Tsirkin /* DeviceState to VirtIOPCIProxy. Note: used on datapath,
56d2a0ccc6SMichael S. Tsirkin  * be careful and test performance if you change this.
57d2a0ccc6SMichael S. Tsirkin  */
58d2a0ccc6SMichael S. Tsirkin static inline VirtIOPCIProxy *to_virtio_pci_proxy_fast(DeviceState *d)
59d2a0ccc6SMichael S. Tsirkin {
60d2a0ccc6SMichael S. Tsirkin     return container_of(d, VirtIOPCIProxy, pci_dev.qdev);
61d2a0ccc6SMichael S. Tsirkin }
62d2a0ccc6SMichael S. Tsirkin 
63d2a0ccc6SMichael S. Tsirkin static void virtio_pci_notify(DeviceState *d, uint16_t vector)
64d2a0ccc6SMichael S. Tsirkin {
65d2a0ccc6SMichael S. Tsirkin     VirtIOPCIProxy *proxy = to_virtio_pci_proxy_fast(d);
66a3fc66d9SPaolo Bonzini 
67aba800a3SMichael S. Tsirkin     if (msix_enabled(&proxy->pci_dev))
68aba800a3SMichael S. Tsirkin         msix_notify(&proxy->pci_dev, vector);
69a3fc66d9SPaolo Bonzini     else {
70a3fc66d9SPaolo Bonzini         VirtIODevice *vdev = virtio_bus_get_device(&proxy->bus);
71a3fc66d9SPaolo Bonzini         pci_set_irq(&proxy->pci_dev, vdev->isr & 1);
72a3fc66d9SPaolo Bonzini     }
7353c25ceaSPaul Brook }
7453c25ceaSPaul Brook 
75d2a0ccc6SMichael S. Tsirkin static void virtio_pci_save_config(DeviceState *d, QEMUFile *f)
76ff24bd58SMichael S. Tsirkin {
77d2a0ccc6SMichael S. Tsirkin     VirtIOPCIProxy *proxy = to_virtio_pci_proxy(d);
78a3fc66d9SPaolo Bonzini     VirtIODevice *vdev = virtio_bus_get_device(&proxy->bus);
79a3fc66d9SPaolo Bonzini 
80ff24bd58SMichael S. Tsirkin     pci_device_save(&proxy->pci_dev, f);
81ff24bd58SMichael S. Tsirkin     msix_save(&proxy->pci_dev, f);
82ff24bd58SMichael S. Tsirkin     if (msix_present(&proxy->pci_dev))
83a3fc66d9SPaolo Bonzini         qemu_put_be16(f, vdev->config_vector);
84ff24bd58SMichael S. Tsirkin }
85ff24bd58SMichael S. Tsirkin 
86d2a0ccc6SMichael S. Tsirkin static void virtio_pci_save_queue(DeviceState *d, int n, QEMUFile *f)
87ff24bd58SMichael S. Tsirkin {
88d2a0ccc6SMichael S. Tsirkin     VirtIOPCIProxy *proxy = to_virtio_pci_proxy(d);
89a3fc66d9SPaolo Bonzini     VirtIODevice *vdev = virtio_bus_get_device(&proxy->bus);
90a3fc66d9SPaolo Bonzini 
91ff24bd58SMichael S. Tsirkin     if (msix_present(&proxy->pci_dev))
92a3fc66d9SPaolo Bonzini         qemu_put_be16(f, virtio_queue_vector(vdev, n));
93ff24bd58SMichael S. Tsirkin }
94ff24bd58SMichael S. Tsirkin 
95d2a0ccc6SMichael S. Tsirkin static int virtio_pci_load_config(DeviceState *d, QEMUFile *f)
96ff24bd58SMichael S. Tsirkin {
97d2a0ccc6SMichael S. Tsirkin     VirtIOPCIProxy *proxy = to_virtio_pci_proxy(d);
98a3fc66d9SPaolo Bonzini     VirtIODevice *vdev = virtio_bus_get_device(&proxy->bus);
99a3fc66d9SPaolo Bonzini 
100ff24bd58SMichael S. Tsirkin     int ret;
101ff24bd58SMichael S. Tsirkin     ret = pci_device_load(&proxy->pci_dev, f);
102e6da7680SMichael S. Tsirkin     if (ret) {
103ff24bd58SMichael S. Tsirkin         return ret;
104e6da7680SMichael S. Tsirkin     }
1053cac001eSMichael S. Tsirkin     msix_unuse_all_vectors(&proxy->pci_dev);
106ff24bd58SMichael S. Tsirkin     msix_load(&proxy->pci_dev, f);
107e6da7680SMichael S. Tsirkin     if (msix_present(&proxy->pci_dev)) {
108a3fc66d9SPaolo Bonzini         qemu_get_be16s(f, &vdev->config_vector);
109e6da7680SMichael S. Tsirkin     } else {
110a3fc66d9SPaolo Bonzini         vdev->config_vector = VIRTIO_NO_VECTOR;
111e6da7680SMichael S. Tsirkin     }
112a3fc66d9SPaolo Bonzini     if (vdev->config_vector != VIRTIO_NO_VECTOR) {
113a3fc66d9SPaolo Bonzini         return msix_vector_use(&proxy->pci_dev, vdev->config_vector);
114e6da7680SMichael S. Tsirkin     }
115ff24bd58SMichael S. Tsirkin     return 0;
116ff24bd58SMichael S. Tsirkin }
117ff24bd58SMichael S. Tsirkin 
118d2a0ccc6SMichael S. Tsirkin static int virtio_pci_load_queue(DeviceState *d, int n, QEMUFile *f)
119ff24bd58SMichael S. Tsirkin {
120d2a0ccc6SMichael S. Tsirkin     VirtIOPCIProxy *proxy = to_virtio_pci_proxy(d);
121a3fc66d9SPaolo Bonzini     VirtIODevice *vdev = virtio_bus_get_device(&proxy->bus);
122a3fc66d9SPaolo Bonzini 
123ff24bd58SMichael S. Tsirkin     uint16_t vector;
124e6da7680SMichael S. Tsirkin     if (msix_present(&proxy->pci_dev)) {
125ff24bd58SMichael S. Tsirkin         qemu_get_be16s(f, &vector);
126e6da7680SMichael S. Tsirkin     } else {
127e6da7680SMichael S. Tsirkin         vector = VIRTIO_NO_VECTOR;
128e6da7680SMichael S. Tsirkin     }
129a3fc66d9SPaolo Bonzini     virtio_queue_set_vector(vdev, n, vector);
130e6da7680SMichael S. Tsirkin     if (vector != VIRTIO_NO_VECTOR) {
131e6da7680SMichael S. Tsirkin         return msix_vector_use(&proxy->pci_dev, vector);
132e6da7680SMichael S. Tsirkin     }
133ff24bd58SMichael S. Tsirkin     return 0;
134ff24bd58SMichael S. Tsirkin }
135ff24bd58SMichael S. Tsirkin 
13625db9ebeSStefan Hajnoczi static int virtio_pci_set_host_notifier_internal(VirtIOPCIProxy *proxy,
13726b9b5feSPaolo Bonzini                                                  int n, bool assign, bool set_handler)
13825db9ebeSStefan Hajnoczi {
139a3fc66d9SPaolo Bonzini     VirtIODevice *vdev = virtio_bus_get_device(&proxy->bus);
140a3fc66d9SPaolo Bonzini     VirtQueue *vq = virtio_get_queue(vdev, n);
14125db9ebeSStefan Hajnoczi     EventNotifier *notifier = virtio_queue_get_host_notifier(vq);
142da146d0aSAvi Kivity     int r = 0;
143da146d0aSAvi Kivity 
14425db9ebeSStefan Hajnoczi     if (assign) {
14525db9ebeSStefan Hajnoczi         r = event_notifier_init(notifier, 1);
14625db9ebeSStefan Hajnoczi         if (r < 0) {
147b36e3914SMichael S. Tsirkin             error_report("%s: unable to init event notifier: %d",
148b36e3914SMichael S. Tsirkin                          __func__, r);
14925db9ebeSStefan Hajnoczi             return r;
15025db9ebeSStefan Hajnoczi         }
15126b9b5feSPaolo Bonzini         virtio_queue_set_host_notifier_fd_handler(vq, true, set_handler);
152da146d0aSAvi Kivity         memory_region_add_eventfd(&proxy->bar, VIRTIO_PCI_QUEUE_NOTIFY, 2,
153753d5e14SPaolo Bonzini                                   true, n, notifier);
15425db9ebeSStefan Hajnoczi     } else {
155da146d0aSAvi Kivity         memory_region_del_eventfd(&proxy->bar, VIRTIO_PCI_QUEUE_NOTIFY, 2,
156753d5e14SPaolo Bonzini                                   true, n, notifier);
15726b9b5feSPaolo Bonzini         virtio_queue_set_host_notifier_fd_handler(vq, false, false);
15825db9ebeSStefan Hajnoczi         event_notifier_cleanup(notifier);
15925db9ebeSStefan Hajnoczi     }
16025db9ebeSStefan Hajnoczi     return r;
16125db9ebeSStefan Hajnoczi }
16225db9ebeSStefan Hajnoczi 
163b36e3914SMichael S. Tsirkin static void virtio_pci_start_ioeventfd(VirtIOPCIProxy *proxy)
16425db9ebeSStefan Hajnoczi {
165a3fc66d9SPaolo Bonzini     VirtIODevice *vdev = virtio_bus_get_device(&proxy->bus);
16625db9ebeSStefan Hajnoczi     int n, r;
16725db9ebeSStefan Hajnoczi 
16825db9ebeSStefan Hajnoczi     if (!(proxy->flags & VIRTIO_PCI_FLAG_USE_IOEVENTFD) ||
16925db9ebeSStefan Hajnoczi         proxy->ioeventfd_disabled ||
17025db9ebeSStefan Hajnoczi         proxy->ioeventfd_started) {
171b36e3914SMichael S. Tsirkin         return;
17225db9ebeSStefan Hajnoczi     }
17325db9ebeSStefan Hajnoczi 
17425db9ebeSStefan Hajnoczi     for (n = 0; n < VIRTIO_PCI_QUEUE_MAX; n++) {
175a3fc66d9SPaolo Bonzini         if (!virtio_queue_get_num(vdev, n)) {
17625db9ebeSStefan Hajnoczi             continue;
17725db9ebeSStefan Hajnoczi         }
17825db9ebeSStefan Hajnoczi 
17926b9b5feSPaolo Bonzini         r = virtio_pci_set_host_notifier_internal(proxy, n, true, true);
18025db9ebeSStefan Hajnoczi         if (r < 0) {
18125db9ebeSStefan Hajnoczi             goto assign_error;
18225db9ebeSStefan Hajnoczi         }
18325db9ebeSStefan Hajnoczi     }
18425db9ebeSStefan Hajnoczi     proxy->ioeventfd_started = true;
185b36e3914SMichael S. Tsirkin     return;
18625db9ebeSStefan Hajnoczi 
18725db9ebeSStefan Hajnoczi assign_error:
18825db9ebeSStefan Hajnoczi     while (--n >= 0) {
189a3fc66d9SPaolo Bonzini         if (!virtio_queue_get_num(vdev, n)) {
19025db9ebeSStefan Hajnoczi             continue;
19125db9ebeSStefan Hajnoczi         }
19225db9ebeSStefan Hajnoczi 
19326b9b5feSPaolo Bonzini         r = virtio_pci_set_host_notifier_internal(proxy, n, false, false);
194b36e3914SMichael S. Tsirkin         assert(r >= 0);
19525db9ebeSStefan Hajnoczi     }
19625db9ebeSStefan Hajnoczi     proxy->ioeventfd_started = false;
197b36e3914SMichael S. Tsirkin     error_report("%s: failed. Fallback to a userspace (slower).", __func__);
19825db9ebeSStefan Hajnoczi }
19925db9ebeSStefan Hajnoczi 
200b36e3914SMichael S. Tsirkin static void virtio_pci_stop_ioeventfd(VirtIOPCIProxy *proxy)
20125db9ebeSStefan Hajnoczi {
202a3fc66d9SPaolo Bonzini     VirtIODevice *vdev = virtio_bus_get_device(&proxy->bus);
203b36e3914SMichael S. Tsirkin     int r;
20425db9ebeSStefan Hajnoczi     int n;
20525db9ebeSStefan Hajnoczi 
20625db9ebeSStefan Hajnoczi     if (!proxy->ioeventfd_started) {
207b36e3914SMichael S. Tsirkin         return;
20825db9ebeSStefan Hajnoczi     }
20925db9ebeSStefan Hajnoczi 
21025db9ebeSStefan Hajnoczi     for (n = 0; n < VIRTIO_PCI_QUEUE_MAX; n++) {
211a3fc66d9SPaolo Bonzini         if (!virtio_queue_get_num(vdev, n)) {
21225db9ebeSStefan Hajnoczi             continue;
21325db9ebeSStefan Hajnoczi         }
21425db9ebeSStefan Hajnoczi 
21526b9b5feSPaolo Bonzini         r = virtio_pci_set_host_notifier_internal(proxy, n, false, false);
216b36e3914SMichael S. Tsirkin         assert(r >= 0);
21725db9ebeSStefan Hajnoczi     }
21825db9ebeSStefan Hajnoczi     proxy->ioeventfd_started = false;
21925db9ebeSStefan Hajnoczi }
22025db9ebeSStefan Hajnoczi 
22153c25ceaSPaul Brook static void virtio_ioport_write(void *opaque, uint32_t addr, uint32_t val)
22253c25ceaSPaul Brook {
22353c25ceaSPaul Brook     VirtIOPCIProxy *proxy = opaque;
224a3fc66d9SPaolo Bonzini     VirtIODevice *vdev = virtio_bus_get_device(&proxy->bus);
225a8170e5eSAvi Kivity     hwaddr pa;
22653c25ceaSPaul Brook 
22753c25ceaSPaul Brook     switch (addr) {
22853c25ceaSPaul Brook     case VIRTIO_PCI_GUEST_FEATURES:
22953c25ceaSPaul Brook         /* Guest does not negotiate properly?  We have to assume nothing. */
23053c25ceaSPaul Brook         if (val & (1 << VIRTIO_F_BAD_FEATURE)) {
231181103cdSKONRAD Frederic             val = virtio_bus_get_vdev_bad_features(&proxy->bus);
23253c25ceaSPaul Brook         }
233ad0c9332SPaolo Bonzini         virtio_set_features(vdev, val);
23453c25ceaSPaul Brook         break;
23553c25ceaSPaul Brook     case VIRTIO_PCI_QUEUE_PFN:
236a8170e5eSAvi Kivity         pa = (hwaddr)val << VIRTIO_PCI_QUEUE_ADDR_SHIFT;
2371b8e9b27SMichael S. Tsirkin         if (pa == 0) {
23825db9ebeSStefan Hajnoczi             virtio_pci_stop_ioeventfd(proxy);
239a3fc66d9SPaolo Bonzini             virtio_reset(vdev);
2401b8e9b27SMichael S. Tsirkin             msix_unuse_all_vectors(&proxy->pci_dev);
2411b8e9b27SMichael S. Tsirkin         }
2427055e687SMichael S. Tsirkin         else
24353c25ceaSPaul Brook             virtio_queue_set_addr(vdev, vdev->queue_sel, pa);
24453c25ceaSPaul Brook         break;
24553c25ceaSPaul Brook     case VIRTIO_PCI_QUEUE_SEL:
24653c25ceaSPaul Brook         if (val < VIRTIO_PCI_QUEUE_MAX)
24753c25ceaSPaul Brook             vdev->queue_sel = val;
24853c25ceaSPaul Brook         break;
24953c25ceaSPaul Brook     case VIRTIO_PCI_QUEUE_NOTIFY:
2507157e2e2SStefan Hajnoczi         if (val < VIRTIO_PCI_QUEUE_MAX) {
25153c25ceaSPaul Brook             virtio_queue_notify(vdev, val);
2527157e2e2SStefan Hajnoczi         }
25353c25ceaSPaul Brook         break;
25453c25ceaSPaul Brook     case VIRTIO_PCI_STATUS:
25525db9ebeSStefan Hajnoczi         if (!(val & VIRTIO_CONFIG_S_DRIVER_OK)) {
25625db9ebeSStefan Hajnoczi             virtio_pci_stop_ioeventfd(proxy);
25725db9ebeSStefan Hajnoczi         }
25825db9ebeSStefan Hajnoczi 
2593e607cb5SMichael S. Tsirkin         virtio_set_status(vdev, val & 0xFF);
26025db9ebeSStefan Hajnoczi 
26125db9ebeSStefan Hajnoczi         if (val & VIRTIO_CONFIG_S_DRIVER_OK) {
26225db9ebeSStefan Hajnoczi             virtio_pci_start_ioeventfd(proxy);
26325db9ebeSStefan Hajnoczi         }
26425db9ebeSStefan Hajnoczi 
2651b8e9b27SMichael S. Tsirkin         if (vdev->status == 0) {
266a3fc66d9SPaolo Bonzini             virtio_reset(vdev);
2671b8e9b27SMichael S. Tsirkin             msix_unuse_all_vectors(&proxy->pci_dev);
2681b8e9b27SMichael S. Tsirkin         }
269c81131dbSAlexander Graf 
270e43c0b2eSMichael S. Tsirkin         /* Linux before 2.6.34 drives the device without enabling
271e43c0b2eSMichael S. Tsirkin            the PCI device bus master bit. Enable it automatically
272e43c0b2eSMichael S. Tsirkin            for the guest. This is a PCI spec violation but so is
273e43c0b2eSMichael S. Tsirkin            initiating DMA with bus master bit clear. */
274e43c0b2eSMichael S. Tsirkin         if (val == (VIRTIO_CONFIG_S_ACKNOWLEDGE | VIRTIO_CONFIG_S_DRIVER)) {
275e43c0b2eSMichael S. Tsirkin             pci_default_write_config(&proxy->pci_dev, PCI_COMMAND,
276e43c0b2eSMichael S. Tsirkin                                      proxy->pci_dev.config[PCI_COMMAND] |
277e43c0b2eSMichael S. Tsirkin                                      PCI_COMMAND_MASTER, 1);
278e43c0b2eSMichael S. Tsirkin         }
27953c25ceaSPaul Brook         break;
280aba800a3SMichael S. Tsirkin     case VIRTIO_MSI_CONFIG_VECTOR:
281aba800a3SMichael S. Tsirkin         msix_vector_unuse(&proxy->pci_dev, vdev->config_vector);
282aba800a3SMichael S. Tsirkin         /* Make it possible for guest to discover an error took place. */
283aba800a3SMichael S. Tsirkin         if (msix_vector_use(&proxy->pci_dev, val) < 0)
284aba800a3SMichael S. Tsirkin             val = VIRTIO_NO_VECTOR;
285aba800a3SMichael S. Tsirkin         vdev->config_vector = val;
286aba800a3SMichael S. Tsirkin         break;
287aba800a3SMichael S. Tsirkin     case VIRTIO_MSI_QUEUE_VECTOR:
288aba800a3SMichael S. Tsirkin         msix_vector_unuse(&proxy->pci_dev,
289aba800a3SMichael S. Tsirkin                           virtio_queue_vector(vdev, vdev->queue_sel));
290aba800a3SMichael S. Tsirkin         /* Make it possible for guest to discover an error took place. */
291aba800a3SMichael S. Tsirkin         if (msix_vector_use(&proxy->pci_dev, val) < 0)
292aba800a3SMichael S. Tsirkin             val = VIRTIO_NO_VECTOR;
293aba800a3SMichael S. Tsirkin         virtio_queue_set_vector(vdev, vdev->queue_sel, val);
294aba800a3SMichael S. Tsirkin         break;
295aba800a3SMichael S. Tsirkin     default:
2964e02d460SStefan Hajnoczi         error_report("%s: unexpected address 0x%x value 0x%x",
297aba800a3SMichael S. Tsirkin                      __func__, addr, val);
298aba800a3SMichael S. Tsirkin         break;
29953c25ceaSPaul Brook     }
30053c25ceaSPaul Brook }
30153c25ceaSPaul Brook 
302aba800a3SMichael S. Tsirkin static uint32_t virtio_ioport_read(VirtIOPCIProxy *proxy, uint32_t addr)
30353c25ceaSPaul Brook {
304a3fc66d9SPaolo Bonzini     VirtIODevice *vdev = virtio_bus_get_device(&proxy->bus);
30553c25ceaSPaul Brook     uint32_t ret = 0xFFFFFFFF;
30653c25ceaSPaul Brook 
30753c25ceaSPaul Brook     switch (addr) {
30853c25ceaSPaul Brook     case VIRTIO_PCI_HOST_FEATURES:
3096b8f1020SCornelia Huck         ret = vdev->host_features;
31053c25ceaSPaul Brook         break;
31153c25ceaSPaul Brook     case VIRTIO_PCI_GUEST_FEATURES:
312704a76fcSMichael S. Tsirkin         ret = vdev->guest_features;
31353c25ceaSPaul Brook         break;
31453c25ceaSPaul Brook     case VIRTIO_PCI_QUEUE_PFN:
31553c25ceaSPaul Brook         ret = virtio_queue_get_addr(vdev, vdev->queue_sel)
31653c25ceaSPaul Brook               >> VIRTIO_PCI_QUEUE_ADDR_SHIFT;
31753c25ceaSPaul Brook         break;
31853c25ceaSPaul Brook     case VIRTIO_PCI_QUEUE_NUM:
31953c25ceaSPaul Brook         ret = virtio_queue_get_num(vdev, vdev->queue_sel);
32053c25ceaSPaul Brook         break;
32153c25ceaSPaul Brook     case VIRTIO_PCI_QUEUE_SEL:
32253c25ceaSPaul Brook         ret = vdev->queue_sel;
32353c25ceaSPaul Brook         break;
32453c25ceaSPaul Brook     case VIRTIO_PCI_STATUS:
32553c25ceaSPaul Brook         ret = vdev->status;
32653c25ceaSPaul Brook         break;
32753c25ceaSPaul Brook     case VIRTIO_PCI_ISR:
32853c25ceaSPaul Brook         /* reading from the ISR also clears it. */
32953c25ceaSPaul Brook         ret = vdev->isr;
33053c25ceaSPaul Brook         vdev->isr = 0;
3319e64f8a3SMarcel Apfelbaum         pci_irq_deassert(&proxy->pci_dev);
33253c25ceaSPaul Brook         break;
333aba800a3SMichael S. Tsirkin     case VIRTIO_MSI_CONFIG_VECTOR:
334aba800a3SMichael S. Tsirkin         ret = vdev->config_vector;
335aba800a3SMichael S. Tsirkin         break;
336aba800a3SMichael S. Tsirkin     case VIRTIO_MSI_QUEUE_VECTOR:
337aba800a3SMichael S. Tsirkin         ret = virtio_queue_vector(vdev, vdev->queue_sel);
338aba800a3SMichael S. Tsirkin         break;
33953c25ceaSPaul Brook     default:
34053c25ceaSPaul Brook         break;
34153c25ceaSPaul Brook     }
34253c25ceaSPaul Brook 
34353c25ceaSPaul Brook     return ret;
34453c25ceaSPaul Brook }
34553c25ceaSPaul Brook 
346df6db5b3SAlexander Graf static uint64_t virtio_pci_config_read(void *opaque, hwaddr addr,
347df6db5b3SAlexander Graf                                        unsigned size)
34853c25ceaSPaul Brook {
34953c25ceaSPaul Brook     VirtIOPCIProxy *proxy = opaque;
350a3fc66d9SPaolo Bonzini     VirtIODevice *vdev = virtio_bus_get_device(&proxy->bus);
351cbbe4f50SMichael S. Tsirkin     uint32_t config = VIRTIO_PCI_CONFIG_SIZE(&proxy->pci_dev);
352df6db5b3SAlexander Graf     uint64_t val = 0;
353df6db5b3SAlexander Graf     if (addr < config) {
354aba800a3SMichael S. Tsirkin         return virtio_ioport_read(proxy, addr);
35553c25ceaSPaul Brook     }
356aba800a3SMichael S. Tsirkin     addr -= config;
357df6db5b3SAlexander Graf 
358df6db5b3SAlexander Graf     switch (size) {
359df6db5b3SAlexander Graf     case 1:
360a3fc66d9SPaolo Bonzini         val = virtio_config_readb(vdev, addr);
361df6db5b3SAlexander Graf         break;
362df6db5b3SAlexander Graf     case 2:
363a3fc66d9SPaolo Bonzini         val = virtio_config_readw(vdev, addr);
364616a6552SGreg Kurz         if (virtio_is_big_endian(vdev)) {
3658e4a424bSBlue Swirl             val = bswap16(val);
3668e4a424bSBlue Swirl         }
367df6db5b3SAlexander Graf         break;
368df6db5b3SAlexander Graf     case 4:
369a3fc66d9SPaolo Bonzini         val = virtio_config_readl(vdev, addr);
370616a6552SGreg Kurz         if (virtio_is_big_endian(vdev)) {
3718e4a424bSBlue Swirl             val = bswap32(val);
3728e4a424bSBlue Swirl         }
373df6db5b3SAlexander Graf         break;
374df6db5b3SAlexander Graf     }
37582afa586SBenjamin Herrenschmidt     return val;
37653c25ceaSPaul Brook }
37753c25ceaSPaul Brook 
378df6db5b3SAlexander Graf static void virtio_pci_config_write(void *opaque, hwaddr addr,
379df6db5b3SAlexander Graf                                     uint64_t val, unsigned size)
38053c25ceaSPaul Brook {
38153c25ceaSPaul Brook     VirtIOPCIProxy *proxy = opaque;
382cbbe4f50SMichael S. Tsirkin     uint32_t config = VIRTIO_PCI_CONFIG_SIZE(&proxy->pci_dev);
383a3fc66d9SPaolo Bonzini     VirtIODevice *vdev = virtio_bus_get_device(&proxy->bus);
384aba800a3SMichael S. Tsirkin     if (addr < config) {
385aba800a3SMichael S. Tsirkin         virtio_ioport_write(proxy, addr, val);
386aba800a3SMichael S. Tsirkin         return;
387aba800a3SMichael S. Tsirkin     }
388aba800a3SMichael S. Tsirkin     addr -= config;
389df6db5b3SAlexander Graf     /*
390df6db5b3SAlexander Graf      * Virtio-PCI is odd. Ioports are LE but config space is target native
391df6db5b3SAlexander Graf      * endian.
392df6db5b3SAlexander Graf      */
393df6db5b3SAlexander Graf     switch (size) {
394df6db5b3SAlexander Graf     case 1:
395a3fc66d9SPaolo Bonzini         virtio_config_writeb(vdev, addr, val);
396df6db5b3SAlexander Graf         break;
397df6db5b3SAlexander Graf     case 2:
398616a6552SGreg Kurz         if (virtio_is_big_endian(vdev)) {
3998e4a424bSBlue Swirl             val = bswap16(val);
4008e4a424bSBlue Swirl         }
401a3fc66d9SPaolo Bonzini         virtio_config_writew(vdev, addr, val);
402df6db5b3SAlexander Graf         break;
403df6db5b3SAlexander Graf     case 4:
404616a6552SGreg Kurz         if (virtio_is_big_endian(vdev)) {
4058e4a424bSBlue Swirl             val = bswap32(val);
4068e4a424bSBlue Swirl         }
407a3fc66d9SPaolo Bonzini         virtio_config_writel(vdev, addr, val);
408df6db5b3SAlexander Graf         break;
409df6db5b3SAlexander Graf     }
41053c25ceaSPaul Brook }
41153c25ceaSPaul Brook 
412da146d0aSAvi Kivity static const MemoryRegionOps virtio_pci_config_ops = {
413df6db5b3SAlexander Graf     .read = virtio_pci_config_read,
414df6db5b3SAlexander Graf     .write = virtio_pci_config_write,
415df6db5b3SAlexander Graf     .impl = {
416df6db5b3SAlexander Graf         .min_access_size = 1,
417df6db5b3SAlexander Graf         .max_access_size = 4,
418df6db5b3SAlexander Graf     },
4198e4a424bSBlue Swirl     .endianness = DEVICE_LITTLE_ENDIAN,
420da146d0aSAvi Kivity };
421aba800a3SMichael S. Tsirkin 
422aba800a3SMichael S. Tsirkin static void virtio_write_config(PCIDevice *pci_dev, uint32_t address,
423aba800a3SMichael S. Tsirkin                                 uint32_t val, int len)
424aba800a3SMichael S. Tsirkin {
425ed757e14SYan Vugenfirer     VirtIOPCIProxy *proxy = DO_UPCAST(VirtIOPCIProxy, pci_dev, pci_dev);
426a3fc66d9SPaolo Bonzini     VirtIODevice *vdev = virtio_bus_get_device(&proxy->bus);
427ed757e14SYan Vugenfirer 
4281129714fSMichael S. Tsirkin     pci_default_write_config(pci_dev, address, val, len);
4291129714fSMichael S. Tsirkin 
4301129714fSMichael S. Tsirkin     if (range_covers_byte(address, len, PCI_COMMAND) &&
43168a27b20SMichael S. Tsirkin         !(pci_dev->config[PCI_COMMAND] & PCI_COMMAND_MASTER)) {
43225db9ebeSStefan Hajnoczi         virtio_pci_stop_ioeventfd(proxy);
43345363e46SMichael S. Tsirkin         virtio_set_status(vdev, vdev->status & ~VIRTIO_CONFIG_S_DRIVER_OK);
434ed757e14SYan Vugenfirer     }
43553c25ceaSPaul Brook }
43653c25ceaSPaul Brook 
4377d37d351SJan Kiszka static int kvm_virtio_pci_vq_vector_use(VirtIOPCIProxy *proxy,
4387d37d351SJan Kiszka                                         unsigned int queue_no,
4397d37d351SJan Kiszka                                         unsigned int vector,
4407d37d351SJan Kiszka                                         MSIMessage msg)
4417d37d351SJan Kiszka {
4427d37d351SJan Kiszka     VirtIOIRQFD *irqfd = &proxy->vector_irqfd[vector];
44315b2bd18SPaolo Bonzini     int ret;
4447d37d351SJan Kiszka 
4457d37d351SJan Kiszka     if (irqfd->users == 0) {
4467d37d351SJan Kiszka         ret = kvm_irqchip_add_msi_route(kvm_state, msg);
4477d37d351SJan Kiszka         if (ret < 0) {
4487d37d351SJan Kiszka             return ret;
4497d37d351SJan Kiszka         }
4507d37d351SJan Kiszka         irqfd->virq = ret;
4517d37d351SJan Kiszka     }
4527d37d351SJan Kiszka     irqfd->users++;
4537d37d351SJan Kiszka     return 0;
4547d37d351SJan Kiszka }
4557d37d351SJan Kiszka 
4567d37d351SJan Kiszka static void kvm_virtio_pci_vq_vector_release(VirtIOPCIProxy *proxy,
457774345f9SMichael S. Tsirkin                                              unsigned int vector)
458774345f9SMichael S. Tsirkin {
459774345f9SMichael S. Tsirkin     VirtIOIRQFD *irqfd = &proxy->vector_irqfd[vector];
460774345f9SMichael S. Tsirkin     if (--irqfd->users == 0) {
461774345f9SMichael S. Tsirkin         kvm_irqchip_release_virq(kvm_state, irqfd->virq);
462774345f9SMichael S. Tsirkin     }
463774345f9SMichael S. Tsirkin }
464774345f9SMichael S. Tsirkin 
465f1d0f15aSMichael S. Tsirkin static int kvm_virtio_pci_irqfd_use(VirtIOPCIProxy *proxy,
466f1d0f15aSMichael S. Tsirkin                                  unsigned int queue_no,
467f1d0f15aSMichael S. Tsirkin                                  unsigned int vector)
468f1d0f15aSMichael S. Tsirkin {
469f1d0f15aSMichael S. Tsirkin     VirtIOIRQFD *irqfd = &proxy->vector_irqfd[vector];
470a3fc66d9SPaolo Bonzini     VirtIODevice *vdev = virtio_bus_get_device(&proxy->bus);
471a3fc66d9SPaolo Bonzini     VirtQueue *vq = virtio_get_queue(vdev, queue_no);
472f1d0f15aSMichael S. Tsirkin     EventNotifier *n = virtio_queue_get_guest_notifier(vq);
473f1d0f15aSMichael S. Tsirkin     int ret;
474ca916d37SVincenzo Maffione     ret = kvm_irqchip_add_irqfd_notifier(kvm_state, n, NULL, irqfd->virq);
475f1d0f15aSMichael S. Tsirkin     return ret;
476f1d0f15aSMichael S. Tsirkin }
477f1d0f15aSMichael S. Tsirkin 
478f1d0f15aSMichael S. Tsirkin static void kvm_virtio_pci_irqfd_release(VirtIOPCIProxy *proxy,
4797d37d351SJan Kiszka                                       unsigned int queue_no,
4807d37d351SJan Kiszka                                       unsigned int vector)
4817d37d351SJan Kiszka {
482a3fc66d9SPaolo Bonzini     VirtIODevice *vdev = virtio_bus_get_device(&proxy->bus);
483a3fc66d9SPaolo Bonzini     VirtQueue *vq = virtio_get_queue(vdev, queue_no);
48415b2bd18SPaolo Bonzini     EventNotifier *n = virtio_queue_get_guest_notifier(vq);
4857d37d351SJan Kiszka     VirtIOIRQFD *irqfd = &proxy->vector_irqfd[vector];
48615b2bd18SPaolo Bonzini     int ret;
4877d37d351SJan Kiszka 
488b131c74aSJan Kiszka     ret = kvm_irqchip_remove_irqfd_notifier(kvm_state, n, irqfd->virq);
4897d37d351SJan Kiszka     assert(ret == 0);
490f1d0f15aSMichael S. Tsirkin }
4917d37d351SJan Kiszka 
492774345f9SMichael S. Tsirkin static int kvm_virtio_pci_vector_use(VirtIOPCIProxy *proxy, int nvqs)
493774345f9SMichael S. Tsirkin {
494774345f9SMichael S. Tsirkin     PCIDevice *dev = &proxy->pci_dev;
495a3fc66d9SPaolo Bonzini     VirtIODevice *vdev = virtio_bus_get_device(&proxy->bus);
496181103cdSKONRAD Frederic     VirtioDeviceClass *k = VIRTIO_DEVICE_GET_CLASS(vdev);
497774345f9SMichael S. Tsirkin     unsigned int vector;
498774345f9SMichael S. Tsirkin     int ret, queue_no;
499774345f9SMichael S. Tsirkin     MSIMessage msg;
500774345f9SMichael S. Tsirkin 
501774345f9SMichael S. Tsirkin     for (queue_no = 0; queue_no < nvqs; queue_no++) {
502774345f9SMichael S. Tsirkin         if (!virtio_queue_get_num(vdev, queue_no)) {
503774345f9SMichael S. Tsirkin             break;
504774345f9SMichael S. Tsirkin         }
505774345f9SMichael S. Tsirkin         vector = virtio_queue_vector(vdev, queue_no);
506774345f9SMichael S. Tsirkin         if (vector >= msix_nr_vectors_allocated(dev)) {
507774345f9SMichael S. Tsirkin             continue;
508774345f9SMichael S. Tsirkin         }
509774345f9SMichael S. Tsirkin         msg = msix_get_message(dev, vector);
510774345f9SMichael S. Tsirkin         ret = kvm_virtio_pci_vq_vector_use(proxy, queue_no, vector, msg);
511774345f9SMichael S. Tsirkin         if (ret < 0) {
512774345f9SMichael S. Tsirkin             goto undo;
513774345f9SMichael S. Tsirkin         }
514f1d0f15aSMichael S. Tsirkin         /* If guest supports masking, set up irqfd now.
515f1d0f15aSMichael S. Tsirkin          * Otherwise, delay until unmasked in the frontend.
516f1d0f15aSMichael S. Tsirkin          */
517181103cdSKONRAD Frederic         if (k->guest_notifier_mask) {
518f1d0f15aSMichael S. Tsirkin             ret = kvm_virtio_pci_irqfd_use(proxy, queue_no, vector);
519f1d0f15aSMichael S. Tsirkin             if (ret < 0) {
520f1d0f15aSMichael S. Tsirkin                 kvm_virtio_pci_vq_vector_release(proxy, vector);
521f1d0f15aSMichael S. Tsirkin                 goto undo;
522f1d0f15aSMichael S. Tsirkin             }
523f1d0f15aSMichael S. Tsirkin         }
524774345f9SMichael S. Tsirkin     }
525774345f9SMichael S. Tsirkin     return 0;
526774345f9SMichael S. Tsirkin 
527774345f9SMichael S. Tsirkin undo:
528774345f9SMichael S. Tsirkin     while (--queue_no >= 0) {
529774345f9SMichael S. Tsirkin         vector = virtio_queue_vector(vdev, queue_no);
530774345f9SMichael S. Tsirkin         if (vector >= msix_nr_vectors_allocated(dev)) {
531774345f9SMichael S. Tsirkin             continue;
532774345f9SMichael S. Tsirkin         }
533181103cdSKONRAD Frederic         if (k->guest_notifier_mask) {
534e387f99eSMichael S. Tsirkin             kvm_virtio_pci_irqfd_release(proxy, queue_no, vector);
535f1d0f15aSMichael S. Tsirkin         }
536774345f9SMichael S. Tsirkin         kvm_virtio_pci_vq_vector_release(proxy, vector);
537774345f9SMichael S. Tsirkin     }
538774345f9SMichael S. Tsirkin     return ret;
539774345f9SMichael S. Tsirkin }
540774345f9SMichael S. Tsirkin 
541774345f9SMichael S. Tsirkin static void kvm_virtio_pci_vector_release(VirtIOPCIProxy *proxy, int nvqs)
542774345f9SMichael S. Tsirkin {
543774345f9SMichael S. Tsirkin     PCIDevice *dev = &proxy->pci_dev;
544a3fc66d9SPaolo Bonzini     VirtIODevice *vdev = virtio_bus_get_device(&proxy->bus);
545774345f9SMichael S. Tsirkin     unsigned int vector;
546774345f9SMichael S. Tsirkin     int queue_no;
547181103cdSKONRAD Frederic     VirtioDeviceClass *k = VIRTIO_DEVICE_GET_CLASS(vdev);
548774345f9SMichael S. Tsirkin 
549774345f9SMichael S. Tsirkin     for (queue_no = 0; queue_no < nvqs; queue_no++) {
550774345f9SMichael S. Tsirkin         if (!virtio_queue_get_num(vdev, queue_no)) {
551774345f9SMichael S. Tsirkin             break;
552774345f9SMichael S. Tsirkin         }
553774345f9SMichael S. Tsirkin         vector = virtio_queue_vector(vdev, queue_no);
554774345f9SMichael S. Tsirkin         if (vector >= msix_nr_vectors_allocated(dev)) {
555774345f9SMichael S. Tsirkin             continue;
556774345f9SMichael S. Tsirkin         }
557f1d0f15aSMichael S. Tsirkin         /* If guest supports masking, clean up irqfd now.
558f1d0f15aSMichael S. Tsirkin          * Otherwise, it was cleaned when masked in the frontend.
559f1d0f15aSMichael S. Tsirkin          */
560181103cdSKONRAD Frederic         if (k->guest_notifier_mask) {
561e387f99eSMichael S. Tsirkin             kvm_virtio_pci_irqfd_release(proxy, queue_no, vector);
562f1d0f15aSMichael S. Tsirkin         }
563774345f9SMichael S. Tsirkin         kvm_virtio_pci_vq_vector_release(proxy, vector);
5647d37d351SJan Kiszka     }
5657d37d351SJan Kiszka }
5667d37d351SJan Kiszka 
567a38b2c49SMichael S. Tsirkin static int virtio_pci_vq_vector_unmask(VirtIOPCIProxy *proxy,
568774345f9SMichael S. Tsirkin                                        unsigned int queue_no,
569774345f9SMichael S. Tsirkin                                        unsigned int vector,
570774345f9SMichael S. Tsirkin                                        MSIMessage msg)
571774345f9SMichael S. Tsirkin {
572a3fc66d9SPaolo Bonzini     VirtIODevice *vdev = virtio_bus_get_device(&proxy->bus);
573a3fc66d9SPaolo Bonzini     VirtioDeviceClass *k = VIRTIO_DEVICE_GET_CLASS(vdev);
574a3fc66d9SPaolo Bonzini     VirtQueue *vq = virtio_get_queue(vdev, queue_no);
575774345f9SMichael S. Tsirkin     EventNotifier *n = virtio_queue_get_guest_notifier(vq);
576a38b2c49SMichael S. Tsirkin     VirtIOIRQFD *irqfd;
57753510bfcSMichael Roth     int ret = 0;
578774345f9SMichael S. Tsirkin 
579a38b2c49SMichael S. Tsirkin     if (proxy->vector_irqfd) {
580a38b2c49SMichael S. Tsirkin         irqfd = &proxy->vector_irqfd[vector];
581774345f9SMichael S. Tsirkin         if (irqfd->msg.data != msg.data || irqfd->msg.address != msg.address) {
582774345f9SMichael S. Tsirkin             ret = kvm_irqchip_update_msi_route(kvm_state, irqfd->virq, msg);
583774345f9SMichael S. Tsirkin             if (ret < 0) {
584774345f9SMichael S. Tsirkin                 return ret;
585774345f9SMichael S. Tsirkin             }
586774345f9SMichael S. Tsirkin         }
587a38b2c49SMichael S. Tsirkin     }
588774345f9SMichael S. Tsirkin 
589f1d0f15aSMichael S. Tsirkin     /* If guest supports masking, irqfd is already setup, unmask it.
590f1d0f15aSMichael S. Tsirkin      * Otherwise, set it up now.
591f1d0f15aSMichael S. Tsirkin      */
592181103cdSKONRAD Frederic     if (k->guest_notifier_mask) {
593a3fc66d9SPaolo Bonzini         k->guest_notifier_mask(vdev, queue_no, false);
594f1d0f15aSMichael S. Tsirkin         /* Test after unmasking to avoid losing events. */
595181103cdSKONRAD Frederic         if (k->guest_notifier_pending &&
596a3fc66d9SPaolo Bonzini             k->guest_notifier_pending(vdev, queue_no)) {
597f1d0f15aSMichael S. Tsirkin             event_notifier_set(n);
598f1d0f15aSMichael S. Tsirkin         }
599f1d0f15aSMichael S. Tsirkin     } else {
600f1d0f15aSMichael S. Tsirkin         ret = kvm_virtio_pci_irqfd_use(proxy, queue_no, vector);
601f1d0f15aSMichael S. Tsirkin     }
602774345f9SMichael S. Tsirkin     return ret;
603774345f9SMichael S. Tsirkin }
604774345f9SMichael S. Tsirkin 
605a38b2c49SMichael S. Tsirkin static void virtio_pci_vq_vector_mask(VirtIOPCIProxy *proxy,
6067d37d351SJan Kiszka                                              unsigned int queue_no,
6077d37d351SJan Kiszka                                              unsigned int vector)
6087d37d351SJan Kiszka {
609a3fc66d9SPaolo Bonzini     VirtIODevice *vdev = virtio_bus_get_device(&proxy->bus);
610a3fc66d9SPaolo Bonzini     VirtioDeviceClass *k = VIRTIO_DEVICE_GET_CLASS(vdev);
611181103cdSKONRAD Frederic 
612f1d0f15aSMichael S. Tsirkin     /* If guest supports masking, keep irqfd but mask it.
613f1d0f15aSMichael S. Tsirkin      * Otherwise, clean it up now.
614f1d0f15aSMichael S. Tsirkin      */
615181103cdSKONRAD Frederic     if (k->guest_notifier_mask) {
616a3fc66d9SPaolo Bonzini         k->guest_notifier_mask(vdev, queue_no, true);
617f1d0f15aSMichael S. Tsirkin     } else {
618e387f99eSMichael S. Tsirkin         kvm_virtio_pci_irqfd_release(proxy, queue_no, vector);
619f1d0f15aSMichael S. Tsirkin     }
6207d37d351SJan Kiszka }
6217d37d351SJan Kiszka 
622a38b2c49SMichael S. Tsirkin static int virtio_pci_vector_unmask(PCIDevice *dev, unsigned vector,
6237d37d351SJan Kiszka                                     MSIMessage msg)
6247d37d351SJan Kiszka {
6257d37d351SJan Kiszka     VirtIOPCIProxy *proxy = container_of(dev, VirtIOPCIProxy, pci_dev);
626a3fc66d9SPaolo Bonzini     VirtIODevice *vdev = virtio_bus_get_device(&proxy->bus);
627851c2a75SJason Wang     VirtQueue *vq = virtio_vector_first_queue(vdev, vector);
628851c2a75SJason Wang     int ret, index, unmasked = 0;
6297d37d351SJan Kiszka 
630851c2a75SJason Wang     while (vq) {
631851c2a75SJason Wang         index = virtio_get_queue_index(vq);
632851c2a75SJason Wang         if (!virtio_queue_get_num(vdev, index)) {
6337d37d351SJan Kiszka             break;
6347d37d351SJan Kiszka         }
635851c2a75SJason Wang         ret = virtio_pci_vq_vector_unmask(proxy, index, vector, msg);
6367d37d351SJan Kiszka         if (ret < 0) {
6377d37d351SJan Kiszka             goto undo;
6387d37d351SJan Kiszka         }
639851c2a75SJason Wang         vq = virtio_vector_next_queue(vq);
640851c2a75SJason Wang         ++unmasked;
6417d37d351SJan Kiszka     }
642851c2a75SJason Wang 
6437d37d351SJan Kiszka     return 0;
6447d37d351SJan Kiszka 
6457d37d351SJan Kiszka undo:
646851c2a75SJason Wang     vq = virtio_vector_first_queue(vdev, vector);
647851c2a75SJason Wang     while (vq && --unmasked >= 0) {
648851c2a75SJason Wang         index = virtio_get_queue_index(vq);
649851c2a75SJason Wang         virtio_pci_vq_vector_mask(proxy, index, vector);
650851c2a75SJason Wang         vq = virtio_vector_next_queue(vq);
6517d37d351SJan Kiszka     }
6527d37d351SJan Kiszka     return ret;
6537d37d351SJan Kiszka }
6547d37d351SJan Kiszka 
655a38b2c49SMichael S. Tsirkin static void virtio_pci_vector_mask(PCIDevice *dev, unsigned vector)
6567d37d351SJan Kiszka {
6577d37d351SJan Kiszka     VirtIOPCIProxy *proxy = container_of(dev, VirtIOPCIProxy, pci_dev);
658a3fc66d9SPaolo Bonzini     VirtIODevice *vdev = virtio_bus_get_device(&proxy->bus);
659851c2a75SJason Wang     VirtQueue *vq = virtio_vector_first_queue(vdev, vector);
660851c2a75SJason Wang     int index;
6617d37d351SJan Kiszka 
662851c2a75SJason Wang     while (vq) {
663851c2a75SJason Wang         index = virtio_get_queue_index(vq);
664851c2a75SJason Wang         if (!virtio_queue_get_num(vdev, index)) {
6657d37d351SJan Kiszka             break;
6667d37d351SJan Kiszka         }
667851c2a75SJason Wang         virtio_pci_vq_vector_mask(proxy, index, vector);
668851c2a75SJason Wang         vq = virtio_vector_next_queue(vq);
6697d37d351SJan Kiszka     }
6707d37d351SJan Kiszka }
6717d37d351SJan Kiszka 
672a38b2c49SMichael S. Tsirkin static void virtio_pci_vector_poll(PCIDevice *dev,
67389d62be9SMichael S. Tsirkin                                    unsigned int vector_start,
67489d62be9SMichael S. Tsirkin                                    unsigned int vector_end)
67589d62be9SMichael S. Tsirkin {
67689d62be9SMichael S. Tsirkin     VirtIOPCIProxy *proxy = container_of(dev, VirtIOPCIProxy, pci_dev);
677a3fc66d9SPaolo Bonzini     VirtIODevice *vdev = virtio_bus_get_device(&proxy->bus);
678181103cdSKONRAD Frederic     VirtioDeviceClass *k = VIRTIO_DEVICE_GET_CLASS(vdev);
67989d62be9SMichael S. Tsirkin     int queue_no;
68089d62be9SMichael S. Tsirkin     unsigned int vector;
68189d62be9SMichael S. Tsirkin     EventNotifier *notifier;
68289d62be9SMichael S. Tsirkin     VirtQueue *vq;
68389d62be9SMichael S. Tsirkin 
6842d620f59SMichael S. Tsirkin     for (queue_no = 0; queue_no < proxy->nvqs_with_notifiers; queue_no++) {
68589d62be9SMichael S. Tsirkin         if (!virtio_queue_get_num(vdev, queue_no)) {
68689d62be9SMichael S. Tsirkin             break;
68789d62be9SMichael S. Tsirkin         }
68889d62be9SMichael S. Tsirkin         vector = virtio_queue_vector(vdev, queue_no);
68989d62be9SMichael S. Tsirkin         if (vector < vector_start || vector >= vector_end ||
69089d62be9SMichael S. Tsirkin             !msix_is_masked(dev, vector)) {
69189d62be9SMichael S. Tsirkin             continue;
69289d62be9SMichael S. Tsirkin         }
69389d62be9SMichael S. Tsirkin         vq = virtio_get_queue(vdev, queue_no);
69489d62be9SMichael S. Tsirkin         notifier = virtio_queue_get_guest_notifier(vq);
695181103cdSKONRAD Frederic         if (k->guest_notifier_pending) {
696181103cdSKONRAD Frederic             if (k->guest_notifier_pending(vdev, queue_no)) {
697f1d0f15aSMichael S. Tsirkin                 msix_set_pending(dev, vector);
698f1d0f15aSMichael S. Tsirkin             }
699f1d0f15aSMichael S. Tsirkin         } else if (event_notifier_test_and_clear(notifier)) {
70089d62be9SMichael S. Tsirkin             msix_set_pending(dev, vector);
70189d62be9SMichael S. Tsirkin         }
70289d62be9SMichael S. Tsirkin     }
70389d62be9SMichael S. Tsirkin }
70489d62be9SMichael S. Tsirkin 
70589d62be9SMichael S. Tsirkin static int virtio_pci_set_guest_notifier(DeviceState *d, int n, bool assign,
70689d62be9SMichael S. Tsirkin                                          bool with_irqfd)
707ade80dc8SMichael S. Tsirkin {
708d2a0ccc6SMichael S. Tsirkin     VirtIOPCIProxy *proxy = to_virtio_pci_proxy(d);
709a3fc66d9SPaolo Bonzini     VirtIODevice *vdev = virtio_bus_get_device(&proxy->bus);
710a3fc66d9SPaolo Bonzini     VirtioDeviceClass *vdc = VIRTIO_DEVICE_GET_CLASS(vdev);
711a3fc66d9SPaolo Bonzini     VirtQueue *vq = virtio_get_queue(vdev, n);
712ade80dc8SMichael S. Tsirkin     EventNotifier *notifier = virtio_queue_get_guest_notifier(vq);
713ade80dc8SMichael S. Tsirkin 
714ade80dc8SMichael S. Tsirkin     if (assign) {
715ade80dc8SMichael S. Tsirkin         int r = event_notifier_init(notifier, 0);
716ade80dc8SMichael S. Tsirkin         if (r < 0) {
717ade80dc8SMichael S. Tsirkin             return r;
718ade80dc8SMichael S. Tsirkin         }
71989d62be9SMichael S. Tsirkin         virtio_queue_set_guest_notifier_fd_handler(vq, true, with_irqfd);
720ade80dc8SMichael S. Tsirkin     } else {
72189d62be9SMichael S. Tsirkin         virtio_queue_set_guest_notifier_fd_handler(vq, false, with_irqfd);
722ade80dc8SMichael S. Tsirkin         event_notifier_cleanup(notifier);
723ade80dc8SMichael S. Tsirkin     }
724ade80dc8SMichael S. Tsirkin 
72562c96360SMichael S. Tsirkin     if (!msix_enabled(&proxy->pci_dev) && vdc->guest_notifier_mask) {
726a3fc66d9SPaolo Bonzini         vdc->guest_notifier_mask(vdev, n, !assign);
72762c96360SMichael S. Tsirkin     }
72862c96360SMichael S. Tsirkin 
729ade80dc8SMichael S. Tsirkin     return 0;
730ade80dc8SMichael S. Tsirkin }
731ade80dc8SMichael S. Tsirkin 
732d2a0ccc6SMichael S. Tsirkin static bool virtio_pci_query_guest_notifiers(DeviceState *d)
7335430a28fSmst@redhat.com {
734d2a0ccc6SMichael S. Tsirkin     VirtIOPCIProxy *proxy = to_virtio_pci_proxy(d);
7355430a28fSmst@redhat.com     return msix_enabled(&proxy->pci_dev);
7365430a28fSmst@redhat.com }
7375430a28fSmst@redhat.com 
7382d620f59SMichael S. Tsirkin static int virtio_pci_set_guest_notifiers(DeviceState *d, int nvqs, bool assign)
73954dd9321SMichael S. Tsirkin {
740d2a0ccc6SMichael S. Tsirkin     VirtIOPCIProxy *proxy = to_virtio_pci_proxy(d);
741a3fc66d9SPaolo Bonzini     VirtIODevice *vdev = virtio_bus_get_device(&proxy->bus);
742181103cdSKONRAD Frederic     VirtioDeviceClass *k = VIRTIO_DEVICE_GET_CLASS(vdev);
74354dd9321SMichael S. Tsirkin     int r, n;
74489d62be9SMichael S. Tsirkin     bool with_irqfd = msix_enabled(&proxy->pci_dev) &&
74589d62be9SMichael S. Tsirkin         kvm_msi_via_irqfd_enabled();
74654dd9321SMichael S. Tsirkin 
7472d620f59SMichael S. Tsirkin     nvqs = MIN(nvqs, VIRTIO_PCI_QUEUE_MAX);
7482d620f59SMichael S. Tsirkin 
7492d620f59SMichael S. Tsirkin     /* When deassigning, pass a consistent nvqs value
7502d620f59SMichael S. Tsirkin      * to avoid leaking notifiers.
7512d620f59SMichael S. Tsirkin      */
7522d620f59SMichael S. Tsirkin     assert(assign || nvqs == proxy->nvqs_with_notifiers);
7532d620f59SMichael S. Tsirkin 
7542d620f59SMichael S. Tsirkin     proxy->nvqs_with_notifiers = nvqs;
7552d620f59SMichael S. Tsirkin 
7567d37d351SJan Kiszka     /* Must unset vector notifier while guest notifier is still assigned */
757181103cdSKONRAD Frederic     if ((proxy->vector_irqfd || k->guest_notifier_mask) && !assign) {
7587d37d351SJan Kiszka         msix_unset_vector_notifiers(&proxy->pci_dev);
759a38b2c49SMichael S. Tsirkin         if (proxy->vector_irqfd) {
760774345f9SMichael S. Tsirkin             kvm_virtio_pci_vector_release(proxy, nvqs);
7617d37d351SJan Kiszka             g_free(proxy->vector_irqfd);
7627d37d351SJan Kiszka             proxy->vector_irqfd = NULL;
7637d37d351SJan Kiszka         }
764a38b2c49SMichael S. Tsirkin     }
7657d37d351SJan Kiszka 
7662d620f59SMichael S. Tsirkin     for (n = 0; n < nvqs; n++) {
76754dd9321SMichael S. Tsirkin         if (!virtio_queue_get_num(vdev, n)) {
76854dd9321SMichael S. Tsirkin             break;
76954dd9321SMichael S. Tsirkin         }
77054dd9321SMichael S. Tsirkin 
77123fe2b3fSMichael S. Tsirkin         r = virtio_pci_set_guest_notifier(d, n, assign, with_irqfd);
77254dd9321SMichael S. Tsirkin         if (r < 0) {
77354dd9321SMichael S. Tsirkin             goto assign_error;
77454dd9321SMichael S. Tsirkin         }
77554dd9321SMichael S. Tsirkin     }
77654dd9321SMichael S. Tsirkin 
7777d37d351SJan Kiszka     /* Must set vector notifier after guest notifier has been assigned */
778181103cdSKONRAD Frederic     if ((with_irqfd || k->guest_notifier_mask) && assign) {
779a38b2c49SMichael S. Tsirkin         if (with_irqfd) {
7807d37d351SJan Kiszka             proxy->vector_irqfd =
7817d37d351SJan Kiszka                 g_malloc0(sizeof(*proxy->vector_irqfd) *
7827d37d351SJan Kiszka                           msix_nr_vectors_allocated(&proxy->pci_dev));
783774345f9SMichael S. Tsirkin             r = kvm_virtio_pci_vector_use(proxy, nvqs);
7847d37d351SJan Kiszka             if (r < 0) {
7857d37d351SJan Kiszka                 goto assign_error;
7867d37d351SJan Kiszka             }
787a38b2c49SMichael S. Tsirkin         }
788774345f9SMichael S. Tsirkin         r = msix_set_vector_notifiers(&proxy->pci_dev,
789a38b2c49SMichael S. Tsirkin                                       virtio_pci_vector_unmask,
790a38b2c49SMichael S. Tsirkin                                       virtio_pci_vector_mask,
791a38b2c49SMichael S. Tsirkin                                       virtio_pci_vector_poll);
792774345f9SMichael S. Tsirkin         if (r < 0) {
793774345f9SMichael S. Tsirkin             goto notifiers_error;
794774345f9SMichael S. Tsirkin         }
7957d37d351SJan Kiszka     }
7967d37d351SJan Kiszka 
79754dd9321SMichael S. Tsirkin     return 0;
79854dd9321SMichael S. Tsirkin 
799774345f9SMichael S. Tsirkin notifiers_error:
800a38b2c49SMichael S. Tsirkin     if (with_irqfd) {
801774345f9SMichael S. Tsirkin         assert(assign);
802774345f9SMichael S. Tsirkin         kvm_virtio_pci_vector_release(proxy, nvqs);
803a38b2c49SMichael S. Tsirkin     }
804774345f9SMichael S. Tsirkin 
80554dd9321SMichael S. Tsirkin assign_error:
80654dd9321SMichael S. Tsirkin     /* We get here on assignment failure. Recover by undoing for VQs 0 .. n. */
8077d37d351SJan Kiszka     assert(assign);
80854dd9321SMichael S. Tsirkin     while (--n >= 0) {
80989d62be9SMichael S. Tsirkin         virtio_pci_set_guest_notifier(d, n, !assign, with_irqfd);
81054dd9321SMichael S. Tsirkin     }
81154dd9321SMichael S. Tsirkin     return r;
81254dd9321SMichael S. Tsirkin }
81354dd9321SMichael S. Tsirkin 
814d2a0ccc6SMichael S. Tsirkin static int virtio_pci_set_host_notifier(DeviceState *d, int n, bool assign)
815ade80dc8SMichael S. Tsirkin {
816d2a0ccc6SMichael S. Tsirkin     VirtIOPCIProxy *proxy = to_virtio_pci_proxy(d);
81725db9ebeSStefan Hajnoczi 
81825db9ebeSStefan Hajnoczi     /* Stop using ioeventfd for virtqueue kick if the device starts using host
81925db9ebeSStefan Hajnoczi      * notifiers.  This makes it easy to avoid stepping on each others' toes.
82025db9ebeSStefan Hajnoczi      */
82125db9ebeSStefan Hajnoczi     proxy->ioeventfd_disabled = assign;
822ade80dc8SMichael S. Tsirkin     if (assign) {
82325db9ebeSStefan Hajnoczi         virtio_pci_stop_ioeventfd(proxy);
824ade80dc8SMichael S. Tsirkin     }
82525db9ebeSStefan Hajnoczi     /* We don't need to start here: it's not needed because backend
82625db9ebeSStefan Hajnoczi      * currently only stops on status change away from ok,
82725db9ebeSStefan Hajnoczi      * reset, vmstop and such. If we do add code to start here,
82825db9ebeSStefan Hajnoczi      * need to check vmstate, device state etc. */
82926b9b5feSPaolo Bonzini     return virtio_pci_set_host_notifier_internal(proxy, n, assign, false);
830ade80dc8SMichael S. Tsirkin }
83125db9ebeSStefan Hajnoczi 
832d2a0ccc6SMichael S. Tsirkin static void virtio_pci_vmstate_change(DeviceState *d, bool running)
83325db9ebeSStefan Hajnoczi {
834d2a0ccc6SMichael S. Tsirkin     VirtIOPCIProxy *proxy = to_virtio_pci_proxy(d);
835a3fc66d9SPaolo Bonzini     VirtIODevice *vdev = virtio_bus_get_device(&proxy->bus);
83625db9ebeSStefan Hajnoczi 
83725db9ebeSStefan Hajnoczi     if (running) {
83868a27b20SMichael S. Tsirkin         /* Old QEMU versions did not set bus master enable on status write.
83968a27b20SMichael S. Tsirkin          * Detect DRIVER set and enable it.
84068a27b20SMichael S. Tsirkin          */
84168a27b20SMichael S. Tsirkin         if ((proxy->flags & VIRTIO_PCI_FLAG_BUS_MASTER_BUG_MIGRATION) &&
84268a27b20SMichael S. Tsirkin             (vdev->status & VIRTIO_CONFIG_S_DRIVER) &&
84345363e46SMichael S. Tsirkin             !(proxy->pci_dev.config[PCI_COMMAND] & PCI_COMMAND_MASTER)) {
84468a27b20SMichael S. Tsirkin             pci_default_write_config(&proxy->pci_dev, PCI_COMMAND,
84568a27b20SMichael S. Tsirkin                                      proxy->pci_dev.config[PCI_COMMAND] |
84668a27b20SMichael S. Tsirkin                                      PCI_COMMAND_MASTER, 1);
84789c473fdSMichael S. Tsirkin         }
84825db9ebeSStefan Hajnoczi         virtio_pci_start_ioeventfd(proxy);
849ade80dc8SMichael S. Tsirkin     } else {
85025db9ebeSStefan Hajnoczi         virtio_pci_stop_ioeventfd(proxy);
851ade80dc8SMichael S. Tsirkin     }
852ade80dc8SMichael S. Tsirkin }
853ade80dc8SMichael S. Tsirkin 
85460653b28SPaolo Bonzini #ifdef CONFIG_VIRTFS
855fc079951SMarkus Armbruster static void virtio_9p_pci_realize(VirtIOPCIProxy *vpci_dev, Error **errp)
85660653b28SPaolo Bonzini {
857234a336fSKONRAD Frederic     V9fsPCIState *dev = VIRTIO_9P_PCI(vpci_dev);
858234a336fSKONRAD Frederic     DeviceState *vdev = DEVICE(&dev->vdev);
85960653b28SPaolo Bonzini 
860234a336fSKONRAD Frederic     qdev_set_parent_bus(vdev, BUS(&vpci_dev->bus));
861fc079951SMarkus Armbruster     object_property_set_bool(OBJECT(vdev), true, "realized", errp);
86260653b28SPaolo Bonzini }
86360653b28SPaolo Bonzini 
864234a336fSKONRAD Frederic static Property virtio_9p_pci_properties[] = {
865234a336fSKONRAD Frederic     DEFINE_PROP_BIT("ioeventfd", VirtIOPCIProxy, flags,
866234a336fSKONRAD Frederic                     VIRTIO_PCI_FLAG_USE_IOEVENTFD_BIT, true),
86760653b28SPaolo Bonzini     DEFINE_PROP_UINT32("vectors", VirtIOPCIProxy, nvectors, 2),
86860653b28SPaolo Bonzini     DEFINE_PROP_END_OF_LIST(),
86960653b28SPaolo Bonzini };
87060653b28SPaolo Bonzini 
871234a336fSKONRAD Frederic static void virtio_9p_pci_class_init(ObjectClass *klass, void *data)
87260653b28SPaolo Bonzini {
87360653b28SPaolo Bonzini     DeviceClass *dc = DEVICE_CLASS(klass);
874234a336fSKONRAD Frederic     PCIDeviceClass *pcidev_k = PCI_DEVICE_CLASS(klass);
875234a336fSKONRAD Frederic     VirtioPCIClass *k = VIRTIO_PCI_CLASS(klass);
87660653b28SPaolo Bonzini 
877fc079951SMarkus Armbruster     k->realize = virtio_9p_pci_realize;
878234a336fSKONRAD Frederic     pcidev_k->vendor_id = PCI_VENDOR_ID_REDHAT_QUMRANET;
879234a336fSKONRAD Frederic     pcidev_k->device_id = PCI_DEVICE_ID_VIRTIO_9P;
880234a336fSKONRAD Frederic     pcidev_k->revision = VIRTIO_PCI_ABI_VERSION;
881234a336fSKONRAD Frederic     pcidev_k->class_id = 0x2;
882125ee0edSMarcel Apfelbaum     set_bit(DEVICE_CATEGORY_STORAGE, dc->categories);
883234a336fSKONRAD Frederic     dc->props = virtio_9p_pci_properties;
88460653b28SPaolo Bonzini }
88560653b28SPaolo Bonzini 
886234a336fSKONRAD Frederic static void virtio_9p_pci_instance_init(Object *obj)
887234a336fSKONRAD Frederic {
888234a336fSKONRAD Frederic     V9fsPCIState *dev = VIRTIO_9P_PCI(obj);
889c8075cafSGonglei 
890c8075cafSGonglei     virtio_instance_init_common(obj, &dev->vdev, sizeof(dev->vdev),
891c8075cafSGonglei                                 TYPE_VIRTIO_9P);
892234a336fSKONRAD Frederic }
893234a336fSKONRAD Frederic 
894234a336fSKONRAD Frederic static const TypeInfo virtio_9p_pci_info = {
895234a336fSKONRAD Frederic     .name          = TYPE_VIRTIO_9P_PCI,
896234a336fSKONRAD Frederic     .parent        = TYPE_VIRTIO_PCI,
897234a336fSKONRAD Frederic     .instance_size = sizeof(V9fsPCIState),
898234a336fSKONRAD Frederic     .instance_init = virtio_9p_pci_instance_init,
899234a336fSKONRAD Frederic     .class_init    = virtio_9p_pci_class_init,
90060653b28SPaolo Bonzini };
901234a336fSKONRAD Frederic #endif /* CONFIG_VIRTFS */
90260653b28SPaolo Bonzini 
903085bccb7SKONRAD Frederic /*
904085bccb7SKONRAD Frederic  * virtio-pci: This is the PCIDevice which has a virtio-pci-bus.
905085bccb7SKONRAD Frederic  */
906085bccb7SKONRAD Frederic 
907e0d686bfSJason Wang static int virtio_pci_query_nvectors(DeviceState *d)
908e0d686bfSJason Wang {
909e0d686bfSJason Wang     VirtIOPCIProxy *proxy = VIRTIO_PCI(d);
910e0d686bfSJason Wang 
911e0d686bfSJason Wang     return proxy->nvectors;
912e0d686bfSJason Wang }
913e0d686bfSJason Wang 
914085bccb7SKONRAD Frederic /* This is called by virtio-bus just after the device is plugged. */
915*e8398045SJason Wang static void virtio_pci_device_plugged(DeviceState *d, Error **errp)
916085bccb7SKONRAD Frederic {
917085bccb7SKONRAD Frederic     VirtIOPCIProxy *proxy = VIRTIO_PCI(d);
918085bccb7SKONRAD Frederic     VirtioBusState *bus = &proxy->bus;
919085bccb7SKONRAD Frederic     uint8_t *config;
920085bccb7SKONRAD Frederic     uint32_t size;
9216b8f1020SCornelia Huck     VirtIODevice *vdev = virtio_bus_get_device(&proxy->bus);
922085bccb7SKONRAD Frederic 
923085bccb7SKONRAD Frederic     config = proxy->pci_dev.config;
924085bccb7SKONRAD Frederic     if (proxy->class_code) {
925085bccb7SKONRAD Frederic         pci_config_set_class(config, proxy->class_code);
926085bccb7SKONRAD Frederic     }
927085bccb7SKONRAD Frederic     pci_set_word(config + PCI_SUBSYSTEM_VENDOR_ID,
928085bccb7SKONRAD Frederic                  pci_get_word(config + PCI_VENDOR_ID));
929085bccb7SKONRAD Frederic     pci_set_word(config + PCI_SUBSYSTEM_ID, virtio_bus_get_vdev_id(bus));
930085bccb7SKONRAD Frederic     config[PCI_INTERRUPT_PIN] = 1;
931085bccb7SKONRAD Frederic 
932085bccb7SKONRAD Frederic     if (proxy->nvectors &&
933085bccb7SKONRAD Frederic         msix_init_exclusive_bar(&proxy->pci_dev, proxy->nvectors, 1)) {
934c7ff5482SFam Zheng         error_report("unable to init msix vectors to %" PRIu32,
935c7ff5482SFam Zheng                      proxy->nvectors);
936085bccb7SKONRAD Frederic         proxy->nvectors = 0;
937085bccb7SKONRAD Frederic     }
938085bccb7SKONRAD Frederic 
939085bccb7SKONRAD Frederic     proxy->pci_dev.config_write = virtio_write_config;
940085bccb7SKONRAD Frederic 
941085bccb7SKONRAD Frederic     size = VIRTIO_PCI_REGION_SIZE(&proxy->pci_dev)
942085bccb7SKONRAD Frederic          + virtio_bus_get_vdev_config_len(bus);
943085bccb7SKONRAD Frederic     if (size & (size - 1)) {
944085bccb7SKONRAD Frederic         size = 1 << qemu_fls(size);
945085bccb7SKONRAD Frederic     }
946085bccb7SKONRAD Frederic 
94722fc860bSPaolo Bonzini     memory_region_init_io(&proxy->bar, OBJECT(proxy), &virtio_pci_config_ops,
94822fc860bSPaolo Bonzini                           proxy, "virtio-pci", size);
949085bccb7SKONRAD Frederic     pci_register_bar(&proxy->pci_dev, 0, PCI_BASE_ADDRESS_SPACE_IO,
950085bccb7SKONRAD Frederic                      &proxy->bar);
951085bccb7SKONRAD Frederic 
952085bccb7SKONRAD Frederic     if (!kvm_has_many_ioeventfds()) {
953085bccb7SKONRAD Frederic         proxy->flags &= ~VIRTIO_PCI_FLAG_USE_IOEVENTFD;
954085bccb7SKONRAD Frederic     }
955085bccb7SKONRAD Frederic 
9566b8f1020SCornelia Huck     virtio_add_feature(&vdev->host_features, VIRTIO_F_BAD_FEATURE);
957085bccb7SKONRAD Frederic }
958085bccb7SKONRAD Frederic 
95906a13073SPaolo Bonzini static void virtio_pci_device_unplugged(DeviceState *d)
96006a13073SPaolo Bonzini {
96106a13073SPaolo Bonzini     VirtIOPCIProxy *proxy = VIRTIO_PCI(d);
96206a13073SPaolo Bonzini 
96306a13073SPaolo Bonzini     virtio_pci_stop_ioeventfd(proxy);
96406a13073SPaolo Bonzini }
96506a13073SPaolo Bonzini 
966fc079951SMarkus Armbruster static void virtio_pci_realize(PCIDevice *pci_dev, Error **errp)
967085bccb7SKONRAD Frederic {
968085bccb7SKONRAD Frederic     VirtIOPCIProxy *dev = VIRTIO_PCI(pci_dev);
969085bccb7SKONRAD Frederic     VirtioPCIClass *k = VIRTIO_PCI_GET_CLASS(pci_dev);
970fc079951SMarkus Armbruster 
971ac7af112SAndreas Färber     virtio_pci_bus_new(&dev->bus, sizeof(dev->bus), dev);
972fc079951SMarkus Armbruster     if (k->realize) {
973fc079951SMarkus Armbruster         k->realize(dev, errp);
974085bccb7SKONRAD Frederic     }
975085bccb7SKONRAD Frederic }
976085bccb7SKONRAD Frederic 
977085bccb7SKONRAD Frederic static void virtio_pci_exit(PCIDevice *pci_dev)
978085bccb7SKONRAD Frederic {
9798b81bb3bSPaolo Bonzini     msix_uninit_exclusive_bar(pci_dev);
980085bccb7SKONRAD Frederic }
981085bccb7SKONRAD Frederic 
98259ccd20aSKONRAD Frederic static void virtio_pci_reset(DeviceState *qdev)
983085bccb7SKONRAD Frederic {
984085bccb7SKONRAD Frederic     VirtIOPCIProxy *proxy = VIRTIO_PCI(qdev);
985085bccb7SKONRAD Frederic     VirtioBusState *bus = VIRTIO_BUS(&proxy->bus);
986085bccb7SKONRAD Frederic     virtio_pci_stop_ioeventfd(proxy);
987085bccb7SKONRAD Frederic     virtio_bus_reset(bus);
988085bccb7SKONRAD Frederic     msix_unuse_all_vectors(&proxy->pci_dev);
989085bccb7SKONRAD Frederic }
990085bccb7SKONRAD Frederic 
99185d1277eSMing Lei static Property virtio_pci_properties[] = {
99268a27b20SMichael S. Tsirkin     DEFINE_PROP_BIT("virtio-pci-bus-master-bug-migration", VirtIOPCIProxy, flags,
99368a27b20SMichael S. Tsirkin                     VIRTIO_PCI_FLAG_BUS_MASTER_BUG_MIGRATION_BIT, false),
99485d1277eSMing Lei     DEFINE_PROP_END_OF_LIST(),
99585d1277eSMing Lei };
99685d1277eSMing Lei 
997085bccb7SKONRAD Frederic static void virtio_pci_class_init(ObjectClass *klass, void *data)
998085bccb7SKONRAD Frederic {
999085bccb7SKONRAD Frederic     DeviceClass *dc = DEVICE_CLASS(klass);
1000085bccb7SKONRAD Frederic     PCIDeviceClass *k = PCI_DEVICE_CLASS(klass);
1001085bccb7SKONRAD Frederic 
100285d1277eSMing Lei     dc->props = virtio_pci_properties;
1003fc079951SMarkus Armbruster     k->realize = virtio_pci_realize;
1004085bccb7SKONRAD Frederic     k->exit = virtio_pci_exit;
1005085bccb7SKONRAD Frederic     k->vendor_id = PCI_VENDOR_ID_REDHAT_QUMRANET;
1006085bccb7SKONRAD Frederic     k->revision = VIRTIO_PCI_ABI_VERSION;
1007085bccb7SKONRAD Frederic     k->class_id = PCI_CLASS_OTHERS;
100859ccd20aSKONRAD Frederic     dc->reset = virtio_pci_reset;
1009085bccb7SKONRAD Frederic }
1010085bccb7SKONRAD Frederic 
1011085bccb7SKONRAD Frederic static const TypeInfo virtio_pci_info = {
1012085bccb7SKONRAD Frederic     .name          = TYPE_VIRTIO_PCI,
1013085bccb7SKONRAD Frederic     .parent        = TYPE_PCI_DEVICE,
1014085bccb7SKONRAD Frederic     .instance_size = sizeof(VirtIOPCIProxy),
1015085bccb7SKONRAD Frederic     .class_init    = virtio_pci_class_init,
1016085bccb7SKONRAD Frederic     .class_size    = sizeof(VirtioPCIClass),
1017085bccb7SKONRAD Frederic     .abstract      = true,
1018085bccb7SKONRAD Frederic };
1019085bccb7SKONRAD Frederic 
1020653ced07SKONRAD Frederic /* virtio-blk-pci */
1021653ced07SKONRAD Frederic 
1022653ced07SKONRAD Frederic static Property virtio_blk_pci_properties[] = {
1023c7bcc85dSPaolo Bonzini     DEFINE_PROP_UINT32("class", VirtIOPCIProxy, class_code, 0),
1024653ced07SKONRAD Frederic     DEFINE_PROP_BIT("ioeventfd", VirtIOPCIProxy, flags,
1025653ced07SKONRAD Frederic                     VIRTIO_PCI_FLAG_USE_IOEVENTFD_BIT, true),
1026653ced07SKONRAD Frederic     DEFINE_PROP_UINT32("vectors", VirtIOPCIProxy, nvectors, 2),
1027653ced07SKONRAD Frederic     DEFINE_PROP_END_OF_LIST(),
1028653ced07SKONRAD Frederic };
1029653ced07SKONRAD Frederic 
1030fc079951SMarkus Armbruster static void virtio_blk_pci_realize(VirtIOPCIProxy *vpci_dev, Error **errp)
1031653ced07SKONRAD Frederic {
1032653ced07SKONRAD Frederic     VirtIOBlkPCI *dev = VIRTIO_BLK_PCI(vpci_dev);
1033653ced07SKONRAD Frederic     DeviceState *vdev = DEVICE(&dev->vdev);
1034fc079951SMarkus Armbruster 
1035653ced07SKONRAD Frederic     qdev_set_parent_bus(vdev, BUS(&vpci_dev->bus));
1036fc079951SMarkus Armbruster     object_property_set_bool(OBJECT(vdev), true, "realized", errp);
1037653ced07SKONRAD Frederic }
1038653ced07SKONRAD Frederic 
1039653ced07SKONRAD Frederic static void virtio_blk_pci_class_init(ObjectClass *klass, void *data)
1040653ced07SKONRAD Frederic {
1041653ced07SKONRAD Frederic     DeviceClass *dc = DEVICE_CLASS(klass);
1042653ced07SKONRAD Frederic     VirtioPCIClass *k = VIRTIO_PCI_CLASS(klass);
1043653ced07SKONRAD Frederic     PCIDeviceClass *pcidev_k = PCI_DEVICE_CLASS(klass);
1044653ced07SKONRAD Frederic 
1045125ee0edSMarcel Apfelbaum     set_bit(DEVICE_CATEGORY_STORAGE, dc->categories);
1046653ced07SKONRAD Frederic     dc->props = virtio_blk_pci_properties;
1047fc079951SMarkus Armbruster     k->realize = virtio_blk_pci_realize;
1048653ced07SKONRAD Frederic     pcidev_k->vendor_id = PCI_VENDOR_ID_REDHAT_QUMRANET;
1049653ced07SKONRAD Frederic     pcidev_k->device_id = PCI_DEVICE_ID_VIRTIO_BLOCK;
1050653ced07SKONRAD Frederic     pcidev_k->revision = VIRTIO_PCI_ABI_VERSION;
1051653ced07SKONRAD Frederic     pcidev_k->class_id = PCI_CLASS_STORAGE_SCSI;
1052653ced07SKONRAD Frederic }
1053653ced07SKONRAD Frederic 
1054653ced07SKONRAD Frederic static void virtio_blk_pci_instance_init(Object *obj)
1055653ced07SKONRAD Frederic {
1056653ced07SKONRAD Frederic     VirtIOBlkPCI *dev = VIRTIO_BLK_PCI(obj);
1057c8075cafSGonglei 
1058c8075cafSGonglei     virtio_instance_init_common(obj, &dev->vdev, sizeof(dev->vdev),
1059c8075cafSGonglei                                 TYPE_VIRTIO_BLK);
1060467b3f33SStefan Hajnoczi     object_property_add_alias(obj, "iothread", OBJECT(&dev->vdev),"iothread",
1061467b3f33SStefan Hajnoczi                               &error_abort);
1062aeb98ddcSGonglei     object_property_add_alias(obj, "bootindex", OBJECT(&dev->vdev),
1063aeb98ddcSGonglei                               "bootindex", &error_abort);
1064653ced07SKONRAD Frederic }
1065653ced07SKONRAD Frederic 
1066653ced07SKONRAD Frederic static const TypeInfo virtio_blk_pci_info = {
1067653ced07SKONRAD Frederic     .name          = TYPE_VIRTIO_BLK_PCI,
1068653ced07SKONRAD Frederic     .parent        = TYPE_VIRTIO_PCI,
1069653ced07SKONRAD Frederic     .instance_size = sizeof(VirtIOBlkPCI),
1070653ced07SKONRAD Frederic     .instance_init = virtio_blk_pci_instance_init,
1071653ced07SKONRAD Frederic     .class_init    = virtio_blk_pci_class_init,
1072653ced07SKONRAD Frederic };
1073653ced07SKONRAD Frederic 
1074bc7b90a0SKONRAD Frederic /* virtio-scsi-pci */
1075bc7b90a0SKONRAD Frederic 
1076bc7b90a0SKONRAD Frederic static Property virtio_scsi_pci_properties[] = {
1077bc7b90a0SKONRAD Frederic     DEFINE_PROP_BIT("ioeventfd", VirtIOPCIProxy, flags,
1078bc7b90a0SKONRAD Frederic                     VIRTIO_PCI_FLAG_USE_IOEVENTFD_BIT, true),
1079bc7b90a0SKONRAD Frederic     DEFINE_PROP_UINT32("vectors", VirtIOPCIProxy, nvectors,
1080bc7b90a0SKONRAD Frederic                        DEV_NVECTORS_UNSPECIFIED),
1081bc7b90a0SKONRAD Frederic     DEFINE_PROP_END_OF_LIST(),
1082bc7b90a0SKONRAD Frederic };
1083bc7b90a0SKONRAD Frederic 
1084fc079951SMarkus Armbruster static void virtio_scsi_pci_realize(VirtIOPCIProxy *vpci_dev, Error **errp)
1085bc7b90a0SKONRAD Frederic {
1086bc7b90a0SKONRAD Frederic     VirtIOSCSIPCI *dev = VIRTIO_SCSI_PCI(vpci_dev);
1087bc7b90a0SKONRAD Frederic     DeviceState *vdev = DEVICE(&dev->vdev);
1088292c8e50SPaolo Bonzini     VirtIOSCSICommon *vs = VIRTIO_SCSI_COMMON(vdev);
10896f32a6b4SKONRAD Frederic     DeviceState *proxy = DEVICE(vpci_dev);
10906f32a6b4SKONRAD Frederic     char *bus_name;
1091bc7b90a0SKONRAD Frederic 
1092bc7b90a0SKONRAD Frederic     if (vpci_dev->nvectors == DEV_NVECTORS_UNSPECIFIED) {
1093292c8e50SPaolo Bonzini         vpci_dev->nvectors = vs->conf.num_queues + 3;
1094bc7b90a0SKONRAD Frederic     }
1095bc7b90a0SKONRAD Frederic 
10966f32a6b4SKONRAD Frederic     /*
10976f32a6b4SKONRAD Frederic      * For command line compatibility, this sets the virtio-scsi-device bus
10986f32a6b4SKONRAD Frederic      * name as before.
10996f32a6b4SKONRAD Frederic      */
11006f32a6b4SKONRAD Frederic     if (proxy->id) {
11016f32a6b4SKONRAD Frederic         bus_name = g_strdup_printf("%s.0", proxy->id);
11026f32a6b4SKONRAD Frederic         virtio_device_set_child_bus_name(VIRTIO_DEVICE(vdev), bus_name);
11036f32a6b4SKONRAD Frederic         g_free(bus_name);
11046f32a6b4SKONRAD Frederic     }
11056f32a6b4SKONRAD Frederic 
1106bc7b90a0SKONRAD Frederic     qdev_set_parent_bus(vdev, BUS(&vpci_dev->bus));
1107fc079951SMarkus Armbruster     object_property_set_bool(OBJECT(vdev), true, "realized", errp);
1108bc7b90a0SKONRAD Frederic }
1109bc7b90a0SKONRAD Frederic 
1110bc7b90a0SKONRAD Frederic static void virtio_scsi_pci_class_init(ObjectClass *klass, void *data)
1111bc7b90a0SKONRAD Frederic {
1112bc7b90a0SKONRAD Frederic     DeviceClass *dc = DEVICE_CLASS(klass);
1113bc7b90a0SKONRAD Frederic     VirtioPCIClass *k = VIRTIO_PCI_CLASS(klass);
1114bc7b90a0SKONRAD Frederic     PCIDeviceClass *pcidev_k = PCI_DEVICE_CLASS(klass);
1115fc079951SMarkus Armbruster 
1116fc079951SMarkus Armbruster     k->realize = virtio_scsi_pci_realize;
1117125ee0edSMarcel Apfelbaum     set_bit(DEVICE_CATEGORY_STORAGE, dc->categories);
1118bc7b90a0SKONRAD Frederic     dc->props = virtio_scsi_pci_properties;
1119bc7b90a0SKONRAD Frederic     pcidev_k->vendor_id = PCI_VENDOR_ID_REDHAT_QUMRANET;
1120bc7b90a0SKONRAD Frederic     pcidev_k->device_id = PCI_DEVICE_ID_VIRTIO_SCSI;
1121bc7b90a0SKONRAD Frederic     pcidev_k->revision = 0x00;
1122bc7b90a0SKONRAD Frederic     pcidev_k->class_id = PCI_CLASS_STORAGE_SCSI;
1123bc7b90a0SKONRAD Frederic }
1124bc7b90a0SKONRAD Frederic 
1125bc7b90a0SKONRAD Frederic static void virtio_scsi_pci_instance_init(Object *obj)
1126bc7b90a0SKONRAD Frederic {
1127bc7b90a0SKONRAD Frederic     VirtIOSCSIPCI *dev = VIRTIO_SCSI_PCI(obj);
1128c8075cafSGonglei 
1129c8075cafSGonglei     virtio_instance_init_common(obj, &dev->vdev, sizeof(dev->vdev),
1130c8075cafSGonglei                                 TYPE_VIRTIO_SCSI);
113119d339f1SFam Zheng     object_property_add_alias(obj, "iothread", OBJECT(&dev->vdev), "iothread",
113219d339f1SFam Zheng                               &error_abort);
1133bc7b90a0SKONRAD Frederic }
1134bc7b90a0SKONRAD Frederic 
1135bc7b90a0SKONRAD Frederic static const TypeInfo virtio_scsi_pci_info = {
1136bc7b90a0SKONRAD Frederic     .name          = TYPE_VIRTIO_SCSI_PCI,
1137bc7b90a0SKONRAD Frederic     .parent        = TYPE_VIRTIO_PCI,
1138bc7b90a0SKONRAD Frederic     .instance_size = sizeof(VirtIOSCSIPCI),
1139bc7b90a0SKONRAD Frederic     .instance_init = virtio_scsi_pci_instance_init,
1140bc7b90a0SKONRAD Frederic     .class_init    = virtio_scsi_pci_class_init,
1141bc7b90a0SKONRAD Frederic };
1142bc7b90a0SKONRAD Frederic 
114350787628SNicholas Bellinger /* vhost-scsi-pci */
114450787628SNicholas Bellinger 
114550787628SNicholas Bellinger #ifdef CONFIG_VHOST_SCSI
114650787628SNicholas Bellinger static Property vhost_scsi_pci_properties[] = {
114750787628SNicholas Bellinger     DEFINE_PROP_UINT32("vectors", VirtIOPCIProxy, nvectors,
114850787628SNicholas Bellinger                        DEV_NVECTORS_UNSPECIFIED),
114950787628SNicholas Bellinger     DEFINE_PROP_END_OF_LIST(),
115050787628SNicholas Bellinger };
115150787628SNicholas Bellinger 
1152fc079951SMarkus Armbruster static void vhost_scsi_pci_realize(VirtIOPCIProxy *vpci_dev, Error **errp)
115350787628SNicholas Bellinger {
115450787628SNicholas Bellinger     VHostSCSIPCI *dev = VHOST_SCSI_PCI(vpci_dev);
115550787628SNicholas Bellinger     DeviceState *vdev = DEVICE(&dev->vdev);
115650787628SNicholas Bellinger     VirtIOSCSICommon *vs = VIRTIO_SCSI_COMMON(vdev);
115750787628SNicholas Bellinger 
115850787628SNicholas Bellinger     if (vpci_dev->nvectors == DEV_NVECTORS_UNSPECIFIED) {
115950787628SNicholas Bellinger         vpci_dev->nvectors = vs->conf.num_queues + 3;
116050787628SNicholas Bellinger     }
116150787628SNicholas Bellinger 
116250787628SNicholas Bellinger     qdev_set_parent_bus(vdev, BUS(&vpci_dev->bus));
1163fc079951SMarkus Armbruster     object_property_set_bool(OBJECT(vdev), true, "realized", errp);
116450787628SNicholas Bellinger }
116550787628SNicholas Bellinger 
116650787628SNicholas Bellinger static void vhost_scsi_pci_class_init(ObjectClass *klass, void *data)
116750787628SNicholas Bellinger {
116850787628SNicholas Bellinger     DeviceClass *dc = DEVICE_CLASS(klass);
116950787628SNicholas Bellinger     VirtioPCIClass *k = VIRTIO_PCI_CLASS(klass);
117050787628SNicholas Bellinger     PCIDeviceClass *pcidev_k = PCI_DEVICE_CLASS(klass);
1171fc079951SMarkus Armbruster     k->realize = vhost_scsi_pci_realize;
1172125ee0edSMarcel Apfelbaum     set_bit(DEVICE_CATEGORY_STORAGE, dc->categories);
117350787628SNicholas Bellinger     dc->props = vhost_scsi_pci_properties;
117450787628SNicholas Bellinger     pcidev_k->vendor_id = PCI_VENDOR_ID_REDHAT_QUMRANET;
117550787628SNicholas Bellinger     pcidev_k->device_id = PCI_DEVICE_ID_VIRTIO_SCSI;
117650787628SNicholas Bellinger     pcidev_k->revision = 0x00;
117750787628SNicholas Bellinger     pcidev_k->class_id = PCI_CLASS_STORAGE_SCSI;
117850787628SNicholas Bellinger }
117950787628SNicholas Bellinger 
118050787628SNicholas Bellinger static void vhost_scsi_pci_instance_init(Object *obj)
118150787628SNicholas Bellinger {
118250787628SNicholas Bellinger     VHostSCSIPCI *dev = VHOST_SCSI_PCI(obj);
1183c8075cafSGonglei 
1184c8075cafSGonglei     virtio_instance_init_common(obj, &dev->vdev, sizeof(dev->vdev),
1185c8075cafSGonglei                                 TYPE_VHOST_SCSI);
1186d4433f32SGonglei     object_property_add_alias(obj, "bootindex", OBJECT(&dev->vdev),
1187d4433f32SGonglei                               "bootindex", &error_abort);
118850787628SNicholas Bellinger }
118950787628SNicholas Bellinger 
119050787628SNicholas Bellinger static const TypeInfo vhost_scsi_pci_info = {
119150787628SNicholas Bellinger     .name          = TYPE_VHOST_SCSI_PCI,
119250787628SNicholas Bellinger     .parent        = TYPE_VIRTIO_PCI,
119350787628SNicholas Bellinger     .instance_size = sizeof(VHostSCSIPCI),
119450787628SNicholas Bellinger     .instance_init = vhost_scsi_pci_instance_init,
119550787628SNicholas Bellinger     .class_init    = vhost_scsi_pci_class_init,
119650787628SNicholas Bellinger };
119750787628SNicholas Bellinger #endif
119850787628SNicholas Bellinger 
1199e378e88dSKONRAD Frederic /* virtio-balloon-pci */
1200e378e88dSKONRAD Frederic 
1201e378e88dSKONRAD Frederic static Property virtio_balloon_pci_properties[] = {
1202c7bcc85dSPaolo Bonzini     DEFINE_PROP_UINT32("class", VirtIOPCIProxy, class_code, 0),
1203e378e88dSKONRAD Frederic     DEFINE_PROP_END_OF_LIST(),
1204e378e88dSKONRAD Frederic };
1205e378e88dSKONRAD Frederic 
1206fc079951SMarkus Armbruster static void virtio_balloon_pci_realize(VirtIOPCIProxy *vpci_dev, Error **errp)
1207e378e88dSKONRAD Frederic {
1208e378e88dSKONRAD Frederic     VirtIOBalloonPCI *dev = VIRTIO_BALLOON_PCI(vpci_dev);
1209e378e88dSKONRAD Frederic     DeviceState *vdev = DEVICE(&dev->vdev);
1210e378e88dSKONRAD Frederic 
1211e378e88dSKONRAD Frederic     if (vpci_dev->class_code != PCI_CLASS_OTHERS &&
1212e378e88dSKONRAD Frederic         vpci_dev->class_code != PCI_CLASS_MEMORY_RAM) { /* qemu < 1.1 */
1213e378e88dSKONRAD Frederic         vpci_dev->class_code = PCI_CLASS_OTHERS;
1214e378e88dSKONRAD Frederic     }
1215e378e88dSKONRAD Frederic 
1216e378e88dSKONRAD Frederic     qdev_set_parent_bus(vdev, BUS(&vpci_dev->bus));
1217fc079951SMarkus Armbruster     object_property_set_bool(OBJECT(vdev), true, "realized", errp);
1218e378e88dSKONRAD Frederic }
1219e378e88dSKONRAD Frederic 
1220e378e88dSKONRAD Frederic static void virtio_balloon_pci_class_init(ObjectClass *klass, void *data)
1221e378e88dSKONRAD Frederic {
1222e378e88dSKONRAD Frederic     DeviceClass *dc = DEVICE_CLASS(klass);
1223e378e88dSKONRAD Frederic     VirtioPCIClass *k = VIRTIO_PCI_CLASS(klass);
1224e378e88dSKONRAD Frederic     PCIDeviceClass *pcidev_k = PCI_DEVICE_CLASS(klass);
1225fc079951SMarkus Armbruster     k->realize = virtio_balloon_pci_realize;
1226125ee0edSMarcel Apfelbaum     set_bit(DEVICE_CATEGORY_MISC, dc->categories);
1227e378e88dSKONRAD Frederic     dc->props = virtio_balloon_pci_properties;
1228e378e88dSKONRAD Frederic     pcidev_k->vendor_id = PCI_VENDOR_ID_REDHAT_QUMRANET;
1229e378e88dSKONRAD Frederic     pcidev_k->device_id = PCI_DEVICE_ID_VIRTIO_BALLOON;
1230e378e88dSKONRAD Frederic     pcidev_k->revision = VIRTIO_PCI_ABI_VERSION;
1231e378e88dSKONRAD Frederic     pcidev_k->class_id = PCI_CLASS_OTHERS;
1232e378e88dSKONRAD Frederic }
1233e378e88dSKONRAD Frederic 
1234e378e88dSKONRAD Frederic static void virtio_balloon_pci_instance_init(Object *obj)
1235e378e88dSKONRAD Frederic {
1236e378e88dSKONRAD Frederic     VirtIOBalloonPCI *dev = VIRTIO_BALLOON_PCI(obj);
123739b87c7bSShannon Zhao 
1238a6027b0fSDenis V. Lunev     virtio_instance_init_common(obj, &dev->vdev, sizeof(dev->vdev),
1239a6027b0fSDenis V. Lunev                                 TYPE_VIRTIO_BALLOON);
124039b87c7bSShannon Zhao     object_property_add_alias(obj, "guest-stats", OBJECT(&dev->vdev),
124139b87c7bSShannon Zhao                                   "guest-stats", &error_abort);
124239b87c7bSShannon Zhao     object_property_add_alias(obj, "guest-stats-polling-interval",
124339b87c7bSShannon Zhao                               OBJECT(&dev->vdev),
124439b87c7bSShannon Zhao                               "guest-stats-polling-interval", &error_abort);
1245e378e88dSKONRAD Frederic }
1246e378e88dSKONRAD Frederic 
1247e378e88dSKONRAD Frederic static const TypeInfo virtio_balloon_pci_info = {
1248e378e88dSKONRAD Frederic     .name          = TYPE_VIRTIO_BALLOON_PCI,
1249e378e88dSKONRAD Frederic     .parent        = TYPE_VIRTIO_PCI,
1250e378e88dSKONRAD Frederic     .instance_size = sizeof(VirtIOBalloonPCI),
1251e378e88dSKONRAD Frederic     .instance_init = virtio_balloon_pci_instance_init,
1252e378e88dSKONRAD Frederic     .class_init    = virtio_balloon_pci_class_init,
1253e378e88dSKONRAD Frederic };
1254e378e88dSKONRAD Frederic 
1255f7f7464aSKONRAD Frederic /* virtio-serial-pci */
1256f7f7464aSKONRAD Frederic 
1257fc079951SMarkus Armbruster static void virtio_serial_pci_realize(VirtIOPCIProxy *vpci_dev, Error **errp)
1258f7f7464aSKONRAD Frederic {
1259f7f7464aSKONRAD Frederic     VirtIOSerialPCI *dev = VIRTIO_SERIAL_PCI(vpci_dev);
1260f7f7464aSKONRAD Frederic     DeviceState *vdev = DEVICE(&dev->vdev);
126180270a19SKONRAD Frederic     DeviceState *proxy = DEVICE(vpci_dev);
126280270a19SKONRAD Frederic     char *bus_name;
1263f7f7464aSKONRAD Frederic 
1264f7f7464aSKONRAD Frederic     if (vpci_dev->class_code != PCI_CLASS_COMMUNICATION_OTHER &&
1265f7f7464aSKONRAD Frederic         vpci_dev->class_code != PCI_CLASS_DISPLAY_OTHER && /* qemu 0.10 */
1266f7f7464aSKONRAD Frederic         vpci_dev->class_code != PCI_CLASS_OTHERS) {        /* qemu-kvm  */
1267f7f7464aSKONRAD Frederic             vpci_dev->class_code = PCI_CLASS_COMMUNICATION_OTHER;
1268f7f7464aSKONRAD Frederic     }
1269f7f7464aSKONRAD Frederic 
1270f7f7464aSKONRAD Frederic     /* backwards-compatibility with machines that were created with
1271f7f7464aSKONRAD Frederic        DEV_NVECTORS_UNSPECIFIED */
1272f7f7464aSKONRAD Frederic     if (vpci_dev->nvectors == DEV_NVECTORS_UNSPECIFIED) {
1273f7f7464aSKONRAD Frederic         vpci_dev->nvectors = dev->vdev.serial.max_virtserial_ports + 1;
1274f7f7464aSKONRAD Frederic     }
1275f7f7464aSKONRAD Frederic 
127680270a19SKONRAD Frederic     /*
127780270a19SKONRAD Frederic      * For command line compatibility, this sets the virtio-serial-device bus
127880270a19SKONRAD Frederic      * name as before.
127980270a19SKONRAD Frederic      */
128080270a19SKONRAD Frederic     if (proxy->id) {
128180270a19SKONRAD Frederic         bus_name = g_strdup_printf("%s.0", proxy->id);
128280270a19SKONRAD Frederic         virtio_device_set_child_bus_name(VIRTIO_DEVICE(vdev), bus_name);
128380270a19SKONRAD Frederic         g_free(bus_name);
128480270a19SKONRAD Frederic     }
128580270a19SKONRAD Frederic 
1286f7f7464aSKONRAD Frederic     qdev_set_parent_bus(vdev, BUS(&vpci_dev->bus));
1287fc079951SMarkus Armbruster     object_property_set_bool(OBJECT(vdev), true, "realized", errp);
1288f7f7464aSKONRAD Frederic }
1289f7f7464aSKONRAD Frederic 
1290f7f7464aSKONRAD Frederic static Property virtio_serial_pci_properties[] = {
1291f7f7464aSKONRAD Frederic     DEFINE_PROP_BIT("ioeventfd", VirtIOPCIProxy, flags,
1292f7f7464aSKONRAD Frederic                     VIRTIO_PCI_FLAG_USE_IOEVENTFD_BIT, true),
1293f7f7464aSKONRAD Frederic     DEFINE_PROP_UINT32("vectors", VirtIOPCIProxy, nvectors, 2),
1294c7bcc85dSPaolo Bonzini     DEFINE_PROP_UINT32("class", VirtIOPCIProxy, class_code, 0),
1295f7f7464aSKONRAD Frederic     DEFINE_PROP_END_OF_LIST(),
1296f7f7464aSKONRAD Frederic };
1297f7f7464aSKONRAD Frederic 
1298f7f7464aSKONRAD Frederic static void virtio_serial_pci_class_init(ObjectClass *klass, void *data)
1299f7f7464aSKONRAD Frederic {
1300f7f7464aSKONRAD Frederic     DeviceClass *dc = DEVICE_CLASS(klass);
1301f7f7464aSKONRAD Frederic     VirtioPCIClass *k = VIRTIO_PCI_CLASS(klass);
1302f7f7464aSKONRAD Frederic     PCIDeviceClass *pcidev_k = PCI_DEVICE_CLASS(klass);
1303fc079951SMarkus Armbruster     k->realize = virtio_serial_pci_realize;
1304125ee0edSMarcel Apfelbaum     set_bit(DEVICE_CATEGORY_INPUT, dc->categories);
1305f7f7464aSKONRAD Frederic     dc->props = virtio_serial_pci_properties;
1306f7f7464aSKONRAD Frederic     pcidev_k->vendor_id = PCI_VENDOR_ID_REDHAT_QUMRANET;
1307f7f7464aSKONRAD Frederic     pcidev_k->device_id = PCI_DEVICE_ID_VIRTIO_CONSOLE;
1308f7f7464aSKONRAD Frederic     pcidev_k->revision = VIRTIO_PCI_ABI_VERSION;
1309f7f7464aSKONRAD Frederic     pcidev_k->class_id = PCI_CLASS_COMMUNICATION_OTHER;
1310f7f7464aSKONRAD Frederic }
1311f7f7464aSKONRAD Frederic 
1312f7f7464aSKONRAD Frederic static void virtio_serial_pci_instance_init(Object *obj)
1313f7f7464aSKONRAD Frederic {
1314f7f7464aSKONRAD Frederic     VirtIOSerialPCI *dev = VIRTIO_SERIAL_PCI(obj);
1315c8075cafSGonglei 
1316c8075cafSGonglei     virtio_instance_init_common(obj, &dev->vdev, sizeof(dev->vdev),
1317c8075cafSGonglei                                 TYPE_VIRTIO_SERIAL);
1318f7f7464aSKONRAD Frederic }
1319f7f7464aSKONRAD Frederic 
1320f7f7464aSKONRAD Frederic static const TypeInfo virtio_serial_pci_info = {
1321f7f7464aSKONRAD Frederic     .name          = TYPE_VIRTIO_SERIAL_PCI,
1322f7f7464aSKONRAD Frederic     .parent        = TYPE_VIRTIO_PCI,
1323f7f7464aSKONRAD Frederic     .instance_size = sizeof(VirtIOSerialPCI),
1324f7f7464aSKONRAD Frederic     .instance_init = virtio_serial_pci_instance_init,
1325f7f7464aSKONRAD Frederic     .class_init    = virtio_serial_pci_class_init,
1326f7f7464aSKONRAD Frederic };
1327f7f7464aSKONRAD Frederic 
1328e37da394SKONRAD Frederic /* virtio-net-pci */
1329e37da394SKONRAD Frederic 
1330e37da394SKONRAD Frederic static Property virtio_net_properties[] = {
1331e37da394SKONRAD Frederic     DEFINE_PROP_BIT("ioeventfd", VirtIOPCIProxy, flags,
1332e37da394SKONRAD Frederic                     VIRTIO_PCI_FLAG_USE_IOEVENTFD_BIT, false),
1333e37da394SKONRAD Frederic     DEFINE_PROP_UINT32("vectors", VirtIOPCIProxy, nvectors, 3),
1334e37da394SKONRAD Frederic     DEFINE_PROP_END_OF_LIST(),
1335e37da394SKONRAD Frederic };
1336e37da394SKONRAD Frederic 
1337fc079951SMarkus Armbruster static void virtio_net_pci_realize(VirtIOPCIProxy *vpci_dev, Error **errp)
1338e37da394SKONRAD Frederic {
1339800ced8cSKONRAD Frederic     DeviceState *qdev = DEVICE(vpci_dev);
1340e37da394SKONRAD Frederic     VirtIONetPCI *dev = VIRTIO_NET_PCI(vpci_dev);
1341e37da394SKONRAD Frederic     DeviceState *vdev = DEVICE(&dev->vdev);
1342e37da394SKONRAD Frederic 
1343800ced8cSKONRAD Frederic     virtio_net_set_netclient_name(&dev->vdev, qdev->id,
1344800ced8cSKONRAD Frederic                                   object_get_typename(OBJECT(qdev)));
1345e37da394SKONRAD Frederic     qdev_set_parent_bus(vdev, BUS(&vpci_dev->bus));
1346fc079951SMarkus Armbruster     object_property_set_bool(OBJECT(vdev), true, "realized", errp);
1347e37da394SKONRAD Frederic }
1348e37da394SKONRAD Frederic 
1349e37da394SKONRAD Frederic static void virtio_net_pci_class_init(ObjectClass *klass, void *data)
1350e37da394SKONRAD Frederic {
1351e37da394SKONRAD Frederic     DeviceClass *dc = DEVICE_CLASS(klass);
1352e37da394SKONRAD Frederic     PCIDeviceClass *k = PCI_DEVICE_CLASS(klass);
1353e37da394SKONRAD Frederic     VirtioPCIClass *vpciklass = VIRTIO_PCI_CLASS(klass);
1354e37da394SKONRAD Frederic 
1355e37da394SKONRAD Frederic     k->romfile = "efi-virtio.rom";
1356e37da394SKONRAD Frederic     k->vendor_id = PCI_VENDOR_ID_REDHAT_QUMRANET;
1357e37da394SKONRAD Frederic     k->device_id = PCI_DEVICE_ID_VIRTIO_NET;
1358e37da394SKONRAD Frederic     k->revision = VIRTIO_PCI_ABI_VERSION;
1359e37da394SKONRAD Frederic     k->class_id = PCI_CLASS_NETWORK_ETHERNET;
1360125ee0edSMarcel Apfelbaum     set_bit(DEVICE_CATEGORY_NETWORK, dc->categories);
1361e37da394SKONRAD Frederic     dc->props = virtio_net_properties;
1362fc079951SMarkus Armbruster     vpciklass->realize = virtio_net_pci_realize;
1363e37da394SKONRAD Frederic }
1364e37da394SKONRAD Frederic 
1365e37da394SKONRAD Frederic static void virtio_net_pci_instance_init(Object *obj)
1366e37da394SKONRAD Frederic {
1367e37da394SKONRAD Frederic     VirtIONetPCI *dev = VIRTIO_NET_PCI(obj);
1368c8075cafSGonglei 
1369c8075cafSGonglei     virtio_instance_init_common(obj, &dev->vdev, sizeof(dev->vdev),
1370c8075cafSGonglei                                 TYPE_VIRTIO_NET);
13710cf63c3eSGonglei     object_property_add_alias(obj, "bootindex", OBJECT(&dev->vdev),
13720cf63c3eSGonglei                               "bootindex", &error_abort);
1373e37da394SKONRAD Frederic }
1374e37da394SKONRAD Frederic 
1375e37da394SKONRAD Frederic static const TypeInfo virtio_net_pci_info = {
1376e37da394SKONRAD Frederic     .name          = TYPE_VIRTIO_NET_PCI,
1377e37da394SKONRAD Frederic     .parent        = TYPE_VIRTIO_PCI,
1378e37da394SKONRAD Frederic     .instance_size = sizeof(VirtIONetPCI),
1379e37da394SKONRAD Frederic     .instance_init = virtio_net_pci_instance_init,
1380e37da394SKONRAD Frederic     .class_init    = virtio_net_pci_class_init,
1381e37da394SKONRAD Frederic };
1382e37da394SKONRAD Frederic 
138359ccd20aSKONRAD Frederic /* virtio-rng-pci */
138459ccd20aSKONRAD Frederic 
138559ccd20aSKONRAD Frederic static Property virtio_rng_pci_properties[] = {
138659ccd20aSKONRAD Frederic     DEFINE_PROP_END_OF_LIST(),
138759ccd20aSKONRAD Frederic };
138859ccd20aSKONRAD Frederic 
1389fc079951SMarkus Armbruster static void virtio_rng_pci_realize(VirtIOPCIProxy *vpci_dev, Error **errp)
139059ccd20aSKONRAD Frederic {
139159ccd20aSKONRAD Frederic     VirtIORngPCI *vrng = VIRTIO_RNG_PCI(vpci_dev);
139259ccd20aSKONRAD Frederic     DeviceState *vdev = DEVICE(&vrng->vdev);
1393fc079951SMarkus Armbruster     Error *err = NULL;
139459ccd20aSKONRAD Frederic 
139559ccd20aSKONRAD Frederic     qdev_set_parent_bus(vdev, BUS(&vpci_dev->bus));
1396fc079951SMarkus Armbruster     object_property_set_bool(OBJECT(vdev), true, "realized", &err);
1397fc079951SMarkus Armbruster     if (err) {
1398fc079951SMarkus Armbruster         error_propagate(errp, err);
1399fc079951SMarkus Armbruster         return;
140059ccd20aSKONRAD Frederic     }
140159ccd20aSKONRAD Frederic 
140259ccd20aSKONRAD Frederic     object_property_set_link(OBJECT(vrng),
14035b456438SCole Robinson                              OBJECT(vrng->vdev.conf.rng), "rng",
140459ccd20aSKONRAD Frederic                              NULL);
140559ccd20aSKONRAD Frederic }
140659ccd20aSKONRAD Frederic 
140759ccd20aSKONRAD Frederic static void virtio_rng_pci_class_init(ObjectClass *klass, void *data)
140859ccd20aSKONRAD Frederic {
140959ccd20aSKONRAD Frederic     DeviceClass *dc = DEVICE_CLASS(klass);
141059ccd20aSKONRAD Frederic     VirtioPCIClass *k = VIRTIO_PCI_CLASS(klass);
141159ccd20aSKONRAD Frederic     PCIDeviceClass *pcidev_k = PCI_DEVICE_CLASS(klass);
141259ccd20aSKONRAD Frederic 
1413fc079951SMarkus Armbruster     k->realize = virtio_rng_pci_realize;
1414125ee0edSMarcel Apfelbaum     set_bit(DEVICE_CATEGORY_MISC, dc->categories);
141559ccd20aSKONRAD Frederic     dc->props = virtio_rng_pci_properties;
141659ccd20aSKONRAD Frederic 
141759ccd20aSKONRAD Frederic     pcidev_k->vendor_id = PCI_VENDOR_ID_REDHAT_QUMRANET;
141859ccd20aSKONRAD Frederic     pcidev_k->device_id = PCI_DEVICE_ID_VIRTIO_RNG;
141959ccd20aSKONRAD Frederic     pcidev_k->revision = VIRTIO_PCI_ABI_VERSION;
142059ccd20aSKONRAD Frederic     pcidev_k->class_id = PCI_CLASS_OTHERS;
142159ccd20aSKONRAD Frederic }
142259ccd20aSKONRAD Frederic 
142359ccd20aSKONRAD Frederic static void virtio_rng_initfn(Object *obj)
142459ccd20aSKONRAD Frederic {
142559ccd20aSKONRAD Frederic     VirtIORngPCI *dev = VIRTIO_RNG_PCI(obj);
1426c8075cafSGonglei 
1427c8075cafSGonglei     virtio_instance_init_common(obj, &dev->vdev, sizeof(dev->vdev),
1428c8075cafSGonglei                                 TYPE_VIRTIO_RNG);
1429cbd5ac69SPaolo Bonzini     object_property_add_alias(obj, "rng", OBJECT(&dev->vdev), "rng",
1430cbd5ac69SPaolo Bonzini                               &error_abort);
143159ccd20aSKONRAD Frederic }
143259ccd20aSKONRAD Frederic 
143359ccd20aSKONRAD Frederic static const TypeInfo virtio_rng_pci_info = {
143459ccd20aSKONRAD Frederic     .name          = TYPE_VIRTIO_RNG_PCI,
143559ccd20aSKONRAD Frederic     .parent        = TYPE_VIRTIO_PCI,
143659ccd20aSKONRAD Frederic     .instance_size = sizeof(VirtIORngPCI),
143759ccd20aSKONRAD Frederic     .instance_init = virtio_rng_initfn,
143859ccd20aSKONRAD Frederic     .class_init    = virtio_rng_pci_class_init,
143959ccd20aSKONRAD Frederic };
144059ccd20aSKONRAD Frederic 
14410a2acf5eSKONRAD Frederic /* virtio-pci-bus */
14420a2acf5eSKONRAD Frederic 
1443ac7af112SAndreas Färber static void virtio_pci_bus_new(VirtioBusState *bus, size_t bus_size,
1444ac7af112SAndreas Färber                                VirtIOPCIProxy *dev)
14450a2acf5eSKONRAD Frederic {
14460a2acf5eSKONRAD Frederic     DeviceState *qdev = DEVICE(dev);
1447f4dd69aaSKONRAD Frederic     char virtio_bus_name[] = "virtio-bus";
1448f4dd69aaSKONRAD Frederic 
1449fb17dfe0SAndreas Färber     qbus_create_inplace(bus, bus_size, TYPE_VIRTIO_PCI_BUS, qdev,
1450f4dd69aaSKONRAD Frederic                         virtio_bus_name);
14510a2acf5eSKONRAD Frederic }
14520a2acf5eSKONRAD Frederic 
14530a2acf5eSKONRAD Frederic static void virtio_pci_bus_class_init(ObjectClass *klass, void *data)
14540a2acf5eSKONRAD Frederic {
14550a2acf5eSKONRAD Frederic     BusClass *bus_class = BUS_CLASS(klass);
14560a2acf5eSKONRAD Frederic     VirtioBusClass *k = VIRTIO_BUS_CLASS(klass);
14570a2acf5eSKONRAD Frederic     bus_class->max_dev = 1;
14580a2acf5eSKONRAD Frederic     k->notify = virtio_pci_notify;
14590a2acf5eSKONRAD Frederic     k->save_config = virtio_pci_save_config;
14600a2acf5eSKONRAD Frederic     k->load_config = virtio_pci_load_config;
14610a2acf5eSKONRAD Frederic     k->save_queue = virtio_pci_save_queue;
14620a2acf5eSKONRAD Frederic     k->load_queue = virtio_pci_load_queue;
14630a2acf5eSKONRAD Frederic     k->query_guest_notifiers = virtio_pci_query_guest_notifiers;
14640a2acf5eSKONRAD Frederic     k->set_host_notifier = virtio_pci_set_host_notifier;
14650a2acf5eSKONRAD Frederic     k->set_guest_notifiers = virtio_pci_set_guest_notifiers;
14660a2acf5eSKONRAD Frederic     k->vmstate_change = virtio_pci_vmstate_change;
1467085bccb7SKONRAD Frederic     k->device_plugged = virtio_pci_device_plugged;
146806a13073SPaolo Bonzini     k->device_unplugged = virtio_pci_device_unplugged;
1469e0d686bfSJason Wang     k->query_nvectors = virtio_pci_query_nvectors;
14700a2acf5eSKONRAD Frederic }
14710a2acf5eSKONRAD Frederic 
14720a2acf5eSKONRAD Frederic static const TypeInfo virtio_pci_bus_info = {
14730a2acf5eSKONRAD Frederic     .name          = TYPE_VIRTIO_PCI_BUS,
14740a2acf5eSKONRAD Frederic     .parent        = TYPE_VIRTIO_BUS,
14750a2acf5eSKONRAD Frederic     .instance_size = sizeof(VirtioPCIBusState),
14760a2acf5eSKONRAD Frederic     .class_init    = virtio_pci_bus_class_init,
14770a2acf5eSKONRAD Frederic };
14780a2acf5eSKONRAD Frederic 
147983f7d43aSAndreas Färber static void virtio_pci_register_types(void)
148053c25ceaSPaul Brook {
148159ccd20aSKONRAD Frederic     type_register_static(&virtio_rng_pci_info);
14820a2acf5eSKONRAD Frederic     type_register_static(&virtio_pci_bus_info);
1483085bccb7SKONRAD Frederic     type_register_static(&virtio_pci_info);
148460653b28SPaolo Bonzini #ifdef CONFIG_VIRTFS
1485234a336fSKONRAD Frederic     type_register_static(&virtio_9p_pci_info);
148660653b28SPaolo Bonzini #endif
1487653ced07SKONRAD Frederic     type_register_static(&virtio_blk_pci_info);
1488bc7b90a0SKONRAD Frederic     type_register_static(&virtio_scsi_pci_info);
1489e378e88dSKONRAD Frederic     type_register_static(&virtio_balloon_pci_info);
1490f7f7464aSKONRAD Frederic     type_register_static(&virtio_serial_pci_info);
1491e37da394SKONRAD Frederic     type_register_static(&virtio_net_pci_info);
149250787628SNicholas Bellinger #ifdef CONFIG_VHOST_SCSI
149350787628SNicholas Bellinger     type_register_static(&vhost_scsi_pci_info);
149450787628SNicholas Bellinger #endif
149553c25ceaSPaul Brook }
149653c25ceaSPaul Brook 
149783f7d43aSAndreas Färber type_init(virtio_pci_register_types)
1498