All of lore.kernel.org
 help / color / mirror / Atom feed
From: James Zhu <James.Zhu@amd.com>
To: <amd-gfx@lists.freedesktop.org>, <alexander.deucher@amd.com>,
	<Bing.Ma@amd.com>
Cc: <jamesz@amd.com>, Bing Ma <bing.ma@amd.com>
Subject: [PATCH 02/12] drm/amdgpu: Add profiler UAPI infrastructure
Date: Mon, 21 Sep 2026 16:03:03 -0400	[thread overview]
Message-ID: <20260921200313.865829-2-James.Zhu@amd.com> (raw)
In-Reply-To: <20260921200313.865829-1-James.Zhu@amd.com>

Add the DRM_AMDGPU_PROFILER ioctl handler and its manager, the base for
GPU performance monitoring features such as SPM (Stream Performance
Monitor).

The manager is per-XCP (eXtended Compute Partition) and refcounted, so
several clients can share a partition. Clients with no partition assigned
are rejected on a partitioned device, to keep partition 0's counters
isolated. Teardown is split into a prepare/fini pair so that in-flight
ioctls are drained across drm_dev_unplug().

The ioctl is not registered in amdgpu_ioctls_kms[] and the SPM operations
return -EOPNOTSUPP. Both land later in this series, so the UAPI only
becomes reachable once it is fully implemented.

Signed-off-by: James Zhu <James.Zhu@amd.com>
Reviewed-by: Bing Ma <bing.ma@amd.com>
---
 drivers/gpu/drm/amd/amdgpu/Makefile          |   2 +-
 drivers/gpu/drm/amd/amdgpu/amdgpu.h          |   8 +
 drivers/gpu/drm/amd/amdgpu/amdgpu_device.c   |   3 +
 drivers/gpu/drm/amd/amdgpu/amdgpu_drv.c      |  16 +
 drivers/gpu/drm/amd/amdgpu/amdgpu_kms.c      |  11 +
 drivers/gpu/drm/amd/amdgpu/amdgpu_profiler.c | 303 +++++++++++++++++++
 drivers/gpu/drm/amd/amdgpu/amdgpu_profiler.h |  92 ++++++
 drivers/gpu/drm/amd/amdgpu/amdgpu_spm.c      |  98 ++++++
 drivers/gpu/drm/amd/amdgpu/amdgpu_spm.h      |  43 +++
 9 files changed, 575 insertions(+), 1 deletion(-)
 create mode 100644 drivers/gpu/drm/amd/amdgpu/amdgpu_profiler.c
 create mode 100644 drivers/gpu/drm/amd/amdgpu/amdgpu_profiler.h
 create mode 100644 drivers/gpu/drm/amd/amdgpu/amdgpu_spm.c
 create mode 100644 drivers/gpu/drm/amd/amdgpu/amdgpu_spm.h

diff --git a/drivers/gpu/drm/amd/amdgpu/Makefile b/drivers/gpu/drm/amd/amdgpu/Makefile
index ec199715ee76..b17d8f7b4e8f 100644
--- a/drivers/gpu/drm/amd/amdgpu/Makefile
+++ b/drivers/gpu/drm/amd/amdgpu/Makefile
@@ -72,7 +72,7 @@ amdgpu-y += amdgpu_device.o amdgpu_reg_access.o amdgpu_doorbell_mgr.o amdgpu_kms
 	amdgpu_eeprom.o amdgpu_mca.o amdgpu_psp_ta.o amdgpu_lsdma.o amdgpu_lockdep.o \
 	amdgpu_ring_mux.o amdgpu_xcp.o amdgpu_seq64.o amdgpu_dev_coredump.o \
 	amdgpu_cper.o amdgpu_userq_fence.o amdgpu_eviction_fence.o amdgpu_ip.o \
-	amdgpu_wb.o amdgpu_trap.o amdgpu_events.o
+	amdgpu_wb.o amdgpu_trap.o amdgpu_events.o amdgpu_profiler.o amdgpu_spm.o
 
 amdgpu-$(CONFIG_PROC_FS) += amdgpu_fdinfo.o
 
diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu.h b/drivers/gpu/drm/amd/amdgpu/amdgpu.h
index e3763c197138..244215320916 100644
--- a/drivers/gpu/drm/amd/amdgpu/amdgpu.h
+++ b/drivers/gpu/drm/amd/amdgpu/amdgpu.h
@@ -110,6 +110,7 @@
 #include "amdgpu_seq64.h"
 #include "amdgpu_reg_state.h"
 #include "amdgpu_userq.h"
