xref: /qemu/hw/virtio/virtio-pci.c (revision 39b87c7b9f8bf3618e0357699d29615e521264d8)
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:
3098172539dSMichael S. Tsirkin         ret = proxy->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 
437d2a0ccc6SMichael S. Tsirkin static unsigned virtio_pci_get_features(DeviceState *d)
4386d74ca5aSMichael S. Tsirkin {
439d2a0ccc6SMichael S. Tsirkin     VirtIOPCIProxy *proxy = to_virtio_pci_proxy(d);
4408172539dSMichael S. Tsirkin     return proxy->host_features;
4416d74ca5aSMichael S. Tsirkin }
4426d74ca5aSMichael S. Tsirkin 
4437d37d351SJan Kiszka static int kvm_virtio_pci_vq_vector_use(VirtIOPCIProxy *proxy,
4447d37d351SJan Kiszka                                         unsigned int queue_no,
4457d37d351SJan Kiszka                                         unsigned int vector,
4467d37d351SJan Kiszka                                         MSIMessage msg)
4477d37d351SJan Kiszka {
4487d37d351SJan Kiszka     VirtIOIRQFD *irqfd = &proxy->vector_irqfd[vector];
44915b2bd18SPaolo Bonzini     int ret;
4507d37d351SJan Kiszka 
4517d37d351SJan Kiszka     if (irqfd->users == 0) {
4527d37d351SJan Kiszka         ret = kvm_irqchip_add_msi_route(kvm_state, msg);
4537d37d351SJan Kiszka         if (ret < 0) {
4547d37d351SJan Kiszka             return ret;
4557d37d351SJan Kiszka         }
4567d37d351SJan Kiszka         irqfd->virq = ret;
4577d37d351SJan Kiszka     }
4587d37d351SJan Kiszka     irqfd->users++;
4597d37d351SJan Kiszka     return 0;
4607d37d351SJan Kiszka }
4617d37d351SJan Kiszka 
4627d37d351SJan Kiszka static void kvm_virtio_pci_vq_vector_release(VirtIOPCIProxy *proxy,
463774345f9SMichael S. Tsirkin                                              unsigned int vector)
464774345f9SMichael S. Tsirkin {
465774345f9SMichael S. Tsirkin     VirtIOIRQFD *irqfd = &proxy->vector_irqfd[vector];
466774345f9SMichael S. Tsirkin     if (--irqfd->users == 0) {
467774345f9SMichael S. Tsirkin         kvm_irqchip_release_virq(kvm_state, irqfd->virq);
468774345f9SMichael S. Tsirkin     }
469774345f9SMichael S. Tsirkin }
470774345f9SMichael S. Tsirkin 
471f1d0f15aSMichael S. Tsirkin static int kvm_virtio_pci_irqfd_use(VirtIOPCIProxy *proxy,
472f1d0f15aSMichael S. Tsirkin                                  unsigned int queue_no,
473f1d0f15aSMichael S. Tsirkin                                  unsigned int vector)
474f1d0f15aSMichael S. Tsirkin {
475f1d0f15aSMichael S. Tsirkin     VirtIOIRQFD *irqfd = &proxy->vector_irqfd[vector];
476a3fc66d9SPaolo Bonzini     VirtIODevice *vdev = virtio_bus_get_device(&proxy->bus);
477a3fc66d9SPaolo Bonzini     VirtQueue *vq = virtio_get_queue(vdev, queue_no);
478f1d0f15aSMichael S. Tsirkin     EventNotifier *n = virtio_queue_get_guest_notifier(vq);
479f1d0f15aSMichael S. Tsirkin     int ret;
480ca916d37SVincenzo Maffione     ret = kvm_irqchip_add_irqfd_notifier(kvm_state, n, NULL, irqfd->virq);
481f1d0f15aSMichael S. Tsirkin     return ret;
482f1d0f15aSMichael S. Tsirkin }
483f1d0f15aSMichael S. Tsirkin 
484f1d0f15aSMichael S. Tsirkin static void kvm_virtio_pci_irqfd_release(VirtIOPCIProxy *proxy,
4857d37d351SJan Kiszka                                       unsigned int queue_no,
4867d37d351SJan Kiszka                                       unsigned int vector)
4877d37d351SJan Kiszka {
488a3fc66d9SPaolo Bonzini     VirtIODevice *vdev = virtio_bus_get_device(&proxy->bus);
489a3fc66d9SPaolo Bonzini     VirtQueue *vq = virtio_get_queue(vdev, queue_no);
49015b2bd18SPaolo Bonzini     EventNotifier *n = virtio_queue_get_guest_notifier(vq);
4917d37d351SJan Kiszka     VirtIOIRQFD *irqfd = &proxy->vector_irqfd[vector];
49215b2bd18SPaolo Bonzini     int ret;
4937d37d351SJan Kiszka 
494b131c74aSJan Kiszka     ret = kvm_irqchip_remove_irqfd_notifier(kvm_state, n, irqfd->virq);
4957d37d351SJan Kiszka     assert(ret == 0);
496f1d0f15aSMichael S. Tsirkin }
4977d37d351SJan Kiszka 
498774345f9SMichael S. Tsirkin static int kvm_virtio_pci_vector_use(VirtIOPCIProxy *proxy, int nvqs)
499774345f9SMichael S. Tsirkin {
500774345f9SMichael S. Tsirkin     PCIDevice *dev = &proxy->pci_dev;
501a3fc66d9SPaolo Bonzini     VirtIODevice *vdev = virtio_bus_get_device(&proxy->bus);
502181103cdSKONRAD Frederic     VirtioDeviceClass *k = VIRTIO_DEVICE_GET_CLASS(vdev);
503774345f9SMichael S. Tsirkin     unsigned int vector;
504774345f9SMichael S. Tsirkin     int ret, queue_no;
505774345f9SMichael S. Tsirkin     MSIMessage msg;
506774345f9SMichael S. Tsirkin 
507774345f9SMichael S. Tsirkin     for (queue_no = 0; queue_no < nvqs; queue_no++) {
508774345f9SMichael S. Tsirkin         if (!virtio_queue_get_num(vdev, queue_no)) {
509774345f9SMichael S. Tsirkin             break;
510774345f9SMichael S. Tsirkin         }
511774345f9SMichael S. Tsirkin         vector = virtio_queue_vector(vdev, queue_no);
512774345f9SMichael S. Tsirkin         if (vector >= msix_nr_vectors_allocated(dev)) {
513774345f9SMichael S. Tsirkin             continue;
514774345f9SMichael S. Tsirkin         }
515774345f9SMichael S. Tsirkin         msg = msix_get_message(dev, vector);
516774345f9SMichael S. Tsirkin         ret = kvm_virtio_pci_vq_vector_use(proxy, queue_no, vector, msg);
517774345f9SMichael S. Tsirkin         if (ret < 0) {
518774345f9SMichael S. Tsirkin             goto undo;
519774345f9SMichael S. Tsirkin         }
520f1d0f15aSMichael S. Tsirkin         /* If guest supports masking, set up irqfd now.
521f1d0f15aSMichael S. Tsirkin          * Otherwise, delay until unmasked in the frontend.
522f1d0f15aSMichael S. Tsirkin          */
523181103cdSKONRAD Frederic         if (k->guest_notifier_mask) {
524f1d0f15aSMichael S. Tsirkin             ret = kvm_virtio_pci_irqfd_use(proxy, queue_no, vector);
525f1d0f15aSMichael S. Tsirkin             if (ret < 0) {
526f1d0f15aSMichael S. Tsirkin                 kvm_virtio_pci_vq_vector_release(proxy, vector);
527f1d0f15aSMichael S. Tsirkin                 goto undo;
528f1d0f15aSMichael S. Tsirkin             }
529f1d0f15aSMichael S. Tsirkin         }
530774345f9SMichael S. Tsirkin     }
531774345f9SMichael S. Tsirkin     return 0;
532774345f9SMichael S. Tsirkin 
533774345f9SMichael S. Tsirkin undo:
534774345f9SMichael S. Tsirkin     while (--queue_no >= 0) {
535774345f9SMichael S. Tsirkin         vector = virtio_queue_vector(vdev, queue_no);
536774345f9SMichael S. Tsirkin         if (vector >= msix_nr_vectors_allocated(dev)) {
537774345f9SMichael S. Tsirkin             continue;
538774345f9SMichael S. Tsirkin         }
539181103cdSKONRAD Frederic         if (k->guest_notifier_mask) {
540e387f99eSMichael S. Tsirkin             kvm_virtio_pci_irqfd_release(proxy, queue_no, vector);
541f1d0f15aSMichael S. Tsirkin         }
542774345f9SMichael S. Tsirkin         kvm_virtio_pci_vq_vector_release(proxy, vector);
543774345f9SMichael S. Tsirkin     }
544774345f9SMichael S. Tsirkin     return ret;
545774345f9SMichael S. Tsirkin }
546774345f9SMichael S. Tsirkin 
547774345f9SMichael S. Tsirkin static void kvm_virtio_pci_vector_release(VirtIOPCIProxy *proxy, int nvqs)
548774345f9SMichael S. Tsirkin {
549774345f9SMichael S. Tsirkin     PCIDevice *dev = &proxy->pci_dev;
550a3fc66d9SPaolo Bonzini     VirtIODevice *vdev = virtio_bus_get_device(&proxy->bus);
551774345f9SMichael S. Tsirkin     unsigned int vector;
552774345f9SMichael S. Tsirkin     int queue_no;
553181103cdSKONRAD Frederic     VirtioDeviceClass *k = VIRTIO_DEVICE_GET_CLASS(vdev);
554774345f9SMichael S. Tsirkin 
555774345f9SMichael S. Tsirkin     for (queue_no = 0; queue_no < nvqs; queue_no++) {
556774345f9SMichael S. Tsirkin         if (!virtio_queue_get_num(vdev, queue_no)) {
557774345f9SMichael S. Tsirkin             break;
558774345f9SMichael S. Tsirkin         }
559774345f9SMichael S. Tsirkin         vector = virtio_queue_vector(vdev, queue_no);
560774345f9SMichael S. Tsirkin         if (vector >= msix_nr_vectors_allocated(dev)) {
561774345f9SMichael S. Tsirkin             continue;
562774345f9SMichael S. Tsirkin         }
563f1d0f15aSMichael S. Tsirkin         /* If guest supports masking, clean up irqfd now.
564f1d0f15aSMichael S. Tsirkin          * Otherwise, it was cleaned when masked in the frontend.
565f1d0f15aSMichael S. Tsirkin          */
566181103cdSKONRAD Frederic         if (k->guest_notifier_mask) {
567e387f99eSMichael S. Tsirkin             kvm_virtio_pci_irqfd_release(proxy, queue_no, vector);
568f1d0f15aSMichael S. Tsirkin         }
569774345f9SMichael S. Tsirkin         kvm_virtio_pci_vq_vector_release(proxy, vector);
5707d37d351SJan Kiszka     }
5717d37d351SJan Kiszka }
5727d37d351SJan Kiszka 
573a38b2c49SMichael S. Tsirkin static int virtio_pci_vq_vector_unmask(VirtIOPCIProxy *proxy,
574774345f9SMichael S. Tsirkin                                        unsigned int queue_no,
575774345f9SMichael S. Tsirkin                                        unsigned int vector,
576774345f9SMichael S. Tsirkin                                        MSIMessage msg)
577774345f9SMichael S. Tsirkin {
578a3fc66d9SPaolo Bonzini     VirtIODevice *vdev = virtio_bus_get_device(&proxy->bus);
579a3fc66d9SPaolo Bonzini     VirtioDeviceClass *k = VIRTIO_DEVICE_GET_CLASS(vdev);
580a3fc66d9SPaolo Bonzini     VirtQueue *vq = virtio_get_queue(vdev, queue_no);
581774345f9SMichael S. Tsirkin     EventNotifier *n = virtio_queue_get_guest_notifier(vq);
582a38b2c49SMichael S. Tsirkin     VirtIOIRQFD *irqfd;
58353510bfcSMichael Roth     int ret = 0;
584774345f9SMichael S. Tsirkin 
585a38b2c49SMichael S. Tsirkin     if (proxy->vector_irqfd) {
586a38b2c49SMichael S. Tsirkin         irqfd = &proxy->vector_irqfd[vector];
587774345f9SMichael S. Tsirkin         if (irqfd->msg.data != msg.data || irqfd->msg.address != msg.address) {
588774345f9SMichael S. Tsirkin             ret = kvm_irqchip_update_msi_route(kvm_state, irqfd->virq, msg);
589774345f9SMichael S. Tsirkin             if (ret < 0) {
590774345f9SMichael S. Tsirkin                 return ret;
591774345f9SMichael S. Tsirkin             }
592774345f9SMichael S. Tsirkin         }
593a38b2c49SMichael S. Tsirkin     }
594774345f9SMichael S. Tsirkin 
595f1d0f15aSMichael S. Tsirkin     /* If guest supports masking, irqfd is already setup, unmask it.
596f1d0f15aSMichael S. Tsirkin      * Otherwise, set it up now.
597f1d0f15aSMichael S. Tsirkin      */
598181103cdSKONRAD Frederic     if (k->guest_notifier_mask) {
599a3fc66d9SPaolo Bonzini         k->guest_notifier_mask(vdev, queue_no, false);
600f1d0f15aSMichael S. Tsirkin         /* Test after unmasking to avoid losing events. */
601181103cdSKONRAD Frederic         if (k->guest_notifier_pending &&
602a3fc66d9SPaolo Bonzini             k->guest_notifier_pending(vdev, queue_no)) {
603f1d0f15aSMichael S. Tsirkin             event_notifier_set(n);
604f1d0f15aSMichael S. Tsirkin         }
605f1d0f15aSMichael S. Tsirkin     } else {
606f1d0f15aSMichael S. Tsirkin         ret = kvm_virtio_pci_irqfd_use(proxy, queue_no, vector);
607f1d0f15aSMichael S. Tsirkin     }
608774345f9SMichael S. Tsirkin     return ret;
609774345f9SMichael S. Tsirkin }
610774345f9SMichael S. Tsirkin 
611a38b2c49SMichael S. Tsirkin static void virtio_pci_vq_vector_mask(VirtIOPCIProxy *proxy,
6127d37d351SJan Kiszka                                              unsigned int queue_no,
6137d37d351SJan Kiszka                                              unsigned int vector)
6147d37d351SJan Kiszka {
615a3fc66d9SPaolo Bonzini     VirtIODevice *vdev = virtio_bus_get_device(&proxy->bus);
616a3fc66d9SPaolo Bonzini     VirtioDeviceClass *k = VIRTIO_DEVICE_GET_CLASS(vdev);
617181103cdSKONRAD Frederic 
618f1d0f15aSMichael S. Tsirkin     /* If guest supports masking, keep irqfd but mask it.
619f1d0f15aSMichael S. Tsirkin      * Otherwise, clean it up now.
620f1d0f15aSMichael S. Tsirkin      */
621181103cdSKONRAD Frederic     if (k->guest_notifier_mask) {
622a3fc66d9SPaolo Bonzini         k->guest_notifier_mask(vdev, queue_no, true);
623f1d0f15aSMichael S. Tsirkin     } else {
624e387f99eSMichael S. Tsirkin         kvm_virtio_pci_irqfd_release(proxy, queue_no, vector);
625f1d0f15aSMichael S. Tsirkin     }
6267d37d351SJan Kiszka }
6277d37d351SJan Kiszka 
628a38b2c49SMichael S. Tsirkin static int virtio_pci_vector_unmask(PCIDevice *dev, unsigned vector,
6297d37d351SJan Kiszka                                     MSIMessage msg)
6307d37d351SJan Kiszka {
6317d37d351SJan Kiszka     VirtIOPCIProxy *proxy = container_of(dev, VirtIOPCIProxy, pci_dev);
632a3fc66d9SPaolo Bonzini     VirtIODevice *vdev = virtio_bus_get_device(&proxy->bus);
633851c2a75SJason Wang     VirtQueue *vq = virtio_vector_first_queue(vdev, vector);
634851c2a75SJason Wang     int ret, index, unmasked = 0;
6357d37d351SJan Kiszka 
636851c2a75SJason Wang     while (vq) {
637851c2a75SJason Wang         index = virtio_get_queue_index(vq);
638851c2a75SJason Wang         if (!virtio_queue_get_num(vdev, index)) {
6397d37d351SJan Kiszka             break;
6407d37d351SJan Kiszka         }
641851c2a75SJason Wang         ret = virtio_pci_vq_vector_unmask(proxy, index, vector, msg);
6427d37d351SJan Kiszka         if (ret < 0) {
6437d37d351SJan Kiszka             goto undo;
6447d37d351SJan Kiszka         }
645851c2a75SJason Wang         vq = virtio_vector_next_queue(vq);
646851c2a75SJason Wang         ++unmasked;
6477d37d351SJan Kiszka     }
648851c2a75SJason Wang 
6497d37d351SJan Kiszka     return 0;
6507d37d351SJan Kiszka 
6517d37d351SJan Kiszka undo:
652851c2a75SJason Wang     vq = virtio_vector_first_queue(vdev, vector);
653851c2a75SJason Wang     while (vq && --unmasked >= 0) {
654851c2a75SJason Wang         index = virtio_get_queue_index(vq);
655851c2a75SJason Wang         virtio_pci_vq_vector_mask(proxy, index, vector);
656851c2a75SJason Wang         vq = virtio_vector_next_queue(vq);
6577d37d351SJan Kiszka     }
6587d37d351SJan Kiszka     return ret;
6597d37d351SJan Kiszka }
6607d37d351SJan Kiszka 
661a38b2c49SMichael S. Tsirkin static void virtio_pci_vector_mask(PCIDevice *dev, unsigned vector)
6627d37d351SJan Kiszka {
6637d37d351SJan Kiszka     VirtIOPCIProxy *proxy = container_of(dev, VirtIOPCIProxy, pci_dev);
664a3fc66d9SPaolo Bonzini     VirtIODevice *vdev = virtio_bus_get_device(&proxy->bus);
665851c2a75SJason Wang     VirtQueue *vq = virtio_vector_first_queue(vdev, vector);
666851c2a75SJason Wang     int index;
6677d37d351SJan Kiszka 
668851c2a75SJason Wang     while (vq) {
669851c2a75SJason Wang         index = virtio_get_queue_index(vq);
670851c2a75SJason Wang         if (!virtio_queue_get_num(vdev, index)) {
6717d37d351SJan Kiszka             break;
6727d37d351SJan Kiszka         }
673851c2a75SJason Wang         virtio_pci_vq_vector_mask(proxy, index, vector);
674851c2a75SJason Wang         vq = virtio_vector_next_queue(vq);
6757d37d351SJan Kiszka     }
6767d37d351SJan Kiszka }
6777d37d351SJan Kiszka 
678a38b2c49SMichael S. Tsirkin static void virtio_pci_vector_poll(PCIDevice *dev,
67989d62be9SMichael S. Tsirkin                                    unsigned int vector_start,
68089d62be9SMichael S. Tsirkin                                    unsigned int vector_end)
68189d62be9SMichael S. Tsirkin {
68289d62be9SMichael S. Tsirkin     VirtIOPCIProxy *proxy = container_of(dev, VirtIOPCIProxy, pci_dev);
683a3fc66d9SPaolo Bonzini     VirtIODevice *vdev = virtio_bus_get_device(&proxy->bus);
684181103cdSKONRAD Frederic     VirtioDeviceClass *k = VIRTIO_DEVICE_GET_CLASS(vdev);
68589d62be9SMichael S. Tsirkin     int queue_no;
68689d62be9SMichael S. Tsirkin     unsigned int vector;
68789d62be9SMichael S. Tsirkin     EventNotifier *notifier;
68889d62be9SMichael S. Tsirkin     VirtQueue *vq;
68989d62be9SMichael S. Tsirkin 
6902d620f59SMichael S. Tsirkin     for (queue_no = 0; queue_no < proxy->nvqs_with_notifiers; queue_no++) {
69189d62be9SMichael S. Tsirkin         if (!virtio_queue_get_num(vdev, queue_no)) {
69289d62be9SMichael S. Tsirkin             break;
69389d62be9SMichael S. Tsirkin         }
69489d62be9SMichael S. Tsirkin         vector = virtio_queue_vector(vdev, queue_no);
69589d62be9SMichael S. Tsirkin         if (vector < vector_start || vector >= vector_end ||
69689d62be9SMichael S. Tsirkin             !msix_is_masked(dev, vector)) {
69789d62be9SMichael S. Tsirkin             continue;
69889d62be9SMichael S. Tsirkin         }
69989d62be9SMichael S. Tsirkin         vq = virtio_get_queue(vdev, queue_no);
70089d62be9SMichael S. Tsirkin         notifier = virtio_queue_get_guest_notifier(vq);
701181103cdSKONRAD Frederic         if (k->guest_notifier_pending) {
702181103cdSKONRAD Frederic             if (k->guest_notifier_pending(vdev, queue_no)) {
703f1d0f15aSMichael S. Tsirkin                 msix_set_pending(dev, vector);
704f1d0f15aSMichael S. Tsirkin             }
705f1d0f15aSMichael S. Tsirkin         } else if (event_notifier_test_and_clear(notifier)) {
70689d62be9SMichael S. Tsirkin             msix_set_pending(dev, vector);
70789d62be9SMichael S. Tsirkin         }
70889d62be9SMichael S. Tsirkin     }
70989d62be9SMichael S. Tsirkin }
71089d62be9SMichael S. Tsirkin 
71189d62be9SMichael S. Tsirkin static int virtio_pci_set_guest_notifier(DeviceState *d, int n, bool assign,
71289d62be9SMichael S. Tsirkin                                          bool with_irqfd)
713ade80dc8SMichael S. Tsirkin {
714d2a0ccc6SMichael S. Tsirkin     VirtIOPCIProxy *proxy = to_virtio_pci_proxy(d);
715a3fc66d9SPaolo Bonzini     VirtIODevice *vdev = virtio_bus_get_device(&proxy->bus);
716a3fc66d9SPaolo Bonzini     VirtioDeviceClass *vdc = VIRTIO_DEVICE_GET_CLASS(vdev);
717a3fc66d9SPaolo Bonzini     VirtQueue *vq = virtio_get_queue(vdev, n);
718ade80dc8SMichael S. Tsirkin     EventNotifier *notifier = virtio_queue_get_guest_notifier(vq);
719ade80dc8SMichael S. Tsirkin 
720ade80dc8SMichael S. Tsirkin     if (assign) {
721ade80dc8SMichael S. Tsirkin         int r = event_notifier_init(notifier, 0);
722ade80dc8SMichael S. Tsirkin         if (r < 0) {
723ade80dc8SMichael S. Tsirkin             return r;
724ade80dc8SMichael S. Tsirkin         }
72589d62be9SMichael S. Tsirkin         virtio_queue_set_guest_notifier_fd_handler(vq, true, with_irqfd);
726ade80dc8SMichael S. Tsirkin     } else {
72789d62be9SMichael S. Tsirkin         virtio_queue_set_guest_notifier_fd_handler(vq, false, with_irqfd);
728ade80dc8SMichael S. Tsirkin         event_notifier_cleanup(notifier);
729ade80dc8SMichael S. Tsirkin     }
730ade80dc8SMichael S. Tsirkin 
73162c96360SMichael S. Tsirkin     if (!msix_enabled(&proxy->pci_dev) && vdc->guest_notifier_mask) {
732a3fc66d9SPaolo Bonzini         vdc->guest_notifier_mask(vdev, n, !assign);
73362c96360SMichael S. Tsirkin     }
73462c96360SMichael S. Tsirkin 
735ade80dc8SMichael S. Tsirkin     return 0;
736ade80dc8SMichael S. Tsirkin }
737ade80dc8SMichael S. Tsirkin 
738d2a0ccc6SMichael S. Tsirkin static bool virtio_pci_query_guest_notifiers(DeviceState *d)
7395430a28fSmst@redhat.com {
740d2a0ccc6SMichael S. Tsirkin     VirtIOPCIProxy *proxy = to_virtio_pci_proxy(d);
7415430a28fSmst@redhat.com     return msix_enabled(&proxy->pci_dev);
7425430a28fSmst@redhat.com }
7435430a28fSmst@redhat.com 
7442d620f59SMichael S. Tsirkin static int virtio_pci_set_guest_notifiers(DeviceState *d, int nvqs, bool assign)
74554dd9321SMichael S. Tsirkin {
746d2a0ccc6SMichael S. Tsirkin     VirtIOPCIProxy *proxy = to_virtio_pci_proxy(d);
747a3fc66d9SPaolo Bonzini     VirtIODevice *vdev = virtio_bus_get_device(&proxy->bus);
748181103cdSKONRAD Frederic     VirtioDeviceClass *k = VIRTIO_DEVICE_GET_CLASS(vdev);
74954dd9321SMichael S. Tsirkin     int r, n;
75089d62be9SMichael S. Tsirkin     bool with_irqfd = msix_enabled(&proxy->pci_dev) &&
75189d62be9SMichael S. Tsirkin         kvm_msi_via_irqfd_enabled();
75254dd9321SMichael S. Tsirkin 
7532d620f59SMichael S. Tsirkin     nvqs = MIN(nvqs, VIRTIO_PCI_QUEUE_MAX);
7542d620f59SMichael S. Tsirkin 
7552d620f59SMichael S. Tsirkin     /* When deassigning, pass a consistent nvqs value
7562d620f59SMichael S. Tsirkin      * to avoid leaking notifiers.
7572d620f59SMichael S. Tsirkin      */
7582d620f59SMichael S. Tsirkin     assert(assign || nvqs == proxy->nvqs_with_notifiers);
7592d620f59SMichael S. Tsirkin 
7602d620f59SMichael S. Tsirkin     proxy->nvqs_with_notifiers = nvqs;
7612d620f59SMichael S. Tsirkin 
7627d37d351SJan Kiszka     /* Must unset vector notifier while guest notifier is still assigned */
763181103cdSKONRAD Frederic     if ((proxy->vector_irqfd || k->guest_notifier_mask) && !assign) {
7647d37d351SJan Kiszka         msix_unset_vector_notifiers(&proxy->pci_dev);
765a38b2c49SMichael S. Tsirkin         if (proxy->vector_irqfd) {
766774345f9SMichael S. Tsirkin             kvm_virtio_pci_vector_release(proxy, nvqs);
7677d37d351SJan Kiszka             g_free(proxy->vector_irqfd);
7687d37d351SJan Kiszka             proxy->vector_irqfd = NULL;
7697d37d351SJan Kiszka         }
770a38b2c49SMichael S. Tsirkin     }
7717d37d351SJan Kiszka 
7722d620f59SMichael S. Tsirkin     for (n = 0; n < nvqs; n++) {
77354dd9321SMichael S. Tsirkin         if (!virtio_queue_get_num(vdev, n)) {
77454dd9321SMichael S. Tsirkin             break;
77554dd9321SMichael S. Tsirkin         }
77654dd9321SMichael S. Tsirkin 
77723fe2b3fSMichael S. Tsirkin         r = virtio_pci_set_guest_notifier(d, n, assign, with_irqfd);
77854dd9321SMichael S. Tsirkin         if (r < 0) {
77954dd9321SMichael S. Tsirkin             goto assign_error;
78054dd9321SMichael S. Tsirkin         }
78154dd9321SMichael S. Tsirkin     }
78254dd9321SMichael S. Tsirkin 
7837d37d351SJan Kiszka     /* Must set vector notifier after guest notifier has been assigned */
784181103cdSKONRAD Frederic     if ((with_irqfd || k->guest_notifier_mask) && assign) {
785a38b2c49SMichael S. Tsirkin         if (with_irqfd) {
7867d37d351SJan Kiszka             proxy->vector_irqfd =
7877d37d351SJan Kiszka                 g_malloc0(sizeof(*proxy->vector_irqfd) *
7887d37d351SJan Kiszka                           msix_nr_vectors_allocated(&proxy->pci_dev));
789774345f9SMichael S. Tsirkin             r = kvm_virtio_pci_vector_use(proxy, nvqs);
7907d37d351SJan Kiszka             if (r < 0) {
7917d37d351SJan Kiszka                 goto assign_error;
7927d37d351SJan Kiszka             }
793a38b2c49SMichael S. Tsirkin         }
794774345f9SMichael S. Tsirkin         r = msix_set_vector_notifiers(&proxy->pci_dev,
795a38b2c49SMichael S. Tsirkin                                       virtio_pci_vector_unmask,
796a38b2c49SMichael S. Tsirkin                                       virtio_pci_vector_mask,
797a38b2c49SMichael S. Tsirkin                                       virtio_pci_vector_poll);
798774345f9SMichael S. Tsirkin         if (r < 0) {
799774345f9SMichael S. Tsirkin             goto notifiers_error;
800774345f9SMichael S. Tsirkin         }
8017d37d351SJan Kiszka     }
8027d37d351SJan Kiszka 
80354dd9321SMichael S. Tsirkin     return 0;
80454dd9321SMichael S. Tsirkin 
805774345f9SMichael S. Tsirkin notifiers_error:
806a38b2c49SMichael S. Tsirkin     if (with_irqfd) {
807774345f9SMichael S. Tsirkin         assert(assign);
808774345f9SMichael S. Tsirkin         kvm_virtio_pci_vector_release(proxy, nvqs);
809a38b2c49SMichael S. Tsirkin     }
810774345f9SMichael S. Tsirkin 
81154dd9321SMichael S. Tsirkin assign_error:
81254dd9321SMichael S. Tsirkin     /* We get here on assignment failure. Recover by undoing for VQs 0 .. n. */
8137d37d351SJan Kiszka     assert(assign);
81454dd9321SMichael S. Tsirkin     while (--n >= 0) {
81589d62be9SMichael S. Tsirkin         virtio_pci_set_guest_notifier(d, n, !assign, with_irqfd);
81654dd9321SMichael S. Tsirkin     }
81754dd9321SMichael S. Tsirkin     return r;
81854dd9321SMichael S. Tsirkin }
81954dd9321SMichael S. Tsirkin 
820d2a0ccc6SMichael S. Tsirkin static int virtio_pci_set_host_notifier(DeviceState *d, int n, bool assign)
821ade80dc8SMichael S. Tsirkin {
822d2a0ccc6SMichael S. Tsirkin     VirtIOPCIProxy *proxy = to_virtio_pci_proxy(d);
82325db9ebeSStefan Hajnoczi 
82425db9ebeSStefan Hajnoczi     /* Stop using ioeventfd for virtqueue kick if the device starts using host
82525db9ebeSStefan Hajnoczi      * notifiers.  This makes it easy to avoid stepping on each others' toes.
82625db9ebeSStefan Hajnoczi      */
82725db9ebeSStefan Hajnoczi     proxy->ioeventfd_disabled = assign;
828ade80dc8SMichael S. Tsirkin     if (assign) {
82925db9ebeSStefan Hajnoczi         virtio_pci_stop_ioeventfd(proxy);
830ade80dc8SMichael S. Tsirkin     }
83125db9ebeSStefan Hajnoczi     /* We don't need to start here: it's not needed because backend
83225db9ebeSStefan Hajnoczi      * currently only stops on status change away from ok,
83325db9ebeSStefan Hajnoczi      * reset, vmstop and such. If we do add code to start here,
83425db9ebeSStefan Hajnoczi      * need to check vmstate, device state etc. */
83526b9b5feSPaolo Bonzini     return virtio_pci_set_host_notifier_internal(proxy, n, assign, false);
836ade80dc8SMichael S. Tsirkin }
83725db9ebeSStefan Hajnoczi 
838d2a0ccc6SMichael S. Tsirkin static void virtio_pci_vmstate_change(DeviceState *d, bool running)
83925db9ebeSStefan Hajnoczi {
840d2a0ccc6SMichael S. Tsirkin     VirtIOPCIProxy *proxy = to_virtio_pci_proxy(d);
841a3fc66d9SPaolo Bonzini     VirtIODevice *vdev = virtio_bus_get_device(&proxy->bus);
84225db9ebeSStefan Hajnoczi 
84325db9ebeSStefan Hajnoczi     if (running) {
84468a27b20SMichael S. Tsirkin         /* Old QEMU versions did not set bus master enable on status write.
84568a27b20SMichael S. Tsirkin          * Detect DRIVER set and enable it.
84668a27b20SMichael S. Tsirkin          */
84768a27b20SMichael S. Tsirkin         if ((proxy->flags & VIRTIO_PCI_FLAG_BUS_MASTER_BUG_MIGRATION) &&
84868a27b20SMichael S. Tsirkin             (vdev->status & VIRTIO_CONFIG_S_DRIVER) &&
84945363e46SMichael S. Tsirkin             !(proxy->pci_dev.config[PCI_COMMAND] & PCI_COMMAND_MASTER)) {
85068a27b20SMichael S. Tsirkin             pci_default_write_config(&proxy->pci_dev, PCI_COMMAND,
85168a27b20SMichael S. Tsirkin                                      proxy->pci_dev.config[PCI_COMMAND] |
85268a27b20SMichael S. Tsirkin                                      PCI_COMMAND_MASTER, 1);
85389c473fdSMichael S. Tsirkin         }
85425db9ebeSStefan Hajnoczi         virtio_pci_start_ioeventfd(proxy);
855ade80dc8SMichael S. Tsirkin     } else {
85625db9ebeSStefan Hajnoczi         virtio_pci_stop_ioeventfd(proxy);
857ade80dc8SMichael S. Tsirkin     }
858ade80dc8SMichael S. Tsirkin }
859ade80dc8SMichael S. Tsirkin 
86060653b28SPaolo Bonzini #ifdef CONFIG_VIRTFS
861fc079951SMarkus Armbruster static void virtio_9p_pci_realize(VirtIOPCIProxy *vpci_dev, Error **errp)
86260653b28SPaolo Bonzini {
863234a336fSKONRAD Frederic     V9fsPCIState *dev = VIRTIO_9P_PCI(vpci_dev);
864234a336fSKONRAD Frederic     DeviceState *vdev = DEVICE(&dev->vdev);
86560653b28SPaolo Bonzini 
866234a336fSKONRAD Frederic     qdev_set_parent_bus(vdev, BUS(&vpci_dev->bus));
867fc079951SMarkus Armbruster     object_property_set_bool(OBJECT(vdev), true, "realized", errp);
86860653b28SPaolo Bonzini }
86960653b28SPaolo Bonzini 
870234a336fSKONRAD Frederic static Property virtio_9p_pci_properties[] = {
871234a336fSKONRAD Frederic     DEFINE_PROP_BIT("ioeventfd", VirtIOPCIProxy, flags,
872234a336fSKONRAD Frederic                     VIRTIO_PCI_FLAG_USE_IOEVENTFD_BIT, true),
87360653b28SPaolo Bonzini     DEFINE_PROP_UINT32("vectors", VirtIOPCIProxy, nvectors, 2),
87460653b28SPaolo Bonzini     DEFINE_PROP_END_OF_LIST(),
87560653b28SPaolo Bonzini };
87660653b28SPaolo Bonzini 
877234a336fSKONRAD Frederic static void virtio_9p_pci_class_init(ObjectClass *klass, void *data)
87860653b28SPaolo Bonzini {
87960653b28SPaolo Bonzini     DeviceClass *dc = DEVICE_CLASS(klass);
880234a336fSKONRAD Frederic     PCIDeviceClass *pcidev_k = PCI_DEVICE_CLASS(klass);
881234a336fSKONRAD Frederic     VirtioPCIClass *k = VIRTIO_PCI_CLASS(klass);
88260653b28SPaolo Bonzini 
883fc079951SMarkus Armbruster     k->realize = virtio_9p_pci_realize;
884234a336fSKONRAD Frederic     pcidev_k->vendor_id = PCI_VENDOR_ID_REDHAT_QUMRANET;
885234a336fSKONRAD Frederic     pcidev_k->device_id = PCI_DEVICE_ID_VIRTIO_9P;
886234a336fSKONRAD Frederic     pcidev_k->revision = VIRTIO_PCI_ABI_VERSION;
887234a336fSKONRAD Frederic     pcidev_k->class_id = 0x2;
888125ee0edSMarcel Apfelbaum     set_bit(DEVICE_CATEGORY_STORAGE, dc->categories);
889234a336fSKONRAD Frederic     dc->props = virtio_9p_pci_properties;
89060653b28SPaolo Bonzini }
89160653b28SPaolo Bonzini 
892234a336fSKONRAD Frederic static void virtio_9p_pci_instance_init(Object *obj)
893234a336fSKONRAD Frederic {
894234a336fSKONRAD Frederic     V9fsPCIState *dev = VIRTIO_9P_PCI(obj);
895c8075cafSGonglei 
896c8075cafSGonglei     virtio_instance_init_common(obj, &dev->vdev, sizeof(dev->vdev),
897c8075cafSGonglei                                 TYPE_VIRTIO_9P);
898234a336fSKONRAD Frederic }
899234a336fSKONRAD Frederic 
900234a336fSKONRAD Frederic static const TypeInfo virtio_9p_pci_info = {
901234a336fSKONRAD Frederic     .name          = TYPE_VIRTIO_9P_PCI,
902234a336fSKONRAD Frederic     .parent        = TYPE_VIRTIO_PCI,
903234a336fSKONRAD Frederic     .instance_size = sizeof(V9fsPCIState),
904234a336fSKONRAD Frederic     .instance_init = virtio_9p_pci_instance_init,
905234a336fSKONRAD Frederic     .class_init    = virtio_9p_pci_class_init,
90660653b28SPaolo Bonzini };
907234a336fSKONRAD Frederic #endif /* CONFIG_VIRTFS */
90860653b28SPaolo Bonzini 
909085bccb7SKONRAD Frederic /*
910085bccb7SKONRAD Frederic  * virtio-pci: This is the PCIDevice which has a virtio-pci-bus.
911085bccb7SKONRAD Frederic  */
912085bccb7SKONRAD Frederic 
913e0d686bfSJason Wang static int virtio_pci_query_nvectors(DeviceState *d)
914e0d686bfSJason Wang {
915e0d686bfSJason Wang     VirtIOPCIProxy *proxy = VIRTIO_PCI(d);
916e0d686bfSJason Wang 
917e0d686bfSJason Wang     return proxy->nvectors;
918e0d686bfSJason Wang }
919e0d686bfSJason Wang 
920085bccb7SKONRAD Frederic /* This is called by virtio-bus just after the device is plugged. */
921085bccb7SKONRAD Frederic static void virtio_pci_device_plugged(DeviceState *d)
922085bccb7SKONRAD Frederic {
923085bccb7SKONRAD Frederic     VirtIOPCIProxy *proxy = VIRTIO_PCI(d);
924085bccb7SKONRAD Frederic     VirtioBusState *bus = &proxy->bus;
925085bccb7SKONRAD Frederic     uint8_t *config;
926085bccb7SKONRAD Frederic     uint32_t size;
927085bccb7SKONRAD Frederic 
928085bccb7SKONRAD Frederic     config = proxy->pci_dev.config;
929085bccb7SKONRAD Frederic     if (proxy->class_code) {
930085bccb7SKONRAD Frederic         pci_config_set_class(config, proxy->class_code);
931085bccb7SKONRAD Frederic     }
932085bccb7SKONRAD Frederic     pci_set_word(config + PCI_SUBSYSTEM_VENDOR_ID,
933085bccb7SKONRAD Frederic                  pci_get_word(config + PCI_VENDOR_ID));
934085bccb7SKONRAD Frederic     pci_set_word(config + PCI_SUBSYSTEM_ID, virtio_bus_get_vdev_id(bus));
935085bccb7SKONRAD Frederic     config[PCI_INTERRUPT_PIN] = 1;
936085bccb7SKONRAD Frederic 
937085bccb7SKONRAD Frederic     if (proxy->nvectors &&
938085bccb7SKONRAD Frederic         msix_init_exclusive_bar(&proxy->pci_dev, proxy->nvectors, 1)) {
939c7ff5482SFam Zheng         error_report("unable to init msix vectors to %" PRIu32,
940c7ff5482SFam Zheng                      proxy->nvectors);
941085bccb7SKONRAD Frederic         proxy->nvectors = 0;
942085bccb7SKONRAD Frederic     }
943085bccb7SKONRAD Frederic 
944085bccb7SKONRAD Frederic     proxy->pci_dev.config_write = virtio_write_config;
945085bccb7SKONRAD Frederic 
946085bccb7SKONRAD Frederic     size = VIRTIO_PCI_REGION_SIZE(&proxy->pci_dev)
947085bccb7SKONRAD Frederic          + virtio_bus_get_vdev_config_len(bus);
948085bccb7SKONRAD Frederic     if (size & (size - 1)) {
949085bccb7SKONRAD Frederic         size = 1 << qemu_fls(size);
950085bccb7SKONRAD Frederic     }
951085bccb7SKONRAD Frederic 
95222fc860bSPaolo Bonzini     memory_region_init_io(&proxy->bar, OBJECT(proxy), &virtio_pci_config_ops,
95322fc860bSPaolo Bonzini                           proxy, "virtio-pci", size);
954085bccb7SKONRAD Frederic     pci_register_bar(&proxy->pci_dev, 0, PCI_BASE_ADDRESS_SPACE_IO,
955085bccb7SKONRAD Frederic                      &proxy->bar);
956085bccb7SKONRAD Frederic 
957085bccb7SKONRAD Frederic     if (!kvm_has_many_ioeventfds()) {
958085bccb7SKONRAD Frederic         proxy->flags &= ~VIRTIO_PCI_FLAG_USE_IOEVENTFD;
959085bccb7SKONRAD Frederic     }
960085bccb7SKONRAD Frederic 
9610cd09c3aSCornelia Huck     virtio_add_feature(&proxy->host_features, VIRTIO_F_NOTIFY_ON_EMPTY);
9620cd09c3aSCornelia Huck     virtio_add_feature(&proxy->host_features, VIRTIO_F_BAD_FEATURE);
963085bccb7SKONRAD Frederic     proxy->host_features = virtio_bus_get_vdev_features(bus,
964085bccb7SKONRAD Frederic                                                       proxy->host_features);
965085bccb7SKONRAD Frederic }
966085bccb7SKONRAD Frederic 
96706a13073SPaolo Bonzini static void virtio_pci_device_unplugged(DeviceState *d)
96806a13073SPaolo Bonzini {
96906a13073SPaolo Bonzini     VirtIOPCIProxy *proxy = VIRTIO_PCI(d);
97006a13073SPaolo Bonzini 
97106a13073SPaolo Bonzini     virtio_pci_stop_ioeventfd(proxy);
97206a13073SPaolo Bonzini }
97306a13073SPaolo Bonzini 
974fc079951SMarkus Armbruster static void virtio_pci_realize(PCIDevice *pci_dev, Error **errp)
975085bccb7SKONRAD Frederic {
976085bccb7SKONRAD Frederic     VirtIOPCIProxy *dev = VIRTIO_PCI(pci_dev);
977085bccb7SKONRAD Frederic     VirtioPCIClass *k = VIRTIO_PCI_GET_CLASS(pci_dev);
978fc079951SMarkus Armbruster 
979ac7af112SAndreas Färber     virtio_pci_bus_new(&dev->bus, sizeof(dev->bus), dev);
980fc079951SMarkus Armbruster     if (k->realize) {
981fc079951SMarkus Armbruster         k->realize(dev, errp);
982085bccb7SKONRAD Frederic     }
983085bccb7SKONRAD Frederic }
984085bccb7SKONRAD Frederic 
985085bccb7SKONRAD Frederic static void virtio_pci_exit(PCIDevice *pci_dev)
986085bccb7SKONRAD Frederic {
9878b81bb3bSPaolo Bonzini     msix_uninit_exclusive_bar(pci_dev);
988085bccb7SKONRAD Frederic }
989085bccb7SKONRAD Frederic 
99059ccd20aSKONRAD Frederic static void virtio_pci_reset(DeviceState *qdev)
991085bccb7SKONRAD Frederic {
992085bccb7SKONRAD Frederic     VirtIOPCIProxy *proxy = VIRTIO_PCI(qdev);
993085bccb7SKONRAD Frederic     VirtioBusState *bus = VIRTIO_BUS(&proxy->bus);
994085bccb7SKONRAD Frederic     virtio_pci_stop_ioeventfd(proxy);
995085bccb7SKONRAD Frederic     virtio_bus_reset(bus);
996085bccb7SKONRAD Frederic     msix_unuse_all_vectors(&proxy->pci_dev);
997085bccb7SKONRAD Frederic }
998085bccb7SKONRAD Frederic 
99985d1277eSMing Lei static Property virtio_pci_properties[] = {
100068a27b20SMichael S. Tsirkin     DEFINE_PROP_BIT("virtio-pci-bus-master-bug-migration", VirtIOPCIProxy, flags,
100168a27b20SMichael S. Tsirkin                     VIRTIO_PCI_FLAG_BUS_MASTER_BUG_MIGRATION_BIT, false),
100285d1277eSMing Lei     DEFINE_VIRTIO_COMMON_FEATURES(VirtIOPCIProxy, host_features),
100385d1277eSMing Lei     DEFINE_PROP_END_OF_LIST(),
100485d1277eSMing Lei };
100585d1277eSMing Lei 
1006085bccb7SKONRAD Frederic static void virtio_pci_class_init(ObjectClass *klass, void *data)
1007085bccb7SKONRAD Frederic {
1008085bccb7SKONRAD Frederic     DeviceClass *dc = DEVICE_CLASS(klass);
1009085bccb7SKONRAD Frederic     PCIDeviceClass *k = PCI_DEVICE_CLASS(klass);
1010085bccb7SKONRAD Frederic 
101185d1277eSMing Lei     dc->props = virtio_pci_properties;
1012fc079951SMarkus Armbruster     k->realize = virtio_pci_realize;
1013085bccb7SKONRAD Frederic     k->exit = virtio_pci_exit;
1014085bccb7SKONRAD Frederic     k->vendor_id = PCI_VENDOR_ID_REDHAT_QUMRANET;
1015085bccb7SKONRAD Frederic     k->revision = VIRTIO_PCI_ABI_VERSION;
1016085bccb7SKONRAD Frederic     k->class_id = PCI_CLASS_OTHERS;
101759ccd20aSKONRAD Frederic     dc->reset = virtio_pci_reset;
1018085bccb7SKONRAD Frederic }
1019085bccb7SKONRAD Frederic 
1020085bccb7SKONRAD Frederic static const TypeInfo virtio_pci_info = {
1021085bccb7SKONRAD Frederic     .name          = TYPE_VIRTIO_PCI,
1022085bccb7SKONRAD Frederic     .parent        = TYPE_PCI_DEVICE,
1023085bccb7SKONRAD Frederic     .instance_size = sizeof(VirtIOPCIProxy),
1024085bccb7SKONRAD Frederic     .class_init    = virtio_pci_class_init,
1025085bccb7SKONRAD Frederic     .class_size    = sizeof(VirtioPCIClass),
1026085bccb7SKONRAD Frederic     .abstract      = true,
1027085bccb7SKONRAD Frederic };
1028085bccb7SKONRAD Frederic 
1029653ced07SKONRAD Frederic /* virtio-blk-pci */
1030653ced07SKONRAD Frederic 
1031653ced07SKONRAD Frederic static Property virtio_blk_pci_properties[] = {
1032c7bcc85dSPaolo Bonzini     DEFINE_PROP_UINT32("class", VirtIOPCIProxy, class_code, 0),
1033653ced07SKONRAD Frederic     DEFINE_PROP_BIT("ioeventfd", VirtIOPCIProxy, flags,
1034653ced07SKONRAD Frederic                     VIRTIO_PCI_FLAG_USE_IOEVENTFD_BIT, true),
1035653ced07SKONRAD Frederic     DEFINE_PROP_UINT32("vectors", VirtIOPCIProxy, nvectors, 2),
1036653ced07SKONRAD Frederic     DEFINE_PROP_END_OF_LIST(),
1037653ced07SKONRAD Frederic };
1038653ced07SKONRAD Frederic 
1039fc079951SMarkus Armbruster static void virtio_blk_pci_realize(VirtIOPCIProxy *vpci_dev, Error **errp)
1040653ced07SKONRAD Frederic {
1041653ced07SKONRAD Frederic     VirtIOBlkPCI *dev = VIRTIO_BLK_PCI(vpci_dev);
1042653ced07SKONRAD Frederic     DeviceState *vdev = DEVICE(&dev->vdev);
1043fc079951SMarkus Armbruster 
1044653ced07SKONRAD Frederic     qdev_set_parent_bus(vdev, BUS(&vpci_dev->bus));
1045fc079951SMarkus Armbruster     object_property_set_bool(OBJECT(vdev), true, "realized", errp);
1046653ced07SKONRAD Frederic }
1047653ced07SKONRAD Frederic 
1048653ced07SKONRAD Frederic static void virtio_blk_pci_class_init(ObjectClass *klass, void *data)
1049653ced07SKONRAD Frederic {
1050653ced07SKONRAD Frederic     DeviceClass *dc = DEVICE_CLASS(klass);
1051653ced07SKONRAD Frederic     VirtioPCIClass *k = VIRTIO_PCI_CLASS(klass);
1052653ced07SKONRAD Frederic     PCIDeviceClass *pcidev_k = PCI_DEVICE_CLASS(klass);
1053653ced07SKONRAD Frederic 
1054125ee0edSMarcel Apfelbaum     set_bit(DEVICE_CATEGORY_STORAGE, dc->categories);
1055653ced07SKONRAD Frederic     dc->props = virtio_blk_pci_properties;
1056fc079951SMarkus Armbruster     k->realize = virtio_blk_pci_realize;
1057653ced07SKONRAD Frederic     pcidev_k->vendor_id = PCI_VENDOR_ID_REDHAT_QUMRANET;
1058653ced07SKONRAD Frederic     pcidev_k->device_id = PCI_DEVICE_ID_VIRTIO_BLOCK;
1059653ced07SKONRAD Frederic     pcidev_k->revision = VIRTIO_PCI_ABI_VERSION;
1060653ced07SKONRAD Frederic     pcidev_k->class_id = PCI_CLASS_STORAGE_SCSI;
1061653ced07SKONRAD Frederic }
1062653ced07SKONRAD Frederic 
1063653ced07SKONRAD Frederic static void virtio_blk_pci_instance_init(Object *obj)
1064653ced07SKONRAD Frederic {
1065653ced07SKONRAD Frederic     VirtIOBlkPCI *dev = VIRTIO_BLK_PCI(obj);
1066c8075cafSGonglei 
1067c8075cafSGonglei     virtio_instance_init_common(obj, &dev->vdev, sizeof(dev->vdev),
1068c8075cafSGonglei                                 TYPE_VIRTIO_BLK);
1069467b3f33SStefan Hajnoczi     object_property_add_alias(obj, "iothread", OBJECT(&dev->vdev),"iothread",
1070467b3f33SStefan Hajnoczi                               &error_abort);
1071aeb98ddcSGonglei     object_property_add_alias(obj, "bootindex", OBJECT(&dev->vdev),
1072aeb98ddcSGonglei                               "bootindex", &error_abort);
1073653ced07SKONRAD Frederic }
1074653ced07SKONRAD Frederic 
1075653ced07SKONRAD Frederic static const TypeInfo virtio_blk_pci_info = {
1076653ced07SKONRAD Frederic     .name          = TYPE_VIRTIO_BLK_PCI,
1077653ced07SKONRAD Frederic     .parent        = TYPE_VIRTIO_PCI,
1078653ced07SKONRAD Frederic     .instance_size = sizeof(VirtIOBlkPCI),
1079653ced07SKONRAD Frederic     .instance_init = virtio_blk_pci_instance_init,
1080653ced07SKONRAD Frederic     .class_init    = virtio_blk_pci_class_init,
1081653ced07SKONRAD Frederic };
1082653ced07SKONRAD Frederic 
1083bc7b90a0SKONRAD Frederic /* virtio-scsi-pci */
1084bc7b90a0SKONRAD Frederic 
1085bc7b90a0SKONRAD Frederic static Property virtio_scsi_pci_properties[] = {
1086bc7b90a0SKONRAD Frederic     DEFINE_PROP_BIT("ioeventfd", VirtIOPCIProxy, flags,
1087bc7b90a0SKONRAD Frederic                     VIRTIO_PCI_FLAG_USE_IOEVENTFD_BIT, true),
1088bc7b90a0SKONRAD Frederic     DEFINE_PROP_UINT32("vectors", VirtIOPCIProxy, nvectors,
1089bc7b90a0SKONRAD Frederic                        DEV_NVECTORS_UNSPECIFIED),
1090bc7b90a0SKONRAD Frederic     DEFINE_PROP_END_OF_LIST(),
1091bc7b90a0SKONRAD Frederic };
1092bc7b90a0SKONRAD Frederic 
1093fc079951SMarkus Armbruster static void virtio_scsi_pci_realize(VirtIOPCIProxy *vpci_dev, Error **errp)
1094bc7b90a0SKONRAD Frederic {
1095bc7b90a0SKONRAD Frederic     VirtIOSCSIPCI *dev = VIRTIO_SCSI_PCI(vpci_dev);
1096bc7b90a0SKONRAD Frederic     DeviceState *vdev = DEVICE(&dev->vdev);
1097292c8e50SPaolo Bonzini     VirtIOSCSICommon *vs = VIRTIO_SCSI_COMMON(vdev);
10986f32a6b4SKONRAD Frederic     DeviceState *proxy = DEVICE(vpci_dev);
10996f32a6b4SKONRAD Frederic     char *bus_name;
1100bc7b90a0SKONRAD Frederic 
1101bc7b90a0SKONRAD Frederic     if (vpci_dev->nvectors == DEV_NVECTORS_UNSPECIFIED) {
1102292c8e50SPaolo Bonzini         vpci_dev->nvectors = vs->conf.num_queues + 3;
1103bc7b90a0SKONRAD Frederic     }
1104bc7b90a0SKONRAD Frederic 
11056f32a6b4SKONRAD Frederic     /*
11066f32a6b4SKONRAD Frederic      * For command line compatibility, this sets the virtio-scsi-device bus
11076f32a6b4SKONRAD Frederic      * name as before.
11086f32a6b4SKONRAD Frederic      */
11096f32a6b4SKONRAD Frederic     if (proxy->id) {
11106f32a6b4SKONRAD Frederic         bus_name = g_strdup_printf("%s.0", proxy->id);
11116f32a6b4SKONRAD Frederic         virtio_device_set_child_bus_name(VIRTIO_DEVICE(vdev), bus_name);
11126f32a6b4SKONRAD Frederic         g_free(bus_name);
11136f32a6b4SKONRAD Frederic     }
11146f32a6b4SKONRAD Frederic 
1115bc7b90a0SKONRAD Frederic     qdev_set_parent_bus(vdev, BUS(&vpci_dev->bus));
1116fc079951SMarkus Armbruster     object_property_set_bool(OBJECT(vdev), true, "realized", errp);
1117bc7b90a0SKONRAD Frederic }
1118bc7b90a0SKONRAD Frederic 
1119bc7b90a0SKONRAD Frederic static void virtio_scsi_pci_class_init(ObjectClass *klass, void *data)
1120bc7b90a0SKONRAD Frederic {
1121bc7b90a0SKONRAD Frederic     DeviceClass *dc = DEVICE_CLASS(klass);
1122bc7b90a0SKONRAD Frederic     VirtioPCIClass *k = VIRTIO_PCI_CLASS(klass);
1123bc7b90a0SKONRAD Frederic     PCIDeviceClass *pcidev_k = PCI_DEVICE_CLASS(klass);
1124fc079951SMarkus Armbruster 
1125fc079951SMarkus Armbruster     k->realize = virtio_scsi_pci_realize;
1126125ee0edSMarcel Apfelbaum     set_bit(DEVICE_CATEGORY_STORAGE, dc->categories);
1127bc7b90a0SKONRAD Frederic     dc->props = virtio_scsi_pci_properties;
1128bc7b90a0SKONRAD Frederic     pcidev_k->vendor_id = PCI_VENDOR_ID_REDHAT_QUMRANET;
1129bc7b90a0SKONRAD Frederic     pcidev_k->device_id = PCI_DEVICE_ID_VIRTIO_SCSI;
1130bc7b90a0SKONRAD Frederic     pcidev_k->revision = 0x00;
1131bc7b90a0SKONRAD Frederic     pcidev_k->class_id = PCI_CLASS_STORAGE_SCSI;
1132bc7b90a0SKONRAD Frederic }
1133bc7b90a0SKONRAD Frederic 
1134bc7b90a0SKONRAD Frederic static void virtio_scsi_pci_instance_init(Object *obj)
1135bc7b90a0SKONRAD Frederic {
1136bc7b90a0SKONRAD Frederic     VirtIOSCSIPCI *dev = VIRTIO_SCSI_PCI(obj);
1137c8075cafSGonglei 
1138c8075cafSGonglei     virtio_instance_init_common(obj, &dev->vdev, sizeof(dev->vdev),
1139c8075cafSGonglei                                 TYPE_VIRTIO_SCSI);
114019d339f1SFam Zheng     object_property_add_alias(obj, "iothread", OBJECT(&dev->vdev), "iothread",
114119d339f1SFam Zheng                               &error_abort);
1142bc7b90a0SKONRAD Frederic }
1143bc7b90a0SKONRAD Frederic 
1144bc7b90a0SKONRAD Frederic static const TypeInfo virtio_scsi_pci_info = {
1145bc7b90a0SKONRAD Frederic     .name          = TYPE_VIRTIO_SCSI_PCI,
1146bc7b90a0SKONRAD Frederic     .parent        = TYPE_VIRTIO_PCI,
1147bc7b90a0SKONRAD Frederic     .instance_size = sizeof(VirtIOSCSIPCI),
1148bc7b90a0SKONRAD Frederic     .instance_init = virtio_scsi_pci_instance_init,
1149bc7b90a0SKONRAD Frederic     .class_init    = virtio_scsi_pci_class_init,
1150bc7b90a0SKONRAD Frederic };
1151bc7b90a0SKONRAD Frederic 
115250787628SNicholas Bellinger /* vhost-scsi-pci */
115350787628SNicholas Bellinger 
115450787628SNicholas Bellinger #ifdef CONFIG_VHOST_SCSI
115550787628SNicholas Bellinger static Property vhost_scsi_pci_properties[] = {
115650787628SNicholas Bellinger     DEFINE_PROP_UINT32("vectors", VirtIOPCIProxy, nvectors,
115750787628SNicholas Bellinger                        DEV_NVECTORS_UNSPECIFIED),
115850787628SNicholas Bellinger     DEFINE_PROP_END_OF_LIST(),
115950787628SNicholas Bellinger };
116050787628SNicholas Bellinger 
1161fc079951SMarkus Armbruster static void vhost_scsi_pci_realize(VirtIOPCIProxy *vpci_dev, Error **errp)
116250787628SNicholas Bellinger {
116350787628SNicholas Bellinger     VHostSCSIPCI *dev = VHOST_SCSI_PCI(vpci_dev);
116450787628SNicholas Bellinger     DeviceState *vdev = DEVICE(&dev->vdev);
116550787628SNicholas Bellinger     VirtIOSCSICommon *vs = VIRTIO_SCSI_COMMON(vdev);
116650787628SNicholas Bellinger 
116750787628SNicholas Bellinger     if (vpci_dev->nvectors == DEV_NVECTORS_UNSPECIFIED) {
116850787628SNicholas Bellinger         vpci_dev->nvectors = vs->conf.num_queues + 3;
116950787628SNicholas Bellinger     }
117050787628SNicholas Bellinger 
117150787628SNicholas Bellinger     qdev_set_parent_bus(vdev, BUS(&vpci_dev->bus));
1172fc079951SMarkus Armbruster     object_property_set_bool(OBJECT(vdev), true, "realized", errp);
117350787628SNicholas Bellinger }
117450787628SNicholas Bellinger 
117550787628SNicholas Bellinger static void vhost_scsi_pci_class_init(ObjectClass *klass, void *data)
117650787628SNicholas Bellinger {
117750787628SNicholas Bellinger     DeviceClass *dc = DEVICE_CLASS(klass);
117850787628SNicholas Bellinger     VirtioPCIClass *k = VIRTIO_PCI_CLASS(klass);
117950787628SNicholas Bellinger     PCIDeviceClass *pcidev_k = PCI_DEVICE_CLASS(klass);
1180fc079951SMarkus Armbruster     k->realize = vhost_scsi_pci_realize;
1181125ee0edSMarcel Apfelbaum     set_bit(DEVICE_CATEGORY_STORAGE, dc->categories);
118250787628SNicholas Bellinger     dc->props = vhost_scsi_pci_properties;
118350787628SNicholas Bellinger     pcidev_k->vendor_id = PCI_VENDOR_ID_REDHAT_QUMRANET;
118450787628SNicholas Bellinger     pcidev_k->device_id = PCI_DEVICE_ID_VIRTIO_SCSI;
118550787628SNicholas Bellinger     pcidev_k->revision = 0x00;
118650787628SNicholas Bellinger     pcidev_k->class_id = PCI_CLASS_STORAGE_SCSI;
118750787628SNicholas Bellinger }
118850787628SNicholas Bellinger 
118950787628SNicholas Bellinger static void vhost_scsi_pci_instance_init(Object *obj)
119050787628SNicholas Bellinger {
119150787628SNicholas Bellinger     VHostSCSIPCI *dev = VHOST_SCSI_PCI(obj);
1192c8075cafSGonglei 
1193c8075cafSGonglei     virtio_instance_init_common(obj, &dev->vdev, sizeof(dev->vdev),
1194c8075cafSGonglei                                 TYPE_VHOST_SCSI);
1195d4433f32SGonglei     object_property_add_alias(obj, "bootindex", OBJECT(&dev->vdev),
1196d4433f32SGonglei                               "bootindex", &error_abort);
119750787628SNicholas Bellinger }
119850787628SNicholas Bellinger 
119950787628SNicholas Bellinger static const TypeInfo vhost_scsi_pci_info = {
120050787628SNicholas Bellinger     .name          = TYPE_VHOST_SCSI_PCI,
120150787628SNicholas Bellinger     .parent        = TYPE_VIRTIO_PCI,
120250787628SNicholas Bellinger     .instance_size = sizeof(VHostSCSIPCI),
120350787628SNicholas Bellinger     .instance_init = vhost_scsi_pci_instance_init,
120450787628SNicholas Bellinger     .class_init    = vhost_scsi_pci_class_init,
120550787628SNicholas Bellinger };
120650787628SNicholas Bellinger #endif
120750787628SNicholas Bellinger 
1208e378e88dSKONRAD Frederic /* virtio-balloon-pci */
1209e378e88dSKONRAD Frederic 
1210e378e88dSKONRAD Frederic static Property virtio_balloon_pci_properties[] = {
1211c7bcc85dSPaolo Bonzini     DEFINE_PROP_UINT32("class", VirtIOPCIProxy, class_code, 0),
1212e378e88dSKONRAD Frederic     DEFINE_PROP_END_OF_LIST(),
1213e378e88dSKONRAD Frederic };
1214e378e88dSKONRAD Frederic 
1215fc079951SMarkus Armbruster static void virtio_balloon_pci_realize(VirtIOPCIProxy *vpci_dev, Error **errp)
1216e378e88dSKONRAD Frederic {
1217e378e88dSKONRAD Frederic     VirtIOBalloonPCI *dev = VIRTIO_BALLOON_PCI(vpci_dev);
1218e378e88dSKONRAD Frederic     DeviceState *vdev = DEVICE(&dev->vdev);
1219e378e88dSKONRAD Frederic 
1220e378e88dSKONRAD Frederic     if (vpci_dev->class_code != PCI_CLASS_OTHERS &&
1221e378e88dSKONRAD Frederic         vpci_dev->class_code != PCI_CLASS_MEMORY_RAM) { /* qemu < 1.1 */
1222e378e88dSKONRAD Frederic         vpci_dev->class_code = PCI_CLASS_OTHERS;
1223e378e88dSKONRAD Frederic     }
1224e378e88dSKONRAD Frederic 
1225e378e88dSKONRAD Frederic     qdev_set_parent_bus(vdev, BUS(&vpci_dev->bus));
1226fc079951SMarkus Armbruster     object_property_set_bool(OBJECT(vdev), true, "realized", errp);
1227e378e88dSKONRAD Frederic }
1228e378e88dSKONRAD Frederic 
1229e378e88dSKONRAD Frederic static void virtio_balloon_pci_class_init(ObjectClass *klass, void *data)
1230e378e88dSKONRAD Frederic {
1231e378e88dSKONRAD Frederic     DeviceClass *dc = DEVICE_CLASS(klass);
1232e378e88dSKONRAD Frederic     VirtioPCIClass *k = VIRTIO_PCI_CLASS(klass);
1233e378e88dSKONRAD Frederic     PCIDeviceClass *pcidev_k = PCI_DEVICE_CLASS(klass);
1234fc079951SMarkus Armbruster     k->realize = virtio_balloon_pci_realize;
1235125ee0edSMarcel Apfelbaum     set_bit(DEVICE_CATEGORY_MISC, dc->categories);
1236e378e88dSKONRAD Frederic     dc->props = virtio_balloon_pci_properties;
1237e378e88dSKONRAD Frederic     pcidev_k->vendor_id = PCI_VENDOR_ID_REDHAT_QUMRANET;
1238e378e88dSKONRAD Frederic     pcidev_k->device_id = PCI_DEVICE_ID_VIRTIO_BALLOON;
1239e378e88dSKONRAD Frederic     pcidev_k->revision = VIRTIO_PCI_ABI_VERSION;
1240e378e88dSKONRAD Frederic     pcidev_k->class_id = PCI_CLASS_OTHERS;
1241e378e88dSKONRAD Frederic }
1242e378e88dSKONRAD Frederic 
1243e378e88dSKONRAD Frederic static void virtio_balloon_pci_instance_init(Object *obj)
1244e378e88dSKONRAD Frederic {
1245e378e88dSKONRAD Frederic     VirtIOBalloonPCI *dev = VIRTIO_BALLOON_PCI(obj);
1246*39b87c7bSShannon Zhao 
1247a6027b0fSDenis V. Lunev     virtio_instance_init_common(obj, &dev->vdev, sizeof(dev->vdev),
1248a6027b0fSDenis V. Lunev                                 TYPE_VIRTIO_BALLOON);
1249*39b87c7bSShannon Zhao     object_property_add_alias(obj, "guest-stats", OBJECT(&dev->vdev),
1250*39b87c7bSShannon Zhao                                   "guest-stats", &error_abort);
1251*39b87c7bSShannon Zhao     object_property_add_alias(obj, "guest-stats-polling-interval",
1252*39b87c7bSShannon Zhao                               OBJECT(&dev->vdev),
1253*39b87c7bSShannon Zhao                               "guest-stats-polling-interval", &error_abort);
1254e378e88dSKONRAD Frederic }
1255e378e88dSKONRAD Frederic 
1256e378e88dSKONRAD Frederic static const TypeInfo virtio_balloon_pci_info = {
1257e378e88dSKONRAD Frederic     .name          = TYPE_VIRTIO_BALLOON_PCI,
1258e378e88dSKONRAD Frederic     .parent        = TYPE_VIRTIO_PCI,
1259e378e88dSKONRAD Frederic     .instance_size = sizeof(VirtIOBalloonPCI),
1260e378e88dSKONRAD Frederic     .instance_init = virtio_balloon_pci_instance_init,
1261e378e88dSKONRAD Frederic     .class_init    = virtio_balloon_pci_class_init,
1262e378e88dSKONRAD Frederic };
1263e378e88dSKONRAD Frederic 
1264f7f7464aSKONRAD Frederic /* virtio-serial-pci */
1265f7f7464aSKONRAD Frederic 
1266fc079951SMarkus Armbruster static void virtio_serial_pci_realize(VirtIOPCIProxy *vpci_dev, Error **errp)
1267f7f7464aSKONRAD Frederic {
1268f7f7464aSKONRAD Frederic     VirtIOSerialPCI *dev = VIRTIO_SERIAL_PCI(vpci_dev);
1269f7f7464aSKONRAD Frederic     DeviceState *vdev = DEVICE(&dev->vdev);
127080270a19SKONRAD Frederic     DeviceState *proxy = DEVICE(vpci_dev);
127180270a19SKONRAD Frederic     char *bus_name;
1272f7f7464aSKONRAD Frederic 
1273f7f7464aSKONRAD Frederic     if (vpci_dev->class_code != PCI_CLASS_COMMUNICATION_OTHER &&
1274f7f7464aSKONRAD Frederic         vpci_dev->class_code != PCI_CLASS_DISPLAY_OTHER && /* qemu 0.10 */
1275f7f7464aSKONRAD Frederic         vpci_dev->class_code != PCI_CLASS_OTHERS) {        /* qemu-kvm  */
1276f7f7464aSKONRAD Frederic             vpci_dev->class_code = PCI_CLASS_COMMUNICATION_OTHER;
1277f7f7464aSKONRAD Frederic     }
1278f7f7464aSKONRAD Frederic 
1279f7f7464aSKONRAD Frederic     /* backwards-compatibility with machines that were created with
1280f7f7464aSKONRAD Frederic        DEV_NVECTORS_UNSPECIFIED */
1281f7f7464aSKONRAD Frederic     if (vpci_dev->nvectors == DEV_NVECTORS_UNSPECIFIED) {
1282f7f7464aSKONRAD Frederic         vpci_dev->nvectors = dev->vdev.serial.max_virtserial_ports + 1;
1283f7f7464aSKONRAD Frederic     }
1284f7f7464aSKONRAD Frederic 
128580270a19SKONRAD Frederic     /*
128680270a19SKONRAD Frederic      * For command line compatibility, this sets the virtio-serial-device bus
128780270a19SKONRAD Frederic      * name as before.
128880270a19SKONRAD Frederic      */
128980270a19SKONRAD Frederic     if (proxy->id) {
129080270a19SKONRAD Frederic         bus_name = g_strdup_printf("%s.0", proxy->id);
129180270a19SKONRAD Frederic         virtio_device_set_child_bus_name(VIRTIO_DEVICE(vdev), bus_name);
129280270a19SKONRAD Frederic         g_free(bus_name);
129380270a19SKONRAD Frederic     }
129480270a19SKONRAD Frederic 
1295f7f7464aSKONRAD Frederic     qdev_set_parent_bus(vdev, BUS(&vpci_dev->bus));
1296fc079951SMarkus Armbruster     object_property_set_bool(OBJECT(vdev), true, "realized", errp);
1297f7f7464aSKONRAD Frederic }
1298f7f7464aSKONRAD Frederic 
1299f7f7464aSKONRAD Frederic static Property virtio_serial_pci_properties[] = {
1300f7f7464aSKONRAD Frederic     DEFINE_PROP_BIT("ioeventfd", VirtIOPCIProxy, flags,
1301f7f7464aSKONRAD Frederic                     VIRTIO_PCI_FLAG_USE_IOEVENTFD_BIT, true),
1302f7f7464aSKONRAD Frederic     DEFINE_PROP_UINT32("vectors", VirtIOPCIProxy, nvectors, 2),
1303c7bcc85dSPaolo Bonzini     DEFINE_PROP_UINT32("class", VirtIOPCIProxy, class_code, 0),
1304f7f7464aSKONRAD Frederic     DEFINE_PROP_END_OF_LIST(),
1305f7f7464aSKONRAD Frederic };
1306f7f7464aSKONRAD Frederic 
1307f7f7464aSKONRAD Frederic static void virtio_serial_pci_class_init(ObjectClass *klass, void *data)
1308f7f7464aSKONRAD Frederic {
1309f7f7464aSKONRAD Frederic     DeviceClass *dc = DEVICE_CLASS(klass);
1310f7f7464aSKONRAD Frederic     VirtioPCIClass *k = VIRTIO_PCI_CLASS(klass);
1311f7f7464aSKONRAD Frederic     PCIDeviceClass *pcidev_k = PCI_DEVICE_CLASS(klass);
1312fc079951SMarkus Armbruster     k->realize = virtio_serial_pci_realize;
1313125ee0edSMarcel Apfelbaum     set_bit(DEVICE_CATEGORY_INPUT, dc->categories);
1314f7f7464aSKONRAD Frederic     dc->props = virtio_serial_pci_properties;
1315f7f7464aSKONRAD Frederic     pcidev_k->vendor_id = PCI_VENDOR_ID_REDHAT_QUMRANET;
1316f7f7464aSKONRAD Frederic     pcidev_k->device_id = PCI_DEVICE_ID_VIRTIO_CONSOLE;
1317f7f7464aSKONRAD Frederic     pcidev_k->revision = VIRTIO_PCI_ABI_VERSION;
1318f7f7464aSKONRAD Frederic     pcidev_k->class_id = PCI_CLASS_COMMUNICATION_OTHER;
1319f7f7464aSKONRAD Frederic }
1320f7f7464aSKONRAD Frederic 
1321f7f7464aSKONRAD Frederic static void virtio_serial_pci_instance_init(Object *obj)
1322f7f7464aSKONRAD Frederic {
1323f7f7464aSKONRAD Frederic     VirtIOSerialPCI *dev = VIRTIO_SERIAL_PCI(obj);
1324c8075cafSGonglei 
1325c8075cafSGonglei     virtio_instance_init_common(obj, &dev->vdev, sizeof(dev->vdev),
1326c8075cafSGonglei                                 TYPE_VIRTIO_SERIAL);
1327f7f7464aSKONRAD Frederic }
1328f7f7464aSKONRAD Frederic 
1329f7f7464aSKONRAD Frederic static const TypeInfo virtio_serial_pci_info = {
1330f7f7464aSKONRAD Frederic     .name          = TYPE_VIRTIO_SERIAL_PCI,
1331f7f7464aSKONRAD Frederic     .parent        = TYPE_VIRTIO_PCI,
1332f7f7464aSKONRAD Frederic     .instance_size = sizeof(VirtIOSerialPCI),
1333f7f7464aSKONRAD Frederic     .instance_init = virtio_serial_pci_instance_init,
1334f7f7464aSKONRAD Frederic     .class_init    = virtio_serial_pci_class_init,
1335f7f7464aSKONRAD Frederic };
1336f7f7464aSKONRAD Frederic 
1337e37da394SKONRAD Frederic /* virtio-net-pci */
1338e37da394SKONRAD Frederic 
1339e37da394SKONRAD Frederic static Property virtio_net_properties[] = {
1340e37da394SKONRAD Frederic     DEFINE_PROP_BIT("ioeventfd", VirtIOPCIProxy, flags,
1341e37da394SKONRAD Frederic                     VIRTIO_PCI_FLAG_USE_IOEVENTFD_BIT, false),
1342e37da394SKONRAD Frederic     DEFINE_PROP_UINT32("vectors", VirtIOPCIProxy, nvectors, 3),
1343e37da394SKONRAD Frederic     DEFINE_PROP_END_OF_LIST(),
1344e37da394SKONRAD Frederic };
1345e37da394SKONRAD Frederic 
1346fc079951SMarkus Armbruster static void virtio_net_pci_realize(VirtIOPCIProxy *vpci_dev, Error **errp)
1347e37da394SKONRAD Frederic {
1348800ced8cSKONRAD Frederic     DeviceState *qdev = DEVICE(vpci_dev);
1349e37da394SKONRAD Frederic     VirtIONetPCI *dev = VIRTIO_NET_PCI(vpci_dev);
1350e37da394SKONRAD Frederic     DeviceState *vdev = DEVICE(&dev->vdev);
1351e37da394SKONRAD Frederic 
1352800ced8cSKONRAD Frederic     virtio_net_set_netclient_name(&dev->vdev, qdev->id,
1353800ced8cSKONRAD Frederic                                   object_get_typename(OBJECT(qdev)));
1354e37da394SKONRAD Frederic     qdev_set_parent_bus(vdev, BUS(&vpci_dev->bus));
1355fc079951SMarkus Armbruster     object_property_set_bool(OBJECT(vdev), true, "realized", errp);
1356e37da394SKONRAD Frederic }
1357e37da394SKONRAD Frederic 
1358e37da394SKONRAD Frederic static void virtio_net_pci_class_init(ObjectClass *klass, void *data)
1359e37da394SKONRAD Frederic {
1360e37da394SKONRAD Frederic     DeviceClass *dc = DEVICE_CLASS(klass);
1361e37da394SKONRAD Frederic     PCIDeviceClass *k = PCI_DEVICE_CLASS(klass);
1362e37da394SKONRAD Frederic     VirtioPCIClass *vpciklass = VIRTIO_PCI_CLASS(klass);
1363e37da394SKONRAD Frederic 
1364e37da394SKONRAD Frederic     k->romfile = "efi-virtio.rom";
1365e37da394SKONRAD Frederic     k->vendor_id = PCI_VENDOR_ID_REDHAT_QUMRANET;
1366e37da394SKONRAD Frederic     k->device_id = PCI_DEVICE_ID_VIRTIO_NET;
1367e37da394SKONRAD Frederic     k->revision = VIRTIO_PCI_ABI_VERSION;
1368e37da394SKONRAD Frederic     k->class_id = PCI_CLASS_NETWORK_ETHERNET;
1369125ee0edSMarcel Apfelbaum     set_bit(DEVICE_CATEGORY_NETWORK, dc->categories);
1370e37da394SKONRAD Frederic     dc->props = virtio_net_properties;
1371fc079951SMarkus Armbruster     vpciklass->realize = virtio_net_pci_realize;
1372e37da394SKONRAD Frederic }
1373e37da394SKONRAD Frederic 
1374e37da394SKONRAD Frederic static void virtio_net_pci_instance_init(Object *obj)
1375e37da394SKONRAD Frederic {
1376e37da394SKONRAD Frederic     VirtIONetPCI *dev = VIRTIO_NET_PCI(obj);
1377c8075cafSGonglei 
1378c8075cafSGonglei     virtio_instance_init_common(obj, &dev->vdev, sizeof(dev->vdev),
1379c8075cafSGonglei                                 TYPE_VIRTIO_NET);
13800cf63c3eSGonglei     object_property_add_alias(obj, "bootindex", OBJECT(&dev->vdev),
13810cf63c3eSGonglei                               "bootindex", &error_abort);
1382e37da394SKONRAD Frederic }
1383e37da394SKONRAD Frederic 
1384e37da394SKONRAD Frederic static const TypeInfo virtio_net_pci_info = {
1385e37da394SKONRAD Frederic     .name          = TYPE_VIRTIO_NET_PCI,
1386e37da394SKONRAD Frederic     .parent        = TYPE_VIRTIO_PCI,
1387e37da394SKONRAD Frederic     .instance_size = sizeof(VirtIONetPCI),
1388e37da394SKONRAD Frederic     .instance_init = virtio_net_pci_instance_init,
1389e37da394SKONRAD Frederic     .class_init    = virtio_net_pci_class_init,
1390e37da394SKONRAD Frederic };
1391e37da394SKONRAD Frederic 
139259ccd20aSKONRAD Frederic /* virtio-rng-pci */
139359ccd20aSKONRAD Frederic 
139459ccd20aSKONRAD Frederic static Property virtio_rng_pci_properties[] = {
139559ccd20aSKONRAD Frederic     DEFINE_PROP_END_OF_LIST(),
139659ccd20aSKONRAD Frederic };
139759ccd20aSKONRAD Frederic 
1398fc079951SMarkus Armbruster static void virtio_rng_pci_realize(VirtIOPCIProxy *vpci_dev, Error **errp)
139959ccd20aSKONRAD Frederic {
140059ccd20aSKONRAD Frederic     VirtIORngPCI *vrng = VIRTIO_RNG_PCI(vpci_dev);
140159ccd20aSKONRAD Frederic     DeviceState *vdev = DEVICE(&vrng->vdev);
1402fc079951SMarkus Armbruster     Error *err = NULL;
140359ccd20aSKONRAD Frederic 
140459ccd20aSKONRAD Frederic     qdev_set_parent_bus(vdev, BUS(&vpci_dev->bus));
1405fc079951SMarkus Armbruster     object_property_set_bool(OBJECT(vdev), true, "realized", &err);
1406fc079951SMarkus Armbruster     if (err) {
1407fc079951SMarkus Armbruster         error_propagate(errp, err);
1408fc079951SMarkus Armbruster         return;
140959ccd20aSKONRAD Frederic     }
141059ccd20aSKONRAD Frederic 
141159ccd20aSKONRAD Frederic     object_property_set_link(OBJECT(vrng),
14125b456438SCole Robinson                              OBJECT(vrng->vdev.conf.rng), "rng",
141359ccd20aSKONRAD Frederic                              NULL);
141459ccd20aSKONRAD Frederic }
141559ccd20aSKONRAD Frederic 
141659ccd20aSKONRAD Frederic static void virtio_rng_pci_class_init(ObjectClass *klass, void *data)
141759ccd20aSKONRAD Frederic {
141859ccd20aSKONRAD Frederic     DeviceClass *dc = DEVICE_CLASS(klass);
141959ccd20aSKONRAD Frederic     VirtioPCIClass *k = VIRTIO_PCI_CLASS(klass);
142059ccd20aSKONRAD Frederic     PCIDeviceClass *pcidev_k = PCI_DEVICE_CLASS(klass);
142159ccd20aSKONRAD Frederic 
1422fc079951SMarkus Armbruster     k->realize = virtio_rng_pci_realize;
1423125ee0edSMarcel Apfelbaum     set_bit(DEVICE_CATEGORY_MISC, dc->categories);
142459ccd20aSKONRAD Frederic     dc->props = virtio_rng_pci_properties;
142559ccd20aSKONRAD Frederic 
142659ccd20aSKONRAD Frederic     pcidev_k->vendor_id = PCI_VENDOR_ID_REDHAT_QUMRANET;
142759ccd20aSKONRAD Frederic     pcidev_k->device_id = PCI_DEVICE_ID_VIRTIO_RNG;
142859ccd20aSKONRAD Frederic     pcidev_k->revision = VIRTIO_PCI_ABI_VERSION;
142959ccd20aSKONRAD Frederic     pcidev_k->class_id = PCI_CLASS_OTHERS;
143059ccd20aSKONRAD Frederic }
143159ccd20aSKONRAD Frederic 
143259ccd20aSKONRAD Frederic static void virtio_rng_initfn(Object *obj)
143359ccd20aSKONRAD Frederic {
143459ccd20aSKONRAD Frederic     VirtIORngPCI *dev = VIRTIO_RNG_PCI(obj);
1435c8075cafSGonglei 
1436c8075cafSGonglei     virtio_instance_init_common(obj, &dev->vdev, sizeof(dev->vdev),
1437c8075cafSGonglei                                 TYPE_VIRTIO_RNG);
1438cbd5ac69SPaolo Bonzini     object_property_add_alias(obj, "rng", OBJECT(&dev->vdev), "rng",
1439cbd5ac69SPaolo Bonzini                               &error_abort);
144059ccd20aSKONRAD Frederic }
144159ccd20aSKONRAD Frederic 
144259ccd20aSKONRAD Frederic static const TypeInfo virtio_rng_pci_info = {
144359ccd20aSKONRAD Frederic     .name          = TYPE_VIRTIO_RNG_PCI,
144459ccd20aSKONRAD Frederic     .parent        = TYPE_VIRTIO_PCI,
144559ccd20aSKONRAD Frederic     .instance_size = sizeof(VirtIORngPCI),
144659ccd20aSKONRAD Frederic     .instance_init = virtio_rng_initfn,
144759ccd20aSKONRAD Frederic     .class_init    = virtio_rng_pci_class_init,
144859ccd20aSKONRAD Frederic };
144959ccd20aSKONRAD Frederic 
14500a2acf5eSKONRAD Frederic /* virtio-pci-bus */
14510a2acf5eSKONRAD Frederic 
1452ac7af112SAndreas Färber static void virtio_pci_bus_new(VirtioBusState *bus, size_t bus_size,
1453ac7af112SAndreas Färber                                VirtIOPCIProxy *dev)
14540a2acf5eSKONRAD Frederic {
14550a2acf5eSKONRAD Frederic     DeviceState *qdev = DEVICE(dev);
1456f4dd69aaSKONRAD Frederic     char virtio_bus_name[] = "virtio-bus";
1457f4dd69aaSKONRAD Frederic 
1458fb17dfe0SAndreas Färber     qbus_create_inplace(bus, bus_size, TYPE_VIRTIO_PCI_BUS, qdev,
1459f4dd69aaSKONRAD Frederic                         virtio_bus_name);
14600a2acf5eSKONRAD Frederic }
14610a2acf5eSKONRAD Frederic 
14620a2acf5eSKONRAD Frederic static void virtio_pci_bus_class_init(ObjectClass *klass, void *data)
14630a2acf5eSKONRAD Frederic {
14640a2acf5eSKONRAD Frederic     BusClass *bus_class = BUS_CLASS(klass);
14650a2acf5eSKONRAD Frederic     VirtioBusClass *k = VIRTIO_BUS_CLASS(klass);
14660a2acf5eSKONRAD Frederic     bus_class->max_dev = 1;
14670a2acf5eSKONRAD Frederic     k->notify = virtio_pci_notify;
14680a2acf5eSKONRAD Frederic     k->save_config = virtio_pci_save_config;
14690a2acf5eSKONRAD Frederic     k->load_config = virtio_pci_load_config;
14700a2acf5eSKONRAD Frederic     k->save_queue = virtio_pci_save_queue;
14710a2acf5eSKONRAD Frederic     k->load_queue = virtio_pci_load_queue;
14720a2acf5eSKONRAD Frederic     k->get_features = virtio_pci_get_features;
14730a2acf5eSKONRAD Frederic     k->query_guest_notifiers = virtio_pci_query_guest_notifiers;
14740a2acf5eSKONRAD Frederic     k->set_host_notifier = virtio_pci_set_host_notifier;
14750a2acf5eSKONRAD Frederic     k->set_guest_notifiers = virtio_pci_set_guest_notifiers;
14760a2acf5eSKONRAD Frederic     k->vmstate_change = virtio_pci_vmstate_change;
1477085bccb7SKONRAD Frederic     k->device_plugged = virtio_pci_device_plugged;
147806a13073SPaolo Bonzini     k->device_unplugged = virtio_pci_device_unplugged;
1479e0d686bfSJason Wang     k->query_nvectors = virtio_pci_query_nvectors;
14800a2acf5eSKONRAD Frederic }
14810a2acf5eSKONRAD Frederic 
14820a2acf5eSKONRAD Frederic static const TypeInfo virtio_pci_bus_info = {
14830a2acf5eSKONRAD Frederic     .name          = TYPE_VIRTIO_PCI_BUS,
14840a2acf5eSKONRAD Frederic     .parent        = TYPE_VIRTIO_BUS,
14850a2acf5eSKONRAD Frederic     .instance_size = sizeof(VirtioPCIBusState),
14860a2acf5eSKONRAD Frederic     .class_init    = virtio_pci_bus_class_init,
14870a2acf5eSKONRAD Frederic };
14880a2acf5eSKONRAD Frederic 
148983f7d43aSAndreas Färber static void virtio_pci_register_types(void)
149053c25ceaSPaul Brook {
149159ccd20aSKONRAD Frederic     type_register_static(&virtio_rng_pci_info);
14920a2acf5eSKONRAD Frederic     type_register_static(&virtio_pci_bus_info);
1493085bccb7SKONRAD Frederic     type_register_static(&virtio_pci_info);
149460653b28SPaolo Bonzini #ifdef CONFIG_VIRTFS
1495234a336fSKONRAD Frederic     type_register_static(&virtio_9p_pci_info);
149660653b28SPaolo Bonzini #endif
1497653ced07SKONRAD Frederic     type_register_static(&virtio_blk_pci_info);
1498bc7b90a0SKONRAD Frederic     type_register_static(&virtio_scsi_pci_info);
1499e378e88dSKONRAD Frederic     type_register_static(&virtio_balloon_pci_info);
1500f7f7464aSKONRAD Frederic     type_register_static(&virtio_serial_pci_info);
1501e37da394SKONRAD Frederic     type_register_static(&virtio_net_pci_info);
150250787628SNicholas Bellinger #ifdef CONFIG_VHOST_SCSI
150350787628SNicholas Bellinger     type_register_static(&vhost_scsi_pci_info);
150450787628SNicholas Bellinger #endif
150553c25ceaSPaul Brook }
150653c25ceaSPaul Brook 
150783f7d43aSAndreas Färber type_init(virtio_pci_register_types)
1508