devicetree.vger.kernel.org archive mirror
 help / color / mirror / Atom feed
* [PATCH v1 0/5] Support host1x actmon
@ 2024-12-10 17:45 Johnny Liu
  2024-12-10 17:45 ` [PATCH v1 1/5] dt-bindings: display: tegra: Add actmon information Johnny Liu
                   ` (5 more replies)
  0 siblings, 6 replies; 16+ messages in thread
From: Johnny Liu @ 2024-12-10 17:45 UTC (permalink / raw)
  To: thierry.reding, jonathanh, skomatineni, luca.ceresoli, mperttunen,
	maarten.lankhorst, mripard, tzimmermann, airlied, simona, robh,
	krzk+dt, conor+dt
  Cc: linux-media, linux-tegra, dri-devel, devicetree, linux-kernel,
	Johnny Liu

Activity monitoring (actmon for short) is a means to dynamically
measure the utilization of units in the system to help drive software
power management policies.

In Tegra, Dynamic Voltage and Frequency Scaling (DVFS) is the primary
dynamic power management mechanism. It uses utilization information
from various units to select the most efficient frequency and thereby,
voltage that the unit should operate while providing the requisite
performance.

Johnny Liu (5):
  dt-bindings: display: tegra: Add actmon information
  arm64: tegra: Add actmon information
  gpu: host1x: Support device monitoring with actmon
  drm/tegra: nvdec: Register the device with actmon
  drm/tegra: vic: Register the device with actmon

 .../display/tegra/nvidia,tegra20-host1x.yaml  |  45 +-
 arch/arm64/boot/dts/nvidia/tegra234.dtsi      |  10 +-
 drivers/gpu/drm/tegra/nvdec.c                 |  82 ++-
 drivers/gpu/drm/tegra/vic.c                   |  39 +-
 drivers/gpu/drm/tegra/vic.h                   |   9 +
 drivers/gpu/host1x/Makefile                   |   1 +
 drivers/gpu/host1x/actmon.c                   | 558 ++++++++++++++++++
 drivers/gpu/host1x/actmon.h                   |  46 ++
 drivers/gpu/host1x/dev.c                      |  71 ++-
 drivers/gpu/host1x/dev.h                      |  59 +-
 drivers/gpu/host1x/hw/actmon.h                |  49 ++
 drivers/gpu/host1x/hw/host1x08.c              |   6 +-
 drivers/gpu/host1x/hw/hw_host1x08_common.h    |  16 +-
 drivers/gpu/host1x/hw/intr_general_hw.c       |  83 +++
 include/linux/host1x.h                        |  30 +-
 15 files changed, 1075 insertions(+), 29 deletions(-)
 create mode 100644 drivers/gpu/host1x/actmon.c
 create mode 100644 drivers/gpu/host1x/actmon.h
 create mode 100644 drivers/gpu/host1x/hw/actmon.h
 create mode 100644 drivers/gpu/host1x/hw/intr_general_hw.c

-- 
2.34.1


^ permalink raw reply	[flat|nested] 16+ messages in thread

* [PATCH v1 1/5] dt-bindings: display: tegra: Add actmon information
  2024-12-10 17:45 [PATCH v1 0/5] Support host1x actmon Johnny Liu
@ 2024-12-10 17:45 ` Johnny Liu
  2024-12-13 10:44   ` Krzysztof Kozlowski
  2024-12-10 17:45 ` [PATCH v1 2/5] arm64: " Johnny Liu
                   ` (4 subsequent siblings)
  5 siblings, 1 reply; 16+ messages in thread
From: Johnny Liu @ 2024-12-10 17:45 UTC (permalink / raw)
  To: thierry.reding, jonathanh, skomatineni, luca.ceresoli, mperttunen,
	maarten.lankhorst, mripard, tzimmermann, airlied, simona, robh,
	krzk+dt, conor+dt
  Cc: linux-media, linux-tegra, dri-devel, devicetree, linux-kernel,
	Johnny Liu

An activity monitor (actmon) is used to measure the device runtime
utilization to help drive software power management policies.

Extend the reg space to include actmon aperture for actmon configuration
through host1x.

Extend the number of clocks to include actmon clock, which is shared
between unit actmons for different host1x clients.

Signed-off-by: Johnny Liu <johnliu@nvidia.com>
---
 .../display/tegra/nvidia,tegra20-host1x.yaml  | 45 ++++++++++++++++---
 1 file changed, 39 insertions(+), 6 deletions(-)

diff --git a/Documentation/devicetree/bindings/display/tegra/nvidia,tegra20-host1x.yaml b/Documentation/devicetree/bindings/display/tegra/nvidia,tegra20-host1x.yaml
index 3563378a01af4..46e1d27ddef8b 100644
--- a/Documentation/devicetree/bindings/display/tegra/nvidia,tegra20-host1x.yaml
+++ b/Documentation/devicetree/bindings/display/tegra/nvidia,tegra20-host1x.yaml
@@ -32,11 +32,11 @@ properties:
 
   reg:
     minItems: 1
-    maxItems: 3
+    maxItems: 4
 
   reg-names:
     minItems: 1
-    maxItems: 3
+    maxItems: 4
 
   interrupts:
     minItems: 1
@@ -60,12 +60,12 @@ properties:
     maxItems: 1
 
   clocks:
-    description: Must contain one entry, for the module clock. See
-      ../clocks/clock-bindings.txt for details.
+    minItems: 1
+    maxItems: 2
 
   clock-names:
-    items:
-      - const: host1x
+    minItems: 1
+    maxItems: 2
 
   resets:
     minItems: 1 # MC reset is optional on Tegra186 and later
@@ -132,6 +132,15 @@ allOf:
           items:
             - const: syncpt
             - const: host1x
+
+        clocks:
+          items:
+            - description: host1x clock
+
+        clock-names:
+          items:
+            - const: host1x
+
       required:
         - resets
         - reset-names
@@ -170,6 +179,14 @@ allOf:
             - const: syncpt
             - const: host1x
 
+        clocks:
+          items:
+            - description: host1x clock
+
+        clock-names:
+          items:
+            - const: host1x
+
         iommu-map:
           description: Specification of stream IDs available for memory context device
             use. Should be a mapping of IDs 0..n to IOMMU entries corresponding to
@@ -195,16 +212,20 @@ allOf:
     then:
       properties:
         reg-names:
+          minItems: 3
           items:
             - const: common
             - const: hypervisor
             - const: vm
+            - const: actmon
 
         reg:
+          minItems: 3
           items:
             - description: region used by host1x server
             - description: region used by the hypervisor
             - description: region assigned to the virtual machine
+            - description: region used for configuring actmon for host1x clients
 
         interrupts:
           items:
@@ -230,6 +251,18 @@ allOf:
             - const: syncpt7
             - const: host1x
 
+        clocks:
+          minItems: 1
+          items:
+            - description: host1x clock
+            - description: actmon clock
+
+        clock-names:
+          minItems: 1
+          items:
+            - const: host1x
+            - const: actmon
+
         iommu-map:
           description: Specification of stream IDs available for memory context device
             use. Should be a mapping of IDs 0..n to IOMMU entries corresponding to
-- 
2.34.1


^ permalink raw reply related	[flat|nested] 16+ messages in thread

* [PATCH v1 2/5] arm64: tegra: Add actmon information
  2024-12-10 17:45 [PATCH v1 0/5] Support host1x actmon Johnny Liu
  2024-12-10 17:45 ` [PATCH v1 1/5] dt-bindings: display: tegra: Add actmon information Johnny Liu
@ 2024-12-10 17:45 ` Johnny Liu
  2024-12-10 17:45 ` [PATCH v1 3/5] gpu: host1x: Support device monitoring with actmon Johnny Liu
                   ` (3 subsequent siblings)
  5 siblings, 0 replies; 16+ messages in thread
From: Johnny Liu @ 2024-12-10 17:45 UTC (permalink / raw)
  To: thierry.reding, jonathanh, skomatineni, luca.ceresoli, mperttunen,
	maarten.lankhorst, mripard, tzimmermann, airlied, simona, robh,
	krzk+dt, conor+dt
  Cc: linux-media, linux-tegra, dri-devel, devicetree, linux-kernel,
	Johnny Liu

An activity monitor (actmon) is used to measure the device runtime
utilization to help drive software power management policies.

Configuration of actmon is under the host1x address space. Therefore,
add the actmon aperture under the host1x.

All unit actmons for host1x clients share the same actmon clock source
from host1x. Therefore, add the clock phandle in host1x.

Signed-off-by: Johnny Liu <johnliu@nvidia.com>
---
 arch/arm64/boot/dts/nvidia/tegra234.dtsi | 10 ++++++----
 1 file changed, 6 insertions(+), 4 deletions(-)

