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: 6858481 Return-Path: X-Original-To: patchwork-kvm@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 5AFF39F358 for ; Fri, 24 Jul 2015 09:04:31 +0000 (UTC) Received: from mail.kernel.org (localhost [127.0.0.1]) by mail.kernel.org (Postfix) with ESMTP id 551C820607 for ; Fri, 24 Jul 2015 09:04:30 +0000 (UTC) Received: from vger.kernel.org (vger.kernel.org [209.132.180.67]) by mail.kernel.org (Postfix) with ESMTP id 264CA20603 for ; Fri, 24 Jul 2015 09:04:29 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1754199AbbGXJDf (ORCPT ); Fri, 24 Jul 2015 05:03:35 -0400 Received: from mail-pa0-f51.google.com ([209.85.220.51]:36811 "EHLO mail-pa0-f51.google.com" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1753893AbbGXJDb (ORCPT ); Fri, 24 Jul 2015 05:03:31 -0400 Received: by pachj5 with SMTP id hj5so11305219pac.3 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=ffWKX6CzsN0AodBTgx5BPWtyHrRB9JhIWIFxeEGqHusFeNTDZjdlP1+YIYJv8oLOHs FYiKYxQHg3xrcasY3wRWj0NfNrdqc8XsyA08uaQM9KP669/ISw8zpGXk5kWSIMNfnXXg Kkp0geP0iONIiZy2t6hYssPiDgEuXdwzRhSEyfV8gispGdpt3sBQB1bxUr880YIlV99G hEbhR+/R2pKT2cmCOkNfwCohcKW720WRRFi+/w33MSIdO/deSJWUphyMlW+PHn7vHj1o oGaVyLkxUi5z7yNiTc/KOl91qybltz1CB/XB+rLwmro7xPVo7irW49BWVPqT0FtxAvto +t9Q== X-Gm-Message-State: ALoCoQluVZvN6SbB5cr8QiUBXymvU7JYV5kWkFnFUMlDDyyK0ZrEccx4p78eLbzKh0XkC64etKjD 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 Cc: linux-arm-kernel@lists.infradead.org, linux-kernel@vger.kernel.org, alex.williamson@redhat.com, christoffer.dall@linaro.org, marc.zyngier@arm.com, will.deacon@arm.com, bhelgaas@google.com, arnd@arndb.de, rob.herring@linaro.org, eric.auger@linaro.org, patches@apm.com, Pranavkumar Sawargaonkar , Ankit Jindal 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> Sender: kvm-owner@vger.kernel.org Precedence: bulk List-ID: X-Mailing-List: kvm@vger.kernel.org X-Spam-Status: No, score=-8.1 required=5.0 tests=BAYES_00, RCVD_IN_DNSWL_HI, 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);