mirror of https://lore.kernel.org/lkml/
 help / color / mirror / Atom feed
From: Hamin Sung <hamin@saltyming.net>
To: Lyude Paul <lyude@redhat.com>, Danilo Krummrich <dakr@kernel.org>
Cc: nouveau@lists.freedesktop.org, dri-devel@lists.freedesktop.org,
	Maarten Lankhorst <maarten.lankhorst@linux.intel.com>,
	Maxime Ripard <mripard@kernel.org>,
	Thomas Zimmermann <tzimmermann@suse.de>,
	linux-kernel@vger.kernel.org, David Airlie <airlied@gmail.com>,
	Simona Vetter <simona@ffwll.ch>,
	Aaron Kling <webgeek1234@gmail.com>,
	Hamin Sung <hamin@saltyming.net>
Subject: [RFC PATCH 1/2] drm/nouveau/pmu/gt215: add graphics engine load counters
Date: Sun,  4 Oct 2026 08:45:20 +0900	[thread overview]
Message-ID: <20261003234520.69573-1-hamin@saltyming.net> (raw)
In-Reply-To: <20261003223420.77993-1-hamin@saltyming.net>

The PDAEMON in GT215, GT216, GT218 and MCP89 has idle counters that
count PMU clock cycles depending on the state of a selected set of
engine idle signals.  Nothing in nouveau uses them on these GPUs;
gk20a_devfreq.c drives the same counter block on Tegra.

Add nvkm_pmu_perfmon_init() and nvkm_pmu_perfmon_read() and implement
them for these GPUs: one counter counts every cycle, a second one the
cycles during which the graphics engine is not idle, and reading returns
and clears both.  The counters are only programmed once
nvkm_pmu_perfmon_init() is called, so nothing changes for existing
users.

The next patch uses them to select performance levels through devfreq.

Link: https://envytools.readthedocs.io/en/latest/hw/pm/pdaemon/counter.html
Assisted-by: Claude:claude-opus-5-5 sparse # max effort
Assisted-by: Claude:claude-fable-5-1 # max effort, review
Signed-off-by: Hamin Sung <hamin@saltyming.net>
---
Sorry for the duplicate copies of the cover letter, and of the two
nouveau fixes I sent with it: my mail server delivered each of them
twice to most recipients.

 .../gpu/drm/nouveau/include/nvkm/subdev/pmu.h |  2 +
 .../gpu/drm/nouveau/nvkm/subdev/pmu/base.c    | 29 ++++++++++++++
 .../gpu/drm/nouveau/nvkm/subdev/pmu/gt215.c   | 40 +++++++++++++++++++
 .../gpu/drm/nouveau/nvkm/subdev/pmu/priv.h    |  5 +++
 4 files changed, 76 insertions(+)

diff --git a/drivers/gpu/drm/nouveau/include/nvkm/subdev/pmu.h b/drivers/gpu/drm/nouveau/include/nvkm/subdev/pmu.h
index f57a3a5a288d..de844e69a5e6 100644
--- a/drivers/gpu/drm/nouveau/include/nvkm/subdev/pmu.h
+++ b/drivers/gpu/drm/nouveau/include/nvkm/subdev/pmu.h
@@ -39,6 +39,8 @@ int nvkm_pmu_send(struct nvkm_pmu *, u32 reply[2], u32 process,
 		  u32 message, u32 data0, u32 data1);
 void nvkm_pmu_pgob(struct nvkm_pmu *, bool enable);
 bool nvkm_pmu_fan_controlled(struct nvkm_device *);
+int nvkm_pmu_perfmon_init(struct nvkm_pmu *pmu);
+int nvkm_pmu_perfmon_read(struct nvkm_pmu *pmu, u32 *busy, u32 *total);
 
 int gt215_pmu_new(struct nvkm_device *, enum nvkm_subdev_type, int inst, struct nvkm_pmu **);
 int gf100_pmu_new(struct nvkm_device *, enum nvkm_subdev_type, int inst, struct nvkm_pmu **);
diff --git a/drivers/gpu/drm/nouveau/nvkm/subdev/pmu/base.c b/drivers/gpu/drm/nouveau/nvkm/subdev/pmu/base.c
index e556b1905702..fb51db6a2ca3 100644
--- a/drivers/gpu/drm/nouveau/nvkm/subdev/pmu/base.c
+++ b/drivers/gpu/drm/nouveau/nvkm/subdev/pmu/base.c
@@ -51,6 +51,35 @@ nvkm_pmu_pgob(struct nvkm_pmu *pmu, bool enable)
 		pmu->func->pgob(pmu, enable);
 }
 
+/*
+ * Set up the PMU counters that nvkm_pmu_perfmon_read() samples.  PMU
+ * initialisation resets the PMU, so this has to be repeated after resume.
+ */
+int
+nvkm_pmu_perfmon_init(struct nvkm_pmu *pmu)
+{
+	if (!pmu || !pmu->func->perfmon.init)
+		return -ENODEV;
+
+	pmu->func->perfmon.init(pmu);
+	return 0;
+}
+
+/*
+ * Return the number of PMU clock cycles that passed, and how many of them the
+ * graphics engine was busy for, since the previous call or since
+ * nvkm_pmu_perfmon_init(), and restart counting.
+ */
+int
+nvkm_pmu_perfmon_read(struct nvkm_pmu *pmu, u32 *busy, u32 *total)
+{
+	if (!pmu || !pmu->func->perfmon.read)
+		return -ENODEV;
+
+	pmu->func->perfmon.read(pmu, busy, total);
+	return 0;
+}
+
 static void
 nvkm_pmu_recv(struct work_struct *work)
 {
diff --git a/drivers/gpu/drm/nouveau/nvkm/subdev/pmu/gt215.c b/drivers/gpu/drm/nouveau/nvkm/subdev/pmu/gt215.c
index 32cee21ed858..37310a8ebe81 100644
--- a/drivers/gpu/drm/nouveau/nvkm/subdev/pmu/gt215.c
+++ b/drivers/gpu/drm/nouveau/nvkm/subdev/pmu/gt215.c
@@ -260,6 +260,44 @@ gt215_pmu_init(struct nvkm_pmu *pmu)
 	return 0;
 }
 
