diff mbox series

[RFC,v1,2/3] vfio/pci: enable vector on dynamic MSI-X allocation

Message ID 20230727072410.135743-3-jing2.liu@intel.com
State New
Headers show
Series Support dynamic MSI-X allocation | expand

Commit Message

Jing Liu July 27, 2023, 7:24 a.m. UTC
The vector_use callback is used to enable vector that is unmasked in
guest. The kernel used to only support static MSI-X allocation. When
allocating a new interrupt using "static MSI-X allocation" kernels,
Qemu first disables all previously allocated vectors and then
re-allocates all including the new one. The nr_vectors of VFIOPCIDevice
indicates that all vectors from 0 to nr_vectors are allocated (and may
be enabled), which is used to to loop all the possibly used vectors
When, e.g., disabling MSI-X interrupts.

Extend the vector_use function to support dynamic MSI-X allocation when
host supports the capability. Qemu therefore can individually allocate
and enable a new interrupt without affecting others or causing interrupts
lost during runtime.

Utilize nr_vectors to calculate the upper bound of enabled vectors in
dynamic MSI-X allocation mode since looping all msix_entries_nr is not
efficient and unnecessary.

Signed-off-by: Jing Liu <jing2.liu@intel.com>
Tested-by: Reinette Chatre <reinette.chatre@intel.com>
---
 hw/vfio/pci.c | 40 +++++++++++++++++++++++++++-------------
 1 file changed, 27 insertions(+), 13 deletions(-)

Comments

