Commit 1b0d3845 authored by Peter Maydell's avatar Peter Maydell
Browse files

Merge remote-tracking branch 'remotes/awilliam/tags/vfio-updates-20161017.0' into staging



VFIO updates 2016-10-17

 - Convert to realize & improve error reporting (Eric Auger)
 - RTL quirk bug fix (Thorsten Kohfeldt)
 - Skip duplicate pre/post reset (Cao jin)

# gpg: Signature made Mon 17 Oct 2016 20:42:44 BST
# gpg:                using RSA key 0x239B9B6E3BB08B22
# gpg: Good signature from "Alex Williamson <alex.williamson@redhat.com>"
# gpg:                 aka "Alex Williamson <alex@shazbot.org>"
# gpg:                 aka "Alex Williamson <alwillia@redhat.com>"
# gpg:                 aka "Alex Williamson <alex.l.williamson@gmail.com>"
# Primary key fingerprint: 42F6 C04E 540B D1A9 9E7B  8A90 239B 9B6E 3BB0 8B22

* remotes/awilliam/tags/vfio-updates-20161017.0:
  vfio: fix duplicate function call
  vfio/pci: Fix vfio_rtl8168_quirk_data_read address offset
  vfio/pci: Handle host oversight
  vfio/pci: Remove vfio_populate_device returned value
  vfio/pci: Remove vfio_msix_early_setup returned value
  vfio/pci: Conversion to realize
  vfio/platform: Pass an error object to vfio_base_device_init
  vfio/platform: fix a wrong returned value in vfio_populate_device
  vfio/platform: Pass an error object to vfio_populate_device
  vfio: Pass an error object to vfio_get_device
  vfio: Pass an error object to vfio_get_group
  vfio: Pass an Error object to vfio_connect_container
  vfio/pci: Pass an error object to vfio_pci_igd_opregion_init
  vfio/pci: Pass an error object to vfio_add_capabilities
  vfio/pci: Pass an error object to vfio_intx_enable
  vfio/pci: Pass an error object to vfio_msix_early_setup
  vfio/pci: Pass an error object to vfio_populate_device
  vfio/pci: Pass an error object to vfio_populate_vga
  vfio/pci: Use local error object in vfio_initfn

Signed-off-by: default avatarPeter Maydell <peter.maydell@linaro.org>
parents f525c8a6 893bfc3c
Loading
Loading
Loading
Loading
+40 −29
Original line number Diff line number Diff line
@@ -34,6 +34,7 @@
#include "qemu/range.h"
#include "sysemu/kvm.h"
#include "trace.h"
#include "qapi/error.h"

struct vfio_group_head vfio_group_list =
    QLIST_HEAD_INITIALIZER(vfio_group_list);
@@ -900,7 +901,8 @@ static void vfio_put_address_space(VFIOAddressSpace *space)
    }
}

