#ifndef KVM__VIRTIO_PCI_H #define KVM__VIRTIO_PCI_H #include "kvm/devices.h" #include "kvm/pci.h" #include "kvm/virtio.h" #include #include #include #define VIRTIO_PCI_MAX_VQ 32 #define VIRTIO_PCI_MAX_CONFIG 1 struct kvm; struct kvm_cpu; struct virtio_pci_ioevent_param { struct virtio_device *vdev; u32 vq; }; #define ALIGN_UP(x, s) ALIGN((x) + (s) - 1, (s)) #define VIRTIO_NR_MSIX (VIRTIO_PCI_MAX_VQ + VIRTIO_PCI_MAX_CONFIG) #define VIRTIO_MSIX_TABLE_SIZE (VIRTIO_NR_MSIX * 16) #define VIRTIO_MSIX_PBA_SIZE (ALIGN_UP(VIRTIO_MSIX_TABLE_SIZE, 64) / 8) #define VIRTIO_MSIX_BAR_SIZE (1UL << fls_long(VIRTIO_MSIX_TABLE_SIZE + \ VIRTIO_MSIX_PBA_SIZE)) struct virtio_pci { struct pci_device_header pci_hdr; struct device_header dev_hdr; void *dev; struct kvm *kvm; u32 doorbell_offset; bool signal_msi; u8 status; u8 isr; u32 device_features_sel; u32 driver_features_sel; /* * We cannot rely on the INTERRUPT_LINE byte in the config space once * we have run guest code, as the OS is allowed to use that field * as a scratch pad to communicate between driver and PCI layer. * So store our legacy interrupt line number in here for internal use. */ u8 legacy_irq_line; /* MSI-X */ u16 config_vector; u32 config_gsi; u16 vq_vector[VIRTIO_PCI_MAX_VQ]; u32 gsis[VIRTIO_PCI_MAX_VQ]; u64 msix_pba; struct msix_table msix_table[VIRTIO_PCI_MAX_VQ + VIRTIO_PCI_MAX_CONFIG]; /* virtio queue */ u16 queue_selector; struct virtio_pci_ioevent_param ioeventfds[VIRTIO_PCI_MAX_VQ]; }; int virtio_pci__signal_vq(struct kvm *kvm, struct virtio_device *vdev, u32 vq); int virtio_pci__signal_config(struct kvm *kvm, struct virtio_device *vdev); int virtio_pci__exit(struct kvm *kvm, struct virtio_device *vdev); int virtio_pci__reset(struct kvm *kvm, struct virtio_device *vdev); int virtio_pci__init(struct kvm *kvm, void *dev, struct virtio_device *vdev, int device_id, int subsys_id, int class); int virtio_pci_modern_init(struct virtio_device *vdev); static inline bool virtio_pci__msix_enabled(struct virtio_pci *vpci) { return vpci->pci_hdr.msix.ctrl & cpu_to_le16(PCI_MSIX_FLAGS_ENABLE); } static inline u16 virtio_pci__port_addr(struct virtio_pci *vpci) { return pci__bar_address(&vpci->pci_hdr, 0); } static inline u32 virtio_pci__mmio_addr(struct virtio_pci *vpci) { return pci__bar_address(&vpci->pci_hdr, 1); } static inline u32 virtio_pci__msix_io_addr(struct virtio_pci *vpci) { return pci__bar_address(&vpci->pci_hdr, 2); } int virtio_pci__add_msix_route(struct virtio_pci *vpci, u32 vec); int virtio_pci__init_ioeventfd(struct kvm *kvm, struct virtio_device *vdev, u32 vq); int virtio_pci_init_vq(struct kvm *kvm, struct virtio_device *vdev, int vq); void virtio_pci_exit_vq(struct kvm *kvm, struct virtio_device *vdev, int vq); void virtio_pci_legacy__io_mmio_callback(struct kvm_cpu *vcpu, u64 addr, u8 *data, u32 len, u8 is_write, void *ptr); void virtio_pci_modern__io_mmio_callback(struct kvm_cpu *vcpu, u64 addr, u8 *data, u32 len, u8 is_write, void *ptr); #endif