From patchwork Tue Oct 13 21:35:48 2015 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: David Woodhouse X-Patchwork-Id: 7389161 Return-Path: X-Original-To: patchwork-intel-gfx@patchwork.kernel.org Delivered-To: patchwork-parsemail@patchwork2.web.kernel.org Received: from mail.kernel.org (mail.kernel.org [198.145.29.136]) by patchwork2.web.kernel.org (Postfix) with ESMTP id 2AC32BEEA4 for ; Tue, 13 Oct 2015 21:35:56 +0000 (UTC) Received: from mail.kernel.org (localhost [127.0.0.1]) by mail.kernel.org (Postfix) with ESMTP id 2A9D120734 for ; Tue, 13 Oct 2015 21:35:55 +0000 (UTC) Received: from gabe.freedesktop.org (gabe.freedesktop.org [131.252.210.177]) by mail.kernel.org (Postfix) with ESMTP id AFCDD20723 for ; Tue, 13 Oct 2015 21:35:53 +0000 (UTC) Received: from gabe.freedesktop.org (localhost [127.0.0.1]) by gabe.freedesktop.org (Postfix) with ESMTP id 326DF6E591; Tue, 13 Oct 2015 14:35:53 -0700 (PDT) X-Original-To: intel-gfx@lists.freedesktop.org Delivered-To: intel-gfx@lists.freedesktop.org Received: from bombadil.infradead.org (bombadil.infradead.org [198.137.202.9]) by gabe.freedesktop.org (Postfix) with ESMTPS id 46A146E591 for ; Tue, 13 Oct 2015 14:35:52 -0700 (PDT) Received: from i7.infradead.org ([2001:8b0:10b:1:21e:67ff:fecb:7a92]) by bombadil.infradead.org with esmtpsa (Exim 4.80.1 #2 (Red Hat Linux)) id 1Zm7Ed-0007Yt-GE; Tue, 13 Oct 2015 21:35:51 +0000 Message-ID: <1444772148.125804.68.camel@infradead.org> From: David Woodhouse To: iommu@lists.linux-foundation.org, intel-gfx@lists.freedesktop.org, Jesse Barnes Date: Tue, 13 Oct 2015 22:35:48 +0100 In-Reply-To: <1444771787.125804.50.camel@infradead.org> References: <1444771787.125804.50.camel@infradead.org> X-Mailer: Evolution 3.16.5 (3.16.5-3.fc22) Mime-Version: 1.0 X-SRS-Rewrite: SMTP reverse-path rewritten from by bombadil.infradead.org See http://www.infradead.org/rpr.html Subject: [Intel-gfx] [PATCH v2 10/10] iommu/vt-d: Add callback to device driver on page faults X-BeenThere: intel-gfx@lists.freedesktop.org X-Mailman-Version: 2.1.18 Precedence: list List-Id: Intel graphics driver community testing & development List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Errors-To: intel-gfx-bounces@lists.freedesktop.org Sender: "Intel-gfx" X-Spam-Status: No, score=-4.2 required=5.0 tests=BAYES_00, RCVD_IN_DNSWL_MED, T_RP_MATCHES_RCVD, UNPARSEABLE_RELAY autolearn=unavailable version=3.3.1 X-Spam-Checker-Version: SpamAssassin 3.3.1 (2010-03-16) on mail.kernel.org X-Virus-Scanned: ClamAV using ClamSMTP Signed-off-by: David Woodhouse --- drivers/iommu/intel-iommu.c | 3 ++- drivers/iommu/intel-svm.c | 26 +++++++++++++++++++++++++- include/linux/intel-iommu.h | 3 +++ include/linux/intel-svm.h | 21 ++++++++++++++++++--- 4 files changed, 48 insertions(+), 5 deletions(-) diff --git a/drivers/iommu/intel-iommu.c b/drivers/iommu/intel-iommu.c index 548f6e5..4f2eab6 100644 --- a/drivers/iommu/intel-iommu.c +++ b/drivers/iommu/intel-iommu.c @@ -5029,12 +5029,13 @@ int intel_iommu_enable_pasid(struct intel_iommu *iommu, struct intel_svm_dev *sd if (!info->pasid_enabled) iommu_enable_dev_iotlb(info); + sdev->sid = (((u16)bus) << 8) | devfn; + if (info->ats_enabled) { sdev->dev_iotlb = 1; sdev->qdep = info->ats_qdep; if (sdev->qdep >= QI_DEV_EIOTLB_MAX_INVS) sdev->qdep = 0; - sdev->sid = (((u16)bus) << 8) | devfn; } return 0; diff --git a/drivers/iommu/intel-svm.c b/drivers/iommu/intel-svm.c index 0e86542..0a31350 100644 --- a/drivers/iommu/intel-svm.c +++ b/drivers/iommu/intel-svm.c @@ -264,7 +264,7 @@ static const struct mmu_notifier_ops intel_mmuops = { static DEFINE_MUTEX(pasid_mutex); -int intel_svm_bind_mm(struct device *dev, int *pasid) +int intel_svm_bind_mm(struct device *dev, int *pasid, int flags, struct svm_dev_ops *ops) { struct intel_iommu *iommu = intel_svm_device_to_iommu(dev); struct intel_svm_dev *sdev; @@ -302,6 +302,10 @@ int intel_svm_bind_mm(struct device *dev, int *pasid) list_for_each_entry(sdev, &svm->devs, list) { if (dev == sdev->dev) { + if (sdev->ops != ops) { + ret = -EBUSY; + goto out; + } sdev->users++; goto success; } @@ -327,6 +331,7 @@ int intel_svm_bind_mm(struct device *dev, int *pasid) } /* Finish the setup now we know we're keeping it */ sdev->users = 1; + sdev->ops = ops; init_rcu_head(&sdev->rcu); if (!svm) { @@ -456,6 +461,7 @@ static irqreturn_t prq_event_thread(int irq, void *d) tail = dmar_readq(iommu->reg + DMAR_PQT_REG) & PRQ_RING_MASK; head = dmar_readq(iommu->reg + DMAR_PQH_REG) & PRQ_RING_MASK; while (head != tail) { + struct intel_svm_dev *sdev; struct vm_area_struct *vma; struct page_req_dsc *req; struct qi_desc resp; @@ -507,6 +513,24 @@ static irqreturn_t prq_event_thread(int irq, void *d) up_read(&svm->mm->mmap_sem); bad_req: /* Accounting for major/minor faults? */ + rcu_read_lock(); + list_for_each_entry_rcu(sdev, &svm->devs, list) { + if (sdev->sid == ((req->bus << 8) | req->devfn)) + break; + } + /* Other devices can go away, but the drivers are not permitted + * to unbind while any page faults might be in flight. So it's + * OK to drop the 'lock' here now we have it. */ + rcu_read_unlock(); + + if (WARN_ON(&sdev->list == &svm->devs)) + sdev = NULL; + + if (sdev && sdev->ops && sdev->ops->fault_cb) { + int rwxp = (req->rd_req << 3) | (req->wr_req << 2) | + (req->wr_req << 1) | (req->exe_req); + sdev->ops->fault_cb(sdev->dev, req->pasid, req->addr, req->private, rwxp, result); + } if (req->lpig) { /* Page Group Response */ diff --git a/include/linux/intel-iommu.h b/include/linux/intel-iommu.h index e5b80d3..57be14f 100644 --- a/include/linux/intel-iommu.h +++ b/include/linux/intel-iommu.h @@ -472,10 +472,13 @@ extern int intel_svm_free_pasid_tables(struct intel_iommu *iommu); extern int intel_svm_enable_prq(struct intel_iommu *iommu); extern int intel_svm_finish_prq(struct intel_iommu *iommu); +struct svm_dev_ops; + struct intel_svm_dev { struct list_head list; struct rcu_head rcu; struct device *dev; + struct svm_dev_ops *ops; int users; u16 did; u16 dev_iotlb:1; diff --git a/include/linux/intel-svm.h b/include/linux/intel-svm.h index 42f80ad..239f8a1 100644 --- a/include/linux/intel-svm.h +++ b/include/linux/intel-svm.h @@ -20,10 +20,23 @@ struct device; +struct svm_dev_ops { + void (*fault_cb)(struct device *dev, int pasid, u64 address, + u32 private, int rwxp, int response); +}; + +/* Values for rxwp in fault_cb callback */ +#define SVM_REQ_READ (1<<3) +#define SVM_REQ_WRITE (1<<2) +#define SVM_REQ_EXEC (1<<1) +#define SVM_REQ_PRIV (1<<0) + /** * intel_svm_bind_mm() - Bind the current process to a PASID * @dev: Device to be granted acccess * @pasid: Address for allocated PASID + * @flags: Flags. Later for requesting supervisor mode, etc. + * @ops: Callbacks to device driver * * This function attempts to enable PASID support for the given device. * If the @pasid argument is non-%NULL, a PASID is allocated for access @@ -45,7 +58,8 @@ struct device; * Multiple calls from the same process may result in the same PASID * being re-used. A reference count is kept. */ -extern int intel_svm_bind_mm(struct device *dev, int *pasid); +extern int intel_svm_bind_mm(struct device *dev, int *pasid, int flags, + struct svm_dev_ops *ops); /** * intel_svm_unbind_mm() - Unbind a specified PASID @@ -66,7 +80,8 @@ extern int intel_svm_unbind_mm(struct device *dev, int pasid); #else /* CONFIG_INTEL_IOMMU_SVM */ -static inline int intel_svm_bind_mm(struct device *dev, int *pasid) +static inline int intel_svm_bind_mm(struct device *dev, int *pasid, + int flags, struct svm_dev_ops *ops) { return -ENOSYS; } @@ -77,6 +92,6 @@ static inline int intel_svm_unbind_mm(struct device *dev, int pasid) } #endif /* CONFIG_INTEL_IOMMU_SVM */ -#define intel_svm_available(dev) (!intel_svm_bind_mm((dev), NULL)) +#define intel_svm_available(dev) (!intel_svm_bind_mm((dev), NULL, 0, NULL)) #endif /* __INTEL_SVM_H__ */