Received: by 2002:a05:6358:3188:b0:123:57c1:9b43 with SMTP id q8csp2581808rwd; Fri, 2 Jun 2023 11:22:55 -0700 (PDT) X-Google-Smtp-Source: ACHHUZ7H4Qi+Z1DcfO1g+bh342dnhzViyoLdv25B+1dbM3Knc46UtTdr04qR+ZrIEvZjotyERNyA X-Received: by 2002:a17:903:2291:b0:1af:c7f8:b329 with SMTP id b17-20020a170903229100b001afc7f8b329mr904840plh.24.1685730174682; Fri, 02 Jun 2023 11:22:54 -0700 (PDT) ARC-Seal: i=1; a=rsa-sha256; t=1685730174; cv=none; d=google.com; s=arc-20160816; b=0WTDVX+4JBq1Z96geZz5xfLXavhPwkZL2kSkTOYsi9BiwsaLpYufbCdtbAECt2phVg ayRjIVZoszaFQbNNFOo3E6tv7EVOyXg3QQhsWrnkbr096RSSc6LwlVYoTCuzs42rDZL6 2B83zuRZMWULCTlBdV2AzO22tZ3D+wZKvGM6A9MHeD1PANngKntyzNLaHP+u4p8Iqd1w NfxLyzNowBmM3OllTrFAjVOSTBEOiD+sJoGRvMjkAf+o9v8rA4NRoWUuftqI1yANhX1m CuvLXfYMCXgM9os0lYRo8dwcWOZV86WjyqHE+nZgcEu19veqLH8K4V30v9DDLT/3ZQ9X /CYw== 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=Sq7pqt8Y9iRtHFj5WNmQmz8el5Av429UBUDx/h88q0M=; b=cRvGC4vRHjICH0K0O4Z0p2FPZjIbI+Wt7R3kol30Eb0fqipF5mE5nSy5tpgpQnqeZd x0F6tS5ZIThLD29IJisL0JxEnvc1+fndZg02Scft8wnedV0t/94hwPvyOLgNnsinkXlt mMAmrhclHAKyQ5wXuIyAFWS/xInam9D+R/632NwrTPq09F54OIHZYrbz5zmDG5Kj9uHI K6+V2ho98pd+ekbXDtUmlzM+ymMxb2S7FGFdYb8a+vyoH0JLkfFE3lzh3bFDiovXXd6l mnD4tu7Nf1bqS3yAGhumzjVzIETkikT3HljLdnJ6H2mweSbovEZqBjHpEtmldPaS/8Vf wZEQ== ARC-Authentication-Results: i=1; mx.google.com; dkim=pass header.i=@intel.com header.s=Intel header.b="XnaY/ywR"; 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 c11-20020a170902d48b00b001a6b5a7db52si1257516plg.596.2023.06.02.11.22.39; Fri, 02 Jun 2023 11:22:54 -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="XnaY/ywR"; 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 S237025AbjFBSSK (ORCPT + 99 others); Fri, 2 Jun 2023 14:18:10 -0400 Received: from lindbergh.monkeyblade.net ([23.128.96.19]:37028 "EHLO lindbergh.monkeyblade.net" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S237026AbjFBSRp (ORCPT ); Fri, 2 Jun 2023 14:17:45 -0400 Received: from mga05.intel.com (mga05.intel.com [192.55.52.43]) by lindbergh.monkeyblade.net (Postfix) with ESMTPS id B63F5198; Fri, 2 Jun 2023 11:17:43 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=intel.com; i=@intel.com; q=dns/txt; s=Intel; t=1685729863; x=1717265863; h=from:to:cc:subject:date:message-id:in-reply-to: references:mime-version:content-transfer-encoding; bh=n9e+x5KIG9y3L9yhpC/i1d2YZuCh2BS2PfXSQcvbH+g=; b=XnaY/ywRsrLF0yQKZLI49UmGyPUM81cFJzVLW6LOTNntlFUbXQkJZvWz 0jNN+R+dRXVaG91XJ4PZ8p7i6os9hOOvQmLH+SAlsdyD2fVWLVG3OmEvO HMnV1t1K1oAZWeBQYeGUaPWJxVZs4SS52hWRvem4VbnLDxDz0FwznWJsH IJWrMxlWeFkhEWGQzHWtsuw5gLM/nfD9zQy57W4AI3lwRT8inQiO5LfFG AINJHeEtCmJ1A4VTTxAZMdrWY5bjVOGoz2zw3BYlBTzQcQfj34xQ3vAO8 XA7WkYI9+PjIdY0G3UhtFMTMKRk1cbjgaito51RkQcwAnBNigwQbZgpYW w==; X-IronPort-AV: E=McAfee;i="6600,9927,10729"; a="442310256" X-IronPort-AV: E=Sophos;i="6.00,213,1681196400"; d="scan'208";a="442310256" Received: from orsmga004.jf.intel.com ([10.7.209.38]) by fmsmga105.fm.intel.com with ESMTP/TLS/ECDHE-RSA-AES256-GCM-SHA384; 02 Jun 2023 11:17:39 -0700 X-ExtLoop1: 1 X-IronPort-AV: E=McAfee;i="6600,9927,10729"; a="832060974" X-IronPort-AV: E=Sophos;i="6.00,213,1681196400"; d="scan'208";a="832060974" Received: from srinivas-otcpl-7600.jf.intel.com (HELO jacob-builder.jf.intel.com) ([10.54.97.184]) by orsmga004.jf.intel.com with ESMTP; 02 Jun 2023 11:17:39 -0700 From: Jacob Pan To: LKML , iommu@lists.linux.dev, Jason Gunthorpe , "Lu Baolu" , Joerg Roedel , "Robin Murphy" , Jean-Philippe Brucker , dmaengine@vger.kernel.org, vkoul@kernel.org Cc: "Will Deacon" , David Woodhouse , Raj Ashok , "Tian, Kevin" , Yi Liu , "Yu, Fenghua" , Dave Jiang , Tony Luck , "Zanussi, Tom" , rex.zhang@intel.com, xiaochen.shen@intel.com, narayan.ranganathan@intel.com, Jacob Pan Subject: [PATCH v8 6/7] iommu/vt-d: Add set_dev_pasid callback for dma domain Date: Fri, 2 Jun 2023 11:22:11 -0700 Message-Id: <20230602182212.150825-7-jacob.jun.pan@linux.intel.com> X-Mailer: git-send-email 2.25.1 In-Reply-To: <20230602182212.150825-1-jacob.jun.pan@linux.intel.com> References: <20230602182212.150825-1-jacob.jun.pan@linux.intel.com> MIME-Version: 1.0 Content-Transfer-Encoding: 8bit X-Spam-Status: No, score=-4.5 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 From: Lu Baolu This allows the upper layers to set a domain to a PASID of a device if the PASID feature is supported by the IOMMU hardware. The typical use cases are, for example, kernel DMA with PASID and hardware assisted mediated device drivers. The attaching device and pasid information is tracked in a per-domain list and is used for IOTLB and devTLB invalidation. Signed-off-by: Lu Baolu Signed-off-by: Jacob Pan --- drivers/iommu/intel/iommu.c | 103 ++++++++++++++++++++++++++++++++++-- drivers/iommu/intel/iommu.h | 7 +++ 2 files changed, 105 insertions(+), 5 deletions(-) diff --git a/drivers/iommu/intel/iommu.c b/drivers/iommu/intel/iommu.c index 8ea656446616..a1f4730743ee 100644 --- a/drivers/iommu/intel/iommu.c +++ b/drivers/iommu/intel/iommu.c @@ -1367,6 +1367,7 @@ domain_lookup_dev_info(struct dmar_domain *domain, static void domain_update_iotlb(struct dmar_domain *domain) { + struct dev_pasid_info *dev_pasid; struct device_domain_info *info; bool has_iotlb_device = false; unsigned long flags; @@ -1378,6 +1379,14 @@ static void domain_update_iotlb(struct dmar_domain *domain) break; } } + + list_for_each_entry(dev_pasid, &domain->dev_pasids, link_domain) { + info = dev_iommu_priv_get(dev_pasid->dev); + if (info->ats_enabled) { + has_iotlb_device = true; + break; + } + } domain->has_iotlb_device = has_iotlb_device; spin_unlock_irqrestore(&domain->lock, flags); } @@ -1463,6 +1472,7 @@ static void __iommu_flush_dev_iotlb(struct device_domain_info *info, static void iommu_flush_dev_iotlb(struct dmar_domain *domain, u64 addr, unsigned mask) { + struct dev_pasid_info *dev_pasid; struct device_domain_info *info; unsigned long flags; @@ -1472,6 +1482,19 @@ static void iommu_flush_dev_iotlb(struct dmar_domain *domain, spin_lock_irqsave(&domain->lock, flags); list_for_each_entry(info, &domain->devices, link) __iommu_flush_dev_iotlb(info, addr, mask); + + list_for_each_entry(dev_pasid, &domain->dev_pasids, link_domain) { + info = dev_iommu_priv_get(dev_pasid->dev); + + if (!info->ats_enabled) + continue; + + qi_flush_dev_iotlb_pasid(info->iommu, + PCI_DEVID(info->bus, info->devfn), + info->pfsid, dev_pasid->pasid, + info->ats_qdep, addr, + mask); + } spin_unlock_irqrestore(&domain->lock, flags); } @@ -1485,9 +1508,13 @@ static void domain_flush_pasid_iotlb(struct intel_iommu *iommu, unsigned long npages, bool ih) { u16 did = domain_id_iommu(domain, iommu); + struct dev_pasid_info *dev_pasid; unsigned long flags; spin_lock_irqsave(&domain->lock, flags); + list_for_each_entry(dev_pasid, &domain->dev_pasids, link_domain) + qi_flush_piotlb(iommu, did, dev_pasid->pasid, addr, npages, ih); + if (!list_empty(&domain->devices)) qi_flush_piotlb(iommu, did, IOMMU_NO_PASID, addr, npages, ih); spin_unlock_irqrestore(&domain->lock, flags); @@ -1752,6 +1779,7 @@ static struct dmar_domain *alloc_domain(unsigned int type) domain->use_first_level = true; domain->has_iotlb_device = false; INIT_LIST_HEAD(&domain->devices); + INIT_LIST_HEAD(&domain->dev_pasids); spin_lock_init(&domain->lock); xa_init(&domain->iommu_array); @@ -4738,7 +4766,10 @@ static void intel_iommu_iotlb_sync_map(struct iommu_domain *domain, static void intel_iommu_remove_dev_pasid(struct device *dev, ioasid_t pasid) { struct intel_iommu *iommu = device_to_iommu(dev, NULL, NULL); + struct dev_pasid_info *curr, *dev_pasid = NULL; + struct dmar_domain *dmar_domain; struct iommu_domain *domain; + unsigned long flags; domain = iommu_get_domain_for_dev_pasid(dev, pasid, 0); if (!domain) @@ -4754,17 +4785,78 @@ static void intel_iommu_remove_dev_pasid(struct device *dev, ioasid_t pasid) goto out_tear_down; } - /* - * Should never reach here until we add support for attaching - * non-SVA domain to a pasid. - */ - WARN_ON(1); + dmar_domain = to_dmar_domain(domain); + spin_lock_irqsave(&dmar_domain->lock, flags); + list_for_each_entry(curr, &dmar_domain->dev_pasids, link_domain) { + if (curr->dev == dev && curr->pasid == pasid) { + list_del(&curr->link_domain); + dev_pasid = curr; + break; + } + } + spin_unlock_irqrestore(&dmar_domain->lock, flags); + domain_detach_iommu(dmar_domain, iommu); + kfree(dev_pasid); out_tear_down: intel_pasid_tear_down_entry(iommu, dev, pasid, false); intel_drain_pasid_prq(dev, pasid); } +static int intel_iommu_set_dev_pasid(struct iommu_domain *domain, + struct device *dev, ioasid_t pasid) +{ + struct device_domain_info *info = dev_iommu_priv_get(dev); + struct dmar_domain *dmar_domain = to_dmar_domain(domain); + struct intel_iommu *iommu = info->iommu; + struct dev_pasid_info *dev_pasid; + unsigned long flags; + int ret; + + if (!pasid_supported(iommu) || dev_is_real_dma_subdevice(dev)) + return -EOPNOTSUPP; + + if (context_copied(iommu, info->bus, info->devfn)) + return -EBUSY; + + ret = prepare_domain_attach_device(domain, dev); + if (ret) + return ret; + + dev_pasid = kzalloc(sizeof(*dev_pasid), GFP_KERNEL); + if (!dev_pasid) + return -ENOMEM; + + ret = domain_attach_iommu(dmar_domain, iommu); + if (ret) + goto out_free; + + if (domain_type_is_si(dmar_domain)) + ret = intel_pasid_setup_pass_through(iommu, dmar_domain, + dev, pasid); + else if (dmar_domain->use_first_level) + ret = domain_setup_first_level(iommu, dmar_domain, + dev, pasid); + else + ret = intel_pasid_setup_second_level(iommu, dmar_domain, + dev, pasid); + if (ret) + goto out_detach_iommu; + + dev_pasid->dev = dev; + dev_pasid->pasid = pasid; + spin_lock_irqsave(&dmar_domain->lock, flags); + list_add(&dev_pasid->link_domain, &dmar_domain->dev_pasids); + spin_unlock_irqrestore(&dmar_domain->lock, flags); + + return 0; +out_detach_iommu: + domain_detach_iommu(dmar_domain, iommu); +out_free: + kfree(dev_pasid); + return ret; +} + const struct iommu_ops intel_iommu_ops = { .capable = intel_iommu_capable, .domain_alloc = intel_iommu_domain_alloc, @@ -4784,6 +4876,7 @@ const struct iommu_ops intel_iommu_ops = { #endif .default_domain_ops = &(const struct iommu_domain_ops) { .attach_dev = intel_iommu_attach_device, + .set_dev_pasid = intel_iommu_set_dev_pasid, .map_pages = intel_iommu_map_pages, .unmap_pages = intel_iommu_unmap_pages, .iotlb_sync_map = intel_iommu_iotlb_sync_map, diff --git a/drivers/iommu/intel/iommu.h b/drivers/iommu/intel/iommu.h index 6d94a29f5d52..68bb7cdf5543 100644 --- a/drivers/iommu/intel/iommu.h +++ b/drivers/iommu/intel/iommu.h @@ -595,6 +595,7 @@ struct dmar_domain { spinlock_t lock; /* Protect device tracking lists */ struct list_head devices; /* all devices' list */ + struct list_head dev_pasids; /* all attached pasids */ struct dma_pte *pgd; /* virtual address */ int gaw; /* max guest address width */ @@ -717,6 +718,12 @@ struct device_domain_info { struct pasid_table *pasid_table; /* pasid table */ }; +struct dev_pasid_info { + struct list_head link_domain; /* link to domain siblings */ + struct device *dev; /* the physical device */ + ioasid_t pasid; /* PASID of the physical device */ +}; + static inline void __iommu_flush_cache( struct intel_iommu *iommu, void *addr, int size) { -- 2.25.1