From patchwork Fri Jan 21 23:48:42 2011 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Alex Williamson X-Patchwork-Id: 497071 Received: from vger.kernel.org (vger.kernel.org [209.132.180.67]) by demeter1.kernel.org (8.14.4/8.14.3) with ESMTP id p0LNmV7O003330 for ; Fri, 21 Jan 2011 23:48:58 GMT Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1754778Ab1AUXsp (ORCPT ); Fri, 21 Jan 2011 18:48:45 -0500 Received: from mx1.redhat.com ([209.132.183.28]:28486 "EHLO mx1.redhat.com" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1754462Ab1AUXsp (ORCPT ); Fri, 21 Jan 2011 18:48:45 -0500 Received: from int-mx10.intmail.prod.int.phx2.redhat.com (int-mx10.intmail.prod.int.phx2.redhat.com [10.5.11.23]) by mx1.redhat.com (8.13.8/8.13.8) with ESMTP id p0LNmh1V021573 (version=TLSv1/SSLv3 cipher=DHE-RSA-AES256-SHA bits=256 verify=OK); Fri, 21 Jan 2011 18:48:43 -0500 Received: from s20.home (ovpn01.gateway.prod.ext.phx2.redhat.com [10.5.9.1]) by int-mx10.intmail.prod.int.phx2.redhat.com (8.14.4/8.14.4) with ESMTP id p0LNmgoJ027184; Fri, 21 Jan 2011 18:48:42 -0500 From: Alex Williamson Subject: [RFC PATCH 2/2] device-assignment: Count required kvm memory slots To: kvm@vger.kernel.org Cc: alex.williamson@redhat.com, ddutile@redhat.com, mst@redhat.com, avi@redhat.com, chrisw@redhat.com, jan.kiszka@siemens.com Date: Fri, 21 Jan 2011 16:48:42 -0700 Message-ID: <20110121234831.22262.31177.stgit@s20.home> In-Reply-To: <20110121233040.22262.68117.stgit@s20.home> References: <20110121233040.22262.68117.stgit@s20.home> User-Agent: StGIT/0.14.3 MIME-Version: 1.0 X-Scanned-By: MIMEDefang 2.68 on 10.5.11.23 Sender: kvm-owner@vger.kernel.org Precedence: bulk List-ID: X-Mailing-List: kvm@vger.kernel.org X-Greylist: IP, sender and recipient auto-whitelisted, not delayed by milter-greylist-4.2.6 (demeter1.kernel.org [140.211.167.41]); Fri, 21 Jan 2011 23:48:59 +0000 (UTC) diff --git a/hw/device-assignment.c b/hw/device-assignment.c index e97f565..0063a11 100644 --- a/hw/device-assignment.c +++ b/hw/device-assignment.c @@ -546,7 +546,9 @@ static int assigned_dev_register_regions(PCIRegion *io_regions, ? PCI_BASE_ADDRESS_MEM_PREFETCH : PCI_BASE_ADDRESS_SPACE_MEMORY; - if (cur_region->size & 0xFFF) { + if (pci_dev->features & ASSIGNED_DEVICE_FORCE_SLOW_MASK) { + slow_map = 1; + } else if (cur_region->size & 0xFFF) { fprintf(stderr, "PCI region %d at address 0x%llx " "has size 0x%x, which is not a multiple of 4K. " "You might experience some performance hit " @@ -556,6 +558,10 @@ static int assigned_dev_register_regions(PCIRegion *io_regions, slow_map = 1; } + if (!slow_map) { + pci_dev->slots_needed++; + } + /* map physical memory */ pci_dev->v_addrs[i].e_physbase = cur_region->base_addr; pci_dev->v_addrs[i].u.r_virtbase = mmap(NULL, cur_region->size, @@ -1666,6 +1672,30 @@ static CPUReadMemoryFunc *msix_mmio_read[] = { static int assigned_dev_register_msix_mmio(AssignedDevice *dev) { + int i; + PCIRegion *pci_region = dev->real_device.regions; + + /* Determine if the MSI-X table splits a BAR, requiring the use of + * two memory slots, one to map each remaining part. */ + if (!(dev->features & ASSIGNED_DEVICE_FORCE_SLOW_MASK)) { + for (i = 0; i < dev->real_device.region_number; i++, pci_region++) { + if (!pci_region->valid) { + continue; + } + + if (ranges_overlap(pci_region->base_addr, pci_region->size, + dev->msix_table_addr, 0x1000)) { + target_phys_addr_t offset; + + offset = dev->msix_table_addr - pci_region->base_addr; + if (offset && pci_region->size > offset + 0x1000) { + dev->slots_needed++; + } + break; + } + } + } + dev->msix_table_page = mmap(NULL, 0x1000, PROT_READ|PROT_WRITE, MAP_ANONYMOUS|MAP_PRIVATE, 0, 0); @@ -1768,6 +1798,31 @@ static int assigned_initfn(struct PCIDevice *pci_dev) if (assigned_dev_register_msix_mmio(dev)) goto assigned_out; + if (!(dev->features & ASSIGNED_DEVICE_FORCE_SLOW_MASK)) { + int free_slots = kvm_free_slots(); + int total_slots = dev->slots_needed; + + if (!dev->dev.qdev.hotplugged) { + AssignedDevice *adev; + + QLIST_FOREACH(adev, &devs, next) { + total_slots += adev->slots_needed; + } + + /* This seems to work, but it's completely heuristically + * determined. Any number of things might make use of kvm + * memory slots before the guest starts mapping memory BARs. + * This is really just a guess. */ + free_slots -= 13; + } + + if (total_slots > free_slots) { + error_report("pci-assign: Out of memory slots, need %d, have %d\n", + total_slots, free_slots); + goto assigned_out; + } + } + assigned_dev_load_option_rom(dev); QLIST_INSERT_HEAD(&devs, dev, next); @@ -1837,6 +1892,8 @@ static PCIDeviceInfo assign_info = { ASSIGNED_DEVICE_USE_IOMMU_BIT, true), DEFINE_PROP_BIT("prefer_msi", AssignedDevice, features, ASSIGNED_DEVICE_PREFER_MSI_BIT, true), + DEFINE_PROP_BIT("force_slow", AssignedDevice, features, + ASSIGNED_DEVICE_FORCE_SLOW_BIT, false), DEFINE_PROP_STRING("configfd", AssignedDevice, configfd_name), DEFINE_PROP_END_OF_LIST(), }, diff --git a/hw/device-assignment.h b/hw/device-assignment.h index c94a730..ad3cc80 100644 --- a/hw/device-assignment.h +++ b/hw/device-assignment.h @@ -76,9 +76,11 @@ typedef struct { #define ASSIGNED_DEVICE_USE_IOMMU_BIT 0 #define ASSIGNED_DEVICE_PREFER_MSI_BIT 1 +#define ASSIGNED_DEVICE_FORCE_SLOW_BIT 2 #define ASSIGNED_DEVICE_USE_IOMMU_MASK (1 << ASSIGNED_DEVICE_USE_IOMMU_BIT) #define ASSIGNED_DEVICE_PREFER_MSI_MASK (1 << ASSIGNED_DEVICE_PREFER_MSI_BIT) +#define ASSIGNED_DEVICE_FORCE_SLOW_MASK (1 << ASSIGNED_DEVICE_FORCE_SLOW_BIT) typedef struct AssignedDevice { PCIDevice dev; @@ -111,6 +113,7 @@ typedef struct AssignedDevice { int mmio_index; int need_emulate_cmd; char *configfd_name; + int slots_needed; QLIST_ENTRY(AssignedDevice) next; } AssignedDevice;