From patchwork Tue Sep 1 03:34:18 2020 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Baolu Lu X-Patchwork-Id: 11747311 Return-Path: Received: from mail.kernel.org (pdx-korg-mail-1.web.codeaurora.org [172.30.200.123]) by pdx-korg-patchwork-2.web.codeaurora.org (Postfix) with ESMTP id 164541667 for ; Tue, 1 Sep 2020 03:40:18 +0000 (UTC) Received: from vger.kernel.org (vger.kernel.org [23.128.96.18]) by mail.kernel.org (Postfix) with ESMTP id 045942083B for ; Tue, 1 Sep 2020 03:40:18 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1726559AbgIADkO (ORCPT ); Mon, 31 Aug 2020 23:40:14 -0400 Received: from mga12.intel.com ([192.55.52.136]:62487 "EHLO mga12.intel.com" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1725987AbgIADkN (ORCPT ); Mon, 31 Aug 2020 23:40:13 -0400 IronPort-SDR: Ouwm8mi3EjYZswVXAjDRuIzqQZfYUsAzlZ2PzM3ElSKQhDhZGSpqgWRu6y2L313TyG8o+i9nkm gLRa1dKg73SA== X-IronPort-AV: E=McAfee;i="6000,8403,9730"; a="136620920" X-IronPort-AV: E=Sophos;i="5.76,377,1592895600"; d="scan'208";a="136620920" X-Amp-Result: SKIPPED(no attachment in message) X-Amp-File-Uploaded: False Received: from fmsmga004.fm.intel.com ([10.253.24.48]) by fmsmga106.fm.intel.com with ESMTP/TLS/ECDHE-RSA-AES256-GCM-SHA384; 31 Aug 2020 20:40:12 -0700 IronPort-SDR: 1kfNDpxVZ6PjA9CK/YbklI2otaiSCxb5Hzrt0nE6YVckEQ9BAy5kwhn0hOaSxj3FTWfku0VgS4 ccCggZH6ZUZw== X-ExtLoop1: 1 X-IronPort-AV: E=Sophos;i="5.76,377,1592895600"; d="scan'208";a="325180863" Received: from allen-box.sh.intel.com ([10.239.159.139]) by fmsmga004.fm.intel.com with ESMTP; 31 Aug 2020 20:40:09 -0700 From: Lu Baolu To: Joerg Roedel , Alex Williamson Cc: Robin Murphy , Jean-Philippe Brucker , Cornelia Huck , Kevin Tian , Ashok Raj , Dave Jiang , Liu Yi L , Zeng Xin , iommu@lists.linux-foundation.org, linux-kernel@vger.kernel.org, kvm@vger.kernel.org, Lu Baolu Subject: [PATCH v4 1/5] iommu: Add optional subdev in aux_at(de)tach ops Date: Tue, 1 Sep 2020 11:34:18 +0800 Message-Id: <20200901033422.22249-2-baolu.lu@linux.intel.com> X-Mailer: git-send-email 2.17.1 In-Reply-To: <20200901033422.22249-1-baolu.lu@linux.intel.com> References: <20200901033422.22249-1-baolu.lu@linux.intel.com> Sender: kvm-owner@vger.kernel.org Precedence: bulk List-ID: X-Mailing-List: kvm@vger.kernel.org In the vfio/mdev use case of aux-domain, the subdevices are created from the physical devices with IOMMU_DEV_FEAT_AUX enabled and the aux-domains are attached to the subdevices through the iommu_ops.aux_attach_dev() interface. Current iommu_ops.aux_at(de)tach_dev() design only takes the aux-domain and the physical device as the parameters, this is insufficient if we want the vendor iommu drivers to learn the knowledge about relationships between the aux-domains and the subdevices. Add a @subdev parameter to iommu_ops.aux_at(de)tach_dev() interfaces so that a subdevice could be opt-in. Signed-off-by: Lu Baolu --- drivers/iommu/intel/iommu.c | 10 ++++++---- drivers/iommu/iommu.c | 4 ++-- include/linux/iommu.h | 6 ++++-- 3 files changed, 12 insertions(+), 8 deletions(-) diff --git a/drivers/iommu/intel/iommu.c b/drivers/iommu/intel/iommu.c index bce158468abf..3c12fd06856c 100644 --- a/drivers/iommu/intel/iommu.c +++ b/drivers/iommu/intel/iommu.c @@ -5338,8 +5338,9 @@ static int intel_iommu_attach_device(struct iommu_domain *domain, return domain_add_dev_info(to_dmar_domain(domain), dev); } -static int intel_iommu_aux_attach_device(struct iommu_domain *domain, - struct device *dev) +static int +intel_iommu_aux_attach_device(struct iommu_domain *domain, + struct device *dev, struct device *subdev) { int ret; @@ -5359,8 +5360,9 @@ static void intel_iommu_detach_device(struct iommu_domain *domain, dmar_remove_one_dev_info(dev); } -static void intel_iommu_aux_detach_device(struct iommu_domain *domain, - struct device *dev) +static void +intel_iommu_aux_detach_device(struct iommu_domain *domain, struct device *dev, + struct device *subdev) { aux_domain_remove_dev(to_dmar_domain(domain), dev); } diff --git a/drivers/iommu/iommu.c b/drivers/iommu/iommu.c index 609bd25bf154..38cdfeb887e1 100644 --- a/drivers/iommu/iommu.c +++ b/drivers/iommu/iommu.c @@ -2728,7 +2728,7 @@ int iommu_aux_attach_device(struct iommu_domain *domain, struct device *dev) int ret = -ENODEV; if (domain->ops->aux_attach_dev) - ret = domain->ops->aux_attach_dev(domain, dev); + ret = domain->ops->aux_attach_dev(domain, dev, NULL); if (!ret) trace_attach_device_to_domain(dev); @@ -2740,7 +2740,7 @@ EXPORT_SYMBOL_GPL(iommu_aux_attach_device); void iommu_aux_detach_device(struct iommu_domain *domain, struct device *dev) { if (domain->ops->aux_detach_dev) { - domain->ops->aux_detach_dev(domain, dev); + domain->ops->aux_detach_dev(domain, dev, NULL); trace_detach_device_from_domain(dev); } } diff --git a/include/linux/iommu.h b/include/linux/iommu.h index fee209efb756..871267104915 100644 --- a/include/linux/iommu.h +++ b/include/linux/iommu.h @@ -279,8 +279,10 @@ struct iommu_ops { int (*dev_disable_feat)(struct device *dev, enum iommu_dev_features f); /* Aux-domain specific attach/detach entries */ - int (*aux_attach_dev)(struct iommu_domain *domain, struct device *dev); - void (*aux_detach_dev)(struct iommu_domain *domain, struct device *dev); + int (*aux_attach_dev)(struct iommu_domain *domain, struct device *dev, + struct device *subdev); + void (*aux_detach_dev)(struct iommu_domain *domain, struct device *dev, + struct device *subdev); int (*aux_get_pasid)(struct iommu_domain *domain, struct device *dev); struct iommu_sva *(*sva_bind)(struct device *dev, struct mm_struct *mm, From patchwork Tue Sep 1 03:34:19 2020 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Baolu Lu X-Patchwork-Id: 11747319 Return-Path: Received: from mail.kernel.org (pdx-korg-mail-1.web.codeaurora.org [172.30.200.123]) by pdx-korg-patchwork-2.web.codeaurora.org (Postfix) with ESMTP id 53D741667 for ; Tue, 1 Sep 2020 03:40:43 +0000 (UTC) Received: from vger.kernel.org (vger.kernel.org [23.128.96.18]) by mail.kernel.org (Postfix) with ESMTP id 3F5042083B for ; Tue, 1 Sep 2020 03:40:43 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1726726AbgIADkT (ORCPT ); Mon, 31 Aug 2020 23:40:19 -0400 Received: from mga12.intel.com ([192.55.52.136]:62487 "EHLO mga12.intel.com" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1725987AbgIADkQ (ORCPT ); Mon, 31 Aug 2020 23:40:16 -0400 IronPort-SDR: Qdzp17WSKunMvCE+OdArXgFE75BvhNgSdsLBQNxp96BDdIKK7tFcqJzAfRiR3QP9NYkpHM0EQZ TE5f2w3g9XPQ== X-IronPort-AV: E=McAfee;i="6000,8403,9730"; a="136620924" X-IronPort-AV: E=Sophos;i="5.76,377,1592895600"; d="scan'208";a="136620924" X-Amp-Result: SKIPPED(no attachment in message) X-Amp-File-Uploaded: False Received: from fmsmga004.fm.intel.com ([10.253.24.48]) by fmsmga106.fm.intel.com with ESMTP/TLS/ECDHE-RSA-AES256-GCM-SHA384; 31 Aug 2020 20:40:15 -0700 IronPort-SDR: 4Co08nlHc/zVxmusrGa+DSn9WKA5VBcnQpNmnKAzdiSxYQUayrhB3xOj4IFDgG1jn6P0DQH9Fe 6+R4aYolmWGg== X-ExtLoop1: 1 X-IronPort-AV: E=Sophos;i="5.76,377,1592895600"; d="scan'208";a="325180875" Received: from allen-box.sh.intel.com ([10.239.159.139]) by fmsmga004.fm.intel.com with ESMTP; 31 Aug 2020 20:40:12 -0700 From: Lu Baolu To: Joerg Roedel , Alex Williamson Cc: Robin Murphy , Jean-Philippe Brucker , Cornelia Huck , Kevin Tian , Ashok Raj , Dave Jiang , Liu Yi L , Zeng Xin , iommu@lists.linux-foundation.org, linux-kernel@vger.kernel.org, kvm@vger.kernel.org, Lu Baolu Subject: [PATCH v4 2/5] iommu: Add iommu_at(de)tach_subdev_group() Date: Tue, 1 Sep 2020 11:34:19 +0800 Message-Id: <20200901033422.22249-3-baolu.lu@linux.intel.com> X-Mailer: git-send-email 2.17.1 In-Reply-To: <20200901033422.22249-1-baolu.lu@linux.intel.com> References: <20200901033422.22249-1-baolu.lu@linux.intel.com> Sender: kvm-owner@vger.kernel.org Precedence: bulk List-ID: X-Mailing-List: kvm@vger.kernel.org This adds two new APIs for the use cases like vfio/mdev where subdevices derived from physical devices are created and put in an iommu_group. The new IOMMU API interfaces mimic the vfio_mdev_at(de)tach_domain() directly, testing whether the resulting device supports IOMMU_DEV_FEAT_AUX and using an aux vs non-aux at(de)tach. By doing this we could - Set the iommu_group.domain. The iommu_group.domain is private to iommu core (therefore vfio code cannot set it), but we need it set in order for iommu_get_domain_for_dev() to work with a group attached to an aux domain. - Prefer to use the _attach_group() interfaces while the _attach_device() interfaces are relegated to special cases. Link: https://lore.kernel.org/linux-iommu/20200730134658.44c57a67@x1.home/ Link: https://lore.kernel.org/linux-iommu/20200730151703.5daf8ad4@x1.home/ Signed-off-by: Lu Baolu --- drivers/iommu/iommu.c | 136 ++++++++++++++++++++++++++++++++++++++++++ include/linux/iommu.h | 20 +++++++ 2 files changed, 156 insertions(+) diff --git a/drivers/iommu/iommu.c b/drivers/iommu/iommu.c index 38cdfeb887e1..fb21c2ff4861 100644 --- a/drivers/iommu/iommu.c +++ b/drivers/iommu/iommu.c @@ -2757,6 +2757,142 @@ int iommu_aux_get_pasid(struct iommu_domain *domain, struct device *dev) } EXPORT_SYMBOL_GPL(iommu_aux_get_pasid); +static int __iommu_aux_attach_device(struct iommu_domain *domain, + struct device *phys_dev, + struct device *sub_dev) +{ + int ret; + + if (unlikely(!domain->ops->aux_attach_dev)) + return -ENODEV; + + ret = domain->ops->aux_attach_dev(domain, phys_dev, sub_dev); + if (!ret) + trace_attach_device_to_domain(sub_dev); + + return ret; +} + +static void __iommu_aux_detach_device(struct iommu_domain *domain, + struct device *phys_dev, + struct device *sub_dev) +{ + if (unlikely(!domain->ops->aux_detach_dev)) + return; + + domain->ops->aux_detach_dev(domain, phys_dev, sub_dev); + trace_detach_device_from_domain(sub_dev); +} + +static int __iommu_attach_subdev_group(struct iommu_domain *domain, + struct iommu_group *group, + iommu_device_lookup_t fn) +{ + struct group_device *device; + struct device *phys_dev; + int ret = -ENODEV; + + list_for_each_entry(device, &group->devices, list) { + phys_dev = fn(device->dev); + if (!phys_dev) { + ret = -ENODEV; + break; + } + + if (iommu_dev_feature_enabled(phys_dev, IOMMU_DEV_FEAT_AUX)) + ret = __iommu_aux_attach_device(domain, phys_dev, + device->dev); + else + ret = __iommu_attach_device(domain, phys_dev); + + if (ret) + break; + } + + return ret; +} + +static void __iommu_detach_subdev_group(struct iommu_domain *domain, + struct iommu_group *group, + iommu_device_lookup_t fn) +{ + struct group_device *device; + struct device *phys_dev; + + list_for_each_entry(device, &group->devices, list) { + phys_dev = fn(device->dev); + if (!phys_dev) + break; + + if (iommu_dev_feature_enabled(phys_dev, IOMMU_DEV_FEAT_AUX)) + __iommu_aux_detach_device(domain, phys_dev, device->dev); + else + __iommu_detach_device(domain, phys_dev); + } +} + +/** + * iommu_attach_subdev_group - attach domain to an iommu_group which + * contains subdevices. + * + * @domain: domain + * @group: iommu_group which contains subdevices + * @fn: callback for each subdevice in the @iommu_group to retrieve the + * physical device where the subdevice was created from. + * + * Returns 0 on success, or an error value. + */ +int iommu_attach_subdev_group(struct iommu_domain *domain, + struct iommu_group *group, + iommu_device_lookup_t fn) +{ + int ret = -ENODEV; + + mutex_lock(&group->mutex); + if (group->domain) { + ret = -EBUSY; + goto unlock_out; + } + + ret = __iommu_attach_subdev_group(domain, group, fn); + if (ret) + __iommu_detach_subdev_group(domain, group, fn); + else + group->domain = domain; + +unlock_out: + mutex_unlock(&group->mutex); + return ret; +} +EXPORT_SYMBOL_GPL(iommu_attach_subdev_group); + +/** + * iommu_detach_subdev_group - detach domain from an iommu_group which + * contains subdevices + * + * @domain: domain + * @group: iommu_group which contains subdevices + * @fn: callback for each subdevice in the @iommu_group to retrieve the + * physical device where the subdevice was created from. + * + * The domain must have been attached to @group via iommu_attach_subdev_group(). + */ +void iommu_detach_subdev_group(struct iommu_domain *domain, + struct iommu_group *group, + iommu_device_lookup_t fn) +{ + mutex_lock(&group->mutex); + if (!group->domain) + goto unlock_out; + + __iommu_detach_subdev_group(domain, group, fn); + group->domain = NULL; + +unlock_out: + mutex_unlock(&group->mutex); +} +EXPORT_SYMBOL_GPL(iommu_detach_subdev_group); + /** * iommu_sva_bind_device() - Bind a process address space to a device * @dev: the device diff --git a/include/linux/iommu.h b/include/linux/iommu.h index 871267104915..b9df8b510d4f 100644 --- a/include/linux/iommu.h +++ b/include/linux/iommu.h @@ -48,6 +48,7 @@ struct iommu_fault_event; typedef int (*iommu_fault_handler_t)(struct iommu_domain *, struct device *, unsigned long, int, void *); typedef int (*iommu_dev_fault_handler_t)(struct iommu_fault *, void *); +typedef struct device *(*iommu_device_lookup_t)(struct device *); struct iommu_domain_geometry { dma_addr_t aperture_start; /* First address that can be mapped */ @@ -631,6 +632,12 @@ bool iommu_dev_feature_enabled(struct device *dev, enum iommu_dev_features f); int iommu_aux_attach_device(struct iommu_domain *domain, struct device *dev); void iommu_aux_detach_device(struct iommu_domain *domain, struct device *dev); int iommu_aux_get_pasid(struct iommu_domain *domain, struct device *dev); +int iommu_attach_subdev_group(struct iommu_domain *domain, + struct iommu_group *group, + iommu_device_lookup_t fn); +void iommu_detach_subdev_group(struct iommu_domain *domain, + struct iommu_group *group, + iommu_device_lookup_t fn); struct iommu_sva *iommu_sva_bind_device(struct device *dev, struct mm_struct *mm, @@ -1019,6 +1026,19 @@ iommu_aux_get_pasid(struct iommu_domain *domain, struct device *dev) return -ENODEV; } +static inline int +iommu_attach_subdev_group(struct iommu_domain *domain, struct iommu_group *group, + iommu_device_lookup_t fn) +{ + return -ENODEV; +} + +static inline void +iommu_detach_subdev_group(struct iommu_domain *domain, struct iommu_group *group, + iommu_device_lookup_t fn) +{ +} + static inline struct iommu_sva * iommu_sva_bind_device(struct device *dev, struct mm_struct *mm, void *drvdata) { From patchwork Tue Sep 1 03:34:20 2020 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Baolu Lu X-Patchwork-Id: 11747313 Return-Path: Received: from mail.kernel.org (pdx-korg-mail-1.web.codeaurora.org [172.30.200.123]) by pdx-korg-patchwork-2.web.codeaurora.org (Postfix) with ESMTP id B71B91667 for ; Tue, 1 Sep 2020 03:40:22 +0000 (UTC) Received: from vger.kernel.org (vger.kernel.org [23.128.96.18]) by mail.kernel.org (Postfix) with ESMTP id A6E5E2083B for ; Tue, 1 Sep 2020 03:40:22 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1726948AbgIADkV (ORCPT ); Mon, 31 Aug 2020 23:40:21 -0400 Received: from mga12.intel.com ([192.55.52.136]:62487 "EHLO mga12.intel.com" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1726858AbgIADkU (ORCPT ); Mon, 31 Aug 2020 23:40:20 -0400 IronPort-SDR: vL6N2OcbuYhC7tUuqY9DG4fvHqeRjCs4YOGVnGZr3lleM/fAw1scES0Cq9c77jWBHjQb6A3v+R qPtB4P6fQcQw== X-IronPort-AV: E=McAfee;i="6000,8403,9730"; a="136620927" X-IronPort-AV: E=Sophos;i="5.76,377,1592895600"; d="scan'208";a="136620927" X-Amp-Result: SKIPPED(no attachment in message) X-Amp-File-Uploaded: False Received: from fmsmga004.fm.intel.com ([10.253.24.48]) by fmsmga106.fm.intel.com with ESMTP/TLS/ECDHE-RSA-AES256-GCM-SHA384; 31 Aug 2020 20:40:19 -0700 IronPort-SDR: Uny4FzJVSCQSqgN74qadmFaEVq0jXOHDJs5Rw8/0OyW8mPY7F0J5iFfI4/WGMAUCuxwk0CA2ju mt5Y1hThFPPA== X-ExtLoop1: 1 X-IronPort-AV: E=Sophos;i="5.76,377,1592895600"; d="scan'208";a="325180890" Received: from allen-box.sh.intel.com ([10.239.159.139]) by fmsmga004.fm.intel.com with ESMTP; 31 Aug 2020 20:40:15 -0700 From: Lu Baolu To: Joerg Roedel , Alex Williamson Cc: Robin Murphy , Jean-Philippe Brucker , Cornelia Huck , Kevin Tian , Ashok Raj , Dave Jiang , Liu Yi L , Zeng Xin , iommu@lists.linux-foundation.org, linux-kernel@vger.kernel.org, kvm@vger.kernel.org, Lu Baolu Subject: [PATCH v4 3/5] iommu: Add iommu_aux_get_domain_for_dev() Date: Tue, 1 Sep 2020 11:34:20 +0800 Message-Id: <20200901033422.22249-4-baolu.lu@linux.intel.com> X-Mailer: git-send-email 2.17.1 In-Reply-To: <20200901033422.22249-1-baolu.lu@linux.intel.com> References: <20200901033422.22249-1-baolu.lu@linux.intel.com> Sender: kvm-owner@vger.kernel.org Precedence: bulk List-ID: X-Mailing-List: kvm@vger.kernel.org The device driver needs an API to get its aux-domain. A typical usage scenario is: unsigned long pasid; struct iommu_domain *domain; struct device *dev = mdev_dev(mdev); struct device *iommu_device = vfio_mdev_get_iommu_device(dev); domain = iommu_aux_get_domain_for_dev(dev); if (!domain) return -ENODEV; pasid = iommu_aux_get_pasid(domain, iommu_device); if (pasid <= 0) return -EINVAL; /* Program the device context */ .... This adds an API for such use case. Suggested-by: Alex Williamson Link: https://lore.kernel.org/linux-iommu/20200708130749.1b1e1421@x1.home/ Signed-off-by: Lu Baolu --- drivers/iommu/iommu.c | 18 ++++++++++++++++++ include/linux/iommu.h | 20 ++++++++++++++++++++ 2 files changed, 38 insertions(+) diff --git a/drivers/iommu/iommu.c b/drivers/iommu/iommu.c index fb21c2ff4861..8fd93a5b8764 100644 --- a/drivers/iommu/iommu.c +++ b/drivers/iommu/iommu.c @@ -2893,6 +2893,24 @@ void iommu_detach_subdev_group(struct iommu_domain *domain, } EXPORT_SYMBOL_GPL(iommu_detach_subdev_group); +struct iommu_domain *iommu_aux_get_domain_for_dev(struct device *subdev) +{ + struct iommu_domain *domain = NULL; + struct iommu_group *group; + + group = iommu_group_get(subdev); + if (!group || !group->domain) + return NULL; + + if (domain_is_aux(group->domain, subdev)) + domain = group->domain; + + iommu_group_put(group); + + return domain; +} +EXPORT_SYMBOL_GPL(iommu_aux_get_domain_for_dev); + /** * iommu_sva_bind_device() - Bind a process address space to a device * @dev: the device diff --git a/include/linux/iommu.h b/include/linux/iommu.h index b9df8b510d4f..ea660a887dbf 100644 --- a/include/linux/iommu.h +++ b/include/linux/iommu.h @@ -120,6 +120,7 @@ enum iommu_attr { DOMAIN_ATTR_NESTING, /* two stages of translation */ DOMAIN_ATTR_DMA_USE_FLUSH_QUEUE, DOMAIN_ATTR_MAX, + DOMAIN_ATTR_IS_AUX, }; /* These are the possible reserved region types */ @@ -622,6 +623,12 @@ static inline void dev_iommu_priv_set(struct device *dev, void *priv) dev->iommu->priv = priv; } +static inline bool +domain_is_aux(struct iommu_domain *domain, struct device *subdev) +{ + return iommu_domain_get_attr(domain, DOMAIN_ATTR_IS_AUX, subdev); +} + int iommu_probe_device(struct device *dev); void iommu_release_device(struct device *dev); @@ -638,6 +645,7 @@ int iommu_attach_subdev_group(struct iommu_domain *domain, void iommu_detach_subdev_group(struct iommu_domain *domain, struct iommu_group *group, iommu_device_lookup_t fn); +struct iommu_domain *iommu_aux_get_domain_for_dev(struct device *subdev); struct iommu_sva *iommu_sva_bind_device(struct device *dev, struct mm_struct *mm, @@ -1039,6 +1047,18 @@ iommu_detach_subdev_group(struct iommu_domain *domain, struct iommu_group *group { } +static inline bool +domain_is_aux(struct iommu_domain *domain, struct device *subdev) +{ + return false; +} + +static inline struct iommu_domain * +iommu_aux_get_domain_for_dev(struct device *subdev) +{ + return NULL; +} + static inline struct iommu_sva * iommu_sva_bind_device(struct device *dev, struct mm_struct *mm, void *drvdata) { From patchwork Tue Sep 1 03:34:21 2020 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Baolu Lu X-Patchwork-Id: 11747315 Return-Path: Received: from mail.kernel.org (pdx-korg-mail-1.web.codeaurora.org [172.30.200.123]) by pdx-korg-patchwork-2.web.codeaurora.org (Postfix) with ESMTP id 43C9214E5 for ; Tue, 1 Sep 2020 03:40:27 +0000 (UTC) Received: from vger.kernel.org (vger.kernel.org [23.128.96.18]) by mail.kernel.org (Postfix) with ESMTP id 33378207EA for ; Tue, 1 Sep 2020 03:40:27 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1727048AbgIADkZ (ORCPT ); Mon, 31 Aug 2020 23:40:25 -0400 Received: from mga12.intel.com ([192.55.52.136]:62487 "EHLO mga12.intel.com" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1727019AbgIADkW (ORCPT ); Mon, 31 Aug 2020 23:40:22 -0400 IronPort-SDR: YlTozWvGBvMdW0KoEP3fYQA/tD3mpMAvqEznkWbjk/a/XQ9+FmVXgHHodXyS7vgi8xuKZhnEKA buLiHq10DJqg== X-IronPort-AV: E=McAfee;i="6000,8403,9730"; a="136620931" X-IronPort-AV: E=Sophos;i="5.76,377,1592895600"; d="scan'208";a="136620931" X-Amp-Result: SKIPPED(no attachment in message) X-Amp-File-Uploaded: False Received: from fmsmga004.fm.intel.com ([10.253.24.48]) by fmsmga106.fm.intel.com with ESMTP/TLS/ECDHE-RSA-AES256-GCM-SHA384; 31 Aug 2020 20:40:22 -0700 IronPort-SDR: GQichjadeDgA+cvpAMfatx8HlghFYqypH/WWjRXZn6/BKY9ghVHsDuzl6QfGB0EsDySntIbQPV ME+MvPKTBC+Q== X-ExtLoop1: 1 X-IronPort-AV: E=Sophos;i="5.76,377,1592895600"; d="scan'208";a="325180898" Received: from allen-box.sh.intel.com ([10.239.159.139]) by fmsmga004.fm.intel.com with ESMTP; 31 Aug 2020 20:40:19 -0700 From: Lu Baolu To: Joerg Roedel , Alex Williamson Cc: Robin Murphy , Jean-Philippe Brucker , Cornelia Huck , Kevin Tian , Ashok Raj , Dave Jiang , Liu Yi L , Zeng Xin , iommu@lists.linux-foundation.org, linux-kernel@vger.kernel.org, kvm@vger.kernel.org, Lu Baolu Subject: [PATCH v4 4/5] vfio/type1: Use iommu_aux_at(de)tach_group() APIs Date: Tue, 1 Sep 2020 11:34:21 +0800 Message-Id: <20200901033422.22249-5-baolu.lu@linux.intel.com> X-Mailer: git-send-email 2.17.1 In-Reply-To: <20200901033422.22249-1-baolu.lu@linux.intel.com> References: <20200901033422.22249-1-baolu.lu@linux.intel.com> Sender: kvm-owner@vger.kernel.org Precedence: bulk List-ID: X-Mailing-List: kvm@vger.kernel.org Replace iommu_aux_at(de)tach_device() with iommu_at(de)tach_subdev_group(). Signed-off-by: Lu Baolu --- drivers/vfio/vfio_iommu_type1.c | 43 +++++---------------------------- 1 file changed, 6 insertions(+), 37 deletions(-) diff --git a/drivers/vfio/vfio_iommu_type1.c b/drivers/vfio/vfio_iommu_type1.c index 5e556ac9102a..8d5eb7ce0986 100644 --- a/drivers/vfio/vfio_iommu_type1.c +++ b/drivers/vfio/vfio_iommu_type1.c @@ -1627,45 +1627,13 @@ static struct device *vfio_mdev_get_iommu_device(struct device *dev) return NULL; } -static int vfio_mdev_attach_domain(struct device *dev, void *data) -{ - struct iommu_domain *domain = data; - struct device *iommu_device; - - iommu_device = vfio_mdev_get_iommu_device(dev); - if (iommu_device) { - if (iommu_dev_feature_enabled(iommu_device, IOMMU_DEV_FEAT_AUX)) - return iommu_aux_attach_device(domain, iommu_device); - else - return iommu_attach_device(domain, iommu_device); - } - - return -EINVAL; -} - -static int vfio_mdev_detach_domain(struct device *dev, void *data) -{ - struct iommu_domain *domain = data; - struct device *iommu_device; - - iommu_device = vfio_mdev_get_iommu_device(dev); - if (iommu_device) { - if (iommu_dev_feature_enabled(iommu_device, IOMMU_DEV_FEAT_AUX)) - iommu_aux_detach_device(domain, iommu_device); - else - iommu_detach_device(domain, iommu_device); - } - - return 0; -} - static int vfio_iommu_attach_group(struct vfio_domain *domain, struct vfio_group *group) { if (group->mdev_group) - return iommu_group_for_each_dev(group->iommu_group, - domain->domain, - vfio_mdev_attach_domain); + return iommu_attach_subdev_group(domain->domain, + group->iommu_group, + vfio_mdev_get_iommu_device); else return iommu_attach_group(domain->domain, group->iommu_group); } @@ -1674,8 +1642,9 @@ static void vfio_iommu_detach_group(struct vfio_domain *domain, struct vfio_group *group) { if (group->mdev_group) - iommu_group_for_each_dev(group->iommu_group, domain->domain, - vfio_mdev_detach_domain); + iommu_detach_subdev_group(domain->domain, + group->iommu_group, + vfio_mdev_get_iommu_device); else iommu_detach_group(domain->domain, group->iommu_group); } From patchwork Tue Sep 1 03:34:22 2020 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Baolu Lu X-Patchwork-Id: 11747317 Return-Path: Received: from mail.kernel.org (pdx-korg-mail-1.web.codeaurora.org [172.30.200.123]) by pdx-korg-patchwork-2.web.codeaurora.org (Postfix) with ESMTP id 2FCD81667 for ; Tue, 1 Sep 2020 03:40:38 +0000 (UTC) Received: from vger.kernel.org (vger.kernel.org [23.128.96.18]) by mail.kernel.org (Postfix) with ESMTP id 175B92083B for ; Tue, 1 Sep 2020 03:40:38 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1727108AbgIADkc (ORCPT ); Mon, 31 Aug 2020 23:40:32 -0400 Received: from mga12.intel.com ([192.55.52.136]:62487 "EHLO mga12.intel.com" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1727041AbgIADkZ (ORCPT ); Mon, 31 Aug 2020 23:40:25 -0400 IronPort-SDR: bkRuVY0X2bCEMp5rpX5iLvAlR42yonrLNsxiJEpUBzk1HC72/h/rXIUOkME2j4p1/nJevndX1p OZWsDk3uXEcw== X-IronPort-AV: E=McAfee;i="6000,8403,9730"; a="136620935" X-IronPort-AV: E=Sophos;i="5.76,377,1592895600"; d="scan'208";a="136620935" X-Amp-Result: SKIPPED(no attachment in message) X-Amp-File-Uploaded: False Received: from fmsmga004.fm.intel.com ([10.253.24.48]) by fmsmga106.fm.intel.com with ESMTP/TLS/ECDHE-RSA-AES256-GCM-SHA384; 31 Aug 2020 20:40:24 -0700 IronPort-SDR: JsAJu6ahu1baBQgm5jWszU3H6hTiT/Qk3zofjkx+XwNaSgbWB0/GGVEXDBmJs1sLBhNI7y8UwR jzn6J1apS0mg== X-ExtLoop1: 1 X-IronPort-AV: E=Sophos;i="5.76,377,1592895600"; d="scan'208";a="325180905" Received: from allen-box.sh.intel.com ([10.239.159.139]) by fmsmga004.fm.intel.com with ESMTP; 31 Aug 2020 20:40:22 -0700 From: Lu Baolu To: Joerg Roedel , Alex Williamson Cc: Robin Murphy , Jean-Philippe Brucker , Cornelia Huck , Kevin Tian , Ashok Raj , Dave Jiang , Liu Yi L , Zeng Xin , iommu@lists.linux-foundation.org, linux-kernel@vger.kernel.org, kvm@vger.kernel.org, Lu Baolu Subject: [PATCH v4 5/5] iommu/vt-d: Add is_aux_domain support Date: Tue, 1 Sep 2020 11:34:22 +0800 Message-Id: <20200901033422.22249-6-baolu.lu@linux.intel.com> X-Mailer: git-send-email 2.17.1 In-Reply-To: <20200901033422.22249-1-baolu.lu@linux.intel.com> References: <20200901033422.22249-1-baolu.lu@linux.intel.com> Sender: kvm-owner@vger.kernel.org Precedence: bulk List-ID: X-Mailing-List: kvm@vger.kernel.org With subdevice information opt-in through iommu_ops.aux_at(de)tach_dev() interfaces, the vendor iommu driver is able to learn the knowledge about the relationships between the subdevices and the aux-domains. Implement is_aux_domain() support based on the relationship knowledges. Signed-off-by: Lu Baolu --- drivers/iommu/intel/iommu.c | 125 ++++++++++++++++++++++++++---------- include/linux/intel-iommu.h | 17 +++-- 2 files changed, 103 insertions(+), 39 deletions(-) diff --git a/drivers/iommu/intel/iommu.c b/drivers/iommu/intel/iommu.c index 3c12fd06856c..50431c7b2e71 100644 --- a/drivers/iommu/intel/iommu.c +++ b/drivers/iommu/intel/iommu.c @@ -334,6 +334,8 @@ static int intel_iommu_attach_device(struct iommu_domain *domain, struct device *dev); static phys_addr_t intel_iommu_iova_to_phys(struct iommu_domain *domain, dma_addr_t iova); +static bool intel_iommu_dev_feat_enabled(struct device *dev, + enum iommu_dev_features feat); #ifdef CONFIG_INTEL_IOMMU_DEFAULT_ON int dmar_disabled = 0; @@ -1832,6 +1834,7 @@ static struct dmar_domain *alloc_domain(int flags) domain->flags |= DOMAIN_FLAG_USE_FIRST_LEVEL; domain->has_iotlb_device = false; INIT_LIST_HEAD(&domain->devices); + INIT_LIST_HEAD(&domain->subdevices); return domain; } @@ -2580,7 +2583,7 @@ static struct dmar_domain *dmar_insert_one_dev_info(struct intel_iommu *iommu, info->iommu = iommu; info->pasid_table = NULL; info->auxd_enabled = 0; - INIT_LIST_HEAD(&info->auxiliary_domains); + INIT_LIST_HEAD(&info->subdevices); if (dev && dev_is_pci(dev)) { struct pci_dev *pdev = to_pci_dev(info->dev); @@ -5137,21 +5140,28 @@ static void intel_iommu_domain_free(struct iommu_domain *domain) domain_exit(to_dmar_domain(domain)); } -/* - * Check whether a @domain could be attached to the @dev through the - * aux-domain attach/detach APIs. - */ -static inline bool -is_aux_domain(struct device *dev, struct iommu_domain *domain) +/* Lookup subdev_info in the domain's subdevice siblings. */ +static struct subdev_info * +subdev_lookup_domain(struct dmar_domain *domain, struct device *dev, + struct device *subdev) { - struct device_domain_info *info = get_domain_info(dev); + struct subdev_info *sinfo = NULL, *tmp; - return info && info->auxd_enabled && - domain->type == IOMMU_DOMAIN_UNMANAGED; + assert_spin_locked(&device_domain_lock); + + list_for_each_entry(tmp, &domain->subdevices, link_domain) { + if ((!dev || tmp->pdev == dev) && tmp->dev == subdev) { + sinfo = tmp; + break; + } + } + + return sinfo; } -static void auxiliary_link_device(struct dmar_domain *domain, - struct device *dev) +static void +subdev_link_device(struct dmar_domain *domain, struct device *dev, + struct subdev_info *sinfo) { struct device_domain_info *info = get_domain_info(dev); @@ -5159,12 +5169,13 @@ static void auxiliary_link_device(struct dmar_domain *domain, if (WARN_ON(!info)) return; - domain->auxd_refcnt++; - list_add(&domain->auxd, &info->auxiliary_domains); + list_add(&info->subdevices, &sinfo->link_phys); + list_add(&domain->subdevices, &sinfo->link_domain); } -static void auxiliary_unlink_device(struct dmar_domain *domain, - struct device *dev) +static void +subdev_unlink_device(struct dmar_domain *domain, struct device *dev, + struct subdev_info *sinfo) { struct device_domain_info *info = get_domain_info(dev); @@ -5172,24 +5183,30 @@ static void auxiliary_unlink_device(struct dmar_domain *domain, if (WARN_ON(!info)) return; - list_del(&domain->auxd); - domain->auxd_refcnt--; + list_del(&sinfo->link_phys); + list_del(&sinfo->link_domain); + kfree(sinfo); - if (!domain->auxd_refcnt && domain->default_pasid > 0) + if (list_empty(&domain->subdevices) && domain->default_pasid > 0) ioasid_free(domain->default_pasid); } -static int aux_domain_add_dev(struct dmar_domain *domain, - struct device *dev) +static int aux_domain_add_dev(struct dmar_domain *domain, struct device *dev, + struct device *subdev) { int ret; unsigned long flags; struct intel_iommu *iommu; + struct subdev_info *sinfo; iommu = device_to_iommu(dev, NULL, NULL); if (!iommu) return -ENODEV; + sinfo = kzalloc(sizeof(*sinfo), GFP_KERNEL); + if (!sinfo) + return -ENOMEM; + if (domain->default_pasid <= 0) { int pasid; @@ -5199,7 +5216,8 @@ static int aux_domain_add_dev(struct dmar_domain *domain, NULL); if (pasid == INVALID_IOASID) { pr_err("Can't allocate default pasid\n"); - return -ENODEV; + ret = -ENODEV; + goto pasid_failed; } domain->default_pasid = pasid; } @@ -5225,7 +5243,10 @@ static int aux_domain_add_dev(struct dmar_domain *domain, goto table_failed; spin_unlock(&iommu->lock); - auxiliary_link_device(domain, dev); + sinfo->dev = subdev; + sinfo->domain = domain; + sinfo->pdev = dev; + subdev_link_device(domain, dev, sinfo); spin_unlock_irqrestore(&device_domain_lock, flags); @@ -5236,27 +5257,36 @@ static int aux_domain_add_dev(struct dmar_domain *domain, attach_failed: spin_unlock(&iommu->lock); spin_unlock_irqrestore(&device_domain_lock, flags); - if (!domain->auxd_refcnt && domain->default_pasid > 0) + if (list_empty(&domain->subdevices) && domain->default_pasid > 0) ioasid_free(domain->default_pasid); +pasid_failed: + kfree(sinfo); return ret; } -static void aux_domain_remove_dev(struct dmar_domain *domain, - struct device *dev) +static void +aux_domain_remove_dev(struct dmar_domain *domain, struct device *dev, + struct device *subdev) { struct device_domain_info *info; struct intel_iommu *iommu; + struct subdev_info *sinfo; unsigned long flags; - if (!is_aux_domain(dev, &domain->domain)) + if (!intel_iommu_dev_feat_enabled(dev, IOMMU_DEV_FEAT_AUX) || + domain->domain.type != IOMMU_DOMAIN_UNMANAGED) return; spin_lock_irqsave(&device_domain_lock, flags); info = get_domain_info(dev); iommu = info->iommu; - - auxiliary_unlink_device(domain, dev); + sinfo = subdev_lookup_domain(domain, dev, subdev); + if (!sinfo) { + spin_unlock_irqrestore(&device_domain_lock, flags); + return; + } + subdev_unlink_device(domain, dev, sinfo); spin_lock(&iommu->lock); intel_pasid_tear_down_entry(iommu, dev, domain->default_pasid, false); @@ -5319,7 +5349,8 @@ static int intel_iommu_attach_device(struct iommu_domain *domain, return -EPERM; } - if (is_aux_domain(dev, domain)) + if (intel_iommu_dev_feat_enabled(dev, IOMMU_DEV_FEAT_AUX) && + domain->type == IOMMU_DOMAIN_UNMANAGED) return -EPERM; /* normally dev is not mapped */ @@ -5344,14 +5375,15 @@ intel_iommu_aux_attach_device(struct iommu_domain *domain, { int ret; - if (!is_aux_domain(dev, domain)) + if (!intel_iommu_dev_feat_enabled(dev, IOMMU_DEV_FEAT_AUX) || + domain->type != IOMMU_DOMAIN_UNMANAGED) return -EPERM; ret = prepare_domain_attach_device(domain, dev); if (ret) return ret; - return aux_domain_add_dev(to_dmar_domain(domain), dev); + return aux_domain_add_dev(to_dmar_domain(domain), dev, subdev); } static void intel_iommu_detach_device(struct iommu_domain *domain, @@ -5364,7 +5396,7 @@ static void intel_iommu_aux_detach_device(struct iommu_domain *domain, struct device *dev, struct device *subdev) { - aux_domain_remove_dev(to_dmar_domain(domain), dev); + aux_domain_remove_dev(to_dmar_domain(domain), dev, subdev); } /* @@ -6020,6 +6052,32 @@ static bool intel_iommu_is_attach_deferred(struct iommu_domain *domain, return attach_deferred(dev); } +static int +intel_iommu_domain_get_attr(struct iommu_domain *domain, + enum iommu_attr attr, void *data) +{ + struct dmar_domain *dmar_domain = to_dmar_domain(domain); + unsigned long flags; + int ret; + + if (domain->type != IOMMU_DOMAIN_UNMANAGED) + return -EINVAL; + + switch (attr) { + case DOMAIN_ATTR_IS_AUX: + spin_lock_irqsave(&device_domain_lock, flags); + ret = !IS_ERR_OR_NULL(subdev_lookup_domain(dmar_domain, + NULL, data)); + spin_unlock_irqrestore(&device_domain_lock, flags); + break; + default: + ret = -EINVAL; + break; + } + + return ret; +} + static int intel_iommu_domain_set_attr(struct iommu_domain *domain, enum iommu_attr attr, void *data) @@ -6073,6 +6131,7 @@ const struct iommu_ops intel_iommu_ops = { .domain_alloc = intel_iommu_domain_alloc, .domain_free = intel_iommu_domain_free, .domain_set_attr = intel_iommu_domain_set_attr, + .domain_get_attr = intel_iommu_domain_get_attr, .attach_dev = intel_iommu_attach_device, .detach_dev = intel_iommu_detach_device, .aux_attach_dev = intel_iommu_aux_attach_device, diff --git a/include/linux/intel-iommu.h b/include/linux/intel-iommu.h index b1ed2f25f7c0..47ba1904c691 100644 --- a/include/linux/intel-iommu.h +++ b/include/linux/intel-iommu.h @@ -526,11 +526,9 @@ struct dmar_domain { /* Domain ids per IOMMU. Use u16 since * domain ids are 16 bit wide according * to VT-d spec, section 9.3 */ - unsigned int auxd_refcnt; /* Refcount of auxiliary attaching */ - bool has_iotlb_device; struct list_head devices; /* all devices' list */ - struct list_head auxd; /* link to device's auxiliary list */ + struct list_head subdevices; /* all subdevices' list */ struct iova_domain iovad; /* iova's that belong to this domain */ struct dma_pte *pgd; /* virtual address */ @@ -603,14 +601,21 @@ struct intel_iommu { struct dmar_drhd_unit *drhd; }; +/* Per subdevice private data */ +struct subdev_info { + struct list_head link_phys; /* link to phys device siblings */ + struct list_head link_domain; /* link to domain siblings */ + struct device *pdev; /* physical device derived from */ + struct device *dev; /* subdevice node */ + struct dmar_domain *domain; /* aux-domain */ +}; + /* PCI domain-device relationship */ struct device_domain_info { struct list_head link; /* link to domain siblings */ struct list_head global; /* link to global list */ struct list_head table; /* link to pasid table */ - struct list_head auxiliary_domains; /* auxiliary domains - * attached to this device - */ + struct list_head subdevices; /* subdevices sibling */ u32 segment; /* PCI segment number */ u8 bus; /* PCI bus number */ u8 devfn; /* PCI devfn number */