#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);
}
}
*/
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, *region_mr, *base_mr;
PCIIORegion *r;
*/
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);
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);
&err);
if (ret < 0) {
if (ret == -ENOTSUP) {
- error_report_err(err);
+ warn_report_err(err);
return 0;
}
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) {
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;
}
}
}
+ /*
+ * 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);
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_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);
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);
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,
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),
}
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)