Received: by 10.192.165.156 with SMTP id m28csp1135242imm; Mon, 16 Apr 2018 14:52:50 -0700 (PDT) X-Google-Smtp-Source: AIpwx4+oIiDswWv4XGHcZ51vkhouyST8joa2gqWGdoG80q1dTdaW1LcgcK6YcbB+A7bs+U0GklVx X-Received: by 2002:a17:902:be15:: with SMTP id r21-v6mr10701712pls.237.1523915570677; Mon, 16 Apr 2018 14:52:50 -0700 (PDT) ARC-Seal: i=1; a=rsa-sha256; t=1523915570; cv=none; d=google.com; s=arc-20160816; b=AsSW0k1jsIwiseoKS+xJTNHG4NVqK6t/2UnMpEUBHERn4yL0Xy8gF3KmcaQAPT+Fi0 aeMJExolOVdCVFj0IC1gaV4aH8Mz+0ux4X2Uwse5vzM01wKTx1phNZHoTYzcOJXi5bY6 xFHJdGhg7fvaz2vgRdb9+LqV+ITMA5lRML5Jx/8BI5OrU/ygxXDCFiYIDobSff5mBiRG ydu4sCUO9jgFgXOa0tZ+7j0D9wI2tE8JljvEe84mHSDo398FjjgzheJRsK43crqzI2bX vEiOodgO4ZXHxNU3vi+1p1cjl2d7rGN1omuB5sDuFrm0depj1mEre8jyox+OcTfQzshu 2ALw== ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=google.com; s=arc-20160816; h=list-id:precedence:sender:references:in-reply-to:message-id:date :subject:cc:to:from:arc-authentication-results; bh=m3Mc0/OujTBJ5tM+aFl+AJ5Jv3z6O+ZyJ8yk1jANiUI=; b=WjvIXm/Stt/nSUTZmVN4hKZv7RxojqbaED5j4BWPIqkG1fEdNEOzmsu/cTV44tXTMp huBmIHcFk8GkBVpjukj400RG91p83MZcHFureYhFd0J2XHz2fndJfHXkQNkRdDadOi9a 70Fgh7XWa2gtr8N+zMV6tEYTj05rjHAj2Opu8lf5xzg3Vf2MwZ5lk6Lj/z1R8gtZISbQ UQahsDC0ui1eI2Q3gtvadHK5X0ZW9JCPYHE1GP6q7gQwnCufZOtN8rU4qcxHyrWre6e7 A0zVOl5QdZxUd4/aZGb0VbNuJlcDWW6ROhBPogQTacob8UTJH035oPKAQndqGZMe/G9X QgXw== ARC-Authentication-Results: i=1; mx.google.com; spf=pass (google.com: best guess record for domain of linux-kernel-owner@vger.kernel.org designates 209.132.180.67 as permitted sender) smtp.mailfrom=linux-kernel-owner@vger.kernel.org Return-Path: Received: from vger.kernel.org (vger.kernel.org. [209.132.180.67]) by mx.google.com with ESMTP id r11si11784385pff.160.2018.04.16.14.52.36; Mon, 16 Apr 2018 14:52:50 -0700 (PDT) Received-SPF: pass (google.com: best guess record for domain of linux-kernel-owner@vger.kernel.org designates 209.132.180.67 as permitted sender) client-ip=209.132.180.67; Authentication-Results: mx.google.com; spf=pass (google.com: best guess record for domain of linux-kernel-owner@vger.kernel.org designates 209.132.180.67 as permitted sender) smtp.mailfrom=linux-kernel-owner@vger.kernel.org Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1753520AbeDPVuz (ORCPT + 99 others); Mon, 16 Apr 2018 17:50:55 -0400 Received: from mga09.intel.com ([134.134.136.24]:12291 "EHLO mga09.intel.com" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1752844AbeDPVqo (ORCPT ); Mon, 16 Apr 2018 17:46:44 -0400 X-Amp-Result: SKIPPED(no attachment in message) X-Amp-File-Uploaded: False Received: from orsmga006.jf.intel.com ([10.7.209.51]) by orsmga102.jf.intel.com with ESMTP/TLS/DHE-RSA-AES256-GCM-SHA384; 16 Apr 2018 14:46:42 -0700 X-ExtLoop1: 1 X-IronPort-AV: E=Sophos;i="5.48,460,1517904000"; d="scan'208";a="34740143" Received: from jacob-builder.jf.intel.com ([10.7.199.155]) by orsmga006.jf.intel.com with ESMTP; 16 Apr 2018 14:46:42 -0700 From: Jacob Pan To: iommu@lists.linux-foundation.org, LKML , Joerg Roedel , David Woodhouse , Greg Kroah-Hartman , Alex Williamson , Jean-Philippe Brucker Cc: Rafael Wysocki , "Liu, Yi L" , "Tian, Kevin" , Raj Ashok , Jean Delvare , "Christoph Hellwig" , "Lu Baolu" , Jacob Pan , Liu@vger.kernel.org, Yi L Subject: [PATCH v4 04/22] iommu/vt-d: add bind_pasid_table function Date: Mon, 16 Apr 2018 14:48:53 -0700 Message-Id: <1523915351-54415-5-git-send-email-jacob.jun.pan@linux.intel.com> X-Mailer: git-send-email 2.7.4 In-Reply-To: <1523915351-54415-1-git-send-email-jacob.jun.pan@linux.intel.com> References: <1523915351-54415-1-git-send-email-jacob.jun.pan@linux.intel.com> Sender: linux-kernel-owner@vger.kernel.org Precedence: bulk List-ID: X-Mailing-List: linux-kernel@vger.kernel.org Add Intel VT-d ops to the generic iommu_bind_pasid_table API functions. The primary use case is for direct assignment of SVM capable device. Originated from emulated IOMMU in the guest, the request goes through many layers (e.g. VFIO). Upon calling host IOMMU driver, caller passes guest PASID table pointer (GPA) and size. Device context table entry is modified by Intel IOMMU specific bind_pasid_table function. This will turn on nesting mode and matching translation type. The unbind operation restores default context mapping. Signed-off-by: Jacob Pan Signed-off-by: Liu, Yi L Signed-off-by: Ashok Raj --- drivers/iommu/intel-iommu.c | 119 ++++++++++++++++++++++++++++++++++++++++++ include/linux/dma_remapping.h | 1 + 2 files changed, 120 insertions(+) diff --git a/drivers/iommu/intel-iommu.c b/drivers/iommu/intel-iommu.c index a0f81a4..d8058be 100644 --- a/drivers/iommu/intel-iommu.c +++ b/drivers/iommu/intel-iommu.c @@ -2409,6 +2409,7 @@ static struct dmar_domain *dmar_insert_one_dev_info(struct intel_iommu *iommu, info->ats_supported = info->pasid_supported = info->pri_supported = 0; info->ats_enabled = info->pasid_enabled = info->pri_enabled = 0; info->ats_qdep = 0; + info->pasid_table_bound = 0; info->dev = dev; info->domain = domain; info->iommu = iommu; @@ -5132,6 +5133,7 @@ static void intel_iommu_put_resv_regions(struct device *dev, #ifdef CONFIG_INTEL_IOMMU_SVM #define MAX_NR_PASID_BITS (20) +#define MIN_NR_PASID_BITS (5) static inline unsigned long intel_iommu_get_pts(struct intel_iommu *iommu) { /* @@ -5258,6 +5260,119 @@ struct intel_iommu *intel_svm_device_to_iommu(struct device *dev) return iommu; } + +static int intel_iommu_bind_pasid_table(struct iommu_domain *domain, + struct device *dev, struct pasid_table_config *pasidt_binfo) +{ + struct intel_iommu *iommu; + struct context_entry *context; + struct dmar_domain *dmar_domain = to_dmar_domain(domain); + struct device_domain_info *info; + struct pci_dev *pdev; + u8 bus, devfn, host_table_pasid_bits; + u16 did, sid; + int ret = 0; + unsigned long flags; + u64 ctx_lo; + + iommu = device_to_iommu(dev, &bus, &devfn); + if (!iommu) + return -ENODEV; + /* VT-d spec section 9.4 says pasid table size is encoded as 2^(x+5) */ + host_table_pasid_bits = intel_iommu_get_pts(iommu) + MIN_NR_PASID_BITS; + if (!pasidt_binfo || pasidt_binfo->pasid_bits > host_table_pasid_bits || + pasidt_binfo->pasid_bits < MIN_NR_PASID_BITS) { + pr_err("Invalid gPASID bits %d, host range %d - %d\n", + pasidt_binfo->pasid_bits, + MIN_NR_PASID_BITS, host_table_pasid_bits); + return -ERANGE; + } + if (!ecap_nest(iommu->ecap)) { + dev_err(dev, "Cannot bind PASID table, no nested translation\n"); + ret = -EINVAL; + goto out; + } + pdev = to_pci_dev(dev); + sid = PCI_DEVID(bus, devfn); + info = dev->archdata.iommu; + + if (!info) { + dev_err(dev, "Invalid device domain info\n"); + ret = -EINVAL; + goto out; + } + if (info->pasid_table_bound) { + dev_err(dev, "Device PASID table already bound\n"); + ret = -EBUSY; + goto out; + } + if (!info->pasid_enabled) { + ret = pci_enable_pasid(pdev, info->pasid_supported & ~1); + if (ret) { + dev_err(dev, "Failed to enable PASID\n"); + goto out; + } + } + spin_lock_irqsave(&iommu->lock, flags); + context = iommu_context_addr(iommu, bus, devfn, 0); + if (!context_present(context)) { + dev_err(dev, "Context not present\n"); + ret = -EINVAL; + goto out_unlock; + } + + /* Anticipate guest to use SVM and owns the first level, so we turn + * nested mode on + */ + ctx_lo = context[0].lo; + ctx_lo |= CONTEXT_NESTE | CONTEXT_PRS | CONTEXT_PASIDE; + ctx_lo &= ~CONTEXT_TT_MASK; + ctx_lo |= CONTEXT_TT_DEV_IOTLB << 2; + context[0].lo = ctx_lo; + + /* Assign guest PASID table pointer and size order */ + ctx_lo = (pasidt_binfo->base_ptr & VTD_PAGE_MASK) | + (pasidt_binfo->pasid_bits - MIN_NR_PASID_BITS); + context[1].lo = ctx_lo; + /* make sure context entry is updated before flushing */ + wmb(); + did = dmar_domain->iommu_did[iommu->seq_id]; + iommu->flush.flush_context(iommu, did, + (((u16)bus) << 8) | devfn, + DMA_CCMD_MASK_NOBIT, + DMA_CCMD_DEVICE_INVL); + iommu->flush.flush_iotlb(iommu, did, 0, 0, DMA_TLB_DSI_FLUSH); + info->pasid_table_bound = 1; +out_unlock: + spin_unlock_irqrestore(&iommu->lock, flags); +out: + return ret; +} + +static void intel_iommu_unbind_pasid_table(struct iommu_domain *domain, + struct device *dev) +{ + struct intel_iommu *iommu; + struct dmar_domain *dmar_domain = to_dmar_domain(domain); + struct device_domain_info *info; + u8 bus, devfn; + + info = dev->archdata.iommu; + if (!info) { + dev_err(dev, "Invalid device domain info\n"); + return; + } + iommu = device_to_iommu(dev, &bus, &devfn); + if (!iommu) { + dev_err(dev, "No IOMMU for device to unbind PASID table\n"); + return; + } + + domain_context_clear(iommu, dev); + + domain_context_mapping_one(dmar_domain, iommu, bus, devfn); + info->pasid_table_bound = 0; +} #endif /* CONFIG_INTEL_IOMMU_SVM */ const struct iommu_ops intel_iommu_ops = { @@ -5266,6 +5381,10 @@ const struct iommu_ops intel_iommu_ops = { .domain_free = intel_iommu_domain_free, .attach_dev = intel_iommu_attach_device, .detach_dev = intel_iommu_detach_device, +#ifdef CONFIG_INTEL_IOMMU_SVM + .bind_pasid_table = intel_iommu_bind_pasid_table, + .unbind_pasid_table = intel_iommu_unbind_pasid_table, +#endif .map = intel_iommu_map, .unmap = intel_iommu_unmap, .map_sg = default_iommu_map_sg, diff --git a/include/linux/dma_remapping.h b/include/linux/dma_remapping.h index 21b3e7d..db290b2 100644 --- a/include/linux/dma_remapping.h +++ b/include/linux/dma_remapping.h @@ -28,6 +28,7 @@ #define CONTEXT_DINVE (1ULL << 8) #define CONTEXT_PRS (1ULL << 9) +#define CONTEXT_NESTE (1ULL << 10) #define CONTEXT_PASIDE (1ULL << 11) struct intel_iommu; -- 2.7.4