static int vfio_connect_container(VFIOGroup *group, AddressSpace *as)
static int vfio_connect_container(VFIOGroup *group, AddressSpace *as,
                                  Error **errp)
{
    VFIOContainer *container;
    int ret, fd;
@@ -918,14 +920,14 @@ static int vfio_connect_container(VFIOGroup *group, AddressSpace *as)

    fd = qemu_open("/dev/vfio/vfio", O_RDWR);
    if (fd < 0) {
        error_report("vfio: failed to open /dev/vfio/vfio: %m");
        error_setg_errno(errp, errno, "failed to open /dev/vfio/vfio");
        ret = -errno;
        goto put_space_exit;
    }

    ret = ioctl(fd, VFIO_GET_API_VERSION);
    if (ret != VFIO_API_VERSION) {
        error_report("vfio: supported vfio version: %d, "
        error_setg(errp, "supported vfio version: %d, "
                   "reported version: %d", VFIO_API_VERSION, ret);
        ret = -EINVAL;
        goto close_fd_exit;
@@ -941,7 +943,7 @@ static int vfio_connect_container(VFIOGroup *group, AddressSpace *as)

        ret = ioctl(group->fd, VFIO_GROUP_SET_CONTAINER, &fd);
        if (ret) {
            error_report("vfio: failed to set group container: %m");
            error_setg_errno(errp, errno, "failed to set group container");
            ret = -errno;
            goto free_container_exit;
        }
@@ -949,7 +951,7 @@ static int vfio_connect_container(VFIOGroup *group, AddressSpace *as)
        container->iommu_type = v2 ? VFIO_TYPE1v2_IOMMU : VFIO_TYPE1_IOMMU;
        ret = ioctl(fd, VFIO_SET_IOMMU, container->iommu_type);
        if (ret) {
            error_report("vfio: failed to set iommu for container: %m");
            error_setg_errno(errp, errno, "failed to set iommu for container");
            ret = -errno;
            goto free_container_exit;
        }
@@ -976,7 +978,7 @@ static int vfio_connect_container(VFIOGroup *group, AddressSpace *as)

        ret = ioctl(group->fd, VFIO_GROUP_SET_CONTAINER, &fd);
        if (ret) {
            error_report("vfio: failed to set group container: %m");
            error_setg_errno(errp, errno, "failed to set group container");
            ret = -errno;
            goto free_container_exit;
        }
@@ -984,7 +986,7 @@ static int vfio_connect_container(VFIOGroup *group, AddressSpace *as)
            v2 ? VFIO_SPAPR_TCE_v2_IOMMU : VFIO_SPAPR_TCE_IOMMU;
        ret = ioctl(fd, VFIO_SET_IOMMU, container->iommu_type);
        if (ret) {
            error_report("vfio: failed to set iommu for container: %m");
            error_setg_errno(errp, errno, "failed to set iommu for container");
            ret = -errno;
            goto free_container_exit;
        }
@@ -997,7 +999,7 @@ static int vfio_connect_container(VFIOGroup *group, AddressSpace *as)
        if (!v2) {
            ret = ioctl(fd, VFIO_IOMMU_ENABLE);
            if (ret) {
                error_report("vfio: failed to enable container: %m");
                error_setg_errno(errp, errno, "failed to enable container");
                ret = -errno;
                goto free_container_exit;
            }
@@ -1008,7 +1010,9 @@ static int vfio_connect_container(VFIOGroup *group, AddressSpace *as)
                                     &address_space_memory);
            if (container->error) {
                memory_listener_unregister(&container->prereg_listener);
                error_report("vfio: RAM memory listener initialization failed for container");
                ret = container->error;
                error_setg(errp,
                    "RAM memory listener initialization failed for container");
                goto free_container_exit;
            }
        }
@@ -1016,7 +1020,8 @@ static int vfio_connect_container(VFIOGroup *group, AddressSpace *as)
        info.argsz = sizeof(info);
        ret = ioctl(fd, VFIO_IOMMU_SPAPR_TCE_GET_INFO, &info);
        if (ret) {
            error_report("vfio: VFIO_IOMMU_SPAPR_TCE_GET_INFO failed: %m");
            error_setg_errno(errp, errno,
                             "VFIO_IOMMU_SPAPR_TCE_GET_INFO failed");
            ret = -errno;
            if (v2) {
                memory_listener_unregister(&container->prereg_listener);
@@ -1033,6 +1038,8 @@ static int vfio_connect_container(VFIOGroup *group, AddressSpace *as)
             */
            ret = vfio_spapr_remove_window(container, info.dma32_window_start);
            if (ret) {
                error_setg_errno(errp, -ret,
                                 "failed to remove existing window");
                goto free_container_exit;
            }
        } else {
@@ -1043,7 +1050,7 @@ static int vfio_connect_container(VFIOGroup *group, AddressSpace *as)
                              0x1000);
        }
    } else {
        error_report("vfio: No available IOMMU models");
        error_setg(errp, "No available IOMMU models");
        ret = -EINVAL;
        goto free_container_exit;
    }
@@ -1054,7 +1061,8 @@ static int vfio_connect_container(VFIOGroup *group, AddressSpace *as)

    if (container->error) {
        ret = container->error;
        error_report("vfio: memory listener initialization failed for container");
        error_setg_errno(errp, -ret,
                         "memory listener initialization failed for container");
        goto listener_release_exit;
    }

@@ -1115,7 +1123,7 @@ static void vfio_disconnect_container(VFIOGroup *group)
    }
}

