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.williamson@xxxxxx> > --- > > 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 majordomo@xxxxxxxxxxxxxxx More majordomo info at http://vger.kernel.org/majordomo-info.html