All of lore.kernel.org
 help / color / mirror / Atom feed
From: Matthew Brost <matthew.brost@intel.com>
To: Srinivasan Shanmugam <srinivasan.shanmugam@amd.com>
Cc: "Thomas Hellström" <thomas.hellstrom@linux.intel.com>,
	dri-devel@lists.freedesktop.org, intel-xe@lists.freedesktop.org,
	"Christian König" <christian.koenig@amd.com>,
	"Alex Deucher" <alexander.deucher@amd.com>,
	amd-gfx@lists.freedesktop.org,
	"Maarten Lankhorst" <maarten.lankhorst@linux.intel.com>
Subject: Re: [PATCH v6 2/4] drm: Add drm_user_fence helper
Date: Mon, 31 Aug 2026 13:36:14 -0700	[thread overview]
Message-ID: <apXlvgjIwe+lj6hb@gsse-cloud1.jf.intel.com> (raw)
In-Reply-To: <20260831134539.112690-3-srinivasan.shanmugam@amd.com>

On Mon, Aug 31, 2026 at 07:15:37PM +0530, Srinivasan Shanmugam wrote:
> Introduce a common DRM user fence helper providing the kref-managed,
> MM-borrowing dma-fence-callback-to-workqueue pattern used by drivers
> that must access userspace memory from a kthread context when a GPU
> fence signals.
> 
> XE uses this pattern (xe_sync.c) to write a fence completion value
> to a userspace VA. AMDGPU will use the same pattern to signal a
> per-queue eventfd from a user-queue EOP fence callback.
> 
> The helper provides:
>  - struct drm_user_fence: embeddable base structure
>  - struct drm_user_fence_ops: worker/destroy callbacks
>  - drm_user_fence_init(): initialize and grab the process MM
>  - drm_user_fence_get/put(): reference counting
>  - drm_user_fence_add_callback(): attach to a dma-fence
> 
> The worker callback receives a bool indicating whether the process
> MM was successfully obtained, allowing drivers to handle the
> unavailable-MM case (log, skip the userspace write, etc.) without
> duplicating the mmget/kthread_use_mm/mmput boilerplate.
> 
> Suggested-by: Christian König <christian.koenig@amd.com>
> Cc: Matthew Brost <matthew.brost@intel.com>
> Cc: Maarten Lankhorst <maarten.lankhorst@linux.intel.com>
> Cc: dri-devel@lists.freedesktop.org
> Cc: intel-xe@lists.freedesktop.org
> Cc: amd-gfx@lists.freedesktop.org
> Signed-off-by: Srinivasan Shanmugam <srinivasan.shanmugam@amd.com>
> ---
>  drivers/gpu/drm/Makefile         |  1 +
>  drivers/gpu/drm/drm_user_fence.c | 69 +++++++++++++++++++++++++
>  include/drm/drm_user_fence.h     | 86 ++++++++++++++++++++++++++++++++
>  3 files changed, 156 insertions(+)
>  create mode 100644 drivers/gpu/drm/drm_user_fence.c
>  create mode 100644 include/drm/drm_user_fence.h
> 
> diff --git a/drivers/gpu/drm/Makefile b/drivers/gpu/drm/Makefile
> index c5be8e80d0c8..ddb770738992 100644
> --- a/drivers/gpu/drm/Makefile
> +++ b/drivers/gpu/drm/Makefile
> @@ -69,6 +69,7 @@ drm-y := \
>  	drm_syncobj.o \
>  	drm_sysfs.o \
>  	drm_trace_points.o \
> +	drm_user_fence.o \
>  	drm_vblank.o \
>  	drm_vblank_work.o \
>  	drm_vma_manager.o \
> diff --git a/drivers/gpu/drm/drm_user_fence.c b/drivers/gpu/drm/drm_user_fence.c
> new file mode 100644
> index 000000000000..664178e2d74c
> --- /dev/null
> +++ b/drivers/gpu/drm/drm_user_fence.c
> @@ -0,0 +1,69 @@
> +// SPDX-License-Identifier: MIT
> +/*
> + * Copyright © 2024 The Linux Foundation
> + *
> + * DRM user fence — extends drm_work_fence with kthread_use_mm() support.
> + *
> + * Use this when a GPU fence signals and work needs to access userspace
> + * memory (copy_to_user, fault-able operations) from a kthread context.
> + * For work that does not require userspace memory access, use
> + * drm_work_fence directly.
> + */
> +
> +#include <linux/kthread.h>
> +#include <linux/sched/mm.h>
> +
> +#include <drm/drm_user_fence.h>
> +
> +static void drm_user_fence_do_work(struct drm_work_fence *wfence)
> +{
> +	struct drm_user_fence *ufence =
> +		container_of(wfence, struct drm_user_fence, base);
> +	bool mm_ok = false;
> +
> +	if (mmget_not_zero(ufence->mm)) {
> +		kthread_use_mm(ufence->mm);
> +		mm_ok = true;
> +	}
> +
> +	ufence->ops->worker(ufence, mm_ok);
> +
> +	if (mm_ok) {
> +		kthread_unuse_mm(ufence->mm);
> +		mmput_async(ufence->mm);

Xe does this incorrectly, but ufence shouldn't be looked after 'worker'.

Also mm_ok probably isn't needed either. I'd write this like:

struct mm_struct *mm = NULL;

if (mmget_not_zero(ufence->mm)) {
	mm = ufence->mm;
	kthread_use_mm(mm);
}

ufence->ops->worker(ufence, !!mm); /* Or just pass in 'mm' */

if (mm) {
	kthread_unuse_mm(mm);
	mmput_async(mm);
}

> +	}
> +}
> +
> +static void drm_user_fence_do_destroy(struct drm_work_fence *wfence)
> +{
> +	struct drm_user_fence *ufence =
> +		container_of(wfence, struct drm_user_fence, base);
> +
> +	mmdrop(ufence->mm);
> +	ufence->ops->destroy(ufence);

I'd invert this:

struct mm_struct *mm = ufence->mm;

ufence->ops->destroy(ufence);
mmdrop(mm);

> +}
> +
> +static const struct drm_work_fence_ops drm_user_fence_wf_ops = {
> +	.work    = drm_user_fence_do_work,

I wouldn't use the name 'work' here. I think writeback is more apporiate.

> +	.destroy = drm_user_fence_do_destroy,
> +};
> +
> +/**
> + * drm_user_fence_init - Initialize a user fence
> + * @ufence: user fence to initialize
> + * @wq: workqueue to run the worker on (must be ordered if sequencing matters)
> + * @ops: driver operations
> + *
> + * Must be called from process context with a valid current->mm.
> + * Grabs a reference to current->mm via mmgrab().
> + */
> +void drm_user_fence_init(struct drm_user_fence *ufence,
> +			 struct workqueue_struct *wq,
> +			 const struct drm_user_fence_ops *ops)
> +{
> +	drm_work_fence_init(&ufence->base, wq, &drm_user_fence_wf_ops);
> +	ufence->mm = current->mm;
> +	mmgrab(ufence->mm);
> +	ufence->ops = ops;
> +}
> +EXPORT_SYMBOL_GPL(drm_user_fence_init);
> diff --git a/include/drm/drm_user_fence.h b/include/drm/drm_user_fence.h
> new file mode 100644
> index 000000000000..2b2b640f510f
> --- /dev/null
> +++ b/include/drm/drm_user_fence.h
> @@ -0,0 +1,86 @@
> +/* SPDX-License-Identifier: MIT */
> +/*
> + * Copyright © 2024 The Linux Foundation
> + */
> +
> +#ifndef __DRM_USER_FENCE_H__
> +#define __DRM_USER_FENCE_H__
> +
> +#include <drm/drm_work_fence.h>
> +
> +struct drm_user_fence;
> +
> +/**
> + * struct drm_user_fence_ops - driver callbacks for a DRM user fence
> + */
> +struct drm_user_fence_ops {
> +	/**
> +	 * @worker: Called from workqueue context with the process MM active.
> +	 *
> +	 * If @mm_ok is true, kthread_use_mm() is active and userspace memory
> +	 * (copy_to_user, etc.) may be accessed safely.
> +	 * If @mm_ok is false, the process MM was already gone; the driver
> +	 * should log a warning and skip the userspace write.

I'd wouldn't dicate if caller should log a warning - rather just say if
should skip the userspace write.

> +	 *
> +	 * wake_up() or other post-signal housekeeping should also happen here.
> +	 */
> +	void (*worker)(struct drm_user_fence *ufence, bool mm_ok);
> +
> +	/**
> +	 * @destroy: Called when the last reference is dropped.
> +	 * Free the containing structure here.
> +	 */
> +	void (*destroy)(struct drm_user_fence *ufence);
> +};
> +
> +/**
> + * struct drm_user_fence - DRM user fence with MM borrowing
> + *
> + * Extends drm_work_fence with kthread_use_mm() support for drivers
> + * that need to access userspace memory when a GPU fence signals.
> + * For work that does not need userspace memory access, use
> + * drm_work_fence directly.
> + *
> + * Call drm_user_fence_init() at creation and drm_user_fence_add_callback()
> + * to arm on a dma-fence. Call drm_user_fence_cancel_sync() before teardown.
> + */
> +struct drm_user_fence {
> +	/** @base: Base work fence. Must be first. */
> +	struct drm_work_fence base;
> +	/** @mm: Process MM grabbed at init time. */
> +	struct mm_struct *mm;
> +	/** @ops: Driver operations. */
> +	const struct drm_user_fence_ops *ops;
> +};
> +
> +void drm_user_fence_init(struct drm_user_fence *ufence,
> +			 struct workqueue_struct *wq,
> +			 const struct drm_user_fence_ops *ops);
> +

