From patchwork Fri Jul 24 09:03:09 2015 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: PranavkumarSawargaonkar X-Patchwork-Id: 6858521 Return-Path: X-Original-To: patchwork-linux-arm@patchwork.kernel.org Delivered-To: patchwork-parsemail@patchwork1.web.kernel.org Received: from mail.kernel.org (mail.kernel.org [198.145.29.136]) by patchwork1.web.kernel.org (Postfix) with ESMTP id E9BA39F358 for ; Fri, 24 Jul 2015 09:10:09 +0000 (UTC) Received: from mail.kernel.org (localhost [127.0.0.1]) by mail.kernel.org (Postfix) with ESMTP id E26E520603 for ; Fri, 24 Jul 2015 09:10:08 +0000 (UTC) Received: from bombadil.infradead.org (bombadil.infradead.org [198.137.202.9]) (using TLSv1.2 with cipher AES128-GCM-SHA256 (128/128 bits)) (No client certificate requested) by mail.kernel.org (Postfix) with ESMTPS id C584E205BD for ; Fri, 24 Jul 2015 09:10:07 +0000 (UTC) Received: from localhost ([127.0.0.1] helo=bombadil.infradead.org) by bombadil.infradead.org with esmtp (Exim 4.80.1 #2 (Red Hat Linux)) id 1ZIYxS-0001EY-FJ; Fri, 24 Jul 2015 09:07:58 +0000 Received: from mail-pa0-f45.google.com ([209.85.220.45]) by bombadil.infradead.org with esmtps (Exim 4.80.1 #2 (Red Hat Linux)) id 1ZIYtU-0004JC-Fb for linux-arm-kernel@lists.infradead.org; Fri, 24 Jul 2015 09:04:07 +0000 Received: by pabkd10 with SMTP id kd10so11344151pab.2 for ; Fri, 24 Jul 2015 02:03:30 -0700 (PDT) X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20130820; h=x-gm-message-state:from:to:cc:subject:date:message-id:in-reply-to :references; bh=yRjcB1FWGds6i11ba0NsZ4usQhc5Rm82HoZjFdvpb3Y=; b=RhO9IzRlRBPtNQA7biD/oa4eAIpNFcmhOAGv/H5AxM9ihVA3vhR8ISfoXZrtvgKuZc X5bVeZqCfo4db3Wm0NfvL2iGcULhTGBF9/07q4Nn+TCXhLSG2q8H75WDU0bL0ZNLNvzH QaKX3FW9azRzqmHQtnbl/d/kNw1pjE+ZaMknGhM1dlNQO4O/w1VQZXNZ3X/9YjBpQsje +Au41lJkuILJQDR3RErIPcFS2reCDF+N4FpA/5K2Kfg6ZSJJD8v5woQBxNwUeOHcxwE6 SxrHDL723E6bZ4PtweYh05TpgK85KCYSIg8OHNp1A8bJgZb4QpaRUorpj7llp679xFyq vE8A== X-Gm-Message-State: ALoCoQkf0wr/mw5In04FrLvGTZWohfE7zb/n7DXRUquMtsZMRebnsvBCeXUt/smcqWHA0AMWgeo4 X-Received: by 10.70.108.137 with SMTP id hk9mr28826130pdb.105.1437728610847; Fri, 24 Jul 2015 02:03:30 -0700 (PDT) Received: from pnqlab006.amcc.com ([182.73.239.130]) by smtp.gmail.com with ESMTPSA id wp5sm13346655pab.22.2015.07.24.02.03.26 (version=TLSv1.1 cipher=ECDHE-RSA-RC4-SHA bits=128/128); Fri, 24 Jul 2015 02:03:30 -0700 (PDT) From: Pranavkumar Sawargaonkar To: kvm@vger.kernel.org, kvmarm@lists.cs.columbia.edu Subject: [RFC 1/2] drivers: vfio: iommu map and unmap device specific memory from kernel. Date: Fri, 24 Jul 2015 14:33:09 +0530 Message-Id: <1437728590-23126-2-git-send-email-pranavkumar@linaro.org> X-Mailer: git-send-email 1.7.9.5 In-Reply-To: <1437728590-23126-1-git-send-email-pranavkumar@linaro.org> References: <1437728590-23126-1-git-send-email-pranavkumar@linaro.org> X-CRM114-Version: 20100106-BlameMichelson ( TRE 0.8.0 (BSD) ) MR-646709E3 X-CRM114-CacheID: sfid-20150724_020353_207026_C0010933 X-CRM114-Status: GOOD ( 17.15 ) X-Spam-Score: -2.6 (--) X-BeenThere: linux-arm-kernel@lists.infradead.org X-Mailman-Version: 2.1.20 Precedence: list List-Id: List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Cc: rob.herring@linaro.org, arnd@arndb.de, eric.auger@linaro.org, marc.zyngier@arm.com, patches@apm.com, will.deacon@arm.com, linux-kernel@vger.kernel.org, alex.williamson@redhat.com, linux-arm-kernel@lists.infradead.org, bhelgaas@google.com, Ankit Jindal , christoffer.dall@linaro.org, Pranavkumar Sawargaonkar MIME-Version: 1.0 Sender: "linux-arm-kernel" Errors-To: linux-arm-kernel-bounces+patchwork-linux-arm=patchwork.kernel.org@lists.infradead.org X-Spam-Status: No, score=-5.4 required=5.0 tests=BAYES_00, RCVD_IN_DNSWL_MED, RP_MATCHES_RCVD, UNPARSEABLE_RELAY autolearn=unavailable version=3.3.1 X-Spam-Checker-Version: SpamAssassin 3.3.1 (2010-03-16) on mail.kernel.org X-Virus-Scanned: ClamAV using ClamSMTP In vfio we map and unmap various regions using "VFIO_IOMMU_MAP_DMA" and "VFIO_IOMMU_UNMAP_DMA" ioctls from userspace. Some device regions (like MSI in case of PCI), which we do not expose to the userspace with mmap. These regions might require vfio driver to create an iommu mapping, as their transactions goes through an iommu like in case of ARM/ARM64. As the memory is not mmaped in userspace and might needs to be mapped with different memory attributes than user memory, we can not use VFIO_IOMMU_MAP_DMA and VFIO_IOMMU_UNMAP_DMA ioctls. This patch extends "vfio_iommu_driver_ops" to provide - device_map() and device_unmap() methods by vfio iommu driver. These methods can be used by other vfio device drivers like PCI, to create and destroy simple iommu mappings for regions like MSI/MSI-X. This patch also implements these methods for vfio iommu type1 driver. Signed-off-by: Ankit Jindal Signed-off-by: Pranavkumar Sawargaonkar Cc: Alex Williamson Cc: Marc Zyngier Cc: Will Deacon Cc: Christoffer Dall --- drivers/vfio/vfio.c | 29 +++++++++++++++++++ drivers/vfio/vfio_iommu_type1.c | 60 +++++++++++++++++++++++++++++++++++++++ include/linux/vfio.h | 11 ++++++- 3 files changed, 99 insertions(+), 1 deletion(-) diff --git a/drivers/vfio/vfio.c b/drivers/vfio/vfio.c index 2fb29df..7897c47 100644 --- a/drivers/vfio/vfio.c +++ b/drivers/vfio/vfio.c @@ -143,6 +143,35 @@ void vfio_unregister_iommu_driver(const struct vfio_iommu_driver_ops *ops) } EXPORT_SYMBOL_GPL(vfio_unregister_iommu_driver); +int vfio_device_iommu_map(struct vfio_device *device, unsigned long iova, + phys_addr_t paddr, size_t size, int prot) +{ + struct vfio_container *container = device->group->container; + const struct vfio_iommu_driver_ops *ops = container->iommu_driver->ops; + int ret; + + if (!ops->device_map) + return -EINVAL; + + ret = ops->device_map(container->iommu_data, iova, paddr, size, prot); + + return ret; +} +EXPORT_SYMBOL_GPL(vfio_device_iommu_map); + +void vfio_device_iommu_unmap(struct vfio_device *device, unsigned long iova, + size_t size) +{ + struct vfio_container *container = device->group->container; + const struct vfio_iommu_driver_ops *ops = container->iommu_driver->ops; + + if (!ops->device_unmap) + return; + + ops->device_unmap(container->iommu_data, iova, size); +} +EXPORT_SYMBOL_GPL(vfio_device_iommu_unmap); + /** * Group minor allocation/free - both called with vfio.group_lock held */ diff --git a/drivers/vfio/vfio_iommu_type1.c b/drivers/vfio/vfio_iommu_type1.c index 57d8c37..e41995d 100644 --- a/drivers/vfio/vfio_iommu_type1.c +++ b/drivers/vfio/vfio_iommu_type1.c @@ -1025,6 +1025,64 @@ static long vfio_iommu_type1_ioctl(void *iommu_data, return -ENOTTY; } +static int vfio_iommu_type1_device_map(void *iommu_data, unsigned long iova, + phys_addr_t paddr, size_t size, + int prot) +{ + struct vfio_iommu *iommu = iommu_data; + struct vfio_domain *d; + int ret; + + mutex_lock(&iommu->lock); + + list_for_each_entry(d, &iommu->domain_list, next) { + + if (iommu_iova_to_phys(d->domain, iova)) + continue; + + ret = iommu_map(d->domain, iova, paddr, + size, prot | d->prot); + + if (ret) { + if (ret != -EBUSY) + goto unwind; + } + + cond_resched(); + } + + mutex_unlock(&iommu->lock); + + return 0; + +unwind: + list_for_each_entry_continue_reverse(d, &iommu->domain_list, next) + iommu_unmap(d->domain, iova, size); + + mutex_unlock(&iommu->lock); + return ret; +} + +static void vfio_iommu_type1_device_unmap(void *iommu_data, unsigned long iova, + size_t size) +{ + struct vfio_iommu *iommu = iommu_data; + struct vfio_domain *d; + + mutex_lock(&iommu->lock); + + list_for_each_entry(d, &iommu->domain_list, next) { + + if (!iommu_iova_to_phys(d->domain, iova)) + continue; + + iommu_unmap(d->domain, iova, size); + cond_resched(); + } + + mutex_unlock(&iommu->lock); +} + static const struct vfio_iommu_driver_ops vfio_iommu_driver_ops_type1 = { .name = "vfio-iommu-type1", .owner = THIS_MODULE, @@ -1033,6 +1091,8 @@ static const struct vfio_iommu_driver_ops vfio_iommu_driver_ops_type1 = { .ioctl = vfio_iommu_type1_ioctl, .attach_group = vfio_iommu_type1_attach_group, .detach_group = vfio_iommu_type1_detach_group, + .device_map = vfio_iommu_type1_device_map, + .device_unmap = vfio_iommu_type1_device_unmap, }; static int __init vfio_iommu_type1_init(void) diff --git a/include/linux/vfio.h b/include/linux/vfio.h index ddb4409..ef0d974 100644 --- a/include/linux/vfio.h +++ b/include/linux/vfio.h @@ -52,6 +52,12 @@ extern void *vfio_del_group_dev(struct device *dev); extern struct vfio_device *vfio_device_get_from_dev(struct device *dev); extern void vfio_device_put(struct vfio_device *device); extern void *vfio_device_data(struct vfio_device *device); +extern int vfio_device_iommu_map(struct vfio_device *device, + unsigned long iova, + phys_addr_t paddr, + size_t size, int prot); +extern void vfio_device_iommu_unmap(struct vfio_device *device, + unsigned long iova, size_t size); /** * struct vfio_iommu_driver_ops - VFIO IOMMU driver callbacks @@ -72,7 +78,10 @@ struct vfio_iommu_driver_ops { struct iommu_group *group); void (*detach_group)(void *iommu_data, struct iommu_group *group); - + int (*device_map)(void *iommu_data, unsigned long iova, + phys_addr_t paddr, size_t size, int prot); + void (*device_unmap)(void *iommu_data, unsigned long iova, + size_t size); }; extern int vfio_register_iommu_driver(const struct vfio_iommu_driver_ops *ops);