From: Matthew Auld <matthew.auld@intel.com>
To: "Christian König" <christian.koenig@amd.com>,
"Thomas Hellström" <thomas.hellstrom@linux.intel.com>,
intel-xe@lists.freedesktop.org
Cc: "Matthew Brost" <matthew.brost@intel.com>,
stable@vger.kernel.org,
"Christian König" <ckoenig.leichtzumerken@gmail.com>
Subject: Re: [PATCH v2 3/3] drm/xe: skip p2p for suspected display buffers
Date: Fri, 9 Oct 2026 10:16:34 +0100 [thread overview]
Message-ID: <31f7eb68-6dfa-4ea7-93a4-d4897fbe6a74@intel.com> (raw)
In-Reply-To: <992d57f0-7327-4c36-adf7-6dd72137fe73@intel.com>
On 08/10/2026 12:17, Matthew Auld wrote:
> On 08/10/2026 10:55, Christian König wrote:
>> On 10/8/26 11:46, Matthew Auld wrote:
>>> On 07/10/2026 19:11, Thomas Hellström wrote:
>>>> On Wed, 2026-10-07 at 16:36 +0100, Matthew Auld wrote:
>>>>> If p2p is allowed on the CPU (like on AMD), we currently permit p2p
>>>>> for
>>>>> all exported VRAM buffers. However, in some multi-GPU setups, like
>>>>> with
>>>>> prime rendering on a dgpu and scanout/compositor using the igpu, it
>>>>> looks like the exported dma-buf window buffer can in some cases end
>>>>> up
>>>>> using p2p.
>>>>>
>>>>> However, user is reporting a kernel regression where performance here
>>>>> massively tanks across many games/workloads, where it looks like on
>>>>> each
>>>>> frame, the igpu is reading/sampling from VRAM over pcie for the
>>>>> window
>>>>> buffer, since it uses p2p. p2p is currently more intended for dgpu <-
>>>>>>
>>>>> dgpu, and not so much display buffers with igpu <-> dgpu, at least
>>>>> for
>>>>> now.
>>>>>
>>>>> We don't currently have any hints to say "please use p2p for this
>>>>> buffer, or please don't", however we can use some heuristics to try
>>>>> to
>>>>> determine if this is likely a display buffer being exported to an
>>>>> igpu,
>>>>> which probably never intended for p2p:
>>>>>
>>>>> 1. FLAG_SCANOUT being set on the buffer. Window buffers usually get
>>>>> tagged with this, but not always.
>>>>>
>>>>> 2. Importer being a PCI device with display, which is not xe
>>>>> driver.
>>>>>
>>>>> We also rely on the existing p2p Intel CPU whitelist to stop this
>>>>> happening on xe igpu. Currently p2p is only enabled for server CPUs,
>>>>> on
>>>>> Intel. We also limit the above to dual placement buffers.
>>>>>
>>>>> The original regression was bisected to commit 609fc8766d68 ("dma-
>>>>> buf:
>>>>> Always build with DMABUF_MOVE_NOTIFY"), however the behaviour was
>>>>> already present when enabling that knob, so this goes back even
>>>>> further.
>>>>>
>>>>> User has confirmed that along with the sticky dma-buf TT placement
>>>>> fix,
>>>>> to prevent ping-ponging, the performance is back to normal.
>>>>>
>>>>
>>>> Actually, I think this needs to be fixed on the importer side. Until we
>>>> have some some user-space hints, I don't think the exporter should
>>>> second-guess. Most sane solution IMO is if igfx importers could just
>>>> not advertise pcie p2p support?
>>>
>>> Yeah, not sure tbh. I'm not a huge fan of this patch either. But you
>>> could argue that the SCANOUT flag is already a good implicit hint/
>>> signal on the exporter side, but unfortunately there were some games
>>> where this did not reliably work. The other implicit hint/signal is
>>> perhaps the dual placement angle. For example, in compute-runtime, it
>>> might be that they use VRAM-only if they want p2p? AFAICT mesa for us
>>> always uses a dual placement or just system memory for these types of
>>> buffers.
>>>
>>> Christian, do you have any thoughts here? We have a kernel perf
>>> regression after DMABUF_MOVE_NOTIFY was made the default after
>>> updating to a new kernel. The gist is that this then turned on the
>>> p2p paths, with a multi-GPU setup with an AMD igpu/APU and Xe dgpu
>>> doing prime rendering. From the user bug report it sounds like the
>>> dgpu linear window buffer exported to the compositor (igpu) is dual
>>> placement VRAM + TT, and so this now attempts to keep that memory in
>>> VRAM instead of moving it. Compositor then uses p2p to access it. It
>>> works but performance falls off a massive cliff here.
>>>
>>> Perhaps Intel Mesa side should use tt-only for this type buffer (?),
>>> but since this is a kernel regression I was hoping we could fix this
>>> on the kernel side.
>>>
>>> Some questions:
>>>
>>> 1. Do you know what is the general story with p2p between igpu and
>>> dgpu? Is this a legit thing? For igpus/APUs, advertising p2p can't be
>>> dropped? It clearly seems to work though.
>>>
>>> 2. If this is legit, do you guys then also prevent p2p with display
>>> buffers? Are you just doing that at the Mesa level, or is there some
>>> magic in the kernel also?
>>
>> If I understand that correctly that the igpu is the importer and the
>> dgpu is the exporter then yeah Thomas is right that definately needs
>> to be fixed on the importer side.
>
> Ideas on how do that? Could we do something like allow_peer2peer = false
> in amdgpu_gem_prime_import() if this is an APU device, or further check
> if the exporter side is not amdgpu, like APU + Xe?
For example:
https://gitlab.freedesktop.org/mwa/kernel/-/commit/7ec86c68b42655b4bb85ee90af434a617e7bec8c
Is that something you would accept?
>
>>
>> At least for AMD APUs we clearly support P2P both as exporter and
>> importer, but what isn't supported is to scan out over P2P. We
>> explicitely reject that inside DC/DAL.
>>
>> And I'm pretty sure that you should do that as well. I'm actually
>> really suprised that this works technically and doesn't cause
>> corruption or anything.
>
> AFAICT on Intel iGPUs it will currently always end up with peer2peer =
> false on attach. Not 100% sure if direct scanout was happening on the
> p2p buffer itself, for the user report.
>
>>
>> Regards,
>> Christian.
>>
>>>
>>>>
>>>> Thanks,
>>>> Thomas
>>>>
>>>>> Assisted-by: LLM
>>>>> Closes:
>>>>> https://gitlab.freedesktop.org/drm/xe/kernel/-/work_items/9415
>>>>> Signed-off-by: Matthew Auld <matthew.auld@intel.com>
>>>>> Fixes: dd08ebf6c352 ("drm/xe: Introduce a new DRM driver for Intel
>>>>> GPUs")
>>>>> Cc: Thomas Hellström <thomas.hellstrom@linux.intel.com>
>>>>> Cc: Matthew Brost <matthew.brost@intel.com>
>>>>> Cc: <stable@vger.kernel.org> # v6.12
>>>>> ---
>>>>> drivers/gpu/drm/xe/xe_bo.c | 3 +-
>>>>> drivers/gpu/drm/xe/xe_bo.h | 1 +
>>>>> drivers/gpu/drm/xe/xe_dma_buf.c | 63 ++++++++++++++++++++++++
>>>>> +------
>>>>> --
>>>>> 3 files changed, 51 insertions(+), 16 deletions(-)
>>>>>
>>>>> diff --git a/drivers/gpu/drm/xe/xe_bo.c b/drivers/gpu/drm/xe/xe_bo.c
>>>>> index 5065a7bac39c..e63437a261cb 100644
>>>>> --- a/drivers/gpu/drm/xe/xe_bo.c
>>>>> +++ b/drivers/gpu/drm/xe/xe_bo.c
>>>>> @@ -3658,7 +3658,7 @@ int xe_gem_create_ioctl(struct drm_device *dev,
>>>>> void *data,
>>>>> * Display scanout is always non-coherent with the CPU
>>>>> cache.
>>>>> */
>>>>> if (args->flags & DRM_XE_GEM_CREATE_FLAG_SCANOUT)
>>>>> - bo_flags |= XE_BO_FLAG_FORCE_WC;
>>>>> + bo_flags |= XE_BO_FLAG_FORCE_WC |
>>>>> XE_BO_FLAG_SCANOUT;
>>>>> if (args->flags & DRM_XE_GEM_CREATE_FLAG_NO_COMPRESSION) {
>>>>> if (XE_IOCTL_DBG(xe, GRAPHICS_VER(xe) < 20))
>>>>> @@ -4228,6 +4228,7 @@ int xe_bo_dumb_create(struct drm_file
>>>>> *file_priv,
>>>>> DRM_XE_GEM_CPU_CACHING_WC,
>>>>> XE_BO_FLAG_VRAM_IF_DGFX(xe_device_get_root_tile(xe)) |
>>>>> XE_BO_FLAG_FORCE_WC |
>>>>> + XE_BO_FLAG_SCANOUT |
>>>>> XE_BO_FLAG_NEEDS_CPU_ACCESS, NULL);
>>>>> if (IS_ERR(bo))
>>>>> return PTR_ERR(bo);
>>>>> diff --git a/drivers/gpu/drm/xe/xe_bo.h b/drivers/gpu/drm/xe/xe_bo.h
>>>>> index 1ddf3b6d4a9e..6965c2655731 100644
>>>>> --- a/drivers/gpu/drm/xe/xe_bo.h
>>>>> +++ b/drivers/gpu/drm/xe/xe_bo.h
>>>>> @@ -56,6 +56,7 @@
>>>>> #define XE_BO_FLAG_FORCE_USER_VRAM BIT(25)
>>>>> #define XE_BO_FLAG_NO_COMPRESSION BIT(26)
>>>>> #define XE_BO_FLAG_NEEDS_1G BIT(27)
>>>>> +#define XE_BO_FLAG_SCANOUT BIT(28)
>>>>> /* this one is trigger internally only */
>>>>> #define XE_BO_FLAG_INTERNAL_TEST BIT(30)
>>>>> diff --git a/drivers/gpu/drm/xe/xe_dma_buf.c
>>>>> b/drivers/gpu/drm/xe/xe_dma_buf.c
>>>>> index b973579a69b8..0a347f09cee4 100644
>>>>> --- a/drivers/gpu/drm/xe/xe_dma_buf.c
>>>>> +++ b/drivers/gpu/drm/xe/xe_dma_buf.c
>>>>> @@ -36,10 +36,40 @@ static void xe_ddebug_flip_bool(const struct
>>>>> _ddebug *desc, bool *flag)
>>>>> #define xe_dma_buf_p2p_debug_flip(flag) do { } while (0)
>>>>> #endif
>>>>> +static void xe_dma_buf_move_notify(struct dma_buf_attachment
>>>>> *attach)
>>>>> +{
>>>>> + struct drm_gem_object *obj = attach->importer_priv;
>>>>> + struct xe_bo *bo = gem_to_xe_bo(obj);
>>>>> + struct drm_exec *exec = XE_VALIDATION_UNSUPPORTED;
>>>>> +
>>>>> + XE_WARN_ON(xe_bo_evict(bo, exec));
>>>>> +}
>>>>> +
>>>>> +static const struct dma_buf_attach_ops xe_dma_buf_attach_ops = {
>>>>> + .allow_peer2peer = true,
>>>>> + .invalidate_mappings = xe_dma_buf_move_notify
>>>>> +};
>>>>> +
>>>>> +static struct pci_dev *xe_find_parent_pci_dev(struct device *dev)
>>>>> +{
>>>>> + while (dev) {
>>>>> + if (dev_is_pci(dev))
>>>>> + return to_pci_dev(dev);
>>>>> + dev = dev->parent;
>>>>> + }
>>>>> + return NULL;
>>>>> +}
>>>>> +
>>>>> +static bool xe_dma_buf_attach_is_xe_device(struct dma_buf_attachment
>>>>> *attach)
>>>>> +{
>>>>> + return attach->importer_ops == &xe_dma_buf_attach_ops;
>>>>> +}
>>>>> +
>>>>> static int xe_dma_buf_attach(struct dma_buf *dmabuf,
>>>>> struct dma_buf_attachment *attach)
>>>>> {
>>>>> struct drm_gem_object *obj = attach->dmabuf->priv;
>>>>> + struct xe_bo *bo = gem_to_xe_bo(obj);
>>>>> bool verbose_p2p_dist = drm_debug_enabled(DRM_UT_DRIVER);
>>>>> xe_dma_buf_p2p_debug_flip(&verbose_p2p_dist);
>>>>> @@ -48,7 +78,24 @@ static int xe_dma_buf_attach(struct dma_buf
>>>>> *dmabuf,
>>>>> pci_p2pdma_distance(to_pci_dev(obj->dev->dev), attach-
>>>>>> dev, verbose_p2p_dist) < 0)
>>>>> attach->peer2peer = false;
>>>>> - if (!attach->peer2peer &&
>>>>> !xe_bo_can_migrate(gem_to_xe_bo(obj), XE_PL_TT))
>>>>> + if (attach->peer2peer && xe_bo_can_migrate(bo, XE_PL_TT)) {
>>>>> + struct pci_dev *client =
>>>>> xe_find_parent_pci_dev(attach->dev);
>>>>> +
>>>>> + /*
>>>>> + * There are perf issues with using p2p with display
>>>>> buffers,
>>>>> + * like with igpu (compositor) <-> dgpu (exported
>>>>> p2p window
>>>>> + * buffer). Probably we need some actual userspace
>>>>> hints. We
>>>>> + * shouldn't really assume anything. Also, note that
>>>>> some of
>>>>> + * these buffers are not always tagged with SCANOUT.
>>>>> + */
>>>>> + if (bo->flags & XE_BO_FLAG_SCANOUT)
>>>>> + attach->peer2peer = false;
>>>>> + else if (client && pci_is_display(client) &&
>>>>> + !xe_dma_buf_attach_is_xe_device(attach))
>>>>> + attach->peer2peer = false;
>>>>> + }
>>>>> +
>>>>> + if (!attach->peer2peer && !xe_bo_can_migrate(bo, XE_PL_TT))
>>>>> return -EOPNOTSUPP;
>>>>> xe_pm_runtime_get(to_xe_device(obj->dev));
>>>>> @@ -349,20 +396,6 @@ xe_dma_buf_create_obj(struct drm_device *dev,
>>>>> struct dma_buf *dma_buf)
>>>>> return ret ? ERR_PTR(ret) : &bo->ttm.base;
>>>>> }
>>>>> -static void xe_dma_buf_move_notify(struct dma_buf_attachment
>>>>> *attach)
>>>>> -{
>>>>> - struct drm_gem_object *obj = attach->importer_priv;
>>>>> - struct xe_bo *bo = gem_to_xe_bo(obj);
>>>>> - struct drm_exec *exec = XE_VALIDATION_UNSUPPORTED;
>>>>> -
>>>>> - XE_WARN_ON(xe_bo_evict(bo, exec));
>>>>> -}
>>>>> -
>>>>> -static const struct dma_buf_attach_ops xe_dma_buf_attach_ops = {
>>>>> - .allow_peer2peer = true,
>>>>> - .invalidate_mappings = xe_dma_buf_move_notify
>>>>> -};
>>>>> -
>>>>> #if IS_ENABLED(CONFIG_DRM_XE_KUNIT_TEST)
>>>>> struct dma_buf_test_params {
>>>
>>
>
next prev parent reply other threads:[~2026-10-09 9:16 UTC|newest]
Thread overview: 30+ messages / expand[flat|nested] mbox.gz Atom feed top
2026-10-07 15:36 [PATCH v2 0/3] sticky TT Matthew Auld
2026-10-07 15:36 ` [PATCH v2 1/3] drm/xe/dma-buf: keep non-p2p imported buffers in system memory Matthew Auld
2026-10-07 15:36 ` [PATCH v2 2/3] drm/xe/vm: make PREFETCH to TT sticky Matthew Auld
2026-10-07 15:36 ` [PATCH v2 3/3] drm/xe: skip p2p for suspected display buffers Matthew Auld
2026-10-07 18:11 ` Thomas Hellström
2026-10-08 9:46 ` Matthew Auld
2026-10-08 9:55 ` Christian König
2026-10-08 11:17 ` Matthew Auld
2026-10-09 9:16 ` Matthew Auld [this message]
2026-10-09 9:26 ` Christian König
2026-10-09 10:29 ` Matthew Auld
2026-10-09 11:38 ` Christian König
2026-10-09 13:02 ` Matthew Auld
2026-10-13 8:51 ` Matthew Auld
2026-10-13 9:10 ` Christian König
2026-10-13 9:18 ` Thomas Hellström
2026-10-13 9:55 ` Christian König
2026-10-13 10:16 ` Thomas Hellström
2026-10-13 11:45 ` Christian König
2026-10-13 12:36 ` Matthew Auld
2026-10-13 9:40 ` Matthew Auld
2026-10-13 11:50 ` Christian König
2026-10-13 13:15 ` Matthew Auld
2026-10-09 13:06 ` Thomas Hellström
2026-10-08 14:40 ` Simon Richter
2026-10-08 16:22 ` Matthew Auld
2026-10-07 15:42 ` ✗ CI.checkpatch: warning for sticky TT (rev2) Patchwork
2026-10-07 15:45 ` ✓ CI.KUnit: success " Patchwork
2026-10-07 16:46 ` ✓ Xe.CI.BAT: " Patchwork
2026-10-07 20:16 ` ✓ Xe.CI.FULL: " 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=31f7eb68-6dfa-4ea7-93a4-d4897fbe6a74@intel.com \
--to=matthew.auld@intel.com \
--cc=christian.koenig@amd.com \
--cc=ckoenig.leichtzumerken@gmail.com \
--cc=intel-xe@lists.freedesktop.org \
--cc=matthew.brost@intel.com \
--cc=stable@vger.kernel.org \
--cc=thomas.hellstrom@linux.intel.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