#include "hw/pci/msix.h"
#include "hw/pci/pci_bridge.h"
#include "qemu/error-report.h"
+#include "qemu/option.h"
#include "qemu/range.h"
+#include "qemu/units.h"
#include "sysemu/kvm.h"
#include "sysemu/sysemu.h"
#include "pci.h"
#define MSIX_CAP_LENGTH 12
+#define TYPE_VFIO_PCI "vfio-pci"
+#define PCI_VFIO(obj) OBJECT_CHECK(VFIOPCIDevice, obj, TYPE_VFIO_PCI)
+
static void vfio_disable_interrupts(VFIOPCIDevice *vdev);
static void vfio_mmap_set_enabled(VFIOPCIDevice *vdev, bool enabled);
static void vfio_intx_update(PCIDevice *pdev)
{
- VFIOPCIDevice *vdev = DO_UPCAST(VFIOPCIDevice, pdev, pdev);
+ VFIOPCIDevice *vdev = PCI_VFIO(pdev);
PCIINTxRoute route;
Error *err = NULL;
vfio_intx_enable_kvm(vdev, &err);
if (err) {
- error_reportf_err(err, WARN_PREFIX, vdev->vbasedev.name);
+ warn_reportf_err(err, VFIO_MSG_PREFIX, vdev->vbasedev.name);
}
/* Re-enable the interrupt in cased we missed an EOI */
vfio_intx_enable_kvm(vdev, &err);
if (err) {
- error_reportf_err(err, WARN_PREFIX, vdev->vbasedev.name);
+ warn_reportf_err(err, VFIO_MSG_PREFIX, vdev->vbasedev.name);
}
vdev->interrupt = VFIO_INT_INTx;
static int vfio_msix_vector_do_use(PCIDevice *pdev, unsigned int nr,
MSIMessage *msg, IOHandler *handler)
{
- VFIOPCIDevice *vdev = DO_UPCAST(VFIOPCIDevice, pdev, pdev);
+ VFIOPCIDevice *vdev = PCI_VFIO(pdev);
VFIOMSIVector *vector;
int ret;
static void vfio_msix_vector_release(PCIDevice *pdev, unsigned int nr)
{
- VFIOPCIDevice *vdev = DO_UPCAST(VFIOPCIDevice, pdev, pdev);
+ VFIOPCIDevice *vdev = PCI_VFIO(pdev);
VFIOMSIVector *vector = &vdev->msi_vectors[nr];
trace_vfio_msix_vector_release(vdev->vbasedev.name, nr);
vfio_intx_enable(vdev, &err);
if (err) {
- error_reportf_err(err, ERR_PREFIX, vdev->vbasedev.name);
+ error_reportf_err(err, VFIO_MSG_PREFIX, vdev->vbasedev.name);
}
}
pci_register_bar(&vdev->pdev, PCI_ROM_SLOT,
PCI_BASE_ADDRESS_SPACE_MEMORY, &vdev->pdev.rom);
- vdev->pdev.has_rom = true;
vdev->rom_read_failed = false;
}
*/
static void vfio_sub_page_bar_update_mapping(PCIDevice *pdev, int bar)
{
- VFIOPCIDevice *vdev = DO_UPCAST(VFIOPCIDevice, pdev, pdev);
+ VFIOPCIDevice *vdev = PCI_VFIO(pdev);
VFIORegion *region = &vdev->bars[bar].region;
- MemoryRegion *mmap_mr, *mr;
+ MemoryRegion *mmap_mr, *region_mr, *base_mr;
PCIIORegion *r;
pcibus_t bar_addr;
uint64_t size = region->size;
r = &pdev->io_regions[bar];
bar_addr = r->addr;
- mr = region->mem;
+ base_mr = vdev->bars[bar].mr;
+ region_mr = region->mem;
mmap_mr = ®ion->mmaps[0].mem;
/* If BAR is mapped and page aligned, update to fill PAGE_SIZE */
memory_region_transaction_begin();
- memory_region_set_size(mr, size);
+ if (vdev->bars[bar].size < size) {
+ memory_region_set_size(base_mr, size);
+ }
+ memory_region_set_size(region_mr, size);
memory_region_set_size(mmap_mr, size);
- if (size != region->size && memory_region_is_mapped(mr)) {
- memory_region_del_subregion(r->address_space, mr);
+ if (size != vdev->bars[bar].size && memory_region_is_mapped(base_mr)) {
+ memory_region_del_subregion(r->address_space, base_mr);
memory_region_add_subregion_overlap(r->address_space,
- bar_addr, mr, 0);
+ bar_addr, base_mr, 0);
}
memory_region_transaction_commit();
*/
uint32_t vfio_pci_read_config(PCIDevice *pdev, uint32_t addr, int len)
{
- VFIOPCIDevice *vdev = DO_UPCAST(VFIOPCIDevice, pdev, pdev);
+ VFIOPCIDevice *vdev = PCI_VFIO(pdev);
uint32_t emu_bits = 0, emu_val = 0, phys_val = 0, val;
memcpy(&emu_bits, vdev->emulated_config_bits + addr, len);
void vfio_pci_write_config(PCIDevice *pdev,
uint32_t addr, uint32_t val, int len)
{
- VFIOPCIDevice *vdev = DO_UPCAST(VFIOPCIDevice, pdev, pdev);
+ VFIOPCIDevice *vdev = PCI_VFIO(pdev);
uint32_t val_le = cpu_to_le32(val);
trace_vfio_pci_write_config(vdev->vbasedev.name, addr, val, len);
for (bar = 0; bar < PCI_ROM_SLOT; bar++) {
if (old_addr[bar] != pdev->io_regions[bar].addr &&
- pdev->io_regions[bar].size > 0 &&
- pdev->io_regions[bar].size < qemu_real_host_page_size) {
+ vdev->bars[bar].region.size > 0 &&
+ vdev->bars[bar].region.size < qemu_real_host_page_size) {
vfio_sub_page_bar_update_mapping(pdev, bar);
}
}
if (ret == -ENOTSUP) {
return 0;
}
- error_prepend(&err, "msi_init failed: ");
- error_propagate(errp, err);
+ error_propagate_prepend(errp, err, "msi_init failed: ");
return ret;
}
vdev->msi_cap_size = 0xa + (msi_maskbit ? 0xa : 0) + (msi_64bit ? 0x4 : 0);
off_t start, end;
VFIORegion *region = &vdev->bars[vdev->msix->table_bar].region;
+ /*
+ * If the host driver allows mapping of a MSIX data, we are going to
+ * do map the entire BAR and emulate MSIX table on top of that.
+ */
+ if (vfio_has_region_cap(&vdev->vbasedev, region->nr,
+ VFIO_REGION_INFO_CAP_MSIX_MAPPABLE)) {
+ return;
+ }
+
/*
* We expect to find a single mmap covering the whole BAR, anything else
* means it's either unsupported or already setup.
}
}
+static void vfio_pci_relocate_msix(VFIOPCIDevice *vdev, Error **errp)
+{
+ int target_bar = -1;
+ size_t msix_sz;
+
+ if (!vdev->msix || vdev->msix_relo == OFF_AUTOPCIBAR_OFF) {
+ return;
+ }
+
+ /* The actual minimum size of MSI-X structures */
+ msix_sz = (vdev->msix->entries * PCI_MSIX_ENTRY_SIZE) +
+ (QEMU_ALIGN_UP(vdev->msix->entries, 64) / 8);
+ /* Round up to host pages, we don't want to share a page */
+ msix_sz = REAL_HOST_PAGE_ALIGN(msix_sz);
+ /* PCI BARs must be a power of 2 */
+ msix_sz = pow2ceil(msix_sz);
+
+ if (vdev->msix_relo == OFF_AUTOPCIBAR_AUTO) {
+ /*
+ * TODO: Lookup table for known devices.
+ *
+ * Logically we might use an algorithm here to select the BAR adding
+ * the least additional MMIO space, but we cannot programatically
+ * predict the driver dependency on BAR ordering or sizing, therefore
+ * 'auto' becomes a lookup for combinations reported to work.
+ */
+ if (target_bar < 0) {
+ error_setg(errp, "No automatic MSI-X relocation available for "
+ "device %04x:%04x", vdev->vendor_id, vdev->device_id);
+ return;
+ }
+ } else {
+ target_bar = (int)(vdev->msix_relo - OFF_AUTOPCIBAR_BAR0);
+ }
+
+ /* I/O port BARs cannot host MSI-X structures */
+ if (vdev->bars[target_bar].ioport) {
+ error_setg(errp, "Invalid MSI-X relocation BAR %d, "
+ "I/O port BAR", target_bar);
+ return;
+ }
+
+ /* Cannot use a BAR in the "shadow" of a 64-bit BAR */
+ if (!vdev->bars[target_bar].size &&
+ target_bar > 0 && vdev->bars[target_bar - 1].mem64) {
+ error_setg(errp, "Invalid MSI-X relocation BAR %d, "
+ "consumed by 64-bit BAR %d", target_bar, target_bar - 1);
+ return;
+ }
+
+ /* 2GB max size for 32-bit BARs, cannot double if already > 1G */
+ if (vdev->bars[target_bar].size > 1 * GiB &&
+ !vdev->bars[target_bar].mem64) {
+ error_setg(errp, "Invalid MSI-X relocation BAR %d, "
+ "no space to extend 32-bit BAR", target_bar);
+ return;
+ }
+
+ /*
+ * If adding a new BAR, test if we can make it 64bit. We make it
+ * prefetchable since QEMU MSI-X emulation has no read side effects
+ * and doing so makes mapping more flexible.
+ */
+ if (!vdev->bars[target_bar].size) {
+ if (target_bar < (PCI_ROM_SLOT - 1) &&
+ !vdev->bars[target_bar + 1].size) {
+ vdev->bars[target_bar].mem64 = true;
+ vdev->bars[target_bar].type = PCI_BASE_ADDRESS_MEM_TYPE_64;
+ }
+ vdev->bars[target_bar].type |= PCI_BASE_ADDRESS_MEM_PREFETCH;
+ vdev->bars[target_bar].size = msix_sz;
+ vdev->msix->table_offset = 0;
+ } else {
+ vdev->bars[target_bar].size = MAX(vdev->bars[target_bar].size * 2,
+ msix_sz * 2);
+ /*
+ * Due to above size calc, MSI-X always starts halfway into the BAR,
+ * which will always be a separate host page.
+ */
+ vdev->msix->table_offset = vdev->bars[target_bar].size / 2;
+ }
+
+ vdev->msix->table_bar = target_bar;
+ vdev->msix->pba_bar = target_bar;
+ /* Requires 8-byte alignment, but PCI_MSIX_ENTRY_SIZE guarantees that */
+ vdev->msix->pba_offset = vdev->msix->table_offset +
+ (vdev->msix->entries * PCI_MSIX_ENTRY_SIZE);
+
+ trace_vfio_msix_relo(vdev->vbasedev.name,
+ vdev->msix->table_bar, vdev->msix->table_offset);
+}
+
/*
* We don't have any control over how pci_add_capability() inserts
* capabilities into the chain. In order to setup MSI-X we need a
vdev->msix = msix;
vfio_pci_fixup_msix_region(vdev);
+
+ vfio_pci_relocate_msix(vdev, errp);
}
static int vfio_msix_setup(VFIOPCIDevice *vdev, int pos, Error **errp)
vdev->msix->pending = g_malloc0(BITS_TO_LONGS(vdev->msix->entries) *
sizeof(unsigned long));
ret = msix_init(&vdev->pdev, vdev->msix->entries,
- vdev->bars[vdev->msix->table_bar].region.mem,
+ vdev->bars[vdev->msix->table_bar].mr,
vdev->msix->table_bar, vdev->msix->table_offset,
- vdev->bars[vdev->msix->pba_bar].region.mem,
+ vdev->bars[vdev->msix->pba_bar].mr,
vdev->msix->pba_bar, vdev->msix->pba_offset, pos,
&err);
if (ret < 0) {
if (ret == -ENOTSUP) {
- error_report_err(err);
+ warn_report_err(err);
return 0;
}
*/
memory_region_set_enabled(&vdev->pdev.msix_pba_mmio, false);
+ /*
+ * The emulated machine may provide a paravirt interface for MSIX setup
+ * so it is not strictly necessary to emulate MSIX here. This becomes
+ * helpful when frequently accessed MMIO registers are located in
+ * subpages adjacent to the MSIX table but the MSIX data containing page
+ * cannot be mapped because of a host page size bigger than the MSIX table
+ * alignment.
+ */
+ if (object_property_get_bool(OBJECT(qdev_get_machine()),
+ "vfio-no-msix-emulation", NULL)) {
+ memory_region_set_enabled(&vdev->pdev.msix_table_mmio, false);
+ }
+
return 0;
}
if (vdev->msix) {
msix_uninit(&vdev->pdev,
- vdev->bars[vdev->msix->table_bar].region.mem,
- vdev->bars[vdev->msix->pba_bar].region.mem);
+ vdev->bars[vdev->msix->table_bar].mr,
+ vdev->bars[vdev->msix->pba_bar].mr);
g_free(vdev->msix->pending);
}
}
}
}
-static void vfio_bar_setup(VFIOPCIDevice *vdev, int nr)
+static void vfio_bar_prepare(VFIOPCIDevice *vdev, int nr)
{
VFIOBAR *bar = &vdev->bars[nr];
uint32_t pci_bar;
- uint8_t type;
int ret;
/* Skip both unimplemented BARs and the upper half of 64bit BARS. */
pci_bar = le32_to_cpu(pci_bar);
bar->ioport = (pci_bar & PCI_BASE_ADDRESS_SPACE_IO);
bar->mem64 = bar->ioport ? 0 : (pci_bar & PCI_BASE_ADDRESS_MEM_TYPE_64);
- type = pci_bar & (bar->ioport ? ~PCI_BASE_ADDRESS_IO_MASK :
- ~PCI_BASE_ADDRESS_MEM_MASK);
+ bar->type = pci_bar & (bar->ioport ? ~PCI_BASE_ADDRESS_IO_MASK :
+ ~PCI_BASE_ADDRESS_MEM_MASK);
+ bar->size = bar->region.size;
+}
+
+static void vfio_bars_prepare(VFIOPCIDevice *vdev)
+{
+ int i;
- if (vfio_region_mmap(&bar->region)) {
- error_report("Failed to mmap %s BAR %d. Performance may be slow",
- vdev->vbasedev.name, nr);
+ for (i = 0; i < PCI_ROM_SLOT; i++) {
+ vfio_bar_prepare(vdev, i);
}
+}
- pci_register_bar(&vdev->pdev, nr, type, bar->region.mem);
+static void vfio_bar_register(VFIOPCIDevice *vdev, int nr)
+{
+ VFIOBAR *bar = &vdev->bars[nr];
+ char *name;
+
+ if (!bar->size) {
+ return;
+ }
+
+ bar->mr = g_new0(MemoryRegion, 1);
+ name = g_strdup_printf("%s base BAR %d", vdev->vbasedev.name, nr);
+ memory_region_init_io(bar->mr, OBJECT(vdev), NULL, NULL, name, bar->size);
+ g_free(name);
+
+ if (bar->region.size) {
+ memory_region_add_subregion(bar->mr, 0, bar->region.mem);
+
+ if (vfio_region_mmap(&bar->region)) {
+ error_report("Failed to mmap %s BAR %d. Performance may be slow",
+ vdev->vbasedev.name, nr);
+ }
+ }
+
+ pci_register_bar(&vdev->pdev, nr, bar->type, bar->mr);
}
-static void vfio_bars_setup(VFIOPCIDevice *vdev)
+static void vfio_bars_register(VFIOPCIDevice *vdev)
{
int i;
for (i = 0; i < PCI_ROM_SLOT; i++) {
- vfio_bar_setup(vdev, i);
+ vfio_bar_register(vdev, i);
}
}
int i;
for (i = 0; i < PCI_ROM_SLOT; i++) {
+ VFIOBAR *bar = &vdev->bars[i];
+
vfio_bar_quirk_exit(vdev, i);
- vfio_region_exit(&vdev->bars[i].region);
+ vfio_region_exit(&bar->region);
+ if (bar->region.size) {
+ memory_region_del_subregion(bar->mr, bar->region.mem);
+ }
}
if (vdev->vga) {
int i;
for (i = 0; i < PCI_ROM_SLOT; i++) {
+ VFIOBAR *bar = &vdev->bars[i];
+
vfio_bar_quirk_finalize(vdev, i);
- vfio_region_finalize(&vdev->bars[i].region);
+ vfio_region_finalize(&bar->region);
+ if (bar->size) {
+ object_unparent(OBJECT(bar->mr));
+ g_free(bar->mr);
+ }
}
if (vdev->vga) {
PCI_EXP_TYPE_ENDPOINT << 4,
PCI_EXP_FLAGS_TYPE);
vfio_add_emulated_long(vdev, pos + PCI_EXP_LNKCAP,
- PCI_EXP_LNK_MLW_1 | PCI_EXP_LNK_LS_25, ~0);
+ QEMU_PCI_EXP_LNKCAP_MLW(QEMU_PCI_EXP_LNK_X1) |
+ QEMU_PCI_EXP_LNKCAP_MLS(QEMU_PCI_EXP_LNK_2_5GT), ~0);
vfio_add_emulated_word(vdev, pos + PCI_EXP_LNKCTL, 0, ~0);
}
-
- /* Mark the Link Status bits as emulated to allow virtual negotiation */
- vfio_add_emulated_word(vdev, pos + PCI_EXP_LNKSTA,
- pci_get_word(vdev->pdev.config + pos +
- PCI_EXP_LNKSTA),
- PCI_EXP_LNKCAP_MLW | PCI_EXP_LNKCAP_SLS);
}
/*
vfio_intx_enable(vdev, &err);
if (err) {
- error_reportf_err(err, ERR_PREFIX, vdev->vbasedev.name);
+ error_reportf_err(err, VFIO_MSG_PREFIX, vdev->vbasedev.name);
}
for (nr = 0; nr < PCI_NUM_REGIONS - 1; ++nr) {
vdev->vbasedev.name, nr);
}
}
+
+ vfio_quirk_reset(vdev);
}
static bool vfio_pci_host_match(PCIHostDeviceAddress *addr, const char *name)
ret = ioctl(vdev->vbasedev.fd, VFIO_DEVICE_GET_IRQ_INFO, &irq_info);
if (ret) {
/* This can fail for an old kernel or legacy PCI dev */
- trace_vfio_populate_device_get_irq_info_failure();
+ trace_vfio_populate_device_get_irq_info_failure(strerror(errno));
} else if (irq_info.count == 1) {
vdev->pci_aer = true;
} else {
- error_report(WARN_PREFIX
- "Could not enable error recovery for the device",
- vbasedev->name);
+ warn_report(VFIO_MSG_PREFIX
+ "Could not enable error recovery for the device",
+ vbasedev->name);
}
}
qdev_unplug(&vdev->pdev.qdev, &err);
if (err) {
- error_reportf_err(err, WARN_PREFIX, vdev->vbasedev.name);
+ warn_reportf_err(err, VFIO_MSG_PREFIX, vdev->vbasedev.name);
}
}
static void vfio_realize(PCIDevice *pdev, Error **errp)
{
- VFIOPCIDevice *vdev = DO_UPCAST(VFIOPCIDevice, pdev, pdev);
+ VFIOPCIDevice *vdev = PCI_VFIO(pdev);
VFIODevice *vbasedev_iter;
VFIOGroup *group;
- char *tmp, group_path[PATH_MAX], *group_name;
+ char *tmp, *subsys, group_path[PATH_MAX], *group_name;
Error *err = NULL;
ssize_t len;
struct stat st;
int groupid;
int i, ret;
+ bool is_mdev;
if (!vdev->vbasedev.sysfsdev) {
if (!(~vdev->host.domain || ~vdev->host.bus ||
if (stat(vdev->vbasedev.sysfsdev, &st) < 0) {
error_setg_errno(errp, errno, "no such host device");
- error_prepend(errp, ERR_PREFIX, vdev->vbasedev.sysfsdev);
+ error_prepend(errp, VFIO_MSG_PREFIX, vdev->vbasedev.sysfsdev);
return;
}
- vdev->vbasedev.name = g_strdup(basename(vdev->vbasedev.sysfsdev));
+ vdev->vbasedev.name = g_path_get_basename(vdev->vbasedev.sysfsdev);
vdev->vbasedev.ops = &vfio_pci_ops;
vdev->vbasedev.type = VFIO_DEVICE_TYPE_PCI;
vdev->vbasedev.dev = &vdev->pdev.qdev;
}
}
+ /*
+ * Mediated devices *might* operate compatibly with memory ballooning, but
+ * we cannot know for certain, it depends on whether the mdev vendor driver
+ * stays in sync with the active working set of the guest driver. Prevent
+ * the x-balloon-allowed option unless this is minimally an mdev device.
+ */
+ tmp = g_strdup_printf("%s/subsystem", vdev->vbasedev.sysfsdev);
+ subsys = realpath(tmp, NULL);
+ g_free(tmp);
+ is_mdev = subsys && (strcmp(subsys, "/sys/bus/mdev") == 0);
+ free(subsys);
+
+ trace_vfio_mdev(vdev->vbasedev.name, is_mdev);
+
+ if (vdev->vbasedev.balloon_allowed && !is_mdev) {
+ error_setg(errp, "x-balloon-allowed only potentially compatible "
+ "with mdev devices");
+ vfio_put_group(group);
+ goto error;
+ }
+
ret = vfio_get_device(group, vdev->vbasedev.name, &vdev->vbasedev, errp);
if (ret) {
vfio_put_group(group);
/* QEMU can choose to expose the ROM or not */
memset(vdev->emulated_config_bits + PCI_ROM_ADDRESS, 0xff, 4);
+ /* QEMU can also add or extend BARs */
+ memset(vdev->emulated_config_bits + PCI_BASE_ADDRESS_0, 0xff, 6 * 4);
/*
* The PCI spec reserves vendor ID 0xffff as an invalid value. The
vfio_pci_size_rom(vdev);
+ vfio_bars_prepare(vdev);
+
vfio_msix_early_setup(vdev, &err);
if (err) {
error_propagate(errp, err);
goto error;
}
- vfio_bars_setup(vdev);
+ vfio_bars_register(vdev);
ret = vfio_add_capabilities(vdev, errp);
if (ret) {
}
}
+ if (vdev->display != ON_OFF_AUTO_OFF) {
+ ret = vfio_display_probe(vdev, errp);
+ if (ret) {
+ goto out_teardown;
+ }
+ }
+ if (vdev->enable_ramfb && vdev->dpy == NULL) {
+ error_setg(errp, "ramfb=on requires display=on");
+ goto out_teardown;
+ }
+
vfio_register_err_notifier(vdev);
vfio_register_req_notifier(vdev);
vfio_setup_resetfn_quirk(vdev);
vfio_teardown_msi(vdev);
vfio_bars_exit(vdev);
error:
- error_prepend(errp, ERR_PREFIX, vdev->vbasedev.name);
+ error_prepend(errp, VFIO_MSG_PREFIX, vdev->vbasedev.name);
}
static void vfio_instance_finalize(Object *obj)
{
- PCIDevice *pci_dev = PCI_DEVICE(obj);
- VFIOPCIDevice *vdev = DO_UPCAST(VFIOPCIDevice, pdev, pci_dev);
+ VFIOPCIDevice *vdev = PCI_VFIO(obj);
VFIOGroup *group = vdev->vbasedev.group;
+ vfio_display_finalize(vdev);
vfio_bars_finalize(vdev);
g_free(vdev->emulated_config_bits);
g_free(vdev->rom);
static void vfio_exitfn(PCIDevice *pdev)
{
- VFIOPCIDevice *vdev = DO_UPCAST(VFIOPCIDevice, pdev, pdev);
+ VFIOPCIDevice *vdev = PCI_VFIO(pdev);
vfio_unregister_req_notifier(vdev);
vfio_unregister_err_notifier(vdev);
static void vfio_pci_reset(DeviceState *dev)
{
- PCIDevice *pdev = DO_UPCAST(PCIDevice, qdev, dev);
- VFIOPCIDevice *vdev = DO_UPCAST(VFIOPCIDevice, pdev, pdev);
+ VFIOPCIDevice *vdev = PCI_VFIO(dev);
trace_vfio_pci_reset(vdev->vbasedev.name);
vfio_pci_pre_reset(vdev);
+ if (vdev->display != ON_OFF_AUTO_OFF) {
+ vfio_display_reset(vdev);
+ }
+
if (vdev->resetfn && !vdev->resetfn(vdev)) {
goto post_reset;
}
static void vfio_instance_init(Object *obj)
{
PCIDevice *pci_dev = PCI_DEVICE(obj);
- VFIOPCIDevice *vdev = DO_UPCAST(VFIOPCIDevice, pdev, PCI_DEVICE(obj));
+ VFIOPCIDevice *vdev = PCI_VFIO(obj);
device_add_bootindex_property(obj, &vdev->bootindex,
"bootindex", NULL,
vdev->host.function = ~0U;
vdev->nv_gpudirect_clique = 0xFF;
+
+ /* QEMU_PCI_CAP_EXPRESS initialization does not depend on QEMU command
+ * line, therefore, no need to wait to realize like other devices */
+ pci_dev->cap_present |= QEMU_PCI_CAP_EXPRESS;
}
static Property vfio_pci_dev_properties[] = {
DEFINE_PROP_PCI_HOST_DEVADDR("host", VFIOPCIDevice, host),
DEFINE_PROP_STRING("sysfsdev", VFIOPCIDevice, vbasedev.sysfsdev),
+ DEFINE_PROP_ON_OFF_AUTO("display", VFIOPCIDevice,
+ display, ON_OFF_AUTO_OFF),
DEFINE_PROP_UINT32("x-intx-mmap-timeout-ms", VFIOPCIDevice,
intx.mmap_timeout, 1100),
DEFINE_PROP_BIT("x-vga", VFIOPCIDevice, features,
DEFINE_PROP_BIT("x-igd-opregion", VFIOPCIDevice, features,
VFIO_FEATURE_ENABLE_IGD_OPREGION_BIT, false),
DEFINE_PROP_BOOL("x-no-mmap", VFIOPCIDevice, vbasedev.no_mmap, false),
+ DEFINE_PROP_BOOL("x-balloon-allowed", VFIOPCIDevice,
+ vbasedev.balloon_allowed, false),
DEFINE_PROP_BOOL("x-no-kvm-intx", VFIOPCIDevice, no_kvm_intx, false),
DEFINE_PROP_BOOL("x-no-kvm-msi", VFIOPCIDevice, no_kvm_msi, false),
DEFINE_PROP_BOOL("x-no-kvm-msix", VFIOPCIDevice, no_kvm_msix, false),
+ DEFINE_PROP_BOOL("x-no-geforce-quirks", VFIOPCIDevice,
+ no_geforce_quirks, false),
+ DEFINE_PROP_BOOL("x-no-kvm-ioeventfd", VFIOPCIDevice, no_kvm_ioeventfd,
+ false),
+ DEFINE_PROP_BOOL("x-no-vfio-ioeventfd", VFIOPCIDevice, no_vfio_ioeventfd,
+ false),
DEFINE_PROP_UINT32("x-pci-vendor-id", VFIOPCIDevice, vendor_id, PCI_ANY_ID),
DEFINE_PROP_UINT32("x-pci-device-id", VFIOPCIDevice, device_id, PCI_ANY_ID),
DEFINE_PROP_UINT32("x-pci-sub-vendor-id", VFIOPCIDevice,
DEFINE_PROP_UNSIGNED_NODEFAULT("x-nv-gpudirect-clique", VFIOPCIDevice,
nv_gpudirect_clique,
qdev_prop_nv_gpudirect_clique, uint8_t),
+ DEFINE_PROP_OFF_AUTO_PCIBAR("x-msix-relocation", VFIOPCIDevice, msix_relo,
+ OFF_AUTOPCIBAR_OFF),
/*
* TODO - support passed fds... is this necessary?
* DEFINE_PROP_STRING("vfiofd", VFIOPCIDevice, vfiofd_name),
pdc->exit = vfio_exitfn;
pdc->config_read = vfio_pci_read_config;
pdc->config_write = vfio_pci_write_config;
- pdc->is_express = 1; /* We might be */
}
static const TypeInfo vfio_pci_dev_info = {
- .name = "vfio-pci",
+ .name = TYPE_VFIO_PCI,
.parent = TYPE_PCI_DEVICE,
.instance_size = sizeof(VFIOPCIDevice),
.class_init = vfio_pci_dev_class_init,
},
};
+static Property vfio_pci_dev_nohotplug_properties[] = {
+ DEFINE_PROP_BOOL("ramfb", VFIOPCIDevice, enable_ramfb, false),
+ DEFINE_PROP_END_OF_LIST(),
+};
+
+static void vfio_pci_nohotplug_dev_class_init(ObjectClass *klass, void *data)
+{
+ DeviceClass *dc = DEVICE_CLASS(klass);
+
+ dc->props = vfio_pci_dev_nohotplug_properties;
+ dc->hotpluggable = false;
+}
+
+static const TypeInfo vfio_pci_nohotplug_dev_info = {
+ .name = "vfio-pci-nohotplug",
+ .parent = "vfio-pci",
+ .instance_size = sizeof(VFIOPCIDevice),
+ .class_init = vfio_pci_nohotplug_dev_class_init,
+};
+
static void register_vfio_pci_dev_type(void)
{
type_register_static(&vfio_pci_dev_info);
+ type_register_static(&vfio_pci_nohotplug_dev_info);
}
type_init(register_vfio_pci_dev_type)