From patchwork Fri May 8 22:31:21 2009 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Alex Williamson X-Patchwork-Id: 22680 Received: from vger.kernel.org (vger.kernel.org [209.132.176.167]) by demeter.kernel.org (8.14.2/8.14.2) with ESMTP id n48MVSr6025727 for ; Fri, 8 May 2009 22:31:28 GMT Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1753023AbZEHWbZ (ORCPT ); Fri, 8 May 2009 18:31:25 -0400 Received: (majordomo@vger.kernel.org) by vger.kernel.org id S1752619AbZEHWbZ (ORCPT ); Fri, 8 May 2009 18:31:25 -0400 Received: from g1t0026.austin.hp.com ([15.216.28.33]:3375 "EHLO g1t0026.austin.hp.com" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1752114AbZEHWbX (ORCPT ); Fri, 8 May 2009 18:31:23 -0400 Received: from g1t0039.austin.hp.com (g1t0039.austin.hp.com [16.236.32.45]) by g1t0026.austin.hp.com (Postfix) with ESMTP id D53C7C42D; Fri, 8 May 2009 22:31:24 +0000 (UTC) Received: from ldl.fc.hp.com (ldl.fc.hp.com [15.11.146.30]) by g1t0039.austin.hp.com (Postfix) with ESMTP id B860E34066; Fri, 8 May 2009 22:31:24 +0000 (UTC) Received: from localhost (ldl.fc.hp.com [127.0.0.1]) by ldl.fc.hp.com (Postfix) with ESMTP id 7304E39C003; Fri, 8 May 2009 16:31:24 -0600 (MDT) X-Virus-Scanned: Debian amavisd-new at ldl.fc.hp.com Received: from ldl.fc.hp.com ([127.0.0.1]) by localhost (ldl.fc.hp.com [127.0.0.1]) (amavisd-new, port 10024) with ESMTP id FW0pOXvHhYTo; Fri, 8 May 2009 16:31:22 -0600 (MDT) Received: from dl380g6-3.ned.telco.ned.telco (lart.fc.hp.com [15.11.146.31]) by ldl.fc.hp.com (Postfix) with ESMTP id BFE5E39C001; Fri, 8 May 2009 16:31:22 -0600 (MDT) From: Alex Williamson Subject: [PATCH v2] kvm: Use a bitmap for tracking used GSIs To: kvm@vger.kernel.org, sheng@linux.intel.com Cc: alex.williamson@hp.com Date: Fri, 08 May 2009 16:31:21 -0600 Message-ID: <20090508222925.5119.94814.stgit@dl380g6-3.ned.telco.ned.telco> In-Reply-To: <20090507222015.5216.18027.stgit@dl380g6-3.ned.telco.ned.telco> References: <20090507222015.5216.18027.stgit@dl380g6-3.ned.telco.ned.telco> User-Agent: StGIT/0.14.2 MIME-Version: 1.0 Sender: kvm-owner@vger.kernel.org Precedence: bulk List-ID: X-Mailing-List: kvm@vger.kernel.org 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 --- v2: Add a mutex around the bitmap to protect from races hw/device-assignment.c | 4 ++ kvm/libkvm/kvm-common.h | 4 ++ kvm/libkvm/libkvm.c | 82 ++++++++++++++++++++++++++++++++++++++++++----- kvm/libkvm/libkvm.h | 10 ++++++ 4 files changed, 89 insertions(+), 11 deletions(-) -- To unsubscribe from this list: send the line "unsubscribe kvm" in the body of a message to majordomo@vger.kernel.org More majordomo info at http://vger.kernel.org/majordomo-info.html diff --git a/hw/device-assignment.c b/hw/device-assignment.c index e06dd08..5bdae24 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 2a4165a..13a2c21 100644 --- a/kvm/libkvm/libkvm.c +++ b/kvm/libkvm/libkvm.c @@ -35,6 +35,7 @@ #include #include #include +#include #include "libkvm.h" #if defined(__x86_64__) || defined(__i386__) @@ -322,6 +323,9 @@ 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); +#endif return kvm; out_close: @@ -1298,8 +1302,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,20 +1406,82 @@ int kvm_commit_irq_routes(kvm_context_t kvm) #endif } +#ifdef KVM_CAP_IRQ_ROUTING +static inline void set_bit(unsigned int *buf, int bit) +{ + buf[bit >> 5] |= (1U << (bit & 0x1f)); +} + +static inline void clear_bit(unsigned int *buf, int bit) +{ + buf[bit >> 5] &= ~(1U << (bit & 0x1f)); +} + +static int kvm_find_free_gsi(kvm_context_t kvm) +{ + int i, bit, gsi; + unsigned int *buf = kvm->used_gsi_bitmap; + + for (i = 0; i < (kvm->max_gsi >> 5); i++) { + if (buf[i] != ~0U) + break; + } + + if (i == kvm->max_gsi >> 5) + return -ENOSPC; + + bit = ffs(~buf[i]); + if (!bit) + return -EAGAIN; + + gsi = (bit - 1) | (i << 5); + set_bit(buf, gsi); + return gsi; +} +#endif + int kvm_get_irq_route_gsi(kvm_context_t kvm) { #ifdef KVM_CAP_IRQ_ROUTING - if (kvm->max_used_gsi >= KVM_IOAPIC_NUM_PINS) { - if (kvm->max_used_gsi + 1 < kvm_get_gsi_count(kvm)) - return kvm->max_used_gsi + 1; - else - return -ENOSPC; - } else - return KVM_IOAPIC_NUM_PINS; + int gsi; + + pthread_mutex_lock(&kvm->gsi_mutex); + + if (!kvm->max_gsi) { + int i; + + /* Round the number of GSIs supported to a 4 byte + * value so we can search it using ints and ffs */ + i = kvm_get_gsi_count(kvm) & ~0x1f; + kvm->used_gsi_bitmap = malloc(i >> 3); + if (!kvm->used_gsi_bitmap) { + pthread_mutex_unlock(&kvm->gsi_mutex); + return -ENOMEM; + } + memset(kvm->used_gsi_bitmap, 0, i >> 3); + kvm->max_gsi = i; + + /* Mark all the IOAPIC pin GSIs as already used */ + for (i = 0; i <= KVM_IOAPIC_NUM_PINS; i++) + set_bit(kvm->used_gsi_bitmap, i); + } + + gsi = kvm_find_free_gsi(kvm); + pthread_mutex_unlock(&kvm->gsi_mutex); + return gsi; #else return -ENOSYS; #endif } + +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 +} #ifdef KVM_CAP_DEVICE_MSIX int kvm_assign_set_msix_nr(kvm_context_t kvm, diff --git a/kvm/libkvm/libkvm.h b/kvm/libkvm/libkvm.h index c23d37b..4e9344c 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);