From patchwork Wed Feb 17 09:43:26 2010 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: borove@il.ibm.com X-Patchwork-Id: 79849 Received: from vger.kernel.org (vger.kernel.org [209.132.180.67]) by demeter.kernel.org (8.14.3/8.14.3) with ESMTP id o1H9hblb004544 for ; Wed, 17 Feb 2010 09:43:38 GMT Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S932959Ab0BQJne (ORCPT ); Wed, 17 Feb 2010 04:43:34 -0500 Received: from mtagate7.de.ibm.com ([195.212.17.167]:42467 "EHLO mtagate7.de.ibm.com" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S932888Ab0BQJna (ORCPT ); Wed, 17 Feb 2010 04:43:30 -0500 Received: from d12nrmr1607.megacenter.de.ibm.com (d12nrmr1607.megacenter.de.ibm.com [9.149.167.49]) by mtagate7.de.ibm.com (8.13.1/8.13.1) with ESMTP id o1H9hTO5027976 for ; Wed, 17 Feb 2010 09:43:29 GMT Received: from d12av01.megacenter.de.ibm.com (d12av01.megacenter.de.ibm.com [9.149.165.212]) by d12nrmr1607.megacenter.de.ibm.com (8.13.8/8.13.8/NCO v10.0) with ESMTP id o1H9hTk21056902 for ; Wed, 17 Feb 2010 10:43:29 +0100 Received: from d12av01.megacenter.de.ibm.com (loopback [127.0.0.1]) by d12av01.megacenter.de.ibm.com (8.12.11.20060308/8.13.3) with ESMTP id o1H9hSTV012235 for ; Wed, 17 Feb 2010 10:43:28 +0100 Received: from localhost.localdomain (cluwyn.haifa.ibm.com [9.148.27.75]) by d12av01.megacenter.de.ibm.com (8.12.11.20060308/8.12.11) with ESMTP id o1H9hRl5012216; Wed, 17 Feb 2010 10:43:28 +0100 From: borove@il.ibm.com To: kvm@vger.kernel.org Cc: borove@il.ibm.com, benami@il.ibm.com Subject: [RFC] KVM: Balloon support for device assignment Date: Wed, 17 Feb 2010 11:43:26 +0200 Message-Id: <1266399807-4498-2-git-send-email-borove@il.ibm.com> X-Mailer: git-send-email 1.6.0.4 In-Reply-To: <1266399807-4498-1-git-send-email-borove@il.ibm.com> References: <1266399807-4498-1-git-send-email-borove@il.ibm.com> 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.3 (demeter.kernel.org [140.211.167.41]); Wed, 17 Feb 2010 09:43:38 +0000 (UTC) diff --git a/include/linux/kvm.h b/include/linux/kvm.h index f8f8900..567f5f8 100644 --- a/include/linux/kvm.h +++ b/include/linux/kvm.h @@ -514,6 +514,9 @@ struct kvm_irqfd { struct kvm_userspace_memory_region) #define KVM_SET_TSS_ADDR _IO(KVMIO, 0x47) #define KVM_SET_IDENTITY_MAP_ADDR _IOW(KVMIO, 0x48, __u64) +#define KVM_IOMMU_UNMAP_PAGE _IOW(KVMIO, 0x49, __u64) +#define KVM_IOMMU_MAP_PAGE _IOW(KVMIO, 0x50, __u64) + /* Device model IOC */ #define KVM_CREATE_IRQCHIP _IO(KVMIO, 0x60) #define KVM_IRQ_LINE _IOW(KVMIO, 0x61, struct kvm_irq_level) diff --git a/include/linux/kvm_host.h b/include/linux/kvm_host.h index b7bbb5d..ad904ec 100644 --- a/include/linux/kvm_host.h +++ b/include/linux/kvm_host.h @@ -411,6 +411,10 @@ int kvm_assign_device(struct kvm *kvm, struct kvm_assigned_dev_kernel *assigned_dev); int kvm_deassign_device(struct kvm *kvm, struct kvm_assigned_dev_kernel *assigned_dev); +void kvm_iommu_unmap_page(struct kvm *kvm, + gfn_t base_gfn); +int kvm_iommu_map_page(struct kvm *kvm, + gfn_t base_gfn); #else /* CONFIG_IOMMU_API */ static inline int kvm_iommu_map_pages(struct kvm *kvm, gfn_t base_gfn, diff --git a/virt/kvm/iommu.c b/virt/kvm/iommu.c index 1514758..54cfd33 100644 --- a/virt/kvm/iommu.c +++ b/virt/kvm/iommu.c @@ -190,23 +190,101 @@ static void kvm_iommu_put_pages(struct kvm *kvm, gfn_t gfn = base_gfn; pfn_t pfn; struct iommu_domain *domain = kvm->arch.iommu_domain; - unsigned long i; + unsigned long i, iommu_pages; u64 phys; /* check if iommu exists and in use */ if (!domain) return; - for (i = 0; i < npages; i++) { + for (i = 0, iommu_pages = 0; i < npages; i++, gfn++) { phys = iommu_iova_to_phys(domain, gfn_to_gpa(gfn)); + + /*Because of ballooning, there can be holes in the + range. In that case, we simply unmap everything + till now, and continue forward. + */ + if (!phys) { + + /*No consecutive IOMMU pages here*/ + if (iommu_pages == 0) + continue; + iommu_unmap_range(domain, + gfn_to_gpa(base_gfn), + PAGE_SIZE*iommu_pages); + + /*Reset consequtive iommu range counters*/ + base_gfn = gfn + 1; + iommu_pages = 0; + continue; + } pfn = phys >> PAGE_SHIFT; kvm_release_pfn_clean(pfn); - gfn++; + ++iommu_pages; } - iommu_unmap_range(domain, gfn_to_gpa(base_gfn), PAGE_SIZE * npages); + /*Unmap the last iommu range if any*/ + if (iommu_pages != 0) + iommu_unmap_range(domain, + gfn_to_gpa(base_gfn), + PAGE_SIZE * iommu_pages); +} + +/*Called to map a page from IOMMU */ +int kvm_iommu_map_page(struct kvm *kvm, + gfn_t base_gfn) +{ + gfn_t gfn = base_gfn; + pfn_t pfn; + struct iommu_domain *domain = kvm->arch.iommu_domain; + u64 phys; + int rc; + int flags; + + /* check if iommu exists and in use */ + if (!domain) + return 0; + phys = iommu_iova_to_phys(domain, gfn_to_gpa(gfn)); + + /*Verify addres is not mapped already*/ + if (phys) + return 0; + flags = IOMMU_READ | IOMMU_WRITE; + if (kvm->arch.iommu_flags & KVM_IOMMU_CACHE_COHERENCY) + flags |= IOMMU_CACHE; + pfn = gfn_to_pfn(kvm, gfn); + rc = iommu_map_range(domain, + gfn_to_gpa(gfn), + pfn_to_hpa(pfn), + PAGE_SIZE, flags); + return rc; +} + + + +/*Called to unmap a page from IOMMU */ +void kvm_iommu_unmap_page(struct kvm *kvm, + gfn_t base_gfn) +{ + gfn_t gfn = base_gfn; + pfn_t pfn; + struct iommu_domain *domain = kvm->arch.iommu_domain; + u64 phys; + + /* check if iommu exists and in use */ + if (!domain) + return; + phys = iommu_iova_to_phys(domain, gfn_to_gpa(gfn)); + + /*Verify addres is mapped*/ + if (!phys) + return; + pfn = phys >> PAGE_SHIFT; + kvm_release_pfn_clean(pfn); + iommu_unmap_range(domain, gfn_to_gpa(gfn), PAGE_SIZE); } + static int kvm_iommu_unmap_memslots(struct kvm *kvm) { int i; diff --git a/virt/kvm/kvm_main.c b/virt/kvm/kvm_main.c index 7495ce3..560a3ff 100644 --- a/virt/kvm/kvm_main.c +++ b/virt/kvm/kvm_main.c @@ -2184,6 +2184,15 @@ static long kvm_vm_ioctl(struct file *filp, r = -EOPNOTSUPP; break; } + case KVM_IOMMU_MAP_PAGE: { + r = kvm_iommu_map_page(kvm, arg); + break; + } + case KVM_IOMMU_UNMAP_PAGE:{ + kvm_iommu_unmap_page(kvm, arg); + r = 0; + break; + } #ifdef KVM_CAP_ASSIGN_DEV_IRQ case KVM_ASSIGN_DEV_IRQ: { struct kvm_assigned_irq assigned_irq;