All of lore.kernel.org
 help / color / mirror / Atom feed
From: "Prabhakaran, Krishna" <krishna.prabhakaran@intel.com>
To: intel-gfx@lists.freedesktop.org
Cc: dri-devel@lists.freedesktop.org,
	"Matthew Auld" <matthew.auld@intel.com>,
	"Thomas Hellström" <thomas.hellstrom@linux.intel.com>,
	"Jani Nikula" <jani.nikula@linux.intel.com>,
	"Joonas Lahtinen" <joonas.lahtinen@linux.intel.com>,
	"Rodrigo Vivi" <rodrigo.vivi@intel.com>,
	"Tvrtko Ursulin" <tursulin@ursulin.net>,
	"Krishna Prabhakaran" <krishna.prabhakaran@intel.com>
Subject: [PATCH v4] drm/i915/dmabuf: avoid global wbinvd on dma-buf import
Date: Wed,  2 Sep 2026 12:31:47 -0700	[thread overview]
Message-ID: <20260902193147.3835028-1-krishna.prabhakaran@intel.com> (raw)
In-Reply-To: <20260820205031.344338-1-krishna.prabhakaran@intel.com>

From: Krishna Prabhakaran <krishna.prabhakaran@intel.com>

When i915 needs to make an imported dma-buf coherent for GPU access on
non-LLC platforms, or for objects that bypass LLC, it currently calls
wbinvd_on_all_cpus(). get_pages() runs whenever an imported buffer is
pinned, so this triggers a whole-cache write-back and invalidate,
broadcast by IPI to every CPU, on every execbuf submission involving an
imported dma-buf. That stalls the entire machine for milliseconds and
starves latency-sensitive work on unrelated cores (e.g. USB isochronous
audio serviced on the VMM's main thread).

Flush only the pages that actually need it instead:

 - If we imported one of our own dma-bufs, the backing object is
   normally struct-page backed once migrated to SMEM, so flush it
   directly with drm_clflush_sg(), exactly as we flush our other
   objects. This also avoids re-entering the exporter through
   dma_buf_vmap(), which would recurse into i915_gem_object_pin_map()
   on the source object we already hold locked (and fails the
   igt_dmabuf_import_same_driver selftest with -EBUSY). SMEM does not
   guarantee the struct-page flag though: phys objects clear it and it
   is dropped transiently during TTM moves, and drm_clflush_sg() walks
   the sgt with sg_page(), so guard the direct flush with
   i915_gem_object_has_struct_page() and fall back to wbinvd when it is
   not set.

 - For a foreign dma-buf the sg_table is not guaranteed to be backed by
   struct pages, and the importer has no way to tell, so drm_clflush_sg()
   cannot be used. vmap the buffer and flush that virtual range with
   drm_clflush_virt_range() instead: x86 uses PIPT caches, so flushing
   one virtual alias evicts the cache lines for every alias of the same
   physical pages. The dma_resv lock required by dma_buf_vmap() is
   already held here via the imported object.

Fall back to wbinvd only when the buffer cannot be vmapped or is backed
by I/O memory, where there is no CPU-side range to clflush.

Fixes: a035154da45d ("drm/i915/dmabuf: add paranoid flush-on-acquire")
Signed-off-by: Krishna Prabhakaran <krishna.prabhakaran@intel.com>
---
v4: Guard the own-dma-buf direct drm_clflush_sg() with
    i915_gem_object_has_struct_page() and fall back to wbinvd when the
    SMEM object is not struct-page backed (phys objects, transient TTM
    moves); sg_page() would otherwise walk bogus pages. (review feedback)
v3: Drop the wbinvd fallback inside the own-dma-buf branch; the exporter is
    migrated to SMEM on attach, so flushing device memory made no sense.
    (Matthew Auld)
v2: Special-case our own dma-bufs with drm_clflush_sg() instead of
    dma_buf_vmap(), which recursed into i915_gem_object_pin_map() on the
    already-locked source object and failed igt_dmabuf_import_same_driver
    with -EBUSY; foreign dma-bufs use vmap + drm_clflush_virt_range().
v1: https://patchwork.freedesktop.org/series/171760/
 drivers/gpu/drm/i915/gem/i915_gem_dmabuf.c | 62 +++++++++++++++++++---
 1 file changed, 54 insertions(+), 8 deletions(-)

diff --git a/drivers/gpu/drm/i915/gem/i915_gem_dmabuf.c b/drivers/gpu/drm/i915/gem/i915_gem_dmabuf.c
index b43d34c7d641..d1695171019c 100644
--- a/drivers/gpu/drm/i915/gem/i915_gem_dmabuf.c
+++ b/drivers/gpu/drm/i915/gem/i915_gem_dmabuf.c
@@ -10,6 +10,8 @@
 
 #include <asm/smp.h>
 
+#include <drm/drm_cache.h>
+
 #include "gem/i915_gem_dmabuf.h"
 #include "i915_drv.h"
 #include "i915_gem_object.h"
@@ -249,16 +251,60 @@ static int i915_gem_object_get_pages_dmabuf(struct drm_i915_gem_object *obj)
 	 * DG1 is special here since it still snoops transactions even with
 	 * CACHE_NONE. This is not the case with other HAS_SNOOP platforms. We
 	 * might need to revisit this as we add new discrete platforms.
-	 *
-	 * XXX: Consider doing a vmap flush or something, where possible.
-	 * Currently we just do a heavy handed wbinvd_on_all_cpus() here since
-	 * the underlying sg_table might not even point to struct pages, so we
-	 * can't just call drm_clflush_sg or similar, like we do elsewhere in
-	 * the driver.
 	 */
 	if (i915_gem_object_can_bypass_llc(obj) ||
-	    (!HAS_LLC(i915) && !IS_DG1(i915)))
-		wbinvd_on_all_cpus();
+	    (!HAS_LLC(i915) && !IS_DG1(i915))) {
+		struct dma_buf *dma_buf = obj->base.import_attach->dmabuf;
+
+		if (dma_buf->ops == &i915_dmabuf_ops) {
+			struct drm_i915_gem_object *dma_obj =
+				dma_buf_to_obj(dma_buf);
+
+			/*
+			 * We imported one of our own dma-bufs. The exporter is
+			 * migrated to SMEM on attach, so it is normally struct-page
+			 * backed and we can flush it directly, the same way we
+			 * flush our other objects. This also avoids re-entering
+			 * the exporter through dma_buf_vmap(), which would
+			 * recurse into i915_gem_object_pin_map() on the source
+			 * object we already hold locked.
+			 *
+			 * SMEM does not guarantee the STRUCT_PAGE flag though: phys
+			 * objects clear it and it is dropped transiently during TTM
+			 * moves. drm_clflush_sg() walks the sgt with sg_page(), so
+			 * without struct pages those pointers are bogus; fall back to
+			 * wbinvd in that case (not the vmap path, which would recurse
+			 * on the already-locked source object).
+			 */
+			if (i915_gem_object_has_struct_page(dma_obj))
+				drm_clflush_sg(dma_obj->mm.pages);
+			else
+				wbinvd_on_all_cpus();
+		} else {
+			struct iosys_map map;
+
+			/*
+			 * A foreign sg_table is not guaranteed to be backed by
+			 * struct pages, so we cannot use drm_clflush_sg(). vmap
+			 * the buffer and flush the virtual range instead; x86
+			 * uses PIPT caches, so flushing one alias evicts the
+			 * lines for every alias of the same physical pages.
+			 *
+			 * We already hold the dma_resv lock via the imported
+			 * obj, so use the locked dma_buf_vmap() variant.
+			 */
+			if (!dma_buf_vmap(dma_buf, &map)) {
+				if (!map.is_iomem)
+					drm_clflush_virt_range(map.vaddr,
+							       obj->base.size);
+				else
+					wbinvd_on_all_cpus();
+				dma_buf_vunmap(dma_buf, &map);
+			} else {
+				wbinvd_on_all_cpus();
+			}
+		}
+	}
 
 	__i915_gem_object_set_pages(obj, sgt);
 
