aboutsummaryrefslogtreecommitdiff
path: root/hw/vfio/pci.c
diff options
context:
space:
mode:
Diffstat (limited to 'hw/vfio/pci.c')
-rw-r--r--hw/vfio/pci.c279
1 files changed, 157 insertions, 122 deletions
diff --git a/hw/vfio/pci.c b/hw/vfio/pci.c
index a5a620a0c4..65d30fdef9 100644
--- a/hw/vfio/pci.c
+++ b/hw/vfio/pci.c
@@ -100,7 +100,7 @@ static void vfio_intx_eoi(VFIODevice *vbasedev)
vfio_unmask_single_irqindex(vbasedev, VFIO_PCI_INTX_IRQ_INDEX);
}
-static void vfio_intx_enable_kvm(VFIOPCIDevice *vdev)
+static void vfio_intx_enable_kvm(VFIOPCIDevice *vdev, Error **errp)
{
#ifdef CONFIG_KVM
struct kvm_irqfd irqfd = {
@@ -126,7 +126,7 @@ static void vfio_intx_enable_kvm(VFIOPCIDevice *vdev)
/* Get an eventfd for resample/unmask */
if (event_notifier_init(&vdev->intx.unmask, 0)) {
- error_report("vfio: Error: event_notifier_init failed eoi");
+ error_setg(errp, "event_notifier_init failed eoi");
goto fail;
}
@@ -134,7 +134,7 @@ static void vfio_intx_enable_kvm(VFIOPCIDevice *vdev)
irqfd.resamplefd = event_notifier_get_fd(&vdev->intx.unmask);
if (kvm_vm_ioctl(kvm_state, KVM_IRQFD, &irqfd)) {
- error_report("vfio: Error: Failed to setup resample irqfd: %m");
+ error_setg_errno(errp, errno, "failed to setup resample irqfd");
goto fail_irqfd;
}
@@ -153,7 +153,7 @@ static void vfio_intx_enable_kvm(VFIOPCIDevice *vdev)
ret = ioctl(vdev->vbasedev.fd, VFIO_DEVICE_SET_IRQS, irq_set);
g_free(irq_set);
if (ret) {
- error_report("vfio: Error: Failed to setup INTx unmask fd: %m");
+ error_setg_errno(errp, -ret, "failed to setup INTx unmask fd");
goto fail_vfio;
}
@@ -222,6 +222,7 @@ static void vfio_intx_update(PCIDevice *pdev)
{
VFIOPCIDevice *vdev = DO_UPCAST(VFIOPCIDevice, pdev, pdev);
PCIINTxRoute route;
+ Error *err = NULL;
if (vdev->interrupt != VFIO_INT_INTx) {
return;
@@ -244,18 +245,22 @@ static void vfio_intx_update(PCIDevice *pdev)
return;
}
- vfio_intx_enable_kvm(vdev);
+ vfio_intx_enable_kvm(vdev, &err);
+ if (err) {
+ error_reportf_err(err, WARN_PREFIX, vdev->vbasedev.name);
+ }
/* Re-enable the interrupt in cased we missed an EOI */
vfio_intx_eoi(&vdev->vbasedev);
}
-static int vfio_intx_enable(VFIOPCIDevice *vdev)
+static int vfio_intx_enable(VFIOPCIDevice *vdev, Error **errp)
{
uint8_t pin = vfio_pci_read_config(&vdev->pdev, PCI_INTERRUPT_PIN, 1);
int ret, argsz;
struct vfio_irq_set *irq_set;
int32_t *pfd;
+ Error *err = NULL;
if (!pin) {
return 0;
@@ -279,7 +284,7 @@ static int vfio_intx_enable(VFIOPCIDevice *vdev)
ret = event_notifier_init(&vdev->intx.interrupt, 0);
if (ret) {
- error_report("vfio: Error: event_notifier_init failed");
+ error_setg_errno(errp, -ret, "event_notifier_init failed");
return ret;
}
@@ -299,13 +304,16 @@ static int vfio_intx_enable(VFIOPCIDevice *vdev)
ret = ioctl(vdev->vbasedev.fd, VFIO_DEVICE_SET_IRQS, irq_set);
g_free(irq_set);
if (ret) {
- error_report("vfio: Error: Failed to setup INTx fd: %m");
+ error_setg_errno(errp, -ret, "failed to setup INTx fd");
qemu_set_fd_handler(*pfd, NULL, NULL, vdev);
event_notifier_cleanup(&vdev->intx.interrupt);
return -errno;
}
- vfio_intx_enable_kvm(vdev);
+ vfio_intx_enable_kvm(vdev, &err);
+ if (err) {
+ error_reportf_err(err, WARN_PREFIX, vdev->vbasedev.name);
+ }
vdev->interrupt = VFIO_INT_INTx;
@@ -707,6 +715,7 @@ retry:
static void vfio_msi_disable_common(VFIOPCIDevice *vdev)
{
+ Error *err = NULL;
int i;
for (i = 0; i < vdev->nr_vectors; i++) {
@@ -726,7 +735,10 @@ static void vfio_msi_disable_common(VFIOPCIDevice *vdev)
vdev->nr_vectors = 0;
vdev->interrupt = VFIO_INT_NONE;
- vfio_intx_enable(vdev);
+ vfio_intx_enable(vdev, &err);
+ if (err) {
+ error_reportf_err(err, ERR_PREFIX, vdev->vbasedev.name);
+ }
}
static void vfio_msix_disable(VFIOPCIDevice *vdev)
@@ -1168,7 +1180,7 @@ static void vfio_disable_interrupts(VFIOPCIDevice *vdev)
}
}
-static int vfio_msi_setup(VFIOPCIDevice *vdev, int pos)
+static int vfio_msi_setup(VFIOPCIDevice *vdev, int pos, Error **errp)
{
uint16_t ctrl;
bool msi_64bit, msi_maskbit;
@@ -1177,6 +1189,7 @@ static int vfio_msi_setup(VFIOPCIDevice *vdev, int pos)
if (pread(vdev->vbasedev.fd, &ctrl, sizeof(ctrl),
vdev->config_offset + pos + PCI_CAP_FLAGS) != sizeof(ctrl)) {
+ error_setg_errno(errp, errno, "failed reading MSI PCI_CAP_FLAGS");
return -errno;
}
ctrl = le16_to_cpu(ctrl);
@@ -1192,8 +1205,8 @@ static int vfio_msi_setup(VFIOPCIDevice *vdev, int pos)
if (ret == -ENOTSUP) {
return 0;
}
- error_prepend(&err, "vfio: msi_init failed: ");
- error_report_err(err);
+ error_prepend(&err, "msi_init failed: ");
+ error_propagate(errp, err);
return ret;
}
vdev->msi_cap_size = 0xa + (msi_maskbit ? 0xa : 0) + (msi_64bit ? 0x4 : 0);
@@ -1277,7 +1290,7 @@ static void vfio_pci_fixup_msix_region(VFIOPCIDevice *vdev)
* need to first look for where the MSI-X table lives. So we
* unfortunately split MSI-X setup across two functions.
*/
-static int vfio_msix_early_setup(VFIOPCIDevice *vdev)
+static void vfio_msix_early_setup(VFIOPCIDevice *vdev, Error **errp)
{
uint8_t pos;
uint16_t ctrl;
@@ -1287,22 +1300,25 @@ static int vfio_msix_early_setup(VFIOPCIDevice *vdev)
pos = pci_find_capability(&vdev->pdev, PCI_CAP_ID_MSIX);
if (!pos) {
- return 0;
+ return;
}
if (pread(fd, &ctrl, sizeof(ctrl),
vdev->config_offset + pos + PCI_MSIX_FLAGS) != sizeof(ctrl)) {
- return -errno;
+ error_setg_errno(errp, errno, "failed to read PCI MSIX FLAGS");
+ return;
}
if (pread(fd, &table, sizeof(table),
vdev->config_offset + pos + PCI_MSIX_TABLE) != sizeof(table)) {
- return -errno;
+ error_setg_errno(errp, errno, "failed to read PCI MSIX TABLE");
+ return;
}
if (pread(fd, &pba, sizeof(pba),
vdev->config_offset + pos + PCI_MSIX_PBA) != sizeof(pba)) {
- return -errno;
+ error_setg_errno(errp, errno, "failed to read PCI MSIX PBA");
+ return;
}
ctrl = le16_to_cpu(ctrl);
@@ -1332,10 +1348,10 @@ static int vfio_msix_early_setup(VFIOPCIDevice *vdev)
(vdev->device_id & 0xff00) == 0x5800) {
msix->pba_offset = 0x1000;
} else {
- error_report("vfio: Hardware reports invalid configuration, "
- "MSIX PBA outside of specified BAR");
+ error_setg(errp, "hardware reports invalid configuration, "
+ "MSIX PBA outside of specified BAR");
g_free(msix);
- return -EINVAL;
+ return;
}
}
@@ -1344,11 +1360,9 @@ static int vfio_msix_early_setup(VFIOPCIDevice *vdev)
vdev->msix = msix;
vfio_pci_fixup_msix_region(vdev);
-
- return 0;
}
-static int vfio_msix_setup(VFIOPCIDevice *vdev, int pos)
+static int vfio_msix_setup(VFIOPCIDevice *vdev, int pos, Error **errp)
{
int ret;
@@ -1363,7 +1377,7 @@ static int vfio_msix_setup(VFIOPCIDevice *vdev, int pos)
if (ret == -ENOTSUP) {
return 0;
}
- error_report("vfio: msix_init failed");
+ error_setg(errp, "msix_init failed");
return ret;
}
@@ -1548,7 +1562,8 @@ static void vfio_add_emulated_long(VFIOPCIDevice *vdev, int pos,
vfio_set_long_bits(vdev->emulated_config_bits + pos, mask, mask);
}
-static int vfio_setup_pcie_cap(VFIOPCIDevice *vdev, int pos, uint8_t size)
+static int vfio_setup_pcie_cap(VFIOPCIDevice *vdev, int pos, uint8_t size,
+ Error **errp)
{
uint16_t flags;
uint8_t type;
@@ -1560,8 +1575,8 @@ static int vfio_setup_pcie_cap(VFIOPCIDevice *vdev, int pos, uint8_t size)
type != PCI_EXP_TYPE_LEG_END &&
type != PCI_EXP_TYPE_RC_END) {
- error_report("vfio: Assignment of PCIe type 0x%x "
- "devices is not currently supported", type);
+ error_setg(errp, "assignment of PCIe type 0x%x "
+ "devices is not currently supported", type);
return -EINVAL;
}
@@ -1695,7 +1710,7 @@ static void vfio_check_af_flr(VFIOPCIDevice *vdev, uint8_t pos)
}
}
-static int vfio_add_std_cap(VFIOPCIDevice *vdev, uint8_t pos)
+static int vfio_add_std_cap(VFIOPCIDevice *vdev, uint8_t pos, Error **errp)
{
PCIDevice *pdev = &vdev->pdev;
uint8_t cap_id, next, size;
@@ -1720,9 +1735,9 @@ static int vfio_add_std_cap(VFIOPCIDevice *vdev, uint8_t pos)
* will be changed as we unwind the stack.
*/
if (next) {
- ret = vfio_add_std_cap(vdev, next);
+ ret = vfio_add_std_cap(vdev, next, errp);
if (ret) {
- return ret;
+ goto out;
}
} else {
/* Begin the rebuild, use QEMU emulated list bits */
@@ -1736,40 +1751,40 @@ static int vfio_add_std_cap(VFIOPCIDevice *vdev, uint8_t pos)
switch (cap_id) {
case PCI_CAP_ID_MSI:
- ret = vfio_msi_setup(vdev, pos);
+ ret = vfio_msi_setup(vdev, pos, errp);
break;
case PCI_CAP_ID_EXP:
vfio_check_pcie_flr(vdev, pos);
- ret = vfio_setup_pcie_cap(vdev, pos, size);
+ ret = vfio_setup_pcie_cap(vdev, pos, size, errp);
break;
case PCI_CAP_ID_MSIX:
- ret = vfio_msix_setup(vdev, pos);
+ ret = vfio_msix_setup(vdev, pos, errp);
break;
case PCI_CAP_ID_PM:
vfio_check_pm_reset(vdev, pos);
vdev->pm_cap = pos;
- ret = pci_add_capability(pdev, cap_id, pos, size);
+ ret = pci_add_capability2(pdev, cap_id, pos, size, errp);
break;
case PCI_CAP_ID_AF:
vfio_check_af_flr(vdev, pos);
- ret = pci_add_capability(pdev, cap_id, pos, size);
+ ret = pci_add_capability2(pdev, cap_id, pos, size, errp);
break;
default:
- ret = pci_add_capability(pdev, cap_id, pos, size);
+ ret = pci_add_capability2(pdev, cap_id, pos, size, errp);
break;
}
-
+out:
if (ret < 0) {
- error_report("vfio: %s Error adding PCI capability "
- "0x%x[0x%x]@0x%x: %d", vdev->vbasedev.name,
- cap_id, size, pos, ret);
+ error_prepend(errp,
+ "failed to add PCI capability 0x%x[0x%x]@0x%x: ",
+ cap_id, size, pos);
return ret;
}
return 0;
}
-static int vfio_add_ext_cap(VFIOPCIDevice *vdev)
+static void vfio_add_ext_cap(VFIOPCIDevice *vdev)
{
PCIDevice *pdev = &vdev->pdev;
uint32_t header;
@@ -1780,7 +1795,7 @@ static int vfio_add_ext_cap(VFIOPCIDevice *vdev)
/* Only add extended caps if we have them and the guest can see them */
if (!pci_is_express(pdev) || !pci_bus_is_express(pdev->bus) ||
!pci_get_long(pdev->config + PCI_CONFIG_SPACE_SIZE)) {
- return 0;
+ return;
}
/*
@@ -1845,10 +1860,10 @@ static int vfio_add_ext_cap(VFIOPCIDevice *vdev)
}
g_free(config);
- return 0;
+ return;
}
-static int vfio_add_capabilities(VFIOPCIDevice *vdev)
+static int vfio_add_capabilities(VFIOPCIDevice *vdev, Error **errp)
{
PCIDevice *pdev = &vdev->pdev;
int ret;
@@ -1858,12 +1873,13 @@ static int vfio_add_capabilities(VFIOPCIDevice *vdev)
return 0; /* Nothing to add */
}
- ret = vfio_add_std_cap(vdev, pdev->config[PCI_CAPABILITY_LIST]);
+ ret = vfio_add_std_cap(vdev, pdev->config[PCI_CAPABILITY_LIST], errp);
if (ret) {
return ret;
}
- return vfio_add_ext_cap(vdev);
+ vfio_add_ext_cap(vdev);
+ return 0;
}
static void vfio_pci_pre_reset(VFIOPCIDevice *vdev)
@@ -1905,7 +1921,12 @@ static void vfio_pci_pre_reset(VFIOPCIDevice *vdev)
static void vfio_pci_post_reset(VFIOPCIDevice *vdev)
{
- vfio_intx_enable(vdev);
+ Error *err = NULL;
+
+ vfio_intx_enable(vdev, &err);
+ if (err) {
+ error_reportf_err(err, ERR_PREFIX, vdev->vbasedev.name);
+ }
}
static bool vfio_pci_host_match(PCIHostDeviceAddress *addr, const char *name)
@@ -1930,7 +1951,9 @@ static int vfio_pci_hot_reset(VFIOPCIDevice *vdev, bool single)
trace_vfio_pci_hot_reset(vdev->vbasedev.name, single ? "one" : "multi");
- vfio_pci_pre_reset(vdev);
+ if (!single) {
+ vfio_pci_pre_reset(vdev);
+ }
vdev->vbasedev.needs_reset = false;
info = g_malloc0(sizeof(*info));
@@ -2088,7 +2111,9 @@ out:
}
}
out_single:
- vfio_pci_post_reset(vdev);
+ if (!single) {
+ vfio_pci_post_reset(vdev);
+ }
g_free(info);
return ret;
@@ -2134,7 +2159,7 @@ static VFIODeviceOps vfio_pci_ops = {
.vfio_eoi = vfio_intx_eoi,
};
-int vfio_populate_vga(VFIOPCIDevice *vdev)
+int vfio_populate_vga(VFIOPCIDevice *vdev, Error **errp)
{
VFIODevice *vbasedev = &vdev->vbasedev;
struct vfio_region_info *reg_info;
@@ -2142,15 +2167,18 @@ int vfio_populate_vga(VFIOPCIDevice *vdev)
ret = vfio_get_region_info(vbasedev, VFIO_PCI_VGA_REGION_INDEX, &reg_info);
if (ret) {
+ error_setg_errno(errp, -ret,
+ "failed getting region info for VGA region index %d",
+ VFIO_PCI_VGA_REGION_INDEX);
return ret;
}
if (!(reg_info->flags & VFIO_REGION_INFO_FLAG_READ) ||
!(reg_info->flags & VFIO_REGION_INFO_FLAG_WRITE) ||
reg_info->size < 0xbffff + 1) {
- error_report("vfio: Unexpected VGA info, flags 0x%lx, size 0x%lx",
- (unsigned long)reg_info->flags,
- (unsigned long)reg_info->size);
+ error_setg(errp, "unexpected VGA info, flags 0x%lx, size 0x%lx",
+ (unsigned long)reg_info->flags,
+ (unsigned long)reg_info->size);
g_free(reg_info);
return -EINVAL;
}
@@ -2199,7 +2227,7 @@ int vfio_populate_vga(VFIOPCIDevice *vdev)
return 0;
}
-static int vfio_populate_device(VFIOPCIDevice *vdev)
+static void vfio_populate_device(VFIOPCIDevice *vdev, Error **errp)
{
VFIODevice *vbasedev = &vdev->vbasedev;
struct vfio_region_info *reg_info;
@@ -2208,19 +2236,19 @@ static int vfio_populate_device(VFIOPCIDevice *vdev)
/* Sanity check device */
if (!(vbasedev->flags & VFIO_DEVICE_FLAGS_PCI)) {
- error_report("vfio: Um, this isn't a PCI device");
- goto error;
+ error_setg(errp, "this isn't a PCI device");
+ return;
}
if (vbasedev->num_regions < VFIO_PCI_CONFIG_REGION_INDEX + 1) {
- error_report("vfio: unexpected number of io regions %u",
- vbasedev->num_regions);
- goto error;
+ error_setg(errp, "unexpected number of io regions %u",
+ vbasedev->num_regions);
+ return;
}
if (vbasedev->num_irqs < VFIO_PCI_MSIX_IRQ_INDEX + 1) {
- error_report("vfio: unexpected number of irqs %u", vbasedev->num_irqs);
- goto error;
+ error_setg(errp, "unexpected number of irqs %u", vbasedev->num_irqs);
+ return;
}
for (i = VFIO_PCI_BAR0_REGION_INDEX; i < VFIO_PCI_ROM_REGION_INDEX; i++) {
@@ -2231,8 +2259,8 @@ static int vfio_populate_device(VFIOPCIDevice *vdev)
g_free(name);
if (ret) {
- error_report("vfio: Error getting region %d info: %m", i);
- goto error;
+ error_setg_errno(errp, -ret, "failed to get region %d info", i);
+ return;
}
QLIST_INIT(&vdev->bars[i].quirks);
@@ -2241,8 +2269,8 @@ static int vfio_populate_device(VFIOPCIDevice *vdev)
ret = vfio_get_region_info(vbasedev,
VFIO_PCI_CONFIG_REGION_INDEX, &reg_info);
if (ret) {
- error_report("vfio: Error getting config info: %m");
- goto error;
+ error_setg_errno(errp, -ret, "failed to get config info");
+ return;
}
trace_vfio_populate_device_config(vdev->vbasedev.name,
@@ -2259,11 +2287,11 @@ static int vfio_populate_device(VFIOPCIDevice *vdev)
g_free(reg_info);
if (vdev->features & VFIO_FEATURE_ENABLE_VGA) {
- ret = vfio_populate_vga(vdev);
+ ret = vfio_populate_vga(vdev, errp);
if (ret) {
- error_report(
- "vfio: Device does not support requested feature x-vga");
- goto error;
+ error_append_hint(errp, "device does not support "
+ "requested feature x-vga\n");
+ return;
}
}
@@ -2273,17 +2301,13 @@ static int vfio_populate_device(VFIOPCIDevice *vdev)
if (ret) {
/* This can fail for an old kernel or legacy PCI dev */
trace_vfio_populate_device_get_irq_info_failure();
- ret = 0;
} else if (irq_info.count == 1) {
vdev->pci_aer = true;
} else {
- error_report("vfio: %s "
+ error_report(WARN_PREFIX
"Could not enable error recovery for the device",
vbasedev->name);
}
-
-error:
- return ret;
}
static void vfio_put_device(VFIOPCIDevice *vdev)
@@ -2487,18 +2511,26 @@ static void vfio_unregister_req_notifier(VFIOPCIDevice *vdev)
vdev->req_enabled = false;
}
-static int vfio_initfn(PCIDevice *pdev)
+static void vfio_realize(PCIDevice *pdev, Error **errp)
{
VFIOPCIDevice *vdev = DO_UPCAST(VFIOPCIDevice, pdev, pdev);
VFIODevice *vbasedev_iter;
VFIOGroup *group;
char *tmp, group_path[PATH_MAX], *group_name;
+ Error *err = NULL;
ssize_t len;
struct stat st;
int groupid;
int i, ret;
if (!vdev->vbasedev.sysfsdev) {
+ if (!(~vdev->host.domain || ~vdev->host.bus ||
+ ~vdev->host.slot || ~vdev->host.function)) {
+ error_setg(errp, "No provided host device");
+ error_append_hint(errp, "Use -vfio-pci,host=DDDD:BB:DD.F "
+ "or -vfio-pci,sysfsdev=PATH_TO_DEVICE\n");
+ return;
+ }
vdev->vbasedev.sysfsdev =
g_strdup_printf("/sys/bus/pci/devices/%04x:%02x:%02x.%01x",
vdev->host.domain, vdev->host.bus,
@@ -2506,9 +2538,9 @@ static int vfio_initfn(PCIDevice *pdev)
}
if (stat(vdev->vbasedev.sysfsdev, &st) < 0) {
- error_report("vfio: error: no such host device: %s",
- vdev->vbasedev.sysfsdev);
- return -errno;
+ error_setg_errno(errp, errno, "no such host device");
+ error_prepend(errp, ERR_PREFIX, vdev->vbasedev.sysfsdev);
+ return;
}
vdev->vbasedev.name = g_strdup(basename(vdev->vbasedev.sysfsdev));
@@ -2520,45 +2552,44 @@ static int vfio_initfn(PCIDevice *pdev)
g_free(tmp);
if (len <= 0 || len >= sizeof(group_path)) {
- error_report("vfio: error no iommu_group for device");
- return len < 0 ? -errno : -ENAMETOOLONG;
+ error_setg_errno(errp, len < 0 ? errno : ENAMETOOLONG,
+ "no iommu_group found");
+ goto error;
}
group_path[len] = 0;
group_name = basename(group_path);
if (sscanf(group_name, "%d", &groupid) != 1) {
- error_report("vfio: error reading %s: %m", group_path);
- return -errno;
+ error_setg_errno(errp, errno, "failed to read %s", group_path);
+ goto error;
}
- trace_vfio_initfn(vdev->vbasedev.name, groupid);
+ trace_vfio_realize(vdev->vbasedev.name, groupid);
- group = vfio_get_group(groupid, pci_device_iommu_address_space(pdev));
+ group = vfio_get_group(groupid, pci_device_iommu_address_space(pdev), errp);
if (!group) {
- error_report("vfio: failed to get group %d", groupid);
- return -ENOENT;
+ goto error;
}
QLIST_FOREACH(vbasedev_iter, &group->device_list, next) {
if (strcmp(vbasedev_iter->name, vdev->vbasedev.name) == 0) {
- error_report("vfio: error: device %s is already attached",
- vdev->vbasedev.name);
+ error_setg(errp, "device is already attached");
vfio_put_group(group);
- return -EBUSY;
+ goto error;
}
}
- ret = vfio_get_device(group, vdev->vbasedev.name, &vdev->vbasedev);
+ ret = vfio_get_device(group, vdev->vbasedev.name, &vdev->vbasedev, errp);
if (ret) {
- error_report("vfio: failed to get device %s", vdev->vbasedev.name);
vfio_put_group(group);
- return ret;
+ goto error;
}
- ret = vfio_populate_device(vdev);
- if (ret) {
- return ret;
+ vfio_populate_device(vdev, &err);
+ if (err) {
+ error_propagate(errp, err);
+ goto error;
}
/* Get a copy of config space */
@@ -2567,8 +2598,8 @@ static int vfio_initfn(PCIDevice *pdev)
vdev->config_offset);
if (ret < (int)MIN(pci_config_size(&vdev->pdev), vdev->config_size)) {
ret = ret < 0 ? -errno : -EFAULT;
- error_report("vfio: Failed to read device config space");
- return ret;
+ error_setg_errno(errp, -ret, "failed to read device config space");
+ goto error;
}
/* vfio emulates a lot for us, but some bits need extra love */
@@ -2584,8 +2615,8 @@ static int vfio_initfn(PCIDevice *pdev)
*/
if (vdev->vendor_id != PCI_ANY_ID) {
if (vdev->vendor_id >= 0xffff) {
- error_report("vfio: Invalid PCI vendor ID provided");
- return -EINVAL;
+ error_setg(errp, "invalid PCI vendor ID provided");
+ goto error;
}
vfio_add_emulated_word(vdev, PCI_VENDOR_ID, vdev->vendor_id, ~0);
trace_vfio_pci_emulated_vendor_id(vdev->vbasedev.name, vdev->vendor_id);
@@ -2595,8 +2626,8 @@ static int vfio_initfn(PCIDevice *pdev)
if (vdev->device_id != PCI_ANY_ID) {
if (vdev->device_id > 0xffff) {
- error_report("vfio: Invalid PCI device ID provided");
- return -EINVAL;
+ error_setg(errp, "invalid PCI device ID provided");
+ goto error;
}
vfio_add_emulated_word(vdev, PCI_DEVICE_ID, vdev->device_id, ~0);
trace_vfio_pci_emulated_device_id(vdev->vbasedev.name, vdev->device_id);
@@ -2606,8 +2637,8 @@ static int vfio_initfn(PCIDevice *pdev)
if (vdev->sub_vendor_id != PCI_ANY_ID) {
if (vdev->sub_vendor_id > 0xffff) {
- error_report("vfio: Invalid PCI subsystem vendor ID provided");
- return -EINVAL;
+ error_setg(errp, "invalid PCI subsystem vendor ID provided");
+ goto error;
}
vfio_add_emulated_word(vdev, PCI_SUBSYSTEM_VENDOR_ID,
vdev->sub_vendor_id, ~0);
@@ -2617,8 +2648,8 @@ static int vfio_initfn(PCIDevice *pdev)
if (vdev->sub_device_id != PCI_ANY_ID) {
if (vdev->sub_device_id > 0xffff) {
- error_report("vfio: Invalid PCI subsystem device ID provided");
- return -EINVAL;
+ error_setg(errp, "invalid PCI subsystem device ID provided");
+ goto error;
}
vfio_add_emulated_word(vdev, PCI_SUBSYSTEM_ID, vdev->sub_device_id, ~0);
trace_vfio_pci_emulated_sub_device_id(vdev->vbasedev.name,
@@ -2646,14 +2677,15 @@ static int vfio_initfn(PCIDevice *pdev)
vfio_pci_size_rom(vdev);
- ret = vfio_msix_early_setup(vdev);
- if (ret) {
- return ret;
+ vfio_msix_early_setup(vdev, &err);
+ if (err) {
+ error_propagate(errp, err);
+ goto error;
}
vfio_bars_setup(vdev);
- ret = vfio_add_capabilities(vdev);
+ ret = vfio_add_capabilities(vdev, errp);
if (ret) {
goto out_teardown;
}
@@ -2671,9 +2703,9 @@ static int vfio_initfn(PCIDevice *pdev)
struct vfio_region_info *opregion;
if (vdev->pdev.qdev.hotplugged) {
- error_report("Cannot support IGD OpRegion feature on hotplugged "
- "device %s", vdev->vbasedev.name);
- ret = -EINVAL;
+ error_setg(errp,
+ "cannot support IGD OpRegion feature on hotplugged "
+ "device");
goto out_teardown;
}
@@ -2681,16 +2713,14 @@ static int vfio_initfn(PCIDevice *pdev)
VFIO_REGION_TYPE_PCI_VENDOR_TYPE | PCI_VENDOR_ID_INTEL,
VFIO_REGION_SUBTYPE_INTEL_IGD_OPREGION, &opregion);
if (ret) {
- error_report("Device %s does not support requested IGD OpRegion "
- "feature", vdev->vbasedev.name);
+ error_setg_errno(errp, -ret,
+ "does not support requested IGD OpRegion feature");
goto out_teardown;
}
- ret = vfio_pci_igd_opregion_init(vdev, opregion);
+ ret = vfio_pci_igd_opregion_init(vdev, opregion, errp);
g_free(opregion);
if (ret) {
- error_report("Device %s IGD OpRegion initialization failed",
- vdev->vbasedev.name);
goto out_teardown;
}
}
@@ -2710,7 +2740,7 @@ static int vfio_initfn(PCIDevice *pdev)
vdev->intx.mmap_timer = timer_new_ms(QEMU_CLOCK_VIRTUAL,
vfio_intx_mmap_enable, vdev);
pci_device_set_intx_routing_notifier(&vdev->pdev, vfio_intx_update);
- ret = vfio_intx_enable(vdev);
+ ret = vfio_intx_enable(vdev, errp);
if (ret) {
goto out_teardown;
}
@@ -2720,13 +2750,14 @@ static int vfio_initfn(PCIDevice *pdev)
vfio_register_req_notifier(vdev);
vfio_setup_resetfn_quirk(vdev);
- return 0;
+ return;
out_teardown:
pci_device_set_intx_routing_notifier(&vdev->pdev, NULL);
vfio_teardown_msi(vdev);
vfio_bars_exit(vdev);
- return ret;
+error:
+ error_prepend(errp, ERR_PREFIX, vdev->vbasedev.name);
}
static void vfio_instance_finalize(Object *obj)
@@ -2808,6 +2839,10 @@ static void vfio_instance_init(Object *obj)
device_add_bootindex_property(obj, &vdev->bootindex,
"bootindex", NULL,
&pci_dev->qdev, NULL);
+ vdev->host.domain = ~0U;
+ vdev->host.bus = ~0U;
+ vdev->host.slot = ~0U;
+ vdev->host.function = ~0U;
}
static Property vfio_pci_dev_properties[] = {
@@ -2855,7 +2890,7 @@ static void vfio_pci_dev_class_init(ObjectClass *klass, void *data)
dc->vmsd = &vfio_pci_vmstate;
dc->desc = "VFIO-based PCI device assignment";
set_bit(DEVICE_CATEGORY_MISC, dc->categories);
- pdc->init = vfio_initfn;
+ pdc->realize = vfio_realize;
pdc->exit = vfio_exitfn;
pdc->config_read = vfio_pci_read_config;
pdc->config_write = vfio_pci_write_config;