linux-pci.vger.kernel.org archive mirror
 help / color / mirror / Atom feed
From: jglisse@redhat.com
To: linux-mm@kvack.org
Cc: linux-kernel@vger.kernel.org,
	"Jérôme Glisse" <jglisse@redhat.com>,
	"Logan Gunthorpe" <logang@deltatee.com>,
	"Greg Kroah-Hartman" <gregkh@linuxfoundation.org>,
	"Rafael J . Wysocki" <rafael@kernel.org>,
	"Bjorn Helgaas" <bhelgaas@google.com>,
	"Christian Koenig" <christian.koenig@amd.com>,
	"Felix Kuehling" <Felix.Kuehling@amd.com>,
	"Jason Gunthorpe" <jgg@mellanox.com>,
	linux-pci@vger.kernel.org, dri-devel@lists.freedesktop.org,
	"Christoph Hellwig" <hch@lst.de>,
	"Marek Szyprowski" <m.szyprowski@samsung.com>,
	"Robin Murphy" <robin.murphy@arm.com>,
	"Joerg Roedel" <jroedel@suse.de>,
	iommu@lists.linux-foundation.org
Subject: [RFC PATCH 5/5] mm/hmm: add support for peer to peer to special device vma
Date: Tue, 29 Jan 2019 12:47:28 -0500	[thread overview]
Message-ID: <20190129174728.6430-6-jglisse@redhat.com> (raw)
In-Reply-To: <20190129174728.6430-1-jglisse@redhat.com>

From: Jérôme Glisse <jglisse@redhat.com>

Special device vma (mmap of a device file) can correspond to device
driver object that some device driver might want to share with other
device (giving access to). This add support for HMM to map those
special device vma if the owning device (exporter) allows it.

Signed-off-by: Jérôme Glisse <jglisse@redhat.com>
Cc: Logan Gunthorpe <logang@deltatee.com>
Cc: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
Cc: Rafael J. Wysocki <rafael@kernel.org>
Cc: Bjorn Helgaas <bhelgaas@google.com>
Cc: Christian Koenig <christian.koenig@amd.com>
Cc: Felix Kuehling <Felix.Kuehling@amd.com>
Cc: Jason Gunthorpe <jgg@mellanox.com>
Cc: linux-pci@vger.kernel.org
Cc: dri-devel@lists.freedesktop.org
Cc: Christoph Hellwig <hch@lst.de>
Cc: Marek Szyprowski <m.szyprowski@samsung.com>
Cc: Robin Murphy <robin.murphy@arm.com>
Cc: Joerg Roedel <jroedel@suse.de>
Cc: iommu@lists.linux-foundation.org
---
 include/linux/hmm.h |   6 ++
 mm/hmm.c            | 156 ++++++++++++++++++++++++++++++++++----------
 2 files changed, 128 insertions(+), 34 deletions(-)

