xref: /qemu/hw/virtio/virtio-pci.c (revision 9824d2a39d9893ef9bbe71f94efb57da265b73f6)
153c25ceaSPaul Brook /*
253c25ceaSPaul Brook  * Virtio PCI Bindings
353c25ceaSPaul Brook  *
453c25ceaSPaul Brook  * Copyright IBM, Corp. 2007
553c25ceaSPaul Brook  * Copyright (c) 2009 CodeSourcery
653c25ceaSPaul Brook  *
753c25ceaSPaul Brook  * Authors:
853c25ceaSPaul Brook  *  Anthony Liguori   <aliguori@us.ibm.com>
953c25ceaSPaul Brook  *  Paul Brook        <paul@codesourcery.com>
1053c25ceaSPaul Brook  *
1153c25ceaSPaul Brook  * This work is licensed under the terms of the GNU GPL, version 2.  See
1253c25ceaSPaul Brook  * the COPYING file in the top-level directory.
1353c25ceaSPaul Brook  *
146b620ca3SPaolo Bonzini  * Contributions after 2012-01-13 are licensed under the terms of the
156b620ca3SPaolo Bonzini  * GNU GPL, version 2 or (at your option) any later version.
1653c25ceaSPaul Brook  */
1753c25ceaSPaul Brook 
1853c25ceaSPaul Brook #include <inttypes.h>
1953c25ceaSPaul Brook 
20cbbe4f50SMichael S. Tsirkin #include "standard-headers/linux/virtio_pci.h"
210d09e41aSPaolo Bonzini #include "hw/virtio/virtio.h"
220d09e41aSPaolo Bonzini #include "hw/virtio/virtio-blk.h"
230d09e41aSPaolo Bonzini #include "hw/virtio/virtio-net.h"
240d09e41aSPaolo Bonzini #include "hw/virtio/virtio-serial.h"
250d09e41aSPaolo Bonzini #include "hw/virtio/virtio-scsi.h"
260d09e41aSPaolo Bonzini #include "hw/virtio/virtio-balloon.h"
27f958c8aaSGerd Hoffmann #include "hw/virtio/virtio-input.h"
2883c9f4caSPaolo Bonzini #include "hw/pci/pci.h"
291de7afc9SPaolo Bonzini #include "qemu/error-report.h"
3083c9f4caSPaolo Bonzini #include "hw/pci/msi.h"
3183c9f4caSPaolo Bonzini #include "hw/pci/msix.h"
3283c9f4caSPaolo Bonzini #include "hw/loader.h"
339c17d615SPaolo Bonzini #include "sysemu/kvm.h"
344be74634SMarkus Armbruster #include "sysemu/block-backend.h"
3547b43a1fSPaolo Bonzini #include "virtio-pci.h"
361de7afc9SPaolo Bonzini #include "qemu/range.h"
370d09e41aSPaolo Bonzini #include "hw/virtio/virtio-bus.h"
3824a6e7f4SKONRAD Frederic #include "qapi/visitor.h"
3953c25ceaSPaul Brook 
40cbbe4f50SMichael S. Tsirkin #define VIRTIO_PCI_REGION_SIZE(dev)     VIRTIO_PCI_CONFIG_OFF(msix_present(dev))
41aba800a3SMichael S. Tsirkin 
42c17bef33SMichael S. Tsirkin #undef VIRTIO_PCI_CONFIG
43c17bef33SMichael S. Tsirkin 
44aba800a3SMichael S. Tsirkin /* The remaining space is defined by each driver as the per-driver
45aba800a3SMichael S. Tsirkin  * configuration space */
46cbbe4f50SMichael S. Tsirkin #define VIRTIO_PCI_CONFIG_SIZE(dev)     VIRTIO_PCI_CONFIG_OFF(msix_enabled(dev))
4753c25ceaSPaul Brook 
48ac7af112SAndreas Färber static void virtio_pci_bus_new(VirtioBusState *bus, size_t bus_size,
49ac7af112SAndreas Färber                                VirtIOPCIProxy *dev);
50d51fcfacSKONRAD Frederic 
5153c25ceaSPaul Brook /* virtio device */
52d2a0ccc6SMichael S. Tsirkin /* DeviceState to VirtIOPCIProxy. For use off data-path. TODO: use QOM. */
53d2a0ccc6SMichael S. Tsirkin static inline VirtIOPCIProxy *to_virtio_pci_proxy(DeviceState *d)
5453c25ceaSPaul Brook {
55d2a0ccc6SMichael S. Tsirkin     return container_of(d, VirtIOPCIProxy, pci_dev.qdev);
56d2a0ccc6SMichael S. Tsirkin }
57d2a0ccc6SMichael S. Tsirkin 
58d2a0ccc6SMichael S. Tsirkin /* DeviceState to VirtIOPCIProxy. Note: used on datapath,
59d2a0ccc6SMichael S. Tsirkin  * be careful and test performance if you change this.
60d2a0ccc6SMichael S. Tsirkin  */
61d2a0ccc6SMichael S. Tsirkin static inline VirtIOPCIProxy *to_virtio_pci_proxy_fast(DeviceState *d)
62d2a0ccc6SMichael S. Tsirkin {
63d2a0ccc6SMichael S. Tsirkin     return container_of(d, VirtIOPCIProxy, pci_dev.qdev);
64d2a0ccc6SMichael S. Tsirkin }
65d2a0ccc6SMichael S. Tsirkin 
66d2a0ccc6SMichael S. Tsirkin static void virtio_pci_notify(DeviceState *d, uint16_t vector)
67d2a0ccc6SMichael S. Tsirkin {
68d2a0ccc6SMichael S. Tsirkin     VirtIOPCIProxy *proxy = to_virtio_pci_proxy_fast(d);
69a3fc66d9SPaolo Bonzini 
70aba800a3SMichael S. Tsirkin     if (msix_enabled(&proxy->pci_dev))
71aba800a3SMichael S. Tsirkin         msix_notify(&proxy->pci_dev, vector);
72a3fc66d9SPaolo Bonzini     else {
73a3fc66d9SPaolo Bonzini         VirtIODevice *vdev = virtio_bus_get_device(&proxy->bus);
74a3fc66d9SPaolo Bonzini         pci_set_irq(&proxy->pci_dev, vdev->isr & 1);
75a3fc66d9SPaolo Bonzini     }
7653c25ceaSPaul Brook }
7753c25ceaSPaul Brook 
78d2a0ccc6SMichael S. Tsirkin static void virtio_pci_save_config(DeviceState *d, QEMUFile *f)
79ff24bd58SMichael S. Tsirkin {
80d2a0ccc6SMichael S. Tsirkin     VirtIOPCIProxy *proxy = to_virtio_pci_proxy(d);
81a3fc66d9SPaolo Bonzini     VirtIODevice *vdev = virtio_bus_get_device(&proxy->bus);
82a3fc66d9SPaolo Bonzini 
83ff24bd58SMichael S. Tsirkin     pci_device_save(&proxy->pci_dev, f);
84ff24bd58SMichael S. Tsirkin     msix_save(&proxy->pci_dev, f);
85ff24bd58SMichael S. Tsirkin     if (msix_present(&proxy->pci_dev))
86a3fc66d9SPaolo Bonzini         qemu_put_be16(f, vdev->config_vector);
87ff24bd58SMichael S. Tsirkin }
88ff24bd58SMichael S. Tsirkin 
89a6df8adfSJason Wang static void virtio_pci_load_modern_queue_state(VirtIOPCIQueue *vq,
90a6df8adfSJason Wang                                                QEMUFile *f)
91a6df8adfSJason Wang {
92a6df8adfSJason Wang     vq->num = qemu_get_be16(f);
93a6df8adfSJason Wang     vq->enabled = qemu_get_be16(f);
94a6df8adfSJason Wang     vq->desc[0] = qemu_get_be32(f);
95a6df8adfSJason Wang     vq->desc[1] = qemu_get_be32(f);
96a6df8adfSJason Wang     vq->avail[0] = qemu_get_be32(f);
97a6df8adfSJason Wang     vq->avail[1] = qemu_get_be32(f);
98a6df8adfSJason Wang     vq->used[0] = qemu_get_be32(f);
99a6df8adfSJason Wang     vq->used[1] = qemu_get_be32(f);
100a6df8adfSJason Wang }
101a6df8adfSJason Wang 
102a6df8adfSJason Wang static bool virtio_pci_has_extra_state(DeviceState *d)
103a6df8adfSJason Wang {
104a6df8adfSJason Wang     VirtIOPCIProxy *proxy = to_virtio_pci_proxy(d);
105a6df8adfSJason Wang 
106a6df8adfSJason Wang     return proxy->flags & VIRTIO_PCI_FLAG_MIGRATE_EXTRA;
107a6df8adfSJason Wang }
108a6df8adfSJason Wang 
109a6df8adfSJason Wang static int get_virtio_pci_modern_state(QEMUFile *f, void *pv, size_t size)
110a6df8adfSJason Wang {
111a6df8adfSJason Wang     VirtIOPCIProxy *proxy = pv;
112a6df8adfSJason Wang     int i;
113a6df8adfSJason Wang 
114a6df8adfSJason Wang     proxy->dfselect = qemu_get_be32(f);
115a6df8adfSJason Wang     proxy->gfselect = qemu_get_be32(f);
116a6df8adfSJason Wang     proxy->guest_features[0] = qemu_get_be32(f);
117a6df8adfSJason Wang     proxy->guest_features[1] = qemu_get_be32(f);
118a6df8adfSJason Wang     for (i = 0; i < VIRTIO_QUEUE_MAX; i++) {
119a6df8adfSJason Wang         virtio_pci_load_modern_queue_state(&proxy->vqs[i], f);
120a6df8adfSJason Wang     }
121a6df8adfSJason Wang 
122a6df8adfSJason Wang     return 0;
123a6df8adfSJason Wang }
124a6df8adfSJason Wang 
125a6df8adfSJason Wang static void virtio_pci_save_modern_queue_state(VirtIOPCIQueue *vq,
126a6df8adfSJason Wang                                                QEMUFile *f)
127a6df8adfSJason Wang {
128a6df8adfSJason Wang     qemu_put_be16(f, vq->num);
129a6df8adfSJason Wang     qemu_put_be16(f, vq->enabled);
130a6df8adfSJason Wang     qemu_put_be32(f, vq->desc[0]);
131a6df8adfSJason Wang     qemu_put_be32(f, vq->desc[1]);
132a6df8adfSJason Wang     qemu_put_be32(f, vq->avail[0]);
133a6df8adfSJason Wang     qemu_put_be32(f, vq->avail[1]);
134a6df8adfSJason Wang     qemu_put_be32(f, vq->used[0]);
135a6df8adfSJason Wang     qemu_put_be32(f, vq->used[1]);
136a6df8adfSJason Wang }
137a6df8adfSJason Wang 
138a6df8adfSJason Wang static void put_virtio_pci_modern_state(QEMUFile *f, void *pv, size_t size)
139a6df8adfSJason Wang {
140a6df8adfSJason Wang     VirtIOPCIProxy *proxy = pv;
141a6df8adfSJason Wang     int i;
142a6df8adfSJason Wang 
143a6df8adfSJason Wang     qemu_put_be32(f, proxy->dfselect);
144a6df8adfSJason Wang     qemu_put_be32(f, proxy->gfselect);
145a6df8adfSJason Wang     qemu_put_be32(f, proxy->guest_features[0]);
146a6df8adfSJason Wang     qemu_put_be32(f, proxy->guest_features[1]);
147a6df8adfSJason Wang     for (i = 0; i < VIRTIO_QUEUE_MAX; i++) {
148a6df8adfSJason Wang         virtio_pci_save_modern_queue_state(&proxy->vqs[i], f);
149a6df8adfSJason Wang     }
150a6df8adfSJason Wang }
151a6df8adfSJason Wang 
152a6df8adfSJason Wang static const VMStateInfo vmstate_info_virtio_pci_modern_state = {
153a6df8adfSJason Wang     .name = "virtqueue_state",
154a6df8adfSJason Wang     .get = get_virtio_pci_modern_state,
155a6df8adfSJason Wang     .put = put_virtio_pci_modern_state,
156a6df8adfSJason Wang };
157a6df8adfSJason Wang 
158a6df8adfSJason Wang static bool virtio_pci_modern_state_needed(void *opaque)
159a6df8adfSJason Wang {
160a6df8adfSJason Wang     VirtIOPCIProxy *proxy = opaque;
161a6df8adfSJason Wang 
162a6df8adfSJason Wang     return !(proxy->flags & VIRTIO_PCI_FLAG_DISABLE_MODERN);
163a6df8adfSJason Wang }
164a6df8adfSJason Wang 
165a6df8adfSJason Wang static const VMStateDescription vmstate_virtio_pci_modern_state = {
166a6df8adfSJason Wang     .name = "virtio_pci/modern_state",
167a6df8adfSJason Wang     .version_id = 1,
168a6df8adfSJason Wang     .minimum_version_id = 1,
169a6df8adfSJason Wang     .needed = &virtio_pci_modern_state_needed,
170a6df8adfSJason Wang     .fields = (VMStateField[]) {
171a6df8adfSJason Wang         {
172a6df8adfSJason Wang             .name         = "modern_state",
173a6df8adfSJason Wang             .version_id   = 0,
174a6df8adfSJason Wang             .field_exists = NULL,
175a6df8adfSJason Wang             .size         = 0,
176a6df8adfSJason Wang             .info         = &vmstate_info_virtio_pci_modern_state,
177a6df8adfSJason Wang             .flags        = VMS_SINGLE,
178a6df8adfSJason Wang             .offset       = 0,
179a6df8adfSJason Wang         },
180a6df8adfSJason Wang         VMSTATE_END_OF_LIST()
181a6df8adfSJason Wang     }
182a6df8adfSJason Wang };
183a6df8adfSJason Wang 
184a6df8adfSJason Wang static const VMStateDescription vmstate_virtio_pci = {
185a6df8adfSJason Wang     .name = "virtio_pci",
186a6df8adfSJason Wang     .version_id = 1,
187a6df8adfSJason Wang     .minimum_version_id = 1,
188a6df8adfSJason Wang     .minimum_version_id_old = 1,
189a6df8adfSJason Wang     .fields = (VMStateField[]) {
190a6df8adfSJason Wang         VMSTATE_END_OF_LIST()
191a6df8adfSJason Wang     },
192a6df8adfSJason Wang     .subsections = (const VMStateDescription*[]) {
193a6df8adfSJason Wang         &vmstate_virtio_pci_modern_state,
194a6df8adfSJason Wang         NULL
195a6df8adfSJason Wang     }
196a6df8adfSJason Wang };
197a6df8adfSJason Wang 
198a6df8adfSJason Wang static void virtio_pci_save_extra_state(DeviceState *d, QEMUFile *f)
199a6df8adfSJason Wang {
200a6df8adfSJason Wang     VirtIOPCIProxy *proxy = to_virtio_pci_proxy(d);
201a6df8adfSJason Wang 
202a6df8adfSJason Wang     vmstate_save_state(f, &vmstate_virtio_pci, proxy, NULL);
203a6df8adfSJason Wang }
204a6df8adfSJason Wang 
205a6df8adfSJason Wang static int virtio_pci_load_extra_state(DeviceState *d, QEMUFile *f)
206a6df8adfSJason Wang {
207a6df8adfSJason Wang     VirtIOPCIProxy *proxy = to_virtio_pci_proxy(d);
208a6df8adfSJason Wang 
209a6df8adfSJason Wang     return vmstate_load_state(f, &vmstate_virtio_pci, proxy, 1);
210a6df8adfSJason Wang }
211a6df8adfSJason Wang 
212d2a0ccc6SMichael S. Tsirkin static void virtio_pci_save_queue(DeviceState *d, int n, QEMUFile *f)
213ff24bd58SMichael S. Tsirkin {
214d2a0ccc6SMichael S. Tsirkin     VirtIOPCIProxy *proxy = to_virtio_pci_proxy(d);
215a3fc66d9SPaolo Bonzini     VirtIODevice *vdev = virtio_bus_get_device(&proxy->bus);
216a3fc66d9SPaolo Bonzini 
217ff24bd58SMichael S. Tsirkin     if (msix_present(&proxy->pci_dev))
218a3fc66d9SPaolo Bonzini         qemu_put_be16(f, virtio_queue_vector(vdev, n));
219ff24bd58SMichael S. Tsirkin }
220ff24bd58SMichael S. Tsirkin 
221d2a0ccc6SMichael S. Tsirkin static int virtio_pci_load_config(DeviceState *d, QEMUFile *f)
222ff24bd58SMichael S. Tsirkin {
223d2a0ccc6SMichael S. Tsirkin     VirtIOPCIProxy *proxy = to_virtio_pci_proxy(d);
224a3fc66d9SPaolo Bonzini     VirtIODevice *vdev = virtio_bus_get_device(&proxy->bus);
225a3fc66d9SPaolo Bonzini 
226ff24bd58SMichael S. Tsirkin     int ret;
227ff24bd58SMichael S. Tsirkin     ret = pci_device_load(&proxy->pci_dev, f);
228e6da7680SMichael S. Tsirkin     if (ret) {
229ff24bd58SMichael S. Tsirkin         return ret;
230e6da7680SMichael S. Tsirkin     }
2313cac001eSMichael S. Tsirkin     msix_unuse_all_vectors(&proxy->pci_dev);
232ff24bd58SMichael S. Tsirkin     msix_load(&proxy->pci_dev, f);
233e6da7680SMichael S. Tsirkin     if (msix_present(&proxy->pci_dev)) {
234a3fc66d9SPaolo Bonzini         qemu_get_be16s(f, &vdev->config_vector);
235e6da7680SMichael S. Tsirkin     } else {
236a3fc66d9SPaolo Bonzini         vdev->config_vector = VIRTIO_NO_VECTOR;
237e6da7680SMichael S. Tsirkin     }
238a3fc66d9SPaolo Bonzini     if (vdev->config_vector != VIRTIO_NO_VECTOR) {
239a3fc66d9SPaolo Bonzini         return msix_vector_use(&proxy->pci_dev, vdev->config_vector);
240e6da7680SMichael S. Tsirkin     }
241ff24bd58SMichael S. Tsirkin     return 0;
242ff24bd58SMichael S. Tsirkin }
243ff24bd58SMichael S. Tsirkin 
244d2a0ccc6SMichael S. Tsirkin static int virtio_pci_load_queue(DeviceState *d, int n, QEMUFile *f)
245ff24bd58SMichael S. Tsirkin {
246d2a0ccc6SMichael S. Tsirkin     VirtIOPCIProxy *proxy = to_virtio_pci_proxy(d);
247a3fc66d9SPaolo Bonzini     VirtIODevice *vdev = virtio_bus_get_device(&proxy->bus);
248a3fc66d9SPaolo Bonzini 
249ff24bd58SMichael S. Tsirkin     uint16_t vector;
250e6da7680SMichael S. Tsirkin     if (msix_present(&proxy->pci_dev)) {
251ff24bd58SMichael S. Tsirkin         qemu_get_be16s(f, &vector);
252e6da7680SMichael S. Tsirkin     } else {
253e6da7680SMichael S. Tsirkin         vector = VIRTIO_NO_VECTOR;
254e6da7680SMichael S. Tsirkin     }
255a3fc66d9SPaolo Bonzini     virtio_queue_set_vector(vdev, n, vector);
256e6da7680SMichael S. Tsirkin     if (vector != VIRTIO_NO_VECTOR) {
257e6da7680SMichael S. Tsirkin         return msix_vector_use(&proxy->pci_dev, vector);
258e6da7680SMichael S. Tsirkin     }
259a6df8adfSJason Wang 
260ff24bd58SMichael S. Tsirkin     return 0;
261ff24bd58SMichael S. Tsirkin }
262ff24bd58SMichael S. Tsirkin 
263975acc0aSJason Wang #define QEMU_VIRTIO_PCI_QUEUE_MEM_MULT 0x1000
264975acc0aSJason Wang 
26525db9ebeSStefan Hajnoczi static int virtio_pci_set_host_notifier_internal(VirtIOPCIProxy *proxy,
26626b9b5feSPaolo Bonzini                                                  int n, bool assign, bool set_handler)
26725db9ebeSStefan Hajnoczi {
268a3fc66d9SPaolo Bonzini     VirtIODevice *vdev = virtio_bus_get_device(&proxy->bus);
269a3fc66d9SPaolo Bonzini     VirtQueue *vq = virtio_get_queue(vdev, n);
27025db9ebeSStefan Hajnoczi     EventNotifier *notifier = virtio_queue_get_host_notifier(vq);
271975acc0aSJason Wang     bool legacy = !(proxy->flags & VIRTIO_PCI_FLAG_DISABLE_LEGACY);
272975acc0aSJason Wang     bool modern = !(proxy->flags & VIRTIO_PCI_FLAG_DISABLE_MODERN);
273bc85ccfdSJason Wang     bool fast_mmio = kvm_ioeventfd_any_length_enabled();
274*9824d2a3SJason Wang     bool modern_pio = proxy->flags & VIRTIO_PCI_FLAG_MODERN_PIO_NOTIFY;
275588255adSGerd Hoffmann     MemoryRegion *modern_mr = &proxy->notify.mr;
276*9824d2a3SJason Wang     MemoryRegion *modern_notify_mr = &proxy->notify_pio.mr;
277975acc0aSJason Wang     MemoryRegion *legacy_mr = &proxy->bar;
278975acc0aSJason Wang     hwaddr modern_addr = QEMU_VIRTIO_PCI_QUEUE_MEM_MULT *
279975acc0aSJason Wang                          virtio_get_queue_index(vq);
280975acc0aSJason Wang     hwaddr legacy_addr = VIRTIO_PCI_QUEUE_NOTIFY;
281da146d0aSAvi Kivity     int r = 0;
282da146d0aSAvi Kivity 
28325db9ebeSStefan Hajnoczi     if (assign) {
28425db9ebeSStefan Hajnoczi         r = event_notifier_init(notifier, 1);
28525db9ebeSStefan Hajnoczi         if (r < 0) {
286b36e3914SMichael S. Tsirkin             error_report("%s: unable to init event notifier: %d",
287b36e3914SMichael S. Tsirkin                          __func__, r);
28825db9ebeSStefan Hajnoczi             return r;
28925db9ebeSStefan Hajnoczi         }
29026b9b5feSPaolo Bonzini         virtio_queue_set_host_notifier_fd_handler(vq, true, set_handler);
291975acc0aSJason Wang         if (modern) {
292bc85ccfdSJason Wang             if (fast_mmio) {
293bc85ccfdSJason Wang                 memory_region_add_eventfd(modern_mr, modern_addr, 0,
294bc85ccfdSJason Wang                                           false, n, notifier);
295bc85ccfdSJason Wang             } else {
296975acc0aSJason Wang                 memory_region_add_eventfd(modern_mr, modern_addr, 2,
297bc85ccfdSJason Wang                                           false, n, notifier);
298bc85ccfdSJason Wang             }
299*9824d2a3SJason Wang             if (modern_pio) {
300*9824d2a3SJason Wang                 memory_region_add_eventfd(modern_notify_mr, 0, 2,
301*9824d2a3SJason Wang                                               true, n, notifier);
302*9824d2a3SJason Wang             }
303975acc0aSJason Wang         }
304975acc0aSJason Wang         if (legacy) {
305975acc0aSJason Wang             memory_region_add_eventfd(legacy_mr, legacy_addr, 2,
306975acc0aSJason Wang                                       true, n, notifier);
307975acc0aSJason Wang         }
30825db9ebeSStefan Hajnoczi     } else {
309975acc0aSJason Wang         if (modern) {
310bc85ccfdSJason Wang             if (fast_mmio) {
311bc85ccfdSJason Wang                 memory_region_del_eventfd(modern_mr, modern_addr, 0,
312bc85ccfdSJason Wang                                           false, n, notifier);
313bc85ccfdSJason Wang             } else {
314975acc0aSJason Wang                 memory_region_del_eventfd(modern_mr, modern_addr, 2,
315bc85ccfdSJason Wang                                           false, n, notifier);
316bc85ccfdSJason Wang             }
317*9824d2a3SJason Wang             if (modern_pio) {
318*9824d2a3SJason Wang                 memory_region_del_eventfd(modern_notify_mr, 0, 2,
319*9824d2a3SJason Wang                                           true, n, notifier);
320*9824d2a3SJason Wang             }
321975acc0aSJason Wang         }
322975acc0aSJason Wang         if (legacy) {
323975acc0aSJason Wang             memory_region_del_eventfd(legacy_mr, legacy_addr, 2,
324975acc0aSJason Wang                                       true, n, notifier);
325975acc0aSJason Wang         }
32626b9b5feSPaolo Bonzini         virtio_queue_set_host_notifier_fd_handler(vq, false, false);
32725db9ebeSStefan Hajnoczi         event_notifier_cleanup(notifier);
32825db9ebeSStefan Hajnoczi     }
32925db9ebeSStefan Hajnoczi     return r;
33025db9ebeSStefan Hajnoczi }
33125db9ebeSStefan Hajnoczi 
332b36e3914SMichael S. Tsirkin static void virtio_pci_start_ioeventfd(VirtIOPCIProxy *proxy)
33325db9ebeSStefan Hajnoczi {
334a3fc66d9SPaolo Bonzini     VirtIODevice *vdev = virtio_bus_get_device(&proxy->bus);
33525db9ebeSStefan Hajnoczi     int n, r;
33625db9ebeSStefan Hajnoczi 
33725db9ebeSStefan Hajnoczi     if (!(proxy->flags & VIRTIO_PCI_FLAG_USE_IOEVENTFD) ||
33825db9ebeSStefan Hajnoczi         proxy->ioeventfd_disabled ||
33925db9ebeSStefan Hajnoczi         proxy->ioeventfd_started) {
340b36e3914SMichael S. Tsirkin         return;
34125db9ebeSStefan Hajnoczi     }
34225db9ebeSStefan Hajnoczi 
34387b3bd1cSJason Wang     for (n = 0; n < VIRTIO_QUEUE_MAX; n++) {
344a3fc66d9SPaolo Bonzini         if (!virtio_queue_get_num(vdev, n)) {
34525db9ebeSStefan Hajnoczi             continue;
34625db9ebeSStefan Hajnoczi         }
34725db9ebeSStefan Hajnoczi 
34826b9b5feSPaolo Bonzini         r = virtio_pci_set_host_notifier_internal(proxy, n, true, true);
34925db9ebeSStefan Hajnoczi         if (r < 0) {
35025db9ebeSStefan Hajnoczi             goto assign_error;
35125db9ebeSStefan Hajnoczi         }
35225db9ebeSStefan Hajnoczi     }
35325db9ebeSStefan Hajnoczi     proxy->ioeventfd_started = true;
354b36e3914SMichael S. Tsirkin     return;
35525db9ebeSStefan Hajnoczi 
35625db9ebeSStefan Hajnoczi assign_error:
35725db9ebeSStefan Hajnoczi     while (--n >= 0) {
358a3fc66d9SPaolo Bonzini         if (!virtio_queue_get_num(vdev, n)) {
35925db9ebeSStefan Hajnoczi             continue;
36025db9ebeSStefan Hajnoczi         }
36125db9ebeSStefan Hajnoczi 
36226b9b5feSPaolo Bonzini         r = virtio_pci_set_host_notifier_internal(proxy, n, false, false);
363b36e3914SMichael S. Tsirkin         assert(r >= 0);
36425db9ebeSStefan Hajnoczi     }
36525db9ebeSStefan Hajnoczi     proxy->ioeventfd_started = false;
366b36e3914SMichael S. Tsirkin     error_report("%s: failed. Fallback to a userspace (slower).", __func__);
36725db9ebeSStefan Hajnoczi }
36825db9ebeSStefan Hajnoczi 
369b36e3914SMichael S. Tsirkin static void virtio_pci_stop_ioeventfd(VirtIOPCIProxy *proxy)
37025db9ebeSStefan Hajnoczi {
371a3fc66d9SPaolo Bonzini     VirtIODevice *vdev = virtio_bus_get_device(&proxy->bus);
372b36e3914SMichael S. Tsirkin     int r;
37325db9ebeSStefan Hajnoczi     int n;
37425db9ebeSStefan Hajnoczi 
37525db9ebeSStefan Hajnoczi     if (!proxy->ioeventfd_started) {
376b36e3914SMichael S. Tsirkin         return;
37725db9ebeSStefan Hajnoczi     }
37825db9ebeSStefan Hajnoczi 
37987b3bd1cSJason Wang     for (n = 0; n < VIRTIO_QUEUE_MAX; n++) {
380a3fc66d9SPaolo Bonzini         if (!virtio_queue_get_num(vdev, n)) {
38125db9ebeSStefan Hajnoczi             continue;
38225db9ebeSStefan Hajnoczi         }
38325db9ebeSStefan Hajnoczi 
38426b9b5feSPaolo Bonzini         r = virtio_pci_set_host_notifier_internal(proxy, n, false, false);
385b36e3914SMichael S. Tsirkin         assert(r >= 0);
38625db9ebeSStefan Hajnoczi     }
38725db9ebeSStefan Hajnoczi     proxy->ioeventfd_started = false;
38825db9ebeSStefan Hajnoczi }
38925db9ebeSStefan Hajnoczi 
39053c25ceaSPaul Brook static void virtio_ioport_write(void *opaque, uint32_t addr, uint32_t val)
39153c25ceaSPaul Brook {
39253c25ceaSPaul Brook     VirtIOPCIProxy *proxy = opaque;
393a3fc66d9SPaolo Bonzini     VirtIODevice *vdev = virtio_bus_get_device(&proxy->bus);
394a8170e5eSAvi Kivity     hwaddr pa;
39553c25ceaSPaul Brook 
39653c25ceaSPaul Brook     switch (addr) {
39753c25ceaSPaul Brook     case VIRTIO_PCI_GUEST_FEATURES:
39853c25ceaSPaul Brook         /* Guest does not negotiate properly?  We have to assume nothing. */
39953c25ceaSPaul Brook         if (val & (1 << VIRTIO_F_BAD_FEATURE)) {
400181103cdSKONRAD Frederic             val = virtio_bus_get_vdev_bad_features(&proxy->bus);
40153c25ceaSPaul Brook         }
402ad0c9332SPaolo Bonzini         virtio_set_features(vdev, val);
40353c25ceaSPaul Brook         break;
40453c25ceaSPaul Brook     case VIRTIO_PCI_QUEUE_PFN:
405a8170e5eSAvi Kivity         pa = (hwaddr)val << VIRTIO_PCI_QUEUE_ADDR_SHIFT;
4061b8e9b27SMichael S. Tsirkin         if (pa == 0) {
40725db9ebeSStefan Hajnoczi             virtio_pci_stop_ioeventfd(proxy);
408a3fc66d9SPaolo Bonzini             virtio_reset(vdev);
4091b8e9b27SMichael S. Tsirkin             msix_unuse_all_vectors(&proxy->pci_dev);
4101b8e9b27SMichael S. Tsirkin         }
4117055e687SMichael S. Tsirkin         else
41253c25ceaSPaul Brook             virtio_queue_set_addr(vdev, vdev->queue_sel, pa);
41353c25ceaSPaul Brook         break;
41453c25ceaSPaul Brook     case VIRTIO_PCI_QUEUE_SEL:
41587b3bd1cSJason Wang         if (val < VIRTIO_QUEUE_MAX)
41653c25ceaSPaul Brook             vdev->queue_sel = val;
41753c25ceaSPaul Brook         break;
41853c25ceaSPaul Brook     case VIRTIO_PCI_QUEUE_NOTIFY:
41987b3bd1cSJason Wang         if (val < VIRTIO_QUEUE_MAX) {
42053c25ceaSPaul Brook             virtio_queue_notify(vdev, val);
4217157e2e2SStefan Hajnoczi         }
42253c25ceaSPaul Brook         break;
42353c25ceaSPaul Brook     case VIRTIO_PCI_STATUS:
42425db9ebeSStefan Hajnoczi         if (!(val & VIRTIO_CONFIG_S_DRIVER_OK)) {
42525db9ebeSStefan Hajnoczi             virtio_pci_stop_ioeventfd(proxy);
42625db9ebeSStefan Hajnoczi         }
42725db9ebeSStefan Hajnoczi 
4283e607cb5SMichael S. Tsirkin         virtio_set_status(vdev, val & 0xFF);
42925db9ebeSStefan Hajnoczi 
43025db9ebeSStefan Hajnoczi         if (val & VIRTIO_CONFIG_S_DRIVER_OK) {
43125db9ebeSStefan Hajnoczi             virtio_pci_start_ioeventfd(proxy);
43225db9ebeSStefan Hajnoczi         }
43325db9ebeSStefan Hajnoczi 
4341b8e9b27SMichael S. Tsirkin         if (vdev->status == 0) {
435a3fc66d9SPaolo Bonzini             virtio_reset(vdev);
4361b8e9b27SMichael S. Tsirkin             msix_unuse_all_vectors(&proxy->pci_dev);
4371b8e9b27SMichael S. Tsirkin         }
438c81131dbSAlexander Graf 
439e43c0b2eSMichael S. Tsirkin         /* Linux before 2.6.34 drives the device without enabling
440e43c0b2eSMichael S. Tsirkin            the PCI device bus master bit. Enable it automatically
441e43c0b2eSMichael S. Tsirkin            for the guest. This is a PCI spec violation but so is
442e43c0b2eSMichael S. Tsirkin            initiating DMA with bus master bit clear. */
443e43c0b2eSMichael S. Tsirkin         if (val == (VIRTIO_CONFIG_S_ACKNOWLEDGE | VIRTIO_CONFIG_S_DRIVER)) {
444e43c0b2eSMichael S. Tsirkin             pci_default_write_config(&proxy->pci_dev, PCI_COMMAND,
445e43c0b2eSMichael S. Tsirkin                                      proxy->pci_dev.config[PCI_COMMAND] |
446e43c0b2eSMichael S. Tsirkin                                      PCI_COMMAND_MASTER, 1);
447e43c0b2eSMichael S. Tsirkin         }
44853c25ceaSPaul Brook         break;
449aba800a3SMichael S. Tsirkin     case VIRTIO_MSI_CONFIG_VECTOR:
450aba800a3SMichael S. Tsirkin         msix_vector_unuse(&proxy->pci_dev, vdev->config_vector);
451aba800a3SMichael S. Tsirkin         /* Make it possible for guest to discover an error took place. */
452aba800a3SMichael S. Tsirkin         if (msix_vector_use(&proxy->pci_dev, val) < 0)
453aba800a3SMichael S. Tsirkin             val = VIRTIO_NO_VECTOR;
454aba800a3SMichael S. Tsirkin         vdev->config_vector = val;
455aba800a3SMichael S. Tsirkin         break;
456aba800a3SMichael S. Tsirkin     case VIRTIO_MSI_QUEUE_VECTOR:
457aba800a3SMichael S. Tsirkin         msix_vector_unuse(&proxy->pci_dev,
458aba800a3SMichael S. Tsirkin                           virtio_queue_vector(vdev, vdev->queue_sel));
459aba800a3SMichael S. Tsirkin         /* Make it possible for guest to discover an error took place. */
460aba800a3SMichael S. Tsirkin         if (msix_vector_use(&proxy->pci_dev, val) < 0)
461aba800a3SMichael S. Tsirkin             val = VIRTIO_NO_VECTOR;
462aba800a3SMichael S. Tsirkin         virtio_queue_set_vector(vdev, vdev->queue_sel, val);
463aba800a3SMichael S. Tsirkin         break;
464aba800a3SMichael S. Tsirkin     default:
4654e02d460SStefan Hajnoczi         error_report("%s: unexpected address 0x%x value 0x%x",
466aba800a3SMichael S. Tsirkin                      __func__, addr, val);
467aba800a3SMichael S. Tsirkin         break;
46853c25ceaSPaul Brook     }
46953c25ceaSPaul Brook }
47053c25ceaSPaul Brook 
471aba800a3SMichael S. Tsirkin static uint32_t virtio_ioport_read(VirtIOPCIProxy *proxy, uint32_t addr)
47253c25ceaSPaul Brook {
473a3fc66d9SPaolo Bonzini     VirtIODevice *vdev = virtio_bus_get_device(&proxy->bus);
47453c25ceaSPaul Brook     uint32_t ret = 0xFFFFFFFF;
47553c25ceaSPaul Brook 
47653c25ceaSPaul Brook     switch (addr) {
47753c25ceaSPaul Brook     case VIRTIO_PCI_HOST_FEATURES:
4786b8f1020SCornelia Huck         ret = vdev->host_features;
47953c25ceaSPaul Brook         break;
48053c25ceaSPaul Brook     case VIRTIO_PCI_GUEST_FEATURES:
481704a76fcSMichael S. Tsirkin         ret = vdev->guest_features;
48253c25ceaSPaul Brook         break;
48353c25ceaSPaul Brook     case VIRTIO_PCI_QUEUE_PFN:
48453c25ceaSPaul Brook         ret = virtio_queue_get_addr(vdev, vdev->queue_sel)
48553c25ceaSPaul Brook               >> VIRTIO_PCI_QUEUE_ADDR_SHIFT;
48653c25ceaSPaul Brook         break;
48753c25ceaSPaul Brook     case VIRTIO_PCI_QUEUE_NUM:
48853c25ceaSPaul Brook         ret = virtio_queue_get_num(vdev, vdev->queue_sel);
48953c25ceaSPaul Brook         break;
49053c25ceaSPaul Brook     case VIRTIO_PCI_QUEUE_SEL:
49153c25ceaSPaul Brook         ret = vdev->queue_sel;
49253c25ceaSPaul Brook         break;
49353c25ceaSPaul Brook     case VIRTIO_PCI_STATUS:
49453c25ceaSPaul Brook         ret = vdev->status;
49553c25ceaSPaul Brook         break;
49653c25ceaSPaul Brook     case VIRTIO_PCI_ISR:
49753c25ceaSPaul Brook         /* reading from the ISR also clears it. */
49853c25ceaSPaul Brook         ret = vdev->isr;
49953c25ceaSPaul Brook         vdev->isr = 0;
5009e64f8a3SMarcel Apfelbaum         pci_irq_deassert(&proxy->pci_dev);
50153c25ceaSPaul Brook         break;
502aba800a3SMichael S. Tsirkin     case VIRTIO_MSI_CONFIG_VECTOR:
503aba800a3SMichael S. Tsirkin         ret = vdev->config_vector;
504aba800a3SMichael S. Tsirkin         break;
505aba800a3SMichael S. Tsirkin     case VIRTIO_MSI_QUEUE_VECTOR:
506aba800a3SMichael S. Tsirkin         ret = virtio_queue_vector(vdev, vdev->queue_sel);
507aba800a3SMichael S. Tsirkin         break;
50853c25ceaSPaul Brook     default:
50953c25ceaSPaul Brook         break;
51053c25ceaSPaul Brook     }
51153c25ceaSPaul Brook 
51253c25ceaSPaul Brook     return ret;
51353c25ceaSPaul Brook }
51453c25ceaSPaul Brook 
515df6db5b3SAlexander Graf static uint64_t virtio_pci_config_read(void *opaque, hwaddr addr,
516df6db5b3SAlexander Graf                                        unsigned size)
51753c25ceaSPaul Brook {
51853c25ceaSPaul Brook     VirtIOPCIProxy *proxy = opaque;
519a3fc66d9SPaolo Bonzini     VirtIODevice *vdev = virtio_bus_get_device(&proxy->bus);
520cbbe4f50SMichael S. Tsirkin     uint32_t config = VIRTIO_PCI_CONFIG_SIZE(&proxy->pci_dev);
521df6db5b3SAlexander Graf     uint64_t val = 0;
522df6db5b3SAlexander Graf     if (addr < config) {
523aba800a3SMichael S. Tsirkin         return virtio_ioport_read(proxy, addr);
52453c25ceaSPaul Brook     }
525aba800a3SMichael S. Tsirkin     addr -= config;
526df6db5b3SAlexander Graf 
527df6db5b3SAlexander Graf     switch (size) {
528df6db5b3SAlexander Graf     case 1:
529a3fc66d9SPaolo Bonzini         val = virtio_config_readb(vdev, addr);
530df6db5b3SAlexander Graf         break;
531df6db5b3SAlexander Graf     case 2:
532a3fc66d9SPaolo Bonzini         val = virtio_config_readw(vdev, addr);
533616a6552SGreg Kurz         if (virtio_is_big_endian(vdev)) {
5348e4a424bSBlue Swirl             val = bswap16(val);
5358e4a424bSBlue Swirl         }
536df6db5b3SAlexander Graf         break;
537df6db5b3SAlexander Graf     case 4:
538a3fc66d9SPaolo Bonzini         val = virtio_config_readl(vdev, addr);
539616a6552SGreg Kurz         if (virtio_is_big_endian(vdev)) {
5408e4a424bSBlue Swirl             val = bswap32(val);
5418e4a424bSBlue Swirl         }
542df6db5b3SAlexander Graf         break;
543df6db5b3SAlexander Graf     }
54482afa586SBenjamin Herrenschmidt     return val;
54553c25ceaSPaul Brook }
54653c25ceaSPaul Brook 
547df6db5b3SAlexander Graf static void virtio_pci_config_write(void *opaque, hwaddr addr,
548df6db5b3SAlexander Graf                                     uint64_t val, unsigned size)
54953c25ceaSPaul Brook {
55053c25ceaSPaul Brook     VirtIOPCIProxy *proxy = opaque;
551cbbe4f50SMichael S. Tsirkin     uint32_t config = VIRTIO_PCI_CONFIG_SIZE(&proxy->pci_dev);
552a3fc66d9SPaolo Bonzini     VirtIODevice *vdev = virtio_bus_get_device(&proxy->bus);
553aba800a3SMichael S. Tsirkin     if (addr < config) {
554aba800a3SMichael S. Tsirkin         virtio_ioport_write(proxy, addr, val);
555aba800a3SMichael S. Tsirkin         return;
556aba800a3SMichael S. Tsirkin     }
557aba800a3SMichael S. Tsirkin     addr -= config;
558df6db5b3SAlexander Graf     /*
559df6db5b3SAlexander Graf      * Virtio-PCI is odd. Ioports are LE but config space is target native
560df6db5b3SAlexander Graf      * endian.
561df6db5b3SAlexander Graf      */
562df6db5b3SAlexander Graf     switch (size) {
563df6db5b3SAlexander Graf     case 1:
564a3fc66d9SPaolo Bonzini         virtio_config_writeb(vdev, addr, val);
565df6db5b3SAlexander Graf         break;
566df6db5b3SAlexander Graf     case 2:
567616a6552SGreg Kurz         if (virtio_is_big_endian(vdev)) {
5688e4a424bSBlue Swirl             val = bswap16(val);
5698e4a424bSBlue Swirl         }
570a3fc66d9SPaolo Bonzini         virtio_config_writew(vdev, addr, val);
571df6db5b3SAlexander Graf         break;
572df6db5b3SAlexander Graf     case 4:
573616a6552SGreg Kurz         if (virtio_is_big_endian(vdev)) {
5748e4a424bSBlue Swirl             val = bswap32(val);
5758e4a424bSBlue Swirl         }
576a3fc66d9SPaolo Bonzini         virtio_config_writel(vdev, addr, val);
577df6db5b3SAlexander Graf         break;
578df6db5b3SAlexander Graf     }
57953c25ceaSPaul Brook }
58053c25ceaSPaul Brook 
581da146d0aSAvi Kivity static const MemoryRegionOps virtio_pci_config_ops = {
582df6db5b3SAlexander Graf     .read = virtio_pci_config_read,
583df6db5b3SAlexander Graf     .write = virtio_pci_config_write,
584df6db5b3SAlexander Graf     .impl = {
585df6db5b3SAlexander Graf         .min_access_size = 1,
586df6db5b3SAlexander Graf         .max_access_size = 4,
587df6db5b3SAlexander Graf     },
5888e4a424bSBlue Swirl     .endianness = DEVICE_LITTLE_ENDIAN,
589da146d0aSAvi Kivity };
590aba800a3SMichael S. Tsirkin 
5911e40356cSMichael S. Tsirkin /* Below are generic functions to do memcpy from/to an address space,
5921e40356cSMichael S. Tsirkin  * without byteswaps, with input validation.
5931e40356cSMichael S. Tsirkin  *
5941e40356cSMichael S. Tsirkin  * As regular address_space_* APIs all do some kind of byteswap at least for
5951e40356cSMichael S. Tsirkin  * some host/target combinations, we are forced to explicitly convert to a
5961e40356cSMichael S. Tsirkin  * known-endianness integer value.
5971e40356cSMichael S. Tsirkin  * It doesn't really matter which endian format to go through, so the code
5981e40356cSMichael S. Tsirkin  * below selects the endian that causes the least amount of work on the given
5991e40356cSMichael S. Tsirkin  * host.
6001e40356cSMichael S. Tsirkin  *
6011e40356cSMichael S. Tsirkin  * Note: host pointer must be aligned.
6021e40356cSMichael S. Tsirkin  */
6031e40356cSMichael S. Tsirkin static
6041e40356cSMichael S. Tsirkin void virtio_address_space_write(AddressSpace *as, hwaddr addr,
6051e40356cSMichael S. Tsirkin                                 const uint8_t *buf, int len)
6061e40356cSMichael S. Tsirkin {
6071e40356cSMichael S. Tsirkin     uint32_t val;
6081e40356cSMichael S. Tsirkin 
6091e40356cSMichael S. Tsirkin     /* address_space_* APIs assume an aligned address.
6101e40356cSMichael S. Tsirkin      * As address is under guest control, handle illegal values.
6111e40356cSMichael S. Tsirkin      */
6121e40356cSMichael S. Tsirkin     addr &= ~(len - 1);
6131e40356cSMichael S. Tsirkin 
6141e40356cSMichael S. Tsirkin     /* Make sure caller aligned buf properly */
6151e40356cSMichael S. Tsirkin     assert(!(((uintptr_t)buf) & (len - 1)));
6161e40356cSMichael S. Tsirkin 
6171e40356cSMichael S. Tsirkin     switch (len) {
6181e40356cSMichael S. Tsirkin     case 1:
6191e40356cSMichael S. Tsirkin         val = pci_get_byte(buf);
6201e40356cSMichael S. Tsirkin         address_space_stb(as, addr, val, MEMTXATTRS_UNSPECIFIED, NULL);
6211e40356cSMichael S. Tsirkin         break;
6221e40356cSMichael S. Tsirkin     case 2:
6231e40356cSMichael S. Tsirkin         val = pci_get_word(buf);
6241e40356cSMichael S. Tsirkin         address_space_stw_le(as, addr, val, MEMTXATTRS_UNSPECIFIED, NULL);
6251e40356cSMichael S. Tsirkin         break;
6261e40356cSMichael S. Tsirkin     case 4:
6271e40356cSMichael S. Tsirkin         val = pci_get_long(buf);
6281e40356cSMichael S. Tsirkin         address_space_stl_le(as, addr, val, MEMTXATTRS_UNSPECIFIED, NULL);
6291e40356cSMichael S. Tsirkin         break;
6301e40356cSMichael S. Tsirkin     default:
6311e40356cSMichael S. Tsirkin         /* As length is under guest control, handle illegal values. */
6321e40356cSMichael S. Tsirkin         break;
6331e40356cSMichael S. Tsirkin     }
6341e40356cSMichael S. Tsirkin }
6351e40356cSMichael S. Tsirkin 
6361e40356cSMichael S. Tsirkin static void
6371e40356cSMichael S. Tsirkin virtio_address_space_read(AddressSpace *as, hwaddr addr, uint8_t *buf, int len)
6381e40356cSMichael S. Tsirkin {
6391e40356cSMichael S. Tsirkin     uint32_t val;
6401e40356cSMichael S. Tsirkin 
6411e40356cSMichael S. Tsirkin     /* address_space_* APIs assume an aligned address.
6421e40356cSMichael S. Tsirkin      * As address is under guest control, handle illegal values.
6431e40356cSMichael S. Tsirkin      */
6441e40356cSMichael S. Tsirkin     addr &= ~(len - 1);
6451e40356cSMichael S. Tsirkin 
6461e40356cSMichael S. Tsirkin     /* Make sure caller aligned buf properly */
6471e40356cSMichael S. Tsirkin     assert(!(((uintptr_t)buf) & (len - 1)));
6481e40356cSMichael S. Tsirkin 
6491e40356cSMichael S. Tsirkin     switch (len) {
6501e40356cSMichael S. Tsirkin     case 1:
6511e40356cSMichael S. Tsirkin         val = address_space_ldub(as, addr, MEMTXATTRS_UNSPECIFIED, NULL);
6521e40356cSMichael S. Tsirkin         pci_set_byte(buf, val);
6531e40356cSMichael S. Tsirkin         break;
6541e40356cSMichael S. Tsirkin     case 2:
6551e40356cSMichael S. Tsirkin         val = address_space_lduw_le(as, addr, MEMTXATTRS_UNSPECIFIED, NULL);
6561e40356cSMichael S. Tsirkin         pci_set_word(buf, val);
6571e40356cSMichael S. Tsirkin         break;
6581e40356cSMichael S. Tsirkin     case 4:
6591e40356cSMichael S. Tsirkin         val = address_space_ldl_le(as, addr, MEMTXATTRS_UNSPECIFIED, NULL);
6601e40356cSMichael S. Tsirkin         pci_set_long(buf, val);
6611e40356cSMichael S. Tsirkin         break;
6621e40356cSMichael S. Tsirkin     default:
6631e40356cSMichael S. Tsirkin         /* As length is under guest control, handle illegal values. */
6641e40356cSMichael S. Tsirkin         break;
6651e40356cSMichael S. Tsirkin     }
6661e40356cSMichael S. Tsirkin }
6671e40356cSMichael S. Tsirkin 
668aba800a3SMichael S. Tsirkin static void virtio_write_config(PCIDevice *pci_dev, uint32_t address,
669aba800a3SMichael S. Tsirkin                                 uint32_t val, int len)
670aba800a3SMichael S. Tsirkin {
671ed757e14SYan Vugenfirer     VirtIOPCIProxy *proxy = DO_UPCAST(VirtIOPCIProxy, pci_dev, pci_dev);
672a3fc66d9SPaolo Bonzini     VirtIODevice *vdev = virtio_bus_get_device(&proxy->bus);
673ada434cdSMichael S. Tsirkin     struct virtio_pci_cfg_cap *cfg;
674ed757e14SYan Vugenfirer 
6751129714fSMichael S. Tsirkin     pci_default_write_config(pci_dev, address, val, len);
6761129714fSMichael S. Tsirkin 
6771129714fSMichael S. Tsirkin     if (range_covers_byte(address, len, PCI_COMMAND) &&
67868a27b20SMichael S. Tsirkin         !(pci_dev->config[PCI_COMMAND] & PCI_COMMAND_MASTER)) {
67925db9ebeSStefan Hajnoczi         virtio_pci_stop_ioeventfd(proxy);
68045363e46SMichael S. Tsirkin         virtio_set_status(vdev, vdev->status & ~VIRTIO_CONFIG_S_DRIVER_OK);
681ed757e14SYan Vugenfirer     }
682ada434cdSMichael S. Tsirkin 
683ada434cdSMichael S. Tsirkin     if (proxy->config_cap &&
684ada434cdSMichael S. Tsirkin         ranges_overlap(address, len, proxy->config_cap + offsetof(struct virtio_pci_cfg_cap,
685ada434cdSMichael S. Tsirkin                                                                   pci_cfg_data),
686ada434cdSMichael S. Tsirkin                        sizeof cfg->pci_cfg_data)) {
687ada434cdSMichael S. Tsirkin         uint32_t off;
688ada434cdSMichael S. Tsirkin         uint32_t len;
689ada434cdSMichael S. Tsirkin 
690ada434cdSMichael S. Tsirkin         cfg = (void *)(proxy->pci_dev.config + proxy->config_cap);
691ada434cdSMichael S. Tsirkin         off = le32_to_cpu(cfg->cap.offset);
692ada434cdSMichael S. Tsirkin         len = le32_to_cpu(cfg->cap.length);
693ada434cdSMichael S. Tsirkin 
6942a639123SMichael S. Tsirkin         if (len == 1 || len == 2 || len == 4) {
6952a639123SMichael S. Tsirkin             assert(len <= sizeof cfg->pci_cfg_data);
6961e40356cSMichael S. Tsirkin             virtio_address_space_write(&proxy->modern_as, off,
697ada434cdSMichael S. Tsirkin                                        cfg->pci_cfg_data, len);
698ada434cdSMichael S. Tsirkin         }
699ada434cdSMichael S. Tsirkin     }
700ada434cdSMichael S. Tsirkin }
701ada434cdSMichael S. Tsirkin 
702ada434cdSMichael S. Tsirkin static uint32_t virtio_read_config(PCIDevice *pci_dev,
703ada434cdSMichael S. Tsirkin                                    uint32_t address, int len)
704ada434cdSMichael S. Tsirkin {
705ada434cdSMichael S. Tsirkin     VirtIOPCIProxy *proxy = DO_UPCAST(VirtIOPCIProxy, pci_dev, pci_dev);
706ada434cdSMichael S. Tsirkin     struct virtio_pci_cfg_cap *cfg;
707ada434cdSMichael S. Tsirkin 
708ada434cdSMichael S. Tsirkin     if (proxy->config_cap &&
709ada434cdSMichael S. Tsirkin         ranges_overlap(address, len, proxy->config_cap + offsetof(struct virtio_pci_cfg_cap,
710ada434cdSMichael S. Tsirkin                                                                   pci_cfg_data),
711ada434cdSMichael S. Tsirkin                        sizeof cfg->pci_cfg_data)) {
712ada434cdSMichael S. Tsirkin         uint32_t off;
713ada434cdSMichael S. Tsirkin         uint32_t len;
714ada434cdSMichael S. Tsirkin 
715ada434cdSMichael S. Tsirkin         cfg = (void *)(proxy->pci_dev.config + proxy->config_cap);
716ada434cdSMichael S. Tsirkin         off = le32_to_cpu(cfg->cap.offset);
717ada434cdSMichael S. Tsirkin         len = le32_to_cpu(cfg->cap.length);
718ada434cdSMichael S. Tsirkin 
7192a639123SMichael S. Tsirkin         if (len == 1 || len == 2 || len == 4) {
7202a639123SMichael S. Tsirkin             assert(len <= sizeof cfg->pci_cfg_data);
7211e40356cSMichael S. Tsirkin             virtio_address_space_read(&proxy->modern_as, off,
722ada434cdSMichael S. Tsirkin                                       cfg->pci_cfg_data, len);
723ada434cdSMichael S. Tsirkin         }
724ada434cdSMichael S. Tsirkin     }
725ada434cdSMichael S. Tsirkin 
726ada434cdSMichael S. Tsirkin     return pci_default_read_config(pci_dev, address, len);
72753c25ceaSPaul Brook }
72853c25ceaSPaul Brook 
7297d37d351SJan Kiszka static int kvm_virtio_pci_vq_vector_use(VirtIOPCIProxy *proxy,
7307d37d351SJan Kiszka                                         unsigned int queue_no,
7317d37d351SJan Kiszka                                         unsigned int vector,
7327d37d351SJan Kiszka                                         MSIMessage msg)
7337d37d351SJan Kiszka {
7347d37d351SJan Kiszka     VirtIOIRQFD *irqfd = &proxy->vector_irqfd[vector];
73515b2bd18SPaolo Bonzini     int ret;
7367d37d351SJan Kiszka 
7377d37d351SJan Kiszka     if (irqfd->users == 0) {
738dc9f06caSPavel Fedin         ret = kvm_irqchip_add_msi_route(kvm_state, msg, &proxy->pci_dev);
7397d37d351SJan Kiszka         if (ret < 0) {
7407d37d351SJan Kiszka             return ret;
7417d37d351SJan Kiszka         }
7427d37d351SJan Kiszka         irqfd->virq = ret;
7437d37d351SJan Kiszka     }
7447d37d351SJan Kiszka     irqfd->users++;
7457d37d351SJan Kiszka     return 0;
7467d37d351SJan Kiszka }
7477d37d351SJan Kiszka 
7487d37d351SJan Kiszka static void kvm_virtio_pci_vq_vector_release(VirtIOPCIProxy *proxy,
749774345f9SMichael S. Tsirkin                                              unsigned int vector)
750774345f9SMichael S. Tsirkin {
751774345f9SMichael S. Tsirkin     VirtIOIRQFD *irqfd = &proxy->vector_irqfd[vector];
752774345f9SMichael S. Tsirkin     if (--irqfd->users == 0) {
753774345f9SMichael S. Tsirkin         kvm_irqchip_release_virq(kvm_state, irqfd->virq);
754774345f9SMichael S. Tsirkin     }
755774345f9SMichael S. Tsirkin }
756774345f9SMichael S. Tsirkin 
757f1d0f15aSMichael S. Tsirkin static int kvm_virtio_pci_irqfd_use(VirtIOPCIProxy *proxy,
758f1d0f15aSMichael S. Tsirkin                                  unsigned int queue_no,
759f1d0f15aSMichael S. Tsirkin                                  unsigned int vector)
760f1d0f15aSMichael S. Tsirkin {
761f1d0f15aSMichael S. Tsirkin     VirtIOIRQFD *irqfd = &proxy->vector_irqfd[vector];
762a3fc66d9SPaolo Bonzini     VirtIODevice *vdev = virtio_bus_get_device(&proxy->bus);
763a3fc66d9SPaolo Bonzini     VirtQueue *vq = virtio_get_queue(vdev, queue_no);
764f1d0f15aSMichael S. Tsirkin     EventNotifier *n = virtio_queue_get_guest_notifier(vq);
765f1d0f15aSMichael S. Tsirkin     int ret;
7661c9b71a7SEric Auger     ret = kvm_irqchip_add_irqfd_notifier_gsi(kvm_state, n, NULL, irqfd->virq);
767f1d0f15aSMichael S. Tsirkin     return ret;
768f1d0f15aSMichael S. Tsirkin }
769f1d0f15aSMichael S. Tsirkin 
770f1d0f15aSMichael S. Tsirkin static void kvm_virtio_pci_irqfd_release(VirtIOPCIProxy *proxy,
7717d37d351SJan Kiszka                                       unsigned int queue_no,
7727d37d351SJan Kiszka                                       unsigned int vector)
7737d37d351SJan Kiszka {
774a3fc66d9SPaolo Bonzini     VirtIODevice *vdev = virtio_bus_get_device(&proxy->bus);
775a3fc66d9SPaolo Bonzini     VirtQueue *vq = virtio_get_queue(vdev, queue_no);
77615b2bd18SPaolo Bonzini     EventNotifier *n = virtio_queue_get_guest_notifier(vq);
7777d37d351SJan Kiszka     VirtIOIRQFD *irqfd = &proxy->vector_irqfd[vector];
77815b2bd18SPaolo Bonzini     int ret;
7797d37d351SJan Kiszka 
7801c9b71a7SEric Auger     ret = kvm_irqchip_remove_irqfd_notifier_gsi(kvm_state, n, irqfd->virq);
7817d37d351SJan Kiszka     assert(ret == 0);
782f1d0f15aSMichael S. Tsirkin }
7837d37d351SJan Kiszka 
784774345f9SMichael S. Tsirkin static int kvm_virtio_pci_vector_use(VirtIOPCIProxy *proxy, int nvqs)
785774345f9SMichael S. Tsirkin {
786774345f9SMichael S. Tsirkin     PCIDevice *dev = &proxy->pci_dev;
787a3fc66d9SPaolo Bonzini     VirtIODevice *vdev = virtio_bus_get_device(&proxy->bus);
788181103cdSKONRAD Frederic     VirtioDeviceClass *k = VIRTIO_DEVICE_GET_CLASS(vdev);
789774345f9SMichael S. Tsirkin     unsigned int vector;
790774345f9SMichael S. Tsirkin     int ret, queue_no;
791774345f9SMichael S. Tsirkin     MSIMessage msg;
792774345f9SMichael S. Tsirkin 
793774345f9SMichael S. Tsirkin     for (queue_no = 0; queue_no < nvqs; queue_no++) {
794774345f9SMichael S. Tsirkin         if (!virtio_queue_get_num(vdev, queue_no)) {
795774345f9SMichael S. Tsirkin             break;
796774345f9SMichael S. Tsirkin         }
797774345f9SMichael S. Tsirkin         vector = virtio_queue_vector(vdev, queue_no);
798774345f9SMichael S. Tsirkin         if (vector >= msix_nr_vectors_allocated(dev)) {
799774345f9SMichael S. Tsirkin             continue;
800774345f9SMichael S. Tsirkin         }
801774345f9SMichael S. Tsirkin         msg = msix_get_message(dev, vector);
802774345f9SMichael S. Tsirkin         ret = kvm_virtio_pci_vq_vector_use(proxy, queue_no, vector, msg);
803774345f9SMichael S. Tsirkin         if (ret < 0) {
804774345f9SMichael S. Tsirkin             goto undo;
805774345f9SMichael S. Tsirkin         }
806f1d0f15aSMichael S. Tsirkin         /* If guest supports masking, set up irqfd now.
807f1d0f15aSMichael S. Tsirkin          * Otherwise, delay until unmasked in the frontend.
808f1d0f15aSMichael S. Tsirkin          */
809181103cdSKONRAD Frederic         if (k->guest_notifier_mask) {
810f1d0f15aSMichael S. Tsirkin             ret = kvm_virtio_pci_irqfd_use(proxy, queue_no, vector);
811f1d0f15aSMichael S. Tsirkin             if (ret < 0) {
812f1d0f15aSMichael S. Tsirkin                 kvm_virtio_pci_vq_vector_release(proxy, vector);
813f1d0f15aSMichael S. Tsirkin                 goto undo;
814f1d0f15aSMichael S. Tsirkin             }
815f1d0f15aSMichael S. Tsirkin         }
816774345f9SMichael S. Tsirkin     }
817774345f9SMichael S. Tsirkin     return 0;
818774345f9SMichael S. Tsirkin 
819774345f9SMichael S. Tsirkin undo:
820774345f9SMichael S. Tsirkin     while (--queue_no >= 0) {
821774345f9SMichael S. Tsirkin         vector = virtio_queue_vector(vdev, queue_no);
822774345f9SMichael S. Tsirkin         if (vector >= msix_nr_vectors_allocated(dev)) {
823774345f9SMichael S. Tsirkin             continue;
824774345f9SMichael S. Tsirkin         }
825181103cdSKONRAD Frederic         if (k->guest_notifier_mask) {
826e387f99eSMichael S. Tsirkin             kvm_virtio_pci_irqfd_release(proxy, queue_no, vector);
827f1d0f15aSMichael S. Tsirkin         }
828774345f9SMichael S. Tsirkin         kvm_virtio_pci_vq_vector_release(proxy, vector);
829774345f9SMichael S. Tsirkin     }
830774345f9SMichael S. Tsirkin     return ret;
831774345f9SMichael S. Tsirkin }
832774345f9SMichael S. Tsirkin 
833774345f9SMichael S. Tsirkin static void kvm_virtio_pci_vector_release(VirtIOPCIProxy *proxy, int nvqs)
834774345f9SMichael S. Tsirkin {
835774345f9SMichael S. Tsirkin     PCIDevice *dev = &proxy->pci_dev;
836a3fc66d9SPaolo Bonzini     VirtIODevice *vdev = virtio_bus_get_device(&proxy->bus);
837774345f9SMichael S. Tsirkin     unsigned int vector;
838774345f9SMichael S. Tsirkin     int queue_no;
839181103cdSKONRAD Frederic     VirtioDeviceClass *k = VIRTIO_DEVICE_GET_CLASS(vdev);
840774345f9SMichael S. Tsirkin 
841774345f9SMichael S. Tsirkin     for (queue_no = 0; queue_no < nvqs; queue_no++) {
842774345f9SMichael S. Tsirkin         if (!virtio_queue_get_num(vdev, queue_no)) {
843774345f9SMichael S. Tsirkin             break;
844774345f9SMichael S. Tsirkin         }
845774345f9SMichael S. Tsirkin         vector = virtio_queue_vector(vdev, queue_no);
846774345f9SMichael S. Tsirkin         if (vector >= msix_nr_vectors_allocated(dev)) {
847774345f9SMichael S. Tsirkin             continue;
848774345f9SMichael S. Tsirkin         }
849f1d0f15aSMichael S. Tsirkin         /* If guest supports masking, clean up irqfd now.
850f1d0f15aSMichael S. Tsirkin          * Otherwise, it was cleaned when masked in the frontend.
851f1d0f15aSMichael S. Tsirkin          */
852181103cdSKONRAD Frederic         if (k->guest_notifier_mask) {
853e387f99eSMichael S. Tsirkin             kvm_virtio_pci_irqfd_release(proxy, queue_no, vector);
854f1d0f15aSMichael S. Tsirkin         }
855774345f9SMichael S. Tsirkin         kvm_virtio_pci_vq_vector_release(proxy, vector);
8567d37d351SJan Kiszka     }
8577d37d351SJan Kiszka }
8587d37d351SJan Kiszka 
859a38b2c49SMichael S. Tsirkin static int virtio_pci_vq_vector_unmask(VirtIOPCIProxy *proxy,
860774345f9SMichael S. Tsirkin                                        unsigned int queue_no,
861774345f9SMichael S. Tsirkin                                        unsigned int vector,
862774345f9SMichael S. Tsirkin                                        MSIMessage msg)
863774345f9SMichael S. Tsirkin {
864a3fc66d9SPaolo Bonzini     VirtIODevice *vdev = virtio_bus_get_device(&proxy->bus);
865a3fc66d9SPaolo Bonzini     VirtioDeviceClass *k = VIRTIO_DEVICE_GET_CLASS(vdev);
866a3fc66d9SPaolo Bonzini     VirtQueue *vq = virtio_get_queue(vdev, queue_no);
867774345f9SMichael S. Tsirkin     EventNotifier *n = virtio_queue_get_guest_notifier(vq);
868a38b2c49SMichael S. Tsirkin     VirtIOIRQFD *irqfd;
86953510bfcSMichael Roth     int ret = 0;
870774345f9SMichael S. Tsirkin 
871a38b2c49SMichael S. Tsirkin     if (proxy->vector_irqfd) {
872a38b2c49SMichael S. Tsirkin         irqfd = &proxy->vector_irqfd[vector];
873774345f9SMichael S. Tsirkin         if (irqfd->msg.data != msg.data || irqfd->msg.address != msg.address) {
874dc9f06caSPavel Fedin             ret = kvm_irqchip_update_msi_route(kvm_state, irqfd->virq, msg,
875dc9f06caSPavel Fedin                                                &proxy->pci_dev);
876774345f9SMichael S. Tsirkin             if (ret < 0) {
877774345f9SMichael S. Tsirkin                 return ret;
878774345f9SMichael S. Tsirkin             }
879774345f9SMichael S. Tsirkin         }
880a38b2c49SMichael S. Tsirkin     }
881774345f9SMichael S. Tsirkin 
882f1d0f15aSMichael S. Tsirkin     /* If guest supports masking, irqfd is already setup, unmask it.
883f1d0f15aSMichael S. Tsirkin      * Otherwise, set it up now.
884f1d0f15aSMichael S. Tsirkin      */
885181103cdSKONRAD Frederic     if (k->guest_notifier_mask) {
886a3fc66d9SPaolo Bonzini         k->guest_notifier_mask(vdev, queue_no, false);
887f1d0f15aSMichael S. Tsirkin         /* Test after unmasking to avoid losing events. */
888181103cdSKONRAD Frederic         if (k->guest_notifier_pending &&
889a3fc66d9SPaolo Bonzini             k->guest_notifier_pending(vdev, queue_no)) {
890f1d0f15aSMichael S. Tsirkin             event_notifier_set(n);
891f1d0f15aSMichael S. Tsirkin         }
892f1d0f15aSMichael S. Tsirkin     } else {
893f1d0f15aSMichael S. Tsirkin         ret = kvm_virtio_pci_irqfd_use(proxy, queue_no, vector);
894f1d0f15aSMichael S. Tsirkin     }
895774345f9SMichael S. Tsirkin     return ret;
896774345f9SMichael S. Tsirkin }
897774345f9SMichael S. Tsirkin 
898a38b2c49SMichael S. Tsirkin static void virtio_pci_vq_vector_mask(VirtIOPCIProxy *proxy,
8997d37d351SJan Kiszka                                              unsigned int queue_no,
9007d37d351SJan Kiszka                                              unsigned int vector)
9017d37d351SJan Kiszka {
902a3fc66d9SPaolo Bonzini     VirtIODevice *vdev = virtio_bus_get_device(&proxy->bus);
903a3fc66d9SPaolo Bonzini     VirtioDeviceClass *k = VIRTIO_DEVICE_GET_CLASS(vdev);
904181103cdSKONRAD Frederic 
905f1d0f15aSMichael S. Tsirkin     /* If guest supports masking, keep irqfd but mask it.
906f1d0f15aSMichael S. Tsirkin      * Otherwise, clean it up now.
907f1d0f15aSMichael S. Tsirkin      */
908181103cdSKONRAD Frederic     if (k->guest_notifier_mask) {
909a3fc66d9SPaolo Bonzini         k->guest_notifier_mask(vdev, queue_no, true);
910f1d0f15aSMichael S. Tsirkin     } else {
911e387f99eSMichael S. Tsirkin         kvm_virtio_pci_irqfd_release(proxy, queue_no, vector);
912f1d0f15aSMichael S. Tsirkin     }
9137d37d351SJan Kiszka }
9147d37d351SJan Kiszka 
915a38b2c49SMichael S. Tsirkin static int virtio_pci_vector_unmask(PCIDevice *dev, unsigned vector,
9167d37d351SJan Kiszka                                     MSIMessage msg)
9177d37d351SJan Kiszka {
9187d37d351SJan Kiszka     VirtIOPCIProxy *proxy = container_of(dev, VirtIOPCIProxy, pci_dev);
919a3fc66d9SPaolo Bonzini     VirtIODevice *vdev = virtio_bus_get_device(&proxy->bus);
920851c2a75SJason Wang     VirtQueue *vq = virtio_vector_first_queue(vdev, vector);
921851c2a75SJason Wang     int ret, index, unmasked = 0;
9227d37d351SJan Kiszka 
923851c2a75SJason Wang     while (vq) {
924851c2a75SJason Wang         index = virtio_get_queue_index(vq);
925851c2a75SJason Wang         if (!virtio_queue_get_num(vdev, index)) {
9267d37d351SJan Kiszka             break;
9277d37d351SJan Kiszka         }
9286652d081SJason Wang         if (index < proxy->nvqs_with_notifiers) {
929851c2a75SJason Wang             ret = virtio_pci_vq_vector_unmask(proxy, index, vector, msg);
9307d37d351SJan Kiszka             if (ret < 0) {
9317d37d351SJan Kiszka                 goto undo;
9327d37d351SJan Kiszka             }
933851c2a75SJason Wang             ++unmasked;
9347d37d351SJan Kiszka         }
9356652d081SJason Wang         vq = virtio_vector_next_queue(vq);
9366652d081SJason Wang     }
937851c2a75SJason Wang 
9387d37d351SJan Kiszka     return 0;
9397d37d351SJan Kiszka 
9407d37d351SJan Kiszka undo:
941851c2a75SJason Wang     vq = virtio_vector_first_queue(vdev, vector);
9426652d081SJason Wang     while (vq && unmasked >= 0) {
943851c2a75SJason Wang         index = virtio_get_queue_index(vq);
9446652d081SJason Wang         if (index < proxy->nvqs_with_notifiers) {
945851c2a75SJason Wang             virtio_pci_vq_vector_mask(proxy, index, vector);
9466652d081SJason Wang             --unmasked;
9476652d081SJason Wang         }
948851c2a75SJason Wang         vq = virtio_vector_next_queue(vq);
9497d37d351SJan Kiszka     }
9507d37d351SJan Kiszka     return ret;
9517d37d351SJan Kiszka }
9527d37d351SJan Kiszka 
953a38b2c49SMichael S. Tsirkin static void virtio_pci_vector_mask(PCIDevice *dev, unsigned vector)
9547d37d351SJan Kiszka {
9557d37d351SJan Kiszka     VirtIOPCIProxy *proxy = container_of(dev, VirtIOPCIProxy, pci_dev);
956a3fc66d9SPaolo Bonzini     VirtIODevice *vdev = virtio_bus_get_device(&proxy->bus);
957851c2a75SJason Wang     VirtQueue *vq = virtio_vector_first_queue(vdev, vector);
958851c2a75SJason Wang     int index;
9597d37d351SJan Kiszka 
960851c2a75SJason Wang     while (vq) {
961851c2a75SJason Wang         index = virtio_get_queue_index(vq);
962851c2a75SJason Wang         if (!virtio_queue_get_num(vdev, index)) {
9637d37d351SJan Kiszka             break;
9647d37d351SJan Kiszka         }
9656652d081SJason Wang         if (index < proxy->nvqs_with_notifiers) {
966851c2a75SJason Wang             virtio_pci_vq_vector_mask(proxy, index, vector);
9676652d081SJason Wang         }
968851c2a75SJason Wang         vq = virtio_vector_next_queue(vq);
9697d37d351SJan Kiszka     }
9707d37d351SJan Kiszka }
9717d37d351SJan Kiszka 
972a38b2c49SMichael S. Tsirkin static void virtio_pci_vector_poll(PCIDevice *dev,
97389d62be9SMichael S. Tsirkin                                    unsigned int vector_start,
97489d62be9SMichael S. Tsirkin                                    unsigned int vector_end)
97589d62be9SMichael S. Tsirkin {
97689d62be9SMichael S. Tsirkin     VirtIOPCIProxy *proxy = container_of(dev, VirtIOPCIProxy, pci_dev);
977a3fc66d9SPaolo Bonzini     VirtIODevice *vdev = virtio_bus_get_device(&proxy->bus);
978181103cdSKONRAD Frederic     VirtioDeviceClass *k = VIRTIO_DEVICE_GET_CLASS(vdev);
97989d62be9SMichael S. Tsirkin     int queue_no;
98089d62be9SMichael S. Tsirkin     unsigned int vector;
98189d62be9SMichael S. Tsirkin     EventNotifier *notifier;
98289d62be9SMichael S. Tsirkin     VirtQueue *vq;
98389d62be9SMichael S. Tsirkin 
9842d620f59SMichael S. Tsirkin     for (queue_no = 0; queue_no < proxy->nvqs_with_notifiers; queue_no++) {
98589d62be9SMichael S. Tsirkin         if (!virtio_queue_get_num(vdev, queue_no)) {
98689d62be9SMichael S. Tsirkin             break;
98789d62be9SMichael S. Tsirkin         }
98889d62be9SMichael S. Tsirkin         vector = virtio_queue_vector(vdev, queue_no);
98989d62be9SMichael S. Tsirkin         if (vector < vector_start || vector >= vector_end ||
99089d62be9SMichael S. Tsirkin             !msix_is_masked(dev, vector)) {
99189d62be9SMichael S. Tsirkin             continue;
99289d62be9SMichael S. Tsirkin         }
99389d62be9SMichael S. Tsirkin         vq = virtio_get_queue(vdev, queue_no);
99489d62be9SMichael S. Tsirkin         notifier = virtio_queue_get_guest_notifier(vq);
995181103cdSKONRAD Frederic         if (k->guest_notifier_pending) {
996181103cdSKONRAD Frederic             if (k->guest_notifier_pending(vdev, queue_no)) {
997f1d0f15aSMichael S. Tsirkin                 msix_set_pending(dev, vector);
998f1d0f15aSMichael S. Tsirkin             }
999f1d0f15aSMichael S. Tsirkin         } else if (event_notifier_test_and_clear(notifier)) {
100089d62be9SMichael S. Tsirkin             msix_set_pending(dev, vector);
100189d62be9SMichael S. Tsirkin         }
100289d62be9SMichael S. Tsirkin     }
100389d62be9SMichael S. Tsirkin }
100489d62be9SMichael S. Tsirkin 
100589d62be9SMichael S. Tsirkin static int virtio_pci_set_guest_notifier(DeviceState *d, int n, bool assign,
100689d62be9SMichael S. Tsirkin                                          bool with_irqfd)
1007ade80dc8SMichael S. Tsirkin {
1008d2a0ccc6SMichael S. Tsirkin     VirtIOPCIProxy *proxy = to_virtio_pci_proxy(d);
1009a3fc66d9SPaolo Bonzini     VirtIODevice *vdev = virtio_bus_get_device(&proxy->bus);
1010a3fc66d9SPaolo Bonzini     VirtioDeviceClass *vdc = VIRTIO_DEVICE_GET_CLASS(vdev);
1011a3fc66d9SPaolo Bonzini     VirtQueue *vq = virtio_get_queue(vdev, n);
1012ade80dc8SMichael S. Tsirkin     EventNotifier *notifier = virtio_queue_get_guest_notifier(vq);
1013ade80dc8SMichael S. Tsirkin 
1014ade80dc8SMichael S. Tsirkin     if (assign) {
1015ade80dc8SMichael S. Tsirkin         int r = event_notifier_init(notifier, 0);
1016ade80dc8SMichael S. Tsirkin         if (r < 0) {
1017ade80dc8SMichael S. Tsirkin             return r;
1018ade80dc8SMichael S. Tsirkin         }
101989d62be9SMichael S. Tsirkin         virtio_queue_set_guest_notifier_fd_handler(vq, true, with_irqfd);
1020ade80dc8SMichael S. Tsirkin     } else {
102189d62be9SMichael S. Tsirkin         virtio_queue_set_guest_notifier_fd_handler(vq, false, with_irqfd);
1022ade80dc8SMichael S. Tsirkin         event_notifier_cleanup(notifier);
1023ade80dc8SMichael S. Tsirkin     }
1024ade80dc8SMichael S. Tsirkin 
102562c96360SMichael S. Tsirkin     if (!msix_enabled(&proxy->pci_dev) && vdc->guest_notifier_mask) {
1026a3fc66d9SPaolo Bonzini         vdc->guest_notifier_mask(vdev, n, !assign);
102762c96360SMichael S. Tsirkin     }
102862c96360SMichael S. Tsirkin 
1029ade80dc8SMichael S. Tsirkin     return 0;
1030ade80dc8SMichael S. Tsirkin }
1031ade80dc8SMichael S. Tsirkin 
1032d2a0ccc6SMichael S. Tsirkin static bool virtio_pci_query_guest_notifiers(DeviceState *d)
10335430a28fSmst@redhat.com {
1034d2a0ccc6SMichael S. Tsirkin     VirtIOPCIProxy *proxy = to_virtio_pci_proxy(d);
10355430a28fSmst@redhat.com     return msix_enabled(&proxy->pci_dev);
10365430a28fSmst@redhat.com }
10375430a28fSmst@redhat.com 
10382d620f59SMichael S. Tsirkin static int virtio_pci_set_guest_notifiers(DeviceState *d, int nvqs, bool assign)
103954dd9321SMichael S. Tsirkin {
1040d2a0ccc6SMichael S. Tsirkin     VirtIOPCIProxy *proxy = to_virtio_pci_proxy(d);
1041a3fc66d9SPaolo Bonzini     VirtIODevice *vdev = virtio_bus_get_device(&proxy->bus);
1042181103cdSKONRAD Frederic     VirtioDeviceClass *k = VIRTIO_DEVICE_GET_CLASS(vdev);
104354dd9321SMichael S. Tsirkin     int r, n;
104489d62be9SMichael S. Tsirkin     bool with_irqfd = msix_enabled(&proxy->pci_dev) &&
104589d62be9SMichael S. Tsirkin         kvm_msi_via_irqfd_enabled();
104654dd9321SMichael S. Tsirkin 
104787b3bd1cSJason Wang     nvqs = MIN(nvqs, VIRTIO_QUEUE_MAX);
10482d620f59SMichael S. Tsirkin 
10492d620f59SMichael S. Tsirkin     /* When deassigning, pass a consistent nvqs value
10502d620f59SMichael S. Tsirkin      * to avoid leaking notifiers.
10512d620f59SMichael S. Tsirkin      */
10522d620f59SMichael S. Tsirkin     assert(assign || nvqs == proxy->nvqs_with_notifiers);
10532d620f59SMichael S. Tsirkin 
10542d620f59SMichael S. Tsirkin     proxy->nvqs_with_notifiers = nvqs;
10552d620f59SMichael S. Tsirkin 
10567d37d351SJan Kiszka     /* Must unset vector notifier while guest notifier is still assigned */
1057181103cdSKONRAD Frederic     if ((proxy->vector_irqfd || k->guest_notifier_mask) && !assign) {
10587d37d351SJan Kiszka         msix_unset_vector_notifiers(&proxy->pci_dev);
1059a38b2c49SMichael S. Tsirkin         if (proxy->vector_irqfd) {
1060774345f9SMichael S. Tsirkin             kvm_virtio_pci_vector_release(proxy, nvqs);
10617d37d351SJan Kiszka             g_free(proxy->vector_irqfd);
10627d37d351SJan Kiszka             proxy->vector_irqfd = NULL;
10637d37d351SJan Kiszka         }
1064a38b2c49SMichael S. Tsirkin     }
10657d37d351SJan Kiszka 
10662d620f59SMichael S. Tsirkin     for (n = 0; n < nvqs; n++) {
106754dd9321SMichael S. Tsirkin         if (!virtio_queue_get_num(vdev, n)) {
106854dd9321SMichael S. Tsirkin             break;
106954dd9321SMichael S. Tsirkin         }
107054dd9321SMichael S. Tsirkin 
107123fe2b3fSMichael S. Tsirkin         r = virtio_pci_set_guest_notifier(d, n, assign, with_irqfd);
107254dd9321SMichael S. Tsirkin         if (r < 0) {
107354dd9321SMichael S. Tsirkin             goto assign_error;
107454dd9321SMichael S. Tsirkin         }
107554dd9321SMichael S. Tsirkin     }
107654dd9321SMichael S. Tsirkin 
10777d37d351SJan Kiszka     /* Must set vector notifier after guest notifier has been assigned */
1078181103cdSKONRAD Frederic     if ((with_irqfd || k->guest_notifier_mask) && assign) {
1079a38b2c49SMichael S. Tsirkin         if (with_irqfd) {
10807d37d351SJan Kiszka             proxy->vector_irqfd =
10817d37d351SJan Kiszka                 g_malloc0(sizeof(*proxy->vector_irqfd) *
10827d37d351SJan Kiszka                           msix_nr_vectors_allocated(&proxy->pci_dev));
1083774345f9SMichael S. Tsirkin             r = kvm_virtio_pci_vector_use(proxy, nvqs);
10847d37d351SJan Kiszka             if (r < 0) {
10857d37d351SJan Kiszka                 goto assign_error;
10867d37d351SJan Kiszka             }
1087a38b2c49SMichael S. Tsirkin         }
1088774345f9SMichael S. Tsirkin         r = msix_set_vector_notifiers(&proxy->pci_dev,
1089a38b2c49SMichael S. Tsirkin                                       virtio_pci_vector_unmask,
1090a38b2c49SMichael S. Tsirkin                                       virtio_pci_vector_mask,
1091a38b2c49SMichael S. Tsirkin                                       virtio_pci_vector_poll);
1092774345f9SMichael S. Tsirkin         if (r < 0) {
1093774345f9SMichael S. Tsirkin             goto notifiers_error;
1094774345f9SMichael S. Tsirkin         }
10957d37d351SJan Kiszka     }
10967d37d351SJan Kiszka 
109754dd9321SMichael S. Tsirkin     return 0;
109854dd9321SMichael S. Tsirkin 
1099774345f9SMichael S. Tsirkin notifiers_error:
1100a38b2c49SMichael S. Tsirkin     if (with_irqfd) {
1101774345f9SMichael S. Tsirkin         assert(assign);
1102774345f9SMichael S. Tsirkin         kvm_virtio_pci_vector_release(proxy, nvqs);
1103a38b2c49SMichael S. Tsirkin     }
1104774345f9SMichael S. Tsirkin 
110554dd9321SMichael S. Tsirkin assign_error:
110654dd9321SMichael S. Tsirkin     /* We get here on assignment failure. Recover by undoing for VQs 0 .. n. */
11077d37d351SJan Kiszka     assert(assign);
110854dd9321SMichael S. Tsirkin     while (--n >= 0) {
110989d62be9SMichael S. Tsirkin         virtio_pci_set_guest_notifier(d, n, !assign, with_irqfd);
111054dd9321SMichael S. Tsirkin     }
111154dd9321SMichael S. Tsirkin     return r;
111254dd9321SMichael S. Tsirkin }
111354dd9321SMichael S. Tsirkin 
1114d2a0ccc6SMichael S. Tsirkin static int virtio_pci_set_host_notifier(DeviceState *d, int n, bool assign)
1115ade80dc8SMichael S. Tsirkin {
1116d2a0ccc6SMichael S. Tsirkin     VirtIOPCIProxy *proxy = to_virtio_pci_proxy(d);
111725db9ebeSStefan Hajnoczi 
111825db9ebeSStefan Hajnoczi     /* Stop using ioeventfd for virtqueue kick if the device starts using host
111925db9ebeSStefan Hajnoczi      * notifiers.  This makes it easy to avoid stepping on each others' toes.
112025db9ebeSStefan Hajnoczi      */
112125db9ebeSStefan Hajnoczi     proxy->ioeventfd_disabled = assign;
1122ade80dc8SMichael S. Tsirkin     if (assign) {
112325db9ebeSStefan Hajnoczi         virtio_pci_stop_ioeventfd(proxy);
1124ade80dc8SMichael S. Tsirkin     }
112525db9ebeSStefan Hajnoczi     /* We don't need to start here: it's not needed because backend
112625db9ebeSStefan Hajnoczi      * currently only stops on status change away from ok,
112725db9ebeSStefan Hajnoczi      * reset, vmstop and such. If we do add code to start here,
112825db9ebeSStefan Hajnoczi      * need to check vmstate, device state etc. */
112926b9b5feSPaolo Bonzini     return virtio_pci_set_host_notifier_internal(proxy, n, assign, false);
1130ade80dc8SMichael S. Tsirkin }
113125db9ebeSStefan Hajnoczi 
1132d2a0ccc6SMichael S. Tsirkin static void virtio_pci_vmstate_change(DeviceState *d, bool running)
113325db9ebeSStefan Hajnoczi {
1134d2a0ccc6SMichael S. Tsirkin     VirtIOPCIProxy *proxy = to_virtio_pci_proxy(d);
1135a3fc66d9SPaolo Bonzini     VirtIODevice *vdev = virtio_bus_get_device(&proxy->bus);
113625db9ebeSStefan Hajnoczi 
113725db9ebeSStefan Hajnoczi     if (running) {
113868a27b20SMichael S. Tsirkin         /* Old QEMU versions did not set bus master enable on status write.
113968a27b20SMichael S. Tsirkin          * Detect DRIVER set and enable it.
114068a27b20SMichael S. Tsirkin          */
114168a27b20SMichael S. Tsirkin         if ((proxy->flags & VIRTIO_PCI_FLAG_BUS_MASTER_BUG_MIGRATION) &&
114268a27b20SMichael S. Tsirkin             (vdev->status & VIRTIO_CONFIG_S_DRIVER) &&
114345363e46SMichael S. Tsirkin             !(proxy->pci_dev.config[PCI_COMMAND] & PCI_COMMAND_MASTER)) {
114468a27b20SMichael S. Tsirkin             pci_default_write_config(&proxy->pci_dev, PCI_COMMAND,
114568a27b20SMichael S. Tsirkin                                      proxy->pci_dev.config[PCI_COMMAND] |
114668a27b20SMichael S. Tsirkin                                      PCI_COMMAND_MASTER, 1);
114789c473fdSMichael S. Tsirkin         }
114825db9ebeSStefan Hajnoczi         virtio_pci_start_ioeventfd(proxy);
1149ade80dc8SMichael S. Tsirkin     } else {
115025db9ebeSStefan Hajnoczi         virtio_pci_stop_ioeventfd(proxy);
1151ade80dc8SMichael S. Tsirkin     }
1152ade80dc8SMichael S. Tsirkin }
1153ade80dc8SMichael S. Tsirkin 
115460653b28SPaolo Bonzini #ifdef CONFIG_VIRTFS
1155fc079951SMarkus Armbruster static void virtio_9p_pci_realize(VirtIOPCIProxy *vpci_dev, Error **errp)
115660653b28SPaolo Bonzini {
1157234a336fSKONRAD Frederic     V9fsPCIState *dev = VIRTIO_9P_PCI(vpci_dev);
1158234a336fSKONRAD Frederic     DeviceState *vdev = DEVICE(&dev->vdev);
115960653b28SPaolo Bonzini 
1160234a336fSKONRAD Frederic     qdev_set_parent_bus(vdev, BUS(&vpci_dev->bus));
1161fc079951SMarkus Armbruster     object_property_set_bool(OBJECT(vdev), true, "realized", errp);
116260653b28SPaolo Bonzini }
116360653b28SPaolo Bonzini 
1164234a336fSKONRAD Frederic static Property virtio_9p_pci_properties[] = {
1165234a336fSKONRAD Frederic     DEFINE_PROP_BIT("ioeventfd", VirtIOPCIProxy, flags,
1166234a336fSKONRAD Frederic                     VIRTIO_PCI_FLAG_USE_IOEVENTFD_BIT, true),
116760653b28SPaolo Bonzini     DEFINE_PROP_UINT32("vectors", VirtIOPCIProxy, nvectors, 2),
116860653b28SPaolo Bonzini     DEFINE_PROP_END_OF_LIST(),
116960653b28SPaolo Bonzini };
117060653b28SPaolo Bonzini 
1171234a336fSKONRAD Frederic static void virtio_9p_pci_class_init(ObjectClass *klass, void *data)
117260653b28SPaolo Bonzini {
117360653b28SPaolo Bonzini     DeviceClass *dc = DEVICE_CLASS(klass);
1174234a336fSKONRAD Frederic     PCIDeviceClass *pcidev_k = PCI_DEVICE_CLASS(klass);
1175234a336fSKONRAD Frederic     VirtioPCIClass *k = VIRTIO_PCI_CLASS(klass);
117660653b28SPaolo Bonzini 
1177fc079951SMarkus Armbruster     k->realize = virtio_9p_pci_realize;
1178234a336fSKONRAD Frederic     pcidev_k->vendor_id = PCI_VENDOR_ID_REDHAT_QUMRANET;
1179234a336fSKONRAD Frederic     pcidev_k->device_id = PCI_DEVICE_ID_VIRTIO_9P;
1180234a336fSKONRAD Frederic     pcidev_k->revision = VIRTIO_PCI_ABI_VERSION;
1181234a336fSKONRAD Frederic     pcidev_k->class_id = 0x2;
1182125ee0edSMarcel Apfelbaum     set_bit(DEVICE_CATEGORY_STORAGE, dc->categories);
1183234a336fSKONRAD Frederic     dc->props = virtio_9p_pci_properties;
118460653b28SPaolo Bonzini }
118560653b28SPaolo Bonzini 
1186234a336fSKONRAD Frederic static void virtio_9p_pci_instance_init(Object *obj)
1187234a336fSKONRAD Frederic {
1188234a336fSKONRAD Frederic     V9fsPCIState *dev = VIRTIO_9P_PCI(obj);
1189c8075cafSGonglei 
1190c8075cafSGonglei     virtio_instance_init_common(obj, &dev->vdev, sizeof(dev->vdev),
1191c8075cafSGonglei                                 TYPE_VIRTIO_9P);
1192234a336fSKONRAD Frederic }
1193234a336fSKONRAD Frederic 
1194234a336fSKONRAD Frederic static const TypeInfo virtio_9p_pci_info = {
1195234a336fSKONRAD Frederic     .name          = TYPE_VIRTIO_9P_PCI,
1196234a336fSKONRAD Frederic     .parent        = TYPE_VIRTIO_PCI,
1197234a336fSKONRAD Frederic     .instance_size = sizeof(V9fsPCIState),
1198234a336fSKONRAD Frederic     .instance_init = virtio_9p_pci_instance_init,
1199234a336fSKONRAD Frederic     .class_init    = virtio_9p_pci_class_init,
120060653b28SPaolo Bonzini };
1201234a336fSKONRAD Frederic #endif /* CONFIG_VIRTFS */
120260653b28SPaolo Bonzini 
1203085bccb7SKONRAD Frederic /*
1204085bccb7SKONRAD Frederic  * virtio-pci: This is the PCIDevice which has a virtio-pci-bus.
1205085bccb7SKONRAD Frederic  */
1206085bccb7SKONRAD Frederic 
1207e0d686bfSJason Wang static int virtio_pci_query_nvectors(DeviceState *d)
1208e0d686bfSJason Wang {
1209e0d686bfSJason Wang     VirtIOPCIProxy *proxy = VIRTIO_PCI(d);
1210e0d686bfSJason Wang 
1211e0d686bfSJason Wang     return proxy->nvectors;
1212e0d686bfSJason Wang }
1213e0d686bfSJason Wang 
1214ada434cdSMichael S. Tsirkin static int virtio_pci_add_mem_cap(VirtIOPCIProxy *proxy,
1215dfb8e184SMichael S. Tsirkin                                    struct virtio_pci_cap *cap)
1216dfb8e184SMichael S. Tsirkin {
1217dfb8e184SMichael S. Tsirkin     PCIDevice *dev = &proxy->pci_dev;
1218dfb8e184SMichael S. Tsirkin     int offset;
1219dfb8e184SMichael S. Tsirkin 
1220dfb8e184SMichael S. Tsirkin     offset = pci_add_capability(dev, PCI_CAP_ID_VNDR, 0, cap->cap_len);
1221dfb8e184SMichael S. Tsirkin     assert(offset > 0);
1222dfb8e184SMichael S. Tsirkin 
1223dfb8e184SMichael S. Tsirkin     assert(cap->cap_len >= sizeof *cap);
1224dfb8e184SMichael S. Tsirkin     memcpy(dev->config + offset + PCI_CAP_FLAGS, &cap->cap_len,
1225dfb8e184SMichael S. Tsirkin            cap->cap_len - PCI_CAP_FLAGS);
1226ada434cdSMichael S. Tsirkin 
1227ada434cdSMichael S. Tsirkin     return offset;
1228dfb8e184SMichael S. Tsirkin }
1229dfb8e184SMichael S. Tsirkin 
1230dfb8e184SMichael S. Tsirkin static uint64_t virtio_pci_common_read(void *opaque, hwaddr addr,
1231dfb8e184SMichael S. Tsirkin                                        unsigned size)
1232dfb8e184SMichael S. Tsirkin {
1233dfb8e184SMichael S. Tsirkin     VirtIOPCIProxy *proxy = opaque;
1234dfb8e184SMichael S. Tsirkin     VirtIODevice *vdev = virtio_bus_get_device(&proxy->bus);
1235dfb8e184SMichael S. Tsirkin     uint32_t val = 0;
1236dfb8e184SMichael S. Tsirkin     int i;
1237dfb8e184SMichael S. Tsirkin 
1238dfb8e184SMichael S. Tsirkin     switch (addr) {
1239dfb8e184SMichael S. Tsirkin     case VIRTIO_PCI_COMMON_DFSELECT:
1240dfb8e184SMichael S. Tsirkin         val = proxy->dfselect;
1241dfb8e184SMichael S. Tsirkin         break;
1242dfb8e184SMichael S. Tsirkin     case VIRTIO_PCI_COMMON_DF:
1243dfb8e184SMichael S. Tsirkin         if (proxy->dfselect <= 1) {
12445f456073SMichael S. Tsirkin             val = (vdev->host_features & ~VIRTIO_LEGACY_FEATURES) >>
12455f456073SMichael S. Tsirkin                 (32 * proxy->dfselect);
1246dfb8e184SMichael S. Tsirkin         }
1247dfb8e184SMichael S. Tsirkin         break;
1248dfb8e184SMichael S. Tsirkin     case VIRTIO_PCI_COMMON_GFSELECT:
1249dfb8e184SMichael S. Tsirkin         val = proxy->gfselect;
1250dfb8e184SMichael S. Tsirkin         break;
1251dfb8e184SMichael S. Tsirkin     case VIRTIO_PCI_COMMON_GF:
12523750dabcSGonglei         if (proxy->gfselect < ARRAY_SIZE(proxy->guest_features)) {
1253dfb8e184SMichael S. Tsirkin             val = proxy->guest_features[proxy->gfselect];
1254dfb8e184SMichael S. Tsirkin         }
1255dfb8e184SMichael S. Tsirkin         break;
1256dfb8e184SMichael S. Tsirkin     case VIRTIO_PCI_COMMON_MSIX:
1257dfb8e184SMichael S. Tsirkin         val = vdev->config_vector;
1258dfb8e184SMichael S. Tsirkin         break;
1259dfb8e184SMichael S. Tsirkin     case VIRTIO_PCI_COMMON_NUMQ:
1260dfb8e184SMichael S. Tsirkin         for (i = 0; i < VIRTIO_QUEUE_MAX; ++i) {
1261dfb8e184SMichael S. Tsirkin             if (virtio_queue_get_num(vdev, i)) {
1262dfb8e184SMichael S. Tsirkin                 val = i + 1;
1263dfb8e184SMichael S. Tsirkin             }
1264dfb8e184SMichael S. Tsirkin         }
1265dfb8e184SMichael S. Tsirkin         break;
1266dfb8e184SMichael S. Tsirkin     case VIRTIO_PCI_COMMON_STATUS:
1267dfb8e184SMichael S. Tsirkin         val = vdev->status;
1268dfb8e184SMichael S. Tsirkin         break;
1269dfb8e184SMichael S. Tsirkin     case VIRTIO_PCI_COMMON_CFGGENERATION:
1270b8f05908SMichael S. Tsirkin         val = vdev->generation;
1271dfb8e184SMichael S. Tsirkin         break;
1272dfb8e184SMichael S. Tsirkin     case VIRTIO_PCI_COMMON_Q_SELECT:
1273dfb8e184SMichael S. Tsirkin         val = vdev->queue_sel;
1274dfb8e184SMichael S. Tsirkin         break;
1275dfb8e184SMichael S. Tsirkin     case VIRTIO_PCI_COMMON_Q_SIZE:
1276dfb8e184SMichael S. Tsirkin         val = virtio_queue_get_num(vdev, vdev->queue_sel);
1277dfb8e184SMichael S. Tsirkin         break;
1278dfb8e184SMichael S. Tsirkin     case VIRTIO_PCI_COMMON_Q_MSIX:
1279dfb8e184SMichael S. Tsirkin         val = virtio_queue_vector(vdev, vdev->queue_sel);
1280dfb8e184SMichael S. Tsirkin         break;
1281dfb8e184SMichael S. Tsirkin     case VIRTIO_PCI_COMMON_Q_ENABLE:
1282dfb8e184SMichael S. Tsirkin         val = proxy->vqs[vdev->queue_sel].enabled;
1283dfb8e184SMichael S. Tsirkin         break;
1284dfb8e184SMichael S. Tsirkin     case VIRTIO_PCI_COMMON_Q_NOFF:
1285dfb8e184SMichael S. Tsirkin         /* Simply map queues in order */
1286dfb8e184SMichael S. Tsirkin         val = vdev->queue_sel;
1287dfb8e184SMichael S. Tsirkin         break;
1288dfb8e184SMichael S. Tsirkin     case VIRTIO_PCI_COMMON_Q_DESCLO:
1289dfb8e184SMichael S. Tsirkin         val = proxy->vqs[vdev->queue_sel].desc[0];
1290dfb8e184SMichael S. Tsirkin         break;
1291dfb8e184SMichael S. Tsirkin     case VIRTIO_PCI_COMMON_Q_DESCHI:
1292dfb8e184SMichael S. Tsirkin         val = proxy->vqs[vdev->queue_sel].desc[1];
1293dfb8e184SMichael S. Tsirkin         break;
1294dfb8e184SMichael S. Tsirkin     case VIRTIO_PCI_COMMON_Q_AVAILLO:
1295dfb8e184SMichael S. Tsirkin         val = proxy->vqs[vdev->queue_sel].avail[0];
1296dfb8e184SMichael S. Tsirkin         break;
1297dfb8e184SMichael S. Tsirkin     case VIRTIO_PCI_COMMON_Q_AVAILHI:
1298dfb8e184SMichael S. Tsirkin         val = proxy->vqs[vdev->queue_sel].avail[1];
1299dfb8e184SMichael S. Tsirkin         break;
1300dfb8e184SMichael S. Tsirkin     case VIRTIO_PCI_COMMON_Q_USEDLO:
1301dfb8e184SMichael S. Tsirkin         val = proxy->vqs[vdev->queue_sel].used[0];
1302dfb8e184SMichael S. Tsirkin         break;
1303dfb8e184SMichael S. Tsirkin     case VIRTIO_PCI_COMMON_Q_USEDHI:
1304dfb8e184SMichael S. Tsirkin         val = proxy->vqs[vdev->queue_sel].used[1];
1305dfb8e184SMichael S. Tsirkin         break;
1306dfb8e184SMichael S. Tsirkin     default:
1307dfb8e184SMichael S. Tsirkin         val = 0;
1308dfb8e184SMichael S. Tsirkin     }
1309dfb8e184SMichael S. Tsirkin 
1310dfb8e184SMichael S. Tsirkin     return val;
1311dfb8e184SMichael S. Tsirkin }
1312dfb8e184SMichael S. Tsirkin 
1313dfb8e184SMichael S. Tsirkin static void virtio_pci_common_write(void *opaque, hwaddr addr,
1314dfb8e184SMichael S. Tsirkin                                     uint64_t val, unsigned size)
1315dfb8e184SMichael S. Tsirkin {
1316dfb8e184SMichael S. Tsirkin     VirtIOPCIProxy *proxy = opaque;
1317dfb8e184SMichael S. Tsirkin     VirtIODevice *vdev = virtio_bus_get_device(&proxy->bus);
1318dfb8e184SMichael S. Tsirkin 
1319dfb8e184SMichael S. Tsirkin     switch (addr) {
1320dfb8e184SMichael S. Tsirkin     case VIRTIO_PCI_COMMON_DFSELECT:
1321dfb8e184SMichael S. Tsirkin         proxy->dfselect = val;
1322dfb8e184SMichael S. Tsirkin         break;
1323dfb8e184SMichael S. Tsirkin     case VIRTIO_PCI_COMMON_GFSELECT:
1324dfb8e184SMichael S. Tsirkin         proxy->gfselect = val;
1325dfb8e184SMichael S. Tsirkin         break;
1326dfb8e184SMichael S. Tsirkin     case VIRTIO_PCI_COMMON_GF:
13273750dabcSGonglei         if (proxy->gfselect < ARRAY_SIZE(proxy->guest_features)) {
1328dfb8e184SMichael S. Tsirkin             proxy->guest_features[proxy->gfselect] = val;
1329dfb8e184SMichael S. Tsirkin             virtio_set_features(vdev,
1330dfb8e184SMichael S. Tsirkin                                 (((uint64_t)proxy->guest_features[1]) << 32) |
1331dfb8e184SMichael S. Tsirkin                                 proxy->guest_features[0]);
1332dfb8e184SMichael S. Tsirkin         }
1333dfb8e184SMichael S. Tsirkin         break;
1334dfb8e184SMichael S. Tsirkin     case VIRTIO_PCI_COMMON_MSIX:
1335dfb8e184SMichael S. Tsirkin         msix_vector_unuse(&proxy->pci_dev, vdev->config_vector);
1336dfb8e184SMichael S. Tsirkin         /* Make it possible for guest to discover an error took place. */
1337dfb8e184SMichael S. Tsirkin         if (msix_vector_use(&proxy->pci_dev, val) < 0) {
1338dfb8e184SMichael S. Tsirkin             val = VIRTIO_NO_VECTOR;
1339dfb8e184SMichael S. Tsirkin         }
1340dfb8e184SMichael S. Tsirkin         vdev->config_vector = val;
1341dfb8e184SMichael S. Tsirkin         break;
1342dfb8e184SMichael S. Tsirkin     case VIRTIO_PCI_COMMON_STATUS:
1343dfb8e184SMichael S. Tsirkin         if (!(val & VIRTIO_CONFIG_S_DRIVER_OK)) {
1344dfb8e184SMichael S. Tsirkin             virtio_pci_stop_ioeventfd(proxy);
1345dfb8e184SMichael S. Tsirkin         }
1346dfb8e184SMichael S. Tsirkin 
1347dfb8e184SMichael S. Tsirkin         virtio_set_status(vdev, val & 0xFF);
1348dfb8e184SMichael S. Tsirkin 
1349dfb8e184SMichael S. Tsirkin         if (val & VIRTIO_CONFIG_S_DRIVER_OK) {
1350dfb8e184SMichael S. Tsirkin             virtio_pci_start_ioeventfd(proxy);
1351dfb8e184SMichael S. Tsirkin         }
1352dfb8e184SMichael S. Tsirkin 
1353dfb8e184SMichael S. Tsirkin         if (vdev->status == 0) {
1354dfb8e184SMichael S. Tsirkin             virtio_reset(vdev);
1355dfb8e184SMichael S. Tsirkin             msix_unuse_all_vectors(&proxy->pci_dev);
1356dfb8e184SMichael S. Tsirkin         }
1357dfb8e184SMichael S. Tsirkin 
1358dfb8e184SMichael S. Tsirkin         break;
1359dfb8e184SMichael S. Tsirkin     case VIRTIO_PCI_COMMON_Q_SELECT:
1360dfb8e184SMichael S. Tsirkin         if (val < VIRTIO_QUEUE_MAX) {
1361dfb8e184SMichael S. Tsirkin             vdev->queue_sel = val;
1362dfb8e184SMichael S. Tsirkin         }
1363dfb8e184SMichael S. Tsirkin         break;
1364dfb8e184SMichael S. Tsirkin     case VIRTIO_PCI_COMMON_Q_SIZE:
1365dfb8e184SMichael S. Tsirkin         proxy->vqs[vdev->queue_sel].num = val;
1366dfb8e184SMichael S. Tsirkin         break;
1367dfb8e184SMichael S. Tsirkin     case VIRTIO_PCI_COMMON_Q_MSIX:
1368dfb8e184SMichael S. Tsirkin         msix_vector_unuse(&proxy->pci_dev,
1369dfb8e184SMichael S. Tsirkin                           virtio_queue_vector(vdev, vdev->queue_sel));
1370dfb8e184SMichael S. Tsirkin         /* Make it possible for guest to discover an error took place. */
1371dfb8e184SMichael S. Tsirkin         if (msix_vector_use(&proxy->pci_dev, val) < 0) {
1372dfb8e184SMichael S. Tsirkin             val = VIRTIO_NO_VECTOR;
1373dfb8e184SMichael S. Tsirkin         }
1374dfb8e184SMichael S. Tsirkin         virtio_queue_set_vector(vdev, vdev->queue_sel, val);
1375dfb8e184SMichael S. Tsirkin         break;
1376dfb8e184SMichael S. Tsirkin     case VIRTIO_PCI_COMMON_Q_ENABLE:
1377dfb8e184SMichael S. Tsirkin         /* TODO: need a way to put num back on reset. */
1378dfb8e184SMichael S. Tsirkin         virtio_queue_set_num(vdev, vdev->queue_sel,
1379dfb8e184SMichael S. Tsirkin                              proxy->vqs[vdev->queue_sel].num);
1380dfb8e184SMichael S. Tsirkin         virtio_queue_set_rings(vdev, vdev->queue_sel,
1381dfb8e184SMichael S. Tsirkin                        ((uint64_t)proxy->vqs[vdev->queue_sel].desc[1]) << 32 |
1382dfb8e184SMichael S. Tsirkin                        proxy->vqs[vdev->queue_sel].desc[0],
1383dfb8e184SMichael S. Tsirkin                        ((uint64_t)proxy->vqs[vdev->queue_sel].avail[1]) << 32 |
1384dfb8e184SMichael S. Tsirkin                        proxy->vqs[vdev->queue_sel].avail[0],
1385dfb8e184SMichael S. Tsirkin                        ((uint64_t)proxy->vqs[vdev->queue_sel].used[1]) << 32 |
1386dfb8e184SMichael S. Tsirkin                        proxy->vqs[vdev->queue_sel].used[0]);
1387dfb8e184SMichael S. Tsirkin         break;
1388dfb8e184SMichael S. Tsirkin     case VIRTIO_PCI_COMMON_Q_DESCLO:
1389dfb8e184SMichael S. Tsirkin         proxy->vqs[vdev->queue_sel].desc[0] = val;
1390dfb8e184SMichael S. Tsirkin         break;
1391dfb8e184SMichael S. Tsirkin     case VIRTIO_PCI_COMMON_Q_DESCHI:
1392dfb8e184SMichael S. Tsirkin         proxy->vqs[vdev->queue_sel].desc[1] = val;
1393dfb8e184SMichael S. Tsirkin         break;
1394dfb8e184SMichael S. Tsirkin     case VIRTIO_PCI_COMMON_Q_AVAILLO:
1395dfb8e184SMichael S. Tsirkin         proxy->vqs[vdev->queue_sel].avail[0] = val;
1396dfb8e184SMichael S. Tsirkin         break;
1397dfb8e184SMichael S. Tsirkin     case VIRTIO_PCI_COMMON_Q_AVAILHI:
1398dfb8e184SMichael S. Tsirkin         proxy->vqs[vdev->queue_sel].avail[1] = val;
1399dfb8e184SMichael S. Tsirkin         break;
1400dfb8e184SMichael S. Tsirkin     case VIRTIO_PCI_COMMON_Q_USEDLO:
1401dfb8e184SMichael S. Tsirkin         proxy->vqs[vdev->queue_sel].used[0] = val;
1402dfb8e184SMichael S. Tsirkin         break;
1403dfb8e184SMichael S. Tsirkin     case VIRTIO_PCI_COMMON_Q_USEDHI:
1404dfb8e184SMichael S. Tsirkin         proxy->vqs[vdev->queue_sel].used[1] = val;
1405dfb8e184SMichael S. Tsirkin         break;
1406dfb8e184SMichael S. Tsirkin     default:
1407dfb8e184SMichael S. Tsirkin         break;
1408dfb8e184SMichael S. Tsirkin     }
1409dfb8e184SMichael S. Tsirkin }
1410dfb8e184SMichael S. Tsirkin 
1411dfb8e184SMichael S. Tsirkin 
1412dfb8e184SMichael S. Tsirkin static uint64_t virtio_pci_notify_read(void *opaque, hwaddr addr,
1413dfb8e184SMichael S. Tsirkin                                        unsigned size)
1414dfb8e184SMichael S. Tsirkin {
1415dfb8e184SMichael S. Tsirkin     return 0;
1416dfb8e184SMichael S. Tsirkin }
1417dfb8e184SMichael S. Tsirkin 
1418dfb8e184SMichael S. Tsirkin static void virtio_pci_notify_write(void *opaque, hwaddr addr,
1419dfb8e184SMichael S. Tsirkin                                     uint64_t val, unsigned size)
1420dfb8e184SMichael S. Tsirkin {
1421dfb8e184SMichael S. Tsirkin     VirtIODevice *vdev = opaque;
1422dfb8e184SMichael S. Tsirkin     unsigned queue = addr / QEMU_VIRTIO_PCI_QUEUE_MEM_MULT;
1423dfb8e184SMichael S. Tsirkin 
1424dfb8e184SMichael S. Tsirkin     if (queue < VIRTIO_QUEUE_MAX) {
1425dfb8e184SMichael S. Tsirkin         virtio_queue_notify(vdev, queue);
1426dfb8e184SMichael S. Tsirkin     }
1427dfb8e184SMichael S. Tsirkin }
1428dfb8e184SMichael S. Tsirkin 
1429*9824d2a3SJason Wang static void virtio_pci_notify_write_pio(void *opaque, hwaddr addr,
1430*9824d2a3SJason Wang                                         uint64_t val, unsigned size)
1431*9824d2a3SJason Wang {
1432*9824d2a3SJason Wang     VirtIODevice *vdev = opaque;
1433*9824d2a3SJason Wang     unsigned queue = val;
1434*9824d2a3SJason Wang 
1435*9824d2a3SJason Wang     if (queue < VIRTIO_QUEUE_MAX) {
1436*9824d2a3SJason Wang         virtio_queue_notify(vdev, queue);
1437*9824d2a3SJason Wang     }
1438*9824d2a3SJason Wang }
1439*9824d2a3SJason Wang 
1440dfb8e184SMichael S. Tsirkin static uint64_t virtio_pci_isr_read(void *opaque, hwaddr addr,
1441dfb8e184SMichael S. Tsirkin                                     unsigned size)
1442dfb8e184SMichael S. Tsirkin {
1443dfb8e184SMichael S. Tsirkin     VirtIOPCIProxy *proxy = opaque;
1444dfb8e184SMichael S. Tsirkin     VirtIODevice *vdev = virtio_bus_get_device(&proxy->bus);
1445dfb8e184SMichael S. Tsirkin     uint64_t val = vdev->isr;
1446dfb8e184SMichael S. Tsirkin 
1447dfb8e184SMichael S. Tsirkin     vdev->isr = 0;
1448dfb8e184SMichael S. Tsirkin     pci_irq_deassert(&proxy->pci_dev);
1449dfb8e184SMichael S. Tsirkin 
1450dfb8e184SMichael S. Tsirkin     return val;
1451dfb8e184SMichael S. Tsirkin }
1452dfb8e184SMichael S. Tsirkin 
1453dfb8e184SMichael S. Tsirkin static void virtio_pci_isr_write(void *opaque, hwaddr addr,
1454dfb8e184SMichael S. Tsirkin                                  uint64_t val, unsigned size)
1455dfb8e184SMichael S. Tsirkin {
1456dfb8e184SMichael S. Tsirkin }
1457dfb8e184SMichael S. Tsirkin 
1458dfb8e184SMichael S. Tsirkin static uint64_t virtio_pci_device_read(void *opaque, hwaddr addr,
1459dfb8e184SMichael S. Tsirkin                                        unsigned size)
1460dfb8e184SMichael S. Tsirkin {
1461dfb8e184SMichael S. Tsirkin     VirtIODevice *vdev = opaque;
1462dfb8e184SMichael S. Tsirkin     uint64_t val = 0;
1463dfb8e184SMichael S. Tsirkin 
1464dfb8e184SMichael S. Tsirkin     switch (size) {
1465dfb8e184SMichael S. Tsirkin     case 1:
146654c720d4SMichael S. Tsirkin         val = virtio_config_modern_readb(vdev, addr);
1467dfb8e184SMichael S. Tsirkin         break;
1468dfb8e184SMichael S. Tsirkin     case 2:
146954c720d4SMichael S. Tsirkin         val = virtio_config_modern_readw(vdev, addr);
1470dfb8e184SMichael S. Tsirkin         break;
1471dfb8e184SMichael S. Tsirkin     case 4:
147254c720d4SMichael S. Tsirkin         val = virtio_config_modern_readl(vdev, addr);
1473dfb8e184SMichael S. Tsirkin         break;
1474dfb8e184SMichael S. Tsirkin     }
1475dfb8e184SMichael S. Tsirkin     return val;
1476dfb8e184SMichael S. Tsirkin }
1477dfb8e184SMichael S. Tsirkin 
1478dfb8e184SMichael S. Tsirkin static void virtio_pci_device_write(void *opaque, hwaddr addr,
1479dfb8e184SMichael S. Tsirkin                                     uint64_t val, unsigned size)
1480dfb8e184SMichael S. Tsirkin {
1481dfb8e184SMichael S. Tsirkin     VirtIODevice *vdev = opaque;
1482dfb8e184SMichael S. Tsirkin     switch (size) {
1483dfb8e184SMichael S. Tsirkin     case 1:
148454c720d4SMichael S. Tsirkin         virtio_config_modern_writeb(vdev, addr, val);
1485dfb8e184SMichael S. Tsirkin         break;
1486dfb8e184SMichael S. Tsirkin     case 2:
148754c720d4SMichael S. Tsirkin         virtio_config_modern_writew(vdev, addr, val);
1488dfb8e184SMichael S. Tsirkin         break;
1489dfb8e184SMichael S. Tsirkin     case 4:
149054c720d4SMichael S. Tsirkin         virtio_config_modern_writel(vdev, addr, val);
1491dfb8e184SMichael S. Tsirkin         break;
1492dfb8e184SMichael S. Tsirkin     }
1493dfb8e184SMichael S. Tsirkin }
1494dfb8e184SMichael S. Tsirkin 
14951141ce21SGerd Hoffmann static void virtio_pci_modern_regions_init(VirtIOPCIProxy *proxy)
14961141ce21SGerd Hoffmann {
14971141ce21SGerd Hoffmann     static const MemoryRegionOps common_ops = {
14981141ce21SGerd Hoffmann         .read = virtio_pci_common_read,
14991141ce21SGerd Hoffmann         .write = virtio_pci_common_write,
15001141ce21SGerd Hoffmann         .impl = {
15011141ce21SGerd Hoffmann             .min_access_size = 1,
15021141ce21SGerd Hoffmann             .max_access_size = 4,
15031141ce21SGerd Hoffmann         },
15041141ce21SGerd Hoffmann         .endianness = DEVICE_LITTLE_ENDIAN,
15051141ce21SGerd Hoffmann     };
15061141ce21SGerd Hoffmann     static const MemoryRegionOps isr_ops = {
15071141ce21SGerd Hoffmann         .read = virtio_pci_isr_read,
15081141ce21SGerd Hoffmann         .write = virtio_pci_isr_write,
15091141ce21SGerd Hoffmann         .impl = {
15101141ce21SGerd Hoffmann             .min_access_size = 1,
15111141ce21SGerd Hoffmann             .max_access_size = 4,
15121141ce21SGerd Hoffmann         },
15131141ce21SGerd Hoffmann         .endianness = DEVICE_LITTLE_ENDIAN,
15141141ce21SGerd Hoffmann     };
15151141ce21SGerd Hoffmann     static const MemoryRegionOps device_ops = {
15161141ce21SGerd Hoffmann         .read = virtio_pci_device_read,
15171141ce21SGerd Hoffmann         .write = virtio_pci_device_write,
15181141ce21SGerd Hoffmann         .impl = {
15191141ce21SGerd Hoffmann             .min_access_size = 1,
15201141ce21SGerd Hoffmann             .max_access_size = 4,
15211141ce21SGerd Hoffmann         },
15221141ce21SGerd Hoffmann         .endianness = DEVICE_LITTLE_ENDIAN,
15231141ce21SGerd Hoffmann     };
15241141ce21SGerd Hoffmann     static const MemoryRegionOps notify_ops = {
15251141ce21SGerd Hoffmann         .read = virtio_pci_notify_read,
15261141ce21SGerd Hoffmann         .write = virtio_pci_notify_write,
15271141ce21SGerd Hoffmann         .impl = {
15281141ce21SGerd Hoffmann             .min_access_size = 1,
15291141ce21SGerd Hoffmann             .max_access_size = 4,
15301141ce21SGerd Hoffmann         },
15311141ce21SGerd Hoffmann         .endianness = DEVICE_LITTLE_ENDIAN,
15321141ce21SGerd Hoffmann     };
1533*9824d2a3SJason Wang     static const MemoryRegionOps notify_pio_ops = {
1534*9824d2a3SJason Wang         .read = virtio_pci_notify_read,
1535*9824d2a3SJason Wang         .write = virtio_pci_notify_write_pio,
1536*9824d2a3SJason Wang         .impl = {
1537*9824d2a3SJason Wang             .min_access_size = 1,
1538*9824d2a3SJason Wang             .max_access_size = 4,
1539*9824d2a3SJason Wang         },
1540*9824d2a3SJason Wang         .endianness = DEVICE_LITTLE_ENDIAN,
1541*9824d2a3SJason Wang     };
1542*9824d2a3SJason Wang 
15431141ce21SGerd Hoffmann 
15441141ce21SGerd Hoffmann     memory_region_init_io(&proxy->common.mr, OBJECT(proxy),
15451141ce21SGerd Hoffmann                           &common_ops,
15461141ce21SGerd Hoffmann                           proxy,
1547b6ce27a5SGerd Hoffmann                           "virtio-pci-common",
1548b6ce27a5SGerd Hoffmann                           proxy->common.size);
1549a3cc2e81SGerd Hoffmann 
15501141ce21SGerd Hoffmann     memory_region_init_io(&proxy->isr.mr, OBJECT(proxy),
15511141ce21SGerd Hoffmann                           &isr_ops,
15521141ce21SGerd Hoffmann                           proxy,
1553b6ce27a5SGerd Hoffmann                           "virtio-pci-isr",
1554b6ce27a5SGerd Hoffmann                           proxy->isr.size);
1555a3cc2e81SGerd Hoffmann 
15561141ce21SGerd Hoffmann     memory_region_init_io(&proxy->device.mr, OBJECT(proxy),
15571141ce21SGerd Hoffmann                           &device_ops,
15581141ce21SGerd Hoffmann                           virtio_bus_get_device(&proxy->bus),
1559b6ce27a5SGerd Hoffmann                           "virtio-pci-device",
1560b6ce27a5SGerd Hoffmann                           proxy->device.size);
1561a3cc2e81SGerd Hoffmann 
15621141ce21SGerd Hoffmann     memory_region_init_io(&proxy->notify.mr, OBJECT(proxy),
15631141ce21SGerd Hoffmann                           &notify_ops,
15641141ce21SGerd Hoffmann                           virtio_bus_get_device(&proxy->bus),
15651141ce21SGerd Hoffmann                           "virtio-pci-notify",
1566b6ce27a5SGerd Hoffmann                           proxy->notify.size);
1567*9824d2a3SJason Wang 
1568*9824d2a3SJason Wang     memory_region_init_io(&proxy->notify_pio.mr, OBJECT(proxy),
1569*9824d2a3SJason Wang                           &notify_pio_ops,
1570*9824d2a3SJason Wang                           virtio_bus_get_device(&proxy->bus),
1571*9824d2a3SJason Wang                           "virtio-pci-notify-pio",
1572*9824d2a3SJason Wang                           proxy->notify.size);
1573a3cc2e81SGerd Hoffmann }
1574a3cc2e81SGerd Hoffmann 
1575a3cc2e81SGerd Hoffmann static void virtio_pci_modern_region_map(VirtIOPCIProxy *proxy,
157654790d71SGerd Hoffmann                                          VirtIOPCIRegion *region,
1577*9824d2a3SJason Wang                                          struct virtio_pci_cap *cap,
1578*9824d2a3SJason Wang                                          MemoryRegion *mr,
1579*9824d2a3SJason Wang                                          uint8_t bar)
1580a3cc2e81SGerd Hoffmann {
1581*9824d2a3SJason Wang     memory_region_add_subregion(mr, region->offset, &region->mr);
158254790d71SGerd Hoffmann 
1583fc004905SGerd Hoffmann     cap->cfg_type = region->type;
1584*9824d2a3SJason Wang     cap->bar = bar;
158554790d71SGerd Hoffmann     cap->offset = cpu_to_le32(region->offset);
1586b6ce27a5SGerd Hoffmann     cap->length = cpu_to_le32(region->size);
158754790d71SGerd Hoffmann     virtio_pci_add_mem_cap(proxy, cap);
1588*9824d2a3SJason Wang 
15891141ce21SGerd Hoffmann }
1590dfb8e184SMichael S. Tsirkin 
1591*9824d2a3SJason Wang static void virtio_pci_modern_mem_region_map(VirtIOPCIProxy *proxy,
1592*9824d2a3SJason Wang                                              VirtIOPCIRegion *region,
1593*9824d2a3SJason Wang                                              struct virtio_pci_cap *cap)
1594*9824d2a3SJason Wang {
1595*9824d2a3SJason Wang     virtio_pci_modern_region_map(proxy, region, cap,
1596*9824d2a3SJason Wang                                  &proxy->modern_bar, proxy->modern_mem_bar);
1597*9824d2a3SJason Wang }
1598*9824d2a3SJason Wang 
1599*9824d2a3SJason Wang static void virtio_pci_modern_io_region_map(VirtIOPCIProxy *proxy,
1600*9824d2a3SJason Wang                                             VirtIOPCIRegion *region,
1601*9824d2a3SJason Wang                                             struct virtio_pci_cap *cap)
1602*9824d2a3SJason Wang {
1603*9824d2a3SJason Wang     virtio_pci_modern_region_map(proxy, region, cap,
1604*9824d2a3SJason Wang                                  &proxy->io_bar, proxy->modern_io_bar);
1605*9824d2a3SJason Wang }
1606*9824d2a3SJason Wang 
1607*9824d2a3SJason Wang static void virtio_pci_modern_mem_region_unmap(VirtIOPCIProxy *proxy,
160827462695SMichael S. Tsirkin                                                VirtIOPCIRegion *region)
160927462695SMichael S. Tsirkin {
161027462695SMichael S. Tsirkin     memory_region_del_subregion(&proxy->modern_bar,
161127462695SMichael S. Tsirkin                                 &region->mr);
161227462695SMichael S. Tsirkin }
161327462695SMichael S. Tsirkin 
1614*9824d2a3SJason Wang static void virtio_pci_modern_io_region_unmap(VirtIOPCIProxy *proxy,
1615*9824d2a3SJason Wang                                               VirtIOPCIRegion *region)
1616*9824d2a3SJason Wang {
1617*9824d2a3SJason Wang     memory_region_del_subregion(&proxy->io_bar,
1618*9824d2a3SJason Wang                                 &region->mr);
1619*9824d2a3SJason Wang }
1620*9824d2a3SJason Wang 
1621085bccb7SKONRAD Frederic /* This is called by virtio-bus just after the device is plugged. */
1622e8398045SJason Wang static void virtio_pci_device_plugged(DeviceState *d, Error **errp)
1623085bccb7SKONRAD Frederic {
1624085bccb7SKONRAD Frederic     VirtIOPCIProxy *proxy = VIRTIO_PCI(d);
1625085bccb7SKONRAD Frederic     VirtioBusState *bus = &proxy->bus;
1626e266d421SGerd Hoffmann     bool legacy = !(proxy->flags & VIRTIO_PCI_FLAG_DISABLE_LEGACY);
1627e266d421SGerd Hoffmann     bool modern = !(proxy->flags & VIRTIO_PCI_FLAG_DISABLE_MODERN);
1628*9824d2a3SJason Wang     bool modern_pio = proxy->flags & VIRTIO_PCI_FLAG_MODERN_PIO_NOTIFY;
1629085bccb7SKONRAD Frederic     uint8_t *config;
1630085bccb7SKONRAD Frederic     uint32_t size;
16316b8f1020SCornelia Huck     VirtIODevice *vdev = virtio_bus_get_device(&proxy->bus);
1632085bccb7SKONRAD Frederic 
1633085bccb7SKONRAD Frederic     config = proxy->pci_dev.config;
1634085bccb7SKONRAD Frederic     if (proxy->class_code) {
1635085bccb7SKONRAD Frederic         pci_config_set_class(config, proxy->class_code);
1636085bccb7SKONRAD Frederic     }
1637e266d421SGerd Hoffmann 
1638e266d421SGerd Hoffmann     if (legacy) {
1639e266d421SGerd Hoffmann         /* legacy and transitional */
1640085bccb7SKONRAD Frederic         pci_set_word(config + PCI_SUBSYSTEM_VENDOR_ID,
1641085bccb7SKONRAD Frederic                      pci_get_word(config + PCI_VENDOR_ID));
1642085bccb7SKONRAD Frederic         pci_set_word(config + PCI_SUBSYSTEM_ID, virtio_bus_get_vdev_id(bus));
1643e266d421SGerd Hoffmann     } else {
1644e266d421SGerd Hoffmann         /* pure virtio-1.0 */
1645e266d421SGerd Hoffmann         pci_set_word(config + PCI_VENDOR_ID,
1646e266d421SGerd Hoffmann                      PCI_VENDOR_ID_REDHAT_QUMRANET);
1647e266d421SGerd Hoffmann         pci_set_word(config + PCI_DEVICE_ID,
1648e266d421SGerd Hoffmann                      0x1040 + virtio_bus_get_vdev_id(bus));
1649e266d421SGerd Hoffmann         pci_config_set_revision(config, 1);
1650e266d421SGerd Hoffmann     }
1651085bccb7SKONRAD Frederic     config[PCI_INTERRUPT_PIN] = 1;
1652085bccb7SKONRAD Frederic 
1653dfb8e184SMichael S. Tsirkin 
1654e266d421SGerd Hoffmann     if (modern) {
1655cc52ea90SGerd Hoffmann         struct virtio_pci_cap cap = {
1656cc52ea90SGerd Hoffmann             .cap_len = sizeof cap,
1657dfb8e184SMichael S. Tsirkin         };
1658dfb8e184SMichael S. Tsirkin         struct virtio_pci_notify_cap notify = {
1659dfb8e184SMichael S. Tsirkin             .cap.cap_len = sizeof notify,
1660dfb8e184SMichael S. Tsirkin             .notify_off_multiplier =
1661dfb8e184SMichael S. Tsirkin                 cpu_to_le32(QEMU_VIRTIO_PCI_QUEUE_MEM_MULT),
1662dfb8e184SMichael S. Tsirkin         };
1663ada434cdSMichael S. Tsirkin         struct virtio_pci_cfg_cap cfg = {
1664ada434cdSMichael S. Tsirkin             .cap.cap_len = sizeof cfg,
1665ada434cdSMichael S. Tsirkin             .cap.cfg_type = VIRTIO_PCI_CAP_PCI_CFG,
1666ada434cdSMichael S. Tsirkin         };
1667*9824d2a3SJason Wang         struct virtio_pci_notify_cap notify_pio = {
1668*9824d2a3SJason Wang             .cap.cap_len = sizeof notify,
1669*9824d2a3SJason Wang             .notify_off_multiplier = cpu_to_le32(0x0),
1670*9824d2a3SJason Wang         };
1671dfb8e184SMichael S. Tsirkin 
1672*9824d2a3SJason Wang         struct virtio_pci_cfg_cap *cfg_mask;
1673dfb8e184SMichael S. Tsirkin 
1674dfb8e184SMichael S. Tsirkin         virtio_add_feature(&vdev->host_features, VIRTIO_F_VERSION_1);
16751141ce21SGerd Hoffmann         virtio_pci_modern_regions_init(proxy);
1676*9824d2a3SJason Wang 
1677*9824d2a3SJason Wang         virtio_pci_modern_mem_region_map(proxy, &proxy->common, &cap);
1678*9824d2a3SJason Wang         virtio_pci_modern_mem_region_map(proxy, &proxy->isr, &cap);
1679*9824d2a3SJason Wang         virtio_pci_modern_mem_region_map(proxy, &proxy->device, &cap);
1680*9824d2a3SJason Wang         virtio_pci_modern_mem_region_map(proxy, &proxy->notify, &notify.cap);
1681*9824d2a3SJason Wang 
1682*9824d2a3SJason Wang         if (modern_pio) {
1683*9824d2a3SJason Wang             memory_region_init(&proxy->io_bar, OBJECT(proxy),
1684*9824d2a3SJason Wang                                "virtio-pci-io", 0x4);
1685*9824d2a3SJason Wang 
1686*9824d2a3SJason Wang             pci_register_bar(&proxy->pci_dev, proxy->modern_io_bar,
1687*9824d2a3SJason Wang                              PCI_BASE_ADDRESS_SPACE_IO, &proxy->io_bar);
1688*9824d2a3SJason Wang 
1689*9824d2a3SJason Wang             virtio_pci_modern_io_region_map(proxy, &proxy->notify_pio,
1690*9824d2a3SJason Wang                                             &notify_pio.cap);
1691*9824d2a3SJason Wang         }
1692ada434cdSMichael S. Tsirkin 
1693b6ce27a5SGerd Hoffmann         pci_register_bar(&proxy->pci_dev, proxy->modern_mem_bar,
16944e93a68eSGerd Hoffmann                          PCI_BASE_ADDRESS_SPACE_MEMORY |
16954e93a68eSGerd Hoffmann                          PCI_BASE_ADDRESS_MEM_PREFETCH |
16964e93a68eSGerd Hoffmann                          PCI_BASE_ADDRESS_MEM_TYPE_64,
1697dfb8e184SMichael S. Tsirkin                          &proxy->modern_bar);
1698ada434cdSMichael S. Tsirkin 
1699ada434cdSMichael S. Tsirkin         proxy->config_cap = virtio_pci_add_mem_cap(proxy, &cfg.cap);
1700ada434cdSMichael S. Tsirkin         cfg_mask = (void *)(proxy->pci_dev.wmask + proxy->config_cap);
1701ada434cdSMichael S. Tsirkin         pci_set_byte(&cfg_mask->cap.bar, ~0x0);
1702ada434cdSMichael S. Tsirkin         pci_set_long((uint8_t *)&cfg_mask->cap.offset, ~0x0);
1703ada434cdSMichael S. Tsirkin         pci_set_long((uint8_t *)&cfg_mask->cap.length, ~0x0);
1704ada434cdSMichael S. Tsirkin         pci_set_long(cfg_mask->pci_cfg_data, ~0x0);
1705dfb8e184SMichael S. Tsirkin     }
1706dfb8e184SMichael S. Tsirkin 
17070d583647SRichard Henderson     if (proxy->nvectors) {
17080d583647SRichard Henderson         int err = msix_init_exclusive_bar(&proxy->pci_dev, proxy->nvectors,
17090d583647SRichard Henderson                                           proxy->msix_bar);
17100d583647SRichard Henderson         if (err) {
17110d583647SRichard Henderson             /* Notice when a system that supports MSIx can't initialize it.  */
17120d583647SRichard Henderson             if (err != -ENOTSUP) {
1713c7ff5482SFam Zheng                 error_report("unable to init msix vectors to %" PRIu32,
1714c7ff5482SFam Zheng                              proxy->nvectors);
17150d583647SRichard Henderson             }
1716085bccb7SKONRAD Frederic             proxy->nvectors = 0;
1717085bccb7SKONRAD Frederic         }
17180d583647SRichard Henderson     }
1719085bccb7SKONRAD Frederic 
1720085bccb7SKONRAD Frederic     proxy->pci_dev.config_write = virtio_write_config;
1721ada434cdSMichael S. Tsirkin     proxy->pci_dev.config_read = virtio_read_config;
1722085bccb7SKONRAD Frederic 
1723e266d421SGerd Hoffmann     if (legacy) {
1724085bccb7SKONRAD Frederic         size = VIRTIO_PCI_REGION_SIZE(&proxy->pci_dev)
1725085bccb7SKONRAD Frederic             + virtio_bus_get_vdev_config_len(bus);
17261d0148feSPeter Maydell         size = pow2ceil(size);
1727085bccb7SKONRAD Frederic 
1728e266d421SGerd Hoffmann         memory_region_init_io(&proxy->bar, OBJECT(proxy),
1729e266d421SGerd Hoffmann                               &virtio_pci_config_ops,
173022fc860bSPaolo Bonzini                               proxy, "virtio-pci", size);
1731dfb8e184SMichael S. Tsirkin 
1732b6ce27a5SGerd Hoffmann         pci_register_bar(&proxy->pci_dev, proxy->legacy_io_bar,
173323c5e397SGerd Hoffmann                          PCI_BASE_ADDRESS_SPACE_IO, &proxy->bar);
1734e266d421SGerd Hoffmann     }
1735085bccb7SKONRAD Frederic 
1736085bccb7SKONRAD Frederic     if (!kvm_has_many_ioeventfds()) {
1737085bccb7SKONRAD Frederic         proxy->flags &= ~VIRTIO_PCI_FLAG_USE_IOEVENTFD;
1738085bccb7SKONRAD Frederic     }
1739085bccb7SKONRAD Frederic 
17406b8f1020SCornelia Huck     virtio_add_feature(&vdev->host_features, VIRTIO_F_BAD_FEATURE);
1741085bccb7SKONRAD Frederic }
1742085bccb7SKONRAD Frederic 
174306a13073SPaolo Bonzini static void virtio_pci_device_unplugged(DeviceState *d)
174406a13073SPaolo Bonzini {
174506a13073SPaolo Bonzini     VirtIOPCIProxy *proxy = VIRTIO_PCI(d);
174627462695SMichael S. Tsirkin     bool modern = !(proxy->flags & VIRTIO_PCI_FLAG_DISABLE_MODERN);
1747*9824d2a3SJason Wang     bool modern_pio = proxy->flags & VIRTIO_PCI_FLAG_MODERN_PIO_NOTIFY;
174806a13073SPaolo Bonzini 
174906a13073SPaolo Bonzini     virtio_pci_stop_ioeventfd(proxy);
175027462695SMichael S. Tsirkin 
175127462695SMichael S. Tsirkin     if (modern) {
1752*9824d2a3SJason Wang         virtio_pci_modern_mem_region_unmap(proxy, &proxy->common);
1753*9824d2a3SJason Wang         virtio_pci_modern_mem_region_unmap(proxy, &proxy->isr);
1754*9824d2a3SJason Wang         virtio_pci_modern_mem_region_unmap(proxy, &proxy->device);
1755*9824d2a3SJason Wang         virtio_pci_modern_mem_region_unmap(proxy, &proxy->notify);
1756*9824d2a3SJason Wang         if (modern_pio) {
1757*9824d2a3SJason Wang             virtio_pci_modern_io_region_unmap(proxy, &proxy->notify_pio);
1758*9824d2a3SJason Wang         }
175927462695SMichael S. Tsirkin     }
176006a13073SPaolo Bonzini }
176106a13073SPaolo Bonzini 
1762fc079951SMarkus Armbruster static void virtio_pci_realize(PCIDevice *pci_dev, Error **errp)
1763085bccb7SKONRAD Frederic {
1764b6ce27a5SGerd Hoffmann     VirtIOPCIProxy *proxy = VIRTIO_PCI(pci_dev);
1765085bccb7SKONRAD Frederic     VirtioPCIClass *k = VIRTIO_PCI_GET_CLASS(pci_dev);
1766fc079951SMarkus Armbruster 
1767b6ce27a5SGerd Hoffmann     /*
1768b6ce27a5SGerd Hoffmann      * virtio pci bar layout used by default.
1769b6ce27a5SGerd Hoffmann      * subclasses can re-arrange things if needed.
1770b6ce27a5SGerd Hoffmann      *
1771b6ce27a5SGerd Hoffmann      *   region 0   --  virtio legacy io bar
1772b6ce27a5SGerd Hoffmann      *   region 1   --  msi-x bar
1773b6ce27a5SGerd Hoffmann      *   region 4+5 --  virtio modern memory (64bit) bar
1774b6ce27a5SGerd Hoffmann      *
1775b6ce27a5SGerd Hoffmann      */
1776b6ce27a5SGerd Hoffmann     proxy->legacy_io_bar  = 0;
1777b6ce27a5SGerd Hoffmann     proxy->msix_bar       = 1;
1778*9824d2a3SJason Wang     proxy->modern_io_bar  = 2;
1779b6ce27a5SGerd Hoffmann     proxy->modern_mem_bar = 4;
1780b6ce27a5SGerd Hoffmann 
1781b6ce27a5SGerd Hoffmann     proxy->common.offset = 0x0;
1782b6ce27a5SGerd Hoffmann     proxy->common.size = 0x1000;
1783b6ce27a5SGerd Hoffmann     proxy->common.type = VIRTIO_PCI_CAP_COMMON_CFG;
1784b6ce27a5SGerd Hoffmann 
1785b6ce27a5SGerd Hoffmann     proxy->isr.offset = 0x1000;
1786b6ce27a5SGerd Hoffmann     proxy->isr.size = 0x1000;
1787b6ce27a5SGerd Hoffmann     proxy->isr.type = VIRTIO_PCI_CAP_ISR_CFG;
1788b6ce27a5SGerd Hoffmann 
1789b6ce27a5SGerd Hoffmann     proxy->device.offset = 0x2000;
1790b6ce27a5SGerd Hoffmann     proxy->device.size = 0x1000;
1791b6ce27a5SGerd Hoffmann     proxy->device.type = VIRTIO_PCI_CAP_DEVICE_CFG;
1792b6ce27a5SGerd Hoffmann 
1793b6ce27a5SGerd Hoffmann     proxy->notify.offset = 0x3000;
1794b6ce27a5SGerd Hoffmann     proxy->notify.size =
1795b6ce27a5SGerd Hoffmann         QEMU_VIRTIO_PCI_QUEUE_MEM_MULT * VIRTIO_QUEUE_MAX;
1796b6ce27a5SGerd Hoffmann     proxy->notify.type = VIRTIO_PCI_CAP_NOTIFY_CFG;
1797b6ce27a5SGerd Hoffmann 
1798*9824d2a3SJason Wang     proxy->notify_pio.offset = 0x0;
1799*9824d2a3SJason Wang     proxy->notify_pio.size = 0x4;
1800*9824d2a3SJason Wang     proxy->notify_pio.type = VIRTIO_PCI_CAP_NOTIFY_CFG;
1801*9824d2a3SJason Wang 
1802b6ce27a5SGerd Hoffmann     /* subclasses can enforce modern, so do this unconditionally */
1803b6ce27a5SGerd Hoffmann     memory_region_init(&proxy->modern_bar, OBJECT(proxy), "virtio-pci",
1804b6ce27a5SGerd Hoffmann                        2 * QEMU_VIRTIO_PCI_QUEUE_MEM_MULT *
1805b6ce27a5SGerd Hoffmann                        VIRTIO_QUEUE_MAX);
1806b6ce27a5SGerd Hoffmann 
1807ada434cdSMichael S. Tsirkin     memory_region_init_alias(&proxy->modern_cfg,
1808ada434cdSMichael S. Tsirkin                              OBJECT(proxy),
1809ada434cdSMichael S. Tsirkin                              "virtio-pci-cfg",
1810ada434cdSMichael S. Tsirkin                              &proxy->modern_bar,
1811ada434cdSMichael S. Tsirkin                              0,
1812ada434cdSMichael S. Tsirkin                              memory_region_size(&proxy->modern_bar));
1813ada434cdSMichael S. Tsirkin 
1814ada434cdSMichael S. Tsirkin     address_space_init(&proxy->modern_as, &proxy->modern_cfg, "virtio-pci-cfg-as");
1815ada434cdSMichael S. Tsirkin 
1816b6ce27a5SGerd Hoffmann     virtio_pci_bus_new(&proxy->bus, sizeof(proxy->bus), proxy);
1817fc079951SMarkus Armbruster     if (k->realize) {
1818b6ce27a5SGerd Hoffmann         k->realize(proxy, errp);
1819085bccb7SKONRAD Frederic     }
1820085bccb7SKONRAD Frederic }
1821085bccb7SKONRAD Frederic 
1822085bccb7SKONRAD Frederic static void virtio_pci_exit(PCIDevice *pci_dev)
1823085bccb7SKONRAD Frederic {
1824ada434cdSMichael S. Tsirkin     VirtIOPCIProxy *proxy = VIRTIO_PCI(pci_dev);
1825ada434cdSMichael S. Tsirkin 
18268b81bb3bSPaolo Bonzini     msix_uninit_exclusive_bar(pci_dev);
1827ada434cdSMichael S. Tsirkin     address_space_destroy(&proxy->modern_as);
1828085bccb7SKONRAD Frederic }
1829085bccb7SKONRAD Frederic 
183059ccd20aSKONRAD Frederic static void virtio_pci_reset(DeviceState *qdev)
1831085bccb7SKONRAD Frederic {
1832085bccb7SKONRAD Frederic     VirtIOPCIProxy *proxy = VIRTIO_PCI(qdev);
1833085bccb7SKONRAD Frederic     VirtioBusState *bus = VIRTIO_BUS(&proxy->bus);
1834085bccb7SKONRAD Frederic     virtio_pci_stop_ioeventfd(proxy);
1835085bccb7SKONRAD Frederic     virtio_bus_reset(bus);
1836085bccb7SKONRAD Frederic     msix_unuse_all_vectors(&proxy->pci_dev);
1837085bccb7SKONRAD Frederic }
1838085bccb7SKONRAD Frederic 
183985d1277eSMing Lei static Property virtio_pci_properties[] = {
184068a27b20SMichael S. Tsirkin     DEFINE_PROP_BIT("virtio-pci-bus-master-bug-migration", VirtIOPCIProxy, flags,
184168a27b20SMichael S. Tsirkin                     VIRTIO_PCI_FLAG_BUS_MASTER_BUG_MIGRATION_BIT, false),
1842e266d421SGerd Hoffmann     DEFINE_PROP_BIT("disable-legacy", VirtIOPCIProxy, flags,
1843e266d421SGerd Hoffmann                     VIRTIO_PCI_FLAG_DISABLE_LEGACY_BIT, false),
1844e266d421SGerd Hoffmann     DEFINE_PROP_BIT("disable-modern", VirtIOPCIProxy, flags,
1845e266d421SGerd Hoffmann                     VIRTIO_PCI_FLAG_DISABLE_MODERN_BIT, true),
1846a6df8adfSJason Wang     DEFINE_PROP_BIT("migrate-extra", VirtIOPCIProxy, flags,
1847a6df8adfSJason Wang                     VIRTIO_PCI_FLAG_MIGRATE_EXTRA_BIT, true),
1848*9824d2a3SJason Wang     DEFINE_PROP_BIT("modern-pio-notify", VirtIOPCIProxy, flags,
1849*9824d2a3SJason Wang                     VIRTIO_PCI_FLAG_MODERN_PIO_NOTIFY_BIT, false),
185085d1277eSMing Lei     DEFINE_PROP_END_OF_LIST(),
185185d1277eSMing Lei };
185285d1277eSMing Lei 
1853085bccb7SKONRAD Frederic static void virtio_pci_class_init(ObjectClass *klass, void *data)
1854085bccb7SKONRAD Frederic {
1855085bccb7SKONRAD Frederic     DeviceClass *dc = DEVICE_CLASS(klass);
1856085bccb7SKONRAD Frederic     PCIDeviceClass *k = PCI_DEVICE_CLASS(klass);
1857085bccb7SKONRAD Frederic 
185885d1277eSMing Lei     dc->props = virtio_pci_properties;
1859fc079951SMarkus Armbruster     k->realize = virtio_pci_realize;
1860085bccb7SKONRAD Frederic     k->exit = virtio_pci_exit;
1861085bccb7SKONRAD Frederic     k->vendor_id = PCI_VENDOR_ID_REDHAT_QUMRANET;
1862085bccb7SKONRAD Frederic     k->revision = VIRTIO_PCI_ABI_VERSION;
1863085bccb7SKONRAD Frederic     k->class_id = PCI_CLASS_OTHERS;
186459ccd20aSKONRAD Frederic     dc->reset = virtio_pci_reset;
1865085bccb7SKONRAD Frederic }
1866085bccb7SKONRAD Frederic 
1867085bccb7SKONRAD Frederic static const TypeInfo virtio_pci_info = {
1868085bccb7SKONRAD Frederic     .name          = TYPE_VIRTIO_PCI,
1869085bccb7SKONRAD Frederic     .parent        = TYPE_PCI_DEVICE,
1870085bccb7SKONRAD Frederic     .instance_size = sizeof(VirtIOPCIProxy),
1871085bccb7SKONRAD Frederic     .class_init    = virtio_pci_class_init,
1872085bccb7SKONRAD Frederic     .class_size    = sizeof(VirtioPCIClass),
1873085bccb7SKONRAD Frederic     .abstract      = true,
1874085bccb7SKONRAD Frederic };
1875085bccb7SKONRAD Frederic 
1876653ced07SKONRAD Frederic /* virtio-blk-pci */
1877653ced07SKONRAD Frederic 
1878653ced07SKONRAD Frederic static Property virtio_blk_pci_properties[] = {
1879c7bcc85dSPaolo Bonzini     DEFINE_PROP_UINT32("class", VirtIOPCIProxy, class_code, 0),
1880653ced07SKONRAD Frederic     DEFINE_PROP_BIT("ioeventfd", VirtIOPCIProxy, flags,
1881653ced07SKONRAD Frederic                     VIRTIO_PCI_FLAG_USE_IOEVENTFD_BIT, true),
1882653ced07SKONRAD Frederic     DEFINE_PROP_UINT32("vectors", VirtIOPCIProxy, nvectors, 2),
1883653ced07SKONRAD Frederic     DEFINE_PROP_END_OF_LIST(),
1884653ced07SKONRAD Frederic };
1885653ced07SKONRAD Frederic 
1886fc079951SMarkus Armbruster static void virtio_blk_pci_realize(VirtIOPCIProxy *vpci_dev, Error **errp)
1887653ced07SKONRAD Frederic {
1888653ced07SKONRAD Frederic     VirtIOBlkPCI *dev = VIRTIO_BLK_PCI(vpci_dev);
1889653ced07SKONRAD Frederic     DeviceState *vdev = DEVICE(&dev->vdev);
1890fc079951SMarkus Armbruster 
1891653ced07SKONRAD Frederic     qdev_set_parent_bus(vdev, BUS(&vpci_dev->bus));
1892fc079951SMarkus Armbruster     object_property_set_bool(OBJECT(vdev), true, "realized", errp);
1893653ced07SKONRAD Frederic }
1894653ced07SKONRAD Frederic 
1895653ced07SKONRAD Frederic static void virtio_blk_pci_class_init(ObjectClass *klass, void *data)
1896653ced07SKONRAD Frederic {
1897653ced07SKONRAD Frederic     DeviceClass *dc = DEVICE_CLASS(klass);
1898653ced07SKONRAD Frederic     VirtioPCIClass *k = VIRTIO_PCI_CLASS(klass);
1899653ced07SKONRAD Frederic     PCIDeviceClass *pcidev_k = PCI_DEVICE_CLASS(klass);
1900653ced07SKONRAD Frederic 
1901125ee0edSMarcel Apfelbaum     set_bit(DEVICE_CATEGORY_STORAGE, dc->categories);
1902653ced07SKONRAD Frederic     dc->props = virtio_blk_pci_properties;
1903fc079951SMarkus Armbruster     k->realize = virtio_blk_pci_realize;
1904653ced07SKONRAD Frederic     pcidev_k->vendor_id = PCI_VENDOR_ID_REDHAT_QUMRANET;
1905653ced07SKONRAD Frederic     pcidev_k->device_id = PCI_DEVICE_ID_VIRTIO_BLOCK;
1906653ced07SKONRAD Frederic     pcidev_k->revision = VIRTIO_PCI_ABI_VERSION;
1907653ced07SKONRAD Frederic     pcidev_k->class_id = PCI_CLASS_STORAGE_SCSI;
1908653ced07SKONRAD Frederic }
1909653ced07SKONRAD Frederic 
1910653ced07SKONRAD Frederic static void virtio_blk_pci_instance_init(Object *obj)
1911653ced07SKONRAD Frederic {
1912653ced07SKONRAD Frederic     VirtIOBlkPCI *dev = VIRTIO_BLK_PCI(obj);
1913c8075cafSGonglei 
1914c8075cafSGonglei     virtio_instance_init_common(obj, &dev->vdev, sizeof(dev->vdev),
1915c8075cafSGonglei                                 TYPE_VIRTIO_BLK);
1916467b3f33SStefan Hajnoczi     object_property_add_alias(obj, "iothread", OBJECT(&dev->vdev),"iothread",
1917467b3f33SStefan Hajnoczi                               &error_abort);
1918aeb98ddcSGonglei     object_property_add_alias(obj, "bootindex", OBJECT(&dev->vdev),
1919aeb98ddcSGonglei                               "bootindex", &error_abort);
1920653ced07SKONRAD Frederic }
1921653ced07SKONRAD Frederic 
1922653ced07SKONRAD Frederic static const TypeInfo virtio_blk_pci_info = {
1923653ced07SKONRAD Frederic     .name          = TYPE_VIRTIO_BLK_PCI,
1924653ced07SKONRAD Frederic     .parent        = TYPE_VIRTIO_PCI,
1925653ced07SKONRAD Frederic     .instance_size = sizeof(VirtIOBlkPCI),
1926653ced07SKONRAD Frederic     .instance_init = virtio_blk_pci_instance_init,
1927653ced07SKONRAD Frederic     .class_init    = virtio_blk_pci_class_init,
1928653ced07SKONRAD Frederic };
1929653ced07SKONRAD Frederic 
1930bc7b90a0SKONRAD Frederic /* virtio-scsi-pci */
1931bc7b90a0SKONRAD Frederic 
1932bc7b90a0SKONRAD Frederic static Property virtio_scsi_pci_properties[] = {
1933bc7b90a0SKONRAD Frederic     DEFINE_PROP_BIT("ioeventfd", VirtIOPCIProxy, flags,
1934bc7b90a0SKONRAD Frederic                     VIRTIO_PCI_FLAG_USE_IOEVENTFD_BIT, true),
1935bc7b90a0SKONRAD Frederic     DEFINE_PROP_UINT32("vectors", VirtIOPCIProxy, nvectors,
1936bc7b90a0SKONRAD Frederic                        DEV_NVECTORS_UNSPECIFIED),
1937bc7b90a0SKONRAD Frederic     DEFINE_PROP_END_OF_LIST(),
1938bc7b90a0SKONRAD Frederic };
1939bc7b90a0SKONRAD Frederic 
1940fc079951SMarkus Armbruster static void virtio_scsi_pci_realize(VirtIOPCIProxy *vpci_dev, Error **errp)
1941bc7b90a0SKONRAD Frederic {
1942bc7b90a0SKONRAD Frederic     VirtIOSCSIPCI *dev = VIRTIO_SCSI_PCI(vpci_dev);
1943bc7b90a0SKONRAD Frederic     DeviceState *vdev = DEVICE(&dev->vdev);
1944292c8e50SPaolo Bonzini     VirtIOSCSICommon *vs = VIRTIO_SCSI_COMMON(vdev);
19456f32a6b4SKONRAD Frederic     DeviceState *proxy = DEVICE(vpci_dev);
19466f32a6b4SKONRAD Frederic     char *bus_name;
1947bc7b90a0SKONRAD Frederic 
1948bc7b90a0SKONRAD Frederic     if (vpci_dev->nvectors == DEV_NVECTORS_UNSPECIFIED) {
1949292c8e50SPaolo Bonzini         vpci_dev->nvectors = vs->conf.num_queues + 3;
1950bc7b90a0SKONRAD Frederic     }
1951bc7b90a0SKONRAD Frederic 
19526f32a6b4SKONRAD Frederic     /*
19536f32a6b4SKONRAD Frederic      * For command line compatibility, this sets the virtio-scsi-device bus
19546f32a6b4SKONRAD Frederic      * name as before.
19556f32a6b4SKONRAD Frederic      */
19566f32a6b4SKONRAD Frederic     if (proxy->id) {
19576f32a6b4SKONRAD Frederic         bus_name = g_strdup_printf("%s.0", proxy->id);
19586f32a6b4SKONRAD Frederic         virtio_device_set_child_bus_name(VIRTIO_DEVICE(vdev), bus_name);
19596f32a6b4SKONRAD Frederic         g_free(bus_name);
19606f32a6b4SKONRAD Frederic     }
19616f32a6b4SKONRAD Frederic 
1962bc7b90a0SKONRAD Frederic     qdev_set_parent_bus(vdev, BUS(&vpci_dev->bus));
1963fc079951SMarkus Armbruster     object_property_set_bool(OBJECT(vdev), true, "realized", errp);
1964bc7b90a0SKONRAD Frederic }
1965bc7b90a0SKONRAD Frederic 
1966bc7b90a0SKONRAD Frederic static void virtio_scsi_pci_class_init(ObjectClass *klass, void *data)
1967bc7b90a0SKONRAD Frederic {
1968bc7b90a0SKONRAD Frederic     DeviceClass *dc = DEVICE_CLASS(klass);
1969bc7b90a0SKONRAD Frederic     VirtioPCIClass *k = VIRTIO_PCI_CLASS(klass);
1970bc7b90a0SKONRAD Frederic     PCIDeviceClass *pcidev_k = PCI_DEVICE_CLASS(klass);
1971fc079951SMarkus Armbruster 
1972fc079951SMarkus Armbruster     k->realize = virtio_scsi_pci_realize;
1973125ee0edSMarcel Apfelbaum     set_bit(DEVICE_CATEGORY_STORAGE, dc->categories);
1974bc7b90a0SKONRAD Frederic     dc->props = virtio_scsi_pci_properties;
1975bc7b90a0SKONRAD Frederic     pcidev_k->vendor_id = PCI_VENDOR_ID_REDHAT_QUMRANET;
1976bc7b90a0SKONRAD Frederic     pcidev_k->device_id = PCI_DEVICE_ID_VIRTIO_SCSI;
1977bc7b90a0SKONRAD Frederic     pcidev_k->revision = 0x00;
1978bc7b90a0SKONRAD Frederic     pcidev_k->class_id = PCI_CLASS_STORAGE_SCSI;
1979bc7b90a0SKONRAD Frederic }
1980bc7b90a0SKONRAD Frederic 
1981bc7b90a0SKONRAD Frederic static void virtio_scsi_pci_instance_init(Object *obj)
1982bc7b90a0SKONRAD Frederic {
1983bc7b90a0SKONRAD Frederic     VirtIOSCSIPCI *dev = VIRTIO_SCSI_PCI(obj);
1984c8075cafSGonglei 
1985c8075cafSGonglei     virtio_instance_init_common(obj, &dev->vdev, sizeof(dev->vdev),
1986c8075cafSGonglei                                 TYPE_VIRTIO_SCSI);
198719d339f1SFam Zheng     object_property_add_alias(obj, "iothread", OBJECT(&dev->vdev), "iothread",
198819d339f1SFam Zheng                               &error_abort);
1989bc7b90a0SKONRAD Frederic }
1990bc7b90a0SKONRAD Frederic 
1991bc7b90a0SKONRAD Frederic static const TypeInfo virtio_scsi_pci_info = {
1992bc7b90a0SKONRAD Frederic     .name          = TYPE_VIRTIO_SCSI_PCI,
1993bc7b90a0SKONRAD Frederic     .parent        = TYPE_VIRTIO_PCI,
1994bc7b90a0SKONRAD Frederic     .instance_size = sizeof(VirtIOSCSIPCI),
1995bc7b90a0SKONRAD Frederic     .instance_init = virtio_scsi_pci_instance_init,
1996bc7b90a0SKONRAD Frederic     .class_init    = virtio_scsi_pci_class_init,
1997bc7b90a0SKONRAD Frederic };
1998bc7b90a0SKONRAD Frederic 
199950787628SNicholas Bellinger /* vhost-scsi-pci */
200050787628SNicholas Bellinger 
200150787628SNicholas Bellinger #ifdef CONFIG_VHOST_SCSI
200250787628SNicholas Bellinger static Property vhost_scsi_pci_properties[] = {
200350787628SNicholas Bellinger     DEFINE_PROP_UINT32("vectors", VirtIOPCIProxy, nvectors,
200450787628SNicholas Bellinger                        DEV_NVECTORS_UNSPECIFIED),
200550787628SNicholas Bellinger     DEFINE_PROP_END_OF_LIST(),
200650787628SNicholas Bellinger };
200750787628SNicholas Bellinger 
2008fc079951SMarkus Armbruster static void vhost_scsi_pci_realize(VirtIOPCIProxy *vpci_dev, Error **errp)
200950787628SNicholas Bellinger {
201050787628SNicholas Bellinger     VHostSCSIPCI *dev = VHOST_SCSI_PCI(vpci_dev);
201150787628SNicholas Bellinger     DeviceState *vdev = DEVICE(&dev->vdev);
201250787628SNicholas Bellinger     VirtIOSCSICommon *vs = VIRTIO_SCSI_COMMON(vdev);
201350787628SNicholas Bellinger 
201450787628SNicholas Bellinger     if (vpci_dev->nvectors == DEV_NVECTORS_UNSPECIFIED) {
201550787628SNicholas Bellinger         vpci_dev->nvectors = vs->conf.num_queues + 3;
201650787628SNicholas Bellinger     }
201750787628SNicholas Bellinger 
201850787628SNicholas Bellinger     qdev_set_parent_bus(vdev, BUS(&vpci_dev->bus));
2019fc079951SMarkus Armbruster     object_property_set_bool(OBJECT(vdev), true, "realized", errp);
202050787628SNicholas Bellinger }
202150787628SNicholas Bellinger 
202250787628SNicholas Bellinger static void vhost_scsi_pci_class_init(ObjectClass *klass, void *data)
202350787628SNicholas Bellinger {
202450787628SNicholas Bellinger     DeviceClass *dc = DEVICE_CLASS(klass);
202550787628SNicholas Bellinger     VirtioPCIClass *k = VIRTIO_PCI_CLASS(klass);
202650787628SNicholas Bellinger     PCIDeviceClass *pcidev_k = PCI_DEVICE_CLASS(klass);
2027fc079951SMarkus Armbruster     k->realize = vhost_scsi_pci_realize;
2028125ee0edSMarcel Apfelbaum     set_bit(DEVICE_CATEGORY_STORAGE, dc->categories);
202950787628SNicholas Bellinger     dc->props = vhost_scsi_pci_properties;
203050787628SNicholas Bellinger     pcidev_k->vendor_id = PCI_VENDOR_ID_REDHAT_QUMRANET;
203150787628SNicholas Bellinger     pcidev_k->device_id = PCI_DEVICE_ID_VIRTIO_SCSI;
203250787628SNicholas Bellinger     pcidev_k->revision = 0x00;
203350787628SNicholas Bellinger     pcidev_k->class_id = PCI_CLASS_STORAGE_SCSI;
203450787628SNicholas Bellinger }
203550787628SNicholas Bellinger 
203650787628SNicholas Bellinger static void vhost_scsi_pci_instance_init(Object *obj)
203750787628SNicholas Bellinger {
203850787628SNicholas Bellinger     VHostSCSIPCI *dev = VHOST_SCSI_PCI(obj);
2039c8075cafSGonglei 
2040c8075cafSGonglei     virtio_instance_init_common(obj, &dev->vdev, sizeof(dev->vdev),
2041c8075cafSGonglei                                 TYPE_VHOST_SCSI);
2042d4433f32SGonglei     object_property_add_alias(obj, "bootindex", OBJECT(&dev->vdev),
2043d4433f32SGonglei                               "bootindex", &error_abort);
204450787628SNicholas Bellinger }
204550787628SNicholas Bellinger 
204650787628SNicholas Bellinger static const TypeInfo vhost_scsi_pci_info = {
204750787628SNicholas Bellinger     .name          = TYPE_VHOST_SCSI_PCI,
204850787628SNicholas Bellinger     .parent        = TYPE_VIRTIO_PCI,
204950787628SNicholas Bellinger     .instance_size = sizeof(VHostSCSIPCI),
205050787628SNicholas Bellinger     .instance_init = vhost_scsi_pci_instance_init,
205150787628SNicholas Bellinger     .class_init    = vhost_scsi_pci_class_init,
205250787628SNicholas Bellinger };
205350787628SNicholas Bellinger #endif
205450787628SNicholas Bellinger 
2055e378e88dSKONRAD Frederic /* virtio-balloon-pci */
2056e378e88dSKONRAD Frederic 
2057e378e88dSKONRAD Frederic static Property virtio_balloon_pci_properties[] = {
2058c7bcc85dSPaolo Bonzini     DEFINE_PROP_UINT32("class", VirtIOPCIProxy, class_code, 0),
2059e378e88dSKONRAD Frederic     DEFINE_PROP_END_OF_LIST(),
2060e378e88dSKONRAD Frederic };
2061e378e88dSKONRAD Frederic 
2062fc079951SMarkus Armbruster static void virtio_balloon_pci_realize(VirtIOPCIProxy *vpci_dev, Error **errp)
2063e378e88dSKONRAD Frederic {
2064e378e88dSKONRAD Frederic     VirtIOBalloonPCI *dev = VIRTIO_BALLOON_PCI(vpci_dev);
2065e378e88dSKONRAD Frederic     DeviceState *vdev = DEVICE(&dev->vdev);
2066e378e88dSKONRAD Frederic 
2067e378e88dSKONRAD Frederic     if (vpci_dev->class_code != PCI_CLASS_OTHERS &&
2068e378e88dSKONRAD Frederic         vpci_dev->class_code != PCI_CLASS_MEMORY_RAM) { /* qemu < 1.1 */
2069e378e88dSKONRAD Frederic         vpci_dev->class_code = PCI_CLASS_OTHERS;
2070e378e88dSKONRAD Frederic     }
2071e378e88dSKONRAD Frederic 
2072e378e88dSKONRAD Frederic     qdev_set_parent_bus(vdev, BUS(&vpci_dev->bus));
2073fc079951SMarkus Armbruster     object_property_set_bool(OBJECT(vdev), true, "realized", errp);
2074e378e88dSKONRAD Frederic }
2075e378e88dSKONRAD Frederic 
2076e378e88dSKONRAD Frederic static void virtio_balloon_pci_class_init(ObjectClass *klass, void *data)
2077e378e88dSKONRAD Frederic {
2078e378e88dSKONRAD Frederic     DeviceClass *dc = DEVICE_CLASS(klass);
2079e378e88dSKONRAD Frederic     VirtioPCIClass *k = VIRTIO_PCI_CLASS(klass);
2080e378e88dSKONRAD Frederic     PCIDeviceClass *pcidev_k = PCI_DEVICE_CLASS(klass);
2081fc079951SMarkus Armbruster     k->realize = virtio_balloon_pci_realize;
2082125ee0edSMarcel Apfelbaum     set_bit(DEVICE_CATEGORY_MISC, dc->categories);
2083e378e88dSKONRAD Frederic     dc->props = virtio_balloon_pci_properties;
2084e378e88dSKONRAD Frederic     pcidev_k->vendor_id = PCI_VENDOR_ID_REDHAT_QUMRANET;
2085e378e88dSKONRAD Frederic     pcidev_k->device_id = PCI_DEVICE_ID_VIRTIO_BALLOON;
2086e378e88dSKONRAD Frederic     pcidev_k->revision = VIRTIO_PCI_ABI_VERSION;
2087e378e88dSKONRAD Frederic     pcidev_k->class_id = PCI_CLASS_OTHERS;
2088e378e88dSKONRAD Frederic }
2089e378e88dSKONRAD Frederic 
2090e378e88dSKONRAD Frederic static void virtio_balloon_pci_instance_init(Object *obj)
2091e378e88dSKONRAD Frederic {
2092e378e88dSKONRAD Frederic     VirtIOBalloonPCI *dev = VIRTIO_BALLOON_PCI(obj);
209339b87c7bSShannon Zhao 
2094a6027b0fSDenis V. Lunev     virtio_instance_init_common(obj, &dev->vdev, sizeof(dev->vdev),
2095a6027b0fSDenis V. Lunev                                 TYPE_VIRTIO_BALLOON);
209639b87c7bSShannon Zhao     object_property_add_alias(obj, "guest-stats", OBJECT(&dev->vdev),
209739b87c7bSShannon Zhao                                   "guest-stats", &error_abort);
209839b87c7bSShannon Zhao     object_property_add_alias(obj, "guest-stats-polling-interval",
209939b87c7bSShannon Zhao                               OBJECT(&dev->vdev),
210039b87c7bSShannon Zhao                               "guest-stats-polling-interval", &error_abort);
2101e378e88dSKONRAD Frederic }
2102e378e88dSKONRAD Frederic 
2103e378e88dSKONRAD Frederic static const TypeInfo virtio_balloon_pci_info = {
2104e378e88dSKONRAD Frederic     .name          = TYPE_VIRTIO_BALLOON_PCI,
2105e378e88dSKONRAD Frederic     .parent        = TYPE_VIRTIO_PCI,
2106e378e88dSKONRAD Frederic     .instance_size = sizeof(VirtIOBalloonPCI),
2107e378e88dSKONRAD Frederic     .instance_init = virtio_balloon_pci_instance_init,
2108e378e88dSKONRAD Frederic     .class_init    = virtio_balloon_pci_class_init,
2109e378e88dSKONRAD Frederic };
2110e378e88dSKONRAD Frederic 
2111f7f7464aSKONRAD Frederic /* virtio-serial-pci */
2112f7f7464aSKONRAD Frederic 
2113fc079951SMarkus Armbruster static void virtio_serial_pci_realize(VirtIOPCIProxy *vpci_dev, Error **errp)
2114f7f7464aSKONRAD Frederic {
2115f7f7464aSKONRAD Frederic     VirtIOSerialPCI *dev = VIRTIO_SERIAL_PCI(vpci_dev);
2116f7f7464aSKONRAD Frederic     DeviceState *vdev = DEVICE(&dev->vdev);
211780270a19SKONRAD Frederic     DeviceState *proxy = DEVICE(vpci_dev);
211880270a19SKONRAD Frederic     char *bus_name;
2119f7f7464aSKONRAD Frederic 
2120f7f7464aSKONRAD Frederic     if (vpci_dev->class_code != PCI_CLASS_COMMUNICATION_OTHER &&
2121f7f7464aSKONRAD Frederic         vpci_dev->class_code != PCI_CLASS_DISPLAY_OTHER && /* qemu 0.10 */
2122f7f7464aSKONRAD Frederic         vpci_dev->class_code != PCI_CLASS_OTHERS) {        /* qemu-kvm  */
2123f7f7464aSKONRAD Frederic             vpci_dev->class_code = PCI_CLASS_COMMUNICATION_OTHER;
2124f7f7464aSKONRAD Frederic     }
2125f7f7464aSKONRAD Frederic 
2126f7f7464aSKONRAD Frederic     /* backwards-compatibility with machines that were created with
2127f7f7464aSKONRAD Frederic        DEV_NVECTORS_UNSPECIFIED */
2128f7f7464aSKONRAD Frederic     if (vpci_dev->nvectors == DEV_NVECTORS_UNSPECIFIED) {
2129f7f7464aSKONRAD Frederic         vpci_dev->nvectors = dev->vdev.serial.max_virtserial_ports + 1;
2130f7f7464aSKONRAD Frederic     }
2131f7f7464aSKONRAD Frederic 
213280270a19SKONRAD Frederic     /*
213380270a19SKONRAD Frederic      * For command line compatibility, this sets the virtio-serial-device bus
213480270a19SKONRAD Frederic      * name as before.
213580270a19SKONRAD Frederic      */
213680270a19SKONRAD Frederic     if (proxy->id) {
213780270a19SKONRAD Frederic         bus_name = g_strdup_printf("%s.0", proxy->id);
213880270a19SKONRAD Frederic         virtio_device_set_child_bus_name(VIRTIO_DEVICE(vdev), bus_name);
213980270a19SKONRAD Frederic         g_free(bus_name);
214080270a19SKONRAD Frederic     }
214180270a19SKONRAD Frederic 
2142f7f7464aSKONRAD Frederic     qdev_set_parent_bus(vdev, BUS(&vpci_dev->bus));
2143fc079951SMarkus Armbruster     object_property_set_bool(OBJECT(vdev), true, "realized", errp);
2144f7f7464aSKONRAD Frederic }
2145f7f7464aSKONRAD Frederic 
2146f7f7464aSKONRAD Frederic static Property virtio_serial_pci_properties[] = {
2147f7f7464aSKONRAD Frederic     DEFINE_PROP_BIT("ioeventfd", VirtIOPCIProxy, flags,
2148f7f7464aSKONRAD Frederic                     VIRTIO_PCI_FLAG_USE_IOEVENTFD_BIT, true),
2149f7f7464aSKONRAD Frederic     DEFINE_PROP_UINT32("vectors", VirtIOPCIProxy, nvectors, 2),
2150c7bcc85dSPaolo Bonzini     DEFINE_PROP_UINT32("class", VirtIOPCIProxy, class_code, 0),
2151f7f7464aSKONRAD Frederic     DEFINE_PROP_END_OF_LIST(),
2152f7f7464aSKONRAD Frederic };
2153f7f7464aSKONRAD Frederic 
2154f7f7464aSKONRAD Frederic static void virtio_serial_pci_class_init(ObjectClass *klass, void *data)
2155f7f7464aSKONRAD Frederic {
2156f7f7464aSKONRAD Frederic     DeviceClass *dc = DEVICE_CLASS(klass);
2157f7f7464aSKONRAD Frederic     VirtioPCIClass *k = VIRTIO_PCI_CLASS(klass);
2158f7f7464aSKONRAD Frederic     PCIDeviceClass *pcidev_k = PCI_DEVICE_CLASS(klass);
2159fc079951SMarkus Armbruster     k->realize = virtio_serial_pci_realize;
2160125ee0edSMarcel Apfelbaum     set_bit(DEVICE_CATEGORY_INPUT, dc->categories);
2161f7f7464aSKONRAD Frederic     dc->props = virtio_serial_pci_properties;
2162f7f7464aSKONRAD Frederic     pcidev_k->vendor_id = PCI_VENDOR_ID_REDHAT_QUMRANET;
2163f7f7464aSKONRAD Frederic     pcidev_k->device_id = PCI_DEVICE_ID_VIRTIO_CONSOLE;
2164f7f7464aSKONRAD Frederic     pcidev_k->revision = VIRTIO_PCI_ABI_VERSION;
2165f7f7464aSKONRAD Frederic     pcidev_k->class_id = PCI_CLASS_COMMUNICATION_OTHER;
2166f7f7464aSKONRAD Frederic }
2167f7f7464aSKONRAD Frederic 
2168f7f7464aSKONRAD Frederic static void virtio_serial_pci_instance_init(Object *obj)
2169f7f7464aSKONRAD Frederic {
2170f7f7464aSKONRAD Frederic     VirtIOSerialPCI *dev = VIRTIO_SERIAL_PCI(obj);
2171c8075cafSGonglei 
2172c8075cafSGonglei     virtio_instance_init_common(obj, &dev->vdev, sizeof(dev->vdev),
2173c8075cafSGonglei                                 TYPE_VIRTIO_SERIAL);
2174f7f7464aSKONRAD Frederic }
2175f7f7464aSKONRAD Frederic 
2176f7f7464aSKONRAD Frederic static const TypeInfo virtio_serial_pci_info = {
2177f7f7464aSKONRAD Frederic     .name          = TYPE_VIRTIO_SERIAL_PCI,
2178f7f7464aSKONRAD Frederic     .parent        = TYPE_VIRTIO_PCI,
2179f7f7464aSKONRAD Frederic     .instance_size = sizeof(VirtIOSerialPCI),
2180f7f7464aSKONRAD Frederic     .instance_init = virtio_serial_pci_instance_init,
2181f7f7464aSKONRAD Frederic     .class_init    = virtio_serial_pci_class_init,
2182f7f7464aSKONRAD Frederic };
2183f7f7464aSKONRAD Frederic 
2184e37da394SKONRAD Frederic /* virtio-net-pci */
2185e37da394SKONRAD Frederic 
2186e37da394SKONRAD Frederic static Property virtio_net_properties[] = {
2187e37da394SKONRAD Frederic     DEFINE_PROP_BIT("ioeventfd", VirtIOPCIProxy, flags,
2188e37da394SKONRAD Frederic                     VIRTIO_PCI_FLAG_USE_IOEVENTFD_BIT, false),
2189e37da394SKONRAD Frederic     DEFINE_PROP_UINT32("vectors", VirtIOPCIProxy, nvectors, 3),
2190e37da394SKONRAD Frederic     DEFINE_PROP_END_OF_LIST(),
2191e37da394SKONRAD Frederic };
2192e37da394SKONRAD Frederic 
2193fc079951SMarkus Armbruster static void virtio_net_pci_realize(VirtIOPCIProxy *vpci_dev, Error **errp)
2194e37da394SKONRAD Frederic {
2195800ced8cSKONRAD Frederic     DeviceState *qdev = DEVICE(vpci_dev);
2196e37da394SKONRAD Frederic     VirtIONetPCI *dev = VIRTIO_NET_PCI(vpci_dev);
2197e37da394SKONRAD Frederic     DeviceState *vdev = DEVICE(&dev->vdev);
2198e37da394SKONRAD Frederic 
2199800ced8cSKONRAD Frederic     virtio_net_set_netclient_name(&dev->vdev, qdev->id,
2200800ced8cSKONRAD Frederic                                   object_get_typename(OBJECT(qdev)));
2201e37da394SKONRAD Frederic     qdev_set_parent_bus(vdev, BUS(&vpci_dev->bus));
2202fc079951SMarkus Armbruster     object_property_set_bool(OBJECT(vdev), true, "realized", errp);
2203e37da394SKONRAD Frederic }
2204e37da394SKONRAD Frederic 
2205e37da394SKONRAD Frederic static void virtio_net_pci_class_init(ObjectClass *klass, void *data)
2206e37da394SKONRAD Frederic {
2207e37da394SKONRAD Frederic     DeviceClass *dc = DEVICE_CLASS(klass);
2208e37da394SKONRAD Frederic     PCIDeviceClass *k = PCI_DEVICE_CLASS(klass);
2209e37da394SKONRAD Frederic     VirtioPCIClass *vpciklass = VIRTIO_PCI_CLASS(klass);
2210e37da394SKONRAD Frederic 
2211e37da394SKONRAD Frederic     k->romfile = "efi-virtio.rom";
2212e37da394SKONRAD Frederic     k->vendor_id = PCI_VENDOR_ID_REDHAT_QUMRANET;
2213e37da394SKONRAD Frederic     k->device_id = PCI_DEVICE_ID_VIRTIO_NET;
2214e37da394SKONRAD Frederic     k->revision = VIRTIO_PCI_ABI_VERSION;
2215e37da394SKONRAD Frederic     k->class_id = PCI_CLASS_NETWORK_ETHERNET;
2216125ee0edSMarcel Apfelbaum     set_bit(DEVICE_CATEGORY_NETWORK, dc->categories);
2217e37da394SKONRAD Frederic     dc->props = virtio_net_properties;
2218fc079951SMarkus Armbruster     vpciklass->realize = virtio_net_pci_realize;
2219e37da394SKONRAD Frederic }
2220e37da394SKONRAD Frederic 
2221e37da394SKONRAD Frederic static void virtio_net_pci_instance_init(Object *obj)
2222e37da394SKONRAD Frederic {
2223e37da394SKONRAD Frederic     VirtIONetPCI *dev = VIRTIO_NET_PCI(obj);
2224c8075cafSGonglei 
2225c8075cafSGonglei     virtio_instance_init_common(obj, &dev->vdev, sizeof(dev->vdev),
2226c8075cafSGonglei                                 TYPE_VIRTIO_NET);
22270cf63c3eSGonglei     object_property_add_alias(obj, "bootindex", OBJECT(&dev->vdev),
22280cf63c3eSGonglei                               "bootindex", &error_abort);
2229e37da394SKONRAD Frederic }
2230e37da394SKONRAD Frederic 
2231e37da394SKONRAD Frederic static const TypeInfo virtio_net_pci_info = {
2232e37da394SKONRAD Frederic     .name          = TYPE_VIRTIO_NET_PCI,
2233e37da394SKONRAD Frederic     .parent        = TYPE_VIRTIO_PCI,
2234e37da394SKONRAD Frederic     .instance_size = sizeof(VirtIONetPCI),
2235e37da394SKONRAD Frederic     .instance_init = virtio_net_pci_instance_init,
2236e37da394SKONRAD Frederic     .class_init    = virtio_net_pci_class_init,
2237e37da394SKONRAD Frederic };
2238e37da394SKONRAD Frederic 
223959ccd20aSKONRAD Frederic /* virtio-rng-pci */
224059ccd20aSKONRAD Frederic 
2241fc079951SMarkus Armbruster static void virtio_rng_pci_realize(VirtIOPCIProxy *vpci_dev, Error **errp)
224259ccd20aSKONRAD Frederic {
224359ccd20aSKONRAD Frederic     VirtIORngPCI *vrng = VIRTIO_RNG_PCI(vpci_dev);
224459ccd20aSKONRAD Frederic     DeviceState *vdev = DEVICE(&vrng->vdev);
2245fc079951SMarkus Armbruster     Error *err = NULL;
224659ccd20aSKONRAD Frederic 
224759ccd20aSKONRAD Frederic     qdev_set_parent_bus(vdev, BUS(&vpci_dev->bus));
2248fc079951SMarkus Armbruster     object_property_set_bool(OBJECT(vdev), true, "realized", &err);
2249fc079951SMarkus Armbruster     if (err) {
2250fc079951SMarkus Armbruster         error_propagate(errp, err);
2251fc079951SMarkus Armbruster         return;
225259ccd20aSKONRAD Frederic     }
225359ccd20aSKONRAD Frederic 
225459ccd20aSKONRAD Frederic     object_property_set_link(OBJECT(vrng),
22555b456438SCole Robinson                              OBJECT(vrng->vdev.conf.rng), "rng",
225659ccd20aSKONRAD Frederic                              NULL);
225759ccd20aSKONRAD Frederic }
225859ccd20aSKONRAD Frederic 
225959ccd20aSKONRAD Frederic static void virtio_rng_pci_class_init(ObjectClass *klass, void *data)
226059ccd20aSKONRAD Frederic {
226159ccd20aSKONRAD Frederic     DeviceClass *dc = DEVICE_CLASS(klass);
226259ccd20aSKONRAD Frederic     VirtioPCIClass *k = VIRTIO_PCI_CLASS(klass);
226359ccd20aSKONRAD Frederic     PCIDeviceClass *pcidev_k = PCI_DEVICE_CLASS(klass);
226459ccd20aSKONRAD Frederic 
2265fc079951SMarkus Armbruster     k->realize = virtio_rng_pci_realize;
2266125ee0edSMarcel Apfelbaum     set_bit(DEVICE_CATEGORY_MISC, dc->categories);
226759ccd20aSKONRAD Frederic 
226859ccd20aSKONRAD Frederic     pcidev_k->vendor_id = PCI_VENDOR_ID_REDHAT_QUMRANET;
226959ccd20aSKONRAD Frederic     pcidev_k->device_id = PCI_DEVICE_ID_VIRTIO_RNG;
227059ccd20aSKONRAD Frederic     pcidev_k->revision = VIRTIO_PCI_ABI_VERSION;
227159ccd20aSKONRAD Frederic     pcidev_k->class_id = PCI_CLASS_OTHERS;
227259ccd20aSKONRAD Frederic }
227359ccd20aSKONRAD Frederic 
227459ccd20aSKONRAD Frederic static void virtio_rng_initfn(Object *obj)
227559ccd20aSKONRAD Frederic {
227659ccd20aSKONRAD Frederic     VirtIORngPCI *dev = VIRTIO_RNG_PCI(obj);
2277c8075cafSGonglei 
2278c8075cafSGonglei     virtio_instance_init_common(obj, &dev->vdev, sizeof(dev->vdev),
2279c8075cafSGonglei                                 TYPE_VIRTIO_RNG);
2280cbd5ac69SPaolo Bonzini     object_property_add_alias(obj, "rng", OBJECT(&dev->vdev), "rng",
2281cbd5ac69SPaolo Bonzini                               &error_abort);
228259ccd20aSKONRAD Frederic }
228359ccd20aSKONRAD Frederic 
228459ccd20aSKONRAD Frederic static const TypeInfo virtio_rng_pci_info = {
228559ccd20aSKONRAD Frederic     .name          = TYPE_VIRTIO_RNG_PCI,
228659ccd20aSKONRAD Frederic     .parent        = TYPE_VIRTIO_PCI,
228759ccd20aSKONRAD Frederic     .instance_size = sizeof(VirtIORngPCI),
228859ccd20aSKONRAD Frederic     .instance_init = virtio_rng_initfn,
228959ccd20aSKONRAD Frederic     .class_init    = virtio_rng_pci_class_init,
229059ccd20aSKONRAD Frederic };
229159ccd20aSKONRAD Frederic 
2292f958c8aaSGerd Hoffmann /* virtio-input-pci */
2293f958c8aaSGerd Hoffmann 
22946f2b9a5bSGerd Hoffmann static Property virtio_input_pci_properties[] = {
2295710e2d90SGerd Hoffmann     DEFINE_PROP_UINT32("vectors", VirtIOPCIProxy, nvectors, 2),
2296710e2d90SGerd Hoffmann     DEFINE_PROP_END_OF_LIST(),
2297710e2d90SGerd Hoffmann };
2298710e2d90SGerd Hoffmann 
2299f958c8aaSGerd Hoffmann static void virtio_input_pci_realize(VirtIOPCIProxy *vpci_dev, Error **errp)
2300f958c8aaSGerd Hoffmann {
2301f958c8aaSGerd Hoffmann     VirtIOInputPCI *vinput = VIRTIO_INPUT_PCI(vpci_dev);
2302f958c8aaSGerd Hoffmann     DeviceState *vdev = DEVICE(&vinput->vdev);
2303f958c8aaSGerd Hoffmann 
2304f958c8aaSGerd Hoffmann     qdev_set_parent_bus(vdev, BUS(&vpci_dev->bus));
2305f958c8aaSGerd Hoffmann     /* force virtio-1.0 */
2306f958c8aaSGerd Hoffmann     vpci_dev->flags &= ~VIRTIO_PCI_FLAG_DISABLE_MODERN;
2307f958c8aaSGerd Hoffmann     vpci_dev->flags |= VIRTIO_PCI_FLAG_DISABLE_LEGACY;
2308f958c8aaSGerd Hoffmann     object_property_set_bool(OBJECT(vdev), true, "realized", errp);
2309f958c8aaSGerd Hoffmann }
2310f958c8aaSGerd Hoffmann 
2311f958c8aaSGerd Hoffmann static void virtio_input_pci_class_init(ObjectClass *klass, void *data)
2312f958c8aaSGerd Hoffmann {
2313f958c8aaSGerd Hoffmann     DeviceClass *dc = DEVICE_CLASS(klass);
2314f958c8aaSGerd Hoffmann     VirtioPCIClass *k = VIRTIO_PCI_CLASS(klass);
2315f958c8aaSGerd Hoffmann     PCIDeviceClass *pcidev_k = PCI_DEVICE_CLASS(klass);
2316f958c8aaSGerd Hoffmann 
23176f2b9a5bSGerd Hoffmann     dc->props = virtio_input_pci_properties;
2318f958c8aaSGerd Hoffmann     k->realize = virtio_input_pci_realize;
2319f958c8aaSGerd Hoffmann     set_bit(DEVICE_CATEGORY_INPUT, dc->categories);
2320f958c8aaSGerd Hoffmann 
2321f958c8aaSGerd Hoffmann     pcidev_k->class_id = PCI_CLASS_INPUT_OTHER;
2322f958c8aaSGerd Hoffmann }
2323f958c8aaSGerd Hoffmann 
2324710e2d90SGerd Hoffmann static void virtio_input_hid_kbd_pci_class_init(ObjectClass *klass, void *data)
2325710e2d90SGerd Hoffmann {
2326710e2d90SGerd Hoffmann     PCIDeviceClass *pcidev_k = PCI_DEVICE_CLASS(klass);
2327710e2d90SGerd Hoffmann 
2328710e2d90SGerd Hoffmann     pcidev_k->class_id = PCI_CLASS_INPUT_KEYBOARD;
2329710e2d90SGerd Hoffmann }
2330710e2d90SGerd Hoffmann 
2331710e2d90SGerd Hoffmann static void virtio_input_hid_mouse_pci_class_init(ObjectClass *klass,
2332710e2d90SGerd Hoffmann                                                   void *data)
2333710e2d90SGerd Hoffmann {
2334710e2d90SGerd Hoffmann     PCIDeviceClass *pcidev_k = PCI_DEVICE_CLASS(klass);
2335710e2d90SGerd Hoffmann 
2336710e2d90SGerd Hoffmann     pcidev_k->class_id = PCI_CLASS_INPUT_MOUSE;
2337710e2d90SGerd Hoffmann }
2338710e2d90SGerd Hoffmann 
2339710e2d90SGerd Hoffmann static void virtio_keyboard_initfn(Object *obj)
2340710e2d90SGerd Hoffmann {
2341710e2d90SGerd Hoffmann     VirtIOInputHIDPCI *dev = VIRTIO_INPUT_HID_PCI(obj);
23426f2b9a5bSGerd Hoffmann 
23436f2b9a5bSGerd Hoffmann     virtio_instance_init_common(obj, &dev->vdev, sizeof(dev->vdev),
23446f2b9a5bSGerd Hoffmann                                 TYPE_VIRTIO_KEYBOARD);
2345710e2d90SGerd Hoffmann }
2346710e2d90SGerd Hoffmann 
2347710e2d90SGerd Hoffmann static void virtio_mouse_initfn(Object *obj)
2348710e2d90SGerd Hoffmann {
2349710e2d90SGerd Hoffmann     VirtIOInputHIDPCI *dev = VIRTIO_INPUT_HID_PCI(obj);
23506f2b9a5bSGerd Hoffmann 
23516f2b9a5bSGerd Hoffmann     virtio_instance_init_common(obj, &dev->vdev, sizeof(dev->vdev),
23526f2b9a5bSGerd Hoffmann                                 TYPE_VIRTIO_MOUSE);
2353710e2d90SGerd Hoffmann }
2354710e2d90SGerd Hoffmann 
2355710e2d90SGerd Hoffmann static void virtio_tablet_initfn(Object *obj)
2356710e2d90SGerd Hoffmann {
2357710e2d90SGerd Hoffmann     VirtIOInputHIDPCI *dev = VIRTIO_INPUT_HID_PCI(obj);
23586f2b9a5bSGerd Hoffmann 
23596f2b9a5bSGerd Hoffmann     virtio_instance_init_common(obj, &dev->vdev, sizeof(dev->vdev),
23606f2b9a5bSGerd Hoffmann                                 TYPE_VIRTIO_TABLET);
2361710e2d90SGerd Hoffmann }
2362710e2d90SGerd Hoffmann 
2363f958c8aaSGerd Hoffmann static const TypeInfo virtio_input_pci_info = {
2364f958c8aaSGerd Hoffmann     .name          = TYPE_VIRTIO_INPUT_PCI,
2365f958c8aaSGerd Hoffmann     .parent        = TYPE_VIRTIO_PCI,
2366f958c8aaSGerd Hoffmann     .instance_size = sizeof(VirtIOInputPCI),
2367f958c8aaSGerd Hoffmann     .class_init    = virtio_input_pci_class_init,
2368f958c8aaSGerd Hoffmann     .abstract      = true,
2369f958c8aaSGerd Hoffmann };
2370f958c8aaSGerd Hoffmann 
2371710e2d90SGerd Hoffmann static const TypeInfo virtio_input_hid_pci_info = {
2372710e2d90SGerd Hoffmann     .name          = TYPE_VIRTIO_INPUT_HID_PCI,
2373710e2d90SGerd Hoffmann     .parent        = TYPE_VIRTIO_INPUT_PCI,
2374710e2d90SGerd Hoffmann     .instance_size = sizeof(VirtIOInputHIDPCI),
2375710e2d90SGerd Hoffmann     .abstract      = true,
2376710e2d90SGerd Hoffmann };
2377710e2d90SGerd Hoffmann 
2378710e2d90SGerd Hoffmann static const TypeInfo virtio_keyboard_pci_info = {
2379710e2d90SGerd Hoffmann     .name          = TYPE_VIRTIO_KEYBOARD_PCI,
2380710e2d90SGerd Hoffmann     .parent        = TYPE_VIRTIO_INPUT_HID_PCI,
2381710e2d90SGerd Hoffmann     .class_init    = virtio_input_hid_kbd_pci_class_init,
2382710e2d90SGerd Hoffmann     .instance_size = sizeof(VirtIOInputHIDPCI),
2383710e2d90SGerd Hoffmann     .instance_init = virtio_keyboard_initfn,
2384710e2d90SGerd Hoffmann };
2385710e2d90SGerd Hoffmann 
2386710e2d90SGerd Hoffmann static const TypeInfo virtio_mouse_pci_info = {
2387710e2d90SGerd Hoffmann     .name          = TYPE_VIRTIO_MOUSE_PCI,
2388710e2d90SGerd Hoffmann     .parent        = TYPE_VIRTIO_INPUT_HID_PCI,
2389710e2d90SGerd Hoffmann     .class_init    = virtio_input_hid_mouse_pci_class_init,
2390710e2d90SGerd Hoffmann     .instance_size = sizeof(VirtIOInputHIDPCI),
2391710e2d90SGerd Hoffmann     .instance_init = virtio_mouse_initfn,
2392710e2d90SGerd Hoffmann };
2393710e2d90SGerd Hoffmann 
2394710e2d90SGerd Hoffmann static const TypeInfo virtio_tablet_pci_info = {
2395710e2d90SGerd Hoffmann     .name          = TYPE_VIRTIO_TABLET_PCI,
2396710e2d90SGerd Hoffmann     .parent        = TYPE_VIRTIO_INPUT_HID_PCI,
2397710e2d90SGerd Hoffmann     .instance_size = sizeof(VirtIOInputHIDPCI),
2398710e2d90SGerd Hoffmann     .instance_init = virtio_tablet_initfn,
2399710e2d90SGerd Hoffmann };
2400710e2d90SGerd Hoffmann 
2401c6047e96SMarkus Armbruster #ifdef CONFIG_LINUX
2402c6047e96SMarkus Armbruster static void virtio_host_initfn(Object *obj)
2403c6047e96SMarkus Armbruster {
2404c6047e96SMarkus Armbruster     VirtIOInputHostPCI *dev = VIRTIO_INPUT_HOST_PCI(obj);
2405c6047e96SMarkus Armbruster 
2406c6047e96SMarkus Armbruster     virtio_instance_init_common(obj, &dev->vdev, sizeof(dev->vdev),
2407c6047e96SMarkus Armbruster                                 TYPE_VIRTIO_INPUT_HOST);
2408c6047e96SMarkus Armbruster }
2409c6047e96SMarkus Armbruster 
2410006a5edeSGerd Hoffmann static const TypeInfo virtio_host_pci_info = {
2411006a5edeSGerd Hoffmann     .name          = TYPE_VIRTIO_INPUT_HOST_PCI,
2412006a5edeSGerd Hoffmann     .parent        = TYPE_VIRTIO_INPUT_PCI,
2413006a5edeSGerd Hoffmann     .instance_size = sizeof(VirtIOInputHostPCI),
2414006a5edeSGerd Hoffmann     .instance_init = virtio_host_initfn,
2415006a5edeSGerd Hoffmann };
2416c6047e96SMarkus Armbruster #endif
2417006a5edeSGerd Hoffmann 
24180a2acf5eSKONRAD Frederic /* virtio-pci-bus */
24190a2acf5eSKONRAD Frederic 
2420ac7af112SAndreas Färber static void virtio_pci_bus_new(VirtioBusState *bus, size_t bus_size,
2421ac7af112SAndreas Färber                                VirtIOPCIProxy *dev)
24220a2acf5eSKONRAD Frederic {
24230a2acf5eSKONRAD Frederic     DeviceState *qdev = DEVICE(dev);
2424f4dd69aaSKONRAD Frederic     char virtio_bus_name[] = "virtio-bus";
2425f4dd69aaSKONRAD Frederic 
2426fb17dfe0SAndreas Färber     qbus_create_inplace(bus, bus_size, TYPE_VIRTIO_PCI_BUS, qdev,
2427f4dd69aaSKONRAD Frederic                         virtio_bus_name);
24280a2acf5eSKONRAD Frederic }
24290a2acf5eSKONRAD Frederic 
24300a2acf5eSKONRAD Frederic static void virtio_pci_bus_class_init(ObjectClass *klass, void *data)
24310a2acf5eSKONRAD Frederic {
24320a2acf5eSKONRAD Frederic     BusClass *bus_class = BUS_CLASS(klass);
24330a2acf5eSKONRAD Frederic     VirtioBusClass *k = VIRTIO_BUS_CLASS(klass);
24340a2acf5eSKONRAD Frederic     bus_class->max_dev = 1;
24350a2acf5eSKONRAD Frederic     k->notify = virtio_pci_notify;
24360a2acf5eSKONRAD Frederic     k->save_config = virtio_pci_save_config;
24370a2acf5eSKONRAD Frederic     k->load_config = virtio_pci_load_config;
24380a2acf5eSKONRAD Frederic     k->save_queue = virtio_pci_save_queue;
24390a2acf5eSKONRAD Frederic     k->load_queue = virtio_pci_load_queue;
2440a6df8adfSJason Wang     k->save_extra_state = virtio_pci_save_extra_state;
2441a6df8adfSJason Wang     k->load_extra_state = virtio_pci_load_extra_state;
2442a6df8adfSJason Wang     k->has_extra_state = virtio_pci_has_extra_state;
24430a2acf5eSKONRAD Frederic     k->query_guest_notifiers = virtio_pci_query_guest_notifiers;
24440a2acf5eSKONRAD Frederic     k->set_host_notifier = virtio_pci_set_host_notifier;
24450a2acf5eSKONRAD Frederic     k->set_guest_notifiers = virtio_pci_set_guest_notifiers;
24460a2acf5eSKONRAD Frederic     k->vmstate_change = virtio_pci_vmstate_change;
2447085bccb7SKONRAD Frederic     k->device_plugged = virtio_pci_device_plugged;
244806a13073SPaolo Bonzini     k->device_unplugged = virtio_pci_device_unplugged;
2449e0d686bfSJason Wang     k->query_nvectors = virtio_pci_query_nvectors;
24500a2acf5eSKONRAD Frederic }
24510a2acf5eSKONRAD Frederic 
24520a2acf5eSKONRAD Frederic static const TypeInfo virtio_pci_bus_info = {
24530a2acf5eSKONRAD Frederic     .name          = TYPE_VIRTIO_PCI_BUS,
24540a2acf5eSKONRAD Frederic     .parent        = TYPE_VIRTIO_BUS,
24550a2acf5eSKONRAD Frederic     .instance_size = sizeof(VirtioPCIBusState),
24560a2acf5eSKONRAD Frederic     .class_init    = virtio_pci_bus_class_init,
24570a2acf5eSKONRAD Frederic };
24580a2acf5eSKONRAD Frederic 
245983f7d43aSAndreas Färber static void virtio_pci_register_types(void)
246053c25ceaSPaul Brook {
246159ccd20aSKONRAD Frederic     type_register_static(&virtio_rng_pci_info);
2462f958c8aaSGerd Hoffmann     type_register_static(&virtio_input_pci_info);
2463710e2d90SGerd Hoffmann     type_register_static(&virtio_input_hid_pci_info);
2464710e2d90SGerd Hoffmann     type_register_static(&virtio_keyboard_pci_info);
2465710e2d90SGerd Hoffmann     type_register_static(&virtio_mouse_pci_info);
2466710e2d90SGerd Hoffmann     type_register_static(&virtio_tablet_pci_info);
2467c6047e96SMarkus Armbruster #ifdef CONFIG_LINUX
2468006a5edeSGerd Hoffmann     type_register_static(&virtio_host_pci_info);
2469c6047e96SMarkus Armbruster #endif
24700a2acf5eSKONRAD Frederic     type_register_static(&virtio_pci_bus_info);
2471085bccb7SKONRAD Frederic     type_register_static(&virtio_pci_info);
247260653b28SPaolo Bonzini #ifdef CONFIG_VIRTFS
2473234a336fSKONRAD Frederic     type_register_static(&virtio_9p_pci_info);
247460653b28SPaolo Bonzini #endif
2475653ced07SKONRAD Frederic     type_register_static(&virtio_blk_pci_info);
2476bc7b90a0SKONRAD Frederic     type_register_static(&virtio_scsi_pci_info);
2477e378e88dSKONRAD Frederic     type_register_static(&virtio_balloon_pci_info);
2478f7f7464aSKONRAD Frederic     type_register_static(&virtio_serial_pci_info);
2479e37da394SKONRAD Frederic     type_register_static(&virtio_net_pci_info);
248050787628SNicholas Bellinger #ifdef CONFIG_VHOST_SCSI
248150787628SNicholas Bellinger     type_register_static(&vhost_scsi_pci_info);
248250787628SNicholas Bellinger #endif
248353c25ceaSPaul Brook }
248453c25ceaSPaul Brook 
248583f7d43aSAndreas Färber type_init(virtio_pci_register_types)
2486