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 189b8bfe21SPeter Maydell #include "qemu/osdep.h" 1953c25ceaSPaul Brook 20cbbe4f50SMichael S. Tsirkin #include "standard-headers/linux/virtio_pci.h" 210d09e41aSPaolo Bonzini #include "hw/virtio/virtio.h" 2283c9f4caSPaolo Bonzini #include "hw/pci/pci.h" 23da34e65cSMarkus Armbruster #include "qapi/error.h" 241de7afc9SPaolo Bonzini #include "qemu/error-report.h" 2583c9f4caSPaolo Bonzini #include "hw/pci/msi.h" 2683c9f4caSPaolo Bonzini #include "hw/pci/msix.h" 2783c9f4caSPaolo Bonzini #include "hw/loader.h" 289c17d615SPaolo Bonzini #include "sysemu/kvm.h" 2947b43a1fSPaolo Bonzini #include "virtio-pci.h" 301de7afc9SPaolo Bonzini #include "qemu/range.h" 310d09e41aSPaolo Bonzini #include "hw/virtio/virtio-bus.h" 3224a6e7f4SKONRAD Frederic #include "qapi/visitor.h" 3353c25ceaSPaul Brook 34cbbe4f50SMichael S. Tsirkin #define VIRTIO_PCI_REGION_SIZE(dev) VIRTIO_PCI_CONFIG_OFF(msix_present(dev)) 35aba800a3SMichael S. Tsirkin 36c17bef33SMichael S. Tsirkin #undef VIRTIO_PCI_CONFIG 37c17bef33SMichael S. Tsirkin 38aba800a3SMichael S. Tsirkin /* The remaining space is defined by each driver as the per-driver 39aba800a3SMichael S. Tsirkin * configuration space */ 40cbbe4f50SMichael S. Tsirkin #define VIRTIO_PCI_CONFIG_SIZE(dev) VIRTIO_PCI_CONFIG_OFF(msix_enabled(dev)) 4153c25ceaSPaul Brook 42ac7af112SAndreas Färber static void virtio_pci_bus_new(VirtioBusState *bus, size_t bus_size, 43ac7af112SAndreas Färber VirtIOPCIProxy *dev); 4475fd6f13SGerd Hoffmann static void virtio_pci_reset(DeviceState *qdev); 45d51fcfacSKONRAD Frederic 4653c25ceaSPaul Brook /* virtio device */ 47d2a0ccc6SMichael S. Tsirkin /* DeviceState to VirtIOPCIProxy. For use off data-path. TODO: use QOM. */ 48d2a0ccc6SMichael S. Tsirkin static inline VirtIOPCIProxy *to_virtio_pci_proxy(DeviceState *d) 4953c25ceaSPaul Brook { 50d2a0ccc6SMichael S. Tsirkin return container_of(d, VirtIOPCIProxy, pci_dev.qdev); 51d2a0ccc6SMichael S. Tsirkin } 52d2a0ccc6SMichael S. Tsirkin 53d2a0ccc6SMichael S. Tsirkin /* DeviceState to VirtIOPCIProxy. Note: used on datapath, 54d2a0ccc6SMichael S. Tsirkin * be careful and test performance if you change this. 55d2a0ccc6SMichael S. Tsirkin */ 56d2a0ccc6SMichael S. Tsirkin static inline VirtIOPCIProxy *to_virtio_pci_proxy_fast(DeviceState *d) 57d2a0ccc6SMichael S. Tsirkin { 58d2a0ccc6SMichael S. Tsirkin return container_of(d, VirtIOPCIProxy, pci_dev.qdev); 59d2a0ccc6SMichael S. Tsirkin } 60d2a0ccc6SMichael S. Tsirkin 61d2a0ccc6SMichael S. Tsirkin static void virtio_pci_notify(DeviceState *d, uint16_t vector) 62d2a0ccc6SMichael S. Tsirkin { 63d2a0ccc6SMichael S. Tsirkin VirtIOPCIProxy *proxy = to_virtio_pci_proxy_fast(d); 64a3fc66d9SPaolo Bonzini 65aba800a3SMichael S. Tsirkin if (msix_enabled(&proxy->pci_dev)) 66aba800a3SMichael S. Tsirkin msix_notify(&proxy->pci_dev, vector); 67a3fc66d9SPaolo Bonzini else { 68a3fc66d9SPaolo Bonzini VirtIODevice *vdev = virtio_bus_get_device(&proxy->bus); 690687c37cSPaolo Bonzini pci_set_irq(&proxy->pci_dev, atomic_read(&vdev->isr) & 1); 70a3fc66d9SPaolo Bonzini } 7153c25ceaSPaul Brook } 7253c25ceaSPaul Brook 73d2a0ccc6SMichael S. Tsirkin static void virtio_pci_save_config(DeviceState *d, QEMUFile *f) 74ff24bd58SMichael S. Tsirkin { 75d2a0ccc6SMichael S. Tsirkin VirtIOPCIProxy *proxy = to_virtio_pci_proxy(d); 76a3fc66d9SPaolo Bonzini VirtIODevice *vdev = virtio_bus_get_device(&proxy->bus); 77a3fc66d9SPaolo Bonzini 78ff24bd58SMichael S. Tsirkin pci_device_save(&proxy->pci_dev, f); 79ff24bd58SMichael S. Tsirkin msix_save(&proxy->pci_dev, f); 80ff24bd58SMichael S. Tsirkin if (msix_present(&proxy->pci_dev)) 81a3fc66d9SPaolo Bonzini qemu_put_be16(f, vdev->config_vector); 82ff24bd58SMichael S. Tsirkin } 83ff24bd58SMichael S. Tsirkin 84b81b948eSDr. David Alan Gilbert static const VMStateDescription vmstate_virtio_pci_modern_queue_state = { 85b81b948eSDr. David Alan Gilbert .name = "virtio_pci/modern_queue_state", 86b81b948eSDr. David Alan Gilbert .version_id = 1, 87b81b948eSDr. David Alan Gilbert .minimum_version_id = 1, 88b81b948eSDr. David Alan Gilbert .fields = (VMStateField[]) { 89b81b948eSDr. David Alan Gilbert VMSTATE_UINT16(num, VirtIOPCIQueue), 90b81b948eSDr. David Alan Gilbert VMSTATE_UNUSED(1), /* enabled was stored as be16 */ 91b81b948eSDr. David Alan Gilbert VMSTATE_BOOL(enabled, VirtIOPCIQueue), 92b81b948eSDr. David Alan Gilbert VMSTATE_UINT32_ARRAY(desc, VirtIOPCIQueue, 2), 93b81b948eSDr. David Alan Gilbert VMSTATE_UINT32_ARRAY(avail, VirtIOPCIQueue, 2), 94b81b948eSDr. David Alan Gilbert VMSTATE_UINT32_ARRAY(used, VirtIOPCIQueue, 2), 95b81b948eSDr. David Alan Gilbert VMSTATE_END_OF_LIST() 96a6df8adfSJason Wang } 97a6df8adfSJason Wang }; 98a6df8adfSJason Wang 99a6df8adfSJason Wang static bool virtio_pci_modern_state_needed(void *opaque) 100a6df8adfSJason Wang { 101a6df8adfSJason Wang VirtIOPCIProxy *proxy = opaque; 102a6df8adfSJason Wang 1039a4c0e22SMarcel Apfelbaum return virtio_pci_modern(proxy); 104a6df8adfSJason Wang } 105a6df8adfSJason Wang 106b81b948eSDr. David Alan Gilbert static const VMStateDescription vmstate_virtio_pci_modern_state_sub = { 107a6df8adfSJason Wang .name = "virtio_pci/modern_state", 108a6df8adfSJason Wang .version_id = 1, 109a6df8adfSJason Wang .minimum_version_id = 1, 110a6df8adfSJason Wang .needed = &virtio_pci_modern_state_needed, 111a6df8adfSJason Wang .fields = (VMStateField[]) { 112b81b948eSDr. David Alan Gilbert VMSTATE_UINT32(dfselect, VirtIOPCIProxy), 113b81b948eSDr. David Alan Gilbert VMSTATE_UINT32(gfselect, VirtIOPCIProxy), 114b81b948eSDr. David Alan Gilbert VMSTATE_UINT32_ARRAY(guest_features, VirtIOPCIProxy, 2), 115b81b948eSDr. David Alan Gilbert VMSTATE_STRUCT_ARRAY(vqs, VirtIOPCIProxy, VIRTIO_QUEUE_MAX, 0, 116b81b948eSDr. David Alan Gilbert vmstate_virtio_pci_modern_queue_state, 117b81b948eSDr. David Alan Gilbert VirtIOPCIQueue), 118a6df8adfSJason Wang VMSTATE_END_OF_LIST() 119a6df8adfSJason Wang } 120a6df8adfSJason Wang }; 121a6df8adfSJason Wang 122a6df8adfSJason Wang static const VMStateDescription vmstate_virtio_pci = { 123a6df8adfSJason Wang .name = "virtio_pci", 124a6df8adfSJason Wang .version_id = 1, 125a6df8adfSJason Wang .minimum_version_id = 1, 126a6df8adfSJason Wang .minimum_version_id_old = 1, 127a6df8adfSJason Wang .fields = (VMStateField[]) { 128a6df8adfSJason Wang VMSTATE_END_OF_LIST() 129a6df8adfSJason Wang }, 130a6df8adfSJason Wang .subsections = (const VMStateDescription*[]) { 131b81b948eSDr. David Alan Gilbert &vmstate_virtio_pci_modern_state_sub, 132a6df8adfSJason Wang NULL 133a6df8adfSJason Wang } 134a6df8adfSJason Wang }; 135a6df8adfSJason Wang 136b81b948eSDr. David Alan Gilbert static bool virtio_pci_has_extra_state(DeviceState *d) 137b81b948eSDr. David Alan Gilbert { 138b81b948eSDr. David Alan Gilbert VirtIOPCIProxy *proxy = to_virtio_pci_proxy(d); 139b81b948eSDr. David Alan Gilbert 140b81b948eSDr. David Alan Gilbert return proxy->flags & VIRTIO_PCI_FLAG_MIGRATE_EXTRA; 141b81b948eSDr. David Alan Gilbert } 142b81b948eSDr. David Alan Gilbert 143a6df8adfSJason Wang static void virtio_pci_save_extra_state(DeviceState *d, QEMUFile *f) 144a6df8adfSJason Wang { 145a6df8adfSJason Wang VirtIOPCIProxy *proxy = to_virtio_pci_proxy(d); 146a6df8adfSJason Wang 147a6df8adfSJason Wang vmstate_save_state(f, &vmstate_virtio_pci, proxy, NULL); 148a6df8adfSJason Wang } 149a6df8adfSJason Wang 150a6df8adfSJason Wang static int virtio_pci_load_extra_state(DeviceState *d, QEMUFile *f) 151a6df8adfSJason Wang { 152a6df8adfSJason Wang VirtIOPCIProxy *proxy = to_virtio_pci_proxy(d); 153a6df8adfSJason Wang 154a6df8adfSJason Wang return vmstate_load_state(f, &vmstate_virtio_pci, proxy, 1); 155a6df8adfSJason Wang } 156a6df8adfSJason Wang 157d2a0ccc6SMichael S. Tsirkin static void virtio_pci_save_queue(DeviceState *d, int n, QEMUFile *f) 158ff24bd58SMichael S. Tsirkin { 159d2a0ccc6SMichael S. Tsirkin VirtIOPCIProxy *proxy = to_virtio_pci_proxy(d); 160a3fc66d9SPaolo Bonzini VirtIODevice *vdev = virtio_bus_get_device(&proxy->bus); 161a3fc66d9SPaolo Bonzini 162ff24bd58SMichael S. Tsirkin if (msix_present(&proxy->pci_dev)) 163a3fc66d9SPaolo Bonzini qemu_put_be16(f, virtio_queue_vector(vdev, n)); 164ff24bd58SMichael S. Tsirkin } 165ff24bd58SMichael S. Tsirkin 166d2a0ccc6SMichael S. Tsirkin static int virtio_pci_load_config(DeviceState *d, QEMUFile *f) 167ff24bd58SMichael S. Tsirkin { 168d2a0ccc6SMichael S. Tsirkin VirtIOPCIProxy *proxy = to_virtio_pci_proxy(d); 169a3fc66d9SPaolo Bonzini VirtIODevice *vdev = virtio_bus_get_device(&proxy->bus); 170a3fc66d9SPaolo Bonzini 171ff24bd58SMichael S. Tsirkin int ret; 172ff24bd58SMichael S. Tsirkin ret = pci_device_load(&proxy->pci_dev, f); 173e6da7680SMichael S. Tsirkin if (ret) { 174ff24bd58SMichael S. Tsirkin return ret; 175e6da7680SMichael S. Tsirkin } 1763cac001eSMichael S. Tsirkin msix_unuse_all_vectors(&proxy->pci_dev); 177ff24bd58SMichael S. Tsirkin msix_load(&proxy->pci_dev, f); 178e6da7680SMichael S. Tsirkin if (msix_present(&proxy->pci_dev)) { 179a3fc66d9SPaolo Bonzini qemu_get_be16s(f, &vdev->config_vector); 180e6da7680SMichael S. Tsirkin } else { 181a3fc66d9SPaolo Bonzini vdev->config_vector = VIRTIO_NO_VECTOR; 182e6da7680SMichael S. Tsirkin } 183a3fc66d9SPaolo Bonzini if (vdev->config_vector != VIRTIO_NO_VECTOR) { 184a3fc66d9SPaolo Bonzini return msix_vector_use(&proxy->pci_dev, vdev->config_vector); 185e6da7680SMichael S. Tsirkin } 186ff24bd58SMichael S. Tsirkin return 0; 187ff24bd58SMichael S. Tsirkin } 188ff24bd58SMichael S. Tsirkin 189d2a0ccc6SMichael S. Tsirkin static int virtio_pci_load_queue(DeviceState *d, int n, QEMUFile *f) 190ff24bd58SMichael S. Tsirkin { 191d2a0ccc6SMichael S. Tsirkin VirtIOPCIProxy *proxy = to_virtio_pci_proxy(d); 192a3fc66d9SPaolo Bonzini VirtIODevice *vdev = virtio_bus_get_device(&proxy->bus); 193a3fc66d9SPaolo Bonzini 194ff24bd58SMichael S. Tsirkin uint16_t vector; 195e6da7680SMichael S. Tsirkin if (msix_present(&proxy->pci_dev)) { 196ff24bd58SMichael S. Tsirkin qemu_get_be16s(f, &vector); 197e6da7680SMichael S. Tsirkin } else { 198e6da7680SMichael S. Tsirkin vector = VIRTIO_NO_VECTOR; 199e6da7680SMichael S. Tsirkin } 200a3fc66d9SPaolo Bonzini virtio_queue_set_vector(vdev, n, vector); 201e6da7680SMichael S. Tsirkin if (vector != VIRTIO_NO_VECTOR) { 202e6da7680SMichael S. Tsirkin return msix_vector_use(&proxy->pci_dev, vector); 203e6da7680SMichael S. Tsirkin } 204a6df8adfSJason Wang 205ff24bd58SMichael S. Tsirkin return 0; 206ff24bd58SMichael S. Tsirkin } 207ff24bd58SMichael S. Tsirkin 2088e93cef1SPaolo Bonzini static bool virtio_pci_ioeventfd_enabled(DeviceState *d) 2099f06e71aSCornelia Huck { 2109f06e71aSCornelia Huck VirtIOPCIProxy *proxy = to_virtio_pci_proxy(d); 2119f06e71aSCornelia Huck 2128e93cef1SPaolo Bonzini return (proxy->flags & VIRTIO_PCI_FLAG_USE_IOEVENTFD) != 0; 2139f06e71aSCornelia Huck } 2149f06e71aSCornelia Huck 215975acc0aSJason Wang #define QEMU_VIRTIO_PCI_QUEUE_MEM_MULT 0x1000 216975acc0aSJason Wang 217d9997d89SMarcel Apfelbaum static inline int virtio_pci_queue_mem_mult(struct VirtIOPCIProxy *proxy) 218d9997d89SMarcel Apfelbaum { 219d9997d89SMarcel Apfelbaum return (proxy->flags & VIRTIO_PCI_FLAG_PAGE_PER_VQ) ? 220d9997d89SMarcel Apfelbaum QEMU_VIRTIO_PCI_QUEUE_MEM_MULT : 4; 221d9997d89SMarcel Apfelbaum } 222d9997d89SMarcel Apfelbaum 2239f06e71aSCornelia Huck static int virtio_pci_ioeventfd_assign(DeviceState *d, EventNotifier *notifier, 2249f06e71aSCornelia Huck int n, bool assign) 22525db9ebeSStefan Hajnoczi { 2269f06e71aSCornelia Huck VirtIOPCIProxy *proxy = to_virtio_pci_proxy(d); 227a3fc66d9SPaolo Bonzini VirtIODevice *vdev = virtio_bus_get_device(&proxy->bus); 228a3fc66d9SPaolo Bonzini VirtQueue *vq = virtio_get_queue(vdev, n); 2299a4c0e22SMarcel Apfelbaum bool legacy = virtio_pci_legacy(proxy); 2309a4c0e22SMarcel Apfelbaum bool modern = virtio_pci_modern(proxy); 231bc85ccfdSJason Wang bool fast_mmio = kvm_ioeventfd_any_length_enabled(); 2329824d2a3SJason Wang bool modern_pio = proxy->flags & VIRTIO_PCI_FLAG_MODERN_PIO_NOTIFY; 233588255adSGerd Hoffmann MemoryRegion *modern_mr = &proxy->notify.mr; 2349824d2a3SJason Wang MemoryRegion *modern_notify_mr = &proxy->notify_pio.mr; 235975acc0aSJason Wang MemoryRegion *legacy_mr = &proxy->bar; 236d9997d89SMarcel Apfelbaum hwaddr modern_addr = virtio_pci_queue_mem_mult(proxy) * 237975acc0aSJason Wang virtio_get_queue_index(vq); 238975acc0aSJason Wang hwaddr legacy_addr = VIRTIO_PCI_QUEUE_NOTIFY; 239da146d0aSAvi Kivity 24025db9ebeSStefan Hajnoczi if (assign) { 241975acc0aSJason Wang if (modern) { 242bc85ccfdSJason Wang if (fast_mmio) { 243bc85ccfdSJason Wang memory_region_add_eventfd(modern_mr, modern_addr, 0, 244bc85ccfdSJason Wang false, n, notifier); 245bc85ccfdSJason Wang } else { 246975acc0aSJason Wang memory_region_add_eventfd(modern_mr, modern_addr, 2, 247bc85ccfdSJason Wang false, n, notifier); 248bc85ccfdSJason Wang } 2499824d2a3SJason Wang if (modern_pio) { 2509824d2a3SJason Wang memory_region_add_eventfd(modern_notify_mr, 0, 2, 2519824d2a3SJason Wang true, n, notifier); 2529824d2a3SJason Wang } 253975acc0aSJason Wang } 254975acc0aSJason Wang if (legacy) { 255975acc0aSJason Wang memory_region_add_eventfd(legacy_mr, legacy_addr, 2, 256975acc0aSJason Wang true, n, notifier); 257975acc0aSJason Wang } 25825db9ebeSStefan Hajnoczi } else { 259975acc0aSJason Wang if (modern) { 260bc85ccfdSJason Wang if (fast_mmio) { 261bc85ccfdSJason Wang memory_region_del_eventfd(modern_mr, modern_addr, 0, 262bc85ccfdSJason Wang false, n, notifier); 263bc85ccfdSJason Wang } else { 264975acc0aSJason Wang memory_region_del_eventfd(modern_mr, modern_addr, 2, 265bc85ccfdSJason Wang false, n, notifier); 266bc85ccfdSJason Wang } 2679824d2a3SJason Wang if (modern_pio) { 2689824d2a3SJason Wang memory_region_del_eventfd(modern_notify_mr, 0, 2, 2699824d2a3SJason Wang true, n, notifier); 2709824d2a3SJason Wang } 271975acc0aSJason Wang } 272975acc0aSJason Wang if (legacy) { 273975acc0aSJason Wang memory_region_del_eventfd(legacy_mr, legacy_addr, 2, 274975acc0aSJason Wang true, n, notifier); 275975acc0aSJason Wang } 27625db9ebeSStefan Hajnoczi } 2779f06e71aSCornelia Huck return 0; 27825db9ebeSStefan Hajnoczi } 27925db9ebeSStefan Hajnoczi 280b36e3914SMichael S. Tsirkin static void virtio_pci_start_ioeventfd(VirtIOPCIProxy *proxy) 28125db9ebeSStefan Hajnoczi { 2829f06e71aSCornelia Huck virtio_bus_start_ioeventfd(&proxy->bus); 28325db9ebeSStefan Hajnoczi } 28425db9ebeSStefan Hajnoczi 285b36e3914SMichael S. Tsirkin static void virtio_pci_stop_ioeventfd(VirtIOPCIProxy *proxy) 28625db9ebeSStefan Hajnoczi { 2879f06e71aSCornelia Huck virtio_bus_stop_ioeventfd(&proxy->bus); 28825db9ebeSStefan Hajnoczi } 28925db9ebeSStefan Hajnoczi 29053c25ceaSPaul Brook static void virtio_ioport_write(void *opaque, uint32_t addr, uint32_t val) 29153c25ceaSPaul Brook { 29253c25ceaSPaul Brook VirtIOPCIProxy *proxy = opaque; 293a3fc66d9SPaolo Bonzini VirtIODevice *vdev = virtio_bus_get_device(&proxy->bus); 294a8170e5eSAvi Kivity hwaddr pa; 29553c25ceaSPaul Brook 29653c25ceaSPaul Brook switch (addr) { 29753c25ceaSPaul Brook case VIRTIO_PCI_GUEST_FEATURES: 29853c25ceaSPaul Brook /* Guest does not negotiate properly? We have to assume nothing. */ 29953c25ceaSPaul Brook if (val & (1 << VIRTIO_F_BAD_FEATURE)) { 300181103cdSKONRAD Frederic val = virtio_bus_get_vdev_bad_features(&proxy->bus); 30153c25ceaSPaul Brook } 302ad0c9332SPaolo Bonzini virtio_set_features(vdev, val); 30353c25ceaSPaul Brook break; 30453c25ceaSPaul Brook case VIRTIO_PCI_QUEUE_PFN: 305a8170e5eSAvi Kivity pa = (hwaddr)val << VIRTIO_PCI_QUEUE_ADDR_SHIFT; 3061b8e9b27SMichael S. Tsirkin if (pa == 0) { 30775fd6f13SGerd Hoffmann virtio_pci_reset(DEVICE(proxy)); 3081b8e9b27SMichael S. Tsirkin } 3097055e687SMichael S. Tsirkin else 31053c25ceaSPaul Brook virtio_queue_set_addr(vdev, vdev->queue_sel, pa); 31153c25ceaSPaul Brook break; 31253c25ceaSPaul Brook case VIRTIO_PCI_QUEUE_SEL: 31387b3bd1cSJason Wang if (val < VIRTIO_QUEUE_MAX) 31453c25ceaSPaul Brook vdev->queue_sel = val; 31553c25ceaSPaul Brook break; 31653c25ceaSPaul Brook case VIRTIO_PCI_QUEUE_NOTIFY: 31787b3bd1cSJason Wang if (val < VIRTIO_QUEUE_MAX) { 31853c25ceaSPaul Brook virtio_queue_notify(vdev, val); 3197157e2e2SStefan Hajnoczi } 32053c25ceaSPaul Brook break; 32153c25ceaSPaul Brook case VIRTIO_PCI_STATUS: 32225db9ebeSStefan Hajnoczi if (!(val & VIRTIO_CONFIG_S_DRIVER_OK)) { 32325db9ebeSStefan Hajnoczi virtio_pci_stop_ioeventfd(proxy); 32425db9ebeSStefan Hajnoczi } 32525db9ebeSStefan Hajnoczi 3263e607cb5SMichael S. Tsirkin virtio_set_status(vdev, val & 0xFF); 32725db9ebeSStefan Hajnoczi 32825db9ebeSStefan Hajnoczi if (val & VIRTIO_CONFIG_S_DRIVER_OK) { 32925db9ebeSStefan Hajnoczi virtio_pci_start_ioeventfd(proxy); 33025db9ebeSStefan Hajnoczi } 33125db9ebeSStefan Hajnoczi 3321b8e9b27SMichael S. Tsirkin if (vdev->status == 0) { 33375fd6f13SGerd Hoffmann virtio_pci_reset(DEVICE(proxy)); 3341b8e9b27SMichael S. Tsirkin } 335c81131dbSAlexander Graf 336e43c0b2eSMichael S. Tsirkin /* Linux before 2.6.34 drives the device without enabling 337e43c0b2eSMichael S. Tsirkin the PCI device bus master bit. Enable it automatically 338e43c0b2eSMichael S. Tsirkin for the guest. This is a PCI spec violation but so is 339e43c0b2eSMichael S. Tsirkin initiating DMA with bus master bit clear. */ 340e43c0b2eSMichael S. Tsirkin if (val == (VIRTIO_CONFIG_S_ACKNOWLEDGE | VIRTIO_CONFIG_S_DRIVER)) { 341e43c0b2eSMichael S. Tsirkin pci_default_write_config(&proxy->pci_dev, PCI_COMMAND, 342e43c0b2eSMichael S. Tsirkin proxy->pci_dev.config[PCI_COMMAND] | 343e43c0b2eSMichael S. Tsirkin PCI_COMMAND_MASTER, 1); 344e43c0b2eSMichael S. Tsirkin } 34553c25ceaSPaul Brook break; 346aba800a3SMichael S. Tsirkin case VIRTIO_MSI_CONFIG_VECTOR: 347aba800a3SMichael S. Tsirkin msix_vector_unuse(&proxy->pci_dev, vdev->config_vector); 348aba800a3SMichael S. Tsirkin /* Make it possible for guest to discover an error took place. */ 349aba800a3SMichael S. Tsirkin if (msix_vector_use(&proxy->pci_dev, val) < 0) 350aba800a3SMichael S. Tsirkin val = VIRTIO_NO_VECTOR; 351aba800a3SMichael S. Tsirkin vdev->config_vector = val; 352aba800a3SMichael S. Tsirkin break; 353aba800a3SMichael S. Tsirkin case VIRTIO_MSI_QUEUE_VECTOR: 354aba800a3SMichael S. Tsirkin msix_vector_unuse(&proxy->pci_dev, 355aba800a3SMichael S. Tsirkin virtio_queue_vector(vdev, vdev->queue_sel)); 356aba800a3SMichael S. Tsirkin /* Make it possible for guest to discover an error took place. */ 357aba800a3SMichael S. Tsirkin if (msix_vector_use(&proxy->pci_dev, val) < 0) 358aba800a3SMichael S. Tsirkin val = VIRTIO_NO_VECTOR; 359aba800a3SMichael S. Tsirkin virtio_queue_set_vector(vdev, vdev->queue_sel, val); 360aba800a3SMichael S. Tsirkin break; 361aba800a3SMichael S. Tsirkin default: 3624e02d460SStefan Hajnoczi error_report("%s: unexpected address 0x%x value 0x%x", 363aba800a3SMichael S. Tsirkin __func__, addr, val); 364aba800a3SMichael S. Tsirkin break; 36553c25ceaSPaul Brook } 36653c25ceaSPaul Brook } 36753c25ceaSPaul Brook 368aba800a3SMichael S. Tsirkin static uint32_t virtio_ioport_read(VirtIOPCIProxy *proxy, uint32_t addr) 36953c25ceaSPaul Brook { 370a3fc66d9SPaolo Bonzini VirtIODevice *vdev = virtio_bus_get_device(&proxy->bus); 37153c25ceaSPaul Brook uint32_t ret = 0xFFFFFFFF; 37253c25ceaSPaul Brook 37353c25ceaSPaul Brook switch (addr) { 37453c25ceaSPaul Brook case VIRTIO_PCI_HOST_FEATURES: 3756b8f1020SCornelia Huck ret = vdev->host_features; 37653c25ceaSPaul Brook break; 37753c25ceaSPaul Brook case VIRTIO_PCI_GUEST_FEATURES: 378704a76fcSMichael S. Tsirkin ret = vdev->guest_features; 37953c25ceaSPaul Brook break; 38053c25ceaSPaul Brook case VIRTIO_PCI_QUEUE_PFN: 38153c25ceaSPaul Brook ret = virtio_queue_get_addr(vdev, vdev->queue_sel) 38253c25ceaSPaul Brook >> VIRTIO_PCI_QUEUE_ADDR_SHIFT; 38353c25ceaSPaul Brook break; 38453c25ceaSPaul Brook case VIRTIO_PCI_QUEUE_NUM: 38553c25ceaSPaul Brook ret = virtio_queue_get_num(vdev, vdev->queue_sel); 38653c25ceaSPaul Brook break; 38753c25ceaSPaul Brook case VIRTIO_PCI_QUEUE_SEL: 38853c25ceaSPaul Brook ret = vdev->queue_sel; 38953c25ceaSPaul Brook break; 39053c25ceaSPaul Brook case VIRTIO_PCI_STATUS: 39153c25ceaSPaul Brook ret = vdev->status; 39253c25ceaSPaul Brook break; 39353c25ceaSPaul Brook case VIRTIO_PCI_ISR: 39453c25ceaSPaul Brook /* reading from the ISR also clears it. */ 3950687c37cSPaolo Bonzini ret = atomic_xchg(&vdev->isr, 0); 3969e64f8a3SMarcel Apfelbaum pci_irq_deassert(&proxy->pci_dev); 39753c25ceaSPaul Brook break; 398aba800a3SMichael S. Tsirkin case VIRTIO_MSI_CONFIG_VECTOR: 399aba800a3SMichael S. Tsirkin ret = vdev->config_vector; 400aba800a3SMichael S. Tsirkin break; 401aba800a3SMichael S. Tsirkin case VIRTIO_MSI_QUEUE_VECTOR: 402aba800a3SMichael S. Tsirkin ret = virtio_queue_vector(vdev, vdev->queue_sel); 403aba800a3SMichael S. Tsirkin break; 40453c25ceaSPaul Brook default: 40553c25ceaSPaul Brook break; 40653c25ceaSPaul Brook } 40753c25ceaSPaul Brook 40853c25ceaSPaul Brook return ret; 40953c25ceaSPaul Brook } 41053c25ceaSPaul Brook 411df6db5b3SAlexander Graf static uint64_t virtio_pci_config_read(void *opaque, hwaddr addr, 412df6db5b3SAlexander Graf unsigned size) 41353c25ceaSPaul Brook { 41453c25ceaSPaul Brook VirtIOPCIProxy *proxy = opaque; 415a3fc66d9SPaolo Bonzini VirtIODevice *vdev = virtio_bus_get_device(&proxy->bus); 416cbbe4f50SMichael S. Tsirkin uint32_t config = VIRTIO_PCI_CONFIG_SIZE(&proxy->pci_dev); 417df6db5b3SAlexander Graf uint64_t val = 0; 418df6db5b3SAlexander Graf if (addr < config) { 419aba800a3SMichael S. Tsirkin return virtio_ioport_read(proxy, addr); 42053c25ceaSPaul Brook } 421aba800a3SMichael S. Tsirkin addr -= config; 422df6db5b3SAlexander Graf 423df6db5b3SAlexander Graf switch (size) { 424df6db5b3SAlexander Graf case 1: 425a3fc66d9SPaolo Bonzini val = virtio_config_readb(vdev, addr); 426df6db5b3SAlexander Graf break; 427df6db5b3SAlexander Graf case 2: 428a3fc66d9SPaolo Bonzini val = virtio_config_readw(vdev, addr); 429616a6552SGreg Kurz if (virtio_is_big_endian(vdev)) { 4308e4a424bSBlue Swirl val = bswap16(val); 4318e4a424bSBlue Swirl } 432df6db5b3SAlexander Graf break; 433df6db5b3SAlexander Graf case 4: 434a3fc66d9SPaolo Bonzini val = virtio_config_readl(vdev, addr); 435616a6552SGreg Kurz if (virtio_is_big_endian(vdev)) { 4368e4a424bSBlue Swirl val = bswap32(val); 4378e4a424bSBlue Swirl } 438df6db5b3SAlexander Graf break; 439df6db5b3SAlexander Graf } 44082afa586SBenjamin Herrenschmidt return val; 44153c25ceaSPaul Brook } 44253c25ceaSPaul Brook 443df6db5b3SAlexander Graf static void virtio_pci_config_write(void *opaque, hwaddr addr, 444df6db5b3SAlexander Graf uint64_t val, unsigned size) 44553c25ceaSPaul Brook { 44653c25ceaSPaul Brook VirtIOPCIProxy *proxy = opaque; 447cbbe4f50SMichael S. Tsirkin uint32_t config = VIRTIO_PCI_CONFIG_SIZE(&proxy->pci_dev); 448a3fc66d9SPaolo Bonzini VirtIODevice *vdev = virtio_bus_get_device(&proxy->bus); 449aba800a3SMichael S. Tsirkin if (addr < config) { 450aba800a3SMichael S. Tsirkin virtio_ioport_write(proxy, addr, val); 451aba800a3SMichael S. Tsirkin return; 452aba800a3SMichael S. Tsirkin } 453aba800a3SMichael S. Tsirkin addr -= config; 454df6db5b3SAlexander Graf /* 455df6db5b3SAlexander Graf * Virtio-PCI is odd. Ioports are LE but config space is target native 456df6db5b3SAlexander Graf * endian. 457df6db5b3SAlexander Graf */ 458df6db5b3SAlexander Graf switch (size) { 459df6db5b3SAlexander Graf case 1: 460a3fc66d9SPaolo Bonzini virtio_config_writeb(vdev, addr, val); 461df6db5b3SAlexander Graf break; 462df6db5b3SAlexander Graf case 2: 463616a6552SGreg Kurz if (virtio_is_big_endian(vdev)) { 4648e4a424bSBlue Swirl val = bswap16(val); 4658e4a424bSBlue Swirl } 466a3fc66d9SPaolo Bonzini virtio_config_writew(vdev, addr, val); 467df6db5b3SAlexander Graf break; 468df6db5b3SAlexander Graf case 4: 469616a6552SGreg Kurz if (virtio_is_big_endian(vdev)) { 4708e4a424bSBlue Swirl val = bswap32(val); 4718e4a424bSBlue Swirl } 472a3fc66d9SPaolo Bonzini virtio_config_writel(vdev, addr, val); 473df6db5b3SAlexander Graf break; 474df6db5b3SAlexander Graf } 47553c25ceaSPaul Brook } 47653c25ceaSPaul Brook 477da146d0aSAvi Kivity static const MemoryRegionOps virtio_pci_config_ops = { 478df6db5b3SAlexander Graf .read = virtio_pci_config_read, 479df6db5b3SAlexander Graf .write = virtio_pci_config_write, 480df6db5b3SAlexander Graf .impl = { 481df6db5b3SAlexander Graf .min_access_size = 1, 482df6db5b3SAlexander Graf .max_access_size = 4, 483df6db5b3SAlexander Graf }, 4848e4a424bSBlue Swirl .endianness = DEVICE_LITTLE_ENDIAN, 485da146d0aSAvi Kivity }; 486aba800a3SMichael S. Tsirkin 487a93c8d82SAlexey Kardashevskiy static MemoryRegion *virtio_address_space_lookup(VirtIOPCIProxy *proxy, 488a93c8d82SAlexey Kardashevskiy hwaddr *off, int len) 489a93c8d82SAlexey Kardashevskiy { 490a93c8d82SAlexey Kardashevskiy int i; 491a93c8d82SAlexey Kardashevskiy VirtIOPCIRegion *reg; 492a93c8d82SAlexey Kardashevskiy 493a93c8d82SAlexey Kardashevskiy for (i = 0; i < ARRAY_SIZE(proxy->regs); ++i) { 494a93c8d82SAlexey Kardashevskiy reg = &proxy->regs[i]; 495a93c8d82SAlexey Kardashevskiy if (*off >= reg->offset && 496a93c8d82SAlexey Kardashevskiy *off + len <= reg->offset + reg->size) { 497a93c8d82SAlexey Kardashevskiy *off -= reg->offset; 498a93c8d82SAlexey Kardashevskiy return ®->mr; 499a93c8d82SAlexey Kardashevskiy } 500a93c8d82SAlexey Kardashevskiy } 501a93c8d82SAlexey Kardashevskiy 502a93c8d82SAlexey Kardashevskiy return NULL; 503a93c8d82SAlexey Kardashevskiy } 504a93c8d82SAlexey Kardashevskiy 5051e40356cSMichael S. Tsirkin /* Below are generic functions to do memcpy from/to an address space, 5061e40356cSMichael S. Tsirkin * without byteswaps, with input validation. 5071e40356cSMichael S. Tsirkin * 5081e40356cSMichael S. Tsirkin * As regular address_space_* APIs all do some kind of byteswap at least for 5091e40356cSMichael S. Tsirkin * some host/target combinations, we are forced to explicitly convert to a 5101e40356cSMichael S. Tsirkin * known-endianness integer value. 5111e40356cSMichael S. Tsirkin * It doesn't really matter which endian format to go through, so the code 5121e40356cSMichael S. Tsirkin * below selects the endian that causes the least amount of work on the given 5131e40356cSMichael S. Tsirkin * host. 5141e40356cSMichael S. Tsirkin * 5151e40356cSMichael S. Tsirkin * Note: host pointer must be aligned. 5161e40356cSMichael S. Tsirkin */ 5171e40356cSMichael S. Tsirkin static 518a93c8d82SAlexey Kardashevskiy void virtio_address_space_write(VirtIOPCIProxy *proxy, hwaddr addr, 5191e40356cSMichael S. Tsirkin const uint8_t *buf, int len) 5201e40356cSMichael S. Tsirkin { 521a93c8d82SAlexey Kardashevskiy uint64_t val; 522a93c8d82SAlexey Kardashevskiy MemoryRegion *mr; 5231e40356cSMichael S. Tsirkin 5241e40356cSMichael S. Tsirkin /* address_space_* APIs assume an aligned address. 5251e40356cSMichael S. Tsirkin * As address is under guest control, handle illegal values. 5261e40356cSMichael S. Tsirkin */ 5271e40356cSMichael S. Tsirkin addr &= ~(len - 1); 5281e40356cSMichael S. Tsirkin 529a93c8d82SAlexey Kardashevskiy mr = virtio_address_space_lookup(proxy, &addr, len); 530a93c8d82SAlexey Kardashevskiy if (!mr) { 531a93c8d82SAlexey Kardashevskiy return; 532a93c8d82SAlexey Kardashevskiy } 533a93c8d82SAlexey Kardashevskiy 5341e40356cSMichael S. Tsirkin /* Make sure caller aligned buf properly */ 5351e40356cSMichael S. Tsirkin assert(!(((uintptr_t)buf) & (len - 1))); 5361e40356cSMichael S. Tsirkin 5371e40356cSMichael S. Tsirkin switch (len) { 5381e40356cSMichael S. Tsirkin case 1: 5391e40356cSMichael S. Tsirkin val = pci_get_byte(buf); 5401e40356cSMichael S. Tsirkin break; 5411e40356cSMichael S. Tsirkin case 2: 542a93c8d82SAlexey Kardashevskiy val = cpu_to_le16(pci_get_word(buf)); 5431e40356cSMichael S. Tsirkin break; 5441e40356cSMichael S. Tsirkin case 4: 545a93c8d82SAlexey Kardashevskiy val = cpu_to_le32(pci_get_long(buf)); 5461e40356cSMichael S. Tsirkin break; 5471e40356cSMichael S. Tsirkin default: 5481e40356cSMichael S. Tsirkin /* As length is under guest control, handle illegal values. */ 549a93c8d82SAlexey Kardashevskiy return; 5501e40356cSMichael S. Tsirkin } 551a93c8d82SAlexey Kardashevskiy memory_region_dispatch_write(mr, addr, val, len, MEMTXATTRS_UNSPECIFIED); 5521e40356cSMichael S. Tsirkin } 5531e40356cSMichael S. Tsirkin 5541e40356cSMichael S. Tsirkin static void 555a93c8d82SAlexey Kardashevskiy virtio_address_space_read(VirtIOPCIProxy *proxy, hwaddr addr, 556a93c8d82SAlexey Kardashevskiy uint8_t *buf, int len) 5571e40356cSMichael S. Tsirkin { 558a93c8d82SAlexey Kardashevskiy uint64_t val; 559a93c8d82SAlexey Kardashevskiy MemoryRegion *mr; 5601e40356cSMichael S. Tsirkin 5611e40356cSMichael S. Tsirkin /* address_space_* APIs assume an aligned address. 5621e40356cSMichael S. Tsirkin * As address is under guest control, handle illegal values. 5631e40356cSMichael S. Tsirkin */ 5641e40356cSMichael S. Tsirkin addr &= ~(len - 1); 5651e40356cSMichael S. Tsirkin 566a93c8d82SAlexey Kardashevskiy mr = virtio_address_space_lookup(proxy, &addr, len); 567a93c8d82SAlexey Kardashevskiy if (!mr) { 568a93c8d82SAlexey Kardashevskiy return; 569a93c8d82SAlexey Kardashevskiy } 570a93c8d82SAlexey Kardashevskiy 5711e40356cSMichael S. Tsirkin /* Make sure caller aligned buf properly */ 5721e40356cSMichael S. Tsirkin assert(!(((uintptr_t)buf) & (len - 1))); 5731e40356cSMichael S. Tsirkin 574a93c8d82SAlexey Kardashevskiy memory_region_dispatch_read(mr, addr, &val, len, MEMTXATTRS_UNSPECIFIED); 5751e40356cSMichael S. Tsirkin switch (len) { 5761e40356cSMichael S. Tsirkin case 1: 5771e40356cSMichael S. Tsirkin pci_set_byte(buf, val); 5781e40356cSMichael S. Tsirkin break; 5791e40356cSMichael S. Tsirkin case 2: 580a93c8d82SAlexey Kardashevskiy pci_set_word(buf, le16_to_cpu(val)); 5811e40356cSMichael S. Tsirkin break; 5821e40356cSMichael S. Tsirkin case 4: 583a93c8d82SAlexey Kardashevskiy pci_set_long(buf, le32_to_cpu(val)); 5841e40356cSMichael S. Tsirkin break; 5851e40356cSMichael S. Tsirkin default: 5861e40356cSMichael S. Tsirkin /* As length is under guest control, handle illegal values. */ 5871e40356cSMichael S. Tsirkin break; 5881e40356cSMichael S. Tsirkin } 5891e40356cSMichael S. Tsirkin } 5901e40356cSMichael S. Tsirkin 591aba800a3SMichael S. Tsirkin static void virtio_write_config(PCIDevice *pci_dev, uint32_t address, 592aba800a3SMichael S. Tsirkin uint32_t val, int len) 593aba800a3SMichael S. Tsirkin { 5943f262b26SLi Qiang VirtIOPCIProxy *proxy = VIRTIO_PCI(pci_dev); 595a3fc66d9SPaolo Bonzini VirtIODevice *vdev = virtio_bus_get_device(&proxy->bus); 596ada434cdSMichael S. Tsirkin struct virtio_pci_cfg_cap *cfg; 597ed757e14SYan Vugenfirer 5981129714fSMichael S. Tsirkin pci_default_write_config(pci_dev, address, val, len); 5991129714fSMichael S. Tsirkin 6001129714fSMichael S. Tsirkin if (range_covers_byte(address, len, PCI_COMMAND) && 60168a27b20SMichael S. Tsirkin !(pci_dev->config[PCI_COMMAND] & PCI_COMMAND_MASTER)) { 60225db9ebeSStefan Hajnoczi virtio_pci_stop_ioeventfd(proxy); 60345363e46SMichael S. Tsirkin virtio_set_status(vdev, vdev->status & ~VIRTIO_CONFIG_S_DRIVER_OK); 604ed757e14SYan Vugenfirer } 605ada434cdSMichael S. Tsirkin 606ada434cdSMichael S. Tsirkin if (proxy->config_cap && 607ada434cdSMichael S. Tsirkin ranges_overlap(address, len, proxy->config_cap + offsetof(struct virtio_pci_cfg_cap, 608ada434cdSMichael S. Tsirkin pci_cfg_data), 609ada434cdSMichael S. Tsirkin sizeof cfg->pci_cfg_data)) { 610ada434cdSMichael S. Tsirkin uint32_t off; 611ada434cdSMichael S. Tsirkin uint32_t len; 612ada434cdSMichael S. Tsirkin 613ada434cdSMichael S. Tsirkin cfg = (void *)(proxy->pci_dev.config + proxy->config_cap); 614ada434cdSMichael S. Tsirkin off = le32_to_cpu(cfg->cap.offset); 615ada434cdSMichael S. Tsirkin len = le32_to_cpu(cfg->cap.length); 616ada434cdSMichael S. Tsirkin 6172a639123SMichael S. Tsirkin if (len == 1 || len == 2 || len == 4) { 6182a639123SMichael S. Tsirkin assert(len <= sizeof cfg->pci_cfg_data); 619a93c8d82SAlexey Kardashevskiy virtio_address_space_write(proxy, off, cfg->pci_cfg_data, len); 620ada434cdSMichael S. Tsirkin } 621ada434cdSMichael S. Tsirkin } 622ada434cdSMichael S. Tsirkin } 623ada434cdSMichael S. Tsirkin 624ada434cdSMichael S. Tsirkin static uint32_t virtio_read_config(PCIDevice *pci_dev, 625ada434cdSMichael S. Tsirkin uint32_t address, int len) 626ada434cdSMichael S. Tsirkin { 6273f262b26SLi Qiang VirtIOPCIProxy *proxy = VIRTIO_PCI(pci_dev); 628ada434cdSMichael S. Tsirkin struct virtio_pci_cfg_cap *cfg; 629ada434cdSMichael S. Tsirkin 630ada434cdSMichael S. Tsirkin if (proxy->config_cap && 631ada434cdSMichael S. Tsirkin ranges_overlap(address, len, proxy->config_cap + offsetof(struct virtio_pci_cfg_cap, 632ada434cdSMichael S. Tsirkin pci_cfg_data), 633ada434cdSMichael S. Tsirkin sizeof cfg->pci_cfg_data)) { 634ada434cdSMichael S. Tsirkin uint32_t off; 635ada434cdSMichael S. Tsirkin uint32_t len; 636ada434cdSMichael S. Tsirkin 637ada434cdSMichael S. Tsirkin cfg = (void *)(proxy->pci_dev.config + proxy->config_cap); 638ada434cdSMichael S. Tsirkin off = le32_to_cpu(cfg->cap.offset); 639ada434cdSMichael S. Tsirkin len = le32_to_cpu(cfg->cap.length); 640ada434cdSMichael S. Tsirkin 6412a639123SMichael S. Tsirkin if (len == 1 || len == 2 || len == 4) { 6422a639123SMichael S. Tsirkin assert(len <= sizeof cfg->pci_cfg_data); 643a93c8d82SAlexey Kardashevskiy virtio_address_space_read(proxy, off, cfg->pci_cfg_data, len); 644ada434cdSMichael S. Tsirkin } 645ada434cdSMichael S. Tsirkin } 646ada434cdSMichael S. Tsirkin 647ada434cdSMichael S. Tsirkin return pci_default_read_config(pci_dev, address, len); 64853c25ceaSPaul Brook } 64953c25ceaSPaul Brook 6507d37d351SJan Kiszka static int kvm_virtio_pci_vq_vector_use(VirtIOPCIProxy *proxy, 6517d37d351SJan Kiszka unsigned int queue_no, 652d1f6af6aSPeter Xu unsigned int vector) 6537d37d351SJan Kiszka { 6547d37d351SJan Kiszka VirtIOIRQFD *irqfd = &proxy->vector_irqfd[vector]; 65515b2bd18SPaolo Bonzini int ret; 6567d37d351SJan Kiszka 6577d37d351SJan Kiszka if (irqfd->users == 0) { 658d1f6af6aSPeter Xu ret = kvm_irqchip_add_msi_route(kvm_state, vector, &proxy->pci_dev); 6597d37d351SJan Kiszka if (ret < 0) { 6607d37d351SJan Kiszka return ret; 6617d37d351SJan Kiszka } 6627d37d351SJan Kiszka irqfd->virq = ret; 6637d37d351SJan Kiszka } 6647d37d351SJan Kiszka irqfd->users++; 6657d37d351SJan Kiszka return 0; 6667d37d351SJan Kiszka } 6677d37d351SJan Kiszka 6687d37d351SJan Kiszka static void kvm_virtio_pci_vq_vector_release(VirtIOPCIProxy *proxy, 669774345f9SMichael S. Tsirkin unsigned int vector) 670774345f9SMichael S. Tsirkin { 671774345f9SMichael S. Tsirkin VirtIOIRQFD *irqfd = &proxy->vector_irqfd[vector]; 672774345f9SMichael S. Tsirkin if (--irqfd->users == 0) { 673774345f9SMichael S. Tsirkin kvm_irqchip_release_virq(kvm_state, irqfd->virq); 674774345f9SMichael S. Tsirkin } 675774345f9SMichael S. Tsirkin } 676774345f9SMichael S. Tsirkin 677f1d0f15aSMichael S. Tsirkin static int kvm_virtio_pci_irqfd_use(VirtIOPCIProxy *proxy, 678f1d0f15aSMichael S. Tsirkin unsigned int queue_no, 679f1d0f15aSMichael S. Tsirkin unsigned int vector) 680f1d0f15aSMichael S. Tsirkin { 681f1d0f15aSMichael S. Tsirkin VirtIOIRQFD *irqfd = &proxy->vector_irqfd[vector]; 682a3fc66d9SPaolo Bonzini VirtIODevice *vdev = virtio_bus_get_device(&proxy->bus); 683a3fc66d9SPaolo Bonzini VirtQueue *vq = virtio_get_queue(vdev, queue_no); 684f1d0f15aSMichael S. Tsirkin EventNotifier *n = virtio_queue_get_guest_notifier(vq); 6859be38598SEduardo Habkost return kvm_irqchip_add_irqfd_notifier_gsi(kvm_state, n, NULL, irqfd->virq); 686f1d0f15aSMichael S. Tsirkin } 687f1d0f15aSMichael S. Tsirkin 688f1d0f15aSMichael S. Tsirkin static void kvm_virtio_pci_irqfd_release(VirtIOPCIProxy *proxy, 6897d37d351SJan Kiszka unsigned int queue_no, 6907d37d351SJan Kiszka unsigned int vector) 6917d37d351SJan Kiszka { 692a3fc66d9SPaolo Bonzini VirtIODevice *vdev = virtio_bus_get_device(&proxy->bus); 693a3fc66d9SPaolo Bonzini VirtQueue *vq = virtio_get_queue(vdev, queue_no); 69415b2bd18SPaolo Bonzini EventNotifier *n = virtio_queue_get_guest_notifier(vq); 6957d37d351SJan Kiszka VirtIOIRQFD *irqfd = &proxy->vector_irqfd[vector]; 69615b2bd18SPaolo Bonzini int ret; 6977d37d351SJan Kiszka 6981c9b71a7SEric Auger ret = kvm_irqchip_remove_irqfd_notifier_gsi(kvm_state, n, irqfd->virq); 6997d37d351SJan Kiszka assert(ret == 0); 700f1d0f15aSMichael S. Tsirkin } 7017d37d351SJan Kiszka 702774345f9SMichael S. Tsirkin static int kvm_virtio_pci_vector_use(VirtIOPCIProxy *proxy, int nvqs) 703774345f9SMichael S. Tsirkin { 704774345f9SMichael S. Tsirkin PCIDevice *dev = &proxy->pci_dev; 705a3fc66d9SPaolo Bonzini VirtIODevice *vdev = virtio_bus_get_device(&proxy->bus); 706181103cdSKONRAD Frederic VirtioDeviceClass *k = VIRTIO_DEVICE_GET_CLASS(vdev); 707774345f9SMichael S. Tsirkin unsigned int vector; 708774345f9SMichael S. Tsirkin int ret, queue_no; 709774345f9SMichael S. Tsirkin 710774345f9SMichael S. Tsirkin for (queue_no = 0; queue_no < nvqs; queue_no++) { 711774345f9SMichael S. Tsirkin if (!virtio_queue_get_num(vdev, queue_no)) { 712774345f9SMichael S. Tsirkin break; 713774345f9SMichael S. Tsirkin } 714774345f9SMichael S. Tsirkin vector = virtio_queue_vector(vdev, queue_no); 715774345f9SMichael S. Tsirkin if (vector >= msix_nr_vectors_allocated(dev)) { 716774345f9SMichael S. Tsirkin continue; 717774345f9SMichael S. Tsirkin } 718d1f6af6aSPeter Xu ret = kvm_virtio_pci_vq_vector_use(proxy, queue_no, vector); 719774345f9SMichael S. Tsirkin if (ret < 0) { 720774345f9SMichael S. Tsirkin goto undo; 721774345f9SMichael S. Tsirkin } 722f1d0f15aSMichael S. Tsirkin /* If guest supports masking, set up irqfd now. 723f1d0f15aSMichael S. Tsirkin * Otherwise, delay until unmasked in the frontend. 724f1d0f15aSMichael S. Tsirkin */ 7255669655aSVictor Kaplansky if (vdev->use_guest_notifier_mask && k->guest_notifier_mask) { 726f1d0f15aSMichael S. Tsirkin ret = kvm_virtio_pci_irqfd_use(proxy, queue_no, vector); 727f1d0f15aSMichael S. Tsirkin if (ret < 0) { 728f1d0f15aSMichael S. Tsirkin kvm_virtio_pci_vq_vector_release(proxy, vector); 729f1d0f15aSMichael S. Tsirkin goto undo; 730f1d0f15aSMichael S. Tsirkin } 731f1d0f15aSMichael S. Tsirkin } 732774345f9SMichael S. Tsirkin } 733774345f9SMichael S. Tsirkin return 0; 734774345f9SMichael S. Tsirkin 735774345f9SMichael S. Tsirkin undo: 736774345f9SMichael S. Tsirkin while (--queue_no >= 0) { 737774345f9SMichael S. Tsirkin vector = virtio_queue_vector(vdev, queue_no); 738774345f9SMichael S. Tsirkin if (vector >= msix_nr_vectors_allocated(dev)) { 739774345f9SMichael S. Tsirkin continue; 740774345f9SMichael S. Tsirkin } 7415669655aSVictor Kaplansky if (vdev->use_guest_notifier_mask && k->guest_notifier_mask) { 742e387f99eSMichael S. Tsirkin kvm_virtio_pci_irqfd_release(proxy, queue_no, vector); 743f1d0f15aSMichael S. Tsirkin } 744774345f9SMichael S. Tsirkin kvm_virtio_pci_vq_vector_release(proxy, vector); 745774345f9SMichael S. Tsirkin } 746774345f9SMichael S. Tsirkin return ret; 747774345f9SMichael S. Tsirkin } 748774345f9SMichael S. Tsirkin 749774345f9SMichael S. Tsirkin static void kvm_virtio_pci_vector_release(VirtIOPCIProxy *proxy, int nvqs) 750774345f9SMichael S. Tsirkin { 751774345f9SMichael S. Tsirkin PCIDevice *dev = &proxy->pci_dev; 752a3fc66d9SPaolo Bonzini VirtIODevice *vdev = virtio_bus_get_device(&proxy->bus); 753774345f9SMichael S. Tsirkin unsigned int vector; 754774345f9SMichael S. Tsirkin int queue_no; 755181103cdSKONRAD Frederic VirtioDeviceClass *k = VIRTIO_DEVICE_GET_CLASS(vdev); 756774345f9SMichael S. Tsirkin 757774345f9SMichael S. Tsirkin for (queue_no = 0; queue_no < nvqs; queue_no++) { 758774345f9SMichael S. Tsirkin if (!virtio_queue_get_num(vdev, queue_no)) { 759774345f9SMichael S. Tsirkin break; 760774345f9SMichael S. Tsirkin } 761774345f9SMichael S. Tsirkin vector = virtio_queue_vector(vdev, queue_no); 762774345f9SMichael S. Tsirkin if (vector >= msix_nr_vectors_allocated(dev)) { 763774345f9SMichael S. Tsirkin continue; 764774345f9SMichael S. Tsirkin } 765f1d0f15aSMichael S. Tsirkin /* If guest supports masking, clean up irqfd now. 766f1d0f15aSMichael S. Tsirkin * Otherwise, it was cleaned when masked in the frontend. 767f1d0f15aSMichael S. Tsirkin */ 7685669655aSVictor Kaplansky if (vdev->use_guest_notifier_mask && k->guest_notifier_mask) { 769e387f99eSMichael S. Tsirkin kvm_virtio_pci_irqfd_release(proxy, queue_no, vector); 770f1d0f15aSMichael S. Tsirkin } 771774345f9SMichael S. Tsirkin kvm_virtio_pci_vq_vector_release(proxy, vector); 7727d37d351SJan Kiszka } 7737d37d351SJan Kiszka } 7747d37d351SJan Kiszka 775a38b2c49SMichael S. Tsirkin static int virtio_pci_vq_vector_unmask(VirtIOPCIProxy *proxy, 776774345f9SMichael S. Tsirkin unsigned int queue_no, 777774345f9SMichael S. Tsirkin unsigned int vector, 778774345f9SMichael S. Tsirkin MSIMessage msg) 779774345f9SMichael S. Tsirkin { 780a3fc66d9SPaolo Bonzini VirtIODevice *vdev = virtio_bus_get_device(&proxy->bus); 781a3fc66d9SPaolo Bonzini VirtioDeviceClass *k = VIRTIO_DEVICE_GET_CLASS(vdev); 782a3fc66d9SPaolo Bonzini VirtQueue *vq = virtio_get_queue(vdev, queue_no); 783774345f9SMichael S. Tsirkin EventNotifier *n = virtio_queue_get_guest_notifier(vq); 784a38b2c49SMichael S. Tsirkin VirtIOIRQFD *irqfd; 78553510bfcSMichael Roth int ret = 0; 786774345f9SMichael S. Tsirkin 787a38b2c49SMichael S. Tsirkin if (proxy->vector_irqfd) { 788a38b2c49SMichael S. Tsirkin irqfd = &proxy->vector_irqfd[vector]; 789774345f9SMichael S. Tsirkin if (irqfd->msg.data != msg.data || irqfd->msg.address != msg.address) { 790dc9f06caSPavel Fedin ret = kvm_irqchip_update_msi_route(kvm_state, irqfd->virq, msg, 791dc9f06caSPavel Fedin &proxy->pci_dev); 792774345f9SMichael S. Tsirkin if (ret < 0) { 793774345f9SMichael S. Tsirkin return ret; 794774345f9SMichael S. Tsirkin } 7953f1fea0fSPeter Xu kvm_irqchip_commit_routes(kvm_state); 796774345f9SMichael S. Tsirkin } 797a38b2c49SMichael S. Tsirkin } 798774345f9SMichael S. Tsirkin 799f1d0f15aSMichael S. Tsirkin /* If guest supports masking, irqfd is already setup, unmask it. 800f1d0f15aSMichael S. Tsirkin * Otherwise, set it up now. 801f1d0f15aSMichael S. Tsirkin */ 8025669655aSVictor Kaplansky if (vdev->use_guest_notifier_mask && k->guest_notifier_mask) { 803a3fc66d9SPaolo Bonzini k->guest_notifier_mask(vdev, queue_no, false); 804f1d0f15aSMichael S. Tsirkin /* Test after unmasking to avoid losing events. */ 805181103cdSKONRAD Frederic if (k->guest_notifier_pending && 806a3fc66d9SPaolo Bonzini k->guest_notifier_pending(vdev, queue_no)) { 807f1d0f15aSMichael S. Tsirkin event_notifier_set(n); 808f1d0f15aSMichael S. Tsirkin } 809f1d0f15aSMichael S. Tsirkin } else { 810f1d0f15aSMichael S. Tsirkin ret = kvm_virtio_pci_irqfd_use(proxy, queue_no, vector); 811f1d0f15aSMichael S. Tsirkin } 812774345f9SMichael S. Tsirkin return ret; 813774345f9SMichael S. Tsirkin } 814774345f9SMichael S. Tsirkin 815a38b2c49SMichael S. Tsirkin static void virtio_pci_vq_vector_mask(VirtIOPCIProxy *proxy, 8167d37d351SJan Kiszka unsigned int queue_no, 8177d37d351SJan Kiszka unsigned int vector) 8187d37d351SJan Kiszka { 819a3fc66d9SPaolo Bonzini VirtIODevice *vdev = virtio_bus_get_device(&proxy->bus); 820a3fc66d9SPaolo Bonzini VirtioDeviceClass *k = VIRTIO_DEVICE_GET_CLASS(vdev); 821181103cdSKONRAD Frederic 822f1d0f15aSMichael S. Tsirkin /* If guest supports masking, keep irqfd but mask it. 823f1d0f15aSMichael S. Tsirkin * Otherwise, clean it up now. 824f1d0f15aSMichael S. Tsirkin */ 8255669655aSVictor Kaplansky if (vdev->use_guest_notifier_mask && k->guest_notifier_mask) { 826a3fc66d9SPaolo Bonzini k->guest_notifier_mask(vdev, queue_no, true); 827f1d0f15aSMichael S. Tsirkin } else { 828e387f99eSMichael S. Tsirkin kvm_virtio_pci_irqfd_release(proxy, queue_no, vector); 829f1d0f15aSMichael S. Tsirkin } 8307d37d351SJan Kiszka } 8317d37d351SJan Kiszka 832a38b2c49SMichael S. Tsirkin static int virtio_pci_vector_unmask(PCIDevice *dev, unsigned vector, 8337d37d351SJan Kiszka MSIMessage msg) 8347d37d351SJan Kiszka { 8357d37d351SJan Kiszka VirtIOPCIProxy *proxy = container_of(dev, VirtIOPCIProxy, pci_dev); 836a3fc66d9SPaolo Bonzini VirtIODevice *vdev = virtio_bus_get_device(&proxy->bus); 837851c2a75SJason Wang VirtQueue *vq = virtio_vector_first_queue(vdev, vector); 838851c2a75SJason Wang int ret, index, unmasked = 0; 8397d37d351SJan Kiszka 840851c2a75SJason Wang while (vq) { 841851c2a75SJason Wang index = virtio_get_queue_index(vq); 842851c2a75SJason Wang if (!virtio_queue_get_num(vdev, index)) { 8437d37d351SJan Kiszka break; 8447d37d351SJan Kiszka } 8456652d081SJason Wang if (index < proxy->nvqs_with_notifiers) { 846851c2a75SJason Wang ret = virtio_pci_vq_vector_unmask(proxy, index, vector, msg); 8477d37d351SJan Kiszka if (ret < 0) { 8487d37d351SJan Kiszka goto undo; 8497d37d351SJan Kiszka } 850851c2a75SJason Wang ++unmasked; 8517d37d351SJan Kiszka } 8526652d081SJason Wang vq = virtio_vector_next_queue(vq); 8536652d081SJason Wang } 854851c2a75SJason Wang 8557d37d351SJan Kiszka return 0; 8567d37d351SJan Kiszka 8577d37d351SJan Kiszka undo: 858851c2a75SJason Wang vq = virtio_vector_first_queue(vdev, vector); 8596652d081SJason Wang while (vq && unmasked >= 0) { 860851c2a75SJason Wang index = virtio_get_queue_index(vq); 8616652d081SJason Wang if (index < proxy->nvqs_with_notifiers) { 862851c2a75SJason Wang virtio_pci_vq_vector_mask(proxy, index, vector); 8636652d081SJason Wang --unmasked; 8646652d081SJason Wang } 865851c2a75SJason Wang vq = virtio_vector_next_queue(vq); 8667d37d351SJan Kiszka } 8677d37d351SJan Kiszka return ret; 8687d37d351SJan Kiszka } 8697d37d351SJan Kiszka 870a38b2c49SMichael S. Tsirkin static void virtio_pci_vector_mask(PCIDevice *dev, unsigned vector) 8717d37d351SJan Kiszka { 8727d37d351SJan Kiszka VirtIOPCIProxy *proxy = container_of(dev, VirtIOPCIProxy, pci_dev); 873a3fc66d9SPaolo Bonzini VirtIODevice *vdev = virtio_bus_get_device(&proxy->bus); 874851c2a75SJason Wang VirtQueue *vq = virtio_vector_first_queue(vdev, vector); 875851c2a75SJason Wang int index; 8767d37d351SJan Kiszka 877851c2a75SJason Wang while (vq) { 878851c2a75SJason Wang index = virtio_get_queue_index(vq); 879851c2a75SJason Wang if (!virtio_queue_get_num(vdev, index)) { 8807d37d351SJan Kiszka break; 8817d37d351SJan Kiszka } 8826652d081SJason Wang if (index < proxy->nvqs_with_notifiers) { 883851c2a75SJason Wang virtio_pci_vq_vector_mask(proxy, index, vector); 8846652d081SJason Wang } 885851c2a75SJason Wang vq = virtio_vector_next_queue(vq); 8867d37d351SJan Kiszka } 8877d37d351SJan Kiszka } 8887d37d351SJan Kiszka 889a38b2c49SMichael S. Tsirkin static void virtio_pci_vector_poll(PCIDevice *dev, 89089d62be9SMichael S. Tsirkin unsigned int vector_start, 89189d62be9SMichael S. Tsirkin unsigned int vector_end) 89289d62be9SMichael S. Tsirkin { 89389d62be9SMichael S. Tsirkin VirtIOPCIProxy *proxy = container_of(dev, VirtIOPCIProxy, pci_dev); 894a3fc66d9SPaolo Bonzini VirtIODevice *vdev = virtio_bus_get_device(&proxy->bus); 895181103cdSKONRAD Frederic VirtioDeviceClass *k = VIRTIO_DEVICE_GET_CLASS(vdev); 89689d62be9SMichael S. Tsirkin int queue_no; 89789d62be9SMichael S. Tsirkin unsigned int vector; 89889d62be9SMichael S. Tsirkin EventNotifier *notifier; 89989d62be9SMichael S. Tsirkin VirtQueue *vq; 90089d62be9SMichael S. Tsirkin 9012d620f59SMichael S. Tsirkin for (queue_no = 0; queue_no < proxy->nvqs_with_notifiers; queue_no++) { 90289d62be9SMichael S. Tsirkin if (!virtio_queue_get_num(vdev, queue_no)) { 90389d62be9SMichael S. Tsirkin break; 90489d62be9SMichael S. Tsirkin } 90589d62be9SMichael S. Tsirkin vector = virtio_queue_vector(vdev, queue_no); 90689d62be9SMichael S. Tsirkin if (vector < vector_start || vector >= vector_end || 90789d62be9SMichael S. Tsirkin !msix_is_masked(dev, vector)) { 90889d62be9SMichael S. Tsirkin continue; 90989d62be9SMichael S. Tsirkin } 91089d62be9SMichael S. Tsirkin vq = virtio_get_queue(vdev, queue_no); 91189d62be9SMichael S. Tsirkin notifier = virtio_queue_get_guest_notifier(vq); 912181103cdSKONRAD Frederic if (k->guest_notifier_pending) { 913181103cdSKONRAD Frederic if (k->guest_notifier_pending(vdev, queue_no)) { 914f1d0f15aSMichael S. Tsirkin msix_set_pending(dev, vector); 915f1d0f15aSMichael S. Tsirkin } 916f1d0f15aSMichael S. Tsirkin } else if (event_notifier_test_and_clear(notifier)) { 91789d62be9SMichael S. Tsirkin msix_set_pending(dev, vector); 91889d62be9SMichael S. Tsirkin } 91989d62be9SMichael S. Tsirkin } 92089d62be9SMichael S. Tsirkin } 92189d62be9SMichael S. Tsirkin 92289d62be9SMichael S. Tsirkin static int virtio_pci_set_guest_notifier(DeviceState *d, int n, bool assign, 92389d62be9SMichael S. Tsirkin bool with_irqfd) 924ade80dc8SMichael S. Tsirkin { 925d2a0ccc6SMichael S. Tsirkin VirtIOPCIProxy *proxy = to_virtio_pci_proxy(d); 926a3fc66d9SPaolo Bonzini VirtIODevice *vdev = virtio_bus_get_device(&proxy->bus); 927a3fc66d9SPaolo Bonzini VirtioDeviceClass *vdc = VIRTIO_DEVICE_GET_CLASS(vdev); 928a3fc66d9SPaolo Bonzini VirtQueue *vq = virtio_get_queue(vdev, n); 929ade80dc8SMichael S. Tsirkin EventNotifier *notifier = virtio_queue_get_guest_notifier(vq); 930ade80dc8SMichael S. Tsirkin 931ade80dc8SMichael S. Tsirkin if (assign) { 932ade80dc8SMichael S. Tsirkin int r = event_notifier_init(notifier, 0); 933ade80dc8SMichael S. Tsirkin if (r < 0) { 934ade80dc8SMichael S. Tsirkin return r; 935ade80dc8SMichael S. Tsirkin } 93689d62be9SMichael S. Tsirkin virtio_queue_set_guest_notifier_fd_handler(vq, true, with_irqfd); 937ade80dc8SMichael S. Tsirkin } else { 93889d62be9SMichael S. Tsirkin virtio_queue_set_guest_notifier_fd_handler(vq, false, with_irqfd); 939ade80dc8SMichael S. Tsirkin event_notifier_cleanup(notifier); 940ade80dc8SMichael S. Tsirkin } 941ade80dc8SMichael S. Tsirkin 9425669655aSVictor Kaplansky if (!msix_enabled(&proxy->pci_dev) && 9435669655aSVictor Kaplansky vdev->use_guest_notifier_mask && 9445669655aSVictor Kaplansky vdc->guest_notifier_mask) { 945a3fc66d9SPaolo Bonzini vdc->guest_notifier_mask(vdev, n, !assign); 94662c96360SMichael S. Tsirkin } 94762c96360SMichael S. Tsirkin 948ade80dc8SMichael S. Tsirkin return 0; 949ade80dc8SMichael S. Tsirkin } 950ade80dc8SMichael S. Tsirkin 951d2a0ccc6SMichael S. Tsirkin static bool virtio_pci_query_guest_notifiers(DeviceState *d) 9525430a28fSmst@redhat.com { 953d2a0ccc6SMichael S. Tsirkin VirtIOPCIProxy *proxy = to_virtio_pci_proxy(d); 9545430a28fSmst@redhat.com return msix_enabled(&proxy->pci_dev); 9555430a28fSmst@redhat.com } 9565430a28fSmst@redhat.com 9572d620f59SMichael S. Tsirkin static int virtio_pci_set_guest_notifiers(DeviceState *d, int nvqs, bool assign) 95854dd9321SMichael S. Tsirkin { 959d2a0ccc6SMichael S. Tsirkin VirtIOPCIProxy *proxy = to_virtio_pci_proxy(d); 960a3fc66d9SPaolo Bonzini VirtIODevice *vdev = virtio_bus_get_device(&proxy->bus); 961181103cdSKONRAD Frederic VirtioDeviceClass *k = VIRTIO_DEVICE_GET_CLASS(vdev); 96254dd9321SMichael S. Tsirkin int r, n; 96389d62be9SMichael S. Tsirkin bool with_irqfd = msix_enabled(&proxy->pci_dev) && 96489d62be9SMichael S. Tsirkin kvm_msi_via_irqfd_enabled(); 96554dd9321SMichael S. Tsirkin 96687b3bd1cSJason Wang nvqs = MIN(nvqs, VIRTIO_QUEUE_MAX); 9672d620f59SMichael S. Tsirkin 9682d620f59SMichael S. Tsirkin /* When deassigning, pass a consistent nvqs value 9692d620f59SMichael S. Tsirkin * to avoid leaking notifiers. 9702d620f59SMichael S. Tsirkin */ 9712d620f59SMichael S. Tsirkin assert(assign || nvqs == proxy->nvqs_with_notifiers); 9722d620f59SMichael S. Tsirkin 9732d620f59SMichael S. Tsirkin proxy->nvqs_with_notifiers = nvqs; 9742d620f59SMichael S. Tsirkin 9757d37d351SJan Kiszka /* Must unset vector notifier while guest notifier is still assigned */ 976181103cdSKONRAD Frederic if ((proxy->vector_irqfd || k->guest_notifier_mask) && !assign) { 9777d37d351SJan Kiszka msix_unset_vector_notifiers(&proxy->pci_dev); 978a38b2c49SMichael S. Tsirkin if (proxy->vector_irqfd) { 979774345f9SMichael S. Tsirkin kvm_virtio_pci_vector_release(proxy, nvqs); 9807d37d351SJan Kiszka g_free(proxy->vector_irqfd); 9817d37d351SJan Kiszka proxy->vector_irqfd = NULL; 9827d37d351SJan Kiszka } 983a38b2c49SMichael S. Tsirkin } 9847d37d351SJan Kiszka 9852d620f59SMichael S. Tsirkin for (n = 0; n < nvqs; n++) { 98654dd9321SMichael S. Tsirkin if (!virtio_queue_get_num(vdev, n)) { 98754dd9321SMichael S. Tsirkin break; 98854dd9321SMichael S. Tsirkin } 98954dd9321SMichael S. Tsirkin 99023fe2b3fSMichael S. Tsirkin r = virtio_pci_set_guest_notifier(d, n, assign, with_irqfd); 99154dd9321SMichael S. Tsirkin if (r < 0) { 99254dd9321SMichael S. Tsirkin goto assign_error; 99354dd9321SMichael S. Tsirkin } 99454dd9321SMichael S. Tsirkin } 99554dd9321SMichael S. Tsirkin 9967d37d351SJan Kiszka /* Must set vector notifier after guest notifier has been assigned */ 997181103cdSKONRAD Frederic if ((with_irqfd || k->guest_notifier_mask) && assign) { 998a38b2c49SMichael S. Tsirkin if (with_irqfd) { 9997d37d351SJan Kiszka proxy->vector_irqfd = 10007d37d351SJan Kiszka g_malloc0(sizeof(*proxy->vector_irqfd) * 10017d37d351SJan Kiszka msix_nr_vectors_allocated(&proxy->pci_dev)); 1002774345f9SMichael S. Tsirkin r = kvm_virtio_pci_vector_use(proxy, nvqs); 10037d37d351SJan Kiszka if (r < 0) { 10047d37d351SJan Kiszka goto assign_error; 10057d37d351SJan Kiszka } 1006a38b2c49SMichael S. Tsirkin } 1007774345f9SMichael S. Tsirkin r = msix_set_vector_notifiers(&proxy->pci_dev, 1008a38b2c49SMichael S. Tsirkin virtio_pci_vector_unmask, 1009a38b2c49SMichael S. Tsirkin virtio_pci_vector_mask, 1010a38b2c49SMichael S. Tsirkin virtio_pci_vector_poll); 1011774345f9SMichael S. Tsirkin if (r < 0) { 1012774345f9SMichael S. Tsirkin goto notifiers_error; 1013774345f9SMichael S. Tsirkin } 10147d37d351SJan Kiszka } 10157d37d351SJan Kiszka 101654dd9321SMichael S. Tsirkin return 0; 101754dd9321SMichael S. Tsirkin 1018774345f9SMichael S. Tsirkin notifiers_error: 1019a38b2c49SMichael S. Tsirkin if (with_irqfd) { 1020774345f9SMichael S. Tsirkin assert(assign); 1021774345f9SMichael S. Tsirkin kvm_virtio_pci_vector_release(proxy, nvqs); 1022a38b2c49SMichael S. Tsirkin } 1023774345f9SMichael S. Tsirkin 102454dd9321SMichael S. Tsirkin assign_error: 102554dd9321SMichael S. Tsirkin /* We get here on assignment failure. Recover by undoing for VQs 0 .. n. */ 10267d37d351SJan Kiszka assert(assign); 102754dd9321SMichael S. Tsirkin while (--n >= 0) { 102889d62be9SMichael S. Tsirkin virtio_pci_set_guest_notifier(d, n, !assign, with_irqfd); 102954dd9321SMichael S. Tsirkin } 103054dd9321SMichael S. Tsirkin return r; 103154dd9321SMichael S. Tsirkin } 103254dd9321SMichael S. Tsirkin 10336f80e617STiwei Bie static int virtio_pci_set_host_notifier_mr(DeviceState *d, int n, 10346f80e617STiwei Bie MemoryRegion *mr, bool assign) 10356f80e617STiwei Bie { 10366f80e617STiwei Bie VirtIOPCIProxy *proxy = to_virtio_pci_proxy(d); 10376f80e617STiwei Bie int offset; 10386f80e617STiwei Bie 10396f80e617STiwei Bie if (n >= VIRTIO_QUEUE_MAX || !virtio_pci_modern(proxy) || 10406f80e617STiwei Bie virtio_pci_queue_mem_mult(proxy) != memory_region_size(mr)) { 10416f80e617STiwei Bie return -1; 10426f80e617STiwei Bie } 10436f80e617STiwei Bie 10446f80e617STiwei Bie if (assign) { 10456f80e617STiwei Bie offset = virtio_pci_queue_mem_mult(proxy) * n; 10466f80e617STiwei Bie memory_region_add_subregion_overlap(&proxy->notify.mr, offset, mr, 1); 10476f80e617STiwei Bie } else { 10486f80e617STiwei Bie memory_region_del_subregion(&proxy->notify.mr, mr); 10496f80e617STiwei Bie } 10506f80e617STiwei Bie 10516f80e617STiwei Bie return 0; 10526f80e617STiwei Bie } 10536f80e617STiwei Bie 1054d2a0ccc6SMichael S. Tsirkin static void virtio_pci_vmstate_change(DeviceState *d, bool running) 105525db9ebeSStefan Hajnoczi { 1056d2a0ccc6SMichael S. Tsirkin VirtIOPCIProxy *proxy = to_virtio_pci_proxy(d); 1057a3fc66d9SPaolo Bonzini VirtIODevice *vdev = virtio_bus_get_device(&proxy->bus); 105825db9ebeSStefan Hajnoczi 105925db9ebeSStefan Hajnoczi if (running) { 106068a27b20SMichael S. Tsirkin /* Old QEMU versions did not set bus master enable on status write. 106168a27b20SMichael S. Tsirkin * Detect DRIVER set and enable it. 106268a27b20SMichael S. Tsirkin */ 106368a27b20SMichael S. Tsirkin if ((proxy->flags & VIRTIO_PCI_FLAG_BUS_MASTER_BUG_MIGRATION) && 106468a27b20SMichael S. Tsirkin (vdev->status & VIRTIO_CONFIG_S_DRIVER) && 106545363e46SMichael S. Tsirkin !(proxy->pci_dev.config[PCI_COMMAND] & PCI_COMMAND_MASTER)) { 106668a27b20SMichael S. Tsirkin pci_default_write_config(&proxy->pci_dev, PCI_COMMAND, 106768a27b20SMichael S. Tsirkin proxy->pci_dev.config[PCI_COMMAND] | 106868a27b20SMichael S. Tsirkin PCI_COMMAND_MASTER, 1); 106989c473fdSMichael S. Tsirkin } 107025db9ebeSStefan Hajnoczi virtio_pci_start_ioeventfd(proxy); 1071ade80dc8SMichael S. Tsirkin } else { 107225db9ebeSStefan Hajnoczi virtio_pci_stop_ioeventfd(proxy); 1073ade80dc8SMichael S. Tsirkin } 1074ade80dc8SMichael S. Tsirkin } 1075ade80dc8SMichael S. Tsirkin 1076085bccb7SKONRAD Frederic /* 1077085bccb7SKONRAD Frederic * virtio-pci: This is the PCIDevice which has a virtio-pci-bus. 1078085bccb7SKONRAD Frederic */ 1079085bccb7SKONRAD Frederic 1080e0d686bfSJason Wang static int virtio_pci_query_nvectors(DeviceState *d) 1081e0d686bfSJason Wang { 1082e0d686bfSJason Wang VirtIOPCIProxy *proxy = VIRTIO_PCI(d); 1083e0d686bfSJason Wang 1084e0d686bfSJason Wang return proxy->nvectors; 1085e0d686bfSJason Wang } 1086e0d686bfSJason Wang 10878607f5c3SJason Wang static AddressSpace *virtio_pci_get_dma_as(DeviceState *d) 10888607f5c3SJason Wang { 10898607f5c3SJason Wang VirtIOPCIProxy *proxy = VIRTIO_PCI(d); 10908607f5c3SJason Wang PCIDevice *dev = &proxy->pci_dev; 10918607f5c3SJason Wang 1092f0edf239SJason Wang return pci_get_address_space(dev); 10938607f5c3SJason Wang } 10948607f5c3SJason Wang 1095ada434cdSMichael S. Tsirkin static int virtio_pci_add_mem_cap(VirtIOPCIProxy *proxy, 1096dfb8e184SMichael S. Tsirkin struct virtio_pci_cap *cap) 1097dfb8e184SMichael S. Tsirkin { 1098dfb8e184SMichael S. Tsirkin PCIDevice *dev = &proxy->pci_dev; 1099dfb8e184SMichael S. Tsirkin int offset; 1100dfb8e184SMichael S. Tsirkin 11019a7c2a59SMao Zhongyi offset = pci_add_capability(dev, PCI_CAP_ID_VNDR, 0, 11029a7c2a59SMao Zhongyi cap->cap_len, &error_abort); 1103dfb8e184SMichael S. Tsirkin 1104dfb8e184SMichael S. Tsirkin assert(cap->cap_len >= sizeof *cap); 1105dfb8e184SMichael S. Tsirkin memcpy(dev->config + offset + PCI_CAP_FLAGS, &cap->cap_len, 1106dfb8e184SMichael S. Tsirkin cap->cap_len - PCI_CAP_FLAGS); 1107ada434cdSMichael S. Tsirkin 1108ada434cdSMichael S. Tsirkin return offset; 1109dfb8e184SMichael S. Tsirkin } 1110dfb8e184SMichael S. Tsirkin 1111dfb8e184SMichael S. Tsirkin static uint64_t virtio_pci_common_read(void *opaque, hwaddr addr, 1112dfb8e184SMichael S. Tsirkin unsigned size) 1113dfb8e184SMichael S. Tsirkin { 1114dfb8e184SMichael S. Tsirkin VirtIOPCIProxy *proxy = opaque; 1115dfb8e184SMichael S. Tsirkin VirtIODevice *vdev = virtio_bus_get_device(&proxy->bus); 1116dfb8e184SMichael S. Tsirkin uint32_t val = 0; 1117dfb8e184SMichael S. Tsirkin int i; 1118dfb8e184SMichael S. Tsirkin 1119dfb8e184SMichael S. Tsirkin switch (addr) { 1120dfb8e184SMichael S. Tsirkin case VIRTIO_PCI_COMMON_DFSELECT: 1121dfb8e184SMichael S. Tsirkin val = proxy->dfselect; 1122dfb8e184SMichael S. Tsirkin break; 1123dfb8e184SMichael S. Tsirkin case VIRTIO_PCI_COMMON_DF: 1124dfb8e184SMichael S. Tsirkin if (proxy->dfselect <= 1) { 11259b706dbbSMichael S. Tsirkin VirtioDeviceClass *vdc = VIRTIO_DEVICE_GET_CLASS(vdev); 11269b706dbbSMichael S. Tsirkin 11279b706dbbSMichael S. Tsirkin val = (vdev->host_features & ~vdc->legacy_features) >> 11285f456073SMichael S. Tsirkin (32 * proxy->dfselect); 1129dfb8e184SMichael S. Tsirkin } 1130dfb8e184SMichael S. Tsirkin break; 1131dfb8e184SMichael S. Tsirkin case VIRTIO_PCI_COMMON_GFSELECT: 1132dfb8e184SMichael S. Tsirkin val = proxy->gfselect; 1133dfb8e184SMichael S. Tsirkin break; 1134dfb8e184SMichael S. Tsirkin case VIRTIO_PCI_COMMON_GF: 11353750dabcSGonglei if (proxy->gfselect < ARRAY_SIZE(proxy->guest_features)) { 1136dfb8e184SMichael S. Tsirkin val = proxy->guest_features[proxy->gfselect]; 1137dfb8e184SMichael S. Tsirkin } 1138dfb8e184SMichael S. Tsirkin break; 1139dfb8e184SMichael S. Tsirkin case VIRTIO_PCI_COMMON_MSIX: 1140dfb8e184SMichael S. Tsirkin val = vdev->config_vector; 1141dfb8e184SMichael S. Tsirkin break; 1142dfb8e184SMichael S. Tsirkin case VIRTIO_PCI_COMMON_NUMQ: 1143dfb8e184SMichael S. Tsirkin for (i = 0; i < VIRTIO_QUEUE_MAX; ++i) { 1144dfb8e184SMichael S. Tsirkin if (virtio_queue_get_num(vdev, i)) { 1145dfb8e184SMichael S. Tsirkin val = i + 1; 1146dfb8e184SMichael S. Tsirkin } 1147dfb8e184SMichael S. Tsirkin } 1148dfb8e184SMichael S. Tsirkin break; 1149dfb8e184SMichael S. Tsirkin case VIRTIO_PCI_COMMON_STATUS: 1150dfb8e184SMichael S. Tsirkin val = vdev->status; 1151dfb8e184SMichael S. Tsirkin break; 1152dfb8e184SMichael S. Tsirkin case VIRTIO_PCI_COMMON_CFGGENERATION: 1153b8f05908SMichael S. Tsirkin val = vdev->generation; 1154dfb8e184SMichael S. Tsirkin break; 1155dfb8e184SMichael S. Tsirkin case VIRTIO_PCI_COMMON_Q_SELECT: 1156dfb8e184SMichael S. Tsirkin val = vdev->queue_sel; 1157dfb8e184SMichael S. Tsirkin break; 1158dfb8e184SMichael S. Tsirkin case VIRTIO_PCI_COMMON_Q_SIZE: 1159dfb8e184SMichael S. Tsirkin val = virtio_queue_get_num(vdev, vdev->queue_sel); 1160dfb8e184SMichael S. Tsirkin break; 1161dfb8e184SMichael S. Tsirkin case VIRTIO_PCI_COMMON_Q_MSIX: 1162dfb8e184SMichael S. Tsirkin val = virtio_queue_vector(vdev, vdev->queue_sel); 1163dfb8e184SMichael S. Tsirkin break; 1164dfb8e184SMichael S. Tsirkin case VIRTIO_PCI_COMMON_Q_ENABLE: 1165dfb8e184SMichael S. Tsirkin val = proxy->vqs[vdev->queue_sel].enabled; 1166dfb8e184SMichael S. Tsirkin break; 1167dfb8e184SMichael S. Tsirkin case VIRTIO_PCI_COMMON_Q_NOFF: 1168dfb8e184SMichael S. Tsirkin /* Simply map queues in order */ 1169dfb8e184SMichael S. Tsirkin val = vdev->queue_sel; 1170dfb8e184SMichael S. Tsirkin break; 1171dfb8e184SMichael S. Tsirkin case VIRTIO_PCI_COMMON_Q_DESCLO: 1172dfb8e184SMichael S. Tsirkin val = proxy->vqs[vdev->queue_sel].desc[0]; 1173dfb8e184SMichael S. Tsirkin break; 1174dfb8e184SMichael S. Tsirkin case VIRTIO_PCI_COMMON_Q_DESCHI: 1175dfb8e184SMichael S. Tsirkin val = proxy->vqs[vdev->queue_sel].desc[1]; 1176dfb8e184SMichael S. Tsirkin break; 1177dfb8e184SMichael S. Tsirkin case VIRTIO_PCI_COMMON_Q_AVAILLO: 1178dfb8e184SMichael S. Tsirkin val = proxy->vqs[vdev->queue_sel].avail[0]; 1179dfb8e184SMichael S. Tsirkin break; 1180dfb8e184SMichael S. Tsirkin case VIRTIO_PCI_COMMON_Q_AVAILHI: 1181dfb8e184SMichael S. Tsirkin val = proxy->vqs[vdev->queue_sel].avail[1]; 1182dfb8e184SMichael S. Tsirkin break; 1183dfb8e184SMichael S. Tsirkin case VIRTIO_PCI_COMMON_Q_USEDLO: 1184dfb8e184SMichael S. Tsirkin val = proxy->vqs[vdev->queue_sel].used[0]; 1185dfb8e184SMichael S. Tsirkin break; 1186dfb8e184SMichael S. Tsirkin case VIRTIO_PCI_COMMON_Q_USEDHI: 1187dfb8e184SMichael S. Tsirkin val = proxy->vqs[vdev->queue_sel].used[1]; 1188dfb8e184SMichael S. Tsirkin break; 1189dfb8e184SMichael S. Tsirkin default: 1190dfb8e184SMichael S. Tsirkin val = 0; 1191dfb8e184SMichael S. Tsirkin } 1192dfb8e184SMichael S. Tsirkin 1193dfb8e184SMichael S. Tsirkin return val; 1194dfb8e184SMichael S. Tsirkin } 1195dfb8e184SMichael S. Tsirkin 1196dfb8e184SMichael S. Tsirkin static void virtio_pci_common_write(void *opaque, hwaddr addr, 1197dfb8e184SMichael S. Tsirkin uint64_t val, unsigned size) 1198dfb8e184SMichael S. Tsirkin { 1199dfb8e184SMichael S. Tsirkin VirtIOPCIProxy *proxy = opaque; 1200dfb8e184SMichael S. Tsirkin VirtIODevice *vdev = virtio_bus_get_device(&proxy->bus); 1201dfb8e184SMichael S. Tsirkin 1202dfb8e184SMichael S. Tsirkin switch (addr) { 1203dfb8e184SMichael S. Tsirkin case VIRTIO_PCI_COMMON_DFSELECT: 1204dfb8e184SMichael S. Tsirkin proxy->dfselect = val; 1205dfb8e184SMichael S. Tsirkin break; 1206dfb8e184SMichael S. Tsirkin case VIRTIO_PCI_COMMON_GFSELECT: 1207dfb8e184SMichael S. Tsirkin proxy->gfselect = val; 1208dfb8e184SMichael S. Tsirkin break; 1209dfb8e184SMichael S. Tsirkin case VIRTIO_PCI_COMMON_GF: 12103750dabcSGonglei if (proxy->gfselect < ARRAY_SIZE(proxy->guest_features)) { 1211dfb8e184SMichael S. Tsirkin proxy->guest_features[proxy->gfselect] = val; 1212dfb8e184SMichael S. Tsirkin virtio_set_features(vdev, 1213dfb8e184SMichael S. Tsirkin (((uint64_t)proxy->guest_features[1]) << 32) | 1214dfb8e184SMichael S. Tsirkin proxy->guest_features[0]); 1215dfb8e184SMichael S. Tsirkin } 1216dfb8e184SMichael S. Tsirkin break; 1217dfb8e184SMichael S. Tsirkin case VIRTIO_PCI_COMMON_MSIX: 1218dfb8e184SMichael S. Tsirkin msix_vector_unuse(&proxy->pci_dev, vdev->config_vector); 1219dfb8e184SMichael S. Tsirkin /* Make it possible for guest to discover an error took place. */ 1220dfb8e184SMichael S. Tsirkin if (msix_vector_use(&proxy->pci_dev, val) < 0) { 1221dfb8e184SMichael S. Tsirkin val = VIRTIO_NO_VECTOR; 1222dfb8e184SMichael S. Tsirkin } 1223dfb8e184SMichael S. Tsirkin vdev->config_vector = val; 1224dfb8e184SMichael S. Tsirkin break; 1225dfb8e184SMichael S. Tsirkin case VIRTIO_PCI_COMMON_STATUS: 1226dfb8e184SMichael S. Tsirkin if (!(val & VIRTIO_CONFIG_S_DRIVER_OK)) { 1227dfb8e184SMichael S. Tsirkin virtio_pci_stop_ioeventfd(proxy); 1228dfb8e184SMichael S. Tsirkin } 1229dfb8e184SMichael S. Tsirkin 1230dfb8e184SMichael S. Tsirkin virtio_set_status(vdev, val & 0xFF); 1231dfb8e184SMichael S. Tsirkin 1232dfb8e184SMichael S. Tsirkin if (val & VIRTIO_CONFIG_S_DRIVER_OK) { 1233dfb8e184SMichael S. Tsirkin virtio_pci_start_ioeventfd(proxy); 1234dfb8e184SMichael S. Tsirkin } 1235dfb8e184SMichael S. Tsirkin 1236dfb8e184SMichael S. Tsirkin if (vdev->status == 0) { 123775fd6f13SGerd Hoffmann virtio_pci_reset(DEVICE(proxy)); 1238dfb8e184SMichael S. Tsirkin } 1239dfb8e184SMichael S. Tsirkin 1240dfb8e184SMichael S. Tsirkin break; 1241dfb8e184SMichael S. Tsirkin case VIRTIO_PCI_COMMON_Q_SELECT: 1242dfb8e184SMichael S. Tsirkin if (val < VIRTIO_QUEUE_MAX) { 1243dfb8e184SMichael S. Tsirkin vdev->queue_sel = val; 1244dfb8e184SMichael S. Tsirkin } 1245dfb8e184SMichael S. Tsirkin break; 1246dfb8e184SMichael S. Tsirkin case VIRTIO_PCI_COMMON_Q_SIZE: 1247dfb8e184SMichael S. Tsirkin proxy->vqs[vdev->queue_sel].num = val; 1248dfb8e184SMichael S. Tsirkin break; 1249dfb8e184SMichael S. Tsirkin case VIRTIO_PCI_COMMON_Q_MSIX: 1250dfb8e184SMichael S. Tsirkin msix_vector_unuse(&proxy->pci_dev, 1251dfb8e184SMichael S. Tsirkin virtio_queue_vector(vdev, vdev->queue_sel)); 1252dfb8e184SMichael S. Tsirkin /* Make it possible for guest to discover an error took place. */ 1253dfb8e184SMichael S. Tsirkin if (msix_vector_use(&proxy->pci_dev, val) < 0) { 1254dfb8e184SMichael S. Tsirkin val = VIRTIO_NO_VECTOR; 1255dfb8e184SMichael S. Tsirkin } 1256dfb8e184SMichael S. Tsirkin virtio_queue_set_vector(vdev, vdev->queue_sel, val); 1257dfb8e184SMichael S. Tsirkin break; 1258dfb8e184SMichael S. Tsirkin case VIRTIO_PCI_COMMON_Q_ENABLE: 1259dfb8e184SMichael S. Tsirkin virtio_queue_set_num(vdev, vdev->queue_sel, 1260dfb8e184SMichael S. Tsirkin proxy->vqs[vdev->queue_sel].num); 1261dfb8e184SMichael S. Tsirkin virtio_queue_set_rings(vdev, vdev->queue_sel, 1262dfb8e184SMichael S. Tsirkin ((uint64_t)proxy->vqs[vdev->queue_sel].desc[1]) << 32 | 1263dfb8e184SMichael S. Tsirkin proxy->vqs[vdev->queue_sel].desc[0], 1264dfb8e184SMichael S. Tsirkin ((uint64_t)proxy->vqs[vdev->queue_sel].avail[1]) << 32 | 1265dfb8e184SMichael S. Tsirkin proxy->vqs[vdev->queue_sel].avail[0], 1266dfb8e184SMichael S. Tsirkin ((uint64_t)proxy->vqs[vdev->queue_sel].used[1]) << 32 | 1267dfb8e184SMichael S. Tsirkin proxy->vqs[vdev->queue_sel].used[0]); 1268393f04d3SJason Wang proxy->vqs[vdev->queue_sel].enabled = 1; 1269dfb8e184SMichael S. Tsirkin break; 1270dfb8e184SMichael S. Tsirkin case VIRTIO_PCI_COMMON_Q_DESCLO: 1271dfb8e184SMichael S. Tsirkin proxy->vqs[vdev->queue_sel].desc[0] = val; 1272dfb8e184SMichael S. Tsirkin break; 1273dfb8e184SMichael S. Tsirkin case VIRTIO_PCI_COMMON_Q_DESCHI: 1274dfb8e184SMichael S. Tsirkin proxy->vqs[vdev->queue_sel].desc[1] = val; 1275dfb8e184SMichael S. Tsirkin break; 1276dfb8e184SMichael S. Tsirkin case VIRTIO_PCI_COMMON_Q_AVAILLO: 1277dfb8e184SMichael S. Tsirkin proxy->vqs[vdev->queue_sel].avail[0] = val; 1278dfb8e184SMichael S. Tsirkin break; 1279dfb8e184SMichael S. Tsirkin case VIRTIO_PCI_COMMON_Q_AVAILHI: 1280dfb8e184SMichael S. Tsirkin proxy->vqs[vdev->queue_sel].avail[1] = val; 1281dfb8e184SMichael S. Tsirkin break; 1282dfb8e184SMichael S. Tsirkin case VIRTIO_PCI_COMMON_Q_USEDLO: 1283dfb8e184SMichael S. Tsirkin proxy->vqs[vdev->queue_sel].used[0] = val; 1284dfb8e184SMichael S. Tsirkin break; 1285dfb8e184SMichael S. Tsirkin case VIRTIO_PCI_COMMON_Q_USEDHI: 1286dfb8e184SMichael S. Tsirkin proxy->vqs[vdev->queue_sel].used[1] = val; 1287dfb8e184SMichael S. Tsirkin break; 1288dfb8e184SMichael S. Tsirkin default: 1289dfb8e184SMichael S. Tsirkin break; 1290dfb8e184SMichael S. Tsirkin } 1291dfb8e184SMichael S. Tsirkin } 1292dfb8e184SMichael S. Tsirkin 1293dfb8e184SMichael S. Tsirkin 1294dfb8e184SMichael S. Tsirkin static uint64_t virtio_pci_notify_read(void *opaque, hwaddr addr, 1295dfb8e184SMichael S. Tsirkin unsigned size) 1296dfb8e184SMichael S. Tsirkin { 1297dfb8e184SMichael S. Tsirkin return 0; 1298dfb8e184SMichael S. Tsirkin } 1299dfb8e184SMichael S. Tsirkin 1300dfb8e184SMichael S. Tsirkin static void virtio_pci_notify_write(void *opaque, hwaddr addr, 1301dfb8e184SMichael S. Tsirkin uint64_t val, unsigned size) 1302dfb8e184SMichael S. Tsirkin { 1303dfb8e184SMichael S. Tsirkin VirtIODevice *vdev = opaque; 1304d9997d89SMarcel Apfelbaum VirtIOPCIProxy *proxy = VIRTIO_PCI(DEVICE(vdev)->parent_bus->parent); 1305d9997d89SMarcel Apfelbaum unsigned queue = addr / virtio_pci_queue_mem_mult(proxy); 1306dfb8e184SMichael S. Tsirkin 1307dfb8e184SMichael S. Tsirkin if (queue < VIRTIO_QUEUE_MAX) { 1308dfb8e184SMichael S. Tsirkin virtio_queue_notify(vdev, queue); 1309dfb8e184SMichael S. Tsirkin } 1310dfb8e184SMichael S. Tsirkin } 1311dfb8e184SMichael S. Tsirkin 13129824d2a3SJason Wang static void virtio_pci_notify_write_pio(void *opaque, hwaddr addr, 13139824d2a3SJason Wang uint64_t val, unsigned size) 13149824d2a3SJason Wang { 13159824d2a3SJason Wang VirtIODevice *vdev = opaque; 13169824d2a3SJason Wang unsigned queue = val; 13179824d2a3SJason Wang 13189824d2a3SJason Wang if (queue < VIRTIO_QUEUE_MAX) { 13199824d2a3SJason Wang virtio_queue_notify(vdev, queue); 13209824d2a3SJason Wang } 13219824d2a3SJason Wang } 13229824d2a3SJason Wang 1323dfb8e184SMichael S. Tsirkin static uint64_t virtio_pci_isr_read(void *opaque, hwaddr addr, 1324dfb8e184SMichael S. Tsirkin unsigned size) 1325dfb8e184SMichael S. Tsirkin { 1326dfb8e184SMichael S. Tsirkin VirtIOPCIProxy *proxy = opaque; 1327dfb8e184SMichael S. Tsirkin VirtIODevice *vdev = virtio_bus_get_device(&proxy->bus); 13280687c37cSPaolo Bonzini uint64_t val = atomic_xchg(&vdev->isr, 0); 1329dfb8e184SMichael S. Tsirkin pci_irq_deassert(&proxy->pci_dev); 1330dfb8e184SMichael S. Tsirkin 1331dfb8e184SMichael S. Tsirkin return val; 1332dfb8e184SMichael S. Tsirkin } 1333dfb8e184SMichael S. Tsirkin 1334dfb8e184SMichael S. Tsirkin static void virtio_pci_isr_write(void *opaque, hwaddr addr, 1335dfb8e184SMichael S. Tsirkin uint64_t val, unsigned size) 1336dfb8e184SMichael S. Tsirkin { 1337dfb8e184SMichael S. Tsirkin } 1338dfb8e184SMichael S. Tsirkin 1339dfb8e184SMichael S. Tsirkin static uint64_t virtio_pci_device_read(void *opaque, hwaddr addr, 1340dfb8e184SMichael S. Tsirkin unsigned size) 1341dfb8e184SMichael S. Tsirkin { 1342dfb8e184SMichael S. Tsirkin VirtIODevice *vdev = opaque; 1343dfb8e184SMichael S. Tsirkin uint64_t val = 0; 1344dfb8e184SMichael S. Tsirkin 1345dfb8e184SMichael S. Tsirkin switch (size) { 1346dfb8e184SMichael S. Tsirkin case 1: 134754c720d4SMichael S. Tsirkin val = virtio_config_modern_readb(vdev, addr); 1348dfb8e184SMichael S. Tsirkin break; 1349dfb8e184SMichael S. Tsirkin case 2: 135054c720d4SMichael S. Tsirkin val = virtio_config_modern_readw(vdev, addr); 1351dfb8e184SMichael S. Tsirkin break; 1352dfb8e184SMichael S. Tsirkin case 4: 135354c720d4SMichael S. Tsirkin val = virtio_config_modern_readl(vdev, addr); 1354dfb8e184SMichael S. Tsirkin break; 1355dfb8e184SMichael S. Tsirkin } 1356dfb8e184SMichael S. Tsirkin return val; 1357dfb8e184SMichael S. Tsirkin } 1358dfb8e184SMichael S. Tsirkin 1359dfb8e184SMichael S. Tsirkin static void virtio_pci_device_write(void *opaque, hwaddr addr, 1360dfb8e184SMichael S. Tsirkin uint64_t val, unsigned size) 1361dfb8e184SMichael S. Tsirkin { 1362dfb8e184SMichael S. Tsirkin VirtIODevice *vdev = opaque; 1363dfb8e184SMichael S. Tsirkin switch (size) { 1364dfb8e184SMichael S. Tsirkin case 1: 136554c720d4SMichael S. Tsirkin virtio_config_modern_writeb(vdev, addr, val); 1366dfb8e184SMichael S. Tsirkin break; 1367dfb8e184SMichael S. Tsirkin case 2: 136854c720d4SMichael S. Tsirkin virtio_config_modern_writew(vdev, addr, val); 1369dfb8e184SMichael S. Tsirkin break; 1370dfb8e184SMichael S. Tsirkin case 4: 137154c720d4SMichael S. Tsirkin virtio_config_modern_writel(vdev, addr, val); 1372dfb8e184SMichael S. Tsirkin break; 1373dfb8e184SMichael S. Tsirkin } 1374dfb8e184SMichael S. Tsirkin } 1375dfb8e184SMichael S. Tsirkin 13761141ce21SGerd Hoffmann static void virtio_pci_modern_regions_init(VirtIOPCIProxy *proxy) 13771141ce21SGerd Hoffmann { 13781141ce21SGerd Hoffmann static const MemoryRegionOps common_ops = { 13791141ce21SGerd Hoffmann .read = virtio_pci_common_read, 13801141ce21SGerd Hoffmann .write = virtio_pci_common_write, 13811141ce21SGerd Hoffmann .impl = { 13821141ce21SGerd Hoffmann .min_access_size = 1, 13831141ce21SGerd Hoffmann .max_access_size = 4, 13841141ce21SGerd Hoffmann }, 13851141ce21SGerd Hoffmann .endianness = DEVICE_LITTLE_ENDIAN, 13861141ce21SGerd Hoffmann }; 13871141ce21SGerd Hoffmann static const MemoryRegionOps isr_ops = { 13881141ce21SGerd Hoffmann .read = virtio_pci_isr_read, 13891141ce21SGerd Hoffmann .write = virtio_pci_isr_write, 13901141ce21SGerd Hoffmann .impl = { 13911141ce21SGerd Hoffmann .min_access_size = 1, 13921141ce21SGerd Hoffmann .max_access_size = 4, 13931141ce21SGerd Hoffmann }, 13941141ce21SGerd Hoffmann .endianness = DEVICE_LITTLE_ENDIAN, 13951141ce21SGerd Hoffmann }; 13961141ce21SGerd Hoffmann static const MemoryRegionOps device_ops = { 13971141ce21SGerd Hoffmann .read = virtio_pci_device_read, 13981141ce21SGerd Hoffmann .write = virtio_pci_device_write, 13991141ce21SGerd Hoffmann .impl = { 14001141ce21SGerd Hoffmann .min_access_size = 1, 14011141ce21SGerd Hoffmann .max_access_size = 4, 14021141ce21SGerd Hoffmann }, 14031141ce21SGerd Hoffmann .endianness = DEVICE_LITTLE_ENDIAN, 14041141ce21SGerd Hoffmann }; 14051141ce21SGerd Hoffmann static const MemoryRegionOps notify_ops = { 14061141ce21SGerd Hoffmann .read = virtio_pci_notify_read, 14071141ce21SGerd Hoffmann .write = virtio_pci_notify_write, 14081141ce21SGerd Hoffmann .impl = { 14091141ce21SGerd Hoffmann .min_access_size = 1, 14101141ce21SGerd Hoffmann .max_access_size = 4, 14111141ce21SGerd Hoffmann }, 14121141ce21SGerd Hoffmann .endianness = DEVICE_LITTLE_ENDIAN, 14131141ce21SGerd Hoffmann }; 14149824d2a3SJason Wang static const MemoryRegionOps notify_pio_ops = { 14159824d2a3SJason Wang .read = virtio_pci_notify_read, 14169824d2a3SJason Wang .write = virtio_pci_notify_write_pio, 14179824d2a3SJason Wang .impl = { 14189824d2a3SJason Wang .min_access_size = 1, 14199824d2a3SJason Wang .max_access_size = 4, 14209824d2a3SJason Wang }, 14219824d2a3SJason Wang .endianness = DEVICE_LITTLE_ENDIAN, 14229824d2a3SJason Wang }; 14239824d2a3SJason Wang 14241141ce21SGerd Hoffmann 14251141ce21SGerd Hoffmann memory_region_init_io(&proxy->common.mr, OBJECT(proxy), 14261141ce21SGerd Hoffmann &common_ops, 14271141ce21SGerd Hoffmann proxy, 1428b6ce27a5SGerd Hoffmann "virtio-pci-common", 1429b6ce27a5SGerd Hoffmann proxy->common.size); 1430a3cc2e81SGerd Hoffmann 14311141ce21SGerd Hoffmann memory_region_init_io(&proxy->isr.mr, OBJECT(proxy), 14321141ce21SGerd Hoffmann &isr_ops, 14331141ce21SGerd Hoffmann proxy, 1434b6ce27a5SGerd Hoffmann "virtio-pci-isr", 1435b6ce27a5SGerd Hoffmann proxy->isr.size); 1436a3cc2e81SGerd Hoffmann 14371141ce21SGerd Hoffmann memory_region_init_io(&proxy->device.mr, OBJECT(proxy), 14381141ce21SGerd Hoffmann &device_ops, 14391141ce21SGerd Hoffmann virtio_bus_get_device(&proxy->bus), 1440b6ce27a5SGerd Hoffmann "virtio-pci-device", 1441b6ce27a5SGerd Hoffmann proxy->device.size); 1442a3cc2e81SGerd Hoffmann 14431141ce21SGerd Hoffmann memory_region_init_io(&proxy->notify.mr, OBJECT(proxy), 14441141ce21SGerd Hoffmann ¬ify_ops, 14451141ce21SGerd Hoffmann virtio_bus_get_device(&proxy->bus), 14461141ce21SGerd Hoffmann "virtio-pci-notify", 1447b6ce27a5SGerd Hoffmann proxy->notify.size); 14489824d2a3SJason Wang 14499824d2a3SJason Wang memory_region_init_io(&proxy->notify_pio.mr, OBJECT(proxy), 14509824d2a3SJason Wang ¬ify_pio_ops, 14519824d2a3SJason Wang virtio_bus_get_device(&proxy->bus), 14529824d2a3SJason Wang "virtio-pci-notify-pio", 1453e3aab6c7SMichael S. Tsirkin proxy->notify_pio.size); 1454a3cc2e81SGerd Hoffmann } 1455a3cc2e81SGerd Hoffmann 1456a3cc2e81SGerd Hoffmann static void virtio_pci_modern_region_map(VirtIOPCIProxy *proxy, 145754790d71SGerd Hoffmann VirtIOPCIRegion *region, 14589824d2a3SJason Wang struct virtio_pci_cap *cap, 14599824d2a3SJason Wang MemoryRegion *mr, 14609824d2a3SJason Wang uint8_t bar) 1461a3cc2e81SGerd Hoffmann { 14629824d2a3SJason Wang memory_region_add_subregion(mr, region->offset, ®ion->mr); 146354790d71SGerd Hoffmann 1464fc004905SGerd Hoffmann cap->cfg_type = region->type; 14659824d2a3SJason Wang cap->bar = bar; 146654790d71SGerd Hoffmann cap->offset = cpu_to_le32(region->offset); 1467b6ce27a5SGerd Hoffmann cap->length = cpu_to_le32(region->size); 146854790d71SGerd Hoffmann virtio_pci_add_mem_cap(proxy, cap); 14699824d2a3SJason Wang 14701141ce21SGerd Hoffmann } 1471dfb8e184SMichael S. Tsirkin 14729824d2a3SJason Wang static void virtio_pci_modern_mem_region_map(VirtIOPCIProxy *proxy, 14739824d2a3SJason Wang VirtIOPCIRegion *region, 14749824d2a3SJason Wang struct virtio_pci_cap *cap) 14759824d2a3SJason Wang { 14769824d2a3SJason Wang virtio_pci_modern_region_map(proxy, region, cap, 14777a25126dSChen Fan &proxy->modern_bar, proxy->modern_mem_bar_idx); 14789824d2a3SJason Wang } 14799824d2a3SJason Wang 14809824d2a3SJason Wang static void virtio_pci_modern_io_region_map(VirtIOPCIProxy *proxy, 14819824d2a3SJason Wang VirtIOPCIRegion *region, 14829824d2a3SJason Wang struct virtio_pci_cap *cap) 14839824d2a3SJason Wang { 14849824d2a3SJason Wang virtio_pci_modern_region_map(proxy, region, cap, 14857a25126dSChen Fan &proxy->io_bar, proxy->modern_io_bar_idx); 14869824d2a3SJason Wang } 14879824d2a3SJason Wang 14889824d2a3SJason Wang static void virtio_pci_modern_mem_region_unmap(VirtIOPCIProxy *proxy, 148927462695SMichael S. Tsirkin VirtIOPCIRegion *region) 149027462695SMichael S. Tsirkin { 149127462695SMichael S. Tsirkin memory_region_del_subregion(&proxy->modern_bar, 149227462695SMichael S. Tsirkin ®ion->mr); 149327462695SMichael S. Tsirkin } 149427462695SMichael S. Tsirkin 14959824d2a3SJason Wang static void virtio_pci_modern_io_region_unmap(VirtIOPCIProxy *proxy, 14969824d2a3SJason Wang VirtIOPCIRegion *region) 14979824d2a3SJason Wang { 14989824d2a3SJason Wang memory_region_del_subregion(&proxy->io_bar, 14999824d2a3SJason Wang ®ion->mr); 15009824d2a3SJason Wang } 15019824d2a3SJason Wang 1502d1b4259fSMaxime Coquelin static void virtio_pci_pre_plugged(DeviceState *d, Error **errp) 1503d1b4259fSMaxime Coquelin { 1504d1b4259fSMaxime Coquelin VirtIOPCIProxy *proxy = VIRTIO_PCI(d); 1505d1b4259fSMaxime Coquelin VirtIODevice *vdev = virtio_bus_get_device(&proxy->bus); 1506d1b4259fSMaxime Coquelin 1507d1b4259fSMaxime Coquelin if (virtio_pci_modern(proxy)) { 1508d1b4259fSMaxime Coquelin virtio_add_feature(&vdev->host_features, VIRTIO_F_VERSION_1); 1509d1b4259fSMaxime Coquelin } 1510d1b4259fSMaxime Coquelin 1511d1b4259fSMaxime Coquelin virtio_add_feature(&vdev->host_features, VIRTIO_F_BAD_FEATURE); 1512d1b4259fSMaxime Coquelin } 1513d1b4259fSMaxime Coquelin 1514085bccb7SKONRAD Frederic /* This is called by virtio-bus just after the device is plugged. */ 1515e8398045SJason Wang static void virtio_pci_device_plugged(DeviceState *d, Error **errp) 1516085bccb7SKONRAD Frederic { 1517085bccb7SKONRAD Frederic VirtIOPCIProxy *proxy = VIRTIO_PCI(d); 1518085bccb7SKONRAD Frederic VirtioBusState *bus = &proxy->bus; 15199a4c0e22SMarcel Apfelbaum bool legacy = virtio_pci_legacy(proxy); 1520d1b4259fSMaxime Coquelin bool modern; 15219824d2a3SJason Wang bool modern_pio = proxy->flags & VIRTIO_PCI_FLAG_MODERN_PIO_NOTIFY; 1522085bccb7SKONRAD Frederic uint8_t *config; 1523085bccb7SKONRAD Frederic uint32_t size; 15246b8f1020SCornelia Huck VirtIODevice *vdev = virtio_bus_get_device(&proxy->bus); 1525085bccb7SKONRAD Frederic 1526d1b4259fSMaxime Coquelin /* 1527d1b4259fSMaxime Coquelin * Virtio capabilities present without 1528d1b4259fSMaxime Coquelin * VIRTIO_F_VERSION_1 confuses guests 1529d1b4259fSMaxime Coquelin */ 153066d1c4c1SMaxime Coquelin if (!proxy->ignore_backend_features && 153166d1c4c1SMaxime Coquelin !virtio_has_feature(vdev->host_features, VIRTIO_F_VERSION_1)) { 1532d1b4259fSMaxime Coquelin virtio_pci_disable_modern(proxy); 1533d1b4259fSMaxime Coquelin 1534d1b4259fSMaxime Coquelin if (!legacy) { 1535d1b4259fSMaxime Coquelin error_setg(errp, "Device doesn't support modern mode, and legacy" 1536d1b4259fSMaxime Coquelin " mode is disabled"); 1537d1b4259fSMaxime Coquelin error_append_hint(errp, "Set disable-legacy to off\n"); 1538d1b4259fSMaxime Coquelin 1539d1b4259fSMaxime Coquelin return; 1540d1b4259fSMaxime Coquelin } 1541d1b4259fSMaxime Coquelin } 1542d1b4259fSMaxime Coquelin 1543d1b4259fSMaxime Coquelin modern = virtio_pci_modern(proxy); 1544d1b4259fSMaxime Coquelin 1545085bccb7SKONRAD Frederic config = proxy->pci_dev.config; 1546085bccb7SKONRAD Frederic if (proxy->class_code) { 1547085bccb7SKONRAD Frederic pci_config_set_class(config, proxy->class_code); 1548085bccb7SKONRAD Frederic } 1549e266d421SGerd Hoffmann 1550e266d421SGerd Hoffmann if (legacy) { 15518607f5c3SJason Wang if (virtio_host_has_feature(vdev, VIRTIO_F_IOMMU_PLATFORM)) { 15528607f5c3SJason Wang error_setg(errp, "VIRTIO_F_IOMMU_PLATFORM was supported by" 15532080a29fSGreg Kurz " neither legacy nor transitional device"); 15548607f5c3SJason Wang return ; 15558607f5c3SJason Wang } 1556f2bc54deSLadi Prosek /* 1557f2bc54deSLadi Prosek * Legacy and transitional devices use specific subsystem IDs. 1558f2bc54deSLadi Prosek * Note that the subsystem vendor ID (config + PCI_SUBSYSTEM_VENDOR_ID) 1559f2bc54deSLadi Prosek * is set to PCI_SUBVENDOR_ID_REDHAT_QUMRANET by default. 1560f2bc54deSLadi Prosek */ 1561085bccb7SKONRAD Frederic pci_set_word(config + PCI_SUBSYSTEM_ID, virtio_bus_get_vdev_id(bus)); 1562e266d421SGerd Hoffmann } else { 1563e266d421SGerd Hoffmann /* pure virtio-1.0 */ 1564e266d421SGerd Hoffmann pci_set_word(config + PCI_VENDOR_ID, 1565e266d421SGerd Hoffmann PCI_VENDOR_ID_REDHAT_QUMRANET); 1566e266d421SGerd Hoffmann pci_set_word(config + PCI_DEVICE_ID, 1567e266d421SGerd Hoffmann 0x1040 + virtio_bus_get_vdev_id(bus)); 1568e266d421SGerd Hoffmann pci_config_set_revision(config, 1); 1569e266d421SGerd Hoffmann } 1570085bccb7SKONRAD Frederic config[PCI_INTERRUPT_PIN] = 1; 1571085bccb7SKONRAD Frederic 1572dfb8e184SMichael S. Tsirkin 1573e266d421SGerd Hoffmann if (modern) { 1574cc52ea90SGerd Hoffmann struct virtio_pci_cap cap = { 1575cc52ea90SGerd Hoffmann .cap_len = sizeof cap, 1576dfb8e184SMichael S. Tsirkin }; 1577dfb8e184SMichael S. Tsirkin struct virtio_pci_notify_cap notify = { 1578dfb8e184SMichael S. Tsirkin .cap.cap_len = sizeof notify, 1579dfb8e184SMichael S. Tsirkin .notify_off_multiplier = 1580d9997d89SMarcel Apfelbaum cpu_to_le32(virtio_pci_queue_mem_mult(proxy)), 1581dfb8e184SMichael S. Tsirkin }; 1582ada434cdSMichael S. Tsirkin struct virtio_pci_cfg_cap cfg = { 1583ada434cdSMichael S. Tsirkin .cap.cap_len = sizeof cfg, 1584ada434cdSMichael S. Tsirkin .cap.cfg_type = VIRTIO_PCI_CAP_PCI_CFG, 1585ada434cdSMichael S. Tsirkin }; 15869824d2a3SJason Wang struct virtio_pci_notify_cap notify_pio = { 15879824d2a3SJason Wang .cap.cap_len = sizeof notify, 15889824d2a3SJason Wang .notify_off_multiplier = cpu_to_le32(0x0), 15899824d2a3SJason Wang }; 1590dfb8e184SMichael S. Tsirkin 15919824d2a3SJason Wang struct virtio_pci_cfg_cap *cfg_mask; 1592dfb8e184SMichael S. Tsirkin 15931141ce21SGerd Hoffmann virtio_pci_modern_regions_init(proxy); 15949824d2a3SJason Wang 15959824d2a3SJason Wang virtio_pci_modern_mem_region_map(proxy, &proxy->common, &cap); 15969824d2a3SJason Wang virtio_pci_modern_mem_region_map(proxy, &proxy->isr, &cap); 15979824d2a3SJason Wang virtio_pci_modern_mem_region_map(proxy, &proxy->device, &cap); 15989824d2a3SJason Wang virtio_pci_modern_mem_region_map(proxy, &proxy->notify, ¬ify.cap); 15999824d2a3SJason Wang 16009824d2a3SJason Wang if (modern_pio) { 16019824d2a3SJason Wang memory_region_init(&proxy->io_bar, OBJECT(proxy), 16029824d2a3SJason Wang "virtio-pci-io", 0x4); 16039824d2a3SJason Wang 16047a25126dSChen Fan pci_register_bar(&proxy->pci_dev, proxy->modern_io_bar_idx, 16059824d2a3SJason Wang PCI_BASE_ADDRESS_SPACE_IO, &proxy->io_bar); 16069824d2a3SJason Wang 16079824d2a3SJason Wang virtio_pci_modern_io_region_map(proxy, &proxy->notify_pio, 16089824d2a3SJason Wang ¬ify_pio.cap); 16099824d2a3SJason Wang } 1610ada434cdSMichael S. Tsirkin 16117a25126dSChen Fan pci_register_bar(&proxy->pci_dev, proxy->modern_mem_bar_idx, 16124e93a68eSGerd Hoffmann PCI_BASE_ADDRESS_SPACE_MEMORY | 16134e93a68eSGerd Hoffmann PCI_BASE_ADDRESS_MEM_PREFETCH | 16144e93a68eSGerd Hoffmann PCI_BASE_ADDRESS_MEM_TYPE_64, 1615dfb8e184SMichael S. Tsirkin &proxy->modern_bar); 1616ada434cdSMichael S. Tsirkin 1617ada434cdSMichael S. Tsirkin proxy->config_cap = virtio_pci_add_mem_cap(proxy, &cfg.cap); 1618ada434cdSMichael S. Tsirkin cfg_mask = (void *)(proxy->pci_dev.wmask + proxy->config_cap); 1619ada434cdSMichael S. Tsirkin pci_set_byte(&cfg_mask->cap.bar, ~0x0); 1620ada434cdSMichael S. Tsirkin pci_set_long((uint8_t *)&cfg_mask->cap.offset, ~0x0); 1621ada434cdSMichael S. Tsirkin pci_set_long((uint8_t *)&cfg_mask->cap.length, ~0x0); 1622ada434cdSMichael S. Tsirkin pci_set_long(cfg_mask->pci_cfg_data, ~0x0); 1623dfb8e184SMichael S. Tsirkin } 1624dfb8e184SMichael S. Tsirkin 16250d583647SRichard Henderson if (proxy->nvectors) { 16260d583647SRichard Henderson int err = msix_init_exclusive_bar(&proxy->pci_dev, proxy->nvectors, 1627ee640c62SCao jin proxy->msix_bar_idx, NULL); 16280d583647SRichard Henderson if (err) { 1629ee640c62SCao jin /* Notice when a system that supports MSIx can't initialize it */ 16300d583647SRichard Henderson if (err != -ENOTSUP) { 16310765691eSMarkus Armbruster warn_report("unable to init msix vectors to %" PRIu32, 1632c7ff5482SFam Zheng proxy->nvectors); 16330d583647SRichard Henderson } 1634085bccb7SKONRAD Frederic proxy->nvectors = 0; 1635085bccb7SKONRAD Frederic } 16360d583647SRichard Henderson } 1637085bccb7SKONRAD Frederic 1638085bccb7SKONRAD Frederic proxy->pci_dev.config_write = virtio_write_config; 1639ada434cdSMichael S. Tsirkin proxy->pci_dev.config_read = virtio_read_config; 1640085bccb7SKONRAD Frederic 1641e266d421SGerd Hoffmann if (legacy) { 1642085bccb7SKONRAD Frederic size = VIRTIO_PCI_REGION_SIZE(&proxy->pci_dev) 1643085bccb7SKONRAD Frederic + virtio_bus_get_vdev_config_len(bus); 16441d0148feSPeter Maydell size = pow2ceil(size); 1645085bccb7SKONRAD Frederic 1646e266d421SGerd Hoffmann memory_region_init_io(&proxy->bar, OBJECT(proxy), 1647e266d421SGerd Hoffmann &virtio_pci_config_ops, 164822fc860bSPaolo Bonzini proxy, "virtio-pci", size); 1649dfb8e184SMichael S. Tsirkin 16507a25126dSChen Fan pci_register_bar(&proxy->pci_dev, proxy->legacy_io_bar_idx, 165123c5e397SGerd Hoffmann PCI_BASE_ADDRESS_SPACE_IO, &proxy->bar); 1652e266d421SGerd Hoffmann } 1653085bccb7SKONRAD Frederic } 1654085bccb7SKONRAD Frederic 165506a13073SPaolo Bonzini static void virtio_pci_device_unplugged(DeviceState *d) 165606a13073SPaolo Bonzini { 165706a13073SPaolo Bonzini VirtIOPCIProxy *proxy = VIRTIO_PCI(d); 16589a4c0e22SMarcel Apfelbaum bool modern = virtio_pci_modern(proxy); 16599824d2a3SJason Wang bool modern_pio = proxy->flags & VIRTIO_PCI_FLAG_MODERN_PIO_NOTIFY; 166006a13073SPaolo Bonzini 166106a13073SPaolo Bonzini virtio_pci_stop_ioeventfd(proxy); 166227462695SMichael S. Tsirkin 166327462695SMichael S. Tsirkin if (modern) { 16649824d2a3SJason Wang virtio_pci_modern_mem_region_unmap(proxy, &proxy->common); 16659824d2a3SJason Wang virtio_pci_modern_mem_region_unmap(proxy, &proxy->isr); 16669824d2a3SJason Wang virtio_pci_modern_mem_region_unmap(proxy, &proxy->device); 16679824d2a3SJason Wang virtio_pci_modern_mem_region_unmap(proxy, &proxy->notify); 16689824d2a3SJason Wang if (modern_pio) { 16699824d2a3SJason Wang virtio_pci_modern_io_region_unmap(proxy, &proxy->notify_pio); 16709824d2a3SJason Wang } 167127462695SMichael S. Tsirkin } 167206a13073SPaolo Bonzini } 167306a13073SPaolo Bonzini 1674fc079951SMarkus Armbruster static void virtio_pci_realize(PCIDevice *pci_dev, Error **errp) 1675085bccb7SKONRAD Frederic { 1676b6ce27a5SGerd Hoffmann VirtIOPCIProxy *proxy = VIRTIO_PCI(pci_dev); 1677085bccb7SKONRAD Frederic VirtioPCIClass *k = VIRTIO_PCI_GET_CLASS(pci_dev); 1678fd56e061SDavid Gibson bool pcie_port = pci_bus_is_express(pci_get_bus(pci_dev)) && 1679fd56e061SDavid Gibson !pci_bus_is_root(pci_get_bus(pci_dev)); 1680fc079951SMarkus Armbruster 1681c324fd0aSStefan Hajnoczi if (kvm_enabled() && !kvm_has_many_ioeventfds()) { 1682ca2b413cSPaolo Bonzini proxy->flags &= ~VIRTIO_PCI_FLAG_USE_IOEVENTFD; 1683ca2b413cSPaolo Bonzini } 1684ca2b413cSPaolo Bonzini 1685b6ce27a5SGerd Hoffmann /* 1686b6ce27a5SGerd Hoffmann * virtio pci bar layout used by default. 1687b6ce27a5SGerd Hoffmann * subclasses can re-arrange things if needed. 1688b6ce27a5SGerd Hoffmann * 1689b6ce27a5SGerd Hoffmann * region 0 -- virtio legacy io bar 1690b6ce27a5SGerd Hoffmann * region 1 -- msi-x bar 1691b6ce27a5SGerd Hoffmann * region 4+5 -- virtio modern memory (64bit) bar 1692b6ce27a5SGerd Hoffmann * 1693b6ce27a5SGerd Hoffmann */ 16947a25126dSChen Fan proxy->legacy_io_bar_idx = 0; 16957a25126dSChen Fan proxy->msix_bar_idx = 1; 16967a25126dSChen Fan proxy->modern_io_bar_idx = 2; 16977a25126dSChen Fan proxy->modern_mem_bar_idx = 4; 1698b6ce27a5SGerd Hoffmann 1699b6ce27a5SGerd Hoffmann proxy->common.offset = 0x0; 1700b6ce27a5SGerd Hoffmann proxy->common.size = 0x1000; 1701b6ce27a5SGerd Hoffmann proxy->common.type = VIRTIO_PCI_CAP_COMMON_CFG; 1702b6ce27a5SGerd Hoffmann 1703b6ce27a5SGerd Hoffmann proxy->isr.offset = 0x1000; 1704b6ce27a5SGerd Hoffmann proxy->isr.size = 0x1000; 1705b6ce27a5SGerd Hoffmann proxy->isr.type = VIRTIO_PCI_CAP_ISR_CFG; 1706b6ce27a5SGerd Hoffmann 1707b6ce27a5SGerd Hoffmann proxy->device.offset = 0x2000; 1708b6ce27a5SGerd Hoffmann proxy->device.size = 0x1000; 1709b6ce27a5SGerd Hoffmann proxy->device.type = VIRTIO_PCI_CAP_DEVICE_CFG; 1710b6ce27a5SGerd Hoffmann 1711b6ce27a5SGerd Hoffmann proxy->notify.offset = 0x3000; 1712d9997d89SMarcel Apfelbaum proxy->notify.size = virtio_pci_queue_mem_mult(proxy) * VIRTIO_QUEUE_MAX; 1713b6ce27a5SGerd Hoffmann proxy->notify.type = VIRTIO_PCI_CAP_NOTIFY_CFG; 1714b6ce27a5SGerd Hoffmann 17159824d2a3SJason Wang proxy->notify_pio.offset = 0x0; 17169824d2a3SJason Wang proxy->notify_pio.size = 0x4; 17179824d2a3SJason Wang proxy->notify_pio.type = VIRTIO_PCI_CAP_NOTIFY_CFG; 17189824d2a3SJason Wang 1719b6ce27a5SGerd Hoffmann /* subclasses can enforce modern, so do this unconditionally */ 1720b6ce27a5SGerd Hoffmann memory_region_init(&proxy->modern_bar, OBJECT(proxy), "virtio-pci", 1721d9997d89SMarcel Apfelbaum /* PCI BAR regions must be powers of 2 */ 1722d9997d89SMarcel Apfelbaum pow2ceil(proxy->notify.offset + proxy->notify.size)); 1723b6ce27a5SGerd Hoffmann 1724*f2784eedSDaniel P. Berrangé if ((proxy->disable_legacy == ON_OFF_AUTO_ON) || 1725*f2784eedSDaniel P. Berrangé ((proxy->disable_legacy == ON_OFF_AUTO_AUTO) && pcie_port)) { 1726*f2784eedSDaniel P. Berrangé if (proxy->disable_modern) { 1727*f2784eedSDaniel P. Berrangé error_setg(errp, "device cannot work as neither modern nor " 1728*f2784eedSDaniel P. Berrangé "legacy mode is enabled"); 1729*f2784eedSDaniel P. Berrangé error_append_hint(errp, "Set either disable-modern or " 1730*f2784eedSDaniel P. Berrangé "disable-legacy to off\n"); 17313eff3769SGreg Kurz return; 17323eff3769SGreg Kurz } 1733*f2784eedSDaniel P. Berrangé proxy->mode = VIRTIO_PCI_MODE_MODERN; 1734*f2784eedSDaniel P. Berrangé } else { 1735*f2784eedSDaniel P. Berrangé if (proxy->disable_modern) { 1736*f2784eedSDaniel P. Berrangé proxy->mode = VIRTIO_PCI_MODE_LEGACY; 1737*f2784eedSDaniel P. Berrangé } else { 1738*f2784eedSDaniel P. Berrangé proxy->mode = VIRTIO_PCI_MODE_TRANSITIONAL; 1739*f2784eedSDaniel P. Berrangé } 1740*f2784eedSDaniel P. Berrangé } 17413eff3769SGreg Kurz 17429a4c0e22SMarcel Apfelbaum if (pcie_port && pci_is_express(pci_dev)) { 17431811e64cSMarcel Apfelbaum int pos; 17441811e64cSMarcel Apfelbaum 17451811e64cSMarcel Apfelbaum pos = pcie_endpoint_cap_init(pci_dev, 0); 17461811e64cSMarcel Apfelbaum assert(pos > 0); 17471811e64cSMarcel Apfelbaum 17489a7c2a59SMao Zhongyi pos = pci_add_capability(pci_dev, PCI_CAP_ID_PM, 0, 17499a7c2a59SMao Zhongyi PCI_PM_SIZEOF, errp); 17509a7c2a59SMao Zhongyi if (pos < 0) { 17519a7c2a59SMao Zhongyi return; 17529a7c2a59SMao Zhongyi } 17539a7c2a59SMao Zhongyi 175427ce0f3aSMarcel Apfelbaum pci_dev->exp.pm_cap = pos; 17551811e64cSMarcel Apfelbaum 17561811e64cSMarcel Apfelbaum /* 17571811e64cSMarcel Apfelbaum * Indicates that this function complies with revision 1.2 of the 17581811e64cSMarcel Apfelbaum * PCI Power Management Interface Specification. 17591811e64cSMarcel Apfelbaum */ 17601811e64cSMarcel Apfelbaum pci_set_word(pci_dev->config + pos + PCI_PM_PMC, 0x3); 1761615c4ed2SJason Wang 1762c2cabb34SMarcel Apfelbaum if (proxy->flags & VIRTIO_PCI_FLAG_INIT_DEVERR) { 1763c2cabb34SMarcel Apfelbaum /* Init error enabling flags */ 1764c2cabb34SMarcel Apfelbaum pcie_cap_deverr_init(pci_dev); 1765c2cabb34SMarcel Apfelbaum } 1766c2cabb34SMarcel Apfelbaum 1767d584f1b9SMarcel Apfelbaum if (proxy->flags & VIRTIO_PCI_FLAG_INIT_LNKCTL) { 1768d584f1b9SMarcel Apfelbaum /* Init Link Control Register */ 1769d584f1b9SMarcel Apfelbaum pcie_cap_lnkctl_init(pci_dev); 1770d584f1b9SMarcel Apfelbaum } 1771d584f1b9SMarcel Apfelbaum 177227ce0f3aSMarcel Apfelbaum if (proxy->flags & VIRTIO_PCI_FLAG_INIT_PM) { 177327ce0f3aSMarcel Apfelbaum /* Init Power Management Control Register */ 177427ce0f3aSMarcel Apfelbaum pci_set_word(pci_dev->wmask + pos + PCI_PM_CTRL, 177527ce0f3aSMarcel Apfelbaum PCI_PM_CTRL_STATE_MASK); 177627ce0f3aSMarcel Apfelbaum } 177727ce0f3aSMarcel Apfelbaum 1778615c4ed2SJason Wang if (proxy->flags & VIRTIO_PCI_FLAG_ATS) { 1779615c4ed2SJason Wang pcie_ats_init(pci_dev, 256); 1780615c4ed2SJason Wang } 1781615c4ed2SJason Wang 17820560b0e9SShmulik Ladkani } else { 17830560b0e9SShmulik Ladkani /* 17840560b0e9SShmulik Ladkani * make future invocations of pci_is_express() return false 17850560b0e9SShmulik Ladkani * and pci_config_size() return PCI_CONFIG_SPACE_SIZE. 17860560b0e9SShmulik Ladkani */ 17870560b0e9SShmulik Ladkani pci_dev->cap_present &= ~QEMU_PCI_CAP_EXPRESS; 17881811e64cSMarcel Apfelbaum } 17891811e64cSMarcel Apfelbaum 1790b6ce27a5SGerd Hoffmann virtio_pci_bus_new(&proxy->bus, sizeof(proxy->bus), proxy); 1791fc079951SMarkus Armbruster if (k->realize) { 1792b6ce27a5SGerd Hoffmann k->realize(proxy, errp); 1793085bccb7SKONRAD Frederic } 1794085bccb7SKONRAD Frederic } 1795085bccb7SKONRAD Frederic 1796085bccb7SKONRAD Frederic static void virtio_pci_exit(PCIDevice *pci_dev) 1797085bccb7SKONRAD Frederic { 17988b81bb3bSPaolo Bonzini msix_uninit_exclusive_bar(pci_dev); 1799085bccb7SKONRAD Frederic } 1800085bccb7SKONRAD Frederic 180159ccd20aSKONRAD Frederic static void virtio_pci_reset(DeviceState *qdev) 1802085bccb7SKONRAD Frederic { 1803085bccb7SKONRAD Frederic VirtIOPCIProxy *proxy = VIRTIO_PCI(qdev); 1804085bccb7SKONRAD Frederic VirtioBusState *bus = VIRTIO_BUS(&proxy->bus); 1805c2cabb34SMarcel Apfelbaum PCIDevice *dev = PCI_DEVICE(qdev); 1806393f04d3SJason Wang int i; 1807393f04d3SJason Wang 1808085bccb7SKONRAD Frederic virtio_pci_stop_ioeventfd(proxy); 1809085bccb7SKONRAD Frederic virtio_bus_reset(bus); 1810085bccb7SKONRAD Frederic msix_unuse_all_vectors(&proxy->pci_dev); 1811393f04d3SJason Wang 1812393f04d3SJason Wang for (i = 0; i < VIRTIO_QUEUE_MAX; i++) { 1813393f04d3SJason Wang proxy->vqs[i].enabled = 0; 181460a8d802SJason Wang proxy->vqs[i].num = 0; 181560a8d802SJason Wang proxy->vqs[i].desc[0] = proxy->vqs[i].desc[1] = 0; 181660a8d802SJason Wang proxy->vqs[i].avail[0] = proxy->vqs[i].avail[1] = 0; 181760a8d802SJason Wang proxy->vqs[i].used[0] = proxy->vqs[i].used[1] = 0; 1818393f04d3SJason Wang } 1819c2cabb34SMarcel Apfelbaum 1820c2cabb34SMarcel Apfelbaum if (pci_is_express(dev)) { 1821c2cabb34SMarcel Apfelbaum pcie_cap_deverr_reset(dev); 1822d584f1b9SMarcel Apfelbaum pcie_cap_lnkctl_reset(dev); 182327ce0f3aSMarcel Apfelbaum 182427ce0f3aSMarcel Apfelbaum pci_set_word(dev->config + dev->exp.pm_cap + PCI_PM_CTRL, 0); 1825c2cabb34SMarcel Apfelbaum } 1826085bccb7SKONRAD Frederic } 1827085bccb7SKONRAD Frederic 182885d1277eSMing Lei static Property virtio_pci_properties[] = { 182968a27b20SMichael S. Tsirkin DEFINE_PROP_BIT("virtio-pci-bus-master-bug-migration", VirtIOPCIProxy, flags, 183068a27b20SMichael S. Tsirkin VIRTIO_PCI_FLAG_BUS_MASTER_BUG_MIGRATION_BIT, false), 1831a6df8adfSJason Wang DEFINE_PROP_BIT("migrate-extra", VirtIOPCIProxy, flags, 1832a6df8adfSJason Wang VIRTIO_PCI_FLAG_MIGRATE_EXTRA_BIT, true), 18339824d2a3SJason Wang DEFINE_PROP_BIT("modern-pio-notify", VirtIOPCIProxy, flags, 18349824d2a3SJason Wang VIRTIO_PCI_FLAG_MODERN_PIO_NOTIFY_BIT, false), 18351811e64cSMarcel Apfelbaum DEFINE_PROP_BIT("x-disable-pcie", VirtIOPCIProxy, flags, 18361811e64cSMarcel Apfelbaum VIRTIO_PCI_FLAG_DISABLE_PCIE_BIT, false), 1837d9997d89SMarcel Apfelbaum DEFINE_PROP_BIT("page-per-vq", VirtIOPCIProxy, flags, 1838d9997d89SMarcel Apfelbaum VIRTIO_PCI_FLAG_PAGE_PER_VQ_BIT, false), 183966d1c4c1SMaxime Coquelin DEFINE_PROP_BOOL("x-ignore-backend-features", VirtIOPCIProxy, 184066d1c4c1SMaxime Coquelin ignore_backend_features, false), 1841615c4ed2SJason Wang DEFINE_PROP_BIT("ats", VirtIOPCIProxy, flags, 1842615c4ed2SJason Wang VIRTIO_PCI_FLAG_ATS_BIT, false), 1843c2cabb34SMarcel Apfelbaum DEFINE_PROP_BIT("x-pcie-deverr-init", VirtIOPCIProxy, flags, 1844c2cabb34SMarcel Apfelbaum VIRTIO_PCI_FLAG_INIT_DEVERR_BIT, true), 1845d584f1b9SMarcel Apfelbaum DEFINE_PROP_BIT("x-pcie-lnkctl-init", VirtIOPCIProxy, flags, 1846d584f1b9SMarcel Apfelbaum VIRTIO_PCI_FLAG_INIT_LNKCTL_BIT, true), 184727ce0f3aSMarcel Apfelbaum DEFINE_PROP_BIT("x-pcie-pm-init", VirtIOPCIProxy, flags, 184827ce0f3aSMarcel Apfelbaum VIRTIO_PCI_FLAG_INIT_PM_BIT, true), 184985d1277eSMing Lei DEFINE_PROP_END_OF_LIST(), 185085d1277eSMing Lei }; 185185d1277eSMing Lei 18520560b0e9SShmulik Ladkani static void virtio_pci_dc_realize(DeviceState *qdev, Error **errp) 18530560b0e9SShmulik Ladkani { 18540560b0e9SShmulik Ladkani VirtioPCIClass *vpciklass = VIRTIO_PCI_GET_CLASS(qdev); 18550560b0e9SShmulik Ladkani VirtIOPCIProxy *proxy = VIRTIO_PCI(qdev); 18560560b0e9SShmulik Ladkani PCIDevice *pci_dev = &proxy->pci_dev; 18570560b0e9SShmulik Ladkani 18580560b0e9SShmulik Ladkani if (!(proxy->flags & VIRTIO_PCI_FLAG_DISABLE_PCIE) && 18599a4c0e22SMarcel Apfelbaum virtio_pci_modern(proxy)) { 18600560b0e9SShmulik Ladkani pci_dev->cap_present |= QEMU_PCI_CAP_EXPRESS; 18610560b0e9SShmulik Ladkani } 18620560b0e9SShmulik Ladkani 18630560b0e9SShmulik Ladkani vpciklass->parent_dc_realize(qdev, errp); 18640560b0e9SShmulik Ladkani } 18650560b0e9SShmulik Ladkani 1866085bccb7SKONRAD Frederic static void virtio_pci_class_init(ObjectClass *klass, void *data) 1867085bccb7SKONRAD Frederic { 1868085bccb7SKONRAD Frederic DeviceClass *dc = DEVICE_CLASS(klass); 1869085bccb7SKONRAD Frederic PCIDeviceClass *k = PCI_DEVICE_CLASS(klass); 18700560b0e9SShmulik Ladkani VirtioPCIClass *vpciklass = VIRTIO_PCI_CLASS(klass); 1871085bccb7SKONRAD Frederic 187285d1277eSMing Lei dc->props = virtio_pci_properties; 1873fc079951SMarkus Armbruster k->realize = virtio_pci_realize; 1874085bccb7SKONRAD Frederic k->exit = virtio_pci_exit; 1875085bccb7SKONRAD Frederic k->vendor_id = PCI_VENDOR_ID_REDHAT_QUMRANET; 1876085bccb7SKONRAD Frederic k->revision = VIRTIO_PCI_ABI_VERSION; 1877085bccb7SKONRAD Frederic k->class_id = PCI_CLASS_OTHERS; 1878bf853881SPhilippe Mathieu-Daudé device_class_set_parent_realize(dc, virtio_pci_dc_realize, 1879bf853881SPhilippe Mathieu-Daudé &vpciklass->parent_dc_realize); 188059ccd20aSKONRAD Frederic dc->reset = virtio_pci_reset; 1881085bccb7SKONRAD Frederic } 1882085bccb7SKONRAD Frederic 1883085bccb7SKONRAD Frederic static const TypeInfo virtio_pci_info = { 1884085bccb7SKONRAD Frederic .name = TYPE_VIRTIO_PCI, 1885085bccb7SKONRAD Frederic .parent = TYPE_PCI_DEVICE, 1886085bccb7SKONRAD Frederic .instance_size = sizeof(VirtIOPCIProxy), 1887085bccb7SKONRAD Frederic .class_init = virtio_pci_class_init, 1888085bccb7SKONRAD Frederic .class_size = sizeof(VirtioPCIClass), 1889085bccb7SKONRAD Frederic .abstract = true, 1890a4ee4c8bSEduardo Habkost }; 1891a4ee4c8bSEduardo Habkost 1892a4ee4c8bSEduardo Habkost static Property virtio_pci_generic_properties[] = { 1893a4ee4c8bSEduardo Habkost DEFINE_PROP_ON_OFF_AUTO("disable-legacy", VirtIOPCIProxy, disable_legacy, 1894a4ee4c8bSEduardo Habkost ON_OFF_AUTO_AUTO), 1895a4ee4c8bSEduardo Habkost DEFINE_PROP_BOOL("disable-modern", VirtIOPCIProxy, disable_modern, false), 1896a4ee4c8bSEduardo Habkost DEFINE_PROP_END_OF_LIST(), 1897a4ee4c8bSEduardo Habkost }; 1898a4ee4c8bSEduardo Habkost 1899a4ee4c8bSEduardo Habkost static void virtio_pci_base_class_init(ObjectClass *klass, void *data) 1900a4ee4c8bSEduardo Habkost { 1901a4ee4c8bSEduardo Habkost const VirtioPCIDeviceTypeInfo *t = data; 1902a4ee4c8bSEduardo Habkost if (t->class_init) { 1903a4ee4c8bSEduardo Habkost t->class_init(klass, NULL); 1904a4ee4c8bSEduardo Habkost } 1905a4ee4c8bSEduardo Habkost } 1906a4ee4c8bSEduardo Habkost 1907a4ee4c8bSEduardo Habkost static void virtio_pci_generic_class_init(ObjectClass *klass, void *data) 1908a4ee4c8bSEduardo Habkost { 1909a4ee4c8bSEduardo Habkost DeviceClass *dc = DEVICE_CLASS(klass); 1910a4ee4c8bSEduardo Habkost 1911a4ee4c8bSEduardo Habkost dc->props = virtio_pci_generic_properties; 1912a4ee4c8bSEduardo Habkost } 1913a4ee4c8bSEduardo Habkost 1914a4ee4c8bSEduardo Habkost /* Used when the generic type and the base type is the same */ 1915a4ee4c8bSEduardo Habkost static void virtio_pci_generic_base_class_init(ObjectClass *klass, void *data) 1916a4ee4c8bSEduardo Habkost { 1917a4ee4c8bSEduardo Habkost virtio_pci_base_class_init(klass, data); 1918a4ee4c8bSEduardo Habkost virtio_pci_generic_class_init(klass, NULL); 1919a4ee4c8bSEduardo Habkost } 1920a4ee4c8bSEduardo Habkost 1921a4ee4c8bSEduardo Habkost static void virtio_pci_transitional_instance_init(Object *obj) 1922a4ee4c8bSEduardo Habkost { 1923a4ee4c8bSEduardo Habkost VirtIOPCIProxy *proxy = VIRTIO_PCI(obj); 1924a4ee4c8bSEduardo Habkost 1925a4ee4c8bSEduardo Habkost proxy->disable_legacy = ON_OFF_AUTO_OFF; 1926a4ee4c8bSEduardo Habkost proxy->disable_modern = false; 1927a4ee4c8bSEduardo Habkost } 1928a4ee4c8bSEduardo Habkost 1929a4ee4c8bSEduardo Habkost static void virtio_pci_non_transitional_instance_init(Object *obj) 1930a4ee4c8bSEduardo Habkost { 1931a4ee4c8bSEduardo Habkost VirtIOPCIProxy *proxy = VIRTIO_PCI(obj); 1932a4ee4c8bSEduardo Habkost 1933a4ee4c8bSEduardo Habkost proxy->disable_legacy = ON_OFF_AUTO_ON; 1934a4ee4c8bSEduardo Habkost proxy->disable_modern = false; 1935a4ee4c8bSEduardo Habkost } 1936a4ee4c8bSEduardo Habkost 1937a4ee4c8bSEduardo Habkost void virtio_pci_types_register(const VirtioPCIDeviceTypeInfo *t) 1938a4ee4c8bSEduardo Habkost { 1939a4ee4c8bSEduardo Habkost TypeInfo base_type_info = { 1940a4ee4c8bSEduardo Habkost .name = t->base_name, 1941a4ee4c8bSEduardo Habkost .parent = t->parent ? t->parent : TYPE_VIRTIO_PCI, 1942a4ee4c8bSEduardo Habkost .instance_size = t->instance_size, 1943a4ee4c8bSEduardo Habkost .instance_init = t->instance_init, 19448ea90ee6SGerd Hoffmann .class_size = t->class_size, 1945a4ee4c8bSEduardo Habkost .class_init = virtio_pci_base_class_init, 1946a4ee4c8bSEduardo Habkost .class_data = (void *)t, 1947a4ee4c8bSEduardo Habkost .abstract = true, 1948a4ee4c8bSEduardo Habkost }; 1949a4ee4c8bSEduardo Habkost TypeInfo generic_type_info = { 1950a4ee4c8bSEduardo Habkost .name = t->generic_name, 1951a4ee4c8bSEduardo Habkost .parent = base_type_info.name, 1952a4ee4c8bSEduardo Habkost .class_init = virtio_pci_generic_class_init, 1953a5fa336fSEduardo Habkost .interfaces = (InterfaceInfo[]) { 1954a5fa336fSEduardo Habkost { INTERFACE_PCIE_DEVICE }, 1955a5fa336fSEduardo Habkost { INTERFACE_CONVENTIONAL_PCI_DEVICE }, 1956a5fa336fSEduardo Habkost { } 1957a5fa336fSEduardo Habkost }, 1958085bccb7SKONRAD Frederic }; 1959085bccb7SKONRAD Frederic 1960a4ee4c8bSEduardo Habkost if (!base_type_info.name) { 1961a4ee4c8bSEduardo Habkost /* No base type -> register a single generic device type */ 1962a4ee4c8bSEduardo Habkost base_type_info.name = t->generic_name; 1963a4ee4c8bSEduardo Habkost base_type_info.class_init = virtio_pci_generic_base_class_init; 1964a4ee4c8bSEduardo Habkost base_type_info.interfaces = generic_type_info.interfaces; 1965a4ee4c8bSEduardo Habkost base_type_info.abstract = false; 1966a4ee4c8bSEduardo Habkost generic_type_info.name = NULL; 1967a4ee4c8bSEduardo Habkost assert(!t->non_transitional_name); 1968a4ee4c8bSEduardo Habkost assert(!t->transitional_name); 1969a4ee4c8bSEduardo Habkost } 1970a4ee4c8bSEduardo Habkost 1971a4ee4c8bSEduardo Habkost type_register(&base_type_info); 1972a4ee4c8bSEduardo Habkost if (generic_type_info.name) { 1973a4ee4c8bSEduardo Habkost type_register(&generic_type_info); 1974a4ee4c8bSEduardo Habkost } 1975a4ee4c8bSEduardo Habkost 1976a4ee4c8bSEduardo Habkost if (t->non_transitional_name) { 1977a4ee4c8bSEduardo Habkost const TypeInfo non_transitional_type_info = { 1978a4ee4c8bSEduardo Habkost .name = t->non_transitional_name, 1979a4ee4c8bSEduardo Habkost .parent = base_type_info.name, 1980a4ee4c8bSEduardo Habkost .instance_init = virtio_pci_non_transitional_instance_init, 1981a4ee4c8bSEduardo Habkost .interfaces = (InterfaceInfo[]) { 1982a4ee4c8bSEduardo Habkost { INTERFACE_PCIE_DEVICE }, 1983a4ee4c8bSEduardo Habkost { INTERFACE_CONVENTIONAL_PCI_DEVICE }, 1984a4ee4c8bSEduardo Habkost { } 1985a4ee4c8bSEduardo Habkost }, 1986a4ee4c8bSEduardo Habkost }; 1987a4ee4c8bSEduardo Habkost type_register(&non_transitional_type_info); 1988a4ee4c8bSEduardo Habkost } 1989a4ee4c8bSEduardo Habkost 1990a4ee4c8bSEduardo Habkost if (t->transitional_name) { 1991a4ee4c8bSEduardo Habkost const TypeInfo transitional_type_info = { 1992a4ee4c8bSEduardo Habkost .name = t->transitional_name, 1993a4ee4c8bSEduardo Habkost .parent = base_type_info.name, 1994a4ee4c8bSEduardo Habkost .instance_init = virtio_pci_transitional_instance_init, 1995a4ee4c8bSEduardo Habkost .interfaces = (InterfaceInfo[]) { 1996a4ee4c8bSEduardo Habkost /* 1997a4ee4c8bSEduardo Habkost * Transitional virtio devices work only as Conventional PCI 1998a4ee4c8bSEduardo Habkost * devices because they require PIO ports. 1999a4ee4c8bSEduardo Habkost */ 2000a4ee4c8bSEduardo Habkost { INTERFACE_CONVENTIONAL_PCI_DEVICE }, 2001a4ee4c8bSEduardo Habkost { } 2002a4ee4c8bSEduardo Habkost }, 2003a4ee4c8bSEduardo Habkost }; 2004a4ee4c8bSEduardo Habkost type_register(&transitional_type_info); 2005a4ee4c8bSEduardo Habkost } 2006a4ee4c8bSEduardo Habkost } 2007a4ee4c8bSEduardo Habkost 20080a2acf5eSKONRAD Frederic /* virtio-pci-bus */ 20090a2acf5eSKONRAD Frederic 2010ac7af112SAndreas Färber static void virtio_pci_bus_new(VirtioBusState *bus, size_t bus_size, 2011ac7af112SAndreas Färber VirtIOPCIProxy *dev) 20120a2acf5eSKONRAD Frederic { 20130a2acf5eSKONRAD Frederic DeviceState *qdev = DEVICE(dev); 2014f4dd69aaSKONRAD Frederic char virtio_bus_name[] = "virtio-bus"; 2015f4dd69aaSKONRAD Frederic 2016fb17dfe0SAndreas Färber qbus_create_inplace(bus, bus_size, TYPE_VIRTIO_PCI_BUS, qdev, 2017f4dd69aaSKONRAD Frederic virtio_bus_name); 20180a2acf5eSKONRAD Frederic } 20190a2acf5eSKONRAD Frederic 20200a2acf5eSKONRAD Frederic static void virtio_pci_bus_class_init(ObjectClass *klass, void *data) 20210a2acf5eSKONRAD Frederic { 20220a2acf5eSKONRAD Frederic BusClass *bus_class = BUS_CLASS(klass); 20230a2acf5eSKONRAD Frederic VirtioBusClass *k = VIRTIO_BUS_CLASS(klass); 20240a2acf5eSKONRAD Frederic bus_class->max_dev = 1; 20250a2acf5eSKONRAD Frederic k->notify = virtio_pci_notify; 20260a2acf5eSKONRAD Frederic k->save_config = virtio_pci_save_config; 20270a2acf5eSKONRAD Frederic k->load_config = virtio_pci_load_config; 20280a2acf5eSKONRAD Frederic k->save_queue = virtio_pci_save_queue; 20290a2acf5eSKONRAD Frederic k->load_queue = virtio_pci_load_queue; 2030a6df8adfSJason Wang k->save_extra_state = virtio_pci_save_extra_state; 2031a6df8adfSJason Wang k->load_extra_state = virtio_pci_load_extra_state; 2032a6df8adfSJason Wang k->has_extra_state = virtio_pci_has_extra_state; 20330a2acf5eSKONRAD Frederic k->query_guest_notifiers = virtio_pci_query_guest_notifiers; 20340a2acf5eSKONRAD Frederic k->set_guest_notifiers = virtio_pci_set_guest_notifiers; 20356f80e617STiwei Bie k->set_host_notifier_mr = virtio_pci_set_host_notifier_mr; 20360a2acf5eSKONRAD Frederic k->vmstate_change = virtio_pci_vmstate_change; 2037d1b4259fSMaxime Coquelin k->pre_plugged = virtio_pci_pre_plugged; 2038085bccb7SKONRAD Frederic k->device_plugged = virtio_pci_device_plugged; 203906a13073SPaolo Bonzini k->device_unplugged = virtio_pci_device_unplugged; 2040e0d686bfSJason Wang k->query_nvectors = virtio_pci_query_nvectors; 20418e93cef1SPaolo Bonzini k->ioeventfd_enabled = virtio_pci_ioeventfd_enabled; 20429f06e71aSCornelia Huck k->ioeventfd_assign = virtio_pci_ioeventfd_assign; 20438607f5c3SJason Wang k->get_dma_as = virtio_pci_get_dma_as; 20440a2acf5eSKONRAD Frederic } 20450a2acf5eSKONRAD Frederic 20460a2acf5eSKONRAD Frederic static const TypeInfo virtio_pci_bus_info = { 20470a2acf5eSKONRAD Frederic .name = TYPE_VIRTIO_PCI_BUS, 20480a2acf5eSKONRAD Frederic .parent = TYPE_VIRTIO_BUS, 20490a2acf5eSKONRAD Frederic .instance_size = sizeof(VirtioPCIBusState), 20500a2acf5eSKONRAD Frederic .class_init = virtio_pci_bus_class_init, 20510a2acf5eSKONRAD Frederic }; 20520a2acf5eSKONRAD Frederic 205383f7d43aSAndreas Färber static void virtio_pci_register_types(void) 205453c25ceaSPaul Brook { 2055a4ee4c8bSEduardo Habkost /* Base types: */ 20560a2acf5eSKONRAD Frederic type_register_static(&virtio_pci_bus_info); 2057085bccb7SKONRAD Frederic type_register_static(&virtio_pci_info); 205853c25ceaSPaul Brook } 205953c25ceaSPaul Brook 206083f7d43aSAndreas Färber type_init(virtio_pci_register_types) 2061271458d7SJuan Quintela 2062