From: Eric Auger <eric.auger@linaro.org>
To: Alex Williamson <alex.williamson@redhat.com>
Cc: agraf@suse.de, kim.phillips@freescale.com, eric.auger@st.com,
peter.maydell@linaro.org, patches@linaro.org,
will.deacon@arm.com, qemu-devel@nongnu.org,
a.rigo@virtualopensystems.com, Bharat.Bhushan@freescale.com,
stuart.yoder@freescale.com, a.motakis@virtualopensystems.com,
kvmarm@lists.cs.columbia.edu, christoffer.dall@linaro.org
Subject: Re: [Qemu-devel] [RFC v4 06/13] hw/vfio/pci: split vfio_get_device
Date: Thu, 24 Jul 2014 12:25:12 +0200 [thread overview]
Message-ID: <53D0DF08.1010505@linaro.org> (raw)
In-Reply-To: <53D0D713.8090101@linaro.org>
On 07/24/2014 11:51 AM, Eric Auger wrote:
> On 07/09/2014 12:43 AM, Alex Williamson wrote:
>> On Mon, 2014-07-07 at 13:27 +0100, Eric Auger wrote:
>>> vfio_get_device now takes a VFIODevice as argument. The function is split
>>> into 4 functional parts: dev_info query, device check, region populate
>>> and interrupt populate. the last 3 are specialized by parent device and
>>> are added into DeviceOps.
>>>
>>> 3 new fields are introduced in VFIODevice to store dev_info.
>>>
>>> vfio_put_base_device is created.
>>>
>>> Signed-off-by: Eric Auger <eric.auger@linaro.org>
>>> ---
>>> hw/vfio/pci.c | 181 +++++++++++++++++++++++++++++++++++++++-------------------
>>> 1 file changed, 121 insertions(+), 60 deletions(-)
>>>
>>> diff --git a/hw/vfio/pci.c b/hw/vfio/pci.c
>>> index 5f0164a..d228cf8 100644
>>> --- a/hw/vfio/pci.c
>>> +++ b/hw/vfio/pci.c
>>> @@ -194,12 +194,18 @@ typedef struct VFIODevice {
>>> bool reset_works;
>>> bool needs_reset;
>>> VFIODeviceOps *ops;
>>> + unsigned int num_irqs;
>>> + unsigned int num_regions;
>>> + unsigned int flags;
>>> } VFIODevice;
>>>
>>> struct VFIODeviceOps {
>>> bool (*vfio_compute_needs_reset)(VFIODevice *vdev);
>>> int (*vfio_hot_reset_multi)(VFIODevice *vdev);
>>> void (*vfio_eoi)(VFIODevice *vdev);
>>> + int (*vfio_check_device)(VFIODevice *vdev);
>>> + int (*vfio_populate_regions)(VFIODevice *vdev);
>>> + int (*vfio_populate_interrupts)(VFIODevice *vdev);
>>> };
>>>
>>> typedef struct VFIOPCIDevice {
>>> @@ -286,6 +292,10 @@ static uint32_t vfio_pci_read_config(PCIDevice *pdev, uint32_t addr, int len);
>>> static void vfio_pci_write_config(PCIDevice *pdev, uint32_t addr,
>>> uint32_t val, int len);
>>> static void vfio_mmap_set_enabled(VFIOPCIDevice *vdev, bool enabled);
>>> +static void vfio_put_base_device(VFIODevice *vbasedev);
>>> +static int vfio_check_device(VFIODevice *vbasedev);
>>> +static int vfio_populate_regions(VFIODevice *vbasedev);
>>> +static int vfio_populate_interrupts(VFIODevice *vbasedev);
>>>
>>> /*
>>> * Common VFIO interrupt disable
>>> @@ -3585,6 +3595,9 @@ static VFIODeviceOps vfio_pci_ops = {
>>> .vfio_compute_needs_reset = vfio_pci_compute_needs_reset,
>>> .vfio_hot_reset_multi = vfio_pci_hot_reset_multi,
>>> .vfio_eoi = vfio_eoi,
>>> + .vfio_check_device = vfio_check_device,
>>> + .vfio_populate_regions = vfio_populate_regions,
>>> + .vfio_populate_interrupts = vfio_populate_interrupts,
>>> };
>>>
>>> static void vfio_reset_handler(void *opaque)
>>> @@ -3927,54 +3940,53 @@ static void vfio_put_group(VFIOGroup *group)
>>> }
>>> }
>>>
>>> -static int vfio_get_device(VFIOGroup *group, const char *name,
>>> - VFIOPCIDevice *vdev)
>>> +static int vfio_check_device(VFIODevice *vbasedev)
>>> {
>>> - struct vfio_device_info dev_info = { .argsz = sizeof(dev_info) };
>>> - struct vfio_region_info reg_info = { .argsz = sizeof(reg_info) };
>>> - struct vfio_irq_info irq_info = { .argsz = sizeof(irq_info) };
>>> - int ret, i;
>>> -
>>> - ret = ioctl(group->fd, VFIO_GROUP_GET_DEVICE_FD, name);
>>> - if (ret < 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-pci "
>>> - "or pci-stub and not already in use\n", group->groupid);
>>> - return ret;
>>> + if (!(vbasedev->flags & VFIO_DEVICE_FLAGS_PCI)) {
>>> + error_report("vfio: Um, this isn't a PCI device");
>>> + goto error;
>>> }
>>> -
>>> - vdev->vbasedev.fd = ret;
>>> - vdev->vbasedev.group = group;
>>> - QLIST_INSERT_HEAD(&group->device_list, &vdev->vbasedev, next);
>>> -
>>> - /* Sanity check device */
>>> - ret = ioctl(vdev->vbasedev.fd, VFIO_DEVICE_GET_INFO, &dev_info);
>>> - if (ret) {
>>> - error_report("vfio: error getting device info: %m");
>>> + if (vbasedev->num_regions < VFIO_PCI_CONFIG_REGION_INDEX + 1) {
>>> + error_report("vfio: unexpected number of io regions %u",
>>> + vbasedev->num_regions);
>>> goto error;
>>> }
>>> -
>>> - DPRINTF("Device %s flags: %u, regions: %u, irgs: %u\n", name,
>>> - dev_info.flags, dev_info.num_regions, dev_info.num_irqs);
>>> -
>>> - if (!(dev_info.flags & VFIO_DEVICE_FLAGS_PCI)) {
>>> - error_report("vfio: Um, this isn't a PCI device");
>>> + if (vbasedev->num_irqs < VFIO_PCI_MSIX_IRQ_INDEX + 1) {
>>> + error_report("vfio: unexpected number of irqs %u",
>>> + vbasedev->num_irqs);
>>> goto error;
>>> }
>>> + return 0;
>>> +error:
>>> + vfio_put_base_device(vbasedev);
>>
>> This doesn't make much sense, this function never "got" the base device,
>> so why does it need to "put" it on error? We should simply return error
>> and the caller (presumably who got it) should put the device.
> Hi Alex,
>
> definitively I need to revisit and homogenize my error handling: all
> sub-functions just returning errors - if sensible- , get/put at upper
> level. errno misusage. Sorry for that :-(
>>
>>> + return -errno;
>>
>> Nothing above seems to guarantee we have anything useful in errno (or
>> that it hasn't been clobbered).
> replaced by -1
>>
>>> +}
>>>
>>> - vdev->vbasedev.reset_works = !!(dev_info.flags & VFIO_DEVICE_FLAGS_RESET);
>>> +static int vfio_populate_interrupts(VFIODevice *vbasedev)
>>> +{
>>> + VFIOPCIDevice *vdev = container_of(vbasedev, VFIOPCIDevice, vbasedev);
>>> + int ret;
>>> + struct vfio_irq_info irq_info = { .argsz = sizeof(irq_info) };
>>> + irq_info.index = VFIO_PCI_ERR_IRQ_INDEX;
>>>
>>> - if (dev_info.num_regions < VFIO_PCI_CONFIG_REGION_INDEX + 1) {
>>> - error_report("vfio: unexpected number of io regions %u",
>>> - dev_info.num_regions);
>>> - goto error;
>>> + ret = ioctl(vbasedev->fd, VFIO_DEVICE_GET_IRQ_INFO, &irq_info);
>>> + if (ret) {
>>> + /* This can fail for an old kernel or legacy PCI dev */
>>> + DPRINTF("VFIO_DEVICE_GET_IRQ_INFO failure: %m\n");
>>> + } else if (irq_info.count == 1) {
>>> + vdev->pci_aer = true;
>>> + } else {
>>> + error_report("vfio: %s Could not enable error recovery for the device",
>>> + vbasedev->name);
>>> }
>>> + return ret;
>>
>> This function returns error if the device doesn't support error
>> reporting, which is an optional feature. I don't think that's what we
>> want.
> OK misunderstood the comment. function proto changed to return void.
after some more thoughts related to platform usage I would like to keep
the return value and set it to 0 for PCI.
BR
Eric
>>
>>> +}
>>>
>>> - if (dev_info.num_irqs < VFIO_PCI_MSIX_IRQ_INDEX + 1) {
>>> - error_report("vfio: unexpected number of irqs %u", dev_info.num_irqs);
>>> - goto error;
>>> - }
>>> +static int vfio_populate_regions(VFIODevice *vbasedev)
>>> +{
>>> + struct vfio_region_info reg_info = { .argsz = sizeof(reg_info) };
>>> + int i, ret;
>>> + VFIOPCIDevice *vdev = container_of(vbasedev, VFIOPCIDevice, vbasedev);
>>>
>>> for (i = VFIO_PCI_BAR0_REGION_INDEX; i < VFIO_PCI_ROM_REGION_INDEX; i++) {
>>> reg_info.index = i;
>>> @@ -4018,7 +4030,7 @@ static int vfio_get_device(VFIOGroup *group, const char *name,
>>> vdev->config_offset = reg_info.offset;
>>>
>>> if ((vdev->features & VFIO_FEATURE_ENABLE_VGA) &&
>>> - dev_info.num_regions > VFIO_PCI_VGA_REGION_INDEX) {
>>> + vbasedev->num_regions > VFIO_PCI_VGA_REGION_INDEX) {
>>> struct vfio_region_info vga_info = {
>>> .argsz = sizeof(vga_info),
>>> .index = VFIO_PCI_VGA_REGION_INDEX,
>>> @@ -4057,38 +4069,87 @@ static int vfio_get_device(VFIOGroup *group, const char *name,
>>>
>>> vdev->has_vga = true;
>>> }
>>> - irq_info.index = VFIO_PCI_ERR_IRQ_INDEX;
>>> + return 0;
>>> +error:
>>> + vfio_put_base_device(vbasedev);
>>> + return -errno;
>>
>> errno can get clobbered by here, don't count on it. Also, why does this
>> put the base device while interrupt_populate error does not? The put
>> needs to happen a level above these functions imho.
>
> ok
>>
>>> +}
>>> +
>>> +static int vfio_get_device(VFIOGroup *group, const char *name,
>>> + VFIODevice *vbasedev)
>>> +{
>>> + struct vfio_device_info dev_info = { .argsz = sizeof(dev_info) };
>>> + struct vfio_region_info reg_info = { .argsz = sizeof(reg_info) };
>>> + struct vfio_irq_info irq_info = { .argsz = sizeof(irq_info) };
>>> + int ret;
>>> +
>>> + ret = ioctl(group->fd, VFIO_GROUP_GET_DEVICE_FD, name);
>>> + if (ret < 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-pci "
>>> + "or pci-stub and not already in use\n", group->groupid);
>>> + return ret;
>>> + }
>>> +
>>> + vbasedev->fd = ret;
>>> + vbasedev->group = group;
>>> + QLIST_INSERT_HEAD(&group->device_list, vbasedev, next);
>>>
>>> - ret = ioctl(vdev->vbasedev.fd, VFIO_DEVICE_GET_IRQ_INFO, &irq_info);
>>> + ret = ioctl(vbasedev->fd, VFIO_DEVICE_GET_INFO, &dev_info);
>>> if (ret) {
>>> - /* This can fail for an old kernel or legacy PCI dev */
>>> - DPRINTF("VFIO_DEVICE_GET_IRQ_INFO failure: %m\n");
>>> - ret = 0;
>>> - } else if (irq_info.count == 1) {
>>> - vdev->pci_aer = true;
>>> - } else {
>>> - error_report("vfio: %04x:%02x:%02x.%x "
>>> - "Could not enable error recovery for the device",
>>> - vdev->host.domain, vdev->host.bus, vdev->host.slot,
>>> - vdev->host.function);
>>> + error_report("vfio: error getting device info: %m");
>>> + goto error;
>>> + }
>>> +
>>> + vbasedev->num_irqs = dev_info.num_irqs;
>>> + vbasedev->num_regions = dev_info.num_regions;
>>> + vbasedev->flags = dev_info.flags;
>>> +
>>> + DPRINTF("Device %s flags: %u, regions: %u, irgs: %u\n", name,
>>> + dev_info.flags, dev_info.num_regions, dev_info.num_irqs);
>>> +
>>> + vbasedev->reset_works = !!(dev_info.flags & VFIO_DEVICE_FLAGS_RESET);
>>> +
>>> + /* call device specific functions */
>>> + ret = vbasedev->ops->vfio_check_device(vbasedev);
>>> + if (ret) {
>>> + error_report("vfio: error when checking device %s\n",
>>> + vbasedev->name);
>>> + goto error;
>>> + }
>>> + ret = vbasedev->ops->vfio_populate_regions(vbasedev);
>>> + if (ret) {
>>> + error_report("vfio: error when populating regions of device %s\n",
>>> + vbasedev->name);
>>> + goto error;
>>> + }
>>> + ret = vbasedev->ops->vfio_populate_interrupts(vbasedev);
>>> + if (ret) {
>>> + error_report("vfio: error when populating interrupts of device %s\n",
>>> + vbasedev->name);
>>> + goto error;
>>> }
>>>
>>> error:
>>> if (ret) {
>>> - QLIST_REMOVE(&vdev->vbasedev, next);
>>> - vdev->vbasedev.group = NULL;
>>> - close(vdev->vbasedev.fd);
>>> + vfio_put_base_device(vbasedev);
>>
>> Whoops, more confusion, the call-out functions are doing put calls
>> (well, some of them) and so is this. This is the only place it should
>> occur.
> OK
>>
>>> }
>>> return ret;
>>> }
>>>
>>> -static void vfio_put_device(VFIOPCIDevice *vdev)
>>> +void vfio_put_base_device(VFIODevice *vbasedev)
>>> {
>>> - QLIST_REMOVE(&vdev->vbasedev, next);
>>> - vdev->vbasedev.group = NULL;
>>> + QLIST_REMOVE(vbasedev, next);
>>> + vbasedev->group = NULL;
>>> DPRINTF("vfio_put_device: close vdev->fd\n");
>>> - close(vdev->vbasedev.fd);
>>> - g_free(vdev->vbasedev.name);
>>> + close(vbasedev->fd);
>>> + g_free(vbasedev->name);
>>
>> get/put of the base device is still a bit messy. .name doesn't get
>> allocated by the get, but gets freed by the put.
>
> .name dealloc moved to vfio_put_device
>
> Thank you for your review
>
> Best Regards
>
> Eric
>>
>>> +}
>>> +
>>> +static void vfio_put_device(VFIOPCIDevice *vdev)
>>> +{
>>> + vfio_put_base_device(&vdev->vbasedev);
>>> if (vdev->msix) {
>>> g_free(vdev->msix);
>>> vdev->msix = NULL;
>>> @@ -4266,7 +4327,7 @@ static int vfio_initfn(PCIDevice *pdev)
>>> }
>>> }
>>>
>>> - ret = vfio_get_device(group, path, vdev);
>>> + ret = vfio_get_device(group, path, &vdev->vbasedev);
>>> if (ret) {
>>> error_report("vfio: failed to get device %s", path);
>>> vfio_put_group(group);
>>
>>
>>
>
next prev parent reply other threads:[~2014-07-24 10:25 UTC|newest]
Thread overview: 29+ messages / expand[flat|nested] mbox.gz Atom feed top
2014-07-07 12:27 [Qemu-devel] [RFC v4 00/13] KVM platform device passthrough Eric Auger
2014-07-07 12:27 ` [Qemu-devel] [RFC v4 01/13] vfio: move hw/misc/vfio.c to hw/vfio/pci.c Move vfio.h into include/hw/vfio Eric Auger
2014-07-07 12:27 ` [Qemu-devel] [RFC v4 02/13] hw/vfio/pci: Rename VFIODevice into VFIOPCIDevice Eric Auger
2014-07-07 12:27 ` [Qemu-devel] [RFC v4 03/13] hw/vfio/pci: Remove unneeded include files Eric Auger
2014-07-08 18:55 ` Alex Williamson
2014-07-23 9:59 ` Eric Auger
2014-07-07 12:27 ` [Qemu-devel] [RFC v4 04/13] hw/vfio/pci: introduce VFIODevice Eric Auger
2014-07-08 22:41 ` Alex Williamson
2014-07-23 10:02 ` Eric Auger
2014-07-23 10:24 ` Peter Maydell
2014-07-23 11:40 ` Eric Auger
2014-07-07 12:27 ` [Qemu-devel] [RFC v4 05/13] hw/vfio/pci: Introduce VFIORegion Eric Auger
2014-07-08 22:41 ` Alex Williamson
2014-07-23 13:50 ` Eric Auger
2014-07-07 12:27 ` [Qemu-devel] [RFC v4 06/13] hw/vfio/pci: split vfio_get_device Eric Auger
2014-07-08 22:43 ` Alex Williamson
2014-07-24 9:51 ` Eric Auger
2014-07-24 10:25 ` Eric Auger [this message]
2014-07-07 12:27 ` [Qemu-devel] [RFC v4 07/13] hw/vfio: create common module Eric Auger
2014-07-07 12:27 ` [Qemu-devel] [RFC v4 08/13] hw/vfio/common: Add EXEC_FLAG to VFIO DMA mappings Eric Auger
2014-07-07 12:40 ` Peter Maydell
2014-07-07 12:49 ` Will Deacon
2014-07-07 13:25 ` Alvise Rigo
2014-07-07 13:29 ` Eric Auger
2014-07-07 12:27 ` [Qemu-devel] [RFC v4 09/13] hw/vfio/platform: add vfio-platform support Eric Auger
2014-07-07 12:27 ` [Qemu-devel] [RFC v4 10/13] hw/intc/arm_gic_kvm: enable irqfd and set routing table Eric Auger
2014-07-07 12:27 ` [Qemu-devel] [RFC v4 11/13] hw/vfio/platform: Add irqfd support Eric Auger
2014-07-07 12:27 ` [Qemu-devel] [RFC v4 12/13] hw/vfio/platform: add default dt generation for vfio device Eric Auger
2014-07-07 12:27 ` [Qemu-devel] [RFC v4 13/13] hw/vfio: add an example calxeda_xgmac Eric Auger
Reply instructions:
You may reply publicly to this message via plain-text email
using any one of the following methods:
* Save the following mbox file, import it into your mail client,
and reply-to-all from there: mbox
Avoid top-posting and favor interleaved quoting:
https://en.wikipedia.org/wiki/Posting_style#Interleaved_style
* Reply using the --to, --cc, and --in-reply-to
switches of git-send-email(1):
git send-email \
--in-reply-to=53D0DF08.1010505@linaro.org \
--to=eric.auger@linaro.org \
--cc=Bharat.Bhushan@freescale.com \
--cc=a.motakis@virtualopensystems.com \
--cc=a.rigo@virtualopensystems.com \
--cc=agraf@suse.de \
--cc=alex.williamson@redhat.com \
--cc=christoffer.dall@linaro.org \
--cc=eric.auger@st.com \
--cc=kim.phillips@freescale.com \
--cc=kvmarm@lists.cs.columbia.edu \
--cc=patches@linaro.org \
--cc=peter.maydell@linaro.org \
--cc=qemu-devel@nongnu.org \
--cc=stuart.yoder@freescale.com \
--cc=will.deacon@arm.com \
/path/to/YOUR_REPLY
https://kernel.org/pub/software/scm/git/docs/git-send-email.html
* If your mail client supports setting the In-Reply-To header
via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line
before the message body.
This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.