From patchwork Thu Sep 1 19:50:30 2011 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Alex Williamson X-Patchwork-Id: 112969 Return-Path: X-Original-To: incoming@patchwork.ozlabs.org Delivered-To: patchwork-incoming@bilbo.ozlabs.org Received: from lists.gnu.org (lists.gnu.org [140.186.70.17]) (using TLSv1 with cipher AES256-SHA (256/256 bits)) (Client did not present a certificate) by ozlabs.org (Postfix) with ESMTPS id D7250B6F8E for ; Fri, 2 Sep 2011 05:51:41 +1000 (EST) Received: from localhost ([::1]:52264 helo=lists.gnu.org) by lists.gnu.org with esmtp (Exim 4.71) (envelope-from ) id 1QzDIS-00065L-Or for incoming@patchwork.ozlabs.org; Thu, 01 Sep 2011 15:51:32 -0400 Received: from eggs.gnu.org ([140.186.70.92]:49912) by lists.gnu.org with esmtp (Exim 4.71) (envelope-from ) id 1QzDIL-00063i-8f for qemu-devel@nongnu.org; Thu, 01 Sep 2011 15:51:27 -0400 Received: from Debian-exim by eggs.gnu.org with spam-scanned (Exim 4.71) (envelope-from ) id 1QzDII-0002Bo-VI for qemu-devel@nongnu.org; Thu, 01 Sep 2011 15:51:25 -0400 Received: from mx1.redhat.com ([209.132.183.28]:22953) by eggs.gnu.org with esmtp (Exim 4.71) (envelope-from ) id 1QzDII-0002BR-JS for qemu-devel@nongnu.org; Thu, 01 Sep 2011 15:51:22 -0400 Received: from int-mx12.intmail.prod.int.phx2.redhat.com (int-mx12.intmail.prod.int.phx2.redhat.com [10.5.11.25]) by mx1.redhat.com (8.14.4/8.14.4) with ESMTP id p81JoWHF012347 (version=TLSv1/SSLv3 cipher=DHE-RSA-AES256-SHA bits=256 verify=OK); Thu, 1 Sep 2011 15:50:32 -0400 Received: from s20.home (ovpn01.gateway.prod.ext.phx2.redhat.com [10.5.9.1]) by int-mx12.intmail.prod.int.phx2.redhat.com (8.14.4/8.14.4) with ESMTP id p81JoURF020501; Thu, 1 Sep 2011 15:50:30 -0400 From: Alex Williamson To: chrisw@sous-sol.org, aik@au1.ibm.com, pmac@au1.ibm.com, dwg@au1.ibm.com, joerg.roedel@amd.com, agraf@suse.de, benve@cisco.com, aafabbri@cisco.com, B08248@freescale.com, B07421@freescale.com, avi@redhat.com, kvm@vger.kernel.org, qemu-devel@nongnu.org, iommu@lists.linux-foundation.org, linux-pci@vger.kernel.org Date: Thu, 01 Sep 2011 13:50:30 -0600 Message-ID: <20110901195030.2391.79018.stgit@s20.home> In-Reply-To: <20110901194915.2391.97400.stgit@s20.home> References: <20110901194915.2391.97400.stgit@s20.home> User-Agent: StGIT/0.14.3 MIME-Version: 1.0 X-Scanned-By: MIMEDefang 2.68 on 10.5.11.25 X-detected-operating-system: by eggs.gnu.org: Genre and OS details not recognized. X-Received-From: 209.132.183.28 Cc: alex.williamson@redhat.com Subject: [Qemu-devel] [RFC PATCH 1/5] iommu: Add iommu_device_group callback and iommu_group sysfs entry X-BeenThere: qemu-devel@nongnu.org X-Mailman-Version: 2.1.14 Precedence: list List-Id: List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Errors-To: qemu-devel-bounces+incoming=patchwork.ozlabs.org@nongnu.org Sender: qemu-devel-bounces+incoming=patchwork.ozlabs.org@nongnu.org An IOMMU group is a set of devices for which the IOMMU cannot distinguish transactions. For PCI devices, a group often occurs when a PCI bridge is involved. Transactions from any device behind the bridge appear to be sourced from the bridge itself. We leave it to the IOMMU driver to define the grouping restraints for their platform. Using this new interface, the group for a device can be retrieved using the iommu_device_group() callback. Users will compare the value returned against the value returned for other devices to determine whether they are part of the same group. Devices with no group are not translated by the IOMMU. There should be no expectations about the group numbers as they may be arbitrarily assigned by the IOMMU driver and may not be persistent across boots. We also provide a sysfs interface to the group numbers here so that user space can understand IOMMU dependencies between devices for managing safe, user space drivers. Signed-off-by: Alex Williamson --- drivers/base/iommu.c | 51 +++++++++++++++++++++++++++++++++++++++++++++++++ include/linux/iommu.h | 6 ++++++ 2 files changed, 57 insertions(+), 0 deletions(-) diff --git a/drivers/base/iommu.c b/drivers/base/iommu.c index 6e6b6a1..566aa17 100644 --- a/drivers/base/iommu.c +++ b/drivers/base/iommu.c @@ -17,20 +17,63 @@ */ #include +#include #include #include #include #include #include +#include static struct iommu_ops *iommu_ops; +static ssize_t show_iommu_group(struct device *dev, + struct device_attribute *attr, char *buf) +{ + unsigned int groupid; + + if (iommu_device_group(dev, &groupid)) + return 0; + + return sprintf(buf, "%u", groupid); +} +static DEVICE_ATTR(iommu_group, S_IRUGO, show_iommu_group, NULL); + +static int add_iommu_group(struct device *dev, void *unused) +{ + unsigned int groupid; + + if (iommu_device_group(dev, &groupid) == 0) + return device_create_file(dev, &dev_attr_iommu_group); + + return 0; +} + +static int device_notifier(struct notifier_block *nb, + unsigned long action, void *data) +{ + struct device *dev = data; + + if (action == BUS_NOTIFY_ADD_DEVICE) + return add_iommu_group(dev, NULL); + + return 0; +} + +static struct notifier_block device_nb = { + .notifier_call = device_notifier, +}; + void register_iommu(struct iommu_ops *ops) { if (iommu_ops) BUG(); iommu_ops = ops; + + /* FIXME - non-PCI, really want for_each_bus() */ + bus_register_notifier(&pci_bus_type, &device_nb); + bus_for_each_dev(&pci_bus_type, NULL, NULL, add_iommu_group); } bool iommu_found(void) @@ -94,6 +137,14 @@ int iommu_domain_has_cap(struct iommu_domain *domain, } EXPORT_SYMBOL_GPL(iommu_domain_has_cap); +int iommu_device_group(struct device *dev, unsigned int *groupid) +{ + if (iommu_ops->device_group) + return iommu_ops->device_group(dev, groupid); + return -ENODEV; +} +EXPORT_SYMBOL_GPL(iommu_device_group); + int iommu_map(struct iommu_domain *domain, unsigned long iova, phys_addr_t paddr, int gfp_order, int prot) { diff --git a/include/linux/iommu.h b/include/linux/iommu.h index 0a2ba40..e3a53ed 100644 --- a/include/linux/iommu.h +++ b/include/linux/iommu.h @@ -45,6 +45,7 @@ struct iommu_ops { unsigned long iova); int (*domain_has_cap)(struct iommu_domain *domain, unsigned long cap); + int (*device_group)(struct device *dev, unsigned int *groupid); }; #ifdef CONFIG_IOMMU_API @@ -65,6 +66,7 @@ extern phys_addr_t iommu_iova_to_phys(struct iommu_domain *domain, unsigned long iova); extern int iommu_domain_has_cap(struct iommu_domain *domain, unsigned long cap); +extern int iommu_device_group(struct device *dev, unsigned int *groupid); #else /* CONFIG_IOMMU_API */ @@ -121,6 +123,10 @@ static inline int domain_has_cap(struct iommu_domain *domain, return 0; } +static inline int iommu_device_group(struct device *dev, unsigned int *groupid); +{ + return -ENODEV; +} #endif /* CONFIG_IOMMU_API */ #endif /* __LINUX_IOMMU_H */