+/*
+ * PDAEMON idle counters.  Each one has a mask of engine idle signals at
+ * 0x10a504, a cycle count at 0x10a508 (bit 31 clears it) and a mode at
+ * 0x10a50c: bit 0 counts cycles in which all masked signals are set, bit 1
+ * cycles in which they are all clear, and both together count every cycle.
+ * Idle signal bit 0 is the graphics engine.
+ */
+#define GT215_PMU_COUNTER_TOTAL 0
+#define GT215_PMU_COUNTER_GR    1
+
+static void
+gt215_pmu_perfmon_init(struct nvkm_pmu *pmu)
+{
+	struct nvkm_device *device = pmu->subdev.device;
+
+	nvkm_wr32(device, 0x10a504 + GT215_PMU_COUNTER_TOTAL * 0x10, 0x00000000);
+	nvkm_wr32(device, 0x10a50c + GT215_PMU_COUNTER_TOTAL * 0x10, 0x00000003);
+	nvkm_wr32(device, 0x10a508 + GT215_PMU_COUNTER_TOTAL * 0x10, 0x80000000);
+
+	nvkm_wr32(device, 0x10a504 + GT215_PMU_COUNTER_GR * 0x10, 0x00000001);
+	nvkm_wr32(device, 0x10a50c + GT215_PMU_COUNTER_GR * 0x10, 0x00000002);
+	nvkm_wr32(device, 0x10a508 + GT215_PMU_COUNTER_GR * 0x10, 0x80000000);
+}
+
+static void
+gt215_pmu_perfmon_read(struct nvkm_pmu *pmu, u32 *busy, u32 *total)
+{
+	struct nvkm_device *device = pmu->subdev.device;
+
+	*busy = nvkm_rd32(device, 0x10a508 + GT215_PMU_COUNTER_GR * 0x10);
+	*total = nvkm_rd32(device, 0x10a508 + GT215_PMU_COUNTER_TOTAL * 0x10);
+	nvkm_wr32(device, 0x10a508 + GT215_PMU_COUNTER_GR * 0x10, 0x80000000);
+	nvkm_wr32(device, 0x10a508 + GT215_PMU_COUNTER_TOTAL * 0x10, 0x80000000);
+
+	*busy &= 0x7fffffff;
+	*total &= 0x7fffffff;
+}
+
 const struct nvkm_falcon_func
 gt215_pmu_flcn = {
 };
@@ -278,6 +316,8 @@ gt215_pmu = {
 	.intr = gt215_pmu_intr,
 	.send = gt215_pmu_send,
 	.recv = gt215_pmu_recv,
+	.perfmon.init = gt215_pmu_perfmon_init,
+	.perfmon.read = gt215_pmu_perfmon_read,
 };
 
 static const struct nvkm_pmu_fwif
diff --git a/drivers/gpu/drm/nouveau/nvkm/subdev/pmu/priv.h b/drivers/gpu/drm/nouveau/nvkm/subdev/pmu/priv.h
index 2d0a8fa6f196..880a7785589a 100644
--- a/drivers/gpu/drm/nouveau/nvkm/subdev/pmu/priv.h
+++ b/drivers/gpu/drm/nouveau/nvkm/subdev/pmu/priv.h
@@ -30,6 +30,11 @@ struct nvkm_pmu_func {
 	void (*recv)(struct nvkm_pmu *);
 	int (*initmsg)(struct nvkm_pmu *);
 	void (*pgob)(struct nvkm_pmu *, bool);
+
+	struct {
+		void (*init)(struct nvkm_pmu *pmu);
+		void (*read)(struct nvkm_pmu *pmu, u32 *busy, u32 *total);
+	} perfmon;
 };
 
 extern const struct nvkm_falcon_func gt215_pmu_flcn;
-- 
2.55.0



  reply	other threads:[~2026-10-03 23:46 UTC|newest]

Thread overview: 4+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2026-10-03 22:34 [RFC PATCH 0/2] drm/nouveau: select GT21x performance levels by load through devfreq Hamin Sung
2026-10-03 23:45 ` Hamin Sung [this message]
2026-10-03 23:45 ` [RFC PATCH 2/2] " Hamin Sung
2026-10-03 23:50 ` [RFC PATCH 0/2] " Lyude Paul

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=20261003234520.69573-1-hamin@saltyming.net \
    --to=hamin@saltyming.net \
    --cc=airlied@gmail.com \
    --cc=dakr@kernel.org \
    --cc=dri-devel@lists.freedesktop.org \
    --cc=linux-kernel@vger.kernel.org \
    --cc=lyude@redhat.com \
    --cc=maarten.lankhorst@linux.intel.com \
    --cc=mripard@kernel.org \
    --cc=nouveau@lists.freedesktop.org \
    --cc=simona@ffwll.ch \
    --cc=tzimmermann@suse.de \
    --cc=webgeek1234@gmail.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

all inboxes | Powered by JetHome®