diff --git a/include/linux/hmm.h b/include/linux/hmm.h
index 7a3ac182cc48..98ebe9f52432 100644
--- a/include/linux/hmm.h
+++ b/include/linux/hmm.h
@@ -137,6 +137,7 @@ enum hmm_pfn_flag_e {
  *      result of vmf_insert_pfn() or vm_insert_page(). Therefore, it should not
  *      be mirrored by a device, because the entry will never have HMM_PFN_VALID
  *      set and the pfn value is undefined.
+ * HMM_PFN_P2P: this entry have been map as P2P ie the dma address is valid
  *
  * Driver provide entry value for none entry, error entry and special entry,
  * driver can alias (ie use same value for error and special for instance). It
@@ -151,6 +152,7 @@ enum hmm_pfn_value_e {
 	HMM_PFN_ERROR,
 	HMM_PFN_NONE,
 	HMM_PFN_SPECIAL,
+	HMM_PFN_P2P,
 	HMM_PFN_VALUE_MAX
 };
 
@@ -250,6 +252,8 @@ static inline bool hmm_range_valid(struct hmm_range *range)
 static inline struct page *hmm_pfn_to_page(const struct hmm_range *range,
 					   uint64_t pfn)
 {
+	if (pfn == range->values[HMM_PFN_P2P])
+		return NULL;
 	if (pfn == range->values[HMM_PFN_NONE])
 		return NULL;
 	if (pfn == range->values[HMM_PFN_ERROR])
@@ -270,6 +274,8 @@ static inline struct page *hmm_pfn_to_page(const struct hmm_range *range,
 static inline unsigned long hmm_pfn_to_pfn(const struct hmm_range *range,
 					   uint64_t pfn)
 {
+	if (pfn == range->values[HMM_PFN_P2P])
+		return -1UL;
 	if (pfn == range->values[HMM_PFN_NONE])
 		return -1UL;
 	if (pfn == range->values[HMM_PFN_ERROR])
diff --git a/mm/hmm.c b/mm/hmm.c
index fd49b1e116d0..621a4f831483 100644
--- a/mm/hmm.c
+++ b/mm/hmm.c
@@ -1058,37 +1058,36 @@ long hmm_range_snapshot(struct hmm_range *range)
 }
 EXPORT_SYMBOL(hmm_range_snapshot);
 
-/*
- * hmm_range_fault() - try to fault some address in a virtual address range
- * @range: range being faulted
- * @block: allow blocking on fault (if true it sleeps and do not drop mmap_sem)
- * Returns: 0 on success ortherwise:
- *      -EINVAL:
- *              Invalid argument
- *      -ENOMEM:
- *              Out of memory.
- *      -EPERM:
- *              Invalid permission (for instance asking for write and range
- *              is read only).
- *      -EAGAIN:
- *              If you need to retry and mmap_sem was drop. This can only
- *              happens if block argument is false.
- *      -EBUSY:
- *              If the the range is being invalidated and you should wait for
- *              invalidation to finish.
- *      -EFAULT:
- *              Invalid (ie either no valid vma or it is illegal to access that
- *              range), number of valid pages in range->pfns[] (from range start
- *              address).
- *
- * This is similar to a regular CPU page fault except that it will not trigger
- * any memory migration if the memory being faulted is not accessible by CPUs
- * and caller does not ask for migration.
- *
- * On error, for one virtual address in the range, the function will mark the
- * corresponding HMM pfn entry with an error flag.
- */
-long hmm_range_fault(struct hmm_range *range, bool block)
+static int hmm_vma_p2p_map(struct hmm_range *range, struct vm_area_struct *vma,
+			   unsigned long start, unsigned long end,
+			   struct device *device, dma_addr_t *pas)
+{
+	struct hmm_vma_walk hmm_vma_walk;
+	unsigned long npages, i;
+	bool fault, write;
+	uint64_t *pfns;
+	int ret;
+
+	i = (start - range->start) >> PAGE_SHIFT;
+	npages = (end - start) >> PAGE_SHIFT;
+	pfns = &range->pfns[i];
+	pas = &pas[i];
+
+	hmm_vma_walk.range = range;
+	hmm_vma_walk.fault = true;
+	hmm_range_need_fault(&hmm_vma_walk, pfns, npages,
+			        0, &fault, &write);
+
+	ret = vma->vm_ops->p2p_map(vma, device, start, end, pas, write);
+	for (i = 0; i < npages; ++i) {
+		pfns[i] = ret ? range->values[HMM_PFN_ERROR] :
+			  range->values[HMM_PFN_P2P];
+	}
+	return ret;
+}
+
+static long _hmm_range_fault(struct hmm_range *range, bool block,
+			     struct device *device, dma_addr_t *pas)
 {
 	const unsigned long device_vma = VM_IO | VM_PFNMAP | VM_MIXEDMAP;
 	unsigned long start = range->start, end;
@@ -1110,9 +1109,22 @@ long hmm_range_fault(struct hmm_range *range, bool block)
 		}
 
 		vma = find_vma(hmm->mm, start);
-		if (vma == NULL || (vma->vm_flags & device_vma))
+		if (vma == NULL)
 			return -EFAULT;
 
+		end = min(range->end, vma->vm_end);
+		if (vma->vm_flags & device_vma) {
+			if (!device || !pas || !vma->vm_ops->p2p_map)
+				return -EFAULT;
+
+			ret = hmm_vma_p2p_map(range, vma, start,
+					      end, device, pas);
+			if (ret)
+				return ret;
+			start = end;
+			continue;
+		}
+
 		if (is_vm_hugetlb_page(vma)) {
 			struct hstate *h = hstate_vma(vma);
 
@@ -1142,7 +1154,6 @@ long hmm_range_fault(struct hmm_range *range, bool block)
 		hmm_vma_walk.block = block;
 		hmm_vma_walk.range = range;
 		mm_walk.private = &hmm_vma_walk;
-		end = min(range->end, vma->vm_end);
 
 		mm_walk.vma = vma;
 		mm_walk.mm = vma->vm_mm;
@@ -1175,6 +1186,41 @@ long hmm_range_fault(struct hmm_range *range, bool block)
 
 	return (hmm_vma_walk.last - range->start) >> PAGE_SHIFT;
 }
+
+/*
+ * hmm_range_fault() - try to fault some address in a virtual address range
+ * @range: range being faulted
+ * @block: allow blocking on fault (if true it sleeps and do not drop mmap_sem)
+ * Returns: 0 on success ortherwise:
+ *      -EINVAL:
+ *              Invalid argument
+ *      -ENOMEM:
+ *              Out of memory.
+ *      -EPERM:
+ *              Invalid permission (for instance asking for write and range
+ *              is read only).
+ *      -EAGAIN:
+ *              If you need to retry and mmap_sem was drop. This can only
+ *              happens if block argument is false.
+ *      -EBUSY:
+ *              If the the range is being invalidated and you should wait for
+ *              invalidation to finish.
+ *      -EFAULT:
+ *              Invalid (ie either no valid vma or it is illegal to access that
+ *              range), number of valid pages in range->pfns[] (from range start
+ *              address).
+ *
+ * This is similar to a regular CPU page fault except that it will not trigger
+ * any memory migration if the memory being faulted is not accessible by CPUs
+ * and caller does not ask for migration.
+ *
+ * On error, for one virtual address in the range, the function will mark the
+ * corresponding HMM pfn entry with an error flag.
+ */
+long hmm_range_fault(struct hmm_range *range, bool block)
+{
+	return _hmm_range_fault(range, block, NULL, NULL);
+}
 EXPORT_SYMBOL(hmm_range_fault);
 
 /*
@@ -1197,7 +1243,7 @@ long hmm_range_dma_map(struct hmm_range *range,
 	long ret;
 
 again:
-	ret = hmm_range_fault(range, block);
+	ret = _hmm_range_fault(range, block, device, daddrs);
 	if (ret <= 0)
 		return ret ? ret : -EBUSY;
 
@@ -1209,6 +1255,11 @@ long hmm_range_dma_map(struct hmm_range *range,
 		enum dma_data_direction dir = DMA_FROM_DEVICE;
 		struct page *page;
 
+		if (range->pfns[i] == range->values[HMM_PFN_P2P]) {
+			mapped++;
+			continue;
+		}
+
 		/*
 		 * FIXME need to update DMA API to provide invalid DMA address
 		 * value instead of a function to test dma address value. This
@@ -1274,6 +1325,11 @@ long hmm_range_dma_map(struct hmm_range *range,
 		enum dma_data_direction dir = DMA_FROM_DEVICE;
 		struct page *page;
 
+		if (range->pfns[i] == range->values[HMM_PFN_P2P]) {
+			mapped--;
+			continue;
+		}
+
 		page = hmm_pfn_to_page(range, range->pfns[i]);
 		if (page == NULL)
 			continue;
@@ -1305,6 +1361,30 @@ long hmm_range_dma_map(struct hmm_range *range,
 }
 EXPORT_SYMBOL(hmm_range_dma_map);
 
+static unsigned long hmm_vma_p2p_unmap(struct hmm_range *range,
+				       struct vm_area_struct *vma,
+				       unsigned long start,
+				       struct device *device,
+				       dma_addr_t *pas)
+{
+	unsigned long end;
+
+	if (!vma) {
+		BUG();
+		return 1;
+	}
+
+	start &= PAGE_MASK;
+	if (start < vma->vm_start || start >= vma->vm_end) {
+		BUG();
+		return 1;
+	}
+
+	end = min(range->end, vma->vm_end);
+	vma->vm_ops->p2p_unmap(vma, device, start, end, pas);
+	return (end - start) >> PAGE_SHIFT;
+}
+
 /*
  * hmm_range_dma_unmap() - unmap range of that was map with hmm_range_dma_map()
  * @range: range being unmapped
@@ -1342,6 +1422,14 @@ long hmm_range_dma_unmap(struct hmm_range *range,
 		enum dma_data_direction dir = DMA_FROM_DEVICE;
 		struct page *page;
 
+		if (range->pfns[i] == range->values[HMM_PFN_P2P]) {
+			BUG_ON(!vma);
+			cpages += hmm_vma_p2p_unmap(range, vma, addr,
+						    device, &daddrs[i]);
+			i += cpages - 1;
+			continue;
+		}
+
 		page = hmm_pfn_to_page(range, range->pfns[i]);
 		if (page == NULL)
 			continue;
-- 
2.17.2


      parent reply	other threads:[~2019-01-29 17:47 UTC|newest]

Thread overview: 95+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2019-01-29 17:47 [RFC PATCH 0/5] Device peer to peer (p2p) through vma jglisse
2019-01-29 17:47 ` [RFC PATCH 1/5] pci/p2p: add a function to test peer to peer capability jglisse
2019-01-29 18:24   ` Logan Gunthorpe
2019-01-29 19:44     ` Greg Kroah-Hartman
2019-01-29 19:53       ` Jerome Glisse
2019-01-29 20:44       ` Logan Gunthorpe
2019-01-29 21:00         ` Jerome Glisse
2019-01-29 19:56   ` Alex Deucher
2019-01-29 20:00     ` Jerome Glisse
2019-01-29 20:24     ` Logan Gunthorpe
2019-01-29 21:28       ` Alex Deucher
2019-01-30 10:25       ` Christian König
2019-01-29 17:47 ` [RFC PATCH 2/5] drivers/base: " jglisse
2019-01-29 18:26   ` Logan Gunthorpe
2019-01-29 19:54     ` Jerome Glisse
2019-01-29 19:46   ` Greg Kroah-Hartman
2019-01-29 19:56     ` Jerome Glisse
2019-01-29 17:47 ` [RFC PATCH 3/5] mm/vma: add support for peer to peer to device vma jglisse
2019-01-29 18:36   ` Logan Gunthorpe
2019-01-29 19:11     ` Jerome Glisse
2019-01-29 19:24       ` Logan Gunthorpe
2019-01-29 19:44         ` Jerome Glisse
2019-01-29 20:43           ` Logan Gunthorpe
2019-01-30  7:52             ` Christoph Hellwig
2019-01-29 19:32       ` Jason Gunthorpe
2019-01-29 19:50         ` Jerome Glisse
2019-01-29 20:24           ` Jason Gunthorpe
2019-01-29 20:44             ` Jerome Glisse
2019-01-29 23:02               ` Jason Gunthorpe
2019-01-30  0:08                 ` Jerome Glisse
2019-01-30  4:30                   ` Jason Gunthorpe
2019-01-30 15:43                     ` Jerome Glisse
2019-01-29 20:39         ` Logan Gunthorpe
2019-01-29 20:57           ` Jerome Glisse
2019-01-29 21:30             ` Logan Gunthorpe
2019-01-29 21:50               ` Jerome Glisse
2019-01-29 22:58                 ` Logan Gunthorpe
2019-01-29 23:47                   ` Jerome Glisse
2019-01-30  1:17                     ` Logan Gunthorpe
2019-01-30  2:48                       ` Jerome Glisse
2019-01-30  4:18                       ` Jason Gunthorpe
2019-01-30  8:00                         ` Christoph Hellwig
2019-01-30 15:49                           ` Jerome Glisse
2019-01-30 19:06                           ` Jason Gunthorpe
2019-01-30 19:45                             ` Logan Gunthorpe
2019-01-30 19:59                               ` Jason Gunthorpe
2019-01-30 21:01                                 ` Logan Gunthorpe
2019-01-30 21:50                                   ` Jason Gunthorpe
2019-01-30 22:52                                     ` Logan Gunthorpe
2019-01-30 23:30                                       ` Jason Gunthorpe
2019-01-31  8:13                                       ` Christoph Hellwig
2019-01-31 15:37                                         ` Jerome Glisse
2019-01-31 19:02                                         ` Jason Gunthorpe
2019-01-31 19:19                                           ` Logan Gunthorpe
2019-01-31 19:54                                             ` Jason Gunthorpe
2019-01-31 19:35                                           ` Jerome Glisse
2019-01-31 19:44                                             ` Logan Gunthorpe
2019-01-31 19:58                                             ` Jason Gunthorpe
2019-01-30 17:17                         ` Logan Gunthorpe
2019-01-30 18:56                           ` Jason Gunthorpe
2019-01-30 19:22                             ` Jerome Glisse
2019-01-30 19:38                               ` Jason Gunthorpe
2019-01-30 20:00                                 ` Logan Gunthorpe
2019-01-30 20:11                                   ` Jason Gunthorpe
2019-01-30 20:43                                     ` Jerome Glisse
2019-01-30 20:50                                       ` Jason Gunthorpe
2019-01-30 21:45                                         ` Jerome Glisse
2019-01-30 21:56                                           ` Jason Gunthorpe
2019-01-30 22:30                                             ` Jerome Glisse
2019-01-30 22:33                                               ` Jason Gunthorpe
2019-01-30 22:47                                                 ` Jerome Glisse
2019-01-30 22:51                                                   ` Jason Gunthorpe
2019-01-30 22:58                                                     ` Jerome Glisse
2019-01-30 19:52                               ` Logan Gunthorpe
2019-01-30 20:35                                 ` Jerome Glisse
2019-01-29 20:58           ` Jason Gunthorpe
2019-01-30  8:02             ` Christoph Hellwig
2019-01-30 10:33               ` Koenig, Christian
2019-01-30 15:55                 ` Jerome Glisse
2019-01-30 17:26                   ` Christoph Hellwig
2019-01-30 17:32                     ` Logan Gunthorpe
2019-01-30 17:39                     ` Jason Gunthorpe
2019-01-30 18:05                     ` Jerome Glisse
2019-01-30 17:44               ` Jason Gunthorpe
2019-01-30 18:13                 ` Logan Gunthorpe
2019-01-30 18:50                   ` Jerome Glisse
2019-01-31  8:02                     ` Christoph Hellwig
2019-01-31 15:03                       ` Jerome Glisse
2019-01-30 19:19                   ` Jason Gunthorpe
2019-01-30 19:48                     ` Logan Gunthorpe
2019-01-30 20:44                       ` Jason Gunthorpe
2019-01-31  8:05                         ` Christoph Hellwig
2019-01-31 15:11                           ` Jerome Glisse
2019-01-29 17:47 ` [RFC PATCH 4/5] mm/hmm: add support for peer to peer to HMM device memory jglisse
2019-01-29 17:47 ` jglisse [this message]

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=20190129174728.6430-6-jglisse@redhat.com \
    --to=jglisse@redhat.com \
    --cc=Felix.Kuehling@amd.com \
    --cc=bhelgaas@google.com \
    --cc=christian.koenig@amd.com \
    --cc=dri-devel@lists.freedesktop.org \
    --cc=gregkh@linuxfoundation.org \
    --cc=hch@lst.de \
    --cc=iommu@lists.linux-foundation.org \
    --cc=jgg@mellanox.com \
    --cc=jroedel@suse.de \
    --cc=linux-kernel@vger.kernel.org \
    --cc=linux-mm@kvack.org \
    --cc=linux-pci@vger.kernel.org \
    --cc=logang@deltatee.com \
    --cc=m.szyprowski@samsung.com \
    --cc=rafael@kernel.org \
    --cc=robin.murphy@arm.com \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).