Received: by 2002:a6b:500f:0:0:0:0:0 with SMTP id e15csp5857746iob; Tue, 10 May 2022 05:27:58 -0700 (PDT) X-Google-Smtp-Source: ABdhPJwvicZqCDX+Ug6b3km0aYWAkYB9bNLGnB+z43TGNDTp1WUPtXw7k9m0AYDhnXCIjAFu2Aks X-Received: by 2002:a17:907:3f95:b0:6f4:f45a:9f66 with SMTP id hr21-20020a1709073f9500b006f4f45a9f66mr18960864ejc.544.1652185677950; Tue, 10 May 2022 05:27:57 -0700 (PDT) ARC-Seal: i=1; a=rsa-sha256; t=1652185677; cv=none; d=google.com; s=arc-20160816; b=jLN0HQyFmN6vHzd+u/OOL92hyxAeB4O/UKFXenpZDUiQrVSuA2YEUWwvG1QcGupH49 xGjH4F0rjygMpW1BRDQ0KqkTomeqXNqfm4Ze9gBiZrMM7NuHwO1AdGfrbwkEe2s36uYv qkoiRdvPkfSSnq7pf/koiwquLWjiPErsUrQtnd9ysS8M0Uup5Isj6kEmU9fvGjeoqq4w /gf6yZo7h4a4d/8AtWLAXxQorVdmvg3oxk0nv/yzZusPslm1TYAKCuX/z6iOd3x2Jpah hqx9u4L26J7jhXPHlWuy/pcSKNCltjfUmFo+XUpI/HxjDO2wAydSdFSVCxQx9sHjmUUO 6CFQ== ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=google.com; s=arc-20160816; h=list-id:precedence:content-transfer-encoding:mime-version :references:in-reply-to:message-id:date:subject:cc:to:from :dkim-signature; bh=4H5/nCEIO7JO0SODMq4FSatC+zu+NJbYdbJTw8SQ7os=; b=rjlTV1xLsvnjwJbzIO3QmHCzCI27xLB1zaE1bpTnQ98IQtJAy+oKnpXEHmOw/mP18i sk8xeElwgg+jqVoowVIrW0al/npl3wPqpDYNTcTJSpiEJbo12so54VYBCSkl3Et584th GkAwsFv7qt7P/ROvTzH1BiQNF+LLWjtXaLkLgMB13A5rMYRw9VI7D2QRiBF1C6r83K31 q0Hlv6j0bgMacLhCuyTrtuv5mrfquyzTmw9mlqsZUzOJ3FiO0iigrpJVu2gBv6Gon7bM HBceFsiGws0aRoGiR8OKkd15Da1vC3oeg1EONSke9ZVWAfWh3cX97jBC7wISj9eOZbRn yrXw== ARC-Authentication-Results: i=1; mx.google.com; dkim=pass header.i=@intel.com header.s=Intel header.b=S2jPF2XW; spf=pass (google.com: domain of linux-kernel-owner@vger.kernel.org designates 2620:137:e000::1:20 as permitted sender) smtp.mailfrom=linux-kernel-owner@vger.kernel.org; dmarc=pass (p=NONE sp=NONE dis=NONE) header.from=intel.com Return-Path: Received: from out1.vger.email (out1.vger.email. [2620:137:e000::1:20]) by mx.google.com with ESMTP id a4-20020a1709062b0400b006f379f93701si15510114ejg.843.2022.05.10.05.27.32; Tue, 10 May 2022 05:27:57 -0700 (PDT) Received-SPF: pass (google.com: domain of linux-kernel-owner@vger.kernel.org designates 2620:137:e000::1:20 as permitted sender) client-ip=2620:137:e000::1:20; Authentication-Results: mx.google.com; dkim=pass header.i=@intel.com header.s=Intel header.b=S2jPF2XW; spf=pass (google.com: domain of linux-kernel-owner@vger.kernel.org designates 2620:137:e000::1:20 as permitted sender) smtp.mailfrom=linux-kernel-owner@vger.kernel.org; dmarc=pass (p=NONE sp=NONE dis=NONE) header.from=intel.com Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S237091AbiEJGZP (ORCPT + 99 others); Tue, 10 May 2022 02:25:15 -0400 Received: from lindbergh.monkeyblade.net ([23.128.96.19]:33834 "EHLO lindbergh.monkeyblade.net" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S237068AbiEJGY5 (ORCPT ); Tue, 10 May 2022 02:24:57 -0400 Received: from mga07.intel.com (mga07.intel.com [134.134.136.100]) by lindbergh.monkeyblade.net (Postfix) with ESMTPS id 8AF8F1E3EB for ; Mon, 9 May 2022 23:21:00 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=intel.com; i=@intel.com; q=dns/txt; s=Intel; t=1652163660; x=1683699660; h=from:to:cc:subject:date:message-id:in-reply-to: references:mime-version:content-transfer-encoding; bh=SkuWVMiahK5jbVuor3KDnHkiDiZb/OYULE9ThL5dTD0=; b=S2jPF2XWioNIwanVmFIkC/zW035wusxxVJY05zV86Oge7xuV3ODx88zr ht1sMICv0wH44wWW3dVghc3zeW51LeYGwL6EgGtDaq9erMObR3jNTUik1 mVxMWwYm4MGFChSMssRAXbEnuNHUQDoOb/46gfsEunb4yzZ/oI22b8LPo g73cfIHveztbWFY+zl4CjGrLoaGd8rw1wEZyO1QUCZsiMtDxp0CsH/Kky 1xDvq0m09fs9vcyAnBIWpXIz6W7wI6A84u38zI4RIBorAtqQZhk//72LT RhCA8StSMvMNycbmIlKFLbJf5hzAw6+57g7tgieQsMEiv3iK98LCtZvFu A==; X-IronPort-AV: E=McAfee;i="6400,9594,10342"; a="332312883" X-IronPort-AV: E=Sophos;i="5.91,213,1647327600"; d="scan'208";a="332312883" Received: from orsmga002.jf.intel.com ([10.7.209.21]) by orsmga105.jf.intel.com with ESMTP/TLS/ECDHE-RSA-AES256-GCM-SHA384; 09 May 2022 23:21:00 -0700 X-ExtLoop1: 1 X-IronPort-AV: E=Sophos;i="5.91,213,1647327600"; d="scan'208";a="552636397" Received: from allen-box.sh.intel.com ([10.239.159.48]) by orsmga002.jf.intel.com with ESMTP; 09 May 2022 23:20:56 -0700 From: Lu Baolu To: Joerg Roedel , Jason Gunthorpe , Christoph Hellwig , Kevin Tian , Ashok Raj , Will Deacon , Robin Murphy , Jean-Philippe Brucker , Dave Jiang , Vinod Koul Cc: Eric Auger , Liu Yi L , Jacob jun Pan , iommu@lists.linux-foundation.org, linux-kernel@vger.kernel.org, Lu Baolu , Jean-Philippe Brucker Subject: [PATCH v6 03/12] iommu: Add attach/detach_dev_pasid domain ops Date: Tue, 10 May 2022 14:17:29 +0800 Message-Id: <20220510061738.2761430-4-baolu.lu@linux.intel.com> X-Mailer: git-send-email 2.25.1 In-Reply-To: <20220510061738.2761430-1-baolu.lu@linux.intel.com> References: <20220510061738.2761430-1-baolu.lu@linux.intel.com> MIME-Version: 1.0 Content-Transfer-Encoding: 8bit X-Spam-Status: No, score=-4.9 required=5.0 tests=BAYES_00,DKIMWL_WL_HIGH, DKIM_SIGNED,DKIM_VALID,DKIM_VALID_EF,RCVD_IN_DNSWL_MED,SPF_HELO_NONE, SPF_NONE,T_SCC_BODY_TEXT_LINE,URIBL_BLOCKED autolearn=ham autolearn_force=no version=3.4.6 X-Spam-Checker-Version: SpamAssassin 3.4.6 (2021-04-09) on lindbergh.monkeyblade.net Precedence: bulk List-ID: X-Mailing-List: linux-kernel@vger.kernel.org Attaching an IOMMU domain to a PASID of a device is a generic operation for modern IOMMU drivers which support PASID-granular DMA address translation. Currently visible usage scenarios include (but not limited): - SVA (Shared Virtual Address) - kernel DMA with PASID - hardware-assist mediated device This adds a pair of common domain ops for this purpose and adds helpers to attach/detach a domain to/from a {device, PASID}. Some buses, like PCI, route packets without considering the PASID value. Thus a DMA target address with PASID might be treated as P2P if the address falls into the MMIO BAR of other devices in the group. To make things simple, these interfaces only apply to devices belonging to the singleton groups, and the singleton is immutable in fabric i.e. not affected by hotplug. Signed-off-by: Lu Baolu Reviewed-by: Jean-Philippe Brucker --- include/linux/iommu.h | 21 +++++++++++++ drivers/iommu/iommu.c | 71 +++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 92 insertions(+) diff --git a/include/linux/iommu.h b/include/linux/iommu.h index b8ffaf2cb1d0..ab36244d4e94 100644 --- a/include/linux/iommu.h +++ b/include/linux/iommu.h @@ -263,6 +263,8 @@ struct iommu_ops { * struct iommu_domain_ops - domain specific operations * @attach_dev: attach an iommu domain to a device * @detach_dev: detach an iommu domain from a device + * @attach_dev_pasid: attach an iommu domain to a pasid of device + * @detach_dev_pasid: detach an iommu domain from a pasid of device * @map: map a physically contiguous memory region to an iommu domain * @map_pages: map a physically contiguous set of pages of the same size to * an iommu domain. @@ -283,6 +285,10 @@ struct iommu_ops { struct iommu_domain_ops { int (*attach_dev)(struct iommu_domain *domain, struct device *dev); void (*detach_dev)(struct iommu_domain *domain, struct device *dev); + int (*attach_dev_pasid)(struct iommu_domain *domain, + struct device *dev, ioasid_t pasid); + void (*detach_dev_pasid)(struct iommu_domain *domain, + struct device *dev, ioasid_t pasid); int (*map)(struct iommu_domain *domain, unsigned long iova, phys_addr_t paddr, size_t size, int prot, gfp_t gfp); @@ -678,6 +684,10 @@ int iommu_group_claim_dma_owner(struct iommu_group *group, void *owner); void iommu_group_release_dma_owner(struct iommu_group *group); bool iommu_group_dma_owner_claimed(struct iommu_group *group); +int iommu_attach_device_pasid(struct iommu_domain *domain, + struct device *dev, ioasid_t pasid); +void iommu_detach_device_pasid(struct iommu_domain *domain, + struct device *dev, ioasid_t pasid); #else /* CONFIG_IOMMU_API */ struct iommu_ops {}; @@ -1051,6 +1061,17 @@ static inline bool iommu_group_dma_owner_claimed(struct iommu_group *group) { return false; } + +static inline int iommu_attach_device_pasid(struct iommu_domain *domain, + struct device *dev, ioasid_t pasid) +{ + return -ENODEV; +} + +static inline void iommu_detach_device_pasid(struct iommu_domain *domain, + struct device *dev, ioasid_t pasid) +{ +} #endif /* CONFIG_IOMMU_API */ /** diff --git a/drivers/iommu/iommu.c b/drivers/iommu/iommu.c index 29906bc16371..16e8db2d86fc 100644 --- a/drivers/iommu/iommu.c +++ b/drivers/iommu/iommu.c @@ -38,6 +38,7 @@ struct iommu_group { struct kobject kobj; struct kobject *devices_kobj; struct list_head devices; + struct xarray pasid_array; struct mutex mutex; void *iommu_data; void (*iommu_data_release)(void *iommu_data); @@ -630,6 +631,7 @@ struct iommu_group *iommu_group_alloc(void) mutex_init(&group->mutex); INIT_LIST_HEAD(&group->devices); INIT_LIST_HEAD(&group->entry); + xa_init(&group->pasid_array); ret = ida_simple_get(&iommu_group_ida, 0, 0, GFP_KERNEL); if (ret < 0) { @@ -3190,3 +3192,72 @@ bool iommu_group_dma_owner_claimed(struct iommu_group *group) return user; } EXPORT_SYMBOL_GPL(iommu_group_dma_owner_claimed); + +static bool device_group_immutable_singleton(struct device *dev) +{ + struct iommu_group *group = iommu_group_get(dev); + int count; + + if (!group) + return false; + + mutex_lock(&group->mutex); + count = iommu_group_device_count(group); + mutex_unlock(&group->mutex); + iommu_group_put(group); + + if (count != 1) + return false; + + /* + * The PCI device could be considered to be fully isolated if all + * devices on the path from the device to the host-PCI bridge are + * protected from peer-to-peer DMA by ACS. + */ + if (dev_is_pci(dev)) + return pci_acs_path_enabled(to_pci_dev(dev), NULL, + REQ_ACS_FLAGS); + + return true; +} + +int iommu_attach_device_pasid(struct iommu_domain *domain, + struct device *dev, ioasid_t pasid) +{ + struct iommu_group *group; + int ret = -EINVAL; + void *curr; + + if (!domain->ops->attach_dev_pasid) + return -EOPNOTSUPP; + + if (!device_group_immutable_singleton(dev)) + return -EINVAL; + + group = iommu_group_get(dev); + mutex_lock(&group->mutex); + curr = xa_cmpxchg(&group->pasid_array, pasid, NULL, domain, GFP_KERNEL); + if (curr) + goto out_unlock; + ret = domain->ops->attach_dev_pasid(domain, dev, pasid); + if (ret) + xa_erase(&group->pasid_array, pasid); +out_unlock: + mutex_unlock(&group->mutex); + iommu_group_put(group); + + return ret; +} + +void iommu_detach_device_pasid(struct iommu_domain *domain, + struct device *dev, ioasid_t pasid) +{ + struct iommu_group *group = iommu_group_get(dev); + + mutex_lock(&group->mutex); + domain->ops->detach_dev_pasid(domain, dev, pasid); + xa_erase(&group->pasid_array, pasid); + mutex_unlock(&group->mutex); + + iommu_group_put(group); +} -- 2.25.1