VFIOGroup *vfio_get_group(int groupid, AddressSpace *as)
VFIOGroup *vfio_get_group(int groupid, AddressSpace *as, Error **errp)
{
    VFIOGroup *group;
    char path[32];
@@ -1127,7 +1135,7 @@ VFIOGroup *vfio_get_group(int groupid, AddressSpace *as)
            if (group->container->space->as == as) {
                return group;
            } else {
                error_report("vfio: group %d used in multiple address spaces",
                error_setg(errp, "group %d used in multiple address spaces",
                           group->groupid);
                return NULL;
            }
@@ -1139,27 +1147,29 @@ VFIOGroup *vfio_get_group(int groupid, AddressSpace *as)
    snprintf(path, sizeof(path), "/dev/vfio/%d", groupid);
    group->fd = qemu_open(path, O_RDWR);
    if (group->fd < 0) {
        error_report("vfio: error opening %s: %m", path);
        error_setg_errno(errp, errno, "failed to open %s", path);
        goto free_group_exit;
    }

    if (ioctl(group->fd, VFIO_GROUP_GET_STATUS, &status)) {
        error_report("vfio: error getting group status: %m");
        error_setg_errno(errp, errno, "failed to get group %d status", groupid);
        goto close_fd_exit;
    }

    if (!(status.flags & VFIO_GROUP_FLAGS_VIABLE)) {
        error_report("vfio: error, group %d is not viable, please ensure "
                     "all devices within the iommu_group are bound to their "
                     "vfio bus driver.", groupid);
        error_setg(errp, "group %d is not viable", groupid);
        error_append_hint(errp,
                          "Please ensure all devices within the iommu_group "
                          "are bound to their vfio bus driver.\n");
        goto close_fd_exit;
    }

    group->groupid = groupid;
    QLIST_INIT(&group->device_list);

    if (vfio_connect_container(group, as)) {
        error_report("vfio: failed to setup container for group %d", groupid);
    if (vfio_connect_container(group, as, errp)) {
        error_prepend(errp, "failed to setup container for group %d: ",
                      groupid);
        goto close_fd_exit;
    }

@@ -1201,23 +1211,24 @@ void vfio_put_group(VFIOGroup *group)
}

int vfio_get_device(VFIOGroup *group, const char *name,
                       VFIODevice *vbasedev)
                    VFIODevice *vbasedev, Error **errp)
{
    struct vfio_device_info dev_info = { .argsz = sizeof(dev_info) };
    int ret, fd;

    fd = ioctl(group->fd, VFIO_GROUP_GET_DEVICE_FD, name);
    if (fd < 0) {
        error_report("vfio: error getting device %s from group %d: %m",
                     name, group->groupid);
        error_printf("Verify all devices in group %d are bound to vfio-<bus> "
        error_setg_errno(errp, errno, "error getting device from group %d",
                         group->groupid);
        error_append_hint(errp,
                      "Verify all devices in group %d are bound to vfio-<bus> "
                      "or pci-stub and not already in use\n", group->groupid);
        return fd;
    }

    ret = ioctl(fd, VFIO_DEVICE_GET_INFO, &dev_info);
    if (ret) {
        error_report("vfio: error getting device info: %m");
        error_setg_errno(errp, errno, "error getting device info");
        close(fd);
        return ret;
    }
+9 −7
Original line number Diff line number Diff line
@@ -898,7 +898,7 @@ static uint64_t vfio_rtl8168_quirk_data_read(void *opaque,
{
    VFIOrtl8168Quirk *rtl = opaque;
    VFIOPCIDevice *vdev = rtl->vdev;
    uint64_t data = vfio_region_read(&vdev->bars[2].region, addr + 0x74, size);
    uint64_t data = vfio_region_read(&vdev->bars[2].region, addr + 0x70, size);

    if (rtl->enabled && (vdev->pdev.cap_present & QEMU_PCI_CAP_MSIX)) {
        hwaddr offset = rtl->addr & 0xfff;
@@ -1056,7 +1056,7 @@ typedef struct VFIOIGDQuirk {
 * of the IGD device.
 */
int vfio_pci_igd_opregion_init(VFIOPCIDevice *vdev,
                               struct vfio_region_info *info)
                               struct vfio_region_info *info, Error **errp)
{
    int ret;

@@ -1064,7 +1064,7 @@ int vfio_pci_igd_opregion_init(VFIOPCIDevice *vdev,
    ret = pread(vdev->vbasedev.fd, vdev->igd_opregion,
                info->size, info->offset);
    if (ret != info->size) {
        error_report("vfio: Error reading IGD OpRegion");
        error_setg(errp, "failed to read IGD OpRegion");
        g_free(vdev->igd_opregion);
        vdev->igd_opregion = NULL;
        return -EINVAL;
@@ -1363,6 +1363,7 @@ static void vfio_probe_igd_bar4_quirk(VFIOPCIDevice *vdev, int nr)
    uint64_t *bdsm_size;
    uint32_t gmch;
    uint16_t cmd_orig, cmd;
    Error *err = NULL;

    /*
     * This must be an Intel VGA device at address 00:02.0 for us to even
@@ -1464,7 +1465,8 @@ static void vfio_probe_igd_bar4_quirk(VFIOPCIDevice *vdev, int nr)
     * try to enable it.  Probably shouldn't be using legacy mode without VGA,
     * but also no point in us enabling VGA if disabled in hardware.
     */
    if (!(gmch & 0x2) && !vdev->vga && vfio_populate_vga(vdev)) {
    if (!(gmch & 0x2) && !vdev->vga && vfio_populate_vga(vdev, &err)) {
        error_reportf_err(err, ERR_PREFIX, vdev->vbasedev.name);
        error_report("IGD device %s failed to enable VGA access, "
                     "legacy mode disabled", vdev->vbasedev.name);
        goto out;
@@ -1487,10 +1489,10 @@ static void vfio_probe_igd_bar4_quirk(VFIOPCIDevice *vdev, int nr)
    }

    /* Setup OpRegion access */
    ret = vfio_pci_igd_opregion_init(vdev, opregion);
    ret = vfio_pci_igd_opregion_init(vdev, opregion, &err);
    if (ret) {
        error_report("IGD device %s failed to setup OpRegion, "
                     "legacy mode disabled", vdev->vbasedev.name);
        error_append_hint(&err, "IGD legacy mode disabled\n");
        error_reportf_err(err, ERR_PREFIX, vdev->vbasedev.name);
        goto out;
    }

+157 −122

File changed.

Preview size limit exceeded, changes collapsed.

+3 −2
Original line number Diff line number Diff line
@@ -161,9 +161,10 @@ void vfio_bar_quirk_exit(VFIOPCIDevice *vdev, int nr);
void vfio_bar_quirk_finalize(VFIOPCIDevice *vdev, int nr);
void vfio_setup_resetfn_quirk(VFIOPCIDevice *vdev);

int vfio_populate_vga(VFIOPCIDevice *vdev);
int vfio_populate_vga(VFIOPCIDevice *vdev, Error **errp);

int vfio_pci_igd_opregion_init(VFIOPCIDevice *vdev,
                               struct vfio_region_info *info);
                               struct vfio_region_info *info,
                               Error **errp);

#endif /* HW_VFIO_VFIO_PCI_H */
+38 −28
Original line number Diff line number Diff line
@@ -44,9 +44,10 @@ static inline bool vfio_irq_is_automasked(VFIOINTp *intp)
 * and add it into the list of IRQs
 * @vbasedev: the VFIO device handle
 * @info: irq info struct retrieved from VFIO driver
 * @errp: error object
 */
static VFIOINTp *vfio_init_intp(VFIODevice *vbasedev,
                                struct vfio_irq_info info)
                                struct vfio_irq_info info, Error **errp)
{
    int ret;
    VFIOPlatformDevice *vdev =
@@ -69,7 +70,8 @@ static VFIOINTp *vfio_init_intp(VFIODevice *vbasedev,
    if (ret) {
        g_free(intp->interrupt);
        g_free(intp);
        error_report("vfio: Error: trigger event_notifier_init failed ");
        error_setg_errno(errp, -ret,
                         "failed to initialize trigger eventd notifier");
        return NULL;
    }
    if (vfio_irq_is_automasked(intp)) {
@@ -80,7 +82,8 @@ static VFIOINTp *vfio_init_intp(VFIODevice *vbasedev,
            g_free(intp->interrupt);
            g_free(intp->unmask);
            g_free(intp);
            error_report("vfio: Error: resamplefd event_notifier_init failed");
            error_setg_errno(errp, -ret,
                             "failed to initialize resample eventd notifier");
            return NULL;
        }
    }
@@ -456,9 +459,10 @@ static int vfio_platform_hot_reset_multi(VFIODevice *vbasedev)
 * vfio_populate_device - Allocate and populate MMIO region
 * and IRQ structs according to driver returned information
 * @vbasedev: the VFIO device handle
 * @errp: error object
 *
 */
static int vfio_populate_device(VFIODevice *vbasedev)
static int vfio_populate_device(VFIODevice *vbasedev, Error **errp)
{
    VFIOINTp *intp, *tmp;
    int i, ret = -1;
@@ -466,7 +470,7 @@ static int vfio_populate_device(VFIODevice *vbasedev)
        container_of(vbasedev, VFIOPlatformDevice, vbasedev);

    if (!(vbasedev->flags & VFIO_DEVICE_FLAGS_PLATFORM)) {
        error_report("vfio: Um, this isn't a platform device");
        error_setg(errp, "this isn't a platform device");
        return ret;
    }

@@ -480,7 +484,7 @@ static int vfio_populate_device(VFIODevice *vbasedev)
                                vdev->regions[i], i, name);
        g_free(name);
        if (ret) {
            error_report("vfio: Error getting region %d info: %m", i);
            error_setg_errno(errp, -ret, "failed to get region %d info", i);
            goto reg_error;
        }
    }
@@ -496,16 +500,15 @@ static int vfio_populate_device(VFIODevice *vbasedev)
        irq.index = i;
        ret = ioctl(vbasedev->fd, VFIO_DEVICE_GET_IRQ_INFO, &irq);
        if (ret) {
            error_report("vfio: error getting device %s irq info",
                         vbasedev->name);
            error_setg_errno(errp, -ret, "failed to get device irq info");
            goto irq_err;
        } else {
            trace_vfio_platform_populate_interrupts(irq.index,
                                                    irq.count,
                                                    irq.flags);
            intp = vfio_init_intp(vbasedev, irq);
            intp = vfio_init_intp(vbasedev, irq, errp);
            if (!intp) {
                error_report("vfio: Error installing IRQ %d up", i);
                ret = -1;
                goto irq_err;
            }
        }
@@ -538,13 +541,14 @@ static VFIODeviceOps vfio_platform_ops = {
/**
 * vfio_base_device_init - perform preliminary VFIO setup
 * @vbasedev: the VFIO device handle
 * @errp: error object
 *
 * Implement the VFIO command sequence that allows to discover
 * assigned device resources: group extraction, device
 * fd retrieval, resource query.
 * Precondition: the device name must be initialized
 */
static int vfio_base_device_init(VFIODevice *vbasedev)
static int vfio_base_device_init(VFIODevice *vbasedev, Error **errp)
{
    VFIOGroup *group;
    VFIODevice *vbasedev_iter;
@@ -560,6 +564,7 @@ static int vfio_base_device_init(VFIODevice *vbasedev)
        vbasedev->name = g_strdup(basename(vbasedev->sysfsdev));
    } else {
        if (!vbasedev->name || strchr(vbasedev->name, '/')) {
            error_setg(errp, "wrong host device name");
            return -EINVAL;
        }

@@ -568,8 +573,8 @@ static int vfio_base_device_init(VFIODevice *vbasedev)
    }

    if (stat(vbasedev->sysfsdev, &st) < 0) {
        error_report("vfio: error: no such host device: %s",
                     vbasedev->sysfsdev);
        error_setg_errno(errp, errno,
                         "failed to get the sysfs host device file status");
        return -errno;
    }

@@ -578,44 +583,41 @@ static int vfio_base_device_init(VFIODevice *vbasedev)
    g_free(tmp);

    if (len < 0 || len >= sizeof(group_path)) {
        error_report("vfio: error no iommu_group for device");
        return len < 0 ? -errno : -ENAMETOOLONG;
        ret = len < 0 ? -errno : -ENAMETOOLONG;
        error_setg_errno(errp, -ret, "no iommu_group found");
        return ret;
    }

    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);
        error_setg_errno(errp, errno, "failed to read %s", group_path);
        return -errno;
    }

    trace_vfio_platform_base_device_init(vbasedev->name, groupid);

    group = vfio_get_group(groupid, &address_space_memory);
    group = vfio_get_group(groupid, &address_space_memory, errp);
    if (!group) {
        error_report("vfio: failed to get group %d", groupid);
        return -ENOENT;
    }

    QLIST_FOREACH(vbasedev_iter, &group->device_list, next) {
        if (strcmp(vbasedev_iter->name, vbasedev->name) == 0) {
            error_report("vfio: error: device %s is already attached",
                         vbasedev->name);
            error_setg(errp, "device is already attached");
            vfio_put_group(group);
            return -EBUSY;
        }
    }
    ret = vfio_get_device(group, vbasedev->name, vbasedev);
    ret = vfio_get_device(group, vbasedev->name, vbasedev, errp);
    if (ret) {
        error_report("vfio: failed to get device %s", vbasedev->name);
        vfio_put_group(group);
        return ret;
    }

    ret = vfio_populate_device(vbasedev);
    ret = vfio_populate_device(vbasedev, errp);
    if (ret) {
        error_report("vfio: failed to populate device %s", vbasedev->name);
        vfio_put_group(group);
    }

@@ -644,11 +646,9 @@ static void vfio_platform_realize(DeviceState *dev, Error **errp)
                                vbasedev->sysfsdev : vbasedev->name,
                                vdev->compat);

    ret = vfio_base_device_init(vbasedev);
    ret = vfio_base_device_init(vbasedev, errp);
    if (ret) {
        error_setg(errp, "vfio: vfio_base_device_init failed for %s",
                   vbasedev->name);
        return;
        goto out;
    }

    for (i = 0; i < vbasedev->num_regions; i++) {
@@ -658,6 +658,16 @@ static void vfio_platform_realize(DeviceState *dev, Error **errp)
        }
        sysbus_init_mmio(sbdev, vdev->regions[i]->mem);
    }
out:
    if (!ret) {
        return;
    }

    if (vdev->vbasedev.name) {
        error_prepend(errp, ERR_PREFIX, vdev->vbasedev.name);
    } else {
        error_prepend(errp, "vfio error: ");
    }
}

static const VMStateDescription vfio_platform_vmstate = {
Loading