From nobody Sun Sep 27 00:36:55 2026 Received: from SN4PR0501CU005.outbound.protection.outlook.com (mail-southcentralusazon11011060.outbound.protection.outlook.com [40.93.194.60]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by smtp.subspace.kernel.org (Postfix) with ESMTPS id 92A7647DD6E; Thu, 27 Aug 2026 15:20:28 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=fail smtp.client-ip=40.93.194.60 ARC-Seal: i=2; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1787844030; cv=fail; b=EQH9S56f5bHE3PizpOm36C0rhNcgK2Wmcxo3LDBTqU3Vinxk7TEINYaIrHoSbf7YvZ7J5rA/kZoRu1Li8ZaGaAJ9iXjoP06bjTX07xm/AuQhu2hmRlHakmC/IPy6wT4p1nWpX6Zr8b3h2u8ToOWVUVG1xwGm8TRr4Ke6A7dQ5nw= ARC-Message-Signature: i=2; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1787844030; c=relaxed/simple; bh=TamgWT+5oOOgKlcneLpgUZmGdpM0JjBOu3rLJjwz7aA=; h=From:To:CC:Subject:Date:Message-ID:In-Reply-To:References: MIME-Version:Content-Type; b=QLUgK5F+95NbBfEVYXOuTvDtgMNRHJU/CaxQqSGOhEwOD7dGJ0xL7/S7oW4BkIWZDpgMXdQrQfaxPYs4jBUjxp5rjSNkkC8nALCYKK/l4RzKzQijm3DsgWR62+GIS9m50e2zPT+EPehEPlx5j4aHxYwBvUhXlCuL7979lNELk+Q= ARC-Authentication-Results: i=2; smtp.subspace.kernel.org; dmarc=pass (p=quarantine dis=none) header.from=amd.com; spf=fail smtp.mailfrom=amd.com; dkim=pass (1024-bit key) header.d=amd.com header.i=@amd.com header.b=xU5tfqyh; arc=fail smtp.client-ip=40.93.194.60 Authentication-Results: smtp.subspace.kernel.org; dmarc=pass (p=quarantine dis=none) header.from=amd.com Authentication-Results: smtp.subspace.kernel.org; spf=fail smtp.mailfrom=amd.com Authentication-Results: smtp.subspace.kernel.org; dkim=pass (1024-bit key) header.d=amd.com header.i=@amd.com header.b="xU5tfqyh" ARC-Seal: i=1; a=rsa-sha256; s=arcselector10001; d=microsoft.com; cv=none; b=cQQZShh/mhfNmg/FHGR2v70S72GXdtJP20SJ0+WgrCiiY7W9/yppeeR3CrpV6ZU/ninXRB3hUKwfAGLhjWWc+bWsIWNQwcvI+8iFwkbVJFei8X5aNsw3x+74Ak+V+KmNdOss8lPOKSUooblGxULcN6rYlgMj5mgisx9qvlRLjB+afnrndckGUndu9VDqhZnxykjnJNGbBTQAuuB3FORFmVJEwE0Eek0CFKJY8663FXilyR2wfPm91n8wPAYcodPKj3xxrCUsMh6pZgI1+5JhEsIdeaShJ/VW3ZlZVwn4+kspKVjUlGZGZQrwg1RzcpYG1QQaoOwYiWXXlpiYb7RneA== ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=microsoft.com; s=arcselector10001; h=From:Date:Subject:Message-ID:Content-Type:MIME-Version:X-MS-Exchange-AntiSpam-MessageData-ChunkCount:X-MS-Exchange-AntiSpam-MessageData-0:X-MS-Exchange-AntiSpam-MessageData-1; bh=07NLEWPyKqY8J7b1BWFsLE0WSc4j1PzmmyeYIeVIOHU=; b=t1lnv2r3hUGjY8n8ZG55JxDgPsu2T9tA3I9QPtlH0GoYKnKR7gqD5t9ABXdk1RV4ZnSZF0XLe+sJW3n46/KN8/wybcHvfNYmkDwJsP6DGk+HT/LgvKCOKyofm8Z9diUn94FinChbUTTs1nbr6bSUivd9LyMO34dlQO9hjFwSrQ7VyvVxY1lvkowl1zJUrr0WDL9hepEGQVaA+Eb+5reNattV5vNIDU2fOHk6tAErXOB4cOVplPZsSlt/JIp33qUEH/Z7Lql7ITY0tI2l4Tem4qCU5rOr4oTlS8BMqg+ONG+3GC2c1t/jUJ/QaK4qJ+0mG/fwhhc2GN+LaOI8HdGIjQ== ARC-Authentication-Results: i=1; mx.microsoft.com 1; spf=pass (sender ip is 165.204.84.17) smtp.rcpttodomain=intel.com smtp.mailfrom=amd.com; dmarc=pass (p=quarantine sp=quarantine pct=100) action=none header.from=amd.com; dkim=none (message not signed); arc=none (0) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=amd.com; s=selector1; h=From:Date:Subject:Message-ID:Content-Type:MIME-Version:X-MS-Exchange-SenderADCheck; bh=07NLEWPyKqY8J7b1BWFsLE0WSc4j1PzmmyeYIeVIOHU=; b=xU5tfqyhwfCpjadWE+CvCbF2din4TIn6fXsh29Y2dlsNjwAcukXcBCRAq6XYC8xvIRtx8ZFIG1dfzBZuq5QjjCg7acF4DAB6xlw3H5a1NzyRRIlnusAa4iqaRMXuAgPMux6M11O3QZnje6V/mXNu5jfWAnLa+0VK0S+AxTQeKHg= Received: from SA9PR13CA0009.namprd13.prod.outlook.com (2603:10b6:806:21::14) by MW4PR12MB5644.namprd12.prod.outlook.com (2603:10b6:303:189::15) with Microsoft SMTP Server (version=TLS1_2, cipher=TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384) id 15.21.360.10; Thu, 27 Aug 2026 15:20:16 +0000 Received: from SN1PEPF000397B2.namprd05.prod.outlook.com (2603:10b6:806:21:cafe::46) by SA9PR13CA0009.outlook.office365.com (2603:10b6:806:21::14) with Microsoft SMTP Server (version=TLS1_3, cipher=TLS_AES_256_GCM_SHA384) id 15.21.360.6 via Frontend Transport; Thu, 27 Aug 2026 15:20:15 +0000 X-MS-Exchange-Authentication-Results: spf=pass (sender IP is 165.204.84.17) smtp.mailfrom=amd.com; dkim=none (message not signed) header.d=none;dmarc=pass action=none header.from=amd.com; Received-SPF: Pass (protection.outlook.com: domain of amd.com designates 165.204.84.17 as permitted sender) receiver=protection.outlook.com; client-ip=165.204.84.17; helo=satlexmb07.amd.com; pr=C Received: from satlexmb07.amd.com (165.204.84.17) by SN1PEPF000397B2.mail.protection.outlook.com (10.167.248.56) with Microsoft SMTP Server (version=TLS1_2, cipher=TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384) id 15.21.360.3 via Frontend Transport; Thu, 27 Aug 2026 15:20:15 +0000 Received: from srishanm-Cloudripper.amd.com (10.180.168.240) by satlexmb07.amd.com (10.181.42.216) with Microsoft SMTP Server (version=TLS1_2, cipher=TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384) id 15.2.2562.45; Thu, 27 Aug 2026 10:20:10 -0500 From: Srinivasan Shanmugam To: CC: Srinivasan Shanmugam , =?UTF-8?q?Christian=20K=C3=B6nig?= , Alex Deucher , Maarten Lankhorst , Maxime Ripard , Thomas Zimmermann , David Airlie , Simona Vetter , Sumit Semwal , =?UTF-8?q?Thomas=20Hellstr=C3=B6m?= , , , , , , Subject: [PATCH v3 1/2] drm: Add common drm_user_fence helper Date: Thu, 27 Aug 2026 20:49:49 +0530 Message-ID: <20260827151950.4080674-2-srinivasan.shanmugam@amd.com> X-Mailer: git-send-email 2.34.1 In-Reply-To: <20260827151950.4080674-1-srinivasan.shanmugam@amd.com> References: <20260827151950.4080674-1-srinivasan.shanmugam@amd.com> Precedence: bulk X-Mailing-List: linux-kernel@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 Content-Type: text/plain; charset="utf-8" Content-Transfer-Encoding: quoted-printable X-ClientProxiedBy: satlexmb08.amd.com (10.181.42.217) To satlexmb07.amd.com (10.181.42.216) X-EOPAttributedMessage: 0 X-MS-PublicTrafficType: Email X-MS-TrafficTypeDiagnostic: SN1PEPF000397B2:EE_|MW4PR12MB5644:EE_ X-MS-Office365-Filtering-Correlation-Id: 9bf0ad20-a09e-4305-98cf-08df044eb280 X-MS-Exchange-SenderADCheck: 1 X-MS-Exchange-AntiSpam-Relay: 0 X-Microsoft-Antispam: BCL:0;ARA:13230040|36860700016|1800799024|7416014|376014|23010399003|82310400026|10067099003|11063799006|56012099006|18002099003|22082099003; X-Microsoft-Antispam-Message-Info: MTpVPLdExxVEpyy7tcB7eJat8s2oI4w3At3VrReS9Aqt2QZeljoNCGsoVuU4YdXhxFcuh6hemMvMJ4d/0YG5L4oe7viC+xYb17Fzyxln2+gRi1yavb7jWm1d4PfNSfteMH/c8G8Ala1bBMwLnr2Hrj2FUPzYksasqG/K8Nf/0LEA5J+UijkBq7Mhi05KTfRdootpyPvYOKz363XQJfx5yFqan98RekdQj3wUtQNFYRPPVvMbmLBxFKJk2uyAeyf5bBR8KohY+9p1ZHX2eGQJO0ao1920eDtwAJIw4cyjh30jixNyRts1xFYVNw+urck1eYzsz6Ut+GAT00PH0/COxUug4C0IEt1CyfahBAoM+9lvJGbwjyhoTqBVZopfMyaJCPJGfKMkfFbODXmTy82xOiInDLh67OZE6Zl6x6hqludRB0TksRQk7Bz70O7xiRKByREWzj+EOXunb5aGRJ9r3Wdv33mmydPwgRmC+Rl5zlv+52qP3VkrYkHjcXm1cUL7OzqmT5D/jZSslOl4tsk22jM0+XjIxxOAXURnNCDRbnBl8f97OeovAUpa+x+yZCdbh2geskuSS6qHQjmsNplNgfgrLL2+JRj4R9HRXwtOguC1Nyhl0p7ZiLSQLuFOm9pMsCteD9oTm5iKkmFKdEA+35IiEX8WWf5YfZrVFez+XUjaNyCQ8og8ExOQA1TRzmyFAyViQ2I0iUAPyFD811hyCQ== X-Forefront-Antispam-Report: CIP:165.204.84.17;CTRY:US;LANG:en;SCL:1;SRV:;IPV:NLI;SFV:NSPM;H:satlexmb07.amd.com;PTR:InfoDomainNonexistent;CAT:NONE;SFS:(13230040)(36860700016)(1800799024)(7416014)(376014)(23010399003)(82310400026)(10067099003)(11063799006)(56012099006)(18002099003)(22082099003);DIR:OUT;SFP:1101; X-MS-Exchange-AntiSpam-MessageData-ChunkCount: 1 X-MS-Exchange-AntiSpam-MessageData-0: iVIt8nMt4fR2HnxcE44w8aq/IDgmikZW7W259DUrpVCCBbrU3KLbQBUh+u7dLpAaEENU5pdrd88kn2zKZJly2jo0HR5ubsgh08vkV058YBeTuyqyM+CMJ95yVEaC7wGQ88bJzsaeO/4pA8+JCrAG2HsFKtEsMRVSo/kU3X6bYkTKKKpkeLNYSDve+uBblDLROKvUh6HSmsFzDk4Hc0hR3y8JI7LYOY447W22oSfju6EMZ6jBwOuzke5+g52bH/EsKk/HQuHmfp4URevAZSi91DiwDhkJ4yzgE+IJjKUDb+cXhA3WkQm7Jh3XHTRqmPNUS+4wiTVhKdO9tmDguKOHoWnl3iOk1XLeThpfnKS+uBqj2p/++SWCppIlIxr6AAzoIedxvuyugqcM5ktnuqCf3B5NLCxsHxVRMkhbxnPWKJsVKZhbcDaYOsbb6iep156Z X-OriginatorOrg: amd.com X-MS-Exchange-CrossTenant-OriginalArrivalTime: 27 Aug 2026 15:20:15.8010 (UTC) X-MS-Exchange-CrossTenant-Network-Message-Id: 9bf0ad20-a09e-4305-98cf-08df044eb280 X-MS-Exchange-CrossTenant-Id: 3dd8961f-e488-4e60-8e11-a82d994e183d X-MS-Exchange-CrossTenant-OriginalAttributedTenantConnectingIp: TenantId=3dd8961f-e488-4e60-8e11-a82d994e183d;Ip=[165.204.84.17];Helo=[satlexmb07.amd.com] X-MS-Exchange-CrossTenant-AuthSource: SN1PEPF000397B2.namprd05.prod.outlook.com X-MS-Exchange-CrossTenant-AuthAs: Anonymous X-MS-Exchange-CrossTenant-FromEntityHeader: HybridOnPrem X-MS-Exchange-Transport-CrossTenantHeadersStamped: MW4PR12MB5644 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=C3=B6nig Cc: Alex Deucher Cc: Maarten Lankhorst Cc: Maxime Ripard Cc: Thomas Zimmermann Cc: David Airlie Cc: Simona Vetter Cc: Sumit Semwal Cc: Matthew Brost Cc: Thomas Hellstr=C3=B6m Cc: dri-devel@lists.freedesktop.org Cc: intel-xe@lists.freedesktop.org Cc: linux-media@vger.kernel.org Cc: linaro-mm-sig@lists.linaro.org Cc: linux-kernel@vger.kernel.org Cc: amd-gfx@lists.freedesktop.org Signed-off-by: Srinivasan Shanmugam --- v3: - Store fence reference inside drm_user_fence during add_callback so drm_user_fence_cancel() can be called safely without the caller holding a separate fence reference, fixing a potential UAF when a foreign dma-fence signals after driver teardown. (Sashiko review) - Fix contradictory kernel-doc for drm_user_fence_cancel() which incorrectly instructed callers to put references that the function already puts internally. (Sashiko review) - Add drm_user_fence_cancel_sync() to guarantee the worker has fully completed before returning. (Sashiko review) v2: - Move INIT_WORK() to drm_user_fence_init() fixing lockdep class divergence. (Sashiko review) - drm_user_fence_add_callback() now consumes the fence reference in all paths. (Sashiko review) - Add drm_user_fence_cancel() for safe driver teardown. (Sashiko review) - Fix missing newline at end of new files. =20 drivers/gpu/drm/Makefile | 1 + drivers/gpu/drm/drm_user_fence.c | 210 +++++++++++++++++++++++++++++++ include/drm/drm_user_fence.h | 76 +++++++++++ 3 files changed, 287 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 e97faabcd783..52de1f474535 100644 --- a/drivers/gpu/drm/Makefile +++ b/drivers/gpu/drm/Makefile @@ -69,6 +69,7 @@ drm-y :=3D \ 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_fe= nce.c new file mode 100644 index 000000000000..83920d2be43b --- /dev/null +++ b/drivers/gpu/drm/drm_user_fence.c @@ -0,0 +1,209 @@ +// SPDX-License-Identifier: MIT +/* + * Copyright =C2=A9 2024 The Linux Foundation + * + * Common DRM user fence helper. + * + * When a GPU dma-fence signals, drivers often need to write a value to a + * userspace VA or notify userspace via an eventfd. Both operations require + * a valid process MM, which is not available in IRQ context. + * + * This helper queues a work item on fence signal. The work item borrows t= he + * process MM via kthread_use_mm() and calls ops->worker(), which the driv= er + * implements to perform the actual userspace access. + */ + +#include +#include +#include + +#include + +static void drm_user_fence_destroy(struct kref *kref) +{ + struct drm_user_fence *ufence =3D + container_of(kref, struct drm_user_fence, refcount); + + /* Release the extra reference stored for cancel() */ + if (ufence->fence) + dma_fence_put(ufence->fence); + + mmdrop(ufence->mm); + ufence->ops->destroy(ufence); +} + +/** + * drm_user_fence_get - Acquire a reference to a user fence + * @ufence: user fence + */ +void drm_user_fence_get(struct drm_user_fence *ufence) +{ + kref_get(&ufence->refcount); +} +EXPORT_SYMBOL_GPL(drm_user_fence_get); + +/** + * drm_user_fence_put - Release a reference to a user fence + * @ufence: user fence + */ +void drm_user_fence_put(struct drm_user_fence *ufence) +{ + kref_put(&ufence->refcount, drm_user_fence_destroy); +} +EXPORT_SYMBOL_GPL(drm_user_fence_put); + +static void drm_user_fence_work(struct work_struct *w) +{ + struct drm_user_fence *ufence =3D + container_of(w, struct drm_user_fence, work); + bool mm_ok =3D false; + + if (mmget_not_zero(ufence->mm)) { + kthread_use_mm(ufence->mm); + mm_ok =3D true; + } + + ufence->ops->worker(ufence, mm_ok); + + if (mm_ok) { + kthread_unuse_mm(ufence->mm); + mmput(ufence->mm); + } + + drm_user_fence_put(ufence); +} + +static void drm_user_fence_cb(struct dma_fence *fence, struct dma_fence_cb= *cb) +{ + struct drm_user_fence *ufence =3D + container_of(cb, struct drm_user_fence, cb); + + queue_work(ufence->wq, &ufence->work); + /* + * Put the transferred reference from add_callback. The stored + * reference in ufence->fence is released in drm_user_fence_destroy(). + */ + dma_fence_put(fence); +} + +/** + * 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 matt= ers) + * @ops: driver operations + * + * Must be called from process context. Grabs a reference to current->mm. + */ +void drm_user_fence_init(struct drm_user_fence *ufence, + struct workqueue_struct *wq, + const struct drm_user_fence_ops *ops) +{ + kref_init(&ufence->refcount); + ufence->mm =3D current->mm; + mmgrab(ufence->mm); + ufence->wq =3D wq; + ufence->ops =3D ops; + ufence->fence =3D NULL; + INIT_WORK(&ufence->work, drm_user_fence_work); +} +EXPORT_SYMBOL_GPL(drm_user_fence_init); + +/** + * drm_user_fence_add_callback - Attach a user fence to a dma-fence + * @ufence: user fence + * @fence: dma-fence to watch; ownership of this reference is transferred + * to the callback =E2=80=94 caller must NOT put it afterward. + * + * When @fence signals, a work item is queued that calls ops->worker() with + * the process MM active. If @fence has already signaled the work item is + * queued immediately. + * + * An additional reference to @fence is stored internally in @ufence to + * allow drm_user_fence_cancel() to be called safely without the caller + * needing to hold a separate fence reference. + * + * On any return value the caller's fence reference is consumed. + * + * Return: 0 on success, negative errno on error. + */ +int drm_user_fence_add_callback(struct drm_user_fence *ufence, + struct dma_fence *fence) +{ + int err; + + drm_user_fence_get(ufence); + + /* Extra ref stored for cancel() =E2=80=94 lives until drm_user_fence_des= troy() */ + ufence->fence =3D dma_fence_get(fence); + + err =3D dma_fence_add_callback(fence, &ufence->cb, drm_user_fence_cb); + if (err =3D=3D -ENOENT) { + /* fence already signaled =E2=80=94 queue work and release transferred r= ef */ + queue_work(ufence->wq, &ufence->work); + dma_fence_put(fence); + err =3D 0; + } else if (err) { + dma_fence_put(ufence->fence); + ufence->fence =3D NULL; + drm_user_fence_put(ufence); + dma_fence_put(fence); + } + /* on success: transferred ref goes to drm_user_fence_cb */ + + return err; +} +EXPORT_SYMBOL_GPL(drm_user_fence_add_callback); + +/** + * drm_user_fence_cancel - Cancel a pending user fence callback + * @ufence: user fence + * + * Attempts to remove the pending callback before driver context teardown. + * Must be called before the driver tears down its workqueue or ops. + * The caller must hold a reference to @ufence across this call. + * + * If the callback has already fired this returns false and all cleanup + * has already been handled internally =E2=80=94 the caller needs no furth= er action. + * + * If removal succeeds all references are released internally =E2=80=94 th= e caller + * must NOT call drm_user_fence_put() or dma_fence_put() afterward. + * + * Return: true if callback was removed, false if it had already fired. + */ +bool drm_user_fence_cancel(struct drm_user_fence *ufence) +{ + struct dma_fence *fence =3D ufence->fence; + + if (!fence) + return false; + + if (dma_fence_remove_callback(fence, &ufence->cb)) { + /* + * Callback will not fire =E2=80=94 release the transferred reference + * that would have been put by drm_user_fence_cb(). The stored + * reference in ufence->fence is released in destroy(). + */ + dma_fence_put(fence); + drm_user_fence_put(ufence); + return true; + } + + /* Callback already fired =E2=80=94 it handled its own cleanup */ + return false; +} +EXPORT_SYMBOL_GPL(drm_user_fence_cancel); + +/** + * drm_user_fence_cancel_sync - Cancel callback and wait for worker to fin= ish + * @ufence: user fence + * + * Calls drm_user_fence_cancel() then cancel_work_sync() to guarantee + * the worker has fully completed before returning. Drivers must call + * this during teardown before freeing any resources accessed by + * ops->worker(). + */ +void drm_user_fence_cancel_sync(struct drm_user_fence *ufence) +{ + drm_user_fence_cancel(ufence); + cancel_work_sync(&ufence->work); +} +EXPORT_SYMBOL_GPL(drm_user_fence_cancel_sync); diff --git a/include/drm/drm_user_fence.h b/include/drm/drm_user_fence.h new file mode 100644 index 000000000000..02a02266ab93 --- /dev/null +++ b/include/drm/drm_user_fence.h @@ -0,0 +1,75 @@ +/* SPDX-License-Identifier: MIT */ +/* + * Copyright =C2=A9 2024 The Linux Foundation + */ + +#ifndef __DRM_USER_FENCE_H__ +#define __DRM_USER_FENCE_H__ + +#include +#include +#include + +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. + * + * If @mm_ok is true, kthread_use_mm() is active and userspace memory + * (copy_to_user, eventfd_signal, 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. + * + * 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 - embeddable DRM user fence + * + * Drivers embed this in their own structure and implement + * &drm_user_fence_ops. 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 driver teardown. + */ +struct drm_user_fence { + /** @refcount: Reference count. */ + struct kref refcount; + /** @mm: Process MM grabbed at init time. */ + struct mm_struct *mm; + /** @work: Work item queued when the dma-fence signals. */ + struct work_struct work; + /** @cb: dma-fence callback. */ + struct dma_fence_cb cb; + /** + * @fence: Extra reference held for safe cancel(). Set during + * add_callback, released in destroy(). + */ + struct dma_fence *fence; + /** @wq: Workqueue to run @work on. */ + struct workqueue_struct *wq; + /** @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); +void drm_user_fence_get(struct drm_user_fence *ufence); +void drm_user_fence_put(struct drm_user_fence *ufence); +int drm_user_fence_add_callback(struct drm_user_fence *ufence, + struct dma_fence *fence); +bool drm_user_fence_cancel(struct drm_user_fence *ufence); +void drm_user_fence_cancel_sync(struct drm_user_fence *ufence); + +#endif /* __DRM_USER_FENCE_H__ */ --=20 2.34.1 From nobody Sun Sep 27 00:36:55 2026 Received: from CH5PR02CU005.outbound.protection.outlook.com (mail-northcentralusazon11012028.outbound.protection.outlook.com [40.107.200.28]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by smtp.subspace.kernel.org (Postfix) with ESMTPS id 211C147F2C3; Thu, 27 Aug 2026 15:20:39 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=fail smtp.client-ip=40.107.200.28 ARC-Seal: i=2; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1787844042; cv=fail; b=StS2kzl616v1LkVpUQFoC/85+MB9jJS0Zs63Eiy0tW8Rn41QGth3uzMeHWjpoYOHk67JnjmpoS4+b6+kzM0Hkltpe9BECKl3PxbIoWqDIHCcvLJ9aFUxjb/qprjwqGxMDQ6hpAnMo4h2sHnAbzXzN37YtP/tf2aadiZuxYcQrMo= ARC-Message-Signature: i=2; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1787844042; c=relaxed/simple; bh=Oz7A52V5LgIAKx91CH3w+5rn1kMCzKLMgZIMl8MIKgM=; h=From:To:CC:Subject:Date:Message-ID:In-Reply-To:References: MIME-Version:Content-Type; b=BstWERVChBevCawfFMUcRWwHP+yD9rWRhK2mkL/LkO9YQgPIFEcfoQaJpB3s5/SO4qwRR0fl0VSih+18hv21y7c/6jUtQzEaITtLy6ogCgRJGYT5fOdwzJJTJN1ksQ0NvvV/zk8cKpWpFxFfDWuiBuSPZ98pVKutz4k0j9LgtBE= ARC-Authentication-Results: i=2; smtp.subspace.kernel.org; dmarc=pass (p=quarantine dis=none) header.from=amd.com; spf=fail smtp.mailfrom=amd.com; dkim=pass (1024-bit key) header.d=amd.com header.i=@amd.com header.b=HzaYxbGg; arc=fail smtp.client-ip=40.107.200.28 Authentication-Results: smtp.subspace.kernel.org; dmarc=pass (p=quarantine dis=none) header.from=amd.com Authentication-Results: smtp.subspace.kernel.org; spf=fail smtp.mailfrom=amd.com Authentication-Results: smtp.subspace.kernel.org; dkim=pass (1024-bit key) header.d=amd.com header.i=@amd.com header.b="HzaYxbGg" ARC-Seal: i=1; a=rsa-sha256; s=arcselector10001; d=microsoft.com; cv=none; b=BVpjg6who5sQjjZUZgssfkK3x5bMg8fH1JkhbU5nZn1BUm6ym214VzH2YJ0H9UwPUXvnIizJOiYyWsjGRIeBAh+Et1LP3CyKHwjXV1GuFPdFVre1hGYehSV4Bpu+8RmYTUcl0XXXsoqP1dAqNP+rGw/plILe2tac/OIgTcMBFTanooGndQqUjMLPqr2AApQMqsObT5ZI9FlY9Pv6sRUzGOUKGNtgJuvcWAzDaXbTkN2TTq78NHxdq0nvHeU0sNbY6v8ITJimxBTTk/coC9QpSsinipH3lTlRolNGP/b2mdaOy3f7oyA+N9OMm/Hmd4ZJN8kPevc6wjFhXQ7wU6KX9w== ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=microsoft.com; s=arcselector10001; h=From:Date:Subject:Message-ID:Content-Type:MIME-Version:X-MS-Exchange-AntiSpam-MessageData-ChunkCount:X-MS-Exchange-AntiSpam-MessageData-0:X-MS-Exchange-AntiSpam-MessageData-1; bh=4VMuTDq8NZbujpr/hAkSxWMhA4+imLCSjJ5vGlwOPyg=; b=nLjM4Sb+42pqI1l5YkCqJNcOmdgIw/ktOcjhpZkOi2NhZ1srAEtjT7t/HNuK2NNuQw33D/SnaquENC8nlA7vX3+fueRfU6EEfyRXBc3yP76YfLvn49SfmzUEhNaajuXrzibnvz0ISpg1kzKn0SUj90Bm0Mkj5MYzDQDNb30cWdN9cGjWyK9/H4EfOV7rq4D7vBEHsU/NNjAx5Ql7/EF5ej/9NrjMcz4wFXn9b7OELSvtYJzOJYfjQwxvjBNUxfFMXo5/sPu1Bu5sI3CWieIN4t/4PJBnif4/BdlEJYrGtwgGXhFN9e3Ldgfpdfxx1Lmn1648fTLjT7acN0x4rlwfoA== ARC-Authentication-Results: i=1; mx.microsoft.com 1; spf=pass (sender ip is 165.204.84.17) smtp.rcpttodomain=intel.com smtp.mailfrom=amd.com; dmarc=pass (p=quarantine sp=quarantine pct=100) action=none header.from=amd.com; dkim=none (message not signed); arc=none (0) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=amd.com; s=selector1; h=From:Date:Subject:Message-ID:Content-Type:MIME-Version:X-MS-Exchange-SenderADCheck; bh=4VMuTDq8NZbujpr/hAkSxWMhA4+imLCSjJ5vGlwOPyg=; b=HzaYxbGgD6z3dclS9xjNYsFJzLQvdS7quNSs/vTXWUhoeykQPxQaCQTw2LCCwGdyLhv9eTch+o29F7Q/G/jFXgnhyXtj9m782yitiCbzVTQ/avr6PNnsx806D6EWFuxp4Vkxr53UpSpCZZEWhtzh6+0WtfI3FETn6sV56vOCQwU= Received: from SA0PR11CA0045.namprd11.prod.outlook.com (2603:10b6:806:d0::20) by SJ1PR12MB6027.namprd12.prod.outlook.com (2603:10b6:a03:48a::7) with Microsoft SMTP Server (version=TLS1_2, cipher=TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384) id 15.21.360.7; Thu, 27 Aug 2026 15:20:24 +0000 Received: from SN1PEPF000397AE.namprd05.prod.outlook.com (2603:10b6:806:d0:cafe::26) by SA0PR11CA0045.outlook.office365.com (2603:10b6:806:d0::20) with Microsoft SMTP Server (version=TLS1_3, cipher=TLS_AES_256_GCM_SHA384) id 15.21.360.10 via Frontend Transport; Thu, 27 Aug 2026 15:20:21 +0000 X-MS-Exchange-Authentication-Results: spf=pass (sender IP is 165.204.84.17) smtp.mailfrom=amd.com; dkim=none (message not signed) header.d=none;dmarc=pass action=none header.from=amd.com; Received-SPF: Pass (protection.outlook.com: domain of amd.com designates 165.204.84.17 as permitted sender) receiver=protection.outlook.com; client-ip=165.204.84.17; helo=satlexmb07.amd.com; pr=C Received: from satlexmb07.amd.com (165.204.84.17) by SN1PEPF000397AE.mail.protection.outlook.com (10.167.248.52) with Microsoft SMTP Server (version=TLS1_2, cipher=TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384) id 15.21.360.3 via Frontend Transport; Thu, 27 Aug 2026 15:20:20 +0000 Received: from srishanm-Cloudripper.amd.com (10.180.168.240) by satlexmb07.amd.com (10.181.42.216) with Microsoft SMTP Server (version=TLS1_2, cipher=TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384) id 15.2.2562.45; Thu, 27 Aug 2026 10:20:15 -0500 From: Srinivasan Shanmugam To: CC: Srinivasan Shanmugam , =?UTF-8?q?Thomas=20Hellstr=C3=B6m?= , Rodrigo Vivi , Mika Kuoppala , David Airlie , "Simona Vetter" , Sumit Semwal , =?UTF-8?q?Christian=20K=C3=B6nig?= , Alex Deucher , , , , , Subject: [PATCH v3 2/2] drm/xe: Convert xe_user_fence to drm_user_fence Date: Thu, 27 Aug 2026 20:49:50 +0530 Message-ID: <20260827151950.4080674-3-srinivasan.shanmugam@amd.com> X-Mailer: git-send-email 2.34.1 In-Reply-To: <20260827151950.4080674-1-srinivasan.shanmugam@amd.com> References: <20260827151950.4080674-1-srinivasan.shanmugam@amd.com> Precedence: bulk X-Mailing-List: linux-kernel@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 Content-Type: text/plain; charset="utf-8" Content-Transfer-Encoding: quoted-printable X-ClientProxiedBy: satlexmb08.amd.com (10.181.42.217) To satlexmb07.amd.com (10.181.42.216) X-EOPAttributedMessage: 0 X-MS-PublicTrafficType: Email X-MS-TrafficTypeDiagnostic: SN1PEPF000397AE:EE_|SJ1PR12MB6027:EE_ X-MS-Office365-Filtering-Correlation-Id: af2e2f48-4e5b-49d7-b9e6-08df044eb559 X-MS-Exchange-SenderADCheck: 1 X-MS-Exchange-AntiSpam-Relay: 0 X-Microsoft-Antispam: BCL:0;ARA:13230040|36860700016|7416014|376014|1800799024|23010399003|82310400026|10067099003|56012099006|11063799006|6133799003|22082099003|18002099003; X-Microsoft-Antispam-Message-Info: T0fYA+iV+DOUHh0/1dhBuBKo0pgzuD18Dg0qZTVecfao5TmBhk6Ez08mHbMF3m9SlGwPc25N+2tsdekYeQchqejfw8LfQKmCZun/31K3OKGA7SO5WMo8ic1KlvgB791lxV7Kkil3ENFRzQ9Gqq2chpRBkOIzJO0P4gk2fKZHYavVLnkVXKtEduA4h4+Xz4qfmILUQcG4ABRG99YidGBnNLsRbqQpkAhuMbwmjYMiXgqm2zycBBe1WdKEmBfaMjXTa/XvQqk8CTz+Z2L1NyEhmhMpBlzuDyW2Q2MtKddRjC3O1fP9BERp0wrdqXdnK8Z0pi5emouvJ/Eb5Iuju33GEDiPmR5VPjPoQMDjRO5gIcKUtSvCanLznSxim53XCf68YNauqa+9gJAHjwDSt0eGBxv72px7LZNkSk+P00yyVenUST3zcz186DiD23fVMddvYgwAAwspatQLgEkOnvD2O3jr9Mqu9tlsvvwroq8ali8XbEP6me5Rorh9TdBbI9OvPa8HfFoY77daWkkPcOFtAM3PNqqAcebfjJ7vO8lBqgqjjM4dtQxidGitX0T0ucLM66a8BnbpMsVgDmgv2gJir97GmWMygOwo1xMDvUUslY3LSiyOFLIhXSfpVaaCJS2jEfrSSYrP5oJBGfg6xAz+Hb4gy5Ig9a5YgW30bEBc6LQ/S8StALhQ8DQOsJZiie0+K8/XqUkoSlgPTcGf6ivUfw== X-Forefront-Antispam-Report: CIP:165.204.84.17;CTRY:US;LANG:en;SCL:1;SRV:;IPV:NLI;SFV:NSPM;H:satlexmb07.amd.com;PTR:InfoDomainNonexistent;CAT:NONE;SFS:(13230040)(36860700016)(7416014)(376014)(1800799024)(23010399003)(82310400026)(10067099003)(56012099006)(11063799006)(6133799003)(22082099003)(18002099003);DIR:OUT;SFP:1101; X-MS-Exchange-AntiSpam-MessageData-ChunkCount: 1 X-MS-Exchange-AntiSpam-MessageData-0: uuz17gr9iNyWdsFZAEZ3XaV3ddVLHuwEZFQKnD/m24+0vIcRHWpKpVDiAbRhnCzfYF2JmFrJLWNqXMOPyUqj/Y4IJiufGuuiUZwHS4OJ05kVKLsZH6oWURuTYqxGDVPEPyBGj7WSHmxfBA33oxD3AaDAR0kF6UXUWSAI6MizVtmmxs8rAHq/a5LGY2Xx5nIwUtAYHxFKF2e+8yhSpFICO1LtcrNm+W6XA8RDj7zuBEKHoC8vtHxKxsht8VQGu5orp+p3g+24SyoSkwwq2eV154j34O/9V0/Fr5SFKg/ZNRSwC3mE0TbaVlpc2mijC5MvUQ4aaxnpmO1suVDs+ZYTicht2SeewZMolst1/zrJ5v1yEDQJ8hwg7vcB1hqLMBMhTI16Y0sKSVkA+60vi06OSuxu20i36sARrCQM/GUpLrqVamehZqX+tb7pdst40Kdl X-OriginatorOrg: amd.com X-MS-Exchange-CrossTenant-OriginalArrivalTime: 27 Aug 2026 15:20:20.5756 (UTC) X-MS-Exchange-CrossTenant-Network-Message-Id: af2e2f48-4e5b-49d7-b9e6-08df044eb559 X-MS-Exchange-CrossTenant-Id: 3dd8961f-e488-4e60-8e11-a82d994e183d X-MS-Exchange-CrossTenant-OriginalAttributedTenantConnectingIp: TenantId=3dd8961f-e488-4e60-8e11-a82d994e183d;Ip=[165.204.84.17];Helo=[satlexmb07.amd.com] X-MS-Exchange-CrossTenant-AuthSource: SN1PEPF000397AE.namprd05.prod.outlook.com X-MS-Exchange-CrossTenant-AuthAs: Anonymous X-MS-Exchange-CrossTenant-FromEntityHeader: HybridOnPrem X-MS-Exchange-Transport-CrossTenantHeadersStamped: SJ1PR12MB6027 Replace the open-coded user fence implementation in xe_sync.c with the new common drm_user_fence helper. struct xe_user_fence now embeds struct drm_user_fence as its base. XE-specific fields (xe_device pointer for the ufence_wq wake-up, userspace VA, expected value, signalled flag) remain in the wrapper. The local user_fence_destroy/get/put/worker/kick_ufence/user_fence_cb functions are removed. Their logic moves to xe_ufence_ops.worker and xe_ufence_ops.destroy, which are called by drm_user_fence_work(). Cc: Matthew Brost Cc: Thomas Hellstr=C3=B6m Cc: Rodrigo Vivi Cc: Mika Kuoppala Cc: David Airlie Cc: Simona Vetter Cc: Sumit Semwal Cc: Christian K=C3=B6nig Cc: Alex Deucher Cc: intel-xe@lists.freedesktop.org Cc: dri-devel@lists.freedesktop.org Cc: linux-media@vger.kernel.org Cc: linaro-mm-sig@lists.linaro.org Cc: linux-kernel@vger.kernel.org Signed-off-by: Srinivasan Shanmugam Suggested-by: Christian K=C3=B6nig --- v3: - Add xe_sync_ufence_cancel_sync() wrapper so xe_vm.c does not need to include drm_user_fence.h or access struct xe_user_fence internals. - Call xe_sync_ufence_cancel_sync() in xe_vma_destroy_late() before dropping the VMA's ufence reference. (Sashiko review) - Call drm_user_fence_cancel_sync() in xe_sync_entry_cleanup() to ensure the worker has completed before teardown. (Sashiko review) - Add smp_wmb() between WRITE_ONCE(signalled) and copy_to_user() to prevent store reordering on ARM64. (Sashiko review) - Replace XE_WARN_ON() on copy_to_user() failure with drm_dbg() to prevent unprivileged DoS via panic_on_warn. (Sashiko review) v2: - Remove unconditional dma_fence_put(fence) after drm_user_fence_add_callback() in xe_sync_entry_signal(). The fence reference is now consumed by drm_user_fence_add_callback() in all paths. (Sashiko review) drivers/gpu/drm/xe/xe_sync.c | 140 ++++++++++++++--------------- drivers/gpu/drm/xe/xe_sync.h | 1 + drivers/gpu/drm/xe/xe_sync_types.h | 3 +- drivers/gpu/drm/xe/xe_vm.c | 1 + 4 files changed, 73 insertions(+), 72 deletions(-) diff --git a/drivers/gpu/drm/xe/xe_sync.c b/drivers/gpu/drm/xe/xe_sync.c index 37866768d64c..7da61ad01c36 100644 --- a/drivers/gpu/drm/xe/xe_sync.c +++ b/drivers/gpu/drm/xe/xe_sync.c @@ -6,12 +6,11 @@ #include "xe_sync.h" =20 #include -#include -#include #include =20 #include #include +#include #include =20 #include "xe_device.h" @@ -19,36 +18,60 @@ #include "xe_macros.h" #include "xe_sched_job_types.h" =20 +/* + * xe_user_fence wraps drm_user_fence with XE-specific fields. + * The drm_user_fence base handles MM borrowing and work-item lifetime. + */ struct xe_user_fence { - struct xe_device *xe; - struct kref refcount; - struct dma_fence_cb cb; - struct work_struct worker; - struct mm_struct *mm; - u64 __user *addr; - u64 value; - int signalled; + struct drm_user_fence base; + struct xe_device *xe; + u64 __user *addr; + u64 value; + int signalled; }; =20 -static void user_fence_destroy(struct kref *kref) +static void xe_ufence_worker(struct drm_user_fence *base, bool mm_ok) { - struct xe_user_fence *ufence =3D container_of(kref, struct xe_user_fence, - refcount); + struct xe_user_fence *ufence =3D container_of(base, struct xe_user_fence,= base); =20 - mmdrop(ufence->mm); - kfree(ufence); -} + /* + * Mark signalled before waking waiters so UMD can safely reuse + * the same ufence without hitting -EBUSY. + */ + WRITE_ONCE(ufence->signalled, 1); =20 -static void user_fence_get(struct xe_user_fence *ufence) -{ - kref_get(&ufence->refcount); + /* + * Ensure the signalled store is visible before the user memory write + * on weakly ordered architectures (e.g. ARM64). Without this barrier + * the CPU may reorder stores, causing userspace to observe the user + * memory update before signalled =3D=3D 1. + */ + smp_wmb(); + + if (mm_ok) { + if (copy_to_user(ufence->addr, &ufence->value, sizeof(ufence->value))) + drm_dbg(&ufence->xe->drm, + "copy_to_user failed, user fence wasn't signaled\n"); + } else { + drm_dbg(&ufence->xe->drm, + "mmget_not_zero() failed, ufence wasn't signaled\n"); + } + + wake_up_all(&ufence->xe->ufence_wq); } =20 -static void user_fence_put(struct xe_user_fence *ufence) +static void xe_ufence_destroy(struct drm_user_fence *base) { - kref_put(&ufence->refcount, user_fence_destroy); + struct xe_user_fence *ufence =3D container_of(base, struct xe_user_fence,= base); + + kfree(ufence); } =20 +static const struct drm_user_fence_ops xe_ufence_ops =3D { + .worker =3D xe_ufence_worker, + .destroy =3D xe_ufence_destroy, +}; + static struct xe_user_fence *user_fence_create(struct xe_device *xe, u64 a= ddr, u64 value) { @@ -63,51 +86,22 @@ static struct xe_user_fence *user_fence_create(struct x= e_device *xe, u64 addr, if (!ufence) return ERR_PTR(-ENOMEM); =20 - ufence->xe =3D xe; - kref_init(&ufence->refcount); - ufence->addr =3D ptr; + ufence->xe =3D xe; + ufence->addr =3D ptr; ufence->value =3D value; - ufence->mm =3D current->mm; - mmgrab(ufence->mm); + drm_user_fence_init(&ufence->base, xe->ordered_wq, &xe_ufence_ops); =20 return ufence; } =20 -static void user_fence_worker(struct work_struct *w) -{ - struct xe_user_fence *ufence =3D container_of(w, struct xe_user_fence, wo= rker); - - WRITE_ONCE(ufence->signalled, 1); - if (mmget_not_zero(ufence->mm)) { - kthread_use_mm(ufence->mm); - if (copy_to_user(ufence->addr, &ufence->value, sizeof(ufence->value))) - XE_WARN_ON("Copy to user failed"); - kthread_unuse_mm(ufence->mm); - mmput(ufence->mm); - } else { - drm_dbg(&ufence->xe->drm, "mmget_not_zero() failed, ufence wasn't signal= ed\n"); - } - - /* - * Wake up waiters only after updating the ufence state, allowing the UMD - * to safely reuse the same ufence without encountering -EBUSY errors. - */ - wake_up_all(&ufence->xe->ufence_wq); - user_fence_put(ufence); -} - -static void kick_ufence(struct xe_user_fence *ufence, struct dma_fence *fe= nce) +static void user_fence_get(struct xe_user_fence *ufence) { - INIT_WORK(&ufence->worker, user_fence_worker); - queue_work(ufence->xe->ordered_wq, &ufence->worker); - dma_fence_put(fence); + drm_user_fence_get(&ufence->base); } =20 -static void user_fence_cb(struct dma_fence *fence, struct dma_fence_cb *cb) +static void user_fence_put(struct xe_user_fence *ufence) { - struct xe_user_fence *ufence =3D container_of(cb, struct xe_user_fence, c= b); - - kick_ufence(ufence, fence); + drm_user_fence_put(&ufence->base); } =20 int xe_sync_entry_parse(struct xe_device *xe, struct xe_file *xef, @@ -282,24 +276,15 @@ void xe_sync_entry_signal(struct xe_sync_entry *sync,= struct dma_fence *fence) } else if (sync->syncobj) { drm_syncobj_replace_fence(sync->syncobj, fence); } else if (sync->ufence) { - int err; - drm_syncobj_add_point(sync->ufence_syncobj, sync->ufence_chain_fence, fence, sync->ufence_timeline_value); sync->ufence_chain_fence =3D NULL; =20 fence =3D drm_syncobj_fence_get(sync->ufence_syncobj); - user_fence_get(sync->ufence); - err =3D dma_fence_add_callback(fence, &sync->ufence->cb, - user_fence_cb); - if (err =3D=3D -ENOENT) { - kick_ufence(sync->ufence, fence); - } else if (err) { + if (drm_user_fence_add_callback(&sync->ufence->base, fence)) XE_WARN_ON("failed to add user fence"); - user_fence_put(sync->ufence); - dma_fence_put(fence); - } + /* fence ref consumed by drm_user_fence_add_callback */ } } =20 @@ -310,8 +295,10 @@ void xe_sync_entry_cleanup(struct xe_sync_entry *sync) dma_fence_put(sync->fence); dma_fence_chain_free(sync->chain_fence); dma_fence_chain_free(sync->ufence_chain_fence); - if (!IS_ERR_OR_NULL(sync->ufence)) + if (!IS_ERR_OR_NULL(sync->ufence)) { + drm_user_fence_cancel_sync(&sync->ufence->base); user_fence_put(sync->ufence); + } } =20 /** @@ -434,6 +421,19 @@ void xe_sync_ufence_put(struct xe_user_fence *ufence) user_fence_put(ufence); } =20 +/** + * xe_sync_ufence_cancel_sync() - Cancel user fence callback and wait for = worker + * @ufence: user fence reference + * + * Cancels any pending dma-fence callback and waits for the worker to fully + * complete before returning. Must be called during teardown before freeing + * any resources accessed by the worker. + */ +void xe_sync_ufence_cancel_sync(struct xe_user_fence *ufence) +{ + drm_user_fence_cancel_sync(&ufence->base); +} + /** * xe_sync_ufence_get_status() - Get user fence status * @ufence: user fence @@ -443,4 +443,3 @@ void xe_sync_ufence_put(struct xe_user_fence *ufence) int xe_sync_ufence_get_status(struct xe_user_fence *ufence) { return READ_ONCE(ufence->signalled); -} +} diff --git a/drivers/gpu/drm/xe/xe_sync.h b/drivers/gpu/drm/xe/xe_sync.h index 6b949194acff..ff47882b3f6f 100644 --- a/drivers/gpu/drm/xe/xe_sync.h +++ b/drivers/gpu/drm/xe/xe_sync.h @@ -44,6 +44,7 @@ static inline bool xe_sync_is_ufence(struct xe_sync_entry= *sync) struct xe_user_fence *__xe_sync_ufence_get(struct xe_user_fence *ufence); struct xe_user_fence *xe_sync_ufence_get(struct xe_sync_entry *sync); void xe_sync_ufence_put(struct xe_user_fence *ufence); +void xe_sync_ufence_cancel_sync(struct xe_user_fence *ufence); int xe_sync_ufence_get_status(struct xe_user_fence *ufence); =20 #endif diff --git a/drivers/gpu/drm/xe/xe_sync_types.h b/drivers/gpu/drm/xe/xe_syn= c_types.h index b88f1833e28c..49df2bfa817c 100644 --- a/drivers/gpu/drm/xe/xe_sync_types.h +++ b/drivers/gpu/drm/xe/xe_sync_types.h @@ -12,7 +12,6 @@ struct drm_syncobj; struct dma_fence; struct dma_fence_chain; struct drm_xe_sync; -struct user_fence; =20 struct xe_sync_entry { struct drm_syncobj *syncobj; @@ -28,4 +27,3 @@ struct xe_sync_entry { u32 flags; }; =20 -#endif +#endif diff --git a/drivers/gpu/drm/xe/xe_vm.c b/drivers/gpu/drm/xe/xe_vm.c index b01f31ed4417..0a1f7615aed9 100644 --- a/drivers/gpu/drm/xe/xe_vm.c +++ b/drivers/gpu/drm/xe/xe_vm.c @@ -1181,6 +1181,7 @@ static void xe_vma_destroy_late(struct xe_vma *vma) struct xe_bo *bo =3D xe_vma_bo(vma); =20 if (vma->ufence) { + xe_sync_ufence_cancel_sync(vma->ufence); xe_sync_ufence_put(vma->ufence); vma->ufence =3D NULL; } --=20 2.34.1