+#include "amdgpu_profiler.h"
 #include "amdgpu_eviction_fence.h"
 #include "amdgpu_wb.h"
 #include "amdgpu_ip.h"
@@ -424,6 +425,11 @@ struct amdgpu_fpriv {
 
 	/** GPU partition selection */
 	uint32_t		xcp_id;
+	/** Profiler XCP manager this fd holds a reference on, latched by
+	 *  amdgpu_profiler_mgr_init(). NULL if no reference was taken, which
+	 *  gates the matching release and the profiler ioctl.
+	 */
+	struct amdgpu_profiler_xcp_mgr	*prof_xcp_mgr;
 };
 
 int amdgpu_file_to_fpriv(struct file *filp, struct amdgpu_fpriv **fpriv);
@@ -960,6 +966,8 @@ struct amdgpu_device {
 
 	struct amdgpu_uma_carveout_info uma_info;
 
+	struct amdgpu_profiler_mgr      prof_mgr;
+
 	/* KFD
 	 * Must be last --ends in a flexible-array member.
 	 */
diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_device.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_device.c
index 380989f4c965..a4703bc28359 100644
--- a/drivers/gpu/drm/amd/amdgpu/amdgpu_device.c
+++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_device.c
@@ -3686,6 +3686,7 @@ int amdgpu_device_init(struct amdgpu_device *adev,
 	mutex_init(&adev->gfx.userq_sch_mutex);
 	mutex_init(&adev->gfx.workload_profile_mutex);
 	mutex_init(&adev->vcn.workload_profile_mutex);
+	amdgpu_profiler_device_init(adev);
 
 	spin_lock_init(&adev->irq.lock);
 
@@ -4244,6 +4245,8 @@ void amdgpu_device_fini_sw(struct amdgpu_device *adev)
 	kfree(adev->pci_state);
 	kfree(adev->pcie_reset_ctx.swds_pcistate);
 	kfree(adev->pcie_reset_ctx.swus_pcistate);
+
+	amdgpu_profiler_device_sw_fini(adev);
 }
 
 /**
diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_drv.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_drv.c
index a93ee106ab92..03bbf101bf23 100644
--- a/drivers/gpu/drm/amd/amdgpu/amdgpu_drv.c
+++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_drv.c
@@ -2556,9 +2556,25 @@ amdgpu_pci_remove(struct pci_dev *pdev)
 	struct amdgpu_device *adev = drm_to_adev(dev);
 
 	amdgpu_ras_eeprom_check_and_recover(adev);
+	/*
+	 * Signal profiler teardown and wake any blocked SPM waiters so their
+	 * ioctls can exit. This must run before drm_dev_unplug(dev) below,
+	 * which is what drains in-flight profiler ioctls via SRCU: a profiler
+	 * ioctl blocked in a client-supplied SPM wait would otherwise stall
+	 * that unplug until the client's timeout expired. (XCP partition nodes
+	 * redirect their ioctls to the primary drm_device in
+	 * amdgpu_xcp_dev_alloc(), so they register on the primary device's SRCU
+	 * and amdgpu_xcp_dev_unplug() itself never waits on a profiler ioctl.)
+	 */
+	amdgpu_profiler_device_prepare_fini(adev);
 	amdgpu_xcp_dev_unplug(adev);
 	amdgpu_gmc_prepare_nps_mode_change(adev);
 	drm_dev_unplug(dev);
+	/*
+	 * Release profiler/SPM state now that drm_dev_unplug() guarantees no
+	 * ioctl is in flight. HW is still live (before amdgpu_driver_unload_kms()).
+	 */
+	amdgpu_profiler_device_fini(adev);
 
 	if (adev->pm.rpm_mode != AMDGPU_RUNPM_NONE) {
 		pm_runtime_get_sync(dev->dev);
diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_kms.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_kms.c
index 47e4680db797..57fa69c0382d 100644
--- a/drivers/gpu/drm/amd/amdgpu/amdgpu_kms.c
+++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_kms.c
@@ -1647,6 +1647,10 @@ int amdgpu_driver_open_kms(struct drm_device *dev, struct drm_file *file_priv)
 			dev_dbg(adev->dev, "trap handler not enabled");
 	}
 
+	/* Profiler is optional - don't fail open if unavailable */
+	if (amdgpu_profiler_mgr_init(adev, fpriv))
+		dev_dbg(adev->dev, "Can't setup profiler, continuing without it\n");
+
 	amdgpu_ctx_mgr_init(&fpriv->ctx_mgr, adev);
 
 	file_priv->driver_priv = fpriv;
@@ -1693,6 +1697,13 @@ void amdgpu_driver_postclose_kms(struct drm_device *dev,
 
 	pm_runtime_get_sync(dev->dev);
 
+	/* Drop the profiler reference here rather than in ->release: postclose
+	 * also runs for in-kernel drm_client teardown (drm_file_free), and
+	 * before kfree(fpriv) below. Placed after pm_runtime_get_sync() so a
+	 * later SPM release can touch registers on a resumed device.
+	 */
+	amdgpu_profiler_mgr_fini(file_priv);
+
 	if (amdgpu_device_ip_get_ip_block(adev, AMD_IP_BLOCK_TYPE_UVD) != NULL)
 		amdgpu_uvd_free_handles(adev, file_priv);
 	if (amdgpu_device_ip_get_ip_block(adev, AMD_IP_BLOCK_TYPE_VCE) != NULL)
diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_profiler.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_profiler.c
new file mode 100644
index 000000000000..da322d2e6431
--- /dev/null
+++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_profiler.c
@@ -0,0 +1,303 @@
+// SPDX-License-Identifier: GPL-2.0 OR MIT
+/*
+ * Copyright 2026 Advanced Micro Devices, Inc.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
+ * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR
+ * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
+ * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
+ * OTHER DEALINGS IN THE SOFTWARE.
+ */
+
+#include <drm/drm_drv.h>
+
+#include "amdgpu.h"
+
+/*
+ * Profiler revision change log
+ *
+ * 1.0 - Initial revision
+ */
+
+#define AMDGPU_PROFILER_VERSION_MAJOR 1
+#define AMDGPU_PROFILER_VERSION_MINOR 0
+
+int amdgpu_profiler_ioctl(struct drm_device *dev,
+			  void *data,
+			  struct drm_file *filp)
+{
+	struct amdgpu_device *adev = drm_to_adev(dev);
+	struct amdgpu_fpriv *fpriv = filp->driver_priv;
+	struct amdgpu_profiler_mgr *prof_mgr = &adev->prof_mgr;
+	struct drm_amdgpu_profiler_args *args = data;
+	struct amdgpu_profiler_xcp_mgr *prof_xcp_mgr = fpriv->prof_xcp_mgr;
+	int ret = 0, idx;
+
+	if (args->pad)
+		return -EINVAL;
+
+	/* Reject clients that never took a profiler reference, i.e. never
+	 * successfully called amdgpu_profiler_mgr_init(). Without this an fd
+	 * that never initialized could ride on another client's XCP-0
+	 * reference and reach amdgpu_spm_ioctl().
+	 */
+	if (!prof_xcp_mgr)
+		return -EACCES;
+
+	/* Prevent ioctl from racing with device removal. drm_dev_enter()
+	 * fails once drm_dev_unplug() has been called, and drm_dev_unplug()
+	 * blocks until every in-flight drm_dev_enter() section (this ioctl
+	 * included) has exited. The torn_down flag, set before unplug, keeps
+	 * new ioctls from touching resources that are about to be released.
+	 */
+	if (!drm_dev_enter(dev, &idx))
+		return -ENODEV;
+
+	mutex_lock(&prof_mgr->mutex);
+	if (!prof_xcp_mgr->refcount || prof_xcp_mgr->torn_down) {
+		dev_dbg(adev->dev, "Profiler IOCTL op %u on xcp %u %s\n",
+			args->op, prof_xcp_mgr->xcp_id,
+			prof_xcp_mgr->torn_down ? "torn down" : "not initialized");
+		mutex_unlock(&prof_mgr->mutex);
+		ret = -ENODEV;
+		goto exit;
+	}
+	/*
+	 * Dispatch without prof_mgr->mutex: holding it here would let a
+	 * client-supplied SPM wait in amdgpu_spm_ioctl() stall every other
+	 * profiler fd. The fd's own reference keeps refcount >= 1 so a
+	 * concurrent close (amdgpu_profiler_mgr_fini) cannot release the
+	 * manager (and its spm_mgr) under us; device teardown is instead
+	 * excluded by the drm_dev_enter() section that drm_dev_unplug() drains.
+	 * The reference does not serialize spm_mgr mutation against
+	 * amdgpu_spm_mgr_release_owner() on another fd's close, so the SPM
+	 * layer serializes that itself by taking prof_xcp_mgr->mutex around
+	 * spm_mgr->file on both the acquire and the release/close paths.
+	 */
+	mutex_unlock(&prof_mgr->mutex);
+
+	switch (args->op) {
+	case AMDGPU_PROFILER_OP_GET_VER:
+		if (memchr_inv(&args->data, 0, sizeof(args->data))) {
+			ret = -EINVAL;
+		} else {
+			args->data.version = ((u32)AMDGPU_PROFILER_VERSION_MAJOR << 24) |
+					     (AMDGPU_PROFILER_VERSION_MINOR & GENMASK(23, 0));
+			ret = 0;
+		}
+		break;
+
+	case AMDGPU_PROFILER_OP_SPM:
+		ret = amdgpu_spm_ioctl(dev, &args->data.spm, filp);
+		break;
+
+	default:
+		dev_dbg(adev->dev, "Invalid profiler op: %u\n", args->op);
+		ret = -EINVAL;
+		break;
+	}
+
+exit:
+	drm_dev_exit(idx);
+	return ret;
+}
+
+void amdgpu_profiler_device_init(struct amdgpu_device *adev)
+{
+	struct amdgpu_profiler_mgr *prof_mgr = &adev->prof_mgr;
+	struct amdgpu_profiler_xcp_mgr *prof_xcp_mgr;
+	int xcp_id;
+
+	mutex_init(&prof_mgr->mutex);
+
+	/* Initialize adev, xcp_id, and the per-XCP mutex for all XCP managers
+	 * at device init. adev and xcp_id remain constant for the device
+	 * lifetime, eliminating the need for mutex protection when reading
+	 * them. Both these mutexes and prof_mgr->mutex are only destroyed by
+	 * amdgpu_profiler_device_sw_fini(), which runs after the last drm_file
+	 * is gone, so teardown paths (amdgpu_spm_mgr_release_owner() and
+	 * amdgpu_spm_mgr_fini()) can take them regardless of the fd refcount.
+	 */
+	for (xcp_id = 0; xcp_id < MAX_XCP; xcp_id++) {
+		prof_xcp_mgr = &prof_mgr->prof_xcp_mgr[xcp_id];
+		prof_xcp_mgr->adev = adev;
+		prof_xcp_mgr->xcp_id = xcp_id;
+		mutex_init(&prof_xcp_mgr->mutex);
+	}
+}
+
+void amdgpu_profiler_device_sw_fini(struct amdgpu_device *adev)
+{
+	struct amdgpu_profiler_mgr *prof_mgr = &adev->prof_mgr;
+	int xcp_id;
+
+	for (xcp_id = 0; xcp_id < MAX_XCP; xcp_id++)
+		mutex_destroy(&prof_mgr->prof_xcp_mgr[xcp_id].mutex);
+
+	mutex_destroy(&prof_mgr->mutex);
+}
+
+int amdgpu_profiler_mgr_init(struct amdgpu_device *adev,
+			     struct amdgpu_fpriv *fpriv)
+{
+	struct amdgpu_profiler_mgr *prof_mgr = &adev->prof_mgr;
+	struct amdgpu_profiler_xcp_mgr *prof_xcp_mgr;
+	u32 xcp_id;
+
+	/* On a partitioned device, reject clients with no partition
+	 * assigned (AMDGPU_XCP_NO_PARTITION): amdgpu_prof_xcp_id() maps
+	 * them to XCP 0, which would expose partition 0's performance
+	 * counters as a cross-partition side channel. Enforce isolation
+	 * here, since amdgpu_xcp_get_xcc_mask() returns the full device
+	 * mask for NO_PARTITION.
+	 */
+	if (fpriv->xcp_id == AMDGPU_XCP_NO_PARTITION &&
+	    adev->xcp_mgr && adev->xcp_mgr->mode != AMDGPU_XCP_MODE_NONE)
+		return -EINVAL;
+
+	/* fpriv->xcp_id is mutable (rewritten by amdgpu_xcp_select_scheds on
+	 * first submit), so the resolved manager is latched into
+	 * fpriv->prof_xcp_mgr below and close drops the refcount on that same
+	 * XCP.
+	 */
+	xcp_id = amdgpu_prof_xcp_id(fpriv->xcp_id);
+	if (xcp_id >= MAX_XCP || !adev->ddev.render)
+		return -ENODEV;
+
+	mutex_lock(&prof_mgr->mutex);
+
+	prof_xcp_mgr = &prof_mgr->prof_xcp_mgr[xcp_id];
+
+	/* Prevent initialization during device teardown */
+	if (prof_xcp_mgr->torn_down) {
+		mutex_unlock(&prof_mgr->mutex);
+		return -ENODEV;
+	}
+
+	if (!prof_xcp_mgr->refcount) {
+		/* First open - initialize everything */
+		prof_xcp_mgr->refcount = 1;
+		dev_dbg(adev->dev, "Initialize profiler on render %u\n",
+			adev->ddev.render->index);
+		amdgpu_spm_mgr_init(&prof_xcp_mgr->spm_mgr);
+	} else {
+		/* Subsequent opens - just increment refcount */
+		prof_xcp_mgr->refcount++;
+	}
+
+	/* Latch the reference. Only set on the success path, so release and
+	 * the profiler ioctl act only for clients that actually took one.
+	 */
+	fpriv->prof_xcp_mgr = prof_xcp_mgr;
+
+	mutex_unlock(&prof_mgr->mutex);
+	return 0;
+}
+
+static void amdgpu_profiler_xcp_mgr_release(struct amdgpu_profiler_xcp_mgr *prof_xcp_mgr)
+{
+	amdgpu_spm_mgr_fini(&prof_xcp_mgr->spm_mgr);
+}
+
+void amdgpu_profiler_mgr_fini(struct drm_file *filp)
+{
+	struct amdgpu_fpriv *fpriv = filp->driver_priv;
+	struct amdgpu_profiler_xcp_mgr *prof_xcp_mgr = fpriv->prof_xcp_mgr;
+	struct amdgpu_profiler_mgr *prof_mgr;
+
+	/* Only clients that successfully took a reference may drop one. fpriv
+	 * is kzalloc'd, so a client that failed or never called mgr_init has
+	 * this NULL and must not decrement any refcount.
+	 */
+	if (!prof_xcp_mgr)
+		return;
+
+	/* prof_xcp_mgr->adev is set at device init: after unplug
+	 * filp->minor->dev may point at a partition drm_device, so
+	 * drm_to_adev() would be bogus here.
+	 */
+	prof_mgr = &prof_xcp_mgr->adev->prof_mgr;
+
+	/* Release outside prof_mgr->mutex: the release path can block on
+	 * prof_xcp_mgr->mutex during another fd's acquire, and holding
+	 * prof_mgr->mutex there would stall all profiler ioctls. No-op unless
+	 * this fd owns the session.
+	 */
+	amdgpu_spm_mgr_release_owner(&prof_xcp_mgr->spm_mgr, filp);
+
+	mutex_lock(&prof_mgr->mutex);
+	/* Skip if device_fini already tore down this XCP manager */
+	if (!prof_xcp_mgr->torn_down) {
+		if (!WARN_ON(!prof_xcp_mgr->refcount) &&
+		    --prof_xcp_mgr->refcount == 0)
+			amdgpu_profiler_xcp_mgr_release(prof_xcp_mgr);
+	}
+	mutex_unlock(&prof_mgr->mutex);
+}
+
+void amdgpu_profiler_device_prepare_fini(struct amdgpu_device *adev)
+{
+	struct amdgpu_profiler_mgr *prof_mgr = &adev->prof_mgr;
+	struct amdgpu_profiler_xcp_mgr *prof_xcp_mgr;
+	int xcp_id;
+
+	/*
+	 * First stage of PCI-removal teardown, run *before* drm_dev_unplug().
+	 *
+	 * Mark every XCP torn down so no new ioctl proceeds. teardown_cb
+	 * provides the hook for waking a thread blocked in an SPM wait so its
+	 * ioctl can return promptly, but no callback is registered until a
+	 * later patch wires it up; until then this stage only sets torn_down.
+	 * drm_dev_unplug() then drains all in-flight profiler ioctls via SRCU
+	 * without stalling on a client-supplied SPM timeout. The actual
+	 * resource release happens afterwards in amdgpu_profiler_device_fini().
+	 */
+	mutex_lock(&prof_mgr->mutex);
+	for (xcp_id = 0; xcp_id < MAX_XCP; xcp_id++)
+		prof_mgr->prof_xcp_mgr[xcp_id].torn_down = true;
+
+	for (xcp_id = 0; xcp_id < MAX_XCP; xcp_id++) {
+		prof_xcp_mgr = &prof_mgr->prof_xcp_mgr[xcp_id];
+		if (prof_xcp_mgr->refcount > 0 && prof_xcp_mgr->teardown_cb)
+			prof_xcp_mgr->teardown_cb(prof_xcp_mgr);
+	}
+	mutex_unlock(&prof_mgr->mutex);
+}
+
+void amdgpu_profiler_device_fini(struct amdgpu_device *adev)
+{
+	struct amdgpu_profiler_mgr *prof_mgr = &adev->prof_mgr;
+	struct amdgpu_profiler_xcp_mgr *prof_xcp_mgr;
+	int xcp_id;
+
+	/*
+	 * Second stage of PCI-removal teardown, run *after* drm_dev_unplug().
+	 *
+	 * drm_dev_unplug() has already drained every in-flight profiler ioctl
+	 * via SRCU, so nothing can be running here and no active-ioctl drain is
+	 * needed. torn_down was set in amdgpu_profiler_device_prepare_fini().
+	 * Release the HW/SPM resources of any XCP that still holds a session;
+	 * the device is still live (this runs before amdgpu_driver_unload_kms()).
+	 */
+	mutex_lock(&prof_mgr->mutex);
+	for (xcp_id = 0; xcp_id < MAX_XCP; xcp_id++) {
+		prof_xcp_mgr = &prof_mgr->prof_xcp_mgr[xcp_id];
+		if (prof_xcp_mgr->refcount > 0) {
+			amdgpu_profiler_xcp_mgr_release(prof_xcp_mgr);
+			prof_xcp_mgr->refcount = 0;
+		}
+	}
+	mutex_unlock(&prof_mgr->mutex);
+}
diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_profiler.h b/drivers/gpu/drm/amd/amdgpu/amdgpu_profiler.h
new file mode 100644
index 000000000000..a220f05c9512
--- /dev/null
+++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_profiler.h
@@ -0,0 +1,92 @@
+/* SPDX-License-Identifier: GPL-2.0 OR MIT */
+/*
+ * Copyright 2026 Advanced Micro Devices, Inc.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
+ * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR
+ * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
+ * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
+ * OTHER DEALINGS IN THE SOFTWARE.
+ *
+ */
+
+#ifndef AMDGPU_PROFILER_H_
+#define AMDGPU_PROFILER_H_
+
+#include <linux/mutex.h>
+
+#include "amdgpu_xcp.h"
+#include "amdgpu_spm.h"
+
+/* Map XCP ID to profiler array index.
+ * AMDGPU_XCP_NO_PARTITION maps to 0. On a partitioned device the SPM
+ * consumer rejects NO_PARTITION before this mapping (see
+ * amdgpu_profiler_mgr_init()), so mapping to 0 only applies to
+ * non-partitioned systems, which legitimately use XCP 0.
+ */
+static inline u32 amdgpu_prof_xcp_id(u32 xcp_id)
+{
+	return xcp_id == AMDGPU_XCP_NO_PARTITION ? 0 : xcp_id;
+}
+
+/*
+ * y is the member name within amdgpu_profiler_xcp_mgr (e.g., spm_mgr)
+ */
+#define to_prof_xcp_mgr(x, y) \
+	container_of(x, struct amdgpu_profiler_xcp_mgr, y)
+
+struct amdgpu_profiler_xcp_mgr {
+	/* track multiple file opens (protected by prof_mgr->mutex) */
+	unsigned int                   refcount;
+	/* back-pointer to device */
+	struct amdgpu_device           *adev;
+	/* protect xcp_mgr shared resources */
+	struct mutex                   mutex;
+	u32                            xcp_id;
+	/* device removal in progress */
+	bool                           torn_down;
+	/* Called during device teardown (before drm_dev_unplug()) to wake
+	 * threads blocked in SPM waits so their ioctls can exit.
+	 * IMPORTANT: Invoked while holding prof_mgr->mutex.
+	 * Callback MUST NOT attempt to acquire prof_mgr->mutex to avoid deadlock.
+	 */
+	void (*teardown_cb)(struct amdgpu_profiler_xcp_mgr *prof_xcp_mgr);
+
+	/*
+	 * Union scaffolding for future profiler sub-managers (PC, SPM2, etc.).
+	 * Currently only SPM, but designed for extensibility.
+	 */
+	union {
+		struct amdgpu_spm_mgr      spm_mgr;
+	};
+};
+
+struct amdgpu_profiler_mgr {
+	/* protect profiler manager share resource */
+	struct mutex                   mutex;
+	struct amdgpu_profiler_xcp_mgr prof_xcp_mgr[MAX_XCP];
+};
+
+int amdgpu_profiler_ioctl(struct drm_device *dev, void *data,
+			  struct drm_file *filp);
+void amdgpu_profiler_device_init(struct amdgpu_device *adev);
+void amdgpu_profiler_device_sw_fini(struct amdgpu_device *adev);
+int amdgpu_profiler_mgr_init(struct amdgpu_device *adev,
+			     struct amdgpu_fpriv *fpriv);
+void amdgpu_profiler_mgr_fini(struct drm_file *filp);
+void amdgpu_profiler_device_prepare_fini(struct amdgpu_device *adev);
+void amdgpu_profiler_device_fini(struct amdgpu_device *adev);
+
+#endif /* AMDGPU_PROFILER_H_ */
diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_spm.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_spm.c
new file mode 100644
index 000000000000..06747dd22b85
--- /dev/null
+++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_spm.c
@@ -0,0 +1,98 @@
+// SPDX-License-Identifier: GPL-2.0 OR MIT
+/*
+ * Copyright 2026 Advanced Micro Devices, Inc.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
+ * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR
+ * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
+ * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
+ * OTHER DEALINGS IN THE SOFTWARE.
+ */
+
+#include "amdgpu.h"
+
+/* Check if the calling file owns the SPM session */
+static bool amdgpu_spm_is_owner(struct amdgpu_spm_mgr *spm_mgr, struct drm_file *filp)
+{
+	return spm_mgr->file == filp;
+}
+
+int amdgpu_spm_ioctl(struct drm_device *dev, struct drm_amdgpu_spm_args *args,
+		     struct drm_file *filp)
+{
+	if (memchr_inv(args->reserved, 0, sizeof(args->reserved)))
+		return -EINVAL;
+
+	switch (args->op) {
+	case AMDGPU_SPM_OP_ACQUIRE:
+		/* Implemented in a later patch */
+		return -EOPNOTSUPP;
+
+	case AMDGPU_SPM_OP_RELEASE:
+		/* Implemented in a later patch */
+		return -EOPNOTSUPP;
+
+	case AMDGPU_SPM_OP_SET_DEST_BUF:
+		/* Implemented in a later patch */
+		return -EOPNOTSUPP;
+
+	default:
+		return -EINVAL;
+	}
+}
+
+static void amdgpu_spm_init_device(struct amdgpu_spm_mgr *spm_mgr)
+{
+	/* TODO */
+}
+
+static int amdgpu_spm_release(struct amdgpu_spm_mgr *spm_mgr, struct drm_file *filp)
+{
+	struct amdgpu_profiler_xcp_mgr *prof_xcp_mgr = to_prof_xcp_mgr(spm_mgr, spm_mgr);
+
+	/* Full teardown lands with AMDGPU_SPM_OP_RELEASE. Re-check ownership
+	 * under the mutex so a close and a concurrent device teardown cannot
+	 * both release the same session.
+	 */
+	mutex_lock(&prof_xcp_mgr->mutex);
+	if (!spm_mgr->file) {
+		mutex_unlock(&prof_xcp_mgr->mutex);
+		return 0;
+	}
+	if (filp && !amdgpu_spm_is_owner(spm_mgr, filp)) {
+		mutex_unlock(&prof_xcp_mgr->mutex);
+		return -EPERM;
+	}
+	spm_mgr->file = NULL;
+	mutex_unlock(&prof_xcp_mgr->mutex);
+
+	return 0;
+}
+
+void amdgpu_spm_mgr_init(struct amdgpu_spm_mgr *spm_mgr)
+{
+	amdgpu_spm_init_device(spm_mgr);
+}
+
+void amdgpu_spm_mgr_release_owner(struct amdgpu_spm_mgr *spm_mgr,
+				  struct drm_file *filp)
+{
+	amdgpu_spm_release(spm_mgr, filp);
+}
+
+void amdgpu_spm_mgr_fini(struct amdgpu_spm_mgr *spm_mgr)
+{
+	amdgpu_spm_release(spm_mgr, NULL);
+}
diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_spm.h b/drivers/gpu/drm/amd/amdgpu/amdgpu_spm.h
new file mode 100644
index 000000000000..59fa641ebb86
--- /dev/null
+++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_spm.h
@@ -0,0 +1,43 @@
+/* SPDX-License-Identifier: GPL-2.0 OR MIT */
+/*
+ * Copyright 2026 Advanced Micro Devices, Inc.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
+ * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR
+ * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
+ * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
+ * OTHER DEALINGS IN THE SOFTWARE.
+ */
+
+#ifndef AMDGPU_SPM_H_
+#define AMDGPU_SPM_H_
+
+struct drm_device;
+struct drm_file;
+struct drm_amdgpu_spm_args;
+
+struct amdgpu_spm_mgr {
+	struct drm_file *file;
+};
+
+int amdgpu_spm_ioctl(struct drm_device *dev, struct drm_amdgpu_spm_args *args,
+		     struct drm_file *filp);
+
+void amdgpu_spm_mgr_init(struct amdgpu_spm_mgr *spm_mgr);
+void amdgpu_spm_mgr_fini(struct amdgpu_spm_mgr *spm_mgr);
+void amdgpu_spm_mgr_release_owner(struct amdgpu_spm_mgr *spm_mgr,
+				  struct drm_file *filp);
+
+#endif
-- 
2.34.1


  reply	other threads:[~2026-09-21 20:03 UTC|newest]

Thread overview: 35+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2026-09-21 20:03 [PATCH 01/12] drm/amdgpu: add profiler UAPI definitions James Zhu
2026-09-21 20:03 ` James Zhu [this message]
2026-09-21 20:03 ` [PATCH 03/12] drm/amdgpu: add generic RLC SPM interface layer James Zhu
2026-09-21 20:03 ` [PATCH 04/12] drm/amdgpu: add amdgpu_xcp_get_xcc_mask helper James Zhu
2026-09-22  5:22   ` Lazar, Lijo
2026-09-22 13:35     ` James Zhu
2026-09-22 13:45       ` Lazar, Lijo
2026-09-22 14:04         ` James Zhu
2026-09-22 14:11         ` James Zhu
2026-09-22 14:26           ` Lazar, Lijo
2026-09-22 15:10             ` James Zhu
2026-09-23  3:39               ` Lazar, Lijo
2026-09-23 12:36                 ` James Zhu
2026-09-23 14:55                   ` Lazar, Lijo
2026-09-23 15:08                     ` James Zhu
2026-09-21 20:03 ` [PATCH 05/12] drm/amdgpu: add profiler/spm operation AMDGPU_SPM_OP_ACQUIRE James Zhu
2026-09-21 20:03 ` [PATCH 06/12] drm/amdgpu: add profiler/spm operation AMDGPU_SPM_OP_SET_DEST_BUF James Zhu
2026-09-21 20:03 ` [PATCH 07/12] drm/amdgpu: add profiler/spm operation AMDGPU_SPM_OP_RELEASE James Zhu
2026-09-21 20:03 ` [PATCH 08/12] drm/amdgpu: implement data dump from spm ring buffer James Zhu
2026-09-21 20:03 ` [PATCH 09/12] drm/amdgpu: workaround for spm ring buffer overflow James Zhu
2026-09-21 20:03 ` [PATCH 10/12] drm/amdgpu: add SPM ring-buffer polling thread for pre-GFX12 James Zhu
2026-09-21 20:03 ` [PATCH 11/12] drm/amdgpu: add profiler/spm support for gfx12_0 James Zhu
2026-09-21 20:03 ` [PATCH 12/12] drm/amdgpu: bump KMS driver version to 3.65 for profiler UAPI James Zhu
2026-09-22 15:09 ` [PATCH 01/12] drm/amdgpu: add profiler UAPI definitions Timur Kristóf
2026-09-22 15:20   ` James Zhu
2026-09-22 15:22     ` Timur Kristóf
2026-09-22 15:32       ` James Zhu
2026-09-22 15:34         ` Timur Kristóf
2026-09-22 15:40       ` Alex Deucher
2026-09-22 15:43         ` Christian König
2026-09-23  1:20           ` Ma, Bing
2026-09-23  7:47             ` Christian König
2026-09-24 12:33               ` Ma, Bing
2026-09-22 15:13 ` Christian König
2026-09-22 15:29   ` James Zhu

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=20260921200313.865829-2-James.Zhu@amd.com \
    --to=james.zhu@amd.com \
    --cc=Bing.Ma@amd.com \
    --cc=alexander.deucher@amd.com \
    --cc=amd-gfx@lists.freedesktop.org \
    --cc=jamesz@amd.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.