Kernel doc for all the inlines.

Matt

> +static inline void drm_user_fence_get(struct drm_user_fence *ufence)
> +{
> +	drm_work_fence_get(&ufence->base);
> +}
> +
> +static inline void drm_user_fence_put(struct drm_user_fence *ufence)
> +{
> +	drm_work_fence_put(&ufence->base);
> +}
> +
> +static inline int drm_user_fence_add_callback(struct drm_user_fence *ufence,
> +					      struct dma_fence *fence)
> +{
> +	return drm_work_fence_add_callback(&ufence->base, fence);
> +}
> +
> +static inline bool drm_user_fence_cancel(struct drm_user_fence *ufence)
> +{
> +	return drm_work_fence_cancel(&ufence->base);
> +}
> +
> +static inline void drm_user_fence_cancel_sync(struct drm_user_fence *ufence)
> +{
> +	drm_work_fence_cancel_sync(&ufence->base);
> +}
> +
> +#endif /* __DRM_USER_FENCE_H__ */
> -- 
> 2.34.1
> 

  reply	other threads:[~2026-08-31 20:36 UTC|newest]

Thread overview: 38+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2026-08-27  6:21 [PATCH 0/2] drm: Add Common drm_user_fence helper and Convert XE Srinivasan Shanmugam
2026-08-27  6:21 ` [PATCH 1/2] drm: Add common drm_user_fence helper Srinivasan Shanmugam
2026-08-27  6:32   ` sashiko-bot
2026-08-27  6:21 ` [PATCH 2/2] drm/xe: Convert xe_user_fence to drm_user_fence Srinivasan Shanmugam
2026-08-27  6:37   ` sashiko-bot
2026-08-27  6:28 ` ✗ CI.checkpatch: warning for drm: Add Common drm_user_fence helper and Convert XE Patchwork
2026-08-27  6:29 ` ✗ CI.KUnit: failure " Patchwork
2026-08-31  5:41 ` [PATCH v5 0/4] drm: Add common drm_work_fence/drm_user_fence helpers and convert XE Srinivasan Shanmugam
2026-08-31 10:16   ` Thomas Hellström
2026-08-31 11:13     ` SHANMUGAM, SRINIVASAN
2026-08-31 12:22       ` Thomas Hellström
2026-08-31 12:36         ` SHANMUGAM, SRINIVASAN
2026-08-31 12:40           ` Thomas Hellström
2026-08-31  5:41 ` [PATCH v5 1/4] drm: Add drm_work_fence helper Srinivasan Shanmugam
2026-08-31  5:41 ` [PATCH v5 2/4] drm: Add drm_user_fence helper Srinivasan Shanmugam
2026-08-31  5:41 ` [PATCH v5 3/4] drm/xe: Convert xe_user_fence to drm_user_fence Srinivasan Shanmugam
2026-08-31  5:56   ` sashiko-bot
2026-08-31  5:41 ` [PATCH v5 4/4] drm: Add per-signal compare functionality " Srinivasan Shanmugam
2026-08-31  5:51   ` sashiko-bot
2026-08-31 13:45 ` [PATCH v6 0/4] drm: Add common drm_work_fence/drm_user_fence helpers and convert XE Srinivasan Shanmugam
2026-08-31 13:45 ` [PATCH v6 1/4] drm: Add drm_work_fence helper Srinivasan Shanmugam
2026-08-31 20:21   ` Matthew Brost
2026-09-01  7:39     ` SHANMUGAM, SRINIVASAN
2026-09-01 10:04       ` Matthew Brost
2026-09-02 15:20   ` [PATCH v7 " Srinivasan Shanmugam
2026-09-02 15:20     ` [PATCH v7 2/4] drm: Add drm_user_fence helper Srinivasan Shanmugam
2026-09-08  4:54       ` Matthew Brost
2026-09-02 15:20     ` [PATCH v7 3/4] drm/xe: Convert xe_user_fence to drm_user_fence Srinivasan Shanmugam
2026-09-02 15:34       ` sashiko-bot
2026-09-08  5:11       ` Matthew Brost
2026-09-02 15:20     ` [PATCH v7 4/4] drm: Add per-signal compare functionality " Srinivasan Shanmugam
2026-09-02 15:29       ` sashiko-bot
2026-09-08  4:53     ` [PATCH v7 1/4] drm: Add drm_work_fence helper Matthew Brost
2026-08-31 13:45 ` [PATCH v6 2/4] drm: Add drm_user_fence helper Srinivasan Shanmugam
2026-08-31 20:36   ` Matthew Brost [this message]
2026-08-31 13:45 ` [PATCH v6 3/4] drm/xe: Convert xe_user_fence to drm_user_fence Srinivasan Shanmugam
2026-08-31 13:45 ` [PATCH v6 4/4] drm: Add per-signal compare functionality " Srinivasan Shanmugam
2026-08-31 14:25   ` sashiko-bot

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=apXlvgjIwe+lj6hb@gsse-cloud1.jf.intel.com \
    --to=matthew.brost@intel.com \
    --cc=alexander.deucher@amd.com \
    --cc=amd-gfx@lists.freedesktop.org \
    --cc=christian.koenig@amd.com \
    --cc=dri-devel@lists.freedesktop.org \
    --cc=intel-xe@lists.freedesktop.org \
    --cc=maarten.lankhorst@linux.intel.com \
    --cc=srinivasan.shanmugam@amd.com \
    --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 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.