From patchwork Mon Feb 1 14:18:04 2010 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Joerg Roedel X-Patchwork-Id: 76082 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 o11EIpxe022118 for ; Mon, 1 Feb 2010 14:18:51 GMT Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1754761Ab0BAOS0 (ORCPT ); Mon, 1 Feb 2010 09:18:26 -0500 Received: from va3ehsobe003.messaging.microsoft.com ([216.32.180.13]:8329 "EHLO VA3EHSOBE003.bigfish.com" rhost-flags-OK-OK-OK-FAIL) by vger.kernel.org with ESMTP id S1753860Ab0BAOSZ (ORCPT ); Mon, 1 Feb 2010 09:18:25 -0500 Received: from mail57-va3-R.bigfish.com (10.7.14.241) by VA3EHSOBE003.bigfish.com (10.7.40.23) with Microsoft SMTP Server id 8.1.240.5; Mon, 1 Feb 2010 14:18:24 +0000 Received: from mail57-va3 (localhost [127.0.0.1]) by mail57-va3-R.bigfish.com (Postfix) with ESMTP id 69ED1A60461; Mon, 1 Feb 2010 14:18:23 +0000 (UTC) X-SpamScore: -13 X-BigFish: VPS-13(z1857rz146fKab9bh1432R98dN936eMzz1202hzzz32i6bh87h61h) X-Spam-TCS-SCL: 0:0 X-FB-DOMAIN-IP-MATCH: fail Received: from mail57-va3 (localhost.localdomain [127.0.0.1]) by mail57-va3 (MessageSwitch) id 1265033897548439_32641; Mon, 1 Feb 2010 14:18:17 +0000 (UTC) Received: from VA3EHSMHS029.bigfish.com (unknown [10.7.14.251]) by mail57-va3.bigfish.com (Postfix) with ESMTP id 9D97757804C; Mon, 1 Feb 2010 14:18:16 +0000 (UTC) Received: from ausb3extmailp02.amd.com (163.181.251.22) by VA3EHSMHS029.bigfish.com (10.7.99.39) with Microsoft SMTP Server (TLS) id 14.0.482.39; Mon, 1 Feb 2010 14:18:14 +0000 Received: from ausb3twp01.amd.com (ausb3twp01.amd.com [163.181.250.37]) by ausb3extmailp02.amd.com (Switch-3.2.7/Switch-3.2.7) with ESMTP id o11EJnGW015614; Mon, 1 Feb 2010 08:19:52 -0600 X-WSS-ID: 0KX62E4-01-9V3-02 X-M-MSG: Received: from sausexbh1.amd.com (sausexbh1.amd.com [163.181.22.101]) by ausb3twp01.amd.com (Tumbleweed MailGate 3.7.2) with ESMTP id 28C74102870D; Mon, 1 Feb 2010 08:18:03 -0600 (CST) Received: from sausexmb1.amd.com ([163.181.3.156]) by sausexbh1.amd.com with Microsoft SMTPSVC(6.0.3790.3959); Mon, 1 Feb 2010 08:18:07 -0600 Received: from seurexmb1.amd.com ([165.204.9.130]) by sausexmb1.amd.com with Microsoft SMTPSVC(6.0.3790.3959); Mon, 1 Feb 2010 08:18:07 -0600 Received: from lemmy.osrc.amd.com ([165.204.15.93]) by seurexmb1.amd.com with Microsoft SMTPSVC(6.0.3790.3959); Mon, 1 Feb 2010 15:18:04 +0100 Received: by lemmy.osrc.amd.com (Postfix, from userid 41430) id B4679C9AE6; Mon, 1 Feb 2010 15:18:04 +0100 (CET) Date: Mon, 1 Feb 2010 15:18:04 +0100 From: Joerg Roedel To: Joerg Roedel CC: Marcelo Tosatti , Avi Kivity , David Woodhouse , kvm@vger.kernel.org, iommu@lists.linux-foundation.org, linux-kernel@vger.kernel.org Subject: Re: [PATCH 06/11] kvm: Change kvm_iommu_map_pages to map large pages Message-ID: <20100201141804.GD16236@amd.com> References: <1264678682-30655-1-git-send-email-joerg.roedel@amd.com> <1264678682-30655-7-git-send-email-joerg.roedel@amd.com> <20100128222455.GA26274@amt.cnet> <20100129093233.GU17809@8bytes.org> MIME-Version: 1.0 Content-Disposition: inline In-Reply-To: <20100129093233.GU17809@8bytes.org> Organization: Advanced Micro Devices =?iso-8859-1?Q?GmbH?= =?iso-8859-1?Q?=2C_Karl-Hammerschmidt-Str=2E_34=2C_85609_Dornach_bei_M=FC?= =?iso-8859-1?Q?nchen=2C_Gesch=E4ftsf=FChrer=3A_Thomas_M=2E_McCoy=2C_Giuli?= =?iso-8859-1?Q?ano_Meroni=2C_Andrew_Bowd=2C_Sitz=3A_Dornach=2C_Gemeinde_A?= =?iso-8859-1?Q?schheim=2C_Landkreis_M=FCnchen=2C_Registergericht_M=FCnche?= =?iso-8859-1?Q?n=2C?= HRB Nr. 43632 User-Agent: Mutt/1.5.20 (2009-06-14) X-OriginalArrivalTime: 01 Feb 2010 14:18:04.0872 (UTC) FILETIME=[5E9C4480:01CAA349] X-Reverse-DNS: ausb3extmailp02.amd.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]); Mon, 01 Feb 2010 14:18:51 +0000 (UTC) diff --git a/virt/kvm/iommu.c b/virt/kvm/iommu.c index 65a5143..f78286e 100644 --- a/virt/kvm/iommu.c +++ b/virt/kvm/iommu.c @@ -32,12 +32,30 @@ static int kvm_iommu_unmap_memslots(struct kvm *kvm); static void kvm_iommu_put_pages(struct kvm *kvm, gfn_t base_gfn, unsigned long npages); +static pfn_t kvm_pin_pages(struct kvm *kvm, struct kvm_memory_slot *slot, + gfn_t gfn, unsigned long size) +{ + gfn_t end_gfn; + pfn_t pfn; + + pfn = gfn_to_pfn_memslot(kvm, slot, gfn); + end_gfn = gfn + (size >> PAGE_SHIFT); + gfn += 1; + + if (is_error_pfn(pfn)) + return pfn; + + while (gfn < end_gfn) + gfn_to_pfn_memslot(kvm, slot, gfn++); + + return pfn; +} + int kvm_iommu_map_pages(struct kvm *kvm, struct kvm_memory_slot *slot) { - gfn_t gfn = slot->base_gfn; - unsigned long npages = slot->npages; + gfn_t gfn, end_gfn; pfn_t pfn; - int i, r = 0; + int r = 0; struct iommu_domain *domain = kvm->arch.iommu_domain; int flags; @@ -45,31 +63,62 @@ int kvm_iommu_map_pages(struct kvm *kvm, struct kvm_memory_slot *slot) if (!domain) return 0; + gfn = slot->base_gfn; + end_gfn = gfn + slot->npages; + flags = IOMMU_READ | IOMMU_WRITE; if (kvm->arch.iommu_flags & KVM_IOMMU_CACHE_COHERENCY) flags |= IOMMU_CACHE; - for (i = 0; i < npages; i++) { - /* check if already mapped */ - if (iommu_iova_to_phys(domain, gfn_to_gpa(gfn))) + + while (gfn < end_gfn) { + unsigned long page_size; + + /* Check if already mapped */ + if (iommu_iova_to_phys(domain, gfn_to_gpa(gfn))) { + gfn += 1; + continue; + } + + /* Get the page size we could use to map */ + page_size = kvm_host_page_size(kvm, gfn); + + /* Make sure the page_size does not exceed the memslot */ + while ((gfn + (page_size >> PAGE_SHIFT)) > end_gfn) + page_size >>= 1; + + /* Make sure gfn is aligned to the page size we want to map */ + while ((gfn << PAGE_SHIFT) & (page_size - 1)) + page_size >>= 1; + + /* + * Pin all pages we are about to map in memory. This is + * important because we unmap and unpin in 4kb steps later. + */ + pfn = kvm_pin_pages(kvm, slot, gfn, page_size); + if (is_error_pfn(pfn)) { + gfn += 1; continue; + } - pfn = gfn_to_pfn_memslot(kvm, slot, gfn); - r = iommu_map_range(domain, - gfn_to_gpa(gfn), - pfn_to_hpa(pfn), - PAGE_SIZE, flags); + /* Map into IO address space */ + r = iommu_map(domain, gfn_to_gpa(gfn), pfn_to_hpa(pfn), + get_order(page_size), flags); if (r) { printk(KERN_ERR "kvm_iommu_map_address:" "iommu failed to map pfn=%lx\n", pfn); goto unmap_pages; } - gfn++; + + gfn += page_size >> PAGE_SHIFT; + + } + return 0; unmap_pages: - kvm_iommu_put_pages(kvm, slot->base_gfn, i); + kvm_iommu_put_pages(kvm, slot->base_gfn, gfn); return r; } @@ -186,27 +235,47 @@ out_unmap: return r; } +static void kvm_unpin_pages(struct kvm *kvm, pfn_t pfn, unsigned long npages) +{ + unsigned long i; + + for (i = 0; i < npages; ++i) + kvm_release_pfn_clean(pfn + i); +} + static void kvm_iommu_put_pages(struct kvm *kvm, gfn_t base_gfn, unsigned long npages) { - gfn_t gfn = base_gfn; + struct iommu_domain *domain; + gfn_t end_gfn, gfn; pfn_t pfn; - struct iommu_domain *domain = kvm->arch.iommu_domain; - unsigned long i; u64 phys; + domain = kvm->arch.iommu_domain; + end_gfn = base_gfn + npages; + gfn = base_gfn; + /* check if iommu exists and in use */ if (!domain) return; - for (i = 0; i < npages; i++) { + while (gfn < end_gfn) { + unsigned long unmap_pages; + int order; + + /* Get physical address */ phys = iommu_iova_to_phys(domain, gfn_to_gpa(gfn)); - pfn = phys >> PAGE_SHIFT; - kvm_release_pfn_clean(pfn); - gfn++; - } + pfn = phys >> PAGE_SHIFT; + + /* Unmap address from IO address space */ + order = iommu_unmap(domain, gfn_to_gpa(gfn), PAGE_SIZE); + unmap_pages = 1ULL << order; - iommu_unmap_range(domain, gfn_to_gpa(base_gfn), PAGE_SIZE * npages); + /* Unpin all pages we just unmapped to not leak any memory */ + kvm_unpin_pages(kvm, pfn, unmap_pages); + + gfn += unmap_pages; + } } static int kvm_iommu_unmap_memslots(struct kvm *kvm)