136f5dc91SSasha Levin #include "kvm/virtio-pci.h" 236f5dc91SSasha Levin 336f5dc91SSasha Levin #include "kvm/ioport.h" 436f5dc91SSasha Levin #include "kvm/kvm.h" 54123ca55SMarc Zyngier #include "kvm/kvm-cpu.h" 636f5dc91SSasha Levin #include "kvm/virtio-pci-dev.h" 736f5dc91SSasha Levin #include "kvm/irq.h" 836f5dc91SSasha Levin #include "kvm/virtio.h" 91599d724SSasha Levin #include "kvm/ioeventfd.h" 102e7380dbSMarc Zyngier #include "kvm/util.h" 1136f5dc91SSasha Levin 1243c81c74SSasha Levin #include <sys/ioctl.h> 1336f5dc91SSasha Levin #include <linux/virtio_pci.h> 145a8e4f25SAlexandru Elisei #include <assert.h> 1536f5dc91SSasha Levin #include <string.h> 1636f5dc91SSasha Levin 17930876d5SJean-Philippe Brucker int virtio_pci__add_msix_route(struct virtio_pci *vpci, u32 vec) 18f44af23eSJean-Philippe Brucker { 19f44af23eSJean-Philippe Brucker int gsi; 20f44af23eSJean-Philippe Brucker struct msi_msg *msg; 21f44af23eSJean-Philippe Brucker 22f44af23eSJean-Philippe Brucker if (vec == VIRTIO_MSI_NO_VECTOR) 23f44af23eSJean-Philippe Brucker return -EINVAL; 24f44af23eSJean-Philippe Brucker 25f44af23eSJean-Philippe Brucker msg = &vpci->msix_table[vec].msg; 26f44af23eSJean-Philippe Brucker gsi = irq__add_msix_route(vpci->kvm, msg, vpci->dev_hdr.dev_num << 3); 27f44af23eSJean-Philippe Brucker /* 28f44af23eSJean-Philippe Brucker * We don't need IRQ routing if we can use 29f44af23eSJean-Philippe Brucker * MSI injection via the KVM_SIGNAL_MSI ioctl. 30f44af23eSJean-Philippe Brucker */ 31f44af23eSJean-Philippe Brucker if (gsi == -ENXIO && vpci->features & VIRTIO_PCI_F_SIGNAL_MSI) 32f44af23eSJean-Philippe Brucker return gsi; 33f44af23eSJean-Philippe Brucker 34f44af23eSJean-Philippe Brucker if (gsi < 0) 35f44af23eSJean-Philippe Brucker die("failed to configure MSIs"); 36f44af23eSJean-Philippe Brucker 37f44af23eSJean-Philippe Brucker return gsi; 38f44af23eSJean-Philippe Brucker } 39f44af23eSJean-Philippe Brucker 40c6590f78SJean-Philippe Brucker static void virtio_pci__del_msix_route(struct virtio_pci *vpci, u32 gsi) 41c6590f78SJean-Philippe Brucker { 42c6590f78SJean-Philippe Brucker struct msi_msg msg = { 0 }; 43c6590f78SJean-Philippe Brucker 44c6590f78SJean-Philippe Brucker irq__update_msix_route(vpci->kvm, gsi, &msg); 45c6590f78SJean-Philippe Brucker } 46c6590f78SJean-Philippe Brucker 471599d724SSasha Levin static void virtio_pci__ioevent_callback(struct kvm *kvm, void *param) 481599d724SSasha Levin { 491599d724SSasha Levin struct virtio_pci_ioevent_param *ioeventfd = param; 5002eca50cSAsias He struct virtio_pci *vpci = ioeventfd->vdev->virtio; 511599d724SSasha Levin 5202eca50cSAsias He ioeventfd->vdev->ops->notify_vq(kvm, vpci->dev, ioeventfd->vq); 531599d724SSasha Levin } 541599d724SSasha Levin 55930876d5SJean-Philippe Brucker int virtio_pci__init_ioeventfd(struct kvm *kvm, struct virtio_device *vdev, 56930876d5SJean-Philippe Brucker u32 vq) 571599d724SSasha Levin { 581599d724SSasha Levin struct ioevent ioevent; 5902eca50cSAsias He struct virtio_pci *vpci = vdev->virtio; 60e539f3e4SAlexandru Elisei u32 mmio_addr = virtio_pci__mmio_addr(vpci); 61e539f3e4SAlexandru Elisei u16 port_addr = virtio_pci__port_addr(vpci); 6221c9bc74SJean-Philippe Brucker off_t offset = vpci->doorbell_offset; 630e1882a4SJean-Philippe Brucker int r, flags = 0; 6473fd1368SJean-Philippe Brucker int pio_fd, mmio_fd; 651599d724SSasha Levin 661599d724SSasha Levin vpci->ioeventfds[vq] = (struct virtio_pci_ioevent_param) { 6702eca50cSAsias He .vdev = vdev, 681599d724SSasha Levin .vq = vq, 691599d724SSasha Levin }; 701599d724SSasha Levin 711599d724SSasha Levin ioevent = (struct ioevent) { 721599d724SSasha Levin .fn = virtio_pci__ioevent_callback, 731599d724SSasha Levin .fn_ptr = &vpci->ioeventfds[vq], 741599d724SSasha Levin .datamatch = vq, 751599d724SSasha Levin .fn_kvm = kvm, 761599d724SSasha Levin }; 771599d724SSasha Levin 78627d6874SAsias He /* 79a463650cSWill Deacon * Vhost will poll the eventfd in host kernel side, otherwise we 80a463650cSWill Deacon * need to poll in userspace. 81627d6874SAsias He */ 82a463650cSWill Deacon if (!vdev->use_vhost) 83a463650cSWill Deacon flags |= IOEVENTFD_FLAG_USER_POLL; 84a463650cSWill Deacon 85a463650cSWill Deacon /* ioport */ 8621c9bc74SJean-Philippe Brucker ioevent.io_addr = port_addr + offset; 87a463650cSWill Deacon ioevent.io_len = sizeof(u16); 8873fd1368SJean-Philippe Brucker ioevent.fd = pio_fd = eventfd(0, 0); 8971ca0facSAndre Przywara r = ioeventfd__add_event(&ioevent, flags | IOEVENTFD_FLAG_PIO); 90ea6eeb1cSSasha Levin if (r) 91ea6eeb1cSSasha Levin return r; 921599d724SSasha Levin 93a463650cSWill Deacon /* mmio */ 9421c9bc74SJean-Philippe Brucker ioevent.io_addr = mmio_addr + offset; 95fe50bacbSAndreas Herrmann ioevent.io_len = sizeof(u16); 9673fd1368SJean-Philippe Brucker ioevent.fd = mmio_fd = eventfd(0, 0); 97a463650cSWill Deacon r = ioeventfd__add_event(&ioevent, flags); 98a463650cSWill Deacon if (r) 99a463650cSWill Deacon goto free_ioport_evt; 100263b80e8SSasha Levin 101a463650cSWill Deacon if (vdev->ops->notify_vq_eventfd) 10273fd1368SJean-Philippe Brucker vdev->ops->notify_vq_eventfd(kvm, vpci->dev, vq, 10373fd1368SJean-Philippe Brucker vdev->legacy ? pio_fd : mmio_fd); 1041599d724SSasha Levin return 0; 105a463650cSWill Deacon 106a463650cSWill Deacon free_ioport_evt: 10721c9bc74SJean-Philippe Brucker ioeventfd__del_event(port_addr + offset, vq); 108a463650cSWill Deacon return r; 1091599d724SSasha Levin } 1101599d724SSasha Levin 111930876d5SJean-Philippe Brucker int virtio_pci_init_vq(struct kvm *kvm, struct virtio_device *vdev, int vq) 112d0607293SJean-Philippe Brucker { 113d0607293SJean-Philippe Brucker int ret; 114d0607293SJean-Philippe Brucker struct virtio_pci *vpci = vdev->virtio; 115d0607293SJean-Philippe Brucker 116d0607293SJean-Philippe Brucker ret = virtio_pci__init_ioeventfd(kvm, vdev, vq); 117d0607293SJean-Philippe Brucker if (ret) { 118d0607293SJean-Philippe Brucker pr_err("couldn't add ioeventfd for vq %d: %d", vq, ret); 119d0607293SJean-Philippe Brucker return ret; 120d0607293SJean-Philippe Brucker } 121d0607293SJean-Philippe Brucker return vdev->ops->init_vq(kvm, vpci->dev, vq); 122d0607293SJean-Philippe Brucker } 123d0607293SJean-Philippe Brucker 124930876d5SJean-Philippe Brucker void virtio_pci_exit_vq(struct kvm *kvm, struct virtio_device *vdev, int vq) 125ad346c2eSJean-Philippe Brucker { 126ad346c2eSJean-Philippe Brucker struct virtio_pci *vpci = vdev->virtio; 127e539f3e4SAlexandru Elisei u32 mmio_addr = virtio_pci__mmio_addr(vpci); 128e539f3e4SAlexandru Elisei u16 port_addr = virtio_pci__port_addr(vpci); 12921c9bc74SJean-Philippe Brucker off_t offset = vpci->doorbell_offset; 130ad346c2eSJean-Philippe Brucker 131c6590f78SJean-Philippe Brucker virtio_pci__del_msix_route(vpci, vpci->gsis[vq]); 132c6590f78SJean-Philippe Brucker vpci->gsis[vq] = 0; 133c6590f78SJean-Philippe Brucker vpci->vq_vector[vq] = VIRTIO_MSI_NO_VECTOR; 13421c9bc74SJean-Philippe Brucker ioeventfd__del_event(mmio_addr + offset, vq); 13521c9bc74SJean-Philippe Brucker ioeventfd__del_event(port_addr + offset, vq); 136ad346c2eSJean-Philippe Brucker virtio_exit_vq(kvm, vdev, vpci->dev, vq); 137ad346c2eSJean-Philippe Brucker } 138ad346c2eSJean-Philippe Brucker 1396518065aSAndre Przywara static void update_msix_map(struct virtio_pci *vpci, 1406518065aSAndre Przywara struct msix_table *msix_entry, u32 vecnum) 1416518065aSAndre Przywara { 1426518065aSAndre Przywara u32 gsi, i; 1436518065aSAndre Przywara 1446518065aSAndre Przywara /* Find the GSI number used for that vector */ 1456518065aSAndre Przywara if (vecnum == vpci->config_vector) { 1466518065aSAndre Przywara gsi = vpci->config_gsi; 1476518065aSAndre Przywara } else { 1486518065aSAndre Przywara for (i = 0; i < VIRTIO_PCI_MAX_VQ; i++) 1496518065aSAndre Przywara if (vpci->vq_vector[i] == vecnum) 1506518065aSAndre Przywara break; 1516518065aSAndre Przywara if (i == VIRTIO_PCI_MAX_VQ) 1526518065aSAndre Przywara return; 1536518065aSAndre Przywara gsi = vpci->gsis[i]; 1546518065aSAndre Przywara } 1556518065aSAndre Przywara 1566518065aSAndre Przywara if (gsi == 0) 1576518065aSAndre Przywara return; 1586518065aSAndre Przywara 1596518065aSAndre Przywara msix_entry = &msix_entry[vecnum]; 1606518065aSAndre Przywara irq__update_msix_route(vpci->kvm, gsi, &msix_entry->msg); 1616518065aSAndre Przywara } 1626518065aSAndre Przywara 1639b735910SMarc Zyngier static void virtio_pci__msix_mmio_callback(struct kvm_cpu *vcpu, 1649b735910SMarc Zyngier u64 addr, u8 *data, u32 len, 165a463650cSWill Deacon u8 is_write, void *ptr) 16636f5dc91SSasha Levin { 167e09b599aSJulien Thierry struct virtio_device *vdev = ptr; 168e09b599aSJulien Thierry struct virtio_pci *vpci = vdev->virtio; 1696518065aSAndre Przywara struct msix_table *table; 170e539f3e4SAlexandru Elisei u32 msix_io_addr = virtio_pci__msix_io_addr(vpci); 1712e7380dbSMarc Zyngier u32 pba_offset; 1726518065aSAndre Przywara int vecnum; 1736518065aSAndre Przywara size_t offset; 17436f5dc91SSasha Levin 1752e7380dbSMarc Zyngier BUILD_BUG_ON(VIRTIO_NR_MSIX > (sizeof(vpci->msix_pba) * 8)); 1762e7380dbSMarc Zyngier 1772e7380dbSMarc Zyngier pba_offset = vpci->pci_hdr.msix.pba_offset & ~PCI_MSIX_TABLE_BIR; 1782e7380dbSMarc Zyngier if (addr >= msix_io_addr + pba_offset) { 1792e7380dbSMarc Zyngier /* Read access to PBA */ 1806518065aSAndre Przywara if (is_write) 1816518065aSAndre Przywara return; 1822e7380dbSMarc Zyngier offset = addr - (msix_io_addr + pba_offset); 1832e7380dbSMarc Zyngier if ((offset + len) > sizeof (vpci->msix_pba)) 1842e7380dbSMarc Zyngier return; 1852e7380dbSMarc Zyngier memcpy(data, (void *)&vpci->msix_pba + offset, len); 1862e7380dbSMarc Zyngier return; 1872e7380dbSMarc Zyngier } 1882e7380dbSMarc Zyngier 1896518065aSAndre Przywara table = vpci->msix_table; 190e539f3e4SAlexandru Elisei offset = addr - msix_io_addr; 1912e7380dbSMarc Zyngier 1926518065aSAndre Przywara vecnum = offset / sizeof(struct msix_table); 1936518065aSAndre Przywara offset = offset % sizeof(struct msix_table); 1946518065aSAndre Przywara 1956518065aSAndre Przywara if (!is_write) { 1966518065aSAndre Przywara memcpy(data, (void *)&table[vecnum] + offset, len); 1976518065aSAndre Przywara return; 19836f5dc91SSasha Levin } 19936f5dc91SSasha Levin 2006518065aSAndre Przywara memcpy((void *)&table[vecnum] + offset, data, len); 2016518065aSAndre Przywara 2026518065aSAndre Przywara /* Did we just update the address or payload? */ 2036518065aSAndre Przywara if (offset < offsetof(struct msix_table, ctrl)) 2046518065aSAndre Przywara update_msix_map(vpci, table, vecnum); 20506f48103SSasha Levin } 20606f48103SSasha Levin 207714ab9e6SAndre Przywara static void virtio_pci__signal_msi(struct kvm *kvm, struct virtio_pci *vpci, 208714ab9e6SAndre Przywara int vec) 20943c81c74SSasha Levin { 21043c81c74SSasha Levin struct kvm_msi msi = { 21143c81c74SSasha Levin .address_lo = vpci->msix_table[vec].msg.address_lo, 21243c81c74SSasha Levin .address_hi = vpci->msix_table[vec].msg.address_hi, 21343c81c74SSasha Levin .data = vpci->msix_table[vec].msg.data, 21443c81c74SSasha Levin }; 21543c81c74SSasha Levin 216714ab9e6SAndre Przywara if (kvm->msix_needs_devid) { 217714ab9e6SAndre Przywara msi.flags = KVM_MSI_VALID_DEVID; 218714ab9e6SAndre Przywara msi.devid = vpci->dev_hdr.dev_num << 3; 219714ab9e6SAndre Przywara } 220714ab9e6SAndre Przywara 221f6108d72SJean-Philippe Brucker irq__signal_msi(kvm, &msi); 22243c81c74SSasha Levin } 22343c81c74SSasha Levin 22402eca50cSAsias He int virtio_pci__signal_vq(struct kvm *kvm, struct virtio_device *vdev, u32 vq) 22536f5dc91SSasha Levin { 22602eca50cSAsias He struct virtio_pci *vpci = vdev->virtio; 22706f48103SSasha Levin int tbl = vpci->vq_vector[vq]; 22836f5dc91SSasha Levin 229f8327b05SSasha Levin if (virtio_pci__msix_enabled(vpci) && tbl != VIRTIO_MSI_NO_VECTOR) { 230aa73be70SMatt Evans if (vpci->pci_hdr.msix.ctrl & cpu_to_le16(PCI_MSIX_FLAGS_MASKALL) || 231aa73be70SMatt Evans vpci->msix_table[tbl].ctrl & cpu_to_le16(PCI_MSIX_ENTRY_CTRL_MASKBIT)) { 23206f48103SSasha Levin 23306f48103SSasha Levin vpci->msix_pba |= 1 << tbl; 23406f48103SSasha Levin return 0; 23506f48103SSasha Levin } 23606f48103SSasha Levin 23743c81c74SSasha Levin if (vpci->features & VIRTIO_PCI_F_SIGNAL_MSI) 23843c81c74SSasha Levin virtio_pci__signal_msi(kvm, vpci, vpci->vq_vector[vq]); 23943c81c74SSasha Levin else 24006f48103SSasha Levin kvm__irq_trigger(kvm, vpci->gsis[vq]); 24106f48103SSasha Levin } else { 242a36eca7bSSasha Levin vpci->isr = VIRTIO_IRQ_HIGH; 2432108c86dSMarc Zyngier kvm__irq_line(kvm, vpci->legacy_irq_line, VIRTIO_IRQ_HIGH); 24406f48103SSasha Levin } 24536f5dc91SSasha Levin return 0; 24636f5dc91SSasha Levin } 24736f5dc91SSasha Levin 24802eca50cSAsias He int virtio_pci__signal_config(struct kvm *kvm, struct virtio_device *vdev) 24936f5dc91SSasha Levin { 25002eca50cSAsias He struct virtio_pci *vpci = vdev->virtio; 25106f48103SSasha Levin int tbl = vpci->config_vector; 25206f48103SSasha Levin 253f8327b05SSasha Levin if (virtio_pci__msix_enabled(vpci) && tbl != VIRTIO_MSI_NO_VECTOR) { 254aa73be70SMatt Evans if (vpci->pci_hdr.msix.ctrl & cpu_to_le16(PCI_MSIX_FLAGS_MASKALL) || 255aa73be70SMatt Evans vpci->msix_table[tbl].ctrl & cpu_to_le16(PCI_MSIX_ENTRY_CTRL_MASKBIT)) { 25606f48103SSasha Levin 25706f48103SSasha Levin vpci->msix_pba |= 1 << tbl; 25806f48103SSasha Levin return 0; 25906f48103SSasha Levin } 26006f48103SSasha Levin 26143c81c74SSasha Levin if (vpci->features & VIRTIO_PCI_F_SIGNAL_MSI) 262f8327b05SSasha Levin virtio_pci__signal_msi(kvm, vpci, tbl); 26343c81c74SSasha Levin else 26406f48103SSasha Levin kvm__irq_trigger(kvm, vpci->config_gsi); 26506f48103SSasha Levin } else { 26606f48103SSasha Levin vpci->isr = VIRTIO_PCI_ISR_CONFIG; 267e9922aafSAndre Przywara kvm__irq_trigger(kvm, vpci->legacy_irq_line); 26806f48103SSasha Levin } 26936f5dc91SSasha Levin 27036f5dc91SSasha Levin return 0; 27136f5dc91SSasha Levin } 27236f5dc91SSasha Levin 2735a8e4f25SAlexandru Elisei static int virtio_pci__bar_activate(struct kvm *kvm, 2745a8e4f25SAlexandru Elisei struct pci_device_header *pci_hdr, 2755a8e4f25SAlexandru Elisei int bar_num, void *data) 2765a8e4f25SAlexandru Elisei { 2775a8e4f25SAlexandru Elisei struct virtio_device *vdev = data; 278*b0d56e3cSJean-Philippe Brucker mmio_handler_fn mmio_fn; 2795a8e4f25SAlexandru Elisei u32 bar_addr, bar_size; 2805a8e4f25SAlexandru Elisei int r = -EINVAL; 2815a8e4f25SAlexandru Elisei 282*b0d56e3cSJean-Philippe Brucker if (vdev->legacy) 283*b0d56e3cSJean-Philippe Brucker mmio_fn = &virtio_pci_legacy__io_mmio_callback; 284*b0d56e3cSJean-Philippe Brucker else 285*b0d56e3cSJean-Philippe Brucker mmio_fn = &virtio_pci_modern__io_mmio_callback; 286*b0d56e3cSJean-Philippe Brucker 2875a8e4f25SAlexandru Elisei assert(bar_num <= 2); 2885a8e4f25SAlexandru Elisei 2895a8e4f25SAlexandru Elisei bar_addr = pci__bar_address(pci_hdr, bar_num); 2905a8e4f25SAlexandru Elisei bar_size = pci__bar_size(pci_hdr, bar_num); 2915a8e4f25SAlexandru Elisei 2925a8e4f25SAlexandru Elisei switch (bar_num) { 2935a8e4f25SAlexandru Elisei case 0: 294*b0d56e3cSJean-Philippe Brucker r = kvm__register_pio(kvm, bar_addr, bar_size, mmio_fn, vdev); 2955a8e4f25SAlexandru Elisei break; 2965a8e4f25SAlexandru Elisei case 1: 297*b0d56e3cSJean-Philippe Brucker r = kvm__register_mmio(kvm, bar_addr, bar_size, false, mmio_fn, 298930876d5SJean-Philippe Brucker vdev); 2995a8e4f25SAlexandru Elisei break; 3005a8e4f25SAlexandru Elisei case 2: 3015a8e4f25SAlexandru Elisei r = kvm__register_mmio(kvm, bar_addr, bar_size, false, 3025a8e4f25SAlexandru Elisei virtio_pci__msix_mmio_callback, vdev); 3035a8e4f25SAlexandru Elisei break; 3045a8e4f25SAlexandru Elisei } 3055a8e4f25SAlexandru Elisei 3065a8e4f25SAlexandru Elisei return r; 3075a8e4f25SAlexandru Elisei } 3085a8e4f25SAlexandru Elisei 3095a8e4f25SAlexandru Elisei static int virtio_pci__bar_deactivate(struct kvm *kvm, 3105a8e4f25SAlexandru Elisei struct pci_device_header *pci_hdr, 3115a8e4f25SAlexandru Elisei int bar_num, void *data) 3125a8e4f25SAlexandru Elisei { 3135a8e4f25SAlexandru Elisei u32 bar_addr; 3145a8e4f25SAlexandru Elisei bool success; 3155a8e4f25SAlexandru Elisei int r = -EINVAL; 3165a8e4f25SAlexandru Elisei 3175a8e4f25SAlexandru Elisei assert(bar_num <= 2); 3185a8e4f25SAlexandru Elisei 3195a8e4f25SAlexandru Elisei bar_addr = pci__bar_address(pci_hdr, bar_num); 3205a8e4f25SAlexandru Elisei 3215a8e4f25SAlexandru Elisei switch (bar_num) { 3225a8e4f25SAlexandru Elisei case 0: 323205eaa79SAndre Przywara r = kvm__deregister_pio(kvm, bar_addr); 3245a8e4f25SAlexandru Elisei break; 3255a8e4f25SAlexandru Elisei case 1: 3265a8e4f25SAlexandru Elisei case 2: 3275a8e4f25SAlexandru Elisei success = kvm__deregister_mmio(kvm, bar_addr); 3285a8e4f25SAlexandru Elisei /* kvm__deregister_mmio fails when the region is not found. */ 3295a8e4f25SAlexandru Elisei r = (success ? 0 : -ENOENT); 3305a8e4f25SAlexandru Elisei break; 3315a8e4f25SAlexandru Elisei } 3325a8e4f25SAlexandru Elisei 3335a8e4f25SAlexandru Elisei return r; 3345a8e4f25SAlexandru Elisei } 3355a8e4f25SAlexandru Elisei 33602eca50cSAsias He int virtio_pci__init(struct kvm *kvm, void *dev, struct virtio_device *vdev, 337507e02d8SAsias He int device_id, int subsys_id, int class) 33836f5dc91SSasha Levin { 33902eca50cSAsias He struct virtio_pci *vpci = vdev->virtio; 340e539f3e4SAlexandru Elisei u32 mmio_addr, msix_io_block; 341e539f3e4SAlexandru Elisei u16 port_addr; 3427af40b91SSasha Levin int r; 34336f5dc91SSasha Levin 344a463650cSWill Deacon vpci->kvm = kvm; 34536f5dc91SSasha Levin vpci->dev = dev; 34636f5dc91SSasha Levin 347ce2fc8f5SAlexandru Elisei BUILD_BUG_ON(!is_power_of_two(PCI_IO_SIZE)); 348ce2fc8f5SAlexandru Elisei 349e539f3e4SAlexandru Elisei port_addr = pci_get_io_port_block(PCI_IO_SIZE); 350e539f3e4SAlexandru Elisei mmio_addr = pci_get_mmio_block(PCI_IO_SIZE); 3512e7380dbSMarc Zyngier msix_io_block = pci_get_mmio_block(VIRTIO_MSIX_BAR_SIZE); 352a463650cSWill Deacon 35336f5dc91SSasha Levin vpci->pci_hdr = (struct pci_device_header) { 354aa73be70SMatt Evans .vendor_id = cpu_to_le16(PCI_VENDOR_ID_REDHAT_QUMRANET), 355aa73be70SMatt Evans .device_id = cpu_to_le16(device_id), 356ec7dd52fSSasha Levin .command = PCI_COMMAND_IO | PCI_COMMAND_MEMORY, 35736f5dc91SSasha Levin .header_type = PCI_HEADER_TYPE_NORMAL, 358*b0d56e3cSJean-Philippe Brucker .revision_id = vdev->legacy ? 0 : 1, 359aa73be70SMatt Evans .class[0] = class & 0xff, 360aa73be70SMatt Evans .class[1] = (class >> 8) & 0xff, 361aa73be70SMatt Evans .class[2] = (class >> 16) & 0xff, 362aa73be70SMatt Evans .subsys_vendor_id = cpu_to_le16(PCI_SUBSYSTEM_VENDOR_ID_REDHAT_QUMRANET), 363aa73be70SMatt Evans .subsys_id = cpu_to_le16(subsys_id), 364e539f3e4SAlexandru Elisei .bar[0] = cpu_to_le32(port_addr 3659c26dab4SSasha Levin | PCI_BASE_ADDRESS_SPACE_IO), 366e539f3e4SAlexandru Elisei .bar[1] = cpu_to_le32(mmio_addr 367a508ea95SJean-Philippe Brucker | PCI_BASE_ADDRESS_SPACE_MEMORY), 368e539f3e4SAlexandru Elisei .bar[2] = cpu_to_le32(msix_io_block 369b4dab816SSasha Levin | PCI_BASE_ADDRESS_SPACE_MEMORY), 370aa73be70SMatt Evans .status = cpu_to_le16(PCI_STATUS_CAP_LIST), 371*b0d56e3cSJean-Philippe Brucker .capabilities = PCI_CAP_OFF(&vpci->pci_hdr, msix), 37248843d10SJulien Thierry .bar_size[0] = cpu_to_le32(PCI_IO_SIZE), 37348843d10SJulien Thierry .bar_size[1] = cpu_to_le32(PCI_IO_SIZE), 3742e7380dbSMarc Zyngier .bar_size[2] = cpu_to_le32(VIRTIO_MSIX_BAR_SIZE), 37536f5dc91SSasha Levin }; 37636f5dc91SSasha Levin 3775a8e4f25SAlexandru Elisei r = pci__register_bar_regions(kvm, &vpci->pci_hdr, 3785a8e4f25SAlexandru Elisei virtio_pci__bar_activate, 3795a8e4f25SAlexandru Elisei virtio_pci__bar_deactivate, vdev); 3805a8e4f25SAlexandru Elisei if (r < 0) 3815a8e4f25SAlexandru Elisei return r; 3825a8e4f25SAlexandru Elisei 38321ff329dSWill Deacon vpci->dev_hdr = (struct device_header) { 38421ff329dSWill Deacon .bus_type = DEVICE_BUS_PCI, 38521ff329dSWill Deacon .data = &vpci->pci_hdr, 38621ff329dSWill Deacon }; 38721ff329dSWill Deacon 38836f5dc91SSasha Levin vpci->pci_hdr.msix.cap = PCI_CAP_ID_MSIX; 38936f5dc91SSasha Levin vpci->pci_hdr.msix.next = 0; 39014bba8a0SAsias He /* 3912e7380dbSMarc Zyngier * We at most have VIRTIO_NR_MSIX entries (VIRTIO_PCI_MAX_VQ 3922e7380dbSMarc Zyngier * entries for virt queue, VIRTIO_PCI_MAX_CONFIG entries for 3932e7380dbSMarc Zyngier * config). 39414bba8a0SAsias He * 39514bba8a0SAsias He * To quote the PCI spec: 39614bba8a0SAsias He * 39714bba8a0SAsias He * System software reads this field to determine the 39814bba8a0SAsias He * MSI-X Table Size N, which is encoded as N-1. 39914bba8a0SAsias He * For example, a returned value of "00000000011" 40014bba8a0SAsias He * indicates a table size of 4. 40114bba8a0SAsias He */ 4022e7380dbSMarc Zyngier vpci->pci_hdr.msix.ctrl = cpu_to_le16(VIRTIO_NR_MSIX - 1); 40306f48103SSasha Levin 404a463650cSWill Deacon /* Both table and PBA are mapped to the same BAR (2) */ 405a463650cSWill Deacon vpci->pci_hdr.msix.table_offset = cpu_to_le32(2); 4062e7380dbSMarc Zyngier vpci->pci_hdr.msix.pba_offset = cpu_to_le32(2 | VIRTIO_MSIX_TABLE_SIZE); 40736f5dc91SSasha Levin vpci->config_vector = 0; 40836f5dc91SSasha Levin 409f6108d72SJean-Philippe Brucker if (irq__can_signal_msi(kvm)) 41043c81c74SSasha Levin vpci->features |= VIRTIO_PCI_F_SIGNAL_MSI; 41143c81c74SSasha Levin 412c0c45eedSAndre Przywara vpci->legacy_irq_line = pci__assign_irq(&vpci->pci_hdr); 413c0c45eedSAndre Przywara 41421ff329dSWill Deacon r = device__register(&vpci->dev_hdr); 415495fbd4eSSasha Levin if (r < 0) 4165a8e4f25SAlexandru Elisei return r; 417495fbd4eSSasha Levin 418*b0d56e3cSJean-Philippe Brucker if (vdev->legacy) 419*b0d56e3cSJean-Philippe Brucker vpci->doorbell_offset = VIRTIO_PCI_QUEUE_NOTIFY; 420*b0d56e3cSJean-Philippe Brucker else 421*b0d56e3cSJean-Philippe Brucker return virtio_pci_modern_init(vdev); 422*b0d56e3cSJean-Philippe Brucker 423495fbd4eSSasha Levin return 0; 424495fbd4eSSasha Levin } 425495fbd4eSSasha Levin 426eb34a8c2SJean-Philippe Brucker int virtio_pci__reset(struct kvm *kvm, struct virtio_device *vdev) 427eb34a8c2SJean-Philippe Brucker { 42831e0eaccSMartin Radev unsigned int vq; 429eb34a8c2SJean-Philippe Brucker struct virtio_pci *vpci = vdev->virtio; 430eb34a8c2SJean-Philippe Brucker 431c6590f78SJean-Philippe Brucker virtio_pci__del_msix_route(vpci, vpci->config_gsi); 432c6590f78SJean-Philippe Brucker vpci->config_gsi = 0; 433c6590f78SJean-Philippe Brucker vpci->config_vector = VIRTIO_MSI_NO_VECTOR; 434c6590f78SJean-Philippe Brucker 435eb34a8c2SJean-Philippe Brucker for (vq = 0; vq < vdev->ops->get_vq_count(kvm, vpci->dev); vq++) 436eb34a8c2SJean-Philippe Brucker virtio_pci_exit_vq(kvm, vdev, vq); 437eb34a8c2SJean-Philippe Brucker 438eb34a8c2SJean-Philippe Brucker return 0; 439eb34a8c2SJean-Philippe Brucker } 440eb34a8c2SJean-Philippe Brucker 44102eca50cSAsias He int virtio_pci__exit(struct kvm *kvm, struct virtio_device *vdev) 442495fbd4eSSasha Levin { 44302eca50cSAsias He struct virtio_pci *vpci = vdev->virtio; 444495fbd4eSSasha Levin 445eb34a8c2SJean-Philippe Brucker virtio_pci__reset(kvm, vdev); 446e539f3e4SAlexandru Elisei kvm__deregister_mmio(kvm, virtio_pci__mmio_addr(vpci)); 447e539f3e4SAlexandru Elisei kvm__deregister_mmio(kvm, virtio_pci__msix_io_addr(vpci)); 448205eaa79SAndre Przywara kvm__deregister_pio(kvm, virtio_pci__port_addr(vpci)); 449495fbd4eSSasha Levin 45036f5dc91SSasha Levin return 0; 45136f5dc91SSasha Levin } 452