-- 
2.43.0


  parent reply	other threads:[~2026-09-02 19:32 UTC|newest]

Thread overview: 18+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2026-08-16  1:45 [PATCH v2] drm/i915/dmabuf: avoid global wbinvd on dma-buf import Prabhakaran, Krishna
2026-08-16  2:24 ` ✓ i915.CI.BAT: success for " Patchwork
2026-08-17 20:25 ` ✗ i915.CI.Full: failure " Patchwork
2026-08-20  9:23 ` [PATCH v2] " Matthew Auld
2026-08-20 10:39   ` Thomas Hellström
2026-08-20 20:20     ` Prabhakaran, Krishna
2026-08-20 18:15   ` Prabhakaran, Krishna
2026-08-20 19:09   ` Prabhakaran, Krishna
2026-08-20 20:50 ` [PATCH v3] " Prabhakaran, Krishna
2026-08-21  9:09   ` Matthew Auld
2026-09-02  5:37     ` Prabhakaran, Krishna
2026-09-02 19:31   ` Prabhakaran, Krishna [this message]
2026-09-15  1:28     ` [PATCH v4] " Prabhakaran, Krishna
2026-09-15  8:49     ` Matthew Auld
2026-10-05 17:33       ` Prabhakaran, Krishna
2026-08-20 22:07 ` ✗ i915.CI.BAT: failure for drm/i915/dmabuf: avoid global wbinvd on dma-buf import (rev3) Patchwork
2026-09-02 21:36 ` ✓ i915.CI.BAT: success for drm/i915/dmabuf: avoid global wbinvd on dma-buf import (rev4) Patchwork
2026-09-03 16:01 ` ✗ i915.CI.Full: failure " Patchwork

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=20260902193147.3835028-1-krishna.prabhakaran@intel.com \
    --to=krishna.prabhakaran@intel.com \
    --cc=dri-devel@lists.freedesktop.org \
    --cc=intel-gfx@lists.freedesktop.org \
    --cc=jani.nikula@linux.intel.com \
    --cc=joonas.lahtinen@linux.intel.com \
    --cc=matthew.auld@intel.com \
    --cc=rodrigo.vivi@intel.com \
    --cc=thomas.hellstrom@linux.intel.com \
    --cc=tursulin@ursulin.net \
    /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 an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.