diff --git a/arch/arm64/boot/dts/nvidia/tegra234.dtsi b/arch/arm64/boot/dts/nvidia/tegra234.dtsi
index 984c85eab41af..8faeef83d7596 100644
--- a/arch/arm64/boot/dts/nvidia/tegra234.dtsi
+++ b/arch/arm64/boot/dts/nvidia/tegra234.dtsi
@@ -4313,8 +4313,9 @@ host1x@13e00000 {
 			compatible = "nvidia,tegra234-host1x";
 			reg = <0x0 0x13e00000 0x0 0x10000>,
 			      <0x0 0x13e10000 0x0 0x10000>,
-			      <0x0 0x13e40000 0x0 0x10000>;
-			reg-names = "common", "hypervisor", "vm";
+			      <0x0 0x13e40000 0x0 0x10000>,
+			      <0x0 0x13ef0000 0x0 0x60000>;
+			reg-names = "common", "hypervisor", "vm", "actmon";
 			interrupts = <GIC_SPI 448 IRQ_TYPE_LEVEL_HIGH>,
 				     <GIC_SPI 449 IRQ_TYPE_LEVEL_HIGH>,
 				     <GIC_SPI 450 IRQ_TYPE_LEVEL_HIGH>,
@@ -4326,8 +4327,9 @@ host1x@13e00000 {
 				     <GIC_SPI 263 IRQ_TYPE_LEVEL_HIGH>;
 			interrupt-names = "syncpt0", "syncpt1", "syncpt2", "syncpt3", "syncpt4",
 					  "syncpt5", "syncpt6", "syncpt7", "host1x";
-			clocks = <&bpmp TEGRA234_CLK_HOST1X>;
-			clock-names = "host1x";
+			clocks = <&bpmp TEGRA234_CLK_HOST1X>,
+				 <&bpmp TEGRA234_CLK_ACTMON>;
+			clock-names = "host1x", "actmon";
 
 			#address-cells = <2>;
 			#size-cells = <2>;
-- 
2.34.1


^ permalink raw reply related	[flat|nested] 16+ messages in thread

* [PATCH v1 3/5] gpu: host1x: Support device monitoring with actmon
  2024-12-10 17:45 [PATCH v1 0/5] Support host1x actmon Johnny Liu
  2024-12-10 17:45 ` [PATCH v1 1/5] dt-bindings: display: tegra: Add actmon information Johnny Liu
  2024-12-10 17:45 ` [PATCH v1 2/5] arm64: " Johnny Liu
@ 2024-12-10 17:45 ` Johnny Liu
  2024-12-17  5:39   ` Krzysztof Kozlowski
  2024-12-10 17:45 ` [PATCH v1 4/5] drm/tegra: nvdec: Register the device " Johnny Liu
                   ` (2 subsequent siblings)
  5 siblings, 1 reply; 16+ messages in thread
From: Johnny Liu @ 2024-12-10 17:45 UTC (permalink / raw)
  To: thierry.reding, jonathanh, skomatineni, luca.ceresoli, mperttunen,
	maarten.lankhorst, mripard, tzimmermann, airlied, simona, robh,
	krzk+dt, conor+dt
  Cc: linux-media, linux-tegra, dri-devel, devicetree, linux-kernel,
	Johnny Liu

An activity monitor (actmon) is used to measure the device runtime
utilization to help drive software power management policies, such as
device dynamic frequency scaling.

For every host1x client, an actmon is employed to monitor its runtime
utilization. Upon detecting an actmon watermark breach against the
sampled runtime utilization value, it will trigger an interrupt to
the host1x subsystem to trigger device dynamic frequency scaling if
supported by the client.

Upon registration with actmon within the host1x subsystem, a host1x
client gains the ability to activate/deactivate its own actmon
during the device resume/suspend cycle. This ensures that a host1x
client runs at the power-optimal frequency when active, while also
preventing unnecessary actmon interrupts during periods of inactivity.

Signed-off-by: Johnny Liu <johnliu@nvidia.com>
---
 drivers/gpu/host1x/Makefile                |   1 +
 drivers/gpu/host1x/actmon.c                | 558 +++++++++++++++++++++
 drivers/gpu/host1x/actmon.h                |  46 ++
 drivers/gpu/host1x/dev.c                   |  71 ++-
 drivers/gpu/host1x/dev.h                   |  59 ++-
 drivers/gpu/host1x/hw/actmon.h             |  49 ++
 drivers/gpu/host1x/hw/host1x08.c           |   6 +-
 drivers/gpu/host1x/hw/hw_host1x08_common.h |  16 +-
 drivers/gpu/host1x/hw/intr_general_hw.c    |  83 +++
 include/linux/host1x.h                     |  30 +-
 10 files changed, 903 insertions(+), 16 deletions(-)
 create mode 100644 drivers/gpu/host1x/actmon.c
 create mode 100644 drivers/gpu/host1x/actmon.h
 create mode 100644 drivers/gpu/host1x/hw/actmon.h
 create mode 100644 drivers/gpu/host1x/hw/intr_general_hw.c

diff --git a/drivers/gpu/host1x/Makefile b/drivers/gpu/host1x/Makefile
index ee5286ffe08d5..230afea0f2aa5 100644
--- a/drivers/gpu/host1x/Makefile
+++ b/drivers/gpu/host1x/Makefile
@@ -1,5 +1,6 @@
 # SPDX-License-Identifier: GPL-2.0
 host1x-y = \
+	actmon.o \
 	bus.o \
 	syncpt.o \
 	dev.o \
diff --git a/drivers/gpu/host1x/actmon.c b/drivers/gpu/host1x/actmon.c
new file mode 100644
index 0000000000000..7a1d98fd099a8
--- /dev/null
+++ b/drivers/gpu/host1x/actmon.c
@@ -0,0 +1,558 @@
+// SPDX-License-Identifier: GPL-2.0-only
+/*
+ * SPDX-FileCopyrightText: Copyright (c) 2024 NVIDIA CORPORATION & AFFILIATES. All rights reserved.
+ *
+ * Tegra host1x actmon driver
+ */
+
+#include <linux/clk.h>
+#include <linux/debugfs.h>
+#include <linux/errno.h>
+#include <linux/fs.h>
+#include <linux/host1x.h>
+#include <linux/units.h>
+
+#include "dev.h"
+#include "actmon.h"
+#include "hw/actmon.h"
+
+static void actmon_writel(struct host1x_actmon *actmon, u32 val, u32 offset)
+{
+	writel(val, actmon->regs + offset);
+}
+
+static u32 actmon_readl(struct host1x_actmon *actmon, u32 offset)
+{
+	return readl(actmon->regs + offset);
+}
+
+static void actmon_module_writel(struct host1x_actmon_module *module, u32 val, u32 offset)
+{
+	writel(val, module->regs + offset);
+}
+
+static u32 actmon_module_readl(struct host1x_actmon_module *module, u32 offset)
+{
+	return readl(module->regs + offset);
+}
+
+static void host1x_actmon_update_sample_period(struct host1x_actmon *actmon)
+{
+	unsigned long actmon_mhz;
+	u32 actmon_clks_per_sample, sample_period, val = 0;
+
+	actmon_mhz = actmon->rate / HZ_PER_MHZ;
+	actmon_clks_per_sample = actmon_mhz * actmon->usecs_per_sample;
+
+	val |= HOST1X_ACTMON_CTRL_SOURCE(2);
+
+	if (actmon_clks_per_sample > 65536) {
+		val |= HOST1X_ACTMON_CTRL_SAMPLE_TICK(1);
+		sample_period = actmon_clks_per_sample / 65536;
+	} else {
+		val &= ~HOST1X_ACTMON_CTRL_SAMPLE_TICK(1);
+		sample_period = actmon_clks_per_sample / 256;
+	}
+
+	val &= ~HOST1X_ACTMON_CTRL_SAMPLE_PERIOD_MASK;
+	val |= HOST1X_ACTMON_CTRL_SAMPLE_PERIOD(sample_period);
+	actmon_writel(actmon, val, HOST1X_ACTMON_CTRL_REG);
+}
+
+static int host1x_actmon_sample_period_get(void *data, u64 *val)
+{
+	struct host1x_actmon *actmon = (struct host1x_actmon *)data;
+
+	*val = (u64)actmon->usecs_per_sample;
+
+	return 0;
+}
+
+static int host1x_actmon_sample_period_set(void *data, u64 val)
+{
+	struct host1x_actmon *actmon = (struct host1x_actmon *)data;
+
+	actmon->usecs_per_sample = (u32)val;
+	host1x_actmon_update_sample_period(actmon);
+
+	return 0;
+}
+
+DEFINE_SIMPLE_ATTRIBUTE(host1x_actmon_sample_period_fops,
+			host1x_actmon_sample_period_get,
+		host1x_actmon_sample_period_set,
+		"%lld\n");
+
+/**
+ * host1x_actmon_debug_init - Initialize actmon debugfs
+ * @actmon: the actmon instance being configured
+ * @name: an unique name of the actmon
+ *
+ * There are multiple modules available inside the actmon, and they perform the
+ * signal sampling at the same rate. The debugfs of an actmon will expose this
+ * shared configuration, sample_period, via a debugfs node:
+ * - sample_period:
+ *   Sampling period in micro-second of modules inside the actmon
+ */
+static void host1x_actmon_debug_init(struct host1x_actmon *actmon, const char *name)
+{
+	struct host1x *host = dev_get_drvdata(actmon->client->host->parent);
+
+	if (!host->debugfs) {
+		dev_warn(host->dev, "debugfs is unavailable\n");
+		return;
+	}
+
+	if (!host->actmon_debugfs)
+		host->actmon_debugfs = debugfs_create_dir("actmon", host->debugfs);
+
+	actmon->debugfs = debugfs_create_dir(name, host->actmon_debugfs);
+
+	/* R/W files */
+	debugfs_create_file("sample_period", 0644, actmon->debugfs, actmon,
+			    &host1x_actmon_sample_period_fops);
+}
+
+static int host1x_actmon_module_k_get(void *data, u64 *val)
+{
+	struct host1x_actmon_module *module = (struct host1x_actmon_module *)data;
+
+	*val = (u64)module->k;
+
+	return 0;
+}
+
+static int host1x_actmon_module_k_set(void *data, u64 val)
+{
+	struct host1x_actmon_module *module = (struct host1x_actmon_module *)data;
+	u32 val32;
+
+	module->k = (u32)val;
+
+	val32 = actmon_module_readl(module, HOST1X_ACTMON_MODULE_CTRL_REG);
+	val32 &= ~HOST1X_ACTMON_MODULE_CTRL_K_VAL_MASK;
+	val32 |= HOST1X_ACTMON_MODULE_CTRL_K_VAL(module->k);
+	actmon_module_writel(module, val32, HOST1X_ACTMON_MODULE_CTRL_REG);
+
+	return 0;
+}
+
+DEFINE_SIMPLE_ATTRIBUTE(host1x_actmon_module_k_fops,
+			host1x_actmon_module_k_get,
+		host1x_actmon_module_k_set,
+		"%lld\n");
+
+static int host1x_actmon_module_consec_upper_num_get(void *data, u64 *val)
+{
+	struct host1x_actmon_module *module = (struct host1x_actmon_module *)data;
+
+	*val = (u64)module->consec_upper_num;
+
+	return 0;
+}
+
+static int host1x_actmon_module_consec_upper_num_set(void *data, u64 val)
+{
+	struct host1x_actmon_module *module = (struct host1x_actmon_module *)data;
+	u32 val32;
+
+	module->consec_upper_num = (u32)val;
+
+	val32 = actmon_module_readl(module, HOST1X_ACTMON_MODULE_CTRL_REG);
+	val32 &= ~HOST1X_ACTMON_MODULE_CTRL_CONSEC_UPPER_NUM_MASK;
+	val32 |= HOST1X_ACTMON_MODULE_CTRL_CONSEC_UPPER_NUM(module->consec_upper_num);
+	actmon_module_writel(module, val32, HOST1X_ACTMON_MODULE_CTRL_REG);
+
+	return 0;
+}
+
+DEFINE_SIMPLE_ATTRIBUTE(host1x_actmon_module_consec_upper_num_fops,
+			host1x_actmon_module_consec_upper_num_get,
+		host1x_actmon_module_consec_upper_num_set,
+		"%lld\n");
+
+static int host1x_actmon_module_consec_lower_num_get(void *data, u64 *val)
+{
+	struct host1x_actmon_module *module = (struct host1x_actmon_module *)data;
+
+	*val = (u64)module->consec_lower_num;
+
+	return 0;
+}
+
+static int host1x_actmon_module_consec_lower_num_set(void *data, u64 val)
+{
+	struct host1x_actmon_module *module = (struct host1x_actmon_module *)data;
+	u32 val32;
+
+	module->consec_lower_num = (u32)val;
+
+	val32 = actmon_module_readl(module, HOST1X_ACTMON_MODULE_CTRL_REG);
+	val32 &= ~HOST1X_ACTMON_MODULE_CTRL_CONSEC_LOWER_NUM_MASK;
+	val32 |= HOST1X_ACTMON_MODULE_CTRL_CONSEC_LOWER_NUM(module->consec_lower_num);
+	actmon_module_writel(module, val32, HOST1X_ACTMON_MODULE_CTRL_REG);
+
+	return 0;
+}
+
+DEFINE_SIMPLE_ATTRIBUTE(host1x_actmon_module_consec_lower_num_fops,
+			host1x_actmon_module_consec_lower_num_get,
+		host1x_actmon_module_consec_lower_num_set,
+		"%lld\n");
+
+static int host1x_actmon_module_avg_norm_get(void *data, u64 *val)
+{
+	struct host1x_actmon_module *module = (struct host1x_actmon_module *)data;
+	struct host1x_actmon *actmon = module->actmon;
+	struct host1x_client *client = actmon->client;
+	unsigned long client_freq;
+	u32 active_clks, client_clks;
+
+	if (!client->ops || !client->ops->get_rate)
+		return -EOPNOTSUPP;
+
+	active_clks = actmon_module_readl(module, HOST1X_ACTMON_MODULE_AVG_COUNT_REG);
+
+	client_freq = client->ops->get_rate(client);
+	client_clks = ((client_freq / 1000) * actmon->usecs_per_sample) / 1000;
+
+	*val = (u64)(active_clks * 1000) / client_clks;
+
+	return 0;
+}
+
+DEFINE_SIMPLE_ATTRIBUTE(host1x_actmon_module_avg_norm_fops,
+			host1x_actmon_module_avg_norm_get, NULL,
+		"%lld\n");
+
+/**
+ * host1x_actmon_module_debug_init - Initialize debugfs for module inside actmon
+ * @module: the actmon module being configured
+ *
+ * Each module inside the actmon is used for monitoring the utilization of the
+ * underlying host1x client. The debugfs of an actmon module will expose the
+ * following debugfs nodes:
+ * - k:
+ *   It is a programmable factor affecting the exponential-moving-average filter
+ *   inside the actmon module for calculating the utilization of the engine over
+ *   the time. The formula of the filter is as following:
+ *
+ *	K = 1 / 2^(k+1)
+ *	A_t = (K * C_t) + ((1-K) * A_{t-1})
+ *
+ *   where A_t is the average utilization at time t. C_t is the sampled actmon
+ *   counter value at time t.
+ *
+ * - consec_upper_num:
+ *   "`consec_upper_num` + 1" of consecutive upper watermark breaches that need
+ *   to occur before actmon module asserts the interrupt to CPU.
+ *
+ * - consec_lower_num:
+ *   "`consec_lower_num` + 1" of consecutive lower watermark breaches that need
+ *   to occur before actmon module asserts the interrupt to CPU.
+ *
+ * - usage:
+ *   A normalized value representing the utilization of the engine ranges from
+ *   0 to 1000.
+ */
+static void host1x_actmon_module_debug_init(struct host1x_actmon_module *module)
+{
+	struct host1x *host = dev_get_drvdata(module->actmon->client->host->parent);
+	struct device *dev = module->actmon->client->dev;
+	struct dentry *debugfs = module->actmon->debugfs;
+	char dirname[8];
+
+	if (!debugfs) {
+		dev_warn(host->dev,
+			 "actmon debugfs entry for %s was not found\n",
+			 dev_name(dev));
+		return;
+	}
+
+	snprintf(dirname, sizeof(dirname), "module%d", module->type);
+	module->debugfs = debugfs_create_dir(dirname, debugfs);
+
+	/* R/W files */
+	debugfs_create_file("k", 0644, module->debugfs, module,
+			    &host1x_actmon_module_k_fops);
+	debugfs_create_file("consec_upper_num", 0644, module->debugfs, module,
+			    &host1x_actmon_module_consec_upper_num_fops);
+	debugfs_create_file("consec_lower_num", 0644, module->debugfs, module,
+			    &host1x_actmon_module_consec_lower_num_fops);
+
+	/* R files */
+	debugfs_create_file("usage", 0444, module->debugfs, module,
+			    &host1x_actmon_module_avg_norm_fops);
+}
+
+static void host1x_actmon_init(struct host1x_actmon *actmon)
+{
+	u32 val;
+
+	/* Global control register */
+	host1x_actmon_update_sample_period(actmon);
+
+	/* Global interrupt enable register */
+	val = (1 << actmon->num_modules) - 1;
+	actmon_writel(actmon, val, HOST1X_ACTMON_INTR_ENB_REG);
+}
+
+static void host1x_actmon_deinit(struct host1x_actmon *actmon)
+{
+	actmon_writel(actmon, 0, HOST1X_ACTMON_CTRL_REG);
+	actmon_writel(actmon, 0, HOST1X_ACTMON_INTR_ENB_REG);
+}
+
+static void host1x_actmon_module_init(struct host1x_actmon_module *module)
+{
+	/* Local control register */
+	actmon_module_writel(module,
+			     HOST1X_ACTMON_MODULE_CTRL_ACTMON_ENB(0) |
+			     HOST1X_ACTMON_MODULE_CTRL_ENB_PERIODIC(1) |
+			     HOST1X_ACTMON_MODULE_CTRL_K_VAL(module->k) |
+			     HOST1X_ACTMON_MODULE_CTRL_CONSEC_UPPER_NUM(module->consec_upper_num) |
+			     HOST1X_ACTMON_MODULE_CTRL_CONSEC_LOWER_NUM(module->consec_lower_num),
+			     HOST1X_ACTMON_MODULE_CTRL_REG);
+
+	/* Interrupt enable register (disable interrupts by default) */
+	actmon_module_writel(module, 0, HOST1X_ACTMON_MODULE_INTR_ENB_REG);
+
+	/* Interrupt status register */
+	actmon_module_writel(module, ~0, HOST1X_ACTMON_MODULE_INTR_STATUS_REG);
+
+	/* Consecutive watermark registers */
+	actmon_module_writel(module, ~0, HOST1X_ACTMON_MODULE_UPPER_WMARK_REG);
+	actmon_module_writel(module, 0, HOST1X_ACTMON_MODULE_LOWER_WMARK_REG);
+
+	/* Moving-average watermark registers */
+	actmon_module_writel(module, ~0, HOST1X_ACTMON_MODULE_AVG_UPPER_WMARK_REG);
+	actmon_module_writel(module, 0, HOST1X_ACTMON_MODULE_AVG_LOWER_WMARK_REG);
+
+	/* Init average value register */
+	actmon_module_writel(module, 0, HOST1X_ACTMON_MODULE_INIT_AVG_REG);
+}
+
+static void host1x_actmon_module_deinit(struct host1x_actmon_module *module)
+{
+	actmon_module_writel(module, 0, HOST1X_ACTMON_MODULE_CTRL_REG);
+	actmon_module_writel(module, 0, HOST1X_ACTMON_MODULE_INTR_ENB_REG);
+	actmon_module_writel(module, ~0, HOST1X_ACTMON_MODULE_INTR_STATUS_REG);
+	actmon_module_writel(module, 0, HOST1X_ACTMON_MODULE_UPPER_WMARK_REG);
+	actmon_module_writel(module, 0, HOST1X_ACTMON_MODULE_LOWER_WMARK_REG);
+	actmon_module_writel(module, 0, HOST1X_ACTMON_MODULE_AVG_UPPER_WMARK_REG);
+	actmon_module_writel(module, 0, HOST1X_ACTMON_MODULE_AVG_LOWER_WMARK_REG);
+	actmon_module_writel(module, 0, HOST1X_ACTMON_MODULE_INIT_AVG_REG);
+	actmon_module_writel(module, 0, HOST1X_ACTMON_MODULE_COUNT_WEIGHT_REG);
+}
+
+void host1x_actmon_handle_interrupt(struct host1x *host, int classid)
+{
+	unsigned long actmon_status, module_status;
+	struct host1x_actmon_module *module;
+	struct host1x_actmon *actmon, *tmp_actmon;
+	struct host1x_client *client;
+
+	list_for_each_entry_safe(actmon, tmp_actmon, &host->actmons, list) {
+		if (actmon->client->class == classid)
+			break;
+	}
+
+	client = actmon->client;
+	module = &actmon->modules[HOST1X_ACTMON_MODULE_ACTIVE];
+
+	actmon_status = actmon_readl(actmon, HOST1X_ACTMON_INTR_STATUS_REG);
+	module_status = actmon_module_readl(module, HOST1X_ACTMON_MODULE_INTR_STATUS_REG);
+
+	/* Trigger DFS if client supports it */
+	if (client->ops && client->ops->actmon_event) {
+		if (module_status & HOST1X_ACTMON_MODULE_INTR_CONSEC_WMARK_ABOVE)
+			client->ops->actmon_event(client, HOST1X_ACTMON_CONSEC_WMARK_ABOVE);
+
+		if (module_status & HOST1X_ACTMON_MODULE_INTR_CONSEC_WMARK_BELOW)
+			client->ops->actmon_event(client, HOST1X_ACTMON_CONSEC_WMARK_BELOW);
+
+		if (module_status & HOST1X_ACTMON_MODULE_INTR_AVG_WMARK_ABOVE)
+			client->ops->actmon_event(client, HOST1X_ACTMON_AVG_WMARK_ABOVE);
+
+		if (module_status & HOST1X_ACTMON_MODULE_INTR_AVG_WMARK_BELOW)
+			client->ops->actmon_event(client, HOST1X_ACTMON_AVG_WMARK_BELOW);
+	}
+
+	actmon_module_writel(module, module_status, HOST1X_ACTMON_MODULE_INTR_STATUS_REG);
+	actmon_writel(actmon, actmon_status, HOST1X_ACTMON_INTR_STATUS_REG);
+}
+
+int host1x_actmon_register(struct host1x_client *client)
+{
+	struct host1x *host = dev_get_drvdata(client->host->parent);
+	const struct host1x_info *info = host->info;
+	const struct host1x_actmon_entry *entry = NULL;
+	struct host1x_actmon_module *module;
+	struct host1x_actmon *actmon;
+	int i;
+
+	if (!info->has_actmon) {
+		dev_dbg(host->dev, "actmon is not supported\n");
+		return 0;
+	}
+
+	if (!host->actmon_regs) {
+		dev_warn(host->dev,
+			 "skip registration since actmon resource is not defined\n");
+		return 0;
+	}
+
+	if (!host->actmon_clk) {
+		dev_warn(host->dev,
+			 "skip registration since actmon clock is unavailable\n");
+		return 0;
+	}
+
+	if (client->actmon) {
+		dev_warn(host->dev,
+			 "%s has already registered actmon\n",
+			 dev_name(client->dev));
+		return 0;
+	}
+
+	for (i = 0; i < info->num_actmon_entries; i++) {
+		if (info->actmon_table[i].classid == client->class)
+			entry = &info->actmon_table[i];
+	}
+	if (!entry)
+		return -ENODEV;
+
+	actmon = devm_kzalloc(client->dev, sizeof(*actmon), GFP_KERNEL);
+	if (!actmon)
+		return -ENOMEM;
+
+	INIT_LIST_HEAD(&actmon->list);
+	mutex_lock(&host->actmons_lock);
+	list_add_tail(&actmon->list, &host->actmons);
+	mutex_unlock(&host->actmons_lock);
+
+	actmon->client = client;
+	actmon->rate = clk_get_rate(host->actmon_clk);
+	actmon->regs = host->actmon_regs + entry->offset;
+	actmon->irq = entry->irq;
+	actmon->num_modules = entry->num_modules;
+	actmon->usecs_per_sample = 1500;
+
+	/* Configure actmon registers */
+	host1x_actmon_init(actmon);
+
+	/* Create debugfs for the actmon */
+	host1x_actmon_debug_init(actmon, entry->name);
+
+	/* Configure actmon module registers */
+	for (i = 0; i < actmon->num_modules; i++) {
+		module = &actmon->modules[i];
+		module->actmon = actmon;
+		module->type = i;
+		module->regs = actmon->regs + (i * HOST1X_ACTMON_MODULE_OFFSET);
+
+		module->k = 2;
+		module->consec_upper_num = 7;
+		module->consec_lower_num = 7;
+		host1x_actmon_module_init(module);
+
+		/* Create debugfs for the actmon module */
+		host1x_actmon_module_debug_init(module);
+	}
+
+	client->actmon = actmon;
+
+	return 0;
+}
+EXPORT_SYMBOL(host1x_actmon_register);
+
+void host1x_actmon_unregister(struct host1x_client *client)
+{
+	struct host1x_actmon_module *module;
+	struct host1x *host = dev_get_drvdata(client->host->parent);
+	struct host1x_actmon *actmon = client->actmon;
+	int i;
+
+	if (!actmon)
+		return;
+
+	for (i = 0; i < actmon->num_modules; i++) {
+		module = &actmon->modules[i];
+		host1x_actmon_module_deinit(module);
+		debugfs_remove_recursive(module->debugfs);
+	}
+
+	debugfs_remove_recursive(actmon->debugfs);
+
+	host1x_actmon_deinit(actmon);
+
+	mutex_lock(&host->actmons_lock);
+	list_del(&actmon->list);
+	mutex_unlock(&host->actmons_lock);
+
+	client->actmon = NULL;
+}
+EXPORT_SYMBOL(host1x_actmon_unregister);
+
+void host1x_actmon_enable(struct host1x_client *client)
+{
+	struct host1x_actmon *actmon = client->actmon;
+	struct host1x_actmon_module *module;
+	int i;
+
+	if (!actmon)
+		return;
+
+	for (i = 0; i < actmon->num_modules; i++) {
+		module = &actmon->modules[i];
+		actmon_module_writel(module,
+				     actmon_module_readl(module, HOST1X_ACTMON_MODULE_CTRL_REG) |
+				     HOST1X_ACTMON_MODULE_CTRL_ACTMON_ENB(1),
+				     HOST1X_ACTMON_MODULE_CTRL_REG);
+	}
+}
+EXPORT_SYMBOL(host1x_actmon_enable);
+
+void host1x_actmon_disable(struct host1x_client *client)
+{
+	struct host1x_actmon *actmon = client->actmon;
+	struct host1x_actmon_module *module;
+	int i;
+
+	if (!actmon)
+		return;
+
+	for (i = 0; i < actmon->num_modules; i++) {
+		module = &actmon->modules[i];
+		actmon_module_writel(module,
+				     actmon_module_readl(module, HOST1X_ACTMON_MODULE_CTRL_REG) &
+				     ~HOST1X_ACTMON_MODULE_CTRL_ACTMON_ENB(1),
+				     HOST1X_ACTMON_MODULE_CTRL_REG);
+	}
+}
+EXPORT_SYMBOL(host1x_actmon_disable);
+
+void host1x_actmon_update_client_rate(struct host1x_client *client,
+				      unsigned long rate,
+				      u32 *weight)
+{
+	struct host1x_actmon *actmon = client->actmon;
+	struct host1x_actmon_module *module;
+	u32 val;
+	int i;
+
+	if (!actmon) {
+		*weight = 0;
+		return;
+	}
+
+	val = (rate / actmon->rate) << 2;
+
+	for (i = 0; i < actmon->num_modules; i++) {
+		module = &actmon->modules[i];
+		actmon_module_writel(module, val, HOST1X_ACTMON_MODULE_COUNT_WEIGHT_REG);
+	}
+
+	*weight = val;
+}
+EXPORT_SYMBOL(host1x_actmon_update_client_rate);
diff --git a/drivers/gpu/host1x/actmon.h b/drivers/gpu/host1x/actmon.h
new file mode 100644
index 0000000000000..8d6f314b8a3ea
--- /dev/null
+++ b/drivers/gpu/host1x/actmon.h
@@ -0,0 +1,46 @@
+/* SPDX-License-Identifier: GPL-2.0-only
+ * SPDX-FileCopyrightText: Copyright (c) 2009-2024 NVIDIA CORPORATION & AFFILIATES. All rights reserved.
+ */
+
+#ifndef HOST1X_ACTMON_H
+#define HOST1X_ACTMON_H
+
+#include <linux/device.h>
+#include <linux/types.h>
+
+enum host1x_actmon_module_type {
+	HOST1X_ACTMON_MODULE_ACTIVE,
+	HOST1X_ACTMON_MODULE_STALL,
+};
+
+struct host1x_actmon;
+
+struct host1x_actmon_module {
+	enum host1x_actmon_module_type type;
+	u32 k;
+	u32 consec_upper_num;
+	u32 consec_lower_num;
+	void __iomem *regs;
+	struct host1x_actmon *actmon;
+	struct dentry *debugfs;
+};
+
+struct host1x_client;
+
+struct host1x_actmon {
+	unsigned int irq;
+	unsigned int num_modules;
+	unsigned long rate;
+	u32 usecs_per_sample;
+	void __iomem *regs;
+	struct host1x_client *client;
+	struct host1x_actmon_module modules[8];
+	struct dentry *debugfs;
+	struct list_head list;
+};
+
+struct host1x;
+
+void host1x_actmon_handle_interrupt(struct host1x *host, int classid);
+
+#endif
diff --git a/drivers/gpu/host1x/dev.c b/drivers/gpu/host1x/dev.c
index 7b1d091f3c090..9b60693dccdb2 100644
--- a/drivers/gpu/host1x/dev.c
+++ b/drivers/gpu/host1x/dev.c
@@ -1,8 +1,8 @@
 // SPDX-License-Identifier: GPL-2.0-only
 /*
- * Tegra host1x driver
+ * SPDX-FileCopyrightText: Copyright (c) 2010-2024 NVIDIA CORPORATION & AFFILIATES. All rights reserved.
  *
- * Copyright (c) 2010-2013, NVIDIA Corporation.
+ * Tegra host1x driver
  */
 
 #include <linux/clk.h>
@@ -47,6 +47,11 @@ void host1x_common_writel(struct host1x *host1x, u32 v, u32 r)
 	writel(v, host1x->common_regs + r);
 }
 
+u32 host1x_common_readl(struct host1x *host1x, u32 r)
+{
+	return readl(host1x->common_regs + r);
+}
+
 void host1x_hypervisor_writel(struct host1x *host1x, u32 v, u32 r)
 {
 	writel(v, host1x->hv_regs + r);
@@ -259,6 +264,23 @@ static const struct host1x_sid_entry tegra234_sid_table[] = {
 	{ /* VI2_THI MMIO */  .base = 0x16f8, .offset = 0x30,  .limit = 0x34  },
 };
 
+static const struct host1x_actmon_entry tegra234_actmon_table[] = {
+	{
+		.classid = HOST1X_CLASS_VIC,
+		.name = "vic",
+		.irq = 3,
+		.offset = 0x10000,
+		.num_modules = 1,
+	},
+	{
+		.classid = HOST1X_CLASS_NVDEC,
+		.name = "nvdec",
+		.irq = 4,
+		.offset = 0x20000,
+		.num_modules = 1,
+	},
+};
+
 static const struct host1x_info host1x08_info = {
 	.nb_channels = 63,
 	.nb_pts = 1024,
@@ -270,7 +292,10 @@ static const struct host1x_info host1x08_info = {
 	.has_wide_gather = true,
 	.has_hypervisor = true,
 	.has_common = true,
+	.has_actmon = true,
+	.num_actmon_entries = ARRAY_SIZE(tegra234_actmon_table),
 	.num_sid_entries = ARRAY_SIZE(tegra234_sid_table),
+	.actmon_table = tegra234_actmon_table,
 	.sid_table = tegra234_sid_table,
 	.streamid_vm_table = { 0x1004, 128 },
 	.classid_vm_table = { 0x1404, 25 },
@@ -530,6 +555,14 @@ static int host1x_probe(struct platform_device *pdev)
 			if (IS_ERR(host->common_regs))
 				return PTR_ERR(host->common_regs);
 		}
+
+		if (host->info->has_actmon) {
+			host->actmon_regs = devm_platform_ioremap_resource_byname(pdev, "actmon");
+			if (IS_ERR(host->actmon_regs)) {
+				dev_warn(&pdev->dev, "failed to get actmon resource\n");
+				host->actmon_regs = NULL;
+			}
+		}
 	} else {
 		host->regs = devm_platform_ioremap_resource(pdev, 0);
 		if (IS_ERR(host->regs))
@@ -561,8 +594,12 @@ static int host1x_probe(struct platform_device *pdev)
 		host->num_syncpt_irqs = 1;
 	}
 
+	host->general_irq = platform_get_irq_byname_optional(pdev, "host1x");
+
 	mutex_init(&host->devices_lock);
 	INIT_LIST_HEAD(&host->devices);
+	mutex_init(&host->actmons_lock);
+	INIT_LIST_HEAD(&host->actmons);
 	INIT_LIST_HEAD(&host->list);
 	host->dev = &pdev->dev;
 
@@ -578,6 +615,12 @@ static int host1x_probe(struct platform_device *pdev)
 			return err;
 	}
 
+	err = host1x_hw_intr_init_host_general(host);
+	if (err) {
+		dev_err(&pdev->dev, "failed to init general interrupt handler: %d\n", err);
+		return err;
+	}
+
 	host->clk = devm_clk_get(&pdev->dev, NULL);
 	if (IS_ERR(host->clk)) {
 		err = PTR_ERR(host->clk);
@@ -588,6 +631,14 @@ static int host1x_probe(struct platform_device *pdev)
 		return err;
 	}
 
+	if (host->info->has_actmon) {
+		host->actmon_clk = devm_clk_get(&pdev->dev, "actmon");
+		if (IS_ERR(host->actmon_clk)) {
+			dev_warn(&pdev->dev, "failed to get actmon clock\n");
+			host->actmon_clk = NULL;
+		}
+	}
+
 	err = host1x_get_resets(host);
 	if (err)
 		return err;
@@ -692,6 +743,7 @@ static int __maybe_unused host1x_runtime_suspend(struct device *dev)
 	struct host1x *host = dev_get_drvdata(dev);
 	int err;
 
+	host1x_hw_intr_disable_general_intrs(host);
 	host1x_channel_stop_all(host);
 	host1x_intr_stop(host);
 	host1x_syncpt_save(host);
@@ -707,6 +759,7 @@ static int __maybe_unused host1x_runtime_suspend(struct device *dev)
 	}
 
 	clk_disable_unprepare(host->clk);
