xref: /qemu/hw/virtio/virtio-pci.c (revision 50787628ee343d3c149eb35c206b68429d1cfdf4)
153c25ceaSPaul Brook /*
253c25ceaSPaul Brook  * Virtio PCI Bindings
353c25ceaSPaul Brook  *
453c25ceaSPaul Brook  * Copyright IBM, Corp. 2007
553c25ceaSPaul Brook  * Copyright (c) 2009 CodeSourcery
653c25ceaSPaul Brook  *
753c25ceaSPaul Brook  * Authors:
853c25ceaSPaul Brook  *  Anthony Liguori   <aliguori@us.ibm.com>
953c25ceaSPaul Brook  *  Paul Brook        <paul@codesourcery.com>
1053c25ceaSPaul Brook  *
1153c25ceaSPaul Brook  * This work is licensed under the terms of the GNU GPL, version 2.  See
1253c25ceaSPaul Brook  * the COPYING file in the top-level directory.
1353c25ceaSPaul Brook  *
146b620ca3SPaolo Bonzini  * Contributions after 2012-01-13 are licensed under the terms of the
156b620ca3SPaolo Bonzini  * GNU GPL, version 2 or (at your option) any later version.
1653c25ceaSPaul Brook  */
1753c25ceaSPaul Brook 
1853c25ceaSPaul Brook #include <inttypes.h>
1953c25ceaSPaul Brook 
200d09e41aSPaolo Bonzini #include "hw/virtio/virtio.h"
210d09e41aSPaolo Bonzini #include "hw/virtio/virtio-blk.h"
220d09e41aSPaolo Bonzini #include "hw/virtio/virtio-net.h"
230d09e41aSPaolo Bonzini #include "hw/virtio/virtio-serial.h"
240d09e41aSPaolo Bonzini #include "hw/virtio/virtio-scsi.h"
250d09e41aSPaolo Bonzini #include "hw/virtio/virtio-balloon.h"
2683c9f4caSPaolo Bonzini #include "hw/pci/pci.h"
271de7afc9SPaolo Bonzini #include "qemu/error-report.h"
2883c9f4caSPaolo Bonzini #include "hw/pci/msi.h"
2983c9f4caSPaolo Bonzini #include "hw/pci/msix.h"
3083c9f4caSPaolo Bonzini #include "hw/loader.h"
319c17d615SPaolo Bonzini #include "sysemu/kvm.h"
329c17d615SPaolo Bonzini #include "sysemu/blockdev.h"
3347b43a1fSPaolo Bonzini #include "virtio-pci.h"
341de7afc9SPaolo Bonzini #include "qemu/range.h"
350d09e41aSPaolo Bonzini #include "hw/virtio/virtio-bus.h"
3624a6e7f4SKONRAD Frederic #include "qapi/visitor.h"
3753c25ceaSPaul Brook 
3853c25ceaSPaul Brook /* from Linux's linux/virtio_pci.h */
3953c25ceaSPaul Brook 
4053c25ceaSPaul Brook /* A 32-bit r/o bitmask of the features supported by the host */
4153c25ceaSPaul Brook #define VIRTIO_PCI_HOST_FEATURES        0
4253c25ceaSPaul Brook 
4353c25ceaSPaul Brook /* A 32-bit r/w bitmask of features activated by the guest */
4453c25ceaSPaul Brook #define VIRTIO_PCI_GUEST_FEATURES       4
4553c25ceaSPaul Brook 
4653c25ceaSPaul Brook /* A 32-bit r/w PFN for the currently selected queue */
4753c25ceaSPaul Brook #define VIRTIO_PCI_QUEUE_PFN            8
4853c25ceaSPaul Brook 
4953c25ceaSPaul Brook /* A 16-bit r/o queue size for the currently selected queue */
5053c25ceaSPaul Brook #define VIRTIO_PCI_QUEUE_NUM            12
5153c25ceaSPaul Brook 
5253c25ceaSPaul Brook /* A 16-bit r/w queue selector */
5353c25ceaSPaul Brook #define VIRTIO_PCI_QUEUE_SEL            14
5453c25ceaSPaul Brook 
5553c25ceaSPaul Brook /* A 16-bit r/w queue notifier */
5653c25ceaSPaul Brook #define VIRTIO_PCI_QUEUE_NOTIFY         16
5753c25ceaSPaul Brook 
5853c25ceaSPaul Brook /* An 8-bit device status register.  */
5953c25ceaSPaul Brook #define VIRTIO_PCI_STATUS               18
6053c25ceaSPaul Brook 
6153c25ceaSPaul Brook /* An 8-bit r/o interrupt status register.  Reading the value will return the
6253c25ceaSPaul Brook  * current contents of the ISR and will also clear it.  This is effectively
6353c25ceaSPaul Brook  * a read-and-acknowledge. */
6453c25ceaSPaul Brook #define VIRTIO_PCI_ISR                  19
6553c25ceaSPaul Brook 
66aba800a3SMichael S. Tsirkin /* MSI-X registers: only enabled if MSI-X is enabled. */
67aba800a3SMichael S. Tsirkin /* A 16-bit vector for configuration changes. */
68aba800a3SMichael S. Tsirkin #define VIRTIO_MSI_CONFIG_VECTOR        20
69aba800a3SMichael S. Tsirkin /* A 16-bit vector for selected queue notifications. */
70aba800a3SMichael S. Tsirkin #define VIRTIO_MSI_QUEUE_VECTOR         22
71aba800a3SMichael S. Tsirkin 
72aba800a3SMichael S. Tsirkin /* Config space size */
73aba800a3SMichael S. Tsirkin #define VIRTIO_PCI_CONFIG_NOMSI         20
74aba800a3SMichael S. Tsirkin #define VIRTIO_PCI_CONFIG_MSI           24
75aba800a3SMichael S. Tsirkin #define VIRTIO_PCI_REGION_SIZE(dev)     (msix_present(dev) ? \
76aba800a3SMichael S. Tsirkin                                          VIRTIO_PCI_CONFIG_MSI : \
77aba800a3SMichael S. Tsirkin                                          VIRTIO_PCI_CONFIG_NOMSI)
78aba800a3SMichael S. Tsirkin 
79aba800a3SMichael S. Tsirkin /* The remaining space is defined by each driver as the per-driver
80aba800a3SMichael S. Tsirkin  * configuration space */
81aba800a3SMichael S. Tsirkin #define VIRTIO_PCI_CONFIG(dev)          (msix_enabled(dev) ? \
82aba800a3SMichael S. Tsirkin                                          VIRTIO_PCI_CONFIG_MSI : \
83aba800a3SMichael S. Tsirkin                                          VIRTIO_PCI_CONFIG_NOMSI)
8453c25ceaSPaul Brook 
8553c25ceaSPaul Brook /* How many bits to shift physical queue address written to QUEUE_PFN.
8653c25ceaSPaul Brook  * 12 is historical, and due to x86 page size. */
8753c25ceaSPaul Brook #define VIRTIO_PCI_QUEUE_ADDR_SHIFT    12
8853c25ceaSPaul Brook 
893dbca8e6SStefan Hajnoczi /* Flags track per-device state like workarounds for quirks in older guests. */
903dbca8e6SStefan Hajnoczi #define VIRTIO_PCI_FLAG_BUS_MASTER_BUG  (1 << 0)
91c81131dbSAlexander Graf 
9253c25ceaSPaul Brook /* QEMU doesn't strictly need write barriers since everything runs in
9353c25ceaSPaul Brook  * lock-step.  We'll leave the calls to wmb() in though to make it obvious for
9453c25ceaSPaul Brook  * KVM or if kqemu gets SMP support.
9553c25ceaSPaul Brook  */
9653c25ceaSPaul Brook #define wmb() do { } while (0)
9753c25ceaSPaul Brook 
988e4a424bSBlue Swirl /* HACK for virtio to determine if it's running a big endian guest */
998e4a424bSBlue Swirl bool virtio_is_big_endian(void);
1008e4a424bSBlue Swirl 
10153c25ceaSPaul Brook /* virtio device */
102d2a0ccc6SMichael S. Tsirkin /* DeviceState to VirtIOPCIProxy. For use off data-path. TODO: use QOM. */
103d2a0ccc6SMichael S. Tsirkin static inline VirtIOPCIProxy *to_virtio_pci_proxy(DeviceState *d)
10453c25ceaSPaul Brook {
105d2a0ccc6SMichael S. Tsirkin     return container_of(d, VirtIOPCIProxy, pci_dev.qdev);
106d2a0ccc6SMichael S. Tsirkin }
107d2a0ccc6SMichael S. Tsirkin 
108d2a0ccc6SMichael S. Tsirkin /* DeviceState to VirtIOPCIProxy. Note: used on datapath,
109d2a0ccc6SMichael S. Tsirkin  * be careful and test performance if you change this.
110d2a0ccc6SMichael S. Tsirkin  */
111d2a0ccc6SMichael S. Tsirkin static inline VirtIOPCIProxy *to_virtio_pci_proxy_fast(DeviceState *d)
112d2a0ccc6SMichael S. Tsirkin {
113d2a0ccc6SMichael S. Tsirkin     return container_of(d, VirtIOPCIProxy, pci_dev.qdev);
114d2a0ccc6SMichael S. Tsirkin }
115d2a0ccc6SMichael S. Tsirkin 
116d2a0ccc6SMichael S. Tsirkin static void virtio_pci_notify(DeviceState *d, uint16_t vector)
117d2a0ccc6SMichael S. Tsirkin {
118d2a0ccc6SMichael S. Tsirkin     VirtIOPCIProxy *proxy = to_virtio_pci_proxy_fast(d);
119aba800a3SMichael S. Tsirkin     if (msix_enabled(&proxy->pci_dev))
120aba800a3SMichael S. Tsirkin         msix_notify(&proxy->pci_dev, vector);
121aba800a3SMichael S. Tsirkin     else
12253c25ceaSPaul Brook         qemu_set_irq(proxy->pci_dev.irq[0], proxy->vdev->isr & 1);
12353c25ceaSPaul Brook }
12453c25ceaSPaul Brook 
125d2a0ccc6SMichael S. Tsirkin static void virtio_pci_save_config(DeviceState *d, QEMUFile *f)
126ff24bd58SMichael S. Tsirkin {
127d2a0ccc6SMichael S. Tsirkin     VirtIOPCIProxy *proxy = to_virtio_pci_proxy(d);
128ff24bd58SMichael S. Tsirkin     pci_device_save(&proxy->pci_dev, f);
129ff24bd58SMichael S. Tsirkin     msix_save(&proxy->pci_dev, f);
130ff24bd58SMichael S. Tsirkin     if (msix_present(&proxy->pci_dev))
131ff24bd58SMichael S. Tsirkin         qemu_put_be16(f, proxy->vdev->config_vector);
132ff24bd58SMichael S. Tsirkin }
133ff24bd58SMichael S. Tsirkin 
134d2a0ccc6SMichael S. Tsirkin static void virtio_pci_save_queue(DeviceState *d, int n, QEMUFile *f)
135ff24bd58SMichael S. Tsirkin {
136d2a0ccc6SMichael S. Tsirkin     VirtIOPCIProxy *proxy = to_virtio_pci_proxy(d);
137ff24bd58SMichael S. Tsirkin     if (msix_present(&proxy->pci_dev))
138ff24bd58SMichael S. Tsirkin         qemu_put_be16(f, virtio_queue_vector(proxy->vdev, n));
139ff24bd58SMichael S. Tsirkin }
140ff24bd58SMichael S. Tsirkin 
141d2a0ccc6SMichael S. Tsirkin static int virtio_pci_load_config(DeviceState *d, QEMUFile *f)
142ff24bd58SMichael S. Tsirkin {
143d2a0ccc6SMichael S. Tsirkin     VirtIOPCIProxy *proxy = to_virtio_pci_proxy(d);
144ff24bd58SMichael S. Tsirkin     int ret;
145ff24bd58SMichael S. Tsirkin     ret = pci_device_load(&proxy->pci_dev, f);
146e6da7680SMichael S. Tsirkin     if (ret) {
147ff24bd58SMichael S. Tsirkin         return ret;
148e6da7680SMichael S. Tsirkin     }
1493cac001eSMichael S. Tsirkin     msix_unuse_all_vectors(&proxy->pci_dev);
150ff24bd58SMichael S. Tsirkin     msix_load(&proxy->pci_dev, f);
151e6da7680SMichael S. Tsirkin     if (msix_present(&proxy->pci_dev)) {
152ff24bd58SMichael S. Tsirkin         qemu_get_be16s(f, &proxy->vdev->config_vector);
153e6da7680SMichael S. Tsirkin     } else {
154e6da7680SMichael S. Tsirkin         proxy->vdev->config_vector = VIRTIO_NO_VECTOR;
155e6da7680SMichael S. Tsirkin     }
156e6da7680SMichael S. Tsirkin     if (proxy->vdev->config_vector != VIRTIO_NO_VECTOR) {
157e6da7680SMichael S. Tsirkin         return msix_vector_use(&proxy->pci_dev, proxy->vdev->config_vector);
158e6da7680SMichael S. Tsirkin     }
159ff24bd58SMichael S. Tsirkin     return 0;
160ff24bd58SMichael S. Tsirkin }
161ff24bd58SMichael S. Tsirkin 
162d2a0ccc6SMichael S. Tsirkin static int virtio_pci_load_queue(DeviceState *d, int n, QEMUFile *f)
163ff24bd58SMichael S. Tsirkin {
164d2a0ccc6SMichael S. Tsirkin     VirtIOPCIProxy *proxy = to_virtio_pci_proxy(d);
165ff24bd58SMichael S. Tsirkin     uint16_t vector;
166e6da7680SMichael S. Tsirkin     if (msix_present(&proxy->pci_dev)) {
167ff24bd58SMichael S. Tsirkin         qemu_get_be16s(f, &vector);
168e6da7680SMichael S. Tsirkin     } else {
169e6da7680SMichael S. Tsirkin         vector = VIRTIO_NO_VECTOR;
170e6da7680SMichael S. Tsirkin     }
171ff24bd58SMichael S. Tsirkin     virtio_queue_set_vector(proxy->vdev, n, vector);
172e6da7680SMichael S. Tsirkin     if (vector != VIRTIO_NO_VECTOR) {
173e6da7680SMichael S. Tsirkin         return msix_vector_use(&proxy->pci_dev, vector);
174e6da7680SMichael S. Tsirkin     }
175ff24bd58SMichael S. Tsirkin     return 0;
176ff24bd58SMichael S. Tsirkin }
177ff24bd58SMichael S. Tsirkin 
17825db9ebeSStefan Hajnoczi static int virtio_pci_set_host_notifier_internal(VirtIOPCIProxy *proxy,
17926b9b5feSPaolo Bonzini                                                  int n, bool assign, bool set_handler)
18025db9ebeSStefan Hajnoczi {
18125db9ebeSStefan Hajnoczi     VirtQueue *vq = virtio_get_queue(proxy->vdev, n);
18225db9ebeSStefan Hajnoczi     EventNotifier *notifier = virtio_queue_get_host_notifier(vq);
183da146d0aSAvi Kivity     int r = 0;
184da146d0aSAvi Kivity 
18525db9ebeSStefan Hajnoczi     if (assign) {
18625db9ebeSStefan Hajnoczi         r = event_notifier_init(notifier, 1);
18725db9ebeSStefan Hajnoczi         if (r < 0) {
188b36e3914SMichael S. Tsirkin             error_report("%s: unable to init event notifier: %d",
189b36e3914SMichael S. Tsirkin                          __func__, r);
19025db9ebeSStefan Hajnoczi             return r;
19125db9ebeSStefan Hajnoczi         }
19226b9b5feSPaolo Bonzini         virtio_queue_set_host_notifier_fd_handler(vq, true, set_handler);
193da146d0aSAvi Kivity         memory_region_add_eventfd(&proxy->bar, VIRTIO_PCI_QUEUE_NOTIFY, 2,
194753d5e14SPaolo Bonzini                                   true, n, notifier);
19525db9ebeSStefan Hajnoczi     } else {
196da146d0aSAvi Kivity         memory_region_del_eventfd(&proxy->bar, VIRTIO_PCI_QUEUE_NOTIFY, 2,
197753d5e14SPaolo Bonzini                                   true, n, notifier);
19826b9b5feSPaolo Bonzini         virtio_queue_set_host_notifier_fd_handler(vq, false, false);
19925db9ebeSStefan Hajnoczi         event_notifier_cleanup(notifier);
20025db9ebeSStefan Hajnoczi     }
20125db9ebeSStefan Hajnoczi     return r;
20225db9ebeSStefan Hajnoczi }
20325db9ebeSStefan Hajnoczi 
204b36e3914SMichael S. Tsirkin static void virtio_pci_start_ioeventfd(VirtIOPCIProxy *proxy)
20525db9ebeSStefan Hajnoczi {
20625db9ebeSStefan Hajnoczi     int n, r;
20725db9ebeSStefan Hajnoczi 
20825db9ebeSStefan Hajnoczi     if (!(proxy->flags & VIRTIO_PCI_FLAG_USE_IOEVENTFD) ||
20925db9ebeSStefan Hajnoczi         proxy->ioeventfd_disabled ||
21025db9ebeSStefan Hajnoczi         proxy->ioeventfd_started) {
211b36e3914SMichael S. Tsirkin         return;
21225db9ebeSStefan Hajnoczi     }
21325db9ebeSStefan Hajnoczi 
21425db9ebeSStefan Hajnoczi     for (n = 0; n < VIRTIO_PCI_QUEUE_MAX; n++) {
21525db9ebeSStefan Hajnoczi         if (!virtio_queue_get_num(proxy->vdev, n)) {
21625db9ebeSStefan Hajnoczi             continue;
21725db9ebeSStefan Hajnoczi         }
21825db9ebeSStefan Hajnoczi 
21926b9b5feSPaolo Bonzini         r = virtio_pci_set_host_notifier_internal(proxy, n, true, true);
22025db9ebeSStefan Hajnoczi         if (r < 0) {
22125db9ebeSStefan Hajnoczi             goto assign_error;
22225db9ebeSStefan Hajnoczi         }
22325db9ebeSStefan Hajnoczi     }
22425db9ebeSStefan Hajnoczi     proxy->ioeventfd_started = true;
225b36e3914SMichael S. Tsirkin     return;
22625db9ebeSStefan Hajnoczi 
22725db9ebeSStefan Hajnoczi assign_error:
22825db9ebeSStefan Hajnoczi     while (--n >= 0) {
22925db9ebeSStefan Hajnoczi         if (!virtio_queue_get_num(proxy->vdev, n)) {
23025db9ebeSStefan Hajnoczi             continue;
23125db9ebeSStefan Hajnoczi         }
23225db9ebeSStefan Hajnoczi 
23326b9b5feSPaolo Bonzini         r = virtio_pci_set_host_notifier_internal(proxy, n, false, false);
234b36e3914SMichael S. Tsirkin         assert(r >= 0);
23525db9ebeSStefan Hajnoczi     }
23625db9ebeSStefan Hajnoczi     proxy->ioeventfd_started = false;
237b36e3914SMichael S. Tsirkin     error_report("%s: failed. Fallback to a userspace (slower).", __func__);
23825db9ebeSStefan Hajnoczi }
23925db9ebeSStefan Hajnoczi 
240b36e3914SMichael S. Tsirkin static void virtio_pci_stop_ioeventfd(VirtIOPCIProxy *proxy)
24125db9ebeSStefan Hajnoczi {
242b36e3914SMichael S. Tsirkin     int r;
24325db9ebeSStefan Hajnoczi     int n;
24425db9ebeSStefan Hajnoczi 
24525db9ebeSStefan Hajnoczi     if (!proxy->ioeventfd_started) {
246b36e3914SMichael S. Tsirkin         return;
24725db9ebeSStefan Hajnoczi     }
24825db9ebeSStefan Hajnoczi 
24925db9ebeSStefan Hajnoczi     for (n = 0; n < VIRTIO_PCI_QUEUE_MAX; n++) {
25025db9ebeSStefan Hajnoczi         if (!virtio_queue_get_num(proxy->vdev, n)) {
25125db9ebeSStefan Hajnoczi             continue;
25225db9ebeSStefan Hajnoczi         }
25325db9ebeSStefan Hajnoczi 
25426b9b5feSPaolo Bonzini         r = virtio_pci_set_host_notifier_internal(proxy, n, false, false);
255b36e3914SMichael S. Tsirkin         assert(r >= 0);
25625db9ebeSStefan Hajnoczi     }
25725db9ebeSStefan Hajnoczi     proxy->ioeventfd_started = false;
25825db9ebeSStefan Hajnoczi }
25925db9ebeSStefan Hajnoczi 
26060653b28SPaolo Bonzini static void virtio_pci_reset(DeviceState *d)
2617055e687SMichael S. Tsirkin {
262d2a0ccc6SMichael S. Tsirkin     VirtIOPCIProxy *proxy = to_virtio_pci_proxy(d);
26325db9ebeSStefan Hajnoczi     virtio_pci_stop_ioeventfd(proxy);
2647055e687SMichael S. Tsirkin     virtio_reset(proxy->vdev);
2653cac001eSMichael S. Tsirkin     msix_unuse_all_vectors(&proxy->pci_dev);
26625db9ebeSStefan Hajnoczi     proxy->flags &= ~VIRTIO_PCI_FLAG_BUS_MASTER_BUG;
2677055e687SMichael S. Tsirkin }
2687055e687SMichael S. Tsirkin 
26953c25ceaSPaul Brook static void virtio_ioport_write(void *opaque, uint32_t addr, uint32_t val)
27053c25ceaSPaul Brook {
27153c25ceaSPaul Brook     VirtIOPCIProxy *proxy = opaque;
27253c25ceaSPaul Brook     VirtIODevice *vdev = proxy->vdev;
273a8170e5eSAvi Kivity     hwaddr pa;
27453c25ceaSPaul Brook 
27553c25ceaSPaul Brook     switch (addr) {
27653c25ceaSPaul Brook     case VIRTIO_PCI_GUEST_FEATURES:
27753c25ceaSPaul Brook 	/* Guest does not negotiate properly?  We have to assume nothing. */
27853c25ceaSPaul Brook 	if (val & (1 << VIRTIO_F_BAD_FEATURE)) {
279ad0c9332SPaolo Bonzini             val = vdev->bad_features ? vdev->bad_features(vdev) : 0;
28053c25ceaSPaul Brook 	}
281ad0c9332SPaolo Bonzini         virtio_set_features(vdev, val);
28253c25ceaSPaul Brook         break;
28353c25ceaSPaul Brook     case VIRTIO_PCI_QUEUE_PFN:
284a8170e5eSAvi Kivity         pa = (hwaddr)val << VIRTIO_PCI_QUEUE_ADDR_SHIFT;
2851b8e9b27SMichael S. Tsirkin         if (pa == 0) {
28625db9ebeSStefan Hajnoczi             virtio_pci_stop_ioeventfd(proxy);
2871b8e9b27SMichael S. Tsirkin             virtio_reset(proxy->vdev);
2881b8e9b27SMichael S. Tsirkin             msix_unuse_all_vectors(&proxy->pci_dev);
2891b8e9b27SMichael S. Tsirkin         }
2907055e687SMichael S. Tsirkin         else
29153c25ceaSPaul Brook             virtio_queue_set_addr(vdev, vdev->queue_sel, pa);
29253c25ceaSPaul Brook         break;
29353c25ceaSPaul Brook     case VIRTIO_PCI_QUEUE_SEL:
29453c25ceaSPaul Brook         if (val < VIRTIO_PCI_QUEUE_MAX)
29553c25ceaSPaul Brook             vdev->queue_sel = val;
29653c25ceaSPaul Brook         break;
29753c25ceaSPaul Brook     case VIRTIO_PCI_QUEUE_NOTIFY:
2987157e2e2SStefan Hajnoczi         if (val < VIRTIO_PCI_QUEUE_MAX) {
29953c25ceaSPaul Brook             virtio_queue_notify(vdev, val);
3007157e2e2SStefan Hajnoczi         }
30153c25ceaSPaul Brook         break;
30253c25ceaSPaul Brook     case VIRTIO_PCI_STATUS:
30325db9ebeSStefan Hajnoczi         if (!(val & VIRTIO_CONFIG_S_DRIVER_OK)) {
30425db9ebeSStefan Hajnoczi             virtio_pci_stop_ioeventfd(proxy);
30525db9ebeSStefan Hajnoczi         }
30625db9ebeSStefan Hajnoczi 
3073e607cb5SMichael S. Tsirkin         virtio_set_status(vdev, val & 0xFF);
30825db9ebeSStefan Hajnoczi 
30925db9ebeSStefan Hajnoczi         if (val & VIRTIO_CONFIG_S_DRIVER_OK) {
31025db9ebeSStefan Hajnoczi             virtio_pci_start_ioeventfd(proxy);
31125db9ebeSStefan Hajnoczi         }
31225db9ebeSStefan Hajnoczi 
3131b8e9b27SMichael S. Tsirkin         if (vdev->status == 0) {
3141b8e9b27SMichael S. Tsirkin             virtio_reset(proxy->vdev);
3151b8e9b27SMichael S. Tsirkin             msix_unuse_all_vectors(&proxy->pci_dev);
3161b8e9b27SMichael S. Tsirkin         }
317c81131dbSAlexander Graf 
318c81131dbSAlexander Graf         /* Linux before 2.6.34 sets the device as OK without enabling
319c81131dbSAlexander Graf            the PCI device bus master bit. In this case we need to disable
320c81131dbSAlexander Graf            some safety checks. */
321c81131dbSAlexander Graf         if ((val & VIRTIO_CONFIG_S_DRIVER_OK) &&
322c81131dbSAlexander Graf             !(proxy->pci_dev.config[PCI_COMMAND] & PCI_COMMAND_MASTER)) {
3233dbca8e6SStefan Hajnoczi             proxy->flags |= VIRTIO_PCI_FLAG_BUS_MASTER_BUG;
324c81131dbSAlexander Graf         }
32553c25ceaSPaul Brook         break;
326aba800a3SMichael S. Tsirkin     case VIRTIO_MSI_CONFIG_VECTOR:
327aba800a3SMichael S. Tsirkin         msix_vector_unuse(&proxy->pci_dev, vdev->config_vector);
328aba800a3SMichael S. Tsirkin         /* Make it possible for guest to discover an error took place. */
329aba800a3SMichael S. Tsirkin         if (msix_vector_use(&proxy->pci_dev, val) < 0)
330aba800a3SMichael S. Tsirkin             val = VIRTIO_NO_VECTOR;
331aba800a3SMichael S. Tsirkin         vdev->config_vector = val;
332aba800a3SMichael S. Tsirkin         break;
333aba800a3SMichael S. Tsirkin     case VIRTIO_MSI_QUEUE_VECTOR:
334aba800a3SMichael S. Tsirkin         msix_vector_unuse(&proxy->pci_dev,
335aba800a3SMichael S. Tsirkin                           virtio_queue_vector(vdev, vdev->queue_sel));
336aba800a3SMichael S. Tsirkin         /* Make it possible for guest to discover an error took place. */
337aba800a3SMichael S. Tsirkin         if (msix_vector_use(&proxy->pci_dev, val) < 0)
338aba800a3SMichael S. Tsirkin             val = VIRTIO_NO_VECTOR;
339aba800a3SMichael S. Tsirkin         virtio_queue_set_vector(vdev, vdev->queue_sel, val);
340aba800a3SMichael S. Tsirkin         break;
341aba800a3SMichael S. Tsirkin     default:
3424e02d460SStefan Hajnoczi         error_report("%s: unexpected address 0x%x value 0x%x",
343aba800a3SMichael S. Tsirkin                      __func__, addr, val);
344aba800a3SMichael S. Tsirkin         break;
34553c25ceaSPaul Brook     }
34653c25ceaSPaul Brook }
34753c25ceaSPaul Brook 
348aba800a3SMichael S. Tsirkin static uint32_t virtio_ioport_read(VirtIOPCIProxy *proxy, uint32_t addr)
34953c25ceaSPaul Brook {
35053c25ceaSPaul Brook     VirtIODevice *vdev = proxy->vdev;
35153c25ceaSPaul Brook     uint32_t ret = 0xFFFFFFFF;
35253c25ceaSPaul Brook 
35353c25ceaSPaul Brook     switch (addr) {
35453c25ceaSPaul Brook     case VIRTIO_PCI_HOST_FEATURES:
3558172539dSMichael S. Tsirkin         ret = proxy->host_features;
35653c25ceaSPaul Brook         break;
35753c25ceaSPaul Brook     case VIRTIO_PCI_GUEST_FEATURES:
358704a76fcSMichael S. Tsirkin         ret = vdev->guest_features;
35953c25ceaSPaul Brook         break;
36053c25ceaSPaul Brook     case VIRTIO_PCI_QUEUE_PFN:
36153c25ceaSPaul Brook         ret = virtio_queue_get_addr(vdev, vdev->queue_sel)
36253c25ceaSPaul Brook               >> VIRTIO_PCI_QUEUE_ADDR_SHIFT;
36353c25ceaSPaul Brook         break;
36453c25ceaSPaul Brook     case VIRTIO_PCI_QUEUE_NUM:
36553c25ceaSPaul Brook         ret = virtio_queue_get_num(vdev, vdev->queue_sel);
36653c25ceaSPaul Brook         break;
36753c25ceaSPaul Brook     case VIRTIO_PCI_QUEUE_SEL:
36853c25ceaSPaul Brook         ret = vdev->queue_sel;
36953c25ceaSPaul Brook         break;
37053c25ceaSPaul Brook     case VIRTIO_PCI_STATUS:
37153c25ceaSPaul Brook         ret = vdev->status;
37253c25ceaSPaul Brook         break;
37353c25ceaSPaul Brook     case VIRTIO_PCI_ISR:
37453c25ceaSPaul Brook         /* reading from the ISR also clears it. */
37553c25ceaSPaul Brook         ret = vdev->isr;
37653c25ceaSPaul Brook         vdev->isr = 0;
3777055e687SMichael S. Tsirkin         qemu_set_irq(proxy->pci_dev.irq[0], 0);
37853c25ceaSPaul Brook         break;
379aba800a3SMichael S. Tsirkin     case VIRTIO_MSI_CONFIG_VECTOR:
380aba800a3SMichael S. Tsirkin         ret = vdev->config_vector;
381aba800a3SMichael S. Tsirkin         break;
382aba800a3SMichael S. Tsirkin     case VIRTIO_MSI_QUEUE_VECTOR:
383aba800a3SMichael S. Tsirkin         ret = virtio_queue_vector(vdev, vdev->queue_sel);
384aba800a3SMichael S. Tsirkin         break;
38553c25ceaSPaul Brook     default:
38653c25ceaSPaul Brook         break;
38753c25ceaSPaul Brook     }
38853c25ceaSPaul Brook 
38953c25ceaSPaul Brook     return ret;
39053c25ceaSPaul Brook }
39153c25ceaSPaul Brook 
392df6db5b3SAlexander Graf static uint64_t virtio_pci_config_read(void *opaque, hwaddr addr,
393df6db5b3SAlexander Graf                                        unsigned size)
39453c25ceaSPaul Brook {
39553c25ceaSPaul Brook     VirtIOPCIProxy *proxy = opaque;
396aba800a3SMichael S. Tsirkin     uint32_t config = VIRTIO_PCI_CONFIG(&proxy->pci_dev);
397df6db5b3SAlexander Graf     uint64_t val = 0;
398df6db5b3SAlexander Graf     if (addr < config) {
399aba800a3SMichael S. Tsirkin         return virtio_ioport_read(proxy, addr);
40053c25ceaSPaul Brook     }
401aba800a3SMichael S. Tsirkin     addr -= config;
402df6db5b3SAlexander Graf 
403df6db5b3SAlexander Graf     switch (size) {
404df6db5b3SAlexander Graf     case 1:
405df6db5b3SAlexander Graf         val = virtio_config_readb(proxy->vdev, addr);
406df6db5b3SAlexander Graf         break;
407df6db5b3SAlexander Graf     case 2:
40882afa586SBenjamin Herrenschmidt         val = virtio_config_readw(proxy->vdev, addr);
4098e4a424bSBlue Swirl         if (virtio_is_big_endian()) {
4108e4a424bSBlue Swirl             val = bswap16(val);
4118e4a424bSBlue Swirl         }
412df6db5b3SAlexander Graf         break;
413df6db5b3SAlexander Graf     case 4:
41482afa586SBenjamin Herrenschmidt         val = virtio_config_readl(proxy->vdev, addr);
4158e4a424bSBlue Swirl         if (virtio_is_big_endian()) {
4168e4a424bSBlue Swirl             val = bswap32(val);
4178e4a424bSBlue Swirl         }
418df6db5b3SAlexander Graf         break;
419df6db5b3SAlexander Graf     }
42082afa586SBenjamin Herrenschmidt     return val;
42153c25ceaSPaul Brook }
42253c25ceaSPaul Brook 
423df6db5b3SAlexander Graf static void virtio_pci_config_write(void *opaque, hwaddr addr,
424df6db5b3SAlexander Graf                                     uint64_t val, unsigned size)
42553c25ceaSPaul Brook {
42653c25ceaSPaul Brook     VirtIOPCIProxy *proxy = opaque;
427aba800a3SMichael S. Tsirkin     uint32_t config = VIRTIO_PCI_CONFIG(&proxy->pci_dev);
428aba800a3SMichael S. Tsirkin     if (addr < config) {
429aba800a3SMichael S. Tsirkin         virtio_ioport_write(proxy, addr, val);
430aba800a3SMichael S. Tsirkin         return;
431aba800a3SMichael S. Tsirkin     }
432aba800a3SMichael S. Tsirkin     addr -= config;
433df6db5b3SAlexander Graf     /*
434df6db5b3SAlexander Graf      * Virtio-PCI is odd. Ioports are LE but config space is target native
435df6db5b3SAlexander Graf      * endian.
436df6db5b3SAlexander Graf      */
437df6db5b3SAlexander Graf     switch (size) {
438df6db5b3SAlexander Graf     case 1:
43953c25ceaSPaul Brook         virtio_config_writeb(proxy->vdev, addr, val);
440df6db5b3SAlexander Graf         break;
441df6db5b3SAlexander Graf     case 2:
4428e4a424bSBlue Swirl         if (virtio_is_big_endian()) {
4438e4a424bSBlue Swirl             val = bswap16(val);
4448e4a424bSBlue Swirl         }
44553c25ceaSPaul Brook         virtio_config_writew(proxy->vdev, addr, val);
446df6db5b3SAlexander Graf         break;
447df6db5b3SAlexander Graf     case 4:
4488e4a424bSBlue Swirl         if (virtio_is_big_endian()) {
4498e4a424bSBlue Swirl             val = bswap32(val);
4508e4a424bSBlue Swirl         }
45153c25ceaSPaul Brook         virtio_config_writel(proxy->vdev, addr, val);
452df6db5b3SAlexander Graf         break;
453df6db5b3SAlexander Graf     }
45453c25ceaSPaul Brook }
45553c25ceaSPaul Brook 
456da146d0aSAvi Kivity static const MemoryRegionOps virtio_pci_config_ops = {
457df6db5b3SAlexander Graf     .read = virtio_pci_config_read,
458df6db5b3SAlexander Graf     .write = virtio_pci_config_write,
459df6db5b3SAlexander Graf     .impl = {
460df6db5b3SAlexander Graf         .min_access_size = 1,
461df6db5b3SAlexander Graf         .max_access_size = 4,
462df6db5b3SAlexander Graf     },
4638e4a424bSBlue Swirl     .endianness = DEVICE_LITTLE_ENDIAN,
464da146d0aSAvi Kivity };
465aba800a3SMichael S. Tsirkin 
466aba800a3SMichael S. Tsirkin static void virtio_write_config(PCIDevice *pci_dev, uint32_t address,
467aba800a3SMichael S. Tsirkin                                 uint32_t val, int len)
468aba800a3SMichael S. Tsirkin {
469ed757e14SYan Vugenfirer     VirtIOPCIProxy *proxy = DO_UPCAST(VirtIOPCIProxy, pci_dev, pci_dev);
470ed757e14SYan Vugenfirer 
4711129714fSMichael S. Tsirkin     pci_default_write_config(pci_dev, address, val, len);
4721129714fSMichael S. Tsirkin 
4731129714fSMichael S. Tsirkin     if (range_covers_byte(address, len, PCI_COMMAND) &&
4741129714fSMichael S. Tsirkin         !(pci_dev->config[PCI_COMMAND] & PCI_COMMAND_MASTER) &&
4751129714fSMichael S. Tsirkin         !(proxy->flags & VIRTIO_PCI_FLAG_BUS_MASTER_BUG)) {
47625db9ebeSStefan Hajnoczi         virtio_pci_stop_ioeventfd(proxy);
4773e607cb5SMichael S. Tsirkin         virtio_set_status(proxy->vdev,
4783e607cb5SMichael S. Tsirkin                           proxy->vdev->status & ~VIRTIO_CONFIG_S_DRIVER_OK);
479ed757e14SYan Vugenfirer     }
48053c25ceaSPaul Brook }
48153c25ceaSPaul Brook 
482d2a0ccc6SMichael S. Tsirkin static unsigned virtio_pci_get_features(DeviceState *d)
4836d74ca5aSMichael S. Tsirkin {
484d2a0ccc6SMichael S. Tsirkin     VirtIOPCIProxy *proxy = to_virtio_pci_proxy(d);
4858172539dSMichael S. Tsirkin     return proxy->host_features;
4866d74ca5aSMichael S. Tsirkin }
4876d74ca5aSMichael S. Tsirkin 
4887d37d351SJan Kiszka static int kvm_virtio_pci_vq_vector_use(VirtIOPCIProxy *proxy,
4897d37d351SJan Kiszka                                         unsigned int queue_no,
4907d37d351SJan Kiszka                                         unsigned int vector,
4917d37d351SJan Kiszka                                         MSIMessage msg)
4927d37d351SJan Kiszka {
4937d37d351SJan Kiszka     VirtIOIRQFD *irqfd = &proxy->vector_irqfd[vector];
49415b2bd18SPaolo Bonzini     int ret;
4957d37d351SJan Kiszka 
4967d37d351SJan Kiszka     if (irqfd->users == 0) {
4977d37d351SJan Kiszka         ret = kvm_irqchip_add_msi_route(kvm_state, msg);
4987d37d351SJan Kiszka         if (ret < 0) {
4997d37d351SJan Kiszka             return ret;
5007d37d351SJan Kiszka         }
5017d37d351SJan Kiszka         irqfd->virq = ret;
5027d37d351SJan Kiszka     }
5037d37d351SJan Kiszka     irqfd->users++;
5047d37d351SJan Kiszka     return 0;
5057d37d351SJan Kiszka }
5067d37d351SJan Kiszka 
5077d37d351SJan Kiszka static void kvm_virtio_pci_vq_vector_release(VirtIOPCIProxy *proxy,
508774345f9SMichael S. Tsirkin                                              unsigned int vector)
509774345f9SMichael S. Tsirkin {
510774345f9SMichael S. Tsirkin     VirtIOIRQFD *irqfd = &proxy->vector_irqfd[vector];
511774345f9SMichael S. Tsirkin     if (--irqfd->users == 0) {
512774345f9SMichael S. Tsirkin         kvm_irqchip_release_virq(kvm_state, irqfd->virq);
513774345f9SMichael S. Tsirkin     }
514774345f9SMichael S. Tsirkin }
515774345f9SMichael S. Tsirkin 
516f1d0f15aSMichael S. Tsirkin static int kvm_virtio_pci_irqfd_use(VirtIOPCIProxy *proxy,
517f1d0f15aSMichael S. Tsirkin                                  unsigned int queue_no,
518f1d0f15aSMichael S. Tsirkin                                  unsigned int vector)
519f1d0f15aSMichael S. Tsirkin {
520f1d0f15aSMichael S. Tsirkin     VirtIOIRQFD *irqfd = &proxy->vector_irqfd[vector];
521f1d0f15aSMichael S. Tsirkin     VirtQueue *vq = virtio_get_queue(proxy->vdev, queue_no);
522f1d0f15aSMichael S. Tsirkin     EventNotifier *n = virtio_queue_get_guest_notifier(vq);
523f1d0f15aSMichael S. Tsirkin     int ret;
524f1d0f15aSMichael S. Tsirkin     ret = kvm_irqchip_add_irqfd_notifier(kvm_state, n, irqfd->virq);
525f1d0f15aSMichael S. Tsirkin     return ret;
526f1d0f15aSMichael S. Tsirkin }
527f1d0f15aSMichael S. Tsirkin 
528f1d0f15aSMichael S. Tsirkin static void kvm_virtio_pci_irqfd_release(VirtIOPCIProxy *proxy,
5297d37d351SJan Kiszka                                       unsigned int queue_no,
5307d37d351SJan Kiszka                                       unsigned int vector)
5317d37d351SJan Kiszka {
5327d37d351SJan Kiszka     VirtQueue *vq = virtio_get_queue(proxy->vdev, queue_no);
53315b2bd18SPaolo Bonzini     EventNotifier *n = virtio_queue_get_guest_notifier(vq);
5347d37d351SJan Kiszka     VirtIOIRQFD *irqfd = &proxy->vector_irqfd[vector];
53515b2bd18SPaolo Bonzini     int ret;
5367d37d351SJan Kiszka 
537b131c74aSJan Kiszka     ret = kvm_irqchip_remove_irqfd_notifier(kvm_state, n, irqfd->virq);
5387d37d351SJan Kiszka     assert(ret == 0);
539f1d0f15aSMichael S. Tsirkin }
5407d37d351SJan Kiszka 
541774345f9SMichael S. Tsirkin static int kvm_virtio_pci_vector_use(VirtIOPCIProxy *proxy, int nvqs)
542774345f9SMichael S. Tsirkin {
543774345f9SMichael S. Tsirkin     PCIDevice *dev = &proxy->pci_dev;
544774345f9SMichael S. Tsirkin     VirtIODevice *vdev = proxy->vdev;
545774345f9SMichael S. Tsirkin     unsigned int vector;
546774345f9SMichael S. Tsirkin     int ret, queue_no;
547774345f9SMichael S. Tsirkin     MSIMessage msg;
548774345f9SMichael S. Tsirkin 
549774345f9SMichael S. Tsirkin     for (queue_no = 0; queue_no < nvqs; queue_no++) {
550774345f9SMichael S. Tsirkin         if (!virtio_queue_get_num(vdev, queue_no)) {
551774345f9SMichael S. Tsirkin             break;
552774345f9SMichael S. Tsirkin         }
553774345f9SMichael S. Tsirkin         vector = virtio_queue_vector(vdev, queue_no);
554774345f9SMichael S. Tsirkin         if (vector >= msix_nr_vectors_allocated(dev)) {
555774345f9SMichael S. Tsirkin             continue;
556774345f9SMichael S. Tsirkin         }
557774345f9SMichael S. Tsirkin         msg = msix_get_message(dev, vector);
558774345f9SMichael S. Tsirkin         ret = kvm_virtio_pci_vq_vector_use(proxy, queue_no, vector, msg);
559774345f9SMichael S. Tsirkin         if (ret < 0) {
560774345f9SMichael S. Tsirkin             goto undo;
561774345f9SMichael S. Tsirkin         }
562f1d0f15aSMichael S. Tsirkin         /* If guest supports masking, set up irqfd now.
563f1d0f15aSMichael S. Tsirkin          * Otherwise, delay until unmasked in the frontend.
564f1d0f15aSMichael S. Tsirkin          */
565f1d0f15aSMichael S. Tsirkin         if (proxy->vdev->guest_notifier_mask) {
566f1d0f15aSMichael S. Tsirkin             ret = kvm_virtio_pci_irqfd_use(proxy, queue_no, vector);
567f1d0f15aSMichael S. Tsirkin             if (ret < 0) {
568f1d0f15aSMichael S. Tsirkin                 kvm_virtio_pci_vq_vector_release(proxy, vector);
569f1d0f15aSMichael S. Tsirkin                 goto undo;
570f1d0f15aSMichael S. Tsirkin             }
571f1d0f15aSMichael S. Tsirkin         }
572774345f9SMichael S. Tsirkin     }
573774345f9SMichael S. Tsirkin     return 0;
574774345f9SMichael S. Tsirkin 
575774345f9SMichael S. Tsirkin undo:
576774345f9SMichael S. Tsirkin     while (--queue_no >= 0) {
577774345f9SMichael S. Tsirkin         vector = virtio_queue_vector(vdev, queue_no);
578774345f9SMichael S. Tsirkin         if (vector >= msix_nr_vectors_allocated(dev)) {
579774345f9SMichael S. Tsirkin             continue;
580774345f9SMichael S. Tsirkin         }
581f1d0f15aSMichael S. Tsirkin         if (proxy->vdev->guest_notifier_mask) {
582e387f99eSMichael S. Tsirkin             kvm_virtio_pci_irqfd_release(proxy, queue_no, vector);
583f1d0f15aSMichael S. Tsirkin         }
584774345f9SMichael S. Tsirkin         kvm_virtio_pci_vq_vector_release(proxy, vector);
585774345f9SMichael S. Tsirkin     }
586774345f9SMichael S. Tsirkin     return ret;
587774345f9SMichael S. Tsirkin }
588774345f9SMichael S. Tsirkin 
589774345f9SMichael S. Tsirkin static void kvm_virtio_pci_vector_release(VirtIOPCIProxy *proxy, int nvqs)
590774345f9SMichael S. Tsirkin {
591774345f9SMichael S. Tsirkin     PCIDevice *dev = &proxy->pci_dev;
592774345f9SMichael S. Tsirkin     VirtIODevice *vdev = proxy->vdev;
593774345f9SMichael S. Tsirkin     unsigned int vector;
594774345f9SMichael S. Tsirkin     int queue_no;
595774345f9SMichael S. Tsirkin 
596774345f9SMichael S. Tsirkin     for (queue_no = 0; queue_no < nvqs; queue_no++) {
597774345f9SMichael S. Tsirkin         if (!virtio_queue_get_num(vdev, queue_no)) {
598774345f9SMichael S. Tsirkin             break;
599774345f9SMichael S. Tsirkin         }
600774345f9SMichael S. Tsirkin         vector = virtio_queue_vector(vdev, queue_no);
601774345f9SMichael S. Tsirkin         if (vector >= msix_nr_vectors_allocated(dev)) {
602774345f9SMichael S. Tsirkin             continue;
603774345f9SMichael S. Tsirkin         }
604f1d0f15aSMichael S. Tsirkin         /* If guest supports masking, clean up irqfd now.
605f1d0f15aSMichael S. Tsirkin          * Otherwise, it was cleaned when masked in the frontend.
606f1d0f15aSMichael S. Tsirkin          */
607f1d0f15aSMichael S. Tsirkin         if (proxy->vdev->guest_notifier_mask) {
608e387f99eSMichael S. Tsirkin             kvm_virtio_pci_irqfd_release(proxy, queue_no, vector);
609f1d0f15aSMichael S. Tsirkin         }
610774345f9SMichael S. Tsirkin         kvm_virtio_pci_vq_vector_release(proxy, vector);
6117d37d351SJan Kiszka     }
6127d37d351SJan Kiszka }
6137d37d351SJan Kiszka 
614a38b2c49SMichael S. Tsirkin static int virtio_pci_vq_vector_unmask(VirtIOPCIProxy *proxy,
615774345f9SMichael S. Tsirkin                                        unsigned int queue_no,
616774345f9SMichael S. Tsirkin                                        unsigned int vector,
617774345f9SMichael S. Tsirkin                                        MSIMessage msg)
618774345f9SMichael S. Tsirkin {
619774345f9SMichael S. Tsirkin     VirtQueue *vq = virtio_get_queue(proxy->vdev, queue_no);
620774345f9SMichael S. Tsirkin     EventNotifier *n = virtio_queue_get_guest_notifier(vq);
621a38b2c49SMichael S. Tsirkin     VirtIOIRQFD *irqfd;
62253510bfcSMichael Roth     int ret = 0;
623774345f9SMichael S. Tsirkin 
624a38b2c49SMichael S. Tsirkin     if (proxy->vector_irqfd) {
625a38b2c49SMichael S. Tsirkin         irqfd = &proxy->vector_irqfd[vector];
626774345f9SMichael S. Tsirkin         if (irqfd->msg.data != msg.data || irqfd->msg.address != msg.address) {
627774345f9SMichael S. Tsirkin             ret = kvm_irqchip_update_msi_route(kvm_state, irqfd->virq, msg);
628774345f9SMichael S. Tsirkin             if (ret < 0) {
629774345f9SMichael S. Tsirkin                 return ret;
630774345f9SMichael S. Tsirkin             }
631774345f9SMichael S. Tsirkin         }
632a38b2c49SMichael S. Tsirkin     }
633774345f9SMichael S. Tsirkin 
634f1d0f15aSMichael S. Tsirkin     /* If guest supports masking, irqfd is already setup, unmask it.
635f1d0f15aSMichael S. Tsirkin      * Otherwise, set it up now.
636f1d0f15aSMichael S. Tsirkin      */
637f1d0f15aSMichael S. Tsirkin     if (proxy->vdev->guest_notifier_mask) {
638f1d0f15aSMichael S. Tsirkin         proxy->vdev->guest_notifier_mask(proxy->vdev, queue_no, false);
639f1d0f15aSMichael S. Tsirkin         /* Test after unmasking to avoid losing events. */
640f1d0f15aSMichael S. Tsirkin         if (proxy->vdev->guest_notifier_pending &&
641f1d0f15aSMichael S. Tsirkin             proxy->vdev->guest_notifier_pending(proxy->vdev, queue_no)) {
642f1d0f15aSMichael S. Tsirkin             event_notifier_set(n);
643f1d0f15aSMichael S. Tsirkin         }
644f1d0f15aSMichael S. Tsirkin     } else {
645f1d0f15aSMichael S. Tsirkin         ret = kvm_virtio_pci_irqfd_use(proxy, queue_no, vector);
646f1d0f15aSMichael S. Tsirkin     }
647774345f9SMichael S. Tsirkin     return ret;
648774345f9SMichael S. Tsirkin }
649774345f9SMichael S. Tsirkin 
650a38b2c49SMichael S. Tsirkin static void virtio_pci_vq_vector_mask(VirtIOPCIProxy *proxy,
6517d37d351SJan Kiszka                                              unsigned int queue_no,
6527d37d351SJan Kiszka                                              unsigned int vector)
6537d37d351SJan Kiszka {
654f1d0f15aSMichael S. Tsirkin     /* If guest supports masking, keep irqfd but mask it.
655f1d0f15aSMichael S. Tsirkin      * Otherwise, clean it up now.
656f1d0f15aSMichael S. Tsirkin      */
657f1d0f15aSMichael S. Tsirkin     if (proxy->vdev->guest_notifier_mask) {
658f1d0f15aSMichael S. Tsirkin         proxy->vdev->guest_notifier_mask(proxy->vdev, queue_no, true);
659f1d0f15aSMichael S. Tsirkin     } else {
660e387f99eSMichael S. Tsirkin         kvm_virtio_pci_irqfd_release(proxy, queue_no, vector);
661f1d0f15aSMichael S. Tsirkin     }
6627d37d351SJan Kiszka }
6637d37d351SJan Kiszka 
664a38b2c49SMichael S. Tsirkin static int virtio_pci_vector_unmask(PCIDevice *dev, unsigned vector,
6657d37d351SJan Kiszka                                     MSIMessage msg)
6667d37d351SJan Kiszka {
6677d37d351SJan Kiszka     VirtIOPCIProxy *proxy = container_of(dev, VirtIOPCIProxy, pci_dev);
6687d37d351SJan Kiszka     VirtIODevice *vdev = proxy->vdev;
6697d37d351SJan Kiszka     int ret, queue_no;
6707d37d351SJan Kiszka 
6712d620f59SMichael S. Tsirkin     for (queue_no = 0; queue_no < proxy->nvqs_with_notifiers; queue_no++) {
6727d37d351SJan Kiszka         if (!virtio_queue_get_num(vdev, queue_no)) {
6737d37d351SJan Kiszka             break;
6747d37d351SJan Kiszka         }
6757d37d351SJan Kiszka         if (virtio_queue_vector(vdev, queue_no) != vector) {
6767d37d351SJan Kiszka             continue;
6777d37d351SJan Kiszka         }
678a38b2c49SMichael S. Tsirkin         ret = virtio_pci_vq_vector_unmask(proxy, queue_no, vector, msg);
6797d37d351SJan Kiszka         if (ret < 0) {
6807d37d351SJan Kiszka             goto undo;
6817d37d351SJan Kiszka         }
6827d37d351SJan Kiszka     }
6837d37d351SJan Kiszka     return 0;
6847d37d351SJan Kiszka 
6857d37d351SJan Kiszka undo:
6867d37d351SJan Kiszka     while (--queue_no >= 0) {
6877d37d351SJan Kiszka         if (virtio_queue_vector(vdev, queue_no) != vector) {
6887d37d351SJan Kiszka             continue;
6897d37d351SJan Kiszka         }
690a38b2c49SMichael S. Tsirkin         virtio_pci_vq_vector_mask(proxy, queue_no, vector);
6917d37d351SJan Kiszka     }
6927d37d351SJan Kiszka     return ret;
6937d37d351SJan Kiszka }
6947d37d351SJan Kiszka 
695a38b2c49SMichael S. Tsirkin static void virtio_pci_vector_mask(PCIDevice *dev, unsigned vector)
6967d37d351SJan Kiszka {
6977d37d351SJan Kiszka     VirtIOPCIProxy *proxy = container_of(dev, VirtIOPCIProxy, pci_dev);
6987d37d351SJan Kiszka     VirtIODevice *vdev = proxy->vdev;
6997d37d351SJan Kiszka     int queue_no;
7007d37d351SJan Kiszka 
7012d620f59SMichael S. Tsirkin     for (queue_no = 0; queue_no < proxy->nvqs_with_notifiers; queue_no++) {
7027d37d351SJan Kiszka         if (!virtio_queue_get_num(vdev, queue_no)) {
7037d37d351SJan Kiszka             break;
7047d37d351SJan Kiszka         }
7057d37d351SJan Kiszka         if (virtio_queue_vector(vdev, queue_no) != vector) {
7067d37d351SJan Kiszka             continue;
7077d37d351SJan Kiszka         }
708a38b2c49SMichael S. Tsirkin         virtio_pci_vq_vector_mask(proxy, queue_no, vector);
7097d37d351SJan Kiszka     }
7107d37d351SJan Kiszka }
7117d37d351SJan Kiszka 
712a38b2c49SMichael S. Tsirkin static void virtio_pci_vector_poll(PCIDevice *dev,
71389d62be9SMichael S. Tsirkin                                    unsigned int vector_start,
71489d62be9SMichael S. Tsirkin                                    unsigned int vector_end)
71589d62be9SMichael S. Tsirkin {
71689d62be9SMichael S. Tsirkin     VirtIOPCIProxy *proxy = container_of(dev, VirtIOPCIProxy, pci_dev);
71789d62be9SMichael S. Tsirkin     VirtIODevice *vdev = proxy->vdev;
71889d62be9SMichael S. Tsirkin     int queue_no;
71989d62be9SMichael S. Tsirkin     unsigned int vector;
72089d62be9SMichael S. Tsirkin     EventNotifier *notifier;
72189d62be9SMichael S. Tsirkin     VirtQueue *vq;
72289d62be9SMichael S. Tsirkin 
7232d620f59SMichael S. Tsirkin     for (queue_no = 0; queue_no < proxy->nvqs_with_notifiers; queue_no++) {
72489d62be9SMichael S. Tsirkin         if (!virtio_queue_get_num(vdev, queue_no)) {
72589d62be9SMichael S. Tsirkin             break;
72689d62be9SMichael S. Tsirkin         }
72789d62be9SMichael S. Tsirkin         vector = virtio_queue_vector(vdev, queue_no);
72889d62be9SMichael S. Tsirkin         if (vector < vector_start || vector >= vector_end ||
72989d62be9SMichael S. Tsirkin             !msix_is_masked(dev, vector)) {
73089d62be9SMichael S. Tsirkin             continue;
73189d62be9SMichael S. Tsirkin         }
73289d62be9SMichael S. Tsirkin         vq = virtio_get_queue(vdev, queue_no);
73389d62be9SMichael S. Tsirkin         notifier = virtio_queue_get_guest_notifier(vq);
734f1d0f15aSMichael S. Tsirkin         if (vdev->guest_notifier_pending) {
735f1d0f15aSMichael S. Tsirkin             if (vdev->guest_notifier_pending(vdev, queue_no)) {
736f1d0f15aSMichael S. Tsirkin                 msix_set_pending(dev, vector);
737f1d0f15aSMichael S. Tsirkin             }
738f1d0f15aSMichael S. Tsirkin         } else if (event_notifier_test_and_clear(notifier)) {
73989d62be9SMichael S. Tsirkin             msix_set_pending(dev, vector);
74089d62be9SMichael S. Tsirkin         }
74189d62be9SMichael S. Tsirkin     }
74289d62be9SMichael S. Tsirkin }
74389d62be9SMichael S. Tsirkin 
74489d62be9SMichael S. Tsirkin static int virtio_pci_set_guest_notifier(DeviceState *d, int n, bool assign,
74589d62be9SMichael S. Tsirkin                                          bool with_irqfd)
746ade80dc8SMichael S. Tsirkin {
747d2a0ccc6SMichael S. Tsirkin     VirtIOPCIProxy *proxy = to_virtio_pci_proxy(d);
748ade80dc8SMichael S. Tsirkin     VirtQueue *vq = virtio_get_queue(proxy->vdev, n);
749ade80dc8SMichael S. Tsirkin     EventNotifier *notifier = virtio_queue_get_guest_notifier(vq);
750ade80dc8SMichael S. Tsirkin 
751ade80dc8SMichael S. Tsirkin     if (assign) {
752ade80dc8SMichael S. Tsirkin         int r = event_notifier_init(notifier, 0);
753ade80dc8SMichael S. Tsirkin         if (r < 0) {
754ade80dc8SMichael S. Tsirkin             return r;
755ade80dc8SMichael S. Tsirkin         }
75689d62be9SMichael S. Tsirkin         virtio_queue_set_guest_notifier_fd_handler(vq, true, with_irqfd);
757ade80dc8SMichael S. Tsirkin     } else {
75889d62be9SMichael S. Tsirkin         virtio_queue_set_guest_notifier_fd_handler(vq, false, with_irqfd);
759ade80dc8SMichael S. Tsirkin         event_notifier_cleanup(notifier);
760ade80dc8SMichael S. Tsirkin     }
761ade80dc8SMichael S. Tsirkin 
762ade80dc8SMichael S. Tsirkin     return 0;
763ade80dc8SMichael S. Tsirkin }
764ade80dc8SMichael S. Tsirkin 
765d2a0ccc6SMichael S. Tsirkin static bool virtio_pci_query_guest_notifiers(DeviceState *d)
7665430a28fSmst@redhat.com {
767d2a0ccc6SMichael S. Tsirkin     VirtIOPCIProxy *proxy = to_virtio_pci_proxy(d);
7685430a28fSmst@redhat.com     return msix_enabled(&proxy->pci_dev);
7695430a28fSmst@redhat.com }
7705430a28fSmst@redhat.com 
7712d620f59SMichael S. Tsirkin static int virtio_pci_set_guest_notifiers(DeviceState *d, int nvqs, bool assign)
77254dd9321SMichael S. Tsirkin {
773d2a0ccc6SMichael S. Tsirkin     VirtIOPCIProxy *proxy = to_virtio_pci_proxy(d);
77454dd9321SMichael S. Tsirkin     VirtIODevice *vdev = proxy->vdev;
77554dd9321SMichael S. Tsirkin     int r, n;
77689d62be9SMichael S. Tsirkin     bool with_irqfd = msix_enabled(&proxy->pci_dev) &&
77789d62be9SMichael S. Tsirkin         kvm_msi_via_irqfd_enabled();
77854dd9321SMichael S. Tsirkin 
7792d620f59SMichael S. Tsirkin     nvqs = MIN(nvqs, VIRTIO_PCI_QUEUE_MAX);
7802d620f59SMichael S. Tsirkin 
7812d620f59SMichael S. Tsirkin     /* When deassigning, pass a consistent nvqs value
7822d620f59SMichael S. Tsirkin      * to avoid leaking notifiers.
7832d620f59SMichael S. Tsirkin      */
7842d620f59SMichael S. Tsirkin     assert(assign || nvqs == proxy->nvqs_with_notifiers);
7852d620f59SMichael S. Tsirkin 
7862d620f59SMichael S. Tsirkin     proxy->nvqs_with_notifiers = nvqs;
7872d620f59SMichael S. Tsirkin 
7887d37d351SJan Kiszka     /* Must unset vector notifier while guest notifier is still assigned */
789a38b2c49SMichael S. Tsirkin     if ((proxy->vector_irqfd || vdev->guest_notifier_mask) && !assign) {
7907d37d351SJan Kiszka         msix_unset_vector_notifiers(&proxy->pci_dev);
791a38b2c49SMichael S. Tsirkin         if (proxy->vector_irqfd) {
792774345f9SMichael S. Tsirkin             kvm_virtio_pci_vector_release(proxy, nvqs);
7937d37d351SJan Kiszka             g_free(proxy->vector_irqfd);
7947d37d351SJan Kiszka             proxy->vector_irqfd = NULL;
7957d37d351SJan Kiszka         }
796a38b2c49SMichael S. Tsirkin     }
7977d37d351SJan Kiszka 
7982d620f59SMichael S. Tsirkin     for (n = 0; n < nvqs; n++) {
79954dd9321SMichael S. Tsirkin         if (!virtio_queue_get_num(vdev, n)) {
80054dd9321SMichael S. Tsirkin             break;
80154dd9321SMichael S. Tsirkin         }
80254dd9321SMichael S. Tsirkin 
80389d62be9SMichael S. Tsirkin         r = virtio_pci_set_guest_notifier(d, n, assign,
80489d62be9SMichael S. Tsirkin                                           kvm_msi_via_irqfd_enabled());
80554dd9321SMichael S. Tsirkin         if (r < 0) {
80654dd9321SMichael S. Tsirkin             goto assign_error;
80754dd9321SMichael S. Tsirkin         }
80854dd9321SMichael S. Tsirkin     }
80954dd9321SMichael S. Tsirkin 
8107d37d351SJan Kiszka     /* Must set vector notifier after guest notifier has been assigned */
811a38b2c49SMichael S. Tsirkin     if ((with_irqfd || vdev->guest_notifier_mask) && assign) {
812a38b2c49SMichael S. Tsirkin         if (with_irqfd) {
8137d37d351SJan Kiszka             proxy->vector_irqfd =
8147d37d351SJan Kiszka                 g_malloc0(sizeof(*proxy->vector_irqfd) *
8157d37d351SJan Kiszka                           msix_nr_vectors_allocated(&proxy->pci_dev));
816774345f9SMichael S. Tsirkin             r = kvm_virtio_pci_vector_use(proxy, nvqs);
8177d37d351SJan Kiszka             if (r < 0) {
8187d37d351SJan Kiszka                 goto assign_error;
8197d37d351SJan Kiszka             }
820a38b2c49SMichael S. Tsirkin         }
821774345f9SMichael S. Tsirkin         r = msix_set_vector_notifiers(&proxy->pci_dev,
822a38b2c49SMichael S. Tsirkin                                       virtio_pci_vector_unmask,
823a38b2c49SMichael S. Tsirkin                                       virtio_pci_vector_mask,
824a38b2c49SMichael S. Tsirkin                                       virtio_pci_vector_poll);
825774345f9SMichael S. Tsirkin         if (r < 0) {
826774345f9SMichael S. Tsirkin             goto notifiers_error;
827774345f9SMichael S. Tsirkin         }
8287d37d351SJan Kiszka     }
8297d37d351SJan Kiszka 
83054dd9321SMichael S. Tsirkin     return 0;
83154dd9321SMichael S. Tsirkin 
832774345f9SMichael S. Tsirkin notifiers_error:
833a38b2c49SMichael S. Tsirkin     if (with_irqfd) {
834774345f9SMichael S. Tsirkin         assert(assign);
835774345f9SMichael S. Tsirkin         kvm_virtio_pci_vector_release(proxy, nvqs);
836a38b2c49SMichael S. Tsirkin     }
837774345f9SMichael S. Tsirkin 
83854dd9321SMichael S. Tsirkin assign_error:
83954dd9321SMichael S. Tsirkin     /* We get here on assignment failure. Recover by undoing for VQs 0 .. n. */
8407d37d351SJan Kiszka     assert(assign);
84154dd9321SMichael S. Tsirkin     while (--n >= 0) {
84289d62be9SMichael S. Tsirkin         virtio_pci_set_guest_notifier(d, n, !assign, with_irqfd);
84354dd9321SMichael S. Tsirkin     }
84454dd9321SMichael S. Tsirkin     return r;
84554dd9321SMichael S. Tsirkin }
84654dd9321SMichael S. Tsirkin 
847d2a0ccc6SMichael S. Tsirkin static int virtio_pci_set_host_notifier(DeviceState *d, int n, bool assign)
848ade80dc8SMichael S. Tsirkin {
849d2a0ccc6SMichael S. Tsirkin     VirtIOPCIProxy *proxy = to_virtio_pci_proxy(d);
85025db9ebeSStefan Hajnoczi 
85125db9ebeSStefan Hajnoczi     /* Stop using ioeventfd for virtqueue kick if the device starts using host
85225db9ebeSStefan Hajnoczi      * notifiers.  This makes it easy to avoid stepping on each others' toes.
85325db9ebeSStefan Hajnoczi      */
85425db9ebeSStefan Hajnoczi     proxy->ioeventfd_disabled = assign;
855ade80dc8SMichael S. Tsirkin     if (assign) {
85625db9ebeSStefan Hajnoczi         virtio_pci_stop_ioeventfd(proxy);
857ade80dc8SMichael S. Tsirkin     }
85825db9ebeSStefan Hajnoczi     /* We don't need to start here: it's not needed because backend
85925db9ebeSStefan Hajnoczi      * currently only stops on status change away from ok,
86025db9ebeSStefan Hajnoczi      * reset, vmstop and such. If we do add code to start here,
86125db9ebeSStefan Hajnoczi      * need to check vmstate, device state etc. */
86226b9b5feSPaolo Bonzini     return virtio_pci_set_host_notifier_internal(proxy, n, assign, false);
863ade80dc8SMichael S. Tsirkin }
86425db9ebeSStefan Hajnoczi 
865d2a0ccc6SMichael S. Tsirkin static void virtio_pci_vmstate_change(DeviceState *d, bool running)
86625db9ebeSStefan Hajnoczi {
867d2a0ccc6SMichael S. Tsirkin     VirtIOPCIProxy *proxy = to_virtio_pci_proxy(d);
86825db9ebeSStefan Hajnoczi 
86925db9ebeSStefan Hajnoczi     if (running) {
87089c473fdSMichael S. Tsirkin         /* Try to find out if the guest has bus master disabled, but is
87189c473fdSMichael S. Tsirkin            in ready state. Then we have a buggy guest OS. */
87289c473fdSMichael S. Tsirkin         if ((proxy->vdev->status & VIRTIO_CONFIG_S_DRIVER_OK) &&
87389c473fdSMichael S. Tsirkin             !(proxy->pci_dev.config[PCI_COMMAND] & PCI_COMMAND_MASTER)) {
87489c473fdSMichael S. Tsirkin             proxy->flags |= VIRTIO_PCI_FLAG_BUS_MASTER_BUG;
87589c473fdSMichael S. Tsirkin         }
87625db9ebeSStefan Hajnoczi         virtio_pci_start_ioeventfd(proxy);
877ade80dc8SMichael S. Tsirkin     } else {
87825db9ebeSStefan Hajnoczi         virtio_pci_stop_ioeventfd(proxy);
879ade80dc8SMichael S. Tsirkin     }
880ade80dc8SMichael S. Tsirkin }
881ade80dc8SMichael S. Tsirkin 
88253c25ceaSPaul Brook static const VirtIOBindings virtio_pci_bindings = {
883ff24bd58SMichael S. Tsirkin     .notify = virtio_pci_notify,
884ff24bd58SMichael S. Tsirkin     .save_config = virtio_pci_save_config,
885ff24bd58SMichael S. Tsirkin     .load_config = virtio_pci_load_config,
886ff24bd58SMichael S. Tsirkin     .save_queue = virtio_pci_save_queue,
887ff24bd58SMichael S. Tsirkin     .load_queue = virtio_pci_load_queue,
8886d74ca5aSMichael S. Tsirkin     .get_features = virtio_pci_get_features,
8895430a28fSmst@redhat.com     .query_guest_notifiers = virtio_pci_query_guest_notifiers,
890ade80dc8SMichael S. Tsirkin     .set_host_notifier = virtio_pci_set_host_notifier,
89154dd9321SMichael S. Tsirkin     .set_guest_notifiers = virtio_pci_set_guest_notifiers,
89225db9ebeSStefan Hajnoczi     .vmstate_change = virtio_pci_vmstate_change,
89353c25ceaSPaul Brook };
89453c25ceaSPaul Brook 
895befeac45SMichael S. Tsirkin void virtio_init_pci(VirtIOPCIProxy *proxy, VirtIODevice *vdev)
89653c25ceaSPaul Brook {
89753c25ceaSPaul Brook     uint8_t *config;
89853c25ceaSPaul Brook     uint32_t size;
89953c25ceaSPaul Brook 
90053c25ceaSPaul Brook     proxy->vdev = vdev;
90153c25ceaSPaul Brook 
90253c25ceaSPaul Brook     config = proxy->pci_dev.config;
90353c25ceaSPaul Brook 
904e75ccf2cSIsaku Yamahata     if (proxy->class_code) {
905e75ccf2cSIsaku Yamahata         pci_config_set_class(config, proxy->class_code);
906e75ccf2cSIsaku Yamahata     }
907ad3d11e6SHui Kai Ran     pci_set_word(config + PCI_SUBSYSTEM_VENDOR_ID,
908ad3d11e6SHui Kai Ran                  pci_get_word(config + PCI_VENDOR_ID));
909ad3d11e6SHui Kai Ran     pci_set_word(config + PCI_SUBSYSTEM_ID, vdev->device_id);
910ad3d11e6SHui Kai Ran     config[PCI_INTERRUPT_PIN] = 1;
91153c25ceaSPaul Brook 
912b2357c48SAlex Williamson     if (vdev->nvectors &&
913b2357c48SAlex Williamson         msix_init_exclusive_bar(&proxy->pci_dev, vdev->nvectors, 1)) {
914aba800a3SMichael S. Tsirkin         vdev->nvectors = 0;
915b2357c48SAlex Williamson     }
916aba800a3SMichael S. Tsirkin 
917ed757e14SYan Vugenfirer     proxy->pci_dev.config_write = virtio_write_config;
918ed757e14SYan Vugenfirer 
919aba800a3SMichael S. Tsirkin     size = VIRTIO_PCI_REGION_SIZE(&proxy->pci_dev) + vdev->config_len;
92053c25ceaSPaul Brook     if (size & (size-1))
92153c25ceaSPaul Brook         size = 1 << qemu_fls(size);
92253c25ceaSPaul Brook 
923da146d0aSAvi Kivity     memory_region_init_io(&proxy->bar, &virtio_pci_config_ops, proxy,
924da146d0aSAvi Kivity                           "virtio-pci", size);
925e824b2ccSAvi Kivity     pci_register_bar(&proxy->pci_dev, 0, PCI_BASE_ADDRESS_SPACE_IO,
926da146d0aSAvi Kivity                      &proxy->bar);
92753c25ceaSPaul Brook 
92825db9ebeSStefan Hajnoczi     if (!kvm_has_many_ioeventfds()) {
92925db9ebeSStefan Hajnoczi         proxy->flags &= ~VIRTIO_PCI_FLAG_USE_IOEVENTFD;
93025db9ebeSStefan Hajnoczi     }
93125db9ebeSStefan Hajnoczi 
932d2a0ccc6SMichael S. Tsirkin     virtio_bind_device(vdev, &virtio_pci_bindings, DEVICE(proxy));
9338172539dSMichael S. Tsirkin     proxy->host_features |= 0x1 << VIRTIO_F_NOTIFY_ON_EMPTY;
9348172539dSMichael S. Tsirkin     proxy->host_features |= 0x1 << VIRTIO_F_BAD_FEATURE;
9358172539dSMichael S. Tsirkin     proxy->host_features = vdev->get_features(vdev, proxy->host_features);
93653c25ceaSPaul Brook }
93753c25ceaSPaul Brook 
938f90c2bcdSAlex Williamson static void virtio_exit_pci(PCIDevice *pci_dev)
9390f457d91SMichael S. Tsirkin {
940da146d0aSAvi Kivity     VirtIOPCIProxy *proxy = DO_UPCAST(VirtIOPCIProxy, pci_dev, pci_dev);
941da146d0aSAvi Kivity 
942da146d0aSAvi Kivity     memory_region_destroy(&proxy->bar);
943b2357c48SAlex Williamson     msix_uninit_exclusive_bar(pci_dev);
9440f457d91SMichael S. Tsirkin }
9450f457d91SMichael S. Tsirkin 
94616c915baSAmit Shah static int virtio_rng_init_pci(PCIDevice *pci_dev)
94716c915baSAmit Shah {
94816c915baSAmit Shah     VirtIOPCIProxy *proxy = DO_UPCAST(VirtIOPCIProxy, pci_dev, pci_dev);
94916c915baSAmit Shah     VirtIODevice *vdev;
95016c915baSAmit Shah 
951500054f1SAnthony Liguori     if (proxy->rng.rng == NULL) {
952500054f1SAnthony Liguori         proxy->rng.default_backend = RNG_RANDOM(object_new(TYPE_RNG_RANDOM));
953500054f1SAnthony Liguori 
954500054f1SAnthony Liguori         object_property_add_child(OBJECT(pci_dev),
955500054f1SAnthony Liguori                                   "default-backend",
956500054f1SAnthony Liguori                                   OBJECT(proxy->rng.default_backend),
957500054f1SAnthony Liguori                                   NULL);
958500054f1SAnthony Liguori 
959500054f1SAnthony Liguori         object_property_set_link(OBJECT(pci_dev),
960500054f1SAnthony Liguori                                  OBJECT(proxy->rng.default_backend),
961500054f1SAnthony Liguori                                  "rng", NULL);
962500054f1SAnthony Liguori     }
963500054f1SAnthony Liguori 
96416c915baSAmit Shah     vdev = virtio_rng_init(&pci_dev->qdev, &proxy->rng);
96516c915baSAmit Shah     if (!vdev) {
96616c915baSAmit Shah         return -1;
96716c915baSAmit Shah     }
96816c915baSAmit Shah     virtio_init_pci(proxy, vdev);
96916c915baSAmit Shah     return 0;
97016c915baSAmit Shah }
97116c915baSAmit Shah 
97216c915baSAmit Shah static void virtio_rng_exit_pci(PCIDevice *pci_dev)
97316c915baSAmit Shah {
97416c915baSAmit Shah     VirtIOPCIProxy *proxy = DO_UPCAST(VirtIOPCIProxy, pci_dev, pci_dev);
97516c915baSAmit Shah 
97616c915baSAmit Shah     virtio_pci_stop_ioeventfd(proxy);
97716c915baSAmit Shah     virtio_rng_exit(proxy->vdev);
97816c915baSAmit Shah     virtio_exit_pci(pci_dev);
97916c915baSAmit Shah }
98016c915baSAmit Shah 
98116c915baSAmit Shah static void virtio_rng_initfn(Object *obj)
98216c915baSAmit Shah {
98316c915baSAmit Shah     PCIDevice *pci_dev = PCI_DEVICE(obj);
98416c915baSAmit Shah     VirtIOPCIProxy *proxy = DO_UPCAST(VirtIOPCIProxy, pci_dev, pci_dev);
98516c915baSAmit Shah 
98616c915baSAmit Shah     object_property_add_link(obj, "rng", TYPE_RNG_BACKEND,
98716c915baSAmit Shah                              (Object **)&proxy->rng.rng, NULL);
98816c915baSAmit Shah }
98916c915baSAmit Shah 
99016c915baSAmit Shah static Property virtio_rng_properties[] = {
99116c915baSAmit Shah     DEFINE_VIRTIO_COMMON_FEATURES(VirtIOPCIProxy, host_features),
992904d6f58SAnthony Liguori     /* Set a default rate limit of 2^47 bytes per minute or roughly 2TB/s.  If
993904d6f58SAnthony Liguori        you have an entropy source capable of generating more entropy than this
994904d6f58SAnthony Liguori        and you can pass it through via virtio-rng, then hats off to you.  Until
995904d6f58SAnthony Liguori        then, this is unlimited for all practical purposes.
996904d6f58SAnthony Liguori     */
997904d6f58SAnthony Liguori     DEFINE_PROP_UINT64("max-bytes", VirtIOPCIProxy, rng.max_bytes, INT64_MAX),
998904d6f58SAnthony Liguori     DEFINE_PROP_UINT32("period", VirtIOPCIProxy, rng.period_ms, 1 << 16),
99916c915baSAmit Shah     DEFINE_PROP_END_OF_LIST(),
100016c915baSAmit Shah };
100116c915baSAmit Shah 
100216c915baSAmit Shah static void virtio_rng_class_init(ObjectClass *klass, void *data)
100316c915baSAmit Shah {
100416c915baSAmit Shah     DeviceClass *dc = DEVICE_CLASS(klass);
100516c915baSAmit Shah     PCIDeviceClass *k = PCI_DEVICE_CLASS(klass);
100616c915baSAmit Shah 
100716c915baSAmit Shah     k->init = virtio_rng_init_pci;
100816c915baSAmit Shah     k->exit = virtio_rng_exit_pci;
100916c915baSAmit Shah     k->vendor_id = PCI_VENDOR_ID_REDHAT_QUMRANET;
101016c915baSAmit Shah     k->device_id = PCI_DEVICE_ID_VIRTIO_RNG;
101116c915baSAmit Shah     k->revision = VIRTIO_PCI_ABI_VERSION;
101216c915baSAmit Shah     k->class_id = PCI_CLASS_OTHERS;
101316c915baSAmit Shah     dc->reset = virtio_pci_reset;
101416c915baSAmit Shah     dc->props = virtio_rng_properties;
101516c915baSAmit Shah }
101616c915baSAmit Shah 
10178c43a6f0SAndreas Färber static const TypeInfo virtio_rng_info = {
101816c915baSAmit Shah     .name          = "virtio-rng-pci",
101916c915baSAmit Shah     .parent        = TYPE_PCI_DEVICE,
102016c915baSAmit Shah     .instance_size = sizeof(VirtIOPCIProxy),
102116c915baSAmit Shah     .instance_init = virtio_rng_initfn,
102216c915baSAmit Shah     .class_init    = virtio_rng_class_init,
102316c915baSAmit Shah };
102416c915baSAmit Shah 
102560653b28SPaolo Bonzini #ifdef CONFIG_VIRTFS
102660653b28SPaolo Bonzini static int virtio_9p_init_pci(PCIDevice *pci_dev)
102760653b28SPaolo Bonzini {
102860653b28SPaolo Bonzini     VirtIOPCIProxy *proxy = DO_UPCAST(VirtIOPCIProxy, pci_dev, pci_dev);
102960653b28SPaolo Bonzini     VirtIODevice *vdev;
103060653b28SPaolo Bonzini 
103160653b28SPaolo Bonzini     vdev = virtio_9p_init(&pci_dev->qdev, &proxy->fsconf);
103260653b28SPaolo Bonzini     vdev->nvectors = proxy->nvectors;
103360653b28SPaolo Bonzini     virtio_init_pci(proxy, vdev);
103460653b28SPaolo Bonzini     /* make the actual value visible */
103560653b28SPaolo Bonzini     proxy->nvectors = vdev->nvectors;
103660653b28SPaolo Bonzini     return 0;
103760653b28SPaolo Bonzini }
103860653b28SPaolo Bonzini 
103960653b28SPaolo Bonzini static Property virtio_9p_properties[] = {
104060653b28SPaolo Bonzini     DEFINE_PROP_BIT("ioeventfd", VirtIOPCIProxy, flags, VIRTIO_PCI_FLAG_USE_IOEVENTFD_BIT, true),
104160653b28SPaolo Bonzini     DEFINE_PROP_UINT32("vectors", VirtIOPCIProxy, nvectors, 2),
104260653b28SPaolo Bonzini     DEFINE_VIRTIO_COMMON_FEATURES(VirtIOPCIProxy, host_features),
104360653b28SPaolo Bonzini     DEFINE_PROP_STRING("mount_tag", VirtIOPCIProxy, fsconf.tag),
104460653b28SPaolo Bonzini     DEFINE_PROP_STRING("fsdev", VirtIOPCIProxy, fsconf.fsdev_id),
104560653b28SPaolo Bonzini     DEFINE_PROP_END_OF_LIST(),
104660653b28SPaolo Bonzini };
104760653b28SPaolo Bonzini 
104860653b28SPaolo Bonzini static void virtio_9p_class_init(ObjectClass *klass, void *data)
104960653b28SPaolo Bonzini {
105060653b28SPaolo Bonzini     DeviceClass *dc = DEVICE_CLASS(klass);
105160653b28SPaolo Bonzini     PCIDeviceClass *k = PCI_DEVICE_CLASS(klass);
105260653b28SPaolo Bonzini 
105360653b28SPaolo Bonzini     k->init = virtio_9p_init_pci;
105460653b28SPaolo Bonzini     k->vendor_id = PCI_VENDOR_ID_REDHAT_QUMRANET;
105560653b28SPaolo Bonzini     k->device_id = PCI_DEVICE_ID_VIRTIO_9P;
105660653b28SPaolo Bonzini     k->revision = VIRTIO_PCI_ABI_VERSION;
105760653b28SPaolo Bonzini     k->class_id = 0x2;
105860653b28SPaolo Bonzini     dc->props = virtio_9p_properties;
105960653b28SPaolo Bonzini     dc->reset = virtio_pci_reset;
106060653b28SPaolo Bonzini }
106160653b28SPaolo Bonzini 
106260653b28SPaolo Bonzini static const TypeInfo virtio_9p_info = {
106360653b28SPaolo Bonzini     .name          = "virtio-9p-pci",
106460653b28SPaolo Bonzini     .parent        = TYPE_PCI_DEVICE,
106560653b28SPaolo Bonzini     .instance_size = sizeof(VirtIOPCIProxy),
106660653b28SPaolo Bonzini     .class_init    = virtio_9p_class_init,
106760653b28SPaolo Bonzini };
106860653b28SPaolo Bonzini #endif
106960653b28SPaolo Bonzini 
1070085bccb7SKONRAD Frederic /*
1071085bccb7SKONRAD Frederic  * virtio-pci: This is the PCIDevice which has a virtio-pci-bus.
1072085bccb7SKONRAD Frederic  */
1073085bccb7SKONRAD Frederic 
1074085bccb7SKONRAD Frederic /* This is called by virtio-bus just after the device is plugged. */
1075085bccb7SKONRAD Frederic static void virtio_pci_device_plugged(DeviceState *d)
1076085bccb7SKONRAD Frederic {
1077085bccb7SKONRAD Frederic     VirtIOPCIProxy *proxy = VIRTIO_PCI(d);
1078085bccb7SKONRAD Frederic     VirtioBusState *bus = &proxy->bus;
1079085bccb7SKONRAD Frederic     uint8_t *config;
1080085bccb7SKONRAD Frederic     uint32_t size;
1081085bccb7SKONRAD Frederic 
1082085bccb7SKONRAD Frederic     proxy->vdev = bus->vdev;
1083085bccb7SKONRAD Frederic 
1084085bccb7SKONRAD Frederic     config = proxy->pci_dev.config;
1085085bccb7SKONRAD Frederic     if (proxy->class_code) {
1086085bccb7SKONRAD Frederic         pci_config_set_class(config, proxy->class_code);
1087085bccb7SKONRAD Frederic     }
1088085bccb7SKONRAD Frederic     pci_set_word(config + PCI_SUBSYSTEM_VENDOR_ID,
1089085bccb7SKONRAD Frederic                  pci_get_word(config + PCI_VENDOR_ID));
1090085bccb7SKONRAD Frederic     pci_set_word(config + PCI_SUBSYSTEM_ID, virtio_bus_get_vdev_id(bus));
1091085bccb7SKONRAD Frederic     config[PCI_INTERRUPT_PIN] = 1;
1092085bccb7SKONRAD Frederic 
1093085bccb7SKONRAD Frederic     if (proxy->nvectors &&
1094085bccb7SKONRAD Frederic         msix_init_exclusive_bar(&proxy->pci_dev, proxy->nvectors, 1)) {
1095085bccb7SKONRAD Frederic         proxy->nvectors = 0;
1096085bccb7SKONRAD Frederic     }
1097085bccb7SKONRAD Frederic 
1098085bccb7SKONRAD Frederic     proxy->pci_dev.config_write = virtio_write_config;
1099085bccb7SKONRAD Frederic 
1100085bccb7SKONRAD Frederic     size = VIRTIO_PCI_REGION_SIZE(&proxy->pci_dev)
1101085bccb7SKONRAD Frederic          + virtio_bus_get_vdev_config_len(bus);
1102085bccb7SKONRAD Frederic     if (size & (size - 1)) {
1103085bccb7SKONRAD Frederic         size = 1 << qemu_fls(size);
1104085bccb7SKONRAD Frederic     }
1105085bccb7SKONRAD Frederic 
1106085bccb7SKONRAD Frederic     memory_region_init_io(&proxy->bar, &virtio_pci_config_ops, proxy,
1107085bccb7SKONRAD Frederic                           "virtio-pci", size);
1108085bccb7SKONRAD Frederic     pci_register_bar(&proxy->pci_dev, 0, PCI_BASE_ADDRESS_SPACE_IO,
1109085bccb7SKONRAD Frederic                      &proxy->bar);
1110085bccb7SKONRAD Frederic 
1111085bccb7SKONRAD Frederic     if (!kvm_has_many_ioeventfds()) {
1112085bccb7SKONRAD Frederic         proxy->flags &= ~VIRTIO_PCI_FLAG_USE_IOEVENTFD;
1113085bccb7SKONRAD Frederic     }
1114085bccb7SKONRAD Frederic 
1115085bccb7SKONRAD Frederic     proxy->host_features |= 0x1 << VIRTIO_F_NOTIFY_ON_EMPTY;
1116085bccb7SKONRAD Frederic     proxy->host_features |= 0x1 << VIRTIO_F_BAD_FEATURE;
1117085bccb7SKONRAD Frederic     proxy->host_features = virtio_bus_get_vdev_features(bus,
1118085bccb7SKONRAD Frederic                                                       proxy->host_features);
1119085bccb7SKONRAD Frederic }
1120085bccb7SKONRAD Frederic 
1121085bccb7SKONRAD Frederic static int virtio_pci_init(PCIDevice *pci_dev)
1122085bccb7SKONRAD Frederic {
1123085bccb7SKONRAD Frederic     VirtIOPCIProxy *dev = VIRTIO_PCI(pci_dev);
1124085bccb7SKONRAD Frederic     VirtioPCIClass *k = VIRTIO_PCI_GET_CLASS(pci_dev);
1125085bccb7SKONRAD Frederic     virtio_pci_bus_new(&dev->bus, dev);
1126085bccb7SKONRAD Frederic     if (k->init != NULL) {
1127085bccb7SKONRAD Frederic         return k->init(dev);
1128085bccb7SKONRAD Frederic     }
1129085bccb7SKONRAD Frederic     return 0;
1130085bccb7SKONRAD Frederic }
1131085bccb7SKONRAD Frederic 
1132085bccb7SKONRAD Frederic static void virtio_pci_exit(PCIDevice *pci_dev)
1133085bccb7SKONRAD Frederic {
1134085bccb7SKONRAD Frederic     VirtIOPCIProxy *proxy = VIRTIO_PCI(pci_dev);
113510479a80SKONRAD Frederic     virtio_pci_stop_ioeventfd(proxy);
1136085bccb7SKONRAD Frederic     virtio_exit_pci(pci_dev);
1137085bccb7SKONRAD Frederic }
1138085bccb7SKONRAD Frederic 
1139085bccb7SKONRAD Frederic /*
1140085bccb7SKONRAD Frederic  * This will be renamed virtio_pci_reset at the end of the series.
1141085bccb7SKONRAD Frederic  * virtio_pci_reset is still in use at this moment.
1142085bccb7SKONRAD Frederic  */
1143085bccb7SKONRAD Frederic static void virtio_pci_rst(DeviceState *qdev)
1144085bccb7SKONRAD Frederic {
1145085bccb7SKONRAD Frederic     VirtIOPCIProxy *proxy = VIRTIO_PCI(qdev);
1146085bccb7SKONRAD Frederic     VirtioBusState *bus = VIRTIO_BUS(&proxy->bus);
1147085bccb7SKONRAD Frederic     virtio_pci_stop_ioeventfd(proxy);
1148085bccb7SKONRAD Frederic     virtio_bus_reset(bus);
1149085bccb7SKONRAD Frederic     msix_unuse_all_vectors(&proxy->pci_dev);
1150085bccb7SKONRAD Frederic     proxy->flags &= ~VIRTIO_PCI_FLAG_BUS_MASTER_BUG;
1151085bccb7SKONRAD Frederic }
1152085bccb7SKONRAD Frederic 
1153085bccb7SKONRAD Frederic static void virtio_pci_class_init(ObjectClass *klass, void *data)
1154085bccb7SKONRAD Frederic {
1155085bccb7SKONRAD Frederic     DeviceClass *dc = DEVICE_CLASS(klass);
1156085bccb7SKONRAD Frederic     PCIDeviceClass *k = PCI_DEVICE_CLASS(klass);
1157085bccb7SKONRAD Frederic 
1158085bccb7SKONRAD Frederic     k->init = virtio_pci_init;
1159085bccb7SKONRAD Frederic     k->exit = virtio_pci_exit;
1160085bccb7SKONRAD Frederic     k->vendor_id = PCI_VENDOR_ID_REDHAT_QUMRANET;
1161085bccb7SKONRAD Frederic     k->revision = VIRTIO_PCI_ABI_VERSION;
1162085bccb7SKONRAD Frederic     k->class_id = PCI_CLASS_OTHERS;
1163085bccb7SKONRAD Frederic     dc->reset = virtio_pci_rst;
1164085bccb7SKONRAD Frederic }
1165085bccb7SKONRAD Frederic 
1166085bccb7SKONRAD Frederic static const TypeInfo virtio_pci_info = {
1167085bccb7SKONRAD Frederic     .name          = TYPE_VIRTIO_PCI,
1168085bccb7SKONRAD Frederic     .parent        = TYPE_PCI_DEVICE,
1169085bccb7SKONRAD Frederic     .instance_size = sizeof(VirtIOPCIProxy),
1170085bccb7SKONRAD Frederic     .class_init    = virtio_pci_class_init,
1171085bccb7SKONRAD Frederic     .class_size    = sizeof(VirtioPCIClass),
1172085bccb7SKONRAD Frederic     .abstract      = true,
1173085bccb7SKONRAD Frederic };
1174085bccb7SKONRAD Frederic 
1175653ced07SKONRAD Frederic /* virtio-blk-pci */
1176653ced07SKONRAD Frederic 
1177653ced07SKONRAD Frederic static Property virtio_blk_pci_properties[] = {
1178653ced07SKONRAD Frederic     DEFINE_PROP_HEX32("class", VirtIOPCIProxy, class_code, 0),
1179653ced07SKONRAD Frederic     DEFINE_PROP_BIT("ioeventfd", VirtIOPCIProxy, flags,
1180653ced07SKONRAD Frederic                     VIRTIO_PCI_FLAG_USE_IOEVENTFD_BIT, true),
1181653ced07SKONRAD Frederic     DEFINE_PROP_UINT32("vectors", VirtIOPCIProxy, nvectors, 2),
1182653ced07SKONRAD Frederic #ifdef CONFIG_VIRTIO_BLK_DATA_PLANE
1183653ced07SKONRAD Frederic     DEFINE_PROP_BIT("x-data-plane", VirtIOBlkPCI, blk.data_plane, 0, false),
1184653ced07SKONRAD Frederic #endif
1185653ced07SKONRAD Frederic     DEFINE_VIRTIO_BLK_FEATURES(VirtIOPCIProxy, host_features),
1186653ced07SKONRAD Frederic     DEFINE_VIRTIO_BLK_PROPERTIES(VirtIOBlkPCI, blk),
1187653ced07SKONRAD Frederic     DEFINE_PROP_END_OF_LIST(),
1188653ced07SKONRAD Frederic };
1189653ced07SKONRAD Frederic 
1190653ced07SKONRAD Frederic static int virtio_blk_pci_init(VirtIOPCIProxy *vpci_dev)
1191653ced07SKONRAD Frederic {
1192653ced07SKONRAD Frederic     VirtIOBlkPCI *dev = VIRTIO_BLK_PCI(vpci_dev);
1193653ced07SKONRAD Frederic     DeviceState *vdev = DEVICE(&dev->vdev);
1194653ced07SKONRAD Frederic     virtio_blk_set_conf(vdev, &(dev->blk));
1195653ced07SKONRAD Frederic     qdev_set_parent_bus(vdev, BUS(&vpci_dev->bus));
1196653ced07SKONRAD Frederic     if (qdev_init(vdev) < 0) {
1197653ced07SKONRAD Frederic         return -1;
1198653ced07SKONRAD Frederic     }
1199653ced07SKONRAD Frederic     return 0;
1200653ced07SKONRAD Frederic }
1201653ced07SKONRAD Frederic 
1202653ced07SKONRAD Frederic static void virtio_blk_pci_class_init(ObjectClass *klass, void *data)
1203653ced07SKONRAD Frederic {
1204653ced07SKONRAD Frederic     DeviceClass *dc = DEVICE_CLASS(klass);
1205653ced07SKONRAD Frederic     VirtioPCIClass *k = VIRTIO_PCI_CLASS(klass);
1206653ced07SKONRAD Frederic     PCIDeviceClass *pcidev_k = PCI_DEVICE_CLASS(klass);
1207653ced07SKONRAD Frederic 
1208653ced07SKONRAD Frederic     dc->props = virtio_blk_pci_properties;
1209653ced07SKONRAD Frederic     k->init = virtio_blk_pci_init;
1210653ced07SKONRAD Frederic     pcidev_k->vendor_id = PCI_VENDOR_ID_REDHAT_QUMRANET;
1211653ced07SKONRAD Frederic     pcidev_k->device_id = PCI_DEVICE_ID_VIRTIO_BLOCK;
1212653ced07SKONRAD Frederic     pcidev_k->revision = VIRTIO_PCI_ABI_VERSION;
1213653ced07SKONRAD Frederic     pcidev_k->class_id = PCI_CLASS_STORAGE_SCSI;
1214653ced07SKONRAD Frederic }
1215653ced07SKONRAD Frederic 
1216653ced07SKONRAD Frederic static void virtio_blk_pci_instance_init(Object *obj)
1217653ced07SKONRAD Frederic {
1218653ced07SKONRAD Frederic     VirtIOBlkPCI *dev = VIRTIO_BLK_PCI(obj);
1219653ced07SKONRAD Frederic     object_initialize(OBJECT(&dev->vdev), TYPE_VIRTIO_BLK);
1220653ced07SKONRAD Frederic     object_property_add_child(obj, "virtio-backend", OBJECT(&dev->vdev), NULL);
1221653ced07SKONRAD Frederic }
1222653ced07SKONRAD Frederic 
1223653ced07SKONRAD Frederic static const TypeInfo virtio_blk_pci_info = {
1224653ced07SKONRAD Frederic     .name          = TYPE_VIRTIO_BLK_PCI,
1225653ced07SKONRAD Frederic     .parent        = TYPE_VIRTIO_PCI,
1226653ced07SKONRAD Frederic     .instance_size = sizeof(VirtIOBlkPCI),
1227653ced07SKONRAD Frederic     .instance_init = virtio_blk_pci_instance_init,
1228653ced07SKONRAD Frederic     .class_init    = virtio_blk_pci_class_init,
1229653ced07SKONRAD Frederic };
1230653ced07SKONRAD Frederic 
1231bc7b90a0SKONRAD Frederic /* virtio-scsi-pci */
1232bc7b90a0SKONRAD Frederic 
1233bc7b90a0SKONRAD Frederic static Property virtio_scsi_pci_properties[] = {
1234bc7b90a0SKONRAD Frederic     DEFINE_PROP_BIT("ioeventfd", VirtIOPCIProxy, flags,
1235bc7b90a0SKONRAD Frederic                     VIRTIO_PCI_FLAG_USE_IOEVENTFD_BIT, true),
1236bc7b90a0SKONRAD Frederic     DEFINE_PROP_UINT32("vectors", VirtIOPCIProxy, nvectors,
1237bc7b90a0SKONRAD Frederic                        DEV_NVECTORS_UNSPECIFIED),
1238bc7b90a0SKONRAD Frederic     DEFINE_VIRTIO_SCSI_FEATURES(VirtIOPCIProxy, host_features),
1239292c8e50SPaolo Bonzini     DEFINE_VIRTIO_SCSI_PROPERTIES(VirtIOSCSIPCI, vdev.parent_obj.conf),
1240bc7b90a0SKONRAD Frederic     DEFINE_PROP_END_OF_LIST(),
1241bc7b90a0SKONRAD Frederic };
1242bc7b90a0SKONRAD Frederic 
1243bc7b90a0SKONRAD Frederic static int virtio_scsi_pci_init_pci(VirtIOPCIProxy *vpci_dev)
1244bc7b90a0SKONRAD Frederic {
1245bc7b90a0SKONRAD Frederic     VirtIOSCSIPCI *dev = VIRTIO_SCSI_PCI(vpci_dev);
1246bc7b90a0SKONRAD Frederic     DeviceState *vdev = DEVICE(&dev->vdev);
1247292c8e50SPaolo Bonzini     VirtIOSCSICommon *vs = VIRTIO_SCSI_COMMON(vdev);
1248bc7b90a0SKONRAD Frederic 
1249bc7b90a0SKONRAD Frederic     if (vpci_dev->nvectors == DEV_NVECTORS_UNSPECIFIED) {
1250292c8e50SPaolo Bonzini         vpci_dev->nvectors = vs->conf.num_queues + 3;
1251bc7b90a0SKONRAD Frederic     }
1252bc7b90a0SKONRAD Frederic 
1253bc7b90a0SKONRAD Frederic     qdev_set_parent_bus(vdev, BUS(&vpci_dev->bus));
1254bc7b90a0SKONRAD Frederic     if (qdev_init(vdev) < 0) {
1255bc7b90a0SKONRAD Frederic         return -1;
1256bc7b90a0SKONRAD Frederic     }
1257bc7b90a0SKONRAD Frederic     return 0;
1258bc7b90a0SKONRAD Frederic }
1259bc7b90a0SKONRAD Frederic 
1260bc7b90a0SKONRAD Frederic static void virtio_scsi_pci_class_init(ObjectClass *klass, void *data)
1261bc7b90a0SKONRAD Frederic {
1262bc7b90a0SKONRAD Frederic     DeviceClass *dc = DEVICE_CLASS(klass);
1263bc7b90a0SKONRAD Frederic     VirtioPCIClass *k = VIRTIO_PCI_CLASS(klass);
1264bc7b90a0SKONRAD Frederic     PCIDeviceClass *pcidev_k = PCI_DEVICE_CLASS(klass);
1265bc7b90a0SKONRAD Frederic     k->init = virtio_scsi_pci_init_pci;
1266bc7b90a0SKONRAD Frederic     dc->props = virtio_scsi_pci_properties;
1267bc7b90a0SKONRAD Frederic     pcidev_k->vendor_id = PCI_VENDOR_ID_REDHAT_QUMRANET;
1268bc7b90a0SKONRAD Frederic     pcidev_k->device_id = PCI_DEVICE_ID_VIRTIO_SCSI;
1269bc7b90a0SKONRAD Frederic     pcidev_k->revision = 0x00;
1270bc7b90a0SKONRAD Frederic     pcidev_k->class_id = PCI_CLASS_STORAGE_SCSI;
1271bc7b90a0SKONRAD Frederic }
1272bc7b90a0SKONRAD Frederic 
1273bc7b90a0SKONRAD Frederic static void virtio_scsi_pci_instance_init(Object *obj)
1274bc7b90a0SKONRAD Frederic {
1275bc7b90a0SKONRAD Frederic     VirtIOSCSIPCI *dev = VIRTIO_SCSI_PCI(obj);
1276bc7b90a0SKONRAD Frederic     object_initialize(OBJECT(&dev->vdev), TYPE_VIRTIO_SCSI);
1277bc7b90a0SKONRAD Frederic     object_property_add_child(obj, "virtio-backend", OBJECT(&dev->vdev), NULL);
1278bc7b90a0SKONRAD Frederic }
1279bc7b90a0SKONRAD Frederic 
1280bc7b90a0SKONRAD Frederic static const TypeInfo virtio_scsi_pci_info = {
1281bc7b90a0SKONRAD Frederic     .name          = TYPE_VIRTIO_SCSI_PCI,
1282bc7b90a0SKONRAD Frederic     .parent        = TYPE_VIRTIO_PCI,
1283bc7b90a0SKONRAD Frederic     .instance_size = sizeof(VirtIOSCSIPCI),
1284bc7b90a0SKONRAD Frederic     .instance_init = virtio_scsi_pci_instance_init,
1285bc7b90a0SKONRAD Frederic     .class_init    = virtio_scsi_pci_class_init,
1286bc7b90a0SKONRAD Frederic };
1287bc7b90a0SKONRAD Frederic 
1288*50787628SNicholas Bellinger /* vhost-scsi-pci */
1289*50787628SNicholas Bellinger 
1290*50787628SNicholas Bellinger #ifdef CONFIG_VHOST_SCSI
1291*50787628SNicholas Bellinger static Property vhost_scsi_pci_properties[] = {
1292*50787628SNicholas Bellinger     DEFINE_PROP_UINT32("vectors", VirtIOPCIProxy, nvectors,
1293*50787628SNicholas Bellinger                        DEV_NVECTORS_UNSPECIFIED),
1294*50787628SNicholas Bellinger     DEFINE_VIRTIO_COMMON_FEATURES(VirtIOPCIProxy, host_features),
1295*50787628SNicholas Bellinger     DEFINE_VHOST_SCSI_PROPERTIES(VHostSCSIPCI, vdev.parent_obj.conf),
1296*50787628SNicholas Bellinger     DEFINE_PROP_END_OF_LIST(),
1297*50787628SNicholas Bellinger };
1298*50787628SNicholas Bellinger 
1299*50787628SNicholas Bellinger static int vhost_scsi_pci_init_pci(VirtIOPCIProxy *vpci_dev)
1300*50787628SNicholas Bellinger {
1301*50787628SNicholas Bellinger     VHostSCSIPCI *dev = VHOST_SCSI_PCI(vpci_dev);
1302*50787628SNicholas Bellinger     DeviceState *vdev = DEVICE(&dev->vdev);
1303*50787628SNicholas Bellinger     VirtIOSCSICommon *vs = VIRTIO_SCSI_COMMON(vdev);
1304*50787628SNicholas Bellinger 
1305*50787628SNicholas Bellinger     if (vpci_dev->nvectors == DEV_NVECTORS_UNSPECIFIED) {
1306*50787628SNicholas Bellinger         vpci_dev->nvectors = vs->conf.num_queues + 3;
1307*50787628SNicholas Bellinger     }
1308*50787628SNicholas Bellinger 
1309*50787628SNicholas Bellinger     qdev_set_parent_bus(vdev, BUS(&vpci_dev->bus));
1310*50787628SNicholas Bellinger     if (qdev_init(vdev) < 0) {
1311*50787628SNicholas Bellinger         return -1;
1312*50787628SNicholas Bellinger     }
1313*50787628SNicholas Bellinger     return 0;
1314*50787628SNicholas Bellinger }
1315*50787628SNicholas Bellinger 
1316*50787628SNicholas Bellinger static void vhost_scsi_pci_class_init(ObjectClass *klass, void *data)
1317*50787628SNicholas Bellinger {
1318*50787628SNicholas Bellinger     DeviceClass *dc = DEVICE_CLASS(klass);
1319*50787628SNicholas Bellinger     VirtioPCIClass *k = VIRTIO_PCI_CLASS(klass);
1320*50787628SNicholas Bellinger     PCIDeviceClass *pcidev_k = PCI_DEVICE_CLASS(klass);
1321*50787628SNicholas Bellinger     k->init = vhost_scsi_pci_init_pci;
1322*50787628SNicholas Bellinger     dc->props = vhost_scsi_pci_properties;
1323*50787628SNicholas Bellinger     pcidev_k->vendor_id = PCI_VENDOR_ID_REDHAT_QUMRANET;
1324*50787628SNicholas Bellinger     pcidev_k->device_id = PCI_DEVICE_ID_VIRTIO_SCSI;
1325*50787628SNicholas Bellinger     pcidev_k->revision = 0x00;
1326*50787628SNicholas Bellinger     pcidev_k->class_id = PCI_CLASS_STORAGE_SCSI;
1327*50787628SNicholas Bellinger }
1328*50787628SNicholas Bellinger 
1329*50787628SNicholas Bellinger static void vhost_scsi_pci_instance_init(Object *obj)
1330*50787628SNicholas Bellinger {
1331*50787628SNicholas Bellinger     VHostSCSIPCI *dev = VHOST_SCSI_PCI(obj);
1332*50787628SNicholas Bellinger     object_initialize(OBJECT(&dev->vdev), TYPE_VHOST_SCSI);
1333*50787628SNicholas Bellinger     object_property_add_child(obj, "virtio-backend", OBJECT(&dev->vdev), NULL);
1334*50787628SNicholas Bellinger }
1335*50787628SNicholas Bellinger 
1336*50787628SNicholas Bellinger static const TypeInfo vhost_scsi_pci_info = {
1337*50787628SNicholas Bellinger     .name          = TYPE_VHOST_SCSI_PCI,
1338*50787628SNicholas Bellinger     .parent        = TYPE_VIRTIO_PCI,
1339*50787628SNicholas Bellinger     .instance_size = sizeof(VHostSCSIPCI),
1340*50787628SNicholas Bellinger     .instance_init = vhost_scsi_pci_instance_init,
1341*50787628SNicholas Bellinger     .class_init    = vhost_scsi_pci_class_init,
1342*50787628SNicholas Bellinger };
1343*50787628SNicholas Bellinger #endif
1344*50787628SNicholas Bellinger 
1345e378e88dSKONRAD Frederic /* virtio-balloon-pci */
1346e378e88dSKONRAD Frederic 
134724a6e7f4SKONRAD Frederic static void balloon_pci_stats_get_all(Object *obj, struct Visitor *v,
134824a6e7f4SKONRAD Frederic                                       void *opaque, const char *name,
134924a6e7f4SKONRAD Frederic                                       Error **errp)
135024a6e7f4SKONRAD Frederic {
135124a6e7f4SKONRAD Frederic     VirtIOBalloonPCI *dev = opaque;
135224a6e7f4SKONRAD Frederic     object_property_get(OBJECT(&dev->vdev), v, "guest-stats", errp);
135324a6e7f4SKONRAD Frederic }
135424a6e7f4SKONRAD Frederic 
135524a6e7f4SKONRAD Frederic static void balloon_pci_stats_get_poll_interval(Object *obj, struct Visitor *v,
135624a6e7f4SKONRAD Frederic                                                 void *opaque, const char *name,
135724a6e7f4SKONRAD Frederic                                                 Error **errp)
135824a6e7f4SKONRAD Frederic {
135924a6e7f4SKONRAD Frederic     VirtIOBalloonPCI *dev = opaque;
136024a6e7f4SKONRAD Frederic     object_property_get(OBJECT(&dev->vdev), v, "guest-stats-polling-interval",
136124a6e7f4SKONRAD Frederic                         errp);
136224a6e7f4SKONRAD Frederic }
136324a6e7f4SKONRAD Frederic 
136424a6e7f4SKONRAD Frederic static void balloon_pci_stats_set_poll_interval(Object *obj, struct Visitor *v,
136524a6e7f4SKONRAD Frederic                                                 void *opaque, const char *name,
136624a6e7f4SKONRAD Frederic                                                 Error **errp)
136724a6e7f4SKONRAD Frederic {
136824a6e7f4SKONRAD Frederic     VirtIOBalloonPCI *dev = opaque;
136924a6e7f4SKONRAD Frederic     object_property_set(OBJECT(&dev->vdev), v, "guest-stats-polling-interval",
137024a6e7f4SKONRAD Frederic                         errp);
137124a6e7f4SKONRAD Frederic }
137224a6e7f4SKONRAD Frederic 
1373e378e88dSKONRAD Frederic static Property virtio_balloon_pci_properties[] = {
1374e378e88dSKONRAD Frederic     DEFINE_VIRTIO_COMMON_FEATURES(VirtIOPCIProxy, host_features),
1375e378e88dSKONRAD Frederic     DEFINE_PROP_HEX32("class", VirtIOPCIProxy, class_code, 0),
1376e378e88dSKONRAD Frederic     DEFINE_PROP_END_OF_LIST(),
1377e378e88dSKONRAD Frederic };
1378e378e88dSKONRAD Frederic 
1379e378e88dSKONRAD Frederic static int virtio_balloon_pci_init(VirtIOPCIProxy *vpci_dev)
1380e378e88dSKONRAD Frederic {
1381e378e88dSKONRAD Frederic     VirtIOBalloonPCI *dev = VIRTIO_BALLOON_PCI(vpci_dev);
1382e378e88dSKONRAD Frederic     DeviceState *vdev = DEVICE(&dev->vdev);
1383e378e88dSKONRAD Frederic 
1384e378e88dSKONRAD Frederic     if (vpci_dev->class_code != PCI_CLASS_OTHERS &&
1385e378e88dSKONRAD Frederic         vpci_dev->class_code != PCI_CLASS_MEMORY_RAM) { /* qemu < 1.1 */
1386e378e88dSKONRAD Frederic         vpci_dev->class_code = PCI_CLASS_OTHERS;
1387e378e88dSKONRAD Frederic     }
1388e378e88dSKONRAD Frederic 
1389e378e88dSKONRAD Frederic     qdev_set_parent_bus(vdev, BUS(&vpci_dev->bus));
1390e378e88dSKONRAD Frederic     if (qdev_init(vdev) < 0) {
1391e378e88dSKONRAD Frederic         return -1;
1392e378e88dSKONRAD Frederic     }
1393e378e88dSKONRAD Frederic     return 0;
1394e378e88dSKONRAD Frederic }
1395e378e88dSKONRAD Frederic 
1396e378e88dSKONRAD Frederic static void virtio_balloon_pci_class_init(ObjectClass *klass, void *data)
1397e378e88dSKONRAD Frederic {
1398e378e88dSKONRAD Frederic     DeviceClass *dc = DEVICE_CLASS(klass);
1399e378e88dSKONRAD Frederic     VirtioPCIClass *k = VIRTIO_PCI_CLASS(klass);
1400e378e88dSKONRAD Frederic     PCIDeviceClass *pcidev_k = PCI_DEVICE_CLASS(klass);
1401e378e88dSKONRAD Frederic     k->init = virtio_balloon_pci_init;
1402e378e88dSKONRAD Frederic     dc->props = virtio_balloon_pci_properties;
1403e378e88dSKONRAD Frederic     pcidev_k->vendor_id = PCI_VENDOR_ID_REDHAT_QUMRANET;
1404e378e88dSKONRAD Frederic     pcidev_k->device_id = PCI_DEVICE_ID_VIRTIO_BALLOON;
1405e378e88dSKONRAD Frederic     pcidev_k->revision = VIRTIO_PCI_ABI_VERSION;
1406e378e88dSKONRAD Frederic     pcidev_k->class_id = PCI_CLASS_OTHERS;
1407e378e88dSKONRAD Frederic }
1408e378e88dSKONRAD Frederic 
1409e378e88dSKONRAD Frederic static void virtio_balloon_pci_instance_init(Object *obj)
1410e378e88dSKONRAD Frederic {
1411e378e88dSKONRAD Frederic     VirtIOBalloonPCI *dev = VIRTIO_BALLOON_PCI(obj);
1412e378e88dSKONRAD Frederic     object_initialize(OBJECT(&dev->vdev), TYPE_VIRTIO_BALLOON);
1413e378e88dSKONRAD Frederic     object_property_add_child(obj, "virtio-backend", OBJECT(&dev->vdev), NULL);
141424a6e7f4SKONRAD Frederic 
141524a6e7f4SKONRAD Frederic     object_property_add(obj, "guest-stats", "guest statistics",
141624a6e7f4SKONRAD Frederic                         balloon_pci_stats_get_all, NULL, NULL, dev,
141724a6e7f4SKONRAD Frederic                         NULL);
141824a6e7f4SKONRAD Frederic 
141924a6e7f4SKONRAD Frederic     object_property_add(obj, "guest-stats-polling-interval", "int",
142024a6e7f4SKONRAD Frederic                         balloon_pci_stats_get_poll_interval,
142124a6e7f4SKONRAD Frederic                         balloon_pci_stats_set_poll_interval,
142224a6e7f4SKONRAD Frederic                         NULL, dev, NULL);
1423e378e88dSKONRAD Frederic }
1424e378e88dSKONRAD Frederic 
1425e378e88dSKONRAD Frederic static const TypeInfo virtio_balloon_pci_info = {
1426e378e88dSKONRAD Frederic     .name          = TYPE_VIRTIO_BALLOON_PCI,
1427e378e88dSKONRAD Frederic     .parent        = TYPE_VIRTIO_PCI,
1428e378e88dSKONRAD Frederic     .instance_size = sizeof(VirtIOBalloonPCI),
1429e378e88dSKONRAD Frederic     .instance_init = virtio_balloon_pci_instance_init,
1430e378e88dSKONRAD Frederic     .class_init    = virtio_balloon_pci_class_init,
1431e378e88dSKONRAD Frederic };
1432e378e88dSKONRAD Frederic 
1433f7f7464aSKONRAD Frederic /* virtio-serial-pci */
1434f7f7464aSKONRAD Frederic 
1435f7f7464aSKONRAD Frederic static int virtio_serial_pci_init(VirtIOPCIProxy *vpci_dev)
1436f7f7464aSKONRAD Frederic {
1437f7f7464aSKONRAD Frederic     VirtIOSerialPCI *dev = VIRTIO_SERIAL_PCI(vpci_dev);
1438f7f7464aSKONRAD Frederic     DeviceState *vdev = DEVICE(&dev->vdev);
1439f7f7464aSKONRAD Frederic 
1440f7f7464aSKONRAD Frederic     if (vpci_dev->class_code != PCI_CLASS_COMMUNICATION_OTHER &&
1441f7f7464aSKONRAD Frederic         vpci_dev->class_code != PCI_CLASS_DISPLAY_OTHER && /* qemu 0.10 */
1442f7f7464aSKONRAD Frederic         vpci_dev->class_code != PCI_CLASS_OTHERS) {        /* qemu-kvm  */
1443f7f7464aSKONRAD Frederic             vpci_dev->class_code = PCI_CLASS_COMMUNICATION_OTHER;
1444f7f7464aSKONRAD Frederic     }
1445f7f7464aSKONRAD Frederic 
1446f7f7464aSKONRAD Frederic     /* backwards-compatibility with machines that were created with
1447f7f7464aSKONRAD Frederic        DEV_NVECTORS_UNSPECIFIED */
1448f7f7464aSKONRAD Frederic     if (vpci_dev->nvectors == DEV_NVECTORS_UNSPECIFIED) {
1449f7f7464aSKONRAD Frederic         vpci_dev->nvectors = dev->vdev.serial.max_virtserial_ports + 1;
1450f7f7464aSKONRAD Frederic     }
1451f7f7464aSKONRAD Frederic 
1452f7f7464aSKONRAD Frederic     qdev_set_parent_bus(vdev, BUS(&vpci_dev->bus));
1453f7f7464aSKONRAD Frederic     if (qdev_init(vdev) < 0) {
1454f7f7464aSKONRAD Frederic         return -1;
1455f7f7464aSKONRAD Frederic     }
1456f7f7464aSKONRAD Frederic     return 0;
1457f7f7464aSKONRAD Frederic }
1458f7f7464aSKONRAD Frederic 
1459f7f7464aSKONRAD Frederic static Property virtio_serial_pci_properties[] = {
1460f7f7464aSKONRAD Frederic     DEFINE_PROP_BIT("ioeventfd", VirtIOPCIProxy, flags,
1461f7f7464aSKONRAD Frederic                     VIRTIO_PCI_FLAG_USE_IOEVENTFD_BIT, true),
1462f7f7464aSKONRAD Frederic     DEFINE_PROP_UINT32("vectors", VirtIOPCIProxy, nvectors, 2),
1463f7f7464aSKONRAD Frederic     DEFINE_PROP_HEX32("class", VirtIOPCIProxy, class_code, 0),
1464f7f7464aSKONRAD Frederic     DEFINE_VIRTIO_COMMON_FEATURES(VirtIOPCIProxy, host_features),
1465f7f7464aSKONRAD Frederic     DEFINE_VIRTIO_SERIAL_PROPERTIES(VirtIOSerialPCI, vdev.serial),
1466f7f7464aSKONRAD Frederic     DEFINE_PROP_END_OF_LIST(),
1467f7f7464aSKONRAD Frederic };
1468f7f7464aSKONRAD Frederic 
1469f7f7464aSKONRAD Frederic static void virtio_serial_pci_class_init(ObjectClass *klass, void *data)
1470f7f7464aSKONRAD Frederic {
1471f7f7464aSKONRAD Frederic     DeviceClass *dc = DEVICE_CLASS(klass);
1472f7f7464aSKONRAD Frederic     VirtioPCIClass *k = VIRTIO_PCI_CLASS(klass);
1473f7f7464aSKONRAD Frederic     PCIDeviceClass *pcidev_k = PCI_DEVICE_CLASS(klass);
1474f7f7464aSKONRAD Frederic     k->init = virtio_serial_pci_init;
1475f7f7464aSKONRAD Frederic     dc->props = virtio_serial_pci_properties;
1476f7f7464aSKONRAD Frederic     pcidev_k->vendor_id = PCI_VENDOR_ID_REDHAT_QUMRANET;
1477f7f7464aSKONRAD Frederic     pcidev_k->device_id = PCI_DEVICE_ID_VIRTIO_CONSOLE;
1478f7f7464aSKONRAD Frederic     pcidev_k->revision = VIRTIO_PCI_ABI_VERSION;
1479f7f7464aSKONRAD Frederic     pcidev_k->class_id = PCI_CLASS_COMMUNICATION_OTHER;
1480f7f7464aSKONRAD Frederic }
1481f7f7464aSKONRAD Frederic 
1482f7f7464aSKONRAD Frederic static void virtio_serial_pci_instance_init(Object *obj)
1483f7f7464aSKONRAD Frederic {
1484f7f7464aSKONRAD Frederic     VirtIOSerialPCI *dev = VIRTIO_SERIAL_PCI(obj);
1485f7f7464aSKONRAD Frederic     object_initialize(OBJECT(&dev->vdev), TYPE_VIRTIO_SERIAL);
1486f7f7464aSKONRAD Frederic     object_property_add_child(obj, "virtio-backend", OBJECT(&dev->vdev), NULL);
1487f7f7464aSKONRAD Frederic }
1488f7f7464aSKONRAD Frederic 
1489f7f7464aSKONRAD Frederic static const TypeInfo virtio_serial_pci_info = {
1490f7f7464aSKONRAD Frederic     .name          = TYPE_VIRTIO_SERIAL_PCI,
1491f7f7464aSKONRAD Frederic     .parent        = TYPE_VIRTIO_PCI,
1492f7f7464aSKONRAD Frederic     .instance_size = sizeof(VirtIOSerialPCI),
1493f7f7464aSKONRAD Frederic     .instance_init = virtio_serial_pci_instance_init,
1494f7f7464aSKONRAD Frederic     .class_init    = virtio_serial_pci_class_init,
1495f7f7464aSKONRAD Frederic };
1496f7f7464aSKONRAD Frederic 
1497e37da394SKONRAD Frederic /* virtio-net-pci */
1498e37da394SKONRAD Frederic 
1499e37da394SKONRAD Frederic static Property virtio_net_properties[] = {
1500e37da394SKONRAD Frederic     DEFINE_PROP_BIT("ioeventfd", VirtIOPCIProxy, flags,
1501e37da394SKONRAD Frederic                     VIRTIO_PCI_FLAG_USE_IOEVENTFD_BIT, false),
1502e37da394SKONRAD Frederic     DEFINE_PROP_UINT32("vectors", VirtIOPCIProxy, nvectors, 3),
1503e37da394SKONRAD Frederic     DEFINE_VIRTIO_NET_FEATURES(VirtIOPCIProxy, host_features),
1504e37da394SKONRAD Frederic     DEFINE_NIC_PROPERTIES(VirtIONetPCI, vdev.nic_conf),
1505e37da394SKONRAD Frederic     DEFINE_VIRTIO_NET_PROPERTIES(VirtIONetPCI, vdev.net_conf),
1506e37da394SKONRAD Frederic     DEFINE_PROP_END_OF_LIST(),
1507e37da394SKONRAD Frederic };
1508e37da394SKONRAD Frederic 
1509e37da394SKONRAD Frederic static int virtio_net_pci_init(VirtIOPCIProxy *vpci_dev)
1510e37da394SKONRAD Frederic {
1511e37da394SKONRAD Frederic     VirtIONetPCI *dev = VIRTIO_NET_PCI(vpci_dev);
1512e37da394SKONRAD Frederic     DeviceState *vdev = DEVICE(&dev->vdev);
1513e37da394SKONRAD Frederic 
1514e37da394SKONRAD Frederic     virtio_net_set_config_size(&dev->vdev, vpci_dev->host_features);
1515e37da394SKONRAD Frederic     qdev_set_parent_bus(vdev, BUS(&vpci_dev->bus));
1516e37da394SKONRAD Frederic     if (qdev_init(vdev) < 0) {
1517e37da394SKONRAD Frederic         return -1;
1518e37da394SKONRAD Frederic     }
1519e37da394SKONRAD Frederic     return 0;
1520e37da394SKONRAD Frederic }
1521e37da394SKONRAD Frederic 
1522e37da394SKONRAD Frederic static void virtio_net_pci_class_init(ObjectClass *klass, void *data)
1523e37da394SKONRAD Frederic {
1524e37da394SKONRAD Frederic     DeviceClass *dc = DEVICE_CLASS(klass);
1525e37da394SKONRAD Frederic     PCIDeviceClass *k = PCI_DEVICE_CLASS(klass);
1526e37da394SKONRAD Frederic     VirtioPCIClass *vpciklass = VIRTIO_PCI_CLASS(klass);
1527e37da394SKONRAD Frederic 
1528e37da394SKONRAD Frederic     k->romfile = "efi-virtio.rom";
1529e37da394SKONRAD Frederic     k->vendor_id = PCI_VENDOR_ID_REDHAT_QUMRANET;
1530e37da394SKONRAD Frederic     k->device_id = PCI_DEVICE_ID_VIRTIO_NET;
1531e37da394SKONRAD Frederic     k->revision = VIRTIO_PCI_ABI_VERSION;
1532e37da394SKONRAD Frederic     k->class_id = PCI_CLASS_NETWORK_ETHERNET;
1533e37da394SKONRAD Frederic     dc->props = virtio_net_properties;
1534e37da394SKONRAD Frederic     vpciklass->init = virtio_net_pci_init;
1535e37da394SKONRAD Frederic }
1536e37da394SKONRAD Frederic 
1537e37da394SKONRAD Frederic static void virtio_net_pci_instance_init(Object *obj)
1538e37da394SKONRAD Frederic {
1539e37da394SKONRAD Frederic     VirtIONetPCI *dev = VIRTIO_NET_PCI(obj);
1540e37da394SKONRAD Frederic     object_initialize(OBJECT(&dev->vdev), TYPE_VIRTIO_NET);
1541e37da394SKONRAD Frederic     object_property_add_child(obj, "virtio-backend", OBJECT(&dev->vdev), NULL);
1542e37da394SKONRAD Frederic }
1543e37da394SKONRAD Frederic 
1544e37da394SKONRAD Frederic static const TypeInfo virtio_net_pci_info = {
1545e37da394SKONRAD Frederic     .name          = TYPE_VIRTIO_NET_PCI,
1546e37da394SKONRAD Frederic     .parent        = TYPE_VIRTIO_PCI,
1547e37da394SKONRAD Frederic     .instance_size = sizeof(VirtIONetPCI),
1548e37da394SKONRAD Frederic     .instance_init = virtio_net_pci_instance_init,
1549e37da394SKONRAD Frederic     .class_init    = virtio_net_pci_class_init,
1550e37da394SKONRAD Frederic };
1551e37da394SKONRAD Frederic 
15520a2acf5eSKONRAD Frederic /* virtio-pci-bus */
15530a2acf5eSKONRAD Frederic 
15540a2acf5eSKONRAD Frederic void virtio_pci_bus_new(VirtioBusState *bus, VirtIOPCIProxy *dev)
15550a2acf5eSKONRAD Frederic {
15560a2acf5eSKONRAD Frederic     DeviceState *qdev = DEVICE(dev);
15570a2acf5eSKONRAD Frederic     BusState *qbus;
15580a2acf5eSKONRAD Frederic     qbus_create_inplace((BusState *)bus, TYPE_VIRTIO_PCI_BUS, qdev, NULL);
15590a2acf5eSKONRAD Frederic     qbus = BUS(bus);
1560cbd19063SKONRAD Frederic     qbus->allow_hotplug = 1;
15610a2acf5eSKONRAD Frederic }
15620a2acf5eSKONRAD Frederic 
15630a2acf5eSKONRAD Frederic static void virtio_pci_bus_class_init(ObjectClass *klass, void *data)
15640a2acf5eSKONRAD Frederic {
15650a2acf5eSKONRAD Frederic     BusClass *bus_class = BUS_CLASS(klass);
15660a2acf5eSKONRAD Frederic     VirtioBusClass *k = VIRTIO_BUS_CLASS(klass);
15670a2acf5eSKONRAD Frederic     bus_class->max_dev = 1;
15680a2acf5eSKONRAD Frederic     k->notify = virtio_pci_notify;
15690a2acf5eSKONRAD Frederic     k->save_config = virtio_pci_save_config;
15700a2acf5eSKONRAD Frederic     k->load_config = virtio_pci_load_config;
15710a2acf5eSKONRAD Frederic     k->save_queue = virtio_pci_save_queue;
15720a2acf5eSKONRAD Frederic     k->load_queue = virtio_pci_load_queue;
15730a2acf5eSKONRAD Frederic     k->get_features = virtio_pci_get_features;
15740a2acf5eSKONRAD Frederic     k->query_guest_notifiers = virtio_pci_query_guest_notifiers;
15750a2acf5eSKONRAD Frederic     k->set_host_notifier = virtio_pci_set_host_notifier;
15760a2acf5eSKONRAD Frederic     k->set_guest_notifiers = virtio_pci_set_guest_notifiers;
15770a2acf5eSKONRAD Frederic     k->vmstate_change = virtio_pci_vmstate_change;
1578085bccb7SKONRAD Frederic     k->device_plugged = virtio_pci_device_plugged;
15790a2acf5eSKONRAD Frederic }
15800a2acf5eSKONRAD Frederic 
15810a2acf5eSKONRAD Frederic static const TypeInfo virtio_pci_bus_info = {
15820a2acf5eSKONRAD Frederic     .name          = TYPE_VIRTIO_PCI_BUS,
15830a2acf5eSKONRAD Frederic     .parent        = TYPE_VIRTIO_BUS,
15840a2acf5eSKONRAD Frederic     .instance_size = sizeof(VirtioPCIBusState),
15850a2acf5eSKONRAD Frederic     .class_init    = virtio_pci_bus_class_init,
15860a2acf5eSKONRAD Frederic };
15870a2acf5eSKONRAD Frederic 
158883f7d43aSAndreas Färber static void virtio_pci_register_types(void)
158953c25ceaSPaul Brook {
159016c915baSAmit Shah     type_register_static(&virtio_rng_info);
15910a2acf5eSKONRAD Frederic     type_register_static(&virtio_pci_bus_info);
1592085bccb7SKONRAD Frederic     type_register_static(&virtio_pci_info);
159360653b28SPaolo Bonzini #ifdef CONFIG_VIRTFS
159460653b28SPaolo Bonzini     type_register_static(&virtio_9p_info);
159560653b28SPaolo Bonzini #endif
1596653ced07SKONRAD Frederic     type_register_static(&virtio_blk_pci_info);
1597bc7b90a0SKONRAD Frederic     type_register_static(&virtio_scsi_pci_info);
1598e378e88dSKONRAD Frederic     type_register_static(&virtio_balloon_pci_info);
1599f7f7464aSKONRAD Frederic     type_register_static(&virtio_serial_pci_info);
1600e37da394SKONRAD Frederic     type_register_static(&virtio_net_pci_info);
1601*50787628SNicholas Bellinger #ifdef CONFIG_VHOST_SCSI
1602*50787628SNicholas Bellinger     type_register_static(&vhost_scsi_pci_info);
1603*50787628SNicholas Bellinger #endif
160453c25ceaSPaul Brook }
160553c25ceaSPaul Brook 
160683f7d43aSAndreas Färber type_init(virtio_pci_register_types)
1607