On Wednesday 13 May 2009 06:07:15 Alex Williamson wrote:
> We're currently using a counter to track the most recent GSI we've
> handed out.  This quickly hits KVM_MAX_IRQ_ROUTES when using device
> assignment with a driver that regularly toggles the MSI enable bit.
> This can mean only a few minutes of usable run time.  Instead, track
> used GSIs in a bitmap.
>
> Signed-off-by: Alex Williamson <alex.william...@hp.com>
> ---
>
>  v2: Added mutex to protect gsi bitmap
>  v3: Updated for comments from Michael Tsirkin
>      No longer depends on "[PATCH] kvm: device-assignment: Catch GSI
> overflow"
>
>  hw/device-assignment.c  |    4 ++
>  kvm/libkvm/kvm-common.h |    4 ++
>  kvm/libkvm/libkvm.c     |   83
> +++++++++++++++++++++++++++++++++++++++++------ kvm/libkvm/libkvm.h     |  
> 10 ++++++
>  4 files changed, 88 insertions(+), 13 deletions(-)
>
> diff --git a/hw/device-assignment.c b/hw/device-assignment.c
> index a7365c8..a6cc9b9 100644
> --- a/hw/device-assignment.c
> +++ b/hw/device-assignment.c
> @@ -561,8 +561,10 @@ static void free_dev_irq_entries(AssignedDevice *dev)
>  {
>      int i;
>
> -    for (i = 0; i < dev->irq_entries_nr; i++)
> +    for (i = 0; i < dev->irq_entries_nr; i++) {
>          kvm_del_routing_entry(kvm_context, &dev->entry[i]);
> +        kvm_free_irq_route_gsi(kvm_context, dev->entry[i].gsi);
> +    }
>      free(dev->entry);
>      dev->entry = NULL;
>      dev->irq_entries_nr = 0;
> diff --git a/kvm/libkvm/kvm-common.h b/kvm/libkvm/kvm-common.h
> index 591fb53..4b3cb51 100644
> --- a/kvm/libkvm/kvm-common.h
> +++ b/kvm/libkvm/kvm-common.h
> @@ -66,8 +66,10 @@ struct kvm_context {
>  #ifdef KVM_CAP_IRQ_ROUTING
>       struct kvm_irq_routing *irq_routes;
>       int nr_allocated_irq_routes;
> +     void *used_gsi_bitmap;
> +     int max_gsi;
> +     pthread_mutex_t gsi_mutex;
>  #endif
> -     int max_used_gsi;
>  };
>
>  int kvm_alloc_kernel_memory(kvm_context_t kvm, unsigned long memory,
> diff --git a/kvm/libkvm/libkvm.c b/kvm/libkvm/libkvm.c
> index ba0a5d1..3d7ab75 100644
> --- a/kvm/libkvm/libkvm.c
> +++ b/kvm/libkvm/libkvm.c
> @@ -35,6 +35,7 @@
>  #include <errno.h>
>  #include <sys/ioctl.h>
>  #include <inttypes.h>
> +#include <pthread.h>
>  #include "libkvm.h"
>
>  #if defined(__x86_64__) || defined(__i386__)
> @@ -65,6 +66,8 @@
>  int kvm_abi = EXPECTED_KVM_API_VERSION;
>  int kvm_page_size;
>
> +static inline void set_bit(uint32_t *buf, unsigned int bit);
> +
>  struct slot_info {
>       unsigned long phys_addr;
>       unsigned long len;
> @@ -286,6 +289,9 @@ kvm_context_t kvm_init(struct kvm_callbacks *callbacks,
>       int fd;
>       kvm_context_t kvm;
>       int r;
> +#ifdef KVM_CAP_IRQ_ROUTING
> +     int gsi_count, gsi_bytes, i;
> +#endif
>
>       fd = open("/dev/kvm", O_RDWR);
>       if (fd == -1) {
> @@ -322,6 +328,27 @@ kvm_context_t kvm_init(struct kvm_callbacks
> *callbacks, kvm->dirty_pages_log_all = 0;
>       kvm->no_irqchip_creation = 0;
>       kvm->no_pit_creation = 0;
> +#ifdef KVM_CAP_IRQ_ROUTING
> +     pthread_mutex_init(&kvm->gsi_mutex, NULL);
> +
> +     gsi_count = kvm_get_gsi_count(kvm);
> +     /* Round up so we can search ints using ffs */
> +     gsi_bytes = (gsi_count + 31) / 32;

CMIW, should it be gsi_bytes = (gsi_count + 7) / 8? This looks like bits-to-
int. 

> +     kvm->used_gsi_bitmap = malloc(gsi_bytes);
> +     if (!kvm->used_gsi_bitmap) {
> +             pthread_mutex_unlock(&kvm->gsi_mutex);
> +             goto out_close;
> +     }
> +     memset(kvm->used_gsi_bitmap, 0, gsi_bytes);
> +     kvm->max_gsi = gsi_bytes * 8;

So max_gsi = gsi_count / 4?

-- 
regards
Yang, Sheng

> +
> +     /* Mark all the IOAPIC pin GSIs and any over-allocated
> +      * GSIs as already in use. */
> +     for (i = 0; i < KVM_IOAPIC_NUM_PINS; i++)
> +             set_bit(kvm->used_gsi_bitmap, i);
> +     for (i = gsi_count; i < kvm->max_gsi; i++)
> +             set_bit(kvm->used_gsi_bitmap, i);
> +#endif
>
>       return kvm;
>   out_close:
> @@ -1298,8 +1325,6 @@ int kvm_add_routing_entry(kvm_context_t kvm,
>       new->flags = entry->flags;
>       new->u = entry->u;
>
> -     if (entry->gsi > kvm->max_used_gsi)
> -             kvm->max_used_gsi = entry->gsi;
>       return 0;
>  #else
>       return -ENOSYS;
> @@ -1404,18 +1429,54 @@ int kvm_commit_irq_routes(kvm_context_t kvm)
>  #endif
>  }
>
> +#ifdef KVM_CAP_IRQ_ROUTING
> +static inline void set_bit(uint32_t *buf, unsigned int bit)
> +{
> +     buf[bit / 32] |= 1U << (bit % 32);
> +}
> +
> +static inline void clear_bit(uint32_t *buf, unsigned int bit)
> +{
> +     buf[bit / 32] &= ~(1U << (bit % 32));
> +}
> +
> +static int kvm_find_free_gsi(kvm_context_t kvm)
> +{
> +     int i, bit, gsi;
> +     uint32_t *buf = kvm->used_gsi_bitmap;
> +
> +     for (i = 0; i < kvm->max_gsi / 32; i++) {
> +             bit = ffs(~buf[i]);
> +             if (!bit)
> +                     continue;
> +
> +             gsi = bit - 1 + i * 32;
> +             set_bit(buf, gsi);
> +             return gsi;
> +     }
> +
> +     return -ENOSPC;
> +}
> +#endif
> +
>  int kvm_get_irq_route_gsi(kvm_context_t kvm)
>  {
> +     int gsi = -ENOSYS;
> +
>  #ifdef KVM_CAP_IRQ_ROUTING
> -     if (kvm->max_used_gsi >= KVM_IOAPIC_NUM_PINS)  {
> -         if (kvm->max_used_gsi <= kvm_get_gsi_count(kvm))
> -                return kvm->max_used_gsi + 1;
> -            else
> -                return -ENOSPC;
> -        } else
> -            return KVM_IOAPIC_NUM_PINS;
> -#else
> -     return -ENOSYS;
> +     pthread_mutex_lock(&kvm->gsi_mutex);
> +     gsi = kvm_find_free_gsi(kvm);
> +     pthread_mutex_unlock(&kvm->gsi_mutex);
> +#endif
> +     return gsi;
> +}
> +
> +void kvm_free_irq_route_gsi(kvm_context_t kvm, int gsi)
> +{
> +#ifdef KVM_CAP_IRQ_ROUTING
> +     pthread_mutex_lock(&kvm->gsi_mutex);
> +     clear_bit(kvm->used_gsi_bitmap, gsi);
> +     pthread_mutex_unlock(&kvm->gsi_mutex);
>  #endif
>  }
>
> diff --git a/kvm/libkvm/libkvm.h b/kvm/libkvm/libkvm.h
> index 4821a1e..845bb8a 100644
> --- a/kvm/libkvm/libkvm.h
> +++ b/kvm/libkvm/libkvm.h
> @@ -856,6 +856,16 @@ int kvm_commit_irq_routes(kvm_context_t kvm);
>   */
>  int kvm_get_irq_route_gsi(kvm_context_t kvm);
>
> +/*!
> + * \brief Free used GSI number
> + *
> + * Free used GSI number acquired from kvm_get_irq_route_gsi()
> + *
> + * \param kvm Pointer to the current kvm_context
> + * \param gsi GSI number to free
> + */
> +void kvm_free_irq_route_gsi(kvm_context_t kvm, int gsi);
> +
>  #ifdef KVM_CAP_DEVICE_MSIX
>  int kvm_assign_set_msix_nr(kvm_context_t kvm,
>                          struct kvm_assigned_msix_nr *msix_nr);


--
To unsubscribe from this list: send the line "unsubscribe kvm" in
the body of a message to majord...@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html

Reply via email to