+	clk_disable_unprepare(host->actmon_clk);
 	reset_control_bulk_release(host->nresets, host->resets);
 
 	return 0;
@@ -715,6 +768,7 @@ static int __maybe_unused host1x_runtime_suspend(struct device *dev)
 	host1x_setup_virtualization_tables(host);
 	host1x_syncpt_restore(host);
 	host1x_intr_start(host);
+	host1x_hw_intr_enable_general_intrs(host);
 
 	return err;
 }
@@ -724,6 +778,12 @@ static int __maybe_unused host1x_runtime_resume(struct device *dev)
 	struct host1x *host = dev_get_drvdata(dev);
 	int err;
 
+	err = clk_prepare_enable(host->actmon_clk);
+	if (err) {
+		dev_err(dev, "failed to enable actmon clock: %d\n", err);
+		goto disable_host1x_clk;
+	}
+
 	err = reset_control_bulk_acquire(host->nresets, host->resets);
 	if (err) {
 		dev_err(dev, "failed to acquire reset: %d\n", err);
@@ -739,16 +799,19 @@ static int __maybe_unused host1x_runtime_resume(struct device *dev)
 	err = reset_control_bulk_deassert(host->nresets, host->resets);
 	if (err < 0) {
 		dev_err(dev, "failed to deassert reset: %d\n", err);
-		goto disable_clk;
+		goto disable_actmon_clk;
 	}
 
 	host1x_setup_virtualization_tables(host);
 	host1x_syncpt_restore(host);
 	host1x_intr_start(host);
+	host1x_hw_intr_enable_general_intrs(host);
 
 	return 0;
 
-disable_clk:
+disable_actmon_clk:
+	clk_disable_unprepare(host->actmon_clk);
+disable_host1x_clk:
 	clk_disable_unprepare(host->clk);
 release_reset:
 	reset_control_bulk_release(host->nresets, host->resets);
diff --git a/drivers/gpu/host1x/dev.h b/drivers/gpu/host1x/dev.h
index d3855a1c6b472..2270ec6b73f2e 100644
--- a/drivers/gpu/host1x/dev.h
+++ b/drivers/gpu/host1x/dev.h
@@ -1,12 +1,12 @@
-/* SPDX-License-Identifier: GPL-2.0-only */
-/*
- * Copyright (c) 2012-2015, NVIDIA Corporation.
+/* SPDX-License-Identifier: GPL-2.0-only
+ * SPDX-FileCopyrightText: Copyright (c) 20012-2024 NVIDIA CORPORATION & AFFILIATES. All rights reserved.
  */
 
 #ifndef HOST1X_DEV_H
 #define HOST1X_DEV_H
 
 #include <linux/device.h>
+#include <linux/errno.h>
 #include <linux/iommu.h>
 #include <linux/iova.h>
 #include <linux/irqreturn.h>
@@ -74,6 +74,12 @@ struct host1x_syncpt_ops {
 	void (*enable_protection)(struct host1x *host);
 };
 
+struct host1x_intr_general_ops {
+	int (*init_host_general)(struct host1x *host);
+	void (*enable_general_intrs)(struct host1x *host);
+	void (*disable_general_intrs)(struct host1x *host);
+};
+
 struct host1x_intr_ops {
 	int (*init_host_sync)(struct host1x *host, u32 cpm);
 	void (*set_syncpt_threshold)(
@@ -85,6 +91,14 @@ struct host1x_intr_ops {
 	irqreturn_t (*isr)(int irq, void *dev_id);
 };
 
+struct host1x_actmon_entry {
+	int classid;
+	const char *name;
+	unsigned int irq;
+	unsigned int offset;
+	unsigned int num_modules;
+};
+
 struct host1x_sid_entry {
 	unsigned int base;
 	unsigned int offset;
@@ -107,8 +121,11 @@ struct host1x_info {
 	bool has_wide_gather; /* supports GATHER_W opcode */
 	bool has_hypervisor; /* has hypervisor registers */
 	bool has_common; /* has common registers separate from hypervisor */
+	bool has_actmon; /* has actmon registers separate from hypervisor */
 	unsigned int num_sid_entries;
+	unsigned int num_actmon_entries;
 	const struct host1x_sid_entry *sid_table;
+	const struct host1x_actmon_entry *actmon_table;
 	struct host1x_table_desc streamid_vm_table;
 	struct host1x_table_desc classid_vm_table;
 	struct host1x_table_desc mmio_vm_table;
@@ -132,12 +149,15 @@ struct host1x {
 	void __iomem *regs;
 	void __iomem *hv_regs; /* hypervisor region */
 	void __iomem *common_regs;
+	void __iomem *actmon_regs;
 	int syncpt_irqs[8];
 	int num_syncpt_irqs;
+	int general_irq;
 	struct host1x_syncpt *syncpt;
 	struct host1x_syncpt_base *bases;
 	struct device *dev;
 	struct clk *clk;
+	struct clk *actmon_clk;
 	struct reset_control_bulk_data resets[2];
 	unsigned int nresets;
 
@@ -149,6 +169,7 @@ struct host1x {
 	struct mutex intr_mutex;
 
 	const struct host1x_syncpt_ops *syncpt_op;
+	const struct host1x_intr_general_ops *intr_general_op;
 	const struct host1x_intr_ops *intr_op;
 	const struct host1x_channel_ops *channel_op;
 	const struct host1x_cdma_ops *cdma_op;
@@ -163,10 +184,15 @@ struct host1x {
 	struct host1x_memory_context_list context_list;
 
 	struct dentry *debugfs;
+	struct dentry *actmon_debugfs;
 
 	struct mutex devices_lock;
 	struct list_head devices;
 
+	/* Ensure atomic update against the list of registered actmons */
+	struct mutex actmons_lock;
+	struct list_head actmons;
+
 	struct list_head list;
 
 	struct device_dma_parameters dma_parms;
@@ -175,7 +201,8 @@ struct host1x {
 };
 
 void host1x_common_writel(struct host1x *host1x, u32 v, u32 r);
-void host1x_hypervisor_writel(struct host1x *host1x, u32 v, u32 r);
+u32 host1x_common_readl(struct host1x *host1x, u32 r);
+void host1x_hypervisor_writel(struct host1x *host1x, u32 r, u32 v);
 u32 host1x_hypervisor_readl(struct host1x *host1x, u32 r);
 void host1x_sync_writel(struct host1x *host1x, u32 v, u32 r);
 u32 host1x_sync_readl(struct host1x *host1x, u32 r);
@@ -224,6 +251,30 @@ static inline void host1x_hw_syncpt_enable_protection(struct host1x *host)
 	return host->syncpt_op->enable_protection(host);
 }
 
+static inline int host1x_hw_intr_init_host_general(struct host1x *host)
+{
+	if (!host->intr_general_op)
+		return 0;
+
+	return host->intr_general_op->init_host_general(host);
+}
+
+static inline void host1x_hw_intr_enable_general_intrs(struct host1x *host)
+{
+	if (!host->intr_general_op)
+		return;
+
+	host->intr_general_op->enable_general_intrs(host);
+}
+
+static inline void host1x_hw_intr_disable_general_intrs(struct host1x *host)
+{
+	if (!host->intr_general_op)
+		return;
+
+	host->intr_general_op->disable_general_intrs(host);
+}
+
 static inline int host1x_hw_intr_init_host_sync(struct host1x *host, u32 cpm)
 {
 	return host->intr_op->init_host_sync(host, cpm);
diff --git a/drivers/gpu/host1x/hw/actmon.h b/drivers/gpu/host1x/hw/actmon.h
new file mode 100644
index 0000000000000..01659829d51ac
--- /dev/null
+++ b/drivers/gpu/host1x/hw/actmon.h
@@ -0,0 +1,49 @@
+/* SPDX-License-Identifier: GPL-2.0-only
+ * SPDX-FileCopyrightText: Copyright (c) 2024 NVIDIA CORPORATION & AFFILIATES. All rights reserved.
+ *
+ * Tegra host1x Actmon Register Offsets
+ */
+
+#ifndef __HOST1X_ACTMON_HARDWARE_H
+#define __HOST1X_ACTMON_HARDWARE_H
+
+#define HOST1X_ACTMON_MODULE_OFFSET				0x80
+
+#define HOST1X_ACTMON_CTRL_REG					0x0
+#define HOST1X_ACTMON_INTR_ENB_REG				0x4
+#define HOST1X_ACTMON_INTR_STATUS_REG				0x8
+#define HOST1X_ACTMON_MODULE_INIT_AVG_REG			0x14
+#define HOST1X_ACTMON_MODULE_CTRL_REG				0x80
+#define HOST1X_ACTMON_MODULE_INTR_ENB_REG			0x84
+#define HOST1X_ACTMON_MODULE_INTR_STATUS_REG			0x88
+#define HOST1X_ACTMON_MODULE_UPPER_WMARK_REG			0x8c
+#define HOST1X_ACTMON_MODULE_LOWER_WMARK_REG			0x90
+#define HOST1X_ACTMON_MODULE_AVG_UPPER_WMARK_REG		0x94
+#define HOST1X_ACTMON_MODULE_AVG_LOWER_WMARK_REG		0x98
+#define HOST1X_ACTMON_MODULE_AVG_COUNT_REG			0xa4
+#define HOST1X_ACTMON_MODULE_COUNT_WEIGHT_REG			0xa8
+
+#define HOST1X_ACTMON_CTRL_SOURCE(v)				(((v) & 0x3) << 8)
+#define HOST1X_ACTMON_CTRL_SAMPLE_TICK(v)			(((v) & 0x1) << 10)
+#define HOST1X_ACTMON_CTRL_SAMPLE_PERIOD(v)			(((v) & 0xff) << 0)
+#define HOST1X_ACTMON_MODULE_CTRL_ACTMON_ENB(v)			(((v) & 0x1) << 31)
+#define HOST1X_ACTMON_MODULE_CTRL_CONSEC_UPPER_NUM(v)		(((v) & 0x7) << 26)
+#define HOST1X_ACTMON_MODULE_CTRL_CONSEC_LOWER_NUM(v)		(((v) & 0x7) << 21)
+#define HOST1X_ACTMON_MODULE_CTRL_ENB_PERIODIC(v)		(((v) & 0x1) << 13)
+#define HOST1X_ACTMON_MODULE_CTRL_K_VAL(v)			(((v) & 0x7) << 10)
+#define HOST1X_ACTMON_MODULE_INTR_CONSEC_WMARK_ABOVE_ENB(v)	(((v) & 0x1) << 31)
+#define HOST1X_ACTMON_MODULE_INTR_CONSEC_WMARK_BELOW_ENB(v)	(((v) & 0x1) << 30)
+#define HOST1X_ACTMON_MODULE_INTR_AVG_WMARK_ABOVE_ENB(v)	(((v) & 0x1) << 29)
+#define HOST1X_ACTMON_MODULE_INTR_AVG_WMARK_BELOW_ENB(v)	(((v) & 0x1) << 28)
+
+#define HOST1X_ACTMON_CTRL_SAMPLE_PERIOD_MASK			0xff
+#define HOST1X_ACTMON_MODULE_CTRL_CONSEC_UPPER_NUM_MASK		(0x7 << 26)
+#define HOST1X_ACTMON_MODULE_CTRL_CONSEC_LOWER_NUM_MASK		(0x7 << 21)
+#define HOST1X_ACTMON_MODULE_CTRL_K_VAL_MASK			(0x7 << 10)
+
+#define HOST1X_ACTMON_MODULE_INTR_CONSEC_WMARK_ABOVE		BIT(31)
+#define HOST1X_ACTMON_MODULE_INTR_CONSEC_WMARK_BELOW		BIT(30)
+#define HOST1X_ACTMON_MODULE_INTR_AVG_WMARK_ABOVE		BIT(29)
+#define HOST1X_ACTMON_MODULE_INTR_AVG_WMARK_BELOW		BIT(28)
+
+#endif
diff --git a/drivers/gpu/host1x/hw/host1x08.c b/drivers/gpu/host1x/hw/host1x08.c
index 754890c34c740..a32b263bcbc75 100644
--- a/drivers/gpu/host1x/hw/host1x08.c
+++ b/drivers/gpu/host1x/hw/host1x08.c
@@ -1,8 +1,8 @@
 // SPDX-License-Identifier: GPL-2.0-only
 /*
- * Host1x init for Tegra234 SoCs
+ * SPDX-FileCopyrightText: Copyright (c) 2022-2024 NVIDIA CORPORATION & AFFILIATES. All rights reserved.
  *
- * Copyright (c) 2022 NVIDIA Corporation.
+ * Host1x init for Tegra234 SoCs
  */
 
 /* include hw specification */
@@ -15,6 +15,7 @@
 #include "cdma_hw.c"
 #include "channel_hw.c"
 #include "debug_hw.c"
+#include "intr_general_hw.c"
 #include "intr_hw.c"
 #include "syncpt_hw.c"
 
@@ -26,6 +27,7 @@ int host1x08_init(struct host1x *host)
 	host->cdma_op = &host1x_cdma_ops;
 	host->cdma_pb_op = &host1x_pushbuffer_ops;
 	host->syncpt_op = &host1x_syncpt_ops;
+	host->intr_general_op = &host1x_intr_general_ops;
 	host->intr_op = &host1x_intr_ops;
 	host->debug_op = &host1x_debug_ops;
 
diff --git a/drivers/gpu/host1x/hw/hw_host1x08_common.h b/drivers/gpu/host1x/hw/hw_host1x08_common.h
index 8e0c99150ec2c..b6c210f357428 100644
--- a/drivers/gpu/host1x/hw/hw_host1x08_common.h
+++ b/drivers/gpu/host1x/hw/hw_host1x08_common.h
@@ -1,6 +1,5 @@
-/* SPDX-License-Identifier: GPL-2.0-only */
-/*
- * Copyright (c) 2022 NVIDIA Corporation.
+/* SPDX-License-Identifier: GPL-2.0-only
+ * SPDX-FileCopyrightText: Copyright (c) 2022-2024 NVIDIA CORPORATION & AFFILIATES. All rights reserved.
  */
 
 #define HOST1X_COMMON_OFA_MLOCK			0x4050
@@ -9,3 +8,14 @@
 #define HOST1X_COMMON_NVENC_MLOCK		0x407c
 #define HOST1X_COMMON_NVDEC_MLOCK		0x4080
 #define HOST1X_COMMON_NVJPG_MLOCK		0x4084
+
+#define HOST1X_COMMON_INTR_CPU0_MASK		0x4
+#define HOST1X_COMMON_THOST_INTRSTATUS		0x1c
+#define HOST1X_COMMON_THOST_INTRMASK		0x30
+#define HOST1X_COMMON_THOST_GLOBAL_INTRMASK	0x44
+
+#define HOST1X_COMMON_THOST_INTRMASK_VIC_ACTMON(v)		((v) << 3)
+#define HOST1X_COMMON_THOST_INTRMASK_NVDEC_ACTMON(v)		((v) << 4)
+
+#define HOST1X_COMMON_THOST_INTRSTATUS_VIC_ACTMON_INTR		BIT(3)
+#define HOST1X_COMMON_THOST_INTRSTATUS_NVDEC_ACTMON_INTR	BIT(4)
diff --git a/drivers/gpu/host1x/hw/intr_general_hw.c b/drivers/gpu/host1x/hw/intr_general_hw.c
new file mode 100644
index 0000000000000..ef5064384f77f
--- /dev/null
+++ b/drivers/gpu/host1x/hw/intr_general_hw.c
@@ -0,0 +1,83 @@
+// SPDX-License-Identifier: GPL-2.0-only
+/*
+ * SPDX-FileCopyrightText: Copyright (c) 2024 NVIDIA CORPORATION & AFFILIATES. All rights reserved.
+ *
+ * Tegra host1x General Interrupt Management
+ */
+
+#include <linux/interrupt.h>
+
+#include "../actmon.h"
+#include "../dev.h"
+
+static irqreturn_t host1x_general_isr(int irq, void *dev_id)
+{
+	struct host1x *host = dev_id;
+	unsigned long status;
+
+	status = host1x_common_readl(host, HOST1X_COMMON_THOST_INTRSTATUS);
+
+	if (status & HOST1X_COMMON_THOST_INTRSTATUS_VIC_ACTMON_INTR)
+		host1x_actmon_handle_interrupt(host, HOST1X_CLASS_VIC);
+
+	if (status & HOST1X_COMMON_THOST_INTRSTATUS_NVDEC_ACTMON_INTR)
+		host1x_actmon_handle_interrupt(host, HOST1X_CLASS_NVDEC);
+
+	host1x_common_writel(host, status, HOST1X_COMMON_THOST_INTRSTATUS);
+
+	return IRQ_HANDLED;
+}
+
+static int host1x_intr_init_host_general(struct host1x *host)
+{
+	int err;
+
+	if (host->general_irq <= 0 && !host->common_regs)
+		return 0;
+
+	host1x_hw_intr_disable_general_intrs(host);
+
+	err = devm_request_threaded_irq(host->dev,
+					host->general_irq,
+					NULL, host1x_general_isr,
+					IRQF_ONESHOT, "host1x_general",
+					host);
+	if (err < 0) {
+		devm_free_irq(host->dev, host->general_irq, host);
+		return err;
+	}
+
+	return 0;
+}
+
+static void host1x_intr_enable_general_intrs(struct host1x *host)
+{
+	if (host->general_irq <= 0 || !host->common_regs)
+		return;
+
+	/* Assign CCPLEX for host1x general interrupts */
+	host1x_common_writel(host, 0x1, HOST1X_COMMON_INTR_CPU0_MASK);
+
+	/* Allow host1x general interrupts go to CCPLEX only */
+	host1x_common_writel(host, 0x1, HOST1X_COMMON_THOST_GLOBAL_INTRMASK);
+
+	/* Enable host1x general interrupts */
+	host1x_common_writel(host,
+			     HOST1X_COMMON_THOST_INTRMASK_VIC_ACTMON(1) |
+			     HOST1X_COMMON_THOST_INTRMASK_NVDEC_ACTMON(1),
+			     HOST1X_COMMON_THOST_INTRMASK);
+}
+
+static void host1x_intr_disable_general_intrs(struct host1x *host)
+{
+	if (host->general_irq <= 0 || !host->common_regs)
+		return;
+
+	host1x_common_writel(host, 0x0, HOST1X_COMMON_THOST_INTRMASK);
+}
+
+static const struct host1x_intr_general_ops host1x_intr_general_ops = {
+	.init_host_general = host1x_intr_init_host_general,
+	.enable_general_intrs = host1x_intr_enable_general_intrs,
+	.disable_general_intrs = host1x_intr_disable_general_intrs,
+};
diff --git a/include/linux/host1x.h b/include/linux/host1x.h
index 9fa9c30a34e65..528b89d0ebdfa 100644
--- a/include/linux/host1x.h
+++ b/include/linux/host1x.h
@@ -1,6 +1,5 @@
-/* SPDX-License-Identifier: GPL-2.0-or-later */
-/*
- * Copyright (c) 2009-2013, NVIDIA Corporation. All rights reserved.
+/* SPDX-License-Identifier: GPL-2.0-only
+ * SPDX-FileCopyrightText: Copyright (c) 2009-2024 NVIDIA CORPORATION & AFFILIATES. All rights reserved.
  */
 
 #ifndef __LINUX_HOST1X_H
@@ -27,6 +26,13 @@ enum host1x_class {
 	HOST1X_CLASS_OFA = 0xF8,
 };
 
+enum host1x_actmon_wmark_event {
+	HOST1X_ACTMON_AVG_WMARK_BELOW,
+	HOST1X_ACTMON_AVG_WMARK_ABOVE,
+	HOST1X_ACTMON_CONSEC_WMARK_BELOW,
+	HOST1X_ACTMON_CONSEC_WMARK_ABOVE,
+};
+
 struct host1x;
 struct host1x_client;
 struct iommu_group;
@@ -68,6 +74,8 @@ static inline void host1x_bo_cache_destroy(struct host1x_bo_cache *cache)
  * @late_exit: host1x client late tear down code
  * @suspend: host1x client suspend code
  * @resume: host1x client resume code
+ * @get_rate: host1x client get clock rate code
+ * @actmon_event: host1x client actmon event handling code in threaded interrupt context
  */
 struct host1x_client_ops {
 	int (*early_init)(struct host1x_client *client);
@@ -76,8 +84,13 @@ struct host1x_client_ops {
 	int (*late_exit)(struct host1x_client *client);
 	int (*suspend)(struct host1x_client *client);
 	int (*resume)(struct host1x_client *client);
+	unsigned long (*get_rate)(struct host1x_client *client);
+	void (*actmon_event)(struct host1x_client *client,
+			     enum host1x_actmon_wmark_event event);
 };
 
+struct host1x_actmon;
+
 /**
  * struct host1x_client - host1x client structure
  * @list: list node for the host1x client
@@ -93,6 +106,7 @@ struct host1x_client_ops {
  * @usecount: reference count for this structure
  * @lock: mutex for mutually exclusive concurrency
  * @cache: host1x buffer object cache
+ * @actmon: unit actmon for this host1x client
  */
 struct host1x_client {
 	struct list_head list;
@@ -113,6 +127,8 @@ struct host1x_client {
 	struct mutex lock;
 
 	struct host1x_bo_cache cache;
+
+	struct host1x_actmon *actmon;
 };
 
 /*
@@ -500,4 +516,12 @@ static inline void host1x_memory_context_put(struct host1x_memory_context *cd)
 }
 #endif
 
+int host1x_actmon_register(struct host1x_client *client);
+void host1x_actmon_unregister(struct host1x_client *client);
+void host1x_actmon_enable(struct host1x_client *client);
+void host1x_actmon_disable(struct host1x_client *client);
+void host1x_actmon_update_client_rate(struct host1x_client *client,
+				      unsigned long rate,
+				      u32 *weight);
+
 #endif
-- 
2.34.1


^ permalink raw reply related	[flat|nested] 16+ messages in thread

* [PATCH v1 4/5] drm/tegra: nvdec: Register the device with actmon
  2024-12-10 17:45 [PATCH v1 0/5] Support host1x actmon Johnny Liu
                   ` (2 preceding siblings ...)
  2024-12-10 17:45 ` [PATCH v1 3/5] gpu: host1x: Support device monitoring with actmon Johnny Liu
@ 2024-12-10 17:45 ` Johnny Liu
  2024-12-10 17:45 ` [PATCH v1 5/5] drm/tegra: vic: " Johnny Liu
  2024-12-13 10:42 ` [PATCH v1 0/5] Support host1x actmon Krzysztof Kozlowski
  5 siblings, 0 replies; 16+ messages in thread
From: Johnny Liu @ 2024-12-10 17:45 UTC (permalink / raw)
  To: thierry.reding, jonathanh, skomatineni, luca.ceresoli, mperttunen,
	maarten.lankhorst, mripard, tzimmermann, airlied, simona, robh,
	krzk+dt, conor+dt
  Cc: linux-media, linux-tegra, dri-devel, devicetree, linux-kernel,
	Johnny Liu

By registering the nvdec with actmon, engine load information can be
exported to the user through debugfs for engine profiling purpose.

Signed-off-by: Johnny Liu <johnliu@nvidia.com>
---
 drivers/gpu/drm/tegra/nvdec.c | 82 ++++++++++++++++++++++++++++++++++-
 1 file changed, 80 insertions(+), 2 deletions(-)

diff --git a/drivers/gpu/drm/tegra/nvdec.c b/drivers/gpu/drm/tegra/nvdec.c
index 2d9a0a3f6c381..b7c572484d1be 100644
--- a/drivers/gpu/drm/tegra/nvdec.c
+++ b/drivers/gpu/drm/tegra/nvdec.c
@@ -1,6 +1,6 @@
 // SPDX-License-Identifier: GPL-2.0-only
 /*
- * Copyright (c) 2015-2022, NVIDIA Corporation.
+ * SPDX-FileCopyrightText: Copyright (c) 2015-2024 NVIDIA CORPORATION & AFFILIATES. All rights reserved.
  */
 
 #include <linux/clk.h>
@@ -22,8 +22,21 @@
 #include "riscv.h"
 #include "vic.h"
 
-#define NVDEC_FALCON_DEBUGINFO			0x1094
+#define NVDEC_FW_MTHD_ADDR_ACTMON_ACTIVE_MASK	0xCAU
+#define NVDEC_FW_MTHD_ADDR_ACTMON_ACTIVE_BORPS	0xCBU
+#define NVDEC_FW_MTHD_ADDR_ACTMON_ACTIVE_WEIGHT	0xC9U
+#define NVDEC_FALCON_UCLASS_METHOD_OFFSET       0x40
+#define NVDEC_FALCON_UCLASS_METHOD_DATA         0x44
+#define NVDEC_FALCON_DEBUGINFO                  0x1094
 #define NVDEC_TFBIF_TRANSCFG			0x2c44
+#define NVDEC_TFBIF_ACTMON_ACTIVE_MASK		0x2c4c
+#define NVDEC_TFBIF_ACTMON_ACTIVE_BORPS		0x2c50
+#define NVDEC_TFBIF_ACTMON_ACTIVE_WEIGHT	0x2c54
+
+#define NVDEC_TFBIF_ACTMON_ACTIVE_MASK_STARVED	BIT(0)
+#define NVDEC_TFBIF_ACTMON_ACTIVE_MASK_STALLED	BIT(1)
+#define NVDEC_TFBIF_ACTMON_ACTIVE_MASK_DELAYED	BIT(2)
+#define NVDEC_TFBIF_ACTMON_ACTIVE_BORPS_ACTIVE	BIT(7)
 
 struct nvdec_config {
 	const char *firmware;
@@ -306,6 +319,56 @@ static int nvdec_load_falcon_firmware(struct nvdec *nvdec)
 	return err;
 }
 
+static void nvdec_actmon_reg_init(struct nvdec *nvdec)
+{
+	if (nvdec->config->has_riscv) {
+		nvdec_writel(nvdec,
+			     NVDEC_FW_MTHD_ADDR_ACTMON_ACTIVE_MASK,
+			     NVDEC_FALCON_UCLASS_METHOD_OFFSET);
+		nvdec_writel(nvdec,
+			     NVDEC_TFBIF_ACTMON_ACTIVE_MASK_DELAYED |
+			     NVDEC_TFBIF_ACTMON_ACTIVE_MASK_STALLED |
+			     NVDEC_TFBIF_ACTMON_ACTIVE_MASK_STARVED,
+			     NVDEC_FALCON_UCLASS_METHOD_DATA);
+		nvdec_writel(nvdec,
+			     NVDEC_FW_MTHD_ADDR_ACTMON_ACTIVE_BORPS,
+			     NVDEC_FALCON_UCLASS_METHOD_OFFSET);
+		nvdec_writel(nvdec,
+			     NVDEC_TFBIF_ACTMON_ACTIVE_BORPS_ACTIVE,
+			     NVDEC_FALCON_UCLASS_METHOD_DATA);
+	} else {
+		nvdec_writel(nvdec,
+			     NVDEC_TFBIF_ACTMON_ACTIVE_MASK_DELAYED |
+			     NVDEC_TFBIF_ACTMON_ACTIVE_MASK_STALLED |
+			     NVDEC_TFBIF_ACTMON_ACTIVE_MASK_STARVED,
+			     NVDEC_TFBIF_ACTMON_ACTIVE_MASK);
+		nvdec_writel(nvdec,
+			     NVDEC_TFBIF_ACTMON_ACTIVE_BORPS_ACTIVE,
+			     NVDEC_TFBIF_ACTMON_ACTIVE_BORPS);
+	}
+}
+
+static void nvdec_count_weight_init(struct nvdec *nvdec, unsigned long rate)
+{
+	const struct nvdec_config *config = nvdec->config;
+	struct host1x_client *client = &nvdec->client.base;
+	u32 weight;
+
+	host1x_actmon_update_client_rate(client, rate, &weight);
+
+	if (!weight)
+		return;
+
+	if (!config->has_riscv) {
+		nvdec_writel(nvdec, weight, NVDEC_TFBIF_ACTMON_ACTIVE_WEIGHT);
+	} else {
+		nvdec_writel(nvdec,
+			     NVDEC_FW_MTHD_ADDR_ACTMON_ACTIVE_WEIGHT,
+			     NVDEC_FALCON_UCLASS_METHOD_OFFSET);
+		nvdec_writel(nvdec, weight, NVDEC_FALCON_UCLASS_METHOD_DATA);
+	}
+}
+
 static __maybe_unused int nvdec_runtime_resume(struct device *dev)
 {
 	struct nvdec *nvdec = dev_get_drvdata(dev);
@@ -331,6 +394,10 @@ static __maybe_unused int nvdec_runtime_resume(struct device *dev)
 			goto disable;
 	}
 
+	nvdec_actmon_reg_init(nvdec);
+	nvdec_count_weight_init(nvdec, clk_get_rate(nvdec->clks[0].clk));
+	host1x_actmon_enable(&nvdec->client.base);
+
 	return 0;
 
 disable:
@@ -346,6 +413,8 @@ static __maybe_unused int nvdec_runtime_suspend(struct device *dev)
 
 	clk_bulk_disable_unprepare(nvdec->num_clks, nvdec->clks);
 
+	host1x_actmon_disable(&nvdec->client.base);
+
 	return 0;
 }
 
@@ -532,12 +601,20 @@ static int nvdec_probe(struct platform_device *pdev)
 		goto exit_falcon;
 	}
 
+	err = host1x_actmon_register(&nvdec->client.base);
+	if (err < 0) {
+		dev_info(&pdev->dev, "failed to register host1x actmon: %d\n", err);
+		goto exit_client;
+	}
+
 	pm_runtime_enable(dev);
 	pm_runtime_use_autosuspend(dev);
 	pm_runtime_set_autosuspend_delay(dev, 500);
 
 	return 0;
 
+exit_client:
+	host1x_client_unregister(&nvdec->client.base);
 exit_falcon:
 	falcon_exit(&nvdec->falcon);
 
@@ -549,6 +626,7 @@ static void nvdec_remove(struct platform_device *pdev)
 	struct nvdec *nvdec = platform_get_drvdata(pdev);
 
 	pm_runtime_disable(&pdev->dev);
+	host1x_actmon_unregister(&nvdec->client.base);
 	host1x_client_unregister(&nvdec->client.base);
 	falcon_exit(&nvdec->falcon);
 }
-- 
2.34.1


^ permalink raw reply related	[flat|nested] 16+ messages in thread

* [PATCH v1 5/5] drm/tegra: vic: Register the device with actmon
  2024-12-10 17:45 [PATCH v1 0/5] Support host1x actmon Johnny Liu
                   ` (3 preceding siblings ...)
  2024-12-10 17:45 ` [PATCH v1 4/5] drm/tegra: nvdec: Register the device " Johnny Liu
@ 2024-12-10 17:45 ` Johnny Liu
  2024-12-13 10:42 ` [PATCH v1 0/5] Support host1x actmon Krzysztof Kozlowski
  5 siblings, 0 replies; 16+ messages in thread
From: Johnny Liu @ 2024-12-10 17:45 UTC (permalink / raw)
  To: thierry.reding, jonathanh, skomatineni, luca.ceresoli, mperttunen,
	maarten.lankhorst, mripard, tzimmermann, airlied, simona, robh,
	krzk+dt, conor+dt
  Cc: linux-media, linux-tegra, dri-devel, devicetree, linux-kernel,
	Johnny Liu

By registering the vic with actmon, engine load information can be
exported to the user through debugfs for engine profiling purpose.

Signed-off-by: Johnny Liu <johnliu@nvidia.com>
---
 drivers/gpu/drm/tegra/vic.c | 39 ++++++++++++++++++++++++++++++++++++-
 drivers/gpu/drm/tegra/vic.h |  9 +++++++++
 2 files changed, 47 insertions(+), 1 deletion(-)

diff --git a/drivers/gpu/drm/tegra/vic.c b/drivers/gpu/drm/tegra/vic.c
index 332c9b563d3f4..54c9b9b2af0a2 100644
--- a/drivers/gpu/drm/tegra/vic.c
+++ b/drivers/gpu/drm/tegra/vic.c
@@ -1,6 +1,6 @@
 // SPDX-License-Identifier: GPL-2.0-only
 /*
- * Copyright (c) 2015, NVIDIA Corporation.
+ * SPDX-FileCopyrightText: Copyright (c) 2015-2024 NVIDIA CORPORATION & AFFILIATES. All rights reserved.
  */
 
 #include <linux/clk.h>
@@ -302,6 +302,28 @@ static int vic_load_firmware(struct vic *vic)
 	return err;
 }
 
+static void vic_actmon_reg_init(struct vic *vic)
+{
+	vic_writel(vic,
+		   VIC_TFBIF_ACTMON_ACTIVE_MASK_STARVED |
+		   VIC_TFBIF_ACTMON_ACTIVE_MASK_STALLED |
+		   VIC_TFBIF_ACTMON_ACTIVE_MASK_DELAYED,
+		   NV_PVIC_TFBIF_ACTMON_ACTIVE_MASK);
+	vic_writel(vic,
+		   VIC_TFBIF_ACTMON_ACTIVE_BORPS_ACTIVE,
+		   NV_PVIC_TFBIF_ACTMON_ACTIVE_BORPS);
+}
+
+static void vic_count_weight_init(struct vic *vic, unsigned long rate)
+{
+	struct host1x_client *client = &vic->client.base;
+	u32 weight = 0;
+
+	host1x_actmon_update_client_rate(client, rate, &weight);
+
+	if (weight)
+		vic_writel(vic, weight, NV_PVIC_TFBIF_ACTMON_ACTIVE_WEIGHT);
+}
 
 static int __maybe_unused vic_runtime_resume(struct device *dev)
 {
@@ -328,6 +350,10 @@ static int __maybe_unused vic_runtime_resume(struct device *dev)
 	if (err < 0)
 		goto assert;
 
+	vic_actmon_reg_init(vic);
+	vic_count_weight_init(vic, clk_get_rate(vic->clk));
+	host1x_actmon_enable(&vic->client.base);
+
 	return 0;
 
 assert:
@@ -352,6 +378,8 @@ static int __maybe_unused vic_runtime_suspend(struct device *dev)
 
 	clk_disable_unprepare(vic->clk);
 
+	host1x_actmon_disable(&vic->client.base);
+
 	return 0;
 }
 
@@ -520,12 +548,20 @@ static int vic_probe(struct platform_device *pdev)
 		goto exit_falcon;
 	}
 
+	err = host1x_actmon_register(&vic->client.base);
+	if (err < 0) {
+		dev_info(&pdev->dev, "failed to register host1x actmon: %d\n", err);
+		goto exit_client;
+	}
+
 	pm_runtime_enable(dev);
 	pm_runtime_use_autosuspend(dev);
 	pm_runtime_set_autosuspend_delay(dev, 500);
 
 	return 0;
 
+exit_client:
+	host1x_client_unregister(&vic->client.base);
 exit_falcon:
 	falcon_exit(&vic->falcon);
 
@@ -537,6 +573,7 @@ static void vic_remove(struct platform_device *pdev)
 	struct vic *vic = platform_get_drvdata(pdev);
 
 	pm_runtime_disable(&pdev->dev);
+	host1x_actmon_unregister(&vic->client.base);
 	host1x_client_unregister(&vic->client.base);
 	falcon_exit(&vic->falcon);
 }
diff --git a/drivers/gpu/drm/tegra/vic.h b/drivers/gpu/drm/tegra/vic.h
index acf35aac948b2..905cd7bfde2f6 100644
--- a/drivers/gpu/drm/tegra/vic.h
+++ b/drivers/gpu/drm/tegra/vic.h
@@ -21,6 +21,15 @@
 #define CG_IDLE_CG_EN				(1 << 6)
 #define CG_WAKEUP_DLY_CNT(val)			((val & 0xf) << 16)
 
+#define NV_PVIC_TFBIF_ACTMON_ACTIVE_MASK	0x0000204c
+#define NV_PVIC_TFBIF_ACTMON_ACTIVE_BORPS	0x00002050
+#define NV_PVIC_TFBIF_ACTMON_ACTIVE_WEIGHT	0x00002054
+
+#define VIC_TFBIF_ACTMON_ACTIVE_MASK_STARVED	BIT(0)
+#define VIC_TFBIF_ACTMON_ACTIVE_MASK_STALLED	BIT(1)
+#define VIC_TFBIF_ACTMON_ACTIVE_MASK_DELAYED	BIT(2)
+#define VIC_TFBIF_ACTMON_ACTIVE_BORPS_ACTIVE	BIT(7)
+
 #define VIC_TFBIF_TRANSCFG	0x00002044
 #define  TRANSCFG_ATT(i, v)	(((v) & 0x3) << (i * 4))
 #define  TRANSCFG_SID_HW	0
-- 
2.34.1


^ permalink raw reply related	[flat|nested] 16+ messages in thread

* Re: [PATCH v1 0/5] Support host1x actmon
  2024-12-10 17:45 [PATCH v1 0/5] Support host1x actmon Johnny Liu
                   ` (4 preceding siblings ...)
  2024-12-10 17:45 ` [PATCH v1 5/5] drm/tegra: vic: " Johnny Liu
@ 2024-12-13 10:42 ` Krzysztof Kozlowski
  2024-12-13 23:17   ` Johnny Liu
  5 siblings, 1 reply; 16+ messages in thread
From: Krzysztof Kozlowski @ 2024-12-13 10:42 UTC (permalink / raw)
  To: Johnny Liu
  Cc: thierry.reding, jonathanh, skomatineni, luca.ceresoli, mperttunen,
	maarten.lankhorst, mripard, tzimmermann, airlied, simona, robh,
	krzk+dt, conor+dt, linux-media, linux-tegra, dri-devel,
	devicetree, linux-kernel

On Tue, Dec 10, 2024 at 09:45:49AM -0800, Johnny Liu wrote:
> Activity monitoring (actmon for short) is a means to dynamically
> measure the utilization of units in the system to help drive software
> power management policies.
> 

Is this a resend or v2? Please always mark your patches appropriately -
see submitting patches document.

b4 diff '20241210174554.18869-1-johnliu@nvidia.com'
Grabbing thread from lore.kernel.org/all/20241210174554.18869-1-johnliu@nvidia.com/t.mbox.gz
---
Analyzing 6 messages in the thread
Could not find lower series to compare against.

But I am sure I saw it somewhere...

Or just use b4, so all this problems disappear.

Best regards,
Krzysztof


^ permalink raw reply	[flat|nested] 16+ messages in thread

* Re: [PATCH v1 1/5] dt-bindings: display: tegra: Add actmon information
  2024-12-10 17:45 ` [PATCH v1 1/5] dt-bindings: display: tegra: Add actmon information Johnny Liu
@ 2024-12-13 10:44   ` Krzysztof Kozlowski
  2024-12-13 23:29     ` Johnny Liu
  0 siblings, 1 reply; 16+ messages in thread
From: Krzysztof Kozlowski @ 2024-12-13 10:44 UTC (permalink / raw)
  To: Johnny Liu
  Cc: thierry.reding, jonathanh, skomatineni, luca.ceresoli, mperttunen,
	maarten.lankhorst, mripard, tzimmermann, airlied, simona, robh,
	krzk+dt, conor+dt, linux-media, linux-tegra, dri-devel,
	devicetree, linux-kernel

On Tue, Dec 10, 2024 at 09:45:50AM -0800, Johnny Liu wrote:
> An activity monitor (actmon) is used to measure the device runtime
> utilization to help drive software power management policies.
> 
> Extend the reg space to include actmon aperture for actmon configuration
> through host1x.

We kind of see that from the diff. Say what we do not see, e.g. ABI
impact or why this is flexible/optional for existing devices.

Best regards,
Krzysztof


^ permalink raw reply	[flat|nested] 16+ messages in thread

* Re: [PATCH v1 0/5] Support host1x actmon
  2024-12-13 10:42 ` [PATCH v1 0/5] Support host1x actmon Krzysztof Kozlowski
@ 2024-12-13 23:17   ` Johnny Liu
  2024-12-16  7:27     ` Krzysztof Kozlowski
  0 siblings, 1 reply; 16+ messages in thread
From: Johnny Liu @ 2024-12-13 23:17 UTC (permalink / raw)
  To: krzk
  Cc: airlied, conor+dt, devicetree, dri-devel, johnliu, jonathanh,
	krzk+dt, linux-kernel, linux-media, linux-tegra, luca.ceresoli,
	maarten.lankhorst, mperttunen, mripard, robh, simona, skomatineni,
	thierry.reding, tzimmermann

> On Tue, Dec 10, 2024 at 09:45:49AM -0800, Johnny Liu wrote:
> > Activity monitoring (actmon for short) is a means to dynamically
> > measure the utilization of units in the system to help drive software
> > power management policies.
> >
>
> Is this a resend or v2? Please always mark your patches appropriately -
> see submitting patches document.
>
> b4 diff '20241210174554.18869-1-johnliu@nvidia.com'
> Grabbing thread from lore.kernel.org/all/20241210174554.18869-1-johnliu@nvidia.com/t.mbox.gz
> ---
> Analyzing 6 messages in the thread
> Could not find lower series to compare against.
>
> But I am sure I saw it somewhere...
>
> Or just use b4, so all this problems disappear.

This is a resend actually to include all necessary To/Cc entries based on your comment
in the previous patch series:
lore.kernel.org/linux-tegra/20241209172549.5624-1-johnliu@nvidia.com

Previous one doesn't cover all the required reviewers as you mentioned, so I don't consider
it as a valid patch series. Therefore, I resend it again and include the required folks and
consider it as a brand new patch series.

I would definitely try the b4 tool you recommended and update my workflow. I actually use
vanilla git send-mail and git format-patch currently...


Thanks,
Johnny

^ permalink raw reply	[flat|nested] 16+ messages in thread

* Re: [PATCH v1 1/5] dt-bindings: display: tegra: Add actmon information
  2024-12-13 10:44   ` Krzysztof Kozlowski
@ 2024-12-13 23:29     ` Johnny Liu
  2024-12-16  7:26       ` Krzysztof Kozlowski
  0 siblings, 1 reply; 16+ messages in thread
From: Johnny Liu @ 2024-12-13 23:29 UTC (permalink / raw)
  To: krzk
  Cc: airlied, conor+dt, devicetree, dri-devel, johnliu, jonathanh,
	krzk+dt, linux-kernel, linux-media, linux-tegra, luca.ceresoli,
	maarten.lankhorst, mperttunen, mripard, robh, simona, skomatineni,
	thierry.reding, tzimmermann

> On Tue, Dec 10, 2024 at 09:45:50AM -0800, Johnny Liu wrote:
> > An activity monitor (actmon) is used to measure the device runtime
> > utilization to help drive software power management policies.
> >
> > Extend the reg space to include actmon aperture for actmon configuration
> > through host1x.
>
> We kind of see that from the diff. Say what we do not see, e.g. ABI
> impact or why this is flexible/optional for existing devices.

Since actmon is not well-supported for the previous chips (e.g. T210,
T186, T194, and etc) in this patch series, it's essential to make the
specification of regs property optional for the previous chips.

Enablement/Disablement of actmon won't affect the host1x main functionality.
Its main job is to monitor the engines behind the host1x and serve for
telemetry purpose.

I could update the commit message to include the above reason. Please
let me know if more information is required.


Thanks,
Johnny

^ permalink raw reply	[flat|nested] 16+ messages in thread

* Re: [PATCH v1 1/5] dt-bindings: display: tegra: Add actmon information
  2024-12-13 23:29     ` Johnny Liu
@ 2024-12-16  7:26       ` Krzysztof Kozlowski
  2024-12-17  1:08         ` Johnny Liu
  0 siblings, 1 reply; 16+ messages in thread
From: Krzysztof Kozlowski @ 2024-12-16  7:26 UTC (permalink / raw)
  To: Johnny Liu
  Cc: airlied, conor+dt, devicetree, dri-devel, jonathanh, krzk+dt,
	linux-kernel, linux-media, linux-tegra, luca.ceresoli,
	maarten.lankhorst, mperttunen, mripard, robh, simona, skomatineni,
	thierry.reding, tzimmermann

On 14/12/2024 00:29, Johnny Liu wrote:
>> On Tue, Dec 10, 2024 at 09:45:50AM -0800, Johnny Liu wrote:
>>> An activity monitor (actmon) is used to measure the device runtime
>>> utilization to help drive software power management policies.
>>>
>>> Extend the reg space to include actmon aperture for actmon configuration
>>> through host1x.
>>
>> We kind of see that from the diff. Say what we do not see, e.g. ABI
>> impact or why this is flexible/optional for existing devices.
> 
> Since actmon is not well-supported for the previous chips (e.g. T210,
> T186, T194, and etc) in this patch series, it's essential to make the
> specification of regs property optional for the previous chips.

Then your schema should express it.

> 
> Enablement/Disablement of actmon won't affect the host1x main functionality.
> Its main job is to monitor the engines behind the host1x and serve for
> telemetry purpose.
> 
> I could update the commit message to include the above reason. Please
> let me know if more information is required.

And fix the schema to make it optional only for older variants.


Best regards,
Krzysztof

^ permalink raw reply	[flat|nested] 16+ messages in thread

* Re: [PATCH v1 0/5] Support host1x actmon
  2024-12-13 23:17   ` Johnny Liu
@ 2024-12-16  7:27     ` Krzysztof Kozlowski
  0 siblings, 0 replies; 16+ messages in thread
From: Krzysztof Kozlowski @ 2024-12-16  7:27 UTC (permalink / raw)
  To: Johnny Liu
  Cc: airlied, conor+dt, devicetree, dri-devel, jonathanh, krzk+dt,
	linux-kernel, linux-media, linux-tegra, luca.ceresoli,
	maarten.lankhorst, mperttunen, mripard, robh, simona, skomatineni,
	thierry.reding, tzimmermann

On 14/12/2024 00:17, Johnny Liu wrote:
>> On Tue, Dec 10, 2024 at 09:45:49AM -0800, Johnny Liu wrote:
>>> Activity monitoring (actmon for short) is a means to dynamically
>>> measure the utilization of units in the system to help drive software
>>> power management policies.
>>>
>>
>> Is this a resend or v2? Please always mark your patches appropriately -
>> see submitting patches document.
>>
>> b4 diff '20241210174554.18869-1-johnliu@nvidia.com'
>> Grabbing thread from lore.kernel.org/all/20241210174554.18869-1-johnliu@nvidia.com/t.mbox.gz
>> ---
>> Analyzing 6 messages in the thread
>> Could not find lower series to compare against.
>>
>> But I am sure I saw it somewhere...
>>
>> Or just use b4, so all this problems disappear.
> 
> This is a resend actually to include all necessary To/Cc entries based on your comment
> in the previous patch series:

Then mark patches as RESEND. Please carefully read submitting patches
before posting anything.



Best regards,
Krzysztof

^ permalink raw reply	[flat|nested] 16+ messages in thread

* Re: [PATCH v1 1/5] dt-bindings: display: tegra: Add actmon information
  2024-12-16  7:26       ` Krzysztof Kozlowski
@ 2024-12-17  1:08         ` Johnny Liu
  2024-12-17  5:36           ` Krzysztof Kozlowski
  0 siblings, 1 reply; 16+ messages in thread
From: Johnny Liu @ 2024-12-17  1:08 UTC (permalink / raw)
  To: krzk
  Cc: airlied, conor+dt, devicetree, dri-devel, johnliu, jonathanh,
	krzk+dt, linux-kernel, linux-media, linux-tegra, luca.ceresoli,
	maarten.lankhorst, mperttunen, mripard, robh, simona, skomatineni,
	thierry.reding, tzimmermann

> On 14/12/2024 00:29, Johnny Liu wrote:
> >> On Tue, Dec 10, 2024 at 09:45:50AM -0800, Johnny Liu wrote:
> >>> An activity monitor (actmon) is used to measure the device runtime
> >>> utilization to help drive software power management policies.
> >>>
> >>> Extend the reg space to include actmon aperture for actmon configuration
> >>> through host1x.
> >>
> >> We kind of see that from the diff. Say what we do not see, e.g. ABI
> >> impact or why this is flexible/optional for existing devices.
> >
> > Since actmon is not well-supported for the previous chips (e.g. T210,
> > T186, T194, and etc) in this patch series, it's essential to make the
> > specification of regs property optional for the previous chips.
>
> Then your schema should express it.

Could you explicitly point out which part doesn't express it well?

Considering old variant T194, the schema in this patch already made the
specification of actmon related properties optional.

If users specify actmon clock handle in clocks/clock-names properties:

 host1x@13e00000 {
	 compatible = "nvidia,tegra194-host1x";
	 // ...
	 clocks = <&bpmp TEGRA194_CLK_HOST1X>,
		  <&bpmp TEGRA194_CLK_ACTMON>;
	 clock-names = "host1x", "actmon";
	 // ...
 }

Running the dtbs_check will report error WITHOUT this patch will have
the following error:

$ make O=out ARCH=arm64 CROSS_COMPILE=aarch64-linux-gnu- dtbs_check DT_SCHEMA_FILES=Documentation/devicetree/bindings/display/tegra/nvidia,tegra20-host1x.yaml

/out/arch/arm64/boot/dts/nvidia/tegra194-p3509-0000+p3668-0000.dtb: host1x@13e00000: clocks: [[5, 46], [5, 1]] is too long
/out/arch/arm64/boot/dts/nvidia/tegra194-p3509-0000+p3668-0000.dtb: host1x@13e00000: clock-names: ['host1x', 'actmon'] is too long


> >
> > Enablement/Disablement of actmon won't affect the host1x main functionality.
> > Its main job is to monitor the engines behind the host1x and serve for
> > telemetry purpose.
> >
> > I could update the commit message to include the above reason. Please
> > let me know if more information is required.
>
> And fix the schema to make it optional only for older variants.

To maintain backward compatibility, shouldn't we keep the newly added
feature optional for all the variants?


Thanks,
Johnny

^ permalink raw reply	[flat|nested] 16+ messages in thread

* Re: [PATCH v1 1/5] dt-bindings: display: tegra: Add actmon information
  2024-12-17  1:08         ` Johnny Liu
@ 2024-12-17  5:36           ` Krzysztof Kozlowski
  0 siblings, 0 replies; 16+ messages in thread
From: Krzysztof Kozlowski @ 2024-12-17  5:36 UTC (permalink / raw)
  To: Johnny Liu
  Cc: airlied, conor+dt, devicetree, dri-devel, jonathanh, krzk+dt,
	linux-kernel, linux-media, linux-tegra, luca.ceresoli,
	maarten.lankhorst, mperttunen, mripard, robh, simona, skomatineni,
	thierry.reding, tzimmermann

On 17/12/2024 02:08, Johnny Liu wrote:
>> On 14/12/2024 00:29, Johnny Liu wrote:
>>>> On Tue, Dec 10, 2024 at 09:45:50AM -0800, Johnny Liu wrote:
>>>>> An activity monitor (actmon) is used to measure the device runtime
>>>>> utilization to help drive software power management policies.
>>>>>
>>>>> Extend the reg space to include actmon aperture for actmon configuration
>>>>> through host1x.
>>>>
>>>> We kind of see that from the diff. Say what we do not see, e.g. ABI
>>>> impact or why this is flexible/optional for existing devices.
>>>
>>> Since actmon is not well-supported for the previous chips (e.g. T210,
>>> T186, T194, and etc) in this patch series, it's essential to make the
>>> specification of regs property optional for the previous chips.
>>
>> Then your schema should express it.
> 
> Could you explicitly point out which part doesn't express it well?
> 

You said it should be optional for previous chip, while this is not made
optional for previous chips. You made it optional for newest chips.


> Considering old variant T194, the schema in this patch already made the
> specification of actmon related properties optional.
> 
> If users specify actmon clock handle in clocks/clock-names properties:
> 
>  host1x@13e00000 {
> 	 compatible = "nvidia,tegra194-host1x";
> 	 // ...
> 	 clocks = <&bpmp TEGRA194_CLK_HOST1X>,
> 		  <&bpmp TEGRA194_CLK_ACTMON>;
> 	 clock-names = "host1x", "actmon";
> 	 // ...
>  }
> 
> Running the dtbs_check will report error WITHOUT this patch will have
> the following error:
> 
> $ make O=out ARCH=arm64 CROSS_COMPILE=aarch64-linux-gnu- dtbs_check DT_SCHEMA_FILES=Documentation/devicetree/bindings/display/tegra/nvidia,tegra20-host1x.yaml
> 
> /out/arch/arm64/boot/dts/nvidia/tegra194-p3509-0000+p3668-0000.dtb: host1x@13e00000: clocks: [[5, 46], [5, 1]] is too long
> /out/arch/arm64/boot/dts/nvidia/tegra194-p3509-0000+p3668-0000.dtb: host1x@13e00000: clock-names: ['host1x', 'actmon'] is too long

This is not the meaning of word "optional".

> 
> 
>>>
>>> Enablement/Disablement of actmon won't affect the host1x main functionality.
>>> Its main job is to monitor the engines behind the host1x and serve for
>>> telemetry purpose.
>>>
>>> I could update the commit message to include the above reason. Please
>>> let me know if more information is required.
>>
>> And fix the schema to make it optional only for older variants.
> 
> To maintain backward compatibility, shouldn't we keep the newly added
> feature optional for all the variants?

Yes, but it is about driver. Is it optional in the driver?

Your binding says optional but driver says required and will fail. This
does not make any sense in the context of this patch and even less in
the context of your explanation.


Best regards,
Krzysztof

^ permalink raw reply	[flat|nested] 16+ messages in thread

* Re: [PATCH v1 3/5] gpu: host1x: Support device monitoring with actmon
  2024-12-10 17:45 ` [PATCH v1 3/5] gpu: host1x: Support device monitoring with actmon Johnny Liu
@ 2024-12-17  5:39   ` Krzysztof Kozlowski
  2024-12-19 20:29     ` Johnny Liu
  0 siblings, 1 reply; 16+ messages in thread
From: Krzysztof Kozlowski @ 2024-12-17  5:39 UTC (permalink / raw)
  To: Johnny Liu, thierry.reding, jonathanh, skomatineni, luca.ceresoli,
	mperttunen, maarten.lankhorst, mripard, tzimmermann, airlied,
	simona, robh, krzk+dt, conor+dt
  Cc: linux-media, linux-tegra, dri-devel, devicetree, linux-kernel

On 10/12/2024 18:45, Johnny Liu wrote:

> +
> +static int host1x_actmon_sample_period_set(void *data, u64 val)
> +{
> +	struct host1x_actmon *actmon = (struct host1x_actmon *)data;
> +
> +	actmon->usecs_per_sample = (u32)val;
> +	host1x_actmon_update_sample_period(actmon);
> +
> +	return 0;
> +}
> +
> +DEFINE_SIMPLE_ATTRIBUTE(host1x_actmon_sample_period_fops,
> +			host1x_actmon_sample_period_get,
> +		host1x_actmon_sample_period_set,
> +		"%lld\n");
> +
> +/**
> + * host1x_actmon_debug_init - Initialize actmon debugfs


No, debugfs is only for debugging, not for usual interfaces. You now
added several driver knobs bypassing any ABI documentation.


> + * @actmon: the actmon instance being configured
> + * @name: an unique name of the actmon
> + *
> + * There are multiple modules available inside the actmon, and they perform the
> + * signal sampling at the same rate. The debugfs of an actmon will expose this
> + * shared configuration, sample_period, via a debugfs node:
> + * - sample_period:
> + *   Sampling period in micro-second of modules inside the actmon
> + */
> +static void host1x_actmon_debug_init(struct host1x_actmon *actmon, const char *name)
> +{
> +	struct host1x *host = dev_get_drvdata(actmon->client->host->parent);
> +
> +	if (!host->debugfs) {
> +		dev_warn(host->dev, "debugfs is unavailable\n");
> +		return;
> +	}
> +
> +	if (!host->actmon_debugfs)
> +		host->actmon_debugfs = debugfs_create_dir("actmon", host->debugfs);
> +
> +	actmon->debugfs = debugfs_create_dir(name, host->actmon_debugfs);
> +
> +	/* R/W files */
> +	debugfs_create_file("sample_period", 0644, actmon->debugfs, actmon,
> +			    &host1x_actmon_sample_period_fops);
> +}
> +
Best regards,
Krzysztof

^ permalink raw reply	[flat|nested] 16+ messages in thread

* Re: [PATCH v1 3/5] gpu: host1x: Support device monitoring with actmon
  2024-12-17  5:39   ` Krzysztof Kozlowski
@ 2024-12-19 20:29     ` Johnny Liu
  0 siblings, 0 replies; 16+ messages in thread
From: Johnny Liu @ 2024-12-19 20:29 UTC (permalink / raw)
  To: krzk
  Cc: airlied, conor+dt, devicetree, dri-devel, johnliu, jonathanh,
	krzk+dt, linux-kernel, linux-media, linux-tegra, luca.ceresoli,
	maarten.lankhorst, mperttunen, mripard, robh, simona, skomatineni,
	thierry.reding, tzimmermann

> On 10/12/2024 18:45, Johnny Liu wrote:
>
> > +
> > +static int host1x_actmon_sample_period_set(void *data, u64 val)
> > +{
> > +	struct host1x_actmon *actmon = (struct host1x_actmon *)data;
> > +
> > +	actmon->usecs_per_sample = (u32)val;
> > +	host1x_actmon_update_sample_period(actmon);
> > +
> > +	return 0;
> > +}
> > +
> > +DEFINE_SIMPLE_ATTRIBUTE(host1x_actmon_sample_period_fops,
> > +			host1x_actmon_sample_period_get,
> > +		host1x_actmon_sample_period_set,
> > +		"%lld\n");
> > +
> > +/**
> > + * host1x_actmon_debug_init - Initialize actmon debugfs
>
>
> No, debugfs is only for debugging, not for usual interfaces. You now
> added several driver knobs bypassing any ABI documentation.

Thank you for pointing out the issue. I will expose these control
interfaces under sysfs, probably hwmon, in the next patch series.

> > + * @actmon: the actmon instance being configured
> > + * @name: an unique name of the actmon
> > + *
> > + * There are multiple modules available inside the actmon, and they perform the
> > + * signal sampling at the same rate. The debugfs of an actmon will expose this
> > + * shared configuration, sample_period, via a debugfs node:
> > + * - sample_period:
> > + *   Sampling period in micro-second of modules inside the actmon
> > + */
> > +static void host1x_actmon_debug_init(struct host1x_actmon *actmon, const char *name)
> > +{
> > +	struct host1x *host = dev_get_drvdata(actmon->client->host->parent);
> > +
> > +	if (!host->debugfs) {
> > +		dev_warn(host->dev, "debugfs is unavailable\n");
> > +		return;
> > +	}
> > +
> > +	if (!host->actmon_debugfs)
> > +		host->actmon_debugfs = debugfs_create_dir("actmon", host->debugfs);
> > +
> > +	actmon->debugfs = debugfs_create_dir(name, host->actmon_debugfs);
> > +
> > +	/* R/W files */
> > +	debugfs_create_file("sample_period", 0644, actmon->debugfs, actmon,
> > +			    &host1x_actmon_sample_period_fops);
> > +}
> > +

Thanks,
Johnny

^ permalink raw reply	[flat|nested] 16+ messages in thread

end of thread, other threads:[~2024-12-19 20:30 UTC | newest]

Thread overview: 16+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2024-12-10 17:45 [PATCH v1 0/5] Support host1x actmon Johnny Liu
2024-12-10 17:45 ` [PATCH v1 1/5] dt-bindings: display: tegra: Add actmon information Johnny Liu
2024-12-13 10:44   ` Krzysztof Kozlowski
2024-12-13 23:29     ` Johnny Liu
2024-12-16  7:26       ` Krzysztof Kozlowski
2024-12-17  1:08         ` Johnny Liu
2024-12-17  5:36           ` Krzysztof Kozlowski
2024-12-10 17:45 ` [PATCH v1 2/5] arm64: " Johnny Liu
2024-12-10 17:45 ` [PATCH v1 3/5] gpu: host1x: Support device monitoring with actmon Johnny Liu
2024-12-17  5:39   ` Krzysztof Kozlowski
2024-12-19 20:29     ` Johnny Liu
2024-12-10 17:45 ` [PATCH v1 4/5] drm/tegra: nvdec: Register the device " Johnny Liu
2024-12-10 17:45 ` [PATCH v1 5/5] drm/tegra: vic: " Johnny Liu
2024-12-13 10:42 ` [PATCH v1 0/5] Support host1x actmon Krzysztof Kozlowski
2024-12-13 23:17   ` Johnny Liu
2024-12-16  7:27     ` Krzysztof Kozlowski

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).