xref: /qemu/hw/virtio/virtio-pci.c (revision 1141ce2190c85daacfa9b874476651ed0f7dc6df)
153c25ceaSPaul Brook /*
253c25ceaSPaul Brook  * Virtio PCI Bindings
353c25ceaSPaul Brook  *
453c25ceaSPaul Brook  * Copyright IBM, Corp. 2007
553c25ceaSPaul Brook  * Copyright (c) 2009 CodeSourcery
653c25ceaSPaul Brook  *
753c25ceaSPaul Brook  * Authors:
853c25ceaSPaul Brook  *  Anthony Liguori   <aliguori@us.ibm.com>
953c25ceaSPaul Brook  *  Paul Brook        <paul@codesourcery.com>
1053c25ceaSPaul Brook  *
1153c25ceaSPaul Brook  * This work is licensed under the terms of the GNU GPL, version 2.  See
1253c25ceaSPaul Brook  * the COPYING file in the top-level directory.
1353c25ceaSPaul Brook  *
146b620ca3SPaolo Bonzini  * Contributions after 2012-01-13 are licensed under the terms of the
156b620ca3SPaolo Bonzini  * GNU GPL, version 2 or (at your option) any later version.
1653c25ceaSPaul Brook  */
1753c25ceaSPaul Brook 
1853c25ceaSPaul Brook #include <inttypes.h>
1953c25ceaSPaul Brook 
20cbbe4f50SMichael S. Tsirkin #include "standard-headers/linux/virtio_pci.h"
210d09e41aSPaolo Bonzini #include "hw/virtio/virtio.h"
220d09e41aSPaolo Bonzini #include "hw/virtio/virtio-blk.h"
230d09e41aSPaolo Bonzini #include "hw/virtio/virtio-net.h"
240d09e41aSPaolo Bonzini #include "hw/virtio/virtio-serial.h"
250d09e41aSPaolo Bonzini #include "hw/virtio/virtio-scsi.h"
260d09e41aSPaolo Bonzini #include "hw/virtio/virtio-balloon.h"
2783c9f4caSPaolo Bonzini #include "hw/pci/pci.h"
281de7afc9SPaolo Bonzini #include "qemu/error-report.h"
2983c9f4caSPaolo Bonzini #include "hw/pci/msi.h"
3083c9f4caSPaolo Bonzini #include "hw/pci/msix.h"
3183c9f4caSPaolo Bonzini #include "hw/loader.h"
329c17d615SPaolo Bonzini #include "sysemu/kvm.h"
334be74634SMarkus Armbruster #include "sysemu/block-backend.h"
3447b43a1fSPaolo Bonzini #include "virtio-pci.h"
351de7afc9SPaolo Bonzini #include "qemu/range.h"
360d09e41aSPaolo Bonzini #include "hw/virtio/virtio-bus.h"
3724a6e7f4SKONRAD Frederic #include "qapi/visitor.h"
3853c25ceaSPaul Brook 
39cbbe4f50SMichael S. Tsirkin #define VIRTIO_PCI_REGION_SIZE(dev)     VIRTIO_PCI_CONFIG_OFF(msix_present(dev))
40aba800a3SMichael S. Tsirkin 
41c17bef33SMichael S. Tsirkin #undef VIRTIO_PCI_CONFIG
42c17bef33SMichael S. Tsirkin 
43aba800a3SMichael S. Tsirkin /* The remaining space is defined by each driver as the per-driver
44aba800a3SMichael S. Tsirkin  * configuration space */
45cbbe4f50SMichael S. Tsirkin #define VIRTIO_PCI_CONFIG_SIZE(dev)     VIRTIO_PCI_CONFIG_OFF(msix_enabled(dev))
4653c25ceaSPaul Brook 
47ac7af112SAndreas Färber static void virtio_pci_bus_new(VirtioBusState *bus, size_t bus_size,
48ac7af112SAndreas Färber                                VirtIOPCIProxy *dev);
49d51fcfacSKONRAD Frederic 
5053c25ceaSPaul Brook /* virtio device */
51d2a0ccc6SMichael S. Tsirkin /* DeviceState to VirtIOPCIProxy. For use off data-path. TODO: use QOM. */
52d2a0ccc6SMichael S. Tsirkin static inline VirtIOPCIProxy *to_virtio_pci_proxy(DeviceState *d)
5353c25ceaSPaul Brook {
54d2a0ccc6SMichael S. Tsirkin     return container_of(d, VirtIOPCIProxy, pci_dev.qdev);
55d2a0ccc6SMichael S. Tsirkin }
56d2a0ccc6SMichael S. Tsirkin 
57d2a0ccc6SMichael S. Tsirkin /* DeviceState to VirtIOPCIProxy. Note: used on datapath,
58d2a0ccc6SMichael S. Tsirkin  * be careful and test performance if you change this.
59d2a0ccc6SMichael S. Tsirkin  */
60d2a0ccc6SMichael S. Tsirkin static inline VirtIOPCIProxy *to_virtio_pci_proxy_fast(DeviceState *d)
61d2a0ccc6SMichael S. Tsirkin {
62d2a0ccc6SMichael S. Tsirkin     return container_of(d, VirtIOPCIProxy, pci_dev.qdev);
63d2a0ccc6SMichael S. Tsirkin }
64d2a0ccc6SMichael S. Tsirkin 
65d2a0ccc6SMichael S. Tsirkin static void virtio_pci_notify(DeviceState *d, uint16_t vector)
66d2a0ccc6SMichael S. Tsirkin {
67d2a0ccc6SMichael S. Tsirkin     VirtIOPCIProxy *proxy = to_virtio_pci_proxy_fast(d);
68a3fc66d9SPaolo Bonzini 
69aba800a3SMichael S. Tsirkin     if (msix_enabled(&proxy->pci_dev))
70aba800a3SMichael S. Tsirkin         msix_notify(&proxy->pci_dev, vector);
71a3fc66d9SPaolo Bonzini     else {
72a3fc66d9SPaolo Bonzini         VirtIODevice *vdev = virtio_bus_get_device(&proxy->bus);
73a3fc66d9SPaolo Bonzini         pci_set_irq(&proxy->pci_dev, vdev->isr & 1);
74a3fc66d9SPaolo Bonzini     }
7553c25ceaSPaul Brook }
7653c25ceaSPaul Brook 
77d2a0ccc6SMichael S. Tsirkin static void virtio_pci_save_config(DeviceState *d, QEMUFile *f)
78ff24bd58SMichael S. Tsirkin {
79d2a0ccc6SMichael S. Tsirkin     VirtIOPCIProxy *proxy = to_virtio_pci_proxy(d);
80a3fc66d9SPaolo Bonzini     VirtIODevice *vdev = virtio_bus_get_device(&proxy->bus);
81a3fc66d9SPaolo Bonzini 
82ff24bd58SMichael S. Tsirkin     pci_device_save(&proxy->pci_dev, f);
83ff24bd58SMichael S. Tsirkin     msix_save(&proxy->pci_dev, f);
84ff24bd58SMichael S. Tsirkin     if (msix_present(&proxy->pci_dev))
85a3fc66d9SPaolo Bonzini         qemu_put_be16(f, vdev->config_vector);
86ff24bd58SMichael S. Tsirkin }
87ff24bd58SMichael S. Tsirkin 
88d2a0ccc6SMichael S. Tsirkin static void virtio_pci_save_queue(DeviceState *d, int n, QEMUFile *f)
89ff24bd58SMichael S. Tsirkin {
90d2a0ccc6SMichael S. Tsirkin     VirtIOPCIProxy *proxy = to_virtio_pci_proxy(d);
91a3fc66d9SPaolo Bonzini     VirtIODevice *vdev = virtio_bus_get_device(&proxy->bus);
92a3fc66d9SPaolo Bonzini 
93ff24bd58SMichael S. Tsirkin     if (msix_present(&proxy->pci_dev))
94a3fc66d9SPaolo Bonzini         qemu_put_be16(f, virtio_queue_vector(vdev, n));
95ff24bd58SMichael S. Tsirkin }
96ff24bd58SMichael S. Tsirkin 
97d2a0ccc6SMichael S. Tsirkin static int virtio_pci_load_config(DeviceState *d, QEMUFile *f)
98ff24bd58SMichael S. Tsirkin {
99d2a0ccc6SMichael S. Tsirkin     VirtIOPCIProxy *proxy = to_virtio_pci_proxy(d);
100a3fc66d9SPaolo Bonzini     VirtIODevice *vdev = virtio_bus_get_device(&proxy->bus);
101a3fc66d9SPaolo Bonzini 
102ff24bd58SMichael S. Tsirkin     int ret;
103ff24bd58SMichael S. Tsirkin     ret = pci_device_load(&proxy->pci_dev, f);
104e6da7680SMichael S. Tsirkin     if (ret) {
105ff24bd58SMichael S. Tsirkin         return ret;
106e6da7680SMichael S. Tsirkin     }
1073cac001eSMichael S. Tsirkin     msix_unuse_all_vectors(&proxy->pci_dev);
108ff24bd58SMichael S. Tsirkin     msix_load(&proxy->pci_dev, f);
109e6da7680SMichael S. Tsirkin     if (msix_present(&proxy->pci_dev)) {
110a3fc66d9SPaolo Bonzini         qemu_get_be16s(f, &vdev->config_vector);
111e6da7680SMichael S. Tsirkin     } else {
112a3fc66d9SPaolo Bonzini         vdev->config_vector = VIRTIO_NO_VECTOR;
113e6da7680SMichael S. Tsirkin     }
114a3fc66d9SPaolo Bonzini     if (vdev->config_vector != VIRTIO_NO_VECTOR) {
115a3fc66d9SPaolo Bonzini         return msix_vector_use(&proxy->pci_dev, vdev->config_vector);
116e6da7680SMichael S. Tsirkin     }
117ff24bd58SMichael S. Tsirkin     return 0;
118ff24bd58SMichael S. Tsirkin }
119ff24bd58SMichael S. Tsirkin 
120d2a0ccc6SMichael S. Tsirkin static int virtio_pci_load_queue(DeviceState *d, int n, QEMUFile *f)
121ff24bd58SMichael S. Tsirkin {
122d2a0ccc6SMichael S. Tsirkin     VirtIOPCIProxy *proxy = to_virtio_pci_proxy(d);
123a3fc66d9SPaolo Bonzini     VirtIODevice *vdev = virtio_bus_get_device(&proxy->bus);
124a3fc66d9SPaolo Bonzini 
125ff24bd58SMichael S. Tsirkin     uint16_t vector;
126e6da7680SMichael S. Tsirkin     if (msix_present(&proxy->pci_dev)) {
127ff24bd58SMichael S. Tsirkin         qemu_get_be16s(f, &vector);
128e6da7680SMichael S. Tsirkin     } else {
129e6da7680SMichael S. Tsirkin         vector = VIRTIO_NO_VECTOR;
130e6da7680SMichael S. Tsirkin     }
131a3fc66d9SPaolo Bonzini     virtio_queue_set_vector(vdev, n, vector);
132e6da7680SMichael S. Tsirkin     if (vector != VIRTIO_NO_VECTOR) {
133e6da7680SMichael S. Tsirkin         return msix_vector_use(&proxy->pci_dev, vector);
134e6da7680SMichael S. Tsirkin     }
135ff24bd58SMichael S. Tsirkin     return 0;
136ff24bd58SMichael S. Tsirkin }
137ff24bd58SMichael S. Tsirkin 
138975acc0aSJason Wang #define QEMU_VIRTIO_PCI_QUEUE_MEM_MULT 0x1000
139975acc0aSJason Wang 
14025db9ebeSStefan Hajnoczi static int virtio_pci_set_host_notifier_internal(VirtIOPCIProxy *proxy,
14126b9b5feSPaolo Bonzini                                                  int n, bool assign, bool set_handler)
14225db9ebeSStefan Hajnoczi {
143a3fc66d9SPaolo Bonzini     VirtIODevice *vdev = virtio_bus_get_device(&proxy->bus);
144a3fc66d9SPaolo Bonzini     VirtQueue *vq = virtio_get_queue(vdev, n);
14525db9ebeSStefan Hajnoczi     EventNotifier *notifier = virtio_queue_get_host_notifier(vq);
146975acc0aSJason Wang     bool legacy = !(proxy->flags & VIRTIO_PCI_FLAG_DISABLE_LEGACY);
147975acc0aSJason Wang     bool modern = !(proxy->flags & VIRTIO_PCI_FLAG_DISABLE_MODERN);
148588255adSGerd Hoffmann     MemoryRegion *modern_mr = &proxy->notify.mr;
149975acc0aSJason Wang     MemoryRegion *legacy_mr = &proxy->bar;
150975acc0aSJason Wang     hwaddr modern_addr = QEMU_VIRTIO_PCI_QUEUE_MEM_MULT *
151975acc0aSJason Wang                          virtio_get_queue_index(vq);
152975acc0aSJason Wang     hwaddr legacy_addr = VIRTIO_PCI_QUEUE_NOTIFY;
153da146d0aSAvi Kivity     int r = 0;
154da146d0aSAvi Kivity 
15525db9ebeSStefan Hajnoczi     if (assign) {
15625db9ebeSStefan Hajnoczi         r = event_notifier_init(notifier, 1);
15725db9ebeSStefan Hajnoczi         if (r < 0) {
158b36e3914SMichael S. Tsirkin             error_report("%s: unable to init event notifier: %d",
159b36e3914SMichael S. Tsirkin                          __func__, r);
16025db9ebeSStefan Hajnoczi             return r;
16125db9ebeSStefan Hajnoczi         }
16226b9b5feSPaolo Bonzini         virtio_queue_set_host_notifier_fd_handler(vq, true, set_handler);
163975acc0aSJason Wang         if (modern) {
164975acc0aSJason Wang             memory_region_add_eventfd(modern_mr, modern_addr, 2,
165753d5e14SPaolo Bonzini                                       true, n, notifier);
166975acc0aSJason Wang         }
167975acc0aSJason Wang         if (legacy) {
168975acc0aSJason Wang             memory_region_add_eventfd(legacy_mr, legacy_addr, 2,
169975acc0aSJason Wang                                       true, n, notifier);
170975acc0aSJason Wang         }
17125db9ebeSStefan Hajnoczi     } else {
172975acc0aSJason Wang         if (modern) {
173975acc0aSJason Wang             memory_region_del_eventfd(modern_mr, modern_addr, 2,
174753d5e14SPaolo Bonzini                                       true, n, notifier);
175975acc0aSJason Wang         }
176975acc0aSJason Wang         if (legacy) {
177975acc0aSJason Wang             memory_region_del_eventfd(legacy_mr, legacy_addr, 2,
178975acc0aSJason Wang                                       true, n, notifier);
179975acc0aSJason Wang         }
18026b9b5feSPaolo Bonzini         virtio_queue_set_host_notifier_fd_handler(vq, false, false);
18125db9ebeSStefan Hajnoczi         event_notifier_cleanup(notifier);
18225db9ebeSStefan Hajnoczi     }
18325db9ebeSStefan Hajnoczi     return r;
18425db9ebeSStefan Hajnoczi }
18525db9ebeSStefan Hajnoczi 
186b36e3914SMichael S. Tsirkin static void virtio_pci_start_ioeventfd(VirtIOPCIProxy *proxy)
18725db9ebeSStefan Hajnoczi {
188a3fc66d9SPaolo Bonzini     VirtIODevice *vdev = virtio_bus_get_device(&proxy->bus);
18925db9ebeSStefan Hajnoczi     int n, r;
19025db9ebeSStefan Hajnoczi 
19125db9ebeSStefan Hajnoczi     if (!(proxy->flags & VIRTIO_PCI_FLAG_USE_IOEVENTFD) ||
19225db9ebeSStefan Hajnoczi         proxy->ioeventfd_disabled ||
19325db9ebeSStefan Hajnoczi         proxy->ioeventfd_started) {
194b36e3914SMichael S. Tsirkin         return;
19525db9ebeSStefan Hajnoczi     }
19625db9ebeSStefan Hajnoczi 
19787b3bd1cSJason Wang     for (n = 0; n < VIRTIO_QUEUE_MAX; n++) {
198a3fc66d9SPaolo Bonzini         if (!virtio_queue_get_num(vdev, n)) {
19925db9ebeSStefan Hajnoczi             continue;
20025db9ebeSStefan Hajnoczi         }
20125db9ebeSStefan Hajnoczi 
20226b9b5feSPaolo Bonzini         r = virtio_pci_set_host_notifier_internal(proxy, n, true, true);
20325db9ebeSStefan Hajnoczi         if (r < 0) {
20425db9ebeSStefan Hajnoczi             goto assign_error;
20525db9ebeSStefan Hajnoczi         }
20625db9ebeSStefan Hajnoczi     }
20725db9ebeSStefan Hajnoczi     proxy->ioeventfd_started = true;
208b36e3914SMichael S. Tsirkin     return;
20925db9ebeSStefan Hajnoczi 
21025db9ebeSStefan Hajnoczi assign_error:
21125db9ebeSStefan Hajnoczi     while (--n >= 0) {
212a3fc66d9SPaolo Bonzini         if (!virtio_queue_get_num(vdev, n)) {
21325db9ebeSStefan Hajnoczi             continue;
21425db9ebeSStefan Hajnoczi         }
21525db9ebeSStefan Hajnoczi 
21626b9b5feSPaolo Bonzini         r = virtio_pci_set_host_notifier_internal(proxy, n, false, false);
217b36e3914SMichael S. Tsirkin         assert(r >= 0);
21825db9ebeSStefan Hajnoczi     }
21925db9ebeSStefan Hajnoczi     proxy->ioeventfd_started = false;
220b36e3914SMichael S. Tsirkin     error_report("%s: failed. Fallback to a userspace (slower).", __func__);
22125db9ebeSStefan Hajnoczi }
22225db9ebeSStefan Hajnoczi 
223b36e3914SMichael S. Tsirkin static void virtio_pci_stop_ioeventfd(VirtIOPCIProxy *proxy)
22425db9ebeSStefan Hajnoczi {
225a3fc66d9SPaolo Bonzini     VirtIODevice *vdev = virtio_bus_get_device(&proxy->bus);
226b36e3914SMichael S. Tsirkin     int r;
22725db9ebeSStefan Hajnoczi     int n;
22825db9ebeSStefan Hajnoczi 
22925db9ebeSStefan Hajnoczi     if (!proxy->ioeventfd_started) {
230b36e3914SMichael S. Tsirkin         return;
23125db9ebeSStefan Hajnoczi     }
23225db9ebeSStefan Hajnoczi 
23387b3bd1cSJason Wang     for (n = 0; n < VIRTIO_QUEUE_MAX; n++) {
234a3fc66d9SPaolo Bonzini         if (!virtio_queue_get_num(vdev, n)) {
23525db9ebeSStefan Hajnoczi             continue;
23625db9ebeSStefan Hajnoczi         }
23725db9ebeSStefan Hajnoczi 
23826b9b5feSPaolo Bonzini         r = virtio_pci_set_host_notifier_internal(proxy, n, false, false);
239b36e3914SMichael S. Tsirkin         assert(r >= 0);
24025db9ebeSStefan Hajnoczi     }
24125db9ebeSStefan Hajnoczi     proxy->ioeventfd_started = false;
24225db9ebeSStefan Hajnoczi }
24325db9ebeSStefan Hajnoczi 
24453c25ceaSPaul Brook static void virtio_ioport_write(void *opaque, uint32_t addr, uint32_t val)
24553c25ceaSPaul Brook {
24653c25ceaSPaul Brook     VirtIOPCIProxy *proxy = opaque;
247a3fc66d9SPaolo Bonzini     VirtIODevice *vdev = virtio_bus_get_device(&proxy->bus);
248a8170e5eSAvi Kivity     hwaddr pa;
24953c25ceaSPaul Brook 
25053c25ceaSPaul Brook     switch (addr) {
25153c25ceaSPaul Brook     case VIRTIO_PCI_GUEST_FEATURES:
25253c25ceaSPaul Brook         /* Guest does not negotiate properly?  We have to assume nothing. */
25353c25ceaSPaul Brook         if (val & (1 << VIRTIO_F_BAD_FEATURE)) {
254181103cdSKONRAD Frederic             val = virtio_bus_get_vdev_bad_features(&proxy->bus);
25553c25ceaSPaul Brook         }
256ad0c9332SPaolo Bonzini         virtio_set_features(vdev, val);
25753c25ceaSPaul Brook         break;
25853c25ceaSPaul Brook     case VIRTIO_PCI_QUEUE_PFN:
259a8170e5eSAvi Kivity         pa = (hwaddr)val << VIRTIO_PCI_QUEUE_ADDR_SHIFT;
2601b8e9b27SMichael S. Tsirkin         if (pa == 0) {
26125db9ebeSStefan Hajnoczi             virtio_pci_stop_ioeventfd(proxy);
262a3fc66d9SPaolo Bonzini             virtio_reset(vdev);
2631b8e9b27SMichael S. Tsirkin             msix_unuse_all_vectors(&proxy->pci_dev);
2641b8e9b27SMichael S. Tsirkin         }
2657055e687SMichael S. Tsirkin         else
26653c25ceaSPaul Brook             virtio_queue_set_addr(vdev, vdev->queue_sel, pa);
26753c25ceaSPaul Brook         break;
26853c25ceaSPaul Brook     case VIRTIO_PCI_QUEUE_SEL:
26987b3bd1cSJason Wang         if (val < VIRTIO_QUEUE_MAX)
27053c25ceaSPaul Brook             vdev->queue_sel = val;
27153c25ceaSPaul Brook         break;
27253c25ceaSPaul Brook     case VIRTIO_PCI_QUEUE_NOTIFY:
27387b3bd1cSJason Wang         if (val < VIRTIO_QUEUE_MAX) {
27453c25ceaSPaul Brook             virtio_queue_notify(vdev, val);
2757157e2e2SStefan Hajnoczi         }
27653c25ceaSPaul Brook         break;
27753c25ceaSPaul Brook     case VIRTIO_PCI_STATUS:
27825db9ebeSStefan Hajnoczi         if (!(val & VIRTIO_CONFIG_S_DRIVER_OK)) {
27925db9ebeSStefan Hajnoczi             virtio_pci_stop_ioeventfd(proxy);
28025db9ebeSStefan Hajnoczi         }
28125db9ebeSStefan Hajnoczi 
2823e607cb5SMichael S. Tsirkin         virtio_set_status(vdev, val & 0xFF);
28325db9ebeSStefan Hajnoczi 
28425db9ebeSStefan Hajnoczi         if (val & VIRTIO_CONFIG_S_DRIVER_OK) {
28525db9ebeSStefan Hajnoczi             virtio_pci_start_ioeventfd(proxy);
28625db9ebeSStefan Hajnoczi         }
28725db9ebeSStefan Hajnoczi 
2881b8e9b27SMichael S. Tsirkin         if (vdev->status == 0) {
289a3fc66d9SPaolo Bonzini             virtio_reset(vdev);
2901b8e9b27SMichael S. Tsirkin             msix_unuse_all_vectors(&proxy->pci_dev);
2911b8e9b27SMichael S. Tsirkin         }
292c81131dbSAlexander Graf 
293e43c0b2eSMichael S. Tsirkin         /* Linux before 2.6.34 drives the device without enabling
294e43c0b2eSMichael S. Tsirkin            the PCI device bus master bit. Enable it automatically
295e43c0b2eSMichael S. Tsirkin            for the guest. This is a PCI spec violation but so is
296e43c0b2eSMichael S. Tsirkin            initiating DMA with bus master bit clear. */
297e43c0b2eSMichael S. Tsirkin         if (val == (VIRTIO_CONFIG_S_ACKNOWLEDGE | VIRTIO_CONFIG_S_DRIVER)) {
298e43c0b2eSMichael S. Tsirkin             pci_default_write_config(&proxy->pci_dev, PCI_COMMAND,
299e43c0b2eSMichael S. Tsirkin                                      proxy->pci_dev.config[PCI_COMMAND] |
300e43c0b2eSMichael S. Tsirkin                                      PCI_COMMAND_MASTER, 1);
301e43c0b2eSMichael S. Tsirkin         }
30253c25ceaSPaul Brook         break;
303aba800a3SMichael S. Tsirkin     case VIRTIO_MSI_CONFIG_VECTOR:
304aba800a3SMichael S. Tsirkin         msix_vector_unuse(&proxy->pci_dev, vdev->config_vector);
305aba800a3SMichael S. Tsirkin         /* Make it possible for guest to discover an error took place. */
306aba800a3SMichael S. Tsirkin         if (msix_vector_use(&proxy->pci_dev, val) < 0)
307aba800a3SMichael S. Tsirkin             val = VIRTIO_NO_VECTOR;
308aba800a3SMichael S. Tsirkin         vdev->config_vector = val;
309aba800a3SMichael S. Tsirkin         break;
310aba800a3SMichael S. Tsirkin     case VIRTIO_MSI_QUEUE_VECTOR:
311aba800a3SMichael S. Tsirkin         msix_vector_unuse(&proxy->pci_dev,
312aba800a3SMichael S. Tsirkin                           virtio_queue_vector(vdev, vdev->queue_sel));
313aba800a3SMichael S. Tsirkin         /* Make it possible for guest to discover an error took place. */
314aba800a3SMichael S. Tsirkin         if (msix_vector_use(&proxy->pci_dev, val) < 0)
315aba800a3SMichael S. Tsirkin             val = VIRTIO_NO_VECTOR;
316aba800a3SMichael S. Tsirkin         virtio_queue_set_vector(vdev, vdev->queue_sel, val);
317aba800a3SMichael S. Tsirkin         break;
318aba800a3SMichael S. Tsirkin     default:
3194e02d460SStefan Hajnoczi         error_report("%s: unexpected address 0x%x value 0x%x",
320aba800a3SMichael S. Tsirkin                      __func__, addr, val);
321aba800a3SMichael S. Tsirkin         break;
32253c25ceaSPaul Brook     }
32353c25ceaSPaul Brook }
32453c25ceaSPaul Brook 
325aba800a3SMichael S. Tsirkin static uint32_t virtio_ioport_read(VirtIOPCIProxy *proxy, uint32_t addr)
32653c25ceaSPaul Brook {
327a3fc66d9SPaolo Bonzini     VirtIODevice *vdev = virtio_bus_get_device(&proxy->bus);
32853c25ceaSPaul Brook     uint32_t ret = 0xFFFFFFFF;
32953c25ceaSPaul Brook 
33053c25ceaSPaul Brook     switch (addr) {
33153c25ceaSPaul Brook     case VIRTIO_PCI_HOST_FEATURES:
3326b8f1020SCornelia Huck         ret = vdev->host_features;
33353c25ceaSPaul Brook         break;
33453c25ceaSPaul Brook     case VIRTIO_PCI_GUEST_FEATURES:
335704a76fcSMichael S. Tsirkin         ret = vdev->guest_features;
33653c25ceaSPaul Brook         break;
33753c25ceaSPaul Brook     case VIRTIO_PCI_QUEUE_PFN:
33853c25ceaSPaul Brook         ret = virtio_queue_get_addr(vdev, vdev->queue_sel)
33953c25ceaSPaul Brook               >> VIRTIO_PCI_QUEUE_ADDR_SHIFT;
34053c25ceaSPaul Brook         break;
34153c25ceaSPaul Brook     case VIRTIO_PCI_QUEUE_NUM:
34253c25ceaSPaul Brook         ret = virtio_queue_get_num(vdev, vdev->queue_sel);
34353c25ceaSPaul Brook         break;
34453c25ceaSPaul Brook     case VIRTIO_PCI_QUEUE_SEL:
34553c25ceaSPaul Brook         ret = vdev->queue_sel;
34653c25ceaSPaul Brook         break;
34753c25ceaSPaul Brook     case VIRTIO_PCI_STATUS:
34853c25ceaSPaul Brook         ret = vdev->status;
34953c25ceaSPaul Brook         break;
35053c25ceaSPaul Brook     case VIRTIO_PCI_ISR:
35153c25ceaSPaul Brook         /* reading from the ISR also clears it. */
35253c25ceaSPaul Brook         ret = vdev->isr;
35353c25ceaSPaul Brook         vdev->isr = 0;
3549e64f8a3SMarcel Apfelbaum         pci_irq_deassert(&proxy->pci_dev);
35553c25ceaSPaul Brook         break;
356aba800a3SMichael S. Tsirkin     case VIRTIO_MSI_CONFIG_VECTOR:
357aba800a3SMichael S. Tsirkin         ret = vdev->config_vector;
358aba800a3SMichael S. Tsirkin         break;
359aba800a3SMichael S. Tsirkin     case VIRTIO_MSI_QUEUE_VECTOR:
360aba800a3SMichael S. Tsirkin         ret = virtio_queue_vector(vdev, vdev->queue_sel);
361aba800a3SMichael S. Tsirkin         break;
36253c25ceaSPaul Brook     default:
36353c25ceaSPaul Brook         break;
36453c25ceaSPaul Brook     }
36553c25ceaSPaul Brook 
36653c25ceaSPaul Brook     return ret;
36753c25ceaSPaul Brook }
36853c25ceaSPaul Brook 
369df6db5b3SAlexander Graf static uint64_t virtio_pci_config_read(void *opaque, hwaddr addr,
370df6db5b3SAlexander Graf                                        unsigned size)
37153c25ceaSPaul Brook {
37253c25ceaSPaul Brook     VirtIOPCIProxy *proxy = opaque;
373a3fc66d9SPaolo Bonzini     VirtIODevice *vdev = virtio_bus_get_device(&proxy->bus);
374cbbe4f50SMichael S. Tsirkin     uint32_t config = VIRTIO_PCI_CONFIG_SIZE(&proxy->pci_dev);
375df6db5b3SAlexander Graf     uint64_t val = 0;
376df6db5b3SAlexander Graf     if (addr < config) {
377aba800a3SMichael S. Tsirkin         return virtio_ioport_read(proxy, addr);
37853c25ceaSPaul Brook     }
379aba800a3SMichael S. Tsirkin     addr -= config;
380df6db5b3SAlexander Graf 
381df6db5b3SAlexander Graf     switch (size) {
382df6db5b3SAlexander Graf     case 1:
383a3fc66d9SPaolo Bonzini         val = virtio_config_readb(vdev, addr);
384df6db5b3SAlexander Graf         break;
385df6db5b3SAlexander Graf     case 2:
386a3fc66d9SPaolo Bonzini         val = virtio_config_readw(vdev, addr);
387616a6552SGreg Kurz         if (virtio_is_big_endian(vdev)) {
3888e4a424bSBlue Swirl             val = bswap16(val);
3898e4a424bSBlue Swirl         }
390df6db5b3SAlexander Graf         break;
391df6db5b3SAlexander Graf     case 4:
392a3fc66d9SPaolo Bonzini         val = virtio_config_readl(vdev, addr);
393616a6552SGreg Kurz         if (virtio_is_big_endian(vdev)) {
3948e4a424bSBlue Swirl             val = bswap32(val);
3958e4a424bSBlue Swirl         }
396df6db5b3SAlexander Graf         break;
397df6db5b3SAlexander Graf     }
39882afa586SBenjamin Herrenschmidt     return val;
39953c25ceaSPaul Brook }
40053c25ceaSPaul Brook 
401df6db5b3SAlexander Graf static void virtio_pci_config_write(void *opaque, hwaddr addr,
402df6db5b3SAlexander Graf                                     uint64_t val, unsigned size)
40353c25ceaSPaul Brook {
40453c25ceaSPaul Brook     VirtIOPCIProxy *proxy = opaque;
405cbbe4f50SMichael S. Tsirkin     uint32_t config = VIRTIO_PCI_CONFIG_SIZE(&proxy->pci_dev);
406a3fc66d9SPaolo Bonzini     VirtIODevice *vdev = virtio_bus_get_device(&proxy->bus);
407aba800a3SMichael S. Tsirkin     if (addr < config) {
408aba800a3SMichael S. Tsirkin         virtio_ioport_write(proxy, addr, val);
409aba800a3SMichael S. Tsirkin         return;
410aba800a3SMichael S. Tsirkin     }
411aba800a3SMichael S. Tsirkin     addr -= config;
412df6db5b3SAlexander Graf     /*
413df6db5b3SAlexander Graf      * Virtio-PCI is odd. Ioports are LE but config space is target native
414df6db5b3SAlexander Graf      * endian.
415df6db5b3SAlexander Graf      */
416df6db5b3SAlexander Graf     switch (size) {
417df6db5b3SAlexander Graf     case 1:
418a3fc66d9SPaolo Bonzini         virtio_config_writeb(vdev, addr, val);
419df6db5b3SAlexander Graf         break;
420df6db5b3SAlexander Graf     case 2:
421616a6552SGreg Kurz         if (virtio_is_big_endian(vdev)) {
4228e4a424bSBlue Swirl             val = bswap16(val);
4238e4a424bSBlue Swirl         }
424a3fc66d9SPaolo Bonzini         virtio_config_writew(vdev, addr, val);
425df6db5b3SAlexander Graf         break;
426df6db5b3SAlexander Graf     case 4:
427616a6552SGreg Kurz         if (virtio_is_big_endian(vdev)) {
4288e4a424bSBlue Swirl             val = bswap32(val);
4298e4a424bSBlue Swirl         }
430a3fc66d9SPaolo Bonzini         virtio_config_writel(vdev, addr, val);
431df6db5b3SAlexander Graf         break;
432df6db5b3SAlexander Graf     }
43353c25ceaSPaul Brook }
43453c25ceaSPaul Brook 
435da146d0aSAvi Kivity static const MemoryRegionOps virtio_pci_config_ops = {
436df6db5b3SAlexander Graf     .read = virtio_pci_config_read,
437df6db5b3SAlexander Graf     .write = virtio_pci_config_write,
438df6db5b3SAlexander Graf     .impl = {
439df6db5b3SAlexander Graf         .min_access_size = 1,
440df6db5b3SAlexander Graf         .max_access_size = 4,
441df6db5b3SAlexander Graf     },
4428e4a424bSBlue Swirl     .endianness = DEVICE_LITTLE_ENDIAN,
443da146d0aSAvi Kivity };
444aba800a3SMichael S. Tsirkin 
445aba800a3SMichael S. Tsirkin static void virtio_write_config(PCIDevice *pci_dev, uint32_t address,
446aba800a3SMichael S. Tsirkin                                 uint32_t val, int len)
447aba800a3SMichael S. Tsirkin {
448ed757e14SYan Vugenfirer     VirtIOPCIProxy *proxy = DO_UPCAST(VirtIOPCIProxy, pci_dev, pci_dev);
449a3fc66d9SPaolo Bonzini     VirtIODevice *vdev = virtio_bus_get_device(&proxy->bus);
450ed757e14SYan Vugenfirer 
4511129714fSMichael S. Tsirkin     pci_default_write_config(pci_dev, address, val, len);
4521129714fSMichael S. Tsirkin 
4531129714fSMichael S. Tsirkin     if (range_covers_byte(address, len, PCI_COMMAND) &&
45468a27b20SMichael S. Tsirkin         !(pci_dev->config[PCI_COMMAND] & PCI_COMMAND_MASTER)) {
45525db9ebeSStefan Hajnoczi         virtio_pci_stop_ioeventfd(proxy);
45645363e46SMichael S. Tsirkin         virtio_set_status(vdev, vdev->status & ~VIRTIO_CONFIG_S_DRIVER_OK);
457ed757e14SYan Vugenfirer     }
45853c25ceaSPaul Brook }
45953c25ceaSPaul Brook 
4607d37d351SJan Kiszka static int kvm_virtio_pci_vq_vector_use(VirtIOPCIProxy *proxy,
4617d37d351SJan Kiszka                                         unsigned int queue_no,
4627d37d351SJan Kiszka                                         unsigned int vector,
4637d37d351SJan Kiszka                                         MSIMessage msg)
4647d37d351SJan Kiszka {
4657d37d351SJan Kiszka     VirtIOIRQFD *irqfd = &proxy->vector_irqfd[vector];
46615b2bd18SPaolo Bonzini     int ret;
4677d37d351SJan Kiszka 
4687d37d351SJan Kiszka     if (irqfd->users == 0) {
4697d37d351SJan Kiszka         ret = kvm_irqchip_add_msi_route(kvm_state, msg);
4707d37d351SJan Kiszka         if (ret < 0) {
4717d37d351SJan Kiszka             return ret;
4727d37d351SJan Kiszka         }
4737d37d351SJan Kiszka         irqfd->virq = ret;
4747d37d351SJan Kiszka     }
4757d37d351SJan Kiszka     irqfd->users++;
4767d37d351SJan Kiszka     return 0;
4777d37d351SJan Kiszka }
4787d37d351SJan Kiszka 
4797d37d351SJan Kiszka static void kvm_virtio_pci_vq_vector_release(VirtIOPCIProxy *proxy,
480774345f9SMichael S. Tsirkin                                              unsigned int vector)
481774345f9SMichael S. Tsirkin {
482774345f9SMichael S. Tsirkin     VirtIOIRQFD *irqfd = &proxy->vector_irqfd[vector];
483774345f9SMichael S. Tsirkin     if (--irqfd->users == 0) {
484774345f9SMichael S. Tsirkin         kvm_irqchip_release_virq(kvm_state, irqfd->virq);
485774345f9SMichael S. Tsirkin     }
486774345f9SMichael S. Tsirkin }
487774345f9SMichael S. Tsirkin 
488f1d0f15aSMichael S. Tsirkin static int kvm_virtio_pci_irqfd_use(VirtIOPCIProxy *proxy,
489f1d0f15aSMichael S. Tsirkin                                  unsigned int queue_no,
490f1d0f15aSMichael S. Tsirkin                                  unsigned int vector)
491f1d0f15aSMichael S. Tsirkin {
492f1d0f15aSMichael S. Tsirkin     VirtIOIRQFD *irqfd = &proxy->vector_irqfd[vector];
493a3fc66d9SPaolo Bonzini     VirtIODevice *vdev = virtio_bus_get_device(&proxy->bus);
494a3fc66d9SPaolo Bonzini     VirtQueue *vq = virtio_get_queue(vdev, queue_no);
495f1d0f15aSMichael S. Tsirkin     EventNotifier *n = virtio_queue_get_guest_notifier(vq);
496f1d0f15aSMichael S. Tsirkin     int ret;
497ca916d37SVincenzo Maffione     ret = kvm_irqchip_add_irqfd_notifier(kvm_state, n, NULL, irqfd->virq);
498f1d0f15aSMichael S. Tsirkin     return ret;
499f1d0f15aSMichael S. Tsirkin }
500f1d0f15aSMichael S. Tsirkin 
501f1d0f15aSMichael S. Tsirkin static void kvm_virtio_pci_irqfd_release(VirtIOPCIProxy *proxy,
5027d37d351SJan Kiszka                                       unsigned int queue_no,
5037d37d351SJan Kiszka                                       unsigned int vector)
5047d37d351SJan Kiszka {
505a3fc66d9SPaolo Bonzini     VirtIODevice *vdev = virtio_bus_get_device(&proxy->bus);
506a3fc66d9SPaolo Bonzini     VirtQueue *vq = virtio_get_queue(vdev, queue_no);
50715b2bd18SPaolo Bonzini     EventNotifier *n = virtio_queue_get_guest_notifier(vq);
5087d37d351SJan Kiszka     VirtIOIRQFD *irqfd = &proxy->vector_irqfd[vector];
50915b2bd18SPaolo Bonzini     int ret;
5107d37d351SJan Kiszka 
511b131c74aSJan Kiszka     ret = kvm_irqchip_remove_irqfd_notifier(kvm_state, n, irqfd->virq);
5127d37d351SJan Kiszka     assert(ret == 0);
513f1d0f15aSMichael S. Tsirkin }
5147d37d351SJan Kiszka 
515774345f9SMichael S. Tsirkin static int kvm_virtio_pci_vector_use(VirtIOPCIProxy *proxy, int nvqs)
516774345f9SMichael S. Tsirkin {
517774345f9SMichael S. Tsirkin     PCIDevice *dev = &proxy->pci_dev;
518a3fc66d9SPaolo Bonzini     VirtIODevice *vdev = virtio_bus_get_device(&proxy->bus);
519181103cdSKONRAD Frederic     VirtioDeviceClass *k = VIRTIO_DEVICE_GET_CLASS(vdev);
520774345f9SMichael S. Tsirkin     unsigned int vector;
521774345f9SMichael S. Tsirkin     int ret, queue_no;
522774345f9SMichael S. Tsirkin     MSIMessage msg;
523774345f9SMichael S. Tsirkin 
524774345f9SMichael S. Tsirkin     for (queue_no = 0; queue_no < nvqs; queue_no++) {
525774345f9SMichael S. Tsirkin         if (!virtio_queue_get_num(vdev, queue_no)) {
526774345f9SMichael S. Tsirkin             break;
527774345f9SMichael S. Tsirkin         }
528774345f9SMichael S. Tsirkin         vector = virtio_queue_vector(vdev, queue_no);
529774345f9SMichael S. Tsirkin         if (vector >= msix_nr_vectors_allocated(dev)) {
530774345f9SMichael S. Tsirkin             continue;
531774345f9SMichael S. Tsirkin         }
532774345f9SMichael S. Tsirkin         msg = msix_get_message(dev, vector);
533774345f9SMichael S. Tsirkin         ret = kvm_virtio_pci_vq_vector_use(proxy, queue_no, vector, msg);
534774345f9SMichael S. Tsirkin         if (ret < 0) {
535774345f9SMichael S. Tsirkin             goto undo;
536774345f9SMichael S. Tsirkin         }
537f1d0f15aSMichael S. Tsirkin         /* If guest supports masking, set up irqfd now.
538f1d0f15aSMichael S. Tsirkin          * Otherwise, delay until unmasked in the frontend.
539f1d0f15aSMichael S. Tsirkin          */
540181103cdSKONRAD Frederic         if (k->guest_notifier_mask) {
541f1d0f15aSMichael S. Tsirkin             ret = kvm_virtio_pci_irqfd_use(proxy, queue_no, vector);
542f1d0f15aSMichael S. Tsirkin             if (ret < 0) {
543f1d0f15aSMichael S. Tsirkin                 kvm_virtio_pci_vq_vector_release(proxy, vector);
544f1d0f15aSMichael S. Tsirkin                 goto undo;
545f1d0f15aSMichael S. Tsirkin             }
546f1d0f15aSMichael S. Tsirkin         }
547774345f9SMichael S. Tsirkin     }
548774345f9SMichael S. Tsirkin     return 0;
549774345f9SMichael S. Tsirkin 
550774345f9SMichael S. Tsirkin undo:
551774345f9SMichael S. Tsirkin     while (--queue_no >= 0) {
552774345f9SMichael S. Tsirkin         vector = virtio_queue_vector(vdev, queue_no);
553774345f9SMichael S. Tsirkin         if (vector >= msix_nr_vectors_allocated(dev)) {
554774345f9SMichael S. Tsirkin             continue;
555774345f9SMichael S. Tsirkin         }
556181103cdSKONRAD Frederic         if (k->guest_notifier_mask) {
557e387f99eSMichael S. Tsirkin             kvm_virtio_pci_irqfd_release(proxy, queue_no, vector);
558f1d0f15aSMichael S. Tsirkin         }
559774345f9SMichael S. Tsirkin         kvm_virtio_pci_vq_vector_release(proxy, vector);
560774345f9SMichael S. Tsirkin     }
561774345f9SMichael S. Tsirkin     return ret;
562774345f9SMichael S. Tsirkin }
563774345f9SMichael S. Tsirkin 
564774345f9SMichael S. Tsirkin static void kvm_virtio_pci_vector_release(VirtIOPCIProxy *proxy, int nvqs)
565774345f9SMichael S. Tsirkin {
566774345f9SMichael S. Tsirkin     PCIDevice *dev = &proxy->pci_dev;
567a3fc66d9SPaolo Bonzini     VirtIODevice *vdev = virtio_bus_get_device(&proxy->bus);
568774345f9SMichael S. Tsirkin     unsigned int vector;
569774345f9SMichael S. Tsirkin     int queue_no;
570181103cdSKONRAD Frederic     VirtioDeviceClass *k = VIRTIO_DEVICE_GET_CLASS(vdev);
571774345f9SMichael S. Tsirkin 
572774345f9SMichael S. Tsirkin     for (queue_no = 0; queue_no < nvqs; queue_no++) {
573774345f9SMichael S. Tsirkin         if (!virtio_queue_get_num(vdev, queue_no)) {
574774345f9SMichael S. Tsirkin             break;
575774345f9SMichael S. Tsirkin         }
576774345f9SMichael S. Tsirkin         vector = virtio_queue_vector(vdev, queue_no);
577774345f9SMichael S. Tsirkin         if (vector >= msix_nr_vectors_allocated(dev)) {
578774345f9SMichael S. Tsirkin             continue;
579774345f9SMichael S. Tsirkin         }
580f1d0f15aSMichael S. Tsirkin         /* If guest supports masking, clean up irqfd now.
581f1d0f15aSMichael S. Tsirkin          * Otherwise, it was cleaned when masked in the frontend.
582f1d0f15aSMichael S. Tsirkin          */
583181103cdSKONRAD Frederic         if (k->guest_notifier_mask) {
584e387f99eSMichael S. Tsirkin             kvm_virtio_pci_irqfd_release(proxy, queue_no, vector);
585f1d0f15aSMichael S. Tsirkin         }
586774345f9SMichael S. Tsirkin         kvm_virtio_pci_vq_vector_release(proxy, vector);
5877d37d351SJan Kiszka     }
5887d37d351SJan Kiszka }
5897d37d351SJan Kiszka 
590a38b2c49SMichael S. Tsirkin static int virtio_pci_vq_vector_unmask(VirtIOPCIProxy *proxy,
591774345f9SMichael S. Tsirkin                                        unsigned int queue_no,
592774345f9SMichael S. Tsirkin                                        unsigned int vector,
593774345f9SMichael S. Tsirkin                                        MSIMessage msg)
594774345f9SMichael S. Tsirkin {
595a3fc66d9SPaolo Bonzini     VirtIODevice *vdev = virtio_bus_get_device(&proxy->bus);
596a3fc66d9SPaolo Bonzini     VirtioDeviceClass *k = VIRTIO_DEVICE_GET_CLASS(vdev);
597a3fc66d9SPaolo Bonzini     VirtQueue *vq = virtio_get_queue(vdev, queue_no);
598774345f9SMichael S. Tsirkin     EventNotifier *n = virtio_queue_get_guest_notifier(vq);
599a38b2c49SMichael S. Tsirkin     VirtIOIRQFD *irqfd;
60053510bfcSMichael Roth     int ret = 0;
601774345f9SMichael S. Tsirkin 
602a38b2c49SMichael S. Tsirkin     if (proxy->vector_irqfd) {
603a38b2c49SMichael S. Tsirkin         irqfd = &proxy->vector_irqfd[vector];
604774345f9SMichael S. Tsirkin         if (irqfd->msg.data != msg.data || irqfd->msg.address != msg.address) {
605774345f9SMichael S. Tsirkin             ret = kvm_irqchip_update_msi_route(kvm_state, irqfd->virq, msg);
606774345f9SMichael S. Tsirkin             if (ret < 0) {
607774345f9SMichael S. Tsirkin                 return ret;
608774345f9SMichael S. Tsirkin             }
609774345f9SMichael S. Tsirkin         }
610a38b2c49SMichael S. Tsirkin     }
611774345f9SMichael S. Tsirkin 
612f1d0f15aSMichael S. Tsirkin     /* If guest supports masking, irqfd is already setup, unmask it.
613f1d0f15aSMichael S. Tsirkin      * Otherwise, set it up now.
614f1d0f15aSMichael S. Tsirkin      */
615181103cdSKONRAD Frederic     if (k->guest_notifier_mask) {
616a3fc66d9SPaolo Bonzini         k->guest_notifier_mask(vdev, queue_no, false);
617f1d0f15aSMichael S. Tsirkin         /* Test after unmasking to avoid losing events. */
618181103cdSKONRAD Frederic         if (k->guest_notifier_pending &&
619a3fc66d9SPaolo Bonzini             k->guest_notifier_pending(vdev, queue_no)) {
620f1d0f15aSMichael S. Tsirkin             event_notifier_set(n);
621f1d0f15aSMichael S. Tsirkin         }
622f1d0f15aSMichael S. Tsirkin     } else {
623f1d0f15aSMichael S. Tsirkin         ret = kvm_virtio_pci_irqfd_use(proxy, queue_no, vector);
624f1d0f15aSMichael S. Tsirkin     }
625774345f9SMichael S. Tsirkin     return ret;
626774345f9SMichael S. Tsirkin }
627774345f9SMichael S. Tsirkin 
628a38b2c49SMichael S. Tsirkin static void virtio_pci_vq_vector_mask(VirtIOPCIProxy *proxy,
6297d37d351SJan Kiszka                                              unsigned int queue_no,
6307d37d351SJan Kiszka                                              unsigned int vector)
6317d37d351SJan Kiszka {
632a3fc66d9SPaolo Bonzini     VirtIODevice *vdev = virtio_bus_get_device(&proxy->bus);
633a3fc66d9SPaolo Bonzini     VirtioDeviceClass *k = VIRTIO_DEVICE_GET_CLASS(vdev);
634181103cdSKONRAD Frederic 
635f1d0f15aSMichael S. Tsirkin     /* If guest supports masking, keep irqfd but mask it.
636f1d0f15aSMichael S. Tsirkin      * Otherwise, clean it up now.
637f1d0f15aSMichael S. Tsirkin      */
638181103cdSKONRAD Frederic     if (k->guest_notifier_mask) {
639a3fc66d9SPaolo Bonzini         k->guest_notifier_mask(vdev, queue_no, true);
640f1d0f15aSMichael S. Tsirkin     } else {
641e387f99eSMichael S. Tsirkin         kvm_virtio_pci_irqfd_release(proxy, queue_no, vector);
642f1d0f15aSMichael S. Tsirkin     }
6437d37d351SJan Kiszka }
6447d37d351SJan Kiszka 
645a38b2c49SMichael S. Tsirkin static int virtio_pci_vector_unmask(PCIDevice *dev, unsigned vector,
6467d37d351SJan Kiszka                                     MSIMessage msg)
6477d37d351SJan Kiszka {
6487d37d351SJan Kiszka     VirtIOPCIProxy *proxy = container_of(dev, VirtIOPCIProxy, pci_dev);
649a3fc66d9SPaolo Bonzini     VirtIODevice *vdev = virtio_bus_get_device(&proxy->bus);
650851c2a75SJason Wang     VirtQueue *vq = virtio_vector_first_queue(vdev, vector);
651851c2a75SJason Wang     int ret, index, unmasked = 0;
6527d37d351SJan Kiszka 
653851c2a75SJason Wang     while (vq) {
654851c2a75SJason Wang         index = virtio_get_queue_index(vq);
655851c2a75SJason Wang         if (!virtio_queue_get_num(vdev, index)) {
6567d37d351SJan Kiszka             break;
6577d37d351SJan Kiszka         }
6586652d081SJason Wang         if (index < proxy->nvqs_with_notifiers) {
659851c2a75SJason Wang             ret = virtio_pci_vq_vector_unmask(proxy, index, vector, msg);
6607d37d351SJan Kiszka             if (ret < 0) {
6617d37d351SJan Kiszka                 goto undo;
6627d37d351SJan Kiszka             }
663851c2a75SJason Wang             ++unmasked;
6647d37d351SJan Kiszka         }
6656652d081SJason Wang         vq = virtio_vector_next_queue(vq);
6666652d081SJason Wang     }
667851c2a75SJason Wang 
6687d37d351SJan Kiszka     return 0;
6697d37d351SJan Kiszka 
6707d37d351SJan Kiszka undo:
671851c2a75SJason Wang     vq = virtio_vector_first_queue(vdev, vector);
6726652d081SJason Wang     while (vq && unmasked >= 0) {
673851c2a75SJason Wang         index = virtio_get_queue_index(vq);
6746652d081SJason Wang         if (index < proxy->nvqs_with_notifiers) {
675851c2a75SJason Wang             virtio_pci_vq_vector_mask(proxy, index, vector);
6766652d081SJason Wang             --unmasked;
6776652d081SJason Wang         }
678851c2a75SJason Wang         vq = virtio_vector_next_queue(vq);
6797d37d351SJan Kiszka     }
6807d37d351SJan Kiszka     return ret;
6817d37d351SJan Kiszka }
6827d37d351SJan Kiszka 
683a38b2c49SMichael S. Tsirkin static void virtio_pci_vector_mask(PCIDevice *dev, unsigned vector)
6847d37d351SJan Kiszka {
6857d37d351SJan Kiszka     VirtIOPCIProxy *proxy = container_of(dev, VirtIOPCIProxy, pci_dev);
686a3fc66d9SPaolo Bonzini     VirtIODevice *vdev = virtio_bus_get_device(&proxy->bus);
687851c2a75SJason Wang     VirtQueue *vq = virtio_vector_first_queue(vdev, vector);
688851c2a75SJason Wang     int index;
6897d37d351SJan Kiszka 
690851c2a75SJason Wang     while (vq) {
691851c2a75SJason Wang         index = virtio_get_queue_index(vq);
692851c2a75SJason Wang         if (!virtio_queue_get_num(vdev, index)) {
6937d37d351SJan Kiszka             break;
6947d37d351SJan Kiszka         }
6956652d081SJason Wang         if (index < proxy->nvqs_with_notifiers) {
696851c2a75SJason Wang             virtio_pci_vq_vector_mask(proxy, index, vector);
6976652d081SJason Wang         }
698851c2a75SJason Wang         vq = virtio_vector_next_queue(vq);
6997d37d351SJan Kiszka     }
7007d37d351SJan Kiszka }
7017d37d351SJan Kiszka 
702a38b2c49SMichael S. Tsirkin static void virtio_pci_vector_poll(PCIDevice *dev,
70389d62be9SMichael S. Tsirkin                                    unsigned int vector_start,
70489d62be9SMichael S. Tsirkin                                    unsigned int vector_end)
70589d62be9SMichael S. Tsirkin {
70689d62be9SMichael S. Tsirkin     VirtIOPCIProxy *proxy = container_of(dev, VirtIOPCIProxy, pci_dev);
707a3fc66d9SPaolo Bonzini     VirtIODevice *vdev = virtio_bus_get_device(&proxy->bus);
708181103cdSKONRAD Frederic     VirtioDeviceClass *k = VIRTIO_DEVICE_GET_CLASS(vdev);
70989d62be9SMichael S. Tsirkin     int queue_no;
71089d62be9SMichael S. Tsirkin     unsigned int vector;
71189d62be9SMichael S. Tsirkin     EventNotifier *notifier;
71289d62be9SMichael S. Tsirkin     VirtQueue *vq;
71389d62be9SMichael S. Tsirkin 
7142d620f59SMichael S. Tsirkin     for (queue_no = 0; queue_no < proxy->nvqs_with_notifiers; queue_no++) {
71589d62be9SMichael S. Tsirkin         if (!virtio_queue_get_num(vdev, queue_no)) {
71689d62be9SMichael S. Tsirkin             break;
71789d62be9SMichael S. Tsirkin         }
71889d62be9SMichael S. Tsirkin         vector = virtio_queue_vector(vdev, queue_no);
71989d62be9SMichael S. Tsirkin         if (vector < vector_start || vector >= vector_end ||
72089d62be9SMichael S. Tsirkin             !msix_is_masked(dev, vector)) {
72189d62be9SMichael S. Tsirkin             continue;
72289d62be9SMichael S. Tsirkin         }
72389d62be9SMichael S. Tsirkin         vq = virtio_get_queue(vdev, queue_no);
72489d62be9SMichael S. Tsirkin         notifier = virtio_queue_get_guest_notifier(vq);
725181103cdSKONRAD Frederic         if (k->guest_notifier_pending) {
726181103cdSKONRAD Frederic             if (k->guest_notifier_pending(vdev, queue_no)) {
727f1d0f15aSMichael S. Tsirkin                 msix_set_pending(dev, vector);
728f1d0f15aSMichael S. Tsirkin             }
729f1d0f15aSMichael S. Tsirkin         } else if (event_notifier_test_and_clear(notifier)) {
73089d62be9SMichael S. Tsirkin             msix_set_pending(dev, vector);
73189d62be9SMichael S. Tsirkin         }
73289d62be9SMichael S. Tsirkin     }
73389d62be9SMichael S. Tsirkin }
73489d62be9SMichael S. Tsirkin 
73589d62be9SMichael S. Tsirkin static int virtio_pci_set_guest_notifier(DeviceState *d, int n, bool assign,
73689d62be9SMichael S. Tsirkin                                          bool with_irqfd)
737ade80dc8SMichael S. Tsirkin {
738d2a0ccc6SMichael S. Tsirkin     VirtIOPCIProxy *proxy = to_virtio_pci_proxy(d);
739a3fc66d9SPaolo Bonzini     VirtIODevice *vdev = virtio_bus_get_device(&proxy->bus);
740a3fc66d9SPaolo Bonzini     VirtioDeviceClass *vdc = VIRTIO_DEVICE_GET_CLASS(vdev);
741a3fc66d9SPaolo Bonzini     VirtQueue *vq = virtio_get_queue(vdev, n);
742ade80dc8SMichael S. Tsirkin     EventNotifier *notifier = virtio_queue_get_guest_notifier(vq);
743ade80dc8SMichael S. Tsirkin 
744ade80dc8SMichael S. Tsirkin     if (assign) {
745ade80dc8SMichael S. Tsirkin         int r = event_notifier_init(notifier, 0);
746ade80dc8SMichael S. Tsirkin         if (r < 0) {
747ade80dc8SMichael S. Tsirkin             return r;
748ade80dc8SMichael S. Tsirkin         }
74989d62be9SMichael S. Tsirkin         virtio_queue_set_guest_notifier_fd_handler(vq, true, with_irqfd);
750ade80dc8SMichael S. Tsirkin     } else {
75189d62be9SMichael S. Tsirkin         virtio_queue_set_guest_notifier_fd_handler(vq, false, with_irqfd);
752ade80dc8SMichael S. Tsirkin         event_notifier_cleanup(notifier);
753ade80dc8SMichael S. Tsirkin     }
754ade80dc8SMichael S. Tsirkin 
75562c96360SMichael S. Tsirkin     if (!msix_enabled(&proxy->pci_dev) && vdc->guest_notifier_mask) {
756a3fc66d9SPaolo Bonzini         vdc->guest_notifier_mask(vdev, n, !assign);
75762c96360SMichael S. Tsirkin     }
75862c96360SMichael S. Tsirkin 
759ade80dc8SMichael S. Tsirkin     return 0;
760ade80dc8SMichael S. Tsirkin }
761ade80dc8SMichael S. Tsirkin 
762d2a0ccc6SMichael S. Tsirkin static bool virtio_pci_query_guest_notifiers(DeviceState *d)
7635430a28fSmst@redhat.com {
764d2a0ccc6SMichael S. Tsirkin     VirtIOPCIProxy *proxy = to_virtio_pci_proxy(d);
7655430a28fSmst@redhat.com     return msix_enabled(&proxy->pci_dev);
7665430a28fSmst@redhat.com }
7675430a28fSmst@redhat.com 
7682d620f59SMichael S. Tsirkin static int virtio_pci_set_guest_notifiers(DeviceState *d, int nvqs, bool assign)
76954dd9321SMichael S. Tsirkin {
770d2a0ccc6SMichael S. Tsirkin     VirtIOPCIProxy *proxy = to_virtio_pci_proxy(d);
771a3fc66d9SPaolo Bonzini     VirtIODevice *vdev = virtio_bus_get_device(&proxy->bus);
772181103cdSKONRAD Frederic     VirtioDeviceClass *k = VIRTIO_DEVICE_GET_CLASS(vdev);
77354dd9321SMichael S. Tsirkin     int r, n;
77489d62be9SMichael S. Tsirkin     bool with_irqfd = msix_enabled(&proxy->pci_dev) &&
77589d62be9SMichael S. Tsirkin         kvm_msi_via_irqfd_enabled();
77654dd9321SMichael S. Tsirkin 
77787b3bd1cSJason Wang     nvqs = MIN(nvqs, VIRTIO_QUEUE_MAX);
7782d620f59SMichael S. Tsirkin 
7792d620f59SMichael S. Tsirkin     /* When deassigning, pass a consistent nvqs value
7802d620f59SMichael S. Tsirkin      * to avoid leaking notifiers.
7812d620f59SMichael S. Tsirkin      */
7822d620f59SMichael S. Tsirkin     assert(assign || nvqs == proxy->nvqs_with_notifiers);
7832d620f59SMichael S. Tsirkin 
7842d620f59SMichael S. Tsirkin     proxy->nvqs_with_notifiers = nvqs;
7852d620f59SMichael S. Tsirkin 
7867d37d351SJan Kiszka     /* Must unset vector notifier while guest notifier is still assigned */
787181103cdSKONRAD Frederic     if ((proxy->vector_irqfd || k->guest_notifier_mask) && !assign) {
7887d37d351SJan Kiszka         msix_unset_vector_notifiers(&proxy->pci_dev);
789a38b2c49SMichael S. Tsirkin         if (proxy->vector_irqfd) {
790774345f9SMichael S. Tsirkin             kvm_virtio_pci_vector_release(proxy, nvqs);
7917d37d351SJan Kiszka             g_free(proxy->vector_irqfd);
7927d37d351SJan Kiszka             proxy->vector_irqfd = NULL;
7937d37d351SJan Kiszka         }
794a38b2c49SMichael S. Tsirkin     }
7957d37d351SJan Kiszka 
7962d620f59SMichael S. Tsirkin     for (n = 0; n < nvqs; n++) {
79754dd9321SMichael S. Tsirkin         if (!virtio_queue_get_num(vdev, n)) {
79854dd9321SMichael S. Tsirkin             break;
79954dd9321SMichael S. Tsirkin         }
80054dd9321SMichael S. Tsirkin 
80123fe2b3fSMichael S. Tsirkin         r = virtio_pci_set_guest_notifier(d, n, assign, with_irqfd);
80254dd9321SMichael S. Tsirkin         if (r < 0) {
80354dd9321SMichael S. Tsirkin             goto assign_error;
80454dd9321SMichael S. Tsirkin         }
80554dd9321SMichael S. Tsirkin     }
80654dd9321SMichael S. Tsirkin 
8077d37d351SJan Kiszka     /* Must set vector notifier after guest notifier has been assigned */
808181103cdSKONRAD Frederic     if ((with_irqfd || k->guest_notifier_mask) && assign) {
809a38b2c49SMichael S. Tsirkin         if (with_irqfd) {
8107d37d351SJan Kiszka             proxy->vector_irqfd =
8117d37d351SJan Kiszka                 g_malloc0(sizeof(*proxy->vector_irqfd) *
8127d37d351SJan Kiszka                           msix_nr_vectors_allocated(&proxy->pci_dev));
813774345f9SMichael S. Tsirkin             r = kvm_virtio_pci_vector_use(proxy, nvqs);
8147d37d351SJan Kiszka             if (r < 0) {
8157d37d351SJan Kiszka                 goto assign_error;
8167d37d351SJan Kiszka             }
817a38b2c49SMichael S. Tsirkin         }
818774345f9SMichael S. Tsirkin         r = msix_set_vector_notifiers(&proxy->pci_dev,
819a38b2c49SMichael S. Tsirkin                                       virtio_pci_vector_unmask,
820a38b2c49SMichael S. Tsirkin                                       virtio_pci_vector_mask,
821a38b2c49SMichael S. Tsirkin                                       virtio_pci_vector_poll);
822774345f9SMichael S. Tsirkin         if (r < 0) {
823774345f9SMichael S. Tsirkin             goto notifiers_error;
824774345f9SMichael S. Tsirkin         }
8257d37d351SJan Kiszka     }
8267d37d351SJan Kiszka 
82754dd9321SMichael S. Tsirkin     return 0;
82854dd9321SMichael S. Tsirkin 
829774345f9SMichael S. Tsirkin notifiers_error:
830a38b2c49SMichael S. Tsirkin     if (with_irqfd) {
831774345f9SMichael S. Tsirkin         assert(assign);
832774345f9SMichael S. Tsirkin         kvm_virtio_pci_vector_release(proxy, nvqs);
833a38b2c49SMichael S. Tsirkin     }
834774345f9SMichael S. Tsirkin 
83554dd9321SMichael S. Tsirkin assign_error:
83654dd9321SMichael S. Tsirkin     /* We get here on assignment failure. Recover by undoing for VQs 0 .. n. */
8377d37d351SJan Kiszka     assert(assign);
83854dd9321SMichael S. Tsirkin     while (--n >= 0) {
83989d62be9SMichael S. Tsirkin         virtio_pci_set_guest_notifier(d, n, !assign, with_irqfd);
84054dd9321SMichael S. Tsirkin     }
84154dd9321SMichael S. Tsirkin     return r;
84254dd9321SMichael S. Tsirkin }
84354dd9321SMichael S. Tsirkin 
844d2a0ccc6SMichael S. Tsirkin static int virtio_pci_set_host_notifier(DeviceState *d, int n, bool assign)
845ade80dc8SMichael S. Tsirkin {
846d2a0ccc6SMichael S. Tsirkin     VirtIOPCIProxy *proxy = to_virtio_pci_proxy(d);
84725db9ebeSStefan Hajnoczi 
84825db9ebeSStefan Hajnoczi     /* Stop using ioeventfd for virtqueue kick if the device starts using host
84925db9ebeSStefan Hajnoczi      * notifiers.  This makes it easy to avoid stepping on each others' toes.
85025db9ebeSStefan Hajnoczi      */
85125db9ebeSStefan Hajnoczi     proxy->ioeventfd_disabled = assign;
852ade80dc8SMichael S. Tsirkin     if (assign) {
85325db9ebeSStefan Hajnoczi         virtio_pci_stop_ioeventfd(proxy);
854ade80dc8SMichael S. Tsirkin     }
85525db9ebeSStefan Hajnoczi     /* We don't need to start here: it's not needed because backend
85625db9ebeSStefan Hajnoczi      * currently only stops on status change away from ok,
85725db9ebeSStefan Hajnoczi      * reset, vmstop and such. If we do add code to start here,
85825db9ebeSStefan Hajnoczi      * need to check vmstate, device state etc. */
85926b9b5feSPaolo Bonzini     return virtio_pci_set_host_notifier_internal(proxy, n, assign, false);
860ade80dc8SMichael S. Tsirkin }
86125db9ebeSStefan Hajnoczi 
862d2a0ccc6SMichael S. Tsirkin static void virtio_pci_vmstate_change(DeviceState *d, bool running)
86325db9ebeSStefan Hajnoczi {
864d2a0ccc6SMichael S. Tsirkin     VirtIOPCIProxy *proxy = to_virtio_pci_proxy(d);
865a3fc66d9SPaolo Bonzini     VirtIODevice *vdev = virtio_bus_get_device(&proxy->bus);
86625db9ebeSStefan Hajnoczi 
86725db9ebeSStefan Hajnoczi     if (running) {
86868a27b20SMichael S. Tsirkin         /* Old QEMU versions did not set bus master enable on status write.
86968a27b20SMichael S. Tsirkin          * Detect DRIVER set and enable it.
87068a27b20SMichael S. Tsirkin          */
87168a27b20SMichael S. Tsirkin         if ((proxy->flags & VIRTIO_PCI_FLAG_BUS_MASTER_BUG_MIGRATION) &&
87268a27b20SMichael S. Tsirkin             (vdev->status & VIRTIO_CONFIG_S_DRIVER) &&
87345363e46SMichael S. Tsirkin             !(proxy->pci_dev.config[PCI_COMMAND] & PCI_COMMAND_MASTER)) {
87468a27b20SMichael S. Tsirkin             pci_default_write_config(&proxy->pci_dev, PCI_COMMAND,
87568a27b20SMichael S. Tsirkin                                      proxy->pci_dev.config[PCI_COMMAND] |
87668a27b20SMichael S. Tsirkin                                      PCI_COMMAND_MASTER, 1);
87789c473fdSMichael S. Tsirkin         }
87825db9ebeSStefan Hajnoczi         virtio_pci_start_ioeventfd(proxy);
879ade80dc8SMichael S. Tsirkin     } else {
88025db9ebeSStefan Hajnoczi         virtio_pci_stop_ioeventfd(proxy);
881ade80dc8SMichael S. Tsirkin     }
882ade80dc8SMichael S. Tsirkin }
883ade80dc8SMichael S. Tsirkin 
88460653b28SPaolo Bonzini #ifdef CONFIG_VIRTFS
885fc079951SMarkus Armbruster static void virtio_9p_pci_realize(VirtIOPCIProxy *vpci_dev, Error **errp)
88660653b28SPaolo Bonzini {
887234a336fSKONRAD Frederic     V9fsPCIState *dev = VIRTIO_9P_PCI(vpci_dev);
888234a336fSKONRAD Frederic     DeviceState *vdev = DEVICE(&dev->vdev);
88960653b28SPaolo Bonzini 
890234a336fSKONRAD Frederic     qdev_set_parent_bus(vdev, BUS(&vpci_dev->bus));
891fc079951SMarkus Armbruster     object_property_set_bool(OBJECT(vdev), true, "realized", errp);
89260653b28SPaolo Bonzini }
89360653b28SPaolo Bonzini 
894234a336fSKONRAD Frederic static Property virtio_9p_pci_properties[] = {
895234a336fSKONRAD Frederic     DEFINE_PROP_BIT("ioeventfd", VirtIOPCIProxy, flags,
896234a336fSKONRAD Frederic                     VIRTIO_PCI_FLAG_USE_IOEVENTFD_BIT, true),
89760653b28SPaolo Bonzini     DEFINE_PROP_UINT32("vectors", VirtIOPCIProxy, nvectors, 2),
89860653b28SPaolo Bonzini     DEFINE_PROP_END_OF_LIST(),
89960653b28SPaolo Bonzini };
90060653b28SPaolo Bonzini 
901234a336fSKONRAD Frederic static void virtio_9p_pci_class_init(ObjectClass *klass, void *data)
90260653b28SPaolo Bonzini {
90360653b28SPaolo Bonzini     DeviceClass *dc = DEVICE_CLASS(klass);
904234a336fSKONRAD Frederic     PCIDeviceClass *pcidev_k = PCI_DEVICE_CLASS(klass);
905234a336fSKONRAD Frederic     VirtioPCIClass *k = VIRTIO_PCI_CLASS(klass);
90660653b28SPaolo Bonzini 
907fc079951SMarkus Armbruster     k->realize = virtio_9p_pci_realize;
908234a336fSKONRAD Frederic     pcidev_k->vendor_id = PCI_VENDOR_ID_REDHAT_QUMRANET;
909234a336fSKONRAD Frederic     pcidev_k->device_id = PCI_DEVICE_ID_VIRTIO_9P;
910234a336fSKONRAD Frederic     pcidev_k->revision = VIRTIO_PCI_ABI_VERSION;
911234a336fSKONRAD Frederic     pcidev_k->class_id = 0x2;
912125ee0edSMarcel Apfelbaum     set_bit(DEVICE_CATEGORY_STORAGE, dc->categories);
913234a336fSKONRAD Frederic     dc->props = virtio_9p_pci_properties;
91460653b28SPaolo Bonzini }
91560653b28SPaolo Bonzini 
916234a336fSKONRAD Frederic static void virtio_9p_pci_instance_init(Object *obj)
917234a336fSKONRAD Frederic {
918234a336fSKONRAD Frederic     V9fsPCIState *dev = VIRTIO_9P_PCI(obj);
919c8075cafSGonglei 
920c8075cafSGonglei     virtio_instance_init_common(obj, &dev->vdev, sizeof(dev->vdev),
921c8075cafSGonglei                                 TYPE_VIRTIO_9P);
922234a336fSKONRAD Frederic }
923234a336fSKONRAD Frederic 
924234a336fSKONRAD Frederic static const TypeInfo virtio_9p_pci_info = {
925234a336fSKONRAD Frederic     .name          = TYPE_VIRTIO_9P_PCI,
926234a336fSKONRAD Frederic     .parent        = TYPE_VIRTIO_PCI,
927234a336fSKONRAD Frederic     .instance_size = sizeof(V9fsPCIState),
928234a336fSKONRAD Frederic     .instance_init = virtio_9p_pci_instance_init,
929234a336fSKONRAD Frederic     .class_init    = virtio_9p_pci_class_init,
93060653b28SPaolo Bonzini };
931234a336fSKONRAD Frederic #endif /* CONFIG_VIRTFS */
93260653b28SPaolo Bonzini 
933085bccb7SKONRAD Frederic /*
934085bccb7SKONRAD Frederic  * virtio-pci: This is the PCIDevice which has a virtio-pci-bus.
935085bccb7SKONRAD Frederic  */
936085bccb7SKONRAD Frederic 
937e0d686bfSJason Wang static int virtio_pci_query_nvectors(DeviceState *d)
938e0d686bfSJason Wang {
939e0d686bfSJason Wang     VirtIOPCIProxy *proxy = VIRTIO_PCI(d);
940e0d686bfSJason Wang 
941e0d686bfSJason Wang     return proxy->nvectors;
942e0d686bfSJason Wang }
943e0d686bfSJason Wang 
944dfb8e184SMichael S. Tsirkin static void virtio_pci_add_mem_cap(VirtIOPCIProxy *proxy,
945dfb8e184SMichael S. Tsirkin                                    struct virtio_pci_cap *cap)
946dfb8e184SMichael S. Tsirkin {
947dfb8e184SMichael S. Tsirkin     PCIDevice *dev = &proxy->pci_dev;
948dfb8e184SMichael S. Tsirkin     int offset;
949dfb8e184SMichael S. Tsirkin 
950dfb8e184SMichael S. Tsirkin     offset = pci_add_capability(dev, PCI_CAP_ID_VNDR, 0, cap->cap_len);
951dfb8e184SMichael S. Tsirkin     assert(offset > 0);
952dfb8e184SMichael S. Tsirkin 
953dfb8e184SMichael S. Tsirkin     assert(cap->cap_len >= sizeof *cap);
954dfb8e184SMichael S. Tsirkin     memcpy(dev->config + offset + PCI_CAP_FLAGS, &cap->cap_len,
955dfb8e184SMichael S. Tsirkin            cap->cap_len - PCI_CAP_FLAGS);
956dfb8e184SMichael S. Tsirkin }
957dfb8e184SMichael S. Tsirkin 
958dfb8e184SMichael S. Tsirkin static uint64_t virtio_pci_common_read(void *opaque, hwaddr addr,
959dfb8e184SMichael S. Tsirkin                                        unsigned size)
960dfb8e184SMichael S. Tsirkin {
961dfb8e184SMichael S. Tsirkin     VirtIOPCIProxy *proxy = opaque;
962dfb8e184SMichael S. Tsirkin     VirtIODevice *vdev = virtio_bus_get_device(&proxy->bus);
963dfb8e184SMichael S. Tsirkin     uint32_t val = 0;
964dfb8e184SMichael S. Tsirkin     int i;
965dfb8e184SMichael S. Tsirkin 
966dfb8e184SMichael S. Tsirkin     switch (addr) {
967dfb8e184SMichael S. Tsirkin     case VIRTIO_PCI_COMMON_DFSELECT:
968dfb8e184SMichael S. Tsirkin         val = proxy->dfselect;
969dfb8e184SMichael S. Tsirkin         break;
970dfb8e184SMichael S. Tsirkin     case VIRTIO_PCI_COMMON_DF:
971dfb8e184SMichael S. Tsirkin         if (proxy->dfselect <= 1) {
972dfb8e184SMichael S. Tsirkin             val = vdev->host_features >> (32 * proxy->dfselect);
973dfb8e184SMichael S. Tsirkin         }
974dfb8e184SMichael S. Tsirkin         break;
975dfb8e184SMichael S. Tsirkin     case VIRTIO_PCI_COMMON_GFSELECT:
976dfb8e184SMichael S. Tsirkin         val = proxy->gfselect;
977dfb8e184SMichael S. Tsirkin         break;
978dfb8e184SMichael S. Tsirkin     case VIRTIO_PCI_COMMON_GF:
979dfb8e184SMichael S. Tsirkin         if (proxy->gfselect <= ARRAY_SIZE(proxy->guest_features)) {
980dfb8e184SMichael S. Tsirkin             val = proxy->guest_features[proxy->gfselect];
981dfb8e184SMichael S. Tsirkin         }
982dfb8e184SMichael S. Tsirkin         break;
983dfb8e184SMichael S. Tsirkin     case VIRTIO_PCI_COMMON_MSIX:
984dfb8e184SMichael S. Tsirkin         val = vdev->config_vector;
985dfb8e184SMichael S. Tsirkin         break;
986dfb8e184SMichael S. Tsirkin     case VIRTIO_PCI_COMMON_NUMQ:
987dfb8e184SMichael S. Tsirkin         for (i = 0; i < VIRTIO_QUEUE_MAX; ++i) {
988dfb8e184SMichael S. Tsirkin             if (virtio_queue_get_num(vdev, i)) {
989dfb8e184SMichael S. Tsirkin                 val = i + 1;
990dfb8e184SMichael S. Tsirkin             }
991dfb8e184SMichael S. Tsirkin         }
992dfb8e184SMichael S. Tsirkin         break;
993dfb8e184SMichael S. Tsirkin     case VIRTIO_PCI_COMMON_STATUS:
994dfb8e184SMichael S. Tsirkin         val = vdev->status;
995dfb8e184SMichael S. Tsirkin         break;
996dfb8e184SMichael S. Tsirkin     case VIRTIO_PCI_COMMON_CFGGENERATION:
997b8f05908SMichael S. Tsirkin         val = vdev->generation;
998dfb8e184SMichael S. Tsirkin         break;
999dfb8e184SMichael S. Tsirkin     case VIRTIO_PCI_COMMON_Q_SELECT:
1000dfb8e184SMichael S. Tsirkin         val = vdev->queue_sel;
1001dfb8e184SMichael S. Tsirkin         break;
1002dfb8e184SMichael S. Tsirkin     case VIRTIO_PCI_COMMON_Q_SIZE:
1003dfb8e184SMichael S. Tsirkin         val = virtio_queue_get_num(vdev, vdev->queue_sel);
1004dfb8e184SMichael S. Tsirkin         break;
1005dfb8e184SMichael S. Tsirkin     case VIRTIO_PCI_COMMON_Q_MSIX:
1006dfb8e184SMichael S. Tsirkin         val = virtio_queue_vector(vdev, vdev->queue_sel);
1007dfb8e184SMichael S. Tsirkin         break;
1008dfb8e184SMichael S. Tsirkin     case VIRTIO_PCI_COMMON_Q_ENABLE:
1009dfb8e184SMichael S. Tsirkin         val = proxy->vqs[vdev->queue_sel].enabled;
1010dfb8e184SMichael S. Tsirkin         break;
1011dfb8e184SMichael S. Tsirkin     case VIRTIO_PCI_COMMON_Q_NOFF:
1012dfb8e184SMichael S. Tsirkin         /* Simply map queues in order */
1013dfb8e184SMichael S. Tsirkin         val = vdev->queue_sel;
1014dfb8e184SMichael S. Tsirkin         break;
1015dfb8e184SMichael S. Tsirkin     case VIRTIO_PCI_COMMON_Q_DESCLO:
1016dfb8e184SMichael S. Tsirkin         val = proxy->vqs[vdev->queue_sel].desc[0];
1017dfb8e184SMichael S. Tsirkin         break;
1018dfb8e184SMichael S. Tsirkin     case VIRTIO_PCI_COMMON_Q_DESCHI:
1019dfb8e184SMichael S. Tsirkin         val = proxy->vqs[vdev->queue_sel].desc[1];
1020dfb8e184SMichael S. Tsirkin         break;
1021dfb8e184SMichael S. Tsirkin     case VIRTIO_PCI_COMMON_Q_AVAILLO:
1022dfb8e184SMichael S. Tsirkin         val = proxy->vqs[vdev->queue_sel].avail[0];
1023dfb8e184SMichael S. Tsirkin         break;
1024dfb8e184SMichael S. Tsirkin     case VIRTIO_PCI_COMMON_Q_AVAILHI:
1025dfb8e184SMichael S. Tsirkin         val = proxy->vqs[vdev->queue_sel].avail[1];
1026dfb8e184SMichael S. Tsirkin         break;
1027dfb8e184SMichael S. Tsirkin     case VIRTIO_PCI_COMMON_Q_USEDLO:
1028dfb8e184SMichael S. Tsirkin         val = proxy->vqs[vdev->queue_sel].used[0];
1029dfb8e184SMichael S. Tsirkin         break;
1030dfb8e184SMichael S. Tsirkin     case VIRTIO_PCI_COMMON_Q_USEDHI:
1031dfb8e184SMichael S. Tsirkin         val = proxy->vqs[vdev->queue_sel].used[1];
1032dfb8e184SMichael S. Tsirkin         break;
1033dfb8e184SMichael S. Tsirkin     default:
1034dfb8e184SMichael S. Tsirkin         val = 0;
1035dfb8e184SMichael S. Tsirkin     }
1036dfb8e184SMichael S. Tsirkin 
1037dfb8e184SMichael S. Tsirkin     return val;
1038dfb8e184SMichael S. Tsirkin }
1039dfb8e184SMichael S. Tsirkin 
1040dfb8e184SMichael S. Tsirkin static void virtio_pci_common_write(void *opaque, hwaddr addr,
1041dfb8e184SMichael S. Tsirkin                                     uint64_t val, unsigned size)
1042dfb8e184SMichael S. Tsirkin {
1043dfb8e184SMichael S. Tsirkin     VirtIOPCIProxy *proxy = opaque;
1044dfb8e184SMichael S. Tsirkin     VirtIODevice *vdev = virtio_bus_get_device(&proxy->bus);
1045dfb8e184SMichael S. Tsirkin 
1046dfb8e184SMichael S. Tsirkin     switch (addr) {
1047dfb8e184SMichael S. Tsirkin     case VIRTIO_PCI_COMMON_DFSELECT:
1048dfb8e184SMichael S. Tsirkin         proxy->dfselect = val;
1049dfb8e184SMichael S. Tsirkin         break;
1050dfb8e184SMichael S. Tsirkin     case VIRTIO_PCI_COMMON_GFSELECT:
1051dfb8e184SMichael S. Tsirkin         proxy->gfselect = val;
1052dfb8e184SMichael S. Tsirkin         break;
1053dfb8e184SMichael S. Tsirkin     case VIRTIO_PCI_COMMON_GF:
1054dfb8e184SMichael S. Tsirkin         if (proxy->gfselect <= ARRAY_SIZE(proxy->guest_features)) {
1055dfb8e184SMichael S. Tsirkin             proxy->guest_features[proxy->gfselect] = val;
1056dfb8e184SMichael S. Tsirkin             virtio_set_features(vdev,
1057dfb8e184SMichael S. Tsirkin                                 (((uint64_t)proxy->guest_features[1]) << 32) |
1058dfb8e184SMichael S. Tsirkin                                 proxy->guest_features[0]);
1059dfb8e184SMichael S. Tsirkin         }
1060dfb8e184SMichael S. Tsirkin         break;
1061dfb8e184SMichael S. Tsirkin     case VIRTIO_PCI_COMMON_MSIX:
1062dfb8e184SMichael S. Tsirkin         msix_vector_unuse(&proxy->pci_dev, vdev->config_vector);
1063dfb8e184SMichael S. Tsirkin         /* Make it possible for guest to discover an error took place. */
1064dfb8e184SMichael S. Tsirkin         if (msix_vector_use(&proxy->pci_dev, val) < 0) {
1065dfb8e184SMichael S. Tsirkin             val = VIRTIO_NO_VECTOR;
1066dfb8e184SMichael S. Tsirkin         }
1067dfb8e184SMichael S. Tsirkin         vdev->config_vector = val;
1068dfb8e184SMichael S. Tsirkin         break;
1069dfb8e184SMichael S. Tsirkin     case VIRTIO_PCI_COMMON_STATUS:
1070dfb8e184SMichael S. Tsirkin         if (!(val & VIRTIO_CONFIG_S_DRIVER_OK)) {
1071dfb8e184SMichael S. Tsirkin             virtio_pci_stop_ioeventfd(proxy);
1072dfb8e184SMichael S. Tsirkin         }
1073dfb8e184SMichael S. Tsirkin 
1074dfb8e184SMichael S. Tsirkin         virtio_set_status(vdev, val & 0xFF);
1075dfb8e184SMichael S. Tsirkin 
1076dfb8e184SMichael S. Tsirkin         if (val & VIRTIO_CONFIG_S_DRIVER_OK) {
1077dfb8e184SMichael S. Tsirkin             virtio_pci_start_ioeventfd(proxy);
1078dfb8e184SMichael S. Tsirkin         }
1079dfb8e184SMichael S. Tsirkin 
1080dfb8e184SMichael S. Tsirkin         if (vdev->status == 0) {
1081dfb8e184SMichael S. Tsirkin             virtio_reset(vdev);
1082dfb8e184SMichael S. Tsirkin             msix_unuse_all_vectors(&proxy->pci_dev);
1083dfb8e184SMichael S. Tsirkin         }
1084dfb8e184SMichael S. Tsirkin 
1085dfb8e184SMichael S. Tsirkin         break;
1086dfb8e184SMichael S. Tsirkin     case VIRTIO_PCI_COMMON_Q_SELECT:
1087dfb8e184SMichael S. Tsirkin         if (val < VIRTIO_QUEUE_MAX) {
1088dfb8e184SMichael S. Tsirkin             vdev->queue_sel = val;
1089dfb8e184SMichael S. Tsirkin         }
1090dfb8e184SMichael S. Tsirkin         break;
1091dfb8e184SMichael S. Tsirkin     case VIRTIO_PCI_COMMON_Q_SIZE:
1092dfb8e184SMichael S. Tsirkin         proxy->vqs[vdev->queue_sel].num = val;
1093dfb8e184SMichael S. Tsirkin         break;
1094dfb8e184SMichael S. Tsirkin     case VIRTIO_PCI_COMMON_Q_MSIX:
1095dfb8e184SMichael S. Tsirkin         msix_vector_unuse(&proxy->pci_dev,
1096dfb8e184SMichael S. Tsirkin                           virtio_queue_vector(vdev, vdev->queue_sel));
1097dfb8e184SMichael S. Tsirkin         /* Make it possible for guest to discover an error took place. */
1098dfb8e184SMichael S. Tsirkin         if (msix_vector_use(&proxy->pci_dev, val) < 0) {
1099dfb8e184SMichael S. Tsirkin             val = VIRTIO_NO_VECTOR;
1100dfb8e184SMichael S. Tsirkin         }
1101dfb8e184SMichael S. Tsirkin         virtio_queue_set_vector(vdev, vdev->queue_sel, val);
1102dfb8e184SMichael S. Tsirkin         break;
1103dfb8e184SMichael S. Tsirkin     case VIRTIO_PCI_COMMON_Q_ENABLE:
1104dfb8e184SMichael S. Tsirkin         /* TODO: need a way to put num back on reset. */
1105dfb8e184SMichael S. Tsirkin         virtio_queue_set_num(vdev, vdev->queue_sel,
1106dfb8e184SMichael S. Tsirkin                              proxy->vqs[vdev->queue_sel].num);
1107dfb8e184SMichael S. Tsirkin         virtio_queue_set_rings(vdev, vdev->queue_sel,
1108dfb8e184SMichael S. Tsirkin                        ((uint64_t)proxy->vqs[vdev->queue_sel].desc[1]) << 32 |
1109dfb8e184SMichael S. Tsirkin                        proxy->vqs[vdev->queue_sel].desc[0],
1110dfb8e184SMichael S. Tsirkin                        ((uint64_t)proxy->vqs[vdev->queue_sel].avail[1]) << 32 |
1111dfb8e184SMichael S. Tsirkin                        proxy->vqs[vdev->queue_sel].avail[0],
1112dfb8e184SMichael S. Tsirkin                        ((uint64_t)proxy->vqs[vdev->queue_sel].used[1]) << 32 |
1113dfb8e184SMichael S. Tsirkin                        proxy->vqs[vdev->queue_sel].used[0]);
1114dfb8e184SMichael S. Tsirkin         break;
1115dfb8e184SMichael S. Tsirkin     case VIRTIO_PCI_COMMON_Q_DESCLO:
1116dfb8e184SMichael S. Tsirkin         proxy->vqs[vdev->queue_sel].desc[0] = val;
1117dfb8e184SMichael S. Tsirkin         break;
1118dfb8e184SMichael S. Tsirkin     case VIRTIO_PCI_COMMON_Q_DESCHI:
1119dfb8e184SMichael S. Tsirkin         proxy->vqs[vdev->queue_sel].desc[1] = val;
1120dfb8e184SMichael S. Tsirkin         break;
1121dfb8e184SMichael S. Tsirkin     case VIRTIO_PCI_COMMON_Q_AVAILLO:
1122dfb8e184SMichael S. Tsirkin         proxy->vqs[vdev->queue_sel].avail[0] = val;
1123dfb8e184SMichael S. Tsirkin         break;
1124dfb8e184SMichael S. Tsirkin     case VIRTIO_PCI_COMMON_Q_AVAILHI:
1125dfb8e184SMichael S. Tsirkin         proxy->vqs[vdev->queue_sel].avail[1] = val;
1126dfb8e184SMichael S. Tsirkin         break;
1127dfb8e184SMichael S. Tsirkin     case VIRTIO_PCI_COMMON_Q_USEDLO:
1128dfb8e184SMichael S. Tsirkin         proxy->vqs[vdev->queue_sel].used[0] = val;
1129dfb8e184SMichael S. Tsirkin         break;
1130dfb8e184SMichael S. Tsirkin     case VIRTIO_PCI_COMMON_Q_USEDHI:
1131dfb8e184SMichael S. Tsirkin         proxy->vqs[vdev->queue_sel].used[1] = val;
1132dfb8e184SMichael S. Tsirkin         break;
1133dfb8e184SMichael S. Tsirkin     default:
1134dfb8e184SMichael S. Tsirkin         break;
1135dfb8e184SMichael S. Tsirkin     }
1136dfb8e184SMichael S. Tsirkin }
1137dfb8e184SMichael S. Tsirkin 
1138dfb8e184SMichael S. Tsirkin 
1139dfb8e184SMichael S. Tsirkin static uint64_t virtio_pci_notify_read(void *opaque, hwaddr addr,
1140dfb8e184SMichael S. Tsirkin                                        unsigned size)
1141dfb8e184SMichael S. Tsirkin {
1142dfb8e184SMichael S. Tsirkin     return 0;
1143dfb8e184SMichael S. Tsirkin }
1144dfb8e184SMichael S. Tsirkin 
1145dfb8e184SMichael S. Tsirkin static void virtio_pci_notify_write(void *opaque, hwaddr addr,
1146dfb8e184SMichael S. Tsirkin                                     uint64_t val, unsigned size)
1147dfb8e184SMichael S. Tsirkin {
1148dfb8e184SMichael S. Tsirkin     VirtIODevice *vdev = opaque;
1149dfb8e184SMichael S. Tsirkin     unsigned queue = addr / QEMU_VIRTIO_PCI_QUEUE_MEM_MULT;
1150dfb8e184SMichael S. Tsirkin 
1151dfb8e184SMichael S. Tsirkin     if (queue < VIRTIO_QUEUE_MAX) {
1152dfb8e184SMichael S. Tsirkin         virtio_queue_notify(vdev, queue);
1153dfb8e184SMichael S. Tsirkin     }
1154dfb8e184SMichael S. Tsirkin }
1155dfb8e184SMichael S. Tsirkin 
1156dfb8e184SMichael S. Tsirkin static uint64_t virtio_pci_isr_read(void *opaque, hwaddr addr,
1157dfb8e184SMichael S. Tsirkin                                     unsigned size)
1158dfb8e184SMichael S. Tsirkin {
1159dfb8e184SMichael S. Tsirkin     VirtIOPCIProxy *proxy = opaque;
1160dfb8e184SMichael S. Tsirkin     VirtIODevice *vdev = virtio_bus_get_device(&proxy->bus);
1161dfb8e184SMichael S. Tsirkin     uint64_t val = vdev->isr;
1162dfb8e184SMichael S. Tsirkin 
1163dfb8e184SMichael S. Tsirkin     vdev->isr = 0;
1164dfb8e184SMichael S. Tsirkin     pci_irq_deassert(&proxy->pci_dev);
1165dfb8e184SMichael S. Tsirkin 
1166dfb8e184SMichael S. Tsirkin     return val;
1167dfb8e184SMichael S. Tsirkin }
1168dfb8e184SMichael S. Tsirkin 
1169dfb8e184SMichael S. Tsirkin static void virtio_pci_isr_write(void *opaque, hwaddr addr,
1170dfb8e184SMichael S. Tsirkin                                  uint64_t val, unsigned size)
1171dfb8e184SMichael S. Tsirkin {
1172dfb8e184SMichael S. Tsirkin }
1173dfb8e184SMichael S. Tsirkin 
1174dfb8e184SMichael S. Tsirkin static uint64_t virtio_pci_device_read(void *opaque, hwaddr addr,
1175dfb8e184SMichael S. Tsirkin                                        unsigned size)
1176dfb8e184SMichael S. Tsirkin {
1177dfb8e184SMichael S. Tsirkin     VirtIODevice *vdev = opaque;
1178dfb8e184SMichael S. Tsirkin     uint64_t val = 0;
1179dfb8e184SMichael S. Tsirkin 
1180dfb8e184SMichael S. Tsirkin     switch (size) {
1181dfb8e184SMichael S. Tsirkin     case 1:
118254c720d4SMichael S. Tsirkin         val = virtio_config_modern_readb(vdev, addr);
1183dfb8e184SMichael S. Tsirkin         break;
1184dfb8e184SMichael S. Tsirkin     case 2:
118554c720d4SMichael S. Tsirkin         val = virtio_config_modern_readw(vdev, addr);
1186dfb8e184SMichael S. Tsirkin         break;
1187dfb8e184SMichael S. Tsirkin     case 4:
118854c720d4SMichael S. Tsirkin         val = virtio_config_modern_readl(vdev, addr);
1189dfb8e184SMichael S. Tsirkin         break;
1190dfb8e184SMichael S. Tsirkin     }
1191dfb8e184SMichael S. Tsirkin     return val;
1192dfb8e184SMichael S. Tsirkin }
1193dfb8e184SMichael S. Tsirkin 
1194dfb8e184SMichael S. Tsirkin static void virtio_pci_device_write(void *opaque, hwaddr addr,
1195dfb8e184SMichael S. Tsirkin                                     uint64_t val, unsigned size)
1196dfb8e184SMichael S. Tsirkin {
1197dfb8e184SMichael S. Tsirkin     VirtIODevice *vdev = opaque;
1198dfb8e184SMichael S. Tsirkin     switch (size) {
1199dfb8e184SMichael S. Tsirkin     case 1:
120054c720d4SMichael S. Tsirkin         virtio_config_modern_writeb(vdev, addr, val);
1201dfb8e184SMichael S. Tsirkin         break;
1202dfb8e184SMichael S. Tsirkin     case 2:
120354c720d4SMichael S. Tsirkin         virtio_config_modern_writew(vdev, addr, val);
1204dfb8e184SMichael S. Tsirkin         break;
1205dfb8e184SMichael S. Tsirkin     case 4:
120654c720d4SMichael S. Tsirkin         virtio_config_modern_writel(vdev, addr, val);
1207dfb8e184SMichael S. Tsirkin         break;
1208dfb8e184SMichael S. Tsirkin     }
1209dfb8e184SMichael S. Tsirkin }
1210dfb8e184SMichael S. Tsirkin 
1211*1141ce21SGerd Hoffmann static void virtio_pci_modern_regions_init(VirtIOPCIProxy *proxy)
1212*1141ce21SGerd Hoffmann {
1213*1141ce21SGerd Hoffmann     static const MemoryRegionOps common_ops = {
1214*1141ce21SGerd Hoffmann         .read = virtio_pci_common_read,
1215*1141ce21SGerd Hoffmann         .write = virtio_pci_common_write,
1216*1141ce21SGerd Hoffmann         .impl = {
1217*1141ce21SGerd Hoffmann             .min_access_size = 1,
1218*1141ce21SGerd Hoffmann             .max_access_size = 4,
1219*1141ce21SGerd Hoffmann         },
1220*1141ce21SGerd Hoffmann         .endianness = DEVICE_LITTLE_ENDIAN,
1221*1141ce21SGerd Hoffmann     };
1222*1141ce21SGerd Hoffmann     static const MemoryRegionOps isr_ops = {
1223*1141ce21SGerd Hoffmann         .read = virtio_pci_isr_read,
1224*1141ce21SGerd Hoffmann         .write = virtio_pci_isr_write,
1225*1141ce21SGerd Hoffmann         .impl = {
1226*1141ce21SGerd Hoffmann             .min_access_size = 1,
1227*1141ce21SGerd Hoffmann             .max_access_size = 4,
1228*1141ce21SGerd Hoffmann         },
1229*1141ce21SGerd Hoffmann         .endianness = DEVICE_LITTLE_ENDIAN,
1230*1141ce21SGerd Hoffmann     };
1231*1141ce21SGerd Hoffmann     static const MemoryRegionOps device_ops = {
1232*1141ce21SGerd Hoffmann         .read = virtio_pci_device_read,
1233*1141ce21SGerd Hoffmann         .write = virtio_pci_device_write,
1234*1141ce21SGerd Hoffmann         .impl = {
1235*1141ce21SGerd Hoffmann             .min_access_size = 1,
1236*1141ce21SGerd Hoffmann             .max_access_size = 4,
1237*1141ce21SGerd Hoffmann         },
1238*1141ce21SGerd Hoffmann         .endianness = DEVICE_LITTLE_ENDIAN,
1239*1141ce21SGerd Hoffmann     };
1240*1141ce21SGerd Hoffmann     static const MemoryRegionOps notify_ops = {
1241*1141ce21SGerd Hoffmann         .read = virtio_pci_notify_read,
1242*1141ce21SGerd Hoffmann         .write = virtio_pci_notify_write,
1243*1141ce21SGerd Hoffmann         .impl = {
1244*1141ce21SGerd Hoffmann             .min_access_size = 1,
1245*1141ce21SGerd Hoffmann             .max_access_size = 4,
1246*1141ce21SGerd Hoffmann         },
1247*1141ce21SGerd Hoffmann         .endianness = DEVICE_LITTLE_ENDIAN,
1248*1141ce21SGerd Hoffmann     };
1249*1141ce21SGerd Hoffmann 
1250*1141ce21SGerd Hoffmann     memory_region_init_io(&proxy->common.mr, OBJECT(proxy),
1251*1141ce21SGerd Hoffmann                           &common_ops,
1252*1141ce21SGerd Hoffmann                           proxy,
1253*1141ce21SGerd Hoffmann                           "virtio-pci-common", 0x1000);
1254*1141ce21SGerd Hoffmann     memory_region_init_io(&proxy->isr.mr, OBJECT(proxy),
1255*1141ce21SGerd Hoffmann                           &isr_ops,
1256*1141ce21SGerd Hoffmann                           proxy,
1257*1141ce21SGerd Hoffmann                           "virtio-pci-isr", 0x1000);
1258*1141ce21SGerd Hoffmann     memory_region_init_io(&proxy->device.mr, OBJECT(proxy),
1259*1141ce21SGerd Hoffmann                           &device_ops,
1260*1141ce21SGerd Hoffmann                           virtio_bus_get_device(&proxy->bus),
1261*1141ce21SGerd Hoffmann                           "virtio-pci-device", 0x1000);
1262*1141ce21SGerd Hoffmann     memory_region_init_io(&proxy->notify.mr, OBJECT(proxy),
1263*1141ce21SGerd Hoffmann                           &notify_ops,
1264*1141ce21SGerd Hoffmann                           virtio_bus_get_device(&proxy->bus),
1265*1141ce21SGerd Hoffmann                           "virtio-pci-notify",
1266*1141ce21SGerd Hoffmann                           QEMU_VIRTIO_PCI_QUEUE_MEM_MULT *
1267*1141ce21SGerd Hoffmann                           VIRTIO_QUEUE_MAX);
1268*1141ce21SGerd Hoffmann }
1269dfb8e184SMichael S. Tsirkin 
1270085bccb7SKONRAD Frederic /* This is called by virtio-bus just after the device is plugged. */
1271e8398045SJason Wang static void virtio_pci_device_plugged(DeviceState *d, Error **errp)
1272085bccb7SKONRAD Frederic {
1273085bccb7SKONRAD Frederic     VirtIOPCIProxy *proxy = VIRTIO_PCI(d);
1274085bccb7SKONRAD Frederic     VirtioBusState *bus = &proxy->bus;
1275e266d421SGerd Hoffmann     bool legacy = !(proxy->flags & VIRTIO_PCI_FLAG_DISABLE_LEGACY);
1276e266d421SGerd Hoffmann     bool modern = !(proxy->flags & VIRTIO_PCI_FLAG_DISABLE_MODERN);
1277085bccb7SKONRAD Frederic     uint8_t *config;
1278085bccb7SKONRAD Frederic     uint32_t size;
12796b8f1020SCornelia Huck     VirtIODevice *vdev = virtio_bus_get_device(&proxy->bus);
1280085bccb7SKONRAD Frederic 
128123c5e397SGerd Hoffmann     /*
128223c5e397SGerd Hoffmann      * virtio pci bar layout
128323c5e397SGerd Hoffmann      *
128423c5e397SGerd Hoffmann      *   region 0   --  virtio legacy io bar
128523c5e397SGerd Hoffmann      *   region 1   --  msi-x bar
128623c5e397SGerd Hoffmann      *   region 2+3 --  not used by virtio-pci
128723c5e397SGerd Hoffmann      *   region 4+5 --  virtio modern memory (64bit) bar
128823c5e397SGerd Hoffmann      *
128923c5e397SGerd Hoffmann      * Regions 2+3 can be used by VirtIOPCIProxy subclasses.
129023c5e397SGerd Hoffmann      * virtio-vga places the vga framebuffer there.
129123c5e397SGerd Hoffmann      *
129223c5e397SGerd Hoffmann      */
129323c5e397SGerd Hoffmann     uint32_t legacy_io_bar  = 0;
129423c5e397SGerd Hoffmann     uint32_t msix_bar       = 1;
129523c5e397SGerd Hoffmann     uint32_t modern_mem_bar = 4;
129623c5e397SGerd Hoffmann 
1297085bccb7SKONRAD Frederic     config = proxy->pci_dev.config;
1298085bccb7SKONRAD Frederic     if (proxy->class_code) {
1299085bccb7SKONRAD Frederic         pci_config_set_class(config, proxy->class_code);
1300085bccb7SKONRAD Frederic     }
1301e266d421SGerd Hoffmann 
1302e266d421SGerd Hoffmann     if (legacy) {
1303e266d421SGerd Hoffmann         /* legacy and transitional */
1304085bccb7SKONRAD Frederic         pci_set_word(config + PCI_SUBSYSTEM_VENDOR_ID,
1305085bccb7SKONRAD Frederic                      pci_get_word(config + PCI_VENDOR_ID));
1306085bccb7SKONRAD Frederic         pci_set_word(config + PCI_SUBSYSTEM_ID, virtio_bus_get_vdev_id(bus));
1307e266d421SGerd Hoffmann     } else {
1308e266d421SGerd Hoffmann         /* pure virtio-1.0 */
1309e266d421SGerd Hoffmann         pci_set_word(config + PCI_VENDOR_ID,
1310e266d421SGerd Hoffmann                      PCI_VENDOR_ID_REDHAT_QUMRANET);
1311e266d421SGerd Hoffmann         pci_set_word(config + PCI_DEVICE_ID,
1312e266d421SGerd Hoffmann                      0x1040 + virtio_bus_get_vdev_id(bus));
1313e266d421SGerd Hoffmann         pci_config_set_revision(config, 1);
1314e266d421SGerd Hoffmann     }
1315085bccb7SKONRAD Frederic     config[PCI_INTERRUPT_PIN] = 1;
1316085bccb7SKONRAD Frederic 
1317dfb8e184SMichael S. Tsirkin 
1318e266d421SGerd Hoffmann     if (modern) {
1319dfb8e184SMichael S. Tsirkin         struct virtio_pci_cap common = {
1320dfb8e184SMichael S. Tsirkin             .cfg_type = VIRTIO_PCI_CAP_COMMON_CFG,
1321dfb8e184SMichael S. Tsirkin             .cap_len = sizeof common,
132223c5e397SGerd Hoffmann             .bar = modern_mem_bar,
1323dfb8e184SMichael S. Tsirkin             .offset = cpu_to_le32(0x0),
1324dfb8e184SMichael S. Tsirkin             .length = cpu_to_le32(0x1000),
1325dfb8e184SMichael S. Tsirkin         };
1326dfb8e184SMichael S. Tsirkin         struct virtio_pci_cap isr = {
1327dfb8e184SMichael S. Tsirkin             .cfg_type = VIRTIO_PCI_CAP_ISR_CFG,
1328dfb8e184SMichael S. Tsirkin             .cap_len = sizeof isr,
132923c5e397SGerd Hoffmann             .bar = modern_mem_bar,
1330dfb8e184SMichael S. Tsirkin             .offset = cpu_to_le32(0x1000),
1331dfb8e184SMichael S. Tsirkin             .length = cpu_to_le32(0x1000),
1332dfb8e184SMichael S. Tsirkin         };
1333dfb8e184SMichael S. Tsirkin         struct virtio_pci_cap device = {
1334dfb8e184SMichael S. Tsirkin             .cfg_type = VIRTIO_PCI_CAP_DEVICE_CFG,
1335dfb8e184SMichael S. Tsirkin             .cap_len = sizeof device,
133623c5e397SGerd Hoffmann             .bar = modern_mem_bar,
1337dfb8e184SMichael S. Tsirkin             .offset = cpu_to_le32(0x2000),
1338dfb8e184SMichael S. Tsirkin             .length = cpu_to_le32(0x1000),
1339dfb8e184SMichael S. Tsirkin         };
1340dfb8e184SMichael S. Tsirkin         struct virtio_pci_notify_cap notify = {
1341dfb8e184SMichael S. Tsirkin             .cap.cfg_type = VIRTIO_PCI_CAP_NOTIFY_CFG,
1342dfb8e184SMichael S. Tsirkin             .cap.cap_len = sizeof notify,
134323c5e397SGerd Hoffmann             .cap.bar = modern_mem_bar,
1344dfb8e184SMichael S. Tsirkin             .cap.offset = cpu_to_le32(0x3000),
1345dfb8e184SMichael S. Tsirkin             .cap.length = cpu_to_le32(QEMU_VIRTIO_PCI_QUEUE_MEM_MULT *
1346dfb8e184SMichael S. Tsirkin                                       VIRTIO_QUEUE_MAX),
1347dfb8e184SMichael S. Tsirkin             .notify_off_multiplier =
1348dfb8e184SMichael S. Tsirkin                 cpu_to_le32(QEMU_VIRTIO_PCI_QUEUE_MEM_MULT),
1349dfb8e184SMichael S. Tsirkin         };
1350dfb8e184SMichael S. Tsirkin 
1351dfb8e184SMichael S. Tsirkin         /* TODO: add io access for speed */
1352dfb8e184SMichael S. Tsirkin         virtio_pci_add_mem_cap(proxy, &common);
1353dfb8e184SMichael S. Tsirkin         virtio_pci_add_mem_cap(proxy, &isr);
1354dfb8e184SMichael S. Tsirkin         virtio_pci_add_mem_cap(proxy, &device);
1355dfb8e184SMichael S. Tsirkin         virtio_pci_add_mem_cap(proxy, &notify.cap);
1356dfb8e184SMichael S. Tsirkin 
1357dfb8e184SMichael S. Tsirkin         virtio_add_feature(&vdev->host_features, VIRTIO_F_VERSION_1);
1358dfb8e184SMichael S. Tsirkin         memory_region_init(&proxy->modern_bar, OBJECT(proxy), "virtio-pci",
1359dfb8e184SMichael S. Tsirkin                            2 * QEMU_VIRTIO_PCI_QUEUE_MEM_MULT *
1360dfb8e184SMichael S. Tsirkin                            VIRTIO_QUEUE_MAX);
1361*1141ce21SGerd Hoffmann         virtio_pci_modern_regions_init(proxy);
1362588255adSGerd Hoffmann         memory_region_add_subregion(&proxy->modern_bar, 0, &proxy->common.mr);
1363588255adSGerd Hoffmann         memory_region_add_subregion(&proxy->modern_bar, 0x1000, &proxy->isr.mr);
1364588255adSGerd Hoffmann         memory_region_add_subregion(&proxy->modern_bar, 0x2000,
1365588255adSGerd Hoffmann                                     &proxy->device.mr);
1366588255adSGerd Hoffmann         memory_region_add_subregion(&proxy->modern_bar, 0x3000,
1367588255adSGerd Hoffmann                                     &proxy->notify.mr);
136823c5e397SGerd Hoffmann         pci_register_bar(&proxy->pci_dev, modern_mem_bar,
13694e93a68eSGerd Hoffmann                          PCI_BASE_ADDRESS_SPACE_MEMORY |
13704e93a68eSGerd Hoffmann                          PCI_BASE_ADDRESS_MEM_PREFETCH |
13714e93a68eSGerd Hoffmann                          PCI_BASE_ADDRESS_MEM_TYPE_64,
1372dfb8e184SMichael S. Tsirkin                          &proxy->modern_bar);
1373dfb8e184SMichael S. Tsirkin     }
1374dfb8e184SMichael S. Tsirkin 
1375085bccb7SKONRAD Frederic     if (proxy->nvectors &&
137623c5e397SGerd Hoffmann         msix_init_exclusive_bar(&proxy->pci_dev, proxy->nvectors, msix_bar)) {
1377c7ff5482SFam Zheng         error_report("unable to init msix vectors to %" PRIu32,
1378c7ff5482SFam Zheng                      proxy->nvectors);
1379085bccb7SKONRAD Frederic         proxy->nvectors = 0;
1380085bccb7SKONRAD Frederic     }
1381085bccb7SKONRAD Frederic 
1382085bccb7SKONRAD Frederic     proxy->pci_dev.config_write = virtio_write_config;
1383085bccb7SKONRAD Frederic 
1384e266d421SGerd Hoffmann     if (legacy) {
1385085bccb7SKONRAD Frederic         size = VIRTIO_PCI_REGION_SIZE(&proxy->pci_dev)
1386085bccb7SKONRAD Frederic             + virtio_bus_get_vdev_config_len(bus);
1387085bccb7SKONRAD Frederic         if (size & (size - 1)) {
1388085bccb7SKONRAD Frederic             size = 1 << qemu_fls(size);
1389085bccb7SKONRAD Frederic         }
1390085bccb7SKONRAD Frederic 
1391e266d421SGerd Hoffmann         memory_region_init_io(&proxy->bar, OBJECT(proxy),
1392e266d421SGerd Hoffmann                               &virtio_pci_config_ops,
139322fc860bSPaolo Bonzini                               proxy, "virtio-pci", size);
1394dfb8e184SMichael S. Tsirkin 
139523c5e397SGerd Hoffmann         pci_register_bar(&proxy->pci_dev, legacy_io_bar,
139623c5e397SGerd Hoffmann                          PCI_BASE_ADDRESS_SPACE_IO, &proxy->bar);
1397e266d421SGerd Hoffmann     }
1398085bccb7SKONRAD Frederic 
1399085bccb7SKONRAD Frederic     if (!kvm_has_many_ioeventfds()) {
1400085bccb7SKONRAD Frederic         proxy->flags &= ~VIRTIO_PCI_FLAG_USE_IOEVENTFD;
1401085bccb7SKONRAD Frederic     }
1402085bccb7SKONRAD Frederic 
14036b8f1020SCornelia Huck     virtio_add_feature(&vdev->host_features, VIRTIO_F_BAD_FEATURE);
1404085bccb7SKONRAD Frederic }
1405085bccb7SKONRAD Frederic 
140606a13073SPaolo Bonzini static void virtio_pci_device_unplugged(DeviceState *d)
140706a13073SPaolo Bonzini {
140806a13073SPaolo Bonzini     VirtIOPCIProxy *proxy = VIRTIO_PCI(d);
140906a13073SPaolo Bonzini 
141006a13073SPaolo Bonzini     virtio_pci_stop_ioeventfd(proxy);
141106a13073SPaolo Bonzini }
141206a13073SPaolo Bonzini 
1413fc079951SMarkus Armbruster static void virtio_pci_realize(PCIDevice *pci_dev, Error **errp)
1414085bccb7SKONRAD Frederic {
1415085bccb7SKONRAD Frederic     VirtIOPCIProxy *dev = VIRTIO_PCI(pci_dev);
1416085bccb7SKONRAD Frederic     VirtioPCIClass *k = VIRTIO_PCI_GET_CLASS(pci_dev);
1417fc079951SMarkus Armbruster 
1418ac7af112SAndreas Färber     virtio_pci_bus_new(&dev->bus, sizeof(dev->bus), dev);
1419fc079951SMarkus Armbruster     if (k->realize) {
1420fc079951SMarkus Armbruster         k->realize(dev, errp);
1421085bccb7SKONRAD Frederic     }
1422085bccb7SKONRAD Frederic }
1423085bccb7SKONRAD Frederic 
1424085bccb7SKONRAD Frederic static void virtio_pci_exit(PCIDevice *pci_dev)
1425085bccb7SKONRAD Frederic {
14268b81bb3bSPaolo Bonzini     msix_uninit_exclusive_bar(pci_dev);
1427085bccb7SKONRAD Frederic }
1428085bccb7SKONRAD Frederic 
142959ccd20aSKONRAD Frederic static void virtio_pci_reset(DeviceState *qdev)
1430085bccb7SKONRAD Frederic {
1431085bccb7SKONRAD Frederic     VirtIOPCIProxy *proxy = VIRTIO_PCI(qdev);
1432085bccb7SKONRAD Frederic     VirtioBusState *bus = VIRTIO_BUS(&proxy->bus);
1433085bccb7SKONRAD Frederic     virtio_pci_stop_ioeventfd(proxy);
1434085bccb7SKONRAD Frederic     virtio_bus_reset(bus);
1435085bccb7SKONRAD Frederic     msix_unuse_all_vectors(&proxy->pci_dev);
1436085bccb7SKONRAD Frederic }
1437085bccb7SKONRAD Frederic 
143885d1277eSMing Lei static Property virtio_pci_properties[] = {
143968a27b20SMichael S. Tsirkin     DEFINE_PROP_BIT("virtio-pci-bus-master-bug-migration", VirtIOPCIProxy, flags,
144068a27b20SMichael S. Tsirkin                     VIRTIO_PCI_FLAG_BUS_MASTER_BUG_MIGRATION_BIT, false),
1441e266d421SGerd Hoffmann     DEFINE_PROP_BIT("disable-legacy", VirtIOPCIProxy, flags,
1442e266d421SGerd Hoffmann                     VIRTIO_PCI_FLAG_DISABLE_LEGACY_BIT, false),
1443e266d421SGerd Hoffmann     DEFINE_PROP_BIT("disable-modern", VirtIOPCIProxy, flags,
1444e266d421SGerd Hoffmann                     VIRTIO_PCI_FLAG_DISABLE_MODERN_BIT, true),
144585d1277eSMing Lei     DEFINE_PROP_END_OF_LIST(),
144685d1277eSMing Lei };
144785d1277eSMing Lei 
1448085bccb7SKONRAD Frederic static void virtio_pci_class_init(ObjectClass *klass, void *data)
1449085bccb7SKONRAD Frederic {
1450085bccb7SKONRAD Frederic     DeviceClass *dc = DEVICE_CLASS(klass);
1451085bccb7SKONRAD Frederic     PCIDeviceClass *k = PCI_DEVICE_CLASS(klass);
1452085bccb7SKONRAD Frederic 
145385d1277eSMing Lei     dc->props = virtio_pci_properties;
1454fc079951SMarkus Armbruster     k->realize = virtio_pci_realize;
1455085bccb7SKONRAD Frederic     k->exit = virtio_pci_exit;
1456085bccb7SKONRAD Frederic     k->vendor_id = PCI_VENDOR_ID_REDHAT_QUMRANET;
1457085bccb7SKONRAD Frederic     k->revision = VIRTIO_PCI_ABI_VERSION;
1458085bccb7SKONRAD Frederic     k->class_id = PCI_CLASS_OTHERS;
145959ccd20aSKONRAD Frederic     dc->reset = virtio_pci_reset;
1460085bccb7SKONRAD Frederic }
1461085bccb7SKONRAD Frederic 
1462085bccb7SKONRAD Frederic static const TypeInfo virtio_pci_info = {
1463085bccb7SKONRAD Frederic     .name          = TYPE_VIRTIO_PCI,
1464085bccb7SKONRAD Frederic     .parent        = TYPE_PCI_DEVICE,
1465085bccb7SKONRAD Frederic     .instance_size = sizeof(VirtIOPCIProxy),
1466085bccb7SKONRAD Frederic     .class_init    = virtio_pci_class_init,
1467085bccb7SKONRAD Frederic     .class_size    = sizeof(VirtioPCIClass),
1468085bccb7SKONRAD Frederic     .abstract      = true,
1469085bccb7SKONRAD Frederic };
1470085bccb7SKONRAD Frederic 
1471653ced07SKONRAD Frederic /* virtio-blk-pci */
1472653ced07SKONRAD Frederic 
1473653ced07SKONRAD Frederic static Property virtio_blk_pci_properties[] = {
1474c7bcc85dSPaolo Bonzini     DEFINE_PROP_UINT32("class", VirtIOPCIProxy, class_code, 0),
1475653ced07SKONRAD Frederic     DEFINE_PROP_BIT("ioeventfd", VirtIOPCIProxy, flags,
1476653ced07SKONRAD Frederic                     VIRTIO_PCI_FLAG_USE_IOEVENTFD_BIT, true),
1477653ced07SKONRAD Frederic     DEFINE_PROP_UINT32("vectors", VirtIOPCIProxy, nvectors, 2),
1478653ced07SKONRAD Frederic     DEFINE_PROP_END_OF_LIST(),
1479653ced07SKONRAD Frederic };
1480653ced07SKONRAD Frederic 
1481fc079951SMarkus Armbruster static void virtio_blk_pci_realize(VirtIOPCIProxy *vpci_dev, Error **errp)
1482653ced07SKONRAD Frederic {
1483653ced07SKONRAD Frederic     VirtIOBlkPCI *dev = VIRTIO_BLK_PCI(vpci_dev);
1484653ced07SKONRAD Frederic     DeviceState *vdev = DEVICE(&dev->vdev);
1485fc079951SMarkus Armbruster 
1486653ced07SKONRAD Frederic     qdev_set_parent_bus(vdev, BUS(&vpci_dev->bus));
1487fc079951SMarkus Armbruster     object_property_set_bool(OBJECT(vdev), true, "realized", errp);
1488653ced07SKONRAD Frederic }
1489653ced07SKONRAD Frederic 
1490653ced07SKONRAD Frederic static void virtio_blk_pci_class_init(ObjectClass *klass, void *data)
1491653ced07SKONRAD Frederic {
1492653ced07SKONRAD Frederic     DeviceClass *dc = DEVICE_CLASS(klass);
1493653ced07SKONRAD Frederic     VirtioPCIClass *k = VIRTIO_PCI_CLASS(klass);
1494653ced07SKONRAD Frederic     PCIDeviceClass *pcidev_k = PCI_DEVICE_CLASS(klass);
1495653ced07SKONRAD Frederic 
1496125ee0edSMarcel Apfelbaum     set_bit(DEVICE_CATEGORY_STORAGE, dc->categories);
1497653ced07SKONRAD Frederic     dc->props = virtio_blk_pci_properties;
1498fc079951SMarkus Armbruster     k->realize = virtio_blk_pci_realize;
1499653ced07SKONRAD Frederic     pcidev_k->vendor_id = PCI_VENDOR_ID_REDHAT_QUMRANET;
1500653ced07SKONRAD Frederic     pcidev_k->device_id = PCI_DEVICE_ID_VIRTIO_BLOCK;
1501653ced07SKONRAD Frederic     pcidev_k->revision = VIRTIO_PCI_ABI_VERSION;
1502653ced07SKONRAD Frederic     pcidev_k->class_id = PCI_CLASS_STORAGE_SCSI;
1503653ced07SKONRAD Frederic }
1504653ced07SKONRAD Frederic 
1505653ced07SKONRAD Frederic static void virtio_blk_pci_instance_init(Object *obj)
1506653ced07SKONRAD Frederic {
1507653ced07SKONRAD Frederic     VirtIOBlkPCI *dev = VIRTIO_BLK_PCI(obj);
1508c8075cafSGonglei 
1509c8075cafSGonglei     virtio_instance_init_common(obj, &dev->vdev, sizeof(dev->vdev),
1510c8075cafSGonglei                                 TYPE_VIRTIO_BLK);
1511467b3f33SStefan Hajnoczi     object_property_add_alias(obj, "iothread", OBJECT(&dev->vdev),"iothread",
1512467b3f33SStefan Hajnoczi                               &error_abort);
1513aeb98ddcSGonglei     object_property_add_alias(obj, "bootindex", OBJECT(&dev->vdev),
1514aeb98ddcSGonglei                               "bootindex", &error_abort);
1515653ced07SKONRAD Frederic }
1516653ced07SKONRAD Frederic 
1517653ced07SKONRAD Frederic static const TypeInfo virtio_blk_pci_info = {
1518653ced07SKONRAD Frederic     .name          = TYPE_VIRTIO_BLK_PCI,
1519653ced07SKONRAD Frederic     .parent        = TYPE_VIRTIO_PCI,
1520653ced07SKONRAD Frederic     .instance_size = sizeof(VirtIOBlkPCI),
1521653ced07SKONRAD Frederic     .instance_init = virtio_blk_pci_instance_init,
1522653ced07SKONRAD Frederic     .class_init    = virtio_blk_pci_class_init,
1523653ced07SKONRAD Frederic };
1524653ced07SKONRAD Frederic 
1525bc7b90a0SKONRAD Frederic /* virtio-scsi-pci */
1526bc7b90a0SKONRAD Frederic 
1527bc7b90a0SKONRAD Frederic static Property virtio_scsi_pci_properties[] = {
1528bc7b90a0SKONRAD Frederic     DEFINE_PROP_BIT("ioeventfd", VirtIOPCIProxy, flags,
1529bc7b90a0SKONRAD Frederic                     VIRTIO_PCI_FLAG_USE_IOEVENTFD_BIT, true),
1530bc7b90a0SKONRAD Frederic     DEFINE_PROP_UINT32("vectors", VirtIOPCIProxy, nvectors,
1531bc7b90a0SKONRAD Frederic                        DEV_NVECTORS_UNSPECIFIED),
1532bc7b90a0SKONRAD Frederic     DEFINE_PROP_END_OF_LIST(),
1533bc7b90a0SKONRAD Frederic };
1534bc7b90a0SKONRAD Frederic 
1535fc079951SMarkus Armbruster static void virtio_scsi_pci_realize(VirtIOPCIProxy *vpci_dev, Error **errp)
1536bc7b90a0SKONRAD Frederic {
1537bc7b90a0SKONRAD Frederic     VirtIOSCSIPCI *dev = VIRTIO_SCSI_PCI(vpci_dev);
1538bc7b90a0SKONRAD Frederic     DeviceState *vdev = DEVICE(&dev->vdev);
1539292c8e50SPaolo Bonzini     VirtIOSCSICommon *vs = VIRTIO_SCSI_COMMON(vdev);
15406f32a6b4SKONRAD Frederic     DeviceState *proxy = DEVICE(vpci_dev);
15416f32a6b4SKONRAD Frederic     char *bus_name;
1542bc7b90a0SKONRAD Frederic 
1543bc7b90a0SKONRAD Frederic     if (vpci_dev->nvectors == DEV_NVECTORS_UNSPECIFIED) {
1544292c8e50SPaolo Bonzini         vpci_dev->nvectors = vs->conf.num_queues + 3;
1545bc7b90a0SKONRAD Frederic     }
1546bc7b90a0SKONRAD Frederic 
15476f32a6b4SKONRAD Frederic     /*
15486f32a6b4SKONRAD Frederic      * For command line compatibility, this sets the virtio-scsi-device bus
15496f32a6b4SKONRAD Frederic      * name as before.
15506f32a6b4SKONRAD Frederic      */
15516f32a6b4SKONRAD Frederic     if (proxy->id) {
15526f32a6b4SKONRAD Frederic         bus_name = g_strdup_printf("%s.0", proxy->id);
15536f32a6b4SKONRAD Frederic         virtio_device_set_child_bus_name(VIRTIO_DEVICE(vdev), bus_name);
15546f32a6b4SKONRAD Frederic         g_free(bus_name);
15556f32a6b4SKONRAD Frederic     }
15566f32a6b4SKONRAD Frederic 
1557bc7b90a0SKONRAD Frederic     qdev_set_parent_bus(vdev, BUS(&vpci_dev->bus));
1558fc079951SMarkus Armbruster     object_property_set_bool(OBJECT(vdev), true, "realized", errp);
1559bc7b90a0SKONRAD Frederic }
1560bc7b90a0SKONRAD Frederic 
1561bc7b90a0SKONRAD Frederic static void virtio_scsi_pci_class_init(ObjectClass *klass, void *data)
1562bc7b90a0SKONRAD Frederic {
1563bc7b90a0SKONRAD Frederic     DeviceClass *dc = DEVICE_CLASS(klass);
1564bc7b90a0SKONRAD Frederic     VirtioPCIClass *k = VIRTIO_PCI_CLASS(klass);
1565bc7b90a0SKONRAD Frederic     PCIDeviceClass *pcidev_k = PCI_DEVICE_CLASS(klass);
1566fc079951SMarkus Armbruster 
1567fc079951SMarkus Armbruster     k->realize = virtio_scsi_pci_realize;
1568125ee0edSMarcel Apfelbaum     set_bit(DEVICE_CATEGORY_STORAGE, dc->categories);
1569bc7b90a0SKONRAD Frederic     dc->props = virtio_scsi_pci_properties;
1570bc7b90a0SKONRAD Frederic     pcidev_k->vendor_id = PCI_VENDOR_ID_REDHAT_QUMRANET;
1571bc7b90a0SKONRAD Frederic     pcidev_k->device_id = PCI_DEVICE_ID_VIRTIO_SCSI;
1572bc7b90a0SKONRAD Frederic     pcidev_k->revision = 0x00;
1573bc7b90a0SKONRAD Frederic     pcidev_k->class_id = PCI_CLASS_STORAGE_SCSI;
1574bc7b90a0SKONRAD Frederic }
1575bc7b90a0SKONRAD Frederic 
1576bc7b90a0SKONRAD Frederic static void virtio_scsi_pci_instance_init(Object *obj)
1577bc7b90a0SKONRAD Frederic {
1578bc7b90a0SKONRAD Frederic     VirtIOSCSIPCI *dev = VIRTIO_SCSI_PCI(obj);
1579c8075cafSGonglei 
1580c8075cafSGonglei     virtio_instance_init_common(obj, &dev->vdev, sizeof(dev->vdev),
1581c8075cafSGonglei                                 TYPE_VIRTIO_SCSI);
158219d339f1SFam Zheng     object_property_add_alias(obj, "iothread", OBJECT(&dev->vdev), "iothread",
158319d339f1SFam Zheng                               &error_abort);
1584bc7b90a0SKONRAD Frederic }
1585bc7b90a0SKONRAD Frederic 
1586bc7b90a0SKONRAD Frederic static const TypeInfo virtio_scsi_pci_info = {
1587bc7b90a0SKONRAD Frederic     .name          = TYPE_VIRTIO_SCSI_PCI,
1588bc7b90a0SKONRAD Frederic     .parent        = TYPE_VIRTIO_PCI,
1589bc7b90a0SKONRAD Frederic     .instance_size = sizeof(VirtIOSCSIPCI),
1590bc7b90a0SKONRAD Frederic     .instance_init = virtio_scsi_pci_instance_init,
1591bc7b90a0SKONRAD Frederic     .class_init    = virtio_scsi_pci_class_init,
1592bc7b90a0SKONRAD Frederic };
1593bc7b90a0SKONRAD Frederic 
159450787628SNicholas Bellinger /* vhost-scsi-pci */
159550787628SNicholas Bellinger 
159650787628SNicholas Bellinger #ifdef CONFIG_VHOST_SCSI
159750787628SNicholas Bellinger static Property vhost_scsi_pci_properties[] = {
159850787628SNicholas Bellinger     DEFINE_PROP_UINT32("vectors", VirtIOPCIProxy, nvectors,
159950787628SNicholas Bellinger                        DEV_NVECTORS_UNSPECIFIED),
160050787628SNicholas Bellinger     DEFINE_PROP_END_OF_LIST(),
160150787628SNicholas Bellinger };
160250787628SNicholas Bellinger 
1603fc079951SMarkus Armbruster static void vhost_scsi_pci_realize(VirtIOPCIProxy *vpci_dev, Error **errp)
160450787628SNicholas Bellinger {
160550787628SNicholas Bellinger     VHostSCSIPCI *dev = VHOST_SCSI_PCI(vpci_dev);
160650787628SNicholas Bellinger     DeviceState *vdev = DEVICE(&dev->vdev);
160750787628SNicholas Bellinger     VirtIOSCSICommon *vs = VIRTIO_SCSI_COMMON(vdev);
160850787628SNicholas Bellinger 
160950787628SNicholas Bellinger     if (vpci_dev->nvectors == DEV_NVECTORS_UNSPECIFIED) {
161050787628SNicholas Bellinger         vpci_dev->nvectors = vs->conf.num_queues + 3;
161150787628SNicholas Bellinger     }
161250787628SNicholas Bellinger 
161350787628SNicholas Bellinger     qdev_set_parent_bus(vdev, BUS(&vpci_dev->bus));
1614fc079951SMarkus Armbruster     object_property_set_bool(OBJECT(vdev), true, "realized", errp);
161550787628SNicholas Bellinger }
161650787628SNicholas Bellinger 
161750787628SNicholas Bellinger static void vhost_scsi_pci_class_init(ObjectClass *klass, void *data)
161850787628SNicholas Bellinger {
161950787628SNicholas Bellinger     DeviceClass *dc = DEVICE_CLASS(klass);
162050787628SNicholas Bellinger     VirtioPCIClass *k = VIRTIO_PCI_CLASS(klass);
162150787628SNicholas Bellinger     PCIDeviceClass *pcidev_k = PCI_DEVICE_CLASS(klass);
1622fc079951SMarkus Armbruster     k->realize = vhost_scsi_pci_realize;
1623125ee0edSMarcel Apfelbaum     set_bit(DEVICE_CATEGORY_STORAGE, dc->categories);
162450787628SNicholas Bellinger     dc->props = vhost_scsi_pci_properties;
162550787628SNicholas Bellinger     pcidev_k->vendor_id = PCI_VENDOR_ID_REDHAT_QUMRANET;
162650787628SNicholas Bellinger     pcidev_k->device_id = PCI_DEVICE_ID_VIRTIO_SCSI;
162750787628SNicholas Bellinger     pcidev_k->revision = 0x00;
162850787628SNicholas Bellinger     pcidev_k->class_id = PCI_CLASS_STORAGE_SCSI;
162950787628SNicholas Bellinger }
163050787628SNicholas Bellinger 
163150787628SNicholas Bellinger static void vhost_scsi_pci_instance_init(Object *obj)
163250787628SNicholas Bellinger {
163350787628SNicholas Bellinger     VHostSCSIPCI *dev = VHOST_SCSI_PCI(obj);
1634c8075cafSGonglei 
1635c8075cafSGonglei     virtio_instance_init_common(obj, &dev->vdev, sizeof(dev->vdev),
1636c8075cafSGonglei                                 TYPE_VHOST_SCSI);
1637d4433f32SGonglei     object_property_add_alias(obj, "bootindex", OBJECT(&dev->vdev),
1638d4433f32SGonglei                               "bootindex", &error_abort);
163950787628SNicholas Bellinger }
164050787628SNicholas Bellinger 
164150787628SNicholas Bellinger static const TypeInfo vhost_scsi_pci_info = {
164250787628SNicholas Bellinger     .name          = TYPE_VHOST_SCSI_PCI,
164350787628SNicholas Bellinger     .parent        = TYPE_VIRTIO_PCI,
164450787628SNicholas Bellinger     .instance_size = sizeof(VHostSCSIPCI),
164550787628SNicholas Bellinger     .instance_init = vhost_scsi_pci_instance_init,
164650787628SNicholas Bellinger     .class_init    = vhost_scsi_pci_class_init,
164750787628SNicholas Bellinger };
164850787628SNicholas Bellinger #endif
164950787628SNicholas Bellinger 
1650e378e88dSKONRAD Frederic /* virtio-balloon-pci */
1651e378e88dSKONRAD Frederic 
1652e378e88dSKONRAD Frederic static Property virtio_balloon_pci_properties[] = {
1653c7bcc85dSPaolo Bonzini     DEFINE_PROP_UINT32("class", VirtIOPCIProxy, class_code, 0),
1654e378e88dSKONRAD Frederic     DEFINE_PROP_END_OF_LIST(),
1655e378e88dSKONRAD Frederic };
1656e378e88dSKONRAD Frederic 
1657fc079951SMarkus Armbruster static void virtio_balloon_pci_realize(VirtIOPCIProxy *vpci_dev, Error **errp)
1658e378e88dSKONRAD Frederic {
1659e378e88dSKONRAD Frederic     VirtIOBalloonPCI *dev = VIRTIO_BALLOON_PCI(vpci_dev);
1660e378e88dSKONRAD Frederic     DeviceState *vdev = DEVICE(&dev->vdev);
1661e378e88dSKONRAD Frederic 
1662e378e88dSKONRAD Frederic     if (vpci_dev->class_code != PCI_CLASS_OTHERS &&
1663e378e88dSKONRAD Frederic         vpci_dev->class_code != PCI_CLASS_MEMORY_RAM) { /* qemu < 1.1 */
1664e378e88dSKONRAD Frederic         vpci_dev->class_code = PCI_CLASS_OTHERS;
1665e378e88dSKONRAD Frederic     }
1666e378e88dSKONRAD Frederic 
1667e378e88dSKONRAD Frederic     qdev_set_parent_bus(vdev, BUS(&vpci_dev->bus));
1668fc079951SMarkus Armbruster     object_property_set_bool(OBJECT(vdev), true, "realized", errp);
1669e378e88dSKONRAD Frederic }
1670e378e88dSKONRAD Frederic 
1671e378e88dSKONRAD Frederic static void virtio_balloon_pci_class_init(ObjectClass *klass, void *data)
1672e378e88dSKONRAD Frederic {
1673e378e88dSKONRAD Frederic     DeviceClass *dc = DEVICE_CLASS(klass);
1674e378e88dSKONRAD Frederic     VirtioPCIClass *k = VIRTIO_PCI_CLASS(klass);
1675e378e88dSKONRAD Frederic     PCIDeviceClass *pcidev_k = PCI_DEVICE_CLASS(klass);
1676fc079951SMarkus Armbruster     k->realize = virtio_balloon_pci_realize;
1677125ee0edSMarcel Apfelbaum     set_bit(DEVICE_CATEGORY_MISC, dc->categories);
1678e378e88dSKONRAD Frederic     dc->props = virtio_balloon_pci_properties;
1679e378e88dSKONRAD Frederic     pcidev_k->vendor_id = PCI_VENDOR_ID_REDHAT_QUMRANET;
1680e378e88dSKONRAD Frederic     pcidev_k->device_id = PCI_DEVICE_ID_VIRTIO_BALLOON;
1681e378e88dSKONRAD Frederic     pcidev_k->revision = VIRTIO_PCI_ABI_VERSION;
1682e378e88dSKONRAD Frederic     pcidev_k->class_id = PCI_CLASS_OTHERS;
1683e378e88dSKONRAD Frederic }
1684e378e88dSKONRAD Frederic 
1685e378e88dSKONRAD Frederic static void virtio_balloon_pci_instance_init(Object *obj)
1686e378e88dSKONRAD Frederic {
1687e378e88dSKONRAD Frederic     VirtIOBalloonPCI *dev = VIRTIO_BALLOON_PCI(obj);
168839b87c7bSShannon Zhao 
1689a6027b0fSDenis V. Lunev     virtio_instance_init_common(obj, &dev->vdev, sizeof(dev->vdev),
1690a6027b0fSDenis V. Lunev                                 TYPE_VIRTIO_BALLOON);
169139b87c7bSShannon Zhao     object_property_add_alias(obj, "guest-stats", OBJECT(&dev->vdev),
169239b87c7bSShannon Zhao                                   "guest-stats", &error_abort);
169339b87c7bSShannon Zhao     object_property_add_alias(obj, "guest-stats-polling-interval",
169439b87c7bSShannon Zhao                               OBJECT(&dev->vdev),
169539b87c7bSShannon Zhao                               "guest-stats-polling-interval", &error_abort);
1696e378e88dSKONRAD Frederic }
1697e378e88dSKONRAD Frederic 
1698e378e88dSKONRAD Frederic static const TypeInfo virtio_balloon_pci_info = {
1699e378e88dSKONRAD Frederic     .name          = TYPE_VIRTIO_BALLOON_PCI,
1700e378e88dSKONRAD Frederic     .parent        = TYPE_VIRTIO_PCI,
1701e378e88dSKONRAD Frederic     .instance_size = sizeof(VirtIOBalloonPCI),
1702e378e88dSKONRAD Frederic     .instance_init = virtio_balloon_pci_instance_init,
1703e378e88dSKONRAD Frederic     .class_init    = virtio_balloon_pci_class_init,
1704e378e88dSKONRAD Frederic };
1705e378e88dSKONRAD Frederic 
1706f7f7464aSKONRAD Frederic /* virtio-serial-pci */
1707f7f7464aSKONRAD Frederic 
1708fc079951SMarkus Armbruster static void virtio_serial_pci_realize(VirtIOPCIProxy *vpci_dev, Error **errp)
1709f7f7464aSKONRAD Frederic {
1710f7f7464aSKONRAD Frederic     VirtIOSerialPCI *dev = VIRTIO_SERIAL_PCI(vpci_dev);
1711f7f7464aSKONRAD Frederic     DeviceState *vdev = DEVICE(&dev->vdev);
171280270a19SKONRAD Frederic     DeviceState *proxy = DEVICE(vpci_dev);
171380270a19SKONRAD Frederic     char *bus_name;
1714f7f7464aSKONRAD Frederic 
1715f7f7464aSKONRAD Frederic     if (vpci_dev->class_code != PCI_CLASS_COMMUNICATION_OTHER &&
1716f7f7464aSKONRAD Frederic         vpci_dev->class_code != PCI_CLASS_DISPLAY_OTHER && /* qemu 0.10 */
1717f7f7464aSKONRAD Frederic         vpci_dev->class_code != PCI_CLASS_OTHERS) {        /* qemu-kvm  */
1718f7f7464aSKONRAD Frederic             vpci_dev->class_code = PCI_CLASS_COMMUNICATION_OTHER;
1719f7f7464aSKONRAD Frederic     }
1720f7f7464aSKONRAD Frederic 
1721f7f7464aSKONRAD Frederic     /* backwards-compatibility with machines that were created with
1722f7f7464aSKONRAD Frederic        DEV_NVECTORS_UNSPECIFIED */
1723f7f7464aSKONRAD Frederic     if (vpci_dev->nvectors == DEV_NVECTORS_UNSPECIFIED) {
1724f7f7464aSKONRAD Frederic         vpci_dev->nvectors = dev->vdev.serial.max_virtserial_ports + 1;
1725f7f7464aSKONRAD Frederic     }
1726f7f7464aSKONRAD Frederic 
172780270a19SKONRAD Frederic     /*
172880270a19SKONRAD Frederic      * For command line compatibility, this sets the virtio-serial-device bus
172980270a19SKONRAD Frederic      * name as before.
173080270a19SKONRAD Frederic      */
173180270a19SKONRAD Frederic     if (proxy->id) {
173280270a19SKONRAD Frederic         bus_name = g_strdup_printf("%s.0", proxy->id);
173380270a19SKONRAD Frederic         virtio_device_set_child_bus_name(VIRTIO_DEVICE(vdev), bus_name);
173480270a19SKONRAD Frederic         g_free(bus_name);
173580270a19SKONRAD Frederic     }
173680270a19SKONRAD Frederic 
1737f7f7464aSKONRAD Frederic     qdev_set_parent_bus(vdev, BUS(&vpci_dev->bus));
1738fc079951SMarkus Armbruster     object_property_set_bool(OBJECT(vdev), true, "realized", errp);
1739f7f7464aSKONRAD Frederic }
1740f7f7464aSKONRAD Frederic 
1741f7f7464aSKONRAD Frederic static Property virtio_serial_pci_properties[] = {
1742f7f7464aSKONRAD Frederic     DEFINE_PROP_BIT("ioeventfd", VirtIOPCIProxy, flags,
1743f7f7464aSKONRAD Frederic                     VIRTIO_PCI_FLAG_USE_IOEVENTFD_BIT, true),
1744f7f7464aSKONRAD Frederic     DEFINE_PROP_UINT32("vectors", VirtIOPCIProxy, nvectors, 2),
1745c7bcc85dSPaolo Bonzini     DEFINE_PROP_UINT32("class", VirtIOPCIProxy, class_code, 0),
1746f7f7464aSKONRAD Frederic     DEFINE_PROP_END_OF_LIST(),
1747f7f7464aSKONRAD Frederic };
1748f7f7464aSKONRAD Frederic 
1749f7f7464aSKONRAD Frederic static void virtio_serial_pci_class_init(ObjectClass *klass, void *data)
1750f7f7464aSKONRAD Frederic {
1751f7f7464aSKONRAD Frederic     DeviceClass *dc = DEVICE_CLASS(klass);
1752f7f7464aSKONRAD Frederic     VirtioPCIClass *k = VIRTIO_PCI_CLASS(klass);
1753f7f7464aSKONRAD Frederic     PCIDeviceClass *pcidev_k = PCI_DEVICE_CLASS(klass);
1754fc079951SMarkus Armbruster     k->realize = virtio_serial_pci_realize;
1755125ee0edSMarcel Apfelbaum     set_bit(DEVICE_CATEGORY_INPUT, dc->categories);
1756f7f7464aSKONRAD Frederic     dc->props = virtio_serial_pci_properties;
1757f7f7464aSKONRAD Frederic     pcidev_k->vendor_id = PCI_VENDOR_ID_REDHAT_QUMRANET;
1758f7f7464aSKONRAD Frederic     pcidev_k->device_id = PCI_DEVICE_ID_VIRTIO_CONSOLE;
1759f7f7464aSKONRAD Frederic     pcidev_k->revision = VIRTIO_PCI_ABI_VERSION;
1760f7f7464aSKONRAD Frederic     pcidev_k->class_id = PCI_CLASS_COMMUNICATION_OTHER;
1761f7f7464aSKONRAD Frederic }
1762f7f7464aSKONRAD Frederic 
1763f7f7464aSKONRAD Frederic static void virtio_serial_pci_instance_init(Object *obj)
1764f7f7464aSKONRAD Frederic {
1765f7f7464aSKONRAD Frederic     VirtIOSerialPCI *dev = VIRTIO_SERIAL_PCI(obj);
1766c8075cafSGonglei 
1767c8075cafSGonglei     virtio_instance_init_common(obj, &dev->vdev, sizeof(dev->vdev),
1768c8075cafSGonglei                                 TYPE_VIRTIO_SERIAL);
1769f7f7464aSKONRAD Frederic }
1770f7f7464aSKONRAD Frederic 
1771f7f7464aSKONRAD Frederic static const TypeInfo virtio_serial_pci_info = {
1772f7f7464aSKONRAD Frederic     .name          = TYPE_VIRTIO_SERIAL_PCI,
1773f7f7464aSKONRAD Frederic     .parent        = TYPE_VIRTIO_PCI,
1774f7f7464aSKONRAD Frederic     .instance_size = sizeof(VirtIOSerialPCI),
1775f7f7464aSKONRAD Frederic     .instance_init = virtio_serial_pci_instance_init,
1776f7f7464aSKONRAD Frederic     .class_init    = virtio_serial_pci_class_init,
1777f7f7464aSKONRAD Frederic };
1778f7f7464aSKONRAD Frederic 
1779e37da394SKONRAD Frederic /* virtio-net-pci */
1780e37da394SKONRAD Frederic 
1781e37da394SKONRAD Frederic static Property virtio_net_properties[] = {
1782e37da394SKONRAD Frederic     DEFINE_PROP_BIT("ioeventfd", VirtIOPCIProxy, flags,
1783e37da394SKONRAD Frederic                     VIRTIO_PCI_FLAG_USE_IOEVENTFD_BIT, false),
1784e37da394SKONRAD Frederic     DEFINE_PROP_UINT32("vectors", VirtIOPCIProxy, nvectors, 3),
1785e37da394SKONRAD Frederic     DEFINE_PROP_END_OF_LIST(),
1786e37da394SKONRAD Frederic };
1787e37da394SKONRAD Frederic 
1788fc079951SMarkus Armbruster static void virtio_net_pci_realize(VirtIOPCIProxy *vpci_dev, Error **errp)
1789e37da394SKONRAD Frederic {
1790800ced8cSKONRAD Frederic     DeviceState *qdev = DEVICE(vpci_dev);
1791e37da394SKONRAD Frederic     VirtIONetPCI *dev = VIRTIO_NET_PCI(vpci_dev);
1792e37da394SKONRAD Frederic     DeviceState *vdev = DEVICE(&dev->vdev);
1793e37da394SKONRAD Frederic 
1794800ced8cSKONRAD Frederic     virtio_net_set_netclient_name(&dev->vdev, qdev->id,
1795800ced8cSKONRAD Frederic                                   object_get_typename(OBJECT(qdev)));
1796e37da394SKONRAD Frederic     qdev_set_parent_bus(vdev, BUS(&vpci_dev->bus));
1797fc079951SMarkus Armbruster     object_property_set_bool(OBJECT(vdev), true, "realized", errp);
1798e37da394SKONRAD Frederic }
1799e37da394SKONRAD Frederic 
1800e37da394SKONRAD Frederic static void virtio_net_pci_class_init(ObjectClass *klass, void *data)
1801e37da394SKONRAD Frederic {
1802e37da394SKONRAD Frederic     DeviceClass *dc = DEVICE_CLASS(klass);
1803e37da394SKONRAD Frederic     PCIDeviceClass *k = PCI_DEVICE_CLASS(klass);
1804e37da394SKONRAD Frederic     VirtioPCIClass *vpciklass = VIRTIO_PCI_CLASS(klass);
1805e37da394SKONRAD Frederic 
1806e37da394SKONRAD Frederic     k->romfile = "efi-virtio.rom";
1807e37da394SKONRAD Frederic     k->vendor_id = PCI_VENDOR_ID_REDHAT_QUMRANET;
1808e37da394SKONRAD Frederic     k->device_id = PCI_DEVICE_ID_VIRTIO_NET;
1809e37da394SKONRAD Frederic     k->revision = VIRTIO_PCI_ABI_VERSION;
1810e37da394SKONRAD Frederic     k->class_id = PCI_CLASS_NETWORK_ETHERNET;
1811125ee0edSMarcel Apfelbaum     set_bit(DEVICE_CATEGORY_NETWORK, dc->categories);
1812e37da394SKONRAD Frederic     dc->props = virtio_net_properties;
1813fc079951SMarkus Armbruster     vpciklass->realize = virtio_net_pci_realize;
1814e37da394SKONRAD Frederic }
1815e37da394SKONRAD Frederic 
1816e37da394SKONRAD Frederic static void virtio_net_pci_instance_init(Object *obj)
1817e37da394SKONRAD Frederic {
1818e37da394SKONRAD Frederic     VirtIONetPCI *dev = VIRTIO_NET_PCI(obj);
1819c8075cafSGonglei 
1820c8075cafSGonglei     virtio_instance_init_common(obj, &dev->vdev, sizeof(dev->vdev),
1821c8075cafSGonglei                                 TYPE_VIRTIO_NET);
18220cf63c3eSGonglei     object_property_add_alias(obj, "bootindex", OBJECT(&dev->vdev),
18230cf63c3eSGonglei                               "bootindex", &error_abort);
1824e37da394SKONRAD Frederic }
1825e37da394SKONRAD Frederic 
1826e37da394SKONRAD Frederic static const TypeInfo virtio_net_pci_info = {
1827e37da394SKONRAD Frederic     .name          = TYPE_VIRTIO_NET_PCI,
1828e37da394SKONRAD Frederic     .parent        = TYPE_VIRTIO_PCI,
1829e37da394SKONRAD Frederic     .instance_size = sizeof(VirtIONetPCI),
1830e37da394SKONRAD Frederic     .instance_init = virtio_net_pci_instance_init,
1831e37da394SKONRAD Frederic     .class_init    = virtio_net_pci_class_init,
1832e37da394SKONRAD Frederic };
1833e37da394SKONRAD Frederic 
183459ccd20aSKONRAD Frederic /* virtio-rng-pci */
183559ccd20aSKONRAD Frederic 
183659ccd20aSKONRAD Frederic static Property virtio_rng_pci_properties[] = {
183759ccd20aSKONRAD Frederic     DEFINE_PROP_END_OF_LIST(),
183859ccd20aSKONRAD Frederic };
183959ccd20aSKONRAD Frederic 
1840fc079951SMarkus Armbruster static void virtio_rng_pci_realize(VirtIOPCIProxy *vpci_dev, Error **errp)
184159ccd20aSKONRAD Frederic {
184259ccd20aSKONRAD Frederic     VirtIORngPCI *vrng = VIRTIO_RNG_PCI(vpci_dev);
184359ccd20aSKONRAD Frederic     DeviceState *vdev = DEVICE(&vrng->vdev);
1844fc079951SMarkus Armbruster     Error *err = NULL;
184559ccd20aSKONRAD Frederic 
184659ccd20aSKONRAD Frederic     qdev_set_parent_bus(vdev, BUS(&vpci_dev->bus));
1847fc079951SMarkus Armbruster     object_property_set_bool(OBJECT(vdev), true, "realized", &err);
1848fc079951SMarkus Armbruster     if (err) {
1849fc079951SMarkus Armbruster         error_propagate(errp, err);
1850fc079951SMarkus Armbruster         return;
185159ccd20aSKONRAD Frederic     }
185259ccd20aSKONRAD Frederic 
185359ccd20aSKONRAD Frederic     object_property_set_link(OBJECT(vrng),
18545b456438SCole Robinson                              OBJECT(vrng->vdev.conf.rng), "rng",
185559ccd20aSKONRAD Frederic                              NULL);
185659ccd20aSKONRAD Frederic }
185759ccd20aSKONRAD Frederic 
185859ccd20aSKONRAD Frederic static void virtio_rng_pci_class_init(ObjectClass *klass, void *data)
185959ccd20aSKONRAD Frederic {
186059ccd20aSKONRAD Frederic     DeviceClass *dc = DEVICE_CLASS(klass);
186159ccd20aSKONRAD Frederic     VirtioPCIClass *k = VIRTIO_PCI_CLASS(klass);
186259ccd20aSKONRAD Frederic     PCIDeviceClass *pcidev_k = PCI_DEVICE_CLASS(klass);
186359ccd20aSKONRAD Frederic 
1864fc079951SMarkus Armbruster     k->realize = virtio_rng_pci_realize;
1865125ee0edSMarcel Apfelbaum     set_bit(DEVICE_CATEGORY_MISC, dc->categories);
186659ccd20aSKONRAD Frederic     dc->props = virtio_rng_pci_properties;
186759ccd20aSKONRAD Frederic 
186859ccd20aSKONRAD Frederic     pcidev_k->vendor_id = PCI_VENDOR_ID_REDHAT_QUMRANET;
186959ccd20aSKONRAD Frederic     pcidev_k->device_id = PCI_DEVICE_ID_VIRTIO_RNG;
187059ccd20aSKONRAD Frederic     pcidev_k->revision = VIRTIO_PCI_ABI_VERSION;
187159ccd20aSKONRAD Frederic     pcidev_k->class_id = PCI_CLASS_OTHERS;
187259ccd20aSKONRAD Frederic }
187359ccd20aSKONRAD Frederic 
187459ccd20aSKONRAD Frederic static void virtio_rng_initfn(Object *obj)
187559ccd20aSKONRAD Frederic {
187659ccd20aSKONRAD Frederic     VirtIORngPCI *dev = VIRTIO_RNG_PCI(obj);
1877c8075cafSGonglei 
1878c8075cafSGonglei     virtio_instance_init_common(obj, &dev->vdev, sizeof(dev->vdev),
1879c8075cafSGonglei                                 TYPE_VIRTIO_RNG);
1880cbd5ac69SPaolo Bonzini     object_property_add_alias(obj, "rng", OBJECT(&dev->vdev), "rng",
1881cbd5ac69SPaolo Bonzini                               &error_abort);
188259ccd20aSKONRAD Frederic }
188359ccd20aSKONRAD Frederic 
188459ccd20aSKONRAD Frederic static const TypeInfo virtio_rng_pci_info = {
188559ccd20aSKONRAD Frederic     .name          = TYPE_VIRTIO_RNG_PCI,
188659ccd20aSKONRAD Frederic     .parent        = TYPE_VIRTIO_PCI,
188759ccd20aSKONRAD Frederic     .instance_size = sizeof(VirtIORngPCI),
188859ccd20aSKONRAD Frederic     .instance_init = virtio_rng_initfn,
188959ccd20aSKONRAD Frederic     .class_init    = virtio_rng_pci_class_init,
189059ccd20aSKONRAD Frederic };
189159ccd20aSKONRAD Frederic 
18920a2acf5eSKONRAD Frederic /* virtio-pci-bus */
18930a2acf5eSKONRAD Frederic 
1894ac7af112SAndreas Färber static void virtio_pci_bus_new(VirtioBusState *bus, size_t bus_size,
1895ac7af112SAndreas Färber                                VirtIOPCIProxy *dev)
18960a2acf5eSKONRAD Frederic {
18970a2acf5eSKONRAD Frederic     DeviceState *qdev = DEVICE(dev);
1898f4dd69aaSKONRAD Frederic     char virtio_bus_name[] = "virtio-bus";
1899f4dd69aaSKONRAD Frederic 
1900fb17dfe0SAndreas Färber     qbus_create_inplace(bus, bus_size, TYPE_VIRTIO_PCI_BUS, qdev,
1901f4dd69aaSKONRAD Frederic                         virtio_bus_name);
19020a2acf5eSKONRAD Frederic }
19030a2acf5eSKONRAD Frederic 
19040a2acf5eSKONRAD Frederic static void virtio_pci_bus_class_init(ObjectClass *klass, void *data)
19050a2acf5eSKONRAD Frederic {
19060a2acf5eSKONRAD Frederic     BusClass *bus_class = BUS_CLASS(klass);
19070a2acf5eSKONRAD Frederic     VirtioBusClass *k = VIRTIO_BUS_CLASS(klass);
19080a2acf5eSKONRAD Frederic     bus_class->max_dev = 1;
19090a2acf5eSKONRAD Frederic     k->notify = virtio_pci_notify;
19100a2acf5eSKONRAD Frederic     k->save_config = virtio_pci_save_config;
19110a2acf5eSKONRAD Frederic     k->load_config = virtio_pci_load_config;
19120a2acf5eSKONRAD Frederic     k->save_queue = virtio_pci_save_queue;
19130a2acf5eSKONRAD Frederic     k->load_queue = virtio_pci_load_queue;
19140a2acf5eSKONRAD Frederic     k->query_guest_notifiers = virtio_pci_query_guest_notifiers;
19150a2acf5eSKONRAD Frederic     k->set_host_notifier = virtio_pci_set_host_notifier;
19160a2acf5eSKONRAD Frederic     k->set_guest_notifiers = virtio_pci_set_guest_notifiers;
19170a2acf5eSKONRAD Frederic     k->vmstate_change = virtio_pci_vmstate_change;
1918085bccb7SKONRAD Frederic     k->device_plugged = virtio_pci_device_plugged;
191906a13073SPaolo Bonzini     k->device_unplugged = virtio_pci_device_unplugged;
1920e0d686bfSJason Wang     k->query_nvectors = virtio_pci_query_nvectors;
19210a2acf5eSKONRAD Frederic }
19220a2acf5eSKONRAD Frederic 
19230a2acf5eSKONRAD Frederic static const TypeInfo virtio_pci_bus_info = {
19240a2acf5eSKONRAD Frederic     .name          = TYPE_VIRTIO_PCI_BUS,
19250a2acf5eSKONRAD Frederic     .parent        = TYPE_VIRTIO_BUS,
19260a2acf5eSKONRAD Frederic     .instance_size = sizeof(VirtioPCIBusState),
19270a2acf5eSKONRAD Frederic     .class_init    = virtio_pci_bus_class_init,
19280a2acf5eSKONRAD Frederic };
19290a2acf5eSKONRAD Frederic 
193083f7d43aSAndreas Färber static void virtio_pci_register_types(void)
193153c25ceaSPaul Brook {
193259ccd20aSKONRAD Frederic     type_register_static(&virtio_rng_pci_info);
19330a2acf5eSKONRAD Frederic     type_register_static(&virtio_pci_bus_info);
1934085bccb7SKONRAD Frederic     type_register_static(&virtio_pci_info);
193560653b28SPaolo Bonzini #ifdef CONFIG_VIRTFS
1936234a336fSKONRAD Frederic     type_register_static(&virtio_9p_pci_info);
193760653b28SPaolo Bonzini #endif
1938653ced07SKONRAD Frederic     type_register_static(&virtio_blk_pci_info);
1939bc7b90a0SKONRAD Frederic     type_register_static(&virtio_scsi_pci_info);
1940e378e88dSKONRAD Frederic     type_register_static(&virtio_balloon_pci_info);
1941f7f7464aSKONRAD Frederic     type_register_static(&virtio_serial_pci_info);
1942e37da394SKONRAD Frederic     type_register_static(&virtio_net_pci_info);
194350787628SNicholas Bellinger #ifdef CONFIG_VHOST_SCSI
194450787628SNicholas Bellinger     type_register_static(&vhost_scsi_pci_info);
194550787628SNicholas Bellinger #endif
194653c25ceaSPaul Brook }
194753c25ceaSPaul Brook 
194883f7d43aSAndreas Färber type_init(virtio_pci_register_types)
1949