[<prev] [next>] [day] [month] [year] [list]
Message-ID: <20251129032921.811332-1-alex.t.tran@gmail.com>
Date: Fri, 28 Nov 2025 19:29:21 -0800
From: Alex Tran <alex.t.tran@...il.com>
To: jani.nikula@...ux.intel.com,
joonas.lahtinen@...ux.intel.com,
rodrigo.vivi@...el.com,
tursulin@...ulin.net
Cc: airlied@...il.com,
simona@...ll.ch,
ville.syrjala@...ux.intel.com,
vinay.belgaumkar@...el.com,
intel-gfx@...ts.freedesktop.org,
dri-devel@...ts.freedesktop.org,
linux-kernel@...r.kernel.org,
Alex Tran <alex.t.tran@...il.com>
Subject: [PATCH v1] drm: i915: gt: intel_rps: handle counter overflow by calculating delta for each register
The previous implementation calculated the power deltas by adding together
the u32 energy counters DMIEC, DDREC, CSIEC into a u64 total and then
subtracting from the previous total to obtain the delta. When any of the
u32 counters overflowed and wrapped, the total would be less then previous
total, causing incorrect delta calculations since u64 subtraction doesn't
handle u32 counter wrapping correctly.
This implementation tracks each counter individually, allowing their deltas
to be calculated separately and then summed. This correctly handles u32
counter wraparound, fixing incorrect power calculations when counters
overflow.
Signed-off-by: Alex Tran <alex.t.tran@...il.com>
---
drivers/gpu/drm/i915/gt/intel_rps.c | 40 +++++++++++++----------
drivers/gpu/drm/i915/gt/intel_rps_types.h | 6 ++--
2 files changed, 27 insertions(+), 19 deletions(-)
diff --git a/drivers/gpu/drm/i915/gt/intel_rps.c b/drivers/gpu/drm/i915/gt/intel_rps.c
index 4da94098bd3e..8247a8b16f18 100644
--- a/drivers/gpu/drm/i915/gt/intel_rps.c
+++ b/drivers/gpu/drm/i915/gt/intel_rps.c
@@ -324,8 +324,10 @@ __ips_chipset_val(struct intel_ips *ips)
struct intel_uncore *uncore =
rps_to_uncore(container_of(ips, struct intel_rps, ips));
unsigned long now = jiffies_to_msecs(jiffies), dt;
+ u32 dmiec_delta, ddrec_delta, csiec_delta;
+ u32 dmiec, ddrec, csiec;
unsigned long result;
- u64 total, delta;
+ u64 delta;
lockdep_assert_held(&mchdev_lock);
@@ -339,17 +341,21 @@ __ips_chipset_val(struct intel_ips *ips)
if (dt <= 10)
return ips->chipset_power;
- /* FIXME: handle per-counter overflow */
- total = intel_uncore_read(uncore, DMIEC);
- total += intel_uncore_read(uncore, DDREC);
- total += intel_uncore_read(uncore, CSIEC);
+ dmiec = intel_uncore_read(uncore, DMIEC);
+ ddrec = intel_uncore_read(uncore, DDREC);
+ csiec = intel_uncore_read(uncore, CSIEC);
- delta = total - ips->last_count1;
+ dmiec_delta = dmiec - ips->last_dmiec;
+ ddrec_delta = ddrec - ips->last_ddrec;
+ csiec_delta = csiec - ips->last_csiec;
+ delta = dmiec_delta + ddrec_delta + csiec_delta;
result = div_u64(div_u64(ips->m * delta, dt) + ips->c, 10);
-
- ips->last_count1 = total;
+
ips->last_time1 = now;
+ ips->last_dmiec = dmiec;
+ ips->last_ddrec = ddrec;
+ ips->last_csiec = csiec;
ips->chipset_power = result;
@@ -396,7 +402,7 @@ static void __gen5_ips_update(struct intel_ips *ips)
struct intel_uncore *uncore =
rps_to_uncore(container_of(ips, struct intel_rps, ips));
u64 now, delta, dt;
- u32 count;
+ u32 gfxec;
lockdep_assert_held(&mchdev_lock);
@@ -408,10 +414,10 @@ static void __gen5_ips_update(struct intel_ips *ips)
if (dt <= 10)
return;
- count = intel_uncore_read(uncore, GFXEC);
- delta = count - ips->last_count2;
-
- ips->last_count2 = count;
+ gfxec = intel_uncore_read(uncore, GFXEC);
+ delta = gfxec - ips->last_gfxec;
+
+ ips->last_gfxec = gfxec;
ips->last_time2 = now;
/* More magic constants... */
@@ -607,12 +613,12 @@ static bool gen5_rps_enable(struct intel_rps *rps)
__gen5_rps_set(rps, rps->cur_freq);
- rps->ips.last_count1 = intel_uncore_read(uncore, DMIEC);
- rps->ips.last_count1 += intel_uncore_read(uncore, DDREC);
- rps->ips.last_count1 += intel_uncore_read(uncore, CSIEC);
+ rps->ips.last_dmiec = intel_uncore_read(uncore, DMIEC);
+ rps->ips.last_ddrec = intel_uncore_read(uncore, DDREC);
+ rps->ips.last_csiec = intel_uncore_read(uncore, CSIEC);
rps->ips.last_time1 = jiffies_to_msecs(jiffies);
- rps->ips.last_count2 = intel_uncore_read(uncore, GFXEC);
+ rps->ips.last_gfxec = intel_uncore_read(uncore, GFXEC);
rps->ips.last_time2 = ktime_get_raw_ns();
ilk_display_rps_enable(display);
diff --git a/drivers/gpu/drm/i915/gt/intel_rps_types.h b/drivers/gpu/drm/i915/gt/intel_rps_types.h
index ece445109305..e275291787cf 100644
--- a/drivers/gpu/drm/i915/gt/intel_rps_types.h
+++ b/drivers/gpu/drm/i915/gt/intel_rps_types.h
@@ -13,10 +13,12 @@
#include <linux/workqueue.h>
struct intel_ips {
- u64 last_count1;
+ u32 last_dmiec;
+ u32 last_ddrec;
+ u32 last_csiec;
unsigned long last_time1;
unsigned long chipset_power;
- u64 last_count2;
+ u32 last_gfxec;
u64 last_time2;
unsigned long gfx_power;
u8 corr;
--
2.51.0
Powered by blists - more mailing lists