Cédric Le Goater July 27, 2023, 5:07 p.m. UTC | #1
On 7/27/23 09:24, Jing Liu wrote:
> The vector_use callback is used to enable vector that is unmasked in
> guest. The kernel used to only support static MSI-X allocation. When
> allocating a new interrupt using "static MSI-X allocation" kernels,
> Qemu first disables all previously allocated vectors and then
> re-allocates all including the new one. The nr_vectors of VFIOPCIDevice
> indicates that all vectors from 0 to nr_vectors are allocated (and may
> be enabled), which is used to to loop all the possibly used vectors
> When, e.g., disabling MSI-X interrupts.
> 
> Extend the vector_use function to support dynamic MSI-X allocation when
> host supports the capability. Qemu therefore can individually allocate
> and enable a new interrupt without affecting others or causing interrupts
> lost during runtime.
> 
> Utilize nr_vectors to calculate the upper bound of enabled vectors in
> dynamic MSI-X allocation mode since looping all msix_entries_nr is not
> efficient and unnecessary.
> 
> Signed-off-by: Jing Liu <jing2.liu@intel.com>
> Tested-by: Reinette Chatre <reinette.chatre@intel.com>
> ---
>   hw/vfio/pci.c | 40 +++++++++++++++++++++++++++-------------
>   1 file changed, 27 insertions(+), 13 deletions(-)
> 
> diff --git a/hw/vfio/pci.c b/hw/vfio/pci.c
> index 0c4ac0873d40..8c485636445c 100644
> --- a/hw/vfio/pci.c
> +++ b/hw/vfio/pci.c
> @@ -512,12 +512,20 @@ static int vfio_msix_vector_do_use(PCIDevice *pdev, unsigned int nr,
>       }
>   
>       /*
> -     * We don't want to have the host allocate all possible MSI vectors
> -     * for a device if they're not in use, so we shutdown and incrementally
> -     * increase them as needed.
> +     * When dynamic allocation is not supported, we don't want to have the
> +     * host allocate all possible MSI vectors for a device if they're not
> +     * in use, so we shutdown and incrementally increase them as needed.
> +     * And nr_vectors stands for the number of vectors being allocated.
> +     *
> +     * When dynamic allocation is supported, let the host only allocate
> +     * and enable a vector when it is in use in guest. nr_vectors stands
> +     * for the upper bound of vectors being enabled (but not all of the
> +     * ranges is allocated or enabled).
>        */
> -    if (vdev->nr_vectors < nr + 1) {
> +    if ((vdev->msix->irq_info_flags & VFIO_IRQ_INFO_NORESIZE) &&

I would add a small helper for this test: vfio_msix_can_alloc_dyn(vdev)

Thanks,

C.


> +        (vdev->nr_vectors < nr + 1)) {
>           vdev->nr_vectors = nr + 1;
> +
>           if (!vdev->defer_kvm_irq_routing) {
>               vfio_disable_irqindex(&vdev->vbasedev, VFIO_PCI_MSIX_IRQ_INDEX);
>               ret = vfio_enable_vectors(vdev, true);
> @@ -529,16 +537,22 @@ static int vfio_msix_vector_do_use(PCIDevice *pdev, unsigned int nr,
>           Error *err = NULL;
>           int32_t fd;
>   
> -        if (vector->virq >= 0) {
> -            fd = event_notifier_get_fd(&vector->kvm_interrupt);
> -        } else {
> -            fd = event_notifier_get_fd(&vector->interrupt);
> -        }
> +        if (!vdev->defer_kvm_irq_routing) {
> +            if (vector->virq >= 0) {
> +                fd = event_notifier_get_fd(&vector->kvm_interrupt);
> +            } else {
> +                fd = event_notifier_get_fd(&vector->interrupt);
> +            }
>   
> -        if (vfio_set_irq_signaling(&vdev->vbasedev,
> -                                     VFIO_PCI_MSIX_IRQ_INDEX, nr,
> -                                     VFIO_IRQ_SET_ACTION_TRIGGER, fd, &err)) {
> -            error_reportf_err(err, VFIO_MSG_PREFIX, vdev->vbasedev.name);
> +            if (vfio_set_irq_signaling(&vdev->vbasedev,
> +                                       VFIO_PCI_MSIX_IRQ_INDEX, nr,
> +                                       VFIO_IRQ_SET_ACTION_TRIGGER, fd, &err)) {
> +                error_reportf_err(err, VFIO_MSG_PREFIX, vdev->vbasedev.name);
> +            }
> +        }
> +        /* Increase for dynamic allocation case. */
> +        if (vdev->nr_vectors < nr + 1) {
> +            vdev->nr_vectors = nr + 1;
>           }
>       }
>
Alex Williamson July 27, 2023, 5:25 p.m. UTC | #2
On Thu, 27 Jul 2023 03:24:09 -0400
Jing Liu <jing2.liu@intel.com> wrote:

> The vector_use callback is used to enable vector that is unmasked in
> guest. The kernel used to only support static MSI-X allocation. When
> allocating a new interrupt using "static MSI-X allocation" kernels,
> Qemu first disables all previously allocated vectors and then
> re-allocates all including the new one. The nr_vectors of VFIOPCIDevice
> indicates that all vectors from 0 to nr_vectors are allocated (and may
> be enabled), which is used to to loop all the possibly used vectors
> When, e.g., disabling MSI-X interrupts.
> 
> Extend the vector_use function to support dynamic MSI-X allocation when
> host supports the capability. Qemu therefore can individually allocate
> and enable a new interrupt without affecting others or causing interrupts
> lost during runtime.
> 
> Utilize nr_vectors to calculate the upper bound of enabled vectors in
> dynamic MSI-X allocation mode since looping all msix_entries_nr is not
> efficient and unnecessary.
> 
> Signed-off-by: Jing Liu <jing2.liu@intel.com>
> Tested-by: Reinette Chatre <reinette.chatre@intel.com>
> ---
>  hw/vfio/pci.c | 40 +++++++++++++++++++++++++++-------------
>  1 file changed, 27 insertions(+), 13 deletions(-)
> 
> diff --git a/hw/vfio/pci.c b/hw/vfio/pci.c
> index 0c4ac0873d40..8c485636445c 100644
> --- a/hw/vfio/pci.c
> +++ b/hw/vfio/pci.c
> @@ -512,12 +512,20 @@ static int vfio_msix_vector_do_use(PCIDevice *pdev, unsigned int nr,
>      }
>  
>      /*
> -     * We don't want to have the host allocate all possible MSI vectors
> -     * for a device if they're not in use, so we shutdown and incrementally
> -     * increase them as needed.
> +     * When dynamic allocation is not supported, we don't want to have the
> +     * host allocate all possible MSI vectors for a device if they're not
> +     * in use, so we shutdown and incrementally increase them as needed.
> +     * And nr_vectors stands for the number of vectors being allocated.

"nr_vectors represents the total number of vectors allocated."

> +     *
> +     * When dynamic allocation is supported, let the host only allocate
> +     * and enable a vector when it is in use in guest. nr_vectors stands
> +     * for the upper bound of vectors being enabled (but not all of the
> +     * ranges is allocated or enabled).

s/stands for/represents/

>       */
> -    if (vdev->nr_vectors < nr + 1) {
> +    if ((vdev->msix->irq_info_flags & VFIO_IRQ_INFO_NORESIZE) &&

Testing vdev->msix->noresize would be cleaner.

> +        (vdev->nr_vectors < nr + 1)) {
>          vdev->nr_vectors = nr + 1;
> +
>          if (!vdev->defer_kvm_irq_routing) {
>              vfio_disable_irqindex(&vdev->vbasedev, VFIO_PCI_MSIX_IRQ_INDEX);
>              ret = vfio_enable_vectors(vdev, true);
> @@ -529,16 +537,22 @@ static int vfio_msix_vector_do_use(PCIDevice *pdev, unsigned int nr,
>          Error *err = NULL;
>          int32_t fd;
>  
> -        if (vector->virq >= 0) {
> -            fd = event_notifier_get_fd(&vector->kvm_interrupt);
> -        } else {
> -            fd = event_notifier_get_fd(&vector->interrupt);
> -        }
> +        if (!vdev->defer_kvm_irq_routing) {
> +            if (vector->virq >= 0) {
> +                fd = event_notifier_get_fd(&vector->kvm_interrupt);
> +            } else {
> +                fd = event_notifier_get_fd(&vector->interrupt);
> +            }
>  
> -        if (vfio_set_irq_signaling(&vdev->vbasedev,
> -                                     VFIO_PCI_MSIX_IRQ_INDEX, nr,
> -                                     VFIO_IRQ_SET_ACTION_TRIGGER, fd, &err)) {
> -            error_reportf_err(err, VFIO_MSG_PREFIX, vdev->vbasedev.name);
> +            if (vfio_set_irq_signaling(&vdev->vbasedev,
> +                                       VFIO_PCI_MSIX_IRQ_INDEX, nr,
> +                                       VFIO_IRQ_SET_ACTION_TRIGGER, fd, &err)) {
> +                error_reportf_err(err, VFIO_MSG_PREFIX, vdev->vbasedev.name);
> +            }
> +        }
> +        /* Increase for dynamic allocation case. */
> +        if (vdev->nr_vectors < nr + 1) {
> +            vdev->nr_vectors = nr + 1;
>          }

We now have two branches where the bulk of the code is skipped when
defer_kvm_irq_routing is enabled and doing effectively the same update
to nr_vectors otherwise.  This suggests we should move the
defer_kvm_irq_routing test out and create a common place to update
nr_vectors.  Thanks,

Alex
Jing Liu July 31, 2023, 7:17 a.m. UTC | #3
Hi Alex,

> On July 28, 2023 1:25 AM,  Alex Williamson <alex.williamson@redhat.com> wrote:
> 
> On Thu, 27 Jul 2023 03:24:09 -0400
> Jing Liu <jing2.liu@intel.com> wrote:
> 
> > The vector_use callback is used to enable vector that is unmasked in
> > guest. The kernel used to only support static MSI-X allocation. When
> > allocating a new interrupt using "static MSI-X allocation" kernels,
> > Qemu first disables all previously allocated vectors and then
> > re-allocates all including the new one. The nr_vectors of
> > VFIOPCIDevice indicates that all vectors from 0 to nr_vectors are
> > allocated (and may be enabled), which is used to to loop all the
> > possibly used vectors When, e.g., disabling MSI-X interrupts.
> >
> > Extend the vector_use function to support dynamic MSI-X allocation
> > when host supports the capability. Qemu therefore can individually
> > allocate and enable a new interrupt without affecting others or
> > causing interrupts lost during runtime.
> >
> > Utilize nr_vectors to calculate the upper bound of enabled vectors in
> > dynamic MSI-X allocation mode since looping all msix_entries_nr is not
> > efficient and unnecessary.
> >
> > Signed-off-by: Jing Liu <jing2.liu@intel.com>
> > Tested-by: Reinette Chatre <reinette.chatre@intel.com>
> > ---
> >  hw/vfio/pci.c | 40 +++++++++++++++++++++++++++-------------
> >  1 file changed, 27 insertions(+), 13 deletions(-)
> >
> > diff --git a/hw/vfio/pci.c b/hw/vfio/pci.c index
> > 0c4ac0873d40..8c485636445c 100644
> > --- a/hw/vfio/pci.c
> > +++ b/hw/vfio/pci.c
> > @@ -512,12 +512,20 @@ static int vfio_msix_vector_do_use(PCIDevice
> *pdev, unsigned int nr,
> >      }
> >
> >      /*
> > -     * We don't want to have the host allocate all possible MSI vectors
> > -     * for a device if they're not in use, so we shutdown and incrementally
> > -     * increase them as needed.
> > +     * When dynamic allocation is not supported, we don't want to have the
> > +     * host allocate all possible MSI vectors for a device if they're not
> > +     * in use, so we shutdown and incrementally increase them as needed.
> > +     * And nr_vectors stands for the number of vectors being allocated.
> 
> "nr_vectors represents the total number of vectors allocated."

Will change.

> 
> > +     *
> > +     * When dynamic allocation is supported, let the host only allocate
> > +     * and enable a vector when it is in use in guest. nr_vectors stands
> > +     * for the upper bound of vectors being enabled (but not all of the
> > +     * ranges is allocated or enabled).
> 
> s/stands for/represents/
Will change.
> 
> >       */
> > -    if (vdev->nr_vectors < nr + 1) {
> > +    if ((vdev->msix->irq_info_flags & VFIO_IRQ_INFO_NORESIZE) &&
> 
> Testing vdev->msix->noresize would be cleaner.
> 
> > +        (vdev->nr_vectors < nr + 1)) {
> >          vdev->nr_vectors = nr + 1;
> > +
> >          if (!vdev->defer_kvm_irq_routing) {
> >              vfio_disable_irqindex(&vdev->vbasedev, VFIO_PCI_MSIX_IRQ_INDEX);
> >              ret = vfio_enable_vectors(vdev, true); @@ -529,16 +537,22
> > @@ static int vfio_msix_vector_do_use(PCIDevice *pdev, unsigned int nr,
> >          Error *err = NULL;
> >          int32_t fd;
> >
> > -        if (vector->virq >= 0) {
> > -            fd = event_notifier_get_fd(&vector->kvm_interrupt);
> > -        } else {
> > -            fd = event_notifier_get_fd(&vector->interrupt);
> > -        }
> > +        if (!vdev->defer_kvm_irq_routing) {
> > +            if (vector->virq >= 0) {
> > +                fd = event_notifier_get_fd(&vector->kvm_interrupt);
> > +            } else {
> > +                fd = event_notifier_get_fd(&vector->interrupt);
> > +            }
> >
> > -        if (vfio_set_irq_signaling(&vdev->vbasedev,
> > -                                     VFIO_PCI_MSIX_IRQ_INDEX, nr,
> > -                                     VFIO_IRQ_SET_ACTION_TRIGGER, fd, &err)) {
> > -            error_reportf_err(err, VFIO_MSG_PREFIX, vdev->vbasedev.name);
> > +            if (vfio_set_irq_signaling(&vdev->vbasedev,
> > +                                       VFIO_PCI_MSIX_IRQ_INDEX, nr,
> > +                                       VFIO_IRQ_SET_ACTION_TRIGGER, fd, &err)) {
> > +                error_reportf_err(err, VFIO_MSG_PREFIX, vdev->vbasedev.name);
> > +            }
> > +        }
> > +        /* Increase for dynamic allocation case. */
> > +        if (vdev->nr_vectors < nr + 1) {
> > +            vdev->nr_vectors = nr + 1;
> >          }
> 
> We now have two branches where the bulk of the code is skipped when
> defer_kvm_irq_routing is enabled and doing effectively the same update to
> nr_vectors otherwise.  This suggests we should move the
> defer_kvm_irq_routing test out and create a common place to update
> nr_vectors.  Thanks,

I make a new logic as follows that moves the defer_kvm_irq_routing test out.
Since the vfio_enable_vectors() function need an updated nr_vectors value
so need first update and test the different conditions using old value,
e.g. old_nr_vec.

int old_nr_vec = vdev->nr_vectors;
...
...
if (vdev->nr_vectors < nr + 1) {
    vdev->nr_vectors = nr + 1;
}
if (!vdev->defer_kvm_irq_routing) {
    if (vdev->msix->noresize && (old_nr_vec < nr + 1)) {
            vfio_disable_irqindex(&vdev->vbasedev, VFIO_PCI_MSIX_IRQ_INDEX);
            ret = vfio_enable_vectors(vdev, true);  // use updated nr_vectors
            ...
    } else {
            if (vector->virq >= 0) {
                fd = event_notifier_get_fd(&vector->kvm_interrupt);
            } else {
                fd = event_notifier_get_fd(&vector->interrupt);
            }
            if (vfio_set_irq_signaling(&vdev->vbasedev,
                                       VFIO_PCI_MSIX_IRQ_INDEX, nr,
                                       VFIO_IRQ_SET_ACTION_TRIGGER, fd, &err)) {
                error_reportf_err(err, VFIO_MSG_PREFIX, vdev->vbasedev.name);
            }        
    }
}
Thanks,
Jing

> 
> Alex
diff mbox series

Patch

diff --git a/hw/vfio/pci.c b/hw/vfio/pci.c
index 0c4ac0873d40..8c485636445c 100644
--- a/hw/vfio/pci.c
+++ b/hw/vfio/pci.c
@@ -512,12 +512,20 @@  static int vfio_msix_vector_do_use(PCIDevice *pdev, unsigned int nr,
     }
 
     /*
-     * We don't want to have the host allocate all possible MSI vectors
-     * for a device if they're not in use, so we shutdown and incrementally
-     * increase them as needed.
+     * When dynamic allocation is not supported, we don't want to have the
+     * host allocate all possible MSI vectors for a device if they're not
+     * in use, so we shutdown and incrementally increase them as needed.
+     * And nr_vectors stands for the number of vectors being allocated.
+     *
+     * When dynamic allocation is supported, let the host only allocate
+     * and enable a vector when it is in use in guest. nr_vectors stands
+     * for the upper bound of vectors being enabled (but not all of the
+     * ranges is allocated or enabled).
      */
-    if (vdev->nr_vectors < nr + 1) {
+    if ((vdev->msix->irq_info_flags & VFIO_IRQ_INFO_NORESIZE) &&
+        (vdev->nr_vectors < nr + 1)) {
         vdev->nr_vectors = nr + 1;
+
         if (!vdev->defer_kvm_irq_routing) {
             vfio_disable_irqindex(&vdev->vbasedev, VFIO_PCI_MSIX_IRQ_INDEX);
             ret = vfio_enable_vectors(vdev, true);
@@ -529,16 +537,22 @@  static int vfio_msix_vector_do_use(PCIDevice *pdev, unsigned int nr,
         Error *err = NULL;
         int32_t fd;
 
-        if (vector->virq >= 0) {
-            fd = event_notifier_get_fd(&vector->kvm_interrupt);
-        } else {
-            fd = event_notifier_get_fd(&vector->interrupt);
-        }
+        if (!vdev->defer_kvm_irq_routing) {
+            if (vector->virq >= 0) {
+                fd = event_notifier_get_fd(&vector->kvm_interrupt);
+            } else {
+                fd = event_notifier_get_fd(&vector->interrupt);
+            }
 
-        if (vfio_set_irq_signaling(&vdev->vbasedev,
-                                     VFIO_PCI_MSIX_IRQ_INDEX, nr,
-                                     VFIO_IRQ_SET_ACTION_TRIGGER, fd, &err)) {
-            error_reportf_err(err, VFIO_MSG_PREFIX, vdev->vbasedev.name);
+            if (vfio_set_irq_signaling(&vdev->vbasedev,
+                                       VFIO_PCI_MSIX_IRQ_INDEX, nr,
+                                       VFIO_IRQ_SET_ACTION_TRIGGER, fd, &err)) {
+                error_reportf_err(err, VFIO_MSG_PREFIX, vdev->vbasedev.name);
+            }
+        }
+        /* Increase for dynamic allocation case. */
+        if (vdev->nr_vectors < nr + 1) {
+            vdev->nr_vectors = nr + 1;
         }
     }